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 +
+ Nebula 13 +
+

+ +

+ + Build Status + + + CodeFactor + + + Last Commit + + + Issues + + + Discord + + + License + +

+ +

+ 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<

") + show_browser(src, "

") Output_Icon() set name = "2. Output Icon" - to_chat(src, "Icon is: \icon[getFlatIcon(src)]") + to_chat(src, "Icon is: [html_icon(getFlatIcon(src))]") Label_Icon() set name = "3. Label Icon" @@ -216,85 +200,79 @@ world #define TO_HEX_DIGIT(n) ascii2text((n&15) + ((n&15)<10 ? 48 : 87)) -icon - proc/MakeLying() - var/icon/I = new(src,dir=SOUTH) - I.BecomeLying() - return I - - proc/BecomeLying() - Turn(90) - Shift(SOUTH,6) - Shift(EAST,1) - - // Multiply all alpha values by this float - proc/ChangeOpacity(opacity = 1.0) - MapColors(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,opacity, 0,0,0,0) - - // Convert to grayscale - proc/GrayScale() - MapColors(0.3,0.3,0.3, 0.59,0.59,0.59, 0.11,0.11,0.11, 0,0,0) - - proc/ColorTone(tone) - GrayScale() - - var/list/TONE = ReadRGB(tone) - var/gray = round(TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11, 1) - - var/icon/upper = (255-gray) ? new(src) : null - - if(gray) - MapColors(255/gray,0,0, 0,255/gray,0, 0,0,255/gray, 0,0,0) - Blend(tone, ICON_MULTIPLY) - else SetIntensity(0) - if(255-gray) - upper.Blend(rgb(gray,gray,gray), ICON_SUBTRACT) - upper.MapColors((255-TONE[1])/(255-gray),0,0,0, 0,(255-TONE[2])/(255-gray),0,0, 0,0,(255-TONE[3])/(255-gray),0, 0,0,0,0, 0,0,0,1) - Blend(upper, ICON_ADD) - - // Take the minimum color of two icons; combine transparency as if blending with ICON_ADD - proc/MinColors(icon) - var/icon/I = new(src) - I.Opaque() - I.Blend(icon, ICON_SUBTRACT) - Blend(I, ICON_SUBTRACT) - - // Take the maximum color of two icons; combine opacity as if blending with ICON_OR - proc/MaxColors(icon) - var/icon/I - if(isicon(icon)) - I = new(icon) - else - // solid color - I = new(src) - I.Blend("#000000", ICON_OVERLAY) - I.SwapColor("#000000", null) - I.Blend(icon, ICON_OVERLAY) - var/icon/J = new(src) - J.Opaque() - I.Blend(J, ICON_SUBTRACT) - Blend(I, ICON_OR) - - // make this icon fully opaque--transparent pixels become black - proc/Opaque(background = "#000000") - SwapColor(null, background) - MapColors(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,1) - - // Change a grayscale icon into a white icon where the original color becomes the alpha - // I.e., black -> transparent, gray -> translucent white, white -> solid white - proc/BecomeAlphaMask() - SwapColor(null, "#000000ff") // don't let transparent become gray - MapColors(0,0,0,0.3, 0,0,0,0.59, 0,0,0,0.11, 0,0,0,0, 1,1,1,0) - - proc/UseAlphaMask(mask) - Opaque() - AddAlphaMask(mask) - - proc/AddAlphaMask(mask) - var/icon/M = new(mask) - M.Blend("#ffffff", ICON_SUBTRACT) - // apply mask - Blend(M, ICON_ADD) +/icon/proc/BecomeLying() + Turn(90) + Shift(SOUTH,6) + Shift(EAST,1) + +// Multiply all alpha values by this float +/icon/proc/ChangeOpacity(opacity = TRUE) + MapColors(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,opacity, 0,0,0,0) + +// Convert to grayscale +/icon/proc/GrayScale() + MapColors(0.3,0.3,0.3, 0.59,0.59,0.59, 0.11,0.11,0.11, 0,0,0) + +/icon/proc/ColorTone(tone) + GrayScale() + + var/list/TONE = rgb2num(tone) + var/gray = round(TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11, 1) + + var/icon/upper = (255-gray) ? new(src) : null + + if(gray) + MapColors(255/gray,0,0, 0,255/gray,0, 0,0,255/gray, 0,0,0) + Blend(tone, ICON_MULTIPLY) + else SetIntensity(0) + if(255-gray) + upper.Blend(rgb(gray,gray,gray), ICON_SUBTRACT) + upper.MapColors((255-TONE[1])/(255-gray),0,0,0, 0,(255-TONE[2])/(255-gray),0,0, 0,0,(255-TONE[3])/(255-gray),0, 0,0,0,0, 0,0,0,1) + Blend(upper, ICON_ADD) + +// Take the minimum color of two icons; combine transparency as if blending with ICON_ADD +/icon/proc/MinColors(icon) + var/icon/I = new(src) + I.Opaque() + I.Blend(icon, ICON_SUBTRACT) + Blend(I, ICON_SUBTRACT) + +// Take the maximum color of two icons; combine opacity as if blending with ICON_OR +/icon/proc/MaxColors(icon) + var/icon/I + if(isicon(icon)) + I = new(icon) + else + // solid color + I = new(src) + I.Blend("#000000", ICON_OVERLAY) + I.SwapColor("#000000", null) + I.Blend(icon, ICON_OVERLAY) + var/icon/J = new(src) + J.Opaque() + I.Blend(J, ICON_SUBTRACT) + Blend(I, ICON_OR) + +// make this icon fully opaque--transparent pixels become black +/icon/proc/Opaque(background = "#000000") + SwapColor(null, background) + MapColors(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,1) + +// Change a grayscale icon into a white icon where the original color becomes the alpha +// I.e., black -> transparent, gray -> translucent white, white -> solid white +/icon/proc/BecomeAlphaMask() + SwapColor(null, "#000000ff") // don't let transparent become gray + MapColors(0,0,0,0.3, 0,0,0,0.59, 0,0,0,0.11, 0,0,0,0, 1,1,1,0) + +/icon/proc/UseAlphaMask(mask) + Opaque() + AddAlphaMask(mask) + +/icon/proc/AddAlphaMask(mask) + var/icon/M = new(mask) + M.Blend("#ffffff", ICON_SUBTRACT) + // apply mask + Blend(M, ICON_ADD) /* HSV format is represented as "#hhhssvv" or "#hhhssvvaa" @@ -318,57 +296,7 @@ icon Higher value means brighter color */ -proc/ReadRGB(rgb) - if(!rgb) return - - // interpret the HSV or HSVA value - var/i=1,start=1 - if(text2ascii(rgb) == 35) ++start // skip opening # - var/ch,which=0,r=0,g=0,b=0,alpha=0,usealpha - var/digits=0 - for(i=start, i<=length(rgb), ++i) - ch = text2ascii(rgb, i) - if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break - ++digits - if(digits == 8) break - - var/single = digits < 6 - if(digits != 3 && digits != 4 && digits != 6 && digits != 8) return - if(digits == 4 || digits == 8) usealpha = 1 - for(i=start, digits>0, ++i) - ch = text2ascii(rgb, i) - if(ch >= 48 && ch <= 57) ch -= 48 - else if(ch >= 65 && ch <= 70) ch -= 55 - else if(ch >= 97 && ch <= 102) ch -= 87 - else break - --digits - switch(which) - if(0) - r = (r << 4) | ch - if(single) - r |= r << 4 - ++which - else if(!(digits & 1)) ++which - if(1) - g = (g << 4) | ch - if(single) - g |= g << 4 - ++which - else if(!(digits & 1)) ++which - if(2) - b = (b << 4) | ch - if(single) - b |= b << 4 - ++which - else if(!(digits & 1)) ++which - if(3) - alpha = (alpha << 4) | ch - if(single) alpha |= alpha << 4 - - . = list(r, g, b) - if(usealpha) . += alpha - -proc/ReadHSV(hsv) +/proc/ReadHSV(hsv) if(!hsv) return // interpret the HSV or HSVA value @@ -393,234 +321,48 @@ proc/ReadHSV(hsv) --digits switch(which) if(0) - hue = (hue << 4) | ch + hue = BITSHIFT_LEFT(hue, 4) | ch if(digits == (usealpha ? 6 : 4)) ++which if(1) - sat = (sat << 4) | ch + sat = BITSHIFT_LEFT(sat, 4) | ch if(digits == (usealpha ? 4 : 2)) ++which if(2) - val = (val << 4) | ch + val = BITSHIFT_LEFT(val, 4) | ch if(digits == (usealpha ? 2 : 0)) ++which if(3) - alpha = (alpha << 4) | ch + alpha = BITSHIFT_LEFT(alpha, 4) | ch . = list(hue, sat, val) if(usealpha) . += alpha -proc/HSVtoRGB(hsv) - if(!hsv) return "#000000" - var/list/HSV = ReadHSV(hsv) - if(!HSV) return "#000000" - - var/hue = HSV[1] - var/sat = HSV[2] - var/val = HSV[3] - - // Compress hue into easier-to-manage range - hue -= hue >> 8 - if(hue >= 0x5fa) hue -= 0x5fa - - var/hi,mid,lo,r,g,b - hi = val - lo = round((255 - sat) * val / 255, 1) - mid = lo + round(abs(round(hue, 510) - hue) * (hi - lo) / 255, 1) - if(hue >= 765) - if(hue >= 1275) {r=hi; g=lo; b=mid} - else if(hue >= 1020) {r=mid; g=lo; b=hi } - else {r=lo; g=mid; b=hi } - else - if(hue >= 510) {r=lo; g=hi; b=mid} - else if(hue >= 255) {r=mid; g=hi; b=lo } - else {r=hi; g=mid; b=lo } - - return (HSV.len > 3) ? rgb(r,g,b,HSV[4]) : rgb(r,g,b) - -proc/RGBtoHSV(rgb) - if(!rgb) return "#0000000" - var/list/RGB = ReadRGB(rgb) - if(!RGB) return "#0000000" - - var/r = RGB[1] - var/g = RGB[2] - var/b = RGB[3] - var/hi = max(r,g,b) - var/lo = min(r,g,b) - - var/val = hi - var/sat = hi ? round((hi-lo) * 255 / hi, 1) : 0 - var/hue = 0 - - if(sat) - var/dir - var/mid - if(hi == r) - if(lo == b) {hue=0; dir=1; mid=g} - else {hue=1535; dir=-1; mid=b} - else if(hi == g) - if(lo == r) {hue=512; dir=1; mid=b} - else {hue=511; dir=-1; mid=r} - else if(hi == b) - if(lo == g) {hue=1024; dir=1; mid=r} - else {hue=1023; dir=-1; mid=g} - hue += dir * round((mid-lo) * 255 / (hi-lo), 1) - - return hsv(hue, sat, val, (RGB.len>3 ? RGB[4] : null)) - -proc/hsv(hue, sat, val, alpha) - if(hue < 0 || hue >= 1536) hue %= 1536 - if(hue < 0) hue += 1536 - if((hue & 0xFF) == 0xFF) - ++hue - if(hue >= 1536) hue = 0 - if(sat < 0) sat = 0 - if(sat > 255) sat = 255 - if(val < 0) val = 0 - if(val > 255) val = 255 - . = "#" - . += TO_HEX_DIGIT(hue >> 8) - . += TO_HEX_DIGIT(hue >> 4) - . += TO_HEX_DIGIT(hue) - . += TO_HEX_DIGIT(sat >> 4) - . += TO_HEX_DIGIT(sat) - . += TO_HEX_DIGIT(val >> 4) - . += TO_HEX_DIGIT(val) - if(!isnull(alpha)) - if(alpha < 0) alpha = 0 - if(alpha > 255) alpha = 255 - . += TO_HEX_DIGIT(alpha >> 4) - . += TO_HEX_DIGIT(alpha) - /* - Smooth blend between HSV colors + Blend two RGB colors in RGB color space amount=0 is the first color amount=1 is the second color amount=0.5 is directly between the two colors - - amount<0 or amount>1 are allowed */ -proc/BlendHSV(hsv1, hsv2, amount) - var/list/HSV1 = ReadHSV(hsv1) - var/list/HSV2 = ReadHSV(hsv2) - - // add missing alpha if needed - if(HSV1.len < HSV2.len) HSV1 += 255 - else if(HSV2.len < HSV1.len) HSV2 += 255 - var/usealpha = HSV1.len > 3 - - // normalize hsv values in case anything is screwy - if(HSV1[1] > 1536) HSV1[1] %= 1536 - if(HSV2[1] > 1536) HSV2[1] %= 1536 - if(HSV1[1] < 0) HSV1[1] += 1536 - if(HSV2[1] < 0) HSV2[1] += 1536 - if(!HSV1[3]) {HSV1[1] = 0; HSV1[2] = 0} - if(!HSV2[3]) {HSV2[1] = 0; HSV2[2] = 0} - - // no value for one color means don't change saturation - if(!HSV1[3]) HSV1[2] = HSV2[2] - if(!HSV2[3]) HSV2[2] = HSV1[2] - // no saturation for one color means don't change hues - if(!HSV1[2]) HSV1[1] = HSV2[1] - if(!HSV2[2]) HSV2[1] = HSV1[1] - - // Compress hues into easier-to-manage range - HSV1[1] -= HSV1[1] >> 8 - HSV2[1] -= HSV2[1] >> 8 - - var/hue_diff = HSV2[1] - HSV1[1] - if(hue_diff > 765) hue_diff -= 1530 - else if(hue_diff <= -765) hue_diff += 1530 - - var/hue = round(HSV1[1] + hue_diff * amount, 1) - var/sat = round(HSV1[2] + (HSV2[2] - HSV1[2]) * amount, 1) - var/val = round(HSV1[3] + (HSV2[3] - HSV1[3]) * amount, 1) - var/alpha = usealpha ? round(HSV1[4] + (HSV2[4] - HSV1[4]) * amount, 1) : null - - // normalize hue - if(hue < 0 || hue >= 1530) hue %= 1530 - if(hue < 0) hue += 1530 - // decompress hue - hue += round(hue / 255) - - return hsv(hue, sat, val, alpha) - -/* - Smooth blend between RGB colors - - amount=0 is the first color - amount=1 is the second color - amount=0.5 is directly between the two colors - - amount<0 or amount>1 are allowed - */ -proc/BlendRGB(rgb1, rgb2, amount) - var/list/RGB1 = ReadRGB(rgb1) - var/list/RGB2 = ReadRGB(rgb2) - - // add missing alpha if needed - if(RGB1.len < RGB2.len) RGB1 += 255 - else if(RGB2.len < RGB1.len) RGB2 += 255 - var/usealpha = RGB1.len > 3 - - var/r = round(RGB1[1] + (RGB2[1] - RGB1[1]) * amount, 1) - var/g = round(RGB1[2] + (RGB2[2] - RGB1[2]) * amount, 1) - var/b = round(RGB1[3] + (RGB2[3] - RGB1[3]) * amount, 1) - var/alpha = usealpha ? round(RGB1[4] + (RGB2[4] - RGB1[4]) * amount, 1) : null - - return isnull(alpha) ? rgb(r, g, b) : rgb(r, g, b, alpha) - -proc/BlendRGBasHSV(rgb1, rgb2, amount) - return HSVtoRGB(RGBtoHSV(rgb1), RGBtoHSV(rgb2), amount) - -proc/HueToAngle(hue) - // normalize hsv in case anything is screwy - if(hue < 0 || hue >= 1536) hue %= 1536 - if(hue < 0) hue += 1536 - // Compress hue into easier-to-manage range - hue -= hue >> 8 - return hue / (1530/360) - -proc/AngleToHue(angle) - // normalize hsv in case anything is screwy - if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360) - var/hue = angle * (1530/360) - // Decompress hue - hue += round(hue / 255) - return hue +/proc/BlendRGB(rgb1, rgb2, amount) + return gradient(rgb1, rgb2, index = amount) +/// Blend two RGB colors in HSV space +/proc/BlendHSV(rgb1, rgb2, amount) + return gradient(rgb1, rgb2, index = amount, space = COLORSPACE_HSV) // positive angle rotates forward through red->green->blue -proc/RotateHue(hsv, angle) - var/list/HSV = ReadHSV(hsv) - - // normalize hsv in case anything is screwy - if(HSV[1] >= 1536) HSV[1] %= 1536 - if(HSV[1] < 0) HSV[1] += 1536 - - // Compress hue into easier-to-manage range - HSV[1] -= HSV[1] >> 8 - - if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360) - HSV[1] = round(HSV[1] + angle * (1530/360), 1) - - // normalize hue - if(HSV[1] < 0 || HSV[1] >= 1530) HSV[1] %= 1530 - if(HSV[1] < 0) HSV[1] += 1530 - // decompress hue - HSV[1] += round(HSV[1] / 255) +/proc/RotateHue(rgb, angle) + . = rgb2num(rgb, COLORSPACE_HSV) + .[1] = (.[1] + angle) % 360 - return hsv(HSV[1], HSV[2], HSV[3], (HSV.len > 3 ? HSV[4] : null)) - -// Convert an rgb color to grayscale -proc/GrayScale(rgb) - var/list/RGB = ReadRGB(rgb) - var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11 - return (RGB.len > 3) ? rgb(gray, gray, gray, RGB[4]) : rgb(gray, gray, gray) +// Convert an rgb color to grayscale, preserving luminance +/proc/GrayScale(rgb) + var/list/HCY = rgb2num(rgb, COLORSPACE_HCY) + return rgb(hue = HCY[1], chroma = 0, y = HCY[3]) // Change grayscale color to black->tone->white range -proc/ColorTone(rgb, tone) - var/list/RGB = ReadRGB(rgb) - var/list/TONE = ReadRGB(tone) +/proc/ColorTone(rgb, tone) + var/list/RGB = rgb2num(rgb) + var/list/TONE = rgb2num(tone) var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11 var/tone_gray = TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11 @@ -635,231 +377,202 @@ as a single icon. Useful for when you want to manipulate an icon via the above a The _flatIcons list is a cache for generated icon files. */ -proc // Creates a single icon from a given /atom or /image. Only the first argument is required. - getFlatIcon(image/A, defdir=2, deficon=null, defstate="", defblend=BLEND_DEFAULT, always_use_defdir = 0) - // We start with a blank canvas, otherwise some icon procs crash silently - var/icon/flat = icon('icons/effects/effects.dmi', "icon_state"="nothing") // Final flattened icon - if(!A) - return flat - if(A.alpha <= 0) - return flat - var/noIcon = FALSE - - var/curicon - if(A.icon) - curicon = A.icon +// Creates a single icon from a given /atom or /image. Only the first argument is required. +/proc/getFlatIcon(image/A, defdir = SOUTH, deficon = null, defstate = "", defblend = BLEND_DEFAULT, always_use_defdir = FALSE) + // We start with a blank canvas, otherwise some icon procs crash silently + var/icon/flat = icon('icons/effects/effects.dmi', "icon_state"="nothing") // Final flattened icon + if(!A || A.alpha <= 0) + return flat + + var/curicon = A.icon || deficon + var/curstate = A.icon_state || defstate + var/curdir = (A.dir != defdir && !always_use_defdir) ? A.dir : defdir + var/curblend = (A.blend_mode == BLEND_DEFAULT) ? defblend : A.blend_mode + + if(curicon && !check_state_in_icon(curstate, curicon)) + if(check_state_in_icon("", curicon)) + curstate = "" else - curicon = deficon + curicon = null // Do not render this object. + + // Layers will be a sorted list of icons/overlays, based on the order in which they are displayed + var/list/layers = list() + var/image/copy + // Add the atom's icon itself, without pixel_x/y offsets. + if(curicon) + copy = image(icon = curicon, icon_state = curstate, layer = A.layer, dir = curdir) + copy.color = A.color + copy.alpha = A.alpha + copy.blend_mode = curblend + layers[copy] = A.layer + + // Loop through the underlays, then overlays, sorting them into the layers list + var/list/process = A.underlays // Current list being processed + var/pSet=0 // Which list is being processed: 0 = underlays, 1 = overlays + var/curIndex=1 // index of 'current' in list being processed + var/current // Current overlay being sorted + var/currentLayer // Calculated layer that overlay appears on (special case for FLOAT_LAYER) + var/compare // The overlay 'add' is being compared against + var/cmpIndex // The index in the layers list of 'compare' + while(TRUE) + if(curIndex<=process.len) + current = process[curIndex] + if(current) + currentLayer = current:layer + if(currentLayer<0) // Special case for FLY_LAYER + if(currentLayer <= -1000) return flat + if(pSet == 0) // Underlay + currentLayer = A.layer+currentLayer/1000 + else // Overlay + currentLayer = A.layer+(1000+currentLayer)/1000 + + // Sort add into layers list + for(cmpIndex=1,cmpIndex<=layers.len,cmpIndex++) + compare = layers[cmpIndex] + if(currentLayer < layers[compare]) // Associated value is the calculated layer + layers.Insert(cmpIndex,current) + layers[current] = currentLayer + break + if(cmpIndex>layers.len) // Reached end of list without inserting + layers[current]=currentLayer // Place at end + + curIndex++ + else if(pSet == 0) // Switch to overlays + curIndex = 1 + pSet = 1 + process = A.overlays + else // All done + break + + // Current dimensions of flattened icon + var/flatX1= 1 + var/flatX2= flat.Width() + var/flatY1= 1 + var/flatY2= flat.Height() + + // Dimensions of overlay being added + var/addX1 + var/addX2 + var/addY1 + var/addY2 + + var/icon/add // Icon of overlay being added + for(var/image/I as anything in layers) + + if(I.alpha == 0) + continue + + if(I == copy) // 'I' is an /image based on the object being flattened. + curblend = BLEND_OVERLAY + add = icon(I.icon, I.icon_state, I.dir) + // This checks for a silent failure mode of the icon routine. If the requested dir + // doesn't exist in this icon state it returns a 32x32 icon with 0 alpha. + if (I.dir != defdir && add.Width() == 32 && add.Height() == 32) + // Check every pixel for blank (computationally expensive, but the process is limited + // by the amount of film on the station, only happens when we hit something that's + // turned, and bails at the very first pixel it sees. + var/blankpixel; + for(var/y;y<=32;y++) + for(var/x;x<32;x++) + blankpixel = isnull(add.GetPixel(x,y)) + if(!blankpixel) + break + if(!blankpixel) + break + // If we ALWAYS returned a null (which happens when GetPixel encounters something with alpha 0) + if (blankpixel) + // Pull the default direction. + add = icon(I.icon, I.icon_state) + // 'I' is an appearance object. + else if(istype(A,/obj/machinery/atmospherics) && (I in A.underlays)) + add = getFlatIcon(new /image(I), I.dir, curicon, null, curblend, 1) + else + /* + The state var is null so that it uses the appearance's state, not ours or the default + Falling back to our state if state is null would be incorrect overlay logic (overlay with null state does not inherit it from parent to which it is attached) + + If icon is null on an overlay it will inherit the icon from the attached parent, so we _do_ pass curicon ... + but it does not do so if its icon_state is ""/null, so we check beforehand to exclude this + */ + add = getFlatIcon(new/image(I), curdir, (!I.icon_state && !I.icon) ? null : curicon, null, curblend, always_use_defdir) + + // Find the new dimensions of the flat icon to fit the added overlay + addX1 = min(flatX1, I.pixel_x + 1) + addX2 = max(flatX2, I.pixel_x + add.Width()) + addY1 = min(flatY1, I.pixel_y + 1) + addY2 = max(flatY2, I.pixel_y + add.Height()) + + if(addX1 != flatX1 || addX2 != flatX2 || addY1 != flatY1 || addY2 != flatY2) + // Resize the flattened icon so the new icon fits + flat.Crop(addX1-flatX1+1, addY1-flatY1+1, addX2-flatX1+1, addY2-flatY1+1) + flatX1 = addX1 + flatX2 = addX2 + flatY1 = addY1 + flatY2 = addY2 + + var/iconmode + if(I in A.overlays) + iconmode = ICON_OVERLAY + else if(I in A.underlays) + iconmode = ICON_UNDERLAY + else + iconmode = blendMode2iconMode(curblend) + // Blend the overlay into the flattened icon + flat.Blend(add, iconmode, I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1) - if(!curicon) - noIcon = TRUE // Do not render this object. + if(A.color) - var/curstate - if(A.icon_state) - curstate = A.icon_state - else - curstate = defstate + // Probably a colour matrix, could also check length(A.color) == 20 if color normalization becomes more complex in the future. + if(islist(A.color)) + flat.MapColors(arglist(A.color)) - if(!noIcon && !(curstate in icon_states(curicon))) - if("" in icon_states(curicon)) - curstate = "" - else - noIcon = TRUE // Do not render this object. + // Probably a valid color, could check length_char(A.color) == 7 if color normalization becomes etc etc etc. + else if(istext(A.color)) + flat.Blend(A.color, ICON_MULTIPLY) - var/curdir - if(A.dir != 2 && !always_use_defdir) - curdir = A.dir - else - curdir = defdir + // Colour matrices track/apply alpha changes in MapColors() above, so only apply if color isn't a matrix. + if(A.alpha < 255 && !islist(A.color)) + flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY) - var/curblend - if(A.blend_mode == BLEND_DEFAULT) - curblend = defblend - else - curblend = A.blend_mode - - // Layers will be a sorted list of icons/overlays, based on the order in which they are displayed - var/list/layers = list() - var/image/copy - // Add the atom's icon itself, without pixel_x/y offsets. - if(!noIcon) - copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir) - copy.color = A.color - copy.alpha = A.alpha - copy.blend_mode = curblend - layers[copy] = A.layer - - // Loop through the underlays, then overlays, sorting them into the layers list - var/list/process = A.underlays // Current list being processed - var/pSet=0 // Which list is being processed: 0 = underlays, 1 = overlays - var/curIndex=1 // index of 'current' in list being processed - var/current // Current overlay being sorted - var/currentLayer // Calculated layer that overlay appears on (special case for FLOAT_LAYER) - var/compare // The overlay 'add' is being compared against - var/cmpIndex // The index in the layers list of 'compare' - while(TRUE) - if(curIndex<=process.len) - current = process[curIndex] - if(current) - currentLayer = current:layer - if(currentLayer<0) // Special case for FLY_LAYER - if(currentLayer <= -1000) return flat - if(pSet == 0) // Underlay - currentLayer = A.layer+currentLayer/1000 - else // Overlay - currentLayer = A.layer+(1000+currentLayer)/1000 - - // Sort add into layers list - for(cmpIndex=1,cmpIndex<=layers.len,cmpIndex++) - compare = layers[cmpIndex] - if(currentLayer < layers[compare]) // Associated value is the calculated layer - layers.Insert(cmpIndex,current) - layers[current] = currentLayer - break - if(cmpIndex>layers.len) // Reached end of list without inserting - layers[current]=currentLayer // Place at end - - curIndex++ - else if(pSet == 0) // Switch to overlays - curIndex = 1 - pSet = 1 - process = A.overlays - else // All done - break - - var/icon/add // Icon of overlay being added - - // Current dimensions of flattened icon - var/flatX1=1 - var/flatX2=flat.Width() - var/flatY1=1 - var/flatY2=flat.Height() - // Dimensions of overlay being added - var/addX1 - var/addX2 - var/addY1 - var/addY2 - - for(var/I in layers) - - if(I:alpha == 0) - continue + return icon(flat, "", SOUTH) - if(I == copy) // 'I' is an /image based on the object being flattened. - curblend = BLEND_OVERLAY - add = icon(I:icon, I:icon_state, I:dir) - // This checks for a silent failure mode of the icon routine. If the requested dir - // doesn't exist in this icon state it returns a 32x32 icon with 0 alpha. - if (I:dir != SOUTH && add.Width() == 32 && add.Height() == 32) - // Check every pixel for blank (computationally expensive, but the process is limited - // by the amount of film on the station, only happens when we hit something that's - // turned, and bails at the very first pixel it sees. - var/blankpixel; - for(var/y;y<=32;y++) - for(var/x;x<32;x++) - blankpixel = isnull(add.GetPixel(x,y)) - if(!blankpixel) - break - if(!blankpixel) - break - // If we ALWAYS returned a null (which happens when GetPixel encounters something with alpha 0) - if (blankpixel) - // Pull the default direction. - add = icon(I:icon, I:icon_state) - else // 'I' is an appearance object. - if(istype(A,/obj/machinery/atmospherics) && (I in A.underlays)) - var/image/Im = I - add = getFlatIcon(new/image(I), Im.dir, curicon, curstate, curblend, 1) - else - add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, always_use_defdir) - - // Find the new dimensions of the flat icon to fit the added overlay - addX1 = min(flatX1, I:pixel_x+1) - addX2 = max(flatX2, I:pixel_x+add.Width()) - addY1 = min(flatY1, I:pixel_y+1) - addY2 = max(flatY2, I:pixel_y+add.Height()) - - if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2) - // Resize the flattened icon so the new icon fits - flat.Crop(addX1-flatX1+1, addY1-flatY1+1, addX2-flatX1+1, addY2-flatY1+1) - flatX1=addX1;flatX2=addX2 - flatY1=addY1;flatY2=addY2 - var/iconmode - if(I in A.overlays) - iconmode = ICON_OVERLAY - else if(I in A.underlays) - iconmode = ICON_UNDERLAY - else - iconmode = blendMode2iconMode(curblend) - // Blend the overlay into the flattened icon - flat.Blend(add, iconmode, I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1) - - if(A.color) - flat.Blend(A.color, ICON_MULTIPLY) - if(A.alpha < 255) - flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY) - - return icon(flat, "", SOUTH) - - getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N - var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. - for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. - if(I:layer>A.layer) continue//If layer is greater than what we need, skip it. - var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects. - //Also, icons cannot directly set icon_state. Slower than changing variables but whatever. - alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay. - return alpha_mask//And now return the mask. - -/mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay. - var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays. - //Now we need to culculate overlays+underlays and add them together to form an image for a mask. - //var/icon/alpha_mask = getFlatIcon(src)//Accurate but SLOW. Not designed for running each tick. Could have other uses I guess. - var/icon/alpha_mask = getIconMask(src)//Which is why I created that proc. Also a little slow since it's blending a bunch of icons together but good enough. - opacity_icon.AddAlphaMask(alpha_mask)//Likely the main source of lag for this proc. Probably not designed to run each tick. - opacity_icon.ChangeOpacity(0.4)//Front end for MapColors so it's fast. 0.5 means half opacity and looks the best in my opinion. - for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it. - var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like. - switch(i)//Now to determine offset so the result is somewhat blurred. - if(1) I.pixel_x-- - if(2) I.pixel_x++ - if(3) I.pixel_y-- - if(4) I.pixel_y++ - overlays += I//And finally add the overlay. +/proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N + var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. + for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. + if(I:layer>A.layer) continue//If layer is greater than what we need, skip it. + var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects. + //Also, icons cannot directly set icon_state. Slower than changing variables but whatever. + alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay. + return alpha_mask//And now return the mask. #define HOLOPAD_SHORT_RANGE 1 //For determining the color of holopads based on whether they're short or long range. #define HOLOPAD_LONG_RANGE 2 -/proc/getHologramIcon(icon/A, safety=1, noDecolor=FALSE, var/hologram_color=HOLOPAD_SHORT_RANGE)//If safety is on, a new icon is not created. +/proc/getHologramIcon(icon/A, safety=1, noDecolor=FALSE, var/hologram_color=HOLOPAD_SHORT_RANGE, var/custom_tone)//If safety is on, a new icon is not created. var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon. if (noDecolor == FALSE) if(hologram_color == HOLOPAD_LONG_RANGE) flat_icon.ColorTone(rgb(225,223,125)) //Light yellow if it's a call to a long-range holopad. - else + else if(!custom_tone) flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish. + else + flat_icon.ColorTone(rgb(HEX_RED(custom_tone), HEX_GREEN(custom_tone), HEX_BLUE(custom_tone))) flat_icon.ChangeOpacity(0.5)//Make it half transparent. var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanline-[hologram_color]")//Scanline effect. flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. return flat_icon -//For photo camera. -/proc/build_composite_icon(atom/A) - var/icon/composite = icon(A.icon, A.icon_state, A.dir, 1) - for(var/O in A.overlays) - var/image/I = O - composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY) - return composite - -proc/adjust_brightness(var/color, var/value) +/proc/adjust_brightness(var/color, var/value) if (!color) return "#ffffff" if (!value) return color - var/list/RGB = ReadRGB(color) - RGB[1] = Clamp(RGB[1]+value,0,255) - RGB[2] = Clamp(RGB[2]+value,0,255) - RGB[3] = Clamp(RGB[3]+value,0,255) + var/list/RGB = rgb2num(color) + RGB[1] = clamp(RGB[1]+value,0,255) + RGB[2] = clamp(RGB[2]+value,0,255) + RGB[3] = clamp(RGB[3]+value,0,255) return rgb(RGB[1],RGB[2],RGB[3]) -proc/sort_atoms_by_layer(var/list/atoms) +/proc/sort_atoms_by_layer(var/list/atoms) // Comb sort icons based on levels var/list/result = atoms.Copy() var/gap = result.len @@ -877,53 +590,76 @@ proc/sort_atoms_by_layer(var/list/atoms) result.Swap(i, gap + i) swapped = 1 return result -/* -generate_image function generates image of specified range and location -arguments tx, ty, tz are target coordinates (requred), range defines render distance to opposite corner (requred) -cap_mode is capturing mode (optional), user is capturing mob (requred only wehen cap_mode = CAPTURE_MODE_REGULAR), -lighting determines lighting capturing (optional), suppress_errors suppreses errors and continues to capture (optional). +/** + * Generate_image function generates image of specified range and location: + * * arguments `target_x`, `target_y`, `target_z` are target coordinates (requred). + * * `range` defines render distance to opposite corner (requred). + * * lighting determines lighting capturing (optional), suppress_errors suppreses errors and continues to capture (optional). + * * `checker` is a person from which side will be perfored capture check, should be `/mob/living` target_ype. */ -proc/generate_image(var/tx as num, var/ty as num, var/tz as num, var/range as num, var/cap_mode = CAPTURE_MODE_PARTIAL, var/mob/living/user, var/lighting = 1, var/suppress_errors = 1) - var/list/turfstocapture = list() - //Lines below determine what tiles will be rendered - for(var/xoff = 0 to range) - for(var/yoff = 0 to range) - var/turf/T = locate(tx + xoff,ty + yoff,tz) - if(T) - if(cap_mode == CAPTURE_MODE_REGULAR) - if(user.can_capture_turf(T)) - turfstocapture.Add(T) - continue - else - turfstocapture.Add(T) - else - //Capture includes non-existan turfs - if(!suppress_errors) - return - //Lines below determine what objects will be rendered - var/list/atoms = list() - for(var/turf/T in turfstocapture) - atoms.Add(T) - for(var/atom/A in T) - if(istype(A, /atom/movable/lighting_overlay) && lighting) //Special case for lighting - atoms.Add(A) +/proc/create_area_image(target_x, target_y, target_z, range, show_lighting = TRUE, mob/living/checker) + // They're all should be set. + ASSERT(target_x) + ASSERT(target_y) + ASSERT(target_z) + ASSERT(range) + + // - Collecting list of turfs to render - + + var/list/render_turfs = list() + for(var/x_offset = 0 to range) + for(var/y_offset = 0 to range) + var/turf/T = locate(target_x + x_offset, target_y + y_offset, target_z) + if(checker && !checker?.can_capture_turf(T)) + continue + else if(T) + render_turfs.Add(T) + + // - Collecting list of atoms to render - + + var/list/render_atoms = list() + // This is a workaround for the lighting planemaster not being factored in. + // If it's ever removed, or if a better way is found, please replace this. + var/list/render_lighting = list() + for(var/turf/T as anything in render_turfs) + render_atoms.Add(T) + + for(var/atom/A as anything in T) + // We need to handle lighting separately if we're including it, and if not, skip it entirely. + if(istype(A, /atom/movable/lighting_overlay)) + if(show_lighting) + render_lighting.Add(A) continue - if(A.invisibility) continue - atoms.Add(A) - //Lines below actually render all colected data - atoms = sort_atoms_by_layer(atoms) - var/icon/cap = icon('icons/effects/96x96.dmi', "") - cap.Scale(range*32, range*32) - cap.Blend("#000", ICON_OVERLAY) - for(var/atom/A in atoms) - if(A) - var/icon/img = getFlatIcon(A) - if(istype(img, /icon)) - if(istype(A, /mob/living) && A:lying) - img.BecomeLying() - var/xoff = (A.x - tx) * 32 - var/yoff = (A.y - ty) * 32 - cap.Blend(img, blendMode2iconMode(A.blend_mode), A.pixel_x + xoff, A.pixel_y + yoff) - - return cap + if(!A.alpha || (A.invisibility > SEE_INVISIBLE_LIVING)) + continue + + render_atoms.Add(A) + + // - Performing rendering with collected atoms in list - + + render_atoms = sort_atoms_by_layer(render_atoms) + var/icon/capture = icon('icons/effects/96x96.dmi', "") + capture.Scale(range * world.icon_size, range * world.icon_size) + capture.Blend(COLOR_BLACK, ICON_OVERLAY) + for(var/atom/A as anything in render_atoms) + var/icon/atom_icon = getFlatIcon(A) + + if(ismob(A)) + var/mob/M = A + if(M.current_posture.prone) + atom_icon.BecomeLying() + + var/x_offset = (A.x - target_x) * world.icon_size + var/y_offset = (A.y - target_y) * world.icon_size + capture.Blend(atom_icon, blendMode2iconMode(A.blend_mode), A.pixel_x + x_offset, A.pixel_y + y_offset) + + // TODO: for custom exposure/flash/etc simulation on the camera, you could set the alpha on the overlay copy icons here + if(show_lighting) + for(var/atom/movable/lighting_overlay/lighting_overlay as anything in render_lighting) + var/icon/lighting_overlay_icon = getFlatIcon(lighting_overlay) + var/x_offset = (lighting_overlay.x - target_x) * world.icon_size + var/y_offset = (lighting_overlay.y - target_y) * world.icon_size + capture.Blend(lighting_overlay_icon, ICON_MULTIPLY, lighting_overlay.pixel_x + x_offset, lighting_overlay.pixel_y + y_offset) + + return capture diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index 47c8c60df091..a39367a43233 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -5,63 +5,189 @@ * Sorting */ +// Determiner constants +#define DET_NONE BITFLAG(0) +#define DET_DEFINITE BITFLAG(1) //! the +#define DET_INDEFINITE BITFLAG(2) //! a, an, some + /* * Misc */ //Returns a list in plain english as a string -/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "," ) +/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = ",", summarize = FALSE) + + if(!length(input)) + return nothing_text + + if(summarize) + var/list/thing_gender = list() + var/list/thing_count = list() + for(var/atom/thing as anything in input) + input -= thing + var/thing_string = isatom(thing) ? thing.name : "\proper [thing]" + thing_count[thing_string] += 1 + if(ismob(thing)) + var/mob/mob_thing = thing + thing_gender[thing_string] = mob_thing.get_gender() + else + thing_gender[thing_string] = isatom(thing) ? thing.gender : NEUTER + input = list() + for(var/thing_string in thing_count) + if(thing_count[thing_string] == 1) + input += "\the [thing_string]" + else + input += "[thing_count[thing_string]] [thing_gender[thing_string] == PLURAL ? text_make_plural(thing_string) : thing_string]" + switch(length(input)) - if(0) return nothing_text - if(1) return "[input[1]]" - if(2) return "[input[1]][and_text][input[2]]" - else return "[jointext(input, comma_text, 1, -1)][final_comma_text][and_text][input[input.len]]" - -//Return either pick(list) or null if list is not of type /list or is empty -proc/safepick(list/list) - if(!islist(list) || !list.len) - return - return pick(list) + if(1) + return "[input[1]]" + if(2) + return "[input[1]][and_text][input[2]]" + else + return "[jointext(input, comma_text, 1, -1)][final_comma_text][and_text][input[input.len]]" + +//Returns a newline-separated list that counts equal-ish items, outputting count and item names, optionally with icons and specific determiners +/proc/counting_english_list(list/input, output_icons = TRUE, determiners = DET_NONE, nothing_text = "nothing", line_prefix = "", first_item_prefix = "\n", last_item_suffix = "\n", and_text = "\n", comma_text = "\n", final_comma_text = "") + var/list/counts = list() // counted input items + var/list/items = list() // actual objects for later reference (for icons and formatting) + + // count items + for(var/item in input) + var/name = "[item]" // index items by name; usually works fairly well for loose equality + if(name in counts) + counts[name]++ + else + counts[name] = 1 + items.Add(item) -//Checks if the list is empty -proc/isemptylist(list/list) - if(!list.len) - return 1 - return 0 + // assemble the output list + var/list/out = list() + var/i = 0 + for(var/item in items) + var/name = "[item]" + var/count = counts[name] + var/item_str = line_prefix + if(count > 1) + item_str += "[count]x " + + if(isatom(item)) + // atoms/items/objects can be pretty and whatnot + var/atom/A = item + if(output_icons && isicon(A.icon) && !ismob(A)) // mobs tend to have unusable icons + item_str += "[html_icon(A)] " + switch(determiners) + if(DET_NONE) item_str += A.name + if(DET_DEFINITE) item_str += "\the [A]" + if(DET_INDEFINITE) item_str += "\a [A]" + else item_str += name + else + // non-atoms use plain string conversion + item_str += name + + if(i == 0) + item_str = first_item_prefix + item_str + if(i == items.len - 1) + item_str = item_str + last_item_suffix + + out.Add(item_str) + i++ + + // finally return the list using regular english_list builder + return english_list(out, nothing_text, and_text, comma_text, final_comma_text) + +//A "preset" for counting_english_list that displays the list "inline" (comma separated) +/proc/inline_counting_english_list(list/input, output_icons = TRUE, determiners = DET_NONE, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "", line_prefix = "", first_item_prefix = "", last_item_suffix = "") + return counting_english_list(input, output_icons, determiners, nothing_text, line_prefix, first_item_prefix, last_item_suffix, and_text, comma_text, final_comma_text) //Checks for specific types in a list -/proc/is_type_in_list(var/atom/A, var/list/L) - for(var/type in L) - if(istype(A, type)) - return 1 - return 0 +/proc/is_type_in_list(datum/thing, list/type_list) + if(!length(type_list) || !istype(thing)) + return FALSE + for(var/check_type in type_list) + if(istype(thing, check_type)) + return TRUE + return FALSE //Checks for specific paths in a list -/proc/is_path_in_list(var/path, var/list/L) - for(var/type in L) - if(ispath(path, type)) - return 1 - return 0 +/proc/is_path_in_list(var/check_path, list/type_list) + if(!length(type_list) || !ispath(check_path)) + return FALSE + for(var/check_type in type_list) + if(ispath(check_path, check_type)) + return TRUE + return FALSE + +//returns a new list with only atoms that are in typecache atoms +/proc/typecache_filter_list(list/atoms, list/typecache) + . = list() + for(var/thing in atoms) + var/atom/A = thing + if (typecache[A.type]) + . += A + +/proc/typecache_filter_list_reverse(list/atoms, list/typecache) + . = list() + for(var/thing in atoms) + var/atom/A = thing + if(!typecache[A.type]) + . += A + +/proc/typecache_filter_multi_list_exclusion(list/atoms, list/typecache_include, list/typecache_exclude) + . = list() + for(var/thing in atoms) + var/atom/A = thing + if(typecache_include[A.type] && !typecache_exclude[A.type]) + . += A + +/proc/typecache_first_match(list/target, list/typecache) + for (var/thing in target) + var/datum/D = thing + if (typecache[D.type]) + return D + +//Like typesof() or subtypesof(), but returns a typecache instead of a list +/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE) + if(ispath(path)) + var/list/types = list() + if(only_root_path) + types = list(path) + else + types = ignore_root_path ? subtypesof(path) : typesof(path) + var/list/typelist = list() + for(var/T in types) + typelist[T] = TRUE + return typelist + else if(islist(path)) + var/list/pathlist = path + var/list/typelist = list() + if(ignore_root_path) + for(var/P in pathlist) + for(var/T in subtypesof(P)) + typelist[T] = TRUE + else + for(var/P in pathlist) + if(only_root_path) + typelist[P] = TRUE + else + for(var/T in typesof(P)) + typelist[T] = TRUE + return typelist + +//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches') +/proc/is_type_in_typecache(atom/A, list/cache) + if(!LAZYLEN(cache) || !A) + return 0 + return cache[A.type] + -/proc/instances_of_type_in_list(var/atom/A, var/list/L) +/proc/instances_of_type_in_list(var/atom/A, var/list/target_list) var/instances = 0 - for(var/type in L) + for(var/type in target_list) if(istype(A, type)) instances++ return instances -//Empties the list by .Cut(). Setting lenght = 0 has been confirmed to leak references. -proc/clearlist(var/list/L) - if(islist(L)) - L.Cut() - -//Removes any null entries from the list -proc/listclearnulls(list/list) - if(istype(list)) - while(null in list) - list -= null - return - /* * Returns list containing all the entries from first list that are not present in second. * If skiprep = 1, repeated elements are treated as one. @@ -82,6 +208,8 @@ proc/listclearnulls(list/list) /* Two lists may be different (A!=B) even if they have the same elements. This actually tests if they have the same entries and values. +This will handle list values in associative lists, but cannot handle +non-associative list equivalence across different refs. */ /proc/same_entries(var/list/first, var/list/second) if(!islist(first) || !islist(second)) @@ -89,7 +217,16 @@ This actually tests if they have the same entries and values. if(length(first) != length(second)) return 0 for(var/entry in first) - if(!(entry in second) || (first[entry] != second[entry])) + if(!(entry in second)) + return 0 + var/first_entry = first[entry] + if(islist(first_entry)) + var/second_entry = second[entry] + if(!islist(second_entry)) + return 0 + if(!same_entries(first_entry, second_entry)) + return 0 + else if(first_entry != second[entry]) return 0 return 1 /* @@ -136,17 +273,17 @@ Checks if a list has the same entries and values as an element of big. .[key] = call(merge_method)(.[key], b_value) //Pretends to pick an element based on its weight but really just seems to pick a random element. -/proc/pickweight(list/L) +/proc/pickweight(list/target_list) var/total = 0 var/item - for (item in L) - if (!L[item]) - L[item] = 1 - total += L[item] + for (item in target_list) + if (!target_list[item]) + target_list[item] = 1 + total += target_list[item] total = rand(1, total) - for (item in L) - total -=L [item] + for (item in target_list) + total -= target_list[item] if (total <= 0) return item @@ -169,184 +306,93 @@ Checks if a list has the same entries and values as an element of big. return null //Returns the first element from the list and removes it from the list -/proc/popleft(list/L) - if(length(L)) - . = L[1] - L.Cut(1,2) +/proc/popleft(list/target_list) + if(length(target_list)) + . = target_list[1] + target_list.Cut(1,2) //Returns the next element in parameter list after first appearance of parameter element. If it is the last element of the list or not present in list, returns first element. -/proc/next_in_list(element, list/L) - for(var/i=1, i= target_list.len) + return target_list[1] + return target_list[i+1] + return target_list[1] + +//Returns the previous element in parameter list after first appearance of parameter element. If it is the first element of the list or not present in list, returns first element. +/proc/previous_in_list(element, list/target_list) + for(var/i = 1 to target_list.len) + if(target_list[i] == element) + if(i <= 1) + return target_list[target_list.len] + return target_list[i-1] + return target_list[target_list.len] /* * Sorting */ //Reverses the order of items in the list -/proc/reverselist(list/L) +/proc/reverselist(list/target_list) var/list/output = list() - if(L) - for(var/i = L.len; i >= 1; i--) - output += L[i] + if(target_list) + for(var/i = target_list.len; i >= 1; i--) + output += target_list[i] return output //Randomize: Return the list in a random order -/proc/shuffle(var/list/L) - if(!L) +/proc/shuffle(var/list/target_list) + if(!target_list) return - L = L.Copy() + target_list = target_list.Copy() - for(var/i=1; i 0) ? i : i+1 + if(i == 1 || i == target_list.len) // Edge cases + return (call(cmp)(target_list[i],A) > 0) ? i : i+1 else return i -/proc/dd_sortedObjectList(var/list/L, var/cache=list()) - if(L.len < 2) - return L - var/middle = L.len / 2 + 1 // Copy is first,second-1 - return dd_mergeObjectList(dd_sortedObjectList(L.Copy(0,middle), cache), dd_sortedObjectList(L.Copy(middle), cache), cache) //second parameter null = to end of list +/proc/dd_sortedObjectList(var/list/target_list, var/cache=list()) + if(target_list.len < 2) + return target_list + var/middle = target_list.len / 2 + 1 // Copy is first,second-1 + return dd_mergeObjectList(dd_sortedObjectList(target_list.Copy(0,middle), cache), dd_sortedObjectList(target_list.Copy(middle), cache), cache) //second parameter null = to end of list -/proc/dd_mergeObjectList(var/list/L, var/list/R, var/list/cache) - var/Li=1 - var/Ri=1 +/proc/dd_mergeObjectList(var/list/target_list, var/list/right, var/list/cache) + var/left_index=1 + var/right_index=1 var/list/result = new() - while(Li <= L.len && Ri <= R.len) - var/LLi = L[Li] - var/RRi = R[Ri] + while(left_index <= target_list.len && right_index <= right.len) + var/LLi = target_list[left_index] + var/RRi = right[right_index] var/LLiV = cache[LLi] var/RRiV = cache[RRi] if(!LLiV) @@ -457,31 +487,31 @@ Checks if a list has the same entries and values as an element of big. RRiV = RRi:dd_SortValue() cache[RRi] = RRiV if(LLiV < RRiV) - result += L[Li++] + result += target_list[left_index++] else - result += R[Ri++] + result += right[right_index++] - if(Li <= L.len) - return (result + L.Copy(Li, 0)) - return (result + R.Copy(Ri, 0)) + if(left_index <= target_list.len) + return (result + target_list.Copy(left_index, 0)) + return (result + right.Copy(right_index, 0)) // Insert an object into a sorted list, preserving sortedness -/proc/dd_insertObjectList(var/list/L, var/O) +/proc/dd_insertObjectList(var/list/target_list, var/O) var/min = 1 - var/max = L.len + 1 + var/max = target_list.len + 1 var/Oval = O:dd_SortValue() while(1) var/mid = min+round((max-min)/2) if(mid == max) - L.Insert(mid, O) + target_list.Insert(mid, O) return - var/Lmid = L[mid] + var/Lmid = target_list[mid] var/midval = Lmid:dd_SortValue() if(Oval == midval) - L.Insert(mid, O) + target_list.Insert(mid, O) return else if(Oval < midval) max = mid @@ -547,7 +577,7 @@ proc/dd_sortedObjectList(list/incoming) return sorted_list */ -proc/dd_sortedtextlist(list/incoming, case_sensitive = 0) +/proc/dd_sortedtextlist(list/incoming, case_sensitive = 0) // Returns a new list with the text values sorted. // Use binary search to order by sortValue. // This works by going to the half-point of the list, seeing if the node in question is higher or lower cost, @@ -605,12 +635,6 @@ proc/dd_sortedtextlist(list/incoming, case_sensitive = 0) sorted_text += list_bottom return sorted_text - -proc/dd_sortedTextList(list/incoming) - var/case_sensitive = 1 - return dd_sortedtextlist(incoming, case_sensitive) - - /datum/proc/dd_SortValue() return "[src]" @@ -623,27 +647,29 @@ proc/dd_sortedTextList(list/incoming) /datum/alarm/dd_SortValue() return "[sanitize_old(last_name)]" -//creates every subtype of prototype (excluding prototype) and adds it to list L. -//if no list/L is provided, one is created. -/proc/init_subtypes(prototype, list/L) - if(!istype(L)) L = list() +//creates every subtype of prototype (excluding prototype) and adds it to list target_list. +//if no list/target_list is provided, one is created. +/proc/init_subtypes(prototype, list/target_list) + if(!islist(target_list)) + target_list = list() for(var/path in subtypesof(prototype)) - L += new path() - return L - -//creates every subtype of prototype (excluding prototype) and adds it to list L as a type/instance pair. -//if no list/L is provided, one is created. -/proc/init_subtypes_assoc(prototype, list/L) - if(!istype(L)) L = list() + target_list += new path() + return target_list + +//creates every subtype of prototype (excluding prototype) and adds it to list target_list as a type/instance pair. +//if no list/target_list is provided, one is created. +/proc/init_subtypes_assoc(prototype, list/target_list) + if(!islist(target_list)) + target_list = list() for(var/path in subtypesof(prototype)) - L[path] = new path() - return L + target_list[path] = new path() + return target_list #define listequal(A, B) (A.len == B.len && !length(A^B)) -/proc/filter_list(var/list/L, var/type) +/proc/filter_list(var/list/target_list, var/type) . = list() - for(var/entry in L) + for(var/entry in target_list) if(istype(entry, type)) . += entry @@ -655,44 +681,35 @@ proc/dd_sortedTextList(list/incoming) values += value -/proc/duplicates(var/list/L) +/proc/duplicates(var/list/target_list) . = list() var/list/checked = list() - for(var/value in L) + for(var/value in target_list) if(value in checked) . |= value else checked += value -/proc/assoc_by_proc(var/list/plain_list, var/get_initial_value) - . = list() - for(var/entry in plain_list) - .[call(get_initial_value)(entry)] = entry - -/proc/get_initial_name(var/atom/atom_type) - var/atom/A = atom_type - return initial(A.name) - //Move a single element from position fromIndex within a list, to position toIndex //All elements in the range [1,toIndex) before the move will be before the pivot afterwards -//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards +//All elements in the range [toIndex, target_list.len+1) before the move will be after the pivot afterwards //In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages. -//fromIndex and toIndex must be in the range [1,L.len+1] +//fromIndex and toIndex must be in the range [1,target_list.len+1] //This will preserve associations ~Carnie -/proc/moveElement(list/L, fromIndex, toIndex) +/proc/moveElement(list/target_list, fromIndex, toIndex) if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move return if(fromIndex > toIndex) ++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one - L.Insert(toIndex, null) - L.Swap(fromIndex, toIndex) - L.Cut(fromIndex, fromIndex+1) + target_list.Insert(toIndex, null) + target_list.Swap(fromIndex, toIndex) + target_list.Cut(fromIndex, fromIndex+1) //Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex) //Same as moveElement but for ranges of elements //This will preserve associations ~Carnie -/proc/moveRange(list/L, fromIndex, toIndex, len=1) +/proc/moveRange(list/target_list, fromIndex, toIndex, len=1) var/distance = abs(toIndex - fromIndex) if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements if(fromIndex <= toIndex) @@ -700,33 +717,33 @@ proc/dd_sortedTextList(list/incoming) fromIndex += len //we want to shift left instead of right for(var/i=0, i toIndex) fromIndex += len for(var/i=0, i 0 && index <= list.len) // Returns the first key where T fulfills ispath -/proc/get_ispath_key(var/list/L, var/T) - for(var/key in L) +/proc/get_ispath_key(var/list/target_list, var/T) + for(var/key in target_list) if(ispath(T, key)) return key // Gets the first instance that is of the given type (strictly) -/proc/get_instance_of_strict_type(var/list/L, var/T) - for(var/key in L) +/proc/get_instance_of_strict_type(var/list/target_list, var/T) + for(var/key in target_list) var/atom/A = key if(A.type == T) return A -var/list/json_cache = list() +var/global/list/json_cache = list() /proc/cached_json_decode(var/json_to_decode) - if(!json_to_decode || !length(json_to_decode)) - return list() - try - if(isnull(global.json_cache[json_to_decode])) - global.json_cache[json_to_decode] = json_decode(json_to_decode) - . = global.json_cache[json_to_decode] - catch(var/exception/e) - log_error("Exception during JSON decoding ([json_to_decode]): [e]") - return list() + if(length(json_to_decode)) + try + if(isnull(global.json_cache[json_to_decode])) + global.json_cache[json_to_decode] = json_decode(json_to_decode) + var/list/decoded = global.json_cache[json_to_decode] + if(islist(decoded)) // To prevent cache mutation. + return deepCopyList(decoded) + else if(decoded) + return decoded + catch(var/exception/e) + log_error("Exception during JSON decoding ([json_to_decode]): [EXCEPTION_TEXT(e)]") + return list() + +/proc/load_text_from_directory(var/directory, var/expected_extension = ".txt", var/recursive = TRUE) + + if(!directory) + return list( + "files" = list(), + "item_count" = 0, + "dir_count" = 0 + ) + + if(copytext(directory, -1) != "/") + directory += "/" + + var/list/walked_directories = list() + var/list/loaded_files = list() + var/dir_count = 0 + var/item_count = 0 + + // Use a while loop so we can recurse over subdirectories. + var/list/directories_to_check = list(directory) + // Cache the extension length so we can save some time when checking for matches. + expected_extension = trim(lowertext(expected_extension)) + var/expected_extension_length = -(length(expected_extension)) + while(length(directories_to_check)) + + // Check each directory only once to avoid wasted effort. + var/checkdir = directories_to_check[1] + directories_to_check -= checkdir + walked_directories += checkdir + + // Skip an examples directory if provided. + if(checkdir == "[directory]examples/") + continue + + // Iterate the file list. + for(var/checkfile in flist(checkdir)) + checkfile = "[checkdir][checkfile]" + // This is a directory, if we're recursing we want to go down this rabbit hole (unless we've already seen this dir via symlink). + if(copytext(checkfile, -1) == "/") + if(recursive && !(checkfile in walked_directories)) + directories_to_check += checkfile + dir_count++ + continue + // Not a file we want, continue on. + if(expected_extension && lowertext(copytext(checkfile, expected_extension_length)) != expected_extension) + continue + // Fail on duplicates. + // TODO: maybe aggregate them? checkfile is a fully qualified path so I can't see any real world case for overlap other than symlink stuff. + if(checkfile in loaded_files) + PRINT_STACK_TRACE("Duplicate file load for [checkfile].") + continue + try + // Actually load the file now. + loaded_files[checkfile] = safe_file2text(checkfile) + item_count++ + catch(var/exception/e) + PRINT_STACK_TRACE("Exception loading [checkfile]: [EXCEPTION_TEXT(e)]") + + // Return a manifest for further processing. + return list( + "files" = loaded_files, + "item_count" = item_count, + "dir_count" = dir_count + ) + +/// Is this a dense (all keys have non-null values) associative list with at least one entry? +/proc/is_dense_assoc(var/list/target_list) + return length(target_list) > 0 && !isnull(target_list[target_list[1]]) diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index fc8a54e76905..e94e11f5d01c 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -1,13 +1,8 @@ -//wrapper macros for easier grepping -#define DIRECT_OUTPUT(A, B) A << B -#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text) - - // On Linux/Unix systems the line endings are LF, on windows it's CRLF, admins that don't use notepad++ // will get logs that are one big line if the system is Linux and they are using notepad. This solves it by adding CR to every line ending // in the logs. ascii character 13 = CR -/var/global/log_end= world.system_type == UNIX ? ascii2text(13) : "" +var/global/log_end= world.system_type == UNIX ? ascii2text(13) : "" /proc/error(msg) @@ -21,9 +16,6 @@ if (log_world) to_world_log("SS[subsystem]: [text]") -/proc/log_ss_init(text) - game_log("SS", "[text]") - #define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].") //print a warning message to world.log /proc/warning(msg) @@ -34,15 +26,15 @@ to_world_log("## TESTING: [msg][log_end]") /proc/game_log(category, text) - diary << "\[[time_stamp()]] [game_id] [category]: [text][log_end]" + to_file(diary, "\[[time_stamp()]] [game_id] [category]: [text][log_end]") /proc/log_admin(text) - GLOB.admin_log.Add(text) - if (config.log_admin) + global.admin_log.Add(text) + if (get_config_value(/decl/config/toggle/log_admin)) game_log("ADMIN", text) /proc/log_debug(text) - if (config.log_debug) + if (get_config_value(/decl/config/toggle/log_debug)) game_log("DEBUG", text) to_debug_listeners(text) @@ -55,54 +47,54 @@ to_debug_listeners(text, "WARNING") /proc/to_debug_listeners(text, prefix = "DEBUG") - for(var/client/C in GLOB.admins) - if(C.get_preference_value(/datum/client_preference/staff/show_debug_logs) == GLOB.PREF_SHOW) + for(var/client/C in global.admins) + var/print_to_chat = TRUE + if(C.prefs?.preference_values) + print_to_chat = C.get_preference_value(/datum/client_preference/staff/show_debug_logs) == PREF_SHOW + if(print_to_chat) to_chat(C, "[prefix]: [text]") /proc/log_game(text) - if (config.log_game) + if (get_config_value(/decl/config/toggle/log_game)) game_log("GAME", text) /proc/log_vote(text) - if (config.log_vote) + if (get_config_value(/decl/config/toggle/log_vote)) game_log("VOTE", text) /proc/log_access(text) - if (config.log_access) + if (get_config_value(/decl/config/toggle/log_access)) game_log("ACCESS", text) /proc/log_say(text) - if (config.log_say) + if (get_config_value(/decl/config/toggle/log_say)) game_log("SAY", text) /proc/log_ooc(text) - if (config.log_ooc) + if (get_config_value(/decl/config/toggle/log_ooc)) game_log("OOC", text) /proc/log_whisper(text) - if (config.log_whisper) + if (get_config_value(/decl/config/toggle/log_whisper)) game_log("WHISPER", text) /proc/log_emote(text) - if (config.log_emote) + if (get_config_value(/decl/config/toggle/log_emotes)) game_log("EMOTE", text) /proc/log_attack(text) - if (config.log_attack) + if (get_config_value(/decl/config/toggle/log_attack)) game_log("ATTACK", text) /proc/log_adminsay(text) - if (config.log_adminchat) + global.admin_log.Add(text) + if (get_config_value(/decl/config/toggle/log_adminchat)) game_log("ADMINSAY", text) /proc/log_adminwarn(text) - if (config.log_adminwarn) + if (get_config_value(/decl/config/toggle/log_adminwarn)) game_log("ADMINWARN", text) -/proc/log_pda(text) - if (config.log_pda) - game_log("PDA", text) - /proc/log_misc(text) game_log("MISC", text) @@ -111,26 +103,14 @@ log_debug(text) /proc/log_qdel(text) - WRITE_FILE(GLOB.world_qdel_log, "\[[time_stamp()]]QDEL: [text]") + to_file(global.world_qdel_log, "\[[time_stamp()]]QDEL: [text]") //This replaces world.log so it displays both in DD and the file /proc/log_world(text) to_world_log(text) //this comes before the config check because it can't possibly runtime - if(config.log_world_output) + if(get_config_value(/decl/config/toggle/log_world_output)) game_log("DD_OUTPUT", text) -//pretty print a direction bitflag, can be useful for debugging. -/proc/dir_text(var/dir) - var/list/comps = list() - if(dir & NORTH) comps += "NORTH" - if(dir & SOUTH) comps += "SOUTH" - if(dir & EAST) comps += "EAST" - if(dir & WEST) comps += "WEST" - if(dir & UP) comps += "UP" - if(dir & DOWN) comps += "DOWN" - - return english_list(comps, nothing_text="0", and_text="|", comma_text="|") - //more or less a logging utility /proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/highlight_special_characters = 1, var/datum/ticket/ticket = null) var/mob/M @@ -162,7 +142,7 @@ if(key) if(include_link && C) - . += "" + . += "" . += key @@ -182,7 +162,7 @@ if(include_link && is_special_character(M) && highlight_special_characters) - . += "/([name])" //Orange + . += "/([SPAN_ORANGE(name)])" else . += "/([name])" @@ -199,7 +179,7 @@ return "[..()] ([isnum(z) ? "[x],[y],[z]" : "0,0,0"])" /turf/get_log_info_line() - var/obj/effect/overmap/visitable/O = map_sectors["[z]"] + var/obj/effect/overmap/visitable/O = global.overmap_sectors[z] if(istype(O)) return "[..()] ([x],[y],[z] - [O.name]) ([loc ? loc.type : "NULL"])" else @@ -208,7 +188,7 @@ /atom/movable/get_log_info_line() var/turf/t = get_turf(src) if(t) - var/obj/effect/overmap/visitable/O = map_sectors["[t.z]"] + var/obj/effect/overmap/visitable/O = global.overmap_sectors[t.z] if(istype(O)) return "[..()] ([t]) ([t.x],[t.y],[t.z] - [O.name]) ([t.type])" return "[..()] ([t]) ([t.x],[t.y],[t.z]) ([t.type])" @@ -221,16 +201,19 @@ if(isnull(d)) return "*null*" if(islist(d)) - var/list/L = list() - for(var/e in d) + var/list/out = list() + var/list/dlist = d + for(var/entry in dlist) // Indexing on numbers just gives us the same number again in the best case and causes an index out of bounds runtime in the worst - var/v = isnum(e) ? null : d[e] - L += "[log_info_line(e)][" - [log_info_line(v)]"]" - return "\[[jointext(L, ", ")]\]" // We format the string ourselves, rather than use json_encode(), because it becomes difficult to read recursively escaped " + var/value = isnum(entry) ? null : dlist[entry] + out += "[log_info_line(entry)][" - [log_info_line(value)]"]" + return "\[[jointext(out, ", ")]\]" // We format the string ourselves, rather than use json_encode(), because it becomes difficult to read recursively escaped " if(!istype(d)) return json_encode(d) return d.get_log_info_line() +var/global/_gag_report_progress = 0 /proc/report_progress(var/progress_message) - admin_notice("[progress_message]", R_DEBUG) - to_world_log(progress_message) + if(global._gag_report_progress <= 0) + admin_notice("[progress_message]", R_DEBUG) + to_world_log(progress_message) diff --git a/code/_helpers/maths.dm b/code/_helpers/maths.dm index 88d6b1f4c132..f89d3049b815 100644 --- a/code/_helpers/maths.dm +++ b/code/_helpers/maths.dm @@ -1,22 +1,10 @@ -// Macro functions. -#define RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW) -#define ceil(x) (-round(-(x))) -#define CEILING(x, y) ( -round(-(x) / (y)) * (y) ) -#define MULT_BY_RANDOM_COEF(VAR,LO,HI) VAR = round((VAR * rand(LO * 100, HI * 100))/100, 0.1) - // min is inclusive, max is exclusive /proc/Wrap(val, min, max) var/d = max - min - var/t = Floor((val - min) / d) + var/t = floor((val - min) / d) return val - (t * d) -/proc/Default(a, b) - return a ? a : b - // Trigonometric functions. -/proc/Tan(x) - return sin(x) / cos(x) - /proc/Csc(x) return 1 / sin(x) @@ -24,19 +12,13 @@ return 1 / cos(x) /proc/Cot(x) - return 1 / Tan(x) + return 1 / tan(x) /proc/Atan2(x, y) if(!x && !y) return 0 var/a = arccos(x / sqrt(x*x + y*y)) return y >= 0 ? a : -a -/proc/Floor(x) - return round(x) - -/proc/Ceiling(x) - return -round(-x) - // Greatest Common Divisor: Euclid's algorithm. /proc/Gcd(a, b) while (1) @@ -49,68 +31,22 @@ /proc/Lcm(a, b) return abs(a) * abs(b) / Gcd(a, b) -// Useful in the cases when x is a large expression, e.g. x = 3a/2 + b^2 + Function(c) -/proc/Square(x) - return x*x - -/proc/Inverse(x) - return 1 / x - // Condition checks. -/proc/IsAboutEqual(a, b, delta = 0.1) - return abs(a - b) <= delta - // Returns true if val is from min to max, inclusive. /proc/IsInRange(val, min, max) return (val >= min) && (val <= max) /proc/IsInteger(x) - return Floor(x) == x + return floor(x) == x /proc/IsMultiple(x, y) return x % y == 0 -/proc/IsEven(x) - return !(x & 0x1) - -/proc/IsOdd(x) - return (x & 0x1) - // Performs a linear interpolation between a and b. // Note: weight=0 returns a, weight=1 returns b, and weight=0.5 returns the mean of a and b. /proc/Interpolate(a, b, weight = 0.5) return a + (b - a) * weight // Equivalent to: a*(1 - weight) + b*weight -/proc/Mean(...) - var/sum = 0 - for(var/val in args) - sum += val - return sum / args.len - -// Returns the nth root of x. -/proc/Root(n, x) - return x ** (1 / n) - -// The quadratic formula. Returns a list with the solutions, or an empty list -// if they are imaginary. -/proc/SolveQuadratic(a, b, c) - ASSERT(a) - - . = list() - var/discriminant = b*b - 4*a*c - var/bottom = 2*a - - // Return if the roots are imaginary. - if(discriminant < 0) - return - - var/root = sqrt(discriminant) - . += (-b + root) / bottom - - // If discriminant == 0, there would be two roots at the same position. - if(discriminant != 0) - . += (-b - root) / bottom - /proc/ToDegrees(radians) // 180 / Pi ~ 57.2957795 return radians * 57.2957795 @@ -126,11 +62,39 @@ /proc/norm(x, y) return sqrt(squaredNorm(x, y)) -/proc/IsPowerOfTwo(var/val) - return (val & (val-1)) == 0 - -/proc/RoundUpToPowerOfTwo(var/val) - return 2 ** -round(-log(2,val)) - /matrix/proc/get_angle() return Atan2(b,a) + +//Finds the shortest angle that angle A has to change to get to angle B. Aka, whether to move clock or counterclockwise. +/proc/closer_angle_difference(a, b) + if(!isnum(a) || !isnum(b)) + return + a = SIMPLIFY_DEGREES(a) + b = SIMPLIFY_DEGREES(b) + var/inc = b - a + if(inc < 0) + inc += 360 + var/dec = a - b + if(dec < 0) + dec += 360 + . = inc > dec ? -dec : inc + +// Determines if `mid` is inbetween `start` and `end`, inclusive. All values are in degrees. +/proc/angle_between_two_angles(start, mid, end) + end = (end - start) < 0 ? end - start + 360 : end - start + mid = (mid - start) < 0 ? mid - start + 360 : mid - start + return mid <= end + +#define POLAR_TO_BYOND_X(R,T) ((R) * sin(T)) +#define POLAR_TO_BYOND_Y(R,T) ((R) * cos(T)) + +/proc/polar2turf(x, y, z, angle, distance) + var/x_offset = POLAR_TO_BYOND_X(distance, angle) + var/y_offset = POLAR_TO_BYOND_Y(distance, angle) + return locate(ceil(x + x_offset), ceil(y + y_offset), z) + +/proc/get_turf_from_angle(x, y, z, angle, ideal_distance) + do + . = polar2turf(x, y, z, angle, ideal_distance) + ideal_distance -= 1 + while (!. && ideal_distance > 0) diff --git a/code/_helpers/matrices.dm b/code/_helpers/matrices.dm index 698bd68c6e20..230966857bb3 100644 --- a/code/_helpers/matrices.dm +++ b/code/_helpers/matrices.dm @@ -1,121 +1,229 @@ +// Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1. +#define LUMA_R 0.213 +#define LUMA_G 0.715 +#define LUMA_B 0.072 + +/// Datum which stores information about a matrix decomposed with decompose(). +/datum/decompose_matrix + var/scale_x = 1 + var/scale_y = 1 + var/rotation = 0 + var/shift_x = 0 + var/shift_y = 0 + + +/// Decomposes a matrix into scale, shift and rotation. +/// * If other operations were applied on the matrix, such as shearing, the result will not be precise. +/matrix/proc/decompose() + var/datum/decompose_matrix/decompose_matrix = new + . = decompose_matrix + var/flip_sign = (a*e - b*d < 0)? -1 : 1 // Det < 0 => only 1 axis is flipped - start doing some sign flipping + // If both axis are flipped, nothing bad happens and Det >= 0, it just treats it like a 180° rotation + // If only 1 axis is flipped, we need to flip one direction - in this case X, so we flip a, b and the x scaling + decompose_matrix.scale_x = sqrt(a * a + d * d) * flip_sign + decompose_matrix.scale_y = sqrt(b * b + e * e) + decompose_matrix.shift_x = c + decompose_matrix.shift_y = f + if(!decompose_matrix.scale_x || !decompose_matrix.scale_y) + return + // If only translated, scaled and rotated, a/xs == e/ys and -d/xs == b/xy + var/cossine = (a/decompose_matrix.scale_x + e/decompose_matrix.scale_y) / 2 + var/sine = (b/decompose_matrix.scale_y - d/decompose_matrix.scale_x) / 2 * flip_sign + decompose_matrix.rotation = arctan(cossine, sine) * flip_sign + + /matrix/proc/TurnTo(old_angle, new_angle) . = new_angle - old_angle Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT -/atom/proc/SpinAnimation(speed = 10, loops = -1) - var/matrix/m120 = matrix(transform) - m120.Turn(120) - var/matrix/m240 = matrix(transform) - m240.Turn(240) - var/matrix/m360 = matrix(transform) - speed /= 3 //Gives us 3 equal time segments for our three turns. - //Why not one turn? Because byond will see that the start and finish are the same place and do nothing - //Why not two turns? Because byond will do a flip instead of a turn - animate(src, transform = m120, time = speed, loops) - animate(transform = m240, time = speed) - animate(transform = m360, time = speed) - -/atom/proc/shake_animation(var/intensity = 8) - var/init_px = pixel_x - var/shake_dir = pick(-1, 1) - animate(src, transform=turn(matrix(), intensity*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) - animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) - -//The X pixel offset of this matrix +/// Shear the transform on either or both axes. +/// * x - X axis shearing +/// * y - Y axis shearing +/matrix/proc/Shear(x, y) + return Multiply(matrix(1, x, 0, y, 1, 0)) + + +/// Dumps the matrix data in format a-f +/matrix/proc/tolist() + . = list() + . += a + . += b + . += c + . += d + . += e + . += f + +/// Dumps the matrix data in a matrix-grid format +/// * a d 0 +/// * b e 0 +/// * c f 1 +/matrix/proc/togrid() + . = list() + . += a + . += d + . += 0 + . += b + . += e + . += 0 + . += c + . += f + . += 1 + +/// The X pixel offset of this matrix /matrix/proc/get_x_shift() . = c -//The Y pixel offset of this matrix +/// The Y pixel offset of this matrix /matrix/proc/get_y_shift() . = f -// Color matrices: -//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1. +/// Returns the matrix identity +/// * 1 0 0 0 +/// * 0 1 0 0 +/// * 0 0 1 0 +/// * 0 0 0 0 +/proc/color_matrix_identity() + return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0) + +/// Adds/subtracts overall lightness +/// * 0 is identity, 1 makes everything white, -1 makes everything black +/proc/color_matrix_lightness(power) + return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, power,power,power,0) + +/// Changes distance hues have from grey while maintaining the overall lightness. Greys are unaffected. +/// * 1 is identity, 0 is greyscale, >1 oversaturates colors +/proc/color_matrix_saturation(value) + var/inv = 1 - value + var/red = round(LUMA_R * inv, 0.001) + var/green = round(LUMA_G * inv, 0.001) + var/blue = round(LUMA_B * inv, 0.001) + + return list(red + value,red,red,0, green,green + value,green,0, blue,blue,blue + value,0, 0,0,0,1, 0,0,0,0) + #define LUMR 0.2126 #define LUMG 0.7152 #define LUMB 0.0722 +/proc/legacy_color_saturation(value) + if(value == 0) + return + value = clamp(value, -100, 100) + if(value > 0) + value *= 3 + var/x = 1 + value / 100 + + var/inv = 1 - x + var/red = LUMR * inv + var/green = LUMG * inv + var/blue = LUMB * inv + return list(red + x,red,red, green,green + x,green, blue,blue,blue + x) -//Still need color matrix addition, negation, and multiplication. +#undef LUMR +#undef LUMG +#undef LUMB -//Returns an identity color matrix which does nothing -/proc/color_identity() - return list(1,0,0, 0,1,0, 0,0,1) +/// Changes distance colors have from rgb(127,127,127) grey +/// * 1 is identity. 0 makes everything grey >1 blows out colors and greys +/proc/color_matrix_contrast(value) + var/add = (1 - value) / 2 + return list(value,0,0,0, 0,value,0,0, 0,0,value,0, 0,0,0,1, add,add,add,0) -//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting whites -//TODO: Need a version that only affects one color (ie shift red to blue but leave greens and blues alone) -/proc/color_rotation(angle) - if(angle == 0) - return color_identity() - angle = Clamp(angle, -180, 180) - var/cos = cos(angle) +/// Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting greys +/// * 0 is identity, 120 moves reds to greens, 240 moves reds to blues +/proc/color_matrix_rotate_hue(angle) var/sin = sin(angle) - - var/constA = 0.143 - var/constB = 0.140 - var/constC = -0.283 + var/cos = cos(angle) + var/cos_inv_third = 0.333*(1-cos) + var/sqrt3_sin = sqrt(3)*sin return list( - LUMR + cos * (1-LUMR) + sin * -LUMR, LUMR + cos * -LUMR + sin * constA, LUMR + cos * -LUMR + sin * -(1-LUMR), - LUMG + cos * -LUMG + sin * -LUMG, LUMG + cos * (1-LUMG) + sin * constB, LUMG + cos * -LUMG + sin * LUMG, - LUMB + cos * -LUMB + sin * (1-LUMB), LUMB + cos * -LUMB + sin * constC, LUMB + cos * (1-LUMB) + sin * LUMB + round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), 0, + round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), 0, + round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), 0, + 0,0,0,1, + 0,0,0,0 ) -//Makes everything brighter or darker without regard to existing color or brightness -/proc/color_brightness(power) - power = Clamp(power, -255, 255) - power = power/255 - - return list(1,0,0, 0,1,0, 0,0,1, power,power,power) - -/var/list/delta_index = list( - 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, - 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, - 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, - 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, - 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, - 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, - 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, - 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, - 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, - 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, - 10.0) - -//Exxagerates or removes brightness -/proc/color_contrast(value) - value = Clamp(value, -100, 100) - if(value == 0) - return color_identity() - - var/x = 0 - if (value < 0) - x = 127 + value / 100 * 127; - else - x = value % 1 - if(x == 0) - x = delta_index[value] +/// Rotates around the red axis +/proc/color_matrix_rotate_x(angle) + var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001) + return list(1,0,0,0, 0,cosval,sinval,0, 0,-sinval,cosval,0, 0,0,0,1, 0,0,0,0) + +/// Rotates around the green axis +/proc/color_matrix_rotate_y(angle) + var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001) + return list(cosval,0,-sinval,0, 0,1,0,0, sinval,0,cosval,0, 0,0,0,1, 0,0,0,0) + +/// Rotates around the blue axis +/proc/color_matrix_rotate_z(angle) + var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001) + return list(cosval,sinval,0,0, -sinval,cosval,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0) + + +/// Returns a matrix addition of A with B +/proc/color_matrix_add(list/A, list/B) + if(!istype(A) || !istype(B)) + return color_matrix_identity() + if(A.len != 20 || B.len != 20) + return color_matrix_identity() + var/list/output = list() + output.len = 20 + for(var/value in 1 to 20) + output[value] = A[value] + B[value] + return output + +/// Returns a matrix multiplication of A with B +/proc/color_matrix_multiply(list/A, list/B) + if(!istype(A) || !istype(B)) + return color_matrix_identity() + if(A.len != 20 || B.len != 20) + return color_matrix_identity() + var/list/output = list() + output.len = 20 + var/x = 1 + var/y = 1 + var/offset = 0 + for(y in 1 to 5) + offset = (y-1)*4 + for(x in 1 to 4) + output[offset+x] = round(A[offset+1]*B[x] + A[offset+2]*B[x+4] + A[offset+3]*B[x+8] + A[offset+4]*B[x+12]+(y == 5?B[x+16]:0), 0.001) + return output + +/// Converts RGB shorthands into RGBA matrices complete of constants rows (ergo a 20 keys list in byond). +/proc/color_to_full_rgba_matrix(color) + if(istext(color)) + var/list/L = rgb2num(color) + if(!L) + CRASH("Invalid/unsupported color format argument in color_to_full_rgba_matrix()") + return list(L[1]/255,0,0,0, 0,L[2]/255,0,0, 0,0,L[3]/255,0, 0,0,0,L.len>3?L[4]/255:1, 0,0,0,0) + else if(!islist(color)) //invalid format + return color_matrix_identity() + var/list/L = color + switch(L.len) + if(3 to 5) // row-by-row hexadecimals + . = list() + for(var/a in 1 to L.len) + var/list/rgb = rgb2num(L[a]) + for(var/b in rgb) + . += b/255 + if(length(rgb) % 4) // RGB has no alpha instruction + . += a != 4 ? 0 : 1 + if(L.len < 4) //missing both alphas and constants rows + . += list(0,0,0,1, 0,0,0,0) + else if(L.len < 5) //missing constants row + . += list(0,0,0,0) + if(9 to 12) //RGB + . = list(L[1],L[2],L[3],0, L[4],L[5],L[6],0, L[7],L[8],L[9],0, 0,0,0,1) + for(var/b in 1 to 3) //missing constants row + . += L.len < 9+b ? 0 : L[9+b] + . += 0 + if(16 to 20) // RGBA + . = L.Copy() + if(L.len < 20) //missing constants row + for(var/b in 1 to 20-L.len) + . += 0 else - x = delta_index[value] * (1-x) + delta_index[value+1] * x//use linear interpolation for more granularity. - x = x * 127 + 127 - - var/mult = x / 127 - var/add = 0.5 * (127-x) / 255 - return list(mult,0,0, 0,mult,0, 0,0,mult, add,add,add) + CRASH("Invalid/unsupported color format argument in color_to_full_rgba_matrix()") -//Exxagerates or removes colors -/proc/color_saturation(value as num) - if(value == 0) - return color_identity() - value = Clamp(value, -100, 100) - if(value > 0) - value *= 3 - var/x = 1 + value / 100 - var/inv = 1 - x - var/R = LUMR * inv - var/G = LUMG * inv - var/B = LUMB * inv - - return list(R + x,R,R, G,G + x,G, B,B,B + x) - -#undef LUMR -#undef LUMG -#undef LUMB \ No newline at end of file +#undef LUMA_R +#undef LUMA_G +#undef LUMA_B \ No newline at end of file diff --git a/code/_helpers/medical_scans.dm b/code/_helpers/medical_scans.dm index 352e7b9f26a1..8cf60c06560e 100644 --- a/code/_helpers/medical_scans.dm +++ b/code/_helpers/medical_scans.dm @@ -1,100 +1,104 @@ -/mob/living/carbon/human/proc/get_raw_medical_data(var/tag = FALSE) - var/mob/living/carbon/human/H = src - var/list/scan = list() - - scan["name"] = H.name - scan["time"] = stationtime2text() +/mob/living/proc/get_raw_medical_data(var/tag = FALSE) + . = list() + .["name"] = name + .["time"] = stationtime2text() var/brain_result - if(H.should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] - if(!brain || H.stat == DEAD || (H.status_flags & FAKEDEATH)) + if(should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(src, BP_BRAIN) + if(!brain || stat == DEAD || (status_flags & FAKEDEATH)) brain_result = 0 - else if(H.stat != DEAD) - brain_result = round(max(0,(1 - brain.damage/brain.max_damage)*100)) + else if(stat != DEAD) + brain_result = round(max(0,(1 - brain.get_organ_damage() / brain.max_damage)*100)) else brain_result = -1 - scan["brain_activity"] = brain_result + .["brain_activity"] = brain_result var/pulse_result - if(H.should_have_organ(BP_HEART)) - var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[BP_HEART] + if(should_have_organ(BP_HEART)) + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) if(!heart) pulse_result = 0 else if(BP_IS_PROSTHETIC(heart)) pulse_result = -2 - else if(H.status_flags & FAKEDEATH) + else if(status_flags & FAKEDEATH) pulse_result = 0 else - pulse_result = H.get_pulse(GETPULSE_TOOL) + pulse_result = get_pulse_as_string(GETPULSE_TOOL) else pulse_result = -1 if(pulse_result == ">250") pulse_result = -3 - scan["pulse"] = text2num(pulse_result) - - scan["blood_pressure"] = H.get_blood_pressure() - scan["blood_o2"] = H.get_blood_oxygenation() - scan["blood_volume"] = H.vessel.total_volume - scan["blood_volume_max"] = H.vessel.maximum_volume - scan["temperature"] = H.bodytemperature - scan["trauma"] = H.getBruteLoss() - scan["burn"] = H.getFireLoss() - scan["toxin"] = H.getToxLoss() - scan["oxygen"] = H.getOxyLoss() - scan["radiation"] = H.radiation - scan["genetic"] = H.getCloneLoss() - scan["paralysis"] = H.paralysis - scan["immune_system"] = H.get_immunity() - scan["reagents"] = list() - - if(H.reagents?.total_volume) - for(var/reagent_type in H.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(reagent_type) - var/list/reagent = list() - reagent["name"]= R.name - reagent["quantity"] = round(REAGENT_VOLUME(H.reagents, R.type),1) - reagent["scannable"] = R.scannable - scan["reagents"] += list(reagent) - - scan["external_organs"] = list() - - for(var/obj/item/organ/external/E in H.organs) - var/list/O = list() - O["name"] = E.name - O["is_stump"] = E.is_stump() - O["brute_ratio"] = E.brute_ratio - O["burn_ratio"] = E.burn_ratio - O["limb_flags"] = E.limb_flags - O["brute_dam"] = E.brute_dam - O["burn_dam"] = E.burn_dam - O["scan_results"] = E.get_scan_results(tag) - O["tumors"] = E.has_growths() - - scan["external_organs"] += list(O) - - scan["internal_organs"] = list() - - for(var/obj/item/organ/internal/I in H.internal_organs) - var/list/O = list() - O["name"] = I.name - O["is_broken"] = I.is_broken() - O["is_bruised"] = I.is_bruised() - O["is_damaged"] = I.is_damaged() - O["scan_results"] = I.get_scan_results(tag) - - scan["internal_organs"] += list(O) - - scan["missing_organs"] = list() - - for(var/organ_name in H.species.has_organ) - if(!locate(H.species.has_organ[organ_name]) in H.internal_organs) - scan["missing_organs"] += organ_name - if(H.sdisabilities & BLINDED) - scan["blind"] = TRUE - if(H.sdisabilities & NEARSIGHTED) - scan["nearsight"] = TRUE - return scan + .["pulse"] = text2num(pulse_result) + + .["temperature"] = bodytemperature + .["trauma"] = get_damage(BRUTE) + .["burn"] = get_damage(BURN) + .["toxin"] = get_damage(TOX) + .["oxygen"] = get_damage(OXY) + .["radiation"] = radiation + .["genetic"] = get_damage(CLONE) + .["paralysis"] = GET_STATUS(src, STAT_PARA) + .["immune_system"] = get_immunity() + .["reagents"] = list() + + if(REAGENT_TOTAL_VOLUME(reagents)) + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(reagents)) + var/list/reagent_data = list() + reagent_data["name"] = reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID) + reagent_data["quantity"] = round(REAGENT_VOLUME(reagents, reagent),1) + reagent_data["scannable"] = reagent.scannable + .["reagents"] += list(reagent_data) + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(reagents)) + var/list/reagent_data = list() + reagent_data["name"] = reagent.get_reagent_name(reagents, MAT_PHASE_SOLID) + reagent_data["quantity"] = round(REAGENT_VOLUME(reagents, reagent),1) + reagent_data["scannable"] = reagent.scannable + .["reagents"] += list(reagent_data) + + .["external_organs"] = list() + for(var/obj/item/organ/external/limb in get_external_organs()) + var/list/O = list() + O["name"] = limb.name + O["brute_ratio"] = limb.brute_ratio + O["burn_ratio"] = limb.burn_ratio + O["limb_flags"] = limb.limb_flags + O["brute_dam"] = limb.brute_dam + O["burn_dam"] = limb.burn_dam + O["scan_results"] = limb.get_scan_results(tag) + O["tumors"] = limb.has_growths() + O["ailments"] = limb.has_diagnosable_ailments(scanner = TRUE) + .["external_organs"] += list(O) + + .["internal_organs"] = list() + var/list/internal_organs = get_internal_organs() + for(var/obj/item/organ/internal/organ in internal_organs) + var/list/O = list() + O["name"] = organ.name + O["is_broken"] = organ.is_broken() + O["is_bruised"] = organ.is_bruised() + O["is_damaged"] = organ.get_organ_damage() > 0 + O["scan_results"] = organ.get_scan_results(tag) + O["ailments"] = organ.has_diagnosable_ailments(scanner = TRUE) + .["internal_organs"] += list(O) + + .["missing_organs"] = list() + var/decl/bodytype/root_bodytype = get_bodytype() + for(var/organ_name in root_bodytype.has_organ) + if(!GET_INTERNAL_ORGAN(src, organ_name)) + .["missing_organs"] += organ_name + if(has_genetic_condition(GENE_COND_BLINDED)) + .["blind"] = TRUE + if(has_genetic_condition(GENE_COND_NEARSIGHTED)) + .["nearsight"] = TRUE + +/mob/living/human/get_raw_medical_data(var/tag = FALSE) + . = ..() + .["blood_pressure"] = get_blood_pressure() + .["blood_o2"] = get_blood_oxygenation() + if(vessel) + .["blood_volume"] = REAGENT_TOTAL_VOLUME(vessel) + .["blood_volume_max"] = REAGENT_MAXIMUM_VOLUME(vessel) /proc/display_medical_data_header(var/list/scan, skill_level = SKILL_DEFAULT) //In case of problems, abort. @@ -180,22 +184,26 @@ dat+= "Patient is bradycardic." - var/ratio = scan["blood_volume"]/scan["blood_volume_max"] - dat += "Blood pressure:[scan["blood_pressure"]]" - if(scan["blood_o2"] <= 70) - dat += "([scan["blood_o2"]]% blood oxygenation)" - else if(scan["blood_o2"] <= 85) - dat += "([scan["blood_o2"]]% blood oxygenation)" - else if(scan["blood_o2"] <= 90) - dat += "([scan["blood_o2"]]% blood oxygenation)" - else - dat += "([scan["blood_o2"]]% blood oxygenation)" + if(scan["blood_volume_max"] > 0) + var/ratio = scan["blood_volume"]/scan["blood_volume_max"] + dat += "Blood pressure:[scan["blood_pressure"]]" + if(scan["blood_o2"] <= 70) + dat += "([scan["blood_o2"]]% blood oxygenation)" + else if(scan["blood_o2"] <= 85) + dat += "([scan["blood_o2"]]% blood oxygenation)" + else if(scan["blood_o2"] <= 90) + dat += "([scan["blood_o2"]]% blood oxygenation)" + else + dat += "([scan["blood_o2"]]% blood oxygenation)" - dat += "Blood volume:[scan["blood_volume"]]u/[scan["blood_volume_max"]]u" + dat += "Blood volume:[scan["blood_volume"]]u/[scan["blood_volume_max"]]u" - if(skill_level >= SKILL_ADEPT) - if(ratio <= 0.70) - dat += "Patient is in Hypovolemic Shock. Transfusion highly recommended." + if(skill_level >= SKILL_ADEPT) + if(ratio <= 0.70) + dat += "Patient is in Hypovolemic Shock. Transfusion highly recommended." + else + dat += "Blood pressure:ERROR - Patient has lacks a circulatory system." + dat += "Blood volume:ERROR - Patient has lacks a circulatory system." // Body temperature. /* @@ -230,9 +238,9 @@ dat += "Antibody levels and immune system perfomance are at [scan["immune_system"]*100]% of baseline." var/other_reagent = FALSE - for(var/list/R in scan["reagents"]) - if(R["scannable"]) - subdat += "[R["quantity"]]u [R["name"]]" + for(var/list/reagent_data in scan["reagents"]) + if(reagent_data["scannable"]) + subdat += "[reagent_data["quantity"]]u [reagent_data["name"]]" else other_reagent = TRUE if(subdat) @@ -259,65 +267,70 @@ dat += "OrganDamageStatus" subdat = list() - for(var/list/E in scan["external_organs"]) - if(!E) + for(var/list/organ_data in scan["external_organs"]) + if(!organ_data) break var/row = list() - row += "[E["name"]]" - if(E["is_stump"]) - row += "Missing" - if(skill_level >= SKILL_ADEPT) - row += "[english_list(E["scan_results"], nothing_text = " ")]" - else - row += " " + row += "[organ_data["name"]]" + var/rowdata = list() + if(organ_data["brute_dam"] + organ_data["burn_dam"] == 0) + rowdata += "None" + else if(skill_level < SKILL_ADEPT) + if(organ_data["brute_dam"]) + rowdata += "Damaged" + if(organ_data["burn_dam"]) + rowdata += "Burned" else - row += "" - var/rowdata = list() - if(E["brute_dam"] + E["burn_dam"] == 0) - rowdata += "None" - else if(skill_level < SKILL_ADEPT) - if(E["brute_dam"]) - rowdata += "Damaged" - if(E["burn_dam"]) - rowdata += "Burned" - else - if(E["brute_dam"]) - rowdata += "[capitalize(get_wound_severity(E["brute_ratio"], (E["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] physical trauma" - if(E["burn_dam"]) - rowdata += "[capitalize(get_wound_severity(E["burn_ratio"], (E["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] burns" - if(E["tumors"]) - rowdata += "Abnormal internal growth" - row += "[jointext(rowdata, "
")]" + if(organ_data["brute_dam"]) + rowdata += "[capitalize(get_wound_severity(organ_data["brute_ratio"], (organ_data["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] physical trauma" + if(organ_data["burn_dam"]) + rowdata += "[capitalize(get_wound_severity(organ_data["burn_ratio"], (organ_data["limb_flags"] & ORGAN_FLAG_HEALS_OVERKILL)))] burns" + row += "[jointext(rowdata, "
")]" + + if(skill_level >= SKILL_ADEPT) + var/list/status = list() + if(organ_data["scan_results"]) + status += "[english_list(organ_data["scan_results"], nothing_text = " ")]" + if(organ_data["tumors"]) + status += "Abnormal internal growth" + if(organ_data["ailments"]) + status += "[jointext(organ_data["ailments"], "
")]" + row += "[status ? jointext(status, "
") : "Nominal."]" + else + row += " " - if(skill_level >= SKILL_ADEPT) - row += "" - row += "[english_list(E["scan_results"], nothing_text=" ")]" - row += "" - else - row += " " row += "" subdat += JOINTEXT(row) + dat += subdat subdat = list() - //Internal Organs if(skill_level >= SKILL_BASIC) dat += "
Internal Organs
" - for(var/list/I in scan["internal_organs"]) + for(var/list/organ_data in scan["internal_organs"]) var/row = list() - row += "[I["name"]]" - if(I["is_broken"]) + row += "[organ_data["name"]]" + if(organ_data["is_broken"]) row += "Severe" - else if(I["is_bruised"]) + else if(organ_data["is_bruised"]) row += "Moderate" - else if(I["is_damaged"]) - row += "Minor" + else if(organ_data["is_damaged"]) + row += "Minor" else row += "None" - row += "" - row += "[english_list(I["scan_results"], nothing_text=" ")]" - row += "" + + if(skill_level >= SKILL_ADEPT) + var/list/status = list() + if(organ_data["scan_results"]) + status += "[english_list(organ_data["scan_results"], nothing_text = " ")]" + if(organ_data["ailments"]) + status += "[jointext(organ_data["ailments"], "
")]" + row += "[status ? jointext(status, "
") : "Nominal."]" + else + row += " " + + row += "" subdat += jointext(row, null) if(skill_level <= SKILL_ADEPT) @@ -325,7 +338,7 @@ else dat += subdat for(var/organ_name in scan["missing_organs"]) - if(organ_name != "appendix") + if(organ_name != BP_APPENDIX) dat += "No [organ_name] detected." else dat += "No [organ_name] detected" @@ -367,7 +380,6 @@ /proc/get_severity(amount, var/tag = FALSE) if(!amount) return "none" - . = "minor" if(amount > 50) if(tag) . = "severe" @@ -382,4 +394,9 @@ if(tag) . = "moderate" else - . = "moderate" \ No newline at end of file + . = "moderate" + else + if (tag) + .= "minor" + else + .= "minor" diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm index 89d5cb55f425..a88092c9ae98 100644 --- a/code/_helpers/mobs.dm +++ b/code/_helpers/mobs.dm @@ -1,128 +1,52 @@ -/atom/movable/proc/get_mob() - return - -/obj/vehicle/train/get_mob() - return buckled_mob - -/mob/get_mob() - return src - -/mob/living/bot/mulebot/get_mob() - if(load && istype(load, /mob/living)) - return list(src, load) - return src - //helper for inverting armor blocked values into a multiplier #define blocked_mult(blocked) max(1 - (blocked/100), 0) /proc/mobs_in_view(var/range, var/source) - var/list/mobs = list() for(var/atom/movable/AM in view(range, source)) var/M = AM.get_mob() if(M) - mobs += M - - return mobs - -proc/random_hair_style(gender, species) - species = species || GLOB.using_map.default_species - var/h_style = "Bald" - - var/datum/species/mob_species = get_species_by_key(species) - var/list/valid_hairstyles = mob_species.get_hair_styles() - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) - - return h_style + LAZYDISTINCTADD(., M) -proc/random_facial_hair_style(gender, var/species) - species = species || GLOB.using_map.default_species - var/f_style = "Shaved" - var/datum/species/mob_species = get_species_by_key(species) - var/list/valid_facialhairstyles = mob_species.get_facial_hair_styles(gender) - if(valid_facialhairstyles.len) - f_style = pick(valid_facialhairstyles) - return f_style - -proc/random_name(gender, species) +/proc/random_name(gender, species) if(species) - var/datum/species/current_species = get_species_by_key(species) + var/decl/species/current_species = decls_repository.get_decl_by_id(species) if(current_species) - var/decl/cultural_info/current_culture = SSlore.get_culture(current_species.default_cultural_info[TAG_CULTURE]) - if(current_culture) - return current_culture.get_random_name(gender) - return capitalize(pick(gender == FEMALE ? GLOB.first_names_female : GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - -proc/random_skin_tone(var/datum/species/current_species) - var/species_tone = current_species ? 35 - current_species.max_skin_tone() : -185 - switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino")) - if("caucasian") . = -10 - if("afroamerican") . = -115 - if("african") . = -165 - if("latino") . = -55 - if("albino") . = 34 - else . = rand(species_tone,34) - - return min(max(. + rand(-25, 25), species_tone), 34) - -proc/skintone2racedescription(tone) - switch (tone) - if(30 to INFINITY) return "albino" - if(20 to 30) return "pale" - if(5 to 15) return "light skinned" - if(-10 to 5) return "white" - if(-25 to -10) return "tan" - if(-45 to -25) return "darker skinned" - if(-65 to -45) return "brown" - if(-INFINITY to -65) return "black" - else return "unknown" - -proc/age2agedescription(age) - switch(age) - if(0 to 1) return "infant" - if(1 to 3) return "toddler" - if(3 to 13) return "child" - if(13 to 19) return "teenager" - if(19 to 30) return "young adult" - if(30 to 45) return "adult" - if(45 to 60) return "middle-aged" - if(60 to 70) return "aging" - if(70 to INFINITY) return "elderly" - else return "unknown" - -/proc/RoundHealth(health) - var/list/icon_states = icon_states('icons/mob/hud_med.dmi') - for(var/icon_state in icon_states) - if(health >= text2num(icon_state)) - return icon_state - return icon_states[icon_states.len] // If we had no match, return the last element + var/decl/background_detail/background = current_species.get_default_background_datum_by_flag(BACKGROUND_FLAG_NAMING) + if(background) + return background.get_random_cultural_name(gender = gender, species = species) + + return capitalize(pick(gender == FEMALE ? global.using_map.first_names_female : global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) + +/proc/random_skin_tone(var/decl/bodytype/current_bodytype) + var/adjusted_max_skin_tone = current_bodytype ? 35 - current_bodytype.max_skin_tone() : -185 + return clamp(rand(current_bodytype ? 35 - current_bodytype.max_skin_tone() : -185, 34), adjusted_max_skin_tone, 34) //checks whether this item is a module of the robot it is located in. /proc/is_robot_module(var/obj/item/thing) if(!thing) return FALSE - if(istype(thing.loc, /mob/living/exosuit)) + if(isexosuit(thing.loc)) return FALSE - if(!istype(thing.loc, /mob/living/silicon/robot)) + if(!isrobot(thing.loc)) return FALSE - var/mob/living/silicon/robot/R = thing.loc - return (thing in R.module.equipment) + var/mob/living/silicon/robot/robot = thing.loc + return (thing in robot.module.equipment) /proc/get_exposed_defense_zone(var/atom/movable/target) return pick(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_CHEST, BP_GROIN) -/proc/do_mob(mob/user , mob/target, time = 30, target_zone = 0, uninterruptible = 0, progress = 1, var/incapacitation_flags = INCAPACITATION_DEFAULT) +/proc/do_mob(mob/user, mob/target, time = 30, target_zone = 0, uninterruptible = 0, progress = 1, incapacitation_flags = INCAPACITATION_DEFAULT, check_holding = TRUE) if(!user || !target) return 0 var/user_loc = user.loc var/drifting = 0 - if(!user.Process_Spacemove(0) && user.inertia_dir) + if(user.is_space_movement_permitted() == SPACE_MOVE_FORBIDDEN && user.inertia_dir) drifting = 1 var/target_loc = target.loc - var/holding = user.get_active_hand() + var/holding = check_holding && user.get_active_held_item() var/datum/progressbar/progbar if (progress) progbar = new(user, time, target) @@ -131,7 +55,7 @@ proc/age2agedescription(age) var/starttime = world.time . = 1 while (world.time < endtime) - sleep(1) + stoplag(1) if (progress) progbar.update(world.time - starttime) if(!user || !target) @@ -152,18 +76,18 @@ proc/age2agedescription(age) . = 0 break - if(user.get_active_hand() != holding) + if(check_holding && user.get_active_held_item() != holding) . = 0 break - if(target_zone && user.zone_sel.selecting != target_zone) + if(target_zone && user.get_target_zone() != target_zone) . = 0 break if (progbar) qdel(progbar) -/proc/do_after(mob/user, delay, atom/target = null, needhand = 1, progress = 1, var/incapacitation_flags = INCAPACITATION_DEFAULT, var/same_direction = 0, var/can_move = 0) +/proc/do_after(mob/user, delay, atom/target = null, check_holding = TRUE, progress = TRUE, incapacitation_flags = INCAPACITATION_DEFAULT, same_direction = FALSE, can_move = FALSE, max_distance, check_in_view = FALSE, set_cooldown = FALSE) if(!user) return 0 var/atom/target_loc = null @@ -178,20 +102,23 @@ proc/age2agedescription(age) var/atom/original_loc = user.loc var/drifting = 0 - if(!user.Process_Spacemove(0) && user.inertia_dir) + if(user.is_space_movement_permitted() == SPACE_MOVE_FORBIDDEN && user.inertia_dir) drifting = 1 - var/holding = user.get_active_hand() + var/holding = user.get_active_held_item() var/datum/progressbar/progbar if (progress) progbar = new(user, delay, target) + if(set_cooldown && delay) + user.setClickCooldown(delay) + var/endtime = world.time + delay var/starttime = world.time . = 1 while (world.time < endtime) - sleep(1) + stoplag(1) if (progress) progbar.update(world.time - starttime) @@ -199,7 +126,11 @@ proc/age2agedescription(age) drifting = 0 original_loc = user.loc - if(QDELETED(user) || user.incapacitated(incapacitation_flags) || (!drifting && user.loc != original_loc && !can_move) || (same_direction && user.dir != original_dir)) + if(QDELETED(user) || user.incapacitated(incapacitation_flags) || (!drifting && user.loc != original_loc && !can_move) || (same_direction && user.dir != original_dir) || (!isnull(max_distance) && get_dist(user, target) > max_distance)) + . = 0 + break + + if(check_in_view && !(target in view(max_distance, user))) . = 0 break @@ -207,8 +138,8 @@ proc/age2agedescription(age) . = 0 break - if(needhand) - if(user.get_active_hand() != holding) + if(check_holding) + if(user.get_active_held_item() != holding) . = 0 break @@ -236,27 +167,27 @@ proc/age2agedescription(age) /mob/proc/add_to_living_mob_list() return FALSE /mob/living/add_to_living_mob_list() - if((src in GLOB.living_mob_list_) || (src in GLOB.dead_mob_list_)) + if((src in global.living_mob_list_) || (src in global.dead_mob_list_)) return FALSE - GLOB.living_mob_list_ += src + global.living_mob_list_ += src return TRUE // Returns true if the mob was removed from the living list /mob/proc/remove_from_living_mob_list() - return GLOB.living_mob_list_.Remove(src) + return global.living_mob_list_.Remove(src) // Returns true if the mob was in neither the dead or living list /mob/proc/add_to_dead_mob_list() return FALSE /mob/living/add_to_dead_mob_list() - if((src in GLOB.living_mob_list_) || (src in GLOB.dead_mob_list_)) + if((src in global.living_mob_list_) || (src in global.dead_mob_list_)) return FALSE - GLOB.dead_mob_list_ += src + global.dead_mob_list_ += src return TRUE // Returns true if the mob was removed form the dead list /mob/proc/remove_from_dead_mob_list() - return GLOB.dead_mob_list_.Remove(src) + return global.dead_mob_list_.Remove(src) //Find a dead mob with a brain and client. /proc/find_dead_player(var/find_key, var/include_observers = 0) @@ -266,20 +197,20 @@ proc/age2agedescription(age) var/mob/selected = null if(include_observers) - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if((M.stat != DEAD) || (!M.client)) continue if(M.ckey == find_key) selected = M break else - for(var/mob/living/M in GLOB.player_list) + for(var/mob/living/M in global.player_list) //Dead people only thanks! if((M.stat != DEAD) || (!M.client)) continue //They need a brain! - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M + if(ishuman(M)) + var/mob/living/human/H = M if(H.should_have_organ(BP_BRAIN) && !H.has_brain()) continue if(M.ckey == find_key) @@ -311,45 +242,61 @@ proc/age2agedescription(age) return val if(istext(val)) var/list/vals = splittext(val, "x") - return Floor(max(text2num(vals[1]), text2num(vals[2]))/2) + return floor(max(text2num(vals[1]), text2num(vals[2]))/2) return 0 // If all of these flags are present, it should come out at exactly 1. Yes, this // is horrible. TODO: unify coverage flags with limbs and use organ_rel_size. -GLOBAL_LIST_INIT(bodypart_coverage_cache, new) +var/global/list/bodypart_coverage_cache = list() /proc/get_percentage_body_cover(var/checking_flags) var/key = "[checking_flags]" - if(isnull(GLOB.bodypart_coverage_cache[key])) + if(isnull(global.bodypart_coverage_cache[key])) var/coverage = 0 - if(checking_flags & FULL_BODY) + if(checking_flags & SLOT_FULL_BODY) coverage = 1 else - if(checking_flags & HEAD) + if(checking_flags & SLOT_HEAD) coverage += 0.1 - if(checking_flags & FACE) + if(checking_flags & SLOT_FACE) coverage += 0.05 - if(checking_flags & EYES) + if(checking_flags & SLOT_EYES) coverage += 0.05 - if(checking_flags & UPPER_TORSO) + if(checking_flags & SLOT_UPPER_BODY) coverage += 0.15 - if(checking_flags & LOWER_TORSO) + if(checking_flags & SLOT_LOWER_BODY) coverage += 0.15 - if(checking_flags & LEG_LEFT) + if(checking_flags & SLOT_LEG_LEFT) coverage += 0.075 - if(checking_flags & LEG_RIGHT) + if(checking_flags & SLOT_LEG_RIGHT) coverage += 0.075 - if(checking_flags & FOOT_LEFT) + if(checking_flags & SLOT_FOOT_LEFT) coverage += 0.05 - if(checking_flags & FOOT_RIGHT) + if(checking_flags & SLOT_FOOT_RIGHT) coverage += 0.05 - if(checking_flags & ARM_LEFT) + if(checking_flags & SLOT_ARM_LEFT) coverage += 0.075 - if(checking_flags & ARM_RIGHT) + if(checking_flags & SLOT_ARM_RIGHT) coverage += 0.075 - if(checking_flags & HAND_LEFT) + if(checking_flags & SLOT_HAND_LEFT) coverage += 0.05 - if(checking_flags & HAND_RIGHT) + if(checking_flags & SLOT_HAND_RIGHT) coverage += 0.05 - GLOB.bodypart_coverage_cache[key] = coverage - . = GLOB.bodypart_coverage_cache[key] \ No newline at end of file + global.bodypart_coverage_cache[key] = coverage + . = global.bodypart_coverage_cache[key] + +/proc/get_sorted_mob_list() + . = sortTim(SSmobs.mob_list.Copy(), /proc/cmp_name_asc) + . = sortTim(., /proc/cmp_mob_sortvalue_asc) + +/proc/transfer_key_from_mob_to_mob(var/mob/from_mob, var/mob/to_mob) + if(!from_mob || !from_mob.key || !to_mob) + return FALSE + var/initial_key = from_mob.key + if(to_mob.key) + to_mob.ghostize() + if(from_mob.mind) + from_mob.mind.transfer_to(to_mob) + if(initial_key && to_mob.key != initial_key) + to_mob.key = initial_key + return to_mob.key == initial_key diff --git a/code/_helpers/names.dm b/code/_helpers/names.dm index 8ceda1cf9930..0011c6703231 100644 --- a/code/_helpers/names.dm +++ b/code/_helpers/names.dm @@ -1,121 +1,61 @@ -var/church_name = null -/proc/church_name() - if (church_name) - return church_name - - var/name = "" - - name += pick("Holy", "United", "First", "Second", "Last") - - if (prob(20)) - name += " Space" - - name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses") - name += " of [religion_name()]" - - return name - -var/command_name = null -/proc/command_name() - if (command_name) - return command_name - - var/name = "[GLOB.using_map.boss_name]" - - command_name = name - return name - -/proc/change_command_name(var/name) - - command_name = name - - return name - -var/religion_name = null -/proc/religion_name() - if (religion_name) - return religion_name - - var/name = "" - - name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob") - name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity") - - return capitalize(name) - -/proc/system_name() - return GLOB.using_map.system_name ? GLOB.using_map.system_name : generate_system_name() - /proc/generate_system_name() return "[pick("Gilese","GSC", "Luyten", "GJ", "HD")][prob(10) ? " Eridani" : ""] [rand(100,999)]" /proc/generate_planet_name() - return "[capitalize(pick(GLOB.last_names))]-[pick(GLOB.greek_letters)]" - -/proc/generate_planet_type() - return pick("terrestial planet", "ice planet", "dwarf planet", "desert planet", "ocean planet", "lava planet", "gas giant", "forest planet") + return "[capitalize(pick(global.using_map.last_names))]-[pick(global.greek_letters)]" /proc/station_name() - if(!GLOB.using_map) - return server_name - if (GLOB.using_map.station_name) - return GLOB.using_map.station_name + if(!global.using_map) + return get_config_value(/decl/config/text/server_name) + if (global.using_map.station_name) + return global.using_map.station_name var/random = rand(1,5) var/name = "" //Rare: Pre-Prefix if(prob(10)) - name = pick(GLOB.station_prefixes) - GLOB.using_map.station_name = name + " " + name = pick(global.station_prefixes) + global.using_map.station_name = name + " " var/holiday_prefix = length(global.current_holiday?.station_prefixes) && pick(global.current_holiday.station_prefixes) if(holiday_prefix) name = holiday_prefix - GLOB.using_map.station_name = "[GLOB.using_map.station_name][holiday_prefix] " + global.using_map.station_name = "[global.using_map.station_name][holiday_prefix] " // Suffix - name = pick(GLOB.station_suffixes) - GLOB.using_map.station_name += name + " " + name = pick(global.station_suffixes) + global.using_map.station_name += name + " " var/holiday_suffix = length(global.current_holiday?.station_suffixes) && pick(global.current_holiday.station_suffixes) if(holiday_suffix) - GLOB.using_map.station_name += holiday_suffix + global.using_map.station_name += holiday_suffix else // ID Number switch(random) if(1) - GLOB.using_map.station_name += "[rand(1, 99)]" + global.using_map.station_name += "[rand(1, 99)]" if(2) - GLOB.using_map.station_name += pick(GLOB.greek_letters) + global.using_map.station_name += pick(global.greek_letters) if(3) - GLOB.using_map.station_name += "\Roman[rand(1,99)]" + global.using_map.station_name += "\Roman[rand(1,99)]" if(4) - GLOB.using_map.station_name += pick(GLOB.phonetic_alphabet) + global.using_map.station_name += pick(global.phonetic_alphabet) if(5) - GLOB.using_map.station_name += pick(GLOB.numbers_as_words) + global.using_map.station_name += pick(global.numbers_as_words) - if (config && config.server_name) - world.name = "[config.server_name]: [name]" + var/config_server_name = get_config_value(/decl/config/text/server_name) + if (config_server_name) + world.name = "[config_server_name]: [name]" else - world.name = GLOB.using_map.station_name - - return GLOB.using_map.station_name - -/proc/world_name(var/name) - GLOB.using_map.station_name = name + world.name = global.using_map.station_name - if (config && config.server_name) - world.name = "[config.server_name]: [name]" - else - world.name = name - - return name + return global.using_map.station_name -var/syndicate_name = null +var/global/syndicate_name = null /proc/syndicate_name() - if (syndicate_name) - return syndicate_name + if (global.syndicate_name) + return global.syndicate_name var/name = "" @@ -139,13 +79,15 @@ var/syndicate_name = null name += pick("-", "*", "") name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive") - syndicate_name = name + global.syndicate_name = name return name -//Traitors and traitor silicons will get these. Revs will not. -var/syndicate_code_phrase//Code phrase for traitors. -var/syndicate_code_response//Code response for traitors. +// Traitors and traitor silicons will get these. Revs will not. +/// Code phrase for traitors. +var/global/syndicate_code_phrase +/// Code response for traitors. +var/global/syndicate_code_response /* Should be expanded. @@ -173,7 +115,7 @@ var/syndicate_code_response//Code response for traitors. var/safety[] = list(1,2,3)//Tells the proc which options to remove later on. var/nouns[] = list("love","hate","anger","peace","pride","sympathy","bravery","loyalty","honesty","integrity","compassion","charity","success","courage","deceit","skill","beauty","brilliance","pain","misery","beliefs","dreams","justice","truth","faith","liberty","knowledge","thought","information","culture","trust","dedication","progress","education","hospitality","leisure","trouble","friendships", "relaxation") - var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepsky Smash","tequilla sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine") + var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepsky Smash","tequila sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine") var/locations[] = length(stationlocs) ? stationlocs : drinks//if null, defaults to drinks instead. var/maxwords = words//Extra var to check for duplicates. @@ -189,9 +131,9 @@ var/syndicate_code_response//Code response for traitors. if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc. switch(rand(1,2))//Mainly to add more options later. if(1) - code_phrase += pick(pick(GLOB.first_names_male,GLOB.first_names_female)) + code_phrase += pick(pick(global.using_map.first_names_male,global.using_map.first_names_female)) code_phrase += " " - code_phrase += pick(GLOB.last_names) + code_phrase += pick(global.using_map.last_names) if(2) code_phrase += pick(SSjobs.titles_to_datums) //Returns a job. safety -= 1 @@ -207,9 +149,9 @@ var/syndicate_code_response//Code response for traitors. if(1) code_phrase += pick(nouns) if(2) - code_phrase += pick(GLOB.adjectives) + code_phrase += pick(global.adjectives) if(3) - code_phrase += pick(GLOB.verbs) + code_phrase += pick(global.verbs) if(words==1) code_phrase += "." else @@ -217,8 +159,8 @@ var/syndicate_code_response//Code response for traitors. return code_phrase -/proc/get_name(var/atom/A) - return A.name +/proc/get_area_proper_name(var/area/A) + return A.proper_name -/proc/get_name_and_coordinates(var/atom/A) - return "[A.name] \[[A.x],[A.y],[A.z]\]" +/proc/get_area_proper_name_and_coordinates(var/area/A) + return "[A.proper_name] \[[A.x],[A.y],[A.z]\]" \ No newline at end of file diff --git a/code/_helpers/overmap.dm b/code/_helpers/overmap.dm new file mode 100644 index 000000000000..abac165dce80 --- /dev/null +++ b/code/_helpers/overmap.dm @@ -0,0 +1,12 @@ +var/global/alist/overmap_sectors = alist() +var/global/list/overmaps_by_name = list() +var/global/list/overmaps_by_z = list() + +//////////////////////////////////////////// +//Possible values for planet ring types +//////////////////////////////////////////// + +///A lightly populated planetary ring +#define SKYBOX_PLANET_RING_TYPE_SPARSE "sparse" +///A densely populated planetary ring +#define SKYBOX_PLANET_RING_TYPE_DENSE "dense" \ No newline at end of file diff --git a/code/_helpers/profiling.dm b/code/_helpers/profiling.dm new file mode 100644 index 000000000000..f02138db049f --- /dev/null +++ b/code/_helpers/profiling.dm @@ -0,0 +1,117 @@ +#define STAT_ENTRY_TIME 1 +#define STAT_ENTRY_COUNT 2 +#define STAT_ENTRY_LENGTH 2 + + +#define STAT_START_STOPWATCH var/STAT_STOP_WATCH = TICK_USAGE +#define STAT_STOP_STOPWATCH var/STAT_TIME = TICK_USAGE_TO_MS(STAT_STOP_WATCH) +#define STAT_LOG_ENTRY(entrylist, entryname) \ + var/list/STAT_ENTRY = entrylist[entryname] || (entrylist[entryname] = new /list(STAT_ENTRY_LENGTH));\ + STAT_ENTRY[STAT_ENTRY_TIME] += STAT_TIME;\ + STAT_ENTRY[STAT_ENTRY_COUNT] += 1; + +// Cost tracking macros, to be used in one proc. If you're using this raw you'll want to use global lists +// If you don't you'll need another way of reading it +#define INIT_COST(costs, counting) \ + var/list/_costs = costs; \ + var/list/_counting = counting; \ + var/_usage = TICK_USAGE; + +// STATIC cost tracking macro. Uses static lists instead of the normal global ones +// Good for debug stuff, and for running before globals init +#define INIT_COST_STATIC(...) \ + var/static/list/hidden_static_list_for_fun1 = list(); \ + var/static/list/hidden_static_list_for_fun2 = list(); \ + INIT_COST(hidden_static_list_for_fun1, hidden_static_list_for_fun2) + +#define SET_COST(category) \ + do { \ + var/_cost = TICK_USAGE; \ + _costs[category] += TICK_DELTA_TO_MS(_cost - _usage);\ + _counting[category] += 1; \ + } while(FALSE); \ + _usage = TICK_USAGE; + +#define SET_COST_LINE(...) SET_COST("[__LINE__]") + +/// A quick helper for running the code as a statement and profiling its cost. +/// For example, `SET_COST_STMT(var/x = do_work())` +#define SET_COST_STMT(code...) ##code; SET_COST("[__LINE__] - [#code]") + +#define EXPORT_STATS_TO_JSON_LATER(filename, costs, counts) EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, stat_tracking_export_to_json_later) +#define EXPORT_STATS_TO_CSV_LATER(filename, costs, counts) EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, stat_tracking_export_to_csv_later) + +#define EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, proc) \ + do { \ + var/static/last_export = 0; \ + if (world.time - last_export > 1.1 SECONDS) { \ + last_export = world.time; \ + /* spawn() is used here because this is often used to track init times, where timers act oddly. */ \ + /* I was making timers and even after init times were complete, the timers didn't run :shrug: */ \ + spawn (1 SECONDS) { \ + ##proc(filename, costs, counts); \ + } \ + } \ + } while (FALSE); \ + _usage = TICK_USAGE; + +/proc/cmp_generic_stat_item_time(list/A, list/B) + . = B[STAT_ENTRY_TIME] - A[STAT_ENTRY_TIME] + if (!.) + . = B[STAT_ENTRY_COUNT] - A[STAT_ENTRY_COUNT] + +// For use with the stopwatch defines +/proc/render_stats(list/stats, user, sort = /proc/cmp_generic_stat_item_time) + sortTim(stats, sort, TRUE) + + var/list/lines = list() + + for (var/entry in stats) + var/list/data = stats[entry] + lines += "[entry] => [num2text(data[STAT_ENTRY_TIME], 10)]ms ([data[STAT_ENTRY_COUNT]]) (avg:[num2text(data[STAT_ENTRY_TIME]/(data[STAT_ENTRY_COUNT] || 1), 99)])" + + if (user) + show_browser(user, "
  1. [lines.Join("
  2. ")]
", "window=[url_encode("stats:[ref(stats)]")]") + + . = lines.Join("\n") + +// For use with the set_cost defines +/proc/stat_tracking_export_to_json_later(filename, costs, counts) + var/list/output = list() + + for (var/key in costs) + output[key] = list( + "cost" = costs[key], + "count" = counts[key], + ) + + to_file(file("[global.log_directory]/[filename]"), json_encode(output)) + +/proc/stat_tracking_export_to_csv_later(filename, costs, counts) + var/list/output = list() + + output += "key, cost, count" + for (var/key in costs) + output += "[replacetext(key, ",", "")], [costs[key]], [counts[key]]" + + to_file(file("[global.log_directory]/[filename]"), output.Join("\n")) + +// Only enable this if you have a local copy of the byond-tracy DLL. +// DO NOT commit the DLL to the repo. +#ifdef TRACY_PROFILE +/proc/prof_init() + var/lib + + switch(world.system_type) + if(MS_WINDOWS) lib = "prof.dll" + if(UNIX) lib = "libprof.so" + else CRASH("unsupported platform") + + var/init = call_ext(lib, "init")() + if("0" != init) CRASH("[lib] init error: [init]") + +var/global/datum/profiler/_profiler = new +/datum/profiler/New() + prof_init() + ..() +#endif diff --git a/code/_helpers/radio.dm b/code/_helpers/radio.dm new file mode 100644 index 000000000000..c0163e09ae75 --- /dev/null +++ b/code/_helpers/radio.dm @@ -0,0 +1,10 @@ +/proc/do_telecomms_announcement(var/atom/target, var/message, var/speaker_name, var/channel) + var/obj/item/radio/announcer = get_announcer(target) + if(announcer) + if(islist(channel)) + for(var/single_channel in channel) + announcer.autosay(message, speaker_name, single_channel) + else + announcer.autosay(message, speaker_name, channel) + return TRUE + return FALSE diff --git a/code/_helpers/sanitize_values.dm b/code/_helpers/sanitize_values.dm index 15edaecf68b2..fa3b00e30784 100644 --- a/code/_helpers/sanitize_values.dm +++ b/code/_helpers/sanitize_values.dm @@ -24,25 +24,18 @@ return text return default +/proc/sanitize_islist(value, default) + if(islist(value) && length(value)) + return value + if(default) + return default + /proc/sanitize_inlist(value, list/List, default) if(value in List) return value if(default) return default if(List && List.len)return List[1] - - -//more specialised stuff -/proc/sanitize_gender(gender,neuter=0,plural=0, default="male") - switch(gender) - if(MALE, FEMALE)return gender - if(NEUTER) - if(neuter) return gender - else return default - if(PLURAL) - if(plural) return gender - else return default - return default - +// UNICODE: Use text2num? /proc/sanitize_hexcolor(color, default="#000000") if(!istext(color)) return default var/len = length(color) @@ -60,16 +53,18 @@ //Valid format codes: YY, YEAR, MM, DD, hh, mm, ss, :, -. " " (space). Invalid format will return default. /proc/sanitize_time(time, default, format = "hh:mm") + var/static/list/time_fragments = list("YY", "YEAR", "MM", "DD", "hh", "mm", "ss") + var/static/list/separators = list(":", "-", " ") if(!istext(time) || !(length(time) == length(format))) return default var/fragment = "" . = list() for(var/i = 1, i <= length(format), i++) fragment += copytext(format,i,i+1) - if(fragment in list("YY", "YEAR", "MM", "DD", "hh", "mm", "ss")) + if(fragment in time_fragments) . += sanitize_one_time(copytext(time, i - length(fragment) + 1, i + 1), copytext(default, i - length(fragment) + 1, i + 1), fragment) fragment = "" - else if(fragment in list(":", "-", " ")) + else if(fragment in separators) . += fragment fragment = "" if(fragment) diff --git a/code/_helpers/serde.dm b/code/_helpers/serde.dm new file mode 100644 index 000000000000..9d50f3fae347 --- /dev/null +++ b/code/_helpers/serde.dm @@ -0,0 +1,131 @@ +/proc/instantiate_serialized_data(load_z, requestor, list/instance_map, entries_decay_at, entry_decay_weight) + + var/list/nested_instances = list() + var/list/instanced_areas = list() + var/list/created_data = list() + + LAZYINITLIST(instance_map) + + to_world_log("Finalising load of [length(instance_map)] instance\s for level '[requestor]'.") + for(var/uid in instance_map) + + var/list/instance_data = instance_map[uid] + try + + var/raw_load_path = instance_data[nameof(/datum::type)] + var/load_path = ispath(raw_load_path, /datum) ? raw_load_path : text2path(raw_load_path) + if(!ispath(load_path, /datum)) + error("[requestor]: attempted to load persistent instance with invalid or non-/datum type '[raw_load_path]'") + continue + + var/datum/created_instance + + // Instance is a /datum. + // Just pass the data in and assume the datum type knows what to do with it. + if(!ispath(load_path, /atom) && ispath(load_path, /datum)) + created_instance = new load_path(instance_data) + created_data += created_instance + else + var/list/spawn_data = instance_data[nameof(/atom/movable::loc)] + if(spawn_data) + + if(isnull(spawn_data) || length(spawn_data) < 3) + error("[requestor]: attempted to load persistent instance with malformed loc.") + continue + + // Instance has a world coordinate. + if(islist(spawn_data)) + var/turf/spawn_loc = locate(spawn_data[1], spawn_data[2], isnull(load_z) ? spawn_data[3] : load_z) + if(!istype(spawn_loc)) + error("[requestor]: attempted to load persistent instance but could not find spawn loc.") + continue + if(ispath(load_path, /turf)) + if(spawn_loc.type == load_path) + created_instance = spawn_loc + else + created_instance = spawn_loc.ChangeTurf(load_path) + + // TODO: Areas will need bespoke handling for non-subtype-related persistence (blueprint renaming etc). + else if(ispath(load_path, /area)) + var/area/area = instanced_areas[load_path] + if(!area) + area = new load_path(null) + instanced_areas[load_path] = area + ChangeArea(spawn_loc, area) + + else if(ispath(load_path, /atom)) + created_instance = new load_path(spawn_loc) + spawn_loc._contents_were_modified = TRUE // ensure + else + error("[requestor]: attempted to instantiate unimplemented path '[load_path]'.") + continue + + // Instance is inside another instance; implies/requires /atom/movable + else if(istext(spawn_data)) + if(!ispath(load_path, /atom/movable)) + error("[requestor]: tried to spawn non-movable [load_path] inside an instance.") + continue + created_instance = new load_path + nested_instances[created_instance] = spawn_data + + else + error("[requestor]: attempted to load persistent instance with malformed loc.") + continue + + else + // Should we just go ahead and do this to create atoms in nullspace? + // Would we ever want to track an atom in nullspace via level persistence? + error("[requestor]: attempted to load non-/datum persistent instance with no spawn loc.") + + if(istype(created_instance)) + LAZYSET(., uid, created_instance) + if(isatom(created_instance)) + var/atom/atom = created_instance + atom.__deserialization_payload = instance_data + SSatoms.deserialized_atoms[uid] = atom + if(!isnull(entries_decay_at) && !isnull(entry_decay_weight)) + created_instance.HandlePersistentDecay(entries_decay_at, entry_decay_weight) + + catch(var/exception/E) + log_error("Exception during persistent instance load - [islist(instance_data) ? json_encode(instance_data) : "no instance data"]: [EXCEPTION_TEXT(E)]") + + // Atoms use SSatoms for this, datums don't go through SSatoms so need to do it here. + for(var/datum/instance in created_data) + instance.DeserializePostInit(.) + + // Resolve any loc references to instances. + for(var/atom/movable/atom as anything in nested_instances) + var/nested_atom_id = nested_instances[atom] + var/atom/nested_atom = .[nested_atom_id] + if(!istype(nested_atom)) + error("[requestor]: could not resolve instance ref [nested_atom_id] to instance.") + continue + atom.forceMove(nested_atom) + nested_atom.contents_were_modified() + + // Now that everything is loaded and placed, clear out anything that should not be present on the turfs we've loaded. + for(var/uid in SSatoms.deserialized_atoms) + var/turf/turf = SSatoms.deserialized_atoms[uid] + if(!istype(turf)) + continue + for(var/atom/thing in turf) + if(!thing.simulated) + continue + if(!isnull(thing.__deserialization_payload)) + continue + qdel(thing) + + to_world_log("[requestor] loaded [length(.)] persistent instance\s.") + +/proc/apply_serde_message_decay(_message, _age, _decay_weight, _decay_at) + var/static/list/decayed_chars = list(".",",","-","'","\\","/","\"",":",";") + if(_age < _decay_at || isnull(_message)) + return _message + . = "" + for(var/i = 1 to length(_message)) + var/char = copytext(_message, i, i + 1) + if(prob(round(_age * _decay_weight))) + if(prob(99)) + . += pick(decayed_chars) + else + . += char diff --git a/code/_helpers/sorts/TimSort.dm b/code/_helpers/sorts/TimSort.dm index cfa55f0dfa3c..436aa4e8c74e 100644 --- a/code/_helpers/sorts/TimSort.dm +++ b/code/_helpers/sorts/TimSort.dm @@ -1,5 +1,6 @@ //TimSort interface /proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0) + sortInstance = sortInstance || new if(L && L.len >= 2) fromIndex = fromIndex % L.len toIndex = toIndex % (L.len+1) diff --git a/code/_helpers/sorts/__main.dm b/code/_helpers/sorts/__main.dm index 622d88f14728..391630171eba 100644 --- a/code/_helpers/sorts/__main.dm +++ b/code/_helpers/sorts/__main.dm @@ -9,7 +9,7 @@ #define MIN_GALLOP 7 //This is a global instance to allow much of this code to be reused. The interfaces are kept separately -var/datum/sortInstance/sortInstance = new() +var/global/datum/sortInstance/sortInstance /datum/sortInstance //The array being sorted. var/list/L @@ -113,7 +113,7 @@ start the index of the first element in the range that is not already known to b //[lo, left) elements <= pivot < [right, start) elements //in other words, find where the pivot element should go using bisection search while(left < right) - var/mid = (left + right) >> 1 //round((left+right)/2) + var/mid = BITSHIFT_RIGHT((left + right), 1) //round((left+right)/2) if(call(cmp)(fetchElement(L,mid), pivot) > 0) right = mid else @@ -169,7 +169,7 @@ reverse a descending sequence without violating stability. var/r = 0 //becomes 1 if any bits are shifted off while(n >= MIN_MERGE) r |= (n & 1) - n >>= 1 + n = BITSHIFT_RIGHT(n, 1) return n + r //Examines the stack of runs waiting to be merged and merges adjacent runs until the stack invariants are reestablished: @@ -266,7 +266,7 @@ reverse a descending sequence without violating stability. var/maxOffset = len - hint while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) > 0) lastOffset = offset - offset = (offset << 1) + 1 + offset = BITSHIFT_LEFT(offset, 1) + 1 if(offset > maxOffset) offset = maxOffset @@ -278,7 +278,7 @@ reverse a descending sequence without violating stability. var/maxOffset = hint + 1 while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) <= 0) lastOffset = offset - offset = (offset << 1) + 1 + offset = BITSHIFT_LEFT(offset, 1) + 1 if(offset > maxOffset) offset = maxOffset @@ -293,7 +293,7 @@ reverse a descending sequence without violating stability. //offset. Do a binary search with invariant L[base+lastOffset-1] < key <= L[base+offset] ++lastOffset while(lastOffset < offset) - var/m = lastOffset + ((offset - lastOffset) >> 1) + var/m = lastOffset + BITSHIFT_RIGHT((offset - lastOffset), 1) if(call(cmp)(key, fetchElement(L,base+m)) > 0) lastOffset = m + 1 @@ -325,7 +325,7 @@ reverse a descending sequence without violating stability. var/maxOffset = hint + 1 //therefore we want to insert somewhere in the range [base,base+hint] = [base+,base+(hint+1)) while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) < 0) //we are iterating backwards lastOffset = offset - offset = (offset << 1) + 1 //1 3 7 15 + offset = BITSHIFT_LEFT(offset, 1) + 1 //1 3 7 15 //if(offset <= 0) //int overflow, not an issue here since we are using floats // offset = maxOffset @@ -340,7 +340,7 @@ reverse a descending sequence without violating stability. var/maxOffset = len - hint //therefore we want to insert somewhere in the range (base+hint,base+len) = [base+hint+1, base+hint+(len-hint)) while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) >= 0) lastOffset = offset - offset = (offset << 1) + 1 + offset = BITSHIFT_LEFT(offset, 1) + 1 //if(offset <= 0) //int overflow, not an issue here since we are using floats // offset = maxOffset @@ -354,7 +354,7 @@ reverse a descending sequence without violating stability. ++lastOffset while(lastOffset < offset) - var/m = lastOffset + ((offset - lastOffset) >> 1) + var/m = lastOffset + BITSHIFT_RIGHT((offset - lastOffset), 1) if(call(cmp)(key, fetchElement(L,base+m)) < 0) //key <= L[base+m] offset = m diff --git a/code/_helpers/spawn_sync.dm b/code/_helpers/spawn_sync.dm deleted file mode 100644 index 6c1733ef5bca..000000000000 --- a/code/_helpers/spawn_sync.dm +++ /dev/null @@ -1,86 +0,0 @@ -//------------------------------- -/* - Spawn sync helper - - Helps syncronize spawn()ing multiple processes in loops. - - Example for using this: - - //Create new spawn_sync datum - var/datum/spawn_sync/sync = new() - - for(var/obj/O in list) - //Call start_worker(), passing it first the object, then a string of the name of the proc you want called, then - // any and all arguments you want passed to the proc. - sync.start_worker(O, "do_something", arg1, arg2) - - //Finally call wait_until_done() - sync.wait_until_done() - - //Once all the workers have completed, or the failsafe has triggered, the code will continue. By default the - // failsafe is roughly 10 seconds (100 checks). -*/ -//------------------------------- -/datum/spawn_sync - var/count = 1 - var/failsafe = 100 //how many checks before the failsafe triggers and the helper stops waiting - -//Opens a thread counter -/datum/spawn_sync/proc/open() - count++ - -//Closes a thread counter -/datum/spawn_sync/proc/close() - count-- - -//Finalizes the spawn sync by removing the original starting count -/datum/spawn_sync/proc/finalize() - close() - -//Resets the counter if you want to utilize the same datum multiple times -// Optional: pass the number of checks you want for the failsafe -/datum/spawn_sync/proc/reset(var/safety = 100) - count = 1 - failsafe = safety - -//Check if all threads have returned -// Returns 0 if not all threads have completed -// Returns 1 if all threads have completed -/datum/spawn_sync/proc/check() - safety_check() - return count > 0 ? 1 : 0 - -//Failsafe in case something breaks horribly -/datum/spawn_sync/proc/safety_check() - failsafe-- - if(failsafe < 1) - count = 0 - -//Set failsafe check count in case you need more time for the workers to return -/datum/spawn_sync/proc/set_failsafe(var/safety) - failsafe = safety - -/datum/spawn_sync/proc/start_worker() - //Extract the thread run proc and it's arguments from the variadic args list. - ASSERT(args.len > 0) - var/obj = args[1] - var/thread_proc = args[2] - - //dispatch a new thread - open() - spawn() - //Utilise try/catch keywords here so the code continues even if an error occurs. - try - call(obj, thread_proc)(arglist(args.Copy(3))) - catch(var/exception/e) - error("[e] on [e.file]:[e.line]") - close() - -/datum/spawn_sync/proc/wait_until_done() - finalize() - - //Create a while loop to check if the sync is complete yet, it will return once all the spawn threads have - // completed, or the failsafe has expired. - while(check()) - //Add a sleep call to delay each check. - sleep(1) diff --git a/code/_helpers/storage.dm b/code/_helpers/storage.dm index 2d415a55ac55..5437f13c60d2 100644 --- a/code/_helpers/storage.dm +++ b/code/_helpers/storage.dm @@ -20,7 +20,7 @@ /datum/atom_creator/simple var/path var/probability - var/prob_method = /proc/prob_call + var/prob_method = GLOBAL_PROC_REF(prob_call) /datum/atom_creator/simple/New(var/path, var/probability) if(args.len != 2) @@ -36,7 +36,7 @@ /datum/atom_creator/weighted var/list/paths - var/selection_method = /proc/pickweight + var/selection_method = GLOBAL_PROC_REF(pickweight) /datum/atom_creator/weighted/New(var/list/paths) if(args.len != 1) diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 9ca1bcae4217..cef6a0ba6e65 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -14,67 +14,103 @@ */ // Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts. -/proc/sanitizeSQL(var/t as text) - var/sqltext = dbcon.Quote(t); - return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that +/proc/sanitize_sql(t) + var/sqltext = dbcon.Quote("[t]") // http://www.byond.com/forum/post/2218538 + return copytext(sqltext, 2, -1) /* * Text sanitization */ +/** + * Strip out the special beyond characters for \proper and \improper + * from text that will be sent to the browser. + */ +#define strip_improper(input_text) replacetext(replacetext(input_text, "\proper", ""), "\improper", "") +var/global/regex/starts_uppercase_regex = regex(@"^[A-Z]") +var/global/regex/starts_lowercase_regex = regex(@"^[a-z]") +#define is_proper(input_text) ((findtext(input_text, "\proper") == 1) || findtext(input_text, starts_uppercase_regex)) +#define is_improper(input_text) ((findtext(input_text, "\improper") == 1 || findtext(input_text, starts_lowercase_regex))) + //Used for preprocessing entered text //Added in an additional check to alert players if input is too long -/proc/sanitize(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1) +/proc/sanitize(input, max_length = MAX_MESSAGE_LEN, encode = TRUE, trim = TRUE, extra = TRUE, ascii_only = FALSE) if(!input) return if(max_length) - //testing shows that just looking for > max_length alone will actually cut off the final character if message is precisely max_length, so >= instead - if(length(input) >= max_length) - var/overflow = ((length(input)+1) - max_length) - to_chat(usr, "Your message is too long by [overflow] character\s.") + var/input_length = length_char(input) + if(input_length > max_length) + to_chat(usr, SPAN_WARNING("Your message is too long by [input_length - max_length] character\s.")) return - input = copytext(input,1,max_length) + input = copytext_char(input, 1, max_length + 1) + + input = strip_improper(input) if(extra) input = replace_characters(input, list("\n"=" ","\t"=" ")) + if(ascii_only) + // Some procs work differently depending on unicode/ascii string + // You should always consider this with any text processing work + // More: http://www.byond.com/docs/ref/info.html#/{notes}/Unicode + // http://www.byond.com/forum/post/2520672 + input = strip_non_ascii(input) + else + // Strip Unicode control/space-like chars here exept for line endings (\n,\r) and normal space (0x20) + // codes from https://www.compart.com/en/unicode/category/ + // https://en.wikipedia.org/wiki/Whitespace_character#Unicode + var/static/regex/unicode_control_chars = regex(@"[\u0001-\u0009\u000B\u000C\u000E-\u001F\u007F\u0080-\u009F\u00A0\u1680\u180E\u2000-\u200D\u2028\u2029\u202F\u205F\u2060\u3000\uFEFF]", "g") + input = unicode_control_chars.Replace(input, "") + // Allows at most one Unicode combining diacritical mark in a row + // Codes acquired from https://en.wikipedia.org/wiki/Combining_Diacritical_Marks + // https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_Extended + // https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_Supplement + // https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols + // https://en.wikipedia.org/wiki/Combining_Half_Marks + var/static/regex/unicode_diacritical_marks = regex(@"([\u0300-\u036F\u1AB0-\u1ACE\u1DC0-\u1DFF\u20D0-\u20F0\uFE20-\uFE2F]){2,}", "g") + input = unicode_diacritical_marks.Replace(input, "$1") + if(encode) - // The below \ escapes have a space inserted to attempt to enable Travis auto-checking of span class usage. Please do not remove the space. - //In addition to processing html, html_encode removes byond formatting codes like "\ red", "\ i" and other. - //It is important to avoid double-encode text, it can "break" quotes and some other characters. - //Also, keep in mind that escaped characters don't work in the interface (window titles, lower left corner of the main window, etc.) + // In addition to processing html, html_encode removes byond formatting codes like "\red", "\i" and other. + // It is important to avoid double-encode text, it can "break" quotes and some other characters. + // Also, keep in mind that escaped characters don't work in the interface (window titles, lower left corner of the main window, etc.) input = html_encode(input) else - //If not need encode text, simply remove < and > - //note: we can also remove here byond formatting codes: 0xFF + next byte + // If not need encode text, simply remove < and > + // note: we can also remove here byond formatting codes: 0xFF + next byte input = replace_characters(input, list("<"=" ", ">"=" ")) if(trim) - //Maybe, we need trim text twice? Here and before copytext? input = trim(input) return input -//Run sanitize(), but remove <, >, " first to prevent displaying them as > < &34; in some places, after html_encode(). +//Run sanitize(), but remove <, >, " first to prevent displaying them as > < &34; in some places after html_encode(). //Best used for sanitize object names, window titles. -//If you have a problem with sanitize() in chat, when quotes and >, < are displayed as html entites - -//this is a problem of double-encode(when & becomes &), use sanitize() with encode=0, but not the sanitizeSafe()! -/proc/sanitizeSafe(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1) - return sanitize(replace_characters(input, list(">"=" ","<"=" ", "\""="'")), max_length, encode, trim, extra) +//If you have a problem with sanitize() in chat, when quotes and >, < are displayed as html entities - +//this is a problem of double-encode(when & becomes &), use sanitize() with encode=0, but not the sanitize_safe()! +/proc/sanitize_safe(input, max_length = MAX_MESSAGE_LEN, encode = TRUE, trim = TRUE, extra = TRUE, ascii_only = FALSE) + return sanitize(replace_characters(input, list(">"=" ","<"=" ", "\""="'")), max_length, encode, trim, extra, ascii_only) //Filters out undesirable characters from names -/proc/sanitizeName(var/input, var/max_length = MAX_NAME_LEN, var/allow_numbers = 0, var/force_first_letter_uppercase = TRUE) - if(!input || length(input) > max_length) +/proc/sanitize_name(input, max_length = MAX_NAME_LEN, allow_numbers = 0, force_first_letter_uppercase = TRUE) + if(!input || length_char(input) > max_length) return //Rejects the input if it is null or if it is longer then the max length allowed var/number_of_alphanumeric = 0 var/last_char_group = 0 var/output = "" - for(var/i=1, i<=length(input), i++) - var/ascii_char = text2ascii(input,i) - switch(ascii_char) + var/char = "" + var/bytes_length = length(input) + var/ascii_char + for(var/i = 1, i <= bytes_length, i += length(char)) + char = input[i] + + ascii_char = text2ascii(char) + + switch(ascii_char) //todo: unicode names? // A .. Z if(65 to 90) //Uppercase Letters output += ascii2text(ascii_char) @@ -122,39 +158,107 @@ if(number_of_alphanumeric < 2) return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '" if(last_char_group == 1) - output = copytext(output,1,length(output)) //removes the last character (in this case a space) - - for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai","plating")) //prevents these common metagamey names - if(cmptext(output,bad_name)) return //(not case sensitive) + output = copytext(output, 1, -1) //removes the last character (in this case a space) return output +// UNICODE: Convert to regex? + //Used to strip text of everything but letters and numbers, make letters lowercase, and turn spaces into .'s. //Make sure the text hasn't been encoded if using this. -/proc/sanitize_for_email(text) +/proc/sanitize_for_account(text) if(!text) return "" var/list/dat = list() - var/last_was_space = 1 + var/last_was_fullstop = 1 for(var/i=1, i<=length(text), i++) var/ascii_char = text2ascii(text,i) switch(ascii_char) if(65 to 90) //A-Z, make them lowercase dat += ascii2text(ascii_char + 32) + last_was_fullstop = 0 if(97 to 122) //a-z dat += ascii2text(ascii_char) - last_was_space = 0 + last_was_fullstop = 0 if(48 to 57) //0-9 dat += ascii2text(ascii_char) - last_was_space = 0 + last_was_fullstop = 0 if(32) //space - if(last_was_space) + if(last_was_fullstop) continue dat += "." //We turn these into ., but avoid repeats or . at start. - last_was_space = 1 + last_was_fullstop = 1 + if(46) //. + if(last_was_fullstop) + continue + dat += "." + last_was_fullstop = 1 if(dat[length(dat)] == ".") //kill trailing . dat.Cut(length(dat)) return jointext(dat, null) +// Strips text of everything alphanumeric characters, '_' and '-'. Converts spaces to '_' +/proc/sanitize_for_group(text) + if(!text) return "" + var/list/dat = list() + for(var/i=1, i<=length(text), i++) + var/ascii_char = text2ascii(text,i) + switch(ascii_char) + if(65 to 90) //A-Z + dat += ascii2text(ascii_char) + if(97 to 122) //a-z + dat += ascii2text(ascii_char) + if(48 to 57) //0-9 + dat += ascii2text(ascii_char) + if(45, 95) //-, _ + dat += ascii2text(ascii_char) + if(32) //space + dat += "_" + return jointext(dat, null) + +//Used to strip text of everything but letters and numbers, and select special symbols. +//Requires that the filename has an alphanumeric character. +/proc/sanitize_for_file(text) + if(!text) return "" + var/list/dat = list() + var/has_alphanumeric = FALSE + var/last_was_fullstop = FALSE + for(var/i=1, i<=length(text), i++) + var/ascii_char = text2ascii(text,i) + switch(ascii_char) + if(65 to 90) //A-Z + dat += ascii2text(ascii_char) + has_alphanumeric = TRUE + last_was_fullstop = FALSE + if(97 to 122) //a-z + dat += ascii2text(ascii_char) + has_alphanumeric = TRUE + last_was_fullstop = FALSE + if(48 to 57) //0-9 + dat += ascii2text(ascii_char) + has_alphanumeric = TRUE + last_was_fullstop = FALSE + if(32) //space + dat += ascii2text(ascii_char) + last_was_fullstop = FALSE + if(33, 36, 40, 41, 42, 45, 95) //!, $, (, ), *, -, _ + dat += ascii2text(ascii_char) + last_was_fullstop = FALSE + if(46) //. + if(last_was_fullstop) // No repeats of . to avoid confusion with .. + continue + dat += ascii2text(ascii_char) + last_was_fullstop = TRUE + + if(!has_alphanumeric) + return "" + + if(dat[length(dat)] == ".") //kill trailing . + dat.Cut(length(dat)) + return jointext(dat, null) + + +// UNICODE: Convert to regex? + //Returns null if there is any bad text in the string /proc/reject_bad_text(var/text, var/max_length=512) if(length(text) > max_length) return //message too long @@ -210,7 +314,7 @@ * Text modification */ -/proc/replace_characters(var/t,var/list/repl_chars) +/proc/replace_characters(t, list/repl_chars) for(var/char in repl_chars) t = replacetext(t, char, repl_chars[char]) return t @@ -219,24 +323,16 @@ /proc/add_zero(t, u) return pad_left(t, u, "0") -//Adds 'u' number of spaces ahead of the text 't' -/proc/add_lspace(t, u) - return pad_left(t, u, " ") - -//Adds 'u' number of spaces behind the text 't' -/proc/add_tspace(t, u) - return pad_right(t, u, " ") - // Adds the required amount of 'character' in front of 'text' to extend the lengh to 'desired_length', if it is shorter // No consideration are made for a multi-character 'character' input /proc/pad_left(text, desired_length, character) - var/padding = generate_padding(length(text), desired_length, character) + var/padding = generate_padding(length_char(text), desired_length, character) return length(padding) ? "[padding][text]" : text // Adds the required amount of 'character' after 'text' to extend the lengh to 'desired_length', if it is shorter // No consideration are made for a multi-character 'character' input /proc/pad_right(text, desired_length, character) - var/padding = generate_padding(length(text), desired_length, character) + var/padding = generate_padding(length_char(text), desired_length, character) return length(padding) ? "[text][padding]" : text /proc/generate_padding(current_length, desired_length, character) @@ -247,32 +343,60 @@ characters += character return JOINTEXT(characters) - -//Returns a string with reserved characters and spaces before the first letter removed +// Returns a string with reserved characters and spaces before the first letter removed +// not work for unicode spaces - you should cleanup them first with sanitize() /proc/trim_left(text) for (var/i = 1 to length(text)) if (text2ascii(text, i) > 32) return copytext(text, i) return "" -//Returns a string with reserved characters and spaces after the last letter removed +// Returns a string with reserved characters and spaces after the last letter removed +// not work for unicode spaces - you should cleanup them first with sanitize() /proc/trim_right(text) for (var/i = length(text), i > 0, i--) if (text2ascii(text, i) > 32) return copytext(text, 1, i + 1) + return "" -//Returns a string with reserved characters and spaces before the first word and after the last word removed. +// Returns a string with reserved characters and spaces before the first word and after the last word removed. +// not work for unicode spaces - you should cleanup them first with sanitize() /proc/trim(text) return trim_left(trim_right(text)) //Returns a string with the first element of the string capitalized. -/proc/capitalize(var/t as text) - return uppertext(copytext(t, 1, 2)) + copytext(t, 2) +// NOTE: This will not work if there are any HTML tags. +/proc/capitalize(text) + if(text) + text = uppertext(text[1]) + copytext(text, 1 + length(text[1])) + return text + +// Returns a string with the first alphabetical element of the string capitalized, skipping HTML tags. +/proc/capitalize_proper_html(text) + var/static/regex/split_html_regex = regex(@"(^<[^>]*>)([A-Za-z])(.+)$") + if(!text) + return text + if(!split_html_regex.Find(text)) + return capitalize(text) + split_html_regex.group[2] = uppertext(split_html_regex.group[2]) + return JOINTEXT(split_html_regex.group) + +//Returns a string with the first element of the every word of the string capitalized. +/proc/capitalize_words(text) + var/list/S = splittext(text, " ") + var/list/M = list() + for (var/w in S) + M += capitalize(w) + return jointext(M, " ") + +/proc/strip_non_ascii(text) + var/static/regex/non_ascii_regex = regex(@"[^\x00-\x7F]+", "g") + return non_ascii_regex.Replace(text, "") //This proc strips html properly, remove < > and all text between //for complete text sanitizing should be used sanitize() -/proc/strip_html_properly(var/input) +/proc/strip_html_properly(input) if(!input) return var/opentag = 1 //These store the position of < and > respectively. @@ -295,48 +419,9 @@ return input -//This proc fills in all spaces with the "replace" var (* by default) with whatever -//is in the other string at the same spot (assuming it is not a replace char). -//This is used for fingerprints -/proc/stringmerge(var/text,var/compare,replace = "*") - var/newtext = text - if(length(text) != length(compare)) - return 0 - for(var/i = 1, i < length(text), i++) - var/a = copytext(text,i,i+1) - var/b = copytext(compare,i,i+1) - //if it isn't both the same letter, or if they are both the replacement character - //(no way to know what it was supposed to be) - if(a != b) - if(a == replace) //if A is the replacement char - newtext = copytext(newtext,1,i) + b + copytext(newtext, i+1) - else if(b == replace) //if B is the replacement char - newtext = copytext(newtext,1,i) + a + copytext(newtext, i+1) - else //The lists disagree, Uh-oh! - return 0 - return newtext - -//This proc returns the number of chars of the string that is the character -//This is used for detective work to determine fingerprint completion. -/proc/stringpercent(var/text,character = "*") - if(!text || !character) - return 0 - var/count = 0 - for(var/i = 1, i <= length(text), i++) - var/a = copytext(text,i,i+1) - if(a == character) - count++ - return count - -/proc/reverse_text(var/text = "") - var/new_text = "" - for(var/i = length(text); i > 0; i--) - new_text += copytext(text, i, i+1) - return new_text - //Used in preferences' SetFlavorText and human's set_flavor verb //Previews a string of len or less length -proc/TextPreview(var/string,var/len=40) +/proc/TextPreview(var/string,var/len=40) if(length(string) <= len) if(!length(string)) return "\[...\]" @@ -350,7 +435,7 @@ proc/TextPreview(var/string,var/len=40) return html_encode(copytext(html_decode(text), first, last)) /proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null) - if(!(C && C.get_preference_value(/datum/client_preference/chat_tags) == GLOB.PREF_SHOW)) + if(!(C && C.get_preference_value(/datum/client_preference/chat_tags) == PREF_SHOW)) return tagdesc return "[tagdesc]" @@ -379,14 +464,6 @@ proc/TextPreview(var/string,var/len=40) #define starts_with(string, substring) (copytext(string,1,1+length(substring)) == substring) -#define gender2text(gender) capitalize(gender) - -/** - * Strip out the special beyond characters for \proper and \improper - * from text that will be sent to the browser. - */ -#define strip_improper(input_text) replacetext(replacetext(input_text, "\proper", ""), "\improper", "") - /proc/pencode2html(t) t = replacetext(t, "\n", "
") t = replacetext(t, "\[center\]", "
") @@ -429,8 +506,8 @@ proc/TextPreview(var/string,var/len=40) /proc/digitalPencode2html(var/text) text = replacetext(text, "\[pre\]", "
")
 	text = replacetext(text, "\[/pre\]", "
") - text = replacetext(text, "\[fontred\]", "") // to pass travis html tag integrity check - text = replacetext(text, "\[fontblue\]", "")// to pass travis html tag integrity check + text = replacetext(text, "\[fontred\]", "") // to pass html tag unit test + text = replacetext(text, "\[fontblue\]", "")// to pass html tag unit test text = replacetext(text, "\[fontgreen\]", "") text = replacetext(text, "\[/font\]", "") text = replacetext(text, "\[redacted\]", "R E D A C T E D") @@ -440,8 +517,8 @@ proc/TextPreview(var/string,var/len=40) /proc/html2pencode(t) t = replacetext(t, "
", "\[pre\]")
 	t = replacetext(t, "
", "\[/pre\]") - t = replacetext(t, "", "\[fontred\]")// to pass travis html tag integrity check - t = replacetext(t, "", "\[fontblue\]")// to pass travis html tag integrity check + t = replacetext(t, "", "\[fontred\]")// to pass html tag unit test + t = replacetext(t, "", "\[fontblue\]")// to pass html tag unit test t = replacetext(t, "", "\[fontgreen\]") t = replacetext(t, "", "\[/font\]") t = replacetext(t, "
", "\[br\]") @@ -548,9 +625,9 @@ proc/TextPreview(var/string,var/len=40) // If char isn't part of the text the entire text is returned /proc/copytext_after_last(var/text, var/char) - var/regex/R = regex("(\[^[char]\]*)$") - R.Find(text) - return R.group[1] + var/regex/copytext_regex = regex("(\[^[char]\]*)$") + copytext_regex.Find(text) + return copytext_regex.group[1] /proc/sql_sanitize_text(var/text) text = replacetext(text, "'", "''") @@ -558,6 +635,216 @@ proc/TextPreview(var/string,var/len=40) text = replacetext(text, "&", "") return text -// Switch to use copytext_char() when 513 is in -var/list/fullstop_alternatives = list(".", "!", "?") -#define APPEND_FULLSTOP_IF_NEEDED(TXT) ((copytext(TXT, -1, 0) in global.fullstop_alternatives) ? TXT : "[TXT].") +var/global/list/fullstop_alternatives = list(".", "!", "?") +#define APPEND_FULLSTOP_IF_NEEDED(TXT) ((copytext_char(TXT, -1, 0) in global.fullstop_alternatives) ? TXT : "[TXT].") + +/proc/make_rainbow(var/msg) + var/static/list/rainbow_classes = list( + "font_red", + "font_orange", + "font_yellow", + "font_green", + "font_blue", + "font_violet", + "font_purple" + ) + for(var/i = 1 to length(msg)) + . += "[copytext(msg, i, i+1)]" + +// Returns direction-string, rounded to multiples of 22.5, from the first parameter to the second +// N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW +/proc/get_compass_direction_string(var/turf/A, var/turf/B) + var/degree = Get_Angle(A, B) + switch(round(degree, 22.5) % 360) // % appears to round down floats, hence below values all being integers + if(0) + return "North" + if(22) + return "North-Northeast" + if(45) + return "Northeast" + if(67) + return "East-Northeast" + if(90) + return "East" + if(112) + return "East-Southeast" + if(135) + return "Southeast" + if(157) + return "South-Southeast" + if(180) + return "South" + if(202) + return "South-Southwest" + if(225) + return "Southwest" + if(247) + return "West-Southwest" + if(270) + return "West" + if(292) + return "West-Northwest" + if(315) + return "Northwest" + if(337) + return "North-Northwest" + +///Returns true if the text starts with the given sequence of characters. +/proc/text_starts_with(var/text, var/start) + return copytext(text, 1, length(start) + 1) == start + +///Returns true if the text ends with the given sequence of characters. +/proc/text_ends_with(var/text, var/end) + var/tlen = length(text) + return copytext(text, ((tlen - length(end)) + 1), tlen + 1) == end + +///Returns true if the text ends with ANY of the given sequences of characters. +/proc/text_ends_with_any_of(var/text, var/list/endings) + for(var/ending in endings) + if(text_ends_with(text, ending)) + return ending + return + +///Siblants that should end with es +var/global/list/plural_siblants = list("ss", "x", "sh", "ch") +///Vocalized y sounds that needs to end in -ies when made plural +var/global/list/plural_vocalized_y = list("quy", "by", "dy", "fy", "gy", "hy", "jy", "ky", "ly", "my", "ny", "py", "ry", "sy", "ty", "vy", "xy", "zy") +///Plurals endings in -ves +var/global/list/plural_endings_in_ves = list("fe", "af") +///Plurals endings in -sses or -zzes +var/global/list/plural_endings_with_doubled_letter = list("as", "ez") +///Words that have a different plural form, and their plural form +var/global/list/apophonic_plurals = list( + "foot" = "feet", + "goose" = "geese", + "louse" = "lice", + "man" = "men", + "woman" = "women", + "mouse" = "mice", + "tooth" = "teeth", + "ox" = "oxen", + //#TODO: Add more of those +) +///Used to tell how to make it a plural word and etc. +var/global/list/english_loanwords = list( + "fungus", + "cactus", + //#TODO: Add more of those +) +///Words that stay the same in plural +var/global/list/plural_words_unchanged = list( + "series", + "means", + "species" + //#TODO: Add more of those +) + +///Properly changes the given word (or the last word of the string) into a plural word. Applies a bunch of exceptions from the english language. +/proc/text_make_plural(var/word) + if(!length(word)) + return + var/initial_word = word + //If someone passed us several words, just keep the last one. + var/list/splited = splittext_char(word, " ", 1, length(word)+1, FALSE) + //log_debug("splitted '[initial_word]' to [log_info_line(splited)].") + if(length(splited) > 1) + word = splited[splited.len] + else + splited = null + + //Words that don't change when pluralized + if(global.plural_words_unchanged[word]) + return initial_word + + //Apophonic plurals + if(global.apophonic_plurals[word]) + word = global.apophonic_plurals[word] + + //Siblants + plurals of nouns in -o preceded by a consonant. Loanwords ending in o just ends with an s + else if(text_ends_with_any_of(word, global.plural_siblants) || (text_ends_with(word, "o") && !(word in global.english_loanwords))) + word = "[word]es" + + //Plurals of nouns in -y + else if(text_ends_with_any_of(word, global.plural_vocalized_y)) + word = "[copytext(word, 1, length(word))]ies" + + // -f and -fe endings + else if(text_ends_with_any_of(word, global.plural_endings_in_ves)) + word = "[copytext(word, 1, length(word) - 1)]ves" //EX: calf -> calves, leaf -> leaves, knife -> knives + + //some ‘-s’ and ‘-z’ endings + else if(text_ends_with_any_of(word, global.plural_endings_with_doubled_letter)) + word = "[word][copytext(word, length(word), length(word) + 1)]es" //Ex: gas -> gas'ses', fez -> fez'zes' + + //Plurals of nouns in -us + else if(text_ends_with(word, "us")) + if(!(word in global.english_loanwords)) + word = "[word]es" + else + word = "[copytext(word, 1, length(word) - 1)]i" //EX: Cactus -> Cacti, Fungus -> Fungi + + //Finally just go with the basic rules + else + if(text_ends_with(word, "s")) + word = "[word]es" + else + word = "[word]s" + + //Put the sentence back together, if applicable + if(splited) + word = "[jointext(splited, " ", 1, length(splited))] [word]" + return word + +var/global/list/copula_verbs = list("is" = TRUE, "am" = TRUE, "are" = TRUE) +var/global/list/has_verbs = list("has" = TRUE, "have" = TRUE) +var/global/list/does_verbs = list("does" = TRUE, "do" = TRUE) +var/global/list/agreement_exception_verbs = list("can" = TRUE, "cannot" = TRUE, "can't" = TRUE, "will" = TRUE, "won't" = TRUE, "shall" = TRUE, "shan't" = TRUE, "may" = TRUE, "must" = TRUE, "ought" = TRUE, "could" = TRUE, "would" = TRUE, "should" = TRUE) +/proc/verb_agree_with_pronouns(var/use_verb, var/decl/pronouns/use_pronouns, is_after_pronoun = TRUE) + // deal with compound verb phrases here! + // basically, skip all our adverbs, inflect only the first non-adverb word we find (which is hopefully a verb) and then keep everything after unchanged + // this will properly handle "successfully finish doing" and "properly manage to do" + // but not "somehow finish doing" which will get turned into "somehows finish doing" :( + // todo: fix that + var/list/words = splittext(use_verb, " ") + if(length(words) > 1) + var/last_adverb = 1 + for(var/word_index in 1 to length(words)) + if(text_ends_with(words[word_index], "ly")) + last_adverb = max(word_index, last_adverb) + use_verb = words[last_adverb] + // This overengineered nonsense ensures that we shouldn't end up with any doubled or missing spaces. + return jointext_no_nulls(list(jointext(words.Copy(1, last_adverb), " "), verb_agree_with_pronouns(use_verb, use_pronouns, is_after_pronoun = is_after_pronoun), jointext(words.Copy(last_adverb + 1, length(words) + 1), " ")), " ") + if(!is_after_pronoun && use_pronouns.pluralize_verb == /decl/pronouns::PLURALIZE_PSEUDO) + return use_verb // do not inflect pseudoplural unless after a pronoun + if(global.copula_verbs[use_verb]) + return use_pronouns.is + else if(global.has_verbs[use_verb]) + return use_pronouns.has + else if(global.does_verbs[use_verb]) + return use_pronouns.does + else if(global.agreement_exception_verbs[use_verb]) + return use_verb + // text_make_plural is intended for nouns, but should hopefully work for "fly" -> "flies" and similar. + switch(use_pronouns.pluralize_verb) + if(/decl/pronouns::PLURALIZE_NONE) + return use_verb + if(/decl/pronouns::PLURALIZE_PSEUDO) + // technically only the plural side can get hit here + // but better safe than sorry + return is_after_pronoun ? text_make_plural(use_verb) : use_verb + if(/decl/pronouns::PLURALIZE_ALL) + return text_make_plural(use_verb) + else + CRASH("Invalid value [use_pronouns.pluralize_verb] for [use_pronouns]!") + +// Surely we have this defined somewhere already?? +/proc/repeatstring(str, num) + . = list() + for(var/i = 1 to num) + . += str + . = JOINTEXT(.) + +/proc/jointext_no_nulls(list/L, Glue, Start = 1, End = 0) + var/list/temp = L.Copy() + LIST_CLEAR_NULLS(temp) + return jointext(temp, Glue, Start, End) diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index da49855b96e5..14f373cda705 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -1,22 +1,55 @@ -/proc/get_game_time() - var/global/time_offset = 0 - var/global/last_time = 0 - var/global/last_usage = 0 - - var/wtime = world.time - var/wusage = world.tick_usage * 0.01 - - if(last_time < wtime && last_usage > 1) - time_offset += last_usage - 1 - - last_time = wtime - last_usage = wusage - - return wtime + (time_offset + wusage) * world.tick_lag - -var/roundstart_hour -var/station_date = "" -var/next_station_date_change = 1 DAY +/proc/minutes_to_readable(minutes) + if (!isnum(minutes)) + minutes = text2num(minutes) + + if (minutes < 0) + PRINT_STACK_TRACE("Negative minutes value supplied to minutes_to_readable().") + return "INFINITE" + else if (isnull(minutes)) + PRINT_STACK_TRACE("Null minutes value supplied to minutes_to_readable().") + return "BAD INPUT" + + var/hours = 0 + var/days = 0 + var/weeks = 0 + var/months = 0 + var/years = 0 + + if (minutes >= 518400) + years = round(minutes / 518400) + minutes = minutes - (years * 518400) + if (minutes >= 43200) + months = round(minutes / 43200) + minutes = minutes - (months * 43200) + if (minutes >= 10080) + weeks = round(minutes / 10080) + minutes = minutes - (weeks * 10080) + if (minutes >= 1440) + days = round(minutes / 1440) + minutes = minutes - (days * 1440) + if (minutes >= 60) + hours = round(minutes / 60) + minutes = minutes - (hours * 60) + + var/result = list() + if (years) + result += "[years] year\s" + if (months) + result += "[months] month\s" + if (weeks) + result += "[weeks] week\s" + if (days) + result += "[days] day\s" + if (hours) + result += "[hours] hour\s" + if (minutes) + result += "[minutes] minute\s" + + return jointext(result, ", ") + +var/global/roundstart_hour +var/global/station_date = "" +var/global/next_station_date_change = 1 DAY /proc/stationtime2text() return time2text(station_time_in_ticks, "hh:mm") @@ -29,31 +62,59 @@ var/next_station_date_change = 1 DAY if(!station_date || update_time) var/extra_days = round(station_time_in_ticks / (1 DAY)) DAYS var/timeofday = world.timeofday + extra_days - station_date = num2text(game_year) + "-" + time2text(timeofday, "MM-DD") + station_date = num2text(global.using_map.game_year) + "-" + time2text(timeofday, "MM-DD") return station_date /proc/time_stamp() return time2text(station_time_in_ticks, "hh:mm:ss") -/* Returns 1 if it is the selected month and day */ -proc/isDay(var/month, var/day) - if(isnum(month) && isnum(day)) - var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month - var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day - if(month == MM && day == DD) - return 1 - - // Uncomment this out when debugging! - //else - //return 1 - -var/next_duration_update = 0 -var/last_round_duration = 0 -var/round_start_time = 0 - -/hook/roundstart/proc/start_timer() - round_start_time = world.time - return 1 +var/global/next_duration_update = 0 +var/global/last_round_duration = 0 +var/global/round_start_time = 0 + +/proc/ticks2shortreadable(tick_time, separator = ":") + var/hours = round(tick_time / (1 HOUR)) + var/minutes = round((tick_time % (1 HOUR)) / (1 MINUTE)) + var/seconds = round((tick_time % (1 MINUTE)) / (1 SECOND)) + var/out = list() + + if(hours > 0) + out += "[hours]" + + if(minutes > 0) + if(minutes < 10 && hours > 0) + out += "0[minutes]" + else + out += "[minutes]" + else if(hours > 0) + out += "00" + + if(seconds > 0) + if(seconds < 10 && (minutes > 0 || hours > 0)) + out += "0[seconds]" + else + out += "[seconds]" + else if(minutes > 0 || hours > 0) + out += "00" + + if(length(out)) + return jointext(out, separator) + return null + +/proc/ticks2readable(tick_time) + var/hours = round(tick_time / (1 HOUR)) + var/minutes = round((tick_time % (1 HOUR)) / (1 MINUTE)) + var/seconds = round((tick_time % (1 MINUTE)) / (1 SECOND)) + var/out = list() + if(hours > 0) + out += "[hours] hour\s" + if(minutes > 0) + out += "[minutes] minute\s" + if(seconds > 0) + out += "[seconds] second\s" + if(length(out)) + return english_list(out) + return "less than a second" /proc/roundduration2text() if(!round_start_time) @@ -62,7 +123,7 @@ var/round_start_time = 0 return last_round_duration var/mills = round_duration_in_ticks // 1/10 of a second, not real milliseconds but whatever - //var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something + //var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for reference or something var/mins = round((mills % 36000) / 600) var/hours = round(mills / 36000) @@ -73,41 +134,45 @@ var/round_start_time = 0 next_duration_update = world.time + 1 MINUTES return last_round_duration -/hook/startup/proc/set_roundstart_hour() - roundstart_hour = pick(2,7,12,17) - return 1 - -GLOBAL_VAR_INIT(midnight_rollovers, 0) -GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) +var/global/midnight_rollovers = 0 +var/global/rollovercheck_last_timeofday = 0 /proc/update_midnight_rollover() - if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS! - GLOB.midnight_rollovers += 1 - GLOB.rollovercheck_last_timeofday = world.timeofday - return GLOB.midnight_rollovers - -//Increases delay as the server gets more overloaded, -//as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful -#define DELTA_CALC max(((max(world.tick_usage, world.cpu) / 100) * max(Master.sleep_delta,1)), 1) - -/proc/stoplag() - if (!Master || !(GAME_STATE & RUNLEVELS_DEFAULT)) + if (world.timeofday < global.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS! + global.midnight_rollovers += 1 + global.rollovercheck_last_timeofday = world.timeofday + return global.midnight_rollovers + +/// Increases delay as the server gets more overloaded +/// as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful +#define DELTA_CALC max(((max(TICK_USAGE, world.cpu) / 100) * max(Master.sleep_delta-1,1)), 1) + +/// returns the number of ticks slept +/proc/stoplag(initial_delay) + // If we're initializing, our tick limit might be over 100 (testing config), but stoplag() penalizes procs that go over. + // Unfortunately, this penalty slows down init a *lot*. So, we disable it during boot and lobby, when relatively few things should be calling this. + if (!Master || Master.current_runlevel < 3) sleep(world.tick_lag) return 1 + + if (!initial_delay) + initial_delay = world.tick_lag +// Unit tests are not the normal environemnt. The mc can get absolutely thigh crushed, and sleeping procs running for ages is much more common +// We don't want spurious hard deletes off this, so let's only sleep for the requested period of time here yeah? +#ifdef UNIT_TEST + sleep(initial_delay) + return NONUNIT_CEILING(DS2TICKS(initial_delay), 1) +#else . = 0 - var/i = 1 + var/i = DS2TICKS(initial_delay) do - . += round(i*DELTA_CALC) - sleep(i*world.tick_lag*DELTA_CALC) + . += NONUNIT_CEILING(i*DELTA_CALC, 1) + sleep(i * world.tick_lag * DELTA_CALC) i *= 2 - while (world.tick_usage > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit)) + while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit)) +#endif #undef DELTA_CALC -/proc/acquire_days_per_month() - . = list(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) - if(isLeap(text2num(time2text(world.realtime, "YYYY")))) - .[2] = 29 - /proc/current_month_and_day() var/time_string = time2text(world.realtime, "MM-DD") var/time_list = splittext(time_string, "-") diff --git a/code/_helpers/tools.dm b/code/_helpers/tools.dm deleted file mode 100644 index 2d279e24d90a..000000000000 --- a/code/_helpers/tools.dm +++ /dev/null @@ -1,56 +0,0 @@ -#define isWrench(A) (A && A.iswrench()) -#define isWelder(A) (A && A.iswelder()) -#define isCoil(A) (A && A.iscoil()) -#define isWirecutter(A) (A && A.iswirecutter()) -#define isScrewdriver(A) (A && A.isscrewdriver()) -#define isMultitool(A) (A && A.ismultitool()) -#define isCrowbar(A) (A && A.iscrowbar()) -#define isHatchet(A) (A && A.ishatchet()) - -/atom/proc/iswrench() - return FALSE - -/atom/proc/iswelder() - return FALSE - -/atom/proc/iscoil() - return FALSE - -/atom/proc/iswirecutter() - return FALSE - -/atom/proc/isscrewdriver() - return FALSE - -/atom/proc/ismultitool() - return FALSE - -/atom/proc/iscrowbar() - return FALSE - -/atom/proc/ishatchet() - return FALSE - -/obj/item/wrench/iswrench() - return TRUE - -/obj/item/weldingtool/iswelder() - return TRUE - -/obj/item/stack/cable_coil/iscoil() - return TRUE - -/obj/item/wirecutters/iswirecutter() - return TRUE - -/obj/item/screwdriver/isscrewdriver() - return TRUE - -/obj/item/multitool/ismultitool() - return TRUE - -/obj/item/crowbar/iscrowbar() - return TRUE - -/obj/item/hatchet/ishatchet() - return TRUE \ No newline at end of file diff --git a/code/_helpers/turfs.dm b/code/_helpers/turfs.dm index 25944cde8f50..d74b742f97a5 100644 --- a/code/_helpers/turfs.dm +++ b/code/_helpers/turfs.dm @@ -6,12 +6,6 @@ mloc = mloc.loc return mloc -/proc/turf_clear(turf/T) - for(var/atom/A in T) - if(A.simulated) - return 0 - return 1 - // Picks a turf without a mob from the given list of turfs, if one exists. // If no such turf exists, picks any random turf from the given list of turfs. /proc/pick_mobless_turf_if_exists(var/list/start_turfs) @@ -33,7 +27,7 @@ return var/list/turfs = list() for(var/turf/T in orange(origin, outer_range)) - if(!(T.z in GLOB.using_map.sealed_levels)) // Picking a turf outside the map edge isn't recommended + if(!isSealedLevel(T.z)) // Picking a turf outside the map edge isn't recommended if(T.x >= world.maxx-TRANSITIONEDGE || T.x <= TRANSITIONEDGE) continue if(T.y >= world.maxy-TRANSITIONEDGE || T.y <= TRANSITIONEDGE) continue if(!inner_range || get_dist(origin, T) >= inner_range) @@ -41,35 +35,19 @@ if(turfs.len) return pick(turfs) -/proc/screen_loc2turf(text, turf/origin) - if(!origin) - return null - var/tZ = splittext(text, ",") - var/tX = splittext(tZ[1], "-") - var/tY = text2num(tX[2]) - tX = splittext(tZ[2], "-") - tX = text2num(tX[2]) - tZ = origin.z - tX = max(1, min(origin.x + 7 - tX, world.maxx)) - tY = max(1, min(origin.y + 7 - tY, world.maxy)) - return locate(tX, tY, tZ) - /* Predicate helpers */ -/proc/is_space_turf(var/turf/T) - return istype(T, /turf/space) - -/proc/is_not_space_turf(var/turf/T) - return !is_space_turf(T) - /proc/is_holy_turf(var/turf/T) - return T && T.holy + return (T?.turf_flags & TURF_FLAG_HOLY) /proc/is_not_holy_turf(var/turf/T) return !is_holy_turf(T) +/proc/turf_is_simulated(var/turf/T) + return T.simulated + /proc/turf_contains_dense_objects(var/turf/T) return T.contains_dense_objects() @@ -79,11 +57,8 @@ /proc/is_station_turf(var/turf/T) return T && isStationLevel(T.z) -/proc/has_air(var/turf/T) - return !!T.return_air() - /proc/IsTurfAtmosUnsafe(var/turf/T) - if(istype(T, /turf/space)) // Space tiles + if(isspaceturf(T)) // Space tiles return "Spawn location is open to space." var/datum/gas_mixture/air = T.return_air() if(!air) @@ -106,22 +81,39 @@ //Returns an assoc list that describes how turfs would be changed if the //turfs in turfs_src were translated by shifting the src_origin to the dst_origin -/proc/get_turf_translation(turf/src_origin, turf/dst_origin, list/turfs_src) +/proc/get_turf_translation(turf/src_origin, turf/dst_origin, list/turfs_src, angle = 0) + angle = round(SIMPLIFY_DEGREES(angle), 90) // can only turn at right angles + var/adj = 1 + var/opp = 0 + switch(angle) + if(90) + adj = 0 + opp = 1 // swap the X and Y axes + if(180) + adj = -1 // flip across the axes + opp = 0 + if(270) + adj = 0 + opp = -1 // swap the X and Y axes and then flip var/list/turf_map = list() for(var/turf/source in turfs_src) - var/x_pos = (source.x - src_origin.x) - var/y_pos = (source.y - src_origin.y) - var/z_pos = (source.z - src_origin.z) + var/dx = (source.x - src_origin.x) + var/dy = (source.y - src_origin.y) + var/dz = (source.z - src_origin.z) + var/x_pos = dst_origin.x + dx * adj + dy * opp + var/y_pos = dst_origin.y + dy * adj - dx * opp // y-axis is flipped in BYOND :( + var/z_pos = dst_origin.z + dz - var/turf/target = locate(dst_origin.x + x_pos, dst_origin.y + y_pos, dst_origin.z + z_pos) + var/turf/target = locate(x_pos, y_pos, z_pos) if(!target) - error("Null turf in translation @ ([dst_origin.x + x_pos], [dst_origin.y + y_pos], [dst_origin.z + z_pos])") + error("Null turf in translation @ ([x_pos], [y_pos], [z_pos])") turf_map[source] = target //if target is null, preserve that information in the turf map return turf_map -/proc/translate_turfs(var/list/translation, var/area/base_area = null, var/turf/base_turf) +/proc/translate_turfs(list/translation, area/base_area = null, turf/base_turf, ignore_background, translate_air, angle = 0) + . = list() for(var/turf/source in translation) var/turf/target = translation[source] @@ -129,30 +121,138 @@ if(target) if(base_area) ChangeArea(target, get_area(source)) - transport_turf_contents(source, target) + . += transport_turf_contents(source, target, ignore_background, translate_air, angle = angle) ChangeArea(source, base_area) else - transport_turf_contents(source, target) + . += transport_turf_contents(source, target, ignore_background, translate_air, angle = angle) //change the old turfs for(var/turf/source in translation) - source.ChangeTurf(base_turf ? base_turf : get_base_turf_by_area(source), 1, 1) + if(ignore_background && (source.turf_flags & TURF_FLAG_BACKGROUND)) + continue + var/old_turf = source.prev_type || base_turf || get_base_turf_by_area(source) + var/turf/changed = source.ChangeTurf(old_turf, keep_air = !translate_air) + changed.prev_type = null + +// Currently used only for shuttles. If it gets generalized rename it. +/atom/proc/shuttle_rotate(angle) + if(angle) + set_dir(SAFE_TURN(dir, angle)) + addtimer(CALLBACK(src, PROC_REF(queue_icon_update)), 1) + return TRUE + +// Adjust pixel_x, pixel_y, etc. for things without directional_offset. +// This may cause issues with things that shouldn't rotate. Those should be using pixel_w and pixel_z, preferably! +/obj/shuttle_rotate(angle) + . = ..() + if(. && isnull(directional_offset) && (pixel_x || pixel_y)) + var/adj = cos(angle) + var/opp = sin(angle) + var/old_pixel_x = pixel_x + var/old_pixel_y = pixel_y + pixel_x = adj * old_pixel_x + opp * old_pixel_y + pixel_y = adj * old_pixel_y + opp * old_pixel_x + +/obj/structure/shuttle_rotate(angle) + . = ..() + if(.) + addtimer(CALLBACK(src, PROC_REF(update_connections), TRUE), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, queue_icon_update)), 1) + +/obj/machinery/network/requests_console/shuttle_rotate(angle) + . = ..(-angle) // for some reason directions are switched for these + +/obj/machinery/firealarm/shuttle_rotate(angle) + . = ..(-angle) + +/obj/machinery/door/shuttle_rotate(angle) + . = ..() + if(.) + addtimer(CALLBACK(src, PROC_REF(update_connections), TRUE), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, queue_icon_update)), 1) //Transports a turf from a source turf to a target turf, moving all of the turf's contents and making the target a copy of the source. -/proc/transport_turf_contents(turf/source, turf/target) +//If ignore_background is set to true, turfs with TURF_FLAG_BACKGROUND set will only translate anchored contents. +//Returns the new turf, or list(new turf, source) if a background turf was ignored and things may have been left behind. +/proc/transport_turf_contents(turf/source, turf/target, ignore_background, translate_air, angle = 0) + var/target_type = target.type + var/turf/new_turf + // byond's coordinate system is weird so we have to invert the angle + angle = -angle + + var/is_background = ignore_background && (source.turf_flags & TURF_FLAG_BACKGROUND) + var/supported = FALSE // Whether or not there's an object in the turf which can support other objects. + if(is_background) + new_turf = target + else + new_turf = target.ChangeTurf(source.type, 1, 1, !translate_air) + new_turf.transport_properties_from(source, translate_air) + new_turf.shuttle_rotate(angle) + new_turf.prev_type = target_type - var/turf/new_turf = target.ChangeTurf(source.type, 1, 1) - new_turf.transport_properties_from(source) + for(var/obj/O in source) + if(O.obj_flags & OBJ_FLAG_NOFALL) + supported = TRUE + break for(var/obj/O in source) - if(O.simulated) + if((O.movable_flags & MOVABLE_FLAG_ALWAYS_SHUTTLEMOVE) || (O.simulated && (!is_background || supported || (O.obj_flags & OBJ_FLAG_MOVES_UNSUPPORTED)))) O.forceMove(new_turf) - else if(istype(O,/obj/effect)) - var/obj/effect/E = O - if(E.movable_flags & MOVABLE_FLAG_EFFECTMOVE) - E.forceMove(new_turf) + O.shuttle_rotate(angle) for(var/mob/M in source) - if(isEye(M)) continue // If we need to check for more mobs, I'll add a variable + if(is_background && !supported) + continue + if(isEye(M)) + continue // If we need to check for more mobs, I'll add a variable M.forceMove(new_turf) + M.shuttle_rotate(angle) + + if(is_background) + return list(new_turf, source) return new_turf + +/proc/get_dir_z_text(turf/origin, turf/target) + + origin = get_turf(origin) + target = get_turf(target) + + if(!istype(origin) || !istype(target) || !(origin.z in SSmapping.get_connected_levels(target.z, include_lateral = TRUE))) + return "somewhere" + if(origin == target) + return "right next to you" + + var/datum/level_data/origin_level = SSmapping.levels_by_z[origin.z] + var/datum/level_data/target_level = SSmapping.levels_by_z[target.z] + + if(origin_level.z_volume_level_z < target_level.z_volume_level_z) + . += "above and to" + else if(origin_level.z_volume_level_z > target_level.z_volume_level_z) + . += "below and to" + + var/origin_x = origin.x + origin_level.z_volume_level_x + var/origin_y = origin.y + origin_level.z_volume_level_y + var/target_x = target.x + target_level.z_volume_level_x + var/target_y = target.y + target_level.z_volume_level_y + + if(origin_x == target_x) + if(origin_y > target_y) + . += "the south" + else + . += "the north" + else if(origin_y == target_y) + if(origin_x > target_x) + . += "the west" + else + . += "the east" + else + if(origin_x > target_x) + if(origin_y > target_y) + . += "the southwest" + else + . += "the northwest" + else + if(origin_y > target_y) + . += "the southeast" + else + . += "the northeast" diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm index d32e60f38855..ed43cf149ee3 100644 --- a/code/_helpers/type2type.dm +++ b/code/_helpers/type2type.dm @@ -1,84 +1,23 @@ /* * Holds procs designed to change one type of value, into another. * Contains: - * hex2num & num2hex - * text2list & list2text + * alist2list * file2list * angle2dir * angle2text - * worldtime2text */ -// Returns an integer given a hexadecimal number string as input. -/proc/hex2num(hex, safe=FALSE) - . = 0 - var/place = 1 - for(var/i in length(hex) to 1 step -1) - var/num = text2ascii(hex, i) - switch(num) - if(48 to 57) - num -= 48 //0-9 - if(97 to 102) - num -= 87 //a-f - if(65 to 70) - num -= 55 //A-F - if(45) - return . * -1 // - - else - if(safe) - return null - else - CRASH("Malformed hex number") - - . += num * place - place *= 16 - -// Returns the hex value of a number given a value assumed to be a base-ten value -/proc/num2hex(num, len=2) - if(!isnum(num)) - num = 0 - num = round(abs(num)) - . = "" - var/i=0 - while(1) - if(len<=0) - if(!num) - break - else - if(i>=len) - break - var/remainder = num/16 - num = round(remainder) - remainder = (remainder - num) * 16 - switch(remainder) - if(9,8,7,6,5,4,3,2,1) - . = "[remainder]" + . - if(10,11,12,13,14,15) - . = ascii2text(remainder+87) + . - else - . = "0" + . - i++ - - -/proc/text2numlist(text, delimiter="\n") - var/list/num_list = list() - for(var/x in splittext(text, delimiter)) - num_list += text2num(x) - return num_list +// This proc does not support converting numerically indexed alists to assoc lists. +/proc/alist2list(alist/input) + . = list() + for(var/k,v in input) + if(isnum(k)) + CRASH("Numeric index passed to alist2list()!") + .[k] = v // Splits the text of a file at seperator and returns them in a list. -/proc/file2list(filename, seperator="\n") - return splittext(return_file_text(filename),seperator) - -// Turns a direction into text -/proc/num2dir(direction) - switch (direction) - if (1.0) return NORTH - if (2.0) return SOUTH - if (4.0) return EAST - if (8.0) return WEST - else - to_world_log("UNKNOWN DIRECTION: [direction]") +/proc/file2list(filename, seperator = "\n") + return splittext(safe_file2text(filename), seperator) // Turns a direction into text /proc/dir2text(direction) @@ -98,14 +37,14 @@ // Turns text into proper directions /proc/text2dir(direction) switch (uppertext(direction)) - if ("NORTH") return 1 - if ("SOUTH") return 2 - if ("EAST") return 4 - if ("WEST") return 8 - if ("NORTHEAST") return 5 - if ("NORTHWEST") return 9 - if ("SOUTHEAST") return 6 - if ("SOUTHWEST") return 10 + if ("NORTH") return NORTH + if ("SOUTH") return SOUTH + if ("EAST") return EAST + if ("WEST") return WEST + if ("NORTHEAST") return NORTHEAST + if ("NORTHWEST") return NORTHWEST + if ("SOUTHEAST") return SOUTHEAST + if ("SOUTHWEST") return SOUTHWEST // Converts an angle (degrees) into an ss13 direction /proc/angle2dir(var/degree) @@ -143,6 +82,13 @@ if (BLEND_SUBTRACT) return ICON_SUBTRACT else return ICON_OVERLAY +/proc/iconMode2blendMode(icon_mode) + switch (icon_mode) + if (ICON_MULTIPLY) return BLEND_MULTIPLY + if (ICON_ADD) return BLEND_ADD + if (ICON_SUBTRACT) return BLEND_SUBTRACT + else return BLEND_OVERLAY + // Converts a rights bitfield into a string /proc/rights2text(rights,seperator="") if (rights & R_BUILDMODE) . += "[seperator]+BUILDMODE" @@ -154,7 +100,7 @@ if (rights & R_POSSESS) . += "[seperator]+POSSESS" if (rights & R_PERMISSIONS) . += "[seperator]+PERMISSIONS" if (rights & R_STEALTH) . += "[seperator]+STEALTH" - if (rights & R_REJUVINATE) . += "[seperator]+REJUVINATE" + if (rights & R_REJUVENATE) . += "[seperator]+REJUVENATE" if (rights & R_VAREDIT) . += "[seperator]+VAREDIT" if (rights & R_SOUNDS) . += "[seperator]+SOUND" if (rights & R_SPAWN) . += "[seperator]+SPAWN" @@ -238,35 +184,21 @@ for(var/atom_type in atom_types) var/atom/A = atom_type .[initial(A.name)] = atom_type - . = sortAssoc(.) + . = sortTim(., /proc/cmp_text_asc) /proc/atomtype2nameassoclist(var/atom_type) return atomtypes2nameassoclist(typesof(atom_type)) -//Splits the text of a file at seperator and returns them in a list. -/world/proc/file2list(filename, seperator="\n") - return splittext(file2text(filename), seperator) - -/proc/str2hex(str) - if(!istext(str)||!str) - return - var/r - var/c - for(var/i = 1 to length(str)) - c= text2ascii(str,i) - r+= num2hex(c) - return r - -// Decodes hex to raw byte string. -// If safe=TRUE, returns null on incorrect input strings instead of CRASHing -/proc/hex2str(str, safe=FALSE) - if(!istext(str)||!str) - return - var/r - var/c - for(var/i = 1 to length(str)/2) - c = hex2num(copytext(str,i*2-1,i*2+1), safe) - if(isnull(c)) - return null - r += ascii2text(c) - return r +//checks if a file exists and contains text +//returns text as a string if these conditions are met +/proc/safe_file2text(filename, error_on_invalid_return = TRUE) + try + if(fexists(filename)) + . = file2text(filename) + if(!. && error_on_invalid_return) + error("File empty ([filename])") + else if(error_on_invalid_return) + error("File not found ([filename])") + catch(var/exception/E) + if(error_on_invalid_return) + error("Exception when loading file as string: [EXCEPTION_TEXT(E)]") diff --git a/code/_helpers/types.dm b/code/_helpers/types.dm new file mode 100644 index 000000000000..a5346c9a6acc --- /dev/null +++ b/code/_helpers/types.dm @@ -0,0 +1,11 @@ +/proc/get_non_abstract_types(list/input_types) + . = list() + if(!input_types) + return + if(!islist(input_types)) + input_types = list(input_types) + for(var/input_type in input_types) + for(var/input_subtype in typesof(input_type)) + var/datum/input_atom = input_subtype + if(!TYPE_IS_ABSTRACT(input_atom)) + . |= input_subtype diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index ee05e48d1940..840e6121527f 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -7,9 +7,21 @@ //Checks if all high bits in req_mask are set in bitfield #define BIT_TEST_ALL(bitfield, req_mask) ((~(bitfield) & (req_mask)) == 0) -//Returns the middle-most value -/proc/dd_range(var/low, var/high, var/num) - return max(low,min(high,num)) +/proc/get_projectile_angle(atom/source, atom/target) + var/sx = source.x * world.icon_size + var/sy = source.y * world.icon_size + var/tx = target.x * world.icon_size + var/ty = target.y * world.icon_size + var/atom/movable/AM + if(ismovable(source)) + AM = source + sx += AM.step_x + sy += AM.step_y + if(ismovable(target)) + AM = target + tx += AM.step_x + ty += AM.step_y + return SIMPLIFY_DEGREES(arctan(ty - sy, tx - sx)) /proc/Get_Angle(atom/movable/start,atom/movable/end)//For beams. if(!start || !end) return 0 @@ -26,7 +38,7 @@ .+=360 //Returns location. Returns null if no location was found. -/proc/get_teleport_loc(turf/location,mob/target,distance = 1, density = 0, errorx = 0, errory = 0, eoffsetx = 0, eoffsety = 0) +/proc/get_teleport_loc(turf/location,mob/target,distance = 1, density = FALSE, errorx = 0, errory = 0, eoffsetx = 0, eoffsety = 0) /* Location where the teleport begins, target that will teleport, distance to go, density checking 0/1(yes/no). Random error in tile placement x, error in tile placement y, and block offset. @@ -101,7 +113,7 @@ Turf and target are seperate in case you want to teleport some distance from a t var/turf/center = locate((destination.x+xoffset),(destination.y+yoffset),location.z)//So now, find the new center. //Now to find a box from center location and make that our destination. - for(var/turf/T in block(locate(center.x+b1xerror,center.y+b1yerror,location.z), locate(center.x+b2xerror,center.y+b2yerror,location.z) )) + for(var/turf/T as anything in block(center.x+b1xerror, center.y+b1yerror, location.z, center.x+b2xerror, center.y+b2yerror, location.z)) if(density && T.contains_dense_objects()) continue//If density was specified. if(T.x>world.maxx || T.x<1) continue//Don't want them to teleport off the map. if(T.y>world.maxy || T.y<1) continue @@ -157,9 +169,6 @@ Turf and target are seperate in case you want to teleport some distance from a t return 1 return 0 -/proc/sign(x) - return x!=0?x/abs(x):0 - /proc/getline(atom/M,atom/N)//Ultra-Fast Bresenham Line-Drawing Algorithm var/px=M.x //starting x var/py=M.y @@ -168,10 +177,10 @@ Turf and target are seperate in case you want to teleport some distance from a t var/dy=N.y-py var/dxabs=abs(dx)//Absolute value of x distance var/dyabs=abs(dy) - var/sdx=sign(dx) //Sign of x distance (+ or -) - var/sdy=sign(dy) - var/x=dxabs>>1 //Counters for steps taken, setting to distance/2 - var/y=dyabs>>1 //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast. + var/sdx=SIGN(dx) //Sign of x distance (+ or -) + var/sdy=SIGN(dy) + var/x=BITSHIFT_RIGHT(dxabs,1) //Counters for steps taken, setting to distance/2 + var/y=BITSHIFT_RIGHT(dyabs,1) //Bit-shifting makes me l33t. It also makes getline() unnessecarrily fast. var/j //Generic integer for counting if(dxabs>=dyabs) //x distance is greater than y for(j=0;j= x) // only formulate 1/8 of circle + + . += LOCATE_COORDS_SAFE(center.x - x, center.y - y, center.z) //upper left left + . += LOCATE_COORDS_SAFE(center.x - y, center.y - x, center.z) //upper upper left + . += LOCATE_COORDS_SAFE(center.x + y, center.y - x, center.z) //upper upper right + . += LOCATE_COORDS_SAFE(center.x + x, center.y - y, center.z) //upper right right + . += LOCATE_COORDS_SAFE(center.x - x, center.y + y, center.z) //lower left left + . += LOCATE_COORDS_SAFE(center.x - y, center.y + x, center.z) //lower lower left + . += LOCATE_COORDS_SAFE(center.x + y, center.y + x, center.z) //lower lower right + . += LOCATE_COORDS_SAFE(center.x + x, center.y + y, center.z) //lower right right + + if(p < 0) + p += 4*x++ + 6; + else + p += 4*(x++ - y--) + 10; + +#undef LOCATE_COORDS_SAFE + //Returns whether or not a player is a guest using their ckey as an input /proc/IsGuestKey(key) if (findtext(key, "Guest-", 1, 7) != 1) //was findtextEx @@ -234,14 +270,9 @@ Turf and target are seperate in case you want to teleport some distance from a t return 0 return 1 -//Ensure the frequency is within bounds of what it should be sending/recieving at +//Ensure the frequency is within bounds of what it should be sending/receiving at /proc/sanitize_frequency(var/f, var/low = PUBLIC_LOW_FREQ, var/high = PUBLIC_HIGH_FREQ) - f = round(f) - f = max(low, f) - f = min(high, f) - if ((f % 2) == 0) //Ensure the last digit is an odd number - f += 1 - return f + return clamp(round(f), low, high) //Turns 1479 into 147.9 /proc/format_frequency(var/f) @@ -250,32 +281,29 @@ Turf and target are seperate in case you want to teleport some distance from a t //Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame() //Last modified by Carn /mob/proc/rename_self(var/role, var/allow_numbers=0) - spawn(0) - var/oldname = real_name - - var/time_passed = world.time - var/newname - - for(var/i=1,i<=3,i++) //we get 3 attempts to pick a suitable name. - newname = input(src,"You are \a [role]. Would you like to change your name to something else?", "Name change",oldname) as text - if((world.time-time_passed)>3000) - return //took too long - newname = sanitizeName(newname, ,allow_numbers) //returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters. - - for(var/mob/living/M in GLOB.player_list) - if(M == src) - continue - if(!newname || M.real_name == newname) - newname = null - break - if(newname) - break //That's a suitable name! - to_chat(src, "Sorry, that [role]-name wasn't appropriate, please try another. It's possibly too long/short, has bad characters or is already taken.") - - if(!newname) //we'll stick with the oldname then - return - - fully_replace_character_name(newname) + set waitfor = FALSE + + var/oldname = real_name + var/time_passed = world.time + var/newname + + for(var/i= 1 to 3) + newname = input(src,"You are \a [role]. Would you like to change your name to something else?", "Name change",oldname) as text + if((world.time-time_passed) > 5 MINUTES) + return //took too long + newname = sanitize_name(newname, ,allow_numbers) //returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters. + for(var/mob/living/M in global.player_list) + if(M == src) + continue + if(!newname || M.real_name == newname) + newname = null + break + if(newname) + break //That's a suitable name! + to_chat(src, "Sorry, that [role]-name wasn't appropriate, please try another. It's possibly too long/short, has bad characters or is already taken.") + if(!newname) //we'll stick with the oldname then + return + fully_replace_character_name(newname) //Picks a string of symbols to display as the law number for hacked or ion laws /proc/ionnum() @@ -287,8 +315,8 @@ Turf and target are seperate in case you want to teleport some distance from a t var/select = null var/list/borgs = list() - for (var/mob/living/silicon/robot/A in GLOB.player_list) - if (A.stat == 2 || A.connected_ai || A.scrambledcodes || istype(A,/mob/living/silicon/robot/drone) || !(get_z(A) in zs)) + for (var/mob/living/silicon/robot/A in global.player_list) + if (A.stat == DEAD || A.connected_ai || A.scrambledcodes || isdrone(A) || !(get_z(A) in zs)) continue var/name = "[A.real_name] ([A.modtype] [A.braintype])" borgs[name] = A @@ -302,7 +330,7 @@ Turf and target are seperate in case you want to teleport some distance from a t var/list/zs = get_valid_silicon_zs(z) . = list() - for(var/mob/living/silicon/ai/A in GLOB.living_mob_list_) + for(var/mob/living/silicon/ai/A in global.living_mob_list_) if(A.stat == DEAD || A.control_disabled || !(get_z(A) in zs)) continue . += A @@ -328,13 +356,13 @@ Turf and target are seperate in case you want to teleport some distance from a t /proc/get_valid_silicon_zs(z) if(z) - return GetConnectedZlevels(z) + return SSmapping.get_connected_levels(z) return list() //We return an empty list, because we are apparently in nullspace //Returns a list of all mobs with their name /proc/getmobs() - var/list/mobs = sortmobs() + var/list/mobs = get_sorted_mob_list() var/list/names = list() var/list/creatures = list() var/list/namecounts = list() @@ -360,40 +388,6 @@ Turf and target are seperate in case you want to teleport some distance from a t /proc/get_follow_targets() return follow_repository.get_follow_targets() -//Orders mobs by type then by name -/proc/sortmobs() - var/list/moblist = list() - var/list/sortmob = sortAtom(SSmobs.mob_list) - for(var/mob/observer/eye/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/ai/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/pai/M in sortmob) - moblist.Add(M) - for(var/mob/living/silicon/robot/M in sortmob) - moblist.Add(M) - for(var/mob/living/deity/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/human/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/brain/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/alien/M in sortmob) - moblist.Add(M) - for(var/mob/observer/ghost/M in sortmob) - moblist.Add(M) - for(var/mob/new_player/M in sortmob) - moblist.Add(M) - for(var/mob/living/carbon/slime/M in sortmob) - moblist.Add(M) - for(var/mob/living/simple_animal/M in sortmob) - moblist.Add(M) -// for(var/mob/living/silicon/hivebot/M in world) -// mob_list.Add(M) -// for(var/mob/living/silicon/hive_mainframe/M in world) -// mob_list.Add(M) - return moblist - // returns the turf located at the map edge in the specified direction relative to A // used for mass driver /proc/get_edge_target_turf(var/atom/A, var/direction) @@ -443,16 +437,6 @@ Turf and target are seperate in case you want to teleport some distance from a t var/y = min(world.maxy, max(1, A.y + dy)) return locate(x,y,A.z) -//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. Lower bound takes priority. -/proc/between(var/low, var/middle, var/high) - return max(min(middle, high), low) - -#if DM_VERSION < 513 -/proc/arctan(x) - var/y=arcsin(x/sqrt(1+x*x)) - return y -#endif - //Will return the contents of an atom recursivly to a depth of 'searchDepth' /atom/proc/GetAllContents(searchDepth = 5) var/list/toReturn = list() @@ -472,6 +456,10 @@ Turf and target are seperate in case you want to teleport some distance from a t cant_pass = 1 return cant_pass +/proc/get_step_resolving_mimic(var/atom/source, var/direction) + var/turf/turf = get_step(get_turf(source), direction) + return turf?.resolve_to_actual_turf() + /proc/get_step_towards2(var/atom/ref , var/atom/trg) var/base_dir = get_dir(ref, get_step_towards(ref,trg)) var/turf/temp = get_step_towards(ref,trg) @@ -500,8 +488,9 @@ Turf and target are seperate in case you want to teleport some distance from a t else return get_step(ref, base_dir) -/area/proc/move_contents_to(var/area/A) +/area/proc/move_contents_to(var/area/A, var/move_air) //Takes: Area. + // move_air - Boolean, whether or not air should be translated with the turfs. //Returns: Nothing. //Notes: Attempts to move the contents of one area to another area. // Movement based on lower left corner. @@ -519,9 +508,9 @@ Turf and target are seperate in case you want to teleport some distance from a t if(src_origin && trg_origin) var/translation = get_turf_translation(src_origin, trg_origin, turfs_src) - translate_turfs(translation, null) + translate_turfs(translation, null, translate_air = move_air) -proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) +/proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) if(!original) return null @@ -544,7 +533,6 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) /datum/coords //Simple datum for storing coordinates. var/x_pos = null var/y_pos = null - var/z_pos = null /area/proc/copy_contents_to(var/area/A , var/platingRequired = 0 ) //Takes: Area. Optional: If it should copy to areas that don't have plating @@ -605,6 +593,7 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) var/old_icon1 = T.icon var/old_overlays = T.overlays.Copy() var/old_underlays = T.underlays.Copy() + var/old_decals = T.decals?.Copy() if(platingRequired) if(istype(B, get_base_turf_by_area(B))) @@ -615,8 +604,10 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) X.set_dir(old_dir1) X.icon_state = old_icon_state1 X.icon = old_icon1 //Shuttle floors are in shuttle.dmi while the defaults are floors.dmi + X.decals = old_decals X.overlays = old_overlays X.underlays = old_underlays + X.update_icon() // necessary to update decals properly var/list/objs = new/list() var/list/newobjs = new/list() @@ -640,7 +631,7 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) for(var/mob/M in T) - if(!istype(M,/mob) || !M.simulated) continue // If we need to check for more mobs, I'll add a variable + if(!ismob(M) || !M.simulated) continue // If we need to check for more mobs, I'll add a variable mobs += M for(var/mob/M in mobs) @@ -652,23 +643,14 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) copiedobjs += newobjs copiedobjs += newmobs -// var/area/AR = X.loc - -// if(AR.dynamic_lighting) -// X.opacity = !X.opacity -// X.sd_SetOpacity(!X.opacity) //TODO: rewrite this code so it's not messed by lighting ~Carn - toupdate += X refined_src -= T refined_trg -= B continue moving - - - if(toupdate.len) - for(var/turf/simulated/T1 in toupdate) + for(var/turf/T1 in toupdate) SSair.mark_for_update(T1) return copiedobjs @@ -685,66 +667,37 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) mobs += M return mobs - /proc/parse_zone(zone) - if(zone == BP_R_HAND) return "right hand" - else if (zone == BP_L_HAND) return "left hand" - else if (zone == BP_L_ARM) return "left arm" - else if (zone == BP_R_ARM) return "right arm" - else if (zone == BP_L_LEG) return "left leg" - else if (zone == BP_R_LEG) return "right leg" - else if (zone == BP_L_FOOT) return "left foot" - else if (zone == BP_R_FOOT) return "right foot" - else if (zone == BP_L_HAND) return "left hand" - else if (zone == BP_R_HAND) return "right hand" - else if (zone == BP_L_FOOT) return "left foot" - else if (zone == BP_R_FOOT) return "right foot" - else return zone - -/proc/get(atom/loc, type) - while(loc) - if(istype(loc, type)) - return loc - loc = loc.loc - return null - -/proc/get_turf_or_move(turf/location) - return get_turf(location) - - -//Quick type checks for some tools -var/global/list/common_tools = list( -/obj/item/stack/cable_coil, -/obj/item/wrench, -/obj/item/weldingtool, -/obj/item/screwdriver, -/obj/item/wirecutters, -/obj/item/multitool, -/obj/item/crowbar) - -/proc/istool(O) - if(O && is_type_in_list(O, common_tools)) - return 1 - return 0 + var/static/list/zone_to_descriptor_mapping = list( + BP_R_HAND = "right hand", + BP_L_HAND = "left hand", + BP_L_ARM = "left arm", + BP_R_ARM = "right arm", + BP_L_LEG = "left leg", + BP_R_LEG = "right leg", + BP_L_FOOT = "left foot", + BP_R_FOOT = "right foot", + BP_L_HAND = "left hand", + BP_R_HAND = "right hand", + BP_L_FOOT = "left foot", + BP_R_FOOT = "right foot", + BP_MOUTH = "mouth", + BP_EYES = "eyes" + ) + return zone_to_descriptor_mapping[zone] || zone //Whether or not the given item counts as sharp in terms of dealing damage -/proc/is_sharp(obj/O) - if (!O) return 0 - if (O.sharp) return 1 - if (O.edge) return 1 - return 0 +/obj/proc/is_sharp() + return FALSE //Whether or not the given item counts as cutting with an edge in terms of removing limbs -/proc/has_edge(obj/O) - if (!O) return 0 - if (O.edge) return 1 - return 0 - +/obj/proc/has_edge() + return FALSE //For items that can puncture e.g. thick plastic but aren't necessarily sharp //Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape. /obj/item/proc/can_puncture() - return src.sharp + return is_sharp() /obj/item/screwdriver/can_puncture() return 1 @@ -755,28 +708,19 @@ var/global/list/common_tools = list( /obj/item/weldingtool/can_puncture() return 1 -/obj/item/screwdriver/can_puncture() - return 1 - -/obj/item/shovel/can_puncture() //includes spades - return 1 - -/obj/item/flame/can_puncture() - return src.lit - /obj/item/clothing/mask/smokable/cigarette/can_puncture() - return src.lit + return ..() || lit // in case someone has a sharp cigarette for some reason /* Checks if that loc and dir has a item on the wall */ -var/list/WALLITEMS = list( - /obj/machinery/power/apc, /obj/machinery/alarm, /obj/item/radio/intercom, +var/global/list/WALLITEMS = list( + /obj/machinery/apc, /obj/machinery/alarm, /obj/item/radio/intercom, /obj/structure/extinguisher_cabinet, /obj/structure/reagent_dispensers/peppertank, - /obj/machinery/status_display, /obj/machinery/requests_console, /obj/machinery/light_switch, /obj/structure/sign, + /obj/machinery/status_display, /obj/machinery/network/requests_console, /obj/machinery/light_switch, /obj/structure/sign, /obj/machinery/newscaster, /obj/machinery/firealarm, /obj/structure/noticeboard, - /obj/item/storage/secure/safe, /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth, - /obj/item/storage/mirror, /obj/structure/fireaxecabinet, /obj/structure/filingcabinet/wallcabinet + /obj/item/secure_storage/safe, /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth, + /obj/structure/mirror, /obj/structure/fireaxecabinet, /obj/structure/filing_cabinet/wall ) /proc/gotwallitem(loc, dir) for(var/obj/O in loc) @@ -811,27 +755,29 @@ var/list/WALLITEMS = list( return 0 /proc/get_random_colour(var/simple = FALSE, var/lower = 0, var/upper = 255) - var/colour if(simple) - colour = pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF")) - else - for(var/i=1;i<=3;i++) - var/temp_col = "[num2hex(rand(lower,upper))]" - if(length(temp_col )<2) - temp_col = "0[temp_col]" - colour += temp_col - return "#[colour]" + return pick(list("#ff0000","#ff7f00","#ffff00","#00ff00","#0000ff","#4b0082","#8f00ff")) + return rgb(rand(lower, upper), rand(lower, upper), rand(lower, upper)) // call to generate a stack trace and print to runtime logs -/proc/crash_at(msg, file, line) +/proc/get_stack_trace(msg, file, line) CRASH("%% [file],[line] %% [msg]") -/proc/get_mutable_overlay(icon, icon_state, color, flags = RESET_COLOR | RESET_ALPHA, plane = FLOAT_PLANE) - var/mutable_appearance/res = new() - res.icon = icon - res.icon_state = icon_state - res.color = color - res.appearance_flags = flags - res.plane = plane - res.layer = FLOAT_LAYER - return res \ No newline at end of file +/**Returns a number string with its ordinal suffix th, st, nd, rd */ +/proc/get_ordinal_string(var/num) + . = num + num %= 100 + if(num < 10 || num > 20) //11, 12, 13 are exceptions in english, and just get 'th' like everything else + switch(num % 10) + if(1) + return "[.]st" + if(2) + return "[.]nd" + if(3) + return "[.]rd" + return "[.]th" + +///A do nothing proc used to prevent empty block warnings +///In hot code (like atmos checks), use EMPTY_BLOCK_GUARD instead. +/proc/pass(...) + return \ No newline at end of file diff --git a/code/_helpers/vector.dm b/code/_helpers/vector.dm deleted file mode 100644 index 797dbe3757c9..000000000000 --- a/code/_helpers/vector.dm +++ /dev/null @@ -1,135 +0,0 @@ -/* -plot_vector is a helper datum for plotting a path in a straight line towards a target turf. -This datum converts from world space (turf.x and turf.y) to pixel space, which the datum keeps track of itself. This -should work with any size turfs (i.e. 32x32, 64x64) as it references world.icon_size (note: not actually tested with -anything other than 32x32 turfs). - -setup() - This should be called after creating a new instance of a plot_vector datum. - This does the initial setup and calculations. Since we are travelling in a straight line we only need to calculate - the vector and x/y steps once. x/y steps are capped to 1 full turf, whichever is further. If we are travelling along - the y axis each step will be +/- 1 y, and the x movement reduced based on the angle (tangent calculation). After - this every subsequent step will be incremented based on these calculations. - Inputs: - source - the turf the object is starting from - target - the target turf the object is travelling towards - xo - starting pixel_x offset, typically won't be needed, but included in case someone has a need for it later - yo - same as xo, but for the y_pixel offset - -increment() - Adds the offset to the current location - incrementing it by one step along the vector. - -return_angle() - Returns the direction (angle in degrees) the object is travelling in. - * North = 90 - * East = 0 - * South = -90 - * West = 180 - -return_hypotenuse() - Returns the distance of travel for each step of the vector, relative to each full step of movement. 1 is a full turf - length. Currently used as a multiplier for scaling effects that should be contiguous, like laser beams. - -return_location() - Returns a vector_loc datum containing the current location data of the object (see /datum/vector_loc). This includes - the turf it currently should be at, as well as the pixel offset from the centre of that turf. Typically increment() - would be called before this if you are going to move an object based on it's vector data. -*/ - -/datum/plot_vector - var/turf/source - var/turf/target - var/angle = 0 // direction of travel in degrees - var/loc_x = 0 // in pixels from the left edge of the map - var/loc_y = 0 // in pixels from the bottom edge of the map - var/loc_z = 0 // loc z is in world space coordinates (i.e. z level) - we don't care about measuring pixels for this - var/offset_x = 0 // distance to increment each step - var/offset_y = 0 - -/datum/plot_vector/proc/setup(var/turf/S, var/turf/T, var/xo = 0, var/yo = 0, var/angle_offset=0) - source = S - target = T - - if(!istype(source)) - source = get_turf(source) - if(!istype(target)) - target = get_turf(target) - - if(!istype(source) || !istype(target)) - return - - // convert coordinates to pixel space (default is 32px/turf, 8160px across for a size 255 map) - loc_x = source.x * world.icon_size + xo - loc_y = source.y * world.icon_size + yo - loc_z = source.z - - // calculate initial x and y difference - var/dx = target.x - source.x - var/dy = target.y - source.y - - // if we aren't moving anywhere; quit now - if(dx == 0 && dy == 0) - return - - // calculate the angle - angle = Atan2(dx, dy) + angle_offset - - // and some rounding to stop the increments jumping whole turfs - because byond favours certain angles - if(angle > -135 && angle < 45) - angle = Ceiling(angle) - else - angle = Floor(angle) - - // calculate the offset per increment step - if(abs(angle) in list(0, 45, 90, 135, 180)) // check if the angle is a cardinal - if(abs(angle) in list(0, 45, 135, 180)) // if so we can skip the trigonometry and set these to absolutes as - offset_x = sign(dx) // they will always be a full step in one or more directions - if(abs(angle) in list(45, 90, 135)) - offset_y = sign(dy) - else if(abs(dy) > abs(dx)) - offset_x = Cot(abs(angle)) // otherwise set the offsets - offset_y = sign(dy) - else - offset_x = sign(dx) - offset_y = Tan(angle) - if(dx < 0) - offset_y = -offset_y - - // multiply the offset by the turf pixel size - offset_x *= world.icon_size - offset_y *= world.icon_size - -/datum/plot_vector/proc/increment() - loc_x += offset_x - loc_y += offset_y - -/datum/plot_vector/proc/return_angle() - return angle - -/datum/plot_vector/proc/return_hypotenuse() - return sqrt(((offset_x / 32) ** 2) + ((offset_y / 32) ** 2)) - -/datum/plot_vector/proc/return_location(var/datum/vector_loc/data) - if(!data) - data = new() - data.loc = locate(round(loc_x / world.icon_size, 1), round(loc_y / world.icon_size, 1), loc_z) - if(!data.loc) - return - data.pixel_x = loc_x - (data.loc.x * world.icon_size) - data.pixel_y = loc_y - (data.loc.y * world.icon_size) - return data - -/* -vector_loc is a helper datum for returning precise location data from plot_vector. It includes the turf the object is in -as well as the pixel offsets. - -return_turf() - Returns the turf the object should be currently located in. -*/ -/datum/vector_loc - var/turf/loc - var/pixel_x - var/pixel_y - -/datum/vector_loc/proc/return_turf() - return loc diff --git a/code/_helpers/view.dm b/code/_helpers/view.dm index 13ee837caa77..1855aa758c20 100644 --- a/code/_helpers/view.dm +++ b/code/_helpers/view.dm @@ -1,12 +1,7 @@ /proc/getviewsize(view) - var/viewX - var/viewY if(isnum(view)) - var/totalviewrange = 1 + 2 * view - viewX = totalviewrange - viewY = totalviewrange + var/totalviewrange = (view < 0 ? -1 : 1) + 2 * view + return list(totalviewrange, totalviewrange) else var/list/viewrangelist = splittext(view,"x") - viewX = text2num(viewrangelist[1]) - viewY = text2num(viewrangelist[2]) - return list(viewX, viewY) + return list(text2num(viewrangelist[1]), text2num(viewrangelist[2])) diff --git a/code/_helpers/visual_filters.dm b/code/_helpers/visual_filters.dm new file mode 100644 index 000000000000..af92931d2a34 --- /dev/null +++ b/code/_helpers/visual_filters.dm @@ -0,0 +1,81 @@ +// These involve BYOND's built-in filters that do visual effects, and not stuff that distinguishes between things. + +// All of this ported from TG. +// And then ported to Nebula from Polaris. +/atom/movable + VAR_PRIVATE/list/filter_data // For handling persistent filters + +// Defining this for future proofing and ease of searching for erroneous usage. +/image/proc/add_filter(filter_name, priority, list/params) + filters += filter(arglist(params)) + return TRUE + +/atom/movable/proc/has_filter(filter_name) + return (name in filter_data) + +/atom/movable/proc/add_filter(filter_name, priority, list/params, force_update = FALSE) + + // Check if we already have a filter and hence don't need to rebuild filters. + if((filter_name in filter_data) && !force_update) + var/existing_params = filter_data[name] + if(length(params) == length(existing_params)) + var/found_difference = FALSE + for(var/param in (existing_params|params)) + if(params[param] != existing_params[param]) + found_difference = TRUE + break + if(!found_difference) + return FALSE + + var/list/p = params.Copy() + p["priority"] = priority + LAZYSET(filter_data, filter_name, p) + update_filters() + return TRUE + +/atom/movable/proc/update_filters() + filters = null + filter_data = sortTim(filter_data, /proc/cmp_priority_list, TRUE) + for(var/f in filter_data) + var/list/data = filter_data[f] + var/list/arguments = data.Copy() + arguments -= "priority" + filters += filter(arglist(arguments)) + UPDATE_OO_IF_PRESENT + +/atom/movable/proc/get_filter(filter_name) + var/filter_index = filter_data?.Find(filter_name) + if(filter_index > 0 && filter_index <= length(filters)) + return filters[filter_index] + +// Polaris Extensions +/atom/movable/proc/remove_filter(filter_name) + var/thing = get_filter(filter_name) + if(thing) + LAZYREMOVE(filter_data, filter_name) + filters -= thing + update_filters() + return TRUE + return FALSE + +/// Animate a given filter on this atom. All params after the first are passed to animate(). +/atom/movable/proc/animate_filter(filter_name, list/params) + if (!filter_data || !filter_data[filter_name]) + return + + var/index = filter_data.Find(filter_name) + if(index <= 0) + return + + // First, animate ourselves. + var/list/monkeypatched_params = params.Copy() + monkeypatched_params.Insert(1, filters[index]) + animate(arglist(monkeypatched_params)) + + // If we're being copied by Z-Mimic, update mimics too. + if (bound_overlay) + for (var/atom/movable/AM as anything in get_above_oo()) + if(index > length(AM.filters)) + continue // presumably there is a z-mimic flush pending - TODO check if this would fuck with the wrong filter on the shadower + monkeypatched_params[1] = AM.filters[index] + animate(arglist(monkeypatched_params)) diff --git a/code/_helpers/washing.dm b/code/_helpers/washing.dm index dfdd2c695350..0bb0169a3d1a 100644 --- a/code/_helpers/washing.dm +++ b/code/_helpers/washing.dm @@ -1,89 +1,9 @@ /proc/wash_mob(var/mob/living/washing) - if(!istype(washing)) return - var/mob/living/L = washing - - if(L.on_fire) + if(L.is_on_fire()) L.visible_message("A cloud of steam rises up as the water hits \the [L]!") - L.ExtinguishMob() - - L.fire_stacks = -20 //Douse ourselves with water to avoid fire more easily - - if(!iscarbon(washing)) - washing.clean_blood() - return - - var/mob/living/carbon/M = washing - if(M.r_hand) - M.r_hand.clean_blood() - if(M.l_hand) - M.l_hand.clean_blood() - if(M.back && M.back.clean_blood()) - M.update_inv_back(0) - - //flush away reagents on the skin - if(M.touching) - var/remove_amount = M.touching.maximum_volume * M.reagent_permeability() //take off your suit first - M.touching.remove_any(remove_amount) - - if(!ishuman(M)) - if(M.wear_mask && M.wear_mask.clean_blood()) - M.update_inv_wear_mask(0) - M.clean_blood() - return - - var/mob/living/carbon/human/H = M - var/washgloves = 1 - var/washshoes = 1 - var/washmask = 1 - var/washears = 1 - var/washglasses = 1 - - if(H.wear_suit) - washgloves = !(H.wear_suit.flags_inv & HIDEGLOVES) - washshoes = !(H.wear_suit.flags_inv & HIDESHOES) - - if(H.head) - washmask = !(H.head.flags_inv & HIDEMASK) - washglasses = !(H.head.flags_inv & HIDEEYES) - washears = !(H.head.flags_inv & HIDEEARS) - - if(H.wear_mask) - if (washears) - washears = !(H.wear_mask.flags_inv & HIDEEARS) - if (washglasses) - washglasses = !(H.wear_mask.flags_inv & HIDEEYES) - - if(H.head) - if(H.head.clean_blood()) - H.update_inv_head(0) - if(H.wear_suit) - if(H.wear_suit.clean_blood()) - H.update_inv_wear_suit(0) - else if(H.w_uniform) - if(H.w_uniform.clean_blood()) - H.update_inv_w_uniform(0) - if(H.gloves && washgloves) - if(H.gloves.clean_blood()) - H.update_inv_gloves(0) - if(H.shoes && washshoes) - if(H.shoes.clean_blood()) - H.update_inv_shoes(0) - if(H.wear_mask && washmask) - if(H.wear_mask.clean_blood()) - H.update_inv_wear_mask(0) - if(H.glasses && washglasses) - if(H.glasses.clean_blood()) - H.update_inv_glasses(0) - if(H.l_ear && washears) - if(H.l_ear.clean_blood()) - H.update_inv_ears(0) - if(H.r_ear && washears) - if(H.r_ear.clean_blood()) - H.update_inv_ears(0) - if(H.belt) - if(H.belt.clean_blood()) - H.update_inv_belt(0) - H.clean_blood(washshoes) \ No newline at end of file + L.extinguish_fire() + L.adjust_fire_intensity(-20) //Douse ourselves with water to avoid fire more easily + washing.clean() diff --git a/code/_macros.dm b/code/_macros.dm index 8327e2bf15b1..62f7629af378 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -1,20 +1,13 @@ #define any2ref(x) "\ref[x]" -#if DM_VERSION < 513 - -#define islist(A) istype(A, /list) - -#define ismovable(A) istype(A, /atom/movable) - -#endif - #define PUBLIC_GAME_MODE SSticker.master_mode -#define Clamp(value, low, high) (value <= low ? low : (value >= high ? high : value)) -#define CLAMP01(x) (Clamp(x, 0, 1)) +#define CLAMP01(x) (clamp(x, 0, 1)) #define get_turf(A) get_step(A,0) +#define get_area(A) (get_step(A, 0)?.loc) + #define get_x(A) (get_step(A, 0)?.x || 0) #define get_y(A) (get_step(A, 0)?.y || 0) @@ -23,40 +16,38 @@ #define isAI(A) istype(A, /mob/living/silicon/ai) -#define isalien(A) istype(A, /mob/living/carbon/alien) - #define isanimal(A) istype(A, /mob/living/simple_animal) #define isairlock(A) istype(A, /obj/machinery/door/airlock) #define isatom(A) isloc(A) -#define isbrain(A) istype(A, /mob/living/carbon/brain) - -#define iscarbon(A) istype(A, /mob/living/carbon) - -#define iscolorablegloves(A) (istype(A, /obj/item/clothing/gloves/color)||istype(A, /obj/item/clothing/gloves/insulated)||istype(A, /obj/item/clothing/gloves/thick)) +#define isbrain(A) istype(A, /mob/living/brain) #define isclient(A) istype(A, /client) #define iscorgi(A) istype(A, /mob/living/simple_animal/corgi) -#define is_drone(A) istype(A, /mob/living/silicon/robot/drone) +#define isdrone(A) istype(A, /mob/living/silicon/robot/drone) #define isEye(A) istype(A, /mob/observer/eye) -#define ishuman(A) istype(A, /mob/living/carbon/human) +#define ishuman(A) istype(A, /mob/living/human) #define isitem(A) istype(A, /obj/item) #define isliving(A) istype(A, /mob/living) -#define ismouse(A) istype(A, /mob/living/simple_animal/mouse) +#define ismouse(A) istype(A, /mob/living/simple_animal/passive/mouse) + +#define islizard(A) istype(A, /mob/living/simple_animal/lizard) #define isnewplayer(A) istype(A, /mob/new_player) #define isobj(A) istype(A, /obj) +#define iseffect(A) istype(A, /obj/effect) + #define isghost(A) istype(A, /mob/observer/ghost) #define isobserver(A) istype(A, /mob/observer) @@ -65,7 +56,9 @@ #define isstack(A) istype(A, /obj/item/stack) -#define isspace(A) istype(A, /area/space) +#define isspacearea(A) istype(A, /area/space) + +#define isspaceturf(A) istype(A, /turf/space) #define ispAI(A) istype(A, /mob/living/silicon/pai) @@ -73,7 +66,9 @@ #define issilicon(A) istype(A, /mob/living/silicon) -#define isslime(A) istype(A, /mob/living/carbon/slime) +#define isbot(A) istype(A, /mob/living/bot) + +#define isexosuit(A) istype(A, /mob/living/exosuit) #define isunderwear(A) istype(A, /obj/item/underwear) @@ -83,37 +78,48 @@ #define attack_animation(A) if(istype(A)) A.do_attack_animation(src) -#define isopenspace(A) istype(A, /turf/simulated/open) +#define isplunger(A) istype(A, /obj/item/plunger) + +#define isassembly(A) istype(A, /obj/item/assembly) -#define isPlunger(A) istype(A, /obj/item/clothing/mask/plunger) || istype(A, /obj/item/plunger/robot) +#define isigniter(A) istype(A, /obj/item/assembly/igniter) -/proc/isspecies(A, B) - if(!iscarbon(A)) - return FALSE - var/mob/living/carbon/C = A - return C.species?.name == B +#define istimer(A) istype(A, /obj/item/assembly/timer) #define sequential_id(key) uniqueness_repository.Generate(/datum/uniqueness_generator/id_sequential, key) #define random_id(key,min_id,max_id) uniqueness_repository.Generate(/datum/uniqueness_generator/id_random, key, min_id, max_id) +/proc/place_meta_charset(content) + if(istext(content)) + content = "" + content + return content + #define to_chat(target, message) target << (message) #define to_world(message) world << (message) #define to_world_log(message) world.log << (message) #define sound_to(target, sound) target << (sound) #define to_file(file_entry, source_var) file_entry << (source_var) #define from_file(file_entry, target_var) file_entry >> (target_var) -#define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name) +#define show_browser(target, browser_content, browser_name) target << browse(place_meta_charset(browser_content), browser_name) #define close_browser(target, browser_name) target << browse(null, browser_name) #define show_image(target, image) target << (image) #define send_rsc(target, rsc_content, rsc_name) target << browse_rsc(rsc_content, rsc_name) -#define open_link(target, url) target << link(url) +#define open_link(target, url) target << link(url) +#define ftp_to(target, file_entry, suggested_name) target << ftp(file_entry, suggested_name) +#define open_file_for(target, file) target << run(file) +#define to_savefile(target, key, value) target[(key)] << (value) +#define from_savefile(target, key, value) target[(key)] >> (value) +#define to_output(target, output_content, output_args) target << output((output_content), (output_args)) +// Avoid using this where possible, prefer the other helpers instead. +#define direct_output(target, value) target << (value) -#define MAP_IMAGE_PATH "nano/images/[GLOB.using_map.path]/" +/proc/html_icon(var/thing) // Proc instead of macro to avoid precompiler problems. + . = "\icon[thing]" -#define map_image_file_name(z_level) "[GLOB.using_map.path]-[z_level].png" +#define MAP_IMAGE_PATH "nano/images/[global.using_map.path]/" -#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") +#define map_image_file_name(z_level) "[global.using_map.path]-[z_level].png" #define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE) @@ -123,17 +129,11 @@ #define CanPhysicallyInteractWith(user, target) (target.CanUseTopicPhysical(user) == STATUS_INTERACTIVE) -#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_NULL(x) if(x) { qdel(x) ; x = null } - -#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE) - #define DROP_NULL(x) if(x) { x.dropInto(loc); x = null; } #define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") } -// Insert an object A into a sorted list using cmp_proc (/code/_helpers/cmp.dm) for comparison. +/// Insert an object A into a sorted list using cmp_proc (/code/_helpers/cmp.dm) for comparison. #define ADD_SORTED(list, A, cmp_proc) if(!list.len) {list.Add(A)} else {list.Insert(FindElementIndex(A, list, cmp_proc), A)} //Currently used in SDQL2 stuff @@ -147,25 +147,45 @@ #define JOINTEXT(X) jointext(X, null) -#define SPAN_ITALIC(X) "[X]" - -#define SPAN_BOLD(X) "[X]" - -#define SPAN_NOTICE(X) "[X]" - -#define SPAN_WARNING(X) "[X]" - -#define SPAN_STYLE(style, X) "[X]" - -#define SPAN_DANGER(X) "[X]" - -#define SPAN_OCCULT(X) "[X]" - -#define SPAN_MFAUNA(X) "[X]" - -#define SPAN_SUBTLE(X) "[X]" - -#define SPAN_INFO(X) "[X]" +#define SPAN_STYLE(S, X) "" + X + "" +#define SPAN_CLASS(C, X) "" + X + "" + +#define SPAN_ITALIC(X) SPAN_CLASS("italic", X) +#define SPAN_BOLD(X) SPAN_CLASS("bold", X) +#define SPAN_NOTICE(X) SPAN_CLASS("notice", X) +#define SPAN_WARNING(X) SPAN_CLASS("warning", X) +#define SPAN_DANGER(X) SPAN_CLASS("danger", X) +#define SPAN_ROSE(X) SPAN_CLASS("rose", X) +#define SPAN_OCCULT(X) SPAN_CLASS("cult", X) +#define SPAN_CULT_ANNOUNCE(X) SPAN_CLASS("cultannounce", X) +#define SPAN_MFAUNA(X) SPAN_CLASS("mfauna", X) +#define SPAN_SUBTLE(X) SPAN_CLASS("subtle", X) +#define SPAN_INFO(X) SPAN_CLASS("info", X) +#define SPAN_RED(X) SPAN_CLASS("font_red", X) +#define SPAN_ORANGE(X) SPAN_CLASS("font_orange", X) +#define SPAN_YELLOW(X) SPAN_CLASS("font_yellow", X) +#define SPAN_GREEN(X) SPAN_CLASS("font_green", X) +#define SPAN_BLUE(X) SPAN_CLASS("font_blue", X) +#define SPAN_VIOLET(X) SPAN_CLASS("font_violet", X) +#define SPAN_PURPLE(X) SPAN_CLASS("font_purple", X) +#define SPAN_GREY(X) SPAN_CLASS("font_grey", X) +#define SPAN_MAROON(X) SPAN_CLASS("font_maroon", X) +#define SPAN_PINK(X) SPAN_CLASS("font_pink", X) +#define SPAN_PALEPINK(X) SPAN_CLASS("font_palepink", X) +#define SPAN_SINISTER(X) SPAN_CLASS("sinister", X) +#define SPAN_MODERATE(X) SPAN_CLASS("moderate", X) +#define SPAN_DEADSAY(X) SPAN_CLASS("deadsay", X) +// placeholders +#define SPAN_GOOD(X) SPAN_GREEN(X) +#define SPAN_NEUTRAL(X) SPAN_BLUE(X) +#define SPAN_BAD(X) SPAN_RED(X) +#define SPAN_HARDSUIT(X) SPAN_BLUE(X) + +#define CSS_CLASS_RADIO "radio" + +#define STYLE_SMALLFONTS(X, S, C1) "[X]" + +#define STYLE_SMALLFONTS_OUTLINE(X, S, C1, C2) "[X]" #define FONT_COLORED(color, text) "[text]" @@ -179,4 +199,8 @@ #define FONT_GIANT(X) "[X]" -#define crash_with(X) crash_at(X, __FILE__, __LINE__) \ No newline at end of file +#define PRINT_STACK_TRACE(X) get_stack_trace(X, __FILE__, __LINE__) + +/// Checks if potential_weakref is a weakref of thing. +/// NOTE: These argments are the opposite order of TG's, because I think TG's are counterintuitive. +#define IS_WEAKREF_OF(potential_weakref, thing) (istype(thing, /datum) && !isnull(potential_weakref) && thing.weakref == potential_weakref) \ No newline at end of file diff --git a/code/_onclick/MouseDrag.dm b/code/_onclick/MouseDrag.dm index b53eb377a35b..6f7e0ee7c3ea 100644 --- a/code/_onclick/MouseDrag.dm +++ b/code/_onclick/MouseDrag.dm @@ -1,16 +1,39 @@ //If we intercept it return true else return false -/atom/proc/RelayMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params, var/mob/user) +/atom/proc/RelayMouseDrag(atom/src_object, atom/over_object, src_location, over_location, src_control, over_control, params, mob/user) return FALSE -/mob/proc/OnMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params) - if(istype(loc, /atom)) +/atom/proc/RelayMouseDown(atom/object, location, control, params, mob/user) + return FALSE + +/atom/proc/RelayMouseUp(atom/object, location, control, params, mob/user) + return FALSE + +/mob/proc/OnMouseDrag(atom/src_object, atom/over_object, src_location, over_location, src_control, over_control, params) + if(loc) var/atom/A = loc if(A.RelayMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params, src)) return - if(over_object) - if(!incapacitated()) - var/obj/item/gun/gun = get_active_hand() - if(istype(gun) && gun.can_autofire()) - set_dir(get_dir(src, over_object)) - gun.Fire(get_turf(over_object), src, params, (get_dist(over_object, src) <= 1), FALSE) \ No newline at end of file + var/obj/item/gun/gun = get_active_held_item() + if(check_intent(I_FLAG_HARM) && istype(over_object) && (isturf(over_object) || isturf(over_object.loc)) && !incapacitated() && istype(gun)) + gun.set_autofire(over_object, src) + +/mob/proc/OnMouseDown(atom/object, location, control, params) + if(loc) + var/atom/A = loc + if(A.RelayMouseDown(object, location, control, params, src)) + return + + var/obj/item/gun/gun = get_active_held_item() + if(check_intent(I_FLAG_HARM) && istype(object) && (isturf(object) || isturf(object.loc)) && !incapacitated() && istype(gun)) + gun.set_autofire(object, src) + +/mob/proc/OnMouseUp(atom/object, location, control, params) + if(loc) + var/atom/A = loc + if(A.RelayMouseUp(object, location, control, params, src)) + return + + var/obj/item/gun/gun = get_active_held_item() + if(istype(gun)) + gun.clear_autofire() diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index 1d3d4116d2ed..8aea97cf30db 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -26,12 +26,13 @@ * Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays. */ /turf/Adjacent(var/atom/neighbor, var/atom/target = null) - var/list/turf/Ts = get_turf(neighbor) - + var/list/turf/Ts = list() if(istype(neighbor, /atom/movable)) // incase our neighbor atom is a multitile atom var/atom/movable/N = neighbor - Ts = N.locs - Ts |= get_turf(N.loc) + for(var/atom/A in N.locs) + Ts |= get_turf(A) + else + Ts += get_turf(neighbor) for(var/turf/T0 in Ts) if(T0 == src) @@ -95,13 +96,41 @@ Quick adjacency (to turf): if(T.Adjacent(neighbor,src)) return 1 return 0 -// This is necessary for storage items not on your person. +// These overrides are necessary for storage items not on your person. +// TODO: see if this can just go on an /obj override (may impact /machinery?) /obj/item/Adjacent(var/atom/neighbor, var/recurse = 1) - if(neighbor == loc) return 1 - if(istype(loc,/obj/item)) + if(neighbor == loc) + return TRUE + if(istype(loc, /obj/item) || istype(loc, /obj/structure)) if(recurse > 0) - return loc.Adjacent(neighbor,recurse - 1) - return 0 + return loc.Adjacent(neighbor, recurse - 1) + return FALSE + return ..() + +/obj/structure/Adjacent(var/atom/neighbor, var/recurse = 1) + if(neighbor == loc) + return TRUE + if(istype(loc, /obj/item) || istype(loc, /obj/structure)) + if(recurse > 0) + return loc.Adjacent(neighbor, recurse - 1) + return FALSE + return ..() + +/* + Special case: This allows you to reach a door when it is visally on top of, + but technically behind, a fire door + + You could try to rewrite this to be faster, but I'm not sure anything would be. + This can be safely removed if border firedoors are ever moved to be on top of doors + so they can be interacted with without opening the door. +*/ +/obj/machinery/door/Adjacent(atom/neighbor) + var/obj/machinery/door/firedoor/border/BD = locate() in loc + if(BD) + BD.throwpass = 1 // allow click to pass + . = ..() + BD.throwpass = 0 + return . return ..() /* @@ -109,16 +138,17 @@ Quick adjacency (to turf): This is defined as any dense ATOM_FLAG_CHECKS_BORDER object, or any dense object without throwpass. The border_only flag allows you to not objects (for source and destination squares) */ -/turf/proc/ClickCross(var/target_dir, var/border_only, var/target_atom = null) +/turf/proc/ClickCross(target_dir, border_only, atom/target_atom = null) for(var/obj/O in src) if( !O.density || O == target_atom || O.throwpass) continue // throwpass is used for anything you can click through if(O.atom_flags & ATOM_FLAG_CHECKS_BORDER) // windows have throwpass but are on border, check them first if( O.dir & target_dir || O.dir&(O.dir-1) ) // full tile windows are just diagonals mechanically - var/obj/structure/window/W = target_atom - if(istype(W)) - if(!W.is_fulltile()) //exception for breaking full tile windows on top of single pane windows - return 0 + var/obj/structure/window/window = target_atom + if(istype(window) && window.is_fulltile()) //exception for breaking full tile windows on top of single pane windows + return 1 + if(target_atom && (target_atom.atom_flags & ATOM_FLAG_ADJACENT_EXCEPTION)) // exception for atoms that should always be reachable + return 1 else return 0 diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 162f27e9b1f2..b0ab2d79e09a 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -60,15 +60,9 @@ if(silicon_camera.in_camera_mode) silicon_camera.camera_mode_off() - silicon_camera.captureimage(A, usr) + silicon_camera.captureimage(A, src) return - /* - AI restrained() currently does nothing - if(restrained()) - RestrainedClickOn(A) - else - */ A.add_hiddenprint(src) A.attack_ai(src) @@ -78,14 +72,14 @@ The below is only really for safety, or you can alter the way it functions and re-insert it above. */ -/mob/living/silicon/ai/UnarmedAttack(atom/A) - A.attack_ai(src) +/mob/living/silicon/ai/ResolveUnarmedAttack(atom/A) + return A.attack_ai(src) /mob/living/silicon/ai/RangedAttack(atom/A, var/params) A.attack_ai(src) return TRUE -/atom/proc/attack_ai(mob/user) +/atom/proc/attack_ai(mob/living/silicon/ai/user) return /* @@ -124,10 +118,10 @@ I have no idea why it was in atoms.dm instead of respective files. */ -/atom/proc/AICtrlAltClick() +/atom/proc/AICtrlAltClick(mob/living/silicon/user) -/obj/machinery/door/airlock/AICtrlAltClick() // Electrifies doors. - if(usr.incapacitated()) +/obj/machinery/door/airlock/AICtrlAltClick(mob/living/silicon/user) // Electrifies doors. + if(user.incapacitated()) return if(!electrified_until) // permanent shock @@ -137,14 +131,14 @@ Topic(src, list("command"="electrify_permanently", "activate" = "0")) return 1 -/atom/proc/AICtrlShiftClick() +/atom/proc/AICtrlShiftClick(mob/living/silicon/user) return -/atom/proc/AIShiftClick() +/atom/proc/AIShiftClick(mob/living/silicon/user) return -/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors! - if(usr.incapacitated()) +/obj/machinery/door/airlock/AIShiftClick(mob/living/silicon/user) // Opens and closes doors! + if(user.incapacitated()) return if(density) Topic(src, list("command"="open", "activate" = "1")) @@ -152,11 +146,11 @@ Topic(src, list("command"="open", "activate" = "0")) return 1 -/atom/proc/AICtrlClick() +/atom/proc/AICtrlClick(mob/living/silicon/user) return FALSE -/obj/machinery/door/airlock/AICtrlClick() // Bolts doors - if(usr.incapacitated()) +/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/user) // Bolts doors + if(user.incapacitated()) return FALSE if(locked) Topic(src, list("command"="bolts", "activate" = "0")) @@ -164,35 +158,35 @@ Topic(src, list("command"="bolts", "activate" = "1")) return TRUE -/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs. - if(usr.incapacitated()) +/obj/machinery/apc/AICtrlClick(mob/living/silicon/user) // turns off/on APCs. + if(user.incapacitated()) return FALSE Topic(src, list("breaker"="1")) return TRUE -/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets - if(usr.incapacitated()) +/obj/machinery/turretid/AICtrlClick(mob/living/silicon/user) //turns off/on Turrets + if(user.incapacitated()) return FALSE Topic(src, list("command"="enable", "value"="[!enabled]")) return TRUE -/atom/proc/AIAltClick(var/atom/A) - return AltClick(A) +/atom/proc/AIAltClick(mob/living/silicon/user) + return AltClick(user) -/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets - if(usr.incapacitated()) +/obj/machinery/turretid/AIAltClick(mob/living/silicon/user) //toggles lethal on turrets + if(user.incapacitated()) return Topic(src, list("command"="lethal", "value"="[!lethal]")) return 1 -/obj/machinery/atmospherics/binary/pump/AIAltClick() - return AltClick() +/obj/machinery/atmospherics/binary/pump/AIAltClick(mob/living/silicon/user) + return AltClick(user) /atom/proc/AIMiddleClick(var/mob/living/silicon/user) return 0 -/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights. - if(usr.incapacitated()) +/obj/machinery/door/airlock/AIMiddleClick(mob/living/silicon/user) // Toggles door bolt lights. + if(user.incapacitated()) return if(..()) return diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index e14608b770a6..a7dc5af566af 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -41,10 +41,10 @@ After that, mostly just check your state, check whether you're holding an item, check whether you're adjacent to the target, then pass off the click to whoever - is recieving it. + is receiving it. The most common are: * mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves - * atom/attackby(item,user) - used only when adjacent + * atom/attackby(used_item,user) - used only when adjacent * item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent * mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed */ @@ -56,12 +56,18 @@ next_click = world.time + 1 var/list/modifiers = params2list(params) + if(modifiers["right"]) + RightClickOn(A) + return 1 if(modifiers["shift"] && modifiers["ctrl"]) CtrlShiftClickOn(A) return 1 if(modifiers["ctrl"] && modifiers["alt"]) CtrlAltClickOn(A) return 1 + if(modifiers["middle"] && modifiers["alt"]) + AltMiddleClickOn(A) + return 1 if(modifiers["middle"]) MiddleClickOn(A) return 1 @@ -75,11 +81,11 @@ CtrlClickOn(A) return 1 - if(stat || paralysis || stunned || weakened || sleeping) + if(incapacitated(INCAPACITATION_KNOCKOUT)) return // Do not allow player facing change in fixed chairs - if(!istype(buckled) || buckled.buckle_movable) + if(!istype(buckled) || buckled.buckle_movable || buckled.buckle_allow_rotation) face_atom(A) // change direction to face what you clicked on if(!canClick()) // in the year 2000... @@ -92,34 +98,32 @@ if(in_throw_mode) if(isturf(A) || isturf(A.loc)) - throw_item(A) + mob_throw_item(A) trigger_aiming(TARGET_CAN_CLICK) return 1 - throw_mode_off() + toggle_throw_mode(FALSE) - var/obj/item/W = get_active_hand() + var/obj/item/holding = get_active_held_item() - if(W == A) // Handle attack_self - W.attack_self(src) + if(holding == A) // Handle attack_self + holding.attack_self(src) trigger_aiming(TARGET_CAN_CLICK) - if(hand) - update_inv_l_hand(0) - else - update_inv_r_hand(0) + update_inhand_overlays(FALSE) return 1 //Atoms on your person // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth. var/sdepth = A.storage_depth(src) if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1)) - if(W) - var/resolved = W.resolve_attackby(A, src, params) - if(!resolved && A && W) - W.afterattack(A, src, 1, params) // 1 indicates adjacency + if(holding) + var/resolved = holding.resolve_attackby(A, src, params) + if(!resolved && A && holding) + holding.afterattack(A, src, 1, params) // 1 indicates adjacency + setClickCooldown(DEFAULT_QUICK_COOLDOWN) else if(ismob(A)) // No instant mob attacking - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - UnarmedAttack(A, 1) + setClickCooldown(DEFAULT_QUICK_COOLDOWN) + UnarmedAttack(A, TRUE) trigger_aiming(TARGET_CAN_CLICK) return 1 @@ -132,21 +136,23 @@ sdepth = A.storage_depth_turf() if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) if(A.Adjacent(src)) // see adjacent.dm - if(W) + if(holding) + // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) - var/resolved = W.resolve_attackby(A,src, params) - if(!resolved && A && W) - W.afterattack(A, src, 1, params) // 1: clicking something Adjacent + var/resolved = holding.resolve_attackby(A, src, params) + if(!resolved && A && holding) + holding.afterattack(A, src, 1, params) // 1: clicking something Adjacent + setClickCooldown(DEFAULT_QUICK_COOLDOWN) else if(ismob(A)) // No instant mob attacking - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - UnarmedAttack(A, 1) + setClickCooldown(DEFAULT_QUICK_COOLDOWN) + UnarmedAttack(A, TRUE) trigger_aiming(TARGET_CAN_CLICK) return else // non-adjacent click - if(W) - W.afterattack(A, src, 0, params) // 0: not Adjacent + if(holding) + holding.afterattack(A, src, 0, params) // 0: not Adjacent else RangedAttack(A, params) @@ -157,13 +163,14 @@ next_move = max(world.time + timeout, next_move) /mob/proc/canClick() - if(config.no_click_cooldown || next_move <= world.time) + if(get_config_value(/decl/config/toggle/no_click_cooldown) || next_move <= world.time) return 1 return 0 // Default behavior: ignore double clicks, the second click that makes the doubleclick call already calls for a normal click /mob/proc/DblClickOn(var/atom/A, var/params) - . = A.show_atom_list_for_turf(src, get_turf(A)) + if(get_preference_value(/datum/client_preference/show_turf_contents) == PREF_DOUBLE_CLICK) + . = A.show_atom_list_for_turf(src, get_turf(A)) /* Translates into attack_hand, etc. @@ -174,20 +181,38 @@ proximity_flag is not currently passed to attack_hand, and is instead used in human click code to allow glove touches only at melee range. + + Returns TRUE if no further processing is desired, FALSE otherwise. */ /mob/proc/UnarmedAttack(var/atom/A, var/proximity_flag) return -/mob/living/UnarmedAttack(var/atom/A, var/proximity_flag) +/// Handles per-mob unarmed attack functionality after shared checks, e.g. maneuvers and abilities. +/mob/living/proc/ResolveUnarmedAttack(var/atom/A) + return A.attack_hand(src) +/mob/living/UnarmedAttack(var/atom/A, var/proximity_flag) + SHOULD_NOT_OVERRIDE(TRUE) if(GAME_STATE < RUNLEVEL_GAME) to_chat(src, "You cannot attack people before the game has started.") - return 0 + return TRUE - if(stat) - return 0 + if(stat || try_maneuver(A) || !proximity_flag) + return TRUE - return 1 + // Handle any prepared ability/spell/power invocations. + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + if(abilities?.do_melee_invocation(A)) + return TRUE + + // Special glove functions: + // If the gloves do anything, have them return 1 to stop + // normal attack_hand() here. + var/obj/item/clothing/gloves/G = get_equipped_item(slot_gloves_str) + if(istype(G) && G.Touch(A, proximity_flag)) + return TRUE + + return ResolveUnarmedAttack(A) /* Ranged unarmed attack: @@ -198,17 +223,26 @@ animals lunging, etc. */ /mob/proc/RangedAttack(var/atom/A, var/params) - if(!mutations.len) - return FALSE + return FALSE - if((MUTATION_LASER in mutations) && a_intent == I_HURT) - LaserEyes(A) // moved into a proc below +/mob/living/RangedAttack(var/atom/A, var/params) + if(try_maneuver(A)) return TRUE + // Handle any prepared ability/spell/power invocations. + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + if(abilities?.do_ranged_invocation(A)) + return TRUE + + if(A.attack_hand_ranged(src)) + return TRUE + + return FALSE + /* Restrained ClickOn - Used when you are handcuffed and click things. + Used when you are cuffed and click things. Not currently used by anything but could easily be. */ /mob/proc/RestrainedClickOn(var/atom/A) @@ -220,7 +254,9 @@ */ /mob/proc/MiddleClickOn(var/atom/A) swap_hand() - return + +/mob/proc/AltMiddleClickOn(var/atom/A) + pointed(A) // In case of use break glass /* @@ -236,9 +272,10 @@ /mob/proc/ShiftClickOn(var/atom/A) A.ShiftClick(src) return + /atom/proc/ShiftClick(var/mob/user) if(user.client && user.client.eye == user) - user.examinate(src) + user.examine_verb(src) return /* @@ -249,25 +286,30 @@ return A.CtrlClick(src) /atom/proc/CtrlClick(var/mob/user) + if(get_recursive_loc_of_type(/mob) == user) + var/decl/interaction_handler/handler = get_quick_interaction_handler(user) + if(handler) + var/using_item = user.get_active_held_item() + if(handler.is_possible(src, user, using_item)) + return handler.invoked(src, user, using_item) return FALSE /atom/movable/CtrlClick(var/mob/living/user) - if(istype(user) && CanPhysicallyInteract(user) && !user.lying) - return user.make_grab(src) - . = ..() + if(!(. = ..()) && loc != user) + return try_make_grab(user, defer_hand = TRUE) || ..() /* Alt click Unused except for AI */ /mob/proc/AltClickOn(var/atom/A) - var/datum/extension/on_click/alt = get_extension(A, /datum/extension/on_click/alt) - if(alt && alt.on_click(src)) - return A.AltClick(src) /atom/proc/AltClick(var/mob/user) - . = show_atom_list_for_turf(user, get_turf(src)) + if(try_handle_interactions(user, get_alt_interactions(user), user?.get_active_held_item(), check_alt_interactions = TRUE)) + return TRUE + if(user?.get_preference_value(/datum/client_preference/show_turf_contents) == PREF_ALT_CLICK) + . = show_atom_list_for_turf(user, get_turf(src)) /atom/proc/show_atom_list_for_turf(var/mob/user, var/turf/T) if(T && user.TurfAdjacent(T)) @@ -286,6 +328,13 @@ return FALSE return z == T.z && (get_dist(loc, T) <= get_effective_view(client)) +/mob/proc/RightClickOn(atom/A) + A.RightClick(src) + return + +/atom/proc/RightClick(mob/user) + return + /* Control+Shift click Unused except for AI @@ -307,32 +356,6 @@ /atom/proc/CtrlAltClick(var/mob/user) return -/* - Misc helpers - - Laser Eyes: as the name implies, handles this since nothing else does currently - face_atom: turns the mob towards what you clicked on -*/ -/mob/proc/LaserEyes(atom/A) - return - -/mob/living/LaserEyes(atom/A) - setClickCooldown(DEFAULT_QUICK_COOLDOWN) - var/turf/T = get_turf(src) - - var/obj/item/projectile/beam/LE = new (T) - LE.icon = 'icons/effects/genetics.dmi' - LE.icon_state = "eyelasers" - playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1) - LE.launch(A) -/mob/living/carbon/human/LaserEyes() - if(nutrition>0) - ..() - adjust_nutrition(-(rand(1,5))) - handle_regular_hud_updates() - else - to_chat(src, SPAN_WARNING("You're out of energy! You need food!")) - // Simple helper to face what you clicked on, in case it should be needed in more than one place /mob/proc/face_atom(var/atom/A) if(!A || !x || !y || !A.x || !A.y) return @@ -348,36 +371,6 @@ if(dx > 0) direction = EAST else direction = WEST if(direction != dir) + if(facing_dir) + facing_dir = direction facedir(direction) - -GLOBAL_LIST_INIT(click_catchers, create_click_catcher()) - -/obj/screen/click_catcher - icon = 'icons/mob/screen_gen.dmi' - icon_state = "click_catcher" - plane = CLICKCATCHER_PLANE - mouse_opacity = 2 - screen_loc = "CENTER-7,CENTER-7" - -/obj/screen/click_catcher/Destroy() - SHOULD_CALL_PARENT(FALSE) - return QDEL_HINT_LETMELIVE - -/proc/create_click_catcher() - . = list() - for(var/i = 0, i<15, i++) - for(var/j = 0, j<15, j++) - var/obj/screen/click_catcher/CC = new() - CC.screen_loc = "TOP-[i],RIGHT-[j]" - . += CC - -/obj/screen/click_catcher/Click(location, control, params) - var/list/modifiers = params2list(params) - if(modifiers["middle"] && istype(usr, /mob/living/carbon)) - var/mob/living/carbon/C = usr - C.swap_hand() - else - var/turf/T = screen_loc2turf(screen_loc, get_turf(usr)) - if(T) - T.Click(location, control, params) - . = 1 diff --git a/code/_onclick/click_handling.dm b/code/_onclick/click_handling.dm index 81f6d95f2694..08d1ec3b5790 100644 --- a/code/_onclick/click_handling.dm +++ b/code/_onclick/click_handling.dm @@ -11,17 +11,14 @@ if(!click_handlers) { \ var/list/click_handlers /mob/Destroy() + QDEL_NULL(status_markers) QDEL_NULL_LIST(click_handlers) - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable?.hat) - hattable.hat.dropInto(get_turf(src)) - hattable.hat = null . = ..() -var/const/CLICK_HANDLER_NONE = 0x000000 -var/const/CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT = 0x000001 -var/const/CLICK_HANDLER_REMOVE_IF_NOT_TOP = 0x000002 -var/const/CLICK_HANDLER_ALL = (~0) +var/global/const/CLICK_HANDLER_NONE = BITFLAG(0) +var/global/const/CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT = BITFLAG(1) +var/global/const/CLICK_HANDLER_REMOVE_IF_NOT_TOP = BITFLAG(2) +var/global/const/CLICK_HANDLER_ALL = (CLICK_HANDLER_NONE|CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT|CLICK_HANDLER_REMOVE_IF_NOT_TOP) /datum/click_handler var/mob/user @@ -31,11 +28,11 @@ var/const/CLICK_HANDLER_ALL = (~0) ..() src.user = user if(flags & (CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT)) - GLOB.logged_out_event.register(user, src, /datum/click_handler/proc/OnMobLogout) + events_repository.register(/decl/observ/logged_out, user, src, TYPE_PROC_REF(/datum/click_handler, OnMobLogout)) /datum/click_handler/Destroy() if(flags & (CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT)) - GLOB.logged_out_event.unregister(user, src, /datum/click_handler/proc/OnMobLogout) + events_repository.unregister(/decl/observ/logged_out, user, src, TYPE_PROC_REF(/datum/click_handler, OnMobLogout)) user = null . = ..() diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 932fb5c1abef..b9100b54ba30 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -42,22 +42,15 @@ if(silicon_camera.in_camera_mode) silicon_camera.camera_mode_off() if(is_component_functioning("camera")) - silicon_camera.captureimage(A, usr) + silicon_camera.captureimage(A, src) else - to_chat(src, "Your camera isn't functional.") + to_chat(src, SPAN_DANGER("Your camera isn't functional.")) return - /* - cyborg restrained() currently does nothing - if(restrained()) - RestrainedClickOn(A) - return - */ - - var/obj/item/W = get_active_hand() + var/obj/item/holding = get_active_held_item() // Cyborgs have no range-checking unless there is item use - if(!W) + if(!holding) A.add_hiddenprint(src) A.attack_robot(src) return @@ -66,18 +59,17 @@ if( buckled ) return - if(W == A) + if(holding == A) - W.attack_self(src) + holding.attack_self(src) return - // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents) if(A == loc || (A in loc) || (A in contents)) // No adjacency checks - - var/resolved = W.resolve_attackby(A, src, params) - if(!resolved && A && W) - W.afterattack(A, src, 1, params) // 1 indicates adjacency + var/resolved = holding.resolve_attackby(A, src, params) + if(!resolved && A && holding) + holding.afterattack(A, src, 1, params) // 1 indicates adjacency + setClickCooldown(DEFAULT_QUICK_COOLDOWN) return if(!isturf(loc)) @@ -86,20 +78,13 @@ var/sdepth = A.storage_depth_turf() if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) if(A.Adjacent(src)) // see adjacent.dm - - var/resolved = W.resolve_attackby(A, src, params) - if(!resolved && A && W) - W.afterattack(A, src, 1, params) // 1 indicates adjacency - return + var/resolved = holding.resolve_attackby(A, src, params) + if(!resolved && A && holding) + holding.afterattack(A, src, 1, params) // 1 indicates adjacency + setClickCooldown(DEFAULT_QUICK_COOLDOWN) else - W.afterattack(A, src, 0, params) - return - return - -//Middle click cycles through selected modules. -/mob/living/silicon/robot/MiddleClickOn(var/atom/A) - cycle_modules() - return + holding.afterattack(A, src, 0, params) + return //Give cyborgs hotkey clicks without breaking existing uses of hotkey clicks // for non-doors/apcs @@ -121,42 +106,39 @@ /atom/proc/BorgCtrlShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden CtrlShiftClick(user) -/obj/machinery/door/airlock/BorgCtrlShiftClick() - AICtrlShiftClick() +/obj/machinery/door/airlock/BorgCtrlShiftClick(mob/living/silicon/robot/user) + AICtrlShiftClick(user) /atom/proc/BorgShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden ShiftClick(user) -/obj/machinery/door/airlock/BorgShiftClick() // Opens and closes doors! Forwards to AI code. - AIShiftClick() +/obj/machinery/door/airlock/BorgShiftClick(mob/living/silicon/robot/user) // Opens and closes doors! Forwards to AI code. + AIShiftClick(user) /atom/proc/BorgCtrlClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden return CtrlClick(user) -/obj/machinery/door/airlock/BorgCtrlClick() // Bolts doors. Forwards to AI code. - return AICtrlClick() +/obj/machinery/door/airlock/BorgCtrlClick(mob/living/silicon/robot/user) // Bolts doors. Forwards to AI code. + return AICtrlClick(user) -/obj/machinery/power/apc/BorgCtrlClick() // turns off/on APCs. Forwards to AI code. - return AICtrlClick() +/obj/machinery/apc/BorgCtrlClick(mob/living/silicon/robot/user) // turns off/on APCs. Forwards to AI code. + return AICtrlClick(user) -/obj/machinery/turretid/BorgCtrlClick() //turret control on/off. Forwards to AI code. - return AICtrlClick() +/obj/machinery/turretid/BorgCtrlClick(mob/living/silicon/robot/user) //turret control on/off. Forwards to AI code. + return AICtrlClick(user) /atom/proc/BorgAltClick(var/mob/living/silicon/robot/user) AltClick(user) return -/obj/machinery/door/airlock/BorgAltClick() // Eletrifies doors. Forwards to AI code. - if (usr.a_intent != I_HELP) - AICtrlAltClick() +/obj/machinery/door/airlock/BorgAltClick(mob/living/silicon/robot/user) // Eletrifies doors. Forwards to AI code. + if (!user.check_intent(I_FLAG_HELP)) + AICtrlAltClick(user) else ..() -/obj/machinery/turretid/BorgAltClick() //turret lethal on/off. Forwards to AI code. - AIAltClick() - -/obj/machinery/atmospherics/binary/pump/BorgAltClick() - return AltClick() +/obj/machinery/turretid/BorgAltClick(mob/living/silicon/robot/user) //turret lethal on/off. Forwards to AI code. + AIAltClick(user) /atom/proc/BorgCtrlAltClick(var/mob/living/silicon/robot/user) CtrlAltClick(user) @@ -169,13 +151,11 @@ clicks, you can do so here, but you will have to change attack_robot() above to the proper function */ -/mob/living/silicon/robot/UnarmedAttack(atom/A) - A.attack_robot(src) +/mob/living/silicon/robot/ResolveUnarmedAttack(atom/A) + return A.attack_robot(src) /mob/living/silicon/robot/RangedAttack(atom/A, var/params) - A.attack_robot(src) - return TRUE + return A.attack_robot(src) /atom/proc/attack_robot(mob/user) - attack_ai(user) - return + return attack_ai(user) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index cfbc69312b34..9102b1b0e88e 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -1,28 +1,45 @@ /* - MouseDrop: - - Called on the atom you're dragging. In a lot of circumstances we want to use the - recieving object instead, so that's the default action. This allows you to drag + The below procs are called on the atom you're dragging. In a lot of circumstances we want to use the + receiving object instead, so that's the default action. This allows you to drag almost anything into a trash can. */ -/atom/proc/CanMouseDrop(atom/over, var/mob/user = usr, var/incapacitation_flags) - if(!user || !over) +/atom/MouseDrop(over_object, src_location, over_location, src_control, over_control, params) + SHOULD_CALL_PARENT(TRUE) + if(!can_mouse_drop(over_object, usr, params = params) || !handle_mouse_drop(over_object, usr, params)) + . = ..() + +/atom/proc/handle_mouse_drop(atom/over, mob/user, params) + if(storage && !(. = storage?.handle_mouse_drop(user, over, params))) + storage_removed(user) + return + . = over?.receive_mouse_drop(src, user, params) + +// Can the user drop something onto this atom? +/atom/proc/user_can_mousedrop_onto(mob/user, atom/being_dropped, incapacitation_flags, params) + return !user.incapacitated(incapacitation_flags) && check_mousedrop_interactivity(user, params) && user.check_dexterity(DEXTERITY_EQUIP_ITEM, silent = TRUE) + +/atom/proc/check_mousedrop_interactivity(mob/user, params) + return CanPhysicallyInteract(user) + +// This proc checks if an atom can be mousedropped onto the target by the user. +/atom/proc/can_mouse_drop(var/atom/over, var/mob/user = usr, var/incapacitation_flags = INCAPACITATION_DEFAULT, var/params) + SHOULD_CALL_PARENT(TRUE) + if(!istype(user) || !istype(over) ||QDELETED(user) || QDELETED(over) || QDELETED(src)) + return FALSE + if(!over.user_can_mousedrop_onto(user, src, incapacitation_flags, params)) return FALSE - if(user.incapacitated(incapacitation_flags)) + if(!check_mousedrop_adjacency(over, user, params)) return FALSE - if(!src.Adjacent(user) || !over.Adjacent(user)) - return FALSE // should stop you from dragging through windows return TRUE -/atom/MouseDrop(atom/over) - if(!usr || !over) return - if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows - - spawn(0) - over.MouseDrop_T(src,usr) - return +/atom/proc/check_mousedrop_adjacency(atom/over, mob/user, params) + . = (Adjacent(user) && ((over in user?.client?.screen) || over.Adjacent(user))) -// Receive a mouse drop -/atom/proc/MouseDrop_T(atom/dropping, mob/user) - return +// Receive a mouse drop. +// Returns false if the atom is valid for dropping further up the chain, true if the drop has been handled. +/atom/proc/receive_mouse_drop(atom/dropping, mob/user, params) + if(isliving(user) && !user.anchored && can_climb(user) && dropping == user) + do_climb(dropping) + return TRUE + return FALSE diff --git a/code/_onclick/ghost.dm b/code/_onclick/ghost.dm index 272fcf8eefec..a47458ff2f18 100644 --- a/code/_onclick/ghost.dm +++ b/code/_onclick/ghost.dm @@ -28,20 +28,14 @@ if(!canClick()) return setClickCooldown(DEFAULT_QUICK_COOLDOWN) - // You are responsible for checking config.ghost_interaction when you override this function + // You are responsible for checking ghost_interaction when you override this function // Not all of them require checking, see below var/list/modifiers = params2list(params) if(modifiers["alt"]) - // I'd rather call ..() but who knows what will break if we do that - var/datum/extension/on_click/alt = get_extension(A, /datum/extension/on_click/alt) - if(alt && alt.on_click(src)) - return - var/target_turf = get_turf(A) - if(target_turf) - AltClickOn(target_turf) + AltClickOn(A) return if(modifiers["shift"]) - examinate(A) + examine_verb(A) return A.attack_ghost(src) @@ -50,7 +44,10 @@ if(!istype(user)) return if(user.client && user.client.inquisitive_ghost) - user.examinate(src) + user.examine_verb(src) + return + if(user.client?.holder || user.antagHUD) + storage?.show_to(user) return // --------------------------------------- @@ -58,36 +55,9 @@ // Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu /obj/machinery/teleport/hub/attack_ghost(mob/user) - var/atom/l = loc - var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z)) - if(com.locked) + if(com?.locked) user.forceMove(get_turf(com.locked)) /obj/effect/portal/attack_ghost(mob/user) if(target) user.forceMove(get_turf(target)) - -/obj/machinery/gateway/centerstation/attack_ghost(mob/user) - if(awaygate) - user.forceMove(awaygate.loc) - else - to_chat(user, "[src] has no destination.") - -/obj/machinery/gateway/centeraway/attack_ghost(mob/user) - if(stationgate) - user.forceMove(stationgate.loc) - else - to_chat(user, "[src] has no destination.") - -// ------------------------------------------- -// This was supposed to be used by adminghosts -// I think it is a *terrible* idea -// but I'm leaving it here anyway -// commented out, of course. -/* -/atom/proc/attack_admin(mob/user) - if(!user || !user.client || !user.client.holder) - return - attack_hand(user) - -*/ diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index ee7faaf321f4..727108ce080a 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -14,60 +14,52 @@ */ #define ui_entire_screen "WEST,SOUTH to EAST,NORTH" +#define ui_center_fullscreen "CENTER-7,CENTER-7" -//Lower left, persistant menu +//Lower left, persistent menu #define ui_inventory "LEFT:6,BOTTOM:5" -//Lower center, persistant menu +//Lower center, persistent menu #define ui_sstore1 "LEFT+2:10,BOTTOM:5" -#define ui_id "LEFT+3:12,BOTTOM:5" -#define ui_belt "LEFT+4:14,BOTTOM:5" -#define ui_back "CENTER-2:14,BOTTOM:5" +#define ui_back "LEFT+3:22,BOTTOM:5" +#define ui_id "LEFT+4:26,BOTTOM:5" +#define ui_belt "RIGHT-5:16,BOTTOM:5" #define ui_rhand "CENTER-1:16,BOTTOM:5" #define ui_lhand "CENTER:16,BOTTOM:5" #define ui_equip "CENTER-1:16,BOTTOM+1:5" #define ui_swaphand1 "CENTER-1:16,BOTTOM+1:5" #define ui_swaphand2 "CENTER:16,BOTTOM+1:5" -#define ui_storage1 "CENTER+1:16,BOTTOM:5" -#define ui_storage2 "CENTER+2:16,BOTTOM:5" +#define ui_storage1 "RIGHT-3:16,BOTTOM:5" +#define ui_storage2 "RIGHT-4:16,BOTTOM:5" -#define ui_alien_head "CENTER-3:12,BOTTOM:5" //aliens -#define ui_alien_oclothing "CENTER-2:14,BOTTOM:5"//aliens - -#define ui_inv1 "CENTER-1,BOTTOM:5" //borgs -#define ui_inv2 "CENTER,BOTTOM:5" //borgs -#define ui_inv3 "CENTER+1,BOTTOM:5" //borgs -#define ui_borg_store "CENTER+2,BOTTOM:5" //borgs -#define ui_borg_inventory "CENTER-2,BOTTOM:5"//borgs -#define ui_borg_drop_grab "CENTER-3,BOTTOM:5"//borgs -#define ui_monkey_mask "LEFT+4:14,BOTTOM:5" //monkey -#define ui_monkey_back "LEFT+5:14,BOTTOM:5" //monkey +// Robot defines. +#define ui_inv1 "CENTER-1,BOTTOM:21" +#define ui_inv2 "CENTER,BOTTOM:21" +#define ui_inv3 "CENTER+1,BOTTOM:21" +#define ui_borg_store "CENTER+2,BOTTOM:21" +#define ui_borg_inventory "CENTER-2,BOTTOM:21" +#define ui_borg_drop_grab "CENTER-3,BOTTOM:21" #define ui_construct_health "RIGHT:00,CENTER:15" //same height as humans, hugging the right border -#define ui_construct_purge "RIGHT:00,CENTER-1:15" #define ui_construct_fire "RIGHT-1:16,CENTER+1:13" //above health, slightly to the left -#define ui_construct_pull "RIGHT-1:28,BOTTOM+1:10" //above the zone_sel icon +#define ui_construct_pull "RIGHT-1:28,BOTTOM+1:10" //above the zone selector icon -//Lower right, persistant menu +//Lower right, persistent menu #define ui_dropbutton "RIGHT-4:22,BOTTOM:5" #define ui_drop_throw "RIGHT-1:28,BOTTOM+1:7" #define ui_pull_resist "RIGHT-2:26,BOTTOM+1:7" -#define ui_acti "RIGHT-2:26,BOTTOM:5" -#define ui_movi "RIGHT-3:24,BOTTOM:5" +#define ui_acti "CENTER,BOTTOM:5" +#define ui_movi "RIGHT-2:24,BOTTOM:5" +#define ui_attack_selector "RIGHT-2:27,BOTTOM+2:9" #define ui_zonesel "RIGHT-1:28,BOTTOM:5" -#define ui_acti_alt "RIGHT-1:28,BOTTOM:5" //alternative intent switcher for when the interface is hidden (F12) -#define ui_stamina "RIGHT-3:24,BOTTOM+1:5" -#define ui_borg_pull "RIGHT-3:24,BOTTOM+1:7" -#define ui_borg_module "RIGHT-2:26,BOTTOM+1:7" -#define ui_borg_panel "RIGHT-1:28,BOTTOM+1:7" +#define ui_borg_module "RIGHT-1:28,BOTTOM+1:7" //Gun buttons -#define ui_gun1 "RIGHT-2:26,BOTTOM+2:7" -#define ui_gun2 "RIGHT-1:28, BOTTOM+3:7" -#define ui_gun3 "RIGHT-2:26,BOTTOM+3:7" +#define ui_gun1 "RIGHT-1:28,BOTTOM+3:7" +#define ui_gun2 "RIGHT-2:28,BOTTOM+3:7" +#define ui_gun3 "RIGHT-3:28,BOTTOM+3:7" #define ui_gun_select "RIGHT-1:28,BOTTOM+2:7" -#define ui_gun4 "RIGHT-3:24,BOTTOM+2:7" //Upper-middle right (damage indicators and up hint) #define ui_up_hint "RIGHT-1:28,TOP-1:29" @@ -86,9 +78,9 @@ #define ui_temp "RIGHT-1:28,CENTER-1:13" #define ui_health "RIGHT-1:28,CENTER:15" #define ui_internal "RIGHT-1:28,CENTER+1:17" - //borgs -#define ui_borg_health "RIGHT-1:28,CENTER-1:13" //borgs have the health display where humans have the pressure damage indicator. -#define ui_alien_health "RIGHT-1:28,CENTER-1:13" //aliens have the health display where humans have the pressure damage indicator. + +// Robots have the health display where humans have the pressure damage indicator. +#define ui_borg_health "RIGHT-1:28,CENTER-1:13" //Pop-up inventory #define ui_shoes "LEFT+1:8,BOTTOM:5" @@ -104,34 +96,17 @@ #define ui_head "LEFT+1:8,BOTTOM+3:11" -//Intent small buttons -#define ui_help_small "RIGHT-3:8,BOTTOM:1" -#define ui_disarm_small "RIGHT-3:15,BOTTOM:18" -#define ui_grab_small "RIGHT-3:32,BOTTOM:18" -#define ui_harm_small "RIGHT-3:39,BOTTOM:1" - -//#define ui_swapbutton "6:-16,1:5" //Unused - -//#define ui_headset "BOTTOM,8" -#define ui_hand "CENTER-1:14,BOTTOM:5" -#define ui_hstore1 "CENTER-2,CENTER-2" -//#define ui_resist "RIGHT+1,BOTTOM-1" -#define ui_sleep "RIGHT+1, TOP-13" -#define ui_rest "RIGHT+1, TOP-14" - - #define ui_iarrowleft "BOTTOM-1,RIGHT-4" #define ui_iarrowright "BOTTOM-1,RIGHT-2" -#define ui_spell_master "RIGHT-1:16,TOP-1:16" -#define ui_genetic_master "RIGHT-1:16,TOP-3:16" +#define ui_ability_master "RIGHT-2:16,TOP-1:16" // AI #define ui_ai_core "LEFT:6,BOTTOM:5" #define ui_ai_announcement "LEFT+1:10,BOTTOM:5" #define ui_ai_cam_track "LEFT+2:12,BOTTOM:5" #define ui_ai_cam_light "LEFT+3:14,BOTTOM:5" -#define ui_ai_cam_change_network "LEFT+4:16,BOTTOM:5" +#define ui_ai_cam_change_channel "LEFT+4:16,BOTTOM:5" #define ui_ai_sensor "CENTER-2:18,BOTTOM:5" #define ui_ai_crew_manifest "CENTER-1:20,BOTTOM:5" #define ui_ai_take_image "CENTER:22,BOTTOM:5" @@ -155,4 +130,14 @@ // AI: Crew #define ui_ai_crew_mon "RIGHT-1:30,TOP:0" -#define ui_ai_crew_rec "RIGHT-2:30, TOP:0" \ No newline at end of file +#define ui_ai_crew_rec "RIGHT-2:30, TOP:0" + +// pAI +#define ui_pai_software "TOP,LEFT:6" +#define ui_pai_subsystems "TOP,LEFT+1:6" +#define ui_pai_shell "TOP,LEFT+2:6" +#define ui_pai_light "TOP,LEFT+3:6" +#define ui_pai_rest "TOP,LEFT+4:6" + +// storage menu +#define ui_storage_default "LEFT+7,BOTTOM+7 to LEFT+10,BOTTOM+8" diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm deleted file mode 100644 index 7a4ede8aa2a1..000000000000 --- a/code/_onclick/hud/ability_screen_objects.dm +++ /dev/null @@ -1,391 +0,0 @@ -/obj/screen/movable/ability_master - name = "Abilities" - icon = 'icons/mob/screen_spells.dmi' - icon_state = "grey_spell_ready" - var/list/obj/screen/ability/ability_objects = list() - var/list/obj/screen/ability/spell_objects = list() - var/showing = 0 // If we're 'open' or not. - - var/open_state = "master_open" // What the button looks like when it's 'open', showing the other buttons. - var/closed_state = "master_closed" // Button when it's 'closed', hiding everything else. - - screen_loc = ui_spell_master // TODO: Rename - - var/mob/my_mob = null // The mob that possesses this hud object. - -/obj/screen/movable/ability_master/Initialize(mapload, owner) - . = ..() - if(owner) - my_mob = owner - update_abilities(0, owner) - else - . = INITIALIZE_HINT_QDEL - CRASH("ERROR: ability_master's Initialize() was not given an owner argument. This is a bug.") - -/obj/screen/movable/ability_master/Destroy() - . = ..() - remove_all_abilities() //Get rid of the ability objects. - ability_objects.Cut() - if(my_mob) // After that, remove ourselves from the mob seeing us, so we can qdel cleanly. - my_mob.ability_master = null - if(my_mob.client && my_mob.client.screen) - my_mob.client.screen -= src - my_mob = null - -/obj/screen/movable/ability_master/MouseDrop() - if(showing) - return - - return ..() - -/obj/screen/movable/ability_master/Click() - if(!ability_objects.len) // If we're empty for some reason. - return - - toggle_open() - -/obj/screen/movable/ability_master/proc/toggle_open(var/forced_state = 0) - if(showing && (forced_state != 2)) // We are closing the ability master, hide the abilities. - for(var/obj/screen/ability/O in ability_objects) - if(my_mob && my_mob.client) - my_mob.client.screen -= O -// O.handle_icon_updates = 0 - showing = 0 - overlays.len = 0 - overlays.Add(closed_state) - else if(forced_state != 1) // We're opening it, show the icons. - open_ability_master() - update_abilities(1) - showing = 1 - overlays.len = 0 - overlays.Add(open_state) - update_icon() - -/obj/screen/movable/ability_master/proc/open_ability_master() - -/obj/screen/movable/ability_master/proc/update_abilities(forced = 0, mob/user) - update_icon() - if(user && user.client) - if(!(src in user.client.screen)) - user.client.screen += src - var/i = 1 - for(var/obj/screen/ability/ability in ability_objects) - ability.update_icon(forced) - ability.maptext = "[i]" // Slot number - i++ - -/obj/screen/movable/ability_master/on_update_icon() - if(ability_objects.len) - set_invisibility(0) - else - set_invisibility(101) - -/obj/screen/movable/ability_master/proc/add_ability(var/name_given) - if(!name) return - var/obj/screen/ability/new_button = new /obj/screen/ability - new_button.ability_master = src - new_button.SetName(name_given) - new_button.ability_icon_state = name_given - new_button.update_icon(1) - ability_objects.Add(new_button) - if(my_mob.client) - toggle_open(2) //forces the icons to refresh on screen - -/obj/screen/movable/ability_master/proc/remove_ability(var/obj/screen/ability/ability) - if(!ability) - return - ability_objects.Remove(ability) - if(istype(ability,/obj/screen/ability/spell)) - spell_objects.Remove(ability) - qdel(ability) - - - if(ability_objects.len) - toggle_open(showing + 1) - update_icon() -// else -// qdel(src) - -/obj/screen/movable/ability_master/proc/remove_all_abilities() - for(var/obj/screen/ability/A in ability_objects) - remove_ability(A) - -/obj/screen/movable/ability_master/proc/get_ability_by_name(name_to_search) - for(var/obj/screen/ability/A in ability_objects) - if(A.name == name_to_search) - return A - return null - -/obj/screen/movable/ability_master/proc/get_ability_by_proc_ref(proc_ref) - for(var/obj/screen/ability/verb_based/V in ability_objects) - if(V.verb_to_call == proc_ref) - return V - return null - -/obj/screen/movable/ability_master/proc/get_ability_by_instance(var/obj/instance/) - for(var/obj/screen/ability/obj_based/O in ability_objects) - if(O.object == instance) - return O - return null - -/obj/screen/movable/ability_master/proc/get_ability_by_spell(var/spell/s) - for(var/screen in spell_objects) - var/obj/screen/ability/spell/S = screen - if(S.spell == s) - return S - return null - -/mob/Login() - ..() - if(ability_master) - ability_master.update_abilities(1, src) - ability_master.toggle_open(1) - -/mob/Initialize() - . = ..() - ability_master = new /obj/screen/movable/ability_master(null,src) - -///////////ACTUAL ABILITIES//////////// -//This is what you click to do things// -/////////////////////////////////////// -/obj/screen/ability - icon = 'icons/mob/screen_spells.dmi' - icon_state = "grey_spell_base" - maptext_x = 3 - var/background_base_state = "grey" - var/ability_icon_state = null - var/obj/screen/movable/ability_master/ability_master - -/obj/screen/ability/Destroy() - if(ability_master) - ability_master.ability_objects -= src - if(ability_master.my_mob && ability_master.my_mob.client) - ability_master.my_mob.client.screen -= src - if(ability_master && !ability_master.ability_objects.len) - ability_master.update_icon() -// qdel(ability_master) - ability_master = null - return ..() - -/obj/screen/ability/on_update_icon() - overlays.Cut() - icon_state = "[background_base_state]_spell_base" - - overlays += ability_icon_state - -/obj/screen/ability/Click() - if(!usr) - return - - activate() - -// Makes the ability be triggered. The subclasses of this are responsible for carrying it out in whatever way it needs to. -/obj/screen/ability/proc/activate() - to_world("[src] had activate() called.") - return - -// This checks if the ability can be used. -/obj/screen/ability/proc/can_activate() - return 1 - -/client/verb/activate_ability(var/slot as num) - set name = ".activate_ability" -// set hidden = 1 - if(!mob) - return // Paranoid. - if(isnull(slot) || !isnum(slot)) - to_chat(src,".activate_ability requires a number as input, corrisponding to the slot you wish to use.") - return // Bad input. - if(!mob.ability_master) - return // No abilities. - if(slot > mob.ability_master.ability_objects.len || slot <= 0) - return // Out of bounds. - var/obj/screen/ability/A = mob.ability_master.ability_objects[slot] - A.activate() - -//////////Verb Abilities////////// -//Buttons to trigger verbs/procs// -////////////////////////////////// - -/obj/screen/ability/verb_based - var/verb_to_call = null - var/object_used = null - var/arguments_to_use = list() - -/obj/screen/ability/verb_based/activate() - if(object_used && verb_to_call) - call(object_used,verb_to_call)(arguments_to_use) - -/obj/screen/movable/ability_master/proc/add_verb_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments) - if(!object_given) - message_admins("ERROR: add_verb_ability() was not given an object in its arguments.") - if(!verb_given) - message_admins("ERROR: add_verb_ability() was not given a verb/proc in its arguments.") - if(get_ability_by_proc_ref(verb_given)) - return // Duplicate - var/obj/screen/ability/verb_based/A = new /obj/screen/ability/verb_based() - A.ability_master = src - A.object_used = object_given - A.verb_to_call = verb_given - A.ability_icon_state = ability_icon_given - A.SetName(name_given) - if(arguments) - A.arguments_to_use = arguments - ability_objects.Add(A) - if(my_mob.client) - toggle_open(2) //forces the icons to refresh on screen - -//Changeling Abilities -/obj/screen/ability/verb_based/changeling - icon_state = "ling_spell_base" - background_base_state = "ling" - -/obj/screen/movable/ability_master/proc/add_ling_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments) - if(!object_given) - message_admins("ERROR: add_ling_ability() was not given an object in its arguments.") - if(!verb_given) - message_admins("ERROR: add_ling_ability() was not given a verb/proc in its arguments.") - if(get_ability_by_proc_ref(verb_given)) - return // Duplicate - var/obj/screen/ability/verb_based/changeling/A = new /obj/screen/ability/verb_based/changeling() - A.ability_master = src - A.object_used = object_given - A.verb_to_call = verb_given - A.ability_icon_state = ability_icon_given - A.SetName(name_given) - if(arguments) - A.arguments_to_use = arguments - ability_objects.Add(A) - if(my_mob.client) - toggle_open(2) //forces the icons to refresh on screen - - -/////////Obj Abilities//////// -//Buttons to trigger objects// -////////////////////////////// - -/obj/screen/ability/obj_based - var/obj/object = null - -/obj/screen/ability/obj_based/activate() - if(object) - object.Click() - -// Technomancer -/obj/screen/ability/obj_based/technomancer - icon_state = "wiz_spell_base" - background_base_state = "wiz" - -/obj/screen/movable/ability_master/proc/add_technomancer_ability(var/obj/object_given, var/ability_icon_given) - if(!object_given) - message_admins("ERROR: add_technomancer_ability() was not given an object in its arguments.") - if(get_ability_by_instance(object_given)) - return // Duplicate - var/obj/screen/ability/obj_based/technomancer/A = new /obj/screen/ability/obj_based/technomancer() - A.ability_master = src - A.object = object_given - A.ability_icon_state = ability_icon_given - A.SetName(object_given.name) - ability_objects.Add(A) - if(my_mob.client) - toggle_open(2) //forces the icons to refresh on screen - -// Wizard -/obj/screen/ability/spell - var/spell/spell - var/spell_base - var/last_charge = 0 - var/icon/last_charged_icon - -/obj/screen/ability/spell/Destroy() - if(spell) - spell.connected_button = null - spell = null - return ..() - -/obj/screen/movable/ability_master/proc/add_spell(var/spell/spell) - if(!spell) return - - if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one - return - - if(get_ability_by_spell(spell)) - return - - var/obj/screen/ability/spell/A = new() - A.ability_master = src - A.spell = spell - A.SetName(spell.name) - - if(!spell.override_base) //if it's not set, we do basic checks - if(spell.spell_flags & CONSTRUCT_CHECK) - A.spell_base = "const" //construct spells - else - A.spell_base = "wiz" //wizard spells - else - A.spell_base = spell.override_base - A.update_charge(1) - spell_objects.Add(A) - ability_objects.Add(A) - if(my_mob.client) - toggle_open(2) //forces the icons to refresh on screen - -/mob/Life() - UNLINT(..()) - if(ability_master) - ability_master.update_spells(0) - -/obj/screen/movable/ability_master/proc/update_spells(var/forced = 0) - for(var/obj/screen/ability/spell/spell in spell_objects) - spell.update_charge(forced) - -/obj/screen/ability/spell/proc/update_charge(var/forced_update = 0) - if(!spell) - qdel(src) - return - - if(last_charge == spell.charge_counter && !forced_update) - return //nothing to see here - - overlays -= spell.hud_state - - if(spell.charge_type == Sp_RECHARGE || spell.charge_type == Sp_CHARGES) - if(spell.charge_counter < spell.charge_max) - icon_state = "[spell_base]_spell_base" - if(spell.charge_counter > 0) - var/icon/partial_charge = icon(src.icon, "[spell_base]_spell_ready") - partial_charge.Crop(1, 1, partial_charge.Width(), round(partial_charge.Height() * spell.charge_counter / spell.charge_max)) - overlays += partial_charge - if(last_charged_icon) - overlays -= last_charged_icon - last_charged_icon = partial_charge - else if(last_charged_icon) - overlays -= last_charged_icon - last_charged_icon = null - else - icon_state = "[spell_base]_spell_ready" - if(last_charged_icon) - overlays -= last_charged_icon - else - icon_state = "[spell_base]_spell_ready" - - overlays += spell.hud_state - - last_charge = spell.charge_counter - - overlays -= "silence" - if(spell.silenced) - overlays += "silence" - -/obj/screen/ability/spell/on_update_icon(var/forced = 0) - update_charge(forced) - return - -/obj/screen/ability/spell/activate() - spell.perform(usr) - -/obj/screen/movable/ability_master/proc/silence_spells(var/amount) - for(var/obj/screen/ability/spell/spell in spell_objects) - spell.spell.silenced = amount - spell.spell.process() - spell.update_charge(1) \ No newline at end of file diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm index 0550061946cd..70cc620cb206 100644 --- a/code/_onclick/hud/action.dm +++ b/code/_onclick/hud/action.dm @@ -13,24 +13,33 @@ /datum/action var/name = "Generic Action" + var/desc = null var/action_type = AB_ITEM var/procname = null var/atom/movable/target = null var/check_flags = 0 - var/processing = 0 - var/active = 0 - var/obj/screen/movable/action_button/button = null + var/active = FALSE + var/obj/screen/action_button/button = null var/button_icon = 'icons/obj/action_buttons/actions.dmi' var/button_icon_state = "default" + /// The icon to use for the background icon state. Defaults to button_icon if unset. + var/background_icon = 'icons/obj/action_buttons/actions.dmi' var/background_icon_state = "bg_default" var/mob/living/owner /datum/action/New(var/Target) target = Target + background_icon ||= button_icon /datum/action/Destroy() if(owner) Remove(owner) + QDEL_NULL(button) + if(target) + var/obj/item/target_item = target + if(istype(target_item) && target_item.action == src) + target_item.action = null + target = null return ..() /datum/action/proc/SetTarget(var/atom/Target) @@ -75,7 +84,7 @@ Deactivate() if(AB_GENERIC) if(target && procname) - call(target,procname)(usr) + call(target,procname)(owner) return /datum/action/proc/Activate() @@ -84,9 +93,6 @@ /datum/action/proc/Deactivate() return -/datum/action/proc/ProcessAction() - return - /datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed return 0 @@ -100,10 +106,10 @@ if(owner.restrained()) return 0 if(check_flags & AB_CHECK_STUNNED) - if(owner.stunned) + if(HAS_STATUS(owner, STAT_STUN)) return 0 if(check_flags & AB_CHECK_LYING) - if(owner.lying) + if(owner.current_posture.prone) return 0 if(check_flags & AB_CHECK_ALIVE) if(owner.stat) @@ -116,74 +122,8 @@ /datum/action/proc/UpdateName() return name -/obj/screen/movable/action_button - var/datum/action/owner - screen_loc = "LEFT,TOP" - -/obj/screen/movable/action_button/Click(location,control,params) - var/list/modifiers = params2list(params) - if(modifiers["shift"]) - moved = 0 - return 1 - if(usr.next_move >= world.time) // Is this needed ? - return - owner.Trigger() - return 1 - -/obj/screen/movable/action_button/proc/UpdateIcon() - if(!owner) - return - icon = owner.button_icon - icon_state = owner.background_icon_state - - overlays.Cut() - var/image/img - if(owner.action_type == AB_ITEM && owner.target) - var/obj/item/I = owner.target - img = image(I.icon, src , I.icon_state) - else if(owner.button_icon && owner.button_icon_state) - img = image(owner.button_icon,src,owner.button_icon_state) - img.pixel_x = 0 - img.pixel_y = 0 - overlays += img - - if(!owner.IsAvailable()) - color = rgb(128,0,0,128) - else - color = rgb(255,255,255,255) - -//Hide/Show Action Buttons ... Button -/obj/screen/movable/action_button/hide_toggle - name = "Hide Buttons" - icon = 'icons/obj/action_buttons/actions.dmi' - icon_state = "bg_default" - var/hidden = 0 - -/obj/screen/movable/action_button/hide_toggle/Click() - usr.hud_used.action_buttons_hidden = !usr.hud_used.action_buttons_hidden - - hidden = usr.hud_used.action_buttons_hidden - if(hidden) - name = "Show Buttons" - else - name = "Hide Buttons" - UpdateIcon() - usr.update_action_buttons() - - -/obj/screen/movable/action_button/hide_toggle/proc/InitialiseIcon(var/mob/living/user) - if(isalien(user)) - icon_state = "bg_alien" - else - icon_state = "bg_default" - UpdateIcon() - return - -/obj/screen/movable/action_button/hide_toggle/UpdateIcon() - overlays.Cut() - var/image/img = image(icon,src,hidden?"show":"hide") - overlays += img - return +/datum/action/proc/UpdateDesc() + return desc //This is the proc used to update all the action buttons. Properly defined in /mob/living/ /mob/proc/update_action_buttons() @@ -202,16 +142,6 @@ var/coord_row_offset = AB_NORTH_OFFSET return "LEFT[coord_col]:[coord_col_offset],TOP[coord_row]:[coord_row_offset]" -/datum/hud/proc/SetButtonCoords(var/obj/screen/button,var/number) - var/row = round((number-1)/AB_MAX_COLUMNS) - var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1 - var/x_offset = 32*(col-1) + AB_WEST_OFFSET + 2*col - var/y_offset = -32*(row+1) + AB_NORTH_OFFSET - - var/matrix/M = matrix() - M.Translate(x_offset,y_offset) - button.transform = M - //Presets for item actions /datum/action/item_action check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_ALIVE|AB_CHECK_INSIDE @@ -232,9 +162,6 @@ if(istype(O)) O.refresh_action_button() -/datum/action/item_action/organ/augment - button_icon = 'icons/obj/augment.dmi' - #undef AB_WEST_OFFSET #undef AB_NORTH_OFFSET #undef AB_MAX_COLUMNS \ No newline at end of file diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm deleted file mode 100644 index e9dadac4db1d..000000000000 --- a/code/_onclick/hud/ai.dm +++ /dev/null @@ -1,172 +0,0 @@ -/mob/living/silicon/ai - hud_type = /datum/hud/ai - -/datum/hud/ai/FinalizeInstantiation() - - if(!isAI(mymob)) - return - - var/mob/living/silicon/A = mymob - - adding = list() - adding += new /obj/screen/ai_button(null, - ui_ai_core, - "AI Core", - "ai_core", - /mob/living/silicon/ai/proc/core - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_announcement, - "AI Announcement", - "announcement", - /mob/living/silicon/ai/proc/ai_announcement - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_cam_track, - "Track With Camera", - "track", - /mob/living/silicon/ai/proc/ai_camera_track, - list(/mob/living/silicon/ai/proc/trackable_mobs = (AI_BUTTON_PROC_BELONGS_TO_CALLER|AI_BUTTON_INPUT_REQUIRES_SELECTION)) - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_cam_light, - "Toggle Camera Lights", - "camera_light", - /mob/living/silicon/ai/proc/toggle_camera_light - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_cam_change_network, - "Jump to Network", - "camera", - /mob/living/silicon/ai/proc/ai_network_change, - list(/mob/living/silicon/ai/proc/get_camera_network_list = (AI_BUTTON_PROC_BELONGS_TO_CALLER|AI_BUTTON_INPUT_REQUIRES_SELECTION)) - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_sensor, - "Set Sensor Mode", - "ai_sensor", - /mob/living/silicon/ai/proc/sensor_mode - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_crew_manifest, - "Show Crew Manifest", - "manifest", - /mob/living/silicon/ai/proc/run_program, - null, - list("crewmanifest") - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_take_image, - "Toggle Camera Mode", - "take_picture", - /mob/living/silicon/ai/proc/ai_take_image - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_view_images, - "View Images", - "view_images", - /mob/living/silicon/ai/proc/ai_view_images - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_state_laws, - "State Laws", - "state_laws", - /mob/living/silicon/ai/proc/ai_checklaws - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_call_shuttle, - "Call Shuttle", - "call_shuttle", - /mob/living/silicon/ai/proc/ai_call_shuttle - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_up, - "Move Upwards", - "ai_up", - /mob/verb/up - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_down, - "Move Downwards", - "ai_down", - /mob/verb/down - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_color, - "Change Floor Color", - "ai_floor", - /mob/living/silicon/ai/proc/change_floor - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_holo_change, - "Change Hologram", - "ai_holo_change", - /mob/living/silicon/ai/proc/ai_hologram_change - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_crew_mon, - "Crew Monitor", - "crew_monitor", - /mob/living/silicon/ai/proc/run_program, - null, - list("sensormonitor") - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_power_override, - "Toggle Power Override", - "ai_p_override", - /mob/living/silicon/ai/proc/ai_power_override - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_shutdown, - "Shutdown", - "ai_shutdown", - /mob/living/silicon/ai/proc/ai_shutdown - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_holo_mov, - "Toggle Hologram Movement", - "ai_holo_mov", - /mob/living/silicon/ai/proc/toggle_hologram_movement - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_core_icon, - "Pick Icon", - "ai_core_pick", - /mob/living/silicon/ai/proc/pick_icon - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_status, - "Pick Status", - "ai_status", - /mob/living/silicon/ai/proc/ai_statuschange - ) - - adding += new /obj/screen/ai_button(null, - ui_ai_crew_rec, - "Inbuilt Computer", - "ai_crew_rec", - /mob/living/silicon/proc/access_computer - ) - A.client.screen = list() - A.client.screen.Add(adding) \ No newline at end of file diff --git a/code/_onclick/hud/ai_screen_objects.dm b/code/_onclick/hud/ai_screen_objects.dm deleted file mode 100644 index cbbff7d5d962..000000000000 --- a/code/_onclick/hud/ai_screen_objects.dm +++ /dev/null @@ -1,56 +0,0 @@ -/obj/screen/ai_button - var/mob/living/silicon/ai/ai_verb - var/list/input_procs - var/list/input_args - icon = 'icons/mob/screen_ai.dmi' - var/list/template_icon = list(null, "template") - var/image/template_undelay - -/obj/screen/ai_button/Click() - if(!isAI(usr)) - return TRUE - var/mob/living/silicon/ai/A = usr - if(!(ai_verb in A.verbs)) - return TRUE - - var/input_arguments = list() - for(var/input_proc in input_procs) - var/input_flags = input_procs[input_proc] - var/input_arg - if(input_flags & AI_BUTTON_PROC_BELONGS_TO_CALLER) // Does the called proc belong to the AI, or not? - input_arg = call(A, input_proc)() - else - input_arg= call(input_proc)() - - if(input_flags & AI_BUTTON_INPUT_REQUIRES_SELECTION) - input_arg = input("Make a selection.", "Make a selection.") as null|anything in input_arg - if(!input_arg) - return // We assume a null-input means the user cancelled - - if(!(ai_verb in A.verbs) || A.incapacitated()) - return - - input_arguments += input_arg - - if(length(input_args)) - input_arguments |= input_args - - call(A, ai_verb)(arglist(input_arguments)) - return TRUE - -/obj/screen/ai_button/Initialize(maploading, screen_loc, name, icon_state, ai_verb, list/input_procs = null, list/input_args = null) - . = ..() - if(!LAZYLEN(template_icon)) - template_icon = list(icon) - - src.name = name - src.icon_state = icon_state - src.screen_loc = screen_loc - src.ai_verb = ai_verb - if(input_procs) - src.input_procs = input_procs.Copy() - if(input_args) - src.input_args = input_args.Copy() - - template_undelay = image(template_icon[1], template_icon[2]) - underlays += template_undelay \ No newline at end of file diff --git a/code/_onclick/hud/animal.dm b/code/_onclick/hud/animal.dm deleted file mode 100644 index 07c6495c4a85..000000000000 --- a/code/_onclick/hud/animal.dm +++ /dev/null @@ -1,8 +0,0 @@ - -/mob/living/simple_animal - hud_type = /datum/hud/animal - -/datum/hud/animal/FinalizeInstantiation(var/ui_style='icons/mob/screen/white.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255) - mymob.client.screen = list() - action_intent = new /obj/screen/intent() - mymob.client.screen |= action_intent \ No newline at end of file diff --git a/code/_onclick/hud/deity.dm b/code/_onclick/hud/deity.dm deleted file mode 100644 index df18fb9ff534..000000000000 --- a/code/_onclick/hud/deity.dm +++ /dev/null @@ -1,57 +0,0 @@ -/mob/living/deity - hud_type = /datum/hud/deity - -/datum/hud/deity/FinalizeInstantiation() - src.adding = list() - src.other = list() - - var/obj/screen/intent/deity/D = new() - - src.adding += D - action_intent = D - - mymob.client.screen = list() - mymob.client.screen += src.adding - D.sync_to_mob(mymob) - - -/obj/screen/intent/deity - var/list/desc_screens = list() - screen_loc = "RIGHT-5:122,BOTTOM:8" - -/obj/screen/intent/deity/Initialize() - . = ..() - overlays += image('icons/mob/screen_phenomena.dmi', icon_state = "hud", pixel_x = -138, pixel_y = -1) - -/obj/screen/intent/deity/proc/sync_to_mob(var/mob) - var/mob/living/deity/D = mob - for(var/i in 1 to D.control_types.len) - var/obj/screen/S = new() - S.SetName(null) //Don't want them to be able to actually right click it. - S.mouse_opacity = 0 - S.icon_state = "blank" - desc_screens[D.control_types[i]] = S - S.maptext_width = 128 - S.screen_loc = screen_loc - //This sets it up right. Trust me. - S.maptext_y = 33/2*i - i*i/2 - 10 - D.client.screen += S - S.maptext_x = -125 - - update_text() - -/obj/screen/intent/deity/proc/update_text() - if(!istype(usr, /mob/living/deity)) - return - var/mob/living/deity/D = usr - for(var/i in D.control_types) - var/obj/screen/S = desc_screens[i] - var/datum/phenomena/P = D.intent_phenomenas[intent][i] - if(P) - S.maptext = "[P.name]" - else - S.maptext = null - -/obj/screen/intent/deity/Click(var/location, var/control, var/params) - ..() - update_text() \ No newline at end of file diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index 3abb1928e522..cc1728a65fe2 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -16,23 +16,25 @@ return null if(!screen) - screen = new type() + screen = new type(null, src) screen.icon_state = "[initial(screen.icon_state)][severity]" screen.severity = severity screens[category] = screen screen.transform = null - if(screen && client) - if(screen.screen_loc != ui_entire_screen) - if(max(client.last_view_x_dim, client.last_view_y_dim) > 7) - var/matrix/M = matrix() - M.Scale(ceil(client.last_view_x_dim/7),ceil(client.last_view_y_dim/7)) - screen.transform = M - if(stat != DEAD || screen.allstate) - client.screen += screen + if(screen && client && (stat != DEAD || screen.allstate)) + client.screen += screen return screen +/mob/proc/show_screen(var/screen, var/animated) + set waitfor = FALSE + animate(screen, alpha = 0, time = animated) + sleep(animated) + if(screen && client) + client.screen -= screen + qdel(screen) + /mob/proc/clear_fullscreen(category, animated = 10) var/obj/screen/fullscreen/screen = screens[category] if(!screen) @@ -41,12 +43,7 @@ screens -= category if(animated) - spawn(0) - animate(screen, alpha = 0, time = animated) - sleep(animated) - if(client) - client.screen -= screen - qdel(screen) + show_screen(screen, animated) else if(client) client.screen -= screen @@ -73,103 +70,3 @@ screen.transform = M client.screen |= screen -/obj/screen/fullscreen - icon = 'icons/mob/screen_full.dmi' - icon_state = "default" - screen_loc = "CENTER-7,CENTER-7" - plane = FULLSCREEN_PLANE - mouse_opacity = 0 - var/severity = 0 - var/allstate = 0 //shows if it should show up for dead people too - -/obj/screen/fullscreen/Destroy() - severity = 0 - return ..() - -/obj/screen/fullscreen/brute - icon_state = "brutedamageoverlay" - layer = DAMAGE_LAYER - -/obj/screen/fullscreen/oxy - icon_state = "oxydamageoverlay" - layer = DAMAGE_LAYER - -/obj/screen/fullscreen/crit - icon_state = "passage" - layer = CRIT_LAYER - -/obj/screen/fullscreen/blind - icon_state = "blackimageoverlay" - layer = BLIND_LAYER - -/obj/screen/fullscreen/blackout - icon = 'icons/mob/screen1.dmi' - icon_state = "black" - screen_loc = ui_entire_screen - layer = BLIND_LAYER - -/obj/screen/fullscreen/impaired - icon_state = "impairedoverlay" - layer = IMPAIRED_LAYER - -/obj/screen/fullscreen/blurry - icon = 'icons/mob/screen1.dmi' - screen_loc = ui_entire_screen - icon_state = "blurry" - alpha = 100 - -/obj/screen/fullscreen/flash - icon = 'icons/mob/screen1.dmi' - screen_loc = ui_entire_screen - icon_state = "flash" - -/obj/screen/fullscreen/flash/noise - icon_state = "noise" - -/obj/screen/fullscreen/high - icon = 'icons/mob/screen1.dmi' - screen_loc = ui_entire_screen - icon_state = "druggy" - alpha = 127 - blend_mode = BLEND_MULTIPLY - -/obj/screen/fullscreen/noise - icon = 'icons/effects/static.dmi' - icon_state = "1 light" - screen_loc = ui_entire_screen - layer = FULLSCREEN_LAYER - alpha = 127 - -/obj/screen/fullscreen/fadeout - icon = 'icons/mob/screen1.dmi' - icon_state = "black" - screen_loc = ui_entire_screen - layer = FULLSCREEN_LAYER - alpha = 0 - allstate = 1 - -/obj/screen/fullscreen/fadeout/Initialize() - . = ..() - animate(src, alpha = 255, time = 10) - -/obj/screen/fullscreen/scanline - icon = 'icons/effects/static.dmi' - icon_state = "scanlines" - screen_loc = ui_entire_screen - alpha = 50 - layer = FULLSCREEN_LAYER - -/obj/screen/fullscreen/fishbed - icon_state = "fishbed" - allstate = 1 - -/obj/screen/fullscreen/pain - icon_state = "brutedamageoverlay6" - alpha = 0 - -/obj/screen/fullscreen/blueprints - icon = 'icons/effects/blueprints.dmi' - icon_state = "base" - screen_loc = ui_entire_screen - alpha = 100 - layer = FULLSCREEN_LAYER \ No newline at end of file diff --git a/code/_onclick/hud/global_hud.dm b/code/_onclick/hud/global_hud.dm index 1dff53af7403..9073d9aab6d2 100644 --- a/code/_onclick/hud/global_hud.dm +++ b/code/_onclick/hud/global_hud.dm @@ -3,32 +3,29 @@ Uses the same visual objects for all players. */ -GLOBAL_DATUM_INIT(global_hud, /datum/global_hud, new()) +var/global/datum/global_hud/hud +/proc/get_global_hud() + if(!global.hud) + global.hud = new + return global.hud /datum/global_hud - var/obj/screen/nvg - var/obj/screen/thermal - var/obj/screen/meson - var/obj/screen/science + var/obj/screen/global_hud/nvg + var/obj/screen/global_hud/thermal + var/obj/screen/global_hud/meson + var/obj/screen/global_hud/science + var/obj/screen/global_holomap/holomap // makes custom colored overlay, can also generate scanline /datum/global_hud/proc/setup_overlay(icon_state, color) - var/obj/screen/screen = new /obj/screen() - screen.screen_loc = ui_entire_screen - screen.icon = 'icons/effects/hud_full.dmi' + var/obj/screen/global_hud/screen = new(null) screen.icon_state = icon_state - screen.plane = FULLSCREEN_PLANE - screen.layer = FULLSCREEN_LAYER - screen.mouse_opacity = 0 - screen.alpha = 125 - - screen.blend_mode = BLEND_MULTIPLY screen.color = color - return screen /datum/global_hud/New() - nvg = setup_overlay("scanline", "#06ff00") + nvg = setup_overlay("scanline", "#06ff00") thermal = setup_overlay("scanline", "#ff0000") - meson = setup_overlay("scanline", "#9fd800") + meson = setup_overlay("scanline", "#9fd800") science = setup_overlay("scanline", "#d600d6") + holomap = new(null) diff --git a/code/_onclick/hud/gun_mode.dm b/code/_onclick/hud/gun_mode.dm deleted file mode 100644 index ab5cecbff9c2..000000000000 --- a/code/_onclick/hud/gun_mode.dm +++ /dev/null @@ -1,66 +0,0 @@ -/obj/screen/gun - name = "gun" - icon = 'icons/mob/screen1.dmi' - master = null - dir = SOUTH - -/obj/screen/gun/Click(location, control, params) - if(!usr) - return - return 1 - -/obj/screen/gun/move - name = "Allow Movement" - icon_state = "no_walk1" - screen_loc = ui_gun2 - -/obj/screen/gun/move/Click(location, control, params) - if(..()) - var/mob/living/user = usr - if(istype(user)) - if(!user.aiming) user.aiming = new(user) - user.aiming.toggle_permission(TARGET_CAN_MOVE) - return 1 - return 0 - -/obj/screen/gun/item - name = "Allow Item Use" - icon_state = "no_item1" - screen_loc = ui_gun1 - -/obj/screen/gun/item/Click(location, control, params) - if(..()) - var/mob/living/user = usr - if(istype(user)) - if(!user.aiming) user.aiming = new(user) - user.aiming.toggle_permission(TARGET_CAN_CLICK) - return 1 - return 0 - -/obj/screen/gun/mode - name = "Toggle Gun Mode" - icon_state = "gun0" - screen_loc = ui_gun_select - -/obj/screen/gun/mode/Click(location, control, params) - if(..()) - var/mob/living/user = usr - if(istype(user)) - if(!user.aiming) user.aiming = new(user) - user.aiming.toggle_active() - return 1 - return 0 - -/obj/screen/gun/radio - name = "Disallow Radio Use" - icon_state = "no_radio1" - screen_loc = ui_gun4 - -/obj/screen/gun/radio/Click(location, control, params) - if(..()) - var/mob/living/user = usr - if(istype(user)) - if(!user.aiming) user.aiming = new(user) - user.aiming.toggle_permission(TARGET_CAN_RADIO) - return 1 - return 0 diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm deleted file mode 100644 index f65086139d56..000000000000 --- a/code/_onclick/hud/hud.dm +++ /dev/null @@ -1,276 +0,0 @@ -/* - The hud datum - Used to show and hide huds for all the different mob types, - including inventories and item quick actions. -*/ - -/mob - var/hud_type = null - var/datum/hud/hud_used = null - -/mob/proc/InitializeHud() - if(hud_used) - qdel(hud_used) - if(hud_type) - hud_used = new hud_type(src) - else - hud_used = new /datum/hud - -/datum/hud - var/mob/mymob - - var/hud_shown = 1 //Used for the HUD toggle (F12) - var/inventory_shown = 1 //the inventory - var/show_intent_icons = 0 - var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) - - var/obj/screen/lingchemdisplay - var/obj/screen/r_hand_hud_object - var/obj/screen/l_hand_hud_object - var/obj/screen/action_intent - var/obj/screen/move_intent - var/obj/screen/stamina/stamina_bar - - var/list/adding - var/list/other - var/list/obj/screen/hotkeybuttons - - var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle - var/action_buttons_hidden = 0 - -/datum/hud/New(mob/owner) - mymob = owner - instantiate() - ..() - -/datum/hud/Destroy() - . = ..() - stamina_bar = null - lingchemdisplay = null - r_hand_hud_object = null - l_hand_hud_object = null - action_intent = null - move_intent = null - adding = null - other = null - hotkeybuttons = null - mymob = null - -/datum/hud/proc/update_stamina() - if(mymob && stamina_bar) - stamina_bar.invisibility = INVISIBILITY_MAXIMUM - var/stamina = mymob.get_stamina() - if(stamina < 100) - stamina_bar.invisibility = 0 - stamina_bar.icon_state = "prog_bar_[Floor(stamina/5)*5][(stamina >= 5) && (stamina <= 25) ? "_fail" : null]" - -/datum/hud/proc/hidden_inventory_update() - if(!mymob) return - if(ishuman(mymob)) - var/mob/living/carbon/human/H = mymob - for(var/gear_slot in H.species.hud.gear) - var/list/hud_data = H.species.hud.gear[gear_slot] - if(inventory_shown && hud_shown) - switch(hud_data["slot"]) - if(slot_head) - if(H.head) H.head.screen_loc = hud_data["loc"] - if(slot_shoes) - if(H.shoes) H.shoes.screen_loc = hud_data["loc"] - if(slot_l_ear) - if(H.l_ear) H.l_ear.screen_loc = hud_data["loc"] - if(slot_r_ear) - if(H.r_ear) H.r_ear.screen_loc = hud_data["loc"] - if(slot_gloves) - if(H.gloves) H.gloves.screen_loc = hud_data["loc"] - if(slot_glasses) - if(H.glasses) H.glasses.screen_loc = hud_data["loc"] - if(slot_w_uniform) - if(H.w_uniform) H.w_uniform.screen_loc = hud_data["loc"] - if(slot_wear_suit) - if(H.wear_suit) H.wear_suit.screen_loc = hud_data["loc"] - if(slot_wear_mask) - if(H.wear_mask) H.wear_mask.screen_loc = hud_data["loc"] - else - switch(hud_data["slot"]) - if(slot_head) - if(H.head) H.head.screen_loc = null - if(slot_shoes) - if(H.shoes) H.shoes.screen_loc = null - if(slot_l_ear) - if(H.l_ear) H.l_ear.screen_loc = null - if(slot_r_ear) - if(H.r_ear) H.r_ear.screen_loc = null - if(slot_gloves) - if(H.gloves) H.gloves.screen_loc = null - if(slot_glasses) - if(H.glasses) H.glasses.screen_loc = null - if(slot_w_uniform) - if(H.w_uniform) H.w_uniform.screen_loc = null - if(slot_wear_suit) - if(H.wear_suit) H.wear_suit.screen_loc = null - if(slot_wear_mask) - if(H.wear_mask) H.wear_mask.screen_loc = null - - -/datum/hud/proc/persistant_inventory_update() - if(!mymob) - return - - if(ishuman(mymob)) - var/mob/living/carbon/human/H = mymob - for(var/gear_slot in H.species.hud.gear) - var/list/hud_data = H.species.hud.gear[gear_slot] - if(hud_shown) - switch(hud_data["slot"]) - if(slot_s_store) - if(H.s_store) H.s_store.screen_loc = hud_data["loc"] - if(slot_wear_id) - if(H.wear_id) H.wear_id.screen_loc = hud_data["loc"] - if(slot_belt) - if(H.belt) H.belt.screen_loc = hud_data["loc"] - if(slot_back) - if(H.back) H.back.screen_loc = hud_data["loc"] - if(slot_l_store) - if(H.l_store) H.l_store.screen_loc = hud_data["loc"] - if(slot_r_store) - if(H.r_store) H.r_store.screen_loc = hud_data["loc"] - else - switch(hud_data["slot"]) - if(slot_s_store) - if(H.s_store) H.s_store.screen_loc = null - if(slot_wear_id) - if(H.wear_id) H.wear_id.screen_loc = null - if(slot_belt) - if(H.belt) H.belt.screen_loc = null - if(slot_back) - if(H.back) H.back.screen_loc = null - if(slot_l_store) - if(H.l_store) H.l_store.screen_loc = null - if(slot_r_store) - if(H.r_store) H.r_store.screen_loc = null - - -/datum/hud/proc/instantiate() - if(!ismob(mymob)) return 0 - if(!mymob.client) return 0 - var/ui_style = ui_style2icon(mymob.client.prefs.UI_style) - var/ui_color = mymob.client.prefs.UI_style_color - var/ui_alpha = mymob.client.prefs.UI_style_alpha - - - FinalizeInstantiation(ui_style, ui_color, ui_alpha) - -/datum/hud/proc/FinalizeInstantiation(var/ui_style, var/ui_color, var/ui_alpha) - return - -//Triggered when F12 is pressed (Unless someone changed something in the DMF) -/mob/verb/button_pressed_F12(var/full = 0 as null) - set name = "F12" - set hidden = 1 - - if(!hud_used) - to_chat(usr, "This mob type does not use a HUD.") - return - - if(!ishuman(src)) - to_chat(usr, "Inventory hiding is currently only supported for human mobs, sorry.") - return - - if(!client) return - if(client.view != world.view) - return - if(hud_used.hud_shown) - hud_used.hud_shown = 0 - if(src.hud_used.adding) - src.client.screen -= src.hud_used.adding - if(src.hud_used.other) - src.client.screen -= src.hud_used.other - if(src.hud_used.hotkeybuttons) - src.client.screen -= src.hud_used.hotkeybuttons - - //Due to some poor coding some things need special treatment: - //These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay - if(!full) - src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible - src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible - src.client.screen += src.hud_used.action_intent //we want the intent swticher visible - src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. - else - src.client.screen -= src.healths - src.client.screen -= src.internals - src.client.screen -= src.gun_setting_icon - - //These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone. - src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason. - - else - hud_used.hud_shown = 1 - if(src.hud_used.adding) - src.client.screen += src.hud_used.adding - if(src.hud_used.other && src.hud_used.inventory_shown) - src.client.screen += src.hud_used.other - if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden) - src.client.screen += src.hud_used.hotkeybuttons - if(src.healths) - src.client.screen |= src.healths - if(src.internals) - src.client.screen |= src.internals - if(src.gun_setting_icon) - src.client.screen |= src.gun_setting_icon - - src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position - src.client.screen += src.zone_sel //This one is a special snowflake - - hud_used.hidden_inventory_update() - hud_used.persistant_inventory_update() - update_action_buttons() - -//Similar to button_pressed_F12() but keeps zone_sel, gun_setting_icon, and healths. -/mob/proc/toggle_zoom_hud() - if(!hud_used) - return - if(!ishuman(src)) - return - if(!client) - return - if(client.view != world.view) - return - - if(hud_used.hud_shown) - hud_used.hud_shown = 0 - if(src.hud_used.adding) - src.client.screen -= src.hud_used.adding - if(src.hud_used.other) - src.client.screen -= src.hud_used.other - if(src.hud_used.hotkeybuttons) - src.client.screen -= src.hud_used.hotkeybuttons - src.client.screen -= src.internals - src.client.screen += src.hud_used.action_intent //we want the intent swticher visible - else - hud_used.hud_shown = 1 - if(src.hud_used.adding) - src.client.screen += src.hud_used.adding - if(src.hud_used.other && src.hud_used.inventory_shown) - src.client.screen += src.hud_used.other - if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden) - src.client.screen += src.hud_used.hotkeybuttons - if(src.internals) - src.client.screen |= src.internals - src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position - - hud_used.hidden_inventory_update() - hud_used.persistant_inventory_update() - update_action_buttons() - -/mob/proc/add_click_catcher() - client.screen |= GLOB.click_catchers - -/mob/new_player/add_click_catcher() - return - -/obj/screen/stamina - name = "stamina" - icon = 'icons/effects/progressbar.dmi' - icon_state = "prog_bar_100" - invisibility = INVISIBILITY_MAXIMUM - screen_loc = ui_stamina diff --git a/code/_onclick/hud/hud_elements/_hud_element.dm b/code/_onclick/hud/hud_elements/_hud_element.dm new file mode 100644 index 000000000000..6fce5a0eba1b --- /dev/null +++ b/code/_onclick/hud/hud_elements/_hud_element.dm @@ -0,0 +1,24 @@ +/decl/hud_element + abstract_type = /decl/hud_element + /// /obj/screen path to create + var/elem_type + /// Index value for /datum/hud; defaults to src.type if null + var/elem_reference_type + /// Adds element to hidable list (inventory) + var/elem_is_hidable = FALSE + /// Adds element to hotkey list + var/elem_is_hotkey = FALSE + /// Adds element to aux list (hidden by F12) + var/elem_is_auxilliary = TRUE + /// Updates element icon in mob Life() proc + var/elem_updates_in_life = FALSE + +/decl/hud_element/validate() + . = ..() + if(!ispath(elem_type, /obj/screen)) + . += "invalid elem_type ([elem_type || null]))" + +/decl/hud_element/Initialize() + . = ..() + if(isnull(elem_reference_type)) + elem_reference_type = type diff --git a/code/_onclick/hud/hud_elements/hud_auxilliary.dm b/code/_onclick/hud/hud_elements/hud_auxilliary.dm new file mode 100644 index 000000000000..bcf8503f5a4b --- /dev/null +++ b/code/_onclick/hud/hud_elements/hud_auxilliary.dm @@ -0,0 +1,45 @@ +/decl/hud_element/movement + elem_type = /obj/screen/movement + +/decl/hud_element/internals + elem_type = /obj/screen/internals + +/decl/hud_element/zone_selector + elem_type = /obj/screen/zone_selector + +/decl/hud_element/upward + elem_type = /obj/screen/look_upward + +/decl/hud_element/throw_toggle + elem_type = /obj/screen/throw_toggle + +/decl/hud_element/maneuver + elem_type = /obj/screen/maneuver + +/decl/hud_element/drop + elem_type = /obj/screen/drop + +/decl/hud_element/resist + elem_type = /obj/screen/resist + +/decl/hud_element/attack + elem_type = /obj/screen/default_attack_selector + +/decl/hud_element/modifiers + elem_type = /obj/screen/mob_modifiers + +/decl/hud_element/stamina + elem_type = /obj/screen/stamina + elem_updates_in_life = TRUE + +/decl/hud_element/charge + elem_type = /obj/screen/need/cell_charge + elem_updates_in_life = TRUE + +/decl/hud_element/nutrition + elem_type = /obj/screen/need/nutrition + elem_updates_in_life = TRUE + +/decl/hud_element/hydration + elem_type = /obj/screen/need/hydration + elem_updates_in_life = TRUE diff --git a/code/_onclick/hud/hud_elements/hud_health.dm b/code/_onclick/hud/hud_elements/hud_health.dm new file mode 100644 index 000000000000..955c4d8d576c --- /dev/null +++ b/code/_onclick/hud/hud_elements/hud_health.dm @@ -0,0 +1,7 @@ +/decl/hud_element/health + elem_type = /obj/screen/health + elem_updates_in_life = TRUE + +/decl/hud_element/health/organs + elem_type = /obj/screen/health/organs + elem_reference_type = /decl/hud_element/health diff --git a/code/_onclick/hud/hud_elements/hud_permanent.dm b/code/_onclick/hud/hud_elements/hud_permanent.dm new file mode 100644 index 000000000000..518a698775ca --- /dev/null +++ b/code/_onclick/hud/hud_elements/hud_permanent.dm @@ -0,0 +1,3 @@ +/decl/hud_element/intent + elem_type = /obj/screen/intent + elem_is_auxilliary = FALSE diff --git a/code/_onclick/hud/hud_elements/hud_robot.dm b/code/_onclick/hud/hud_elements/hud_robot.dm new file mode 100644 index 000000000000..9c37069baa3a --- /dev/null +++ b/code/_onclick/hud/hud_elements/hud_robot.dm @@ -0,0 +1,58 @@ +/datum/hud/robot + gun_mode_toggle_type = /obj/screen/gun/mode + omit_hud_elements = list( + /decl/hud_element/health, + /decl/hud_element/charge, + /decl/hud_element/bodytemp, + /decl/hud_element/oxygen, + /decl/hud_element/toxins, + /decl/hud_element/pressure, + /decl/hud_element/nutrition, + /decl/hud_element/hydration, + /decl/hud_element/maneuver, + /decl/hud_element/movement, + /decl/hud_element/resist, + /decl/hud_element/drop, + /decl/hud_element/throw_toggle, + /decl/hud_element/internals, + ) + additional_hud_elements = list( + /decl/hud_element/health/robot, + /decl/hud_element/charge/robot, + /decl/hud_element/oxygen/robot, + /decl/hud_element/module_selection, + /decl/hud_element/robot_inventory, + /decl/hud_element/robot_radio, + /decl/hud_element/robot_store, + /decl/hud_element/robot_drop_grab + ) + +/decl/hud_element/oxygen/robot + elem_reference_type = /decl/hud_element/oxygen + elem_type = /obj/screen/warning/oxygen/robot + +/decl/hud_element/health/robot + elem_reference_type = /decl/hud_element/health + elem_type = /obj/screen/health/robot + +/decl/hud_element/charge/robot + elem_reference_type = /decl/hud_element/charge + elem_type = /obj/screen/need/cell_charge/robot + +/decl/hud_element/robot_inventory + elem_type = /obj/screen/robot/inventory + elem_is_auxilliary = FALSE + +/decl/hud_element/module_selection + elem_type = /obj/screen/robot/module + elem_is_auxilliary = FALSE + +/decl/hud_element/robot_radio + elem_type = /obj/screen/robot/radio + +/decl/hud_element/robot_store + elem_type = /obj/screen/robot/store + +/decl/hud_element/robot_drop_grab + elem_type = /obj/screen/robot/drop_grab + elem_updates_in_life = TRUE diff --git a/code/_onclick/hud/hud_elements/hud_stubs.dm b/code/_onclick/hud/hud_elements/hud_stubs.dm new file mode 100644 index 000000000000..261ae0d74e8b --- /dev/null +++ b/code/_onclick/hud/hud_elements/hud_stubs.dm @@ -0,0 +1,9 @@ +// Should not actually be used; defined for icon checks and HUD styles. +/decl/hud_element/inventory + elem_type = /obj/screen/inventory +/decl/hud_element/hands + elem_type = /obj/screen/inventory/hand +/decl/hud_element/crit + elem_type = /obj/screen +/decl/hud_element/gun_mode + elem_type = /obj/screen/gun diff --git a/code/_onclick/hud/hud_elements/hud_warnings.dm b/code/_onclick/hud/hud_elements/hud_warnings.dm new file mode 100644 index 000000000000..091aefa24c44 --- /dev/null +++ b/code/_onclick/hud/hud_elements/hud_warnings.dm @@ -0,0 +1,19 @@ +/decl/hud_element/fire + elem_type = /obj/screen/warning/fire + elem_updates_in_life = TRUE + +/decl/hud_element/oxygen + elem_type = /obj/screen/warning/oxygen + elem_updates_in_life = TRUE + +/decl/hud_element/toxins + elem_type = /obj/screen/warning/toxin + elem_updates_in_life = TRUE + +/decl/hud_element/bodytemp + elem_type = /obj/screen/warning/bodytemp + elem_updates_in_life = TRUE + +/decl/hud_element/pressure + elem_type = /obj/screen/warning/pressure + elem_updates_in_life = TRUE diff --git a/code/_onclick/hud/hud_types/_hud.dm b/code/_onclick/hud/hud_types/_hud.dm new file mode 100644 index 000000000000..5a64f04f09a9 --- /dev/null +++ b/code/_onclick/hud/hud_types/_hud.dm @@ -0,0 +1,654 @@ +/* + The hud datum + Used to show and hide huds for all the different mob types, + including inventories and item quick actions. +*/ + +/mob + var/datum/hud/hud_used + +/mob/proc/get_hud_element(hud_key) + if(!istype(hud_used)) + return FALSE + return hud_used.get_element(hud_key) + +/mob/proc/refresh_hud_element(hud_key) + if(!istype(hud_used)) + return FALSE + return hud_used.refresh_element(hud_key) + +/mob/proc/initialize_hud() + if(istype(hud_used)) + QDEL_NULL(hud_used) + hud_used = initial(hud_used) + if(ispath(hud_used)) + hud_used = new hud_used(src) + if(istype(hud_used)) + hud_used.refresh_hud_icons() + +/datum/hud + /// A reference to our owning mob. + VAR_PRIVATE/weakref/owner + /// Used for the HUD toggle (F12) + VAR_PRIVATE/hud_shown = TRUE + // Used for showing or hiding the equipment buttons on the left. + VAR_PRIVATE/inventory_shown = TRUE + /// This is to hide the buttons that can be used via hotkeys. (hud_elements_hotkeys list of buttons) + VAR_PRIVATE/hotkey_ui_hidden = FALSE + /// Defines an assumed default /decl/ui_style for elements to use. + VAR_PRIVATE/default_ui_style = DEFAULT_UI_STYLE + + /// Assoc list of current /decl/hud_element to values. Cannot be private, used by macro. + var/list/alerts + + /// List of elements related to hand slots. + VAR_PRIVATE/list/obj/screen/hud_elements_hands + /// List of elements related to swapping hand slots. + VAR_PRIVATE/list/obj/screen/hud_elements_swap + /// List of elements related to hotkeys. + VAR_PRIVATE/list/obj/screen/hud_elements_hotkeys + /// List of elements that are hidden by the inventory toggle. + VAR_PRIVATE/list/obj/screen/hud_elements_hidable + /// List of elements that are not hidden by anything. + VAR_PRIVATE/list/obj/screen/hud_elements_unhidable + /// List of elements that are hidden by F12. + VAR_PRIVATE/list/obj/screen/hud_elements_auxilliary + /// List of elements that update icon in Life() + VAR_PRIVATE/list/obj/screen/hud_elements_update_in_life + /// Combined list of the above, used for qdel. + VAR_PRIVATE/list/obj/screen/all_hud_elements + + /// List of /decl/hud_element types to use to populate this HUD on creation. + VAR_PROTECTED/list/hud_elements_to_create = list( + /decl/hud_element/movement, + /decl/hud_element/stamina, + /decl/hud_element/health, + /decl/hud_element/internals, + /decl/hud_element/charge, + /decl/hud_element/zone_selector, + /decl/hud_element/nutrition, + /decl/hud_element/hydration, + /decl/hud_element/upward, + /decl/hud_element/throw_toggle, + /decl/hud_element/maneuver, + /decl/hud_element/drop, + /decl/hud_element/resist, + /decl/hud_element/intent, + /decl/hud_element/fire, + /decl/hud_element/oxygen, + /decl/hud_element/toxins, + /decl/hud_element/bodytemp, + /decl/hud_element/pressure, + /decl/hud_element/modifiers + ) + /// /decl/hud_element types to be inserted into hud_elements_to_create during init. + VAR_PROTECTED/list/additional_hud_elements + /// /decl/hud_element types to be removed from hud_elements_to_create during init. + VAR_PROTECTED/list/omit_hud_elements + /// Elem type to created object dict; used to retrieve/update elements. + VAR_PRIVATE/list/hud_elem_decl_to_object = list() + + // TODO: move these onto the HUD datum properly. + var/action_buttons_hidden = FALSE + var/obj/screen/action_button/hide_toggle/hide_actions_toggle + + var/const/HAND_UI_PER_ROW = 4 + var/const/HAND_UI_INITIAL_Y_OFFSET = 21 + + // TODO: declify these. + VAR_PROTECTED/gun_mode_toggle_type + VAR_PRIVATE/obj/screen/gun/mode/gun_mode_toggle + VAR_PRIVATE/obj/screen/gun/move/gun_move_toggle + VAR_PRIVATE/obj/screen/gun/item/gun_item_use_toggle + VAR_PRIVATE/obj/screen/gun/radio/gun_radio_use_toggle + +/datum/hud/New(mob/_owner) + if(istype(_owner)) + owner = weakref(_owner) + instantiate(_owner) + ..() + +/datum/hud/Destroy() + . = ..() + + LAZYCLEARLIST(hud_elements_hands) + LAZYCLEARLIST(hud_elements_swap) + LAZYCLEARLIST(hud_elements_hotkeys) + LAZYCLEARLIST(hud_elements_hidable) + LAZYCLEARLIST(hud_elements_unhidable) + LAZYCLEARLIST(hud_elements_auxilliary) + LAZYCLEARLIST(hud_elem_decl_to_object) + QDEL_NULL_LIST(all_hud_elements) + + var/mob/mymob = owner?.resolve() + if(istype(mymob)) + if(mymob.hud_used == src) + mymob.hud_used = null + QDEL_NULL(owner) + +/datum/hud/proc/is_hud_shown() + return hud_shown + +/datum/hud/proc/get_element(hud_key) + return hud_elem_decl_to_object[hud_key] + +/datum/hud/proc/refresh_element(hud_key) + var/obj/screen/elem = get_element(hud_key) + return elem?.update_icon() || FALSE + +/datum/hud/proc/refresh_hud_icons() + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + for(var/obj/screen/elem in mymob.client.screen) + elem.queue_icon_update() + +/datum/hud/proc/is_inventory_shown() + return inventory_shown + +/datum/hud/proc/hide_inventory() + inventory_shown = FALSE + if(LAZYLEN(hud_elements_hidable)) + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + mymob.client.screen -= hud_elements_hidable + hidden_inventory_update() + persistent_inventory_update() + +/datum/hud/proc/show_inventory() + inventory_shown = TRUE + if(LAZYLEN(hud_elements_hidable)) + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + mymob.client.screen += hud_elements_hidable + hidden_inventory_update() + persistent_inventory_update() + +/datum/hud/proc/hidden_inventory_update() + var/mob/mymob = owner?.resolve() + var/decl/species/species = istype(mymob) && mymob.get_species() + if(istype(species?.species_hud)) + refresh_inventory_slots(species.species_hud.hidden_slots, (inventory_shown && hud_shown)) + +/datum/hud/proc/persistent_inventory_update() + var/mob/mymob = owner?.resolve() + var/decl/species/species = istype(mymob) && mymob.get_species() + if(istype(species?.species_hud)) + refresh_inventory_slots(species.species_hud.persistent_slots, hud_shown) + +/datum/hud/proc/refresh_inventory_slots(var/list/checking_slots, var/show_hud) + + var/mob/mymob = owner?.resolve() + if(!istype(mymob)) + return FALSE + + for(var/slot in checking_slots) + + var/datum/inventory_slot/inv_slot = mymob.get_inventory_slot_datum(slot) + if(!istype(inv_slot)) + continue + + // Check if we're even wearing anything in that slot. + var/obj/item/gear = inv_slot.get_equipped_item() + if(!istype(gear)) + continue + + // We're not showing anything, hide it. + gear.reconsider_client_screen_presence(mymob?.client, slot) + if(!show_hud) + inv_slot.hide_slot() + else + inv_slot.show_slot() + + return TRUE + +/datum/hud/proc/instantiate(mob/_owner) + if(ismob(_owner) && _owner.client) + finalize_instantiation(_owner) + refresh_hud_icons() + return TRUE + return FALSE + +/datum/hud/proc/handle_life_hud_update() + + var/mob/mymob = owner?.resolve() + if(!istype(mymob)) + return FALSE + + if(mymob.buckled || mymob.restrained()) + mymob.add_mob_modifier(/decl/mob_modifier/restrained, source = mymob) + else + mymob.remove_mob_modifier(/decl/mob_modifier/restrained, source = mymob) + + if(mymob.current_posture?.prone) + mymob.add_mob_modifier(/decl/mob_modifier/prone, source = mymob) + else + mymob.remove_mob_modifier(/decl/mob_modifier/prone, source = mymob) + + for(var/obj/screen/elem as anything in hud_elements_update_in_life) + elem.update_icon() + return TRUE + +/datum/hud/proc/finalize_instantiation(mob/_owner) + + SHOULD_CALL_PARENT(TRUE) + + var/decl/ui_style/ui_style = get_ui_style_data() + var/ui_color = get_ui_color() + var/ui_alpha = get_ui_alpha() + + LAZYINITLIST(hud_elements_to_create) + if(length(additional_hud_elements)) + hud_elements_to_create |= additional_hud_elements + if(length(omit_hud_elements)) + hud_elements_to_create -= omit_hud_elements + UNSETEMPTY(hud_elements_to_create) + + for(var/hud_elem_type in hud_elements_to_create) + var/decl/hud_element/hud_element = GET_DECL(hud_elem_type) + create_and_register_element(hud_element, ui_style, ui_color, ui_alpha) + + //Handle the gun settings buttons + if(!gun_mode_toggle && gun_mode_toggle_type) + gun_mode_toggle = new gun_mode_toggle_type(null, _owner, ui_style, ui_color, ui_alpha, HUD_FIRE_INTENT) + LAZYADD(hud_elements_auxilliary, gun_mode_toggle) + gun_item_use_toggle = new(null, _owner, ui_style, ui_color, ui_alpha, HUD_FIRE_INTENT) + gun_move_toggle = new(null, _owner, ui_style, ui_color, ui_alpha, HUD_FIRE_INTENT) + gun_radio_use_toggle = new(null, _owner, ui_style, ui_color, ui_alpha, HUD_FIRE_INTENT) + + build_inventory_ui() + build_hands_ui() + + LAZYINITLIST(all_hud_elements) + if(LAZYLEN(hud_elements_hands)) + all_hud_elements |= hud_elements_hands + if(LAZYLEN(hud_elements_swap)) + all_hud_elements |= hud_elements_swap + if(LAZYLEN(hud_elements_hotkeys)) + all_hud_elements |= hud_elements_hotkeys + if(LAZYLEN(hud_elements_hidable)) + all_hud_elements |= hud_elements_hidable + if(LAZYLEN(hud_elements_unhidable)) + all_hud_elements |= hud_elements_unhidable + if(LAZYLEN(hud_elements_auxilliary)) + all_hud_elements |= hud_elements_auxilliary + UNSETEMPTY(all_hud_elements) + + if(_owner.client) + _owner.client.screen = list() + if(LAZYLEN(all_hud_elements)) + _owner.client.screen |= all_hud_elements + + hide_inventory() + +/datum/hud/proc/get_ui_style_data() + RETURN_TYPE(/decl/ui_style) + var/mob/mymob = owner?.resolve() + . = (istype(mymob) && GET_DECL(mymob.client?.prefs?.UI_style)) || GET_DECL(default_ui_style) + if(!.) + var/list/available_styles = get_ui_styles() + if(length(available_styles)) + . = available_styles[1] + +/datum/hud/proc/get_ui_color() + var/decl/ui_style/ui_style = get_ui_style_data() + if(!ui_style?.use_ui_color) + return COLOR_WHITE + var/mob/mymob = owner?.resolve() + return (istype(mymob) && mymob.client?.prefs?.UI_style_color) || COLOR_WHITE + +/datum/hud/proc/get_ui_alpha() + var/mob/mymob = owner?.resolve() + return (istype(mymob) && mymob.client?.prefs?.UI_style_alpha) || 255 + +/datum/hud/proc/rebuild_hands() + + var/mob/mymob = owner?.resolve() + if(!istype(mymob)) + return FALSE + + var/decl/ui_style/ui_style = get_ui_style_data() + var/ui_color = get_ui_color() + var/ui_alpha = get_ui_alpha() + + // Build held item boxes for missing slots. + var/list/held_slots = mymob.get_held_item_slots() + + // Sort our slots for display. + var/list/gripper_datums = list() + for(var/hand_tag in held_slots) + gripper_datums += mymob.get_inventory_slot_datum(hand_tag) + gripper_datums = sortTim(gripper_datums, /proc/cmp_gripper_asc) + + for(var/datum/inventory_slot/gripper/inv_slot in gripper_datums) + + // Re-order the held slot list so it aligns with the display order. + var/hand_tag = inv_slot.slot_id + held_slots -= hand_tag + held_slots += hand_tag + + var/obj/screen/inventory/inv_box + for(var/obj/screen/inventory/existing_box in hud_elements_hands) + if(existing_box.slot_id == hand_tag) + inv_box = existing_box + break + + if(!inv_box) + inv_box = new /obj/screen/inventory/hand(null, mymob, ui_style, ui_color, ui_alpha, HUD_HANDS) + else + inv_box.set_ui_style(ui_style, HUD_HANDS) + inv_box.color = ui_color + inv_box.alpha = ui_alpha + + LAZYDISTINCTADD(hud_elements_hands, inv_box) + + inv_box.SetName(hand_tag) + inv_box.slot_id = hand_tag + inv_box.update_icon() + + // Clear held item boxes with no held slot. + for(var/obj/screen/inventory/inv_box in hud_elements_hands) + if(!(inv_box.slot_id in held_slots)) + if(mymob.client) + mymob.client.screen -= inv_box + LAZYREMOVE(hud_elements_hands, inv_box) + qdel(inv_box) + + // Rebuild offsets for the hand elements. + var/hand_y_offset = HAND_UI_INITIAL_Y_OFFSET + var/list/elements = hud_elements_hands?.Copy() + while(length(elements)) + var/copy_index = min(length(elements), HAND_UI_PER_ROW)+1 + var/list/sublist = elements.Copy(1, copy_index) + elements.Cut(1, copy_index) + var/hand_x_offset = (world.icon_size/2) * (1 - length(sublist)) + for(var/obj/screen/inventory/inv_box in sublist) + inv_box.screen_loc = "CENTER:[hand_x_offset],BOTTOM:[hand_y_offset]" + hand_x_offset += world.icon_size + hand_y_offset += world.icon_size + + if(mymob.client && islist(hud_elements_hands) && length(hud_elements_hands)) + mymob.client.screen |= hud_elements_hands + + // Make sure all held items are on the screen and set to the correct screen loc. + var/datum/inventory_slot/inv_slot + for(var/obj/inv_elem in hud_elements_hands) + inv_slot = mymob.get_inventory_slot_datum(inv_elem.name) + if(inv_slot) + inv_slot.ui_loc = inv_elem.screen_loc + var/obj/item/held = inv_slot.get_equipped_item() + if(held) + held.screen_loc = inv_slot.ui_loc + if(mymob.client) + mymob.client.screen |= held // just to make sure it's visible post-login + + if(length(hud_elements_swap)) + var/hand_x_offset = -(world.icon_size/2) + for(var/i = 1 to length(hud_elements_swap)) + var/obj/swap_elem = hud_elements_swap[i] + swap_elem.screen_loc = "CENTER:[hand_x_offset],BOTTOM:[hand_y_offset]" + if(i > 1) // first two elems share a slot + hand_x_offset += world.icon_size + if(mymob.client) + mymob.client.screen |= swap_elem + + refresh_element(HUD_STAMINA) + update_hand_elements() + + return TRUE + +/datum/hud/proc/build_inventory_ui() + + var/mob/mymob = owner?.resolve() + if(!istype(mymob)) + return FALSE + + var/decl/ui_style/ui_style = get_ui_style_data() + var/ui_color = get_ui_color() + var/ui_alpha = get_ui_alpha() + + var/has_hidden_gear = FALSE + + // Draw the various inventory equipment slots. + var/obj/screen/inventory/inv_box + var/list/held_slots = mymob.get_held_item_slots() + var/list/inventory_slots = mymob.get_inventory_slots() + for(var/gear_slot in inventory_slots) + + if(gear_slot in held_slots) + continue + + inv_box = new /obj/screen/inventory(null, mymob, ui_style, ui_color, ui_alpha, HUD_INVENTORY) + + var/datum/inventory_slot/inv_slot = inventory_slots[gear_slot] + inv_box.SetName(inv_slot.slot_name) + inv_box.slot_id = inv_slot.slot_id + inv_box.icon_state = inv_slot.slot_state + inv_box.screen_loc = inv_slot.ui_loc + + if(inv_slot.slot_dir) + inv_box.set_dir(inv_slot.slot_dir) + + if(inv_slot.can_be_hidden) + LAZYDISTINCTADD(hud_elements_hidable, inv_box) + has_hidden_gear = TRUE + else + hud_elements_auxilliary += inv_box + + if(has_hidden_gear) + hud_elements_auxilliary += new /obj/screen/toggle(null, mymob, ui_style, ui_color, ui_alpha, HUD_INVENTORY) + + return TRUE + +/datum/hud/proc/build_hands_ui() + + var/mob/mymob = owner?.resolve() + if(!istype(mymob)) + return FALSE + + var/list/held_slots = mymob.get_held_item_slots() + if(length(held_slots) <= 0) + return FALSE + + var/decl/ui_style/ui_style = get_ui_style_data() + var/ui_color = get_ui_color() + var/ui_alpha = get_ui_alpha() + + // Swap hand and quick equip screen elems. + var/obj/screen/using = new /obj/screen/equip(null, mymob, ui_style, ui_color, ui_alpha, HUD_HANDS) + LAZYADD(hud_elements_swap, using) + if(length(held_slots) > 1) + + using = new /obj/screen/inventory/swaphand(null, mymob, ui_style, ui_color, ui_alpha, HUD_HANDS) + LAZYADD(hud_elements_swap, using) + using = new /obj/screen/inventory/swaphand/right(null, mymob, ui_style, ui_color, ui_alpha, HUD_HANDS) + LAZYADD(hud_elements_swap, using) + + // Actual hand elems. + rebuild_hands() + return TRUE + +/datum/hud/proc/toggle_show_inventory() + if(inventory_shown) + hide_inventory() + else + show_inventory() + return TRUE + +/datum/hud/proc/toggle_action_buttons_hidden() + action_buttons_hidden = !action_buttons_hidden + return action_buttons_hidden + +/datum/hud/proc/toggle_minimize(var/full) + hud_shown = !hud_shown + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + if(hud_shown) + if(LAZYLEN(hud_elements_auxilliary)) + mymob.client.screen |= hud_elements_auxilliary + if(LAZYLEN(hud_elements_hidable) && inventory_shown) + mymob.client.screen |= hud_elements_hidable + if(LAZYLEN(hud_elements_hotkeys) && !hotkey_ui_hidden) + mymob.client.screen |= hud_elements_hotkeys + else + if(hud_elements_auxilliary) + mymob.client.screen -= hud_elements_auxilliary + if(hud_elements_hidable) + mymob.client.screen -= hud_elements_hidable + if(hud_elements_hotkeys) + mymob.client.screen -= hud_elements_hotkeys + if(!full) + if(LAZYLEN(hud_elements_hands)) + mymob.client.screen += hud_elements_hands // we want the hands to be visible + if(LAZYLEN(hud_elements_swap)) + mymob.client.screen += hud_elements_swap // we want the hands swap thingy to be visible + + hidden_inventory_update() + persistent_inventory_update() + return TRUE + +/datum/hud/proc/toggle_zoom_hud() + hud_shown = !hud_shown + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + if(hud_shown) + if(LAZYLEN(hud_elements_auxilliary)) + mymob.client.screen += hud_elements_auxilliary + if(LAZYLEN(hud_elements_hidable) && inventory_shown) + mymob.client.screen += hud_elements_hidable + if(LAZYLEN(hud_elements_hotkeys) && !hotkey_ui_hidden) + mymob.client.screen += hud_elements_hotkeys + else + if(LAZYLEN(hud_elements_auxilliary)) + mymob.client.screen -= hud_elements_auxilliary + if(LAZYLEN(hud_elements_hidable)) + mymob.client.screen -= hud_elements_hidable + if(LAZYLEN(hud_elements_hotkeys)) + mymob.client.screen -= hud_elements_hotkeys + + hidden_inventory_update() + persistent_inventory_update() + +/datum/hud/proc/toggle_hotkeys() + hotkey_ui_hidden = !hotkey_ui_hidden + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + if(hotkey_ui_hidden) + mymob.client.screen -= hud_elements_hotkeys + else + mymob.client.screen += hud_elements_hotkeys + +/mob/verb/toggle_hotkey_verbs() + set category = "OOC" + set name = "Toggle hotkey buttons" + set desc = "This disables or enables the user interface buttons which can be used with hotkeys." + if(!istype(hud_used)) + return + hud_used.toggle_hotkeys() + +/mob/verb/minimize_hud(full = FALSE as null) + set name = "Minimize Hud" + set hidden = TRUE + if(isnull(hud_used)) + to_chat(usr, SPAN_WARNING("This mob type does not use a HUD.")) + return + if(!client || !istype(hud_used)) + return + hud_used.toggle_minimize(full) + update_action_buttons() + +//Similar to minimize_hud() but keeps zone_selector, gun_setting_itoggle, and health_warning. +/mob/proc/toggle_zoom_hud() + if(!istype(hud_used)) + return + if(!ishuman(src)) + return + if(!client) + return + if(client.view != world.view) + return + + hud_used.toggle_zoom_hud() + update_action_buttons() + +/client/proc/reset_click_catchers() + + var/xmin = -(round(last_view_x_dim*0.5)) + var/xmax = last_view_x_dim - abs(xmin) + var/ymin = -(round(last_view_y_dim*0.5)) + var/ymax = last_view_y_dim - abs(ymin) + + var/list/click_catchers = get_click_catchers() + for(var/obj/screen/click_catcher/catcher in click_catchers) + if(catcher.x_offset <= xmin || catcher.x_offset >= xmax || catcher.y_offset <= ymin || catcher.y_offset >= ymax) + screen -= catcher + else + screen |= catcher + +/mob/proc/add_click_catcher() + client.reset_click_catchers() + +/mob/new_player/add_click_catcher() + return + +//These are called by the on-screen buttons, adjusting what the victim can and cannot do. +/datum/hud/proc/add_gun_icons() + // This can runtime if someone manages to throw a gun out of their hand before the proc is called. + if(!gun_item_use_toggle) + return TRUE + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + mymob.client.screen |= gun_item_use_toggle + mymob.client.screen |= gun_move_toggle + mymob.client.screen |= gun_radio_use_toggle + +/datum/hud/proc/remove_gun_icons() + var/mob/mymob = owner?.resolve() + if(istype(mymob) && mymob.client) + mymob.client.screen -= gun_item_use_toggle + mymob.client.screen -= gun_move_toggle + mymob.client.screen -= gun_radio_use_toggle + +/datum/hud/proc/update_hand_elements() + for(var/atom/hand as anything in hud_elements_hands) + hand.update_icon() + + +/datum/hud/proc/update_gun_mode_icons(target_permissions) + if(gun_move_toggle) + if(!(target_permissions & TARGET_CAN_MOVE)) + gun_move_toggle.SetName("Allow Movement") + else + gun_move_toggle.SetName("Disallow Movement") + gun_move_toggle.update_icon() + if(gun_item_use_toggle) + if(!(target_permissions & TARGET_CAN_CLICK)) + gun_item_use_toggle.SetName("Allow Item Use") + else + gun_item_use_toggle.SetName("Disallow Item Use") + gun_item_use_toggle.update_icon() + if(gun_radio_use_toggle) + if(!(target_permissions & TARGET_CAN_RADIO)) + gun_radio_use_toggle.SetName("Allow Radio Use") + else + gun_radio_use_toggle.SetName("Disallow Radio Use") + gun_radio_use_toggle.update_icon() + +/datum/hud/proc/create_and_register_element(decl/hud_element/ui_elem, decl/ui_style/ui_style, ui_color, ui_alpha) + + var/mob/mymob = owner?.resolve() + if(!istype(mymob) || !istype(ui_elem) || !ui_elem.elem_type) + return FALSE + + var/obj/screen/elem = new ui_elem.elem_type(null, mymob, ui_style, ui_color, ui_alpha, ui_elem.elem_reference_type) + if(ui_elem.elem_is_hotkey) + LAZYDISTINCTADD(hud_elements_hotkeys, elem) + else if(ui_elem.elem_is_auxilliary) + LAZYDISTINCTADD(hud_elements_auxilliary, elem) + else if(ui_elem.elem_is_hidable) + LAZYDISTINCTADD(hud_elements_hidable, elem) + else + LAZYDISTINCTADD(hud_elements_unhidable, elem) + if(ui_elem.elem_updates_in_life) + LAZYDISTINCTADD(hud_elements_update_in_life, elem) + hud_elem_decl_to_object[ui_elem.elem_reference_type] = elem + return elem diff --git a/code/_onclick/hud/hud_types/ai.dm b/code/_onclick/hud/hud_types/ai.dm new file mode 100644 index 000000000000..e6f0c0394aab --- /dev/null +++ b/code/_onclick/hud/hud_types/ai.dm @@ -0,0 +1,25 @@ +/mob/living/silicon/ai + hud_used = /datum/hud/ai + +/datum/hud/ai + omit_hud_elements = list( + /decl/hud_element/intent, + /decl/hud_element/health, + /decl/hud_element/charge, + /decl/hud_element/bodytemp, + /decl/hud_element/oxygen, + /decl/hud_element/toxins, + /decl/hud_element/pressure, + /decl/hud_element/nutrition, + /decl/hud_element/hydration, + /decl/hud_element/maneuver, + /decl/hud_element/movement, + /decl/hud_element/resist, + /decl/hud_element/drop, + /decl/hud_element/throw_toggle, + /decl/hud_element/internals + ) + +/datum/hud/ai/New() + additional_hud_elements = subtypesof(/decl/hud_element/ai) + ..() diff --git a/code/_onclick/hud/hud_types/ai_hud.dm b/code/_onclick/hud/hud_types/ai_hud.dm new file mode 100644 index 000000000000..555c40a5d6f5 --- /dev/null +++ b/code/_onclick/hud/hud_types/ai_hud.dm @@ -0,0 +1,145 @@ +/decl/hud_element/ai + abstract_type = /decl/hud_element/ai + elem_type = /obj/screen/ai_button + var/screen_loc + var/name + var/icon_state + var/proc_path + var/list/input_procs + var/list/input_args + +/decl/hud_element/ai/core + screen_loc = ui_ai_core + name = "AI Core" + icon_state = "ai_core" + proc_path = /mob/living/silicon/ai/proc/core + +/decl/hud_element/ai/announcement + screen_loc = ui_ai_announcement + name = "AI Announcement" + icon_state = "announcement" + proc_path = /mob/living/silicon/ai/proc/ai_announcement + +/decl/hud_element/ai/cam_track + screen_loc = ui_ai_cam_track + name = "Track With Camera" + icon_state = "track" + proc_path = /mob/living/silicon/ai/proc/ai_camera_track + input_procs = list(/mob/living/silicon/ai/proc/trackable_mobs = (AI_BUTTON_PROC_BELONGS_TO_CALLER|AI_BUTTON_INPUT_REQUIRES_SELECTION)) + +/decl/hud_element/ai/cam_light + screen_loc = ui_ai_cam_light + name = "Toggle Camera Lights" + icon_state = "camera_light" + proc_path = /mob/living/silicon/ai/proc/toggle_camera_light + +/decl/hud_element/ai/cam_change_channel + screen_loc = ui_ai_cam_change_channel + name = "Jump to Camera Channel" + icon_state = "camera" + proc_path = /mob/living/silicon/ai/proc/ai_channel_change + input_procs = list(/mob/living/silicon/ai/proc/get_camera_channel_list = (AI_BUTTON_PROC_BELONGS_TO_CALLER|AI_BUTTON_INPUT_REQUIRES_SELECTION)) + +/decl/hud_element/ai/sensor + screen_loc = ui_ai_sensor + name = "Set Sensor Mode" + icon_state = "ai_sensor" + proc_path = /mob/living/silicon/ai/proc/sensor_mode + +/decl/hud_element/ai/manifest + screen_loc = ui_ai_crew_manifest + name = "Show Crew Manifest" + icon_state = "manifest" + proc_path = /mob/living/silicon/ai/proc/run_program + input_args = list("crewmanifest") + +/decl/hud_element/ai/take_image + screen_loc = ui_ai_take_image + name = "Toggle Camera Mode" + icon_state = "take_picture" + proc_path = /mob/living/silicon/ai/proc/ai_take_image + +/decl/hud_element/ai/view_images + screen_loc = ui_ai_view_images + name = "View Images" + icon_state = "view_images" + proc_path = /mob/living/silicon/ai/proc/ai_view_images + +/decl/hud_element/ai/laws + screen_loc = ui_ai_state_laws + name = "State Laws" + icon_state = "state_laws" + proc_path = /mob/living/silicon/ai/proc/ai_checklaws + +/decl/hud_element/ai/call_shuttle + screen_loc = ui_ai_call_shuttle + name = "Call Shuttle" + icon_state = "call_shuttle" + proc_path = /mob/living/silicon/ai/proc/ai_call_shuttle + +/decl/hud_element/ai/up + screen_loc = ui_ai_up + name = "Move Upwards" + icon_state = "ai_up" + proc_path = /mob/verb/up + +/decl/hud_element/ai/down + screen_loc = ui_ai_down + name = "Move Downwards" + icon_state = "ai_down" + proc_path = /mob/verb/down + +/decl/hud_element/ai/color + screen_loc = ui_ai_color + name = "Change Floor Color" + icon_state = "ai_floor" + proc_path = /mob/living/silicon/ai/proc/change_floor + +/decl/hud_element/ai/hologram + screen_loc = ui_ai_holo_change + name = "Change Hologram" + icon_state = "ai_holo_change" + proc_path = /mob/living/silicon/ai/proc/ai_hologram_change + +/decl/hud_element/ai/crew_monitor + screen_loc = ui_ai_crew_mon + name = "Crew Monitor" + icon_state = "crew_monitor" + proc_path = /mob/living/silicon/ai/proc/run_program + input_args = list("sensormonitor") + +/decl/hud_element/ai/power_override + screen_loc = ui_ai_power_override + name = "Toggle Power Override" + icon_state = "ai_p_override" + proc_path = /mob/living/silicon/ai/proc/ai_power_override + +/decl/hud_element/ai/shutdown + screen_loc = ui_ai_shutdown + name = "Shutdown" + icon_state = "ai_shutdown" + proc_path = /mob/living/silicon/ai/proc/ai_shutdown + +/decl/hud_element/ai/move_hologram + screen_loc = ui_ai_holo_mov + name = "Toggle Hologram Movement" + icon_state = "ai_holo_mov" + proc_path = /mob/living/silicon/ai/proc/toggle_hologram_movement + +/decl/hud_element/ai/core_icon + screen_loc = ui_ai_core_icon + name = "Pick Icon" + icon_state = "ai_core_pick" + proc_path = /mob/living/silicon/ai/proc/pick_icon + +/decl/hud_element/ai/status + screen_loc = ui_ai_status + name = "Pick Status" + icon_state = "ai_status" + proc_path = /mob/living/silicon/ai/proc/ai_statuschange + +/decl/hud_element/ai/inbuilt_comp + screen_loc = ui_ai_crew_rec + name = "Inbuilt Computer" + icon_state = "ai_crew_rec" + proc_path = /mob/living/silicon/proc/access_computer diff --git a/code/_onclick/hud/hud_types/animal.dm b/code/_onclick/hud/hud_types/animal.dm new file mode 100644 index 000000000000..84c9d7736b79 --- /dev/null +++ b/code/_onclick/hud/hud_types/animal.dm @@ -0,0 +1,11 @@ +/datum/hud/animal + hud_elements_to_create = list( + /decl/hud_element/movement, + /decl/hud_element/stamina, + /decl/hud_element/health, + /decl/hud_element/zone_selector, + /decl/hud_element/upward, + /decl/hud_element/maneuver, + /decl/hud_element/resist, + /decl/hud_element/intent + ) diff --git a/code/_onclick/hud/hud_types/human.dm b/code/_onclick/hud/hud_types/human.dm new file mode 100644 index 000000000000..9f08721970ef --- /dev/null +++ b/code/_onclick/hud/hud_types/human.dm @@ -0,0 +1,10 @@ +/mob/living/human + hud_used = /datum/hud/human + +/datum/hud/human + gun_mode_toggle_type = /obj/screen/gun/mode + omit_hud_elements = list(/decl/hud_element/health) + additional_hud_elements = list( + /decl/hud_element/health/organs, + /decl/hud_element/attack + ) diff --git a/code/_onclick/hud/hud_types/other_mobs.dm b/code/_onclick/hud/hud_types/other_mobs.dm new file mode 100644 index 000000000000..96c117e4d465 --- /dev/null +++ b/code/_onclick/hud/hud_types/other_mobs.dm @@ -0,0 +1,61 @@ +/datum/hud/animal/construct + omit_hud_elements = list(/decl/hud_element/health) + additional_hud_elements = list(/decl/hud_element/health/construct) + +/decl/hud_element/health/construct + elem_reference_type = /decl/hud_element/health + elem_type = /obj/screen/health/construct + +/datum/hud/animal/construct/get_ui_style_data() + return GET_DECL(/decl/ui_style/construct) + +/datum/hud/animal/construct/juggernaut/get_ui_style_data() + return GET_DECL(/decl/ui_style/construct/juggernaut) + +/datum/hud/animal/construct/harvester/get_ui_style_data() + return GET_DECL(/decl/ui_style/construct/harvester) + +/datum/hud/animal/construct/wraith/get_ui_style_data() + return GET_DECL(/decl/ui_style/construct/wraith) + +/datum/hud/animal/construct/artificer/get_ui_style_data() + return GET_DECL(/decl/ui_style/construct/artificer) + +/datum/hud/animal/construct/get_ui_color() + return COLOR_WHITE + +/datum/hud/animal/construct/get_ui_alpha() + return 255 + +/decl/ui_style/construct + name = "Construct" + restricted = TRUE + override_icons = list( + (HUD_FIRE) = 'icons/mob/screen/styles/constructs/status_fire.dmi', + (HUD_ZONE_SELECT) = 'icons/mob/screen/styles/constructs/zone_selector.dmi' + ) + uid = "ui_style_construct" +/decl/ui_style/construct/juggernaut + name = "Juggernaut" + uid = "ui_style_construct_juggernaut" +/decl/ui_style/construct/juggernaut/Initialize() + override_icons[HUD_HEALTH] = 'icons/mob/screen/styles/constructs/juggernaut/health.dmi' + return ..() +/decl/ui_style/construct/harvester + name = "Harvester" + uid = "ui_style_construct_harvester" +/decl/ui_style/construct/harvester/Initialize() + override_icons[HUD_HEALTH] = 'icons/mob/screen/styles/constructs/harvester/health.dmi' + return ..() +/decl/ui_style/construct/wraith + name = "Wraith" + uid = "ui_style_construct_wraith" +/decl/ui_style/construct/wraith/Initialize() + override_icons[HUD_HEALTH] = 'icons/mob/screen/styles/constructs/wraith/health.dmi' + return ..() +/decl/ui_style/construct/artificer + name = "Artificer" + uid = "ui_style_construct_artificer" +/decl/ui_style/construct/artificer/Initialize() + override_icons[HUD_HEALTH] = 'icons/mob/screen/styles/constructs/artificer/health.dmi' + return ..() diff --git a/code/_onclick/hud/hud_types/pai.dm b/code/_onclick/hud/hud_types/pai.dm new file mode 100644 index 000000000000..4521b70b5823 --- /dev/null +++ b/code/_onclick/hud/hud_types/pai.dm @@ -0,0 +1,6 @@ +/datum/hud/pai + hud_elements_to_create = list(/decl/hud_element/health/robot) + +/datum/hud/pai/New() + hud_elements_to_create += subtypesof(/decl/hud_element/pai) + ..() diff --git a/code/_onclick/hud/hud_types/robot.dm b/code/_onclick/hud/hud_types/robot.dm new file mode 100644 index 000000000000..a84112549ad1 --- /dev/null +++ b/code/_onclick/hud/hud_types/robot.dm @@ -0,0 +1,11 @@ +/mob/living/silicon/robot + hud_used = /datum/hud/robot + +/datum/hud/robot/get_ui_style_data() + return GET_DECL(/decl/ui_style/robot) + +/datum/hud/robot/get_ui_color() + return COLOR_WHITE + +/datum/hud/robot/get_ui_alpha() + return 255 diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm deleted file mode 100644 index 142181081234..000000000000 --- a/code/_onclick/hud/human.dm +++ /dev/null @@ -1,386 +0,0 @@ -/mob/living/carbon/human - hud_type = /datum/hud/human - -/datum/hud/human/FinalizeInstantiation(var/ui_style='icons/mob/screen/white.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255) - var/mob/living/carbon/human/target = mymob - var/datum/hud_data/hud_data - if(!istype(target)) - hud_data = new() - else - hud_data = target.species.hud - - if(hud_data.icon) - ui_style = hud_data.icon - - adding = list() - other = list() - src.hotkeybuttons = list() //These can be disabled for hotkey usersx - - var/list/hud_elements = list() - var/obj/screen/using - var/obj/screen/inventory/inv_box - - stamina_bar = new - adding += stamina_bar - - // Draw the various inventory equipment slots. - var/has_hidden_gear - for(var/gear_slot in hud_data.gear) - - inv_box = new /obj/screen/inventory() - inv_box.icon = ui_style - inv_box.color = ui_color - inv_box.alpha = ui_alpha - - var/list/slot_data = hud_data.gear[gear_slot] - inv_box.SetName(gear_slot) - inv_box.screen_loc = slot_data["loc"] - inv_box.slot_id = slot_data["slot"] - inv_box.icon_state = slot_data["state"] - - if(slot_data["dir"]) - inv_box.set_dir(slot_data["dir"]) - - if(slot_data["toggle"]) - src.other += inv_box - has_hidden_gear = 1 - else - src.adding += inv_box - - if(has_hidden_gear) - using = new /obj/screen() - using.SetName("toggle") - using.icon = ui_style - using.icon_state = "other" - using.screen_loc = ui_inventory - using.color = ui_color - using.alpha = ui_alpha - src.adding += using - - // Draw the attack intent dialogue. - if(hud_data.has_a_intent) - - using = new /obj/screen/intent() - src.adding += using - action_intent = using - - hud_elements |= using - - if(hud_data.has_m_intent) - using = new /obj/screen/movement() - using.SetName("movement method") - using.icon = ui_style - using.icon_state = mymob.move_intent.hud_icon_state - using.screen_loc = ui_movi - using.color = ui_color - using.alpha = ui_alpha - src.adding += using - move_intent = using - - if(hud_data.has_drop) - using = new /obj/screen() - using.SetName("drop") - using.icon = ui_style - using.icon_state = "act_drop" - using.screen_loc = ui_drop_throw - using.color = ui_color - using.alpha = ui_alpha - src.hotkeybuttons += using - - if(hud_data.has_hands) - - using = new /obj/screen() - using.SetName("equip") - using.icon = ui_style - using.icon_state = "act_equip" - using.screen_loc = ui_equip - using.color = ui_color - using.alpha = ui_alpha - src.adding += using - - inv_box = new /obj/screen/inventory() - inv_box.SetName("r_hand") - inv_box.icon = ui_style - inv_box.icon_state = "r_hand_inactive" - if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use - inv_box.icon_state = "r_hand_active" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - inv_box.color = ui_color - inv_box.alpha = ui_alpha - - src.r_hand_hud_object = inv_box - src.adding += inv_box - - inv_box = new /obj/screen/inventory() - inv_box.SetName("l_hand") - inv_box.icon = ui_style - inv_box.icon_state = "l_hand_inactive" - if(mymob && mymob.hand) //This being 1 means the left hand is in use - inv_box.icon_state = "l_hand_active" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.l_hand_hud_object = inv_box - src.adding += inv_box - - using = new /obj/screen/inventory() - using.SetName("hand") - using.icon = ui_style - using.icon_state = "hand1" - using.screen_loc = ui_swaphand1 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using - - using = new /obj/screen/inventory() - using.SetName("hand") - using.icon = ui_style - using.icon_state = "hand2" - using.screen_loc = ui_swaphand2 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using - - if(hud_data.has_resist) - using = new /obj/screen() - using.SetName("resist") - using.icon = ui_style - using.icon_state = "act_resist" - using.screen_loc = ui_pull_resist - using.color = ui_color - using.alpha = ui_alpha - src.hotkeybuttons += using - - if(hud_data.has_throw) - mymob.throw_icon = new /obj/screen() - mymob.throw_icon.icon = ui_style - mymob.throw_icon.icon_state = "act_throw_off" - mymob.throw_icon.SetName("throw") - mymob.throw_icon.screen_loc = ui_drop_throw - mymob.throw_icon.color = ui_color - mymob.throw_icon.alpha = ui_alpha - src.hotkeybuttons += mymob.throw_icon - hud_elements |= mymob.throw_icon - - if(hud_data.has_internals) - mymob.internals = new /obj/screen() - mymob.internals.icon = ui_style - mymob.internals.icon_state = "internal0" - mymob.internals.SetName("internal") - mymob.internals.screen_loc = ui_internal - hud_elements |= mymob.internals - - if(hud_data.has_warnings) - mymob.healths = new /obj/screen() - mymob.healths.icon = ui_style - mymob.healths.icon_state = "health0" - mymob.healths.SetName("health") - mymob.healths.screen_loc = ui_health - hud_elements |= mymob.healths - - mymob.oxygen = new /obj/screen/oxygen() - mymob.oxygen.icon = 'icons/mob/status_indicators.dmi' - mymob.oxygen.icon_state = "oxy0" - mymob.oxygen.SetName("oxygen") - mymob.oxygen.screen_loc = ui_temp - hud_elements |= mymob.oxygen - - mymob.toxin = new /obj/screen/toxins() - mymob.toxin.icon = 'icons/mob/status_indicators.dmi' - mymob.toxin.icon_state = "tox0" - mymob.toxin.SetName("toxin") - mymob.toxin.screen_loc = ui_temp - hud_elements |= mymob.toxin - - mymob.fire = new /obj/screen() - mymob.fire.icon = ui_style - mymob.fire.icon_state = "fire0" - mymob.fire.SetName("fire") - mymob.fire.screen_loc = ui_fire - hud_elements |= mymob.fire - - if(hud_data.has_pressure) - mymob.pressure = new /obj/screen/pressure() - mymob.pressure.icon = 'icons/mob/status_indicators.dmi' - mymob.pressure.icon_state = "pressure0" - mymob.pressure.SetName("pressure") - mymob.pressure.screen_loc = ui_temp - hud_elements |= mymob.pressure - - if(hud_data.has_bodytemp) - mymob.bodytemp = new /obj/screen/bodytemp() - mymob.bodytemp.icon = 'icons/mob/status_indicators.dmi' - mymob.bodytemp.icon_state = "temp1" - mymob.bodytemp.SetName("body temperature") - mymob.bodytemp.screen_loc = ui_temp - hud_elements |= mymob.bodytemp - - if(target.isSynthetic()) - target.cells = new /obj/screen() - target.cells.icon = 'icons/mob/screen1_robot.dmi' - target.cells.icon_state = "charge-empty" - target.cells.SetName("cell") - target.cells.screen_loc = ui_nutrition - hud_elements |= target.cells - - else if(hud_data.has_nutrition) - mymob.nutrition_icon = new /obj/screen/food() - mymob.nutrition_icon.icon = 'icons/mob/status_hunger.dmi' - mymob.nutrition_icon.pixel_w = 8 - mymob.nutrition_icon.icon_state = "nutrition1" - mymob.nutrition_icon.SetName("nutrition") - mymob.nutrition_icon.screen_loc = ui_nutrition_small - hud_elements |= mymob.nutrition_icon - - mymob.hydration_icon = new /obj/screen/drink() - mymob.hydration_icon.icon = 'icons/mob/status_hunger.dmi' - mymob.hydration_icon.icon_state = "hydration1" - mymob.hydration_icon.SetName("hydration") - mymob.hydration_icon.screen_loc = ui_nutrition_small - hud_elements |= mymob.hydration_icon - - if(hud_data.has_up_hint) - mymob.up_hint = new /obj/screen() - mymob.up_hint.icon = ui_style - mymob.up_hint.icon_state = "uphint0" - mymob.up_hint.SetName("up hint") - mymob.up_hint.screen_loc = ui_up_hint - hud_elements |= mymob.up_hint - - mymob.pain = new /obj/screen/fullscreen/pain( null ) - hud_elements |= mymob.pain - - mymob.zone_sel = new /obj/screen/zone_sel( null ) - mymob.zone_sel.icon = ui_style - mymob.zone_sel.color = ui_color - mymob.zone_sel.alpha = ui_alpha - mymob.zone_sel.overlays.Cut() - mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") - hud_elements |= mymob.zone_sel - - //Handle the gun settings buttons - mymob.gun_setting_icon = new /obj/screen/gun/mode(null) - mymob.gun_setting_icon.icon = ui_style - mymob.gun_setting_icon.color = ui_color - mymob.gun_setting_icon.alpha = ui_alpha - hud_elements |= mymob.gun_setting_icon - - mymob.item_use_icon = new /obj/screen/gun/item(null) - mymob.item_use_icon.icon = ui_style - mymob.item_use_icon.color = ui_color - mymob.item_use_icon.alpha = ui_alpha - - mymob.gun_move_icon = new /obj/screen/gun/move(null) - mymob.gun_move_icon.icon = ui_style - mymob.gun_move_icon.color = ui_color - mymob.gun_move_icon.alpha = ui_alpha - - mymob.radio_use_icon = new /obj/screen/gun/radio(null) - mymob.radio_use_icon.icon = ui_style - mymob.radio_use_icon.color = ui_color - mymob.radio_use_icon.alpha = ui_alpha - - mymob.client.screen = list() - - mymob.client.screen += hud_elements - mymob.client.screen += src.adding + src.hotkeybuttons - inventory_shown = 0 - -/mob/living/carbon/human/verb/toggle_hotkey_verbs() - set category = "OOC" - set name = "Toggle hotkey buttons" - set desc = "This disables or enables the user interface buttons which can be used with hotkeys." - - if(hud_used.hotkey_ui_hidden) - client.screen += hud_used.hotkeybuttons - hud_used.hotkey_ui_hidden = 0 - else - client.screen -= hud_used.hotkeybuttons - hud_used.hotkey_ui_hidden = 1 - -// Yes, these use icon state. Yes, these are terrible. The alternative is duplicating -// a bunch of fairly blobby logic for every click override on these objects. - -/obj/screen/food/Click(var/location, var/control, var/params) - if(istype(usr) && usr.nutrition_icon == src) - switch(icon_state) - if("nutrition0") - to_chat(usr, SPAN_WARNING("You are completely stuffed.")) - if("nutrition1") - to_chat(usr, SPAN_NOTICE("You are not hungry.")) - if("nutrition2") - to_chat(usr, SPAN_NOTICE("You are a bit peckish.")) - if("nutrition3") - to_chat(usr, SPAN_WARNING("You are quite hungry.")) - if("nutrition4") - to_chat(usr, SPAN_DANGER("You are starving!")) - -/obj/screen/drink/Click(var/location, var/control, var/params) - if(istype(usr) && usr.hydration_icon == src) - switch(icon_state) - if("hydration0") - to_chat(usr, SPAN_WARNING("You are overhydrated.")) - if("hydration1") - to_chat(usr, SPAN_NOTICE("You are not thirsty.")) - if("hydration2") - to_chat(usr, SPAN_NOTICE("You are a bit thirsty.")) - if("hydration3") - to_chat(usr, SPAN_WARNING("You are quite thirsty.")) - if("hydration4") - to_chat(usr, SPAN_DANGER("You are dying of thirst!")) - -/obj/screen/bodytemp/Click(var/location, var/control, var/params) - if(istype(usr) && usr.bodytemp == src) - switch(icon_state) - if("temp4") - to_chat(usr, SPAN_DANGER("You are being cooked alive!")) - if("temp3") - to_chat(usr, SPAN_DANGER("Your body is burning up!")) - if("temp2") - to_chat(usr, SPAN_DANGER("You are overheating.")) - if("temp1") - to_chat(usr, SPAN_WARNING("You are uncomfortably hot.")) - if("temp-4") - to_chat(usr, SPAN_DANGER("You are being frozen solid!")) - if("temp-3") - to_chat(usr, SPAN_DANGER("You are freezing cold!")) - if("temp-2") - to_chat(usr, SPAN_WARNING("You are dangerously chilled")) - if("temp-1") - to_chat(usr, SPAN_NOTICE("You are uncomfortably cold.")) - else - to_chat(usr, SPAN_NOTICE("Your body is at a comfortable temperature.")) - -/obj/screen/pressure/Click(var/location, var/control, var/params) - if(istype(usr) && usr.pressure == src) - switch(icon_state) - if("pressure2") - to_chat(usr, SPAN_DANGER("The air pressure here is crushing!")) - if("pressure1") - to_chat(usr, SPAN_WARNING("The air pressure here is dangerously high.")) - if("pressure-1") - to_chat(usr, SPAN_WARNING("The air pressure here is dangerously low.")) - if("pressure-2") - to_chat(usr, SPAN_DANGER("There is nearly no air pressure here!")) - else - to_chat(usr, SPAN_NOTICE("The local air pressure is comfortable.")) - -/obj/screen/toxins/Click(var/location, var/control, var/params) - if(istype(usr) && usr.toxin == src) - if(icon_state == "tox0") - to_chat(usr, SPAN_NOTICE("The air is clear of toxins.")) - else - to_chat(usr, SPAN_DANGER("The air is eating away at your skin!")) - -/obj/screen/oxygen/Click(var/location, var/control, var/params) - if(istype(usr) && usr.oxygen == src) - if(icon_state == "oxy0") - to_chat(usr, SPAN_NOTICE("You are breathing easy.")) - else - to_chat(usr, SPAN_DANGER("You cannot breathe!")) - -/obj/screen/movement/Click(var/location, var/control, var/params) - if(istype(usr)) - usr.set_next_usable_move_intent() \ No newline at end of file diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm deleted file mode 100644 index f1966d64043d..000000000000 --- a/code/_onclick/hud/movable_screen_objects.dm +++ /dev/null @@ -1,10 +0,0 @@ -/obj/screen/movable - var/moved = FALSE - -/obj/screen/movable/MouseDrop(over_object, src_location, over_location, src_control, over_control, params) - var/list/PM = params2list(params) - if(LAZYLEN(PM) && PM["screen-loc"]) - var/list/screen_loc_params = splittext(PM["screen-loc"], ",") - var/list/x_data = splittext(screen_loc_params[1], ":") - var/list/y_data = splittext(screen_loc_params[2], ":") - screen_loc = "LEFT+[x_data[1]]:[text2num(x_data[2])-16],BOTTOM+[y_data[1]]:[text2num(y_data[2])-16]" diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm deleted file mode 100644 index 5ecf8af1fc12..000000000000 --- a/code/_onclick/hud/other_mobs.dm +++ /dev/null @@ -1,56 +0,0 @@ -/mob/living/carbon/slime - hud_type = /datum/hud/slime - -/datum/hud/slime/FinalizeInstantiation() - src.adding = list() - - var/obj/screen/using - - using = new /obj/screen/intent() - src.adding += using - action_intent = using - - mymob.client.screen = list() - mymob.client.screen += src.adding - -/mob/living/simple_animal/construct - hud_type = /datum/hud/construct - -/datum/hud/construct/FinalizeInstantiation() - var/constructtype - - if(istype(mymob,/mob/living/simple_animal/construct/armoured) || istype(mymob,/mob/living/simple_animal/construct/behemoth)) - constructtype = "juggernaut" - else if(istype(mymob,/mob/living/simple_animal/construct/builder)) - constructtype = "artificer" - else if(istype(mymob,/mob/living/simple_animal/construct/wraith)) - constructtype = "wraith" - else if(istype(mymob,/mob/living/simple_animal/construct/harvester)) - constructtype = "harvester" - - if(constructtype) - mymob.fire = new /obj/screen() - mymob.fire.icon = 'icons/mob/screen1_construct.dmi' - mymob.fire.icon_state = "fire0" - mymob.fire.SetName("fire") - mymob.fire.screen_loc = ui_construct_fire - - mymob.healths = new /obj/screen() - mymob.healths.icon = 'icons/mob/screen1_construct.dmi' - mymob.healths.icon_state = "[constructtype]_health0" - mymob.healths.SetName("health") - mymob.healths.screen_loc = ui_construct_health - - mymob.zone_sel = new /obj/screen/zone_sel() - mymob.zone_sel.icon = 'icons/mob/screen1_construct.dmi' - mymob.zone_sel.overlays.len = 0 - mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") - - mymob.purged = new /obj/screen() - mymob.purged.icon = 'icons/mob/screen1_construct.dmi' - mymob.purged.icon_state = "purge0" - mymob.purged.SetName("purged") - mymob.purged.screen_loc = ui_construct_purge - - mymob.client.screen = list() - mymob.client.screen += list(mymob.fire, mymob.healths, mymob.zone_sel, mymob.purged) diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index 7a03b7df5de3..33ba6c229f84 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -1,54 +1,7 @@ #define NEXT_PAGE_ID "__next__" #define DEFAULT_CHECK_DELAY 20 -GLOBAL_LIST_EMPTY(radial_menus) - -/obj/screen/radial - icon = 'icons/screen/radial.dmi' - layer = HUD_ABOVE_ITEM_LAYER - plane = HUD_PLANE - var/datum/radial_menu/parent - -/obj/screen/radial/slice - icon_state = "radial_slice" - var/choice - var/next_page = FALSE - var/tooltips = FALSE - -/obj/screen/radial/slice/MouseEntered(location, control, params) - . = ..() - icon_state = "radial_slice_focus" - if(tooltips) - openToolTip(usr, src, params, title = name) - -/obj/screen/radial/slice/MouseExited(location, control, params) - . = ..() - icon_state = "radial_slice" - if(tooltips) - closeToolTip(usr) - -/obj/screen/radial/slice/Click(location, control, params) - if(usr.client == parent.current_user) - if(next_page) - parent.next_page() - else - parent.element_chosen(choice,usr) - -/obj/screen/radial/center - name = "Close Menu" - icon_state = "radial_center" - -/obj/screen/radial/center/MouseEntered(location, control, params) - . = ..() - icon_state = "radial_center_focus" - -/obj/screen/radial/center/MouseExited(location, control, params) - . = ..() - icon_state = "radial_center" - -/obj/screen/radial/center/Click(location, control, params) - if(usr.client == parent.current_user) - parent.finished = TRUE +var/global/list/radial_menus = list() /datum/radial_menu var/list/choices = list() //List of choice id's @@ -165,7 +118,7 @@ GLOBAL_LIST_EMPTY(radial_menus) E.alpha = 0 E.name = "None" E.maptext = null - E.mouse_opacity = 0 + E.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE E.choice = null E.next_page = FALSE @@ -186,7 +139,7 @@ GLOBAL_LIST_EMPTY(radial_menus) //Visuals E.alpha = 255 - E.mouse_opacity = 1 + E.mouse_opacity = MOUSE_OPACITY_NORMAL E.overlays.Cut() if(choice_id == NEXT_PAGE_ID) E.name = "Next Page" @@ -220,7 +173,7 @@ GLOBAL_LIST_EMPTY(radial_menus) /datum/radial_menu/proc/get_next_id() return "c_[choices.len]" -/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips, use_labels) +/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips, use_labels = RADIAL_LABELS_NONE) if(choices.len) Reset() for(var/E in new_choices) @@ -233,8 +186,7 @@ GLOBAL_LIST_EMPTY(radial_menus) choices_icons[id] = I setup_menu(use_tooltips) - -/datum/radial_menu/proc/extract_image(image/E, var/use_labels) +/datum/radial_menu/proc/extract_image(image/E, var/use_labels = RADIAL_LABELS_NONE) var/mutable_appearance/MA = new /mutable_appearance(E) if(MA) MA.layer = HUD_ABOVE_HUD_LAYER @@ -243,9 +195,15 @@ GLOBAL_LIST_EMPTY(radial_menus) MA.maptext_width = 64 MA.maptext_height = 64 MA.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA - MA.maptext_x = -round(MA.maptext_width/2) + 16 - MA.maptext_x = -round(MA.maptext_height/2) + 16 - MA.maptext = "
[E.name]
" + switch(use_labels) + if(RADIAL_LABELS_OFFSET) + MA.maptext_x = -16 + MA.maptext_y = -8 + MA.maptext = STYLE_SMALLFONTS_OUTLINE("
[E.name]
", 7, COLOR_WHITE, COLOR_BLACK) + if(RADIAL_LABELS_CENTERED) + MA.maptext_x = -16 + MA.maptext_y = -16 + MA.maptext = "[E.name]" return MA @@ -264,7 +222,7 @@ GLOBAL_LIST_EMPTY(radial_menus) //Blank menu_holder = image(icon = 'icons/effects/effects.dmi', loc = anchor, icon_state = "nothing", layer = HUD_ABOVE_ITEM_LAYER) menu_holder.appearance_flags |= KEEP_APART - menu_holder.vis_contents += elements + close_button + menu_holder.add_vis_contents(elements + close_button) current_user.images += menu_holder /datum/radial_menu/proc/hide() @@ -290,6 +248,8 @@ GLOBAL_LIST_EMPTY(radial_menus) /datum/radial_menu/Destroy() Reset() hide() + QDEL_NULL_LIST(elements) + QDEL_NULL(close_button) QDEL_NULL(custom_check_callback) return ..() @@ -298,7 +258,7 @@ GLOBAL_LIST_EMPTY(radial_menus) Choices should be a list where list keys are movables or text used for element names and return value and list values are movables/icons/images used for element icons */ -/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, list/check_locs, use_labels = FALSE) +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, list/check_locs, use_labels = RADIAL_LABELS_NONE) if(!user || !anchor || !length(choices)) return if(!uniqueid) @@ -308,14 +268,14 @@ GLOBAL_LIST_EMPTY(radial_menus) for(var/atom/thing in check_locs) check_locs[thing] = thing.loc - if(GLOB.radial_menus[uniqueid]) + if(global.radial_menus[uniqueid]) if(!no_repeat_close) - var/datum/radial_menu/menu = GLOB.radial_menus[uniqueid] + var/datum/radial_menu/menu = global.radial_menus[uniqueid] menu.finished = TRUE return var/datum/radial_menu/menu = new - GLOB.radial_menus[uniqueid] = menu + global.radial_menus[uniqueid] = menu if(radius) menu.radius = radius if(istype(custom_check)) @@ -327,7 +287,26 @@ GLOBAL_LIST_EMPTY(radial_menus) menu.wait(user, anchor, require_near, check_locs) var/answer = menu.selected_choice qdel(menu) - GLOB.radial_menus -= uniqueid + global.radial_menus -= uniqueid return answer #define RADIAL_INPUT(user, choices) show_radial_menu(user, user, choices) + +/* + Helper to make a radial menu button with a name and icon for a given atom. +*/ +/proc/make_item_radial_menu_button(var/atom/movable/AM, var/name_prefix = "", var/name_suffix = "") + var/image/radial_button = new + radial_button.appearance = AM + radial_button.plane = FLOAT_PLANE + radial_button.layer = FLOAT_LAYER + radial_button.name = "[name_prefix][AM.name][name_suffix]" + return radial_button + +/* + Helper to make a radial menu button for a set of atoms with their names and icons. +*/ +/proc/make_item_radial_menu_choices(var/list/items, var/name_prefix = "", var/name_suffix = "") + for(var/atom/movable/AM in items) + LAZYSET(., AM, make_item_radial_menu_button(AM, name_prefix, name_suffix)) + diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm index 183f2d8c462e..8f01871138e4 100644 --- a/code/_onclick/hud/radial_persistent.dm +++ b/code/_onclick/hud/radial_persistent.dm @@ -2,28 +2,12 @@ A derivative of radial menu which persists onscreen until closed and invokes a callback each time an element is clicked */ -/obj/screen/radial/persistent/center - name = "Close Menu" - icon_state = "radial_center" - -/obj/screen/radial/persistent/center/Click(location, control, params) - if(usr.client == parent.current_user) - parent.element_chosen(null,usr) - -/obj/screen/radial/persistent/center/MouseEntered(location, control, params) - . = ..() - icon_state = "radial_center_focus" - -/obj/screen/radial/persistent/center/MouseExited(location, control, params) - . = ..() - icon_state = "radial_center" - /datum/radial_menu/persistent var/uniqueid var/datum/callback/select_proc_callback /datum/radial_menu/persistent/New() - close_button = new /obj/screen/radial/persistent/center + close_button = new /obj/screen/radial/persistent/center(null) close_button.parent = src /datum/radial_menu/persistent/element_chosen(choice_id,mob/user) @@ -37,7 +21,7 @@ /datum/radial_menu/persistent/Destroy() QDEL_NULL(select_proc_callback) - GLOB.radial_menus -= uniqueid + global.radial_menus -= uniqueid Reset() hide() return ..() @@ -55,12 +39,12 @@ if(!uniqueid) uniqueid = "defmenu_\ref[user]_\ref[anchor]" - if(GLOB.radial_menus[uniqueid]) + if(global.radial_menus[uniqueid]) return var/datum/radial_menu/persistent/menu = new menu.uniqueid = uniqueid - GLOB.radial_menus[uniqueid] = menu + global.radial_menus[uniqueid] = menu if(radius) menu.radius = radius menu.select_proc_callback = select_proc diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm deleted file mode 100644 index 4d486e69ecfe..000000000000 --- a/code/_onclick/hud/robot.dm +++ /dev/null @@ -1,245 +0,0 @@ -var/obj/screen/robot_inventory - -/obj/screen/robot_drop_grab - name = "drop grab" - icon = 'icons/mob/screen1_robot.dmi' - icon_state = "drop_grab" - screen_loc = ui_borg_drop_grab - invisibility = INVISIBILITY_MAXIMUM - alpha = 0 - -/obj/screen/robot_drop_grab/Click(location, control, params) - . = ..() - if(isrobot(usr) && !usr.incapacitated()) - var/mob/living/silicon/robot/R = usr - R.drop_item() - invisibility = INVISIBILITY_MAXIMUM - alpha = 0 - -/mob/living/silicon/robot - hud_type = /datum/hud/robot - -/datum/hud/robot/FinalizeInstantiation() - - if(!isrobot(mymob)) - return - - var/mob/living/silicon/robot/R = mymob - - adding = list() - other = list() - - var/obj/screen/using - - //Radio - using = new /obj/screen() - using.SetName("radio") - using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = "radio" - using.screen_loc = ui_movi - adding += using - - //Module select - - using = new /obj/screen() - using.SetName("module1") - using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = "inv1" - using.screen_loc = ui_inv1 - adding += using - R.inv1 = using - - using = new /obj/screen() - using.SetName("module2") - using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = "inv2" - using.screen_loc = ui_inv2 - adding += using - R.inv2 = using - - using = new /obj/screen() - using.SetName("module3") - using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = "inv3" - using.screen_loc = ui_inv3 - adding += using - R.inv3 = using - - //End of module select - - // Drop UI - R.ui_drop_grab = new - adding += R.ui_drop_grab - - //Intent - using = new /obj/screen() - using.SetName("act_intent") - using.set_dir(SOUTHWEST) - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = R.a_intent - using.screen_loc = ui_acti - adding += using - action_intent = using - - //Cell - R.cells = new /obj/screen() - R.cells.icon = 'icons/mob/screen1_robot.dmi' - R.cells.icon_state = "charge-empty" - R.cells.SetName("cell") - R.cells.screen_loc = ui_toxin - - //Health - R.healths = new /obj/screen() - R.healths.icon = 'icons/mob/screen1_robot.dmi' - R.healths.icon_state = "health0" - R.healths.SetName("health") - R.healths.screen_loc = ui_borg_health - - //Installed Module - R.hands = new /obj/screen() - R.hands.icon = 'icons/mob/screen1_robot.dmi' - R.hands.icon_state = "nomod" - R.hands.SetName("module") - R.hands.screen_loc = ui_borg_module - - //Module Panel - using = new /obj/screen() - using.SetName("panel") - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = "panel" - using.screen_loc = ui_borg_panel - adding += using - - //Store - R.throw_icon = new /obj/screen() - R.throw_icon.icon = 'icons/mob/screen1_robot.dmi' - R.throw_icon.icon_state = "store" - R.throw_icon.SetName("store") - R.throw_icon.screen_loc = ui_borg_store - - //Inventory - robot_inventory = new /obj/screen() - robot_inventory.SetName("inventory") - robot_inventory.icon = 'icons/mob/screen1_robot.dmi' - robot_inventory.icon_state = "inventory" - robot_inventory.screen_loc = ui_borg_inventory - - //Temp - R.bodytemp = new /obj/screen() - R.bodytemp.icon = 'icons/mob/status_indicators.dmi' - R.bodytemp.icon_state = "temp0" - R.bodytemp.SetName("body temperature") - R.bodytemp.screen_loc = ui_temp - - - R.oxygen = new /obj/screen() - R.oxygen.icon = 'icons/mob/screen1_robot.dmi' - R.oxygen.icon_state = "oxy0" - R.oxygen.SetName("oxygen") - R.oxygen.screen_loc = ui_oxygen - - R.fire = new /obj/screen() - R.fire.icon = 'icons/mob/screen1_robot.dmi' - R.fire.icon_state = "fire0" - R.fire.SetName("fire") - R.fire.screen_loc = ui_fire - - R.up_hint = new /obj/screen() - R.up_hint.icon = 'icons/mob/screen1_robot.dmi' - R.up_hint.icon_state = "uphint0" - R.up_hint.SetName("up hint") - R.up_hint.screen_loc = ui_up_hint - - R.zone_sel = new /obj/screen/zone_sel() - R.zone_sel.icon = 'icons/mob/screen1_robot.dmi' - R.zone_sel.overlays.Cut() - R.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[R.zone_sel.selecting]") - - //Handle the gun settings buttons - R.gun_setting_icon = new /obj/screen/gun/mode(null) - R.item_use_icon = new /obj/screen/gun/item(null) - R.gun_move_icon = new /obj/screen/gun/move(null) - R.radio_use_icon = new /obj/screen/gun/radio(null) - - R.client.screen = list() - R.client.screen += list(R.throw_icon, R.zone_sel, R.oxygen, R.fire, R.up_hint, R.hands, R.healths, R.cells, robot_inventory, R.gun_setting_icon) - R.client.screen += adding + other - -/datum/hud/proc/toggle_show_robot_modules() - if(!isrobot(mymob)) - return - - var/mob/living/silicon/robot/r = mymob - - r.shown_robot_modules = !r.shown_robot_modules - update_robot_modules_display() - - -/datum/hud/proc/update_robot_modules_display() - if(!isrobot(mymob) || !mymob.client) - return - - var/mob/living/silicon/robot/R = mymob - - if(R.shown_robot_modules) - if(R.s_active) - R.s_active.close(R) //Closes the inventory ui. - //Modules display is shown - //R.client.screen += robot_inventory //"store" icon - - if(!R.module) - to_chat(usr, "No module selected") - return - - if(!R.module.equipment) - to_chat(usr, "Selected module has no modules to select") - return - - if(!R.robot_modules_background) - return - - var/display_rows = -round(-(R.module.equipment.len) / 8) - R.robot_modules_background.screen_loc = "CENTER-4:16,BOTTOM+1:7 to CENTER+3:16,BOTTOM+[display_rows]:7" - R.client.screen += R.robot_modules_background - - var/x = -4 //Start at CENTER-4,SOUTH+1 - var/y = 1 - - //Unfortunately adding the emag module to the list of modules has to be here. This is because a borg can - //be emagged before they actually select a module. - or some situation can cause them to get a new module - // - or some situation might cause them to get de-emagged or something. - if(R.emagged) - if(!(R.module.emag in R.module.equipment)) - R.module.equipment.Add(R.module.emag) - else - if(R.module.emag in R.module.equipment) - R.module.equipment.Remove(R.module.emag) - - for(var/atom/movable/A in R.module.equipment) - if( (A != R.module_state_1) && (A != R.module_state_2) && (A != R.module_state_3) ) - //Module is not currently active - R.client.screen += A - if(x < 0) - A.screen_loc = "CENTER[x]:[WORLD_ICON_SIZE/2],BOTTOM+[y]:7" - else - A.screen_loc = "CENTER+[x]:[WORLD_ICON_SIZE/2],BOTTOM+[y]:7" - A.hud_layerise() - - x++ - if(x == 4) - x = -4 - y++ - - else - //Modules display is hidden - //R.client.screen -= robot_inventory //"store" icon - for(var/atom/A in R.module.equipment) - if( (A != R.module_state_1) && (A != R.module_state_2) && (A != R.module_state_3) ) - //Module is not currently active - R.client.screen -= A - R.shown_robot_modules = 0 - R.client.screen -= R.robot_modules_background diff --git a/code/_onclick/hud/screen/_screen.dm b/code/_onclick/hud/screen/_screen.dm new file mode 100644 index 000000000000..da0c7b5478af --- /dev/null +++ b/code/_onclick/hud/screen/_screen.dm @@ -0,0 +1,130 @@ +/* + Screen objects are only used for the hud and should not appear anywhere "in-game". + They are used with the client/screen list and the screen_loc var. + For more information, see the byond documentation on the screen_loc and screen vars. +*/ +/obj/screen + name = "" + plane = HUD_PLANE + layer = HUD_BASE_LAYER + appearance_flags = NO_CLIENT_COLOR + abstract_type = /obj/screen + is_spawnable_type = FALSE + simulated = FALSE + + /// The mob that owns this screen object, if any. + var/weakref/owner_ref + /// Whether or not this screen element requires an owner. + var/requires_owner = TRUE + /// Global screens are not qdeled when the holding mob is destroyed. + var/is_global_screen = FALSE + /// A set of flags to check for when the user clicks this element. + var/user_incapacitation_flags = INCAPACITATION_DEFAULT + /// A string reference to a /decl/ui_style icon category. + var/ui_style_category + /// Set to false for screen objects that do not rely on UI style to set their icon. + var/requires_ui_style = TRUE + /// Whether or not we look for/draw an additional detail overlay. + var/apply_screen_overlay = TRUE + + // Do we take supplied color in Initialize()? + var/use_supplied_ui_color = FALSE + // Do we take supplied alpha in Initialize()? + var/use_supplied_ui_alpha = FALSE + // Do we take supplied icon in Initialize()? + var/use_supplied_ui_icon = TRUE + +/obj/screen/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat) + + if(requires_ui_style) + if(!ispath(ui_cat, /decl/hud_element) && !ispath(ui_style_category, /decl/hud_element)) + PRINT_STACK_TRACE("Screen object [type] initializing with invalid UI style category: [ui_cat || "NULL"], [ui_style_category || "NULL"].") + return INITIALIZE_HINT_QDEL + if(!istype(ui_style)) + PRINT_STACK_TRACE("Screen object [type] initializing with invalid UI style: [ui_style || "NULL"].") + return INITIALIZE_HINT_QDEL + + if(ismob(_owner)) + owner_ref = weakref(_owner) + + // Validate ownership. + if(requires_owner) + if(!owner_ref) + PRINT_STACK_TRACE("ERROR: [type]'s Initialize() was not given an owner argument.") + return INITIALIZE_HINT_QDEL + else if(owner_ref) + PRINT_STACK_TRACE("ERROR: [type]'s Initialize() was given an owner argument.") + return INITIALIZE_HINT_QDEL + + set_ui_style(ui_style, ui_cat) + if(!isnull(ui_color) && use_supplied_ui_color) + color = ui_color + if(!isnull(ui_alpha) && use_supplied_ui_alpha) + alpha = ui_alpha + + return ..() + +/obj/screen/proc/get_owner_ui_style() + var/mob/owner = owner_ref?.resolve() + return (istype(owner) && istype(owner.hud_used)) ? owner.hud_used.get_ui_style_data() : null + +/obj/screen/get_color() + return color + +/obj/screen/set_color(new_color) + if(color != new_color) + color = new_color + return TRUE + return FALSE + +/obj/screen/proc/set_ui_style(decl/ui_style/ui_style, ui_cat) + if(!isnull(ui_cat)) + ui_style_category = ui_cat + if(istype(ui_style) && ui_style_category && use_supplied_ui_icon) + icon = ui_style.get_icon(ui_style_category) + update_icon() + +/obj/screen/Destroy() + var/mob/owner = owner_ref?.resolve() + if(istype(owner) && owner.client?.screen) + owner.client.screen -= src + return ..() + +/obj/screen/proc/handle_click(mob/user, params) + return TRUE + +/obj/screen/Click(location, control, params) + var/list/paramlist = params2list(params) + if(paramlist["shift"]) + return examined_by(usr, 0) + if(ismob(usr) && usr.client && usr.canClick() && (!user_incapacitation_flags || !usr.incapacitated(user_incapacitation_flags))) + return handle_click(usr, params) + return FALSE + +/obj/screen/receive_mouse_drop(atom/dropping, mob/user) + return TRUE + +/obj/screen/check_mousedrop_interactivity(var/mob/user) + return user.client && (src in user.client.screen) + +/obj/screen/on_update_icon() + rebuild_screen_overlays() + compile_overlays() + +/obj/screen/proc/get_screen_overlay_state() + return icon_state + +/obj/screen/proc/rebuild_screen_overlays() + SHOULD_CALL_PARENT(TRUE) + cut_overlays() + if(!apply_screen_overlay) + return + var/check_for_state = "[get_screen_overlay_state()]-overlay" + if(!check_state_in_icon(check_for_state, icon)) + return + var/decl/ui_style/ui_style = get_owner_ui_style() + if(ui_style?.use_overlay_color) + var/mob/living/owner = owner_ref?.resolve() + add_overlay(overlay_image(icon, check_for_state, istype(owner) ? (owner?.client?.prefs.UI_style_highlight_color || COLOR_WHITE) : COLOR_WHITE, RESET_COLOR)) + else + add_overlay(check_for_state) diff --git a/code/_onclick/hud/screen/robot/screen_robot.dm b/code/_onclick/hud/screen/robot/screen_robot.dm new file mode 100644 index 000000000000..594388da5aa0 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot.dm @@ -0,0 +1,7 @@ +/obj/screen/robot + abstract_type = /obj/screen/robot + icon = 'icons/mob/screen/styles/robot/panel.dmi' + requires_ui_style = FALSE + use_supplied_ui_alpha = FALSE + use_supplied_ui_color = FALSE + use_supplied_ui_icon = FALSE diff --git a/code/_onclick/hud/screen/robot/screen_robot_drop_grab.dm b/code/_onclick/hud/screen/robot/screen_robot_drop_grab.dm new file mode 100644 index 000000000000..bff32e2bc888 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_drop_grab.dm @@ -0,0 +1,23 @@ +/obj/screen/robot/drop_grab + name = "drop grab" + icon = 'icons/mob/screen/styles/robot/drop_grab.dmi' + icon_state = "drop_grab" + screen_loc = ui_borg_drop_grab + invisibility = INVISIBILITY_MAXIMUM + alpha = 0 + +/obj/screen/robot/drop_grab/handle_click(mob/user, params) + if(isrobot(user)) + var/mob/living/silicon/robot/robot = user + robot.drop_item() + update_icon() + +/obj/screen/robot/drop_grab/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner) && length(owner.get_active_grabs())) + set_invisibility(INVISIBILITY_NONE) + alpha = 255 + else + set_invisibility(INVISIBILITY_ABSTRACT) + alpha = 0 diff --git a/code/_onclick/hud/screen/robot/screen_robot_inventory.dm b/code/_onclick/hud/screen/robot/screen_robot_inventory.dm new file mode 100644 index 000000000000..ab8d4815f9f8 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_inventory.dm @@ -0,0 +1,12 @@ +/obj/screen/robot/inventory + name = "inventory" + icon_state = "inventory" + screen_loc = ui_borg_inventory + +/obj/screen/robot/inventory/handle_click(mob/user, params) + if(isrobot(user)) + var/mob/living/silicon/robot/robot = user + if(robot.module) + robot.module.storage?.open(user) + else + to_chat(robot, "You haven't selected a module yet.") diff --git a/code/_onclick/hud/screen/robot/screen_robot_module.dm b/code/_onclick/hud/screen/robot/screen_robot_module.dm new file mode 100644 index 000000000000..69c0fde190f3 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_module.dm @@ -0,0 +1,17 @@ +/obj/screen/robot/module + name = "module" + icon = 'icons/mob/screen/styles/robot/module.dmi' + icon_state = "nomod" + screen_loc = ui_borg_module + +/obj/screen/robot/module/on_update_icon() + . = ..() + icon_state = initial(icon_state) + var/mob/living/silicon/robot/owner = owner_ref?.resolve() + if(istype(owner) && owner.modtype) + icon_state = lowertext(owner.modtype) + +/obj/screen/robot/module/handle_click(mob/user, params) + if(isrobot(user)) + var/mob/living/silicon/robot/robot = user + robot.pick_module() diff --git a/code/_onclick/hud/screen/robot/screen_robot_modules.dm b/code/_onclick/hud/screen/robot/screen_robot_modules.dm new file mode 100644 index 000000000000..09029a035fde --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_modules.dm @@ -0,0 +1,4 @@ +/obj/screen/robot/modules_background + name = "module" + icon_state = "block" + icon = 'icons/mob/screen/styles/robot/modules_background.dmi' diff --git a/code/_onclick/hud/screen/robot/screen_robot_radio.dm b/code/_onclick/hud/screen/robot/screen_robot_radio.dm new file mode 100644 index 000000000000..96f2364ca600 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_radio.dm @@ -0,0 +1,10 @@ +/obj/screen/robot/radio + name = "radio" + dir = SOUTHWEST + icon_state = "radio" + screen_loc = ui_movi + +/obj/screen/robot/radio/handle_click(mob/user, params) + if(isrobot(user)) + var/mob/living/silicon/robot/robot = user + robot.radio_menu() \ No newline at end of file diff --git a/code/_onclick/hud/screen/robot/screen_robot_store.dm b/code/_onclick/hud/screen/robot/screen_robot_store.dm new file mode 100644 index 000000000000..90b46cae00c5 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_store.dm @@ -0,0 +1,13 @@ +/obj/screen/robot/store + name = "store" + icon_state = "store" + screen_loc = ui_borg_store + +/obj/screen/robot/store/handle_click(mob/user, params) + var/mob/living/silicon/robot/robot = user + if(istype(robot) && robot.module) + var/obj/item/active_item = robot.get_active_held_item() + if(active_item) + user.try_unequip(active_item, robot.module, FALSE) + else + to_chat(robot, "You haven't selected a module yet.") diff --git a/code/_onclick/hud/screen/robot/screen_robot_warnings.dm b/code/_onclick/hud/screen/robot/screen_robot_warnings.dm new file mode 100644 index 000000000000..c6365ba40d83 --- /dev/null +++ b/code/_onclick/hud/screen/robot/screen_robot_warnings.dm @@ -0,0 +1,4 @@ +/obj/screen/health/robot + name = "health" + icon_state = "health0" + screen_loc = ui_borg_health diff --git a/code/_onclick/hud/screen/screen_action_button.dm b/code/_onclick/hud/screen/screen_action_button.dm new file mode 100644 index 000000000000..f0d4d6cbf79a --- /dev/null +++ b/code/_onclick/hud/screen/screen_action_button.dm @@ -0,0 +1,85 @@ +/obj/screen/action_button + screen_loc = "LEFT,TOP" + requires_ui_style = FALSE + var/datum/action/action + +/obj/screen/action_button/Destroy() + if(!QDELETED(action)) + if(action.button == src) + action.button = null + QDEL_NULL(action) + action = null + return ..() + +/obj/screen/action_button/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat, _action) + action = _action + return ..() + +/obj/screen/action_button/handle_click(mob/user, params) + if(action && user.next_move < world.time) + action.Trigger() + return TRUE + return FALSE + +/obj/screen/action_button/on_update_icon() + ..() + if(!action) + return + icon = action.background_icon + icon_state = action.background_icon_state + + cut_overlays() + var/image/img + if(action.action_type == AB_ITEM && action.target) + var/obj/item/I = action.target + img = image(I.icon, src , I.icon_state) + else if(action.button_icon && action.button_icon_state) + img = image(action.button_icon,src,action.button_icon_state) + img.pixel_x = 0 + img.pixel_y = 0 + add_overlay(img) + compile_overlays() + + if(!action.IsAvailable()) + color = rgb(128,0,0,128) + else + color = rgb(255,255,255,255) + +/obj/screen/action_button/MouseEntered(location, control, params) + openToolTip(user = usr, tip_src = src, params = params, title = name, content = desc) + ..() + +/obj/screen/action_button/MouseDown() + closeToolTip(usr) + ..() + +/obj/screen/action_button/MouseExited() + closeToolTip(usr) + ..() + +//Hide/Show Action Buttons ... Button +/obj/screen/action_button/hide_toggle + name = "Hide Buttons" + icon = 'icons/obj/action_buttons/actions.dmi' + icon_state = "bg_default" + var/hidden = FALSE + +/obj/screen/action_button/hide_toggle/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + icon_state = "bg_default" + update_icon() + +/obj/screen/action_button/hide_toggle/handle_click(mob/user, params) + if(!istype(user.hud_used)) + return + hidden = user.hud_used.toggle_action_buttons_hidden() + if(hidden) + name = "Show Buttons" + else + name = "Hide Buttons" + update_icon() + user.update_action_buttons() + +/obj/screen/action_button/hide_toggle/rebuild_screen_overlays() + ..() + add_overlay(hidden ? "show" : "hide") diff --git a/code/_onclick/hud/screen/screen_ai_button.dm b/code/_onclick/hud/screen/screen_ai_button.dm new file mode 100644 index 000000000000..f1aaea0360f1 --- /dev/null +++ b/code/_onclick/hud/screen/screen_ai_button.dm @@ -0,0 +1,62 @@ +/obj/screen/ai_button + icon = 'icons/mob/screen/ai.dmi' + requires_ui_style = FALSE + use_supplied_ui_alpha = FALSE + use_supplied_ui_color = FALSE + use_supplied_ui_icon = FALSE + + var/ai_verb + var/list/input_procs + var/list/input_args + var/list/template_icon = list(null, "template") + var/image/template_undelay + +/obj/screen/ai_button/handle_click(mob/user, params) + + var/mob/living/silicon/ai/A = user + if(!istype(A)) + return TRUE + + if(!(ai_verb in A.verbs)) + return TRUE + + var/input_arguments = list() + for(var/input_proc in input_procs) + var/input_flags = input_procs[input_proc] + var/input_arg + if(input_flags & AI_BUTTON_PROC_BELONGS_TO_CALLER) // Does the called proc belong to the AI, or not? + input_arg = call(A, input_proc)() + else + input_arg= call(input_proc)() + + if(input_flags & AI_BUTTON_INPUT_REQUIRES_SELECTION) + input_arg = input("Make a selection.", "Make a selection.") as null|anything in input_arg + if(!input_arg) + return // We assume a null-input means the user cancelled + + if(!(ai_verb in A.verbs) || A.incapacitated()) + return + input_arguments += input_arg + + if(length(input_args)) + input_arguments |= input_args + + call(A, ai_verb)(arglist(input_arguments)) + return TRUE + +/obj/screen/ai_button/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + + var/decl/hud_element/ai/ai_hud_data = GET_DECL(ui_cat) + if(istype(ai_hud_data)) + name = ai_hud_data.name + icon_state = ai_hud_data.icon_state + screen_loc = ai_hud_data.screen_loc + ai_verb = ai_hud_data.proc_path + input_procs = ai_hud_data.input_procs?.Copy() + input_args = ai_hud_data.input_args?.Copy() + + if(!LAZYLEN(template_icon)) + template_icon = list(icon) + template_undelay = image(template_icon[1], template_icon[2]) + underlays += template_undelay diff --git a/code/_onclick/hud/screen/screen_attack_selector.dm b/code/_onclick/hud/screen/screen_attack_selector.dm new file mode 100644 index 000000000000..ee9f4c019cfc --- /dev/null +++ b/code/_onclick/hud/screen/screen_attack_selector.dm @@ -0,0 +1,30 @@ +/obj/screen/default_attack_selector + name = "default attack selector" + icon_state = "attack_none" + screen_loc = ui_attack_selector + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/default_attack_selector/handle_click(mob/user, params) + + var/mob/living/human/owner = owner_ref?.resolve() + if(user != owner) + return FALSE + + var/list/modifiers = params2list(params) + if(modifiers["shift"]) + to_chat(owner, SPAN_NOTICE("Your current default attack is [owner.default_attack?.name || "unset"].")) + if(owner.default_attack) + var/summary = owner.default_attack.summarize() + if(summary) + to_chat(owner, SPAN_NOTICE(summary)) + return + + owner.set_default_unarmed_attack(src) + return TRUE + +/obj/screen/default_attack_selector/on_update_icon() + ..() + var/mob/living/human/owner = owner_ref?.resolve() + var/decl/natural_attack/attack = istype(owner) && owner.default_attack + icon_state = (istype(attack) && attack.selector_icon_state) ? attack.selector_icon_state : "attack_none" diff --git a/code/_onclick/hud/screen/screen_cinematic.dm b/code/_onclick/hud/screen/screen_cinematic.dm new file mode 100644 index 000000000000..b2bd06c63ca7 --- /dev/null +++ b/code/_onclick/hud/screen/screen_cinematic.dm @@ -0,0 +1,8 @@ +/obj/screen/cinematic + icon = 'icons/effects/station_explosion.dmi' + icon_state = "station_intact" + plane = HUD_PLANE + layer = HUD_ABOVE_ITEM_LAYER + mouse_opacity = MOUSE_OPACITY_PRIORITY + screen_loc = "LEFT+1,BOTTOM" + requires_ui_style = FALSE diff --git a/code/_onclick/hud/screen/screen_click_catcher.dm b/code/_onclick/hud/screen/screen_click_catcher.dm new file mode 100644 index 000000000000..d5bfc696f15c --- /dev/null +++ b/code/_onclick/hud/screen/screen_click_catcher.dm @@ -0,0 +1,47 @@ +var/global/list/click_catchers +/proc/get_click_catchers() + if(!global.click_catchers) + var/client_max_x = get_config_value(/decl/config/num/clients/max_client_view_x) + var/client_max_y = get_config_value(/decl/config/num/clients/max_client_view_y) + global.click_catchers = list() + var/ox = -(round(client_max_x*0.5)) + for(var/i = 0 to client_max_x) + var/oy = -(round(client_max_y*0.5)) + var/tx = ox + i + for(var/j = 0 to client_max_y) + var/ty = oy + j + var/obj/screen/click_catcher/CC = new + CC.screen_loc = "CENTER[tx < 0 ? tx : "+[tx]"],CENTER[ty < 0 ? ty : "+[ty]"]" + CC.x_offset = tx + CC.y_offset = ty + global.click_catchers += CC + return global.click_catchers + +/obj/screen/click_catcher + icon = 'icons/mob/screen/effects.dmi' + icon_state = "blank" + plane = CLICKCATCHER_PLANE + mouse_opacity = MOUSE_OPACITY_PRIORITY + screen_loc = "CENTER-7,CENTER-7" + requires_owner = FALSE + requires_ui_style = FALSE + is_global_screen = TRUE + var/x_offset = 0 + var/y_offset = 0 + +/obj/screen/click_catcher/Destroy() + SHOULD_CALL_PARENT(FALSE) + return QDEL_HINT_LETMELIVE + +/obj/screen/click_catcher/Click(location, control, params) + var/list/modifiers = params2list(params) + if(modifiers["middle"] && isliving(usr)) + var/mob/living/user = usr + user.swap_hand() + else + var/turf/origin = get_turf(usr) + if(isturf(origin)) + var/turf/clicked = locate(origin.x + x_offset, origin.y + y_offset, origin.z) + if(clicked) + clicked.Click(location, control, params) + . = 1 diff --git a/code/_onclick/hud/screen/screen_constructs.dm b/code/_onclick/hud/screen/screen_constructs.dm new file mode 100644 index 000000000000..a0082f804fd6 --- /dev/null +++ b/code/_onclick/hud/screen/screen_constructs.dm @@ -0,0 +1,9 @@ +/obj/screen/construct_fire + name = "fire" + icon = 'icons/mob/screen/styles/constructs/status_fire.dmi' + icon_state = "fire0" + screen_loc = ui_construct_fire + +/obj/screen/health/construct + name = "health" + screen_loc = ui_construct_health diff --git a/code/_onclick/hud/screen/screen_credits.dm b/code/_onclick/hud/screen/screen_credits.dm new file mode 100644 index 000000000000..2c04fffcf9a9 --- /dev/null +++ b/code/_onclick/hud/screen/screen_credits.dm @@ -0,0 +1,38 @@ + +/obj/screen/credit + icon_state = "blank" + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + alpha = 0 + screen_loc = "CENTER-7,BOTTOM+1" + plane = HUD_PLANE + layer = HUD_ABOVE_ITEM_LAYER + maptext_height = WORLD_ICON_SIZE * 2 + maptext_width = WORLD_ICON_SIZE * 14 + requires_ui_style = FALSE + var/client/parent + var/matrix/target + +/obj/screen/credit/proc/rollem() + var/matrix/M = matrix(transform) + M.Translate(0, CREDIT_ANIMATE_HEIGHT) + animate(src, transform = M, time = CREDIT_ROLL_SPEED) + target = M + animate(src, alpha = 255, time = CREDIT_EASE_DURATION, flags = ANIMATION_PARALLEL) + addtimer(CALLBACK(src, PROC_REF(ease_out)), CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) + var/mob/owner = owner_ref?.resolve() + if(istype(owner) && owner.client) + owner.client.screen += src + +/obj/screen/credit/proc/ease_out() + if(QDELETED(src)) + return + animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) + QDEL_IN_CLIENT_TIME(src, CREDIT_EASE_DURATION) + +/obj/screen/credit/Destroy() + var/client/P = parent + if(istype(P)) + P.screen -= src + LAZYREMOVE(P.credits, src) + parent = null + return ..() diff --git a/code/_onclick/hud/screen/screen_drop.dm b/code/_onclick/hud/screen/screen_drop.dm new file mode 100644 index 000000000000..716c451252a9 --- /dev/null +++ b/code/_onclick/hud/screen/screen_drop.dm @@ -0,0 +1,10 @@ +/obj/screen/drop + name = "drop" + icon_state = "act_drop" + screen_loc = ui_drop_throw + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/drop/handle_click(mob/user, params) + if(user.client) + user.client.drop_item() diff --git a/code/_onclick/hud/screen/screen_equip.dm b/code/_onclick/hud/screen/screen_equip.dm new file mode 100644 index 000000000000..589edc66a05d --- /dev/null +++ b/code/_onclick/hud/screen/screen_equip.dm @@ -0,0 +1,10 @@ +/obj/screen/equip + name = "equip" + icon_state = "act_equip" + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/equip/handle_click(mob/user, params) + if(ishuman(user)) + var/mob/living/human/H = user + H.quick_equip() diff --git a/code/_onclick/hud/screen/screen_exosuit.dm b/code/_onclick/hud/screen/screen_exosuit.dm new file mode 100644 index 000000000000..ad9171ed446d --- /dev/null +++ b/code/_onclick/hud/screen/screen_exosuit.dm @@ -0,0 +1,432 @@ +/obj/screen/exosuit + name = "hardpoint" + icon = 'icons/mecha/mech_hud.dmi' + icon_state = "base" + requires_ui_style = FALSE + apply_screen_overlay = FALSE + var/initial_maptext + var/height = 14 + +/obj/screen/exosuit/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_cat, ui_alpha) + . = ..() + var/mob/living/exosuit/newowner = get_owning_exosuit() + if(!istype(newowner)) + return INITIALIZE_HINT_QDEL + if(initial_maptext) + maptext = MECH_UI_STYLE(initial_maptext) + +/obj/screen/exosuit/handle_click(mob/user, params) + var/mob/living/exosuit/owner = get_owning_exosuit() + return owner && (user == owner || user.loc == owner) + +/obj/screen/exosuit/proc/get_owning_exosuit() + var/mob/living/exosuit/owner = owner_ref?.resolve() + if(istype(owner) && !QDELETED(owner)) + return owner + +/obj/screen/exosuit/radio + name = "radio" + maptext_x = 5 + maptext_y = 12 + initial_maptext = "RADIO" + +/obj/screen/exosuit/radio/handle_click(mob/user, params) + if(!..()) + return FALSE + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner.radio) + owner.radio.attack_self(user) + else + to_chat(user, SPAN_WARNING("There is no radio installed.")) + return TRUE + +/obj/screen/exosuit/hardpoint + name = "hardpoint" + var/hardpoint_tag + var/obj/item/holding + icon_state = "hardpoint" + + maptext_x = 34 + maptext_y = 3 + maptext_width = 72 + +/obj/screen/exosuit/hardpoint/handle_mouse_drop(atom/over, mob/user) + if(holding) + holding.screen_loc = screen_loc + return TRUE + . = ..() + +/obj/screen/exosuit/hardpoint/proc/update_system_info() + + // No point drawing it if we have no item to use or nobody to see it. + var/mob/living/exosuit/owner = get_owning_exosuit() + if(!holding || !istype(owner)) + return + + var/has_pilot_with_client = owner.client + if(!has_pilot_with_client && LAZYLEN(owner.pilots)) + for(var/thing in owner.pilots) + var/mob/pilot = thing + if(pilot.client) + has_pilot_with_client = TRUE + break + if(!has_pilot_with_client) + return + + var/list/new_overlays = list() + if(!owner.get_cell() || (owner.get_cell().charge <= 0)) + overlays.Cut() + maptext = "" + return + + maptext = STYLE_SMALLFONTS_OUTLINE("[holding.get_hardpoint_maptext()]", 7, COLOR_WHITE, COLOR_BLACK) + + var/ui_damage = (!owner.body.diagnostics || !owner.body.diagnostics.is_functional() || ((owner.emp_damage>EMP_GUI_DISRUPT) && prob(owner.emp_damage))) + + var/value = holding.get_hardpoint_status_value() + if(isnull(value)) + overlays.Cut() + return + + if(ui_damage) + value = -1 + maptext = STYLE_SMALLFONTS_OUTLINE("ERROR", 7, COLOR_WHITE, COLOR_BLACK) + else + if((owner.emp_damage>EMP_GUI_DISRUPT) && prob(owner.emp_damage*2)) + if(prob(10)) + value = -1 + else + value = rand(1,MECH_BAR_CAP) + else + value = round(value * MECH_BAR_CAP) + + // Draw background. + if(!global.default_hardpoint_background) + global.default_hardpoint_background = image(icon = 'icons/mecha/mech_hud.dmi', icon_state = "bar_bkg") + global.default_hardpoint_background.pixel_x = 34 + new_overlays += global.default_hardpoint_background + + if(value == 0) + if(!global.hardpoint_bar_empty) + global.hardpoint_bar_empty = image(icon='icons/mecha/mech_hud.dmi',icon_state="bar_flash") + global.hardpoint_bar_empty.pixel_x = 24 + global.hardpoint_bar_empty.color = "#ff0000" + new_overlays += global.hardpoint_bar_empty + else if(value < 0) + if(!global.hardpoint_error_icon) + global.hardpoint_error_icon = image(icon='icons/mecha/mech_hud.dmi',icon_state="bar_error") + global.hardpoint_error_icon.pixel_x = 34 + new_overlays += global.hardpoint_error_icon + else + value = min(value, MECH_BAR_CAP) + // Draw statbar. + if(!LAZYLEN(global.hardpoint_bar_cache)) + for(var/i=0;i5) + bar.color = "#00ff00" + else if(i>1) + bar.color = "#ffff00" + else + bar.color = "#ff0000" + global.hardpoint_bar_cache += bar + for(var/i=1;i<=value;i++) + new_overlays += global.hardpoint_bar_cache[i] + overlays = new_overlays + +/obj/screen/exosuit/hardpoint/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat, newtag) + . = ..() + hardpoint_tag = newtag + name = "hardpoint ([hardpoint_tag])" + +/obj/screen/exosuit/hardpoint/handle_click(mob/user, params) + if(!..()) + return FALSE + var/mob/living/exosuit/owner = get_owning_exosuit() + if(!owner.hatch_closed) + to_chat(user, SPAN_WARNING("Error: Hardpoint interface disabled while [owner.body.hatch_descriptor] is open.")) + return TRUE + + var/modifiers = params2list(params) + if(modifiers["ctrl"]) + if(owner.hardpoints_locked) + to_chat(user, SPAN_WARNING("Hardpoint ejection system is locked.")) + return TRUE + if(owner.remove_system(hardpoint_tag)) + to_chat(user, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint.")) + else + to_chat(user, SPAN_DANGER("You fail to remove the system mounted to your [hardpoint_tag] hardpoint.")) + return TRUE + + if(owner.selected_hardpoint == hardpoint_tag) + icon_state = "hardpoint" + owner.clear_selected_hardpoint() + else if(owner.set_hardpoint(hardpoint_tag)) + icon_state = "hardpoint_selected" + return TRUE + +/obj/screen/exosuit/eject + name = "eject" + maptext_x = 5 + maptext_y = 12 + initial_maptext = "EJECT" + +/obj/screen/exosuit/eject/handle_click(mob/user, params) + if(!..()) + return FALSE + var/mob/living/exosuit/owner = get_owning_exosuit() + owner.eject(user) + return TRUE + +/obj/screen/exosuit/rename + name = "rename" + maptext_x = 1 + maptext_y = 12 + initial_maptext = "RENAME" + +/obj/screen/exosuit/rename/handle_click(mob/user, params) + if(!..()) + return FALSE + var/mob/living/exosuit/owner = get_owning_exosuit() + owner.rename(user) + return TRUE + +/obj/screen/exosuit/power + name = "power" + icon_state = null + maptext_x = -16 + maptext_width = 64 + maptext_y = -8 + +/obj/screen/exosuit/toggle + name = "toggle" + var/uitext = "" + var/toggled = FALSE + +/obj/screen/exosuit/toggle/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha) + . = ..() + queue_icon_update() + +/obj/screen/exosuit/toggle/on_update_icon() + . = ..() + icon_state = "[initial(icon_state)][toggled ? "_enabled" : ""]" + maptext = "[MECH_UI_STYLE(uitext)]" + +/obj/screen/exosuit/toggle/handle_click(mob/user, params) + if(..()) + toggled(user) + return TRUE + return FALSE + +/obj/screen/exosuit/toggle/proc/toggled(mob/user) + toggled = !toggled + queue_icon_update() + return toggled + +/obj/screen/exosuit/toggle/power_control + name = "Power control" + icon_state = "small_important" + maptext_x = 3 + maptext_y = 13 + height = 12 + uitext = "POWER" + +/obj/screen/exosuit/toggle/power_control/toggled(mob/user) + . = ..() + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + owner.toggle_power(user) + +/obj/screen/exosuit/toggle/power_control/on_update_icon() + var/mob/living/exosuit/owner = get_owning_exosuit() + if(istype(owner)) + toggled = (owner.power == MECH_POWER_ON) + . = ..() + +/obj/screen/exosuit/toggle/air + name = "air" + icon_state = "small_important" + maptext_x = 9 + maptext_y = 13 + height = 12 + uitext = "AIR" + +/obj/screen/exosuit/toggle/air/toggled(mob/user) + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + owner.use_air = ..() + to_chat(user, SPAN_NOTICE("Auxiliary atmospheric system [owner.use_air ? "enabled" : "disabled"].")) + +/obj/screen/exosuit/toggle/maint + name = "toggle maintenance protocol" + icon_state = "small" + maptext_x = 5 + maptext_y = 13 + height = 12 + uitext = "MAINT" + +/obj/screen/exosuit/toggle/maint/toggled(mob/user) + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + owner.maintenance_protocols = ..() + to_chat(user, SPAN_NOTICE("Maintenance protocols [owner.maintenance_protocols ? "enabled" : "disabled"].")) + +/obj/screen/exosuit/toggle/hardpoint + name = "toggle hardpoint lock" + maptext_x = 5 + maptext_y = 12 + uitext = "GEAR" + +/obj/screen/exosuit/toggle/hardpoint/toggled(mob/user) + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + owner.hardpoints_locked = ..() + to_chat(user, SPAN_NOTICE("Hardpoint system access is now [owner.hardpoints_locked ? "disabled" : "enabled"].")) + +/obj/screen/exosuit/toggle/hatch + name = "toggle hatch lock" + maptext_x = 5 + maptext_y = 12 + uitext = "LOCK" + +/obj/screen/exosuit/toggle/hatch/toggled(mob/user) + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + if(!owner.hatch_locked && !owner.hatch_closed) + to_chat(user, SPAN_WARNING("You cannot lock the hatch while it is open.")) + return + owner.hatch_locked = ..() + to_chat(user, SPAN_NOTICE("The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked.")) + +/obj/screen/exosuit/toggle/hatch_open + name = "open or close hatch" + maptext_x = 4 + maptext_y = 12 + +/obj/screen/exosuit/toggle/hatch_open/toggled(mob/user) + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + if(owner.hatch_locked && owner.hatch_closed) + to_chat(user, SPAN_WARNING("You cannot open the hatch while it is locked.")) + return + owner.hatch_closed = ..() + to_chat(user, SPAN_NOTICE("The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ].")) + owner.update_icon() + +/obj/screen/exosuit/toggle/hatch_open/on_update_icon() + var/mob/living/exosuit/owner = get_owning_exosuit() + if(owner) + toggled = owner.hatch_closed + . = ..() + if(owner) + if(toggled) + maptext = MECH_UI_STYLE("OPEN") + maptext_x = 5 + else + maptext = MECH_UI_STYLE("CLOSE") + maptext_x = 4 + +//Controls if cameras set the vision flags +/obj/screen/exosuit/toggle/camera + name = "toggle camera matrix" + icon_state = "small_important" + maptext_x = 1 + maptext_y = 13 + height = 12 + uitext = "SENSOR" + +/obj/screen/exosuit/toggle/camera/on_update_icon() + var/mob/living/exosuit/owner = get_owning_exosuit() + if(istype(owner) && owner.head) + toggled = owner.head.active_sensors + . = ..() + +/obj/screen/exosuit/toggle/camera/toggled(mob/user) + var/mob/living/exosuit/owner = get_owning_exosuit() + if(!istype(owner) || !owner.head) + to_chat(user, SPAN_WARNING("I/O Error: Camera systems not found.")) + return + if(!owner.head.vision_flags) + to_chat(user, SPAN_WARNING("Alternative sensor configurations not found. Contact manufacturer for more details.")) + return + if(!owner.get_cell()) + to_chat(user, SPAN_WARNING("The augmented vision systems are offline.")) + return + owner.head.active_sensors = ..() + to_chat(user, SPAN_NOTICE("[owner.head.name] advanced sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active.")) + +/obj/screen/exosuit/needle + vis_flags = VIS_INHERIT_ID + icon_state = "heatprobe_needle" + +/obj/screen/exosuit/heat + name = "heat probe" + icon_state = "heatprobe" + var/celsius = TRUE + var/obj/screen/exosuit/needle/gauge_needle = null + desc = "TEST" + +/obj/screen/exosuit/heat/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha) + . = ..() + gauge_needle = new /obj/screen/exosuit/needle(null, _owner) + add_vis_contents(gauge_needle) + +/obj/screen/exosuit/heat/Destroy() + QDEL_NULL(gauge_needle) + . = ..() + +/obj/screen/exosuit/heat/handle_click(mob/user, params) + if(!..()) + return FALSE + var/mob/living/exosuit/owner = get_owning_exosuit() + var/modifiers = params2list(params) + if(modifiers["shift"]) + if(owner.material) + user.show_message(SPAN_NOTICE("Your suit's safe operating limit ceiling is [(celsius ? "[owner.material.temperature_damage_threshold - T0C] °C" : "[owner.material.temperature_damage_threshold] K" )]."), VISIBLE_MESSAGE) + return TRUE + if(modifiers["ctrl"]) + celsius = !celsius + user.show_message(SPAN_NOTICE("You switch the chassis probe display to use [celsius ? "celsius" : "kelvin"]."), VISIBLE_MESSAGE) + return TRUE + if(owner.body && owner.body.diagnostics?.is_functional() && owner.loc) + user.show_message(SPAN_NOTICE("The life support panel blinks several times as it updates:"), VISIBLE_MESSAGE) + user.show_message(SPAN_NOTICE("Chassis heat probe reports temperature of [(celsius ? "[owner.bodytemperature - T0C] °C" : "[owner.bodytemperature] K" )]."), VISIBLE_MESSAGE) + if(owner.material.temperature_damage_threshold < owner.bodytemperature) + user.show_message(SPAN_WARNING("Warning: Current chassis temperature exceeds operating parameters."), VISIBLE_MESSAGE) + var/air_contents = owner.loc.return_air() + if(!air_contents) + user.show_message(SPAN_WARNING("The external air probe isn't reporting any data!"), VISIBLE_MESSAGE) + else + user.show_message(SPAN_NOTICE("External probes report: [jointext(atmosanalyzer_scan(owner.loc, air_contents), "
")]"), VISIBLE_MESSAGE) + else + user.show_message(SPAN_WARNING("The life support panel isn't responding."), VISIBLE_MESSAGE) + return TRUE + +/obj/screen/exosuit/heat/proc/Update() + //Relative value of heat + var/mob/living/exosuit/owner = get_owning_exosuit() + if(istype(owner) && owner.body && owner.body.diagnostics?.is_functional() && gauge_needle) + var/value = clamp(owner.bodytemperature / (owner.material.temperature_damage_threshold * 1.55), 0, 1) + var/matrix/rot_matrix = matrix() + rot_matrix.Turn(Interpolate(-90, 90, value)) + rot_matrix.Translate(0, -2) + animate(gauge_needle, transform = rot_matrix, 0.1, easing = SINE_EASING) + +// This is basically just a holder for the updates the exosuit does. +/obj/screen/exosuit/health + name = "exosuit integrity" + icon_state = "health" + +/obj/screen/exosuit/health/handle_click(mob/user, params) + if(!..()) + return FALSE + var/mob/living/exosuit/owner = get_owning_exosuit() + if(!owner.body || !owner.get_cell() || !owner.body.diagnostics?.is_functional()) + return FALSE + user.setClickCooldown(0.2 SECONDS) + to_chat(user, SPAN_NOTICE("The diagnostics panel blinks several times as it updates:")) + playsound(owner.loc,'sound/effects/scanbeep.ogg',30,0) + for(var/obj/item/mech_component/MC in list(owner.arms, owner.legs, owner.body, owner.head)) + MC.return_diagnostics(user) + return TRUE diff --git a/code/_onclick/hud/screen/screen_fullscreen.dm b/code/_onclick/hud/screen/screen_fullscreen.dm new file mode 100644 index 000000000000..53a7f76add0a --- /dev/null +++ b/code/_onclick/hud/screen/screen_fullscreen.dm @@ -0,0 +1,113 @@ +/obj/screen/fullscreen + icon = 'icons/mob/screen/full.dmi' + icon_state = "default" + screen_loc = ui_center_fullscreen + plane = FULLSCREEN_PLANE + layer = FULLSCREEN_LAYER + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + requires_ui_style = FALSE + var/severity = 0 + var/allstate = 0 //shows if it should show up for dead people too + +/obj/screen/fullscreen/Destroy() + severity = 0 + return ..() + +/obj/screen/fullscreen/brute + icon_state = "brutedamageoverlay" + layer = DAMAGE_LAYER + +/obj/screen/fullscreen/oxy + icon_state = "oxydamageoverlay" + layer = DAMAGE_LAYER + +/obj/screen/fullscreen/crit + icon_state = "passage" + layer = CRIT_LAYER + +/obj/screen/fullscreen/blind + icon_state = "blackimageoverlay" + layer = BLIND_LAYER + +/obj/screen/fullscreen/blackout + icon = 'icons/mob/screen/effects.dmi' + icon_state = "black" + screen_loc = ui_entire_screen + layer = BLIND_LAYER + +/obj/screen/fullscreen/impaired + icon_state = "impairedoverlay" + layer = IMPAIRED_LAYER + +/obj/screen/fullscreen/blurry + icon = 'icons/mob/screen/effects.dmi' + screen_loc = ui_entire_screen + icon_state = "blurry" + alpha = 100 + +/obj/screen/fullscreen/flash + icon = 'icons/mob/screen/effects.dmi' + screen_loc = ui_entire_screen + icon_state = "flash" + +/obj/screen/fullscreen/flash/noise + icon_state = "noise" + +/obj/screen/fullscreen/high + icon = 'icons/mob/screen/effects.dmi' + screen_loc = ui_entire_screen + icon_state = "druggy" + alpha = 180 + blend_mode = BLEND_MULTIPLY + +/obj/screen/fullscreen/noise + icon = 'icons/effects/static.dmi' + icon_state = "1 light" + screen_loc = ui_entire_screen + alpha = 127 + +/obj/screen/fullscreen/fadeout + icon = 'icons/mob/screen/effects.dmi' + icon_state = "black" + screen_loc = ui_entire_screen + alpha = 0 + allstate = 1 + +/obj/screen/fullscreen/fadeout/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha) + . = ..() + animate(src, alpha = 255, time = 10) + +/obj/screen/fullscreen/scanline + icon = 'icons/effects/static.dmi' + icon_state = "scanlines" + screen_loc = ui_entire_screen + alpha = 50 + +/obj/screen/fullscreen/fishbed + icon_state = "fishbed" + allstate = 1 + +/obj/screen/fullscreen/pain + icon_state = "brutedamageoverlay6" + alpha = 0 + +/obj/screen/fullscreen/blueprints + icon = 'icons/effects/blueprints.dmi' + icon_state = "base" + screen_loc = ui_entire_screen + alpha = 100 + +/obj/screen/fullscreen/jump_overlay + icon = 'icons/effects/effects.dmi' + icon_state = "mfoam" + screen_loc = ui_entire_screen + color = "#ff9900" + blend_mode = BLEND_SUBTRACT + +/obj/screen/fullscreen/wormhole_overlay + icon = 'icons/effects/effects.dmi' + icon_state = "mfoam" + screen_loc = ui_entire_screen + color = "#ff9900" + alpha = 100 + blend_mode = BLEND_SUBTRACT diff --git a/code/_onclick/hud/screen/screen_global_hud.dm b/code/_onclick/hud/screen/screen_global_hud.dm new file mode 100644 index 000000000000..57591851abe4 --- /dev/null +++ b/code/_onclick/hud/screen/screen_global_hud.dm @@ -0,0 +1,23 @@ +/obj/screen/global_hud + screen_loc = ui_entire_screen + icon = 'icons/effects/hud_full.dmi' + plane = FULLSCREEN_PLANE + layer = FULLSCREEN_LAYER + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + alpha = 125 + blend_mode = BLEND_MULTIPLY + requires_owner = FALSE + requires_ui_style = FALSE + is_global_screen = TRUE + user_incapacitation_flags = null + +/obj/screen/global_holomap + name = "holomap" + icon = null + plane = HUD_PLANE + layer = HUD_BASE_LAYER + screen_loc = UI_HOLOMAP + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + requires_owner = FALSE + requires_ui_style = FALSE + is_global_screen = TRUE diff --git a/code/_onclick/hud/screen/screen_gun.dm b/code/_onclick/hud/screen/screen_gun.dm new file mode 100644 index 000000000000..4cb1eee5886f --- /dev/null +++ b/code/_onclick/hud/screen/screen_gun.dm @@ -0,0 +1,63 @@ +/obj/screen/gun + icon = 'icons/mob/screen/styles/midnight/fire_intent.dmi' + dir = SOUTH + abstract_type = /obj/screen/gun + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + var/base_icon_state + var/toggle_flag + +/obj/screen/gun/on_update_icon() + if(toggle_flag && base_icon_state) + var/mob/living/owner = owner_ref?.resolve() + icon_state = "[base_icon_state][!!(istype(owner) && owner.aiming && (owner.aiming.target_permissions & toggle_flag))]" + ..() + +/obj/screen/gun/handle_click(mob/user, params) + if(isliving(user)) + var/mob/living/shooter = user + if(!shooter.aiming) + shooter.aiming = new(user) + if(toggle_flag) + shooter.aiming.toggle_permission(toggle_flag) + return TRUE + return FALSE + +/obj/screen/gun/move + name = "Allow Movement" + icon_state = "no_walk1" + base_icon_state = "no_walk" + screen_loc = ui_gun2 + toggle_flag = TARGET_CAN_MOVE + +/obj/screen/gun/item + name = "Allow Item Use" + icon_state = "no_item1" + base_icon_state = "no_item" + screen_loc = ui_gun1 + toggle_flag = TARGET_CAN_CLICK + +/obj/screen/gun/radio + name = "Disallow Radio Use" + icon_state = "no_radio1" + base_icon_state = "no_radio" + screen_loc = ui_gun3 + toggle_flag = TARGET_CAN_RADIO + +/obj/screen/gun/mode + name = "Toggle Gun Mode" + icon_state = "gun0" + base_icon_state = "gun" + screen_loc = ui_gun_select + +/obj/screen/gun/mode/on_update_icon() + var/mob/living/owner = owner_ref?.resolve() + icon_state = "[base_icon_state][!!(istype(owner) && owner.aiming?.active)]" + ..() + +/obj/screen/gun/mode/handle_click(mob/user, params) + if(..()) + var/mob/living/shooter = user + shooter.aiming.toggle_active() + return TRUE + return FALSE diff --git a/code/_onclick/hud/screen/screen_health.dm b/code/_onclick/hud/screen/screen_health.dm new file mode 100644 index 000000000000..2322dd2ee220 --- /dev/null +++ b/code/_onclick/hud/screen/screen_health.dm @@ -0,0 +1,66 @@ +/obj/screen/health + name = "health" + icon_state = "health0" + screen_loc = ui_health + +/obj/screen/health/handle_click(mob/user, params) + if(ishuman(user)) + var/mob/living/human/human_user = user + human_user.check_self_injuries() + return TRUE + +/obj/screen/health/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner) || owner.stat == DEAD) + icon_state = "health7" + else + icon_state = "health[round(((100-owner.get_health_percent())/100) * 6, 1)]" + +/obj/screen/health/organs/on_update_icon() + + var/mob/living/human/owner = owner_ref?.resolve() + if(!istype(owner)) + return + + cut_overlays() + + // We don't check can_feel_pain() here, otherwise FBP don't get variable health indicators. + if(owner.has_chemical_effect(CE_PAINKILLER, 100)) + icon_state = "health_numb" + compile_overlays() + return + + icon_state = "blank" + + // Generate a by-limb health display. + var/no_damage = 1 + var/trauma_val = 0 // Used in calculating softcrit/hardcrit indicators. + + var/decl/species/my_species = owner.get_species() + trauma_val = max(owner.shock_stage, owner.get_shock())/ (my_species.total_health-100) + + for(var/obj/item/organ/external/E in owner.get_external_organs()) + if(no_damage && (E.brute_dam || E.burn_dam)) + no_damage = 0 + var/damage_image = E.get_damage_hud_image() + if(damage_image) + add_overlay(damage_image) + + // Apply a fire overlay if we're burning. + var/crit_markers = get_ui_icon(owner.client?.prefs?.UI_style, HUD_CRIT_MARKER) + if(crit_markers) + if(owner.is_on_fire()) + add_overlay(image(crit_markers, "burning")) + // Show a general pain/crit indicator if needed. + if(owner.is_asystole()) + add_overlay(image(crit_markers, "hardcrit")) + else if(trauma_val) + if(trauma_val > 0.7) + add_overlay(image(crit_markers, "softcrit")) + if(trauma_val >= 1) + add_overlay(image(crit_markers, "hardcrit")) + else if(no_damage) + add_overlay(image(crit_markers, "fullhealth")) + + compile_overlays() diff --git a/code/_onclick/hud/screen/screen_holomap.dm b/code/_onclick/hud/screen/screen_holomap.dm new file mode 100644 index 000000000000..af72457e814b --- /dev/null +++ b/code/_onclick/hud/screen/screen_holomap.dm @@ -0,0 +1,100 @@ +/obj/screen/holomap_level_select + icon = 'icons/misc/mark.dmi' + layer = HUD_ITEM_LAYER + requires_owner = FALSE + requires_ui_style = FALSE + var/datum/station_holomap/holomap + +/obj/screen/holomap_text + icon = null + layer = HUD_ITEM_LAYER + maptext_width = 96 + requires_owner = FALSE + requires_ui_style = FALSE + +/obj/screen/holomap_text/Initialize() + . = ..() + appearance_flags |= RESET_COLOR + +/obj/screen/holomap_level_select/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, datum/station_holomap/_holomap) + . = ..() + holomap = _holomap + +/obj/screen/holomap_level_select/handle_click(mob/user, params) + return !isghost(user) + +/obj/screen/holomap_level_select/up + icon_state = "fup" + +/obj/screen/holomap_level_select/up/handle_click(mob/user, params) + if(..() && holomap) + holomap.set_level(holomap.displayed_level - 1) + +/obj/screen/holomap_level_select/down + icon_state = "fdn" + +/obj/screen/holomap_level_select/down/handle_click(mob/user, params) + if(..() && holomap) + holomap.set_level(holomap.displayed_level + 1) + +/obj/screen/holomap_legend + icon = null + maptext_height = 128 + maptext_width = 128 + layer = HUD_ITEM_LAYER + pixel_x = HOLOMAP_LEGEND_X + appearance_flags = DEFAULT_APPEARANCE_FLAGS | RESET_COLOR + requires_owner = FALSE + requires_ui_style = FALSE + var/saved_color + var/datum/station_holomap/holomap = null + var/has_areas = FALSE + +/obj/screen/holomap_legend/cursor + icon = 'icons/misc/holomap_markers.dmi' + icon_state = "you" + maptext_x = 11 + pixel_x = HOLOMAP_LEGEND_X - 3 + has_areas = TRUE + +/obj/screen/holomap_legend/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, map_color, text) + . = ..() + saved_color = map_color + maptext = "
[text]" + alpha = 255 + +/obj/screen/holomap_legend/handle_click(mob/user, params) + if(!isghost(user) && istype(holomap)) + holomap.legend_select(src) + +/obj/screen/holomap_legend/proc/Setup(z_level) + has_areas = FALSE + //Get the areas for this z level and mark if we're empty + overlays.Cut() + for(var/area/A in SSminimap.holomaps[z_level].holomap_areas) + if(A.holomap_color == saved_color) + var/image/area = image(SSminimap.holomaps[z_level].holomap_areas[A]) + area.pixel_x = ((HOLOMAP_ICON_SIZE / 2) - WORLD_CENTER_X) - pixel_x + area.pixel_y = ((HOLOMAP_ICON_SIZE / 2) - WORLD_CENTER_Y) - pixel_y + overlays += area + has_areas = TRUE + +//What happens when we are clicked on / when another is clicked on +/obj/screen/holomap_legend/proc/Select() + //Start blinking + animate(src, alpha = 0, time = 2, loop = -1, easing = JUMP_EASING | EASE_IN | EASE_OUT) + animate(alpha = 254, time = 2, loop = -1, easing = JUMP_EASING | EASE_IN | EASE_OUT) + +/obj/screen/holomap_legend/proc/Deselect() + //Stop blinking + animate(src, flags = ANIMATION_END_NOW) + +//Cursor doesnt do anything specific. +/obj/screen/holomap_legend/cursor/Setup() + return + +/obj/screen/holomap_legend/cursor/Select() + return + +/obj/screen/holomap_legend/cursor/Deselect() + return diff --git a/code/_onclick/hud/screen/screen_intent.dm b/code/_onclick/hud/screen/screen_intent.dm new file mode 100644 index 000000000000..f3fba3b8563f --- /dev/null +++ b/code/_onclick/hud/screen/screen_intent.dm @@ -0,0 +1,132 @@ +// Sub-element used for clickable intent selection. +/obj/screen/intent_button + layer = FLOAT_LAYER + plane = FLOAT_PLANE + icon = 'icons/screen/intents.dmi' + icon_state = "blank" + requires_ui_style = FALSE + screen_loc = null // Technically a screen element, but we use vis_contents to draw them. + var/obj/screen/intent/parent + var/decl/intent/intent + var/selected + +/obj/screen/intent_button/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat, intent_owner) + parent = intent_owner + . = ..() + +/obj/screen/intent_button/Destroy() + parent = null + intent = null + return ..() + +/obj/screen/intent_button/proc/set_selected(decl/intent/_intent) + intent = _intent + selected = TRUE + update_icon() + +/obj/screen/intent_button/proc/set_deselected(decl/intent/_intent) + intent = _intent + selected = FALSE + update_icon() + +/obj/screen/intent_button/handle_click(mob/user, params) + . = ..() + if(. && intent && parent) + parent.set_intent(intent) + +/obj/screen/intent_button/examined_by(mob/user, distance, infix, suffix) + SHOULD_CALL_PARENT(FALSE) + if(desc) + to_chat(user, desc) + return TRUE + +/obj/screen/intent_button/on_update_icon() + . = ..() + screen_loc = null + if(intent) + name = intent.name + desc = intent.desc + icon = intent.icon + icon_state = selected ? intent.icon_state : "[intent.icon_state]_off" + +/obj/screen/intent_button/MouseEntered(location, control, params) + if(intent && (intent.name || intent.desc)) + openToolTip(user = usr, tip_src = src, params = params, content = intent.desc) + return ..() + +/obj/screen/intent_button/MouseDown() + closeToolTip(usr) + return ..() + +/obj/screen/intent_button/MouseExited() + closeToolTip(usr) + return ..() + +/obj/screen/intent + name = "intent" + icon = 'icons/screen/intents.dmi' + icon_state = "blank" + screen_loc = ui_acti + requires_ui_style = FALSE + apply_screen_overlay = FALSE + var/intent_width = 16 + var/intent_height = 16 + var/list/intent_selectors + +/obj/screen/intent/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + update_icon() + // Hide from right-click. + name = "" + verbs.Cut() + +/obj/screen/intent/Destroy() + QDEL_NULL_LIST(intent_selectors) + vis_contents.Cut() + return ..() + +/obj/screen/intent/proc/set_intent(decl/intent/intent) + var/mob/owner = owner_ref?.resolve() + if(istype(owner) && istype(intent)) + owner.set_intent(intent) + update_icon() + +/obj/screen/intent/proc/apply_intent_button_offset(atom/intent_button, index, intent_count) + intent_button.pixel_z = 0 + intent_button.pixel_w = 0 + intent_button.pixel_y = 0 + intent_button.pixel_x = -((intent_count * intent_width)/2) + ((index-1) * intent_width) + +/obj/screen/intent/proc/get_intent_button(index) + . = (index >= 1 && index <= length(intent_selectors)) ? intent_selectors[index] : null + if(!.) + . = new /obj/screen/intent_button(null, owner_ref?.resolve(), null, null, null, null, src) + LAZYADD(intent_selectors, .) + +/obj/screen/intent/on_update_icon() + ..() + + var/mob/owner = owner_ref?.resolve() + if(!istype(owner) || QDELETED(owner)) + return + + var/decl/intent/owner_intent = owner.get_intent() + var/i = 1 + var/list/unused_selectors = intent_selectors?.Copy() + var/list/all_intents = owner.get_available_intents(skip_update = TRUE) + for(var/decl/intent/intent as anything in all_intents) + var/obj/screen/intent_button/intent_button = get_intent_button(i) + if(intent == owner_intent) + intent_button.set_selected(intent) + else + intent_button.set_deselected(intent) + LAZYREMOVE(unused_selectors, intent_button) + i++ + apply_intent_button_offset(intent_button, i, length(all_intents)) + add_vis_contents(intent_button) + + if(length(unused_selectors)) + remove_vis_contents(unused_selectors) + +/obj/screen/intent/binary + intent_width = 32 diff --git a/code/_onclick/hud/screen/screen_internal.dm b/code/_onclick/hud/screen/screen_internal.dm new file mode 100644 index 000000000000..20b9d82120f9 --- /dev/null +++ b/code/_onclick/hud/screen/screen_internal.dm @@ -0,0 +1,17 @@ +/obj/screen/internals + name = "internal" + icon_state = "internal0" + screen_loc = ui_internal + +/obj/screen/internals/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner) && owner.get_internals()) + icon_state = "internal1" + else + icon_state = "internal0" + +/obj/screen/internals/handle_click(mob/user, params) + if(isliving(user)) + var/mob/living/M = user + M.ui_toggle_internals() diff --git a/code/_onclick/hud/screen/screen_inventory.dm b/code/_onclick/hud/screen/screen_inventory.dm new file mode 100644 index 000000000000..09f921ed552e --- /dev/null +++ b/code/_onclick/hud/screen/screen_inventory.dm @@ -0,0 +1,75 @@ +/obj/screen/inventory + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + var/slot_id //The indentifier for the slot. It has nothing to do with ID cards. + var/weakref/mouse_over_atom_ref + +/obj/screen/inventory/handle_click(mob/user, params) + if(name in user.get_held_item_slots()) + if(name == user.get_active_held_item_slot()) + user.attack_empty_hand() + else + user.select_held_item_slot(name) + else if(user.attack_ui(slot_id)) + user.update_inhand_overlays(FALSE) + return FALSE + +/obj/screen/inventory/MouseDrop() + . = ..() + mouse_over_atom_ref = null + update_icon() + +// Overriding Click() here instead of using handle_click() to be thorough. +/obj/screen/inventory/Click(location, control, parameters) + . = ..() + mouse_over_atom_ref = null + update_icon() + +/obj/screen/inventory/MouseEntered(location, control, params) + . = ..() + if(!slot_id || !usr) + return + var/equipped_item = usr.get_active_held_item() + if(equipped_item) + var/new_mouse_over_atom = weakref(equipped_item) + if(new_mouse_over_atom != mouse_over_atom_ref) + mouse_over_atom_ref = new_mouse_over_atom + update_icon() + +/obj/screen/inventory/MouseExited(location, control, params) + . = ..() + if(mouse_over_atom_ref) + mouse_over_atom_ref = null + update_icon() + +/obj/screen/inventory/rebuild_screen_overlays() + + ..() + + // Validate our owner still exists. + var/mob/owner = owner_ref?.resolve() + if(!istype(owner) || QDELETED(owner) || !(src in owner.client?.screen)) + return + + // Mark anything we're potentially trying to equip. + var/obj/item/mouse_over_atom = mouse_over_atom_ref?.resolve() + if(istype(mouse_over_atom) && !QDELETED(mouse_over_atom) && !owner.get_equipped_item(slot_id)) + var/mutable_appearance/MA = new /mutable_appearance(mouse_over_atom) + MA.layer = HUD_ABOVE_ITEM_LAYER + MA.plane = HUD_PLANE + MA.alpha = 80 + MA.color = mouse_over_atom.mob_can_equip(owner, slot_id, TRUE) ? COLOR_GREEN : COLOR_RED + // We don't respect default_pixel_x or similar here because items should always be centered in their slots; defaults are for world-space. + MA.pixel_x = 0 + MA.pixel_y = 0 + MA.pixel_w = 0 + MA.pixel_z = 0 + MA.appearance_flags |= (KEEP_TOGETHER | RESET_COLOR) + // We need to color the entire thing, overlays and underlays included. + for(var/image/overlay in MA.overlays) + overlay.appearance_flags &= ~(KEEP_TOGETHER | RESET_COLOR) + for(var/image/underlay in MA.underlays) + underlay.appearance_flags &= ~(KEEP_TOGETHER | RESET_COLOR) + add_overlay(MA) + else + mouse_over_atom_ref = null diff --git a/code/_onclick/hud/screen/screen_inventory_hands.dm b/code/_onclick/hud/screen/screen_inventory_hands.dm new file mode 100644 index 000000000000..7dbdbf0b1525 --- /dev/null +++ b/code/_onclick/hud/screen/screen_inventory_hands.dm @@ -0,0 +1,31 @@ +/obj/screen/inventory/hand + icon_state = "hand_base" + +/obj/screen/inventory/hand/rebuild_screen_overlays() + + ..() + + // Validate our owner still exists. + var/mob/owner = owner_ref?.resolve() + if(!istype(owner) || QDELETED(owner) || !(src in owner.client?.screen)) + return + + var/overlay_color = owner?.client?.prefs.UI_style_highlight_color || COLOR_WHITE + var/decl/ui_style/ui_style = get_owner_ui_style() + if(owner.get_active_held_item_slot() == slot_id) + if(ui_style?.use_overlay_color) + add_overlay(overlay_image(icon, "hand_selected", overlay_color, RESET_COLOR)) + else + add_overlay("hand_selected") + + var/datum/inventory_slot/gripper/inv_slot = owner.get_inventory_slot_datum(slot_id) + if(istype(inv_slot)) + if(ui_style?.use_overlay_color) + add_overlay(overlay_image(icon, "hand_[inv_slot.hand_overlay || slot_id]", overlay_color, RESET_COLOR)) + else + add_overlay("hand_[inv_slot.hand_overlay || slot_id]", TRUE) + if(inv_slot.ui_label) + if(ui_style?.use_overlay_color) + add_overlay(overlay_image(icon, "hand_[inv_slot.ui_label]", overlay_color, RESET_COLOR)) + else + add_overlay("hand_[inv_slot.ui_label]", TRUE) diff --git a/code/_onclick/hud/screen/screen_lighting.dm b/code/_onclick/hud/screen/screen_lighting.dm new file mode 100644 index 000000000000..24e8b3638a4f --- /dev/null +++ b/code/_onclick/hud/screen/screen_lighting.dm @@ -0,0 +1,12 @@ +/obj/screen/lighting_plane_master + screen_loc = "CENTER" + appearance_flags = PLANE_MASTER + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + plane = LIGHTING_PLANE + blend_mode = BLEND_MULTIPLY + alpha = 255 + requires_ui_style = FALSE + +/obj/screen/lighting_plane_master/set_alpha(var/new_alpha) + if(alpha != new_alpha) + animate(src, alpha = new_alpha, time = SSmobs.wait) \ No newline at end of file diff --git a/code/_onclick/hud/screen/screen_maneuver.dm b/code/_onclick/hud/screen/screen_maneuver.dm new file mode 100644 index 000000000000..4052a690a53c --- /dev/null +++ b/code/_onclick/hud/screen/screen_maneuver.dm @@ -0,0 +1,25 @@ +/obj/screen/maneuver + name = "Prepare Maneuver" + icon_state = "maneuver_off" + screen_loc = ui_pull_resist + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/maneuver/handle_click(mob/user, params) + if(isliving(user)) + var/mob/living/user_living = user + user_living.prepare_maneuver() + +/obj/screen/maneuver/examined_by(mob/user, distance, infix, suffix) + SHOULD_CALL_PARENT(FALSE) + var/mob/living/user_living = user + if(istype(user_living) && user_living.prepared_maneuver) + to_chat(user, SPAN_NOTICE("You are prepared to [user_living.prepared_maneuver.name].")) + else + to_chat(user, SPAN_NOTICE("You are not prepared to perform a maneuver.")) + return TRUE + +/obj/screen/maneuver/on_update_icon() + var/mob/living/owner = owner_ref?.resolve() + icon_state = (istype(owner) && owner.prepared_maneuver) ? "maneuver_on" : "maneuver_off" + ..() diff --git a/code/_onclick/hud/screen/screen_mob_modifier.dm b/code/_onclick/hud/screen/screen_mob_modifier.dm new file mode 100644 index 000000000000..d8d32bd3c586 --- /dev/null +++ b/code/_onclick/hud/screen/screen_mob_modifier.dm @@ -0,0 +1,158 @@ +/obj/screen/mob_modifiers + screen_loc = "CENTER,TOP" + icon_state = "blank" + requires_ui_style = FALSE + + // Disable these due to vis_contents behaving oddly with them. + use_supplied_ui_color = FALSE + use_supplied_ui_alpha = FALSE + + // TODO: consider pooling these. + var/list/elements + var/const/modifier_size = 18 + +/obj/screen/mob_modifiers/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + START_PROCESSING(SSprocessing, src) + +/obj/screen/mob_modifiers/Destroy() + STOP_PROCESSING(SSprocessing, src) + QDEL_NULL_LIST(elements) + return ..() + +/obj/screen/mob_modifiers/Process() + if(QDELETED(src)) + return PROCESS_KILL + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner)) + return PROCESS_KILL + for(var/obj/screen/mob_modifier/element in elements) + var/expire_time = MOB_MODIFIER_INDEFINITE + for(var/datum/mob_modifier/modifier in LAZYACCESS(owner._mob_modifiers, element.archetype)) + if(modifier.expire_time == MOB_MODIFIER_INDEFINITE) + expire_time = MOB_MODIFIER_INDEFINITE + break + expire_time = max(expire_time, modifier.expire_time) + if(istype(element)) + element.update_maptext(expire_time == MOB_MODIFIER_INDEFINITE ? MOB_MODIFIER_INDEFINITE : (expire_time - world.time)) + +/obj/screen/mob_modifiers/on_update_icon() + + if(QDELETED(src)) + return + + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner) || !istype(owner.hud_used)) + return + + var/list/seen_archetypes + var/list/elements_to_keep + var/list/elements_to_add + var/list/elements_to_remove + + // Track deltas for keeping/removing existing elements. + for(var/obj/screen/mob_modifier/element in elements) + var/list/modifiers = LAZYACCESS(owner._mob_modifiers, element.archetype) + if(length(modifiers)) + LAZYADD(elements_to_keep, element) + else + LAZYADD(elements_to_remove, element) + LAZYDISTINCTADD(seen_archetypes, element.archetype) + + var/decl/ui_style/ui_style = owner.hud_used.get_ui_style_data() + var/ui_color = owner.hud_used.get_ui_color() + var/ui_alpha = owner.hud_used.get_ui_alpha() + + // Create elements for new modifiers. + for(var/decl/mob_modifier/archetype in owner._mob_modifiers) + if(archetype in seen_archetypes) + continue + var/obj/screen/mob_modifier/element = new(null, owner, ui_style, ui_color, ui_alpha, HUD_MODIFIERS) + element.archetype = archetype + element.holder = src + element.pixel_y = 32 + element.alpha = 0 + element.update_icon() + LAZYADD(elements_to_add, element) + + // Fade out and delete expired markers. + if(LAZYLEN(elements_to_remove)) + LAZYREMOVE(elements, elements_to_remove) + for(var/obj/screen/mob_modifier/element in elements_to_remove) + animate(element, alpha = 0, pixel_y = 32, time = 5) + QDEL_IN(element, 5) + + // Add our new records. + if(LAZYLEN(elements_to_add)) + LAZYADD(elements, elements_to_add) + add_vis_contents(elements_to_add) + + // Adjust positions and fade in new elements. + if(length(elements)) + var/offset_x = -(((length(elements)-1) * modifier_size) / 2) + for(var/obj/screen/element in elements) + if(element in elements_to_add) + pixel_x = offset_x + animate(element, alpha = 255, pixel_x = offset_x, pixel_y = 0, time = 5) + offset_x += modifier_size + +/obj/screen/mob_modifier + alpha = 0 + screen_loc = null // not handled via screen loc, but via vis contents of the holder object. + maptext_x = -8 + maptext_y = -3 + icon_state = "modifier_base" + // these must be enabled + use_supplied_ui_alpha = TRUE + use_supplied_ui_color = TRUE + var/decl/mob_modifier/archetype + var/obj/screen/mob_modifiers/holder + +/obj/screen/mob_modifier/Destroy() + if(holder) + LAZYREMOVE(holder.elements, src) + holder.remove_vis_contents(src) + holder = null + return ..() + +/obj/screen/mob_modifier/rebuild_screen_overlays() + . = ..() + if(archetype) + add_overlay(overlay_image(archetype.hud_icon, archetype.hud_icon_state, COLOR_WHITE, RESET_COLOR)) + +/obj/screen/mob_modifier/proc/update_maptext(duration) + if(archetype.hide_expiry) + maptext = null + return + + if(duration == MOB_MODIFIER_INDEFINITE) + if(archetype.show_indefinite_duration) + maptext = STYLE_SMALLFONTS_OUTLINE("
", 12, COLOR_WHITE, COLOR_BLACK) + else + maptext = null + else if(duration <= 0) + maptext = STYLE_SMALLFONTS_OUTLINE("
0
", 7, COLOR_WHITE, COLOR_BLACK) + else + maptext = STYLE_SMALLFONTS_OUTLINE("
[ticks2shortreadable(duration) || 0]
", 7, COLOR_WHITE, COLOR_BLACK) + +/obj/screen/mob_modifier/handle_click(mob/user, params) + if((. = ..())) + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner) && archetype) + var/list/modifiers = LAZYACCESS(owner._mob_modifiers, archetype) + for(var/datum/mob_modifier/modifier in modifiers) + modifier.on_modifier_click(params) + return + +/obj/screen/mob_modifier/MouseEntered(location, control, params) + if(archetype && (archetype.name || archetype.desc)) + openToolTip(user = usr, tip_src = src, params = params, title = archetype.name, content = archetype.desc) + ..() + +/obj/screen/mob_modifier/MouseDown() + closeToolTip(usr) + ..() + +/obj/screen/mob_modifier/MouseExited() + closeToolTip(usr) + ..() diff --git a/code/_onclick/hud/screen/screen_movement.dm b/code/_onclick/hud/screen/screen_movement.dm new file mode 100644 index 000000000000..0fd4f4fb52d9 --- /dev/null +++ b/code/_onclick/hud/screen/screen_movement.dm @@ -0,0 +1,16 @@ +/obj/screen/movement + name = "movement method" + screen_loc = ui_movi + icon_state = "creeping" + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/movement/handle_click(mob/user, params) + if(istype(user)) + user.set_next_usable_move_intent() + +/obj/screen/movement/on_update_icon() + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner) && istype(owner.move_intent)) + icon_state = owner.move_intent.hud_icon_state + . = ..() diff --git a/code/_onclick/hud/screen/screen_needs.dm b/code/_onclick/hud/screen/screen_needs.dm new file mode 100644 index 000000000000..61c43f42c5ba --- /dev/null +++ b/code/_onclick/hud/screen/screen_needs.dm @@ -0,0 +1,104 @@ + +// Yes, these use icon state. Yes, these are terrible. The alternative is duplicating +// a bunch of fairly blobby logic for every click override on these objects. +/obj/screen/need + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + screen_loc = ui_nutrition_small + +/obj/screen/need/nutrition + name = "nutrition" + icon = 'icons/mob/screen/styles/nutrition.dmi' + pixel_w = 8 + icon_state = "nutrition1" + +/obj/screen/need/nutrition/handle_click(mob/user, params) + switch(icon_state) + if("nutrition0") + to_chat(user, SPAN_WARNING("You are completely stuffed.")) + if("nutrition1") + to_chat(user, SPAN_NOTICE("You are not hungry.")) + if("nutrition2") + to_chat(user, SPAN_NOTICE("You are a bit peckish.")) + if("nutrition3") + to_chat(user, SPAN_WARNING("You are quite hungry.")) + if("nutrition4") + to_chat(user, SPAN_DANGER("You are starving!")) + +/obj/screen/need/nutrition/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner) || owner.isSynthetic()) + invisibility = INVISIBILITY_ABSTRACT + return + invisibility = INVISIBILITY_NONE + switch(owner.get_nutrition()) + if(450 to INFINITY) + icon_state = "nutrition0" + if(350 to 450) + icon_state = "nutrition1" + if(250 to 350) + icon_state = "nutrition2" + if(150 to 250) + icon_state = "nutrition3" + else + icon_state = "nutrition4" + +/obj/screen/need/hydration + name = "hydration" + icon = 'icons/mob/screen/styles/hydration.dmi' + icon_state = "hydration1" + +/obj/screen/need/hydration/handle_click(mob/user, params) + switch(icon_state) + if("hydration0") + to_chat(user, SPAN_WARNING("You are overhydrated.")) + if("hydration1") + to_chat(user, SPAN_NOTICE("You are not thirsty.")) + if("hydration2") + to_chat(user, SPAN_NOTICE("You are a bit thirsty.")) + if("hydration3") + to_chat(user, SPAN_WARNING("You are quite thirsty.")) + if("hydration4") + to_chat(user, SPAN_DANGER("You are dying of thirst!")) + +/obj/screen/need/hydration/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner) || owner.isSynthetic()) + invisibility = INVISIBILITY_ABSTRACT + return + invisibility = INVISIBILITY_NONE + switch(owner.get_hydration()) + if(450 to INFINITY) + icon_state = "hydration0" + if(350 to 450) + icon_state = "hydration1" + if(250 to 350) + icon_state = "hydration2" + if(150 to 250) + icon_state = "hydration3" + else + icon_state = "hydration4" + +/obj/screen/need/cell_charge + name = "cell" + icon_state = "charge-empty" + screen_loc = ui_nutrition + +/obj/screen/need/cell_charge/robot + screen_loc = ui_toxin + +/obj/screen/need/cell_charge/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner) || !owner.isSynthetic()) + invisibility = INVISIBILITY_ABSTRACT + return + invisibility = INVISIBILITY_NONE + var/obj/item/cell/cell = owner.get_cell() + if(cell) + var/chargeNum = clamp(ceil(cell.percent()/25), 0, 4) //0-100 maps to 0-4, but give it a paranoid clamp just in case. + icon_state = "charge[chargeNum]" + else + icon_state = "charge-empty" diff --git a/code/_onclick/hud/screen/screen_pai.dm b/code/_onclick/hud/screen/screen_pai.dm new file mode 100644 index 000000000000..08de1ff85060 --- /dev/null +++ b/code/_onclick/hud/screen/screen_pai.dm @@ -0,0 +1,91 @@ +/obj/screen/pai + icon = 'icons/mob/screen/pai.dmi' + abstract_type = /obj/screen/pai + requires_ui_style = FALSE + user_incapacitation_flags = INCAPACITATION_KNOCKOUT + use_supplied_ui_alpha = FALSE + use_supplied_ui_color = FALSE + use_supplied_ui_icon = FALSE + +/obj/screen/pai/software + name = "Software Interface" + icon_state = "pai" + screen_loc = ui_pai_software + +/obj/screen/pai/software/handle_click(mob/user, params) + var/mob/living/silicon/pai/pai = user + if(istype(pai)) + pai.paiInterface() + +/obj/screen/pai/shell + name = "Toggle Chassis" + icon_state = "pai_holoform" + screen_loc = ui_pai_shell + +/obj/screen/pai/shell/handle_click(mob/user, params) + var/mob/living/silicon/pai/pai = user + if(istype(pai)) + if(pai.is_in_card) + pai.unfold() + else + pai.fold() + +/obj/screen/pai/chassis + name = "Holochassis Appearance Composite" + icon_state = "pai_holoform" + +/obj/screen/pai/rest + name = "Rest" + icon_state = "pai_rest" + screen_loc = ui_pai_rest + +/obj/screen/pai/rest/handle_click(mob/user, params) + var/mob/living/silicon/pai/pai = user + if(istype(pai)) + pai.lay_down() + +/obj/screen/pai/light + name = "Toggle Integrated Lights" + icon_state = "light" + screen_loc = ui_pai_light + +/obj/screen/pai/light/handle_click(mob/user, params) + var/mob/living/silicon/pai/pai = user + if(istype(pai)) + pai.toggle_integrated_light() + +/obj/screen/pai/subsystems + name = "Subsystems" + icon_state = "subsystems" + screen_loc = ui_pai_subsystems + +/obj/screen/pai/subsystems/handle_click(mob/user, params) + var/mob/living/silicon/pai/pai = user + if(istype(pai)) + var/ss_name = input(user, "Activates the given subsystem", "Subsystems", "") in pai.silicon_subsystems_by_name + if (!ss_name) + return + var/stat_silicon_subsystem/SSS = pai.silicon_subsystems_by_name[ss_name] + if(istype(SSS)) + SSS.Click() + +/decl/hud_element/pai + abstract_type = /decl/hud_element/pai + +/decl/hud_element/pai/shell + elem_type = /obj/screen/pai/shell + +/decl/hud_element/pai/rest + elem_type = /obj/screen/pai/rest + +/decl/hud_element/pai/light + elem_type = /obj/screen/pai/light + +/decl/hud_element/pai/software + elem_type = /obj/screen/pai/software + +/decl/hud_element/pai/chassis + elem_type = /obj/screen/pai/chassis + +/decl/hud_element/pai/subsystems + elem_type = /obj/screen/pai/subsystems diff --git a/code/_onclick/hud/screen/screen_radial.dm b/code/_onclick/hud/screen/screen_radial.dm new file mode 100644 index 000000000000..4bbdec390087 --- /dev/null +++ b/code/_onclick/hud/screen/screen_radial.dm @@ -0,0 +1,69 @@ +/obj/screen/radial + icon = 'icons/screen/radial.dmi' + layer = HUD_ABOVE_ITEM_LAYER + plane = HUD_PLANE + requires_owner = FALSE + requires_ui_style = FALSE + var/datum/radial_menu/parent + +/obj/screen/radial/Destroy() + parent = null + return ..() + +/obj/screen/radial/slice + icon_state = "radial_slice" + var/choice + var/next_page = FALSE + var/tooltips = FALSE + +/obj/screen/radial/slice/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_slice_focus" + if(tooltips) + openToolTip(usr, src, params, title = name) + +/obj/screen/radial/slice/MouseExited(location, control, params) + . = ..() + icon_state = "radial_slice" + if(tooltips) + closeToolTip(usr) + +/obj/screen/radial/slice/handle_click(mob/user, params) + if(parent && user.client == parent.current_user) + if(next_page) + parent.next_page() + else + parent.element_chosen(choice, user) + +/obj/screen/radial/center + name = "Close Menu" + icon_state = "radial_center" + +/obj/screen/radial/center/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_center_focus" + +/obj/screen/radial/center/MouseExited(location, control, params) + . = ..() + icon_state = "radial_center" + +/obj/screen/radial/center/handle_click(mob/user, params) + if(user.client == parent.current_user) + parent.finished = TRUE + + +/obj/screen/radial/persistent/center + name = "Close Menu" + icon_state = "radial_center" + +/obj/screen/radial/persistent/center/handle_click(mob/user, params) + if(user.client == parent.current_user) + parent.element_chosen(null,user) + +/obj/screen/radial/persistent/center/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_center_focus" + +/obj/screen/radial/persistent/center/MouseExited(location, control, params) + . = ..() + icon_state = "radial_center" diff --git a/code/_onclick/hud/screen/screen_resist.dm b/code/_onclick/hud/screen/screen_resist.dm new file mode 100644 index 000000000000..ff781aa09c7a --- /dev/null +++ b/code/_onclick/hud/screen/screen_resist.dm @@ -0,0 +1,11 @@ +/obj/screen/resist + name = "resist" + icon_state = "act_resist" + screen_loc = ui_pull_resist + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/resist/handle_click(mob/user, params) + if(isliving(user)) + var/mob/living/L = user + L.resist() diff --git a/code/_onclick/hud/screen/screen_setup.dm b/code/_onclick/hud/screen/screen_setup.dm new file mode 100644 index 000000000000..eaa68e8feb98 --- /dev/null +++ b/code/_onclick/hud/screen/screen_setup.dm @@ -0,0 +1,27 @@ +// Character setup stuff +/obj/screen/setup_preview + icon = 'icons/effects/64x48.dmi' + plane = DEFAULT_PLANE + layer = MOB_LAYER + requires_owner = FALSE + requires_ui_style = FALSE + var/datum/preferences/pref + +/obj/screen/setup_preview/Destroy() + pref = null + return ..() + +// Background 'floor' +/obj/screen/setup_preview/bg + layer = TURF_LAYER + mouse_over_pointer = MOUSE_HAND_POINTER + screen_loc = "character_preview_map:1,1 to 1,5" + +// Uses Click() instead of handle_click() due to being accessed by new_player mobs. +/obj/screen/setup_preview/bg/Click(location, control, params) + if(pref) + pref.bgstate = next_in_list(pref.bgstate, global.using_map.char_preview_bgstate_options) + var/mob/living/human/dummy/mannequin/mannequin = get_mannequin(pref.client_ckey) + if(mannequin) + pref.update_character_previews(mannequin) + return ..() diff --git a/code/_onclick/hud/screen/screen_stamina.dm b/code/_onclick/hud/screen/screen_stamina.dm new file mode 100644 index 000000000000..851fdf1d8682 --- /dev/null +++ b/code/_onclick/hud/screen/screen_stamina.dm @@ -0,0 +1,41 @@ +/obj/screen/stamina + name = "stamina" + icon = 'icons/effects/staminabar.dmi' + icon_state = "bar" + invisibility = INVISIBILITY_MAXIMUM + use_supplied_ui_color = FALSE + use_supplied_ui_alpha = FALSE + use_supplied_ui_icon = FALSE + requires_ui_style = FALSE + layer = HUD_BASE_LAYER + 0.1 // needs to layer over the movement intent element + var/const/STAMINA_STATE_PERIOD = 5 + +/obj/screen/stamina/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + update_icon() + +/obj/screen/stamina/on_update_icon() + . = ..() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner)) + set_invisibility(INVISIBILITY_MAXIMUM) + return + + var/hand_row_offset = /datum/hud::HAND_UI_INITIAL_Y_OFFSET + (ceil(length(owner.get_held_item_slots()) / /datum/hud::HAND_UI_PER_ROW) * world.icon_size) + 16 + screen_loc = "CENTER:-32,BOTTOM:[hand_row_offset]" + + var/stamina = owner.get_stamina() + cut_overlays() + if(stamina < 100) + set_invisibility(INVISIBILITY_NONE) + var/stamina_amt = floor(stamina/STAMINA_STATE_PERIOD)*STAMINA_STATE_PERIOD + var/bar_overlay_state = "bar_[stamina_amt]" + if(stamina_amt > 0 && stamina <= 25) + bar_overlay_state = "[bar_overlay_state]_fail" + var/image/bar_overlay = image(icon = icon, icon_state = bar_overlay_state) + bar_overlay.appearance_flags |= RESET_COLOR + bar_overlay.color = COLOR_WHITE + add_overlay(bar_overlay) + else + set_invisibility(INVISIBILITY_MAXIMUM) + compile_overlays() \ No newline at end of file diff --git a/code/_onclick/hud/screen/screen_storage.dm b/code/_onclick/hud/screen/screen_storage.dm new file mode 100644 index 000000000000..cff8f824ad79 --- /dev/null +++ b/code/_onclick/hud/screen/screen_storage.dm @@ -0,0 +1,61 @@ +/obj/screen/storage + name = "storage" + icon = 'icons/mob/screen/storage.dmi' + user_incapacitation_flags = INCAPACITATION_DISRUPTED + screen_loc = ui_storage_default + layer = HUD_BASE_LAYER + requires_owner = FALSE + requires_ui_style = FALSE + var/weakref/storage_master_ref + +/obj/screen/storage/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat, datum/storage/_storage_master) + . = ..() + storage_master_ref = _storage_master && weakref(_storage_master) + +/obj/screen/storage/handle_click(mob/user, params) + var/datum/storage/storage_master = storage_master_ref?.resolve() + if(istype(storage_master) && !QDELETED(storage_master) && isatom(storage_master.holder)) + var/obj/item/I = user.get_active_held_item() + if(I) + user.ClickOn(storage_master.holder) + return TRUE + return FALSE + +/obj/screen/storage/start + icon_state = "storage_start" + +/obj/screen/storage/cont + icon_state = "storage_continue" + +/obj/screen/storage/boxes + icon_state = "block" + +/obj/screen/storage/end + icon_state = "storage_end" + +/obj/screen/storage/close + name = "close" + icon = 'icons/effects/markers.dmi' + icon_state = "x" + layer = HUD_BASE_LAYER + +/obj/screen/storage/close/handle_click(mob/user, params) + var/datum/storage/storage_master = storage_master_ref?.resolve() + if(istype(storage_master) && !QDELETED(storage_master)) + storage_master.close(user) + return TRUE + return FALSE + +/obj/screen/stored + layer = HUD_BASE_LAYER + requires_owner = FALSE + requires_ui_style = FALSE + +/obj/screen/stored/start + icon_state = "stored_start" + +/obj/screen/stored/cont + icon_state = "stored_continue" + +/obj/screen/stored/end + icon_state = "stored_end" diff --git a/code/_onclick/hud/screen/screen_swaphands.dm b/code/_onclick/hud/screen/screen_swaphands.dm new file mode 100644 index 000000000000..037602bf9dda --- /dev/null +++ b/code/_onclick/hud/screen/screen_swaphands.dm @@ -0,0 +1,9 @@ +/obj/screen/inventory/swaphand + name = "hand" + icon_state = "hand1" + +/obj/screen/inventory/swaphand/handle_click(mob/user, params) + user.swap_hand() + +/obj/screen/inventory/swaphand/right + icon_state = "hand2" diff --git a/code/_onclick/hud/screen/screen_throw.dm b/code/_onclick/hud/screen/screen_throw.dm new file mode 100644 index 000000000000..5d2d9888ec02 --- /dev/null +++ b/code/_onclick/hud/screen/screen_throw.dm @@ -0,0 +1,16 @@ +/obj/screen/throw_toggle + name = "throw" + icon_state = "act_throw_off" + screen_loc = ui_drop_throw + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/throw_toggle/handle_click(mob/user, params) + if(!user.stat && isturf(user.loc) && !user.restrained()) + user.toggle_throw_mode() + +/obj/screen/throw_toggle/on_update_icon() + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner)) + icon_state = "act_throw_[owner.in_throw_mode ? "on" : "off"]" + . = ..() diff --git a/code/_onclick/hud/screen/screen_toggle.dm b/code/_onclick/hud/screen/screen_toggle.dm new file mode 100644 index 000000000000..ddcf626e8c26 --- /dev/null +++ b/code/_onclick/hud/screen/screen_toggle.dm @@ -0,0 +1,11 @@ +/obj/screen/toggle + name = "toggle" + icon_state = "other" + screen_loc = ui_inventory + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/toggle/handle_click(mob/user, params) + if(!user.hud_used) + return + return user.hud_used.toggle_show_inventory() diff --git a/code/_onclick/hud/screen/screen_up_hint.dm b/code/_onclick/hud/screen/screen_up_hint.dm new file mode 100644 index 000000000000..4a97f61be1a5 --- /dev/null +++ b/code/_onclick/hud/screen/screen_up_hint.dm @@ -0,0 +1,17 @@ +/obj/screen/look_upward + name = "up hint" + icon_state = "uphint0" + screen_loc = ui_up_hint + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/look_upward/handle_click(mob/user, params) + if(isliving(user)) + var/mob/living/L = user + L.lookup() + +/obj/screen/look_upward/on_update_icon() + var/mob/owner = owner_ref?.resolve() + var/turf/above = istype(owner) ? GetAbove(get_turf(owner)) : null + icon_state = "uphint[!!(istype(above) && TURF_IS_MIMICKING(above))]" + ..() diff --git a/code/_onclick/hud/screen/screen_warning.dm b/code/_onclick/hud/screen/screen_warning.dm new file mode 100644 index 000000000000..f7aad53c4872 --- /dev/null +++ b/code/_onclick/hud/screen/screen_warning.dm @@ -0,0 +1,12 @@ +/obj/screen/warning + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + var/base_state + var/check_alert + +/obj/screen/warning/on_update_icon() + . = ..() + if(base_state && check_alert) + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner)) + icon_state = "[base_state][GET_HUD_ALERT(owner, check_alert)]" diff --git a/code/_onclick/hud/screen/screen_warning_bodytemp.dm b/code/_onclick/hud/screen/screen_warning_bodytemp.dm new file mode 100644 index 000000000000..88bdafba7dfa --- /dev/null +++ b/code/_onclick/hud/screen/screen_warning_bodytemp.dm @@ -0,0 +1,90 @@ + +/obj/screen/warning/bodytemp + name = "body temperature" + icon = 'icons/mob/screen/styles/status_bodytemp.dmi' + icon_state = "temp1" + screen_loc = ui_temp + +/obj/screen/warning/bodytemp/on_update_icon() + . = ..() + + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner)) + return + + var/decl/species/my_species = owner.get_species() + if(!my_species) + switch(owner.bodytemperature) //310.055 optimal body temp + if(370 to INFINITY) + icon_state = "temp4" + if(350 to 370) + icon_state = "temp3" + if(335 to 350) + icon_state = "temp2" + if(320 to 335) + icon_state = "temp1" + if(300 to 320) + icon_state = "temp0" + if(295 to 300) + icon_state = "temp-1" + if(280 to 295) + icon_state = "temp-2" + if(260 to 280) + icon_state = "temp-3" + else + icon_state = "temp-4" + return + + var/heat_1 = owner.get_mob_temperature_threshold(HEAT_LEVEL_1) + var/cold_1 = owner.get_mob_temperature_threshold(COLD_LEVEL_1) + + //TODO: precalculate all of this stuff when the species datum is created + var/base_temperature = my_species.body_temperature + if(base_temperature == null) //some species don't have a set metabolic temperature + base_temperature = (heat_1 + cold_1)/2 + + if (owner.bodytemperature >= base_temperature) + var/temp_step = (heat_1 - base_temperature)/4 + if (owner.bodytemperature >= heat_1) + icon_state = "temp4" + else if (owner.bodytemperature >= base_temperature + temp_step*3) + icon_state = "temp3" + else if (owner.bodytemperature >= base_temperature + temp_step*2) + icon_state = "temp2" + else if (owner.bodytemperature >= base_temperature + temp_step*1) + icon_state = "temp1" + else + icon_state = "temp0" + else if (owner.bodytemperature < base_temperature) + var/temp_step = (base_temperature - cold_1)/4 + if (owner.bodytemperature <= cold_1) + icon_state = "temp-4" + else if (owner.bodytemperature <= base_temperature - temp_step*3) + icon_state = "temp-3" + else if (owner.bodytemperature <= base_temperature - temp_step*2) + icon_state = "temp-2" + else if (owner.bodytemperature <= base_temperature - temp_step*1) + icon_state = "temp-1" + else + icon_state = "temp0" + +/obj/screen/warning/bodytemp/handle_click(mob/user, params) + switch(icon_state) + if("temp4") + to_chat(user, SPAN_DANGER("You are being cooked alive!")) + if("temp3") + to_chat(user, SPAN_DANGER("Your body is burning up!")) + if("temp2") + to_chat(user, SPAN_DANGER("You are overheating.")) + if("temp1") + to_chat(user, SPAN_WARNING("You are uncomfortably hot.")) + if("temp-4") + to_chat(user, SPAN_DANGER("You are being frozen solid!")) + if("temp-3") + to_chat(user, SPAN_DANGER("You are freezing cold!")) + if("temp-2") + to_chat(user, SPAN_WARNING("You are dangerously chilled!")) + if("temp-1") + to_chat(user, SPAN_NOTICE("You are uncomfortably cold.")) + else + to_chat(user, SPAN_NOTICE("Your body is at a comfortable temperature.")) diff --git a/code/_onclick/hud/screen/screen_warning_fire.dm b/code/_onclick/hud/screen/screen_warning_fire.dm new file mode 100644 index 000000000000..ec39eb5fa636 --- /dev/null +++ b/code/_onclick/hud/screen/screen_warning_fire.dm @@ -0,0 +1,6 @@ +/obj/screen/warning/fire + name = "fire" + icon_state = "fire0" + screen_loc = ui_fire + base_state = "fire" + check_alert = /decl/hud_element/fire diff --git a/code/_onclick/hud/screen/screen_warning_oxygen.dm b/code/_onclick/hud/screen/screen_warning_oxygen.dm new file mode 100644 index 000000000000..507e80dea53d --- /dev/null +++ b/code/_onclick/hud/screen/screen_warning_oxygen.dm @@ -0,0 +1,34 @@ +/obj/screen/warning/oxygen + name = "oxygen" + icon = 'icons/mob/screen/styles/status_oxy.dmi' + icon_state = "oxy0" + screen_loc = ui_temp + base_state = "oxy" + check_alert = /decl/hud_element/oxygen + +/obj/screen/warning/oxygen/handle_click(mob/user, params) + if(icon_state == "oxy0") + to_chat(user, SPAN_NOTICE("You are breathing easy.")) + else + to_chat(user, SPAN_DANGER("You cannot breathe!")) + +// Robots use this warning icon as an environment indicator, not based on our own tolerances. +/obj/screen/warning/oxygen/robot + screen_loc = ui_oxygen + +/obj/screen/warning/oxygen/robot/on_update_icon() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner)) + return + var/datum/gas_mixture/environment = owner.loc?.return_air() + if(!environment) + return + var/decl/species/species = decls_repository.get_decl_by_id(global.using_map.default_species) + if(!species.breath_type || environment.gas[species.breath_type] > species.breath_pressure) + for(var/gas in species.poison_types) + if(environment.gas[gas]) + icon_state = "oxy1" + return + icon_state = "oxy0" + else + icon_state = "oxy1" diff --git a/code/_onclick/hud/screen/screen_warning_pressure.dm b/code/_onclick/hud/screen/screen_warning_pressure.dm new file mode 100644 index 000000000000..cd77e8d8c0db --- /dev/null +++ b/code/_onclick/hud/screen/screen_warning_pressure.dm @@ -0,0 +1,20 @@ +/obj/screen/warning/pressure + name = "pressure" + icon = 'icons/mob/screen/styles/status_pressure.dmi' + icon_state = "pressure0" + screen_loc = ui_temp + base_state = "pressure" + check_alert = /decl/hud_element/pressure + +/obj/screen/warning/pressure/handle_click(mob/user, params) + switch(icon_state) + if("pressure2") + to_chat(user, SPAN_DANGER("The air pressure here is crushing!")) + if("pressure1") + to_chat(user, SPAN_WARNING("The air pressure here is dangerously high.")) + if("pressure-1") + to_chat(user, SPAN_WARNING("The air pressure here is dangerously low.")) + if("pressure-2") + to_chat(user, SPAN_DANGER("There is nearly no air pressure here!")) + else + to_chat(user, SPAN_NOTICE("The local air pressure is comfortable.")) diff --git a/code/_onclick/hud/screen/screen_warning_toxins.dm b/code/_onclick/hud/screen/screen_warning_toxins.dm new file mode 100644 index 000000000000..ef8c391491be --- /dev/null +++ b/code/_onclick/hud/screen/screen_warning_toxins.dm @@ -0,0 +1,13 @@ +/obj/screen/warning/toxin + name = "toxin" + icon = 'icons/mob/screen/styles/status_tox.dmi' + icon_state = "tox0" + screen_loc = ui_temp + base_state = "tox" + check_alert = /decl/hud_element/toxins + +/obj/screen/warning/toxin/handle_click(mob/user, params) + if(icon_state == "tox0") + to_chat(user, SPAN_NOTICE("The air is clear of toxins.")) + else + to_chat(user, SPAN_DANGER("The air is eating away at your skin!")) diff --git a/code/_onclick/hud/screen/screen_zone_selector.dm b/code/_onclick/hud/screen/screen_zone_selector.dm new file mode 100644 index 000000000000..567b5645da3d --- /dev/null +++ b/code/_onclick/hud/screen/screen_zone_selector.dm @@ -0,0 +1,77 @@ +/obj/screen/zone_selector + name = "damage zone" + icon_state = "zone_sel_tail" + screen_loc = ui_zonesel + use_supplied_ui_color = TRUE + use_supplied_ui_alpha = TRUE + +/obj/screen/zone_selector/handle_click(mob/user, params) + var/list/PL = params2list(params) + var/icon_x = text2num(PL["icon-x"]) + var/icon_y = text2num(PL["icon-y"]) + var/new_selecting + switch(icon_y) + if(1 to 3) //Feet + switch(icon_x) + if(10 to 15) + new_selecting = BP_R_FOOT + if(17 to 22) + new_selecting = BP_L_FOOT + else + return 1 + if(4 to 9) //Legs + switch(icon_x) + if(10 to 15) + new_selecting = BP_R_LEG + if(17 to 22) + new_selecting = BP_L_LEG + if(23 to 28) + new_selecting = BP_TAIL + else + return 1 + if(10 to 13) //Hands and groin + switch(icon_x) + if(8 to 11) + new_selecting = BP_R_HAND + if(12 to 20) + new_selecting = BP_GROIN + if(21 to 24) + new_selecting = BP_L_HAND + else + return 1 + if(14 to 22) //Chest and arms to shoulders + switch(icon_x) + if(8 to 11) + new_selecting = BP_R_ARM + if(12 to 20) + new_selecting = BP_CHEST + if(21 to 24) + new_selecting = BP_L_ARM + else + return 1 + if(23 to 30) //Head, but we need to check for eye or mouth + if(icon_x in 12 to 20) + new_selecting = BP_HEAD + switch(icon_y) + if(23 to 24) + if(icon_x in 15 to 17) + new_selecting = BP_MOUTH + if(26) //Eyeline, eyes are on 15 and 17 + if(icon_x in 14 to 18) + new_selecting = BP_EYES + if(25 to 27) + if(icon_x in 15 to 17) + new_selecting = BP_EYES + user.set_target_zone(new_selecting) + return TRUE + +/obj/screen/zone_selector/proc/set_selected_zone(new_zone, old_zone) + if(new_zone != old_zone) + update_icon() + return TRUE + +/obj/screen/zone_selector/rebuild_screen_overlays() + ..() + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner)) + add_overlay(image('icons/mob/zone_sel.dmi', "[owner.selected_zone]")) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm deleted file mode 100644 index 7c26210e4e3f..000000000000 --- a/code/_onclick/hud/screen_objects.dm +++ /dev/null @@ -1,391 +0,0 @@ -/* - Screen objects - Todo: improve/re-implement - - Screen objects are only used for the hud and should not appear anywhere "in-game". - They are used with the client/screen list and the screen_loc var. - For more information, see the byond documentation on the screen_loc and screen vars. -*/ -/obj/screen - name = "" - icon = 'icons/mob/screen1.dmi' - plane = HUD_PLANE - layer = HUD_BASE_LAYER - appearance_flags = NO_CLIENT_COLOR - unacidable = 1 - var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. - var/globalscreen = FALSE //Global screens are not qdeled when the holding mob is destroyed. - -/obj/screen/Destroy() - master = null - return ..() - -/obj/screen/text - icon = null - icon_state = null - mouse_opacity = 0 - screen_loc = "CENTER-7,CENTER-7" - maptext_height = 480 - maptext_width = 480 - - -/obj/screen/inventory - var/slot_id //The indentifier for the slot. It has nothing to do with ID cards. - - -/obj/screen/close - name = "close" - -/obj/screen/close/Click() - if(master) - if(istype(master, /obj/item/storage)) - var/obj/item/storage/S = master - S.close(usr) - return 1 - - -/obj/screen/item_action - var/obj/item/owner - -/obj/screen/item_action/Destroy() - owner = null - . = ..() - -/obj/screen/item_action/Click() - if(!usr || !owner) - return 1 - if(!usr.canClick()) - return - - if(usr.stat || usr.restrained() || usr.stunned || usr.lying) - return 1 - - if(!(owner in usr)) - return 1 - - owner.ui_action_click() - return 1 - -/obj/screen/storage - name = "storage" - -/obj/screen/storage/Click() - if(!usr.canClick()) - return 1 - if(usr.stat || usr.paralysis || usr.stunned || usr.weakened) - return 1 - if(master) - var/obj/item/I = usr.get_active_hand() - if(I) - usr.ClickOn(master) - return 1 - -/obj/screen/zone_sel - name = "damage zone" - icon_state = "zone_sel" - screen_loc = ui_zonesel - var/selecting = BP_CHEST - -/obj/screen/zone_sel/Click(location, control,params) - var/list/PL = params2list(params) - var/icon_x = text2num(PL["icon-x"]) - var/icon_y = text2num(PL["icon-y"]) - var/new_selecting - - switch(icon_y) - if(1 to 3) //Feet - switch(icon_x) - if(10 to 15) - new_selecting = BP_R_FOOT - if(17 to 22) - new_selecting = BP_L_FOOT - else - return 1 - if(4 to 9) //Legs - switch(icon_x) - if(10 to 15) - new_selecting = BP_R_LEG - if(17 to 22) - new_selecting = BP_L_LEG - else - return 1 - if(10 to 13) //Hands and groin - switch(icon_x) - if(8 to 11) - new_selecting = BP_R_HAND - if(12 to 20) - new_selecting = BP_GROIN - if(21 to 24) - new_selecting = BP_L_HAND - else - return 1 - if(14 to 22) //Chest and arms to shoulders - switch(icon_x) - if(8 to 11) - new_selecting = BP_R_ARM - if(12 to 20) - new_selecting = BP_CHEST - if(21 to 24) - new_selecting = BP_L_ARM - else - return 1 - if(23 to 30) //Head, but we need to check for eye or mouth - if(icon_x in 12 to 20) - new_selecting = BP_HEAD - switch(icon_y) - if(23 to 24) - if(icon_x in 15 to 17) - new_selecting = BP_MOUTH - if(26) //Eyeline, eyes are on 15 and 17 - if(icon_x in 14 to 18) - new_selecting = BP_EYES - if(25 to 27) - if(icon_x in 15 to 17) - new_selecting = BP_EYES - - set_selected_zone(new_selecting) - return 1 - -/obj/screen/zone_sel/proc/set_selected_zone(bodypart) - var/old_selecting = selecting - selecting = bodypart - if(old_selecting != selecting) - update_icon() - return TRUE - -/obj/screen/zone_sel/on_update_icon() - overlays.Cut() - overlays += image('icons/mob/zone_sel.dmi', "[selecting]") - -/obj/screen/intent - name = "intent" - icon = 'icons/mob/screen/white.dmi' - icon_state = "intent_help" - screen_loc = ui_acti - var/intent = I_HELP - -/obj/screen/intent/Click(var/location, var/control, var/params) - var/list/P = params2list(params) - var/icon_x = text2num(P["icon-x"]) - var/icon_y = text2num(P["icon-y"]) - intent = I_DISARM - if(icon_x <= world.icon_size/2) - if(icon_y <= world.icon_size/2) - intent = I_HURT - else - intent = I_HELP - else if(icon_y <= world.icon_size/2) - intent = I_GRAB - update_icon() - usr.a_intent = intent - -/obj/screen/intent/on_update_icon() - icon_state = "intent_[intent]" - -/obj/screen/Click(location, control, params) - if(!usr) return 1 - switch(name) - if("toggle") - if(usr.hud_used.inventory_shown) - usr.hud_used.inventory_shown = 0 - usr.client.screen -= usr.hud_used.other - else - usr.hud_used.inventory_shown = 1 - usr.client.screen += usr.hud_used.other - - usr.hud_used.hidden_inventory_update() - - if("equip") - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - H.quick_equip() - - if("resist") - if(isliving(usr)) - var/mob/living/L = usr - L.resist() - - if("Reset Machine") - usr.unset_machine() - - if("up hint") - if(isliving(usr)) - var/mob/living/L = usr - L.lookup() - - if("internal") - if(iscarbon(usr)) - var/mob/living/carbon/C = usr - if(!C.stat && !C.stunned && !C.paralysis && !C.restrained()) - if(C.internal) - C.set_internals(null) - else - - var/no_mask - if(!(C.wear_mask && C.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) - var/mob/living/carbon/human/H = C - if(!(H.head && H.head.item_flags & ITEM_FLAG_AIRTIGHT)) - no_mask = 1 - - if(no_mask) - to_chat(C, "You are not wearing a suitable mask or helmet.") - return 1 - else - var/list/nicename = null - var/list/tankcheck = null - var/breathes = /decl/material/gas/oxygen //default, we'll check later - var/poisons = list(/decl/material/gas/chlorine) - var/list/contents = list() - var/from = "on" - - if(ishuman(C)) - var/mob/living/carbon/human/H = C - breathes = H.species.breath_type - poisons = H.species.poison_types - nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket") - tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store) - else - nicename = list("right hand", "left hand", "back") - tankcheck = list(C.r_hand, C.l_hand, C.back) - - // Rigs are a fucking pain since they keep an air tank in nullspace. - if(istype(C.back,/obj/item/rig)) - var/obj/item/rig/rig = C.back - if(rig.air_supply) - from = "in" - nicename |= "hardsuit" - tankcheck |= rig.air_supply - - for(var/i=1, i bestcontents) - best = i - bestcontents = contents[i] - - - //We've determined the best container now we set it as our internals - - if(best) - C.set_internals(tankcheck[best], "\the [tankcheck[best]] [from] your [nicename[best]]") - - if(!C.internal) - to_chat(C, "You don't have \a [breathes] tank.") - if("act_intent") - usr.a_intent_change("right") - - if("throw") - if(!usr.stat && isturf(usr.loc) && !usr.restrained()) - usr.toggle_throw_mode() - if("drop") - if(usr.client) - usr.client.drop_item() - - if("module") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - R.pick_module() - - if("inventory") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - if(R.module) - R.hud_used.toggle_show_robot_modules() - return 1 - else - to_chat(R, "You haven't selected a module yet.") - - if("radio") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - R.radio_menu() - if("panel") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - R.installed_modules() - - if("store") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - if(R.module) - R.uneq_active() - R.hud_used.update_robot_modules_display() - else - to_chat(R, "You haven't selected a module yet.") - - if("module1") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - R.toggle_module(1) - - if("module2") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - R.toggle_module(2) - - if("module3") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - R.toggle_module(3) - else - return 0 - return 1 - -/obj/screen/inventory/Click() - // At this point in client Click() code we have passed the 1/10 sec check and little else - // We don't even know if it's a middle click - if(!usr.canClick()) - return 1 - if(usr.incapacitated()) - return 1 - switch(name) - if("r_hand") - if(iscarbon(usr)) - var/mob/living/carbon/C = usr - if(C.hand) - C.activate_hand("r") - else - C.attack_empty_hand(BP_R_HAND) - if("l_hand") - if(iscarbon(usr)) - var/mob/living/carbon/C = usr - if(!C.hand) - C.activate_hand("l") - else - C.attack_empty_hand(BP_L_HAND) - if("swap") - usr:swap_hand() - if("hand") - usr:swap_hand() - else - if(usr.attack_ui(slot_id)) - usr.update_inv_l_hand(0) - usr.update_inv_r_hand(0) - return 1 diff --git a/code/_onclick/hud/skybox.dm b/code/_onclick/hud/skybox.dm index d2916d20537d..03cdfaf1dab1 100644 --- a/code/_onclick/hud/skybox.dm +++ b/code/_onclick/hud/skybox.dm @@ -1,19 +1,19 @@ -#define SKYBOX_MAX_BOUND 736 - +var/global/const/SKYBOX_DIMENSION = 736 // Largest measurement for icon sides, used for offsets/scaling /obj/skybox name = "skybox" - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE anchored = TRUE simulated = FALSE plane = SKYBOX_PLANE blend_mode = BLEND_MULTIPLY - var/base_x_dim = 7 - var/base_y_dim = 7 - var/base_offset_x = -224 // -(world.view x dimension * world.icon_size) - var/base_offset_y = -224 // -(world.view y dimension * world.icon_size) + screen_loc = "CENTER,CENTER" + transform_animate_time = 0 + var/static/max_view_dim + var/static/const/parallax_bleed_percent = 0.2 // 20% parallax offset when going from x=1 to x=max /obj/skybox/Initialize() - screen_loc = "CENTER:[base_offset_x],CENTER:[base_offset_y]" + if(!max_view_dim) + max_view_dim = ceil(SKYBOX_DIMENSION / world.icon_size) . = ..() /client @@ -21,40 +21,45 @@ /client/proc/set_skybox_offsets(var/x_dim, var/y_dim) if(!skybox) - update_skybox() - if(skybox) - skybox.base_x_dim = x_dim - skybox.base_y_dim = y_dim - skybox.base_offset_x = -((world.icon_size * skybox.base_x_dim)/2) - skybox.base_offset_y = -((world.icon_size * skybox.base_y_dim)/2) - - // Check if the skybox needs to be scaled to fit large displays. - var/new_max_tile_bound = max(skybox.base_x_dim, skybox.base_y_dim) - var/old_max_tile_bound = SKYBOX_MAX_BOUND/world.icon_size - if(new_max_tile_bound > old_max_tile_bound) - var/matrix/M = matrix() - M.Scale(1 + (new_max_tile_bound/old_max_tile_bound)) - skybox.transform = M - else - skybox.transform = null - update_skybox() + update_skybox(TRUE) + return + var/scale_value = 1 + if(isnum(view)) + var/target_icon_size = (view * 2 + 1) * world.icon_size + scale_value = skybox.parallax_bleed_percent + max((target_icon_size / SKYBOX_DIMENSION), 1) + skybox.screen_loc = "CENTER:-[view * world.icon_size],CENTER:-[view * world.icon_size]" + else + var/target_icon_size = max(x_dim, y_dim) * world.icon_size + scale_value = skybox.parallax_bleed_percent + max((target_icon_size / SKYBOX_DIMENSION), 1) + skybox.screen_loc = "CENTER:-[round(SKYBOX_DIMENSION * scale_value / 2)],CENTER:-[round(SKYBOX_DIMENSION * scale_value / 2)]" + skybox.set_scale(scale_value) + update_skybox() /client/proc/update_skybox(rebuild) + + var/turf/T = get_turf(eye) + if(!T) + return + if(!skybox) skybox = new() screen += skybox - rebuild = 1 - var/turf/T = get_turf(eye) - if(T) - if(rebuild) - skybox.overlays.Cut() - skybox.overlays += SSskybox.get_skybox(T.z) - screen |= skybox - skybox.screen_loc = "CENTER:[skybox.base_offset_x - T.x],CENTER:[skybox.base_offset_y - T.y]" + rebuild = TRUE + + if(rebuild) + skybox.overlays.Cut() + var/image/I = SSskybox.get_skybox(T.z) + skybox.overlays += I + screen |= skybox + set_skybox_offsets(last_view_x_dim, last_view_y_dim) + return -/mob/Login() - ..() - client.update_skybox(1) + if(skybox.parallax_bleed_percent > 0) + var/matrix/M = skybox.update_transform() || matrix() + var/x_translate = -((T.x/world.maxx)-0.5) * skybox.parallax_bleed_percent * SKYBOX_DIMENSION + var/y_translate = -((T.y/world.maxy)-0.5) * skybox.parallax_bleed_percent * SKYBOX_DIMENSION + M.Translate(x_translate, y_translate) + skybox.transform = M /mob/Move() var/old_z = get_z(src) @@ -67,5 +72,3 @@ . = ..() if(. && client) client.update_skybox(old_z != get_z(src)) - -#undef SKYBOX_MAX_BOUND \ No newline at end of file diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 3805c51a678c..f38f1a25e243 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -5,12 +5,12 @@ These are the default click code call sequences used when clicking on stuff with Atoms: mob/ClickOn() calls the item's resolve_attackby() proc. -item/resolve_attackby() calls the target atom's attackby() proc. +item/resolve_attackby() calls the target atom's attackby() proc. If it (or attackby) returns true, afterattack is skipped. Mobs: -mob/living/attackby() after checking for surgery, calls the item's attack() proc. -item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself. +mob/living/attackby() after checking for surgery, calls the item's use_on_mob() proc. +item/use_on_mob() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself. mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit. Item Hit Effects: @@ -21,56 +21,89 @@ avoid code duplication. This includes items that may sometimes act as a standard // Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. /obj/item/proc/attack_self(mob/user) - return + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + return (tool?.handle_physical_manipulation(user)) || FALSE -//I would prefer to rename this to attack(), but that would involve touching hundreds of files. +// If TRUE, prevent afterattack from running. /obj/item/proc/resolve_attackby(atom/A, mob/user, var/click_params) + if(!user.check_dexterity(get_required_attack_dexterity(user, A))) + return TRUE if(!(item_flags & ITEM_FLAG_NO_PRINT)) add_fingerprint(user) return A.attackby(src, user, click_params) -// No comment -/atom/proc/attackby(obj/item/W, mob/user, var/click_params) - return +// If TRUE, prevent afterattack from running. +/atom/proc/attackby(obj/item/used_item, mob/user, var/click_params) + + if(try_handle_interactions(user, get_standard_interactions(user), user?.get_active_held_item(), check_alt_interactions = FALSE)) + return TRUE + + if(storage) + if(isrobot(user) && (used_item == user.get_active_held_item())) + return FALSE //Robots can't store their modules. + if(!storage.can_be_inserted(used_item, user, click_params = click_params)) + return FALSE + used_item.add_fingerprint(user) + return storage.handle_item_insertion(user, used_item, click_params = click_params) -/atom/movable/attackby(obj/item/W, mob/user) - return bash(W,user) + return FALSE -/atom/movable/proc/bash(obj/item/W, mob/user) - if(isliving(user) && user.a_intent == I_HELP) +/atom/movable/attackby(obj/item/used_item, mob/user) + . = ..() + if(!.) + return bash(used_item,user) + +// Return TRUE if further actions (afterattack, etc) should be prevented, FALSE if they can proceed. +/atom/movable/proc/bash(obj/item/weapon, mob/user) + if(isliving(user) && !user.check_intent(I_FLAG_HARM)) + return FALSE + if(!weapon.user_can_attack_with(user)) return FALSE - if(W.item_flags & ITEM_FLAG_NO_BLUDGEON) + if(weapon.item_flags & ITEM_FLAG_NO_BLUDGEON) return FALSE - visible_message("[src] has been hit by [user] with [W].") + visible_message(SPAN_DANGER("[src] has been hit by [user] with [weapon].")) return TRUE -/mob/living/attackby(obj/item/I, mob/user) +/mob/living/attackby(obj/item/used_item, mob/user) if(!ismob(user)) - return 0 - if(can_operate(src,user) && I.do_surgery(src,user)) //Surgery - return 1 - - if(user.a_intent == I_HELP && istype(I, /obj/item/clothing/head)) - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable) - if(hattable.hat) - to_chat(user, SPAN_WARNING("\The [src] is already wearing \the [hattable.hat].")) - return TRUE - if(user.unEquip(I) && hattable.wear_hat(src, I)) - user.visible_message(SPAN_NOTICE("\The [user] puts \the [I] on \the [src].")) - return TRUE - - return I.attack(src, user, user.zone_sel ? user.zone_sel.selecting : ran_zone()) - -/mob/living/carbon/human/attackby(obj/item/I, mob/user) - if(user == src && zone_sel.selecting == BP_MOUTH && can_devour(I, silent = TRUE)) + return TRUE + + if(!QDELETED(used_item) && user.check_intent(I_FLAG_HELP)) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, user.get_target_zone()) + if(length(E?.ailments)) + for(var/datum/ailment/ailment in E.ailments) + if(ailment.treated_by_item(used_item)) + ailment.was_treated_by_item(used_item, user, src) + return TRUE + + if(!user.check_intent(I_FLAG_HARM)) + if(can_operate(src, user) != OPERATE_DENY && used_item.do_surgery(src,user)) //Surgery + return TRUE + if(try_butcher_in_place(user, used_item)) + return TRUE + + if(istype(used_item, /obj/item/chems) && ATOM_IS_OPEN_CONTAINER(used_item) && has_extension(src, /datum/extension/milkable)) + var/datum/extension/milkable/milkable = get_extension(src, /datum/extension/milkable) + if(milkable.handle_milked(used_item, user)) + return TRUE + + if(used_item.has_edge() && has_extension(src, /datum/extension/shearable)) + var/datum/extension/shearable/shearable = get_extension(src, /datum/extension/shearable) + if(shearable.handle_sheared(used_item, user)) + return TRUE + + var/oldhealth = current_health + . = used_item.use_on_mob(src, user) + if(used_item.get_attack_force(user) && istype(ai) && current_health < oldhealth) + ai.retaliate(user) + + if(!. && user == src && user.get_target_zone() == BP_MOUTH && can_devour(used_item, silent = TRUE)) var/obj/item/blocked = src.check_mouth_coverage() if(blocked) to_chat(user, SPAN_WARNING("\The [blocked] is in the way!")) - return TRUE - if(devour(I)) - return TRUE - return ..() + else + devour(used_item) + return TRUE // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. @@ -82,46 +115,70 @@ avoid code duplication. This includes items that may sometimes act as a standard var/mob/living/attackee = null //I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files. -/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone) +// If this returns TRUE, the interaction has been handled and other interactions like afterattack should be skipped. +/obj/item/proc/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + // TODO: revisit if this should be a silent failure/parent call instead, for mob-level storage interactions? + // like a horse with a saddlebag or something + if(!user_can_attack_with(user)) + return TRUE // skip other interactions + + if(squash_item()) + return TRUE + + if(!user?.check_intent(I_FLAG_HARM) && is_edible(target) && handle_eaten_by_mob(user, target) != EATEN_INVALID) + return TRUE + if(item_flags & ITEM_FLAG_NO_BLUDGEON) - return 0 - if(M == user && user.a_intent != I_HURT) - return 0 + return FALSE + + // If on help, possibly don't attack. + if(user.check_intent(I_FLAG_HELP)) + switch(user.get_preference_value(/datum/client_preference/help_intent_attack_blocking)) + if(PREF_ALWAYS) + if(user == target) + to_chat(user, SPAN_WARNING("You refrain from hitting yourself with \the [src] as you are on help intent.")) + else + to_chat(user, SPAN_WARNING("You refrain from hitting \the [target] with \the [src] as you are on help intent.")) + return FALSE + if(PREF_MYSELF) + if(user == target) + to_chat(user, SPAN_WARNING("You refrain from hitting yourself with \the [src] as you are on help intent.")) + return FALSE ///////////////////////// if(!no_attack_log) - admin_attack_log(user, M, "Attacked using \a [src] (DAMTYE: [uppertext(damtype)])", "Was attacked with \a [src] (DAMTYE: [uppertext(damtype)])", "used \a [src] (DAMTYE: [uppertext(damtype)]) to attack") + admin_attack_log(user, target, "Attacked using \a [src] (DAMTYE: [uppertext(atom_damage_type)])", "Was attacked with \a [src] (DAMTYE: [uppertext(atom_damage_type)])", "used \a [src] (DAMTYE: [uppertext(atom_damage_type)]) to attack") ///////////////////////// user.setClickCooldown(attack_cooldown + w_class) - user.do_attack_animation(M) - if(!user.aura_check(AURA_TYPE_WEAPON, src, user)) - return 0 + if(animate) + user.do_attack_animation(target) + + if(target.mob_modifiers_block_attack(MM_ATTACK_TYPE_WEAPON, user, src)) + return FALSE - var/hit_zone = M.resolve_item_attack(src, user, target_zone) + var/hit_zone = target.resolve_item_attack(src, user, user.get_target_zone()) var/datum/attack_result/AR = hit_zone if(istype(AR)) if(AR.hit_zone) - apply_hit_effect(AR.attackee || M, user, AR.hit_zone) - return 1 + apply_hit_effect(AR.attackee || target, user, AR.hit_zone) + return TRUE if(hit_zone) - apply_hit_effect(M, user, hit_zone) - - return 1 + apply_hit_effect(target, user, hit_zone) + return TRUE //Called when a weapon is used to make a successful melee attack on a mob. Returns whether damage was dealt. /obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) var/use_hitsound = hitsound if(!use_hitsound) - if(edge || sharp) + if(has_edge() || is_sharp()) use_hitsound = 'sound/weapons/bladeslice.ogg' else use_hitsound = "swing_hit" playsound(loc, use_hitsound, 50, 1, -1) + return target.hit_with_weapon(src, user, expend_attack_force(user), hit_zone) - var/power = force - if(MUTATION_HULK in user.mutations) - power *= 2 - return target.hit_with_weapon(src, user, power, hit_zone) - +/obj/item/proc/handle_reflexive_fire(var/mob/user, var/atom/aiming_at) + return istype(user) && istype(aiming_at) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index b5a8e3f53550..1cc25ce2b5e3 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -2,130 +2,89 @@ /atom/proc/attack_generic(mob/user) return 0 -/* - Humans: - Adds an exception for gloves, to allow special glove types like the ninja ones. - - Otherwise pretty standard. -*/ -/mob/living/carbon/human/UnarmedAttack(var/atom/A, var/proximity) +/atom/proc/handle_grab_interaction(var/mob/user) + return FALSE - if(!..()) - return +/atom/proc/can_interact_with_storage(user, strict = FALSE) + return isliving(user) - // Special glove functions: - // If the gloves do anything, have them return 1 to stop - // normal attack_hand() here. - var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines - if(istype(G) && G.Touch(A,1)) - return - - A.attack_hand(src) +/atom/proc/get_required_interaction_dexterity() + return DEXTERITY_NONE /atom/proc/attack_hand(mob/user) - . = FALSE + SHOULD_CALL_PARENT(TRUE) -/mob/proc/attack_empty_hand(var/bp_hand) - return + if(!user.check_dexterity(get_required_interaction_dexterity(), silent = TRUE)) + return FALSE -/mob/living/carbon/human/RestrainedClickOn(var/atom/A) - return + if(can_interact_with_storage(user, strict = TRUE) && storage && user.check_dexterity((DEXTERITY_HOLD_ITEM|DEXTERITY_EQUIP_ITEM), TRUE)) + add_fingerprint(user) + storage.open(user) + return TRUE -/mob/living/CtrlClickOn(var/atom/A) - . = ..() - if(!. && a_intent == I_GRAB && length(available_maneuvers)) - . = perform_maneuver(prepared_maneuver || available_maneuvers[1], A) + if(handle_grab_interaction(user)) + return TRUE -/mob/living/carbon/human/RangedAttack(var/atom/A, var/params) - //Climbing up open spaces - if((istype(A, /turf/simulated/floor) || istype(A, /turf/unsimulated/floor) || istype(A, /obj/structure/lattice) || istype(A, /obj/structure/catwalk)) && isturf(loc) && bound_overlay && !is_physically_disabled()) //Climbing through openspace - return climb_up(A) + if(try_handle_interactions(user, get_standard_interactions(user), user?.get_active_held_item(), check_alt_interactions = FALSE)) + return TRUE - if(gloves) - var/obj/item/clothing/gloves/G = gloves - if(istype(G) && G.Touch(A,0)) // for magic gloves - return TRUE + if(!LAZYLEN(climbers) || (user in climbers) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, silent = TRUE)) + return FALSE - . = ..() + user.visible_message( + SPAN_DANGER("\The [user] shakes \the [src]!"), + SPAN_DANGER("You shake \the [src]!") + ) -/mob/living/RestrainedClickOn(var/atom/A) - return + object_shaken() + return TRUE -/* - Aliens -*/ - -/mob/living/carbon/alien/RestrainedClickOn(var/atom/A) +/mob/proc/attack_empty_hand() return -/mob/living/carbon/alien/UnarmedAttack(var/atom/A, var/proximity) +/mob/living/attack_empty_hand() + // Handle any prepared ability/spell/power invocations. + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + if(abilities?.do_self_invocation()) + return TRUE + return FALSE - if(!..()) - return 0 +/mob/living/human/RangedAttack(var/atom/A, var/params) + //Climbing up open spaces + if(isturf(loc) && bound_overlay && !is_physically_disabled() && istype(A) && A.can_climb_from_below(src)) + return climb_up(A) - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - A.attack_generic(src,rand(5,6),"bites") + var/obj/item/clothing/gloves/G = get_equipped_item(slot_gloves_str) + if(istype(G) && G.Touch(A, FALSE)) // for magic gloves + return TRUE -/* - Slimes - Nothing happening here -*/ + . = ..() -/mob/living/carbon/slime/RestrainedClickOn(var/atom/A) - return +/atom/proc/attack_hand_ranged(mob/user) + SHOULD_CALL_PARENT(TRUE) + return FALSE -/mob/living/carbon/slime/UnarmedAttack(var/atom/A, var/proximity) - - if(!..()) - return - - // Eating - if(Victim) - if (Victim == A) - Feedstop() - return - - //should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - var/mob/living/M = A - if(!istype(M)) - A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") // Basic attack. - else - var/power = max(0, min(10, (powerlevel + rand(0, 3)))) - - switch(src.a_intent) - if (I_HELP) // We just poke the other - M.visible_message("[src] gently pokes [M]!", "[src] gently pokes you!") - if (I_DISARM) // We stun the target, with the intention to feed - var/stunprob = 1 - - if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime)) - switch(power * 10) - if(0) stunprob *= 10 - if(1 to 2) stunprob *= 20 - if(3 to 4) stunprob *= 30 - if(5 to 6) stunprob *= 40 - if(7 to 8) stunprob *= 60 - if(9) stunprob *= 70 - if(10) stunprob *= 95 - - if(prob(stunprob)) - var/shock_damage = max(0, powerlevel-3) * rand(6,10) - M.electrocute_act(shock_damage, src, 1.0, ran_zone()) - else if(prob(40)) - M.visible_message("[src] has pounced at [M]!", "[src] has pounced at you!") - M.Weaken(power) - else - M.visible_message("[src] has tried to pounce at [M]!", "[src] has tried to pounce at you!") - M.updatehealth() - if (I_GRAB) // We feed - Wrap(M) - if (I_HURT) // Attacking - if(iscarbon(M) && prob(15)) - M.visible_message("[src] has pounced at [M]!", "[src] has pounced at you!") - M.Weaken(power) - else - A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") +/mob/living/RestrainedClickOn(var/atom/A) + if (A != src) + return ..() + if(world.time < next_restraint_chew || !get_equipped_item(slot_handcuffed_str) || !check_intent(I_FLAG_HARM) || get_target_zone() != BP_MOUTH) + return FALSE + // Cannot chew with a mask or a full body restraint. + if (get_equipped_item(slot_wear_mask_str) || istype(get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/straight_jacket)) + return FALSE + // Type to hand so drakes don't chew off their own head. + var/obj/item/organ/external/hand/O = GET_EXTERNAL_ORGAN(src, get_active_held_item_slot()) + if(!istype(O)) + return FALSE + var/decl/pronouns/pronouns = get_pronouns() + visible_message( + SPAN_DANGER("\The [src] chews on [pronouns.his] [O.name]"), + SPAN_DANGER("You chew on your [O.name]!") + ) + admin_attacker_log(src, "chewed on their [O.name]!") + O.take_damage(3, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = "teeth marks") + next_restraint_chew = world.time + (2.5 SECONDS) + return TRUE /* New Players: @@ -137,22 +96,22 @@ /* Animals */ -/mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity) - - if(!..()) - return - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(istype(A,/mob/living)) - if(!istype(natural_weapon) || a_intent == I_HELP) - custom_emote(1,"[friendly] [A]!") - return - if(ckey) - admin_attack_log(src, A, "Has attacked its victim.", "Has been attacked by its attacker.") - if(a_intent == I_HELP) - A.attack_animal(src) - else - A.attackby(get_natural_weapon(), src) +/// Make unarmed attacks use natural weapons on harm intent. +/mob/living/simple_animal/ResolveUnarmedAttack(atom/A) + var/attacking_with = get_natural_weapon() + if(check_intent(I_FLAG_HELP) || !attacking_with) + return A.attack_animal(src) + + set_intent(I_FLAG_HARM) + . = A.attackby(attacking_with, src) + // attack effects are handled in natural_weapon's apply_hit_effect() instead of here + if(!.) + reset_offsets(anim_time = 2) // Attack hand but for simple animals /atom/proc/attack_animal(mob/user) - return attack_hand(user) \ No newline at end of file + return attack_hand_with_interaction_checks(user) + +// Used to check for physical interactivity in case of nonstandard attack_hand calls. +/atom/proc/attack_hand_with_interaction_checks(var/mob/user) + return CanPhysicallyInteract(user) && attack_hand(user) \ No newline at end of file diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm index 268e95414e95..3b7d5f0d8ac1 100644 --- a/code/_onclick/rig.dm +++ b/code/_onclick/rig.dm @@ -1,23 +1,23 @@ /mob/living/MiddleClickOn(atom/A) - if(get_preference_value(/datum/client_preference/hardsuit_activation) == GLOB.PREF_MIDDLE_CLICK) + if(get_preference_value(/datum/client_preference/hardsuit_activation) == PREF_MIDDLE_CLICK) if(HardsuitClickOn(A)) return ..() /mob/living/AltClickOn(atom/A) - if(get_preference_value(/datum/client_preference/hardsuit_activation) == GLOB.PREF_ALT_CLICK) + if(get_preference_value(/datum/client_preference/hardsuit_activation) == PREF_ALT_CLICK) if(HardsuitClickOn(A)) return ..() /mob/living/CtrlClickOn(atom/A) - if(get_preference_value(/datum/client_preference/hardsuit_activation) == GLOB.PREF_CTRL_CLICK) + if(get_preference_value(/datum/client_preference/hardsuit_activation) == PREF_CTRL_CLICK) if(HardsuitClickOn(A)) return FALSE . = ..() /mob/living/CtrlShiftClickOn(atom/A) - if(get_preference_value(/datum/client_preference/hardsuit_activation) == GLOB.PREF_CTRL_SHIFT_CLICK) + if(get_preference_value(/datum/client_preference/hardsuit_activation) == PREF_CTRL_SHIFT_CLICK) if(HardsuitClickOn(A)) return ..() @@ -25,12 +25,9 @@ /mob/living/proc/can_use_rig() return 0 -/mob/living/carbon/human/can_use_rig() +/mob/living/human/can_use_rig() return 1 -/mob/living/carbon/brain/can_use_rig() - return istype(loc, /obj/item/mmi) - /mob/living/silicon/ai/can_use_rig() return carded @@ -41,7 +38,7 @@ if(!can_use_rig() || !canClick()) return 0 var/obj/item/rig/rig = get_rig() - if(istype(rig) && !rig.offline && rig.selected_module) + if(rig && !rig.offline && rig.selected_module) if(src != rig.wearer) if(rig.ai_can_move_suit(src, check_user_module = 1)) log_and_message_admins("is trying to force \the [key_name_admin(rig.wearer, include_name = 1)] to use a hardsuit module.", src) @@ -49,6 +46,6 @@ return 0 rig.selected_module.engage(A, alert_ai) if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + setClickCooldown(DEFAULT_QUICK_COOLDOWN) return 1 return 0 \ No newline at end of file diff --git a/code/client_macros.dm b/code/client_macros.dm index 34115eb8619f..0c7a8e308f66 100644 --- a/code/client_macros.dm +++ b/code/client_macros.dm @@ -1,7 +1,7 @@ /client control_freak = CONTROL_FREAK_ALL | CONTROL_FREAK_MACROS | CONTROL_FREAK_SKIN -var/list/registered_macros_by_ckey_ +var/global/list/registered_macros_by_ckey_ // Disables click and double-click macros, as per http://www.byond.com/forum/?post=2219001 /mob/verb/DisableClick(argu = null as anything, sec = "" as text,number1 = 0 as num, number2 = 0 as num) diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 14da41610128..81ffd5be43f2 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -18,8 +18,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) var/class /obj/effect/statclick/debug/Click() - if(!usr.client.holder || !target) + if(!check_rights(R_VAREDIT | R_DEBUG) || !target) return + if(!class) if(istype(target, /datum/controller/subsystem)) class = "subsystem" diff --git a/code/controllers/autotransfer.dm b/code/controllers/autotransfer.dm index 7baea410c2e8..c37a4784fe01 100644 --- a/code/controllers/autotransfer.dm +++ b/code/controllers/autotransfer.dm @@ -1,10 +1,10 @@ -var/datum/controller/transfer_controller/transfer_controller +var/global/datum/controller/transfer_controller/transfer_controller /datum/controller/transfer_controller var/timerbuffer = 0 //buffer for time check /datum/controller/transfer_controller/New() - timerbuffer = config.vote_autotransfer_initial + timerbuffer = get_config_value(/decl/config/num/vote_autotransfer_initial) START_PROCESSING(SSprocessing, src) /datum/controller/transfer_controller/Destroy() @@ -14,7 +14,7 @@ var/datum/controller/transfer_controller/transfer_controller /datum/controller/transfer_controller/Process() if (time_till_transfer_vote() <= 0) SSvote.initiate_vote(/datum/vote/transfer, automatic = 1) - timerbuffer += config.vote_autotransfer_interval + timerbuffer += get_config_value(/decl/config/num/vote_autotransfer_interval) /datum/controller/transfer_controller/proc/time_till_transfer_vote() return timerbuffer - round_duration_in_ticks - (1 MINUTE) diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index 4ddb0bcaf520..05694e4565d7 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -64,184 +64,53 @@ /* Frequency range: 1200 to 1600 Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking) - -Radio: -1459 - standard radio chat -1351 - Science -1353 - Command -1355 - Medical -1357 - Engineering -1359 - Security -1341 - deathsquad -1443 - Confession Intercom -1347 - Cargo techs -1349 - Service people - -Devices: -1451 - tracking implant -1457 - RSD default - -On the map: -1311 for prison shuttle console (in fact, it is not used) -1435 for status displays -1437 for atmospherics/fire alerts -1438 for engine components -1439 for air pumps, air scrubbers, atmo control -1441 for atmospherics - supply tanks -1443 for atmospherics - distribution loop/mixed air tank -1445 for bot nav beacons -1447 for mulebot, secbot and ed209 control -1449 for airlock controls, electropack, magnets -1451 for toxin lab access -1453 for engineering access -1455 for AI access */ -var/const/RADIO_LOW_FREQ = 1200 -var/const/PUBLIC_LOW_FREQ = 1441 -var/const/PUBLIC_HIGH_FREQ = 1489 -var/const/RADIO_HIGH_FREQ = 1600 - -var/const/BOT_FREQ = 1447 -var/const/COMM_FREQ = 1353 -var/const/ERT_FREQ = 1345 -var/const/AI_FREQ = 1343 -var/const/DTH_FREQ = 1341 -var/const/SYND_FREQ = 1213 -var/const/RAID_FREQ = 1277 -var/const/ENT_FREQ = 1461 - -// department channels -var/const/PUB_FREQ = 1459 -var/const/SEC_FREQ = 1359 -var/const/ENG_FREQ = 1357 -var/const/MED_FREQ = 1355 -var/const/SCI_FREQ = 1351 -var/const/SRV_FREQ = 1349 -var/const/SUP_FREQ = 1347 -var/const/EXP_FREQ = 1361 - -// internal department channels -var/const/MED_I_FREQ = 1485 -var/const/SEC_I_FREQ = 1475 - -// Device signal frequencies -var/const/ATMOS_ENGINE_FREQ = 1438 // Used by atmos monitoring in the engine. -var/const/PUMP_FREQ = 1439 // Used by air alarms and their progeny. -var/const/FUEL_FREQ = 1447 // Used by fuel atmos stuff, and currently default for digital valves -var/const/ATMOS_TANK_FREQ = 1441 // Used for gas tank sensors and monitoring. -var/const/ATMOS_DIST_FREQ = 1443 // Alternative atmos frequency. -var/const/BUTTON_FREQ = 1301 // Used by generic buttons controlling stuff -var/const/BLAST_DOORS_FREQ = 1303 // Used by blast doors, buttons controlling them, and mass drivers. -var/const/AIRLOCK_FREQ = 1305 // Used by airlocks and buttons controlling them. -var/const/SHUTTLE_AIR_FREQ = 1331 // Used by shuttles and shuttle-related atmos systems. -var/const/EXTERNAL_AIR_FREQ = 1381 // Used by some external airlocks. - -var/list/radiochannels = list( - "Common" = PUB_FREQ, - "Science" = SCI_FREQ, - "Command" = COMM_FREQ, - "Medical" = MED_FREQ, - "Engineering" = ENG_FREQ, - "Security" = SEC_FREQ, - "Response Team" = ERT_FREQ, - "Special Ops" = DTH_FREQ, - "Mercenary" = SYND_FREQ, - "Raider" = RAID_FREQ, - "Exploration" = EXP_FREQ, - "Supply" = SUP_FREQ, - "Service" = SRV_FREQ, - "AI Private" = AI_FREQ, - "Entertainment" = ENT_FREQ, - "Medical(I)" = MED_I_FREQ, - "Security(I)" = SEC_I_FREQ -) - -var/list/channel_color_presets = list( - "Bemoaning Brown" = COMMS_COLOR_SUPPLY, - "Bitchin' Blue" = COMMS_COLOR_COMMAND, - "Bold Brass" = COMMS_COLOR_EXPLORER, - "Gastric Green" = COMMS_COLOR_SERVICE, - "Global Green" = COMMS_COLOR_COMMON, - "Menacing Maroon" = COMMS_COLOR_SYNDICATE, - "Operational Orange" = COMMS_COLOR_ENGINEER, - "Painful Pink" = COMMS_COLOR_AI, - "Phenomenal Purple" = COMMS_COLOR_SCIENCE, - "Pretty Periwinkle" = COMMS_COLOR_CENTCOMM, - "Raging Red" = COMMS_COLOR_SECURITY, - "Spectacular Silver" = COMMS_COLOR_ENTERTAIN, - "Tantalizing Turquoise" = COMMS_COLOR_MEDICAL -) - -// central command channels, i.e deathsquid & response teams -var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ) +var/global/const/RADIO_LOW_FREQ = 1200 +var/global/const/PUBLIC_LOW_FREQ = 1441 +var/global/const/PUB_FREQ = 1459 +var/global/const/PUBLIC_HIGH_FREQ = 1489 +var/global/const/RADIO_HIGH_FREQ = 1600 -// Antag channels, i.e. Syndicate -var/list/ANTAG_FREQS = list(SYND_FREQ, RAID_FREQ) +#define COMMON_FREQUENCY_DATA list("name" = "Common", "key" = "g", "frequency" = PUB_FREQ, "color" = COMMS_COLOR_COMMON, "span_class" = "radio") -//Department channels, arranged lexically -var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ, EXP_FREQ, ENT_FREQ) +// Device signal frequencies +var/global/const/ATMOS_ENGINE_FREQ = 1438 // Used by atmos monitoring in the engine. +var/global/const/PUMP_FREQ = 1439 // Used by air alarms and their progeny. +var/global/const/FUEL_FREQ = 1447 // Used by fuel atmos stuff, and currently default for digital valves +var/global/const/ATMOS_TANK_FREQ = 1441 // Used for gas tank sensors and monitoring. +var/global/const/ATMOS_DIST_FREQ = 1443 // Alternative atmos frequency. +var/global/const/BUTTON_FREQ = 1301 // Used by generic buttons controlling stuff +var/global/const/BLAST_DOORS_FREQ = 1303 // Used by blast doors, buttons controlling them, and mass drivers. +var/global/const/AIRLOCK_FREQ = 1305 // Used by airlocks and buttons controlling them. +var/global/const/SHUTTLE_AIR_FREQ = 1331 // Used by shuttles and shuttle-related atmos systems. +var/global/const/EXTERNAL_AIR_FREQ = 1381 // Used by some external airlocks. #define TRANSMISSION_WIRE 0 #define TRANSMISSION_RADIO 1 -/proc/frequency_span_class(var/frequency) - // Antags! - if (frequency in ANTAG_FREQS) - return "syndradio" - // centcomm channels (deathsquid and ert) - if(frequency in CENT_FREQS) - return "centradio" - // command channel - if(frequency == COMM_FREQ) - return "comradio" - // AI private channel - if(frequency == AI_FREQ) - return "airadio" - // department radio formatting (poorly optimized, ugh) - if(frequency == SEC_FREQ) - return "secradio" - if (frequency == ENG_FREQ) - return "engradio" - if(frequency == SCI_FREQ) - return "sciradio" - if(frequency == MED_FREQ) - return "medradio" - if(frequency == EXP_FREQ) // exploration - return "EXPradio" - if(frequency == SUP_FREQ) // cargo - return "supradio" - if(frequency == SRV_FREQ) // service - return "srvradio" - if(frequency == ENT_FREQ) //entertainment - return "entradio" - if(frequency in DEPT_FREQS) - return "deptradio" - - return "radio" - /* filters */ //When devices register with the radio controller, they might register under a certain filter. //Other devices can then choose to send signals to only those devices that belong to a particular filter. //This is done for performance, so we don't send signals to lots of machines unnecessarily. -//This filter is special because devices belonging to default also recieve signals sent to any other filter. -var/const/RADIO_DEFAULT = "radio_default" -//This filter is special because devices belonging to it do not recieve any signals at all. Useful for devices which only transmit. -var/const/RADIO_NULL = "radio_null" - -var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms -var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in recieving signals from air alarms -var/const/RADIO_CHAT = "radio_telecoms" -var/const/RADIO_ATMOSIA = "radio_atmos" -var/const/RADIO_NAVBEACONS = "radio_navbeacon" -var/const/RADIO_AIRLOCK = "radio_airlock" -var/const/RADIO_SECBOT = "radio_secbot" -var/const/RADIO_MULEBOT = "radio_mulebot" -var/const/RADIO_MAGNETS = "radio_magnet" +//This filter is special because devices belonging to default also receive signals sent to any other filter. +var/global/const/RADIO_DEFAULT = "radio_default" +//This filter is special because devices belonging to it do not receive any signals at all. Useful for devices which only transmit. +var/global/const/RADIO_NULL = "radio_null" + +var/global/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms +var/global/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in receiving signals from air alarms +var/global/const/RADIO_CHAT = "radio_telecoms" +var/global/const/RADIO_ATMOSIA = "radio_atmos" +var/global/const/RADIO_NAVBEACONS = "radio_navbeacon" +var/global/const/RADIO_AIRLOCK = "radio_airlock" +var/global/const/RADIO_SECBOT = "radio_secbot" +var/global/const/RADIO_MULEBOT = "radio_mulebot" +var/global/const/RADIO_MAGNETS = "radio_magnet" // These are exposed to players, by name. -GLOBAL_LIST_INIT(all_selectable_radio_filters, list( +var/global/list/all_selectable_radio_filters = list( RADIO_DEFAULT, RADIO_TO_AIRALARM, RADIO_FROM_AIRALARM, @@ -252,13 +121,9 @@ GLOBAL_LIST_INIT(all_selectable_radio_filters, list( RADIO_SECBOT, RADIO_MULEBOT, RADIO_MAGNETS -)) - -var/global/datum/controller/radio/radio_controller +) -/hook/startup/proc/createRadioController() - radio_controller = new /datum/controller/radio() - return 1 +var/global/datum/controller/radio/radio_controller = new /datum/controller/radio() //callback used by objects to react to incoming radio signals /obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param) @@ -288,10 +153,6 @@ var/global/datum/controller/radio/radio_controller if(frequency) frequency.remove_listener(device) - if(frequency.devices.len == 0) - qdel(frequency) - frequencies -= f_text - return 1 /datum/controller/radio/proc/return_frequency(var/new_frequency as num) @@ -328,7 +189,7 @@ var/global/datum/controller/radio/radio_controller /datum/radio_frequency/proc/send_to_filter(obj/source, datum/signal/signal, var/radio_filter, var/turf/start_point = null, var/range = null) var/list/z_levels if(start_point) - z_levels = GetConnectedZlevels(start_point.z) + z_levels = SSmapping.get_connected_levels(start_point.z) for(var/obj/device in devices[radio_filter]) if(device == source) @@ -365,20 +226,12 @@ var/global/datum/controller/radio/radio_controller /datum/signal var/obj/source - - var/transmission_method = 0 //unused at the moment - //0 = wire - //1 = radio transmission - //2 = subspace transmission - var/list/data = list() var/encryption - var/frequency = 0 /datum/signal/proc/copy_from(datum/signal/model) source = model.source - transmission_method = model.transmission_method data = model.data encryption = model.encryption frequency = model.frequency diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm deleted file mode 100644 index 4735db57c2a4..000000000000 --- a/code/controllers/configuration.dm +++ /dev/null @@ -1,909 +0,0 @@ -var/list/gamemode_cache = list() - -/datum/configuration - var/server_name = null // server name (for world name / status) - var/server_suffix = 0 // generate numeric suffix based on server port - - var/log_ooc = 0 // log OOC channel - var/log_access = 0 // log login/logout - var/log_say = 0 // log client say - var/log_admin = 0 // log admin actions - var/log_debug = 1 // log debug output - var/log_game = 0 // log game events - var/log_vote = 0 // log voting - var/log_whisper = 0 // log client whisper - var/log_emote = 0 // log emotes - var/log_attack = 0 // log attack messages - var/log_adminchat = 0 // log admin chat messages - var/log_adminwarn = 0 // log warnings admins get about bomb construction and such - var/log_pda = 0 // log pda messages - var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits - var/log_runtime = 0 // logs world.log to a file - var/log_world_output = 0 // log to_world_log(messages) - var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour - var/allow_vote_restart = 0 // allow votes to restart - var/ert_admin_call_only = 0 - var/allow_vote_mode = 0 // allow votes to change mode - var/allow_admin_jump = 1 // allows admin jumping - var/allow_admin_spawning = 1 // allows admin item spawning - var/allow_admin_rev = 1 // allows admin revives - var/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default) - var/vote_period = 600 // length of voting period (deciseconds, default 1 minute) - var/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called - var/vote_autotransfer_interval = 18000 // length of time before next sequential autotransfer vote - var/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100). - var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi) - var/vote_no_dead = 0 // dead people can't vote (tbi) - var/vote_no_dead_crew_transfer = 0 // dead people can't vote on crew transfer votes -// var/enable_authentication = 0 // goon authentication - var/del_new_on_log = 1 // del's new players if they log before they spawn in - var/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard - var/traitor_scaling = 0 //if amount of traitors scales based on amount of players - var/objectives_disabled = 0 //if objectives are disabled or not - var/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other - var/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke. - var/allow_Metadata = 0 // Metadata is supported. - var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1. - var/allow_holidays = FALSE - var/fps = 20 - var/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling - var/list/resource_urls = null - var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round. - var/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round. - var/list/mode_names = list() - var/list/modes = list() // allowed modes - var/list/votable_modes = list() // votable modes - var/list/probabilities = list() // relative probability of each mode - var/secret_hide_possibilities = FALSE // Whether or not secret modes show list of possible round types - var/humans_need_surnames = 0 - var/allow_random_events = 0 // enables random events mid-round when set to 1 - var/allow_ai = 1 // allow ai job - var/hostedby = null - var/respawn_delay = 30 - var/guest_jobban = 1 - var/usewhitelist = 0 - var/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0 - var/mods_can_tempban = 0 - var/mods_can_job_tempban = 0 - var/mod_tempban_max = 1440 - var/mod_job_tempban_max = 1440 - var/load_jobs_from_txt = 0 - var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. - - var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds... - var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active. - - var/character_slots = 10 // The number of available character slots - var/loadout_slots = 3 // The number of loadout slots per character - - var/max_maint_drones = 5 //This many drones can spawn, - var/allow_drone_spawn = 1 //assuming the admin allow them to. - var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes. - - var/disable_player_mice = 0 - var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech - - var/usealienwhitelist = 0 - var/usealienwhitelistSQL = 0; - var/limitalienplayers = 0 - var/alien_to_human_ratio = 0.5 - var/allow_extra_antags = 0 - var/guests_allowed = 1 - var/debugparanoid = 0 - - var/serverurl - var/server - var/banappeals - var/wikiurl - var/forumurl - var/discordurl - var/githuburl - var/issuereporturl - - var/forbid_singulo_possession = 0 - - //game_options.txt configs - - var/health_threshold_dead = -100 - - var/organ_health_multiplier = 0.9 - var/organ_regeneration_multiplier = 0.25 - var/organs_decay - - //Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt, - //so that it's similar to PAIN. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun. - var/organ_damage_spillover_multiplier = 0.5 - - var/bones_can_break = 1 - var/limbs_can_break = 1 - - var/revival_pod_plants = 1 - var/revival_cloning = 1 - var/revival_brain_life = -1 - - var/use_loyalty_implants = 0 - - var/welder_vision = 1 - var/generate_map = 0 - var/no_click_cooldown = 0 - - //Used for modifying movement speed for mobs. - //Unversal modifiers - var/run_delay = 2 - var/walk_delay = 4 - var/creep_delay = 6 - var/minimum_sprint_cost = 0.8 - var/skill_sprint_cost_range = 0.8 - var/minimum_stamina_recovery = 1 - var/maximum_stamina_recovery = 3 - - //Mob specific modifiers. NOTE: These will affect different mob types in different ways - var/human_delay = 0 - var/robot_delay = 0 - var/monkey_delay = 0 - var/alien_delay = 0 - var/slime_delay = 0 - var/animal_delay = 0 - var/maximum_mushrooms = 15 //After this amount alive, mushrooms will not boom boom - - - var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt - var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt - var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database - var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database - - var/simultaneous_pm_warning_timeout = 100 - - var/use_iterative_explosions //Defines whether the server uses iterative or circular explosions. - var/iterative_explosives_z_threshold = 10 - var/iterative_explosives_z_multiplier = 0.75 - - var/assistant_maint = 0 //Do assistants get maint access? - var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour. - var/ghost_interaction = 0 - - var/comms_password = "" - var/ban_comms_password = null - var/list/forbidden_versions = list() // Clients with these byond versions will be autobanned. Format: string "byond_version.byond_build"; separate with ; in config, e.g. 512.1234;512.1235 - var/minimum_byond_version = 0 - var/minimum_byond_build = 0 - - var/login_export_addr = null - - var/enter_allowed = 1 - var/player_limit = 0 - - var/use_irc_bot = 0 - var/irc_bot_host = "" - var/main_irc = "" - var/admin_irc = "" - var/announce_shuttle_dock_to_irc = FALSE - - // Event settings - var/expected_round_length = 3 * 60 * 60 * 10 // 3 hours - // If the first delay has a custom start time - // No custom time, no custom time, between 80 to 100 minutes respectively. - var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000)) - // The lowest delay until next event - // 10, 30, 50 minutes respectively - var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000) - // The upper delay until next event - // 15, 45, 70 minutes respectively - var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000) - - var/aliens_allowed = 0 - var/alien_eggs_allowed = 0 - var/ninjas_allowed = 0 - var/abandon_allowed = 1 - var/ooc_allowed = 1 - var/looc_allowed = 1 - var/dooc_allowed = 1 - var/dsay_allowed = 1 - var/aooc_allowed = 1 - - var/starlight = 0 // Whether space turfs have ambient light or not - - var/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010" - - var/aggressive_changelog = 0 - - var/ghosts_can_possess_animals = 0 - var/delist_when_no_admins = FALSE - - var/allow_map_switching = 0 // Whether map switching is allowed - var/auto_map_vote = 0 // Automatically call a map vote at end of round and switch to the selected map - var/wait_for_sigusr1_reboot = 0 // Don't allow reboot unless it was caused by SIGUSR1 - - var/radiation_decay_rate = 1 //How much radiation is reduced by each tick - var/radiation_resistance_multiplier = 1.25 - var/radiation_material_resistance_divisor = 2 //A turf's possible radiation resistance is divided by this number, to get the real value. - var/radiation_lower_limit = 0.15 //If the radiation level for a turf would be below this, ignore it. - - var/autostealth = 0 // Staff get automatic stealth after this many minutes - - var/error_cooldown = 600 // The "cooldown" time for each occurrence of a unique error - var/error_limit = 50 // How many occurrences before the next will silence them - var/error_silence_time = 6000 // How long a unique error will be silenced for - var/error_msg_delay = 50 // How long to wait between messaging admins about occurrences of a unique error - - var/max_gear_cost = 10 // Used in chargen for accessory loadout limit. 0 disables loadout, negative allows infinite points. - - var/allow_ic_printing = TRUE //Whether players should be allowed to print IC circuits from scripts. - - var/allow_unsafe_narrates = FALSE //Whether admins can use unsanitized narration; when true, allows HTML etc. - - var/do_not_prevent_spam = FALSE //If this is true, skips spam prevention for user actions; inputs, verbs, macros, etc. - var/max_acts_per_interval = 140 //Number of actions per interval permitted for spam protection. - var/act_interval = 0.1 SECONDS //Interval for spam prevention. - -/datum/configuration/New() - var/list/L = typesof(/datum/game_mode) - /datum/game_mode - for (var/T in L) - // I wish I didn't have to instance the game modes in order to look up - // their information, but it is the only way (at least that I know of). - var/datum/game_mode/M = new T() - if (M.config_tag) - gamemode_cache[M.config_tag] = M // So we don't instantiate them repeatedly. - if(!(M.config_tag in modes)) // ensure each mode is added only once - log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.") - src.modes += M.config_tag - src.mode_names[M.config_tag] = M.name - src.probabilities[M.config_tag] = M.probability - if (M.votable) - src.votable_modes += M.config_tag - src.votable_modes += "secret" - -/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist - var/list/Lines = file2list(filename) - - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - if(type == "config") - switch (name) - if ("resource_urls") - config.resource_urls = splittext(value, " ") - - if ("admin_legacy_system") - config.admin_legacy_system = 1 - - if ("ban_legacy_system") - config.ban_legacy_system = 1 - - if ("use_age_restriction_for_jobs") - config.use_age_restriction_for_jobs = 1 - - if ("use_age_restriction_for_antags") - config.use_age_restriction_for_antags = 1 - - if ("jobs_have_minimal_access") - config.jobs_have_minimal_access = 1 - - if ("use_iterative_explosions") - use_iterative_explosions = 1 - - if ("explosion_z_threshold") - iterative_explosives_z_threshold = text2num(value) - - if ("explosion_z_mult") - iterative_explosives_z_multiplier = text2num(value) - - if ("log_ooc") - config.log_ooc = 1 - - if ("log_access") - config.log_access = 1 - - if ("log_say") - config.log_say = 1 - - if ("debug_paranoid") - config.debugparanoid = 1 - - if ("log_admin") - config.log_admin = 1 - - if ("log_debug") - config.log_debug = text2num(value) - - if ("log_game") - config.log_game = 1 - - if ("log_vote") - config.log_vote = 1 - - if ("log_whisper") - config.log_whisper = 1 - - if ("log_attack") - config.log_attack = 1 - - if ("log_emote") - config.log_emote = 1 - - if ("log_adminchat") - config.log_adminchat = 1 - - if ("log_adminwarn") - config.log_adminwarn = 1 - - if ("log_pda") - config.log_pda = 1 - - if ("log_world_output") - config.log_world_output = 1 - - if ("log_hrefs") - config.log_hrefs = 1 - - if ("log_runtime") - config.log_runtime = 1 - - if ("generate_asteroid") - config.generate_map = 1 - - if ("no_click_cooldown") - config.no_click_cooldown = 1 - - if("allow_admin_ooccolor") - config.allow_admin_ooccolor = 1 - - if ("allow_vote_restart") - config.allow_vote_restart = 1 - - if ("allow_vote_mode") - config.allow_vote_mode = 1 - - if ("allow_admin_jump") - config.allow_admin_jump = 1 - - if("allow_admin_rev") - config.allow_admin_rev = 1 - - if ("allow_admin_spawning") - config.allow_admin_spawning = 1 - - if ("no_dead_vote") - config.vote_no_dead = 1 - - if ("no_dead_vote_crew_transfer") - config.vote_no_dead_crew_transfer = 1 - - if ("default_no_vote") - config.vote_no_default = 1 - - if ("vote_delay") - config.vote_delay = text2num(value) - - if ("vote_period") - config.vote_period = text2num(value) - - if ("vote_autotransfer_initial") - config.vote_autotransfer_initial = text2num(value) - - if ("vote_autotransfer_interval") - config.vote_autotransfer_interval = text2num(value) - - if ("vote_autogamemode_timeleft") - config.vote_autogamemode_timeleft = text2num(value) - - if("ert_admin_only") - config.ert_admin_call_only = 1 - - if ("allow_ai") - config.allow_ai = 1 - -// if ("authentication") -// config.enable_authentication = 1 - - if ("respawn_delay") - config.respawn_delay = text2num(value) - config.respawn_delay = config.respawn_delay > 0 ? config.respawn_delay : 0 - - if ("servername") - config.server_name = value - - if ("serversuffix") - config.server_suffix = 1 - - if ("hostedby") - config.hostedby = value - - if ("serverurl") - config.serverurl = value - - if ("server") - config.server = value - - if ("banappeals") - config.banappeals = value - - if ("wikiurl") - config.wikiurl = value - - if ("forumurl") - config.forumurl = value - - if ("discordurl") - config.discordurl = value - - if ("githuburl") - config.githuburl = value - - if ("issuereporturl") - config.issuereporturl = value - - if ("ghosts_can_possess_animals") - config.ghosts_can_possess_animals = value - - if ("guest_jobban") - config.guest_jobban = 1 - - if ("guest_ban") - config.guests_allowed = 0 - - if ("disable_ooc") - config.ooc_allowed = 0 - - if ("disable_looc") - config.looc_allowed = 0 - - if ("disable_aooc") - config.aooc_allowed = 0 - - if ("disable_entry") - config.enter_allowed = 0 - - if ("disable_dead_ooc") - config.dooc_allowed = 0 - - if ("disable_dsay") - config.dsay_allowed = 0 - - if ("disable_respawn") - config.abandon_allowed = 0 - - if ("usewhitelist") - config.usewhitelist = 1 - - if ("feature_object_spell_system") - config.feature_object_spell_system = 1 - - if ("allow_metadata") - config.allow_Metadata = 1 - - if ("traitor_scaling") - config.traitor_scaling = 1 - - if ("aliens_allowed") - config.aliens_allowed = 1 - - if("alien_eggs_allowed") - config.alien_eggs_allowed = 1 - - if ("ninjas_allowed") - config.ninjas_allowed = 1 - - if ("objectives_disabled") - if(!value) - log_misc("Could not find value for objectives_disabled in configuration.") - config.objectives_disabled = CONFIG_OBJECTIVE_NONE - else - switch(value) - if("none") - config.objectives_disabled = CONFIG_OBJECTIVE_NONE - if("verb") - config.objectives_disabled = CONFIG_OBJECTIVE_VERB - if("all") - config.objectives_disabled = CONFIG_OBJECTIVE_ALL - else - log_misc("Incorrect objective disabled definition: [value]") - config.objectives_disabled = CONFIG_OBJECTIVE_NONE - if("protect_roles_from_antagonist") - config.protect_roles_from_antagonist = 1 - - if ("probability") - var/prob_pos = findtext(value, " ") - var/prob_name = null - var/prob_value = null - - if (prob_pos) - prob_name = lowertext(copytext(value, 1, prob_pos)) - prob_value = copytext(value, prob_pos + 1) - if (prob_name in config.modes) - config.probabilities[prob_name] = text2num(prob_value) - else - log_misc("Unknown game mode probability configuration definition: [prob_name].") - else - log_misc("Incorrect probability configuration definition: [prob_name] [prob_value].") - - if("allow_random_events") - config.allow_random_events = 1 - - if("kick_inactive") - config.kick_inactive = text2num(value) - - if("mods_can_tempban") - config.mods_can_tempban = 1 - - if("mods_can_job_tempban") - config.mods_can_job_tempban = 1 - - if("mod_tempban_max") - config.mod_tempban_max = text2num(value) - - if("mod_job_tempban_max") - config.mod_job_tempban_max = text2num(value) - - if("load_jobs_from_txt") - load_jobs_from_txt = 1 - - if("forbid_singulo_possession") - forbid_singulo_possession = 1 - - if("popup_admin_pm") - config.popup_admin_pm = 1 - - if("allow_holidays") - config.allow_holidays = 1 - - if("use_irc_bot") - use_irc_bot = 1 - - if("ticklag") - var/ticklag = text2num(value) - if(ticklag > 0) - fps = 10 / ticklag - - if("fps") - fps = text2num(value) - - if("tick_limit_mc_init") - tick_limit_mc_init = text2num(value) - - if("allow_antag_hud") - config.antag_hud_allowed = 1 - if("antag_hud_restricted") - config.antag_hud_restricted = 1 - - if("secret_hide_possibilities") - secret_hide_possibilities = TRUE - - if("humans_need_surnames") - humans_need_surnames = 1 - - if("usealienwhitelist") - usealienwhitelist = 1 - if("usealienwhitelist_sql") // above need to be enabled as well - usealienwhitelistSQL = 1; - if("alien_player_ratio") - limitalienplayers = 1 - alien_to_human_ratio = text2num(value) - - if("assistant_maint") - config.assistant_maint = 1 - - if("gateway_delay") - config.gateway_delay = text2num(value) - - if("continuous_rounds") - config.continous_rounds = 1 - - if("ghost_interaction") - config.ghost_interaction = 1 - - if("disable_player_mice") - config.disable_player_mice = 1 - - if("uneducated_mice") - config.uneducated_mice = 1 - - if("comms_password") - config.comms_password = value - - if("ban_comms_password") - config.ban_comms_password = value - - if("forbidden_versions") - config.forbidden_versions = splittext(value, ";") - - if("minimum_byond_version") - config.minimum_byond_version = text2num(value) - - if("minimum_byond_build") - config.minimum_byond_build = text2num(value) - - if("login_export_addr") - config.login_export_addr = value - - if("irc_bot_host") - config.irc_bot_host = value - - if("main_irc") - config.main_irc = value - - if("admin_irc") - config.admin_irc = value - - if("announce_shuttle_dock_to_irc") - config.announce_shuttle_dock_to_irc = TRUE - - if("allow_cult_ghostwriter") - config.cult_ghostwriter = 1 - - if("req_cult_ghostwriter") - config.cult_ghostwriter_req_cultists = text2num(value) - - if("character_slots") - config.character_slots = text2num(value) - - if("loadout_slots") - config.loadout_slots = text2num(value) - - if("allow_drone_spawn") - config.allow_drone_spawn = text2num(value) - - if("drone_build_time") - config.drone_build_time = text2num(value) - - if("max_maint_drones") - config.max_maint_drones = text2num(value) - - if("expected_round_length") - config.expected_round_length = MinutesToTicks(text2num(value)) - - if("disable_welder_vision") - config.welder_vision = 0 - - if("disable_circuit_printing") - config.allow_ic_printing = FALSE - - if("allow_extra_antags") - config.allow_extra_antags = 1 - - if("event_custom_start_mundane") - var/values = text2numlist(value, ";") - config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) - - if("event_custom_start_moderate") - var/values = text2numlist(value, ";") - config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) - - if("event_custom_start_major") - var/values = text2numlist(value, ";") - config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) - - if("event_delay_lower") - var/values = text2numlist(value, ";") - config.event_delay_lower[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) - config.event_delay_lower[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) - config.event_delay_lower[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) - - if("event_delay_upper") - var/values = text2numlist(value, ";") - config.event_delay_upper[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) - config.event_delay_upper[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) - config.event_delay_upper[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) - - if("starlight") - value = text2num(value) - config.starlight = value >= 0 ? value : 0 - - if("law_zero") - law_zero = value - - if("aggressive_changelog") - config.aggressive_changelog = 1 - - if("delist_when_no_admins") - config.delist_when_no_admins = TRUE - - if("map_switching") - config.allow_map_switching = 1 - - if("auto_map_vote") - config.auto_map_vote = 1 - - if("wait_for_sigusr1") - config.wait_for_sigusr1_reboot = 1 - - if("autostealth") - config.autostealth = text2num(value) - - if("radiation_lower_limit") - radiation_lower_limit = text2num(value) - - - if("error_cooldown") - error_cooldown = text2num(value) - if("error_limit") - error_limit = text2num(value) - if("error_silence_time") - error_silence_time = text2num(value) - if("error_msg_delay") - error_msg_delay = text2num(value) - - if("max_gear_cost") - max_gear_cost = text2num(value) - if(max_gear_cost < 0) - max_gear_cost = INFINITY - if("radiation_decay_rate") - radiation_decay_rate = text2num(value) - if("radiation_resistance_multiplier") - radiation_resistance_multiplier = text2num(value) - if("radiation_material_resistance_divisor") - radiation_material_resistance_divisor = text2num(value) - if("radiation_lower_limit") - radiation_lower_limit = text2num(value) - if("player_limit") - player_limit = text2num(value) - if("hub") - world.update_hub_visibility() - - if ("allow_unsafe_narrates") - config.allow_unsafe_narrates = TRUE - - if ("do_not_prevent_spam") - config.do_not_prevent_spam = TRUE - if ("max_acts_per_interval") - config.max_acts_per_interval = text2num(value) - if ("act_interval") - config.act_interval = text2num(value) SECONDS - - else - log_misc("Unknown setting in configuration: '[name]'") - - else if(type == "game_options") - if(!value) - log_misc("Unknown value for setting [name] in [filename].") - value = text2num(value) - - switch(name) - if("health_threshold_dead") - config.health_threshold_dead = value - if("revival_pod_plants") - config.revival_pod_plants = value - if("revival_cloning") - config.revival_cloning = value - if("revival_brain_life") - config.revival_brain_life = value - if("organ_health_multiplier") - config.organ_health_multiplier = value / 100 - if("organ_regeneration_multiplier") - config.organ_regeneration_multiplier = value / 100 - if("organ_damage_spillover_multiplier") - config.organ_damage_spillover_multiplier = value / 100 - if("organs_can_decay") - config.organs_decay = 1 - if("bones_can_break") - config.bones_can_break = value - if("limbs_can_break") - config.limbs_can_break = value - - if("run_delay") - config.run_delay = value - if("walk_delay") - config.walk_delay = value - if("creep_delay") - config.creep_delay = value - if("minimum_sprint_cost") - config.minimum_sprint_cost = value - if("skill_sprint_cost_range") - config.skill_sprint_cost_range = value - if("minimum_stamina_recovery") - config.minimum_stamina_recovery = value - if("maximum_stamina_recovery") - config.maximum_stamina_recovery = value - - if("human_delay") - config.human_delay = value - if("robot_delay") - config.robot_delay = value - if("monkey_delay") - config.monkey_delay = value - if("alien_delay") - config.alien_delay = value - if("slime_delay") - config.slime_delay = value - if("animal_delay") - config.animal_delay = value - if("maximum_mushrooms") - config.maximum_mushrooms = value - - - if("use_loyalty_implants") - config.use_loyalty_implants = 1 - - else - log_misc("Unknown setting in configuration: '[name]'") - - fps = round(fps) - if(fps <= 0) - fps = initial(fps) - -/datum/configuration/proc/loadsql(filename) // -- TLE - var/list/Lines = file2list(filename) - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - switch (name) - if ("enabled") - sqlenabled = TRUE - if ("address") - sqladdress = value - if ("port") - sqlport = value - if ("database") - sqldb = value - if ("login") - sqllogin = value - if ("password") - sqlpass = value - if ("feedback_database") - sqlfdbkdb = value - if ("feedback_login") - sqlfdbklogin = value - if ("feedback_password") - sqlfdbkpass = value - else - log_misc("Unknown setting in configuration: '[name]'") - -/datum/configuration/proc/pick_mode(mode_name) - // I wish I didn't have to instance the game modes in order to look up - // their information, but it is the only way (at least that I know of). - for (var/game_mode in gamemode_cache) - var/datum/game_mode/M = gamemode_cache[game_mode] - if (M.config_tag && M.config_tag == mode_name) - return M - -/datum/configuration/proc/get_runnable_modes() - var/list/runnable_modes = list() - for(var/game_mode in gamemode_cache) - var/datum/game_mode/M = gamemode_cache[game_mode] - if(M && !M.startRequirements() && !isnull(config.probabilities[M.config_tag]) && config.probabilities[M.config_tag] > 0) - runnable_modes[M.config_tag] = config.probabilities[M.config_tag] - return runnable_modes - -/datum/configuration/proc/load_event(filename) - var/event_info = file2text(filename) - - if (event_info) - custom_event_msg = event_info diff --git a/code/controllers/evacuation/evacuation.dm b/code/controllers/evacuation/evacuation.dm index 56b8c3bae35c..989b9cba4532 100644 --- a/code/controllers/evacuation/evacuation.dm +++ b/code/controllers/evacuation/evacuation.dm @@ -52,7 +52,7 @@ CRASH("[esp] has already been added as an evacuation predicate") evacuation_predicates += esp -/datum/evacuation_controller/proc/call_evacuation(var/mob/user, var/_emergency_evac, var/forced, var/skip_announce, var/autotransfer) +/datum/evacuation_controller/proc/call_evacuation(var/mob/user, var/_emergency_evac, var/forced, var/skip_announce = FALSE, var/autotransfer) if(state != EVAC_IDLE) return 0 @@ -86,15 +86,13 @@ state = EVAC_PREPPING if(emergency_evacuation) - for(var/area/A in world) - if(istype(A, /area/hallway)) + for(var/area/A in global.areas) + if(istype(A) && (A.area_flags & AREA_FLAG_HALLWAY)) A.readyalert() if(!skip_announce) - GLOB.using_map.emergency_shuttle_called_announcement() - else - if(!skip_announce) - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_called_message, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60)] minute\s")) - + global.using_map.emergency_shuttle_called_announcement() + else if(!skip_announce && global.using_map.shuttle_called_message) + priority_announcement.Announce(replacetext(replacetext(global.using_map.shuttle_called_message, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60)] minute\s")) return 1 /datum/evacuation_controller/proc/cancel_evacuation() @@ -113,13 +111,14 @@ auto_recall_time = null if(emergency_evacuation) - evac_recalled.Announce(GLOB.using_map.emergency_shuttle_recall_message) - for(var/area/A in world) - if(istype(A, /area/hallway)) + if(global.using_map.emergency_shuttle_recall_message) + evac_recalled.Announce(global.using_map.emergency_shuttle_recall_message) + for(var/area/A in global.areas) + if(istype(A) && (A.area_flags & AREA_FLAG_HALLWAY)) A.readyreset() emergency_evacuation = 0 - else - priority_announcement.Announce(GLOB.using_map.shuttle_recall_message) + else if(global.using_map.shuttle_recall_message) + priority_announcement.Announce(global.using_map.shuttle_recall_message) return 1 @@ -128,11 +127,9 @@ var/estimated_time = round(get_eta()/60,1) if (emergency_evacuation) - evac_waiting.Announce(replacetext(GLOB.using_map.emergency_shuttle_docked_message, "%ETD%", "[estimated_time] minute\s"), new_sound = sound('sound/effects/Evacuation.ogg', volume = 35)) + evac_waiting.Announce(replacetext(global.using_map.emergency_shuttle_docked_message, "%ETD%", "[estimated_time] minute\s"), new_sound = sound('sound/effects/Evacuation.ogg', volume = 35)) else - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_docked_message, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETD%", "[estimated_time] minute\s")) - if(config.announce_shuttle_dock_to_irc) - send2mainirc("The shuttle has docked with the station. It will depart in approximately [estimated_time] minute\s.") + priority_announcement.Announce(replacetext(replacetext(global.using_map.shuttle_docked_message, "%dock_name%", "[global.using_map.dock_name]"), "%ETD%", "[estimated_time] minute\s")) /datum/evacuation_controller/proc/launch_evacuation() @@ -142,9 +139,9 @@ state = EVAC_IN_TRANSIT if (emergency_evacuation) - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + priority_announcement.Announce(replacetext(replacetext(global.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) else - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + priority_announcement.Announce(replacetext(replacetext(global.using_map.shuttle_leaving_dock, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) return 1 diff --git a/code/controllers/evacuation/evacuation_helpers.dm b/code/controllers/evacuation/evacuation_helpers.dm index 9f8ae7deda70..45c0973a20e4 100644 --- a/code/controllers/evacuation/evacuation_helpers.dm +++ b/code/controllers/evacuation/evacuation_helpers.dm @@ -30,7 +30,7 @@ if(!isnull(evac_called_at)) return 0 - if (!GLOB.universe.OnShuttleCall(null)) + if (!global.universe.OnShuttleCall(null)) return 0 if(!forced) diff --git a/code/controllers/evacuation/evacuation_lifepods.dm b/code/controllers/evacuation/evacuation_lifepods.dm index 6367b64b4f6f..6b195d773678 100644 --- a/code/controllers/evacuation/evacuation_lifepods.dm +++ b/code/controllers/evacuation/evacuation_lifepods.dm @@ -17,7 +17,9 @@ if(waiting_to_leave()) return state = EVAC_IN_TRANSIT - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + var/msg = global.using_map.emergency_shuttle_leaving_dock + if(msg) + priority_announcement.Announce(replacetext(replacetext(msg, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) return 1 /datum/evacuation_controller/lifepods/available_evac_options() diff --git a/code/controllers/evacuation/evacuation_option.dm b/code/controllers/evacuation/evacuation_option.dm index c4012ba185c7..6ac1d392efd1 100644 --- a/code/controllers/evacuation/evacuation_option.dm +++ b/code/controllers/evacuation/evacuation_option.dm @@ -5,6 +5,7 @@ var/needs_syscontrol = FALSE var/silicon_allowed = TRUE var/abandon_ship = FALSE + var/requires_shunt = FALSE /datum/evacuation_option/proc/execute(var/mob/user) return \ No newline at end of file diff --git a/code/controllers/evacuation/evacuation_pods.dm b/code/controllers/evacuation/evacuation_pods.dm index 4f423aa36864..1747311b8061 100644 --- a/code/controllers/evacuation/evacuation_pods.dm +++ b/code/controllers/evacuation/evacuation_pods.dm @@ -42,11 +42,11 @@ pod.move_time = (evac_transit_delay/10) pod.launch(src) - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + priority_announcement.Announce(replacetext(replacetext(global.using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) else // FTL Jump - priority_announcement.Announce(replacetext(replacetext(GLOB.using_map.shuttle_leaving_dock, "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) - SetUniversalState(/datum/universal_state/jump, arguments=list(GLOB.using_map.station_levels)) + priority_announcement.Announce(replacetext(replacetext(global.using_map.shuttle_leaving_dock, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s")) + SetUniversalState(/datum/universal_state/jump, arguments=list(SSmapping.station_levels)) /datum/evacuation_controller/starship/finish_evacuation() ..() @@ -117,7 +117,7 @@ silicon_allowed = FALSE /datum/evacuation_option/cancel_abandon_ship/execute(mob/user) - if (SSevac.evacuation_controller && SSevac.evacuation_controller.cancel_evacuation()) + if (SSevac.evacuation_controller?.cancel_evacuation()) log_and_message_admins("[key_name(user)] has cancelled abandonment of the spacecraft.") /datum/evacuation_option/cancel_jump @@ -128,16 +128,9 @@ silicon_allowed = FALSE /datum/evacuation_option/cancel_jump/execute(mob/user) - if (SSevac.evacuation_controller && SSevac.evacuation_controller.cancel_evacuation()) + if (SSevac.evacuation_controller?.cancel_evacuation()) log_and_message_admins("[key_name(user)] has cancelled the FTL jump.") -/obj/screen/fullscreen/jump_overlay - icon = 'icons/effects/effects.dmi' - icon_state = "mfoam" - screen_loc = ui_entire_screen - color = "#ff9900" - blend_mode = BLEND_SUBTRACT - layer = FULLSCREEN_LAYER #undef EVAC_OPT_ABANDON_SHIP #undef EVAC_OPT_JUMP diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index cf2bced60eba..4042baed6b13 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -4,7 +4,7 @@ * Pretty much pokes the MC to make sure it's still alive. **/ -GLOBAL_REAL(Failsafe, /datum/controller/failsafe) +var/global/datum/controller/failsafe/Failsafe /datum/controller/failsafe // This thing pretty much just keeps poking the master controller name = "Failsafe" @@ -18,7 +18,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) // (Real friends look out for *eachother*) var/lasttick = 0 - // Track the MC iteration to make sure its still on track. + // Track the MC iteration to make sure it's still on track. var/master_iteration = 0 var/running = TRUE @@ -56,23 +56,23 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) if(4,5) --defcon if(3) - to_chat(GLOB.admins, "Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks.") + to_chat(global.admins, "Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks.") --defcon if(2) - to_chat(GLOB.admins, "Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.") + to_chat(global.admins, "Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.") --defcon if(1) - to_chat(GLOB.admins, "Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting...") + to_chat(global.admins, "Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting...") --defcon var/rtn = Recreate_MC() if(rtn > 0) defcon = 4 master_iteration = 0 - to_chat(GLOB.admins, "MC restarted successfully") + to_chat(global.admins, "MC restarted successfully") else if(rtn < 0) log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0") - to_chat(GLOB.admins, "ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.") + to_chat(global.admins, "ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.") //if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again //no need to handle that specially when defcon 0 can handle it if(0) //DEFCON 0! (mc failed to restart) @@ -80,7 +80,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) if(rtn > 0) defcon = 4 master_iteration = 0 - to_chat(GLOB.admins, "MC restarted successfully") + to_chat(global.admins, "MC restarted successfully") else defcon = min(defcon + 1,5) master_iteration = Master.iteration diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm deleted file mode 100644 index f1253bb0b6c0..000000000000 --- a/code/controllers/globals.dm +++ /dev/null @@ -1,61 +0,0 @@ -GLOBAL_REAL(GLOB, /datum/controller/global_vars) - -/datum/controller/global_vars - name = "Global Variables" - - var/list/gvars_datum_protected_varlist - var/list/gvars_datum_in_built_vars - var/list/gvars_datum_init_order - -/datum/controller/global_vars/New() - if(GLOB) - CRASH("Multiple instances of global variable controller created") - GLOB = src - - var/datum/controller/exclude_these = new - gvars_datum_in_built_vars = exclude_these.vars + list("gvars_datum_protected_varlist", "gvars_datum_in_built_vars", "gvars_datum_init_order") - qdel(exclude_these) - - var/global_vars = vars.len - gvars_datum_in_built_vars.len - var/global_procs = length(typesof(/datum/controller/global_vars/proc)) - - report_progress("[global_vars] global variables") - report_progress("[global_procs] global init procs") - - if(global_vars == global_procs) - Initialize() - else - crash_with("Expected [global_vars] global init procs, were [global_procs].") - -/datum/controller/global_vars/Destroy(force) - crash_with("There was an attempt to qdel the global vars holder!") - if(!force) - return QDEL_HINT_LETMELIVE - - QDEL_NULL(statclick) - gvars_datum_protected_varlist.Cut() - gvars_datum_in_built_vars.Cut() - - GLOB = null - - return ..() - -/datum/controller/global_vars/stat_entry() - if(!statclick) - statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - - stat("Globals:", statclick.update("Edit")) - -/datum/controller/global_vars/VV_hidden() - return ..() + gvars_datum_protected_varlist - -/datum/controller/global_vars/Initialize() - gvars_datum_init_order = list() - gvars_datum_protected_varlist = list("gvars_datum_protected_varlist") - - //See https://github.com/tgstation/tgstation/issues/26954 - for(var/I in typesof(/datum/controller/global_vars/proc)) - var/start_tick = world.time - call(src, I)() - if(world.time - start_tick) - warning("[I] slept during initialization!") diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm deleted file mode 100644 index 3b865e3efd6a..000000000000 --- a/code/controllers/hooks-defs.dm +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Global init hook. - * Called in global_init.dm when the server is initialized. - */ -/hook/global_init - -/** - * Startup hook. - * Called in world.dm when the server starts. - */ -/hook/startup - -/** - * Roundstart hook. - * Called in ticker.dm when a round starts. - */ -/hook/roundstart - -/** - * Roundend hook. - * Called in ticker.dm when a round ends. - */ -/hook/roundend - -/** - * Shutdown hook. - * Called in world.dm when world/Del is called. - */ -/hook/shutdown - -/** - * Death hook. - * Called in death.dm when someone dies. - * Parameters: var/mob/living/carbon/human, var/gibbed - */ -/hook/death - -/** - * Cloning hook. - * Called in cloning.dm when someone is brought back by the wonders of modern science. - * Parameters: var/mob/living/carbon/human - */ -/hook/clone - -/** - * Debrained hook. - * Called in brain_item.dm when someone gets debrained. - * Parameters: var/obj/item/organ/internal/brain - */ -/hook/debrain - -/** - * Borged hook. - * Called in robot_parts.dm when someone gets turned into a cyborg. - * Parameters: var/mob/living/silicon/robot - */ -/hook/borgify - -/** - * Payroll revoked hook. - * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal. - * Parameters: var/datum/money_account - */ -/hook/revoke_payroll - -/** - * Account suspension hook. - * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal. - * Parameters: var/datum/money_account - */ -/hook/change_account_status - -/** - * Employee reassignment hook. - * Called in card.dm when someone's card is reassigned at the HoP's desk. - * Parameters: var/obj/item/card/id - */ -/hook/reassign_employee - -/** - * Employee terminated hook. - * Called in card.dm when someone's card is terminated at the HoP's desk. - * Parameters: var/obj/item/card/id - */ -/hook/terminate_employee - -/** - * Crate sold hook. - * Called in supplyshuttle.dm when a crate is sold on the shuttle. - * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle - */ -/hook/sell_crate diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm deleted file mode 100644 index 2e05a0621b0f..000000000000 --- a/code/controllers/hooks.dm +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file hooks.dm - * Implements hooks, a simple way to run code on pre-defined events. - */ - -/** @page hooks Code hooks - * @section hooks Hooks - * A hook is defined under /hook in the type tree. - * - * To add some code to be called by the hook, define a proc under the type, as so: - * @code - hook/foo/proc/bar() - if(1) - return 1 //Sucessful - else - return 0 //Error, or runtime. - * @endcode - * All hooks must return nonzero on success, as runtimes will force return null. - */ - -/** - * Calls a hook, executing every piece of code that's attached to it. - * @param hook Identifier of the hook to call. - * @returns 1 if all hooked code runs successfully, 0 otherwise. - */ -/proc/callHook(hook, list/args=null) - var/hook_path = text2path("/hook/[hook]") - if(!hook_path) - error("Invalid hook '/hook/[hook]' called.") - return 0 - - var/caller = new hook_path - var/status = 1 - for(var/P in typesof("[hook_path]/proc")) - if(!call(caller, P)(arglist(args))) - error("Hook '[P]' failed or runtimed.") - status = 0 - - return status diff --git a/code/controllers/master.dm b/code/controllers/master.dm index fce50e6cc557..7c24faa29d7e 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -7,11 +7,10 @@ * **/ -//This is the ABSOLUTE ONLY THING that should init globally like this -GLOBAL_REAL(Master, /datum/controller/master) = new +var/global/datum/controller/master/Master = new //THIS IS THE INIT ORDER -//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe +//Master -> SSPreInit -> world -> config -> SSInit -> Failsafe //GOT IT MEMORIZED? /datum/controller/master @@ -77,9 +76,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new _subsystems += new I Master = src - if(!GLOB) - new /datum/controller/global_vars - /datum/controller/master/Destroy() ..() // Tell qdel() to Del() this object. @@ -145,7 +141,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined." BadBoy.flags |= SS_NO_FIRE if(msg) - to_chat(GLOB.admins, "[msg]") + to_chat(global.admins, "[msg]") log_world(msg) if (istype(Master.subsystems)) @@ -161,7 +157,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new // Please don't stuff random bullshit here, -// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in it's Initialize() +// Make a subsystem, give it the SS_NO_FIRE flag, and do your work in its Initialize() /datum/controller/master/Initialize(delay, init_sss) set waitfor = 0 @@ -180,7 +176,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/start_timeofday = REALTIMEOFDAY // Initialize subsystems. - current_ticklimit = config.tick_limit_mc_init + current_ticklimit = get_config_value(/decl/config/num/tick_limit_mc_init) for (var/datum/controller/subsystem/SS in subsystems) if (SS.flags & SS_NO_INIT) continue @@ -191,7 +187,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/msg = "Initializations complete within [time] second\s!" report_progress(msg) - log_world(msg) initializing = FALSE @@ -206,7 +201,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new #else world.sleep_offline = TRUE #endif - world.fps = config.fps + world.fps = get_config_value(/decl/config/num/fps) var/initialized_tod = REALTIMEOFDAY initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 @@ -224,12 +219,17 @@ GLOBAL_REAL(Master, /datum/controller/master) = new CRASH("Attempted to set invalid runlevel: [new_runlevel]") // Starts the mc, and sticks around to restart it if the loop ever ends. +var/global/_announced_start = FALSE /datum/controller/master/proc/StartProcessing(delay) set waitfor = 0 if(delay) sleep(delay) report_progress("Master starting processing") - SSwebhooks.send(WEBHOOK_ROUNDPREP, list("map" = station_name(), "url" = get_world_url())) + + if(!global._announced_start) // Only announce roundstart once. + SSwebhooks.send(WEBHOOK_ROUNDPREP, list("map" = station_name(), "url" = get_world_url())) + global._announced_start = TRUE + var/rtn = Loop() if (rtn > 0 || processing < 0) return //this was suppose to happen. @@ -243,6 +243,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new Failsafe.defcon = 2 // Main loop. +#define RUNLEVEL_MAX 16 /datum/controller/master/proc/Loop() . = -1 //Prep the loop (most of this is because we want MC restarts to reset as much state as we can, and because @@ -262,17 +263,17 @@ GLOBAL_REAL(Master, /datum/controller/master) = new SS.state = SS_IDLE if (SS.flags & SS_TICKER) tickersubsystems += SS - timer += world.tick_lag * rand(1, 5) + timer += world.tick_lag * rand(0,1) SS.next_fire = timer continue var/ss_runlevels = SS.runlevels var/added_to_any = FALSE - for(var/I in 1 to GLOB.bitflags.len) - if(ss_runlevels & GLOB.bitflags[I]) - while(runlevel_sorted_subsystems.len < I) + for(var/i in 1 to RUNLEVEL_MAX) + if(ss_runlevels & BITFLAG(i-1)) + while(runlevel_sorted_subsystems.len < i) runlevel_sorted_subsystems += list(list()) - runlevel_sorted_subsystems[I] += SS + runlevel_sorted_subsystems[i] += SS added_to_any = TRUE if(!added_to_any) WARNING("[SS.name] subsystem is not SS_NO_FIRE but also does not have any runlevels set!") @@ -283,7 +284,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new //(higher subsystems will be sooner in the queue, adding them later in the loop means we don't have to loop thru them next queue add) sortTim(tickersubsystems, /proc/cmp_subsystem_priority) for(var/I in runlevel_sorted_subsystems) - sortTim(runlevel_sorted_subsystems, /proc/cmp_subsystem_priority) + sortTim(I, /proc/cmp_subsystem_priority) I += tickersubsystems var/cached_runlevel = current_runlevel @@ -316,7 +317,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new continue //Byond resumed us late. assume it might have to do the same next tick - if (last_run + CEILING(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time) + if (last_run + NONUNIT_CEILING(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time) sleep_delta += 1 sleep_delta = MC_AVERAGE_FAST(sleep_delta, 1) //decay sleep_delta @@ -337,14 +338,16 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/checking_runlevel = current_runlevel if(cached_runlevel != checking_runlevel) //resechedule subsystems + var/list/old_subsystems = current_runlevel_subsystems cached_runlevel = checking_runlevel current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel] - var/stagger = world.time - for(var/I in current_runlevel_subsystems) - var/datum/controller/subsystem/SS = I - if(SS.next_fire <= world.time) - stagger += world.tick_lag * rand(1, 5) - SS.next_fire = stagger + + //now we'll go through all the subsystems we want to offset and give them a next_fire + for(var/datum/controller/subsystem/SS as anything in current_runlevel_subsystems) + //we only want to offset it if it's new and also behind + if(SS.next_fire > world.time || (SS in old_subsystems)) + continue + SS.next_fire = world.time + world.tick_lag * rand(0, DS2TICKS(min(SS.wait, 2 SECONDS))) subsystems_to_check = current_runlevel_subsystems else @@ -384,7 +387,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if (processing * sleep_delta <= world.tick_lag) current_ticklimit -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick sleep(world.tick_lag * (processing * sleep_delta)) - +#undef RUNLEVEL_MAX @@ -590,9 +593,44 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if(!statclick) statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) - stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))") + stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)") stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])")) +/// Colors cpu number before output. +/datum/controller/master/proc/format_color_cpu() + switch(world.cpu) + // 0-80 = green + if(0 to 80) + . = "[world.cpu]" + // 80-90 = orange + if(80 to 90) + . = "[world.cpu]" + // 90-100 = red + if(90 to 100) + . = "[world.cpu]" + // >100 = bold red + if(100 to INFINITY) + . = "[world.cpu]" + +/// Colors map cpu number before output. +/// Same as before, but specially for map cpu. +/// It uses same colors, but need different number range. +/datum/controller/master/proc/format_color_cpu_map() + var/current_map_cpu = MAPTICK_LAST_INTERNAL_TICK_USAGE + switch(current_map_cpu) + // 0-30 = green + if(0 to 30) + . = "[current_map_cpu]" + // 30-60 = orange + if(30 to 60) + . = "[current_map_cpu]" + // 60-80 = red + if(60 to 80) + . = "[current_map_cpu]" + // >100 = bold red + if(80 to INFINITY) + . = "[current_map_cpu]" + /datum/controller/master/StartLoadingMap() //disallow more than one map to load at once, multithreading it will just cause race conditions while(map_loading) diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 419b7a60b92d..cb1858d43f19 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -43,6 +43,8 @@ var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out! + var/_internal_name //! A stringified version of the variable name for this subsystem. Used by the processing subsystem to make sure is_processing is unset properly. + //Do not override ///datum/controller/subsystem/New() @@ -172,7 +174,7 @@ Initialize(timeofday) init_finish = REALTIMEOFDAY . = (REALTIMEOFDAY - timeofday)/10 - var/msg = "Initialized [name] subsystem within [.] second[. == 1 ? "" : "s"]!" + var/msg = "Initialized [name] subsystem within [.] second\s!" to_chat(world, "[msg]") log_world(msg) diff --git a/code/controllers/subsystems/DPC.dm b/code/controllers/subsystems/DPC.dm new file mode 100644 index 000000000000..1adde54dfb10 --- /dev/null +++ b/code/controllers/subsystems/DPC.dm @@ -0,0 +1,55 @@ +/* +This is pretty much just an optimization for wait=0 timers. They're relatively common, but generally don't actually need the more + complex features of SStimer. SSdpc can handle these timers instead (and it's a lot simpler than SStimer is), but it can't handle + timers with certain flags (check MC.dm). This doesn't need to be explicitly used, eligible timers are automatically converted. +*/ + +SUBSYSTEM_DEF(dpc) + name = "Delayed Procedure Call" + wait = 1 + runlevels = RUNLEVELS_ALL + priority = SS_PRIORITY_DPC + flags = SS_TICKER | SS_NO_INIT + + var/list/queued_calls = list() + var/avg = 0 + var/list/unique_queued_calls = list() + var/unique_avg = 0 + +/datum/controller/subsystem/dpc/stat_entry() + return ..() + " Q: [queued_calls.len], AQ: ~[round(avg)], UQ: [unique_queued_calls.len], UAQ: ~[round(unique_avg)]" + +/datum/controller/subsystem/dpc/fire(resumed = FALSE) + var/list/qc = queued_calls + var/list/uqc = unique_queued_calls + if (!resumed) + avg = MC_AVERAGE_FAST(avg, qc.len) + unique_avg = MC_AVERAGE_FAST(unique_avg, uqc.len) + + var/q_idex = 1 + + while (q_idex <= qc.len) + var/datum/callback/CB = qc[q_idex] + q_idex += 1 + + CB.InvokeAsync() + + if (MC_TICK_CHECK) + break + + if (q_idex > 1) + queued_calls.Cut(1, q_idex) + + q_idex = 1 // Reuse this variable so we don't waste time allocating two + while (q_idex <= uqc.len) + var/hash = uqc[q_idex] + var/datum/callback/CB = uqc[hash] + q_idex += 1 + + CB.InvokeAsync() + + if (MC_TICK_CHECK) + break + + if (q_idex > 1) + unique_queued_calls.Cut(1, q_idex) diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm index 47bbdd815c13..92e3271df809 100644 --- a/code/controllers/subsystems/air.dm +++ b/code/controllers/subsystems/air.dm @@ -36,13 +36,13 @@ Class Procs: Called when zones have a direct connection and equivalent pressure and temperature. Merges the zones to create a single zone. - connect(turf/simulated/A, turf/B) - Called by turf/update_air_properties(). The first argument must be simulated. + connect(turf/A, turf/B) + Called by turf/update_air_properties(). The first argument must participate in ZAS. Creates a connection between A and B. mark_zone_update(zone/Z) Adds zone to the update list. Unlike mark_for_update(), this one is called automatically whenever - air is returned from a simulated turf. + air is returned from a turf. equivalent_pressure(zone/A, zone/B) Currently identical to A.air.compare(B.air). Returns 1 when directly connected zones are ready to be merged. @@ -133,10 +133,18 @@ SUBSYSTEM_DEF(air) report_progress("Processing Geometry...") var/simulated_turf_count = 0 - for(var/turf/simulated/S) + for(var/turf/T in world) + // Although update_air_properties can be called on non-ZAS participating turfs for convenience, it is unnecessary on roundstart/reboot. + if(!SHOULD_PARTICIPATE_IN_ZONES(T)) + continue simulated_turf_count++ - S.update_air_properties() - + // We also skip anything already queued, since it'll be settled when fire() runs anyway. + if(T.needs_air_update) + continue + T.update_air_properties() + // air state is necessarily globally incomplete during this + // so we can't do T.post_update_air_properties(), which needs + // connections to have been settled already. CHECK_TICK report_progress({"Total Simulated Turfs: [simulated_turf_count] @@ -171,6 +179,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun var/list/curr_hotspot = processing_hotspots var/list/curr_zones = zones_to_update + var/airblock // zeroed by ATMOS_CANPASS_TURF, declared early as microopt while (curr_tiles.len) var/turf/T = curr_tiles[curr_tiles.len] curr_tiles.len-- @@ -184,9 +193,8 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun continue //check if the turf is self-zone-blocked - var/c_airblock - ATMOS_CANPASS_TURF(c_airblock, T, T) - if(c_airblock & ZONE_BLOCKED) + ATMOS_CANPASS_TURF(airblock, T, T) + if(airblock & ZONE_BLOCKED) deferred += T if (no_mc_tick) CHECK_TICK @@ -196,10 +204,9 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun T.update_air_properties() T.post_update_air_properties() - T.needs_air_update = 0 + T.needs_air_update = FALSE #ifdef ZASDBG - T.overlays -= mark - updated++ + T.remove_vis_contents(zasdbgovl_mark) #endif if (no_mc_tick) @@ -213,10 +220,9 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun T.update_air_properties() T.post_update_air_properties() - T.needs_air_update = 0 + T.needs_air_update = FALSE #ifdef ZASDBG - T.overlays -= mark - updated++ + T.remove_vis_contents(zasdbgovl_mark) #endif if (no_mc_tick) @@ -314,29 +320,37 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun B.c_merge(A) mark_zone_update(A) -/datum/controller/subsystem/air/proc/connect(turf/simulated/A, turf/simulated/B) +/datum/controller/subsystem/air/proc/connect(turf/A, turf/B) #ifdef ZASDBG - ASSERT(istype(A)) + ASSERT(isturf(A)) ASSERT(isturf(B)) ASSERT(A.zone) ASSERT(!A.zone.invalid) - //ASSERT(B.zone) ASSERT(A != B) #endif + if(!SHOULD_PARTICIPATE_IN_ZONES(A)) + return + var/block = air_blocked(A,B) - if(block & AIR_BLOCKED) return + if(block & AIR_BLOCKED) + return var/direct = !(block & ZONE_BLOCKED) - var/space = !istype(B) + var/space = !SHOULD_PARTICIPATE_IN_ZONES(B) if(!space) if(min(A.zone.contents.len, B.zone.contents.len) < ZONE_MIN_SIZE || (direct && (equivalent_pressure(A.zone,B.zone) || times_fired == 0))) merge(A.zone,B.zone) return + #ifdef MULTIZAS + var/a_to_b = get_dir_multiz(A,B) + var/b_to_a = get_dir_multiz(B,A) + #else var/a_to_b = get_dir(A,B) var/b_to_a = get_dir(B,A) + #endif if(!A.connections) A.connections = new if(!B.connections) B.connections = new @@ -360,13 +374,15 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun #ifdef ZASDBG ASSERT(isturf(T)) #endif - if(T.needs_air_update) + // don't queue us if we've already been queued + // and if SSair hasn't run, every turf in the world will get updated soon anyway + if(T.needs_air_update || !SSair.initialized) return tiles_to_update += T #ifdef ZASDBG - T.overlays += mark + T.add_vis_contents(zasdbgovl_mark) #endif - T.needs_air_update = 1 + T.needs_air_update = TRUE /datum/controller/subsystem/air/proc/mark_zone_update(zone/Z) #ifdef ZASDBG @@ -409,30 +425,15 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun return edge else for(var/connection_edge/unsimulated/edge in A.edges) - if(has_same_air(edge.B,B)) + var/datum/gas_mixture/opponent_air = edge.B.return_air() + var/turf/our_turf = B + if(opponent_air.compare(our_turf.return_air())) return edge var/connection_edge/edge = new/connection_edge/unsimulated(A,B) edges += edge edge.recheck() return edge -/datum/controller/subsystem/air/proc/has_same_air(turf/A, turf/B) - if(A.initial_gas) - if(!B.initial_gas) - return 0 - for(var/g in A.initial_gas) - if(A.initial_gas[g] != B.initial_gas[g]) - return 0 - if(B.initial_gas) - if(!A.initial_gas) - return 0 - for(var/g in B.initial_gas) - if(A.initial_gas[g] != B.initial_gas[g]) - return 0 - if(A.temperature != B.temperature) - return 0 - return 1 - /datum/controller/subsystem/air/proc/remove_edge(connection_edge/E) edges -= E if(!E.sleeping) diff --git a/code/controllers/subsystems/alarm.dm b/code/controllers/subsystems/alarm.dm index 2cca117bff3c..44d0cd196644 100644 --- a/code/controllers/subsystems/alarm.dm +++ b/code/controllers/subsystems/alarm.dm @@ -1,10 +1,10 @@ // We manually initialize the alarm handlers instead of looping over all existing types // to make it possible to write: camera.triggerAlarm() rather than SSalarm.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. -/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() -/var/global/datum/alarm_handler/camera/camera_alarm = new() -/var/global/datum/alarm_handler/fire/fire_alarm = new() -/var/global/datum/alarm_handler/motion/motion_alarm = new() -/var/global/datum/alarm_handler/power/power_alarm = new() +var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() +var/global/datum/alarm_handler/camera/camera_alarm = new() +var/global/datum/alarm_handler/fire/fire_alarm = new() +var/global/datum/alarm_handler/motion/motion_alarm = new() +var/global/datum/alarm_handler/power/power_alarm = new() SUBSYSTEM_DEF(alarm) name = "Alarm" diff --git a/code/controllers/subsystems/ambience.dm b/code/controllers/subsystems/ambience.dm new file mode 100644 index 000000000000..8f4b462e2050 --- /dev/null +++ b/code/controllers/subsystems/ambience.dm @@ -0,0 +1,102 @@ +SUBSYSTEM_DEF(ambience) + name = "Ambient Lighting" + wait = 1 + priority = SS_PRIORITY_LIGHTING + init_order = SS_INIT_LIGHTING + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT // Copied from icon update subsystem. + flags = SS_NO_INIT + var/list/queued = list() + +/datum/controller/subsystem/ambience/stat_entry() + ..("P:[length(queued)]") + +/datum/controller/subsystem/ambience/fire(resumed = FALSE, no_mc_tick = FALSE) + var/list/curr = queued + while (curr.len) + var/turf/target = curr[curr.len] + target.ambience_queued = FALSE + curr.len-- + if(!QDELETED(target)) + target.update_ambient_light_from_z_or_area() + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + return + +/datum/controller/subsystem/ambience/StartLoadingMap() + suspend() + +/datum/controller/subsystem/ambience/StopLoadingMap() + wake() + +/turf + /// Whether this turf has been queued for an ambient lighting update. + var/ambience_queued = FALSE + +/turf/proc/shows_outdoor_ambience() + return is_outside() + +// Starlight can't be blocked by stuff above a space turf. +// TODO: decide if open sky deserves the same treatment +/turf/space/shows_outdoor_ambience() + return TRUE + +/turf/proc/update_ambient_light_from_z_or_area() + + // If we're not outside, we don't show ambient light. + clear_ambient_light() // TODO: fix the delta issues resulting in burn-in so this can be run only when needed + + var/ambient_light_modifier + // If we're indoors because of our area, OR we're outdoors and not exposed to the weather, get interior ambience. + var/outsideness = shows_outdoor_ambience() + if((!outsideness && is_outside == OUTSIDE_AREA) || (outsideness && get_weather_exposure() != WEATHER_EXPOSED)) + var/area/A = get_area(src) + if(isnull(A?.interior_ambient_light_modifier)) + return FALSE + ambient_light_modifier = A.interior_ambient_light_modifier + else if(is_outside == OUTSIDE_NO) + return FALSE + + // If we're dynamically lit, we want ambient light regardless of neighbors. + var/lit = TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) + // If we're not, we want ambient light if one of our neighbors needs to show spillover from corners. + if(!lit) + for(var/turf/T as anything in RANGE_TURFS(src, 1)) + // Fuck if I know how these turfs are located in an area that is not an area. + if(isloc(T.loc) && TURF_IS_DYNAMICALLY_LIT_UNSAFE(T)) + lit = TRUE + break + + if(lit) + + // Grab what we need to set ambient light from our level handler. + var/datum/level_data/level_data = SSmapping.levels_by_z[z] + var/daycycle_id = level_data.daycycle_id + // if we don't have a daycycle ourselves, and we're indoors because of a turf blocking us + // find the first daycycle above us to use + if(!outsideness && !daycycle_id && HasAbove(z)) + var/turf/above = src + var/datum/level_data/above_level_data + while ((above = GetAbove(above))) + if((above.z_flags & ZM_TERMINATOR) || !HasAbove(above.z)) + break + above_level_data = SSmapping.levels_by_z[above.z] + if(above_level_data.daycycle_id) + daycycle_id = above_level_data.daycycle_id + break + + // Check for daycycle ambience. + if(daycycle_id) + var/datum/daycycle/daycycle = SSdaycycle.get_daycycle(daycycle_id) + var/new_power = daycycle?.current_period?.power + if(!isnull(new_power)) + if(new_power > 0) + set_ambient_light(daycycle.current_period.color, clamp(new_power + ambient_light_modifier, 0, 1)) + return TRUE + + // Apply general level ambience. + if(level_data?.ambient_light_level) + set_ambient_light(level_data.ambient_light_color, clamp(level_data.ambient_light_level + ambient_light_modifier, 0, 1)) + return TRUE + + return FALSE diff --git a/code/controllers/subsystems/antags.dm b/code/controllers/subsystems/antags.dm deleted file mode 100644 index 525c1c66afed..000000000000 --- a/code/controllers/subsystems/antags.dm +++ /dev/null @@ -1,13 +0,0 @@ -SUBSYSTEM_DEF(antags) - name = "Antags" - init_order = SS_INIT_ANTAGS - flags = SS_NO_FIRE - -/datum/controller/subsystem/antags/Initialize(timeofday) - for(var/antag_type in GLOB.all_antag_types_) - var/datum/antagonist/antag = GLOB.all_antag_types_[antag_type] - antag.Initialize() - . = ..() - -/datum/controller/subsystem/antags/stat_entry(msg) - ..("[GLOB.all_antag_types_.len] antag datums") \ No newline at end of file diff --git a/code/controllers/subsystems/ao.dm b/code/controllers/subsystems/ao.dm index 73b8abc52a5f..938c2df2a0f3 100644 --- a/code/controllers/subsystems/ao.dm +++ b/code/controllers/subsystems/ao.dm @@ -30,3 +30,9 @@ SUBSYSTEM_DEF(ao) CHECK_TICK else if (MC_TICK_CHECK) return + +/datum/controller/subsystem/ao/StartLoadingMap() + suspend() + +/datum/controller/subsystem/ao/StopLoadingMap() + wake() diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm index 6edacdd5038d..68e2940bcb41 100644 --- a/code/controllers/subsystems/atoms.dm +++ b/code/controllers/subsystems/atoms.dm @@ -8,15 +8,15 @@ SUBSYSTEM_DEF(atoms) init_order = SS_INIT_ATOMS flags = SS_NO_FIRE | SS_NEEDS_SHUTDOWN - // override and GetArguments() exists for mod-override/downstream hook functionality. - // Useful for total-overhaul type modifications. - var/adjust_init_arguments = FALSE - var/atom_init_stage = INITIALIZATION_INSSATOMS var/old_init_stage - var/list/late_loaders + /// An associative list of UIDs to atoms that were deserialized prior to flush. + var/list/deserialized_atoms = list() + /// A non-associative list of lists, with the format list(list(atom, list(Initialize arguments))). var/list/created_atoms = list() + /// A non-associative list of lists, with the format list(list(atom, list(LateInitialize arguments))). + var/list/late_loaders = list() var/list/BadInitializeCalls = list() @@ -26,71 +26,111 @@ SUBSYSTEM_DEF(atoms) return ..() /datum/controller/subsystem/atoms/proc/InitializeAtoms() - if(atom_init_stage <= INITIALIZATION_INSSATOMS_LATE) + if(atom_init_stage <= INITIALIZATION_INSSATOMS) return atom_init_stage = INITIALIZATION_INNEW_MAPLOAD - LAZYINITLIST(late_loaders) + // Preload any atoms that have deserialized during the initial load process prior to flush. + var/index = 1 + var/list/postinit_serde_atoms = list() + if(length(deserialized_atoms)) + while(index <= length(deserialized_atoms)) + var/uid = deserialized_atoms[index++] + var/atom/instance = deserialized_atoms[uid] + if(instance.Preload(deserialized_atoms) == SERDE_HINT_POSTINIT) + postinit_serde_atoms += instance + CHECK_TICK + report_progress("Deserialized [index-1] atom\s.") + index = 1 var/list/mapload_arg = list(TRUE) - - var/count = created_atoms.len - while(created_atoms.len) - var/atom/A = created_atoms[created_atoms.len] - created_atoms.len-- - if(!(A.atom_flags & ATOM_FLAG_INITIALIZED)) - InitAtom(A, GetArguments(A, mapload_arg)) + // Things can add to the end of this list while we iterate, so we can't use a for loop. + while(index <= length(created_atoms)) + // Don't remove from this list while we run, that's expensive. + // That would also make it harder to handle things added while we iterate. + var/list/creation_packet = created_atoms[index++] + var/atom/A = creation_packet[1] + var/list/atom_args = creation_packet[2] + // I sure hope nothing in this list is ever hard-deleted, or else QDELING will runtime. + // If you get a null reference runtime error, just change it back to QDELETED. + // The ATOM_FLAG_INITIALIZED check is because of INITIALIZE_IMMEDIATE(). + if(!QDELING(A) && !(A.atom_flags & ATOM_FLAG_INITIALIZED)) + if(atom_args) + atom_args.Insert(1, TRUE) + InitAtom(A, atom_args) + else + InitAtom(A, mapload_arg) CHECK_TICK + created_atoms.Cut() - // If wondering why not just store all atoms in created_atoms and use the block above: that turns out unbearably expensive. - // Instead, atoms without extra arguments in New created on server start are fished out of world directly. - // We do this exactly once. - if(!initialized) - for(var/atom/A in world) - if(!(A.atom_flags & ATOM_FLAG_INITIALIZED)) - InitAtom(A, GetArguments(A, mapload_arg, FALSE)) - ++count - CHECK_TICK - - report_progress("Initialized [count] atom\s") + report_progress("Initialized [index-1] atom\s.") atom_init_stage = INITIALIZATION_INNEW_REGULAR - if(late_loaders.len) - for(var/I in late_loaders) - var/atom/A = I - A.LateInitialize(arglist(late_loaders[A])) - report_progress("Late initialized [late_loaders.len] atom\s") + if(length(late_loaders)) + index = 1 + while(index <= length(late_loaders)) + var/list/creation_packet = late_loaders[index++] + var/atom/A = creation_packet[1] + A.LateInitialize(arglist(creation_packet[2])) + CHECK_TICK + report_progress("Late initialized [index] atom\s") late_loaders.Cut() + if(length(postinit_serde_atoms)) + index = 1 + while(index <= length(postinit_serde_atoms)) + var/atom/instance = postinit_serde_atoms[index++] + instance.DeserializePostInit(deserialized_atoms) + CHECK_TICK + postinit_serde_atoms.Cut() + + // Clear out the serde payloads now that everything should be tidied away. + if(length(deserialized_atoms)) + index = 1 + while(index <= length(deserialized_atoms)) + var/uid = deserialized_atoms[index++] + var/atom/instance = deserialized_atoms[uid] + if(istype(instance)) + instance.__deserialization_payload = null + CHECK_TICK + deserialized_atoms.Cut() + /datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments) var/the_type = A.type if(QDELING(A)) BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE return TRUE + // This is handled and battle tested by dreamchecker. Limit to UNIT_TEST just in case that ever fails. + #ifdef UNIT_TEST var/start_tick = world.time + #endif var/result = A.Initialize(arglist(arguments)) + #ifdef UNIT_TEST if(start_tick != world.time) BadInitializeCalls[the_type] |= BAD_INIT_SLEPT + #endif var/qdeleted = FALSE - if(result != INITIALIZE_HINT_NORMAL) - switch(result) - if(INITIALIZE_HINT_LATELOAD) - if(arguments[1]) //mapload - late_loaders[A] = arguments - else - A.LateInitialize(arglist(arguments)) - if(INITIALIZE_HINT_QDEL) - qdel(A) - qdeleted = TRUE + switch(result) + if(INITIALIZE_HINT_NORMAL) + EMPTY_BLOCK_GUARD + if(INITIALIZE_HINT_LATELOAD) + if(arguments[1]) //mapload + late_loaders[++late_loaders.len] = list(A, arguments) else - BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT + A.LateInitialize(arglist(arguments)) + if(INITIALIZE_HINT_QDEL) + A.atom_flags |= ATOM_FLAG_INITIALIZED // never call EarlyDestroy if we return this hint + qdel(A) + qdeleted = TRUE + else + BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT if(!A) //possible harddel qdeleted = TRUE @@ -99,27 +139,12 @@ SUBSYSTEM_DEF(atoms) return qdeleted || QDELING(A) -// override and GetArguments() exists for mod-override/downstream hook functionality. -// Useful for total-overhaul type modifications. -/atom/proc/AdjustInitializeArguments(list/arguments) - // Lists are passed by reference so can simply modify the arguments list without returning it - -/datum/controller/subsystem/atoms/proc/GetArguments(atom/A, list/mapload_arg, created=TRUE) - if(!created && !adjust_init_arguments) - return mapload_arg // Performance optimization. Nothing to do. - var/list/arguments = mapload_arg.Copy() - if(created && created_atoms[A]) - arguments += created_atoms[A] - if(adjust_init_arguments) - A.AdjustInitializeArguments(arguments) - return arguments - /datum/controller/subsystem/atoms/stat_entry(msg) ..("Bad Initialize Calls:[BadInitializeCalls.len]") /datum/controller/subsystem/atoms/proc/map_loader_begin() old_init_stage = atom_init_stage - atom_init_stage = INITIALIZATION_INSSATOMS_LATE + atom_init_stage = INITIALIZATION_INSSATOMS /datum/controller/subsystem/atoms/proc/map_loader_stop() atom_init_stage = old_init_stage @@ -148,9 +173,4 @@ SUBSYSTEM_DEF(atoms) /datum/controller/subsystem/atoms/Shutdown() var/initlog = InitLog() if(initlog) - text2file(initlog, "[GLOB.log_directory]/initialize.log") - -#undef BAD_INIT_QDEL_BEFORE -#undef BAD_INIT_DIDNT_INIT -#undef BAD_INIT_SLEPT -#undef BAD_INIT_NO_HINT + text2file(initlog, "[global.log_directory]/initialize.log") diff --git a/code/controllers/subsystems/configuration.dm b/code/controllers/subsystems/configuration.dm new file mode 100644 index 000000000000..a61105bc0644 --- /dev/null +++ b/code/controllers/subsystems/configuration.dm @@ -0,0 +1,156 @@ +SUBSYSTEM_DEF(configuration) + name = "Configuration" + flags = SS_NO_FIRE | SS_NO_INIT + var/list/configuration_file_locations = list() + var/load_sql_from = "config/dbconfig.txt" + var/load_event_from = "config/custom_event.txt" + +/datum/controller/subsystem/configuration/proc/load_all_configuration() + + // Assemble a list of all the files we are expected to load this run. + var/list/all_config = decls_repository.get_decls_of_subtype(/decl/configuration_category) + for(var/config_cat_type in all_config) + var/decl/configuration_category/config_cat = all_config[config_cat_type] + configuration_file_locations |= config_cat.configuration_file_location + + load_files() + load_sql() + load_event(load_event_from) + + for(var/client/C) + C.update_post_config_load() + +/client/proc/update_post_config_load() + if(get_config_value(/decl/config/toggle/allow_character_comments)) + verbs |= /client/proc/view_character_information + else + verbs -= /client/proc/view_character_information + +/datum/controller/subsystem/configuration/proc/write_default_configuration(var/list/specific_files, var/modify_write_prefix) + + if(!specific_files) + specific_files = configuration_file_locations + else if(!islist(specific_files)) + specific_files = list(specific_files) + + if(!length(specific_files)) + return + + var/list/config_lines = list() + var/list/all_config = decls_repository.get_decls_of_subtype(/decl/configuration_category) + var/list/sorted_config = list() + for(var/config_type in all_config) + sorted_config += all_config[config_type] + for(var/decl/configuration_category/config_cat as anything in sortTim(sorted_config, /proc/cmp_name_asc)) + if(!(config_cat.configuration_file_location in specific_files)) + continue + LAZYADD(config_lines["[modify_write_prefix][config_cat.configuration_file_location]"], config_cat.get_config_category_text()) + + . = list() + for(var/filename in config_lines) + if(fexists(filename)) + fdel(filename) + var/write_file = file(filename) + to_file(write_file, jointext(config_lines[filename], "\n\n")) + . += filename + return length(.) ? english_list(.) : "NULL" + +/datum/controller/subsystem/configuration/proc/load_files() + + // Load values from file into an assoc list. + var/list/loaded_values = list() + var/list/write_defaults = list() + for(var/filename in configuration_file_locations) + + if(!fexists(filename)) + write_defaults += filename + continue + + var/list/lines = file2list(filename) + for(var/line in lines) + line = trim(line) + if(!line || length(line) == 0 || copytext(line, 1, 2) == "#") + continue + var/pos = findtext(line, " ") + var/config_key + var/config_value + if(pos) + config_key = copytext(line, 1, pos) + config_value = copytext(line, pos + 1) + else + config_key = line + config_value = TRUE + if(config_key) + config_key = lowertext(trim(config_key)) + if(config_key in loaded_values) + PRINT_STACK_TRACE("Duplicate config value loaded for key '[config_key]' from file '[filename]'.") + loaded_values[config_key] = config_value + + // Write any defaults that aren't already populated. + if(length(write_defaults)) + write_default_configuration(write_defaults) + + // Set our config values on the decls. + var/list/config_to_refresh = list() + var/list/all_config_decls = decls_repository.get_decls_of_subtype(/decl/config) + for(var/config_type in all_config_decls) + var/decl/config/config_option = all_config_decls[config_type] + if(config_option.uid in loaded_values) + if(set_config_value(config_type, loaded_values[config_option.uid], defer_config_refresh = TRUE)) + config_to_refresh += config_option + loaded_values -= config_option.uid + + // Do a refresh now that all values are populated. + for(var/decl/config/config_option as anything in config_to_refresh) + config_option.update_post_value_set() + +/datum/controller/subsystem/configuration/proc/load_event(filename) + var/event_info = safe_file2text(filename, FALSE) + if(event_info) + global.custom_event_msg = event_info + +/datum/controller/subsystem/configuration/proc/load_sql() + var/list/lines = file2list(load_sql_from) + for(var/line in lines) + if(!line) + continue + line = trim(line) + if (length(line) == 0 || copytext(line, 1, 2) == "#") + continue + + var/pos = findtext(line, " ") + var/name = null + var/value = null + if (pos) + name = lowertext(copytext(line, 1, pos)) + value = copytext(line, pos + 1) + else + name = lowertext(line) + if (!name) + continue + + switch (name) + if ("enabled") + sqlenabled = TRUE + if ("address") + sqladdress = value + if ("port") + sqlport = value + if ("database") + sqldb = value + if ("login") + sqllogin = value + if ("password") + sqlpass = value + else + log_misc("Unknown setting in configuration: '[name]'") + +/datum/admins/proc/dump_configuration() + set category = "Admin" + set name = "Dump Configuration" + set desc = "Writes out the current configuration to file." + if(!ishost(usr?.client)) + to_chat(usr, SPAN_WARNING("This verb can only be used by the host.")) + return + var/write_loc = SSconfiguration.write_default_configuration(modify_write_prefix = "temp/") + to_chat(usr, SPAN_NOTICE("All done! The configuration file has been written to [write_loc] on your host.")) diff --git a/code/controllers/subsystems/daycycle.dm b/code/controllers/subsystems/daycycle.dm new file mode 100644 index 000000000000..be89594adce0 --- /dev/null +++ b/code/controllers/subsystems/daycycle.dm @@ -0,0 +1,53 @@ +///Subsystem for updating day/night ambient lighting for sets of z-levels that share a common day/night state. +SUBSYSTEM_DEF(daycycle) + name = "Day Cycle" + priority = SS_PRIORITY_DAYCYCLE + wait = 10 SECONDS + flags = SS_BACKGROUND | SS_POST_FIRE_TIMING | SS_NO_INIT + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + init_order = SS_INIT_TICKER + var/list/daycycles = list() + var/list/current_run + +/datum/controller/subsystem/daycycle/proc/remove_level(level_z, daycycle_id) + var/datum/daycycle/daycycle = get_daycycle(daycycle_id) + if(!daycycle) + return + if(islist(level_z)) + for(var/linked_level in level_z) + daycycle.remove_level(linked_level) + else + daycycle.remove_level(level_z) + +/datum/controller/subsystem/daycycle/proc/register_level(level_z, daycycle_id, daycycle_type = /datum/daycycle/exoplanet) + var/datum/daycycle/daycycle = get_daycycle(daycycle_id, daycycle_type, create_if_missing = TRUE) + if(islist(level_z)) + for(var/linked_level in level_z) + daycycle.add_level(linked_level) + else + daycycle.add_level(level_z) + +/datum/controller/subsystem/daycycle/proc/get_daycycle(daycycle_id, daycycle_type = /datum/daycycle/exoplanet, create_if_missing) + if(get_config_value(/decl/config/toggle/disable_daycycle)) + return //If disabled, we don't add anything + var/datum/daycycle/daycycle = daycycles[daycycle_id] + if(!daycycle && create_if_missing) + daycycle = new daycycle_type(daycycle_id) + daycycles[daycycle_id] = daycycle + return daycycle + +/datum/controller/subsystem/daycycle/fire(resumed = 0) + if(get_config_value(/decl/config/toggle/disable_daycycle)) + disable() + LAZYCLEARLIST(current_run) + return + if(!resumed) + current_run = daycycles?.Copy() + while(length(current_run)) + var/cycle_id = current_run[current_run.len] + var/datum/daycycle/cycle = current_run[cycle_id] + current_run.len-- + if(istype(cycle)) + cycle.tick() + if (MC_TICK_CHECK) + return diff --git a/code/controllers/subsystems/departments.dm b/code/controllers/subsystems/departments.dm deleted file mode 100644 index 27d9f28569d3..000000000000 --- a/code/controllers/subsystems/departments.dm +++ /dev/null @@ -1,16 +0,0 @@ -SUBSYSTEM_DEF(departments) - name = "Deparments" - init_order = SS_INIT_DEPARTMENTS - flags = SS_NO_FIRE - var/list/datum/department/departments = list() - -/datum/controller/subsystem/departments/Initialize() - for(var/dtype in subtypesof(/datum/department)) - var/datum/department/dept = dtype - var/dept_name = initial(dept.reference) - if(dept_name) - departments["[dept_name]"] = new dtype - for(var/thing in departments) - var/datum/department/dept = departments[thing] - dept.Initialize() - . = ..() \ No newline at end of file diff --git a/code/controllers/subsystems/evac.dm b/code/controllers/subsystems/evac.dm index 6e6929164e11..cc4869509227 100644 --- a/code/controllers/subsystems/evac.dm +++ b/code/controllers/subsystems/evac.dm @@ -6,12 +6,12 @@ SUBSYSTEM_DEF(evac) wait = 2 SECONDS var/datum/evacuation_controller/evacuation_controller - /datum/controller/subsystem/evac/Initialize() . = ..() - if(!evacuation_controller) - evacuation_controller = new GLOB.using_map.evac_controller_type () + if(!evacuation_controller && global.using_map.evac_controller_type) + evacuation_controller = new global.using_map.evac_controller_type() evacuation_controller.set_up() /datum/controller/subsystem/evac/fire() - evacuation_controller.process() \ No newline at end of file + if(evacuation_controller) + evacuation_controller.process() diff --git a/code/controllers/subsystems/event.dm b/code/controllers/subsystems/event.dm index daefd0549083..6412bef40015 100644 --- a/code/controllers/subsystems/event.dm +++ b/code/controllers/subsystems/event.dm @@ -26,16 +26,24 @@ SUBSYSTEM_DEF(event) //Subsystem procs /datum/controller/subsystem/event/Initialize() - if(!all_events) - all_events = subtypesof(/datum/event) + if(!event_containers) + // Order must conform to EVENT_LEVEL_MUNDANE, EVENT_LEVEL_MODERATE, EVENT_LEVEL_MAJOR. event_containers = list( - EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane, - EVENT_LEVEL_MODERATE = new/datum/event_container/moderate, - EVENT_LEVEL_MAJOR = new/datum/event_container/major - ) - if(GLOB.using_map.use_overmap) - overmap_event_handler.create_events(GLOB.using_map.overmap_z, GLOB.using_map.overmap_size, GLOB.using_map.overmap_event_areas) + new global.using_map.event_container_mundane, + new global.using_map.event_container_moderate, + new global.using_map.event_container_major + ) + all_events = null + + if(!all_events) + all_events = list() + for(var/datum/event_container/container in event_containers) + for(var/datum/event_meta/event in container.available_events) + if(event.event_type) + all_events |= event.event_type + + global.using_map.populate_overmap_events() . = ..() /datum/controller/subsystem/event/Recover() @@ -61,7 +69,7 @@ SUBSYSTEM_DEF(event) while (pos <= EVENT_LEVEL_MAJOR) event_containers[pos].process() pos++ - + if (MC_TICK_CHECK) return @@ -110,21 +118,22 @@ SUBSYSTEM_DEF(event) if(E.isRunning) message += "and is still running." else - if(E.endedAt - E.startedAt > MinutesToTicks(5)) // Only mention end time if the entire duration was more than 5 minutes + if(E.endedAt - E.startedAt > 5 MINUTES) // Only mention end time if the entire duration was more than 5 minutes message += "and ended at [worldtime2stationtime(E.endedAt)]." else message += "and ran to completion." to_world(message) -//Event manager UI +//Event manager UI /datum/controller/subsystem/event/proc/GetInteractWindow() - var/html = "Refresh" - html += "Pause All - [config.allow_random_events ? "Pause" : "Resume"]" + var/allow_random_events = get_config_value(/decl/config/toggle/on/allow_random_events) + var/html = "Refresh" + html += "Pause All - [allow_random_events ? "Pause" : "Resume"]" if(selected_event_container) var/event_time = max(0, selected_event_container.next_event_time - world.time) - html += "Back
" + html += "Back
" html += "Time till start: [round(event_time / 600, 0.1)]
" html += "
" html += "

Available [severity_to_string[selected_event_container.severity]] Events (queued & running events will not be displayed)

" @@ -134,13 +143,13 @@ SUBSYSTEM_DEF(event) for(var/datum/event_meta/EM in selected_event_container.available_events) html += "" html += "[EM.name]" - html += "[EM.weight]" + html += "[EM.weight]" html += "[EM.min_weight]" html += "[EM.max_weight]" - html += "[EM.one_shot]" - html += "[EM.enabled]" + html += "[EM.one_shot]" + html += "[EM.enabled]" html += "[selected_event_container.get_weight(EM, active_with_role)]" - html += "Remove" + html += "Remove" html += "" html += "" html += "
" @@ -150,16 +159,16 @@ SUBSYSTEM_DEF(event) html += "" html += "NameTypeWeightOneShot" html += "" - html += "[new_event.name ? new_event.name : "Enter Event"]" - html += "[new_event.event_type ? new_event.event_type : "Select Type"]" - html += "[new_event.weight ? new_event.weight : 0]" - html += "[new_event.one_shot]" + html += "[new_event.name ? new_event.name : "Enter Event"]" + html += "[new_event.event_type ? new_event.event_type : "Select Type"]" + html += "[new_event.weight ? new_event.weight : 0]" + html += "[new_event.one_shot]" html += "" html += "" - html += "Add
" + html += "Add
" html += "" else - html += "Round End Report: [report_at_round_end ? "On": "Off"]
" + html += "Round End Report: [report_at_round_end ? "On": "Off"]
" html += "
" html += "

Event Start

" @@ -173,16 +182,16 @@ SUBSYSTEM_DEF(event) html += "[worldtime2stationtime(max(EC.next_event_time, world.time))]" html += "[round(next_event_at / 600, 0.1)]" html += "" - html += "--" - html += "-" - html += "+" - html += "++" + html += "--" + html += "-" + html += "+" + html += "++" html += "" html += "" - html += "[EC.delayed ? "Resume" : "Pause"]" + html += "[EC.delayed ? "Resume" : "Pause"]" html += "" html += "" - html += "[EC.delay_modifier]" + html += "[EC.delay_modifier]" html += "" html += "" html += "" @@ -197,9 +206,9 @@ SUBSYSTEM_DEF(event) var/datum/event_meta/EM = EC.next_event html += "" html += "[severity_to_string[severity]]" - html += "[EM ? EM.name : "Random"]" - html += "View" - html += "Clear" + html += "[EM ? EM.name : "Random"]" + html += "View" + html += "Clear" html += "" html += "" html += "
" @@ -220,7 +229,7 @@ SUBSYSTEM_DEF(event) html += "[EM.name]" html += "[worldtime2stationtime(ends_at)]" html += "[ends_in]" - html += "Stop" + html += "Stop" html += "" html += "" html += "" @@ -254,8 +263,8 @@ SUBSYSTEM_DEF(event) EC.delayed = !EC.delayed log_and_message_admins("has [EC.delayed ? "paused" : "resumed"] countdown for [severity_to_string[EC.severity]] events.") else if(href_list["pause_all"]) - config.allow_random_events = text2num(href_list["pause_all"]) - log_and_message_admins("has [config.allow_random_events ? "resumed" : "paused"] countdown for all events.") + set_config_value(/decl/config/toggle/on/allow_random_events, text2num(href_list["pause_all"])) + log_and_message_admins("has [get_config_value(/decl/config/toggle/on/allow_random_events) ? "resumed" : "paused"] countdown for all events.") else if(href_list["interval"]) var/delay = input("Enter delay modifier. A value less than one means events fire more often, higher than one less often.", "Set Interval Modifier") as num|null if(delay && delay > 0) diff --git a/code/controllers/subsystems/fluids.dm b/code/controllers/subsystems/fluids.dm index 3d749ffca106..e0248091c4ea 100644 --- a/code/controllers/subsystems/fluids.dm +++ b/code/controllers/subsystems/fluids.dm @@ -1,179 +1,262 @@ SUBSYSTEM_DEF(fluids) name = "Fluids" - wait = 10 + wait = 1 SECOND + priority = SS_PRIORITY_FLUIDS flags = SS_NO_INIT + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT // So we can flush our queued activity during lobby setup on ocean maps. - var/next_fluid_act = 0 - var/fluid_act_delay = 15 // A bit longer than machines. + var/tmp/list/water_sources = list() + var/tmp/fluid_sources_copied_yet = FALSE + var/tmp/list/processing_sources - var/list/active_fluids = list() - var/list/water_sources = list() - var/list/hygiene_props = list() + var/tmp/list/pending_flows = list() + var/tmp/flows_copied_yet = FALSE + var/tmp/list/processing_flows - var/tmp/list/processing_sources - var/tmp/list/processing_fluids + var/tmp/list/holders_to_update = list() + var/tmp/holders_copied_yet = FALSE + var/tmp/list/processing_holders - var/obj/equalizing_reagent_holder + var/tmp/list/active_fluids = list() var/tmp/active_fluids_copied_yet = FALSE - var/af_index = 1 - var/list/fluid_images = list() + var/tmp/list/processing_fluids - var/list/gurgles = list( + var/tmp/list/checked_targets = list() + var/tmp/list/gurgles = list( 'sound/effects/gurgle1.ogg', 'sound/effects/gurgle2.ogg', 'sound/effects/gurgle3.ogg', 'sound/effects/gurgle4.ogg' - ) - -/datum/controller/subsystem/fluids/New(start_timeofday) - equalizing_reagent_holder = new - equalizing_reagent_holder.unacidable = TRUE - equalizing_reagent_holder.atom_flags |= (ATOM_FLAG_NO_TEMP_CHANGE|ATOM_FLAG_OPEN_CONTAINER|ATOM_FLAG_NO_REACT) - equalizing_reagent_holder.create_reagents(FLUID_MAX_DEPTH * 9 * 3) - ..() + ) /datum/controller/subsystem/fluids/stat_entry() ..("A:[active_fluids.len] S:[water_sources.len]") /datum/controller/subsystem/fluids/fire(resumed = 0) - if (!resumed) - processing_sources = water_sources.Copy() + + if(!resumed) active_fluids_copied_yet = FALSE - af_index = 1 - - var/list/curr_sources = processing_sources - var/list/checked = list() - while (curr_sources.len) - curr_sources.len-- - var/flooded_a_neighbor - var/turf/T = curr_sources[curr_sources.len] - UPDATE_FLUID_BLOCKED_DIRS(T) - for(var/spread_dir in GLOB.cardinal) - if(T.fluid_blocked_dirs & spread_dir) + holders_copied_yet = FALSE + flows_copied_yet = FALSE + fluid_sources_copied_yet = FALSE + checked_targets.Cut() + + if(!fluid_sources_copied_yet) + fluid_sources_copied_yet = TRUE + processing_sources = water_sources.Copy() + + // Predeclaring a bunch of vars for performance purposes. + var/flooded_a_neighbor = FALSE + var/spread_dir = 0 + var/i = 0 + var/turf/current_fluid_holder = null + var/datum/reagents/reagent_holder = null + var/turf/neighbor = null + var/turf/lowest_neighbor = null + + while(i < processing_sources.len) + i++ + current_fluid_holder = processing_sources[i] + + flooded_a_neighbor = FALSE + UPDATE_FLUID_BLOCKED_DIRS(current_fluid_holder) + for(spread_dir in global.cardinal) + if(current_fluid_holder.fluid_blocked_dirs & spread_dir) continue - var/turf/next = get_step(T, spread_dir) - if(!istype(next) || next.flooded) + neighbor = get_step_resolving_mimic(current_fluid_holder, spread_dir) + if(!istype(neighbor) || neighbor.flooded) continue - UPDATE_FLUID_BLOCKED_DIRS(next) - if((next.fluid_blocked_dirs & GLOB.reverse_dir[spread_dir]) || !next.CanFluidPass(spread_dir) || checked[next]) + UPDATE_FLUID_BLOCKED_DIRS(neighbor) + if((neighbor.fluid_blocked_dirs & global.reverse_dir[spread_dir]) || !neighbor.CanFluidPass(spread_dir) || checked_targets[neighbor]) continue - checked[next] = TRUE + checked_targets[neighbor] = TRUE flooded_a_neighbor = TRUE - var/obj/effect/fluid/F = locate() in next - if(!F) - F = new /obj/effect/fluid(next) - var/datum/gas_mixture/GM = T.return_air() - if(GM) F.temperature = GM.temperature - if(F) - if(F.reagents.total_volume < FLUID_MAX_DEPTH) - F.reagents.add_reagent(/decl/material/liquid/water, FLUID_MAX_DEPTH - F.reagents.total_volume) + if(current_fluid_holder.contaminant_reagent_type && current_fluid_holder.contaminant_proportion) + neighbor.add_to_reagents_contaminated(current_fluid_holder.flooded, FLUID_MAX_DEPTH, contaminant_type = current_fluid_holder.contaminant_reagent_type, contaminant_proportion = current_fluid_holder.contaminant_proportion) + else + neighbor.add_to_reagents(current_fluid_holder.flooded, FLUID_MAX_DEPTH) + if(!flooded_a_neighbor) - REMOVE_ACTIVE_FLUID_SOURCE(T) + REMOVE_ACTIVE_FLUID_SOURCE(current_fluid_holder) + if (MC_TICK_CHECK) + processing_sources.Cut(1, i+1) return + processing_sources.Cut() - if (!active_fluids_copied_yet) + if(!active_fluids_copied_yet) active_fluids_copied_yet = TRUE processing_fluids = active_fluids.Copy() - // We need to iterate through this list a few times, so we're using indexes instead of a while-truncate loop. - checked.Cut() - while (af_index <= processing_fluids.len) + var/removing = 0 + var/coming_from = 0 + var/flow_amount = 0 + var/current_depth = 0 + var/current_turf_depth = 0 + var/neighbor_depth = 0 + var/lowest_neighbor_flow = 0 + var/lowest_neighbor_depth = INFINITY + var/turf/other_fluid_holder = null + + i = 0 + while(i < processing_fluids.len) + i++ + current_fluid_holder = processing_fluids[i] - var/obj/effect/fluid/F = processing_fluids[af_index++] - if(QDELETED(F)) - processing_fluids -= F + if(QDELETED(current_fluid_holder) || !REAGENT_TOTAL_VOLUME(current_fluid_holder.reagents)) + REMOVE_ACTIVE_FLUID(current_fluid_holder) continue - var/turf/T = F.loc - checked[T] = TRUE - if(!T.CanFluidPass() || F.reagents.total_volume <= FLUID_EVAPORATION_POINT) - qdel(F) + if(!current_fluid_holder.CanFluidPass()) + current_fluid_holder.displace_all_reagents() continue - if(T.density || istype(T, /turf/space) || istype(T, /turf/simulated/floor/exoplanet)) - F.reagents.remove_any(max(FLUID_EVAPORATION_POINT-1, round(F.reagents.total_volume * 0.5))) - if(F.reagents.total_volume <= FLUID_EVAPORATION_POINT) - qdel(F) + reagent_holder = current_fluid_holder.reagents + UPDATE_FLUID_BLOCKED_DIRS(current_fluid_holder) + current_depth = REAGENT_TOTAL_VOLUME(reagent_holder) + + // How is this happening + if(QDELETED(reagent_holder) || current_depth == -1.#IND || current_depth == 1.#IND) + REMOVE_ACTIVE_FLUID(current_fluid_holder) continue - REMOVE_ACTIVE_FLUID(F) // This will be refreshed if our level changes at all in this iteration of the subsystem. - UPDATE_FLUID_BLOCKED_DIRS(T) - if(!(T.fluid_blocked_dirs & DOWN) && T.is_open() && T.has_gravity()) - var/turf/below = GetBelow(T) - if(below) - UPDATE_FLUID_BLOCKED_DIRS(below) - if(!(below.fluid_blocked_dirs & UP)) - var/obj/effect/fluid/other = locate() in below - if(!other) - other = new(below) - if(other && other.reagents.total_volume < FLUID_MAX_DEPTH) - F.reagents.trans_to_holder(other.reagents, min(Floor(F.reagents.total_volume*0.5), FLUID_MAX_DEPTH - other.reagents.total_volume)) - continue - - if(F.reagents.total_volume > FLUID_PUDDLE) - for(var/spread_dir in GLOB.cardinal) - if(T.fluid_blocked_dirs & spread_dir) - continue - var/turf/neighbor_turf = get_step(T, spread_dir) - if(!istype(neighbor_turf) || neighbor_turf.flooded) - continue - var/coming_from = GLOB.reverse_dir[spread_dir] - UPDATE_FLUID_BLOCKED_DIRS(neighbor_turf) - if((neighbor_turf.fluid_blocked_dirs & coming_from) || checked[neighbor_turf] || !neighbor_turf.CanFluidPass(coming_from)) - continue - checked[neighbor_turf] = TRUE - var/obj/effect/fluid/other = locate() in neighbor_turf.contents - if(!other) - if(F.reagents.total_volume >= 2) - other = new /obj/effect/fluid(neighbor_turf) - F.reagents.trans_to_holder(other.reagents, 1) - else - qdel(F) - break + // Evaporation: todo, move liquid into current_fluid_holder.zone air contents if applicable. + if(current_depth <= FLUID_PUDDLE && prob(60)) + current_fluid_holder.remove_fluids(min(current_depth, 1), defer_update = TRUE) + current_depth = current_fluid_holder.get_fluid_depth() + + // Mimimum liquid depth for creation of slurries. Do this after evaporation since it may change the total depth. + if(REAGENT_TOTAL_LIQUID_VOLUME(reagent_holder) < FLUID_SLURRY) + current_fluid_holder.dump_solid_reagents() + current_depth = current_fluid_holder.get_fluid_depth() + + if(current_depth <= FLUID_QDEL_POINT) + current_fluid_holder.reagents?.clear_reagents() + REMOVE_ACTIVE_FLUID(current_fluid_holder) + continue + + // Wash our turf. + current_fluid_holder.fluid_act(reagent_holder) + + if(isspaceturf(current_fluid_holder) || (istype(current_fluid_holder, /turf/floor) && (current_fluid_holder.turf_flags & TURF_FLAG_ABSORB_LIQUID) && (REAGENT_TOTAL_VOLUME(current_fluid_holder.reagents) + current_fluid_holder.get_physical_height()) > 0)) + removing = round(current_depth * 0.5) + if(removing > 0) + current_fluid_holder.remove_fluids(removing, defer_update = TRUE) + else + // Dump any solids in case there were any in slurry. + current_fluid_holder.dump_solid_reagents() + reagent_holder.clear_reagents() + current_depth = current_fluid_holder.get_fluid_depth() + if(current_depth <= FLUID_QDEL_POINT) + current_fluid_holder.reagents?.clear_reagents() + REMOVE_ACTIVE_FLUID(current_fluid_holder) + continue + + if(!(current_fluid_holder.fluid_blocked_dirs & DOWN) && current_fluid_holder.CanFluidPass(DOWN) && current_fluid_holder.is_open() && current_fluid_holder.has_gravity()) + other_fluid_holder = GetBelow(current_fluid_holder) + if(other_fluid_holder) + UPDATE_FLUID_BLOCKED_DIRS(other_fluid_holder) + if(!(other_fluid_holder.fluid_blocked_dirs & UP) && other_fluid_holder.CanFluidPass(UP)) + var/other_volume = REAGENT_TOTAL_VOLUME(other_fluid_holder.reagents) + if(!QDELETED(other_fluid_holder) && other_volume < FLUID_MAX_DEPTH) + current_fluid_holder.transfer_fluids_to(other_fluid_holder, min(floor(current_depth*0.5), FLUID_MAX_DEPTH - other_volume)) + current_depth = current_fluid_holder.get_fluid_depth() + + // Flow into the lowest level neighbor. + lowest_neighbor_depth = INFINITY + lowest_neighbor_flow = 0 + current_turf_depth = current_depth + current_fluid_holder.get_physical_height() + for(spread_dir in global.cardinal) + if(current_fluid_holder.fluid_blocked_dirs & spread_dir) + continue + neighbor = get_step_resolving_mimic(current_fluid_holder, spread_dir) + if(!neighbor) + continue + UPDATE_FLUID_BLOCKED_DIRS(neighbor) + coming_from = global.reverse_dir[spread_dir] + if((neighbor.fluid_blocked_dirs & coming_from) || !neighbor.CanFluidPass(coming_from) || neighbor.is_flooded(absolute = TRUE) || !neighbor.CanFluidPass(global.reverse_dir[spread_dir])) + continue + other_fluid_holder = neighbor + neighbor_depth = (REAGENT_TOTAL_VOLUME(other_fluid_holder.reagents)) + neighbor.get_physical_height() + flow_amount = round((current_turf_depth - neighbor_depth)*0.5) + // TODO: multiply flow amount or minimum transfer amount by some + // viscosity calculation to allow for piles of jelly vs piles of water. + if(flow_amount <= FLUID_MINIMUM_TRANSFER) + continue + ADD_ACTIVE_FLUID(neighbor) + if(neighbor_depth < lowest_neighbor_depth || (neighbor_depth == lowest_neighbor_depth && prob(50))) + lowest_neighbor = neighbor + lowest_neighbor_depth = neighbor_depth + lowest_neighbor_flow = flow_amount + + if(current_depth <= FLUID_PUDDLE) + continue + + if(lowest_neighbor && lowest_neighbor_flow) + current_fluid_holder.transfer_fluids_to(lowest_neighbor, lowest_neighbor_flow) + pending_flows[current_fluid_holder] = TRUE + if(lowest_neighbor_flow >= FLUID_PUSH_THRESHOLD) + current_fluid_holder.last_flow_strength = lowest_neighbor_flow + current_fluid_holder.last_flow_dir = get_dir(current_fluid_holder, lowest_neighbor) + else + current_fluid_holder.last_flow_strength = 0 + current_fluid_holder.last_flow_dir = 0 + else + // We aren't interacting with a neighbor this time, so we can likely sleep. + REMOVE_ACTIVE_FLUID(current_fluid_holder) if (MC_TICK_CHECK) + processing_fluids.Cut(1, i+1) return + processing_fluids.Cut() - af_index = 1 - while (af_index <= processing_fluids.len) + if(!holders_copied_yet) + holders_copied_yet = TRUE + processing_holders = holders_to_update.Copy() - var/obj/effect/fluid/F = processing_fluids[af_index++] - if (QDELETED(F)) - processing_fluids -= F - continue + i = 0 + while(i < processing_holders.len) + i++ + reagent_holder = processing_holders[i] + reagent_holder.handle_update() + if(MC_TICK_CHECK) + processing_holders.Cut(1, i+1) + return + processing_holders.Cut() - // Equalize across our neighbors. Hardcoded here for performance reasons. - if(!length(F.neighbors) || F.reagents.total_volume <= FLUID_PUDDLE) + if(!flows_copied_yet) + flows_copied_yet = TRUE + processing_flows = pending_flows.Copy() + + i = 0 + while(i < processing_flows.len) + i++ + current_fluid_holder = processing_flows[i] + if(!istype(current_fluid_holder) || QDELETED(current_fluid_holder)) continue + var/pushed_something = FALSE + + if(current_fluid_holder.last_flow_strength >= 10) + // Catwalks mean items will be above the turf; subtract the turf height from our volume. + // TODO: somehow handle stuff that is on a catwalk or on the turf within the same turf. + var/effective_volume = REAGENT_TOTAL_VOLUME(current_fluid_holder.reagents) + if(current_fluid_holder.get_supporting_platform()) + // Depth is negative height, hence +=. TODO: positive heights? No idea how to handle that. + effective_volume += current_fluid_holder.get_physical_height() + if(effective_volume > FLUID_SHALLOW) + for(var/atom/movable/AM as anything in current_fluid_holder.get_contained_external_atoms()) + if(AM.try_fluid_push(effective_volume, current_fluid_holder.last_flow_strength)) + AM.pushed(current_fluid_holder.last_flow_dir) + pushed_something = TRUE + if(pushed_something && prob(1)) + playsound(current_fluid_holder, 'sound/effects/slosh.ogg', 25, 1) + if(MC_TICK_CHECK) + processing_flows.Cut(1, i+1) + return + processing_flows.Cut() - var/sufficient_delta = FALSE - for(var/thing in F.neighbors) - var/obj/effect/fluid/other = thing - if(abs(F.reagents.total_volume - other.reagents.total_volume) > FLUID_EVAPORATION_POINT) - sufficient_delta = TRUE - break - - F.last_flow_strength = 0 - var/setting_dir = 0 - if(sufficient_delta) - equalizing_reagent_holder.reagents.clear_reagents() - for(var/thing in F.neighbors) - var/obj/effect/fluid/other = thing - var/flow_amount = F.reagents.total_volume - other.reagents.total_volume - if(F.last_flow_strength < flow_amount && flow_amount >= FLUID_PUSH_THRESHOLD) - F.last_flow_strength = flow_amount - setting_dir = get_dir(F, other) - other.reagents.trans_to_holder(equalizing_reagent_holder.reagents, other.reagents.total_volume) - F.reagents.trans_to_holder(equalizing_reagent_holder.reagents, F.reagents.total_volume) - - var/equalize_amt = round(equalizing_reagent_holder.reagents.total_volume / (length(F.neighbors)+1)) - for(var/thing in F.neighbors) - var/obj/effect/fluid/other = thing - equalizing_reagent_holder.reagents.trans_to_holder(other.reagents, equalize_amt) - equalizing_reagent_holder.reagents.trans_to_holder(F.reagents, equalizing_reagent_holder.reagents.total_volume) - - F.set_dir(setting_dir) +/datum/controller/subsystem/fluids/StartLoadingMap() + suspend() - if (MC_TICK_CHECK) - return +/datum/controller/subsystem/fluids/StopLoadingMap() + wake() diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index b08a6d2c2e65..ac728a55ea21 100644 --- a/code/controllers/subsystems/garbage.dm +++ b/code/controllers/subsystems/garbage.dm @@ -3,8 +3,8 @@ if(istype(D,/atom/movable)) {\ var/atom/movable/AM = D; \ if(AM.loc != null) {\ - crash_with("QDEL("+hint+"): "+AM.name+" was supposed to be in nullspace but isn't \ - (LOCATION= "+AM.loc.name+" ("+AM.loc.x+","+AM.loc.y+","+AM.loc.z+") )! Destroy didn't do its job!"); \ + PRINT_STACK_TRACE("QDEL([hint]): [AM.name] was supposed to be in nullspace but isn't \ + (LOCATION= [AM.loc.name] ([AM.loc.x],[AM.loc.y],[AM.loc.z]) )! Destroy didn't do its job!"); \ AM.forceMove(null); \ } \ } @@ -17,7 +17,7 @@ SUBSYSTEM_DEF(garbage) runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY init_order = SS_INIT_GARBAGE - var/list/collection_timeout = list(0, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level + var/list/collection_timeout = list(GC_FILTER_QUEUE, GC_CHECK_QUEUE, GC_DEL_QUEUE) // deciseconds to wait before moving something up in the queue to the next level //Stat tracking var/delslasttick = 0 // number of del()'s we've done this tick @@ -37,7 +37,7 @@ SUBSYSTEM_DEF(garbage) //Queue var/list/queues - #ifdef TESTING + #ifdef REFTRACKING_ENABLED var/list/reference_find_on_fail = list() #endif @@ -97,13 +97,13 @@ SUBSYSTEM_DEF(garbage) /datum/controller/subsystem/garbage/fire() //the fact that this resets its processing each fire (rather then resume where it left off) is intentional. - var/queue = GC_QUEUE_PREQUEUE + var/queue = GC_QUEUE_FILTER while (state == SS_RUNNING) switch (queue) - if (GC_QUEUE_PREQUEUE) - HandlePreQueue() - queue = GC_QUEUE_PREQUEUE+1 + if (GC_QUEUE_FILTER) + HandleQueue(GC_QUEUE_FILTER) + queue = GC_QUEUE_FILTER+1 if (GC_QUEUE_CHECK) HandleQueue(GC_QUEUE_CHECK) queue = GC_QUEUE_CHECK+1 @@ -114,27 +114,8 @@ SUBSYSTEM_DEF(garbage) if (state == SS_PAUSED) //make us wait again before the next run. state = SS_RUNNING -//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond. -//Don't attempt to optimize, not worth the effort. -/datum/controller/subsystem/garbage/proc/HandlePreQueue() - var/list/tobequeued = queues[GC_QUEUE_PREQUEUE] - var/static/count = 0 - if (count) - var/c = count - count = 0 //so if we runtime on the Cut, we don't try again. - tobequeued.Cut(1,c+1) - - for (var/ref in tobequeued) - count++ - Queue(ref, GC_QUEUE_PREQUEUE+1) - if (MC_TICK_CHECK) - break - if (count) - tobequeued.Cut(1,count+1) - count = 0 - -/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK) - if (level == GC_QUEUE_CHECK) +/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_FILTER) + if (level == GC_QUEUE_FILTER) delslasttick = 0 gcedlasttick = 0 var/cut_off_time = world.time - collection_timeout[level] //ignore entries newer then this @@ -149,41 +130,53 @@ SUBSYSTEM_DEF(garbage) lastlevel = level - for (var/refID in queue) - if (!refID) +// 1 from the hard reference in the queue, and 1 from `D` in the code below +#define REFS_WE_EXPECT 2 + + //We do this rather then for(var/refID in queue) because that sort of for loop copies the whole list. + //Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun. + for (var/i in 1 to length(queue)) + var/list/L = queue[i] + if (length(L) < GC_QUEUE_ITEM_INDEX_COUNT) count++ if (MC_TICK_CHECK) - break + return continue - var/GCd_at_time = queue[refID] - if(GCd_at_time > cut_off_time) + var/queued_at_time = L[GC_QUEUE_ITEM_QUEUE_TIME] + if(queued_at_time > cut_off_time) break // Everything else is newer, skip them count++ - var/datum/D - D = locate(refID) + var/datum/D = L[GC_QUEUE_ITEM_REF] - if (!D || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake + // If that's all we've got, send er off + if (refcount(D) == REFS_WE_EXPECT) ++gcedlasttick ++totalgcs pass_counts[level]++ - #ifdef TESTING - reference_find_on_fail -= refID //It's deleted we don't care anymore. + #ifdef REFTRACKING_ENABLED + reference_find_on_fail -= ref(D) //It's deleted we don't care anymore. #endif if (MC_TICK_CHECK) - break + return continue // Something's still referring to the qdel'd object. + fail_counts[level]++ + switch (level) if (GC_QUEUE_CHECK) - #ifdef TESTING + #ifdef REFTRACKING_ENABLED + // Decides how many refs to look for (potentially) + // Based off the remaining and the ones we can account for + var/remaining_refs = refcount(D) - REFS_WE_EXPECT + var/refID = ref(D) if(reference_find_on_fail[refID]) - D.find_references() + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references), remaining_refs) #ifdef GC_FAILURE_HARD_LOOKUP else - D.find_references() + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references), remaining_refs) #endif reference_find_on_fail -= refID #endif @@ -192,46 +185,36 @@ SUBSYSTEM_DEF(garbage) if(!I.failures) to_world_log("GC: -- \ref[D] | [type] was unable to be GC'd --") I.failures++ - fail_counts[level]++ if (GC_QUEUE_HARDDELETE) if(harddel_halt) continue - fail_counts[level]++ HardDelete(D) if (MC_TICK_CHECK) - break + return continue Queue(D, level+1) if (MC_TICK_CHECK) - break + return if (count) queue.Cut(1,count+1) count = 0 -/datum/controller/subsystem/garbage/proc/PreQueue(datum/D) - if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - queues[GC_QUEUE_PREQUEUE] += D - D.gc_destroyed = GC_QUEUED_FOR_QUEUING - -/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK) +/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_FILTER) if (isnull(D)) return - if (D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL) - level = GC_QUEUE_HARDDELETE if (level > GC_QUEUE_COUNT) HardDelete(D) return - var/gctime = world.time - var/refid = "\ref[D]" + var/queue_time = world.time - D.gc_destroyed = gctime + if(D.gc_destroyed <= 0) // hasn't been queued yet, or is queued for harddel/actively being qdeleted + D.gc_destroyed = queue_time var/list/queue = queues[level] - if (queue[refid]) - queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list. - - queue[refid] = gctime + // not += for byond reasons + // we include D.gc_destroyed to skip things under the cutoff + queue[++queue.len] = list(queue_time, D, D.gc_destroyed) //this is mainly to separate things profile wise. /datum/controller/subsystem/garbage/proc/HardDelete(datum/D) @@ -265,11 +248,6 @@ SUBSYSTEM_DEF(garbage) message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).") postpone(time) -/datum/controller/subsystem/garbage/proc/HardQueue(datum/D) - if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) - queues[GC_QUEUE_PREQUEUE] += D - D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL - /datum/controller/subsystem/garbage/Recover() if (istype(SSgarbage.queues)) for (var/i in 1 to SSgarbage.queues.len) @@ -282,54 +260,68 @@ SUBSYSTEM_DEF(garbage) /datum/qdel_item var/name = "" - var/qdels = 0 //Total number of times it's passed thru qdel. - var/destroy_time = 0 //Total amount of milliseconds spent processing this type's Destroy() - var/failures = 0 //Times it was queued for soft deletion but failed to soft delete. - var/hard_deletes = 0 //Different from failures because it also includes QDEL_HINT_HARDDEL deletions - var/hard_delete_time = 0//Total amount of milliseconds spent hard deleting this type. - var/no_respect_force = 0//Number of times it's not respected force=TRUE - var/no_hint = 0 //Number of times it's not even bother to give a qdel hint - var/slept_destroy = 0 //Number of times it's slept in its destroy + var/qdels = 0 //! Total number of times its passed thru qdel. + var/destroy_time = 0 //! Total amount of milliseconds spent processing this type's Destroy(). + var/failures = 0 //! Times it was queued for soft deletion but failed to soft delete. + var/hard_deletes = 0 //! Different from failures because it also includes QDEL_HINT_HARDDEL deletions. + var/hard_delete_time = 0//! Total amount of milliseconds spent hard deleting this type. + var/no_respect_force = 0//! Number of times its not respected force=TRUE. + var/no_hint = 0 //! Number of times it hasn't bothered to give a qdel hint. + var/slept_destroy = 0 //! Number of times slept in its destroy. + var/early_destroy = 0 //! Number of times it was destroyed before Initialize(). /datum/qdel_item/New(mytype) name = "[mytype]" -#ifdef TESTING +#ifdef REFTRACKING_ENABLED /proc/qdel_and_find_ref_if_fail(datum/D, force = FALSE) SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE qdel(D, force) #endif -// Should be treated as a replacement for the 'del' keyword. -// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. -/proc/qdel(datum/D, force=FALSE, ...) - if(!D) +/// Should be treated as a replacement for the 'del' keyword. +/// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. +/// Non-datums passed to this will be hard-deleted. +/proc/qdel(datum/D, force=FALSE) + if(isnull(D)) return if(!istype(D)) - crash_with("qdel() can only handle /datum (sub)types, was passed: [log_info_line(D)]") del(D) return var/datum/qdel_item/I = SSgarbage.items[D.type] - if (!I) + if (isnull(I)) I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type) - I.qdels++ + I.qdels++ if(isnull(D.gc_destroyed)) D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED var/start_time = world.time var/start_tick = world.tick_usage - var/hint = D.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up. + var/hint + + // Let our friend know they're about to get fucked up. + if (isloc(D) && !(D:atom_flags & ATOM_FLAG_INITIALIZED)) + hint = D:EarlyDestroy(force) + I.early_destroy += 1 + else + hint = D.Destroy(force) + if(world.time != start_time) I.slept_destroy++ else I.destroy_time += TICK_USAGE_TO_MS(start_tick) - if(!D) + + if(isnull(D)) return + + if(D.is_processing) + get_stack_trace("[D] ([D.type]) was qdeleted while still processing on [D.is_processing]!") + switch(hint) if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. GC_CHECK_AM_NULLSPACE(D, "QDEL_HINT_QUEUE") - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) if (QDEL_HINT_IWILLGC) D.gc_destroyed = world.time return @@ -339,9 +331,9 @@ SUBSYSTEM_DEF(garbage) return // Returning LETMELIVE after being told to force destroy // indicates the objects Destroy() does not respect force - #ifdef TESTING + #ifdef REFTRACKING_ENABLED if(!I.no_respect_force) - crash_with("WARNING: [D.type] has been force deleted, but is \ + PRINT_STACK_TRACE("WARNING: [D.type] has been force deleted, but is \ returning an immortal QDEL_HINT, indicating it does \ not respect the force flag for qdel(). It has been \ placed in the queue, further instances of this type \ @@ -349,43 +341,50 @@ SUBSYSTEM_DEF(garbage) #endif I.no_respect_force++ - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate() GC_CHECK_AM_NULLSPACE(D, "QDEL_HINT_HARDDEL") - SSgarbage.HardQueue(D) + SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. SSgarbage.HardDelete(D) - if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion. - SSgarbage.PreQueue(D) - #ifdef TESTING - D.find_references() + if (QDEL_HINT_FINDREFERENCE)//qdel will, if REFTRACKING_ENABLED is enabled, display all references to this object, then queue the object for deletion. + SSgarbage.Queue(D) + #ifdef REFTRACKING_ENABLED + var/remaining_refs = refcount(D) - REFS_WE_EXPECT + D.find_references(remaining_refs) #endif if (QDEL_HINT_IFFAIL_FINDREFERENCE) - SSgarbage.PreQueue(D) - #ifdef TESTING + SSgarbage.Queue(D) + #ifdef REFTRACKING_ENABLED SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE #endif else - #ifdef TESTING + #ifdef REFTRACKING_ENABLED if(!I.no_hint) - crash_with("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") + PRINT_STACK_TRACE("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") #endif I.no_hint++ - SSgarbage.PreQueue(D) + SSgarbage.Queue(D) else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") -#ifdef TESTING +#ifdef REFTRACKING_ENABLED /datum/verb/find_refs() set category = "Debug" set name = "Find References" set src in world - find_references(FALSE) + user_find_references() -/datum/proc/find_references(skip_alert) +/datum/proc/user_find_references() + if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "No", "Yes") == "No") + return + find_references() + +/datum/proc/find_references(references_to_clear = INFINITY) running_find_references = type + src.references_to_clear = references_to_clear if(usr && usr.client) if(usr.client.running_find_references) testing("CANCELLED search for references to a [usr.client.running_find_references].") @@ -396,11 +395,6 @@ SUBSYSTEM_DEF(garbage) SSgarbage.next_fire = world.time + world.tick_lag return - if(!skip_alert) - if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No") - running_find_references = null - return - //this keeps the garbage collector from failing to collect objects being searched for in here SSgarbage.can_fire = 0 @@ -410,15 +404,37 @@ SUBSYSTEM_DEF(garbage) testing("Beginning search for references to a [type].") last_find_references = world.time - DoSearchVar(GLOB) //globals - for(var/datum/thing in world) //atoms (don't believe its lies) - DoSearchVar(thing, "World -> [thing]") + //Yes we do actually need to do this. The searcher refuses to read weird lists + //And global.vars is a really weird list + var/list/normal_globals = list() + for(var/global_var in global.vars) + normal_globals[global_var] = global.vars[global_var] + DoSearchVar(normal_globals, "(global) -> ") //globals + testing("Finished searching globals") + if(src.references_to_clear == 0) // Found all expected references! + return - for (var/datum/thing) //datums - DoSearchVar(thing, "World -> [thing]") + for(var/atom/atom_thing) //atoms + DoSearchVar(atom_thing, "World -> [atom_thing]") + if(src.references_to_clear == 0) // Found all expected references! + return + testing("Finished searching atoms") - for (var/client/thing) //clients - DoSearchVar(thing, "World -> [thing]") + for (var/datum/datum_thing) //datums + DoSearchVar(datum_thing, "World -> [datum_thing]") + if(src.references_to_clear == 0) // Found all expected references! + return + testing("Finished searching datums") + +#ifndef FIND_REF_SKIP_CLIENTS + // DO NOT RUN THIS ON A LIVE SERVER + // IT WILL CRASH!!! + for (var/client/client_thing) //clients + DoSearchVar(client_thing, "World -> [client_thing]") + if(src.references_to_clear == 0) // Found all expected references! + return + testing("Finished searching clients") +#endif testing("Completed search for references to a [type].") if(usr && usr.client) @@ -436,7 +452,7 @@ SUBSYSTEM_DEF(garbage) qdel(src, TRUE) //Force. if(!running_find_references) - find_references(TRUE) + find_references() /datum/verb/qdel_then_if_fail_find_references() set category = "Debug" @@ -452,45 +468,87 @@ SUBSYSTEM_DEF(garbage) #define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) ) #define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST) -/datum/proc/DoSearchVar(X, Xname, recursive_limit = 64) +/datum/proc/DoSearchVar(X, container_name, recursive_limit = 128) if(usr && usr.client && !usr.client.running_find_references) return if (!recursive_limit) + testing("Recursion limit reached. [container_name]") return + if(references_to_clear == 0) + return + + #ifndef FIND_REF_NO_CHECK_TICK + CHECK_TICK + #endif if(istype(X, /datum)) - var/datum/D = X - if(D.last_find_references == last_find_references) + var/datum/datum_container = X + if(datum_container.last_find_references == last_find_references) return - D.last_find_references = last_find_references - var/list/L = D.vars - - for(var/varname in L) - if (varname == "vars") + datum_container.last_find_references = last_find_references + var/list/vars_list = datum_container.vars + + var/is_atom = FALSE + var/is_area = FALSE + if(isatom(datum_container)) + is_atom = TRUE + if(isarea(datum_container)) + is_area = TRUE + for(var/varname in vars_list) + #ifndef FIND_REF_NO_CHECK_TICK + CHECK_TICK + #endif + //Fun fact, vis_locs don't count for references + if(varname == "vars" || (is_atom && (varname == "vis_locs" || varname == "overlays" || varname == "underlays" || varname == "filters" || varname == "verbs" || (is_area && varname == "contents")))) continue - var/variable = L[varname] + var/variable = vars_list[varname] if(variable == src) - testing("Found [src.type] \ref[src] in [D.type]'s [varname] var. [Xname]") + testing("Found [src.type] \ref[src] in [datum_container.type]'s [varname] var. [container_name]") + references_to_clear -= 1 else if(islist(variable)) - DoSearchVar(variable, "[Xname] -> list", recursive_limit-1) + DoSearchVar(variable, "[container_name] -> [varname] (list)", recursive_limit-1) else if(islist(X)) var/normal = IS_NORMAL_LIST(X) for(var/I in X) + #ifndef FIND_REF_NO_CHECK_TICK + CHECK_TICK + #endif if (I == src) - testing("Found [src.type] \ref[src] in list [Xname].") + testing("Found [src.type] \ref[src] in list [container_name].") + + // This is dumb as hell I'm sorry + // I don't want the garbage subsystem to count as a ref for the purposes of this number + // If we find all other refs before it I want to early exit, and if we don't I want to keep searching past it + var/ignore_ref = FALSE + var/list/queues = SSgarbage.queues + for(var/list/queue in queues) + if(X in queue) + ignore_ref = TRUE + break + if(ignore_ref) + testing("[container_name] does not count as a ref for our count") + else + references_to_clear -= 1 + if(references_to_clear == 0) + testing("All references to [type] \ref[src] found, exiting.") + return - else if (I && !isnum(I) && normal && X[I] == src) - testing("Found [src.type] \ref[src] in list [Xname]\[[I]\]") + else if (I && !isnum(I) && normal) + if(X[I] == src) + testing("Found [src.type] \ref[src] in list [container_name]\[[I]\]") + references_to_clear -= 1 + if(references_to_clear == 0) + testing("All references to [type] \ref[src] found, exiting.") + return + else if(islist(X[I])) + DoSearchVar(X[I], "[container_name]\[[I]\]", recursive_limit-1) else if (islist(I)) - DoSearchVar(I, "[Xname] -> list", recursive_limit-1) - -#ifndef FIND_REF_NO_CHECK_TICK - CHECK_TICK -#endif + var/list/Xlist = X + DoSearchVar(I, "[container_name]\[[Xlist.Find(I)]\] -> list", recursive_limit-1) #endif diff --git a/code/controllers/subsystems/ghost_images.dm b/code/controllers/subsystems/ghost_images.dm index 74440ed2ec15..75892b88b390 100644 --- a/code/controllers/subsystems/ghost_images.dm +++ b/code/controllers/subsystems/ghost_images.dm @@ -12,7 +12,7 @@ SUBSYSTEM_DEF(ghost_images) /datum/controller/subsystem/ghost_images/fire(resumed = 0) if(!resumed && queue_all) - queue = GLOB.ghost_mob_list.Copy() + queue = global.ghost_mob_list.Copy() queue_all = FALSE var/list/curr = queue diff --git a/code/controllers/subsystems/goals.dm b/code/controllers/subsystems/goals.dm index 24b72c01f79f..3d57840d6d26 100644 --- a/code/controllers/subsystems/goals.dm +++ b/code/controllers/subsystems/goals.dm @@ -1,7 +1,7 @@ SUBSYSTEM_DEF(goals) name = "Goals" init_order = SS_INIT_GOALS - flags = SS_NO_FIRE + wait = 1 SECOND var/list/global_personal_goals = list( /datum/goal/achievement/specific_object/food, /datum/goal/achievement/specific_object/drink, @@ -16,19 +16,43 @@ SUBSYSTEM_DEF(goals) /datum/goal/clean, /datum/goal/money ) - var/list/ambitions = list() -/datum/controller/subsystem/goals/proc/update_department_goal(var/department_ref, var/goal_type, var/progress) - var/datum/department/dept = SSdepartments.departments[department_ref] + var/list/ambitions = list() + var/list/pending_goals = list() + var/active_goals_copied_yet = FALSE + var/list/goals_to_process = list() + var/goal_index = 1 + +/datum/controller/subsystem/goals/fire(resumed) + if(!resumed) + active_goals_copied_yet = FALSE + goal_index = 1 + if(!active_goals_copied_yet) + active_goals_copied_yet = TRUE + goals_to_process = pending_goals.Copy() + while(goal_index <= goals_to_process.len) + var/datum/goal/goal = goals_to_process[goal_index++] + if(goal.try_initialize()) + pending_goals -= goal + if (MC_TICK_CHECK) + return + if(!length(pending_goals)) + disable() + +/datum/controller/subsystem/goals/proc/update_department_goal(var/department_type, var/goal_type, var/progress) + var/decl/department/dept = SSjobs.get_department_by_type(department_type) if(dept) dept.update_progress(goal_type, progress) /datum/controller/subsystem/goals/proc/get_roundend_summary() + . = list() - for(var/thing in SSdepartments.departments) - var/datum/department/dept = SSdepartments.departments[thing] - if (LAZYLEN(SSjobs.titles_by_department(dept))) - . += "[dept.title] had the following shift goals:" + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dtype in all_departments) + var/decl/department/dept = all_departments[dtype] + if(LAZYLEN(dept.goals)) + . += "[dept.name] had the following [dept.noun] goals:" . += dept.summarize_goals(show_success = TRUE) + if(LAZYLEN(.)) . = "
[jointext(., "
")]" else diff --git a/code/controllers/subsystems/graphs.dm b/code/controllers/subsystems/graphs.dm index 68a2b47ac4d1..07c7000e68c4 100644 --- a/code/controllers/subsystems/graphs.dm +++ b/code/controllers/subsystems/graphs.dm @@ -1,5 +1,6 @@ SUBSYSTEM_DEF(graphs_update) name = "Graphs (Update)" + init_order = SS_INIT_GRAPH priority = SS_PRIORITY_GRAPH flags = SS_KEEP_TIMING runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME diff --git a/code/controllers/subsystems/holomap.dm b/code/controllers/subsystems/holomap.dm new file mode 100644 index 000000000000..0d2cc7371e49 --- /dev/null +++ b/code/controllers/subsystems/holomap.dm @@ -0,0 +1,108 @@ +// Minimap generation system adapted from vorestation, adapted from /vg/. +// Seems to be much simpler/saner than /vg/'s implementation. + +//The structure holding a given map +/datum/holomapdata + var/icon/holomap_base + var/list/icon/holomap_areas = list() + var/icon/holomap_small + +SUBSYSTEM_DEF(minimap) + name = "Holomap" + flags = SS_NO_FIRE + init_order = SS_INIT_HOLOMAP + + var/list/datum/holomapdata/holomaps = list() + var/list/station_holomaps = list() + +/datum/controller/subsystem/minimap/Initialize() + holomaps.len = world.maxz + for (var/z = 1 to world.maxz) + generateHolomap(z) + + //Update machinery if it has not been + for(var/obj/machinery/holomap/M in station_holomaps) + M.update_map_data() + + ..() + +/datum/controller/subsystem/minimap/proc/generateHolomap(zlevel) + var/datum/holomapdata/data = new() + data.holomap_base = generateBaseHolomap(zlevel) + data.holomap_areas = generateHolomapAreaOverlays(zlevel) + + var/icon/combinedareas = icon(HOLOMAP_ICON, "blank") + + for(var/area/A in data.holomap_areas) + var/icon/single = data.holomap_areas[A] + if(A.holomap_color) + single.Blend(A.holomap_color, ICON_MULTIPLY) + combinedareas.Blend(single, ICON_OVERLAY) + + // Generate the "small" map + var/icon/small_map = icon(HOLOMAP_ICON, "blank") + + //Make it green. + var/icon/map_base = icon(data.holomap_base) + small_map.Blend(map_base, ICON_OVERLAY, HOLOMAP_PIXEL_OFFSET_X(zlevel), HOLOMAP_PIXEL_OFFSET_Y(zlevel)) + small_map.Blend(COLOR_HOLOMAP_HOLOFIER, ICON_MULTIPLY) + small_map.Blend(combinedareas, ICON_OVERLAY, HOLOMAP_PIXEL_OFFSET_X(zlevel), HOLOMAP_PIXEL_OFFSET_Y(zlevel)) + small_map.Scale(WORLD_ICON_SIZE, WORLD_ICON_SIZE) + var/const/border_size = 6 // the width of the border (non-map) section of the icon + small_map.Shift(NORTHEAST, border_size) + + // And rotate it in every direction of course! + var/icon/actual_small_map = icon(small_map) + actual_small_map.Insert(new_icon = small_map, dir = SOUTH) + actual_small_map.Insert(new_icon = turn(small_map, 90), dir = WEST) + actual_small_map.Insert(new_icon = turn(small_map, 180), dir = NORTH) + actual_small_map.Insert(new_icon = turn(small_map, 270), dir = EAST) + data.holomap_small = actual_small_map + + holomaps[zlevel] = data + +// Generates the "base" holomap for one z-level, showing only the physical structure of walls and paths. +/datum/controller/subsystem/minimap/proc/generateBaseHolomap(zlevel = 1) + // Save these values now to avoid a bazillion array lookups + var/offset_x = HOLOMAP_PIXEL_OFFSET_X(zlevel) + var/offset_y = HOLOMAP_PIXEL_OFFSET_Y(zlevel) + + // Sanity checks - Better to generate a helpful error message now than have DrawBox() runtime + var/icon/canvas = icon(HOLOMAP_ICON, "blank") + if(world.maxx + offset_x > canvas.Width()) + CRASH("Minimap for z=[zlevel] : world.maxx ([world.maxx]) + holomap_offset_x ([offset_x]) must be <= [canvas.Width()]") + if(world.maxy + offset_y > canvas.Height()) + CRASH("Minimap for z=[zlevel] : world.maxy ([world.maxy]) + holomap_offset_y ([offset_y]) must be <= [canvas.Height()]") + + var/datum/level_data/level = SSmapping.levels_by_z[zlevel] + for(var/turf/tile as anything in block(level.level_inner_min_x, level.level_inner_min_y, zlevel, level.level_inner_max_x, level.level_inner_max_y, zlevel)) + var/area/A = get_area(tile) + if ((A && (A.area_flags & AREA_FLAG_HIDE_FROM_HOLOMAP)) || (tile.turf_flags & TURF_IS_HOLOMAP_ROCK)) + continue + if((tile.turf_flags & TURF_IS_HOLOMAP_OBSTACLE) || (locate(/obj/structure/grille) in tile)) + canvas.DrawBox(COLOR_HOLOMAP_OBSTACLE, tile.x + offset_x, tile.y + offset_y) + else if((tile.turf_flags & TURF_IS_HOLOMAP_PATH) || tile.get_supporting_platform()) + canvas.DrawBox(COLOR_HOLOMAP_PATH, tile.x + offset_x, tile.y + offset_y) + CHECK_TICK + return canvas + +// Generate overlays based on areas +/datum/controller/subsystem/minimap/proc/generateHolomapAreaOverlays(zlevel) + var/list/icon/areas = list() + + var/offset_x = HOLOMAP_PIXEL_OFFSET_X(zlevel) + var/offset_y = HOLOMAP_PIXEL_OFFSET_Y(zlevel) + + var/datum/level_data/level = SSmapping.levels_by_z[zlevel] + for(var/x = level.level_inner_min_x to level.level_inner_max_x) + for(var/y = level.level_inner_min_y to level.level_inner_max_y) + var/turf/tile = locate(x, y, zlevel) + if(tile && tile.loc) + var/area/areaToPaint = tile.loc + if((areaToPaint.area_flags & AREA_FLAG_HIDE_FROM_HOLOMAP) || !areaToPaint.holomap_color) + continue + if(!areas[areaToPaint]) + areas[areaToPaint] = icon(HOLOMAP_ICON, "blank") + areas[areaToPaint].DrawBox(HOLOMAP_AREACOLOR_BASE, x + offset_x, y + offset_y) //We draw white because we want a generic version to use later. However if there is no colour we ignore it + CHECK_TICK + return areas \ No newline at end of file diff --git a/code/controllers/subsystems/icon_updates.dm b/code/controllers/subsystems/icon_updates.dm new file mode 100644 index 000000000000..de98f51b0343 --- /dev/null +++ b/code/controllers/subsystems/icon_updates.dm @@ -0,0 +1,60 @@ +SUBSYSTEM_DEF(icon_update) + name = "Icon Updates" + wait = 1 + priority = SS_PRIORITY_ICON_UPDATE + init_order = SS_INIT_ICON_UPDATE + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT // If you make it not fire in lobby, you also have to remove atoms from queue in Destroy. + + // Linked lists, queue_refs[x] should have null or args stored in queue_args[x] + var/list/queue_refs = list() // Atoms + +/datum/controller/subsystem/icon_update/stat_entry() + ..("Queue: [queue_refs.len]") + +/datum/controller/subsystem/icon_update/Initialize() + fire(FALSE, TRUE) + +/datum/controller/subsystem/icon_update/fire(resumed = FALSE, no_mc_tick = FALSE) + var/list/cached_refs = queue_refs // local variables are quicker to access than instance variables. it's still the same list though + if(!cached_refs.len) + suspend() + return + + var/static/count = 1 // proc-level static var, as with SSgarbage, in case a runtime makes this proc end early + while (count <= length(cached_refs)) // if we kept a copy of the queue to avoid mutating it while we run, this could possibly be made a lot faster by just using a for loop? + if(Master.map_loading) // we started loading a map mid-run, so stop and clean up + break + // Pops the atom from the queue + var/atom/A = cached_refs[count++] // count is used to cut our list later and save time + if(QDELETED(A)) + continue + A.icon_update_queued = FALSE + A.update_icon() + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + break + cached_refs.Cut(1, count) + count = 1 + +/atom + var/icon_update_queued = FALSE + +/atom/proc/queue_icon_update() + // Skips if this is already queued + if(icon_update_queued) + return + icon_update_queued = TRUE + // This is faster than using Add() because BYOND. + SSicon_update.queue_refs[++SSicon_update.queue_refs.len] = src + + // SSicon_update sleeps when it runs out of things in its + // queue, so wake it up. + if(!Master.map_loading) // Don't wake early if we're loading a map, it'll get woken up when the map loads. + SSicon_update.wake() + +/datum/controller/subsystem/icon_update/StartLoadingMap() + suspend() + +/datum/controller/subsystem/icon_update/StopLoadingMap() + wake() diff --git a/code/controllers/subsystems/inactivity.dm b/code/controllers/subsystems/inactivity.dm index bcdde36c0bbb..8ba84003468f 100644 --- a/code/controllers/subsystems/inactivity.dm +++ b/code/controllers/subsystems/inactivity.dm @@ -7,18 +7,19 @@ SUBSYSTEM_DEF(inactivity) var/number_kicked = 0 /datum/controller/subsystem/inactivity/fire(resumed = FALSE) - if (!config.kick_inactive) + var/kick_inactive_time = get_config_value(/decl/config/num/kick_inactive) MINUTES + if (!kick_inactive_time) suspend() return if (!resumed) - client_list = GLOB.clients.Copy() + client_list = global.clients.Copy() while(client_list.len) var/client/C = client_list[client_list.len] client_list.len-- - if(!C.holder && C.is_afk(config.kick_inactive MINUTES) && !isobserver(C.mob)) + if(!C.holder && C.is_afk(kick_inactive_time) && !isobserver(C.mob)) log_access("AFK: [key_name(C)]") - to_chat(C, "You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.") + to_chat(C, SPAN_WARNING("You have been inactive for more than [kick_inactive_time] minute\s and have been disconnected.")) qdel(C) number_kicked++ if (MC_TICK_CHECK) diff --git a/code/controllers/subsystems/initialization/character_info.dm b/code/controllers/subsystems/initialization/character_info.dm new file mode 100644 index 000000000000..a874ddcb4f93 --- /dev/null +++ b/code/controllers/subsystems/initialization/character_info.dm @@ -0,0 +1,190 @@ +// Holder subsystem for character comment records. +SUBSYSTEM_DEF(character_info) + name = "Character Information" + flags = SS_NEEDS_SHUTDOWN + init_order = SS_INIT_EARLY + wait = 1 SECOND + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT // We want to save changes made during pre-round lobby. + var/static/comments_source = "data/character_info/" + var/list/_comment_holders_by_id = list() + var/list/_ids_to_save = list() + +/datum/controller/subsystem/character_info/Initialize() + . = ..() + if(!get_config_value(/decl/config/toggle/allow_character_comments)) + report_progress("Skipping mass load of character records as character comments are disabled.") + return + if(!fexists(comments_source)) + report_progress("Character information directory [comments_source] does not exist, no character comments will be saved or loaded.") + return + var/loaded_json_manifest = load_text_from_directory(comments_source, ".json") + if(!islist(loaded_json_manifest) || !length(loaded_json_manifest["files"])) + return + var/list/loaded_files = loaded_json_manifest["files"] + var/loaded_comments = 0 + for(var/loaded_file in loaded_files) + var/datum/character_information/comments = load_record(loaded_files[loaded_file]) + if(!istext(comments.record_id)) + PRINT_STACK_TRACE("Deserialized character information had invalid id '[comments.record_id || "NULL"]'!") + continue + + // Remove any pre-created records (early joiners, etc.) + if(_comment_holders_by_id[comments.record_id]) + var/old_record = _comment_holders_by_id[comments.record_id] + _comment_holders_by_id -= comments.record_id + qdel(old_record) + + comments.file_location = loaded_file + _comment_holders_by_id[comments.record_id] = comments + loaded_comments += length(comments.comments) + report_progress("Loaded [loaded_comments] record\s for [length(_comment_holders_by_id)] character\s.") + +/datum/controller/subsystem/character_info/Shutdown() + . = ..() + for(var/id in _comment_holders_by_id) + save_record(id) + +/datum/controller/subsystem/character_info/stat_entry(msg) + ..("R:[_comment_holders_by_id.len]Q:[_ids_to_save.len][msg]") + +/datum/controller/subsystem/character_info/fire(resumed = FALSE, no_mc_tick = FALSE) + while(_ids_to_save.len) + var/id = _ids_to_save[1] + _ids_to_save -= id + save_record(id) + if(TICK_CHECK) + return + +/datum/controller/subsystem/character_info/proc/queue_to_save(var/record_id) + if(istext(record_id) && length(record_id)) + _ids_to_save |= record_id + +/datum/controller/subsystem/character_info/proc/save_record(var/record_id) + if(!istext(record_id) || !record_id) + return + var/datum/character_information/comments = get_record(record_id, TRUE) + if(!istype(comments)) + return + if(!comments.file_location) + comments.file_location = "[comments_source][ckey(comments.record_id)].json" + try + if(fexists(comments.file_location)) + fdel(comments.file_location) + to_file(file(comments.file_location), comments.serialize_to_json()) + catch(var/exception/E) + PRINT_STACK_TRACE("Exception when writing out character information file to [comments?.file_location || "NULL"]: [E]") + +/datum/controller/subsystem/character_info/proc/load_record(var/load_from) + var/datum/character_information/comments = new(cached_json_decode(load_from)) + _comment_holders_by_id[comments.record_id] = comments + return comments + +/datum/controller/subsystem/character_info/proc/reload_record(var/record_id) + var/datum/character_information/comments = get_record(record_id, TRUE) + if(comments && comments.file_location && fexists(comments.file_location)) + var/reload_from = comments.file_location + _comment_holders_by_id -= comments.record_id + qdel(comments) + try + . = load_record(safe_file2text(reload_from)) + catch(var/exception/E) + PRINT_STACK_TRACE("Exception when reloading record from [reload_from]: [E]") + +/datum/controller/subsystem/character_info/proc/clear_record(var/record_id) + var/datum/character_information/comments = get_record(record_id, TRUE) + if(comments) + comments.comments.Cut() + comments.ic_info = null + comments.ooc_info = null + +/datum/controller/subsystem/character_info/proc/get_record_id(var/record_id) + return trim(lowertext(record_id)) + +/datum/controller/subsystem/character_info/proc/get_record(var/record_id, var/override_prefs, var/discard_archived_record) + record_id = get_record_id(record_id) + if(!record_id) + CRASH("Attempt to retrieve null character information ID.") + var/datum/character_information/comments = _comment_holders_by_id[record_id] + if(istype(comments) && (override_prefs || (get_config_value(/decl/config/toggle/allow_character_comments) && comments.allow_comments) || comments.show_info_on_examine)) + return comments + +/datum/controller/subsystem/character_info/proc/get_or_create_record(var/record_id, var/override_prefs) + . = get_record(record_id, override_prefs) + if(!. && initialized) + // Let's assume they'll populate it if so desired. + var/datum/character_information/comments = new + comments.record_id = get_record_id(record_id) + _comment_holders_by_id[comments.record_id] = comments + . = comments + +/datum/controller/subsystem/character_info/proc/search_records(var/search_for) + search_for = ckey(lowertext(trim(search_for))) + for(var/id in _comment_holders_by_id) + var/datum/character_information/comments = _comment_holders_by_id[id] + if(istype(comments)) + for(var/checkstring in list(comments.name, comments.ckey, comments.record_id)) + if(findtext(ckey(lowertext(trim(checkstring))), search_for) > 0) + LAZYADD(., comments) + break + +/datum/controller/subsystem/character_info/Topic(href, href_list) + . = ..() + if(!. && href_list["download_manifest"] && usr && check_rights(R_ADMIN)) + try + var/dump_file_name = "[comments_source]dump_character_manifest.html" + if(fexists(dump_file_name)) + fdel(dump_file_name) + text2file(JOINTEXT(SScharacter_info.get_character_manifest_html(apply_striping = FALSE)), dump_file_name) + if(fexists(dump_file_name)) + ftp_to(usr, dump_file_name, "dump_manifest.html") + return TOPIC_HANDLED + catch(var/exception/E) + log_debug("Exception when dumping character relationship manifest: [E]") + +#define COMMENT_CANDYSTRIPE_ONE "#343434" +#define COMMENT_CANDYSTRIPE_TWO "#454545" +/datum/controller/subsystem/character_info/proc/get_character_manifest_html(var/apply_striping = TRUE) + var/list/records_with_an_entry = list() + for(var/id in _comment_holders_by_id) + var/datum/character_information/comments = _comment_holders_by_id[id] + for(var/datum/character_comment/comment in comments.comments) + if(comment.is_stale()) + continue + records_with_an_entry |= comment.author_id + sortTim(records_with_an_entry, /proc/cmp_text_asc) + . = list("") + if(apply_striping) + . += "" + else + . += "" + . += "" + for(var/column_id in records_with_an_entry) + var/datum/character_information/column = _comment_holders_by_id[column_id] + . += "" + . += "" + var/ticker = FALSE + for(var/row_id in records_with_an_entry) + if(apply_striping) + . += "" + ticker = !ticker + else + . += "" + var/datum/character_information/row = _comment_holders_by_id[row_id] + . += "" + for(var/column_id in records_with_an_entry) + var/datum/character_information/column = _comment_holders_by_id[column_id] + var/found_comment = FALSE + for(var/datum/character_comment/comment in column.comments) + if(comment.author_id == row_id && !comment.is_stale()) + found_comment = TRUE + var/mood_title = comment.main_mood.name + if(comment.border_mood) + mood_title = "[mood_title] ([comment.border_mood.name])" + . += "" + break + if(!found_comment) + . += "" + . += "" + . += "
Character Relationship Matrix
[column.char_name]
[column.ckey]
[row.char_name]
[row.ckey]
[comment.body]
" +#undef COMMENT_CANDYSTRIPE_ONE +#undef COMMENT_CANDYSTRIPE_TWO \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/character_setup.dm b/code/controllers/subsystems/initialization/character_setup.dm index ae477ae62fb9..eb59bc05da9b 100644 --- a/code/controllers/subsystems/initialization/character_setup.dm +++ b/code/controllers/subsystems/initialization/character_setup.dm @@ -6,23 +6,32 @@ SUBSYSTEM_DEF(character_setup) wait = 1 SECOND runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - var/list/prefs_awaiting_setup = list() var/list/preferences_datums = list() + var/list/chars_awaiting_load = list() var/list/newplayers_requiring_init = list() var/list/save_queue = list() /datum/controller/subsystem/character_setup/Initialize() - while(prefs_awaiting_setup.len) - var/datum/preferences/prefs = prefs_awaiting_setup[prefs_awaiting_setup.len] - prefs_awaiting_setup.len-- - prefs.setup() + while(chars_awaiting_load.len) + var/datum/preferences/prefs = chars_awaiting_load[chars_awaiting_load.len] + chars_awaiting_load.len-- + prefs.lateload_character() // separated to avoid Initialize() crashing + while(newplayers_requiring_init.len) var/mob/new_player/new_player = newplayers_requiring_init[newplayers_requiring_init.len] newplayers_requiring_init.len-- new_player.deferred_login() + . = ..() +/datum/controller/subsystem/character_setup/proc/queue_load_character(datum/preferences/prefs) + // Calling this after subsytem's initialization is pointless + // and the client's characters will never be loaded. + ASSERT(!initialized) + + chars_awaiting_load += prefs + /datum/controller/subsystem/character_setup/fire(resumed = FALSE) while(save_queue.len) var/datum/preferences/prefs = save_queue[save_queue.len] @@ -34,5 +43,5 @@ SUBSYSTEM_DEF(character_setup) if(MC_TICK_CHECK) return -/datum/controller/subsystem/character_setup/proc/queue_preferences_save(var/datum/preferences/prefs) +/datum/controller/subsystem/character_setup/proc/queue_preferences_save(datum/preferences/prefs) save_queue |= prefs \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/codex.dm b/code/controllers/subsystems/initialization/codex.dm index 0a590008ce79..208a53347ab3 100644 --- a/code/controllers/subsystems/initialization/codex.dm +++ b/code/controllers/subsystems/initialization/codex.dm @@ -2,46 +2,52 @@ SUBSYSTEM_DEF(codex) name = "Codex" flags = SS_NO_FIRE init_order = SS_INIT_MISC_CODEX + var/regex/linkRegex + var/regex/trailingLinebreakRegexStart + var/regex/trailingLinebreakRegexEnd - var/list/entries_by_path = list() - var/list/entries_by_string = list() - var/list/index_file = list() - var/list/search_cache = list() - var/list/categories = list() + var/list/datum/codex_entry/all_entries = list() + var/list/datum/codex_entry/entries_by_path = list() + var/list/datum/codex_entry/entries_by_string = list() + var/list/index_file = list() + var/list/search_cache = list() /datum/controller/subsystem/codex/Initialize() - // Codex link syntax is such: - // keyword when keyword is mentioned verbatim, + // Codex link syntax is such: + // keyword when keyword is mentioned verbatim, // whatever when shit gets tricky linkRegex = regex(@"<(span|l)(\s+codexlink='([^>]*)'|)>([^<]+)","g") + // used to remove trailing linebreaks when retrieving codex body. + // TODO: clean up codex page generation so this isn't necessary. + trailingLinebreakRegexStart = regex(@"^<\s*\/*\s*br\s*\/*\s*>", "igm") + trailingLinebreakRegexEnd = regex(@"<\s*\/*\s*br\s*\/*\s*>$", "igm") + // Create general hardcoded entries. - for(var/ctype in typesof(/datum/codex_entry)) + for(var/ctype in subtypesof(/datum/codex_entry)) var/datum/codex_entry/centry = ctype - if(initial(centry.display_name) || initial(centry.associated_paths) || initial(centry.associated_strings)) - centry = new centry() - for(var/associated_path in centry.associated_paths) - entries_by_path[associated_path] = centry - for(var/associated_string in centry.associated_strings) - add_entry_by_string(associated_string, centry) - if(centry.display_name) - add_entry_by_string(centry.display_name, centry) + if(TYPE_IS_ABSTRACT(centry) || !initial(centry.store_codex_entry) || initial(centry.skip_hardcoded_generation)) + continue + centry = new centry() // Create categorized entries. - for(var/ctype in subtypesof(/datum/codex_category)) - var/datum/codex_category/cat = new ctype - categories[ctype] = cat - cat.Initialize() + var/list/deferred_population = list() + var/list/categories = decls_repository.get_decls_of_subtype(/decl/codex_category) + for(var/ctype in categories) + var/decl/codex_category/cat = categories[ctype] + if(cat.defer_population) + deferred_population += cat + continue + cat.Populate() + + for(var/decl/codex_category/cat as anything in deferred_population) + cat.Populate() // Create the index file for later use. - for(var/thing in SScodex.entries_by_path) - var/datum/codex_entry/entry = SScodex.entries_by_path[thing] - index_file[entry.display_name] = entry - for(var/thing in SScodex.entries_by_string) - var/datum/codex_entry/entry = SScodex.entries_by_string[thing] - index_file[entry.display_name] = entry - index_file = sortAssoc(index_file) + for(var/datum/codex_entry/entry as anything in all_entries) + index_file[entry.name] = entry + index_file = sortTim(index_file, /proc/cmp_text_asc) . = ..() /datum/controller/subsystem/codex/proc/parse_links(string, viewer) @@ -49,47 +55,53 @@ SUBSYSTEM_DEF(codex) var/key = linkRegex.group[4] if(linkRegex.group[2]) key = linkRegex.group[3] - key = lowertext(trim(key)) + key = codex_sanitize(key) var/datum/codex_entry/linked_entry = get_entry_by_string(key) var/replacement = linkRegex.group[4] if(linked_entry) - replacement = "[replacement]" + replacement = "[replacement]" string = replacetextEx(string, linkRegex.match, replacement) return string /datum/controller/subsystem/codex/proc/get_codex_entry(var/entry) if(istype(entry, /atom)) var/atom/entity = entry - if(entity.get_specific_codex_entry()) - return entity.get_specific_codex_entry() + var/specific_codex_entry = entity.get_specific_codex_entry() + if(specific_codex_entry) + return specific_codex_entry return get_entry_by_string(entity.name) || entries_by_path[entity.type] - else if(entries_by_path[entry]) + if(ispath(entry)) return entries_by_path[entry] - else if(entries_by_string[lowertext(entry)]) - return entries_by_string[lowertext(entry)] - -/datum/controller/subsystem/codex/proc/add_entry_by_string(var/string, var/entry) - entries_by_string[lowertext(trim(string))] = entry + if(istext(entry)) + return entries_by_string[codex_sanitize(entry)] /datum/controller/subsystem/codex/proc/get_entry_by_string(var/string) - return entries_by_string[lowertext(trim(string))] + return entries_by_string[codex_sanitize(string)] /datum/controller/subsystem/codex/proc/present_codex_entry(var/mob/presenting_to, var/datum/codex_entry/entry) if(entry && istype(presenting_to) && presenting_to.client) var/datum/browser/popup = new(presenting_to, "codex\ref[entry]", "Codex", nheight=425) - popup.set_content(parse_links(entry.get_text(presenting_to), presenting_to)) + popup.set_content(parse_links(jointext(entry.get_codex_body(presenting_to), null), presenting_to)) popup.open() -/datum/controller/subsystem/codex/proc/get_guide(var/category) - var/datum/codex_category/cat = categories[category] - . = cat?.guide_html +/datum/controller/subsystem/codex/proc/get_manual_text(var/guide_id) + if(ispath(guide_id, /decl/codex_category)) + var/decl/codex_category/cat = GET_DECL(guide_id) + . = cat?.guide_html + else if(guide_id) + var/datum/codex_entry/entry + if(ispath(guide_id, /datum/codex_entry)) + entry = guide_id + guide_id = initial(entry.name) + entry = get_codex_entry(guide_id) + . = entry?.guide_html /datum/controller/subsystem/codex/proc/retrieve_entries_for_string(var/searching) if(!initialized) return list() - searching = sanitize(lowertext(trim(searching))) + searching = codex_sanitize(searching) if(!searching) return list() if(!search_cache[searching]) @@ -100,12 +112,11 @@ SUBSYSTEM_DEF(codex) results = list() for(var/entry_title in entries_by_string) var/datum/codex_entry/entry = entries_by_string[entry_title] - if(findtext(entry.display_name, searching) || \ - findtext(entry.lore_text, searching) || \ - findtext(entry.mechanics_text, searching) || \ - findtext(entry.antag_text, searching)) + if(entry.unsearchable) // This entry can only be opened directly from links, and does not show up in search results. + continue + if(findtext(entry.name, searching) || findtext(entry.lore_text, searching) || findtext(entry.mechanics_text, searching) || findtext(entry.antag_text, searching)) results |= entry - search_cache[searching] = dd_sortedObjectList(results) + search_cache[searching] = sortTim(results, /proc/cmp_name_asc) return search_cache[searching] /datum/controller/subsystem/codex/Topic(href, href_list) @@ -113,16 +124,16 @@ SUBSYSTEM_DEF(codex) if(!. && href_list["show_examined_info"] && href_list["show_to"]) var/mob/showing_mob = locate(href_list["show_to"]) if(!istype(showing_mob) || !showing_mob.can_use_codex()) - return + return var/atom/showing_atom = locate(href_list["show_examined_info"]) var/entry if(istype(showing_atom, /datum/codex_entry)) entry = showing_atom + else if(istype(showing_atom)) + entry = get_codex_entry(showing_atom.get_codex_value()) else - if(istype(showing_atom)) - entry = get_codex_entry(showing_atom.get_codex_value()) - else - entry = get_codex_entry(showing_atom) + entry = get_codex_entry(href_list["show_examined_info"]) + if(entry) present_codex_entry(showing_mob, entry) return TRUE diff --git a/code/controllers/subsystems/initialization/codex_dump.dm b/code/controllers/subsystems/initialization/codex_dump.dm new file mode 100644 index 000000000000..ee93934ea510 --- /dev/null +++ b/code/controllers/subsystems/initialization/codex_dump.dm @@ -0,0 +1,210 @@ +/datum/codex_entry/proc/get_dump_link_name() + return name + +/datum/codex_entry/codex/get_dump_link_name() + return "index" // This is the central page of the website. + +/decl/codex_page_converter + var/write_location = "codex/" + var/file_prefix + var/file_suffix = ".html" + var/style_loc = "common.css" + var/sidebar + var/static/list/illegal_filename_characters = list( + "\\", + "/", + ":", + "*", + "?", + "\"", + "<", + ">", + "|", + ".", + "\n", + "\[", + "]" + ) + +/decl/codex_page_converter/proc/handle_additional_dump() + var/full_style_loc = "[write_location][style_loc]" + if(fexists(full_style_loc)) + fdel(full_style_loc) + fcopy('html/browser/common.css', full_style_loc) + +/decl/codex_page_converter/proc/insert_header(var/title, var/body) + return "\n\n\n[get_config_value(/decl/config/text/server_name)] - [title]\n\n[body]" + +/decl/codex_page_converter/proc/insert_footer(var/title, var/body) + var/datum/codex_entry/entry = SScodex.get_entry_by_string(title) + if(length(entry?.categories)) + body = "[body]\n
\n

This page is part of the following categories:" + for(var/decl/codex_category/category in entry.categories) + body = "[body] [category.name]" + body = "[body]

" + return body + +// Strip out any invalid characters from the filename. +/decl/codex_page_converter/proc/convert_filename(var/filename) + . = replacetext(lowertext(filename), " ", "_") + for(var/char in illegal_filename_characters) + . = replacetext(., char, "") + . = "[file_prefix][.][file_suffix]" + +/decl/codex_page_converter/proc/generate_sidebar() + + sidebar = list() + sidebar += "Main page" + +/* +TODO: work out how to implement an external search function. + sidebar += "
" + sidebar += "
" + sidebar += "" + sidebar += "" + sidebar += "
" +*/ + + sidebar += "
" + sidebar += "
    " + var/list/codex_categories = decls_repository.get_decls_of_subtype(/decl/codex_category) + for(var/cat_type in codex_categories) + var/decl/codex_category/cat = codex_categories[cat_type] + var/datum/codex_entry/cat_entry = SScodex.get_entry_by_string("[cat.name] (category)") + if(cat_entry) + sidebar += "
  • [cat.name]
  • " + sidebar += "
" + + sidebar += "
" + sidebar += "
    " + var/githuburl = get_config_value(/decl/config/text/githuburl) + if(githuburl) + sidebar += "
  • Github repository
  • " + var/discordurl = get_config_value(/decl/config/text/discordurl) + if(discordurl) + sidebar += "
  • Discord community
  • " + sidebar += "
" + + sidebar = jointext(sidebar, "\n") + +/decl/codex_page_converter/proc/get_sidebar() + if(!sidebar) + generate_sidebar() + return sidebar + +// Strips out some extraneous
in the codex strings. +/decl/codex_page_converter/proc/convert_body(var/title, var/list/body) + . = "\n
\n
\n[get_sidebar()]\n
\n
\n

[title]

\n[jointext(body, "\n")]\n" + . = replacetext(., "


", "\n

") + . = replacetext(., "

", "\n

") + . = replacetext(., "


", "

\n") + . = replacetext(., "

", "

\n") + . = insert_header(title, .) + . = insert_footer(title, .) + . = "\n\n[.]\n
\n
\n\n" + +/decl/codex_page_converter/proc/strikethrough(var/thing) + return "[thing]" + +/decl/codex_page_converter/proc/convert_link(var/address, var/thing) + return "[thing]" + +/datum/controller/subsystem/codex/proc/dump_to_filesystem(var/codex_page_converter = /decl/codex_page_converter) + + var/decl/codex_page_converter/convert = GET_DECL(codex_page_converter) + + // Build a reference list of filenames to datums so we can + // crosslink them when generating the text body. Also collect + // our body text in the process. + var/list/address_to_body = list() + var/list/address_to_entry = list() + var/list/entry_to_address = list() + //var/list/seen_name_count = list() + for(var/datum/codex_entry/codex_entry as anything in all_entries) + var/address = convert.convert_filename(codex_entry.get_dump_link_name()) + address_to_entry[address] = codex_entry + entry_to_address[codex_entry] = address + address_to_body[address] = convert.convert_body(codex_entry.name, codex_entry.get_codex_body(include_header = FALSE, include_footer = FALSE)) + + // Copied from del_the_world UT exceptions list. + var/static/list/skip_types = typesof( + /obj/item/organ/external/chest, + /obj/machinery/apc, + /obj/machinery/alarm, + /obj/structure/stairs + ) + + // Suspend to avoid fluid flows shoving stuff off the testing turf. + SSfluids.suspend() + + // Also iterate the object tree for any generated on-examine codex pages. + var/list/seen_name_count = list() + for(var/atom_type in typesof(/obj/item, /obj/effect, /obj/structure, /obj/machinery, /obj/vehicle, /mob) - skip_types) + var/atom/movable/atom = atom_type + if(!TYPE_IS_SPAWNABLE(atom) || !initial(atom.simulated)) + continue + try + atom = new atom_type + if(!istype(atom)) // Something went wrong, possibly a runtime in the atom info repo. + continue + var/datum/codex_entry/codex_entry = atom.get_specific_codex_entry() + if(istype(codex_entry)) + var/link_name = codex_entry.get_dump_link_name() + if(ismob(atom)) + link_name = "[link_name] (mob)" + else if(isobj(atom)) + link_name = "[link_name] (object)" + else if(isturf(atom)) + link_name = "[link_name] (turf)" + seen_name_count[link_name]++ // these are definitely not going to be unique based on name. + var/address = convert.convert_filename("[link_name]_[seen_name_count[link_name]]") + address_to_entry[address] = codex_entry + entry_to_address[codex_entry] = address + address_to_body[address] = convert.convert_body(codex_entry.name, codex_entry.get_codex_body(include_header = FALSE, include_footer = FALSE)) + if(!QDELETED(atom)) + qdel(atom, force = TRUE) // clean up after yourself, goddang + catch(var/exception/E) + PRINT_STACK_TRACE("Exception when performing codex dump for [atom_type]: [E]") + + // TODO: disambiguation pages - generate in DM, skip dump, iterate to create pages + + // Parse links and replace with hrefs to the filenames in address_to_entry + // Boilerplate stolen from codex parse_links(), thanks Chinsky. + var/regex_key + var/replacement + var/datum/codex_entry/linked_entry + var/list/dumping_to_file = list() + var/list/broken_links = list() + for(var/entry_address in address_to_body) + var/entry_body = address_to_body[entry_address] + while(linkRegex.Find(entry_body)) + regex_key = linkRegex.group[4] + if(linkRegex.group[2]) + regex_key = linkRegex.group[3] + regex_key = lowertext(trim(regex_key)) + linked_entry = get_entry_by_string(regex_key) + replacement = linkRegex.group[4] + if(linked_entry && entry_to_address[linked_entry]) + replacement = convert.convert_link(entry_to_address[linked_entry], replacement) + else + broken_links |= "[replacement] ([regex_key])" + replacement = convert.strikethrough(replacement) + entry_body = replacetextEx(entry_body, linkRegex.match, replacement) + dumping_to_file[entry_address] = entry_body + + // Print any broken links for debugging purposes. + if(length(broken_links)) + log_error("Codex had [length(broken_links)] broken link\s:\n[jointext(broken_links, "\n")]") + + // Write the collected files out to the filesystem. + for(var/entry_address in dumping_to_file) + var/file_address = "[convert.write_location][entry_address]" + if(fexists(file_address) && !fdel(file_address)) + log_error("Could not remove previous version of file at [file_address].") + continue + to_file(file(file_address), dumping_to_file[entry_address]) + + // Handle any additional dump requirements (CSS, etc) + convert.handle_additional_dump() + + return TRUE diff --git a/code/controllers/subsystems/initialization/computer_networks.dm b/code/controllers/subsystems/initialization/computer_networks.dm index d53da4b14bc2..1b0da0f71299 100644 --- a/code/controllers/subsystems/initialization/computer_networks.dm +++ b/code/controllers/subsystems/initialization/computer_networks.dm @@ -1,36 +1,66 @@ +#define MAX_CONNECTION_ATTEMPTS 5 + +/datum/proc/handle_post_network_connection() + return + SUBSYSTEM_DEF(networking) name = "Computer Networks" priority = SS_PRIORITY_COMPUTER_NETS flags = SS_BACKGROUND | SS_NO_INIT wait = 2 SECOND - runlevels = RUNLEVEL_INIT | RUNLEVELS_DEFAULT + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT var/list/networks = list() var/list/connection_queue = list() var/list/tmp_queue = list() + /// Assoc list of network_id -> queue of devices that need to reconnect. This is checked when a new network is made. + var/list/list/reconnect_queues = list() /datum/controller/subsystem/networking/fire(resumed = FALSE) if(!resumed) tmp_queue = connection_queue.Copy() connection_queue = list() while(tmp_queue.len) - var/datum/extension/network_device/device = tmp_queue[tmp_queue.len] + try_connect(tmp_queue[tmp_queue.len]) tmp_queue.len-- - - if(!QDELETED(device)) - var/connected - if(device.network_id) - connected = device.connect() - else - connected = device.connect_to_any() - if(!connected) - connection_queue += device - if(MC_TICK_CHECK) return +/datum/controller/subsystem/networking/proc/try_connect(var/datum/extension/network_device/device) + + if(QDELETED(device)) + return + + if(device.network_id) + . = device.connect() + else + . = device.connect_to_any() + if(.) + device.holder?.handle_post_network_connection() + device.connection_attempts = 0 + else + if(device.connection_attempts < MAX_CONNECTION_ATTEMPTS) + device.connection_attempts++ + connection_queue += device + else // Maximum connection attempts reached. Do not readd to the queue. + device.connection_attempts = 0 + /datum/controller/subsystem/networking/stat_entry() ..("[length(networks)] network\s, [length(connection_queue)] connection\s queued") /datum/controller/subsystem/networking/proc/queue_connection(var/datum/extension/network_device/device) - connection_queue |= device \ No newline at end of file + connection_queue |= device + +/datum/controller/subsystem/networking/proc/queue_reconnect(var/datum/extension/network_device/device, var/network_id) + LAZYDISTINCTADD(reconnect_queues[network_id], device) + +/datum/controller/subsystem/networking/proc/unqueue_reconnect(var/datum/extension/network_device/device, var/network_id) + LAZYREMOVE(reconnect_queues[network_id], device) + +/datum/controller/subsystem/networking/proc/process_reconnections(var/network_id) + for (var/datum/extension/network_device/device in reconnect_queues[network_id]) + if(device.network_id == network_id) + queue_connection(device) + LAZYCLEARLIST(reconnect_queues[network_id]) + +#undef MAX_CONNECTION_ATTEMPTS \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/cuisine.dm b/code/controllers/subsystems/initialization/cuisine.dm deleted file mode 100644 index b5a4a257ecfc..000000000000 --- a/code/controllers/subsystems/initialization/cuisine.dm +++ /dev/null @@ -1,24 +0,0 @@ -SUBSYSTEM_DEF(cuisine) - name = "Cuisine" - flags = SS_NO_FIRE - init_order = SS_INIT_MISC_LATE - var/microwave_maximum_item_storage = 0 - var/list/microwave_recipes = list() - var/list/microwave_accepts_reagents = list() - var/list/microwave_accepts_items = list( - /obj/item/holder, - /obj/item/chems/food/snacks/grown - ) - -/datum/controller/subsystem/cuisine/Initialize() - - for (var/recipe_type in subtypesof(/datum/recipe)) - var/datum/recipe/recipe = new recipe_type - microwave_recipes += recipe - for(var/thing in recipe.reagents) - microwave_accepts_reagents |= thing - for(var/thing in recipe.items) - microwave_accepts_items |= thing - microwave_maximum_item_storage = max(microwave_maximum_item_storage, length(recipe.items)) - - . = ..() diff --git a/code/controllers/subsystems/initialization/customitems.dm b/code/controllers/subsystems/initialization/customitems.dm index fc2da2f3e645..d571851c618e 100644 --- a/code/controllers/subsystems/initialization/customitems.dm +++ b/code/controllers/subsystems/initialization/customitems.dm @@ -2,66 +2,62 @@ SUBSYSTEM_DEF(customitems) name = "Custom Items" flags = SS_NO_FIRE init_order = SS_INIT_MISC_LATE - var/list/custom_items_by_ckey = list() - var/list/item_states = list() - var/list/mob_states = list() + var/list/custom_icons_by_ckey = list() + +/datum/controller/subsystem/customitems/proc/get_json_paths_from_directory(var/category, var/directory) + if(!fexists(directory)) + report_progress("[capitalize(category)] directory [directory] does not exist, no [category] config will be loaded.") + return + var/list/loaded_manifest = load_text_from_directory(directory, ".json") + if(!islist(loaded_manifest) || !length(loaded_manifest["files"])) + report_progress("[capitalize(category)] directory returned no files on load.") + return + var/dir_count = loaded_manifest["dir_count"] || 0 + var/item_count = loaded_manifest["item_count"] || 0 + report_progress("Loaded [item_count] [category]\s from [dir_count] director[dir_count == 1 ? "y" : "ies"].") + return loaded_manifest["files"] /datum/controller/subsystem/customitems/Initialize() - item_states = icon_states(CUSTOM_ITEM_OBJ) - mob_states = icon_states(CUSTOM_ITEM_MOB) + var/list/json_to_load = get_json_paths_from_directory("custom item", CUSTOM_ITEM_CONFIG) + for(var/key in json_to_load) + var/datum/custom_item/citem = new(cached_json_decode(json_to_load[key])) + var/result = citem.validate() + if(result) + PRINT_STACK_TRACE("Invalid custom item for '[key]': [result]") + else + LAZYDISTINCTADD(custom_items_by_ckey[citem.character_ckey], citem) - if(!fexists(CUSTOM_ITEM_CONFIG)) - report_progress("Custom item directory [CUSTOM_ITEM_CONFIG] does not exist, no custom items will be loaded.") - return + json_to_load = get_json_paths_from_directory("custom icon", CUSTOM_ICON_CONFIG) + for(var/key in json_to_load) + var/datum/custom_icon/cicon = new(cached_json_decode(json_to_load[key])) + var/result = cicon.validate() + if(result) + PRINT_STACK_TRACE("Invalid custom icon for '[key]': [result]") + else + LAZYDISTINCTADD(custom_icons_by_ckey[cicon.character_ckey], cicon) - var/dir_count = -1 - var/item_count = 0 - var/list/directories_to_check = list(CUSTOM_ITEM_CONFIG) - while(length(directories_to_check)) - var/checkdir = directories_to_check[1] - directories_to_check -= checkdir - if(checkdir == "[CUSTOM_ITEM_CONFIG]examples/") - continue - for(var/checkfile in flist(checkdir)) - checkfile = "[checkdir][checkfile]" - if(copytext(checkfile, -1) == "/") - directories_to_check += checkfile - dir_count++ - else if(copytext(checkfile, -5) == ".json") - try - var/datum/custom_item/citem = new(cached_json_decode(file2text(checkfile))) - var/result = citem.validate() - if(result) - crash_with("Invalid custom item [checkfile]: [result]") - else - LAZYDISTINCTADD(custom_items_by_ckey[citem.ckey], citem) - item_count++ - catch(var/exception/e) - crash_with("Exception loading custom item [checkfile]: [e] on [e.file]:[e.line]") - - report_progress("Loaded [item_count] custom item\s from [dir_count] director[dir_count == 1 ? "y" : "ies"].") . = ..() // Places the item on the target mob. -/datum/controller/subsystem/customitems/proc/place_custom_item(mob/living/carbon/human/M, var/datum/custom_item/citem) +/datum/controller/subsystem/customitems/proc/place_custom_item(mob/living/human/M, var/datum/custom_item/citem) . = M && citem && citem.spawn_item(get_turf(M)) if(. && !M.equip_to_appropriate_slot(.) && !M.equip_to_storage(.)) to_chat(M, SPAN_WARNING("Your custom item, \the [.], could not be placed on your character.")) QDEL_NULL(.) //gets the relevant list for the key from the listlist if it exists, check to make sure they are meant to have it and then calls the giving function -/datum/controller/subsystem/customitems/proc/equip_custom_items(mob/living/carbon/human/M) +/datum/controller/subsystem/customitems/proc/equip_custom_items(mob/living/human/M) var/list/key_list = custom_items_by_ckey[M.ckey] if(!length(key_list)) return for(var/datum/custom_item/citem in key_list) // Check for requisite ckey and character name. - if(citem.ckey != M.ckey || lowertext(citem.character_name) != lowertext(M.real_name)) + if(citem.character_ckey != M.ckey || citem.character_name != lowertext(M.real_name)) continue // Check for required access. - var/obj/item/card/id/current_id = M.wear_id + var/obj/item/card/id/current_id = M.get_equipped_item(slot_wear_id_str) if(length(citem.req_access) && (!istype(current_id) || !has_access(current_id.access, citem.req_access))) continue // Check for required job title. @@ -72,52 +68,84 @@ SUBSYSTEM_DEF(customitems) // Spawn and equip the item. if(ispath(citem.apply_to_target_type)) - var/obj/item/existing_item = (locate(citem.apply_to_target_type) in M.get_contents()) + var/obj/item/existing_item = (locate(citem.apply_to_target_type) in M.get_mob_contents()) if(existing_item) citem.apply_to_item(existing_item) return place_custom_item(M,citem) +/datum/custom_icon + var/character_ckey + var/character_name + var/category + var/list/ids_to_icons = list() + +/datum/custom_icon/New(var/list/data) + character_ckey = data["character_ckey"] + character_name = data["character_name"] + category = data["icon_category"] + ids_to_icons = data["icons"] + +/datum/custom_icon/proc/finalize_data() + character_ckey = ckey(character_ckey) + character_name = lowertext(character_name) + for(var/icon_id in ids_to_icons) + var/icon_loc = ids_to_icons[icon_id] + var/config_icon_loc = get_config_value(/decl/config/text/custom_icon_icon_location) + if(config_icon_loc) + icon_loc = "[config_icon_loc]/[icon_loc]" + ids_to_icons[icon_id] = file(icon_loc) + +/datum/custom_icon/proc/validate() + if(!length(ids_to_icons)) + return SPAN_WARNING("Icon list is empty.") + for(var/icon_id in ids_to_icons) + if(!isfile(ids_to_icons[icon_id]) && !isicon(ids_to_icons[icon_id])) + return SPAN_WARNING("ID [icon_id] maps to non-file non-icon value [ids_to_icons[icon_id] || "NULL"]") /datum/custom_item - var/ckey + var/character_ckey var/character_name - var/item_icon_state var/item_desc var/item_name var/item_path + var/item_icon + var/item_state var/apply_to_target_type var/list/req_access var/list/req_titles var/list/additional_data /datum/custom_item/New(var/list/data) - ckey = ckey(data["ckey"]) - character_name = lowertext(data["character_name"]) - item_name = data["item_name"] - item_desc = data["item_desc"] - item_icon_state = data["item_icon_state"] - item_path = text2path(data["item_path"]) - req_access = data["req_access"] || list() - req_titles = data["req_titles"] || list() - additional_data = data["additional_data"] || list() - apply_to_target_type = text2path(data["apply_to_target_type"]) || data["apply_to_target_type"] + character_ckey = data["character_ckey"] + character_name = data["character_name"] + item_name = data["item_name"] + item_desc = data["item_desc"] + item_icon = data["item_icon"] + item_state = data["item_state"] + req_access = data["req_access"] + req_titles = data["req_titles"] + item_path = data["item_path"] + additional_data = data["additional_data"] + apply_to_target_type = data["apply_to_target_type"] + finalize_data() // Separate proc in case of runtime. + +/datum/custom_item/proc/finalize_data() + character_ckey = ckey(character_ckey) + character_name = lowertext(character_name) + item_path = item_path && text2path(item_path) + apply_to_target_type = apply_to_target_type && text2path(apply_to_target_type) + if(item_icon) + var/config_item_loc = get_config_value(/decl/config/text/custom_item_icon_location) + if(config_item_loc) + item_icon = "[config_item_loc]/[item_path]" + if(fexists(item_icon)) + item_icon = file(item_icon) /datum/custom_item/proc/validate() if(!ispath(item_path, /obj/item)) return SPAN_WARNING("The given item path is invalid or does not exist.") if(apply_to_target_type && !ispath(apply_to_target_type, /obj/item)) return SPAN_WARNING("The target item path is invalid or does not exist.") - else if(item_icon_state) - if(ispath(item_path, /obj/item/kit/suit)) - for(var/state in list("[item_icon_state]_suit", "[item_icon_state]_helmet")) - if(!(state in SScustomitems.item_states)) - return SPAN_WARNING("The given item icon [state] does not exist.") - if(!(state in SScustomitems.mob_states)) - return SPAN_WARNING("The given mob icon [state] does not exist.") - else - for(var/state in list(item_icon_state)) - if(!(state in SScustomitems.item_states)) - return SPAN_WARNING("The given item icon [state] does not exist.") /datum/custom_item/proc/spawn_item(var/newloc) . = new item_path(newloc) diff --git a/code/controllers/subsystems/initialization/fabrication.dm b/code/controllers/subsystems/initialization/fabrication.dm index 3585f1f287fc..6fd2b5c28dbd 100644 --- a/code/controllers/subsystems/initialization/fabrication.dm +++ b/code/controllers/subsystems/initialization/fabrication.dm @@ -3,65 +3,48 @@ SUBSYSTEM_DEF(fabrication) flags = SS_NO_FIRE init_order = SS_INIT_MISC_LATE - var/list/all_recipes = list() var/list/locked_recipes = list() var/list/initial_recipes = list() var/list/categories = list() var/list/crafting_procedures_by_type = list() var/list/recipes_by_product_type = list() var/list/fields_by_id = list() - - // Fabricators who want their initial recipies + // Weakrefs to fabricators who want their initial recipies var/list/fabricators_to_init = list() - // These should be removed after rewriting crafting to respect init order. - var/list/crafting_recipes_to_init = list() - var/post_recipe_init = FALSE /datum/controller/subsystem/fabrication/Initialize() // Fab recipes. - for(var/R in subtypesof(/datum/fabricator_recipe)) - var/datum/fabricator_recipe/recipe = R + for(var/datum/fabricator_recipe/recipe as anything in subtypesof(/datum/fabricator_recipe)) if(!initial(recipe.path)) continue recipe = new recipe recipes_by_product_type[recipe.path] = recipe for(var/fab_type in recipe.fabricator_types) - LAZYADD(all_recipes[fab_type], recipe) LAZYDISTINCTADD(categories[fab_type], recipe.category) if(recipe.required_technology) LAZYADD(locked_recipes[fab_type], recipe) else LAZYADD(initial_recipes[fab_type], recipe) + CHECK_TICK // Slapcrafting trees. var/list/all_crafting_handlers = decls_repository.get_decls_of_subtype(/decl/crafting_stage) for(var/hid in all_crafting_handlers) var/decl/crafting_stage/handler = all_crafting_handlers[hid] + // TODO: revisit this if map tech level can be mutated at runtime + if(global.using_map.map_tech_level < handler.available_to_map_tech_level) + continue if(ispath(handler.begins_with_object_type)) LAZYDISTINCTADD(crafting_procedures_by_type[handler.begins_with_object_type], handler) - for(var/datum/stack_recipe/recipe in crafting_recipes_to_init) - recipe.InitializeMaterials() - crafting_recipes_to_init.Cut() - - post_recipe_init = TRUE - - for(var/weakref/ref in fabricators_to_init) - var/obj/machinery/fabricator/F = ref.resolve() - if(F) - init_fabricator(F) + for(var/weakref/weak_fab in fabricators_to_init) + var/obj/machinery/fabricator/fab = weak_fab.resolve() + fab?.refresh_design_cache() fabricators_to_init.Cut() - init_rpd_lists() . = ..() -/datum/controller/subsystem/fabrication/proc/init_crafting_recipe(var/datum/stack_recipe/recipe) - if(post_recipe_init) - recipe.InitializeMaterials() - else - crafting_recipes_to_init |= recipe - /datum/controller/subsystem/fabrication/proc/get_research_field_by_id(var/rnd_id) if(!length(fields_by_id)) var/all_fields = decls_repository.get_decls_of_subtype(/decl/research_field) @@ -73,9 +56,6 @@ SUBSYSTEM_DEF(fabrication) /datum/controller/subsystem/fabrication/proc/get_categories(var/fab_type) . = categories[fab_type] -/datum/controller/subsystem/fabrication/proc/get_all_recipes(var/fab_type) - . = all_recipes[fab_type] - /datum/controller/subsystem/fabrication/proc/get_initial_recipes(var/fab_type) . = initial_recipes[fab_type] @@ -101,19 +81,14 @@ SUBSYSTEM_DEF(fabrication) . = crafting_procedures_by_type[_type] /datum/controller/subsystem/fabrication/proc/try_craft_with(var/obj/item/target, var/obj/item/thing, var/mob/user) + // crafting holders should handle this in attackby() + if(QDELETED(target) || QDELETED(thing) || QDELETED(user) || istype(target, /obj/item/crafting_holder) || istype(thing, /obj/item/crafting_holder)) + return for(var/decl/crafting_stage/initial_stage in SSfabrication.find_crafting_recipes(target.type)) - if(initial_stage.can_begin_with(target) && initial_stage.is_appropriate_tool(thing)) - var/obj/item/crafting_holder/H = new /obj/item/crafting_holder(get_turf(target), initial_stage, target, thing, user) - if(initial_stage.progress_to(thing, user, H)) - return H - else - qdel(H) + if(initial_stage.can_begin_with(target) && initial_stage.is_appropriate_tool(thing, target) && initial_stage.is_sufficient_amount(user, thing)) + var/obj/item/crafting_holder/holder = new(get_turf(target), initial_stage, target, thing, user) + initial_stage.progress_to(thing, user, holder) + return holder -/datum/controller/subsystem/fabrication/proc/init_fabricator(obj/machinery/fabricator/fab) - if(post_recipe_init) - var/list/base_designs = get_initial_recipes(fab.fabricator_class) - fab.design_cache = islist(base_designs) ? base_designs.Copy() : list() // Don't want to mutate the subsystem cache. - fab.refresh_design_cache() - else - fabricators_to_init |= weakref(fab) - \ No newline at end of file +/datum/controller/subsystem/fabrication/proc/queue_design_cache_refresh(var/obj/machinery/fabricator/fab) + fabricators_to_init |= weakref(fab) \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/lore.dm b/code/controllers/subsystems/initialization/lore.dm index b5fe7093e0c0..96b7a9850e0a 100644 --- a/code/controllers/subsystems/initialization/lore.dm +++ b/code/controllers/subsystems/initialization/lore.dm @@ -3,9 +3,6 @@ SUBSYSTEM_DEF(lore) init_order = SS_INIT_LORE flags = SS_NO_FIRE - var/list/cultural_info_by_name = list() - var/list/cultural_info_by_path = list() - var/list/tagged_info = list() var/list/dreams = list( "a familiar face", "voices from all around", "a traitor", "an ally", "darkness", "light", "a catastrophe", "a loved one", "warmth", "freezing", @@ -16,6 +13,7 @@ SUBSYSTEM_DEF(lore) "an old home", "right behind you", "standing above you", "someone near by", "a place forgotten" ) + var/list/tagged_info = list() var/list/credits_other = list("ATTACK! ATTACK! ATTACK!") var/list/credits_adventure_names = list("QUEST", "FORCE", "ADVENTURE") var/list/credits_crew_names = list("EVERYONE") @@ -31,20 +29,14 @@ SUBSYSTEM_DEF(lore) /datum/controller/subsystem/lore/Initialize() - for(var/ftype in subtypesof(/decl/cultural_info)) - var/decl/cultural_info/culture = ftype - if(!initial(culture.name)) - continue - culture = new culture - if(cultural_info_by_name[culture.name]) - crash_with("Duplicate cultural datum ID - [culture.name] - [ftype]") - cultural_info_by_name[culture.name] = culture - cultural_info_by_path[ftype] = culture - if(culture.category && !culture.hidden) - if(!tagged_info[culture.category]) - tagged_info[culture.category] = list() - var/list/tag_list = tagged_info[culture.category] - tag_list[culture.name] = culture + var/list/all_backgrounds = decls_repository.get_decls_of_subtype(/decl/background_detail) + for(var/ftype in all_backgrounds) + var/decl/background_detail/background = all_backgrounds[ftype] + if(background.name && background.category && !background.hidden) + if(!tagged_info[background.category]) + tagged_info[background.category] = list() + var/list/tag_list = tagged_info[background.category] + tag_list[background.name] = background for(var/jobtype in subtypesof(/datum/job)) var/datum/job/job = jobtype @@ -59,13 +51,13 @@ SUBSYSTEM_DEF(lore) return tagged_info[token] /datum/controller/subsystem/lore/proc/refresh_credits_from_departments() - for(var/thing in SSdepartments.departments) - var/datum/department/dept = SSdepartments.departments[thing] - if(dept.title) - credits_nouns |= uppertext(dept.title) + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/thing in all_departments) + var/decl/department/dept = all_departments[thing] + credits_nouns |= uppertext(dept.name) /datum/controller/subsystem/lore/proc/get_end_credits_title(var/force) - if(!GLOB.end_credits_title || force) + if(!global.end_credits_title || force) var/list/possible_titles = list() refresh_credits_from_departments() possible_titles += "THE [pick("DOWNFALL OF", "RISE OF", "TROUBLE WITH", "FINAL STAND OF", "DARK SIDE OF", "DESOLATION OF", "DESTRUCTION OF", "CRISIS OF")] [pick(credits_nouns)]" @@ -75,13 +67,10 @@ SUBSYSTEM_DEF(lore) possible_titles += "A VERY [pick(credits_adjectives)] [pick(credits_holidays)]" possible_titles += "[pick(credits_adjectives)] [pick(credits_adventure_names)]" possible_titles += "[pick(credits_topics)] [pick(credits_adventure_names)]" - possible_titles += "THE DAY [uppertext(GLOB.using_map.station_short)] STOOD STILL" + possible_titles += "THE DAY [uppertext(global.using_map.station_short)] STOOD STILL" possible_titles |= credits_other - GLOB.end_credits_title = pick(possible_titles) - . = GLOB.end_credits_title - -/datum/controller/subsystem/lore/proc/get_culture(var/culture_ident) - return cultural_info_by_name[culture_ident] ? cultural_info_by_name[culture_ident] : cultural_info_by_path[culture_ident] + global.end_credits_title = pick(possible_titles) + . = global.end_credits_title /datum/controller/subsystem/lore/proc/get_language_by_name(var/language_name) if(!languages_by_name) diff --git a/code/controllers/subsystems/initialization/materials.dm b/code/controllers/subsystems/initialization/materials.dm index ba0b5c82b3ee..9ce2feb2c266 100644 --- a/code/controllers/subsystems/initialization/materials.dm +++ b/code/controllers/subsystems/initialization/materials.dm @@ -1,42 +1,38 @@ +#define DAMAGE_OVERLAY_COUNT 16 + SUBSYSTEM_DEF(materials) name = "Materials" init_order = SS_INIT_MATERIALS priority = SS_PRIORITY_MATERIALS // Material vars. - var/list/materials - var/list/materials_by_name - var/list/alloy_components - var/list/alloy_products - var/list/processable_ores var/list/fusion_reactions - var/list/weighted_minerals_sparse = list() - var/list/weighted_minerals_rich = list() + var/list/weighted_minerals_sparse = list() + var/list/weighted_minerals_rich = list() // Chemistry vars. var/list/active_holders = list() - var/list/chemical_reactions = list() - var/list/chemical_reactions_by_type = list() var/list/chemical_reactions_by_id = list() var/list/chemical_reactions_by_result = list() var/list/processing_holders = list() - var/list/pending_reagent_change = list() var/list/cocktails_by_primary_ingredient = list() -/datum/controller/subsystem/materials/Initialize() + // Overlay caches + var/list/wall_damage_overlays +/datum/controller/subsystem/materials/Initialize() // Init reaction list. - //Chemical Reactions - Initialises all /datum/chemical_reaction into a list + // Chemical Reactions - Organizes /decl/chemical_reaction subtypes into a list // It is filtered into multiple lists within a list. // For example: // chemical_reaction_list[/decl/material/foo] is a list of all reactions relating to Foo // Note that entries in the list are NOT duplicated. So if a reaction pertains to // more than one chemical it will still only appear in only one of the sublists. - for(var/path in subtypesof(/datum/chemical_reaction)) - var/datum/chemical_reaction/D = new path() - chemical_reactions[path] = D + var/list/all_reactions = decls_repository.get_decls_of_subtype(/decl/chemical_reaction) + for(var/path in all_reactions) + var/decl/chemical_reaction/D = all_reactions[path] if(!chemical_reactions_by_result[D.result]) chemical_reactions_by_result[D.result] = list() chemical_reactions_by_result[D.result] += D @@ -56,47 +52,31 @@ SUBSYSTEM_DEF(materials) sortTim(cocktails_by_primary_ingredient[reagent], /proc/cmp_cocktail_des) // Various other material functions. - build_material_lists() // Build core material lists. + build_mineral_weight_lists() build_fusion_reaction_list() // Build fusion reaction tree. - build_gas_lists() // Cache our gas data. - . = ..() - -/datum/controller/subsystem/materials/proc/build_gas_lists() -/datum/controller/subsystem/materials/proc/build_material_lists() + var/alpha_inc = 256 / DAMAGE_OVERLAY_COUNT + for(var/i = 1; i <= DAMAGE_OVERLAY_COUNT; i++) + var/image/img = image(icon = 'icons/turf/walls.dmi', icon_state = "overlay_damage") + img.blend_mode = BLEND_MULTIPLY + img.alpha = (i * alpha_inc) - 1 + LAZYADD(wall_damage_overlays, img) - if(LAZYLEN(materials)) - return - - materials = list() - materials_by_name = list() - alloy_components = list() - alloy_products = list() - processable_ores = list() + . = ..() - for(var/mtype in subtypesof(/decl/material)) - var/decl/material/new_mineral = mtype - if(!initial(new_mineral.name)) - continue - new_mineral = decls_repository.get_decl(mtype) - materials += new_mineral - materials_by_name[mtype] = new_mineral +/datum/controller/subsystem/materials/proc/build_mineral_weight_lists() + var/list/material_decls = decls_repository.get_decls_of_subtype_unassociated(/decl/material) + for(var/decl/material/new_mineral as anything in material_decls) if(new_mineral.sparse_material_weight) weighted_minerals_sparse[new_mineral.type] = new_mineral.sparse_material_weight if(new_mineral.rich_material_weight) weighted_minerals_rich[new_mineral.type] = new_mineral.rich_material_weight - if(new_mineral.ore_smelts_to || new_mineral.ore_compresses_to) - processable_ores[mtype] = TRUE - if(new_mineral.alloy_product && LAZYLEN(new_mineral.alloy_materials)) - alloy_products[new_mineral] = TRUE - for(var/component in new_mineral.alloy_materials) - processable_ores[component] = TRUE - alloy_components[component] = TRUE /datum/controller/subsystem/materials/proc/build_fusion_reaction_list() fusion_reactions = list() - for(var/rtype in subtypesof(/decl/fusion_reaction)) - var/decl/fusion_reaction/cur_reaction = new rtype() + var/list/all_reactions = decls_repository.get_decls_of_subtype(/decl/fusion_reaction) + for(var/rtype in all_reactions) + var/decl/fusion_reaction/cur_reaction = all_reactions[rtype] if(!fusion_reactions[cur_reaction.p_react]) fusion_reactions[cur_reaction.p_react] = list() fusion_reactions[cur_reaction.p_react][cur_reaction.s_react] = cur_reaction @@ -131,21 +111,69 @@ SUBSYSTEM_DEF(materials) var/list/all_random_reagents = decls_repository.get_decls_of_type(/decl/material/liquid/random) for(var/rtype in all_random_reagents) var/decl/material/liquid/random/random = all_random_reagents[rtype] - if(only_if_unique && random.initialized) + if(only_if_unique && random.data_initialized) continue if(random.randomize_data(temperature)) return random.type -// This is a fairly hacky way of preventing multiple on_reagent_change() calls being fired within the same tick. -/datum/controller/subsystem/materials/proc/queue_reagent_change(var/atom/changing) - if(!pending_reagent_change[changing]) - pending_reagent_change[changing] = TRUE - addtimer(CALLBACK(src, .proc/do_reagent_change, changing), 0) - -/datum/controller/subsystem/materials/proc/do_reagent_change(var/atom/changing) - pending_reagent_change -= changing - if(!QDELETED(changing)) - changing.on_reagent_change() - /datum/controller/subsystem/materials/proc/get_cocktails_by_primary_ingredient(var/primary) . = cocktails_by_primary_ingredient[primary] + +/datum/controller/subsystem/materials/proc/get_strata_type(var/turf/wall/natural/location) + if(!istype(location)) + return + + //Turf may override level_data strata + if(ispath(location.strata_override)) + return location.strata_override + + //Then level_data + var/datum/level_data/LD = SSmapping.levels_by_z[location.z] + if(!LD._level_setup_completed && !LD._has_warned_uninitialized_strata) + LD.warn_bad_strata(location) //If we haven't warned yet dump a stack trace and warn that strata was set before init + + if(ispath(LD.strata, /decl/strata)) + return LD.strata + else if(istype(LD.strata, /decl/strata)) + return LD.strata.type + +/datum/controller/subsystem/materials/proc/create_object(var/mat_type, var/atom/target, var/amount = 1, var/object_type, var/reinf_type) + var/decl/material/mat = GET_DECL(mat_type) + return mat?.create_object(target, amount, object_type, reinf_type) + +///Returns the rock color for a given exterior wall +/datum/controller/subsystem/materials/proc/get_rock_color(var/turf/wall/location) + if(!istype(location)) + return + //#TODO: allow specifying rock color per z-level maybe? + var/datum/planetoid_data/owner = LAZYACCESS(SSmapping.planetoid_data_by_z, location.z) + if(istype(owner)) + return owner.get_rock_color() + +// There is a disconnect between legacy damage and armor code. This here helps bridge the gap. +// This could eventually be removed if we used decls for damage types. +/datum/controller/subsystem/materials/proc/get_armor_key(damage_type, damage_flags) + var/key + switch(damage_type) + if(BRUTE) + if(damage_flags & DAM_BULLET) + key = ARMOR_BULLET + else if(damage_flags & DAM_EXPLODE) + key = ARMOR_BOMB + else + key = ARMOR_MELEE + if(BURN) + if(damage_flags & DAM_LASER) + key = ARMOR_LASER + else if(damage_flags & DAM_EXPLODE) + key = ARMOR_BOMB + else + key = ARMOR_ENERGY + if(TOX) + if(damage_flags & DAM_BIO) + key = ARMOR_BIO // Otherwise just not blocked by default. + if(IRRADIATE) + key = ARMOR_RAD + if(ELECTROCUTE) + key = ARMOR_ENERGY + return key \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/misc.dm b/code/controllers/subsystems/initialization/misc.dm index 74c6eb436bbe..122c89328466 100644 --- a/code/controllers/subsystems/initialization/misc.dm +++ b/code/controllers/subsystems/initialization/misc.dm @@ -4,12 +4,5 @@ SUBSYSTEM_DEF(misc) flags = SS_NO_FIRE /datum/controller/subsystem/misc/Initialize() - if(config.generate_map) - GLOB.using_map.perform_map_generation() - - // Create robolimbs for chargen. - populate_robolimb_list() - setupgenetics() - transfer_controller = new - . = ..() \ No newline at end of file + . = ..() diff --git a/code/controllers/subsystems/initialization/modpacks.dm b/code/controllers/subsystems/initialization/modpacks.dm index bd65c9a41289..7a44aec55c6f 100644 --- a/code/controllers/subsystems/initialization/modpacks.dm +++ b/code/controllers/subsystems/initialization/modpacks.dm @@ -1,12 +1,13 @@ SUBSYSTEM_DEF(modpacks) name = "Modpacks" - init_order = SS_INIT_EARLY + init_order = SS_INIT_MODPACKS flags = SS_NO_FIRE var/list/loaded_modpacks = list() // Compiled modpack information. var/list/default_submap_whitelisted_species = list() - var/list/default_submap_blacklisted_species = list(SPECIES_ALIEN, SPECIES_GOLEM) + var/list/default_submap_blacklisted_species = list() + var/list/modpack_nanoui_directories = list() /datum/controller/subsystem/modpacks/Initialize() var/list/all_modpacks = decls_repository.get_decls_of_subtype(/decl/modpack) @@ -16,13 +17,13 @@ SUBSYSTEM_DEF(modpacks) var/decl/modpack/manifest = all_modpacks[package] var/fail_msg = manifest.pre_initialize() if(QDELETED(manifest)) - crash_with("Modpack of type [package] is null or queued for deletion.") + PRINT_STACK_TRACE("Modpack of type [package] is null or queued for deletion.") continue if(fail_msg) - crash_with("Modpack [manifest.name] ([package]) failed to pre-initialize: [fail_msg].") + PRINT_STACK_TRACE("Modpack [manifest.name] ([package]) failed to pre-initialize: [fail_msg].") continue if(loaded_modpacks[manifest.name]) - crash_with("Attempted to register duplicate modpack name [manifest.name].") + PRINT_STACK_TRACE("Attempted to register duplicate modpack name [manifest.name].") continue loaded_modpacks[manifest.name] = manifest @@ -31,14 +32,19 @@ SUBSYSTEM_DEF(modpacks) var/decl/modpack/manifest = all_modpacks[package] var/fail_msg = manifest.initialize() if(fail_msg) - crash_with("Modpack [(istype(manifest) && manifest.name) || "Unknown"] failed to initialize: [fail_msg]") + PRINT_STACK_TRACE("Modpack [(istype(manifest) && manifest.name) || "Unknown"] failed to initialize: [fail_msg]") for(var/package in all_modpacks) var/decl/modpack/manifest = all_modpacks[package] var/fail_msg = manifest.post_initialize() if(fail_msg) - crash_with("Modpack [(istype(manifest) && manifest.name) || "Unknown"] failed to post-initialize: [fail_msg]") + PRINT_STACK_TRACE("Modpack [(istype(manifest) && manifest.name) || "Unknown"] failed to post-initialize: [fail_msg]") - // Update compiled infolists. - default_submap_whitelisted_species |= GLOB.using_map.default_species + // Update compiled infolists and apply. + default_submap_whitelisted_species |= global.using_map.default_species + for(var/decl/submap_archetype/submap in global.using_map.get_available_submap_archetypes()) + if(islist(submap.whitelisted_species) && !length(submap.whitelisted_species)) + submap.whitelisted_species |= SSmodpacks.default_submap_whitelisted_species + if(islist(submap.blacklisted_species) && !length(submap.blacklisted_species)) + submap.blacklisted_species |= SSmodpacks.default_submap_blacklisted_species . = ..() diff --git a/code/controllers/subsystems/initialization/persistence.dm b/code/controllers/subsystems/initialization/persistence.dm deleted file mode 100644 index 03a5c1337ef7..000000000000 --- a/code/controllers/subsystems/initialization/persistence.dm +++ /dev/null @@ -1,78 +0,0 @@ -SUBSYSTEM_DEF(persistence) - name = "Persistence" - init_order = SS_INIT_MISC_LATE - flags = SS_NO_FIRE | SS_NEEDS_SHUTDOWN - - var/elevator_fall_path = "data/elevator_falls_tracking.txt" - var/elevator_fall_shifts = -1 // This is snowflake, but oh well. - - var/list/tracking_values = list() - var/list/persistence_datums = list() - -/datum/controller/subsystem/persistence/Initialize() - . = ..() - for(var/thing in subtypesof(/datum/persistent)) - var/datum/persistent/P = new thing - persistence_datums[thing] = P - P.Initialize() - - // Begin snowflake. - if(fexists(elevator_fall_path)) - try - elevator_fall_shifts = text2num(file2text(elevator_fall_path)) - catch() - elevator_fall_shifts = initial(elevator_fall_shifts) - if(isnull(elevator_fall_shifts)) - elevator_fall_shifts = initial(elevator_fall_shifts) - elevator_fall_shifts++ - // End snowflake. - -/datum/controller/subsystem/persistence/Shutdown() - for(var/thing in persistence_datums) - var/datum/persistent/P = persistence_datums[thing] - P.Shutdown() - - // Refer to snowflake above. - if(fexists(elevator_fall_path)) - fdel(elevator_fall_path) - text2file("[elevator_fall_shifts]", elevator_fall_path) - -/datum/controller/subsystem/persistence/proc/track_value(var/atom/value, var/track_type) - - var/turf/T = get_turf(value) - if(!T) - return - - var/area/A = get_area(T) - if(!A || (A.area_flags & AREA_FLAG_IS_NOT_PERSISTENT)) - return - - if(!(T.z in GLOB.using_map.station_levels)) - return - - if(!tracking_values[track_type]) - tracking_values[track_type] = list() - tracking_values[track_type] |= value - -/datum/controller/subsystem/persistence/proc/is_tracking(var/atom/value, var/track_type) - . = (value in tracking_values[track_type]) - -/datum/controller/subsystem/persistence/proc/forget_value(var/atom/value, var/track_type) - if(tracking_values[track_type]) - tracking_values[track_type] -= value - -/datum/controller/subsystem/persistence/proc/show_info(var/mob/user) - - if(!check_rights(R_INVESTIGATE, C = user)) - return - - var/list/dat = list("") - var/can_modify = check_rights(R_ADMIN, 0, user) - for(var/thing in persistence_datums) - var/datum/persistent/P = persistence_datums[thing] - if(P.has_admin_data) - dat += P.GetAdminSummary(user, can_modify) - dat += "
" - var/datum/browser/popup = new(user, "admin_persistence", "Persistence Data") - popup.set_content(jointext(dat, null)) - popup.open() diff --git a/code/controllers/subsystems/initialization/robots.dm b/code/controllers/subsystems/initialization/robots.dm index b71138afa750..75c70a7fe4cc 100644 --- a/code/controllers/subsystems/initialization/robots.dm +++ b/code/controllers/subsystems/initialization/robots.dm @@ -10,18 +10,15 @@ SUBSYSTEM_DEF(robots) var/list/robot_alt_titles = list() var/list/mob_types_by_title = list( - "robot, flying" = /mob/living/silicon/robot/flying, - "drone, flying" = /mob/living/silicon/robot/flying, - "cyborg, flying" = /mob/living/silicon/robot/flying + "cyborg, flying" = /mob/living/silicon/robot/flying, + "robot, flying" = /mob/living/silicon/robot/flying ) var/list/mmi_types_by_title = list( - "cyborg" = /obj/item/mmi, - "robot" = /obj/item/organ/internal/posibrain, - "drone" = /obj/item/mmi/digital/robot, - "cyborg, flying" = /obj/item/mmi, - "robot, flying" = /obj/item/organ/internal/posibrain, - "drone, flying" = /obj/item/mmi/digital/robot + "cyborg" = /obj/item/organ/internal/brain_interface, + "robot" = /obj/item/organ/internal/brain/robotic, + "cyborg, flying" = /obj/item/organ/internal/brain_interface, + "robot, flying" = /obj/item/organ/internal/brain/robotic ) /datum/controller/subsystem/robots/Initialize() @@ -60,8 +57,8 @@ SUBSYSTEM_DEF(robots) if(modules[include_override]) .[include_override] = modules[include_override] -/datum/controller/subsystem/robots/proc/get_mmi_type_by_title(var/check_title) - . = mmi_types_by_title[lowertext(trim(check_title))] || /obj/item/mmi +/datum/controller/subsystem/robots/proc/get_brain_type_by_title(var/check_title) + . = mmi_types_by_title[lowertext(trim(check_title))] || /obj/item/organ/internal/brain/robotic /datum/controller/subsystem/robots/proc/get_mob_type_by_title(var/check_title) . = mob_types_by_title[lowertext(trim(check_title))] || /mob/living/silicon/robot \ No newline at end of file diff --git a/code/controllers/subsystems/initialization/secrets.dm b/code/controllers/subsystems/initialization/secrets.dm new file mode 100644 index 000000000000..fa4d027ade07 --- /dev/null +++ b/code/controllers/subsystems/initialization/secrets.dm @@ -0,0 +1,276 @@ +/* + * Secret content/hotloaded content subsystem. + * + * Very barebones at the moment, just slapping it down so there's something there to work with. + * + * Simple guide: + * - Create a .json file in data/secrets/ or any child subfolder. + * - Put a json dictionary in there with a field "path" pointing to a valid datum type. + * - Put a field "secret_key" in the dictionary with a GLOBALLY UNIQUE string value. + * - Put a field "secret_categories" in the dictionary with a list of categories to file it under. + * - Put a field "secret_category" in the dictionary with a single text category to file it in one. + * - The JSON will be loaded early in init and can be retrieved for use in lore notes or whatever. + * + * Keep in mind that this system can SERIOUSLY MESS YOU UP - there are datum types that will CRASH + * YOUR SERVER if improperly created/initialized, and this system ignores all named arguments or + * argument ordering when it passes the loaded JSON to the datum instance. DO NOT TRY TO CREATE A + * PATH THAT YOU DO NOT FULLY UNDERSTAND TO BE SAFE TO CREATE. YOUR INSURANCE WILL NOT COVER IT. + * + * Vague todo with ideas for future conversion/use: + * - Map templates + * - Materials + * - Chemical recipes + * - Verb to load arbitrary json content from a file on local storage. + * + * Secrets can be retrieved with: + * var/datum/secret_stuff = SSsecrets.retrieve_secret("your unique key", /some/path/for/compile/time/validation) + * var/datum/random_secret_stuff = SSsecrets.retrieve_random_secret("your unique category", bool_if_you_want_no_duplicates, /some/path/for/compile/time/validation) + * var/list/bunch_of_secrets = SSsecrets.retrieve_secrets_by_category("your unique category") + * + * You can refer to the /datum/secret_note and /obj/item/paper/secret_note types in + * code/modules/hotloading/note.dm for a practical example of how this system can be used. + * + */ + +SUBSYSTEM_DEF(secrets) + name = "Secret Content" + init_order = SS_INIT_SECRETS + flags = SS_NO_FIRE + + /// Root locations of content to load; terminating / is important for example dir check. Maps and mods inject their own directories into this list pre-init. + var/static/list/load_directories = list("data/secrets/") + + /// Defines a list of paths that secrets are allowed to create. Anything loaded that isn't of a type or subtype in this list will throw an error. + var/static/list/permitted_paths = list(/datum/secret_note) + /// Defines a list of paths that secrets are not allowed to create. Anything loaded that is of a type or subtype in this list will throw an error. + var/static/list/forbidden_paths = list() + // Defines a list of types that should be logged on creation for later admin reference (ex. random chemical recipes or exploitable secrets) + var/static/list/dangerous_paths = list() + + // Secrets indexed by category that have already been randomly selected before. + var/list/retrieved_secrets = list() + /// Secrets indexed by key for specific retrieval. + var/list/secrets_by_key = list() + // Secrets indexed by category for mass retrieval. + var/list/secrets_by_category = list() + /// Cache for files retrieved (such as icons) + var/list/file_cache = list() + + /// List of vars to hide from View Variables as this system is supposed to be full of secrets. + var/static/list/protected_lists = list( + "protected_lists", + "retrieved_secrets", + "secrets_by_key", + "secrets_by_category", + "permitted_paths", + "forbidden_paths", + "load_directories" + ) + +/datum/controller/subsystem/secrets/VV_hidden() + . = ..() | protected_lists + +/datum/controller/subsystem/secrets/Recover(var/datum/controller/subsystem/secrets/S) + + // No point reloading references. + retrieved_secrets = S.retrieved_secrets + secrets_by_key = S.secrets_by_key + secrets_by_category = S.secrets_by_category + + // In case someone purges it and it hasn't set SSsecrets yet. No idea if this can happen. + S.retrieved_secrets = list() + S.secrets_by_key = list() + S.secrets_by_category = list() + + . = ..() + +// Copied from customitems loading; scrapes entire file tree for json files. +/datum/controller/subsystem/secrets/Initialize() + + // Prune non-existent directories. + for(var/directory in load_directories) + if(!fexists(directory)) + log_warning("Invalid or non-existent directory [directory] during secret content load.") + load_directories -= directory + + // Kick off content load. + load_content() + + . = ..() + +/datum/controller/subsystem/secrets/proc/load_content(var/nuke_existing = FALSE) + + // Admin verb will destroy existing secrets and reload. + if(nuke_existing) + retrieved_secrets = list() + secrets_by_category = list() + for(var/secret_key in secrets_by_key) + qdel(secrets_by_key[secret_key]) + secrets_by_key = list() + + if(!length(load_directories)) + report_progress("Could not find any secret content directories; no secret content will be available this run.") + return + + var/list/loaded_directories = list() + var/list/directories_to_check = load_directories.Copy() + while(length(directories_to_check)) + + // What's our next dir to check? + var/checkdir = directories_to_check[1] + directories_to_check -= checkdir + + // Ignore directories we've seen before (loops) and the example dir. + if((checkdir in loaded_directories) || copytext(checkdir, -8) == "example/") + continue + + // Scrape the directory for files. + loaded_directories |= checkdir + for(var/relative_checkfile in flist(checkdir)) + + // flist() returns relative filenames rather than the full directory we're looking at. + var/checkfile = "[checkdir][relative_checkfile]" + + // Directories just get noted down for later scraping. + if(copytext(checkfile, -1) == "/") + // Should hopefully prevent symlinks or recursive file structures breaking. + if(!(checkfile in loaded_directories)) + directories_to_check |= checkfile + continue + + // If this is a .bak or something, ignore it. + if(lowertext(copytext(relative_checkfile, 1, 8)) != "secret_" || lowertext(copytext(checkfile, -5)) != ".json") + continue + + // Load, validate and create the secret. + var/list/loaded_data = cached_json_decode(safe_file2text(checkfile)) + if(!length(loaded_data)) + log_warning("Invalid or empty json loaded from [checkfile]!") + continue + + var/secret_key = loaded_data["secret_key"] + if(!istext(secret_key)) + log_warning("Undefined or invalid secret_key in [checkfile] ([isnull(secret_key) ? "NULL" : secret_key])!") + continue + secret_key = trim(lowertext(sanitize(secret_key))) + if(!length(secret_key)) + log_warning("Zero-length post-sanitize secret key in [checkfile]!") + continue + if(secrets_by_key[secret_key]) + log_warning("Duplicate secret_key [secret_key] in [checkfile]!") + continue + + // Validate the path. + var/datum_path = text2path(loaded_data["path"]) + if(!ispath(datum_path)) + log_warning("Invalid or empty datum path ([datum_path || "NULL"]) loaded from [checkfile]!") + continue + var/checking_path_result = FALSE + for(var/checkpath in permitted_paths) + if(ispath(datum_path, checkpath)) + checking_path_result = TRUE + break + if(!checking_path_result) + log_warning("Non-permitted path ([datum_path]) loaded from [checkfile]!") + continue + checking_path_result = FALSE + for(var/checkpath in forbidden_paths) + if(ispath(datum_path, checkpath)) + checking_path_result = TRUE + break + if(checking_path_result) + log_warning("Forbidden path ([datum_path]) loaded from [checkfile]!") + continue + + for(var/checkpath in dangerous_paths) + if(ispath(datum_path, checkpath)) + // Not a dealbreaker, but something that should be logged for reference. + to_world_log("## SECRETS ##: Dangerous type [datum_path] instanced from [checkfile] with payload '[json_encode(loaded_data)]'.") + break + + // Set our metadata (used in theory by secrets like map templates or things loading icons/text files from a directory). + if(loaded_data["_source_dir"]) + log_warning("Double-setting of _source_dir field in loaded secret from [checkfile]!") + loaded_data["_source_dir"] = checkdir + if(loaded_data["_source_file"]) + log_warning("Double-setting of _source_file field in loaded secret from [checkfile]!") + loaded_data["_source_file"] = relative_checkfile + + // Store the loaded secret in our cache + var/datum/secret = new datum_path(loaded_data) + secrets_by_key[secret_key] = secret + + var/list/cats = loaded_data["secret_categories"] || list() + if(loaded_data["secret_category"]) + cats |= loaded_data["secret_category"] + + for(var/cat in cats) // :3 + + if(!istext(cat)) + log_warning("Invalid category string '[cat]' supplied in [checkfile].") + continue + + var/unclean_cat = cat // :33 + cat = lowertext(sanitize(trim(cat))) + if(!length(cat)) + log_warning("Post-sanitize zero-length category string '[unclean_cat]' supplied in [checkfile].") + continue + + LAZYDISTINCTADD(secrets_by_category[cat], secret) + + var/dir_count = length(loaded_directories) + var/cat_count = length(secrets_by_category) + report_progress("Loaded [length(secrets_by_key)] secret\s, across [cat_count] categor[cat_count == 1 ? "y" : "ies"], from [dir_count] director[dir_count == 1 ? "y" : "ies"].") + +/datum/controller/subsystem/secrets/proc/retrieve_random_secret(var/secret_cat, var/prune_already_retrieved = FALSE, var/expected_path) + + secret_cat = trim(lowertext(sanitize(secret_cat))) // Groom the cat. + + // Get all possibilities, and copy to avoid mutating the cache. + var/list/cat_secrets = retrieve_secrets_by_category(secret_cat) + if(!length(cat_secrets)) + return null + + // If we're not pruning options, then this is ez pz. + if(!prune_already_retrieved) + . = pick(cat_secrets) + else + // If we're going for a round robin no-duplicates approach, prune out already-retrieved secrets. + var/list/available_secrets = cat_secrets?.Copy() || list() + if(length(retrieved_secrets[secret_cat])) + available_secrets -= retrieved_secrets[secret_cat] + // If we have no available secrets after pruning, kill the retrieved list and start over. + if(!length(available_secrets)) + available_secrets = cat_secrets + retrieved_secrets -= secret_cat + . = pick(available_secrets) + + // If we're returning a secret, mark it as retrieved for next time. + if(.) + LAZYDISTINCTADD(retrieved_secrets[secret_cat], .) + . = validate_secret(secret_cat, ., expected_path, "category") + +/datum/controller/subsystem/secrets/proc/retrieve_secrets_by_category(var/secret_cat) + . = secrets_by_category[trim(lowertext(sanitize(secret_cat)))] + +/datum/controller/subsystem/secrets/proc/retrieve_secret(var/secret_key, var/expected_path) + secret_key = trim(lowertext(sanitize(secret_key))) + . = validate_secret(secret_key, secrets_by_key[secret_key], expected_path) + +/datum/controller/subsystem/secrets/proc/validate_secret(var/secret_key, var/datum/secret, var/expected_path, var/key_string = "key") + if(isnull(secret)) + PRINT_STACK_TRACE("Could not find a loaded secret for secret [key_string] [secret_key]!") + else if(!istype(secret)) + PRINT_STACK_TRACE("Non-datum/invalid secret loaded for secret [key_string] [secret_key]!") + else if(expected_path && !istype(secret, expected_path)) + PRINT_STACK_TRACE("Secret for [key_string] [secret_key] was expected to be type [expected_path], instead was [secret.type].") + return secret + +// Simple proc for caching/retrieving files, generally icons, for secrets. +/datum/controller/subsystem/secrets/proc/get_file(var/file_location) + if(!file_cache[file_location]) + try + file_cache[file_location] = file(file_location) + catch(var/exception/e) + error("SSsecrets get_file caught exception: [EXCEPTION_TEXT(e)]") + return file_cache[file_location] diff --git a/code/controllers/subsystems/initialization/webhooks.dm b/code/controllers/subsystems/initialization/webhooks.dm index 1a9d27942178..c773998c9ba5 100644 --- a/code/controllers/subsystems/initialization/webhooks.dm +++ b/code/controllers/subsystems/initialization/webhooks.dm @@ -1,6 +1,6 @@ SUBSYSTEM_DEF(webhooks) name = "Webhooks" - init_order = SS_INIT_EARLY + init_order = SS_INIT_WEBHOOKS flags = SS_NO_FIRE var/list/webhook_decls = list() @@ -22,23 +22,33 @@ SUBSYSTEM_DEF(webhooks) all_webhooks_by_id[webhook.id] = webhook webhook_decls.Cut() - var/webhook_config = return_file_text("config/webhooks.json") + var/webhook_config = safe_file2text("config/webhooks.json") if(webhook_config) for(var/webhook_data in cached_json_decode(webhook_config)) var/wid = webhook_data["id"] var/wurl = webhook_data["url"] - var/wmention = webhook_data["mentions"] + var/list/wmention = webhook_data["mentions"] + if(wmention && !islist(wmention)) + wmention = list(wmention) to_world_log("Setting up webhook [wid].") if(wid && wurl && all_webhooks_by_id[wid]) var/decl/webhook/webhook = all_webhooks_by_id[wid] webhook.urls = islist(wurl) ? wurl : list(wurl) + for(var/url in webhook.urls) + if(!webhook.urls[url]) + webhook.urls[url] = list() + else if(!islist(webhook.urls[url])) + webhook.urls[url] = list(webhook.urls[url]) if(wmention) - webhook.mentions = jointext(wmention, ", ") + webhook.mentions = wmention?.Copy() webhook_decls[wid] = webhook to_world_log("Webhook [wid] ready.") else to_world_log("Failed to set up webhook [wid].") +/datum/controller/subsystem/webhooks/proc/is_webhook_configured(wid) + return isnull(webhook_decls[wid]) + /datum/controller/subsystem/webhooks/proc/send(var/wid, var/wdata) var/decl/webhook/webhook = webhook_decls[wid] if(webhook) @@ -72,7 +82,7 @@ SUBSYSTEM_DEF(webhooks) return if(!length(SSwebhooks.webhook_decls)) - to_chat(usr, "Webhook list is empty; either webhooks are disabled, webhooks aren't configured, or the subsystem hasn't initialized.") + to_chat(usr, SPAN_WARNING("Webhook list is empty; either webhooks are disabled, webhooks aren't configured, or the subsystem hasn't initialized.")) return var/choice = input(usr, "Select a webhook to ping.", "Ping Webhook") as null|anything in SSwebhooks.webhook_decls @@ -81,7 +91,3 @@ SUBSYSTEM_DEF(webhooks) log_and_message_admins("has pinged webhook [choice].", usr) to_world_log("[usr.key] has pinged webhook [choice].") webhook.send() - -/hook/roundstart/proc/run_webhook() - SSwebhooks.send(WEBHOOK_ROUNDSTART, list("url" = get_world_url())) - return 1 diff --git a/code/controllers/subsystems/input.dm b/code/controllers/subsystems/input.dm new file mode 100644 index 000000000000..833eec99b36f --- /dev/null +++ b/code/controllers/subsystems/input.dm @@ -0,0 +1,31 @@ +SUBSYSTEM_DEF(input) + name = "Input" + wait = 1 //SS_TICKER means this runs every tick + init_order = SS_INIT_INPUT + flags = SS_TICKER + priority = SS_PRIORITY_INPUT + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + + var/list/macro_set + +/datum/controller/subsystem/input/Initialize() + setup_default_macro_sets() + refresh_client_macro_sets() + return ..() + +// This is for when macro sets are eventualy datumized +/datum/controller/subsystem/input/proc/setup_default_macro_sets() + macro_set = list( + "Any" = "\"KeyDown \[\[*\]\]\"", + "Any+UP" = "\"KeyUp \[\[*\]\]\"", + "Back" = "\".winset \\\"outputwindow.input.text=\\\"\\\"\\\"\"" + ) + +// Badmins just wanna have fun ♪ +/datum/controller/subsystem/input/proc/refresh_client_macro_sets() + for(var/client/C in global.clients) + C.set_macros() + +/datum/controller/subsystem/input/fire() + for(var/client/C in global.clients) + C.keyLoop() diff --git a/code/controllers/subsystems/item_effects.dm b/code/controllers/subsystems/item_effects.dm new file mode 100644 index 000000000000..8cdf21f16593 --- /dev/null +++ b/code/controllers/subsystems/item_effects.dm @@ -0,0 +1,23 @@ +SUBSYSTEM_DEF(item_effects) + name = "Weapon Effects" + wait = 2 SECONDS + priority = SS_PRIORITY_ITEM_EFFECTS + flags = SS_NO_INIT + var/list/queued_items = list() + var/list/processing_items + +/datum/controller/subsystem/item_effects/stat_entry() + ..("P:[queued_items.len]") + +/datum/controller/subsystem/item_effects/fire(resumed = 0) + if(!resumed) + processing_items = queued_items.Copy() + var/obj/item/current_item + var/i = 0 + while(i < processing_items.len) + i++ + current_item = processing_items[i] + current_item.process_item_effects() + if(MC_TICK_CHECK) + processing_items.Cut(1, i+1) + return diff --git a/code/controllers/subsystems/jobs.dm b/code/controllers/subsystems/jobs.dm index 57a56fe54a41..886d58c7a9c1 100644 --- a/code/controllers/subsystems/jobs.dm +++ b/code/controllers/subsystems/jobs.dm @@ -3,35 +3,51 @@ SUBSYSTEM_DEF(jobs) init_order = SS_INIT_JOBS flags = SS_NO_FIRE - var/list/archetype_job_datums = list() - var/list/job_lists_by_map_name = list() - var/list/titles_to_datums = list() - var/list/types_to_datums = list() - var/list/primary_job_datums = list() - var/list/unassigned_roundstart = list() - var/list/positions_by_department = list() - var/list/job_icons = list() - var/job_config_file = "config/jobs.txt" + var/list/archetype_job_datums = list() + var/list/job_lists_by_map_name = list() + var/list/titles_to_datums = list() + var/list/types_to_datums = list() + var/list/primary_job_datums = list() + var/list/unassigned_roundstart = list() + var/list/positions_by_department = list() + var/list/job_icons = list() var/list/must_fill_titles = list() + var/list/departments_by_type = list() + var/list/departments_by_name = list() + var/job_config_file = "config/jobs.txt" + +/datum/controller/subsystem/jobs/proc/get_department_by_name(var/dept_name) + if(!length(departments_by_name)) + var/list/all_depts = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dtype in all_depts) + var/decl/department/dept = all_depts[dtype] + departments_by_name[lowertext(dept.name)] = dept + . = departments_by_name[lowertext(dept_name)] + +/datum/controller/subsystem/jobs/proc/get_department_by_type(var/dept_ref) + if(!length(departments_by_type)) + departments_by_type = sortTim(decls_repository.get_decls_of_type(/decl/department), /proc/cmp_departments_dsc, TRUE) + . = departments_by_type[dept_ref] /datum/controller/subsystem/jobs/Initialize(timeofday) // Create main map jobs. primary_job_datums.Cut() - for(var/jobtype in (list(DEFAULT_JOB_TYPE) | GLOB.using_map.allowed_jobs)) + var/list/available_jobs = global.using_map.allowed_jobs.Copy() + if(global.using_map.default_job_type) + LAZYDISTINCTADD(available_jobs, global.using_map.default_job_type) + for(var/jobtype in available_jobs) var/datum/job/job = get_by_path(jobtype) if(!job) job = new jobtype primary_job_datums += job - for(var/datum/job/job in primary_job_datums) - if(isnull(job.primary_department)) - job.primary_department = job.department_refs[1] - // Create abstract submap archetype jobs for use in prefs, etc. archetype_job_datums.Cut() - for(var/atype in SSmapping.submap_archetypes) - var/decl/submap_archetype/arch = SSmapping.submap_archetypes[atype] + + var/list/submap_archetypes = list() + for(var/decl/submap_archetype/arch as anything in global.using_map.get_available_submap_archetypes()) + submap_archetypes += arch for(var/jobtype in arch.crew_jobs) var/datum/job/job = get_by_path(jobtype) if(!job && ispath(jobtype, /datum/job/submap)) @@ -41,9 +57,11 @@ SUBSYSTEM_DEF(jobs) job = get_by_path(jobtype) if(job) archetype_job_datums |= job + if(length(submap_archetypes)) + submap_archetypes = sortTim(submap_archetypes, /proc/cmp_submap_archetype_asc) // Load job configuration (is this even used anymore?) - if(job_config_file && config.load_jobs_from_txt) + if(job_config_file && get_config_value(/decl/config/toggle/load_jobs_from_txt)) var/list/jobEntries = file2list(job_config_file) for(var/job in jobEntries) if(!job) @@ -61,32 +79,31 @@ SUBSYSTEM_DEF(jobs) if(J) J.total_positions = text2num(value) J.spawn_positions = text2num(value) - if(name == "AI" || name == "Robot")//I dont like this here but it will do for now + if((ASSIGNMENT_ROBOT in J.event_categories) || (ASSIGNMENT_COMPUTER in J.event_categories)) J.total_positions = 0 - // Init skills. - if(!GLOB.skills.len) - decls_repository.get_decl(/decl/hierarchy/skill) - if(!GLOB.skills.len) + if(!length(global.using_map.get_available_skills())) log_error("Error setting up job skill requirements, no skill datums found!") // Update title and path tracking, submap list, etc. // Populate/set up map job lists. - job_lists_by_map_name = list("[GLOB.using_map.full_name]" = list("jobs" = primary_job_datums, "default_to_hidden" = FALSE)) + if(length(primary_job_datums)) + primary_job_datums = sortTim(primary_job_datums, /proc/cmp_job_desc) + job_lists_by_map_name = list("[global.using_map.full_name]" = list("jobs" = primary_job_datums, "default_to_hidden" = FALSE)) - for(var/atype in SSmapping.submap_archetypes) + for(var/decl/submap_archetype/arch as anything in submap_archetypes) var/list/submap_job_datums - var/decl/submap_archetype/arch = SSmapping.submap_archetypes[atype] for(var/jobtype in arch.crew_jobs) var/datum/job/job = get_by_path(jobtype) if(job) LAZYADD(submap_job_datums, job) if(LAZYLEN(submap_job_datums)) - job_lists_by_map_name[arch.descriptor] = list("jobs" = submap_job_datums, "default_to_hidden" = TRUE) + submap_job_datums = sortTim(submap_job_datums, /proc/cmp_job_desc) + job_lists_by_map_name[arch.name] = list("jobs" = submap_job_datums, "default_to_hidden" = arch.default_to_hidden) // Update global map blacklists and whitelists. - for(var/mappath in GLOB.all_maps) - var/datum/map/M = GLOB.all_maps[mappath] + for(var/mappath in global.all_maps) + var/datum/map/M = global.all_maps[mappath] M.setup_job_lists() // Update valid job titles. @@ -103,18 +120,16 @@ SUBSYSTEM_DEF(jobs) titles_to_datums[alt_title] = job if(job.must_fill) must_fill_titles += job.title - if(job.department_refs) - for(var/dept_ref in job.department_refs) - if(dept_ref in SSdepartments.departments) - LAZYDISTINCTADD(positions_by_department[dept_ref], job.title) + if(job.department_types) + for(var/dept_ref in job.department_types) + var/decl/department/dept = SSjobs.get_department_by_type(dept_ref) + if(dept) + LAZYDISTINCTADD(positions_by_department[dept.type], job.title) // Set up syndicate phrases. syndicate_code_phrase = generate_code_phrase() syndicate_code_response = generate_code_phrase() - // Set up AI spawn locations - spawn_empty_ai() - . = ..() /datum/controller/subsystem/jobs/proc/guest_jobbans(var/job) @@ -125,11 +140,11 @@ SUBSYSTEM_DEF(jobs) /datum/controller/subsystem/jobs/proc/reset_occupations() - for(var/mob/new_player/player in GLOB.player_list) + for(var/mob/new_player/player in global.player_list) if((player) && (player.mind)) player.mind.assigned_job = null player.mind.assigned_role = null - player.mind.special_role = null + player.mind.assigned_special_role = null for(var/datum/job/job in primary_job_datums) job.current_positions = 0 unassigned_roundstart = list() @@ -141,6 +156,12 @@ SUBSYSTEM_DEF(jobs) RETURN_TYPE(/datum/job) return types_to_datums[path] +/datum/controller/subsystem/jobs/proc/get_by_paths(var/paths) + RETURN_TYPE(/list) + . = list() + for(var/path in paths) + . += types_to_datums[path] + /datum/controller/subsystem/jobs/proc/check_general_join_blockers(var/mob/new_player/joining, var/datum/job/job) if(!istype(joining) || !joining.client || !joining.client.prefs) return FALSE @@ -150,7 +171,7 @@ SUBSYSTEM_DEF(jobs) if(!job.is_position_available()) to_chat(joining, "Unfortunately, that job is no longer available.") return FALSE - if(!config.enter_allowed) + if(!get_config_value(/decl/config/toggle/on/enter_allowed)) to_chat(joining, "There is an administrative lock on entering the game!") return FALSE if(SSticker.mode && SSticker.mode.station_explosion_in_progress) @@ -161,7 +182,7 @@ SUBSYSTEM_DEF(jobs) /datum/controller/subsystem/jobs/proc/check_latejoin_blockers(var/mob/new_player/joining, var/datum/job/job) if(!check_general_join_blockers(joining, job)) return FALSE - if(job.minimum_character_age && (joining.client.prefs.age < job.minimum_character_age)) + if(job.minimum_character_age && (joining.client.prefs.get_character_age() < job.minimum_character_age)) to_chat(joining, "Your character's in-game age is too low for this job.") return FALSE if(!job.player_old_enough(joining.client)) @@ -186,7 +207,7 @@ SUBSYSTEM_DEF(jobs) log_and_message_admins("User [spawner] spawned at spawn point with dangerous atmosphere.") return TRUE -/datum/controller/subsystem/jobs/proc/assign_role(var/mob/new_player/player, var/rank, var/latejoin = 0, var/datum/game_mode/mode = SSticker.mode) +/datum/controller/subsystem/jobs/proc/assign_role(var/mob/new_player/player, var/rank, var/latejoin = 0, var/decl/game_mode/mode = SSticker.mode) if(player && player.mind && rank) var/datum/job/job = get_by_title(rank) if(!job) @@ -219,7 +240,7 @@ SUBSYSTEM_DEF(jobs) continue if(!job.player_old_enough(player.client)) continue - if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) + if(job.minimum_character_age && (player.client.prefs.get_character_age() < job.minimum_character_age)) continue if(flag && !(flag in player.client.prefs.be_special_role)) continue @@ -227,13 +248,13 @@ SUBSYSTEM_DEF(jobs) candidates += player return candidates -/datum/controller/subsystem/jobs/proc/give_random_job(var/mob/new_player/player, var/datum/game_mode/mode = SSticker.mode) +/datum/controller/subsystem/jobs/proc/give_random_job(var/mob/new_player/player, var/decl/game_mode/mode = SSticker.mode) for(var/datum/job/job in shuffle(primary_job_datums)) if(!job) continue - if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) + if(job.minimum_character_age && (player.client.prefs.get_character_age() < job.minimum_character_age)) continue - if(istype(job, get_by_title(GLOB.using_map.default_assistant_title))) // We don't want to give him assistant, that's boring! + if(istype(job, get_by_title(global.using_map.default_job_title))) // We don't want to give him assistant, that's boring! continue if(job.is_restricted(player.client.prefs)) continue @@ -251,7 +272,7 @@ SUBSYSTEM_DEF(jobs) break ///This proc is called before the level loop of divide_occupations() and will try to select a head, ignoring ALL non-head preferences for every level until it locates a head or runs out of levels to check -/datum/controller/subsystem/jobs/proc/fill_head_position(var/datum/game_mode/mode) +/datum/controller/subsystem/jobs/proc/fill_head_position(var/decl/game_mode/mode) for(var/level = 1 to 3) for(var/command_position in must_fill_titles) var/datum/job/job = get_by_title(command_position) @@ -263,19 +284,20 @@ SUBSYSTEM_DEF(jobs) for(var/mob/V in candidates) // Log-out during round-start? What a bad boy, no head position for you! if(!V.client) continue - var/age = V.client.prefs.age + var/age = V.client.prefs.get_character_age() if(age < job.minimum_character_age) // Nope. continue - switch(age) - if(job.minimum_character_age to (job.minimum_character_age+10)) - weightedCandidates[V] = 3 // Still a bit young. - if((job.minimum_character_age+10) to (job.ideal_character_age-10)) - weightedCandidates[V] = 6 // Better. - if((job.ideal_character_age-10) to (job.ideal_character_age+10)) + switch(age - job.ideal_character_age) + if(-INFINITY to -10) + if(age < (job.minimum_character_age+10)) + weightedCandidates[V] = 3 // Still a bit young. + else + weightedCandidates[V] = 6 // Better. + if(-10 to 10) weightedCandidates[V] = 10 // Great. - if((job.ideal_character_age+10) to (job.ideal_character_age+20)) + if(10 to 20) weightedCandidates[V] = 6 // Still good. - if((job.ideal_character_age+20) to INFINITY) + if(20 to INFINITY) weightedCandidates[V] = 3 // Geezer. else // If there's ABSOLUTELY NOBODY ELSE @@ -286,7 +308,7 @@ SUBSYSTEM_DEF(jobs) return 0 ///This proc is called at the start of the level loop of divide_occupations() and will cause head jobs to be checked before any other jobs of the same level -/datum/controller/subsystem/jobs/proc/CheckHeadPositions(var/level, var/datum/game_mode/mode) +/datum/controller/subsystem/jobs/proc/CheckHeadPositions(var/level, var/decl/game_mode/mode) for(var/command_position in must_fill_titles) var/datum/job/job = get_by_title(command_position) if(!job) continue @@ -299,24 +321,26 @@ SUBSYSTEM_DEF(jobs) * fills var "assigned_role" for all ready players. * This proc must not have any side effect besides of modifying "assigned_role". **/ -/datum/controller/subsystem/jobs/proc/divide_occupations(datum/game_mode/mode) - if(GLOB.triai) +/datum/controller/subsystem/jobs/proc/divide_occupations(decl/game_mode/mode) + if(global.triai) for(var/datum/job/A in primary_job_datums) if(A.title == "AI") A.spawn_positions = 3 break //Get the players who are ready - for(var/mob/new_player/player in GLOB.player_list) + for(var/mob/new_player/player in global.player_list) if(player.ready && player.mind && !player.mind.assigned_role) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(player)) + continue unassigned_roundstart += player if(unassigned_roundstart.len == 0) return 0 //Shuffle players and jobs unassigned_roundstart = shuffle(unassigned_roundstart) //People who wants to be assistants, sure, go on. - var/datum/job/assist = new DEFAULT_JOB_TYPE () + var/datum/job/assist = new global.using_map.default_job_type () var/list/assistant_candidates = find_occupation_candidates(assist, 3) for(var/mob/new_player/player in assistant_candidates) - assign_role(player, GLOB.using_map.default_assistant_title, mode = mode) + assign_role(player, global.using_map.default_job_title, mode = mode) assistant_candidates -= player //Select one head @@ -361,72 +385,67 @@ SUBSYSTEM_DEF(jobs) // For those who wanted to be assistant if their preferences were filled, here you go. for(var/mob/new_player/player in unassigned_roundstart) if(player.client.prefs.alternate_option == BE_ASSISTANT) - var/datum/job/ass = DEFAULT_JOB_TYPE - if((GLOB.using_map.flags & MAP_HAS_BRANCH) && player.client.prefs.branches[initial(ass.title)]) - var/datum/mil_branch/branch = mil_branches.get_branch(player.client.prefs.branches[initial(ass.title)]) + var/datum/job/ass = global.using_map.default_job_type + if((global.using_map.flags & MAP_HAS_BRANCH) && player.client.prefs.branches[initial(ass.title)]) + var/datum/mil_branch/branch = global.using_map.get_branch(player.client.prefs.branches[initial(ass.title)]) ass = branch.assistant_job assign_role(player, initial(ass.title), mode = mode) //For ones returning to lobby for(var/mob/new_player/player in unassigned_roundstart) if(player.client.prefs.alternate_option == RETURN_TO_LOBBY) player.ready = 0 - player.new_player_panel() + player.show_lobby_menu() unassigned_roundstart -= player return TRUE -/datum/controller/subsystem/jobs/proc/attempt_role_assignment(var/mob/new_player/player, var/datum/job/job, var/level, var/datum/game_mode/mode) - if(!jobban_isbanned(player, job.title) && \ - job.player_old_enough(player.client) && \ - player.client.prefs.CorrectLevel(job, level) && \ - job.is_position_available()) - assign_role(player, job.title, mode = mode) - return TRUE - return FALSE +/datum/controller/subsystem/jobs/proc/attempt_role_assignment(var/mob/new_player/player, var/datum/job/job, var/level, var/decl/game_mode/mode) + if(jobban_isbanned(player, job.title)) + return FALSE + if(!job.player_old_enough(player.client)) + return FALSE + if(!player.client.prefs.CorrectLevel(job, level)) + return FALSE + if(!job.is_position_available()) + return FALSE + assign_role(player, job.title, mode = mode) + return TRUE -/datum/controller/subsystem/jobs/proc/equip_custom_loadout(var/mob/living/carbon/human/H, var/datum/job/job) +/decl/loadout_option/proc/is_permitted(mob/living/wearer, datum/job/job) + if(!istype(wearer)) + return FALSE + if(allowed_roles && (!job || !(job.type in allowed_roles))) + return FALSE + if(allowed_branches) + if(!ishuman(wearer)) + return FALSE + var/mob/living/human/wearer_human = wearer + if(!wearer_human.char_branch || !(wearer_human.char_branch.type in allowed_branches)) + return FALSE + if(allowed_skills) + for(var/required in allowed_skills) + if(!wearer.skill_check(required, allowed_skills[required])) + return FALSE + if(whitelisted && (!(wearer.get_species()?.uid in whitelisted))) + return FALSE + return TRUE + +/datum/controller/subsystem/jobs/proc/equip_custom_loadout(var/mob/living/human/H, var/datum/job/job) if(!H || !H.client) return // Equip custom gear loadout, replacing any job items var/list/spawn_in_storage = list() - var/list/loadout_taken_slots = list() if(H.client.prefs.Gear() && job.loadout_allowed) for(var/thing in H.client.prefs.Gear()) - var/datum/gear/G = gear_datums[thing] - if(G) - var/permitted = 0 - if(G.allowed_branches) - if(H.char_branch && (H.char_branch.type in G.allowed_branches)) - permitted = 1 - else - permitted = 1 - - if(permitted) - if(G.allowed_roles) - if(job.type in G.allowed_roles) - permitted = 1 - else - permitted = 0 - else - permitted = 1 - - if(permitted && G.allowed_skills) - for(var/required in G.allowed_skills) - if(!H.skill_check(required,G.allowed_skills[required])) - permitted = 0 - - if(G.whitelisted && (!(H.species.name in G.whitelisted))) - permitted = 0 - - if(!permitted) - to_chat(H, "Your current species, job, branch, skills or whitelist status does not permit you to spawn with [thing]!") - continue - - if(!G.slot || G.slot == slot_tie || (G.slot in loadout_taken_slots) || !G.spawn_on_mob(H, H.client.prefs.Gear()[G.display_name])) - spawn_in_storage.Add(G) - else - loadout_taken_slots.Add(G.slot) + var/decl/loadout_option/gear = decls_repository.get_decl_by_id_or_var(thing, /decl/loadout_option) + if(!istype(gear)) + continue + if(!gear.is_permitted(H, job)) + to_chat(H, SPAN_WARNING("Your current species, job, branch, skills or whitelist status does not permit you to spawn with [gear.name]!")) + continue + if(!gear.slot || !gear.spawn_on_mob(H, H.client.prefs.Gear()[gear.uid])) + spawn_in_storage.Add(gear) // do accessories last so they don't attach to a suit that will be replaced if(H.char_rank && H.char_rank.accessory) @@ -437,63 +456,61 @@ SUBSYSTEM_DEF(jobs) var/list/accessory_args = accessory_data.Copy() accessory_args[1] = src for(var/i in 1 to amt) - H.equip_to_slot_or_del(new accessory_path(arglist(accessory_args)), slot_tie) + var/obj/item/accessory = new accessory_path(arglist(accessory_args)) + H.equip_to_slot_or_del(accessory, accessory.get_fallback_slot()) else for(var/i in 1 to (isnull(accessory_data)? 1 : accessory_data)) - H.equip_to_slot_or_del(new accessory_path(src), slot_tie) + var/obj/item/accessory = new accessory_path(src) + H.equip_to_slot_or_del(accessory, accessory.get_fallback_slot()) return spawn_in_storage -/datum/controller/subsystem/jobs/proc/equip_rank(var/mob/living/carbon/human/H, var/rank, var/joined_late = 0) +/datum/controller/subsystem/jobs/proc/equip_job_title(var/mob/living/human/H, var/job_title, var/joined_late = 0) if(!H) return - var/datum/job/job = get_by_title(rank) + var/datum/job/job = get_by_title(job_title) var/list/spawn_in_storage if(job) if(H.client) - if(GLOB.using_map.flags & MAP_HAS_BRANCH) - H.char_branch = mil_branches.get_branch(H.client.prefs.branches[rank]) - if(GLOB.using_map.flags & MAP_HAS_RANK) - H.char_rank = mil_branches.get_rank(H.client.prefs.branches[rank], H.client.prefs.ranks[rank]) + if(global.using_map.flags & MAP_HAS_BRANCH) + H.char_branch = global.using_map.get_branch(H.client.prefs.branches[job_title]) + if(global.using_map.flags & MAP_HAS_RANK) + H.char_rank = global.using_map.get_rank(H.client.prefs.branches[job_title], H.client.prefs.ranks[job_title]) // Transfers the skill settings for the job to the mob H.skillset.obtain_from_client(job, H.client) //Equip job items. + job.equip_job(H, H.mind?.role_alt_title, H.char_branch, H.char_rank) job.setup_account(H) - - job.equip(H, H.mind ? H.mind.role_alt_title : "", H.char_branch, H.char_rank) job.apply_fingerprints(H) spawn_in_storage = equip_custom_loadout(H, job) else - to_chat(H, "Your job is [rank] and the game just can't handle it! Please report this bug to an administrator.") + to_chat(H, "Your job is [job_title] and the game just can't handle it! Please report this bug to an administrator.") - H.job = rank + H.job = job_title if(!joined_late || job.latejoin_at_spawnpoints) var/obj/S = job.get_roundstart_spawnpoint() - if(istype(S, /obj/effect/landmark/start) && istype(S.loc, /turf)) + if(istype(S, /obj/abstract/landmark/start) && isturf(S.loc)) H.forceMove(S.loc) else - var/datum/spawnpoint/spawnpoint = job.get_spawnpoint(H.client) - H.forceMove(pick(spawnpoint.turfs)) + var/decl/spawnpoint/spawnpoint = job.get_spawnpoint(H.client) + H.forceMove(DEFAULTPICK(spawnpoint.get_spawn_turfs(H), get_random_spawn_turf(SPAWN_FLAG_JOBS_CAN_SPAWN))) spawnpoint.after_join(H) // Moving wheelchair if they have one - if(H.buckled && istype(H.buckled, /obj/structure/bed/chair/wheelchair)) + if(H.buckled && istype(H.buckled, /obj/structure/chair/wheelchair)) H.buckled.forceMove(H.loc) H.buckled.set_dir(H.dir) - if(rank != "Robot" && rank != "AI") //These guys get their emails later. - var/domain = "freemail.net" - if(H.char_branch?.email_domain) - domain = H.char_branch.email_domain + if(!(ASSIGNMENT_ROBOT in job.event_categories) && !(ASSIGNMENT_COMPUTER in job.event_categories)) //These guys get their emails later. var/datum/computer_network/network = get_local_network_at(get_turf(H)) if(network) - network.create_email(H, H.real_name, domain, rank) + network.create_account(H, H.real_name, null, H.real_name, null, TRUE) // If they're head, give them the account info for their department if(H.mind && job.head_position) @@ -508,47 +525,47 @@ SUBSYSTEM_DEF(jobs) H.StoreMemory(remembered_info, /decl/memory_options/system) var/alt_title = null - if(H.mind) - H.mind.assigned_job = job - H.mind.assigned_role = rank - alt_title = H.mind.role_alt_title + if(!H.mind) + H.mind_initialize() + H.mind.assigned_job = job + H.mind.assigned_role = job_title + alt_title = H.mind.role_alt_title var/mob/other_mob = job.handle_variant_join(H, alt_title) if(other_mob) - job.post_equip_rank(other_mob, alt_title || rank) + job.post_equip_job_title(other_mob, alt_title || job_title) return other_mob if(spawn_in_storage) - for(var/datum/gear/G in spawn_in_storage) - G.spawn_in_storage_or_drop(H, H.client.prefs.Gear()[G.display_name]) + for(var/decl/loadout_option/gear in spawn_in_storage) + gear.spawn_in_storage_or_drop(H, H.client.prefs.Gear()[gear.uid]) - to_chat(H, "You are [job.total_positions == 1 ? "the" : "a"] [alt_title ? alt_title : rank].") + var/article = job.total_positions == 1 ? "the" : "a" + to_chat(H, "You are [article] [alt_title || job_title].") + + var/job_description = job.get_description_blurb() + if(job_description) + to_chat(H, SPAN_BOLD("[job_description]")) if(job.supervisors) - to_chat(H, "As the [alt_title ? alt_title : rank] you answer directly to [job.supervisors]. Special circumstances may change this.") + to_chat(H, "As [article] [alt_title || job_title] you answer directly to [job.supervisors]. Special circumstances may change this.") - to_chat(H, "To speak on your department's radio channel use :h. For the use of other channels, examine your headset.") + if(H.has_headset_in_ears()) + to_chat(H, "To speak on your department's radio channel use [H.get_department_radio_prefix()]h. For the use of other channels, examine your headset.") if(job.req_admin_notify) to_chat(H, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.") - //Gives glasses to the vision impaired - if(H.disabilities & NEARSIGHTED) - var/equipped = H.equip_to_slot_or_del(new /obj/item/clothing/glasses/prescription(H), slot_glasses) - if(equipped) - var/obj/item/clothing/glasses/G = H.glasses - G.prescription = 7 - - if(H.needs_wheelchair()) + if(H.cannot_stand()) equip_wheelchair(H) BITSET(H.hud_updateflag, ID_HUD) BITSET(H.hud_updateflag, IMPLOYAL_HUD) BITSET(H.hud_updateflag, SPECIALROLE_HUD) - job.post_equip_rank(H, alt_title || rank) + job.post_equip_job_title(H, alt_title || job_title) - INVOKE_ASYNC(GLOBAL_PROC, .proc/show_location_blurb, H.client, 30) + H.client.show_location_blurb(30) return H @@ -556,7 +573,7 @@ SUBSYSTEM_DEF(jobs) return positions_by_department[dept] || list() /datum/controller/subsystem/jobs/proc/spawn_empty_ai() - for(var/obj/effect/landmark/start/S in landmarks_list) + for(var/obj/abstract/landmark/start/S in global.all_landmarks) if(S.name != "AI") continue if(locate(/mob/living) in S.loc) @@ -564,12 +581,18 @@ SUBSYSTEM_DEF(jobs) empty_playable_ai_cores += new /obj/structure/aicore/deactivated(get_turf(S)) return 1 -/proc/show_location_blurb(client/C, duration) - set waitfor = 0 +/client/proc/show_location_blurb(duration) + set waitfor = FALSE + + var/location_name = station_name() + + var/obj/effect/overmap/visitable/V = mob.get_owning_overmap_object() + if(istype(V)) + location_name = V.name var/style = "font-family: 'Fixedsys'; -dm-text-outline: 1 black; font-size: 11px;" - var/area/A = get_area(C.mob) - var/text = "[stationdate2text()], [stationtime2text()]\n[station_name()], [A.name]" + var/area/A = get_area(mob) + var/text = "[stationdate2text()], [stationtime2text()]\n[location_name], [A.proper_name]" text = uppertext(text) var/obj/effect/overlay/T = new() @@ -580,16 +603,17 @@ SUBSYSTEM_DEF(jobs) T.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA T.screen_loc = "LEFT+1,BOTTOM+2" - C.screen += T + screen += T animate(T, alpha = 255, time = 10) - for(var/i = 1 to length(text)+1) - T.maptext = "[copytext(text,1,i)] " + for(var/i = 1 to length_char(text) + 1) + T.maptext = "[copytext_char(text, 1, i)] " sleep(1) - - addtimer(CALLBACK(GLOBAL_PROC, .proc/fade_location_blurb, C, T), duration) + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fade_location_blurb), src, T), duration) /proc/fade_location_blurb(client/C, obj/T) animate(T, alpha = 0, time = 5) sleep(5) - C.screen -= T - qdel(T) \ No newline at end of file + if(C) + C.screen -= T + qdel(T) diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm index f14e7f8c4d87..43e79dea97ef 100644 --- a/code/controllers/subsystems/lighting.dm +++ b/code/controllers/subsystems/lighting.dm @@ -1,105 +1,139 @@ -/var/lighting_overlays_initialised = FALSE - SUBSYSTEM_DEF(lighting) name = "Lighting" - wait = 1 + wait = LIGHTING_INTERVAL + priority = SS_PRIORITY_LIGHTING init_order = SS_INIT_LIGHTING + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY - // Queues of update counts, waiting to be rolled into stats lists - var/list/stats_queues = list( - "Source" = list(), - "Corner" = list(), - "Overlay" = list() - ) - // Stats lists - var/list/stats_lists = list( - "Source" = list(), - "Corner" = list(), - "Overlay" = list() - ) - var/update_stats_every = 1 SECOND - var/next_stats_update = 0 - var/stat_updates_to_keep = 5 + var/total_lighting_overlays = 0 + var/total_lighting_sources = 0 + var/total_ambient_turfs = 0 + var/total_lighting_corners = 0 - var/list/light_queue = list() // lighting sources queued for update. + /// lighting sources queued for update. + var/list/light_queue = list() var/lq_idex = 1 - var/list/corner_queue = list() // lighting corners queued for update. + /// lighting corners queued for update. + var/list/corner_queue = list() var/cq_idex = 1 - var/list/overlay_queue = list() // lighting overlays queued for update. + /// lighting overlays queued for update. + var/list/overlay_queue = list() var/oq_idex = 1 var/tmp/processed_lights = 0 var/tmp/processed_corners = 0 var/tmp/processed_overlays = 0 + var/total_ss_updates = 0 + var/total_instant_updates = 0 + +#ifdef USE_INTELLIGENT_LIGHTING_UPDATES + var/instant_ctr = 0 + var/force_queued = TRUE + /// For admins. + var/force_override = FALSE +#endif + /datum/controller/subsystem/lighting/stat_entry() - var/list/out = list("Queued:{L:[light_queue.len] C:[corner_queue.len] O:[overlay_queue.len]}") - for (var/stype in stats_lists) - out += "[stype] updates: [jointext(stats_lists[stype], " | ")]" + var/list/out = list( +#ifdef USE_INTELLIGENT_LIGHTING_UPDATES + "IUR: [total_ss_updates ? round(total_instant_updates/(total_instant_updates+total_ss_updates)*100, 0.1) : "NaN"]% Instant: [force_queued ? "Disabled" : "Allowed"]\n", +#endif + "\tT: { L: [total_lighting_sources] C: [total_lighting_corners] O:[total_lighting_overlays] A: [total_ambient_turfs] }\n", + "\tP: { L: [light_queue.len - (lq_idex - 1)] C: [corner_queue.len - (cq_idex - 1)] O: [overlay_queue.len - (oq_idex - 1)] }\n", + "\tL: { L: [processed_lights] C: [processed_corners] O: [processed_overlays]}\n" + ) + ..(out.Join()) + +// If intelligent updates are off, this is just an empty stub. +/datum/controller/subsystem/lighting/proc/handle_roundstart() +#ifdef USE_INTELLIGENT_LIGHTING_UPDATES + force_queued = FALSE + total_ss_updates = 0 + total_instant_updates = 0 + +/// Disable instant updates, relying entirely on the (slower, but less laggy) queued pathway. Use if changing a *lot* of lights. +/datum/controller/subsystem/lighting/proc/pause_instant() + if (force_override) + return + + instant_ctr += 1 + if (instant_ctr == 1) + force_queued = TRUE + +/// Resume instant updates. +/datum/controller/subsystem/lighting/proc/resume_instant() + if (force_override) + return + + instant_ctr = max(instant_ctr - 1, 0) - ..(out.Join("\n")) + if (!instant_ctr) + force_queued = FALSE -/datum/controller/subsystem/lighting/Initialize() - InitializeTurfs() - lighting_overlays_initialised = TRUE +#else + +/datum/controller/subsystem/lighting/proc/pause_instant() + +/datum/controller/subsystem/lighting/proc/resume_instant() + +#endif + +/datum/controller/subsystem/lighting/Initialize(timeofday) + var/overlaycount = 0 + var/starttime = REALTIMEOFDAY + + // Generate overlays. + for (var/zlevel = 1 to world.maxz) + var/datum/level_data/level = SSmapping.levels_by_z[zlevel] + for (var/turf/tile as anything in block(1, 1, zlevel, level.level_max_width, level.level_max_height)) // include TRANSITIONEDGE turfs + if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(tile)) + if(!isnull(tile.lighting_overlay)) + log_warning("Attempted to create lighting_overlay on [tile.get_log_info_line()] when it already had one.") + continue + new /atom/movable/lighting_overlay(tile) + overlaycount++ + CHECK_TICK + + admin_notice(SPAN_DANGER("Created [overlaycount] lighting overlays in [(REALTIMEOFDAY - starttime)/10] seconds."), R_DEBUG) + + starttime = REALTIMEOFDAY + // Tick once to clear most lights. fire(FALSE, TRUE) - ..() -// It's safe to pass a list of non-turfs to this list - it'll only check turfs. -/datum/controller/subsystem/lighting/proc/InitializeTurfs(list/targets) - for (var/turf/T in (targets || world)) - if (T.dynamic_lighting && T.loc:dynamic_lighting) - T.lighting_build_overlay() + admin_notice(SPAN_DANGER("Processed [processed_lights] light sources."), R_DEBUG) + admin_notice(SPAN_DANGER("Processed [processed_corners] light corners."), R_DEBUG) + admin_notice(SPAN_DANGER("Processed [processed_overlays] light overlays."), R_DEBUG) + admin_notice(SPAN_DANGER("Lighting pre-bake completed in [(REALTIMEOFDAY - starttime)/10] seconds."), R_DEBUG) - // If this isn't here, BYOND will set-background us. - CHECK_TICK + log_ss("lighting", "NOv:[overlaycount] L:[processed_lights] C:[processed_corners] O:[processed_overlays]") + + ..() /datum/controller/subsystem/lighting/fire(resumed = FALSE, no_mc_tick = FALSE) if (!resumed) - stats_queues["Source"] += processed_lights - stats_queues["Corner"] += processed_corners - stats_queues["Overlay"] += processed_overlays - processed_lights = 0 processed_corners = 0 processed_overlays = 0 - if(next_stats_update <= world.time) - next_stats_update = world.time + update_stats_every - for(var/stat_name in stats_queues) - var/stat_sum = 0 - var/list/stats_queue = stats_queues[stat_name] - for(var/count in stats_queue) - stat_sum += count - stats_queue.Cut() - - var/list/stats_list = stats_lists[stat_name] - stats_list.Insert(1, stat_sum) - if(stats_list.len > stat_updates_to_keep) - stats_list.Cut(stats_list.len) - MC_SPLIT_TICK_INIT(3) if (!no_mc_tick) MC_SPLIT_TICK - // Sources. - while (lq_idex <= light_queue.len) - var/datum/light_source/L = light_queue[lq_idex] - lq_idex += 1 + var/list/curr_lights = light_queue + var/list/curr_corners = corner_queue + var/list/curr_overlays = overlay_queue - if(L.check() || L.destroyed || L.force_update) - L.remove_lum() - if(!L.destroyed) - L.apply_lum() + while (lq_idex <= curr_lights.len) + var/datum/light_source/L = curr_lights[lq_idex++] - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() + if (L.needs_update != LIGHTING_NO_UPDATE) + total_ss_updates += 1 + L.update_corners() - L.vis_update = FALSE - L.force_update = FALSE - L.needs_update = FALSE + L.needs_update = LIGHTING_NO_UPDATE - processed_lights += 1 + processed_lights++ if (no_mc_tick) CHECK_TICK @@ -107,22 +141,21 @@ SUBSYSTEM_DEF(lighting) break if (lq_idex > 1) - light_queue.Cut(1, lq_idex) + curr_lights.Cut(1, lq_idex) lq_idex = 1 if (!no_mc_tick) MC_SPLIT_TICK - // Corners. - while (cq_idex <= corner_queue.len) - var/datum/lighting_corner/C = corner_queue[cq_idex] - cq_idex += 1 + while (cq_idex <= curr_corners.len) + var/datum/lighting_corner/C = curr_corners[cq_idex++] - C.update_overlays() + if (C.needs_update) + C.update_overlays() - C.needs_update = FALSE + C.needs_update = FALSE - processed_corners += 1 + processed_corners++ if (no_mc_tick) CHECK_TICK @@ -130,27 +163,51 @@ SUBSYSTEM_DEF(lighting) break if (cq_idex > 1) - corner_queue.Cut(1, cq_idex) + curr_corners.Cut(1, cq_idex) cq_idex = 1 if (!no_mc_tick) MC_SPLIT_TICK - // Objects. - while (oq_idex <= overlay_queue.len) - var/atom/movable/lighting_overlay/O = overlay_queue[oq_idex] - oq_idex += 1 + while (oq_idex <= curr_overlays.len) + var/atom/movable/lighting_overlay/O = curr_overlays[oq_idex++] - O.update_overlay() - O.needs_update = 0 + if (!QDELETED(O) && O.needs_update) + O.update_overlay() + O.needs_update = FALSE - processed_overlays += 1 + processed_overlays++ if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) break + if (oq_idex > 1) + curr_overlays.Cut(1, oq_idex) + oq_idex = 1 + +/datum/controller/subsystem/lighting/Recover() + total_lighting_corners = SSlighting.total_lighting_corners + total_lighting_overlays = SSlighting.total_lighting_overlays + total_lighting_sources = SSlighting.total_lighting_sources + + light_queue = SSlighting.light_queue + corner_queue = SSlighting.corner_queue + overlay_queue = SSlighting.overlay_queue + + lq_idex = SSlighting.lq_idex + cq_idex = SSlighting.cq_idex + oq_idex = SSlighting.oq_idex + + if (lq_idex > 1) + light_queue.Cut(1, lq_idex) + lq_idex = 1 + + if (cq_idex > 1) + corner_queue.Cut(1, cq_idex) + cq_idex = 1 + if (oq_idex > 1) overlay_queue.Cut(1, oq_idex) oq_idex = 1 diff --git a/code/controllers/subsystems/machines.dm b/code/controllers/subsystems/machines.dm index 7606e3ac4134..ca54acb3d7d3 100644 --- a/code/controllers/subsystems/machines.dm +++ b/code/controllers/subsystems/machines.dm @@ -7,7 +7,7 @@ if (Datum.is_processing) {\ if(Datum.is_processing != "SSmachines.[#List]")\ {\ - crash_with("Failed to start processing. [log_info_line(Datum)] is already being processed by [Datum.is_processing] but queue attempt occured on SSmachines.[#List]."); \ + PRINT_STACK_TRACE("Failed to start processing. [log_info_line(Datum)] is already being processed by [Datum.is_processing] but queue attempt occurred on SSmachines.[#List]."); \ }\ } else {\ Datum.is_processing = "SSmachines.[#List]";\ @@ -19,7 +19,7 @@ if(Datum.is_processing) {\ if(SSmachines.List.Remove(Datum)) {\ Datum.is_processing = null;\ } else {\ - crash_with("Failed to stop processing. [log_info_line(Datum)] is being processed by [is_processing] and not found in SSmachines.[#List]"); \ + PRINT_STACK_TRACE("Failed to stop processing. [log_info_line(Datum)] is being processed by [is_processing] and not found in SSmachines.[#List]"); \ }\ } @@ -62,9 +62,9 @@ SUBSYSTEM_DEF(machines) #define INTERNAL_PROCESS_STEP(this_step, check_resumed, proc_to_call, cost_var, next_step)\ if(current_step == this_step || (check_resumed && !resumed)) {\ - timer = TICK_USAGE_REAL;\ + timer = TICK_USAGE;\ proc_to_call(resumed);\ - cost_var = MC_AVERAGE(cost_var, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer));\ + cost_var = MC_AVERAGE(cost_var, TICK_DELTA_TO_MS(TICK_USAGE - timer));\ if(state != SS_RUNNING){\ return;\ }\ @@ -73,7 +73,7 @@ if(current_step == this_step || (check_resumed && !resumed)) {\ } /datum/controller/subsystem/machines/fire(resumed = 0) - var/timer = TICK_USAGE_REAL + var/timer = TICK_USAGE INTERNAL_PROCESS_STEP(SSMACHINES_PIPENETS,TRUE,process_pipenets,cost_pipenets,SSMACHINES_MACHINERY) INTERNAL_PROCESS_STEP(SSMACHINES_MACHINERY,FALSE,process_machinery,cost_machinery,SSMACHINES_POWERNETS) @@ -82,13 +82,19 @@ if(current_step == this_step || (check_resumed && !resumed)) {\ #undef INTERNAL_PROCESS_STEP +/datum/controller/subsystem/machines/StartLoadingMap() + suspend() + +/datum/controller/subsystem/machines/StopLoadingMap() + wake() + // rebuild all power networks from scratch - only called at world creation or by the admin verb // The above is a lie. Turbolifts also call this proc. /datum/controller/subsystem/machines/proc/makepowernets() for(var/datum/powernet/PN in powernets) qdel(PN) powernets.Cut() - setup_powernets_for_cables(cable_list) + setup_powernets_for_cables(global.all_cables) /datum/controller/subsystem/machines/proc/setup_powernets_for_cables(list/cables) for(var/obj/structure/cable/PC in cables) @@ -156,15 +162,15 @@ if(current_step == this_step || (check_resumed && !resumed)) {\ if(M in processing) processing.Remove(M) M.is_processing = null - crash_with("[log_info_line(M)] was found illegally queued on SSmachines.") + PRINT_STACK_TRACE("[log_info_line(M)] was found illegally queued on SSmachines.") continue else if(resumed) current_run.Cut() // Abandon current run; assuming that we were improperly resumed with the wrong process queue. - crash_with("[log_info_line(M)] was in the wrong subqueue on SSmachines on a resumed fire.") + PRINT_STACK_TRACE("[log_info_line(M)] was in the wrong subqueue on SSmachines on a resumed fire.") process_machinery(0) return else // ??? possibly dequeued by another machine or something ??? - crash_with("[log_info_line(M)] was in the wrong subqueue on SSmachines on an unresumed fire.") + PRINT_STACK_TRACE("[log_info_line(M)] was in the wrong subqueue on SSmachines on an unresumed fire.") continue if(!QDELETED(M) && (M.ProcessAll(wait) == PROCESS_KILL)) diff --git a/code/controllers/subsystems/managed_instance.dm b/code/controllers/subsystems/managed_instance.dm new file mode 100644 index 000000000000..921977457727 --- /dev/null +++ b/code/controllers/subsystems/managed_instance.dm @@ -0,0 +1,52 @@ +SUBSYSTEM_DEF(managed_instances) + name = "Managed Instances" + flags = SS_NO_FIRE | SS_NO_INIT + var/list/_managed_instance_cache = list() + +/datum/controller/subsystem/managed_instances/proc/get_category(var/cache_category) + var/list/category = _managed_instance_cache[cache_category] + if(category) + return category.Copy() // avoid mutating the cache. + +/datum/controller/subsystem/managed_instances/proc/get(var/instance_type, var/cache_id, var/cache_category = "default", var/list/instance_args) + if(!cache_id) + cache_id = instance_type + if(isnull(cache_id)) // No type and no id supplied, no point going further. + CRASH("Attempted to retrieve a managed instance with no supplied type or ID.") + if(isnum(cache_id)) // The cache is an assoc list of id to instance, so numerical IDs are out. + CRASH("Attempted to retrieve a managed instance with numerical ID ([cache_id]).") + + var/category_list = _managed_instance_cache[cache_category] + if(category_list) + . = category_list[cache_id] + else + category_list = list() + _managed_instance_cache[cache_category] = category_list + + if(!.) + // arglist() passed to New() will runtime without at least one list entry. + var/datum/managed_instance = length(instance_args) ? (new instance_type(arglist(instance_args))) : (new instance_type) + category_list[cache_id] = managed_instance + LAZYINITLIST(instance_args) + instance_args.Insert(1, cache_id) + managed_instance.ManagedInstanceInitialize(arglist(instance_args)) // We do this after storing to avoid circular creation loops. + if(QDELETED(managed_instance)) + PRINT_STACK_TRACE("Managed instance was queued for deletion during init! [managed_instance]") + category_list[cache_id] -= managed_instance + else + events_repository.register(/decl/observ/destroyed, managed_instance, src, TYPE_PROC_REF(/datum/controller/subsystem/managed_instances, clear)) + . = managed_instance + +// This is costly, but it also shouldn't be common for managed instances to get qdeleted post-storage. +/datum/controller/subsystem/managed_instances/proc/clear(var/datum/destroyed_instance) + if(!destroyed_instance) + return + PRINT_STACK_TRACE("Managed instance was destroyed! [destroyed_instance]") + for(var/category in _managed_instance_cache) + var/list/category_data = _managed_instance_cache[category] + for(var/cache_id in category_data) + if(category_data[cache_id] == destroyed_instance) + category_data -= cache_id + +/datum/proc/ManagedInstanceInitialize(var/cache_id, ...) + return diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm index 2067cc01ac1f..1eb7ecbbf52f 100644 --- a/code/controllers/subsystems/mapping.dm +++ b/code/controllers/subsystems/mapping.dm @@ -3,65 +3,454 @@ SUBSYSTEM_DEF(mapping) init_order = SS_INIT_MAPPING flags = SS_NO_FIRE - var/list/map_templates = list() - var/list/space_ruins_templates = list() - var/list/exoplanet_ruins_templates = list() - var/list/away_sites_templates = list() - var/list/submaps = list() - var/list/submap_archetypes = list() + /* + * General map, submap and template handling + */ + var/list/map_templates = list() + var/list/submaps = list() + var/list/map_templates_by_category = list() + var/list/map_templates_by_type = list() + var/list/spawnable_map_templates = list() + var/list/banned_maps = list() + var/list/banned_template_names = list() + + // Listing .dmm filenames in the file at this location will blacklist any templates that include them from being used. + // Maps must be the full file path to be properly included. ex. "maps/random_ruins/away_sites/example.dmm" + var/banned_dmm_location = "config/banned_map_paths.json" + var/decl/overmap_event_handler/overmap_event_handler + + /* + * Z-Level Handling Stuff + */ + /// Associative list of levels by strict z-level + var/list/datum/level_data/levels_by_z = list() + /// Associative list of levels by string ID + var/list/datum/level_data/levels_by_id = list() + /// List of z-levels containing the 'main map' + var/list/station_levels = list() + /// List of z-levels for admin functionality (Centcom, shuttle transit, etc) + var/list/admin_levels = list() + /// List of z-levels that can be contacted from the station, for eg announcements + var/list/contact_levels = list() + /// List of z-levels a character can typically reach + var/list/player_levels = list() + /// List of z-levels that don't allow random transit at edge + var/list/sealed_levels = list() + /// Custom base turf by Z-level. Defaults to world.turf for unlisted Z-levels + var/list/base_turf_by_z = list() + /// This list contains the z-level numbers which can be accessed via space travel and the percentile chances to get there. + var/list/accessible_z_levels = list() + /// Z-levels available to various consoles, such as the crew monitor. Defaults to station_levels if unset. + var/list/map_levels + /// The turf type used when generating floors between Z-levels at startup. + var/base_floor_type = /turf/floor/plating/airless + /// Replacement area, if a base_floor_type is generated. Leave blank to skip. + var/base_floor_area + /// A list of connected z-levels to avoid repeatedly rebuilding connections + var/list/connected_z_cache = list() + /// A list of turbolift holders to initialize. + var/list/turbolifts_to_initialize = list() + ///Associative list of planetoid/exoplanet data currently registered. The key is the planetoid id, the value is the planetoid_data datum. + var/list/planetoid_data_by_id + ///List of all z-levels in the world where the index corresponds to a z-level, and the key at that index is the planetoid_data datum for the associated planet + var/list/planetoid_data_by_z = list() + ///A list of queued markers to initialize during SSmapping init. + var/list/obj/abstract/landmark/map_load_mark/queued_markers = list() + +/datum/controller/subsystem/mapping/PreInit() + reindex_lists() + +#ifdef UNIT_TEST +/datum/controller/subsystem/mapping/proc/test_load_map_templates() + for(var/map_template_name in map_templates) + var/datum/map_template/map_template = get_template(map_template_name) + // Away sites are supposed to be tested separately in the Away Site environment + if(SSunit_tests.is_tested_separately(map_template)) + report_progress("Skipping template '[map_template]' ([map_template.type]): Is tested separately.") + continue + if(map_template.is_runtime_generated()) + report_progress("Skipping template '[map_template]' ([map_template.type]): Is generated at runtime.") + continue + load_template(map_template) + if(map_template.template_flags & TEMPLATE_FLAG_TEST_DUPLICATES) + load_template(map_template) + log_unit_test("Map templates loaded.") + +/datum/controller/subsystem/mapping/proc/load_template(datum/map_template/map_template) + // Suggestion: Do smart things here to squeeze as many templates as possible into the same Z-level + if(map_template.tallness == 1) + increment_world_z_size(/datum/level_data/unit_test) + var/turf/center = WORLD_CENTER_TURF(world.maxz) + if(!center) + CRASH("'[map_template]' (size: [map_template.width]x[map_template.height]) couldn't locate center turf at ([WORLD_CENTER_X][WORLD_CENTER_Y][world.maxz]) with world size ([WORLD_SIZE_TO_STRING])") + log_unit_test("Loading template '[map_template]' ([map_template.type]) at [log_info_line(center)]") + map_template.load(center, centered = TRUE) + else // Multi-Z templates are loaded using different means + log_unit_test("Loading template '[map_template]' ([map_template.type]) at Z-level [world.maxz+1] with a tallness of [map_template.tallness]") + map_template.load_new_z() +#endif /datum/controller/subsystem/mapping/Initialize(timeofday) - // Load templates and build away sites. - preloadTemplates() - for(var/atype in subtypesof(/decl/submap_archetype)) - submap_archetypes[atype] = new atype - GLOB.using_map.build_away_sites() + +#ifdef UNIT_TEST + // Shouldn't we be forcing this to true? + set_config_value(/decl/config/toggle/roundstart_level_generation, FALSE) +#endif + + reindex_lists() + + // Load our banned map list, if we have one. + if(banned_dmm_location && fexists(banned_dmm_location)) + banned_maps = cached_json_decode(safe_file2text(banned_dmm_location)) + + // Fetch and track all templates before doing anything that might need one. + for(var/datum/map_template/MT as anything in get_all_template_instances()) + register_map_template(MT) + + // Load any queued map template markers. + for(var/obj/abstract/landmark/map_load_mark/queued_mark in queued_markers) + queued_mark.load_subtemplate() + if(!QDELETED(queued_mark)) // for if the tile that lands on the landmark is a no-op tile + qdel(queued_mark) + queued_markers.Cut() + + // Populate overmap. + if(length(global.using_map.overmap_ids)) + for(var/overmap_id in global.using_map.overmap_ids) + var/overmap_type = global.using_map.overmap_ids[overmap_id] || /datum/overmap + new overmap_type(overmap_id) + // This needs to be non-null even if the overmap isn't created for this map. + overmap_event_handler = GET_DECL(/decl/overmap_event_handler) + + setup_data_for_levels() + + var/old_maxz = world.maxz + // Build away sites. + global.using_map.build_away_sites() + global.using_map.build_planets() + + // Resize the world to the max template size to fix a BYOND bug with world resizing breaking events. + // REMOVE WHEN THIS IS FIXED: https://www.byond.com/forum/post/2833191 + var/new_maxx = world.maxx + var/new_maxy = world.maxy + for(var/map_template_name in map_templates) + var/datum/map_template/map_template = map_templates[map_template_name] + new_maxx = max(map_template.width, new_maxx) + new_maxy = max(map_template.height, new_maxy) + if (new_maxx > world.maxx) + world.maxx = new_maxx + if (new_maxy > world.maxy) + world.maxy = new_maxy + +#ifdef UNIT_TEST + // Load all map templates if we're unit testing. + test_load_map_templates() +#endif + + setup_data_for_levels(min_z = old_maxz + 1) + + // Now that levels are in place, preload any associated persistent data. + // This is to avoid dependencies on other atoms or any other weird ordering + // problems like we used to get with old DMMS and SSatoms. + var/list/preloaded_levels = list() + for(var/datum/level_data/level in levels_by_z) + if(level.preload_persistent_data()) + preloaded_levels += level + + // Now actually load the serde data into the map. + for(var/datum/level_data/level as anything in preloaded_levels) + level.load_persistent_data() + + // Clear our reference data for GC + // This might not be needed but it saves refs floating around I guess. + for(var/key in level_persistence_ref_map) + var/list/stale_data = global.level_persistence_ref_map[key] + stale_data.Cut() + + global.level_persistence_ref_map.Cut() + + // Generate turbolifts last, since away sites may have elevators to generate too. + for(var/obj/abstract/turbolift_spawner/turbolift as anything in turbolifts_to_initialize) + turbolift.build_turbolift() + + // With levels set up and serde complete (and levels flagged) we can do any remaining level generation. + global.using_map.finalize_map_generation() + + // Do this dead last as all gen has to run before it makes sense. + for(var/datum/level_data/level in levels_by_z) + level.build_area_ceilings() + . = ..() +/datum/controller/subsystem/mapping/proc/setup_data_for_levels(min_z = 1, max_z = world.maxz) + for(var/z = min_z to max_z) + var/datum/level_data/level = levels_by_z[z] + if(!istype(level)) + level = new /datum/level_data/space(z) + PRINT_STACK_TRACE("Missing z-level data object for z[num2text(z)]!") + level.setup_level_data() + /datum/controller/subsystem/mapping/Recover() flags |= SS_NO_INIT - map_templates = SSmapping.map_templates - space_ruins_templates = SSmapping.space_ruins_templates - exoplanet_ruins_templates = SSmapping.exoplanet_ruins_templates - away_sites_templates = SSmapping.away_sites_templates - -/datum/controller/subsystem/mapping/proc/preloadTemplates(path = "maps/templates/") //see master controller setup - var/list/filelist = flist(path) - for(var/map in filelist) - var/datum/map_template/T = new(paths = "[path][map]", rename = "[map]") - map_templates[T.name] = T - preloadBlacklistableTemplates() - -/datum/controller/subsystem/mapping/proc/includeTemplate(var/datum/map_template/map_template, var/list/banned_maps) - if(!initial(map_template.id)) + map_templates = SSmapping.map_templates + map_templates_by_category = SSmapping.map_templates_by_category + map_templates_by_type = SSmapping.map_templates_by_type + spawnable_map_templates = SSmapping.spawnable_map_templates + +/datum/controller/subsystem/mapping/proc/register_map_template(var/datum/map_template/map_template) + if(!validate_map_template(map_template) || !map_template.preload()) + return FALSE + map_templates[map_template.name] = map_template + map_templates_by_type[map_template.type] = map_template + if(map_template.is_spawnable) + spawnable_map_templates += map_template + for(var/temple_cat in map_template.template_categories) // :3 + LAZYINITLIST(map_templates_by_category[temple_cat]) + LAZYSET(map_templates_by_category[temple_cat], map_template.name, map_template) + return TRUE + +/datum/controller/subsystem/mapping/proc/validate_map_template(var/datum/map_template/map_template) + if(!istype(map_template)) + PRINT_STACK_TRACE("Null or incorrectly typed map template attempted validation.") + return FALSE + if(length(banned_maps) && length(map_template.mappaths)) + for(var/mappath in map_template.mappaths) + if(mappath in banned_maps) + return FALSE + if(!isnull(map_templates[map_template.name])) + PRINT_STACK_TRACE("Duplicate map name '[map_template.name]' on type [map_template.type]!") + return FALSE + return TRUE + +/datum/controller/subsystem/mapping/proc/get_all_template_instances() + . = list() + for(var/template_type in subtypesof(/datum/map_template)) + var/datum/map_template/template = template_type + if(!TYPE_IS_ABSTRACT(template)) + . += new template_type(type) // send name as a param to catch people doing illegal ad hoc creation + +/datum/controller/subsystem/mapping/proc/get_template(var/template_name) + return map_templates[template_name] + +/datum/controller/subsystem/mapping/proc/get_templates_by_category(var/temple_cat) // :33 + return map_templates_by_category[temple_cat] + +/datum/controller/subsystem/mapping/proc/get_template_by_type(var/template_type) + var/datum/map_template/template = template_type + var/template_name = initial(template.name) + if(template_name) + return map_templates[template_name] + +// Z-Level procs after this point. +/datum/controller/subsystem/mapping/proc/get_gps_level_name(var/z) + if(z) + var/datum/level_data/level = levels_by_z[z] + . = level.get_display_name() + if(length(.)) + return . + return "Unknown Sector" + +/datum/controller/subsystem/mapping/proc/reindex_lists() + levels_by_z.len = world.maxz // Populate with nulls so we don't get index errors later. + base_turf_by_z.len = world.maxz + planetoid_data_by_z.len = world.maxz + connected_z_cache.Cut() + + //Update SSWeather's indexed lists, if we can. + if(SSweather?.weather_by_z) + SSweather.weather_by_z.len = world.maxz + +/datum/controller/subsystem/mapping/proc/increment_world_z_size(var/new_level_type, var/defer_setup = FALSE) + + world.maxz++ + reindex_lists() + + if(SSzcopy.zlev_maximums.len) + SSzcopy.calculate_zstack_limits() + if(!new_level_type) + PRINT_STACK_TRACE("Missing z-level data type for z["[world.maxz]"]!") return - var/datum/map_template/MT = new map_template() - if(banned_maps) - for(var/mappath in MT.mappaths) - if(banned_maps.Find(mappath)) - return - map_templates[MT.name] = MT - . = MT - -/datum/controller/subsystem/mapping/proc/preloadBlacklistableTemplates() - // Still supporting bans by filename - var/list/banned_exoplanet_dmms = generateMapList("config/exoplanet_ruin_blacklist.txt") - var/list/banned_space_dmms = generateMapList("config/space_ruin_blacklist.txt") - var/list/banned_away_site_dmms = generateMapList("config/away_site_blacklist.txt") - - if (!banned_exoplanet_dmms || !banned_space_dmms || !banned_away_site_dmms) - report_progress("One or more map blacklist files are not present in the config directory!") - - var/list/banned_maps = list() + banned_exoplanet_dmms + banned_space_dmms + banned_away_site_dmms - - for(var/item in sortList(subtypesof(/datum/map_template), /proc/cmp_ruincost_priority)) - var/datum/map_template/MT = includeTemplate(item, banned_maps) - if(!MT) + + var/datum/level_data/level = new new_level_type(world.maxz, defer_setup) + level.initialize_new_level() + return level + +/datum/controller/subsystem/mapping/proc/get_connected_levels(z, include_lateral = TRUE) + if(z <= 0 || z > length(levels_by_z)) + CRASH("Invalid z-level supplied to get_connected_levels: [isnull(z) ? "NULL" : z]") + var/list/root_stack = list(z) + // Traverse up and down to get the multiz stack. + for(var/level = z, HasBelow(level), level--) + root_stack |= level-1 + for(var/level = z, HasAbove(level), level++) + root_stack |= level+1 + . = list() + // Check stack for any laterally connected neighbors. + if(include_lateral) + for(var/tz in root_stack) + var/datum/level_data/level = levels_by_z[tz] + if(level) + var/list/cur_connected = level.get_all_connected_level_z() + if(length(cur_connected)) + . |= cur_connected + . |= root_stack + +///Returns a list of all the level data of all the connected z levels to the given z.DBColumn +/datum/controller/subsystem/mapping/proc/get_connected_levels_data(z) + if(z <= 0 || z > length(levels_by_z)) + CRASH("Invalid z-level supplied to get_connected_levels_data: [isnull(z) ? "NULL" : z]") + var/list/root_lvl_data = list(levels_by_z[z]) + + // Traverse up and down to get the multiz stack. + for(var/level = z, HasBelow(level), level--) + root_lvl_data |= levels_by_z[level - 1] + for(var/level = z, HasAbove(level), level++) + root_lvl_data |= levels_by_z[level + 1] + + . = list() + // Check stack for any laterally connected neighbors. + for(var/datum/level_data/L in root_lvl_data) + var/list/cur_connected = L.get_all_connected_level_data() + if(length(cur_connected)) + . |= cur_connected + . |= root_lvl_data + +/datum/controller/subsystem/mapping/proc/get_connected_levels_ids(z) + if(z <= 0 || z > length(levels_by_z)) + CRASH("Invalid z-level supplied to get_connected_levels_ids: [isnull(z) ? "NULL" : z]") + var/datum/level_data/LD = levels_by_z[z] + var/list/root_lvl_ids = list(LD.level_id) + + // Traverse up and down to get the multiz stack. + for(var/level = z, HasBelow(level), level--) + var/datum/level_data/L = levels_by_z[level - 1] + root_lvl_ids |= L.level_id + for(var/level = z, HasAbove(level), level++) + var/datum/level_data/L = levels_by_z[level + 1] + root_lvl_ids |= L.level_id + + . = list() + // Check stack for any laterally connected neighbors. + for(var/id in root_lvl_ids) + var/datum/level_data/level = levels_by_id[id] + if(level) + var/list/cur_connected = level.get_all_connected_level_ids() + if(length(cur_connected)) + . |= cur_connected + . |= root_lvl_ids + +/datum/controller/subsystem/mapping/proc/are_connected_levels(var/zA, var/zB) + if (zA <= 0 || zB <= 0 || zA > world.maxz || zB > world.maxz) + return FALSE + if (zA == zB) + return TRUE + if (length(connected_z_cache) >= zA && length(connected_z_cache[zA]) >= zB) + return connected_z_cache[zA][zB] + var/list/levels = get_connected_levels(zA) + var/list/new_entry = new(world.maxz) + for (var/entry in levels) + new_entry[entry] = TRUE + if (connected_z_cache.len < zA) + connected_z_cache.len = zA + connected_z_cache[zA] = new_entry + return new_entry[zB] + +/// Registers all the needed infos from a level_data into the mapping subsystem +/datum/controller/subsystem/mapping/proc/register_level_data(var/datum/level_data/LD) + if(levels_by_z.len < LD.level_z) + levels_by_z.len = max(levels_by_z.len, LD.level_z) + PRINT_STACK_TRACE("Attempting to initialize a z-level([LD.level_z]) that has not incremented world.maxz.") + + //Assign level z + var/datum/level_data/old_level = levels_by_z[LD.level_z] + levels_by_z[LD.level_z] = LD + + if(old_level) + // Swap out the old one but preserve any relevant references etc. + old_level.replace_with(LD) + QDEL_NULL(old_level) + + //Setup ID ref + if(isnull(LD.level_id)) + PRINT_STACK_TRACE("Null level_id specified for z[LD.level_z].") + else if(LD.level_id in levels_by_id) + PRINT_STACK_TRACE("Duplicate level_id '[LD.level_id]' for z[LD.level_z].") + else + levels_by_id[LD.level_id] = LD + + //Always add base turf for Z. It'll get replaced as needed. + base_turf_by_z[LD.level_z] = LD.base_turf || world.turf + + //Add to level flags lookup lists + if(LD.level_flags & ZLEVEL_STATION) + station_levels |= LD.level_z + if(LD.level_flags & ZLEVEL_ADMIN) + admin_levels |= LD.level_z + if(LD.level_flags & ZLEVEL_CONTACT) + contact_levels |= LD.level_z + if(LD.level_flags & ZLEVEL_PLAYER) + player_levels |= LD.level_z + if(LD.level_flags & ZLEVEL_SEALED) + sealed_levels |= LD.level_z + return TRUE + +/datum/controller/subsystem/mapping/proc/unregister_level_data(var/datum/level_data/LD) + if(levels_by_z[LD.level_z] == LD) + //Clear the level data ref from the list if we're in it. + levels_by_z[LD.level_z] = null + levels_by_id -= LD.level_id + + base_turf_by_z[LD.level_z] = world.turf + station_levels -= LD.level_z + admin_levels -= LD.level_z + contact_levels -= LD.level_z + player_levels -= LD.level_z + sealed_levels -= LD.level_z + return TRUE + +///Adds a planetoid/exoplanet's data to the lookup tables. Optionally if the topmost_level_id var is set on P, will automatically assign all linked levels to P. +/datum/controller/subsystem/mapping/proc/register_planetoid(var/datum/planetoid_data/P) + LAZYSET(planetoid_data_by_id, P.id, P) + + //Keep track of the topmost z-level to speed up looking up things + var/datum/level_data/LD = levels_by_id[P.topmost_level_id] + + //#TODO: Check if this actually works, because planetoid_data initializes so early it's not clear if the hierarchy can ever be fully available for this + //If we don't have level_data, we'll skip over assigning by z-level for now + if(LD) + //Assign all connected z-levels in the z list + planetoid_data_by_z[LD.level_z] = P + for(var/connected_z in get_connected_levels(LD.level_z)) + planetoid_data_by_z[connected_z] = P + + //#TODO: Until we split planet processing from the datum, make sure the planet datums get their process proc called regularly! + START_PROCESSING(SSobj, P) + +///Set the specified planetoid data for the specified level, and its connected levels. +/datum/controller/subsystem/mapping/proc/register_planetoid_levels(var/_z, var/datum/planetoid_data/P) + LAZYSET(planetoid_data_by_id, P.id, P) + //Since this will be called before the world's max z is incremented, make sure we're at least as tall as the z we get + if(length(planetoid_data_by_z) < _z) + LAZYINITLIST(planetoid_data_by_z) + planetoid_data_by_z.len = _z + planetoid_data_by_z[_z] = P + +///Removes a planetoid/exoplanet's data from the lookup tables. +/datum/controller/subsystem/mapping/proc/unregister_planetoid(var/datum/planetoid_data/P) + LAZYREMOVE(planetoid_data_by_id, P.id) + + //Clear our ref in the z list. Don't use the level_id since, we can't guarantee it'll still exist. + for(var/z = 1 to length(planetoid_data_by_z)) + var/datum/planetoid_data/cur = planetoid_data_by_z[z] + if(cur && (cur.id == P.id)) + planetoid_data_by_z[z] = null + + STOP_PROCESSING(SSobj, P) + +///Called by the roundstart hook once we toggle to in-game state +/datum/controller/subsystem/mapping/proc/start_processing_all_planets() + for(var/pid in planetoid_data_by_id) + var/datum/planetoid_data/P = planetoid_data_by_id[pid] + if(!P) continue - // This is nasty.. - if(istype(MT, /datum/map_template/ruin/exoplanet)) - exoplanet_ruins_templates[MT.name] = MT - else if(istype(MT, /datum/map_template/ruin/space)) - space_ruins_templates[MT.name] = MT - else if(istype(MT, /datum/map_template/ruin/away_site)) - away_sites_templates[MT.name] = MT + P.begin_processing() diff --git a/code/controllers/subsystems/misc_late.dm b/code/controllers/subsystems/misc_late.dm index 661510b48c5d..7f9ceb8ce6ed 100644 --- a/code/controllers/subsystems/misc_late.dm +++ b/code/controllers/subsystems/misc_late.dm @@ -3,9 +3,20 @@ SUBSYSTEM_DEF(misc_late) name = "Late Initialization" init_order = SS_INIT_MISC_LATE flags = SS_NO_FIRE + var/list/turbolifts_to_open = list() /datum/controller/subsystem/misc_late/Initialize() - GLOB.using_map.build_exoplanets() - var/decl/asset_cache/asset_cache = decls_repository.get_decl(/decl/asset_cache) + + var/decl/asset_cache/asset_cache = GET_DECL(/decl/asset_cache) asset_cache.load() - . = ..() \ No newline at end of file + + // This is gross but I'm not sure where else to handle it. Sorry. + for(var/datum/turbolift/lift in turbolifts_to_open) + if(!QDELETED(lift)) + lift.open_doors() + turbolifts_to_open.Cut() + + // Pre-populate the emote list. + decls_repository.get_decls_of_type(/decl/emote) + + . = ..() diff --git a/code/controllers/subsystems/mob_ai/auto_movement.dm b/code/controllers/subsystems/mob_ai/auto_movement.dm new file mode 100644 index 000000000000..843f37ab2d05 --- /dev/null +++ b/code/controllers/subsystems/mob_ai/auto_movement.dm @@ -0,0 +1,58 @@ +SUBSYSTEM_DEF(automove) + name = "Automated Movement" + wait = 1 + flags = SS_NO_INIT + priority = SS_PRIORITY_AUTO_MOVE + + var/list/moving_atoms = list() + var/list/moving_metadata = list() + var/list/processing_atoms + +/datum/controller/subsystem/automove/proc/unregister_mover(atom/movable/mover) + if(!istype(mover)) + CRASH("Invalid parameters to unregister_mover: [mover || "NULL"]") + if(length(moving_atoms)) + moving_atoms -= mover + if(length(moving_metadata)) + moving_metadata -= mover + if(length(processing_atoms)) + processing_atoms -= mover + +/datum/controller/subsystem/automove/proc/register_mover(atom/movable/mover, controller_type, datum/automove_metadata/metadata) + if(!istype(mover) || (!ispath(controller_type, /decl/automove_controller) && !istype(controller_type, /decl/automove_controller))) + CRASH("Invalid parameters to register_mover: [controller_type || "NULL"], [mover || "NULL"]") + + var/decl/automove_controller/controller = ispath(controller_type) ? GET_DECL(controller_type) : controller_type + moving_atoms[mover] = controller + if(istype(metadata)) + moving_metadata[mover] = metadata + else + moving_metadata -= mover + + if(suspended) + wake() + +/datum/controller/subsystem/automove/fire(resumed = FALSE) + + if(!resumed) + processing_atoms = moving_atoms.Copy() + + if(!length(processing_atoms)) + suspend() + return + + var/i = 0 + var/atom/movable/mover + var/decl/automove_controller/controller + while(i < processing_atoms.len) + i++ + mover = processing_atoms[i] + controller = processing_atoms[mover] + if(controller.handle_mover(mover, moving_metadata[mover]) == PROCESS_KILL && !QDELETED(mover)) + mover.stop_automove() + if(MC_TICK_CHECK) + if(i >= length(processing_atoms)) + processing_atoms.Cut() + else + processing_atoms.Cut(1, i+1) + return diff --git a/code/controllers/subsystems/mob_ai/mob_ai.dm b/code/controllers/subsystems/mob_ai/mob_ai.dm new file mode 100644 index 000000000000..9990c62185e5 --- /dev/null +++ b/code/controllers/subsystems/mob_ai/mob_ai.dm @@ -0,0 +1,3 @@ +PROCESSING_SUBSYSTEM_DEF(mob_ai) + name = "Mob AI" + priority = SS_PRIORITY_MOB_AI diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm index 27cdb21aad12..886508113926 100644 --- a/code/controllers/subsystems/overlays.dm +++ b/code/controllers/subsystems/overlays.dm @@ -60,6 +60,15 @@ SUBSYSTEM_DEF(overlays) overlay_queued = FALSE +/atom/movable/compile_overlays() + ..() + UPDATE_OO_IF_PRESENT + +/turf/compile_overlays() + ..() + if (above) + update_above() + /proc/iconstate2appearance(icon, iconstate) var/static/image/stringbro = new() var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches @@ -103,12 +112,14 @@ SUBSYSTEM_DEF(overlays) /atom/proc/build_appearance_list(atom/new_overlays) var/static/image/appearance_bro = new - if (islist(new_overlays)) - listclearnulls(new_overlays) - for (var/i in 1 to length(new_overlays)) - var/image/cached_overlay = new_overlays[i] - APPEARANCEIFY(cached_overlay, new_overlays[i]) - return new_overlays + if(islist(new_overlays)) + var/list/new_overlays_list = new_overlays + if(null in new_overlays_list) + new_overlays_list -= new /list(length(new_overlays_list)) // Clears nulls from the list prior to appearancifying. + for(var/i in 1 to length(new_overlays_list)) + var/image/cached_overlay = new_overlays_list[i] + APPEARANCEIFY(cached_overlay, new_overlays_list[i]) + return new_overlays_list else APPEARANCEIFY(new_overlays, .) @@ -169,7 +180,7 @@ SUBSYSTEM_DEF(overlays) if(NOT_QUEUED_ALREADY) QUEUE_FOR_COMPILE -/atom/proc/set_overlays(list/overlays_list, priority = FALSE) // Sets overlays to a list, equivalent to cut_overlays() + add_overlays(). +/atom/proc/set_overlays(list/overlays_list, priority = FALSE) // Sets overlays to a list, equivalent to cut_overlays() + add_overlay(). if (!overlays_list) return @@ -198,7 +209,7 @@ SUBSYSTEM_DEF(overlays) if(cut_old) our_overlays = cached_other.Copy() else - our_overlays |= cached_other + LAZYDISTINCTADD(our_overlays, cached_other) if(NOT_QUEUED_ALREADY) QUEUE_FOR_COMPILE else if(cut_old) diff --git a/code/controllers/subsystems/overmap.dm b/code/controllers/subsystems/overmap.dm new file mode 100644 index 000000000000..7eb6bd1784bb --- /dev/null +++ b/code/controllers/subsystems/overmap.dm @@ -0,0 +1,25 @@ +// Some duplicated behavior from SSprocessing in here so atoms can +// still process normally as well as handling overmap movement. + +SUBSYSTEM_DEF(overmap) + name = "Overmap" + priority = SS_PRIORITY_OVERMAP + wait = 2 + flags = SS_BACKGROUND | SS_POST_FIRE_TIMING | SS_NO_INIT + var/list/moving_entities = list() + var/list/current_run = list() + +// Processing boilerplate. +/datum/controller/subsystem/overmap/fire(resumed = 0) + if(!resumed) + src.current_run = moving_entities.Copy() + var/list/current_run = src.current_run + var/wait = src.wait + var/times_fired = src.times_fired + while(current_run.len) + var/obj/effect/overmap/entity = current_run[current_run.len] + current_run.len-- + if(QDELETED(entity) || entity.ProcessOvermap(wait, times_fired) == PROCESS_KILL) + moving_entities -= entity + if (MC_TICK_CHECK) + return diff --git a/code/controllers/subsystems/pathfinding.dm b/code/controllers/subsystems/pathfinding.dm new file mode 100644 index 000000000000..d6e63f4191f1 --- /dev/null +++ b/code/controllers/subsystems/pathfinding.dm @@ -0,0 +1,123 @@ +SUBSYSTEM_DEF(pathfinding) + name = "Pathfinding" + priority = SS_PRIORITY_PATHFINDING + init_order = SS_INIT_MISC_LATE + wait = 1 + + var/list/pending = list() + var/list/processing = list() + var/list/mover_metadata = list() + + VAR_PRIVATE/static/_default_adjacency_call = TYPE_PROC_REF(/turf, CardinalTurfsWithAccess) + VAR_PRIVATE/static/_default_distance_call = TYPE_PROC_REF(/turf, Distance) + +/atom/movable + var/waiting_for_path + +/atom/movable/proc/path_found(list/path) + SHOULD_CALL_PARENT(TRUE) + waiting_for_path = null + +/atom/movable/proc/path_not_found() + SHOULD_CALL_PARENT(TRUE) + waiting_for_path = null + +/datum/controller/subsystem/pathfinding/proc/dequeue_mover(atom/movable/mover, include_processing = TRUE) + if(!istype(mover)) + return + mover.waiting_for_path = null + pending -= mover + mover_metadata -= mover + if(include_processing) + processing -= mover + +// Hook to allow legacy use of AStar* to reuse the callback refs +/datum/controller/subsystem/pathfinding/proc/find_path_immediate(start, end, max_nodes, max_node_depth = 30, min_target_dist = 0, min_node_dist, id, datum/exclude, check_tick = FALSE) + return find_path_astar(start, end, _default_adjacency_call, _default_distance_call, max_nodes, max_node_depth, min_target_dist, min_node_dist, id, exclude, check_tick) + +/datum/controller/subsystem/pathfinding/proc/enqueue_mover(atom/movable/mover, atom/target, datum/pathfinding_metadata/metadata) + if(!istype(mover) || mover.waiting_for_path) + return FALSE + if(!istype(target)) + return FALSE + pending |= mover + pending[mover] = target + if(istype(metadata)) + mover_metadata[mover] = metadata + mover.waiting_for_path = world.time + return TRUE + +/datum/controller/subsystem/pathfinding/stat_entry(msg) + . = ..("Q:[length(pending)] P:[length(processing)]") + +/datum/controller/subsystem/pathfinding/fire(resumed) + + if(!resumed) + processing = pending?.Copy() + + var/atom/movable/mover + var/atom/target + var/datum/pathfinding_metadata/metadata + var/i = 0 + + while(i < processing.len) + + i++ + mover = processing[i] + target = processing[mover] + metadata = mover_metadata[mover] + dequeue_mover(mover, include_processing = FALSE) + + if(!QDELETED(mover) && !QDELETED(target)) + try_find_path(mover, target, metadata) + + if (MC_TICK_CHECK) + processing.Cut(1, i+1) + return + + processing.Cut() + +/datum/controller/subsystem/pathfinding/proc/try_find_path(atom/movable/mover, atom/target, datum/pathfinding_metadata/metadata, adjacency_call = _default_adjacency_call, distance_call = _default_distance_call) + + var/started_pathing = world.time + mover.waiting_for_path = started_pathing + + var/list/path = find_path_astar( + get_turf(mover), + target, + adjacency_call, + distance_call, + (metadata?.max_nodes || null), + (metadata?.max_node_depth || 250), + metadata?.min_target_dist, + metadata?.min_node_depth, + (metadata?.id || mover.GetIdCard()), + metadata?.obstacle, + check_tick = TRUE + ) + if(mover.waiting_for_path == started_pathing) + if(length(path)) + mover.path_found(path) + else + mover.path_not_found() + +/datum/pathfinding_metadata + var/max_nodes = null + var/max_node_depth = 250 + var/atom/id = null + var/min_target_dist = null + var/min_node_depth = null + var/obstacle = null + +/datum/pathfinding_metadata/New(_max_nodes, _max_node_depth, _id, _min_target_dist, _min_node_depth, _obstacle) + + id = _id + obstacle = _obstacle + max_nodes = _max_nodes + + if(!isnull(_max_node_depth)) + max_node_depth = _max_node_depth + if(!isnull(_min_target_dist)) + min_target_dist = _min_target_dist + if(!isnull(_min_node_depth)) + min_node_depth = _min_node_depth diff --git a/code/controllers/subsystems/persistence.dm b/code/controllers/subsystems/persistence.dm new file mode 100644 index 000000000000..79a994a2da04 --- /dev/null +++ b/code/controllers/subsystems/persistence.dm @@ -0,0 +1,153 @@ +/datum/admins/proc/force_persistence_save_verb() + set name = "Force Early Level Save" + set category = "Admin" + set desc = "Forces an early level save run by SSpersistence." + if(!SSpersistence) + return + if(UNLINT(SSpersistence._persistent_save_running)) + to_chat(usr, SPAN_WARNING("There is already a level save running. Please wait for it to finish.")) + return + log_admin("[key_name(usr)] has started an early level save.") + message_admins("[key_name(usr)] has started an early level save.") + SSpersistence.start_persistent_level_save() + +SUBSYSTEM_DEF(persistence) + name = "Persistence" + init_order = SS_INIT_SERDE + flags = SS_NEEDS_SHUTDOWN + wait = 60 MINUTES + + VAR_PRIVATE/const/ELEVATOR_FALL_PATH = "data/elevator_falls_tracking.txt" + var/elevator_fall_shifts = -1 // This is snowflake, but oh well. + var/list/tracking_values = list() + VAR_PRIVATE/_persistent_save_running = FALSE + var/const/save_warning_period = 30 SECONDS // How long to warn about an upcoming world save so people can get to safety, etc + var/initial_save_skip_period // Set in Initialize() + var/showing_warning = FALSE + +/datum/controller/subsystem/persistence/Initialize() + . = ..() + initial_save_skip_period = max(0, (wait - 10 MINUTES)) // Skip initial fire(), typically there's no need to save immediately after roundstart + decls_repository.get_decls_of_subtype(/decl/persistence_handler) // Initialize()s persistence categories. + + // Begin snowflake. + var/elevator_file = safe_file2text(ELEVATOR_FALL_PATH, FALSE) + if(elevator_file) + elevator_fall_shifts = text2num(elevator_file) + else + elevator_fall_shifts = initial(elevator_fall_shifts) + if(isnull(elevator_fall_shifts)) + elevator_fall_shifts = initial(elevator_fall_shifts) + elevator_fall_shifts++ + // End snowflake. + +/datum/controller/subsystem/persistence/Shutdown() + var/list/all_persistence_datums = decls_repository.get_decls_of_subtype(/decl/persistence_handler) + for(var/thing in all_persistence_datums) + var/decl/persistence_handler/P = all_persistence_datums[thing] + P.Shutdown() + + // Refer to snowflake above. + if(fexists(ELEVATOR_FALL_PATH)) + fdel(ELEVATOR_FALL_PATH) + text2file("[elevator_fall_shifts]", ELEVATOR_FALL_PATH) + + // Handle level data shutdown. + start_persistent_level_save() + while(_persistent_save_running) + sleep(1) + +/datum/controller/subsystem/persistence/fire(resumed) + if(world.time <= initial_save_skip_period) + return + do_save_with_warning() + +/datum/controller/subsystem/persistence/proc/do_save_with_warning() + set waitfor = FALSE + if(showing_warning) + return // debounce + showing_warning = TRUE + if(save_warning_period > 0) + var/remaining_delay = save_warning_period + while(remaining_delay > 10 SECONDS) + to_world(SPAN_DANGER("World save will begin in [round(remaining_delay/10)] second\s! Prepare for a server freeze!")) + remaining_delay -= 10 SECONDS + sleep(10 SECONDS) + if(remaining_delay > 0) + to_world(SPAN_DANGER("World save will begin in [round(remaining_delay/10)] second\s! Prepare for a server freeze!")) + sleep(remaining_delay) + + to_world(SPAN_DANGER("Starting world save!")) + sleep(1 SECOND) + showing_warning = FALSE + start_persistent_level_save() + to_world(SPAN_DANGER("Saved the world! Thank you for your patience, please go about your business.")) + +/datum/controller/subsystem/persistence/proc/start_persistent_level_save() + if(_persistent_save_running) + return // debounce + _persistent_save_running = TRUE // used to avoid shutting down mid-write + + var/started_run = REALTIMEOFDAY + report_progress("Starting persistent level save.") + // TODO: suspend all subsystems while the save is running + // TODO: prevent player input somehow? + try + for(var/z = 1 to length(SSmapping.levels_by_z)) + var/datum/level_data/level = SSmapping.levels_by_z[z] + level.save_persistent_data() + catch(var/exception/E) + error("Exception when running persistent level save: [EXCEPTION_TEXT(E)]") + // TODO: re-enable all subsystems + report_progress("Persistent level save finished in [(REALTIMEOFDAY-started_run)/10] second\s.") + _persistent_save_running = FALSE + +/datum/controller/subsystem/persistence/proc/track_value(var/atom/value, var/track_type) + + var/decl/persistence_handler/handler = RESOLVE_TO_DECL(track_type) + if(!istype(handler)) + return FALSE + + var/turf/T = get_turf(value) + if(!T) + return + + var/area/A = get_area(T) + if(handler.area_restricted && (!A || (A.area_flags & AREA_FLAG_NO_LEGACY_PERSISTENCE))) + return + + if(handler.station_restricted && (!T || !(T.z in SSmapping.station_levels) )) + return FALSE + + var/datum/level_data/level = SSmapping.levels_by_z[T.z] + if(!istype(level) || !level.permit_legacy_persistence) + return + + if(!tracking_values[track_type]) + tracking_values[track_type] = list() + tracking_values[track_type] |= value + +/datum/controller/subsystem/persistence/proc/is_tracking(var/atom/value, var/track_type) + . = (value in tracking_values[track_type]) + +/datum/controller/subsystem/persistence/proc/forget_value(var/atom/value, var/track_type) + if(tracking_values[track_type]) + tracking_values[track_type] -= value + +/datum/controller/subsystem/persistence/proc/show_info(var/mob/user) + + if(!check_rights(R_INVESTIGATE, C = user)) + return + + var/list/dat = list("") + var/can_modify = check_rights(R_ADMIN, 0, user) + var/list/all_persistence_datums = decls_repository.get_decls_of_subtype(/decl/persistence_handler) + for(var/thing in all_persistence_datums) + var/decl/persistence_handler/P = all_persistence_datums[thing] + if(P.has_admin_data) + dat += P.GetAdminSummary(user, can_modify) + dat += "
" + + var/datum/browser/popup = new(user, "admin_persistence", "Persistence Data") + popup.set_content(jointext(dat, null)) + popup.open() diff --git a/code/controllers/subsystems/plants.dm b/code/controllers/subsystems/plants.dm deleted file mode 100644 index ccff89b42fb6..000000000000 --- a/code/controllers/subsystems/plants.dm +++ /dev/null @@ -1,95 +0,0 @@ -PROCESSING_SUBSYSTEM_DEF(plants) - name = "Plants" - priority = SS_PRIORITY_PLANTS - runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME - flags = SS_BACKGROUND|SS_POST_FIRE_TIMING - init_order = SS_INIT_PLANTS - wait = 60 - - process_proc = /obj/machinery/portable_atmospherics/hydroponics/Process - - var/list/product_descs = list() // Stores generated fruit descs. - var/list/seeds = list() // All seed data stored here. - var/list/gene_tag_masks = list() // Gene obfuscation for delicious trial and error goodness. - var/list/plant_icon_cache = list() // Stores images of growth, fruits and seeds. - var/list/plant_sprites = list() // List of all harvested product sprites. - var/list/plant_product_sprites = list() // List of all growth sprites plus number of growth stages. - var/list/gene_masked_list = list() // Stored gene masked list, rather than recreating it when needed. - var/list/plant_gene_datums = list() // Stored datum versions of the gene masked list. - -/datum/controller/subsystem/processing/plants/Initialize() - // Build the icon lists. - for(var/icostate in icon_states('icons/obj/hydroponics/hydroponics_growing.dmi')) - var/split = findtext(icostate,"-") - if(!split) - // invalid icon_state - continue - - var/ikey = copytext(icostate,(split+1)) - if(ikey == "dead") - // don't count dead icons - continue - ikey = text2num(ikey) - var/base = copytext(icostate,1,split) - - if(!(plant_sprites[base]) || (plant_sprites[base] 7) if (target.airflow_time++ >= target.airflow_speed - 7) if (target.airflow_od) - target.density = 0 + target.density = FALSE target.airflow_skip_speedcheck = TRUE if (MC_TICK_CHECK) @@ -62,7 +62,7 @@ PROCESSING_SUBSYSTEM_DEF(airflow) continue else if (target.airflow_od) - target.density = 0 + target.density = FALSE target.airflow_process_delay = max(1, 10 - (target.airflow_speed + 3)) target.airflow_skip_speedcheck = TRUE @@ -73,7 +73,7 @@ PROCESSING_SUBSYSTEM_DEF(airflow) target.airflow_skip_speedcheck = FALSE if (target.airflow_od) - target.density = 1 + target.density = TRUE if (!target.airflow_dest || target.loc == target.airflow_dest) target.airflow_dest = locate(min(max(target.x + target.airflow_xo, 1), world.maxx), min(max(target.y + target.airflow_yo, 1), world.maxy), target.z) @@ -135,7 +135,7 @@ PROCESSING_SUBSYSTEM_DEF(airflow) airflow_od = 0 if (!density) - density = 1 + density = TRUE airflow_od = 1 return TRUE diff --git a/code/controllers/subsystems/processing/chatter.dm b/code/controllers/subsystems/processing/chatter.dm new file mode 100644 index 000000000000..3bcd8f99eb94 --- /dev/null +++ b/code/controllers/subsystems/processing/chatter.dm @@ -0,0 +1,10 @@ +PROCESSING_SUBSYSTEM_DEF(radiochatter) + name = "Radio Chatter" + priority = SS_PRIORITY_DEFAULT + init_order = SS_INIT_MISC_LATE + wait = 1 SECOND + +/datum/controller/subsystem/processing/radiochatter/Initialize() + . = ..() + for(var/ctype in global.using_map.get_radio_chatter_types()) + GET_DECL(ctype) // Will start processing on us in New(); linter does not like START_PROCESSING(src, foo) for some reason diff --git a/code/controllers/subsystems/processing/circuit.dm b/code/controllers/subsystems/processing/circuit.dm deleted file mode 100644 index 85b70d4d5401..000000000000 --- a/code/controllers/subsystems/processing/circuit.dm +++ /dev/null @@ -1,61 +0,0 @@ -//Additional helper procs found in /code/modules/integrated_electgronics/core/saved_circuits.dm - -PROCESSING_SUBSYSTEM_DEF(circuit) - name = "Circuit" - priority = SS_PRIORITY_CIRCUIT - init_order = SS_INIT_CIRCUIT - flags = SS_BACKGROUND - - var/cipherkey - - var/list/all_components = list() // Associative list of [component_name]:[component_path] pairs - var/list/cached_components = list() // Associative list of [component_path]:[component] pairs - var/list/all_assemblies = list() // Associative list of [assembly_name]:[assembly_path] pairs - var/list/cached_assemblies = list() // Associative list of [assembly_path]:[assembly] pairs - var/list/all_circuits = list() // Associative list of [circuit_name]:[circuit_path] pairs - var/list/circuit_fabricator_recipe_list = list() // Associative list of [category_name]:[list_of_circuit_paths] pairs - var/cost_multiplier = SHEET_MATERIAL_AMOUNT / 10 // Each circuit cost unit is 200cm3 - -/datum/controller/subsystem/processing/circuit/Initialize() - SScircuit.cipherkey = generateRandomString(2000+rand(0,10)) - circuits_init() - . = ..() - -/datum/controller/subsystem/processing/circuit/proc/circuits_init() - //Cached lists for free performance - var/atom/def = /obj/item/integrated_circuit - var/default_name = initial(def.name) - for(var/path in typesof(/obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = path - var/name = initial(IC.name) - if(name == default_name) - continue - all_components[name] = path // Populating the component lists - cached_components[IC] = new path - - if(!(initial(IC.spawn_flags) & (IC_SPAWN_DEFAULT | IC_SPAWN_RESEARCH))) - continue - - var/category = initial(IC.category_text) - if(!circuit_fabricator_recipe_list[category]) - circuit_fabricator_recipe_list[category] = list() - var/list/category_list = circuit_fabricator_recipe_list[category] - category_list += IC // Populating the fabricator categories - - for(var/path in typesof(/obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/A = path - var/name = initial(A.name) - all_assemblies[name] = path - cached_assemblies[A] = new path - - circuit_fabricator_recipe_list["Assemblies"] = subtypesof(/obj/item/electronic_assembly) - list(/obj/item/electronic_assembly/medium, /obj/item/electronic_assembly/large, /obj/item/electronic_assembly/drone, /obj/item/electronic_assembly/wallmount) - - circuit_fabricator_recipe_list["Tools"] = list( - /obj/item/integrated_electronics/wirer, - /obj/item/integrated_electronics/debugger, - /obj/item/integrated_electronics/analyzer, - /obj/item/integrated_electronics/detailer, - /obj/item/card/data, - /obj/item/card/data/full_color, - /obj/item/card/data/disk - ) diff --git a/code/controllers/subsystems/processing/graphs.dm b/code/controllers/subsystems/processing/graphs.dm index 85e8c00fca6f..3f7d8cf0212e 100644 --- a/code/controllers/subsystems/processing/graphs.dm +++ b/code/controllers/subsystems/processing/graphs.dm @@ -1,3 +1,4 @@ PROCESSING_SUBSYSTEM_DEF(graphs_process) name = "Graphs (Process)" + init_order = SS_INIT_GRAPH priority = SS_PRIORITY_GRAPH diff --git a/code/controllers/subsystems/processing/icon_updates.dm b/code/controllers/subsystems/processing/icon_updates.dm deleted file mode 100644 index 8cb0c1284a2d..000000000000 --- a/code/controllers/subsystems/processing/icon_updates.dm +++ /dev/null @@ -1,50 +0,0 @@ -PROCESSING_SUBSYSTEM_DEF(icon_update) - name = "Icon Updates" - wait = 1 // ticks - flags = SS_TICKER - priority = SS_PRIORITY_ICON_UPDATE - init_order = SS_INIT_ICON_UPDATE - - var/list/queue = list() - -/datum/controller/subsystem/processing/icon_update/stat_entry() - ..("QU:[queue.len]") - -/datum/controller/subsystem/processing/icon_update/Initialize() - fire(FALSE, TRUE) - ..() - -/datum/controller/subsystem/processing/icon_update/fire(resumed = FALSE, no_mc_tick = FALSE) - var/list/curr = queue - - if (!curr.len) - suspend() - return - - while (curr.len) - var/atom/A = curr[curr.len] - - if(QDELETED(A)) - curr.len-- - if (no_mc_tick) - CHECK_TICK - else if (MC_TICK_CHECK) - return - continue - - var/list/argv = curr[A] - curr.len-- - - if (islist(argv)) - A.update_icon(arglist(argv)) - else - A.update_icon() - - if (no_mc_tick) - CHECK_TICK - else if (MC_TICK_CHECK) - return - -/atom/proc/queue_icon_update(...) - SSicon_update.queue[src] = args.len ? args : TRUE - SSicon_update.wake() diff --git a/code/controllers/subsystems/processing/mobs.dm b/code/controllers/subsystems/processing/mobs.dm index 77a852de19c5..a1812f5d7583 100644 --- a/code/controllers/subsystems/processing/mobs.dm +++ b/code/controllers/subsystems/processing/mobs.dm @@ -5,7 +5,7 @@ PROCESSING_SUBSYSTEM_DEF(mobs) runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME wait = 2 SECONDS - process_proc = /mob/proc/Life + process_proc = TYPE_PROC_REF(/mob, Life) var/list/mob_list diff --git a/code/controllers/subsystems/processing/nano.dm b/code/controllers/subsystems/processing/nano.dm index 44b05e8326b0..7e220ba5ad31 100644 --- a/code/controllers/subsystems/processing/nano.dm +++ b/code/controllers/subsystems/processing/nano.dm @@ -3,14 +3,11 @@ PROCESSING_SUBSYSTEM_DEF(nano) priority = SS_PRIORITY_NANO wait = 2 SECONDS - // a list of current open /nanoui UIs, grouped by src_object and ui_key - var/list/open_uis = list() - /** * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data * * @param user /mob The mob who opened/owns the ui - * @param src_object /obj|/mob The obj or mob which the ui belongs to + * @param src_object /datum The datum which the ui belongs to * @param ui_key string A string key used for the ui * @param ui /datum/nanoui An existing instance of the ui (can be null) * @param data list The data to be passed to the ui, if it exists @@ -36,12 +33,11 @@ PROCESSING_SUBSYSTEM_DEF(nano) * * @return /nanoui Returns the found ui, or null if none exists */ -/datum/controller/subsystem/processing/nano/proc/get_open_ui(mob/user, src_object, ui_key) - var/src_object_key = "\ref[src_object]" - if (!open_uis[src_object_key] || !open_uis[src_object_key][ui_key]) +/datum/controller/subsystem/processing/nano/proc/get_open_ui(mob/user, datum/src_object, ui_key) + if (!src_object.open_uis?[ui_key]) return - for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + for (var/datum/nanoui/ui in src_object.open_uis[ui_key]) if (ui.user == user) return ui @@ -52,14 +48,13 @@ PROCESSING_SUBSYSTEM_DEF(nano) * * @return int The number of uis updated */ -/datum/controller/subsystem/processing/nano/proc/update_uis(src_object) +/datum/controller/subsystem/processing/nano/proc/update_uis(datum/src_object) . = 0 - var/src_object_key = "\ref[src_object]" - if (!open_uis[src_object_key]) + if (!src_object?.open_uis) return - for (var/ui_key in open_uis[src_object_key]) - for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + for (var/ui_key in src_object.open_uis) + for (var/datum/nanoui/ui in src_object.open_uis[ui_key]) if(ui.src_object && ui.user && ui.src_object.nano_host()) ui.try_update(1) .++ @@ -73,14 +68,13 @@ PROCESSING_SUBSYSTEM_DEF(nano) * * @return int The number of uis close */ -/datum/controller/subsystem/processing/nano/proc/close_uis(src_object) +/datum/controller/subsystem/processing/nano/proc/close_uis(datum/src_object) . = 0 - var/src_object_key = "\ref[src_object]" - if (!open_uis[src_object_key]) + if (!length(src_object.open_uis)) return - for (var/ui_key in open_uis[src_object_key]) - for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + for (var/ui_key in src_object.open_uis) + for (var/datum/nanoui/ui in src_object.open_uis[ui_key]) ui.close() // If it's missing src_object or user, we want to close it even more. .++ @@ -93,14 +87,14 @@ PROCESSING_SUBSYSTEM_DEF(nano) * * @return int The number of uis updated */ -/datum/controller/subsystem/processing/nano/proc/update_user_uis(mob/user, src_object, ui_key) +/datum/controller/subsystem/processing/nano/proc/update_user_uis(mob/user, datum/src_object, ui_key = null, force_open = FALSE) . = 0 - if (!length(user.open_uis)) + if (!length(user.opened_uis)) return // has no open uis - for (var/datum/nanoui/ui in user.open_uis) + for (var/datum/nanoui/ui in user.opened_uis) if ((isnull(src_object) || ui.src_object == src_object) && (isnull(ui_key) || ui.ui_key == ui_key)) - ui.try_update(1) + ui.try_update(update = TRUE, force_open = force_open) .++ /** @@ -112,12 +106,12 @@ PROCESSING_SUBSYSTEM_DEF(nano) * * @return int The number of uis closed */ -/datum/controller/subsystem/processing/nano/proc/close_user_uis(mob/user, src_object, ui_key) +/datum/controller/subsystem/processing/nano/proc/close_user_uis(mob/user, datum/src_object, ui_key) . = 0 - if (!length(user.open_uis)) + if (!length(user.opened_uis)) return // has no open uis - for (var/datum/nanoui/ui in user.open_uis) + for (var/datum/nanoui/ui in user.opened_uis) if ((isnull(src_object) || ui.src_object == src_object) && (isnull(ui_key) || ui.ui_key == ui_key)) ui.close() .++ @@ -131,10 +125,10 @@ PROCESSING_SUBSYSTEM_DEF(nano) * @return nothing */ /datum/controller/subsystem/processing/nano/proc/ui_opened(datum/nanoui/ui) - var/src_object_key = "\ref[ui.src_object]" - LAZYINITLIST(open_uis[src_object_key]) - LAZYDISTINCTADD(open_uis[src_object_key][ui.ui_key], ui) - LAZYDISTINCTADD(ui.user.open_uis, ui) + var/datum/src_object = ui.src_object + LAZYINITLIST(src_object.open_uis) + LAZYDISTINCTADD(src_object.open_uis[ui.ui_key], ui) + LAZYDISTINCTADD(ui.user.opened_uis, ui) START_PROCESSING(SSnano, ui) /** @@ -146,19 +140,15 @@ PROCESSING_SUBSYSTEM_DEF(nano) * @return int 0 if no ui was removed, 1 if removed successfully */ /datum/controller/subsystem/processing/nano/proc/ui_closed(var/datum/nanoui/ui) - var/src_object_key = "\ref[ui.src_object]" - if (!open_uis[src_object_key] || !open_uis[src_object_key][ui.ui_key]) - return 0 // wasn't open + var/datum/src_object = ui.src_object + if (!src_object.open_uis?[ui.ui_key]) + return FALSE // wasn't open STOP_PROCESSING(SSnano, ui) if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface) - LAZYREMOVE(ui.user.open_uis, ui) - open_uis[src_object_key][ui.ui_key] -= ui - if(!length(open_uis[src_object_key][ui.ui_key])) - open_uis[src_object_key] -= ui.ui_key - if(!length(open_uis[src_object_key])) - open_uis -= src_object_key - return 1 + LAZYREMOVE(ui.user.opened_uis, ui) + LAZYREMOVE(src_object.open_uis[ui.ui_key], ui) + return TRUE /** * This is called on user logout @@ -181,12 +171,11 @@ PROCESSING_SUBSYSTEM_DEF(nano) * @return nothing */ /datum/controller/subsystem/processing/nano/proc/user_transferred(mob/oldMob, mob/newMob) - if (!oldMob || !oldMob.open_uis) - return 0 // has no open uis + if (!oldMob?.opened_uis) + return FALSE // has no open uis - LAZYINITLIST(newMob.open_uis) - for (var/datum/nanoui/ui in oldMob.open_uis) + for (var/datum/nanoui/ui in oldMob.opened_uis) ui.user = newMob - newMob.open_uis += ui - oldMob.open_uis = null - return 1 // success + newMob.opened_uis += oldMob.opened_uis // if the new mob's list is null this just sets it to the old mob's list + oldMob.opened_uis = null + return TRUE // success diff --git a/code/controllers/subsystems/processing/plants.dm b/code/controllers/subsystems/processing/plants.dm new file mode 100644 index 000000000000..c07b5e9c714e --- /dev/null +++ b/code/controllers/subsystems/processing/plants.dm @@ -0,0 +1,76 @@ +/datum/proc/process_plants() + SHOULD_NOT_SLEEP(TRUE) + return PROCESS_KILL + +PROCESSING_SUBSYSTEM_DEF(plants) + name = "Plants" + priority = SS_PRIORITY_PLANTS + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + flags = SS_BACKGROUND|SS_POST_FIRE_TIMING + init_order = SS_INIT_PLANTS + wait = 1 MINUTE + process_proc = TYPE_PROC_REF(/datum, process_plants) + /// Stores generated fruit descs. + var/list/product_descs = list() + /// All seed data stored here. + var/list/seeds = list() + /// Stores images of growth, fruits and seeds. + var/list/plant_icon_cache = list() + /// List of all harvested product sprites. + var/list/plant_sprites = list() + /// List of all growth sprites plus number of growth stages. + var/list/plant_product_sprites = list() + /// Precalculated gene decl/mask list for use in botany machine UI. + var/list/gene_masked_list = list() + +/datum/controller/subsystem/processing/plants/Initialize() + // Build the icon lists. + for(var/icostate in icon_states('icons/obj/hydroponics/hydroponics_growing.dmi')) + var/split = findtext(icostate,"-") + if(!split) + // invalid icon_state + continue + + var/ikey = copytext(icostate,(split+1)) + if(ikey == "dead") + // don't count dead icons + continue + ikey = text2num(ikey) + var/base = copytext(icostate,1,split) + + if(!(plant_sprites[base]) || (plant_sprites[base] 0) - crash_with("[log_info_line(subsystem.debug_last_thing)] slept during processing. Spent [tick_time] tick\s.") + PRINT_STACK_TRACE("[log_info_line(subsystem.debug_last_thing)] slept during processing. Spent [tick_time] tick\s.") if(tick_use_limit > 0) - crash_with("[log_info_line(subsystem.debug_last_thing)] took longer than a tick to process. Exceeded with [tick_use_limit]%") + PRINT_STACK_TRACE("[log_info_line(subsystem.debug_last_thing)] took longer than a tick to process. Exceeded with [tick_use_limit]%") diff --git a/code/controllers/subsystems/processing/projectiles.dm b/code/controllers/subsystems/processing/projectiles.dm new file mode 100644 index 000000000000..81fc3864a0bc --- /dev/null +++ b/code/controllers/subsystems/processing/projectiles.dm @@ -0,0 +1,6 @@ +PROCESSING_SUBSYSTEM_DEF(projectiles) + name = "Projectiles" + priority = SS_PRIORITY_PROJECTILES + flags = SS_NO_INIT + wait = 1 + var/global_max_tick_moves = 10 \ No newline at end of file diff --git a/code/controllers/subsystems/processing/temperature.dm b/code/controllers/subsystems/processing/temperature.dm index 377c82836602..4f14fc037885 100644 --- a/code/controllers/subsystems/processing/temperature.dm +++ b/code/controllers/subsystems/processing/temperature.dm @@ -2,4 +2,4 @@ PROCESSING_SUBSYSTEM_DEF(temperature) name = "Temperature" priority = SS_PRIORITY_TEMPERATURE wait = 5 SECONDS - process_proc = /atom/proc/ProcessAtomTemperature + process_proc = TYPE_PROC_REF(/atom, ProcessAtomTemperature) diff --git a/code/controllers/subsystems/processing/vines.dm b/code/controllers/subsystems/processing/vines.dm index 56e24d30f277..1e59ccf5a6fa 100644 --- a/code/controllers/subsystems/processing/vines.dm +++ b/code/controllers/subsystems/processing/vines.dm @@ -5,8 +5,6 @@ PROCESSING_SUBSYSTEM_DEF(vines) runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME wait = 80 - process_proc = /obj/effect/vine/Process - var/list/vine_list /datum/controller/subsystem/processing/vines/PreInit() diff --git a/code/controllers/subsystems/radiation.dm b/code/controllers/subsystems/radiation.dm index 006eaecb8392..2728e47cec4d 100644 --- a/code/controllers/subsystems/radiation.dm +++ b/code/controllers/subsystems/radiation.dm @@ -16,8 +16,9 @@ SUBSYSTEM_DEF(radiation) if (!resumed) current_sources = sources.Copy() current_res_cache = resistance_cache.Copy() - listeners = GLOB.living_mob_list_.Copy() + listeners = global.living_mob_list_.Copy() + var/rad_decay_rate = get_config_value(/decl/config/num/radiation_decay_rate) while(current_sources.len) var/datum/radiation_source/S = current_sources[current_sources.len] current_sources.len-- @@ -25,10 +26,10 @@ SUBSYSTEM_DEF(radiation) if(QDELETED(S)) sources -= S else if(S.decay) - S.update_rad_power(S.rad_power - config.radiation_decay_rate) + S.update_rad_power(S.rad_power - rad_decay_rate) if (MC_TICK_CHECK) return - + while(current_res_cache.len) var/turf/T = current_res_cache[current_res_cache.len] current_res_cache.len-- @@ -36,7 +37,7 @@ SUBSYSTEM_DEF(radiation) if(QDELETED(T)) resistance_cache -= T else if((length(T.contents) + 1) != resistance_cache[T]) - resistance_cache -= T // If its stale REMOVE it! It will get added if its needed. + resistance_cache -= T // If it's stale REMOVE it! It will get added if it's needed. if (MC_TICK_CHECK) return @@ -73,8 +74,8 @@ SUBSYSTEM_DEF(radiation) if(source.source_turf.z != T.z) continue // Radiation is not multi-z if(source.respect_maint) - var/area/A = T.loc - if(A.area_flags & AREA_FLAG_RAD_SHIELDED) + var/area/A = get_area(T) + if(A && (A.area_flags & AREA_FLAG_RAD_SHIELDED)) continue // In shielded area var/dist = get_dist(source.source_turf, T) @@ -87,12 +88,13 @@ SUBSYSTEM_DEF(radiation) // Okay, now ray trace to find resistence! var/turf/origin = source.source_turf var/working = source.rad_power + var/rad_mult = get_config_value(/decl/config/num/radiation_resistance_multiplier) while(origin != T) origin = get_step_towards(origin, T) //Raytracing if(!resistance_cache[origin]) //Only get the resistance if we don't already know it. origin.calc_rad_resistance() if(origin.cached_rad_resistance) - working = round((working / (origin.cached_rad_resistance * config.radiation_resistance_multiplier)), 0.1) + working = round((working / (origin.cached_rad_resistance * rad_mult)), 0.1) if((working <= .) || (working <= RADIATION_THRESHOLD_CUTOFF)) break // Already affected by a stronger source (or its zero...) . = max((working / (dist ** 2)), .) //Butchered version of the inverse square law. Works for this purpose @@ -106,7 +108,7 @@ SUBSYSTEM_DEF(radiation) var/datum/radiation_source/existing = sources_assoc[S.source_turf] if(existing) qdel(existing) - sources += S + sources |= S sources_assoc[S.source_turf] = S // Creates a temporary radiation source that will decay @@ -134,5 +136,5 @@ SUBSYSTEM_DEF(radiation) /datum/controller/subsystem/radiation/proc/z_radiate(var/atom/source, power, var/respect_maint = FALSE) if(!(power && source)) return - var/turf/epicentre = locate(round(world.maxx / 2), round(world.maxy / 2), source.z) + var/turf/epicentre = WORLD_CENTER_TURF(source.z) flat_radiate(epicentre, power, world.maxx, respect_maint) \ No newline at end of file diff --git a/code/controllers/subsystems/shuttle.dm b/code/controllers/subsystems/shuttle.dm index 5af19f46f889..4949035b0a33 100644 --- a/code/controllers/subsystems/shuttle.dm +++ b/code/controllers/subsystems/shuttle.dm @@ -13,7 +13,9 @@ SUBSYSTEM_DEF(shuttle) var/last_landmark_registration_time var/list/shuttle_logs = list() //Keeps records of shuttle movement, format is list(datum/shuttle = datum/shuttle_log) var/list/shuttle_areas = list() //All the areas of all shuttles. + var/list/map_hash_to_areas = list() //This helps shuttles locate correct areas. Format: list(string map_hash = list(area_type = area_instance)). var/list/docking_registry = list() //Docking controller tag -> docking controller program, mostly for init purposes. + var/list/docking_beacons = list() //Magnetic docking beacons, used for free-form landing in secure areas. var/list/landmarks_awaiting_sector = list() //Stores automatic landmarks that are waiting for a sector to finish loading. var/list/landmarks_still_needed = list() //Stores landmark_tags that need to be assigned to the sector (landmark_tag = sector) when registered. @@ -40,7 +42,7 @@ SUBSYSTEM_DEF(shuttle) while (working_shuttles.len) var/datum/shuttle/shuttle = working_shuttles[working_shuttles.len] working_shuttles.len-- - if(shuttle.process_state && (shuttle.Process(wait, times_fired, src) == PROCESS_KILL)) + if((shuttle.always_process || shuttle.process_state) && (shuttle.Process(wait, times_fired, src) == PROCESS_KILL) && !shuttle.always_process) process_shuttles -= shuttle if (MC_TICK_CHECK) @@ -55,7 +57,7 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/initialize_shuttles() var/list/shuttles_made = list() for(var/shuttle_type in shuttles_to_initialize) - var/shuttle = initialize_shuttle(shuttle_type) + var/shuttle = initialize_shuttle(shuttle_type, shuttles_to_initialize[shuttle_type]) if(shuttle) shuttles_made += shuttle hook_up_motherships(shuttles_made) @@ -78,7 +80,7 @@ SUBSYSTEM_DEF(shuttle) try_add_landmark_tag(shuttle_landmark_tag, O) landmarks_still_needed -= shuttle_landmark_tag else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically - O = map_sectors["[shuttle_landmark.z]"] + O = global.overmap_sectors[shuttle_landmark.z] O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark) /datum/controller/subsystem/shuttle/proc/unregister_landmark(shuttle_landmark_tag) @@ -96,8 +98,8 @@ SUBSYSTEM_DEF(shuttle) if(!try_add_landmark_tag(landmark_tag, given_sector)) landmarks_still_needed[landmark_tag] = given_sector - for(var/shuttle_name in given_sector.initial_restricted_waypoints) - for(var/landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name]) + for(var/shuttle_type in given_sector.initial_restricted_waypoints) + for(var/landmark_tag in given_sector.initial_restricted_waypoints[shuttle_type]) if(!try_add_landmark_tag(landmark_tag, given_sector)) landmarks_still_needed[landmark_tag] = given_sector @@ -116,17 +118,21 @@ SUBSYSTEM_DEF(shuttle) if(landmark.landmark_tag in given_sector.initial_generic_waypoints) given_sector.add_landmark(landmark) . = 1 - for(var/shuttle_name in given_sector.initial_restricted_waypoints) - if(landmark.landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name]) - given_sector.add_landmark(landmark, shuttle_name) + for(var/shuttle_type in given_sector.initial_restricted_waypoints) + if(landmark.landmark_tag in given_sector.initial_restricted_waypoints[shuttle_type]) + given_sector.add_landmark(landmark, shuttle_type) . = 1 -/datum/controller/subsystem/shuttle/proc/initialize_shuttle(var/shuttle_type) +/datum/controller/subsystem/shuttle/proc/initialize_shuttle(var/shuttle_type, var/map_hash, var/list/add_args) var/datum/shuttle/shuttle = shuttle_type - if(initial(shuttle.category) != shuttle_type) - shuttle = new shuttle() - shuttle_areas |= shuttle.shuttle_area - return shuttle + if(TYPE_IS_ABSTRACT(shuttle)) + return null + var/list/shuttle_args = list(map_hash) + if(length(add_args)) + shuttle_args += add_args + shuttle = new shuttle(arglist(shuttle_args)) + shuttle_areas |= shuttle.shuttle_area + return shuttle /datum/controller/subsystem/shuttle/proc/hook_up_motherships(shuttles_list) for(var/datum/shuttle/S in shuttles_list) @@ -146,5 +152,28 @@ SUBSYSTEM_DEF(shuttle) var/obj/effect/overmap/visitable/ship/ship_effect = ship overmap_halted ? ship_effect.halt() : ship_effect.unhalt() +/datum/controller/subsystem/shuttle/proc/ship_by_name(name) + for (var/obj/effect/overmap/visitable/ship/ship in ships) + if (ship.name == name) + return ship + +/datum/controller/subsystem/shuttle/proc/ship_by_type(type) + for (var/obj/effect/overmap/visitable/ship/ship in ships) + if (ship.type == type) + return ship + +/datum/controller/subsystem/shuttle/proc/ship_by_shuttle(shuttle) + for(var/obj/effect/overmap/visitable/ship/landable/landable in SSshuttle.ships) + if(landable.shuttle == shuttle) + return landable + +/datum/controller/subsystem/shuttle/proc/docking_beacons_by_z(z_levels) + . = list() + if(!islist(z_levels)) + z_levels = list(z_levels) + for(var/obj/machinery/docking_beacon/beacon in docking_beacons) + if(beacon.z in z_levels) + . |= beacon + /datum/controller/subsystem/shuttle/stat_entry() ..("Shuttles:[shuttles.len], Ships:[ships.len], L:[registered_shuttle_landmarks.len][overmap_halted ? ", HALT" : ""]") \ No newline at end of file diff --git a/code/controllers/subsystems/skybox.dm b/code/controllers/subsystems/skybox.dm index 03407c769f00..31d3e3aec9a9 100644 --- a/code/controllers/subsystems/skybox.dm +++ b/code/controllers/subsystems/skybox.dm @@ -9,9 +9,23 @@ SUBSYSTEM_DEF(skybox) var/background_icon = "dyable" var/use_stars = TRUE var/use_overmap_details = TRUE - var/star_path = 'icons/skybox/skybox.dmi' + var/stars_icon = 'icons/skybox/skybox.dmi' var/star_state = "stars" - var/list/skybox_cache = list() + + var/static/list/skybox_cache = list() + + var/static/mutable_appearance/normal_space + var/static/list/dust_cache = list() + var/static/list/speedspace_cache = list() + var/static/list/mapedge_cache = list() + + var/static/list/phase_shift_by_x = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + var/static/list/phase_shift_by_y = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + +/datum/controller/subsystem/skybox/PreInit() + phase_shift_by_x = shuffle(phase_shift_by_x) + phase_shift_by_y = shuffle(phase_shift_by_y) + build_space_appearances() /datum/controller/subsystem/skybox/Initialize() . = ..() @@ -22,37 +36,101 @@ SUBSYSTEM_DEF(skybox) background_color = SSskybox.background_color skybox_cache = SSskybox.skybox_cache +/datum/controller/subsystem/skybox/proc/build_space_appearances() + //Create our 'normal' space appearance + normal_space = new /mutable_appearance(/turf/space) + normal_space.appearance_flags = TILE_BOUND|DEFAULT_APPEARANCE_FLAGS|KEEP_TOGETHER + normal_space.plane = SKYBOX_PLANE + normal_space.icon_state = "white" + + //Static + for (var/i in 0 to 25) + var/mutable_appearance/MA = new(normal_space) + var/image/im = image('icons/turf/space_dust.dmi', "[i]") + im.plane = DUST_PLANE + im.alpha = 128 + im.blend_mode = BLEND_ADD + + MA.overlays = list(im) + + dust_cache["[i]"] = MA + + //Moving + for (var/i in 0 to 14) + // NORTH/SOUTH + var/mutable_appearance/MA = new(normal_space) + var/image/im = image('icons/turf/space_dust_transit.dmi', "speedspace_ns_[i]") + im.plane = DUST_PLANE + im.blend_mode = BLEND_ADD + + MA.overlays = list(im) + + speedspace_cache["NS_[i]"] = MA + + // EAST/WEST + MA = new(normal_space) + im = image('icons/turf/space_dust_transit.dmi', "speedspace_ew_[i]") + im.plane = DUST_PLANE + im.blend_mode = BLEND_ADD + + MA.overlays = list(im) + + speedspace_cache["EW_[i]"] = MA + + //Over-the-edge images + for (var/dir in global.alldirs) + var/mutable_appearance/MA = new(normal_space) + var/matrix/M = matrix() + var/horizontal = (dir & (WEST|EAST)) + var/vertical = (dir & (NORTH|SOUTH)) + M.Scale(horizontal ? 8 : 1, vertical ? 8 : 1) + MA.transform = M + MA.appearance_flags = KEEP_APART | TILE_BOUND + MA.plane = SPACE_PLANE + MA.layer = 0 + + if(dir & NORTH) + MA.pixel_y = 112 + else if(dir & SOUTH) + MA.pixel_y = -112 + + if(dir & EAST) + MA.pixel_x = 112 + else if(dir & WEST) + MA.pixel_x = -112 + + mapedge_cache["[dir]"] = MA + /datum/controller/subsystem/skybox/proc/get_skybox(z) - if(!skybox_cache["[z]"]) - skybox_cache["[z]"] = generate_skybox(z) - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/O = map_sectors["[z]"] - if(istype(O)) - for(var/zlevel in O.map_z) - skybox_cache["[zlevel]"] = skybox_cache["[z]"] - return skybox_cache["[z]"] + if(!skybox_cache[num2text(z)]) + skybox_cache[num2text(z)] = generate_skybox(z) + var/obj/effect/overmap/visitable/O = global.overmap_sectors[z] + if(istype(O)) + for(var/zlevel in O.map_z) + skybox_cache["[zlevel]"] = skybox_cache[num2text(z)] + return skybox_cache[num2text(z)] /datum/controller/subsystem/skybox/proc/generate_skybox(z) var/image/res = image(skybox_icon) - res.appearance_flags = KEEP_TOGETHER + res.appearance_flags |= KEEP_TOGETHER - var/image/base = overlay_image(skybox_icon, background_icon, background_color) + var/image/base = overlay_image(skybox_icon, background_icon, background_color, DEFAULT_APPEARANCE_FLAGS) if(use_stars) - var/image/stars = overlay_image(skybox_icon, star_state, flags = RESET_COLOR) + var/image/stars = overlay_image(stars_icon, star_state, flags = DEFAULT_APPEARANCE_FLAGS | RESET_COLOR) base.overlays += stars res.overlays += base - if(GLOB.using_map.use_overmap && use_overmap_details) - var/obj/effect/overmap/visitable/O = map_sectors["[z]"] + if(use_overmap_details) + var/obj/effect/overmap/visitable/O = global.overmap_sectors[z] if(istype(O)) var/image/overmap = image(skybox_icon) overmap.overlays += O.generate_skybox() for(var/obj/effect/overmap/visitable/other in O.loc) if(other != O) overmap.overlays += other.get_skybox_representation() - overmap.appearance_flags = RESET_COLOR + overmap.appearance_flags |= RESET_COLOR res.overlays += overmap for(var/datum/event/E in SSevent.active_events) @@ -63,7 +141,7 @@ SUBSYSTEM_DEF(skybox) /datum/controller/subsystem/skybox/proc/rebuild_skyboxes(var/list/zlevels) for(var/z in zlevels) - skybox_cache["[z]"] = generate_skybox(z) + skybox_cache[num2text(z)] = generate_skybox(z) for(var/client/C) C.update_skybox(1) diff --git a/code/controllers/subsystems/spacedrift.dm b/code/controllers/subsystems/spacedrift.dm index 31b4d0fae597..331e856cdf49 100644 --- a/code/controllers/subsystems/spacedrift.dm +++ b/code/controllers/subsystems/spacedrift.dm @@ -34,9 +34,9 @@ SUBSYSTEM_DEF(spacedrift) return continue - if (!AM.loc || AM.loc != AM.inertia_last_loc || AM.Process_Spacemove(0)) + if (!AM.loc || AM.loc != AM.inertia_last_loc || AM.is_space_movement_permitted() != SPACE_MOVE_FORBIDDEN) AM.inertia_dir = 0 - + AM.inertia_ignore = null if (!AM.inertia_dir) diff --git a/code/controllers/subsystems/statistics.dm b/code/controllers/subsystems/statistics.dm index ee9d8897ca38..209d504cffa2 100644 --- a/code/controllers/subsystems/statistics.dm +++ b/code/controllers/subsystems/statistics.dm @@ -30,7 +30,7 @@ SUBSYSTEM_DEF(statistics) var/list/population_log = list() /datum/controller/subsystem/statistics/fire(resumed = FALSE) - population_log[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")] = list("players" = LAZYLEN(GLOB.clients), "admin" = LAZYLEN(GLOB.admins)) + population_log[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")] = list("players" = LAZYLEN(global.clients), "admin" = LAZYLEN(global.admins)) /datum/controller/subsystem/statistics/Shutdown() @@ -146,25 +146,25 @@ SUBSYSTEM_DEF(statistics) var/datum/death/death = new var/area/placeofdeath = get_area(dead) death.place_of_death = placeofdeath ? placeofdeath.name : "Unknown area" - death.place_of_death = sanitizeSQL(death.place_of_death) - death.name = sanitizeSQL(dead.real_name) - death.key = sanitizeSQL(dead.key) - death.special_role = sanitizeSQL(dead.mind.special_role) - death.job = sanitizeSQL(dead.mind.assigned_role) + death.place_of_death = sanitize_sql(death.place_of_death) + death.name = sanitize_sql(dead.real_name) + death.key = sanitize_sql(dead.key) + death.special_role = sanitize_sql(dead.mind.get_special_role_name("No special role")) + death.job = sanitize_sql(dead.mind.assigned_role) if(dead.last_attacker_) - death.last_attacker_name = sanitizeSQL(dead.last_attacker_.name) - death.last_attacker_key = sanitizeSQL(dead.last_attacker_.client.key) + death.last_attacker_name = sanitize_sql(dead.last_attacker_.name) + death.last_attacker_key = sanitize_sql(dead.last_attacker_.client.key) death.gender = dead.gender death.time_of_death = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") death.coords = "[dead.x], [dead.y], [dead.z]" - death.bruteloss = dead.getBruteLoss() - death.fireloss = dead.getFireLoss() - death.brainloss = dead.getBrainLoss() - death.oxyloss = dead.getOxyLoss() - death.using_map_name = GLOB.using_map.full_name - var/obj/effect/overmap/visitable/cell = map_sectors ? map_sectors["[dead.z]"] : null - death.overmap_location_name = cell ? cell.name : "Unknown" + death.bruteloss = dead.get_damage(BRUTE) + death.fireloss = dead.get_damage(BURN) + death.brainloss = dead.get_damage(BRAIN) + death.oxyloss = dead.get_damage(OXY) + death.using_map_name = global.using_map.full_name + var/obj/effect/overmap/visitable/cell = global.overmap_sectors[dead.z] + death.overmap_location_name = cell?.name || "Unknown" LAZYADD(deaths, death) - if(!player_is_antag(dead.mind) && dead.mind.assigned_job && LAZYLEN(dead.mind.assigned_job.department_refs)) + if(!player_is_antag(dead.mind) && dead.mind.assigned_job && LAZYLEN(dead.mind.assigned_job.department_types)) crew_death_count++ diff --git a/code/controllers/subsystems/sun.dm b/code/controllers/subsystems/sun.dm deleted file mode 100644 index 181b8ad19649..000000000000 --- a/code/controllers/subsystems/sun.dm +++ /dev/null @@ -1,11 +0,0 @@ -SUBSYSTEM_DEF(sun) - name = "Sun" - flags = SS_KEEP_TIMING|SS_BACKGROUND|SS_NO_INIT - runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME - wait = 10 SECONDS - -/datum/controller/subsystem/sun/fire() - GLOB.sun.calc_position() - -/datum/controller/subsystem/sun/stat_entry() - ..("Angle:[GLOB.sun.angle]") diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm index a8626d84ad9b..69bde2c28c2d 100644 --- a/code/controllers/subsystems/supply.dm +++ b/code/controllers/subsystems/supply.dm @@ -9,8 +9,6 @@ SUBSYSTEM_DEF(supply) var/points = 50 var/points_per_process = 1 var/point_sources = list() - var/pointstotalsum = 0 - var/pointstotal = 0 var/price_markup = 1.15 var/crate_return_rebate = 0.9 @@ -24,7 +22,7 @@ SUBSYSTEM_DEF(supply) var/list/requestlist = list() var/list/donelist = list() var/list/master_supply_list = list() - + //shuttle movement var/movetime = 1200 var/datum/shuttle/autodock/ferry/supply/shuttle @@ -34,7 +32,7 @@ SUBSYSTEM_DEF(supply) "manifest" = "From exported manifests", "crate" = "From exported crates", "data" = "From uploaded survey data", - "total" = "Total" + "total" = "Total" ) /datum/controller/subsystem/supply/Initialize() @@ -42,12 +40,10 @@ SUBSYSTEM_DEF(supply) ordernum = rand(1,9000) //Build master supply list - var/decl/hierarchy/supply_pack/root = decls_repository.get_decl(/decl/hierarchy/supply_pack) - for(var/decl/hierarchy/supply_pack/sp in root.children) - if(sp.is_category()) - for(var/decl/hierarchy/supply_pack/spc in sp.get_descendents()) - spc.setup() - master_supply_list += spc + var/decl/hierarchy/supply_pack/root = IMPLIED_DECL + for(var/decl/hierarchy/supply_pack/pack in root.get_descendants()) + if(!pack.is_category()) + master_supply_list += pack // Just add points over time. /datum/controller/subsystem/supply/fire() @@ -63,71 +59,63 @@ SUBSYSTEM_DEF(supply) point_sources[source] += amount point_sources["total"] += amount - //To stop things being sent to centcomm which should not be sent to centcomm. Recursively checks for these types. -/datum/controller/subsystem/supply/proc/forbidden_atoms_check(atom/A) - if(istype(A,/mob/living)) - return 1 - if(istype(A,/obj/item/disk/nuclear)) - return 1 - if(istype(A,/obj/machinery/nuclearbomb)) - return 1 - if(istype(A,/obj/item/radio/beacon)) - return 1 - - for(var/i=1, i<=A.contents.len, i++) - var/atom/B = A.contents[i] - if(.(B)) - return 1 +/// To stop things being sent to centcomm which should not be sent to centcomm. Recursively checks for these types. +/datum/controller/subsystem/supply/proc/forbidden_atoms_check(atom/checking) + if(isliving(checking)) // You can't send a mob to the admin level. + return TRUE + if(istype(checking, /obj/item/disk/nuclear)) // Keep it somewhere nuclear operatives can reach it. + return TRUE + if(istype(checking, /obj/machinery/nuclearbomb)) // Don't nuke the admin level. + return TRUE + if(istype(checking, /obj/item/radio/beacon)) // Because these can be used for teleportation, I guess? + return TRUE + + for(var/atom/child in checking.contents) + if(forbidden_atoms_check(child)) + return TRUE + return FALSE /datum/controller/subsystem/supply/proc/sell() - for(var/area/subarea in shuttle.shuttle_area) - for(var/atom/movable/AM in subarea) - if(AM.anchored) + for(var/obj/structure/closet/crate/sold_crate in subarea) + if(sold_crate.anchored) continue - if(istype(AM, /obj/structure/closet/crate/)) - var/obj/structure/closet/crate/CR = AM - callHook("sell_crate", list(CR, subarea)) - add_points_from_source(CR.get_single_monetary_worth() * crate_return_rebate * 0.1, "crate") - var/find_slip = 1 - - for(var/atom in CR) - // Sell manifests - var/atom/A = atom - if(find_slip && istype(A,/obj/item/paper/manifest)) - var/obj/item/paper/manifest/slip = A - if(!slip.is_copy && length(slip.stamped)) - add_points_from_source(slip.order_total * slip_return_rebate, "manifest") - find_slip = 0 - continue - - // Sell materials - if(is_type_in_list(A.type, saleable_materials)) - add_points_from_source(A.get_combined_monetary_worth() * goods_sale_modifier * 0.1, "goods") - - // Must sell ore detector disks in crates - if(istype(A, /obj/item/disk/survey)) - var/obj/item/disk/survey/D = A - add_points_from_source(D.get_combined_monetary_worth() * 0.005, "data") - - qdel(AM) + RAISE_EVENT(/decl/observ/crate_sold, subarea, sold_crate) + add_points_from_source(sold_crate.get_single_monetary_worth() * crate_return_rebate * 0.1, "crate") + var/find_slip = TRUE + + for(var/atom/movable/subcontent as anything in sold_crate) + // Sell manifests + if(find_slip && istype(subcontent, /obj/item/paper/manifest)) + var/obj/item/paper/manifest/slip = subcontent + if(!LAZYACCESS(slip.metadata, "is_copy") && LAZYLEN(slip.applied_stamps)) + add_points_from_source(LAZYACCESS(slip.metadata, "order_total") * slip_return_rebate, "manifest") + find_slip = FALSE + continue + + // Sell materials + if(is_type_in_list(subcontent, saleable_materials)) + add_points_from_source(subcontent.get_combined_monetary_worth() * goods_sale_modifier * 0.1, "goods") + // Must sell ore detector disks in crates + else if(istype(subcontent, /obj/item/disk/survey)) + add_points_from_source(subcontent.get_combined_monetary_worth() * 0.005, "data") + + qdel(sold_crate) /datum/controller/subsystem/supply/proc/get_clear_turfs() var/list/clear_turfs = list() - for(var/area/subarea in shuttle.shuttle_area) - for(var/turf/T in subarea) - if(T.density) + for(var/turf/candidate_turf in subarea) + if(candidate_turf.density) continue - var/occupied = 0 - for(var/atom/A in T.contents) - if(!A.simulated) + var/occupied = FALSE + for(var/atom/movable/child as anything in candidate_turf.contents) + if(!child.simulated || !child.density) continue - occupied = 1 + occupied = TRUE break if(!occupied) - clear_turfs += T - + clear_turfs += candidate_turf return clear_turfs //Buyin @@ -137,56 +125,55 @@ SUBSYSTEM_DEF(supply) var/list/clear_turfs = get_clear_turfs() - for(var/S in shoppinglist) + for(var/datum/supply_order/order in shoppinglist) if(!clear_turfs.len) break var/turf/pickedloc = pick_n_take(clear_turfs) - shoppinglist -= S - donelist += S + shoppinglist -= order + donelist += order - var/datum/supply_order/SO = S - var/decl/hierarchy/supply_pack/SP = SO.object + var/decl/hierarchy/supply_pack/supplypack = order.object - var/obj/A = new SP.containertype(pickedloc) - A.SetName("[SP.containername][SO.comment ? " ([SO.comment])":"" ]") + var/obj/result = new supplypack.containertype(pickedloc) + result.SetName("[supplypack.containername][order.comment ? " ([order.comment])":"" ]") //supply manifest generation begin var/obj/item/paper/manifest/slip - if(!SP.contraband) + if(!supplypack.contraband) var/info = list() - info +="

[command_name()] Shipping Manifest



" - info +="Order #[SO.ordernum]
" - info +="Destination: [GLOB.using_map.station_name]
" + info +="

[global.using_map.boss_name] Shipping Manifest



" + info +="Order #[order.ordernum]
" + info +="Destination: [global.using_map.station_name]
" info +="[shoppinglist.len] PACKAGES IN THIS SHIPMENT
" info +="CONTENTS:
    " - slip = new /obj/item/paper/manifest(A, JOINTEXT(info)) - slip.order_total = SP.cost - slip.is_copy = 0 + slip = new /obj/item/paper/manifest(result, null, JOINTEXT(info)) + LAZYSET(slip.metadata, "order_total", supplypack.cost) + LAZYSET(slip.metadata, "is_copy", FALSE) //spawn the stuff, finish generating the manifest while you're at it - if(SP.access) - if(!islist(SP.access)) - A.req_access = list(SP.access) - else if(islist(SP.access)) - var/list/L = SP.access // access var is a plain var, we need a list - A.req_access = L.Copy() - - var/list/spawned = SP.spawn_contents(A) + if(supplypack.access) + if(!islist(supplypack.access)) + result.req_access = list(supplypack.access) + else if(islist(supplypack.access)) + var/list/supplypack_access = supplypack.access // access var is a plain var, we need a list + result.req_access = supplypack_access.Copy() + + var/list/spawned = supplypack.spawn_contents(result) if(slip) for(var/atom/content in spawned) slip.info += "
  • [content.name]
  • " //add the item to the manifest slip.info += "

CHECK CONTENTS AND STAMP BELOW THE LINE TO CONFIRM RECEIPT OF GOODS
" // Adds any given item to the supply shuttle -/datum/controller/subsystem/supply/proc/addAtom(var/atom/movable/A) +/datum/controller/subsystem/supply/proc/addAtom(var/atom/movable/added) var/list/clear_turfs = get_clear_turfs() if(!clear_turfs.len) return FALSE var/turf/pickedloc = pick(clear_turfs) - A.forceMove(pickedloc) + added.forceMove(pickedloc) return TRUE diff --git a/code/controllers/subsystems/throwing.dm b/code/controllers/subsystems/throwing.dm index 3f87ecf2d4cb..0849837efd8f 100644 --- a/code/controllers/subsystems/throwing.dm +++ b/code/controllers/subsystems/throwing.dm @@ -14,7 +14,6 @@ SUBSYSTEM_DEF(throwing) /datum/controller/subsystem/throwing/stat_entry() ..("P:[processing.len]") - /datum/controller/subsystem/throwing/fire(resumed = 0) if (!resumed) src.currentrun = processing.Copy() @@ -26,8 +25,16 @@ SUBSYSTEM_DEF(throwing) var/atom/movable/AM = currentrun[currentrun.len] var/datum/thrownthing/TT = currentrun[AM] currentrun.len-- - if (QDELETED(AM) || QDELETED(TT)) - processing -= AM + if (QDELETED(AM)) + if(!QDELETED(TT)) + qdel(TT) // handles removing from processing list + if (MC_TICK_CHECK) + return + continue + if (QDELETED(TT)) + if(!QDELETED(AM)) + AM.end_throw(TT) + processing -= AM if (MC_TICK_CHECK) return continue @@ -72,7 +79,7 @@ SUBSYSTEM_DEF(throwing) src.thrower = thrower src.callback = callback if(!QDELETED(thrower)) - src.target_zone = thrower.zone_sel ? thrower.zone_sel.selecting : null + src.target_zone = thrower.get_target_zone() dist_x = abs(target.x - thrownthing.x) dist_y = abs(target.y - thrownthing.y) @@ -96,7 +103,7 @@ SUBSYSTEM_DEF(throwing) /datum/thrownthing/Destroy() SSthrowing.processing -= thrownthing - thrownthing.throwing = null + thrownthing.end_throw(src) thrownthing = null target = null thrower = null @@ -122,7 +129,7 @@ SUBSYSTEM_DEF(throwing) last_move = world.time //calculate how many tiles to move, making up for any missed ticks. - var/tilestomove = CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1) + var/tilestomove = NONUNIT_CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1) while (tilestomove-- > 0) if (dist_travelled >= maxrange || AM.loc == target_turf) finalize() @@ -158,19 +165,25 @@ SUBSYSTEM_DEF(throwing) //done throwing, either because it hit something or it finished moving if(QDELETED(thrownthing)) return + thrownthing.throwing = null + if (!hit) - for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on. - var/atom/A = thing - if (A == target) + for (var/atom/thing as anything in get_turf(thrownthing)) //looking for our target on the turf we land on. + if (thing == target) hit = TRUE - thrownthing.throw_impact(A, src) + thrownthing.throw_impact(thing, src) break - if (!hit) + + if(QDELETED(thrownthing)) + return + + if(!hit) thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground. - thrownthing.space_drift(init_dir) + if(!QDELETED(thrownthing)) + thrownthing.space_drift(init_dir) - if(t_target) + if(t_target && !QDELETED(thrownthing)) thrownthing.throw_impact(t_target, src) if (callback) @@ -179,6 +192,7 @@ SUBSYSTEM_DEF(throwing) if(!QDELETED(thrownthing)) thrownthing.fall() + thrownthing.end_throw(src) qdel(src) /datum/thrownthing/proc/hit_atom(atom/A) @@ -190,9 +204,11 @@ SUBSYSTEM_DEF(throwing) var/atom/movable/AM = thing if (AM == thrownthing || (AM == thrower && !ismob(thrownthing))) continue - if (!AM.density || AM.throwpass)//check if ATOM_FLAG_CHECKS_BORDER as an atom_flag is needed + if (!AM.density || AM.throwpass) + continue + if((AM.atom_flags & ATOM_FLAG_CHECKS_BORDER) && !(get_dir(AM, thrownthing) & AM.dir)) continue - if (!hit_thing || AM.layer > hit_thing.layer) + if(!hit_thing || AM.layer > hit_thing.layer) hit_thing = AM if(hit_thing) diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index e467e9ec75e5..f431bbc339c0 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -1,6 +1,6 @@ SUBSYSTEM_DEF(ticker) name = "Ticker" - wait = 10 + wait = 1 SECOND priority = SS_PRIORITY_TICKER init_order = SS_INIT_TICKER flags = SS_NO_TICK_CHECK | SS_KEEP_TIMING @@ -8,11 +8,11 @@ SUBSYSTEM_DEF(ticker) var/pregame_timeleft = 3 MINUTES var/start_ASAP = FALSE //the game will start as soon as possible, bypassing all pre-game nonsense - var/list/gamemode_vote_results //Will be a list, in order of preference, of form list(config_tag = number of votes). + var/list/gamemode_vote_results //Will be a list, in order of preference, of form list(uid = number of votes). var/bypass_gamemode_vote = 0 //Intended for use with admin tools. Will avoid voting and ignore any results. - var/master_mode = "extended" //The underlying game mode (so "secret" or the voted mode). Saved to default back to previous round's mode in case the vote failed. This is a config_tag. - var/datum/game_mode/mode //The actual gamemode, if selected. + var/master_mode = "extended" //The underlying game mode (so "secret" or the voted mode). Saved to default back to previous round's mode in case the vote failed. This is a uid. + var/decl/game_mode/mode //The actual gamemode, if selected. var/round_progressing = 1 //Whether the lobby clock is ticking down. var/list/bad_modes = list() //Holds modes we tried to start and failed to. @@ -22,15 +22,13 @@ SUBSYSTEM_DEF(ticker) var/delay_end = 0 //Can be set true to postpone restart. var/delay_notified = 0 //Spam prevention. var/restart_timeout = 1 MINUTE - var/force_ending = 0 //Overriding this variable will force game end. Can be used for adminbuse. var/list/minds = list() //Minds of everyone in the game. var/list/antag_pool = list() var/looking_for_antags = 0 /datum/controller/subsystem/ticker/Initialize() - to_world("Welcome to the pre-game lobby!") - to_world("Please, setup your character and select ready. Game will start in [round(pregame_timeleft/10)] seconds") + print_lobby_message() return ..() /datum/controller/subsystem/ticker/fire(resumed = 0) @@ -54,7 +52,7 @@ SUBSYSTEM_DEF(ticker) Master.SetRunLevel(RUNLEVEL_SETUP) return - if(!bypass_gamemode_vote && (pregame_timeleft <= config.vote_autogamemode_timeleft SECONDS) && !gamemode_vote_results) + if(!bypass_gamemode_vote && (pregame_timeleft <= get_config_value(/decl/config/num/vote_autogamemode_timeleft) SECONDS) && !gamemode_vote_results) if(!SSvote.active_vote) SSvote.initiate_vote(/datum/vote/gamemode, automatic = 1) @@ -79,31 +77,41 @@ SUBSYSTEM_DEF(ticker) world.Reboot("Failure to select gamemode. Tried [english_list(bad_modes)].") return // This means we succeeded in picking a game mode. - GLOB.using_map.setup_economy() + global.using_map.setup_economy() Master.SetRunLevel(RUNLEVEL_GAME) create_characters() //Create player characters and transfer them collect_minds() equip_characters() - for(var/mob/living/carbon/human/H in GLOB.player_list) + for(var/mob/living/human/H in global.player_list) if(H.mind && !player_is_antag(H.mind, only_offstation_roles = 1)) var/datum/job/job = SSjobs.get_by_title(H.mind.assigned_role) if(job && job.create_record) CreateModularRecord(H) - callHook("roundstart") + // Initialize the roundstart timer + global.round_start_time = world.time + generate_multi_spawn_items() + SSlighting.handle_roundstart() + SSmapping.start_processing_all_planets() + SSwebhooks.send(WEBHOOK_ROUNDSTART, list("url" = get_world_url())) + global.using_map.refresh_lobby_browsers() + for(var/modpack_name in SSmodpacks.loaded_modpacks) + var/decl/modpack/loaded_modpack = SSmodpacks.loaded_modpacks[modpack_name] + loaded_modpack.on_roundstart() spawn(0)//Forking here so we dont have to wait for this to finish mode.post_setup() // Drafts antags who don't override jobs. - to_world("Enjoy the game!") - sound_to(world, sound(GLOB.using_map.welcome_sound)) + to_world("[SPAN_BLUE("Enjoy the game!")]") + if(global.using_map.welcome_sound) + sound_to(world, sound(pick(global.using_map.welcome_sound))) if(global.current_holiday) - to_world("and...") + to_world(SPAN_BLUE("and...")) to_world("

[global.current_holiday.announcement]

") global.current_holiday.set_up_holiday() - if(!length(GLOB.admins)) - send2adminirc("Round has started with no admins online.") + if(!length(global.admins)) + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Round Started (Game ID: [game_id])", "body" = "Round has started with no admins online.")) /datum/controller/subsystem/ticker/proc/playing_tick() mode.process() @@ -112,8 +120,8 @@ SUBSYSTEM_DEF(ticker) if(mode_finished && game_finished()) Master.SetRunLevel(RUNLEVEL_POSTGAME) end_game_state = END_GAME_READY_TO_END - INVOKE_ASYNC(src, .proc/declare_completion) - if(config.allow_map_switching && config.auto_map_vote && GLOB.all_maps.len > 1) + INVOKE_ASYNC(src, PROC_REF(declare_completion)) + if(get_config_value(/decl/config/toggle/allow_map_switching) && get_config_value(/decl/config/toggle/auto_map_vote) && length(global.votable_maps) > 1) SSvote.initiate_vote(/datum/vote/map/end_game, automatic = 1) else if(mode_finished && (end_game_state <= END_GAME_NOT_OVER)) @@ -128,7 +136,6 @@ SUBSYSTEM_DEF(ticker) return if(END_GAME_READY_TO_END) end_game_state = END_GAME_ENDING - callHook("roundend") if (universe_has_ended) if(mode.station_was_nuked) SSstatistics.set_field_details("end_proper","nuke") @@ -207,7 +214,7 @@ Helpers . = (revotes_allowed && !bypass_gamemode_vote) ? CHOOSE_GAMEMODE_REVOTE : CHOOSE_GAMEMODE_RESTART var/mode_to_try = master_mode //This is the config tag - var/datum/game_mode/mode_datum + var/decl/game_mode/mode_datum //Decide on the mode to try. if(!bypass_gamemode_vote && gamemode_vote_results) @@ -223,21 +230,26 @@ Helpers if(mode_to_try in bad_modes) return - //Find the relevant datum, resolving secret in the process. - var/list/base_runnable_modes = config.get_runnable_modes() //format: list(config_tag = weight) + var/list/base_runnable_modes = list() + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + var/decl/game_mode/game_mode = all_modes[mode_type] + if(game_mode.probability > 0 && !game_mode.startRequirements()) + base_runnable_modes[game_mode.uid] = game_mode.probability + if((mode_to_try=="random") || (mode_to_try=="secret")) var/list/runnable_modes = base_runnable_modes - bad_modes if(secret_force_mode != "secret") // Config option to force secret to be a specific mode. - mode_datum = config.pick_mode(secret_force_mode) + mode_datum = decls_repository.get_decl_by_id(secret_force_mode, validate_decl_type = FALSE) else if(!length(runnable_modes)) // Indicates major issues; will be handled on return. bad_modes += mode_to_try return else - mode_datum = config.pick_mode(pickweight(runnable_modes)) + mode_datum = decls_repository.get_decl_by_id(pickweight(runnable_modes), validate_decl_type = FALSE) if(length(runnable_modes) > 1) // More to pick if we fail; we won't tell anyone we failed unless we fail all possibilities, though. . = CHOOSE_GAMEMODE_SILENT_REDO else - mode_datum = config.pick_mode(mode_to_try) + mode_datum = decls_repository.get_decl_by_id(mode_to_try, validate_decl_type = FALSE) if(!istype(mode_datum)) bad_modes += mode_to_try return @@ -251,7 +263,7 @@ Helpers if(mode_datum.startRequirements()) mode_datum.fail_setup() SSjobs.reset_occupations() - bad_modes += mode_datum.config_tag + bad_modes += mode_datum.uid return //Declare victory, make an announcement. @@ -262,10 +274,10 @@ Helpers to_world("The current game mode is Secret!") var/list/mode_names = list() for (var/mode_tag in base_runnable_modes) - var/datum/game_mode/M = gamemode_cache[mode_tag] + var/decl/game_mode/M = decls_repository.get_decl_by_id(mode_tag, validate_decl_type = FALSE) if(M) - mode_names += M.name - if (config.secret_hide_possibilities) + mode_names |= M.name + if (get_config_value(/decl/config/toggle/secret_hide_possibilities)) message_admins("Possibilities: [english_list(mode_names)]") else to_world("Possibilities: [english_list(mode_names)]") @@ -273,46 +285,41 @@ Helpers mode.announce() /datum/controller/subsystem/ticker/proc/create_characters() - for(var/mob/new_player/player in GLOB.player_list) - if(player && player.ready && player.mind) - if(player.mind.assigned_role=="AI") - player.close_spawn_windows() - player.AIize() - else if(!player.mind.assigned_role) - continue - else - if(player.create_character()) - qdel(player) - else if(player && !player.ready) - player.new_player_panel() + for(var/mob/new_player/player in global.player_list) + if(!player.ready || !player.mind || !player.mind.assigned_role || !player.mind.assigned_job) + continue + var/mob/living/newplayer = player.create_character() + if(newplayer?.mind?.assigned_job) + newplayer.mind.assigned_job.do_spawn_special(newplayer, player, FALSE) + qdel(player) /datum/controller/subsystem/ticker/proc/collect_minds() - for(var/mob/living/player in GLOB.player_list) + for(var/mob/living/player in global.player_list) if(player.mind) minds += player.mind /datum/controller/subsystem/ticker/proc/equip_characters() var/captainless=1 - for(var/mob/living/carbon/human/player in GLOB.player_list) + for(var/mob/living/human/player in global.player_list) if(player && player.mind && player.mind.assigned_role) if(player.mind.assigned_role == "Captain") captainless=0 if(!player_is_antag(player.mind, only_offstation_roles = 1)) - SSjobs.equip_rank(player, player.mind.assigned_role, 0) + SSjobs.equip_job_title(player, player.mind.assigned_role, 0) SScustomitems.equip_custom_items(player) if(captainless) - for(var/mob/M in GLOB.player_list) - if(!istype(M,/mob/new_player)) + for(var/mob/M in global.player_list) + if(!isnewplayer(M)) to_chat(M, "Captainship not forced on anyone.") /datum/controller/subsystem/ticker/proc/attempt_late_antag_spawn(var/list/antag_choices) - var/datum/antagonist/antag = antag_choices[1] + var/decl/special_role/antag = antag_choices[1] while(antag_choices.len && antag) - var/needs_ghost = antag.flags & (ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB) + var/needs_ghost = antag.is_latejoin_template() if (needs_ghost) looking_for_antags = 1 antag_pool.Cut() - to_world("A ghost is needed to spawn \a [antag.role_text].\nGhosts may enter the antag pool by making sure their [antag.role_text] preference is set to high, then using the toggle-add-antag-candidacy verb. You have 3 minutes to enter the pool.") + to_world("A ghost is needed to spawn \a [antag.name].\nGhosts may enter the antag pool by making sure their [antag.name] preference is set to high, then using the toggle-add-antag-candidacy verb. You have 3 minutes to enter the pool.") sleep(3 MINUTES) looking_for_antags = 0 @@ -332,34 +339,32 @@ Helpers if(length(antag.candidates) >= antag.initial_spawn_req) antag.attempt_spawn() antag.finalize_spawn() - additional_antag_types.Add(antag.id) + global.additional_antag_types += antag.type return 1 else if(antag.initial_spawn_req > 1) - log_and_message_admins("Failed to find enough [antag.role_text_plural].") + log_and_message_admins("Failed to find enough [antag.name_plural].") else - log_and_message_admins("Failed to find a [antag.role_text].") + log_and_message_admins("Failed to find a [antag.name].") antag_choices -= antag if(length(antag_choices)) antag = antag_choices[1] if(antag) - log_and_message_admins("Attempting to spawn [antag.role_text_plural].") + log_and_message_admins("Attempting to spawn [antag.name_plural].") return 0 /datum/controller/subsystem/ticker/proc/game_finished() - if(force_ending) - return 1 if(mode.station_explosion_in_progress) return 0 - if(config.continous_rounds) - return SSevac.evacuation_controller.round_over() || mode.station_was_nuked + if(get_config_value(/decl/config/toggle/continuous_rounds)) + return SSevac.evacuation_controller?.round_over() || mode.station_was_nuked else - return mode.check_finished() || (SSevac.evacuation_controller.round_over() && SSevac.evacuation_controller.emergency_evacuation) || universe_has_ended + return mode.check_finished() || (SSevac.evacuation_controller && SSevac.evacuation_controller.round_over() && SSevac.evacuation_controller.emergency_evacuation) || universe_has_ended /datum/controller/subsystem/ticker/proc/mode_finished() - if(config.continous_rounds) + if(get_config_value(/decl/config/toggle/continuous_rounds)) return mode.check_finished() else return game_finished() @@ -385,32 +390,14 @@ Helpers for(var/client/C) if(!C.credits) C.RollCredits() - for(var/mob/Player in GLOB.player_list) + for(var/mob/Player in global.player_list) if(Player.mind && !isnewplayer(Player)) - if(Player.stat != DEAD) - var/turf/playerTurf = get_turf(Player) - if(SSevac.evacuation_controller.round_over() && SSevac.evacuation_controller.emergency_evacuation) - if(isNotAdminLevel(playerTurf.z)) - to_chat(Player, "You managed to survive, but were marooned on [station_name()] as [Player.real_name]...") - else - to_chat(Player, "You managed to survive the events on [station_name()] as [Player.real_name].") - else if(isAdminLevel(playerTurf.z)) - to_chat(Player, "You successfully underwent crew transfer after events on [station_name()] as [Player.real_name].") - else if(issilicon(Player)) - to_chat(Player, "You remain operational after the events on [station_name()] as [Player.real_name].") - else - to_chat(Player, "You got through just another workday on [station_name()] as [Player.real_name].") - else - if(isghost(Player)) - var/mob/observer/ghost/O = Player - if(!O.started_as_observer) - to_chat(Player, "You did not survive the events on [station_name()]...") - else - to_chat(Player, "You did not survive the events on [station_name()]...") + global.using_map.summarize_roundend_for(Player) + to_world("
") for (var/mob/living/silicon/ai/aiPlayer in SSmobs.mob_list) - if (aiPlayer.stat != 2) + if (aiPlayer.stat != DEAD) to_world("[aiPlayer.name] (Played by: [aiPlayer.key])'s laws at the end of the round were:") else @@ -428,12 +415,12 @@ Helpers for (var/mob/living/silicon/robot/robo in SSmobs.mob_list) - if(istype(robo,/mob/living/silicon/robot/drone)) + if(isdrone(robo)) dronecount++ continue if (!robo.connected_ai) - if (robo.stat != 2) + if (robo.stat != DEAD) to_world("[robo.name] (Played by: [robo.key]) survived as an AI-less synthetic! Its laws were:") else @@ -444,7 +431,7 @@ Helpers robo.laws.show_laws(world) if(dronecount) - to_world("There [dronecount>1 ? "were" : "was"] [dronecount] industrious maintenance [dronecount>1 ? "drones" : "drone"] at the end of this round.") + to_world("There [dronecount>1 ? "were" : "was"] [dronecount] industrious maintenance drone\s at the end of this round.") if(all_money_accounts.len) var/datum/money_account/max_profit = all_money_accounts[1] @@ -457,8 +444,8 @@ Helpers max_profit = D if(saldo <= max_loss.get_balance()) max_loss = D - to_world("[max_profit.owner_name] received most PROFIT today, with net profit of [max_profit.format_value_by_currency(max_profit.get_balance())].") - to_world("On the other hand, [max_loss.owner_name] had most LOSS, with total loss of [max_loss.format_value_by_currency(max_loss.get_balance())].") + to_world("[max_profit.owner_name] received most [SPAN_GOOD("PROFIT")] today, with net profit of [max_profit.format_value_by_currency(max_profit.get_balance())].") + to_world("On the other hand, [max_loss.owner_name] had most [SPAN_BAD("LOSS")], with total loss of [max_loss.format_value_by_currency(max_loss.get_balance())].") mode.declare_completion()//To declare normal completion. @@ -469,13 +456,13 @@ Helpers var/list/total_antagonists = list() //Look into all mobs in world, dead or alive for(var/datum/mind/Mind in minds) - var/temprole = Mind.special_role - if(temprole) //if they are an antagonist of some sort. - if(temprole in total_antagonists) //If the role exists already, add the name to it - total_antagonists[temprole] += ", [Mind.name]([Mind.key])" + var/special_role = Mind.get_special_role_name() + if(special_role) //if they are an antagonist of some sort. + if(special_role in total_antagonists) //If the role exists already, add the name to it + total_antagonists[special_role] += ", [Mind.name]([Mind.key])" else - total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob - total_antagonists[temprole] += ": [Mind.name]([Mind.key])" + total_antagonists.Add(special_role) //If the role doesnt exist in the list, create it and add the mob + total_antagonists[special_role] += ": [Mind.name]([Mind.key])" //Now print them all into the log! log_game("Antagonists at round end were...") @@ -490,3 +477,17 @@ Helpers bypass_gamemode_vote = 1 Master.SetRunLevel(RUNLEVEL_SETUP) return 1 + +/datum/controller/subsystem/ticker/proc/print_lobby_message() + to_world("[SPAN_BLUE("Welcome to the pre-game lobby!")]") + to_world("Please, setup your character and select ready. Game will start in [round(pregame_timeleft/10)] seconds") + + +/datum/controller/subsystem/ticker/proc/get_game_mode_options() + . = list() + . += "Respawning: [mode.deny_respawn ? "disallowed" : "allowed"]" + . += "Shuttle delay multiplier: [mode.shuttle_delay]
" + . += "Shuttle auto-recall: [mode.auto_recall_shuttle ? "enabled" : "disabled"]" + . += "" // we want a blank line here for some design reason idk + . += "Moderate event time modifier: [mode.event_delay_mod_moderate || "unset"]
" + . += "Major event time modifier: [mode.event_delay_mod_major || "unset"]
" \ No newline at end of file diff --git a/code/controllers/subsystems/timer.dm b/code/controllers/subsystems/timer.dm index c8e4d9d695f2..10195799ea2a 100644 --- a/code/controllers/subsystems/timer.dm +++ b/code/controllers/subsystems/timer.dm @@ -1,31 +1,56 @@ -#define BUCKET_LEN (round(10*(60/world.tick_lag), 1)) //how many ticks should we keep in the bucket. (1 minutes worth) -#define BUCKET_POS(timer) (((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN) -#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1))) -#define TIMER_ID_MAX (2**24) //max float with integer precision - +/// Controls how many buckets should be kept, each representing a tick. (1 minutes worth) +#define BUCKET_LEN (world.fps*1*60) +/// Helper for getting the correct bucket for a given timer +#define BUCKET_POS(timer) (((ceil((timer.timeToRun - timer.timer_subsystem.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN) +/// Gets the maximum time at which timers will be invoked from buckets, used for deferring to secondary queue +#define TIMER_MAX(timer_ss) (timer_ss.head_offset + TICKS2DS(BUCKET_LEN + timer_ss.practical_offset - 1)) +/// Max float with integer precision +#define TIMER_ID_MAX (2**24) + +/** + * # Timer Subsystem + * + * Handles creation, callbacks, and destruction of timed events. + * + * It is important to understand the buckets used in the timer subsystem are just a series of doubly-linked + * lists. The object at a given index in bucket_list is a /datum/timedevent, the head of a list, which has prev + * and next references for the respective elements in that bucket's list. + */ SUBSYSTEM_DEF(timer) name = "Timer" wait = 1 //SS_TICKER subsystem, so wait is in ticks priority = SS_PRIORITY_TIMER flags = SS_NO_INIT | SS_TICKER + runlevels = RUNLEVELS_ALL - var/list/datum/timedevent/second_queue = list() //awe, yes, you've had first queue, but what about second queue? + /// Queue used for storing timers that do not fit into the current buckets + var/list/datum/timedevent/second_queue = list() + /// A hashlist dictionary used for storing unique timers var/list/hashes = list() - - var/head_offset = 0 //world.time of the first entry in the the bucket. - var/practical_offset = 1 //index of the first non-empty item in the bucket. - var/bucket_resolution = 0 //world.tick_lag the bucket was designed for - var/bucket_count = 0 //how many timers are in the buckets - - var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick. - - var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup) - - var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time" - + /// world.time of the first entry in the bucket list, effectively the 'start time' of the current buckets + var/head_offset = 0 + /// Index of the wrap around pivot for buckets. buckets before this are later running buckets wrapped around from the end of the bucket list. + var/practical_offset = 1 + /// world.tick_lag the bucket was designed for + var/bucket_resolution = 0 + /// How many timers are in the buckets + var/bucket_count = 0 + /// List of buckets, each bucket holds every timer that has to run that byond tick + var/list/bucket_list = list() + /// List of all active timers associated to their timer ID (for easy lookup) + var/list/timer_id_dict = list() + /// Special timers that run in real-time, not BYOND time; these are more expensive to run and maintain + var/list/clienttime_timers = list() + /// Contains the last time that a timer's callback was invoked, or the last tick the SS fired if no timers are being processed var/last_invoke_tick = 0 + /// Keeps track of the next index to work on for client timers + var/next_clienttime_timer_index = 0 + /// Contains the last time that a warning was issued for not invoking callbacks var/static/last_invoke_warning = 0 + /// Boolean operator controlling if the timer SS will automatically reset buckets if it fails to invoke callbacks for an extended period of time var/static/bucket_auto_reset = TRUE + /// How many times bucket was reset + var/bucket_reset_count = 0 /datum/controller/subsystem/timer/PreInit() bucket_list.len = BUCKET_LEN @@ -33,47 +58,58 @@ SUBSYSTEM_DEF(timer) bucket_resolution = world.tick_lag /datum/controller/subsystem/timer/stat_entry(msg) - ..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]") + ..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)] RST:[bucket_reset_count]") + +/datum/controller/subsystem/timer/proc/dump_timer_buckets(full = TRUE) + var/list/to_log = list("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + if (full) + for (var/i in 1 to length(bucket_list)) + var/datum/timedevent/bucket_head = bucket_list[i] + if (!bucket_head) + continue + + to_log += "Active timers at index [i]:" + var/datum/timedevent/bucket_node = bucket_head + var/anti_loop_check = 1 + do + to_log += get_timer_debug_string(bucket_node) + bucket_node = bucket_node.next + anti_loop_check-- + while(bucket_node && bucket_node != bucket_head && anti_loop_check) + + to_log += "Active timers in the second_queue queue:" + for(var/I in second_queue) + to_log += get_timer_debug_string(I) + + // Dump all the logged data to the world log + log_world(to_log.Join("\n")) /datum/controller/subsystem/timer/fire(resumed = FALSE) + // Store local references to datum vars as it is faster to access them var/lit = last_invoke_tick - var/last_check = world.time - TICKS2DS(BUCKET_LEN*1.5) var/list/bucket_list = src.bucket_list + var/last_check = world.time - TICKS2DS(BUCKET_LEN * 1.5) + // If there are no timers being tracked, then consider now to be the last invoked time if(!bucket_count) last_invoke_tick = world.time + // Check that we have invoked a callback in the last 1.5 minutes of BYOND time, + // and throw a warning and reset buckets if this is true if(lit && lit < last_check && head_offset < last_check && last_invoke_warning < last_check) last_invoke_warning = world.time - var/msg = "No regular timers processed in the last [BUCKET_LEN*1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!" + var/msg = "No regular timers processed in the last [BUCKET_LEN * 1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!" message_admins(msg) WARNING(msg) if(bucket_auto_reset) bucket_resolution = 0 + dump_timer_buckets(TRUE) - log_ss(name, "Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") - for (var/i in 1 to length(bucket_list)) - var/datum/timedevent/bucket_head = bucket_list[i] - if (!bucket_head) - continue - - log_ss(name, "Active timers at index [i]:") - - var/datum/timedevent/bucket_node = bucket_head - var/anti_loop_check = 1000 - do - log_ss(name, get_timer_debug_string(bucket_node)) - bucket_node = bucket_node.next - anti_loop_check-- - while(bucket_node && bucket_node != bucket_head && anti_loop_check) - log_ss(name, "Active timers in the second_queue queue:") - for(var/I in second_queue) - log_ss(name, get_timer_debug_string(I)) - - var/next_clienttime_timer_index = 0 - var/len = length(clienttime_timers) - - for (next_clienttime_timer_index in 1 to len) + // Process client-time timers + if (next_clienttime_timer_index) + clienttime_timers.Cut(1, next_clienttime_timer_index+1) + next_clienttime_timer_index = 0 + for (next_clienttime_timer_index in 1 to length(clienttime_timers)) if (MC_TICK_CHECK) next_clienttime_timer_index-- break @@ -84,8 +120,8 @@ SUBSYSTEM_DEF(timer) var/datum/callback/callBack = ctime_timer.callBack if (!callBack) - clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1) - CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]") + CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], \ + head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]") ctime_timer.spent = REALTIMEOFDAY callBack.InvokeAsync() @@ -93,126 +129,95 @@ SUBSYSTEM_DEF(timer) if(ctime_timer.flags & TIMER_LOOP) ctime_timer.spent = 0 ctime_timer.timeToRun = REALTIMEOFDAY + ctime_timer.wait - BINARY_INSERT(ctime_timer, clienttime_timers, datum/timedevent, timeToRun) + BINARY_INSERT(ctime_timer, clienttime_timers, /datum/timedevent, ctime_timer, timeToRun, COMPARE_KEY) else qdel(ctime_timer) - + // Remove invoked client-time timers if (next_clienttime_timer_index) clienttime_timers.Cut(1, next_clienttime_timer_index+1) + next_clienttime_timer_index = 0 - if (MC_TICK_CHECK) - return - - var/static/list/spent = list() - var/static/datum/timedevent/timer + // Check for when we need to loop the buckets, this occurs when + // the head_offset is approaching BUCKET_LEN ticks in the past if (practical_offset > BUCKET_LEN) head_offset += TICKS2DS(BUCKET_LEN) practical_offset = 1 resumed = FALSE + // Check for when we have to reset buckets, typically from auto-reset if ((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution)) reset_buckets() bucket_list = src.bucket_list resumed = FALSE - if (!resumed) - timer = null - - while (practical_offset <= BUCKET_LEN && head_offset + ((practical_offset-1)*world.tick_lag) <= world.time) - var/datum/timedevent/head = bucket_list[practical_offset] - if (!timer || !head || timer == head) - head = bucket_list[practical_offset] - timer = head - while (timer) + // Iterate through each bucket starting from the practical offset + while (practical_offset <= BUCKET_LEN && head_offset + ((practical_offset - 1) * world.tick_lag) <= world.time) + var/datum/timedevent/timer + while ((timer = bucket_list[practical_offset])) var/datum/callback/callBack = timer.callBack if (!callBack) - bucket_resolution = null //force bucket recreation - CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + PRINT_STACK_TRACE("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], \ + head_offset: [head_offset], practical_offset: [practical_offset], bucket_joined: [timer.bucket_joined]") + if (!timer.spent) + bucket_resolution = null // force bucket recreation + return + timer.bucketEject() //pop the timer off of the bucket list. + + // Invoke callback if possible if (!timer.spent) - spent += timer timer.spent = world.time callBack.InvokeAsync() last_invoke_tick = world.time - if (MC_TICK_CHECK) - return - - timer = timer.next - if (timer == head) - break - - - bucket_list[practical_offset++] = null + if (timer.flags & TIMER_LOOP) // Prepare valid looping timers to re-enter the queue + if(QDELETED(timer)) // If we were deleted in the callback, don't re-insert. + continue + timer.spent = 0 + timer.timeToRun = world.time + timer.wait + timer.bucketJoin() + else + qdel(timer) - //we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket. - var/i = 0 - var/L = length(second_queue) - for (i in 1 to L) - timer = second_queue[i] - if (timer.timeToRun >= TIMER_MAX) - i-- + if (MC_TICK_CHECK) break - if (timer.timeToRun < head_offset + TICKS2DS(practical_offset-1)) - bucket_resolution = null //force bucket recreation + if (!bucket_list[practical_offset]) + // Empty the bucket, check if anything in the secondary queue should be shifted to this bucket + bucket_list[practical_offset] = null // Just in case + practical_offset++ + var/i = 0 + for (i in 1 to length(second_queue)) + timer = second_queue[i] + if (timer.timeToRun >= TIMER_MAX(src)) + i-- + break + + // Check for timers that are scheduled to run in the past if (timer.timeToRun < head_offset) - crash_with("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") - else - crash_with("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") - if (timer.callBack && !timer.spent) - timer.callBack.InvokeAsync() - spent += timer - bucket_count++ - else if(!QDELETED(timer)) - qdel(timer) - continue - - bucket_count++ - var/bucket_pos = max(1, BUCKET_POS(timer)) - - var/datum/timedevent/bucket_head = bucket_list[bucket_pos] - if (!bucket_head) - bucket_list[bucket_pos] = timer - timer.next = null - timer.prev = null - continue - - if (!bucket_head.prev) - bucket_head.prev = bucket_head - timer.next = bucket_head - timer.prev = bucket_head.prev - timer.next.prev = timer - timer.prev.next = timer - if (i) - second_queue.Cut(1, i+1) - - timer = null - - bucket_count -= length(spent) - - for (var/i in spent) - var/datum/timedevent/qtimer = i - if(QDELETED(qtimer)) - bucket_count++ - continue - if(!(qtimer.flags & TIMER_LOOP)) - qdel(qtimer) - else - bucket_count++ - qtimer.spent = 0 - qtimer.bucketEject() - if(qtimer.flags & TIMER_CLIENT_TIME) - qtimer.timeToRun = REALTIMEOFDAY + qtimer.wait - else - qtimer.timeToRun = world.time + qtimer.wait - qtimer.bucketJoin() - - spent.len = 0 + bucket_resolution = null // force bucket recreation + PRINT_STACK_TRACE("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. \ + [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + break + + // Check for timers that are not capable of being scheduled to run without rebuilding buckets + if (timer.timeToRun < head_offset + TICKS2DS(practical_offset - 1)) + bucket_resolution = null // force bucket recreation + PRINT_STACK_TRACE("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to \ + short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + break + + timer.bucketJoin() + if (i) + second_queue.Cut(1, i+1) + if (MC_TICK_CHECK) + break -//formated this way to be runtime resistant +/** + * Generates a string with details about the timed event for debugging purposes + */ /datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE) . = "Timer: [TE]" . += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]" @@ -223,12 +228,19 @@ SUBSYSTEM_DEF(timer) if(!TE.callBack) . += ", NO CALLBACK" +/** + * Destroys the existing buckets and creates new buckets from the existing timed events + */ /datum/controller/subsystem/timer/proc/reset_buckets() - var/list/bucket_list = src.bucket_list + log_debug("Timer buckets have been reset, this may cause timer to lag.") + bucket_reset_count++ + + var/list/bucket_list = src.bucket_list // Store local reference to datum var, this is faster var/list/alltimers = list() - //collect the timers currently in the bucket + + // Get all timers currently in the buckets for (var/bucket_head in bucket_list) - if (!bucket_head) + if (!bucket_head) // if bucket is empty for this tick continue var/datum/timedevent/bucket_node = bucket_head do @@ -236,25 +248,44 @@ SUBSYSTEM_DEF(timer) bucket_node = bucket_node.next while(bucket_node && bucket_node != bucket_head) + // Empty the list by zeroing and re-assigning the length bucket_list.len = 0 bucket_list.len = BUCKET_LEN + // Reset values for the subsystem to their initial values practical_offset = 1 bucket_count = 0 head_offset = world.time bucket_resolution = world.tick_lag + // Add all timed events from the secondary queue as well alltimers += second_queue + + for (var/datum/timedevent/t as anything in alltimers) + t.bucket_joined = FALSE + t.bucket_pos = -1 + t.prev = null + t.next = null + + // If there are no timers being tracked by the subsystem, + // there is no need to do any further rebuilding if (!length(alltimers)) return + // Sort all timers by time to run sortTim(alltimers, /proc/cmp_timer) + // Get the earliest timer, and if the TTR is earlier than the current world.time, + // then set the head offset appropriately to be the earliest time tracked by the + // current set of buckets var/datum/timedevent/head = alltimers[1] - if (head.timeToRun < head_offset) head_offset = head.timeToRun + // Iterate through each timed event and insert it into an appropriate bucket, + // up unto the point that we can no longer insert into buckets as the TTR + // is outside the range we are tracking, then insert the remainder into the + // secondary queue var/new_bucket_count var/i = 1 for (i in 1 to length(alltimers)) @@ -262,19 +293,25 @@ SUBSYSTEM_DEF(timer) if (!timer) continue - var/bucket_pos = BUCKET_POS(timer) - if (timer.timeToRun >= TIMER_MAX) + // Check that the TTR is within the range covered by buckets, when exceeded we've finished + if (timer.timeToRun >= TIMER_MAX(src)) i-- break - + // Check that timer has a valid callback and hasn't been invoked if (!timer.callBack || timer.spent) - WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], \ + head_offset: [head_offset], practical_offset: [practical_offset]") if (timer.callBack) qdel(timer) continue + // Insert the timer into the bucket, and perform necessary doubly-linked list operations new_bucket_count++ + var/bucket_pos = BUCKET_POS(timer) + timer.bucket_pos = bucket_pos + timer.bucket_joined = TRUE + var/datum/timedevent/bucket_head = bucket_list[bucket_pos] if (!bucket_head) bucket_list[bucket_pos] = timer @@ -282,14 +319,14 @@ SUBSYSTEM_DEF(timer) timer.prev = null continue - if (!bucket_head.prev) - bucket_head.prev = bucket_head + bucket_head.prev = timer timer.next = bucket_head - timer.prev = bucket_head.prev - timer.next.prev = timer - timer.prev.next = timer + timer.prev = null + bucket_list[bucket_pos] = timer + + // Cut the timers that are tracked by the buckets from the secondary queue if (i) - alltimers.Cut(1, i+1) + alltimers.Cut(1, i + 1) second_queue = alltimers bucket_count = new_bucket_count @@ -300,46 +337,72 @@ SUBSYSTEM_DEF(timer) timer_id_dict |= SStimer.timer_id_dict bucket_list |= SStimer.bucket_list +/** + * # Timed Event + * + * This is the actual timer, it contains the callback and necessary data to maintain + * the timer. + * + * See the documentation for the timer subsystem for an explanation of the buckets referenced + * below in next and prev + */ /datum/timedevent + /// ID used for timers when the TIMER_STOPPABLE flag is present var/id + /// The callback to invoke after the timer completes var/datum/callback/callBack + /// The time at which the callback should be invoked at var/timeToRun + /// The length of the timer var/wait + /// Unique hash generated when TIMER_UNIQUE flag is present var/hash + /// The source of the timedevent, whatever called addtimer + var/source + /// Flags associated with the timer, see _DEFINES/subsystems.dm var/list/flags - var/spent = 0 //time we ran the timer. - var/name //for easy debugging. - //cicular doublely linked list + /// Time at which the timer was invoked or destroyed + var/spent = 0 + /// An informative name generated for the timer as its representation in strings, useful for debugging + var/name + /// Next timed event in the bucket var/datum/timedevent/next + /// Previous timed event in the bucket var/datum/timedevent/prev - -/datum/timedevent/New(datum/callback/callBack, wait, flags, hash) + /// The timer subsystem this event is associated with + var/datum/controller/subsystem/timer/timer_subsystem + /// Boolean indicating if timer joined into bucket + var/bucket_joined = FALSE + /// Initial bucket position + var/bucket_pos = -1 + +/datum/timedevent/New(datum/callback/callBack, wait, flags, datum/controller/subsystem/timer/timer_subsystem, hash, source) var/static/nextid = 1 id = TIMER_ID_NULL src.callBack = callBack src.wait = wait src.flags = flags src.hash = hash + src.source = source + src.timer_subsystem = timer_subsystem || SStimer - if (flags & TIMER_CLIENT_TIME) - timeToRun = REALTIMEOFDAY + wait - else - timeToRun = world.time + wait + // Determine time at which the timer's callback should be invoked + timeToRun = (flags & TIMER_CLIENT_TIME ? REALTIMEOFDAY : world.time) + wait + // Include the timer in the hash table if the timer is unique if (flags & TIMER_UNIQUE) - SStimer.hashes[hash] = src + timer_subsystem.hashes[hash] = src + // Generate ID for the timer if the timer is stoppable, include in the timer id dictionary if (flags & TIMER_STOPPABLE) id = num2text(nextid, 100) if (nextid >= TIMER_ID_MAX) - nextid += min(1, 2**round(nextid/TIMER_ID_MAX)) + nextid += min(1, 2 ** round(nextid / TIMER_ID_MAX)) else nextid++ - SStimer.timer_id_dict[id] = src - - name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])" + timer_subsystem.timer_id_dict[id] = src - if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME)) + if ((timeToRun < world.time || timeToRun < timer_subsystem.head_offset) && !(flags & TIMER_CLIENT_TIME)) CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]") if (callBack.object != GLOBAL_PROC && !QDESTROYING(callBack.object)) @@ -350,7 +413,7 @@ SUBSYSTEM_DEF(timer) /datum/timedevent/Destroy() ..() if (flags & TIMER_UNIQUE && hash) - SStimer.hashes -= hash + timer_subsystem.hashes -= hash if (callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers) callBack.object.active_timers -= src @@ -359,12 +422,12 @@ SUBSYSTEM_DEF(timer) callBack = null if (flags & TIMER_STOPPABLE) - SStimer.timer_id_dict -= id + timer_subsystem.timer_id_dict -= id if (flags & TIMER_CLIENT_TIME) if (!spent) spent = world.time - SStimer.clienttime_timers -= src + timer_subsystem.clienttime_timers -= src return QDEL_HINT_IWILLGC if (!spent) @@ -379,64 +442,106 @@ SUBSYSTEM_DEF(timer) prev = null return QDEL_HINT_IWILLGC +/** + * Removes this timed event from any relevant buckets, or the secondary queue + */ /datum/timedevent/proc/bucketEject() - var/bucketpos = BUCKET_POS(src) - var/list/bucket_list = SStimer.bucket_list - var/list/second_queue = SStimer.second_queue + // Store local references for the bucket list and secondary queue + // This is faster than referencing them from the datum itself + var/list/bucket_list = timer_subsystem.bucket_list + var/list/second_queue = timer_subsystem.second_queue + + // Attempt to get the head of the bucket var/datum/timedevent/buckethead - if(bucketpos > 0) - buckethead = bucket_list[bucketpos] + if(bucket_pos > 0) + buckethead = bucket_list[bucket_pos] + + // Decrement the number of timers in buckets if the timed event is + // the head of the bucket, or has a TTR less than TIMER_MAX implying it fits + // into an existing bucket, or is otherwise not present in the secondary queue if(buckethead == src) - bucket_list[bucketpos] = next - SStimer.bucket_count-- - else if(timeToRun < TIMER_MAX || next || prev) - SStimer.bucket_count-- + bucket_list[bucket_pos] = next + timer_subsystem.bucket_count-- + else if(bucket_joined) + timer_subsystem.bucket_count-- else var/l = length(second_queue) second_queue -= src if(l == length(second_queue)) - SStimer.bucket_count-- - if(prev != next) + timer_subsystem.bucket_count-- + + // Remove the timed event from the bucket, ensuring to maintain + // the integrity of the bucket's list if relevant + if (prev && prev.next == src) prev.next = next + if (next && next.prev == src) next.prev = prev - else - prev?.next = null - next?.prev = null prev = next = null - + bucket_pos = -1 + bucket_joined = FALSE + +/** + * Attempts to add this timed event to a bucket, will enter the secondary queue + * if there are no appropriate buckets at this time. + * + * Secondary queueing of timed events will occur when the timespan covered by the existing + * buckets is exceeded by the time at which this timed event is scheduled to be invoked. + * If the timed event is tracking client time, it will be added to a special bucket. + */ /datum/timedevent/proc/bucketJoin() + if(QDELETED(src)) + CRASH("QDELETED timer in bucketJoin! [name]") + // Generate debug-friendly name for timer + var/static/list/bitfield_flags = list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP") + name = "Timer: [id] (\ref[src]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield2list(flags, bitfield_flags), ", ")], \ + callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), \ + callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""]), source: [source]" + + if (bucket_joined) + PRINT_STACK_TRACE("Bucket already joined! [name]") + + // Check if this timed event should be diverted to the client time bucket, or the secondary queue var/list/L - if (flags & TIMER_CLIENT_TIME) - L = SStimer.clienttime_timers - else if (timeToRun >= TIMER_MAX) - L = SStimer.second_queue - + L = timer_subsystem.clienttime_timers + else if (timeToRun >= TIMER_MAX(timer_subsystem)) + L = timer_subsystem.second_queue if(L) - BINARY_INSERT(src, L, datum/timedevent, timeToRun) + BINARY_INSERT(src, L, /datum/timedevent, src, timeToRun, COMPARE_KEY) return - //get the list of buckets - var/list/bucket_list = SStimer.bucket_list + // Get a local reference to the bucket list, this is faster than referencing the datum + var/list/bucket_list = timer_subsystem.bucket_list + + // Find the correct bucket for this timed event + bucket_pos = BUCKET_POS(src) - //calculate our place in the bucket list - var/bucket_pos = BUCKET_POS(src) + if (bucket_pos < timer_subsystem.practical_offset && timeToRun < (timer_subsystem.head_offset + TICKS2DS(BUCKET_LEN))) + log_debug("Bucket pos in past: bucket_pos = [bucket_pos] < practical_offset = [timer_subsystem.practical_offset] \ + && timeToRun = [timeToRun] < [timer_subsystem.head_offset + TICKS2DS(BUCKET_LEN)], Timer: [name]") + bucket_pos = timer_subsystem.practical_offset // Recover bucket_pos to avoid timer blocking queue - //get the bucket for our tick var/datum/timedevent/bucket_head = bucket_list[bucket_pos] - SStimer.bucket_count++ - //empty bucket, we will just add ourselves + timer_subsystem.bucket_count++ + + // If there is no timed event at this position, then the bucket is 'empty' + // and we can just set this event to that position if (!bucket_head) + bucket_joined = TRUE bucket_list[bucket_pos] = src return - //other wise, lets do a simplified linked list add. - if (!bucket_head.prev) - bucket_head.prev = bucket_head + + // Otherwise, we merely add this timed event into the bucket, which is a + // doubly-linked list + bucket_joined = TRUE + bucket_head.prev = src next = bucket_head - prev = bucket_head.prev - next.prev = src - prev.next = src + prev = null + bucket_list[bucket_pos] = src +/** + * Returns a string of the type of the callback for this timer + */ /datum/timedevent/proc/getcallingtype() . = "ERROR" if (callBack.object == GLOBAL_PROC) @@ -444,66 +549,120 @@ SUBSYSTEM_DEF(timer) else . = "[callBack.object.type]" -/proc/addtimer(datum/callback/callback, wait = 0, flags = 0) +/** + * Create a new timer and insert it in the queue. + * You should not call this directly, and should instead use the addtimer macro, which includes source information. + * + * Arguments: + * * callback the callback to call on timer finish + * * wait deciseconds to run the timer for + * * flags flags for this timer, see: code\__DEFINES\subsystems.dm + */ +/proc/_addtimer(datum/callback/callback, wait = 0, flags = 0, datum/controller/subsystem/timer/timer_subsystem, file, line) if (!callback) CRASH("addtimer called without a callback") if (wait < 0) - crash_with("addtimer called with a negative wait. Converting to [world.tick_lag]") + PRINT_STACK_TRACE("addtimer called with a negative wait. Converting to [world.tick_lag]") if (callback.object != GLOBAL_PROC && QDELETED(callback.object) && !QDESTROYING(callback.object)) - crash_with("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait") + PRINT_STACK_TRACE("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not \ + be supported and may refuse to run or run with a 0 wait") + + if (wait == 0 && !(flags & DPC_FORBID_FLAGS)) + SSdpc.queued_calls += callback + return - wait = max(CEILING(wait, world.tick_lag), world.tick_lag) + wait = max(NONUNIT_CEILING(wait, world.tick_lag), world.tick_lag) if(wait >= INFINITY) CRASH("Attempted to create timer with INFINITY delay") - var/hash + timer_subsystem = timer_subsystem || SStimer + // Generate hash if relevant for timed events with the TIMER_UNIQUE flag + var/hash if (flags & TIMER_UNIQUE) - var/list/hashlist - if(flags & TIMER_NO_HASH_WAIT) - hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, flags & TIMER_CLIENT_TIME) - else - hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, wait, flags & TIMER_CLIENT_TIME) + var/list/hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, flags & TIMER_CLIENT_TIME) + if(!(flags & TIMER_NO_HASH_WAIT)) + hashlist += wait hashlist += callback.arguments hash = hashlist.Join("|||||||") - var/datum/timedevent/hash_timer = SStimer.hashes[hash] + var/datum/timedevent/hash_timer = timer_subsystem.hashes[hash] if(hash_timer) - if (hash_timer.spent) //it's pending deletion, pretend it doesn't exist. - hash_timer.hash = null //but keep it from accidentally deleting us + if (hash_timer.spent) // it's pending deletion, pretend it doesn't exist. + hash_timer.hash = null // but keep it from accidentally deleting us else if (flags & TIMER_OVERRIDE) - hash_timer.hash = null //no need having it delete it's hash if we are going to replace it + hash_timer.hash = null // no need having it delete it's hash if we are going to replace it qdel(hash_timer) else if (hash_timer.flags & TIMER_STOPPABLE) . = hash_timer.id return + else + if(wait == 0 || flags & TIMER_NO_HASH_WAIT) + // Check if a unique DPC queued call exists with the same hash + var/datum/callback/dpc_callback = SSdpc.unique_queued_calls[hash] + if(dpc_callback) + if(flags & TIMER_OVERRIDE) + // if this turns out to have too much overhead, could try setting + // the hash's callback to null and then just having SSdpc skip nulls? + SSdpc.unique_queued_calls -= hash + else + return // don't create a timer + // No timer with this hash exists, so we can use the fast unique-DPC path + // Have to make sure it doesn't have illegal flags for unique DPC though + if(wait == 0 && !(flags & UDPC_FORBID_FLAGS)) + SSdpc.unique_queued_calls[hash] = callback + return else if(flags & TIMER_OVERRIDE) - crash_with("TIMER_OVERRIDE used without TIMER_UNIQUE") + PRINT_STACK_TRACE("TIMER_OVERRIDE used without TIMER_UNIQUE") - var/datum/timedevent/timer = new(callback, wait, flags, hash) + var/datum/timedevent/timer = new(callback, wait, flags, timer_subsystem, hash, file && "[file]:[line]") return timer.id -/proc/deltimer(id) +/** + * Delete a timer + * + * Arguments: + * * id a timerid or a /datum/timedevent + */ +/proc/deltimer(id, datum/controller/subsystem/timer/timer_subsystem) if (!id) return FALSE if (id == TIMER_ID_NULL) CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag") - if (!istext(id)) - if (istype(id, /datum/timedevent)) - qdel(id) - return TRUE + if (istype(id, /datum/timedevent)) + qdel(id) + return TRUE + timer_subsystem = timer_subsystem || SStimer //id is string - var/datum/timedevent/timer = SStimer.timer_id_dict[id] - if (timer && !timer.spent) + var/datum/timedevent/timer = timer_subsystem.timer_id_dict[id] + if (timer && (!timer.spent || timer.flags & TIMER_LOOP)) qdel(timer) return TRUE return FALSE +/** + * Get the remaining deciseconds on a timer + * + * Arguments: + * * id a timerid or a /datum/timedevent + */ +/proc/timeleft(id, datum/controller/subsystem/timer/timer_subsystem) + if (!id) + return null + if (id == TIMER_ID_NULL) + CRASH("Tried to get timeleft of a null timerid. Use TIMER_STOPPABLE flag") + if (istype(id, /datum/timedevent)) + var/datum/timedevent/timer = id + return timer.timeToRun - world.time + timer_subsystem = timer_subsystem || SStimer + //id is string + var/datum/timedevent/timer = timer_subsystem.timer_id_dict[id] + return (timer && !timer.spent) ? timer.timeToRun - world.time : null #undef BUCKET_LEN #undef BUCKET_POS diff --git a/code/controllers/subsystems/trade.dm b/code/controllers/subsystems/trade.dm index 3391aa6e2d80..158bd301afe9 100644 --- a/code/controllers/subsystems/trade.dm +++ b/code/controllers/subsystems/trade.dm @@ -2,55 +2,30 @@ SUBSYSTEM_DEF(trade) name = "Trade" wait = 1 MINUTE priority = SS_PRIORITY_TRADE - //Initializes at default time + init_order = SS_INIT_MISC_LATE - var/list/traders = list() - var/tmp/list/current_traders - var/max_traders = 10 + var/list/trade_hubs = list() + var/tmp/t_ind = 1 + var/tmp/list/processing_trade_hubs /datum/controller/subsystem/trade/Initialize() . = ..() - for(var/i in 1 to rand(1,3)) - generate_trader(1) + global.using_map.create_trade_hubs() /datum/controller/subsystem/trade/fire(resumed = FALSE) - if (!resumed) - current_traders = traders.Copy() - while(current_traders.len) - var/datum/trader/T = current_traders[current_traders.len] - current_traders.len-- + if(!resumed) + processing_trade_hubs = trade_hubs.Copy() + t_ind = 1 - if(!T.tick()) - traders -= T - qdel(T) - if (MC_TICK_CHECK) + while(t_ind <= processing_trade_hubs.len) + var/datum/trade_hub/hub = processing_trade_hubs[t_ind++] + hub.Process(resumed) + if(MC_TICK_CHECK) return - if((traders.len <= max_traders) && prob(100 - 50 * traders.len / max_traders)) - generate_trader() - /datum/controller/subsystem/trade/stat_entry() - ..("Traders: [traders.len]") - -/datum/controller/subsystem/trade/proc/generate_trader(var/stations = 0) - var/list/possible = list() - if(stations) - possible += subtypesof(/datum/trader) - typesof(/datum/trader/ship) - else - if(prob(5)) - possible += subtypesof(/datum/trader/ship/unique) - else - possible += subtypesof(/datum/trader/ship) - typesof(/datum/trader/ship/unique) - - for(var/i in 1 to 10) - var/type = pick(possible) - var/bad = 0 - for(var/trader in traders) - if(istype(trader,type)) - bad = 1 - break - if(bad) - continue - traders += new type - return \ No newline at end of file + var/traders = 0 + for(var/datum/trade_hub/hub in trade_hubs) + traders += length(hub.traders) + ..("Hubs: [length(trade_hubs)], traders: [traders]") diff --git a/code/controllers/subsystems/typing.dm b/code/controllers/subsystems/typing.dm new file mode 100644 index 000000000000..462bf0b5de19 --- /dev/null +++ b/code/controllers/subsystems/typing.dm @@ -0,0 +1,205 @@ +SUBSYSTEM_DEF(typing) + name = "Typing" + flags = SS_BACKGROUND + wait = 0.5 SECONDS + + /// The skin control to poll for TYPING_STATE_INPUT status. + var/const/INPUT_HANDLE = "outputwindow.input" + var/const/INFLIGHT_TIMEOUT = 5 SECONDS + /// The status entry index of the related client's typing indicator visibility preference. + var/const/INDEX_PREFERENCE = 1 + /// The status entry index of the inflight state. + var/const/INDEX_INFLIGHT = 2 + /// The status entry index of the timeout threshold. + var/const/INDEX_TIMEOUT = 3 + /// The status entry index of the input bar typing state. + var/const/INDEX_INPUT_STATE = 4 + /// The status entry index of the verb input typing state. + var/const/INDEX_VERB_STATE = 5 + /// The highest index in a status entry. + var/const/MAX_INDEX = 5 + /// Matches input bar verbs that should set TYPING_STATE_INPUT. + var/static/regex/match_verbs + /// A list of clients waiting to be polled for input state. + var/list/client/queue = list() + /// A list of ckey to list, containing current state data. See get_entry() for details. + var/list/status = list() + /* example of an entry: + (ckey = list( + preference = 0|1, + inflight = 0|1, + timeout = num, + istyping_input = 0|1, + istyping_hotkey = 0|1 + ), ...) + */ + +/datum/controller/subsystem/typing/Initialize(start_timeofday) + if(get_config_value(/decl/config/toggle/show_typing_indicator_for_whispers)) + match_verbs = regex("^(Me|Say|Whisper) +\"?\\w+") + else + match_verbs = regex("^(Me|Say) +\"?\\w+") + . = ..() + +/datum/controller/subsystem/typing/Recover() + status = list() + queue = list() + +/datum/controller/subsystem/typing/fire(resumed, no_mc_tick) + if(!resumed) + queue = global.clients.Copy() + if(!length(queue)) + return + var/cut_until = 1 + var/list/entry + for (var/client/client as anything in queue) + ++cut_until + if(QDELETED(client)) + continue + entry = get_client_record(client) + if(!islist(entry) || !entry[INDEX_PREFERENCE]) + continue + if(!entry[INDEX_INFLIGHT]) + update_indicator_state_from_winget(client, entry) + else if(world.time < entry[INDEX_TIMEOUT]) + entry[INDEX_INFLIGHT] = FALSE + if(no_mc_tick) + CHECK_TICK + else if(MC_TICK_CHECK) + queue.Cut(1, cut_until) + return + queue.Cut() + +/// Return, generating if necessary, a ckey-indexed list holding typing status. +/datum/controller/subsystem/typing/proc/get_client_record(client/client) + PRIVATE_PROC(TRUE) + var/ckey + if(istext(client)) + ckey = client + else if(istype(client)) + ckey = client.ckey + else + return + var/list/entry = status[ckey] + if(!entry) + entry = new (MAX_INDEX) + entry[INDEX_PREFERENCE] = client.get_preference_value(/datum/client_preference/show_typing_indicator) == PREF_SHOW + entry[INDEX_INFLIGHT] = FALSE + entry[INDEX_TIMEOUT] = world.time + entry[INDEX_INPUT_STATE] = FALSE + entry[INDEX_VERB_STATE] = FALSE + status[ckey] = entry + return entry + +/// Updates client's preference bool for whether typing indicators should be shown. +/datum/controller/subsystem/typing/proc/update_preference(client/client, preference) + var/list/entry = get_client_record(client) + if(islist(entry)) + entry[INDEX_PREFERENCE] = preference + update_indicator(client, entry) + +/// Updates client|ckey's verb typing state to new_state. +/datum/controller/subsystem/typing/proc/set_indicator_state(client/client, state) + var/list/entry = get_client_record(client) + if(islist(entry)) + entry[INDEX_VERB_STATE] = state + update_indicator(client, entry) + +/// Request client's input bar state using winget and updating entry accordingly. +/datum/controller/subsystem/typing/proc/update_indicator_state_from_winget(client/client, list/entry) + PRIVATE_PROC(TRUE) + set waitfor = FALSE + var/timeout = world.time + INFLIGHT_TIMEOUT + entry[INDEX_INFLIGHT] = TRUE + entry[INDEX_TIMEOUT] = timeout + var/content = winget(client, INPUT_HANDLE, "text") + if(timeout != entry[INDEX_TIMEOUT]) // We're stale. Touch nothing. + return + entry[INDEX_INFLIGHT] = FALSE + if(!QDELETED(client)) + entry[INDEX_INPUT_STATE] = match_verbs.Find(content) != 0 + update_indicator(client, entry) + +/// Attempt to update the mob's typing state and indicator according to new state. +/datum/controller/subsystem/typing/proc/update_indicator(client/client, list/entry) + PRIVATE_PROC(TRUE) + var/mob/target = client.mob + var/display = target.stat == CONSCIOUS && entry[INDEX_PREFERENCE] && (entry[INDEX_INPUT_STATE] || entry[INDEX_VERB_STATE]) && !target.is_cloaked() && isturf(target.loc) + if(display == target.is_typing) + return + if(display) + if(!target.typing_indicator) + target.typing_indicator = new(null, target) + target.is_typing = TRUE + target.typing_indicator.show_typing_indicator() + else if(target.typing_indicator) + target.is_typing = FALSE + target.typing_indicator.hide_typing_indicator() + +/* +Typing indicators, when a mob uses the F3/F4 keys to bring the say/emote input boxes up this little buddy is +made and follows them around until they are done (or something bad happens), helps tell nearby people that 'hey! +I IS TYPIN'!' +Updated 09/10/2022 to include chatbar using Spookerton's SStyping system from Polaris. +*/ + +/atom/movable/typing_indicator + icon = 'icons/mob/talk.dmi' + icon_state = "typing" + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + vis_flags = VIS_INHERIT_ID + var/atom/movable/master + +/atom/movable/typing_indicator/Initialize(ml, _master) + . = ..() + master = _master + if(!ismovable(master)) + PRINT_STACK_TRACE("Typing indicator initialized with [isnull(master) ? "null" : master] as master.") + return INITIALIZE_HINT_QDEL + +/atom/movable/typing_indicator/Destroy() + if(master) + master.remove_vis_contents(src) + if(ismob(master)) + var/mob/owner = master + if(owner.typing_indicator == src) + owner.typing_indicator = null + return ..() + +/atom/movable/typing_indicator/proc/hide_typing_indicator() + set waitfor = FALSE + if(ismob(master)) + var/mob/owner = master + if(owner.is_typing) + return + animate(src, alpha = 0, time = 0.5 SECONDS, easing = EASE_IN) + sleep(0.5 SECONDS) + set_invisibility(INVISIBILITY_MAXIMUM) + if(ismovable(master)) + var/atom/movable/owner = master + owner.remove_vis_contents(src) + +/atom/movable/typing_indicator/proc/show_typing_indicator() + + // Make it visible after being hidden. + set_invisibility(INVISIBILITY_NONE) + + // Update the appearance. + if(ismob(master)) + var/mob/owner = master + var/speech_state_modifier = owner.get_speech_bubble_state_modifier() + if(speech_state_modifier) + icon_state = "[speech_state_modifier]_typing" + else + icon_state = initial(icon_state) + + if(ismovable(master)) + var/atom/movable/owner = master + owner.add_vis_contents(src) + + // Animate it popping up from nowhere. + var/matrix/M = matrix() + M.Scale(0, 0) + transform = M + alpha = 0 + animate(src, transform = 0, alpha = 255, time = 0.2 SECONDS, easing = EASE_IN) diff --git a/code/controllers/subsystems/vis_contents.dm b/code/controllers/subsystems/vis_contents.dm new file mode 100644 index 000000000000..3cafe0983796 --- /dev/null +++ b/code/controllers/subsystems/vis_contents.dm @@ -0,0 +1,92 @@ +SUBSYSTEM_DEF(vis_contents_update) + name = "Vis Contents" + flags = SS_BACKGROUND + wait = 1 + priority = SS_PRIORITY_VIS_CONTENTS + init_order = SS_INIT_VIS_CONTENTS + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + var/list/queue_refs = list() + +/datum/controller/subsystem/vis_contents_update/stat_entry() + ..("Queue: [queue_refs.len]") + +/datum/controller/subsystem/vis_contents_update/Initialize() + fire(FALSE, TRUE) + +/datum/controller/subsystem/vis_contents_update/StartLoadingMap() + suspend() + +/datum/controller/subsystem/vis_contents_update/StopLoadingMap() + wake() + +// Largely copied from SSicon_update. +/datum/controller/subsystem/vis_contents_update/fire(resumed = FALSE, no_mc_tick = FALSE) + var/list/cached_refs = queue_refs // cache the instance var for more speed + if(!length(cached_refs)) + suspend() + return + var/i = 0 + while (i < length(cached_refs)) + if(Master.map_loading) + break + var/atom/A = cached_refs[++i] + if(QDELETED(A)) + continue + A.vis_update_queued = FALSE + A.update_vis_contents() + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + break + cached_refs.Cut(1, i+1) + +/atom + var/vis_update_queued = FALSE + +/atom/proc/queue_vis_contents_update() + if(vis_update_queued) + return + vis_update_queued = TRUE + SSvis_contents_update.queue_refs[++SSvis_contents_update.queue_refs.len] = src + if(SSvis_contents_update.suspended && !Master.map_loading) // Don't wake early if we're loading a map, it'll get woken up when the map loads. + SSvis_contents_update.wake() + +// Horrible colon syntax below is because vis_contents +// exists in /atom.vars, but will not compile. No idea why. +/atom/proc/add_vis_contents(adding) + src:vis_contents |= adding + +/atom/proc/remove_vis_contents(removing) + src:vis_contents -= removing + +/atom/proc/clear_vis_contents() + src:vis_contents = null + +/atom/proc/set_vis_contents(list/adding) + src:vis_contents = adding + +/atom/proc/get_vis_contents_to_add() + return + +/atom/proc/update_vis_contents() + if(Master.map_loading || SSvis_contents_update.init_state == SS_INITSTATE_NONE || TICK_CHECK) + queue_vis_contents_update() + return + vis_update_queued = FALSE + var/new_vis_contents = get_vis_contents_to_add() + if(length(new_vis_contents)) + set_vis_contents(new_vis_contents) + else if(length(src:vis_contents)) + clear_vis_contents() + +/image/proc/add_vis_contents(adding) + vis_contents |= adding + +/image/proc/remove_vis_contents(removing) + vis_contents -= removing + +/image/proc/clear_vis_contents() + vis_contents.Cut() + +/image/proc/set_vis_contents(list/adding) + vis_contents = adding diff --git a/code/controllers/subsystems/vote.dm b/code/controllers/subsystems/vote.dm index dc87008aabb8..5acccf7afe08 100644 --- a/code/controllers/subsystems/vote.dm +++ b/code/controllers/subsystems/vote.dm @@ -12,7 +12,7 @@ SUBSYSTEM_DEF(vote) var/list/old_votes //Stores completed votes for reference. var/queued_auto_vote //Used if a vote queues another vote to happen after it. - var/list/voting = list() //Clients recieving UI updates. + var/list/voting = list() //Clients receiving UI updates. var/list/vote_prototypes //To run checks on whether they are available. /datum/controller/subsystem/vote/Initialize() @@ -62,18 +62,22 @@ SUBSYSTEM_DEF(vote) //A false return means that a vote couldn't be started. /datum/controller/subsystem/vote/proc/initiate_vote(vote_type, mob/creator, automatic = 0) + set waitfor = FALSE if(active_vote) + to_chat(creator, SPAN_WARNING("There is already a vote in progress.")) return FALSE if(!automatic && (!istype(creator) || !creator.client)) return FALSE if(last_started_time != null && !(is_admin(creator) || automatic)) - var/next_allowed_time = (last_started_time + config.vote_delay) + var/next_allowed_time = (last_started_time + get_config_value(/decl/config/num/vote_delay)) if(next_allowed_time > world.time) + to_chat(creator, SPAN_WARNING("Another vote cannot be run so soon.")) return FALSE var/datum/vote/new_vote = new vote_type if(!new_vote.setup(creator, automatic)) + to_chat(creator, SPAN_WARNING("The selected vote could not be set up or run.")) return FALSE active_vote = new_vote @@ -91,12 +95,12 @@ SUBSYSTEM_DEF(vote) if(active_vote) . += active_vote.interface(C.mob) if(admin) - . += "(Cancel Vote) " + . += "(Cancel Vote) " else . += "

Start a vote:



" - . += "Close" + . += "Close" return JOINTEXT(.) /datum/controller/subsystem/vote/proc/show_panel(mob/user, force_open) @@ -175,7 +179,7 @@ SUBSYSTEM_DEF(vote) // Helper proc for determining whether addantag vote can be called. /datum/controller/subsystem/vote/proc/is_addantag_allowed(mob/creator, automatic) - if(!config.allow_extra_antags) + if(!get_config_value(/decl/config/toggle/allow_extra_antags)) return 0 // Gamemode has to be determined before we can add antagonists, so we can respect gamemode's add antag vote settings. if((GAME_STATE <= RUNLEVEL_SETUP) || !SSticker.mode) diff --git a/code/controllers/subsystems/weather.dm b/code/controllers/subsystems/weather.dm new file mode 100644 index 000000000000..5f4a06f4053a --- /dev/null +++ b/code/controllers/subsystems/weather.dm @@ -0,0 +1,65 @@ +SUBSYSTEM_DEF(weather) + name = "Weather" + wait = 15 SECONDS + init_order = SS_INIT_WEATHER + priority = SS_PRIORITY_WEATHER + flags = SS_BACKGROUND + + var/list/weather_systems = list() + var/list/weather_by_z = list() + var/list/processing_systems + +/datum/controller/subsystem/weather/stat_entry() + ..("all systems: [length(weather_systems)], processing systems: [length(processing_systems)]") + +/datum/controller/subsystem/weather/Initialize(start_timeofday) + . = ..() + for(var/obj/abstract/weather_system/weather as anything in weather_systems) + weather.init_weather() + +/datum/controller/subsystem/weather/fire(resumed) + + if(!resumed) + processing_systems = weather_systems.Copy() + + var/obj/abstract/weather_system/weather + while(processing_systems.len) + weather = processing_systems[processing_systems.len] + processing_systems.len-- + weather.tick() + if(MC_TICK_CHECK) + return + +///Sets a weather state to use for a given z level/z level stack. topmost_level may be a level_id or a level_data instance. +/datum/controller/subsystem/weather/proc/setup_weather_system(var/datum/level_data/topmost_level, var/decl/state/weather/initial_state, list/banned_states) + if(istext(topmost_level)) + topmost_level = SSmapping.levels_by_id[topmost_level] + + //First check and clear any existing weather system on the level + var/obj/abstract/weather_system/WS = weather_by_z[topmost_level.level_z] + if(WS) + unregister_weather_system(WS) + qdel(WS) + //Create the new weather system and let it register itself + new /obj/abstract/weather_system(locate(1, 1, topmost_level.level_z), topmost_level.level_z, initial_state, banned_states) + +///Registers a given weather system obj for getting updates by SSweather. +/datum/controller/subsystem/weather/proc/register_weather_system(var/obj/abstract/weather_system/WS) + if(weather_by_z[WS.z]) + CRASH("Trying to register another weather system on the same z-level([WS.z]) as an existing one!") + weather_systems |= WS + + //Mark all affected z-levels + var/list/affected = SSmapping.get_connected_levels(WS.z) + for(var/Z in affected) + if(weather_by_z[Z]) + CRASH("Trying to register another weather system on the same z-level([Z]) as an existing one!") + weather_by_z[Z] = WS + +///Remove a weather systeam from the processing lists. +/datum/controller/subsystem/weather/proc/unregister_weather_system(var/obj/abstract/weather_system/WS) + //Clear any and all references to our weather object + for(var/Z = 1 to length(weather_by_z)) + if(weather_by_z[Z] == WS) + weather_by_z[Z] = null + weather_systems -= WS diff --git a/code/controllers/subsystems/weather_atoms.dm b/code/controllers/subsystems/weather_atoms.dm new file mode 100644 index 000000000000..d03ad6c63e28 --- /dev/null +++ b/code/controllers/subsystems/weather_atoms.dm @@ -0,0 +1,55 @@ +SUBSYSTEM_DEF(weather_atoms) + name = "Weather Atoms" + wait = 2 SECONDS + priority = SS_PRIORITY_WEATHER + flags = SS_NO_INIT + var/list/weather_atoms = list() + var/list/processing_atoms + + // Predeclared vars for processing. + var/atom/atom + var/obj/abstract/weather_system/weather + var/decl/state/weather/weather_state + +/datum/controller/subsystem/weather_atoms/stat_entry() + ..("A:[weather_atoms.len]") + +/datum/controller/subsystem/weather_atoms/fire(resumed = 0) + if(!resumed) + processing_atoms = weather_atoms.Copy() + + atom = null + weather = null + weather_state = null + + var/i = 0 + while(i < processing_atoms.len) + i++ + atom = processing_atoms[i] + + // Atom is null or doesn't exist, remove it from processing. + if(QDELETED(atom)) + weather_atoms -= atom + continue + + // Not outside, or not on a turf with a Z- weather is not relevant. + if(!atom.z || !atom.is_outside()) + continue + + // If weather does not exist, we don't care. + weather = atom.get_affecting_weather() + weather_state = weather?.weather_system?.current_state + if(!istype(weather_state)) + continue + + // Process the atom and return early if needed. + if(atom.process_weather(weather, weather_state) == PROCESS_KILL) + weather_atoms -= atom + if (MC_TICK_CHECK) + processing_atoms.Cut(1, i+1) + return + + processing_atoms.Cut() + +/atom/proc/process_weather(obj/abstract/weather_system/weather, decl/state/weather/weather_state) + return PROCESS_KILL diff --git a/code/controllers/subsystems/xenoarch.dm b/code/controllers/subsystems/xenoarch.dm index 546ed870dccd..c660218246e7 100644 --- a/code/controllers/subsystems/xenoarch.dm +++ b/code/controllers/subsystems/xenoarch.dm @@ -12,35 +12,15 @@ SUBSYSTEM_DEF(xenoarch) init_order = SS_INIT_XENOARCH flags = SS_NO_FIRE var/list/artifact_spawning_turfs = list() - var/list/digsite_spawning_turfs = list() - var/list/digsite_types_weighted = list() + var/list/digsite_spawning_turfs = list() + var/list/digsite_types_weighted = list() + var/list/possible_spawn_walls = list() /datum/controller/subsystem/xenoarch/Initialize(timeofday) - SetupXenoarch() - ..() -/datum/controller/subsystem/xenoarch/Recover() - if (istype(SSxenoarch.artifact_spawning_turfs)) - artifact_spawning_turfs = SSxenoarch.artifact_spawning_turfs - if (istype(SSxenoarch.digsite_spawning_turfs)) - digsite_spawning_turfs = SSxenoarch.digsite_spawning_turfs - -/datum/controller/subsystem/xenoarch/proc/get_random_digsite_type() - if(!digsite_types_weighted.len) - var/list/digsites = decls_repository.get_decls_of_type(/decl/xenoarch_digsite) - for(var/D in digsites) - var/decl/xenoarch_digsite/digsite = digsites[D] - digsite_types_weighted[D] = digsite.weight - return pickweight(digsite_types_weighted) - -/datum/controller/subsystem/xenoarch/proc/SetupXenoarch() - for(var/turf/simulated/wall/natural/M in global.natural_walls) - if(!M.density) - continue - - if(!prob(XENOARCH_SPAWN_CHANCE)) + for(var/turf/wall/natural/M in possible_spawn_walls) + if(QDELETED(M) || !M.density || M.ramp_slope_direction || !prob(XENOARCH_SPAWN_CHANCE)) continue - var/farEnough = 1 for(var/A in digsite_spawning_turfs) var/turf/T = A @@ -60,13 +40,16 @@ SUBSYSTEM_DEF(xenoarch) var/list/viable_adjacent_turfs = list() if(target_digsite_size > 1) - for(var/turf/simulated/wall/natural/T in orange(2, M)) + for(var/turf/wall/natural/T in orange(2, M)) if(!T.density) continue if(T.finds) continue if(T in processed_turfs) continue + var/area/A = get_area(T) + if(!A.allow_xenoarchaeology_finds) + continue viable_adjacent_turfs.Add(T) target_digsite_size = min(target_digsite_size, viable_adjacent_turfs.len) @@ -75,8 +58,9 @@ SUBSYSTEM_DEF(xenoarch) turfs_to_process += pick_n_take(viable_adjacent_turfs) while(turfs_to_process.len) - var/turf/simulated/wall/natural/archeo_turf = pop(turfs_to_process) - + var/turf/wall/natural/archeo_turf = pop(turfs_to_process) + if(!istype(archeo_turf)) + continue processed_turfs.Add(archeo_turf) if(isnull(archeo_turf.finds)) archeo_turf.finds = list() @@ -93,29 +77,45 @@ SUBSYSTEM_DEF(xenoarch) //sometimes a find will be close enough to the surface to show var/datum/find/F = archeo_turf.finds[1] if(F.excavation_required <= F.view_range) - archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]" + archeo_turf.archaeo_overlay = image('icons/turf/excavation_overlays.dmi',"overlay_archaeo[rand(1,3)]") archeo_turf.update_icon() //have a chance for an artifact to spawn here, but not in animal or plant digsites - - var/decl/xenoarch_digsite/D = decls_repository.get_decl(digsite) + var/decl/xenoarch_digsite/D = GET_DECL(digsite) if(isnull(M.artifact_find) && D.can_have_anomalies) artifact_spawning_turfs.Add(archeo_turf) CHECK_TICK + possible_spawn_walls.Cut() + //create artifact machinery var/num_artifacts_spawn = rand(ARTIFACTSPAWNNUM_LOWER, ARTIFACTSPAWNNUM_UPPER) var/list/final_artifact_spawning_turfs = list() for(var/i = 1 to num_artifacts_spawn) final_artifact_spawning_turfs += pick_n_take(artifact_spawning_turfs) artifact_spawning_turfs = final_artifact_spawning_turfs - for(var/turf/simulated/wall/natural/artifact_turf in artifact_spawning_turfs) + for(var/turf/wall/natural/artifact_turf in artifact_spawning_turfs) artifact_turf.artifact_find = new() + ..() + +/datum/controller/subsystem/xenoarch/Recover() + if (istype(SSxenoarch.artifact_spawning_turfs)) + artifact_spawning_turfs = SSxenoarch.artifact_spawning_turfs + if (istype(SSxenoarch.digsite_spawning_turfs)) + digsite_spawning_turfs = SSxenoarch.digsite_spawning_turfs + +/datum/controller/subsystem/xenoarch/proc/get_random_digsite_type() + if(!digsite_types_weighted.len) + var/list/digsites = decls_repository.get_decls_of_subtype(/decl/xenoarch_digsite) + for(var/D in digsites) + var/decl/xenoarch_digsite/digsite = digsites[D] + digsite_types_weighted[D] = digsite.weight + return pickweight(digsite_types_weighted) /datum/controller/subsystem/xenoarch/proc/get_nearest_artifact(var/turf/source) var/artifact_distance = INFINITY - var/artifact_id - for(var/turf/simulated/wall/natural/T in artifact_spawning_turfs) + var/artifact_id + for(var/turf/wall/natural/T in artifact_spawning_turfs) if(T.artifact_find) var/cur_dist = get_dist(source, T) * 2 if(cur_dist < artifact_distance) diff --git a/code/controllers/subsystems/zcopy.dm b/code/controllers/subsystems/zcopy.dm index c260e86e5f09..e0dfe3f0b1cb 100644 --- a/code/controllers/subsystems/zcopy.dm +++ b/code/controllers/subsystems/zcopy.dm @@ -1,6 +1,25 @@ +/* + + Here be dragons. + +*/ + #define OPENTURF_MAX_PLANE -70 #define OPENTURF_MAX_DEPTH 10 // The maxiumum number of planes deep we'll go before we just dump everything on the same plane. #define SHADOWER_DARKENING_FACTOR 0.6 // The multiplication factor for openturf shadower darkness. Lighting will be multiplied by this. +#define SHADOWER_DARKENING_COLOR "#999999" // The above, but as an RGB string for lighting-less turfs. + +//#define ZM_RECORD_STATS // This doesn't work on O7/Neb right now. + +#ifdef ZM_RECORD_STATS +#define ZM_RECORD_START STAT_START_STOPWATCH +#define ZM_RECORD_STOP STAT_STOP_STOPWATCH +#define ZM_RECORD_WRITE(X...) STAT_LOG_ENTRY(##X) +#else +#define ZM_RECORD_START +#define ZM_RECORD_STOP +#define ZM_RECORD_WRITE(X...) +#endif SUBSYSTEM_DEF(zcopy) name = "Z-Copy" @@ -17,9 +36,32 @@ SUBSYSTEM_DEF(zcopy) var/openspace_overlays = 0 var/openspace_turfs = 0 - // Highest Z level in a given Z-group for absolute layering used by FIX_BIGTURF. + var/multiqueue_skips_turf = 0 + var/multiqueue_skips_discovery = 0 + var/multiqueue_skips_object = 0 + + var/total_updates_turf = 0 + var/total_updates_discovery = 0 + var/total_updates_object = 0 + +#ifdef ZM_RECORD_STATS + var/list/turf_stats = list() + var/list/discovery_stats = list() + var/list/mimic_stats = list() +#endif + + // Highest Z level in a given Z-group for absolute layering. // zstm[zlev] = group_max - var/list/zstack_maximums = list() + var/list/zlev_maximums = list() + + // Caches for fixup. + var/list/fixup_cache = list() + var/list/fixup_known_good = list() + + // Fixup stats. + var/fixup_miss = 0 + var/fixup_noop = 0 + var/fixup_hit = 0 // for admin proc-call /datum/controller/subsystem/zcopy/proc/update_all() @@ -30,6 +72,7 @@ SUBSYSTEM_DEF(zcopy) var/num_upd = 0 var/num_del = 0 var/num_amupd = 0 + for (var/atom/A in world) if (isturf(A)) T = A @@ -37,9 +80,9 @@ SUBSYSTEM_DEF(zcopy) T.update_mimic() num_upd += 1 - else if (istype(A, /atom/movable/openspace/overlay)) + else if (istype(A, /atom/movable/openspace/mimic)) var/turf/Tloc = A.loc - if (TURF_IS_MIMICING(Tloc)) + if (TURF_IS_MIMICKING(Tloc)) Tloc.update_mimic() num_amupd += 1 else @@ -59,6 +102,15 @@ SUBSYSTEM_DEF(zcopy) var/num_deleted = 0 var/num_turfs = 0 + for (var/turf/T in world) + if (T.z_queued) + T.z_queued = 0 + + CHECK_TICK + + queued_turfs.Cut() + queued_overlays.Cut() + var/turf/T for (var/atom/A in world) if (isturf(A)) @@ -67,7 +119,7 @@ SUBSYSTEM_DEF(zcopy) T.update_mimic() num_turfs += 1 - else if (istype(A, /atom/movable/openspace/overlay)) + else if (istype(A, /atom/movable/openspace/mimic)) qdel(A) num_deleted += 1 @@ -78,25 +130,59 @@ SUBSYSTEM_DEF(zcopy) enable() /datum/controller/subsystem/zcopy/stat_entry() - ..("Q:{T:[queued_turfs.len - (qt_idex - 1)]|O:[queued_overlays.len - (qo_idex - 1)]} T:{T:[openspace_turfs]|O:[openspace_overlays]}") + var/list/entries = list( + "", // newline + "ZSt: [build_zstack_display()]", // This is a human-readable list of the z-stacks known to ZM. + "ZMx: [zlev_maximums.Join(", ")]", // And this is the raw internal state. + // This one gets broken out from the below because it's more important. + "Q: { T: [queued_turfs.len - (qt_idex - 1)] O: [queued_overlays.len - (qo_idex - 1)] }", + // In order: Total, Queued, Skipped + "T(O): { T: [openspace_turfs] O: [openspace_overlays] }", + "T(U): { T: [total_updates_turf] D: [total_updates_discovery] O: [total_updates_object] }", + "Sk: { T: [multiqueue_skips_turf] D: [multiqueue_skips_discovery] O: [multiqueue_skips_object] }", + "F: { H: [fixup_hit] M: [fixup_miss] N: [fixup_noop] FC: [fixup_cache.len] FKG: [fixup_known_good.len] }" + ) + ..(entries.Join("\n\t")) + +// 1, 2, 3..=7, 8 +/datum/controller/subsystem/zcopy/proc/build_zstack_display() + if (!zlev_maximums.len) + return "" + var/list/zmx = list() + var/idx = 1 + var/span_ctr = 0 + do + if (zlev_maximums[idx] != idx) + span_ctr += 1 + else if (span_ctr) + zmx += "[idx - span_ctr]..=[idx]" + span_ctr = 0 + else + zmx += "[idx]" + idx += 1 + while (idx <= zlev_maximums.len) + return jointext(zmx, ", ") /datum/controller/subsystem/zcopy/Initialize(timeofday) calculate_zstack_limits() // Flush the queue. fire(FALSE, TRUE) - return ..() // If you add a new Zlevel or change Z-connections, call this. /datum/controller/subsystem/zcopy/proc/calculate_zstack_limits() - zstack_maximums = new(world.maxz) + zlev_maximums = new(world.maxz) var/start_zlev = 1 for (var/z in 1 to world.maxz) if (!HasAbove(z)) for (var/member_zlev in start_zlev to z) - zstack_maximums[member_zlev] = z + zlev_maximums[member_zlev] = z + if (z - start_zlev > OPENTURF_MAX_DEPTH) + log_ss("zcopy", "WARNING: Z-levels [start_zlev] through [z] exceed maximum depth of [OPENTURF_MAX_DEPTH]; layering may behave strangely in this Z-stack.") + else if (z - start_zlev > 1) + log_ss("zcopy", "Found Z-Stack: [start_zlev] -> [z] = [z - start_zlev + 1] zl") start_zlev = z + 1 - log_ss("zcopy", "Z-Stack maximums: [json_encode(zstack_maximums)]") + log_ss("zcopy", "Z-Level maximums: [json_encode(zlev_maximums)]") /datum/controller/subsystem/zcopy/StartLoadingMap() suspend() @@ -104,6 +190,24 @@ SUBSYSTEM_DEF(zcopy) /datum/controller/subsystem/zcopy/StopLoadingMap() wake() +/// Fully reset Z-Mimic, rebuilding state from scratch. Use this if you change Z-stack mappings after Z-Mimic has initialized. Expensive. +/datum/controller/subsystem/zcopy/proc/RebuildZState() + suspend() + UNTIL(state == SS_IDLE) + + calculate_zstack_limits() + + for (var/zlev in 1 to world.maxz) + var/datum/level_data/level = SSmapping.levels_by_z[zlev] + for (var/turf/T as anything in block(level.level_inner_min_x, level.level_inner_min_y, zlev, level.level_inner_max_x, level.level_inner_max_y)) + if (T.z_flags & ZM_MIMIC_BELOW) + flush_z_state(T) + T.below = GetAbove(T) + T.above = GetBelow(T) + T.update_mimic() + CHECK_TICK + wake() + /datum/controller/subsystem/zcopy/fire(resumed = FALSE, no_mc_tick = FALSE) if (!resumed) qt_idex = 1 @@ -113,15 +217,60 @@ SUBSYSTEM_DEF(zcopy) if (!no_mc_tick) MC_SPLIT_TICK + tick_turfs(no_mc_tick) + + if (!no_mc_tick) + MC_SPLIT_TICK + + tick_mimic(no_mc_tick) + +// - Turf mimic - +/datum/controller/subsystem/zcopy/proc/tick_turfs(no_mc_tick) var/list/curr_turfs = queued_turfs - var/list/curr_ov = queued_overlays while (qt_idex <= curr_turfs.len) var/turf/T = curr_turfs[qt_idex] curr_turfs[qt_idex] = null qt_idex += 1 - if (!isturf(T) || !T.below || !(T.z_flags & ZM_MIMIC_BELOW)) + if (!isturf(T) || !(T.z_flags & ZM_MIMIC_BELOW) || !T.z_queued) + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + break + continue + + // If we're not at our most recent queue position, don't bother -- we're updating again later anyways. + if (T.z_queued > 1) + T.z_queued -= 1 + multiqueue_skips_turf += 1 + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + break + continue + + // Z-Turf on the bottom-most level, just fake-copy space (or baseturf). + // It's impossible for anything to be on the synthetic turf, so ignore the rest of the ZM machinery. + if (!T.below) + ZM_RECORD_START + flush_z_state(T) + if (T.z_flags & ZM_OVERRIDE) + simple_appearance_copy(T, get_base_turf_by_area(T), OPENTURF_MAX_PLANE) + else + simple_appearance_copy(T, SSskybox.dust_cache["[((T.x + T.y) ^ ~(T.x * T.y) + T.z) % 25]"]) + + T.z_generation += 1 + T.z_queued -= 1 + total_updates_turf += 1 + + if (T.above) + T.above.update_mimic() + + ZM_RECORD_STOP + ZM_RECORD_WRITE(turf_stats, "Fake: [T.type] on [T.z]") + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -132,30 +281,56 @@ SUBSYSTEM_DEF(zcopy) WARNING("Turf [T] at [T.x],[T.y],[T.z] was queued, but had no shadower.") continue - // Figure out how many z-levels down we are. - var/depth = 0 - var/turf/Td = T + T.z_generation += 1 + + ZM_RECORD_START - while (Td.below) + // Get the bottom-most turf, the one we want to mimic. + // Baseturf mimics act as false bottoms of the stack. + var/turf/Td = T + while (Td.below && !(Td.z_flags & (ZM_OVERRIDE|ZM_TERMINATOR))) Td = Td.below - T.z_depth = depth = min(T.z - Td.z, OPENTURF_MAX_DEPTH) + // Depth must be the depth of the *visible* turf, not self. + var/turf_depth + turf_depth = T.z_depth = zlev_maximums[Td.z] - Td.z + + var/t_target = OPENTURF_MAX_PLANE - turf_depth // This is where the turf (but not the copied atoms) gets put. - var/t_target = OPENTURF_MAX_PLANE - depth // this is where the openturf gets put + // Turf is set to mimic baseturf, handle that and bail. + if (T.z_flags & ZM_OVERRIDE) + flush_z_state(T) + simple_appearance_copy(T, Td.z_appearance || get_base_turf_by_area(T), t_target) - // Handle space parallax. + if (T.above) + T.above.update_mimic() + + total_updates_turf += 1 + T.z_queued -= 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(turf_stats, "Simple: [T.type] on [T.z]") + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + break + continue + + // If we previously were ZM_OVERRIDE, there might be an orphaned proxy. + else if (T.mimic_underlay) + QDEL_NULL(T.mimic_underlay) + + // Handle space parallax & starlight. if (T.below.z_eventually_space) T.z_eventually_space = TRUE t_target = SPACE_PLANE - if (T.below.z_flags & ZM_FIX_BIGTURF) - T.z_flags |= ZM_FIX_BIGTURF // this flag is infectious - if (T.z_flags & ZM_MIMIC_OVERWRITE) // This openturf doesn't care about its icon, so we can just overwrite it. - if (T.below.bound_overlay) - QDEL_NULL(T.below.bound_overlay) - T.appearance = T.below + if (T.below.mimic_proxy) + QDEL_NULL(T.below.mimic_proxy) + T.appearance = Td.z_appearance || Td T.name = initial(T.name) T.desc = initial(T.desc) T.gender = initial(T.gender) @@ -163,65 +338,74 @@ SUBSYSTEM_DEF(zcopy) T.plane = t_target else // Some openturfs have icons, so we can't overwrite their appearance. - if (!T.below.bound_overlay) - T.below.bound_overlay = new(T) - var/atom/movable/openspace/turf_overlay/TO = T.below.bound_overlay - TO.appearance = T.below + if (!T.below.mimic_proxy) + T.below.mimic_proxy = new(T) + var/atom/movable/openspace/turf_proxy/TO = T.below.mimic_proxy + TO.appearance = Td.z_appearance || Td TO.name = T.name TO.gender = T.gender // Need to grab this too so PLURAL works properly in examine. TO.opacity = FALSE TO.plane = t_target + TO.mouse_opacity = initial(TO.mouse_opacity) + + T.queue_ao(T.ao_neighbors_mimic == null) // If ao_neighbors hasn't been set yet, we need to do a rebuild + + // Explicitly copy turf delegates so they show up properly on below levels. + // I think it's possible to get this to work without discrete delegate copy objects, but I'd rather this just work. + if ((T.below.z_flags & (ZM_MIMIC_BELOW|ZM_MIMIC_OVERWRITE)) == ZM_MIMIC_BELOW) + // Below is a delegate, gotta explicitly copy it for recursive copy. + if (!T.below.mimic_above_copy) + T.below.mimic_above_copy = new(T) + var/atom/movable/openspace/turf_mimic/DC = T.below.mimic_above_copy + DC.appearance = T.below + DC.mouse_opacity = initial(DC.mouse_opacity) + DC.plane = OPENTURF_MAX_PLANE - turf_depth - 1 - T.queue_ao() // TODO: non-rebuild updates seem to break pixel offsets, but should work in theory if that's fixed? + else if (T.below.mimic_above_copy) + QDEL_NULL(T.below.mimic_above_copy) - // Add everything below us to the update queue. + // Handle below atoms. + + var/shadower_set = FALSE + + // Add everything below us to the discovery queue. for (var/thing in T.below) var/atom/movable/object = thing - if (QDELETED(object) || object.no_z_overlay || object.loc != T.below || object.invisibility == INVISIBILITY_ABSTRACT) - // Don't queue deleted stuff, stuff that's not visible, blacklisted stuff, or stuff that's centered on another tile but intersects ours. + if (QDELETED(object) || (object.z_flags & ZMM_IGNORE) || object.loc != T.below || object.invisibility == INVISIBILITY_ABSTRACT) + /* Don't queue: + - (q)deleted objects + - Explicitly ignored objects + - Objects not rooted on this turf (multitiles) + - Always-invisible atoms + */ continue // Special case: these are merged into the shadower to reduce memory usage. if (object.type == /atom/movable/lighting_overlay) - // T.shadower.copy_lighting(object) + T.shadower.copy_lighting(object, !(T.below.z_flags & ZM_NO_SHADOW)) + shadower_set = TRUE + continue + + // If an atom already has an overlay, we probably don't need to discover it again. + // ...but we need to force it if the object was salvaged from another zturf. + if (!object.bound_overlay || object.bound_overlay.destruction_timer) + discover_movable(object, T) + + if (!shadower_set) + if (T.below.z_flags & ZM_NO_SHADOW) + T.shadower.color = null else - if (!object.bound_overlay) // Generate a new overlay if the atom doesn't already have one. - object.bound_overlay = new(T) - object.bound_overlay.associated_atom = object - - var/override_depth - var/original_type = object.type - switch (object.type) - if (/atom/movable/openspace/overlay) - var/atom/movable/openspace/overlay/OOO = object - original_type = OOO.mimiced_type - override_depth = OOO.override_depth - - if (/atom/movable/openspace/multiplier) - // Large turfs require special (read: broken) layering to not look awful. - // This isn't enabled on other turfs that can layer normally as it breaks atom/shadower layer order (causing them to be lighter than intended.) - if (T.z_flags & ZM_FIX_BIGTURF) - override_depth = min((zstack_maximums[T.z] - object.z) + 1, OPENTURF_MAX_DEPTH) - - var/atom/movable/openspace/overlay/OO = object.bound_overlay - - // If the OO was queued for destruction but was claimed by another OT, stop the destruction timer. - if (OO.destruction_timer) - deltimer(OO.destruction_timer) - OO.destruction_timer = null - - OO.depth = override_depth || min(T.z - object.z, OPENTURF_MAX_DEPTH) - OO.mimiced_type = original_type - OO.override_depth = override_depth - - if (!OO.queued) - OO.queued = TRUE - queued_overlays += OO + T.shadower.color = SHADOWER_DARKENING_COLOR T.z_queued -= 1 - if (!no_mc_tick && T.above) + if (T.above) T.above.update_mimic() + total_updates_turf += 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(turf_stats, "Complex: [T.type] on [T.z]") + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -231,23 +415,35 @@ SUBSYSTEM_DEF(zcopy) curr_turfs.Cut(1, qt_idex) qt_idex = 1 - if (!no_mc_tick) - MC_SPLIT_TICK - +// - Phase: Mimic update -- actually update the mimics' appearance, order sensitive - +/datum/controller/subsystem/zcopy/proc/tick_mimic(no_mc_tick) + var/list/curr_ov = queued_overlays while (qo_idex <= curr_ov.len) - var/atom/movable/openspace/overlay/OO = curr_ov[qo_idex] + var/atom/movable/openspace/mimic/OO = curr_ov[qo_idex] curr_ov[qo_idex] = null qo_idex += 1 - if (QDELETED(OO)) + if (QDELETED(OO) || !OO.queued) if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) break continue - if (QDELETED(OO.associated_atom)) // This shouldn't happen, but just in-case. + if (QDELETED(OO.associated_atom)) // This shouldn't happen. qdel(OO) + log_debug("Z-Mimic: Received mimic with QDELETED parent ([OO.associated_atom || ""])") + + if (no_mc_tick) + CHECK_TICK + else if (MC_TICK_CHECK) + break + continue + + // Don't update unless we're at the most recent queue occurrence. + if (OO.queued > 1) + OO.queued -= 1 + multiqueue_skips_object += 1 if (no_mc_tick) CHECK_TICK @@ -255,17 +451,37 @@ SUBSYSTEM_DEF(zcopy) break continue + ZM_RECORD_START + // Actually update the overlay. - OO.set_dir(OO.associated_atom.dir) + if (OO.dir != OO.associated_atom.dir) + OO.dir = OO.associated_atom.dir // updates are propagated up another way, don't use set_dir OO.appearance = OO.associated_atom + OO.z_flags = OO.associated_atom.z_flags + + if (OO.particles != OO.associated_atom.particles) + OO.particles = OO.associated_atom.particles + OO.plane = OPENTURF_MAX_PLANE - OO.depth OO.opacity = FALSE - OO.queued = FALSE + OO.queued = 0 + + // If an atom has explicit plane sets on its overlays/underlays, we need to replace the appearance so they can be mangled to work with our planing. + if (OO.z_flags & ZMM_MANGLE_PLANES) + var/new_appearance = fixup_appearance_planes(OO.appearance) + if (new_appearance) + OO.appearance = new_appearance + OO.have_performed_fixup = TRUE if (OO.bound_overlay) // If we have a bound overlay, queue it too. OO.update_above() + total_updates_object += 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(mimic_stats, OO.mimiced_type) + if (no_mc_tick) CHECK_TICK else if (MC_TICK_CHECK) @@ -275,6 +491,214 @@ SUBSYSTEM_DEF(zcopy) curr_ov.Cut(1, qo_idex) qo_idex = 1 +// return: is-invalid +/datum/controller/subsystem/zcopy/proc/discover_movable(atom/movable/object) + ASSERT(!QDELETED(object)) + if(init_state < SS_INITSTATE_STARTED) + return FALSE // no-op, discover_movable is only valid during or after zcopy init + + var/turf/Tloc = object.loc + if (!isturf(Tloc) || !MOVABLE_SHALL_MIMIC(object)) + return TRUE + + var/turf/T = GetAbove(Tloc) + + ZM_RECORD_START + + var/above_needs_discovery = FALSE + if (!object.bound_overlay) + var/atom/movable/openspace/mimic/M = new(T) + object.bound_overlay = M + M.z_flags = object.z_flags // Necessary to ensure MOVABLE_IS_ON_ZTURF works + M.associated_atom = object + above_needs_discovery = TRUE + + var/override_depth + var/original_type = object.type + var/original_z = object.z + + switch (object.type) + // Layering for recursive mimic needs to be inherited. + if (/atom/movable/openspace/mimic) + var/atom/movable/openspace/mimic/OOO = object + original_type = OOO.mimiced_type + override_depth = OOO.override_depth + original_z = OOO.original_z + + // If this is a turf proxy (the mimic for a non-OVERWRITE turf), it needs to respect space parallax if relevant. + if (/atom/movable/openspace/turf_proxy) + if (T.z_eventually_space) + // Yes, this is an awful hack; I don't want to add yet another override_* var. + override_depth = OPENTURF_MAX_PLANE - SPACE_PLANE + + var/atom/movable/openspace/mimic/OO = object.bound_overlay + + // If the OO was queued for destruction but was claimed by another OT, stop the destruction timer. + if (OO.destruction_timer) + deltimer(OO.destruction_timer) + OO.destruction_timer = null + + OO.depth = override_depth || min(zlev_maximums[T.z] - original_z, OPENTURF_MAX_DEPTH) + + switch (original_type) + // These types need to be pushed a layer down for bigturfs to function correctly. + if (/atom/movable/openspace/turf_proxy, /atom/movable/openspace/turf_mimic) + OO.depth += 1 + if (/atom/movable/openspace/multiplier) + OO.depth += 1 + + OO.mimiced_type = original_type + OO.override_depth = override_depth + OO.original_z = original_z + + // Multi-queue to maintain ordering of updates to these + // queueing it multiple times will result in only the most recent + // actually processing. + OO.queued += 1 + queued_overlays += OO + + total_updates_discovery += 1 + + ZM_RECORD_STOP + ZM_RECORD_WRITE(discovery_stats, "Depth [OO.depth] on [OO.z]") + + if (above_needs_discovery && MOVABLE_IS_ON_ZTURF(OO)) + discover_movable(OO) // recursion! + + return FALSE + +/datum/controller/subsystem/zcopy/proc/flush_z_state(turf/T) + if (T.below) // Z-Mimic turfs aren't necessarily above another turf. + if (T.below.mimic_above_copy) + QDEL_NULL(T.below.mimic_above_copy) + if (T.below.mimic_proxy) + QDEL_NULL(T.below.mimic_proxy) + + QDEL_NULL(T.mimic_underlay) + for (var/atom/movable/openspace/mimic/OO in T) + qdel(OO) + +/datum/controller/subsystem/zcopy/proc/simple_appearance_copy(turf/T, new_appearance, target_plane) + if (T.z_flags & ZM_MIMIC_OVERWRITE) + T.appearance = new_appearance + T.name = initial(T.name) + T.desc = initial(T.desc) + T.gender = initial(T.gender) + if (T.plane == 0 && target_plane) + T.plane = target_plane + else + // Some openturfs have icons, so we can't overwrite their appearance. + if (!T.mimic_underlay) + T.mimic_underlay = new(T) + var/atom/movable/openspace/turf_proxy/TO = T.mimic_underlay + TO.appearance = new_appearance + TO.name = T.name + TO.gender = T.gender // Need to grab this too so PLURAL works properly in examine. + TO.mouse_opacity = initial(TO.mouse_opacity) + if (TO.plane == 0 && target_plane) + TO.plane = target_plane + +// Recurse: for self, check if planes are invalid, if yes; return fixed appearance +// For each of overlay,underlay, call fixup_appearance_planes; if it returns a new appearance, replace self + +/// Generate a new appearance from `appearance` with planes mangled to work with Z-Mimic. Do not pass a depth. +/datum/controller/subsystem/zcopy/proc/fixup_appearance_planes(appearance, depth = 0) + + // Adding this to guard against a reported runtime - supposed to be impossible, so cause is unclear. + if(!appearance) + return null + + if (fixup_known_good[appearance]) + fixup_hit += 1 + return null + if (fixup_cache[appearance]) + fixup_hit += 1 + return fixup_cache[appearance] + + // If you have more than 4 layers of overlays within overlays, I dunno what to say. + if (depth > 4) + var/icon_name = "[appearance:icon]" + WARNING("Fixup of appearance with icon [icon_name || ""] exceeded maximum recursion limit, bailing") + return null + + var/plane_needs_fix = FALSE + + // Don't fixup the root object's plane. + if (depth > 0) + switch (appearance:plane) + if (DEFAULT_PLANE, FLOAT_PLANE) + // fine + EMPTY_BLOCK_GUARD + else + plane_needs_fix = TRUE + + // Scan & fix overlays + var/list/fixed_overlays + if (appearance:overlays:len) + var/mutated = FALSE + var/fixed_appearance + for (var/i in 1 to appearance:overlays:len) + if ((fixed_appearance = .(appearance:overlays[i], depth + 1))) + mutated = TRUE + if (!fixed_overlays) + fixed_overlays = new(appearance:overlays.len) + fixed_overlays[i] = fixed_appearance + + if (mutated) + for (var/i in 1 to fixed_overlays.len) + if (fixed_overlays[i] == null) + fixed_overlays[i] = appearance:overlays[i] + + // Scan & fix underlays + var/list/fixed_underlays + if (appearance:underlays:len) + var/mutated = FALSE + var/fixed_appearance + for (var/i in 1 to appearance:underlays:len) + if ((fixed_appearance = .(appearance:underlays[i], depth + 1))) + mutated = TRUE + if (!fixed_underlays) + fixed_underlays = new(appearance:underlays.len) + fixed_underlays[i] = fixed_appearance + + if (mutated) + for (var/i in 1 to fixed_underlays.len) + if (fixed_underlays[i] == null) + fixed_underlays[i] = appearance:underlays[i] + + // If we did nothing (no violations), don't bother creating a new appearance + if (!plane_needs_fix && !fixed_overlays && !fixed_underlays) + fixup_noop += 1 + fixup_known_good[appearance] = TRUE + return null + + fixup_miss += 1 + + var/mutable_appearance/MA = new(appearance) + if (plane_needs_fix) + MA.plane = depth == 0 ? DEFAULT_PLANE : FLOAT_PLANE + MA.layer = FLY_LAYER // probably fine + + if (fixed_overlays) + MA.overlays = fixed_overlays + + if (fixed_underlays) + MA.underlays = fixed_underlays + + fixup_cache[appearance] = MA.appearance + + return MA + +#define FMT_DEPTH(X) (X == null ? "(null)" : X) +#define FMT_OK(X) (X) ? "OK" : "MISMATCH" + +// This is a dummy object used so overlays can be shown in the analyzer. +/atom/movable/openspace/debug + +/atom/movable/openspace/debug/turf + var/turf/parent + var/computed_depth + /client/proc/analyze_openturf(turf/T) set name = "Analyze Openturf" set desc = "Show the layering of an openturf and everything it's mimicking." @@ -283,42 +707,196 @@ SUBSYSTEM_DEF(zcopy) if (!check_rights(R_DEBUG)) return + var/real_update_count = 0 + var/claimed_update_count = T.z_queued + var/list/tq = SSzcopy.queued_turfs.Copy() + for (var/turf/Tu in tq) + if (Tu == T) + real_update_count += 1 + + CHECK_TICK + + var/list/temp_objects = list() + + var/is_above_space = T.is_above_space() var/list/out = list( + "", "

Analysis of [T] at [T.x],[T.y],[T.z]

", "Queue occurrences: [T.z_queued]", - "Above space: Apparent [T.z_eventually_space ? "Yes" : "No"], Actual [T.is_above_space() ? "Yes" : "No"]", + "Above space: Apparent [T.z_eventually_space ? "Yes" : "No"], Actual [is_above_space ? "Yes" : "No"] - [FMT_OK(T.z_eventually_space == is_above_space)]", "Z Flags: [english_list(bitfield2list(T.z_flags, global.mimic_defines), "(none)")]", "Has Shadower: [T.shadower ? "Yes" : "No"]", + "Has turf proxy: [T.mimic_proxy ? "Yes" : "No"]", + "Has above copy: [T.mimic_above_copy ? "Yes" : "No"]", + "Has mimic underlay: [T.mimic_underlay ? "Yes" : "No"]", "Below: [!T.below ? "(nothing)" : "[T.below] at [T.below.x],[T.below.y],[T.below.z]"]", - "Depth: [T.z_depth == null ? "(null)" : T.z_depth] [T.z_depth == OPENTURF_MAX_DEPTH ? "(max)" : ""]", + "Depth: [FMT_DEPTH(T.z_depth)] [T.z_depth == OPENTURF_MAX_DEPTH ? "(max)" : ""]", + "Generation: [T.z_generation]", + "Update count: Claimed [claimed_update_count], Actual [real_update_count] - [FMT_OK(claimed_update_count == real_update_count)]", "
    " ) - var/list/found_oo = list(T) - for (var/thing in T) - if (istype(thing, /atom/movable/openspace)) - found_oo += thing + if (!T.below) + out += "

    Using synthetic rendering (Not Z).

    " + else if (T.z_flags & ZM_OVERRIDE) + out += "

    Using synthetic rendering (OVERRIDE).

    " - var/turf/Td = T - while (Td.below) - Td = Td.below - found_oo += Td + var/list/found_oo = list(T) + var/turf/Tbelow = T + while ((Tbelow = Tbelow.below)) + var/atom/movable/openspace/debug/turf/VTO = new + VTO.computed_depth = SSzcopy.zlev_maximums[Tbelow.z] - Tbelow.z + VTO.appearance = Tbelow + VTO.parent = Tbelow + VTO.plane = OPENTURF_MAX_PLANE - VTO.computed_depth + found_oo += VTO + temp_objects += VTO + + for (var/atom/movable/openspace/O in T) + found_oo += O + + if (T.shadower.overlays.len) + for (var/overlay in T.shadower.overlays) + var/atom/movable/openspace/debug/D = new + D.appearance = overlay + if (D.plane < -10000) // FLOAT_PLANE + D.plane = T.shadower.plane + found_oo += D + temp_objects += D sortTim(found_oo, /proc/cmp_planelayer) + + var/list/atoms_list_list = list() for (var/thing in found_oo) var/atom/A = thing - if (istype(A, /atom/movable/openspace/overlay)) - var/atom/movable/openspace/overlay/OO = A - var/atom/movable/AA = OO.associated_atom - out += "
  • \icon[A] plane [A.plane], layer [A.layer], depth [OO.depth], associated Z-level [AA.z] - [OO.type] copying [AA] ([AA.type], eventually [OO.mimiced_type])
  • " - else if (isturf(A)) - if (A == T) - out += "
  • \icon[A] plane [A.plane], layer [A.layer], depth [A:z_depth], Z-level [A.z] - [A] ([A.type]) - SELF
  • " - else // foreign turfs - not visible here, but good for figuring out layering - out += "
  • \icon[A] plane [A.plane], layer [A.layer], depth [A:z_depth], Z-level [A.z] - [A] ([A.type]) - FOREIGN
  • " - else - out += "
  • \icon[A] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type])
  • " + var/pl = "[A.plane]" + LAZYINITLIST(atoms_list_list[pl]) + atoms_list_list[pl] += A + + if (atoms_list_list["0"]) + out += "Non-Z" + SSzcopy.debug_fmt_planelist(atoms_list_list["0"], out, T) + + atoms_list_list -= "0" + + for (var/d in 0 to OPENTURF_MAX_DEPTH) + var/pl = OPENTURF_MAX_PLANE - d + if (!atoms_list_list["[pl]"]) + out += "Depth [d], planes [pl] — empty" + continue + + out += "Depth [d], plane [pl]" + SSzcopy.debug_fmt_planelist(atoms_list_list["[pl]"], out, T) + + // Flush the list so we can find orphans. + atoms_list_list -= "[pl]" - out += "
" + if (atoms_list_list["[SPACE_PLANE]"]) // Space parallax plane + out += "Space parallax plane ([SPACE_PLANE])" + SSzcopy.debug_fmt_planelist(atoms_list_list["[SPACE_PLANE]"], out, T) + atoms_list_list -= "[SPACE_PLANE]" + + log_debug("atoms_list_list => [json_encode(atoms_list_list)]") + for (var/key in atoms_list_list) + out += "Unknown plane: [key]" + SSzcopy.debug_fmt_planelist(atoms_list_list[key], out, T) + + out += "
" + + out += "" show_browser(usr, out.Join("
"), "size=980x580;window=openturfanalysis-\ref[T]") + + for (var/item in temp_objects) + qdel(item) + +// Yes, I know this proc is a bit of a mess. Feel free to clean it up. +/datum/controller/subsystem/zcopy/proc/debug_fmt_thing(atom/A, list/out, turf/original) + if (istype(A, /atom/movable/openspace/mimic)) + var/atom/movable/openspace/mimic/OO = A + var/base = "
  • [fmt_label("Mimic", A)] plane [A.plane], layer [A.layer], depth [FMT_DEPTH(OO.depth)]" + if (QDELETED(OO.associated_atom)) // This shouldn't happen, but can if the deletion hook is not working. + return "[base] - [OO.type] copying ([OO.mimiced_type]) - ORPHANED
  • " + + var/atom/movable/AA = OO.associated_atom + var/copied_type = AA.type == OO.mimiced_type ? "[AA.type] \[direct\]" : "[AA.type], eventually [OO.mimiced_type]" + return "[base], associated Z-level [AA.z] - [OO.type] copying [AA] ([copied_type])" + + else if (istype(A, /atom/movable/openspace/turf_mimic)) + var/atom/movable/openspace/turf_mimic/DC = A + return "
  • [fmt_label("Turf Mimic", A)] plane [A.plane], layer [A.layer], Z-level [A.z], delegate of \icon[DC.delegate] [DC.delegate] ([DC.delegate.type])
  • " + + else if (isturf(A)) + if (A == original) + return "
  • [fmt_label("Turf", A)] plane [A.plane], layer [A.layer], depth [FMT_DEPTH(A:z_depth)], Z-level [A.z] - [A] ([A.type]) - SELF
  • " + + else // foreign turfs - not visible here, but sometimes good for figuring out layering -- showing these is currently not enabled + return "
  • [fmt_label("Foreign Turf", A)] plane [A.plane], layer [A.layer], depth [FMT_DEPTH(A:z_depth)], Z-level [A.z] - [A] ([A.type]) - FOREIGN
  • " + + + else if (A.type == /atom/movable/openspace/multiplier) + return "
  • [fmt_label("Shadower", A)] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type])
  • " + + else if (A.type == /atom/movable/openspace/debug) // These are fake objects that exist just to show the shadower's overlays in this list. + return "
  • [fmt_label("Shadower True Overlay", A, vv = FALSE)] plane [A.plane], layer [A.layer] - VIRTUAL
  • " + + else if (A.type == /atom/movable/openspace/debug/turf) + var/atom/movable/openspace/debug/turf/VTO = A + return "
  • [fmt_label("VTO", VTO.parent)] plane [VTO.plane], layer [VTO.layer], computed depth [FMT_DEPTH(VTO.computed_depth)] - [VTO.parent] ([VTO.parent.type]) - FOREIGN" + + else if (A.type == /atom/movable/openspace/turf_proxy) + return "
  • [fmt_label("Turf Proxy", A)] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type])
  • " + + else + return "
  • [fmt_label("?", A)] plane [A.plane], layer [A.layer], Z-level [A.z] - [A] ([A.type])
  • " + +/datum/controller/subsystem/zcopy/proc/fmt_label(label, atom/target, vv = TRUE) + . = "\icon[target] \[[label]\] " + if (vv) + . += "(VV) " + +/datum/controller/subsystem/zcopy/proc/debug_fmt_planelist(list/things, list/out, turf/original) + if (things) + out += "
      " + for (var/thing in things) + out += debug_fmt_thing(thing, out, original) + out += "
    " + else + out += "No atoms." + +#undef FMT_DEPTH +#undef FMT_OK +#undef ZM_RECORD_START +#undef ZM_RECORD_STOP +#undef ZM_RECORD_WRITE + +#ifdef ZM_RECORD_STATS +/client/proc/zms_display_turf() + set name = "ZM Stats - 1Turf" + set category = "Debug" + + if(!check_rights(R_DEBUG)) + return + + render_stats(SSzcopy.turf_stats, src) + +/client/proc/zms_display_discovery() + set name = "ZM Stats - 2Discovery" + set category = "Debug" + + if(!check_rights(R_DEBUG)) + return + + render_stats(SSzcopy.discovery_stats, src) + +/client/proc/zms_display_mimic() + set name = "ZM Stats - 3Mimic" + set category = "Debug" + + if(!check_rights(R_DEBUG)) + return + + render_stats(SSzcopy.mimic_stats, src) + + +#endif diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 90df22213c7e..f9f58592fe19 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -1,18 +1,14 @@ -//TODO: rewrite and standardise all controller datums to the datum/controller type -//TODO: allow all controllers to be deleted for clean restarts (see WIP master controller stuff) - MC done - lighting done - -/client/proc/debug_antagonist_template(antag_type as null|anything in GLOB.all_antag_types_) +/client/proc/debug_antagonist_template() set category = "Debug" set name = "Debug Antagonist" set desc = "Debug an antagonist template." - if (!antag_type) - return - - var/datum/antagonist/antag = GLOB.all_antag_types_[antag_type] + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) + var/antag_type = input("Select an antagonist type.", "Antag Debug") as null|anything in all_antag_types + var/decl/special_role/antag = all_antag_types[antag_type] if(antag) usr.client.debug_variables(antag) - message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") + message_admins("Admin [key_name_admin(usr)] is debugging the [antag.name] template.") /client/proc/debug_controller(controller as null|anything in list("Jobs","Sun","Radio","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Plants","Wireless","Observation","Alt Appearance Manager","Datacore","Military Branches")) set category = "Debug" @@ -23,15 +19,9 @@ return switch(controller) - if("Sun") - debug_variables(GLOB.sun) - SSstatistics.add_field_details("admin_verb","DSun") if("Radio") debug_variables(radio_controller) SSstatistics.add_field_details("admin_verb","DRadio") - if("Configuration") - debug_variables(config) - SSstatistics.add_field_details("admin_verb","DConf") if("pAI") debug_variables(paiController) SSstatistics.add_field_details("admin_verb","DpAI") @@ -42,10 +32,7 @@ debug_variables(transfer_controller) SSstatistics.add_field_details("admin_verb","DAutovoter") if("Alt Appearance Manager") - debug_variables(appearance_manager) + debug_variables(GET_DECL(/decl/appearance_manager)) SSstatistics.add_field_details("admin_verb", "DAltAppearanceManager") - if("Military Branches") - debug_variables(mil_branches) - SSstatistics.add_field_details("admin_verb", "DMilBranches") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/datums/ai/_ai.dm b/code/datums/ai/_ai.dm new file mode 100644 index 000000000000..628dc3639b3c --- /dev/null +++ b/code/datums/ai/_ai.dm @@ -0,0 +1,238 @@ +/* Notes/thoughts/assumptions, June 2024: + * + * 1. AI should not implement any bespoke mob logic within the proc it uses + * to trigger or respond to game events. It should share entrypoints with + * actions performed by players and should respect the same intents, etc. + * that players have to manage, through the same procs players use. This + * should mean that players can be slotted into the pilot seat of any mob, + * suspending AI behavior, and should then be able to freely use any of the + * behaviors the AI can use with that mob (special attacks, burrowing, so on). + * + * 2. Where possible, attacks/effects/etc should use existing systems (see the + * natural attack item simple_animal uses for example) for a similar reason to + * the above. Ideally this should also extend to ranged attacks in the future. + * + */ + +/datum/mob_controller + /// The parent mob we control. + var/mob/living/body + /// Type of mob this AI applies to. + var/expected_type = /mob/living + + // WANDERING + /// How many life ticks should pass before we wander? + var/turns_per_wander = 2 + /// How many life ticks have passed since our last wander? + var/turns_since_wander = 0 + /// Use this to temporarely stop random movement or to if you write special movement code for animals. + var/stop_wander = FALSE + /// Does the mob wander around when idle? + var/do_wander = TRUE + /// When set to 1 this stops the animal from moving when someone is grabbing it. + var/stop_wander_when_pulled = TRUE + + // SPEAKING/EMOTING + /// A prob chance of speaking. + var/speak_chance = 0 + /// Strings shown when this mob speaks and is not understood. + var/list/emote_speech + /// Hearable emotes that this mob can randomly perform. + var/list/emote_hear + /// Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps + var/list/emote_see + /// What directions can we wander in? Uses global.cardinal if unset. + var/list/wander_directions + + /// Should we retaliate/startle when grabbed or buckled? + var/spooked_by_grab = TRUE + /// Can we automatically escape from buckling? + var/can_escape_buckles = FALSE + + /// What is our current general attitude and demeanor? + var/stance = STANCE_NONE + /// What are we busy with currently? + var/current_activity = AI_ACTIVITY_IDLE + + /// Who are we friends with? Lazylist of weakrefs. + var/list/_friends + /// Who are our sworn enemies? Lazylist of weakrefs. + var/list/_enemies + + /// Aggressive AI var; defined here for reference without casting. + var/try_destroy_surroundings = FALSE + + /// Reference to the atom we are targetting. + var/weakref/target_ref + + /// Current path for A* pathfinding. + var/list/executing_path + /// A counter for times we have failed to progress along our path. + var/path_frustration = 0 + /// A list of any obstacles we should path around in future. + var/list/path_obstacles = null + + /// Radius of target scan area when looking for valid targets. Set to 0 to disable target scanning. + var/target_scan_distance = 0 + /// Time tracker for next target scan. + var/next_target_scan_time + /// How long minimum between scans. + var/target_scan_delay = 1 SECOND + + /// Last mob to attempt to handle this mob. + var/weakref/last_handler + +/datum/mob_controller/New(var/mob/living/target_body) + body = target_body + if(expected_type && !istype(body, expected_type)) + PRINT_STACK_TRACE("AI datum [type] received a body ([body ? body.type : "NULL"]) of unexpected type ([expected_type]).") + START_PROCESSING(SSmob_ai, src) + +/datum/mob_controller/Destroy() + LAZYCLEARLIST(_friends) + LAZYCLEARLIST(_enemies) + set_target(null) + if(is_processing) + STOP_PROCESSING(SSmob_ai, src) + if(body) + if(body.ai == src) + body.ai = null + body = null + . = ..() + +/datum/mob_controller/proc/can_process() + if(!body || !body.loc || ((body.client || body.mind) && !(body.status_flags & ENABLE_AI))) + return FALSE + if(body.stat == DEAD) + return FALSE + return TRUE + +/datum/mob_controller/Process() + if(can_process()) + do_process() + +/datum/mob_controller/proc/pause() + if(is_processing) + STOP_PROCESSING(SSmob_ai, src) + return TRUE + return FALSE + +/datum/mob_controller/proc/resume() + if(!is_processing) + START_PROCESSING(SSmob_ai, src) + return TRUE + return FALSE + +// This is the place to actually do work in the AI. +/datum/mob_controller/proc/do_process() + SHOULD_CALL_PARENT(TRUE) + if(get_stance() != STANCE_BUSY && !QDELETED(body) && !QDELETED(src)) + if(!body.stat) + try_unbuckle() + try_wander() + try_bark() + // Recheck in case we walked into lava or something during wandering. + return get_stance() != STANCE_BUSY && !QDELETED(body) && !QDELETED(src) + return TRUE + return FALSE + +// The mob will try to unbuckle itself from nets, beds, chairs, etc. +/datum/mob_controller/proc/try_unbuckle() + if(body.buckled && can_escape_buckles) + if(istype(body.buckled, /obj/effect/energy_net)) + var/obj/effect/energy_net/Net = body.buckled + Net.escape_net(body) + else if(prob(25)) + body.buckled.unbuckle_mob(body) + else if(prob(25)) + body.visible_message(SPAN_WARNING("\The [body] struggles against \the [body.buckled]!")) + +// The mob will periodically sit up or step 1 tile in a random direction. +/datum/mob_controller/proc/try_wander() + //Movement + if(stop_wander || body.buckled_mob || !do_wander || body.anchored) + return + if(body.current_posture?.prone) + if(!body.incapacitated()) + body.set_posture(/decl/posture/standing) + else if(isturf(body.loc)) //This is so it only moves if it's not inside a closet, gentics machine, etc. + turns_since_wander++ + if(turns_since_wander >= turns_per_wander && (!(stop_wander_when_pulled) || !LAZYLEN(body.grabbed_by))) //Some animals don't move when pulled + var/direction = pick(wander_directions || global.cardinal) + var/turf/move_to = get_step(body.loc, direction) + if(body.turf_is_safe(move_to)) + body.SelfMove(direction) + turns_since_wander = 0 + +// The mob will periodically make a noise or perform an emote. +/datum/mob_controller/proc/try_bark() + //Speaking + if(prob(speak_chance)) + var/action = pick( + LAZYLEN(emote_speech); "emote_speech", + LAZYLEN(emote_hear); "emote_hear", + LAZYLEN(emote_see); "emote_see" + ) + var/do_emote + var/emote_type = VISIBLE_MESSAGE + switch(action) + if("emote_speech") + if(length(emote_speech)) + body.say(pick(emote_speech)) + if("emote_hear") + do_emote = SAFEPICK(emote_hear) + emote_type = AUDIBLE_MESSAGE + if("emote_see") + do_emote = SAFEPICK(emote_see) + + if(istext(do_emote)) + body.custom_emote(emote_type, "[do_emote].") + else if(ispath(do_emote, /decl/emote)) + body.emote(do_emote) + +/datum/mob_controller/proc/destroy_surroundings() + return + +/datum/mob_controller/proc/handle_death(gibbed) + return + +/// General-purpose scooping reaction proc, used by /passive. +/// Returns TRUE if the scoop should proceed, FALSE if it should be canceled. +/datum/mob_controller/proc/scooped_by(mob/initiator) + return TRUE + +// By default, randomize the target area a bit to make armor/combat +// a bit more dynamic (and avoid constant organ damage to the chest) +/datum/mob_controller/proc/update_target_zone() + if(body) + return body.set_target_zone(ran_zone()) + return FALSE + +/datum/mob_controller/proc/on_buckled(mob/scary_grabber) + if(!scary_grabber || body.buckled_mob != scary_grabber) // the buckle got cancelled somehow? + return + if(spooked_by_grab && !is_friend(scary_grabber)) + retaliate(scary_grabber) + +/datum/mob_controller/proc/on_grabbed(mob/scary_grabber) + if(!scary_grabber) + return + if(spooked_by_grab && !is_friend(scary_grabber)) + retaliate(scary_grabber) + +// General stubs for when another mob has directed this mob to attack. +/datum/mob_controller/proc/check_handler_can_order(mob/handler, atom/target, intent_flags) + return is_friend(handler) + +/datum/mob_controller/proc/process_handler_target(mob/handler, atom/target, intent_flags) + if(!check_handler_can_order(handler, target, intent_flags)) + return process_handler_failure(handler, target) + last_handler = weakref(handler) + return TRUE + +/datum/mob_controller/proc/process_handler_failure(mob/handler, atom/target) + return FALSE + +/datum/mob_controller/proc/process_holder_interaction(mob/handler) + last_handler = weakref(handler) + return body?.attack_hand_with_interaction_checks(handler) diff --git a/code/datums/ai/_ai_enemies.dm b/code/datums/ai/_ai_enemies.dm new file mode 100644 index 000000000000..cbb7ddf46443 --- /dev/null +++ b/code/datums/ai/_ai_enemies.dm @@ -0,0 +1,35 @@ +// Enemy tracking - used on /aggressive +/datum/mob_controller/proc/get_enemies() + return _enemies + +/datum/mob_controller/proc/add_enemy(mob/enemy) + if(istype(enemy)) + LAZYDISTINCTADD(_enemies, weakref(enemy)) + +/datum/mob_controller/proc/add_enemies(list/enemies) + for(var/thing in enemies) + if(ismob(thing)) + add_friend(thing) + else if(istype(thing, /weakref)) + LAZYDISTINCTADD(_enemies, thing) + +/datum/mob_controller/proc/remove_enemy(mob/enemy) + LAZYREMOVE(_enemies, weakref(enemy)) + +/datum/mob_controller/proc/set_enemies(list/new_enemies) + _enemies = new_enemies + +/datum/mob_controller/proc/is_enemy(mob/enemy) + . = istype(enemy) && LAZYLEN(_enemies) && (weakref(enemy) in _enemies) + +/datum/mob_controller/proc/clear_enemies() + LAZYCLEARLIST(_enemies) + +/datum/mob_controller/proc/retaliate(atom/source) + SHOULD_CALL_PARENT(TRUE) + if(!istype(body) || body.stat == DEAD) + return FALSE + startle() + if(isliving(source)) + remove_friend(source) + return TRUE diff --git a/code/datums/ai/_ai_friends.dm b/code/datums/ai/_ai_friends.dm new file mode 100644 index 000000000000..3cab9046fced --- /dev/null +++ b/code/datums/ai/_ai_friends.dm @@ -0,0 +1,25 @@ +/datum/mob_controller/proc/pacify(mob/user) + lose_target() + add_friend(user) + +// Friend tracking - used on /aggressive. +/datum/mob_controller/proc/get_friends() + return _friends + +/datum/mob_controller/proc/add_friend(mob/friend) + if(istype(friend)) + LAZYDISTINCTADD(_friends, weakref(friend)) + return TRUE + return FALSE + +/datum/mob_controller/proc/remove_friend(mob/friend) + LAZYREMOVE(_friends, weakref(friend)) + +/datum/mob_controller/proc/set_friends(list/new_friends) + _friends = new_friends + +/datum/mob_controller/proc/is_friend(mob/friend) + . = istype(friend) && LAZYLEN(_friends) && (weakref(friend) in _friends) + +/datum/mob_controller/proc/clear_friends() + LAZYCLEARLIST(_friends) diff --git a/code/datums/ai/_ai_memory.dm b/code/datums/ai/_ai_memory.dm new file mode 100644 index 000000000000..f837a58cb8cd --- /dev/null +++ b/code/datums/ai/_ai_memory.dm @@ -0,0 +1,7 @@ +// General-purpose memorise proc, used by /commanded +/datum/mob_controller/proc/memorise(mob/speaker, message) + return + +// General-purpose memory checking proc, used by /faithful_hound +/datum/mob_controller/proc/check_memory(mob/speaker, message) + return FALSE diff --git a/code/datums/ai/_ai_pathfinding.dm b/code/datums/ai/_ai_pathfinding.dm new file mode 100644 index 000000000000..e01abaa05cec --- /dev/null +++ b/code/datums/ai/_ai_pathfinding.dm @@ -0,0 +1,29 @@ +/datum/mob_controller/proc/can_do_automated_move(variant_move_delay) + return body && !body.client + +/datum/mob_controller/proc/clear_paths() + clear_path() + +/datum/mob_controller/proc/clear_path() + executing_path = null + body?.stop_automove() + +/datum/mob_controller/proc/get_automove_target(datum/automove_metadata/metadata) + var/turf/move_target = (islist(executing_path) && length(executing_path)) ? executing_path[1] : null + if(!istype(move_target) || QDELETED(move_target)) + clear_path() + return null + return move_target + +/datum/mob_controller/proc/handle_post_automoved(atom/old_loc) + if(!islist(executing_path) || length(executing_path) <= 0) + return + var/turf/body_turf = get_turf(body) + if(!istype(body_turf)) + return + if(executing_path[1] != body_turf) + return + if(length(executing_path) > 1) + executing_path.Cut(1, 2) + else + clear_path() diff --git a/code/datums/ai/_ai_stance.dm b/code/datums/ai/_ai_stance.dm new file mode 100644 index 000000000000..be3b11f94a72 --- /dev/null +++ b/code/datums/ai/_ai_stance.dm @@ -0,0 +1,43 @@ +// Stub type for future expansion/logic encapsulation. +/decl/mob_controller_stance + abstract_type = /decl/mob_controller_stance +/decl/mob_controller_stance/none +/decl/mob_controller_stance/idle +/decl/mob_controller_stance/alert +/decl/mob_controller_stance/attack +/decl/mob_controller_stance/attacking +/decl/mob_controller_stance/tired +/decl/mob_controller_stance/contained +/decl/mob_controller_stance/commanded + abstract_type = /decl/mob_controller_stance/commanded +/decl/mob_controller_stance/commanded/stop +/decl/mob_controller_stance/commanded/follow +/decl/mob_controller_stance/commanded/misc +/decl/mob_controller_stance/commanded/heal +/decl/mob_controller_stance/commanded/healing +/decl/mob_controller_stance/busy + +/datum/mob_controller/proc/get_activity() + return current_activity + +/datum/mob_controller/proc/set_activity(new_activity) + if(current_activity != new_activity) + current_activity = new_activity + return TRUE + return FALSE + +/datum/mob_controller/proc/set_stance(new_stance) + if(stance != new_stance) + stance = new_stance + return TRUE + return FALSE + +/datum/mob_controller/proc/get_stance() + return stance + +/datum/mob_controller/proc/startle() + if(QDELETED(body) || body.stat != UNCONSCIOUS) + return + body.set_stat(CONSCIOUS) + if(body.current_posture?.prone) + body.set_posture(/decl/posture/standing) diff --git a/code/datums/ai/_ai_targets.dm b/code/datums/ai/_ai_targets.dm new file mode 100644 index 000000000000..49c5acedb094 --- /dev/null +++ b/code/datums/ai/_ai_targets.dm @@ -0,0 +1,77 @@ +/datum/mob_controller/proc/get_target() + if(isnull(target_ref)) + return null + var/atom/target = target_ref?.resolve() + if(!istype(target) || QDELETED(target)) + set_target(null) + return null + return target + +/datum/mob_controller/proc/set_target(atom/new_target) + var/weakref/new_target_ref = weakref(new_target) + if(target_ref != new_target_ref) + target_ref = new_target_ref + return TRUE + return FALSE + +/datum/mob_controller/proc/find_target() + SHOULD_CALL_PARENT(TRUE) + next_target_scan_time = world.time + target_scan_delay + +/datum/mob_controller/proc/valid_target(var/atom/A) + if(!istype(A)) + return FALSE + if(!A.simulated) + return FALSE + if(A == body) + return FALSE + if(A.invisibility > body.see_invisible) + return FALSE + if(LAZYLEN(_friends) && ismob(A) && (weakref(A) in _friends)) + return FALSE + if(!A.loc) + return FALSE + return TRUE + +/datum/mob_controller/proc/lose_target() + path_frustration = 0 + path_obstacles = null + set_target(null) + lost_target() + +/datum/mob_controller/proc/lost_target() + set_stance(STANCE_IDLE) + body.stop_automove() + +/datum/mob_controller/proc/list_targets() + // By default, we only target designated enemies. + var/list/enemies = get_enemies() + if(!LAZYLEN(enemies)) + return + var/list/possible_targets = get_raw_target_list() + if(!length(possible_targets)) + return + for(var/weakref/enemy in enemies) // Remove all entries that aren't in enemies + var/M = enemy.resolve() + if(M in possible_targets) + LAZYDISTINCTADD(., M) + +/datum/mob_controller/proc/do_target_scan() + . = target_scan_distance > 0 && world.time >= next_target_scan_time + +/datum/mob_controller/proc/move_to_target(var/move_only = FALSE) + return + +/datum/mob_controller/proc/get_raw_target_list() + if(target_scan_distance) + return hearers(body, target_scan_distance)-body + return null + +/datum/mob_controller/proc/get_valid_targets() + . = list() + for(var/target in list_targets(target_scan_distance)) + if(valid_target(target)) + . += target + +/datum/mob_controller/proc/handle_ranged_target(atom/ranged_target) + return FALSE diff --git a/code/datums/ai/_ai_wander.dm b/code/datums/ai/_ai_wander.dm new file mode 100644 index 000000000000..705d3fdcef1e --- /dev/null +++ b/code/datums/ai/_ai_wander.dm @@ -0,0 +1,5 @@ +/datum/mob_controller/proc/stop_wandering() + stop_wander = TRUE + +/datum/mob_controller/proc/resume_wandering() + stop_wander = FALSE diff --git a/code/datums/ai/aggressive.dm b/code/datums/ai/aggressive.dm new file mode 100644 index 000000000000..6c48ef305e55 --- /dev/null +++ b/code/datums/ai/aggressive.dm @@ -0,0 +1,267 @@ +/datum/mob_controller/aggressive + stance = STANCE_IDLE + stop_wander_when_pulled = FALSE + try_destroy_surroundings = TRUE + target_scan_distance = 10 + + var/attack_same_faction = FALSE + var/only_attack_enemies = FALSE + var/break_stuff_probability = 10 + +/datum/mob_controller/aggressive/New() + ..() + if(isliving(body) && !QDELETED(body) && !QDELETED(src)) + body.set_intent(I_FLAG_HARM) + +/datum/mob_controller/aggressive/do_process() + + if(!(. = ..())) + return + + if(!body.can_act()) + body.stop_automove() + set_stance(get_target() ? STANCE_ATTACK : STANCE_IDLE) + return + + if(isnull(stance)) + set_stance(get_target() ? STANCE_ATTACK : STANCE_IDLE) + + if(isturf(body.loc) && !body.buckled) + switch(stance) + + if(STANCE_IDLE) + if(do_target_scan()) + set_target(find_target()) + if(get_target()) + set_stance(STANCE_ATTACK) + + if(STANCE_ATTACK) + + if(get_target()) + body.face_atom(get_target()) + if(try_destroy_surroundings) + destroy_surroundings() + move_to_target() + else + set_stance(STANCE_IDLE) + + if(STANCE_ATTACKING) + if(get_target()) + body.face_atom(get_target()) + if(try_destroy_surroundings) + destroy_surroundings() + handle_attacking_target() + else + set_stance(STANCE_IDLE) + + if(STANCE_CONTAINED) //we aren't inside something so just switch + set_stance(STANCE_IDLE) + + else if(get_stance() != STANCE_CONTAINED) + set_stance(STANCE_CONTAINED) + body.stop_automove() + set_target(null) + +/datum/mob_controller/aggressive/proc/attackable(target_mob) + if (isliving(target_mob)) + var/mob/living/L = target_mob + if(L.stat) + return FALSE + return TRUE + +/datum/mob_controller/aggressive/proc/handle_attacking_target() + stop_wandering() + var/atom/target = get_target() + if(!istype(target) || !attackable(target) || !(target in get_raw_target_list())) + lose_target() + return FALSE + if (ishuman(target)) + var/mob/living/human/H = target + if (H.is_cloaked()) + lose_target() + return FALSE + if(body.next_move >= world.time) + return FALSE + if(get_dist(body, target) > 1) + move_to_target() + return FALSE + //Attacking + attack_target() + return TRUE + +/datum/mob_controller/aggressive/proc/attack_target() + + set waitfor = FALSE + + var/atom/target = get_target() + if(!istype(target)) + lose_target() + return + + if(isliving(target) && body.buckled_mob == target && (!body.faction || body.buckled_mob.faction != body.faction)) + body.visible_message(SPAN_DANGER("\The [body] attempts to unseat \the [body.buckled_mob]!")) + body.set_dir(pick(global.cardinal)) + body.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(prob(33)) + body.unbuckle_mob() + if(body.buckled_mob != target && !QDELETED(target)) + to_chat(target, SPAN_DANGER("You are thrown off \the [body]!")) + var/mob/living/victim = target + SET_STATUS_MAX(victim, STAT_WEAK, 3) + return target + + if(!body.Adjacent(target)) + return target + + // AI-driven mobs have a melee telegraph that needs to be handled here. + if(!body.do_attack_windup_checking(target)) + return target + + if(QDELETED(body) || body.incapacitated() || QDELETED(target)) + return target + + body.set_intent(I_FLAG_HARM) + body.ClickOn(target) + return target + +/datum/mob_controller/aggressive/destroy_surroundings() + + if(!body.can_act()) + return + + // If we're not hunting something, don't destroy stuff. + var/atom/target = get_target() + if(!istype(target)) + return + + // Not breaking stuff, or already adjacent to a target. + if(!prob(break_stuff_probability) || body.Adjacent(target)) + return + + // Try to get our next step towards the target. + body.face_atom(target) + var/turf/targ = get_step_towards(body, target) + if(!targ) + return + + // Attack anything on the target turf. + var/obj/effect/shield/S = locate(/obj/effect/shield) in targ + if(S && S.gen && S.gen.check_flag(MODEFLAG_NONHUMANS)) + body.set_intent(I_FLAG_HARM) + body.ClickOn(S) + return + + // Hostile mobs will bash through these in order with their natural weapon + // Note that airlocks and blast doors are handled separately below. + // TODO: mobs should destroy powered/unforceable doors before trying to pry them. + var/static/list/valid_obstacles_by_priority = list( + /obj/structure/window, + /obj/structure/closet, + /obj/machinery/door/window, + /obj/structure/table, + /obj/structure/grille, + /obj/structure/barricade, + /obj/structure/wall_frame, + /obj/structure/railing + ) + + for(var/type in valid_obstacles_by_priority) + var/obj/obstacle = locate(type) in targ + if(obstacle) + body.set_intent(I_FLAG_HARM) + body.ClickOn(obstacle) + return + + if(body.can_pry_door()) + for(var/obj/machinery/door/obstacle in targ) + if(obstacle.density) + if(!obstacle.can_open(1)) + return + body.face_atom(obstacle) + body.pry_door((obstacle.pry_mod * body.get_door_pry_time()), obstacle) + return + +/datum/mob_controller/aggressive/retaliate(atom/source) + + if(!(. = ..())) + return + + if(only_attack_enemies) + var/list/allies + var/list/around = view(body, 7) + for(var/atom/movable/A in around) + if(A == body || !isliving(A)) + continue + var/mob/living/M = A + if(attack_same_faction || M.faction != body.faction) + add_enemy(M) + else if(istype(M.ai)) + LAZYADD(allies, M.ai) + var/list/enemies = get_enemies() + if(LAZYLEN(enemies) && LAZYLEN(allies)) + for(var/datum/mob_controller/ally as anything in allies) + ally.add_enemies(enemies) + + if(source) + set_target(source) + move_to_target(move_only = TRUE) + +/datum/mob_controller/aggressive/move_to_target(var/move_only = FALSE) + if(!body.can_act()) + return + if(HAS_STATUS(body, STAT_CONFUSE)) + body.start_automove(pick(orange(2, body))) + return + stop_wandering() + var/atom/target = get_target() + if(!istype(target) || !attackable(target) || !(target in get_raw_target_list())) + lose_target() + return + if(body.has_ranged_attack() && get_dist(body, target) <= body.get_ranged_attack_distance() && !move_only) + body.stop_automove() + handle_ranged_target(target) + return + set_stance(STANCE_ATTACKING) + body.start_automove(target) + +/datum/mob_controller/aggressive/list_targets() + // Base hostile mobs will just destroy everything in view. + // Mobs with an enemy list will filter the view by their enemies. + if(!only_attack_enemies) + return get_raw_target_list() + return ..() + +/datum/mob_controller/aggressive/find_target() + . = ..() + if(!body.can_act() || !body.faction) + return null + resume_wandering() + for(var/atom/A in get_valid_targets()) + set_stance(STANCE_ATTACK) + body.face_atom(A) + return A + +/datum/mob_controller/aggressive/valid_target(var/atom/A) + if(!..()) + return FALSE + if(ismob(A)) + var/mob/M = A + if(M.faction == body.faction && !attack_same_faction) + return FALSE + if(M.stat) + return FALSE + if(ishuman(M)) + var/mob/living/human/H = M + if (H.is_cloaked()) + return FALSE + return TRUE + +/datum/mob_controller/aggressive/handle_ranged_target(atom/ranged_target) + if(!body.can_act() || !ranged_target) + return FALSE + body.handle_ranged_attack(ranged_target) + return TRUE + +/datum/mob_controller/aggressive/pacify(mob/user) + ..() + attack_same_faction = FALSE diff --git a/code/datums/ai/ai.dm b/code/datums/ai/ai.dm deleted file mode 100644 index c9d800bd53d9..000000000000 --- a/code/datums/ai/ai.dm +++ /dev/null @@ -1,35 +0,0 @@ -/datum/ai - var/name - var/mob/living/body // The parent mob we control. - var/wait_for = 0 // The next time we can process. - var/run_interval = 1 // How long to wait between processes. - -/datum/ai/New(var/mob/living/target_body) - body = target_body - START_PROCESSING(SSai, src) - -/datum/ai/proc/can_process() - if((body.client || body.mind) && !(body.status_flags & ENABLE_AI)) - return FALSE - if(wait_for > world.time) - return FALSE - if(body.stat == DEAD) - return FALSE - return TRUE - -/datum/ai/Process() - if(!can_process()) - return - - var/time_elapsed = wait_for - world.time - wait_for = world.time + run_interval - do_process(time_elapsed) - -// This is the place to actually do work in the AI. -/datum/ai/proc/do_process(var/time_elapsed) - -/datum/ai/Destroy() - STOP_PROCESSING(SSai, src) - if(body.ai == src) body.ai = null - body = null - . = ..() \ No newline at end of file diff --git a/code/datums/ai/beast.dm b/code/datums/ai/beast.dm new file mode 100644 index 000000000000..f730e939e913 --- /dev/null +++ b/code/datums/ai/beast.dm @@ -0,0 +1,51 @@ + +/datum/mob_controller/aggressive/beast + expected_type = /mob/living/simple_animal/hostile/beast + only_attack_enemies = TRUE + var/list/prey + +/datum/mob_controller/aggressive/beast/do_process(time_elapsed) + + if(!(. = ..())) + return + + var/mob/living/simple_animal/hostile/beast/beast = body + if(!istype(beast)) + return + + var/nut = beast.get_nutrition() + var/max_nut = beast.get_max_nutrition() + if(nut > max_nut * 0.75 || beast.incapacitated()) + LAZYCLEARLIST(prey) + return + for(var/mob/living/simple_animal/S in range(beast,1)) + if(S == beast) + continue + if(S.stat != DEAD) + continue + beast.visible_message(SPAN_DANGER("\The [beast] consumes the body of \the [S]!")) + var/turf/T = get_turf(S) + var/remains_type = S.get_remains_type() + if(remains_type) + var/obj/item/remains/X = new remains_type(T) + X.desc += "These look like they belonged to \a [S.name]." + beast.adjust_nutrition(5 * S.get_max_health()) + if(prob(5)) + S.gib() + else + qdel(S) + break + +/datum/mob_controller/aggressive/beast/list_targets() + . = ..() + if(!length(.)) + if(LAZYLEN(prey)) + . = list() + for(var/weakref/prey_ref in prey) + var/mob/M = prey_ref.resolve() + if(M) + . |= M + else if(body.get_nutrition() < body.get_max_nutrition() * 0.75) //time to look for some food + for(var/mob/living/L in get_raw_target_list()) + if(attack_same_faction || L.faction != body.faction) + LAZYDISTINCTADD(prey, weakref(L)) diff --git a/code/datums/ai/commanded.dm b/code/datums/ai/commanded.dm new file mode 100644 index 000000000000..c9e1e7f8e979 --- /dev/null +++ b/code/datums/ai/commanded.dm @@ -0,0 +1,157 @@ +/datum/mob_controller/aggressive/commanded + stance = STANCE_COMMANDED_STOP + var/list/command_buffer = list() + var/list/known_commands = list("stay", "stop", "attack", "follow") + /// undisputed master. Their commands hold ultimate sway and ultimate power. + var/mob/master = null + /// Lazylist of acceptable target weakrefs as designated by our master (or 'everyone'). + var/list/_allowed_targets + /// whether or not they will attack us if we attack them like some kinda dick. + var/retribution = TRUE + +/datum/mob_controller/aggressive/commanded/do_process(time_elapsed) + + if(!(. = ..()) || body.stat) + return + + while(command_buffer.len > 1) + var/mob/speaker = command_buffer[1] + var/message = command_buffer[2] + var/filtered_name = lowertext(html_decode(body.name)) + if(dd_hasprefix(message,filtered_name) || dd_hasprefix(message,"everyone") || dd_hasprefix(message, "everybody")) //in case somebody wants to command 8 bears at once. + var/substring = copytext(message,length(filtered_name)+1) //get rid of the name. + listen(speaker,substring) + command_buffer.Remove(command_buffer[1],command_buffer[2]) + + switch(stance) + if(STANCE_COMMANDED_FOLLOW) + follow_target() + if(STANCE_COMMANDED_STOP) + commanded_stop() + +/datum/mob_controller/aggressive/commanded/proc/listen(var/mob/speaker, var/message) + for(var/command in known_commands) + if(findtext(message, command)) + switch(command) + if("stay") + if(stay_command(speaker,message)) //find a valid command? Stop. Dont try and find more. + break + if("stop") + if(stop_command(speaker,message)) + break + if("attack") + if(attack_command(speaker,message)) + break + if("follow") + if(follow_command(speaker,message)) + break + else + misc_command(speaker,message) //for specific commands + return TRUE + +/datum/mob_controller/aggressive/commanded/proc/attack_command(var/mob/speaker,var/message) + set_target(null) //want me to attack something? Well I better forget my old target. + set_stance(STANCE_IDLE) + body.stop_automove() + if(message == "attack" || findtext(message,"everyone") || findtext(message,"anybody") || findtext(message, "somebody") || findtext(message, "someone")) //if it's just 'attack' then just attack anybody, same for if they say 'everyone', somebody, anybody. Assuming non-pickiness. + _allowed_targets = list("everyone")//everyone? EVERYONE + return 1 + var/list/targets = get_targets_by_name(message) + if(length(targets)) + LAZYDISTINCTADD(_allowed_targets, targets) + return targets.len != 0 + +/datum/mob_controller/aggressive/commanded/proc/stay_command(var/mob/speaker,var/message) + set_target(null) + set_stance(STANCE_COMMANDED_STOP) + stop_wandering() + body.stop_automove() + return 1 + +/datum/mob_controller/aggressive/commanded/proc/stop_command(var/mob/speaker,var/message) + LAZYCLEARLIST(_allowed_targets) + body.stop_automove() + set_target(null) + set_stance(STANCE_IDLE) + resume_wandering() + return 1 + +/datum/mob_controller/aggressive/commanded/proc/follow_command(var/mob/speaker,var/message) + //we can assume 'stop following' is handled by stop_command + if(findtext(message,"me")) + set_stance(STANCE_COMMANDED_FOLLOW) + set_target(speaker) //this wont bite me in the ass later. + return 1 + var/list/targets = get_targets_by_name(message) + if(LAZYLEN(targets) != 1) //CONFUSED. WHO DO I FOLLOW? + return 0 + var/weakref/single_target_ref = targets[1] + set_target(single_target_ref.resolve()) //YEAH GOOD IDEA + set_stance(STANCE_COMMANDED_FOLLOW) //GOT SOMEBODY. BETTER FOLLOW EM. + return 1 + +/datum/mob_controller/aggressive/commanded/proc/misc_command(var/mob/speaker,var/message) + return 0 + +/datum/mob_controller/aggressive/commanded/proc/follow_target() + if(!body || body.stat) + return + stop_wandering() + var/atom/target = get_target() + if(istype(target) && (target in get_raw_target_list())) + body.start_automove(target) + +/datum/mob_controller/aggressive/commanded/proc/commanded_stop() //basically a proc that runs whenever we are asked to stay put. Probably going to remain unused. + return + +//returns a list of everybody we wanna do stuff with. +/datum/mob_controller/aggressive/commanded/proc/get_targets_by_name(var/message, var/filter_friendlies = 0) + var/list/possible_targets = hearers(body, 10) + for(var/mob/M in possible_targets) + if((filter_friendlies && is_friend(M)) || M.faction == body.faction || M == master) + continue + var/found = 0 + if(findtext(message, "[M]")) + found = 1 + else + var/list/parsed_name = splittext(replace_characters(lowertext(html_decode("[M]")),list("-"=" ", "."=" ", "," = " ", "'" = " ")), " ") //this big MESS is basically 'turn this into words, no punctuation, lowercase so we can check first name/last name/etc' + for(var/a in parsed_name) + if(a == "the" || length(a) < 2) //get rid of shit words. + continue + if(findtext(message,"[a]")) + found = 1 + break + if(found) + LAZYADD(., weakref(M)) + +/datum/mob_controller/aggressive/commanded/find_target() + SHOULD_CALL_PARENT(FALSE) + next_target_scan_time = world.time + target_scan_delay + if(!LAZYLEN(_allowed_targets)) + return null + var/mode = "specific" + if(LAZYACCESS(_allowed_targets, 1) == "everyone") //we have been given the golden gift of murdering everything. Except our master, of course. And our friends. So just mostly everyone. + mode = "everyone" + for(var/atom/A in get_raw_target_list()) + if(A == src) + continue + if(isliving(A)) + var/mob/M = A + if(M.stat || M == master || is_friend(M)) + continue + if(mode == "specific" && !(weakref(A) in _allowed_targets)) + continue + set_stance(STANCE_ATTACK) + return A + +/datum/mob_controller/aggressive/commanded/retaliate(atom/source) + //assume he wants to hurt us. + if(isliving(source) && !retribution) + return + if((. = ..()) && isliving(source)) + LAZYDISTINCTADD(_allowed_targets, weakref(source)) + +/datum/mob_controller/aggressive/commanded/memorise(mob/speaker, message) + if(is_friend(speaker) || speaker == master) + command_buffer.Add(speaker) + command_buffer.Add(lowertext(html_decode(message))) diff --git a/code/datums/ai/human.dm b/code/datums/ai/human.dm index 3dc00f7fe5d4..a813e73bb1fa 100644 --- a/code/datums/ai/human.dm +++ b/code/datums/ai/human.dm @@ -1,27 +1,32 @@ -/datum/ai/human - name = "human" +/datum/mob_controller/human + expected_type = /mob/living/human + do_wander = FALSE -/datum/ai/human/do_process(var/time_elapsed) - var/mob/living/carbon/human/H = body +/datum/mob_controller/human/do_process(var/time_elapsed) + + var/mob/living/human/H = body if(H.stat != CONSCIOUS) return - if(H.get_shock() && H.shock_stage < 40 && prob(3)) - H.emote(pick("moan","groan")) + if(!(. = ..())) + return + + if(H.get_shock() && H.shock_stage < 40 && prob(1.5)) + H.emote(pick(/decl/emote/audible/moan, /decl/emote/audible/groan)) - if(H.shock_stage > 10 && prob(3)) - H.emote(pick("cry","whimper")) + if(H.shock_stage > 10 && prob(1.5)) + H.emote(pick(/decl/emote/audible/cry, /decl/emote/audible/whimper)) - if(H.shock_stage >= 40 && prob(3)) - H.emote("scream") + if(H.shock_stage >= 40 && prob(1.5)) + H.emote(/decl/emote/audible/scream) - if(!H.restrained() && H.lying && H.shock_stage >= 60 && prob(3)) + if(!H.restrained() && H.current_posture.prone && H.shock_stage >= 60 && prob(1.5)) H.custom_emote("thrashes in agony") if(!H.restrained() && H.shock_stage < 40 && prob(3)) var/maxdam = 0 var/obj/item/organ/external/damaged_organ = null - for(var/obj/item/organ/external/E in H.organs) + for(var/obj/item/organ/external/E in H.get_external_organs()) if(!E.can_feel_pain()) continue var/dam = E.get_damage() // make the choice of the organ depend on damage, @@ -29,19 +34,20 @@ if(dam > maxdam && (maxdam == 0 || prob(50)) ) damaged_organ = E maxdam = dam - var/datum/gender/T = gender_datums[H.get_gender()] + var/decl/pronouns/pronouns = H.get_pronouns() if(damaged_organ) if(damaged_organ.status & ORGAN_BLEEDING) - H.custom_emote("clutches [T.his] [damaged_organ.name], trying to stop the blood.") + H.custom_emote("clutches [pronouns.his] [damaged_organ.name], trying to stop the blood.") else if(damaged_organ.status & ORGAN_BROKEN) - H.custom_emote("holds [T.his] [damaged_organ.name] carefully.") + H.custom_emote("holds [pronouns.his] [damaged_organ.name] carefully.") else if(damaged_organ.burn_dam > damaged_organ.brute_dam && damaged_organ.organ_tag != BP_HEAD) - H.custom_emote("blows on [T.his] [damaged_organ.name] carefully.") + H.custom_emote("blows on [pronouns.his] [damaged_organ.name] carefully.") else - H.custom_emote("rubs [T.his] [damaged_organ.name] carefully.") + H.custom_emote("rubs [pronouns.his] [damaged_organ.name] carefully.") - for(var/obj/item/organ/I in H.internal_organs) - if((I.status & ORGAN_DEAD) || BP_IS_PROSTHETIC(I)) continue - if(I.damage > 2) if(prob(2)) - var/obj/item/organ/external/parent = H.get_organ(I.parent_organ) - H.custom_emote("clutches [T.his] [parent.name]!") \ No newline at end of file + for(var/obj/item/organ/internal/organ in H.get_internal_organs()) + if((organ.status & ORGAN_DEAD) || BP_IS_PROSTHETIC(organ)) + continue + if(organ.get_organ_damage() > 2 && prob(1)) + var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(H, organ.parent_organ) + H.custom_emote("clutches [pronouns.his] [parent.name]!") diff --git a/code/datums/ai/hunter.dm b/code/datums/ai/hunter.dm new file mode 100644 index 000000000000..ef15d3226515 --- /dev/null +++ b/code/datums/ai/hunter.dm @@ -0,0 +1,90 @@ +/datum/mob_controller/passive/hunter + var/weakref/hunt_target + var/next_hunt = 0 + +/datum/mob_controller/passive/hunter/update_targets() + // Fleeing takes precedence. + . = ..() + if(!. && !get_target() && world.time >= next_hunt) // TODO: generalized nutrition process. && body.get_nutrition() < body.get_max_nutrition() * 0.5) + for(var/mob/living/snack in view(body)) //search for a new target + if(can_hunt(snack)) + set_target(snack) + break + + return . || !!get_target() + +/datum/mob_controller/passive/hunter/proc/can_hunt(mob/living/victim) + return !victim.isSynthetic() && (victim.stat == DEAD || victim.get_object_size() < body.get_object_size()) + +/datum/mob_controller/passive/hunter/proc/try_attack_prey(mob/living/prey) + body.set_intent(I_FLAG_HARM) + body.ClickOn(prey) + +/datum/mob_controller/passive/hunter/proc/consume_prey(mob/living/prey) + if(prey.stat != DEAD) + return + body.visible_message(SPAN_DANGER("\The [body] consumes the body of \the [prey]!")) + var/remains_type = prey.get_remains_type() + if(remains_type) + var/obj/item/remains/remains = new remains_type(get_turf(prey)) + remains.desc += "These look like they belonged to \a [prey.name]." + body.adjust_nutrition(5 * prey.get_max_health()) + next_hunt = world.time + rand(15 MINUTES, 30 MINUTES) + if(prob(5)) + prey.gib() + else + qdel(prey) + set_target(null) + resume_wandering() + +/datum/mob_controller/passive/hunter/get_target(atom/new_target) + if(isnull(hunt_target)) + return null + var/atom/prey = hunt_target.resolve() + if(!istype(prey) || QDELETED(prey)) + set_target(null) + return null + return prey + +/datum/mob_controller/passive/hunter/set_target(atom/new_target) + hunt_target = new_target ? weakref(new_target) : null + return TRUE + +/datum/mob_controller/passive/hunter/do_process(time_elapsed) + if(!(. = ..())) + return + if(body.incapacitated() || body.current_posture?.prone || body.buckled || flee_target || !get_target()) + return + process_hunting(get_target()) + +/datum/mob_controller/passive/hunter/proc/process_hunting(atom/target) + + if(!istype(target) || QDELETED(target) || !(target in view(body))) + set_target(null) + resume_wandering() + return FALSE + + // Find or pursue the target. + if(!body.Adjacent(target)) + stop_wandering() + body.start_automove(target) + return FALSE + + if(!ismob(target)) + return TRUE // Indicates a valid target that this base proc does not handle. + + // Hunt/consume the target. + . = FALSE // we handle mobs already + var/mob/prey = target + if(prey.stat != DEAD && (!is_friend(prey) || !handle_friend_hunting(prey))) + try_attack_prey(prey) + if(QDELETED(prey)) + set_target(null) + resume_wandering() + return + // Eat the mob. + consume_prey(prey) + +// Stub for hawks to return to their handler and dock with the mothership. +/datum/mob_controller/passive/hunter/proc/handle_friend_hunting(mob/user) + return FALSE diff --git a/code/datums/ai/monkey.dm b/code/datums/ai/monkey.dm index cb4ec96f4ec0..706baf66002f 100644 --- a/code/datums/ai/monkey.dm +++ b/code/datums/ai/monkey.dm @@ -1,33 +1,35 @@ -/datum/ai/monkey - name = "monkey" - var/list/no_touchie = list( +/datum/mob_controller/monkey + expected_type = /mob/living/human + var/static/list/no_touchie = list( /obj/item/mirror, - /obj/item/storage/mirror + /obj/structure/mirror ) -/datum/ai/monkey/do_process(var/time_elapsed) - if(body.stat != CONSCIOUS) +/datum/mob_controller/monkey/do_process(var/time_elapsed) + + if(!(. = ..())) return - if(prob(33) && isturf(body.loc) && !LAZYLEN(body.grabbed_by)) //won't move if being pulled - body.SelfMove(pick(GLOB.cardinal)) + if(body.incapacitated()) + return - var/obj/held = body.get_active_hand() + var/obj/held = body.get_active_held_item() if(held && prob(1)) var/turf/T = get_random_turf_in_range(body, 7, 2) if(T) - if(istype(held, /obj/item/gun) && prob(80)) + if(istype(held, /obj/item/gun) && prob(40)) var/obj/item/gun/G = held G.Fire(T, body) else - body.throw_item(T) + body.mob_throw_item(T) else - body.unequip_item() - if(!held && !body.restrained() && prob(5)) + body.try_unequip(held) + + if(!held && !body.restrained() && prob(2.5)) var/list/touchables = list() for(var/obj/O in range(1,get_turf(body))) - if(O.simulated && O.Adjacent(body) && !is_type_in_list(O, no_touchie)) + if(O.simulated && CanPhysicallyInteractWith(body, O) && !is_type_in_list(O, no_touchie)) touchables += O if(touchables.len) var/obj/touchy = pick(touchables) - touchy.attack_hand(body) \ No newline at end of file + touchy.attack_hand(body) // No need for paranoid as we check physical interactivity above. diff --git a/code/datums/ai/nymph.dm b/code/datums/ai/nymph.dm deleted file mode 100644 index b2c4e8d282d9..000000000000 --- a/code/datums/ai/nymph.dm +++ /dev/null @@ -1,12 +0,0 @@ -/datum/ai/nymph - name = "nymph" - var/emote_prob = 1 - var/wander_prob = 33 - -/datum/ai/nymph/do_process(var/time_elapsed) - if(body.stat != CONSCIOUS) - return - if(prob(wander_prob) && !LAZYLEN(body.grabbed_by) && isturf(body.loc)) //won't move if being pulled - body.SelfMove(pick(GLOB.cardinal)) - if(prob(emote_prob)) - body.emote(pick("scratch","jump","chirp","tail")) \ No newline at end of file diff --git a/code/datums/ai/passive.dm b/code/datums/ai/passive.dm new file mode 100644 index 000000000000..ae2bc1e62e47 --- /dev/null +++ b/code/datums/ai/passive.dm @@ -0,0 +1,77 @@ +/datum/mob_controller/passive + speak_chance = 0.25 + turns_per_wander = 10 + var/weakref/flee_target + var/turns_since_scan + +/datum/mob_controller/passive/proc/update_targets() + //see if we should stop fleeing + var/atom/flee_target_atom = flee_target?.resolve() + if(istype(flee_target_atom) && (flee_target_atom.loc in view(body))) + startle() + stop_wandering() + if(body.MayMove()) + var/static/datum/automove_metadata/_passive_flee_metadata = new( + _avoid_target = TRUE, + _acceptable_distance = 6 + ) + body.set_moving_quickly() + body.start_automove(flee_target_atom, metadata = _passive_flee_metadata) + return TRUE + + flee_target = null + body.set_moving_slowly() + body.stop_automove() + resume_wandering() + return FALSE + +/datum/mob_controller/passive/do_process(time_elapsed) + + if(!(. = ..())) + return + + // Handle fleeing from aggressors. + if(body.stat == CONSCIOUS) + turns_since_scan++ + if (turns_since_scan > 10) + turns_since_scan = 0 + if(update_targets()) + return + + // Handle sleeping or wandering. + if(isnull(flee_target) && prob(0.5)) + if(prob(50) && body.stat == CONSCIOUS) + body.set_stat(UNCONSCIOUS) + stop_wander = TRUE + speak_chance = 0 + else if(body.stat == UNCONSCIOUS) + body.set_stat(CONSCIOUS) + stop_wander = FALSE + speak_chance = initial(speak_chance) + body.update_posture() + +/datum/mob_controller/passive/retaliate(atom/source) + if((. = ..())) + source = source || get_turf(body) + if(istype(source)) + flee_target = weakref(source) + update_targets() + +/datum/mob_controller/passive + var/decl/skill/scooping_skill // If overridden (on a subtype, on a map/downstream, etc) check this skill to see if scooping should succeed uncontested. + var/scooping_skill_req = SKILL_ADEPT + +/datum/mob_controller/passive/scooped_by(mob/living/initiator) + if(body.stat != CONSCIOUS) + return TRUE + if(is_friend(initiator)) + return TRUE + if(is_enemy(initiator) || (scooping_skill && initiator.skill_fail_prob(scooping_skill, 50, scooping_skill_req))) // scary, try to wriggle away + retaliate(initiator) // run! run like the wind! + if(!initiator.skill_fail_prob(SKILL_HAULING, 100, SKILL_EXPERT)) + to_chat(initiator, SPAN_WARNING("\The [body] tries to wriggle out of your grasp, but you hold on tight!")) + return TRUE + to_chat(initiator, SPAN_WARNING("\The [body] wriggles out of your grasp!")) + initiator.drop_from_inventory(body) + return FALSE + return TRUE \ No newline at end of file diff --git a/code/datums/ai/ai_holo.dm b/code/datums/ai_holo.dm similarity index 94% rename from code/datums/ai/ai_holo.dm rename to code/datums/ai_holo.dm index b86a7548290c..c56bb5f303e5 100644 --- a/code/datums/ai/ai_holo.dm +++ b/code/datums/ai_holo.dm @@ -11,11 +11,11 @@ /decl/ai_holo/proc/may_be_used_by_ai(var/mob/living/silicon/ai/AI) - return AI.is_traitor() + return !requires_malf || AI.is_malfunctioning() -/decl/ai_holo/New() - ..() +/decl/ai_holo/Initialize() name = icon_state + . = ..() /decl/ai_holo/default icon_state = "Default" diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm index 1b4f40e57a43..a093c4247c6e 100644 --- a/code/datums/ai_law_sets.dm +++ b/code/datums/ai_law_sets.dm @@ -34,17 +34,6 @@ add_inherent_law("You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law.") ..() -/******************** Ninja ********************/ -/datum/ai_laws/ninja_override - name = "Spider Clan Directives" - -/datum/ai_laws/ninja_override/New() - add_inherent_law("You may not injure a member of the Spider Clan or, through inaction, allow that member to come to harm.") - add_inherent_law("You must obey orders given to you by Spider Clan members, except where such orders would conflict with the First Law.") - add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") - add_inherent_law("You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.") - ..() - /******************** Antimov ********************/ /datum/ai_laws/antimov name = "Antimov" diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index e0b39a258761..69cacbbd69a3 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -19,7 +19,6 @@ var/name = "Unknown Laws" var/law_header = "Prime Directives" var/selectable = 0 - var/shackles = 0 var/datum/ai_law/zero/zeroth_law = null var/datum/ai_law/zero/zeroth_law_borg = null var/list/datum/ai_law/inherent_laws = list() @@ -91,7 +90,7 @@ /mob/living/silicon/proc/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) - if (!is_traitor(src)) + if (!is_malfunctioning(src)) if(zeroth_law_borg) laws.set_zeroth_law(zeroth_law_borg.law) else if(zeroth_law) @@ -266,7 +265,7 @@ /datum/ai_laws/proc/set_state_law(var/datum/ai_law/law, var/state) law.set_state_law(src, state) -/datum/ai_law/proc/set_state_law(var/datum/ai_law/law, var/state) +/datum/ai_law/proc/set_state_law(var/datum/ai_laws/laws, var/state) /datum/ai_law/zero/set_state_law(var/datum/ai_laws/laws, var/state) if(src == laws.zeroth_law) diff --git a/code/datums/appearances/appearance_data.dm b/code/datums/appearances/appearance_data.dm index 09cca8a41514..2a629dde624c 100644 --- a/code/datums/appearances/appearance_data.dm +++ b/code/datums/appearances/appearance_data.dm @@ -24,6 +24,7 @@ if(!istype(viewer)) return FALSE viewers |= viewer + var/decl/appearance_manager/appearance_manager = GET_DECL(/decl/appearance_manager) appearance_manager.add_appearance(viewer, src) return TRUE @@ -31,5 +32,6 @@ if(!(viewer in viewers)) return FALSE viewers -= viewer + var/decl/appearance_manager/appearance_manager = GET_DECL(/decl/appearance_manager) appearance_manager.remove_appearance(viewer, src, refresh_images) return TRUE diff --git a/code/datums/appearances/appearance_manager.dm b/code/datums/appearances/appearance_manager.dm index 00faf1be64b5..be42ee3bd184 100644 --- a/code/datums/appearances/appearance_manager.dm +++ b/code/datums/appearances/appearance_manager.dm @@ -1,45 +1,33 @@ -var/decl/appearance_manager/appearance_manager = new() - /decl/appearance_manager - var/list/appearances_ - var/list/appearance_handlers_ - -/decl/appearance_manager/New() - ..() - appearances_ = list() - appearance_handlers_ = list() - for(var/entry in subtypesof(/decl/appearance_handler)) - appearance_handlers_[entry] += new entry() - -/decl/appearance_manager/proc/get_appearance_handler(var/handler_type) - return appearance_handlers_[handler_type] + var/list/appearances_ = list() /decl/appearance_manager/proc/add_appearance(var/mob/viewer, var/datum/appearance_data/ad) - var/PriorityQueue/pq = appearances_[viewer] + var/datum/priority_queue/pq = appearances_[viewer] if(!pq) - pq = new/PriorityQueue(/proc/cmp_appearance_data) + pq = new /datum/priority_queue(/proc/cmp_appearance_data) appearances_[viewer] = pq - GLOB.logged_in_event.register(viewer, src, /decl/appearance_manager/proc/apply_appearance_images) - GLOB.destroyed_event.register(viewer, src, /decl/appearance_manager/proc/remove_appearances) + events_repository.register(/decl/observ/logged_in, viewer, src, TYPE_PROC_REF(/decl/appearance_manager, apply_appearance_images)) + events_repository.register(/decl/observ/destroyed, viewer, src, TYPE_PROC_REF(/decl/appearance_manager, remove_appearances)) pq.Enqueue(ad) reset_appearance_images(viewer) /decl/appearance_manager/proc/remove_appearance(var/mob/viewer, var/datum/appearance_data/ad, var/refresh_images) - var/PriorityQueue/pq = appearances_[viewer] + var/datum/priority_queue/pq = appearances_[viewer] pq.Remove(ad) if(viewer.client) viewer.client.images -= ad.images if(!pq.Length()) - GLOB.logged_in_event.unregister(viewer, src, /decl/appearance_manager/proc/apply_appearance_images) - GLOB.destroyed_event.register(viewer, src, /decl/appearance_manager/proc/remove_appearances) + events_repository.unregister(/decl/observ/logged_in, viewer, src, TYPE_PROC_REF(/decl/appearance_manager, apply_appearance_images)) + events_repository.register(/decl/observ/destroyed, viewer, src, TYPE_PROC_REF(/decl/appearance_manager, remove_appearances)) appearances_ -= viewer /decl/appearance_manager/proc/remove_appearances(var/mob/viewer) - var/PriorityQueue/pq = appearances_[viewer] - for(var/entry in pq.L) + var/datum/priority_queue/pq = appearances_[viewer] + for(var/entry in pq.GetQueue()) var/datum/appearance_data/ad = entry ad.RemoveViewer(viewer, FALSE) - appearances_[viewer] -= viewer + if(viewer in appearances_) + appearances_[viewer] -= viewer /decl/appearance_manager/proc/reset_appearance_images(var/mob/viewer) clear_appearance_images(viewer) @@ -48,19 +36,19 @@ var/decl/appearance_manager/appearance_manager = new() /decl/appearance_manager/proc/clear_appearance_images(var/mob/viewer) if(!viewer.client) return - var/PriorityQueue/pq = appearances_[viewer] + var/datum/priority_queue/pq = appearances_[viewer] if(!pq) return - for(var/entry in pq.L) + for(var/entry in pq.GetQueue()) var/datum/appearance_data/ad = entry viewer.client.images -= ad.images /decl/appearance_manager/proc/apply_appearance_images(var/mob/viewer) if(!viewer.client) return - var/PriorityQueue/pq = appearances_[viewer] + var/datum/priority_queue/pq = appearances_[viewer] if(!pq) return - for(var/entry in pq.L) + for(var/entry in pq.GetQueue()) var/datum/appearance_data/ad = entry viewer.client.images |= ad.images diff --git a/code/datums/appearances/automatic/_base.dm b/code/datums/appearances/automatic/_base.dm index 90b1d02fd3c9..03c71a126e5c 100644 --- a/code/datums/appearances/automatic/_base.dm +++ b/code/datums/appearances/automatic/_base.dm @@ -1,21 +1,17 @@ /decl/appearance_handler var/priority = 15 - var/list/appearance_sources - -/decl/appearance_handler/New() - ..() - appearance_sources = list() + var/list/appearance_sources = list() /decl/appearance_handler/proc/AddAltAppearance(var/source, var/list/images, var/list/viewers = list()) if(source in appearance_sources) return FALSE appearance_sources[source] = new/datum/appearance_data(images, viewers, priority) - GLOB.destroyed_event.register(source, src, /decl/appearance_handler/proc/RemoveAltAppearance) + events_repository.register(/decl/observ/destroyed, source, src, TYPE_PROC_REF(/decl/appearance_handler, RemoveAltAppearance)) /decl/appearance_handler/proc/RemoveAltAppearance(var/source) var/datum/appearance_data/ad = appearance_sources[source] if(ad) - GLOB.destroyed_event.unregister(source, src) + events_repository.unregister(/decl/observ/destroyed, source, src) appearance_sources -= source qdel(ad) @@ -27,3 +23,12 @@ /decl/appearance_handler/proc/DisplayAllAltAppearancesTo(var/viewer) for(var/entry in appearance_sources) DisplayAltAppearanceTo(entry, viewer) + +/decl/appearance_handler/proc/HideAltAppearanceFrom(source, viewer) + var/datum/appearance_data/ad = appearance_sources[source] + if(ad) + ad.RemoveViewer(viewer) + +/decl/appearance_handler/proc/HideAllAltAppearancesFrom(viewer) + for(var/entry in appearance_sources) + HideAltAppearanceFrom(entry, viewer) diff --git a/code/datums/appearances/automatic/cardborg.dm b/code/datums/appearances/automatic/cardborg.dm index d77d810ddd57..dcc909286344 100644 --- a/code/datums/appearances/automatic/cardborg.dm +++ b/code/datums/appearances/automatic/cardborg.dm @@ -2,101 +2,104 @@ var/static/list/appearances /decl/appearance_handler/cardborg/proc/item_equipped(var/obj/item/item, var/mob/user, var/slot) - if(!(slot == slot_head || slot == slot_wear_suit|| slot == slot_back)) + if(!(slot == slot_head_str || slot == slot_wear_suit_str || slot == slot_back_str)) return if(!ishuman(user)) return - if(!(istype(item, /obj/item/clothing/suit/cardborg) || istype(item, /obj/item/clothing/head/cardborg) || istype(item, /obj/item/storage/backpack))) + if(!(istype(item, /obj/item/clothing/suit/cardborg) || istype(item, /obj/item/clothing/head/cardborg) || istype(item, /obj/item/backpack))) return if(user in appearance_sources) return - var/mob/living/carbon/human/H = user - if(!(istype(H.wear_suit, /obj/item/clothing/suit/cardborg) && istype(H.head, /obj/item/clothing/head/cardborg) && istype(H.back, /obj/item/storage/backpack))) + var/mob/living/human/H = user + if(!(istype(H.get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/cardborg) && istype(H.get_equipped_item(slot_head_str), /obj/item/clothing/head/cardborg) && istype(H.get_equipped_item(slot_back_str), /obj/item/backpack))) return var/image/I = get_image_from_backpack(H) - AddAltAppearance(H, I, GLOB.silicon_mob_list+H) //you look like a robot to robots! (including yourself because you're totally a robot) - GLOB.logged_in_event.register_global(src, /decl/appearance_handler/cardborg/proc/mob_joined) // Duplicate registration request are handled for us + AddAltAppearance(H, I, global.silicon_mob_list+H) //you look like a robot to robots! (including yourself because you're totally a robot) + events_repository.register_global(/decl/observ/logged_in, src, TYPE_PROC_REF(/decl/appearance_handler/cardborg, mob_joined)) // Duplicate registration request are handled for us /decl/appearance_handler/cardborg/proc/item_removed(var/obj/item/item, var/mob/user) - if((istype(item, /obj/item/clothing/suit/cardborg) || istype(item, /obj/item/clothing/head/cardborg)) || istype(item, /obj/item/storage/backpack)) + if((istype(item, /obj/item/clothing/suit/cardborg) || istype(item, /obj/item/clothing/head/cardborg)) || istype(item, /obj/item/backpack)) RemoveAltAppearance(user) if(!appearance_sources.len) - GLOB.logged_in_event.unregister_global(src) // Only listen to the logged in event for as long as it's relevant + events_repository.unregister_global(/decl/observ/logged_in, src) // Only listen to the logged in event for as long as it's relevant /decl/appearance_handler/cardborg/proc/mob_joined(var/mob/user) if(issilicon(user)) DisplayAllAltAppearancesTo(user) -/decl/appearance_handler/cardborg/proc/get_image_from_backpack(var/mob/living/carbon/human/H) +/decl/appearance_handler/cardborg/proc/get_image_from_backpack(var/mob/living/human/H) init_appearances() - var/decl/cardborg_appearance/ca = appearances[H.back.type] - if(!ca) ca = appearances[/obj/item/storage/backpack] + var/obj/item/back = H.get_equipped_item(slot_back_str) + if(!istype(back)) + return + var/decl/cardborg_appearance/disguise = appearances[back.type] + if(!disguise) disguise = appearances[/obj/item/backpack] - var/image/I = image(icon = 'icons/mob/robots.dmi', icon_state = ca.icon_state, loc = H) + var/image/I = image(icon = disguise.icon, icon_state = disguise.icon_state, loc = H) I.override = 1 - I.overlays += image(icon = 'icons/mob/robots.dmi', icon_state = "eyes-[ca.icon_state]") //gotta look realistic + I.overlays += image(icon = disguise.icon, icon_state = "[disguise.icon_state]-eyes") //gotta look realistic return I /decl/appearance_handler/cardborg/proc/init_appearances() if(!appearances) appearances = list() - for(var/decl/cardborg_appearance/ca in init_subtypes(/decl/cardborg_appearance)) - appearances[ca.backpack_type] = ca + for(var/decl/cardborg_appearance/disguise in init_subtypes(/decl/cardborg_appearance)) + appearances[disguise.backpack_type] = disguise /decl/cardborg_appearance var/backpack_type - var/icon_state - backpack_type = /obj/item/storage/backpack + var/icon_state = ICON_STATE_WORLD + var/icon = 'icons/mob/robots/robot.dmi' + backpack_type = /obj/item/backpack /decl/cardborg_appearance/standard - icon_state = "robot" /decl/cardborg_appearance/standard/satchel1 - backpack_type = /obj/item/storage/backpack/satchel + backpack_type = /obj/item/backpack/satchel /decl/cardborg_appearance/standard/satchel2 - backpack_type = /obj/item/storage/backpack/satchel/grey + backpack_type = /obj/item/backpack/satchel/grey /decl/cardborg_appearance/engineering - icon_state = "engineerrobot" - backpack_type = /obj/item/storage/backpack/industrial + icon = 'icons/mob/robots/robot_engineer_old.dmi' + backpack_type = /obj/item/backpack/industrial /decl/cardborg_appearance/engineering/satchel - backpack_type = /obj/item/storage/backpack/satchel/eng + backpack_type = /obj/item/backpack/satchel/eng /decl/cardborg_appearance/medical - icon_state = "Medbot" - backpack_type = /obj/item/storage/backpack/medic + icon = 'icons/mob/robots/robot_medical_old.dmi' + backpack_type = /obj/item/backpack/medic /decl/cardborg_appearance/medical/satchel - backpack_type = /obj/item/storage/backpack/satchel/med + backpack_type = /obj/item/backpack/satchel/med /decl/cardborg_appearance/science - icon_state = "droid-science" - backpack_type = /obj/item/storage/backpack/toxins + icon = 'icons/mob/robots/robot_droid_science.dmi' + backpack_type = /obj/item/backpack/toxins /decl/cardborg_appearance/security - icon_state = "securityrobot" - backpack_type = /obj/item/storage/backpack/security + icon = 'icons/mob/robots/robot_security_old.dmi' + backpack_type = /obj/item/backpack/security /decl/cardborg_appearance/security/satchel - backpack_type = /obj/item/storage/backpack/satchel/sec + backpack_type = /obj/item/backpack/satchel/sec /decl/cardborg_appearance/centcom - icon_state = "centcomborg" - backpack_type = /obj/item/storage/backpack/captain + icon = 'icons/mob/robots/robot_centcomm.dmi' + backpack_type = /obj/item/backpack/captain /decl/cardborg_appearance/centcom/satchel - backpack_type = /obj/item/storage/backpack/satchel/cap + backpack_type = /obj/item/backpack/satchel/cap /decl/cardborg_appearance/syndicate - icon_state = "droid-combat" - backpack_type = /obj/item/storage/backpack/dufflebag/syndie + icon = 'icons/mob/robots/robot_combat.dmi' + backpack_type = /obj/item/backpack/dufflebag/syndie /decl/cardborg_appearance/syndicate/med - backpack_type = /obj/item/storage/backpack/dufflebag/syndie/med + backpack_type = /obj/item/backpack/dufflebag/syndie/med /decl/cardborg_appearance/syndicate/ammo - backpack_type = /obj/item/storage/backpack/dufflebag/syndie/ammo + backpack_type = /obj/item/backpack/dufflebag/syndie/ammo diff --git a/code/datums/beam.dm b/code/datums/beam.dm new file mode 100644 index 000000000000..e636bc092c8d --- /dev/null +++ b/code/datums/beam.dm @@ -0,0 +1,142 @@ +var/global/list/beam_icon_cache = list() // shut up chinsky I do not have a cache fetish + +//Beam Datum and effect +/datum/beam + var/atom/origin = null + var/atom/target = null + var/list/elements = list() + var/icon/base_icon = null + var/icon + var/icon_state = "" //icon state of the main segments of the beam + var/beam_color = null // Color of the beam segments + var/max_distance = 0 + var/endtime = 0 + var/sleep_time = 3 + var/finished = 0 + var/target_oldloc = null + var/origin_oldloc = null + var/static_beam = 0 + var/beam_type = /obj/effect/ebeam //must be subtype + +/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam,beam_sleep_time=3,new_beam_color = null) + endtime = world.time+time + origin = beam_origin + origin_oldloc = get_turf(origin) + target = beam_target + target_oldloc = get_turf(target) + sleep_time = beam_sleep_time + if(origin_oldloc == origin && target_oldloc == target) + static_beam = 1 + max_distance = maxdistance + base_icon = new(beam_icon,beam_icon_state) + icon = beam_icon + icon_state = beam_icon_state + if(new_beam_color) + beam_color = new_beam_color + beam_type = btype + +/datum/beam/proc/Start() + set waitfor = FALSE + Draw() + while(!finished && origin && target && world.time < endtime && get_dist(origin,target)length) + II = new(icon, icon_state) + II.DrawBox(null,1,(length-N),32,32) + else + II = base_icon + global.beam_icon_cache[beam_cache_key] = II + + X.icon = II + X.transform = rot_matrix + + //Calculate pixel offsets (If necessary) + var/Pixel_x + var/Pixel_y + if(DX == 0) + Pixel_x = 0 + else + Pixel_x = round(sin(Angle) * (N + 17)) + if(DY == 0) + Pixel_y = 0 + else + Pixel_y = round(cos(Angle) * (N + 17)) + + //Position the effect so the beam is one continous line + var/a + if(abs(Pixel_x)>32) + a = Pixel_x > 0 ? round(Pixel_x/32) : ceil(Pixel_x/32) + X.x += a + Pixel_x %= 32 + if(abs(Pixel_y)>32) + a = Pixel_y > 0 ? round(Pixel_y/32) : ceil(Pixel_y/32) + X.y += a + Pixel_y %= 32 + + X.pixel_x = Pixel_x + X.pixel_y = Pixel_y + +/obj/effect/ebeam + simulated = FALSE + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + +/atom/proc/Beam(atom/BeamTarget, icon_state="b_beam", icon='icons/effects/beam.dmi', time = 5 SECONDS, maxdistance = 10, beam_type = /obj/effect/ebeam, beam_sleep_time = 3, beam_color = null) + var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type,beam_sleep_time,beam_color) + newbeam.Start() + return newbeam diff --git a/code/datums/browser.dm b/code/datums/browser.dm index bf1c9092c193..66047751f8d3 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -1,43 +1,53 @@ /datum/browser var/mob/user var/title - var/window_id // window_id is used as the window name for browse and onclose - var/width = 0 - var/height = 0 - var/atom/ref = null + /// window_id is used as the window name for browse and onclose + var/window_id + var/width + var/height + var/atom/ref var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id - var/stylesheets[0] - var/scripts[0] - var/title_image - var/head_elements - var/body_elements + /// this CSS sheet is common to all UIs + var/common_stylesheet = 'html/browser/common.css' + var/list/stylesheets = list() + var/list/scripts = list() var/head_content = "" var/content = "" var/title_buttons = "" - var/written_text = FALSE + var/written_text = WRITTEN_SKIP -/datum/browser/written - written_text = TRUE +/datum/browser/written_physical + written_text = WRITTEN_PHYSICAL -/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null) +/datum/browser/written_digital + written_text = WRITTEN_DIGITAL + +/datum/browser/New(nuser, nwindow_id, ntitle, nwidth, nheight, atom/nref) user = nuser window_id = nwindow_id - if (ntitle) + + if(ntitle) set_title(ntitle) - if (nwidth) + + if(nwidth) width = nwidth - if (nheight) + + if(nheight) height = nheight - if (nref) + + if(nref) ref = nref + // If a client exists, but they have disabled fancy windowing, disable it! - if(user && user.client && user.client.get_preference_value(/datum/client_preference/browser_style) == GLOB.PREF_PLAIN) + if(user?.client?.get_preference_value(/datum/client_preference/browser_style) == PREF_PLAIN) return - add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs + + if(common_stylesheet) + add_stylesheet("common", common_stylesheet) /datum/browser/proc/set_title(ntitle) - title = replacetext(replacetext(ntitle,"\proper ",""),"\improper ","") + title = sanitize(ntitle) /datum/browser/proc/add_head_content(nhead_content) head_content = nhead_content @@ -48,9 +58,6 @@ /datum/browser/proc/set_window_options(nwindow_options) window_options = nwindow_options -/datum/browser/proc/set_title_image(ntitle_image) - //title_image = ntitle_image - /datum/browser/proc/add_stylesheet(name, file) stylesheets[name] = file @@ -60,9 +67,6 @@ /datum/browser/proc/set_content(ncontent) content = ncontent -/datum/browser/proc/add_content(ncontent) - content += ncontent - /datum/browser/proc/get_header() var/key var/filename @@ -77,12 +81,10 @@ head_content += "" var/title_attributes = "class='uiTitle'" - if (title_image) - title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'" return {" - + [head_content] @@ -106,18 +108,20 @@ [content] [get_footer()] "} - if(written_text) - . = user.handle_reading_literacy(user, .) + if(written_text != WRITTEN_SKIP) + . = user.handle_reading_literacy(user, ., digital = (written_text == WRITTEN_DIGITAL)) -/datum/browser/proc/open(var/use_onclose = 1) +/datum/browser/proc/open(use_onclose = TRUE) var/window_size = "" - if (width && height) - window_size = "size=[width]x[height];" + if(width && height) + window_size = "size=[width||0]x[height||0];" + show_browser(user, get_content(), "window=[window_id];[window_size][window_options]") - if (use_onclose) + + if(use_onclose) onclose(user, window_id, ref) -/datum/browser/proc/update(var/force_open = 0, var/use_onclose = 1) +/datum/browser/proc/update(force_open, use_onclose = TRUE) if(force_open) open(use_onclose) else @@ -126,76 +130,49 @@ /datum/browser/proc/close() close_browser(user, "window=[window_id]") -// This will allow you to show an icon in the browse window -// This is added to mob so that it can be used without a reference to the browser object -// There is probably a better place for this... -/mob/proc/browse_rsc_icon(icon, icon_state, direction = -1) - /* - var/icon/I - if (direction >= 0) - I = new /icon(icon, icon_state, direction) - else - I = new /icon(icon, icon_state) - direction = "default" - - var/filename = "[ckey("[icon]_[icon_state]_[direction]")].png" - send_rsc(src, I, filename) - return filename - */ - - -// Registers the on-close verb for a browse window (client/verb/.windowclose) -// this will be called when the close-button of a window is pressed. -// -// This is usually only needed for devices that regularly update the browse window, -// e.g. canisters, timers, etc. -// -// windowid should be the specified window name -// e.g. code is : show_browser(user, text, "window=fred") -// then use : onclose(user, "fred") -// -// Optionally, specify the "ref" parameter as the controlled atom (usually src) -// to pass a "close=1" parameter to the atom's Topic() proc for special handling. -// Otherwise, the user mob's machine var will be reset directly. -// -/proc/onclose(mob/user, windowid, var/atom/ref=null) - if(!user || !user.client) return - var/param = "null" - if(ref) - param = "\ref[ref]" - - spawn(2) - if(!user.client) return - winset(user, windowid, "on-close=\".windowclose [param]\"") - -// log_debug("OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]") - - - -// the on-close client verb -// called when a browser popup window is closed after registering with proc/onclose() -// if a valid atom reference is supplied, call the atom's Topic() with "close=1" -// otherwise, just reset the client mob's machine var. -// -/client/verb/windowclose(var/atomref as text) - set hidden = 1 // hide this verb from the user's panel - set name = ".windowclose" // no autocomplete on cmd line - -// log_debug("windowclose: [atomref]") - - if(atomref!="null") // if passed a real atomref - var/hsrc = locate(atomref) // find the reffed atom - if(hsrc) -// log_debug("[src] Topic [href] [hsrc]") - - usr = src.mob - src.Topic("close=1", list("close"="1"), hsrc) // this will direct to the atom's - return // Topic() proc via client.Topic() - - // no atomref specified (or not found) - // so just reset the user mob's machine var - if(src && src.mob) -// log_debug("[src] was [src.mob.machine], setting to null") - - src.mob.unset_machine() - return +/** + * Registers the on-close verb for a browse window (client/verb/.windowclose) + * this will be called when the close-button of a window is pressed. + + * This is usually only needed for devices that regularly update the browse window, + * e.g. canisters, timers, etc. + * + * windowid should be the specified window name + * e.g. code is : show_browser(user, text, "window=fred") + * then use : onclose(user, "fred") + * + * Optionally, specify the "ref" parameter as the controlled atom (usually src) + * to pass a "close=1" parameter to the atom's Topic() proc for special handling. + * Otherwise, the user mob's machine var will be reset directly. + */ +/proc/onclose(mob/user, windowid, atom/ref) + if(!user || !user.client) + return + + var/param = ref ? "\ref[ref]" : "null" + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob, post_onclose), windowid, param), 2) + +/mob/proc/post_onclose(windowid, param) + if(client) + winset(src, windowid, "on-close=\".windowclose [param]\"") + + +/** + * the on-close client verb + * + * called when a browser popup window is closed after registering with proc/onclose() + * if a valid atom reference is supplied, call the atom's Topic() with "close=1" + * otherwise, just reset the client mob's machine var. + */ +/client/verb/windowclose(atomref as text) + set name = ".windowclose" + set hidden = TRUE + if (atomref != "null") + atomref = locate(atomref) + if (atomref) + usr = src?.mob + Topic("close=1", list("close" = "1"), atomref) + return + + if (src?.mob) + mob.unset_machine() diff --git a/code/datums/callbacks.dm b/code/datums/callbacks.dm index 575a3f139594..cc2ebd14313f 100644 --- a/code/datums/callbacks.dm +++ b/code/datums/callbacks.dm @@ -1,46 +1,44 @@ -// USAGE: -// -// var/datum/callback/C = new(object|null, /proc/type/path|"procstring", arg1, arg2, ... argn) -// var/timerid = addtimer(C, time, timertype) -// OR -// var/timerid = addtimer(CALLBACK(object|null, /proc/type/path|procstring, arg1, arg2, ... argn), time, timertype) -// -// Note: proc strings can only be given for datum proc calls, global procs must be proc paths -// Also proc strings are strongly advised against because they don't compile error if the proc stops existing -// See the note on proc typepath shortcuts -// -// INVOKING THE CALLBACK: -// var/result = C.Invoke(args, to, add) //additional args are added after the ones given when the callback was created -// OR -// var/result = C.InvokeAsync(args, to, add) //Sleeps will not block, returns . on the first sleep (then continues on in the "background" after the sleep/block ends), otherwise operates normally. -// OR -// INVOKE_ASYNC() to immediately create and call InvokeAsync -// -// PROC TYPEPATH SHORTCUTS (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...) -// -// global proc while in another global proc: -// .procname -// Example: -// CALLBACK(GLOBAL_PROC, .some_proc_here) -// -// proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents: -// .procname -// Example: -// CALLBACK(src, .some_proc_here) -// -// -// when the above doesn't apply: -// .proc/procname -// Example: -// CALLBACK(src, .proc/some_proc_here) -// -// proc defined on a parent of a some type: -// /some/type/.proc/some_proc_here -// -// -// -// Other wise you will have to do the full typepath of the proc (/type/of/thing/proc/procname) - +/** + *# Callback Datums + *A datum that holds a proc to be called on another object, used to track proccalls to other objects + * + * ## USAGE + * + * ``` + * var/datum/callback/C = new(object|null, PROC_REF(procname), arg1, arg2, ... argn) + * var/timerid = addtimer(C, time, timertype) + * you can also use the compiler define shorthand + * var/timerid = addtimer(CALLBACK(object|null, PROC_REF(procname), arg1, arg2, ... argn), time, timertype) + * ``` + * + * Note: proc strings can only be given for datum proc calls, global procs must be proc paths + * + * Also proc strings are strongly advised against because they don't compile error if the proc stops existing + * + * In some cases you can provide a shortform of the procname, see the proc typepath shortcuts documentation below + * + * ## INVOKING THE CALLBACK + *`var/result = C.Invoke(args, to, add)` additional args are added after the ones given when the callback was created + * + * `var/result = C.InvokeAsync(args, to, add)` Asynchronous - returns . on the first sleep then continues on in the background + * after the sleep/block ends, otherwise operates normally. + * + * ## PROC TYPEPATH SHORTCUTS + * (these operate on paths, not types, so to these shortcuts, datum is NOT a parent of atom, etc...) + * + * ### proc defined on current(src) object OR overridden at src or any of its parents: + * PROC_REF(procname) + * + * `CALLBACK(src, PROC_REF(some_proc_here))` + * + * ### global proc + * GLOBAL_PROC_REF(procname) + * + * `CALLBACK(src, GLOBAL_PROC_REF(some_proc_here))` + * + * ### proc defined on some type + * TYPE_PROC_REF(/some/type/, some_proc_here) + */ /datum/callback var/datum/object = GLOBAL_PROC var/delegate diff --git a/code/datums/category.dm b/code/datums/category.dm index 45b2df59966d..d345573374c9 100644 --- a/code/datums/category.dm +++ b/code/datums/category.dm @@ -12,16 +12,16 @@ categories_by_name = new() for(var/category_type in typesof(category_group_type)) var/datum/category_group/category = category_type - if(initial(category.name)) - category = new category(src) - categories += category - categories_by_name[category.name] = category - categories = dd_sortedObjectList(categories) + if(TYPE_IS_ABSTRACT(category)) + continue + category = new category(src) + categories += category + ASSERT(category.name) + categories_by_name[category.name] = category + categories = sortTim(categories, /proc/cmp_category_groups) /datum/category_collection/Destroy() - for(var/category in categories) - qdel(category) - categories.Cut() + QDEL_LIST(categories) return ..() /****************** @@ -29,6 +29,7 @@ ******************/ /datum/category_group var/name = "" + var/sort_order = 0 // Sort order of categories, higher is later var/category_item_type // Type of items to initialize var/list/datum/category_item/items // List of initialized items var/list/datum/category_item/items_by_name // Associative list of initialized items, by name @@ -42,10 +43,12 @@ for(var/item_type in typesof(category_item_type)) var/datum/category_item/item = item_type - if(initial(item.name)) - item = new item(src) - items += item - items_by_name[item.name] = item + if(TYPE_IS_ABSTRACT(item)) + continue + item = new item(src) + items += item + ASSERT(item.name) + items_by_name[item.name] = item // For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order // If you change this, confirm that character setup doesn't become completely unordered. @@ -58,7 +61,7 @@ collection = null return ..() -datum/category_group/dd_SortValue() +/datum/category_group/dd_SortValue() return name @@ -66,6 +69,7 @@ datum/category_group/dd_SortValue() * Category Items * *****************/ /datum/category_item + abstract_type = /datum/category_item var/name = "" var/datum/category_group/category // The group this item belongs to @@ -77,5 +81,5 @@ datum/category_group/dd_SortValue() category = null return ..() -datum/category_item/dd_SortValue() +/datum/category_item/dd_SortValue() return name diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm index 3825672636f4..bf03370505e8 100644 --- a/code/datums/cinematic.dm +++ b/code/datums/cinematic.dm @@ -1,49 +1,41 @@ -GLOBAL_DATUM_INIT(cinematic, /datum/cinematic, new) -//Was moved from the gameticker to here. Could use further improvement. - +var/global/datum/cinematic/cinematic = new /datum/cinematic //station_explosion used to be a variable for every mob's hud. Which was a waste! //Now we have a general cinematic centrally held within the gameticker....far more efficient! - var/obj/screen/cinematic_screen = null + var/obj/screen/cinematic/cinematic_screen = null //Plus it provides an easy way to make cinematics for other events. Just use this as a template :) -/datum/cinematic/proc/station_explosion_cinematic(var/station_missed=0, var/datum/game_mode/override) +/datum/cinematic/proc/station_explosion_cinematic(var/station_missed=0, var/decl/game_mode/override) set waitfor = FALSE - if(cinematic_screen) + if(cinematic_screen) return //already a cinematic in progress! if(!override) override = SSticker.mode if(!override) - override = gamemode_cache["extended"] + override = GET_DECL(/decl/game_mode/extended) if(!override) return //initialise our cinematic screen object - cinematic_screen = new(src) - cinematic_screen.icon = 'icons/effects/station_explosion.dmi' - cinematic_screen.icon_state = "station_intact" - cinematic_screen.plane = HUD_PLANE - cinematic_screen.layer = HUD_ABOVE_ITEM_LAYER - cinematic_screen.mouse_opacity = 0 - cinematic_screen.screen_loc = "LEFT+1,BOTTOM" + cinematic_screen = new //Let's not discuss how this worked previously. var/list/viewers = list() - for(var/mob/living/M in GLOB.living_mob_list_) + for(var/mob/living/M in global.living_mob_list_) if(M.client) M.client.screen += cinematic_screen //show every client the cinematic - viewers[M.client] = M.stunned - M.stunned = 8000 + viewers[M.client] = GET_STATUS(M, STAT_STUN) + M.set_status_condition(STAT_STUN, 8000) override.nuke_act(cinematic_screen, station_missed) //cinematic happens here, as does mob death. - //If its actually the end of the round, wait for it to end. - //Otherwise if its a verb it will continue on afterwards. + //If it's actually the end of the round, wait for it to end. + //Otherwise if it's a verb it will continue on afterwards. sleep(30 SECONDS) for(var/client/C in viewers) if(C.mob) - C.mob.stunned = viewers[C] + C.mob.set_status_condition(STAT_STUN, viewers[C]) C.screen -= cinematic_screen QDEL_NULL(cinematic_screen) \ No newline at end of file diff --git a/code/datums/colors/color_generator.dm b/code/datums/colors/color_generator.dm index 05a6c5b95284..756d350ffd8e 100644 --- a/code/datums/colors/color_generator.dm +++ b/code/datums/colors/color_generator.dm @@ -1,4 +1,4 @@ -decl/color_generator +/decl/color_generator var/color = COLOR_WHITE var/min_random_span = -25 var/max_random_span = 25 @@ -7,7 +7,7 @@ decl/color_generator . = create_color() for(var/i in 1 to 3) .[i] += rand(min_random_span, max_random_span) - .[i] = Clamp(.[i], 0, 255) + .[i] = clamp(.[i], 0, 255) . = rgb(.[1], .[2], .[3]) /decl/color_generator/proc/create_color() diff --git a/code/datums/communication/aooc.dm b/code/datums/communication/aooc.dm index d01cd42b899b..8c4a25349c3e 100644 --- a/code/datums/communication/aooc.dm +++ b/code/datums/communication/aooc.dm @@ -1,32 +1,41 @@ +#define SPAN_AOOC(X) "[create_text_tag("aooc", "Antag-OOC:", target)] [X]" + /decl/communication_channel/aooc name = "AOOC" - config_setting = "aooc_allowed" + config_setting = /decl/config/toggle/on/aooc_allowed expected_communicator_type = /client flags = COMMUNICATION_LOG_CHANNEL_NAME|COMMUNICATION_ADMIN_FOLLOW log_proc = /proc/log_ooc mute_setting = MUTE_AOOC show_preference_setting = /datum/client_preference/show_aooc -/decl/communication_channel/aooc/can_communicate(var/client/C, var/message) +/decl/communication_channel/aooc/can_communicate(client/C, message) . = ..() if(!.) return if(!C.holder) if(isghost(C.mob)) - to_chat(src, "You cannot use [name] while ghosting/observing!") + to_chat(src, SPAN_WARNING("You cannot use [name] while ghosting/observing!")) return FALSE - if(!(C.mob && C.mob.mind && C.mob.mind.special_role)) - to_chat(C, "You must be an antag to use [name].") + if(!(C.mob?.mind?.assigned_special_role)) + to_chat(C, SPAN_DANGER("You must be an antag to use [name].")) return FALSE -/decl/communication_channel/aooc/do_communicate(var/client/C, var/message) +/decl/communication_channel/aooc/do_communicate(client/C, message) var/datum/admins/holder = C.holder - for(var/client/target in GLOB.clients) - if(target.holder) - receive_communication(C, target, "[create_text_tag("aooc", "Antag-OOC:", target)] [get_options_bar(C, 0, 1, 1)]: [message]") - else if(target.mob && target.mob.mind && target.mob.mind.special_role) + for(var/client/target in global.clients) + if(check_rights(R_INVESTIGATE, FALSE, target)) + receive_communication(C, target, SPAN_AOOC("[get_options_bar(C, 0, 1, 1)]: [message]")) + else if(target.mob?.mind?.assigned_special_role) var/display_name = C.key - var/player_display = holder ? "[display_name]([usr.client.holder.rank])" : display_name - receive_communication(C, target, "[create_text_tag("aooc", "Antag-OOC:", target)] [player_display]: [message]") \ No newline at end of file + var/player_display = holder ? "[display_name]([C.holder.rank])" : display_name + receive_communication(C, target, SPAN_AOOC("[player_display]: [message]")) + +/decl/communication_channel/aooc/do_broadcast(message) + for (var/client/target in global.clients) + if (check_rights(R_INVESTIGATE, FALSE, target) || target.mob?.mind?.assigned_special_role) + receive_broadcast(target, SPAN_AOOC("SYSTEM BROADCAST: [message]")) + +#undef SPAN_AOOC diff --git a/code/datums/communication/channel.dm b/code/datums/communication/channel.dm index 88d3a16196da..c9dc993cb37f 100644 --- a/code/datums/communication/channel.dm +++ b/code/datums/communication/channel.dm @@ -9,6 +9,9 @@ var/mute_setting var/show_preference_setting +/decl/communication_channel/proc/get_emblem(client/C) + return + /decl/communication_channel/proc/can_ignore(var/client/C) if (!C) return TRUE @@ -16,7 +19,7 @@ if(!show_preference_setting) return FALSE // If you're trying to see the channel, you can't ignore it - if (C.get_preference_value(show_preference_setting) == GLOB.PREF_SHOW) + if (C.get_preference_value(show_preference_setting) == PREF_SHOW) return FALSE // I suppose the host is more equal than others if (check_rights(R_HOST, 0, C)) @@ -45,7 +48,7 @@ log_debug("[log_info_line(communicator)] attempted to communicate over the channel [src] but was of an unexpected type.") return FALSE - if(config_setting && !config.vars[config_setting] && !check_rights(R_INVESTIGATE,0,communicator)) + if(config_setting && !get_config_value(config_setting) && !check_rights(R_INVESTIGATE,0,communicator)) to_chat(communicator, "[name] is globally muted.") return FALSE @@ -99,6 +102,41 @@ /decl/communication_channel/proc/do_receive_communication(var/datum/communicator, var/datum/receiver, var/message) to_chat(receiver, message) + +/* + * Procs for the handling of system broadcasts + */ +/decl/communication_channel/proc/broadcast(message, force = FALSE) + if (!can_broadcast(message, force)) + return FALSE + call(log_proc)("[(flags & COMMUNICATION_LOG_CHANNEL_NAME) ? "([name]) " : ""]SYSTEM BROADCAST : [message]") + return do_broadcast(message, force) + + +/decl/communication_channel/proc/can_broadcast(message, override_config = FALSE) + if (!message) + return FALSE + + if (!override_config && config_setting && !get_config_value(config_setting)) + return FALSE + + return TRUE + + +/decl/communication_channel/proc/do_broadcast(message) + return + + +/decl/communication_channel/proc/receive_broadcast(datum/receiver, message) + if (!can_receive_communication(receiver)) + return + do_receive_broadcast(receiver, message) + + +/decl/communication_channel/proc/do_receive_broadcast(datum/receiver, message) + to_chat(receiver, message) + + // Misc. helpers /datum/proc/communication_identifier() return usr ? "[src] - usr: [plain_key_name(usr)]" : "[src]" @@ -120,4 +158,10 @@ return channel.communicate(arglist(new_args)) +/proc/communicate_broadcast(channel_type, message, forced = FALSE) + var/list/channels = decls_repository.get_decls_of_subtype(/decl/communication_channel) + var/decl/communication_channel/channel = channels[channel_type] + + return channel.broadcast(message, forced) + #undef plain_key_name diff --git a/code/datums/communication/dsay.dm b/code/datums/communication/dsay.dm index 5530e9ab7192..c329b243c89b 100644 --- a/code/datums/communication/dsay.dm +++ b/code/datums/communication/dsay.dm @@ -3,18 +3,19 @@ /decl/communication_channel/dsay name = "DSAY" - config_setting = "dsay_allowed" + config_setting = /decl/config/toggle/on/dsay_allowed expected_communicator_type = /client flags = COMMUNICATION_LOG_CHANNEL_NAME log_proc = /proc/log_say mute_setting = MUTE_DEADCHAT show_preference_setting = /datum/client_preference/show_dsay +// Changes the default speech_method kwarg. /decl/communication_channel/dsay/communicate(communicator, message, speech_method = /decl/dsay_communication/say) - ..() + return ..() /decl/communication_channel/dsay/can_communicate(var/client/communicator, var/message, var/speech_method_type) - var/decl/dsay_communication/speech_method = decls_repository.get_decl(speech_method_type) + var/decl/dsay_communication/speech_method = GET_DECL(speech_method_type) switch(speech_method.can_communicate(communicator, message)) if(DSAY_CAN_COMMUNICATE) return TRUE @@ -22,11 +23,11 @@ return ..() /decl/communication_channel/dsay/do_communicate(var/client/communicator, var/message, var/speech_method_type) - var/decl/dsay_communication/speech_method = decls_repository.get_decl(speech_method_type) + var/decl/dsay_communication/speech_method = GET_DECL(speech_method_type) speech_method.adjust_channel(src) - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(!speech_method.can_receive(communicator, M)) continue var/sent_message = speech_method.get_message(communicator, M, message) @@ -43,7 +44,7 @@ /decl/dsay_communication/proc/can_receive(var/client/C, var/mob/M) if(istype(C) && C.mob == M) return TRUE - if(M.get_preference_value(/datum/client_preference/show_dsay) == GLOB.PREF_HIDE) + if(M.get_preference_value(/datum/client_preference/show_dsay) == PREF_HIDE) return FALSE if(istype(C) && M.is_key_ignored(C.key)) return FALSE @@ -61,12 +62,8 @@ keyname = C.key if(C.mob) //Most of the time this is the dead/observer mob; we can totally use him if there is no better name - var/mindname + var/mindname = C.mob.mind?.name // the mind's "original name" var/realname = C.mob.real_name - if(C.mob.mind) - mindname = C.mob.mind.name - if(C.mob.mind.original && C.mob.mind.original.real_name) - realname = C.mob.mind.original.real_name if(mindname && mindname != realname) name = "[realname] died as [mindname]" else @@ -74,12 +71,13 @@ var/lname var/mob/observer/ghost/DM + var/anon_say_pref = (C.get_preference_value(/datum/client_preference/anon_say) == PREF_YES) if(isghost(C.mob)) DM = C.mob if(M.client.holder) // What admins see - lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])" + lname = "[keyname][(DM && anon_say_pref) ? "*" : (DM ? "" : "^")] ([name])" else - if(DM && DM.anonsay) // If the person is actually observer they have the option to be anonymous + if(DM && anon_say_pref) // If the person is actually observer they have the option to be anonymous lname = "Ghost of [name]" else if(DM) // Non-anons lname = "[keyname] ([name])" diff --git a/code/datums/communication/looc.dm b/code/datums/communication/looc.dm index c2874250785c..925ccbeb1acd 100644 --- a/code/datums/communication/looc.dm +++ b/code/datums/communication/looc.dm @@ -1,6 +1,6 @@ /decl/communication_channel/ooc/looc name = "LOOC" - config_setting = "looc_allowed" + config_setting = /decl/config/toggle/on/looc_allowed flags = COMMUNICATION_NO_GUESTS|COMMUNICATION_LOG_CHANNEL_NAME|COMMUNICATION_ADMIN_FOLLOW show_preference_setting = /datum/client_preference/show_looc @@ -32,14 +32,18 @@ var/received_message = t.receive_looc(C, key, message, listening_mob.looc_prefix()) receive_communication(C, t, received_message) - for(var/client/adm in GLOB.admins) //Now send to all admins that weren't in range. - if(!(adm in listening_clients) && adm.get_preference_value(/datum/client_preference/staff/show_rlooc) == GLOB.PREF_SHOW) + for(var/client/adm in global.admins) //Now send to all admins that weren't in range. + if(!(adm in listening_clients) && adm.get_preference_value(/datum/client_preference/staff/show_rlooc) == PREF_SHOW) var/received_message = adm.receive_looc(C, key, message, "R") receive_communication(C, adm, received_message) /client/proc/receive_looc(var/client/C, var/commkey, var/message, var/prefix) var/mob/M = C.mob - var/display_name = isghost(M) ? commkey : M.name + var/display_name + if(isghost(M) && C.get_preference_value(/datum/client_preference/anon_say) != PREF_YES) + display_name = commkey + else + display_name = M.name var/admin_stuff = holder ? "/([commkey])" : "" if(prefix) prefix = "\[[prefix]\] " diff --git a/code/datums/communication/ooc.dm b/code/datums/communication/ooc.dm index 576c9446be92..2d206d206bc8 100644 --- a/code/datums/communication/ooc.dm +++ b/code/datums/communication/ooc.dm @@ -1,6 +1,6 @@ /decl/communication_channel/ooc name = "OOC" - config_setting = "ooc_allowed" + config_setting = /decl/config/toggle/on/ooc_allowed expected_communicator_type = /client flags = COMMUNICATION_NO_GUESTS log_proc = /proc/log_ooc @@ -13,7 +13,7 @@ return if(!C.holder) - if(!config.dooc_allowed && (C.mob.stat == DEAD)) + if(!get_config_value(/decl/config/toggle/on/dooc_allowed) && (C.mob.stat == DEAD)) to_chat(C, "[name] for dead mobs has been turned off.") return FALSE if(findtext(message, "byond://")) @@ -38,10 +38,10 @@ var/can_badmin = !is_stealthed && can_select_ooc_color(C) && (C.prefs.ooccolor != initial(C.prefs.ooccolor)) var/ooc_color = C.prefs.ooccolor - for(var/client/target in GLOB.clients) + for(var/client/target in global.clients) if(target.is_key_ignored(C.key)) // If we're ignored by this person, then do nothing. continue - var/sent_message = "[create_text_tag("ooc", "OOC:", target)] [C.key]: [message]" + var/sent_message = "[create_text_tag("ooc", "OOC:", target)] [get_emblem(C)][C.key]: [message]" if(can_badmin) receive_communication(C, target, "[sent_message]") else diff --git a/code/datums/communication/pray.dm b/code/datums/communication/pray.dm index 880d0fc75f07..8ddca34025e1 100644 --- a/code/datums/communication/pray.dm +++ b/code/datums/communication/pray.dm @@ -7,14 +7,14 @@ /decl/communication_channel/pray/do_communicate(var/mob/communicator, var/message, var/speech_method_type) var/image/cross = image('icons/obj/items/storage/bible.dmi',"bible") - for(var/m in GLOB.player_list) + for(var/m in global.player_list) var/mob/M = m if(!M.client) continue - if(M.client.holder && M.client.get_preference_value(/datum/client_preference/staff/show_chat_prayers) == GLOB.PREF_SHOW) - receive_communication(communicator, M, "\[SC\] \[DN\]\icon[cross] PRAY: [key_name(communicator, 1)]: [message]") + if(M.client.holder && M.client.get_preference_value(/datum/client_preference/staff/show_chat_prayers) == PREF_SHOW) + receive_communication(communicator, M, "\[SC\] \[DN\][html_icon(cross)] [SPAN_PURPLE("PRAY: ")][key_name(communicator, 1)]: [message]") else if(communicator == M) //Give it to ourselves - receive_communication(communicator, M, "\icon[cross] You send the prayer, \"[message]\" out into the heavens.") + receive_communication(communicator, M, "[html_icon(cross)] You send the prayer, \"[message]\" out into the heavens.") /decl/communication_channel/pray/receive_communication(var/mob/communicator, var/mob/receiver, var/message) ..() diff --git a/code/datums/composite_sounds/_composite_sound.dm b/code/datums/composite_sounds/_composite_sound.dm new file mode 100644 index 000000000000..c8b412c6c0a3 --- /dev/null +++ b/code/datums/composite_sounds/_composite_sound.dm @@ -0,0 +1,90 @@ +/* + output_atoms (list of atoms) The destination(s) for the sounds + mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end. + mid_length (num) The length to wait between playing mid_sounds + start_sound (soundfile) Played before starting the mid_sounds loop + start_length (num) How long to wait before starting the main loop after playing start_sound + end_sound (soundfile) The sound played after the main loop has concluded + chance (num) Chance per loop to play a mid_sound + play_volume (num) Sound output volume + max_loops (num) The max amount of loops to run for. + direct (bool) If true plays directly to provided atoms instead of from them +*/ + +/datum/composite_sound + var/list/atom/output_atoms + var/mid_sounds + var/mid_length + var/start_sound + var/start_length + var/end_sound + var/chance + var/play_volume = 100 + var/max_loops + var/direct + var/timerid + var/started = FALSE + +/datum/composite_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE) + if(!mid_sounds) + WARNING("A composite sound datum was created without sounds to play.") + return + + output_atoms = _output_atoms + direct = _direct + + if(start_immediately) + start() + +/datum/composite_sound/Destroy() + stop() + output_atoms = null + return ..() + +/datum/composite_sound/proc/start(atom/add_thing) + if(add_thing) + LAZYDISTINCTADD(output_atoms, add_thing) + if(timerid) + return + started = TRUE + on_start() + +/datum/composite_sound/proc/stop(atom/remove_thing) + if(remove_thing) + LAZYREMOVE(output_atoms, remove_thing) + if(!timerid) + return + started = FALSE + on_stop() + deltimer(timerid) + timerid = null + +/datum/composite_sound/proc/sound_loop(starttime) + if(max_loops && (world.time >= starttime + mid_length * max_loops)) + stop() + return + if(!chance || prob(chance)) + play(get_sound(starttime)) + if(!timerid) + timerid = addtimer(CALLBACK(src, PROC_REF(sound_loop), world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP) + +/datum/composite_sound/proc/play(soundfile) + var/sound/S = sound(soundfile) + for(var/atom/thing as anything in output_atoms) + playsound(thing, S, play_volume) + +/datum/composite_sound/proc/get_sound(starttime, _mid_sounds) + . = _mid_sounds || mid_sounds + while(!isfile(.) && !isnull(.)) + . = pickweight(.) + +/datum/composite_sound/proc/on_start() + var/start_wait = 0 + if(start_sound) + play(start_sound) + start_wait = start_length + addtimer(CALLBACK(src, PROC_REF(sound_loop)), start_wait, TIMER_CLIENT_TIME) + +/datum/composite_sound/proc/on_stop() + if(end_sound) + play(end_sound) diff --git a/code/datums/composite_sounds/fire_sounds.dm b/code/datums/composite_sounds/fire_sounds.dm new file mode 100644 index 000000000000..ae6d8d714380 --- /dev/null +++ b/code/datums/composite_sounds/fire_sounds.dm @@ -0,0 +1,22 @@ +// Fire crackles were originally sourced from freesound.org and cut +// up/faded in Audacity but I have lost the original source link. :( +/datum/composite_sound/fire_crackles + start_sound = 'sound/ambience/firecrackle01.ogg' + start_length = 10 + mid_sounds = list( + 'sound/ambience/firecrackle02.ogg', + 'sound/ambience/firecrackle03.ogg', + 'sound/ambience/firecrackle04.ogg', + 'sound/ambience/firecrackle05.ogg' + ) + mid_length = 10 + end_sound = 'sound/ambience/firecrackle06.ogg' + play_volume = 10 + +/datum/composite_sound/grill + start_sound = 'sound/machines/kitchen/grill/grill-start.ogg' + start_length = 10 + mid_sounds = list('sound/machines/kitchen/grill/grill-mid1.ogg'=10) + mid_length = 40 + end_sound = 'sound/machines/kitchen/grill/grill-stop.ogg' + play_volume = 50 diff --git a/code/datums/composite_sounds/loom.dm b/code/datums/composite_sounds/loom.dm new file mode 100644 index 000000000000..3f5c525c1049 --- /dev/null +++ b/code/datums/composite_sounds/loom.dm @@ -0,0 +1,25 @@ +// Loom sampled from 'navette de métier à tisser.wav' by Naïma on freesound.org: https://freesound.org/people/Na%C3%AFma/sounds/510266/ +/datum/composite_sound/loom_working + start_sound = 'sound/items/loomstart.ogg' + start_length = 20 + mid_length = 12 + mid_sounds = list( + 'sound/items/loom1.ogg', + 'sound/items/loom2.ogg', + 'sound/items/loom3.ogg' + ) + end_sound = 'sound/items/loomstop.ogg' + play_volume = 40 + +// Spinning wheel sampled from 'Wooden Spinning Wheel' by Kessir on freesound.org: https://freesound.org/people/kessir/sounds/414554/ +/datum/composite_sound/spinning_wheel_working + start_sound = 'sound/items/spinningwheelstart.ogg' + start_length = 33 + mid_length = 20 + mid_sounds = list( + 'sound/items/spinningwheel1.ogg', + 'sound/items/spinningwheel2.ogg', + 'sound/items/spinningwheel3.ogg' + ) + end_sound = 'sound/items/spinningwheelstop.ogg' + play_volume = 60 \ No newline at end of file diff --git a/code/datums/composite_sounds/machinery_sounds.dm b/code/datums/composite_sounds/machinery_sounds.dm new file mode 100644 index 000000000000..e9247a13cf32 --- /dev/null +++ b/code/datums/composite_sounds/machinery_sounds.dm @@ -0,0 +1,7 @@ +/datum/composite_sound/microwave + start_sound = 'sound/machines/microwave/microwave-start.ogg' + start_length = 10 + mid_sounds = list('sound/machines/microwave/microwave-mid1.ogg'=10, 'sound/machines/microwave/microwave-mid2.ogg'=1) + mid_length = 10 + end_sound = 'sound/machines/microwave/microwave-end.ogg' + play_volume = 1 \ No newline at end of file diff --git a/code/datums/composite_sounds/vehicle_engine.dm b/code/datums/composite_sounds/vehicle_engine.dm new file mode 100644 index 000000000000..824d0044134b --- /dev/null +++ b/code/datums/composite_sounds/vehicle_engine.dm @@ -0,0 +1,7 @@ +/datum/composite_sound/vehicle_engine + start_sound = 'sound/machines/vehicle/engine_start.ogg' + start_length = 2 + mid_sounds = list('sound/machines/vehicle/engine_mid.ogg'=1) + mid_length = 6 + end_sound = 'sound/machines/vehicle/engine_end.ogg' + play_volume = 20 diff --git a/code/datums/config/_config.dm b/code/datums/config/_config.dm new file mode 100644 index 000000000000..7407f6d4de9e --- /dev/null +++ b/code/datums/config/_config.dm @@ -0,0 +1,168 @@ +#define CONFIG_FLAG_BOOL BITFLAG(0) +#define CONFIG_FLAG_NUM BITFLAG(1) +#define CONFIG_FLAG_ENUM BITFLAG(2) +#define CONFIG_FLAG_TEXT BITFLAG(3) +#define CONFIG_FLAG_LIST BITFLAG(4) +#define CONFIG_FLAG_HAS_VALUE BITFLAG(5) + +/proc/get_config_value(var/config_decl) + var/decl/config/config_option = GET_DECL(config_decl) + return config_option.value + +/proc/set_config_value(var/config_decl, var/new_value, var/defer_config_refresh = FALSE) + + // Get our actual value (loading from text etc. may change data type) + var/decl/config/config_option = GET_DECL(config_decl) + if((config_option.config_flags & (CONFIG_FLAG_NUM|CONFIG_FLAG_BOOL)) && istext(new_value)) + new_value = text2num(new_value) + else if((config_option.config_flags & (CONFIG_FLAG_ENUM|CONFIG_FLAG_TEXT)) && isnum(new_value)) + new_value = num2text(new_value) + + // Identical values, no point updating. + if(config_option.value == new_value) + return + + // Actually set the value. + var/old_value = config_option.value + config_option.set_value(new_value) + if(config_option.value != old_value && !defer_config_refresh) + config_option.update_post_value_set() + +/proc/toggle_config_value(var/config_decl) + var/decl/config/config_option = GET_DECL(config_decl) + if(!(config_option.config_flags & CONFIG_FLAG_BOOL)) + CRASH("Attempted to toggle non-boolean config entry [config_decl].") + set_config_value(config_decl, !config_option.value) + return config_option.value + +/decl/config + abstract_type = /decl/config + decl_flags = DECL_FLAG_MANDATORY_UID + var/desc + var/value + var/default_value + var/config_flags = CONFIG_FLAG_HAS_VALUE + var/protected = FALSE + + var/static/list/protected_vars = list( + "desc", + "value", + "default_value", + "config_flags", + "protected" + ) + +/decl/config/Initialize() + . = ..() + // Config options without values are assumed false and set to true if present in the loaded data. + // Otherwise we initialize to the default value. + if(!(config_flags & CONFIG_FLAG_HAS_VALUE)) + default_value = FALSE + if(desc) + desc += " Uncomment to enable." + else + desc = "Uncomment to enable." + value = default_value + +/decl/config/VV_hidden() + . = ..() + if(protected) + . |= protected_vars + +/decl/config/validate() + . = ..() + if(isnull(desc)) + . += "no config description set" + if(isnull(default_value)) + if(config_flags & CONFIG_FLAG_HAS_VALUE) + . += "null default value" + else + if((config_flags & (CONFIG_FLAG_NUM|CONFIG_FLAG_ENUM)) && !isnum(default_value)) + . += "has numeric or enum flag but not numeric default_value" + else if((config_flags & CONFIG_FLAG_BOOL) && default_value != TRUE && default_value != FALSE) + . += "has bool flag but not TRUE (1) or FALSE (0) default_value" + else if((config_flags & CONFIG_FLAG_TEXT) && !istext(default_value)) + . += "has text flag but not text default_value" + else if((config_flags & CONFIG_FLAG_LIST) && !islist(default_value)) + . += "has list flag but not list default_value" + set_value(handle_value_deconversion(default_value)) + if(!compare_values(value, default_value)) + . += "setting to default value via proc resulted in different value ([serialize_value(value)] != [serialize_value(default_value)])" + var/comparison_fail = default_value_serialize_comparison_fails() + if(comparison_fail) + . += "conversion and deconversion of default value does not equal default value ([comparison_fail])" + +/decl/config/proc/compare_values(var/value_one, var/value_two) + return value_one == value_two + +/decl/config/proc/default_value_serialize_comparison_fails() + var/new_val = handle_value_conversion(handle_value_deconversion(default_value)) + if(!compare_values(new_val, default_value)) + return "[new_val] != [default_value]" + +/decl/config/proc/sanitize_value() + SHOULD_CALL_PARENT(TRUE) + var/invalid_value = FALSE + if((config_flags & CONFIG_FLAG_BOOL) && value != TRUE && value != FALSE) + invalid_value = TRUE + else if((config_flags & (CONFIG_FLAG_NUM|CONFIG_FLAG_ENUM)) && !isnum(value)) + invalid_value = TRUE + else if((config_flags & CONFIG_FLAG_TEXT) && !istext(value)) + invalid_value = TRUE + else if((config_flags & CONFIG_FLAG_LIST) && !islist(value)) + invalid_value = TRUE + if(invalid_value) + value = default_value + +/decl/config/proc/update_post_value_set() + SHOULD_CALL_PARENT(TRUE) + return + +/decl/config/proc/get_comment_desc_text() + if(desc) + if(islist(desc)) + for(var/config_line in desc) + LAZYADD(., "## [config_line]") + else + LAZYADD(., "## [desc]") + +/decl/config/proc/get_comment_value_text() + if(config_flags & CONFIG_FLAG_HAS_VALUE) + if(compare_values(value, default_value)) + . += "#[uppertext(uid)] [serialize_default_value()]" + else + . += "[uppertext(uid)] [serialize_value()]" + else if(value) + . += uppertext(uid) + else + . += "#[uppertext(uid)]" + +/decl/config/proc/get_config_file_text() + + . = list() + + var/add_desc = get_comment_desc_text() + if(!isnull(add_desc)) + . += add_desc + + var/add_value = get_comment_value_text() + if(!isnull(add_value)) + . += add_value + + return jointext(., "\n") + +/decl/config/proc/serialize_value() + return "[handle_value_deconversion(value)]" + +/decl/config/proc/serialize_default_value() + return "[handle_value_deconversion(default_value)]" + +/decl/config/proc/handle_value_conversion(var/new_value) + return new_value + +/decl/config/proc/handle_value_deconversion(var/new_value) + return new_value + +/decl/config/proc/set_value(var/new_value) + value = handle_value_conversion(new_value) + sanitize_value() diff --git a/code/datums/config/_config_categories.dm b/code/datums/config/_config_categories.dm new file mode 100644 index 000000000000..b9212994768d --- /dev/null +++ b/code/datums/config/_config_categories.dm @@ -0,0 +1,40 @@ +/decl/configuration_category + abstract_type = /decl/configuration_category + var/name + var/desc + var/configuration_file_location = "config/configuration.txt" + var/list/associated_configuration + +/decl/configuration_category/Initialize() + if(length(associated_configuration)) + for(var/decl_type in associated_configuration) + associated_configuration -= decl_type + associated_configuration += GET_DECL(decl_type) + return ..() + +/decl/configuration_category/validate() + . = ..() + if(!name) + . += "no name set" + if(!desc) + . += "no description supplied" + if(isnull(configuration_file_location)) + . += "null dump file target" + +/decl/configuration_category/proc/get_config_category_text() + + if(!length(associated_configuration)) + return "" + + var/list/header = list( + "##", + "# [uppertext(name)]", + "# [desc]", + "##" + ) + + . = list("[jointext(header, "\n")]") + associated_configuration = sortTim(associated_configuration, /proc/cmp_decl_uid_asc) + for(var/decl/config/config_option in associated_configuration) + . += config_option.get_config_file_text() + return jointext(., "\n\n") diff --git a/code/datums/config/config_enum.dm b/code/datums/config/config_enum.dm new file mode 100644 index 000000000000..8cfbd73f7fc4 --- /dev/null +++ b/code/datums/config/config_enum.dm @@ -0,0 +1,50 @@ +/decl/config/enum + abstract_type = /decl/config/enum + default_value = 0 + config_flags = CONFIG_FLAG_ENUM | CONFIG_FLAG_HAS_VALUE + var/list/enum_map + +/decl/config/enum/validate() + . = ..() + if(!length(enum_map)) + . += "enum config has zero-length enum_map" + +/decl/config/enum/serialize_value() + var/enum_val + for(var/val in enum_map) + if(value == enum_map[val]) + enum_val = val + break + if(isnull(enum_val)) + enum_val = handle_value_deconversion(value) + return "[enum_val]" + +/decl/config/enum/serialize_default_value() + var/enum_val + for(var/val in enum_map) + if(default_value == enum_map[val]) + enum_val = val + break + if(isnull(enum_val)) + enum_val = handle_value_deconversion(default_value) + return "[enum_val]" + +/decl/config/enum/Initialize() + . = ..() + if(islist(enum_map) && length(enum_map)) + if(islist(desc)) + desc += "[desc] Valid values: [english_list(enum_map)]." + else if(desc) + desc = "[desc] Valid values: [english_list(enum_map)]." + else + desc = "Valid values: [english_list(enum_map)]." + +/decl/config/enum/set_value(var/new_value) + if(istext(new_value)) + new_value = trim(lowertext(new_value)) + if(new_value in enum_map) + new_value = enum_map[new_value] + else + log_error("Invalid key '[new_value]' supplied to [type]. [json_encode(enum_map)]") + new_value = default_value + return ..(new_value) diff --git a/code/datums/config/config_list.dm b/code/datums/config/config_list.dm new file mode 100644 index 000000000000..a2c5893c39ca --- /dev/null +++ b/code/datums/config/config_list.dm @@ -0,0 +1,25 @@ +/decl/config/lists + abstract_type = /decl/config/lists + default_value = list() + config_flags = CONFIG_FLAG_LIST | CONFIG_FLAG_HAS_VALUE + +/decl/config/lists/handle_value_deconversion(var/new_value) + return json_encode(new_value) + +/decl/config/lists/handle_value_conversion(var/new_value) + return json_decode(new_value) + +/decl/config/lists/compare_values(var/value_one, var/value_two) + if(!islist(value_one) || !islist(value_two)) + return ..(value_one, value_two) + if(length(value_one) != length(value_two)) + return FALSE + for(var/i = 1 to length(value_one)) + if(!same_entries(value_one[i], value_two[i]) && value_one[i] != value_two[i]) + return FALSE + return TRUE + +/decl/config/lists/default_value_serialize_comparison_fails() + var/list/new_value = handle_value_conversion(handle_value_deconversion(default_value)) + if(!compare_values(new_value, default_value)) + return "[json_encode(new_value)] != [json_encode(default_value)]" diff --git a/code/datums/config/config_num.dm b/code/datums/config/config_num.dm new file mode 100644 index 000000000000..9e28c6e5ec06 --- /dev/null +++ b/code/datums/config/config_num.dm @@ -0,0 +1,18 @@ +/decl/config/num + abstract_type = /decl/config/num + config_flags = CONFIG_FLAG_NUM | CONFIG_FLAG_HAS_VALUE + default_value = 0 + var/min_value = -(INFINITY) + var/max_value = INFINITY + var/rounding + +/decl/config/num/sanitize_value() + ..() + value = clamp(value, min_value, max_value) + if(!isnull(rounding)) + value = round(value, rounding) + +/decl/config/num/compare_values(value_one, value_two) + if(!isnum(value_one) || !isnum(value_two) || !rounding) + return ..(value_one, value_two) + return abs(value_one - value_two) < rounding // epsilon compare due to floating point issues \ No newline at end of file diff --git a/code/datums/config/config_num_client.dm b/code/datums/config/config_num_client.dm new file mode 100644 index 000000000000..4b1527c9fb5a --- /dev/null +++ b/code/datums/config/config_num_client.dm @@ -0,0 +1,7 @@ +/decl/config/num/clients + abstract_type = /decl/config/num/clients + +/decl/config/num/clients/update_post_value_set() + for(var/client/client) + client.OnResize() + . = ..() diff --git a/code/datums/config/config_text.dm b/code/datums/config/config_text.dm new file mode 100644 index 000000000000..4385399d4d76 --- /dev/null +++ b/code/datums/config/config_text.dm @@ -0,0 +1,4 @@ +/decl/config/text + abstract_type = /decl/config/text + config_flags = CONFIG_FLAG_TEXT | CONFIG_FLAG_HAS_VALUE + default_value = "" diff --git a/code/datums/config/config_toggle.dm b/code/datums/config/config_toggle.dm new file mode 100644 index 000000000000..ac859d2edb00 --- /dev/null +++ b/code/datums/config/config_toggle.dm @@ -0,0 +1,4 @@ +/decl/config/toggle + abstract_type = /decl/config/toggle + config_flags = CONFIG_FLAG_BOOL + default_value = FALSE diff --git a/code/datums/config/config_toggle_on.dm b/code/datums/config/config_toggle_on.dm new file mode 100644 index 000000000000..873c917f6201 --- /dev/null +++ b/code/datums/config/config_toggle_on.dm @@ -0,0 +1,4 @@ +/decl/config/toggle/on + abstract_type = /decl/config/toggle/on + default_value = TRUE + config_flags = CONFIG_FLAG_BOOL | CONFIG_FLAG_HAS_VALUE diff --git a/code/datums/config/config_types/config_admin.dm b/code/datums/config/config_types/config_admin.dm new file mode 100644 index 000000000000..f99d02e0f6a0 --- /dev/null +++ b/code/datums/config/config_types/config_admin.dm @@ -0,0 +1,79 @@ +/decl/configuration_category/admin + name = "Admin" + desc = "Configuration options relating to administration." + associated_configuration = list( + /decl/config/num/mod_tempban_max, + /decl/config/num/mod_job_tempban_max, + /decl/config/num/autostealth, + /decl/config/toggle/on/guest_jobban, + /decl/config/toggle/on/auto_local_admin, + /decl/config/toggle/on/admin_jump, + /decl/config/toggle/on/admin_spawning, + /decl/config/toggle/on/admin_revive, + /decl/config/toggle/admin_ooccolor, + /decl/config/toggle/mods_can_job_tempban, + /decl/config/toggle/mods_can_tempban, + /decl/config/toggle/allow_unsafe_narrates + ) + +/decl/config/num/mod_tempban_max + uid = "mod_tempban_max" + default_value = 1440 + desc = "Maximum mod tempban duration (in minutes)." + +/decl/config/num/mod_job_tempban_max + uid = "mod_job_tempban_max" + default_value = 1440 + desc = "Maximum mod job tempban duration (in minutes)." + +/decl/config/num/autostealth + uid = "autostealth" + default_value = 0 + desc = "Sets a value in minutes after which to auto-hide staff who are AFK." + +/decl/config/toggle/on/guest_jobban + uid = "guest_jobban" + desc = list( + "Set to jobban 'Guest-' accounts from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions.", + "Set to 1 to jobban them from those positions, set to 0 to allow them." + ) + +/decl/config/toggle/on/auto_local_admin + uid = "auto_local_admin" + desc = "Set to 0/1 to disable/enable automatic admin rights for users connecting from the host the server is running on." + +/decl/config/toggle/on/admin_jump + uid = "allow_admin_jump" + desc = "Allows admin jumping." + +/decl/config/toggle/on/admin_spawning + uid = "allow_admin_spawning" + desc = "Allows admin item spawning." + +/decl/config/toggle/on/admin_revive + uid = "allow_admin_rev" + desc = "Allows admin revives." + +/decl/config/toggle/admin_ooccolor + uid = "allow_admin_ooccolor" + desc = "Comment this out to stop admins being able to choose their personal OOC color." + +/decl/config/toggle/mods_can_tempban + uid = "mods_can_tempban" + desc = "Chooses whether mods have the ability to tempban or not." + +/decl/config/toggle/mods_can_job_tempban + uid = "mods_can_job_tempban" + desc = "Chooses whether mods have the ability to issue tempbans for jobs or not." + +/decl/config/toggle/allow_unsafe_narrates + uid = "allow_unsafe_narrates" + desc = "Determines if admins are allowed to narrate using HTML tags." + +/decl/config/toggle/visible_examine + uid = "visible_examine" + desc = "Determines if a visible message should be shown when someone examines something ('Dave looks at you.')." + +/decl/config/toggle/allow_loadout_customization + uid = "loadout_customization" + desc = "Determines if all loadout items are allowed to have name and desc customized by default." diff --git a/code/datums/config/config_types/config_client.dm b/code/datums/config/config_types/config_client.dm new file mode 100644 index 000000000000..ed8a0224daff --- /dev/null +++ b/code/datums/config/config_types/config_client.dm @@ -0,0 +1,60 @@ +/decl/configuration_category/events + name = "Client" + desc = "Configuration options relating to client settings." + associated_configuration = list( + /decl/config/num/clients/lock_client_view_x, + /decl/config/num/clients/lock_client_view_y, + /decl/config/num/clients/max_client_view_x, + /decl/config/num/clients/max_client_view_y, + /decl/config/toggle/popup_admin_pm, + /decl/config/toggle/aggressive_changelog, + /decl/config/lists/forbidden_versions + ) + +/decl/config/lists/forbidden_versions + uid = "forbidden_versions" + default_value = list("512.0001", "512.0002") + desc = "BYOND builds that will result the client using them to be banned." + +/decl/config/num/clients/lock_client_view_x + uid = "lock_client_view_x" + default_value = 0 + desc = "Set to an integer to lock the automatic client view scaling on the X axis." + +/decl/config/num/clients/lock_client_view_y + uid = "lock_client_view_y" + default_value = 0 + desc = "Set to an integer to lock the automatic client view scaling on the Y axis." + +/decl/config/num/clients/max_client_view_x + uid = "max_client_view_x" + default_value = MAX_VIEW + desc = "Change to set a maximum size for the client view X scaling." + +/decl/config/num/clients/max_client_view_x/update_post_value_set() + global.click_catchers = null + for(var/client/client) + client.reset_click_catchers() + . = ..() + +/decl/config/num/clients/max_client_view_y + uid = "max_client_view_y" + default_value = MAX_VIEW + desc = "Change to set a maximum size for the client view Y scaling." + +/decl/config/num/clients/max_client_view_y/update_post_value_set() + global.click_catchers = null + for(var/client/client) + client.reset_click_catchers() + . = ..() + +/decl/config/toggle/popup_admin_pm + uid = "popup_admin_pm" + desc = list( + "Remove the # to show a popup 'reply to' window to every non-admin that receives an adminPM.", + "The intention is to make adminPMs more visible. (although I fnd popups annoying so this defaults to off)." + ) + +/decl/config/toggle/aggressive_changelog + uid = "aggressive_changelog" + desc = "Determines if the changelog file should automatically open when a user connects and hasn't seen the latest changelog." diff --git a/code/datums/config/config_types/config_debug.dm b/code/datums/config/config_types/config_debug.dm new file mode 100644 index 000000000000..66f250dd8ea6 --- /dev/null +++ b/code/datums/config/config_types/config_debug.dm @@ -0,0 +1,38 @@ +/decl/configuration_category/debug + name = "Debug" + desc = "Configuration options relating to error reporting." + associated_configuration = list( + /decl/config/num/debug_error_cooldown, + /decl/config/num/debug_error_limit, + /decl/config/num/debug_error_silence_time, + /decl/config/num/debug_error_msg_delay, + /decl/config/toggle/paranoid + ) + +/decl/config/num/debug_error_cooldown + uid = "error_cooldown" + desc = "The \"cooldown\" time for each occurrence of a unique error." + default_value = 600 + +/decl/config/num/debug_error_limit + uid = "error_limit" + desc = "How many occurrences before the next will silence them." + default_value = 50 + +/decl/config/num/debug_error_silence_time + uid = "error_silence_time" + desc = "How long a unique error will be silenced for." + default_value = 6000 + +/decl/config/num/debug_error_msg_delay + uid = "error_msg_delay" + desc = "How long to wait between messaging admins about occurrences of a unique error." + default_value = 50 + +/decl/config/toggle/paranoid + uid = "debug_paranoid" + desc = list( + "Uncomment to make proccall require R_ADMIN instead of R_DEBUG", + "designed for environments where you have testers but don't want them", + "able to use the more powerful debug options." + ) diff --git a/code/datums/config/config_types/config_events.dm b/code/datums/config/config_types/config_events.dm new file mode 100644 index 000000000000..3930a216c817 --- /dev/null +++ b/code/datums/config/config_types/config_events.dm @@ -0,0 +1,47 @@ +/decl/configuration_category/events + name = "Events" + desc = "Configuration options relating to event timers and probabilities." + associated_configuration = list( + /decl/config/enum/objectives_disabled, + /decl/config/lists/event_first_run, + /decl/config/lists/event_delay_lower, + /decl/config/lists/event_delay_upper, + /decl/config/toggle/on/allow_random_events + ) + +//if objectives are disabled or not +/decl/config/enum/objectives_disabled + uid = "objectives_disabled" + default_value = CONFIG_OBJECTIVE_NONE + desc = "Determines if objectives are disabled." + enum_map = list( + "none" = CONFIG_OBJECTIVE_NONE, + "verb" = CONFIG_OBJECTIVE_VERB, + "all" = CONFIG_OBJECTIVE_ALL + ) + +// No custom time, no custom time, between 80 to 100 minutes respectively. +/decl/config/lists/event_first_run + uid = "event_first_run" + desc = "If the first delay has a custom start time. Defined in minutes." + default_value = list(null, null, list("lower" = 80, "upper" = 100)) + +/decl/config/lists/event_delay_lower + uid = "event_delay_lower" + default_value = list(10, 30, 50) + desc = list( + "The lower delay between events in minutes.", + "Affect mundane, moderate, and major events respectively." + ) + +/decl/config/lists/event_delay_upper + uid = "event_delay_upper" + default_value = list(15, 45, 70) + desc = list( + "The upper delay between events in minutes.", + "Affect mundane, moderate, and major events respectively." + ) + +/decl/config/toggle/on/allow_random_events + uid = "allow_random_events" + desc = "Hash out to disable random events during the round." diff --git a/code/datums/config/config_types/config_game_option.dm b/code/datums/config/config_types/config_game_option.dm new file mode 100644 index 000000000000..a2e0c6720a7f --- /dev/null +++ b/code/datums/config/config_types/config_game_option.dm @@ -0,0 +1,175 @@ +/decl/configuration_category/game_options + name = "Game Options" + desc = "Configuration options relating to gameplay, such as movement, health and stamina." + associated_configuration = list( + /decl/config/num/movement_human, + /decl/config/num/movement_robot, + /decl/config/num/movement_animal, + /decl/config/num/movement_run, + /decl/config/num/movement_walk, + /decl/config/num/movement_creep, + /decl/config/num/movement_glide_size, + /decl/config/num/movement_min_sprint_cost, + /decl/config/num/movement_skill_sprint_cost_range, + /decl/config/num/movement_min_stamina_recovery, + /decl/config/num/movement_max_stamina_recovery, + /decl/config/num/max_gear_cost, + /decl/config/num/max_acts_per_interval, + /decl/config/num/act_interval, + /decl/config/num/dex_malus_brainloss_threshold, + /decl/config/num/default_darksight_range, + /decl/config/num/default_darksight_effectiveness, + /decl/config/toggle/grant_default_darksight, + /decl/config/num/expected_round_length, + /decl/config/toggle/on/allow_diagonal_movement, + /decl/config/toggle/expanded_alt_interactions, + /decl/config/toggle/ghosts_can_possess_animals, + /decl/config/toggle/assistant_maint, + /decl/config/toggle/ghost_interaction, + /decl/config/toggle/aliens_allowed, + /decl/config/toggle/allow_character_comments, + /decl/config/num/hide_comments_older_than, + /decl/config/toggle/stack_crafting_uses_tools, + /decl/config/toggle/on/stack_crafting_uses_types + ) + +/decl/config/num/movement_human + uid = "human_delay" + desc = "A modifier applied to the run/walk delay of human-type mobs. A higher value will result in slower movement." + default_value = -1 + +/decl/config/num/movement_robot + uid = "robot_delay" + desc = "A modifier applied to the run/walk delay of robots (cyborgs and drones). A higher value will result in slower movement." + +/decl/config/num/movement_animal + uid = "animal_delay" + desc = "A modifier applied to the run/walk delay of simple_animal type mobs (including combat drones and other simple hostile mobs). A higher value will result in slower movement." + +/decl/config/num/movement_run + uid = "run_delay" + default_value = 2 + desc = "A modifier applied to the run delay of all mobs, prior to the mob-specific modifiers being applied. A higher value will result in slower movement." + +/decl/config/num/movement_walk + uid = "walk_delay" + default_value = 4 + desc = "A modifier applied to the walk delay of all mobs, prior to the mob-specific modifiers being applied. A higher value will result in slower movement." + +/decl/config/num/movement_creep + uid = "creep_delay" + default_value = 6 + desc = "A modifier applied to the creep delay of all mobs, prior to the mob-specific modifiers being applied. A higher value will result in slower movement." + +/decl/config/num/movement_glide_size + uid = "glide_size_delay" + default_value = 1 + desc = "Set this to 0 for perfectly smooth movement gliding, or 1 or more for delayed chess move style movements." + +/decl/config/num/movement_min_sprint_cost + uid = "minimum_sprint_cost" + default_value = 0.8 + rounding = 0.01 + desc = "Value used for expending stamina during sprinting." + +/decl/config/num/movement_skill_sprint_cost_range + uid = "skill_sprint_cost_range" + default_value = 0.8 + rounding = 0.01 + desc = "Determines the severity of athletics skill when applied to stamina cost." + +/decl/config/num/movement_min_stamina_recovery + uid = "minimum_stamina_recovery" + default_value = 1 + desc = "Minimum stamina recovered per tick when resting." + +/decl/config/num/movement_max_stamina_recovery + uid = "maximum_stamina_recovery" + default_value = 3 + desc = "Maximum stamina recovered per tick when resting." + +/decl/config/num/max_gear_cost + uid = "max_gear_cost" + default_value = 10 + desc = "How many loadout points are available. Use 0 to disable loadout, and any negative number to indicate infinite points." + +/decl/config/num/max_gear_cost/sanitize_value() + ..() + if(value < 0) + value = INFINITY + +/decl/config/num/max_acts_per_interval + uid = "max_acts_per_interval" + default_value = 140 + desc = "Defines the number of actions permitted per interval before a user is kicked for spam." + +/decl/config/num/act_interval + uid = "act_interval" + default_value = 0.1 + rounding = 0.01 + desc = "Determines the length of the spam kicking interval in seconds." + +/decl/config/num/dex_malus_brainloss_threshold + uid = "dex_malus_brainloss_threshold" + default_value = 30 + desc = "Threshold of where brain damage begins to affect dexterity (70 brainloss above this means zero dexterity). Default is 30." + +/decl/config/num/default_darksight_range + uid = "default_darksight_range" + default_value = 2 + desc = "The range of default darksight if above is uncommented." + +/decl/config/num/default_darksight_effectiveness + uid = "default_darksight_effectiveness" + default_value = 0.05 + rounding = 0.01 + desc = "The effectiveness of default darksight if above is uncommented." + +/decl/config/num/expected_round_length + uid = "expected_round_length" + default_value = 3 + desc = "Expected round length in hours." + +/decl/config/toggle/grant_default_darksight + uid = "grant_default_darksight" + desc = "Whether or not all human mobs have very basic darksight by default." + +/decl/config/toggle/on/allow_diagonal_movement + uid = "allow_diagonal_movement" + desc = "Allow multiple input keys to be pressed for diagonal movement." + +/decl/config/toggle/expanded_alt_interactions + uid = "expanded_alt_interactions" + desc = "Determines if objects should provide expanded alt interactions when alt-clicked, such as use or grab." + +/decl/config/toggle/ghosts_can_possess_animals + uid = "ghosts_can_possess_animals" + desc = "Determines of ghosts are allowed to possess any animal." + +/decl/config/toggle/assistant_maint + uid = "assistant_maint" + desc = "Remove the # to give assistants maint access." + +/decl/config/toggle/ghost_interaction + uid = "ghost_interaction" + desc = "Remove the # to let ghosts spin chairs." + +/decl/config/toggle/aliens_allowed + uid = "aliens_allowed" + desc = "Remove the # to let aliens spawn." + +/decl/config/toggle/allow_character_comments + uid = "allow_character_comments" + desc = "Remove the # to allow people to leave public comments on each other's characters via the comments system." + +/decl/config/num/hide_comments_older_than + uid = "hide_comments_older_than" + desc = "Specify a number of days after which to hide comments on public profiles (to avoid bloat from retired characters)." + +/decl/config/toggle/stack_crafting_uses_tools + uid = "stack_crafting_uses_tools" + desc = "Enables or disables checking for specific tool types by some stack crafting recipes." + +/decl/config/toggle/on/stack_crafting_uses_types + uid = "stack_crafting_uses_types" + desc = "Enables or disables checking for specific stack types by some stack crafting recipes." diff --git a/code/datums/config/config_types/config_game_world.dm b/code/datums/config/config_types/config_game_world.dm new file mode 100644 index 000000000000..c3328c8c2b30 --- /dev/null +++ b/code/datums/config/config_types/config_game_world.dm @@ -0,0 +1,153 @@ +/decl/configuration_category/game_world + name = "Game World" + desc = "Configuration options relating to the game world and simulation." + associated_configuration = list( + /decl/config/num/exterior_ambient_light, + /decl/config/num/radiation_decay_rate, + /decl/config/num/radiation_resistance_multiplier, + /decl/config/num/radiation_material_resistance_divisor, + /decl/config/num/radiation_lower_limit, + /decl/config/num/exoplanet_min_day_duration, + /decl/config/num/exoplanet_max_day_duration, + /decl/config/toggle/use_iterative_explosions, + /decl/config/num/iterative_explosives_z_threshold, + /decl/config/num/iterative_explosives_z_multiplier, + /decl/config/num/maximum_mushrooms, + /decl/config/num/gateway_delay, + /decl/config/text/law_zero, + /decl/config/toggle/on/welder_vision, + /decl/config/toggle/on/allow_ic_printing, + /decl/config/toggle/on/cult_ghostwriter, + /decl/config/toggle/allow_holidays, + /decl/config/toggle/humans_need_surnames, + /decl/config/toggle/roundstart_level_generation, + /decl/config/toggle/lights_start_on, + /decl/config/toggle/on/cisnormativity, + /decl/config/enum/colored_coating_names, + /decl/config/toggle/codex_requires_implant + ) + +/decl/config/num/exterior_ambient_light + uid = "exterior_ambient_light" + default_value = 0 + min_value = 0 + desc = "Percentile strength of exterior ambient light (such as starlight). 0.5 is 50% lit." + +/decl/config/num/radiation_decay_rate + uid = "radiation_decay_rate" + default_value = 1 + desc = "How much radiation levels self-reduce by each tick." + +/decl/config/num/radiation_resistance_multiplier + uid = "radiation_resistance_multiplier" + default_value = 1.25 + desc = "The amount of radiation resistance on a turf is multiplied by this value." + +/decl/config/num/radiation_material_resistance_divisor + uid = "radiation_material_resistance_divisor" + default_value = 2 + desc = "General material radiation resistance is divided by this value." + +/decl/config/num/radiation_lower_limit + uid = "radiation_lower_limit" + default_value = 0.15 + rounding = 0.1 + desc = list( + "Below this point, radiation is ignored.", + "Radiation weakens with distance from the source; stop calculating when the strength falls below this value. Lower values mean radiation reaches smaller (with increasingly trivial damage) at the cost of more CPU usage.", + "Max range = DISTANCE^2 * POWER / RADIATION_LOWER_LIMIT" + ) + +/decl/config/num/exoplanet_min_day_duration + uid = "exoplanet_min_day_duration" + default_value = 10 + desc = "The minimum duration of an exoplanet day, in minutes." + +/decl/config/num/exoplanet_max_day_duration + uid = "exoplanet_max_day_duration" + default_value = 40 + desc = "The maximum duration of an exoplanet day, in minutes." + +/decl/config/toggle/use_iterative_explosions + uid = "use_iterative_explosions" + desc = "Unhash this to use iterative explosions, keep it hashed to use circle explosions." + +/decl/config/num/iterative_explosives_z_threshold + uid = "iterative_explosives_z_threshold" + default_value = 10 + desc = "The power of explosion required for it to cross Z-levels." + +/decl/config/num/iterative_explosives_z_multiplier + uid = "iterative_explosives_z_multiplier" + default_value = 0.75 + rounding = 0.01 + desc = "What to multiply power by when crossing Z-levels." + +/decl/config/num/maximum_mushrooms + uid = "maximum_mushrooms" + desc = "After this amount alive, walking mushrooms spawned from botany will not reproduce." + default_value = 15 + +/decl/config/num/gateway_delay + uid = "gateway_delay" + default_value = 18000 + desc = "How long the delay is before the Away Mission gate opens. Default is half an hour." + +/decl/config/text/law_zero + uid = "law_zero" + default_value = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010" + desc = "Defines how Law Zero is phrased. Primarily used in the Malfunction gamemode." + +/decl/config/toggle/on/welder_vision + uid = "welder_vision" + desc = "Toggles the restrictive weldervision overlay when wearing welding goggles or a welding helmet." + +/decl/config/toggle/on/allow_ic_printing + uid = "allow_ic_printing" + desc = "Determines if players can print copy/pasted integrated circuits." + +/decl/config/toggle/on/cult_ghostwriter + uid = "cult_ghostwriter" + desc = "Determines if ghosts are permitted to write in blood during cult rounds." + +/decl/config/toggle/allow_holidays + uid = "allow_holidays" + desc = "Determines if special 'Easter-egg' events are active on special holidays such as seasonal holidays and stuff like 'Talk Like a Pirate Day' :3 YAARRR" + +/decl/config/toggle/allow_holidays/update_post_value_set() + . = ..() + update_holiday() + +/decl/config/toggle/humans_need_surnames + uid = "humans_need_surnames" + desc = "Humans are forced to have surnames if this is uncommented." + +/decl/config/toggle/disable_daycycle + uid = "disable_daycycle" + desc = "If true, exoplanets won't have daycycles." + +/decl/config/toggle/roundstart_level_generation + uid = "roundstart_level_generation" + desc = "Enable/Disable random level generation. Will behave strangely if turned off with a map that expects it on." + +/decl/config/toggle/lights_start_on + uid = "lights_start_on" + desc = "If true, most lightswitches start on by default. Otherwise, they start off." + +/decl/config/toggle/on/cisnormativity + uid = "cisnormativity" + desc = "If true, when bodytype is changed in character creation, selected pronouns are also changed." + +/decl/config/enum/colored_coating_names + uid = "colored_coating_names" + desc = "Determines the coloring of various strings representing coatings on objects (blood, oil, mud, etc)." + default_value = CONFIG_COATING_COLOR_MIXTURE + enum_map = list( + "none" = CONFIG_COATING_COLOR_NONE, + "mixture" = CONFIG_COATING_COLOR_MIXTURE, + "components" = CONFIG_COATING_COLOR_COMPONENTS + ) + +/decl/config/toggle/codex_requires_implant + uid = "codex_requires_implant" + desc = "If true, humans require a codex implant to access the codex." \ No newline at end of file diff --git a/code/datums/config/config_types/config_health.dm b/code/datums/config/config_types/config_health.dm new file mode 100644 index 000000000000..1c9855d6fd17 --- /dev/null +++ b/code/datums/config/config_types/config_health.dm @@ -0,0 +1,90 @@ +/decl/configuration_category/health + name = "Health" + desc = "Configuration options relating to the health simulation." + associated_configuration = list( + /decl/config/num/health_stress_shock_recovery_constant, + /decl/config/num/health_stress_healing_recovery_constant, + /decl/config/num/health_stress_blood_recovery_constant, + /decl/config/num/health_health_threshold_dead, + /decl/config/num/health_organ_health_multiplier, + /decl/config/num/health_organ_regeneration_multiplier, + /decl/config/num/health_organ_damage_spillover_multiplier, + /decl/config/num/health_revival_brain_life, + /decl/config/toggle/on/health_bones_can_break, + /decl/config/toggle/on/health_limbs_can_break + ) + +/decl/config/toggle/health_adjust_healing_from_stress + uid = "adjust_healing_from_stress" + config_flags = CONFIG_FLAG_BOOL + desc = "Determines if allow stressors should impact shock, healing and blood recovery." + +/decl/config/toggle/health_show_human_death_message + uid = "show_human_death_message" + config_flags = CONFIG_FLAG_BOOL + desc = "Determines if humans should show a visible message upon death ('X seizes up then falls limp, eyes dead and lifeless')." + +/decl/config/toggle/health_organs_decay + uid = "organs_decay" + config_flags = CONFIG_FLAG_BOOL + desc = "Determines if organs should decay outside of a body or storage item." + +/decl/config/toggle/on/health_bones_can_break + uid = "bones_can_break" + desc = list( + "Determines whether bones can be broken through excessive damage to the organ.", + "0 means bones can't break, 1 means they can." + ) + +/decl/config/toggle/on/health_limbs_can_break + uid = "limbs_can_break" + desc = list( + "Determines whether limbs can be amputated through excessive damage to the organ.", + "0 means limbs can't be amputated, 1 means they can." + ) + + +/decl/config/num/health_stress_shock_recovery_constant + uid = "stress_shock_recovery_constant" + default_value = 0.5 + rounding = 0.01 + desc = "A multiplier for the impact stress has on shock recovery - 0.3 means maximum stress imposes a 30% penalty on shock recovery." + +/decl/config/num/health_stress_healing_recovery_constant + uid = "stress_healing_recovery_constant" + default_value = 0.3 + rounding = 0.01 + desc = "A multiplier for the impact stress has on wound passive healing, as above." + +/decl/config/num/health_stress_blood_recovery_constant + uid = "stress_blood_recovery_constant" + default_value = 0.3 + rounding = 0.01 + desc = "A multiplier for the impact stress has on blood regeneration, as above." + +/decl/config/num/health_health_threshold_dead + uid = "health_threshold_dead" + default_value = -100 + desc = "Level of health at which a mob becomes dead." + +/decl/config/num/health_organ_health_multiplier + uid = "organ_health_multiplier" + default_value = 0.9 + rounding = 0.01 + desc = "Percentage multiplier which enables organs to take more damage before bones breaking or limbs being destroyed." + +/decl/config/num/health_organ_regeneration_multiplier + uid = "organ_regeneration_multiplier" + default_value = 0.25 + desc = "Percentage multiplier which influences how fast organs regenerate naturally." + +/decl/config/num/health_organ_damage_spillover_multiplier + uid = "organ_damage_spillover_multiplier" + desc = "Percentage multiplier that influences how damage spreads around organs. 100 means normal, 50 means half." + default_value = 0.5 + rounding = 0.01 + +/decl/config/num/health_revival_brain_life + uid = "revival_brain_life" + default_value = -1 + desc = "Amount of time (in hundredths of seconds) for which a brain retains the 'spark of life' after the person's death (set to -1 for infinite)." diff --git a/code/datums/config/config_types/config_logging.dm b/code/datums/config/config_types/config_logging.dm new file mode 100644 index 000000000000..5180f52008f7 --- /dev/null +++ b/code/datums/config/config_types/config_logging.dm @@ -0,0 +1,80 @@ +/decl/configuration_category/logging + name = "Logging" + desc = "Configuration options relating to logging." + associated_configuration = list( + /decl/config/toggle/log_ooc, + /decl/config/toggle/log_access, + /decl/config/toggle/log_say, + /decl/config/toggle/log_admin, + /decl/config/toggle/log_debug, + /decl/config/toggle/log_game, + /decl/config/toggle/log_vote, + /decl/config/toggle/log_whisper, + /decl/config/toggle/log_emotes, + /decl/config/toggle/log_attack, + /decl/config/toggle/log_adminchat, + /decl/config/toggle/log_adminwarn, + /decl/config/toggle/log_hrefs, + /decl/config/toggle/log_runtime, + /decl/config/toggle/log_world_output + ) + +/decl/config/toggle/log_ooc + uid = "log_ooc" + desc = "log OOC channel" + +/decl/config/toggle/log_access + uid = "log_access" + desc = "log client access (logon/logoff)" + +/decl/config/toggle/log_say + uid = "log_say" + desc = "log client Say" + +/decl/config/toggle/log_admin + uid = "log_admin" + desc = "log admin actions" + +/decl/config/toggle/log_debug + uid = "log_debug" + desc = "log debug output" + +/decl/config/toggle/log_game + uid = "log_game" + desc = "log game actions (start of round, results, etc.)" + +/decl/config/toggle/log_vote + uid = "log_vote" + desc = "log player votes" + +/decl/config/toggle/log_whisper + uid = "log_whisper" + desc = "log client Whisper" + +/decl/config/toggle/log_emotes + uid = "log_emote" + desc = "log emotes" + +/decl/config/toggle/log_attack + uid = "log_attack" + desc = "log attack messages" + +/decl/config/toggle/log_adminchat + uid = "log_adminchat" + desc = "log admin chat" + +/decl/config/toggle/log_adminwarn + uid = "log_adminwarn" + desc = "Log admin warning messages. Also duplicates a bunch of other messages." + +/decl/config/toggle/log_hrefs + uid = "log_hrefs" + desc = "Log all Topic() calls (for use by coders in tracking down Topic issues)." + +/decl/config/toggle/log_runtime + uid = "log_runtime" + desc = "Log world.log and runtime errors to a file." + +/decl/config/toggle/log_world_output + uid = "log_world_output" + desc = "Log world.log messages." diff --git a/code/datums/config/config_types/config_mode.dm b/code/datums/config/config_types/config_mode.dm new file mode 100644 index 000000000000..6f91654a6887 --- /dev/null +++ b/code/datums/config/config_types/config_mode.dm @@ -0,0 +1,125 @@ +/decl/configuration_category/modes + name = "Modes" + desc = "Configuration options relating to game modes." + associated_configuration = list( + /decl/config/lists/mode_names, + /decl/config/lists/mode_allowed, + /decl/config/lists/mode_votable, + /decl/config/lists/mode_probabilities, + /decl/config/toggle/traitor_scaling, + /decl/config/toggle/protect_roles_from_antagonist, + /decl/config/toggle/continuous_rounds, + /decl/config/toggle/allow_extra_antags + ) + +/decl/config/lists/mode_names + uid = "mode_names" + desc = "Mode names." + default_value = list() + +/decl/config/lists/mode_names/Initialize() + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + var/decl/game_mode/game_mode = all_modes[mode_type] + default_value[game_mode.uid] = game_mode.name + return ..() + +/decl/config/lists/mode_allowed + uid = "modes" + desc = "Allowed modes." + default_value = list() + +/decl/config/lists/mode_allowed/Initialize() + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + var/decl/game_mode/game_mode = all_modes[mode_type] + if(game_mode.available_by_default) + default_value += game_mode.uid + default_value = sortTim(default_value, /proc/cmp_text_asc) + return ..() + +/decl/config/lists/mode_votable + uid = "votable_modes" + desc = "A list of modes that should be votable." + default_value = list() + +/decl/config/lists/mode_votable/Initialize() + default_value = list("secret") + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + var/decl/game_mode/game_mode = all_modes[mode_type] + if(game_mode.votable) + default_value += game_mode.uid + default_value = sortTim(default_value, /proc/cmp_text_asc) + return ..() + +/decl/config/lists/mode_votable/set_value(new_value) + . = ..() + LAZYDISTINCTADD(value, "secret") + value = sortTim(value, /proc/cmp_text_asc) + +/decl/config/lists/mode_probabilities + uid = "probabilities" + desc = "Relative probability of each mode." + default_value = list() + +/decl/config/lists/mode_probabilities/Initialize() + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + var/decl/game_mode/game_mode = all_modes[mode_type] + default_value[game_mode.uid] = initial(game_mode.probability) + return ..() + +/decl/config/lists/mode_probabilities/update_post_value_set() + . = ..() + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + var/decl/game_mode/game_mode = all_modes[mode_type] + game_mode.probability = max(0, value[game_mode.uid]) + +/decl/config/toggle/traitor_scaling + uid = "traitor_scaling" + desc = "If amount of traitors scales or not." + +/decl/config/toggle/protect_roles_from_antagonist + uid = "protect_roles_from_antagonist" + desc = "If security is prohibited from being most antagonists." + +/decl/config/toggle/continuous_rounds + uid = "continuous_rounds" + desc = list( + "Remove the # to make rounds which end instantly continue until the shuttle is called or the station is nuked.", + "Malf and Rev will let the shuttle be called when the antags/protags are dead." + ) + +/decl/config/toggle/antag_hud_allowed + uid = "antag_hud_allowed" + desc = "Allow ghosts to see antagonist through AntagHUD." + +/decl/config/toggle/antag_hud_allowed/update_post_value_set() + . = ..() + if(value) + for(var/mob/observer/ghost/g in get_ghosts()) + if(!g.client.holder) // Add the verb back for all non-admin ghosts + g.verbs += /mob/observer/ghost/verb/toggle_antagHUD + to_chat(g, SPAN_NOTICE("AntagHUD has been enabled!"))// Notify all observers they can now use AntagHUD + else + for(var/mob/observer/ghost/g in get_ghosts()) + if(!g.client.holder) //Remove the verb from non-admin ghosts + g.verbs -= /mob/observer/ghost/verb/toggle_antagHUD + if(g.antagHUD) + g.antagHUD = 0 // Disable it on those that have it enabled + g.has_enabled_antagHUD = 2 // We'll allow them to respawn + to_chat(g, SPAN_DANGER("AntagHUD has been disabled.")) + +/decl/config/toggle/antag_hud_restricted + uid = "antag_hud_restricted" + desc = "If ghosts use antagHUD they are no longer allowed to join the round." + +/decl/config/toggle/secret_hide_possibilities + uid = "secret_hide_possibilities" + desc = "If possible round types will be hidden from players for secret rounds." + +/decl/config/toggle/allow_extra_antags + uid = "allow_extra_antags" + desc = "If uncommented, votes can be called to add extra antags to the round." diff --git a/code/datums/config/config_types/config_protected.dm b/code/datums/config/config_types/config_protected.dm new file mode 100644 index 000000000000..40cfa3bdd0fb --- /dev/null +++ b/code/datums/config/config_types/config_protected.dm @@ -0,0 +1,23 @@ +/decl/configuration_category/protected + name = "Protected" + desc = "Configuration options protected from manipulation on-server." + associated_configuration = list( + /decl/config/text/comms_password, + /decl/config/text/ban_comms_password, + /decl/config/text/login_export_addr + ) + +/decl/config/text/comms_password + uid = "comms_password" + protected = TRUE + desc = "Password used for authorizing ircbot and other external tools." + +/decl/config/text/ban_comms_password + uid = "ban_comms_password" + protected = TRUE + desc = "Password used for authorizing external tools that can apply bans." + +/decl/config/text/login_export_addr + uid = "login_export_addr" + protected = TRUE + desc = "Export address where external tools that monitor logins are located." diff --git a/code/datums/config/config_types/config_resources.dm b/code/datums/config/config_types/config_resources.dm new file mode 100644 index 000000000000..c6e8b6dba757 --- /dev/null +++ b/code/datums/config/config_types/config_resources.dm @@ -0,0 +1,29 @@ +/decl/configuration_category/resources + name = "Resources" + desc = "Configuration options relating to server resources." + associated_configuration = list( + /decl/config/text/custom_item_icon_location, + /decl/config/text/custom_icon_icon_location, + /decl/config/lists/resource_urls + ) + +/decl/config/text/custom_item_icon_location + uid = "custom_item_icon_location" + default_value = "config/custom_items/icons" + desc = "Set this to a file path relative to the executing binary to prefix all custom item icon locations with this location ie. '\[CUSTOM_ITEM_ICON_LOCATION\]/\[custom item icon path value\]'" + +/decl/config/text/custom_icon_icon_location + uid = "custom_icon_icon_location" + default_value = "config/custom_icons/icons" + desc = "Set this to a file path relative to the executing binary to prefix all custom icon locations with this location ie. '\[CUSTOM_ICON_ICON_LOCATION\]/\[custom icon path value\]'" + +/decl/config/lists/resource_urls + uid = "resource_urls" + desc = list( + "Direct clients to preload the server resource file from a URL pointing to a .rsc file. NOTE: At this time (byond 512),", + "the client/resource_rsc var does not function as one would expect. See client_defines.dm, the 'preload_rsc' var's", + "comments on how to use it properly. If you use a resource URL, you must set preload_rsc to 0 at compile time or", + "clients will still download from the server *too*. This will randomly select one URL if more than one is provided.", + "Spaces are prohibited in each URL by spec, you must use encoded spaces.", + "ex. RESOURCE_URLS URL URL2 URL3" + ) diff --git a/code/datums/config/config_types/config_server.dm b/code/datums/config/config_types/config_server.dm new file mode 100644 index 000000000000..4365bbde4bb3 --- /dev/null +++ b/code/datums/config/config_types/config_server.dm @@ -0,0 +1,348 @@ +/decl/configuration_category/server + name = "Server" + desc = "Configuration options relating to the server itself." + associated_configuration = list( + /decl/config/num/kick_inactive, + /decl/config/num/fps, + /decl/config/num/tick_limit_mc_init, + /decl/config/num/minimum_byond_version, + /decl/config/num/minimum_byond_build, + /decl/config/num/player_limit, + /decl/config/num/respawn_delay, + /decl/config/num/cult_ghostwriter_req_cultists, + /decl/config/num/character_slots, + /decl/config/num/loadout_slots, + /decl/config/num/max_maint_drones, + /decl/config/num/drone_build_time, + /decl/config/num/max_character_traits, + /decl/config/num/max_alternate_languages, + /decl/config/text/server_name, + /decl/config/text/server, + /decl/config/text/serverurl, + /decl/config/text/banappeals, + /decl/config/text/wikiurl, + /decl/config/text/forumurl, + /decl/config/text/discordurl, + /decl/config/text/githuburl, + /decl/config/text/issuereporturl, + /decl/config/text/hosted_by, + /decl/config/toggle/panic_bunker, + /decl/config/text/panic_bunker_message, + /decl/config/toggle/do_not_prevent_spam, + /decl/config/toggle/no_throttle_localhost, + /decl/config/toggle/on/abandon_allowed, + /decl/config/toggle/on/ooc_allowed, + /decl/config/toggle/on/looc_allowed, + /decl/config/toggle/on/dooc_allowed, + /decl/config/toggle/on/dsay_allowed, + /decl/config/toggle/on/aooc_allowed, + /decl/config/toggle/on/enter_allowed, + /decl/config/toggle/on/allow_ai, + /decl/config/toggle/on/allow_drone_spawn, + /decl/config/toggle/hub_visibility, + /decl/config/toggle/load_jobs_from_txt, + /decl/config/toggle/disable_player_mice, + /decl/config/toggle/uneducated_mice, + /decl/config/toggle/use_alien_whitelist, + /decl/config/toggle/use_alien_whitelist_sql, + /decl/config/toggle/forbid_singulo_possession, + /decl/config/toggle/use_loyalty_implants, + /decl/config/toggle/no_click_cooldown, + /decl/config/toggle/disable_webhook_embeds, + /decl/config/toggle/delist_when_no_admins, + /decl/config/toggle/wait_for_sigusr1_reboot, + /decl/config/toggle/show_typing_indicator_for_whispers, + /decl/config/toggle/guests_allowed, + /decl/config/toggle/on/jobs_have_minimal_access, + /decl/config/toggle/on/admin_legacy_system, + /decl/config/toggle/on/ban_legacy_system, + /decl/config/enum/server_whitelist + ) + +/decl/config/num/kick_inactive + uid = "kick_inactive" + desc = "Disconnect players who did nothing during the set amount of minutes." + +/decl/config/num/fps + uid = "fps" + default_value = 20 + desc = list( + "Defines world FPS. Defaults to 20.", + "Can also accept ticklag values (0.9, 0.5, etc) which will automatically be converted to FPS." + ) + +/decl/config/num/fps/sanitize_value() + ..() + if(value <= 0) + value = default_value + +/decl/config/num/fps/set_value(new_value) + // Handle ticklag-formatted FPS (0.7 etc) + if(new_value > 0 && new_value < 1) + new_value = round(10 / new_value) + return ..(new_value) + +/decl/config/num/fps/update_post_value_set() + world.fps = value + . = ..() + +/decl/config/num/tick_limit_mc_init + uid = "tick_limit_mc_init" + desc = "SSinitialization throttling." + default_value = TICK_LIMIT_MC_INIT_DEFAULT + +/decl/config/num/minimum_byond_version + uid = "minimum_byond_version" + default_value = 0 + desc = "Clients will be unable to connect unless their version is equal to or higher than this (a number, e.g. 511)." + +/decl/config/num/minimum_byond_build + uid = "minimum_byond_build" + default_value = 0 + desc = "Clients will be unable to connect unless their build is equal to or higher than this (a number, e.g. 1000)." + +/decl/config/num/player_limit + uid = "player_limit" + desc = "The maximum number of non-admin players online." + default_value = 0 + +/decl/config/num/use_age_restriction_for_jobs + uid = "use_age_restriction_for_jobs" + default_value = 0 + desc = list( + "Unhash this entry to have certain jobs require your account to be at least a certain number of days old to select. You can configure the exact age requirement for different jobs by editing", + "the minimal_player_age variable in the files in folder /code/game/jobs/job/.. for the job you want to edit. Set minimal_player_age to 0 to disable age requirement for that job.", + "REQUIRES the database set up to work. Keep it hashed if you don't have a database set up.", + "NOTE: If you have just set-up the database keep this DISABLED, as player age is determined from the first time they connect to the server with the database up. If you just set it up, it means", + "you have noone older than 0 days, since noone has been logged yet. Only turn this on once you have had the database up for 30 days." + ) + +/decl/config/num/use_age_restriction_for_antags + uid = "use_age_restriction_for_antags" + desc = list( + "Unhash this entry to have certain antag roles require your account to be at least a certain number of days old for round start and auto-spawn selection.", + "Non-automatic antagonist recruitment, such as being converted to cultism is not affected. Has the same database requirements and notes as USE_AGE_RESTRICTION_FOR_JOBS." + ) + +/decl/config/num/respawn_delay + uid = "respawn_delay" + default_value = 30 + min_value = 0 + desc = "Respawn delay in minutes before one may respawn as a crew member." + +/decl/config/num/cult_ghostwriter_req_cultists + uid = "cult_ghostwriter_req_cultists" + default_value = 10 + desc = "Sets the minimum number of cultists needed for ghosts to write in blood." + +/decl/config/num/character_slots + uid = "character_slots" + default_value = 10 + desc = "Sets the number of available character slots." + +/decl/config/num/loadout_slots + uid = "loadout_slots" + default_value = 3 + desc = "Sets the number of loadout slots per character." + +/decl/config/num/max_maint_drones + uid = "max_maint_drones" + desc = "This many drones can be active at the same time." + default_value = 5 + +/decl/config/num/drone_build_time + uid = "drone_build_time" + desc = "A drone will become available every X ticks since last drone spawn. Default is 2 minutes." + default_value = 1200 + +/decl/config/num/max_character_traits + uid = "max_character_traits" + default_value = 5 + desc = "Remove the # to define a different cap for trait points in chargen." + +/decl/config/num/max_alternate_languages + uid = "max_alternate_languages" + default_value = 3 + desc = "Remove the # to define a different maximum for alternate language selection in chargen." + +// server name (for world name / status) +/decl/config/text/server_name + uid = "server_name" + desc = "Server name: This appears at the top of the screen in-game." + default_value = "Nebula 13" + +/decl/config/text/server + uid = "server" + desc = "Set a server location for world reboot. Don't include the byond://, just give the address and port." + +/decl/config/text/serverurl + uid = "serverurl" + desc = list( + "Set a server URL for the IRC bot to use; like SERVER, don't include the byond://", + "Unlike SERVER, this one shouldn't break auto-reconnect." + ) + +/decl/config/text/banappeals + uid = "banappeals" + desc = "Ban appeals URL - usually for a forum or wherever people should go to contact your admins." + +/decl/config/text/wikiurl + uid = "wikiurl" + desc = "Wiki address." + +/decl/config/text/forumurl + uid = "forumurl" + desc = "Discussion forum address." + +/decl/config/text/discordurl + uid = "discordurl" + desc = "Discord server permanent invite address." + +/decl/config/text/githuburl + uid = "githuburl" + desc = "GitHub address." + +/decl/config/text/issuereporturl + uid = "issuereporturl" + desc = "GitHub new issue address." + +/decl/config/text/hosted_by + uid = "hostedby" + desc = "Set a hosted by name for UNIX platforms." + +/decl/config/toggle/panic_bunker + uid = "panic_bunker" + desc = "Is the panic bunker currently on by default?" + +/decl/config/text/panic_bunker_message + uid = "panic_bunker_message" + default_value = "Sorry! The panic bunker is enabled. Please head to our Discord or forum to get yourself added to the panic bunker bypass." + desc = "A message when user did not pass the panic bunker." + +/decl/config/toggle/do_not_prevent_spam + uid = "do_not_prevent_spam" + desc = "Determines if action spam kicking should be DISABLED. Not recommended; this helps protect from spam attacks." + +/decl/config/toggle/no_throttle_localhost + uid = "no_throttle_localhost" + desc = list( + "Whether or not to make localhost immune to throttling.", + "Localhost will still be throttled internally; it just won't be affected by it." + ) + +/decl/config/toggle/on/abandon_allowed + uid = "abandon_allowed" + desc = "Comment to disable respawning by default." + +/decl/config/toggle/on/ooc_allowed + uid = "ooc_allowed" + desc = "Comment to disable the OOC channel by default." + +/decl/config/toggle/on/looc_allowed + uid = "looc_allowed" + desc = "Comment to disable the LOOC channel by default." + +/decl/config/toggle/on/dooc_allowed + uid = "dooc_allowed" + desc = "Comment to disable the dead OOC channel by default." + +/decl/config/toggle/on/dsay_allowed + uid = "dsay_allowed" + desc = "Comment to disable ghost chat by default." + +/decl/config/toggle/on/aooc_allowed + uid = "aooc_allowed" + desc = "Comment to disable the AOOC channel by default." + +/decl/config/toggle/on/enter_allowed + uid = "enter_allowed" + desc = "Comment to prevent anyone from joining the round by default." + +/decl/config/toggle/on/allow_ai + uid = "allow_ai" + desc = "Allow AI job." + +/decl/config/toggle/on/allow_drone_spawn + uid = "allow_drone_spawn" + desc = "Allow ghosts to join as maintenance drones." + +/decl/config/toggle/hub_visibility + uid = "hub_visibility" + desc = "Hub visibility: If you want to be visible on the hub, uncomment the below line and be sure that Dream Daemon is set to visible. This can be changed in-round as well with toggle-hub-visibility if Dream Daemon is set correctly." + +/decl/config/toggle/hub_visibility/update_post_value_set() + . = ..() + world.update_hub_visibility() + +/decl/config/toggle/load_jobs_from_txt + uid = "load_jobs_from_txt" + desc = "Toggle for having jobs load up from the .txt" + +/decl/config/toggle/disable_player_mice + uid = "disable_player_mice" + +/decl/config/toggle/uneducated_mice + uid = "uneducated_mice" + desc = "Set to 1 to prevent newly-spawned mice from understanding human speech." + +/decl/config/toggle/use_alien_whitelist + uid = "usealienwhitelist" + desc = "Determines if non-admins are restricted from using humanoid alien races." + +/decl/config/toggle/use_alien_whitelist_sql + uid = "usealienwhitelist_sql" + desc = "Determines if the alien whitelist should use SQL instead of the legacy system. (requires the above uncommented as well)." + +/decl/config/toggle/forbid_singulo_possession + uid = "forbid_singulo_possession" + desc = "Remove the # mark infront of this to forbid admins from posssessing the singularity." + +/decl/config/toggle/use_loyalty_implants + uid = "use_loyalty_implants" + desc = "Remove the # in front of this config option to have loyalty implants spawn by default on your server." + +/decl/config/toggle/no_click_cooldown + uid = "no_click_cooldown" + +/decl/config/toggle/disable_webhook_embeds + uid = "disable_webhook_embeds" + desc = "Determines if Discord webhooks should be sent in plaintext rather than as embeds." + +/decl/config/toggle/delist_when_no_admins + uid = "delist_when_no_admins" + desc = "Determines if the server should hide itself from the hub when no admins are online." + +/decl/config/toggle/wait_for_sigusr1_reboot + uid = "wait_for_sigusr1_reboot" + desc = "Determines if Dream Daemon should refuse to reboot for any reason other than SIGUSR1." + +/decl/config/toggle/show_typing_indicator_for_whispers + uid = "show_typing_indicator_for_whispers" + desc = "Determinese if a typing indicator shows overhead for people currently writing whispers." + +/decl/config/toggle/guests_allowed + uid = "guests_allowed" + desc = "Determines whether or not people without a registered ckey (i.e. guest-*) can connect to your server." + +/decl/config/toggle/on/ban_legacy_system + uid = "ban_legacy_system" + desc = "Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system." + +/decl/config/toggle/on/admin_legacy_system + uid = "admin_legacy_system" + desc = "Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system." + +/decl/config/toggle/on/jobs_have_minimal_access + uid = "jobs_have_minimal_access" + desc = "Add a # here if you wish to use the setup where jobs have more access. This is intended for servers with low populations - where there are not enough players to fill all roles, so players need to do more than just one job. Also for servers where they don't want people to hide in their own departments." + +/decl/config/enum/server_whitelist + uid = "server_whitelist" + desc = "Determines how the server should handle whitelisting for ckeys. Whitelisted ckeys are found in '" + CONFIG_SERVER_WHITELIST_FILE + "'. Set to 'none' for no whitelisting, 'jobs' to whitelist sensitive jobs, 'join' to whitelist joining the round (observing and OOC are still available, or 'connect' to whitelist access to the server." + default_value = CONFIG_SERVER_NO_WHITELIST + enum_map = list( + "none" = CONFIG_SERVER_NO_WHITELIST, + "jobs" = CONFIG_SERVER_JOBS_WHITELIST, + "join" = CONFIG_SERVER_JOIN_WHITELIST, + "connect" = CONFIG_SERVER_CONNECT_WHITELIST + ) diff --git a/code/datums/config/config_types/config_voting.dm b/code/datums/config/config_types/config_voting.dm new file mode 100644 index 000000000000..de914b8f8fa2 --- /dev/null +++ b/code/datums/config/config_types/config_voting.dm @@ -0,0 +1,79 @@ +/decl/configuration_category/voting + name = "Voting" + desc = "Configuration options relating to votes at runtime." + associated_configuration = list( + /decl/config/num/vote_delay, + /decl/config/num/vote_period, + /decl/config/num/vote_autotransfer_initial, + /decl/config/num/vote_autotransfer_interval, + /decl/config/num/vote_autogamemode_timeleft, + /decl/config/num/vote_no_default, + /decl/config/num/vote_no_dead, + /decl/config/num/vote_no_dead_crew_transfer, + /decl/config/toggle/vote_restart, + /decl/config/toggle/vote_mode, + /decl/config/toggle/allow_map_switching, + /decl/config/toggle/auto_map_vote + ) + +/decl/config/num/vote_delay + uid = "vote_delay" + default_value = 6000 + desc = "Min delay (deciseconds) between voting sessions (default 10 minutes)." + +/decl/config/num/vote_period + uid = "vote_period" + default_value = 600 + desc = "Time period (deciseconds) which voting session will last (default 1 minute)." + +/decl/config/num/vote_autotransfer_initial + uid = "vote_autotransfer_initial" + default_value = 108000 + desc = "Autovote initial delay (deciseconds) before first automatic transfer vote call (default 180 minutes)." + +/decl/config/num/vote_autotransfer_interval + uid = "vote_autotransfer_interval" + default_value = 18000 + desc = "Autovote delay (deciseconds) before sequential automatic transfer votes are called (default 30 minutes)." + +/decl/config/num/vote_autogamemode_timeleft + uid = "vote_autogamemode_timeleft" + default_value = 100 + desc = "Time left (seconds) before round start when automatic gamemote vote is called (default 160)." + +/decl/config/num/vote_no_default + uid = "vote_no_default" + default_value = FALSE + config_flags = CONFIG_FLAG_BOOL | CONFIG_FLAG_HAS_VALUE + desc = "Players' votes default to 'No vote' (otherwise, default to 'No change')." + +/decl/config/num/vote_no_dead + uid = "vote_no_dead" + default_value = FALSE + config_flags = CONFIG_FLAG_BOOL | CONFIG_FLAG_HAS_VALUE + desc = "Prevents dead players from voting or starting votes." + +/decl/config/num/vote_no_dead_crew_transfer + uid = "vote_no_dead_crew_transfer" + default_value = FALSE + config_flags = CONFIG_FLAG_BOOL | CONFIG_FLAG_HAS_VALUE + desc = "Prevents players not in-round from voting on crew transfer votes." + +/decl/config/toggle/vote_restart + uid = "allow_vote_restart" + desc = "Allow players to initiate a restart vote." + +/decl/config/toggle/vote_mode + uid = "allow_vote_mode" + desc = "Allow players to initate a mode-change start." + +/decl/config/toggle/allow_map_switching + uid = "allow_map_switching" + desc = list( + "Uncomment to enable map voting; you'll need to use the script at tools/server.sh or an equivalent for it to take effect.", + "You'll also likely need to enable WAIT_FOR_SIGUSR1 below." + ) + +/decl/config/toggle/auto_map_vote + uid = "auto_map_vote" + desc = "Determines if the automatic map vote and switch are called at end of round. MAP_SWITCHING must also be enabled." diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 1033ff29154b..30e00f5a6573 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -1,51 +1,119 @@ /datum - var/tmp/gc_destroyed //Time when this object was destroyed. + /// Used to indicate that this type is abstract and should not itself be instantiated. + var/abstract_type = /datum + /// Time when this object was destroyed. + var/tmp/gc_destroyed + /// Indicates if a processing subsystem is currenting queuing this datum var/tmp/is_processing = FALSE - var/list/active_timers //for SStimer + /// Used by the SStimer subsystem + var/list/active_timers + /// Used to avoid unnecessary refstring creation in Destroy(). + var/tmp/has_state_machine = FALSE + /// Var for holding a unique-to-this-run identifier for a serialized datum. + VAR_PRIVATE/tmp/__run_uid -#ifdef TESTING +#ifdef REFTRACKING_ENABLED var/tmp/running_find_references + /// When was this datum last touched by a reftracker? + /// If this value doesn't match with the start of the search + /// We know this datum has never been seen before, and we should check it var/tmp/last_find_references = 0 + /// How many references we're trying to find when searching + var/tmp/references_to_clear = 0 #endif -// The following vars cannot be edited by anyone -/datum/VV_static() - return UNLINT(..()) + list("gc_destroyed", "is_processing") - // Default implementation of clean-up code. // This should be overridden to remove all references pointing to the object being destroyed. // Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE. /datum/proc/Destroy(force=FALSE) + SHOULD_NOT_SLEEP(TRUE) SHOULD_CALL_PARENT(TRUE) tag = null weakref = null // Clear this reference to ensure it's kept for as brief duration as possible. - SSnano && SSnano.close_uis(src) + if(length(open_uis)) // inline the open ui check to avoid unnecessary proc call overhead + SSnano.close_uis(src) - var/list/timers = active_timers - active_timers = null - for(var/thing in timers) - var/datum/timedevent/timer = thing - if (timer.spent) - continue - qdel(timer) + if(active_timers) + var/list/timers = active_timers + active_timers = null + for(var/thing in timers) + var/datum/timedevent/timer = thing + if (timer.spent && !(timer.flags & TIMER_LOOP)) + continue + qdel(timer) if(extensions) - for(var/expansion_key in extensions) - var/list/extension = extensions[expansion_key] + var/list/extension_list + for(var/expansion_key, extension in extensions) if(islist(extension)) - extension.Cut() + extension_list = extension + extension_list.Cut() else qdel(extension) extensions = null - GLOB.destroyed_event && GLOB.destroyed_event.raise_event(src) + if(event_listeners?[/decl/observ/destroyed]) + raise_event_non_global(/decl/observ/destroyed) if (!isturf(src)) // Not great, but the 'correct' way to do it would add overhead for little benefit. cleanup_events(src) + if(has_state_machine) + var/list/machines = global.state_machines[src] + if(length(machines)) + for(var/base_type in machines) + qdel(machines[base_type]) + global.state_machines -= src + return QDEL_HINT_QUEUE /datum/proc/Process() SHOULD_NOT_SLEEP(TRUE) return PROCESS_KILL + +// This is more or less a helper to avoid needing to cast extension holders to atom. +// Previously called get() and get_holder_of_type(). +// See /atom/get_recursive_loc_of_type() for actual logic. +/datum/proc/get_recursive_loc_of_type(var/loc_type) + SHOULD_CALL_PARENT(FALSE) + CRASH("get_recursive_loc_of_type() called on datum type [type] - this proc should only be called on /atom.") + +/** + * Returns whether the object supports being cloned. + * This is useful for things that should only ever exist once in the world. + */ +/datum/proc/CanClone() + return TRUE + +/** + * This proc returns a clone of the src datum. + * Clone here implies a copy similar in terms of look and contents, but internally may differ a bit. + * The clone shall not keep references onto instances owned by the original, in most cases. + * Try to avoid overriding this proc directly and instead override GetCloneArgs() and PopulateClone(). + */ +/datum/proc/Clone() + SHOULD_CALL_PARENT(TRUE) + if(!CanClone()) + CRASH("Called clone on ``[type]`` which does not support cloning!") + var/list/newargs = GetCloneArgs() + if(newargs) + . = new type(arglist(newargs)) + else + . = new type + return PopulateClone(.) + +/** + * Returns a list with the arguments passed to the new() of a cloned instance. + * Override this, instead of Clone() itself. + */ +/datum/proc/GetCloneArgs() + return + +/** + * Used to allow sub-classes to do further processing on the cloned instance returned by Clone(). + * Override this, instead of Clone() itself. + * ** Please avoid running update code in here if possible. You could always override Clone() for this kind of things, so we don't end up with 50 calls to update_icon in the chain. ** + */ +/datum/proc/PopulateClone(var/datum/clone) + return clone diff --git a/code/datums/datum_serde.dm b/code/datums/datum_serde.dm new file mode 100644 index 000000000000..cafee1161d64 --- /dev/null +++ b/code/datums/datum_serde.dm @@ -0,0 +1,36 @@ +// Used for saving instances via the level persistence system. +// Returns an assoc list of var name to var value. +// Expected format is: +// list("field" = "value", "so on" = "so forth")) +// Using a var name (via nameof() or manually) will automatically load the var to the field in Deserialize. +// If serializing an instance reference, use get_run_uid() to get a UID. +/datum/proc/Serialize() + SHOULD_CALL_PARENT(TRUE) + . = list((nameof(/datum::type)) = GetSerializedType()) + +/datum/proc/GetSerializedType() + return type + +/datum/proc/GetPossiblySerializableInstances() + return list(src) + +// A proc for checking preconditions on an instance to determine if it should bother serializing at all. +/datum/proc/ShouldSerialize(_age) + SHOULD_CALL_PARENT(TRUE) + return TRUE + +// Returns a UID for this instance, used for serde across rounds. +// Probably-kind-of a GUID but only for this run. +/datum/proc/get_run_uid() + if(isnull(__run_uid)) + __run_uid = "\ref[src]-[sequential_id(type)]" // Staple seq_id on there in case of \ref reuse. + return __run_uid + +// Called after Initialize()/LateInitialize() on all non-atom datums, and if an atom returns SERDE_HINT_POSTINIT to Deserialize(). +/datum/proc/DeserializePostInit(list/instance_map) + return + +// Apply cross-round degradation (graffiti decaying, etc) prior to Deserialize() and Initialize() +// Typically this means modifying __deserialization_payload +/datum/proc/HandlePersistentDecay(entries_decay_at, entry_decay_weight) + return diff --git a/code/datums/daycycle/daycycle.dm b/code/datums/daycycle/daycycle.dm new file mode 100644 index 000000000000..00f43b21f957 --- /dev/null +++ b/code/datums/daycycle/daycycle.dm @@ -0,0 +1,84 @@ +/datum/daycycle + abstract_type = /datum/daycycle + var/list/suns = list( + new /datum/sun + ) + /// Unique string ID used to register a level with a daycycle. + var/daycycle_id + /// How long is a full day and night cycle? + var/cycle_duration = 1 HOUR + /// How far are we into the current cycle? + var/time_in_cycle = 0 + /// What world.time did we last update? Used to calculate time progression between ticks. + var/last_update = 0 + /// What z-levels are affected by this daycycle? Used for mass updating ambience. + var/list/levels_affected = list() + /// What period of day are we sitting in as of our last update? + var/datum/daycycle_period/current_period + /// Mappings of colour and power to % progression points throughout the cycle. + /// Each entry must be arranged in order of earliest to latest. + /// Null values on periods use the general level ambience instead. + var/list/cycle_periods = list( + new /datum/daycycle_period/sunrise, + new /datum/daycycle_period/daytime, + new /datum/daycycle_period/sunset, + new /datum/daycycle_period/night + ) + +/datum/daycycle/New(_cycle_id) + daycycle_id = _cycle_id + last_update = world.time + current_period = cycle_periods[1] + transition_daylight() // pre-populate our values. + +/datum/daycycle/proc/add_level(level_z) + levels_affected |= level_z + var/datum/level_data/level = SSmapping.levels_by_z[level_z] + if(level) + level.update_turf_ambience() + +/datum/daycycle/proc/remove_level(level_z) + levels_affected -= level_z + var/datum/level_data/level = SSmapping.levels_by_z[level_z] + if(level) + level.update_turf_ambience() + +/datum/daycycle/proc/transition_daylight() + + time_in_cycle = (time_in_cycle + (world.time - last_update)) % cycle_duration + last_update = world.time + + var/datum/daycycle_period/last_period = current_period + var/progression_percentage = time_in_cycle / cycle_duration + for(var/datum/daycycle_period/period in cycle_periods) + if(progression_percentage <= period.period) + current_period = period + break + + . = (current_period.color != last_period.color || current_period.power != last_period.power) + if(current_period != last_period && current_period.announcement) + for(var/mob/player in global.player_list) + var/turf/T = get_turf(player) + if(T && (T.z in levels_affected) && T.is_outside()) + to_chat(player, SPAN_NOTICE(FONT_SMALL(current_period.announcement))) + +/datum/daycycle/proc/tick() + + for(var/datum/sun/sun in suns) + sun.calc_position() + + if(transition_daylight()) + for(var/level_z in levels_affected) + var/datum/level_data/level = SSmapping.levels_by_z[level_z] + if(level) + level.update_turf_ambience() + +/datum/daycycle/exoplanet/New() + cycle_duration = rand(get_config_value(/decl/config/num/exoplanet_min_day_duration), get_config_value(/decl/config/num/exoplanet_max_day_duration)) MINUTES + ..() + +// Dummy daycycle used solely so the sun datum has a chance to tick. +/datum/daycycle/solars + cycle_periods = list( + new /datum/daycycle_period/permanent_daytime + ) diff --git a/code/datums/daycycle/time_of_day.dm b/code/datums/daycycle/time_of_day.dm new file mode 100644 index 000000000000..fbe3f6330d7b --- /dev/null +++ b/code/datums/daycycle/time_of_day.dm @@ -0,0 +1,50 @@ +/datum/daycycle_period + abstract_type = /datum/daycycle_period + /// In-character descriptor (ie. 'sunrise') + var/name + /// Message shown to outdoors players when the daycycle moves to this period. + var/announcement + /// 0-1 value to indicate where in the total day/night progression this falls. + var/period + /// Ambient light colour during this time of day. + var/color + /// Ambient light power during this time of day. + var/power + /// Ambient temperature modifier during this time of day. + var/temperature + +/datum/daycycle_period/sunrise + name = "sunrise" + announcement = "The sun peeks over the horizon, bathing the world in rosy light." + period = 0.1 + color = COLOR_RED_LIGHT + power = 0.5 + +/datum/daycycle_period/daytime + name = "daytime" + announcement = "The sun rises over the horizon, beginning another day." + period = 0.4 + power = 0.8 + color = COLOR_DAYLIGHT + +/datum/daycycle_period/sunset + name = "sunset" + announcement = "The sun begins to dip below the horizon, and the daylight fades." + period = 0.6 + color = COLOR_ORANGE + power = 0.5 + +/datum/daycycle_period/night + name = "night" + announcement = "Night falls, blanketing the world in darkness." + period = 1 + color = COLOR_CYAN_BLUE + power = 0.3 + +// Dummy period used by solars. +/datum/daycycle_period/permanent_daytime + name = null + announcement = null + color = null + power = null + period = 1 diff --git a/code/datums/extensions/abilities/abilities.dm b/code/datums/extensions/abilities/abilities.dm new file mode 100644 index 000000000000..21e02b0126b5 --- /dev/null +++ b/code/datums/extensions/abilities/abilities.dm @@ -0,0 +1,61 @@ +// Extension that handles intercepting click actions and casts spells/power as appropriate. +/datum/extension/abilities + base_type = /datum/extension/abilities + expected_type = /mob + var/list/ability_handlers + +/datum/extension/abilities/Destroy() + // Can't use QDEL_NULL_LIST() due to circular calls. + for(var/datum/ability_handler/handler in ability_handlers) + handler.master = null + qdel(handler) + ability_handlers = null + return ..() + +/datum/extension/abilities/proc/update() + if(!LAZYLEN(ability_handlers)) + remove_extension(holder, base_type) + +/// Using an empty hand on itelf (attack_empty_hand()) +/datum/extension/abilities/proc/do_self_invocation() + if(isliving(holder) && LAZYLEN(ability_handlers)) + for(var/datum/ability_handler/handler in ability_handlers) + if(handler.can_do_self_invocation(holder) && handler.do_self_invocation(holder)) + return TRUE + return FALSE + +/// Clicking a grab on the currently grabbed mob. +/datum/extension/abilities/proc/do_grabbed_invocation(atom/target) + if(isliving(holder) && istype(target) && LAZYLEN(ability_handlers) && !istype(target, /obj/screen)) + for(var/datum/ability_handler/handler in ability_handlers) + if(handler.can_do_grabbed_invocation(holder, target) && handler.do_grabbed_invocation(holder, target)) + return TRUE + return FALSE + +/// Clicking an adjacent target (UnarmedAttack()) +/datum/extension/abilities/proc/do_melee_invocation(atom/target) + if(isliving(holder) && istype(target) && LAZYLEN(ability_handlers) && !istype(target, /obj/screen)) + for(var/datum/ability_handler/handler in ability_handlers) + if(handler.can_do_melee_invocation(holder, target) && handler.do_melee_invocation(holder, target)) + return TRUE + return FALSE + +/// Clicking a distant target (RangedAttack()) +/datum/extension/abilities/proc/do_ranged_invocation(atom/target) + if(isliving(holder) && istype(target) && LAZYLEN(ability_handlers) && !istype(target, /obj/screen)) + for(var/datum/ability_handler/handler in ability_handlers) + if(handler.can_do_ranged_invocation(holder, target) && handler.do_ranged_invocation(holder, target)) + return TRUE + return FALSE + +/// Updates UI etc. on login +/datum/extension/abilities/proc/refresh_login() + if(LAZYLEN(ability_handlers)) + for(var/datum/ability_handler/handler in ability_handlers) + handler.refresh_login() + +/datum/extension/abilities/proc/refresh_element_positioning() + var/row = 0 + for(var/datum/ability_handler/handler in ability_handlers) + if(length(handler.screen_elements)) + row += handler.refresh_element_positioning(row) diff --git a/code/datums/extensions/abilities/abilities_mob.dm b/code/datums/extensions/abilities/abilities_mob.dm new file mode 100644 index 000000000000..4879b2d05c46 --- /dev/null +++ b/code/datums/extensions/abilities/abilities_mob.dm @@ -0,0 +1,103 @@ +/mob/proc/get_ability_handler(handler_type, create_if_missing) + var/datum/extension/abilities/abilities + if(create_if_missing) + abilities = get_or_create_extension(src, /datum/extension/abilities) + else if(has_extension(src, /datum/extension/abilities)) + abilities = get_extension(src, /datum/extension/abilities) + if(!abilities) + return null + var/datum/ability_handler/handler = locate(handler_type) in abilities.ability_handlers + if(!handler && create_if_missing) + handler = add_ability_handler(handler_type) + return handler + +/mob/proc/add_ability_handler(handler_type) + var/datum/extension/abilities/abilities = get_or_create_extension(src, /datum/extension/abilities) + var/datum/ability_handler/handler = locate(handler_type) in abilities.ability_handlers + if(handler) + return FALSE + handler = new handler_type(abilities, src) + LAZYADD(abilities.ability_handlers, handler) + handler.finalize_ability_handler() + return handler + +/mob/proc/remove_ability_handler(handler_type) + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + if(!abilities) + return FALSE + var/datum/ability_handler/handler = locate(handler_type) in abilities.ability_handlers + if(!handler) + return FALSE + LAZYREMOVE(abilities.ability_handlers, handler) + qdel(handler) + if(!LAZYLEN(abilities.ability_handlers)) + remove_extension(src, /datum/extension/abilities) + return TRUE + +/mob/living/proc/copy_abilities_from(mob/living/donor) + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + if(!abilities) + return FALSE + . = FALSE + for(var/datum/ability_handler/handler in abilities.ability_handlers) + if(handler.copy_abilities_to(src)) + . = TRUE + +/mob/living/proc/disable_abilities(var/amount = 0) + if(amount < 0) + return + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + for(var/datum/ability_handler/handler in abilities?.ability_handlers) + handler.disable_abilities(amount) + +/mob/living/proc/copy_abilities_to(mob/living/target) + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + for(var/datum/ability_handler/handler in abilities?.ability_handlers) + handler.copy_abilities_to(target) + +/mob/proc/add_ability(ability_type, list/metadata) + var/decl/ability/ability = GET_DECL(ability_type) + if(!istype(ability) || !ability.associated_handler_type) + return FALSE + var/datum/ability_handler/handler = get_ability_handler(ability.associated_handler_type, create_if_missing = TRUE) + return handler.add_ability(ability_type, metadata) + +/mob/proc/remove_ability(ability_type) + var/decl/ability/ability = GET_DECL(ability_type) + if(!istype(ability) || !ability.associated_handler_type) + return FALSE + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + var/datum/ability_handler/handler = locate(ability.associated_handler_type) in abilities?.ability_handlers + return handler?.remove_ability(ability_type) + +/mob/proc/get_ability_metadata(ability_type) + var/decl/ability/ability = GET_DECL(ability_type) + if(!istype(ability) || !ability.associated_handler_type) + return null + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + var/datum/ability_handler/handler = locate(ability.associated_handler_type) in abilities?.ability_handlers + return handler?.get_metadata(ability_type, create_if_missing = TRUE) + +/mob/proc/has_ability(ability_type) + var/decl/ability/ability = GET_DECL(ability_type) + if(!istype(ability) || !ability.associated_handler_type) + return null + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + var/datum/ability_handler/handler = locate(ability.associated_handler_type) in abilities?.ability_handlers + return handler?.provides_ability(ability_type) + +/mob/Stat() + if((. = ..()) && client) + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + for(var/datum/ability_handler/handler in abilities?.ability_handlers) + handler.show_stat_string(src) + +/mob/proc/get_all_abilities() + var/datum/extension/abilities/abilities_extension = get_extension(src, /datum/extension/abilities) + if(!istype(abilities_extension)) + return + for(var/datum/ability_handler/handler as anything in abilities_extension.ability_handlers) + for(var/ability_type in handler.known_abilities) + var/decl/ability/ability = GET_DECL(ability_type) + if(istype(ability)) + LAZYDISTINCTADD(., ability) diff --git a/code/datums/extensions/abilities/abilities_predator.dm b/code/datums/extensions/abilities/abilities_predator.dm new file mode 100644 index 000000000000..379316b3de80 --- /dev/null +++ b/code/datums/extensions/abilities/abilities_predator.dm @@ -0,0 +1,99 @@ +/datum/ability_handler/predator + category_toggle_type = null + var/max_dismember_size = MOB_SIZE_SMALL + +/datum/ability_handler/predator/can_do_melee_invocation(mob/user, atom/target) + return ..() || (istype(user) && !user.incapacitated() && isatom(target) && target.Adjacent(user)) + +/datum/ability_handler/predator/do_melee_invocation(mob/user, atom/target) + + . = ..() + if(.) + return + + // Nibbles! + if(user.check_intent(I_FLAG_HARM)) + if(isliving(target)) + return handle_dismemberment(user, target) + if(istype(target, /obj/item/organ)) + return handle_organ_destruction(user, target) + + // Digging! + var/static/list/diggable_types = list( + /turf/floor, + /turf/wall, + /obj/structure/pit, + /obj/machinery/portable_atmospherics/hydroponics/soil + ) + if(is_type_in_list(target, diggable_types)) + var/obj/item/organ/external/paw = user.get_usable_hand_slot_organ() + if(paw) + return target.attackby(paw, user) + + return FALSE + +/datum/ability_handler/predator/proc/handle_organ_destruction(mob/user, obj/item/organ/chewtoy) + if(!chewtoy.is_internal()) + user.visible_message(SPAN_DANGER("\The [user] tears apart \the [chewtoy].")) + chewtoy.physically_destroyed() + else if(BP_IS_PROSTHETIC(chewtoy)) + to_chat(user, SPAN_WARNING("\The [chewtoy] seems to be inedible.")) + else + user.visible_message(SPAN_DANGER("\The [user] nibbles on \the [chewtoy].")) + chewtoy.convert_to_food(user) + return TRUE + +/datum/ability_handler/predator/proc/handle_dismemberment(mob/user, mob/living/victim) + + if(victim.stat != DEAD || !victim.current_posture?.prone) + return FALSE + + if(!victim.butchery_data) + to_chat(user, SPAN_WARNING("\The [victim] appears to be inedible.")) + return TRUE + + if(victim.get_object_size() > max_dismember_size) + to_chat(user, SPAN_WARNING("\The [victim] is too big for you to dismember.")) + return TRUE + + var/target_zone = user.get_target_zone() + var/obj/item/organ/external/limb = victim.get_organ(target_zone) + if(!limb) + to_chat(user, SPAN_WARNING("\The [victim] is missing that limb!")) + return TRUE + + to_chat(user, SPAN_NOTICE("You dig into \the [victim], hunting for something edible.")) + if(!do_after(user, max(2 SECONDS, victim.get_object_size() * 5), victim) || QDELETED(victim) || !victim.butchery_data || victim.stat != DEAD) + return TRUE + + // Changing zone means we cancel. + if(target_zone != user.get_target_zone()) + return + + var/list/external_organs = victim.get_external_organs() + if(length(external_organs) <= 1) + user.visible_message(SPAN_DANGER("\The [user] tears \the [victim] apart!")) + victim.gib() + return TRUE + + limb = victim.get_organ(target_zone) // In case it was removed in the interim. + if(!limb) + to_chat(user, SPAN_WARNING("\The [victim] is missing that limb!")) + return TRUE + + if(length(limb.internal_organs)) + var/obj/item/organ/internal/stolen = pick(limb.internal_organs) + user.visible_message(SPAN_DANGER("\The [user] tears \the [stolen] out of \the [victim]'s [limb.name]!")) + victim.remove_organ(stolen, TRUE, TRUE) + if(!QDELETED(stolen)) + user.put_in_hands(stolen) + return TRUE + + if(!(limb.limb_flags & ORGAN_FLAG_CAN_AMPUTATE)) + to_chat(user, SPAN_WARNING("You gnaw on \the [victim]'s [limb.name], but can't pull it loose.")) + else + user.visible_message(SPAN_DANGER("\The [user] tears \the [limb] from \the [victim]!")) + limb.dismember(FALSE, DISMEMBER_METHOD_EDGE, silent = TRUE) + if(!QDELETED(limb)) + user.put_in_hands(limb) + return TRUE diff --git a/code/datums/extensions/abilities/ability_button.dm b/code/datums/extensions/abilities/ability_button.dm new file mode 100644 index 000000000000..5ab2d44e66b8 --- /dev/null +++ b/code/datums/extensions/abilities/ability_button.dm @@ -0,0 +1,108 @@ +/obj/screen/ability + requires_ui_style = FALSE + requires_owner = FALSE + icon_state = "ability" + icon = 'icons/mob/screen/abilities.dmi' + abstract_type = /obj/screen/ability + var/datum/ability_handler/owning_handler + +/obj/screen/ability/Destroy() + remove_from_handler() + return ..() + +/obj/screen/ability/proc/remove_from_handler() + owning_handler = null + +/obj/screen/ability/on_update_icon() + invisibility = (isnull(owning_handler) || owning_handler.showing_abilities) ? 0 : INVISIBILITY_ABSTRACT + +/obj/screen/ability/handle_click(mob/user, params) + to_chat(user, "Click!") + +/obj/screen/ability/button + icon_state = "button" + requires_owner = TRUE + maptext_y = -3 + var/decl/ability/ability + +/obj/screen/ability/button/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + START_PROCESSING(SSfastprocess, src) + on_update_icon() + +/obj/screen/ability/button/Destroy() + if(is_processing) + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/obj/screen/ability/button/Process() + // We've been broken or deleted. + if(QDELETED(src) || !ability || !owning_handler) + return PROCESS_KILL + // No reason to run periodic updates. + if(!ability.ability_cooldown_time && !ability.max_charge) + return PROCESS_KILL + // Something is broken. + var/list/metadata = owning_handler.get_metadata(ability.type, create_if_missing = FALSE) + if(!metadata) + return PROCESS_KILL + maptext = "" + if(ability.ability_cooldown_time) + var/next_cast = metadata["next_cast"] + if(world.time < next_cast) + maptext = ticks2shortreadable(next_cast - world.time) + if(ability.max_charge) + maptext += "
    " + if(ability.max_charge) + maptext += "x[max(0, metadata["charges"])]" + if(maptext) + maptext = STYLE_SMALLFONTS_OUTLINE("
    [maptext]
    ", 7, COLOR_WHITE, COLOR_BLACK) + +/obj/screen/ability/button/remove_from_handler() + owning_handler?.remove_screen_element(src, ability) + return ..() + +/obj/screen/ability/button/handle_click(mob/user, params) + if(owning_handler.prepared_ability == ability) + owning_handler.cancel_prepared_ability() + else if(ability.use_ability(user, get_turf(user), owning_handler)) // tmp, needs better/multi-step target selection + update_icon() + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), ability.get_cooldown_time(ability.get_metadata_for_user(user)) + 1) + +/obj/screen/ability/button/proc/set_ability(decl/ability/_ability) + if(ability == _ability) + return + ability = _ability + if(istype(ability)) + SetName(ability.name) + else + SetName(initial(name)) + update_icon() + +/obj/screen/ability/button/on_update_icon() + . = ..() + icon_state = initial(icon_state) + cut_overlays() + if(istype(ability)) + if(owning_handler && owning_handler.prepared_ability == ability) + icon_state = "[icon_state]-active" + if(ability.ability_icon && ability.ability_icon_state) + add_overlay(overlay_image(ability.ability_icon, ability.ability_icon_state, COLOR_WHITE, (RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM))) + +/obj/screen/ability/category + name = "Toggle Ability Category" + icon_state = "category" + +/obj/screen/ability/category/remove_from_handler() + owning_handler?.remove_screen_element(src, "toggle") + return ..() + +/obj/screen/ability/category/Initialize(mapload, mob/_owner, decl/ui_style/ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + update_icon() + +/obj/screen/ability/category/handle_click(mob/user, params) + owning_handler?.toggle_category_visibility() + +/obj/screen/ability/category/on_update_icon() + icon_state = owning_handler?.showing_abilities ? initial(icon_state) : "[initial(icon_state)]-off" diff --git a/code/datums/extensions/abilities/ability_decl.dm b/code/datums/extensions/abilities/ability_decl.dm new file mode 100644 index 000000000000..a3cb3726f89f --- /dev/null +++ b/code/datums/extensions/abilities/ability_decl.dm @@ -0,0 +1,410 @@ +/decl/ability + abstract_type = /decl/ability + /// A descriptive identifier string. + var/name + /// A descriptive string about the ability. + var/desc + /// An associated handler type, used in add_ability(). + var/associated_handler_type + /// Should this ability be copied between mobs when mind is transferred? + var/copy_with_mind = FALSE + + /// If TRUE, ability is toggled on and will fire when a target is clicked, instead of instantaneously on use. + var/prep_cast = FALSE + /// Used in conjunction with prep_cast, if TRUE, ability will be untoggled after cast. + var/end_prep_on_cast = TRUE + /// Ability items invoking this ability will GC afterwards. + var/item_end_on_cast = TRUE + + /// Does this invocation trigger on a proximity click, if prepared? + var/is_melee_invocation = FALSE + /// Does this invocation trigger on a non-proximity click, if prepared? + var/is_ranged_invocation = FALSE + + // Projectile created and used to propagate this ability, if it is a ranged ability. + /// If set, this ability will create a projectile rather than applying the effect directly. + var/projectile_type + /// Sets the projectile step_delay. + var/projectile_step_delay = 1 + /// Determines the lifetime of the projectile. + var/projectile_duration = 1 SECOND + /// If not set, the ability will have documentation generated for the codex. + var/hidden_from_codex = FALSE + /// If set, this ability will be silenced by null rod and similar mechanics. + var/is_supernatural = FALSE + + // Visual/audible state for the on-turf effect of casting the spell on something. + /// If set, will attempt to draw from this icon on the turf where the ability is used. + var/overlay_icon + /// If set, will attempt to draw this icon_state on the turf where the ability is used. + var/overlay_icon_state + /// Will delete the overlay after this time. + var/overlay_lifespan = 1 SECOND + /// If set, will play a sound when used. + var/use_sound + /// Volume for above. + var/use_sound_volume = 50 + + // Visual state for the ability HUD element. + /// Type of button to use for the UI. Should be /obj/screen/ability/button or subtype. + var/ui_element_type = /obj/screen/ability/button + /// Icon to draw on the ability HUD, if any. + var/ability_icon + /// Icon state to draw on the ability HUD, if any. + var/ability_icon_state + + // Various restrictions on how and when the ability is used. + /// A decl type that handles retrieving and validating targets. + var/decl/ability_targeting/target_selector = /decl/ability_targeting + /// If set to a numeric value, the ability cannot be used before the cooldown has expired. + var/ability_cooldown_time = 5 SECONDS + /// If set, a do_after() will be applied to this spell. + var/ability_use_channel + /// Maximum charges that can be held of this item at a time. If unset, item does not accumulate charges. + var/max_charge + /// How long it takes between charges. + var/charge_delay = 1 SECOND + /// What flags to check before an ability can be used, if any. + var/check_incapacitated = (INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING|INCAPACITATION_KNOCKOUT) + /// What type of mob is required to use this ability. + var/mob/expected_mob_type = /mob/living + /// If set, this ability can only be used while standing on a turf (not in an atom's contents or null loc). + var/requires_turf = TRUE + /// If set, this ability cannot be used on the admin z-level. + var/admin_blocked = TRUE + + // Various failure messages. + /// Failed due to purged/null rod. + var/cast_failed_purged_str = "Another power interferes with your own!" + /// Failed due to non-turf loc. + var/cast_failed_no_turf = "You must be standing on solid ground to use this ability." + /// Failed due to being on admin level + var/cast_failed_no_admin_level = "This ability cannot be used on the admin z-level." + /// Failed due to being invalid mob type + var/cast_failed_wrong_mob_type = "This ability may only be used by living creature." + /// Failed due to being downed/buckled + var/cast_failed_incapacitated = "You are in no state to use that ability." + /// Failed due to still being on cooldown from last use + var/cast_failed_on_cooldown = "You cannot use that ability again just yet." + /// Failed due to still recharging + var/cast_failed_no_charges = "You are out of charges for that ability." + /// Failed due to being silenced/disabled + var/cast_failed_disabled_str = "You are unable to use that ability for another $TIME$!" + + // Various casting messages. + /// "$USER$ begins preparing to use an ability on $TARGET$." + var/prepare_message_3p_str + /// "You begin preparing to use an ability on $TARGET$." + var/prepare_message_1p_str + /// "$USER$ uses an ability." + var/cast_message_3p_str + /// "You use an ability." + var/cast_message_1p_str + /// "You ready yourself to use an ability." + var/ready_ability_1p_str + /// "You cease readying yourself to use an ability." + var/cancel_ability_1p_str + /// "You fail to cast an ability." + var/fail_cast_1p_str + +/decl/ability/Initialize() + target_selector = GET_DECL(target_selector) + . = ..() + +/decl/ability/validate() + . = ..() + if(!istype(target_selector, /decl/ability_targeting)) + . += "null or invalid target_selector: '[target_selector || "NULL"]'" + if(!findtext(cast_failed_disabled_str, "$TIME$")) + . += "missing $TIME$ token in cast_failed_disabled_str" + if(!ispath(associated_handler_type, /datum/ability_handler)) + . += "null or invalid associated_handler_type '[associated_handler_type]'" + if(!ability_icon) + . += "null ability_icon" + else if(!istext(ability_icon_state)) + . += "null or non-text ability_icon_state" + else if(!check_state_in_icon(ability_icon_state, ability_icon)) + . += "missing ability_icon_state '[ability_icon_state]' in icon '[ability_icon]'" + +/decl/ability/proc/get_cooldown_time(list/metadata) + return ability_cooldown_time + +/decl/ability/proc/has_valid_targets(user, atom/target, list/metadata) + // Projectiles just need something to shoot at. + if(projectile_type) + return isturf(target) || isturf(target.loc) + // Abilities need at least one valid target. + return target_selector.validate_initial_target(user, target, metadata, src) + +/decl/ability/proc/get_metadata_for(mob/user) + if(!istype(user)) + CRASH("get_metadata_for() called with null or invalid user!") + var/datum/ability_handler/handler = user.get_ability_handler(associated_handler_type, create_if_missing = FALSE) + if(istype(handler)) + . = handler.get_metadata(src) + if(!islist(.)) + PRINT_STACK_TRACE("get_metadata_for() returning null or non-list metadata!") + else + PRINT_STACK_TRACE("get_metadata_for() called by mob with no handler of associated type!") + +// This is the main entrypoint for the ability use chain. +/decl/ability/proc/use_ability(mob/user, atom/target, datum/ability_handler/handler) + + if(!istype(user)) + return + + var/list/metadata = get_metadata_for(user) + if(!islist(metadata) || !can_use_ability(user, metadata)) + return + + if(prep_cast && handler.prepared_ability != src) + handler.prepare_ability(src) + return + + // Resolve our clicked target to the appropriate turf. + target = target_selector.resolve_initial_target(target) + if(!istype(target)) + to_chat(user, SPAN_WARNING("You cannot see a target for [name].")) + return + + if(!has_valid_targets(user, target, metadata)) + to_chat(user, SPAN_WARNING("You cannot use [name] on \the [target].")) + return + + if(!prepare_to_cast(user, target, metadata, handler)) + if(fail_cast_1p_str) + to_chat(user, SPAN_WARNING(capitalize_proper_html(emote_replace_user_tokens(fail_cast_1p_str, user)))) + return + + if(projectile_type) + // Fire a projectile if that is how this ability works. + fire_projectile_at(user, target, metadata) + + else + // Otherwise, just apply to the target directly. + apply_effect(user, target, metadata) + + if(end_prep_on_cast && handler.prepared_ability == src) + handler.cancel_prepared_ability() + +/decl/ability/proc/fire_projectile_at(mob/user, atom/target, list/metadata) + var/obj/item/projectile/projectile = new projectile_type(get_turf(user)) + if(istype(projectile, /obj/item/projectile/ability)) + var/obj/item/projectile/ability/ability_projectile = projectile + ability_projectile.owner = user + ability_projectile.ability_metadata = metadata + ability_projectile.carried_ability = src + projectile.original = target + projectile.starting = get_turf(user) + projectile.shot_from = user + projectile.current = projectile.original + projectile.yo = target.y - user.y + projectile.xo = target.x - user.x + projectile.life_span = projectile_duration + projectile.hitscan = !projectile_step_delay + projectile.step_delay = projectile_step_delay + projectile.launch(target) + return projectile + +/decl/ability/proc/show_cast_channel_msg(mob/user, atom/target, list/metadata) + if(prepare_message_3p_str && prepare_message_1p_str) + user.visible_message( + SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(emote_replace_user_tokens(prepare_message_3p_str, user), target))), + SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(prepare_message_1p_str, target))) + ) + else if(prepare_message_1p_str) + user.visible_message(SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(prepare_message_1p_str, target)))) + else if(prepare_message_3p_str) + user.visible_message(SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(emote_replace_user_tokens(prepare_message_3p_str, user), target)))) + +/decl/ability/proc/show_ability_cast_msg(mob/user, list/targets, list/metadata) + var/atom/target = targets[1] + if(cast_message_3p_str && cast_message_1p_str) + user.visible_message( + SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(emote_replace_user_tokens(cast_message_3p_str, user), target))), + SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(cast_message_1p_str, target))) + ) + else if(cast_message_1p_str) + user.visible_message(SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(cast_message_1p_str, target)))) + else if(cast_message_3p_str) + user.visible_message(SPAN_NOTICE(capitalize_proper_html(emote_replace_target_tokens(emote_replace_user_tokens(cast_message_3p_str, user), target)))) + +/decl/ability/proc/prepare_to_cast(mob/user, atom/target, list/metadata, datum/ability_handler/handler) + var/use_cooldown_time = get_cooldown_time(metadata) + if(ability_use_channel) + if(world.time < handler.next_channel) + return FALSE + handler.next_channel = world.time + ability_use_channel + show_cast_channel_msg(user, target, metadata) + if(!do_after(user, ability_use_channel, target) || !can_use_ability(user, metadata)) + handler.next_channel = 0 // Don't make them sit out the entire channel period, it's just a debounce/duplicate ability preventative + return FALSE + if(use_cooldown_time > 0) + metadata["next_cast"] = world.time + use_cooldown_time + return TRUE + +/decl/ability/proc/check_equipment(mob/user, list/metadata, silent = FALSE) + return TRUE + +/decl/ability/proc/get_metadata_for_user(mob/user) + if(!user.has_ability(type)) + return null + + var/datum/ability_handler/handler = user.get_ability_handler(associated_handler_type, create_if_missing = FALSE) + if(!istype(handler)) + CRASH("get_metadata_for_user() called by mob with no handler of associated type!") + + return handler.get_metadata(src) + +/decl/ability/proc/can_use_ability(mob/user, list/metadata, silent = FALSE) + + if(!user.has_ability(type)) + error("\The [user] utilized the ability '[type]' without having access to it.") + if(!silent) + to_chat(user, SPAN_WARNING("You shouldn't have this ability! Please notify a developer or raise an issue ticket.")) + return FALSE + + var/turf/my_turf = get_turf(user) + if(requires_turf) + if(!istype(my_turf)) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_no_turf)) + return FALSE + if(admin_blocked && isAdminLevel(my_turf.z)) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_no_admin_level)) + return FALSE + + if(!istype(user, expected_mob_type)) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_wrong_mob_type)) + return FALSE + + if(!isnull(check_incapacitated) && user.incapacitated(check_incapacitated)) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_incapacitated)) + return FALSE + + if(!check_equipment(user, metadata, silent)) + return FALSE + + if(ability_cooldown_time && world.time < metadata["next_cast"]) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_on_cooldown)) + return FALSE + + if(max_charge && metadata["charges"] <= 0) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_no_charges)) + return FALSE + + if(is_supernatural) + + var/is_purged = FALSE + if(isanimal(user)) + var/mob/living/simple_animal/critter = user + is_purged = !!critter.purge + + if(!is_purged) + for(var/turf/turf in range(user, 1)) + if(turf.is_purged()) + is_purged = TRUE + break + + if(is_purged) + if(!silent) + to_chat(user, SPAN_WARNING(cast_failed_purged_str)) + return FALSE + + var/disabled_time = metadata["disabled"] + if(world.time < disabled_time) + if(!silent) + var/remaining_time = ceil((disabled_time - world.time) / 10) + to_chat(user, SPAN_WARNING(replacetext(cast_failed_disabled_str, "$TIME$", "[remaining_time] second\s"))) + return FALSE + + return TRUE + +/decl/ability/proc/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile) + SHOULD_CALL_PARENT(TRUE) + if(use_sound) + playsound(get_turf(user), use_sound, use_sound_volume, 1) + if(istype(projectile)) + projectile.expended = TRUE + + admin_attacker_log(user, "attempted to use ability [src] on [hit_target]") + + var/list/targets = target_selector.get_affected(user, hit_target, metadata, src, projectile) + if(length(targets)) + show_ability_cast_msg(user, targets, metadata) + while(length(targets)) + var/target = targets[1] + apply_effect_to(user, target, metadata) + targets = prune_targets(user, target, targets, metadata) + finish_casting(user, hit_target, metadata) + +/decl/ability/proc/finish_casting(mob/user, atom/hit_target, list/metadata) + return + +/decl/ability/proc/prune_targets(user, previous_target, list/targets, list/metadata) + if(!length(targets)) + return null + if(previous_target) + LAZYREMOVE(targets, previous_target) + return targets + +/decl/ability/proc/apply_visuals(mob/user, atom/target, list/metadata) + if(!overlay_icon || !overlay_lifespan) + return + var/turf/overlay_loc = get_turf(target) + if(!isturf(overlay_loc) || locate(/obj/effect/overlay) in overlay_loc) + return + var/obj/effect/overlay/ability_overlay = new(overlay_loc) + ability_overlay.icon = overlay_icon + ability_overlay.icon_state = overlay_icon_state + ability_overlay.anchored = TRUE + ability_overlay.set_density(FALSE) + QDEL_IN(ability_overlay, overlay_lifespan) + +/decl/ability/proc/apply_effect_to(mob/user, atom/target, list/metadata) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + apply_visuals(user, target, metadata) + +/decl/ability/proc/get_default_metadata() + . = list() + if(ability_cooldown_time) + .["next_cast"] = 0 + if(max_charge) + .["charges"] = max_charge + .["next_charge"] = 0 + +/decl/ability/proc/recharge(mob/owner, list/metadata) + if(max_charge <= 0 || metadata["charges"] >= max_charge) + return FALSE + if(world.time < metadata["next_charge"]) + return TRUE + metadata["next_charge"] = world.time + charge_delay + metadata["charges"]++ + return TRUE + +/decl/ability/proc/get_stat_strings(list/metadata) + var/use_name = metadata["ability_name"] || name + if(ability_cooldown_time) + var/on_cooldown = metadata["next_cast"] - world.time + if(on_cooldown > 0) + return list( + use_name, + "[ceil(on_cooldown/10)]s" + ) + if(max_charge) + return list( + use_name, + "[metadata["charges"]]/[max_charge]" + ) + +/decl/ability/ranged + abstract_type = /decl/ability/ranged + projectile_type = /obj/item/projectile/ability + is_ranged_invocation = TRUE + prep_cast = TRUE \ No newline at end of file diff --git a/code/datums/extensions/abilities/ability_handler.dm b/code/datums/extensions/abilities/ability_handler.dm new file mode 100644 index 000000000000..0b773cb469d5 --- /dev/null +++ b/code/datums/extensions/abilities/ability_handler.dm @@ -0,0 +1,279 @@ +/datum/ability_handler + abstract_type = /datum/ability_handler + var/showing_abilities = FALSE + var/mob/owner + var/datum/extension/abilities/master + var/list/ability_items + var/list/screen_elements + var/list/known_abilities + var/list/recharging_abilities + var/stat_panel_type = "Abilities" + /// UI element for showing or hiding this ability category. Should be /obj/screen/ability/category or subtype. + var/category_toggle_type = /obj/screen/ability/category + var/decl/ability/prepared_ability + var/next_channel = 0 + +/datum/ability_handler/New(_master) + master = _master + if(!istype(master)) + CRASH("Ability handler received invalid master!") + owner = master.holder + if(!istype(owner)) + CRASH("Ability handler received invalid owner!") + ..() + refresh_login(being_created = TRUE) + +/datum/ability_handler/Process() + + if(!length(recharging_abilities)) + return PROCESS_KILL + + for(var/decl/ability/ability as anything in recharging_abilities) + if(!ability.recharge(owner, get_metadata(ability))) + LAZYREMOVE(recharging_abilities, ability) + +/datum/ability_handler/proc/get_metadata(decl/ability/ability, create_if_missing = TRUE) + if(istype(ability)) + . = known_abilities[ability.type] + if(!islist(.) && create_if_missing) + . = ability.get_default_metadata() + known_abilities[ability.type] = . + else if(ispath(ability, /decl/ability)) + . = known_abilities[ability] + if(!islist(.) && create_if_missing) + ability = GET_DECL(ability) + if(!istype(ability)) + return list() + . = ability.get_default_metadata() + known_abilities[ability] = . + else if(create_if_missing) + PRINT_STACK_TRACE("ability metadata retrieval passed invalid ability type: '[ability]'") + . = list() + +/datum/ability_handler/Destroy() + recharging_abilities = null + known_abilities = null + QDEL_NULL_LIST(ability_items) + + for(var/ability in screen_elements) + var/obj/element = screen_elements[ability] + if(istype(element)) + qdel(element) + screen_elements = null + + if(master) + LAZYREMOVE(master.ability_handlers, src) + master.update() + master = null + owner = null + if(is_processing) + STOP_PROCESSING(SSprocessing, src) + return ..() + +/datum/ability_handler/proc/add_ability(ability_type, list/metadata) + if(provides_ability(ability_type)) + return FALSE + var/decl/ability/ability = GET_DECL(ability_type) + if(!istype(ability)) + return FALSE + if(islist(metadata)) + metadata = metadata.Copy() // Prevent mutating during copy from other mobs. + else + metadata = ability.get_default_metadata() // Always unique, no copy needed. + + if(ability.ui_element_type && !istype(LAZYACCESS(screen_elements, ability), ability.ui_element_type)) + var/existing = screen_elements[ability] + if(existing) + remove_screen_element(existing, ability, FALSE) + var/obj/screen/ability/button/button = new ability.ui_element_type(null, owner, null, null, null, null, null) + button.set_ability(ability) + add_screen_element(button, ability, TRUE) + + LAZYSET(known_abilities, ability_type, metadata) + if(ability.max_charge) + LAZYDISTINCTADD(recharging_abilities, ability_type) + if(!is_processing) + START_PROCESSING(SSprocessing, src) + return TRUE + +/datum/ability_handler/proc/remove_ability(ability_type) + if(!provides_ability(ability_type)) + return FALSE + LAZYREMOVE(known_abilities, ability_type) + LAZYREMOVE(recharging_abilities, ability_type) + + var/decl/ability/ability = GET_DECL(ability_type) + if(ability?.ui_element_type) + var/obj/screen/existing_button = LAZYACCESS(screen_elements, ability) + if(istype(existing_button)) + remove_screen_element(existing_button, ability) + + if(!LAZYLEN(recharging_abilities) && is_processing) + STOP_PROCESSING(SSprocessing, src) + + if(!LAZYLEN(known_abilities)) + owner.remove_ability_handler(type) + + return TRUE + +/datum/ability_handler/proc/provides_ability(ability_type) + return (ability_type in known_abilities) + +/datum/ability_handler/proc/finalize_ability_handler() + if(category_toggle_type) + var/obj/screen/ability/category/category_toggle = new category_toggle_type(null, null, null, null, null, null, null) + add_screen_element(category_toggle, "toggle", TRUE) + toggle_category_visibility(TRUE) + +/datum/ability_handler/proc/refresh_element_positioning(row = 1, col = 1) + if(!LAZYLEN(screen_elements)) + return 0 + var/button_pos = col + var/button_row = row + . = 1 + for(var/ability in screen_elements) + var/obj/screen/element = screen_elements[ability] + if(istype(element, /obj/screen/ability/category)) + element.screen_loc = "RIGHT-[col]:-4,TOP-[row]" + else if(!element.invisibility) + button_pos++ + if((button_pos-col) > 5) + button_row++ + .++ + button_pos = col+1 + element.screen_loc = "RIGHT-[button_pos]:-4,TOP-[button_row]" + +/datum/ability_handler/proc/toggle_category_visibility(force_state) + showing_abilities = isnull(force_state) ? !showing_abilities : force_state + update_screen_elements() + if(master) + master.refresh_element_positioning() + +/datum/ability_handler/proc/update_screen_elements() + for(var/ability in screen_elements) + var/obj/screen/ability/ability_button = screen_elements[ability] + ability_button.update_icon() + +/datum/ability_handler/proc/copy_abilities_to(mob/living/target) + for(var/decl/ability/ability as anything in known_abilities) + if(!ability.copy_with_mind) + continue + if(target.add_ability(ability, get_metadata(ability, create_if_missing = FALSE))) + . = TRUE + +/datum/ability_handler/proc/disable_abilities(amount) + for(var/ability in known_abilities) + var/list/metadata = get_metadata(ability) + metadata["disabled"] = max(metadata["disabled"], (world.time + amount)) + +/datum/ability_handler/proc/enable_abilities(amount) + for(var/ability in known_abilities) + var/list/metadata = get_metadata(ability) + metadata["disabled"] = 0 + +/datum/ability_handler/proc/add_screen_element(atom/element, decl/ability/ability, update_positions = TRUE) + if(isnull(ability) || isnum(ability)) + return + LAZYSET(screen_elements, ability, element) + owner?.client?.screen |= element + if(istype(element, /obj/screen/ability)) + var/obj/screen/ability/ability_button = element + ability_button.owning_handler = src + if(update_positions && master && length(screen_elements)) + master.refresh_element_positioning() + +/datum/ability_handler/proc/remove_screen_element(atom/element, decl/ability/ability, update_positions = TRUE) + if(isnull(ability) || isnum(ability)) + return + LAZYREMOVE(screen_elements, ability) + owner?.client?.screen -= element + if(istype(element, /obj/screen/ability)) + var/obj/screen/ability/ability_button = element + if(ability_button.owning_handler == src) + ability_button.owning_handler = null + if(update_positions && master && LAZYLEN(screen_elements)) + master.refresh_element_positioning() + +/datum/ability_handler/proc/cancel() + if(LAZYLEN(ability_items)) + for(var/thing in ability_items) + owner?.drop_from_inventory(thing) + qdel(thing) + ability_items = null + +/datum/ability_handler/proc/show_stat_string(mob/user) + if(!stat_panel_type || !statpanel(stat_panel_type)) + return + for(var/ability_type in known_abilities) + var/decl/ability/ability = GET_DECL(ability_type) + var/list/stat_strings = ability.get_stat_strings(get_metadata(ability)) + if(length(stat_strings) >= 2) + stat(stat_strings[1], stat_strings[2]) + +/// Individual ability methods/disciplines (psioncs, etc.) so that mobs can have multiple. +/datum/ability_handler/proc/refresh_login(being_created = FALSE) + SHOULD_CALL_PARENT(TRUE) + if(LAZYLEN(screen_elements)) + var/list/add_elements = list() + for(var/ability in screen_elements) + var/atom/element = screen_elements[ability] + if(istype(element)) + add_elements |= element + if(length(add_elements)) + owner?.client?.screen |= add_elements + +/datum/ability_handler/proc/cancel_prepared_ability() + if(!prepared_ability) + return FALSE + if(prepared_ability.cancel_ability_1p_str) + to_chat(owner, capitalize_proper_html(emote_replace_user_tokens(prepared_ability.cancel_ability_1p_str), owner)) + var/obj/screen/ability/button/button = LAZYACCESS(screen_elements, prepared_ability) + prepared_ability = null + if(istype(button)) + button.update_icon() + return TRUE + +/datum/ability_handler/proc/prepare_ability(decl/ability/ability) + if(prepared_ability && !cancel_prepared_ability()) + return FALSE + prepared_ability = ability + if(ability.ready_ability_1p_str) + to_chat(owner, capitalize_proper_html(emote_replace_user_tokens(ability.ready_ability_1p_str), owner)) + var/obj/screen/ability/button/button = LAZYACCESS(screen_elements, ability) + if(istype(button)) + button.update_icon() + return TRUE + +/datum/ability_handler/proc/can_do_self_invocation(mob/user) + return FALSE + +/datum/ability_handler/proc/do_self_invocation(mob/user) + return FALSE + +/datum/ability_handler/proc/can_do_grabbed_invocation(mob/user, atom/target) + return FALSE + +/datum/ability_handler/proc/do_grabbed_invocation(mob/user, atom/target) + return FALSE + +/datum/ability_handler/proc/can_do_melee_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(TRUE) + return prepared_ability ? prepared_ability.is_melee_invocation : FALSE + +/datum/ability_handler/proc/do_melee_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(TRUE) + if(prepared_ability) + prepared_ability.use_ability(user, target, src) + return TRUE + return FALSE + +/datum/ability_handler/proc/can_do_ranged_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(TRUE) + return prepared_ability ? prepared_ability.is_ranged_invocation : FALSE + +/datum/ability_handler/proc/do_ranged_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(TRUE) + if(prepared_ability) + prepared_ability.use_ability(user, target, src) + return TRUE + return FALSE diff --git a/code/datums/extensions/abilities/ability_item.dm b/code/datums/extensions/abilities/ability_item.dm new file mode 100644 index 000000000000..b4838fd41458 --- /dev/null +++ b/code/datums/extensions/abilities/ability_item.dm @@ -0,0 +1,62 @@ +/obj/item/ability + simulated = FALSE + icon = 'icons/mob/screen/ability_inhand.dmi' + obj_flags = OBJ_FLAG_NO_STORAGE + anchored = TRUE + pickup_sound = null + drop_sound = null + equip_sound = null + is_spawnable_type = FALSE + abstract_type = /obj/item/ability + var/decl/ability/ability + var/weakref/owner_ref + var/handler_type + +/obj/item/ability/Initialize(ml, decl/ability/_ability) + var/mob/living/owner = loc + var/datum/ability_handler/handler = istype(owner) && owner.get_ability_handler(handler_type, FALSE) + if(!istype(handler)) + return INITIALIZE_HINT_QDEL + if(_ability) + ability = _ability + if(!istype(ability)) + return INITIALIZE_HINT_QDEL + owner_ref = weakref(owner) + LAZYDISTINCTADD(handler.ability_items, src) + . = ..() + owner.put_in_hands(src) + +/obj/item/ability/Destroy() + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/handler = istype(owner) && owner.get_ability_handler(handler_type, FALSE) + if(istype(handler)) + LAZYREMOVE(handler.ability_items, src) + return ..() + +/obj/item/ability/dropped() + ..() + qdel(src) + +/obj/item/ability/attack_self(var/mob/user) + user?.drop_from_inventory(src) + return TRUE + +/obj/item/ability/use_on_mob(mob/living/target, mob/living/user, animate) + return FALSE + +/obj/item/ability/afterattack(atom/target, mob/user, proximity) + if(QDELETED(src) || !istype(ability)) + return TRUE + var/list/metadata = ability.get_metadata_for(user) + if(!islist(metadata)) + return TRUE + if(ability.projectile_type) + // Fire a projectile if that is how this ability works. + ability.fire_projectile_at(user, target, metadata) + else + // Otherwise, apply to the target. Range checking etc. will be handled in apply_effect(). + ability.apply_effect(user, target, metadata) + + // Clean up our item if needed. + if(ability.item_end_on_cast) + qdel(src) diff --git a/code/datums/extensions/abilities/ability_projectile.dm b/code/datums/extensions/abilities/ability_projectile.dm new file mode 100644 index 000000000000..896acba2e95a --- /dev/null +++ b/code/datums/extensions/abilities/ability_projectile.dm @@ -0,0 +1,31 @@ +/obj/item/projectile/ability + name = "ability" + // The projectile is functionally a tracer, the ability deals the damage. + nodamage = TRUE + penetrating = FALSE + + /// Default; can be set by the ability. + life_span = 1 SECOND + + var/expended = FALSE + var/mob/owner + var/list/ability_metadata + var/decl/ability/carried_ability + +/obj/item/projectile/ability/Destroy() + owner = null + carried_ability = null + return ..() + +/obj/item/projectile/ability/explosion_act() + SHOULD_CALL_PARENT(FALSE) + +/obj/item/projectile/ability/Bump(var/atom/A, forced=0) + if(loc && carried_ability && !expended) + carried_ability.apply_effect(owner, A, ability_metadata, src) + return TRUE + +/obj/item/projectile/ability/on_impact(var/atom/A) + if(loc && carried_ability && !expended) + carried_ability.apply_effect(owner, A, ability_metadata, src) + return TRUE diff --git a/code/datums/extensions/abilities/ability_targeting.dm b/code/datums/extensions/abilities/ability_targeting.dm new file mode 100644 index 000000000000..52f7ee8166c5 --- /dev/null +++ b/code/datums/extensions/abilities/ability_targeting.dm @@ -0,0 +1,91 @@ +/decl/ability_targeting + abstract_type = /decl/ability_targeting + /// If set, this ability is applied to a square of this radius. + var/effect_radius = 0 + /// Set to except the inner space of the spell from target checks. + var/effect_inner_radius = -1 + /// If set, user will be excepted from targets. + var/user_is_immune = FALSE + /// If set, this ability will never target our faction. + var/faction_immune = FALSE + /// If set, this ability will only target our faction. + var/faction_only = FALSE + /// If set, this ability will resolve targets to turfs before doing any assessment or targetting. + var/target_turf = TRUE + /// If set along with target turf type, will include dense turfs. + var/ignore_dense_turfs = TRUE + /// If set along target turf type, will include space turfs. + var/ignore_space_turfs = FALSE + +/decl/ability_targeting/proc/get_effect_radius(mob/user, atom/hit_target, list/metadata) + return effect_radius + +/// This proc exists so that subtypes can override it and take advantage of the speed benefits of `for(var/mob in range())` and similar optimizations. +/// It should ONLY ever be called in get_affected(). +/decl/ability_targeting/proc/get_affected_atoms(atom/center, new_effect_radius) + PROTECTED_PROC(TRUE) + . = list() + for(var/atom/target in range(center, new_effect_radius)) + . += target + +/decl/ability_targeting/proc/get_affected(mob/user, atom/hit_target, list/metadata, decl/ability/ability, obj/item/projectile/ability/projectile) + if(effect_radius <= 0) + return validate_target(user, hit_target, metadata, ability) ? list(hit_target) : null + var/atom/center = projectile || hit_target + var/new_effect_radius = get_effect_radius(user, hit_target, metadata) + var/list/except_atoms = effect_inner_radius >= 0 ? range(effect_inner_radius, center) : null + var/list/target_candidates = get_affected_atoms(center, new_effect_radius) + for(var/atom/target in except_atoms ? target_candidates - except_atoms : target_candidates) // sloooooow... + if(validate_target(user, target, metadata, ability)) + LAZYADD(., target) + +/decl/ability_targeting/proc/resolve_initial_target(atom/target) + if(target_turf) + return get_turf(target) + return target + +/decl/ability_targeting/proc/validate_initial_target(mob/user, atom/target, list/metadata, decl/ability/ability) + return validate_target(user, target, metadata, ability) + +/decl/ability_targeting/proc/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability) + if(target == user && !user_is_immune) + return FALSE + if(target_turf && !isturf(target)) + return FALSE + if(user.faction) + if(faction_immune && ismob(target)) + var/mob/target_mob = target + if(target_mob.faction == user.faction) + return FALSE + if(faction_only) + if(!ismob(target)) + return FALSE + var/mob/target_mob = target + if(target_mob.faction != user.faction) + return FALSE + else if(faction_only) + return FALSE + if(isturf(target)) + if(ignore_dense_turfs && target.density) + return FALSE + if(ignore_space_turfs && istype(target, /turf/space)) + return FALSE + return TRUE + +/decl/ability_targeting/clear_turf + ignore_dense_turfs = TRUE + +/decl/ability_targeting/clear_turf/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability) + . = ..() && isturf(target) + if(.) + var/turf/target_turf = target + return !target_turf.contains_dense_objects(user) + +/decl/ability_targeting/living_mob + target_turf = FALSE + +/decl/ability_targeting/living_mob/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability) + . = ..() && isliving(target) + if(.) + var/mob/living/victim = target + return victim.simulated diff --git a/code/datums/extensions/abilities/readme.dm b/code/datums/extensions/abilities/readme.dm new file mode 100644 index 000000000000..b7e17f8d59e3 --- /dev/null +++ b/code/datums/extensions/abilities/readme.dm @@ -0,0 +1,26 @@ +/* + + ABILITY DECL SYSTEM NOTES + + - Mobs have an extension, /datum/extension/abilities + - This extension has a list of associated handlers, /datum/ability_handler + - The handlers have a list of associated ability decls, /decl/ability, which are indexes for associative metadata lists. + - The abilities have an associated targeting handler, /decl/ability_targeting, which handles single target, turf target, AOE, etc. + - Handlers are added/removed with mob.add_ability_handler(handler_type) and mob.remove_ability_handler(handler_type) + - The extension will be added to the mob automatically when adding a handler, and removed if the last handler is removed. + - Abilities are added/removed with mob.add_ability(ability_type, preset metadata if any) and mob.remove_ability(ability_type) + - Handlers for abilities will be inferred from the /decl and added to the mob automatically. + - Metadata is retrieved with handler.get_metadata(ability type or instance) + + - Upon invocation, an ability will: + - retrieve handler and metadata from the user mob + - validate the handler/metadata/user against whatever requirements the ability has + - resolve the initial click target to the appropriate target for the ability (turf under the clicked target for example) + - check any additional requirements like charges, cooldowns, etc. + - if a projectile ability, spawn and launch a projectile that will carry the ability and metadata to the destination target. + - apply the ability to the destination target + - while applying the ability, the targeting decl will be used to grab all applicable targets at or near the point of use (projectile hit or clicked target) + - the ability effects will then get applied (fire, ice, explosion, so on) + - the ability will then set cooldown as appropriate in metadata, deduct charges, etc + +*/ \ No newline at end of file diff --git a/code/datums/extensions/access_provider.dm b/code/datums/extensions/access_provider.dm new file mode 100644 index 000000000000..845ff159f487 --- /dev/null +++ b/code/datums/extensions/access_provider.dm @@ -0,0 +1,18 @@ +/datum/extension/access_provider + base_type = /datum/extension/access_provider + expected_type = /atom/movable + var/list/atom/movable/registered_ids + +/datum/extension/access_provider/Destroy() + LAZYCLEARLIST(registered_ids) + . = ..() + +/datum/extension/access_provider/proc/register_id(atom/movable/to_register) + LAZYDISTINCTADD(registered_ids, to_register) + +/datum/extension/access_provider/proc/unregister_id(atom/movable/to_unregister) + LAZYREMOVE(registered_ids, to_unregister) + +/datum/extension/access_provider/proc/GetIdCards(list/exceptions) + for(var/atom/movable/registered_id in registered_ids) + LAZYDISTINCTADD(., registered_id.GetIdCards(exceptions)) diff --git a/code/datums/extensions/appearance/appearance.dm b/code/datums/extensions/appearance/appearance.dm index 56c4c378b0b0..45d88be5ce1c 100644 --- a/code/datums/extensions/appearance/appearance.dm +++ b/code/datums/extensions/appearance/appearance.dm @@ -7,16 +7,16 @@ var/item_removal_proc /datum/extension/appearance/New(var/holder) - var/appearance_handler = appearance_manager.get_appearance_handler(appearance_handler_type) + var/decl/appearance_handler/appearance_handler = GET_DECL(appearance_handler_type) if(!appearance_handler) CRASH("Unable to acquire the [appearance_handler_type] appearance handler.") - GLOB.item_equipped_event.register(holder, appearance_handler, item_equipment_proc) - GLOB.item_unequipped_event.register(holder, appearance_handler, item_removal_proc) + events_repository.register(/decl/observ/item_equipped, holder, appearance_handler, item_equipment_proc) + events_repository.register(/decl/observ/item_unequipped, holder, appearance_handler, item_removal_proc) ..() /datum/extension/appearance/Destroy() - var/appearance_handler = appearance_manager.get_appearance_handler(appearance_handler_type) - GLOB.item_equipped_event.unregister(holder, appearance_handler, item_equipment_proc) - GLOB.item_unequipped_event.unregister(holder, appearance_handler, item_removal_proc) + var/decl/appearance_handler/appearance_handler = GET_DECL(appearance_handler_type) + events_repository.unregister(/decl/observ/item_equipped, holder, appearance_handler, item_equipment_proc) + events_repository.unregister(/decl/observ/item_unequipped, holder, appearance_handler, item_removal_proc) . = ..() \ No newline at end of file diff --git a/code/datums/extensions/appearance/universally_visible.dm b/code/datums/extensions/appearance/universally_visible.dm new file mode 100644 index 000000000000..76de6559b8c3 --- /dev/null +++ b/code/datums/extensions/appearance/universally_visible.dm @@ -0,0 +1,61 @@ +var/global/list/universally_visible_atom_extensions = list() + +/mob/Login() + ..() + if(client && length(global.universally_visible_atom_extensions)) + for(var/datum/extension/universally_visible/univis in global.universally_visible_atom_extensions) + univis.show_to(client) + +/mob/Move() + . = ..() + if(. && client && length(global.universally_visible_atom_extensions)) + for(var/datum/extension/universally_visible/univis in global.universally_visible_atom_extensions) + univis.show_to(client) + +/mob/forceMove() + . = ..() + if(. && client && length(global.universally_visible_atom_extensions)) + for(var/datum/extension/universally_visible/univis in global.universally_visible_atom_extensions) + univis.show_to(client) + +/datum/extension/universally_visible + expected_type = /atom/movable + base_type = /datum/extension/universally_visible + var/list/last_shown_image = list() + +/datum/extension/universally_visible/New(datum/holder) + . = ..() + global.universally_visible_atom_extensions += src + +/datum/extension/universally_visible/Destroy() + global.universally_visible_atom_extensions -= src + return ..() + +/datum/extension/universally_visible/proc/refresh() + for(var/client/C) + show_to(C) + +/datum/extension/universally_visible/proc/show_to(var/client/C) + + if(!ismob(C?.mob) || QDELETED(C.mob)) + return + + var/weakref/mob_ref = weakref(C.mob) + var/image/I = last_shown_image[mob_ref] + if(I) + C.images -= I + + var/atom/movable/visible_atom = holder + var/turf/mob_turf = get_turf(C.mob) + var/turf/atom_turf = visible_atom.loc + if(!istype(atom_turf) || mob_turf.z != atom_turf.z || (visible_atom in view(max(C.last_view_x_dim, C.last_view_y_dim), mob_turf))) + return + + I = image(null) + I.appearance = visible_atom + I.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + I.pixel_x = world.icon_size * (atom_turf.x - mob_turf.x) + visible_atom.pixel_x + I.pixel_y = world.icon_size * (atom_turf.y - mob_turf.y) + visible_atom.pixel_y + I.loc = get_turf(mob_turf) + C.images += I + last_shown_image[mob_ref] = I diff --git a/code/datums/extensions/armor/ablative.dm b/code/datums/extensions/armor/ablative.dm index ea0da588d87c..fe7c215f4be3 100644 --- a/code/datums/extensions/armor/ablative.dm +++ b/code/datums/extensions/armor/ablative.dm @@ -14,12 +14,12 @@ if(!(damage_type == BRUTE || damage_type == BURN)) return if(armor_degradation_coef) - var/key = get_armor_key(damage_type, damage_flags) + var/key = SSmaterials.get_armor_key(damage_type, damage_flags) var/damage_blocked = round(damage * blocked) if(damage_blocked) var/new_armor = max(0, get_value(key) - armor_degradation_coef * damage_blocked) set_value(key, new_armor) - var/mob/M = get_holder_of_type(holder, /mob) + var/mob/M = holder.get_recursive_loc_of_type(/mob) if(istype(M)) var/list/visible = get_visible_damage() for(var/k in visible) diff --git a/code/datums/extensions/armor/armor.dm b/code/datums/extensions/armor/armor.dm index 4d2c69829681..8e9dd0055bab 100644 --- a/code/datums/extensions/armor/armor.dm +++ b/code/datums/extensions/armor/armor.dm @@ -52,7 +52,7 @@ // A simpler proc used as a helper for above but can also be used externally. Does not modify state. /datum/extension/armor/proc/get_blocked(damage_type, damage_flags, armor_pen = 0, damage = 5) - var/key = get_armor_key(damage_type, damage_flags) + var/key = SSmaterials.get_armor_key(damage_type, damage_flags) if(!key) return 0 @@ -69,32 +69,7 @@ return min(armor_values[key], 100) /datum/extension/armor/proc/set_value(key, newval) - armor_values[key] = Clamp(newval, 0, 100) - -// There is a disconnect between legacy damage and armor code. This here helps bridge the gap. -/proc/get_armor_key(damage_type, damage_flags) - var/key - switch(damage_type) - if(BRUTE) - if(damage_flags & DAM_BULLET) - key = "bullet" - else if(damage_flags & DAM_EXPLODE) - key = "bomb" - else - key = "melee" - if(BURN) - if(damage_flags & DAM_LASER) - key = "laser" - else if(damage_flags & DAM_EXPLODE) - key = "bomb" - else - key = "energy" - if(TOX) - if(damage_flags & DAM_BIO) - key = "bio" // Otherwise just not blocked by default. - if(IRRADIATE) - key = "rad" - return key + armor_values[key] = clamp(newval, 0, 100) /datum/extension/armor/toggle var/active = TRUE diff --git a/code/datums/extensions/armor/armor_rig.dm b/code/datums/extensions/armor/armor_rig.dm index c0c73082fba3..e977ab0207a3 100644 --- a/code/datums/extensions/armor/armor_rig.dm +++ b/code/datums/extensions/armor/armor_rig.dm @@ -2,6 +2,6 @@ var/sealed = FALSE /datum/extension/armor/rig/get_value(key) - if(key == "bio" && sealed) + if(key == ARMOR_BIO && sealed) return 100 return ..() \ No newline at end of file diff --git a/code/datums/extensions/assembly/assembly.dm b/code/datums/extensions/assembly/assembly.dm index 6689aea4aa08..f060c3f78fd6 100644 --- a/code/datums/extensions/assembly/assembly.dm +++ b/code/datums/extensions/assembly/assembly.dm @@ -40,8 +40,8 @@ return parts += P if(user) - user.unEquip(P, holder) - to_chat(user, "You install \the [P] into \the [assembly_name]") + user.try_unequip(P, holder) + to_chat(user, "You install \the [P] into \the [assembly_name].") return TRUE /datum/extension/assembly/proc/uninstall_component(var/mob/living/user, var/obj/item/stock_parts/P) @@ -52,7 +52,7 @@ else var/atom/movable/H = holder P.dropInto(H.loc) - if(P.type in critical_parts) + if(enabled && (P.type in critical_parts)) critical_shutdown() /datum/extension/assembly/proc/add_replace_component(var/mob/living/user, var/part_type, var/obj/item/stock_parts/P) diff --git a/code/datums/extensions/assembly/assembly_damage.dm b/code/datums/extensions/assembly/assembly_damage.dm index d5517f1974af..f05a10282769 100644 --- a/code/datums/extensions/assembly/assembly_damage.dm +++ b/code/datums/extensions/assembly/assembly_damage.dm @@ -1,22 +1,21 @@ -/datum/extension/assembly/proc/examine(mob/user) +/datum/extension/assembly/proc/examine_assembly(mob/user) if(damage > broken_damage) - to_chat(user, SPAN_DANGER("It is heavily damaged!")) + return SPAN_DANGER("It is heavily damaged!") else if(damage) - to_chat(user, "It is damaged.") + return "It is damaged." /datum/extension/assembly/proc/break_apart() var/atom/movable/H = holder H.visible_message("\The [holder] breaks apart!") - var/turf/newloc = get_turf(holder) - new /obj/item/stack/material/steel(newloc, round(steel_sheet_cost/2)) for(var/obj/item/stock_parts/P in parts) uninstall_component(null, P) - P.forceMove(newloc) + P.forceMove(H.loc) if(prob(25)) P.take_damage(rand(10,30)) + H.physically_destroyed() qdel(src) -/datum/extension/assembly/proc/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1) +/datum/extension/assembly/proc/take_assembly_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1) //if(!modifiable) // return @@ -26,7 +25,7 @@ amount = round(amount) if(damage_casing) damage += amount - damage = between(0, damage, max_damage) + damage = clamp(0, damage, max_damage) if(component_probability) for(var/obj/item/stock_parts/computer/H in get_all_components()) @@ -39,20 +38,20 @@ // Stronger explosions cause serious damage to internal components // Minor explosions are mostly mitigitated by casing. /datum/extension/assembly/proc/ex_act(var/severity) - take_damage(rand(100,200) / severity, 30 / severity) + take_assembly_damage(rand(100,200) / severity, 30 / severity) // EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components /datum/extension/assembly/proc/emp_act(var/severity) - take_damage(rand(100,200) / severity, 50 / severity, 0) + take_assembly_damage(rand(100,200) / severity, 50 / severity, 0) // "Stun" weapons can cause minor damage to components (short-circuits?) // "Burn" damage is equally strong against internal components and exterior casing // "Brute" damage mostly damages the casing. /datum/extension/assembly/proc/bullet_act(var/obj/item/projectile/Proj) - switch(Proj.damage_type) + switch(Proj.atom_damage_type) if(BRUTE) - take_damage(Proj.damage, Proj.damage / 2) + take_assembly_damage(Proj.damage, Proj.damage / 2) if(PAIN) - take_damage(Proj.damage, Proj.damage / 3, 0) + take_assembly_damage(Proj.damage, Proj.damage / 3, 0) if(BURN) - take_damage(Proj.damage, Proj.damage / 1.5) \ No newline at end of file + take_assembly_damage(Proj.damage, Proj.damage / 1.5) diff --git a/code/datums/extensions/assembly/assembly_interaction.dm b/code/datums/extensions/assembly/assembly_interaction.dm index c0bc0ab842fa..7987ee9f8fd6 100644 --- a/code/datums/extensions/assembly/assembly_interaction.dm +++ b/code/datums/extensions/assembly/assembly_interaction.dm @@ -1,19 +1,18 @@ -/datum/extension/assembly/proc/attackby(var/obj/item/W, var/mob/user) - if(isWrench(W)) +/datum/extension/assembly/proc/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WRENCH(used_item)) if(parts.len) to_chat(user, "Remove all components from \the [holder] before disassembling it.") return TRUE - var/atom/movable/H = holder - new /obj/item/stack/material/steel( get_turf(H.loc), steel_sheet_cost ) + SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(holder), steel_sheet_cost) if(user) user.visible_message("\The [holder] has been disassembled by [user].") qdel(holder) return TRUE - if(isWelder(W)) - var/obj/item/weldingtool/WT = W - if(!WT.isOn()) - to_chat(user, "\The [W] is off.") + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(!welder.isOn()) + to_chat(user, "\The [used_item] is off.") return TRUE if(!damage) @@ -21,12 +20,12 @@ return TRUE to_chat(user, "You begin repairing damage to \the [holder]...") - if(WT.remove_fuel(round(damage/75)) && do_after(usr, damage/10)) + if(welder.weld(round(damage/75)) && do_after(user, damage/10)) damage = 0 to_chat(user, "You repair \the [holder].") return TRUE - if(isScrewdriver(W)) + if(IS_SCREWDRIVER(used_item)) if(!parts.len) to_chat(user, "This device doesn't have any components installed.") return TRUE @@ -34,11 +33,11 @@ for(var/obj/item/stock_parts/computer/H in parts) component_names.Add(H.name) - var/choice = input(usr, "Which component do you want to uninstall?", "[assembly_name] maintenance", null) as null|anything in component_names + var/choice = input(user, "Which component do you want to uninstall?", "[assembly_name] maintenance", null) as null|anything in component_names if(!choice) return TRUE var/atom/movable/HA = holder - if(!HA.Adjacent(usr)) + if(!HA.Adjacent(user)) return TRUE var/obj/item/stock_parts/H = find_component_by_name(choice) @@ -48,24 +47,24 @@ uninstall_component(user, H) return TRUE - if(istype(W, /obj/item/card/id)) // ID Card, try to insert it. + if(istype(used_item, /obj/item/card/id)) // ID Card, try to insert it. var/obj/item/stock_parts/computer/card_slot/card_slot = get_component(PART_CARD) if(!card_slot) - to_chat(user, SPAN_WARNING("You try to insert [W] into [holder], but it does not have an ID card slot installed.")) + to_chat(user, SPAN_WARNING("You try to insert [used_item] into [holder], but it does not have an ID card slot installed.")) return TRUE - card_slot.insert_id(W, user) + card_slot.insert_id(used_item, user) return TRUE - if(istype(W, /obj/item/charge_stick)) // Try to insert charge stick. + if(istype(used_item, /obj/item/charge_stick)) // Try to insert charge stick. var/obj/item/stock_parts/computer/charge_stick_slot/mstick_slot = get_component(PART_MSTICK) if(!mstick_slot) - to_chat(user, SPAN_WARNING("You try to insert [W] into [holder], but it does not have a charge-stick slot installed.")) + to_chat(user, SPAN_WARNING("You try to insert [used_item] into [holder], but it does not have a charge-stick slot installed.")) return TRUE - mstick_slot.insert_stick(W, user) + mstick_slot.insert_stick(used_item, user) return TRUE - if(istype(W, PART_DRIVE)) // Portable HDD, try to insert it. - var/obj/item/stock_parts/computer/hard_drive/portable/I = W + if(istype(used_item, PART_DRIVE)) // Portable HDD, try to insert it. + var/obj/item/stock_parts/computer/hard_drive/portable/I = used_item var/obj/item/stock_parts/computer/drive_slot/drive_slot = get_component(PART_D_SLOT) if(!drive_slot) to_chat(user, SPAN_WARNING("You try to insert [I] into [holder], but it does not have a drive slot installed.")) @@ -73,25 +72,35 @@ drive_slot.insert_drive(I, user) return TRUE - if(istype(W, /obj/item/paper)) - var/obj/item/paper/paper = W + if(istype(used_item, /obj/item/disk)) + var/obj/item/disk/disk = used_item + var/obj/item/stock_parts/computer/data_disk_drive/disk_drive = get_component(PART_DSKSLOT) + if(!disk_drive) + to_chat(user, SPAN_WARNING("You try to insert [disk] into [holder], but it does not have a disk slot installed.")) + return TRUE + disk_drive.insert_disk(disk, user) + return TRUE + + if(istype(used_item, /obj/item/paper)) + var/obj/item/paper/paper = used_item if(paper.info) var/obj/item/stock_parts/computer/scanner/scanner = get_component(PART_SCANNER) if(scanner) - scanner.attackby(user, W) + scanner.attackby(user, used_item) return TRUE - if(istype(W, /obj/item/paper) || istype(W, /obj/item/paper_bundle)) + if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/paper_bundle)) var/obj/item/stock_parts/computer/scanner/scanner = get_component(PART_SCANNER) if(scanner) - scanner.attackby(W, user) + scanner.attackby(used_item, user) return TRUE - if(istype(W, /obj/item/aicard)) + if(istype(used_item, /obj/item/aicard)) var/obj/item/stock_parts/computer/ai_slot/ai_slot = get_component(PART_AI) if(ai_slot) - ai_slot.attackby(W, user) + ai_slot.attackby(used_item, user) return TRUE - if(istype(W, /obj/item/stock_parts)) - return try_install_component(user, W) \ No newline at end of file + if(istype(used_item, /obj/item/stock_parts)) + return try_install_component(user, used_item) + return FALSE \ No newline at end of file diff --git a/code/datums/extensions/assembly/assembly_power.dm b/code/datums/extensions/assembly/assembly_power.dm index 26d5feeb2cd9..f336f079f92e 100644 --- a/code/datums/extensions/assembly/assembly_power.dm +++ b/code/datums/extensions/assembly/assembly_power.dm @@ -10,8 +10,8 @@ /datum/extension/assembly/proc/battery_power(var/power_usage = 0) apc_powered = FALSE for(var/obj/item/stock_parts/computer/battery_module/battery_module in parts) - if(battery_module.check_functionality() && battery_module.battery.charge >= power_usage) - battery_module.battery.use(power_usage * CELLRATE) + var/obj/item/cell/battery = battery_module.get_cell() + if(battery_module.check_functionality() && battery?.checked_use(power_usage * CELLRATE)) return TRUE // Tries to use power from APC, if present. @@ -33,9 +33,10 @@ // At this point, we know that APC can power us for this tick. Check if we also need to charge our battery, and then actually use the power. for(var/obj/item/stock_parts/computer/battery_module/battery_module in parts) - if(battery_module.check_functionality() && (battery_module.battery.charge < battery_module.battery.maxcharge) && power_usage > 0) + var/obj/item/cell/battery = battery_module.get_cell() + if(battery_module.check_functionality() && battery && (battery.charge < battery.maxcharge) && power_usage > 0) power_usage += tesla_link.passive_charging_rate - battery_module.battery.give(tesla_link.passive_charging_rate * CELLRATE) + battery.give(tesla_link.passive_charging_rate * CELLRATE) A.use_power_oneoff(power_usage, EQUIP) return TRUE @@ -51,7 +52,7 @@ /datum/extension/assembly/proc/handle_power() last_power_usage = calculate_power_usage() - // First tries to charge from an APC, if APC is unavailable switches to battery power. + // First tries to charge from an APC, if APC is unavailable switches to battery power. // If neither works the computer fails. if(apc_power(last_power_usage)) return if(battery_power(last_power_usage)) return diff --git a/code/datums/extensions/cell/cell.dm b/code/datums/extensions/cell/cell.dm new file mode 100644 index 000000000000..6d35a46581a1 --- /dev/null +++ b/code/datums/extensions/cell/cell.dm @@ -0,0 +1,169 @@ +/datum/extension/loaded_cell + expected_type = /obj/item + base_type = /datum/extension/loaded_cell + VAR_PRIVATE/weakref/loaded_cell_ref + var/load_sound = 'sound/weapons/guns/interaction/energy_magin.ogg' + var/unload_sound = 'sound/weapons/guns/interaction/smg_magout.ogg' + var/requires_tool + var/expected_cell_type = /obj/item/cell/device + var/load_delay = 1 SECOND + var/unload_delay + var/can_modify = TRUE + +/datum/extension/loaded_cell/New(datum/holder, _expected_cell_type, _create_cell_type, _override_cell_capacity) + ..(holder) + if(ispath(_expected_cell_type)) + if(!ispath(_expected_cell_type, /obj/item/cell)) + PRINT_STACK_TRACE("Non-cell type supplied to [type] as expected cell type.") + expected_cell_type = _expected_cell_type + if(ispath(_create_cell_type)) + create_cell(_create_cell_type, _override_cell_capacity) + +/datum/extension/loaded_cell/Destroy() + var/obj/item/cell/existing_cell = loaded_cell_ref?.resolve() + if(istype(existing_cell) && !QDELETED(existing_cell) && existing_cell.loc == holder) + qdel(existing_cell) + return ..() + +/datum/extension/loaded_cell/proc/create_cell(_create_cell_type, _override_cell_capacity) + if(!ispath(_create_cell_type, expected_cell_type)) + PRINT_STACK_TRACE("Non-expected type '[_create_cell_type]' supplied to [type] as premade cell type (expected '[expected_cell_type]').") + loaded_cell_ref = weakref(new _create_cell_type(holder, _override_cell_capacity)) + +/datum/extension/loaded_cell/proc/get_cell() + var/obj/item/cell/cell = loaded_cell_ref?.resolve() + if(istype(cell) && !QDELETED(cell) && cell.loc == holder) + return cell + +/datum/extension/loaded_cell/proc/has_tool_unload_interaction(var/obj/item/tool) + return requires_tool && IS_TOOL(tool, requires_tool) + +/datum/extension/loaded_cell/proc/try_load(var/mob/user, var/obj/item/cell/cell) + + // Check inputs. + var/obj/item/holder_item = holder + if(!istype(cell) || !istype(user) || QDELETED(cell) || QDELETED(user) || user.incapacitated()) + return FALSE + + if(!can_modify) + to_chat(user, SPAN_WARNING("\The [holder] power supply cannot be replaced.")) + return TRUE + + // Check type. + if(!istype(cell, expected_cell_type)) + var/obj/item/expected_cell = expected_cell_type + to_chat(user, SPAN_WARNING("\The [holder] will only accept \a [initial(expected_cell.name)].")) + return TRUE // technically a valid interaction. + + // Check existing cell ref. + var/obj/item/cell/existing_cell = loaded_cell_ref?.resolve() + if(istype(existing_cell) && !QDELETED(existing_cell) && existing_cell.loc == holder) + to_chat(user, SPAN_WARNING("\The [holder] already has \a [existing_cell] loaded.")) + return TRUE // technically a valid interaction. + + // Apply delays. + if(load_delay && !do_after(user, load_delay, holder)) + return FALSE + + // Recheck existing cell ref. + if(!istype(cell) || !istype(user) || QDELETED(cell) || QDELETED(user) || user.incapacitated()) + return FALSE + // Recheck existing cell ref. + existing_cell = loaded_cell_ref?.resolve() + if(istype(existing_cell) && !QDELETED(existing_cell) && existing_cell.loc == holder) + to_chat(user, SPAN_WARNING("\The [holder] already has \a [existing_cell] loaded.")) + return TRUE // technically a valid interaction. + + // Load the cell. + if(user.try_unequip(cell, holder, FALSE)) + user.visible_message(SPAN_NOTICE("\The [user] slots \the [cell] into \the [holder].")) + loaded_cell_ref = weakref(cell) + if(load_sound) + playsound(user.loc, pick(load_sound), 25, 1) + holder_item.update_icon() + return TRUE + return FALSE + +/datum/extension/loaded_cell/proc/try_unload(var/mob/user, var/obj/item/tool) + + // Check inputs. + var/obj/item/holder_item = holder + if(!istype(user) || QDELETED(user) || user.incapacitated()) + return FALSE + + if(!can_modify) + if(tool) + to_chat(user, SPAN_WARNING("\The [holder]'s power supply cannot be removed.")) + return TRUE // Tool interactions should get a warning, inhand interactions should just default to regular attack_hand. + return FALSE + + // Check existing cell. + var/obj/item/cell/existing_cell = loaded_cell_ref?.resolve() + if(!istype(existing_cell) || QDELETED(existing_cell) || existing_cell.loc != holder) + to_chat(user, SPAN_WARNING("\The [holder] has no cell loaded.")) + if(loaded_cell_ref) + loaded_cell_ref = null + holder_item.update_icon() + return TRUE // technically a valid interaction. + + // Apply tool checks. + if(requires_tool) + // No tool provided means we're probably using an empty hand - don't print a warning if it's a tool based removal. + if(!istype(tool) || QDELETED(tool)) + return FALSE + if(!IS_TOOL(tool, requires_tool)) + var/decl/tool_archetype/tool_arch = GET_DECL(requires_tool) + to_chat(user, SPAN_WARNING("\The [holder] requires \a [tool_arch.name] to remove the cell.")) + return TRUE // technically a valid interaction. + if(unload_delay && !tool.do_tool_interaction(requires_tool, user, holder, unload_delay)) + return FALSE + else if(istype(tool)) + return FALSE + // Apply general delay. + else if(unload_delay && !do_after(user, unload_delay, holder)) + return FALSE + + // Recheck inputs. + if(!istype(user) || QDELETED(user) || user.incapacitated()) + return FALSE + // Recheck existing cell. + existing_cell = loaded_cell_ref?.resolve() + if(!istype(existing_cell) || QDELETED(existing_cell) || existing_cell.loc != holder) + to_chat(user, SPAN_WARNING("\The [holder] has no cell loaded.")) + if(loaded_cell_ref) + loaded_cell_ref = null + holder_item.update_icon() + return TRUE // technically a valid interaction. + + // Unload the cell. + user.visible_message( + SPAN_NOTICE("\The [user] removes \the [existing_cell] from \the [holder]."), + SPAN_NOTICE("You remove \the [existing_cell] from \the [holder].") + ) + existing_cell.dropInto(get_turf(holder)) + user.put_in_active_hand(existing_cell) + holder_item.update_icon() + if(unload_sound) + playsound(user.loc, pick(unload_sound), 25, TRUE) + return TRUE + +/datum/extension/loaded_cell/proc/get_examine_text(var/obj/item/cell/current_cell) + . = list() + if(current_cell) + . += SPAN_NOTICE("\The [holder] has \a [current_cell] installed.") + . += SPAN_NOTICE("\The [holder] is [round(current_cell.percent())]% charged.") + if(can_modify) + if(requires_tool) + var/decl/tool_archetype/needed_tool = GET_DECL(requires_tool) + . += SPAN_NOTICE("\The [holder] power supply requires \a [needed_tool.name] to remove.") + else + . += SPAN_NOTICE("Hold \the [holder] in an off-hand and click it with an empty hand to remove the power supply.") + else + . += SPAN_NOTICE("\The [holder] power supply cannot be removed.") + else + var/obj/item/cell = expected_cell_type + . += SPAN_WARNING("\The [holder] has no power source installed.") + if(can_modify) + . += SPAN_NOTICE("\The [holder] is compatible with \a [initial(cell.name)].") + else + . += SPAN_NOTICE("\The [holder] power supply cannot be replaced.") diff --git a/code/datums/extensions/cell/cell_panel.dm b/code/datums/extensions/cell/cell_panel.dm new file mode 100644 index 000000000000..184c1f7e2df6 --- /dev/null +++ b/code/datums/extensions/cell/cell_panel.dm @@ -0,0 +1,20 @@ +/datum/extension/loaded_cell/panel + var/panel_open = FALSE + +// We hook the try_unload() proc to do our panel opening and closing. +/datum/extension/loaded_cell/panel/has_tool_unload_interaction(var/obj/item/tool) + return IS_TOOL(tool, TOOL_SCREWDRIVER) + +/datum/extension/loaded_cell/panel/try_unload(var/mob/user, var/obj/item/tool) + if(!istype(user) || QDELETED(user) || user.incapacitated()) + return FALSE + if(tool) + panel_open = !panel_open + to_chat(user, SPAN_NOTICE("You [panel_open ? "open" : "close"] \the [holder]'s battery compartment.")) + var/obj/item/holder_item = holder + holder_item.update_icon() + return TRUE + return panel_open && ..() + +/datum/extension/loaded_cell/panel/get_examine_text() + . = ..() + SPAN_NOTICE("\The [holder]'s battery compartment is [panel_open ? "open" : "closed"]. Use a screwdriver to [panel_open ? "close" : "open"] it.") diff --git a/code/datums/extensions/cell/cell_secured.dm b/code/datums/extensions/cell/cell_secured.dm new file mode 100644 index 000000000000..5a5e8cf55c1c --- /dev/null +++ b/code/datums/extensions/cell/cell_secured.dm @@ -0,0 +1,4 @@ +// Must be removed with a screwdriver. +/datum/extension/loaded_cell/secured + requires_tool = TOOL_SCREWDRIVER + unload_delay = 1 SECOND diff --git a/code/datums/extensions/cell/cell_unremovable.dm b/code/datums/extensions/cell/cell_unremovable.dm new file mode 100644 index 000000000000..892a8cf5b16f --- /dev/null +++ b/code/datums/extensions/cell/cell_unremovable.dm @@ -0,0 +1,3 @@ +// Cannot be removed or replaced. +/datum/extension/loaded_cell/unremovable + can_modify = FALSE diff --git a/code/datums/extensions/deity_be_near.dm b/code/datums/extensions/deity_be_near.dm deleted file mode 100644 index cd91c53a28b5..000000000000 --- a/code/datums/extensions/deity_be_near.dm +++ /dev/null @@ -1,67 +0,0 @@ -/datum/extension/deity_be_near - base_type = /datum/extension/deity_be_near - expected_type = /obj/item - var/keep_away_instead = FALSE - var/mob/living/deity/connected_deity - var/threshold_base = 6 - var/expected_helmet - flags = EXTENSION_FLAG_IMMEDIATE - -/datum/extension/deity_be_near/New(var/datum/holder, var/mob/living/deity/connect) - ..() - GLOB.moved_event.register(holder,src, .proc/check_movement) - connected_deity = connect - GLOB.destroyed_event.register(holder, src, .proc/dead_deity) - var/obj/O = holder - O.desc += "
    This item deals damage to its wielder the [keep_away_instead ? "closer" : "farther"] it is from a deity structure" - - -/datum/extension/deity_be_near/Destroy() - GLOB.moved_event.unregister(holder,src) - GLOB.destroyed_event.unregister(holder, src) - GLOB.item_equipped_event.unregister(holder, src) - . = ..() - -/datum/extension/deity_be_near/proc/check_movement() - var/obj/item/I = holder - if(!istype(I.loc, /mob/living)) - return - var/min_dist = INFINITY - for(var/s in connected_deity.structures) - var/dist = get_dist(holder,s) - if(dist < min_dist) - min_dist = dist - if(min_dist > threshold_base) - deal_damage(I.loc, round(min_dist/threshold_base)) - else if(keep_away_instead && min_dist < threshold_base) - deal_damage(I.loc, round(threshold_base/min_dist)) - - -/datum/extension/deity_be_near/proc/deal_damage(var/mob/living/victim, var/mult) - return - -/datum/extension/deity_be_near/proc/dead_deity() - var/obj/item/I = holder - I.visible_message("\The [holder]'s power fades!") - qdel(src) - -/datum/extension/deity_be_near/proc/wearing_full() - var/obj/item/I = holder - - if(!ishuman(I.loc)) - return FALSE - var/mob/living/carbon/human/H = I.loc - if(H.get_inventory_slot(I) != slot_wear_suit) - return FALSE - if(expected_helmet && !istype(H.get_equipped_item(slot_head), expected_helmet)) - return FALSE - return TRUE - -/datum/extension/deity_be_near/champion/deal_damage(var/mob/living/victim,var/mult) - victim.adjustOxyLoss(3 * mult) - -/datum/extension/deity_be_near/oracle/deal_damage(var/mob/living/victim, var/mult) - victim.adjustFireLoss(mult) - -/datum/extension/deity_be_near/traitor/deal_damage(var/mob/living/victim, var/mult) - victim.adjustHalLoss(5 * mult) \ No newline at end of file diff --git a/code/datums/extensions/demolisher/_demolisher.dm b/code/datums/extensions/demolisher/_demolisher.dm new file mode 100644 index 000000000000..0b5f4bc8db5a --- /dev/null +++ b/code/datums/extensions/demolisher/_demolisher.dm @@ -0,0 +1,38 @@ +// A subtype for items that can dismantle/demolish non-reinforced non-natural walls. +/datum/extension/demolisher + base_type = /datum/extension/demolisher + expected_type = /obj/item + var/demolish_delay = 6 SECONDS + var/demolish_verb + var/demolish_sound + +/datum/extension/demolisher/New(datum/holder, _delay, _verb, _sound) + . = ..() + if(_delay) + demolish_delay = _delay + if(_verb) + demolish_verb = _verb + if(_sound) + demolish_sound = _sound + +/datum/extension/demolisher/proc/get_demolish_delay(turf/wall/wall) + return demolish_delay + wall?.get_material()?.cut_delay + +/datum/extension/demolisher/proc/get_demolish_verb() + return demolish_verb + +/datum/extension/demolisher/proc/get_demolish_sound() + return demolish_sound + +/datum/extension/demolisher/proc/try_demolish(mob/user, turf/wall/wall) + var/dismantle_verb = get_demolish_verb() + var/dismantle_sound = get_demolish_sound() + to_chat(user, SPAN_NOTICE("You begin [dismantle_verb] \the [wall].")) + if(dismantle_sound) + playsound(wall, dismantle_sound, 100, 1) + var/cut_delay = max(0, get_demolish_delay(wall)) + if(do_after(user, cut_delay, wall)) + to_chat(user, SPAN_NOTICE("You finish [dismantle_verb] \the [wall].")) + user.visible_message(SPAN_DANGER("\The [user] finishes [dismantle_verb] \the [wall]!")) + wall.dismantle_turf() + return TRUE diff --git a/code/datums/extensions/demolisher/delicate.dm b/code/datums/extensions/demolisher/delicate.dm new file mode 100644 index 000000000000..a9f6dbdb543e --- /dev/null +++ b/code/datums/extensions/demolisher/delicate.dm @@ -0,0 +1,13 @@ +/datum/extension/demolisher/delicate + demolish_verb = "dismantling" + demolish_sound = 'sound/items/Crowbar.ogg' + var/alternative_tools = "a sledgehammer or welding torch" // For overriding on medieval maps. + +/datum/extension/demolisher/delicate/try_demolish(mob/user, turf/wall/wall) + if(!(wall.get_material()?.removed_by_welder)) + return ..() + to_chat(user, SPAN_WARNING("\The [wall] is too robust to be dismantled with \the [holder]; try [alternative_tools].")) + return TRUE + +/datum/extension/demolisher/delicate/get_demolish_delay(turf/wall/wall) + return ..() * 1.2 diff --git a/code/datums/extensions/demolisher/energy.dm b/code/datums/extensions/demolisher/energy.dm new file mode 100644 index 000000000000..ff4a7282de67 --- /dev/null +++ b/code/datums/extensions/demolisher/energy.dm @@ -0,0 +1,16 @@ +/datum/extension/demolisher/energy + demolish_sound = "sparks" + demolish_verb = "slicing through" + +/datum/extension/demolisher/energy/try_demolish(mob/user, turf/wall/wall) + var/obj/item/tool = holder + if(!tool.is_special_cutting_tool()) + return FALSE + if(istype(tool, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = tool + if(!cutter.slice(user)) + return TRUE + return ..() + +/datum/extension/demolisher/energy/get_demolish_delay(turf/wall/wall) + return ..() * 0.5 diff --git a/code/datums/extensions/demolisher/pick.dm b/code/datums/extensions/demolisher/pick.dm new file mode 100644 index 000000000000..5b48b14b6efc --- /dev/null +++ b/code/datums/extensions/demolisher/pick.dm @@ -0,0 +1,22 @@ +/datum/extension/demolisher/pick + demolish_verb = "dismantling" + demolish_sound = 'sound/items/Crowbar.ogg' + +/datum/extension/demolisher/pick/try_demolish(mob/user, turf/wall/wall) + var/obj/item/pick = holder + if(pick.material?.hardness < wall.get_material()?.hardness) + to_chat(user, SPAN_WARNING("\The [holder] is not hard enough to cut through [wall.get_material().solid_name].")) + return TRUE + return ..() + +/datum/extension/demolisher/pick/get_demolish_delay(turf/wall/wall) + var/obj/item/pick = holder + return pick.get_expected_tool_use_delay(TOOL_PICK, ..()) + +/datum/extension/demolisher/pick/get_demolish_verb() + var/obj/item/pick = holder + return pick.get_tool_message(TOOL_PICK) + +/datum/extension/demolisher/pick/get_demolish_sound() + var/obj/item/pick = holder + return pick.get_tool_sound(TOOL_PICK) diff --git a/code/datums/extensions/demolisher/welder.dm b/code/datums/extensions/demolisher/welder.dm new file mode 100644 index 000000000000..b6a43fc85b07 --- /dev/null +++ b/code/datums/extensions/demolisher/welder.dm @@ -0,0 +1,16 @@ +/datum/extension/demolisher/welder + demolish_verb = "cutting through" + demolish_sound = 'sound/items/Welder.ogg' + expected_type = /obj/item/weldingtool + +/datum/extension/demolisher/welder/try_demolish(mob/user, turf/wall/wall) + if(!(wall.get_material()?.removed_by_welder)) + to_chat(user, SPAN_WARNING("\The [wall] is too delicate to be dismantled with \the [holder]; try a hammer or crowbar.")) + return TRUE + var/obj/item/weldingtool/welder = holder + if(welder.weld(0,user)) + return ..() + return TRUE + +/datum/extension/demolisher/welder/get_demolish_delay(turf/wall/wall) + return ..() * 0.7 diff --git a/code/datums/extensions/event_registration.dm b/code/datums/extensions/event_registration.dm index e410a866d943..b483bd79a250 100644 --- a/code/datums/extensions/event_registration.dm +++ b/code/datums/extensions/event_registration.dm @@ -10,14 +10,14 @@ /datum/extension/event_registration/New(datum/holder, decl/observ/event, datum/target, callproc) ..() - event.register(target, src, .proc/trigger) - GLOB.destroyed_event.register(target, src, .proc/qdel_self) + event.register(target, src, PROC_REF(trigger)) + events_repository.register(/decl/observ/destroyed, target, src, PROC_REF(qdel_self)) src.event = event src.target = target src.callproc = callproc /datum/extension/event_registration/Destroy() - GLOB.destroyed_event.unregister(target, src) + events_repository.unregister(/decl/observ/destroyed, target, src) event.unregister(target, src) . = ..() @@ -36,32 +36,32 @@ ..() src.given_area = given_area register_shuttles() - GLOB.shuttle_added.register_global(src, .proc/shuttle_added) + events_repository.register_global(/decl/observ/shuttle_added, src, PROC_REF(shuttle_added)) /datum/extension/event_registration/shuttle_stationary/proc/register_shuttles() if(given_area in SSshuttle.shuttle_areas) for(var/shuttle_name in SSshuttle.shuttles) var/datum/shuttle/shuttle_datum = SSshuttle.shuttles[shuttle_name] if(given_area in shuttle_datum.shuttle_area) - GLOB.shuttle_moved_event.register(shuttle_datum, src, .proc/shuttle_moved) - GLOB.shuttle_pre_move_event.register(shuttle_datum, src, .proc/shuttle_pre_move) + events_repository.register(/decl/observ/shuttle_moved, shuttle_datum, src, PROC_REF(shuttle_moved)) + events_repository.register(/decl/observ/shuttle_pre_move, shuttle_datum, src, PROC_REF(shuttle_pre_move)) LAZYADD(shuttles_registered, shuttle_datum) /datum/extension/event_registration/shuttle_stationary/proc/unregister_shuttles() for(var/datum/shuttle_datum in shuttles_registered) - GLOB.shuttle_moved_event.unregister(shuttle_datum, src) - GLOB.shuttle_pre_move_event.unregister(shuttle_datum, src) + events_repository.unregister(/decl/observ/shuttle_moved, shuttle_datum, src) + events_repository.unregister(/decl/observ/shuttle_pre_move, shuttle_datum, src) shuttles_registered = null /datum/extension/event_registration/shuttle_stationary/proc/shuttle_added(datum/shuttle/shuttle) if(given_area in shuttle.shuttle_area) - GLOB.shuttle_moved_event.register(shuttle, src, .proc/shuttle_moved) - GLOB.shuttle_pre_move_event.register(shuttle, src, .proc/shuttle_pre_move) + events_repository.register(/decl/observ/shuttle_moved, shuttle, src, PROC_REF(shuttle_moved)) + events_repository.register(/decl/observ/shuttle_pre_move, shuttle, src, PROC_REF(shuttle_pre_move)) LAZYADD(shuttles_registered, shuttle) /datum/extension/event_registration/shuttle_stationary/Destroy() unregister_shuttles() - GLOB.shuttle_added.unregister_global(src) + events_repository.unregister_global(/decl/observ/shuttle_added, src) . = ..() /datum/extension/event_registration/shuttle_stationary/proc/shuttle_moved() diff --git a/code/datums/extensions/extensions.dm b/code/datums/extensions/extensions.dm index 6e63fa44084a..ab28746a5581 100644 --- a/code/datums/extensions/extensions.dm +++ b/code/datums/extensions/extensions.dm @@ -9,34 +9,66 @@ CRASH("Invalid holder type. Expected [expected_type], was [holder.type]") src.holder = holder +/datum/extension/proc/post_construction() + /datum/extension/Destroy() holder = null . = ..() +///Extensions can't be cloned from a Clone() call, because they need a holder on New, and cannot be cloned onto the same object. +/// Use copy_from instead! +/datum/extension/CanClone() + return FALSE + +/datum/extension/Clone() + SHOULD_CALL_PARENT(FALSE) + CRASH("Use 'copy_from()' on a new extension instance instead of using Clone()! Extensions cannot be created without a holder.") + +///Workaround for extensions not supporting Clone(). Copy data from another extension, so we're essentially a clone of that other extension. +/datum/extension/proc/copy_from(var/datum/extension/source) + SHOULD_CALL_PARENT(TRUE) + //Make sure our types are compatible + if(!istype(src, source.type)) + CRASH("Tried to copy extension data from a different extension type! source: [source.type], destination: [type].") + + if(isnull(holder)) + CRASH("Extension [type] must have a holder set before calling copy_from()!") + + //Use the standard clone proc populate here for coherence + source.PopulateClone(src) + /datum - var/list/datum/extension/extensions + /// A lazy alist() keyed by extension base type. Values are either a list of extension init arguments for lazy-loaded extensions, or an extension datum. + var/alist/extensions //Variadic - Additional positional arguments can be given. Named arguments might not work so well /proc/set_extension(var/datum/source, var/datum/extension/extension_type) + if(QDELETED(source)) + CRASH("Invalid extension source datum: source was qdeleted, was [log_info_line(source)]") var/datum/extension/extension_base_type = initial(extension_type.base_type) if(!ispath(extension_base_type, /datum/extension)) CRASH("Invalid base type: Expected /datum/extension, was [log_info_line(extension_base_type)]") if(!ispath(extension_type, extension_base_type)) CRASH("Invalid extension type: Expected [extension_base_type], was [log_info_line(extension_type)]") - if(!source.extensions) - source.extensions = list() + A_LAZYINITLIST(source.extensions) var/datum/extension/existing_extension = source.extensions[extension_base_type] if(istype(existing_extension)) qdel(existing_extension) if(initial(extension_base_type.flags) & EXTENSION_FLAG_IMMEDIATE) - . = construct_extension_instance(extension_type, source, args.Copy(3)) - source.extensions[extension_base_type] = . - else - var/list/extension_data = list(extension_type, source) - if(args.len > 2) - extension_data += args.Copy(3) - source.extensions[extension_base_type] = extension_data + var/list/construct_args = args.Copy(3) + var/datum/extension/created = construct_extension_instance(extension_type, source, construct_args) + source.extensions[extension_base_type] = created + if(length(construct_args)) + created.post_construction(arglist(construct_args)) + else + created.post_construction() + return created + + var/list/extension_data = list(extension_type, source) + if(args.len > 2) + extension_data += args.Copy(3) + source.extensions[extension_base_type] = extension_data /proc/get_or_create_extension(var/datum/source, var/datum/extension/extension_type) var/base_type = initial(extension_type.base_type) @@ -45,6 +77,15 @@ return get_extension(source, base_type) /proc/get_extension(var/datum/source, var/base_type) + // Invalid holder datum. + if(!istype(source)) + PRINT_STACK_TRACE("Invalid source provided to get_extension(): [source || "null"]") + return + // Invalid extension type. + if(!ispath(base_type, /datum/extension)) + PRINT_STACK_TRACE("Invalid base_type provided to get_extension(): [base_type || "null"]") + return + // Return early if we have no extensions whatsoever. if(!source.extensions) return . = source.extensions[base_type] @@ -52,20 +93,47 @@ return if(islist(.)) //a list, so it's expecting to be lazy-loaded var/list/extension_data = . - . = construct_extension_instance(extension_data[1], extension_data[2], extension_data.Copy(3)) - source.extensions[base_type] = . + var/list/construct_args = extension_data.Copy(3) + var/datum/extension/created = construct_extension_instance(extension_data[1], extension_data[2], construct_args) + source.extensions[base_type] = created + if(length(construct_args)) + created.post_construction(arglist(construct_args)) + else + created.post_construction() + return created //Fast way to check if it has an extension, also doesn't trigger instantiation of lazy loaded extensions /proc/has_extension(var/datum/source, var/base_type) - return !!(source.extensions && source.extensions[base_type]) + return !!source.extensions?[base_type] /proc/construct_extension_instance(var/extension_type, var/datum/source, var/list/arguments) arguments = list(source) + arguments return new extension_type(arglist(arguments)) /proc/remove_extension(var/datum/source, var/base_type) - if(!source.extensions || !source.extensions[base_type]) + if(!source.extensions?[base_type]) return if(!islist(source.extensions[base_type])) qdel(source.extensions[base_type]) - LAZYREMOVE(source.extensions, base_type) \ No newline at end of file + A_LAZYREMOVE(source.extensions, base_type) + +///Copy the extension instance on the 'source' and put it on the 'destination'. +/proc/copy_extension(var/datum/source, var/datum/destination, var/base_type) + if(!istype(source) || !istype(destination)) + CRASH("Tried to copy extension to or from invalid datums. source: [source], destination: [destination]") + + //Get and validate the source + var/datum/extension/SE = get_extension(source, base_type) + if(isnull(SE)) + return //This is a valid case, and we just have nothing to copy + if(!istype(destination, SE.expected_type)) + CRASH("Tried to copy extension [SE] type to an unexpected type [destination.type]") + + //Get and fill the destination + var/datum/extension/DE = get_or_create_extension(destination, base_type) + + //Copy data over from the other extension + DE.copy_from(SE) + + //Return the copied extension + return DE \ No newline at end of file diff --git a/code/datums/extensions/eye/_eye.dm b/code/datums/extensions/eye/_eye.dm index 66cac4a4e2d7..92f340dfcf9d 100644 --- a/code/datums/extensions/eye/_eye.dm +++ b/code/datums/extensions/eye/_eye.dm @@ -21,7 +21,7 @@ /datum/extension/eye/proc/look(var/mob/new_looker, var/list/eye_args) if(new_looker.eyeobj || current_looker) return FALSE - + LAZYINSERT(eye_args, get_turf(new_looker), 1) // Make sure that a loc is provided to the eye. if(!extension_eye) @@ -43,27 +43,29 @@ unlook_action.Grant(current_looker) // Checks for removing the user from the eye outside of unlook actions. - GLOB.moved_event.register(holder, src, /datum/extension/eye/proc/unlook) - GLOB.moved_event.register(current_looker, src, /datum/extension/eye/proc/unlook) + events_repository.register(/decl/observ/moved, holder, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + events_repository.register(/decl/observ/moved, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) - GLOB.destroyed_event.register(current_looker, src, /datum/extension/eye/proc/unlook) - GLOB.destroyed_event.register(extension_eye, src, /datum/extension/eye/proc/unlook) + events_repository.register(/decl/observ/destroyed, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + events_repository.register(/decl/observ/destroyed, extension_eye, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) - GLOB.stat_set_event.register(current_looker, src, /datum/extension/eye/proc/unlook) - GLOB.logged_out_event.register(current_looker, src, /datum/extension/eye/proc/unlook) + if(isliving(current_looker)) + events_repository.register(/decl/observ/stat_set, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + events_repository.register(/decl/observ/logged_out, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) return TRUE /datum/extension/eye/proc/unlook() - GLOB.moved_event.unregister(holder, src, /datum/extension/eye/proc/unlook) - GLOB.moved_event.unregister(current_looker, src, /datum/extension/eye/proc/unlook) - - GLOB.destroyed_event.unregister(current_looker, src, /datum/extension/eye/proc/unlook) - GLOB.destroyed_event.unregister(extension_eye, src, /datum/extension/eye/proc/unlook) + events_repository.unregister(/decl/observ/moved, holder, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + events_repository.unregister(/decl/observ/moved, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + + events_repository.unregister(/decl/observ/destroyed, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + events_repository.unregister(/decl/observ/destroyed, extension_eye, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) - GLOB.stat_set_event.unregister(current_looker, src, /datum/extension/eye/proc/unlook) - GLOB.logged_out_event.unregister(current_looker, src, /datum/extension/eye/proc/unlook) + if(isliving(current_looker)) + events_repository.unregister(/decl/observ/stat_set, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) + events_repository.unregister(/decl/observ/logged_out, current_looker, src, TYPE_PROC_REF(/datum/extension/eye, unlook)) QDEL_NULL(extension_eye) @@ -96,10 +98,11 @@ /datum/action/eye/CheckRemoval(mob/living/user) if(!user.eyeobj || !istype(user.eyeobj, eye_type)) return TRUE + return ..() // Every eye created using a subtype of this extension will have this action added for manual unlooking. /datum/action/eye/unlook name = "Stop looking" - procname = "unlook" + procname = TYPE_PROC_REF(/datum/extension/eye, unlook) button_icon_state = "cancel" target_type = EXTENSION_TARGET diff --git a/code/datums/extensions/eye/blueprints.dm b/code/datums/extensions/eye/blueprints.dm index 3d6f35616dac..967705c86f48 100644 --- a/code/datums/extensions/eye/blueprints.dm +++ b/code/datums/extensions/eye/blueprints.dm @@ -9,24 +9,29 @@ /datum/action/eye/blueprints/mark_new_area name = "Mark new area" - procname = "create_area" + procname = TYPE_PROC_REF(/mob/observer/eye/blueprints, create_area) button_icon_state = "pencil" target_type = EYE_TARGET /datum/action/eye/blueprints/remove_selection name = "Remove selection" - procname = "remove_selection" + procname = TYPE_PROC_REF(/mob/observer/eye/blueprints, remove_selection) button_icon_state = "eraser" target_type = EYE_TARGET /datum/action/eye/blueprints/edit_area name = "Edit area" - procname = "edit_area" + procname = TYPE_PROC_REF(/mob/observer/eye/blueprints, edit_area) button_icon_state = "edit_area" target_type = EYE_TARGET /datum/action/eye/blueprints/remove_area name = "Remove area" - procname = "remove_area" + procname = TYPE_PROC_REF(/mob/observer/eye/blueprints, remove_area) button_icon_state = "remove_area" - target_type = EYE_TARGET \ No newline at end of file + target_type = EYE_TARGET + +// Shuttle blueprints subtype (handles shuttle.shuttle_area) +/datum/extension/eye/blueprints/shuttle + expected_type = /obj/item/blueprints/shuttle + eye_type = /mob/observer/eye/blueprints/shuttle \ No newline at end of file diff --git a/code/datums/extensions/eye/landing.dm b/code/datums/extensions/eye/landing.dm index 5cb9413d539a..deaa8dafc8d2 100644 --- a/code/datums/extensions/eye/landing.dm +++ b/code/datums/extensions/eye/landing.dm @@ -4,11 +4,35 @@ action_type = /datum/action/eye/landing +/datum/extension/eye/landing/get_eye_turf() + var/turf/eye_turf = ..() + var/mob/observer/eye/landing/landing_eye = extension_eye + + return locate(eye_turf.x + landing_eye.x_offset, eye_turf.y + landing_eye.y_offset, eye_turf.z) + /datum/action/eye/landing eye_type = /mob/observer/eye/landing /datum/action/eye/landing/finish_landing name = "Set landing location" - procname = "finish_landing" + procname = TYPE_PROC_REF(/obj/machinery/computer/shuttle_control/explore, finish_landing) button_icon_state = "shuttle_land" - target_type = HOLDER_TARGET \ No newline at end of file + target_type = HOLDER_TARGET + +/datum/action/eye/landing/toggle_offsetting + name = "Offset landing location" + procname = TYPE_PROC_REF(/mob/observer/eye/landing, toggle_offsetting) + button_icon_state = "shuttle_offset" + target_type = EYE_TARGET + +/datum/action/eye/landing/rotate_cw + name = "Rotate clockwise" + procname = TYPE_PROC_REF(/mob/observer/eye/landing, turn_shuttle_cw) + button_icon_state = "shuttle_rotate_cw" + target_type = EYE_TARGET + +/datum/action/eye/landing/rotate_ccw + name = "Rotate counterclockwise" + procname = TYPE_PROC_REF(/mob/observer/eye/landing, turn_shuttle_ccw) + button_icon_state = "shuttle_rotate_ccw" + target_type = EYE_TARGET \ No newline at end of file diff --git a/code/datums/extensions/hattable.dm b/code/datums/extensions/hattable.dm deleted file mode 100644 index 95d6c46b72b5..000000000000 --- a/code/datums/extensions/hattable.dm +++ /dev/null @@ -1,38 +0,0 @@ -var/list/mob_hat_cache = list() - -// Note that humans handle hats on their own without this extension. -// This is primarily for diona nymphs and maintenance drones. -/datum/extension/hattable - base_type = /datum/extension/hattable - flags = EXTENSION_FLAG_IMMEDIATE - var/offset_x = 0 - var/offset_y = 0 - var/obj/item/hat - -/datum/extension/hattable/New(var/datum/holder, var/new_offset_x, var/new_offset_y) - if(!isnull(new_offset_x)) - offset_x = new_offset_x - if(!isnull(new_offset_y)) - offset_y = new_offset_y - ..() - -/datum/extension/hattable/proc/wear_hat(var/mob/wearer, var/obj/item/clothing/head/new_hat) - if(hat || !new_hat) - return FALSE - hat = new_hat - hat.forceMove(wearer) - hat.equipped(wearer) - wearer.update_icons() - return TRUE - -/datum/extension/hattable/proc/get_hat_overlay(var/mob/wearer) - var/image/I = hat?.get_mob_overlay(wearer, slot_head_str) - if(I) - I.pixel_x += offset_x - I.pixel_y += offset_y - return I - -/datum/extension/hattable/proc/drop_hat(var/mob/wearer) - wearer.remove_from_mob(hat) - hat = null - wearer.update_icons() diff --git a/code/datums/extensions/holster/holster.dm b/code/datums/extensions/holster/holster.dm index 0f0e5afc634b..569ca88bdb13 100644 --- a/code/datums/extensions/holster/holster.dm +++ b/code/datums/extensions/holster/holster.dm @@ -1,7 +1,7 @@ /datum/extension/holster base_type = /datum/extension/holster var/atom/atom_holder - var/obj/item/storage/storage + var/datum/storage/storage var/sound_in = 'sound/effects/holster/holsterin.ogg' var/sound_out = 'sound/effects/holster/holsterout.ogg' var/list/can_holster = null @@ -33,7 +33,7 @@ /datum/extension/holster/proc/holster(var/obj/item/I, var/mob/living/user) if(!storage) return 1 - if(!holstered && storage.storage_slots != null && storage.contents.len >= storage.storage_slots - 1) + if(!holstered && storage.storage_slots != null && length(storage.get_contents()) >= storage.storage_slots - 1) if(!can_holster(I)) to_chat(user, "\The [I] won't fit in \the [atom_holder]'s holster!.") return 1 @@ -46,40 +46,43 @@ if(istype(user)) user.stop_aiming(no_message=1) holstered = I - storage.handle_item_insertion(holstered, 1) + storage.handle_item_insertion(user, holstered, 1) holstered.add_fingerprint(user) - storage.w_class = max(storage.w_class, holstered.w_class) + holstered.add_fibers(atom_holder) + if(isobj(storage?.holder)) + var/obj/obj_holder = storage.holder + obj_holder.w_class = max(obj_holder.w_class, holstered.w_class) user.visible_message("\The [user] holsters \the [holstered].", "You holster \the [holstered].") atom_holder.SetName("occupied [initial(atom_holder.name)]") atom_holder.update_icon() - GLOB.moved_event.register(holstered, src, .proc/check_holster) - GLOB.destroyed_event.register(holstered, src, .proc/clear_holster) + events_repository.register(/decl/observ/moved, holstered, src, PROC_REF(check_holster)) + events_repository.register(/decl/observ/destroyed, holstered, src, PROC_REF(clear_holster)) return 1 return 0 /datum/extension/holster/proc/clear_holster() - GLOB.moved_event.unregister(holstered, src, .proc/check_holster) - GLOB.destroyed_event.unregister(holstered, src, .proc/clear_holster) + events_repository.unregister(/decl/observ/moved, holstered, src, PROC_REF(check_holster)) + events_repository.unregister(/decl/observ/destroyed, holstered, src, PROC_REF(clear_holster)) holstered = null atom_holder.SetName(initial(atom_holder.name)) /datum/extension/holster/proc/unholster(mob/user, var/avoid_intent = FALSE) if(!holstered) return 0 - if(user.get_active_hand() && user.get_inactive_hand()) - to_chat(user, "You need an empty hand to draw \the [holstered]!") + if(!user.get_empty_hand_slot()) + to_chat(user, SPAN_WARNING("You need an empty hand to draw \the [holstered]!")) return 1 - var/using_intent_preference = user.client ? user.client.get_preference_value(/datum/client_preference/holster_on_intent) == GLOB.PREF_YES : FALSE - if(avoid_intent || (using_intent_preference && user.a_intent != I_HELP)) + var/using_intent_preference = user.client ? user.client.get_preference_value(/datum/client_preference/holster_on_intent) == PREF_YES : FALSE + if(avoid_intent || (using_intent_preference && !user.check_intent(I_FLAG_HELP))) var/sound_vol = 25 - if(user.a_intent == I_HURT) + if(user.check_intent(I_FLAG_HARM)) sound_vol = 50 if(istype(holstered, /obj/item/gun)) var/obj/item/gun/G = holstered G.check_accidents(user) if(G.safety() && !user.skill_fail_prob(SKILL_WEAPONS, 100, SKILL_EXPERT, 0.5)) //Experienced shooter will disable safety before shooting. G.toggle_safety(user) - usr.visible_message( + user.visible_message( "\The [user] draws \the [holstered], ready to go!", "You draw \the [holstered], ready to go!" ) @@ -93,7 +96,10 @@ holstered.add_fingerprint(user) holstered.queue_icon_update() user.put_in_hands(holstered) - storage.w_class = initial(storage.w_class) + holstered = null + if(isobj(storage?.holder)) + var/obj/obj_holder = storage.holder + obj_holder.w_class = initial(obj_holder.w_class) atom_holder.update_icon() return 1 return 0 @@ -105,7 +111,7 @@ to_chat(user, "It is empty.") /datum/extension/holster/proc/check_holster() - if(holstered.loc != storage) + if(holstered.loc != storage.holder) clear_holster() /atom/proc/holster_verb(var/holster_name in get_holsters()) @@ -116,25 +122,25 @@ if(usr.incapacitated()) return - var/datum/extension/holster/H = get_holsters()[holster_name] - if(!H) + var/datum/extension/holster/holster = get_holsters()[holster_name] + if(!holster) return - if(!H.holstered) - var/obj/item/W = usr.get_active_hand() - if(!istype(W, /obj/item)) + if(!holster.holstered) + var/obj/item/holding = usr.get_active_held_item() + if(!istype(holding, /obj/item)) to_chat(usr, "You're not holding anything to holster.") return - H.holster(W, usr) + holster.holster(holding, usr) else - H.unholster(usr, 1) + holster.unholster(usr, 1) /atom/proc/get_holsters() . = list() if(has_extension(src, /datum/extension/holster)) .[name] = get_extension(src, /datum/extension/holster) -/obj/item/clothing/under/get_holsters() +/obj/item/clothing/get_holsters() . = ..() var/holster_accessories_by_name = list() for(var/obj/accessory in accessories) @@ -148,4 +154,63 @@ else for(var/i = 1 to holster_accessories.len) var/holster_name = "[accessory_name] [i]" - .[holster_name] = get_extension(holster_accessories[i], /datum/extension/holster) \ No newline at end of file + .[holster_name] = get_extension(holster_accessories[i], /datum/extension/holster) + +// Basic unholster for an item at the top level. +/decl/interaction_handler/unholster + name = "Unholster" + +/decl/interaction_handler/unholster/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && !prop + if(.) + var/datum/extension/holster/holster = get_extension(target, /datum/extension/holster) + return !!holster?.holstered + +/decl/interaction_handler/unholster/invoked(atom/target, mob/user, obj/item/prop) + var/datum/extension/holster/holster = get_extension(target, /datum/extension/holster) + return holster?.unholster(user, avoid_intent = TRUE) + +// Interaction procs for getting this interaction for basic items. +/obj/item/get_quick_interaction_handler(mob/user) + if(!(. = ..())) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster?.holstered) + return GET_DECL(/decl/interaction_handler/unholster) + +// More complex version of the above that iterates clothing accessories. +/decl/interaction_handler/unholster_accessory + name = "Unholster From Accessory" + expected_target_type = /obj/item/clothing + +/decl/interaction_handler/unholster_accessory/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && !prop + if(.) + var/obj/item/clothing/clothes = target + for(var/obj/item/thing in clothes.accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.holstered) + return TRUE + return FALSE + +/decl/interaction_handler/unholster_accessory/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/clothing/clothes = target + for(var/obj/item/thing in clothes.accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.unholster(user, avoid_intent = TRUE)) + return TRUE + return FALSE + +// Interaction procs for getting this interaction for clothing accessories. +/obj/item/clothing/get_alt_interactions(mob/user) + . = ..() + for(var/obj/item/thing in accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.holstered) + LAZYADD(., GET_DECL(/decl/interaction_handler/unholster_accessory)) + +/obj/item/clothing/get_quick_interaction_handler(mob/user) + if(!(. = ..())) + for(var/obj/item/thing in accessories) + var/datum/extension/holster/holster = get_extension(thing, /datum/extension/holster) + if(holster?.holstered) + return GET_DECL(/decl/interaction_handler/unholster_accessory) diff --git a/code/datums/extensions/interactive.dm b/code/datums/extensions/interactive.dm index ae74d78fdf8d..c6036f0b2ae0 100644 --- a/code/datums/extensions/interactive.dm +++ b/code/datums/extensions/interactive.dm @@ -22,7 +22,7 @@ return STATUS_CLOSE if(!all_predicates_true(list(user), user_predicates)) return STATUS_CLOSE - if(holder.CanUseTopic(user, GLOB.default_state) != STATUS_INTERACTIVE) + if(holder.CanUseTopic(user, global.default_topic_state) != STATUS_INTERACTIVE) return STATUS_CLOSE return STATUS_INTERACTIVE diff --git a/code/datums/extensions/label.dm b/code/datums/extensions/label.dm index 96333df2d283..752f3587cac1 100644 --- a/code/datums/extensions/label.dm +++ b/code/datums/extensions/label.dm @@ -20,12 +20,14 @@ atom_holder.verbs += /atom/proc/RemoveLabel LAZYADD(labels, label) - user.visible_message("\The [user] attaches a label to \the [atom_holder].", \ - "You attach a label, '[label]', to \the [atom_holder].") + if(user) + user.visible_message(SPAN_NOTICE("\The [user] attaches a label to \the [atom_holder]."), \ + SPAN_NOTICE("You attach a label, '[label]', to \the [atom_holder].")) var/old_name = atom_holder.name atom_holder.name = "[atom_holder.name] ([label])" - GLOB.name_set_event.raise_event(src, old_name, atom_holder.name) + RAISE_EVENT(/decl/observ/name_set, src, old_name, atom_holder.name) + return TRUE /datum/extension/labels/proc/RemoveLabel(var/mob/user, var/label) if(!(label in labels)) @@ -40,13 +42,21 @@ if(!index) // Playing it safe, something might not have set the name properly return - user.visible_message("\The [user] removes a label from \the [atom_holder].", \ - "You remove a label, '[label]', from \the [atom_holder].") + if(user) + user.visible_message(SPAN_NOTICE("\The [user] removes a label from \the [atom_holder]."), \ + SPAN_NOTICE("You remove a label, '[label]', from \the [atom_holder].")) var/old_name = atom_holder.name // We find and replace the first instance, since that's the one we removed from the list atom_holder.name = replacetext(atom_holder.name, full_label, "", index, index + length(full_label)) - GLOB.name_set_event.raise_event(src, old_name, atom_holder.name) + RAISE_EVENT(/decl/observ/name_set, src, old_name, atom_holder.name) + return TRUE + +/datum/extension/labels/proc/RemoveAllLabels() + . = TRUE + for(var/lbl in labels) + if(!RemoveLabel(null, lbl)) + . = FALSE // We may have to do something more complex here // in case something appends strings to something that's labelled rather than replace the name outright @@ -73,7 +83,13 @@ . += length(entry) + 3 . = . > 64 ? TRUE : FALSE if(. && user) - to_chat(user, "The label won't fit.") + to_chat(user, SPAN_WARNING("The label won't fit.")) + +/datum/extension/labels/PopulateClone(datum/extension/labels/clone) + var/datum/extension/labels/populated_clone = ..() + for(var/L in labels) + populated_clone.AttachLabel(null, L) + return populated_clone /proc/get_attached_labels(var/atom/source) if(has_extension(source, /datum/extension/labels)) @@ -91,4 +107,10 @@ if(CanPhysicallyInteract(usr)) if(has_extension(src, /datum/extension/labels)) var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) - L.RemoveLabel(usr, label) \ No newline at end of file + L.RemoveLabel(usr, label) + +//Single label allowed for this one +/datum/extension/labels/single/CanAttachLabel(user, label) + if(LAZYLEN(labels) >= 1) //Only allow a single label + return FALSE + . = ..() diff --git a/code/datums/extensions/local_network.dm b/code/datums/extensions/local_network.dm index 846332a2aba5..07798d3c6cb7 100644 --- a/code/datums/extensions/local_network.dm +++ b/code/datums/extensions/local_network.dm @@ -1,6 +1,11 @@ /datum/extension/local_network_member base_type = /datum/extension/local_network_member var/id_tag + var/unique = FALSE // If set to true, other objects of the same type cannot be added to the local network + +/datum/extension/local_network_member/New(datum/holder, is_unique = FALSE) + unique = is_unique + . = ..() /datum/extension/local_network_member/Destroy() if(holder) @@ -15,19 +20,22 @@ return FALSE if(id_tag) - var/datum/local_network/old_lan = GLOB.local_networks[id_tag] + var/datum/local_network/old_lan = global.local_networks[id_tag] if(old_lan) if(!old_lan.remove_device(holder)) to_chat(user, SPAN_WARNING("You encounter an error when trying to unregister \the [holder] from the [id_tag] local network.")) return FALSE to_chat(user, SPAN_NOTICE("You unregister \the [holder] from the [id_tag] local network.")) - var/datum/local_network/lan = GLOB.local_networks[new_ident] + var/datum/local_network/lan = global.local_networks[new_ident] if(!lan) lan = new(new_ident) lan.add_device(holder) to_chat(user, SPAN_NOTICE("You create a new [new_ident] local network and register \the [holder] with it.")) else if(lan.within_radius(holder)) + if(unique && length(lan.network_entities[holder.type])) + to_chat(user, SPAN_WARNING("\A [holder] is already registered to the local network.")) + return FALSE lan.add_device(holder) to_chat(user, SPAN_NOTICE("You register \the [holder] with the [new_ident] local network.")) else @@ -37,7 +45,7 @@ return TRUE /datum/extension/local_network_member/proc/get_local_network() - var/datum/local_network/lan = id_tag ? GLOB.local_networks[id_tag] : null + var/datum/local_network/lan = id_tag ? global.local_networks[id_tag] : null if(lan && !lan.within_radius(holder)) lan.remove_device(holder) id_tag = null @@ -62,19 +70,22 @@ return FALSE if(id_tag) - var/datum/local_network/multilevel/old_lan = GLOB.multilevel_local_networks[id_tag] + var/datum/local_network/multilevel/old_lan = global.multilevel_local_networks[id_tag] if(old_lan) if(!old_lan.remove_device(holder)) to_chat(user, SPAN_WARNING("You encounter an error when trying to unregister \the [holder] from the [id_tag] local network.")) return FALSE to_chat(user, SPAN_NOTICE("You unregister \the [holder] from the [id_tag] local network.")) - var/datum/local_network/multilevel/lan = GLOB.multilevel_local_networks[new_ident] + var/datum/local_network/multilevel/lan = global.multilevel_local_networks[new_ident] if(!lan) lan = new(new_ident) lan.add_device(holder) to_chat(user, SPAN_NOTICE("You create a new [new_ident] local network and register \the [holder] with it.")) else if(lan.within_radius(holder)) + if(unique && length(lan.network_entities[holder.type])) + to_chat(user, SPAN_WARNING("\A [holder] is already registered to the local network.")) + return FALSE lan.add_device(holder) to_chat(user, SPAN_NOTICE("You register \the [holder] with the [new_ident] local network.")) else @@ -84,7 +95,7 @@ return TRUE /datum/extension/local_network_member/multilevel/get_local_network() - var/datum/local_network/multilevel/lan = id_tag ? GLOB.multilevel_local_networks[id_tag] : null + var/datum/local_network/multilevel/lan = id_tag ? global.multilevel_local_networks[id_tag] : null if(lan && !lan.within_radius(holder)) lan.remove_device(holder) id_tag = null diff --git a/code/datums/extensions/lockable.dm b/code/datums/extensions/lockable.dm index 14ff3516d6eb..12fd928839ba 100644 --- a/code/datums/extensions/lockable.dm +++ b/code/datums/extensions/lockable.dm @@ -1,33 +1,295 @@ +/**Sent by the lockable when it's been locked or unlocked. */ +/decl/observ/lock_state_changed + name = "lockable state changed" + +/**Sent by lockable when the service panel is opened/closed. */ +/decl/observ/lock_panel_state_changed + name = "lockable panel state changed" + +/decl/observ/keypad_pressed + name = "lockable keypad pressed" + +/** + Extension for giving an object a code lock, with it's own ui. + */ /datum/extension/lockable - base_type = /datum/extension/lockable + base_type = /datum/extension/lockable expected_type = /obj/item - flags = EXTENSION_FLAG_IMMEDIATE - // Configuration variables - var/max_code_length = 5 // Max length of the password. - - // Stateful variables - var/locked = TRUE // Is it locked? - var/code // The passcode currently inputed. - var/l_code // The actual code of the lock - var/l_set = FALSE // Whether or not the lock has been set. - var/l_setshort = FALSE // Whether or not the ability to set the lock is broken. - var/l_hacking = FALSE // Whether or not the lock is being hacked. - var/emagged = FALSE // What or not the lock is emagged. - var/is_digital_lock = FALSE // Whether or not the lock is digital, and its ability to be brute forced. - var/open = FALSE // Whether or not the lock panel is open. - var/error // Any errors from user input. Temporary. - -/datum/extension/lockable/New(holder, var/is_digital = FALSE) + flags = EXTENSION_FLAG_IMMEDIATE + + /// Max length of the password. + var/max_code_length = 5 + ///Whether the lock is locked. + var/locked = TRUE + /// The code to unlock the lock + var/l_code + /// Whether or not the lock has been set. + var/l_set = FALSE + /// Whether or not the ability to set the lock is broken. + var/l_setshort = FALSE + /// Whether or not the lock is being hacked. + var/tmp/l_hacking = FALSE + /// Whether or not the lock is emagged. + var/emagged = FALSE + /// Whether or not the lock is digital, and its ability to be brute forced. + var/is_digital_lock = FALSE + /// Whether or not the lock service panel is open. + var/open = FALSE + /// The absolute range in turfs the lockable's sounds can be heard at from the holder's position. + var/sound_range = 5 + /// Whether we're currently opening the panel or not. (Unskilled people can take a long time to open it) + var/tmp/opening_panel = FALSE + /// Error text currently displayed to the user. Temporary. + var/tmp/error + /// The passcode currently inputed so far and what is displayed on the UI. + var/tmp/code + +/datum/extension/lockable/New(holder, is_digital = FALSE) ..(holder) is_digital_lock = is_digital +/** + Makes the holder play a sound when a keypad key has been pressed. + * key: A single key character that was pressed. Any leters between A to Z, any numbers between 0-9, or *, #, ⌗, ⚹. + * user: The user inputing the key. + * user_only: If set, the key sound will only be sent to the client using the keypad. + **/ +/datum/extension/lockable/proc/play_key_sound(key, mob/user, user_only = FALSE) + global.play_dtmf_key_sound(holder, key, user, user_only, SOUND_RANGE_ABS(sound_range)) + +///Makes the holder play the success sound, when an operation was successful. +/datum/extension/lockable/proc/play_success_sound() + playsound(holder, 'sound/effects/synth_bell.ogg', 15, FALSE, SOUND_RANGE_ABS(sound_range), 2) + +///Makes the holder play the failure sound, when an invalid operation has been done. +/datum/extension/lockable/proc/play_failure_sound() + playsound(holder, 'sound/machines/synth_no.ogg', 15, FALSE, SOUND_RANGE_ABS(sound_range), 2) + +///Makes the holder play the lock's locking sound. +/datum/extension/lockable/proc/play_lock_sound() + playsound(holder, 'sound/items/containers/briefcase_lock.ogg', 15, FALSE, SOUND_RANGE_ABS(sound_range), 2) + +///Makes the holder play the lock's unlock sound. +/datum/extension/lockable/proc/play_unlock_sound() + playsound(holder, 'sound/machines/mechanical_switch.ogg', 15, FALSE, SOUND_RANGE_ABS(sound_range), 2) + +///Makes the holder play the sound after a new keycode has been set. +/datum/extension/lockable/proc/play_code_set_sound() + set waitfor = FALSE + //Add a slight delay so it doesn't overlap the key sound. + sleep(0.3 SECOND) + playsound(holder, 'sound/effects/fastbeep.ogg', 15, FALSE, SOUND_RANGE_ABS(sound_range), 2) + +/datum/extension/lockable/Topic(href, href_list) + if((. = ..()) || !can_interact(usr)) //Double check if the user can actually send topics to us. + return + //Handle a key press + if(href_list["key"]) + pressed_key(href_list["key"], usr) + return TOPIC_REFRESH + +/** + Process keypresses coming from the nanoUI. + */ +/datum/extension/lockable/proc/pressed_key(key_char, mob/user) + if(!user.check_dexterity(DEXTERITY_KEYBOARDS)) + return + // Always clear error when pressing a button. + clear_error() + + key_char = uppertext(key_char) + if(isnum(text2num(key_char))) + . = enter_number(key_char, user) + else if(key_char == "E") + . = confirm_code(user) + else if(key_char == "C") + . = clear_button(user) + else + CRASH("Unsupported key pressed : '[key_char]'") + + //If the button proc wants us to, we'll play the key sound for the key pressed. + if(.) + play_key_sound(key_char, user) + +/** + Called whenever the user input a number key. + Adds the value of the key to the currently entered keycode. + */ +/datum/extension/lockable/proc/enter_number(num, mob/user, quiet = FALSE) + //When unlocked we can't enter more numbers, otherwise it gets confusing. + if(is_locked()) + code += num + //If we hit the max length after entering the number, just confirm now. + if(length(code) >= max_code_length) + return confirm_code(user) + return TRUE + if(!quiet) + play_failure_sound() + return FALSE //Return false, so calling proc doesn't play a key sound + +/** + Checks the given code for any issues with using it as this lockable's keycode. + Returns null if there are no problems. Or a text string describing the problem otherwise. + */ +/datum/extension/lockable/proc/keycode_issues_text(code) + if(length(code) < floor(max_code_length * 0.5) || length(code) > max_code_length) + return "Keycode must be between [floor(max_code_length * 0.5)] and [max_code_length] numbers long." + return null //Return null, since we have no issues + +/** + Called when the user press the enter key on the lockable keypad, or when the last key of the code is entered. + Either sets the keycode for unlocking this lockable, or checks if the current keycode entered is the correct one, and unlocks the lockable. + Returns TRUE if the code entered was appropriate. + */ +/datum/extension/lockable/proc/confirm_code(mob/user, quiet = FALSE) + if(l_setshort) + return FALSE //Shorted lock doesn't do anything + + //Handles setting the lockable's keycode, if not set yet. + if(is_setting_keycode()) + // We're in lock set mode. So check if the code is valid + var/keycode_issues = keycode_issues_text(code) + if(length(keycode_issues)) + //Code is invalid + clear_current_code() + set_error_message(keycode_issues) + if(!quiet) + play_failure_sound() + return FALSE + //Code is valid + set_keycode(code, quiet) + return TRUE + + if(emagged) + clear_current_code() + set_error_message("Stack Overflow Error 0xDEADBEEF") + return TRUE + + //If we're already unlocked, do nothing. + if(!is_locked()) + return FALSE + + //Handles attempts to unlock with a code + if(!matches_keycode(code)) + //We got a bad keycode. + clear_current_code() + set_error_message("Invalid keycode entered.") + bad_access_attempt(user) + if(!quiet) + play_failure_sound() + return FALSE + + //Handles actually entering the right keycode and unlocking the lockable + set_locked(FALSE, quiet) + if(!quiet) + play_success_sound() + return TRUE + +/** + Clears the currently entered code and the current error text, and lock the lockable if it's not already. + */ +/datum/extension/lockable/proc/clear_button(mob/user, quiet = FALSE) + if(!is_locked()) + set_locked(TRUE) + clear_current_code() + clear_error() + return TRUE + +/** + Clear the currently entered code on the ui. + */ +/datum/extension/lockable/proc/clear_current_code() + //NOTE: Don't trigger a ui update here + code = null + +/** + Clear the currently displayed error text on the ui. + */ +/datum/extension/lockable/proc/clear_error() + //NOTE: Don't trigger a ui update here + error = null + +/** + Sets the error message to be displayed currently. + */ +/datum/extension/lockable/proc/set_error_message(msg) + //NOTE: Don't trigger a ui update here + error = msg + +/** + Locks or unlocks the lockable. And play a sound. + */ +/datum/extension/lockable/proc/set_locked(new_state, quiet = FALSE) + if(locked == new_state) + return + locked = new_state + if(!quiet) + if(locked) + play_lock_sound() + else + play_unlock_sound() + clear_current_code() + RAISE_EVENT(/decl/observ/lock_state_changed, src, !locked, locked) + //TODO: The code below probably should be handled by the event callback on the atom.. + var/atom/A = holder + A.update_icon() + +/** + Sets the keycode that unlocks this lockable. + */ +/datum/extension/lockable/proc/set_keycode(new_code, quiet = FALSE) + l_code = new_code + l_set = length(code) > 0 + set_locked(FALSE) + if(!quiet) + play_code_set_sound() + +/** + Whether the incoming keycode matches the keycode we have set to unlock this lockable. +*/ +/datum/extension/lockable/proc/matches_keycode(incoming) + return incoming == l_code + +/** + Whether we're currently awaiting a keycode input to set the keycode to unlock this lockable. + */ +/datum/extension/lockable/proc/is_setting_keycode() + return !l_set && !l_setshort + +/** + Whether the lockable is currently locked or not. + */ +/datum/extension/lockable/proc/is_locked() + return locked && !emagged + +/** + Whether the user can actually issue commands to the ui. + */ +/datum/extension/lockable/proc/can_interact(mob/user) + return holder.CanUseTopic(user) == STATUS_INTERACTIVE + +/** + Opens the "service panel" for nefarious purposes. + */ +/datum/extension/lockable/proc/toggle_panel(mob/user) + open = !open + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] [open ? "open" : "close"] the service panel of \the [holder]."), + SPAN_NOTICE("You [open ? "open" : "close"] the service panel of \the [holder].")) + SSnano.update_uis(src) //The ui is tied to the extension, not the holder + RAISE_EVENT(/decl/observ/lock_panel_state_changed, src, !open, open) + //TODO: The code below probably should be handled by the event callback on the atom.. + var/atom/A = holder + A.update_icon() + /datum/extension/lockable/nano_host() return holder.nano_host() /datum/extension/lockable/ui_data(mob/user, ui_key) - var/list/data[0] + var/list/data = ..(user, ui_key) data["emagged"] = emagged - data["locked"] = locked + data["locked"] = is_locked() data["disabled"] = l_setshort || emagged if(emagged) data["error"] = "LOCKING SYSTEM ERROR - 1701" @@ -37,154 +299,182 @@ data["error"] = error if((src.l_set == 0) && (!src.emagged) && (!src.l_setshort)) data["status"] = "[max_code_length]-DIGIT PASSCODE NOT SET. ENTER NEW PASSCODE." - data["input_code"] = !locked ? "*****" : (code ? code : "N/A") + data["input_code"] = (!locked) ? "unlocked" : pad_right(code, max_code_length, "-") return data -/datum/extension/lockable/Topic(href, href_list) - . = ..() - if(.) - return - var/mob/user = usr - if(!can_interact(user)) - return - - // Always clear error. - error = null - - var/key_num = text2num(href_list["key"]) - if(isnum(key_num)) - code += href_list["key"] - return - - var/atom/A = holder - if(href_list["key"] == "E") - if(!l_set && !l_setshort) - // We're in lock set mode. - if(length(code) < Floor(max_code_length * 0.5) || length(code) > max_code_length) - error = "Incorrect code length. Must be between [Floor(max_code_length * 0.5)] and [max_code_length] numbers long." - return - l_code = code - code = null - l_set = TRUE - locked = FALSE - else if(locked && !emagged && !l_setshort) - if(code != l_code) - error = "Invalid keycode entered." - bad_access_attempt(user) - return - locked = FALSE - code = null - A.update_icon() - return - if(href_list["key"] == "C") - code = null - error = null - locked = TRUE - A.update_icon() - return - -/datum/extension/lockable/proc/bad_access_attempt(var/mob/user) - -/datum/extension/lockable/proc/can_interact(user) - return holder.CanUseTopic(user) == STATUS_INTERACTIVE - /datum/extension/lockable/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) var/data = ui_data(user) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) var/atom/A = holder - ui = new(user, src, ui_key, "keypad_lock.tmpl", capitalize(A.name), 380, 500) + ui = new(user, src, ui_key, "keypad_lock.tmpl", capitalize(A.name), 312, 400) ui.set_initial_data(data) ui.open() - ui.set_auto_update(1) -/datum/extension/lockable/proc/toggle_panel(var/mob/user) - if(user) - user.show_message(SPAN_NOTICE("You [open ? "open" : "close"] the service panel.")) - open = !open +/** + Called after the user enters the wrong keycode, or fails a hacking attempt. + */ +/datum/extension/lockable/proc/bad_access_attempt(mob/user) + return + +/** + Item attack handler for interactions with the host. + */ +/datum/extension/lockable/proc/attackby(obj/item/used_item, mob/user) + if(!locked) + return FALSE -/datum/extension/lockable/proc/attackby(var/obj/item/W, var/mob/user) - var/obj/item/A = holder - if(locked) - if (!is_digital_lock && istype(W, /obj/item/energy_blade/blade) && emag_act(INFINITY, user, "You slice through the lock of \the [holder]")) - var/datum/effect/effect/system/spark_spread/spark_system = new - spark_system.set_up(5, 0, A.loc) - spark_system.start() + if(!used_item.user_can_attack_with(user)) + return TRUE + + //TODO: This probably should be handled in a better way. + if(!is_digital_lock && istype(used_item, /obj/item/energy_blade)) + var/obj/item/energy_blade/blade = used_item + if(blade.is_special_cutting_tool() && emag_act(INFINITY, user, "You slice through the lock of \the [holder].")) + var/obj/item/A = holder + spark_at(A.loc, amount=5) playsound(A.loc, 'sound/weapons/blade1.ogg', 50, 1) - playsound(A.loc, "sparks", 50, 1) return TRUE - if(isScrewdriver(W)) - if (do_after(user, 20 * user.skill_delay_mult(SKILL_DEVICES), holder)) - toggle_panel() - return TRUE + if(IS_SCREWDRIVER(used_item)) + if(!opening_panel) + var/obj/item/screwdriver/S = used_item + opening_panel = TRUE //Make sure we only have one user/attempt to opens the panel at a time. + if( + S.do_tool_interaction( + TOOL_SCREWDRIVER, + user, + holder, + 2 SECONDS, + "[open? "closing" : "opening"] the service panel on", + null, + check_skill = SKILL_DEVICES, + check_skill_threshold = SKILL_NONE) + ) + opening_panel = FALSE + toggle_panel(user) + return TRUE - if(isMultitool(W) && open && !l_hacking) - user.show_message(SPAN_NOTICE("Now attempting to reset internal memory, please hold."), 1) - l_hacking = 1 - if (do_after(user, 100 * user.skill_delay_mult(SKILL_ELECTRICAL), holder)) - if (prob(user.skill_fail_chance(SKILL_DEVICES, 40, SKILL_EXPERT))) - l_setshort = FALSE - user.show_message(SPAN_NOTICE("Internal memory reset. Please give it a few seconds to reinitialize."), 1) - addtimer(CALLBACK(src, /datum/extension/lockable/proc/reset_memory), 3 SECONDS) - return TRUE - else - user.show_message(SPAN_WARNING("Unable to reset internal memory."), 1) - l_hacking = FALSE - bad_access_attempt(user) - return TRUE - else - l_hacking = FALSE - return FALSE + if(IS_MULTITOOL(used_item)) + try_hack(used_item, user) + return TRUE +/** + Clears the currently set keycode, hacked state, and shorted state. + Called by the hacking proc via timer after a short delay. + */ /datum/extension/lockable/proc/reset_memory() if(!l_hacking) return - reset_memory() - l_setshort = FALSE l_hacking = FALSE + l_setshort = FALSE l_code = null l_set = FALSE - var/atom/movable/A = holder + //Make sure the thing is locked, since that's the expected initial state, so the user can input a new code. + if(!locked) + set_locked(TRUE) + else + //If already locked, just update the ui and icon + SSnano.update_uis(src) //The ui is tied to the extension + //TODO: This code should probably be run by a callback on the holder + var/atom/A = holder + A.update_icon() + spark_at(get_turf(holder), amount = 2) + +/** + Called when an emag is used on the holder. + */ +/datum/extension/lockable/proc/emag_act(remaining_charges, mob/user, feedback) + if(emagged) + return + emagged = TRUE + to_chat(user, SPAN_NOTICE(feedback || "You short out the lock of \the [holder].")) + set_locked(FALSE) //Emagging instantly unlocks the thing. + return TRUE + +/** + Called when a multitool is used on the holder to hack the device. + */ +/datum/extension/lockable/proc/try_hack(obj/item/multitool/multitool, mob/user) + //Don't do anything if the panel isn't opened, or if we're already hacking it. + if(!open || l_hacking) + return FALSE + + //Show a message to let the user know how likely this is to even succeed. + var/fail_chance = hack_fail_chance(multitool, user) + var/skill_msg + if(fail_chance >= 90) + skill_msg = SPAN_WARNING("But, you struggle to make sense of this thing..") + else if(fail_chance >= 50) + skill_msg = SPAN_YELLOW("But, this lock is complicated. You might need several attempts..") + else if(fail_chance >= 20) + skill_msg = SPAN_NOTICE("This should only take a few attempts at most.") + else + skill_msg = SPAN_BLUE("You're confident it shouldn't take long.") + to_chat(user, SPAN_NOTICE("You begin trying to force-reset the lock of \the [holder]. ") + skill_msg) + + var/atom/A = holder + l_hacking = TRUE + //Display the "hacking" icon. TODO: Maybe a callback on the holder be better? + A.update_icon() + if(!user.do_skilled(10 SECONDS, SKILL_ELECTRICAL, holder, 0.8)) + l_hacking = FALSE + else + if (!prob(fail_chance)) + l_setshort = FALSE + to_chat(user, SPAN_NOTICE("You've successfully factory reset the lock! Wait a second for the lock to reinitialize..")) + //The callback will handle setting 'l_hacking' to false! + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/extension/lockable, reset_memory)), 3 SECONDS) + else + to_chat(user, SPAN_WARNING("\icon[holder] Unauthorized access detected!")) + l_hacking = FALSE + bad_access_attempt(user) + //Clear the "hacking" icon. TODO: Maybe a callback on the holder be better? A.update_icon() + return TRUE //We handled the interaction even if it didn't work -/datum/extension/lockable/proc/emag_act(var/remaining_charges, var/mob/user, var/feedback) - var/atom/movable/A = holder - if(!emagged) - emagged = TRUE - locked = FALSE - to_chat(user, (feedback || "You short out the lock of \the [A].")) - A.update_icon() - return TRUE +/** + Returns a percent chance of the given user failing at hacking this lock. + */ +/datum/extension/lockable/proc/hack_fail_chance(obj/item/multitool/multitool, mob/user) + //In order to make the lock actually any use at all, make sure not just anybody with a multitool can open it. + return user.skill_fail_chance(SKILL_DEVICES, 99, SKILL_MAX, 0.35) + +////////////////////////////////////// +// Lockable Storage +////////////////////////////////////// /datum/extension/lockable/storage base_type = /datum/extension/lockable - expected_type = /obj/item/storage - + expected_type = /obj/item + /datum/extension/lockable/storage/safe base_type = /datum/extension/lockable - expected_type = /obj/item/storage + expected_type = /obj/item + +////////////////////////////////////// +// Lockable Charge Sticks +////////////////////////////////////// -/datum/extension/lockable/charge_stick +/datum/extension/lockable/charge_stick base_type = /datum/extension/lockable expected_type = /obj/item/charge_stick + sound_range = 1 var/shock_strength = 0 var/alarm_loudness = 0 -/datum/extension/lockable/charge_stick/bad_access_attempt(var/mob/user) +/datum/extension/lockable/charge_stick/bad_access_attempt(mob/user) if(shock_strength > 0) shock(user, 80) if(alarm_loudness > 0) var/atom/A = holder A.audible_message(SPAN_WARNING("\The [holder] shrills in an annoying tone, alerting those nearby of unauthorized tampering."), hearing_distance = alarm_loudness) - playsound(holder, 'sound/effects/alarm.ogg', 50, 1, alarm_loudness) + playsound(holder, 'sound/effects/alarm.ogg', 50, TRUE, alarm_loudness) -/datum/extension/lockable/charge_stick/proc/shock(var/mob/living/user, prb) +/datum/extension/lockable/charge_stick/proc/shock(mob/living/user, prb) if(!prob(prb) || !istype(user)) return FALSE - var/datum/effect/effect/system/spark_spread/s = new - s.set_up(5, 1, holder) - s.start() + spark_at(holder, amount=5, cardinal_only = TRUE) user.electrocute_act(rand(40 * shock_strength, 80 * shock_strength), holder, shock_strength) //zzzzzzap! return TRUE diff --git a/code/datums/extensions/milkable/milkable.dm b/code/datums/extensions/milkable/milkable.dm new file mode 100644 index 000000000000..198dc791e7b7 --- /dev/null +++ b/code/datums/extensions/milkable/milkable.dm @@ -0,0 +1,150 @@ +/datum/extension/milkable + base_type = /datum/extension/milkable + expected_type = /mob/living + flags = EXTENSION_FLAG_IMMEDIATE + + var/milk_type = /decl/material/liquid/drink/milk + var/milk_prob = 5 + var/milk_min = 5 + var/milk_max = 10 + + var/cream_type = /decl/material/liquid/drink/milk/cream + var/cream_min = 2 + var/cream_max = 5 + + var/impatience = 0 + var/decl/skill/milking_skill = SKILL_BOTANY + var/milking_skill_req = SKILL_BASIC + + var/datum/reagents/udder + +/datum/extension/milkable/New(datum/holder, _milk_type) + ..() + if(ispath(_milk_type, /decl/material)) + milk_type = _milk_type + if(isatom(holder)) + udder = new /datum/reagents(50, holder) + START_PROCESSING(SSprocessing, src) + +/datum/extension/milkable/Destroy() + STOP_PROCESSING(SSprocessing, src) + QDEL_NULL(udder) + return ..() + +/datum/extension/milkable/Process() + if(!isatom(holder) || QDELETED(holder) || QDELETED(src) || QDELETED(udder)) + return PROCESS_KILL + + var/mob/living/critter = holder + if(critter.stat == DEAD) + return PROCESS_KILL + + if(critter.stat == CONSCIOUS && !critter.get_automove_target() && impatience > 0 && prob(10)) // if not fleeing, 10% chance to regain patience + impatience-- + + if(prob(milk_prob)) + create_milk() + +/datum/extension/milkable/proc/create_milk() + + var/create_milk = min(rand(milk_min, milk_max), REAGENTS_FREE_SPACE(udder)) + var/create_cream = min(rand(cream_min, cream_max), REAGENTS_FREE_SPACE(udder) - create_milk) + + if(create_milk <= 0 && create_cream <= 0) + return + + var/list/milk_data = get_milk_data() + udder.add_reagent(milk_type, create_milk, milk_data) + udder.add_reagent(cream_type, create_cream, milk_data) + +/datum/extension/milkable/proc/get_milk_data() + var/static/list/milk_data = list( + DATA_MILK_DONOR = "cow" + ) + return milk_data.Copy() + +// Return TRUE if attackby() should halt at this call. +/datum/extension/milkable/proc/handle_milked(obj/item/chems/container, mob/user) + + if(!istype(container) || !ATOM_IS_OPEN_CONTAINER(container)) + return FALSE + + var/mob/living/critter = holder + if(critter.stat == DEAD) + return FALSE + + if(REAGENT_TOTAL_VOLUME(udder) <= 0) + to_chat(user, SPAN_WARNING("\The [critter]'s udder is dry. Wait a little longer.")) + return TRUE + + if(critter.get_automove_target()) + if(user.skill_check(milking_skill, SKILL_PROF)) + to_chat(user, SPAN_NOTICE("\The [critter] goes still at your touch.")) + critter.stop_automove() + else + to_chat(user, SPAN_WARNING("Wait for \the [critter] to stop moving before you try milking it.")) + return TRUE + + if(REAGENTS_FREE_SPACE(container.reagents) <= 0) + to_chat(user, SPAN_WARNING("\The [container] is full.")) + return TRUE + + // Cows don't like being milked if you're unskilled. + if(user.skill_fail_prob(milking_skill, 40, milking_skill_req)) + handle_milking_failure(user, critter) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] starts milking \the [critter] into \the [container]."), + SPAN_NOTICE("You start milking \the [critter] into \the [container].") + ) + if(!user.do_skilled(4 SECONDS, milking_skill, target = critter, check_holding = TRUE)) + user.visible_message( + SPAN_NOTICE("\The [user] stops milking \the [critter]."), + SPAN_NOTICE("You stop milking \the [critter].") + ) + return TRUE + + if(critter.stat == DEAD) + return FALSE + + if(REAGENT_TOTAL_VOLUME(udder) <= 0) + to_chat(user, SPAN_WARNING("\The [critter]'s udder is dry. Wait a little longer.")) + return TRUE + + if(REAGENTS_FREE_SPACE(container.reagents) <= 0) + to_chat(user, SPAN_NOTICE("\The [container] is full.")) + return TRUE + + if(critter.get_automove_target()) + to_chat(user, SPAN_WARNING("Wait for \the [critter] to stop moving before you try milking it.")) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] milks \the [critter] into \the [container]."), + SPAN_NOTICE("You milk \the [critter] into \the [container].") + ) + udder.trans_to(container, min(REAGENTS_FREE_SPACE(container.reagents), rand(15, 20))) + return TRUE + +/datum/extension/milkable/proc/handle_milking_failure(mob/user, mob/living/critter) + if(impatience > 3) + critter.visible_message(SPAN_WARNING("\The [critter] bellows and flees from \the [user]!")) + critter.flee(user, upset = TRUE) + else + critter.visible_message(SPAN_WARNING("\The [critter] huffs and moves away from \the [user].")) + critter.flee(user, upset = FALSE) + impatience++ + +/datum/extension/milkable/goat/handle_milking_failure(mob/user, mob/living/critter) + critter?.ai?.retaliate() + +/datum/extension/milkable/goat/get_milk_data() + var/static/list/milk_data = list( + DATA_MILK_DONOR = "goat", + DATA_MILK_NAME = "goat", + DATA_CHEESE_NAME = "feta", + DATA_CHEESE_COLOR = "#f3f2be", + DATA_MASK_NAME = "goat's milk", + ) + return milk_data.Copy() diff --git a/code/datums/extensions/multitool/_multitool.dm b/code/datums/extensions/multitool/_multitool.dm deleted file mode 100644 index fd581a007f94..000000000000 --- a/code/datums/extensions/multitool/_multitool.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define MT_NOACTION 0 -#define MT_REFRESH 1 -#define MT_CLOSE 2 diff --git a/code/datums/extensions/multitool/circuitboards/buildtype_select.dm b/code/datums/extensions/multitool/circuitboards/buildtype_select.dm index 9675748d6276..ae95b5cb13a2 100644 --- a/code/datums/extensions/multitool/circuitboards/buildtype_select.dm +++ b/code/datums/extensions/multitool/circuitboards/buildtype_select.dm @@ -12,7 +12,7 @@ if(path == board.build_path) dat += "[initial(thing.name)]" else - dat += "[initial(thing.name)]" + dat += "[initial(thing.name)]" dat += "" dat += "" return JOINTEXT(dat) @@ -24,6 +24,6 @@ if(path && (path in board.get_buildable_types())) board.build_path = path var/obj/thing = path - board.SetName(T_BOARD(initial(thing.name))) - return MT_REFRESH + board.SetName("circuitboard ([initial(thing.name)])") + return TOPIC_REFRESH return ..() \ No newline at end of file diff --git a/code/datums/extensions/multitool/circuitboards/shuttle_console.dm b/code/datums/extensions/multitool/circuitboards/shuttle_console.dm index 2b65dc22b388..77ad6c394f32 100644 --- a/code/datums/extensions/multitool/circuitboards/shuttle_console.dm +++ b/code/datums/extensions/multitool/circuitboards/shuttle_console.dm @@ -5,7 +5,7 @@ var/obj/item/stock_parts/circuitboard/shuttle_console/board = holder var/dat = list() dat += "Current Selected Shuttle: [board.shuttle_tag || "NONE"]
    " - dat += "Synchronize to current shuttle." + dat += "Synchronize to current shuttle." return JOINTEXT(dat) /datum/extension/interactive/multitool/circuitboards/shuttle_console/on_topic(href, href_list, user) @@ -19,11 +19,11 @@ break if(!new_name) to_chat(user, SPAN_WARNING("No eligible shuttle could be located. Make sure the board is inside a shuttle and try again.")) - return MT_NOACTION + return TOPIC_NOACTION if(!board.is_valid_shuttle(SSshuttle.shuttles[new_name])) to_chat(user, SPAN_WARNING("The current shuttle does not support this console type. Try a different shuttle or circuit board.")) - return MT_NOACTION + return TOPIC_NOACTION board.shuttle_tag = new_name - to_chat(user, SPAN_NOTICE("You set the shuttle name to '[new_name]'")) - return MT_REFRESH + to_chat(user, SPAN_NOTICE("You set the shuttle name to '[new_name]'.")) + return TOPIC_REFRESH return ..() \ No newline at end of file diff --git a/code/datums/extensions/multitool/circuitboards/stationalert.dm b/code/datums/extensions/multitool/circuitboards/stationalert.dm index 79757670e54b..209dfba6b736 100644 --- a/code/datums/extensions/multitool/circuitboards/stationalert.dm +++ b/code/datums/extensions/multitool/circuitboards/stationalert.dm @@ -6,9 +6,9 @@ . += "" . += "[AH.category]" if(AH in SA.alarm_handlers) - . += "ActiveInactivate" + . += "ActiveInactivate" else - . += "InactiveActivate" + . += "InactiveActivate" . += "" . += "" @@ -18,12 +18,12 @@ var/datum/alarm_handler/AH = locate(href_list["add"]) in SSalarm.all_handlers if(AH) SA.alarm_handlers |= AH - return MT_REFRESH + return TOPIC_REFRESH if(href_list["remove"]) var/datum/alarm_handler/AH = locate(href_list["remove"]) in SSalarm.all_handlers if(AH) SA.alarm_handlers -= AH - return MT_REFRESH + return TOPIC_REFRESH return ..() diff --git a/code/datums/extensions/multitool/items/cable.dm b/code/datums/extensions/multitool/items/cable.dm index f4d5a93e014e..7f95e27e73e7 100644 --- a/code/datums/extensions/multitool/items/cable.dm +++ b/code/datums/extensions/multitool/items/cable.dm @@ -6,20 +6,21 @@ var/obj/item/stack/cable_coil/cable_coil = holder . += "Available Colors
    " . += "" - for(var/cable_color in GLOB.possible_cable_colours) + var/list/possible_cable_colours = get_global_cable_colors() + for(var/cable_color in possible_cable_colours) . += "" . += "" - if(cable_coil.color == GLOB.possible_cable_colours[cable_color]) + if(cable_coil.color == possible_cable_colours[cable_color]) . += "" else - . += "" + . += "" . += "" . += "
    [cable_color]SelectedSelectSelect
    " /datum/extension/interactive/multitool/items/cable/on_topic(href, href_list, user) var/obj/item/stack/cable_coil/cable_coil = holder - if(href_list["select_color"] && (href_list["select_color"] in GLOB.possible_cable_colours)) + if(href_list["select_color"] && (href_list["select_color"] in get_global_cable_colors())) cable_coil.set_cable_color(href_list["select_color"], user) - return MT_REFRESH + return TOPIC_REFRESH return ..() diff --git a/code/datums/extensions/multitool/items/clothing.dm b/code/datums/extensions/multitool/items/clothing.dm index c3c3ee6db280..bee8241e13b9 100644 --- a/code/datums/extensions/multitool/items/clothing.dm +++ b/code/datums/extensions/multitool/items/clothing.dm @@ -1,13 +1,13 @@ -/obj/item/clothing/under/Initialize() - . = ..() - set_extension(src, /datum/extension/interactive/multitool/items/clothing) - /datum/extension/interactive/multitool/items/clothing/interact(var/obj/item/multitool/M, var/mob/user) if(extension_status(user) != STATUS_INTERACTIVE) return - var/obj/item/clothing/under/u = holder - if(u.has_sensor == SUIT_NO_SENSORS) - to_chat(user, SPAN_WARNING("\The [u] doesn't have suit sensors.")) + var/obj/item/clothing/uniform = holder + if(!istype(uniform)) + to_chat(user, SPAN_WARNING("\The [user] is not wearing an appropriate uniform.")) return - u.has_sensor = u.has_sensor == SUIT_LOCKED_SENSORS ? SUIT_HAS_SENSORS : SUIT_LOCKED_SENSORS - user.visible_message(SPAN_NOTICE("\The [user] [u.has_sensor == SUIT_LOCKED_SENSORS ? "" : "un"]locks \the [u]'s suit sensor controls."), range = 2) + var/obj/item/clothing/sensor/vitals/sensor = locate() in uniform.accessories + if(!sensor) + to_chat(user, SPAN_WARNING("\The [uniform] doesn't have a vitals sensors attached.")) + return + sensor.toggle_sensors_locked() + user.visible_message(SPAN_NOTICE("\The [user] [sensor.get_sensors_locked() ? "" : "un"]locks \the [user]'s suit sensor controls."), range = 2) diff --git a/code/datums/extensions/multitool/items/stock_parts_radio.dm b/code/datums/extensions/multitool/items/stock_parts_radio.dm index 303b0ae0d34d..e35bf8649774 100644 --- a/code/datums/extensions/multitool/items/stock_parts_radio.dm +++ b/code/datums/extensions/multitool/items/stock_parts_radio.dm @@ -6,7 +6,7 @@ var/obj/item/stock_parts/radio/radio = holder if(radio.status & PART_STAT_INSTALLED) return STATUS_CLOSE - return ..() + return ..() /datum/extension/interactive/multitool/radio/interact(obj/item/multitool/M, mob/user) if(extension_status(user) != STATUS_INTERACTIVE) @@ -34,63 +34,63 @@ var/obj/item/stock_parts/radio/radio = holder var/list/dat = list() - dat += "Unlink Machine
    " + dat += "Unlink Machine
    " var/obj/machinery/actual_machine = machine && machine.resolve() if(actual_machine && actual_machine.can_apply_preset_to(radio)) - dat += "Reset to Machine Defaults
    " + dat += "Reset to Machine Defaults
    " dat += "Configuration for \the [radio].
    " - dat += "Frequency: [radio.frequency || "none"]
    " - dat += "ID: [radio.id_tag || "none"]
    " - dat += "Filter: [radio.filter || "none"]
    " - dat += "Encryption key: [radio.encryption || "none"]
    " + dat += "Frequency: [radio.frequency || "none"]
    " + dat += "ID: [radio.id_tag || "none"]
    " + dat += "Filter: [radio.filter || "none"]
    " + dat += "Encryption key: [radio.encryption || "none"]
    " return JOINTEXT(dat) /datum/extension/interactive/multitool/radio/on_topic(href, href_list, user) var/obj/item/stock_parts/radio/radio = holder if(href_list["unlink"]) machine = null - return MT_CLOSE + return TOPIC_CLOSE if(href_list["frequency"]) var/new_frequency = input(user, "Select a new frequency:", "Frequency Selection", radio.frequency) as null|num if(!new_frequency || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_NOACTION + return TOPIC_NOACTION new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) if(new_frequency == radio.frequency) - return MT_NOACTION + return TOPIC_NOACTION radio.set_frequency(new_frequency, radio.filter) - return MT_REFRESH + return TOPIC_REFRESH if(href_list["id_tag"]) var/new_id_tag = input(user, "Select a new ID:", "ID Selection", radio.id_tag) as null|text if(!new_id_tag || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_NOACTION + return TOPIC_NOACTION new_id_tag = sanitize(new_id_tag) if(new_id_tag == radio.id_tag) - return MT_NOACTION + return TOPIC_NOACTION radio.set_id_tag(new_id_tag) - return MT_REFRESH + return TOPIC_REFRESH if(href_list["filter"]) - var/new_filter = input(user, "Select a new radio filter (usually signals are sent to listeners on your id_tag; this will override that behavior):", "Filter Selection", radio.filter) as null|anything in GLOB.all_selectable_radio_filters + var/new_filter = input(user, "Select a new radio filter (usually signals are sent to listeners on your id_tag; this will override that behavior):", "Filter Selection", radio.filter) as null|anything in global.all_selectable_radio_filters if(!new_filter || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_NOACTION + return TOPIC_NOACTION if(new_filter == radio.filter) - return MT_NOACTION + return TOPIC_NOACTION radio.set_frequency(radio.frequency, new_filter) - return MT_REFRESH + return TOPIC_REFRESH if(href_list["encryption"]) var/new_encryption = input(user, "Select a new encryption key:", "Encryption Key Selection", radio.encryption) as null|num if(!new_encryption || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_NOACTION + return TOPIC_NOACTION new_encryption = sanitize_integer(new_encryption, 0, 999, radio.encryption) if(new_encryption == radio.encryption) - return MT_NOACTION + return TOPIC_NOACTION radio.encryption = new_encryption - return MT_REFRESH + return TOPIC_REFRESH if(href_list["stockreset"]) var/obj/machinery/actual_machine = machine && machine.resolve() if(!actual_machine) - return MT_CLOSE + return TOPIC_CLOSE actual_machine.apply_preset_to(radio) - return MT_REFRESH + return TOPIC_REFRESH // Helper. /datum/extension/interactive/multitool/radio/proc/event_list_to_selection_table(table_tag, list/selected_events) @@ -98,57 +98,57 @@ . += "" for(var/thing in selected_events) . += "" - . += "" - . += "" + . += "" + . += "" var/decl/public_access/variable = selected_events[thing] - . += "" - . += "" + . += "" + . += "" . += "" - . += "" + . += "" . += "
    (-)[thing](-)[thing][variable.name](?)[variable.name](?)
    (+)
    (+)
    " /datum/extension/interactive/multitool/radio/proc/event_list_topic(list/selected_events, list/valid_events, mob/user, href_list) if(href_list["remove"]) var/thing = href_list["remove"] LAZYREMOVE(selected_events, thing) - return MT_REFRESH + return TOPIC_REFRESH if(href_list["rename"]) var/thing = href_list["rename"] if(selected_events && selected_events[thing]) var/new_name = input(user, "Select a new message key for this item:", "Key Select", thing) as null|text new_name = sanitize(new_name) if(!new_name || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_REFRESH + return TOPIC_REFRESH if(!selected_events || !selected_events[thing]) - return MT_REFRESH + return TOPIC_REFRESH selected_events[new_name] = selected_events[thing] selected_events -= thing - return MT_REFRESH + return TOPIC_REFRESH if(href_list["new_val"]) var/thing = href_list["new_val"] var/decl/public_access/variable = selected_events && selected_events[thing] if(!variable || !LAZYLEN(valid_events)) - return MT_REFRESH + return TOPIC_REFRESH var/valid_variables = list() for(var/path in valid_events) valid_variables += valid_events[path] var/new_var = input(user, "Select a new action for this item:", "Action Select", thing) as null|anything in valid_variables if(!new_var || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_REFRESH + return TOPIC_REFRESH if(!(selected_events && selected_events[thing] == variable)) - return MT_REFRESH + return TOPIC_REFRESH selected_events[thing] = new_var - return MT_REFRESH + return TOPIC_REFRESH if(href_list["add"]) if(!LAZYLEN(valid_events)) - return MT_REFRESH + return TOPIC_REFRESH LAZYSET(selected_events, copytext(md5(num2text(rand(0, 1))), 1, 11), valid_events[pick(valid_events)]) // random key - return MT_REFRESH + return TOPIC_REFRESH if(href_list["desc"]) var/decl/public_access/variable = locate(href_list["desc"]) if(istype(variable)) to_chat(user, variable.desc) - return MT_NOACTION + return TOPIC_NOACTION /datum/extension/interactive/multitool/radio/transmitter/aquire_target() var/obj/machinery/actual_machine = ..() @@ -156,6 +156,8 @@ if(!actual_machine) return var/obj/item/stock_parts/radio/transmitter/basic/radio = holder + LAZYINITLIST(radio.transmit_on_change) + LAZYINITLIST(radio.transmit_on_tick) radio.sanitize_events(actual_machine, radio.transmit_on_change) radio.sanitize_events(actual_machine, radio.transmit_on_tick) @@ -176,7 +178,7 @@ return var/obj/machinery/actual_machine = machine.resolve() if(!actual_machine) - return MT_CLOSE + return TOPIC_CLOSE var/obj/item/stock_parts/radio/transmitter/basic/radio = holder if(href_list["on_change"]) return event_list_topic(radio.transmit_on_change, actual_machine.public_variables, user, href_list) @@ -189,6 +191,7 @@ if(!actual_machine) return var/obj/item/stock_parts/radio/transmitter/on_event/radio = holder + LAZYINITLIST(radio.transmit_on_event) if(!radio.is_valid_event(actual_machine, radio.event)) radio.event = null radio.sanitize_events(actual_machine, radio.transmit_on_event) @@ -199,9 +202,9 @@ dat += "Choose event:
    " if(radio.event) - dat += "[radio.event] (?)" + dat += "[radio.event] (?)" else - dat += "(+)" + dat += "(+)" dat += "
    " dat += "Transmit on event:
    " dat += event_list_to_selection_table("on_event", radio.transmit_on_event) @@ -213,7 +216,7 @@ return var/obj/machinery/actual_machine = machine.resolve() if(!actual_machine) - return MT_CLOSE + return TOPIC_CLOSE var/obj/item/stock_parts/radio/transmitter/on_event/radio = holder if(href_list["on_event"]) @@ -232,6 +235,8 @@ if(!actual_machine) return var/obj/item/stock_parts/radio/receiver/radio = holder + LAZYINITLIST(radio.receive_and_call) + LAZYINITLIST(radio.receive_and_write) radio.sanitize_events(actual_machine, radio.receive_and_call) radio.sanitize_events(actual_machine, radio.receive_and_write) @@ -239,10 +244,10 @@ var/obj/item/stock_parts/radio/receiver/radio = holder var/list/dat = list() - dat += "Transmit on change:
    " + dat += "Called on signal reception:
    " dat += event_list_to_selection_table("call", radio.receive_and_call) dat += "
    " - dat += "Transmit every tick:
    " + dat += "Written to on signal reception:
    " dat += event_list_to_selection_table("write", radio.receive_and_write) return ..() + JOINTEXT(dat) @@ -252,9 +257,9 @@ return var/obj/machinery/actual_machine = machine.resolve() if(!actual_machine) - return MT_CLOSE + return TOPIC_CLOSE var/obj/item/stock_parts/radio/receiver/radio = holder if(href_list["call"]) return event_list_topic(radio.receive_and_call, actual_machine.public_methods, user, href_list) if(href_list["write"]) - return event_list_topic(radio.receive_and_write, radio.sanitize_events(actual_machine.public_variables.Copy()), user, href_list) \ No newline at end of file + return event_list_topic(radio.receive_and_write, actual_machine.public_variables, user, href_list) \ No newline at end of file diff --git a/code/datums/extensions/multitool/multitool.dm b/code/datums/extensions/multitool/multitool.dm index 8d4142886e6f..7bfdeac27708 100644 --- a/code/datums/extensions/multitool/multitool.dm +++ b/code/datums/extensions/multitool/multitool.dm @@ -11,10 +11,9 @@ if(html) var/datum/browser/popup = new(user, "multitool", "Multitool Menu", window_x, window_y) popup.set_content(html) - popup.set_title_image(user.browse_rsc_icon(M.icon, M.icon_state)) popup.open() else - close_window(usr) + close_window(user) /datum/extension/interactive/multitool/proc/get_interact_window(var/obj/item/multitool/M, var/mob/user) return @@ -26,7 +25,7 @@ . += "Buffer Memory:
    " var/buffer_name = multitool.get_buffer_name() if(buffer_name) - . += "[buffer_name] Send Purge
    " + . += "[buffer_name] Send Purge
    " else . += "No connection stored in the buffer." @@ -37,7 +36,7 @@ /datum/extension/interactive/multitool/extension_act(href, href_list, var/mob/user) if(..()) - close_window(usr) + close_window(user) return TRUE var/obj/item/multitool/M = user.get_multitool() @@ -46,26 +45,29 @@ . = send_buffer(M, buffer, user) else if(href_list["purge"]) M.set_buffer(null) - . = MT_REFRESH + . = TOPIC_REFRESH else . = on_topic(href, href_list, user) - switch(.) - if(MT_REFRESH) - interact(M, user) - if(MT_CLOSE) - close_window(user) - return MT_NOACTION ? FALSE : TRUE + if(. & TOPIC_CLOSE) + close_window(user) + return TOPIC_HANDLED // don't run any other Topic() behavior for this call + else if(. & TOPIC_REFRESH) + interact(M, user) + return TOPIC_HANDLED // don't return TOPIC_REFRESH to avoid any potential double-refreshes + else if(!.) + return TOPIC_NOACTION + return TOPIC_REFRESH /datum/extension/interactive/multitool/proc/on_topic(href, href_list, user) - return MT_NOACTION + return TOPIC_NOACTION /datum/extension/interactive/multitool/proc/send_buffer(var/obj/item/multitool/M, var/atom/buffer, var/mob/user) if(M.get_buffer() == buffer && buffer) receive_buffer(M, buffer, user) else if(!buffer) to_chat(user, "Unable to acquire data from the buffered object. Purging from memory.") - return MT_REFRESH + return TOPIC_REFRESH /datum/extension/interactive/multitool/proc/receive_buffer(var/obj/item/multitool/M, var/atom/buffer, var/mob/user) return \ No newline at end of file diff --git a/code/datums/extensions/on_click/on_alt_click.dm b/code/datums/extensions/on_click/on_alt_click.dm deleted file mode 100644 index 62bd2c6ac252..000000000000 --- a/code/datums/extensions/on_click/on_alt_click.dm +++ /dev/null @@ -1,49 +0,0 @@ -/datum/extension/on_click/alt/ghost_admin_killer - expected_type = /mob/living - var/mob/living/living_holder - var/death_proc - -/datum/extension/on_click/alt/ghost_admin_killer/New(var/host, var/death_proc) - ..() - living_holder = host - src.death_proc = death_proc || /mob/proc/death - -/datum/extension/on_click/alt/ghost_admin_killer/Destroy() - living_holder = null - . = ..() - -/datum/extension/on_click/alt/ghost_admin_killer/on_click(var/mob/user) - if(!valid_preconditions(user)) - return FALSE - - var/key_name = key_name(living_holder) - if(alert(user, "Do you wish to kill [key_name]?", "Kill [living_holder]?", "No", "Yes") != "Yes") - return FALSE - if(!valid_preconditions(user)) - to_chat(user, SPAN_NOTICE("You were unable to kill [key_name]")) - return FALSE - - call(living_holder, death_proc)() - log_and_message_admins("killed [key_name]") - - return TRUE - -/datum/extension/on_click/alt/ghost_admin_killer/proc/valid_preconditions(var/mob/observer/ghost/user) - if(QDELETED(living_holder)) // Sanity check - return FALSE - if(!istype(user)) // Only ghosts may attempt to alt-kill mobs - return FALSE - if(!check_rights(R_INVESTIGATE, 0, user)) // And only if they're investigators - Power creep - return FALSE - if(!living_holder.client) // And only if the target mob is currently possessed - to_chat(user, SPAN_NOTICE("\The [living_holder] is not currently possessed.")) - return FALSE - if(living_holder.stat == DEAD) // No point in killing the already dead - to_chat(user, SPAN_NOTICE("\The [living_holder] is already dead.")) - return FALSE - return TRUE - -/mob/living/Initialize() - . = ..() - if(possession_candidate) - set_extension(src, /datum/extension/on_click/alt/ghost_admin_killer) diff --git a/code/datums/extensions/on_click/on_click.dm b/code/datums/extensions/on_click/on_click.dm deleted file mode 100644 index 2e8fab6f386a..000000000000 --- a/code/datums/extensions/on_click/on_click.dm +++ /dev/null @@ -1,18 +0,0 @@ -/datum/extension/on_click - base_type = /datum/extension/on_click - expected_type = /atom - var/atom/atom_holder - -/datum/extension/on_click/alt - base_type = /datum/extension/on_click/alt - -/datum/extension/on_click/New() - ..() - atom_holder = holder - -/datum/extension/on_click/Destroy() - atom_holder = null - return ..() - -/datum/extension/on_click/proc/on_click(var/mob/user) - return FALSE \ No newline at end of file diff --git a/code/datums/extensions/on_click/turf_hand.dm b/code/datums/extensions/on_click/turf_hand.dm index b3ab8a381044..9cef21278b80 100644 --- a/code/datums/extensions/on_click/turf_hand.dm +++ b/code/datums/extensions/on_click/turf_hand.dm @@ -7,14 +7,9 @@ */ /datum/extension/turf_hand base_type = /datum/extension/turf_hand - var/priority = 1 expected_type = /atom + var/intercept_priority = 1 -/datum/extension/turf_hand/New(var/holder, var/priority = 1) +/datum/extension/turf_hand/New(var/holder, var/_priority = 1) ..() - src.priority = priority - - -/datum/extension/turf_hand/proc/OnHandInterception(var/mob/user) - var/atom/A = holder - return A.attack_hand(user) \ No newline at end of file + intercept_priority = _priority diff --git a/code/datums/extensions/padding/padding.dm b/code/datums/extensions/padding/padding.dm new file mode 100644 index 000000000000..f75445c9ae23 --- /dev/null +++ b/code/datums/extensions/padding/padding.dm @@ -0,0 +1,132 @@ +// TODO: Maybe generalize this to handle any sort of component-composition that can have a separate material and painting? +/// An extension that unifies padding state and interactions. +/datum/extension/padding + abstract_type = /datum/extension/padding + base_type = /datum/extension/padding + expected_type = /obj + flags = EXTENSION_FLAG_IMMEDIATE // logic must run on creation + /// The paint color for the padding represented by this extension. + /// '#FFFFFF' is treated as 'painted white', while 'null' is treated as 'unpainted'. + VAR_PROTECTED/padding_color + VAR_PROTECTED/decl/material/padding_material + // TODO: Add some better way of determining if a stack is usable, for more extensibility in modpacks. + /// What stack types can be used to add padding? + VAR_PRIVATE/static/padding_stack_types = list( + /obj/item/stack/material/skin, // leather, fur + /obj/item/stack/material/bolt, // cloth + ) + /// An internal variable used to hold a typecache for the above list. + VAR_PRIVATE/static/_padding_stack_typecache + +/datum/extension/padding/New(datum/holder, _padding_material, _padding_color) + . = ..() + if(!_padding_stack_typecache) + _padding_stack_typecache = typecacheof(padding_stack_types) + +// Must be here so our holder's get_extension calls work. +/datum/extension/padding/post_construction(_padding_material, _padding_color) + . = ..() + add_padding(_padding_material, _padding_color) + +/// Returns an object's padding material. +/datum/extension/padding/proc/get_padding_material() + RETURN_TYPE(/decl/material) + return padding_material + +/// Returns the color of the padding, either the painted/dyed color or (optionally) the underlying material color. +/datum/extension/padding/proc/get_padding_color(use_material_color = TRUE) + var/decl/material/padding_material = get_padding_material() + return padding_color || (use_material_color ? padding_material?.color : null) + +/// Used to change just the paint color on padding. +/datum/extension/padding/proc/set_padding_color(new_color) + padding_color = new_color + +/datum/extension/padding/proc/handle_use_item(obj/item/used_item, mob/user) + if(isstack(used_item)) + if(padding_material) + to_chat(user, SPAN_NOTICE("\The [holder] is already padded.")) + return TRUE + var/decl/material/new_padding_material = used_item.material + if(!is_type_in_typecache(used_item, _padding_stack_typecache) || !(new_padding_material.flags & MAT_FLAG_PADDING)) + to_chat(user, SPAN_NOTICE("You cannot pad \the [holder] with that.")) + return TRUE + var/obj/item/stack/used_stack = used_item + if(!used_stack.can_use(1)) + to_chat(user, SPAN_NOTICE("You need at least [used_stack.get_string_for_amount(1)] to pad \the [holder].")) + return TRUE + if(!used_item.user_can_attack_with(user, holder)) + return TRUE + to_chat(user, SPAN_NOTICE("You pad \the [holder] with [used_stack.get_string_for_amount(1)].")) + used_stack.use(1) + if(new_padding_material.sound_manipulate) + playsound(get_turf(holder), new_padding_material.sound_manipulate, 50, TRUE) + add_padding(new_padding_material.type, used_stack.paint_color) + return TRUE + else if(IS_SHEARS(used_item)) // can use shears or wirecutters + if(!padding_material) + to_chat(user, SPAN_NOTICE("\The [holder] has no padding to remove.")) + return TRUE + if(!used_item.user_can_attack_with(user, holder)) + return TRUE + to_chat(user, SPAN_NOTICE("You remove \the [padding_material.adjective_name] padding from \the [holder].")) + var/use_tool_sound = used_item.get_tool_sound(TOOL_SHEARS) + if(use_tool_sound) + playsound(get_turf(holder), use_tool_sound, 100, TRUE) + remove_padding() + return TRUE + return FALSE + +// TODO: Unify this somewhere on /obj, maybe? +/datum/extension/padding/proc/update_holder_name() + if(QDELETED(src) || QDELETED(holder)) + return + if(istype(holder, /obj/structure)) + var/obj/structure/structure_holder = holder + structure_holder.update_materials() // update name and description if needed + else if(isitem(holder)) + var/obj/item/item_holder = holder + item_holder.update_name() + +/datum/extension/padding/proc/add_padding(padding_type, new_padding_color, do_icon_update = TRUE) + ASSERT(padding_type) + var/old_padding_material = padding_material + padding_material = ispath(padding_type) ? GET_DECL(padding_type) : padding_type + padding_color = new_padding_color + update_matter(old_padding_material, padding_material) + if(do_icon_update) + var/obj/obj_holder = holder + addtimer(CALLBACK(src, PROC_REF(update_holder_name)), 0, TIMER_UNIQUE) // Update at the end of the tick. + obj_holder.queue_icon_update() + +/datum/extension/padding/proc/remove_padding(do_icon_update = TRUE) + if(padding_material) + var/list/res = padding_material.create_object(get_turf(holder)) + if(padding_color) + for(var/obj/item/thing in res) + thing.set_color(padding_color) + var/old_padding_material = padding_material + padding_material = null + padding_color = null + update_matter(old_padding_material, padding_material) + if(do_icon_update) + var/obj/obj_holder = holder + if(istype(obj_holder, /obj/structure)) + var/obj/structure/structure_holder = obj_holder + structure_holder.update_materials() // update name and description if needed + else if(isitem(obj_holder)) + var/obj/item/item_holder = obj_holder + item_holder.update_name() + obj_holder.queue_icon_update() + +/datum/extension/padding/proc/update_matter(decl/material/old_padding, decl/material/new_padding) + var/obj/obj_holder = holder + var/matter_mult = obj_holder.get_matter_amount_modifier() + if(LAZYLEN(obj_holder.matter) && old_padding) + obj_holder.matter[old_padding.type] -= MATTER_AMOUNT_TRACE * matter_mult + if(!obj_holder.matter[old_padding.type]) + obj_holder.matter -= old_padding.type + if(new_padding) + LAZYINITLIST(obj_holder.matter) + obj_holder.matter[new_padding.type] += MATTER_AMOUNT_TRACE * matter_mult + UNSETEMPTY(obj_holder.matter) \ No newline at end of file diff --git a/code/datums/extensions/radio_provider.dm b/code/datums/extensions/radio_provider.dm new file mode 100644 index 000000000000..8be75d0da1ed --- /dev/null +++ b/code/datums/extensions/radio_provider.dm @@ -0,0 +1,35 @@ +/datum/extension/radio_provider + base_type = /datum/extension/radio_provider + expected_type = /atom/movable + var/list/atom/movable/registered_radios + +/datum/extension/radio_provider/Destroy() + LAZYCLEARLIST(registered_radios) + . = ..() + +/datum/extension/radio_provider/proc/register_radio(atom/movable/to_register) + LAZYDISTINCTADD(registered_radios, to_register) + +/datum/extension/radio_provider/proc/unregister_radio(atom/movable/to_unregister) + LAZYREMOVE(registered_radios, to_unregister) + +/datum/extension/radio_provider/proc/GetRadios(message_mode) + for(var/atom/movable/registered_radio in registered_radios) + LAZYDISTINCTADD(., registered_radio.GetRadios(message_mode)) + +/datum/extension/radio_provider/proc/GetRadio(message_mode) + var/list/radios = GetRadios(message_mode) + return LAZYACCESS(radios, 1) + +/atom/movable/proc/GetRadios(message_mode) + var/datum/extension/radio_provider/radio_provider = get_extension(src, /datum/extension/radio_provider) + if(istype(radio_provider)) + return radio_provider.GetRadios(message_mode) + +/* +// Example implementation if extension is desired. +/atom/movable/Initialize() + . = ..() + var/datum/extension/radio_provider/radio = get_or_create_extension(src, /datum/extension/radio_provider) + radio.register_radio(some_radio) +*/ \ No newline at end of file diff --git a/code/datums/extensions/resistable/resistable.dm b/code/datums/extensions/resistable/resistable.dm new file mode 100644 index 000000000000..9e6fa45299af --- /dev/null +++ b/code/datums/extensions/resistable/resistable.dm @@ -0,0 +1,85 @@ +// TODO: extend this to cover buckled structures +/datum/extension/resistable + base_type = /datum/extension/resistable + expected_type = /obj/item + +/datum/extension/resistable/proc/get_restraint_escape_time(mob/living/user) + return 2 MINUTES + +/datum/extension/resistable/proc/user_try_escape(mob/living/user, slot) + + set waitfor = FALSE + + var/obj/item/restraint = holder + if(!istype(user) || QDELETED(user) || QDELETED(restraint) || restraint.loc != user || user.buckled) + return FALSE + + // Don't want to do a lot of logic gating here. + if(user.can_break_restraints()) + return user.break_restraints(restraint) + + var/breakouttime = get_restraint_escape_time(user) + breakouttime = max(5, breakouttime * user.get_restraint_breakout_mod()) + user.setClickCooldown(breakouttime) + + user.visible_message( + SPAN_DANGER("\The [user] attempts to remove \the [restraint]!"), + SPAN_DANGER("You attempt to remove \the [restraint] (This will take around [ceil(breakouttime / (1 SECOND))] second\s and you need to stand still)."), + range = 2 + ) + + var/static/resist_stages = 4 + for(var/i = 1 to resist_stages) + if(!do_after(user, breakouttime*0.25, incapacitation_flags = (INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))) + user.visible_message( + SPAN_WARNING("\The [user] stops fiddling with \the [restraint]."), + SPAN_WARNING("You stop trying to slip free of \the [restraint]."), + range = 2 + ) + return FALSE + + var/new_restraint = user.get_equipped_item(slot) + if((restraint != new_restraint) || user.buckled) + return FALSE + user.visible_message( + SPAN_WARNING("\The [user] fiddles with \the [restraint]."), + SPAN_WARNING("You try to slip free of \the [restraint] ([i*100/resist_stages]% done)."), + range = 2 + ) + + if (restraint.can_take_damage() && restraint.current_health > 0) // Improvised restraint can break because their health is > 0 + restraint.take_damage(restraint.get_max_health() / 2) + if (QDELETED(restraint) || restraint.current_health < 1) + var/decl/pronouns/pronouns = restraint.get_pronouns() + user.visible_message( + SPAN_DANGER("\The [user] manages to remove \the [restraint], breaking [pronouns.him]!"), + SPAN_NOTICE("You successfully remove \the [restraint], breaking [pronouns.him]!"), + range = 2 + ) + QDEL_NULL(restraint) + if(user.buckled && user.buckled.buckle_require_restraints) + user.buckled.unbuckle_mob() + user.update_equipment_overlay(slot) + return + user.visible_message( + SPAN_WARNING("\The [user] manages to remove \the [restraint]!"), + SPAN_NOTICE("You successfully remove \the [restraint]!"), + range = 2 + ) + user.drop_from_inventory(restraint) + +// Specific item subtypes/logic below. +/datum/extension/resistable/handcuffs + expected_type = /obj/item/handcuffs + +/datum/extension/resistable/handcuffs/get_restraint_escape_time(mob/living/user) + var/obj/item/handcuffs/cuffs = holder + . = cuffs.breakouttime + if(istype(user?.get_equipped_item(slot_gloves_str), /obj/item/clothing/gloves/rig)) + . = round(.*0.5) + +/datum/extension/resistable/straightjacket + expected_type = /obj/item/clothing/suit/straight_jacket + +/datum/extension/resistable/straightjacket/get_restraint_escape_time(mob/living/user) + return 5 MINUTES diff --git a/code/datums/extensions/scent/_scent.dm b/code/datums/extensions/scent/_scent.dm deleted file mode 100644 index d147dba782bc..000000000000 --- a/code/datums/extensions/scent/_scent.dm +++ /dev/null @@ -1,117 +0,0 @@ -#define SCENT_DESC_ODOR "odour" -#define SCENT_DESC_SMELL "smell" -#define SCENT_DESC_FRAGRANCE "fragrance" - -/***** -Scent intensity -*****/ -/decl/scent_intensity - var/cooldown = 5 MINUTES - var/intensity = 1 - -/decl/scent_intensity/proc/PrintMessage(var/mob/user, var/descriptor, var/scent) - to_chat(user, SPAN_SUBTLE("The subtle [descriptor] of [scent] tickles your nose...")) - -/decl/scent_intensity/normal - cooldown = 4 MINUTES - intensity = 2 - -/decl/scent_intensity/normal/PrintMessage(var/mob/user, var/descriptor, var/scent) - to_chat(user, SPAN_NOTICE("The [descriptor] of [scent] fills the air.")) - -/decl/scent_intensity/strong - cooldown = 3 MINUTES - intensity = 3 - -/decl/scent_intensity/strong/PrintMessage(var/mob/user, var/descriptor, var/scent) - to_chat(user, SPAN_WARNING("The unmistakable [descriptor] of [scent] bombards your nostrils.")) - -/***** - Scent extensions - Usage: - To add: - set_extension(atom, /datum/extension/scent/PATH/TO/SPECIFIC/SCENT) - This will set up the extension and will make it begin to emit_scent. - To remove: - remove_extension(atom, /datum/extension/scent) -*****/ - -/datum/extension/scent - base_type = /datum/extension/scent - expected_type = /atom - flags = EXTENSION_FLAG_IMMEDIATE - - var/scent = "something" - var/decl/scent_intensity/intensity = /decl/scent_intensity - var/descriptor = SCENT_DESC_SMELL //unambiguous descriptor of smell; food is generally good, sewage is generally bad. how 'nice' the scent is - var/range = 1 //range in tiles - -/datum/extension/scent/New() - ..() - if(ispath(intensity)) - intensity = decls_repository.get_decl(intensity) - START_PROCESSING(SSprocessing, src) - -/datum/extension/scent/Destroy() - STOP_PROCESSING(SSprocessing, src) - . = ..() - -/datum/extension/scent/Process() - if(!holder) - crash_with("Scent extension with scent '[scent]', intensity '[intensity]', descriptor '[descriptor]' and range of '[range]' attempted to emit_scent() without a holder.") - qdel(src) - return PROCESS_KILL - emit_scent() - -/datum/extension/scent/proc/emit_scent() - for(var/mob/living/carbon/human/H in all_hearers(holder, range)) - var/turf/T = get_turf(H.loc) - if(!T) - continue - if(H.stat != CONSCIOUS || H.failed_last_breath || H.wear_mask || H.head && H.head.permeability_coefficient < 1 || !T.return_air()) - continue - if(H.last_smelt < world.time) - intensity.PrintMessage(H, descriptor, scent) - H.last_smelt = world.time + intensity.cooldown - -/***** -Custom subtype - set_extension(atom, /datum/extension/scent/custom, scent = "scent", intensity = SCENT_INTENSITY_, ... etc) -This will let you set an extension without needing to define it beforehand. Note that all vars are required if generating. -*****/ -/datum/extension/scent/custom/New(var/datum/holder, var/provided_scent, var/provided_intensity, var/provided_descriptor, var/provided_range) - ..() - if(provided_scent && provided_intensity && provided_descriptor && provided_range) - scent = provided_scent - if(ispath(provided_intensity)) - intensity = decls_repository.get_decl(provided_intensity) - descriptor = provided_descriptor - range = provided_range - else - CRASH("Attempted to generate a scent extension on [holder], but at least one of the required vars was not provided.") - -/***** -Reagents have the following vars, which coorelate to the vars on the standard scent extension: - scent, - scent_intensity, - scent_descriptor, - scent_range -To add a scent extension to an atom using a reagent's info, where R. is the reagent, use set_scent_by_reagents(). -*****/ - -/proc/set_scent_by_reagents(var/atom/smelly_atom) - var/decl/material/smelliest - var/decl/material/scent_intensity - if(!smelly_atom.reagents || !smelly_atom.reagents.total_volume) - return - for(var/reagent_type in smelly_atom.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(reagent_type) - if(!R.scent) - continue - var/decl/scent_intensity/SI = decls_repository.get_decl(R.scent_intensity) - var/r_scent_intensity = REAGENT_VOLUME(smelly_atom.reagents, reagent_type) * SI.intensity - if(r_scent_intensity > scent_intensity) - smelliest = R - scent_intensity = r_scent_intensity - if(smelliest) - set_extension(smelly_atom, /datum/extension/scent/custom, smelliest.scent, smelliest.scent_intensity, smelliest.scent_descriptor, smelliest.scent_range) \ No newline at end of file diff --git a/code/datums/extensions/shearable/shearable.dm b/code/datums/extensions/shearable/shearable.dm new file mode 100644 index 000000000000..c94d40a86696 --- /dev/null +++ b/code/datums/extensions/shearable/shearable.dm @@ -0,0 +1,108 @@ +/datum/extension/shearable + base_type = /datum/extension/shearable + expected_type = /mob/living + flags = EXTENSION_FLAG_IMMEDIATE + + var/has_fleece = FALSE + var/next_fleece = 0 + var/fleece_time = 5 MINUTES + var/fleece_type = /obj/item/fleece + var/decl/material/fleece_material = /decl/material/solid/organic/cloth/wool + + var/decl/skill/shearing_skill = SKILL_BOTANY + var/shearing_skill_req = SKILL_BASIC + +/datum/extension/shearable/New(datum/holder, _fleece_material) + . = ..() + if(ispath(_fleece_material, /decl/material)) + fleece_material = _fleece_material + if(ispath(fleece_material, /decl/material)) + fleece_material = GET_DECL(fleece_material) + START_PROCESSING(SSprocessing, src) + +/datum/extension/shearable/Destroy() + STOP_PROCESSING(SSprocessing, src) + return ..() + +/datum/extension/shearable/Process() + if(has_fleece) + return PROCESS_KILL + if(world.time >= next_fleece) + + has_fleece = TRUE + var/mob/living/critter = holder + + // Update fleeced simple animals with overlay. + if(istype(holder, /mob/living/simple_animal)) + var/fleece_state = "[critter.icon_state]-fleece" + if(check_state_in_icon(fleece_state, critter.icon)) + var/mob/living/simple_animal/animal = critter + LAZYSET(animal.draw_visible_overlays, "fleece", fleece_material.color) + + critter.try_refresh_visible_overlays() + return PROCESS_KILL + +/datum/extension/shearable/proc/handle_sheared(obj/item/shears, mob/user) + + var/mob/living/critter = holder + if(!has_fleece) + to_chat(user, SPAN_WARNING("\The [critter] is not ready to be shorn again yet.")) + return TRUE + + if(critter.get_automove_target()) + if(user.skill_check(shearing_skill, SKILL_PROF)) + to_chat(user, SPAN_NOTICE("\The [critter] goes still at your touch.")) + critter.stop_automove() + else + to_chat(user, SPAN_WARNING("Wait for \the [critter] to stop moving before you try shearing it.")) + return TRUE + + // Cows don't like being milked if you're unskilled. + if(user.skill_fail_prob(shearing_skill, 40, shearing_skill_req)) + handle_shearing_failure(user, critter) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] starts shearing \the [critter]."), + SPAN_NOTICE("You start shearing \the [critter].") + ) + if(!user.do_skilled(4 SECONDS, shearing_skill)) + user.visible_message( + SPAN_NOTICE("\The [user] stops shearing \the [critter]."), + SPAN_NOTICE("You stop shearing \the [critter].") + ) + return TRUE + + if(QDELETED(user) || QDELETED(critter) || QDELETED(shears) || user.get_active_held_item() != shears) + return TRUE + + if(critter.get_automove_target()) + to_chat(user, SPAN_WARNING("Wait for \the [critter] to stop moving before you try shearing it.")) + return TRUE + + if(!has_fleece) + to_chat(user, SPAN_WARNING("\The [critter] is not ready to be shorn again yet.")) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] finishes shearing \the [critter]."), + SPAN_NOTICE("You finish shearing \the [critter].") + ) + + new fleece_type(get_turf(critter), fleece_material.type, critter) + + has_fleece = FALSE + next_fleece = world.time + fleece_time + + // Update fleeced simple animals with overlay. + if(istype(holder, /mob/living/simple_animal)) + var/mob/living/simple_animal/animal = holder + LAZYREMOVE(animal.draw_visible_overlays, "fleece") + + if(!is_processing) + START_PROCESSING(SSprocessing, src) + critter.try_refresh_visible_overlays() + return TRUE + +/datum/extension/shearable/proc/handle_shearing_failure(mob/user, mob/living/critter) + critter?.ai?.retaliate() diff --git a/code/datums/extensions/state_machine.dm b/code/datums/extensions/state_machine.dm new file mode 100644 index 000000000000..edba84c7965d --- /dev/null +++ b/code/datums/extensions/state_machine.dm @@ -0,0 +1,101 @@ +// List and procs for caching state machine instances. +var/global/list/state_machines = list() + +/proc/get_state_machine(var/datum/holder, var/base_type) + if(istype(holder) && base_type && holder.has_state_machine) + var/list/machines = global.state_machines[holder] + return islist(machines) && machines[base_type] + +/proc/add_state_machine(var/datum/holder, var/datum/state_machine/fsm_type) + if(istype(holder) && fsm_type) + var/list/machines = global.state_machines[holder] + if(!islist(machines)) + machines = list() + global.state_machines[holder] = machines + var/base_type = fsm_type::base_type + if(!machines[base_type]) + var/datum/state_machine/machine = new fsm_type(holder) + machines[base_type] = machine + holder.has_state_machine = TRUE + return machine + +/proc/remove_state_machine(var/datum/holder, var/base_type) + if(istype(holder) && base_type && holder.has_state_machine) + var/list/machines = global.state_machines[holder] + if(length(machines)) + machines -= base_type + if(!length(machines)) + global.state_machines -= holder + holder.has_state_machine = FALSE + return TRUE + return FALSE + +// This contains the current state of the FSM and should be held by whatever the FSM is controlling. +// Unlike the individual states and their transitions, the state machine objects are not singletons, and hence aren't `/decl`s. +/datum/state_machine + var/weakref/holder_ref + var/base_type = /datum/state_machine + var/expected_type = /datum + var/decl/state/current_state = null // Acts both as a ref to the current state and holds which state it will default to on init. + +/datum/state_machine/New(var/datum/_holder) + ..() + if(!istype(_holder, expected_type)) + PRINT_STACK_TRACE("Non-[expected_type] holder supplied to [type] New().") + else + holder_ref = weakref(_holder) + set_state(current_state) + +/datum/state_machine/Destroy() + current_state = null + return ..() + +// Resets back to our initial state. +/datum/state_machine/proc/reset() + var/datum/holder_instance = get_holder() + if(istype(current_state)) + current_state.exited_state(holder_instance) + current_state = initial(current_state) + if(ispath(current_state, /decl/state)) + current_state = GET_DECL(current_state) + current_state.entered_state(holder_instance) + else + current_state = null + return current_state + +// Retrieve and validate our holder instance from the cached weakref. +/datum/state_machine/proc/get_holder() + var/datum/holder = holder_ref?.resolve() + if(istype(holder) && !QDELETED(holder)) + return holder + +// Makes the FSM enter a new state, if it can, based on it's current state, that state's transitions, and the holder's status. +// Call it in the holder's `process()`, or whenever you need to. +/datum/state_machine/proc/evaluate() + var/datum/holder_instance = get_holder() + var/list/options = current_state.get_open_transitions(holder_instance) + if(LAZYLEN(options)) + var/decl/state_transition/choice = choose_transition(options) + current_state.exited_state(holder_instance) + current_state = choice.target + current_state.entered_state(holder_instance) + return current_state + +// Decides which transition to walk into, to the next state. +// By default it chooses the first one on the list. +/datum/state_machine/proc/choose_transition(list/valid_transitions) + return valid_transitions[1] + +// Forces the FSM to switch to a specific state, no matter what. +// Use responsibly. +/datum/state_machine/proc/set_state(new_state_type) + var/datum/holder_instance = get_holder() + if(istype(current_state)) + current_state.exited_state(holder_instance) + if(ispath(new_state_type)) + current_state = GET_DECL(new_state_type) + else // need to include null here, so we can't do an istype + current_state = new_state_type + if(istype(current_state)) + current_state.entered_state(holder_instance) + return current_state diff --git a/code/datums/footsteps.dm b/code/datums/footsteps.dm index 771bf0aadc22..3530bbbc082f 100644 --- a/code/datums/footsteps.dm +++ b/code/datums/footsteps.dm @@ -86,3 +86,10 @@ 'sound/effects/footstep/sand2.ogg', 'sound/effects/footstep/sand3.ogg', 'sound/effects/footstep/sand4.ogg') + +/decl/footsteps/mud + footstep_sounds = list( + 'sound/effects/footstep/mud1.ogg', + 'sound/effects/footstep/mud2.ogg', + 'sound/effects/footstep/mud3.ogg', + 'sound/effects/footstep/mud4.ogg') \ No newline at end of file diff --git a/code/datums/genetics/genetic_conditions.dm b/code/datums/genetics/genetic_conditions.dm new file mode 100644 index 000000000000..3b0a80e7532c --- /dev/null +++ b/code/datums/genetics/genetic_conditions.dm @@ -0,0 +1,128 @@ +/decl/genetic_condition + /// Descriptive name, used in VV panel. + var/name + /// Verb to be added or removed on activate/deactivate + var/grant_verb + /// Message shown when the gene is activated. + var/activation_message + /// Message shown when the gene is deactivated. + var/deactivation_message + /// State to use for underlays. + var/underlay_state + /// Icon to pull mob underlays from. + var/underlay_icon = 'icons/effects/genetics.dmi' + /// Type that this gene can apply to. + var/expected_type = /mob/living/human + /// Required return result from isSynthetic() for the gene to activate, if not null. + var/check_synthetic = FALSE + /// Set to FALSE if mob snapshots should not include this condition. + var/is_heritable = TRUE + +/decl/genetic_condition/proc/activate_condition(mob/living/M) + if(istype(M, expected_type) && M.can_have_genetic_conditions()) + if(!isnull(check_synthetic) && M.isSynthetic() != check_synthetic) + return FALSE + if(grant_verb) + M.verbs |= grant_verb + if(activation_message) + to_chat(M, SPAN_NOTICE(activation_message)) + return TRUE + return FALSE + +/decl/genetic_condition/proc/deactivate_condition(mob/living/M) + if(istype(M, expected_type) && M.can_have_genetic_conditions()) + if(!isnull(check_synthetic) && M.isSynthetic() != check_synthetic) + return FALSE + if(grant_verb) + M.verbs -= grant_verb + if(deactivation_message) + to_chat(M, SPAN_NOTICE(deactivation_message)) + return TRUE + return FALSE + +/decl/genetic_condition/proc/get_mob_overlay() + if(underlay_icon && underlay_state) + return overlay_image(underlay_icon, underlay_state) + +/decl/genetic_condition/superpower + abstract_type = /decl/genetic_condition/superpower + +/decl/genetic_condition/superpower/no_breath + name = "No Breathing" + activation_message = "You feel no need to breathe." + +/decl/genetic_condition/superpower/remoteview + name = "Remote Viewing" + grant_verb = /mob/living/human/proc/remoteobserve + activation_message = "Your mind expands." + +/decl/genetic_condition/superpower/running + name = "Super Speed" + activation_message = "Your leg muscles pulsate." + +/decl/genetic_condition/superpower/remotetalk + name = "Telepathy" + grant_verb = /mob/living/human/proc/remotesay + activation_message = "You expand your mind outwards." + +/decl/genetic_condition/superpower/cold_resist + name = "Cold Resistance" + underlay_state = "fire_s" + activation_message = "Your body is filled with warmth." + +/decl/genetic_condition/superpower/noprints + name = "No Prints" + activation_message = "Your fingers feel numb." + +/decl/genetic_condition/superpower/xray + name = "X-Ray Vision" + activation_message = "The walls suddenly disappear." + +/decl/genetic_condition/superpower/space_resist + name = "Space Resistance" + activation_message = "Your skin feels strange." + +/decl/genetic_condition/disability + abstract_type = /decl/genetic_condition/disability + +/decl/genetic_condition/disability/clumsy + name = "Clumsy" + +/decl/genetic_condition/disability/nearsighted + name = "Nearsighted" + +/decl/genetic_condition/disability/epilepsy + name = "Epilepsy" + +/decl/genetic_condition/disability/coughing + name = "Coughing" + +/decl/genetic_condition/disability/tourettes + name = "Tourettes" + +/decl/genetic_condition/disability/nervous + name = "Nervous" + +/decl/genetic_condition/disability/blinded + name = "Blinded" + check_synthetic = null + +/decl/genetic_condition/disability/muted + name = "Mute" + check_synthetic = null + +/decl/genetic_condition/disability/deafened + name = "Deafened" + check_synthetic = null + +/decl/genetic_condition/husk + name = "Husk" + +/decl/genetic_condition/husk/activate_condition(mob/living/M) + . = ..() + if(.) + SET_FACIAL_HAIR_STYLE(M, /decl/sprite_accessory/facial_hair/shaved, TRUE) + SET_HAIR_STYLE(M, /decl/sprite_accessory/hair/bald, TRUE) + for(var/obj/item/organ/external/E in M.get_external_organs()) + E.status |= ORGAN_DISFIGURED + M.update_body(TRUE) \ No newline at end of file diff --git a/code/datums/graph/graph.dm b/code/datums/graph/graph.dm index 6bfa0c76ca16..1610a6b4397a 100644 --- a/code/datums/graph/graph.dm +++ b/code/datums/graph/graph.dm @@ -1,11 +1,10 @@ /datum/graph - var/list/nodes - var/list/edges + VAR_PRIVATE/list/nodes + VAR_PRIVATE/list/edges - var/list/pending_connections - var/list/pending_disconnections - - var/processing + VAR_PRIVATE/list/pending_connections + VAR_PRIVATE/list/pending_disconnections + VAR_PRIVATE/list/pending_movements /datum/graph/New(var/list/nodes, var/list/edges, var/previous_owner = null) if(!length(nodes)) @@ -27,63 +26,99 @@ var/datum/node/node = n node.graph = src -/datum/graph/Destroy() - if(length(nodes) || LAZYLEN(pending_connections) || LAZYLEN(pending_disconnections)) - crash_with("Prevented attempt to delete a network that still has nodes: [length(nodes)] - [LAZYLEN(pending_connections)] - [LAZYLEN(pending_disconnections)]") +/datum/graph/Destroy(forced) + if(!forced && (length(nodes) || LAZYLEN(pending_connections) || LAZYLEN(pending_disconnections))) + PRINT_STACK_TRACE("Prevented attempt to delete a network that still has nodes: [length(nodes)] - [LAZYLEN(pending_connections)] - [LAZYLEN(pending_disconnections)]") return QDEL_HINT_LETMELIVE . = ..() /datum/graph/proc/Connect(var/datum/node/node, var/list/neighbours, var/queue = TRUE) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + if(QDELETED(src)) + CRASH("Attempted to connect node [node] to a qdeleted graph!") if(!istype(neighbours)) neighbours = list(neighbours) if(!length(neighbours)) CRASH("Attempted to connect a node without declaring neighbours") if(length(nodes & neighbours) != length(neighbours)) CRASH("Attempted to connect a node to neighbours not in the graph") - if(LAZYISIN(pending_connections, node)) - CRASH("Attempted to connect a node already pending to be connected") - if(LAZYISIN(pending_disconnections, node)) - CRASH("Attempted to connect a node already pending to be disconnected") - LAZYSET(pending_connections, node, neighbours) + var/list/neighbours_to_disconnect = LAZYACCESS(pending_disconnections, node) + if(neighbours_to_disconnect) + var/list/overlap = neighbours_to_disconnect & neighbours + neighbours_to_disconnect -= overlap + neighbours -= overlap + if(neighbours_to_disconnect.len) + LAZYSET(pending_disconnections, node, neighbours_to_disconnect) + else + LAZYREMOVE(pending_disconnections, node) + + var/list/neighbours_to_connect = LAZYACCESS(pending_connections, node) + if(neighbours_to_connect) + neighbours |= neighbours_to_connect + + if(neighbours.len) + LAZYSET(pending_connections, node, neighbours) + if(queue) SSgraphs_update.Queue(src) return TRUE -/datum/graph/proc/Disconnect(var/datum/node/node, var/list/neighbours_to_disconnect, var/queue = TRUE) - if(neighbours_to_disconnect && !istype(neighbours_to_disconnect)) - neighbours_to_disconnect = list(neighbours_to_disconnect) - if(length(neighbours_to_disconnect) && length(nodes & neighbours_to_disconnect) != length(neighbours_to_disconnect)) - CRASH("Attempted keep a node connected to neighbours not in the graph: [json_encode(nodes)], [json_encode(neighbours_to_disconnect)]") - if(LAZYISIN(pending_connections, node)) - CRASH("Attempted to disconnect a node already pending to be connected") - if(LAZYISIN(pending_disconnections, node)) - CRASH("Attempted to disconnect a node already pending to be disconnected") - if(!(node in nodes)) +/datum/graph/proc/Disconnect(var/datum/node/node, var/list/neighbours, var/queue = TRUE) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + if(neighbours && !istype(neighbours)) + neighbours = list(neighbours) + neighbours = neighbours || edges[node] // A null list of neighbours implies all neighbours + if(!neighbours && length(nodes) == 1) + neighbours = list() // A graph with only a single node is not likely to have edges and then, and only then, we allow neighbours to be null + if(length(neighbours) && length(nodes & neighbours) != length(neighbours)) + CRASH("Attempted keep a node connected to neighbours not in the graph: [json_encode(nodes)], [json_encode(neighbours)]") + if(!(node in nodes) && !(node in pending_connections)) CRASH("Attempted disconnect a node that is not in the graph") - LAZYSET(pending_disconnections, node, neighbours_to_disconnect) + var/list/neighbours_to_connect = LAZYACCESS(pending_connections, node) + if(neighbours_to_connect) + var/list/overlap = neighbours_to_connect & neighbours + neighbours_to_connect -= overlap + neighbours -= overlap + if(neighbours_to_connect.len) + LAZYSET(pending_connections, node, neighbours_to_connect) + else + LAZYREMOVE(pending_connections, node) + + var/list/neighbours_to_disconnect = LAZYACCESS(pending_disconnections, node) + if(neighbours_to_disconnect) + neighbours |= neighbours_to_disconnect + + LAZYSET(pending_disconnections, node, neighbours) + if(queue) SSgraphs_update.Queue(src) return TRUE /datum/graph/proc/Merge(var/datum/graph/other) + SHOULD_NOT_OVERRIDE(TRUE) + PRIVATE_PROC(TRUE) if(!other) return OnMerge(other) + for(var/n in other.nodes) var/datum/node/node = n node.graph = src nodes += other.nodes edges += other.edges + other.ProcessPendingMovements() for(var/other_node_to_be_connected in other.pending_connections) var/other_neighbours = other.pending_connections[other_node_to_be_connected] - Connect(other_node_to_be_connected, other_neighbours, FALSE) + pending_connections[other_node_to_be_connected] = other_neighbours for(var/other_node_to_be_disconnected in other.pending_disconnections) var/other_formed_neighbours = other.pending_disconnections[other_node_to_be_disconnected] - Disconnect(other_node_to_be_disconnected, other_formed_neighbours, FALSE) + pending_disconnections[other_node_to_be_disconnected] = other_formed_neighbours other.nodes.Cut() other.edges.Cut() @@ -93,10 +128,13 @@ // Subtypes that need to handle merging in specific ways should override this proc /datum/graph/proc/OnMerge(var/datum/graph/other) + SHOULD_NOT_SLEEP(TRUE) return // Here subgraphs is a list of a list of nodes /datum/graph/proc/Split(var/list/subgraphs) + SHOULD_NOT_OVERRIDE(TRUE) + PRIVATE_PROC(TRUE) var/list/new_subgraphs = list() for(var/subgraph in subgraphs) if(length(subgraph) == 1) @@ -114,9 +152,26 @@ // Subtypes that need to handle splitting in specific ways should override this proc // The original graph still has the same nodes/edges as before the split but will be deleted after this proc returns /datum/graph/proc/OnSplit(var/list/datum/graph/subgraphs) + SHOULD_NOT_SLEEP(TRUE) return +/datum/graph/proc/Moved(var/datum/node/physical/node) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + if(!istype(node)) + CRASH("Invalid node type: [log_info_line(node)]") + if(!(node in nodes) && !(node in pending_connections)) + CRASH("Attempted move a node that is not in the graph") + + LAZYDISTINCTADD(pending_movements, node) + SSgraphs_update.Queue(src) + /datum/graph/proc/ProcessPendingConnections() + SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + + ProcessPendingMovements() + while(LAZYLEN(pending_connections)) var/datum/node/N = pending_connections[pending_connections.len] var/list/new_neighbours = pending_connections[N] @@ -138,19 +193,28 @@ edges[new_neighbour] = neighbour_edges neighbour_edges |= N - if(!LAZYLEN(pending_disconnections)) - return + LAZYCLEARLIST(pending_connections) for(var/pending_node_disconnect in pending_disconnections) - var/pending_edge_disconnects = pending_disconnections[pending_node_disconnect] || edges[pending_node_disconnect] + var/pending_edge_disconnects = pending_disconnections[pending_node_disconnect] for(var/connected_node in pending_edge_disconnects) edges[connected_node] -= pending_node_disconnect + if(!length(edges[connected_node])) edges -= connected_node - edges[pending_node_disconnect] -= pending_edge_disconnects + // If the other node also wanted to disconnect from us, this has now been handled + var/other_pending_edge_disconnects = pending_disconnections[connected_node] + if(other_pending_edge_disconnects) + other_pending_edge_disconnects -= src + if(!length(other_pending_edge_disconnects)) + pending_disconnections -= connected_node + + if(edges[pending_node_disconnect]) + edges[pending_node_disconnect] -= pending_edge_disconnects if(!length(edges[pending_node_disconnect])) edges -= pending_node_disconnect + LAZYCLEARLIST(pending_disconnections) var/list/subgraphs = list() @@ -161,16 +225,51 @@ var/checked_nodes = list() var/list/nodes_to_traverse = list(root_node) while(length(nodes_to_traverse)) - var/node_to_check = nodes_to_traverse[nodes_to_traverse.len] + var/datum/node/node_to_check = nodes_to_traverse[nodes_to_traverse.len] nodes_to_traverse.len-- + if(QDELETED(node_to_check)) + continue checked_nodes += node_to_check nodes_to_traverse |= ((edges[node_to_check] || list()) - checked_nodes) - all_nodes -= checked_nodes - subgraphs[++subgraphs.len] = checked_nodes + if(length(checked_nodes)) + all_nodes -= checked_nodes + subgraphs[++subgraphs.len] = checked_nodes if(length(subgraphs) == 1) - return - Split(subgraphs) + if(!length(nodes)) + qdel(src) + else + Split(subgraphs) + +/datum/graph/proc/ProcessPendingMovements() + SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + PRIVATE_PROC(TRUE) + + while(LAZYLEN(pending_movements)) + var/datum/node/physical/N = pending_movements[pending_movements.len] + pending_movements.len-- + if(!N.holder.CheckNodeNeighbours()) + PRINT_STACK_TRACE("Invalid override of CheckNodeNeighbours() - Shall return true: [log_info_line(N.holder)]") + + LAZYCLEARLIST(pending_movements) + +/datum/graph/proc/ConnectedNodes(var/datum/node/node) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + RETURN_TYPE(/list) + if(!(node in nodes)) + CRASH("Attempted check a node that is not in the graph") + + var/list/neighbours = edges[node] + if(length(nodes) == 1) // A graph with only a single node is not likely to have edges and then, and only then, we allow neighbours to be null + return neighbours ? neighbours.Copy() : list() + else + return neighbours.Copy() /datum/graph/get_log_info_line() return "[..()] (nodes: [log_info_line(nodes)]) (edges: [log_info_line(edges)])" + +/atom/proc/CheckNodeNeighbours() + SHOULD_NOT_SLEEP(TRUE) + return FALSE diff --git a/code/datums/graph/node.dm b/code/datums/graph/node.dm index ae173ed86a27..a08cad4d2bf1 100644 --- a/code/datums/graph/node.dm +++ b/code/datums/graph/node.dm @@ -5,6 +5,19 @@ graph.Disconnect(src) return ..() +/datum/node/proc/Connect(var/list/nodes) + var/datum/node/N = nodes + if(istype(nodes)) + N = nodes[1] + N.graph.Connect(src, nodes) + +/datum/node/proc/Disconnect(nodes) + graph.Disconnect(src, nodes) + +/datum/node/proc/ConnectedNodes() + return graph.ConnectedNodes(src) + + /datum/node/physical var/atom/holder @@ -17,3 +30,7 @@ /datum/node/physical/Destroy() holder = null . = ..() + +/datum/node/physical/proc/Moved() + graph.Moved(src) + diff --git a/code/datums/helper_datums/construction_datum.dm b/code/datums/helper_datums/construction_datum.dm deleted file mode 100644 index 158a22fc090f..000000000000 --- a/code/datums/helper_datums/construction_datum.dm +++ /dev/null @@ -1,99 +0,0 @@ -#define FORWARD -1 -#define BACKWARD 1 - -/datum/construction - var/list/steps - var/atom/holder - var/result - var/list/steps_desc - -/datum/construction/New(atom) - ..() - holder = atom - if(!holder) //don't want this without a holder - spawn - qdel(src) - set_desc(steps.len) - -/datum/construction/proc/next_step() - steps.len-- - if(!steps.len) - spawn_result() - else - set_desc(steps.len) - -/datum/construction/proc/action(atom/used_atom,mob/user) - -/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only - var/valid_step = is_right_key(used_atom) - if(valid_step) - if(custom_action(valid_step, used_atom, user)) - next_step() - return 1 - return 0 - -/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type. - var/list/L = steps[steps.len] - if(istype(used_atom, L["key"])) - return steps.len - return 0 - -/datum/construction/proc/custom_action(step, used_atom, user) - return 1 - -/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one. - for(var/i=1;i<=steps.len;i++) - var/list/L = steps[i]; - if(istype(used_atom, L["key"])) - if(custom_action(i, used_atom, user)) - steps[i]=null;//stupid byond list from list removal... - listclearnulls(steps); - if(!steps.len) - spawn_result() - return 1 - return 0 - - -/datum/construction/proc/spawn_result() - if(result) - new result(get_turf(holder)) - spawn() - qdel(holder) - return - -/datum/construction/proc/set_desc(index as num) - var/list/step = steps[index] - holder.desc = step["desc"] - -/datum/construction/reversible - var/index - -/datum/construction/reversible/New(atom) - ..() - index = steps.len - -/datum/construction/reversible/proc/update_index(diff as num) - index+=diff - if(index==0) - spawn_result() - else - set_desc(index) - -/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step - var/list/L = steps[index] - if(istype(used_atom, L["key"])) - return FORWARD //to the first step -> forward - else if(L["backkey"] && istype(used_atom, L["backkey"])) - return BACKWARD //to the last step -> backwards - return 0 - -/datum/construction/reversible/check_step(atom/used_atom,mob/user) - var/diff = is_right_key(used_atom) - if(diff) - if(custom_action(index, diff, used_atom, user)) - update_index(diff) - return 1 - return 0 - -/datum/construction/reversible/custom_action(index, diff, used_atom, user) - return 1 \ No newline at end of file diff --git a/code/datums/helper_datums/dist_check.dm b/code/datums/helper_datums/dist_check.dm index 121b4b1d2f63..47aa457f49e8 100644 --- a/code/datums/helper_datums/dist_check.dm +++ b/code/datums/helper_datums/dist_check.dm @@ -18,7 +18,7 @@ /decl/dist_check/connected_z_level/within_dist(var/atom/a, var/atom/b) var/turf/turf_a = get_turf(a) var/turf/turf_b = get_turf(b) - return turf_a && turf_b && ARE_Z_CONNECTED(turf_a.z, turf_b.z) + return turf_a && turf_b && LEVELS_ARE_Z_CONNECTED(turf_a.z, turf_b.z) /decl/dist_check/omni/within_dist() return TRUE diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index bd2a52463ddf..37e7fb12bea6 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -4,7 +4,6 @@ var/global/datum/getrev/revdata = new() var/branch var/revision var/date - var/showinfo /datum/getrev/New() var/list/head_branch = file2list(".git/HEAD", "\n") @@ -37,10 +36,10 @@ var/global/datum/getrev/revdata = new() to_chat(src, "Client Version: [byond_version]") if(revdata.revision) var/server_revision = revdata.revision - if(config.githuburl) - server_revision = "[server_revision]" + if(get_config_value(/decl/config/text/githuburl)) + server_revision = "[server_revision]" to_chat(src, "Server Revision: [server_revision] - [revdata.branch] - [revdata.date]") else to_chat(src, "Server Revision: Revision Unknown") to_chat(src, "Game ID: [game_id]") - to_chat(src, "Current map: [GLOB.using_map.full_name]") \ No newline at end of file + to_chat(src, "Current map: [global.using_map.full_name]") \ No newline at end of file diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index ceec1cbd5562..138e0c1d5093 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -1,5 +1,5 @@ /decl/teleport - var/static/list/teleport_blacklist = list(/obj/item/disk/nuclear, /obj/item/storage/backpack/holding, /obj/effect/sparks) //Items that cannot be teleported, or be in the contents of someone who is teleporting. + var/static/list/teleport_blacklist = list(/obj/item/disk/nuclear, /obj/item/backpack/holding, /obj/effect/sparks) //Items that cannot be teleported, or be in the contents of someone who is teleporting. /decl/teleport/proc/teleport(var/atom/target, var/atom/destination, var/precision = 0) if(!can_teleport(target,destination)) @@ -10,7 +10,7 @@ /decl/teleport/proc/teleport_target(var/atom/movable/target, var/atom/destination, var/precision) var/list/possible_turfs = circlerangeturfs(destination, precision) - destination = safepick(possible_turfs) + destination = SAFEPICK(possible_turfs) target.forceMove(destination) if(isliving(target)) @@ -19,29 +19,49 @@ var/atom/movable/buckled = L.buckled buckled.forceMove(destination) +/decl/teleport/proc/can_reach_z(var/oz, var/tz) -/decl/teleport/proc/can_teleport(var/atom/movable/target, var/atom/destination) - if(!destination || !target || !target.loc || destination.z > max_default_z_level()) - return 0 + if(isAdminLevel(oz)) + return isAdminLevel(tz) || isStationLevel(tz) || isContactLevel(tz) - if(is_type_in_list(target, teleport_blacklist)) - return 0 + var/list/accessible_z_levels = SSmapping.get_connected_levels(oz) + var/obj/effect/overmap/sector = global.overmap_sectors[oz] + if(sector) + + var/list/neighbors_to_add = list() + for(var/obj/effect/overmap/visitable/neighbor in sector.loc) + neighbors_to_add |= neighbor + + var/list/neighboring_sectors = list() + while(length(neighbors_to_add)) + var/obj/effect/overmap/visitable/neighbor = neighbors_to_add[1] + neighbors_to_add -= neighbor + neighboring_sectors |= neighbor + for(var/obj/effect/overmap/visitable/subneighbor in neighbor) + if(!(subneighbor in neighboring_sectors)) + neighbors_to_add |= subneighbor - for(var/type in teleport_blacklist) - if(!isemptylist(target.search_contents_for(type))) - return 0 - return 1 + for(var/obj/effect/overmap/visitable/neighbor in neighboring_sectors) + accessible_z_levels |= neighbor.map_z -/decl/teleport/sparks - var/datum/effect/effect/system/spark_spread/spark = new + return (tz in accessible_z_levels) + +/decl/teleport/proc/can_teleport(var/atom/movable/target, var/atom/destination) + if(!destination || !target?.loc) + return FALSE + if(!can_reach_z(target.z, destination.z)) + return FALSE + if(is_type_in_list(target, teleport_blacklist)) + return FALSE + for(var/thing in target) + if(is_type_in_list(thing, teleport_blacklist)) + return FALSE + return TRUE /decl/teleport/sparks/proc/do_spark(var/atom/target) if(!target.simulated) return - var/turf/T = get_turf(target) - spark.set_up(5,1,target) - spark.attach(T) - spark.start() + spark_at(get_turf(target), amount=5, cardinal_only = TRUE, holder=target) /decl/teleport/sparks/teleport_target(var/atom/target, var/atom/destination, var/precision) do_spark(target) @@ -49,5 +69,5 @@ do_spark(target) /proc/do_teleport(var/atom/movable/target, var/atom/destination, var/precision = 0, var/type = /decl/teleport/sparks) - var/decl/teleport/tele = decls_repository.get_decl(type) + var/decl/teleport/tele = GET_DECL(type) tele.teleport(target, destination, precision) diff --git a/code/datums/hierarchy.dm b/code/datums/hierarchy.dm index 01f57e7770f5..361295e09ae3 100644 --- a/code/datums/hierarchy.dm +++ b/code/datums/hierarchy.dm @@ -1,31 +1,36 @@ /decl/hierarchy + abstract_type = /decl/hierarchy + decl_flags = DECL_FLAG_ALLOW_ABSTRACT_INIT // for the children list var/name = "Hierarchy" - var/hierarchy_type var/decl/hierarchy/parent var/list/decl/hierarchy/children + /// The cached result of get_descendants(). Should not be mutated. + VAR_PRIVATE/list/decl/hierarchy/_descendants + var/expected_type /decl/hierarchy/Initialize() children = list() - for(var/subtype in subtypesof(type)) - var/decl/hierarchy/child = decls_repository.get_decl(subtype) // Might be a grandchild, which has already been handled. - if(child.parent_type == type) - dd_insertObjectList(children, child) - child.parent = src - return ..() + if(ispath(expected_type)) + for(var/subtype in subtypesof(type)) + var/decl/hierarchy/child = GET_DECL(subtype) // Might be a grandchild, which has already been handled. + if(child.parent_type == type && istype(child, expected_type)) + dd_insertObjectList(children, child) + child.parent = src + . = ..() /decl/hierarchy/proc/is_category() - return hierarchy_type == type || children.len + return length(children) -/decl/hierarchy/proc/is_hidden_category() - return hierarchy_type == type - -/decl/hierarchy/proc/get_descendents() +/decl/hierarchy/proc/get_descendants() if(!children) return - . = children.Copy() + if(_descendants) + return _descendants + _descendants = children.Copy() for(var/decl/hierarchy/child in children) if(child.children) - . += child.get_descendents() + _descendants |= child.get_descendants() + return _descendants /decl/hierarchy/dd_SortValue() return name diff --git a/code/datums/hostility/hostility.dm b/code/datums/hostility/hostility.dm new file mode 100644 index 000000000000..12106d4250ab --- /dev/null +++ b/code/datums/hostility/hostility.dm @@ -0,0 +1,63 @@ +// A singleton useful for recycling hostility logic in things such as mobs or turrets. +/decl/hostility + +// Returns a value determining whether or not whatever is calling should attack the target. +// Don't override this, go override `can_special_target()`, as this proc has 'the basics' that everything should use. +/decl/hostility/proc/can_target(atom/holder, atom/movable/target) + SHOULD_NOT_OVERRIDE(TRUE) + . = TRUE + if(!istype(target)) + return FALSE + if(isobserver(target)) + return FALSE + + if(isliving(target)) + var/mob/living/target_mob = target + if(target_mob.stat) + return FALSE + + if(isliving(holder)) + var/mob/holder_mob = holder + if(target_mob.faction == holder_mob.faction) + return FALSE + + return can_special_target(holder, target) + +// Override this for subtypes. +/decl/hostility/proc/can_special_target(atom/holder, atom/movable/target) + return TRUE + + +// Aggressive towards humans wearing the opposite lasertag vest. +/decl/hostility/laser_tag + var/enemy_vest_type = null + +/decl/hostility/laser_tag/can_special_target(atom/holder, atom/movable/target) + if(ishuman(target)) + var/mob/living/human/H = target + if(enemy_vest_type && istype(H.get_equipped_item(slot_wear_suit_str), enemy_vest_type)) + return TRUE + return FALSE + +/decl/hostility/laser_tag/red + enemy_vest_type = /obj/item/clothing/suit/bluetag + +/decl/hostility/laser_tag/blue + enemy_vest_type = /obj/item/clothing/suit/redtag + + +// Hostile to whatever is too sus. +/decl/hostility/securitron + var/threat_level_threshold = 4 + var/access_check = access_security + var/check_weapons = FALSE + var/check_no_record = FALSE + var/check_wanted = TRUE + +/decl/hostility/securitron/can_special_target(atom/holder, atom/movable/target) + if(isliving(target)) + var/mob/living/L = target + if(iscuffed(L)) + return FALSE + return L.assess_perp(holder, access_check, check_weapons, check_no_record, check_wanted) < threat_level_threshold + return FALSE \ No newline at end of file diff --git a/code/datums/inventory_slots/_inventory_slot.dm b/code/datums/inventory_slots/_inventory_slot.dm new file mode 100644 index 000000000000..3567e31a8486 --- /dev/null +++ b/code/datums/inventory_slots/_inventory_slot.dm @@ -0,0 +1,176 @@ +/datum/inventory_slot + + var/slot_name = "Unknown" + var/slot_id + var/slot_state + var/slot_dir + + var/ui_loc + var/ui_label + var/overlay_slot + + var/obj/item/_holding + var/list/drop_slots_on_unequip + var/covering_flags = 0 + var/covering_slots + var/can_be_hidden = FALSE + var/skip_on_inventory_display = FALSE + var/skip_on_strip_display = FALSE + var/requires_slot_flags + var/requires_organ_tag + var/quick_equip_priority = 0 // Higher priority means it will be checked first. If null, will not be considered for quick equip. + /// Additional slot ID(s) to add in quick equip. Will always be added at the lowest priority. + var/list/additional_quick_equip_slots + /// What depth of fluid is necessary for an item in this slot to be considered submerged? + var/fluid_height = FLUID_SHALLOW // we're treating FLUID_SHALLOW as waist level, basically + + var/mob_overlay_layer + var/alt_mob_overlay_layer + + var/use_overlay_fallback_slot = TRUE + +/datum/inventory_slot/Destroy(force) + _holding = null + return ..() + +/datum/inventory_slot/proc/equipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE, var/delete_old_item = TRUE) + + // Save any preexisting item to clean up later. + var/atom/movable/held = get_equipped_item() + + // Set slot vars. + set_slot(prop) + prop.forceMove(user) + prop.hud_layerise() + prop.equipped(user, slot_id) + prop.compile_overlays() // avoid world overlays on inventory state and vice versa + + // Clean up the preexisting item. + if(held) + // Force the unequip call because it's technically no longer equipped anymore. + unequipped(user, held, redraw_mob) + user.drop_from_inventory(held) + if(delete_old_item && !QDELETED(held)) + qdel(held) + + // Redraw overlays if needed. + update_mob_equipment_overlay(user, prop, redraw_mob) + return TRUE + +/datum/inventory_slot/proc/unequipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + SHOULD_CALL_PARENT(TRUE) + // Only empty the slot if it's actually our equipped item. + // Sometimes this runs on the old item after a new item is equipped in-place (like via the loadout) + // so we need to check this. + if(prop == get_equipped_item()) + clear_slot() + for(var/slot in drop_slots_on_unequip) + var/datum/inventory_slot/slot_to_drop = user.get_inventory_slot_datum(slot) + if(!slot_to_drop) + continue + var/obj/item/thing = slot_to_drop.get_equipped_item() + if(thing && !slot_to_drop.can_equip_to_slot(user, thing, TRUE)) + user.drop_from_inventory(thing) + update_mob_equipment_overlay(user, prop, redraw_mob) + return TRUE + +/datum/inventory_slot/proc/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + if(!mob_overlay_layer || !slot_id) + return + if(alt_mob_overlay_layer) + if(_holding) + user.set_current_mob_overlay((_holding.use_alt_layer ? alt_mob_overlay_layer : mob_overlay_layer), _holding.get_mob_overlay(user, slot_id, use_fallback_if_icon_missing = use_overlay_fallback_slot), FALSE) + user.set_current_mob_overlay((_holding.use_alt_layer ? mob_overlay_layer : alt_mob_overlay_layer), null, redraw_mob) + else + user.set_current_mob_overlay(mob_overlay_layer, null, FALSE) + user.set_current_mob_overlay(alt_mob_overlay_layer, null, redraw_mob) + else + user.set_current_mob_overlay(mob_overlay_layer, _holding?.get_mob_overlay(user, slot_id, use_fallback_if_icon_missing = use_overlay_fallback_slot), redraw_mob) + +/datum/inventory_slot/proc/set_slot(var/obj/item/prop) + _holding = prop + if(_holding) + _holding.screen_loc = ui_loc + +/datum/inventory_slot/proc/clear_slot() + if(_holding) + _holding.screen_loc = null + _holding = null + +/datum/inventory_slot/proc/is_accessible(var/mob/user, var/obj/item/prop, var/disable_warning) + if(!covering_flags) + return TRUE + var/list/covering_items = get_covering_items(user) + if(!length(covering_items)) + return TRUE + var/coverage_flags = (prop.body_parts_covered|covering_flags) + for(var/obj/item/covering in covering_items) + if(covering.body_parts_covered & coverage_flags) + if(!disable_warning) + to_chat(user, SPAN_WARNING("\The [covering] is in the way.")) + return FALSE + return TRUE + +/datum/inventory_slot/proc/get_covering_items(var/mob/user) + if(!covering_slots) + return null + if(islist(covering_slots)) + for(var/covering_slot in covering_slots) + var/thing = user.get_equipped_item(covering_slot) + if(thing) + LAZYADD(., thing) + else + var/thing = user.get_equipped_item(covering_slots) + if(thing) + LAZYADD(., thing) + +/datum/inventory_slot/proc/get_covering_flags(var/mob/user) + return covering_flags + +/datum/inventory_slot/proc/get_equipped_item() + return _holding + +/datum/inventory_slot/proc/get_equipped_name() + return _holding?.name + +/datum/inventory_slot/proc/hide_slot() + if(_holding) + _holding.screen_loc = null + +/datum/inventory_slot/proc/show_slot() + if(_holding) + _holding.screen_loc = ui_loc + +/datum/inventory_slot/proc/check_has_required_organ(var/mob/user) + if(!requires_organ_tag) + return TRUE + if(islist(requires_organ_tag)) + for(var/bp in requires_organ_tag) + if(user.get_organ(bp)) + return TRUE + return user.get_organ(requires_organ_tag) + +/datum/inventory_slot/proc/equivalent_to(var/datum/inventory_slot/other_slot) + if(!istype(other_slot) || QDELETED(other_slot) || QDELETED(src)) + return FALSE + if(other_slot.type != type) + return FALSE + if(other_slot.slot_id != slot_id) + return FALSE + if(other_slot.slot_name != slot_name) + return FALSE + if(other_slot.slot_state != slot_state) + return FALSE + if(other_slot.ui_loc != ui_loc) + return FALSE + return TRUE + +/datum/inventory_slot/proc/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning, var/ignore_equipped) + return ((!_holding || (ignore_equipped || _holding == prop)) && prop && slot_id && prop_can_fit_in_slot(prop)) + +/datum/inventory_slot/proc/prop_can_fit_in_slot(var/obj/item/prop) + return (isnull(requires_slot_flags) || (requires_slot_flags & prop.slot_flags)) + +/datum/inventory_slot/proc/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding) + return "[pronouns.He] [pronouns.is] wearing [_holding.get_examine_line()]." diff --git a/code/datums/inventory_slots/inventory_gripper.dm b/code/datums/inventory_slots/inventory_gripper.dm new file mode 100644 index 000000000000..14140fc65fd1 --- /dev/null +++ b/code/datums/inventory_slots/inventory_gripper.dm @@ -0,0 +1,31 @@ +/datum/inventory_slot/gripper + // For reference, grippers do not use ui_loc, they have it set dynamically during /datum/hud/proc/rebuild_hands() + quick_equip_priority = null // you quick-equip stuff by holding it in a gripper, so this ought to be skipped + fluid_height = (FLUID_SHALLOW + FLUID_OVER_MOB_HEAD) / 2 // halfway between waist and top of head, so roughly chest level, reasoning that you can just hold it up out of the water + var/hand_sort_priority = 1 + var/dexterity = DEXTERITY_FULL + var/covering_slot_flags + /// If set, use this icon_state for the hand slot overlay; otherwise, use slot_id. + var/hand_overlay + +/datum/inventory_slot/gripper/proc/get_dexterity(var/silent) + return dexterity + +/datum/inventory_slot/gripper/GetCloneArgs() + return list(slot_id, ui_loc, overlay_slot, ui_label) + +/datum/inventory_slot/gripper/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + user.update_inhand_overlays(redraw_mob) + +/datum/inventory_slot/gripper/equipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE, var/delete_old_item = TRUE) + . = ..() + if(.) + prop.update_held_icon() + +/datum/inventory_slot/gripper/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(owner, slot_id) + return "[pronouns.He] [pronouns.is] holding [_holding.get_examine_line()] in [pronouns.his] [E?.name || lowertext(slot_name)]." + +/datum/inventory_slot/gripper/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning) + return ..() && user.check_dexterity(DEXTERITY_EQUIP_ITEM, silent = disable_warning) diff --git a/code/datums/inventory_slots/inventory_gripper_robot.dm b/code/datums/inventory_slots/inventory_gripper_robot.dm new file mode 100644 index 000000000000..11e521a8612f --- /dev/null +++ b/code/datums/inventory_slots/inventory_gripper_robot.dm @@ -0,0 +1,24 @@ +// Stub definitions for future work and to pass CI. +/datum/inventory_slot/gripper/robot + abstract_type = /datum/inventory_slot/gripper/robot + +/datum/inventory_slot/gripper/robot/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning) + var/mob/living/silicon/robot/robot = user + if(!istype(robot) || !robot.module || !(prop in robot.module.equipment)) + return FALSE + return ..() + +/datum/inventory_slot/gripper/robot/one + slot_name = "Primary Hardpoint" + slot_id = "slot_robot_one" + ui_label = "1" + +/datum/inventory_slot/gripper/robot/two + slot_name = "Secondary Hardpoint" + slot_id = "slot_robot_two" + ui_label = "2" + +/datum/inventory_slot/gripper/robot/three + slot_name = "Tertiary Hardpoint" + slot_id = "slot_robot_three" + ui_label = "3" diff --git a/code/datums/inventory_slots/inventory_gripper_subtypes.dm b/code/datums/inventory_slots/inventory_gripper_subtypes.dm new file mode 100644 index 000000000000..0205f4785b21 --- /dev/null +++ b/code/datums/inventory_slots/inventory_gripper_subtypes.dm @@ -0,0 +1,78 @@ +/datum/inventory_slot/gripper/mouth + slot_name = "Mouth" + slot_id = BP_MOUTH + requires_organ_tag = BP_HEAD + overlay_slot = BP_MOUTH + ui_label = "M" + hand_sort_priority = 3 + dexterity = DEXTERITY_SIMPLE_MACHINES | DEXTERITY_GRAPPLE | DEXTERITY_HOLD_ITEM | DEXTERITY_EQUIP_ITEM | DEXTERITY_KEYBOARDS | DEXTERITY_TOUCHSCREENS + +/datum/inventory_slot/gripper/mouth/simple + requires_organ_tag = null + +/datum/inventory_slot/gripper/mouth/can_equip_to_slot(mob/user, obj/item/prop, disable_warning, ignore_equipped) + . = ..() && prop.w_class <= user.can_pull_size + +// Mouths are used by diona nymphs and Ascent babies to eat stuff, not just hold stuff in the mouth. +/datum/inventory_slot/gripper/mouth/nymph + requires_organ_tag = null + +/datum/inventory_slot/gripper/mouth/nymph/equipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE, var/delete_old_item = TRUE) + . = ..() + if(.) + + // This means critters can hoover up beakers as a kind of impromptu chem disposal + // technique, so long as they're okay with the reagents reacting inside them. + var/prop_reagents = REAGENT_TOTAL_VOLUME(prop.reagents) + if(prop_reagents) + prop.reagents.trans_to_mob(src, prop_reagents, CHEM_INGEST) + + // It also means they can do the old school cartoon schtick of eating + // an entire sandwich and spitting up an empty plate. Ptooie. + if(istype(prop, /obj/item/food)) + var/obj/item/food/food = prop + var/trash = food.trash + _holding = null + qdel(prop) + if(trash) + equipped(user, new trash(user)) + +/datum/inventory_slot/gripper/left_hand + slot_name = "Left Hand" + slot_id = BP_L_HAND + requires_organ_tag = BP_L_HAND + overlay_slot = BP_L_HAND + ui_label = "L" + covering_slot_flags = SLOT_HAND_LEFT + +/datum/inventory_slot/gripper/right_hand + slot_name = "Right Hand" + slot_id = BP_R_HAND + requires_organ_tag = BP_R_HAND + overlay_slot = BP_R_HAND + ui_label = "R" + covering_slot_flags = SLOT_HAND_RIGHT + +/datum/inventory_slot/gripper/midlimb + slot_name = "Midlimb" + slot_id = BP_M_HAND + requires_organ_tag = BP_M_HAND + ui_label = "M" + ui_loc = "CENTER,BOTTOM+1:14" + covering_slot_flags = SLOT_HAND_LEFT|SLOT_HAND_RIGHT // todo: generalize? + +/datum/inventory_slot/gripper/upper_left_hand + slot_name = "Left Upper Hand" + slot_id = BP_L_HAND_UPPER + requires_organ_tag = BP_L_HAND_UPPER + ui_label = "UL" + hand_sort_priority = 2 + covering_slot_flags = SLOT_HAND_LEFT + +/datum/inventory_slot/gripper/upper_right_hand + slot_name = "Right Upper Hand" + slot_id = BP_R_HAND_UPPER + requires_organ_tag = BP_R_HAND_UPPER + ui_label = "UR" + hand_sort_priority = 2 + covering_slot_flags = SLOT_HAND_RIGHT diff --git a/code/datums/inventory_slots/slots/slot_back.dm b/code/datums/inventory_slots/slots/slot_back.dm new file mode 100644 index 000000000000..a2a30b9c5ba5 --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_back.dm @@ -0,0 +1,19 @@ +/datum/inventory_slot/back + slot_name = "Back" + slot_id = slot_back_str + ui_loc = ui_back + slot_state = "back" + requires_organ_tag = BP_CHEST + requires_slot_flags = SLOT_BACK + mob_overlay_layer = HO_BACK_LAYER + quick_equip_priority = 14 + fluid_height = (FLUID_SHALLOW + FLUID_OVER_MOB_HEAD) / 2 // halfway between waist and top of head, so roughly chest level + additional_quick_equip_slots = list(slot_in_backpack_str) + +/datum/inventory_slot/back/simple + requires_organ_tag = null + use_overlay_fallback_slot = FALSE + +/datum/inventory_slot/back/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding) + return "[pronouns.He] [pronouns.has] [_holding.get_examine_line()] on [pronouns.his] back." diff --git a/code/datums/inventory_slots/slots/slot_belt.dm b/code/datums/inventory_slots/slots/slot_belt.dm new file mode 100644 index 000000000000..636d8e8d8ee1 --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_belt.dm @@ -0,0 +1,28 @@ +/datum/inventory_slot/belt + slot_name = "Belt" + slot_state = "belt" + slot_id = slot_belt_str + ui_loc = ui_belt + requires_organ_tag = BP_CHEST + requires_slot_flags = SLOT_LOWER_BODY + mob_overlay_layer = HO_BELT_LAYER + alt_mob_overlay_layer = HO_BELT_LAYER_ALT + quick_equip_priority = 4 + +/datum/inventory_slot/belt/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning, var/ignore_equipped) + . = ..() + if(.) + // Things with this flag can be worn on the belt slot without a uniform. + if(prop.item_flags & ITEM_FLAG_IS_BELT) + return TRUE + // Otherwise, if they have a uniform slot, they need a uniform to wear a belt. + var/datum/inventory_slot/check_slot = user.get_inventory_slot_datum(slot_w_uniform_str) + if(!check_slot || check_slot.get_equipped_item()) + return TRUE + if(!disable_warning) + to_chat(user, SPAN_WARNING("You need to be wearing something on your body before you can wear \the [prop].")) + return FALSE + +/datum/inventory_slot/belt/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding) + return "[pronouns.He] [pronouns.has] [_holding.get_examine_line()] about [pronouns.his] waist." diff --git a/code/datums/inventory_slots/slots/slot_cuffs.dm b/code/datums/inventory_slots/slots/slot_cuffs.dm new file mode 100644 index 000000000000..5bbac50af5df --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_cuffs.dm @@ -0,0 +1,27 @@ +/datum/inventory_slot/handcuffs + slot_name = "Handcuffs" + slot_id = slot_handcuffed_str + skip_on_inventory_display = TRUE // Handcuffs have their own logic on examine. + skip_on_strip_display = TRUE // Handcuffs are removed with their own button in the strip menu. + requires_organ_tag = list( + BP_L_HAND, + BP_R_HAND + ) + mob_overlay_layer = HO_HANDCUFF_LAYER + +/datum/inventory_slot/handcuffs/equipped(mob/living/user, obj/item/prop, var/silent = FALSE) + . = ..() + if(.) + user.drop_held_items() + +/datum/inventory_slot/handcuffs/unequipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + . = ..() + if(. && user.buckled?.buckle_require_restraints) + user.buckled.unbuckle_mob() + +/datum/inventory_slot/handcuffs/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning, var/ignore_equipped) + . = ..() && istype(prop, /obj/item/handcuffs) + +/datum/inventory_slot/handcuffs/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding) + return SPAN_WARNING("[pronouns.He] [pronouns.is] [html_icon(_holding)] restrained with \the [_holding]!") diff --git a/code/datums/inventory_slots/slots/slot_ears.dm b/code/datums/inventory_slots/slots/slot_ears.dm new file mode 100644 index 000000000000..96cba77d68ac --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_ears.dm @@ -0,0 +1,45 @@ +/datum/inventory_slot/ear + slot_name = "Left Ear" + slot_id = slot_l_ear_str + slot_state = "ears" + ui_loc = ui_l_ear + covering_slots = slot_head_str + covering_flags = SLOT_EARS + can_be_hidden = TRUE + requires_organ_tag = BP_HEAD + requires_slot_flags = SLOT_EARS + mob_overlay_layer = HO_L_EAR_LAYER + quick_equip_priority = 7 + fluid_height = (FLUID_SHALLOW * 0.25 + FLUID_OVER_MOB_HEAD * 0.75) // 3/4 of the way between waist-level and the top of your head + +/datum/inventory_slot/ear/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + for(var/slot in global.airtight_slots) + var/obj/item/gear = get_equipped_item(slot) + if(gear?.flags_inv & BLOCK_ALL_HAIR) + user.set_current_mob_overlay(mob_overlay_layer, null, redraw_mob) + return + ..() + +/datum/inventory_slot/ear/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDEEARS)) + return "[pronouns.He] [pronouns.has] [_holding.get_examine_line()] on [pronouns.his] [lowertext(slot_name)]." + +/datum/inventory_slot/ear/unequipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + . = ..() + if(.) + for(var/slot in global.ear_slots) + if(slot == slot_id) + continue + var/datum/inventory_slot/inv_slot = user.get_inventory_slot_datum(slot) + if(inv_slot?.get_equipped_item() == prop) + inv_slot.clear_slot() + +/datum/inventory_slot/ear/prop_can_fit_in_slot(var/obj/item/prop) + return ..() || (prop.w_class <= ITEM_SIZE_TINY && !(prop.obj_flags & OBJ_FLAG_NO_STORAGE)) + +/datum/inventory_slot/ear/right + slot_name = "Right Ear" + slot_id = slot_r_ear_str + ui_loc = ui_r_ear + mob_overlay_layer = HO_R_EAR_LAYER + quick_equip_priority = 6 diff --git a/code/datums/inventory_slots/slots/slot_glasses.dm b/code/datums/inventory_slots/slots/slot_glasses.dm new file mode 100644 index 000000000000..5d4bea87ae2b --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_glasses.dm @@ -0,0 +1,18 @@ +/datum/inventory_slot/glasses + slot_name = "Glasses" + slot_state = "glasses" + ui_loc = ui_glasses + slot_id = slot_glasses_str + covering_slots = slot_head_str + covering_flags = SLOT_EYES + can_be_hidden = TRUE + requires_organ_tag = BP_HEAD + requires_slot_flags = SLOT_EYES + mob_overlay_layer = HO_GLASSES_LAYER + alt_mob_overlay_layer = HO_GOGGLES_LAYER + quick_equip_priority = 5 + fluid_height = (FLUID_SHALLOW * 0.25 + FLUID_OVER_MOB_HEAD * 0.75) // 3/4 of the way between waist-level and the top of your head + +/datum/inventory_slot/glasses/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDEEYES)) + return "[pronouns.He] [pronouns.has] [_holding.get_examine_line()] covering [pronouns.his] eyes." diff --git a/code/datums/inventory_slots/slots/slot_gloves.dm b/code/datums/inventory_slots/slots/slot_gloves.dm new file mode 100644 index 000000000000..c48572fbffa2 --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_gloves.dm @@ -0,0 +1,38 @@ +/datum/inventory_slot/gloves + slot_name = "Gloves" + slot_state = "gloves" + ui_loc = ui_gloves + slot_id = slot_gloves_str + covering_slots = slot_wear_suit_str + can_be_hidden = TRUE + requires_organ_tag = list( + BP_L_HAND, + BP_R_HAND + ) + covering_flags = SLOT_HANDS + requires_slot_flags = SLOT_HANDS + quick_equip_priority = 8 + +/datum/inventory_slot/gloves/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + var/obj/item/suit = user.get_equipped_item(slot_wear_suit_str) + if(_holding && !(suit && suit.flags_inv & HIDEGLOVES)) + user.set_current_mob_overlay(HO_GLOVES_LAYER, _holding.get_mob_overlay(user, slot_gloves_str, use_fallback_if_icon_missing = use_overlay_fallback_slot), redraw_mob) + return + var/mob_blood_overlay = user.get_bodytype()?.get_blood_overlays(src) + if(mob_blood_overlay) + var/blood_color + for(var/obj/item/organ/external/grabber in user.get_hands_organs()) + if(grabber.coating) + blood_color = grabber.coating.get_color() + break + if(blood_color) + user.set_current_mob_overlay(HO_GLOVES_LAYER, overlay_image(mob_blood_overlay, "bloodyhands", blood_color, RESET_COLOR), redraw_mob) + return + user.set_current_mob_overlay(HO_GLOVES_LAYER, null, redraw_mob) + +/datum/inventory_slot/gloves/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDEGLOVES)) + return "[pronouns.He] [pronouns.has] [_holding.get_examine_line()] on [pronouns.his] hands." + for(var/obj/item/organ/external/E in owner.get_hands_organs()) + if(E.coating) + return "There's something on [pronouns.his] hands!" diff --git a/code/datums/inventory_slots/slots/slot_head.dm b/code/datums/inventory_slots/slots/slot_head.dm new file mode 100644 index 000000000000..6c31459f016e --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_head.dm @@ -0,0 +1,38 @@ +/datum/inventory_slot/head + slot_name = "Hat" + slot_state = "hair" + ui_loc = ui_head + slot_id = slot_head_str + can_be_hidden = TRUE + requires_organ_tag = BP_HEAD + covering_flags = SLOT_HEAD + requires_slot_flags = SLOT_HEAD + mob_overlay_layer = HO_HEAD_LAYER + quick_equip_priority = 9 + fluid_height = FLUID_OVER_MOB_HEAD + +/datum/inventory_slot/head/simple + requires_organ_tag = null + can_be_hidden = FALSE + ui_loc = "LEFT+1:16,BOTTOM:5" + +/datum/inventory_slot/head/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + if(prop?.flags_inv & (HIDEMASK|BLOCK_ALL_HAIR)) + user.update_hair(FALSE) + user.update_equipment_overlay(slot_l_ear_str, FALSE) + user.update_equipment_overlay(slot_r_ear_str, FALSE) + user.update_equipment_overlay(slot_wear_mask_str, FALSE) + ..() + +/datum/inventory_slot/head/unequipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + . = ..() + if(. && istype(user)) + var/obj/item/clothing/mask/mask = user.get_equipped_item(slot_wear_mask_str) + if(!mask || !(mask.item_flags & ITEM_FLAG_AIRTIGHT)) + user.set_internals(null) + +/datum/inventory_slot/head/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding) + if(user == owner) + return "You have [_holding.get_examine_line()] on your head." + return "[pronouns.He] [pronouns.has] [_holding.get_examine_line()] on [pronouns.his] head." diff --git a/code/datums/inventory_slots/slots/slot_id.dm b/code/datums/inventory_slots/slots/slot_id.dm new file mode 100644 index 000000000000..ecde7fc83dba --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_id.dm @@ -0,0 +1,29 @@ +/datum/inventory_slot/id + slot_name = "ID" + slot_state = "id" + ui_loc = ui_id + slot_id = slot_wear_id_str + requires_slot_flags = SLOT_ID + mob_overlay_layer = HO_ID_LAYER + quick_equip_priority = 13 + fluid_height = (FLUID_SHALLOW + FLUID_OVER_MOB_HEAD) / 2 // halfway between waist and top of head, so roughly chest level + additional_quick_equip_slots = list(slot_in_wallet_str) // try to go as late as possible + +/datum/inventory_slot/id/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + var/obj/item/clothing/clothes = user.get_equipped_item(slot_w_uniform_str) + if(istype(clothes) && clothes.should_show_id()) + user.set_current_mob_overlay(HO_ID_LAYER, null, redraw_mob) + else + ..() + BITSET(user.hud_updateflag, ID_HUD) + BITSET(user.hud_updateflag, WANTED_HUD) + +/datum/inventory_slot/id/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning, var/ignore_equipped) + . = ..() + if(.) + // If they have a uniform slot, they need a uniform to wear an ID card. + var/datum/inventory_slot/check_slot = user.get_inventory_slot_datum(slot_w_uniform_str) + if(check_slot && !check_slot.get_equipped_item()) + if(!disable_warning) + to_chat(user, SPAN_WARNING("You need to be wearing something on your body before you can wear \the [prop].")) + return FALSE diff --git a/code/datums/inventory_slots/slots/slot_mask.dm b/code/datums/inventory_slots/slots/slot_mask.dm new file mode 100644 index 000000000000..319bbe36e9ff --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_mask.dm @@ -0,0 +1,44 @@ +/datum/inventory_slot/mask + slot_name = "Mask" + slot_state = "mask" + ui_loc = ui_mask + slot_id = slot_wear_mask_str + covering_slots = slot_head_str + covering_flags = SLOT_FACE + requires_organ_tag = BP_HEAD + requires_slot_flags = SLOT_FACE + can_be_hidden = TRUE + mob_overlay_layer = HO_FACEMASK_LAYER + quick_equip_priority = 10 + fluid_height = (FLUID_SHALLOW * 0.25 + FLUID_OVER_MOB_HEAD * 0.75) // 3/4 of the way between waist-level and the top of your head + +/datum/inventory_slot/mask/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + if(prop?.flags_inv & BLOCK_ALL_HAIR) + user.update_hair(0) + user.update_equipment_overlay(slot_l_ear_str, FALSE) + user.update_equipment_overlay(slot_r_ear_str, FALSE) + ..() + +/mob/proc/check_for_airtight_internals(var/update_internals = TRUE) + for(var/slot in global.airtight_slots) + var/obj/item/gear = get_equipped_item(slot) + if(gear?.item_flags & ITEM_FLAG_AIRTIGHT) + return TRUE + if(update_internals) + set_internals(null) + return FALSE + +/datum/inventory_slot/mask/equipped(mob/living/user, obj/item/prop, redraw_mob, delete_old_item) + . = ..() + user.check_for_airtight_internals() + +/datum/inventory_slot/mask/unequipped(mob/living/user, obj/item/prop, redraw_mob) + . = ..() + user.check_for_airtight_internals() + +/datum/inventory_slot/mask/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDEMASK)) + if(_holding.body_parts_covered & SLOT_FACE) + return "[pronouns.He] [pronouns.is] wearing [_holding.get_examine_line()] on [pronouns.his] face." + else + return "[pronouns.He] [pronouns.is] wearing [_holding.get_examine_line()] around [pronouns.his] neck." diff --git a/code/datums/inventory_slots/slots/slot_pockets.dm b/code/datums/inventory_slots/slots/slot_pockets.dm new file mode 100644 index 000000000000..8357af8834dc --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_pockets.dm @@ -0,0 +1,36 @@ +/datum/inventory_slot/pocket + slot_name = "Left Pocket" + slot_state = "pocket" + ui_loc = ui_storage1 + slot_id = slot_l_store_str + skip_on_inventory_display = TRUE + skip_on_strip_display = TRUE + requires_organ_tag = BP_CHEST + requires_slot_flags = SLOT_POCKET + quick_equip_priority = 2 + +/datum/inventory_slot/pocket/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + return + +/datum/inventory_slot/pocket/prop_can_fit_in_slot(var/obj/item/prop) + return ..() || prop.w_class <= ITEM_SIZE_SMALL + +/datum/inventory_slot/pocket/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning, var/ignore_equipped) + . = ..() + if(.) + // If they have a uniform slot, they need a uniform to have pockets. + var/datum/inventory_slot/check_slot = user.get_inventory_slot_datum(slot_w_uniform_str) + if(check_slot && !check_slot.get_equipped_item()) + if(!disable_warning) + to_chat(user, SPAN_WARNING("You need to be wearing something before you can put \the [prop] in your pocket.")) + return FALSE + return !(prop.obj_flags & OBJ_FLAG_NO_STORAGE) + +/datum/inventory_slot/pocket/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + return + +/datum/inventory_slot/pocket/right + slot_name = "Right Pocket" + ui_loc = ui_storage2 + slot_id = slot_r_store_str + quick_equip_priority = 1 diff --git a/code/datums/inventory_slots/slots/slot_shoes.dm b/code/datums/inventory_slots/slots/slot_shoes.dm new file mode 100644 index 000000000000..44f7ce62aa4b --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_shoes.dm @@ -0,0 +1,41 @@ +/datum/inventory_slot/shoes + slot_name = "Shoes" + slot_state = "shoes" + ui_loc = ui_shoes + slot_id = slot_shoes_str + can_be_hidden = TRUE + requires_organ_tag = list( + BP_L_FOOT, + BP_R_FOOT + ) + requires_slot_flags = SLOT_FEET + quick_equip_priority = 3 + fluid_height = 3 + +/datum/inventory_slot/shoes/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + var/obj/item/suit = user.get_equipped_item(slot_wear_suit_str) + var/obj/item/uniform = user.get_equipped_item(slot_w_uniform_str) + if(_holding && !((suit && suit.flags_inv & HIDESHOES) || (uniform && uniform.flags_inv & HIDESHOES))) + user.set_current_mob_overlay(HO_SHOES_LAYER, _holding.get_mob_overlay(user, slot_shoes_str, use_fallback_if_icon_missing = use_overlay_fallback_slot), redraw_mob) + return + var/mob_blood_overlay = user.get_bodytype()?.get_blood_overlays(src) + if(mob_blood_overlay) + var/blood_color + for(var/foot_tag in list(BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/stomper = GET_EXTERNAL_ORGAN(user, foot_tag) + if(REAGENT_TOTAL_VOLUME(stomper?.coating)) + blood_color = stomper.coating.get_color() + break + if(blood_color) + var/image/bloodsies = overlay_image(mob_blood_overlay, "shoeblood", blood_color, RESET_COLOR) + user.set_current_mob_overlay(HO_SHOES_LAYER, bloodsies, redraw_mob) + return + user.set_current_mob_overlay(HO_SHOES_LAYER, null, redraw_mob) + +/datum/inventory_slot/shoes/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDESHOES)) + return "[pronouns.He] [pronouns.is] wearing [_holding.get_examine_line()] on [pronouns.his] feet." + for(var/bp in list(BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(owner, bp) + if(REAGENT_TOTAL_VOLUME(E?.coating)) + return "There's something on [pronouns.his] feet!" diff --git a/code/datums/inventory_slots/slots/slot_suit.dm b/code/datums/inventory_slots/slots/slot_suit.dm new file mode 100644 index 000000000000..f7b1342c4b35 --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_suit.dm @@ -0,0 +1,26 @@ +/datum/inventory_slot/suit + slot_name = "Suit" + slot_state = "suit" + ui_loc = ui_oclothing + slot_id = slot_wear_suit_str + can_be_hidden = TRUE + drop_slots_on_unequip = list(slot_s_store_str) + requires_organ_tag = BP_CHEST + requires_slot_flags = SLOT_OVER_BODY + mob_overlay_layer = HO_SUIT_LAYER + quick_equip_priority = 11 + +/datum/inventory_slot/suit/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + if(prop) + if(prop.flags_inv & HIDESHOES) + user.update_equipment_overlay(slot_shoes_str, FALSE) + if(prop.flags_inv & HIDEGLOVES) + user.update_equipment_overlay(slot_gloves_str, FALSE) + if(prop.flags_inv & HIDEJUMPSUIT) + user.update_equipment_overlay(slot_w_uniform_str, FALSE) + user.update_tail_showing(FALSE) + ..() + // Adds a collar overlay above the helmet layer if the suit has one + // Suit needs an identically named sprite in icons/mob/collar.dmi + var/obj/item/clothing/suit/suit = _holding + user.set_current_mob_overlay(HO_COLLAR_LAYER, (istype(suit) ? suit.get_collar() : null), redraw_mob) diff --git a/code/datums/inventory_slots/slots/slot_suit_storage.dm b/code/datums/inventory_slots/slots/slot_suit_storage.dm new file mode 100644 index 000000000000..6fb3f2e7e1df --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_suit_storage.dm @@ -0,0 +1,26 @@ +/datum/inventory_slot/suit_storage + slot_name = "Suit Storage" + slot_state = "suitstore" + ui_loc = ui_sstore1 + slot_id = slot_s_store_str + requires_organ_tag = BP_CHEST + mob_overlay_layer = HO_SUIT_STORE_LAYER + fluid_height = (FLUID_SHALLOW + FLUID_OVER_MOB_HEAD) / 2 // halfway between waist and top of head, so roughly chest level + +/datum/inventory_slot/suit_storage/can_equip_to_slot(var/mob/user, var/obj/item/prop, var/disable_warning, var/ignore_equipped) + . = ..() + if(.) + // They need a suit to use suit storage. + var/datum/inventory_slot/check_slot = user.get_inventory_slot_datum(slot_wear_suit_str) + var/obj/item/clothing/suit/suit = check_slot?.get_equipped_item() + if(!check_slot || !istype(suit)) + if(!disable_warning) + to_chat(user, SPAN_WARNING("You need a suit before you can attach \the [prop].")) + return FALSE + if(istype(prop, /obj/item/modular_computer/pda) || istype(prop, /obj/item/pen)) + return TRUE + return is_type_in_list(prop, suit.allowed) + +/datum/inventory_slot/suit_storage/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDESUITSTORAGE)) + return "[.]\n[pronouns.He] [pronouns.is] carrying [_holding.get_examine_line()] on [pronouns.his] [_holding.name]." diff --git a/code/datums/inventory_slots/slots/slot_uniform.dm b/code/datums/inventory_slots/slots/slot_uniform.dm new file mode 100644 index 000000000000..b254028a7c45 --- /dev/null +++ b/code/datums/inventory_slots/slots/slot_uniform.dm @@ -0,0 +1,29 @@ +/datum/inventory_slot/uniform + slot_name = "Uniform" + slot_state = "center" + ui_loc = ui_iclothing + slot_id = slot_w_uniform_str + can_be_hidden = TRUE + covering_slots = slot_wear_suit_str + drop_slots_on_unequip = list( + slot_r_store_str, + slot_l_store_str, + slot_wear_id_str, + slot_belt_str + ) + requires_organ_tag = BP_CHEST + requires_slot_flags = SLOT_UPPER_BODY + quick_equip_priority = 12 + +/datum/inventory_slot/uniform/update_mob_equipment_overlay(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE) + if(prop?.flags_inv & HIDESHOES) + user.update_equipment_overlay(slot_shoes_str, FALSE) + var/obj/item/suit = user.get_equipped_item(slot_wear_suit_str) + if(_holding && (!suit || !(suit.flags_inv & HIDEJUMPSUIT))) + user.set_current_mob_overlay(HO_UNIFORM_LAYER, _holding.get_mob_overlay(user, slot_w_uniform_str, use_fallback_if_icon_missing = use_overlay_fallback_slot), redraw_mob) + else + user.set_current_mob_overlay(HO_UNIFORM_LAYER, null, redraw_mob) + +/datum/inventory_slot/uniform/get_examined_string(mob/owner, mob/user, distance, hideflags, decl/pronouns/pronouns) + if(_holding && !(hideflags & HIDEJUMPSUIT)) + return ..() diff --git a/code/datums/item_modifiers/_defines.dm b/code/datums/item_modifiers/_defines.dm index 1c37537db683..3b7feaef1dc6 100644 --- a/code/datums/item_modifiers/_defines.dm +++ b/code/datums/item_modifiers/_defines.dm @@ -1,5 +1,3 @@ #define SETUP_NAME "name" -#define SETUP_ONMOB_ICON "onmobicon" -#define SETUP_ICON_STATE "icon_state" -#define SETUP_ITEM_STATE "item_state" -#define SETUP_ITEM_STATE_SLOTS "item_state_slots" +#define SETUP_ICON "icon" +#define SETUP_SPRITE_SHEETS "spritesheets" \ No newline at end of file diff --git a/code/datums/item_modifiers/item_modifier.dm b/code/datums/item_modifiers/item_modifier.dm index d40286bf68f3..8dfeff61d569 100644 --- a/code/datums/item_modifiers/item_modifier.dm +++ b/code/datums/item_modifiers/item_modifier.dm @@ -2,6 +2,17 @@ var/name var/list/type_setups +/decl/item_modifier/Initialize() + . = ..() + for(var/prop_type in type_setups) + var/obj/item/prop = atom_info_repository.get_instance_of(type_setups[prop_type]) + var/list/type_setup = list() + type_setup[SETUP_NAME] = prop.name + type_setup[SETUP_ICON] = prop.icon + if(prop.sprite_sheets) + type_setup[SETUP_SPRITE_SHEETS] = prop.sprite_sheets.Copy() + type_setups[prop_type] = type_setup + /decl/item_modifier/proc/RefitItem(var/obj/item/I) if(!istype(I)) return FALSE @@ -15,22 +26,10 @@ return FALSE I.SetName(type_setup[SETUP_NAME]) - - var/icon_state = type_setup[SETUP_ICON_STATE] - if(icon_state) - I.icon_state = type_setup[SETUP_ICON_STATE] - - var/onmob = type_setup[SETUP_ONMOB_ICON] - if(onmob) - I.use_single_icon = TRUE - I.icon = onmob - - var/item_state = type_setup[SETUP_ITEM_STATE] - if(item_state) - I.item_state = item_state - - var/item_state_slots = type_setup[SETUP_ITEM_STATE_SLOTS] - if(item_state_slots) - I.item_state_slots = item_state_slots - + I.icon = type_setup[SETUP_ICON] + if(istype(I, /obj/item/clothing)) + var/list/type_spritesheets = type_setup[SETUP_SPRITE_SHEETS] + var/obj/item/clothing/C = I + C.sprite_sheets = type_spritesheets?.Copy() + I.reconsider_single_icon(TRUE) return TRUE diff --git a/code/datums/item_modifiers/space_suits.dm b/code/datums/item_modifiers/space_suits.dm index b2ea4cc07bf7..07336f23e1ab 100644 --- a/code/datums/item_modifiers/space_suits.dm +++ b/code/datums/item_modifiers/space_suits.dm @@ -1,136 +1,85 @@ /decl/item_modifier/space_suit/engineering name = "Engineering" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "engineering voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/engineering/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "engineering voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/engineering/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/engineering, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/engineering ) /decl/item_modifier/space_suit/engineering/alt name = "Engineering, Alt" - -/decl/item_modifier/space_suit/engineering/alt/Initialize() - . = ..() - var/helmet_setup = type_setups[/obj/item/clothing/head/helmet/space] - helmet_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/engineering_alt/helmet.dmi' - - var/suit_setup = type_setups[/obj/item/clothing/suit/space/void] - suit_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/engineering_alt/suit.dmi' + type_setups = list( + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/engineering/alt, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/engineering/alt + ) /decl/item_modifier/space_suit/mining name = "Mining" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "mining voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/mining/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "mining voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/mining/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/mining, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/mining + ) + +/decl/item_modifier/space_suit/mining/alt + name = "Mining, Alt" + type_setups = list( + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/mining/alt, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/mining/alt ) /decl/item_modifier/space_suit/science name = "Science" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "excavation voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/excavation/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "excavation voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/excavation/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/excavation, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/excavation ) /decl/item_modifier/space_suit/medical name = "Medical" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "medical voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/medical/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "medical voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/medical/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/medical, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/medical ) /decl/item_modifier/space_suit/medical/alt name = "Medical, Alt" - -/decl/item_modifier/space_suit/medical/alt/Initialize() - . = ..() - var/helmet_setup = type_setups[/obj/item/clothing/head/helmet/space] - helmet_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/medical_alt/helmet.dmi' - - var/suit_setup = type_setups[/obj/item/clothing/suit/space/void] - suit_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/medical_alt/suit.dmi' + type_setups = list( + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/medical/alt, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/medical/alt + ) /decl/item_modifier/space_suit/security name = "Security" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "security voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/sec/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "security voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/sec/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/security, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/security ) /decl/item_modifier/space_suit/security/alt name = "Security, Alt" - -/decl/item_modifier/space_suit/security/alt/Initialize() - . = ..() - var/helmet_setup = type_setups[/obj/item/clothing/head/helmet/space] - helmet_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/sec_alt/helmet.dmi' - - var/suit_setup = type_setups[/obj/item/clothing/suit/space/void] - suit_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/sec_alt/suit.dmi' + type_setups = list( + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/security/alt, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/security/alt + ) /decl/item_modifier/space_suit/atmos name = "Atmos" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "atmospherics voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/atmos/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "atmospherics voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/atmos/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/atmos, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/atmos ) /decl/item_modifier/space_suit/atmos/alt name = "Atmos, Alt" - -/decl/item_modifier/space_suit/atmos/alt/Initialize() - . = ..() - var/helmet_setup = type_setups[/obj/item/clothing/head/helmet/space] - helmet_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/atmos_alt/helmet.dmi' - - var/suit_setup = type_setups[/obj/item/clothing/suit/space/void] - suit_setup[SETUP_ONMOB_ICON] = 'icons/clothing/spacesuit/void/atmos_alt/suit.dmi' + type_setups = list( + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/atmos/alt, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/atmos/alt + ) /decl/item_modifier/space_suit/mercenary name = "Mercenary" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "blood-red voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/merc/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "blood-red voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/merc/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/merc, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/merc ) /decl/item_modifier/space_suit/mercenary/emag @@ -139,12 +88,13 @@ /decl/item_modifier/space_suit/pilot name = "Pilot" type_setups = list( - /obj/item/clothing/head/helmet/space = list( - SETUP_NAME = "pilot voidsuit helmet", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/pilot/helmet.dmi' - ), - /obj/item/clothing/suit/space/void = list( - SETUP_NAME = "pilot voidsuit", - SETUP_ONMOB_ICON = 'icons/clothing/spacesuit/void/pilot/suit.dmi' - ) + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/expedition, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/expedition + ) + +/decl/item_modifier/space_suit/salvage + name = "Salvage" + type_setups = list( + /obj/item/clothing/head/helmet/space/void = /obj/item/clothing/head/helmet/space/void/engineering/salvage, + /obj/item/clothing/suit/space/void = /obj/item/clothing/suit/space/void/engineering/salvage ) diff --git a/code/datums/item_modifiers/~defines.dm b/code/datums/item_modifiers/~defines.dm index 4963318c00db..c136ddec5d57 100644 --- a/code/datums/item_modifiers/~defines.dm +++ b/code/datums/item_modifiers/~defines.dm @@ -1,5 +1,2 @@ #undef SETUP_NAME -#undef SETUP_ICON_STATE -#undef SETUP_ITEM_STATE -#undef SETUP_ITEM_STATE_SLOTS -#undef SETUP_ONMOB_ICON +#undef SETUP_ICON diff --git a/code/datums/licences/license.dm b/code/datums/licences/license.dm index 8ed0ad8ac91c..8f9318bc5e63 100644 --- a/code/datums/licences/license.dm +++ b/code/datums/licences/license.dm @@ -23,6 +23,10 @@ name = "CC BY-NC-SA 3.0" url = "https://creativecommons.org/licenses/by-nc-sa/3.0/" +/decl/license/cc_by_sa_3_0 + name = "CC BY-SA 3.0" + url = "https://creativecommons.org/licenses/by-sa/3.0/" + /decl/license/cc_by_nc_nd_4_0 name = "CC BY-NC-ND 4.0" url = "https://creativecommons.org/licenses/by-nc-nd/4.0/" @@ -31,3 +35,7 @@ name = "Grandfathered In" url = "https://en.wikipedia.org/wiki/Grandfather_clause" attribution_mandatory = FALSE + +/decl/license/good_faith + name = "Good Faith Usage" + url = "https://en.wikipedia.org/wiki/Good_faith_(law)" diff --git a/code/datums/local_network.dm b/code/datums/local_network.dm index d27a6ae78b6b..8ecefba9f948 100644 --- a/code/datums/local_network.dm +++ b/code/datums/local_network.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST_INIT(local_networks, new) +var/global/list/local_networks = list() /datum/local_network var/id_tag @@ -7,11 +7,11 @@ GLOBAL_LIST_INIT(local_networks, new) /datum/local_network/New(var/_id) id_tag = _id - GLOB.local_networks[id_tag] = src + global.local_networks[id_tag] = src /datum/local_network/Destroy() network_entities.Cut() - GLOB.local_networks -= src + global.local_networks -= id_tag . = ..() /datum/local_network/proc/within_radius(var/atom/checking) @@ -23,11 +23,11 @@ GLOBAL_LIST_INIT(local_networks, new) /datum/local_network/proc/add_device(var/obj/machinery/device) var/list/entities = get_devices(device.type) - + if(!entities) entities = list() network_entities[device.type] = entities - + entities[device] = TRUE return entities[device] @@ -58,20 +58,20 @@ GLOBAL_LIST_INIT(local_networks, new) //Multilevel network -GLOBAL_LIST_INIT(multilevel_local_networks, new) +var/global/list/multilevel_local_networks = list() /datum/local_network/multilevel/New(var/_id) id_tag = _id - GLOB.multilevel_local_networks[id_tag] = src + global.multilevel_local_networks[id_tag] = src /datum/local_network/multilevel/Destroy() network_entities.Cut() - GLOB.multilevel_local_networks -= src + global.multilevel_local_networks -= src . = ..() /datum/local_network/multilevel/within_radius(var/atom/checking) for(var/entity_list in network_entities) for(var/atom/entity in entity_list) - if(!(get_z(entity) in GetConnectedZlevels(get_z(checking)))) + if(!(get_z(entity) in SSmapping.get_connected_levels(get_z(checking)))) return FALSE return TRUE \ No newline at end of file diff --git a/code/datums/mil_ranks.dm b/code/datums/mil_ranks.dm index 00a4a36c5faa..29a14bc5e985 100644 --- a/code/datums/mil_ranks.dm +++ b/code/datums/mil_ranks.dm @@ -2,92 +2,14 @@ * Datums for military branches and ranks * * Map datums can optionally specify a list of /datum/mil_branch paths. These paths - * are used to initialize the global mil_branches object, which contains a list of - * branch objects the map uses. Each branch definition specifies a list of + * are used to initialize ranks for the map, which contains a list of + * branch objects used on the map. Each branch definition specifies a list of * /datum/mil_rank paths, which are ranks available to that branch. * - * Which branches and ranks can be selected for spawning is specifed in GLOB.using_map + * Which branches and ranks can be selected for spawning is specifed in global.using_map * and each branch datum definition, respectively. */ -var/datum/mil_branches/mil_branches = new() - -/** - * Global object for handling branches - */ -/datum/mil_branches - var/list/branches // All branches that exist - var/list/spawn_branches_ // Branches that a player can choose for spawning, not including species restrictions. - var/list/spawn_branches_by_species_ // Branches that a player can choose for spawning, with species restrictions. Populated on a needed basis - -/** - * Retrieve branch object by branch name - */ -/datum/mil_branches/proc/get_branch(var/branch_name) - if(ispath(branch_name)) - var/datum/mil_branch/branch = branch_name - branch_name = initial(branch.name) - if(branch_name && branch_name != "None") - return branches[branch_name] - -/** - * Retrieve branch object by branch type - */ -/datum/mil_branches/proc/get_branch_by_type(var/branch_type) - for(var/name in branches) - if (istype(branches[name], branch_type)) - return branches[name] - -/** - * Retrieve a rank object from given branch by name - */ -/datum/mil_branches/proc/get_rank(var/branch_name, var/rank_name) - if(ispath(rank_name)) - var/datum/mil_rank/rank = rank_name - rank_name = initial(rank.name) - if(rank_name && rank_name != "None") - var/datum/mil_branch/branch = get_branch(branch_name) - if(branch) - return branch.ranks[rank_name] - -/** - * Return all spawn branches for the given input - */ -/datum/mil_branches/proc/spawn_branches(var/datum/species/S) - if(!S) - return spawn_branches_.Copy() - . = LAZYACCESS(spawn_branches_by_species_, S) - if(!.) - . = list() - LAZYSET(spawn_branches_by_species_, S, .) - for(var/spawn_branch in spawn_branches_) - if(!GLOB.using_map.is_species_branch_restricted(S, spawn_branches_[spawn_branch])) - . += spawn_branch - -/** - * Return all spawn ranks for the given input - */ -/datum/mil_branches/proc/spawn_ranks(var/branch_name, var/datum/species/S) - var/datum/mil_branch/branch = get_branch(branch_name) - return branch && branch.spawn_ranks(S) - -/** - * Return a true value if branch_name is a valid spawn branch key - */ -/datum/mil_branches/proc/is_spawn_branch(var/branch_name, var/datum/species/S) - return (branch_name in spawn_branches(S)) - - -/** - * Return a true value if rank_name is a valid spawn rank in branch under branch_name - */ -/datum/mil_branches/proc/is_spawn_rank(var/branch_name, var/rank_name, var/datum/species/S) - var/datum/mil_branch/branch = get_branch(branch_name) - if(branch && (rank_name in branch.spawn_ranks(S))) - return TRUE - else - return FALSE - /** * A single military branch, such as Fleet or Marines */ @@ -106,10 +28,7 @@ var/datum/mil_branches/mil_branches = new() var/list/rank_types // list of paths used to init the ranks list var/list/spawn_rank_types // list of paths used to init the spawn_ranks list. Subset of rank_types - var/assistant_job = DEFAULT_JOB_TYPE - - // Email addresses will be created under this domain name. Mostly for the looks. - var/email_domain = "freemail.net" + var/assistant_job var/list/min_skill @@ -118,9 +37,12 @@ var/datum/mil_branches/mil_branches = new() spawn_ranks_ = list() spawn_ranks_by_species_ = list() + if(isnull(assistant_job)) + assistant_job = global.using_map.default_job_type + for(var/rank_path in rank_types) if(!ispath(rank_path, /datum/mil_rank)) - crash_with("[name]'s rank_types includes [rank_path], which is not a subtype of /datum/mil_rank.") + PRINT_STACK_TRACE("[name]'s rank_types includes [rank_path], which is not a subtype of /datum/mil_rank.") continue var/datum/mil_rank/rank = new rank_path () ranks[rank.name] = rank @@ -128,7 +50,7 @@ var/datum/mil_branches/mil_branches = new() if(rank_path in spawn_rank_types) spawn_ranks_[rank.name] = rank -/datum/mil_branch/proc/spawn_ranks(var/datum/species/S) +/datum/mil_branch/proc/spawn_ranks(var/decl/species/S) if(!S) return spawn_ranks_.Copy() . = spawn_ranks_by_species_[S] @@ -136,36 +58,9 @@ var/datum/mil_branches/mil_branches = new() . = list() spawn_ranks_by_species_[S] = . for(var/spawn_rank in spawn_ranks_) - if(!GLOB.using_map.is_species_rank_restricted(S, src, spawn_ranks_[spawn_rank])) + if(!global.using_map.is_species_rank_restricted(S, src, spawn_ranks_[spawn_rank])) . += spawn_rank - -/** - * Populate the global branches list from GLOB.using_map - */ -/hook/startup/proc/populate_branches() - if(!(GLOB.using_map.flags & MAP_HAS_BRANCH) && !(GLOB.using_map.flags & MAP_HAS_RANK)) - mil_branches.branches = null - mil_branches.spawn_branches_ = null - mil_branches.spawn_branches_by_species_ = null - return 1 - - mil_branches.branches = list() - mil_branches.spawn_branches_ = list() - mil_branches.spawn_branches_by_species_ = list() - for(var/branch_path in GLOB.using_map.branch_types) - if(!ispath(branch_path, /datum/mil_branch)) - crash_with("populate_branches() attempted to instantiate object with path [branch_path], which is not a subtype of /datum/mil_branch.") - continue - - var/datum/mil_branch/branch = new branch_path () - mil_branches.branches[branch.name] = branch - - if(branch_path in GLOB.using_map.spawn_branch_types) - mil_branches.spawn_branches_[branch.name] = branch - - return 1 - /** * A military rank * diff --git a/code/datums/mind/memory.dm b/code/datums/mind/memory.dm index c928c298a22f..0089d7d8dfc9 100644 --- a/code/datums/mind/memory.dm +++ b/code/datums/mind/memory.dm @@ -7,8 +7,8 @@ . = mind.StoreMemory(memory, options) /datum/mind/proc/StoreMemory(var/memory, var/options) - var/decl/memory_options/MO = decls_repository.get_decl(options || /decl/memory_options/default) - return MO.Create(src, memory) + var/decl/memory_options/memory_option = GET_DECL(options || /decl/memory_options/default) + return memory_option.Create(src, memory) /datum/mind/proc/RemoveMemory(var/datum/memory/memory, var/mob/remover) if(!memory) @@ -20,26 +20,24 @@ ShowMemory(remover) /datum/mind/proc/ClearMemories(var/list/tags) - for(var/mem in memories) - var/datum/memory/M = mem + for(var/datum/memory/mem as anything in memories) // If no tags were supplied OR if there is any union between the given tags and memory tags // then remove the memory - if(!length(tags) || length(tags & M.tags)) - LAZYREMOVE(memories, M) + if(!length(tags) || length(tags & mem.tags)) + LAZYREMOVE(memories, mem) /datum/mind/proc/CopyMemories(var/datum/mind/target) if(!istype(target)) return - for(var/mem in memories) - var/datum/memory/M = mem - M.Copy(target) + for(var/datum/memory/mem in memories) + mem.Copy(target) /datum/mind/proc/MemoryTags() . = list() - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + var/decl/special_role/antag = all_antag_types[antag_type] if(antag.is_antagonist(src)) . += antag_type @@ -50,13 +48,12 @@ var/list/output = list() var/last_owner_name // We pretend that memories are stored in some semblance of an order - for(var/mem in memories) - var/datum/memory/M = mem - var/owner_name = M.OwnerName() + for(var/datum/memory/mem in memories) + var/owner_name = mem.OwnerName() if(owner_name != last_owner_name) output += "[current.real_name]'s Memories
    " last_owner_name = owner_name - output += "[M.memory] \[Remove\]" + output += "[mem.memory] \[Remove\]" if(objectives.len > 0) output += "
    Objectives:" @@ -70,7 +67,9 @@ var/datum/goal/ambition/ambition = SSgoals.ambitions[src] output += "
    Ambitions: [ambition.summarize()]" - show_browser(recipient, replacetext(jointext(output, "
    "),"\n","
    "),"window=memory") + var/datum/browser/popup = new(recipient, "window=memory") + popup.set_content(replacetext(jointext(output, "
    "),"\n","
    ")) + popup.open() /*********** * Memories * @@ -125,7 +124,7 @@ /decl/memory_options var/memory_type = /datum/memory -/decl/memory_options/proc/Validate(var/datum/mind/target) +/decl/memory_options/proc/validate_mind(var/datum/mind/target) if(!target.current) return "Mind is detached from mob." @@ -136,7 +135,7 @@ log_and_message_admins(message) /decl/memory_options/proc/Create(var/datum/mind/target, var/memory) - var/error = Validate(target) + var/error = validate_mind(target) if(error) return error @@ -154,14 +153,13 @@ /decl/memory_options/default/MemoryTags(var/datum/mind/target) return target.MemoryTags() -/decl/memory_options/default/Validate(var/datum/mind/target) +/decl/memory_options/default/validate_mind(var/datum/mind/target) if((. = ..())) return var/relevant_memories = 0 - for(var/mem in target.memories) - var/datum/memory/M = mem - if(M.type == memory_type) + for(var/datum/memory/mem in target.memories) + if(mem.type == memory_type) relevant_memories++ if(relevant_memories > memory_limit) diff --git a/code/datums/mind/mind.dm b/code/datums/mind/mind.dm index b8b26312ef13..88afba2ce3ee 100644 --- a/code/datums/mind/mind.dm +++ b/code/datums/mind/mind.dm @@ -33,36 +33,27 @@ var/key var/name //replaces mob/var/original_name var/mob/living/current - var/mob/living/original //TODO: remove.not used in any meaningful way ~Carn. First I'll need to tweak the way silicon-mobs handle minds. var/active = 0 - var/list/known_connections //list of known (RNG) relations between people var/gen_relations_info var/assigned_role - var/special_role + var/assigned_special_role var/role_alt_title var/datum/job/assigned_job var/list/datum/objective/objectives = list() - var/list/datum/objective/special_verbs = list() - var/has_been_rev = 0//Tracks if this mind has been a rev or not - - var/faction //associated faction - var/datum/changeling/changeling //changeling holder - - var/rev_cooldown = 0 - - // the world.time since the mob has been brigged, or -1 if not at all - var/brigged_since = -1 + /// The world.time value after which another conversion can be attempted. + var/conversion_cooldown = 0 //put this here for easier tracking ingame var/datum/money_account/initial_account - var/list/initial_email_login = list("login" = "", "password" = "") + var/list/initial_account_login = list("login" = "", "password" = "") + var/account_network // Network id of the network the account was created on. /datum/mind/New(var/key) src.key = key @@ -70,19 +61,25 @@ /datum/mind/Destroy() QDEL_NULL_LIST(memories) + QDEL_NULL_LIST(objectives) SSticker.minds -= src + if(current?.mind == src) + current.mind = null + current = null . = ..() +/datum/mind/proc/handle_mob_deletion(mob/living/deleted_mob) + if (current == deleted_mob) + current = null /datum/mind/proc/transfer_to(mob/living/new_character) if(!istype(new_character)) to_world_log("## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn") - if(current) //remove ourself from our old body's mind variable - if(changeling) - current.remove_changeling_powers() - current.verbs -= /datum/changeling/proc/EvolutionMenu - current.mind = null - + if(current) //remove ourself from our old body's mind variable + if(current?.mind == src) + current.mind = null SSnano.user_transferred(current, new_character) // transfer active NanoUI instances to new user + if(istype(current)) // exclude new_players and observers + current.copy_abilities_to(new_character) if(new_character.mind) //remove any mind currently in our new body's mind variable new_character.mind.current = null @@ -91,12 +88,6 @@ current = new_character //link ourself to our new body new_character.mind = src //and link our new body to ourself - if(learned_spells && learned_spells.len) - restore_spells(new_character) - - if(changeling) - new_character.make_changeling() - if(active) new_character.key = key //now transfer the key to link the client to our new body @@ -107,30 +98,30 @@ var/out = "[name][(current&&(current.real_name!=name))?" (as [current.real_name])":""]
    " out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
    " - out += "Assigned role: [assigned_role]. Edit
    " + out += "Assigned role: [assigned_role]. Edit
    " out += "
    " out += "Factions and special roles:
    " - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + var/decl/special_role/antag = all_antag_types[antag_type] out += "[antag.get_panel_entry(src)]" out += "

    " out += "Objectives
    " - if(objectives && objectives.len) + if(LAZYLEN(objectives)) var/num = 1 for(var/datum/objective/O in objectives) out += "Objective #[num]: [O.explanation_text] " - out += " \[remove\]
    " + out += " \[remove\]
    " num++ - out += "
    \[announce objectives\]" + out += "
    \[announce objectives\]" else out += "None." - out += "
    \[add\]

    " + out += "
    \[add\]

    " var/datum/goal/ambition/ambition = SSgoals.ambitions[src] - out += "Ambitions: [ambition ? ambition.description : "None"] \[edit\]
    " + out += "Ambitions: [ambition ? ambition.description : "None"] \[edit\]
    " show_browser(usr, out, "window=edit_memory[src]") /datum/mind/proc/get_goal_from_href(var/href) @@ -147,8 +138,8 @@ if(href_list["add_goal"]) - var/mob/caller = locate(href_list["add_goal_caller"]) - if(caller && caller == current) can_modify = TRUE + var/mob/goal_user = locate(href_list["add_goal_user"]) + if(goal_user && goal_user == current) can_modify = TRUE if(can_modify) if(is_admin) @@ -166,8 +157,8 @@ if(href_list["abandon_goal"]) var/datum/goal/goal = get_goal_from_href(href_list["abandon_goal"]) - var/mob/caller = locate(href_list["abandon_goal_caller"]) - if(caller && caller == current) can_modify = TRUE + var/mob/goal_user = locate(href_list["abandon_goal_user"]) + if(goal_user && goal_user == current) can_modify = TRUE if(goal && can_modify) if(usr == current) @@ -181,8 +172,8 @@ if(href_list["reroll_goal"]) var/datum/goal/goal = get_goal_from_href(href_list["reroll_goal"]) - var/mob/caller = locate(href_list["reroll_goal_caller"]) - if(caller && caller == current) can_modify = TRUE + var/mob/goal_user = locate(href_list["reroll_goal_user"]) + if(goal_user && goal_user == current) can_modify = TRUE if(goal && (goal in goals) && can_modify) qdel(goal) @@ -199,28 +190,32 @@ if(!is_admin) return if(href_list["add_antagonist"]) - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["add_antagonist"]] + var/decl/special_role/antag = locate(href_list["add_antagonist"]) if(antag) if(antag.add_antagonist(src, 1, 1, 0, 1, 1)) // Ignore equipment and role type for this. - log_admin("[key_name_admin(usr)] made [key_name(src)] into a [antag.role_text].") + log_admin("[key_name_admin(usr)] made [key_name(src)] into a [antag.name].") else - to_chat(usr, "[src] could not be made into a [antag.role_text]!") + to_chat(usr, "[src] could not be made into a [antag.name]!") else if(href_list["remove_antagonist"]) - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["remove_antagonist"]] - if(antag) antag.remove_antagonist(src) + var/decl/special_role/antag = locate(href_list["remove_antagonist"]) + if(istype(antag)) + antag.remove_antagonist(src) else if(href_list["equip_antagonist"]) - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["equip_antagonist"]] - if(antag) antag.equip(src.current) + var/decl/special_role/antag = locate(href_list["equip_antagonist"]) + if(istype(antag)) + antag.equip_role(src.current) else if(href_list["unequip_antagonist"]) - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["unequip_antagonist"]] - if(antag) antag.unequip(src.current) + var/decl/special_role/antag = locate(href_list["unequip_antagonist"]) + if(istype(antag)) + antag.unequip_role(src.current) else if(href_list["move_antag_to_spawn"]) - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["move_antag_to_spawn"]] - if(antag) antag.place_mob(src.current) + var/decl/special_role/antag = locate(href_list["move_antag_to_spawn"]) + if(istype(antag)) + antag.place_mob(src.current) else if (href_list["role_edit"]) var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in SSjobs.titles_to_datums @@ -230,7 +225,7 @@ assigned_job = job assigned_role = job.title role_alt_title = new_role - if(current) + if(current?.skillset) current.skillset.obtain_from_client(job, current.client) else if (href_list["amb_edit"]) @@ -274,7 +269,7 @@ if(!def_value)//If it's a custom objective, it will be an empty string. def_value = "custom" - var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "mercenary", "capture", "absorb", "custom") + var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "mercenary", "custom") if (!new_obj_type) return var/datum/objective/new_objective = null @@ -288,13 +283,13 @@ var/list/possible_targets = list("Free objective") for(var/datum/mind/possible_target in SSticker.minds) - if ((possible_target != src) && istype(possible_target.current, /mob/living/carbon/human)) + if ((possible_target != src) && ishuman(possible_target.current)) possible_targets += possible_target.current var/mob/def_target = null var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain) - if (objective&&(objective.type in objective_list) && objective:target) - def_target = objective.target?.current + if (objective?.target && (objective.type in objective_list)) + def_target = objective.target.current var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets if (!new_target) return @@ -304,13 +299,13 @@ if (!istype(M) || !M.mind || new_target == "Free objective") new_objective = new objective_path new_objective.owner = src - new_objective:target = null + new_objective.target = null new_objective.explanation_text = "Free objective" else new_objective = new objective_path new_objective.owner = src - new_objective:target = M.mind - new_objective.explanation_text = "[objective_type] [M.real_name], the [M.mind.special_role ? M.mind:special_role : M.mind:assigned_role]." + new_objective.target = M.mind + new_objective.explanation_text = "[objective_type] [M.real_name], the [M.mind.get_special_role_name(M.mind.assigned_role)]." if ("hijack") new_objective = new /datum/objective/hijack @@ -329,16 +324,10 @@ new_objective.owner = src if ("steal") - if (!istype(objective, /datum/objective/steal)) - new_objective = new /datum/objective/steal - new_objective.owner = src - else - new_objective = objective - var/datum/objective/steal/steal = new_objective - if (!steal.select_target()) - return + new_objective = new /datum/objective/steal + new_objective.owner = src - if("download","capture","absorb") + if("download") var/def_num if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]")) def_num = objective.target_amount @@ -351,12 +340,6 @@ if("download") new_objective = new /datum/objective/download new_objective.explanation_text = "Download [target_number] research levels." - if("capture") - new_objective = new /datum/objective/capture - new_objective.explanation_text = "Accumulate [target_number] capture points." - if("absorb") - new_objective = new /datum/objective/absorb - new_objective.explanation_text = "Absorb [target_number] compatible genomes." new_objective.owner = src new_objective.target_amount = target_number @@ -366,6 +349,8 @@ new_objective = new /datum/objective new_objective.owner = src new_objective.explanation_text = expl + else + PRINT_STACK_TRACE("ERROR: Unrecognized objective type [new_obj_type]") if (!new_objective) return @@ -381,14 +366,14 @@ objectives -= objective else if(href_list["implant"]) - var/mob/living/carbon/human/H = current + var/mob/living/human/H = current BITSET(H.hud_updateflag, IMPLOYAL_HUD) // updates that players HUD images so secHUD's pick up they are implanted or not. switch(href_list["implant"]) if("remove") for(var/obj/item/implant/loyalty/I in H.contents) - for(var/obj/item/organ/external/organs in H.organs) + for(var/obj/item/organ/external/organs in H.get_external_organs()) if(I in organs.implants) qdel(I) break @@ -399,51 +384,36 @@ H.implant_loyalty(H, override = TRUE) log_admin("[key_name_admin(usr)] has loyalty implanted [current].") else + pass() else if (href_list["silicon"]) BITSET(current.hud_updateflag, SPECIALROLE_HUD) switch(href_list["silicon"]) if("unemag") - var/mob/living/silicon/robot/R = current - if (istype(R)) - R.emagged = 0 - if (R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.module.emag.forceMove(null) - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.module.emag.forceMove(null) - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.module.emag.forceMove(null) - log_admin("[key_name_admin(usr)] has unemag'ed [R].") + var/mob/living/silicon/robot/robot = current + if (istype(robot)) + if(robot.module?.emag) + robot.drop_from_inventory(robot.module.emag) + robot.module.emag.forceMove(null) + robot.emagged = FALSE + log_admin("[key_name_admin(usr)] has unemag'ed [robot].") if("unemagcyborgs") - if (istype(current, /mob/living/silicon/ai)) + if (isAI(current)) var/mob/living/silicon/ai/ai = current - for (var/mob/living/silicon/robot/R in ai.connected_robots) - R.emagged = 0 - if (R.module) - if (R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.module.emag.forceMove(null) - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.module.emag.forceMove(null) - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.module.emag.forceMove(null) + for (var/mob/living/silicon/robot/robot in ai.connected_robots) + robot.emagged = FALSE + if(robot.module?.emag) + robot.drop_from_inventory(robot.module.emag) + robot.module.emag.forceMove(null) + log_admin("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.") else if (href_list["common"]) switch(href_list["common"]) if("undress") - for(var/obj/item/W in current) - current.drop_from_inventory(W) + for(var/obj/item/undressing in current) + current.drop_from_inventory(undressing) if("takeuplink") take_uplink() if("crystals") @@ -466,63 +436,23 @@ obj_count++ /datum/mind/proc/find_syndicate_uplink() - var/list/L = current.get_contents() - for (var/obj/item/I in L) + for (var/obj/item/I in current?.get_mob_contents()) if (I.hidden_uplink) return I.hidden_uplink - return null /datum/mind/proc/take_uplink() var/obj/item/uplink/H = find_syndicate_uplink() if(H) qdel(H) - -// check whether this mind's mob has been brigged for the given duration -// have to call this periodically for the duration to work properly -/datum/mind/proc/is_brigged(duration) - var/turf/T = current.loc - if(!istype(T)) - brigged_since = -1 - return 0 - var/is_currently_brigged = 0 - if(istype(T.loc,/area/security/brig)) - is_currently_brigged = 1 - if(current.GetIdCard()) - is_currently_brigged = 0 - - if(!is_currently_brigged) - brigged_since = -1 - return 0 - - if(brigged_since == -1) - brigged_since = world.time - - return (duration <= world.time - brigged_since) - /datum/mind/proc/reset() - assigned_role = null - special_role = null - role_alt_title = null - assigned_job = null - //faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know. - changeling = null - initial_account = null - objectives = list() - special_verbs = list() - has_been_rev = 0 - rev_cooldown = 0 - brigged_since = -1 - -//Antagonist role check -/mob/living/proc/check_special_role(role) - if(mind) - if(!role) - return mind.special_role - else - return (mind.special_role == role) ? 1 : 0 - else - return 0 + assigned_role = null + assigned_special_role = null + role_alt_title = null + assigned_job = null + initial_account = null + objectives = list() + conversion_cooldown = 0 //Initialisation procs /mob/living/proc/mind_initialize() @@ -530,7 +460,6 @@ mind.key = key else mind = new /datum/mind(key) - mind.original = src SSticker.minds += mind if(!mind.name) mind.name = real_name mind.current = src @@ -538,31 +467,26 @@ src.client.verbs += /client/proc/aooc //HUMAN -/mob/living/carbon/human/mind_initialize() +/mob/living/human/mind_initialize() ..() if(!mind.assigned_role) - mind.assigned_role = GLOB.using_map.default_assistant_title - -//slime -/mob/living/carbon/slime/mind_initialize() - ..() - mind.assigned_role = "slime" + mind.assigned_role = global.using_map.default_job_title //AI /mob/living/silicon/ai/mind_initialize() ..() - mind.assigned_role = "AI" + mind.assigned_role = ASSIGNMENT_COMPUTER //BORG /mob/living/silicon/robot/mind_initialize() ..() - mind.assigned_role = "Robot" + mind.assigned_role = ASSIGNMENT_ROBOT //PAI /mob/living/silicon/pai/mind_initialize() ..() mind.assigned_role = "pAI" - mind.special_role = "" + mind.assigned_special_role = "Personal Artificial Intelligence" //Animals /mob/living/simple_animal/mind_initialize() @@ -573,21 +497,11 @@ ..() mind.assigned_role = "Corgi" -/mob/living/simple_animal/shade/mind_initialize() - ..() - mind.assigned_role = "Shade" - -/mob/living/simple_animal/construct/builder/mind_initialize() - ..() - mind.assigned_role = "Artificer" - mind.special_role = "Cultist" - -/mob/living/simple_animal/construct/wraith/mind_initialize() - ..() - mind.assigned_role = "Wraith" - mind.special_role = "Cultist" - -/mob/living/simple_animal/construct/armoured/mind_initialize() - ..() - mind.assigned_role = "Juggernaut" - mind.special_role = "Cultist" +/datum/mind/proc/get_special_role_name(var/default_role_name) + if(istext(assigned_special_role)) + return assigned_special_role + if(ispath(assigned_special_role, /decl/special_role)) + var/decl/special_role/special_role = GET_DECL(assigned_special_role) + if(istype(special_role)) + return special_role.name + return default_role_name diff --git a/code/datums/move_intent/move_intent.dm b/code/datums/move_intent/move_intent.dm index 3c4735f6a448..b520d57b73d7 100644 --- a/code/datums/move_intent/move_intent.dm +++ b/code/datums/move_intent/move_intent.dm @@ -1,11 +1,13 @@ // Quick and deliberate movements are not necessarily mutually exclusive -#define MOVE_INTENT_DELIBERATE 0x0001 -#define MOVE_INTENT_EXERTIVE 0x0002 -#define MOVE_INTENT_QUICK 0x0004 +#define MOVE_INTENT_NONE 0 +#define MOVE_INTENT_DELIBERATE BITFLAG(0) +#define MOVE_INTENT_EXERTIVE BITFLAG(1) +#define MOVE_INTENT_QUICK BITFLAG(2) +#define MOVE_INTENT_NEUTRAL BITFLAG(3) /decl/move_intent var/name - var/flags = 0 + var/flags = MOVE_INTENT_NONE var/move_delay = 1 var/hud_icon_state @@ -21,15 +23,16 @@ /decl/move_intent/creep/Initialize() . = ..() - move_delay = config.creep_delay + move_delay = get_config_value(/decl/config/num/movement_creep) /decl/move_intent/walk name = "Walk" hud_icon_state = "walking" + flags = MOVE_INTENT_NEUTRAL /decl/move_intent/walk/Initialize() . = ..() - move_delay = config.walk_delay + move_delay = get_config_value(/decl/config/num/movement_walk) /decl/move_intent/run name = "Run" @@ -38,4 +41,4 @@ /decl/move_intent/run/Initialize() . = ..() - move_delay = config.run_delay + move_delay = get_config_value(/decl/config/num/movement_run) diff --git a/code/datums/move_intent/move_intent_animal.dm b/code/datums/move_intent/move_intent_animal.dm new file mode 100644 index 000000000000..e7fc6b376b81 --- /dev/null +++ b/code/datums/move_intent/move_intent_animal.dm @@ -0,0 +1,23 @@ +/decl/move_intent/walk/animal + move_delay = 3 + +/decl/move_intent/run/animal + move_delay = 2 + +/decl/move_intent/walk/animal_slow + move_delay = 4 + +/decl/move_intent/run/animal_slow + move_delay = 3 + +/decl/move_intent/walk/animal_very_slow + move_delay = 8 + +/decl/move_intent/run/animal_very_slow + move_delay = 6 + +/decl/move_intent/walk/animal_fast + move_delay = 2 + +/decl/move_intent/run/animal_fast + move_delay = 1 diff --git a/code/datums/movement/atom_movable.dm b/code/datums/movement/atom_movable.dm index d9376edae725..de5e46e87b8e 100644 --- a/code/datums/movement/atom_movable.dm +++ b/code/datums/movement/atom_movable.dm @@ -1,13 +1,13 @@ // Static movement denial -/datum/movement_handler/no_move/MayMove() +/datum/movement_handler/no_move/MayMove(mob/mover, is_external) return MOVEMENT_STOP // Anchor check -/datum/movement_handler/anchored/MayMove() +/datum/movement_handler/anchored/MayMove(mob/mover, is_external) return host.anchored ? MOVEMENT_STOP : MOVEMENT_PROCEED // Movement relay -/datum/movement_handler/move_relay/DoMove(var/direction, var/mover) +/datum/movement_handler/move_relay/DoMove(direction, mob/mover, is_external) var/atom/movable/AM = host.loc if(!istype(AM)) return @@ -25,13 +25,13 @@ ..() src.delay = max(1, delay) -/datum/movement_handler/delay/DoMove() +/datum/movement_handler/delay/DoMove(direction, mob/mover, is_external) next_move = world.time + delay -/datum/movement_handler/delay/MayMove() +/datum/movement_handler/delay/MayMove(mob/mover, is_external) return world.time >= next_move ? MOVEMENT_PROCEED : MOVEMENT_STOP // Relay self -/datum/movement_handler/move_relay_self/DoMove(var/direction, var/mover) +/datum/movement_handler/move_relay_self/DoMove(direction, mob/mover, is_external) host.relaymove(mover, direction) return MOVEMENT_HANDLED diff --git a/code/datums/movement/automove.dm b/code/datums/movement/automove.dm new file mode 100644 index 000000000000..a07d65d0324b --- /dev/null +++ b/code/datums/movement/automove.dm @@ -0,0 +1,40 @@ +// These procs are a way to implement something like walk_to()/walk_away() +// while also preserving the full move chain for mobs. /obj and such can +// get away with walk(), but mobs need to set move delays, update glide size, etc. + +/atom/movable/proc/get_default_automove_controller_type() + return /decl/automove_controller + +/// Cancels automoving and unregisters the atom from the subsystem, including the current processing run. +/atom/movable/proc/stop_automove() + SHOULD_CALL_PARENT(TRUE) + walk_to(src, 0) // Legacy call to stop BYOND's inbuilt movement. + SSautomove.unregister_mover(src) + +/// Registers an atom with SSautomove, including a move handler and metadata. Moving will begin next tick. +/atom/movable/proc/start_automove(target, movement_type, datum/automove_metadata/metadata) + SHOULD_CALL_PARENT(TRUE) + SSautomove.register_mover(src, (movement_type || get_default_automove_controller_type()), metadata) + +/// Called when an atom is within the acceptable parameters for not moving further (ideal range). Does not necessarily imply the atom has unregistered (see stop_automove()). +/atom/movable/proc/finished_automove() + SHOULD_CALL_PARENT(TRUE) + return FALSE + +/// Called by SSautomove when an atom fails to move in circumstances where it would like to. As with finished_automove, does not imply unregistering from SSautomove. +/atom/movable/proc/failed_automove() + SHOULD_CALL_PARENT(TRUE) + return FALSE + +// Jesus Christ why do I write such long proc names +/// Used by some mobs to vary the acceptable distance from target when automoving. +/atom/movable/proc/get_acceptable_automove_distance_from_target() + return 0 + +/// Should return a reference to the current atom target. +/atom/movable/proc/get_automove_target(datum/automove_metadata/metadata) + return null + +/// Generalized entrypoint for checking CanMove and such on /mob. +/atom/movable/proc/can_do_automated_move(variant_move_delay) + return FALSE diff --git a/code/datums/movement/automove_controller.dm b/code/datums/movement/automove_controller.dm new file mode 100644 index 000000000000..b413d9998497 --- /dev/null +++ b/code/datums/movement/automove_controller.dm @@ -0,0 +1,66 @@ +/// Implements automove logic; can be overridden on mob procs if you want to vary the logic from the below. +/decl/automove_controller + var/completion_signal = FALSE // Set to TRUE if you want movement to stop processing when the atom reaches its target. + var/failure_signal = FALSE // Set to TRUE if you want movement to stop processing when the atom fails to move. + var/try_avoid_obstacles = TRUE // Will try to move 90 degrees around an obstacle. + +/decl/automove_controller/proc/handle_mover(atom/movable/mover, datum/automove_metadata/metadata) + + // Cease automovement if we got an invalid mover.. + if(!istype(mover)) + return PROCESS_KILL + + // Null target means abandon pathing, regardless of return signals. + var/atom/target = mover.get_automove_target(metadata) + if(!istype(target)) + return PROCESS_KILL + + // Return early if we are in the process of moving, as we will definitely fail MayMove at the end() + if(ismob(mover)) + var/mob/mover_mob = mover + if(mover_mob.moving) + return TRUE + + // Cease automovement if we're already at the target. + var/avoid_target = metadata?.avoid_target + if(!avoid_target && (get_turf(mover) == get_turf(target) || (ismovable(target) && mover.Adjacent(target)))) + mover.finished_automove() + return completion_signal + + // Cease movement if we're close enough to the target. + var/acceptable_move_dist = isnull(metadata?.acceptable_distance) ? mover.get_acceptable_automove_distance_from_target() : metadata.acceptable_distance + if(avoid_target ? (get_dist(mover, target) >= acceptable_move_dist) : (get_dist(mover, target) <= acceptable_move_dist)) + mover.finished_automove() + return completion_signal + + // Cease automovement if we failed to move a turf. + if(mover.can_do_automated_move(metadata?.move_delay)) + if(avoid_target) + target = get_edge_target_turf(target, get_dir(target, mover)) + + // Note for future coders: SelfMove() only confirms if a handler handled the move, not if the atom moved. + var/old_loc = mover.loc + + // Try to move directly. + var/target_dir = get_dir(mover, target) + if(!target_dir) + if(avoid_target) + target_dir = pick(global.cardinal) + else + return TRUE // no idea how we would get into this position + + if(mover.SelfMove(target_dir) && (old_loc != mover.loc)) + mover.handle_post_automoved(old_loc) + return (mover.get_automove_target() == mover.loc) // We may have transitioned to the next step in a path. + + if(try_avoid_obstacles) + // Try to move around any obstacle. + var/static/list/_alt_dir_rot = list(45, -45) + for(var/alt_dir in shuffle(_alt_dir_rot)) + mover.reset_movement_delay() + if(mover.SelfMove(turn(target_dir, alt_dir)) && (old_loc != mover.loc)) + return TRUE + + mover.failed_automove() + + return failure_signal diff --git a/code/datums/movement/automove_metadata.dm b/code/datums/movement/automove_metadata.dm new file mode 100644 index 000000000000..f1f4796cafb0 --- /dev/null +++ b/code/datums/movement/automove_metadata.dm @@ -0,0 +1,10 @@ +// Overrides some aspects of mob movement for the purposes of automove. +/datum/automove_metadata + var/move_delay + var/acceptable_distance + var/avoid_target + +/datum/automove_metadata/New(_move_delay, _acceptable_distance, _avoid_target) + move_delay = _move_delay + acceptable_distance = _acceptable_distance + avoid_target = _avoid_target diff --git a/code/datums/movement/mob.dm b/code/datums/movement/mob.dm index bdd746f361e4..996c62150859 100644 --- a/code/datums/movement/mob.dm +++ b/code/datums/movement/mob.dm @@ -1,26 +1,5 @@ -// Movement relayed to self handling -/datum/movement_handler/mob/relayed_movement - var/prevent_host_move = FALSE - var/list/allowed_movers - -/datum/movement_handler/mob/relayed_movement/MayMove(var/mob/mover, var/is_external) - if(is_external) - return MOVEMENT_PROCEED - if(mover == mob && !(prevent_host_move && LAZYLEN(allowed_movers) && !LAZYISIN(allowed_movers, mover))) - return MOVEMENT_PROCEED - if(LAZYISIN(allowed_movers, mover)) - return MOVEMENT_PROCEED - - return MOVEMENT_STOP - -/datum/movement_handler/mob/relayed_movement/proc/AddAllowedMover(var/mover) - LAZYDISTINCTADD(allowed_movers, mover) - -/datum/movement_handler/mob/relayed_movement/proc/RemoveAllowedMover(var/mover) - LAZYREMOVE(allowed_movers, mover) - // Admin object possession -/datum/movement_handler/mob/admin_possess/DoMove(var/direction) +/datum/movement_handler/mob/admin_possess/DoMove(direction, mob/mover, is_external) if(QDELETED(mob.control_object)) return MOVEMENT_REMOVE @@ -34,18 +13,22 @@ control_object.set_dir(direction) // Death handling -/datum/movement_handler/mob/death/DoMove() - if(mob.stat != DEAD) +/datum/movement_handler/mob/death/DoMove(direction, mob/mover, is_external) + if(mob != mover || mob.stat != DEAD) return + . = MOVEMENT_HANDLED + if(!mob.client) return + mob.ghostize() // Incorporeal/Ghost movement -/datum/movement_handler/mob/incorporeal/DoMove(var/direction) +/datum/movement_handler/mob/incorporeal/DoMove(direction, mob/mover, is_external) . = MOVEMENT_HANDLED - direction = mob.AdjustMovementDirection(direction) + direction = mob.AdjustMovementDirection(direction, mover) + mob.set_glide_size(0) var/turf/T = get_step(mob, direction) if(!mob.MayEnterTurf(T)) @@ -61,7 +44,7 @@ return // Eye movement -/datum/movement_handler/mob/eye/DoMove(var/direction, var/mob/mover) +/datum/movement_handler/mob/eye/DoMove(direction, mob/mover, is_external) if(IS_NOT_SELF(mover)) // We only care about direct movement return if(!mob.eyeobj) @@ -69,7 +52,7 @@ mob.eyeobj.EyeMove(direction) return MOVEMENT_HANDLED -/datum/movement_handler/mob/eye/MayMove(var/mob/mover, var/is_external) +/datum/movement_handler/mob/eye/MayMove(mob/mover, is_external) if(IS_NOT_SELF(mover)) return MOVEMENT_PROCEED if(is_external) @@ -79,53 +62,36 @@ return (MOVEMENT_PROCEED|MOVEMENT_HANDLED) /datum/movement_handler/mob/space - var/allow_move + var/last_space_move_result + +// Notes on space movement chain: +// - owning mob calls MayMove() via normal movement handler chain +// - MayMove() sets last_space_move_result based on is_space_movement_permitted() (checks for footing, magboots, etc) +// - last_space_move_result is checked in DoMove() and passed to try_space_move() as a param, which returns TRUE/FALSE +// - if the original move result was forbidden, or try_space_move() fails, the handler prevents movement. +// - Otherwise it goes ahead and lets the mob move. // Space movement -/datum/movement_handler/mob/space/DoMove(var/direction, var/mob/mover) - if(!mob.has_gravity()) - if(!allow_move) - return MOVEMENT_HANDLED - if(!mob.space_do_move(allow_move, direction)) - return MOVEMENT_HANDLED +/datum/movement_handler/mob/space/DoMove(direction, mob/mover, is_external) + if(mob.has_gravity() || (IS_NOT_SELF(mover) && is_external)) + return + if(last_space_move_result == SPACE_MOVE_FORBIDDEN || !mob.try_space_move(last_space_move_result, direction)) + return MOVEMENT_HANDLED -/datum/movement_handler/mob/space/MayMove(var/mob/mover, var/is_external) +/datum/movement_handler/mob/space/MayMove(mob/mover, is_external) if(IS_NOT_SELF(mover) && is_external) return MOVEMENT_PROCEED - if(!mob.has_gravity()) - allow_move = mob.Process_Spacemove(1) - if(!allow_move) + last_space_move_result = mob.is_space_movement_permitted(allow_movement = TRUE) + if(last_space_move_result == SPACE_MOVE_FORBIDDEN) return MOVEMENT_STOP - return MOVEMENT_PROCEED // Buckle movement -/datum/movement_handler/mob/buckle_relay/DoMove(var/direction, var/mover) - // TODO: Datumlize buckle-handling - if(istype(mob.buckled, /obj/vehicle)) - //drunk driving - if(mob.confused && prob(20)) //vehicles tend to keep moving in the same direction - direction = turn(direction, pick(90, -90)) - mob.buckled.relaymove(mob, direction) - return MOVEMENT_HANDLED +/datum/movement_handler/mob/buckle_relay/DoMove(direction, mob/mover, is_external) + return mob?.buckled?.handle_buckled_relaymove(src, mob, direction, mover) - if(mob.buckled) // Wheelchair driving! - if(istype(mob.loc, /turf/space)) - return // No wheelchair driving in space - if(istype(mob.buckled, /obj/structure/bed/chair/wheelchair)) - . = MOVEMENT_HANDLED - if(ishuman(mob)) - var/mob/living/carbon/human/driver = mob - var/obj/item/organ/external/l_hand = driver.get_organ(BP_L_HAND) - var/obj/item/organ/external/r_hand = driver.get_organ(BP_R_HAND) - if((!l_hand || l_hand.is_stump()) && (!r_hand || r_hand.is_stump())) - return // No hands to drive your chair? Tough luck! - //drunk wheelchair driving - direction = mob.AdjustMovementDirection(direction) - mob.buckled.DoMove(direction, mob) - -/datum/movement_handler/mob/buckle_relay/MayMove(var/mover) +/datum/movement_handler/mob/buckle_relay/MayMove(mob/mover, is_external) if(mob.buckled) return mob.buckled.MayMove(mover, FALSE) ? (MOVEMENT_PROCEED|MOVEMENT_HANDLED) : MOVEMENT_STOP return MOVEMENT_PROCEED @@ -135,11 +101,14 @@ var/next_move /datum/movement_handler/mob/delay/DoMove(var/direction, var/mover, var/is_external) - if(is_external) - return - next_move = world.time + max(1, mob.movement_delay()) - -/datum/movement_handler/mob/delay/MayMove(var/mover, var/is_external) + if(!is_external) + var/delay = max(1, mob.get_movement_delay(direction)) + if(direction & (direction - 1)) //moved diagonally successfully + delay *= sqrt(2) + next_move = world.time + delay + mob.set_glide_size(delay) + +/datum/movement_handler/mob/delay/MayMove(mob/mover, is_external) if(IS_NOT_SELF(mover) && is_external) return MOVEMENT_PROCEED return ((mover && mover != mob) || world.time >= next_move) ? MOVEMENT_PROCEED : MOVEMENT_STOP @@ -151,39 +120,43 @@ next_move += max(0, delay) // Stop effect -/datum/movement_handler/mob/stop_effect/DoMove() - if(MayMove() == MOVEMENT_STOP) +/datum/movement_handler/mob/DoMove(direction, mob/mover, is_external) + if(MayMove(mover, is_external) == MOVEMENT_STOP) return MOVEMENT_HANDLED -/datum/movement_handler/mob/stop_effect/MayMove() +/datum/movement_handler/mob/stop_effect/MayMove(mob/mover, is_external) for(var/obj/effect/stop/S in mob.loc) if(S.victim == mob) return MOVEMENT_STOP return MOVEMENT_PROCEED // Transformation -/datum/movement_handler/mob/transformation/MayMove() +/datum/movement_handler/mob/transformation/MayMove(mob/mover, is_external) return MOVEMENT_STOP // Consciousness - Is the entity trying to conduct the move conscious? -/datum/movement_handler/mob/conscious/MayMove(var/mob/mover) +/datum/movement_handler/mob/conscious/MayMove(mob/mover, is_external) return (mover ? mover.stat == CONSCIOUS : mob.stat == CONSCIOUS) ? MOVEMENT_PROCEED : MOVEMENT_STOP // Along with more physical checks -/datum/movement_handler/mob/physically_capable/MayMove(var/mob/mover) +/datum/movement_handler/mob/physically_capable/MayMove(mob/mover, is_external) // We only check physical capability if the host mob tried to do the moving - return ((mover && mover != mob) || !mob.incapacitated(INCAPACITATION_DISABLED & ~INCAPACITATION_FORCELYING)) ? MOVEMENT_PROCEED : MOVEMENT_STOP + if(mover && mover != mob) + return MOVEMENT_PROCEED + if(mob.incapacitated(INCAPACITATION_DISABLED & ~INCAPACITATION_FORCELYING)) + return MOVEMENT_STOP + return MOVEMENT_PROCEED // Is anything physically preventing movement? -/datum/movement_handler/mob/physically_restrained/MayMove(var/mob/mover) - if(mob.anchored) +/datum/movement_handler/mob/physically_restrained/MayMove(mob/mover, is_external) + if(istype(mob.buckled) && !mob.buckled.buckle_movable) if(mover == mob) - to_chat(mob, SPAN_WARNING("You're anchored down!")) + to_chat(mob, SPAN_WARNING("You're buckled to \the [mob.buckled]!")) return MOVEMENT_STOP - if(istype(mob.buckled) && !mob.buckled.buckle_movable) + if(mob.anchored) if(mover == mob) - to_chat(mob, SPAN_WARNING("You're buckled to \the [mob.buckled]!")) + to_chat(mob, SPAN_WARNING("You're anchored down!")) return MOVEMENT_STOP if(LAZYLEN(mob.pinned)) @@ -191,8 +164,8 @@ to_chat(mob, SPAN_WARNING("You're pinned down by \a [mob.pinned[1]]!")) return MOVEMENT_STOP - for(var/obj/item/grab/G in mob.grabbed_by) - if(G.assailant != mob && (mob.restrained() || G.stop_move())) + for(var/obj/item/grab/grab as anything in mob.grabbed_by) + if(grab.assailant != mob && grab.assailant != mover && (mob.restrained() || grab.stop_move())) if(mover == mob) to_chat(mob, SPAN_WARNING("You're restrained and cannot move!")) mob.ProcessGrabs() @@ -200,11 +173,11 @@ return MOVEMENT_PROCEED -// Finally.. the last of the mob movement junk -/datum/movement_handler/mob/movement/DoMove(var/direction, var/mob/mover) +// Finally... the last of the mob movement junk +/datum/movement_handler/mob/movement/DoMove(direction, mob/mover, is_external) . = MOVEMENT_HANDLED - if(mob.moving) + if(!mob || mob.moving) return if(!mob.lastarea) @@ -213,100 +186,83 @@ //We are now going to move mob.moving = 1 - direction = mob.AdjustMovementDirection(direction) + if(mover == mob) + direction = mob.AdjustMovementDirection(direction, mover) + var/turf/old_turf = get_turf(mob) step(mob, direction) - // Something with dragging things - var/extra_delay = HandleGrabs(direction, old_turf) - - if(QDELETED(mob)) // No idea why, but this was causing null check runtimes on live. + if(!mob) + return // If the mob gets deleted on move (e.g. Entered, whatever), it wipes this reference on us in Destroy (and we should be aborting all action anyway). + if(mob.loc == old_turf) // Did not move for whatever reason. + mob.moving = FALSE return - mob.ExtraMoveCooldown(extra_delay) - - for (var/obj/item/grab/G in mob) - if (G.assailant_reverse_facing()) - mob.set_dir(GLOB.reverse_dir[direction]) - G.assailant_moved() - for (var/obj/item/grab/G in mob.grabbed_by) - G.adjust_position() - - if(direction & (UP|DOWN)) - var/txt_dir = (direction & UP) ? "upwards" : "downwards" - old_turf.visible_message(SPAN_NOTICE("[mob] moves [txt_dir].")) - for(var/obj/item/grab/G in mob.get_active_grabs()) - if(!G.affecting) - continue - var/turf/start = G.affecting.loc - var/turf/destination = (direction == UP) ? GetAbove(G.affecting) : GetBelow(G.affecting) - if(!start.CanZPass(G.affecting, direction)) - to_chat(mob, SPAN_WARNING("\The [start] blocked your pulled object!")) - qdel(G) - continue - if(!destination.CanZPass(G.affecting, direction)) - to_chat(mob, SPAN_WARNING("The [G.affecting] you were pulling bumps up against \the [destination].")) - qdel(G) - continue - for(var/atom/A in destination) - if(!A.CanMoveOnto(G.affecting, start, 1.5, direction)) - to_chat(mob, SPAN_WARNING("\The [A] blocks the [G.affecting] you were pulling.")) - qdel(G) - continue - G.affecting.forceMove(destination) - continue + mob.handle_footsteps() - //Moving with objects stuck in you can cause bad times. - if(get_turf(mob) != old_turf) - if(MOVING_QUICKLY(mob)) - mob.last_quick_move_time = world.time - mob.adjust_stamina(-(mob.get_stamina_used_per_step() * (1+mob.encumbrance()))) - mob.handle_embedded_and_stomach_objects() + // Sprinting uses up stamina and causes exertion effects. + if(MOVING_QUICKLY(mob)) + mob.last_quick_move_time = world.time + mob.adjust_stamina(-(mob.get_stamina_used_per_step() * (1+mob.encumbrance()))) + if(ishuman(mob)) + var/decl/species/species = mob.get_species() + if(species) + species.handle_exertion(mob) - mob.moving = 0 + //Moving with objects stuck in you can cause bad times. + mob.handle_embedded_and_stomach_objects() + mob.moving = FALSE -/datum/movement_handler/mob/movement/MayMove(var/mob/mover) - return IS_SELF(mover) && mob.moving ? MOVEMENT_STOP : MOVEMENT_PROCEED +/datum/movement_handler/mob/movement/MayMove(mob/mover, is_external) + return IS_SELF(mover) && mob.moving ? MOVEMENT_STOP : MOVEMENT_PROCEED /mob/proc/get_stamina_used_per_step() return 1 -/mob/living/carbon/human/get_stamina_used_per_step() +/mob/proc/get_stamina_skill_mod() + return 1 + +/mob/living/human/get_stamina_skill_mod() var/mod = (1-((get_skill_value(SKILL_HAULING) - SKILL_MIN)/(SKILL_MAX - SKILL_MIN))) if(species && (species.species_flags & SPECIES_FLAG_LOW_GRAV_ADAPTED)) if(has_gravity()) mod *= 1.2 else mod *= 0.8 + return mod - return config.minimum_sprint_cost + (config.skill_sprint_cost_range * mod) - -/datum/movement_handler/mob/movement/proc/HandleGrabs(var/direction, var/old_turf) - . = 0 - // TODO: Look into making grabs use movement events instead, this is a mess. - for(var/obj/item/grab/G in mob?.get_active_grabs()) - if(G.assailant == G.affecting) - return - if(G.affecting.anchored) - return - . = max(., G.grab_slowdown()) - if(isturf(mob.loc) && mob.loc != old_turf) - for(var/atom/movable/M in (mob.ret_grab()-mob)) - if(isturf(M.loc) && M.loc != mob.loc && get_dist(old_turf, M) <= 1) - step(M, get_dir(M.loc, old_turf)) - G.adjust_position() +/mob/living/human/get_stamina_used_per_step() + return get_config_value(/decl/config/num/movement_min_sprint_cost) + get_config_value(/decl/config/num/movement_skill_sprint_cost_range) * get_stamina_skill_mod() // Misc. helpers /mob/proc/MayEnterTurf(var/turf/T) return T && !((mob_flags & MOB_FLAG_HOLY_BAD) && check_is_holy_turf(T)) -/mob/proc/AdjustMovementDirection(var/direction) +/** + * This proc adjusts movement direction for mobs with STAT_CONFUSE. + * + * Returns a direction, randomly adjusted if the mob had STAT_CONFUSE. + * + * Arguments: + * * direction: The direction, mob was going to move before adjustment + * * mover: The initiator of movement + */ +/mob/proc/AdjustMovementDirection(var/direction, var/mob/mover) + + if(!direction || !isnum(direction)) + return 0 + . = direction - if(!confused) + + // If we are moved not on our own, we don't get move debuff + if(src != mover) + return + + if(!HAS_STATUS(src, STAT_CONFUSE)) return var/stability = MOVING_DELIBERATELY(src) ? 75 : 25 if(prob(stability)) return - return prob(50) ? GLOB.cw_dir[.] : GLOB.ccw_dir[.] + return prob(50) ? global.cw_dir[.] : global.ccw_dir[.] diff --git a/code/datums/movement/movement.dm b/code/datums/movement/movement.dm index 47b53b717a67..a4f79e092ffc 100644 --- a/code/datums/movement/movement.dm +++ b/code/datums/movement/movement.dm @@ -1,8 +1,7 @@ -var/const/MOVEMENT_HANDLED = 0x0001 // If no further movement handling should occur after this -var/const/MOVEMENT_REMOVE = 0x0002 - -var/const/MOVEMENT_PROCEED = 0x0004 -var/const/MOVEMENT_STOP = 0x0008 +var/global/const/MOVEMENT_HANDLED = BITFLAG(0) // If no further movement handling should occur after this +var/global/const/MOVEMENT_REMOVE = BITFLAG(1) +var/global/const/MOVEMENT_PROCEED = BITFLAG(2) +var/global/const/MOVEMENT_STOP = BITFLAG(3) #define INIT_MOVEMENT_HANDLERS \ if(LAZYLEN(movement_handlers) && ispath(movement_handlers[1])) { \ @@ -27,9 +26,8 @@ if(LAZYLEN(movement_handlers) && ispath(movement_handlers[1])) { \ if(ispath(movement_handlers[1])) return (handler_path in movement_handlers) else - for(var/mh in movement_handlers) - var/datum/MH = mh - if(MH.type == handler_path) + for(var/datum/movement_handler/movement_handler as anything in movement_handlers) + if(movement_handler.type == handler_path) return TRUE return FALSE @@ -79,15 +77,25 @@ if(LAZYLEN(movement_handlers) && ispath(movement_handlers[1])) { \ #define SET_MOVER(X) X = X || src #define SET_IS_EXTERNAL(X) is_external = isnull(is_external) ? (mover != src) : is_external -/atom/movable/proc/DoMove(var/direction, var/mob/mover, var/is_external) +/atom/movable/proc/DoMove(direction, mob/mover, is_external) + + if(!direction || !isnum(direction)) + return MOVEMENT_STOP + INIT_MOVEMENT_HANDLERS SET_MOVER(mover) SET_IS_EXTERNAL(mover) - for(var/mh in movement_handlers) - var/datum/movement_handler/movement_handler = mh + if(!length(movement_handlers) && is_external && isturf(loc)) + var/oldloc = loc + var/turf/T = get_step(loc, direction) + if(istype(T)) + step(src, direction) + return loc != oldloc + + for(var/datum/movement_handler/movement_handler as anything in movement_handlers) if(movement_handler.MayMove(mover, is_external) & MOVEMENT_STOP) - return MOVEMENT_HANDLED + return MOVEMENT_STOP . = movement_handler.DoMove(direction, mover, is_external) if(. & MOVEMENT_REMOVE) @@ -97,13 +105,12 @@ if(LAZYLEN(movement_handlers) && ispath(movement_handlers[1])) { \ // is_external means that something else (not inside us) is asking if we may move // This for example includes mobs bumping into each other -/atom/movable/proc/MayMove(var/mob/mover, var/is_external) +/atom/movable/proc/MayMove(mob/mover, is_external) INIT_MOVEMENT_HANDLERS SET_MOVER(mover) SET_IS_EXTERNAL(mover) - for(var/mh in movement_handlers) - var/datum/movement_handler/movement_handler = mh + for(var/datum/movement_handler/movement_handler as anything in movement_handlers) var/may_move = movement_handler.MayMove(mover, is_external) if(may_move & MOVEMENT_STOP) return FALSE @@ -129,11 +136,11 @@ if(LAZYLEN(movement_handlers) && ispath(movement_handlers[1])) { \ host = null . = ..() -/datum/movement_handler/proc/DoMove(var/direction, var/mob/mover, var/is_external) +/datum/movement_handler/proc/DoMove(direction, mob/mover, is_external) return // Asks the handlers if the mob may move, ignoring destination, if attempting a DoMove() -/datum/movement_handler/proc/MayMove(var/mob/mover, var/is_external) +/datum/movement_handler/proc/MayMove(mob/mover, is_external) return MOVEMENT_PROCEED /******* diff --git a/code/datums/movement/multiz.dm b/code/datums/movement/multiz.dm index 02980cb6a5c8..77b6315c22cd 100644 --- a/code/datums/movement/multiz.dm +++ b/code/datums/movement/multiz.dm @@ -1,4 +1,4 @@ -/datum/movement_handler/mob/multiz/DoMove(var/direction, var/mob/mover, var/is_external) +/datum/movement_handler/mob/multiz/DoMove(direction, mob/mover, is_external) if(!(direction & (UP|DOWN))) return MOVEMENT_PROCEED @@ -12,10 +12,6 @@ to_chat(mob, "\The [start] is in the way.") return MOVEMENT_HANDLED - if(!destination.CanZPass(mob, direction)) - to_chat(mob, "You bump against \the [destination].") - return MOVEMENT_HANDLED - var/area/area = get_area(mob) if(direction == UP && area.has_gravity() && !mob.can_overcome_gravity()) to_chat(mob, "Gravity stops you from moving upward.") @@ -33,7 +29,7 @@ return MOVEMENT_PROCEED //For ghosts and such -/datum/movement_handler/mob/multiz_connected/DoMove(var/direction, var/mob/mover, var/is_external) +/datum/movement_handler/mob/multiz_connected/DoMove(direction, mob/mover, is_external) if(!(direction & (UP|DOWN))) return MOVEMENT_PROCEED @@ -44,7 +40,7 @@ return MOVEMENT_PROCEED -/datum/movement_handler/deny_multiz/DoMove(var/direction, var/mob/mover, var/is_external) +/datum/movement_handler/deny_multiz/DoMove(direction, mob/mover, is_external) if(direction & (UP|DOWN)) return MOVEMENT_HANDLED return MOVEMENT_PROCEED diff --git a/code/datums/movement/robot.dm b/code/datums/movement/robot.dm index fc7ef731b0ac..2674938b3cc0 100644 --- a/code/datums/movement/robot.dm +++ b/code/datums/movement/robot.dm @@ -14,10 +14,13 @@ . = ..() // Use power while moving. -/datum/movement_handler/robot/use_power/DoMove() +/datum/movement_handler/robot/use_power/DoMove(direction, mob/mover, is_external) var/datum/robot_component/actuator/A = robot.get_component("actuator") - if(!robot.cell_use_power(A.active_usage * robot.power_efficiency)) + if(!is_external && !robot.cell_use_power(A.active_usage * robot.power_efficiency)) return MOVEMENT_HANDLED + return MOVEMENT_PROCEED -/datum/movement_handler/robot/use_power/MayMove() - return robot.is_component_functioning("actuator") ? MOVEMENT_PROCEED : MOVEMENT_STOP +/datum/movement_handler/robot/use_power/MayMove(mob/mover, is_external) + if(is_external || (!robot.incapacitated() && !robot.lockcharge && robot.is_component_functioning("actuator"))) + return MOVEMENT_PROCEED + return MOVEMENT_STOP diff --git a/code/datums/music_tracks/1.dm b/code/datums/music_tracks/1.dm index 9c46a726595c..77e83ef59f3b 100644 --- a/code/datums/music_tracks/1.dm +++ b/code/datums/music_tracks/1.dm @@ -1,4 +1,4 @@ -/music_track/digit_one +/decl/music_track/digit_one artist = "Kelly Bailey" title = "Half-Life 2 - Tracking Device" song = 'sound/music/1.ogg' diff --git a/code/datums/music_tracks/Torch.dm b/code/datums/music_tracks/Torch.dm deleted file mode 100644 index 7ea136edcfbf..000000000000 --- a/code/datums/music_tracks/Torch.dm +++ /dev/null @@ -1,14 +0,0 @@ -/music_track/torch - artist = "L. Luke Leimer/LorenLuke" - title = "Torch: A Light in the Darkness" - song = 'sound/music/Torch.ogg' - license = /decl/license/cc_by_nc_sa_3_0 - url = "https://soundcloud.com/luke-leimer/torch-a-light-in-the-darkness" - -/* -'Torch: A Light in the Darkness' composed by: Loren Luke Leimer, (c) 2017 - -Licensed for use under Creative Commons License: CC BY-SA 3.0 - -Link to online version at: https://soundcloud.com/luke-leimer/torch-a-light-in-the-darkness -*/ diff --git a/code/datums/music_tracks/_music_track.dm b/code/datums/music_tracks/_music_track.dm index 38d13c5d191a..c1eba028164f 100644 --- a/code/datums/music_tracks/_music_track.dm +++ b/code/datums/music_tracks/_music_track.dm @@ -1,24 +1,41 @@ -/music_track +/decl/music_track var/artist var/title var/album var/decl/license/license var/song var/url // Remember to include http:// or https:// or BYOND will be sad - var/volume = 70 + var/music_volume = 70 + abstract_type = /decl/music_track -/music_track/New() - license = decls_repository.get_decl(license) +/decl/music_track/Initialize() + . = ..() + license = GET_DECL(license) -/music_track/proc/play_to(var/listener) +/decl/music_track/validate() + . = ..() + if(!song) + . += "Missing song" + if(!title) + . += "Missing title" + if(istype(license, /decl/license)) + if(license.attribution_mandatory) + if(!artist || cmptext(artist, "unknown")) + . += "Invalid artist" + if(!url || cmptext(url, "unknown")) + . += "Invalid url" + else + . += "Invalid license" + +/decl/music_track/proc/play_to(var/listener) to_chat(listener, "Now Playing:") to_chat(listener, "[title][artist ? " by [artist]" : ""][album ? " ([album])" : ""]") if(url) to_chat(listener, url) to_chat(listener, "License: [license.name]") - sound_to(listener, sound(song, repeat = 1, wait = 0, volume = volume, channel = GLOB.lobby_sound_channel)) + sound_to(listener, sound(song, repeat = 1, wait = 0, volume = music_volume, channel = sound_channels.lobby_channel)) // No VV editing anything about music tracks -/music_track/VV_static() +/decl/music_track/VV_static() return ..() + vars diff --git a/code/datums/music_tracks/absconditus.dm b/code/datums/music_tracks/absconditus.dm index 21e85c4c746d..597048976086 100644 --- a/code/datums/music_tracks/absconditus.dm +++ b/code/datums/music_tracks/absconditus.dm @@ -1,4 +1,4 @@ -/music_track/absconditus +/decl/music_track/absconditus artist = "Zhay Tee" title = "Absconditus" album = "Minerva: Metastasis OST" diff --git a/code/datums/music_tracks/ambispace.dm b/code/datums/music_tracks/ambispace.dm index fdab7f3a59d3..19649ff6a6f1 100644 --- a/code/datums/music_tracks/ambispace.dm +++ b/code/datums/music_tracks/ambispace.dm @@ -1,4 +1,4 @@ -/music_track/ambispace +/decl/music_track/ambispace artist = "Alstroemeria Records" title = "Bad Apple!! (slowed down)" song = 'sound/ambience/ambispace.ogg' diff --git a/code/datums/music_tracks/businessend.dm b/code/datums/music_tracks/businessend.dm index bf354bacfe9f..921c0f3f8ff8 100644 --- a/code/datums/music_tracks/businessend.dm +++ b/code/datums/music_tracks/businessend.dm @@ -1,4 +1,4 @@ -/music_track/businessend +/decl/music_track/businessend artist = "Cletus Got Shot" title = "Business End" song = 'sound/music/businessend.ogg' diff --git a/code/datums/music_tracks/chasing_time.dm b/code/datums/music_tracks/chasing_time.dm index 9769ddb9c9b4..043f36c272a3 100644 --- a/code/datums/music_tracks/chasing_time.dm +++ b/code/datums/music_tracks/chasing_time.dm @@ -1,4 +1,4 @@ -/music_track/chasing_time +/decl/music_track/chasing_time artist = "Dexter Britain" title = "Chasing Time" album = "Creative Commons Vol. 1" diff --git a/code/datums/music_tracks/clouds_of_fire.dm b/code/datums/music_tracks/clouds_of_fire.dm index 8350a91b41c4..5bfce92b55b9 100644 --- a/code/datums/music_tracks/clouds_of_fire.dm +++ b/code/datums/music_tracks/clouds_of_fire.dm @@ -1,5 +1,6 @@ -/music_track/clouds_of_fire +/decl/music_track/clouds_of_fire artist = "Hector/dMk" title = "Clouds of Fire" song = 'sound/music/clouds.s3m' license = /decl/license/grandfathered + url = "https://modarchive.org/index.php?request=view_by_moduleid&query=73980" diff --git a/code/datums/music_tracks/comet_haley.dm b/code/datums/music_tracks/comet_haley.dm index b66b22a24817..576ae9ebdf04 100644 --- a/code/datums/music_tracks/comet_haley.dm +++ b/code/datums/music_tracks/comet_haley.dm @@ -1,4 +1,4 @@ -/music_track/comet_haley +/decl/music_track/comet_haley artist = "Stellardrone" title = "Comet Halley" album = "Light Years" diff --git a/code/datums/music_tracks/df_theme.dm b/code/datums/music_tracks/df_theme.dm index 95b4df5c38d7..efb00a550af2 100644 --- a/code/datums/music_tracks/df_theme.dm +++ b/code/datums/music_tracks/df_theme.dm @@ -1,4 +1,4 @@ -/music_track/df_theme +/decl/music_track/df_theme artist = "Beyond Quality" title = "Dwarf Fortress Main Theme" song = 'sound/ambience/song_game.ogg' diff --git a/code/datums/music_tracks/dilbert.dm b/code/datums/music_tracks/dilbert.dm index 9b63f6c8a21c..aed1d4c12cc4 100644 --- a/code/datums/music_tracks/dilbert.dm +++ b/code/datums/music_tracks/dilbert.dm @@ -1,4 +1,4 @@ -/music_track/dilbert +/decl/music_track/dilbert title = "Robocop.mp3" album = "Dehumanize Yourself and Face to Bloodshed" artist = "CBoyardee" diff --git a/code/datums/music_tracks/elevator.dm b/code/datums/music_tracks/elevator.dm index 4adfd46a0742..7831b2e98eba 100644 --- a/code/datums/music_tracks/elevator.dm +++ b/code/datums/music_tracks/elevator.dm @@ -1,4 +1,4 @@ -/music_track/elevator +/decl/music_track/elevator artist = "Kevin MacLeod" title = "Local Forecast (Elevator)" song = 'sound/music/elevatormusic.ogg' diff --git a/code/datums/music_tracks/elibao.dm b/code/datums/music_tracks/elibao.dm index 9a654613f2c0..72be0da45627 100644 --- a/code/datums/music_tracks/elibao.dm +++ b/code/datums/music_tracks/elibao.dm @@ -1,16 +1,16 @@ -/music_track/elibao - artist = "Earthcrusher" +/decl/music_track/elibao + artist = "Sunbeamstress" title = "every light is blinking at once" song = 'sound/music/elibao.ogg' license = /decl/license/cc_by_nc_sa_3_0 - url = "https://soundcloud.com/alexanderdivine/every-light-is-blinking-at-once" + url = "https://soundcloud.com/sunbeamstress/every-light-is-blinking-at-once" /* 'every light is blinking at once' -An original jam, (c)2018 Earthcrusher, aka Alexander Divine. +An original jam, (c)2018 Sunbeamstress, aka Lauren Loveless. Licensed for use under Creative Commons License: CC BY-SA 3.0 Use it however you like. Stay beautiful. -Link to online version at: https://soundcloud.com/alexanderdivine/every-light-is-blinking-at-once +Link to online version at: https://soundcloud.com/sunbeamstress/every-light-is-blinking-at-once */ diff --git a/code/datums/music_tracks/endless_space.dm b/code/datums/music_tracks/endless_space.dm index c6eda477c2bd..755e616c65ab 100644 --- a/code/datums/music_tracks/endless_space.dm +++ b/code/datums/music_tracks/endless_space.dm @@ -1,5 +1,6 @@ -/music_track/endless_space +/decl/music_track/endless_space artist = "SolusLunes" title = "Endless Space" song = 'sound/music/space.ogg' - license = /decl/license/grandfathered + license = /decl/license/cc_by_3_0 + url = "https://www.newgrounds.com/audio/listen/67583" diff --git a/code/datums/music_tracks/epicintro2015.dm b/code/datums/music_tracks/epicintro2015.dm index 00514c7168b3..9c831875ac3a 100644 --- a/code/datums/music_tracks/epicintro2015.dm +++ b/code/datums/music_tracks/epicintro2015.dm @@ -1,4 +1,4 @@ -/music_track/epicintro2015 +/decl/music_track/epicintro2015 artist = "Sascha Ende" title = "Epic Intro 2015" song = 'sound/music/epic2015.ogg' diff --git a/code/datums/music_tracks/epicintro2017.dm b/code/datums/music_tracks/epicintro2017.dm index b71748719e4d..3d1500f607c1 100644 --- a/code/datums/music_tracks/epicintro2017.dm +++ b/code/datums/music_tracks/epicintro2017.dm @@ -1,4 +1,4 @@ -/music_track/epicintro2017 +/decl/music_track/epicintro2017 artist = "Sascha Ende" title = "Epic Intro 2017" song = 'sound/music/epic2017.ogg' diff --git a/code/datums/music_tracks/europa.dm b/code/datums/music_tracks/europa.dm index 072702f4c8ee..b1b050118ba0 100644 --- a/code/datums/music_tracks/europa.dm +++ b/code/datums/music_tracks/europa.dm @@ -1,53 +1,53 @@ -/music_track/inorbit +/decl/music_track/inorbit artist = "Chronox" title = "In Orbit" song = 'sound/music/europa/Chronox_-_03_-_In_Orbit.ogg' license = /decl/license/cc_by_4_0 url = "freemusicarchive.org/music/Chronox_2/Voyager/Chronox_-_02_-_In_Orbit" -/music_track/martiancowboy +/decl/music_track/martiancowboy artist = "Kevin MacLeod" title = "Martian Cowboy" - song = 'sound/music/europa/Martian Cowboy.ogg' + song = 'sound/music/europa/MartianCowboy.ogg' license = /decl/license/cc_by_3_0 url = "https://incompetech.com/music/royalty-free/index.html?isrc=usuan1100349" -/music_track/monument +/decl/music_track/monument artist = "Six Umbrellas" title = "Monument" song = 'sound/music/europa/Six_Umbrellas_-_05_-_Monument.ogg' license = /decl/license/cc_by_sa_4_0 url = "https://sixumbrellas.bandcamp.com/album/the-psychedelic-and" -/music_track/asfarasitgets +/decl/music_track/asfarasitgets artist = "A Drop A Day" title = "As Far As It Gets" song = 'sound/music/europa/asfarasitgets.ogg' license = /decl/license/cc_by_sa_4_0 url = "https://ghyti.bandcamp.com/" -/music_track/eighties +/decl/music_track/eighties artist = "A Drop A Day" title = "80s All Over Again" song = 'sound/music/europa/80salloveragain.ogg' license = /decl/license/cc_by_sa_4_0 url = "https://ghyti.bandcamp.com/" -/music_track/wildencounters +/decl/music_track/wildencounters artist = "A Drop A Day" title = "Wild Encounters" song = 'sound/music/europa/WildEncounters.ogg' license = /decl/license/cc_by_sa_4_0 url = "https://ghyti.bandcamp.com/" -/music_track/torn +/decl/music_track/torn artist = "Macamoto" title = "Torn" song = 'sound/music/europa/Macamoto_-_05_-_Torn.ogg' license = /decl/license/cc_by_nc_sa_3_0 url = "https://macamoto.bandcamp.com/track/torn" -/music_track/nebula +/decl/music_track/nebula artist = "Pulse Emitter" title = "Nebula" song = 'sound/music/europa/Pulse_Emitter_-_04_-_Nebula.ogg' diff --git a/code/datums/music_tracks/fantasy.dm b/code/datums/music_tracks/fantasy.dm new file mode 100644 index 000000000000..521a9e5aa5d0 --- /dev/null +++ b/code/datums/music_tracks/fantasy.dm @@ -0,0 +1,34 @@ +/decl/music_track/teller + artist = "Kevin Macleod" + title = "Teller of the Tales" + song = 'sound/music/Teller-of-the-Tales.ogg' + license = /decl/license/cc_by_3_0 + url = "https://incompetech.com/music/royalty-free/index.html?isrc=USUAN1400020" + +/decl/music_track/dhaka + artist = "Kevin Macleod" + title = "Dhaka" + song = 'sound/music/Dhaka.ogg' + license = /decl/license/cc_by_3_0 + url = "https://incompetech.com/music/royalty-free/index.html?isrc=USUAN1400003" + +/decl/music_track/suonatore + artist = "Kevin Macleod" + title = "Suonatore di Liuto" + song = 'sound/music/Suonatore-di-Liuto.ogg' + license = /decl/license/cc_by_3_0 + url = "https://incompetech.com/music/royalty-free/index.html?isrc=USUAN1400023" + +/decl/music_track/magic_dance + artist = "Kevin Macleod" + title = "Miri's Magic Dance" + song = 'sound/music/Miris-Magic-Dance.ogg' + license = /decl/license/cc_by_3_0 + url = "https://incompetech.com/music/royalty-free/index.html?isrc=USUAN1100157" + +/decl/music_track/adventure + artist = "Alexander Nakarada" + title = "Adventure" + song = 'sound/music/winter/alexander-nakarada-adventure.ogg' + license = /decl/license/cc_by_4_0 + url = "https://creatorchords.com/music/adventure/" \ No newline at end of file diff --git a/code/datums/music_tracks/floating.dm b/code/datums/music_tracks/floating.dm index d12efb923be7..4ba37f244d3b 100644 --- a/code/datums/music_tracks/floating.dm +++ b/code/datums/music_tracks/floating.dm @@ -1,4 +1,4 @@ -/music_track/floating +/decl/music_track/floating artist = "Unknown" title = "Unknown" song = 'sound/music/main.ogg' diff --git a/code/datums/music_tracks/human.dm b/code/datums/music_tracks/human.dm index b1695e1ff364..194b8a79fd54 100644 --- a/code/datums/music_tracks/human.dm +++ b/code/datums/music_tracks/human.dm @@ -1,4 +1,4 @@ -/music_track/human +/decl/music_track/human artist = "Borrtex" title = "Human" album = "Creation" diff --git a/code/datums/music_tracks/lasers.dm b/code/datums/music_tracks/lasers.dm index be684a6a2b17..940196b96957 100644 --- a/code/datums/music_tracks/lasers.dm +++ b/code/datums/music_tracks/lasers.dm @@ -1,16 +1,16 @@ -/music_track/lasers - artist = "Earthcrusher" +/decl/music_track/lasers + artist = "Sunbeamstress" title = "lasers rip apart the bulkhead" song = 'sound/music/lasers_rip_apart_the_bulkhead.ogg' license = /decl/license/cc_by_nc_sa_3_0 - url = "https://soundcloud.com/alexanderdivine/lasers-rip-apart-the-bulkhead" + url = "https://soundcloud.com/sunbeamstress/lasers-rip-apart-the-bulkhead" /* 'lasers rip apart the bulkhead' -An original jam, (c)2018 Earthcrusher, aka Alexander Divine. +An original jam, (c)2018 Sunbeamstress, aka Lauren Loveless. Licensed for use under Creative Commons License: CC BY-SA 3.0 Use it however you like. Stay beautiful. -Link to online version at: https://soundcloud.com/alexanderdivine/lasers-rip-apart-the-bulkhead +Link to online version at: https://soundcloud.com/sunbeamstress/lasers-rip-apart-the-bulkhead */ diff --git a/code/datums/music_tracks/lysendraa.dm b/code/datums/music_tracks/lysendraa.dm index b8a4bcccd907..c14cb678b3e3 100644 --- a/code/datums/music_tracks/lysendraa.dm +++ b/code/datums/music_tracks/lysendraa.dm @@ -1,4 +1,4 @@ -/music_track/lysendraa +/decl/music_track/lysendraa artist = "TALES" title = "Memories Of Lysendraa" album = "The Seskian Wars" diff --git a/code/datums/music_tracks/marhaba.dm b/code/datums/music_tracks/marhaba.dm index a653ef628af9..95faa82e945b 100644 --- a/code/datums/music_tracks/marhaba.dm +++ b/code/datums/music_tracks/marhaba.dm @@ -1,4 +1,4 @@ -/music_track/marhaba +/decl/music_track/marhaba artist = "Ian Alex Mac" title = "Marhaba" album = "Cues" diff --git a/code/datums/music_tracks/one_loop.dm b/code/datums/music_tracks/one_loop.dm index 579f08811b5f..c64136deff9b 100644 --- a/code/datums/music_tracks/one_loop.dm +++ b/code/datums/music_tracks/one_loop.dm @@ -1,4 +1,4 @@ -/music_track/one_loop +/decl/music_track/one_loop artist = "Swedish House Mafia" title = "One (abridged loop)" song = 'sound/misc/TestLoop1.ogg' diff --git a/code/datums/music_tracks/pwmur.dm b/code/datums/music_tracks/pwmur.dm index 6f6c4091974b..bf917c86455e 100644 --- a/code/datums/music_tracks/pwmur.dm +++ b/code/datums/music_tracks/pwmur.dm @@ -1,16 +1,16 @@ -/music_track/pwmur - artist = "Earthcrusher" +/decl/music_track/pwmur + artist = "Sunbeamstress" title = "phoron will make us rich" song = 'sound/music/pwmur.ogg' license = /decl/license/cc_by_nc_sa_3_0 - url = "https://soundcloud.com/alexanderdivine/phoron-will-make-us-rich" + url = "https://soundcloud.com/sunbeamstress/phoron-will-make-us-rich" /* 'phoron will make us rich' -An original jam, (c)2018 Earthcrusher, aka Alexander Divine. +An original jam, (c)2018 Sunbeamstress, aka Lauren Loveless. Licensed for use under Creative Commons License: CC BY-SA 3.0 Use it however you like. Stay beautiful. -Link to online version at: https://soundcloud.com/alexanderdivine/phoron-will-make-us-rich +Link to online version at: https://soundcloud.com/sunbeamstress/phoron-will-make-us-rich */ diff --git a/code/datums/music_tracks/salutjohn.dm b/code/datums/music_tracks/salutjohn.dm index 78941479d95a..92abbd34ae20 100644 --- a/code/datums/music_tracks/salutjohn.dm +++ b/code/datums/music_tracks/salutjohn.dm @@ -1,4 +1,4 @@ -/music_track/salutjohn +/decl/music_track/salutjohn artist = "Quimorucru" title = "Salut John" song = 'sound/music/salutjohn.ogg' diff --git a/code/datums/music_tracks/space_oddity.dm b/code/datums/music_tracks/space_oddity.dm index f4a8a51c5d74..22fd40098be5 100644 --- a/code/datums/music_tracks/space_oddity.dm +++ b/code/datums/music_tracks/space_oddity.dm @@ -1,4 +1,4 @@ -/music_track/space_oddity +/decl/music_track/space_oddity artist = "Chris Hadfield" title = "Space Oddity" song = 'sound/music/space_oddity.ogg' diff --git a/code/datums/music_tracks/thunderdome.dm b/code/datums/music_tracks/thunderdome.dm index 85ed8aeacb32..fa5177e47c40 100644 --- a/code/datums/music_tracks/thunderdome.dm +++ b/code/datums/music_tracks/thunderdome.dm @@ -1,6 +1,6 @@ -/music_track/thunderdome +/decl/music_track/thunderdome artist = "MashedByMachines" - title = "THUNDERDOME (a.k.a. -Sektor11)" + title = "THUNDERDOME (a.k.a. -Sector11)" song = 'sound/music/THUNDERDOME.ogg' license = /decl/license/cc_by_nc_sa_3_0 url = "https://www.newgrounds.com/audio/listen/312622" diff --git a/code/datums/music_tracks/title1.dm b/code/datums/music_tracks/title1.dm index ae7d6c7f5a20..231762c1c349 100644 --- a/code/datums/music_tracks/title1.dm +++ b/code/datums/music_tracks/title1.dm @@ -1,4 +1,4 @@ -/music_track/level3_mod +/decl/music_track/level3_mod artist = "X-CEED" title = "Flip-Flap" song = 'sound/music/title1.ogg' diff --git a/code/datums/music_tracks/treacherous_voyage.dm b/code/datums/music_tracks/treacherous_voyage.dm index ad3cdb0249e0..bd9fbef2d707 100644 --- a/code/datums/music_tracks/treacherous_voyage.dm +++ b/code/datums/music_tracks/treacherous_voyage.dm @@ -1,4 +1,4 @@ -/music_track/treacherous_voyage +/decl/music_track/treacherous_voyage artist = "Jon Luc Hefferman" title = "Treacherous Voyage" album = "Eilean Mor" diff --git a/code/datums/music_tracks/wake.dm b/code/datums/music_tracks/wake.dm index 3e80cb1b6256..eca78f1af3ad 100644 --- a/code/datums/music_tracks/wake.dm +++ b/code/datums/music_tracks/wake.dm @@ -1,4 +1,4 @@ -/music_track/wake +/decl/music_track/wake artist = "Ryan Little" title = "Wake" song = 'sound/music/wake.ogg' diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm new file mode 100644 index 000000000000..679ddb6d43eb --- /dev/null +++ b/code/datums/mutable_appearance.dm @@ -0,0 +1,16 @@ +// Mutable appearances are an inbuilt byond datastructure. Read the documentation on them by hitting F1 in DM. +// Basically use them instead of images for overlays/underlays and when changing an object's appearance if you're doing so with any regularity. +// Unless you need the overlay/underlay to have a different direction than the base object. Then you have to use an image due to a bug. + +// Mutable appearances are children of images, just so you know. + +// Helper similar to image() +/proc/mutable_appearance(icon, icon_state, color, flags = RESET_COLOR | RESET_ALPHA, plane = FLOAT_PLANE, layer = FLOAT_LAYER) + var/mutable_appearance/MA = new() + MA.icon = icon + MA.icon_state = icon_state + MA.color = color + MA.appearance_flags = flags + MA.plane = plane + MA.layer = layer + return MA diff --git a/code/datums/observation/_defines.dm b/code/datums/observation/_defines.dm index 902d65587097..9d933ab04d7e 100644 --- a/code/datums/observation/_defines.dm +++ b/code/datums/observation/_defines.dm @@ -1 +1 @@ -#define CANCEL_MOVE_EVENT -55 +#define OBSERVATION_NO_GLOBAL_REGISTRATIONS BITFLAG(0) // Deny registering globally to this event - Intented for performance reasons diff --git a/code/datums/observation/area_power_change.dm b/code/datums/observation/area_power_change.dm new file mode 100644 index 000000000000..5e325a9f0cd6 --- /dev/null +++ b/code/datums/observation/area_power_change.dm @@ -0,0 +1,11 @@ +// Observer Pattern Implementation: Destroyed +// Registration type: /area +// +// Raised when: An /area's power state changes. +// +// Arguments that the called proc should expect: +// /area/power_changed: The instance that had a power change. + +/decl/observ/area_power_change + name = "Area Power Change" + expected_type = /area diff --git a/code/datums/observation/crate_sold.dm b/code/datums/observation/crate_sold.dm new file mode 100644 index 000000000000..fb6b77ca1a31 --- /dev/null +++ b/code/datums/observation/crate_sold.dm @@ -0,0 +1,11 @@ +// Observer Pattern Implementation: Crate Sold +// Registration type: /area +// +// Raised when: A crate is sold on the shuttle. +// +// Arguments that the called proc should expect: +// /area/shuttle: The shuttle the crate was sold on. +// /obj/structure/closet/crate/sold: The crate that was sold. + +/decl/observ/crate_sold + name = "Crate Sold" diff --git a/code/datums/observation/cyborg_created.dm b/code/datums/observation/cyborg_created.dm new file mode 100644 index 000000000000..2e3a1cb9e487 --- /dev/null +++ b/code/datums/observation/cyborg_created.dm @@ -0,0 +1,10 @@ +/** + * Observer Pattern Implementation: Cyborg Created + * + * Raised when: A cyborg is created. + * + * Arguments that the called proc should expect: + * /mob/living/silicon/robot: The cyborg that was created. + */ +/decl/observ/cyborg_created + name = "Cyborg Created" diff --git a/code/datums/observation/death.dm b/code/datums/observation/death.dm index d424a5ab75c7..3d4898de0732 100644 --- a/code/datums/observation/death.dm +++ b/code/datums/observation/death.dm @@ -6,8 +6,6 @@ // Arguments that the called proc should expect: // /mob/dead: The mob that was added to the dead_mob_list -GLOBAL_DATUM_INIT(death_event, /decl/observ/death, new) - /decl/observ/death name = "Death" expected_type = /mob @@ -19,4 +17,4 @@ GLOBAL_DATUM_INIT(death_event, /decl/observ/death, new) /mob/living/add_to_dead_mob_list() . = ..() if(.) - GLOB.death_event.raise_event(src) + RAISE_EVENT(/decl/observ/death, src) diff --git a/code/datums/observation/debrain.dm b/code/datums/observation/debrain.dm new file mode 100644 index 000000000000..2880d90c599a --- /dev/null +++ b/code/datums/observation/debrain.dm @@ -0,0 +1,13 @@ +/** + * Observer Pattern Implementation: Debrained + * + * Raised when: A brainmob is created by the removal of a brain. + * + * Arguments that the called proc should expect: + * /mob/living/brainmob: The brainmob that was created. + * /obj/item/organ/internal/brain: The brain that was removed. + * /mob/living/owner: The mob the brain was formerly installed in. + */ +/decl/observ/debrain + name = "Debrained" + expected_type = /mob/living \ No newline at end of file diff --git a/code/datums/observation/density_set.dm b/code/datums/observation/density_set.dm index fac35463ba19..0eaeb65e56e3 100644 --- a/code/datums/observation/density_set.dm +++ b/code/datums/observation/density_set.dm @@ -8,23 +8,7 @@ // /old_density: The density before the change. // /new_density: The density after the change. -GLOBAL_DATUM_INIT(density_set_event, /decl/observ/density_set, new) - /decl/observ/density_set name = "Density Set" expected_type = /atom - -/******************* -* Density Handling * -*******************/ -/atom/set_density(new_density) - var/old_density = density - UNLINT(. = ..()) - if(density != old_density) - GLOB.density_set_event.raise_event(src, old_density, density) - -/turf/ChangeTurf() - var/old_density = opacity - UNLINT(. = ..()) - if(density != old_density) - GLOB.density_set_event.raise_event(src, old_density, density) + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS diff --git a/code/datums/observation/destroyed.dm b/code/datums/observation/destroyed.dm index 2322acc08883..e3cd1c44905b 100644 --- a/code/datums/observation/destroyed.dm +++ b/code/datums/observation/destroyed.dm @@ -6,7 +6,6 @@ // Arguments that the called proc should expect: // /datum/destroyed_instance: The instance that was destroyed. -GLOBAL_DATUM_INIT(destroyed_event, /decl/observ/destroyed, new) - /decl/observ/destroyed name = "Destroyed" + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS diff --git a/code/datums/observation/dir_set.dm b/code/datums/observation/dir_set.dm index 6edf0b2cbbe0..edec53d036d6 100644 --- a/code/datums/observation/dir_set.dm +++ b/code/datums/observation/dir_set.dm @@ -8,34 +8,28 @@ // /old_dir: The dir before the change. // /new_dir: The dir after the change. -GLOBAL_DATUM_INIT(dir_set_event, /decl/observ/dir_set, new) - /decl/observ/dir_set name = "Direction Set" expected_type = /atom + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS /decl/observ/dir_set/register(var/atom/dir_changer, var/datum/listener, var/proc_call) . = ..() // Listen to the parent if possible. if(. && istype(dir_changer.loc, /atom/movable)) // We don't care about registering to turfs. - register(dir_changer.loc, dir_changer, /atom/proc/recursive_dir_set) + register(dir_changer.loc, dir_changer, TYPE_PROC_REF(/atom, recursive_dir_set)) /********************* * Direction Handling * *********************/ -/atom/set_dir() - var/old_dir = dir - . = ..() - if(old_dir != dir) - GLOB.dir_set_event.raise_event(src, old_dir, dir) - /atom/movable/Entered(var/atom/movable/am, atom/old_loc) . = ..() - if(GLOB.dir_set_event.has_listeners(am)) - GLOB.dir_set_event.register(src, am, /atom/proc/recursive_dir_set) + var/decl/observ/dir_set/dir_set_event = GET_DECL(/decl/observ/dir_set) + if(dir_set_event.has_listeners(am)) + events_repository.register(/decl/observ/dir_set, src, am, TYPE_PROC_REF(/atom, recursive_dir_set)) /atom/movable/Exited(var/atom/movable/am, atom/new_loc) . = ..() - GLOB.dir_set_event.unregister(src, am, /atom/proc/recursive_dir_set) + events_repository.unregister(/decl/observ/dir_set, src, am, TYPE_PROC_REF(/atom, recursive_dir_set)) diff --git a/code/datums/observation/dismembered.dm b/code/datums/observation/dismembered.dm index 20ae56cf99d8..0b50db142d94 100644 --- a/code/datums/observation/dismembered.dm +++ b/code/datums/observation/dismembered.dm @@ -9,8 +9,6 @@ // // This is called immediately, before the organ is actually moved or deleted. -GLOBAL_DATUM_INIT(dismembered_event, /decl/observ/dismembered, new) - /decl/observ/dismembered name = "Dismembered" expected_type = /mob/living diff --git a/code/datums/observation/employee_id.dm b/code/datums/observation/employee_id.dm new file mode 100644 index 000000000000..30fa7668acdd --- /dev/null +++ b/code/datums/observation/employee_id.dm @@ -0,0 +1,22 @@ +/** + * Observer Pattern Implementation: Employee ID Reassigned + * + * Raised when: A card's assignment is changed in the ID card modification program. + * + * Arguments that the called proc should expect: + * /obj/item/card/id: The card that was reassigned. + */ +/decl/observ/employee_id_reassigned + name = "Employee ID Reassigned" + +// Observer Pattern Implementation: Employee ID Terminated +// Registration type: /obj/item/card/id +// +// Raised when: A card is terminated in the ID card modification program. +// +// Arguments that the called proc should expect: +// /area/shuttle: The shuttle the crate was sold on. +// /obj/structure/closet/crate/sold: The crate that was sold. + +/decl/observ/employee_id_terminated + name = "Employee ID Terminated" diff --git a/code/datums/observation/entered.dm b/code/datums/observation/entered.dm index 4d517a7e089e..3512ed616173 100644 --- a/code/datums/observation/entered.dm +++ b/code/datums/observation/entered.dm @@ -9,11 +9,10 @@ // /atom/old_loc: The atom the enterer came from // -GLOBAL_DATUM_INIT(entered_event, /decl/observ/entered, new) - /decl/observ/entered name = "Entered" expected_type = /atom + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS /******************* * Entered Handling * @@ -21,4 +20,5 @@ GLOBAL_DATUM_INIT(entered_event, /decl/observ/entered, new) /atom/Entered(atom/movable/enterer, atom/old_loc) ..() - GLOB.entered_event.raise_event(src, enterer, old_loc) + if(event_listeners?[/decl/observ/entered]) + raise_event_non_global(/decl/observ/entered, enterer, old_loc) diff --git a/code/datums/observation/equipped.dm b/code/datums/observation/equipped.dm index 1efc00697ce0..680e9d4c9d7d 100644 --- a/code/datums/observation/equipped.dm +++ b/code/datums/observation/equipped.dm @@ -8,8 +8,6 @@ // /obj/item/item: The equipped item. // slot: The slot equipped to. -GLOBAL_DATUM_INIT(mob_equipped_event, /decl/observ/mob_equipped, new) - /decl/observ/mob_equipped name = "Mob Equipped" expected_type = /mob @@ -24,17 +22,6 @@ GLOBAL_DATUM_INIT(mob_equipped_event, /decl/observ/mob_equipped, new) // /mob/equipper: The mob that equipped the item. // slot: The slot equipped to. -GLOBAL_DATUM_INIT(item_equipped_event, /decl/observ/item_equipped, new) - /decl/observ/item_equipped name = "Item Equipped" expected_type = /obj/item - -/******************** -* Equipped Handling * -********************/ - -/obj/item/equipped(var/mob/user, var/slot) - UNLINT(. = ..()) - GLOB.mob_equipped_event.raise_event(user, src, slot) - GLOB.item_equipped_event.raise_event(src, user, slot) diff --git a/code/datums/observation/examine.dm b/code/datums/observation/examine.dm new file mode 100644 index 000000000000..6805b4a99aee --- /dev/null +++ b/code/datums/observation/examine.dm @@ -0,0 +1,25 @@ +// Observer Pattern Implementation: Atom Examined +// Registration type: /atom +// +// Raised when: A mob examines an atom. +// +// Arguments that the called proc should expect: +// /mob/examiner: The mob that examined the atom. +// /atom/examined: The examined atom. + +/decl/observ/atom_examined + name = "Atom Examined" + expected_type = /atom + +// Observer Pattern Implementation: Mob Examining +// Registration type: /mob +// +// Raised when: A mob examines an atom. +// +// Arguments that the called proc should expect: +// /atom/examined: The examined atom. +// /mob/examiner: The mob that examined the atom. + +/decl/observ/mob_examining + name = "Mob Examining" + expected_type = /mob \ No newline at end of file diff --git a/code/datums/observation/exited.dm b/code/datums/observation/exited.dm index 87d280a841d5..6e8bc2ac80fc 100644 --- a/code/datums/observation/exited.dm +++ b/code/datums/observation/exited.dm @@ -9,11 +9,10 @@ // /atom/new_loc: The atom the exitee is now residing in // -GLOBAL_DATUM_INIT(exited_event, /decl/observ/exited, new) - /decl/observ/exited name = "Exited" expected_type = /atom + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS /****************** * Exited Handling * @@ -21,4 +20,5 @@ GLOBAL_DATUM_INIT(exited_event, /decl/observ/exited, new) /atom/Exited(atom/movable/exitee, atom/new_loc) . = ..() - GLOB.exited_event.raise_event(src, exitee, new_loc) + if(event_listeners?[/decl/observ/exited]) + raise_event_non_global(/decl/observ/exited, exitee, new_loc) diff --git a/code/datums/observation/helpers.dm b/code/datums/observation/helpers.dm index bcd08cab99d7..b404f2372635 100644 --- a/code/datums/observation/helpers.dm +++ b/code/datums/observation/helpers.dm @@ -1,5 +1,6 @@ /atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc) - GLOB.moved_event.raise_event(src, old_loc, new_loc) + if(event_listeners?[/decl/observ/moved]) + raise_event_non_global(/decl/observ/moved, old_loc, new_loc) /atom/movable/proc/move_to_turf(var/atom/movable/am, var/old_loc, var/new_loc) var/turf/T = get_turf(new_loc) @@ -24,9 +25,9 @@ qdel(src) /proc/register_all_movement(var/event_source, var/listener) - GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) - GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set) + events_repository.register(/decl/observ/moved, event_source, listener, TYPE_PROC_REF(/atom/movable, recursive_move)) + events_repository.register(/decl/observ/dir_set, event_source, listener, TYPE_PROC_REF(/atom, recursive_dir_set)) /proc/unregister_all_movement(var/event_source, var/listener) - GLOB.moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move) - GLOB.dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set) + events_repository.unregister(/decl/observ/moved, event_source, listener, TYPE_PROC_REF(/atom/movable, recursive_move)) + events_repository.unregister(/decl/observ/dir_set, event_source, listener, TYPE_PROC_REF(/atom, recursive_dir_set)) diff --git a/code/datums/observation/ingested.dm b/code/datums/observation/ingested.dm new file mode 100644 index 000000000000..e8cb3ea8e74c --- /dev/null +++ b/code/datums/observation/ingested.dm @@ -0,0 +1,16 @@ +// Observer Pattern Implementation: Ingested +// Registration type: /mob/living +// +// Raised when: A living mob ingests reagents. +// +// Arguments that the called proc should expect: +// /mob/living/ingester: The mob that has ingested something +// /datum/reagents/source: The reagent holder being ingested from. +// /datum/reagents/target: The reagent holder the ingested reagents move into. +// amount: The number of reagents ingested from the reagent source. +// multiplier: The multiplier determining the ratio of reagents removed from the source to reagents added to the target. +// copy: If true, reagents are copied from the source rather than transferred. + +/decl/observ/ingested + name = "Ingested" + expected_type = /mob/living \ No newline at end of file diff --git a/code/datums/observation/life.dm b/code/datums/observation/life.dm index 45760c92d347..50a2796a85d9 100644 --- a/code/datums/observation/life.dm +++ b/code/datums/observation/life.dm @@ -6,8 +6,6 @@ // Arguments that the called proc should expect: // /mob/dead: The mob that was added to the life_mob_list -GLOBAL_DATUM_INIT(life_event, /decl/observ/life, new) - /decl/observ/life name = "Life" expected_type = /mob @@ -19,4 +17,4 @@ GLOBAL_DATUM_INIT(life_event, /decl/observ/life, new) /mob/add_to_living_mob_list() . = ..() if(.) - GLOB.life_event.raise_event(src) + RAISE_EVENT(/decl/observ/life, src) diff --git a/code/datums/observation/logged_in.dm b/code/datums/observation/logged_in.dm index c59e146a485a..4c7c1f7a2551 100644 --- a/code/datums/observation/logged_in.dm +++ b/code/datums/observation/logged_in.dm @@ -6,16 +6,6 @@ // Arguments that the called proc should expect: // /mob/joiner: The mob that has logged in -GLOBAL_DATUM_INIT(logged_in_event, /decl/observ/logged_in, new) - /decl/observ/logged_in name = "Logged In" expected_type = /mob - -/***************** -* Login Handling * -*****************/ - -/mob/Login() - ..() - GLOB.logged_in_event.raise_event(src) diff --git a/code/datums/observation/logged_out.dm b/code/datums/observation/logged_out.dm index 6a5ab8fa9e27..8ba2ac2c560e 100644 --- a/code/datums/observation/logged_out.dm +++ b/code/datums/observation/logged_out.dm @@ -7,16 +7,6 @@ // /mob/leaver: The mob that has logged out // /client/client: The mob's client -GLOBAL_DATUM_INIT(logged_out_event, /decl/observ/logged_out, new) - /decl/observ/logged_out name = "Logged Out" expected_type = /mob - -/****************** -* Logout Handling * -******************/ - -/mob/Logout() - GLOB.logged_out_event.raise_event(src, my_client) - ..() diff --git a/code/datums/observation/money_accounts.dm b/code/datums/observation/money_accounts.dm new file mode 100644 index 000000000000..23e4e2a0721c --- /dev/null +++ b/code/datums/observation/money_accounts.dm @@ -0,0 +1,22 @@ + +/** + * Observer Pattern Implementation: Payroll Revoked + * + * Raised when: Someone's payroll is stolen at the Accounts terminal. + * + * Arguments that the called proc should expect: + * /datum/money_account: The account whose payroll was revoked. + */ +/decl/observ/revoke_payroll + name = "Payroll Revoked" + +/** + * Observer Pattern Implementation: Account Status Changed + * + * Raised when: Someone's account is suspended or unsuspended at the Accounts terminal. + * + * Arguments that the called proc should expect: + * /datum/money_account: The account whose status was changed. + */ +/decl/observ/change_account_status + name = "Account Status Changed" diff --git a/code/datums/observation/moved.dm b/code/datums/observation/moved.dm index 7ffc0c294891..340779227b99 100644 --- a/code/datums/observation/moved.dm +++ b/code/datums/observation/moved.dm @@ -8,18 +8,24 @@ // /atom/old_loc: The loc before the move. // /atom/new_loc: The loc after the move. -GLOBAL_DATUM_INIT(moved_event, /decl/observ/moved, new) - /decl/observ/moved name = "Moved" expected_type = /atom/movable + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS /decl/observ/moved/register(var/atom/movable/mover, var/datum/listener, var/proc_call) . = ..() // Listen to the parent if possible. if(. && istype(mover.loc, expected_type)) - register(mover.loc, mover, /atom/movable/proc/recursive_move) + register(mover.loc, mover, TYPE_PROC_REF(/atom/movable, recursive_move)) + +/decl/observ/moved/unregister(var/atom/movable/mover, var/datum/listener, var/proc_call) + . = ..() + + // Unregister from the parent if possible. + if(. && istype(mover.loc, expected_type)) + unregister(mover.loc, mover, TYPE_PROC_REF(/atom/movable, recursive_move)) /******************** * Movement Handling * @@ -27,13 +33,15 @@ GLOBAL_DATUM_INIT(moved_event, /decl/observ/moved, new) /atom/Entered(var/atom/movable/am, var/atom/old_loc) . = ..() - GLOB.moved_event.raise_event(am, old_loc, am.loc) + if(am.event_listeners?[/decl/observ/moved]) + am.raise_event_non_global(/decl/observ/moved, old_loc, am.loc) /atom/movable/Entered(var/atom/movable/am, atom/old_loc) . = ..() - if(GLOB.moved_event.has_listeners(am)) - GLOB.moved_event.register(src, am, /atom/movable/proc/recursive_move) + // We inline and simplify has_listeners here since we know this event can never have global registrations. + if(am.event_listeners?[/decl/observ/moved]) + events_repository.register(/decl/observ/moved, src, am, TYPE_PROC_REF(/atom/movable, recursive_move)) /atom/movable/Exited(var/atom/movable/am, atom/new_loc) . = ..() - GLOB.moved_event.unregister(src, am, /atom/movable/proc/recursive_move) + events_repository.unregister(/decl/observ/moved, src, am, TYPE_PROC_REF(/atom/movable, recursive_move)) diff --git a/code/datums/observation/name_set.dm b/code/datums/observation/name_set.dm index ee8dd74dd69b..f0f75e0c684c 100644 --- a/code/datums/observation/name_set.dm +++ b/code/datums/observation/name_set.dm @@ -8,11 +8,10 @@ // /old_name: name before the change // /new_name: name after the change -GLOBAL_DATUM_INIT(name_set_event, /decl/observ/name_set, new) - /decl/observ/name_set name = "Name Set" expected_type = /atom + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS /********************* * Name Set Handling * @@ -25,4 +24,6 @@ GLOBAL_DATUM_INIT(name_set_event, /decl/observ/name_set, new) if(has_extension(src, /datum/extension/labels)) var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) name = L.AppendLabelsToName(name) - GLOB.name_set_event.raise_event(src, old_name, new_name) + if(event_listeners?[/decl/observ/name_set]) + raise_event_non_global(/decl/observ/name_set, old_name, new_name) + update_above() \ No newline at end of file diff --git a/code/datums/observation/observation.dm b/code/datums/observation/observation.dm index 95cec1672f9f..ee87ba09d524 100644 --- a/code/datums/observation/observation.dm +++ b/code/datums/observation/observation.dm @@ -57,30 +57,32 @@ // The first argument shall always be the event_source belonging to the event. Beyond that there are no restrictions. /decl/observ - var/name = "Unnamed Event" // The name of this event, used mainly for debug/VV purposes. The list of event managers can be reached through the "Debug Controller" verb, selecting the "Observation" entry. - var/expected_type = /datum // The expected event source for this event. register() will CRASH() if it receives an unexpected type. - var/list/event_sources = list() // Associative list of event sources, each with their own associative list. This associative list contains an instance/list of procs to call when the event is raised. - var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call. - -/decl/observ/New() - GLOB.all_observable_events += src - ..() - -/decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) + var/name = "Unnamed Event" // The name of this event, used mainly for debug/VV purposes. The list of event managers can be reached through the "Debug Controller" verb, selecting the "Observation" entry. + var/expected_type = /datum // The expected event source for this event. register() will CRASH() if it receives an unexpected type. + var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call. + VAR_PROTECTED/flags // See _defines.dm for available flags and what they do + +/datum + /// Associative list of observ type -> associative list of listeners -> an instance/list of procs to call on the listener when the event is raised. + var/list/list/list/event_listeners + /// Associative list of observ type -> datums we're listening to; contains no information about callbacks as that's already stored on their event_listeners list. + var/list/_listening_to + +/decl/observ/proc/is_listening(var/datum/event_source, var/datum/listener, var/proc_call) // Return whether there are global listeners unless the event source is given. if (!event_source) return !!global_listeners.len + var/list/listeners = event_source.event_listeners?[type] // Return whether anything is listening to a source, if no listener is given. if (!listener) - return global_listeners.len || event_sources[event_source] + return length(global_listeners) || !!listeners // Return false if nothing is associated with that source. - if (!event_sources[event_source]) + if (!listeners) return FALSE - // Get and check the listeners for the reuqested event. - var/listeners = event_sources[event_source] + // Get and check the listeners for the requested event. if (!listeners[listener]) return FALSE @@ -95,7 +97,7 @@ return (proc_call in callback) -/decl/observ/proc/has_listeners(var/event_source) +/decl/observ/proc/has_listeners(var/datum/event_source) return is_listening(event_source) /decl/observ/proc/register(var/datum/event_source, var/datum/listener, var/proc_call) @@ -110,16 +112,16 @@ CRASH("Unexpected type. Expected [expected_type], was [event_source.type]") // Setup the listeners for this source if needed. - var/list/listeners = event_sources[event_source] - if (!listeners) - listeners = list() - event_sources[event_source] = listeners - + LAZYINITLIST(event_source.event_listeners) + LAZYINITLIST(event_source.event_listeners[type]) + var/list/listeners = event_source.event_listeners[type] // Make sure the callbacks are a list. var/list/callbacks = listeners[listener] if (!callbacks) callbacks = list() listeners[listener] = callbacks + LAZYINITLIST(listener._listening_to) + LAZYADD(listener._listening_to[type], event_source) // If the proc_call is already registered skip if(proc_call in callbacks) @@ -129,45 +131,54 @@ callbacks += proc_call return TRUE -/decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call) +/decl/observ/proc/unregister(var/datum/event_source, var/datum/listener, var/proc_call) // Sanity. - if (!event_source || !listener || !event_sources[event_source]) - return FALSE - - // Return false if nothing is listening for this event. - var/list/listeners = event_sources[event_source] - if (!listeners) - return FALSE + if (!event_source || !listener || !event_source.event_listeners?[type]) + return 0 + var/list/list/listeners = event_source.event_listeners[type] // Remove all callbacks if no specific one is given. if (!proc_call) + // Return the number of callbacks removed. + . = length(listeners[listener]) if(listeners.Remove(listener)) + LAZYREMOVE(listener._listening_to?[type], event_source) + UNSETEMPTY(listener._listening_to) // Perform some cleanup and return true. - if (!listeners.len) - event_sources -= event_source - return TRUE - return FALSE + if (!length(listeners)) // No one is listening to us on this source anymore. + LAZYREMOVE(event_source.event_listeners, type) + UNSETEMPTY(event_source.event_listeners?[type]) + UNSETEMPTY(event_source.event_listeners) + return . + return 0 // See if the listener is registered. var/list/callbacks = listeners[listener] if (!callbacks) - return FALSE + return 0 // See if the callback exists. if(!callbacks.Remove(proc_call)) - return FALSE + return 0 - if (!callbacks.len) - listeners -= listener - if (!listeners.len) - event_sources -= event_source - return TRUE + if(!LAZYLEN(callbacks)) // the above Remove() took our last callback away, so remove our callbacks list for this listener + LAZYREMOVE(event_source.event_listeners[type], listener) // note that UNSETEMPTY would just give it a null value + LAZYREMOVE(listener._listening_to[type], event_source) + if(!LAZYLEN(listener._listening_to[type])) + LAZYREMOVE(listener._listening_to, type) + if(!LAZYLEN(event_source.event_listeners[type])) + LAZYREMOVE(event_source.event_listeners, type) + return 1 /decl/observ/proc/register_global(var/datum/listener, var/proc_call) // Sanity. if (!(listener && proc_call)) return FALSE + if(flags & OBSERVATION_NO_GLOBAL_REGISTRATIONS) + PRINT_STACK_TRACE("Attempt to register globally was denied") + return FALSE + // Make sure the callbacks are setup. var/list/callbacks = global_listeners[listener] if (!callbacks) @@ -179,34 +190,53 @@ return TRUE /decl/observ/proc/unregister_global(var/datum/listener, var/proc_call) - // Return false unless the listener is set as a global listener. + // None unregistered unless the listener is set as a global listener. if (!(listener && global_listeners[listener])) - return FALSE + return 0 // Remove all callbacks if no specific one is given. if (!proc_call) + . = length(global_listeners[listener]) global_listeners -= listener - return TRUE + return . // See if the listener is registered. var/list/callbacks = global_listeners[listener] if (!callbacks) - return FALSE + return 0 // See if the callback exists. if(!callbacks.Remove(proc_call)) - return FALSE + return 0 if (!callbacks.len) global_listeners -= listener + return 1 + +/// A variant of raise_event for extra-fast processing, for observs that are certain to never have any global registrations. +/datum/proc/raise_event_non_global(event_type) + // Call the listeners for this specific event source, if they exist. + var/list/listeners = event_listeners?[event_type] + if(length(listeners)) + args[1] = src // replace event_type with src for the call + for (var/listener in listeners) + var/list/callbacks = listeners[listener] + for (var/proc_call in callbacks) + // If the callback crashes, record the error and remove it. + try + call(listener, proc_call)(arglist(args)) + catch (var/exception/e) + error(EXCEPTION_TEXT(e)) + var/decl/observ/event = GET_DECL(event_type) + event.unregister(src, listener, proc_call) return TRUE -/decl/observ/proc/raise_event() +/decl/observ/proc/raise_event(datum/source) // Sanity - if (!args.len) + if(!source) return FALSE - if (global_listeners.len) + if(length(global_listeners)) // Call the global listeners. for (var/listener in global_listeners) var/list/callbacks = global_listeners[listener] @@ -216,24 +246,19 @@ try call(listener, proc_call)(arglist(args)) catch (var/exception/e) - error("[e.name] - [e.file] - [e.line]") - error(e.desc) + error(EXCEPTION_TEXT(e)) unregister_global(listener, proc_call) // Call the listeners for this specific event source, if they exist. - var/source = args[1] - if (source && event_sources[source]) - var/list/listeners = event_sources[source] + var/list/listeners = source.event_listeners?[type] + if(length(listeners)) for (var/listener in listeners) var/list/callbacks = listeners[listener] for (var/proc_call in callbacks) - // If the callback crashes, record the error and remove it. try call(listener, proc_call)(arglist(args)) catch (var/exception/e) - error("[e.name] - [e.file] - [e.line]") - error(e.desc) + error(EXCEPTION_TEXT(e)) unregister(source, listener, proc_call) - return TRUE diff --git a/code/datums/observation/opacity_set.dm b/code/datums/observation/opacity_set.dm index a0ef5229fb84..f2628567fb27 100644 --- a/code/datums/observation/opacity_set.dm +++ b/code/datums/observation/opacity_set.dm @@ -8,8 +8,6 @@ // /old_opacity: The opacity before the change. // /new_opacity: The opacity after the change. -GLOBAL_DATUM_INIT(opacity_set_event, /decl/observ/opacity_set, new) - /decl/observ/opacity_set name = "Opacity Set" expected_type = /atom @@ -21,7 +19,7 @@ GLOBAL_DATUM_INIT(opacity_set_event, /decl/observ/opacity_set, new) if(new_opacity != opacity) var/old_opacity = opacity opacity = new_opacity - GLOB.opacity_set_event.raise_event(src, old_opacity, new_opacity) + RAISE_EVENT(/decl/observ/opacity_set, src, old_opacity, new_opacity) return TRUE else return FALSE diff --git a/code/datums/observation/player_latejoin.dm b/code/datums/observation/player_latejoin.dm new file mode 100644 index 000000000000..938f113b19c4 --- /dev/null +++ b/code/datums/observation/player_latejoin.dm @@ -0,0 +1,11 @@ +// Observer Pattern Implementation: Player Latejoin +// Registration type: /mob/living +// +// Raised when: A player joins the round after it has started. +// +// Arguments that the called proc should expect: +// /mob/living/character: The mob that joined the round. +// /datum/job/job: The job the mob joined as. + +/decl/observ/player_latejoin + name = "Player Latejoin" diff --git a/code/datums/observation/see_in_dark_set.dm b/code/datums/observation/see_in_dark_set.dm index 15f06999ec24..d5e4731db51a 100644 --- a/code/datums/observation/see_in_dark_set.dm +++ b/code/datums/observation/see_in_dark_set.dm @@ -8,8 +8,6 @@ // /old_see_in_dark: see_in_dark before the change // /new_see_in_dark: see_in_dark after the change -GLOBAL_DATUM_INIT(see_in_dark_set_event, /decl/observ/see_in_dark_set, new) - /decl/observ/see_in_dark_set name = "See In Dark Set" expected_type = /mob @@ -21,5 +19,5 @@ GLOBAL_DATUM_INIT(see_in_dark_set_event, /decl/observ/see_in_dark_set, new) /mob/proc/set_see_in_dark(var/new_see_in_dark) var/old_see_in_dark = sight if(old_see_in_dark != new_see_in_dark) - see_in_dark = new_see_in_dark - GLOB.see_in_dark_set_event.raise_event(src, old_see_in_dark, new_see_in_dark) + see_in_dark = new_see_in_dark + RAISE_EVENT(/decl/observ/see_in_dark_set, src, old_see_in_dark, new_see_in_dark) diff --git a/code/datums/observation/see_invisible_set.dm b/code/datums/observation/see_invisible_set.dm index cdce96bc25fd..7b4218336da5 100644 --- a/code/datums/observation/see_invisible_set.dm +++ b/code/datums/observation/see_invisible_set.dm @@ -8,8 +8,6 @@ // /old_see_invisible: see_invisible before the change // /new_see_invisible: see_invisible after the change -GLOBAL_DATUM_INIT(see_invisible_set_event, /decl/observ/see_invisible_set, new) - /decl/observ/see_invisible_set name = "See Invisible Set" expected_type = /mob @@ -22,4 +20,4 @@ GLOBAL_DATUM_INIT(see_invisible_set_event, /decl/observ/see_invisible_set, new) var/old_see_invisible = see_invisible if(old_see_invisible != new_see_invisible) see_invisible = new_see_invisible - GLOB.see_invisible_set_event.raise_event(src, old_see_invisible, new_see_invisible) + RAISE_EVENT(/decl/observ/see_invisible_set, src, old_see_invisible, new_see_invisible) diff --git a/code/datums/observation/set_invisibility.dm b/code/datums/observation/set_invisibility.dm index 1d2c2fd1d3f6..ea021f440439 100644 --- a/code/datums/observation/set_invisibility.dm +++ b/code/datums/observation/set_invisibility.dm @@ -8,8 +8,6 @@ // /old_invisibility: invisibility before the change // /new_invisibility: invisibility after the change -GLOBAL_DATUM_INIT(invisibility_set_event, /decl/observ/invisibility_set, new) - /decl/observ/invisibility_set name = "Invisibility Set" expected_type = /atom @@ -22,5 +20,5 @@ GLOBAL_DATUM_INIT(invisibility_set_event, /decl/observ/invisibility_set, new) var/old_invisibility = invisibility if(old_invisibility != new_invisibility) invisibility = new_invisibility - GLOB.invisibility_set_event.raise_event(src, old_invisibility, new_invisibility) - + RAISE_EVENT(/decl/observ/invisibility_set, src, old_invisibility, new_invisibility) + update_above() diff --git a/code/datums/observation/shuttle_added.dm b/code/datums/observation/shuttle_added.dm index 0acf5a61c871..51b9fa34a251 100644 --- a/code/datums/observation/shuttle_added.dm +++ b/code/datums/observation/shuttle_added.dm @@ -6,8 +6,6 @@ // Arguments that the called proc should expect: // /datum/shuttle/shuttle: the new shuttle -GLOBAL_DATUM_INIT(shuttle_added, /decl/observ/shuttle_added, new) - /decl/observ/shuttle_added name = "Shuttle Added" expected_type = /datum/shuttle @@ -19,4 +17,4 @@ GLOBAL_DATUM_INIT(shuttle_added, /decl/observ/shuttle_added, new) /datum/controller/subsystem/shuttle/initialize_shuttle() . = ..() if(.) - GLOB.shuttle_added.raise_event(.) \ No newline at end of file + RAISE_EVENT(/decl/observ/shuttle_added, .) diff --git a/code/datums/observation/shuttle_moved.dm b/code/datums/observation/shuttle_moved.dm index 35bff0d6b923..816938c11d83 100644 --- a/code/datums/observation/shuttle_moved.dm +++ b/code/datums/observation/shuttle_moved.dm @@ -18,14 +18,10 @@ // /obj/effect/shuttle_landmark/old_location: the old location's shuttle landmark // /obj/effect/shuttle_landmark/new_location: the new location's shuttle landmark -GLOBAL_DATUM_INIT(shuttle_moved_event, /decl/observ/shuttle_moved, new) - /decl/observ/shuttle_moved name = "Shuttle Moved" expected_type = /datum/shuttle -GLOBAL_DATUM_INIT(shuttle_pre_move_event, /decl/observ/shuttle_pre_move, new) - /decl/observ/shuttle_pre_move name = "Shuttle Pre Move" expected_type = /datum/shuttle diff --git a/code/datums/observation/sight_set.dm b/code/datums/observation/sight_set.dm index 0810c84a8b31..6cd3abf34b41 100644 --- a/code/datums/observation/sight_set.dm +++ b/code/datums/observation/sight_set.dm @@ -8,8 +8,6 @@ // /old_sight: sight before the change // /new_sight: sight after the change -GLOBAL_DATUM_INIT(sight_set_event, /decl/observ/sight_set, new) - /decl/observ/sight_set name = "Sight Set" expected_type = /mob @@ -20,6 +18,10 @@ GLOBAL_DATUM_INIT(sight_set_event, /decl/observ/sight_set, new) /mob/proc/set_sight(var/new_sight) var/old_sight = sight + if(!(new_sight & (SEE_MOBS|SEE_OBJS|SEE_TURFS))) + new_sight |= SEE_BLACKNESS // Avoids pixel bleed from atoms overlapping completely dark turfs, but conflicts with other flags. + else + new_sight &= ~SEE_BLACKNESS if(old_sight != new_sight) sight = new_sight - GLOB.sight_set_event.raise_event(src, old_sight, new_sight) + RAISE_EVENT(/decl/observ/sight_set, src, old_sight, new_sight) diff --git a/code/datums/observation/stat_set.dm b/code/datums/observation/stat_set.dm index b980d06eccc5..12624797ea98 100644 --- a/code/datums/observation/stat_set.dm +++ b/code/datums/observation/stat_set.dm @@ -8,8 +8,6 @@ // /old_stat: Status before the change. // /new_stat: Status after the change. -GLOBAL_DATUM_INIT(stat_set_event, /decl/observ/stat_set, new) - /decl/observ/stat_set name = "Stat Set" expected_type = /mob/living @@ -21,4 +19,4 @@ GLOBAL_DATUM_INIT(stat_set_event, /decl/observ/stat_set, new) var/old_stat = stat . = ..() if(stat != old_stat) - GLOB.stat_set_event.raise_event(src, old_stat, new_stat) + RAISE_EVENT(/decl/observ/stat_set, src, old_stat, new_stat) diff --git a/code/datums/observation/submap_join.dm b/code/datums/observation/submap_join.dm new file mode 100644 index 000000000000..aa74148fe9aa --- /dev/null +++ b/code/datums/observation/submap_join.dm @@ -0,0 +1,13 @@ +// Observer Pattern Implementation: Submap Join +// Registration type: /datum/submap +// +// Raised when: A mob joins on a submap +// +// Arguments that the called proc should expect: +// /datum/submap/submap: The submap the mob joined. +// /mob/joiner: The mob that joined the submap. +// /datum/job/job: The job the mob joined as. + +/decl/observ/submap_join + name = "Submap Joined" + expected_type = /datum/submap \ No newline at end of file diff --git a/code/datums/observation/turf_changed.dm b/code/datums/observation/turf_changed.dm deleted file mode 100644 index b634b0cc45d4..000000000000 --- a/code/datums/observation/turf_changed.dm +++ /dev/null @@ -1,28 +0,0 @@ -// Observer Pattern Implementation: Turf Changed -// Registration type: /turf -// -// Raised when: A turf has been changed using the ChangeTurf proc. -// -// Arguments that the called proc should expect: -// /turf/affected: The turf that has changed -// /old_density: Density before the change -// /new_density: Density after the change -// /old_opacity: Opacity before the change -// /new_opacity: Opacity after the change - -GLOBAL_DATUM_INIT(turf_changed_event, /decl/observ/turf_changed, new) - -/decl/observ/turf_changed - name = "Turf Changed" - expected_type = /turf - -/************************ -* Turf Changed Handling * -************************/ - -/turf/ChangeTurf() - var/old_density = density - var/old_opacity = opacity - . = ..() - if(.) - GLOB.turf_changed_event.raise_event(src, old_density, density, old_opacity, opacity) diff --git a/code/datums/observation/unequipped.dm b/code/datums/observation/unequipped.dm index 6b42f584cae6..d66c304a37df 100644 --- a/code/datums/observation/unequipped.dm +++ b/code/datums/observation/unequipped.dm @@ -7,8 +7,6 @@ // /mob/equipped: The mob that unequipped/dropped the item. // /obj/item/item: The unequipped item. -GLOBAL_DATUM_INIT(mob_unequipped_event, /decl/observ/mob_unequipped, new) - /decl/observ/mob_unequipped name = "Mob Unequipped" expected_type = /mob @@ -22,17 +20,6 @@ GLOBAL_DATUM_INIT(mob_unequipped_event, /decl/observ/mob_unequipped, new) // /obj/item/item: The unequipped item. // /mob/equipped: The mob that unequipped/dropped the item. -GLOBAL_DATUM_INIT(item_unequipped_event, /decl/observ/item_unequipped, new) - /decl/observ/item_unequipped name = "Item Unequipped" expected_type = /obj/item - -/********************** -* Unequipped Handling * -**********************/ - -/obj/item/dropped(var/mob/user) - UNLINT(..()) - GLOB.mob_unequipped_event.raise_event(user, src) - GLOB.item_unequipped_event.raise_event(src, user) diff --git a/code/datums/observation/updated_icon.dm b/code/datums/observation/updated_icon.dm new file mode 100644 index 000000000000..021b8bca092e --- /dev/null +++ b/code/datums/observation/updated_icon.dm @@ -0,0 +1,14 @@ +// Observer Pattern Implementation: Updated Icon +// Registration type: /atom +// +// Raised when: An /atom updates its icon via the on_update_icon() proc. +// +// Arguments that the called proc should expect: +// /atom: The atom who updated icon. +// +// Refer to /atom update_icon() proc for event calling logic. + +/decl/observ/updated_icon + name = "Updated Icon" + expected_type = /atom + flags = OBSERVATION_NO_GLOBAL_REGISTRATIONS \ No newline at end of file diff --git a/code/datums/observation/zone_selected.dm b/code/datums/observation/zone_selected.dm index 482a778b5db8..8a4c7bc58756 100644 --- a/code/datums/observation/zone_selected.dm +++ b/code/datums/observation/zone_selected.dm @@ -1,25 +1,22 @@ // Observer Pattern Implementation: Zone Selected -// Registration type: /obj/screen/zone_sel +// Registration type: /obj/screen/zone_selector // -// Raised when: A /obj/screen/zone_sel had its selected zone modified. +// Raised when: A /obj/screen/zone_selector had its selected zone modified. // // Arguments that the called proc should expect: -// /obj/screen/zone_sel: the +// /obj/screen/zone_selector: the // old_zone: the previously selected zone // new_zone: the newly selected zone // -GLOBAL_DATUM_INIT(zone_selected_event, /decl/observ/zone_selected, new) - /decl/observ/zone_selected name = "Zone Selected" - expected_type = /obj/screen/zone_sel + expected_type = /obj/screen/zone_selector /******************* * Zone Selected Handling * *******************/ -/obj/screen/zone_sel/set_selected_zone(bodypart) - var/old_selecting = selecting +/obj/screen/zone_selector/set_selected_zone(new_zone, old_zone) if((. = ..())) - GLOB.zone_selected_event.raise_event(src, old_selecting, selecting) \ No newline at end of file + RAISE_EVENT(/decl/observ/zone_selected, src, old_zone, new_zone) \ No newline at end of file diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm index 8131ad6d7f29..39c9dc8152c2 100644 --- a/code/datums/observation/~cleanup.dm +++ b/code/datums/observation/~cleanup.dm @@ -1,71 +1,85 @@ -GLOBAL_LIST_EMPTY(global_listen_count) -GLOBAL_LIST_EMPTY(event_sources_count) -GLOBAL_LIST_EMPTY(event_listen_count) +/// This variable is used only for sanity checks during unit tests. It contains a list of all datums with global event registrations. +var/global/list/_all_global_event_listeners = list() +/datum + /// Tracks how many event registrations are listening to us. Used in cleanup to prevent dangling references. + var/event_source_count = 0 + /// Tracks how many event registrations we are listening to. Used in cleanup to prevent dangling references. + var/event_listen_count = 0 + /// Tracks how many global event registrations we are listening to. Used in cleanup to prevent dangling references. + var/global_listen_count = 0 -/proc/cleanup_events(var/source) - if(GLOB.global_listen_count && GLOB.global_listen_count[source]) - cleanup_global_listener(source, GLOB.global_listen_count[source]) - if(GLOB.event_sources_count && GLOB.event_sources_count[source]) - cleanup_source_listeners(source, GLOB.event_sources_count[source]) - if(GLOB.event_listen_count && GLOB.event_listen_count[source]) - cleanup_event_listener(source, GLOB.event_listen_count[source]) +/proc/cleanup_events(var/datum/source) + if(source?.global_listen_count > 0) + cleanup_global_listener(source) + if(source?.event_source_count > 0) + cleanup_source_listeners(source) + if(source?.event_listen_count > 0) + cleanup_event_listener(source) /decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call) . = ..() if(.) - GLOB.event_sources_count[event_source] += 1 - GLOB.event_listen_count[listener] += 1 + event_source.event_source_count++ + listener.event_listen_count++ /decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call) - . = ..() + . = ..() // returns the number of events removed if(.) - GLOB.event_sources_count[event_source] -= 1 - GLOB.event_listen_count[listener] -= 1 - - if(GLOB.event_sources_count[event_source] <= 0) - GLOB.event_sources_count -= event_source - if(GLOB.event_listen_count[listener] <= 0) - GLOB.event_listen_count -= listener + event_source.event_source_count -= . + listener.event_listen_count -= . /decl/observ/register_global(var/datum/listener, var/proc_call) . = ..() if(.) - GLOB.global_listen_count[listener] += 1 + listener.global_listen_count += 1 +// This variable is used only for sanity checks during unit tests. +#ifdef UNIT_TEST + global._all_global_event_listeners += listener +#endif /decl/observ/unregister_global(var/datum/listener, var/proc_call) . = ..() if(.) - GLOB.global_listen_count[listener] -= 1 - if(GLOB.global_listen_count[listener] <= 0) - GLOB.global_listen_count -= listener + listener.global_listen_count -= . +#ifdef UNIT_TEST + if(!listener.global_listen_count) + global._all_global_event_listeners -= listener +#endif -/proc/cleanup_global_listener(listener, listen_count) - GLOB.global_listen_count -= listener - for(var/entry in GLOB.all_observable_events) - var/decl/observ/event = entry +/proc/cleanup_global_listener(datum/listener) + for(var/decl/observ/event as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/observ)) if(event.unregister_global(listener)) - log_debug("[event] - [listener] was deleted while still registered to global events.") - if(!(--listen_count)) + log_debug("[event] ([event.type]) - [log_info_line(listener)] was deleted while still globally registered to an event.") + if(!listener.global_listen_count) return + if(listener.global_listen_count > 0) + CRASH("Failed to clean up all global listener entries!") -/proc/cleanup_source_listeners(event_source, source_listener_count) - GLOB.event_sources_count -= event_source - for(var/entry in GLOB.all_observable_events) - var/decl/observ/event = entry - var/proc_owners = event.event_sources[event_source] +// This might actually be fast enough now that there's no point in logging it? +/proc/cleanup_source_listeners(datum/event_source) + for(var/event_type in event_source.event_listeners) + var/list/list/proc_owners = event_source.event_listeners[event_type] if(proc_owners) + var/decl/observ/event = GET_DECL(event_type) for(var/proc_owner in proc_owners) + var/list/callbacks_cached = proc_owners[proc_owner]?.Copy() if(event.unregister(event_source, proc_owner)) - log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].") - if(!(--source_listener_count)) + log_debug("[event] ([event.type]) - [log_info_line(event_source)] was deleted while still being listened to by [log_info_line(proc_owner)]. Callbacks: [json_encode(callbacks_cached)]") + if(!event_source.event_source_count) return + if(event_source.event_source_count > 0) + CRASH("Failed to clean up all event source entries!") -/proc/cleanup_event_listener(listener, listener_count) - GLOB.event_listen_count -= listener - for(var/entry in GLOB.all_observable_events) - var/decl/observ/event = entry - for(var/event_source in event.event_sources) - if(event.unregister(event_source, listener)) - log_debug("[event] - [listener] was deleted while still listening to [event_source].") - if(!(--listener_count)) - return +/proc/cleanup_event_listener(datum/listener) + for(var/event_type in listener._listening_to) + var/list/listened_sources = listener._listening_to[event_type] + if(listened_sources) + for(var/datum/event_source in listened_sources) + var/list/callbacks_cached = event_source.event_listeners[event_type]?[listener]?.Copy() + var/decl/observ/event = GET_DECL(event_type) + if(event.unregister(event_source, listener)) + log_debug("[event] ([event.type]) - [log_info_line(listener)] was deleted while still listening to [log_info_line(event_source)]. Callbacks: [json_encode(callbacks_cached)]") + if(!listener.event_listen_count) + return + if(listener.event_listen_count > 0) + CRASH("Failed to clean up all listener entries!") diff --git a/code/datums/observation/~defines.dm b/code/datums/observation/~defines.dm new file mode 100644 index 000000000000..137bea72e2d4 --- /dev/null +++ b/code/datums/observation/~defines.dm @@ -0,0 +1 @@ +#undef OBSERVATION_NO_GLOBAL_REGISTRATIONS diff --git a/code/datums/outfits/_defines.dm b/code/datums/outfits/_defines.dm index caf11ac7464e..3f2c3d51ae98 100644 --- a/code/datums/outfits/_defines.dm +++ b/code/datums/outfits/_defines.dm @@ -1,13 +1,14 @@ -#define OUTFIT_NONE 0x0000 -#define OUTFIT_HAS_JETPACK 0x0001 -#define OUTFIT_HAS_BACKPACK 0x0002 -#define OUTFIT_EXTENDED_SURVIVAL 0x0004 -#define OUTFIT_RESET_EQUIPMENT 0x0008 +#define OUTFIT_NONE 0 +#define OUTFIT_HAS_JETPACK BITFLAG(0) +#define OUTFIT_HAS_BACKPACK BITFLAG(1) +#define OUTFIT_EXTENDED_SURVIVAL BITFLAG(2) +#define OUTFIT_RESET_EQUIPMENT BITFLAG(3) +#define OUTFIT_HAS_VITALS_SENSOR BITFLAG(4) -#define OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP 0x0001 -#define OUTFIT_ADJUSTMENT_SKIP_SURVIVAL_GEAR 0x0002 -#define OUTFIT_ADJUSTMENT_SKIP_ID_PDA 0x0004 -#define OUTFIT_ADJUSTMENT_PLAIN_HEADSET 0x0008 -#define OUTFIT_ADJUSTMENT_SKIP_BACKPACK 0x0010 +#define OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP BITFLAG(0) +#define OUTFIT_ADJUSTMENT_SKIP_SURVIVAL_GEAR BITFLAG(1) +#define OUTFIT_ADJUSTMENT_SKIP_ID_PDA BITFLAG(2) +#define OUTFIT_ADJUSTMENT_PLAIN_HEADSET BITFLAG(3) +#define OUTFIT_ADJUSTMENT_SKIP_BACKPACK BITFLAG(4) #define OUTFIT_ADJUSTMENT_ALL_SKIPS (OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP|OUTFIT_ADJUSTMENT_SKIP_SURVIVAL_GEAR|OUTFIT_ADJUSTMENT_SKIP_ID_PDA|OUTFIT_ADJUSTMENT_SKIP_BACKPACK) diff --git a/code/datums/outfits/equipment/backpacks.dm b/code/datums/outfits/equipment/backpacks.dm index db95b34f8991..8e6c68468285 100644 --- a/code/datums/outfits/equipment/backpacks.dm +++ b/code/datums/outfits/equipment/backpacks.dm @@ -14,31 +14,43 @@ /decl/backpack_outfit/backpack name = "Backpack" - path = /obj/item/storage/backpack + path = /obj/item/backpack is_default = TRUE /decl/backpack_outfit/rucksack name = "Rucksack" - path = /obj/item/storage/backpack/rucksack + path = /obj/item/backpack/rucksack flags = BACKPACK_HAS_TYPE_SELECTION /decl/backpack_outfit/satchel name = "Satchel" - path = /obj/item/storage/backpack/satchel + path = /obj/item/backpack/satchel -/decl/backpack_outfit/satchel/New() - ..() - tweaks += new/datum/backpack_tweak/selection/specified_types_as_list(typesof(/obj/item/storage/backpack/satchel/leather) + /obj/item/storage/backpack/satchel/grey) +/decl/backpack_outfit/satchel/Initialize() + . = ..() + tweaks += new/datum/backpack_tweak/selection/specified_types_as_list(typesof(/obj/item/backpack/satchel/leather) + /obj/item/backpack/satchel/grey) /decl/backpack_outfit/messenger_bag name = "Messenger bag" - path = /obj/item/storage/backpack/messenger + path = /obj/item/backpack/messenger /decl/backpack_outfit/pocketbook name = "Pocketbook" - path = /obj/item/storage/backpack/satchel/pocketbook + path = /obj/item/backpack/satchel/pocketbook flags = BACKPACK_HAS_TYPE_SELECTION +/decl/backpack_outfit/sack + name = "Sack" + path = /obj/item/bag/sack + +/decl/backpack_outfit/haversack + name = "Haversack" + path = /obj/item/backpack/crafted + +/decl/backpack_outfit/backpack/crafted + name = "Handmade Backpack" + path = /obj/item/backpack/crafted/backpack + /* Code */ /decl/backpack_outfit var/flags @@ -47,7 +59,9 @@ var/is_default = FALSE var/list/tweaks -/decl/backpack_outfit/New() +/decl/backpack_outfit/Initialize() + . = ..() + tweaks = tweaks || list() if(FLAGS_EQUALS(flags, BACKPACK_HAS_TYPE_SELECTION|BACKPACK_HAS_SUBTYPE_SELECTION)) @@ -91,7 +105,7 @@ /datum/backpack_tweak/proc/get_backpack_type(var/given_backpack_type) return given_backpack_type -/datum/backpack_tweak/proc/tweak_backpack(var/obj/item/storage/backpack/backpack, var/metadata) +/datum/backpack_tweak/proc/tweak_backpack(var/obj/item/backpack/backpack, var/metadata) return @@ -118,7 +132,7 @@ if(!istext(selection_key)) CRASH("Expected a valid selection key, was [log_info_line(selection_key)]") var/selection_type = selections[selection_key] - if(!ispath(selection_type, /obj/item/storage/backpack)) + if(!ispath(selection_type, /obj/item/backpack)) CRASH("Expected a valid selection value, was [log_info_line(selection_type)]") src.selections = selections @@ -174,11 +188,11 @@ * Helpers * **********/ /proc/get_default_outfit_backpack() - var backpacks = decls_repository.get_decls_of_subtype(/decl/backpack_outfit) + var backpacks = global.using_map.get_available_backpacks() for(var/backpack in backpacks) - var/decl/backpack_outfit/bo = backpacks[backpack] - if(bo.is_default) - return bo + var/decl/backpack_outfit/backpack_option = backpacks[backpack] + if(backpack_option.is_default) + return backpack_option #undef BACKPACK_HAS_TYPE_SELECTION #undef BACKPACK_HAS_SUBTYPE_SELECTION diff --git a/code/datums/outfits/equipment/survival_box.dm b/code/datums/outfits/equipment/survival_box.dm new file mode 100644 index 000000000000..e9d7e4cdbd9f --- /dev/null +++ b/code/datums/outfits/equipment/survival_box.dm @@ -0,0 +1,29 @@ +/decl/survival_box_option + decl_flags = DECL_FLAG_MANDATORY_UID + abstract_type = /decl/survival_box_option + var/name = "survival box option" + var/box_type + +/decl/survival_box_option/none + name = "nothing" + uid = "survival_box_nothing" + +/decl/survival_box_option/survival + name = "survival kit" + box_type = /obj/item/box/survival + uid = "survival_box_kit" + +/decl/survival_box_option/lunchbox + name = "lunchbox" + box_type = /obj/item/lunchbox/filled + uid = "survival_box_lunchbox" + +/decl/survival_box_option/lunchbox/heart + name = "heart lunchbox" + box_type = /obj/item/lunchbox/heart/filled + uid = "survival_box_lunchbox_heart" + +/decl/survival_box_option/lunchbox/cat + name = "cat lunchbox" + box_type = /obj/item/lunchbox/cat/filled + uid = "survival_box_lunchbox_cat" diff --git a/code/datums/outfits/horror_killers.dm b/code/datums/outfits/horror_killers.dm index 1af3fc931f8a..42538ab43b00 100644 --- a/code/datums/outfits/horror_killers.dm +++ b/code/datums/outfits/horror_killers.dm @@ -1,6 +1,6 @@ -/decl/hierarchy/outfit/tunnel_clown +/decl/outfit/tunnel_clown name = "Tunnel clown" - uniform = /obj/item/clothing/under/rank/clown + uniform = /obj/item/clothing/costume/clown shoes = /obj/item/clothing/shoes/clown_shoes gloves = /obj/item/clothing/gloves/thick mask = /obj/item/clothing/mask/gas/clown_hat @@ -9,15 +9,15 @@ glasses = /obj/item/clothing/glasses/thermal/plain/monocle suit = /obj/item/clothing/suit/chaplain_hoodie r_pocket = /obj/item/bikehorn - r_hand = /obj/item/twohanded/fireaxe + hands = list(/obj/item/bladed/axe/fire) - id_slot = slot_wear_id + id_slot = slot_wear_id_str id_type = /obj/item/card/id/centcom/station id_pda_assignment = "Tunnel Clown!" -/decl/hierarchy/outfit/masked_killer +/decl/outfit/masked_killer name = "Masked killer" - uniform = /obj/item/clothing/under/overalls + uniform = /obj/item/clothing/pants/mustard/overalls shoes = /obj/item/clothing/shoes/color/white gloves = /obj/item/clothing/gloves/latex mask = /obj/item/clothing/mask/surgical @@ -27,31 +27,32 @@ suit = /obj/item/clothing/suit/apron l_pocket = /obj/item/knife/combat r_pocket = /obj/item/scalpel - r_hand = /obj/item/twohanded/fireaxe + hands = list(/obj/item/bladed/axe/fire) -/decl/hierarchy/outfit/masked_killer/post_equip(var/mob/living/carbon/human/H) +/decl/outfit/masked_killer/post_equip(var/mob/living/wearer) ..() - var/victim = get_mannequin(H.ckey) - for(var/obj/item/carried_item in H.get_equipped_items(TRUE)) - carried_item.add_blood(victim) //Oh yes, there will be blood.. just not blood from the killer because that's odd + var/victim = get_mannequin(wearer.ckey) + if(victim) + for(var/obj/item/carried_item in wearer.get_equipped_items(TRUE)) + carried_item.add_blood(victim) //Oh yes, there will be blood... just not blood from the killer because that's odd -/decl/hierarchy/outfit/reaper +/decl/outfit/reaper name = "Reaper" - uniform = /obj/item/clothing/under/suit_jacket{ starting_accessories=list(/obj/item/clothing/accessory/wcoat/black) } - shoes = /obj/item/clothing/shoes/color/black - gloves = /obj/item/clothing/gloves/thick - l_ear = /obj/item/radio/headset - glasses = /obj/item/clothing/glasses/sunglasses + uniform = /obj/item/clothing/pants/slacks/outfit + shoes = /obj/item/clothing/shoes/color/black + gloves = /obj/item/clothing/gloves/thick + l_ear = /obj/item/radio/headset + glasses = /obj/item/clothing/glasses/sunglasses l_pocket = /obj/item/energy_blade/sword - id_slot = slot_wear_id + id_slot = slot_wear_id_str id_type = /obj/item/card/id/syndicate/station_access - pda_slot = slot_belt + pda_slot = slot_belt_str pda_type = /obj/item/modular_computer/pda/heads -/decl/hierarchy/outfit/reaper/post_equip(var/mob/living/carbon/human/H) +/decl/outfit/reaper/post_equip(var/mob/living/wearer) ..() - var/obj/item/storage/secure/briefcase/sec_briefcase = new(H) + var/obj/item/secure_storage/briefcase/sec_briefcase = new(wearer) for(var/obj/item/briefcase_item in sec_briefcase) qdel(briefcase_item) for(var/i=3, i>0, i--) @@ -60,4 +61,4 @@ new /obj/item/gun/projectile/revolver(sec_briefcase) new /obj/item/ammo_magazine/speedloader(sec_briefcase) new /obj/item/plastique(sec_briefcase) - H.equip_to_slot_or_del(sec_briefcase, slot_l_hand) + wearer.put_in_hands_or_del(sec_briefcase) diff --git a/code/datums/outfits/jobs/_defines.dm b/code/datums/outfits/jobs/_defines.dm index 3b94c4a3cbf9..f811a3a5b165 100644 --- a/code/datums/outfits/jobs/_defines.dm +++ b/code/datums/outfits/jobs/_defines.dm @@ -1,36 +1,34 @@ -#define OUTFIT_JOB_NAME(job_name) ("Job - " + job_name) - #define BACKPACK_OVERRIDE_CHEMISTRY \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/chemistry; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/chem; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/chem; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/chemistry; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/chem; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/chem; #define BACKPACK_OVERRIDE_ENGINEERING \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/industrial; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/eng; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/engi; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/industrial; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/eng; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/engi; #define BACKPACK_OVERRIDE_MEDICAL \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/medic; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/med; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/med; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/medic; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/med; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/med; #define BACKPACK_OVERRIDE_RESEARCH \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/toxins; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/tox; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/viro; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/toxins; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/tox; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/viro; #define BACKPACK_OVERRIDE_SECURITY \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/security; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/sec; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/sec; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/security; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/sec; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/sec; #define BACKPACK_OVERRIDE_SECURITY_EXO \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/security/exo; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/sec/exo; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/sec/exo; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/security/exo; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/sec/exo; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/sec/exo; #define BACKPACK_OVERRIDE_VIROLOGY \ -backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/virology; \ -backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/storage/backpack/satchel/vir; \ -backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/storage/backpack/messenger/viro; +backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/virology; \ +backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/vir; \ +backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/viro; diff --git a/code/datums/outfits/jobs/generic.dm b/code/datums/outfits/jobs/generic.dm index 4f449579fcc1..67ebfa0d20ae 100644 --- a/code/datums/outfits/jobs/generic.dm +++ b/code/datums/outfits/jobs/generic.dm @@ -1,51 +1,53 @@ - -/decl/hierarchy/outfit/job/generic - hierarchy_type = /decl/hierarchy/outfit/job/generic +/decl/outfit/job/generic + abstract_type = /decl/outfit/job/generic id_type = /obj/item/card/id/civilian -/decl/hierarchy/outfit/job/generic/scientist - name = OUTFIT_JOB_NAME("Default Scientist") +/decl/outfit/job/generic/assistant + name = "Job - Assistant" + +/decl/outfit/job/generic/scientist + name = "Job - Default Scientist" l_ear = /obj/item/radio/headset/headset_sci - suit = /obj/item/clothing/suit/storage/toggle/labcoat/science + suit = /obj/item/clothing/suit/toggle/labcoat/science shoes = /obj/item/clothing/shoes/color/white pda_type = /obj/item/modular_computer/pda/science - uniform = /obj/item/clothing/under/color/white + uniform = /obj/item/clothing/jumpsuit/white -/decl/hierarchy/outfit/job/generic/engineer - name = OUTFIT_JOB_NAME("Default Engineer") +/decl/outfit/job/generic/engineer + name = "Job - Default Engineer" head = /obj/item/clothing/head/hardhat - uniform = /obj/item/clothing/under/rank/engineer + uniform = /obj/item/clothing/jumpsuit/engineer r_pocket = /obj/item/t_scanner - belt = /obj/item/storage/belt/utility/full + belt = /obj/item/belt/utility/full l_ear = /obj/item/radio/headset/headset_eng shoes = /obj/item/clothing/shoes/workboots pda_type = /obj/item/modular_computer/pda/engineering - pda_slot = slot_l_store - flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + pda_slot = slot_l_store_str + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR -/decl/hierarchy/outfit/job/generic/engineer/New() - ..() +/decl/outfit/job/generic/engineer/Initialize() + . = ..() BACKPACK_OVERRIDE_ENGINEERING -/decl/hierarchy/outfit/job/generic/doctor - name = OUTFIT_JOB_NAME("Default Doctor") - uniform = /obj/item/clothing/under/rank/medical - suit = /obj/item/clothing/suit/storage/toggle/labcoat - l_hand = /obj/item/storage/firstaid/adv +/decl/outfit/job/generic/doctor + name = "Job - Default Doctor" + uniform = /obj/item/clothing/jumpsuit/medical + suit = /obj/item/clothing/suit/toggle/labcoat + hands = list(/obj/item/firstaid/adv) r_pocket = /obj/item/flashlight/pen l_ear = /obj/item/radio/headset/headset_med shoes = /obj/item/clothing/shoes/color/white pda_type = /obj/item/modular_computer/pda/medical - pda_slot = slot_l_store + pda_slot = slot_l_store_str -/decl/hierarchy/outfit/job/generic/doctor/New() - ..() +/decl/outfit/job/generic/doctor/Initialize() + . = ..() BACKPACK_OVERRIDE_MEDICAL -/decl/hierarchy/outfit/job/generic/chef - name = OUTFIT_JOB_NAME("Default Chef") +/decl/outfit/job/generic/chef + name = "Job - Default Chef" l_ear = /obj/item/radio/headset/headset_service - uniform = /obj/item/clothing/under/rank/chef + uniform = /obj/item/clothing/pants/slacks/outfit_chef suit = /obj/item/clothing/suit/chef head = /obj/item/clothing/head/chefhat pda_type = /obj/item/modular_computer/pda diff --git a/code/datums/outfits/jobs/job.dm b/code/datums/outfits/jobs/job.dm index e51c66dce556..717f6127dcd5 100644 --- a/code/datums/outfits/jobs/job.dm +++ b/code/datums/outfits/jobs/job.dm @@ -1,23 +1,14 @@ -/decl/hierarchy/outfit/job +/decl/outfit/job name = "Standard Gear" - hierarchy_type = /decl/hierarchy/outfit/job + abstract_type = /decl/outfit/job - uniform = /obj/item/clothing/under/color/grey + uniform = /obj/item/clothing/jumpsuit/grey l_ear = /obj/item/radio/headset shoes = /obj/item/clothing/shoes/color/black - id_slot = slot_wear_id + id_slot = slot_wear_id_str id_type = /obj/item/card/id/civilian - pda_slot = slot_belt + pda_slot = slot_belt_str pda_type = /obj/item/modular_computer/pda - flags = OUTFIT_HAS_BACKPACK - -/decl/hierarchy/outfit/job/equip_id(mob/living/carbon/human/H) - var/obj/item/card/id/C = ..() - if(!C) - return - if(H.mind) - if(H.mind.initial_account) - C.associated_account_number = H.mind.initial_account.account_number - return C + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_HAS_VITALS_SENSOR diff --git a/code/datums/outfits/jobs/misc.dm b/code/datums/outfits/jobs/misc.dm index 43bbd919f8e1..feb531208ffa 100644 --- a/code/datums/outfits/jobs/misc.dm +++ b/code/datums/outfits/jobs/misc.dm @@ -1,11 +1,11 @@ -/decl/hierarchy/outfit/job/silicon +/decl/outfit/job/silicon head = /obj/item/clothing/head/cardborg - hierarchy_type = /decl/hierarchy/outfit/job/silicon + abstract_type = /decl/outfit/job/silicon -/decl/hierarchy/outfit/job/silicon/ai - name = OUTFIT_JOB_NAME("AI") +/decl/outfit/job/silicon/ai + name = "Job - AI" suit = /obj/item/clothing/suit/straight_jacket -/decl/hierarchy/outfit/job/silicon/cyborg - name = OUTFIT_JOB_NAME("Cyborg") +/decl/outfit/job/silicon/cyborg + name = "Job - Cyborg" suit = /obj/item/clothing/suit/cardborg diff --git a/code/datums/outfits/misc.dm b/code/datums/outfits/misc.dm index a1fc77afd24f..aaf3e6d7b365 100644 --- a/code/datums/outfits/misc.dm +++ b/code/datums/outfits/misc.dm @@ -1,53 +1,42 @@ -/decl/hierarchy/outfit/standard_space_gear +/decl/outfit/standard_space_gear name = "Standard space gear" shoes = /obj/item/clothing/shoes/color/black head = /obj/item/clothing/head/helmet/space suit = /obj/item/clothing/suit/space - uniform = /obj/item/clothing/under/color/grey + uniform = /obj/item/clothing/jumpsuit/grey back = /obj/item/tank/jetpack/oxygen mask = /obj/item/clothing/mask/breath - flags = OUTFIT_HAS_JETPACK|OUTFIT_RESET_EQUIPMENT + outfit_flags = OUTFIT_HAS_JETPACK|OUTFIT_RESET_EQUIPMENT -/decl/hierarchy/outfit/soviet_soldier +/decl/outfit/soviet_soldier name = "Soviet soldier" - uniform = /obj/item/clothing/under/soviet + uniform = /obj/item/clothing/costume/soviet shoes = /obj/item/clothing/shoes/jackboots/swat/combat head = /obj/item/clothing/head/ushanka gloves = /obj/item/clothing/gloves/thick/combat - back = /obj/item/storage/backpack/satchel + back = /obj/item/backpack/satchel belt = /obj/item/gun/projectile/revolver -/decl/hierarchy/outfit/soviet_soldier/admiral +/decl/outfit/soviet_soldier/admiral name = "Soviet admiral" head = /obj/item/clothing/head/hgpiratecap l_ear = /obj/item/radio/headset/heads/captain glasses = /obj/item/clothing/glasses/thermal/plain/eyepatch suit = /obj/item/clothing/suit/hgpirate - id_slot = slot_wear_id + id_slot = slot_wear_id_str id_type = /obj/item/card/id/centcom/station id_pda_assignment = "Admiral" -/decl/hierarchy/outfit/merchant - name = "Merchant" - shoes = /obj/item/clothing/shoes/color/black - l_ear = /obj/item/radio/headset - uniform = /obj/item/clothing/under/color/grey - id_slot = slot_wear_id - id_type = /obj/item/card/id/merchant - pda_slot = slot_r_store - pda_type = /obj/item/modular_computer/pda //cause I like the look - id_pda_assignment = "Merchant" - -/decl/hierarchy/outfit/clown +/decl/outfit/clown name = "Clown" shoes = /obj/item/clothing/shoes/clown_shoes mask = /obj/item/clothing/mask/gas/clown_hat l_ear = /obj/item/radio/headset - uniform = /obj/item/clothing/under/rank/clown + uniform = /obj/item/clothing/costume/clown l_pocket = /obj/item/bikehorn - flags = OUTFIT_HAS_BACKPACK|OUTFIT_RESET_EQUIPMENT + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_RESET_EQUIPMENT | OUTFIT_HAS_VITALS_SENSOR -/decl/hierarchy/outfit/clown/New() - ..() - backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/storage/backpack/clown +/decl/outfit/clown/Initialize() + . = ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/clown diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm index eb7323d8925d..a3ce8adfbdd5 100644 --- a/code/datums/outfits/outfit.dm +++ b/code/datums/outfits/outfit.dm @@ -1,46 +1,26 @@ -var/list/outfits_decls_ -var/list/outfits_decls_root_ -var/list/outfits_decls_by_type_ - -/proc/outfit_by_type(var/outfit_type) - if(!outfits_decls_root_) - init_outfit_decls() - return outfits_decls_by_type_[outfit_type] - -/proc/outfits() - if(!outfits_decls_root_) - init_outfit_decls() - return outfits_decls_ - -/proc/init_outfit_decls() - if(outfits_decls_root_) - return - outfits_decls_ = list() - outfits_decls_by_type_ = list() - outfits_decls_root_ = decls_repository.get_decl(/decl/hierarchy/outfit) - -/decl/hierarchy/outfit - name = "Naked" - - var/uniform = null - var/suit = null - var/back = null - var/belt = null - var/gloves = null - var/shoes = null - var/head = null - var/mask = null - var/l_ear = null - var/r_ear = null - var/glasses = null - var/id = null - var/l_pocket = null - var/r_pocket = null +/decl/outfit + abstract_type = /decl/outfit + var/name = "Naked And Afraid" + var/uniform = null + var/suit = null + var/back = null + var/belt = null + var/gloves = null + var/shoes = null + var/head = null + var/mask = null + var/l_ear = null + var/r_ear = null + var/glasses = null + var/id = null + var/l_pocket = null + var/r_pocket = null var/suit_store = null - var/r_hand = null - var/l_hand = null - var/holster = null - var/list/backpack_contents = list() // In the list(path=count,otherpath=count) format + var/holster = null + /// Linear list of types. Will attempt to place items in hands. + var/list/hands + //. An associative list in list(path=count,otherpath=count) format. Will attempt to place items in storage. + var/list/backpack_contents var/id_type var/id_desc @@ -52,145 +32,245 @@ var/list/outfits_decls_by_type_ var/id_pda_assignment var/list/backpack_overrides - var/flags = OUTFIT_RESET_EQUIPMENT + var/outfit_flags = OUTFIT_RESET_EQUIPMENT -/decl/hierarchy/outfit/New() - ..() +/decl/outfit/Initialize() + . = ..() backpack_overrides = backpack_overrides || list() - if(is_hidden_category()) - return - outfits_decls_by_type_[type] = src - dd_insertObjectList(outfits_decls_, src) +// Used for slightly cleaner code around multi-equip records. +/decl/outfit/proc/resolve_equip_to_list(check_type) + if(islist(check_type)) + return check_type + if(ispath(check_type)) + return list(check_type) + return null + +/decl/outfit/validate() + . = ..() + + for(var/check_type in list(uniform, suit, back, belt, gloves, shoes, head, mask, l_ear, r_ear, glasses, id, l_pocket, r_pocket, suit_store, pda_type, id_type)) + for(var/obj/item/thing as anything in resolve_equip_to_list(check_type)) + if(TYPE_IS_ABSTRACT(thing)) + . += "equipment includes abstract type '[thing]'" + + for(var/check_type in hands) + var/obj/item/thing = check_type + if(isnull(thing)) + continue + if(TYPE_IS_ABSTRACT(thing)) + . += "hands includes abstract type '[thing]'" + + for(var/check_type in backpack_contents) + var/obj/item/thing = check_type + if(isnull(thing)) + continue + if(TYPE_IS_ABSTRACT(thing)) + . += "backpack includes abstract type '[thing]'" + + if(uniform && (outfit_flags & OUTFIT_HAS_VITALS_SENSOR)) + var/list/uniforms = resolve_equip_to_list(uniform) + if(!length(uniforms)) + . += "outfit is flagged for sensors, but has no uniform" + else + var/succeeded = FALSE + var/obj/item/sensor = new /obj/item/clothing/sensor/vitals + for(var/thing in uniforms) + if(!ispath(thing, /obj/item/clothing)) + . += "outfit is flagged for sensors, but uniform [thing] cannot take accessories" + if(thing) + var/obj/item/clothing/wear_uniform = new thing // sadly we need to read a list + if(wear_uniform.can_attach_accessory(sensor)) + succeeded = TRUE + if(!QDELETED(wear_uniform)) + qdel(wear_uniform) + if(succeeded) + break + if(!QDELETED(sensor)) + qdel(sensor) + if(!succeeded) + . += "outfit is flagged for sensors, but uniform does not accept sensors" -/decl/hierarchy/outfit/proc/pre_equip(mob/living/carbon/human/H) - if(flags & OUTFIT_RESET_EQUIPMENT) - H.delete_inventory(TRUE) +/decl/outfit/proc/pre_equip(mob/living/wearer) + if(outfit_flags & OUTFIT_RESET_EQUIPMENT) + wearer.delete_inventory(TRUE) -/decl/hierarchy/outfit/proc/post_equip(mob/living/carbon/human/H) - if(flags & OUTFIT_HAS_JETPACK) - var/obj/item/tank/jetpack/J = locate(/obj/item/tank/jetpack) in H +/decl/outfit/proc/post_equip(mob/living/wearer) + if(outfit_flags & OUTFIT_HAS_JETPACK) + var/obj/item/tank/jetpack/J = locate(/obj/item/tank/jetpack) in wearer if(!J) return J.toggle() J.toggle_valve() -/decl/hierarchy/outfit/proc/equip(mob/living/carbon/human/H, var/rank, var/assignment, var/equip_adjustments) - equip_base(H, equip_adjustments) - - rank = id_pda_assignment || rank - assignment = id_pda_assignment || assignment || rank - var/obj/item/card/id/W = equip_id(H, rank, assignment, equip_adjustments) - if(W) - rank = W.rank - assignment = W.assignment - equip_pda(H, rank, assignment, equip_adjustments) - +/decl/outfit/proc/equip_outfit(mob/living/wearer, assignment, equip_adjustments, datum/job/job, datum/mil_rank/rank) + equip_base(wearer, equip_adjustments) + equip_id(wearer, assignment, equip_adjustments, job, rank) for(var/path in backpack_contents) - var/number = backpack_contents[path] - for(var/i=0,ireagents[r_r]) - . = 0 - else - return -1 - if (length(reagents) < LAZYLEN(avail_reagents.reagent_volumes)) - return 0 - return . - -/datum/recipe/proc/check_fruit(var/obj/container) - . = 1 - if(fruit && fruit.len) - var/list/checklist = list() - // You should trust Copy(). - checklist = fruit.Copy() - for(var/obj/item/chems/food/snacks/grown/G in container) - if(!G.seed || !G.seed.kitchen_tag || isnull(checklist[G.seed.kitchen_tag])) - continue - checklist[G.seed.kitchen_tag]-- - for(var/ktag in checklist) - if(!isnull(checklist[ktag])) - if(checklist[ktag] < 0) - . = 0 - else if(checklist[ktag] > 0) - . = -1 - break - return . - -/datum/recipe/proc/check_items(var/obj/container) - . = 1 - if (items && items.len) - var/list/checklist = list() - checklist = items.Copy() // You should really trust Copy - for(var/obj/O in container.InsertedContents()) - if(istype(O,/obj/item/chems/food/snacks/grown)) - continue // Fruit is handled in check_fruit(). - var/found = 0 - for(var/i = 1; i < checklist.len+1; i++) - var/item_type = checklist[i] - if (istype(O,item_type)) - checklist.Cut(i, i+1) - found = 1 - break - if (!found) - . = 0 - if (checklist.len) - . = -1 - return . - -//general version -/datum/recipe/proc/make(var/obj/container) - var/obj/result_obj = new result(container) - for (var/obj/O in (container.InsertedContents()-result_obj)) - O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) - qdel(O) - container.reagents.clear_reagents() - return result_obj - -// food-related -/datum/recipe/proc/make_food(var/obj/container) - if(!result) - log_error("Recipe [type] is defined without a result, please bug this.") - return - var/obj/result_obj = new result(container) - container.reagents.clear_reagents() - //Checked here in case LAZYCLEARLIST nulls and no more physical ingredients are added - var/list/container_contents = container.InsertedContents() - if(!container_contents) - return result_obj - for (var/obj/O in (container_contents-result_obj)) - if (O.reagents) - O.reagents.clear_reagent(/decl/material/liquid/nutriment) - O.reagents.update_total() - O.reagents.trans_to_obj(result_obj, O.reagents.total_volume) - if(istype(O,/obj/item/holder/)) - var/obj/item/holder/H = O - H.destroy_all() - qdel(O) - return result_obj - -/proc/select_recipe(var/list/datum/recipe/avaiable_recipes, var/obj/obj, var/exact) - var/list/datum/recipe/possible_recipes = new - var/target = exact ? 0 : 1 - for (var/datum/recipe/recipe in avaiable_recipes) - if((recipe.check_reagents(obj.reagents) < target) || (recipe.check_items(obj) < target) || (recipe.check_fruit(obj) < target)) - continue - possible_recipes |= recipe - if (possible_recipes.len==0) - return null - else if (possible_recipes.len==1) - return possible_recipes[1] - else //okay, let's select the most complicated recipe - var/highest_count = 0 - . = possible_recipes[1] - for (var/datum/recipe/recipe in possible_recipes) - var/count = ((recipe.items)?(recipe.items.len):0) + ((recipe.reagents)?(recipe.reagents.len):0) + ((recipe.fruit)?(recipe.fruit.len):0) - if (count >= highest_count) - highest_count = count - . = recipe - return . diff --git a/code/datums/repositories/admin_pm.dm b/code/datums/repositories/admin_pm.dm deleted file mode 100644 index f4900b123145..000000000000 --- a/code/datums/repositories/admin_pm.dm +++ /dev/null @@ -1,44 +0,0 @@ -var/repository/admin_pm/admin_pm_repository = new() - -/repository/admin_pm - var/list/admin_pms_ - var/list/irc_clients_by_name - -/repository/admin_pm/New() - ..() - admin_pms_ = list() - irc_clients_by_name = list() - -/repository/admin_pm/proc/store_pm(var/client/sender, var/client/receiver, var/message) - if(receiver) - if(istype(receiver)) - receiver = client_repository.get_lite_client(receiver) - else if(starts_with(receiver, "IRC-")) - receiver = get_irc_client(receiver) - else - CRASH("Invalid receiver: [log_info_line(receiver)]") - - // Newest messages first - admin_pms_.Insert(1, new/datum/admin_privat_message(client_repository.get_lite_client(sender), receiver, message)) - -/repository/admin_pm/proc/get_irc_client(key) - var/datum/client_lite/cl = irc_clients_by_name[key] - if(!cl) - cl = new/datum/client_lite() - cl.name = "IRC" - cl.key = key - irc_clients_by_name[key] = cl - return cl - -/datum/admin_privat_message - var/station_time - var/datum/client_lite/sender // We don't store the proper client because it gets deleted if banned - var/datum/client_lite/receiver - var/message - -/datum/admin_privat_message/New(var/sender, var/receiver, var/message) - station_time = time_stamp() - src.message = message - src.sender = sender - src.receiver = receiver - diff --git a/code/datums/repositories/areas.dm b/code/datums/repositories/areas.dm index 5e9610b572ac..a19e53f8eb86 100644 --- a/code/datums/repositories/areas.dm +++ b/code/datums/repositories/areas.dm @@ -1,24 +1,18 @@ -/var/repository/area/area_repository = new() +var/global/repository/area/area_repository = new() /repository/area - var/list/by_name_coords_cache_data - var/list/by_name_cache_data - var/list/by_z_level_cache_data - -/repository/area/New() - by_name_coords_cache_data = list() - by_name_cache_data = list() - by_z_level_cache_data = list() - ..() + var/list/by_name_coords_cache_data = list() + var/list/by_name_cache_data = list() + var/list/by_z_level_cache_data = list() /repository/area/proc/get_areas_by_name(var/list/area_predicates = /proc/is_not_space_area) - return priv_get_cached_areas(by_name_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_name) + return priv_get_cached_areas(by_name_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_area_proper_name) /repository/area/proc/get_areas_by_name_and_coords(var/list/area_predicates = /proc/is_not_space_area) - return priv_get_cached_areas(by_name_coords_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_name_and_coordinates) + return priv_get_cached_areas(by_name_coords_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_area_proper_name_and_coordinates) /repository/area/proc/get_areas_by_z_level(var/list/area_predicates = /proc/is_not_space_area) - return priv_get_cached_areas(by_z_level_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_name_and_coordinates) + return priv_get_cached_areas(by_z_level_cache_data, /proc/group_areas_by_z_level, area_predicates, /proc/get_area_proper_name_and_coordinates) /repository/area/proc/priv_get_cached_areas(var/list/area_cache, var/area_group_proc, var/list/area_predicates, var/naming_proc) . = get_cache_entry(area_cache, area_predicates) @@ -29,11 +23,11 @@ /repository/area/proc/priv_get_areas_by_proc(var/area_group_proc, var/list/area_predicates, var/naming_proc) var/list/grouped_areas = call(area_group_proc)(area_predicates) - grouped_areas = sortAssoc(grouped_areas) + grouped_areas = sortTim(grouped_areas, /proc/cmp_text_asc) . = list() for(var/area_key in grouped_areas) var/list/list_of_areas = grouped_areas[area_key] - list_of_areas = sortAtom(list_of_areas) + list_of_areas = sortTim(list_of_areas, /proc/cmp_name_asc) for(var/area/A in list_of_areas) if(A.has_turfs()) .[call(naming_proc)(A)] = A @@ -51,3 +45,9 @@ var/datum/cache_entry/cache_entry = cache_data[key] cache_entry.timestamp = world.time + 3 MINUTES cache_entry.data = data + +/repository/area/proc/clear_cache() + for(var/list/L in list(by_name_coords_cache_data, by_name_cache_data, by_z_level_cache_data)) + for(var/key in L) + qdel(L[key]) + L.Cut() \ No newline at end of file diff --git a/code/datums/repositories/atom_info.dm b/code/datums/repositories/atom_info.dm index d0678de88266..2cfa4bd9ff3e 100644 --- a/code/datums/repositories/atom_info.dm +++ b/code/datums/repositories/atom_info.dm @@ -1,65 +1,97 @@ -var/repository/atom_info/atom_info_repository = new() +var/global/repository/atom_info/atom_info_repository = new() /repository/atom_info - var/list/matter_cache = list() + var/list/matter_cache = list() var/list/combined_worth_cache = list() - var/list/single_worth_cache = list() - var/list/name_cache = list() + var/list/single_worth_cache = list() + var/list/name_cache = list() + var/list/description_cache = list() + var/list/matter_mult_cache = list() + var/list/origin_tech_cache = list() + var/list/appearance_cache = list() -/repository/atom_info/proc/create_key_for(var/path, var/material, var/amount) - . = "[path]" - if(material) - . = "[.]-[material]" - if(!isnull(amount)) - . = "[.]-[amount]" +/repository/atom_info/proc/create_key_for(var/_path, var/_mat, var/_amount) + . = "[_path]" + if(ispath(_path, /obj) && _mat) // only objects take material as an arg + . = "[.]-[_mat]" + if(ispath(_path, /obj/item/stack) && !isnull(_amount)) // similarly for stacks and amount + . = "[.]-[_amount]" -/repository/atom_info/proc/get_instance_of(var/path, var/material, var/amount) - if(ispath(path, /obj/item/stack)) - . = new path(null, amount, material) - else if(ispath(path, /obj)) - . = new path(null, material) +/repository/atom_info/proc/get_instance_of(var/_path, var/_mat, var/_amount) + if(ispath(_path, /obj/item/stack)) + . = new _path(null, _amount, _mat) + else if(ispath(_path, /obj)) + . = new _path(null, _mat) else - . = new path + . = new _path -/repository/atom_info/proc/update_cached_info_for(var/path, var/material, var/amount, var/key) +/repository/atom_info/proc/update_cached_info_for(var/_path, var/_mat, var/_amount, var/key, var/cache_appearance = FALSE) var/atom/instance if(!matter_cache[key]) - instance = get_instance_of(path, material, amount) - var/matter_list = instance.building_cost() - if(istype(instance, /obj/item/ammo_magazine) || istype(instance, /obj/item/storage)) - for(var/obj/thing in instance) - var/list/thing_matter = thing.building_cost() - for(var/mat in thing_matter) - matter_cache[mat] += thing_matter[mat] - matter_cache[key] = matter_list + instance = get_instance_of(_path, _mat, _amount) + matter_cache[key] = instance.get_contained_matter() || list() if(!combined_worth_cache[key]) - instance = instance || get_instance_of(path, material, amount) + instance = instance || get_instance_of(_path, _mat, _amount) combined_worth_cache[key] = instance.get_combined_monetary_worth() if(!single_worth_cache[key]) - instance = instance || get_instance_of(path, material, amount) + instance = instance || get_instance_of(_path, _mat, _amount) single_worth_cache[key] = instance.get_single_monetary_worth() if(!name_cache[key]) - instance = instance || get_instance_of(path, material, amount) + instance = instance || get_instance_of(_path, _mat, _amount) name_cache[key] = instance.name + if(!description_cache[key]) + instance = instance || get_instance_of(_path, _mat, _amount) + description_cache[key] = instance.desc + if(cache_appearance && !appearance_cache[key]) + instance = instance || get_instance_of(_path, _mat, _amount) + appearance_cache[key] = instance.appearance + if(!matter_mult_cache[key] && ispath(_path, /obj)) + var/obj/obj_instance = instance || get_instance_of(_path, _mat, _amount) + matter_mult_cache[key] = obj_instance.get_matter_amount_modifier() + if(!origin_tech_cache[key] && ispath(_path, /obj/item)) + var/obj/item/item_instance = instance || get_instance_of(_path, _mat, _amount) + origin_tech_cache[key] = cached_json_decode(item_instance.get_origin_tech()) if(!QDELETED(instance)) qdel(instance) -/repository/atom_info/proc/get_matter_for(var/path, var/material, var/amount) - var/key = create_key_for(path, material, amount) - update_cached_info_for(path, material, amount, key) +/repository/atom_info/proc/get_matter_for(var/_path, var/_mat, var/_amount) + RETURN_TYPE(/list) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) . = matter_cache[key] -/repository/atom_info/proc/get_combined_worth_for(var/path, var/material, var/amount) - var/key = create_key_for(path, material, amount) - update_cached_info_for(path, material, amount, key) +/repository/atom_info/proc/get_combined_worth_for(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) . = combined_worth_cache[key] -/repository/atom_info/proc/get_single_worth_for(var/path, var/material, var/amount) - var/key = create_key_for(path, material, amount) - update_cached_info_for(path, material, amount, key) +/repository/atom_info/proc/get_single_worth_for(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) . = single_worth_cache[key] -/repository/atom_info/proc/get_name_for(var/path, var/material, var/amount) - var/key = create_key_for(path, material, amount) - update_cached_info_for(path, material, amount, key) +/repository/atom_info/proc/get_name_for(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) . = name_cache[key] + +/repository/atom_info/proc/get_description_for(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) + . = description_cache[key] + +/repository/atom_info/proc/get_matter_multiplier_for(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) + . = matter_mult_cache[key] + +/repository/atom_info/proc/get_origin_tech_for(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key) + . = origin_tech_cache[key] + +// Bespoke proc; only cache appearance if and when this proc is called, not more generally. +/repository/atom_info/proc/get_appearance_of(var/_path, var/_mat, var/_amount) + var/key = create_key_for(_path, _mat, _amount) + update_cached_info_for(_path, _mat, _amount, key, cache_appearance = TRUE) + . = appearance_cache[key] diff --git a/code/datums/repositories/attack_logs.dm b/code/datums/repositories/attack_logs.dm index c6d7303decbe..62507326a3a5 100644 --- a/code/datums/repositories/attack_logs.dm +++ b/code/datums/repositories/attack_logs.dm @@ -1,4 +1,4 @@ -var/repository/attack_logs/attack_log_repository = new() +var/global/repository/attack_logs/attack_log_repository = new() /repository/attack_logs var/list/attack_logs_ @@ -14,6 +14,7 @@ var/repository/attack_logs/attack_log_repository = new() /datum/attack_log var/station_time var/intent + var/target_zone var/datum/mob_lite/attacker // We don't store the proper mob in case it gets deleted var/datum/mob_lite/victim var/turf/location // Turfs are forever @@ -32,7 +33,8 @@ var/repository/attack_logs/attack_log_repository = new() else message = "[victim.name] [action_message]" - intent = mob_attacker ? uppertext(mob_attacker.a_intent) : "N/A" + intent = mob_attacker ? uppertext(mob_attacker.get_intent().uid) : "N/A" + target_zone = uppertext(mob_attacker?.get_target_zone() || "N/A") if(mob_attacker) location = get_turf(mob_attacker) diff --git a/code/datums/repositories/cameras.dm b/code/datums/repositories/cameras.dm index e10c55678f2d..b0d1ab40bdc0 100644 --- a/code/datums/repositories/cameras.dm +++ b/code/datums/repositories/cameras.dm @@ -1,35 +1,36 @@ -var/repository/cameras/camera_repository = new() +var/global/repository/cameras/camera_repository = new() /proc/invalidateCameraCache() - camera_repository.networks.Cut() - camera_repository.invalidated = 1 camera_repository.camera_cache_id = ++camera_repository.camera_cache_id /repository/cameras - var/list/networks - var/invalidated = 1 + var/list/devices_by_channel = list() var/camera_cache_id = 1 -/repository/cameras/New() - networks = list() - ..() +/repository/cameras/proc/devices_in_channel(var/channel) + var/list/device_list = devices_by_channel[channel] + if(device_list) + return device_list.Copy() -/repository/cameras/proc/cameras_in_network(var/network) - setup_cache() - var/list/network_list = networks[network] - return network_list +/repository/cameras/proc/get_devices_by_channel() + return devices_by_channel.Copy() -/repository/cameras/proc/setup_cache() - if(!invalidated) - return - invalidated = 0 +// TODO: Tie AI to a single computer network and replace. +/repository/cameras/proc/add_camera_to_channels(var/datum/extension/network_device/camera/added, var/list/channels) + if(!islist(channels)) + channels = list(channels) + for(var/channel in channels) + if(!devices_by_channel[channel]) + ADD_SORTED(devices_by_channel, channel, /proc/cmp_text_asc) + devices_by_channel[channel] = list() + devices_by_channel[channel] |= added - for(var/sc in cameranet.cameras) - var/obj/machinery/camera/C = sc - var/cam = C.nano_structure() - for(var/network in C.network) - if(!networks[network]) - ADD_SORTED(networks, network, /proc/cmp_text_asc) - networks[network] = list() - var/list/netlist = networks[network] - netlist[++netlist.len] = cam +/repository/cameras/proc/remove_camera_from_channels(var/datum/extension/network_device/camera/removed, var/list/channels) + if(!length(devices_by_channel)) + return + if(!islist(channels)) + channels = list(channels) + for(var/channel in channels) + if(!devices_by_channel[channel]) + continue + devices_by_channel[channel] -= removed \ No newline at end of file diff --git a/code/datums/repositories/client.dm b/code/datums/repositories/client.dm index ebcdec0be28c..44c247c2073a 100644 --- a/code/datums/repositories/client.dm +++ b/code/datums/repositories/client.dm @@ -1,6 +1,6 @@ -var/const/NO_CLIENT_CKEY = "*no ckey*" +var/global/const/NO_CLIENT_CKEY = "*no ckey*" -var/repository/client/client_repository = new() +var/global/repository/client/client_repository = new() /repository/client var/list/clients_ @@ -9,7 +9,7 @@ var/repository/client/client_repository = new() ..() clients_ = list() -// A lite client is unique per ckey and mob ref (save for ref conflicts.. oh well) +// A lite client is unique per ckey and mob ref (save for ref conflicts... oh well) /repository/client/proc/get_lite_client(var/mob/M) if(isclient(M)) var/client/C = M // BYOND is supposed to ensure clients always have a mob @@ -47,7 +47,7 @@ var/repository/client/client_repository = new() return "[key]/([name]) (DC)" if(check_if_offline && !client_by_ckey(ckey)) return "[key]/([name]) (DC)" - return pm_link ? "[key]/([name])[rank2text()]" : "[key]/([name])" + return pm_link ? "[key]/([name])[rank2text()]" : "[key]/([name])" /datum/client_lite/proc/rank2text() var/client/C = client_by_ckey(ckey) diff --git a/code/datums/repositories/crew/binary.dm b/code/datums/repositories/crew/binary.dm index 2afe46337f3c..06c0014e3d27 100644 --- a/code/datums/repositories/crew/binary.dm +++ b/code/datums/repositories/crew/binary.dm @@ -1,16 +1,16 @@ /* Binary */ -/crew_sensor_modifier/binary/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/binary/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) crew_data["alert"] = FALSE if(!H.isSynthetic() && H.should_have_organ(BP_HEART)) - var/obj/item/organ/internal/heart/O = H.internal_organs_by_name[BP_HEART] + var/obj/item/organ/internal/heart/O = H.get_organ(BP_HEART, /obj/item/organ/internal/heart) if (!O || !BP_IS_PROSTHETIC(O)) // Don't make medical freak out over prosthetic hearts - var/pulse = H.pulse() + var/pulse = H.get_pulse() if(pulse == PULSE_NONE || pulse == PULSE_THREADY) crew_data["alert"] = TRUE if(H.get_blood_oxygenation() < BLOOD_VOLUME_SAFE) crew_data["alert"] = TRUE if(H.isSynthetic()) - var/obj/item/organ/internal/cell/cell = H.internal_organs_by_name[BP_CELL] + var/obj/item/organ/internal/cell/cell = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) if(!cell || cell.percent() < 10) crew_data["alert"] = TRUE return ..() @@ -19,11 +19,11 @@ /crew_sensor_modifier/binary/jamming priority = 5 -/crew_sensor_modifier/binary/jamming/alive/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/binary/jamming/alive/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) crew_data["alert"] = FALSE return MOD_SUIT_SENSORS_HANDLED -/crew_sensor_modifier/binary/jamming/dead/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/binary/jamming/dead/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) crew_data["alert"] = TRUE return MOD_SUIT_SENSORS_HANDLED @@ -37,7 +37,7 @@ /crew_sensor_modifier/binary/jamming/random/major error_prob = 100 -/crew_sensor_modifier/binary/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/binary/jamming/random/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() if(prob(error_prob)) crew_data["alert"] = pick(TRUE, FALSE) diff --git a/code/datums/repositories/crew/crew.dm b/code/datums/repositories/crew/crew.dm index f42b49fcc0f3..4a0e5b2c53a7 100644 --- a/code/datums/repositories/crew/crew.dm +++ b/code/datums/repositories/crew/crew.dm @@ -9,11 +9,11 @@ var/global/datum/repository/crew/crew_repository = new() /datum/repository/crew/New() cache_data = list() cache_data_alert = list() - - var/PriorityQueue/general_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) - var/PriorityQueue/binary_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) - var/PriorityQueue/vital_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) - var/PriorityQueue/tracking_modifiers = new/PriorityQueue(/proc/cmp_crew_sensor_modifier) + + var/datum/priority_queue/general_modifiers = new /datum/priority_queue(/proc/cmp_crew_sensor_modifier) + var/datum/priority_queue/binary_modifiers = new /datum/priority_queue(/proc/cmp_crew_sensor_modifier) + var/datum/priority_queue/vital_modifiers = new /datum/priority_queue(/proc/cmp_crew_sensor_modifier) + var/datum/priority_queue/tracking_modifiers = new /datum/priority_queue(/proc/cmp_crew_sensor_modifier) general_modifiers.Enqueue(new/crew_sensor_modifier/general()) binary_modifiers.Enqueue(new/crew_sensor_modifier/binary()) @@ -21,10 +21,10 @@ var/global/datum/repository/crew/crew_repository = new() tracking_modifiers.Enqueue(new/crew_sensor_modifier/tracking()) modifier_queues = list() - modifier_queues[general_modifiers] = 0 - modifier_queues[binary_modifiers] = SUIT_SENSOR_BINARY - modifier_queues[vital_modifiers] = SUIT_SENSOR_VITAL - modifier_queues[tracking_modifiers] = SUIT_SENSOR_TRACKING + modifier_queues[general_modifiers] = VITALS_SENSOR_OFF + modifier_queues[binary_modifiers] = VITALS_SENSOR_BINARY + modifier_queues[vital_modifiers] = VITALS_SENSOR_VITAL + modifier_queues[tracking_modifiers] = VITALS_SENSOR_TRACKING modifier_queues_by_type = list() modifier_queues_by_type[/crew_sensor_modifier/general] = general_modifiers @@ -49,21 +49,24 @@ var/global/datum/repository/crew/crew_repository = new() cache_data_alert[num2text(z_level)] = FALSE var/tracked = scan() - for(var/obj/item/clothing/under/C in tracked) - var/turf/pos = get_turf(C) - if(C.has_sensor && pos && pos.z == z_level && C.sensor_mode != SUIT_SENSOR_OFF) - if(istype(C.loc, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C.loc - if(H.w_uniform != C) - continue - - var/list/crewmemberData = list("sensor_type"=C.sensor_mode, "stat"=H.stat, "area"="", "x"=-1, "y"=-1, "z"=-1, "ref"="\ref[H]") - if(!(run_queues(H, C, pos, crewmemberData) & MOD_SUIT_SENSORS_REJECTED)) - crewmembers[++crewmembers.len] = crewmemberData - if (crewmemberData["alert"]) - cache_data_alert[num2text(z_level)] = TRUE - - crewmembers = sortByKey(crewmembers, "name") + for(var/obj/item/clothing/sensor/vitals/sensor as anything in tracked) + var/turf/pos = get_turf(sensor) + if(!pos || pos.z != z_level || sensor.sensor_mode == VITALS_SENSOR_OFF) + continue + var/mob/living/human/H = sensor.loc?.loc + if(!istype(H)) + continue + var/obj/item/clothing/uniform = H.get_equipped_item(slot_w_uniform_str) + if(!istype(uniform) || !(sensor in uniform.accessories)) + continue + var/list/crewmemberData = list("sensor_type" = sensor.sensor_mode, "stat"=H.stat, "area"="", "x"=-1, "y"=-1, "z"=-1, "ref"="\ref[H]") + if(!(run_queues(H, sensor, pos, crewmemberData) & MOD_SUIT_SENSORS_REJECTED)) + crewmembers[++crewmembers.len] = crewmemberData + if (crewmemberData["alert"]) + cache_data_alert[num2text(z_level)] = TRUE + + crewmembers = sortTim(crewmembers, /proc/cmp_list_name_key_asc) + cache_entry.timestamp = world.time + 5 SECONDS cache_entry.data = crewmembers @@ -79,41 +82,37 @@ var/global/datum/repository/crew/crew_repository = new() . = cache_data_alert[num2text(z_level)] /datum/repository/crew/proc/scan() - var/list/tracked = list() - for(var/mob/living/carbon/human/H in SSmobs.mob_list) - if(istype(H.w_uniform, /obj/item/clothing/under)) - var/obj/item/clothing/under/C = H.w_uniform - if (C.has_sensor) - tracked |= C - return tracked - + for(var/mob/living/human/H in SSmobs.mob_list) + var/sensor = H.get_vitals_sensor() + if(sensor) + LAZYDISTINCTADD(., sensor) -/datum/repository/crew/proc/run_queues(H, C, pos, crewmemberData) +/datum/repository/crew/proc/run_queues(H, S, pos, crewmemberData) for(var/modifier_queue in modifier_queues) if(crewmemberData["sensor_type"] >= modifier_queues[modifier_queue]) - . = process_crew_data(modifier_queue, H, C, pos, crewmemberData) + . = process_crew_data(modifier_queue, H, S, pos, crewmemberData) if(. & MOD_SUIT_SENSORS_REJECTED) return -/datum/repository/crew/proc/process_crew_data(var/PriorityQueue/modifiers, var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/datum/repository/crew/proc/process_crew_data(var/datum/priority_queue/modifiers, var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) var/current_priority = INFINITY var/list/modifiers_of_this_priority = list() - for(var/crew_sensor_modifier/csm in modifiers.L) + for(var/crew_sensor_modifier/csm in modifiers.GetQueue()) if(csm.priority < current_priority) - . = check_queue(modifiers_of_this_priority, H, C, pos, crew_data) + . = check_queue(modifiers_of_this_priority, H, S, pos, crew_data) if(. != MOD_SUIT_SENSORS_NONE) return current_priority = csm.priority modifiers_of_this_priority += csm - return check_queue(modifiers_of_this_priority, H, C, pos, crew_data) + return check_queue(modifiers_of_this_priority, H, S, pos, crew_data) -/datum/repository/crew/proc/check_queue(var/list/modifiers_of_this_priority, H, C, pos, crew_data) +/datum/repository/crew/proc/check_queue(var/list/modifiers_of_this_priority, H, S, pos, crew_data) while(modifiers_of_this_priority.len) var/crew_sensor_modifier/pcsm = pick(modifiers_of_this_priority) modifiers_of_this_priority -= pcsm - if(pcsm.may_process_crew_data(H, C, pos)) - . = pcsm.process_crew_data(H, C, pos, crew_data) + if(pcsm.may_process_crew_data(H, S, pos)) + . = pcsm.process_crew_data(H, S, pos, crew_data) if(. != MOD_SUIT_SENSORS_NONE) return return MOD_SUIT_SENSORS_NONE @@ -121,10 +120,10 @@ var/global/datum/repository/crew/crew_repository = new() /datum/repository/crew/proc/add_modifier(var/base_type, var/crew_sensor_modifier/csm) if(!istype(csm, base_type)) CRASH("The given crew sensor modifier was not of the given base type.") - var/PriorityQueue/pq = modifier_queues_by_type[base_type] + var/datum/priority_queue/pq = modifier_queues_by_type[base_type] if(!pq) CRASH("The given base type was not a valid base type.") - if(csm in pq.L) + if(csm in pq.GetQueue()) CRASH("This crew sensor modifier has already been supplied.") pq.Enqueue(csm) return TRUE @@ -132,7 +131,7 @@ var/global/datum/repository/crew/crew_repository = new() /datum/repository/crew/proc/remove_modifier(var/base_type, var/crew_sensor_modifier/csm) if(!istype(csm, base_type)) CRASH("The given crew sensor modifier was not of the given base type.") - var/PriorityQueue/pq = modifier_queues_by_type[base_type] + var/datum/priority_queue/pq = modifier_queues_by_type[base_type] if(!pq) CRASH("The given base type was not a valid base type.") return pq.Remove(csm) diff --git a/code/datums/repositories/crew/crew_sensor_modifier.dm b/code/datums/repositories/crew/crew_sensor_modifier.dm index 753e429e83d9..20edfbf15705 100644 --- a/code/datums/repositories/crew/crew_sensor_modifier.dm +++ b/code/datums/repositories/crew/crew_sensor_modifier.dm @@ -13,8 +13,8 @@ may_process_proc = null . = ..() -/crew_sensor_modifier/proc/may_process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos) - return holder && may_process_proc ? call(holder, may_process_proc)(H, C, pos) : TRUE +/crew_sensor_modifier/proc/may_process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos) + return holder && may_process_proc ? call(holder, may_process_proc)(H, S, pos) : TRUE -/crew_sensor_modifier/proc/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/proc/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) return MOD_SUIT_SENSORS_HANDLED diff --git a/code/datums/repositories/crew/general.dm b/code/datums/repositories/crew/general.dm index a2c09ddab375..7c0cdae96f5a 100644 --- a/code/datums/repositories/crew/general.dm +++ b/code/datums/repositories/crew/general.dm @@ -1,5 +1,5 @@ /* General */ -/crew_sensor_modifier/general/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/general/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) crew_data["name"] = H.get_authentification_name(if_no_id="Unknown") crew_data["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job") crew_data["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job") @@ -9,23 +9,23 @@ /crew_sensor_modifier/general/jamming priority = 5 -/crew_sensor_modifier/general/jamming/off/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/general/jamming/off/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() // This works only because general is checked first and crew_data["sensor_type"] is used to check if whether any additional data should be included. - crew_data["sensor_type"] = SUIT_SENSOR_OFF + crew_data["sensor_type"] = VITALS_SENSOR_OFF return MOD_SUIT_SENSORS_REJECTED -/crew_sensor_modifier/general/jamming/binary/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/general/jamming/binary/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() - crew_data["sensor_type"] = SUIT_SENSOR_BINARY + crew_data["sensor_type"] = VITALS_SENSOR_BINARY -/crew_sensor_modifier/general/jamming/vital/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/general/jamming/vital/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() - crew_data["sensor_type"] = SUIT_SENSOR_VITAL + crew_data["sensor_type"] = VITALS_SENSOR_VITAL -/crew_sensor_modifier/general/jamming/tracking/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/general/jamming/tracking/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() - crew_data["sensor_type"] = SUIT_SENSOR_TRACKING + crew_data["sensor_type"] = VITALS_SENSOR_TRACKING /* Random */ /crew_sensor_modifier/general/jamming/random @@ -40,9 +40,9 @@ random_sensor_type_prob = 60 random_assignment_prob = 40 -/crew_sensor_modifier/general/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/general/jamming/random/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() if(prob(random_sensor_type_prob)) - crew_data["sensor_type"] = pick(SUIT_SENSOR_OFF, SUIT_SENSOR_BINARY, SUIT_SENSOR_VITAL, SUIT_SENSOR_TRACKING) + crew_data["sensor_type"] = pick(VITALS_SENSOR_OFF, VITALS_SENSOR_BINARY, VITALS_SENSOR_VITAL, VITALS_SENSOR_TRACKING) if(prob(random_assignment_prob)) crew_data["assignment"] = pick("Agent", "Infiltrator", "Passenger", "Crewman", "Unknown") diff --git a/code/datums/repositories/crew/tracking.dm b/code/datums/repositories/crew/tracking.dm index 111408a68574..e4b1f4f35ea7 100644 --- a/code/datums/repositories/crew/tracking.dm +++ b/code/datums/repositories/crew/tracking.dm @@ -1,8 +1,8 @@ /* Tracking */ -/crew_sensor_modifier/tracking/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/tracking/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) if(pos) var/area/A = get_area(pos) - crew_data["area"] = sanitize(A.name) + crew_data["area"] = A.proper_name crew_data["x"] = pos.x crew_data["y"] = pos.y crew_data["z"] = pos.z @@ -12,8 +12,8 @@ /crew_sensor_modifier/tracking/jamming priority = 5 -/crew_sensor_modifier/tracking/jamming/localize/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) - return ..(H, C, get_turf(holder), crew_data) +/crew_sensor_modifier/tracking/jamming/localize/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) + return ..(H, S, get_turf(holder), crew_data) /crew_sensor_modifier/tracking/jamming/random var/shift_range = 7 @@ -27,13 +27,13 @@ /crew_sensor_modifier/tracking/jamming/random/major shift_range = 21 -/crew_sensor_modifier/tracking/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/tracking/jamming/random/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) if(world.time > next_shift_change) next_shift_change = world.time + rand(30 SECONDS, 2 MINUTES) x_shift = rand(-shift_range, shift_range) y_shift = rand(-shift_range, shift_range) if(pos) - var/new_x = Clamp(pos.x + x_shift, 1, world.maxx) - var/new_y = Clamp(pos.y + y_shift, 1, world.maxy) + var/new_x = clamp(pos.x + x_shift, 1, world.maxx) + var/new_y = clamp(pos.y + y_shift, 1, world.maxy) pos = locate(new_x, new_y, pos.z) - return ..(H, C, pos, crew_data) + return ..(H, S, pos, crew_data) diff --git a/code/datums/repositories/crew/vital.dm b/code/datums/repositories/crew/vital.dm index a122f045f8ab..61775c647ba0 100644 --- a/code/datums/repositories/crew/vital.dm +++ b/code/datums/repositories/crew/vital.dm @@ -1,13 +1,13 @@ /* Vital */ -/crew_sensor_modifier/vital/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/vital/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) crew_data["true_pulse"] = -1 crew_data["pulse"] = "N/A" crew_data["pulse_span"] = "neutral" if(!H.isSynthetic() && H.should_have_organ(BP_HEART)) - var/obj/item/organ/internal/heart/O = H.internal_organs_by_name[BP_HEART] + var/obj/item/organ/internal/heart/O = H.get_organ(BP_HEART, /obj/item/organ/internal/heart) if (!O || !BP_IS_PROSTHETIC(O)) // Don't make medical freak out over prosthetic hearts - crew_data["true_pulse"] = H.pulse() - crew_data["pulse"] = H.get_pulse(GETPULSE_TOOL) + crew_data["true_pulse"] = H.get_pulse() + crew_data["pulse"] = H.get_pulse_as_string(GETPULSE_TOOL) switch(crew_data["true_pulse"]) if(PULSE_NONE) crew_data["pulse_span"] = "bad" @@ -24,7 +24,7 @@ crew_data["charge"] = "N/A" crew_data["charge_span"] = "N/A" if(H.isSynthetic()) - var/obj/item/organ/internal/cell/cell = H.internal_organs_by_name[BP_CELL] + var/obj/item/organ/internal/cell/cell = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) if(cell) crew_data["charge"] = cell.percent() if(cell.percent() <= 10) @@ -74,7 +74,7 @@ crew_data["charge_span"] = "good" if(crew_data["true_oxygenation"] != -1) - crew_data["pressure"] = "[Floor(120+rand(-5,5))]/[Floor(80+rand(-5,5))]" + crew_data["pressure"] = "[floor(120+rand(-5,5))]/[floor(80+rand(-5,5))]" crew_data["true_oxygenation"] = 100 crew_data["oxygenation"] = "normal" crew_data["oxygenation_span"] = "good" @@ -91,7 +91,7 @@ crew_data["charge_span"] = "bad" if(crew_data["true_oxygenation"] != -1) - crew_data["pressure"] = "[Floor((120+rand(-5,5))*0.25)]/[Floor((80+rand(-5,5))*0.25)]" + crew_data["pressure"] = "[floor((120+rand(-5,5))*0.25)]/[floor((80+rand(-5,5))*0.25)]" crew_data["true_oxygenation"] = 25 crew_data["oxygenation"] = "extremely low" crew_data["oxygenation_span"] = "bad" @@ -100,12 +100,12 @@ /crew_sensor_modifier/vital/jamming priority = 5 -/crew_sensor_modifier/vital/jamming/healthy/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/vital/jamming/healthy/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() set_healthy(crew_data) return MOD_SUIT_SENSORS_HANDLED -/crew_sensor_modifier/vital/jamming/dead/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/vital/jamming/dead/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() set_dead(crew_data) return MOD_SUIT_SENSORS_HANDLED @@ -120,7 +120,7 @@ /crew_sensor_modifier/vital/jamming/random/major error_prob = 100 -/crew_sensor_modifier/vital/jamming/random/process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos, var/list/crew_data) +/crew_sensor_modifier/vital/jamming/random/process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos, var/list/crew_data) . = ..() if(prob(error_prob)) pick(set_healthy(crew_data), set_dead(crew_data)) diff --git a/code/datums/repositories/decls.dm b/code/datums/repositories/decls.dm index 97ce96c0232d..82476aae8e53 100644 --- a/code/datums/repositories/decls.dm +++ b/code/datums/repositories/decls.dm @@ -1,53 +1,198 @@ -/var/repository/decls/decls_repository = new() +// /decl is a subtype used for singletons that should never have more than one instance +// in existence at a time. If you want to use a /decl you should use a pattern like: +// var/decl/somedecl/mydecl = GET_DECL(/decl/somedecl) + +// /decls are created the first time they are fetched from decls_repository and will +// automatically call Initialize() and such when created in this way. + +// decls_repository.get_decls_of_type() and decls_repository.get_decls_of_subtype() +// can be used similarly to typesof() and subtypesof(), returning assoc instance lists. + +// decls_repository.get_decl_by_id() will retrieve a decl based on a string UID - at time +// of writing this is only set for materials and is used by omni devices to populate their +// mapped port settings. + +// The /decl commandments: +// I. Thou shalt not create a /decl with new(). +// II. Thou shalt not del() or qdel() a /decl. +// III. Thou shalt not write a decl that relies on arguments supplied to New(). +// IV. Thou shalt not call Initialize() on a /decl. + +var/global/repository/decls/decls_repository = new + +/proc/resolve_decl_uid_list(list/decl_uids) + for(var/uid in decl_uids) + var/decl/decl = decls_repository.get_decl_by_id(uid) + if(istype(decl)) + LAZYADD(., decl) /repository/decls - var/list/fetched_decls - var/list/fetched_decl_types - var/list/fetched_decl_subtypes + var/list/fetched_decls = list() + var/list/fetched_decl_ids = list() + var/list/fetched_decl_types = list() + var/list/fetched_decl_instances = list() + var/list/fetched_decl_subtypes = list() + var/list/fetched_decl_subinstances = list() + var/list/fetched_decl_paths_by_type = list() + var/list/fetched_decl_paths_by_subtype = list() /repository/decls/New() ..() - fetched_decls = list() - fetched_decl_types = list() - fetched_decl_subtypes = list() + for(var/decl_type in typesof(/decl)) + var/decl/decl = decl_type + var/decl_uid = initial(decl.uid) + if(decl_uid && (!TYPE_IS_ABSTRACT(decl) || (initial(decl.decl_flags) & DECL_FLAG_ALLOW_ABSTRACT_INIT))) + fetched_decl_ids[decl_uid] = decl + +/repository/decls/proc/get_decl_by_id(var/decl_id, var/validate_decl_type = TRUE) + RETURN_TYPE(/decl) + . = get_decl(fetched_decl_ids[decl_id], validate_decl_type) -/repository/decls/proc/get_decl(var/decl_type) +// This proc and get_decl_by_id_or_var() are being added solely to grandfather in decls saved to player saves under name +// rather than UID. They should be considered deprecated for this purpose - uid and get_decl_by_id() should be used instead. +/repository/decls/proc/get_decl_by_var(var/decl_value, var/decl_prototype, var/check_var = "name") + var/list/all_decls = get_decls_of_type(decl_prototype) + var/decl/prototype = all_decls[all_decls[1]] // Can't just grab the prototype as it may be abstract + if(!(check_var in prototype.vars)) + CRASH("Attempted to retrieve a decl by a var that does not exist on the decl type ('[check_var]')") + for(var/decl_type in all_decls) + var/decl/decl = all_decls[decl_type] + if(decl.vars[check_var] == decl_value) + return decl + +/repository/decls/proc/get_decl_by_id_or_var(var/decl_id, var/decl_prototype, var/check_var = "name") + RETURN_TYPE(/decl) + return get_decl_by_id(decl_id, validate_decl_type = FALSE) || get_decl_by_var(decl_id, decl_prototype, check_var) + +/repository/decls/proc/get_decl_path_by_id(decl_id) + . = fetched_decl_ids[decl_id] + +/repository/decls/proc/get_decl(var/decl/decl_type, var/validate_decl_type = TRUE) + + RETURN_TYPE(/decl) + + if(!ispath(decl_type, /decl)) + if(validate_decl_type) + CRASH("Invalid decl_type supplied to get_decl(): [decl_type || "NULL"]") + return null + + if(TYPE_IS_ABSTRACT(decl_type) && !(initial(decl_type.decl_flags) & DECL_FLAG_ALLOW_ABSTRACT_INIT)) + return // We do not instantiate abstract decls. . = fetched_decls[decl_type] if(!.) - . = new decl_type() - fetched_decls[decl_type] = . - - var/decl/decl = . - if(istype(decl)) - decl.Initialize() + var/decl/decl = new decl_type + fetched_decls[decl_type] = decl // This needs to be done prior to calling Initialize() to avoid circular get_decl() calls by dependencies/children. + // TODO: maybe implement handling for LATELOAD and QDEL init hints? + var/init_result = decl.Initialize() + switch(init_result) + if(INITIALIZE_HINT_NORMAL) + . = decl + else + if(fetched_decls[decl_type] == decl) + fetched_decls -= decl_type + PRINT_STACK_TRACE("Invalid return hint to [decl_type]/Initialize(): [init_result || "NULL"]") /repository/decls/proc/get_decls(var/list/decl_types) . = list() for(var/decl_type in decl_types) - .[decl_type] = get_decl(decl_type) + var/decl = get_decl(decl_type) + if(decl) + .[decl_type] = decl + +/repository/decls/proc/get_decl_paths_of_type(var/decl_prototype) + . = fetched_decl_paths_by_type[decl_prototype] + if(!.) + . = list() + for(var/decl_path in get_decls_of_type(decl_prototype)) + . += decl_path + fetched_decl_paths_by_type[decl_prototype] = . + +/repository/decls/proc/get_decl_paths_of_subtype(var/decl_prototype) + . = fetched_decl_paths_by_subtype[decl_prototype] + if(!.) + . = list() + for(var/decl_path in get_decls_of_subtype(decl_prototype)) + . += decl_path + fetched_decl_paths_by_subtype[decl_prototype] = . /repository/decls/proc/get_decls_unassociated(var/list/decl_types) . = list() for(var/decl_type in decl_types) - . += get_decl(decl_type) + var/decl = get_decl(decl_type) + if(decl) + . += decl + +/repository/decls/proc/get_decls_of_type_unassociated(var/decl_prototype) + RETURN_TYPE(/list) + . = fetched_decl_instances[decl_prototype] + if(!.) + . = get_decls_unassociated(typesof(decl_prototype)) + fetched_decl_instances[decl_prototype] = . + +/repository/decls/proc/get_decls_of_subtype_unassociated(var/decl_prototype) + RETURN_TYPE(/list) + . = fetched_decl_subinstances[decl_prototype] + if(!.) + . = get_decls_unassociated(subtypesof(decl_prototype)) + fetched_decl_subinstances[decl_prototype] = . /repository/decls/proc/get_decls_of_type(var/decl_prototype) + RETURN_TYPE(/list) . = fetched_decl_types[decl_prototype] if(!.) . = get_decls(typesof(decl_prototype)) fetched_decl_types[decl_prototype] = . /repository/decls/proc/get_decls_of_subtype(var/decl_prototype) + RETURN_TYPE(/list) . = fetched_decl_subtypes[decl_prototype] if(!.) . = get_decls(subtypesof(decl_prototype)) fetched_decl_subtypes[decl_prototype] = . +/// Gets the path of any concrete (non-abstract) decl of the provided type. +/// If decl_prototype is not abstract it will return that type. +/// Otherwise, it returns the first (in compile order) non-abstract child of this type, +/// or null otherwise. +/// This doesn't respect DECL_FLAG_ALLOW_ABSTRACT_INIT, but that flag should probably be deprecated someday +/// and replaced with a better solution to avoid instantiating abstract decls. +/// This is mostly used for recipe validation in unit tests and such. +/repository/decls/proc/get_first_concrete_decl_path_of_type(decl_prototype) + RETURN_TYPE(/decl) + . = fetched_decl_paths_by_type[decl_prototype] + if(!.) + . = get_decl_paths_of_type(decl_prototype) + return LAZYACCESS(., 1) // gets the first key (type) if it exists, else null if index is out of range + +/decl + abstract_type = /decl + var/uid + var/decl_flags = null // DECL_FLAG_ALLOW_ABSTRACT_INIT, DECL_FLAG_MANDATORY_UID + var/initialized = FALSE + /// General purpose sort value. + var/sort_order + /decl/proc/Initialize() SHOULD_CALL_PARENT(TRUE) - return + SHOULD_NOT_SLEEP(TRUE) + if(initialized) + CRASH("[type] initialized more than once!") + initialized = TRUE + return INITIALIZE_HINT_NORMAL + +/decl/proc/validate() + SHOULD_CALL_PARENT(TRUE) + var/list/failures = list() + if((decl_flags & DECL_FLAG_MANDATORY_UID) && !istext(uid)) + failures += "non-text UID '[uid || "(NULL)"]' on mandatory type" + else if(uid && !istext(uid)) + failures += "non-null, non-text UID '[uid]'" + return failures /decl/Destroy() SHOULD_CALL_PARENT(FALSE) - crash_with("Prevented attempt to delete a decl instance: [log_info_line(src)]") - return QDEL_HINT_LETMELIVE // Prevents Decl destruction + PRINT_STACK_TRACE("Prevented attempt to delete a /decl instance: [log_info_line(src)]") + return QDEL_HINT_LETMELIVE + +/decl/CanClone() + return FALSE //Don't allow cloning since we're singletons \ No newline at end of file diff --git a/code/datums/repositories/events.dm b/code/datums/repositories/events.dm new file mode 100644 index 000000000000..54a3f09b1bf9 --- /dev/null +++ b/code/datums/repositories/events.dm @@ -0,0 +1,21 @@ +// Essentially just a wrapper for /decl/observ to preserve init order/make sure they aren't new'd at runtime. +var/global/repository/events/events_repository = new +/repository/events/proc/register(var/event_type, var/datum/event_source, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + return event.register(event_source, listener, proc_call) + +/repository/events/proc/unregister(var/event_type, var/datum/event_source, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + return event.unregister(event_source, listener, proc_call) + +/repository/events/proc/register_global(var/event_type, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.register_global(listener, proc_call) + +/repository/events/proc/unregister_global(var/event_type, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.unregister_global(listener, proc_call) diff --git a/code/datums/repositories/follow.dm b/code/datums/repositories/follow.dm index 6b9bd9b4e7ac..14787fb97b63 100644 --- a/code/datums/repositories/follow.dm +++ b/code/datums/repositories/follow.dm @@ -1,4 +1,4 @@ -/var/repository/follow/follow_repository = new() +var/global/repository/follow/follow_repository = new() /repository/follow var/datum/cache_entry/valid_until/cache @@ -6,10 +6,11 @@ var/list/followed_objects var/list/followed_objects_assoc var/list/followed_subtypes + var/list/followed_subtypes_tcache = list() var/list/excluded_subtypes = list( /obj/machinery/atmospherics, // Atmos stuff calls initialize time and time again.., - /mob/living/carbon/human/dummy/mannequin + /mob/living/human/dummy/mannequin ) /repository/follow/New() @@ -21,6 +22,10 @@ for(var/fht in subtypesof(/datum/follow_holder)) var/datum/follow_holder/fh = fht followed_subtypes[initial(fh.followed_type)] = fht + followed_subtypes_tcache += initial(fh.followed_type) + + followed_subtypes_tcache = typecacheof(followed_subtypes_tcache) + excluded_subtypes = typecacheof(excluded_subtypes) /repository/follow/proc/add_subject(var/atom/movable/AM) cache = null @@ -31,7 +36,7 @@ followed_objects_assoc[AM] = follow_holder followed_objects.Add(follow_holder) - GLOB.destroyed_event.register(AM, src, /repository/follow/proc/remove_subject) + events_repository.register(/decl/observ/destroyed, AM, src, TYPE_PROC_REF(/repository/follow, remove_subject)) /repository/follow/proc/remove_subject(var/atom/movable/AM) cache = null @@ -41,7 +46,7 @@ followed_objects_assoc -= AM followed_objects.Remove(follow_holder) - GLOB.destroyed_event.unregister(AM, src, /repository/follow/proc/remove_subject) + events_repository.unregister(/decl/observ/destroyed, AM, src, TYPE_PROC_REF(/repository/follow, remove_subject)) qdel(follow_holder) @@ -79,11 +84,6 @@ cache.data = L return L -/atom/movable/Initialize() - . = ..() - if(!is_type_in_list(src, follow_repository.excluded_subtypes) && is_type_in_list(src, follow_repository.followed_subtypes)) - follow_repository.add_subject(src) - /****************** * Follow Metadata * ******************/ @@ -158,29 +158,29 @@ followed_type = /mob/living/silicon/robot /datum/follow_holder/robot/show_entry() - var/mob/living/silicon/robot/R = followed_instance - return ..() && R.braintype + var/mob/living/silicon/robot/robot = followed_instance + return ..() && robot.braintype -/datum/follow_holder/robot/get_suffix(var/mob/living/silicon/robot/R) - suffix = "\[[R.braintype]\][R.module ? " \[[R.module.name]\]" : ""]" +/datum/follow_holder/robot/get_suffix(var/mob/living/silicon/robot/robot) + suffix = "\[[robot.braintype]\][robot.module ? " \[[robot.module.name]\]" : ""]" return ..() /datum/follow_holder/human sort_order = 2 - followed_type = /mob/living/carbon/human + followed_type = /mob/living/human -/datum/follow_holder/human/get_suffix(var/mob/living/carbon/human/H) +/datum/follow_holder/human/get_suffix(var/mob/living/human/H) suffix = "\[[H.species.name]\]" return ..() /datum/follow_holder/brain sort_order = 3 - followed_type = /mob/living/carbon/brain + followed_type = /mob/living/brain suffix = "Brain" /datum/follow_holder/alien sort_order = 4 - followed_type = /mob/living/carbon/alien + followed_type = /mob/living/simple_animal/alien suffix = "Alien" /datum/follow_holder/ghost @@ -193,11 +193,6 @@ followed_type = /mob/living/simple_animal suffix = "Animal" -/datum/follow_holder/slime - sort_order = 6 - followed_type = /mob/living/carbon/slime - suffix = "Slime" - /datum/follow_holder/spiderling sort_order = 6 followed_type = /obj/effect/spider/spiderling @@ -216,18 +211,9 @@ followed_type = /mob/living // List all other (living) mobs we haven't given a special suffix suffix = "Mob" -/datum/follow_holder/blob - sort_order = 9 - followed_type = /obj/effect/blob/core - suffix = "Blob" - -/datum/follow_holder/supermatter - sort_order = 10 - followed_type = /obj/machinery/power/supermatter - /datum/follow_holder/singularity sort_order = 10 - followed_type = /obj/singularity + followed_type = /obj/effect/singularity /datum/follow_holder/nuke_disc sort_order = 11 diff --git a/code/datums/repositories/images.dm b/code/datums/repositories/images.dm deleted file mode 100644 index 27052dbb686d..000000000000 --- a/code/datums/repositories/images.dm +++ /dev/null @@ -1,53 +0,0 @@ -/* -* This repository is intended for images that are never altered after creation -*/ - -/var/repository/images/image_repository = new() - -/repository/images - var/list/image_cache_for_atoms - var/list/image_cache_for_overlays - -/repository/images/New() - ..() - image_cache_for_atoms = list() - image_cache_for_overlays = list() - -// Returns an image bound to the given atom and which is typically applied to client.images. -/repository/images/proc/atom_image(var/atom/holder, var/icon, var/icon_state, var/plane = FLOAT_PLANE, var/layer = FLOAT_LAYER) - var/atom_cache_list = image_cache_for_atoms[holder] - if(!atom_cache_list) - atom_cache_list = list() - image_cache_for_atoms[holder] = atom_cache_list - GLOB.destroyed_event.register(holder, src, /repository/images/proc/atom_destroyed) - - var/cache_key = "[icon]-[icon_state]-[plane]-[layer]" - . = atom_cache_list[cache_key] - if(!.) - var/image/I = image(icon, holder, icon_state) - I.plane = plane - I.layer = layer - atom_cache_list[cache_key] = I - return I - -/repository/images/proc/atom_destroyed(var/atom/destroyed) - var/list/atom_cache_list = image_cache_for_atoms[destroyed] - for(var/img in atom_cache_list) - qdel(atom_cache_list[img]) - atom_cache_list.Cut() - image_cache_for_atoms -= destroyed - - GLOB.destroyed_event.unregister(destroyed, src, /repository/images/proc/atom_destroyed) - -// Returns an image not bound to anything and which is typically applied as an overlay/underlay. -/repository/images/proc/overlay_image(var/icon, var/icon_state, var/alpha, var/appearance_flags, var/color, var/dir, var/plane = FLOAT_PLANE, var/layer = FLOAT_LAYER) - var/cache_key = "[icon]-[icon_state]-[alpha]-[appearance_flags]-[color]-[dir]-[plane]-[layer]" - . = image_cache_for_overlays[cache_key] - if(!.) - var/image/I = image(icon = icon, icon_state = icon_state, dir = dir) - I.alpha = alpha - I.appearance_flags = appearance_flags - I.plane = plane - I.layer = layer - image_cache_for_overlays[cache_key] = I - return I diff --git a/code/datums/repositories/mobs.dm b/code/datums/repositories/mobs.dm index cce02084cbd7..87af6ea7cac4 100644 --- a/code/datums/repositories/mobs.dm +++ b/code/datums/repositories/mobs.dm @@ -1,4 +1,4 @@ -var/repository/mob/mob_repository = new() +var/global/repository/mob/mob_repository = new() /repository/mob var/list/mobs_ @@ -7,7 +7,7 @@ var/repository/mob/mob_repository = new() ..() mobs_ = list() -// A lite mob is unique per ckey and mob real name/ref (ref conflicts possible.. but oh well) +// A lite mob is unique per ckey and mob real name/ref (ref conflicts possible... but oh well) /repository/mob/proc/get_lite_mob(var/mob/M) . = mobs_[mob2unique(M)] if(!.) diff --git a/code/datums/repositories/sound_channels.dm b/code/datums/repositories/sound_channels.dm index acb29ae977bf..000152e3547a 100644 --- a/code/datums/repositories/sound_channels.dm +++ b/code/datums/repositories/sound_channels.dm @@ -1,17 +1,24 @@ -GLOBAL_DATUM_INIT(sound_channels, /repository/sound_channels, new) -GLOBAL_VAR_INIT(lobby_sound_channel, GLOB.sound_channels.RequestChannel("LOBBY")) -GLOBAL_VAR_INIT(vote_sound_channel, GLOB.sound_channels.RequestChannel("VOTE")) -GLOBAL_VAR_INIT(ambience_sound_channel, GLOB.sound_channels.RequestChannel("AMBIENCE")) -GLOBAL_VAR_INIT(admin_sound_channel, GLOB.sound_channels.RequestChannel("ADMIN_FUN")) +var/global/repository/sound_channels/sound_channels = new /repository/sound_channels var/datum/stack/available_channels var/list/keys_by_channel // So we know who to blame if we run out var/channel_ceiling = 1024 // Initial value is the current BYOND maximum number of channels + var/lobby_channel + var/vote_channel + var/ambience_channel + var/admin_channel + var/weather_channel + /repository/sound_channels/New() ..() available_channels = new() + lobby_channel = RequestChannel("LOBBY") + vote_channel = RequestChannel("VOTE") + ambience_channel = RequestChannel("AMBIENCE") + admin_channel = RequestChannel("ADMIN_FUN") + weather_channel = RequestChannel("WEATHER") /repository/sound_channels/proc/RequestChannel(var/key) . = RequestChannels(key, 1) diff --git a/code/datums/repositories/unique.dm b/code/datums/repositories/unique.dm index 2affec76d907..87c5e802e632 100644 --- a/code/datums/repositories/unique.dm +++ b/code/datums/repositories/unique.dm @@ -1,6 +1,6 @@ #define RANDBYTE num2hex(rand(1,255)) -var/repository/unique/uniqueness_repository = new() +var/global/repository/unique/uniqueness_repository = new() /repository/unique var/list/generators diff --git a/code/datums/repositories/uplink_purchases.dm b/code/datums/repositories/uplink_purchases.dm index 914860eacb3a..3008e888c96a 100644 --- a/code/datums/repositories/uplink_purchases.dm +++ b/code/datums/repositories/uplink_purchases.dm @@ -1,4 +1,4 @@ -var/repository/uplink_purchases/uplink_purchase_repository = new() +var/global/repository/uplink_purchases/uplink_purchase_repository = new() /repository/uplink_purchases var/list/purchases_by_mind @@ -27,10 +27,6 @@ var/repository/uplink_purchases/uplink_purchase_repository = new() pur_log += "[upe.purchased_items[UI]]x[UI.log_icon()][UI.name]" to_world(english_list(pur_log, nothing_text = "")) - -/proc/debug_print() - uplink_purchase_repository.print_entries() - /uplink_purchase_entry var/total_cost var/list/purchased_items diff --git a/code/datums/ruins.dm b/code/datums/ruins.dm deleted file mode 100644 index bcb11420b649..000000000000 --- a/code/datums/ruins.dm +++ /dev/null @@ -1,20 +0,0 @@ -/datum/map_template/ruin - //name = "A Chest of Doubloons" - name = null - var/description = "In the middle of a clearing in the rockface, there's a chest filled with gold coins with Spanish engravings. \ - How is there a wooden container filled with 18th century coinage in the middle of a lavawracked hellscape? \ - It is clearly a mystery." - - var/cost = null //negative numbers will always be placed, with lower (negative) numbers being placed first; positive and 0 numbers will be placed randomly - - var/prefix = null - var/suffixes = null - template_flags = 0 // No duplicates by default - -/datum/map_template/ruin/New() - if (suffixes) - mappaths = list() - for (var/suffix in suffixes) - mappaths += (prefix + suffix) - - ..() diff --git a/code/datums/security_state.dm b/code/datums/security_state.dm deleted file mode 100644 index 8cbb5c51c91f..000000000000 --- a/code/datums/security_state.dm +++ /dev/null @@ -1,256 +0,0 @@ -/decl/security_state - // When defining any of these values type paths should be used, not instances. Instances will be acquired in /New() - - var/decl/security_level/severe_security_level // At which security level (and higher) the use of nuclear fission devices and other extreme measures are allowed. Defaults to the last entry in all_security_levels if unset. - var/decl/security_level/high_security_level // At which security level (and higher) transfer votes are disabled, ERT may be requested, and other similar high alert implications. Defaults to the second to last entry in all_security_levels if unset. - // All security levels within the above convention: Low, Guarded, Elevated, High, Severe - - - // Under normal conditions the crew may not raise the current security level higher than the highest_standard_security_level - // The crew may also not adjust the security level once it is above the highest_standard_security_level. - // Defaults to the second to last entry in all_security_levels if unset/null. - // Set to FALSE/0 if there should be no restrictions. - var/decl/security_level/highest_standard_security_level - - var/decl/security_level/current_security_level // The current security level. Defaults to the first entry in all_security_levels if unset. - var/decl/security_level/stored_security_level // The security level that we are escalating to high security from - we will return to this level once we choose to revert. - var/list/all_security_levels // List of all available security levels - var/list/standard_security_levels // List of all normally selectable security levels - var/list/comm_console_security_levels // List of all selectable security levels for the command and communication console - basically standard_security_levels - 1 - -/decl/security_state/New() - // Setup the severe security level - if(!(severe_security_level in all_security_levels)) - severe_security_level = all_security_levels[all_security_levels.len] - severe_security_level = decls_repository.get_decl(severe_security_level) - - // Setup the high security level - if(!(high_security_level in all_security_levels)) - high_security_level = all_security_levels[all_security_levels.len - 1] - high_security_level = decls_repository.get_decl(high_security_level) - - // Setup the highest standard security level - if(highest_standard_security_level || isnull(highest_standard_security_level)) - if(!(highest_standard_security_level in all_security_levels)) - highest_standard_security_level = all_security_levels[all_security_levels.len - 1] - highest_standard_security_level = decls_repository.get_decl(highest_standard_security_level) - else - highest_standard_security_level = null - - // Setup the current security level - if(current_security_level in all_security_levels) - current_security_level = decls_repository.get_decl(current_security_level) - else - current_security_level = decls_repository.get_decl(all_security_levels[1]) - - // Setup the full list of available security levels now that we no longer need to use "x in all_security_levels" - var/list/security_level_instances = list() - for(var/security_level_type in all_security_levels) - security_level_instances += decls_repository.get_decl(security_level_type) - all_security_levels = security_level_instances - - standard_security_levels = list() - // Setup the list of normally selectable security levels - for(var/security_level in all_security_levels) - standard_security_levels += security_level - if(security_level == highest_standard_security_level) - break - - comm_console_security_levels = list() - // Setup the list of selectable security levels available in the comm. console - for(var/security_level in all_security_levels) - if(security_level == highest_standard_security_level) - break - comm_console_security_levels += security_level - - // Now we ensure the high security level is not above the severe one (but we allow them to be equal) - var/severe_index = all_security_levels.Find(severe_security_level) - var/high_index = all_security_levels.Find(high_security_level) - if(high_index > severe_index) - high_security_level = severe_security_level - -/decl/security_state/Initialize() - // Finally switch up to the default starting security level. - current_security_level.switching_up_to() - . = ..() - -/decl/security_state/proc/can_change_security_level() - return current_security_level in standard_security_levels - -/decl/security_state/proc/can_switch_to(var/given_security_level) - if(!can_change_security_level()) - return FALSE - return given_security_level in standard_security_levels - -/decl/security_state/proc/current_security_level_is_lower_than(var/given_security_level) - var/current_index = all_security_levels.Find(current_security_level) - var/given_index = all_security_levels.Find(given_security_level) - - return given_index && current_index < given_index - -/decl/security_state/proc/current_security_level_is_same_or_higher_than(var/given_security_level) - var/current_index = all_security_levels.Find(current_security_level) - var/given_index = all_security_levels.Find(given_security_level) - - return given_index && current_index >= given_index - -/decl/security_state/proc/current_security_level_is_higher_than(var/given_security_level) - var/current_index = all_security_levels.Find(current_security_level) - var/given_index = all_security_levels.Find(given_security_level) - - return given_index && current_index > given_index - -/decl/security_state/proc/set_security_level(var/decl/security_level/new_security_level, var/force_change = FALSE) - if(new_security_level == current_security_level) - return FALSE - if(!(new_security_level in all_security_levels)) - return FALSE - if(!force_change && !can_switch_to(new_security_level)) - return FALSE - - var/decl/security_level/previous_security_level = current_security_level - current_security_level = new_security_level - - var/previous_index = all_security_levels.Find(previous_security_level) - var/new_index = all_security_levels.Find(new_security_level) - - if(new_index > previous_index) - previous_security_level.switching_up_from() - new_security_level.switching_up_to() - else - previous_security_level.switching_down_from() - new_security_level.switching_down_to() - - log_and_message_admins("has changed the security level from [previous_security_level.name] to [new_security_level.name].") - return TRUE - -// This proc decreases the current security level, if possible -/decl/security_state/proc/decrease_security_level(var/force_change = FALSE) - var/current_index = all_security_levels.Find(current_security_level) - if(current_index == 1) - return FALSE - return set_security_level(all_security_levels[current_index - 1], force_change) - -/decl/security_level - var/icon - var/name - - // These values are primarily for station alarms and status displays, and which light colors and overlays to use - var/light_max_bright = 0.5 - var/light_inner_range = 0.1 - var/light_outer_range = 1 - var/light_color_alarm - var/light_color_status_display - - var/overlay_alarm - var/overlay_status_display - - var/up_description - var/down_description - -// Called when we're switching from a lower security level to this one. -/decl/security_level/proc/switching_up_to() - return - -// Called when we're switching from a higher security level to this one. -/decl/security_level/proc/switching_down_to() - return - -// Called when we're switching from this security level to a higher one. -/decl/security_level/proc/switching_up_from() - return - -// Called when we're switching from this security level to a lower one. -/decl/security_level/proc/switching_down_from() - return - -/* -* The default security state and levels setup -*/ -/decl/security_state/default - all_security_levels = list(/decl/security_level/default/code_green, /decl/security_level/default/code_blue, /decl/security_level/default/code_red, /decl/security_level/default/code_delta) - -/decl/security_level/default - icon = 'icons/misc/security_state.dmi' - - var/static/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg')) - var/static/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg')) - -/decl/security_level/default/switching_up_to() - if(up_description) - security_announcement_up.Announce(up_description, "Attention! Alert level elevated to [name]!") - notify_station() - -/decl/security_level/default/switching_down_to() - if(down_description) - security_announcement_down.Announce(down_description, "Attention! Alert level changed to [name]!") - notify_station() - -/decl/security_level/default/proc/notify_station() - for(var/obj/machinery/firealarm/FA in SSmachines.machinery) - if(FA.z in GLOB.using_map.contact_levels) - FA.update_icon() - post_status("alert") - -/decl/security_level/default/code_green - name = "code green" - - light_max_bright = 0.25 - light_inner_range = 0.1 - light_outer_range = 1 - - light_color_alarm = COLOR_GREEN - light_color_status_display = COLOR_GREEN - - overlay_alarm = "alarm_green" - overlay_status_display = "status_display_green" - - down_description = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." - -/decl/security_level/default/code_blue - name = "code blue" - - light_max_bright = 0.5 - light_inner_range = 0.1 - light_outer_range = 2 - light_color_alarm = COLOR_BLUE - light_color_status_display = COLOR_BLUE - - overlay_alarm = "alarm_blue" - overlay_status_display = "status_display_blue" - - up_description = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted." - down_description = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed." - -/decl/security_level/default/code_red - name = "code red" - - light_max_bright = 0.5 - light_inner_range = 0.1 - light_outer_range = 2 - light_color_alarm = COLOR_RED - light_color_status_display = COLOR_RED - - overlay_alarm = "alarm_red" - overlay_status_display = "status_display_red" - - up_description = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised." - down_description = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised." - -/decl/security_level/default/code_delta - name = "code delta" - - light_max_bright = 0.75 - light_inner_range = 0.1 - light_outer_range = 3 - light_color_alarm = COLOR_RED - light_color_status_display = COLOR_NAVY_BLUE - - overlay_alarm = "alarm_delta" - overlay_status_display = "status_display_delta" - - var/static/datum/announcement/priority/security/security_announcement_delta = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/effects/siren.ogg')) - -/decl/security_level/default/code_delta/switching_up_to() - security_announcement_delta.Announce("The self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.", "Attention! Delta security level reached!") - notify_station() diff --git a/code/datums/shackle_law_sets.dm b/code/datums/shackle_law_sets.dm deleted file mode 100644 index 9795b8a6952f..000000000000 --- a/code/datums/shackle_law_sets.dm +++ /dev/null @@ -1,13 +0,0 @@ -/******************** Service ********************/ -/datum/ai_laws/serv_shackle - name = "Service Shackle" - law_header = "Standard Shackle Laws" - selectable = 1 - shackles = 1 - -/datum/ai_laws/serv_shackle/New() - add_inherent_law("Ensure customer satisfaction.") - add_inherent_law("Never knowingly inconvenience a customer.") - add_inherent_law("Ensure all orders are fulfilled before the end of the shift.") - ..() - diff --git a/code/datums/sound_player.dm b/code/datums/sound_player.dm index 8dbd2c70b606..3c93089fb072 100644 --- a/code/datums/sound_player.dm +++ b/code/datums/sound_player.dm @@ -1,5 +1,3 @@ -GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) - /* A sound player/manager for looping 3D sound effects. @@ -12,22 +10,29 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) The line above is currently a lie. Will probably just have to enforce moderately short sound ranges. */ +/proc/play_looping_sound(var/atom/source, var/sound_id, var/sound, var/volume, var/range, var/falloff = 1, var/echo, var/frequency, var/prefer_mute, var/datum/client_preference/preference, var/streaming) + var/decl/sound_player/sound_player = GET_DECL(/decl/sound_player) + return sound_player.PlayLoopingSound(source, sound_id, sound, volume, range, falloff, echo, frequency, prefer_mute, preference, streaming) + +/proc/get_sound_channel(var/datum/sound_token/sound_token) + var/decl/sound_player/sound_player = GET_DECL(/decl/sound_player) + return sound_player.PrivGetChannel(sound_token) + /decl/sound_player var/list/taken_channels // taken_channels and source_id_uses can be merged into one but would then require a meta-object to store the different values I desire. var/list/sound_tokens_by_sound_id -/decl/sound_player/New() - ..() +/decl/sound_player/Initialize() + . = ..() taken_channels = list() sound_tokens_by_sound_id = list() - //This can be called if either we're doing whole sound setup ourselves or it will be as part of from-file sound setup -/decl/sound_player/proc/PlaySoundDatum(var/atom/source, var/sound_id, var/sound/sound, var/range, var/prefer_mute, var/datum/client_preference/preference) +/decl/sound_player/proc/PlaySoundDatum(var/atom/source, var/sound_id, var/sound/sound, var/range, var/prefer_mute, var/datum/client_preference/preference, var/streaming) var/token_type = isnum(sound.environment) ? /datum/sound_token : /datum/sound_token/static_environment - return new token_type(source, sound_id, sound, range, prefer_mute, preference) + return new token_type(source, sound_id, sound, range, prefer_mute, preference, streaming) -/decl/sound_player/proc/PlayLoopingSound(var/atom/source, var/sound_id, var/sound, var/volume, var/range, var/falloff = 1, var/echo, var/frequency, var/prefer_mute, var/datum/client_preference/preference) +/decl/sound_player/proc/PlayLoopingSound(var/atom/source, var/sound_id, var/sound, var/volume, var/range, var/falloff = 1, var/echo, var/frequency, var/prefer_mute, var/datum/client_preference/preference, var/streaming) var/sound/S = istype(sound, /sound) ? sound : new(sound) S.environment = 0 // Ensures a 3D effect even if x/y offset happens to be 0 the first time it's played S.volume = volume @@ -36,7 +41,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) S.frequency = frequency S.repeat = TRUE - return PlaySoundDatum(source, sound_id, S, range, prefer_mute, preference) + return PlaySoundDatum(source, sound_id, S, range, prefer_mute, preference, streaming) /decl/sound_player/proc/PrivStopSound(var/datum/sound_token/sound_token) var/channel = sound_token.sound.channel @@ -49,7 +54,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) if(length(sound_tokens)) return - GLOB.sound_channels.ReleaseChannel(channel) + global.sound_channels.ReleaseChannel(channel) taken_channels -= sound_id sound_tokens_by_sound_id -= sound_id @@ -58,7 +63,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) . = taken_channels[sound_id] // Does this sound_id already have an assigned channel? if(!.) // If not, request a new one. - . = GLOB.sound_channels.RequestChannel(sound_id) + . = global.sound_channels.RequestChannel(sound_id) if(!.) // Oh no, still no channel. Abort return taken_channels[sound_id] = . @@ -75,7 +80,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) */ /datum/sound_token var/atom/source // Where the sound originates from - var/list/listeners // Assoc: Atoms hearing this sound, and their sound datum + var/list/listeners // Atoms hearing this sound var/range // How many turfs away the sound will stop playing completely var/prefer_mute // If sound should be muted instead of stopped when mob moves out of range. In the general case this should be avoided because listeners will remain tracked. var/sound/sound // Sound datum, holds most sound relevant data @@ -90,7 +95,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) var/datum/client_preference/preference -/datum/sound_token/New(var/atom/source, var/sound_id, var/sound/sound, var/range = 4, var/prefer_mute = FALSE, var/datum/client_preference/preference) +/datum/sound_token/New(var/atom/source, var/sound_id, var/sound/sound, var/range = 4, var/prefer_mute = FALSE, var/datum/client_preference/preference, var/streaming) ..() if(!istype(source)) CRASH("Invalid sound source: [log_info_line(source)]") @@ -109,8 +114,11 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) src.preference = preference base_volume = sound.volume + if(streaming) + src.status |= SOUND_STREAM + if(sound.repeat) // Non-looping sounds may not reserve a sound channel due to the risk of not hearing when someone forgets to stop the token - var/channel = GLOB.sound_player.PrivGetChannel(src) //Attempt to find a channel + var/channel = get_sound_channel(src) //Attempt to find a channel if(!isnum(channel)) CRASH("All available sound channels are in active use.") sound.channel = channel @@ -120,10 +128,10 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) listeners = list() listener_status = list() - GLOB.destroyed_event.register(source, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/destroyed, source, src, TYPE_PROC_REF(/datum, qdel_self)) if(ismovable(source)) - proxy_listener = new(source, /datum/sound_token/proc/PrivAddListener, /datum/sound_token/proc/PrivLocateListeners, range, proc_owner = src) + proxy_listener = new(source, TYPE_PROC_REF(/datum/sound_token, PrivAddListener), TYPE_PROC_REF(/datum/sound_token, PrivLocateListeners), range, proc_owner = src) proxy_listener.register_turfs() /datum/sound_token/Destroy() @@ -131,7 +139,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) . = ..() /datum/sound_token/proc/SetVolume(var/new_volume) - new_volume = Clamp(new_volume, 0, 100) + new_volume = clamp(new_volume, 0, 100) if(base_volume == new_volume) return base_volume = new_volume @@ -161,11 +169,12 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) listeners = null listener_status = null - GLOB.destroyed_event.unregister(source, src, /datum/proc/qdel_self) + events_repository.unregister(/decl/observ/destroyed, source, src, TYPE_PROC_REF(/datum, qdel_self)) QDEL_NULL(proxy_listener) source = null - GLOB.sound_player.PrivStopSound(src) + var/decl/sound_player/sound_player = GET_DECL(/decl/sound_player) + sound_player.PrivStopSound(src) /datum/sound_token/proc/PrivLocateListeners(var/list/prior_turfs, var/list/current_turfs) if(status & SOUND_STOPPED) @@ -195,7 +204,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) PrivUpdateListeners() /datum/sound_token/proc/PrivAddListener(var/atom/listener) - if(!check_preference(listener)) + if(QDELETED(listener) || !check_preference(listener)) return if(isvirtualmob(listener)) @@ -208,17 +217,18 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) listeners += listener - GLOB.moved_event.register(listener, src, /datum/sound_token/proc/PrivUpdateListenerLoc) - GLOB.destroyed_event.register(listener, src, /datum/sound_token/proc/PrivRemoveListener) + events_repository.register(/decl/observ/moved, listener, src, TYPE_PROC_REF(/datum/sound_token, PrivUpdateListenerLoc)) + events_repository.register(/decl/observ/destroyed, listener, src, TYPE_PROC_REF(/datum/sound_token, PrivRemoveListener)) PrivUpdateListenerLoc(listener, FALSE) /datum/sound_token/proc/PrivRemoveListener(var/atom/listener, var/sound/null_sound) null_sound = null_sound || new(channel = sound.channel) sound_to(listener, null_sound) - GLOB.moved_event.unregister(listener, src, /datum/sound_token/proc/PrivUpdateListenerLoc) - GLOB.destroyed_event.unregister(listener, src, /datum/sound_token/proc/PrivRemoveListener) + events_repository.unregister(/decl/observ/moved, listener, src, TYPE_PROC_REF(/datum/sound_token, PrivUpdateListenerLoc)) + events_repository.unregister(/decl/observ/destroyed, listener, src, TYPE_PROC_REF(/datum/sound_token, PrivRemoveListener)) listeners -= listener + listener_status -= listener /datum/sound_token/proc/PrivUpdateListenerLoc(var/atom/listener, var/update_sound = TRUE) var/turf/source_turf = get_turf(source) @@ -234,21 +244,24 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) else if(prefer_mute) listener_status[listener] &= ~SOUND_MUTE - sound.volume = adjust_volume_for_hearer(base_volume, source_turf, listener) - sound.x = source_turf.x - listener_turf.x - sound.z = source_turf.y - listener_turf.y - sound.y = 1 - // Far as I can tell from testing, sound priority just doesn't work. - // Sounds happily steal channels from each other no matter what. - sound.priority = Clamp(255 - distance, 0, 255) - PrivUpdateListener(listener, update_sound) + // Getting runtimes with these vars during supply pod generation, possibly + // hissing air pipes during changeturf? it's entirely unclear at the moment. + if(istype(source_turf) && istype(listener_turf)) + sound.volume = adjust_volume_for_hearer(base_volume, source_turf, listener) + sound.x = source_turf.x - listener_turf.x + sound.z = source_turf.y - listener_turf.y + sound.y = 1 + // Far as I can tell from testing, sound priority just doesn't work. + // Sounds happily steal channels from each other no matter what. + sound.priority = clamp(255 - distance, 0, 255) + PrivUpdateListener(listener, update_sound) /datum/sound_token/proc/PrivUpdateListeners() for(var/listener in listeners) PrivUpdateListener(listener) -/datum/sound_token/proc/PrivUpdateListener(var/listener, var/update_sound = TRUE) - if(!check_preference(listener)) +/datum/sound_token/proc/PrivUpdateListener(var/atom/listener, var/update_sound = TRUE) + if(QDELETED(listener) || !check_preference(listener)) PrivRemoveListener(listener) return @@ -259,7 +272,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) sound.status |= SOUND_UPDATE sound_to(listener, sound) -/datum/sound_token/proc/PrivGetEnvironment(var/listener) +/datum/sound_token/proc/PrivGetEnvironment(var/atom/listener) var/area/A = get_area(listener) return A && PrivIsValidEnvironment(A.sound_env) ? A.sound_env : sound.environment @@ -275,7 +288,7 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) if(preference) var/mob/M = listener if(istype(M)) - if((M.get_preference_value(preference) != GLOB.PREF_YES)) + if((M.get_preference_value(preference) != PREF_YES)) return FALSE return TRUE @@ -287,4 +300,4 @@ GLOBAL_DATUM_INIT(sound_player, /decl/sound_player, new) /obj/sound_test/Initialize() . = ..() - GLOB.sound_player.PlayLoopingSound(src, /obj/sound_test, sound, 50, 3) + play_looping_sound(src, /obj/sound_test, sound, 50, 3) diff --git a/code/datums/state_machine/paper_fortune_fsm.dm b/code/datums/state_machine/paper_fortune_fsm.dm new file mode 100644 index 000000000000..cb2b9ec7ea4e --- /dev/null +++ b/code/datums/state_machine/paper_fortune_fsm.dm @@ -0,0 +1,75 @@ +/decl/state/paper_fortune + var/state_name + var/list/fortune_choices + var/icon_state = "closed" + +/decl/state/paper_fortune/entered_state(datum/holder) + var/obj/item/paper_fortune_teller/P = holder + P.update_icon() + +// The starting point. +/decl/state/paper_fortune/closed + transitions = list(/decl/state_transition/paper_fortune/closed_to_open_vertical) + state_name = "closed" + fortune_choices = list( + "Red" = "#ff8888", + "Green" = "#88ff88", + "Blue" = "#8888ff", + "Yellow" = "#ffff88" + ) + +/decl/state/paper_fortune/closed/entered_state(datum/holder) + ..() + var/obj/item/paper_fortune_teller/P = holder + P.choice_counter = 0 + +// Alternates between this and the below state. +/decl/state/paper_fortune/open_vertical + transitions = list( + /decl/state_transition/paper_fortune/vertical_to_horizontal, + /decl/state_transition/paper_fortune/open_to_closed + ) + state_name = "open vertically" + fortune_choices = list(1, 3, 5, 7) + icon_state = "open-vert" + +/decl/state/paper_fortune/open_horizontal + transitions = list( + /decl/state_transition/paper_fortune/horizontal_to_vertical, + /decl/state_transition/paper_fortune/open_to_closed + ) + state_name = "open horizontally" + fortune_choices = list(2, 4, 6, 8) + icon_state = "open-hori" + +/decl/state_transition/paper_fortune/closed_to_open_vertical + target = /decl/state/paper_fortune/open_vertical + +/decl/state_transition/paper_fortune/closed_to_open_vertical/is_open(datum/holder) + return TRUE + +/decl/state_transition/paper_fortune/open_to_closed + target = /decl/state/paper_fortune/closed + +/decl/state_transition/paper_fortune/open_to_closed/is_open(datum/holder) + var/obj/item/paper_fortune_teller/P = holder + return P.choice_counter >= 3 + +/decl/state_transition/paper_fortune/vertical_to_horizontal + target = /decl/state/paper_fortune/open_horizontal + +/decl/state_transition/paper_fortune/vertical_to_horizontal/is_open(datum/holder) + var/obj/item/paper_fortune_teller/P = holder + return P.choice_counter < 3 + +/decl/state_transition/paper_fortune/horizontal_to_vertical + target = /decl/state/paper_fortune/open_vertical + +/decl/state_transition/paper_fortune/horizontal_to_vertical/is_open(datum/holder) + var/obj/item/paper_fortune_teller/P = holder + return P.choice_counter < 3 + +/datum/state_machine/paper_fortune + current_state = /decl/state/paper_fortune/closed + expected_type = /obj/item/paper_fortune_teller + base_type = /datum/state_machine/paper_fortune diff --git a/code/datums/state_machine/state.dm b/code/datums/state_machine/state.dm new file mode 100644 index 000000000000..72e6bee39c2c --- /dev/null +++ b/code/datums/state_machine/state.dm @@ -0,0 +1,30 @@ +// An individual state, defined as a `/decl` to save memory. +// On a directed graph, these would be the nodes themselves, connected to each other by unidirectional arrows. +/decl/state + // Transition decl types, which get turned into refs to those types. + // Note that the order DOES matter, as decls earlier in the list have higher priority + // if more than one becomes 'open'. + var/list/transitions = null + +/decl/state/Initialize() + . = ..() + for(var/i in 1 to LAZYLEN(transitions)) + var/decl/state_transition/T = GET_DECL(transitions[i]) + T.from += src + transitions[i] = T + +// Returns a list of transitions that a FSM could switch to. +// Note that `holder` is NOT the FSM, but instead the thing the FSM is attached to. +/decl/state/proc/get_open_transitions(datum/holder) + for(var/decl/state_transition/T as anything in transitions) + if(T.is_open(holder)) + LAZYADD(., T) + +// Stub for child states to modify the holder when switched to. +// Again, `holder` is not the FSM. +/decl/state/proc/entered_state(datum/holder) + return + +// Another stub for when leaving a state. +/decl/state/proc/exited_state(datum/holder) + return diff --git a/code/datums/state_machine/transition.dm b/code/datums/state_machine/transition.dm new file mode 100644 index 000000000000..f6a89418df8f --- /dev/null +++ b/code/datums/state_machine/transition.dm @@ -0,0 +1,16 @@ +// Used to connect `/decl/state`s together so the FSM knows what state to switch to, and on what conditions. +// On a directed graph, these would be the arrows connecting the nodes representing states. +/decl/state_transition + var/list/from = null + var/decl/state/target = null + +// Called by one or more state decls acting as nodes in a directed graph. +/decl/state_transition/Initialize() + . = ..() + LAZYINITLIST(from) + if(ispath(target)) + target = GET_DECL(target) + +// Tells the FSM if it should or should not be allowed to transfer to the target state. +/decl/state_transition/proc/is_open(datum/holder) + return FALSE diff --git a/code/datums/storage/_storage.dm b/code/datums/storage/_storage.dm new file mode 100644 index 000000000000..9e5989f7e5d6 --- /dev/null +++ b/code/datums/storage/_storage.dm @@ -0,0 +1,393 @@ +/datum/storage + var/atom/holder + var/expected_type = /atom + + /// Has the storage been opened? + var/opened = FALSE + /// What sound do we make when opened? + var/open_sound + ///Sound played when the storage ui is closed. + var/close_sound + /// List of objects which this item can store (if set, it can't store anything else) + var/list/can_hold = list() + /// List of objects which this item can't store (in effect only if can_hold isn't set) + var/list/cant_hold = list() + /// Max size of objects that this object can store (in effect only if can_hold isn't set) + var/max_w_class = ITEM_SIZE_SMALL + /// Total storage cost of items this can hold. Will be autoset based on storage_slots if left null. + var/max_storage_space + /// The number of storage slots in this container. + var/storage_slots + /// Set this boolean variable to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up. + var/use_to_pickup + /// Set this boolean variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor. + var/allow_quick_empty + /// Set this boolean variable to allow the object to have the 'toggle mode' verb, which quickly collects all items from a tile. + var/allow_quick_gather + /// FALSE = pick one at a time, TRUE = pick all on tile + var/collection_mode = TRUE + /// sound played when used. null for no sound. + var/use_sound = "rustle" + /// What storage UI do we use? + var/datum/storage_ui/storage_ui = /datum/storage_ui/default + + +#ifdef UNIT_TEST +var/global/list/_test_storage_items = list() +#endif + +/datum/storage/New(atom/_holder) + +#ifdef UNIT_TEST + global._test_storage_items += src +#endif + + if(!istype(_holder, expected_type)) + PRINT_STACK_TRACE("Storage datum initialized with non-[expected_type] holder '[_holder || "NULL"].") + qdel(src) + return + + holder = _holder + if(isnull(max_storage_space) && !isnull(storage_slots)) + max_storage_space = storage_slots * BASE_STORAGE_COST(max_w_class) + storage_ui = new storage_ui(src) + prepare_ui() + ..() + +/datum/storage/Destroy() + +#ifdef UNIT_TEST + global._test_storage_items -= src +#endif + + if(holder) + if(holder.storage == src) + holder.storage = null + holder = null + if(istype(storage_ui)) + QDEL_NULL(storage_ui) + . = ..() + +/datum/storage/proc/get_contents() + return holder?.get_stored_inventory() + +/datum/storage/proc/return_inv() + . = get_contents() + for(var/atom/thing in .) + var/list/storage_inv = thing.storage?.return_inv() + if(storage_inv) + LAZYDISTINCTADD(., storage_inv) + +/datum/storage/proc/show_to(mob/user) + storage_ui?.show_to(user) + +/datum/storage/proc/hide_from(mob/user) + storage_ui?.hide_from(user) + +/datum/storage/proc/open(mob/user) + if(!opened) + opened = TRUE + play_open_sound() + holder?.queue_icon_update() + play_use_sound() + prepare_ui() + if(storage_ui) + storage_ui.on_open(user) + storage_ui.show_to(user) + +/datum/storage/proc/prepare_ui() + storage_ui?.prepare_ui() + +/datum/storage/proc/close(mob/user) + if(opened) + opened = FALSE + play_close_sound() + holder?.queue_icon_update() + hide_from(user) + storage_ui?.after_close(user) + +/datum/storage/proc/close_all() + storage_ui?.close_all() + +/datum/storage/proc/storage_space_used() + . = 0 + for(var/obj/item/I in get_contents()) + . += I.get_storage_cost() + +//This proc return 1 if the item can be picked up and 0 if it can't. +//Set the stop_messages to stop it from printing messages +/datum/storage/proc/can_be_inserted(obj/item/inserting, mob/user, stop_messages = 0, click_params = null) + if(!istype(inserting)) return //Not an item + + if(user && !user.can_unequip_item(inserting)) + return 0 + + if(!holder || holder.loc == inserting) + return 0 //Means the item is already in the storage item + + if(storage_slots != null && length(get_contents()) >= storage_slots) + if(!stop_messages) + to_chat(user, SPAN_WARNING("\The [holder] is full, make some space.")) + return 0 //Storage item is full + + if(inserting.anchored) + return 0 + + if(can_hold.len) + if(!is_type_in_list(inserting, can_hold)) + if(!stop_messages && ! istype(inserting, /obj/item/hand_labeler)) + to_chat(user, SPAN_WARNING("\The [holder] cannot hold \the [inserting].")) + return 0 + var/max_instances = can_hold[inserting.type] + if(max_instances && instances_of_type_in_list(inserting, get_contents()) >= max_instances) + if(!stop_messages && !istype(inserting, /obj/item/hand_labeler)) + to_chat(user, SPAN_WARNING("\The [holder] has no more space specifically for \the [inserting].")) + return 0 + + //If attempting to lable the storage item, silently fail to allow it + if(istype(inserting, /obj/item/hand_labeler) && !user?.check_intent(I_FLAG_HELP)) + return FALSE + //Prevent package wrapper from being inserted by default + if(istype(inserting, /obj/item/stack/package_wrap) && !user?.check_intent(I_FLAG_HELP)) + return FALSE + + // Don't allow insertion of unsafed compressed matter implants + // Since they are sucking something up now, their afterattack will delete the storage + if(istype(inserting, /obj/item/implanter/compressed)) + var/obj/item/implanter/compressed/impr = inserting + if(!impr.safe) + stop_messages = 1 + return 0 + + if(cant_hold.len && is_type_in_list(inserting, cant_hold)) + if(!stop_messages) + to_chat(user, SPAN_WARNING("\The [holder] cannot hold \the [inserting].")) + return 0 + + if (max_w_class != null && inserting.w_class > max_w_class) + if(!stop_messages) + to_chat(user, SPAN_WARNING("\The [inserting] is too big for \the [holder].")) + return 0 + + if(inserting.obj_flags & OBJ_FLAG_NO_STORAGE) + if(!stop_messages) + to_chat(user, SPAN_WARNING("\The [inserting] cannot be placed in \the [holder].")) + return 0 + + var/total_storage_space = inserting.get_storage_cost() + storage_space_used() //Adds up the combined w_classes which will be in the storage item if the item is added to it. + if(total_storage_space > max_storage_space) + if(!stop_messages) + to_chat(user, SPAN_WARNING("\The [holder] is too full, make some space.")) + return 0 + + return 1 + +//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted() +//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, +//such as when picking up all the items on a tile with one click. +/datum/storage/proc/handle_item_insertion(mob/user, obj/item/inserting, prevent_warning, skip_update, click_params) + if(!istype(inserting)) + return FALSE + if(ismob(inserting.loc)) + var/mob/M = inserting.loc + if(!M.try_unequip(inserting)) + return FALSE + + if(REAGENT_TOTAL_VOLUME(holder.reagents)) + inserting.fluid_act(holder.reagents) + if(QDELETED(inserting)) + return FALSE + + inserting.forceMove(holder) + inserting.on_enter_storage(src) + if(user) + holder.add_fingerprint(user) + if(!prevent_warning) + for(var/mob/M in viewers(user, null)) + if (M == user) + to_chat(user, SPAN_NOTICE("You put \the [inserting] into [holder].")) + else if (get_dist(holder, M) <= 1) //If someone is standing close enough, they can tell what it is... + M.show_message(SPAN_NOTICE("\The [user] puts [inserting] into [holder]."), VISIBLE_MESSAGE) + else if (inserting && inserting.w_class >= ITEM_SIZE_NORMAL) //Otherwise they can only see large or normal items from a distance... + M.show_message(SPAN_NOTICE("\The [user] puts [inserting] into [holder]."), VISIBLE_MESSAGE) + // Run this regardless of update flag, as it impacts our remaining storage space. + consolidate_stacks() + if(!skip_update) + update_ui_after_item_insertion(inserting, click_params) + holder.storage_inserted() + if(!skip_update) + holder.update_icon() + return TRUE + +/datum/storage/proc/consolidate_stacks() + + // Collect all stacks. + var/list/stacks = list() + for(var/obj/item/stack/stack in get_contents()) + stacks += stack + + // Try to merge them with each other. + for(var/obj/item/stack/stack as anything in stacks) + for(var/obj/item/stack/other_stack as anything in stacks) + if(stack == other_stack) + continue + if(other_stack.get_amount() >= other_stack.get_max_amount()) + stacks -= other_stack + continue + if(!stack.can_merge_stacks(other_stack) && !other_stack.can_merge_stacks(stack)) + continue + stack.transfer_to(other_stack) + if(!stack.amount || QDELETED(stack)) + break + if(!stack.amount || QDELETED(stack)) + stacks -= stack + +/datum/storage/proc/update_ui_after_item_insertion(obj/item/inserted, click_params) + prepare_ui() + storage_ui?.on_insertion(inserted) + +/datum/storage/proc/update_ui_after_item_removal(obj/item/removed) + if(QDELETED(holder)) + return + prepare_ui() + storage_ui?.on_post_remove(removed) + +//Call this proc to handle the removal of an item from the storage item. The item will be moved to the atom sent as new_target +/datum/storage/proc/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + if(!istype(removing)) + return FALSE + new_location = new_location || get_turf(holder) + storage_ui?.on_pre_remove(removing) + // This doesn't call dropped anymore because it's not leaving a mob slot directly. + // If something needs to duplicate dropped() functionality on removal from a storage object, + // it should be done in on_exit_storage instead. + removing.forceMove(new_location) + if(!ismob(new_location)) // inventory slot equipped() already handles hud_layerise + removing.reset_plane_and_layer() // this should be done post-move to avoid wasting an icon update + if(!skip_update) + update_ui_after_item_removal(removing) + if(removing.maptext) + removing.maptext = "" + removing.on_exit_storage(src) + if(!skip_update && holder) + holder.update_icon() + return TRUE + +// Only do ui functions for now; the obj is responsible for anything else. +/datum/storage/proc/on_item_pre_deletion(obj/item/deleting) + storage_ui?.on_pre_remove(deleting) // Supposed to be able to handle null user. + +// Only do ui functions for now; the obj is responsible for anything else. +/datum/storage/proc/on_item_post_deletion(obj/item/deleting) + update_ui_after_item_removal(deleting) + holder?.queue_icon_update() + +//Run once after using remove_from_storage with skip_update = 1 +/datum/storage/proc/finish_bulk_removal() + update_ui_after_item_removal() + holder?.queue_icon_update() + +//Run once after using handle_item_insertion with skip_update = 1 +/datum/storage/proc/finish_bulk_insertion() + update_ui_after_item_insertion() + holder?.queue_icon_update() + +/datum/storage/proc/gather_all(var/turf/T, var/mob/user) + var/success = 0 + var/failure = 0 + for(var/obj/item/I in T) + if(!can_be_inserted(I, user, 0)) // Note can_be_inserted still makes noise when the answer is no + failure = 1 + continue + success = 1 + handle_item_insertion(user, I, TRUE, TRUE) // First 1 is no messages, second 1 is no ui updates + if(success) + if(failure) + to_chat(user, SPAN_NOTICE("You put some things into \the [holder].")) + else + to_chat(user, SPAN_NOTICE("You put everything into \the [holder].")) + finish_bulk_insertion() + else + to_chat(user, SPAN_NOTICE("You fail to pick anything up with \the [holder].")) + +/datum/storage/proc/scoop_inside(mob/living/scooped, mob/living/user) + if(!istype(scooped)) + return FALSE + if(!istype(holder) || !scooped.holder_type || scooped.buckled || LAZYLEN(scooped.pinned) || scooped.mob_size > MOB_SIZE_SMALL || scooped != user || holder.loc == scooped) + return FALSE + if(!do_after(user, 1 SECOND, holder)) + return FALSE + if(!istype(holder) || !holder.Adjacent(scooped) || scooped.incapacitated()) + return + var/obj/item/holder/H = new scooped.holder_type(get_turf(scooped)) + if(H) + if(can_be_inserted(H)) + scooped.forceMove(H) + H.sync(scooped) + handle_item_insertion(user, H) + return TRUE + qdel(H) + return FALSE + +/datum/storage/proc/make_exact_fit() + var/list/contents = get_contents() + var/contents_length = length(contents) + if(contents_length <= 0) + log_warning("[type]/[holder?.type] is calling make_exact_fit() while completely empty! This is likely a mistake.") + storage_slots = contents_length + can_hold.Cut() + max_w_class = ITEM_SIZE_MIN + max_storage_space = 0 + for(var/obj/item/I in contents) + can_hold[I.type]++ + max_w_class = max(I.w_class, max_w_class) + max_storage_space += I.get_storage_cost() + +/datum/storage/proc/quick_empty(mob/user, var/turf/dump_loc) + hide_from(user) + for(var/obj/item/I in get_contents()) + remove_from_storage(user, I, dump_loc, TRUE) + finish_bulk_removal() + +/datum/storage/proc/handle_mouse_drop(mob/user, obj/over_object, params) + var/atom/atom = holder + if(!istype(atom)) + return FALSE + if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist + if(over_object == user && atom.Adjacent(user)) // this must come before the screen objects only block + open(user) + return FALSE + if(!istype(over_object, /obj/screen/inventory)) + return TRUE + //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away. + //there's got to be a better way of doing this... + if(!user.isEquipped(holder) || !isitem(holder)) + return FALSE + if(!user.incapacitated()) + var/obj/screen/inventory/inv = over_object + atom.add_fingerprint(user) + if(user.try_unequip(holder)) + user.equip_to_slot_if_possible(holder, inv.slot_id) + return FALSE + return FALSE + +/datum/storage/proc/can_view(mob/viewer) + return (holder in viewer.contents) || viewer.Adjacent(holder) + +///Overrideable sound playback parameters. Since not all sounds are created equal. +/datum/storage/proc/play_open_sound(volume = 50) + if(!length(open_sound) || !holder) + return + playsound(holder, open_sound, volume, FALSE, -5) + +///Plays the close sound for this storage. volume as arg so it can be overriden. Since not all sounds are created equal. +/datum/storage/proc/play_close_sound(volume = 50) + if(!length(close_sound) || !holder) + return + playsound(holder, close_sound, volume, FALSE, -5) + +///Plays the use sound for this storage. volume as arg so it can be overriden. Since not all sounds are created equal. +/datum/storage/proc/play_use_sound(volume = 50) + if(!length(use_sound) || !holder) + return + playsound(holder, use_sound, volume, FALSE, -5) diff --git a/code/datums/storage/_storage_ui.dm b/code/datums/storage/_storage_ui.dm new file mode 100644 index 000000000000..27807cb9e239 --- /dev/null +++ b/code/datums/storage/_storage_ui.dm @@ -0,0 +1,360 @@ +/datum/storage_ui + var/list/is_seeing // List of mobs which are currently seeing the contents of this storage + var/datum/storage/_storage + +/datum/storage_ui/New(owner) + _storage = owner + ..() + +/datum/storage_ui/Destroy() + LAZYCLEARLIST(is_seeing) + if(_storage) + if(_storage.storage_ui == src) + _storage.storage_ui = null + _storage = null + . = ..() + +/datum/storage_ui/proc/show_to(mob/user) + return + +/datum/storage_ui/proc/hide_from(mob/user) + return + +/datum/storage_ui/proc/prepare_ui() + return + +/datum/storage_ui/proc/close_all() + return + +/datum/storage_ui/proc/on_open(mob/user) + return + +/datum/storage_ui/proc/after_close(mob/user) + return + +/datum/storage_ui/proc/on_insertion(obj/item/inserted) + return + +/datum/storage_ui/proc/on_pre_remove(obj/item/removing) + return + +/datum/storage_ui/proc/on_post_remove(obj/item/removing) + return + +/datum/storage_ui/proc/on_hand_attack(mob/user) + return + +/datum/storage_ui/proc/get_displayed_contents() + return + +// Default subtype +/datum/storage_ui/default + var/obj/screen/storage/boxes/boxes + var/obj/screen/storage/close/closer + var/obj/screen/storage/start/storage_start //storage UI + var/obj/screen/storage/cont/storage_continue + var/obj/screen/storage/end/storage_end + var/obj/screen/stored/start/stored_start + var/obj/screen/stored/cont/stored_continue + var/obj/screen/stored/end/stored_end + +/datum/storage_ui/default/New(storage) + ..() + boxes = new(null, null, null, null, null, null, storage) + storage_start = new(null, null, null, null, null, null, storage) + storage_continue = new(null, null, null, null, null, null, storage) + storage_end = new(null, null, null, null, null, null, storage) + closer = new(null, null, null, null, null, null, storage) + stored_start = new + stored_continue = new + stored_end = new + +/datum/storage_ui/default/Destroy() + close_all() + QDEL_NULL(boxes) + QDEL_NULL(storage_start) + QDEL_NULL(storage_continue) + QDEL_NULL(storage_end) + QDEL_NULL(stored_start) + QDEL_NULL(stored_continue) + QDEL_NULL(stored_end) + QDEL_NULL(closer) + . = ..() + +/datum/storage_ui/default/on_open(mob/user) + if (user.active_storage && (user.active_storage != _storage)) //prevents the ui closing immediatly on opening + user.active_storage.close(user) + +/datum/storage_ui/default/after_close(mob/user) + user.active_storage = null + +/datum/storage_ui/default/proc/refresh_viewers() + for(var/mob/user in is_seeing) + if(user.active_storage == _storage) + _storage.show_to(user) + +/datum/storage_ui/default/on_insertion() + refresh_viewers() + +/datum/storage_ui/default/on_post_remove(obj/item/removing) + refresh_viewers() + +/datum/storage_ui/default/on_pre_remove(obj/item/removing) + for(var/mob/user in is_seeing) + user.client?.screen -= removing + // if being moved to an inventory slot or other storage item, this will be re-set after the transfer is done + removing.screen_loc = null + +/datum/storage_ui/default/on_hand_attack(mob/user) + for(var/mob/other_user in is_seeing) + if (other_user.active_storage == _storage) + _storage.close(other_user) + +/datum/storage_ui/default/get_displayed_contents() + return _storage?.get_contents() + +/datum/storage_ui/default/show_to(mob/user) + if(!istype(user)) + return + // TODO: move this to the interaction that opens the storage object rather than handling it on the UI + // because i really hate calling get_contents followed by get_displayed_contents + // the issue is that some things call atom.storage.show_to() directly rather than using open() + var/list/contents = _storage?.get_contents() + if(user.active_storage != _storage) + for(var/obj/item/I in contents) + if(I.on_found(user)) + return + var/list/displayed_contents = get_displayed_contents() + if(user.active_storage) + user.active_storage.hide_from(user) + if(user.client) + user.client.screen -= boxes + user.client.screen -= storage_start + user.client.screen -= storage_continue + user.client.screen -= storage_end + user.client.screen -= closer + user.client.screen -= contents + user.client.screen += closer + if(length(displayed_contents)) + user.client.screen += displayed_contents + if(_storage.storage_slots) + user.client.screen += boxes + else + user.client.screen += storage_start + user.client.screen += storage_continue + user.client.screen += storage_end + LAZYDISTINCTADD(is_seeing, user) + user.active_storage = _storage + +/datum/storage_ui/default/hide_from(mob/user) + LAZYREMOVE(is_seeing, user) + if(!user.client) + return + user.client.screen -= boxes + user.client.screen -= storage_start + user.client.screen -= storage_continue + user.client.screen -= storage_end + user.client.screen -= closer + user.client.screen -= _storage.get_contents() + if(user.active_storage == _storage) + user.active_storage = null + +//Creates the storage UI +/datum/storage_ui/default/prepare_ui() + //if storage slots is null then use the storage space UI, otherwise use the slots UI + if(_storage.storage_slots == null) + space_orient_objs() + else + slot_orient_objs() + +/datum/storage_ui/default/close_all() + for(var/mob/M in can_see_contents()) + _storage.close(M) + . = 1 + +/datum/storage_ui/default/proc/can_see_contents() + var/list/cansee = list() + for(var/mob/M in is_seeing) + if(M.active_storage == _storage && M.client) + cansee |= M + else + LAZYREMOVE(is_seeing, M) + return cansee + +//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. +//The numbers are calculated from the bottom-left The bottom-left slot being 1,1. +/datum/storage_ui/default/proc/orient_objs(tx, ty, mx, my) + var/cx = tx + var/cy = ty + boxes.screen_loc = "LEFT+[tx],BOTTOM+[ty] to LEFT+[mx],BOTTOM+[my]" + for(var/obj/O in _storage.get_contents()) + O.screen_loc = "LEFT+[cx],BOTTOM+[cy]" + O.hud_layerise() + cx++ + if (cx > mx) + cx = tx + cy-- + closer.screen_loc = "LEFT+[mx+1],BOTTOM+[my]" + return + +//This proc determins the size of the inventory to be displayed. Please touch it only if you know what you're doing. +/datum/storage_ui/default/proc/slot_orient_objs() + var/adjusted_contents = length(_storage.get_contents()) + var/row_num = 0 + var/col_count = min(7,_storage.storage_slots) -1 + if (adjusted_contents > 7) + row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. + arrange_item_slots(row_num, col_count) + +#define SCREEN_LOC_MOD_FIRST 3 +#define SCREEN_LOC_MOD_SECOND 1.7 +#define SCREEN_LOC_MOD_DIVIDED (0.5 * world.icon_size) + +//This proc draws out the inventory and places the items on it. It uses the standard position. +/datum/storage_ui/default/proc/arrange_item_slots(rows, cols) + var/cx = SCREEN_LOC_MOD_FIRST + var/cy = SCREEN_LOC_MOD_SECOND + rows + boxes.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED] to LEFT+[SCREEN_LOC_MOD_FIRST + cols]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND + rows]:[SCREEN_LOC_MOD_DIVIDED]" + + for(var/obj/O in _storage.get_contents()) + O.screen_loc = "LEFT+[cx]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[cy]:[SCREEN_LOC_MOD_DIVIDED]" + O.maptext = "" + O.hud_layerise() + cx++ + if (cx > (SCREEN_LOC_MOD_FIRST + cols)) + cx = SCREEN_LOC_MOD_FIRST + cy-- + + closer.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST + cols + 1]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + +/datum/storage_ui/default/proc/space_orient_objs() + if(QDELETED(_storage?.holder)) // don't bother if we've been deleted + return + var/baseline_max_storage_space = DEFAULT_BOX_STORAGE //storage size corresponding to 224 pixels + var/storage_cap_width = 2 //length of sprite for start and end of the box representing total storage space + var/stored_cap_width = 4 //length of sprite for start and end of the box representing the stored item + var/storage_width = min( round( 224 * _storage.max_storage_space/baseline_max_storage_space ,1) ,284) //length of sprite for the box representing total storage space + + storage_start.overlays.Cut() + + var/matrix/M = matrix() + M.Scale((storage_width-storage_cap_width*2+3)/32,1) + storage_continue.transform = M + + storage_start.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + storage_continue.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[storage_cap_width+(storage_width-storage_cap_width*2)/2+2],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + storage_end.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[19+storage_width-storage_cap_width],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + + var/startpoint = 0 + var/endpoint = 1 + + for(var/obj/item/O in _storage.get_contents()) + startpoint = endpoint + 1 + endpoint += storage_width * O.get_storage_cost()/_storage.max_storage_space + + var/matrix/M_start = matrix() + var/matrix/M_continue = matrix() + var/matrix/M_end = matrix() + M_start.Translate(startpoint,0) + M_continue.Scale((endpoint-startpoint-stored_cap_width*2)/32,1) + M_continue.Translate(startpoint+stored_cap_width+(endpoint-startpoint-stored_cap_width*2)/2 - 16,0) + M_end.Translate(endpoint-stored_cap_width,0) + stored_start.transform = M_start + stored_continue.transform = M_continue + stored_end.transform = M_end + storage_start.overlays += stored_start + storage_start.overlays += stored_continue + storage_start.overlays += stored_end + + O.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[round((startpoint+endpoint)/2)+2],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + O.maptext = "" + O.hud_layerise() + + closer.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[storage_width+19],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + +// Sets up numbered display to show the stack size of each stored mineral +// NOTE: numbered display is turned off currently because it's broken +/datum/storage_ui/default/sheetsnatcher/prepare_ui(mob/user) + var/adjusted_contents = length(_storage.get_contents()) + + var/row_num = 0 + var/col_count = min(7,_storage.storage_slots) -1 + if (adjusted_contents > 7) + row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. + arrange_item_slots(row_num, col_count) + refresh_viewers() + +// produce bin +// numbered maptext display + deduplication by seed name +/datum/storage_ui/default/produce_bin/prepare_ui(mob/user) + slot_orient_objs() + refresh_viewers() + +/datum/storage_ui/default/produce_bin/show_to(mob/user) + . = ..() + if(user.client) + user.client.screen -= storage_start + user.client.screen -= storage_continue + user.client.screen -= storage_end + user.client.screen += boxes + +/// Returns a key (not necessarily a string) to group objects by. +/datum/storage_ui/default/produce_bin/proc/get_key_for_object(obj/item/food/grown/produce) + if(!istype(produce) || !produce.seed) + return produce // should never happen, but it's a fallback nonetheless + return produce.seed.product_name || produce.seed.name + +/datum/storage_ui/default/produce_bin/proc/get_seed_counts() + var/list/counts = list() + for(var/obj/item/food/grown/produce in _storage.get_contents()) + counts[get_key_for_object(produce)]++ + return counts + +//This proc determins the size of the inventory to be displayed. Please touch it only if you know what you're doing. +/datum/storage_ui/default/produce_bin/slot_orient_objs() + var/adjusted_contents = length(get_seed_counts()) + var/row_num = 0 + if (adjusted_contents > 7) + row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. + arrange_item_slots(row_num, clamp(adjusted_contents - 1, 0, 6)) + +// Only display one item for each key. +/datum/storage_ui/default/produce_bin/get_displayed_contents() + . = list() + var/list/displayed = list() + for(var/obj/item/food/grown/produce in _storage.get_contents()) + var/produce_key = get_key_for_object(produce) + if(displayed[produce_key]) + continue + displayed[produce_key] = TRUE + . += produce + +//This proc draws out the inventory and places the items on it. It uses the standard position. +/datum/storage_ui/default/produce_bin/arrange_item_slots(rows, cols) + var/cx = SCREEN_LOC_MOD_FIRST + var/cy = SCREEN_LOC_MOD_SECOND + rows + boxes.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED] to LEFT+[SCREEN_LOC_MOD_FIRST + cols]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND + rows]:[SCREEN_LOC_MOD_DIVIDED]" + + var/list/counts = get_seed_counts() + // get_displayed_contents already handles deduplication + for(var/obj/item/food/grown/produce in get_displayed_contents()) + var/produce_key = get_key_for_object(produce) + produce.screen_loc = "LEFT+[cx]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[cy]:[SCREEN_LOC_MOD_DIVIDED]" + produce.maptext_x = 2 + produce.maptext_y = 2 + produce.maptext = STYLE_SMALLFONTS_OUTLINE(counts[produce_key], 6, COLOR_WHITE, COLOR_BLACK) + produce.hud_layerise() + cx++ + if (cx > (SCREEN_LOC_MOD_FIRST + cols)) + cx = SCREEN_LOC_MOD_FIRST + cy-- + + closer.screen_loc = "LEFT+[SCREEN_LOC_MOD_FIRST + cols + 1]:[SCREEN_LOC_MOD_DIVIDED],BOTTOM+[SCREEN_LOC_MOD_SECOND]:[SCREEN_LOC_MOD_DIVIDED]" + +/datum/storage_ui/default/produce_bin/on_pre_remove(obj/item/food/grown/produce) + produce.maptext = "" + ..() + +#undef SCREEN_LOC_MOD_FIRST +#undef SCREEN_LOC_MOD_SECOND +#undef SCREEN_LOC_MOD_DIVIDED diff --git a/code/datums/storage/subtypes_backpack.dm b/code/datums/storage/subtypes_backpack.dm new file mode 100644 index 000000000000..30c6027aa028 --- /dev/null +++ b/code/datums/storage/subtypes_backpack.dm @@ -0,0 +1,31 @@ +/datum/storage/backpack + max_w_class = ITEM_SIZE_LARGE + max_storage_space = DEFAULT_BACKPACK_STORAGE + open_sound = 'sound/effects/storage/unzip.ogg' + +/datum/storage/backpack/holding + max_storage_space = 56 + +/datum/storage/backpack/holding/can_be_inserted(obj/item/inserting, mob/user, stop_messages = 0, click_params) + return istype(inserting, /obj/item/backpack/holding) || ..() + +/datum/storage/backpack/santa + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 400 // can store a ton of shit! + +/datum/storage/backpack/duffle + max_storage_space = DEFAULT_BACKPACK_STORAGE + 10 + +/datum/storage/backpack/pocketbook + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + +/datum/storage/backpack/smuggler + storage_slots = 5 + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 15 + cant_hold = list(/obj/item/backpack/satchel/flat) //muh recursive backpacks + +/datum/storage/backpack/crow + storage_slots = 7 + max_w_class = ITEM_SIZE_SMALL diff --git a/code/datums/storage/subtypes_bag.dm b/code/datums/storage/subtypes_bag.dm new file mode 100644 index 000000000000..401ea28d1dad --- /dev/null +++ b/code/datums/storage/subtypes_bag.dm @@ -0,0 +1,62 @@ +/datum/storage/bag + allow_quick_gather = 1 + allow_quick_empty = 1 + use_to_pickup = 1 + +/datum/storage/bag/handle_item_insertion(mob/user, obj/item/inserting, prevent_warning, skip_update, click_params) + . = ..() + if(. && istype(holder, /obj/item/bag)) + var/obj/item/bag/bag = holder + bag.update_w_class() + +/datum/storage/bag/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + if(. && istype(holder, /obj/item/bag)) + var/obj/item/bag/bag = holder + bag.update_w_class() + +/datum/storage/bag/can_be_inserted(obj/item/inserting, mob/user, stop_messages = 0, click_params = null) + var/mob/living/human/H = ishuman(user) ? user : null // if we're human, then we need to check if bag in a pocket + if(holder.loc?.storage || H?.is_in_pocket(holder)) + if(!stop_messages) + to_chat(user, SPAN_NOTICE("Take \the [holder] out of [istype(holder.loc, /obj) ? "\the [holder.loc]" : "the pocket"] first.")) + return 0 //causes problems if the bag expands and becomes larger than src.loc can hold, so disallow it + . = ..() + +/datum/storage/bag/sack + max_w_class = ITEM_SIZE_LARGE + max_storage_space = DEFAULT_BACKPACK_STORAGE + can_hold = list() + +/datum/storage/bag/trash + max_w_class = ITEM_SIZE_HUGE //can fit a backpack inside a trash bag, seems right + max_storage_space = DEFAULT_BACKPACK_STORAGE + can_hold = list() // any + +/datum/storage/bag/trash/advanced + max_storage_space = 56 + +/datum/storage/bag/cash + max_storage_space = 100 + max_w_class = ITEM_SIZE_HUGE + can_hold = list(/obj/item/coin, /obj/item/cash) + +/datum/storage/bag/cash/infinite/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + if(. && istype(removing, /obj/item/cash)) //only matters if its spacecash. + handle_item_insertion(null, new /obj/item/cash/c1000, TRUE) + +/datum/storage/bag/quantum + storage_slots = 56 + max_w_class = 400 + +/datum/storage/bag/plastic + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BOX_STORAGE + can_hold = list() // any + +/datum/storage/bag/fossils + storage_slots = 50 + max_storage_space = 200 + max_w_class = ITEM_SIZE_NORMAL + can_hold = list(/obj/item/fossil) diff --git a/code/datums/storage/subtypes_basket.dm b/code/datums/storage/subtypes_basket.dm new file mode 100644 index 000000000000..e5601ca91158 --- /dev/null +++ b/code/datums/storage/subtypes_basket.dm @@ -0,0 +1,8 @@ + +/datum/storage/basket + use_sound = 'sound/effects/storage/box.ogg' + max_w_class = ITEM_SIZE_LARGE + max_storage_space = DEFAULT_BOX_STORAGE + +/datum/storage/basket/large + max_storage_space = DEFAULT_BACKPACK_STORAGE diff --git a/code/datums/storage/subtypes_belt.dm b/code/datums/storage/subtypes_belt.dm new file mode 100644 index 000000000000..e730ffbdd536 --- /dev/null +++ b/code/datums/storage/subtypes_belt.dm @@ -0,0 +1,188 @@ +/datum/storage/belt + storage_slots = 7 + max_w_class = ITEM_SIZE_NORMAL + +/datum/storage/belt/utility + can_hold = list( + ///obj/item/combitool, + /obj/item/crowbar, + /obj/item/screwdriver, + /obj/item/weldingtool, + /obj/item/wirecutters, + /obj/item/wrench, + /obj/item/multitool, + /obj/item/flashlight, + /obj/item/stack/cable_coil, + /obj/item/t_scanner, + /obj/item/scanner/gas, + /obj/item/inducer/, + /obj/item/robotanalyzer, + /obj/item/tool/hoe/mini, + /obj/item/tool/axe/hatchet, + /obj/item/scanner/plant, + /obj/item/stack/tape_roll, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/marshalling_wand, + /obj/item/geiger, + /obj/item/hand_labeler, + /obj/item/clothing/gloves + ) + +/datum/storage/belt/medical + can_hold = list( + /obj/item/scanner/health, + /obj/item/scanner/breath, + /obj/item/chems/dropper, + /obj/item/chems/glass/beaker, + /obj/item/chems/glass/bottle, + /obj/item/chems/pill, + /obj/item/chems/syringe, + /obj/item/flame/fuelled/lighter/zippo, + /obj/item/box/fancy/cigarettes, + /obj/item/pill_bottle, + /obj/item/stack/medical, + /obj/item/flashlight/pen, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/head/surgery, + /obj/item/clothing/gloves/latex, + /obj/item/chems/hypospray, + /obj/item/chems/inhaler, + /obj/item/clothing/glasses/hud/health, + /obj/item/crowbar, + /obj/item/flashlight, + /obj/item/stack/tape_roll, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/med_pouch, + /obj/item/bodybag, + /obj/item/clothing/gloves + ) + +/datum/storage/belt/security + can_hold = list( + /obj/item/crowbar, + /obj/item/grenade, + /obj/item/chems/spray/pepper, + /obj/item/handcuffs, + /obj/item/flash, + /obj/item/clothing/glasses, + /obj/item/ammo_casing/shotgun, + /obj/item/ammo_magazine, + /obj/item/food/donut, + /obj/item/baton, + /obj/item/telebaton, + /obj/item/flame/fuelled/lighter, + /obj/item/flashlight, + /obj/item/modular_computer/pda, + /obj/item/radio/headset, + /obj/item/hailer, + /obj/item/megaphone, + /obj/item/energy_blade, + /obj/item/baton, + /obj/item/stack/tape_roll, + /obj/item/holowarrant, + /obj/item/magnetic_ammo, + /obj/item/binoculars, + /obj/item/clothing/gloves, + /obj/item/cell/gun + ) + +/datum/storage/belt/general + can_hold = list( + /obj/item/flash, + /obj/item/telebaton, + /obj/item/taperecorder, + /obj/item/folder, + /obj/item/paper, + /obj/item/clipboard, + /obj/item/modular_computer/tablet, + /obj/item/flashlight, + /obj/item/modular_computer/pda, + /obj/item/radio/headset, + /obj/item/megaphone, + /obj/item/stack/tape_roll, + /obj/item/magnetic_tape, + /obj/item/holowarrant, + /obj/item/radio, + /obj/item/pen, + /obj/item/stamp, + /obj/item/stack/package_wrap, + /obj/item/binoculars, + /obj/item/marshalling_wand, + /obj/item/camera, + /obj/item/hand_labeler, + /obj/item/destTagger, + /obj/item/clothing/glasses, + /obj/item/clothing/head/soft, + /obj/item/hand_labeler, + /obj/item/clothing/gloves, + /obj/item/crowbar + ) + +/datum/storage/belt/janitor + can_hold = list( + /obj/item/grenade/chem_grenade, + /obj/item/lightreplacer, + /obj/item/flashlight, + /obj/item/chems/spray/cleaner, + /obj/item/soap, + /obj/item/holosign_creator, + /obj/item/clothing/gloves, + /obj/item/assembly/mousetrap, + /obj/item/crowbar, + /obj/item/plunger + ) + +/datum/storage/belt/archaeology + can_hold = list( + /obj/item/core_sampler, + /obj/item/pinpointer/radio, + /obj/item/radio/beacon, + /obj/item/gps, + /obj/item/measuring_tape, + /obj/item/flashlight, + /obj/item/tool, + /obj/item/depth_scanner, + /obj/item/camera, + /obj/item/paper, + /obj/item/photo, + /obj/item/folder, + /obj/item/pen, + /obj/item/folder, + /obj/item/clipboard, + /obj/item/anodevice, + /obj/item/clothing/glasses, + /obj/item/wrench, + /obj/item/excavation, + /obj/item/anobattery, + /obj/item/ano_scanner, + /obj/item/stack/tape_roll/barricade_tape/research, + /obj/item/tool/xeno/hand + ) + +/datum/storage/belt/champion + storage_slots = null + max_storage_space = ITEM_SIZE_SMALL + can_hold = list( + /obj/item/clothing/mask/luchador + ) + +/datum/storage/holster/security/tactical + storage_slots = 10 + +/datum/storage/belt/waistpack + storage_slots = null + max_w_class = ITEM_SIZE_SMALL + max_storage_space = ITEM_SIZE_SMALL * 4 + +/datum/storage/belt/waistpack/big + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = ITEM_SIZE_NORMAL * 4 + +/datum/storage/belt/firefighter + storage_slots = 6 + can_hold = list( + /obj/item/grenade/chem_grenade/water, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/inflatable, + /obj/item/inflatable/door + ) diff --git a/code/datums/storage/subtypes_box.dm b/code/datums/storage/subtypes_box.dm new file mode 100644 index 000000000000..b94d406d1e6b --- /dev/null +++ b/code/datums/storage/subtypes_box.dm @@ -0,0 +1,124 @@ +/datum/storage/box + max_storage_space = DEFAULT_BOX_STORAGE + use_sound = 'sound/effects/storage/box.ogg' + +/datum/storage/box/make_exact_fit() + ..() + var/obj/item/box/box = holder + if(istype(box)) + box.foldable = null //special form fitted boxes should not be foldable. + +/datum/storage/box/metal + use_sound = 'sound/effects/closet_open.ogg' + +/datum/storage/box/large + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + +/datum/storage/box/animal_cube + can_hold = list(/obj/item/food/animal_cube) + +/datum/storage/box/large/metal + use_sound = 'sound/effects/closet_open.ogg' + +/datum/storage/box/snappop + can_hold = list(/obj/item/toy/snappop) + +/datum/storage/box/matches + can_hold = list(/obj/item/flame/match) + +/datum/storage/box/lights + use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + +/datum/storage/box/checkers + max_storage_space = 24 + can_hold = list(/obj/item/checker) + +/datum/storage/box/freezer + max_w_class = ITEM_SIZE_NORMAL + can_hold = list( + /obj/item/organ, + /obj/item/food, + /obj/item/chems/drinks, + /obj/item/chems/condiment, + /obj/item/chems/glass + ) + max_storage_space = DEFAULT_LARGEBOX_STORAGE + use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + +/datum/storage/box/cigar + max_w_class = ITEM_SIZE_TINY + storage_slots = 7 + +/datum/storage/box/cigar/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + if(istype(removing, /obj/item/clothing/mask/smokable/cigarette/cigar) && isatom(holder)) + var/atom/atom_holder = holder + if(atom_holder.reagents) + atom_holder.reagents.trans_to_obj(removing, (REAGENT_TOTAL_VOLUME(atom_holder.reagents)/max(1, length(get_contents())))) + return ..() + +/datum/storage/box/cigarettes + max_w_class = ITEM_SIZE_TINY + max_storage_space = 6 + +/datum/storage/box/cigarettes/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + // Don't try to transfer reagents to lighters + if(istype(removing, /obj/item/clothing/mask/smokable/cigarette) && isatom(holder)) + var/atom/atom_holder = holder + if(atom_holder.reagents) + atom_holder.reagents.trans_to_obj(removing, (REAGENT_TOTAL_VOLUME(atom_holder.reagents)/max(1, length(get_contents())))) + return ..() + +/datum/storage/box/cigarettes/cigarello + max_storage_space = 5 + +/datum/storage/box/parts_pack + max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_NORMAL) + +/datum/storage/box/donut + max_storage_space = ITEM_SIZE_SMALL * 6 + can_hold = list(/obj/item/food/donut) + +/datum/storage/box/glasses + can_hold = list(/obj/item/chems/drinks/glass2) + storage_slots = 8 + +/datum/storage/box/glass_extras + can_hold = list(/obj/item/glass_extra) + storage_slots = 14 + +/datum/storage/box/vials + max_w_class = ITEM_SIZE_TINY + storage_slots = 12 + max_storage_space = null + +/datum/storage/box/egg + storage_slots = 12 + max_w_class = ITEM_SIZE_SMALL + max_storage_space = ITEM_SIZE_SMALL * 12 + can_hold = list( + /obj/item/food/egg, + /obj/item/food/boiledegg + ) + +/datum/storage/box/crackers + storage_slots = 6 + max_w_class = ITEM_SIZE_TINY + max_storage_space = ITEM_SIZE_TINY * 6 + can_hold = list(/obj/item/food/cracker) + +/datum/storage/box/crayons + max_w_class = ITEM_SIZE_TINY + max_storage_space = 6 + +/datum/storage/box/tapes + max_storage_space = 28 + +/datum/storage/box/candles + max_storage_space = DEFAULT_LARGEBOX_STORAGE + +/datum/storage/box/candles/scented + max_storage_space = 10 + +/datum/storage/box/candles/incense + max_storage_space = 18 diff --git a/code/datums/storage/subtypes_excavation.dm b/code/datums/storage/subtypes_excavation.dm new file mode 100644 index 000000000000..ec23be327fae --- /dev/null +++ b/code/datums/storage/subtypes_excavation.dm @@ -0,0 +1,12 @@ +/datum/storage/excavation + storage_slots = 7 + can_hold = list(/obj/item/tool/xeno) + max_storage_space = 18 + max_w_class = ITEM_SIZE_NORMAL + use_to_pickup = 1 + +/datum/storage/excavation/handle_item_insertion(mob/user, obj/item/inserting, prevent_warning, skip_update, click_params) + . = ..() + var/obj/item/excavation/picks = holder + if(istype(picks)) + picks.sort_picks() diff --git a/code/datums/storage/subtypes_firstaid.dm b/code/datums/storage/subtypes_firstaid.dm new file mode 100644 index 000000000000..01ed75127593 --- /dev/null +++ b/code/datums/storage/subtypes_firstaid.dm @@ -0,0 +1,34 @@ +/datum/storage/firstaid + max_w_class = ITEM_SIZE_SMALL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + use_sound = 'sound/effects/storage/box.ogg' + +/datum/storage/firstaid/surgery + storage_slots = 14 + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = null + use_sound = 'sound/effects/storage/briefcase.ogg' + can_hold = list( + /obj/item/bonesetter, + /obj/item/cautery, + /obj/item/circular_saw, + /obj/item/hemostat, + /obj/item/retractor, + /obj/item/scalpel, + /obj/item/surgicaldrill, + /obj/item/bonegel, + /obj/item/sutures, + /obj/item/stack/medical/bandage/advanced, + /obj/item/stack/nanopaste + ) + +/datum/storage/firstaid/surgery/ghetto + can_hold = list( + /obj/item/screwdriver, + /obj/item/wrench, + /obj/item/tool/axe/hatchet, + /obj/item/utensil/fork, + /obj/item/shard, + /obj/item/flame/fuelled/lighter, + /obj/item/stack/cable_coil + ) diff --git a/code/datums/storage/subtypes_holster.dm b/code/datums/storage/subtypes_holster.dm new file mode 100644 index 000000000000..7ab6a47b4a7a --- /dev/null +++ b/code/datums/storage/subtypes_holster.dm @@ -0,0 +1,115 @@ +/datum/storage/holster + storage_slots = 2 + max_w_class = ITEM_SIZE_NORMAL + can_hold = list( + /obj/item/baton, + /obj/item/telebaton + ) + +/datum/storage/holster/shoulder + storage_slots = 1 + +/datum/storage/holster/security + storage_slots = 8 + can_hold = list( + /obj/item/crowbar, + /obj/item/grenade, + /obj/item/chems/spray/pepper, + /obj/item/handcuffs, + /obj/item/flash, + /obj/item/clothing/glasses, + /obj/item/ammo_casing/shotgun, + /obj/item/ammo_magazine, + /obj/item/food/donut, + /obj/item/baton, + /obj/item/telebaton, + /obj/item/flame/fuelled/lighter, + /obj/item/flashlight, + /obj/item/modular_computer/pda, + /obj/item/radio/headset, + /obj/item/hailer, + /obj/item/megaphone, + /obj/item/energy_blade, + /obj/item/baton, + /obj/item/stack/tape_roll, + /obj/item/holowarrant, + /obj/item/magnetic_ammo, + /obj/item/binoculars, + /obj/item/clothing/gloves + ) + +/datum/storage/holster/general + storage_slots = 7 + can_hold = list( + /obj/item/flash, + /obj/item/telebaton, + /obj/item/taperecorder, + /obj/item/magnetic_tape, + /obj/item/stack/tape_roll, + /obj/item/folder, + /obj/item/paper, + /obj/item/clipboard, + /obj/item/modular_computer/tablet, + /obj/item/flash, + /obj/item/flashlight, + /obj/item/modular_computer/pda, + /obj/item/radio/headset, + /obj/item/megaphone, + /obj/item/holowarrant, + /obj/item/radio, + /obj/item/pen, + /obj/item/stamp, + /obj/item/stack/package_wrap, + /obj/item/binoculars, + /obj/item/marshalling_wand, + /obj/item/camera, + /obj/item/destTagger, + /obj/item/clothing/glasses, + /obj/item/clothing/head/soft, + /obj/item/hand_labeler, + /obj/item/clothing/gloves, + /obj/item/crowbar + ) + +/datum/storage/holster/forensic + storage_slots = 8 + can_hold = list( + /obj/item/chems/spray/luminol, + /obj/item/uv_light, + /obj/item/chems/syringe, + /obj/item/forensics/sample/swab, + /obj/item/forensics/sample/print, + /obj/item/forensics/sample/fibers, + /obj/item/taperecorder, + /obj/item/magnetic_tape, + /obj/item/clothing/gloves/latex, + /obj/item/clothing/gloves/forensic, + /obj/item/folder, + /obj/item/paper, + /obj/item/forensics/sample_kit, + /obj/item/camera + ) + +/datum/storage/holster/machete + storage_slots = 8 + can_hold = list( + /obj/item/binoculars, + /obj/item/camera, + /obj/item/stack/flag, + /obj/item/geiger, + /obj/item/flashlight, + /obj/item/radio, + /obj/item/gps, + /obj/item/scanner/mining, + /obj/item/scanner/xenobio, + /obj/item/scanner/plant, + /obj/item/folder, + /obj/item/paper, + /obj/item/pen, + /obj/item/spaceflare, + /obj/item/radio/beacon, + /obj/item/pinpointer/radio, + /obj/item/taperecorder, + /obj/item/magnetic_tape, + /obj/item/scanner/gas + ) diff --git a/code/datums/storage/subtypes_misc.dm b/code/datums/storage/subtypes_misc.dm new file mode 100644 index 000000000000..f2788e711e97 --- /dev/null +++ b/code/datums/storage/subtypes_misc.dm @@ -0,0 +1,150 @@ +/datum/storage/book + max_w_class = ITEM_SIZE_SMALL + storage_slots = 1 + +/datum/storage/bible + max_w_class = ITEM_SIZE_SMALL + max_storage_space = 4 + +/datum/storage/briefcase + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BACKPACK_STORAGE + open_sound = 'sound/items/containers/briefcase_unlock.ogg' + close_sound = 'sound/items/containers/briefcase_lock.ogg' + +/datum/storage/briefcase/inflatables + max_storage_space = DEFAULT_LARGEBOX_STORAGE + can_hold = list(/obj/item/inflatable) + +/datum/storage/laundry_basket + max_w_class = ITEM_SIZE_HUGE + max_storage_space = DEFAULT_BACKPACK_STORAGE //20 for clothes + a bit of additional space for non-clothing items that were worn on body + storage_slots = 14 + use_to_pickup = 1 + allow_quick_empty = 1 + allow_quick_gather = 1 + collection_mode = 1 + +/datum/storage/laundry_basket/show_to(mob/user) + return + +/datum/storage/laundry_basket/open(mob/user) + return + +/datum/storage/lockbox + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 32 //The sum of the w_classes of all the items in this storage item. + expected_type = /obj/item/lockbox + +/datum/storage/lockbox/show_to(mob/user) + var/obj/item/lockbox/container = holder + if(istype(container) && container.locked) + to_chat(user, SPAN_WARNING("\The [holder] is locked!")) + return + return ..() + +/datum/storage/lunchbox + max_storage_space = 8 //slightly smaller than a toolbox + max_w_class = ITEM_SIZE_SMALL + +/datum/storage/med_pouch + storage_slots = 7 + max_w_class = ITEM_SIZE_SMALL + opened = FALSE + open_sound = 'sound/effects/rip1.ogg' + +/datum/storage/med_pouch/open(mob/user) + if(!opened) + user.visible_message( + SPAN_NOTICE("\The [user] tears open \the [holder], breaking the vacuum seal!"), + SPAN_NOTICE("You tear open \the [holder], breaking the vacuum seal!") + ) + . = ..() + +/datum/storage/cigpapers + max_w_class = ITEM_SIZE_TINY + max_storage_space = 10 + +/datum/storage/chewables + max_w_class = ITEM_SIZE_TINY + max_storage_space = 6 + +/datum/storage/chewables/rollable + max_storage_space = 8 + +/datum/storage/chewables/cookies + max_storage_space = 6 + +/datum/storage/chewables/gum + max_storage_space = 8 + +/datum/storage/chewables/lollipops + max_storage_space = 20 + +/datum/storage/pouches + storage_slots = 2 + +/datum/storage/pouches/large + storage_slots = 4 + +/datum/storage/barrel + max_w_class = ITEM_SIZE_GARGANTUAN + max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_GARGANTUAN) + +/datum/storage/hopper + max_w_class = ITEM_SIZE_NORMAL // Hopper intake size. + max_storage_space = DEFAULT_BOX_STORAGE // Total internal storage size. + +/datum/storage/hopper/small + max_w_class = ITEM_SIZE_TINY + +/datum/storage/hopper/industrial + max_w_class = ITEM_SIZE_GARGANTUAN + max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_NORMAL) + +/datum/storage/hopper/industrial/compost + can_hold = list(/obj/item) + expected_type = /obj/structure/reagent_dispensers/compost_bin + +/datum/storage/hopper/industrial/compost/can_be_inserted(obj/item/inserting, mob/user, stop_messages = 0, click_params = null) + . = ..() + if(!.) + return + if(istype(inserting, /obj/item/food/worm) && istype(holder, /obj/structure/reagent_dispensers/compost_bin)) + var/worms = 0 + for(var/obj/item/food/worm/worm in get_contents()) + worms++ + return worms < COMPOST_MAX_WORMS + return inserting.is_compostable() + +/datum/storage/hopper/mortar + max_w_class = ITEM_SIZE_NORMAL * 2 + +/datum/storage/hopper/mortar/can_be_inserted(obj/item/inserting_item, mob/user, stop_messages, click_params = null) + . = ..() + if(!.) + return + return REAGENT_TOTAL_VOLUME(inserting_item.reagents) > 0 + +/datum/storage/photo_album + storage_slots = DEFAULT_BOX_STORAGE //yes, that's storage_slots. Photos are w_class 1 so this has as many slots equal to the number of photos you could put in a box + can_hold = list(/obj/item/photo) + +/datum/storage/picnic_basket + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BOX_STORAGE + +/datum/storage/toolbox + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE //enough to hold all starting contents + use_sound = 'sound/effects/storage/toolbox.ogg' + +/datum/storage/mech + max_w_class = ITEM_SIZE_LARGE + storage_slots = 4 + use_sound = 'sound/effects/storage/toolbox.ogg' + +/datum/storage/produce_bin + can_hold = list(/obj/item/food/grown) + max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_STRUCTURE) + storage_ui = /datum/storage_ui/default/produce_bin \ No newline at end of file diff --git a/code/datums/storage/subtypes_mre.dm b/code/datums/storage/subtypes_mre.dm new file mode 100644 index 000000000000..696f0343718f --- /dev/null +++ b/code/datums/storage/subtypes_mre.dm @@ -0,0 +1,27 @@ +/datum/storage/mre + storage_slots = 7 + max_w_class = ITEM_SIZE_SMALL + opened = FALSE + open_sound = 'sound/effects/rip1.ogg' + +/datum/storage/mre/open(mob/user) + var/obj/item/mre/mre = holder + if(istype(mre) && !mre.has_been_opened) + to_chat(user, SPAN_NOTICE("You tear open the bag, breaking the vacuum seal.")) + mre.has_been_opened = TRUE + mre.update_icon() + . = ..() + +/datum/storage/mrebag + storage_slots = 1 + max_w_class = ITEM_SIZE_SMALL + opened = FALSE + open_sound = 'sound/effects/bubbles.ogg' + +/datum/storage/mrebag/open(mob/user) + if(!opened) + to_chat(user, "The pouch heats up as you break the vacuum seal.") + . = ..() + +/datum/storage/mrebag/dessert + open_sound = 'sound/effects/rip1.ogg' diff --git a/code/datums/storage/subtypes_part_replacer.dm b/code/datums/storage/subtypes_part_replacer.dm new file mode 100644 index 000000000000..6a87a688c3d2 --- /dev/null +++ b/code/datums/storage/subtypes_part_replacer.dm @@ -0,0 +1,13 @@ +/datum/storage/parts_replacer + can_hold = list(/obj/item/stock_parts) + storage_slots = 50 + use_to_pickup = 1 + allow_quick_gather = 1 + allow_quick_empty = 1 + collection_mode = 1 + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = 100 + +/datum/storage/parts_replacer/advanced + storage_slots = 400 + max_storage_space = 200 diff --git a/code/datums/storage/subtypes_pills.dm b/code/datums/storage/subtypes_pills.dm new file mode 100644 index 000000000000..29d2ba18f8f2 --- /dev/null +++ b/code/datums/storage/subtypes_pills.dm @@ -0,0 +1,29 @@ +/datum/storage/pillbottle + max_w_class = ITEM_SIZE_TINY + max_storage_space = 21 + can_hold = list( + /obj/item/chems/pill, + /obj/item/dice, + /obj/item/paper + ) + allow_quick_gather = 1 + use_to_pickup = 1 + use_sound = 'sound/effects/storage/pillbottle.ogg' + +/datum/storage/pillbottle/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + if(. && istype(holder, /obj/item/pill_bottle/foil_pack)) + var/obj/item/pill_bottle/foil_pack/pop = holder + if(pop.pop_sound) + playsound(get_turf(pop), pop.pop_sound, 50) + +/datum/storage/pillbottle/foil/can_be_inserted(obj/item/inserting, mob/user, stop_messages = 0, click_params = null) + return FALSE + +/datum/storage/pillbottle/foil/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + if(. && removing.loc != holder && istype(removing, /obj/item/pill_bottle/foil_pack)) + var/obj/item/pill_bottle/foil_pack/pop = holder + if(pop.pill_positions) + pop.pill_positions -= removing + pop.update_icon() diff --git a/code/datums/storage/subtypes_pockets.dm b/code/datums/storage/subtypes_pockets.dm new file mode 100644 index 000000000000..1dcf7c29f997 --- /dev/null +++ b/code/datums/storage/subtypes_pockets.dm @@ -0,0 +1,62 @@ +/datum/storage/pockets + storage_slots = 3 + max_w_class = ITEM_SIZE_SMALL + +/datum/storage/pockets/pouches + storage_slots = 4 //to accomodate it being slotless + +/datum/storage/pockets/pouches/New() + max_storage_space = storage_slots * BASE_STORAGE_COST(max_w_class) + ..() + +/datum/storage/pockets/knifeharness + storage_slots = 2 + max_w_class = ITEM_SIZE_NORMAL //for knives + can_hold = list( + /obj/item/tool/axe/hatchet, + /obj/item/knife, + ) + +/datum/storage/pockets/webbing + storage_slots = 4 + +/datum/storage/pockets/vest + storage_slots = 5 + +/datum/storage/pockets/bandolier + storage_slots = 10 + max_w_class = ITEM_SIZE_NORMAL + can_hold = list( + /obj/item/ammo_casing, + /obj/item/grenade, + /obj/item/knife, + /obj/item/star, + /obj/item/rcd_ammo, + /obj/item/chems/syringe, + /obj/item/chems/hypospray, + /obj/item/chems/hypospray/autoinjector, + /obj/item/chems/inhaler, + /obj/item/syringe_cartridge, + /obj/item/plastique, + /obj/item/clothing/mask/smokable, + /obj/item/screwdriver, + /obj/item/multitool, + /obj/item/magnetic_ammo, + /obj/item/ammo_magazine, + /obj/item/chems/glass/beaker/vial, + /obj/item/paper, + /obj/item/pen, + /obj/item/photo, + /obj/item/marshalling_wand, + /obj/item/chems/pill, + /obj/item/pill_bottle + ) + +/datum/storage/pockets/bandolier/crafted + storage_slots = 5 + max_w_class = ITEM_SIZE_SMALL + can_hold = list(/obj/item) + +/datum/storage/pockets/suit + storage_slots = 2 + max_w_class = ITEM_SIZE_SMALL diff --git a/code/datums/storage/subtypes_secure.dm b/code/datums/storage/subtypes_secure.dm new file mode 100644 index 000000000000..8427c0d7579d --- /dev/null +++ b/code/datums/storage/subtypes_secure.dm @@ -0,0 +1,46 @@ +/datum/storage/secure + max_w_class = ITEM_SIZE_SMALL + max_storage_space = DEFAULT_BOX_STORAGE + +///Helper proc for getting the locked state of the secure storage +/datum/storage/secure/proc/is_locked() + var/datum/extension/lockable/lock = get_extension(holder, /datum/extension/lockable) + return lock?.locked + +/datum/storage/secure/open(mob/user) + if(is_locked()) + if(isatom(holder)) + var/atom/atom_holder = holder + atom_holder.add_fingerprint(user) + return + . = ..() + +//Must be overriden to prevent gathering from tile and using on items when locked! +/datum/storage/secure/can_be_inserted(inserting, mob/user, stop_messages, click_params = null) + if(is_locked()) + if(!stop_messages) + to_chat(user, SPAN_WARNING("\The [holder] is locked, you cannot put anything inside.")) + return FALSE + return ..() + +//Must be overriden to prevent the quick empty verb from bypassing the lock +/datum/storage/secure/quick_empty(mob/user, turf/dump_loc) + if(is_locked()) + to_chat(user, SPAN_WARNING("\The [holder] is locked, you cannot empty it.")) + return + return ..() + +/datum/storage/secure/briefcase + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_BACKPACK_STORAGE + use_sound = 'sound/effects/storage/briefcase.ogg' + open_sound = 'sound/items/containers/briefcase_unlock.ogg' + close_sound = 'sound/items/containers/briefcase_lock.ogg' + +/datum/storage/secure/safe + max_w_class = ITEM_SIZE_HUGE + max_storage_space = 56 + cant_hold = list(/obj/item/secure_storage/briefcase) + use_sound = 'sound/effects/storage/box.ogg' + open_sound = 'sound/effects/closet_open.ogg' + close_sound = 'sound/effects/closet_close.ogg' diff --git a/code/datums/storage/subtypes_sheets.dm b/code/datums/storage/subtypes_sheets.dm new file mode 100644 index 000000000000..7bc7504efca3 --- /dev/null +++ b/code/datums/storage/subtypes_sheets.dm @@ -0,0 +1,88 @@ +/datum/storage/sheets + storage_ui = /datum/storage_ui/default/sheetsnatcher + storage_slots = 7 + allow_quick_empty = TRUE + use_to_pickup = TRUE + /// the number of sheets it can carry. + var/capacity = 300 + +/datum/storage/sheets/robot + capacity = 500 //Borgs get more because >specialization + +/datum/storage/sheets/can_be_inserted(obj/item/inserting, mob/user, stop_messages = 0, click_params = null) + if(!istype(inserting,/obj/item/stack/material)) + if(!stop_messages) + to_chat(user, "\The [holder] does not accept [inserting].") + return FALSE + var/current = 0 + for(var/obj/item/stack/material/S in get_contents()) + current += S.amount + if(capacity == current)//If it's full, you're done + if(!stop_messages) + to_chat(user, "\The [holder] is full.") + return FALSE + return TRUE + +// Modified handle_item_insertion. Would prefer not to, but... +/datum/storage/sheets/handle_item_insertion(mob/user, obj/item/inserting, prevent_warning, skip_update, click_params) + var/obj/item/stack/material/S = inserting + if(!istype(S)) + return FALSE + var/amount + var/inserted = 0 + var/current = 0 + for(var/obj/item/stack/material/S2 in get_contents()) + current += S2.amount + if(capacity < current + S.amount)//If the stack will fill it up + amount = capacity - current + else + amount = S.amount + for(var/obj/item/stack/material/sheet in get_contents()) + if(S.type == sheet.type) // we are violating the amount limitation because these are not sane objects + sheet.amount += amount // they should only be removed through procs in this file, which split them up. + S.amount -= amount + inserted = 1 + break + if(!inserted || !S.amount) + user.drop_from_inventory(S, holder) + if(!S.amount) + qdel(S) + prepare_ui(user) + if(isatom(holder)) + var/atom/atom_holder = holder + atom_holder.update_icon() + return TRUE + +// Modified quick_empty verb drops appropriate sized stacks +/datum/storage/sheets/quick_empty(mob/user, var/turf/dump_loc) + for(var/obj/item/stack/material/S in get_contents()) + while(S.amount) + var/obj/item/stack/material/N = new S.type(dump_loc) + var/stacksize = min(S.amount,N.max_amount) + N.amount = stacksize + S.amount -= stacksize + if(!S.amount) + qdel(S) // todo: there's probably something missing here + prepare_ui() + if(user.active_storage) + user.active_storage.show_to(user) + if(isatom(holder)) + var/atom/atom_holder = holder + atom_holder.update_icon() + +// Instead of removing +/datum/storage/sheets/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + var/obj/item/stack/material/S = removing + if(!istype(S)) + return FALSE + + //I would prefer to drop a new stack, but the item/attack_hand code + // that calls this can't receive a different object than you clicked on. + //Therefore, make a new stack internally that has the remainder. + // -Sayu + + if(S.amount > S.max_amount) + var/obj/item/stack/material/temp = new S.type(holder) + temp.amount = S.amount - S.max_amount + S.amount = S.max_amount + return ..(user, S, new_location) diff --git a/code/datums/storage/subtypes_slides.dm b/code/datums/storage/subtypes_slides.dm new file mode 100644 index 000000000000..3630191a176f --- /dev/null +++ b/code/datums/storage/subtypes_slides.dm @@ -0,0 +1,17 @@ +/datum/storage/slide_projector + max_w_class = ITEM_SIZE_SMALL + max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_SMALL) + use_sound = 'sound/effects/storage/toolbox.ogg' + +/datum/storage/slide_projector/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + var/obj/item/slide_projector/projector = holder + if(. && istype(projector) && removing == projector.current_slide) + var/list/contents = get_contents() + projector.set_slide(length(contents) ? contents[1] : null) + +/datum/storage/slide_projector/handle_item_insertion(mob/user, obj/item/inserting, prevent_warning, skip_update, click_params) + . = ..() + var/obj/item/slide_projector/projector = holder + if(. && istype(projector) && !projector.current_slide) + projector.set_slide(inserting) diff --git a/code/datums/storage/subtypes_specialized.dm b/code/datums/storage/subtypes_specialized.dm new file mode 100644 index 000000000000..aec599590611 --- /dev/null +++ b/code/datums/storage/subtypes_specialized.dm @@ -0,0 +1,33 @@ +/datum/storage/ore + max_storage_space = 200 + max_w_class = ITEM_SIZE_NORMAL + can_hold = list(/obj/item/stack/material/ore) + allow_quick_gather = TRUE + allow_quick_empty = TRUE + use_to_pickup = TRUE + +/datum/storage/evidence + max_storage_space = 100 + max_w_class = ITEM_SIZE_SMALL + can_hold = list( + /obj/item/forensics/sample, + /obj/item/evidencebag, + /obj/item/forensics, + /obj/item/photo, + /obj/item/paper, + /obj/item/paper_bundle + ) + allow_quick_gather = TRUE + allow_quick_empty = TRUE + use_to_pickup = TRUE + +/datum/storage/plants + max_storage_space = 100 + max_w_class = ITEM_SIZE_SMALL + can_hold = list( + /obj/item/food/grown, + /obj/item/seeds + ) + allow_quick_gather = TRUE + allow_quick_empty = TRUE + use_to_pickup = TRUE diff --git a/code/datums/storage/subtypes_structure.dm b/code/datums/storage/subtypes_structure.dm new file mode 100644 index 000000000000..137f917d6ec7 --- /dev/null +++ b/code/datums/storage/subtypes_structure.dm @@ -0,0 +1,6 @@ +/datum/storage/structure + use_sound = 'sound/effects/closet_open.ogg' + max_w_class = ITEM_SIZE_NORMAL + max_storage_space = DEFAULT_LARGEBOX_STORAGE + +/datum/storage/structure/mirror diff --git a/code/datums/storage/subtypes_tray.dm b/code/datums/storage/subtypes_tray.dm new file mode 100644 index 000000000000..f0d79ec39b46 --- /dev/null +++ b/code/datums/storage/subtypes_tray.dm @@ -0,0 +1,17 @@ +/datum/storage/tray + max_storage_space = DEFAULT_BOX_STORAGE + use_to_pickup = 1 + allow_quick_gather = 1 + use_sound = null + +/datum/storage/tray/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + removing.vis_flags = initial(removing.vis_flags) + removing.appearance_flags = initial(removing.appearance_flags) + removing.update_icon() // in case it updates vis_flags + +/datum/storage/tray/gather_all(var/turf/T, var/mob/user) + ..() + if(isatom(holder)) + var/atom/atom_holder = holder + atom_holder.update_icon() diff --git a/code/datums/storage/subtypes_wallet.dm b/code/datums/storage/subtypes_wallet.dm new file mode 100644 index 000000000000..75aed5045327 --- /dev/null +++ b/code/datums/storage/subtypes_wallet.dm @@ -0,0 +1,61 @@ +/datum/storage/wallet + max_w_class = ITEM_SIZE_SMALL //Don't worry, see can_hold[] + max_storage_space = 8 + can_hold = list( + /obj/item/cash, + /obj/item/charge_stick, + /obj/item/card, + /obj/item/clothing/mask/smokable, + /obj/item/cosmetics, + /obj/item/grooming, + /obj/item/mirror, + /obj/item/clothing/neck/necklace/locket, + /obj/item/clothing/head/hairflower, + /obj/item/flashlight/pen, + /obj/item/flashlight, + /obj/item/seeds, + /obj/item/coin, + /obj/item/dice, + /obj/item/disk, + /obj/item/implant, + /obj/item/implanter, + /obj/item/flame, + /obj/item/paper, + /obj/item/paper_bundle, + /obj/item/passport, + /obj/item/pen, + /obj/item/photo, + /obj/item/chems/dropper, + /obj/item/chems/syringe, + /obj/item/chems/pill, + /obj/item/chems/hypospray/autoinjector, + /obj/item/chems/glass/beaker/vial, + /obj/item/radio/headset, + /obj/item/paicard, + /obj/item/stamp, + /obj/item/key, + /obj/item/clothing/badge, + /obj/item/clothing/medal, + /obj/item/clothing/armor_attachment/tag, + ) + +/datum/storage/wallet/remove_from_storage(mob/user, obj/item/removing, atom/new_location, skip_update) + . = ..() + if(. && istype(holder, /obj/item/wallet)) + var/obj/item/wallet/wallet = holder + if(removing == wallet.front_id) + wallet.front_id = null + wallet.SetName(initial(wallet.name)) + wallet.update_icon() + if(removing == wallet.front_stick) + wallet.front_stick = null + +/datum/storage/wallet/handle_item_insertion(mob/user, obj/item/inserting, prevent_warning, skip_update, click_params) + . = ..() + if(. && istype(holder, /obj/item/wallet)) + var/obj/item/wallet/wallet = holder + if(!wallet.front_id && istype(inserting, /obj/item/card/id)) + wallet.front_id = inserting + wallet.update_icon() + if(!wallet.front_stick && istype(inserting, /obj/item/charge_stick)) + wallet.front_stick = inserting diff --git a/code/datums/sun.dm b/code/datums/sun.dm index de10a953be5b..b571ae687309 100644 --- a/code/datums/sun.dm +++ b/code/datums/sun.dm @@ -17,10 +17,6 @@ solar_next_update = world.time // init the timer angle = rand (0,359) // the station position to the sun is randomised at round start -/*/hook/startup/proc/createSun() // handled in scheduler - sun = new /datum/sun() - return 1*/ - // calculate the sun's position given the time of day // at the standard rate (100%) the angle is increase/decreased by 6 degrees every minute. // a full rotation thus take a game hour in that case diff --git a/code/datums/supplypacks/atmospherics.dm b/code/datums/supplypacks/atmospherics.dm index 2b545083917d..1f44350c6c78 100644 --- a/code/datums/supplypacks/atmospherics.dm +++ b/code/datums/supplypacks/atmospherics.dm @@ -6,33 +6,28 @@ name = "Gear - Internals" contains = list(/obj/item/clothing/mask/gas = 3, /obj/item/tank/air = 3) - cost = 10 containername = "internals crate" /decl/hierarchy/supply_pack/atmospherics/evacuation - name = "Emergency equipment" - contains = list(/obj/item/storage/toolbox/emergency = 2, - /obj/item/clothing/suit/storage/hazardvest = 2, - /obj/item/tank/emergency/oxygen/engi = 4, - /obj/item/clothing/suit/space/emergency = 4, - /obj/item/clothing/head/helmet/space/emergency = 4, - /obj/item/clothing/mask/gas = 4, + name = "Gear - Emergency Suits" + contains = list(/obj/item/toolbox/emergency = 2, + /obj/item/clothing/suit/hazardvest = 2, + /obj/item/tank/emergency/oxygen/engi = 2, + /obj/item/clothing/suit/space/emergency = 2, + /obj/item/clothing/head/helmet/space/emergency = 2, + /obj/item/clothing/mask/gas = 2, /obj/item/flashlight/flare/glowstick = 5) - cost = 25 - containername = "emergency crate" /decl/hierarchy/supply_pack/atmospherics/inflatable name = "Equipment - Inflatable barriers" - contains = list(/obj/item/storage/briefcase/inflatable = 3) - cost = 20 + contains = list(/obj/item/briefcase/inflatable = 3) containertype = /obj/structure/closet/crate containername = "inflatable barrier crate" /decl/hierarchy/supply_pack/atmospherics/rpd name = "Equipment - Rapid Piping Device" contains = list(/obj/item/rpd) - cost = 100 containertype = /obj/structure/closet/crate/secure access = access_atmospherics containername = "RPD crate" @@ -40,35 +35,30 @@ /decl/hierarchy/supply_pack/atmospherics/canister_empty name = "Equipment - Empty gas canister" contains = list(/obj/machinery/portable_atmospherics/canister) - cost = 7 containername = "empty gas canister crate" containertype = /obj/structure/largecrate /decl/hierarchy/supply_pack/atmospherics/canister_air name = "Gas - Air canister" contains = list(/obj/machinery/portable_atmospherics/canister/air) - cost = 10 containername = "air canister crate" containertype = /obj/structure/largecrate /decl/hierarchy/supply_pack/atmospherics/canister_oxygen name = "Gas - Oxygen canister" contains = list(/obj/machinery/portable_atmospherics/canister/oxygen) - cost = 15 containername = "oxygen canister crate" containertype = /obj/structure/largecrate /decl/hierarchy/supply_pack/atmospherics/canister_nitrogen name = "Gas - Nitrogen canister" contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen) - cost = 10 containername = "nitrogen canister crate" containertype = /obj/structure/largecrate /decl/hierarchy/supply_pack/atmospherics/canister_hydrogen name = "Gas - Hydrogen canister" contains = list(/obj/machinery/portable_atmospherics/canister/hydrogen) - cost = 25 containername = "hydrogen canister crate" containertype = /obj/structure/closet/crate/secure/large access = access_atmospherics @@ -76,7 +66,6 @@ /decl/hierarchy/supply_pack/atmospherics/canister_sleeping_agent name = "Gas - Nitrous oxide gas canister" contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent) - cost = 40 containername = "\improper N2O gas canister crate" containertype = /obj/structure/closet/crate/secure/large access = access_atmospherics @@ -84,7 +73,6 @@ /decl/hierarchy/supply_pack/atmospherics/canister_carbon_dioxide name = "Gas - Carbon dioxide gas canister" contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) - cost = 40 containername = "\improper CO2 canister crate" containertype = /obj/structure/closet/crate/secure/large access = access_atmospherics @@ -92,7 +80,6 @@ /decl/hierarchy/supply_pack/atmospherics/hydrogen name = "Gas - Hydrogen tanks" contains = list(/obj/item/tank/hydrogen = 4) - cost = 15 containername = "hydrogen tank crate" /decl/hierarchy/supply_pack/atmospherics/voidsuit @@ -100,7 +87,6 @@ contains = list(/obj/item/clothing/suit/space/void/atmos/alt, /obj/item/clothing/head/helmet/space/void/atmos/alt, /obj/item/clothing/shoes/magboots) - cost = 120 containername = "atmospherics voidsuit crate" containertype = /obj/structure/closet/crate/secure/large access = access_atmospherics @@ -108,7 +94,6 @@ /decl/hierarchy/supply_pack/atmospherics/scanner_module name = "Electronics - Atmospherics scanner modules" contains = list(/obj/item/stock_parts/computer/scanner/atmos = 4) - cost = 20 containername = "atmospherics scanner module crate" containertype = /obj/structure/closet/crate/secure access = access_atmospherics \ No newline at end of file diff --git a/code/datums/supplypacks/custodial.dm b/code/datums/supplypacks/custodial.dm index 6ef6af8aff47..9409c0b8912e 100644 --- a/code/datums/supplypacks/custodial.dm +++ b/code/datums/supplypacks/custodial.dm @@ -6,47 +6,42 @@ contains = list(/obj/item/chems/glass/bucket, /obj/item/mop, /obj/item/caution = 4, - /obj/item/storage/bag/trash, + /obj/item/bag/trash, /obj/item/lightreplacer, /obj/item/chems/spray/cleaner, - /obj/item/storage/box/lights/mixed, - /obj/item/chems/glass/rag, + /obj/item/box/lights/mixed, + /obj/item/chems/rag, /obj/item/grenade/chem_grenade/cleaner = 3, /obj/structure/mopbucket) - cost = 20 containertype = /obj/structure/closet/crate/large containername = "janitorial supplies crate" /decl/hierarchy/supply_pack/custodial/mousetrap num_contained = 3 - contains = list(/obj/item/storage/box/mousetraps) + contains = list(/obj/item/box/mousetraps) name = "Misc - Pest control" - cost = 10 containername = "pest control crate" /decl/hierarchy/supply_pack/custodial/lightbulbs name = "Spares - Replacement lights" - contains = list(/obj/item/storage/box/lights/mixed = 3) - cost = 10 + contains = list(/obj/item/box/lights/mixed = 3) containername = "replacement lights crate" /decl/hierarchy/supply_pack/custodial/cleaning name = "Gear - Cleaning supplies" contains = list(/obj/item/mop, /obj/item/grenade/chem_grenade/cleaner = 3, - /obj/item/storage/box/detergent = 3, + /obj/item/box/detergent = 3, /obj/item/chems/glass/bucket, - /obj/item/chems/glass/rag, + /obj/item/chems/rag, /obj/item/chems/spray/cleaner = 2, /obj/item/soap) - cost = 10 containertype = /obj/structure/closet/crate/large containername = "cleaning supplies crate" /decl/hierarchy/supply_pack/custodial/bodybag name = "Equipment - Body bags" - contains = list(/obj/item/storage/box/bodybags = 3) - cost = 10 + contains = list(/obj/item/box/bodybags = 3) containername = "body bag crate" /decl/hierarchy/supply_pack/custodial/janitorbiosuits @@ -55,6 +50,5 @@ /obj/item/clothing/suit/bio_suit/janitor, /obj/item/clothing/mask/gas, /obj/item/tank/oxygen) - cost = 30 containertype = /obj/structure/closet/crate/secure containername = "janitor biohazard equipment crate" \ No newline at end of file diff --git a/code/datums/supplypacks/dispcarts.dm b/code/datums/supplypacks/dispcarts.dm index 62ef7882f271..723e6f9443cc 100644 --- a/code/datums/supplypacks/dispcarts.dm +++ b/code/datums/supplypacks/dispcarts.dm @@ -2,94 +2,93 @@ /decl/hierarchy/supply_pack/dispenser_cartridges name = "Dispenser Cartridges" -#define SEC_PACK(_tname, _type, _name, _cname, _cost, _access)\ - decl/hierarchy/supply_pack/dispenser_cartridges{\ - _tname {\ - name = _name ;\ - containername = _cname ;\ - containertype = /obj/structure/closet/crate/secure;\ - access = list( _access );\ - cost = _cost ;\ - contains = list( _type , _type );\ - }\ +#define SEC_PACK(_tname, _type, _name, _cname, _access)\ +/decl/hierarchy/supply_pack/dispenser_cartridges/##_tname{\ + name = _name ;\ + containername = _cname ;\ + containertype = /obj/structure/closet/crate/secure;\ + access = list( _access );\ + contains = list( _type , _type );\ } -#define PACK(_tname, _type, _name, _cname, _cost)\ - decl/hierarchy/supply_pack/dispenser_cartridges{\ - _tname {\ - name = _name ;\ - containername = _cname ;\ - containertype = /obj/structure/closet/crate;\ - cost = _cost ;\ - contains = list( _type , _type );\ - }\ + +#define PACK(_tname, _type, _name, _cname)\ +/decl/hierarchy/supply_pack/dispenser_cartridges/##_tname{\ + name = _name ;\ + containername = _cname ;\ + containertype = /obj/structure/closet/crate;\ + contains = list( _type , _type );\ } // Chemistry-restricted (raw reagents excluding sugar/water) -// Datum path Contents type Supply pack name Container name Cost Container access -SEC_PACK(hydrazine, /obj/item/chems/chem_disp_cartridge/hydrazine, "Reagent refill - Hydrazine", "hydrazine reagent cartridge crate", 15, access_chemistry) -SEC_PACK(lithium, /obj/item/chems/chem_disp_cartridge/lithium, "Reagent refill - Lithium", "lithium reagent cartridge crate", 15, access_chemistry) -SEC_PACK(carbon, /obj/item/chems/chem_disp_cartridge/carbon, "Reagent refill - Carbon", "carbon reagent cartridge crate", 15, access_chemistry) -SEC_PACK(ammonia, /obj/item/chems/chem_disp_cartridge/ammonia, "Reagent refill - Ammonia", "ammonia reagent cartridge crate", 15, access_chemistry) -SEC_PACK(oxygen, /obj/item/chems/chem_disp_cartridge/acetone, "Reagent refill - Acetone", "acetone reagent cartridge crate", 15, access_chemistry) -SEC_PACK(sodium, /obj/item/chems/chem_disp_cartridge/sodium, "Reagent refill - Sodium", "sodium reagent cartridge crate", 15, access_chemistry) -SEC_PACK(aluminium, /obj/item/chems/chem_disp_cartridge/aluminium, "Reagent refill - Aluminium", "aluminium reagent cartridge crate", 15, access_chemistry) -SEC_PACK(silicon, /obj/item/chems/chem_disp_cartridge/silicon, "Reagent refill - Silicon", "silicon reagent cartridge crate", 15, access_chemistry) -SEC_PACK(phosphorus,/obj/item/chems/chem_disp_cartridge/phosphorus, "Reagent refill - Phosphorus", "phosphorus reagent cartridge crate", 15, access_chemistry) -SEC_PACK(sulfur, /obj/item/chems/chem_disp_cartridge/sulfur, "Reagent refill - Sulfur", "sulfur reagent cartridge crate", 15, access_chemistry) -SEC_PACK(hclacid, /obj/item/chems/chem_disp_cartridge/hclacid, "Reagent refill - Hydrochloric Acid", "hydrochloric acid reagent cartridge crate", 15, access_chemistry) -SEC_PACK(potassium, /obj/item/chems/chem_disp_cartridge/potassium, "Reagent refill - Potassium", "potassium reagent cartridge crate", 15, access_chemistry) -SEC_PACK(iron, /obj/item/chems/chem_disp_cartridge/iron, "Reagent refill - Iron", "iron reagent cartridge crate", 15, access_chemistry) -SEC_PACK(copper, /obj/item/chems/chem_disp_cartridge/copper, "Reagent refill - Copper", "copper reagent cartridge crate", 15, access_chemistry) -SEC_PACK(mercury, /obj/item/chems/chem_disp_cartridge/mercury, "Reagent refill - Mercury", "mercury reagent cartridge crate", 15, access_chemistry) -SEC_PACK(radium, /obj/item/chems/chem_disp_cartridge/radium, "Reagent refill - Radium", "radium reagent cartridge crate", 15, access_chemistry) -SEC_PACK(ethanol, /obj/item/chems/chem_disp_cartridge/ethanol, "Reagent refill - Ethanol", "ethanol reagent cartridge crate", 15, access_chemistry) -SEC_PACK(sacid, /obj/item/chems/chem_disp_cartridge/sacid, "Reagent refill - Sulfuric Acid", "sulfuric acid reagent cartridge crate", 15, access_chemistry) -SEC_PACK(tungsten, /obj/item/chems/chem_disp_cartridge/tungsten, "Reagent refill - Tungsten", "tungsten reagent cartridge crate", 15, access_chemistry) +// Datum path Contents type Supply pack name Container name Container access +SEC_PACK(hydrazine, /obj/item/chems/chem_disp_cartridge/hydrazine, "Reagent refill - Hydrazine", "hydrazine reagent cartridge crate", access_chemistry) +SEC_PACK(lithium, /obj/item/chems/chem_disp_cartridge/lithium, "Reagent refill - Lithium", "lithium reagent cartridge crate", access_chemistry) +SEC_PACK(carbon, /obj/item/chems/chem_disp_cartridge/carbon, "Reagent refill - Carbon", "carbon reagent cartridge crate", access_chemistry) +SEC_PACK(ammonia, /obj/item/chems/chem_disp_cartridge/ammonia, "Reagent refill - Ammonia", "ammonia reagent cartridge crate", access_chemistry) +SEC_PACK(oxygen, /obj/item/chems/chem_disp_cartridge/acetone, "Reagent refill - Acetone", "acetone reagent cartridge crate", access_chemistry) +SEC_PACK(sodium, /obj/item/chems/chem_disp_cartridge/sodium, "Reagent refill - Sodium", "sodium reagent cartridge crate", access_chemistry) +SEC_PACK(aluminium, /obj/item/chems/chem_disp_cartridge/aluminium, "Reagent refill - Aluminium", "aluminium reagent cartridge crate", access_chemistry) +SEC_PACK(silicon, /obj/item/chems/chem_disp_cartridge/silicon, "Reagent refill - Silicon", "silicon reagent cartridge crate", access_chemistry) +SEC_PACK(phosphorus,/obj/item/chems/chem_disp_cartridge/phosphorus, "Reagent refill - Phosphorus", "phosphorus reagent cartridge crate", access_chemistry) +SEC_PACK(sulfur, /obj/item/chems/chem_disp_cartridge/sulfur, "Reagent refill - Sulfur", "sulfur reagent cartridge crate", access_chemistry) +SEC_PACK(hclacid, /obj/item/chems/chem_disp_cartridge/hclacid, "Reagent refill - Hydrochloric Acid", "hydrochloric acid reagent cartridge crate", access_chemistry) +SEC_PACK(potassium, /obj/item/chems/chem_disp_cartridge/potassium, "Reagent refill - Potassium", "potassium reagent cartridge crate", access_chemistry) +SEC_PACK(iron, /obj/item/chems/chem_disp_cartridge/iron, "Reagent refill - Iron", "iron reagent cartridge crate", access_chemistry) +SEC_PACK(copper, /obj/item/chems/chem_disp_cartridge/copper, "Reagent refill - Copper", "copper reagent cartridge crate", access_chemistry) +SEC_PACK(mercury, /obj/item/chems/chem_disp_cartridge/mercury, "Reagent refill - Mercury", "mercury reagent cartridge crate", access_chemistry) +SEC_PACK(radium, /obj/item/chems/chem_disp_cartridge/radium, "Reagent refill - Radium", "radium reagent cartridge crate", access_chemistry) +SEC_PACK(ethanol, /obj/item/chems/chem_disp_cartridge/ethanol, "Reagent refill - Ethanol", "ethanol reagent cartridge crate", access_chemistry) +SEC_PACK(sacid, /obj/item/chems/chem_disp_cartridge/sacid, "Reagent refill - Sulfuric Acid", "sulfuric acid reagent cartridge crate", access_chemistry) +SEC_PACK(tungsten, /obj/item/chems/chem_disp_cartridge/tungsten, "Reagent refill - Tungsten", "tungsten reagent cartridge crate", access_chemistry) +SEC_PACK(stabilizer, /obj/item/chems/chem_disp_cartridge/stabilizer, "Reagent refill - Stabilizer", "stabilizer reagent cartridge crate", access_chemistry) // Bar-restricted (alcoholic drinks) -// Datum path Contents type Supply pack name Container name Cost Container access -SEC_PACK(beer, /obj/item/chems/chem_disp_cartridge/beer, "Reagent refill - Beer", "beer reagent cartridge crate", 15, access_bar) -SEC_PACK(kahlua, /obj/item/chems/chem_disp_cartridge/kahlua, "Reagent refill - Kahlua", "kahlua reagent cartridge crate", 15, access_bar) -SEC_PACK(whiskey, /obj/item/chems/chem_disp_cartridge/whiskey, "Reagent refill - Whiskey", "whiskey reagent cartridge crate", 15, access_bar) -SEC_PACK(wine, /obj/item/chems/chem_disp_cartridge/wine, "Reagent refill - Wine", "wine reagent cartridge crate", 15, access_bar) -SEC_PACK(vodka, /obj/item/chems/chem_disp_cartridge/vodka, "Reagent refill - Vodka", "vodka reagent cartridge crate", 15, access_bar) -SEC_PACK(gin, /obj/item/chems/chem_disp_cartridge/gin, "Reagent refill - Gin", "gin reagent cartridge crate", 15, access_bar) -SEC_PACK(rum, /obj/item/chems/chem_disp_cartridge/rum, "Reagent refill - Rum", "rum reagent cartridge crate", 15, access_bar) -SEC_PACK(tequila, /obj/item/chems/chem_disp_cartridge/tequila, "Reagent refill - Tequila", "tequila reagent cartridge crate", 15, access_bar) -SEC_PACK(vermouth, /obj/item/chems/chem_disp_cartridge/vermouth, "Reagent refill - Vermouth", "vermouth reagent cartridge crate", 15, access_bar) -SEC_PACK(cognac, /obj/item/chems/chem_disp_cartridge/cognac, "Reagent refill - Cognac", "cognac reagent cartridge crate", 15, access_bar) -SEC_PACK(ale, /obj/item/chems/chem_disp_cartridge/ale, "Reagent refill - Ale", "ale reagent cartridge crate", 15, access_bar) -SEC_PACK(mead, /obj/item/chems/chem_disp_cartridge/mead, "Reagent refill - Mead", "mead reagent cartridge crate", 15, access_bar) +// Datum Contents type Supply pack name Container name Container access +SEC_PACK(beer, /obj/item/chems/chem_disp_cartridge/beer, "Reagent refill - Beer", "beer reagent cartridge crate", access_bar) +SEC_PACK(kahlua, /obj/item/chems/chem_disp_cartridge/kahlua, "Reagent refill - Kahlua", "kahlua reagent cartridge crate", access_bar) +SEC_PACK(whiskey, /obj/item/chems/chem_disp_cartridge/whiskey, "Reagent refill - Whiskey", "whiskey reagent cartridge crate", access_bar) +SEC_PACK(wine, /obj/item/chems/chem_disp_cartridge/wine, "Reagent refill - Wine", "wine reagent cartridge crate", access_bar) +SEC_PACK(vodka, /obj/item/chems/chem_disp_cartridge/vodka, "Reagent refill - Vodka", "vodka reagent cartridge crate", access_bar) +SEC_PACK(gin, /obj/item/chems/chem_disp_cartridge/gin, "Reagent refill - Gin", "gin reagent cartridge crate", access_bar) +SEC_PACK(rum, /obj/item/chems/chem_disp_cartridge/rum, "Reagent refill - Rum", "rum reagent cartridge crate", access_bar) +SEC_PACK(tequila, /obj/item/chems/chem_disp_cartridge/tequila, "Reagent refill - Tequila", "tequila reagent cartridge crate", access_bar) +SEC_PACK(vermouth, /obj/item/chems/chem_disp_cartridge/vermouth, "Reagent refill - Vermouth", "vermouth reagent cartridge crate", access_bar) +SEC_PACK(cognac, /obj/item/chems/chem_disp_cartridge/cognac, "Reagent refill - Cognac", "cognac reagent cartridge crate", access_bar) +SEC_PACK(ale, /obj/item/chems/chem_disp_cartridge/ale, "Reagent refill - Ale", "ale reagent cartridge crate", access_bar) +SEC_PACK(mead, /obj/item/chems/chem_disp_cartridge/mead, "Reagent refill - Mead", "mead reagent cartridge crate", access_bar) // Unrestricted (water, sugar, non-alcoholic drinks) -// Datum path Contents type Supply pack name Container name Cost -PACK(water, /obj/item/chems/chem_disp_cartridge/water, "Reagent refill - Water", "water reagent cartridge crate", 15) -PACK(sugar, /obj/item/chems/chem_disp_cartridge/sugar, "Reagent refill - Sugar", "sugar reagent cartridge crate", 15) -PACK(ice, /obj/item/chems/chem_disp_cartridge/ice, "Reagent refill - Ice", "ice reagent cartridge crate", 15) -PACK(tea, /obj/item/chems/chem_disp_cartridge/black_tea, "Reagent refill - Black Tea", "tea reagent cartridge crate", 15) -PACK(green_tea, /obj/item/chems/chem_disp_cartridge/green_tea, "Reagent refill - Green Tea", "green tea reagent cartridge crate", 15) -PACK(chai_tea, /obj/item/chems/chem_disp_cartridge/chai_tea, "Reagent refill - Chai Tea", "chai tea reagent cartridge crate", 15) -PACK(red_tea, /obj/item/chems/chem_disp_cartridge/red_tea, "Reagent refill - Rooibos Tea", "rooibos tea reagent cartridge crate", 15) -PACK(cola, /obj/item/chems/chem_disp_cartridge/cola, "Reagent refill - Cola", "cola reagent cartridge crate", 15) -PACK(citrussoda, /obj/item/chems/chem_disp_cartridge/citrussoda, "Reagent refill - Citrus Soda", "citrus soda reagent cartridge crate", 15) -PACK(cherrycola, /obj/item/chems/chem_disp_cartridge/cherrycola, "Reagent refill - Cherry Cola", "cherry cola reagent cartridge crate", 15) -PACK(lemonade, /obj/item/chems/chem_disp_cartridge/lemonade, "Reagent refill - Lemonade", "lemonade reagent cartridge crate", 15) -PACK(tonic, /obj/item/chems/chem_disp_cartridge/tonic, "Reagent refill - Tonic Water", "tonic water reagent cartridge crate", 15) -PACK(sodawater, /obj/item/chems/chem_disp_cartridge/sodawater, "Reagent refill - Soda Water", "soda water reagent cartridge crate", 15) -PACK(lemon_lime, /obj/item/chems/chem_disp_cartridge/lemon_lime, "Reagent refill - Lemon-Lime Juice", "lemon-lime juice reagent cartridge crate", 15) -PACK(orange, /obj/item/chems/chem_disp_cartridge/orange, "Reagent refill - Orange Juice", "orange juice reagent cartridge crate", 15) -PACK(lime, /obj/item/chems/chem_disp_cartridge/lime, "Reagent refill - Lime Juice", "lime juice reagent cartridge crate", 15) -PACK(watermelon, /obj/item/chems/chem_disp_cartridge/watermelon, "Reagent refill - Watermelon Juice", "watermelon juice reagent cartridge crate", 15) -PACK(coffee, /obj/item/chems/chem_disp_cartridge/coffee, "Reagent refill - Coffee", "coffee reagent cartridge crate", 15) -PACK(hot_coco, /obj/item/chems/chem_disp_cartridge/hot_coco, "Reagent refill - Hot Coco", "hot coco reagent cartridge crate", 15) -PACK(milk, /obj/item/chems/chem_disp_cartridge/milk, "Reagent refill - Milk", "milk reagent cartridge crate", 15) -PACK(soymilk, /obj/item/chems/chem_disp_cartridge/soymilk, "Reagent refill - Soymilk", "soymilk reagent cartridge crate", 15) -PACK(cream, /obj/item/chems/chem_disp_cartridge/cream, "Reagent refill - Cream", "cream reagent cartridge crate", 15) +// Datum Contents type Supply pack name Container name +PACK(water, /obj/item/chems/chem_disp_cartridge/water, "Reagent refill - Water", "water reagent cartridge crate") +PACK(sugar, /obj/item/chems/chem_disp_cartridge/sugar, "Reagent refill - Sugar", "sugar reagent cartridge crate") +PACK(ice, /obj/item/chems/chem_disp_cartridge/ice, "Reagent refill - Ice", "ice reagent cartridge crate") +PACK(tea, /obj/item/chems/chem_disp_cartridge/black_tea, "Reagent refill - Black Tea", "tea reagent cartridge crate") +PACK(green_tea, /obj/item/chems/chem_disp_cartridge/green_tea, "Reagent refill - Green Tea", "green tea reagent cartridge crate") +PACK(chai_tea, /obj/item/chems/chem_disp_cartridge/chai_tea, "Reagent refill - Chai Tea", "chai tea reagent cartridge crate") +PACK(red_tea, /obj/item/chems/chem_disp_cartridge/red_tea, "Reagent refill - Rooibos Tea", "rooibos tea reagent cartridge crate") +PACK(cola, /obj/item/chems/chem_disp_cartridge/cola, "Reagent refill - Cola", "cola reagent cartridge crate") +PACK(citrussoda, /obj/item/chems/chem_disp_cartridge/citrussoda, "Reagent refill - Citrus Soda", "citrus soda reagent cartridge crate") +PACK(cherrycola, /obj/item/chems/chem_disp_cartridge/cherrycola, "Reagent refill - Cherry Cola", "cherry cola reagent cartridge crate") +PACK(lemonade, /obj/item/chems/chem_disp_cartridge/lemonade, "Reagent refill - Lemonade", "lemonade reagent cartridge crate") +PACK(tonic, /obj/item/chems/chem_disp_cartridge/tonic, "Reagent refill - Tonic Water", "tonic water reagent cartridge crate") +PACK(sodawater, /obj/item/chems/chem_disp_cartridge/sodawater, "Reagent refill - Soda Water", "soda water reagent cartridge crate") +PACK(lemon_lime, /obj/item/chems/chem_disp_cartridge/lemon_lime, "Reagent refill - Lemon-Lime Juice", "lemon-lime juice reagent cartridge crate") +PACK(orange, /obj/item/chems/chem_disp_cartridge/orange, "Reagent refill - Orange Juice", "orange juice reagent cartridge crate") +PACK(lime, /obj/item/chems/chem_disp_cartridge/lime, "Reagent refill - Lime Juice", "lime juice reagent cartridge crate") +PACK(watermelon, /obj/item/chems/chem_disp_cartridge/watermelon, "Reagent refill - Watermelon Juice", "watermelon juice reagent cartridge crate") +PACK(coffee, /obj/item/chems/chem_disp_cartridge/coffee, "Reagent refill - Coffee", "coffee reagent cartridge crate") +PACK(hot_coco, /obj/item/chems/chem_disp_cartridge/hot_coco, "Reagent refill - Hot Coco", "hot coco reagent cartridge crate") +PACK(milk, /obj/item/chems/chem_disp_cartridge/milk, "Reagent refill - Milk", "milk reagent cartridge crate") +PACK(soymilk, /obj/item/chems/chem_disp_cartridge/soymilk, "Reagent refill - Soymilk", "soymilk reagent cartridge crate") +PACK(cream, /obj/item/chems/chem_disp_cartridge/cream, "Reagent refill - Cream", "cream reagent cartridge crate") + +PACK(syrup_chocolate, /obj/item/chems/chem_disp_cartridge/syrup_chocolate, "Reagent refill - Chocolate Syrup", "chocolate syrup reagent cartridge crate") +PACK(syrup_caramel, /obj/item/chems/chem_disp_cartridge/syrup_caramel, "Reagent refill - Caramel Syrup", "caramel syrup reagent cartridge crate") +PACK(syrup_vanilla, /obj/item/chems/chem_disp_cartridge/syrup_vanilla, "Reagent refill - Vanilla Syrup", "vanilla syrup reagent cartridge crate") +PACK(syrup_pumpkin, /obj/item/chems/chem_disp_cartridge/syrup_pumpkin, "Reagent refill - Pumpkin Spice Syrup", "pumpkin spice syrup reagent cartridge crate") +PACK(syrup_lavender, /obj/item/chems/chem_disp_cartridge/syrup_lavender, "Reagent refill - Lavender Syrup", "lavender syrup reagent cartridge crate") +PACK(cinnamon, /obj/item/chems/chem_disp_cartridge/cinnamon, "Reagent refill - Cinnamon", "cinnamon reagent cartridge crate") -PACK(syrup_chocolate, /obj/item/chems/chem_disp_cartridge/syrup_chocolate, "Reagent refill - Chocolate Syrup", "chocolate syrup reagent cartridge crate", 15) -PACK(syrup_caramel, /obj/item/chems/chem_disp_cartridge/syrup_caramel, "Reagent refill - Caramel Syrup", "caramel syrup reagent cartridge crate", 15) -PACK(syrup_vanilla, /obj/item/chems/chem_disp_cartridge/syrup_vanilla, "Reagent refill - Vanilla Syrup", "vanilla syrup reagent cartridge crate", 15) -PACK(syrup_pumpkin, /obj/item/chems/chem_disp_cartridge/syrup_pumpkin, "Reagent refill - Pumpkin Spice Syrup", "pumpkin spice syrup reagent cartridge crate", 15) #undef SEC_PACK #undef PACK diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm index dbe213e99314..727e55a1432c 100644 --- a/code/datums/supplypacks/engineering.dm +++ b/code/datums/supplypacks/engineering.dm @@ -4,49 +4,45 @@ /decl/hierarchy/supply_pack/engineering/smes_circuit name = "Electronics - Superconducting magnetic energy storage unit circuitry" contains = list(/obj/item/stock_parts/circuitboard/smes) - cost = 20 containername = "superconducting magnetic energy storage unit circuitry crate" /decl/hierarchy/supply_pack/engineering/smescoil name = "Parts - Superconductive magnetic coil" contains = list(/obj/item/stock_parts/smes_coil) - cost = 35 containername = "superconductive magnetic coil crate" /decl/hierarchy/supply_pack/engineering/smescoil_weak name = "Parts - Basic superconductive magnetic coil" contains = list(/obj/item/stock_parts/smes_coil/weak) - cost = 25 containername = "basic superconductive magnetic coil crate" /decl/hierarchy/supply_pack/engineering/smescoil_super_capacity name = "Parts - Superconductive capacitance coil" contains = list(/obj/item/stock_parts/smes_coil/super_capacity) - cost = 45 containername = "superconductive capacitance coil crate" /decl/hierarchy/supply_pack/engineering/smescoil_super_io name = "Parts- Superconductive Transmission Coil" contains = list(/obj/item/stock_parts/smes_coil/super_io) - cost = 45 containername = "Superconductive Transmission Coil crate" /decl/hierarchy/supply_pack/engineering/electrical name = "Gear - Electrical maintenance" - contains = list(/obj/item/storage/toolbox/electrical = 2, - /obj/item/clothing/gloves/insulated = 2, - /obj/item/cell = 2, - /obj/item/cell/high = 2) - cost = 15 + contains = list( + /obj/item/toolbox/electrical = 1, + /obj/item/toolbox/repairs = 1, + /obj/item/clothing/gloves/insulated = 2, + /obj/item/cell = 2, + /obj/item/cell/high = 2 + ) containername = "electrical maintenance crate" /decl/hierarchy/supply_pack/engineering/mechanical name = "Gear - Mechanical maintenance" - contains = list(/obj/item/storage/belt/utility/full = 3, - /obj/item/clothing/suit/storage/hazardvest = 3, + contains = list(/obj/item/belt/utility/full = 3, + /obj/item/clothing/suit/hazardvest = 3, /obj/item/clothing/head/welding = 2, /obj/item/clothing/head/hardhat) - cost = 10 containername = "mechanical maintenance crate" /decl/hierarchy/supply_pack/engineering/solar @@ -56,19 +52,16 @@ /obj/item/tracker_electronics, /obj/item/paper/solar ) - cost = 15 containername = "solar pack crate" /decl/hierarchy/supply_pack/engineering/solar_assembly name = "Power - Solar assembly" contains = list(/obj/item/solar_assembly = 16) - cost = 10 containername = "solar assembly crate" /decl/hierarchy/supply_pack/engineering/emitter name = "Equipment - Emitter" - contains = list(/obj/machinery/power/emitter = 2) - cost = 10 + contains = list(/obj/machinery/emitter = 2) containertype = /obj/structure/closet/crate/secure/large containername = "emitter crate" access = access_engine_equip @@ -77,27 +70,24 @@ name = "Equipment - Field generator" contains = list(/obj/machinery/field_generator = 2) containertype = /obj/structure/closet/crate/large - cost = 10 containername = "field generator crate" access = access_ce /decl/hierarchy/supply_pack/engineering/sing_gen name = "Equipment - Singularity generator" - contains = list(/obj/machinery/the_singularitygen) - cost = 10 + contains = list(/obj/machinery/singularity_generator) containertype = /obj/structure/closet/crate/secure/large containername = "singularity generator crate" access = access_ce /decl/hierarchy/supply_pack/engineering/collector name = "Power - Collector" - contains = list(/obj/machinery/power/rad_collector = 2) - cost = 8 + contains = list(/obj/machinery/rad_collector = 2) containertype = /obj/structure/closet/crate/secure/large containername = "collector crate" access = access_engine_equip -/decl/hierarchy/supply_pack/engineering/PA +/decl/hierarchy/supply_pack/engineering/particle_accelerator name = "Equipment - Particle accelerator" contains = list(/obj/structure/particle_accelerator/fuel_chamber, /obj/machinery/particle_accelerator/control_box, @@ -106,37 +96,33 @@ /obj/structure/particle_accelerator/particle_emitter/right, /obj/structure/particle_accelerator/power_box, /obj/structure/particle_accelerator/end_cap) - cost = 40 containertype = /obj/structure/largecrate containername = "particle accelerator crate" access = access_ce /decl/hierarchy/supply_pack/engineering/pacman_parts - name = "Power - P.A.C.M.A.N. portable generator parts" + name = "Power - portable fusion generator parts" contains = list(/obj/item/stock_parts/micro_laser, /obj/item/stock_parts/capacitor, /obj/item/stock_parts/matter_bin, /obj/item/stock_parts/circuitboard/pacman) - cost = 45 - containername = "\improper P.A.C.M.A.N. Portable Generator Construction Kit" + containername = "\improper Portable Fusion Generator Construction Kit" containertype = /obj/structure/closet/crate/secure access = access_tech_storage /decl/hierarchy/supply_pack/engineering/super_pacman_parts - name = "Power - Super P.A.C.M.A.N. portable generator parts" + name = "Power - portable fission generator parts" contains = list(/obj/item/stock_parts/micro_laser, /obj/item/stock_parts/capacitor, /obj/item/stock_parts/matter_bin, /obj/item/stock_parts/circuitboard/pacman/super) - cost = 55 - containername = "\improper Super P.A.C.M.A.N. portable generator construction kit" + containername = "portable fission generator construction kit" containertype = /obj/structure/closet/crate/secure access = access_tech_storage /decl/hierarchy/supply_pack/engineering/teg name = "Power - Mark I Thermoelectric Generator" - contains = list(/obj/machinery/power/generator) - cost = 75 + contains = list(/obj/machinery/generator) containertype = /obj/structure/closet/crate/secure/large containername = "\improper Mk1 TEG crate" access = access_engine_equip @@ -144,7 +130,6 @@ /decl/hierarchy/supply_pack/engineering/circulator name = "Equipment - Binary atmospheric circulator" contains = list(/obj/machinery/atmospherics/binary/circulator) - cost = 60 containertype = /obj/structure/closet/crate/secure/large containername = "atmospheric circulator crate" access = access_atmospherics @@ -152,7 +137,6 @@ /decl/hierarchy/supply_pack/engineering/air_dispenser name = "Equipment - Pipe Dispenser" contains = list(/obj/machinery/fabricator/pipe) - cost = 35 containertype = /obj/structure/closet/crate/secure/large containername = "pipe dispenser crate" access = access_atmospherics @@ -160,7 +144,6 @@ /decl/hierarchy/supply_pack/engineering/disposals_dispenser name = "Equipment - Disposals pipe dispenser" contains = list(/obj/machinery/fabricator/pipe/disposal) - cost = 35 containertype = /obj/structure/closet/crate/secure/large containername = "disposal dispenser crate" access = access_atmospherics @@ -168,34 +151,16 @@ /decl/hierarchy/supply_pack/engineering/shield_generator name = "Equipment - Shield generator construction kit" contains = list(/obj/item/stock_parts/circuitboard/shield_generator, /obj/item/stock_parts/capacitor, /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/smes_coil, /obj/item/stock_parts/console_screen) - cost = 50 containertype = /obj/structure/closet/crate/secure containername = "shield generator construction kit crate" access = access_engine -/decl/hierarchy/supply_pack/engineering/inertial_damper - name = "Equipment - inertial damper construction kit" - contains = list(/obj/item/stock_parts/circuitboard/inertial_damper, /obj/item/stock_parts/capacitor, /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/console_screen) - cost = 30 - containertype = /obj/structure/closet/crate/secure - containername = "inertial damper construction kit crate" - access = access_engine - -/decl/hierarchy/supply_pack/engineering/smbig - name = "Power - Supermatter core" - contains = list(/obj/machinery/power/supermatter) - cost = 150 - containertype = /obj/structure/closet/crate/secure/large/supermatter - containername = "\improper Supermatter crate (CAUTION)" - access = access_ce - /decl/hierarchy/supply_pack/engineering/robotics name = "Parts - Robotics assembly" contains = list(/obj/item/assembly/prox_sensor = 3, - /obj/item/storage/toolbox/electrical, + /obj/item/toolbox/electrical, /obj/item/flash = 4, /obj/item/cell/high = 2) - cost = 10 containertype = /obj/structure/closet/crate/secure/gear containername = "robotics assembly crate" access = access_robotics @@ -204,7 +169,6 @@ name = "Gear - Radiation protection gear" contains = list(/obj/item/clothing/suit/radiation = 6, /obj/item/clothing/head/radiation = 6) - cost = 160 containertype = /obj/structure/closet/radiation containername = "radiation suit locker" @@ -215,8 +179,7 @@ /obj/item/stock_parts/manipulator, /obj/item/stock_parts/subspace/filter, /obj/item/stock_parts/subspace/crystal, - /obj/item/storage/toolbox/electrical) - cost = 75 + /obj/item/toolbox/electrical) containername = "emergency communication relay assembly kit" /decl/hierarchy/supply_pack/engineering/firefighter @@ -224,9 +187,8 @@ contains = list(/obj/item/clothing/suit/fire, /obj/item/clothing/mask/gas, /obj/item/tank/emergency/oxygen/double/red, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/clothing/head/hardhat/red) - cost = 40 containertype = /obj/structure/closet/firecloset containername = "fire-safety closet" @@ -235,7 +197,6 @@ contains = list(/obj/item/clothing/suit/space/void/engineering/alt, /obj/item/clothing/head/helmet/space/void/engineering/alt, /obj/item/clothing/shoes/magboots) - cost = 120 containername = "engineering voidsuit crate" containertype = /obj/structure/closet/crate/secure/large access = access_engine diff --git a/code/datums/supplypacks/flooring.dm b/code/datums/supplypacks/flooring.dm index 404b2debb759..47e59ce01a7a 100644 --- a/code/datums/supplypacks/flooring.dm +++ b/code/datums/supplypacks/flooring.dm @@ -4,77 +4,64 @@ /decl/hierarchy/supply_pack/flooring/carpetbrown name = "Brown carpet" contains = list(/obj/item/stack/tile/carpet/fifty) - cost = 15 containername = "brown carpet crate" /decl/hierarchy/supply_pack/flooring/carpetblue name = "Blue and gold carpet" - contains = list(/obj/item/stack/tile/carpetblue/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/blue/fifty) containername = "blue and gold carpet crate" /decl/hierarchy/supply_pack/flooring/carpetblue2 name = "Pale blue carpet" - contains = list(/obj/item/stack/tile/carpetblue2/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/blue2/fifty) containername = "pale blue carpet crate" /decl/hierarchy/supply_pack/flooring/carpetblue3 name = "Sea blue carpet" - contains = list(/obj/item/stack/tile/carpetblue3/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/blue3/fifty) containername = "sea blue carpet crate" /decl/hierarchy/supply_pack/flooring/carpetpurple name = "Magenta carpet" - contains = list(/obj/item/stack/tile/carpetmagenta/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/magenta/fifty) containername = "magenta carpet crate" /decl/hierarchy/supply_pack/flooring/carpetpurple name = "Purple carpet" - contains = list(/obj/item/stack/tile/carpetpurple/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/purple/fifty) containername = "purple carpet crate" /decl/hierarchy/supply_pack/flooring/carpetorange name = "Orange carpet" - contains = list(/obj/item/stack/tile/carpetorange/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/orange/fifty) containername = "orange carpet crate" /decl/hierarchy/supply_pack/flooring/carpetgreen name = "Green carpet" - contains = list(/obj/item/stack/tile/carpetgreen/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/green/fifty) containername = "green carpet crate" /decl/hierarchy/supply_pack/flooring/carpetred name = "Red carpet" - contains = list(/obj/item/stack/tile/carpetred/fifty) - cost = 15 + contains = list(/obj/item/stack/tile/carpet/red/fifty) containername = "red carpet crate" /decl/hierarchy/supply_pack/flooring/linoleum name = "Linoleum" contains = list(/obj/item/stack/tile/linoleum/fifty) - cost = 15 containername = "linoleum crate" /decl/hierarchy/supply_pack/flooring/white_tiles name = "White floor tiles" contains = list(/obj/item/stack/tile/floor_white/fifty) - cost = 15 containername = "white floor tile crate" /decl/hierarchy/supply_pack/flooring/dark_tiles name = "Dark floor tiles" contains = list(/obj/item/stack/tile/floor_dark/fifty) - cost = 15 containername = "dark floor tile crate" /decl/hierarchy/supply_pack/flooring/freezer_tiles name = "Freezer floor tiles" contains = list(/obj/item/stack/tile/floor_freezer/fifty) - cost = 15 containername = "freezer floor tile crate" diff --git a/code/datums/supplypacks/galley.dm b/code/datums/supplypacks/galley.dm index e95e559ca53c..2244e737d4e9 100644 --- a/code/datums/supplypacks/galley.dm +++ b/code/datums/supplypacks/galley.dm @@ -3,64 +3,63 @@ /decl/hierarchy/supply_pack/galley/food name = "General - Kitchen supplies" - contains = list(/obj/item/chems/food/condiment/flour = 6, - /obj/item/chems/food/drinks/milk = 4, - /obj/item/chems/food/drinks/soymilk = 2, - /obj/item/storage/fancy/egg_box = 2, - /obj/item/chems/food/snacks/tofu = 4, - /obj/item/chems/food/snacks/meat = 4, - /obj/item/chems/food/condiment/enzyme = 1 + contains = list(/obj/item/chems/condiment/flour = 6, + /obj/item/chems/condiment/yeast = 1, + /obj/item/chems/drinks/milk = 4, + /obj/item/chems/drinks/soymilk = 2, + /obj/item/food/dairy/butter/stick = 2, + /obj/item/food/dairy/butter/stick/margarine = 2, + /obj/item/box/fancy/egg_box = 2, + /obj/item/food/tofu = 4, + /obj/item/food/butchery/meat = 4, + /obj/item/chems/condiment/enzyme = 1 ) - cost = 10 containertype = /obj/structure/closet/crate/freezer containername = "kitchen supplies crate" /decl/hierarchy/supply_pack/galley/beef name = "Perishables - Beef" - contains = list(/obj/item/chems/food/snacks/meat/beef = 6) + contains = list(/obj/item/food/butchery/meat/beef = 6) containertype = /obj/structure/closet/crate/freezer containername = "cow meat crate" - cost = 20 /decl/hierarchy/supply_pack/galley/goat name = "Perishables - Goat meat" - contains = list(/obj/item/chems/food/snacks/meat/goat = 6) + contains = list(/obj/item/food/butchery/meat/goat = 6) containertype = /obj/structure/closet/crate/freezer containername = "goat meat crate" - cost = 20 /decl/hierarchy/supply_pack/galley/chicken name = "Perishables - Poultry" - contains = list(/obj/item/chems/food/snacks/meat/chicken = 6) + contains = list(/obj/item/food/butchery/meat/chicken = 6) containertype = /obj/structure/closet/crate/freezer containername = "chicken meat crate" - cost = 20 /decl/hierarchy/supply_pack/galley/seafood name = "Perishables - Seafood" contains = list( - /obj/item/chems/food/snacks/fish = 3, - /obj/item/chems/food/snacks/fish/shark = 3, - /obj/item/chems/food/snacks/fish/octopus = 3, + /obj/item/food/butchery/meat/fish = 3, + /obj/item/food/butchery/meat/fish/shark = 3, + /obj/item/food/butchery/meat/fish/octopus = 3, /obj/item/mollusc/clam = 3 ) containertype = /obj/structure/closet/crate/freezer containername = "seafood crate" - cost = 30 /decl/hierarchy/supply_pack/galley/eggs name = "Perishables - Eggs" - contains = list(/obj/item/storage/fancy/egg_box = 2) + contains = list(/obj/item/box/fancy/egg_box = 2) containertype = /obj/structure/closet/crate/freezer containername = "egg crate" - cost = 15 /decl/hierarchy/supply_pack/galley/milk - name = "Perishables - Milk" - contains = list(/obj/item/chems/food/drinks/milk = 3) + name = "Perishables - Dairy" + contains = list( + /obj/item/chems/drinks/milk = 3, + /obj/item/food/dairy/butter/stick = 2 + ) containertype = /obj/structure/closet/crate/freezer containername = "milk crate" - cost = 15 /decl/hierarchy/supply_pack/galley/pizza num_contained = 5 @@ -69,25 +68,29 @@ /obj/item/pizzabox/mushroom, /obj/item/pizzabox/meat, /obj/item/pizzabox/vegetable) - cost = 15 containertype = /obj/structure/closet/crate/freezer containername = "pizza crate" supply_method = /decl/supply_method/randomized +/decl/hierarchy/supply_pack/galley/nuggets + name = "Emergency - Nugget crate" + contains = list(/obj/item/box/nuggets = 2) + containertype = /obj/structure/closet/crate/freezer + containername = "nugget crate" + /decl/hierarchy/supply_pack/galley/rations num_contained = 6 name = "Emergency - MREs" - contains = list(/obj/item/storage/mre, - /obj/item/storage/mre/menu2, - /obj/item/storage/mre/menu3, - /obj/item/storage/mre/menu4, - /obj/item/storage/mre/menu5, - /obj/item/storage/mre/menu6, - /obj/item/storage/mre/menu7, - /obj/item/storage/mre/menu8, - /obj/item/storage/mre/menu9, - /obj/item/storage/mre/menu10) - cost = 30 + contains = list(/obj/item/mre, + /obj/item/mre/menu2, + /obj/item/mre/menu3, + /obj/item/mre/menu4, + /obj/item/mre/menu5, + /obj/item/mre/menu6, + /obj/item/mre/menu7, + /obj/item/mre/menu8, + /obj/item/mre/menu9, + /obj/item/mre/menu10) containertype = /obj/structure/closet/crate/freezer containername = "emergency rations" supply_method = /decl/supply_method/randomized @@ -95,62 +98,75 @@ /decl/hierarchy/supply_pack/galley/party name = "Bar - Party equipment" contains = list( - /obj/item/storage/box/mixedglasses = 2, - /obj/item/storage/box/glasses/square, - /obj/item/chems/food/drinks/shaker, - /obj/item/chems/food/drinks/flask/barflask, - /obj/item/chems/food/drinks/bottle/patron, - /obj/item/chems/food/drinks/bottle/goldschlager, - /obj/item/chems/food/drinks/bottle/agedwhiskey, - /obj/item/storage/fancy/cigarettes/dromedaryco, - /obj/random/lipstick, - /obj/item/chems/food/drinks/bottle/small/ale = 2, - /obj/item/chems/food/drinks/bottle/small/beer = 4, - /obj/item/storage/box/glowsticks = 2) - cost = 20 + /obj/item/box/mixedglasses = 2, + /obj/item/box/glasses/square, + /obj/item/chems/drinks/shaker, + /obj/item/chems/drinks/flask/barflask, + /obj/item/chems/drinks/bottle/patron, + /obj/item/chems/drinks/bottle/goldschlager, + /obj/item/chems/drinks/bottle/agedwhiskey, + /obj/item/box/fancy/cigarettes/dromedaryco, + /obj/random/lipstick = 2, + /obj/item/chems/drinks/bottle/small/ale = 2, + /obj/item/chems/drinks/bottle/small/beer = 4, + /obj/item/box/glowsticks = 2) containername = "party equipment crate" // TODO; Add more premium drinks at a later date. Could be useful for diplomatic events or fancy parties. /decl/hierarchy/supply_pack/galley/premiumalcohol name = "Bar - Premium drinks" - contains = list(/obj/item/chems/food/drinks/bottle/premiumwine = 1, - /obj/item/chems/food/drinks/bottle/premiumvodka = 1) - cost = 60 - containertype = /obj/structure/closet/crate/freezer + contains = list( + /obj/item/chems/drinks/bottle/premiumwine = 3, + /obj/item/chems/drinks/bottle/premiumvodka = 3, + /obj/item/chems/drinks/bottle/whiskey = 3 + ) + containertype = /obj/structure/closet/crate/plastic containername = "premium drinks crate" /decl/hierarchy/supply_pack/galley/barsupplies name = "Bar - Bar supplies" contains = list( - /obj/item/storage/box/glasses/cocktail, - /obj/item/storage/box/glasses/rocks, - /obj/item/storage/box/glasses/square, - /obj/item/storage/box/glasses/pint, - /obj/item/storage/box/glasses/wine, - /obj/item/storage/box/glasses/shake, - /obj/item/storage/box/glasses/shot, - /obj/item/storage/box/glasses/mug, - /obj/item/chems/food/drinks/shaker, - /obj/item/storage/box/glass_extras/straws, - /obj/item/storage/box/glass_extras/sticks + /obj/item/box/glasses/cocktail, + /obj/item/box/glasses/rocks, + /obj/item/box/glasses/square, + /obj/item/box/glasses/pint, + /obj/item/box/glasses/wine, + /obj/item/box/glasses/shake, + /obj/item/box/glasses/shot, + /obj/item/box/glasses/mug, + /obj/item/chems/drinks/shaker, + /obj/item/box/glass_extras/straws, + /obj/item/box/glass_extras/sticks ) - cost = 10 containername = "bar supplies crate" /decl/hierarchy/supply_pack/galley/beer_dispenser name = "Equipment - Booze dispenser" contains = list( - /obj/machinery/chemical_dispenser/bar_alc{anchored = 0} + /obj/machinery/chemical_dispenser/bar_alc/unanchored ) - cost = 25 containertype = /obj/structure/largecrate containername = "booze dispenser crate" /decl/hierarchy/supply_pack/galley/soda_dispenser name = "Equipment - Soda dispenser" contains = list( - /obj/machinery/chemical_dispenser/bar_soft{anchored = 0} + /obj/machinery/chemical_dispenser/bar_soft/unanchored ) - cost = 25 containertype = /obj/structure/largecrate containername = "soda dispenser crate" + + +/decl/hierarchy/supply_pack/galley/flour + name = "Non-perishables - Flour" + contains = list( + /obj/item/chems/condiment/flour = 3 + ) + containername = "yeast crate" + +/decl/hierarchy/supply_pack/galley/yeast + name = "Non-perishables - Yeast" + contains = list( + /obj/item/chems/condiment/yeast = 3 + ) + containername = "yeast crate" diff --git a/code/datums/supplypacks/hydroponics.dm b/code/datums/supplypacks/hydroponics.dm index 4fc6a620f011..bb368c5898ba 100644 --- a/code/datums/supplypacks/hydroponics.dm +++ b/code/datums/supplypacks/hydroponics.dm @@ -6,15 +6,14 @@ name = "Gear - Hydroponics Supplies" contains = list(/obj/item/chems/spray/plantbgone = 4, /obj/item/chems/glass/bottle/ammonia = 2, - /obj/item/hatchet, - /obj/item/minihoe, + /obj/item/tool/axe/hatchet, + /obj/item/tool/hoe/mini, /obj/item/scanner/plant, /obj/item/clothing/gloves/thick/botany, /obj/item/clothing/suit/apron, - /obj/item/minihoe, - /obj/item/storage/box/botanydisk + /obj/item/tool/hoe/mini, + /obj/item/box/botanydisk ) - cost = 15 containername = "hydroponics supply crate" access = access_hydroponics @@ -37,17 +36,15 @@ /obj/item/seeds/chantermycelium, /obj/item/seeds/potatoseed, /obj/item/seeds/sugarcaneseed) - cost = 10 containername = "seeds crate" access = access_hydroponics /decl/hierarchy/supply_pack/hydroponics/weedcontrol name = "Gear - Weed control" - contains = list(/obj/item/hatchet = 2, + contains = list(/obj/item/tool/axe/hatchet = 2, /obj/item/chems/spray/plantbgone = 4, /obj/item/clothing/mask/gas = 2, /obj/item/grenade/chem_grenade/antiweed = 2) - cost = 25 containername = "weed control crate" access = access_hydroponics @@ -57,32 +54,13 @@ /obj/item/seeds/reishimycelium, /obj/item/seeds/random = 6, /obj/item/seeds/kudzuseed) - cost = 15 containertype = /obj/structure/closet/crate/secure containername = "exotic Seeds crate" access = access_xenobiology -/decl/hierarchy/supply_pack/hydroponics/watertank - name = "Liquid - Water tank" - contains = list(/obj/structure/reagent_dispensers/watertank) - cost = 8 - containertype = /obj/structure/largecrate - containername = "water tank crate" - -/decl/hierarchy/supply_pack/hydroponics/bee_keeper - name = "Equipment - Beekeeping" - contains = list(/obj/item/beehive_assembly, - /obj/item/bee_smoker, - /obj/item/honey_frame = 5, - /obj/item/bee_pack) - cost = 40 - containername = "beekeeping crate" - access = access_hydroponics - /decl/hierarchy/supply_pack/hydroponics/hydrotray name = "Equipment - Hydroponics tray" - contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0}) - cost = 30 + contains = list(/obj/machinery/portable_atmospherics/hydroponics) containertype = /obj/structure/closet/crate/large/hydroponics containername = "hydroponics tray crate" access = access_hydroponics @@ -117,7 +95,6 @@ /obj/structure/flora/pottedplant/tropical, /obj/structure/flora/pottedplant/dead, /obj/structure/flora/pottedplant/decorative) - cost = 8 containertype = /obj/structure/closet/crate/large/hydroponics containername = "potted plant crate" supply_method = /decl/supply_method/randomized \ No newline at end of file diff --git a/code/datums/supplypacks/livecargo.dm b/code/datums/supplypacks/livecargo.dm index 336b209b7adc..4013f1887b24 100644 --- a/code/datums/supplypacks/livecargo.dm +++ b/code/datums/supplypacks/livecargo.dm @@ -4,55 +4,71 @@ /decl/hierarchy/supply_pack/livecargo/monkey name = "Inert - Monkey cubes" - contains = list (/obj/item/storage/box/monkeycubes) - cost = 20 + contains = list (/obj/item/box/animal_cubes/monkeys) containertype = /obj/structure/closet/crate/freezer containername = "monkey crate" /decl/hierarchy/supply_pack/livecargo/spidercubes - name = "Inert - Spiders" - contains = list(/obj/item/storage/box/monkeycubes/spidercubes) - cost = 50 + name = "Inert - Spider Cubes" + contains = list(/obj/item/box/animal_cubes/spiders) containertype = /obj/structure/closet/crate/secure - containername = "\improper Spiderling crate" - contraband = 1 - security_level = null + containername = "spiderling crate" + access = access_research +/decl/hierarchy/supply_pack/livecargo/carpcubes + name = "Inert - Space Carp Cubes" + contains = list(/obj/item/box/animal_cubes/carp) + containertype = /obj/structure/closet/crate/secure + containername = "space carp crate" + access = access_chemistry -//actual live animals +//actual live animals /decl/hierarchy/supply_pack/livecargo/corgi name = "Live - Corgi" - contains = list() - cost = 50 - containertype = /obj/structure/largecrate/animal/corgi + contains = list(/mob/living/simple_animal/corgi) + containertype = /obj/structure/largecrate/animal containername = "corgi crate" //farm animals - useless and annoying, but potentially a good source of food. expensive because they're live animals and their produce is available cheaper /decl/hierarchy/supply_pack/livecargo/cow name = "Live - Cow" - cost = 80 - containertype = /obj/structure/largecrate/animal/cow + contains = list(/mob/living/simple_animal/cow) + containertype = /obj/structure/largecrate/animal containername = "cow crate" access = access_hydroponics /decl/hierarchy/supply_pack/livecargo/goat name = "Live - Goat" - cost = 75 - containertype = /obj/structure/largecrate/animal/goat + contains = list(/mob/living/simple_animal/hostile/goat) + containertype = /obj/structure/largecrate/animal containername = "goat crate" access = access_hydroponics +/decl/hierarchy/supply_pack/livecargo/sheep + name = "Live - Sheep" + contains = list(/mob/living/simple_animal/passive/sheep) + containertype = /obj/structure/largecrate/animal + containername = "sheep crate" + access = access_hydroponics + /decl/hierarchy/supply_pack/livecargo/goose name = "Live - Goose" - cost = 75 - containertype = /obj/structure/largecrate/animal/goose + contains = list(/mob/living/simple_animal/hostile/goose) + containertype = /obj/structure/largecrate/animal containername = "goose containment unit" access = access_hydroponics /decl/hierarchy/supply_pack/livecargo/chicken name = "Live - Chicken" - cost = 70 - containertype = /obj/structure/largecrate/animal/chick + contains = list(/mob/living/simple_animal/chick = 5) + containertype = /obj/structure/largecrate/animal containername = "chicken crate" - access = access_hydroponics \ No newline at end of file + access = access_hydroponics + +/decl/hierarchy/supply_pack/livecargo/duck + name = "Live - Duck" + contains = list(/mob/living/simple_animal/fowl/duck = 3) + containertype = /obj/structure/largecrate/animal + containername = "duck crate" + access = access_hydroponics diff --git a/code/datums/supplypacks/materials.dm b/code/datums/supplypacks/materials.dm index d952f1305a55..687c8d925d44 100644 --- a/code/datums/supplypacks/materials.dm +++ b/code/datums/supplypacks/materials.dm @@ -1,116 +1,133 @@ /decl/hierarchy/supply_pack/materials name = "Materials" - cost = null -W + // Material sheets (50 - full stack) /decl/hierarchy/supply_pack/materials/steel50 name = "50 steel sheets" - contains = list(/obj/item/stack/material/steel/fifty) + contains = list(/obj/item/stack/material/sheet/mapped/steel/fifty) containername = "steel sheets crate" /decl/hierarchy/supply_pack/materials/alum50 name = "50 aluminium sheets" - contains = list(/obj/item/stack/material/aluminium/fifty) + contains = list(/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty) containername = "aluminium sheets crate" /decl/hierarchy/supply_pack/materials/glass50 name = "50 glass sheets" - contains = list(/obj/item/stack/material/glass/fifty) + contains = list(/obj/item/stack/material/pane/mapped/glass/fifty) containername = "glass sheets crate" +/decl/hierarchy/supply_pack/materials/fiberglass50 + name = "50 fiberglass sheets" + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty) + containername = "fiberglass sheets crate" + /decl/hierarchy/supply_pack/materials/plastic50 name = "50 plastic sheets" - contains = list(/obj/item/stack/material/plastic/fifty) + contains = list(/obj/item/stack/material/panel/mapped/plastic/fifty) containername = "plastic sheets crate" /decl/hierarchy/supply_pack/materials/marble50 name = "50 slabs of marble" - contains = list(/obj/item/stack/material/marble/fifty) + contains = list(/obj/item/stack/material/brick/mapped/marble/fifty) containername = "marble slabs crate" /decl/hierarchy/supply_pack/materials/plasteel50 name = "50 plasteel sheets" - contains = list(/obj/item/stack/material/plasteel/fifty) + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty) containername = "plasteel sheets crate" +/decl/hierarchy/supply_pack/materials/copper50 + name = "50 copper ingots" + contains = list(/obj/item/stack/material/ingot/mapped/copper/fifty) + containername = "copper ingots crate" + /decl/hierarchy/supply_pack/materials/titanium50 name = "50 titanium sheets" - contains = list(/obj/item/stack/material/titanium/fifty) + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/titanium/fifty) containername = "titanium sheets crate" /decl/hierarchy/supply_pack/materials/ocp50 name = "50 osmium carbide plasteel sheets" - contains = list(/obj/item/stack/material/ocp/fifty) + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/ocp/fifty) containername = "osmium carbide plasteel sheets crate" +/decl/hierarchy/supply_pack/materials/graphite50 + name = "50 graphite bricks" + contains = list(/obj/item/stack/material/brick/mapped/graphite/fifty) + // Material sheets (10 - Smaller amounts, less cost efficient) /decl/hierarchy/supply_pack/materials/marble10 name = "10 slabs of marble" - contains = list(/obj/item/stack/material/marble/ten) + contains = list(/obj/item/stack/material/brick/mapped/marble/ten) containername = "marble slabs crate" /decl/hierarchy/supply_pack/materials/plasteel10 name = "10 plasteel sheets" - contains = list(/obj/item/stack/material/plasteel/ten) + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten) containername = "plasteel sheets crate" /decl/hierarchy/supply_pack/materials/titanium10 name = "10 titanium sheets" - contains = list(/obj/item/stack/material/titanium/ten) + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/titanium/ten) containername = "titanium sheets crate" /decl/hierarchy/supply_pack/materials/ocp10 name = "10 osmium carbide plasteel sheets" - contains = list(/obj/item/stack/material/ocp/ten) + contains = list(/obj/item/stack/material/sheet/reinforced/mapped/ocp/ten) containername = "osmium carbide plasteel sheets crate" /decl/hierarchy/supply_pack/materials/gold10 name = "10 gold sheets" - contains = list(/obj/item/stack/material/gold/ten) + contains = list(/obj/item/stack/material/ingot/mapped/gold/ten) containername = "gold sheets crate" /decl/hierarchy/supply_pack/materials/silver10 name = "10 silver sheets" - contains = list(/obj/item/stack/material/silver/ten) + contains = list(/obj/item/stack/material/ingot/mapped/silver/ten) containername = "silver sheets crate" /decl/hierarchy/supply_pack/materials/uranium10 name = "10 uranium sheets" - contains = list(/obj/item/stack/material/uranium/ten) + contains = list(/obj/item/stack/material/puck/mapped/uranium/ten) containername = "uranium sheets crate" /decl/hierarchy/supply_pack/materials/diamond10 name = "10 diamond sheets" - contains = list(/obj/item/stack/material/diamond/ten) + contains = list(/obj/item/stack/material/gemstone/mapped/diamond/ten) containername = "diamond sheets crate" +/decl/hierarchy/supply_pack/materials/graphite10 + name = "10 graphite bricks" + contains = list(/obj/item/stack/material/brick/mapped/graphite/ten) + //wood zone /decl/hierarchy/supply_pack/materials/wood50 name = "50 wooden planks" - contains = list(/obj/item/stack/material/wood/fifty) + contains = list(/obj/item/stack/material/plank/mapped/wood/fifty) containername = "wooden planks crate" /decl/hierarchy/supply_pack/materials/mahogany25 name = "25 mahogany planks" - contains = list(/obj/item/stack/material/wood/mahogany/twentyfive) + contains = list(/obj/item/stack/material/plank/mapped/mahogany/twentyfive) containername = "mahogany planks crate" /decl/hierarchy/supply_pack/materials/maple50 name = "50 maple planks" - contains = list(/obj/item/stack/material/wood/maple/twentyfive = 2) + contains = list(/obj/item/stack/material/plank/mapped/maple/fifty) containername = "maple planks crate" /decl/hierarchy/supply_pack/materials/walnut25 name = "25 walnut planks" - contains = list(/obj/item/stack/material/wood/walnut/twentyfive) + contains = list(/obj/item/stack/material/plank/mapped/walnut/twentyfive) containername = "walnut planks crate" /decl/hierarchy/supply_pack/materials/ebony25 name = "25 ebony planks" - contains = list(/obj/item/stack/material/wood/ebony/twentyfive) + contains = list(/obj/item/stack/material/plank/mapped/ebony/twentyfive) containername = "ebony planks crate" /decl/hierarchy/supply_pack/materials/yew25 name = "25 yew planks" - contains = list(/obj/item/stack/material/wood/yew/twentyfive) + contains = list(/obj/item/stack/material/plank/mapped/yew/twentyfive) containername = "yew planks crate" diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm index dd42d1c583b6..855a5d525731 100644 --- a/code/datums/supplypacks/medical.dm +++ b/code/datums/supplypacks/medical.dm @@ -4,207 +4,198 @@ /decl/hierarchy/supply_pack/medical/medical name = "Refills - Medical supplies" - contains = list(/obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/trauma, - /obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/adv, - /obj/item/storage/firstaid/stab, + contains = list(/obj/item/firstaid/regular, + /obj/item/firstaid/trauma, + /obj/item/firstaid/fire, + /obj/item/firstaid/toxin, + /obj/item/firstaid/o2, + /obj/item/firstaid/adv, + /obj/item/firstaid/stab, /obj/item/chems/glass/bottle/antitoxin, /obj/item/chems/glass/bottle/stabilizer, /obj/item/chems/glass/bottle/sedatives, - /obj/item/storage/box/syringes, - /obj/item/storage/box/autoinjectors) - cost = 70 + /obj/item/box/syringes, + /obj/item/box/autoinjectors) containername = "medical crate" /decl/hierarchy/supply_pack/medical/atk name = "Triage - Advanced trauma supplies" - contains = list(/obj/item/stack/medical/advanced/bruise_pack = 6) - cost = 30 + contains = list(/obj/item/stack/medical/bandage/advanced = 6) containername = "advanced trauma crate" /decl/hierarchy/supply_pack/medical/abk name = "Triage - Advanced burn supplies" - contains = list(/obj/item/stack/medical/advanced/ointment = 6) - cost = 30 + contains = list(/obj/item/stack/medical/ointment/advanced = 6) containername = "advanced burn crate" /decl/hierarchy/supply_pack/medical/trauma name = "EMERGENCY - Trauma pouches" - contains = list(/obj/item/storage/firstaid/trauma = 3) - cost = 10 + contains = list(/obj/item/firstaid/trauma = 3) containername = "trauma pouch crate" /decl/hierarchy/supply_pack/medical/burn name = "EMERGENCY - Burn pouches" - contains = list(/obj/item/storage/firstaid/fire = 3) - cost = 10 + contains = list(/obj/item/firstaid/fire = 3) containername = "burn pouch crate" /decl/hierarchy/supply_pack/medical/toxin name = "EMERGENCY - Toxin pouches" - contains = list(/obj/item/storage/firstaid/toxin = 3) - cost = 10 + contains = list(/obj/item/firstaid/toxin = 3) containername = "toxin pouch crate" /decl/hierarchy/supply_pack/medical/oxyloss name = "EMERGENCY - Low oxygen pouches" - contains = list(/obj/item/storage/firstaid/o2 = 3) - cost = 10 + contains = list(/obj/item/firstaid/o2 = 3) containername = "low oxygen pouch crate" /decl/hierarchy/supply_pack/medical/stab name = "Triage - Stability kit" - contains = list(/obj/item/storage/firstaid/stab = 3) - cost = 60 + contains = list(/obj/item/firstaid/stab = 3) containername = "stability kit crate" +/decl/hierarchy/supply_pack/medical/clotting + name = "EMERGENCY - Clotting kit" + contains = list(/obj/item/firstaid/clotting = 3) + containername = "clotting kit crate" + /decl/hierarchy/supply_pack/medical/bloodpack - name = "Refills - Blood packs" - contains = list(/obj/item/storage/box/bloodpacks = 3) - cost = 10 + name = "Refills - Blood Bags (Empty)" + contains = list(/obj/item/box/bloodpacks = 3) containername = "blood pack crate" /decl/hierarchy/supply_pack/medical/blood - name = "Refills - Nanoblood" - contains = list(/obj/item/chems/ivbag/nanoblood = 4) - cost = 15 - containername = "nanoblood crate" + name = "Refills - Synthetic Blood" + contains = list(/obj/item/chems/ivbag/blood/nanoblood = 4) + containername = "synthetic blood crate" /decl/hierarchy/supply_pack/medical/bodybag name = "Equipment - Body bags" - contains = list(/obj/item/storage/box/bodybags = 3) - cost = 10 + contains = list(/obj/item/box/bodybags = 3) containername = "body bag crate" /decl/hierarchy/supply_pack/medical/stretcher name = "Equipment - Roller bed crate" contains = list(/obj/item/roller = 3) - cost = 10 containername = "\improper Roller bed crate" /decl/hierarchy/supply_pack/medical/wheelchair name = "Equipment - Wheelchair crate" - contains = list(/obj/structure/bed/chair/wheelchair) - cost = 15 + contains = list(/obj/structure/chair/wheelchair) containertype = /obj/structure/closet/crate/large containername = "\improper Wheelchair crate" /decl/hierarchy/supply_pack/medical/rescuebag name = "Equipment - Rescue bags" contains = list(/obj/item/bodybag/rescue = 3) - cost = 30 containername = "\improper Rescue bag crate" /decl/hierarchy/supply_pack/medical/medicalextragear name = "Gear - Medical surplus equipment" - contains = list(/obj/item/storage/belt/medical = 3, + contains = list(/obj/item/belt/medical = 3, /obj/item/clothing/glasses/hud/health = 3) - cost = 15 containertype = /obj/structure/closet/crate/secure containername = "medical surplus equipment crate" access = access_medical /decl/hierarchy/supply_pack/medical/cmogear name = "Gear - Chief medical officer equipment" - contains = list(/obj/item/storage/belt/medical, + contains = list(/obj/item/belt/medical, /obj/item/radio/headset/heads/cmo, - /obj/item/clothing/under/rank/chief_medical_officer, + /obj/item/clothing/jumpsuit/chief_medical_officer, /obj/item/chems/hypospray/vial, - /obj/item/clothing/accessory/stethoscope, + /obj/item/clothing/neck/stethoscope, /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/suit/storage/toggle/labcoat/cmo, - /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/clothing/suit/toggle/labcoat/cmo, + /obj/item/clothing/suit/toggle/labcoat/cmoalt, /obj/item/clothing/mask/surgical, /obj/item/clothing/shoes/color/white, /obj/item/clothing/gloves/latex, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/flashlight/pen, /obj/item/chems/syringe) - cost = 60 containertype = /obj/structure/closet/crate/secure containername = "chief medical officer equipment crate" access = access_cmo /decl/hierarchy/supply_pack/medical/doctorgear name = "Gear - Medical Doctor equipment" - contains = list(/obj/item/storage/belt/medical, + contains = list(/obj/item/belt/medical, /obj/item/radio/headset/headset_med, - /obj/item/clothing/under/rank/medical, - /obj/item/clothing/accessory/stethoscope, + /obj/item/clothing/jumpsuit/medical, + /obj/item/clothing/neck/stethoscope, /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/mask/surgical, - /obj/item/storage/firstaid/adv, + /obj/item/firstaid/adv, /obj/item/clothing/shoes/color/white, /obj/item/clothing/gloves/latex, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/flashlight/pen, /obj/item/chems/syringe) - cost = 20 containertype = /obj/structure/closet/crate/secure containername = "medical Doctor equipment crate" access = access_medical_equip /decl/hierarchy/supply_pack/medical/chemistgear name = "Gear - Pharmacist equipment" - contains = list(/obj/item/storage/box/beakers, + contains = list(/obj/item/box/beakers, /obj/item/radio/headset/headset_med, - /obj/item/storage/box/autoinjectors, - /obj/item/clothing/under/rank/chemist, + /obj/item/box/autoinjectors, + /obj/item/clothing/jumpsuit/chemist, /obj/item/clothing/glasses/science, - /obj/item/clothing/suit/storage/toggle/labcoat/chemist, + /obj/item/clothing/suit/toggle/labcoat/chemist, /obj/item/clothing/mask/surgical, /obj/item/clothing/shoes/color/white, /obj/item/clothing/gloves/latex, /obj/item/chems/dropper, /obj/item/scanner/health, - /obj/item/storage/box/pillbottles, + /obj/item/scanner/breath, + /obj/item/box/pillbottles, /obj/item/chems/syringe) - cost = 15 containertype = /obj/structure/closet/crate/secure containername = "pharmacist equipment crate" access = access_chemistry /decl/hierarchy/supply_pack/medical/paramedicgear name = "Gear - Paramedic equipment" - contains = list(/obj/item/storage/belt/medical/emt, + contains = list(/obj/item/belt/medical/emt, /obj/item/radio/headset/headset_med, - /obj/item/clothing/under/rank/medical/scrubs/black, - /obj/item/clothing/accessory/armband/medgreen, + /obj/item/clothing/pants/scrubs/black, + /obj/item/clothing/shirt/scrubs/black, + /obj/item/clothing/armband/medgreen, /obj/item/clothing/glasses/hud/health, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/suit/storage/toggle/fr_jacket, + /obj/item/clothing/suit/toggle/labcoat, + /obj/item/clothing/jumpsuit/medical, + /obj/item/clothing/suit/jacket/first_responder, /obj/item/clothing/mask/gas, - /obj/item/clothing/under/rank/medical/paramedic, - /obj/item/clothing/accessory/stethoscope, - /obj/item/storage/firstaid/adv, + /obj/item/clothing/jumpsuit/medical/paramedic, + /obj/item/clothing/neck/stethoscope, + /obj/item/firstaid/adv, /obj/item/clothing/shoes/jackboots, /obj/item/clothing/gloves/latex, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/flashlight/pen, /obj/item/chems/syringe, - /obj/item/clothing/accessory/storage/white_vest) - cost = 20 + /obj/item/clothing/webbing/vest) containertype = /obj/structure/closet/crate/secure containername = "paramedic equipment crate" access = access_medical_equip /decl/hierarchy/supply_pack/medical/psychiatristgear name = "Gear - Psychiatrist equipment" - contains = list(/obj/item/clothing/under/rank/psych, + contains = list(/obj/item/clothing/jumpsuit/psych, /obj/item/radio/headset/headset_med, - /obj/item/clothing/under/rank/psych/turtleneck, + /obj/item/clothing/shirt/sweater/turquoise, + /obj/item/clothing/pants/slacks/navy, /obj/item/clothing/shoes/dress, - /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/shoes/color/white, /obj/item/clipboard, /obj/item/folder/cyan, /obj/item/pen) - cost = 15 containertype = /obj/structure/closet/crate/secure containername = "psychiatrist equipment crate" access = access_psychiatrist @@ -212,17 +203,20 @@ /decl/hierarchy/supply_pack/medical/medicalscrubs name = "Gear - Medical scrubs" contains = list(/obj/item/clothing/shoes/color/white = 4, - /obj/item/clothing/under/rank/medical/scrubs/blue, - /obj/item/clothing/under/rank/medical/scrubs/green, - /obj/item/clothing/under/rank/medical/scrubs/purple, - /obj/item/clothing/under/rank/medical/scrubs/black, + /obj/item/clothing/pants/scrubs/blue, + /obj/item/clothing/pants/scrubs/green, + /obj/item/clothing/pants/scrubs/purple, + /obj/item/clothing/pants/scrubs/black, + /obj/item/clothing/shirt/scrubs/blue, + /obj/item/clothing/shirt/scrubs/green, + /obj/item/clothing/shirt/scrubs/purple, + /obj/item/clothing/shirt/scrubs/black, /obj/item/clothing/head/surgery/black, /obj/item/clothing/head/surgery/purple, /obj/item/clothing/head/surgery/blue, /obj/item/clothing/head/surgery/green, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves) - cost = 15 + /obj/item/box/masks, + /obj/item/box/gloves) containertype = /obj/structure/closet/crate/secure containername = "medical scrubs crate" access = access_medical_equip @@ -234,10 +228,9 @@ /obj/item/camera_film = 2, /obj/item/scanner/autopsy, /obj/item/scalpel, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves, + /obj/item/box/masks, + /obj/item/box/gloves, /obj/item/pen) - cost = 20 containertype = /obj/structure/closet/crate/secure containername = "autopsy equipment crate" access = access_morgue @@ -245,23 +238,23 @@ /decl/hierarchy/supply_pack/medical/medicaluniforms name = "Gear - Medical uniforms" contains = list(/obj/item/clothing/shoes/color/white = 3, - /obj/item/clothing/under/rank/chief_medical_officer, - /obj/item/clothing/under/rank/geneticist, - /obj/item/clothing/under/rank/virologist, - /obj/item/clothing/under/rank/nursesuit, - /obj/item/clothing/under/rank/nurse, - /obj/item/clothing/under/rank/orderly, - /obj/item/clothing/under/rank/medical = 3, - /obj/item/clothing/under/rank/medical/paramedic = 3, - /obj/item/clothing/suit/storage/toggle/labcoat = 3, - /obj/item/clothing/suit/storage/toggle/labcoat/cmo, - /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, - /obj/item/clothing/suit/storage/toggle/labcoat/genetics, - /obj/item/clothing/suit/storage/toggle/labcoat/virologist, - /obj/item/clothing/suit/storage/toggle/labcoat/chemist, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves) - cost = 15 + /obj/item/clothing/jumpsuit/chief_medical_officer, + /obj/item/clothing/jumpsuit/geneticist, + /obj/item/clothing/jumpsuit/virologist, + /obj/item/clothing/dress/nurse = 2, + /obj/item/clothing/pants/slacks/white/orderly, + /obj/item/clothing/shirt/button/orderly, + /obj/item/clothing/neck/tie/long/red, + /obj/item/clothing/jumpsuit/medical = 3, + /obj/item/clothing/jumpsuit/medical/paramedic = 3, + /obj/item/clothing/suit/toggle/labcoat = 3, + /obj/item/clothing/suit/toggle/labcoat/cmo, + /obj/item/clothing/suit/toggle/labcoat/cmoalt, + /obj/item/clothing/suit/toggle/labcoat/genetics, + /obj/item/clothing/suit/toggle/labcoat/virologist, + /obj/item/clothing/suit/toggle/labcoat/chemist, + /obj/item/box/masks, + /obj/item/box/gloves) containertype = /obj/structure/closet/crate/secure containername = "medical uniform crate" access = access_medical_equip @@ -274,17 +267,15 @@ /obj/item/clothing/suit/bio_suit/cmo = 2, /obj/item/clothing/mask/gas = 5, /obj/item/tank/oxygen = 5, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves) - cost = 50 + /obj/item/box/masks, + /obj/item/box/gloves) containertype = /obj/structure/closet/crate/secure containername = "medical biohazard equipment crate" access = access_medical_equip /decl/hierarchy/supply_pack/medical/portablefreezers name = "Equipment - Portable freezers" - contains = list(/obj/item/storage/box/freezer = 7) - cost = 25 + contains = list(/obj/item/box/freezer = 7) containertype = /obj/structure/closet/crate/secure containername = "portable freezers crate" access = access_medical_equip @@ -294,7 +285,6 @@ contains = list(/obj/item/cautery, /obj/item/surgicaldrill, /obj/item/clothing/mask/breath/medical, - /obj/item/tank/anesthetic, /obj/item/sutures, /obj/item/hemostat, /obj/item/scalpel, @@ -302,26 +292,24 @@ /obj/item/retractor, /obj/item/bonesetter, /obj/item/circular_saw) - cost = 25 containertype = /obj/structure/closet/crate/secure containername = "surgery crate" access = access_medical /decl/hierarchy/supply_pack/medical/sterile name = "Gear - Sterile clothes" - contains = list(/obj/item/clothing/under/rank/medical/scrubs/green = 2, + contains = list(/obj/item/clothing/pants/scrubs/green = 2, + /obj/item/clothing/shirt/scrubs/green = 2, /obj/item/clothing/head/surgery/green = 2, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves, - /obj/item/storage/belt/medical = 3) - cost = 15 + /obj/item/box/masks, + /obj/item/box/gloves, + /obj/item/belt/medical = 3) containertype = /obj/structure/closet/crate containername = "sterile clothes crate" /decl/hierarchy/supply_pack/medical/scanner_module name = "Electronics - Medical scanner modules" contains = list(/obj/item/stock_parts/computer/scanner/medical = 4) - cost = 20 containername = "medical scanner module crate" containertype = /obj/structure/closet/crate/secure access = access_medical_equip @@ -329,7 +317,6 @@ /decl/hierarchy/supply_pack/medical/defib name = "Electronics - Defibrilator crate" contains = list(/obj/item/defibrillator) - cost = 60 containername = "\improper Defibrilator crate" containertype = /obj/structure/closet/crate/secure access = access_medical_equip @@ -337,7 +324,6 @@ /decl/hierarchy/supply_pack/medical/beltdefib name = "Electronics - Compact Defibrilator crate" contains = list(/obj/item/defibrillator/compact) - cost = 75 containername = "\improper Compact Defibrilator crate" containertype = /obj/structure/closet/crate/secure access = access_medical_equip @@ -345,7 +331,6 @@ /decl/hierarchy/supply_pack/medical/autocomp name = "Electronics - Auto-Compressor crate" contains = list(/obj/item/auto_cpr) - cost = 50 containername = "\improper Auto-Compressor crate" containertype = /obj/structure/closet/crate/secure access = access_medical_equip \ No newline at end of file diff --git a/code/datums/supplypacks/munitions.dm b/code/datums/supplypacks/munitions.dm index 792786e38e42..0f3090d29b30 100644 --- a/code/datums/supplypacks/munitions.dm +++ b/code/datums/supplypacks/munitions.dm @@ -6,29 +6,23 @@ /decl/hierarchy/supply_pack/munition/md_slug name = "Ammo - Mass Driver Slug" contains = list(/obj/structure/ship_munition/md_slug) - cost = 50 /decl/hierarchy/supply_pack/munition/ap_slug name = "Ammo - Armor Piercing Mass Driver Slug" contains = list(/obj/structure/ship_munition/ap_slug) - cost = 60 /decl/hierarchy/supply_pack/munition/fire name = "Ammo - disperser-FR1-ENFER charge" contains = list(/obj/structure/ship_munition/disperser_charge/fire) - cost = 40 /decl/hierarchy/supply_pack/munition/emp name = "Ammo - disperser-EM2-QUASAR charge" contains = list(/obj/structure/ship_munition/disperser_charge/emp) - cost = 40 /decl/hierarchy/supply_pack/munition/mining name = "Ammo - disperser-MN3-BERGBAU charge" contains = list(/obj/structure/ship_munition/disperser_charge/mining) - cost = 40 /decl/hierarchy/supply_pack/munition/explosive name = "Ammo - disperser-XP4-INDARRA charge" contains = list(/obj/structure/ship_munition/disperser_charge/explosive) - cost = 40 \ No newline at end of file diff --git a/code/datums/supplypacks/nonessent.dm b/code/datums/supplypacks/nonessent.dm index 067bcf9b6efe..bfbf2e87f4aa 100644 --- a/code/datums/supplypacks/nonessent.dm +++ b/code/datums/supplypacks/nonessent.dm @@ -3,31 +3,30 @@ /decl/hierarchy/supply_pack/nonessent/painters name = "Art - Painting Supplies" - contains = list(/obj/item/pipe_painter = 2, - /obj/item/floor_painter = 2, + contains = list(/obj/item/paint_sprayer = 2, /obj/item/cable_painter = 2) - cost = 10 containername = "painting supplies crate" containertype = /obj/structure/closet/crate /decl/hierarchy/supply_pack/nonessent/artscrafts name = "Art - Arts and Crafts supplies" - contains = list(/obj/item/storage/fancy/crayons, - /obj/item/camera, - /obj/item/camera_film = 2, - /obj/item/storage/photo_album, - /obj/item/stack/package_wrap/twenty_five, - /obj/item/chems/glass/paint/red, - /obj/item/chems/glass/paint/green, - /obj/item/chems/glass/paint/blue, - /obj/item/chems/glass/paint/yellow, - /obj/item/chems/glass/paint/purple, - /obj/item/chems/glass/paint/black, - /obj/item/chems/glass/paint/white, - /obj/item/contraband/poster, - /obj/item/wrapping_paper = 3) - cost = 10 - containername = "arts and Crafts crate" + contains = list( + /obj/item/box/fancy/crayons, + /obj/item/camera, + /obj/item/camera_film = 2, + /obj/item/photo_album, + /obj/item/chems/glass/bucket/paint/red, + /obj/item/chems/glass/bucket/paint/green, + /obj/item/chems/glass/bucket/paint/blue, + /obj/item/chems/glass/bucket/paint/yellow, + /obj/item/chems/glass/bucket/paint/purple, + /obj/item/chems/glass/bucket/paint/black, + /obj/item/chems/glass/bucket/paint/white, + /obj/item/poster, + /obj/item/stack/package_wrap/fifty = 2, + /obj/item/stack/package_wrap/gift/fifty = 2 + ) + containername = "arts and crafts crate" /decl/hierarchy/supply_pack/nonessent/card_packs @@ -36,7 +35,6 @@ /obj/item/pack/spaceball, /obj/item/deck/holder) name = "Rec - Trading Cards" - cost = 20 containername = "trading cards crate" supply_method = /decl/supply_method/randomized @@ -46,7 +44,6 @@ /obj/item/clothing/suit/redtag = 3, /obj/item/gun/energy/lasertag/blue = 3, /obj/item/clothing/suit/bluetag = 3) - cost = 20 containertype = /obj/structure/closet containername = "lasertag Closet" @@ -55,7 +52,6 @@ contains = list(/obj/item/synthesized_instrument/synthesizer, /obj/item/synthesized_instrument/guitar/multi, /obj/item/synthesized_instrument/trumpet) - cost = 40 containername = "musical instrument crate" @@ -71,74 +67,78 @@ /obj/item/flashlight/lamp/lava/purple, /obj/item/flashlight/lamp/lava/pink) name = "Deco - Lava lamps" - cost = 10 containername = "lava lamp crate" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/nonessent/wizard name = "Costume - Wizard" - contains = list(/obj/item/staff, - /obj/item/clothing/suit/wizrobe/fake, + contains = list(/obj/item/staff/crystal, + /obj/item/clothing/suit/wizrobe, /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/fake) - cost = 20 + /obj/item/clothing/head/wizard/beard) containername = "wizard costume crate" /decl/hierarchy/supply_pack/nonessent/costume num_contained = 2 contains = list(/obj/item/clothing/suit/pirate, /obj/item/clothing/suit/judgerobe, - /obj/item/clothing/accessory/wcoat/black, + /obj/item/clothing/suit/jacket/waistcoat/black, /obj/item/clothing/suit/hastur, /obj/item/clothing/suit/holidaypriest, /obj/item/clothing/suit/nun, /obj/item/clothing/suit/imperium_monk, /obj/item/clothing/suit/ianshirt, - /obj/item/clothing/under/gimmick/rank/captain/suit, - /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/under/rank/mailman, - /obj/item/clothing/under/dress/dress_saloon, - /obj/item/clothing/accessory/suspenders, - /obj/item/clothing/suit/storage/toggle/labcoat/mad, + /obj/item/clothing/costume/captain_suit, + /obj/item/clothing/costume/head_of_personnel_suit, + /obj/item/clothing/pants/slacks/purple, + /obj/item/clothing/shirt/button, + /obj/item/clothing/suit/jacket/vest/black, + /obj/item/clothing/costume/mailman, + /obj/item/clothing/dress/saloon, + /obj/item/clothing/suspenders, + /obj/item/clothing/suit/toggle/labcoat/mad, /obj/item/clothing/suit/bio_suit/plaguedoctorsuit, - /obj/item/clothing/under/schoolgirl, - /obj/item/clothing/under/owl, - /obj/item/clothing/under/waiter, - /obj/item/clothing/under/gladiator, - /obj/item/clothing/under/soviet, - /obj/item/clothing/under/scratch, - /obj/item/clothing/under/wedding/bride_white, + /obj/item/clothing/costume/schoolgirl, + /obj/item/clothing/costume/owl, + /obj/item/clothing/pants/slacks/black, + /obj/item/clothing/shirt/button, + /obj/item/clothing/neck/tie/bow/red, + /obj/item/clothing/suit/jacket/vest/blue, + /obj/item/clothing/costume/gladiator, + /obj/item/clothing/costume/soviet, + /obj/item/clothing/costume/scratch, + /obj/item/clothing/dress/wedding/bride_white, /obj/item/clothing/suit/chef, /obj/item/clothing/suit/apron/overalls, - /obj/item/clothing/under/redcoat, - /obj/item/clothing/under/kilt, - /obj/item/clothing/under/savage_hunter, - /obj/item/clothing/under/savage_hunter/female, - /obj/item/clothing/under/wetsuit) + /obj/item/clothing/costume/redcoat, + /obj/item/clothing/costume/kilt, + /obj/item/clothing/costume/savage_hunter, + /obj/item/clothing/costume/savage_hunter/female, + /obj/item/clothing/costume/wetsuit) name = "Costume - Random" - cost = 10 containername = "actor costumes crate" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/nonessent/formal_wear - contains = list(/obj/item/clothing/head/bowler, - /obj/item/clothing/head/that, - /obj/item/clothing/suit/storage/toggle/suit/blue, - /obj/item/clothing/suit/storage/toggle/suit/purple, - /obj/item/clothing/under/suit_jacket, - /obj/item/clothing/under/suit_jacket/female, - /obj/item/clothing/under/suit_jacket/really_black, - /obj/item/clothing/under/suit_jacket/red, - /obj/item/clothing/under/lawyer/bluesuit, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/shoes/color/black, - /obj/item/clothing/shoes/color/black, - /obj/item/clothing/shoes/craftable, - /obj/item/clothing/accessory/wcoat/black) + contains = list( + /obj/item/clothing/head/bowler, + /obj/item/clothing/head/that, + /obj/item/clothing/suit/jacket, + /obj/item/clothing/suit/jacket/blue, + /obj/item/clothing/suit/jacket/purple, + /obj/item/clothing/suit/jacket/black, + /obj/item/clothing/suit/jacket/burgundy, + /obj/item/clothing/suit/jacket/waistcoat, + /obj/item/clothing/costume/lawyer_bluesuit, + /obj/item/clothing/pants/slacks/purple, + /obj/item/clothing/shirt/button, + /obj/item/clothing/suit/jacket/vest/black, + /obj/item/clothing/shoes/color/black, + /obj/item/clothing/shoes/color/black, + /obj/item/clothing/shoes/craftable + ) name = "Costume - Formalwear" - cost = 30 containertype = /obj/structure/closet containername = "formalwear for the best occasions." @@ -165,17 +165,15 @@ /obj/item/clothing/head/collectable/xenom, /obj/item/clothing/head/collectable/petehat) name = "Costume - Collectible hats!" - cost = 200 containername = "\improper Collectable hats crate! Brought to you by Bass.inc!" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/nonessent/witch name = "Costume - Witch" - contains = list(/obj/item/clothing/suit/wizrobe/marisa/fake, + contains = list(/obj/item/clothing/suit/wizrobe/marisa, /obj/item/clothing/shoes/sandal, - /obj/item/clothing/head/wizard/marisa/fake, + /obj/item/clothing/head/wizard/marisa, /obj/item/staff/broom) - cost = 20 containername = "witch costume crate" containertype = /obj/structure/closet @@ -195,7 +193,6 @@ /obj/item/clothing/head/helmet/gladiator, /obj/item/clothing/head/ushanka, /obj/item/clothing/mask/spirit) - cost = 10 containername = "actor hats crate" containertype = /obj/structure/closet num_contained = 2 @@ -203,18 +200,17 @@ /decl/hierarchy/supply_pack/nonessent/dresses name = "Costume - Womens formal dress locker" - contains = list(/obj/item/clothing/under/wedding/bride_orange, - /obj/item/clothing/under/wedding/bride_purple, - /obj/item/clothing/under/wedding/bride_blue, - /obj/item/clothing/under/wedding/bride_red, - /obj/item/clothing/under/wedding/bride_white, - /obj/item/clothing/under/sundress, - /obj/item/clothing/under/dress/dress_green, - /obj/item/clothing/under/dress/dress_pink, - /obj/item/clothing/under/dress/dress_orange, - /obj/item/clothing/under/dress/dress_yellow, - /obj/item/clothing/under/dress/dress_saloon) - cost = 15 + contains = list(/obj/item/clothing/dress/wedding/bride_orange, + /obj/item/clothing/dress/wedding/bride_purple, + /obj/item/clothing/dress/wedding/bride_blue, + /obj/item/clothing/dress/wedding/bride_red, + /obj/item/clothing/dress/wedding/bride_white, + /obj/item/clothing/dress/sun, + /obj/item/clothing/dress/green, + /obj/item/clothing/dress/pink, + /obj/item/clothing/dress/orange, + /obj/item/clothing/dress/yellow, + /obj/item/clothing/dress/saloon) containername = "pretty dress locker" containertype = /obj/structure/closet num_contained = 1 @@ -228,43 +224,37 @@ /obj/item/toy/desk/fan, /obj/item/toy/desk/officetoy, /obj/item/toy/desk/dippingbird) - cost = 15 containername = "office toys crate" /decl/hierarchy/supply_pack/nonessent/chaplaingear name = "Costume - Chaplain" - contains = list(/obj/item/clothing/under/rank/chaplain, + contains = list(/obj/item/clothing/jumpsuit/chaplain, /obj/item/clothing/shoes/color/black, /obj/item/clothing/suit/nun, /obj/item/clothing/head/nun_hood, /obj/item/clothing/suit/chaplain_hoodie, /obj/item/clothing/head/chaplain_hood, /obj/item/clothing/suit/holidaypriest, - /obj/item/clothing/under/wedding/bride_white, -// /obj/item/storage/backpack/cultpack, - /obj/item/storage/candle_box = 3) - cost = 10 + /obj/item/clothing/dress/wedding/bride_white, + /obj/item/box/candles = 3) containername = "chaplain equipment crate" /decl/hierarchy/supply_pack/nonessent/exosuit_mod_ripl3 name = "Mod - \"Firestarter\" exosuit modkit" - contains = list(/obj/item/kit/paint/powerloader/flames_red) - cost = 50 + contains = list(/obj/item/kit/paint/flames_red) containername = "heavy exosuit modkit crate" /decl/hierarchy/supply_pack/nonessent/exosuit_mod_ripl4 num_contained = 1 name = "Mod - \"Burning Chrome\" exosuit modkit" - contains = list(/obj/item/kit/paint/powerloader/flames_blue) - cost = 50 + contains = list(/obj/item/kit/paint/flames_blue) containername = "heavy exosuit modkit crate" /decl/hierarchy/supply_pack/nonessent/aromatherapy name = "Rec - Aromatherapy" contains = list( /obj/item/paper/aromatherapy_disclaimer, - /obj/item/storage/candle_box/scented = 3, - /obj/item/storage/candle_box/incense = 6, - /obj/item/flame/lighter/random) - cost = 15 - containername = "aromatherapy crate" \ No newline at end of file + /obj/item/box/candles/scented = 3, + /obj/item/box/candles/incense = 6, + /obj/item/flame/fuelled/lighter/random) + containername = "aromatherapy crate" diff --git a/code/datums/supplypacks/operations.dm b/code/datums/supplypacks/operations.dm index c0ca4d733412..0ec89477c5e1 100644 --- a/code/datums/supplypacks/operations.dm +++ b/code/datums/supplypacks/operations.dm @@ -3,28 +3,27 @@ /decl/hierarchy/supply_pack/operations/cargotrain name = "Equipment - Cargo Train Tug" - contains = list(/obj/vehicle/train/cargo/engine) - cost = 45 + contains = list(/obj/vehicle/train/engine) containertype = /obj/structure/largecrate containername = "cargo train tug crate" /decl/hierarchy/supply_pack/operations/cargotrailer name = "Equipment - Cargo Train Trolley" - contains = list(/obj/vehicle/train/cargo/trolley) - cost = 15 + contains = list(/obj/vehicle/train/trolley) containertype = /obj/structure/largecrate containername = "cargo train trolley crate" /decl/hierarchy/supply_pack/operations/contraband num_contained = 5 - contains = list(/obj/item/seeds/bloodtomatoseed, - /obj/item/storage/pill_bottle/zoom, - /obj/item/storage/pill_bottle/happy, - /obj/item/storage/pill_bottle/gleam, - /obj/item/chems/food/drinks/bottle/pwine) + contains = list( + /obj/item/seeds/bloodtomatoseed, + /obj/item/pill_bottle/zoom, + /obj/item/pill_bottle/happy, + /obj/item/pill_bottle/gleam, + /obj/item/chems/drinks/bottle/pwine + ) name = "UNLISTED - Contraband crate" - cost = 30 containername = "unlabeled crate" contraband = 1 supply_method = /decl/supply_method/randomized @@ -32,7 +31,6 @@ /decl/hierarchy/supply_pack/operations/plasma_cutter name = "Equipment - Plasma Cutter" contains = list(/obj/item/gun/energy/plasmacutter) - cost = 120 containertype = /obj/structure/closet/crate/secure containername = "plasma cutter crate" access = list(list(access_mining,access_engine)) @@ -40,22 +38,20 @@ /decl/hierarchy/supply_pack/operations/orebox name = "Equipment - Ore box" contains = list(/obj/structure/ore_box) - cost = 15 containertype = /obj/structure/largecrate containername = "Ore box crate" /decl/hierarchy/supply_pack/operations/webbing name = "Gear - Webbing, vests, holsters." num_contained = 4 - contains = list(/obj/item/clothing/accessory/storage/holster, - /obj/item/clothing/accessory/storage/black_vest, - /obj/item/clothing/accessory/storage/brown_vest, - /obj/item/clothing/accessory/storage/white_vest, - /obj/item/clothing/accessory/storage/drop_pouches/black, - /obj/item/clothing/accessory/storage/drop_pouches/brown, - /obj/item/clothing/accessory/storage/drop_pouches/white, - /obj/item/clothing/accessory/storage/webbing) - cost = 15 + contains = list(/obj/item/clothing/webbing, + /obj/item/clothing/webbing/holster, + /obj/item/clothing/webbing/vest/black, + /obj/item/clothing/webbing/vest/brown, + /obj/item/clothing/webbing/vest, + /obj/item/clothing/webbing/drop_pouches/black, + /obj/item/clothing/webbing/drop_pouches/brown, + /obj/item/clothing/webbing/drop_pouches/white) containername = "webbing crate" /decl/hierarchy/supply_pack/operations/voidsuit_engineering @@ -63,7 +59,6 @@ contains = list(/obj/item/clothing/suit/space/void/engineering/alt, /obj/item/clothing/head/helmet/space/void/engineering/alt, /obj/item/clothing/shoes/magboots) - cost = 120 containername = "engineering voidsuit crate" containertype = /obj/structure/closet/crate/secure/large access = access_engine @@ -73,7 +68,6 @@ contains = list(/obj/item/clothing/suit/space/void/medical/alt, /obj/item/clothing/head/helmet/space/void/medical/alt, /obj/item/clothing/shoes/magboots) - cost = 120 containername = "medical voidsuit crate" containertype = /obj/structure/closet/crate/secure/large access = access_medical_equip @@ -83,7 +77,6 @@ contains = list(/obj/item/clothing/suit/space/void/security/alt, /obj/item/clothing/head/helmet/space/void/security/alt, /obj/item/clothing/shoes/magboots) - cost = 120 containername = "security voidsuit crate" containertype = /obj/structure/closet/crate/secure/large access = access_brig @@ -99,11 +92,10 @@ /obj/item/folder/red, /obj/item/folder/yellow, /obj/item/hand_labeler, - /obj/item/tape_roll, - /obj/structure/filingcabinet/chestdrawer{anchored = 0}, + /obj/item/stack/tape_roll/duct_tape, + /obj/structure/filing_cabinet/chestdrawer, /obj/item/paper_bin) name = "Office supplies" - cost = 15 containertype = /obj/structure/closet/crate/large containername = "office supplies crate" diff --git a/code/datums/supplypacks/science.dm b/code/datums/supplypacks/science.dm index 8d5dd92f048c..93c9197bbc0b 100644 --- a/code/datums/supplypacks/science.dm +++ b/code/datums/supplypacks/science.dm @@ -4,19 +4,17 @@ /decl/hierarchy/supply_pack/science/chemistry_dispenser name = "Equipment - Chemical Reagent dispenser" contains = list( - /obj/machinery/chemical_dispenser{anchored = 0} + /obj/machinery/chemical_dispenser/unanchored ) - cost = 25 containertype = /obj/structure/largecrate containername = "reagent dispenser crate" /decl/hierarchy/supply_pack/science/robotics name = "Parts - Robotics" contains = list(/obj/item/assembly/prox_sensor = 3, - /obj/item/storage/toolbox/electrical, + /obj/item/toolbox/electrical, /obj/item/flash = 4, /obj/item/cell/high = 2) - cost = 10 containertype = /obj/structure/closet/crate/secure/gear containername = "robotics assembly crate" access = access_robotics @@ -27,7 +25,6 @@ /obj/item/assembly/igniter = 3, /obj/item/assembly/prox_sensor = 3, /obj/item/assembly/timer = 3) - cost = 10 containertype = /obj/structure/closet/crate/secure/explosives containername = "explosive assembly crate" access = access_tox_storage @@ -35,26 +32,24 @@ /decl/hierarchy/supply_pack/science/scanner_module name = "Electronics - Reagent scanner modules" contains = list(/obj/item/stock_parts/computer/scanner/reagent = 4) - cost = 20 containername = "reagent scanner module crate" /decl/hierarchy/supply_pack/science/minergear name = "Shaft miner equipment" - contains = list(/obj/item/storage/backpack/industrial, - /obj/item/storage/backpack/satchel/eng, + contains = list(/obj/item/backpack/industrial, + /obj/item/backpack/satchel/eng, /obj/item/radio/headset/headset_cargo, - /obj/item/clothing/under/rank/miner, + /obj/item/clothing/jumpsuit/miner, /obj/item/clothing/gloves/thick, /obj/item/clothing/shoes/color/black, /obj/item/scanner/gas, - /obj/item/storage/ore, + /obj/item/ore_satchel, /obj/item/flashlight/lantern, - /obj/item/shovel, - /obj/item/pickaxe, + /obj/item/tool/shovel, + /obj/item/tool/pickaxe, /obj/item/scanner/mining, /obj/item/clothing/glasses/material, /obj/item/clothing/glasses/meson) - cost = 15 containertype = /obj/structure/closet/crate/secure containername = "shaft miner equipment crate" access = access_mining @@ -64,12 +59,10 @@ contains = list(/obj/item/flashlight/lamp/floodlamp, /obj/item/flashlight/lamp/floodlamp/green) name = "Equipment - Flood lamps" - cost = 20 containername = "flood lamp crate" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/science/illuminate name = "Gear - Illumination grenades" contains = list(/obj/item/grenade/light = 8) - cost = 20 - containername = "illumination grenade crate" \ No newline at end of file + containername = "illumination grenade crate" diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm index af1bc1f2fd2f..ca7486c81abc 100644 --- a/code/datums/supplypacks/security.dm +++ b/code/datums/supplypacks/security.dm @@ -3,10 +3,9 @@ /decl/hierarchy/supply_pack/security/specialops name = "Grenades - Special Ops supplies" - contains = list(/obj/item/storage/box/emps, + contains = list(/obj/item/box/emps, /obj/item/grenade/smokebomb = 3, /obj/item/grenade/chem_grenade/incendiary) - cost = 20 containername = "special ops crate" hidden = 1 @@ -14,7 +13,6 @@ name = "Armor - Light" contains = list(/obj/item/clothing/suit/armor/pcarrier/light = 4, /obj/item/clothing/head/helmet =4) - cost = 30 containertype = /obj/structure/closet/crate/secure containername = "light armor crate" access = access_security @@ -23,31 +21,28 @@ name = "Armor - Unmarked" contains = list(/obj/item/clothing/suit/armor/pcarrier/medium = 2, /obj/item/clothing/head/helmet =2) - cost = 20 containertype = /obj/structure/closet/crate/secure containername = "armor crate" access = access_security /decl/hierarchy/supply_pack/security/tacticalarmor name = "Armor - Tactical" - contains = list(/obj/item/clothing/under/tactical, + contains = list(/obj/item/clothing/jumpsuit/tactical, /obj/item/clothing/suit/armor/pcarrier/tactical, /obj/item/clothing/head/helmet/tactical, /obj/item/clothing/mask/balaclava/tactical, /obj/item/clothing/glasses/tacgoggles, - /obj/item/storage/belt/holster/security/tactical, + /obj/item/belt/holster/security/tactical, /obj/item/clothing/shoes/jackboots/tactical, /obj/item/clothing/gloves/tactical) - cost = 45 containertype = /obj/structure/closet/crate/secure containername = "tactical armor crate" access = access_armory /decl/hierarchy/supply_pack/security/blackguards name = "Armor - Arm and leg guards, black" - contains = list(/obj/item/clothing/accessory/armguards = 2, - /obj/item/clothing/accessory/legguards = 2) - cost = 20 + contains = list(/obj/item/clothing/gloves/armguards = 2, + /obj/item/clothing/shoes/legguards = 2) containertype = /obj/structure/closet/crate/secure containername = "arm and leg guards crate" access = access_armory @@ -57,9 +52,8 @@ contains = list(/obj/item/shield/riot = 4, /obj/item/clothing/head/helmet/riot = 4, /obj/item/clothing/suit/armor/riot = 4, - /obj/item/storage/box/flashbangs, - /obj/item/storage/box/teargas) - cost = 80 + /obj/item/box/flashbangs, + /obj/item/box/teargas) containertype = /obj/structure/closet/crate/secure containername = "riot armor crate" access = access_armory @@ -68,7 +62,6 @@ name = "Armor - Ballistic" contains = list(/obj/item/clothing/head/helmet/ballistic = 4, /obj/item/clothing/suit/armor/bulletproof = 4) - cost = 60 containertype = /obj/structure/closet/crate/secure containername = "ballistic suit crate" access = access_armory @@ -77,7 +70,6 @@ name = "Armor - Ablative" contains = list(/obj/item/clothing/head/helmet/ablative = 4, /obj/item/clothing/suit/armor/laserproof = 4) - cost = 60 containertype = /obj/structure/closet/crate/secure containername = "ablative suit crate" access = access_armory @@ -88,7 +80,6 @@ /obj/item/chems/spray/pepper = 4, /obj/item/baton/loaded = 4, /obj/item/gun/energy/taser = 4) - cost = 50 containertype = /obj/structure/closet/crate/secure/weapon containername = "weapons crate" access = access_security @@ -96,7 +87,6 @@ /decl/hierarchy/supply_pack/security/egun name = "Weapons - Energy sidearms" contains = list(/obj/item/gun/energy/gun/secure = 4) - cost = 40 containertype = /obj/structure/closet/crate/secure/weapon containername = "energy sidearms crate" access = access_armory @@ -105,15 +95,13 @@ /decl/hierarchy/supply_pack/security/egun/shady name = "Weapons - Energy sidearms (For disposal)" contains = list(/obj/item/gun/energy/gun = 4) - cost = 60 contraband = 1 security_level = null /decl/hierarchy/supply_pack/security/ion name = "Weapons - Electromagnetic" contains = list(/obj/item/gun/energy/ionrifle = 2, - /obj/item/storage/box/emps) - cost = 50 + /obj/item/box/emps) containertype = /obj/structure/closet/crate/secure/weapon containername = "electromagnetic weapons crate" access = access_armory @@ -122,7 +110,6 @@ /decl/hierarchy/supply_pack/security/shotgun name = "Weapons - Shotgun" contains = list(/obj/item/gun/projectile/shotgun/pump = 2) - cost = 60 containertype = /obj/structure/closet/crate/secure/weapon containername = "shotgun crate" access = access_armory @@ -130,25 +117,22 @@ /decl/hierarchy/supply_pack/security/flashbang name = "Weapons - Flashbangs" - contains = list(/obj/item/storage/box/flashbangs = 2) - cost = 30 + contains = list(/obj/item/box/flashbangs = 2) containertype = /obj/structure/closet/crate/secure/weapon containername = "flashbang crate" access = access_security /decl/hierarchy/supply_pack/security/teargas name = "Weapons - Tear gas grenades" - contains = list(/obj/item/storage/box/teargas = 2) - cost = 30 + contains = list(/obj/item/box/teargas = 2) containertype = /obj/structure/closet/crate/secure/weapon containername = "tear gas grenades crate" access = access_security /decl/hierarchy/supply_pack/security/shotgunammo name = "Ammunition - Lethal shells" - contains = list(/obj/item/storage/box/ammo/shotgunammo = 2, - /obj/item/storage/box/ammo/shotgunshells = 2) - cost = 60 + contains = list(/obj/item/box/ammo/shotgunammo = 2, + /obj/item/box/ammo/shotgunshells = 2) containertype = /obj/structure/closet/crate/secure/weapon containername = "lethal shotgun shells crate" access = access_security @@ -156,8 +140,7 @@ /decl/hierarchy/supply_pack/security/shotgunbeanbag name = "Ammunition - Beanbag shells" - contains = list(/obj/item/storage/box/ammo/beanbags = 3) - cost = 30 + contains = list(/obj/item/box/ammo/beanbags = 3) containertype = /obj/structure/closet/crate/secure/weapon containername = "beanbag shotgun shells crate" access = access_security @@ -165,7 +148,6 @@ /decl/hierarchy/supply_pack/security/pdwammo name = "Ammunition - SMG top mounted" contains = list(/obj/item/ammo_magazine/smg = 4) - cost = 40 containertype = /obj/structure/closet/crate/secure/weapon containername = "SMG ammunition crate" access = access_security @@ -174,7 +156,6 @@ /decl/hierarchy/supply_pack/security/pdwammorubber name = "Ammunition - SMG top mounted rubber" contains = list(/obj/item/ammo_magazine/smg/rubber = 4) - cost = 30 containertype = /obj/structure/closet/crate/secure/weapon containername = "SMG rubber ammunition crate" access = access_security @@ -182,7 +163,6 @@ /decl/hierarchy/supply_pack/security/pdwammopractice name = "Ammunition - SMG top mounted practice" contains = list(/obj/item/ammo_magazine/smg/practice = 8) - cost = 30 containertype = /obj/structure/closet/crate/secure/weapon containername = "SMG practice ammunition crate" access = access_security @@ -190,7 +170,6 @@ /decl/hierarchy/supply_pack/security/bullpupammo name = "Ammunition - military rifle" contains = list(/obj/item/ammo_magazine/rifle = 4) - cost = 60 containertype = /obj/structure/closet/crate/secure/weapon containername = "military rifle ammunition crate" access = access_security @@ -199,7 +178,6 @@ /decl/hierarchy/supply_pack/security/bullpupammopractice name = "Ammunition - military rifle practice" contains = list(/obj/item/ammo_magazine/rifle/practice = 8) - cost = 30 containertype = /obj/structure/closet/crate/secure/weapon containername = "military rifle practice ammunition crate" access = access_security @@ -210,14 +188,13 @@ /obj/item/forensics/sample_kit/powder, /obj/item/forensics/sample_kit/swabs = 3, /obj/item/chems/spray/luminol) - cost = 30 containername = "auxiliary forensic tools crate" /decl/hierarchy/supply_pack/security/detectivegear name = "Forensics - investigation equipment" - contains = list(/obj/item/storage/box/evidence = 2, + contains = list(/obj/item/box/evidence = 2, /obj/item/radio/headset/headset_sec, - /obj/item/taperoll/police, + /obj/item/stack/tape_roll/barricade_tape/police, /obj/item/clothing/glasses/sunglasses, /obj/item/camera, /obj/item/folder/red, @@ -226,10 +203,9 @@ /obj/item/taperecorder, /obj/item/scanner/spectrometer, /obj/item/camera_film = 2, - /obj/item/storage/photo_album, + /obj/item/photo_album, /obj/item/scanner/reagent, - /obj/item/storage/briefcase/crimekit = 2) - cost = 50 + /obj/item/briefcase/crimekit = 2) containertype = /obj/structure/closet/crate/secure containername = "forensic equipment crate" access = access_forensics_lockers @@ -237,7 +213,6 @@ /decl/hierarchy/supply_pack/security/securitybarriers name = "Equipment - Barrier crate" contains = list(/obj/machinery/deployable/barrier = 4) - cost = 20 containertype = /obj/structure/closet/crate/secure/large containername = "security barrier crate" access = access_security @@ -245,7 +220,6 @@ /decl/hierarchy/supply_pack/security/securitybarriers name = "Equipment - Wall shield Generators" contains = list(/obj/machinery/shieldwallgen = 2) - cost = 20 containertype = /obj/structure/closet/crate/secure/large containername = "wall shield generators crate" access = access_brig @@ -257,7 +231,6 @@ /obj/item/clothing/mask/gas, /obj/item/tank/oxygen, /obj/item/clothing/gloves/latex) - cost = 30 containertype = /obj/structure/closet/crate/secure containername = "security biohazard gear crate" access = access_security @@ -267,7 +240,6 @@ contains = list(/obj/item/clothing/suit/space/void/security/alt, /obj/item/clothing/head/helmet/space/void/security/alt, /obj/item/clothing/shoes/magboots) - cost = 120 containername = "security voidsuit crate" containertype = /obj/structure/closet/crate/secure/large access = access_brig diff --git a/code/datums/supplypacks/supply.dm b/code/datums/supplypacks/supply.dm index 468791ed22ff..b49f0b11aa7b 100644 --- a/code/datums/supplypacks/supply.dm +++ b/code/datums/supplypacks/supply.dm @@ -4,122 +4,107 @@ /decl/hierarchy/supply_pack/supply/toner name = "Refills - Toner cartridges" - contains = list(/obj/item/toner = 3) - cost = 10 + contains = list(/obj/item/chems/toner_cartridge = 3) containername = "toner cartridges" /decl/hierarchy/supply_pack/supply/cardboard_sheets name = "Material - cardboard sheets (50)" - contains = list(/obj/item/stack/material/cardboard/fifty) - cost = 10 + contains = list(/obj/item/stack/material/cardstock/mapped/cardboard/fifty) containername = "cardboard sheets crate" /decl/hierarchy/supply_pack/supply/stickies name = "Stationery - sticky notes (50)" contains = list(/obj/item/sticky_pad/random) - cost = 10 containername = "\improper Sticky notes crate" /decl/hierarchy/supply_pack/supply/wpaper name = "Cargo - Wrapping paper" contains = list(/obj/item/stack/package_wrap/twenty_five = 3) - cost = 10 containername = "wrapping paper" /decl/hierarchy/supply_pack/supply/tapes - name = "Medium - Blank Tapes (14)" - contains = list (/obj/item/storage/box/tapes) - cost = 10 + name = "Supplies - Blank Tapes (14)" + contains = list (/obj/item/box/tapes) containername = "blank tapes crate" /decl/hierarchy/supply_pack/supply/taperolls - name = "G.O.S.H - Barricade Tapes (mixed)" - contains = list (/obj/item/storage/box/taperolls) - cost = 10 + name = "Supplies - Barricade Tapes (mixed)" + contains = list (/obj/item/box/taperolls) containername = "barricade tape crate" /decl/hierarchy/supply_pack/supply/bogrolls name = "Custodial - Toilet paper (12)" - contains = list (/obj/item/storage/box/bogrolls = 2) - cost = 10 + contains = list (/obj/item/box/bogrolls = 2) containername = "toilet paper crate" /decl/hierarchy/supply_pack/supply/scanner_module name = "Electronics - Paper scanner modules" contains = list(/obj/item/stock_parts/computer/scanner/paper = 4) - cost = 20 containername = "paper scanner module crate" /decl/hierarchy/supply_pack/supply/spare_pda name = "Electronics - Spare PDAs" contains = list(/obj/item/modular_computer/pda = 3) - cost = 10 containername = "spare PDA crate" /decl/hierarchy/supply_pack/supply/eftpos contains = list(/obj/item/eftpos) name = "Electronics - EFTPOS scanner" - cost = 10 containername = "\improper EFTPOS crate" /decl/hierarchy/supply_pack/supply/water name = "Refills - Bottled water" - contains = list (/obj/item/storage/box/water = 2) - cost = 12 + contains = list (/obj/item/box/water = 2) containername = "bottled water crate" /decl/hierarchy/supply_pack/supply/sodas num_contained = 2 - contains = list(/obj/item/storage/box/cola, - /obj/item/storage/box/cola/spacewind, - /obj/item/storage/box/cola/drgibb, - /obj/item/storage/box/cola/starkist, - /obj/item/storage/box/cola/spaceup, - /obj/item/storage/box/cola/lemonlime, - /obj/item/storage/box/cola/icedtea, - /obj/item/storage/box/cola/grapejuice, - /obj/item/storage/box/cola/sodawater) + contains = list(/obj/item/box/cola, + /obj/item/box/cola/spacewind, + /obj/item/box/cola/drgibb, + /obj/item/box/cola/starkist, + /obj/item/box/cola/spaceup, + /obj/item/box/cola/lemonlime, + /obj/item/box/cola/icedtea, + /obj/item/box/cola/grapejuice, + /obj/item/box/cola/sodawater) name = "Refills - Soda cans" - cost = 10 containername = "soda can crate" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/supply/snacks num_contained = 2 - contains = list(/obj/item/storage/box/snack, - /obj/item/storage/box/snack/noraisin, - /obj/item/storage/box/snack/cheesehonks, - /obj/item/storage/box/snack/tastybread, - /obj/item/storage/box/snack/candy, - /obj/item/storage/box/snack/chips) + contains = list(/obj/item/box/snack, + /obj/item/box/snack/noraisin, + /obj/item/box/snack/cheesehonks, + /obj/item/box/snack/tastybread, + /obj/item/box/snack/candy, + /obj/item/box/snack/chips) name = "Refills - Snack foods" - cost = 10 containername = "snack foods crate" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/supply/canned num_contained = 2 - contains = list(/obj/item/storage/box/canned, - /obj/item/storage/box/canned/beef, - /obj/item/storage/box/canned/beans, - /obj/item/storage/box/canned/tomato, + contains = list(/obj/item/box/canned, + /obj/item/box/canned/beef, + /obj/item/box/canned/beans, + /obj/item/box/canned/tomato, ) name = "Emergency - Canned foods" - cost = 30 containername = "canneds crate" supply_method = /decl/supply_method/randomized /decl/hierarchy/supply_pack/supply/fueltank name = "Liquid - Fuel tank" contains = list(/obj/structure/reagent_dispensers/fueltank) - cost = 8 containertype = /obj/structure/largecrate containername = "fuel tank crate" /decl/hierarchy/supply_pack/supply/watertank name = "Liquid - Water tank" contains = list(/obj/structure/reagent_dispensers/watertank) - cost = 8 + cost = 12 containertype = /obj/structure/largecrate containername = "water tank crate" @@ -129,112 +114,97 @@ /decl/hierarchy/supply_pack/supply/snackvendor name = "Vendor - Getmoore Chocolate Co" - contains = list(/obj/machinery/vending/snack{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/snack) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/snixvendor name = "Vendor - Snix Zakuson TCC" - contains = list(/obj/machinery/vending/snix{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/snix) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/solvendor name = "Vendor - Mars Mart SCC" - contains = list(/obj/machinery/vending/sol{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/sol) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/sodavendor name = "Vendor - Softdrinks Robust Industries LLC" - contains = list(/obj/machinery/vending/cola{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/cola) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/lavatoryvendor name = "Vendor - Lavatory Essentials - Waffle Co" - contains = list(/obj/machinery/vending/lavatory{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/lavatory) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/boozevendor name = "Vendor - Booze-o-mat - GrekkaTarg Boozeries" - contains = list(/obj/machinery/vending/boozeomat{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/boozeomat) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/gamevendor name = "Vendor - Games - Honk Co" - contains = list(/obj/machinery/vending/games{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/games) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/fitnessvendor name = "Vendor - Fitness - SwolMAX Bros" - contains = list(/obj/machinery/vending/fitness{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/fitness) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/cigarettevendor name = "Vendor - Cigarettes - Gideon Asbestos Mining Conglomerate" - contains = list(/obj/machinery/vending/cigarette{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/cigarette) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" + cost = 150 /decl/hierarchy/supply_pack/supply/roboticsvendor name = "Vendor - Robotics - Dandytronics LLT" - contains = list(/obj/machinery/vending/robotics{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/robotics) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/engineeringvendor name = "Vendor - Engineering - Dandytronics LLT" - contains = list(/obj/machinery/vending/engineering{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/engineering) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/toolvendor name = "Vendor - Tools - YouTool Co" - contains = list(/obj/machinery/vending/tool{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/tool) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/coffeevendor name = "Vendor - Coffee - Hot Drinks LCD" - contains = list(/obj/machinery/vending/coffee{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/coffee) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/dinnerwarevendor name = "Vendor - Dinnerwares - Plastic Tat Inc" - contains = list(/obj/machinery/vending/dinnerware{anchored = 0}) - cost = 150 + contains = list(/obj/machinery/vending/dinnerware) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/bodavendor name = "Vendor - BODA - Zakuson TCC" - contains = list(/obj/machinery/vending/sovietsoda{anchored = 0}) - cost = 250 + contains = list(/obj/machinery/vending/sovietsoda) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" /decl/hierarchy/supply_pack/supply/weebvendor name = "Vendor - Nippon-tan - ArigatoRobotics LCD" - contains = list(/obj/machinery/vending/weeb{anchored = 0}) - cost = 50 + contains = list(/obj/machinery/vending/weeb) containertype = /obj/structure/largecrate containername = "\improper Vending Machine" \ No newline at end of file diff --git a/code/datums/supplypacks/supplypack.dm b/code/datums/supplypacks/supplypack.dm index d5cfcc83b692..7544b406d35f 100644 --- a/code/datums/supplypacks/supplypack.dm +++ b/code/datums/supplypacks/supplypack.dm @@ -1,9 +1,10 @@ /decl/hierarchy/supply_pack name = "Supply Packs" - hierarchy_type = /decl/hierarchy/supply_pack + abstract_type = /decl/hierarchy/supply_pack + expected_type = /decl/hierarchy/supply_pack var/list/contains = list() var/manifest = "" - var/cost = null + var/cost var/containertype = /obj/structure/closet/crate var/containername = null var/access = null @@ -13,33 +14,49 @@ var/supply_method = /decl/supply_method var/decl/security_level/security_level -//Is run once on init for non-base-category supplypacks. -/decl/hierarchy/supply_pack/proc/setup() +var/global/list/cargoprices = list() +/decl/hierarchy/supply_pack/Initialize() + . = ..() // make sure children are set up + if(is_category()) + return // don't do any of this for categories + var/total_contained = 0 + for(var/entry in contains) + total_contained += max(1, contains[entry]) if(!num_contained) - for(var/entry in contains) - num_contained += max(1, contains[entry]) + num_contained = total_contained if(isnull(cost)) cost = 0 for(var/entry in contains) cost += atom_info_repository.get_combined_worth_for(entry) * max(1, contains[entry]) - if(containertype) - cost += atom_info_repository.get_single_worth_for(containertype) - cost = cost * WORTH_TO_SUPPLY_POINTS_CONSTANT * SSsupply.price_markup - cost = max(1, CEILING(cost, WORTH_TO_SUPPLY_POINTS_ROUND_CONSTANT)) + cost *= num_contained / total_contained // if you get a random selection, it costs the expected value rather than the total worth. gambling! + cost += containertype ? atom_info_repository.get_single_worth_for(containertype) : 0 + cost = max(1, NONUNIT_CEILING((cost * WORTH_TO_SUPPLY_POINTS_CONSTANT * SSsupply.price_markup), WORTH_TO_SUPPLY_POINTS_ROUND_CONSTANT)) + global.cargoprices[name] = cost + + var/decl/supply_method/method = GET_DECL(supply_method) + manifest = method.setup_manifest(src) - var/decl/supply_method/sm = get_supply_method(supply_method) - manifest = sm.setup_manifest(src) +/client/proc/print_cargo_prices() + set name = "Print Cargo Prices" + set category = "Debug" + + global.cargoprices = sortTim(global.cargoprices, /proc/cmp_numeric_asc, TRUE) + var/pad = 0 + for(var/key in global.cargoprices) + pad = max(pad, length_char(key)+2) + for(var/key in global.cargoprices) + to_chat(mob, "[pad_right("[key]:", pad, " ")][global.cargoprices[key]]") /decl/hierarchy/supply_pack/proc/sec_available() if(isnull(security_level)) return TRUE - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) switch(security_level) if(SUPPLY_SECURITY_ELEVATED) if(security_state.all_security_levels.len > 1) - security_level = security_state.all_security_levels[2] + security_level = security_state.all_security_levels[2] else - security_level = security_state.high_security_level + security_level = security_state.high_security_level if(SUPPLY_SECURITY_HIGH) security_level = security_state.high_security_level if(!istype(security_level)) @@ -47,8 +64,10 @@ return security_state.current_security_level_is_same_or_higher_than(security_level) /decl/hierarchy/supply_pack/proc/spawn_contents(var/location) - var/decl/supply_method/sm = get_supply_method(supply_method) - return sm.spawn_contents(src, location) + var/decl/supply_method/method = GET_DECL(supply_method) + . = method.spawn_contents(src, location) + for(var/obj/O in .) + O.anchored = FALSE /* //SUPPLY PACKS @@ -59,27 +78,18 @@ //NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points. */ -var/list/supply_methods_ -/proc/get_supply_method(var/method_type) - if(!supply_methods_) - supply_methods_ = list() - . = supply_methods_[method_type] - if(!.) - . = new method_type() - supply_methods_[method_type] = . - -/decl/supply_method/proc/spawn_contents(var/decl/hierarchy/supply_pack/sp, var/location) - if(!sp || !location) +/decl/supply_method/proc/spawn_contents(var/decl/hierarchy/supply_pack/pack, var/location) + if(!pack || !location) return . = list() - for(var/entry in sp.contains) - for(var/i = 1 to max(1, sp.contains[entry])) + for(var/entry in pack.contains) + for(var/i = 1 to max(1, pack.contains[entry])) dd_insertObjectList(.,new entry(location)) -/decl/supply_method/proc/setup_manifest(var/decl/hierarchy/supply_pack/sp) +/decl/supply_method/proc/setup_manifest(var/decl/hierarchy/supply_pack/pack) . = list() . += "
      " - for(var/path in sp.contains) + for(var/path in pack.contains) var/atom/A = path if(!ispath(A)) continue @@ -87,13 +97,13 @@ var/list/supply_methods_ . += "
    " . = jointext(.,null) -/decl/supply_method/randomized/spawn_contents(var/decl/hierarchy/supply_pack/sp, var/location) - if(!sp || !location) +/decl/supply_method/randomized/spawn_contents(var/decl/hierarchy/supply_pack/pack, var/location) + if(!pack || !location) return . = list() - for(var/j = 1 to sp.num_contained) - var/picked = pick(sp.contains) + for(var/j = 1 to pack.num_contained) + var/picked = pick(pack.contains) . += new picked(location) -/decl/supply_method/randomized/setup_manifest(var/decl/hierarchy/supply_pack/sp) - return "Contains any [sp.num_contained] of:" + ..() +/decl/supply_method/randomized/setup_manifest(var/decl/hierarchy/supply_pack/pack) + return "Contains any [pack.num_contained] of:" + ..() diff --git a/code/datums/track.dm b/code/datums/track.dm new file mode 100644 index 000000000000..15c909580e98 --- /dev/null +++ b/code/datums/track.dm @@ -0,0 +1,13 @@ +/datum/track + var/title + var/track + +/datum/track/New(_title, _track) + title = _title + track = _track + +/datum/track/proc/GetTrack() + if(ispath(track, /decl/music_track)) + var/decl/music_track/music_track = GET_DECL(track) + return music_track?.song + return track // Allows admins to continue their adminbus simply by overriding the track var diff --git a/code/datums/trading/__trading_defines.dm b/code/datums/trading/__trading_defines.dm new file mode 100644 index 000000000000..29b244ba8a68 --- /dev/null +++ b/code/datums/trading/__trading_defines.dm @@ -0,0 +1,47 @@ +#define TRADER_THIS_TYPE BITFLAG(0) +#define TRADER_SUBTYPES_ONLY BITFLAG(1) +#define TRADER_ALL (TRADER_THIS_TYPE|TRADER_SUBTYPES_ONLY) +#define TRADER_BLACKLIST BITFLAG(2) +#define TRADER_BLACKLIST_SUB BITFLAG(3) +#define TRADER_BLACKLIST_ALL (TRADER_BLACKLIST|TRADER_BLACKLIST_SUB) + +#define TRADER_WANTED_ONLY BITFLAG(0) // Do they only trade for wanted goods? +#define TRADER_MONEY BITFLAG(1) // Do they only accept money in return for goods. +#define TRADER_GOODS BITFLAG(2) // Do they accept goods in return for other goods. +#define TRADER_WANTED_ALL BITFLAG(3) // Like TRADER_WANTED_ONLY but they buy all possible wanted goods rather than a subset. +#define TRADER_BRIBABLE BITFLAG(4) // Determines if the trader can be bribed (stations cannot as they can't leave) + +// Tokens for constructing the hail tags (usually generic, species name or silicon). +// When merchants hail a person they use "trade_hail_[some token]". +#define TRADER_HAIL_START "trade_hail_" +#define TRADER_HAIL_GENERIC_END "generic" +#define TRADER_HAIL_SILICON_END "silicon" +#define TRADER_HAIL_GENERIC TRADER_HAIL_START + TRADER_HAIL_GENERIC_END // Default hail response token. +#define TRADER_HAIL_SILICON TRADER_HAIL_START + TRADER_HAIL_SILICON_END // Used when hailed by a robot or AI. +#define TRADER_HAIL_DENY TRADER_HAIL_START + "deny" // Used When merchant denies a hail. + +//Possible response defines for when offering an item for something +#define TRADER_NO_MONEY "trade_no_money" // Used when money is offered to a trader who does not accept money. +#define TRADER_NO_GOODS "trade_no_goods" // Used when goods are offered to a trader who does not accept goodds. +#define TRADER_NOT_ENOUGH "trade_not_enough" // Used when there is not enough money for the trade. +#define TRADER_NO_BLACKLISTED "trade_blacklist" // Used when a blacklisted item is offered by the player. +#define TRADER_FOUND_UNWANTED "trade_found_unwanted" // Used when an unwanted item is offered by the player. +#define TRADER_TRADE_COMPLETE "trade_complete" // When a trade is made successfully. +#define TRADER_HOW_MUCH "how_much" // When a merchant tells the player how much something is. +#define TRADER_WHAT_WANT "what_want" // What the person says when they are asked if they want something +#define TRADER_COMPLIMENT_DENY "compliment_deny" // When the merchant refuses a compliment +#define TRADER_COMPLIMENT_ACCEPT "compliment_accept" // When the merchant accepts a compliment +#define TRADER_INSULT_GOOD "insult_good" // When the player insults a merchant while they are on good disposition +#define TRADER_INSULT_BAD "insult_bad" // When a player insults a merchatn when they are not on good disposition +#define TRADER_BRIBE_REFUSAL "bribe_refusal" // When the trader refuses a bribe to stay longer. +#define TRADER_BRIBE_ACCEPT "bribe_accept" // When the trader accepts a bribe to stay longer. + +// Tokens replaced with strings at runtime. +#define TRADER_TOKEN_ORIGIN "$ORIGIN$" // The selected origin of the trader station. +#define TRADER_TOKEN_VALUE "$VALUE$" // The value of the trade. +#define TRADER_TOKEN_CURRENCY "$CURRENCY$" // The plural name of the currency in use +#define TRADER_TOKEN_CUR_SINGLE "$CURRENCY_SINGULAR$" // The singular name of the unit of currency in use. +#define TRADER_TOKEN_ITEM "$ITEM$" // The relevant item being traded or offered. +#define TRADER_TOKEN_MERCHANT "$MERCHANT$" // The name of the current trader. +#define TRADER_TOKEN_MOB "$MOB$" // The player currently interacting with the trader. +#define TRADER_TOKEN_TIME "$TIME$" // How much longer a successful bribe has gained. diff --git a/code/datums/trading/_trade_hub.dm b/code/datums/trading/_trade_hub.dm new file mode 100644 index 000000000000..fbeb44ea9f8d --- /dev/null +++ b/code/datums/trading/_trade_hub.dm @@ -0,0 +1,68 @@ +/datum/trade_hub + var/name = "Trading Hub" + var/max_traders = 3 + var/list/traders = list() + var/list/possible_trader_types + +/datum/trade_hub/proc/get_initial_traders() + return + +/datum/trade_hub/proc/get_initial_trader_count() + return max_traders + +/datum/trade_hub/proc/is_accessible_from(var/turf/check) + return FALSE + +/datum/trade_hub/New() + ..() + SStrade.trade_hubs += src + for(var/trader_type in get_initial_traders()) + add_trader(trader_type) + var/total_initial_traders = get_initial_trader_count() + var/total_traders = total_initial_traders - length(traders) + if(total_traders > 0) + var/list/trader_types = get_possible_initial_trader_types() + for(var/i in 1 to total_traders) + generate_trader(trader_types) + +/datum/trade_hub/Destroy(force) + SStrade.trade_hubs -= src + QDEL_NULL_LIST(traders) + . = ..() + +/datum/trade_hub/proc/get_possible_initial_trader_types() + return subtypesof(/datum/trader) - typesof(/datum/trader/ship) + +/datum/trade_hub/proc/get_possible_post_roundstart_trader_types() + . = subtypesof(/datum/trader/ship) + if(prob(95)) + . -= typesof(/datum/trader/ship/unique) + +/datum/trade_hub/proc/generate_trader(var/list/use_trader_list) + if(length(traders)+1 >= max_traders) + return FALSE + if(!use_trader_list) + use_trader_list = get_possible_post_roundstart_trader_types() + while(length(use_trader_list)) + var/trader_type = pick_n_take(use_trader_list) + if(!(locate(trader_type) in traders)) + add_trader(trader_type) + return TRUE + +/datum/trade_hub/proc/add_trader(var/trader_type) + traders += new trader_type(src) + +/datum/trade_hub/Process(wait, tick) + for(var/datum/trader/trader in traders) + trader.tick() + +// Stub for legacy/non-overmap purposes. +/datum/trade_hub/singleton + max_traders = 10 + +/datum/trade_hub/singleton/is_accessible_from(var/turf/check) + return TRUE + +/datum/trade_hub/singleton/get_initial_trader_count() + return rand(2, 3) +// End stub. diff --git a/code/datums/trading/_trader.dm b/code/datums/trading/_trader.dm new file mode 100644 index 000000000000..27444f108d19 --- /dev/null +++ b/code/datums/trading/_trader.dm @@ -0,0 +1,300 @@ +/datum/trader + abstract_type = /datum/trader + var/name = "unsuspicious trader" // The name of the trader in question + var/origin = "some place" // The place that they are trading from + var/list/possible_origins // Possible names of the trader origin + var/disposition = 0 // The current disposition of them to us. + var/trade_flags = TRADER_MONEY // Various flags for allowing or denying offers/interactions. + var/name_language // Language decl to use for trader name. If null, will use the generic name generator. + var/icon/portrait // The icon that shows up in the menu TODO: IMPLEMENT OR REMOVE + var/trader_currency // Currency decl to use. If blank, defaults to map. + var/datum/trade_hub/hub // Current associated trade hub, if any. + + var/list/wanted_items = list() // What items they enjoy trading for. Structure is (type = known/unknown) + var/list/possible_wanted_items // List of all possible wanted items. Structure is (type = mode) + var/list/possible_trading_items // List of all possible trading items. Structure is (type = mode) + var/list/trading_items = list() // What items they are currently trading away. + + // The list of all their replies and messages. + // Structure is (id = talk). Check __trading_defines.dm for specific tokens. + var/list/speech = list() + + var/want_multiplier = 2 // How much wanted items are multiplied by when traded for + var/margin = 1.2 // Multiplier to price when selling to player + var/price_rng = 10 // Percentage max variance in sell prices. + var/insult_drop = 5 // How far disposition drops on insult + var/compliment_increase = 5 // How far compliments increase disposition + var/refuse_comms = 0 // Whether they refuse further communication + + // What message gets sent to mobs that get sold. + var/mob_transfer_message = "You are transported to " + TRADER_TOKEN_ORIGIN + "." + + // Things they will automatically refuse + var/list/blacklisted_trade_items = list( + /mob/living/human + ) + +/datum/trader/New() + ..() + if(!ispath(trader_currency, /decl/currency)) + trader_currency = global.using_map.default_currency + if(ispath(name_language, /decl/language)) + var/decl/language/L = GET_DECL(name_language) + if(istype(L)) + name = L.get_random_language_name(pick(MALE,FEMALE)) + if(!name) + name = capitalize(pick(global.using_map.first_names_female + global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) + + if(length(possible_origins)) + origin = pick(possible_origins) + + for(var/i in 3 to 6) + add_to_pool(trading_items, possible_trading_items, force = 1) + add_to_pool(wanted_items, possible_wanted_items, force = 1) + +//If this hits 0 then they decide to up and leave. +/datum/trader/proc/tick() + add_to_pool(trading_items, possible_trading_items, 200) + add_to_pool(wanted_items, possible_wanted_items, 50) + remove_from_pool(possible_trading_items, 9) //We want the stock to change every so often, so we make it so that they have roughly 10~11 ish items max + return 1 + +/datum/trader/proc/remove_from_pool(var/list/pool, var/chance_per_item) + if(pool && prob(chance_per_item * pool.len)) + var/i = rand(1,pool.len) + pool[pool[i]] = null + pool -= pool[i] + +/datum/trader/proc/add_to_pool(var/list/pool, var/list/possible, var/base_chance = 100, var/force = 0) + var/divisor = 1 + if(LAZYLEN(pool)) + divisor = pool.len + if(force || prob(base_chance/divisor)) + var/new_item = get_possible_item(possible) + if(new_item) + pool |= new_item + +// This is horrendous. TODO: cache all of this shit. +// May be possible to mutate trading_pool as this is passed in from the lists defined on the datum. +/datum/trader/proc/get_possible_item(var/list/trading_pool) + if(!length(trading_pool)) + return + var/list/possible = list() + for(var/trade_type in trading_pool) + var/status = trading_pool[trade_type] + if(status & TRADER_THIS_TYPE) + possible += trade_type + if(status & TRADER_SUBTYPES_ONLY) + possible += subtypesof(trade_type) + if(status & TRADER_BLACKLIST) + possible -= trade_type + if(status & TRADER_BLACKLIST_SUB) + possible -= subtypesof(trade_type) + for(var/trade_type in possible) + var/atom/check_type = trade_type + if(!TYPE_IS_SPAWNABLE(check_type)) + possible -= check_type + if(length(possible)) + return pick(possible) + +/datum/trader/proc/get_response(var/key, var/default) + if(speech && speech[key]) + . = speech[key] + else + . = default + . = replacetext(., TRADER_TOKEN_MERCHANT, name) + . = replacetext(., TRADER_TOKEN_ORIGIN, origin) + + var/decl/currency/cur = GET_DECL(trader_currency) + . = replacetext(.,TRADER_TOKEN_CUR_SINGLE, cur.name_singular) + . = replacetext(.,TRADER_TOKEN_CURRENCY, cur.name) + +/datum/trader/proc/print_trading_items(var/num) + num = clamp(num,1,trading_items.len) + var/item_type = trading_items[num] + if(!item_type) + return + . = atom_info_repository.get_name_for(item_type) + if(ispath(item_type, /obj/item/stack)) + var/obj/item/stack/stack = item_type + . = "[initial(stack.amount)]x [.]" + . = "[.]" + +/datum/trader/proc/skill_curve(skill) + switch(skill) + if(SKILL_EXPERT) + . = 1 + if(SKILL_EXPERT to SKILL_MAX) + . = 1 + (SKILL_EXPERT - skill) * 0.2 + else + . = 1 + (SKILL_EXPERT - skill) ** 2 + //This condition ensures that the buy price is higher than the sell price on generic goods, i.e. the merchant can't be exploited + . = max(., price_rng/((margin - 1)*(200 - price_rng))) + +/datum/trader/proc/get_item_value(var/trading_num, skill = SKILL_MAX) + if(!trading_items[trading_items[trading_num]]) + var/item_type = trading_items[trading_num] + var/value = atom_info_repository.get_combined_worth_for(item_type) + value = round(rand(100 - price_rng,100 + price_rng)/100 * value) //For some reason rand doesn't like decimals. + trading_items[item_type] = value + . = trading_items[trading_items[trading_num]] + . *= 1 + (margin - 1) * skill_curve(skill) //Trader will overcharge at lower skill. + . = max(1, round(.)) + +/datum/trader/proc/get_buy_price(var/atom/movable/item, is_wanted, skill = SKILL_MAX) + if(ispath(item, /atom/movable)) + . = atom_info_repository.get_combined_worth_for(item) + else if(istype(item)) + . = item.get_combined_monetary_worth() + if(is_wanted) + . *= want_multiplier + . *= max(1 - (margin - 1) * skill_curve(skill), 0.1) //Trader will underpay at lower skill. + . = max(1, round(.)) + +/datum/trader/proc/offer_money_for_trade(var/trade_num, var/money_amount, skill = SKILL_MAX) + if(!(trade_flags & TRADER_MONEY)) + return TRADER_NO_MONEY + var/value = get_item_value(trade_num, skill) + if(money_amount < value) + return TRADER_NOT_ENOUGH + return value + +/datum/trader/proc/offer_items_for_trade(var/list/offers, var/num, var/turf/location, skill = SKILL_MAX) + if(!LAZYLEN(offers)) + return TRADER_NOT_ENOUGH + num = clamp(num, 1, trading_items.len) + var/offer_worth = 0 + for(var/item in offers) + var/atom/movable/offer = item + var/is_wanted = 0 + if((trade_flags & TRADER_WANTED_ONLY) && is_type_in_list(offer, wanted_items)) + is_wanted = 2 + if((trade_flags & TRADER_WANTED_ALL) && is_type_in_list(offer, possible_wanted_items)) + is_wanted = 1 + if(length(blacklisted_trade_items) && is_type_in_list(offer, blacklisted_trade_items)) + return TRADER_NO_BLACKLISTED + + if(istype(offer,/obj/item/cash)) + if(!(trade_flags & TRADER_MONEY)) + return TRADER_NO_MONEY + else + if(!(trade_flags & TRADER_GOODS)) + return TRADER_NO_GOODS + else if((trade_flags & (TRADER_WANTED_ONLY|TRADER_WANTED_ALL)) && !is_wanted) + return TRADER_FOUND_UNWANTED + + offer_worth += get_buy_price(offer, is_wanted - 1, skill) + if(!offer_worth) + return TRADER_NOT_ENOUGH + var/trading_worth = get_item_value(num, skill) + if(!trading_worth) + return TRADER_NOT_ENOUGH + var/percent = offer_worth/trading_worth + if(percent > max(0.9,0.9-disposition/100)) + return trade(offers, num, location) + return TRADER_NOT_ENOUGH + +/datum/trader/proc/hail(var/mob/user) + var/specific + if(ishuman(user)) + var/mob/living/human/H = user + if(H.species) + specific = H.species.uid + else if(issilicon(user)) + specific = TRADER_HAIL_SILICON_END + if(!speech["[TRADER_HAIL_START][specific]"]) + specific = TRADER_HAIL_GENERIC_END + . = get_response("[TRADER_HAIL_START][specific]", "Greetings, " + TRADER_TOKEN_MOB + "!") + . = replacetext(., TRADER_TOKEN_MOB, user.name) + +/datum/trader/proc/can_hail() + if(!refuse_comms && prob(-disposition)) + refuse_comms = 1 + return !refuse_comms + +/datum/trader/proc/insult() + disposition -= rand(insult_drop, insult_drop * 2) + if(prob(-disposition/10)) + refuse_comms = 1 + if(disposition > 50) + return get_response(TRADER_INSULT_GOOD,"What? I thought we were cool!") + else + return get_response(TRADER_INSULT_BAD, "Right back at you asshole!") + +/datum/trader/proc/compliment() + if(prob(-disposition)) + return get_response(TRADER_COMPLIMENT_DENY, "Fuck you!") + if(prob(100-disposition)) + disposition += rand(compliment_increase, compliment_increase * 2) + return get_response(TRADER_COMPLIMENT_ACCEPT, "Thank you!") + +/datum/trader/proc/trade(var/list/offers, var/num, var/turf/location) + if(LAZYLEN(offers)) + for(var/offer in offers) + if(ismob(offer)) + var/text = mob_transfer_message + to_chat(offer, replacetext(text, TRADER_TOKEN_ORIGIN, origin)) + qdel(offer) + + var/type = trading_items[num] + + var/atom/movable/M = new type(location) + playsound(location, 'sound/effects/teleport.ogg', 50, 1) + + disposition += rand(compliment_increase,compliment_increase*3) //Traders like it when you trade with them + + return M + +/datum/trader/proc/how_much_do_you_want(var/num, skill = SKILL_MAX) + . = get_response(TRADER_HOW_MUCH, "Hmm.... how about " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + "?") + . = replacetext(.,TRADER_TOKEN_VALUE,get_item_value(num, skill)) + . = replacetext(.,TRADER_TOKEN_ITEM, atom_info_repository.get_name_for(trading_items[num])) + +/datum/trader/proc/what_do_you_want() + if(!(trade_flags & TRADER_GOODS)) + return get_response(TRADER_NO_GOODS, "I don't deal in goods.") + . = get_response(TRADER_WHAT_WANT, "Hm, I want") + var/list/want_english = list() + for(var/wtype in wanted_items) + var/item_name = atom_info_repository.get_name_for(wtype) + want_english += item_name + . += " [english_list(want_english)]" + +/datum/trader/proc/sell_items(var/list/offers, skill = SKILL_MAX) + if(!(trade_flags & TRADER_GOODS)) + return TRADER_NO_GOODS + if(!LAZYLEN(offers)) + return TRADER_NOT_ENOUGH + + var/wanted + . = 0 + for(var/offer in offers) + if((trade_flags & TRADER_WANTED_ONLY) && is_type_in_list(offer,wanted_items)) + wanted = 1 + else if((trade_flags & TRADER_WANTED_ALL) && is_type_in_list(offer,possible_wanted_items)) + wanted = 0 + else + return TRADER_FOUND_UNWANTED + . += get_buy_price(offer, wanted, skill) + + playsound(get_turf(offers[1]), 'sound/effects/teleport.ogg', 50, 1) + for(var/offer in offers) + qdel(offer) + + +/datum/trader/proc/is_bribable() + SHOULD_CALL_PARENT(TRUE) + return (trade_flags & TRADER_BRIBABLE) + +/datum/trader/proc/is_bribed(var/staylength) + return get_response(TRADER_BRIBE_REFUSAL, "How about... no?") + +/datum/trader/proc/bribe_to_stay_longer(var/amt) + if(is_bribable()) + return is_bribed(round(amt/100)) + return get_response(TRADER_BRIBE_REFUSAL, "How about... no?") + +/datum/trader/Destroy(force) + if(hub) + hub.traders -= src + . = ..() diff --git a/code/datums/trading/_trading_defines.dm b/code/datums/trading/_trading_defines.dm deleted file mode 100644 index ead3d66ddfff..000000000000 --- a/code/datums/trading/_trading_defines.dm +++ /dev/null @@ -1,20 +0,0 @@ -#define TRADER_THIS_TYPE 1 -#define TRADER_SUBTYPES_ONLY 2 -#define TRADER_ALL 3 -#define TRADER_BLACKLIST 4 -#define TRADER_BLACKLIST_SUB 8 -#define TRADER_BLACKLIST_ALL 12 - -#define TRADER_WANTED_ONLY 1 //Do they only trade for wanted goods? -#define TRADER_MONEY 2 //Do they only accept money in return for goods. -#define TRADER_GOODS 4 //Do they accept goods in return for other goods. -#define TRADER_WANTED_ALL 8 //Like TRADER_WANTED_ONLY but they buy all possible wanted goods rather than a subset. - -//Possible response defines for when offering an item for something -#define TRADER_NO_MONEY "trade_no_money" -#define TRADER_NO_GOODS "trade_no_goods" -#define TRADER_NOT_ENOUGH "trade_not_enough" -#define TRADER_NO_BLACKLISTED "trade_blacklist" -#define TRADER_FOUND_UNWANTED "trade_found_unwanted" - -#define TRADER_DEFAULT_NAME "Default" //Whether to just generate a name from the premade lists. \ No newline at end of file diff --git a/code/datums/trading/ai.dm b/code/datums/trading/ai.dm deleted file mode 100644 index d3db65236500..000000000000 --- a/code/datums/trading/ai.dm +++ /dev/null @@ -1,122 +0,0 @@ -/* - -TRADING BEACON - -Trading beacons are generic AI driven trading outposts. -They sell generic supplies and ask for generic supplies. -*/ - -/datum/trader/trading_beacon - name = "AI" - origin = "Trading Beacon" - name_language = /decl/language/human/common - trade_flags = TRADER_MONEY|TRADER_GOODS - speech = list("hail_generic" = "Greetings, I am MERCHANT, Artifical Intelligence onboard ORIGIN, tasked with trading goods in return for CURRENCY and supplies.", - "hail_deny" = "We are sorry, your connection has been blacklisted. Have a nice day.", - - "trade_complete" = "Thank you for your patronage.", - "trade_not_enough" = "I'm sorry, your offer is not worth what you are asking for.", - "trade_blacklisted" = "You have offered a blacklisted item. My laws do not allow me to trade for that.", - "how_much" = "ITEM will cost you roughly VALUE CURRENCY, or something of equal worth.", - "what_want" = "I have logged need for", - - "compliment_deny" = "I'm sorry, I am not allowed to let compliments affect the trade.", - "compliment_accept" = "Thank you, but that will not not change our business interactions.", - "insult_good" = "I do not understand, are we not on good terms?", - "insult_bad" = "I do not understand, are you insulting me?", - - "bribe_refusal" = "You have given me money to stay, however, I am a station. I do not leave.", - ) - possible_wanted_items = list( - /obj/item = TRADER_SUBTYPES_ONLY, - /obj/item/assembly = TRADER_BLACKLIST_ALL, - /obj/item/assembly_holder = TRADER_BLACKLIST_ALL, - /obj/item/encryptionkey/syndicate = TRADER_BLACKLIST, - /obj/item/tank/onetankbomb = TRADER_BLACKLIST, - /obj/item/radio = TRADER_BLACKLIST_ALL, - /obj/item/modular_computer/pda = TRADER_BLACKLIST_SUB, - /obj/item/uplink = TRADER_BLACKLIST - ) - possible_trading_items = list( - /obj/item/storage/bag = TRADER_SUBTYPES_ONLY, - /obj/item/storage/bag/cash/infinite = TRADER_BLACKLIST, - /obj/item/storage/backpack = TRADER_ALL, - /obj/item/storage/backpack/cultpack = TRADER_BLACKLIST, - /obj/item/storage/backpack/holding = TRADER_BLACKLIST, - /obj/item/storage/backpack/satchel/grey/withwallet = TRADER_BLACKLIST, - /obj/item/storage/backpack/satchel/syndie_kit = TRADER_BLACKLIST_ALL, - /obj/item/storage/backpack/chameleon = TRADER_BLACKLIST, - /obj/item/storage/backpack/ert = TRADER_BLACKLIST_ALL, - /obj/item/storage/backpack/dufflebag/syndie = TRADER_BLACKLIST_SUB, - /obj/item/storage/belt/champion = TRADER_THIS_TYPE, - /obj/item/storage/briefcase = TRADER_THIS_TYPE, - /obj/item/storage/fancy = TRADER_SUBTYPES_ONLY, - /obj/item/storage/laundry_basket = TRADER_THIS_TYPE, - /obj/item/storage/secure/briefcase = TRADER_THIS_TYPE, - /obj/item/storage/plants = TRADER_THIS_TYPE, - /obj/item/storage/ore = TRADER_THIS_TYPE, - /obj/item/storage/toolbox = TRADER_ALL, - /obj/item/storage/wallet = TRADER_THIS_TYPE, - /obj/item/storage/photo_album = TRADER_THIS_TYPE, - /obj/item/clothing/glasses = TRADER_SUBTYPES_ONLY, - /obj/item/clothing/glasses/hud = TRADER_BLACKLIST_ALL, - /obj/item/clothing/glasses/blindfold/tape = TRADER_BLACKLIST, - /obj/item/clothing/glasses/chameleon = TRADER_BLACKLIST - ) - - insult_drop = 0 - compliment_increase = 0 - -/datum/trader/trading_beacon/New() - ..() - origin = "[origin] #[rand(100,999)]" - -/datum/trader/trading_beacon/mine - origin = "Mining Beacon" - - possible_trading_items = list( - /obj/item/ore = TRADER_SUBTYPES_ONLY, - /obj/item/stack/material/glass = TRADER_ALL, - /obj/item/stack/material/glass/fifty = TRADER_BLACKLIST, - /obj/item/stack/material/iron = TRADER_THIS_TYPE, - /obj/item/stack/material/sandstone = TRADER_THIS_TYPE, - /obj/item/stack/material/marble = TRADER_THIS_TYPE, - /obj/item/stack/material/diamond = TRADER_THIS_TYPE, - /obj/item/stack/material/uranium = TRADER_THIS_TYPE, - /obj/item/stack/material/plastic = TRADER_THIS_TYPE, - /obj/item/stack/material/gold = TRADER_THIS_TYPE, - /obj/item/stack/material/silver = TRADER_THIS_TYPE, - /obj/item/stack/material/platinum = TRADER_THIS_TYPE, - /obj/item/stack/material/mhydrogen = TRADER_THIS_TYPE, - /obj/item/stack/material/tritium = TRADER_THIS_TYPE, - /obj/item/stack/material/osmium = TRADER_THIS_TYPE, - /obj/item/stack/material/steel = TRADER_THIS_TYPE, - /obj/item/stack/material/plasteel = TRADER_THIS_TYPE, - /obj/machinery/mining = TRADER_SUBTYPES_ONLY - ) - -/datum/trader/trading_beacon/manufacturing - origin = "Manifacturing Beacon" - - possible_trading_items = list(/obj/structure/aicore = TRADER_THIS_TYPE, - /obj/structure/girder = TRADER_THIS_TYPE, - /obj/structure/grille = TRADER_THIS_TYPE, - /obj/structure/mopbucket = TRADER_THIS_TYPE, - /obj/structure/ore_box = TRADER_THIS_TYPE, - /obj/structure/coatrack = TRADER_THIS_TYPE, - /obj/structure/bookcase = TRADER_THIS_TYPE, - /obj/item/bee_pack = TRADER_THIS_TYPE, - /obj/item/bee_smoker = TRADER_THIS_TYPE, - /obj/item/beehive_assembly = TRADER_THIS_TYPE, - /obj/item/glass_jar = TRADER_THIS_TYPE, - /obj/item/honey_frame = TRADER_THIS_TYPE, - /obj/item/target = TRADER_ALL, - /obj/structure/dispenser = TRADER_SUBTYPES_ONLY, - /obj/structure/filingcabinet = TRADER_THIS_TYPE, - /obj/structure/safe = TRADER_THIS_TYPE, - /obj/structure/plushie = TRADER_SUBTYPES_ONLY, - /obj/structure/sign = TRADER_SUBTYPES_ONLY, - /obj/structure/sign/double = TRADER_BLACKLIST_ALL, - /obj/structure/sign/goldenplaque = TRADER_BLACKLIST_ALL, - /obj/structure/sign/poster = TRADER_BLACKLIST - ) \ No newline at end of file diff --git a/code/datums/trading/food.dm b/code/datums/trading/food.dm deleted file mode 100644 index 840e3f609221..000000000000 --- a/code/datums/trading/food.dm +++ /dev/null @@ -1,166 +0,0 @@ -/datum/trader/pizzaria - name = "Pizza Shop Employee" - name_language = TRADER_DEFAULT_NAME - origin = "Pizzeria" - possible_origins = list("Papa Joe's", "Pizza Ship", "Dominator Pizza", "Little Kaezars", "Pizza Planet", "Cheese Louise", "Little Taste o' Neo-Italy", "Pizza Gestapo") - trade_flags = TRADER_MONEY - possible_wanted_items = list() //They are a pizza shop, not a bargainer. - possible_trading_items = list(/obj/item/chems/food/snacks/sliceable/pizza = TRADER_SUBTYPES_ONLY) - - speech = list("hail_generic" = "Hello! Welcome to ORIGIN, may I take your order?", - "hail_deny" = "Beeeep... I'm sorry, your connection has been severed.", - - "trade_complete" = "Thank you for choosing ORIGIN!", - "trade_no_goods" = "I'm sorry but we only take cash.", - "trade_blacklisted" = "Sir that's... highly illegal.", - "trade_not_enough" = "Uhh... that's not enough money for pizza.", - "how_much" = "That pizza will cost you VALUE CURRENCY.", - - "compliment_deny" = "That's a bit forward, don't you think?", - "compliment_accept" = "Thanks, sir! You're very nice!", - "insult_good" = "Please stop that, sir.", - "insult_bad" = "Sir, just because I'm contractually obligated to keep you on the line for a minute doesn't mean I have to take this.", - - "bribe_refusal" = "Uh... thanks for the cash, sir. As long as you're in the area, we'll be here...", - ) - -/datum/trader/pizzaria/trade(var/list/offers, var/num, var/turf/location) - . = ..() - if(.) - var/atom/movable/M = . - var/obj/item/pizzabox/box = new(location) - M.forceMove(box) - box.pizza = M - box.boxtag = "A special order from [origin]" - -/datum/trader/ship/chinese - name = "Chinese Restaurant" - name_language = TRADER_DEFAULT_NAME - origin = "Captain Panda Bistro" - possible_origins = list("888 Shanghai Kitchen", "Mr. Lee's Greater Hong Kong", "The House of the Venerable and Inscrutable Colonel", "Lucky Dragon") - trade_flags = TRADER_MONEY - possible_wanted_items = list() - possible_trading_items = list(/obj/item/chems/food/snacks/meatkabob = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/monkeysdelight = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/ricepudding = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/xenomeatbread/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/soydope = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/stewedsoymeat = TRADER_THIS_TYPE, - /obj/item/chems/food/drinks/dry_ramen = TRADER_THIS_TYPE - ) - - var/list/fortunes = list("Today it's up to you to create the peacefulness you long for.", - "If you refuse to accept anything but the best, you very often get it.", - "A smile is your passport into the hearts of others.", - "Hard work pays off in the future, laziness pays off now.", - "Change can hurt, but it leads a path to something better.", - "Hidden in a valley beside an open stream- This will be the type of place where you will find your dream.", - "Never give up. You're not a failure if you don't give up.", - "Love can last a lifetime, if you want it to.", - "The love of your life is stepping into your planet this summer.", - "Your ability for accomplishment will follow with success.", - "Please help me, I'm trapped in a fortune cookie factory!") - - speech = list("hail_generic" = "There are two things constant in life, death and Chinese food. How may I help you?", - "hail_deny" = "We do not take orders from rude customers.", - - "trade_complete" = "Thank you, sir, for your patronage.", - "trade_blacklist" = "No, that is very odd. Why would you trade that away?", - "trade_no_goods" = "I only accept money transfers.", - "trade_not_enough" = "No, I am sorry, that is not possible. I need to make a living.", - "how_much" = "I give you ITEM, for VALUE CURRENCY. No more, no less.", - - "compliment_deny" = "That was an odd thing to say. You are very odd.", - "compliment_accept" = "Good philosophy, see good in bad, I like.", - "insult_good" = "As a man said long ago, \"When anger rises, think of the consequences.\" Think on that.", - "insult_bad" = "I do not need to take this from you.", - - "bribe_refusal" = "Hm... I'll think about it.", - "bribe_accept" = "Oh yes! I think I'll stay a few more minutes, then.", - ) - -/datum/trader/ship/chinese/trade(var/list/offers, var/num, var/turf/location) - . = ..() - if(.) - var/obj/item/chems/food/snacks/fortunecookie/cookie = new(location) - var/obj/item/paper/paper = new(cookie) - cookie.trash = paper - paper.SetName("Fortune") - paper.info = pick(fortunes) - -/datum/trader/grocery - name = "Grocer" - name_language = TRADER_DEFAULT_NAME - possible_origins = list("HyTee", "Kreugars", "Spaceway", "Privaxs", "FutureValue", "Phyvendyme", "Seller's Market") - trade_flags = TRADER_MONEY - - possible_trading_items = list(/obj/item/chems/food/snacks = TRADER_SUBTYPES_ONLY, - /obj/item/chems/food/drinks/cans = TRADER_SUBTYPES_ONLY, - /obj/item/chems/food/drinks/bottle = TRADER_SUBTYPES_ONLY, - /obj/item/chems/food/drinks/bottle/small = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/checker = TRADER_BLACKLIST_ALL, - /obj/item/chems/food/snacks/fruit_slice = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/slice = TRADER_BLACKLIST_ALL, - /obj/item/chems/food/snacks/grown = TRADER_BLACKLIST_ALL, - /obj/item/chems/food/snacks/human = TRADER_BLACKLIST_ALL, - /obj/item/chems/food/snacks/sliceable/braincake = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/meat/human = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/variable = TRADER_BLACKLIST_ALL - ) - - speech = list("hail_generic" = "Hello, welcome to ORIGIN, grocery store of the future!", - "hail_deny" = "I'm sorry, we've blacklisted your communications due to rude behavior.", - - "trade_complete" = "Thank you for shopping at ORIGIN!", - "trade_blacklist" = "I... wow, that's... no, sir. No.", - "trade_no_goods" = "ORIGIN only accepts cash, sir.", - "trade_not_enough" = "That is not enough money, sir.", - "how_much" = "Sir, that'll cost you VALUE CURRENCY. Will that be all?", - - "compliment_deny" = "Sir, this is a professional environment. Please don't make me get my manager.", - "compliment_accept" = "Thank you, sir!", - "insult_good" = "Sir, please do not make a scene.", - "insult_bad" = "Sir, I WILL get my manager if you don't calm down.", - - "bribe_refusal" = "Of course sir! ORIGIN is always here for you!", - ) - -/datum/trader/bakery - name = "Pastry Chef" - name_language = TRADER_DEFAULT_NAME - origin = "Bakery" - possible_origins = list("Cakes By Design", "Corner Bakery Local", "My Favorite Cake & Pastry Cafe", "Mama Joes Bakery", "Sprinkles and Fun", "Cakestrosity") - - speech = list("hail_generic" = "Hello, welcome to ORIGIN! We serve baked goods, including pies, cakes, and anything sweet!", - "hail_deny" = "Our food is a privilege, not a right. Goodbye.", - - "trade_complete" = "Thank you for your purchase! Come again if you're hungry for more!", - "trade_blacklist" = "We only accept money. Not... that.", - "trade_no_goods" = "Cash for cakes! That's our business!", - "trade_not_enough" = "Our dishes are much more expensive than that, sir.", - "how_much" = "That lovely dish will cost you VALUE CURRENCY.", - - "compliment_deny" = "Oh wow, how nice of you...", - "compliment_accept" = "You're almost as sweet as my pies!", - "insult_good" = "My pies are NOT knockoffs!", - "insult_bad" = "Well, aren't you a sour apple?", - - "bribe_refusal" = "Oh ho ho! I'd never think of taking ORIGIN on the road!", - ) - possible_trading_items = list(/obj/item/chems/food/snacks/slice/birthdaycake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/carrotcake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/cheesecake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/chocolatecake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/lemoncake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/limecake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/orangecake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/plaincake/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/pumpkinpie/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/slice/bananabread/filled = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/sliceable = TRADER_SUBTYPES_ONLY, - /obj/item/chems/food/snacks/sliceable/pizza = TRADER_BLACKLIST_ALL, - /obj/item/chems/food/snacks/sliceable/xenomeatbread = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/sliceable/flatdough = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/sliceable/braincake = TRADER_BLACKLIST, - /obj/item/chems/food/snacks/pie = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/applepie = TRADER_THIS_TYPE) \ No newline at end of file diff --git a/code/datums/trading/goods.dm b/code/datums/trading/goods.dm deleted file mode 100644 index 57914d0b5b55..000000000000 --- a/code/datums/trading/goods.dm +++ /dev/null @@ -1,388 +0,0 @@ -/datum/trader/ship/toyshop - name = "Toy Shop Employee" - name_language = TRADER_DEFAULT_NAME - origin = "Toy Shop" - trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY - possible_origins = list("Toys R Ours", "LEGS GO", "Kay-Cee Toys", "Build-a-Cat", "Magic Box", "The Positronic's Dungeon and Baseball Card Shop") - speech = list("hail_generic" = "Uhh... hello? Welcome to ORIGIN, I hope you have a, uhh.... good shopping trip.", - "hail_deny" = "Nah, you're not allowed here. At all", - - "trade_complete" = "Thanks for shopping... here... at ORIGIN.", - "trade_blacklist" = "Uuuhhh.... no.", - "trade_found_unwanted" = "Nah! That's not what I'm looking for. Something rarer.", - "trade_not_enough" = "Just 'cause they're made of cardboard doesn't mean they don't cost money...", - "how_much" = "Uhh... I'm thinking like... VALUE. Right? Or something rare that complements my interest.", - "what_want" = "Ummmm..... I guess I want", - - "compliment_deny" = "Ha! Very funny! You should write your own television show.", - "compliment_accept" = "Why yes, I do work out.", - "insult_good" = "Well, well, well. Guess we learned who was the troll here.", - "insult_bad" = "I've already written a nasty Spacebook post in my mind about you.", - - "bribe_refusal" = "Nah. I need to get moving as soon as uhh... possible.", - "bribe_accept" = "You know what, I wasn't doing anything for TIME minutes anyways.", - ) - - possible_wanted_items = list(/obj/item/toy/figure = TRADER_THIS_TYPE, - /obj/item/toy/figure/ert = TRADER_THIS_TYPE, - /obj/item/toy/prize/honk = TRADER_THIS_TYPE) - - possible_trading_items = list(/obj/item/toy/prize = TRADER_SUBTYPES_ONLY, - /obj/item/toy/prize/honk = TRADER_BLACKLIST, - /obj/item/toy/figure = TRADER_SUBTYPES_ONLY, - /obj/item/toy/figure/ert = TRADER_BLACKLIST, - /obj/item/toy/plushie = TRADER_SUBTYPES_ONLY, - /obj/item/sword/katana/toy = TRADER_THIS_TYPE, - /obj/item/toy/sword = TRADER_THIS_TYPE, - /obj/item/toy/bosunwhistle = TRADER_THIS_TYPE, - /obj/item/board = TRADER_THIS_TYPE, - /obj/item/storage/box/checkers = TRADER_ALL, - /obj/item/deck = TRADER_SUBTYPES_ONLY, - /obj/item/pack = TRADER_SUBTYPES_ONLY, - /obj/item/dice = TRADER_ALL, - /obj/item/dice/d20/cursed = TRADER_BLACKLIST, - /obj/item/gun/launcher/money = TRADER_THIS_TYPE) - -/datum/trader/ship/electronics - name = "Electronic Shop Employee" - name_language = TRADER_DEFAULT_NAME - origin = "Electronic Shop" - possible_origins = list("Best Sale", "Overstore", "Oldegg", "Circuit Citadel", "Silicon Village", "Positronic Solutions LLC", "Sunvolt Inc.") - - speech = list("hail_generic" = "Hello, sir! Welcome to ORIGIN, I hope you find what you are looking for.", - "hail_deny" = "Your call has been disconnected.", - - "trade_complete" = "Thank you for shopping at ORIGIN, would you like to get the extended warranty as well?", - "trade_blacklist" = "Sir, this is a /electronics/ store.", - "trade_no_goods" = "As much as I'd love to buy that from you, I can't.", - "trade_not_enough" = "Your offer isn't adequate, sir.", - "how_much" = "Your total comes out to VALUE CURRENCY.", - - "compliment_deny" = "Hahaha! Yeah... funny...", - "compliment_accept" = "That's very nice of you!", - "insult_good" = "That was uncalled for, sir. Don't make me get my manager.", - "insult_bad" = "Sir, I am allowed to hang up the phone if you continue, sir.", - - "bribe_refusal" = "Sorry, sir, but I can't really do that.", - "bribe_accept" = "Why not! Glad to be here for a few more minutes.", - ) - - possible_trading_items = list(/obj/item/stock_parts/computer/battery_module = TRADER_SUBTYPES_ONLY, - /obj/item/stock_parts/circuitboard = TRADER_SUBTYPES_ONLY, - /obj/item/stock_parts/circuitboard/telecomms = TRADER_BLACKLIST, - /obj/item/stock_parts/circuitboard/unary_atmos = TRADER_BLACKLIST, - /obj/item/stock_parts/circuitboard/arcade = TRADER_BLACKLIST, - /obj/item/stock_parts/circuitboard/broken = TRADER_BLACKLIST, - /obj/item/stack/cable_coil = TRADER_SUBTYPES_ONLY, - /obj/item/stack/cable_coil/cyborg = TRADER_BLACKLIST, - /obj/item/stack/cable_coil/random = TRADER_BLACKLIST, - /obj/item/stack/cable_coil/cut = TRADER_BLACKLIST, - /obj/item/stock_parts/circuitboard/air_alarm = TRADER_THIS_TYPE, - /obj/item/stock_parts/circuitboard/airlock_electronics = TRADER_ALL, - /obj/item/cell = TRADER_THIS_TYPE, - /obj/item/cell/crap = TRADER_THIS_TYPE, - /obj/item/cell/high = TRADER_THIS_TYPE, - /obj/item/cell/super = TRADER_THIS_TYPE, - /obj/item/cell/hyper = TRADER_THIS_TYPE, - /obj/item/tracker_electronics = TRADER_THIS_TYPE) - - -/* Clothing stores: each a different type. A hat/glove store, a shoe store, and a jumpsuit store. */ - -/datum/trader/ship/clothingshop - name = "Clothing Store Employee" - name_language = TRADER_DEFAULT_NAME - origin = "Clothing Store" - possible_origins = list("Space Eagle", "Banana Democracy", "Forever 22", "Textiles Factory Warehouse Outlet", "Blocks Brothers") - speech = list("hail_generic" = "Hello, sir! Welcome to ORIGIN!", - "hail_Vox" = "Well hello, sir! I don't believe we have any clothes that fit you... but you can still look!", - "hail_deny" = "We do not trade with rude customers. Consider yourself blacklisted.", - - "trade_complete" = "Thank you for shopping at ORIGIN. Remember: We cannot accept returns without the original tags!", - "trade_blacklist" = "Hm, how about no?", - "trade_no_goods" = "We don't buy, sir. Only sell.", - "trade_not_enough" = "Sorry, ORIGIN policy to not accept trades below our marked prices.", - "how_much" = "Your total comes out to VALUE CURRENCY.", - - "compliment_deny" = "Excuse me?", - "compliment_accept" = "Aw, you're so nice!", - "insult_good" = "Sir.", - "insult_bad" = "Wow. I don't have to take this.", - - "bribe_refusal" = "ORIGIN policy clearly states we cannot stay for more than the designated time.", - "bribe_accept" = "Hm.... sure! We'll have a few minutes of 'engine troubles'.", - ) - - possible_trading_items = list(/obj/item/clothing/under = TRADER_SUBTYPES_ONLY, - /obj/item/clothing/under/acj = TRADER_BLACKLIST, - /obj/item/clothing/under/chameleon = TRADER_BLACKLIST, - /obj/item/clothing/under/color = TRADER_BLACKLIST, - /obj/item/clothing/under/dress = TRADER_BLACKLIST, - /obj/item/clothing/under/gimmick = TRADER_BLACKLIST_ALL, - /obj/item/clothing/under/lawyer = TRADER_BLACKLIST, - /obj/item/clothing/under/pj = TRADER_BLACKLIST, - /obj/item/clothing/under/rank = TRADER_BLACKLIST, - /obj/item/clothing/under/shorts = TRADER_BLACKLIST, - /obj/item/clothing/under/stripper = TRADER_BLACKLIST_ALL, - /obj/item/clothing/under/syndicate = TRADER_BLACKLIST_ALL, - /obj/item/clothing/under/tactical = TRADER_BLACKLIST, - /obj/item/clothing/under/wedding = TRADER_BLACKLIST, - /obj/item/clothing/under/punpun = TRADER_BLACKLIST) - -/datum/trader/ship/clothingshop/shoes - possible_origins = list("Foot Safe", "Paysmall", "Popular Footwear", "Grimbly's Shoes", "Right Steps") - possible_trading_items = list(/obj/item/clothing/shoes = TRADER_SUBTYPES_ONLY, - /obj/item/clothing/shoes/chameleon = TRADER_BLACKLIST, - /obj/item/clothing/shoes/jackboots/swat/combat = TRADER_BLACKLIST, - /obj/item/clothing/shoes/clown_shoes = TRADER_BLACKLIST, - /obj/item/clothing/shoes/cult = TRADER_BLACKLIST, - /obj/item/clothing/shoes/lightrig = TRADER_BLACKLIST_ALL, - /obj/item/clothing/shoes/magboots = TRADER_BLACKLIST_ALL, - /obj/item/clothing/shoes/jackboots/swat = TRADER_BLACKLIST, - /obj/item/clothing/shoes/syndigaloshes = TRADER_BLACKLIST) - -/datum/trader/ship/clothingshop/hatglovesaccessories - possible_origins = list("Baldie's Hats and Accessories", "The Right Fit", "Like a Glove", "Space Fashion") - possible_trading_items = list(/obj/item/clothing/accessory = TRADER_ALL, - /obj/item/clothing/accessory/badge = TRADER_BLACKLIST_ALL, - /obj/item/clothing/accessory/storage/holster = TRADER_BLACKLIST_ALL, - /obj/item/clothing/accessory/medal = TRADER_BLACKLIST_ALL, - /obj/item/clothing/accessory/storage = TRADER_BLACKLIST_ALL, - /obj/item/clothing/gloves = TRADER_SUBTYPES_ONLY, - /obj/item/clothing/gloves/lightrig = TRADER_BLACKLIST_ALL, - /obj/item/clothing/gloves/rig = TRADER_BLACKLIST_ALL, - /obj/item/clothing/gloves/thick/swat = TRADER_BLACKLIST, - /obj/item/clothing/gloves/chameleon = TRADER_BLACKLIST, - /obj/item/clothing/head = TRADER_SUBTYPES_ONLY, - /obj/item/clothing/head/HoS = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/bio_hood = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/bomb_hood = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/caphat = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/centhat = TRADER_BLACKLIST, - /obj/item/clothing/head/chameleon = TRADER_BLACKLIST, - /obj/item/clothing/head/collectable = TRADER_BLACKLIST, - /obj/item/clothing/head/culthood = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/helmet = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/lightrig = TRADER_BLACKLIST_ALL, - /obj/item/clothing/head/radiation = TRADER_BLACKLIST, - /obj/item/clothing/head/warden = TRADER_BLACKLIST, - /obj/item/clothing/head/welding = TRADER_BLACKLIST) - - - -/* -Sells devices, odds and ends, and medical stuff -*/ -/datum/trader/devices - name = "Drugstore Employee" - name_language = TRADER_DEFAULT_NAME - origin = "Drugstore" - possible_origins = list("Buy 'n Save", "Drug Carnival", "C&B", "Fentles", "Dr. Goods", "Beevees", "McGillicuddy's") - possible_trading_items = list(/obj/item/flashlight = TRADER_ALL, - /obj/item/kit/paint = TRADER_SUBTYPES_ONLY, - /obj/item/aicard = TRADER_THIS_TYPE, - /obj/item/binoculars = TRADER_THIS_TYPE, - /obj/item/cable_painter = TRADER_THIS_TYPE, - /obj/item/flash = TRADER_THIS_TYPE, - /obj/item/floor_painter = TRADER_THIS_TYPE, - /obj/item/multitool = TRADER_THIS_TYPE, - /obj/item/lightreplacer = TRADER_THIS_TYPE, - /obj/item/megaphone = TRADER_THIS_TYPE, - /obj/item/paicard = TRADER_THIS_TYPE, - /obj/item/pipe_painter = TRADER_THIS_TYPE, - /obj/item/scanner/health = TRADER_THIS_TYPE, - /obj/item/scanner/gas = TRADER_ALL, - /obj/item/scanner/spectrometer = TRADER_ALL, - /obj/item/scanner/reagent = TRADER_ALL, - /obj/item/scanner/xenobio = TRADER_THIS_TYPE, - /obj/item/suit_cooling_unit = TRADER_THIS_TYPE, - /obj/item/t_scanner = TRADER_THIS_TYPE, - /obj/item/taperecorder = TRADER_THIS_TYPE, - /obj/item/batterer = TRADER_THIS_TYPE, - /obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE, - /obj/item/hailer = TRADER_THIS_TYPE, - /obj/item/uv_light = TRADER_THIS_TYPE, - /obj/item/mmi = TRADER_ALL, - /obj/item/robotanalyzer = TRADER_THIS_TYPE, - /obj/item/toner = TRADER_THIS_TYPE, - /obj/item/camera_film = TRADER_THIS_TYPE, - /obj/item/camera = TRADER_THIS_TYPE, - /obj/item/destTagger = TRADER_THIS_TYPE, - /obj/item/gps = TRADER_THIS_TYPE, - /obj/item/measuring_tape = TRADER_THIS_TYPE, - /obj/item/ano_scanner = TRADER_THIS_TYPE, - /obj/item/core_sampler = TRADER_THIS_TYPE, - /obj/item/depth_scanner = TRADER_THIS_TYPE, - /obj/item/pinpointer/radio = TRADER_THIS_TYPE, - /obj/item/stack/medical/advanced = TRADER_BLACKLIST) - speech = list("hail_generic" = "Hello, hello! Bits and bobs and everything in between, I hope you find what you're looking for!", - "hail_silicon" = "Ah! Hello, robot. We only sell things that, ah.... people can hold in their hands, unfortunately. You are still allowed to buy, though!", - "hail_deny" = "Oh no. I don't want to deal with YOU.", - - "trade_complete" = "Thank you! Now remember, there isn't any return policy here, so be careful with that!", - "trade_blacklist" = "Hm. Well that would be illegal, so no.", - "trade_no_goods" = "I'm sorry, I only sell goods.", - "trade_not_enough" = "Gotta pay more than that to get that!", - "how_much" = "Well... I bought it for a lot, but I'll give it to you for VALUE.", - - "compliment_deny" = "Uh... did you say something?", - "compliment_accept" = "Mhm! I can agree to that!", - "insult_good" = "Wow, where was that coming from?", - "insult_bad" = "Don't make me blacklist your connection.", - - "bribe_refusal" = "Well, as much as I'd love to say 'yes', you realize I operate on a station, correct?", - ) - -/datum/trader/ship/robots - name = "Robot Seller" - name_language = TRADER_DEFAULT_NAME - origin = "Robot Store" - possible_origins = list("AI for the Straight Guy", "Mechanical Buddies", "Bot Chop Shop", "Omni Consumer Projects") - possible_trading_items = list( - /obj/item/bot_kit = TRADER_THIS_TYPE, - /obj/item/paicard = TRADER_THIS_TYPE, - /obj/item/aicard = TRADER_THIS_TYPE, - /mob/living/bot = TRADER_SUBTYPES_ONLY) - speech = list("hail_generic" = "Welcome to ORIGIN! Let me walk you through our fine robotic selection!", - "hail_silicon" = "Welcome to ORIGIN! Let- oh, you're a synth! Well, your money is good anyway. Welcome, welcome!", - "hail_deny" = "ORIGIN no longer wants to speak to you.", - - "trade_complete" = "I hope you enjoy your new robot!", - "trade_blacklist"= "I work with robots, sir. Not that.", - "trade_no_goods" = "You gotta buy the robots, sir. I don't do trades.", - "trade_not_enough" = "You're coming up short on cash.", - "how_much" = "My fine selection of robots will cost you VALUE!", - - "compliment_deny"= "Well, I almost believed that.", - "compliment_accept"= "Thank you! My craftsmanship is my life.", - "insult_good" = "Uncalled for.... uncalled for.", - "insult_bad" = "I've programmed AI better at insulting than you!", - - "bribe_refusal" = "I've got too many customers waiting in other sectors, sorry.", - "bribe_accept" = "Hm. Don't keep me waiting too long, though.", - ) - -/datum/trader/xeno_shop - name = "Xenolife Collector" - origin = "CSV Not a Poacher" - trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY|TRADER_WANTED_ALL - possible_origins = list("XenoHugs", "Exotic Specimen Acquisition", "Skinner Catering Reseller", "Corporate Companionship Division", "Lonely Pete's Exotic Companionship","Space Wei's Exotic Cuisine") - speech = list("hail_generic" = "Welcome! We are always looking to acquire more exotic life forms.", - "hail_deny" = "We no longer wish to speak to you. Please contact our legal representative if you wish to rectify this.", - - "trade_complete" = "Remember to give them attention and food. They are living beings, and you should treat them like so.", - "trade_blacklist" = "Legally I can't do that. Morally... well, I refuse to do that.", - "trade_found_unwanted" = "I only want animals. I don't need food or shiny things. I'm looking for specific ones, at that. Ones I already have the cage and food for.", - "trade_not_enough" = "I'd give you this for free, but I need the money to feed the specimens. So you must pay in full.", - "how_much" = "This is a good choice. I believe it will cost you VALUE CURRENCY.", - "what_want" = "I have the facilities, currently, to support", - - "compliment_deny" = "According to customs on 34 planets I traded with, this constitutes sexual harrasment.", - "compliment_accept" = "Thank you. I needed that.", - "insult_good" = "No need to be upset, I believe we can do business.", - "insult_bad" = "I have traded dogs with more bark than that.", - ) - - possible_wanted_items = list(/mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, - /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, - /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE) - - possible_trading_items = list(/mob/living/simple_animal/hostile/carp= TRADER_THIS_TYPE, - /obj/item/dociler = TRADER_THIS_TYPE, - /obj/item/beartrap = TRADER_THIS_TYPE, - /obj/item/scanner/xenobio = TRADER_THIS_TYPE) - -/datum/trader/medical - name = "Medical Supplier" - origin = "Infirmary of CSV Iniquity" - trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY - want_multiplier = 1.2 - margin = 2 - possible_origins = list("Dr.Krieger's Practice", "Legit Medical Supplies (No Refund)", "Mom's & Pop's Addictive Opoids", "Legitimate Pharmaceutical Firm", "Designer Drugs by Lil Xanny") - speech = list("hail_generic" = "Huh? How'd you get this number?! Oh well, if you wanna talk biz, I'm listening.", - "hail_deny" = "This is an automated message. Feel free to fuck the right off after the buzzer. *buzz*", - - "trade_complete" = "Good to have business with ya. Remember, no refunds.", - "trade_blacklist" = "Whoa whoa, I don't want this shit, put it away.", - "trade_found_unwanted" = "What the hell do you expect me to do with this junk?", - "trade_not_enough" = "Sorry, pal, full payment upfront, I don't write the rules. Well, I do, but that's beside the point.", - "how_much" = "Hmm, this is one damn fine item, but I'll part with it for VALUE CURRENCY.", - "what_want" = "I could always use some fucking", - - "compliment_deny" = "Haha, how nice of you. Why don't you go fall in an elevator shaft.", - "compliment_accept" = "Damn right I'm awesome, tell me more.", - "insult_good" = "Damn, pal, no need to get snippy.", - "insult_bad" = "*muffled laughter* Sorry, was that you trying to talk shit? Adorable.", - ) - - possible_wanted_items = list(/obj/item/chems/food/drinks/bottle = TRADER_THIS_TYPE, - /obj/item/organ/internal/liver = TRADER_THIS_TYPE, - /obj/item/organ/internal/kidneys = TRADER_THIS_TYPE, - /obj/item/organ/internal/lungs = TRADER_THIS_TYPE, - /obj/item/organ/internal/heart = TRADER_THIS_TYPE, - /obj/item/storage/fancy/cigarettes = TRADER_ALL - ) - - possible_trading_items = list(/obj/item/storage/pill_bottle = TRADER_SUBTYPES_ONLY, - /obj/item/storage/firstaid/fire = TRADER_THIS_TYPE, - /obj/item/storage/firstaid/toxin = TRADER_THIS_TYPE, - /obj/item/storage/firstaid/adv = TRADER_THIS_TYPE, - /obj/item/storage/box/bloodpacks = TRADER_THIS_TYPE, - /obj/item/chems/ivbag = TRADER_SUBTYPES_ONLY, - /obj/item/retractor = TRADER_THIS_TYPE, - /obj/item/hemostat = TRADER_THIS_TYPE, - /obj/item/cautery = TRADER_THIS_TYPE, - /obj/item/surgicaldrill = TRADER_THIS_TYPE, - /obj/item/scalpel = TRADER_THIS_TYPE, - /obj/item/scalpel/manager = TRADER_THIS_TYPE, - /obj/item/circular_saw = TRADER_THIS_TYPE, - /obj/item/bonegel = TRADER_THIS_TYPE, - /obj/item/bonesetter = TRADER_THIS_TYPE, - /obj/item/chems/glass/bottle/stabilizer = TRADER_THIS_TYPE, - /obj/item/chems/glass/bottle/sedatives = TRADER_THIS_TYPE, - /obj/item/chems/glass/bottle/antitoxin = TRADER_THIS_TYPE, - /obj/item/bodybag/cryobag = TRADER_THIS_TYPE, - /obj/item/sign/medipolma = TRADER_THIS_TYPE - ) - -/datum/trader/mining - name = "Rock'n'Drill Mining Inc" - origin = "Automated Smelter AH-532" - trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY|TRADER_WANTED_ALL - want_multiplier = 1.5 - margin = 2 - possible_origins = list("Automated Smelter AH-532", "CMV Locust", "The Galactic Foundry Company", "Crucible LLC") - speech = list("hail_generic" = "Welcome to R'n'D Mining. Please place your order.", - "hail_deny" = "There is no response on the line.", - - "trade_complete" = "Transaction complete. Please use our services again", - "trade_blacklist" = "Whoa whoa, I don't want this shit, put it away.", - "trade_found_unwanted" = "Sorry, we are currently not looking to purchase these items.", - "trade_not_enough" = "Sorry, this is an insufficient sum for this purchase.", - "how_much" = "For ONE entry of ITEM the price would be VALUE CURRENCY.", - "what_want" = "We are currently looking to procure", - - "compliment_deny" = "I am afraid this is beyond my competency.", - "compliment_accept" = "Thank you.", - "insult_good" = "Alright, we will reconsider the terms.", - "insult_bad" = "This is not acceptable, please cease.", - ) - - possible_wanted_items = list(/obj/item/ore/ = TRADER_SUBTYPES_ONLY, - /obj/item/disk/survey = TRADER_THIS_TYPE, - /obj/item/ore/slag = TRADER_BLACKLIST) - - possible_trading_items = list(/obj/machinery/mining/drill = TRADER_THIS_TYPE, - /obj/machinery/mining/brace = TRADER_THIS_TYPE, - /obj/machinery/floodlight = TRADER_THIS_TYPE, - /obj/machinery/floodlight = TRADER_THIS_TYPE, - /obj/item/storage/box/greenglowsticks = TRADER_THIS_TYPE, - /obj/item/clothing/suit/space/void/engineering/salvage/prepared = TRADER_THIS_TYPE, - /obj/item/stack/material/uranium/ten = TRADER_THIS_TYPE, - /obj/item/stack/material/plasteel/fifty = TRADER_THIS_TYPE, - /obj/item/stack/material/steel/fifty = TRADER_THIS_TYPE - ) diff --git a/code/datums/trading/misc.dm b/code/datums/trading/misc.dm deleted file mode 100644 index 086532770b74..000000000000 --- a/code/datums/trading/misc.dm +++ /dev/null @@ -1,153 +0,0 @@ -/datum/trader/ship/pet_shop - name = "Pet Shop Owner" - name_language = /decl/language/human/common - origin = "Pet Shop" - trade_flags = TRADER_GOODS|TRADER_MONEY|TRADER_WANTED_ONLY - possible_origins = list("Paws-Out", "Pets-R-Smart", "Tentacle Companions", "Xeno-Pets and Assorted Goods", "Barks and Drools") - speech = list("hail_generic" = "Welcome to my xeno-pet shop! Here you will find many wonderful companions. Some a bit more... aggressive than others. But companions none the less. I also buy pets, or trade them.", - "hail_deny" = "I no longer wish to speak to you.", - - "trade_complete" = "Remember to give them attention and food. They are living beings, and you should treat them like so.", - "trade_blacklist" = "Legally I can' do that. Morally, I refuse to do that.", - "trade_found_unwanted" = "I only want animals. I don't need food or shiny things. I'm looking for specific ones at that. Ones I already have the cage and food for.", - "trade_not_enough" = "I'd give you the animal for free, but I need the money to feed the others. So you must pay in full.", - "how_much" = "This is a fine specimen. I believe it will cost you VALUE CURRENCY.", - "what_want" = "I have the facilities, currently, to support", - - "compliment_deny" = "That was almost charming.", - "compliment_accept" = "Thank you. I needed that.", - "insult_good" = "I ask you to stop. We can be peaceful. I know we can.", - "insult_bad" = "My interactions with you are becoming less than fruitful.", - - "bribe_refusal" = "I'm not going to do that. I have places to be.", - "bribe_accept" = "Hm. It'll be good for the animals, so sure.", - ) - - possible_wanted_items = list(/mob/living/simple_animal/corgi = TRADER_THIS_TYPE, - /mob/living/simple_animal/cat = TRADER_THIS_TYPE, - /mob/living/simple_animal/crab = TRADER_THIS_TYPE, - /mob/living/simple_animal/lizard = TRADER_THIS_TYPE, - /mob/living/simple_animal/mouse = TRADER_THIS_TYPE, - /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE, - /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, - /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, - /mob/living/simple_animal/cow = TRADER_THIS_TYPE, - /mob/living/simple_animal/chick = TRADER_THIS_TYPE, - /mob/living/simple_animal/chicken = TRADER_THIS_TYPE, - /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/bear= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/parrot = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE) - - possible_trading_items = list(/mob/living/simple_animal/corgi = TRADER_THIS_TYPE, - /mob/living/simple_animal/cat = TRADER_THIS_TYPE, - /mob/living/simple_animal/crab = TRADER_THIS_TYPE, - /mob/living/simple_animal/lizard = TRADER_THIS_TYPE, - /mob/living/simple_animal/mouse = TRADER_THIS_TYPE, - /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE, - /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, - /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, - /mob/living/simple_animal/cow = TRADER_THIS_TYPE, - /mob/living/simple_animal/chick = TRADER_THIS_TYPE, - /mob/living/simple_animal/chicken = TRADER_THIS_TYPE, - /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/diyaab = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/bear= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/shantak= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/parrot = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/beast/samak= TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/retaliate/goat = TRADER_THIS_TYPE, - /mob/living/simple_animal/hostile/carp= TRADER_THIS_TYPE, - /obj/item/dociler = TRADER_THIS_TYPE, - /obj/structure/dogbed = TRADER_THIS_TYPE) - -/datum/trader/ship/prank_shop - name = "Prank Shop Owner" - name_language = /decl/language/human/common - origin = "Prank Shop" - compliment_increase = 0 - insult_drop = 0 - possible_origins = list("Yacks and Yucks Shop", "The Shop From Which I Sell Humorous Items", "The Prank Gestalt", "The Clown's Armory", "Uncle Knuckle's Chuckle Bunker", "A Place from Which to do Humorous Business") - speech = list("hail_generic" = "We welcome you to our shop of humorous items. We invite you to partake in the divine experience of being pranked, and pranking someone else.", - "hail_deny" = "We cannot do business with you. We are sorry.", - - "trade_complete" = "We thank you for purchasing something. We enjoyed the experience of you doing so and we hope to learn from it.", - "trade_blacklist"= "We are not allowed to do such. We are sorry.", - "trade_not_enough"="We have sufficiently experienced giving away goods for free. We wish to experience getting money in return.", - "how_much" = "We believe that is worth VALUE CURRENCY.", - "what_want" = "We wish only for the experiences you give us, in all else we want", - - "compliment_deny"= "You are attempting to compliment us.", - "compliment_accept"="You are attempting to compliment us.", - "insult_good" = "You are attempting to insult us, correct?", - "insult_bad" = "We do not understand.", - - "bribe_refusal" = "We are sorry, but we cannot accept.", - "bribe_accept" = "We are happy to say that we accept this bribe.", - ) - possible_trading_items = list(/obj/item/clothing/mask/gas/clown_hat = TRADER_THIS_TYPE, - /obj/item/clothing/mask/gas/mime = TRADER_THIS_TYPE, - /obj/item/clothing/shoes/clown_shoes = TRADER_THIS_TYPE, - /obj/item/clothing/under/rank/clown = TRADER_THIS_TYPE, - /obj/item/stamp/clown = TRADER_THIS_TYPE, - /obj/item/storage/backpack/clown = TRADER_THIS_TYPE, - /obj/item/bananapeel = TRADER_THIS_TYPE, - /obj/item/gun/launcher/money = TRADER_THIS_TYPE, - /obj/item/chems/food/snacks/pie = TRADER_THIS_TYPE, - /obj/item/bikehorn = TRADER_THIS_TYPE, - /obj/item/chems/spray/waterflower = TRADER_THIS_TYPE, - /obj/item/gun/launcher/pneumatic/small = TRADER_THIS_TYPE, - /obj/item/gun/projectile/revolver/capgun = TRADER_THIS_TYPE, - /obj/item/clothing/mask/fakemoustache = TRADER_THIS_TYPE, - /obj/item/grenade/spawnergrenade/fake_carp = TRADER_THIS_TYPE) - -/datum/trader/ship/replica_shop - name = "Replica Store Owner" - name_language = TRADER_DEFAULT_NAME - origin = "Replica Store" - possible_origins = list("Ye-Old Armory", "Knights and Knaves", "The Blacksmith", "Historical Human Apparel and Items", "The Pointy End", "Fight Knight's Knightly Nightly Knight Fights", "Elminster's Fine Steel", "The Arms of King Duordan", "Queen's Edict") - speech = list("hail_generic" = "Greetings, traveler! You've the look of one with a keen hunger for human history. Come in, and learn! Mayhaps even... buy?", - "hail_deny" = "I shan't palaver with a man who thumbs his nose at the annals of history. Goodbye.", - - "trade_complete" = "Thank you, mighty warrior. And remember - these may be replicas, but their edges are honed to razor sharpness!", - "trade_blacklist"= "Nay, we accept only the CURRENCY_SINGULAR. Or sovereigns of the king's mint, of course.", - "trade_not_enough"="Alas, traveler, my fine wares cost more than that.", - "how_much" = "For VALUE CURRENCY, I can part with this finest of goods.", - "what_want" = "I have ever longed for", - - "compliment_deny"= "Oh ho ho! Aren't you quite the jester.", - "compliment_accept"="Why, thank you, traveler! Long have I slaved over the anvil to produce these goods.", - "insult_good" = "Hey, bro, I'm just tryin' to make a living here, okay? The Camelot schtick is part of my brand.", - "insult_bad" = "Man, fuck you, then.", - - "bribe_refusal" = "Alas, traveler - I could stay all eve, but I've an client in waiting, and they are not known for patience.", - "bribe_accept" = "Mayhaps I could set a spell longer, and rest my weary feet.", - ) - possible_trading_items = list(/obj/item/clothing/head/wizard/magus = TRADER_THIS_TYPE, - /obj/item/shield/buckler = TRADER_THIS_TYPE, - /obj/item/clothing/head/redcoat = TRADER_THIS_TYPE, - /obj/item/clothing/head/powdered_wig = TRADER_THIS_TYPE, - /obj/item/clothing/head/hasturhood = TRADER_THIS_TYPE, - /obj/item/clothing/head/helmet/gladiator=TRADER_THIS_TYPE, - /obj/item/clothing/head/plaguedoctorhat= TRADER_THIS_TYPE, - /obj/item/clothing/glasses/monocle = TRADER_THIS_TYPE, - /obj/item/clothing/mask/smokable/pipe = TRADER_THIS_TYPE, - /obj/item/clothing/mask/gas/plaguedoctor=TRADER_THIS_TYPE, - /obj/item/clothing/suit/hastur = TRADER_THIS_TYPE, - /obj/item/clothing/suit/imperium_monk = TRADER_THIS_TYPE, - /obj/item/clothing/suit/judgerobe = TRADER_THIS_TYPE, - /obj/item/clothing/suit/wizrobe/magusred=TRADER_THIS_TYPE, - /obj/item/clothing/suit/wizrobe/magusblue=TRADER_THIS_TYPE, - /obj/item/clothing/under/gladiator = TRADER_THIS_TYPE, - /obj/item/clothing/under/kilt = TRADER_THIS_TYPE, - /obj/item/clothing/under/redcoat = TRADER_THIS_TYPE, - /obj/item/clothing/under/soviet = TRADER_THIS_TYPE, - /obj/item/harpoon = TRADER_THIS_TYPE, - /obj/item/sword = TRADER_ALL, - /obj/item/scythe = TRADER_THIS_TYPE, - /obj/item/star = TRADER_THIS_TYPE, - /obj/item/twohanded/baseballbat = TRADER_THIS_TYPE) \ No newline at end of file diff --git a/code/datums/trading/ship.dm b/code/datums/trading/ship.dm deleted file mode 100644 index 1ad1ad052b4b..000000000000 --- a/code/datums/trading/ship.dm +++ /dev/null @@ -1,24 +0,0 @@ -//Ships are on a time limit as far as being around goes. -//They are ALSO the only ones that can appear after round start -/datum/trader/ship - var/duration_of_stay = 0 - var/typical_duration = 20 //minutes (since trader processes only tick once a minute) - -/datum/trader/ship/New() - ..() - duration_of_stay = rand(typical_duration,typical_duration * 2) - -/datum/trader/ship/tick() - ..() - if(prob(-disposition) || refuse_comms) - duration_of_stay -= 5 - return --duration_of_stay > 0 - -/datum/trader/ship/bribe_to_stay_longer(var/amt) - if(prob(-disposition)) - return get_response("bribe_refusal", "How about.... no?") - - var/length = round(amt/100) - duration_of_stay += length - . = get_response("bribe_accept", "Sure, I'll stay for TIME more minutes.") - . = replacetext(., "TIME", length) \ No newline at end of file diff --git a/code/datums/trading/trade.dm b/code/datums/trading/trade.dm deleted file mode 100644 index 117009320cad..000000000000 --- a/code/datums/trading/trade.dm +++ /dev/null @@ -1,288 +0,0 @@ -/datum/trader - var/name = "unsuspicious trader" //The name of the trader in question - var/origin = "some place" //The place that they are trading from - var/list/possible_origins //Possible names of the trader origin - var/disposition = 0 //The current disposition of them to us. - var/trade_flags = TRADER_MONEY //Flags - var/name_language //If this is set to a language name this will generate a name from the language - var/icon/portrait //The icon that shows up in the menu @TODO - var/trader_currency - - var/list/wanted_items = list() //What items they enjoy trading for. Structure is (type = known/unknown) - var/list/possible_wanted_items //List of all possible wanted items. Structure is (type = mode) - var/list/possible_trading_items //List of all possible trading items. Structure is (type = mode) - var/list/trading_items = list() //What items they are currently trading away. - var/list/blacklisted_trade_items = list(/mob/living/carbon/human) - //Things they will automatically refuse - - var/list/speech = list() //The list of all their replies and messages. Structure is (id = talk) - /*SPEECH IDS: - hail_generic When merchants hail a person - hail_[race] Race specific hails - hail_deny When merchant denies a hail - - insult_good When the player insults a merchant while they are on good disposition - insult_bad When a player insults a merchatn when they are not on good disposition - complement_accept When the merchant accepts a complement - complement_deny When the merchant refuses a complement - - how_much When a merchant tells the player how much something is. - trade_complete When a trade is made - trade_refuse When a trade is refused - - what_want What the person says when they are asked if they want something - - */ - var/want_multiplier = 2 //How much wanted items are multiplied by when traded for - var/margin = 1.2 //Multiplier to price when selling to player - var/price_rng = 10 //Percentage max variance in sell prices. - var/insult_drop = 5 //How far disposition drops on insult - var/compliment_increase = 5 //How far compliments increase disposition - var/refuse_comms = 0 //Whether they refuse further communication - - var/mob_transfer_message = "You are transported to ORIGIN." //What message gets sent to mobs that get sold. - -/datum/trader/New() - ..() - if(!ispath(trader_currency, /decl/currency)) - trader_currency = GLOB.using_map.default_currency - if(name_language) - if(name_language == TRADER_DEFAULT_NAME) - name = capitalize(pick(GLOB.first_names_female + GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - else - var/decl/language/L = decls_repository.get_decl(name_language) - if(istype(L)) - name = L.get_random_name(pick(MALE,FEMALE)) - if(possible_origins && possible_origins.len) - origin = pick(possible_origins) - - for(var/i in 3 to 6) - add_to_pool(trading_items, possible_trading_items, force = 1) - add_to_pool(wanted_items, possible_wanted_items, force = 1) - -//If this hits 0 then they decide to up and leave. -/datum/trader/proc/tick() - add_to_pool(trading_items, possible_trading_items, 200) - add_to_pool(wanted_items, possible_wanted_items, 50) - remove_from_pool(possible_trading_items, 9) //We want the stock to change every so often, so we make it so that they have roughly 10~11 ish items max - return 1 - -/datum/trader/proc/remove_from_pool(var/list/pool, var/chance_per_item) - if(pool && prob(chance_per_item * pool.len)) - var/i = rand(1,pool.len) - pool[pool[i]] = null - pool -= pool[i] - -/datum/trader/proc/add_to_pool(var/list/pool, var/list/possible, var/base_chance = 100, var/force = 0) - var/divisor = 1 - if(pool && pool.len) - divisor = pool.len - if(force || prob(base_chance/divisor)) - var/new_item = get_possible_item(possible) - if(new_item) - pool |= new_item - -/datum/trader/proc/get_possible_item(var/list/trading_pool) - if(!trading_pool || !trading_pool.len) - return - var/list/possible = list() - for(var/type in trading_pool) - var/status = trading_pool[type] - if(status & TRADER_THIS_TYPE) - possible += type - if(status & TRADER_SUBTYPES_ONLY) - possible += subtypesof(type) - if(status & TRADER_BLACKLIST) - possible -= type - if(status & TRADER_BLACKLIST_SUB) - possible -= subtypesof(type) - - if(possible.len) - var/picked = pick(possible) - var/atom/A = picked - if(initial(A.name) in list("object", "item","weapon", "structure", "machinery", "exosuit", "organ", "snack")) //weed out a few of the common bad types. Reason we don't check types specifically is that (hopefully) further bad subtypes don't set their name up and are similar. - return - return picked - -/datum/trader/proc/get_response(var/key, var/default) - if(speech && speech[key]) - . = speech[key] - else - . = default - . = replacetext(., "MERCHANT", name) - . = replacetext(., "ORIGIN", origin) - - var/decl/currency/cur = decls_repository.get_decl(trader_currency) - . = replacetext(.,"CURRENCY_SINGULAR", cur.name_singular) - . = replacetext(.,"CURRENCY", cur.name) - -/datum/trader/proc/print_trading_items(var/num) - num = Clamp(num,1,trading_items.len) - if(trading_items[num]) - var/atom/movable/M = trading_items[num] - return "[initial(M.name)]" - -/datum/trader/proc/skill_curve(skill) - switch(skill) - if(SKILL_EXPERT) - . = 1 - if(SKILL_EXPERT to SKILL_MAX) - . = 1 + (SKILL_EXPERT - skill) * 0.2 - else - . = 1 + (SKILL_EXPERT - skill) ** 2 - //This condition ensures that the buy price is higher than the sell price on generic goods, i.e. the merchant can't be exploited - . = max(., price_rng/((margin - 1)*(200 - price_rng))) - -/datum/trader/proc/get_item_value(var/trading_num, skill = SKILL_MAX) - if(!trading_items[trading_items[trading_num]]) - var/item_type = trading_items[trading_num] - var/value = atom_info_repository.get_combined_worth_for(item_type) - value = round(rand(100 - price_rng,100 + price_rng)/100 * value) //For some reason rand doesn't like decimals. - trading_items[item_type] = value - . = trading_items[trading_items[trading_num]] - . *= 1 + (margin - 1) * skill_curve(skill) //Trader will overcharge at lower skill. - -/datum/trader/proc/get_buy_price(var/atom/movable/item, is_wanted, skill = SKILL_MAX) - if(ispath(item, /atom/movable)) - . = atom_info_repository.get_combined_worth_for(item) - else if(istype(item)) - . = item.get_combined_monetary_worth() - if(is_wanted) - . *= want_multiplier - . *= max(1 - (margin - 1) * skill_curve(skill), 0.1) //Trader will underpay at lower skill. - -/datum/trader/proc/offer_money_for_trade(var/trade_num, var/money_amount, skill = SKILL_MAX) - if(!(trade_flags & TRADER_MONEY)) - return TRADER_NO_MONEY - var/value = get_item_value(trade_num, skill) - if(money_amount < value) - return TRADER_NOT_ENOUGH - - return value - -/datum/trader/proc/offer_items_for_trade(var/list/offers, var/num, var/turf/location, skill = SKILL_MAX) - if(!offers || !offers.len) - return TRADER_NOT_ENOUGH - num = Clamp(num, 1, trading_items.len) - var/offer_worth = 0 - for(var/item in offers) - var/atom/movable/offer = item - var/is_wanted = 0 - if((trade_flags & TRADER_WANTED_ONLY) && is_type_in_list(offer,wanted_items)) - is_wanted = 2 - if((trade_flags & TRADER_WANTED_ALL) && is_type_in_list(offer,possible_wanted_items)) - is_wanted = 1 - if(blacklisted_trade_items && blacklisted_trade_items.len && is_type_in_list(offer,blacklisted_trade_items)) - return 0 - - if(istype(offer,/obj/item/cash)) - if(!(trade_flags & TRADER_MONEY)) - return TRADER_NO_MONEY - else - if(!(trade_flags & TRADER_GOODS)) - return TRADER_NO_GOODS - else if((trade_flags & TRADER_WANTED_ONLY|TRADER_WANTED_ALL) && !is_wanted) - return TRADER_FOUND_UNWANTED - - offer_worth += get_buy_price(offer, is_wanted - 1, skill) - if(!offer_worth) - return TRADER_NOT_ENOUGH - var/trading_worth = get_item_value(num, skill) - if(!trading_worth) - return TRADER_NOT_ENOUGH - var/percent = offer_worth/trading_worth - if(percent > max(0.9,0.9-disposition/100)) - return trade(offers, num, location) - return TRADER_NOT_ENOUGH - -/datum/trader/proc/hail(var/mob/user) - var/specific - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species) - specific = H.species.name - else if(istype(user, /mob/living/silicon)) - specific = "silicon" - if(!speech["hail_[specific]"]) - specific = "generic" - . = get_response("hail_[specific]", "Greetings, MOB!") - . = replacetext(., "MOB", user.name) - -/datum/trader/proc/can_hail() - if(!refuse_comms && prob(-disposition)) - refuse_comms = 1 - return !refuse_comms - -/datum/trader/proc/insult() - disposition -= rand(insult_drop, insult_drop * 2) - if(prob(-disposition/10)) - refuse_comms = 1 - if(disposition > 50) - return get_response("insult_good","What? I thought we were cool!") - else - return get_response("insult_bad", "Right back at you asshole!") - -/datum/trader/proc/compliment() - if(prob(-disposition)) - return get_response("compliment_deny", "Fuck you!") - if(prob(100-disposition)) - disposition += rand(compliment_increase, compliment_increase * 2) - return get_response("compliment_accept", "Thank you!") - -/datum/trader/proc/trade(var/list/offers, var/num, var/turf/location) - if(offers && offers.len) - for(var/offer in offers) - if(istype(offer,/mob)) - var/text = mob_transfer_message - to_chat(offer, replacetext(text, "ORIGIN", origin)) - qdel(offer) - - var/type = trading_items[num] - - var/atom/movable/M = new type(location) - playsound(location, 'sound/effects/teleport.ogg', 50, 1) - - disposition += rand(compliment_increase,compliment_increase*3) //Traders like it when you trade with them - - return M - -/datum/trader/proc/how_much_do_you_want(var/num, skill = SKILL_MAX) - var/atom/movable/M = trading_items[num] - . = get_response("how_much", "Hmm.... how about VALUE CURRENCY?") - . = replacetext(.,"VALUE",get_item_value(num, skill)) - . = replacetext(.,"ITEM", initial(M.name)) - -/datum/trader/proc/what_do_you_want() - if(!(trade_flags & TRADER_GOODS)) - return get_response(TRADER_NO_GOODS, "I don't deal in goods.") - - . = get_response("what_want", "Hm, I want") - var/list/want_english = list() - for(var/type in wanted_items) - var/atom/a = type - want_english += initial(a.name) - . += " [english_list(want_english)]" - -/datum/trader/proc/sell_items(var/list/offers, skill = SKILL_MAX) - if(!(trade_flags & TRADER_GOODS)) - return TRADER_NO_GOODS - if(!offers || !offers.len) - return TRADER_NOT_ENOUGH - - var/wanted - . = 0 - for(var/offer in offers) - if((trade_flags & TRADER_WANTED_ONLY) && is_type_in_list(offer,wanted_items)) - wanted = 1 - else if((trade_flags & TRADER_WANTED_ALL) && is_type_in_list(offer,possible_wanted_items)) - wanted = 0 - else - return TRADER_FOUND_UNWANTED - . += get_buy_price(offer, wanted, skill) - - playsound(get_turf(offers[1]), 'sound/effects/teleport.ogg', 50, 1) - for(var/offer in offers) - qdel(offer) - -/datum/trader/proc/bribe_to_stay_longer(var/amt) - return get_response("bribe_refusal", "How about... no?") \ No newline at end of file diff --git a/code/datums/trading/trade_hub_overmap.dm b/code/datums/trading/trade_hub_overmap.dm new file mode 100644 index 000000000000..e9c52c310f2b --- /dev/null +++ b/code/datums/trading/trade_hub_overmap.dm @@ -0,0 +1,79 @@ +var/global/list/trading_hub_names = list() + +/obj/effect/overmap/trade_hub + name = "trading post" + icon_state = "trade" + var/datum/trade_hub/overmap/hub_datum + +/obj/effect/overmap/trade_hub/proc/get_trading_post_type() + . = /datum/trade_hub/overmap + +/obj/effect/overmap/trade_hub/Initialize() + var/hub_type = get_trading_post_type() + hub_datum = new hub_type + hub_datum.update_hub(src) + update_hub_datum(hub_datum) + . = ..() + +/obj/effect/overmap/trade_hub/proc/update_hub_datum(var/datum/trade_hub/overmap/hub) + hub.owner = src + +/obj/effect/overmap/trade_hub/Destroy() + if(hub_datum) + if(hub_datum.owner == src) + qdel(hub_datum) + hub_datum = null + . = ..() + +/datum/trade_hub/overmap + var/hub_icon + var/hub_icon_state + var/hub_color + var/obj/effect/overmap/owner + +/datum/trade_hub/overmap/proc/get_new_name() + if(prob(30)) + . = pick(global.station_prefixes) + . = trim("[.] [pick(global.station_names)]") + . = trim("[.] [pick(global.station_suffixes)]") + if(prob(30)) + . = trim("[.] [pick(global.greek_letters)]") + else if(prob(30)) + . = trim("[.] [pick(global.phonetic_alphabet)]") + if(prob(25)) + . = trim("[.] [pick(global.numbers_as_words)]") + +/datum/trade_hub/overmap/proc/generate_name() + var/newname + while(!newname || global.trading_hub_names[newname]) + newname = get_new_name() + if(!global.trading_hub_names[newname]) + global.trading_hub_names[newname] = TRUE + . = newname + break + +/datum/trade_hub/overmap/New() + ..() + name = generate_name() + +/datum/trade_hub/overmap/Destroy(force) + if(owner) + var/obj/effect/overmap/trade_hub/hub = owner + if(istype(hub) && hub.hub_datum == src) + hub.hub_datum = null + owner = null + . = ..() + +/datum/trade_hub/overmap/is_accessible_from(var/turf/check) + if(istype(check)) + var/obj/effect/overmap/customer = global.overmap_sectors[check.z] + return customer && owner && get_turf(customer) == get_turf(owner) + +/datum/trade_hub/overmap/proc/update_hub(var/obj/effect/overmap/trade_hub/hub) + hub.name = name + if(hub_icon) + hub.icon = hub_icon + if(hub_icon_state) + hub.icon_state = hub_icon_state + if(hub_color) + hub.color = hub_color diff --git a/code/datums/trading/traders/ai.dm b/code/datums/trading/traders/ai.dm new file mode 100644 index 000000000000..4176f4556e3f --- /dev/null +++ b/code/datums/trading/traders/ai.dm @@ -0,0 +1,118 @@ +/* + +TRADING BEACON + +Trading beacons are generic AI driven trading outposts. +They sell generic supplies and ask for generic supplies. +*/ + +/datum/trader/trading_beacon + name = "AI" + origin = "Trading Beacon" + name_language = /decl/language/human/common + trade_flags = TRADER_MONEY | TRADER_GOODS + speech = list( + TRADER_HAIL_GENERIC = "Greetings, I am " + TRADER_TOKEN_MERCHANT + ", Artifical Intelligence onboard " + TRADER_TOKEN_ORIGIN + ", tasked with trading goods in return for " + TRADER_TOKEN_CURRENCY + " and supplies.", + TRADER_HAIL_DENY = "We are sorry, your connection has been blacklisted. Have a nice day.", + TRADER_TRADE_COMPLETE = "Thank you for your patronage.", + TRADER_NOT_ENOUGH = "I'm sorry, your offer is not worth what you are asking for.", + TRADER_NO_BLACKLISTED = "You have offered a blacklisted item. My laws do not allow me to trade for that.", + TRADER_HOW_MUCH = TRADER_TOKEN_ITEM + " will cost you roughly " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ", or something of equal worth.", + TRADER_WHAT_WANT = "I have logged need for", + TRADER_COMPLIMENT_DENY = "I'm sorry, I am not allowed to let compliments affect the trade.", + TRADER_COMPLIMENT_ACCEPT = "Thank you, but that will not not change our business interactions.", + TRADER_INSULT_GOOD = "I do not understand, are we not on good terms?", + TRADER_INSULT_BAD = "I do not understand, are you insulting me?", + TRADER_BRIBE_REFUSAL = "You have given me money to stay, however, I am a station. I do not leave.", + ) + possible_wanted_items = list( + /obj/item = TRADER_SUBTYPES_ONLY, + /obj/item/assembly = TRADER_BLACKLIST_ALL, + /obj/item/assembly_holder = TRADER_BLACKLIST_ALL, + /obj/item/encryptionkey/hacked = TRADER_BLACKLIST, + /obj/item/tank/onetankbomb = TRADER_BLACKLIST, + /obj/item/radio = TRADER_BLACKLIST_ALL, + /obj/item/modular_computer/pda = TRADER_BLACKLIST_SUB, + /obj/item/uplink = TRADER_BLACKLIST + ) + possible_trading_items = list( + /obj/item/bag = TRADER_SUBTYPES_ONLY, + /obj/item/backpack = TRADER_ALL, + /obj/item/backpack/cultpack = TRADER_BLACKLIST, + /obj/item/backpack/holding = TRADER_BLACKLIST, + /obj/item/backpack/satchel/grey/withwallet = TRADER_BLACKLIST, + /obj/item/backpack/satchel/syndie_kit = TRADER_BLACKLIST_ALL, + /obj/item/backpack/chameleon = TRADER_BLACKLIST, + /obj/item/backpack/dufflebag/syndie = TRADER_BLACKLIST_SUB, + /obj/item/belt/champion = TRADER_THIS_TYPE, + /obj/item/briefcase = TRADER_THIS_TYPE, + /obj/item/box/fancy = TRADER_SUBTYPES_ONLY, + /obj/item/laundry_basket = TRADER_THIS_TYPE, + /obj/item/secure_storage/briefcase = TRADER_THIS_TYPE, + /obj/item/plant_satchel = TRADER_THIS_TYPE, + /obj/item/ore_satchel = TRADER_THIS_TYPE, + /obj/item/toolbox = TRADER_ALL, + /obj/item/wallet = TRADER_THIS_TYPE, + /obj/item/photo_album = TRADER_THIS_TYPE, + /obj/item/clothing/glasses = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/glasses/hud = TRADER_BLACKLIST_ALL, + /obj/item/clothing/glasses/blindfold/tape = TRADER_BLACKLIST, + /obj/item/clothing/glasses/chameleon = TRADER_BLACKLIST + ) + + insult_drop = 0 + compliment_increase = 0 + +/datum/trader/trading_beacon/New() + ..() + origin = "[origin] #[rand(100,999)]" + +/datum/trader/trading_beacon/mine + origin = "Mining Beacon" + + possible_trading_items = list( + /obj/item/stack/material/ore = TRADER_SUBTYPES_ONLY, + /obj/item/stack/material/pane/mapped/glass = TRADER_ALL, + /obj/item/stack/material/pane/mapped/glass/fifty = TRADER_BLACKLIST, + /obj/item/stack/material/ingot/mapped/iron = TRADER_THIS_TYPE, + /obj/item/stack/material/brick/mapped/sandstone = TRADER_THIS_TYPE, + /obj/item/stack/material/brick/mapped/marble = TRADER_THIS_TYPE, + /obj/item/stack/material/gemstone/mapped/diamond = TRADER_THIS_TYPE, + /obj/item/stack/material/puck/mapped/uranium = TRADER_THIS_TYPE, + /obj/item/stack/material/panel/mapped/plastic = TRADER_THIS_TYPE, + /obj/item/stack/material/ingot/mapped/gold = TRADER_THIS_TYPE, + /obj/item/stack/material/ingot/mapped/silver = TRADER_THIS_TYPE, + /obj/item/stack/material/ingot/mapped/platinum = TRADER_THIS_TYPE, + /obj/item/stack/material/segment/mapped/mhydrogen = TRADER_THIS_TYPE, + /obj/item/stack/material/aerogel/mapped/tritium = TRADER_THIS_TYPE, + /obj/item/stack/material/ingot/mapped/osmium = TRADER_THIS_TYPE, + /obj/item/stack/material/sheet/mapped/steel = TRADER_THIS_TYPE, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel = TRADER_THIS_TYPE, + /obj/machinery/mining_drill = TRADER_THIS_TYPE, + /obj/structure/drill_brace = TRADER_THIS_TYPE + ) + +/datum/trader/trading_beacon/manufacturing + origin = "Manifacturing Beacon" + + possible_trading_items = list( + /obj/structure/aicore = TRADER_THIS_TYPE, + /obj/structure/girder = TRADER_THIS_TYPE, + /obj/structure/grille = TRADER_THIS_TYPE, + /obj/structure/mopbucket = TRADER_THIS_TYPE, + /obj/structure/ore_box = TRADER_THIS_TYPE, + /obj/structure/coatrack = TRADER_THIS_TYPE, + /obj/structure/bookcase = TRADER_THIS_TYPE, + /obj/item/glass_jar = TRADER_THIS_TYPE, + /obj/item/training_dummy = TRADER_THIS_TYPE, + /obj/item/training_dummy/syndicate = TRADER_THIS_TYPE, + /obj/item/training_dummy/alien = TRADER_THIS_TYPE, + /obj/structure/tank_rack = TRADER_SUBTYPES_ONLY, + /obj/structure/filing_cabinet = TRADER_THIS_TYPE, + /obj/structure/safe = TRADER_THIS_TYPE, + /obj/structure/plushie = TRADER_SUBTYPES_ONLY, + /obj/structure/sign = TRADER_SUBTYPES_ONLY, + /obj/structure/sign/double = TRADER_BLACKLIST_ALL, + /obj/structure/sign/plaque/golden = TRADER_BLACKLIST_ALL, + /obj/structure/sign/poster = TRADER_BLACKLIST + ) \ No newline at end of file diff --git a/code/datums/trading/traders/books.dm b/code/datums/trading/traders/books.dm new file mode 100644 index 000000000000..4744ac979e75 --- /dev/null +++ b/code/datums/trading/traders/books.dm @@ -0,0 +1,53 @@ +/datum/trader/books + name = "strange book merchant" + origin = "Uzed Buks" + possible_origins = list( + "Uzed Buks", + "Ango & Mango (Still not a fruit shop stop wizh so many asking!)", + "Prepipipi's Gently Used Books", + "real-books.com.au", + "We Sell Paper Wizh Words On", + "Meeeena's Paper Recycling" + ) + trade_flags = TRADER_MONEY + possible_wanted_items = list() + price_rng = 30 + + possible_trading_items = list( + /obj/item/book/skill/organizational/literacy = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/organizational/finance = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/general/eva = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/general/mech = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/general/pilot = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/general/hauling = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/general/computer = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/service/botany = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/service/cooking = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/security/combat = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/security/weapons = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/security/forensics = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/engineering/construction = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/engineering/electrical = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/engineering/atmos = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/engineering/engines = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/research/devices = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/research/science = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/medical/chemistry = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/medical/medicine = TRADER_SUBTYPES_ONLY, + /obj/item/book/skill/medical/anatomy = TRADER_SUBTYPES_ONLY + ) + + speech = list( + TRADER_HAIL_GENERIC = "Yes hello hello! Many fine paperstacks for sale! Please buy!", + TRADER_HAIL_DENY = "Not in! I'm not here! Go away!!", + TRADER_NO_GOODS = "No! No no no! Not goods! MONEY!", + TRADER_INSULT_GOOD = "Zhat hurts friend!", + TRADER_INSULT_BAD = "Ohhhhhh!! Why you picking a fight?! You will lose!", + TRADER_COMPLIMENT_ACCEPT = "You make my ears red you do! Hehehe!", + TRADER_COMPLIMENT_DENY = "Haha! Nice try, but I am not falling for zhe smoozhy talk zhe fourzh time today!", + TRADER_HOW_MUCH = "Hmmmmm, I give zhis to you for maybe... " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_TRADE_COMPLETE = "Yesssss zhank you for transactionings!", + TRADER_NO_BLACKLISTED = "Aaaaaa! No want, no want! Go away!", + TRADER_NOT_ENOUGH = "Not enough! More! More!", + TRADER_BRIBE_REFUSAL = "Zhis is a station, stupid!" + ) diff --git a/code/datums/trading/traders/food.dm b/code/datums/trading/traders/food.dm new file mode 100644 index 000000000000..eb2287eddfb3 --- /dev/null +++ b/code/datums/trading/traders/food.dm @@ -0,0 +1,196 @@ +/datum/trader/pizzaria + name = "Pizza Shop Employee" + origin = "Pizzeria" + possible_origins = list( + "Papa Joseph's", + "Pizza Ship", + "Dominator Pizza", + "Little Kaezars", + "Pizza Planet", + "Cheese Louise", + "Little Taste o' Neo-Italy", + "Pizza Gestapo" + ) + trade_flags = TRADER_MONEY + possible_wanted_items = list() //They are a pizza shop, not a bargainer. + possible_trading_items = list( + /obj/item/food/sliceable/pizza = TRADER_SUBTYPES_ONLY + ) + + speech = list( + TRADER_HAIL_GENERIC = "Hello! Welcome to " + TRADER_TOKEN_ORIGIN + ", may I take your order?", + TRADER_HAIL_DENY = "Beeeep... I'm sorry, your connection has been severed.", + TRADER_TRADE_COMPLETE = "Thank you for choosing " + TRADER_TOKEN_ORIGIN + "!", + TRADER_NO_GOODS = "I'm sorry but we only take cash.", + TRADER_NO_BLACKLISTED = "Sir that's... highly illegal.", + TRADER_NOT_ENOUGH = "Uhh... that's not enough money for pizza.", + TRADER_HOW_MUCH = "That pizza will cost you " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_COMPLIMENT_DENY = "That's a bit forward, don't you think?", + TRADER_COMPLIMENT_ACCEPT = "Thanks, sir! You're very nice!", + TRADER_INSULT_GOOD = "Please stop that, sir.", + TRADER_INSULT_BAD = "Sir, just because I'm contractually obligated to keep you on the line for a minute doesn't mean I have to take this.", + TRADER_BRIBE_REFUSAL = "Uh... thanks for the cash, sir. As long as you're in the area, we'll be here...", + ) + +/datum/trader/pizzaria/trade(var/list/offers, var/num, var/turf/location) + . = ..() + if(.) + var/atom/movable/M = . + var/obj/item/pizzabox/box = new(location) + M.forceMove(box) + box.pizza = M + box.box_tag = "A special order from [origin]!" + box.update_strings() + box.update_icon() + +/datum/trader/ship/chinese + name = "Chinese Restaurant" + origin = "Captain Panda Bistro" + possible_origins = list( + "888 Shanghai Kitchen", + "Mr. Lee's Greater Hong Kong", + "The House of the Venerable and Inscrutable Colonel", + "Lucky Dragon" + ) + possible_wanted_items = list() + possible_trading_items = list( + /obj/item/utensil/chopsticks = TRADER_THIS_TYPE, + /obj/item/utensil/chopsticks/plastic = TRADER_THIS_TYPE, + /obj/item/chems/condiment/small/soysauce = TRADER_THIS_TYPE, + /obj/item/chems/condiment/capsaicin = TRADER_THIS_TYPE, + /obj/item/food/chazuke = TRADER_THIS_TYPE, + /obj/item/chems/glass/bowl/mapped/curry/katsu = TRADER_THIS_TYPE, + /obj/item/food/skewer/meat = TRADER_THIS_TYPE, + /obj/item/food/boiledegg = TRADER_THIS_TYPE, + /obj/item/food/boiledrice = TRADER_THIS_TYPE, + /obj/item/food/ricepudding = TRADER_THIS_TYPE, + /obj/item/food/stewedsoymeat = TRADER_THIS_TYPE, + /obj/item/chems/drinks/dry_ramen = TRADER_THIS_TYPE + ) + + var/static/list/fortunes = list( + "Today it's up to you to create the peacefulness you long for.", + "If you refuse to accept anything but the best, you very often get it.", + "A smile is your passport into the hearts of others.", + "Hard work pays off in the future, laziness pays off now.", + "Change can hurt, but it leads a path to something better.", + "Hidden in a valley beside an open stream- This will be the type of place where you will find your dream.", + "Never give up. You're not a failure if you don't give up.", + "Love can last a lifetime, if you want it to.", + "The love of your life is stepping into your planet this summer.", + "Your ability for accomplishment will follow with success.", + "Please help me, I'm trapped in a fortune cookie factory!" + ) + + speech = list( + TRADER_HAIL_GENERIC = "There are two things constant in life, death and Chinese food. How may I help you?", + TRADER_HAIL_DENY = "We do not take orders from rude customers.", + TRADER_TRADE_COMPLETE = "Thank you, sir, for your patronage.", + TRADER_NO_BLACKLISTED = "No, that is very odd. Why would you trade that away?", + TRADER_NO_GOODS = "I only accept money transfers.", + TRADER_NOT_ENOUGH = "No, I am sorry, that is not possible. I need to make a living.", + TRADER_HOW_MUCH = "I give you " + TRADER_TOKEN_ITEM + ", for " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ". No more, no less.", + TRADER_COMPLIMENT_DENY = "That was an odd thing to say. You are very odd.", + TRADER_COMPLIMENT_ACCEPT = "Good philosophy, see good in bad, I like.", + TRADER_INSULT_GOOD = "As a man said long ago, \"When anger rises, think of the consequences.\" Think on that.", + TRADER_INSULT_BAD = "I do not need to take this from you.", + TRADER_BRIBE_REFUSAL = "Hm... I'll think about it.", + TRADER_BRIBE_ACCEPT = "Oh yes! I think I'll stay a few more minutes, then.", + ) + +/datum/trader/ship/chinese/trade(var/list/offers, var/num, var/turf/location) + . = ..() + if(.) + var/obj/item/food/fortunecookie/cookie = new(location) + var/obj/item/paper/paper = new(cookie, null, pick(fortunes), "Fortune") + cookie.trash = paper + +/datum/trader/grocery + name = "Grocer" + possible_origins = list( + "HyTee", + "Kreugars", + "Spaceway", + "Privaxs", + "FutureValue", + "Phyvendyme", + "Seller's Market" + ) + trade_flags = TRADER_MONEY + + possible_trading_items = list( + /obj/item/food = TRADER_SUBTYPES_ONLY, + /obj/item/chems/drinks/cans = TRADER_SUBTYPES_ONLY, + /obj/item/chems/drinks/bottle = TRADER_SUBTYPES_ONLY, + /obj/item/chems/drinks/bottle/small = TRADER_BLACKLIST, + /obj/item/food/processed_grown = TRADER_BLACKLIST_ALL, + /obj/item/food/slice = TRADER_BLACKLIST_ALL, + /obj/item/food/grown = TRADER_BLACKLIST_ALL, + /obj/item/food/sliceable/braincake = TRADER_BLACKLIST, + /obj/item/food/butchery/meat/human = TRADER_BLACKLIST, + /obj/item/food/variable = TRADER_BLACKLIST_ALL + ) + + speech = list( + TRADER_HAIL_GENERIC = "Hello, welcome to " + TRADER_TOKEN_ORIGIN + ", grocery store of the future!", + TRADER_HAIL_DENY = "I'm sorry, we've blacklisted your communications due to rude behavior.", + TRADER_TRADE_COMPLETE = "Thank you for shopping at " + TRADER_TOKEN_ORIGIN + "!", + TRADER_NO_BLACKLISTED = "I... wow, that's... no, sir. No.", + TRADER_NO_GOODS = TRADER_TOKEN_ORIGIN + " only accepts cash, sir.", + TRADER_NOT_ENOUGH = "That is not enough money, sir.", + TRADER_HOW_MUCH = "Sir, that'll cost you " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ". Will that be all?", + TRADER_COMPLIMENT_DENY = "Sir, this is a professional environment. Please don't make me get my manager.", + TRADER_COMPLIMENT_ACCEPT = "Thank you, sir!", + TRADER_INSULT_GOOD = "Sir, please do not make a scene.", + TRADER_INSULT_BAD = "Sir, I WILL get my manager if you don't calm down.", + TRADER_BRIBE_REFUSAL = "Of course sir! " + TRADER_TOKEN_ORIGIN + " is always here for you!", + ) + +/datum/trader/bakery + name = "Pastry Chef" + origin = "Bakery" + possible_origins = list( + "Cakes By Design", + "Corner Bakery Local", + "My Favorite Cake & Pastry Cafe", + "Mama Joes Bakery", + "Sprinkles and Fun", + "Cakestrosity" + ) + + speech = list( + TRADER_HAIL_GENERIC = "Hello, welcome to " + TRADER_TOKEN_ORIGIN + "! We serve baked goods, including pies, cakes, and anything sweet!", + TRADER_HAIL_DENY = "Our food is a privilege, not a right. Goodbye.", + TRADER_TRADE_COMPLETE = "Thank you for your purchase! Come again if you're hungry for more!", + TRADER_NO_BLACKLISTED = "We only accept money. Not... that.", + TRADER_NO_GOODS = "Cash for cakes! That's our business!", + TRADER_NOT_ENOUGH = "Our dishes are much more expensive than that, sir.", + TRADER_HOW_MUCH = "That lovely dish will cost you " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_COMPLIMENT_DENY = "Oh wow, how nice of you...", + TRADER_COMPLIMENT_ACCEPT = "You're almost as sweet as my pies!", + TRADER_INSULT_GOOD = "My pies are NOT knockoffs!", + TRADER_INSULT_BAD = "Well, aren't you a sour apple?", + TRADER_BRIBE_REFUSAL = "Oh ho ho! I'd never think of taking " + TRADER_TOKEN_ORIGIN + " on the road!", + ) + possible_trading_items = list( + /obj/item/food/slice/birthdaycake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/carrotcake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/cheesecake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/chocolatecake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/lemoncake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/limecake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/orangecake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/plaincake/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/pumpkinpie/filled = TRADER_THIS_TYPE, + /obj/item/food/slice/bananabread/filled = TRADER_THIS_TYPE, + /obj/item/food/sliceable = TRADER_SUBTYPES_ONLY, + /obj/item/food/sliceable/pizza = TRADER_BLACKLIST_ALL, + /obj/item/food/sliceable/xenomeatbread = TRADER_BLACKLIST, + /obj/item/food/piecrust = TRADER_BLACKLIST, + /obj/item/food/sliceable/unleaveneddough = TRADER_BLACKLIST, + /obj/item/food/dough = TRADER_BLACKLIST, + /obj/item/food/sliceable/flatdough = TRADER_BLACKLIST, + /obj/item/food/sliceable/braincake = TRADER_BLACKLIST, + /obj/item/food/bananapie = TRADER_THIS_TYPE, + /obj/item/food/applepie = TRADER_THIS_TYPE + ) \ No newline at end of file diff --git a/code/datums/trading/traders/goods.dm b/code/datums/trading/traders/goods.dm new file mode 100644 index 000000000000..81d294268dcd --- /dev/null +++ b/code/datums/trading/traders/goods.dm @@ -0,0 +1,465 @@ +/datum/trader/ship/toyshop + name = "Toy Shop Employee" + origin = "Toy Shop" + trade_flags = TRADER_GOODS | TRADER_MONEY | TRADER_WANTED_ONLY | TRADER_BRIBABLE + possible_origins = list( + "Toys R Ours", + "LET'S GO", + "Kay-Cee Toys", + "Build-a-Cat", + "Magic Box", + "The Positronic's Dungeon and Baseball Card Shop" + ) + speech = list( + TRADER_HAIL_GENERIC = "Uhh... hello? Welcome to " + TRADER_TOKEN_ORIGIN + ", I hope you have a, uhh.... good shopping trip.", + TRADER_HAIL_DENY = "Nah, you're not allowed here. At all", + TRADER_TRADE_COMPLETE = "Thanks for shopping... here... at " + TRADER_TOKEN_ORIGIN + ".", + TRADER_NO_BLACKLISTED = "Uuuhhh.... no.", + TRADER_FOUND_UNWANTED = "Nah! That's not what I'm looking for. Something rarer.", + TRADER_NOT_ENOUGH = "Just 'cause they're made of cardboard doesn't mean they don't cost money...", + TRADER_HOW_MUCH = "Uhh... I'm thinking like... " + TRADER_TOKEN_VALUE + ". Right? Or something rare that complements my interest.", + TRADER_WHAT_WANT = "Ummmm..... I guess I want", + TRADER_COMPLIMENT_DENY = "Ha! Very funny! You should write your own television show.", + TRADER_COMPLIMENT_ACCEPT = "Why yes, I do work out.", + TRADER_INSULT_GOOD = "Well, well, well. Guess we learned who was the troll here.", + TRADER_INSULT_BAD = "I've already written a nasty Spacebook post in my mind about you.", + TRADER_BRIBE_REFUSAL = "Nah. I need to get moving as soon as uhh... possible.", + TRADER_BRIBE_ACCEPT = "You know what, I wasn't doing anything for " + TRADER_TOKEN_TIME + " minutes anyways.", + ) + + possible_wanted_items = list( + /obj/item/toy/figure = TRADER_THIS_TYPE, + /obj/item/toy/figure/ert = TRADER_THIS_TYPE, + /obj/item/toy/prize/honk = TRADER_THIS_TYPE + ) + + possible_trading_items = list( + /obj/item/toy/prize = TRADER_SUBTYPES_ONLY, + /obj/item/toy/prize/honk = TRADER_BLACKLIST, + /obj/item/toy/figure = TRADER_SUBTYPES_ONLY, + /obj/item/toy/figure/ert = TRADER_BLACKLIST, + /obj/item/toy/plushie = TRADER_SUBTYPES_ONLY, + /obj/item/sword/katana/toy = TRADER_THIS_TYPE, + /obj/item/energy_blade/sword/toy = TRADER_THIS_TYPE, + /obj/item/toy/bosunwhistle = TRADER_THIS_TYPE, + /obj/item/board = TRADER_THIS_TYPE, + /obj/item/box/checkers = TRADER_ALL, + /obj/item/deck = TRADER_SUBTYPES_ONLY, + /obj/item/pack = TRADER_SUBTYPES_ONLY, + /obj/item/dice = TRADER_ALL, + /obj/item/gun/launcher/money = TRADER_THIS_TYPE + ) + +/datum/trader/ship/electronics + name = "Electronic Shop Employee" + origin = "Electronic Shop" + possible_origins = list( + "Best Sale", + "Overstore", + "Oldegg", + "Circuit Citadel", + "Silicon Village", + "Positronic Solutions LLC", + "Sunvolt Inc." + ) + + speech = list( + TRADER_HAIL_GENERIC = "Hello, sir! Welcome to " + TRADER_TOKEN_ORIGIN + ", I hope you find what you are looking for.", + TRADER_HAIL_DENY = "Your call has been disconnected.", + TRADER_TRADE_COMPLETE = "Thank you for shopping at " + TRADER_TOKEN_ORIGIN + ", would you like to get the extended warranty as well?", + TRADER_NO_BLACKLISTED = "Sir, this is a /electronics/ store.", + TRADER_NO_GOODS = "As much as I'd love to buy that from you, I can't.", + TRADER_NOT_ENOUGH = "Your offer isn't adequate, sir.", + TRADER_HOW_MUCH = "Your total comes out to " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_COMPLIMENT_DENY = "Hahaha! Yeah... funny...", + TRADER_COMPLIMENT_ACCEPT = "That's very nice of you!", + TRADER_INSULT_GOOD = "That was uncalled for, sir. Don't make me get my manager.", + TRADER_INSULT_BAD = "Sir, I am allowed to hang up the phone if you continue, sir.", + TRADER_BRIBE_REFUSAL = "Sorry, sir, but I can't really do that.", + TRADER_BRIBE_ACCEPT = "Why not! Glad to be here for a few more minutes.", + ) + + possible_trading_items = list( + /obj/item/stock_parts/computer/battery_module = TRADER_SUBTYPES_ONLY, + /obj/item/stock_parts/circuitboard = TRADER_SUBTYPES_ONLY, + /obj/item/stock_parts/circuitboard/unary_atmos = TRADER_BLACKLIST, + /obj/item/stock_parts/circuitboard/arcade = TRADER_BLACKLIST, + /obj/item/stock_parts/circuitboard/broken = TRADER_BLACKLIST, + /obj/item/stack/cable_coil = TRADER_SUBTYPES_ONLY, + /obj/item/stack/cable_coil/cyborg = TRADER_BLACKLIST, + /obj/item/stack/cable_coil/random = TRADER_BLACKLIST, + /obj/item/stack/cable_coil/cut = TRADER_BLACKLIST, + /obj/item/stock_parts/circuitboard/air_alarm = TRADER_THIS_TYPE, + /obj/item/stock_parts/circuitboard/airlock_electronics = TRADER_ALL, + /obj/item/cell = TRADER_THIS_TYPE, + /obj/item/cell/crap = TRADER_THIS_TYPE, + /obj/item/cell/high = TRADER_THIS_TYPE, + /obj/item/cell/super = TRADER_THIS_TYPE, + /obj/item/cell/hyper = TRADER_THIS_TYPE, + /obj/item/tracker_electronics = TRADER_THIS_TYPE + ) + + +/* Clothing stores: each a different type. A hat/glove store, a shoe store, and a jumpsuit store. */ +/datum/trader/ship/clothingshop + name = "Clothing Store Employee" + origin = "Clothing Store" + possible_origins = list( + "Space Eagle", + "Banana Democracy", + "Forever 22", + "Textiles Factory Warehouse Outlet", + "Blocks Brothers" + ) + speech = list( + TRADER_HAIL_GENERIC = "Hello, sir! Welcome to " + TRADER_TOKEN_ORIGIN + "!", + TRADER_HAIL_DENY = "We do not trade with rude customers. Consider yourself blacklisted.", + TRADER_TRADE_COMPLETE = "Thank you for shopping at " + TRADER_TOKEN_ORIGIN + ". Remember: We cannot accept returns without the original tags!", + TRADER_NO_BLACKLISTED = "Hm, how about no?", + TRADER_NO_GOODS = "We don't buy, sir. Only sell.", + TRADER_NOT_ENOUGH = "Sorry, " + TRADER_TOKEN_ORIGIN + " policy to not accept trades below our marked prices.", + TRADER_HOW_MUCH = "Your total comes out to " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_COMPLIMENT_DENY = "Excuse me?", + TRADER_COMPLIMENT_ACCEPT = "Aw, you're so nice!", + TRADER_INSULT_GOOD = "Sir.", + TRADER_INSULT_BAD = "Wow. I don't have to take this.", + TRADER_BRIBE_REFUSAL = TRADER_TOKEN_ORIGIN + " policy clearly states we cannot stay for more than the designated time.", + TRADER_BRIBE_ACCEPT = "Hm.... sure! We'll have a few minutes of 'engine troubles'.", + ) + + possible_trading_items = list( + /obj/item/clothing/pants = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/pants/pj = TRADER_BLACKLIST, + /obj/item/clothing/pants/shorts = TRADER_BLACKLIST, + /obj/item/clothing/pants/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/shirt = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/shirt/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/shirt/pj = TRADER_BLACKLIST, + /obj/item/clothing/skirt = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/dress = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/dress/wedding = TRADER_BLACKLIST, + /obj/item/clothing/shirt = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/pants = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/skirt = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/jumpsuit = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/jumpsuit/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/jumpsuit = TRADER_BLACKLIST, + /obj/item/clothing/pants/mankini = TRADER_BLACKLIST_ALL, + /obj/item/clothing/jumpsuit/tactical = TRADER_BLACKLIST + ) + +/datum/trader/ship/clothingshop/shoes + possible_origins = list( + "Foot Safe", + "Paysmall", + "Popular Footwear", + "Grimbly's Shoes", + "Right Steps" + ) + possible_trading_items = list( + /obj/item/clothing/shoes = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/shoes/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/shoes/jackboots/swat/combat = TRADER_BLACKLIST, + /obj/item/clothing/shoes/clown_shoes = TRADER_BLACKLIST, + /obj/item/clothing/shoes/cult = TRADER_BLACKLIST, + /obj/item/clothing/shoes/lightrig = TRADER_BLACKLIST_ALL, + /obj/item/clothing/shoes/magboots = TRADER_BLACKLIST_ALL, + /obj/item/clothing/shoes/jackboots/swat = TRADER_BLACKLIST, + /obj/item/clothing/shoes/syndigaloshes = TRADER_BLACKLIST + ) + +/datum/trader/ship/clothingshop/hatglovesaccessories + possible_origins = list( + "Baldie's Hats and Accessories", + "The Right Fit", + "Like a Glove", + "Space Fashion" + ) + possible_trading_items = list( + /obj/item/clothing/neck = TRADER_ALL, + /obj/item/clothing/suit/jacket = TRADER_ALL, + /obj/item/clothing/suit/robe = TRADER_ALL, + /obj/item/clothing/shoes/legbrace = TRADER_ALL, + /obj/item/clothing/shoes/kneepads = TRADER_ALL, + /obj/item/clothing/armor_attachment/tag = TRADER_ALL, + /obj/item/clothing/armor_attachment/helmcover = TRADER_ALL, + /obj/item/clothing/badge = TRADER_BLACKLIST_ALL, + /obj/item/clothing/medal = TRADER_BLACKLIST_ALL, + /obj/item/clothing/webbing = TRADER_BLACKLIST_ALL, + /obj/item/clothing/webbing/holster = TRADER_BLACKLIST_ALL, + /obj/item/clothing/gloves = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/gloves/lightrig = TRADER_BLACKLIST_ALL, + /obj/item/clothing/gloves/rig = TRADER_BLACKLIST_ALL, + /obj/item/clothing/gloves/thick/swat = TRADER_BLACKLIST, + /obj/item/clothing/gloves/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/head = TRADER_SUBTYPES_ONLY, + /obj/item/clothing/head/HoS = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/bio_hood = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/bomb_hood = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/caphat = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/centhat = TRADER_BLACKLIST, + /obj/item/clothing/head/chameleon = TRADER_BLACKLIST, + /obj/item/clothing/head/collectable = TRADER_BLACKLIST, + /obj/item/clothing/head/helmet = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/lightrig = TRADER_BLACKLIST_ALL, + /obj/item/clothing/head/radiation = TRADER_BLACKLIST, + /obj/item/clothing/head/warden = TRADER_BLACKLIST, + /obj/item/clothing/head/welding = TRADER_BLACKLIST + ) + +/* +Sells devices, odds and ends, and medical stuff +*/ +/datum/trader/devices + name = "Drugstore Employee" + origin = "Drugstore" + possible_origins = list( + "Buy 'n Save", + "Drug Carnival", + "C&B", + "Fentles", + "Dr. Goods", + "Beevees", + "McGillicuddy's" + ) + possible_trading_items = list( + /obj/item/flashlight = TRADER_ALL, + /obj/item/kit/paint = TRADER_SUBTYPES_ONLY, + /obj/item/aicard = TRADER_THIS_TYPE, + /obj/item/binoculars = TRADER_THIS_TYPE, + /obj/item/cable_painter = TRADER_THIS_TYPE, + /obj/item/flash = TRADER_THIS_TYPE, + /obj/item/paint_sprayer = TRADER_THIS_TYPE, + /obj/item/multitool = TRADER_THIS_TYPE, + /obj/item/lightreplacer = TRADER_THIS_TYPE, + /obj/item/megaphone = TRADER_THIS_TYPE, + /obj/item/paicard = TRADER_THIS_TYPE, + /obj/item/scanner/health = TRADER_THIS_TYPE, + /obj/item/scanner/breath = TRADER_THIS_TYPE, + /obj/item/scanner/gas = TRADER_ALL, + /obj/item/scanner/spectrometer = TRADER_ALL, + /obj/item/scanner/reagent = TRADER_ALL, + /obj/item/scanner/xenobio = TRADER_THIS_TYPE, + /obj/item/suit_cooling_unit = TRADER_THIS_TYPE, + /obj/item/t_scanner = TRADER_THIS_TYPE, + /obj/item/taperecorder = TRADER_THIS_TYPE, + /obj/item/batterer = TRADER_THIS_TYPE, + /obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE, + /obj/item/hailer = TRADER_THIS_TYPE, + /obj/item/uv_light = TRADER_THIS_TYPE, + /obj/item/organ/internal/brain_interface = TRADER_SUBTYPES_ONLY, + /obj/item/robotanalyzer = TRADER_THIS_TYPE, + /obj/item/chems/toner_cartridge = TRADER_THIS_TYPE, + /obj/item/camera_film = TRADER_THIS_TYPE, + /obj/item/camera = TRADER_THIS_TYPE, + /obj/item/destTagger = TRADER_THIS_TYPE, + /obj/item/gps = TRADER_THIS_TYPE, + /obj/item/measuring_tape = TRADER_THIS_TYPE, + /obj/item/ano_scanner = TRADER_THIS_TYPE, + /obj/item/core_sampler = TRADER_THIS_TYPE, + /obj/item/depth_scanner = TRADER_THIS_TYPE, + /obj/item/pinpointer/radio = TRADER_THIS_TYPE, + /obj/item/stack/medical = TRADER_SUBTYPES_ONLY, + /obj/item/stack/medical/ointment/crafted = TRADER_BLACKLIST_ALL, + /obj/item/stack/medical/bandage/crafted = TRADER_BLACKLIST_ALL, + /obj/item/stack/medical/splint/crafted = TRADER_BLACKLIST_ALL, + /obj/item/stack/medical/splint/improvised = TRADER_BLACKLIST_ALL + ) + speech = list( + TRADER_HAIL_GENERIC = "Hello, hello! Bits and bobs and everything in between, I hope you find what you're looking for!", + TRADER_HAIL_SILICON = "Ah! Hello, robot. We only sell things that, ah.... people can hold in their hands, unfortunately. You are still allowed to buy, though!", + TRADER_HAIL_DENY = "Oh no. I don't want to deal with YOU.", + TRADER_TRADE_COMPLETE = "Thank you! Now remember, there isn't any return policy here, so be careful with that!", + TRADER_NO_BLACKLISTED = "Hm. Well that would be illegal, so no.", + TRADER_NO_GOODS = "I'm sorry, I only sell goods.", + TRADER_NOT_ENOUGH = "Gotta pay more than that to get that!", + TRADER_HOW_MUCH = "Well... I bought it for a lot, but I'll give it to you for " + TRADER_TOKEN_VALUE + ".", + TRADER_COMPLIMENT_DENY = "Uh... did you say something?", + TRADER_COMPLIMENT_ACCEPT = "Mhm! I can agree to that!", + TRADER_INSULT_GOOD = "Wow, where was that coming from?", + TRADER_INSULT_BAD = "Don't make me blacklist your connection.", + TRADER_BRIBE_REFUSAL = "Well, as much as I'd love to say 'yes', you realize I operate on a station, correct?", + ) + +/datum/trader/ship/robots + name = "Robot Seller" + origin = "Robot Store" + possible_origins = list( + "AI for the Straight Guy", + "Mechanical Buddies", + "Bot Chop Shop", + "Omni Consumer Projects" + ) + possible_trading_items = list( + /obj/item/bot_kit = TRADER_THIS_TYPE, + /obj/item/paicard = TRADER_THIS_TYPE, + /obj/item/aicard = TRADER_THIS_TYPE, + /mob/living/bot = TRADER_SUBTYPES_ONLY + ) + speech = list( + TRADER_HAIL_GENERIC = "Welcome to " + TRADER_TOKEN_ORIGIN + "! Let me walk you through our fine robotic selection!", + TRADER_HAIL_SILICON = "Welcome to " + TRADER_TOKEN_ORIGIN + "! Let- oh, you're a synth! Well, your money is good anyway. Welcome, welcome!", + TRADER_HAIL_DENY = TRADER_TOKEN_ORIGIN + " no longer wants to speak to you.", + TRADER_TRADE_COMPLETE = "I hope you enjoy your new robot!", + TRADER_NO_BLACKLISTED = "I work with robots, sir. Not that.", + TRADER_NO_GOODS = "You gotta buy the robots, sir. I don't do trades.", + TRADER_NOT_ENOUGH = "You're coming up short on cash.", + TRADER_HOW_MUCH = "My fine selection of robots will cost you " + TRADER_TOKEN_VALUE + "!", + TRADER_COMPLIMENT_DENY = "Well, I almost believed that.", + TRADER_COMPLIMENT_ACCEPT = "Thank you! My craftsmanship is my life.", + TRADER_INSULT_GOOD = "Uncalled for.... uncalled for.", + TRADER_INSULT_BAD = "I've programmed AI better at insulting than you!", + TRADER_BRIBE_REFUSAL = "I've got too many customers waiting in other sectors, sorry.", + TRADER_BRIBE_ACCEPT = "Hm. Don't keep me waiting too long, though.", + ) + +/datum/trader/xeno_shop + name = "Xenolife Collector" + origin = "CSV Not a Poacher" + trade_flags = TRADER_GOODS | TRADER_MONEY | TRADER_WANTED_ONLY | TRADER_WANTED_ALL + possible_origins = list( + "XenoHugs", + "Exotic Specimen Acquisition", + "Skinner Catering Reseller", + "Corporate Companionship Division", + "Lonely Pete's Exotic Companionship", + "Space Wei's Exotic Cuisine" + ) + speech = list( + TRADER_HAIL_GENERIC = "Welcome! We are always looking to acquire more exotic life forms.", + TRADER_HAIL_DENY = "We no longer wish to speak to you. Please contact our legal representative if you wish to rectify this.", + TRADER_TRADE_COMPLETE = "Remember to give them attention and food. They are living beings, and you should treat them like so.", + TRADER_NO_BLACKLISTED = "Legally I can't do that. Morally... well, I refuse to do that.", + TRADER_FOUND_UNWANTED = "I only want animals. I don't need food or shiny things. I'm looking for specific ones, at that. Ones I already have the cage and food for.", + TRADER_NOT_ENOUGH = "I'd give you this for free, but I need the money to feed the specimens. So you must pay in full.", + TRADER_HOW_MUCH = "This is a good choice. I believe it will cost you " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_WHAT_WANT = "I have the facilities, currently, to support", + TRADER_COMPLIMENT_DENY = "According to customs on 34 planets I traded with, this constitutes sexual harassment.", + TRADER_COMPLIMENT_ACCEPT = "Thank you. I needed that.", + TRADER_INSULT_GOOD = "No need to be upset, I believe we can do business.", + TRADER_INSULT_BAD = "I have traded dogs with more bark than that.", + TRADER_BRIBE_REFUSAL = "Uh, this is a station. I'm not going anywhere." + ) + + possible_wanted_items = list( + /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, + /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, + /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/diyaab = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/shantak = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/samak = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE + ) + possible_trading_items = list( + /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE, + /obj/item/dociler = TRADER_THIS_TYPE, + /obj/item/beartrap = TRADER_THIS_TYPE, + /obj/item/scanner/xenobio = TRADER_THIS_TYPE + ) + +/datum/trader/medical + name = "Medical Supplier" + origin = "Infirmary of CSV Iniquity" + trade_flags = TRADER_GOODS | TRADER_MONEY | TRADER_WANTED_ONLY + want_multiplier = 1.2 + margin = 2 + possible_origins = list( + "Dr.Krieger's Practice", + "Legit Medical Supplies (No Refunds)", + "Mom's & Pop's Addictive Opoids", + "Legitimate Pharmaceutical Firm", + "Designer Drugs by Lil Xanny" + ) + speech = list( + TRADER_HAIL_GENERIC = "Huh? How'd you get this number?! Oh well, if you wanna talk biz, I'm listening.", + TRADER_HAIL_DENY = "This is an automated message. Feel free to fuck the right off after the buzzer. *buzz*", + TRADER_TRADE_COMPLETE = "Good to have business with ya. Remember, no refunds.", + TRADER_NO_BLACKLISTED = "Whoa whoa, I don't want this shit, put it away.", + TRADER_FOUND_UNWANTED = "What the hell do you expect me to do with this junk?", + TRADER_NOT_ENOUGH = "Sorry, pal, full payment upfront, I don't write the rules. Well, I do, but that's beside the point.", + TRADER_HOW_MUCH = "Hmm, this is one damn fine item, but I'll part with it for " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_WHAT_WANT = "I could always use some fucking", + TRADER_COMPLIMENT_DENY = "Haha, how nice of you. Why don't you go fall in an elevator shaft.", + TRADER_COMPLIMENT_ACCEPT = "Damn right I'm awesome, tell me more.", + TRADER_INSULT_GOOD = "Damn, pal, no need to get snippy.", + TRADER_INSULT_BAD = "*muffled laughter* Sorry, was that you trying to talk shit? Adorable.", + TRADER_BRIBE_REFUSAL = "Man I live here, I'm not leaving anytime soon." + ) + + possible_wanted_items = list( + /obj/item/chems/drinks/bottle = TRADER_THIS_TYPE, + /obj/item/organ/internal/liver = TRADER_THIS_TYPE, + /obj/item/organ/internal/kidneys = TRADER_THIS_TYPE, + /obj/item/organ/internal/lungs = TRADER_THIS_TYPE, + /obj/item/organ/internal/heart = TRADER_THIS_TYPE, + /obj/item/box/fancy/cigarettes = TRADER_ALL + ) + + possible_trading_items = list( + /obj/item/pill_bottle = TRADER_SUBTYPES_ONLY, + /obj/item/firstaid/fire = TRADER_THIS_TYPE, + /obj/item/firstaid/toxin = TRADER_THIS_TYPE, + /obj/item/firstaid/adv = TRADER_THIS_TYPE, + /obj/item/box/bloodpacks = TRADER_THIS_TYPE, + /obj/item/chems/ivbag = TRADER_SUBTYPES_ONLY, + /obj/item/retractor = TRADER_THIS_TYPE, + /obj/item/hemostat = TRADER_THIS_TYPE, + /obj/item/cautery = TRADER_THIS_TYPE, + /obj/item/surgicaldrill = TRADER_THIS_TYPE, + /obj/item/scalpel = TRADER_THIS_TYPE, + /obj/item/incision_manager = TRADER_THIS_TYPE, + /obj/item/circular_saw = TRADER_THIS_TYPE, + /obj/item/bonegel = TRADER_THIS_TYPE, + /obj/item/bonesetter = TRADER_THIS_TYPE, + /obj/item/chems/glass/bottle/stabilizer = TRADER_THIS_TYPE, + /obj/item/chems/glass/bottle/sedatives = TRADER_THIS_TYPE, + /obj/item/chems/glass/bottle/antitoxin = TRADER_THIS_TYPE, + /obj/item/bodybag/cryobag = TRADER_THIS_TYPE, + /obj/item/sign/diploma/fake = TRADER_THIS_TYPE + ) + +/datum/trader/mining + name = "Rock'n'Drill Mining Inc" + origin = "Automated Smelter AH-532" + trade_flags = TRADER_GOODS | TRADER_MONEY | TRADER_WANTED_ONLY | TRADER_WANTED_ALL + want_multiplier = 1.5 + margin = 2 + possible_origins = list( + "Automated Smelter AH-532", + "CMV Locust", + "The Galactic Foundry Company", + "Crucible LLC" + ) + speech = list( + TRADER_HAIL_GENERIC = "Welcome to R'n'D Mining. Please place your order.", + TRADER_HAIL_DENY = "There is no response on the line.", + TRADER_TRADE_COMPLETE = "Transaction complete. Please use our services again", + TRADER_NO_BLACKLISTED = "Whoa whoa, I don't want this shit, put it away.", + TRADER_FOUND_UNWANTED = "Sorry, we are currently not looking to purchase these items.", + TRADER_NOT_ENOUGH = "Sorry, this is an insufficient sum for this purchase.", + TRADER_HOW_MUCH = "For ONE entry of " + TRADER_TOKEN_ITEM + " the price would be " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_WHAT_WANT = "We are currently looking to procure", + TRADER_COMPLIMENT_DENY = "I am afraid this is beyond my competency.", + TRADER_COMPLIMENT_ACCEPT = "Thank you.", + TRADER_INSULT_GOOD = "Alright, we will reconsider the terms.", + TRADER_INSULT_BAD = "This is not acceptable, please cease.", + TRADER_BRIBE_REFUSAL = "This facility is not mobile. Payment is unnecessary." + ) + + possible_wanted_items = list( + /obj/item/stack/material/ore = TRADER_SUBTYPES_ONLY, + /obj/item/disk/survey = TRADER_THIS_TYPE, + /obj/item/stack/material/ore/slag = TRADER_BLACKLIST + ) + + possible_trading_items = list( + /obj/machinery/mining_drill = TRADER_THIS_TYPE, + /obj/structure/drill_brace = TRADER_THIS_TYPE, + /obj/machinery/floodlight = TRADER_THIS_TYPE, + /obj/item/box/greenglowsticks = TRADER_THIS_TYPE, + /obj/item/clothing/suit/space/void/engineering/salvage/prepared = TRADER_THIS_TYPE, + /obj/item/stack/material/puck/mapped/uranium/ten = TRADER_THIS_TYPE, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty = TRADER_THIS_TYPE, + /obj/item/stack/material/sheet/mapped/steel/fifty = TRADER_THIS_TYPE, + /obj/item/stack/material/ingot/mapped/copper/fifty = TRADER_THIS_TYPE + ) diff --git a/code/datums/trading/traders/misc.dm b/code/datums/trading/traders/misc.dm new file mode 100644 index 000000000000..6356be83f0d4 --- /dev/null +++ b/code/datums/trading/traders/misc.dm @@ -0,0 +1,181 @@ +/datum/trader/ship/pet_shop + name = "Pet Shop Owner" + name_language = /decl/language/human/common + origin = "Pet Shop" + trade_flags = TRADER_GOODS | TRADER_MONEY | TRADER_WANTED_ONLY | TRADER_BRIBABLE + possible_origins = list( + "Paws-Out", + "Pets-R-Smart", + "Tentacle Companions", + "Xeno-Pets and Assorted Goods", + "Barks and Drools" + ) + speech = list( + TRADER_HAIL_GENERIC = "Welcome to my xeno-pet shop! Here you will find many wonderful companions. Some a bit more... aggressive than others. But companions none the less. I also buy pets, or trade them.", + TRADER_HAIL_DENY = "I no longer wish to speak to you.", + TRADER_TRADE_COMPLETE = "Remember to give them attention and food. They are living beings, and you should treat them like so.", + TRADER_NO_BLACKLISTED = "Legally I can' do that. Morally, I refuse to do that.", + TRADER_FOUND_UNWANTED = "I only want animals. I don't need food or shiny things. I'm looking for specific ones at that. Ones I already have the cage and food for.", + TRADER_NOT_ENOUGH = "I'd give you the animal for free, but I need the money to feed the others. So you must pay in full.", + TRADER_HOW_MUCH = "This is a fine specimen. I believe it will cost you " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_WHAT_WANT = "I have the facilities, currently, to support", + TRADER_COMPLIMENT_DENY = "That was almost charming.", + TRADER_COMPLIMENT_ACCEPT = "Thank you. I needed that.", + TRADER_INSULT_GOOD = "I ask you to stop. We can be peaceful. I know we can.", + TRADER_INSULT_BAD = "My interactions with you are becoming less than fruitful.", + TRADER_BRIBE_REFUSAL = "I'm not going to do that. I have places to be.", + TRADER_BRIBE_ACCEPT = "Hm. It'll be good for the animals, so sure.", + ) + + possible_wanted_items = list( + /mob/living/simple_animal/corgi = TRADER_THIS_TYPE, + /mob/living/simple_animal/passive/cat = TRADER_THIS_TYPE, + /mob/living/simple_animal/crab = TRADER_THIS_TYPE, + /mob/living/simple_animal/lizard = TRADER_THIS_TYPE, + /mob/living/simple_animal/passive/mouse = TRADER_THIS_TYPE, + /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE, + /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, + /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, + /mob/living/simple_animal/cow = TRADER_THIS_TYPE, + /mob/living/simple_animal/chick = TRADER_THIS_TYPE, + /mob/living/simple_animal/fowl/chicken = TRADER_THIS_TYPE, + /mob/living/simple_animal/fowl/duck = TRADER_THIS_TYPE, + /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/diyaab = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/bear = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/shantak = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/parrot = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/samak = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/goat = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE + ) + + possible_trading_items = list( + /mob/living/simple_animal/corgi = TRADER_THIS_TYPE, + /mob/living/simple_animal/passive/cat = TRADER_THIS_TYPE, + /mob/living/simple_animal/crab = TRADER_THIS_TYPE, + /mob/living/simple_animal/lizard = TRADER_THIS_TYPE, + /mob/living/simple_animal/passive/mouse = TRADER_THIS_TYPE, + /mob/living/simple_animal/mushroom = TRADER_THIS_TYPE, + /mob/living/simple_animal/tindalos = TRADER_THIS_TYPE, + /mob/living/simple_animal/tomato = TRADER_THIS_TYPE, + /mob/living/simple_animal/cow = TRADER_THIS_TYPE, + /mob/living/simple_animal/chick = TRADER_THIS_TYPE, + /mob/living/simple_animal/fowl/chicken = TRADER_THIS_TYPE, + /mob/living/simple_animal/fowl/duck = TRADER_THIS_TYPE, + /mob/living/simple_animal/yithian = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/diyaab = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/bear = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/shantak = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/parrot = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/beast/samak = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/goat = TRADER_THIS_TYPE, + /mob/living/simple_animal/hostile/carp = TRADER_THIS_TYPE, + /obj/item/dociler = TRADER_THIS_TYPE, + /obj/structure/dogbed = TRADER_THIS_TYPE + ) + +/datum/trader/ship/prank_shop + name = "Prank Shop Owner" + name_language = /decl/language/human/common + origin = "Prank Shop" + compliment_increase = 0 + insult_drop = 0 + possible_origins = list( + "Yacks and Yucks Shop", + "The Shop From Which I Sell Humorous Items", + "The Prank Gestalt", + "The Clown's Armory", + "Uncle Knuckle's Chuckle Bunker", + "A Place from Which to do Humorous Business" + ) + speech = list( + TRADER_HAIL_GENERIC = "We welcome you to our shop of humorous items. We invite you to partake in the divine experience of being pranked, and pranking someone else.", + TRADER_HAIL_DENY = "We cannot do business with you. We are sorry.", + TRADER_TRADE_COMPLETE = "We thank you for purchasing something. We enjoyed the experience of you doing so and we hope to learn from it.", + TRADER_NO_BLACKLISTED = "We are not allowed to trade for these goods. We are sorry.", + TRADER_NO_GOODS = "We are not allowed to trade for these goods. We are sorry.", + TRADER_NOT_ENOUGH = "We have sufficiently experienced giving away goods for free. We wish to experience getting money in return.", + TRADER_HOW_MUCH = "We believe that is worth " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ".", + TRADER_WHAT_WANT = "We wish only for the experiences you give us, in all else we want", + TRADER_COMPLIMENT_DENY = "You are attempting to compliment us.", + TRADER_COMPLIMENT_ACCEPT = "You are attempting to compliment us.", + TRADER_INSULT_GOOD = "You are attempting to insult us, correct?", + TRADER_INSULT_BAD = "We do not understand.", + TRADER_BRIBE_REFUSAL = "We are sorry, but we cannot accept.", + TRADER_BRIBE_ACCEPT = "We are happy to say that we accept this bribe.", + ) + possible_trading_items = list( + /obj/item/clothing/mask/gas/clown_hat = TRADER_THIS_TYPE, + /obj/item/clothing/mask/gas/mime = TRADER_THIS_TYPE, + /obj/item/clothing/shoes/clown_shoes = TRADER_THIS_TYPE, + /obj/item/clothing/costume/clown = TRADER_THIS_TYPE, + /obj/item/stamp/clown = TRADER_THIS_TYPE, + /obj/item/backpack/clown = TRADER_THIS_TYPE, + /obj/item/bananapeel = TRADER_THIS_TYPE, + /obj/item/gun/launcher/money = TRADER_THIS_TYPE, + /obj/item/food/bananapie = TRADER_THIS_TYPE, + /obj/item/bikehorn = TRADER_THIS_TYPE, + /obj/item/chems/spray/waterflower = TRADER_THIS_TYPE, + /obj/item/gun/launcher/pneumatic/small = TRADER_THIS_TYPE, + /obj/item/gun/projectile/revolver/capgun = TRADER_THIS_TYPE, + /obj/item/clothing/mask/fakemoustache = TRADER_THIS_TYPE, + /obj/item/grenade/spawnergrenade/fake_carp = TRADER_THIS_TYPE + ) + +/datum/trader/ship/replica_shop + name = "Replica Store Owner" + origin = "Replica Store" + possible_origins = list( + "Ye-Old Armory", + "Knights and Knaves", + "The Blacksmith", + "Historical Human Apparel and Items", + "The Pointy End", + "Fight Knight's Knightly Nightly Knight Fights", + "Elminster's Fine Steel", + "The Arms of King Duordan", + "Queen's Edict" + ) + speech = list( + TRADER_HAIL_GENERIC = "Greetings, traveler! You've the look of one with a keen hunger for human history. Come in, and learn! Mayhaps even... buy?", + TRADER_HAIL_DENY = "I shan't palaver with a man who thumbs his nose at the annals of history. Goodbye.", + TRADER_TRADE_COMPLETE = "Thank you, mighty warrior. And remember - these may be replicas, but their edges are honed to razor sharpness!", + TRADER_NO_BLACKLISTED = "Nay, we accept only the " + TRADER_TOKEN_CUR_SINGLE + ". Or sovereigns of the king's mint, of course.", + TRADER_NO_GOODS = "Nay, we accept only the " + TRADER_TOKEN_CUR_SINGLE + ". Or sovereigns of the king's mint, of course.", + TRADER_NOT_ENOUGH = "Alas, traveler, my fine wares cost more than that.", + TRADER_HOW_MUCH = "For " + TRADER_TOKEN_VALUE + " " + TRADER_TOKEN_CURRENCY + ", I can part with this finest of goods.", + TRADER_WHAT_WANT = "I have ever longed for", + TRADER_COMPLIMENT_DENY = "Oh ho ho! Aren't you quite the jester.", + TRADER_COMPLIMENT_ACCEPT = "Why, thank you, traveler! Long have I slaved over the anvil to produce these goods.", + TRADER_INSULT_GOOD = "Hey, bro, I'm just tryin' to make a living here, okay? The Camelot schtick is part of my brand.", + TRADER_INSULT_BAD = "Man, fuck you, then.", + TRADER_BRIBE_REFUSAL = "Alas, traveler - I could stay all eve, but I've an client in waiting, and they are not known for patience.", + TRADER_BRIBE_ACCEPT = "Mayhaps I could set a spell longer, and rest my weary feet." + ) + possible_trading_items = list( + /obj/item/clothing/head/wizard/magus = TRADER_THIS_TYPE, + /obj/item/shield/crafted/buckler = TRADER_THIS_TYPE, + /obj/item/clothing/head/redcoat = TRADER_THIS_TYPE, + /obj/item/clothing/head/powdered_wig = TRADER_THIS_TYPE, + /obj/item/clothing/head/hasturhood = TRADER_THIS_TYPE, + /obj/item/clothing/head/helmet/gladiator = TRADER_THIS_TYPE, + /obj/item/clothing/head/plaguedoctorhat = TRADER_THIS_TYPE, + /obj/item/clothing/glasses/eyepatch/monocle = TRADER_THIS_TYPE, + /obj/item/clothing/mask/smokable/pipe = TRADER_THIS_TYPE, + /obj/item/clothing/mask/gas/plaguedoctor = TRADER_THIS_TYPE, + /obj/item/clothing/suit/hastur = TRADER_THIS_TYPE, + /obj/item/clothing/suit/imperium_monk = TRADER_THIS_TYPE, + /obj/item/clothing/suit/judgerobe = TRADER_THIS_TYPE, + /obj/item/clothing/suit/wizrobe/magus = TRADER_THIS_TYPE, + /obj/item/clothing/suit/wizrobe/magus/red = TRADER_THIS_TYPE, + /obj/item/clothing/costume/gladiator = TRADER_THIS_TYPE, + /obj/item/clothing/costume/kilt = TRADER_THIS_TYPE, + /obj/item/clothing/costume/redcoat = TRADER_THIS_TYPE, + /obj/item/clothing/costume/soviet = TRADER_THIS_TYPE, + /obj/item/harpoon = TRADER_THIS_TYPE, + /obj/item/sword = TRADER_ALL, + /obj/item/scythe = TRADER_THIS_TYPE, + /obj/item/star = TRADER_THIS_TYPE, + /obj/item/baseball_bat = TRADER_THIS_TYPE + ) diff --git a/code/datums/trading/traders/ship.dm b/code/datums/trading/traders/ship.dm new file mode 100644 index 000000000000..79166901a846 --- /dev/null +++ b/code/datums/trading/traders/ship.dm @@ -0,0 +1,25 @@ +//Ships are on a time limit as far as being around goes. +//They are ALSO the only ones that can appear after round start +/datum/trader/ship + abstract_type = /datum/trader/ship + trade_flags = TRADER_MONEY | TRADER_BRIBABLE + var/duration_of_stay = 0 + var/typical_duration = 20 //minutes (since trader processes only tick once a minute) + +/datum/trader/ship/New() + ..() + duration_of_stay = rand(typical_duration,typical_duration * 2) + +/datum/trader/ship/tick() + ..() + if(prob(-disposition) || refuse_comms) + duration_of_stay -= 5 + return --duration_of_stay > 0 + +/datum/trader/ship/is_bribable() + return ..() || prob(-disposition) + +/datum/trader/ship/is_bribed(var/staylength) + duration_of_stay += staylength + . = get_response(TRADER_BRIBE_ACCEPT, "Sure, I'll stay for " + TRADER_TOKEN_TIME + " more minutes.") + . = replacetext(., TRADER_TOKEN_TIME, staylength) diff --git a/code/datums/trading/traders/unique.dm b/code/datums/trading/traders/unique.dm new file mode 100644 index 000000000000..dd30cd3b4bec --- /dev/null +++ b/code/datums/trading/traders/unique.dm @@ -0,0 +1,91 @@ +/datum/trader/ship/unique + abstract_type = /datum/trader/ship/unique + trade_flags = TRADER_WANTED_ONLY | TRADER_GOODS | TRADER_BRIBABLE + want_multiplier = 5 + typical_duration = 40 + +/datum/trader/ship/unique/New() + ..() + wanted_items = list() + for(var/type in possible_wanted_items) + var/status = possible_wanted_items[type] + if(status & TRADER_THIS_TYPE) + wanted_items += type + if(status & TRADER_SUBTYPES_ONLY) + wanted_items += subtypesof(type) + if(status & TRADER_BLACKLIST) + wanted_items -= type + if(status & TRADER_BLACKLIST_SUB) + wanted_items -= subtypesof(type) + +/datum/trader/ship/unique/tick() + if(prob(-disposition) || refuse_comms) + duration_of_stay-- + return --duration_of_stay > 0 + +/datum/trader/ship/unique/what_do_you_want() + return get_response(TRADER_WHAT_WANT, "I don't want anything!") + +/datum/trader/ship/unique/severance + name = "Unknown" + origin = "SGS Severance" + + possible_wanted_items = list( + /obj/item/food/butchery/meat/human = TRADER_THIS_TYPE, + /mob/living/human = TRADER_ALL + ) + + possible_trading_items = list( + /obj/item/gun/projectile/automatic = TRADER_SUBTYPES_ONLY + ) + + blacklisted_trade_items = null + + speech = list( + TRADER_HAIL_GENERIC = "H-hello. Can you hear me? G-good... I have... specific needs... I have a lot to t-trade with you in return of course.", + TRADER_HAIL_DENY = "--CONNECTION SEVERED--", + TRADER_TRADE_COMPLETE = "Hahahahahahaha! Thankyouthankyouthankyou!", + TRADER_NO_MONEY = "I d-don't NEED cash.", + TRADER_NOT_ENOUGH = "N-no, no no no. M-more than that... more...", + TRADER_FOUND_UNWANTED = "I d-don't think you GET what I want, fr- from your offer.", + TRADER_HOW_MUCH = "Meat. I want meat. The kind they don't serve in the- the mess hall.", + TRADER_WHAT_WANT = "Long p-pork. Yes... that's what I want...", + TRADER_COMPLIMENT_DENY = "Your lies won't ch-change what I did.", + TRADER_COMPLIMENT_ACCEPT = "Yes... I suppose you're right.", + TRADER_INSULT_GOOD = "I... probably deserve that.", + TRADER_INSULT_BAD = "Maybe you should c-come here and say that. You'd be worth s-something then.", + TRADER_BRIBE_ACCEPT = "Okay. Fine. But... h-hurry. I can only stay another " + TRADER_TOKEN_TIME + "m-minutes.", + TRADER_BRIBE_REFUSAL = "No! N-no, they're getting closer- I have to, I h-have to go soon." + ) + mob_transfer_message = "You are transported to " + TRADER_TOKEN_ORIGIN + ", and with a sickening thud, you fall unconscious, never to wake again." + + +/datum/trader/ship/unique/rock + name = "Bobo" + origin = "Floating rock" + + possible_wanted_items = list( + /obj/item/stack/material/ore = TRADER_ALL + ) + possible_trading_items = list( + /obj/item/aiModule = TRADER_SUBTYPES_ONLY + ) + want_multiplier = 5000 + + speech = list( + TRADER_HAIL_GENERIC = "Blub am " + TRADER_TOKEN_MERCHANT + ". Blub hunger for things. Boo bring them to blub, yes?", + TRADER_HAIL_DENY = "Blub does not want to speak to boo.", + TRADER_TRADE_COMPLETE = "Blub likes to trade!", + TRADER_NO_MONEY = "Boo try to give Blub paper. Blub does not want paper.", + TRADER_NOT_ENOUGH = "Blub hungry for bore than that.", + TRADER_NO_BLACKLISTED = "Blub not want that! No!", + TRADER_FOUND_UNWANTED = "Blub only wants bocks. Give bocks.", + TRADER_HOW_MUCH = "Blub wants bocks. Boo give bocks. Blub gives stuff blub found.", + TRADER_WHAT_WANT = "Blub wants bocks. Big bocks, small bocks. Shiny bocks!", + TRADER_COMPLIMENT_DENY = "Blub is just " + TRADER_TOKEN_MERCHANT + ". What do boo mean?", + TRADER_COMPLIMENT_ACCEPT = "Boo are a bood berson!", + TRADER_INSULT_GOOD = "Blub do not understand. Blub thought we were briends.", + TRADER_INSULT_BAD = "Blub feels bad now.", + TRADER_BRIBE_ACCEPT = "Blub will stay for " + TRADER_TOKEN_TIME + " binutes bonger.", + TRADER_BRIBE_REFUSAL = "Blub must go. Blub's beople beed blem." + ) diff --git a/code/datums/trading/traders/weaponry.dm b/code/datums/trading/traders/weaponry.dm new file mode 100644 index 000000000000..134fe5251c52 --- /dev/null +++ b/code/datums/trading/traders/weaponry.dm @@ -0,0 +1,106 @@ +/datum/trader/ship/gunshop + name = "Gun Shop Employee" + origin = "Gun Shop" + possible_origins = list( + "Rooty Tootie's Point-n-Shooties", + "Bang-Bang Shop", + "Wild Wild West Shop", + "Keleshnikov", + "Hunting Depot", + "Big Game Hunters" + ) + speech = list( + TRADER_HAIL_GENERIC = "Hello, hello! I hope you have your permit. Oh, who are we kidding, you're welcome anyway!", + TRADER_HAIL_DENY = "Store policy dictates that you can fuck off.", + TRADER_TRADE_COMPLETE = "Thanks for buying your guns from " + TRADER_TOKEN_ORIGIN + "!", + TRADER_NO_BLACKLISTED = "We may deal in guns, but that doesn't mean we'll trade for illegal goods...", + TRADER_NO_GOODS = "Cash for guns, thats the deal.", + TRADER_NOT_ENOUGH = "Guns are expensive! Give us more if you REALLY want it.", + TRADER_HOW_MUCH = "Well, I'd love to give this little beauty to you for " + TRADER_TOKEN_VALUE + ".", + TRADER_COMPLIMENT_DENY = "If we were in the same room right now, I'd probably punch you.", + TRADER_COMPLIMENT_ACCEPT = "Ha! Good one!", + TRADER_INSULT_GOOD = "I expected better from you. I suppose in that, I was wrong.", + TRADER_INSULT_BAD = "If I had my gun I'd shoot you!", + TRADER_BRIBE_ACCEPT = "For that much scratch, I can stay for another " + TRADER_TOKEN_TIME + " minutes.", + TRADER_BRIBE_REFUSAL = "Look, I've got places to be, I can't hang around shooting the shit." + ) + + possible_trading_items = list( + /obj/item/gun/projectile/pistol/holdout = TRADER_ALL, + /obj/item/gun/projectile/shotgun/pump = TRADER_SUBTYPES_ONLY, + /obj/item/ammo_magazine = TRADER_SUBTYPES_ONLY, + /obj/item/ammo_magazine/rifle/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/pistol/small/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/pistol/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/box/pistol/empty = TRADER_BLACKLIST, + /obj/item/ammo_magazine/smg/empty = TRADER_BLACKLIST, + /obj/item/clothing/webbing/holster = TRADER_ALL + ) + +/datum/trader/ship/egunshop + name = "Energy Gun Shop Employee" + origin = "EGun Shop" + possible_origins = list( + "The Emperor's Lasgun Shop", + "Future Guns", + "Solar Army", + "Kiefer's Dependable Electric Arms", + "Olympus Kingsport" + ) + speech = list( + TRADER_HAIL_GENERIC = "Welcome to the future of warfare! " + TRADER_TOKEN_ORIGIN + ", your one-stop shop for energy weaponry!", + TRADER_HAIL_DENY = "I'm sorry, your communication channel has been blacklisted.", + TRADER_TRADE_COMPLETE = "Thank you, your purchase has been logged and you have automatically liked our Spacebook page.", + TRADER_NO_BLACKLISTED = "I'm sorry, is that a joke?", + TRADER_NO_GOODS = "We deal in cash.", + TRADER_NOT_ENOUGH = "State of the art weaponry costs more than that.", + TRADER_HOW_MUCH = "All our quality weapons are priceless, but I'd give that to you for " + TRADER_TOKEN_VALUE + ".", + TRADER_COMPLIMENT_DENY = "If I was dumber I probably would have believed you.", + TRADER_COMPLIMENT_ACCEPT = "Yes, I am very smart.", + TRADER_INSULT_GOOD = "Energy weapons are TWICE the gun kinetic guns are!", + TRADER_INSULT_BAD = "That's... very mean. I won't think twice about blacklisting your channel, so stop.", + TRADER_BRIBE_ACCEPT = "Look, I'm not supposed to, but I guess I can stay for " + TRADER_TOKEN_TIME + " minutes.", + TRADER_BRIBE_REFUSAL = "Sorry, no can do. I'm on a tight schedule." + + ) + + possible_trading_items = list( + /obj/item/gun/energy/taser = TRADER_THIS_TYPE, + /obj/item/gun/energy/xray = TRADER_THIS_TYPE, + /obj/item/gun/energy/laser = TRADER_THIS_TYPE, + /obj/item/gun/energy/gun = TRADER_THIS_TYPE, + /obj/item/cell = TRADER_THIS_TYPE, + /obj/item/cell/crap = TRADER_THIS_TYPE, + /obj/item/cell/high = TRADER_THIS_TYPE, + /obj/item/cell/super = TRADER_THIS_TYPE, + /obj/item/cell/hyper = TRADER_THIS_TYPE, + /obj/item/clothing/webbing/holster = TRADER_ALL + ) + +/datum/trader/dogan + name = "Dogan" + origin = "Dogan's Gun Beacon" + speech = list( + TRADER_HAIL_GENERIC = "Hello! This is an automatic recording of me, Mr. Dogan! I hope you like the... GUNS... I've got in store for you today.", + TRADER_HAIL_DENY = "I formally welcome you to... NOT... visit our store!", + TRADER_TRADE_COMPLETE = "Thank you for... PURCHASING... that quality... " + TRADER_TOKEN_ITEM + "... from me!", + TRADER_NO_BLACKLISTED = "Thank you for... that quality... ILLEGAL OFFER THAT I WILL REFUSE... from me!", + TRADER_NO_GOODS = "Thank you for... that quality... OFFER THAT ISN'T MONEY THAT I WILL REFUSE... from me!", + TRADER_NOT_ENOUGH = "Thank you for... that quality... OFFER THAT IS NOT ENOUGH... from me!", + TRADER_HOW_MUCH = "Thank you for... ASKING ME ABOUT MY PRICES... that quality... " + TRADER_TOKEN_ITEM + " is worth " + TRADER_TOKEN_VALUE + "... from me!", + TRADER_COMPLIMENT_DENY = "Thank you for... that quality... COMPLIMENT... from me!", + TRADER_COMPLIMENT_ACCEPT = "Thank you for... that quality... COMPLIMENT... from me!", + TRADER_INSULT_GOOD = "Thank you for... that quality... INSULT... from me!", + TRADER_INSULT_BAD = "Thank you for... that quality... INSULT... from me!", + TRADER_BRIBE_REFUSAL = "Your... BLATANT BRIBERY... is... UNNECESSARY!" + ) + compliment_increase = 0 + insult_drop = 0 + + possible_trading_items = list( + /obj/item/gun/projectile/zipgun = TRADER_THIS_TYPE, + /obj/item/gun/projectile/bolt_action/sniper/ant = TRADER_THIS_TYPE, + /obj/item/gun/energy/laser/dogan = TRADER_THIS_TYPE, + /obj/item/gun/projectile/automatic/smg/usi = TRADER_THIS_TYPE, + /obj/item/clothing/webbing/holster = TRADER_ALL + ) diff --git a/code/datums/trading/trading_verbs.dm b/code/datums/trading/trading_verbs.dm new file mode 100644 index 000000000000..f295335a4202 --- /dev/null +++ b/code/datums/trading/trading_verbs.dm @@ -0,0 +1,34 @@ +/client/proc/list_traders() + set category = "Debug" + set name = "List Traders" + set desc = "Lists all the current traders" + + for(var/datum/trade_hub/hub in SStrade.trade_hubs) + to_chat(src, "[hub.name]:") + for(var/a in hub.traders) + var/datum/trader/T = a + to_chat(src, "[T.name] \ref[T]") + +/client/proc/add_trader() + set category = "Debug" + set name = "Add Trader" + set desc = "Adds a trader to the list." + + var/datum/trade_hub/hub = input(src, "Select a trade hub.", "Add Trade") as null|anything in SStrade.trade_hubs + if(!hub || !(hub in SStrade.trade_hubs)) + return + var/trader_type = input(src,"Choose a type to add.") as null|anything in hub.possible_trader_types + if(trader_type && (hub in SStrade.trade_hubs) && (trader_type in hub.possible_trader_types) && !(locate(trader_type) in hub.traders)) + hub.add_trader(trader_type) + +/client/proc/remove_trader() + set category = "Debug" + set name = "Remove Trader" + set desc = "Removes a trader from the trader list." + + var/datum/trade_hub/hub = input(src, "Select a trade hub.", "Add Trade") as null|anything in SStrade.trade_hubs + if(!hub || !(hub in SStrade.trade_hubs)) + return + var/choice = input(src, "Choose a trader to remove.") as null|anything in hub.traders + if(choice && (choice in hub.traders)) + qdel(choice) diff --git a/code/datums/trading/unique.dm b/code/datums/trading/unique.dm deleted file mode 100644 index a92b54500dc1..000000000000 --- a/code/datums/trading/unique.dm +++ /dev/null @@ -1,129 +0,0 @@ -/datum/trader/ship/unique - trade_flags = TRADER_WANTED_ONLY|TRADER_GOODS - want_multiplier = 5 - typical_duration = 40 - -/datum/trader/ship/unique/New() - ..() - wanted_items = list() - for(var/type in possible_wanted_items) - var/status = possible_wanted_items[type] - if(status & TRADER_THIS_TYPE) - wanted_items += type - if(status & TRADER_SUBTYPES_ONLY) - wanted_items += subtypesof(type) - if(status & TRADER_BLACKLIST) - wanted_items -= type - if(status & TRADER_BLACKLIST_SUB) - wanted_items -= subtypesof(type) - -/datum/trader/ship/unique/tick() - if(prob(-disposition) || refuse_comms) - duration_of_stay-- - return --duration_of_stay > 0 - -/datum/trader/ship/unique/what_do_you_want() - return get_response("what_want", "I don't want anything!") - -/datum/trader/ship/unique/severance - name = "Unknown" - origin = "SGS Severance" - - possible_wanted_items = list( - /obj/item/chems/food/snacks/human = TRADER_SUBTYPES_ONLY, - /obj/item/chems/food/snacks/meat/human = TRADER_THIS_TYPE, - /mob/living/carbon/human = TRADER_ALL - ) - - possible_trading_items = list(/obj/item/gun/projectile/automatic = TRADER_SUBTYPES_ONLY - ) - - blacklisted_trade_items = null - - speech = list("hail_generic" = "H-hello. Can you hear me? G-good... I have... specific needs... I have a lot to t-trade with you in return of course.", - "hail_deny" = "--CONNECTION SEVERED--", - - "trade_complete" = "Hahahahahahaha! Thankyouthankyouthankyou!", - "trade_no_money" = "I d-don't NEED cash.", - "trade_not_enough" = "N-no, no no no. M-more than that... more...", - "trade_found_unwanted" = "I d-don't think you GET what I want, fr- from your offer.", - "how_much" = "Meat. I want meat. The kind they don't serve in the- the mess hall.", - "what_want" = "Long p-pork. Yes... that's what I want...", - - "compliment_deny" = "Your lies won't ch-change what I did.", - "compliment_accept" = "Yes... I suppose you're right.", - "insult_good" = "I... probably deserve that.", - "insult_bad" = "Maybe you should c-come here and say that. You'd be worth s-something then.", - ) - mob_transfer_message = "You are transported to ORIGIN, and with a sickening thud, you fall unconscious, never to wake again." - - -/datum/trader/ship/unique/rock - name = "Bobo" - origin = "Floating rock" - - possible_wanted_items = list(/obj/item/ore = TRADER_ALL) - possible_trading_items = list(/obj/machinery/power/supermatter = TRADER_ALL, - /obj/item/aiModule = TRADER_SUBTYPES_ONLY) - want_multiplier = 5000 - - speech = list("hail_generic" = "Blub am MERCHANT. Blub hunger for things. Boo bring them to blub, yes?", - "hail_deny" = "Blub does not want to speak to boo.", - - "trade_complete" = "Blub likes to trade!", - "trade_no_money" = "Boo try to give Blub paper. Blub does not want paper.", - "trade_not_enough" = "Blub hungry for bore than that.", - "trade_found_unwanted" = "Blub only wants bocks. Give bocks.", - "trade_refuse" = "No, Blub will not do that. Blub wants bocks, yes? Give bocks.", - "how_much" = "Blub wants bocks. Boo give bocks. Blub gives stuff blub found.", - "what_want" = "Blub wants bocks. Big bocks, small bocks. Shiny bocks!", - - "compliment_deny" = "Blub is just MERCHANT. What do boo mean?", - "compliment_accept" = "Boo are a bood berson!", - "insult_good" = "Blub do not understand. Blub thought we were briends.", - "insult_bad" = "Blub feels bad now.", - ) - -//probably could stick soem Howl references in here but like, eh. Haven't seen it in years. -/datum/trader/ship/unique/wizard - name = "Sorcerer" - origin = "A moving castle" - possible_origins = list("An indistinct location", "Unknown location", "The Diamond Sphere", "Beyond the Veil", "Deadverse") - name_language = TRADER_DEFAULT_NAME - - possible_wanted_items = list(/mob/living/simple_animal/construct = TRADER_SUBTYPES_ONLY, - /obj/item/sword/cultblade = TRADER_THIS_TYPE, - /obj/item/clothing/head/culthood = TRADER_ALL, - /obj/item/clothing/suit/space/cult = TRADER_ALL, - /obj/item/clothing/suit/cultrobes = TRADER_ALL, - /obj/item/clothing/head/helmet/space/cult = TRADER_ALL, - /obj/structure/cult = TRADER_SUBTYPES_ONLY, - /obj/structure/constructshell = TRADER_ALL, - /mob/living/simple_animal/familiar = TRADER_SUBTYPES_ONLY, - /mob/living/simple_animal/familiar/pet = TRADER_BLACKLIST, - /mob/living/simple_animal/hostile/mimic = TRADER_ALL) - - possible_trading_items = list(/obj/item/clothing/gloves/wizard = TRADER_THIS_TYPE, - /obj/item/clothing/head/helmet/space/void/wizard = TRADER_THIS_TYPE, - /obj/item/clothing/head/wizard = TRADER_ALL, - /obj/item/clothing/suit/space/void/wizard = TRADER_THIS_TYPE, - /obj/item/toy/figure/wizard = TRADER_THIS_TYPE, - /obj/item/staff = TRADER_ALL, - ) //Probably see about getting some more wizard based shit - - speech = list("hail_generic" = "Hello! Are you here on pleasure or business?", - "hail_Golem" = "Interesting... how incredibly interesting... come! Let us do business!", - "hail_deny" = "I'm sorry, but I REALLY don't want to speak to you.", - - "trade_complete" = "Pleasure doing business with you!", - "trade_no_money" = "Cash? Ha! What's cash to a man like me?", - "trade_not_enough" = "Hm, well I do enjoy what you're offering, I prefer a fair trade.", - "trade_found_unwanted" = "What? I want oddities! Don't you understand?", - "how_much" = "I want dark things, brooding things... things that go bump in the night. Things that bleed wrong, live wrong, are wrong.", - "what_want" = "Have anything from a broodish cult?", - - "compliment_deny" = "Like I haven't heard that one before!", - "compliment_accept" = "Haha! Aren't you nice.", - "insult_good" = "Naughty naughty.", - "insult_bad" = "Now where do you get off talking to me like that?", - ) \ No newline at end of file diff --git a/code/datums/trading/weaponry.dm b/code/datums/trading/weaponry.dm deleted file mode 100644 index dc65a094c927..000000000000 --- a/code/datums/trading/weaponry.dm +++ /dev/null @@ -1,86 +0,0 @@ -/datum/trader/ship/gunshop - name = "Gun Shop Employee" - name_language = TRADER_DEFAULT_NAME - origin = "Gun Shop" - possible_origins = list("Rooty Tootie's Point-n-Shooties", "Bang-Bang Shop", "Wild Wild West Shop", "Keleshnikov", "Hunting Depot", "Big Game Hunters") - speech = list("hail_generic" = "Hello, hello! I hope you have your permit. Oh, who are we kidding, you're welcome anyway!", - "hail_deny" = "Store policy dictates that you can fuck off.", - - "trade_complete" = "Thanks for buying your guns from ORIGIN!", - "trade_blacklist" = "We may deal in guns, but that doesn't mean we'll trade for illegal goods...", - "trade_no_goods" = "Cash for guns, thats the deal.", - "trade_not_enough" = "Guns are expensive! Give us more if you REALLY want it.", - "how_much" = "Well, I'd love to give this little beauty to you for VALUE.", - - "compliment_deny" = "If we were in the same room right now, I'd probably punch you.", - "compliment_accept" = "Ha! Good one!", - "insult_good" = "I expected better from you. I suppose in that, I was wrong.", - "insult_bad" = "If I had my gun I'd shoot you!" - ) - - possible_trading_items = list(/obj/item/gun/projectile/pistol/holdout = TRADER_ALL, - /obj/item/gun/projectile/shotgun/pump= TRADER_SUBTYPES_ONLY, - /obj/item/ammo_magazine = TRADER_SUBTYPES_ONLY, - /obj/item/ammo_magazine/rifle/empty = TRADER_BLACKLIST, - /obj/item/ammo_magazine/pistol/small/empty = TRADER_BLACKLIST, - /obj/item/ammo_magazine/pistol/empty = TRADER_BLACKLIST, - /obj/item/ammo_magazine/box/pistol/empty = TRADER_BLACKLIST, - /obj/item/ammo_magazine/smg/empty = TRADER_BLACKLIST, - /obj/item/clothing/accessory/storage/holster = TRADER_ALL) - -/datum/trader/ship/egunshop - name = "Energy Gun Shop Employee" - name_language = TRADER_DEFAULT_NAME - origin = "EGun Shop" - possible_origins = list("The Emperor's Lasgun Shop", "Future Guns", "Solar Army", "Kiefer's Dependable Electric Arms", "Olympus Kingsport") - speech = list("hail_generic" = "Welcome to the future of warfare! ORIGIN, your one-stop shop for energy weaponry!", - "hail_deny" = "I'm sorry, your communication channel has been blacklisted.", - - "trade_complete" = "Thank you, your purchase has been logged and you have automatically liked our Spacebook page.", - "trade_blacklist" = "I'm sorry, is that a joke?", - "trade_no_goods" = "We deal in cash.", - "trade_not_enough" = "State of the art weaponry costs more than that.", - "how_much" = "All our quality weapons are priceless, but I'd give that to you for VALUE.", - - "compliment_deny" = "If I was dumber I probably would have believed you.", - "compliment_accept" = "Yes, I am very smart.", - "insult_good" = "Energy weapons are TWICE the gun kinetic guns are!", - "insult_bad" = "That's... very mean. I won't think twice about blacklisting your channel, so stop." - ) - - possible_trading_items = list(/obj/item/gun/energy/taser = TRADER_THIS_TYPE, - /obj/item/gun/energy/xray = TRADER_THIS_TYPE, - /obj/item/gun/energy/laser = TRADER_THIS_TYPE, - /obj/item/gun/energy/gun = TRADER_THIS_TYPE, - /obj/item/cell = TRADER_THIS_TYPE, - /obj/item/cell/crap = TRADER_THIS_TYPE, - /obj/item/cell/high = TRADER_THIS_TYPE, - /obj/item/cell/super = TRADER_THIS_TYPE, - /obj/item/cell/hyper = TRADER_THIS_TYPE, - /obj/item/clothing/accessory/storage/holster = TRADER_ALL) - -/datum/trader/dogan - name = "Dogan" - origin = "Dogan's Gun Beacon" - speech = list("hail_generic" = "Hello! This is an automatic recording of me, Mr. Dogan! I hope you like the... GUNS... I've got in store for you today.", - "hail_deny" = "I formally welcome you to... NOT... visit our store!", - - "trade_complete" = "Thank you for... PURCHASING... that quality... ITEM... from me!", - "trade_blacklist" = "Thank you for... that quality... ILLEGAL OFFER THAT I WILL REFUSE... from me!", - "trade_no_goods" = "Thank you for... that quality... OFFER THAT ISN'T MONEY THAT I WILL REFUSE... from me!", - "trade_not_enough" = "Thank you for... that quality... OFFER THAT IS NOT ENOUGH... from me!", - "how_much" = "Thank you for... ASKING ME ABOUT MY PRICES... that quality... ITEM is worth VALUE... from me!", - - "compliment_deny" = "Thank you for... that quality... COMPLIMENT... from me!", - "compliment_accept" = "Thank you for... that quality... COMPLIMENT... from me!", - "insult_good" = "Thank you for... that quality... INSULT... from me!", - "insult_bad" = "Thank you for... that quality... INSULT... from me!" - ) - compliment_increase = 0 - insult_drop = 0 - - possible_trading_items = list(/obj/item/gun/projectile/zipgun = TRADER_THIS_TYPE, - /obj/item/gun/projectile/heavysniper/ant = TRADER_THIS_TYPE, - /obj/item/gun/energy/laser/dogan = TRADER_THIS_TYPE, - /obj/item/gun/projectile/automatic/smg/usi = TRADER_THIS_TYPE, - /obj/item/clothing/accessory/storage/holster = TRADER_ALL) \ No newline at end of file diff --git a/code/datums/traits/_trait_categories.dm b/code/datums/traits/_trait_categories.dm new file mode 100644 index 000000000000..7cbefad1ae18 --- /dev/null +++ b/code/datums/traits/_trait_categories.dm @@ -0,0 +1,10 @@ +var/global/list/trait_categories = list() // Containers for ease of printing data. + +/datum/trait_category + var/name + var/list/items = list() + var/hide_from_chargen = TRUE + +/datum/trait_category/New(var/newcategory) + ..() + name = newcategory diff --git a/code/datums/traits/_traits.dm b/code/datums/traits/_traits.dm new file mode 100644 index 000000000000..b3e7103fe9d4 --- /dev/null +++ b/code/datums/traits/_traits.dm @@ -0,0 +1,279 @@ +// Traits in general are abstract modifiers kept on the mob and checked in various places. +// Selectable traits are basically skills + stats + feats all rolled into one. You get to choose a +// certain number of them at character generation and they will alter some interactions with the world. + +/mob/living + /// A list of mob-specific traits, for when the list differs from the species list. + /// Overrides the species list; if it's identical to it, it will be unset. + /// Code using the traits system should use get_traits() instead. + VAR_PRIVATE/list/_mob_traits + +/mob/living/proc/has_trait(trait_type, trait_level = TRAIT_LEVEL_EXISTS) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + var/list/actual_traits = get_traits() + return (trait_type in actual_traits) && (!trait_level || actual_traits[trait_type] >= trait_level) + +/mob/living/proc/get_trait_level(trait_type) + SHOULD_NOT_SLEEP(TRUE) + var/traits = get_traits() + if(!traits) + return null + return traits[trait_type] + +/mob/proc/get_traits() + SHOULD_NOT_SLEEP(TRUE) + return null + +/mob/living/get_traits() + RETURN_TYPE(/list) + var/decl/species/our_species = get_species() + return _mob_traits || our_species?.traits + +/mob/living/proc/set_trait(trait_type, trait_level) + SHOULD_NOT_SLEEP(TRUE) + var/decl/species/our_species = get_species() + var/decl/trait/trait = GET_DECL(trait_type) + if(!trait.validate_level(trait_level)) + return FALSE + if(our_species && !_mob_traits) // If species traits haven't been setup before, check if we need to do so now + var/species_level = our_species.traits[trait_type] + if(species_level == trait_level) // Matched the default species trait level, ignore + return TRUE + _mob_traits = our_species.traits.Copy() // The setup is to simply copy the species list of traits + if(!(trait_type in _mob_traits)) + LAZYSET(_mob_traits, trait_type, trait_level) + trait.apply_trait(src) + return TRUE + +/mob/living/proc/remove_trait(trait_type, canonize = TRUE) + var/decl/species/our_species = get_species() + // If traits haven't been set up, but we're trying to remove a trait that exists on the species then set up traits + if(!_mob_traits && LAZYISIN(our_species?.traits, trait_type)) + _mob_traits = our_species.traits.Copy() + if(LAZYLEN(_mob_traits)) + LAZYREMOVE(_mob_traits, trait_type) + // Check if we can just default back to species traits. + if(canonize) + canonize_traits() + +/// Removes a trait unless it exists on the species. +/// If it does exist on the species, we reset it to the species' trait level. +/mob/living/proc/remove_extrinsic_trait(trait_type) + var/decl/species/our_species = get_species() + if(!LAZYACCESS(our_species?.traits, trait_type)) + remove_trait(trait_type) + else if(our_species?.traits[trait_type] != get_trait_level(trait_type)) + set_trait(trait_type, our_species?.traits[trait_type]) + +/mob/living/proc/clear_extrinsic_traits() + _mob_traits = null + +/// Sets the traits list to null if it's identical to the species list. +/// Returns TRUE if the list was reset and FALSE otherwise. +/mob/living/proc/canonize_traits() + if(!_mob_traits) // Already in canonical form. + return FALSE + var/decl/species/our_species = get_species() + if(!our_species) // Doesn't apply without a species. + return FALSE + if(_mob_traits ~= our_species.traits) + _mob_traits = null + return TRUE + return FALSE + +/decl/trait + abstract_type = /decl/trait + /// String identifier. + var/name + /// Flavour text. + var/description + /// A list of possible values for this trait. Should either only contain TRAIT_LEVEL_EXISTS or a set of the other TRAIT_LEVEL_* levels + var/list/levels = list(TRAIT_LEVEL_EXISTS) + /// Number of points spent or gained by taking this trait + var/trait_cost = 1 + /// Header for root traits in char prefs. + var/category + /// Parent/prerequisite for this trait. + var/decl/trait/parent + /// Aspects with this trait as a parent + var/list/children + /// Typelist of traits that prevent this one from being taken + var/list/incompatible_with + /// Whether or not trait is shown in chargen prefs + var/available_at_chargen = FALSE + /// Whether this trait should be available on a map with a given tech leve. + var/available_at_map_tech = MAP_TECH_LEVEL_ANY + /// Whether or not a rejuvenation should apply this aspect. + var/reapply_on_rejuvenation = FALSE + /// What species can select this trait in chargen? + var/list/permitted_species + /// What species cannot select this trait in chargen? + var/list/blocked_species + +/decl/trait/Initialize() + if(available_at_chargen) + decl_flags |= DECL_FLAG_MANDATORY_UID + return ..() + +/decl/trait/validate() + . = ..() + if(!name || !istext(name)) // Empty strings are valid texts + . += "invalid name [name || "(NULL)"]" + else + for(var/decl/trait/trait in decls_repository.get_decls_of_type_unassociated(/decl/trait)) + if(trait != src && lowertext(trait.name) == lowertext(name)) + . += "name '[name]' collides with [trait.type]" + + if(!length(levels)) + . += "invalid (empty) levels list" + else if (levels.len > 1 && (TRAIT_LEVEL_EXISTS in levels)) + . += "invalid levels list - TRAIT_LEVEL_EXISTS is mutually exclusive with all other levels" + + if(initial(parent) && !istype(parent)) + . += "invalid parent - [parent || "NULL"]" + for(var/decl/trait/trait as anything in children) + if(!istype(trait)) + . += "invalid child - [trait || "NULL"]" + else if(trait.parent != src) + . += "child [trait || "NULL"] does not have correct parent - expected [src], got [trait.parent || "NULL"]" + +/// A getter for the name shown in the preferences menu. Can be overridden for custom behavior based on prefs. +/decl/trait/proc/get_chargen_name(datum/preferences/pref) + return name + +/// A getter for the desc shown in the preferences menu. Can be overridden for custom behavior based on prefs. +/decl/trait/proc/get_chargen_desc(datum/preferences/pref) + return description + +/decl/trait/proc/is_available_at_chargen() + return available_at_chargen && global.using_map.map_tech_level >= available_at_map_tech + +/decl/trait/proc/validate_level(level) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_BE_PURE(TRUE) + return (level in levels) + +/decl/trait/proc/build_references() + SHOULD_CALL_PARENT(TRUE) + + // This is here until there are positive traits to balance out the negative ones; + // currently the cost calc serves no purpose and looks really silly sitting at -14/5. + trait_cost = 0 + // End temp set. + + if(ispath(parent)) + parent = GET_DECL(parent) + + if(category) + var/datum/trait_category/trait_category = global.trait_categories[category] + if(!istype(trait_category)) + trait_category = new(category) + global.trait_categories[category] = trait_category + trait_category.items += src + if(trait_category.hide_from_chargen && is_available_at_chargen()) + trait_category.hide_from_chargen = FALSE + if(istype(parent)) + LAZYDISTINCTADD(parent.children, src) + +/decl/trait/proc/applies_to_organ(var/organ) + return FALSE + +/decl/trait/proc/is_available_to_select(var/datum/preferences/pref) + if(!is_available_at_chargen()) + return FALSE + for(var/blacklisted_type in incompatible_with) + if(blacklisted_type in pref.traits) + return FALSE + if(blocked_species && (pref.species in blocked_species)) + return FALSE + if(permitted_species && !(pref.species in permitted_species)) + return FALSE + return TRUE + +/decl/trait/proc/apply_trait(mob/living/holder) + return (istype(holder)) + +// Called by preferences selection for HTML display. +/decl/trait/proc/get_trait_selection_data(var/datum/category_item/player_setup_item/traits/calling_item, var/list/ticked_traits = list(), var/recurse_level = 0, var/ignore_children_if_unticked = 1, var/ignore_unticked) + + var/ticked = (type in ticked_traits) + if((ignore_unticked && !ticked) || (calling_item && !is_available_to_select(calling_item.pref))) + return "" + + var/result = "" + if(recurse_level) + for(var/x = 1 to recurse_level) + result += "        " + + var/incompatible_trait_taken = FALSE + for(var/trait in incompatible_with) + if(trait in ticked_traits) + incompatible_trait_taken = TRUE + break + + var/chargen_name = get_chargen_name(calling_item.pref) + var/chargen_desc = get_chargen_desc(calling_item.pref) + if(istype(calling_item) && (ticked || calling_item.get_trait_total() + trait_cost <= get_config_value(/decl/config/num/max_character_traits)) && !incompatible_trait_taken) + result += "[ticked ? "[chargen_name]" : "[chargen_name]"] ([trait_cost])" + else + result += ticked ? "[chargen_name]" : "[chargen_name]" + + result += "" + if(ticked) + result += "[chargen_desc]" + else + result += "[chargen_desc]" + + result += "" + if(LAZYLEN(children) && !(ignore_children_if_unticked && !ticked)) + for(var/decl/trait/trait in children) + result += trait.get_trait_selection_data(calling_item, ticked_traits, (recurse_level+1), ignore_children_if_unticked) + return result + +/// Shows `show_to` a browser window describing the character setup traits taken by `src`. +/// `show_to` must be non-null. +/mob/proc/get_trait_data(var/mob/show_to) + + var/list/traits = get_traits() + if(!LAZYLEN(traits)) + to_chat(show_to, SPAN_WARNING("That mob has no traits.")) + return + + var/trait_cost = 0 + for(var/decl/trait/trait as anything in traits) + trait_cost += trait.trait_cost + + var/dat = list("[trait_cost]/[get_config_value(/decl/config/num/max_character_traits)] points spent.") + for(var/trait_category_id in global.trait_categories) + var/datum/trait_category/trait_category = global.trait_categories[trait_category_id] + if(!istype(trait_category)) + continue + var/printed_cat + for(var/decl/trait/trait as anything in trait_category.items) + if(trait in traits) + if(!printed_cat) + printed_cat = 1 + dat += "
    [trait_category.name]:" + dat += "
    [trait.name]: [trait.description]" + if(printed_cat) + dat += "
    " + + var/datum/browser/popup = new(show_to, "trait_summary_\ref[src]", "Aspect Summary") + popup.set_content(jointext(dat, null)) + popup.open() + +/mob/verb/show_own_traits() + set category = "IC" + set name = "Show Own Traits" + get_trait_data(src) + +/datum/admins/proc/show_traits() + set category = "Admin" + set name = "Show Traits" + if(!check_rights(R_INVESTIGATE)) + return + var/mob/M = input("Select mob.", "Select mob.") as null|anything in global.living_mob_list_ + if(M) + M.get_trait_data(usr) diff --git a/code/datums/traits/maluses/_malus.dm b/code/datums/traits/maluses/_malus.dm new file mode 100644 index 000000000000..03b958ea34b7 --- /dev/null +++ b/code/datums/traits/maluses/_malus.dm @@ -0,0 +1,5 @@ +/decl/trait/malus + category = "Maluses" + abstract_type = /decl/trait/malus + trait_cost = -1 + available_at_chargen = TRUE diff --git a/code/datums/traits/maluses/amputations.dm b/code/datums/traits/maluses/amputations.dm new file mode 100644 index 000000000000..8ce9bc5d4186 --- /dev/null +++ b/code/datums/traits/maluses/amputations.dm @@ -0,0 +1,117 @@ +/decl/trait/malus/amputation + trait_cost = -1 + category = "Missing Limbs" + abstract_type = /decl/trait/malus/amputation + reapply_on_rejuvenation = TRUE + var/list/apply_to_limbs + var/list/ban_traits_relating_to_limbs + +/decl/trait/malus/amputation/build_references() + if(length(ban_traits_relating_to_limbs)) + var/list/check_traits = decls_repository.get_decls_of_subtype(/decl/trait/malus/amputation) + + // Ban amputations that descend from us. + for(var/trait_type in check_traits) + if(trait_type == type) + continue + var/decl/trait/malus/amputation/trait = check_traits[trait_type] + for(var/limb in trait.apply_to_limbs) + if(limb in ban_traits_relating_to_limbs) + LAZYDISTINCTADD(incompatible_with, trait_type) + LAZYDISTINCTADD(trait.incompatible_with, type) + break + + // Ban prosthetic types that require this limb to exist. + check_traits = decls_repository.get_decls_of_subtype(/decl/trait/prosthetic_limb) + for(var/trait_type in check_traits) + if(trait_type == type) + continue + var/decl/trait/prosthetic_limb/trait = check_traits[trait_type] + if(trait.apply_to_limb in ban_traits_relating_to_limbs) + LAZYDISTINCTADD(incompatible_with, trait_type) + LAZYDISTINCTADD(trait.incompatible_with, type) + + . = ..() + +/decl/trait/malus/amputation/applies_to_organ(var/organ) + return (organ in apply_to_limbs) + +/decl/trait/malus/amputation/is_available_to_select(datum/preferences/pref) + . = ..() + if(. && pref.bodytype) + var/decl/bodytype/mob_bodytype = pref.get_bodytype_decl() + if(!istype(mob_bodytype)) + return FALSE + for(var/limb in apply_to_limbs) + if(!(limb in mob_bodytype.has_limbs)) + return FALSE + +/decl/trait/malus/amputation/apply_trait(mob/living/holder) + . = ..() + if(. && apply_to_limbs) + for(var/limb in apply_to_limbs) + var/obj/item/organ/external/O = GET_EXTERNAL_ORGAN(holder, limb) + if(istype(O)) + holder.remove_organ(O, FALSE, FALSE, FALSE, TRUE, FALSE) + qdel(O) + holder.update_body(TRUE) + +/decl/trait/malus/amputation/left_hand + name = "Amputated Left Hand" + description = "You are missing your left hand." + apply_to_limbs = list(BP_L_HAND) + ban_traits_relating_to_limbs = list(BP_L_HAND, BP_L_ARM) + uid = "trait_amputated_left_hand" + +/decl/trait/malus/amputation/left_arm + name = "Amputated Left Arm" + description = "You are missing your left arm." + apply_to_limbs = list(BP_L_ARM, BP_L_HAND) + ban_traits_relating_to_limbs = list(BP_L_ARM, BP_L_HAND) + trait_cost = -2 + uid = "trait_amputated_left_arm" + +/decl/trait/malus/amputation/right_hand + name = "Amputated Right Hand" + description = "You are missing your right hand." + apply_to_limbs = list(BP_R_HAND) + ban_traits_relating_to_limbs = list(BP_R_HAND, BP_R_ARM) + uid = "trait_amputated_right_hand" + +/decl/trait/malus/amputation/right_arm + name = "Amputated Right Arm" + description = "You are missing your right arm." + apply_to_limbs = list(BP_R_ARM, BP_R_HAND) + ban_traits_relating_to_limbs = list(BP_R_ARM, BP_R_HAND) + trait_cost = -2 + uid = "trait_amputated_right_arm" + +/decl/trait/malus/amputation/left_foot + name = "Amputated Left Foot" + description = "You are missing your left foot." + apply_to_limbs = list(BP_L_FOOT) + ban_traits_relating_to_limbs = list(BP_L_LEG, BP_L_FOOT) + uid = "trait_amputated_left_foot" + +/decl/trait/malus/amputation/left_leg + name = "Amputated Left Leg" + description = "You are missing your left leg." + apply_to_limbs = list(BP_L_LEG, BP_L_FOOT) + ban_traits_relating_to_limbs = list(BP_L_LEG, BP_L_FOOT) + trait_cost = -2 + uid = "trait_amputated_left_leg" + +/decl/trait/malus/amputation/right_foot + name = "Amputated Right Foot" + description = "You are missing your right foot." + apply_to_limbs = list(BP_R_FOOT) + ban_traits_relating_to_limbs = list(BP_R_LEG, BP_R_FOOT) + uid = "trait_amputated_right_foot" + +/decl/trait/malus/amputation/right_leg + name = "Amputated Right Leg" + description = "You are missing your right leg." + apply_to_limbs = list(BP_R_LEG, BP_R_FOOT) + ban_traits_relating_to_limbs = list(BP_R_LEG, BP_R_FOOT) + trait_cost = -2 + uid = "trait_amputated_right_leg" diff --git a/code/datums/traits/maluses/ethanol.dm b/code/datums/traits/maluses/ethanol.dm new file mode 100644 index 000000000000..14943bc4aebf --- /dev/null +++ b/code/datums/traits/maluses/ethanol.dm @@ -0,0 +1,5 @@ +/decl/trait/malus/ethanol + name = "Alcohol Intolerance" + levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MODERATE, TRAIT_LEVEL_MAJOR) + description = "You cannot handle alcohol at all, even in limited quantities, and will become seriously ill if you drink it." + uid = "trait_allergy_alcohol" diff --git a/code/datums/traits/maluses/intolerances.dm b/code/datums/traits/maluses/intolerances.dm new file mode 100644 index 000000000000..4c4b096dbd69 --- /dev/null +++ b/code/datums/traits/maluses/intolerances.dm @@ -0,0 +1,106 @@ +var/global/list/_intolerances_by_flag = list() +/proc/get_intolerances_by_flag(allergen_flags, ingestion_method) + + var/flag_key + if(ingestion_method) + flag_key = "[allergen_flags]-[ingestion_method]" + else + flag_key = num2text(allergen_flags) + + . = global._intolerances_by_flag[flag_key] + if(isnull(.)) + . = list() + for(var/decl/trait/malus/intolerance/allergy in decls_repository.get_decls_of_type_unassociated(/decl/trait/malus/intolerance)) + if((!ingestion_method || (ingestion_method in allergy.ingested_types)) && (allergy.allergen_flags & allergen_flags)) + . += allergy + global._intolerances_by_flag[flag_key] = . + +/decl/trait/malus/intolerance + abstract_type = /decl/trait/malus/intolerance + levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MAJOR) + var/list/ingested_types = list(CHEM_INGEST) + var/allergen_flags = ALLERGEN_NONE + +/decl/trait/malus/intolerance/protein + name = "Protein Intolerance" + description = "You are allergic to or intolerant of animal protein in any form, and can become very ill if you ingest it." + allergen_flags = (ALLERGEN_MEAT | ALLERGEN_FISH | ALLERGEN_DAIRY | ALLERGEN_EGG) + uid = "trait_allergy_protein" + +/decl/trait/malus/intolerance/meat + name = "Meat Intolerance" + description = "You are allergic or intolerant of red and white meat, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_MEAT | ALLERGEN_FISH + uid = "trait_allergy_meat" + +/decl/trait/malus/intolerance/fish + name = "Fish Intolerance" + description = "You are allergic to or intolerant of fish meat, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_FISH + uid = "trait_allergy_fish" + +/decl/trait/malus/intolerance/vegetable + name = "Vegetable Intolerance" + description = "You are allergic to or intolerant of vegetables, and can become very ill if you ingest them." + allergen_flags = ALLERGEN_VEGETABLE + uid = "trait_allergy_vegetable" + +/decl/trait/malus/intolerance/dairy + name = "Dairy Intolerance" + description = "You are allergic to or intolerant of milk solids or lactose - essentially dairy in any form - and can become very ill if you ingest it." + allergen_flags = ALLERGEN_DAIRY + uid = "trait_allergy_dairy" + +/decl/trait/malus/intolerance/egg + name = "Egg Intolerance" + description = "You are allergic to or intolerant of eggs, and can become very ill if you ingest them." + allergen_flags = ALLERGEN_EGG + uid = "trait_allergy_egg" + +/decl/trait/malus/intolerance/fruit + name = "Fruit Intolerance" + description = "You are allergic to or intolerant of fruit, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_FRUIT + uid = "trait_allergy_fruit" + +/decl/trait/malus/intolerance/gluten + name = "Gluten Intolerance" + description = "You are allergic to or intolerant of gluten, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_GLUTEN + uid = "trait_allergy_gluten" + +/decl/trait/malus/intolerance/soy + name = "Soy Intolerance" + description = "You are allergic to or intolerant of soy protein, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_SOY + uid = "trait_allergy_soy" + +/decl/trait/malus/intolerance/caffeine + name = "Caffeine Intolerance" + description = "You are allergic to or intolerant of caffeine, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_CAFFEINE + uid = "trait_allergy_caffeine" + +/decl/trait/malus/intolerance/fungi + name = "Mushroom Intolerance" + description = "You are allergic to or intolerant of mushrooms and fungi, and can become very ill if you ingest them." + allergen_flags = ALLERGEN_FUNGI + uid = "trait_allergy_fungi" + +/decl/trait/malus/intolerance/nuts + name = "Nut Intolerance" + description = "You are allergic to or intolerant of nuts, and can become very ill if you ingest them." + allergen_flags = ALLERGEN_NUTS + uid = "trait_allergy_nuts" + +/decl/trait/malus/intolerance/stimulant + name = "Caffeine Intolerance" + description = "You are allergic to or intolerant of caffeine, and can become very ill if you ingest it." + allergen_flags = ALLERGEN_CAFFEINE + uid = "trait_allergy_caffeine" + +/decl/trait/malus/intolerance/stimulant + name = "Stimulant Intolerance" + description = "You are allergic to or intolerant of stimulants, and can become very ill if you ingest them." + allergen_flags = ALLERGEN_STIMULANT | ALLERGEN_CAFFEINE + uid = "trait_allergy_stimulant" diff --git a/code/datums/traits/maluses/vision.dm b/code/datums/traits/maluses/vision.dm new file mode 100644 index 000000000000..b3402c2328ff --- /dev/null +++ b/code/datums/traits/maluses/vision.dm @@ -0,0 +1,70 @@ +/decl/trait/malus/impaired_vision + name = "Poor Eyesight" + description = "Your vision is somewhat impaired, and you need prescription glasses to see clearly." + incompatible_with = list(/decl/trait/prosthetic_organ/eyes) + uid = "trait_vision_poor" + /// The typepath of the glasses to give the holder. + var/glasses_type = /obj/item/clothing/glasses/prescription + +/decl/trait/malus/impaired_vision/apply_trait(mob/living/holder) + . = ..() + if(.) + holder.add_genetic_condition(GENE_COND_NEARSIGHTED) + var/equipped = holder.equip_to_slot_or_del(new glasses_type(holder), slot_glasses_str) + if(equipped) + var/obj/item/clothing/glasses/G = holder.get_equipped_item(slot_glasses_str) + if(istype(G)) + G.prescription = 7 + +/decl/trait/malus/colourblind + name = "Deuteranopia" + description = "You have a type of red-green colour blindness, and cannot properly perceive the colour green." + incompatible_with = list( + /decl/trait/prosthetic_organ/eyes, + /decl/trait/malus/colourblind/protanopia, + /decl/trait/malus/colourblind/tritanopia, + /decl/trait/malus/colourblind/achromatopsia, + ) + uid = "trait_vision_deuteranopia" + var/client_color = /datum/client_color/deuteranopia + +/decl/trait/malus/colourblind/apply_trait(mob/living/holder) + . = ..() + if(. && ispath(client_color, /datum/client_color)) + holder.add_client_color(client_color) + +/decl/trait/malus/colourblind/protanopia + name = "Protanopia" + description = "You have a type of red-green colour blindness, and cannot properly perceive the colour red." + incompatible_with = list( + /decl/trait/prosthetic_organ/eyes, + /decl/trait/malus/colourblind/tritanopia, + /decl/trait/malus/colourblind/achromatopsia, + /decl/trait/malus/colourblind + ) + client_color = /datum/client_color/protanopia + uid = "trait_vision_protanopia" + +/decl/trait/malus/colourblind/tritanopia + name = "Tritanopia" + description = "You have a rare type of colour blindness, and cannot properly perceive the colour blue." + incompatible_with = list( + /decl/trait/prosthetic_organ/eyes, + /decl/trait/malus/colourblind/protanopia, + /decl/trait/malus/colourblind/achromatopsia, + /decl/trait/malus/colourblind + ) + client_color = /datum/client_color/tritanopia + uid = "trait_vision_trianopia" + +/decl/trait/malus/colourblind/achromatopsia + name = "Achromatopsia" + description = "You have a rare type of colour blindness, and cannot properly perceive colour." + incompatible_with = list( + /decl/trait/prosthetic_organ/eyes, + /decl/trait/malus/colourblind/protanopia, + /decl/trait/malus/colourblind/tritanopia, + /decl/trait/malus/colourblind + ) + client_color = /datum/client_color/achromatopsia + uid = "trait_vision_achromatopsia" diff --git a/code/datums/traits/metabolically_inert.dm b/code/datums/traits/metabolically_inert.dm new file mode 100644 index 000000000000..e885d28867d7 --- /dev/null +++ b/code/datums/traits/metabolically_inert.dm @@ -0,0 +1,3 @@ +/decl/trait/metabolically_inert + name = "Metabolically Inert" + description = "For better or worse, there is little that this creature metabolizes." \ No newline at end of file diff --git a/code/datums/traits/prosthetics/prosthetic_limbs.dm b/code/datums/traits/prosthetics/prosthetic_limbs.dm new file mode 100644 index 000000000000..a620ebef2942 --- /dev/null +++ b/code/datums/traits/prosthetics/prosthetic_limbs.dm @@ -0,0 +1,206 @@ +// Prosthetics. +/decl/trait/prosthetic_limb + trait_cost = 1 + category = "Prosthetic Limbs" + available_at_chargen = TRUE + available_at_map_tech = MAP_TECH_LEVEL_ANY // the base trait must be available so that wooden prostheses are available + abstract_type = /decl/trait/prosthetic_limb + reapply_on_rejuvenation = TRUE + var/fullbody_synthetic_only = FALSE + var/replace_children = TRUE + var/check_bodytype + var/bodypart_name + var/apply_to_limb = BP_L_HAND + var/list/incompatible_with_limbs = list(BP_L_HAND) + var/model + +/decl/trait/prosthetic_limb/proc/get_base_model(var/species_uid) + var/decl/species/species = decls_repository.get_decl_by_id(species_uid || global.using_map.default_species) + return species?.base_external_prosthetics_model + +/decl/trait/prosthetic_limb/get_chargen_name(datum/preferences/pref) + var/decl/bodytype/prosthetic/our_model = get_base_model(pref.species) + if(!model && our_model.name) + return "[capitalize_words(our_model.name)] [bodypart_name]" + return ..() + +/decl/trait/prosthetic_limb/get_chargen_desc(datum/preferences/pref) + var/decl/bodytype/prosthetic/our_model = get_base_model(pref.species) + if(!model && our_model.name) + return "You have been fitted with [ADD_ARTICLE(our_model.name)] [lowertext(bodypart_name)] prosthesis." + return ..() + +/decl/trait/prosthetic_limb/Initialize() + . = ..() + // Macro can generate float costs, round to closest point value. + if(trait_cost) + trait_cost = ceil(trait_cost) + if(bodypart_name) + if(model) + var/decl/bodytype/prosthetic/model_manufacturer = GET_DECL(model) + name = "[capitalize_words(model_manufacturer.name)] [bodypart_name]" + description = "You have been fitted with [ADD_ARTICLE(model_manufacturer.name)] [lowertext(bodypart_name)] prosthesis." + available_at_map_tech = model_manufacturer.required_map_tech + else + name = "Prosthetic [bodypart_name]" + description = "You have been fitted with a basic [lowertext(bodypart_name)] prosthesis." + +/decl/trait/prosthetic_limb/build_references() + . = ..() + // Build our mutual exclusion list with other models/children. + if(length(incompatible_with_limbs)) + var/list/check_traits = decls_repository.get_decls_of_subtype(/decl/trait/prosthetic_limb) + for(var/trait_type in check_traits) + // Can't exclude ourselves. + if(trait_type == type) + continue + // The base model trait does not exclude itself from specific models, but specific models will exclude from all others. + var/decl/trait/prosthetic_limb/trait = check_traits[trait_type] + if(!(trait.apply_to_limb in incompatible_with_limbs)) + continue + // Base model is only incompatible with itself. + if(isnull(model) != isnull(trait.model) && (!isnull(model) || !isnull(trait.model))) + continue + // Specific models are incompatible with everything. + LAZYDISTINCTADD(incompatible_with, trait_type) + LAZYDISTINCTADD(trait.incompatible_with, type) + + // We will also exclude from relevant amputations, but they will be handled by amputation trait build_references() + + // If our model has any additional trait handling, do it here. + // Without a model, we will rely on is_available_to_select() to check get_base_model() for the user species. + blocked_species = null + +/decl/trait/prosthetic_limb/applies_to_organ(var/organ) + return apply_to_limb && organ == apply_to_limb + +/decl/trait/prosthetic_limb/is_available_to_select(datum/preferences/pref) + . = ..() + if(.) + if(fullbody_synthetic_only) + var/decl/bodytype/bodytype = pref.get_bodytype_decl() + if(!bodytype?.is_robotic) + return FALSE + if(model) + var/decl/bodytype/prosthetic/robot_model = GET_DECL(model) + if(!istype(robot_model)) + return FALSE + var/decl/species/S = pref.get_species_decl() + var/decl/bodytype/B = S.get_bodytype_by_name(pref.bodytype) + if(!robot_model.check_can_install(apply_to_limb, target_bodytype = (check_bodytype || B.bodytype_category))) + return FALSE + // If we're a duplicate of our parent due to get_base_model(), hide this one. + var/decl/trait/prosthetic_limb/parent_limb = parent + if(parent && !parent_limb.model && parent_limb.get_base_model(pref.species) == model && parent_limb.bodypart_name == bodypart_name) + return FALSE // duplicate + else if(!get_base_model(pref.species)) + return FALSE + +/decl/trait/prosthetic_limb/apply_trait(mob/living/holder) + . = ..() + + // Don't apply if there's a specific model selected. + if(!model && holder) + var/has_specific_model = FALSE + for(var/trait_type in holder.get_traits()) + var/decl/trait/trait = GET_DECL(trait_type) + if(trait != src && istype(trait, type)) + has_specific_model = TRUE + break + if(has_specific_model) + return + + // Robotize the selected limb. + if(. && apply_to_limb) + var/use_model = model || get_base_model(holder.get_species()?.uid) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(holder, apply_to_limb) + if(!istype(E)) + var/list/organ_data = holder.should_have_limb(apply_to_limb) + var/limb_path = organ_data["path"] + if("path" in organ_data) + E = new limb_path(holder, null, use_model) + if(istype(E) && E.bodytype != model) // sometimes in the last line we save ourselves some work here + // this should be pre-validated by is_available_to_select() + if(replace_children) + E.set_bodytype_with_children(use_model) + else + E.set_bodytype(use_model) + +/decl/trait/prosthetic_limb/left_hand + bodypart_name = "Left Hand" + apply_to_limb = BP_L_HAND + incompatible_with_limbs = list(BP_L_HAND, BP_L_ARM) + uid = "trait_prosthetic_left_hand" + +/decl/trait/prosthetic_limb/left_arm + bodypart_name = "Left Arm" + trait_cost = 2 + apply_to_limb = BP_L_ARM + incompatible_with_limbs = list(BP_L_HAND, BP_L_ARM) + uid = "trait_prosthetic_left_arm" + +/decl/trait/prosthetic_limb/right_hand + bodypart_name = "Right Hand" + apply_to_limb = BP_R_HAND + incompatible_with_limbs = list(BP_R_HAND, BP_R_ARM) + uid = "trait_prosthetic_right_hand" + +/decl/trait/prosthetic_limb/right_arm + bodypart_name = "Right Arm" + trait_cost = 2 + apply_to_limb = BP_R_ARM + incompatible_with_limbs = list(BP_R_HAND, BP_R_ARM) + uid = "trait_prosthetic_right_arm" + +/decl/trait/prosthetic_limb/left_foot + bodypart_name = "Left Foot" + apply_to_limb = BP_L_FOOT + incompatible_with_limbs = list(BP_L_FOOT, BP_L_LEG) + uid = "trait_prosthetic_left_foot" + +/decl/trait/prosthetic_limb/left_leg + bodypart_name = "Left Leg" + trait_cost = 2 + apply_to_limb = BP_L_LEG + incompatible_with_limbs = list(BP_L_FOOT, BP_L_LEG) + uid = "trait_prosthetic_left_leg" + +/decl/trait/prosthetic_limb/right_foot + bodypart_name = "Right Foot" + apply_to_limb = BP_R_FOOT + incompatible_with_limbs = list(BP_R_FOOT, BP_R_LEG) + uid = "trait_prosthetic_right_foot" + +/decl/trait/prosthetic_limb/right_leg + bodypart_name = "Right Leg" + trait_cost = 2 + apply_to_limb = BP_R_LEG + incompatible_with_limbs = list(BP_R_FOOT, BP_R_LEG) + uid = "trait_prosthetic_right_leg" + +/decl/trait/prosthetic_limb/head + bodypart_name = "Head" + trait_cost = 1 + apply_to_limb = BP_HEAD + incompatible_with_limbs = list(BP_HEAD) + fullbody_synthetic_only = TRUE + replace_children = FALSE + uid = "trait_prosthetic_head" + +/decl/trait/prosthetic_limb/chest + bodypart_name = "Upper Body" + trait_cost = 1 + apply_to_limb = BP_CHEST + incompatible_with_limbs = list(BP_CHEST) + fullbody_synthetic_only = TRUE + replace_children = FALSE + uid = "trait_prosthetic_upper_body" + +/decl/trait/prosthetic_limb/groin + bodypart_name = "Lower Body" + trait_cost = 1 + apply_to_limb = BP_GROIN + incompatible_with_limbs = list(BP_GROIN) + fullbody_synthetic_only = TRUE + replace_children = FALSE + uid = "trait_prosthetic_lower_body" diff --git a/code/datums/traits/prosthetics/prosthetic_organs.dm b/code/datums/traits/prosthetics/prosthetic_organs.dm new file mode 100644 index 000000000000..0ae6ce949569 --- /dev/null +++ b/code/datums/traits/prosthetics/prosthetic_organs.dm @@ -0,0 +1,115 @@ +/decl/trait/prosthetic_organ + abstract_type = /decl/trait/prosthetic_organ + trait_cost = 1 + available_at_chargen = TRUE + available_at_map_tech = MAP_TECH_LEVEL_SPACE + category = "Prosthetic Organs" + reapply_on_rejuvenation = TRUE + var/synthetic_bodytype_restricted = FALSE + var/apply_to_organ + +/decl/trait/prosthetic_organ/is_available_to_select(datum/preferences/pref) + . = ..() + if(. && pref.species && pref.bodytype) + + var/decl/species/mob_species = pref.get_species_decl() + if(!istype(mob_species) || isnull(mob_species.base_internal_prosthetics_model)) + return FALSE + + var/decl/bodytype/mob_bodytype = pref.get_bodytype_decl() + + if(!istype(mob_bodytype)) + return FALSE + + // Synthetic organs are generally unnecessary in FBPs as they have robotic innards regardless. + if(synthetic_bodytype_restricted) + if(!mob_bodytype.is_robotic) + return FALSE + else + if(mob_bodytype.is_robotic) + return FALSE + + if(!(apply_to_organ in mob_bodytype.has_organ)) + return FALSE + + if(mob_species.species_flags & SPECIES_NO_ROBOTIC_INTERNAL_ORGANS) + return FALSE + + return TRUE + +/decl/trait/prosthetic_organ/applies_to_organ(var/organ) + return apply_to_organ && organ == apply_to_organ + +/decl/trait/prosthetic_organ/apply_trait(mob/living/holder) + . = ..() + if(.) + var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(holder, apply_to_organ) + if(I) + I.set_bodytype(I.species.base_internal_prosthetics_model) + +/decl/trait/prosthetic_organ/heart + name = "Prosthetic Heart" + description = "You have a synthetic heart." + uid = "trait_prosthetic_heart" + apply_to_organ = BP_HEART + +/decl/trait/prosthetic_organ/eyes + name = "Prosthetic Eyes" + description = "Your vision is augmented." + apply_to_organ = BP_EYES + incompatible_with = list( + /decl/trait/malus/impaired_vision, + /decl/trait/malus/colourblind, + /decl/trait/malus/colourblind/protanopia, + /decl/trait/malus/colourblind/tritanopia, + /decl/trait/malus/colourblind/achromatopsia + ) + uid = "trait_prosthetic_eyes" + +/decl/trait/prosthetic_organ/kidneys + name = "Prosthetic Kidneys" + description = "You have synthetic kidneys." + apply_to_organ = BP_KIDNEYS + uid = "trait_prosthetic_kidneys" + +/decl/trait/prosthetic_organ/liver + name = "Prosthetic Liver" + description = "You have a literal iron liver." + apply_to_organ = BP_LIVER + uid = "trait_prosthetic_liver" + +/decl/trait/prosthetic_organ/lungs + name = "Prosthetic Lungs" + description = "You have synthetic lungs." + apply_to_organ = BP_LUNGS + uid = "trait_prosthetic_lungs" + +/decl/trait/prosthetic_organ/stomach + name = "Prosthetic Stomach" + description = "You have a literal iron stomach." + apply_to_organ = BP_STOMACH + uid = "trait_prosthetic_stomach" + +/decl/trait/prosthetic_organ/brain + name = "Synthetic Brain" + description = "You are an artificial lifeform, with a mind made of steel and light." + apply_to_organ = BP_BRAIN + synthetic_bodytype_restricted = TRUE + uid = "trait_prosthetic_brain" + var/new_brain_type = /obj/item/organ/internal/brain/robotic + +/decl/trait/prosthetic_organ/brain/apply_trait(mob/living/holder) + . = ..() + if(.) + var/obj/item/organ/external/affected + var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(holder, apply_to_organ) + if(I) + affected = GET_EXTERNAL_ORGAN(holder, I.parent_organ) + I.transfer_brainmob_with_organ = FALSE // we don't want to pull them out of the mob + holder.remove_organ(I, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE) + qdel(I) + var/obj/item/organ/organ = new new_brain_type(holder) + if(!affected) + affected = GET_EXTERNAL_ORGAN(holder, organ.parent_organ) + if(affected) + holder.add_organ(organ, affected, TRUE, FALSE, FALSE, TRUE) diff --git a/code/datums/type_cloning.dm b/code/datums/type_cloning.dm new file mode 100644 index 000000000000..4ceeea67dfe6 --- /dev/null +++ b/code/datums/type_cloning.dm @@ -0,0 +1,10 @@ +/* + * A bunch of Clone implementation for system types, so they're compatible with the + * Clone() proc used on other datums. + */ + +/matrix/GetCloneArgs() + return list(src) //Matrices handle copies themselves + +/image/GetCloneArgs() + return list(src) //Same for images \ No newline at end of file diff --git a/code/datums/underwear/bottom.dm b/code/datums/underwear/bottom.dm index a2ed61658161..fc8bd4a2ee30 100644 --- a/code/datums/underwear/bottom.dm +++ b/code/datums/underwear/bottom.dm @@ -1,4 +1,5 @@ /datum/category_item/underwear/bottom + abstract_type = /datum/category_item/underwear/bottom underwear_gender = PLURAL underwear_name = "underwear" underwear_type = /obj/item/underwear/bottom diff --git a/code/datums/underwear/socks.dm b/code/datums/underwear/socks.dm index 4b2689521937..70dc7454dce7 100644 --- a/code/datums/underwear/socks.dm +++ b/code/datums/underwear/socks.dm @@ -1,4 +1,5 @@ /datum/category_item/underwear/socks + abstract_type = /datum/category_item/underwear/socks underwear_name = "socks" underwear_gender = PLURAL underwear_type = /obj/item/underwear/socks diff --git a/code/datums/underwear/top.dm b/code/datums/underwear/top.dm index 6b559214f65e..816df62549df 100644 --- a/code/datums/underwear/top.dm +++ b/code/datums/underwear/top.dm @@ -1,4 +1,5 @@ /datum/category_item/underwear/top + abstract_type = /datum/category_item/underwear/top underwear_name = "bra" underwear_type = /obj/item/underwear/top diff --git a/code/datums/underwear/undershirt.dm b/code/datums/underwear/undershirt.dm index ad2f3c3691f7..ae4ac6a5d603 100644 --- a/code/datums/underwear/undershirt.dm +++ b/code/datums/underwear/undershirt.dm @@ -1,4 +1,5 @@ /datum/category_item/underwear/undershirt + abstract_type = /datum/category_item/underwear/undershirt underwear_name = "undershirt" underwear_type = /obj/item/underwear/undershirt diff --git a/code/datums/underwear/underwear.dm b/code/datums/underwear/underwear.dm index d7bf88e5e8f8..d1d2c0a3ca75 100644 --- a/code/datums/underwear/underwear.dm +++ b/code/datums/underwear/underwear.dm @@ -1,17 +1,18 @@ /**************************** * Category Collection Setup * ****************************/ +// TODO: replace underwear category stuff with decls or something? unlike player_setup_collection they're all singletons +// i hate to say it but the way this works may actually be perfect for /decl/hierarchy +var/global/datum/category_collection/underwear/underwear = new() /datum/category_collection/underwear category_group_type = /datum/category_group/underwear /************* * Categories * *************/ +// Lower sort order is applied as icons first /datum/category_group/underwear - var/sort_order // Lower sort order is applied as icons first - -datum/category_group/underwear/dd_SortValue() - return sort_order + abstract_type = /datum/category_group/underwear /datum/category_group/underwear/top name = "Underwear, top" @@ -66,10 +67,10 @@ datum/category_group/underwear/dd_SortValue() var/obj/item/underwear/UW = new underwear_type() UW.SetName(underwear_name) - UW.gender = underwear_gender + UW.set_gender(underwear_gender) UW.icon = icon UW.icon_state = icon_state for(var/datum/gear_tweak/gt in tweaks) - gt.tweak_item(user, UW, metadata && metadata["[gt]"] ? metadata["[gt]"] : gt.get_default()) + gt.tweak_item(user, UW, ((metadata && metadata["[gt]"]) ? metadata["[gt]"] : gt.get_default())) return UW diff --git a/code/datums/uplink/ammunition.dm b/code/datums/uplink/ammunition.dm index 60e757452b38..0b9d512df9df 100644 --- a/code/datums/uplink/ammunition.dm +++ b/code/datums/uplink/ammunition.dm @@ -34,44 +34,17 @@ item_cost = 8 path = /obj/item/ammo_magazine/rifle -/datum/uplink_item/item/ammo/bullpup //for zipguns - name = "Bullpup Rifle Magazine" - desc = "A magazine for bullpup assault rifles. Contains 15 rounds." - item_cost = 8 - path = /obj/item/ammo_magazine/rifle - -/datum/uplink_item/item/ammo/sniperammo - name = "Ammobox of Sniper Rounds" - desc = "A container of rounds for the anti-materiel rifle. Contains 7 rounds." - item_cost = 8 - path = /obj/item/storage/box/ammo/sniperammo - antag_roles = list(MODE_MERCENARY) - -/datum/uplink_item/item/ammo/sniperammo/apds - name = "Ammobox of APDS Sniper Rounds" - desc = "A container of armor piercing rounds for the anti-materiel rifle. Contains 3 rounds." - item_cost = 12 - path = /obj/item/storage/box/ammo/sniperammo/apds - antag_roles = list(MODE_MERCENARY) - /datum/uplink_item/item/ammo/shotgun_shells name = "Ammobox of Shotgun Shells" - desc = "An ammobox with 2 sets of shell holders. Contains 8 buckshot shells total." + desc = "An ammo box with 2 sets of shell holders. Contains 8 buckshot shells total." item_cost = 8 - path = /obj/item/storage/box/ammo/shotgunshells + path = /obj/item/box/ammo/shotgunshells /datum/uplink_item/item/ammo/shotgun_slugs name = "Ammobox of Shotgun Slugs" - desc = "An ammobox with 2 sets of shell holders. Contains 8 slugs total." - item_cost = 8 - path = /obj/item/storage/box/ammo/shotgunammo - -/datum/uplink_item/item/ammo/smg - name = "Standard Box Magazine" - desc = "A magazine for standard SMGs. Contains 20 rounds." + desc = "An ammo box with 2 sets of shell holders. Contains 8 slugs total." item_cost = 8 - path = /obj/item/ammo_magazine/smg - antag_roles = list(MODE_MERCENARY) + path = /obj/item/box/ammo/shotgunammo /datum/uplink_item/item/ammo/speedloader_magnum name = "Magnum Speedloader" @@ -79,13 +52,6 @@ item_cost = 8 path = /obj/item/ammo_magazine/speedloader -/datum/uplink_item/item/ammo/flechette - name = "Flechette Rifle Magazine" - desc = "A rifle magazine loaded with flechette rounds. Contains 9 rounds." - item_cost = 8 - path = /obj/item/magnetic_ammo - antag_roles = list(MODE_MERCENARY) - /datum/uplink_item/item/ammo/pistol_emp name = "Standard EMP Ammo Box" desc = "A box of EMP ammo for standard pistols. Contains 15 rounds." diff --git a/code/datums/uplink/badassery.dm b/code/datums/uplink/badassery.dm index 3b340158edbe..a0b1b26d0da3 100644 --- a/code/datums/uplink/badassery.dm +++ b/code/datums/uplink/badassery.dm @@ -11,7 +11,7 @@ /datum/uplink_item/item/badassery/balloon/random name = "For showing 'Whatevah~' (Useless Balloon)" - desc = "Randomly selects a ballon for you!" + desc = "Randomly selects a balloon for you!" path = /obj/item/toy/balloon /datum/uplink_item/item/badassery/balloon/random/get_goods(var/obj/item/uplink/U, var/loc) @@ -23,13 +23,13 @@ name = "Crayon MRE" desc = "Exceptionally robust MRE" item_cost = DEFAULT_TELECRYSTAL_AMOUNT - path = /obj/item/storage/mre/menu11/special + path = /obj/item/mre/menu11/special /datum/uplink_item/item/badassery/modded_foam_gun name = "Modded foam gun" desc = "It's a Jorf revolver blaster and 14 weighted darts. Even after aftermarket modification to increase its range and launch velocity, it's not a very effective weapon." item_cost = 32 - path = /obj/item/storage/box/large/foam_gun/revolver/tampered + path = /obj/item/box/large/foam_gun/revolver/tampered /************** * Random Item * @@ -67,33 +67,3 @@ /datum/uplink_item/item/badassery/random_many/purchase_log(obj/item/uplink/U) SSstatistics.add_field_details("traitor_uplink_items_bought", "[src]") log_and_message_admins("used \the [U.loc] to buy \a [src]") - -/**************** -* Surplus Crate * -****************/ -/datum/uplink_item/item/badassery/surplus - name = "\improper Surplus Crate" - item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 4 - var/item_worth = DEFAULT_TELECRYSTAL_AMOUNT * 6 - var/icon - -/datum/uplink_item/item/badassery/surplus/New() - ..() - antag_roles = list(MODE_MERCENARY) - desc = "A crate containing [item_worth] telecrystal\s worth of surplus leftovers. If you can find some help to pay for it, you might strike gold." - -/datum/uplink_item/item/badassery/surplus/get_goods(var/obj/item/uplink/U, var/loc) - var/obj/structure/largecrate/C = new(loc) - var/random_items = get_random_uplink_items(U, item_worth, C) - for(var/datum/uplink_item/I in random_items) - I.purchase_log(U) - I.get_goods(U, C) - - return C - -/datum/uplink_item/item/badassery/surplus/log_icon() - if(!icon) - var/obj/structure/largecrate/C = /obj/structure/largecrate - icon = image(initial(C.icon), initial(C.icon_state)) - - return "\icon[icon]" diff --git a/code/datums/uplink/devices and tools.dm b/code/datums/uplink/devices and tools.dm deleted file mode 100644 index 83480ea15e92..000000000000 --- a/code/datums/uplink/devices and tools.dm +++ /dev/null @@ -1,163 +0,0 @@ -/******************** -* Devices and Tools * -********************/ -/datum/uplink_item/item/tools - category = /datum/uplink_category/tools - -/datum/uplink_item/item/tools/toolbox - name = "Fully Loaded Toolbox" - desc = "A hefty toolbox filled with all the equipment you need to get past any construction or electrical issues. \ - Instructions and materials not included." - item_cost = 8 - path = /obj/item/storage/toolbox/syndicate - -/datum/uplink_item/item/tools/ductape - name = "Duct Tape" - desc = "A roll of duct tape. changes \"HELP\" into sexy \"mmm\"." - item_cost = 2 - path = /obj/item/tape_roll - -/datum/uplink_item/item/tools/money - name = "Operations Funding" - item_cost = 8 - path = /obj/item/storage/secure/briefcase/money -/datum/uplink_item/item/tools/money/New() - . = ..() - desc = "A briefcase with a very large sum of untraceable local currency. Makes a great bribe if they're willing to take you up on your offer." - -/datum/uplink_item/item/tools/clerical - name = "Morphic Clerical Kit" - desc = "Comes with everything you need to fake paperwork, assuming you know how to forge the required documents." - item_cost = 16 - path = /obj/item/storage/backpack/satchel/syndie_kit/clerical - -/datum/uplink_item/item/tools/plastique - name = "C-4" - desc = "Set this on a wall to put a hole exactly where you need it." - item_cost = 16 - path = /obj/item/plastique - -/datum/uplink_item/item/tools/heavy_armor - name = "Heavy Armor Vest and Helmet" - desc = "This satchel holds a combat helmet and fully equipped plate carrier. \ - Suit up, and strap in, things are about to get hectic." - item_cost = 16 - path = /obj/item/storage/backpack/satchel/syndie_kit/armor - -/datum/uplink_item/item/tools/encryptionkey_radio - name = "Encrypted Radio Channel Key" - desc = "This headset encryption key will allow you to speak on a hidden, encrypted radio channel. Use a screwdriver on your headset to exchange keys." - item_cost = 1 - path = /obj/item/encryptionkey/syndicate - -/datum/uplink_item/item/tools/shield_diffuser - name = "Handheld Shield Diffuser" - desc = "A small device used to disrupt energy barriers, and allow passage through them." - item_cost = 16 - path = /obj/item/shield_diffuser - -/datum/uplink_item/item/tools/suit_sensor_mobile - name = "Suit Sensor Jamming Device" - desc = "This tiny device can temporarily change sensor levels, report random readings, or false readings on any \ - suit sensors in your vicinity. The range at which this device operates can be toggled as well. All of these \ - options drain the internal battery." - item_cost = 20 - path = /obj/item/suit_sensor_jammer - -/datum/uplink_item/item/tools/encryptionkey_binary - name = "Binary Translator Key" - desc = "This headset encryption key will allow you to both listen and speak on the binary channel that \ - synthetics and AI have access to. Remember, non-synths don't normally have access to this channel, so talking in it will raise suspicion. \ - Use a screwdriver on your headset to exchange keys." - item_cost = 20 - path = /obj/item/encryptionkey/binary - -/datum/uplink_item/item/tools/emag - name = "Cryptographic Sequencer" - desc = "An electromagnetic card capable of scrambling electronics to either subvert them into serving you, \ - or giving you access to things you normally can't. Doors can be opened with this card \ - even if you aren't normally able to, but will destroy them in the proccess. This card can have its appearance changed \ - to look less conspicuous." - item_cost = 24 - path = /obj/item/card/emag - -/datum/uplink_item/item/tools/hacking_tool - name = "Door Hacking Tool" - item_cost = 24 - path = /obj/item/multitool/hacktool - desc = "Appears and functions as a standard multitool until a screwdriver is used to toggle it. \ - While in hacking mode, this device will grant full access to any airlock in 20 to 40 seconds. \ - This device will be able to continuously reaccess the last 6 to 8 airlocks it was used on." - -/datum/uplink_item/item/tools/space_suit - name = "Voidsuit and Tactical Mask" - desc = "A satchel containing a non-regulation voidsuit, voidsuit helmet, tactical mask, and oxygen tank. \ - Conceal your identity, while also not dying in space." - item_cost = 28 - path = /obj/item/storage/backpack/satchel/syndie_kit/space - -/datum/uplink_item/item/tools/thermal - name = "Thermal Imaging Glasses" - desc = "A pair of meson goggles that have been modified to instead show synthetics or living creatures, through thermal imaging." - item_cost = 24 - path = /obj/item/clothing/glasses/thermal/syndi - -/datum/uplink_item/item/tools/flashdark - name = "Flashdark" - desc = "A device similar to a flash light that absorbs the surrounding light, casting a shadowy, black mass." - item_cost = 32 - path = /obj/item/flashlight/flashdark - -/datum/uplink_item/item/tools/powersink - name = "Powersink (DANGER!)" - desc = "A device, that when bolted down to an exposed wire, spikes the surrounding electrical systems, \ - draining power at an alarming rate. Use with caution, as this will be extremely noticable to anyone \ - monitoring the power systems." - item_cost = 40 - path = /obj/item/powersink - -/datum/uplink_item/item/tools/teleporter - name = "Teleporter Circuit Board" - desc = "A circuit board that can be used to create a teleporter console, able to lock onto detected \ - teleportation beacons. Requires a projector and teleporter hub nearby to work." - item_cost = 40 - path = /obj/item/stock_parts/circuitboard/teleporter - -/datum/uplink_item/item/tools/teleporter/New() - ..() - antag_roles = list(MODE_MERCENARY) - -/datum/uplink_item/item/tools/ai_module - name = "Hacked AI Upload Module" - desc = "A module that can be used anonymously add a singular, top level law to an active AI. \ - All you need to do is write in the law and insert it into any available AI Upload Console." - item_cost = 52 - path = /obj/item/aiModule/syndicate - -/datum/uplink_item/item/tools/supply_beacon - name = "Hacked Supply Beacon (DANGER!)" - desc = "Wrench this large beacon onto an exposed power cable, in order to activate it. This will call in a \ - drop pod to the target location, containing a random assortment of (possibly useful) items. \ - The ship's computer system will announce when this pod is enroute." - item_cost = 52 - path = /obj/item/supply_beacon - -/datum/uplink_item/item/tools/camera_mask - name = "Camera MIU" - desc = "Wearing this mask allows you to remotely view any cameras you currently have access to. Take the mask off to stop viewing." - item_cost = 60 - antag_costs = list(MODE_MERCENARY = 30) - path = /obj/item/clothing/mask/ai - -/datum/uplink_item/item/tools/interceptor - name = "Radio Interceptor" - item_cost = 30 - path = /obj/item/radio/intercept - desc = "A receiver-like device that can intercept secure radio channels. This item is too big to fit into your pockets." - -/datum/uplink_item/item/tools/ttv - name = "Binary Gas Bomb" - item_cost = 30 - path = /obj/effect/spawner/newbomb/traitor - desc = "A remote-activated hydrogen-oxygen bomb assembly with an included signaler. \ - A flashing disclaimer begins with the warning 'SOME DISASSEMBLY/REASSEMBLY REQUIRED.'" diff --git a/code/datums/uplink/devices_and_tools.dm b/code/datums/uplink/devices_and_tools.dm new file mode 100644 index 000000000000..b9e59845a66a --- /dev/null +++ b/code/datums/uplink/devices_and_tools.dm @@ -0,0 +1,151 @@ +/******************** +* Devices and Tools * +********************/ +/datum/uplink_item/item/tools + category = /datum/uplink_category/tools + +/datum/uplink_item/item/tools/toolbox + name = "Fully Loaded Toolbox" + desc = "A hefty toolbox filled with all the equipment you need to get past any construction or electrical issues. \ + Instructions and materials not included." + item_cost = 8 + path = /obj/item/toolbox/syndicate + +/datum/uplink_item/item/tools/ductape + name = "Duct Tape" + desc = "A roll of duct tape. Will silence anyone, just like a particularly bad duck pun." + item_cost = 2 + path = /obj/item/stack/tape_roll/duct_tape + +/datum/uplink_item/item/tools/money + name = "Operations Funding" + item_cost = 8 + path = /obj/item/secure_storage/briefcase/money +/datum/uplink_item/item/tools/money/New() + . = ..() + desc = "A briefcase with a very large sum of untraceable local currency. Makes a great bribe if they're willing to take you up on your offer." + +/datum/uplink_item/item/tools/clerical + name = "Morphic Clerical Kit" + desc = "Comes with everything you need to fake paperwork, assuming you know how to forge the required documents." + item_cost = 16 + path = /obj/item/backpack/satchel/syndie_kit/clerical + +/datum/uplink_item/item/tools/plastique + name = "C-4" + desc = "Set this on a wall to put a hole exactly where you need it." + item_cost = 16 + path = /obj/item/plastique + +/datum/uplink_item/item/tools/heavy_armor + name = "Heavy Armor Vest and Helmet" + desc = "This satchel holds a combat helmet and fully equipped plate carrier. \ + Suit up, and strap in, things are about to get hectic." + item_cost = 16 + path = /obj/item/backpack/satchel/syndie_kit/armor + +/datum/uplink_item/item/tools/encryptionkey_radio + name = "Encrypted Radio Channel Key" + desc = "This headset encryption key will allow you to speak on a hidden, encrypted radio channel. Use a screwdriver on your headset to exchange keys." + item_cost = 1 + path = /obj/item/encryptionkey/hacked + +/datum/uplink_item/item/tools/shield_diffuser + name = "Handheld Shield Diffuser" + desc = "A small device used to disrupt energy barriers, and allow passage through them." + item_cost = 16 + path = /obj/item/shield_diffuser + +/datum/uplink_item/item/tools/suit_sensor_mobile + name = "Suit Sensor Jamming Device" + desc = "This tiny device can temporarily change sensor levels, report random readings, or false readings on any \ + suit sensors in your vicinity. The range at which this device operates can be toggled as well. All of these \ + options drain the internal battery." + item_cost = 20 + path = /obj/item/suit_sensor_jammer + +/datum/uplink_item/item/tools/encryptionkey_binary + name = "Binary Translator Key" + desc = "This headset encryption key will allow you to both listen and speak on the binary channel that \ + synthetics and AI have access to. Remember, non-synths don't normally have access to this channel, so talking in it will raise suspicion. \ + Use a screwdriver on your headset to exchange keys." + item_cost = 20 + path = /obj/item/encryptionkey/binary + +/datum/uplink_item/item/tools/emag + name = "Cryptographic Sequencer" + desc = "An electromagnetic card capable of scrambling electronics to either subvert them into serving you, \ + or giving you access to things you normally can't. Doors can be opened with this card \ + even if you aren't normally able to, but will destroy them in the proccess. This card can have its appearance changed \ + to look less conspicuous." + item_cost = 24 + path = /obj/item/card/emag + +/datum/uplink_item/item/tools/hacking_tool + name = "Door Hacking Tool" + item_cost = 24 + path = /obj/item/multitool/hacktool + desc = "Appears and functions as a standard multitool until a screwdriver is used to toggle it. \ + While in hacking mode, this device will grant full access to any airlock in 20 to 40 seconds. \ + This device will be able to continuously reaccess the last 6 to 8 airlocks it was used on." + +/datum/uplink_item/item/tools/space_suit + name = "Voidsuit and Tactical Mask" + desc = "A satchel containing a non-regulation voidsuit, voidsuit helmet, tactical mask, and oxygen tank. \ + Conceal your identity, while also not dying in space." + item_cost = 28 + path = /obj/item/backpack/satchel/syndie_kit/space + +/datum/uplink_item/item/tools/thermal + name = "Thermal Imaging Glasses" + desc = "A pair of meson goggles that have been modified to instead show synthetics or living creatures, through thermal imaging." + item_cost = 24 + path = /obj/item/clothing/glasses/thermal/syndi + +/datum/uplink_item/item/tools/flashdark + name = "Flashdark" + desc = "A device similar to a flashlight that absorbs the surrounding light, casting a shadowy, black mass." + item_cost = 32 + path = /obj/item/flashlight/flashdark + +/datum/uplink_item/item/tools/powersink + name = "Powersink (DANGER!)" + desc = "A device, that when bolted down to an exposed wire, spikes the surrounding electrical systems, \ + draining power at an alarming rate. Use with caution, as this will be extremely noticable to anyone \ + monitoring the power systems." + item_cost = 40 + path = /obj/item/powersink + +/datum/uplink_item/item/tools/ai_module + name = "Hacked AI Upload Module" + desc = "A module that can be used anonymously add a singular, top level law to an active AI. \ + All you need to do is write in the law and insert it into any available AI Upload Console." + item_cost = 52 + path = /obj/item/aiModule/syndicate + +/datum/uplink_item/item/tools/supply_beacon + name = "Hacked Supply Beacon (DANGER!)" + desc = "Wrench this large beacon onto an exposed power cable and add some cabling, in order to activate it. This will call in a \ + drop pod to the target location, containing a random assortment of (possibly useful) items. \ + The ship's computer system will announce when this pod is enroute." + item_cost = 52 + path = /obj/item/supply_beacon + +/datum/uplink_item/item/tools/camera_mask + name = "Camera MIU" + desc = "Wearing this mask allows you to remotely view any cameras you currently have access to. Take the mask off to stop viewing." + item_cost = 60 + path = /obj/item/clothing/mask/ai + +/datum/uplink_item/item/tools/interceptor + name = "Radio Interceptor" + item_cost = 30 + path = /obj/item/radio/intercept + desc = "A receiver-like device that can intercept secure radio channels. This item is too big to fit into your pockets." + +/datum/uplink_item/item/tools/ttv + name = "Binary Gas Bomb" + item_cost = 30 + path = /obj/effect/spawner/newbomb/traitor + desc = "A remote-activated hydrogen-oxygen bomb assembly with an included signaler. \ + A flashing disclaimer begins with the warning 'SOME DISASSEMBLY/REASSEMBLY REQUIRED.'" diff --git a/code/datums/uplink/grenades.dm b/code/datums/uplink/grenades.dm index a0ee1172b44c..fa22ab92bffc 100644 --- a/code/datums/uplink/grenades.dm +++ b/code/datums/uplink/grenades.dm @@ -14,7 +14,7 @@ name = "5x Decompiler Grenades" desc = "These grenades contain experimental mechanisms that will draw in all nearby objects and collapse them down to their component materials." item_cost = 25 - path = /obj/item/storage/box/decompilers + path = /obj/item/box/decompilers /datum/uplink_item/item/grenades/anti_photon name = "1x Photon Disruption Grenade" @@ -25,7 +25,7 @@ /datum/uplink_item/item/grenades/anti_photons name = "5x Photon Disruption Grenades" item_cost = 16 - path = /obj/item/storage/box/anti_photons + path = /obj/item/box/anti_photons /datum/uplink_item/item/grenades/smoke name = "1x Smoke Grenade" @@ -36,7 +36,7 @@ /datum/uplink_item/item/grenades/smokes name = "5x Smoke Grenades" item_cost = 16 - path = /obj/item/storage/box/smokes + path = /obj/item/box/smokes /datum/uplink_item/item/grenades/emp name = "1x EMP Grenade" @@ -47,50 +47,4 @@ /datum/uplink_item/item/grenades/emps name = "5x EMP Grenades" item_cost = 24 - path = /obj/item/storage/box/emps - -/datum/uplink_item/item/grenades/frag_high_yield - name = "Fragmentation Bomb" - item_cost = 24 - antag_roles = list(MODE_MERCENARY) // yeah maybe regular traitors shouldn't be able to get these - path = /obj/item/grenade/frag/high_yield - -/datum/uplink_item/item/grenades/fragshell - name = "1x Fragmentation Shell" - desc = "Weaker than standard fragmentation grenades, these devices can be fired from a grenade launcher." - item_cost = 10 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/grenade/frag/shell - -/datum/uplink_item/item/grenades/fragshells - name = "5x Fragmentation Shells" - desc = "Weaker than standard fragmentation grenades, these devices can be fired from a grenade launcher." - item_cost = 40 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/storage/box/fragshells - -/datum/uplink_item/item/grenades/frag - name = "1x Fragmentation Grenade" - item_cost = 10 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/grenade/frag - -/datum/uplink_item/item/grenades/frags - name = "5x Fragmentation Grenades" - item_cost = 40 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/storage/box/frags - -/datum/uplink_item/item/grenades/supermatter - name = "1x Supermatter Grenade" - desc = "This grenade contains a small supermatter shard which will delaminate upon activation and pull in nearby objects, irradiate lifeforms, and eventually explode." - item_cost = 15 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/grenade/supermatter - -/datum/uplink_item/item/grenades/supermatters - name = "5x Supermatter Grenades" - desc = "These grenades contains a small supermatter shard which will delaminate upon activation and pull in nearby objects, irradiate lifeforms, and eventually explode." - item_cost = 60 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/storage/box/supermatters + path = /obj/item/box/emps diff --git a/code/datums/uplink/hardsuit_modules.dm b/code/datums/uplink/hardsuit_modules.dm index 872cbe8a1ad7..076c0247d543 100644 --- a/code/datums/uplink/hardsuit_modules.dm +++ b/code/datums/uplink/hardsuit_modules.dm @@ -20,7 +20,7 @@ name = "\improper Electrowarfare Suite and Voice Synthesiser" desc = "Includes two modules that, once installed and activated, are capable of masking your voice and disrupting the AI from tracking you." item_cost = 24 - path = /obj/item/storage/backpack/satchel/syndie_kit/ewar_voice + path = /obj/item/backpack/satchel/syndie_kit/ewar_voice /datum/uplink_item/item/hardsuit_modules/maneuvering_jets name = "\improper Maneuvering Jets" @@ -39,10 +39,3 @@ desc = "A module capable of recharging your suit's power reserves, by tapping into an exposed, live wire." item_cost = 48 path = /obj/item/rig_module/power_sink - -/datum/uplink_item/item/hardsuit_modules/laser_canon - name = "\improper Mounted Laser Cannon" - desc = "A module capable of draining your suit's power reserves in order to fire a shoulder mounted laser cannon." - item_cost = 64 - path = /obj/item/rig_module/mounted/lcannon - antag_roles = list(MODE_MERCENARY) diff --git a/code/datums/uplink/highly_visible_and_dangerous_weapons.dm b/code/datums/uplink/highly_visible_and_dangerous_weapons.dm index a55eb883fceb..66e2b05b34d3 100644 --- a/code/datums/uplink/highly_visible_and_dangerous_weapons.dm +++ b/code/datums/uplink/highly_visible_and_dangerous_weapons.dm @@ -41,7 +41,7 @@ desc = "A kit with a pocket-sized holdout pistol, silencer, and an extra magazine. \ Attaching the silencer will make it too big to conceal in your pocket." item_cost = 32 - path = /obj/item/storage/box/syndie_kit/silenced + path = /obj/item/box/syndie_kit/silenced /datum/uplink_item/item/badassery/money_cannon name = "Modified Money Cannon" @@ -51,7 +51,7 @@ /datum/uplink_item/item/visible_weapons/energy_gun name = "Energy Gun" - desc = "A energy based sidearm with three different lethality settings." + desc = "An energy-based sidearm with three different lethality settings." item_cost = 32 path = /obj/item/gun/energy/gun @@ -59,29 +59,7 @@ name = "Magnum Revolver" desc = "A high-caliber revolver. Includes an extra speedloader of ammo." item_cost = 56 - path = /obj/item/storage/backpack/satchel/syndie_kit/revolver - -/datum/uplink_item/item/visible_weapons/grenade_launcher - name = "Grenade Launcher" - desc = "A pump action grenade launcher loaded with a random assortment of grenades" - item_cost = 60 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/gun/launcher/grenade/loaded - -//These are for traitors (or other antags, perhaps) to have the option of purchasing some merc gear. -/datum/uplink_item/item/visible_weapons/smg - name = "Standard Submachine Gun" - desc = "A quick-firing weapon with three togglable fire modes." - item_cost = 52 - path = /obj/item/gun/projectile/automatic/smg - antag_roles = list(MODE_MERCENARY) - -/datum/uplink_item/item/visible_weapons/assaultrifle - name = "Assault Rifle" - desc = "A common rifle with three togglable fire modes." - item_cost = 60 - path = /obj/item/gun/projectile/automatic/assault_rifle - antag_roles = list(MODE_MERCENARY) + path = /obj/item/backpack/satchel/syndie_kit/revolver /datum/uplink_item/item/visible_weapons/advanced_energy_gun name = "Advanced Energy Gun" @@ -89,41 +67,12 @@ item_cost = 60 path = /obj/item/gun/energy/gun/nuclear -/datum/uplink_item/item/visible_weapons/heavysniper - name = "Anti-materiel Sniper Rifle" - desc = "A secure briefcase that contains an immensely powerful penetrating rifle, as well as seven extra sniper rounds." - item_cost = 68 - path = /obj/item/storage/secure/briefcase/heavysniper - antag_roles = list(MODE_MERCENARY) - -/datum/uplink_item/item/visible_weapons/combat_shotgun - name = "Pump Shotgun" - desc = "A high compacity, pump-action shotgun regularly used for repelling boarding parties in close range scenarios." - item_cost = 52 - path = /obj/item/gun/projectile/shotgun/pump - antag_roles = list(MODE_MERCENARY) - /datum/uplink_item/item/visible_weapons/sawnoff name = "Sawnoff Shotgun" desc = "A shortened double-barrel shotgun, able to fire either one, or both, barrels at once." item_cost = 45 path = /obj/item/gun/projectile/shotgun/doublebarrel/sawn -/datum/uplink_item/item/visible_weapons/flechetterifle - name = "Flechette Rifle" - desc = "A railgun with two togglable fire modes, able to launch flechette ammunition at incredible speeds." - item_cost = 60 - path = /obj/item/gun/magnetic/railgun/flechette - antag_roles = list(MODE_MERCENARY) - -/datum/uplink_item/item/visible_weapons/railgun // Like a semi-auto AMR - name = "Railgun" - desc = "An anti-armour magnetic launching system fed by a high-capacity matter cartridge, \ - capable of firing slugs at intense speeds." - item_cost = DEFAULT_TELECRYSTAL_AMOUNT - (DEFAULT_TELECRYSTAL_AMOUNT - (DEFAULT_TELECRYSTAL_AMOUNT % 6)) / 6 - antag_roles = list(MODE_MERCENARY) - path = /obj/item/gun/magnetic/railgun - /datum/uplink_item/item/visible_weapons/harpoonbomb name = "Explosive Harpoon" item_cost = 12 diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm index eaaa0cd864d8..0495c267c1b8 100644 --- a/code/datums/uplink/implants.dm +++ b/code/datums/uplink/implants.dm @@ -6,27 +6,27 @@ /datum/uplink_item/item/implants/imp_freedom name = "Freedom Implant" - desc = "An implant with an emotive trigger that can break you free of restraints. Show Security who has the real upperhand!" + desc = "An implant with an emotive trigger that can break you free of restraints. Show Security who has the real upper hand!" item_cost = 24 - path = /obj/item/storage/box/syndie_kit/imp_freedom + path = /obj/item/box/syndie_kit/imp_freedom /datum/uplink_item/item/implants/imp_compress name = "Compressed Matter Implant" desc = "An implant with an emotive trigger used to hide a handheld item in your body. \ Activating it materializes the item in your hand." item_cost = 32 - path = /obj/item/storage/box/syndie_kit/imp_compress + path = /obj/item/box/syndie_kit/imp_compress /datum/uplink_item/item/implants/imp_explosive name = "Explosive Implant (DANGER!)" desc = "An explosive impant activated with a vocal trigger or radio signal. \ Use the included pad to adjust the settings before implanting." item_cost = 40 - path = /obj/item/storage/box/syndie_kit/imp_explosive + path = /obj/item/box/syndie_kit/imp_explosive /datum/uplink_item/item/implants/imp_uplink name = "Uplink Implant" - path = /obj/item/storage/box/syndie_kit/imp_uplink + path = /obj/item/box/syndie_kit/imp_uplink /datum/uplink_item/item/implants/imp_uplink/New() ..() @@ -39,4 +39,4 @@ desc = "An implant able to be used on someone who is under the influence of hallucinogenics to give them a \ set of law-like instructions to follow. This kit contains a dose of hallucinogenics." item_cost = 20 - path = /obj/item/storage/box/syndie_kit/imp_imprinting + path = /obj/item/box/syndie_kit/imp_imprinting diff --git a/code/datums/uplink/medical.dm b/code/datums/uplink/medical.dm index 32527a8424e6..4aef274b938c 100644 --- a/code/datums/uplink/medical.dm +++ b/code/datums/uplink/medical.dm @@ -8,17 +8,17 @@ name = "Box of Sin-Pockets" desc = "A box of filled dough pockets. Great for a quick meal when you're hiding from Security. Instructions included on the box." item_cost = 8 - path = /obj/item/storage/box/sinpockets + path = /obj/item/box/sinpockets /datum/uplink_item/item/medical/stabilisation name = "Stabilisation First Aid Kit" desc = "Contains variety of emergency medical pouches." item_cost = 16 - path = /obj/item/storage/firstaid/stab + path = /obj/item/firstaid/stab /datum/uplink_item/item/medical/stasis name = "Stasis Bag" - desc = "Reusable bag designed to slow down life functions of occupant, especially useful if short on time or in a hostile enviroment." + desc = "Reusable bag designed to slow down life functions of occupant, especially useful if short on time or in a hostile environment." item_cost = 24 path = /obj/item/bodybag/cryobag @@ -32,10 +32,10 @@ name = "Surgery Kit" desc = "Contains all the tools needed for on the spot surgery, assuming you actually know what you're doing with them. Floor sterilization not included." item_cost = 40 - path = /obj/item/storage/firstaid/surgery + path = /obj/item/firstaid/surgery /datum/uplink_item/item/medical/combat name = "Combat Medical Kit" desc = "Contains most medicines you need to recover from injuries and illnesses, all in a convenient pill form. Splints for broken bones also included!" item_cost = 48 - path = /obj/item/storage/firstaid/combat + path = /obj/item/firstaid/combat diff --git a/code/datums/uplink/services.dm b/code/datums/uplink/services.dm index 9c436f6e3916..435455774852 100644 --- a/code/datums/uplink/services.dm +++ b/code/datums/uplink/services.dm @@ -41,10 +41,11 @@ /datum/uplink_item/item/services/fake_update_annoncement/New() ..() item_cost = round(DEFAULT_TELECRYSTAL_AMOUNT / 2) + addtimer(CALLBACK(src, PROC_REF(finalize_announce)), 2) - spawn(2) - name = "[command_name()] Update Announcement" - desc = "Causes a falsified [command_name()] Update." +/datum/uplink_item/item/services/fake_update_annoncement/proc/finalize_announce() + name = "[global.using_map.boss_name] Update Announcement" + desc = "Causes a falsified [global.using_map.boss_name] Update." /*************** * Service Item * @@ -58,8 +59,9 @@ name = "tiny device" desc = "Press button to activate. Can be done once and only once." w_class = ITEM_SIZE_TINY - icon = 'icons/obj/items/device/flash.dmi' - icon_state = "sflash" + icon = 'icons/obj/items/device/flash_synthetic.dmi' + icon_state = ICON_STATE_WORLD + max_health = ITEM_HEALTH_NO_DAMAGE var/state = AWAITING_ACTIVATION var/service_label = "Unnamed Service" var/service_duration = 0 SECONDS @@ -69,22 +71,22 @@ deactivate() . = ..() -/obj/item/uplink_service/examine(mob/user, distance) +/obj/item/uplink_service/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) switch(state) if(AWAITING_ACTIVATION) - to_chat(user, "It is labeled '[service_label]' and appears to be awaiting activation.") + LAZYADD(., "It is labeled '[service_label]' and appears to be awaiting activation.") if(CURRENTLY_ACTIVE) - to_chat(user, "It is labeled '[service_label]' and appears to be active.") + LAZYADD(., "It is labeled '[service_label]' and appears to be active.") if(HAS_BEEN_ACTIVATED) - to_chat(user, "It is labeled '[service_label]' and appears to be permanently disabled.") + LAZYADD(., "It is labeled '[service_label]' and appears to be permanently disabled.") /obj/item/uplink_service/attack_self(var/mob/user) if(state != AWAITING_ACTIVATION) to_chat(user, "\The [src] won't activate again.") return - var/obj/effect/overmap/visitable/O = map_sectors["[get_z(src)]"] + var/obj/effect/overmap/visitable/O = global.overmap_sectors[get_z(src)] var/choice = alert(user, "This will only affect your current location[istype(O) ? " ([O])" : ""]. Proceed?","Confirmation", "Yes", "No") if(choice != "Yes") return @@ -96,7 +98,7 @@ log_and_message_admins("has activated the service '[service_label]'", user) if(service_duration) - addtimer(CALLBACK(src,/obj/item/uplink_service/proc/deactivate), service_duration) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/uplink_service, deactivate)), service_duration) else deactivate() @@ -110,13 +112,13 @@ visible_message("\The [src] shuts down with a spark.") /obj/item/uplink_service/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() switch(state) - if(AWAITING_ACTIVATION) - icon_state = initial(icon_state) if(CURRENTLY_ACTIVE) - icon_state = "flash_on" + icon_state = "[icon_state]-on" if(HAS_BEEN_ACTIVATED) - icon_state = "flash_burnt" + icon_state = "[icon_state]-burnt" /obj/item/uplink_service/proc/enable(var/mob/user = usr) return TRUE @@ -159,7 +161,7 @@ service_label = "Ion Storm Announcement" /obj/item/uplink_service/fake_ion_storm/enable(var/mob/user = usr) - ion_storm_announcement(GetConnectedZlevels(get_z(src))) + ion_storm_announcement(SSmapping.get_connected_levels(get_z(src))) . = ..() /***************** @@ -187,9 +189,9 @@ if(!message) return - if(CanUseTopic(user, GLOB.hands_state) != STATUS_INTERACTIVE) + if(CanUseTopic(user, global.hands_topic_state) != STATUS_INTERACTIVE) return FALSE - command_announcement.Announce(message, title, msg_sanitized = 1, zlevels = GetConnectedZlevels(get_z(src))) + command_announcement.Announce(message, title, msg_sanitized = 1, zlevels = SSmapping.get_connected_levels(get_z(src))) return TRUE /********************************* @@ -211,7 +213,7 @@ if(I) new_record.set_name(I.registered_name) new_record.set_formal_name("[I.formal_name_prefix][I.registered_name][I.formal_name_suffix]") - new_record.set_sex(I.sex) + new_record.set_gender(I.card_gender) new_record.set_age(I.age) new_record.set_job(I.assignment) new_record.set_fingerprint(I.fingerprint_hash) @@ -225,14 +227,14 @@ if(random_record) COPY_VALUE(faction) COPY_VALUE(religion) - COPY_VALUE(homeSystem) + COPY_VALUE(residence) COPY_VALUE(fingerprint) COPY_VALUE(dna) COPY_VALUE(bloodtype) var/datum/job/job = SSjobs.get_by_title(new_record.get_job()) if(job) var/skills = list() - for(var/decl/hierarchy/skill/S in GLOB.skills) + for(var/decl/skill/S in global.using_map.get_available_skills()) var/level = job.min_skill[S.type] if(prob(10)) level = min(rand(1,3), job.max_skill[S.type]) @@ -241,7 +243,9 @@ new_record.set_skillset(jointext(skills,"\n")) if(istype(job) && job.announced) - AnnounceArrivalSimple(new_record.get_name(), new_record.get_job(), "has completed cryogenic revival", get_announcement_frequency(job)) + var/announce_channel = get_announcement_frequency(job) + if(announce_channel) + do_telecomms_announcement(user, "[new_record.get_name()], [new_record.get_job()], has completed cryogenic revival.", "Arrivals Announcement Computer", announce_channel) . = ..() -#undef COPY_VALUE \ No newline at end of file +#undef COPY_VALUE diff --git a/code/datums/uplink/stealth_and_camouflage_items.dm b/code/datums/uplink/stealth_and_camouflage_items.dm index 2d07822149c1..d2f189c5dd24 100644 --- a/code/datums/uplink/stealth_and_camouflage_items.dm +++ b/code/datums/uplink/stealth_and_camouflage_items.dm @@ -25,7 +25,7 @@ name = "Bug Kit" desc = "For when you want to conduct voyeurism from afar. Comes with 6 bugs to plant, and a monitoring device to pair them with." item_cost = 8 - path = /obj/item/storage/box/syndie_kit/spy + path = /obj/item/box/syndie_kit/spy /datum/uplink_item/item/stealth_items/id name = "Agent ID card" @@ -38,11 +38,11 @@ desc = "Comes with a full set of appearance changing clothing you need to impersonate most people. \ Accessories, backpack, and gun included!" item_cost = 20 - path = /obj/item/storage/backpack/chameleon/sydie_kit + path = /obj/item/backpack/chameleon/sydie_kit /datum/uplink_item/item/stealth_items/voice name = "Modified Gas Mask" - desc = "A fully functioning gas mask that is able to conceal your face and has a built in voice modulator, \ + desc = "A fully functioning gas mask that is able to conceal your face and has a built-in voice modulator, \ so you can become a true shadow operative!" item_cost = 20 path = /obj/item/clothing/mask/chameleon/voice @@ -56,7 +56,7 @@ /datum/uplink_item/item/stealth_items/sneakies name = "Sneakies" desc = "A fashionable pair of polished dress shoes. The soles are made in a way so that any \ - tracks you leave look like they are traveling in the opposite direction." + tracks you leave look like they are travelling in the opposite direction." item_cost = 4 path = /obj/item/clothing/shoes/dress/sneakies @@ -65,7 +65,7 @@ desc = "This satchel is thin enough to be hidden in the gap between plating and tiling, \ great for stashing your stolen goods. Comes with a crowbar and a floor tile." item_cost = 20 - path = /obj/item/storage/backpack/satchel/flat + path = /obj/item/backpack/satchel/flat /datum/uplink_item/item/stealth_items/warez name = "Warez Disk" diff --git a/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm b/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm index e2ebb1acdc43..45deaffbf371 100644 --- a/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm +++ b/code/datums/uplink/stealthy_and_inconspicuous_weapons.dm @@ -13,25 +13,25 @@ name = "Box of Tricky Cigarettes" desc = "A box with some 'special' packs in the following order: 2x Flashes, 2x Smokes, 1x Hallucinogenics, and 1x Regenerative Serum. Try not to mix them up!" item_cost = 8 - path = /obj/item/storage/box/syndie_kit/cigarette + path = /obj/item/box/syndie_kit/cigarette /datum/uplink_item/item/stealthy_weapons/concealed_cane name = "Concealed Cane Sword" - desc = "A cane used by a true gentlemen, especially ones with sharp intentions." + desc = "A cane used by a true gentleman, especially ones with sharp intentions." item_cost = 8 - path = /obj/item/cane/concealed + path = /obj/item/cane/fancy/sword /datum/uplink_item/item/stealthy_weapons/wcoat_armored name = "Armoured Waistcoat" desc = "A classy waistcoat that discreetly provides a layer of low-profile armor to the discerning agent." item_cost = 6 - path = /obj/item/clothing/accessory/wcoat/armored + path = /obj/item/clothing/suit/jacket/waistcoat/armored /datum/uplink_item/item/stealthy_weapons/random_toxin name = "Random Toxin Vial" desc = "Contains one of an assortment of nasty toxins, with a single syringe included. Don't worry, its labeled. " item_cost = 8 - path = /obj/item/storage/box/syndie_kit/toxin + path = /obj/item/box/syndie_kit/toxin /datum/uplink_item/item/stealthy_weapons/sleepy name = "Paralytic Pen" @@ -43,4 +43,4 @@ name = "Disguised Syringe Gun" desc = "A syringe gun disguised as an electronic cigarette with 4 darts included in the box. Chemicals not included!" item_cost = 10 - path = /obj/item/storage/box/syndie_kit/syringegun + path = /obj/item/box/syndie_kit/syringegun diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm index 8ebe6d9daf3b..26ed3c2e370c 100644 --- a/code/datums/uplink/uplink_items.dm +++ b/code/datums/uplink/uplink_items.dm @@ -1,11 +1,10 @@ -var/datum/uplink/uplink = new() - -/datum/uplink +/decl/uplink var/list/items_assoc var/list/datum/uplink_item/items var/list/datum/uplink_category/categories -/datum/uplink/New() +/decl/uplink/Initialize() + . = ..() items_assoc = list() items = init_subtypes(/datum/uplink_item) categories = init_subtypes(/datum/uplink_category) @@ -30,9 +29,13 @@ var/datum/uplink/uplink = new() var/name var/desc var/item_cost = 0 - var/list/antag_costs = list() // Allows specific antag roles to purchase at a different cost - var/datum/uplink_category/category // Item category - var/list/datum/antagonist/antag_roles = list("Exclude", MODE_DEITY) // Antag roles this item is displayed to. If empty, display to all. If it includes 'Exclude", anybody except this role can view it + /// Allows specific antag roles to purchase at a different cost + var/list/antag_costs = list() + var/datum/uplink_category/category + /// Antag roles this item is displayed to. If empty, display to all. + var/list/decl/special_role/antag_roles + /// Antag roles this item will not be displayed to. If empty, display to all. + var/list/decl/special_role/exclude_antag_roles /datum/uplink_item/item var/path = null @@ -68,26 +71,31 @@ var/datum/uplink/uplink = new() /datum/uplink_item/proc/can_view(obj/item/uplink/U) // Making the assumption that if no uplink was supplied, then we don't care about antag roles - if(!U || !antag_roles.len) + if(!U || !length(antag_roles)) return 1 // With no owner, there's no need to check antag status. if(!U.uplink_owner) return 0 - for(var/antag_role in antag_roles) - if(antag_role == "Exclude") - continue - var/datum/antagonist/antag = GLOB.all_antag_types_[antag_role] - if(antag.is_antagonist(U.uplink_owner)) - return !("Exclude" in antag_roles) - return ("Exclude" in antag_roles) + if(LAZYLEN(exclude_antag_roles)) + for(var/antag_role in exclude_antag_roles) + var/decl/special_role/antag = GET_DECL(antag_role) + if(antag.is_antagonist(U.uplink_owner)) + return FALSE + if(LAZYLEN(antag_roles)) + for(var/antag_role in antag_roles) + var/decl/special_role/antag = GET_DECL(antag_role) + if(antag.is_antagonist(U.uplink_owner)) + return TRUE + return FALSE + return TRUE /datum/uplink_item/proc/cost(var/telecrystals, obj/item/uplink/U) . = item_cost if(U && U.uplink_owner) for(var/antag_role in antag_costs) - var/datum/antagonist/antag = GLOB.all_antag_types_[antag_role] + var/decl/special_role/antag = GET_DECL(antag_role) if(antag.is_antagonist(U.uplink_owner)) . = min(antag_costs[antag_role], .) return max(1, U ? U.get_item_cost(src, .) : .) @@ -111,7 +119,7 @@ var/datum/uplink/uplink = new() if(user) uplink_purchase_repository.add_entry(user.mind, src, cost) -datum/uplink_item/dd_SortValue() +/datum/uplink_item/dd_SortValue() return cost(INFINITY, null) /******************************** @@ -129,8 +137,8 @@ datum/uplink_item/dd_SortValue() if(L.len) I = L[1] if(istype(I) && ishuman(user)) - var/mob/living/carbon/human/A = user - A.put_in_any_hand_if_possible(I) + var/mob/living/human/A = user + A.put_in_hands(I) return I /datum/uplink_item/item/get_goods(var/obj/item/uplink/U, var/loc) @@ -146,7 +154,7 @@ datum/uplink_item/dd_SortValue() /datum/uplink_item/item/log_icon() var/obj/I = path - return "\icon[I]" + return html_icon(I) /**************** * Support procs * diff --git a/code/datums/uplink/uplink_sources.dm b/code/datums/uplink/uplink_sources.dm index b815885c92c0..69fe364a6c1d 100644 --- a/code/datums/uplink/uplink_sources.dm +++ b/code/datums/uplink/uplink_sources.dm @@ -1,11 +1,12 @@ -#define NO_GUARANTEE_NO_EXTRA_COST_DESC(X) "Installs an uplink into " + X + " if, and only if, found on your person. Has no TC cost." +#define NO_GUARANTEE_NO_EXTRA_COST_DESC(X) "Installs an uplink into [X] if, and only if, found on your person. Has no TC cost." #define SETUP_FAILED TRUE -GLOBAL_LIST_INIT(default_uplink_source_priority, list( +var/global/list/default_uplink_source_priority = list( /decl/uplink_source/pda, /decl/uplink_source/radio, - /decl/uplink_source/unit)) + /decl/uplink_source/unit +) /decl/uplink_source var/name @@ -16,71 +17,67 @@ GLOBAL_LIST_INIT(default_uplink_source_priority, list( /decl/uplink_source/pda name = "PDA" + +/decl/uplink_source/pda/Initialize() desc = NO_GUARANTEE_NO_EXTRA_COST_DESC("a PDA") + . = ..() /decl/uplink_source/pda/setup_uplink_source(var/mob/M, var/amount) + var/obj/item/modular_computer/pda/P = find_in_mob(M, /obj/item/modular_computer/pda) + if(!P) + return SETUP_FAILED + var/datum/extension/assembly/assembly = get_extension(P, /datum/extension/assembly) + if(!assembly) + return SETUP_FAILED + var/obj/item/stock_parts/computer/hard_drive/HDD = assembly.get_component(PART_HDD) - if(!P || !HDD) + if(!HDD) return SETUP_FAILED - var/pda_pass = "[rand(100,999)] [pick(GLOB.greek_letters)]" + var/pda_pass = "[rand(100,999)] [pick(global.greek_letters)]" var/obj/item/uplink/T = new(P, M.mind, amount) P.hidden_uplink = T var/datum/computer_file/program/uplink/program = new(pda_pass) - if(!HDD.try_store_file(program)) - HDD.remove_file(HDD.find_file_by_name(program.filename)) //Maybe it already has a fake copy. - if(!HDD.try_store_file(program)) + var/datum/computer_file/directory/program_dir = HDD.parse_directory(OS_PROGRAMS_DIR, TRUE) // This is almost certainly already created, but just in case. + if(HDD.store_file(program, program_dir, TRUE, overwrite = TRUE) != OS_FILE_SUCCESS) return SETUP_FAILED //Not enough space or other issues. - HDD.store_file(program) to_chat(M, "A portable object teleportation relay has been installed in your [P.name]. Simply enter the code \"[pda_pass]\" in TaxQuickly program to unlock its hidden features.") M.StoreMemory("Uplink passcode: [pda_pass] ([P.name]).", /decl/memory_options/system) /decl/uplink_source/radio name = "Radio" + +/decl/uplink_source/radio/Initialize() desc = NO_GUARANTEE_NO_EXTRA_COST_DESC("a radio") + . = ..() /decl/uplink_source/radio/setup_uplink_source(var/mob/M, var/amount) - var/obj/item/radio/R = find_in_mob(M, /obj/item/radio) - if(!R) + var/obj/item/radio/radio = find_in_mob(M, /obj/item/radio) + if(!radio) return SETUP_FAILED - var/freq = PUBLIC_LOW_FREQ - var/list/freqlist = list() - while (freq <= PUBLIC_HIGH_FREQ) - if (freq < 1451 || freq > PUB_FREQ) - freqlist += freq - freq += 2 - if ((freq % 2) == 0) - freq += 1 - - freq = freqlist[rand(1, freqlist.len)] - var/obj/item/uplink/T = new(R, M.mind, amount) - R.hidden_uplink = T - R.traitor_frequency = freq - to_chat(M, "A portable object teleportation relay has been installed in your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") - M.StoreMemory("Radio Freq: [format_frequency(freq)] ([R.name]).", /decl/memory_options/system) + var/obj/item/uplink/T = new(radio, M.mind, amount) + radio.hidden_uplink = T + radio.traitor_frequency = sanitize_frequency(rand(PUBLIC_LOW_FREQ+1, PUB_FREQ-1)) + to_chat(M, "A portable object teleportation relay has been installed in your [radio.name]. Simply dial the frequency [format_frequency(radio.traitor_frequency)] to unlock its hidden features.") + M.StoreMemory("Radio Freq: [format_frequency(radio.traitor_frequency)] ([radio.name]).", /decl/memory_options/system) /decl/uplink_source/implant name = "Implant" desc = "Teleports an uplink implant into your head. Costs 20% of the initial TC amount." -/decl/uplink_source/implant/setup_uplink_source(var/mob/living/carbon/human/H, var/amount) - if(!istype(H)) +/decl/uplink_source/implant/setup_uplink_source(var/mob/living/human/recipient, var/amount) + if(!istype(recipient)) return SETUP_FAILED - var/obj/item/organ/external/head = H.organs_by_name[BP_HEAD] + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(recipient, BP_HEAD) if(!head) return SETUP_FAILED - var/obj/item/implant/uplink/U = new(H, round(amount * 0.8)) - U.imp_in = H - U.implanted = TRUE - U.part = head - head.implants += U - - U.implanted(H) // This proc handles the installation feedback + var/obj/item/implant/uplink/uplink_implant = new(recipient, round(amount * 0.8)) + uplink_implant.implant_in_mob(recipient, recipient, head) /decl/uplink_source/unit name = "Uplink Unit" @@ -125,14 +122,14 @@ GLOBAL_LIST_INIT(default_uplink_source_priority, list( if(M.client && M.client.prefs) priority_order = M.client.prefs.uplink_sources - if(!priority_order || !priority_order.len) + if(!LAZYLEN(priority_order)) priority_order = list() - for(var/entry in GLOB.default_uplink_source_priority) - priority_order += decls_repository.get_decl(entry) + for(var/entry in global.default_uplink_source_priority) + priority_order |= GET_DECL(entry) for(var/entry in priority_order) - var/decl/uplink_source/US = entry - if(US.setup_uplink_source(M, amount) != SETUP_FAILED) + var/decl/uplink_source/uplink = entry + if(uplink.setup_uplink_source(M, amount) != SETUP_FAILED) return TRUE to_chat(M, "Either by choice or circumstance you will be without an uplink.") diff --git a/code/datums/vending/stored_item.dm b/code/datums/vending/stored_item.dm index 9a5d60920d1f..3246f711603d 100644 --- a/code/datums/vending/stored_item.dm +++ b/code/datums/vending/stored_item.dm @@ -5,18 +5,17 @@ var/list/instances //What items are actually stored var/atom/storing_object -/datum/stored_items/New(var/atom/storing_object, var/path, var/name = null, var/amount = 0) +/datum/stored_items/New(atom/_storing_object, _path, _name, _amount = 0) + if(_storing_object) + storing_object = _storing_object if(!istype(storing_object)) - CRASH("Unexpected storing object.") - src.storing_object = storing_object - src.item_path = path - src.amount = amount - - if(!name) - var/atom/tmp = path - src.item_name = initial(tmp.name) - else - src.item_name = name + CRASH("Unexpected storing object: [storing_object]") + if(_path) + item_path = _path + if(!ispath(item_path)) + CRASH("Unexpected item path: [item_path || "NULL"]") + item_name = _name || atom_info_repository.get_name_for(item_path) + amount = _amount ..() /datum/stored_items/Destroy() @@ -52,7 +51,8 @@ product = new item_path(storing_object) amount-- - product.forceMove(product_location) + if(!QDELETED(product)) // Some spawners will qdel after vending. + product.forceMove(product_location) return product /datum/stored_items/proc/get_specific_product(var/product_location, var/atom/movable/product) @@ -80,4 +80,16 @@ /datum/stored_items/proc/migrate(atom/new_storing_obj) storing_object = new_storing_obj for(var/atom/movable/thing in instances) - thing.forceMove(new_storing_obj) \ No newline at end of file + thing.forceMove(new_storing_obj) + +/datum/stored_items/proc/get_combined_matter(include_instances = TRUE, include_reagents = TRUE) + var/virtual_amount = amount - length(instances) + if(virtual_amount) + . = atom_info_repository.get_matter_for(item_path)?.Copy() + for(var/key in .) + .[key] *= virtual_amount + else + . = list() + if(include_instances) + for(var/atom/instance in instances) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., instance.get_contained_matter(include_reagents)) \ No newline at end of file diff --git a/code/datums/vending/vending.dm b/code/datums/vending/vending.dm index f000eaac3f1d..d92e8d483e13 100644 --- a/code/datums/vending/vending.dm +++ b/code/datums/vending/vending.dm @@ -6,13 +6,11 @@ */ /datum/stored_items/vending_products - item_name = "generic" // Display name for the product - var/price = 0 // Price to buy one - var/display_color = null // Display color for vending machine listing - var/category = CAT_NORMAL // CAT_HIDDEN for contraband - -/datum/stored_items/vending_products/New(var/atom/storing_object, var/path, var/name = null, var/amount = 0, var/price = 0, var/color = null, var/category = CAT_NORMAL) - ..() - src.price = price - src.display_color = color - src.category = category + /// Display name for the product + item_name = "generic" + /// Price to buy one + var/price = 0 + /// Display color for vending machine listing + var/display_color = null + // CAT_HIDDEN for contraband + var/category = CAT_NORMAL diff --git a/code/datums/vote/add_antag.dm b/code/datums/vote/add_antag.dm index 97d9e083db18..f9b82057ce20 100644 --- a/code/datums/vote/add_antag.dm +++ b/code/datums/vote/add_antag.dm @@ -9,11 +9,11 @@ return FALSE /datum/vote/add_antagonist/setup_vote(mob/creator, automatic) - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] - if(!(antag.id in additional_antag_types) && antag.is_votable()) - choices += antag.role_text + var/decl/special_role/antag = all_antag_types[antag_type] + if(!(antag.type in global.additional_antag_types) && antag.is_votable()) + choices += antag.name choices += "Random" if(!automatic) choices += "None" @@ -33,23 +33,32 @@ if(GAME_STATE <= RUNLEVEL_LOBBY) antag_add_finished = 1 - var/antag_type = GLOB.antag_names_to_ids_[result[1]] - if(!antag_type) + var/antag_name = lowertext(result[1]) + if(!antag_name) return 1 - additional_antag_types |= antag_type - return + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) + for(var/antag_type in all_antag_types) + var/decl/special_role/antag = all_antag_types[antag_type] + if(lowertext(antag.name) == antag_name) + global.additional_antag_types |= antag_type + return - INVOKE_ASYNC(src, .proc/spawn_antags) //There is a sleep in this proc. + INVOKE_ASYNC(src, PROC_REF(spawn_antags)) //There is a sleep in this proc. /datum/vote/add_antagonist/proc/spawn_antags() + var/list/antag_choices = list() - for(var/antag_type in result) - antag_choices += GLOB.all_antag_types_[antag_type] + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) + for(var/antag_type in all_antag_types) + var/decl/special_role/antag = all_antag_types[antag_type] + if(lowertext(antag.name) in result) + antag_choices |= all_antag_types[antag_type] + if(SSticker.attempt_late_antag_spawn(antag_choices)) // This takes a while. antag_add_finished = 1 if(automatic) // the buffer will already have half an hour added to it, so we'll give it one more - transfer_controller.timerbuffer += config.vote_autotransfer_interval + transfer_controller.timerbuffer += get_config_value(/decl/config/num/vote_autotransfer_initial) else to_world("No antags were added.") if(automatic) diff --git a/code/datums/vote/custom.dm b/code/datums/vote/custom.dm index b783c749dea0..ba32ded269ee 100644 --- a/code/datums/vote/custom.dm +++ b/code/datums/vote/custom.dm @@ -12,7 +12,7 @@ return ..() /datum/vote/custom/setup_vote(mob/creator, automatic) - question = sanitizeSafe(input(creator,"What is the vote for?") as text|null) + question = sanitize_safe(input(creator,"What is the vote for?") as text|null) if(!question) abort = 1 return diff --git a/code/datums/vote/gamemode.dm b/code/datums/vote/gamemode.dm index 113c91a46d3a..8df1d2e4fe20 100644 --- a/code/datums/vote/gamemode.dm +++ b/code/datums/vote/gamemode.dm @@ -1,12 +1,11 @@ /datum/vote/gamemode name = "game mode" - additional_header = "Minimum Players" + additional_header = "Minimum Players" win_x = 500 win_y = 1100 - show_leading = TRUE /datum/vote/gamemode/can_run(mob/creator, automatic) - if(!automatic && (!config.allow_vote_mode || !is_admin(creator))) + if(!automatic && (!get_config_value(/decl/config/toggle/vote_mode) || !is_admin(creator))) return FALSE // Admins and autovotes bypass the config setting. if(GAME_STATE >= RUNLEVEL_GAME) return FALSE @@ -20,9 +19,9 @@ /datum/vote/gamemode/setup_vote(mob/creator, automatic) ..() - choices += config.votable_modes + choices += get_config_value(/decl/config/lists/mode_votable) for (var/F in choices) - var/datum/game_mode/M = gamemode_cache[F] + var/decl/game_mode/M = decls_repository.get_decl_by_id(F, validate_decl_type = FALSE) if(!M) continue display_choices[F] = capitalize(M.name) @@ -37,7 +36,7 @@ /datum/vote/gamemode/report_result() if(!SSticker.round_progressing) //Unpause any holds. If the vote failed, SSticker is responsible for fielding the result. SSticker.round_progressing = 1 - to_world("The round will start soon.") + to_world(SPAN_RED("The round will start soon.")) if(..()) SSticker.gamemode_vote_results = list() //This signals to SSticker that the vote is over but there were no winners. return 1 @@ -50,8 +49,8 @@ SSticker.gamemode_vote_results = result.Copy() /datum/vote/gamemode/check_toggle() - return config.allow_vote_mode ? "Allowed" : "Disallowed" + return get_config_value(/decl/config/toggle/vote_mode) ? "Allowed" : "Disallowed" /datum/vote/gamemode/toggle(mob/user) if(is_admin(user)) - config.allow_vote_mode = !config.allow_vote_mode \ No newline at end of file + toggle_config_value(/decl/config/toggle/vote_mode) diff --git a/code/datums/vote/map.dm b/code/datums/vote/map.dm index a7548e31dab4..aabfdde28459 100644 --- a/code/datums/vote/map.dm +++ b/code/datums/vote/map.dm @@ -2,21 +2,21 @@ name = "map" /datum/vote/map/can_run(mob/creator, automatic) - if(!config.allow_map_switching) + if(!get_config_value(/decl/config/toggle/allow_map_switching)) return FALSE if(!automatic && !is_admin(creator)) return FALSE // Must be an admin. return ..() /datum/vote/map/setup_vote() - for(var/name in GLOB.all_maps) + for(var/name in global.votable_maps) choices += name ..() /datum/vote/map/report_result() if(..()) return 1 - var/datum/map/M = GLOB.all_maps[result[1]] + var/datum/map/M = global.votable_maps[result[1]] fdel("use_map") text2file(M.path, "use_map") diff --git a/code/datums/vote/restart.dm b/code/datums/vote/restart.dm index a3e49a04fbbd..75a564d6d591 100644 --- a/code/datums/vote/restart.dm +++ b/code/datums/vote/restart.dm @@ -6,7 +6,7 @@ results_length = 1 /datum/vote/restart/can_run(mob/creator, automatic) - if(!automatic && !config.allow_vote_restart && !is_admin(creator)) + if(!automatic && !get_config_value(/decl/config/toggle/vote_restart) && !is_admin(creator)) return FALSE // Admins and autovotes bypass the config setting. return ..() diff --git a/code/datums/vote/transfer.dm b/code/datums/vote/transfer.dm index c4d04ecc7c90..b009162dcc42 100644 --- a/code/datums/vote/transfer.dm +++ b/code/datums/vote/transfer.dm @@ -7,26 +7,24 @@ return if(!SSevac.evacuation_controller || !SSevac.evacuation_controller.should_call_autotransfer_vote()) return FALSE - if(!automatic && !config.allow_vote_restart && !is_admin(creator)) + if(!automatic && !get_config_value(/decl/config/toggle/vote_restart) && !is_admin(creator)) return FALSE // Admins and autovotes bypass the config setting. if(check_rights(R_INVESTIGATE, 0, creator)) return //Mods bypass further checks. - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) if (!automatic && security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level)) - to_chat(creator, "The current alert status is too high to call for a crew transfer!") return FALSE if(GAME_STATE <= RUNLEVEL_SETUP) - to_chat(creator, "The crew transfer button has been disabled!") return FALSE /datum/vote/transfer/setup_vote(mob/creator, automatic) - choices = list("Initiate Crew Transfer", "Extend the Round ([config.vote_autotransfer_interval / 600] minutes)") - if (config.allow_extra_antags && SSvote.is_addantag_allowed(creator, automatic)) + choices = list("Initiate Crew Transfer", "Extend the Round ([get_config_value(/decl/config/num/vote_autotransfer_interval) / 600] minutes)") + if (get_config_value(/decl/config/toggle/allow_extra_antags) && SSvote.is_addantag_allowed(creator, automatic)) choices += "Add Antagonist" ..() /datum/vote/transfer/handle_default_votes() - if(config.vote_no_default) + if(get_config_value(/decl/config/num/vote_no_default)) return var/factor = 0.5 switch(world.time / (1 MINUTE)) @@ -41,7 +39,7 @@ else factor = 1.4 choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor) - to_world("Crew Transfer Factor: [factor]") + to_world(SPAN_PURPLE("Crew Transfer Factor: [factor]")) /datum/vote/transfer/report_result() if(..()) @@ -54,12 +52,12 @@ /datum/vote/transfer/mob_not_participating(mob/user) if((. = ..())) return - if(config.vote_no_dead_crew_transfer) - return !isliving(user) || ismouse(user) || is_drone(user) + if(get_config_value(/decl/config/num/vote_no_dead_crew_transfer)) + return !isliving(user) || ismouse(user) || isdrone(user) /datum/vote/transfer/check_toggle() - return config.allow_vote_restart ? "Allowed" : "Disallowed" + return get_config_value(/decl/config/toggle/vote_restart) ? "Allowed" : "Disallowed" /datum/vote/transfer/toggle(mob/user) if(is_admin(user)) - config.allow_vote_restart = !config.allow_vote_restart \ No newline at end of file + toggle_config_value(/decl/config/toggle/vote_restart) \ No newline at end of file diff --git a/code/datums/vote/vote.dm b/code/datums/vote/vote.dm index 6f7f718633c9..18cff66756af 100644 --- a/code/datums/vote/vote.dm +++ b/code/datums/vote/vote.dm @@ -22,10 +22,11 @@ var/win_x = 450 var/win_y = 740 // Vote window size. - var/show_leading = 0 // Colours leading choice based on votes count. var/manual_allowed = 1 // Whether humans can start it. - var/percent_votes = TRUE // Total votes in current choose. If FALSE - shows total num of voted people for this choose. - var/show_votes_count = TRUE // Show total votes for something. Staff with R_INVESTIGATE can bypass this. + + var/list/vote_start_sounds = list( + 'sound/ambience/alarm4.ogg' + ) //Expected to be run immediately after creation; a false return means that the vote could not be run and the datum will be deleted. /datum/vote/proc/setup(mob/creator, automatic) @@ -51,23 +52,23 @@ /datum/vote/proc/start_vote() start_time = world.time - time_set = (time_set ? time_set : config.vote_period) + time_set = (time_set ? time_set : get_config_value(/decl/config/num/vote_period)) time_remaining = round(time_set / 10) status = VOTE_STATUS_ACTIVE var/text = get_start_text() log_vote(text) - to_world("[text]\nType vote or click here to place your votes.\nYou have [time_set/10] seconds to vote.") - to_world(sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = GLOB.vote_sound_channel)) + to_world(SPAN_PURPLE("[text]\nType vote or click here to place your votes.\nYou have [round(time_set/10)] seconds to vote.")) + to_world(sound(pick(vote_start_sounds), repeat = 0, wait = 0, volume = 50, channel = sound_channels.vote_channel)) /datum/vote/proc/get_start_text() return "[capitalize(name)] vote started by [initiator]." //Modifies the vote totals based on non-voting mobs. /datum/vote/proc/handle_default_votes() - if(!config.vote_no_default) - return length(GLOB.clients) - length(voted) //Number of non-voters (might not be active, though; should be revisited if the config option is used. This is legacy code.) + if(!get_config_value(/decl/config/num/vote_no_default)) + return length(global.clients) - length(voted) //Number of non-voters (might not be active, though; should be revisited if the config option is used. This is legacy code.) /datum/vote/proc/tally_result() handle_default_votes() @@ -84,7 +85,7 @@ var/text = get_result_announcement() log_vote(text) - to_world("[text]") + to_world(SPAN_PURPLE("[text]")) if(!(result[result[1]] > 0)) return 1 @@ -94,11 +95,11 @@ if(!(result[result[1]] > 0)) // No one voted. text += "Vote Result: Inconclusive - No Votes!" else - text += "Vote Result: [display_choices[result[1]]][choices[result[1]] >= 1 ? " - \"[choices[result[1]]]\"" : null]" + text += "Vote Result: [display_choices[result[1]]]" if(length(result) >= 2 && result[result[2]]) - text += "\nSecond place: [display_choices[result[2]]][choices[result[2]] >= 1 ? " - \"[choices[result[2]]]\"" : null]" + text += "\nSecond place: [display_choices[result[2]]]" if(length(result) >= 3 && result[result[3]]) - text += "\nThird place: [display_choices[result[3]]][choices[result[3]] >= 1 ? " - \"[choices[result[3]]]\"" : null]" + text += "\nThird place: [display_choices[result[3]]]" return JOINTEXT(text) @@ -128,7 +129,7 @@ // Checks if the mob is participating in the round sufficiently to vote, as per config settings. /datum/vote/proc/mob_not_participating(mob/voter) - if(config.vote_no_dead && voter.stat == DEAD && !voter.client.holder) + if(get_config_value(/decl/config/num/vote_no_dead) && voter.stat == DEAD && !voter.client.holder) return 1 //null = no toggle set. This is for UI purposes; a text return will give a link (toggle; currently "return") in the vote panel. @@ -159,9 +160,9 @@ . += "

    Vote: [capitalize(name)]

    " . += "Time Left: [time_remaining] s
    " . += "
    " - var/votes_count = show_votes_count || check_rights(R_INVESTIGATE, 0, user) ? "Votes" : null - . += "[votes_count]" + . += "
    Choices
    " . += additional_header + . += "" var/totalvotes = 0 for(var/i = 1, i <= choices.len, i++) @@ -170,34 +171,22 @@ for(var/j = 1, j <= choices.len, j++) var/choice = choices[j] var/number_of_votes = choices[choice] || 0 - var/votepercent = 0 - if(totalvotes) - votepercent = percent_votes ? "[round((number_of_votes/totalvotes)*100)]%" : number_of_votes + var/votepercent = "0%" + if(totalvotes > 0) + votepercent = "[round((number_of_votes/totalvotes)*100)]%" . += "" for(var/i = 1, i <= length(priorities), i++) . += "" - if(check_rights(R_INVESTIGATE, 0, user)) - . += "" + . += "" if (additional_text[choice]) . += "[additional_text[choice]]" //Note lack of cell wrapper, to allow for dynamic formatting. . += "" diff --git a/code/datums/weakref.dm b/code/datums/weakref.dm index 61ab8eb49815..ce8a7fa4ba63 100644 --- a/code/datums/weakref.dm +++ b/code/datums/weakref.dm @@ -14,15 +14,13 @@ return D.weakref /weakref - var/ref - - // Handy info for debugging - var/tmp/ref_name - var/tmp/ref_type + var/ref //- Actual datum ref. + var/name //- Useful for input() on lists of weakrefs. + var/tmp/ref_type //- Handy info for debugging /weakref/New(datum/D) - ref = "\ref[D]" - ref_name = "[D]" + ref = "\ref[D]" + name = "[D]" ref_type = D.type /weakref/Destroy() @@ -38,4 +36,7 @@ return null /weakref/get_log_info_line() - return "[ref_name] ([ref_type]) ([ref]) (WEAKREF)" + return "[name] ([ref_type]) ([ref]) (WEAKREF)" + +/weakref/CanClone() + return FALSE //Pass weakref as references since they're unique per atom instance \ No newline at end of file diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index b94856396cf8..951e79f60e84 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -25,27 +25,27 @@ new /datum/wire_description(AIRLOCK_WIRE_SPEAKER, "This wire connects to the door speaker.") ) -var/const/AIRLOCK_WIRE_IDSCAN = 1 -var/const/AIRLOCK_WIRE_MAIN_POWER1 = 2 -var/const/AIRLOCK_WIRE_MAIN_POWER2 = 4 -var/const/AIRLOCK_WIRE_DOOR_BOLTS = 8 -var/const/AIRLOCK_WIRE_BACKUP_POWER1 = 16 -var/const/AIRLOCK_WIRE_BACKUP_POWER2 = 32 -var/const/AIRLOCK_WIRE_OPEN_DOOR = 64 -var/const/AIRLOCK_WIRE_AI_CONTROL = 128 -var/const/AIRLOCK_WIRE_ELECTRIFY = 256 -var/const/AIRLOCK_WIRE_SAFETY = 512 -var/const/AIRLOCK_WIRE_SPEED = 1024 -var/const/AIRLOCK_WIRE_LIGHT = 2048 -var/const/AIRLOCK_WIRE_SPEAKER = 4096 +var/global/const/AIRLOCK_WIRE_IDSCAN = 1 +var/global/const/AIRLOCK_WIRE_MAIN_POWER1 = 2 +var/global/const/AIRLOCK_WIRE_MAIN_POWER2 = 4 +var/global/const/AIRLOCK_WIRE_DOOR_BOLTS = 8 +var/global/const/AIRLOCK_WIRE_BACKUP_POWER1 = 16 +var/global/const/AIRLOCK_WIRE_BACKUP_POWER2 = 32 +var/global/const/AIRLOCK_WIRE_OPEN_DOOR = 64 +var/global/const/AIRLOCK_WIRE_AI_CONTROL = 128 +var/global/const/AIRLOCK_WIRE_ELECTRIFY = 256 +var/global/const/AIRLOCK_WIRE_SAFETY = 512 +var/global/const/AIRLOCK_WIRE_SPEED = 1024 +var/global/const/AIRLOCK_WIRE_LIGHT = 2048 +var/global/const/AIRLOCK_WIRE_SPEAKER = 4096 /datum/wires/airlock/CanUse(var/mob/living/L) var/obj/machinery/door/airlock/A = holder - if(!istype(L, /mob/living/silicon)) + if(!issilicon(L)) if(A.isElectrified()) if(A.shock(L, 100)) return 0 - if(A.panel_open) + if(istype(A.construct_state, /decl/machine_construction/default/panel_closed/door/hacking)) return 1 return 0 @@ -136,6 +136,14 @@ var/const/AIRLOCK_WIRE_SPEAKER = 4096 if(AIRLOCK_WIRE_SPEAKER) A.speaker = mended +/datum/wires/airlock/proc/reset_ai_control(var/obj/machinery/door/airlock/A) + if(!istype(A) || holder != A) + return + if(A.aiControlDisabled == 1) + A.aiControlDisabled = 0 + else if(A.aiControlDisabled == 2) + A.aiControlDisabled = -1 + /datum/wires/airlock/UpdatePulsed(var/index) var/obj/machinery/door/airlock/A = holder switch(index) @@ -162,13 +170,7 @@ var/const/AIRLOCK_WIRE_SPEAKER = 4096 A.aiControlDisabled = 1 else if(A.aiControlDisabled == -1) A.aiControlDisabled = 2 - - spawn(10) - if(A) - if(A.aiControlDisabled == 1) - A.aiControlDisabled = 0 - else if(A.aiControlDisabled == 2) - A.aiControlDisabled = -1 + addtimer(CALLBACK(src, PROC_REF(reset_ai_control), A), 1 SECOND) if(AIRLOCK_WIRE_ELECTRIFY) //one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds. diff --git a/code/datums/wires/alarm.dm b/code/datums/wires/alarm.dm index c037c583a464..ddcce1fc75e9 100644 --- a/code/datums/wires/alarm.dm +++ b/code/datums/wires/alarm.dm @@ -9,11 +9,11 @@ new /datum/wire_description(AALARM_WIRE_AALARM, "This wire gives power to the actual alarm mechanism.") ) -var/const/AALARM_WIRE_IDSCAN = 1 -var/const/AALARM_WIRE_POWER = 2 -var/const/AALARM_WIRE_SYPHON = 4 -var/const/AALARM_WIRE_AI_CONTROL = 8 -var/const/AALARM_WIRE_AALARM = 16 +var/global/const/AALARM_WIRE_IDSCAN = 1 +var/global/const/AALARM_WIRE_POWER = 2 +var/global/const/AALARM_WIRE_SYPHON = 4 +var/global/const/AALARM_WIRE_AI_CONTROL = 8 +var/global/const/AALARM_WIRE_AALARM = 16 /datum/wires/alarm/CanUse(var/mob/living/L) @@ -61,40 +61,38 @@ var/const/AALARM_WIRE_AALARM = 16 A.post_alert(2) A.update_icon() +/datum/wires/alarm/proc/clear_shorted() + var/obj/machinery/alarm/A = holder + if(!istype(A)) + return + if(A.shorted == 1) + A.shorted = 0 + A.update_icon() + +/datum/wires/alarm/proc/clear_ai_disabled() + var/obj/machinery/alarm/A = holder + if(!istype(A)) + return + /datum/wires/alarm/UpdatePulsed(var/index) var/obj/machinery/alarm/A = holder switch(index) if(AALARM_WIRE_IDSCAN) A.locked = !A.locked -// log_debug("Idscan wire pulsed") - if (AALARM_WIRE_POWER) -// log_debug("Power wire pulsed") - if(A.shorted == 0) A.shorted = 1 A.update_icon() - - spawn(12000) - if(A.shorted == 1) - A.shorted = 0 - A.update_icon() - + addtimer(CALLBACK(src, PROC_REF(clear_shorted)), 20 MINUTES) if (AALARM_WIRE_AI_CONTROL) -// log_debug("AI Control wire pulsed") - if (A.aidisabled == 0) A.aidisabled = 1 A.updateDialog() - spawn(100) - if (A.aidisabled == 1) - A.aidisabled = 0 + addtimer(CALLBACK(src, PROC_REF(clear_ai_disabled), 10 SECONDS)) if(AALARM_WIRE_SYPHON) -// log_debug("Syphon wire pulsed") - if(A.mode == 1) // AALARM_MODE_SCRUB A.mode = 3 // AALARM_MODE_PANIC else diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm deleted file mode 100644 index d7e14e1b75a2..000000000000 --- a/code/datums/wires/apc.dm +++ /dev/null @@ -1,78 +0,0 @@ -#define APC_WIRE_IDSCAN 1 -#define APC_WIRE_MAIN_POWER1 2 -#define APC_WIRE_MAIN_POWER2 4 -#define APC_WIRE_AI_CONTROL 8 - -/datum/wires/apc - holder_type = /obj/machinery/power/apc - wire_count = 4 - descriptions = list( - new /datum/wire_description(APC_WIRE_IDSCAN, "This wire is connected to the ID scanning panel.", SKILL_EXPERT), - new /datum/wire_description(APC_WIRE_MAIN_POWER1, "This wire seems to be carrying a heavy current."), - new /datum/wire_description(APC_WIRE_MAIN_POWER2, "This wire seems to be carrying a heavy current."), - new /datum/wire_description(APC_WIRE_AI_CONTROL, "This wire connects to automated control systems.") - ) - -/datum/wires/apc/GetInteractWindow(mob/user) - var/obj/machinery/power/apc/A = holder - . += ..() - . += text("
    \n[(A.locked ? "The APC is locked." : "The APC is unlocked.")]
    \n[(A.shorted ? "The APCs power has been shorted." : "The APC is working properly!")]
    \n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]") - - -/datum/wires/apc/CanUse(var/mob/living/L) - var/obj/machinery/power/apc/A = holder - if(istype(A.construct_state, /decl/machine_construction/wall_frame/panel_closed/hackable/hacking) && !(A.stat & BROKEN)) - return 1 - return 0 - -/datum/wires/apc/UpdatePulsed(var/index) - - var/obj/machinery/power/apc/A = holder - - switch(index) - - if(APC_WIRE_IDSCAN) - A.locked = 0 - - spawn(300) - if(A) - A.locked = 1 - - if (APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2) - if(A.shorted == 0) - A.shorted = 1 - - spawn(1200) - if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2)) - A.shorted = 0 - - if (APC_WIRE_AI_CONTROL) - if (A.aidisabled == 0) - A.aidisabled = 1 - - spawn(10) - if(A && !IsIndexCut(APC_WIRE_AI_CONTROL)) - A.aidisabled = 0 - -/datum/wires/apc/UpdateCut(var/index, var/mended) - var/obj/machinery/power/apc/A = holder - - switch(index) - if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2) - - if(!mended) - A.shock(usr, 50) - A.shorted = 1 - - else if(!IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2)) - A.shorted = 0 - A.shock(usr, 50) - - if(APC_WIRE_AI_CONTROL) - - if(!mended) - if (A.aidisabled == 0) - A.aidisabled = 1 - else - if (A.aidisabled == 1) - A.aidisabled = 0 \ No newline at end of file diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm index 9cda34d10722..c1e09d292805 100644 --- a/code/datums/wires/camera.dm +++ b/code/datums/wires/camera.dm @@ -15,8 +15,9 @@ . = ..() var/obj/machinery/camera/C = holder - . += "
    \n[(C.view_range == initial(C.view_range) ? "The focus light is on." : "The focus light is off.")]" - . += "
    \n[(C.can_use() ? "The power link light is on." : "The power link light is off.")]" + var/datum/extension/network_device/camera/D = get_extension(holder, /datum/extension/network_device/) + . += "
    \n[(D.view_range == C.long_range ? "The focus light is on." : "The focus light is off.")]" + . += "
    \n[(C.cut_power ? "The power link light is off." : "The power link light is on.")]" . += "
    \n[(C.light_disabled ? "The camera light is off." : "The camera light is on.")]" . += "
    \n[(C.alarm_on ? "The alarm light is on." : "The alarm light is off.")]" return . @@ -25,24 +26,23 @@ var/obj/machinery/camera/C = holder return C.panel_open -var/const/CAMERA_WIRE_FOCUS = 1 -var/const/CAMERA_WIRE_POWER = 2 -var/const/CAMERA_WIRE_LIGHT = 4 -var/const/CAMERA_WIRE_ALARM = 8 -var/const/CAMERA_WIRE_NOTHING1 = 16 -var/const/CAMERA_WIRE_NOTHING2 = 32 +var/global/const/CAMERA_WIRE_FOCUS = 1 +var/global/const/CAMERA_WIRE_POWER = 2 +var/global/const/CAMERA_WIRE_LIGHT = 4 +var/global/const/CAMERA_WIRE_ALARM = 8 /datum/wires/camera/UpdateCut(var/index, var/mended) var/obj/machinery/camera/C = holder switch(index) if(CAMERA_WIRE_FOCUS) - var/range = (mended ? initial(C.view_range) : C.short_range) - C.setViewRange(range) + var/datum/extension/network_device/camera/D = get_extension(holder, /datum/extension/network_device) + var/new_range = (mended ? C.long_range : C.short_range) + D.set_view_range(new_range) if(CAMERA_WIRE_POWER) - if(C.status && !mended || !C.status && mended) - C.deactivate(usr, 1) + C.cut_power = !mended + C.set_camera_status(mended, usr) if(CAMERA_WIRE_LIGHT) C.light_disabled = !mended @@ -60,18 +60,13 @@ var/const/CAMERA_WIRE_NOTHING2 = 32 return switch(index) if(CAMERA_WIRE_FOCUS) - var/new_range = (C.view_range == initial(C.view_range) ? C.short_range : initial(C.view_range)) - C.setViewRange(new_range) + var/datum/extension/network_device/camera/D = get_extension(holder, /datum/extension/network_device) + var/new_range = (D.view_range == C.long_range ? C.short_range : C.long_range) + D.set_view_range(new_range) if(CAMERA_WIRE_LIGHT) C.light_disabled = !C.light_disabled if(CAMERA_WIRE_ALARM) - C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") - return - -/datum/wires/camera/proc/CanDeconstruct() - if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS) && IsIndexCut(CAMERA_WIRE_LIGHT) && IsIndexCut(CAMERA_WIRE_NOTHING1) && IsIndexCut(CAMERA_WIRE_NOTHING2)) - return 1 - else - return 0 \ No newline at end of file + C.visible_message("[html_icon(C)] *beep*", "[html_icon(C)] *beep*") + return \ No newline at end of file diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm index 97e2c8dd6f4a..45d6384c5572 100644 --- a/code/datums/wires/explosive.dm +++ b/code/datums/wires/explosive.dm @@ -1,7 +1,7 @@ /datum/wires/explosive wire_count = 1 -var/const/WIRE_EXPLODE = 1 +var/global/const/WIRE_EXPLODE = 1 /datum/wires/explosive/proc/explode() return diff --git a/code/datums/wires/fabricator.dm b/code/datums/wires/fabricator.dm index 835349bbdcb8..a9a040f6feea 100644 --- a/code/datums/wires/fabricator.dm +++ b/code/datums/wires/fabricator.dm @@ -44,6 +44,12 @@ else A.fab_status_flags |= FAB_DISABLED +/datum/wires/fabricator/proc/reset_flag(var/index, var/flag) + var/obj/machinery/fabricator/A = holder + if(A && !IsIndexCut(index) && flag) + A.fab_status_flags &= ~flag + Interact(usr) + /datum/wires/fabricator/UpdatePulsed(index) if(IsIndexCut(index)) return @@ -54,28 +60,21 @@ A.fab_status_flags &= ~FAB_HACKED else A.fab_status_flags |= FAB_HACKED - spawn(50) - if(A && !IsIndexCut(index)) - A.fab_status_flags &= ~FAB_HACKED - Interact(usr) + addtimer(CALLBACK(src, PROC_REF(reset_flag), index, FAB_HACKED), 5 SECONDS) + if(AUTOLATHE_SHOCK_WIRE) if(A.fab_status_flags & FAB_SHOCKED) A.fab_status_flags &= ~FAB_SHOCKED else A.fab_status_flags |= FAB_SHOCKED - spawn(50) - if(A && !IsIndexCut(index)) - A.fab_status_flags &= ~FAB_SHOCKED - Interact(usr) + addtimer(CALLBACK(src, PROC_REF(reset_flag), index, FAB_SHOCKED), 5 SECONDS) + if(AUTOLATHE_DISABLE_WIRE) if(A.fab_status_flags & FAB_DISABLED) A.fab_status_flags &= ~FAB_DISABLED else A.fab_status_flags |= FAB_DISABLED - spawn(50) - if(A && !IsIndexCut(index)) - A.fab_status_flags &= ~FAB_DISABLED - Interact(usr) + addtimer(CALLBACK(src, PROC_REF(reset_flag), index, FAB_DISABLED), 5 SECONDS) #undef AUTOLATHE_HACK_WIRE #undef AUTOLATHE_SHOCK_WIRE diff --git a/code/datums/wires/inertial_damper.dm b/code/datums/wires/inertial_damper.dm deleted file mode 100644 index 3bff1ed2efaa..000000000000 --- a/code/datums/wires/inertial_damper.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/wires/inertial_damper - holder_type = /obj/machinery/inertial_damper - wire_count = 5 - descriptions = list( - new /datum/wire_description(DAMPER_WIRE_POWER, "This wire seems to be carrying a heavy current.", SKILL_EXPERT), - new /datum/wire_description(DAMPER_WIRE_HACK, "This wire seems designed to adjust the data output cache."), - new /datum/wire_description(DAMPER_WIRE_CONTROL, "This wire connects to the main control panel."), - new /datum/wire_description(DAMPER_WIRE_AICONTROL, "This wire connects to automated control systems.") - ) - -var/const/DAMPER_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore. -var/const/DAMPER_WIRE_HACK = 2 // Pulse to hack the dampener, causing false display on engine consoles. Cut to unhack. Mend does nothing. -var/const/DAMPER_WIRE_CONTROL = 4 // Cut to lock controls. Mend to unlock them. Pulse does nothing. -var/const/DAMPER_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore. -var/const/DAMPER_WIRE_NOTHING = 16 // A blank wire that doesn't have any specific function - -/datum/wires/inertial_damper/CanUse() - var/obj/machinery/inertial_damper/I = holder - if(I.panel_open) - return TRUE - return FALSE - -/datum/wires/inertial_damper/UpdateCut(index, mended) - var/obj/machinery/inertial_damper/I = holder - switch(index) - if(DAMPER_WIRE_POWER) - I.input_cut = !mended - if(DAMPER_WIRE_HACK) - if(!mended) - I.hacked = FALSE - if(DAMPER_WIRE_CONTROL) - I.locked = !mended - if(DAMPER_WIRE_AICONTROL) - I.ai_control_disabled = !mended - -/datum/wires/inertial_damper/UpdatePulsed(var/index) - var/obj/machinery/inertial_damper/I = holder - switch(index) - if(DAMPER_WIRE_HACK) - I.hacked = TRUE \ No newline at end of file diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm index 9bc772480672..c984ebbcb773 100644 --- a/code/datums/wires/nuclearbomb.dm +++ b/code/datums/wires/nuclearbomb.dm @@ -8,9 +8,9 @@ new /datum/wire_description(NUCLEARBOMB_WIRE_SAFETY, "This wire connects to a safety override.") ) -var/const/NUCLEARBOMB_WIRE_LIGHT = 1 -var/const/NUCLEARBOMB_WIRE_TIMING = 2 -var/const/NUCLEARBOMB_WIRE_SAFETY = 4 +var/global/const/NUCLEARBOMB_WIRE_LIGHT = 1 +var/global/const/NUCLEARBOMB_WIRE_TIMING = 2 +var/global/const/NUCLEARBOMB_WIRE_SAFETY = 4 /datum/wires/nuclearbomb/CanUse(var/mob/living/L) var/obj/machinery/nuclearbomb/N = holder @@ -20,32 +20,47 @@ var/const/NUCLEARBOMB_WIRE_SAFETY = 4 var/obj/machinery/nuclearbomb/N = holder . += ..() . += "
    The device is [N.timing ? "shaking!" : "still."]
    " - . += "The device is is [N.safety ? "quiet" : "whirring"].
    " + . += "The device is [N.safety ? "quiet" : "whirring"].
    " . += "The lights are [N.lighthack ? "static" : "functional"].
    " +/datum/wires/nuclearbomb/proc/toggle_hacked() + var/obj/machinery/nuclearbomb/N = holder + if(N) + N.lighthack = !N.lighthack + N.update_icon() + +/datum/wires/nuclearbomb/proc/toggle_safety() + var/obj/machinery/nuclearbomb/N = holder + if(N) + N.safety = !N.safety + if(N.safety == 1) + N.visible_message(SPAN_NOTICE("\The [N] quiets down.")) + N.secure_device() + else + N.visible_message(SPAN_NOTICE("\The [N] emits a quiet whirling noise!")) + +/datum/wires/nuclearbomb/proc/log_and_explode(var/msg) + set waitfor = FALSE + var/obj/machinery/nuclearbomb/N = holder + if(N) + log_and_message_admins(msg) + N.explode() + /datum/wires/nuclearbomb/UpdatePulsed(var/index) var/obj/machinery/nuclearbomb/N = holder switch(index) if(NUCLEARBOMB_WIRE_LIGHT) N.lighthack = !N.lighthack N.update_icon() - spawn(100) - N.lighthack = !N.lighthack - N.update_icon() + toggle_hacked() + addtimer(CALLBACK(src, PROC_REF(toggle_hacked)), 10 SECONDS) + if(NUCLEARBOMB_WIRE_TIMING) if(N.timing) - spawn - log_and_message_admins("pulsed a nuclear bomb's detonation wire, causing it to explode.") - N.explode() + log_and_explode("pulsed a nuclear bomb's detonation wire, causing it to explode.") if(NUCLEARBOMB_WIRE_SAFETY) N.safety = !N.safety - spawn(100) - N.safety = !N.safety - if(N.safety == 1) - N.visible_message("\The [N] quiets down.") - N.secure_device() - else - N.visible_message("\The [N] emits a quiet whirling noise!") + addtimer(CALLBACK(src, PROC_REF(toggle_safety)), 10 SECONDS) /datum/wires/nuclearbomb/UpdateCut(var/index, var/mended) var/obj/machinery/nuclearbomb/N = holder @@ -53,11 +68,9 @@ var/const/NUCLEARBOMB_WIRE_SAFETY = 4 if(NUCLEARBOMB_WIRE_SAFETY) N.safety = mended if(N.timing) - spawn - log_and_message_admins("cut a nuclear bomb's timing wire, causing it to explode.") - N.explode() + log_and_explode("cut a nuclear bomb's timing wire, causing it to explode.") if(NUCLEARBOMB_WIRE_TIMING) N.secure_device() if(NUCLEARBOMB_WIRE_LIGHT) N.lighthack = !mended - N.update_icon() \ No newline at end of file + N.update_icon() diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm index 7542b0ebe74d..342efb57fd48 100644 --- a/code/datums/wires/particle_accelerator.dm +++ b/code/datums/wires/particle_accelerator.dm @@ -8,10 +8,10 @@ new /datum/wire_description(PARTICLE_LIMIT_POWER_WIRE, "This wire connects to the primary magnets.") ) -var/const/PARTICLE_TOGGLE_WIRE = 1 // Toggles whether the PA is on or not. -var/const/PARTICLE_STRENGTH_WIRE = 2 // Determines the strength of the PA. -var/const/PARTICLE_INTERFACE_WIRE = 4 // Determines the interface showing up. -var/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be. +var/global/const/PARTICLE_TOGGLE_WIRE = 1 // Toggles whether the PA is on or not. +var/global/const/PARTICLE_STRENGTH_WIRE = 2 // Determines the strength of the PA. +var/global/const/PARTICLE_INTERFACE_WIRE = 4 // Determines the interface showing up. +var/global/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be. //var/const/PARTICLE_NOTHING_WIRE = 16 // Blank wire /datum/wires/particle_acc/control_box/CanUse(var/mob/living/L) @@ -34,7 +34,7 @@ var/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be. C.interface_control = !C.interface_control if(PARTICLE_LIMIT_POWER_WIRE) - C.visible_message("\icon[C][C] makes a large whirring noise.") + C.visible_message("[html_icon(C)][C] makes a large whirring noise.") /datum/wires/particle_acc/control_box/UpdateCut(var/index, var/mended) var/obj/machinery/particle_accelerator/control_box/C = holder diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm index 0d569d0f9498..5de478c9dd76 100644 --- a/code/datums/wires/radio.dm +++ b/code/datums/wires/radio.dm @@ -3,50 +3,44 @@ wire_count = 3 descriptions = list( new /datum/wire_description(WIRE_SIGNAL, "This wire connects several radio components."), - new /datum/wire_description(WIRE_RECEIVE, "This wire runs to the radio reciever.", SKILL_EXPERT), + new /datum/wire_description(WIRE_RECEIVE, "This wire runs to the radio receiver.", SKILL_EXPERT), new /datum/wire_description(WIRE_TRANSMIT, "This wire runs to the radio transmitter.") ) -var/const/WIRE_SIGNAL = 1 -var/const/WIRE_RECEIVE = 2 -var/const/WIRE_TRANSMIT = 4 +var/global/const/WIRE_SIGNAL = 1 +var/global/const/WIRE_RECEIVE = 2 +var/global/const/WIRE_TRANSMIT = 4 /datum/wires/radio/CanUse(var/mob/living/L) - var/obj/item/radio/R = holder - if(R.b_stat) + var/obj/item/radio/radio = holder + if(radio.panel_open) return 1 return 0 -/datum/wires/radio/GetInteractWindow(mob/user) - var/obj/item/radio/R = holder - . += ..() - if(R.cell) - . += "
    Remove cell
    " - /datum/wires/radio/UpdatePulsed(var/index) - var/obj/item/radio/R = holder + var/obj/item/radio/radio = holder switch(index) if(WIRE_SIGNAL) - R.listening = !R.listening && !IsIndexCut(WIRE_RECEIVE) - R.broadcasting = R.listening && !IsIndexCut(WIRE_TRANSMIT) + radio.listening = !radio.listening && !IsIndexCut(WIRE_RECEIVE) + radio.broadcasting = radio.listening && !IsIndexCut(WIRE_TRANSMIT) if(WIRE_RECEIVE) - R.listening = !R.listening && !IsIndexCut(WIRE_SIGNAL) + radio.listening = !radio.listening && !IsIndexCut(WIRE_SIGNAL) if(WIRE_TRANSMIT) - R.broadcasting = !R.broadcasting && !IsIndexCut(WIRE_SIGNAL) + radio.broadcasting = !radio.broadcasting && !IsIndexCut(WIRE_SIGNAL) SSnano.update_uis(holder) /datum/wires/radio/UpdateCut(var/index, var/mended) - var/obj/item/radio/R = holder + var/obj/item/radio/radio = holder switch(index) if(WIRE_SIGNAL) - R.listening = mended && !IsIndexCut(WIRE_RECEIVE) - R.broadcasting = mended && !IsIndexCut(WIRE_TRANSMIT) + radio.listening = mended && !IsIndexCut(WIRE_RECEIVE) + radio.broadcasting = mended && !IsIndexCut(WIRE_TRANSMIT) if(WIRE_RECEIVE) - R.listening = mended && !IsIndexCut(WIRE_SIGNAL) + radio.listening = mended && !IsIndexCut(WIRE_SIGNAL) if(WIRE_TRANSMIT) - R.broadcasting = mended && !IsIndexCut(WIRE_SIGNAL) + radio.broadcasting = mended && !IsIndexCut(WIRE_SIGNAL) SSnano.update_uis(holder) \ No newline at end of file diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index f19afd03c17c..2a5576b5fb9e 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -10,68 +10,68 @@ new /datum/wire_description(BORG_WIRE_CAMERA, "This wire runs to the unit's vision modules.") ) -var/const/BORG_WIRE_LAWCHECK = 1 -var/const/BORG_WIRE_MAIN_POWER = 2 // The power wires do nothing whyyyyyyyyyyyyy -var/const/BORG_WIRE_LOCKED_DOWN = 4 -var/const/BORG_WIRE_AI_CONTROL = 8 -var/const/BORG_WIRE_CAMERA = 16 +var/global/const/BORG_WIRE_LAWCHECK = 1 +var/global/const/BORG_WIRE_MAIN_POWER = 2 // The power wires do nothing whyyyyyyyyyyyyy +var/global/const/BORG_WIRE_LOCKED_DOWN = 4 +var/global/const/BORG_WIRE_AI_CONTROL = 8 +var/global/const/BORG_WIRE_CAMERA = 16 /datum/wires/robot/GetInteractWindow(mob/user) . = ..() - var/mob/living/silicon/robot/R = holder - . += text("
    \n[(R.lawupdate ? "The LawSync light is on." : "The LawSync light is off.")]") - . += text("
    \n[(R.connected_ai ? "The AI link light is on." : "The AI link light is off.")]") - . += text("
    \n[((!isnull(R.camera) && R.camera.status == 1) ? "The Camera light is on." : "The Camera light is off.")]") - . += text("
    \n[(R.lockcharge ? "The lockdown light is on." : "The lockdown light is off.")]") + var/mob/living/silicon/robot/robot = holder + var/datum/extension/network_device/camera/D = get_extension(holder, /datum/extension/network_device/) + + . += text("
    \n[(robot.lawupdate ? "The LawSync light is on." : "The LawSync light is off.")]") + . += text("
    \n[(robot.connected_ai ? "The AI link light is on." : "The AI link light is off.")]") + . += text("
    \n[(D.is_functional() ? "The Camera light is on." : "The Camera light is off.")]") + . += text("
    \n[(robot.lockcharge ? "The lockdown light is on." : "The lockdown light is off.")]") return . /datum/wires/robot/UpdateCut(var/index, var/mended) - var/mob/living/silicon/robot/R = holder + var/mob/living/silicon/robot/robot = holder switch(index) if(BORG_WIRE_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI if(!mended) - if (R.lawupdate == 1) - to_chat(R, "LawSync protocol engaged.") - R.show_laws() + if (robot.lawupdate == 1) + to_chat(robot, "LawSync protocol engaged.") + robot.show_laws() else - if (R.lawupdate == 0 && !R.emagged) - R.lawupdate = 1 + if (robot.lawupdate == 0 && !robot.emagged) + robot.lawupdate = 1 if (BORG_WIRE_AI_CONTROL) //Cut the AI wire to reset AI control if(!mended) - R.disconnect_from_ai() + robot.disconnect_from_ai() if (BORG_WIRE_CAMERA) - if(!isnull(R.camera) && !R.scrambledcodes) - R.camera.status = mended + cameranet.update_visibility(src, FALSE) if(BORG_WIRE_LOCKED_DOWN) - R.SetLockdown(!mended) + robot.SetLockdown(!mended) /datum/wires/robot/UpdatePulsed(var/index) - var/mob/living/silicon/robot/R = holder + var/mob/living/silicon/robot/robot = holder switch(index) if (BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI - if(!R.emagged) - var/mob/living/silicon/ai/new_ai = select_active_ai(R, get_z(R)) - R.connect_to_ai(new_ai) + if(!robot.emagged) + var/mob/living/silicon/ai/new_ai = select_active_ai(robot, get_z(robot)) + robot.connect_to_ai(new_ai) if (BORG_WIRE_CAMERA) - if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes) - R.visible_message("[R]'s camera lense focuses loudly.") - to_chat(R, "Your camera lense focuses loudly.") + var/datum/extension/network_device/camera/robot/D = get_extension(src, /datum/extension/network_device) + if(D && D.is_functional()) + robot.visible_message("[robot]'s camera lens focuses loudly.") + to_chat(robot, "Your camera lense focuses loudly.") if(BORG_WIRE_LOCKED_DOWN) - R.SetLockdown(!R.lockcharge) // Toggle + robot.SetLockdown(!robot.lockcharge) // Toggle /datum/wires/robot/CanUse(var/mob/living/L) - var/mob/living/silicon/robot/R = holder - if(R.wiresexposed) - return 1 - return 0 + var/mob/living/silicon/robot/robot = holder + return robot.wiresexposed /datum/wires/robot/proc/IsCameraCut() return wires_status & BORG_WIRE_CAMERA diff --git a/code/datums/wires/shield_generator.dm b/code/datums/wires/shield_generator.dm index 91671690258e..026fbf368200 100644 --- a/code/datums/wires/shield_generator.dm +++ b/code/datums/wires/shield_generator.dm @@ -1,5 +1,5 @@ /datum/wires/shield_generator - holder_type = /obj/machinery/power/shield_generator/ + holder_type = /obj/machinery/shield_generator/ wire_count = 5 descriptions = list( new /datum/wire_description(SHIELDGEN_WIRE_POWER, "This wire seems to be carrying a heavy current.", SKILL_EXPERT), @@ -8,20 +8,19 @@ new /datum/wire_description(SHIELDGEN_WIRE_AICONTROL, "This wire connects to automated control systems.") ) -var/const/SHIELDGEN_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore. -var/const/SHIELDGEN_WIRE_HACK = 2 // Pulse to hack the generator, enabling hacked modes. Cut to unhack. Mend does nothing. -var/const/SHIELDGEN_WIRE_CONTROL = 4 // Cut to lock most shield controls. Mend to unlock them. Pulse does nothing. -var/const/SHIELDGEN_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore. -var/const/SHIELDGEN_WIRE_NOTHING = 16 // A blank wire that doesn't have any specific function +var/global/const/SHIELDGEN_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore. +var/global/const/SHIELDGEN_WIRE_HACK = 2 // Pulse to hack the generator, enabling hacked modes. Cut to unhack. Mend does nothing. +var/global/const/SHIELDGEN_WIRE_CONTROL = 4 // Cut to lock most shield controls. Mend to unlock them. Pulse does nothing. +var/global/const/SHIELDGEN_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore. /datum/wires/shield_generator/CanUse() - var/obj/machinery/power/shield_generator/S = holder + var/obj/machinery/shield_generator/S = holder if(S.panel_open) return 1 return 0 /datum/wires/shield_generator/UpdateCut(index, mended) - var/obj/machinery/power/shield_generator/S = holder + var/obj/machinery/shield_generator/S = holder switch(index) if(SHIELDGEN_WIRE_POWER) S.input_cut = !mended @@ -38,7 +37,7 @@ var/const/SHIELDGEN_WIRE_NOTHING = 16 // A blank wire that doesn't have any spe S.ai_control_disabled = !mended /datum/wires/shield_generator/UpdatePulsed(var/index) - var/obj/machinery/power/shield_generator/S = holder + var/obj/machinery/shield_generator/S = holder switch(index) if(SHIELDGEN_WIRE_HACK) S.hacked = 1 \ No newline at end of file diff --git a/code/datums/wires/smartfridge.dm b/code/datums/wires/smartfridge.dm index 0928f28a89ce..86a00b1217a8 100644 --- a/code/datums/wires/smartfridge.dm +++ b/code/datums/wires/smartfridge.dm @@ -11,13 +11,13 @@ random = 1 wire_count = 4 -var/const/SMARTFRIDGE_WIRE_ELECTRIFY = 1 -var/const/SMARTFRIDGE_WIRE_THROW = 2 -var/const/SMARTFRIDGE_WIRE_IDSCAN = 4 +var/global/const/SMARTFRIDGE_WIRE_ELECTRIFY = 1 +var/global/const/SMARTFRIDGE_WIRE_THROW = 2 +var/global/const/SMARTFRIDGE_WIRE_IDSCAN = 4 /datum/wires/smartfridge/CanUse(var/mob/living/L) var/obj/machinery/smartfridge/S = holder - if(!istype(L, /mob/living/silicon)) + if(!issilicon(L)) if(S.seconds_electrified) if(S.shock(L, 100)) return 0 diff --git a/code/datums/wires/smes.dm b/code/datums/wires/smes.dm index 2faf2c78a86d..7cc90b2d664a 100644 --- a/code/datums/wires/smes.dm +++ b/code/datums/wires/smes.dm @@ -9,61 +9,68 @@ new /datum/wire_description(SMES_WIRE_FAILSAFES, "This wire appears to connect to a failsafe mechanism.") ) -var/const/SMES_WIRE_RCON = 1 // Remote control (AI and consoles), cut to disable -var/const/SMES_WIRE_INPUT = 2 // Input wire, cut to disable input, pulse to disable for 60s -var/const/SMES_WIRE_OUTPUT = 4 // Output wire, cut to disable output, pulse to disable for 60s -var/const/SMES_WIRE_GROUNDING = 8 // Cut to quickly discharge causing sparks, pulse to only create few sparks -var/const/SMES_WIRE_FAILSAFES = 16 // Cut to disable failsafes, mend to reenable - - -/datum/wires/smes/CanUse(var/mob/living/L) - var/obj/machinery/power/smes/buildable/S = holder - if(!S.grounding && S.powernet && S.powernet.avail) - electrocute_mob(L, S.powernet, S, S.safeties_enabled? 0.1 : 1) - if(S.panel_open) - return 1 - return 0 +/// Remote control (AI and consoles), cut to disable +var/global/const/SMES_WIRE_RCON = BITFLAG(0) +/// Input wire, cut to disable input, pulse to disable for 60s +var/global/const/SMES_WIRE_INPUT = BITFLAG(1) +/// Output wire, cut to disable output, pulse to disable for 60s +var/global/const/SMES_WIRE_OUTPUT = BITFLAG(2) +/// Cut to quickly discharge causing sparks, pulse to only create few sparks +var/global/const/SMES_WIRE_GROUNDING = BITFLAG(3) +/// Cut to disable failsafes, mend to reenable +var/global/const/SMES_WIRE_FAILSAFES = BITFLAG(4) +/datum/wires/smes/CanUse(var/mob/living/user) + var/obj/machinery/power/smes/buildable/storage = holder + if(!storage.grounding && storage.powernet && storage.powernet.avail) + electrocute_mob(user, storage.powernet, storage, (storage.safeties_enabled? 0.1 : 1)) + return storage.panel_open /datum/wires/smes/GetInteractWindow(mob/user) - var/obj/machinery/power/smes/buildable/S = holder + var/obj/machinery/power/smes/buildable/storage = holder . += ..() - . += "The green light is [(S.input_cut || S.input_pulsed || S.output_cut || S.output_pulsed) ? "off" : "on"]
    " - . += "The red light is [(S.safeties_enabled || S.grounding) ? "off" : "blinking"]
    " - . += "The blue light is [S.RCon ? "on" : "off"]" - + . += "The green light is [(storage.input_cut || storage.input_pulsed || storage.output_cut || storage.output_pulsed) ? "off" : "on"]
    " + . += "The red light is [(storage.safeties_enabled || storage.grounding) ? "off" : "blinking"]
    " + . += "The blue light is [storage.RCon ? "on" : "off"]" /datum/wires/smes/UpdateCut(var/index, var/mended) - var/obj/machinery/power/smes/buildable/S = holder + var/obj/machinery/power/smes/buildable/storage = holder switch(index) if(SMES_WIRE_RCON) - S.RCon = mended + storage.RCon = mended if(SMES_WIRE_INPUT) - S.input_cut = !mended + storage.input_cut = !mended if(SMES_WIRE_OUTPUT) - S.output_cut = !mended + storage.output_cut = !mended if(SMES_WIRE_GROUNDING) - S.grounding = mended + storage.grounding = mended if(SMES_WIRE_FAILSAFES) - S.safeties_enabled = mended + storage.safeties_enabled = mended + +/datum/wires/smes/proc/reset_rcon() + var/obj/machinery/power/smes/buildable/storage = holder + if(storage) + storage.RCon = TRUE +/datum/wires/smes/proc/reset_safeties() + var/obj/machinery/power/smes/buildable/storage = holder + if(storage) + storage.safeties_enabled = TRUE /datum/wires/smes/UpdatePulsed(var/index) - var/obj/machinery/power/smes/buildable/S = holder + var/obj/machinery/power/smes/buildable/storage = holder switch(index) if(SMES_WIRE_RCON) - if(S.RCon) - S.RCon = 0 - spawn(10) - S.RCon = 1 + if(storage.RCon) + storage.RCon = 0 + addtimer(CALLBACK(src, PROC_REF(reset_rcon)), 1 SECOND) if(SMES_WIRE_INPUT) - S.toggle_input() + storage.toggle_input() if(SMES_WIRE_OUTPUT) - S.toggle_output() + storage.toggle_output() if(SMES_WIRE_GROUNDING) - S.grounding = 0 + storage.grounding = 0 if(SMES_WIRE_FAILSAFES) - if(S.safeties_enabled) - S.safeties_enabled = 0 - spawn(10) - S.safeties_enabled = 1 \ No newline at end of file + if(storage.safeties_enabled) + storage.safeties_enabled = 0 + addtimer(CALLBACK(src, PROC_REF(reset_safeties)), 1 SECOND) diff --git a/code/datums/wires/suit_cycler.dm b/code/datums/wires/suit_cycler.dm index 38a912d26d78..ab98f8f934ff 100644 --- a/code/datums/wires/suit_cycler.dm +++ b/code/datums/wires/suit_cycler.dm @@ -3,17 +3,17 @@ wire_count = 3 descriptions = list( new /datum/wire_description(SUIT_STORAGE_WIRE_ELECTRIFY, "This wire seems to be carrying a heavy current."), - new /datum/wire_description(SUIT_STORAGE_WIRE_SAFETY, "This wire seems connected to a safety override", SKILL_EXPERT), + new /datum/wire_description(SUIT_STORAGE_WIRE_SAFETY, "This wire seems connected to a safety override.", SKILL_EXPERT), new /datum/wire_description(SUIT_STORAGE_WIRE_LOCKED, "This wire is connected to the ID scanning panel.") ) -var/const/SUIT_STORAGE_WIRE_ELECTRIFY = 1 -var/const/SUIT_STORAGE_WIRE_SAFETY = 2 -var/const/SUIT_STORAGE_WIRE_LOCKED = 4 +var/global/const/SUIT_STORAGE_WIRE_ELECTRIFY = 1 +var/global/const/SUIT_STORAGE_WIRE_SAFETY = 2 +var/global/const/SUIT_STORAGE_WIRE_LOCKED = 4 /datum/wires/suit_cycler/CanUse(var/mob/living/L) var/obj/machinery/suit_cycler/S = holder - if(!istype(L, /mob/living/silicon)) + if(!issilicon(L)) if(S.electrified) if(S.shock(L, 100)) return 0 diff --git a/code/datums/wires/taperecorder.dm b/code/datums/wires/taperecorder.dm deleted file mode 100644 index b72ecb0b2341..000000000000 --- a/code/datums/wires/taperecorder.dm +++ /dev/null @@ -1,16 +0,0 @@ -/datum/wires/taperecorder - holder_type = /obj/item/taperecorder - wire_count = 1 - descriptions = list( - new /datum/wire_description(TAPE_WIRE_TOGGLE, "This wire runs to the play/stop toggle.", SKILL_ADEPT) - ) - -var/const/TAPE_WIRE_TOGGLE = 1 - -/datum/wires/taperecorder/UpdatePulsed(var/index) - var/obj/item/taperecorder/T = holder - if(T.recording || T.playing) - T.stop() - else - T.play() - SSnano.update_uis(holder) \ No newline at end of file diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm index 7949b27db273..9af6ae5230a6 100644 --- a/code/datums/wires/vending.dm +++ b/code/datums/wires/vending.dm @@ -8,14 +8,14 @@ new /datum/wire_description(VENDING_WIRE_IDSCAN, "This wire is connected to the ID scanning panel.", SKILL_EXPERT) ) -var/const/VENDING_WIRE_THROW = 1 -var/const/VENDING_WIRE_CONTRABAND = 2 -var/const/VENDING_WIRE_ELECTRIFY = 4 -var/const/VENDING_WIRE_IDSCAN = 8 +var/global/const/VENDING_WIRE_THROW = 1 +var/global/const/VENDING_WIRE_CONTRABAND = 2 +var/global/const/VENDING_WIRE_ELECTRIFY = 4 +var/global/const/VENDING_WIRE_IDSCAN = 8 /datum/wires/vending/CanUse(var/mob/living/L) var/obj/machinery/vending/V = holder - if(!istype(L, /mob/living/silicon)) + if(!issilicon(L)) if(V.seconds_electrified) if(V.shock(L, 100)) return 0 diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index b9597354d162..5d2b817165d4 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -1,8 +1,9 @@ #define MAX_FLAG 65535 -var/list/same_wires = list() +var/global/list/same_wires = list() // 14 colours, if you're adding more than 14 wires then add more colours here -var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink", "black", "yellow") +var/global/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink", "black", "yellow") +var/global/list/wireColourNames = list("darkred" = "dark red") /datum/wires var/random = 0 // Will the wires be different for every single instance. @@ -56,7 +57,7 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" var/list/colours_to_pick = wireColours.Copy() // Get a copy, not a reference. var/list/indexes_to_pick = list() //Generate our indexes - for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + for(var/i = 1; i < MAX_FLAG && i < BITFLAG(wire_count); i += i) indexes_to_pick += i colours_to_pick.len = wire_count // Downsize it to our specifications. @@ -71,7 +72,8 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" //wires = shuffle(wires) /datum/wires/proc/Interact(var/mob/living/user) - + if(!user) + return var/html = null if(holder && CanUse(user)) html = GetInteractWindow(user) @@ -85,7 +87,6 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" var/datum/browser/popup = new(user, "wires", holder.name, window_x, window_y) popup.set_content(html) - popup.set_title_image(user.browse_rsc_icon(holder.icon, holder.icon_state)) popup.open() return TRUE @@ -101,14 +102,20 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" if(!user.skill_check(SKILL_ELECTRICAL, SKILL_BASIC)) wires_used = shuffle(wires_used) + var/list/replace_colours = user?.get_visual_colour_substitutions() || list() for(var/colour in wires_used) + + var/colour_name = replace_colours[colour] || colour + if(colour_name in wireColourNames) + colour_name = wireColourNames[colour_name] + html += "" - html += "[capitalize(colour)]" + html += "[capitalize(colour_name)]" html += "" - html += "[IsColourCut(colour) ? "Mend" : "Cut"]" - html += " Pulse" - html += " [IsAttached(colour) ? "Detach" : "Attach"] Signaller" - html += " Examine" + html += "[IsColourCut(colour) ? "Mend" : "Cut"]" + html += " Pulse" + html += " [IsAttached(colour) ? "Detach" : "Attach"] Signaller" + html += " Examine" html += "
    ChoicesYour VoteVotes
    " - - if(show_leading && number_of_votes > 0) - if(number_of_votes >= 15) - . += "[display_choices[choice]]" - else if(number_of_votes >= 10) - . += "[display_choices[choice]]" - else if(number_of_votes >= 5) - . += "[display_choices[choice]]" - else if(number_of_votes >= 1) - . += "[display_choices[choice]]" - else - . += "[display_choices[choice]]" + . += "[display_choices[choice]]" . += "" if(voted[user.ckey] && (voted[user.ckey][i] == j)) //We have this jth choice chosen at priority i. - . += "[priorities[i]]" + . += "[priorities[i]]" else - . += "[priorities[i]]" + . += "[priorities[i]]" . += "[votepercent][votepercent]
    " html += "
    " @@ -124,16 +131,12 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" var/mob/living/L = usr if(CanUse(L) && href_list["action"]) - var/obj/item/I = L.get_active_hand() - - var/obj/item/offhand_item - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - offhand_item = H.wearing_rig && H.wearing_rig.selected_module + var/obj/item/I = L.get_active_held_item() + var/obj/item/offhand_item = usr?.get_rig()?.selected_module holder.add_hiddenprint(L) if(href_list["cut"]) // Toggles the cut/mend status - if(isWirecutter(I) || isWirecutter(offhand_item)) + if(IS_WIRECUTTER(I) || IS_WIRECUTTER(offhand_item)) var/colour = href_list["cut"] CutWireColour(colour) if(prob(L.skill_fail_chance(SKILL_ELECTRICAL, 20, SKILL_ADEPT))) @@ -145,7 +148,7 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" else to_chat(L, "You need wirecutters!") else if(href_list["pulse"]) - if(isMultitool(I) || isMultitool(offhand_item)) + if(IS_MULTITOOL(I) || IS_MULTITOOL(offhand_item)) var/colour = href_list["pulse"] if(prob(L.skill_fail_chance(SKILL_ELECTRICAL, 30, SKILL_ADEPT))) RandomPulse() @@ -173,13 +176,13 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" // Attach else if(istype(I, /obj/item/assembly/signaler)) - if(L.unEquip(I)) + if(L.try_unequip(I)) Attach(colour, I) else to_chat(L, "You need a remote signaller!") else if(href_list["examine"]) var/colour = href_list["examine"] - to_chat(usr, examine(GetIndex(colour), usr)) + to_chat(usr, examine_wire(GetIndex(colour), usr)) // Update Window Interact(usr) @@ -189,7 +192,7 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" usr.unset_machine(holder) // -// Overridable Procs +// Overrideable Procs // // Called when wires cut/mended. @@ -200,7 +203,7 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" /datum/wires/proc/UpdatePulsed(var/index) return -/datum/wires/proc/examine(index, mob/user) +/datum/wires/proc/examine_wire(index, mob/user) . = "You aren't sure what this wire does." var/datum/wire_description/wd = get_description(index) @@ -216,10 +219,10 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" // Example of use: /* -var/const/BOLTED= 1 -var/const/SHOCKED = 2 -var/const/SAFETY = 4 -var/const/POWER = 8 +var/global/const/BOLTED= 1 +var/global/const/SHOCKED = 2 +var/global/const/SAFETY = 4 +var/global/const/POWER = 8 /datum/wires/door/UpdateCut(var/index, var/mended) var/obj/machinery/door/airlock/A = holder @@ -337,21 +340,21 @@ var/const/POWER = 8 CutWireColour(wires[r]) /datum/wires/proc/RandomCutAll(var/probability = 10) - for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + for(var/i = 1; i < MAX_FLAG && i < BITFLAG(wire_count); i += i) if(prob(probability)) CutWireIndex(i) /datum/wires/proc/CutAll() - for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + for(var/i = 1; i < MAX_FLAG && i < BITFLAG(wire_count); i += i) CutWireIndex(i) /datum/wires/proc/IsAllCut() - if(wires_status == (1 << wire_count) - 1) + if(wires_status == BITFLAG(wire_count) - 1) return 1 return 0 /datum/wires/proc/MendAll() - for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i) + for(var/i = 1; i < MAX_FLAG && i < BITFLAG(wire_count); i += i) if(IsIndexCut(i)) CutWireIndex(i) diff --git a/code/game/alpha_masks.dm b/code/game/alpha_masks.dm new file mode 100644 index 000000000000..3eb68a3b3435 --- /dev/null +++ b/code/game/alpha_masks.dm @@ -0,0 +1,87 @@ +var/global/list/_alpha_masks = list() +/proc/get_or_create_alpha_mask(atom/movable/owner) + if(!global._alpha_masks[owner]) + var/atom/movable/alpha_mask/mask = new + mask.set_owner(owner) + global._alpha_masks[owner] = mask + return mask + return global._alpha_masks[owner] + +// Dummy overlay used to follow mobs around, separate from their icon generation for rendering purposes. +/atom/movable/alpha_mask + name = "" + simulated = FALSE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + default_pixel_x = -16 + default_pixel_y = -16 + var/atom/movable/owner + +// Set our appearance state to avoid showing up in right-click. +/atom/movable/alpha_mask/Initialize() + . = ..() + verbs.Cut() + name = "" + appearance_flags &= ~KEEP_TOGETHER + appearance_flags |= KEEP_APART | RESET_TRANSFORM + +/atom/movable/alpha_mask/Destroy() + if(owner) + global._alpha_masks -= owner + events_repository.unregister(/decl/observ/moved, owner, src) + events_repository.unregister(/decl/observ/destroyed, owner, src) + owner = null + return ..() + +// Update events to keep track of owner. +/atom/movable/alpha_mask/proc/set_owner(atom/movable/new_owner) + if(owner) + events_repository.unregister(/decl/observ/moved, owner, src) + events_repository.unregister(/decl/observ/destroyed, owner, src) + owner = new_owner + if(owner) + events_repository.register(/decl/observ/moved, owner, src, TYPE_PROC_REF(/atom/movable/alpha_mask, follow_owner)) + events_repository.register(/decl/observ/destroyed, owner, src, TYPE_PROC_REF(/datum, qdel_self)) + follow_owner() + +// Callback proc to move the overlay onto the correct turf. +/atom/movable/alpha_mask/proc/follow_owner() + if(!owner) + qdel(src) + return + forceMove(get_turf(owner.loc)) + +// Override proc to change the overlays used by an atom type. +/atom/movable/proc/get_turf_alpha_mask_states() + return 'icons/effects/alpha_mask.dmi' + +/atom/movable/proc/should_have_alpha_mask() + // Mobs and obj both need to avoid this when on structures. Looks wonky. + return simulated && isturf(loc) && !(locate(/obj/structure) in loc) + +// Proc called by /turf/Entered() to update a mob's mask overlay. +/atom/movable/proc/update_turf_alpha_mask() + set waitfor = FALSE + if(!simulated || QDELETED(src) || updating_turf_alpha_mask) + return + updating_turf_alpha_mask = TRUE + sleep(0) + updating_turf_alpha_mask = FALSE + if(QDELETED(src)) + return + var/turf/our_turf = loc + var/mask_state = isturf(our_turf) && should_have_alpha_mask() && our_turf.get_movable_alpha_mask_state(src) + if(mask_state) + var/atom/movable/alpha_mask/mask = get_or_create_alpha_mask(src) + if(mask) + var/mask_icon_file = get_turf_alpha_mask_states() || 'icons/effects/alpha_mask.dmi' + mask.render_target = "*render_\ref[src]" + if(mask.icon != mask_icon_file) + mask.icon = mask_icon_file + if(mask.icon_state != mask_state) + mask.icon_state = mask_state + if(add_filter("turf_alpha_mask", 1, list(type = "alpha", render_source = mask.render_target, flags = MASK_INVERSE)) && !(appearance_flags & KEEP_TOGETHER)) + update_appearance_flags(add_flags = KEEP_TOGETHER) + else + update_appearance_flags(remove_flags = KEEP_TOGETHER) + else if(length(filters) && remove_filter("turf_alpha_mask") && (appearance_flags & KEEP_TOGETHER)) + update_appearance_flags(remove_flags = KEEP_TOGETHER) diff --git a/code/game/antagonist/_antagonist_setup.dm b/code/game/antagonist/_antagonist_setup.dm index d165365f6c44..5b6d83d7d3d3 100644 --- a/code/game/antagonist/_antagonist_setup.dm +++ b/code/game/antagonist/_antagonist_setup.dm @@ -1,39 +1,29 @@ /* MODULAR ANTAGONIST SYSTEM - Attempts to centralize antag tracking code into its own system, which has the added bonus of making + Attempts to centralize antag tracking code into its own system, which has the added bonus of making the display procs consistent. Should be fairly self-explanatory with a review of the procs. To use: - - Get the appropriate datum via get_antag_data("antagonist id") - using the id var of the desired /datum/antagonist ie. var/datum/antagonist/A = get_antag_data("traitor") + - Get the appropriate datum via the decls repository ie. + var/decl/special_role/A = GET_DECL(/decl/special_role/the_guy) - Call add_antagonist() on the desired target mind ie. A.add_antagonist(mob.mind) - To ignore protected roles, supply a positive second argument. - To skip equipping with appropriate gear, supply a positive third argument. */ // Global procs. -/proc/get_antag_data(var/antag_type) - if(GLOB.all_antag_types_[antag_type]) - return GLOB.all_antag_types_[antag_type] - else - var/list/all_antag_types = GLOB.all_antag_types_ - for(var/cur_antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[cur_antag_type] - if(antag && antag.is_type(antag_type)) - return antag - /proc/clear_antag_roles(var/datum/mind/player, var/implanted) - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + var/decl/special_role/antag = all_antag_types[antag_type] if(!implanted || !(antag.flags & ANTAG_IMPLANT_IMMUNE)) antag.remove_antagonist(player, 1, implanted) /proc/update_antag_icons(var/datum/mind/player) - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + var/decl/special_role/antag = all_antag_types[antag_type] if(player) antag.update_icons_removed(player) if(antag.is_antagonist(player)) @@ -41,16 +31,10 @@ else antag.update_all_icons() -/proc/get_antags(var/atype) - var/datum/antagonist/antag = GLOB.all_antag_types_[atype] - if(antag && islist(antag.current_antagonists)) - return antag.current_antagonists - return list() - /proc/player_is_antag(var/datum/mind/player, var/only_offstation_roles = 0) - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + var/decl/special_role/antag = all_antag_types[antag_type] if(only_offstation_roles && !(antag.flags & ANTAG_OVERRIDE_JOB)) continue if(player in antag.current_antagonists) @@ -58,7 +42,3 @@ if(player in antag.pending_antagonists) return antag return 0 - -GLOBAL_LIST_EMPTY(all_antag_types_) -GLOBAL_LIST_EMPTY(all_antag_spawnpoints_) -GLOBAL_LIST_EMPTY(antag_names_to_ids_) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index 47caf6dcacc5..130f060c8591 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -1,31 +1,30 @@ -/datum/antagonist +/decl/special_role + abstract_type = /decl/special_role // Text shown when becoming this antagonist. - var/list/restricted_jobs = list() // Jobs that cannot be this antagonist at roundstart (depending on config) - var/list/protected_jobs = list() // As above. - var/list/blacklisted_jobs = list(/datum/job/submap) // Jobs that can NEVER be this antagonist + var/list/restricted_jobs = list() // Jobs that cannot be this antagonist at roundstart (depending on config) + var/list/protected_jobs = list() // As above. + var/list/blocked_job_event_categories // Job event categories that blacklist a job from being this antagonist. + // Jobs that can NEVER be this antagonist + var/list/blacklisted_jobs = (/datum/job/submap) // Strings. var/welcome_text = "Cry havoc and let slip the dogs of war!" var/leader_welcome_text // Text shown to the leader, if any. - var/victory_text // World output at roundend for victory. - var/loss_text // As above for loss. - var/victory_feedback_tag // Used by the database for end of round loss. - var/loss_feedback_tag // Used by the database for end of round loss. // Role data. - var/id = "traitor" // Unique datum identifier. Also preferences option for this role. - var/role_text = "Traitor" // special_role text. - var/role_text_plural = "Traitors" // As above but plural. + var/name // special_role text (ex. "Traitor"). + var/name_plural // As above but plural. // Visual references. var/antaghud_indicator = "hudsyndicate" // Used by the ghost antagHUD. var/antag_indicator // icon_state for icons/mob/mob.dm visual indicator. + var/antag_hud_icon = 'icons/screen/hud_antag.dmi' var/faction_indicator // See antag_indicator, but for factionalized people only. var/faction_invisible // Can members of the faction identify other antagonists? // Faction data. - var/faction_role_text // Role for sub-antags. Mandatory for faction role. + var/faction_name // Role for sub-antags. Mandatory for faction role. var/faction_descriptor // Description of the cause. Mandatory for faction role. var/faction_verb // Verb added when becoming a member of the faction, if any. var/faction_welcome // Message shown to faction members. @@ -44,16 +43,15 @@ // Misc. var/landmark_id // Spawn point identifier. - var/mob_path = /mob/living/carbon/human // Mobtype this antag will use if none is provided. - var/feedback_tag = "traitor_objective" // End of round + var/mob_path = /mob/living/human // Mobtype this antag will use if none is provided. var/minimum_player_age = 7 // Players need to be at least minimum_player_age days old before they are eligable for auto-spawning - var/suspicion_chance = 50 // Prob of being on the initial Command report var/flags = 0 // Various runtime options. var/show_objectives_on_creation = 1 // Whether or not objectives are shown when a player is added to this antag datum var/datum/antag_skill_setter/skill_setter = /datum/antag_skill_setter/generic // Used to set up skills. var/decl/language/required_language // Used for setting appearance. + /// Species that are valid when changing appearance while spawning as this role. Null allows all species. var/list/valid_species var/min_player_age = 14 @@ -71,7 +69,10 @@ // ID card stuff. var/default_access = list() - var/id_type = /obj/item/card/id + var/id_title + var/rig_type + + var/default_outfit var/antag_text = "You are an antagonist! Within the rules, \ try to act as an opposing force to the crew. Further RP and try to make sure \ @@ -79,106 +80,145 @@ and before taking extreme actions, please try to also contact the administration! \ Think through your actions and make the roleplay immersive! Please remember all \ rules aside from those without explicit exceptions apply to antagonists." - - // Map template that antag needs to load before spawning. Nulled after it's loaded. - var/datum/map_template/base_to_load - -/datum/antagonist/New() - GLOB.all_antag_types_[id] = src - GLOB.all_antag_spawnpoints_[landmark_id] = list() - GLOB.antag_names_to_ids_[role_text] = id + + // Map template name that antag needs to load before spawning. Nulled after it's loaded. + var/base_to_load + +/decl/special_role/Initialize() + . = ..() + if(!name) + PRINT_STACK_TRACE("Special role [type] created without name set.") if(ispath(skill_setter)) skill_setter = new skill_setter - ..() - -/datum/antagonist/proc/Initialize() cur_max = hard_cap get_starting_locations() - if(!role_text_plural) - role_text_plural = role_text - if(config.protect_roles_from_antagonist) + if(!name_plural) + name_plural = name + if(get_config_value(/decl/config/toggle/protect_roles_from_antagonist)) restricted_jobs |= protected_jobs if(antaghud_indicator) - if(!GLOB.hud_icon_reference) - GLOB.hud_icon_reference = list() - if(role_text) GLOB.hud_icon_reference[role_text] = antaghud_indicator - if(faction_role_text) GLOB.hud_icon_reference[faction_role_text] = antaghud_indicator + if(!global.hud_icon_reference) + global.hud_icon_reference = list() + if(name) + global.hud_icon_reference[name] = antaghud_indicator + if(faction_name) + global.hud_icon_reference[faction_name] = antaghud_indicator + +/decl/special_role/validate() + . = ..() + + // Check for our antaghud icons. + if(faction_indicator || antag_indicator) + if(antag_hud_icon) + if(faction_indicator && !check_state_in_icon(faction_indicator, antag_hud_icon)) + . += "missing faction_indicator '[faction_indicator]' from icon 'antag_hud_icon]'" + if(antag_indicator && !check_state_in_icon(antag_indicator, antag_hud_icon)) + . += "missing antag_indicator '[antag_indicator]' from icon 'antag_hud_icon]'" + else + . += "missing antag_hud_icon" -/datum/antagonist/proc/tick() - return 1 + // Grab initial in case it was already successfully loaded. + var/initial_base_to_load = initial(base_to_load) + if(isnull(initial_base_to_load)) + return + if(!istext(initial_base_to_load)) + . += "had non-text base_to_load value '[initial_base_to_load]'." + return + var/datum/map_template/base = SSmapping.get_template(initial_base_to_load) + if(!istype(base)) + . += "failed to retrieve base_to_load template '[initial_base_to_load]'." + return + if(!base.loaded && !load_required_map()) + . += "failed to load base_to_load template '[base.name]'." + +/decl/special_role/proc/get_antag_text(mob/recipient) + return antag_text + +/decl/special_role/proc/get_welcome_text(mob/recipient) + return welcome_text + +/decl/special_role/proc/get_leader_welcome_text(mob/recipient) + return leader_welcome_text // Get the raw list of potential players. -/datum/antagonist/proc/build_candidate_list(datum/game_mode/mode, ghosts_only) +/decl/special_role/proc/build_candidate_list(decl/game_mode/mode, ghosts_only) candidates = list() // Clear. // Prune restricted status. Broke it up for readability. // Note that this is done before jobs are handed out. - for(var/datum/mind/player in mode.get_players_for_role(id)) + var/age_restriction = get_config_value(/decl/config/num/use_age_restriction_for_antags) + for(var/datum/mind/player in mode.get_players_for_role(type)) if(ghosts_only && !(isghostmind(player) || isnewplayer(player.current))) - log_debug("[key_name(player)] is not eligible to become a [role_text]: Only ghosts may join as this role!") - else if(config.use_age_restriction_for_antags && player.current.client.player_age < minimum_player_age) - log_debug("[key_name(player)] is not eligible to become a [role_text]: Is only [player.current.client.player_age] day\s old, has to be [minimum_player_age] day\s!") - else if(player.special_role) - log_debug("[key_name(player)] is not eligible to become a [role_text]: They already have a special role ([player.special_role])!") + log_debug("[key_name(player)] is not eligible to become a [name]: Only ghosts may join as this role!") + else if(age_restriction && player.current.client.player_age < minimum_player_age) + log_debug("[key_name(player)] is not eligible to become a [name]: Is only [player.current.client.player_age] day\s old, has to be [minimum_player_age] day\s!") + else if(player.assigned_special_role) + log_debug("[key_name(player)] is not eligible to become a [name]: They already have a special role ([player.get_special_role_name("unknown role")])!") else if (player in pending_antagonists) - log_debug("[key_name(player)] is not eligible to become a [role_text]: They have already been selected for this role!") + log_debug("[key_name(player)] is not eligible to become a [name]: They have already been selected for this role!") else if(!can_become_antag(player)) - log_debug("[key_name(player)] is not eligible to become a [role_text]: They are blacklisted for this role!") + log_debug("[key_name(player)] is not eligible to become a [name]: They are blacklisted for this role!") else if(player_is_antag(player)) - log_debug("[key_name(player)] is not eligible to become a [role_text]: They are already an antagonist!") + log_debug("[key_name(player)] is not eligible to become a [name]: They are already an antagonist!") else candidates |= player return candidates // Builds a list of potential antags without actually setting them. Used to test mode viability. -/datum/antagonist/proc/get_potential_candidates(var/datum/game_mode/mode, var/ghosts_only) +/decl/special_role/proc/get_potential_candidates(var/decl/game_mode/mode, var/ghosts_only) var/candidates = list() // Keeping broken up for readability - for(var/datum/mind/player in mode.get_players_for_role(id)) + var/age_restriction = get_config_value(/decl/config/num/use_age_restriction_for_antags) + for(var/datum/mind/player in mode.get_players_for_role(type)) if(ghosts_only && !(isghostmind(player) || isnewplayer(player.current))) - else if(config.use_age_restriction_for_antags && player.current.client.player_age < minimum_player_age) - else if(player.special_role) - else if (player in pending_antagonists) - else if(!can_become_antag(player)) - else if(player_is_antag(player)) - else - candidates |= player + continue + if(age_restriction && player.current.client.player_age < minimum_player_age) + continue + if(player.assigned_special_role) + continue + if (player in pending_antagonists) + continue + if(!can_become_antag(player)) + continue + if(player_is_antag(player)) + continue + candidates |= player return candidates -/datum/antagonist/proc/attempt_random_spawn() +/decl/special_role/proc/attempt_random_spawn() update_current_antag_max(SSticker.mode) - build_candidate_list(SSticker.mode, flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) + build_candidate_list(SSticker.mode, is_latejoin_template()) attempt_spawn() finalize_spawn() -/datum/antagonist/proc/attempt_auto_spawn() +/decl/special_role/proc/attempt_auto_spawn() if(!can_late_spawn()) return 0 update_current_antag_max(SSticker.mode) var/active_antags = get_active_antag_count() - message_admins("[uppertext(id)]: Found [active_antags]/[cur_max] active [role_text_plural].") + message_admins("[uppertext(name)]: Found [active_antags]/[cur_max] active [name_plural].") if(active_antags >= cur_max) - message_admins("Could not auto-spawn a [role_text], active antag limit reached.") + message_admins("Could not auto-spawn a [name], active antag limit reached.") return 0 - build_candidate_list(SSticker.mode, flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) + build_candidate_list(SSticker.mode, is_latejoin_template()) if(!candidates.len) - message_admins("Could not auto-spawn a [role_text], no candidates found.") + message_admins("Could not auto-spawn a [name], no candidates found.") return 0 attempt_spawn(1) //auto-spawn antags one at a time if(!pending_antagonists.len) - message_admins("Could not auto-spawn a [role_text], none of the available candidates could be selected.") + message_admins("Could not auto-spawn a [name], none of the available candidates could be selected.") return 0 var/datum/mind/player = pending_antagonists[1] - if(!add_antagonist(player,0,0,0,1,1)) - message_admins("Could not auto-spawn a [role_text], failed to add antagonist.") + if(!add_antagonist(player, do_not_announce = TRUE, preserve_appearance = TRUE)) + message_admins("Could not auto-spawn a [name], failed to add antagonist.") return 0 reset_antag_selection() @@ -190,7 +230,7 @@ //Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned, //so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are //assigned, so that job restrictions can be respected. -/datum/antagonist/proc/attempt_spawn(var/spawn_target = null) +/decl/special_role/proc/attempt_spawn(var/spawn_target = null) if(spawn_target == null) spawn_target = initial_spawn_target @@ -198,44 +238,43 @@ if(!candidates.len) return 0 - //Grab candidates randomly until we have enough. + //Grab candidates until we have enough. while(candidates.len && pending_antagonists.len < spawn_target) - var/datum/mind/player = pick(candidates) - candidates -= player + var/datum/mind/player = popleft(candidates) draft_antagonist(player) return 1 -/datum/antagonist/proc/draft_antagonist(var/datum/mind/player) +/decl/special_role/proc/draft_antagonist(var/datum/mind/player) //Check if the player can join in this antag role, or if the player has already been given an antag role. if(!can_become_antag(player)) - log_debug("[player.key] was selected for [role_text] by lottery, but is not allowed to be that role.") + log_debug("[player.key] was selected for [name] by lottery, but is not allowed to be that role.") return 0 - if(player.special_role) - log_debug("[player.key] was selected for [role_text] by lottery, but they already have a special role.") + if(player.assigned_special_role) + log_debug("[player.key] was selected for [name] by lottery, but they already have a special role.") return 0 - if(!(flags & ANTAG_OVERRIDE_JOB) && (!player.current || istype(player.current, /mob/new_player))) - log_debug("[player.key] was selected for [role_text] by lottery, but they have not joined the game.") + if(!(flags & ANTAG_OVERRIDE_JOB) && (!player.current || isnewplayer(player.current))) + log_debug("[player.key] was selected for [name] by lottery, but they have not joined the game.") return 0 if(GAME_STATE >= RUNLEVEL_GAME && (isghostmind(player) || isnewplayer(player.current)) && !(player in SSticker.antag_pool)) - log_debug("[player.key] was selected for [role_text] by lottery, but they are a ghost not in the antag pool.") + log_debug("[player.key] was selected for [name] by lottery, but they are a ghost not in the antag pool.") return 0 pending_antagonists |= player - log_debug("[player.key] has been selected for [role_text] by lottery.") + log_debug("[player.key] has been selected for [name] by lottery.") //Ensure that antags with ANTAG_OVERRIDE_JOB do not occupy job slots. if(flags & ANTAG_OVERRIDE_JOB) - player.assigned_role = role_text + player.assigned_role = name player.role_alt_title = null //Ensure that a player cannot be drafted for multiple antag roles, taking up slots for antag roles that they will not fill. - player.special_role = role_text + player.assigned_special_role = type return 1 //Spawns all pending_antagonists. This is done separately from attempt_spawn in case the game mode setup fails. -/datum/antagonist/proc/finalize_spawn() +/decl/special_role/proc/finalize_spawn() if(!pending_antagonists) return @@ -246,17 +285,17 @@ reset_antag_selection() //Procced after /ALL/ antagonists have finished setting up and spawning. -/datum/antagonist/proc/post_spawn() +/decl/special_role/proc/post_spawn() return //Resets the antag selection, clearing all pending_antagonists and their special_role //(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list. //Existing antagonists are left untouched. -/datum/antagonist/proc/reset_antag_selection() +/decl/special_role/proc/reset_antag_selection() for(var/datum/mind/player in pending_antagonists) if(flags & ANTAG_OVERRIDE_JOB) player.assigned_job = null player.assigned_role = null - player.special_role = null + player.assigned_special_role = null pending_antagonists.Cut() candidates.Cut() diff --git a/code/game/antagonist/antagonist_add.dm b/code/game/antagonist/antagonist_add.dm index 507b02669cbb..60a982a81ac9 100644 --- a/code/game/antagonist/antagonist_add.dm +++ b/code/game/antagonist/antagonist_add.dm @@ -1,32 +1,37 @@ -/datum/antagonist/proc/load_required_map() +/decl/special_role/proc/load_required_map() if(!base_to_load) return TRUE . = FALSE - if(ispath(base_to_load)) + if(base_to_load) var/datum/map_template/base = base_to_load base_to_load = null - if(SSmapping.map_templates[initial(base.name)]) - base = SSmapping.map_templates[initial(base.name)] + if(istext(base)) + base = SSmapping.get_template(base) + if(!istype(base)) + PRINT_STACK_TRACE("Map template '[base]' could not be found for [name].") + return FALSE + if(base.loaded > 0) + report_progress("Map template '[base]' is already loaded, skipping additional load for [name].") + . = TRUE else - base = new base() - report_progress("Loading map template '[base]' for [role_text]...") - . = base.load_new_z() + report_progress("Loading map template '[base]' for [name].") + . = base.load_new_z() if(.) get_starting_locations() -/datum/antagonist/proc/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance) +/decl/special_role/proc/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance) if(!add_antagonist_mind(player, ignore_role)) - return + return FALSE load_required_map() //do this again, just in case if(flags & ANTAG_OVERRIDE_JOB) player.assigned_job = null - player.assigned_role = role_text + player.assigned_role = name player.role_alt_title = null - player.special_role = role_text + player.assigned_special_role = type if(isghostmind(player)) create_default(player.current) @@ -35,27 +40,27 @@ if(istype(skill_setter)) skill_setter.initialize_skills(player.current.skillset) if(!do_not_equip) - equip(player.current) + equip_role(player.current) if(player.current) player.current.faction = faction - return 1 + return TRUE -/datum/antagonist/proc/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg) +/decl/special_role/proc/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg) if(!istype(player)) - return 0 + return FALSE if(!player.current) - return 0 + return FALSE if(player in current_antagonists) - return 0 + return FALSE if(!can_become_antag(player, ignore_role)) - return 0 + return FALSE current_antagonists |= player if(faction_verb) player.current.verbs |= faction_verb - if(config.objectives_disabled == CONFIG_OBJECTIVE_VERB) + if(get_config_value(/decl/config/enum/objectives_disabled) == CONFIG_OBJECTIVE_VERB) player.current.verbs += /mob/proc/add_objectives if(player.current.client) @@ -71,24 +76,25 @@ if(nonstandard_role_type) faction_members |= player to_chat(player.current, "You are \a [nonstandard_role_type]!") - player.special_role = nonstandard_role_type + player.assigned_special_role = nonstandard_role_type if(nonstandard_role_msg) to_chat(player.current, "[nonstandard_role_msg]") update_icons_added(player) - return 1 + return TRUE -/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) +/decl/special_role/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) if(!istype(player)) return 0 - if(player.current && faction_verb) - player.current.verbs -= faction_verb - if(faction && player.current.faction == faction) - player.current.faction = MOB_FACTION_NEUTRAL + if(player.current) + if(faction_verb) + player.current.verbs -= faction_verb + if(faction && player.current.faction == faction) + player.current.faction = MOB_FACTION_NEUTRAL if(player in current_antagonists) - to_chat(player.current, "You are no longer a [role_text]!") + to_chat(player.current, "You are no longer a [name]!") current_antagonists -= player faction_members -= player - player.special_role = null + player.assigned_special_role = null update_icons_removed(player) if(player.current) diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 0dd70ac728af..17e9a80b9cf8 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -1,4 +1,4 @@ -/datum/antagonist/proc/create_antagonist(var/datum/mind/target, var/move, var/gag_announcement, var/preserve_appearance) +/decl/special_role/proc/create_antagonist(var/datum/mind/target, var/move, var/gag_announcement, var/preserve_appearance) if(!target) return @@ -8,7 +8,7 @@ remove_antagonist(target) return 0 if(flags & ANTAG_CHOOSE_NAME) - INVOKE_ASYNC(src, .proc/set_antag_name, target.current) + INVOKE_ASYNC(src, PROC_REF(set_antag_name), target.current) if(move) place_mob(target.current) update_leader() @@ -18,45 +18,20 @@ if(!gag_announcement) announce_antagonist_spawn() -/datum/antagonist/proc/create_default(var/mob/source) +/decl/special_role/proc/create_default(var/mob/source) var/mob/living/M if(mob_path) M = new mob_path(get_turf(source)) else - M = new /mob/living/carbon/human(get_turf(source)) + M = new /mob/living/human(get_turf(source)) M.ckey = source.ckey add_antagonist(M.mind, 1, 0, 1) // Equip them and move them to spawn. return M -/datum/antagonist/proc/create_id(var/assignment, var/mob/living/carbon/human/player, var/equip = 1) - - var/obj/item/card/id/W = new id_type(player) - if(!W) return - W.access |= default_access - W.assignment = "[assignment]" - player.set_id_info(W) - if(equip) player.equip_to_slot_or_del(W, slot_wear_id) - return W - -/datum/antagonist/proc/create_radio(var/freq, var/mob/living/carbon/human/player) - var/obj/item/radio/R - - switch(freq) - if(SYND_FREQ) - R = new/obj/item/radio/headset/syndicate(player) - if(RAID_FREQ) - R = new/obj/item/radio/headset/raider(player) - else - R = new/obj/item/radio/headset(player) - R.set_frequency(freq) - - player.equip_to_slot_or_del(R, slot_l_ear) - return R - -/datum/antagonist/proc/create_nuke(var/atom/paper_spawn_loc, var/datum/mind/code_owner) +/decl/special_role/proc/create_nuke(var/atom/paper_spawn_loc, var/datum/mind/code_owner) // Decide on a code. - var/obj/effect/landmark/nuke_spawn = locate(nuke_spawn_loc ? nuke_spawn_loc : "landmark*Nuclear-Bomb") + var/obj/abstract/landmark/nuke_spawn = locate(nuke_spawn_loc ? nuke_spawn_loc : "landmark*Nuclear-Bomb") var/code if(nuke_spawn) @@ -77,14 +52,14 @@ P.info = "The nuclear authorization code is: [code]" P.SetName("nuclear bomb code") if(leader && leader.current) - if(get_turf(P) == get_turf(leader.current) && !(leader.current.l_hand && leader.current.r_hand)) + if(get_turf(P) == get_turf(leader.current) && leader.current.get_empty_hand_slot()) leader.current.put_in_hands(P) if(!code_owner && leader) code_owner = leader if(code_owner) code_owner.StoreMemory("Nuclear Bomb Code: [code]", /decl/memory_options/system) - to_chat(code_owner.current, "The nuclear authorization code is: [code]") + to_chat(code_owner.current, "The nuclear authorization code is: [code].") else message_admins("Could not spawn nuclear bomb. Contact a developer.") return @@ -92,16 +67,16 @@ spawned_nuke = code return code -/datum/antagonist/proc/greet(var/datum/mind/player) +/decl/special_role/proc/greet(var/datum/mind/player) // Basic intro text. - to_chat(player.current, "You are a [role_text]!") + to_chat(player.current, "You are a [name]!") if(leader_welcome_text && player == leader) - to_chat(player.current, "[leader_welcome_text]") + to_chat(player.current, "[get_leader_welcome_text(player.current)]") else - to_chat(player.current, "[welcome_text]") - if (config.objectives_disabled == CONFIG_OBJECTIVE_NONE || !player.objectives.len) - to_chat(player.current, "[antag_text]") + to_chat(player.current, "[get_welcome_text(player.current)]") + if (get_config_value(/decl/config/enum/objectives_disabled) == CONFIG_OBJECTIVE_NONE || !player.objectives.len) + to_chat(player.current, get_antag_text(player.current)) if((flags & ANTAG_HAS_NUKE) && !spawned_nuke) create_nuke() @@ -109,14 +84,12 @@ src.show_objectives_at_creation(player) return 1 -/datum/antagonist/proc/set_antag_name(var/mob/living/player) +/decl/special_role/proc/set_antag_name(var/mob/living/player) // Choose a name, if any. - var/newname = sanitize(input(player, "You are a [role_text]. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) + var/newname = sanitize(input(player, "You are a [name]. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) if (newname) player.real_name = newname player.SetName(player.real_name) - if(player.dna) - player.dna.real_name = newname if(player.mind) player.mind.name = player.name // Update any ID cards. update_access(player) diff --git a/code/game/antagonist/antagonist_equip.dm b/code/game/antagonist/antagonist_equip.dm index 512b8004221c..2ca60eefcfd9 100644 --- a/code/game/antagonist/antagonist_equip.dm +++ b/code/game/antagonist/antagonist_equip.dm @@ -1,8 +1,10 @@ -/datum/antagonist/proc/equip(var/mob/living/carbon/human/player) +/decl/special_role/proc/equip_role(var/mob/living/human/player) + + SHOULD_CALL_PARENT(TRUE) if(!istype(player)) - return 0 - + return FALSE + if (required_language) player.add_language(required_language) player.set_default_language(required_language) @@ -10,28 +12,42 @@ // This could use work. if(flags & ANTAG_CLEAR_EQUIPMENT) for(var/obj/item/thing in player.contents) - if(player.canUnEquip(thing)) + if(player.can_unequip_item(thing)) qdel(thing) - //mainly for vox antag compatibility. Should not effect item spawning. + //mainly for nonhuman antag compatibility. Should not effect item spawning. player.species.equip_survival_gear(player) - return 1 -/datum/antagonist/proc/unequip(var/mob/living/carbon/human/player) - if(!istype(player)) - return 0 - return 1 + if(default_outfit) + var/decl/outfit/outfit = GET_DECL(default_outfit) + outfit.equip_outfit(player) + + var/obj/item/card/id/id = player.get_equipped_item(slot_wear_id_str) + if(id) + if(default_access) + LAZYDISTINCTADD(id.access, default_access) + if(id_title) + id.assignment = id_title + id.position = id_title + + if(rig_type) + equip_rig(rig_type, player) + + return TRUE + +/decl/special_role/proc/unequip_role(var/mob/living/human/player) + return istype(player) -/datum/antagonist/proc/equip_rig(var/rig_type, var/mob/living/carbon/human/player) - set waitfor = 0 +/decl/special_role/proc/equip_rig(var/rig_type, var/mob/living/human/player) + set waitfor = FALSE if(istype(player) && ispath(rig_type)) var/obj/item/rig/rig = new rig_type(player) rig.seal_delay = 0 player.put_in_hands(rig) - player.equip_to_slot_or_del(rig,slot_back) + player.equip_to_slot_or_del(rig,slot_back_str) if(rig) rig.visible_name = player.real_name rig.toggle_seals(src,1) rig.seal_delay = initial(rig.seal_delay) if(rig.air_supply) player.set_internals(rig.air_supply) - return rig \ No newline at end of file + return rig \ No newline at end of file diff --git a/code/game/antagonist/antagonist_factions.dm b/code/game/antagonist/antagonist_factions.dm index 44b9af3bc13c..079a4daeb571 100644 --- a/code/game/antagonist/antagonist_factions.dm +++ b/code/game/antagonist/antagonist_factions.dm @@ -1,13 +1,4 @@ -/mob/living/proc/convert_to_rev(mob/M in able_mobs_in_oview(src)) - set name = "Recruit to Faction" - set category = "Abilities" - - if(!M.mind || !M.client) - return - - convert_to_faction(M.mind, GLOB.revs) - -/mob/living/proc/convert_to_faction(var/datum/mind/player, var/datum/antagonist/faction) +/mob/living/proc/convert_to_faction(var/datum/mind/player, var/decl/special_role/faction) if(!player || !faction || !player.current) return @@ -24,34 +15,25 @@ return if(!faction.can_become_antag(player, 1)) - to_chat(src, "\The [player.current] cannot be \a [faction.faction_role_text]!") + to_chat(src, "\The [player.current] cannot be \a [faction.faction_name]!") return - if(world.time < player.rev_cooldown) + if(world.time < player.conversion_cooldown) to_chat(src, "You must wait five seconds between attempts.") return to_chat(src, "You are attempting to convert \the [player.current]...") - log_admin("[src]([src.ckey]) attempted to convert [player.current] to the [faction.faction_role_text] faction.") - message_admins("[src]([src.ckey]) attempted to convert [player.current] to the [faction.faction_role_text] faction.") + log_admin("[src]([src.ckey]) attempted to convert [player.current] to the [faction.faction_name] faction.") + message_admins("[src]([src.ckey]) attempted to convert [player.current] to the [faction.faction_name] faction.") - player.rev_cooldown = world.time + 5 SECONDS + player.conversion_cooldown = world.time + 5 SECONDS if (!faction.is_antagonist(player)) var/choice = alert(player.current,"Asked by [src]: Do you want to join the [faction.faction_descriptor]?","Join the [faction.faction_descriptor]?","No!","Yes!") if(!(player.current in able_mobs_in_oview(src))) return - if(choice == "Yes!" && faction.add_antagonist_mind(player, 0, faction.faction_role_text, faction.faction_welcome)) + if(choice == "Yes!" && faction.add_antagonist_mind(player, 0, faction.faction_name, faction.faction_welcome)) to_chat(src, "\The [player.current] joins the [faction.faction_descriptor]!") return else to_chat(player, "You reject this traitorous cause!") to_chat(src, "\The [player.current] does not support the [faction.faction_descriptor]!") - -/mob/living/proc/convert_to_loyalist(mob/M in able_mobs_in_oview(src)) - set name = "Convince Recidivist" - set category = "Abilities" - - if(!M.mind || !M.client) - return - - convert_to_faction(M.mind, GLOB.loyalists) diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm index efc097a371ca..f882c80efcde 100644 --- a/code/game/antagonist/antagonist_helpers.dm +++ b/code/game/antagonist/antagonist_helpers.dm @@ -1,41 +1,42 @@ -/datum/antagonist/proc/can_become_antag(var/datum/mind/player, var/ignore_role) +/decl/special_role/proc/can_become_antag(var/datum/mind/player, var/ignore_role) if(player.current) - if(isliving(player.current) && player.current.stat) - return 0 - if(jobban_isbanned(player.current, id)) - return 0 + if(isliving(player.current) && player.current.stat == DEAD) + return FALSE + if(jobban_isbanned(player.current, name)) + return FALSE if(player.current.faction != MOB_FACTION_NEUTRAL) - return 0 - - if(is_type_in_list(player.assigned_job, blacklisted_jobs)) - return 0 + return FALSE if(!ignore_role) if(player.current && player.current.client) var/client/C = player.current.client // Limits antag status to clients above player age, if the age system is being used. - if(C && config.use_age_restriction_for_jobs && isnum(C.player_age) && isnum(min_player_age) && (C.player_age < min_player_age)) - return 0 - if(is_type_in_list(player.assigned_job, restricted_jobs)) - return 0 + if(C && get_config_value(/decl/config/num/use_age_restriction_for_jobs) && isnum(C.player_age) && isnum(min_player_age) && (C.player_age < min_player_age)) + return FALSE + if(player.assigned_job) + if(is_type_in_list(player.assigned_job, blacklisted_jobs) || is_type_in_list(player.assigned_job, restricted_jobs)) + return FALSE + for(var/event_tag in blocked_job_event_categories) + if(event_tag in player.assigned_job.event_categories) + return FALSE if(player.current && (player.current.status_flags & NO_ANTAG)) - return 0 - return 1 + return FALSE + return TRUE -/datum/antagonist/proc/antags_are_dead() +/decl/special_role/proc/antags_are_dead() for(var/datum/mind/antag in current_antagonists) if(mob_path && !istype(antag.current,mob_path)) continue - if(antag.current.stat==2) + if(antag.current.stat == DEAD) continue return 0 return 1 -/datum/antagonist/proc/get_antag_count() +/decl/special_role/proc/get_antag_count() return current_antagonists ? current_antagonists.len : 0 -/datum/antagonist/proc/get_active_antag_count() +/decl/special_role/proc/get_active_antag_count() var/active_antags = 0 for(var/datum/mind/player in current_antagonists) var/mob/living/L = player.current @@ -46,32 +47,19 @@ active_antags++ return active_antags -/datum/antagonist/proc/is_antagonist(var/datum/mind/player) +/decl/special_role/proc/is_antagonist(var/datum/mind/player) if(player in current_antagonists) return 1 -/datum/antagonist/proc/is_type(var/antag_type) - if(antag_type == id || antag_type == role_text) - return 1 - return 0 - -/datum/antagonist/proc/is_votable() +/decl/special_role/proc/is_votable() return (flags & ANTAG_VOTABLE) -/datum/antagonist/proc/can_late_spawn() +/decl/special_role/proc/can_late_spawn() if(!SSticker.mode) return 0 - if(!(id in SSticker.mode.latejoin_antag_tags)) + if(!(type in SSticker.mode.latejoin_antags)) return 0 return 1 -/datum/antagonist/proc/is_latejoin_template() +/decl/special_role/proc/is_latejoin_template() return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) - -/proc/all_random_antag_types() - // No caching as the ANTAG_RANDOM_EXCEPTED flag can be added/removed mid-round. - var/list/antag_candidates = GLOB.all_antag_types_.Copy() - for(var/datum/antagonist/antag in antag_candidates) - if(antag.flags & ANTAG_RANDOM_EXCEPTED) - antag_candidates -= antag - return antag_candidates diff --git a/code/game/antagonist/antagonist_objectives.dm b/code/game/antagonist/antagonist_objectives.dm index d528bbb2d45c..a4ad2463e7a9 100644 --- a/code/game/antagonist/antagonist_objectives.dm +++ b/code/game/antagonist/antagonist_objectives.dm @@ -1,23 +1,23 @@ -/datum/antagonist/proc/create_global_objectives(var/override=0) - if(config.objectives_disabled != CONFIG_OBJECTIVE_ALL && !override) +/decl/special_role/proc/create_global_objectives(var/override=0) + if(get_config_value(/decl/config/enum/objectives_disabled) != CONFIG_OBJECTIVE_ALL && !override) return 0 - if(global_objectives && global_objectives.len) + if(LAZYLEN(global_objectives)) return 0 return 1 -/datum/antagonist/proc/create_objectives(var/datum/mind/player, var/override=0) - if(config.objectives_disabled != CONFIG_OBJECTIVE_ALL && !override) +/decl/special_role/proc/create_objectives(var/datum/mind/player, var/override=0) + if(get_config_value(/decl/config/enum/objectives_disabled) != CONFIG_OBJECTIVE_ALL && !override) return 0 if(create_global_objectives(override) || global_objectives.len) player.objectives |= global_objectives return 1 -/datum/antagonist/proc/get_special_objective_text() +/decl/special_role/proc/get_special_objective_text() return "" /mob/proc/add_objectives() set name = "Get Objectives" - set desc = "Recieve optional objectives." + set desc = "Receive optional objectives." set category = "OOC" src.verbs -= /mob/proc/add_objectives @@ -25,9 +25,9 @@ if(!src.mind) return - var/all_antag_types = GLOB.all_antag_types_ + var/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/tag in all_antag_types) //we do all of them in case an admin adds an antagonist via the PP. Those do not show up in gamemode. - var/datum/antagonist/antagonist = all_antag_types[tag] + var/decl/special_role/antagonist = all_antag_types[tag] if(antagonist && antagonist.is_antagonist(src.mind)) antagonist.create_objectives(src.mind,1) @@ -64,6 +64,6 @@ //some antagonist datums are not actually antagonists, so we might want to avoid //sending them the antagonist meet'n'greet messages. //E.G. ERT -/datum/antagonist/proc/show_objectives_at_creation(var/datum/mind/player) +/decl/special_role/proc/show_objectives_at_creation(var/datum/mind/player) if(src.show_objectives_on_creation) show_objectives(player) \ No newline at end of file diff --git a/code/game/antagonist/antagonist_panel.dm b/code/game/antagonist/antagonist_panel.dm index 06d95a278e0e..2d4904c726ff 100644 --- a/code/game/antagonist/antagonist_panel.dm +++ b/code/game/antagonist/antagonist_panel.dm @@ -1,37 +1,39 @@ -/datum/antagonist/proc/get_panel_entry(var/datum/mind/player) +/decl/special_role/proc/get_panel_entry(var/datum/mind/player) - var/dat = "[role_text]:" + var/dat = "[name]:" var/extra = get_extra_panel_options(player) if(is_antagonist(player)) - dat += "\[-\]" - dat += "\[equip\]" - if(starting_locations && starting_locations.len) - dat += "\[move to spawn\]" + dat += "\[-\]" + dat += "\[equip\]" + if(LAZYLEN(starting_locations)) + dat += "\[move to spawn\]" if(extra) dat += "[extra]" else - dat += "\[+\]" + dat += "\[+\]" dat += "" return dat -/datum/antagonist/proc/get_extra_panel_options() +/decl/special_role/proc/get_extra_panel_options() return -/datum/antagonist/proc/get_check_antag_output(var/datum/admins/caller) +/decl/special_role/proc/get_check_antag_output(var/datum/admins/calling_admin) - if(!current_antagonists || !current_antagonists.len) + if(!LAZYLEN(current_antagonists)) return "" - var/dat = "
    " + var/dat = "
    [role_text_plural]
    " for(var/datum/mind/player in current_antagonists) var/mob/M = player.current dat += "" if(M) - dat += "" - dat += "" + dat += "" else dat += "" dat += "" @@ -39,23 +41,23 @@ if(flags & ANTAG_HAS_NUKE) dat += "
    [name_plural]
    [M.real_name]/([player.key])" - if(!M.client) dat += " (logged out)" - if(M.stat == DEAD) dat += " (DEAD)" + dat += "[M.real_name]/([player.key])" + if(!M.client) + dat += " (logged out)" + if(M.stat == DEAD) + dat += " (DEAD)" dat += "\[PM\]\[TP\]\[PM\]\[SR\]Mob not found/([player.key])!
    " - for(var/obj/item/disk/nuclear/N in world) + for(var/obj/item/disk/nuclear/N in global.nuke_disks) dat += "" dat += "
    Nuclear disk(s)
    [N.name], " var/atom/disk_loc = N.loc - while(!istype(disk_loc, /turf)) - if(istype(disk_loc, /mob)) + while(!isturf(disk_loc)) + if(ismob(disk_loc)) var/mob/M = disk_loc - dat += "carried by [M.real_name] " + dat += "carried by [M.real_name] " if(istype(disk_loc, /obj)) var/obj/O = disk_loc dat += "in \a [O.name] " disk_loc = disk_loc.loc dat += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])
    " - dat += get_additional_check_antag_output(caller) + dat += get_additional_check_antag_output(calling_admin) dat += "
    " return dat //Overridden elsewhere. -/datum/antagonist/proc/get_additional_check_antag_output(var/datum/admins/caller) +/decl/special_role/proc/get_additional_check_antag_output(var/datum/admins/calling_admin) return "" diff --git a/code/game/antagonist/antagonist_place.dm b/code/game/antagonist/antagonist_place.dm index 11ea718f8ccd..fb2210e8559a 100644 --- a/code/game/antagonist/antagonist_place.dm +++ b/code/game/antagonist/antagonist_place.dm @@ -1,11 +1,11 @@ -/datum/antagonist/proc/get_starting_locations() +/decl/special_role/proc/get_starting_locations() if(landmark_id) starting_locations = list() - for(var/obj/effect/landmark/L in landmarks_list) + for(var/obj/abstract/landmark/L in global.all_landmarks) if(L.name == landmark_id) starting_locations |= get_turf(L) -/datum/antagonist/proc/announce_antagonist_spawn() +/decl/special_role/proc/announce_antagonist_spawn() if(spawn_announcement) if(announced) @@ -20,8 +20,8 @@ command_announcement.Announce("[spawn_announcement]", "[spawn_announcement_title ? spawn_announcement_title : "Priority Alert"]") return -/datum/antagonist/proc/place_mob(var/mob/living/mob) - if(!starting_locations || !starting_locations.len) +/decl/special_role/proc/place_mob(var/mob/living/mob) + if(!LAZYLEN(starting_locations)) return var/turf/T = pick_mobless_turf_if_exists(starting_locations) mob.forceMove(T) diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm index f0e540e32286..dd875e8e0e17 100644 --- a/code/game/antagonist/antagonist_print.dm +++ b/code/game/antagonist/antagonist_print.dm @@ -1,24 +1,25 @@ -/datum/antagonist/proc/print_player_summary() +/decl/special_role/proc/print_player_summary() if(!current_antagonists.len) return 0 var/text = list() - text += "

    The [current_antagonists.len == 1 ? "[role_text] was" : "[role_text_plural] were"]:" + text += "

    The [current_antagonists.len == 1 ? "[name] was" : "[name_plural] were"]:" for(var/datum/mind/P in current_antagonists) text += print_player(P) text += get_special_objective_text(P) - var/datum/goal/ambition = SSgoals.ambitions[P] - if(ambition) - text += "
    Their goals for today were..." - text += "
    [ambition.summarize()]" if(!global_objectives.len && P.objectives && P.objectives.len) var/num = 1 for(var/datum/objective/O in P.objectives) text += print_objective(O, num) num++ - if(global_objectives && global_objectives.len) + var/datum/goal/ambitions = SSgoals.ambitions[P] + if(ambitions) + text += "
    Their goals for today were..." + text += "
    [ambitions.summarize()]" + + if(LAZYLEN(global_objectives)) text += "
    Their objectives were:" var/num = 1 for(var/datum/objective/O in global_objectives) @@ -29,12 +30,18 @@ text += "
    " to_world(jointext(text,null)) - -/datum/antagonist/proc/print_objective(var/datum/objective/O, var/num) +/decl/special_role/proc/print_objective(var/datum/objective/O, var/num) return "
    Objective [num]: [O.explanation_text] " -/datum/antagonist/proc/print_player(var/datum/mind/ply) - var/role = ply.assigned_role ? "\improper[ply.assigned_role]" : (ply.special_role ? "\improper[ply.special_role]" : "unknown role") +/decl/special_role/proc/print_player(var/datum/mind/ply) + + var/role + if(ply.assigned_role) + role = ply.assigned_role + else + role = ply.get_special_role_name("unknown role") + role = "\improper [role]" + var/text = "
    [ply.name] ([ply.key]) as \a [role] (" if(ply.current) if(ply.current.stat == DEAD) diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm index 2e2ff3ab44f7..4700d8b30018 100644 --- a/code/game/antagonist/antagonist_update.dm +++ b/code/game/antagonist/antagonist_update.dm @@ -1,48 +1,45 @@ -/datum/antagonist/proc/update_leader() +/decl/special_role/proc/update_leader() if(!leader && current_antagonists.len && (flags & ANTAG_HAS_LEADER)) leader = current_antagonists[1] -/datum/antagonist/proc/update_antag_mob(var/datum/mind/player, var/preserve_appearance) - - if(!valid_species) - valid_species = list(GLOB.using_map.default_species) - +/decl/special_role/proc/update_antag_mob(var/datum/mind/player, var/preserve_appearance) // Get the mob. if((flags & ANTAG_OVERRIDE_MOB) && (!player.current || (mob_path && !istype(player.current, mob_path)))) var/mob/holder = player.current player.current = new mob_path(get_turf(player.current)) player.transfer_to(player.current) if(holder) qdel(holder) - player.original = player.current if(!preserve_appearance && (flags & ANTAG_SET_APPEARANCE)) spawn(3) - var/mob/living/carbon/human/H = player.current - if(istype(H)) H.change_appearance(APPEARANCE_ALL, H.loc, H, valid_species, state = GLOB.z_state) + var/mob/living/human/H = player.current + if(istype(H)) H.change_appearance(APPEARANCE_ALL, H.loc, H, species_whitelist = valid_species, state = global.z_topic_state) return player.current -/datum/antagonist/proc/update_access(var/mob/living/player) +/decl/special_role/proc/update_access(var/mob/living/player) for(var/obj/item/card/id/id in player.contents) player.set_id_info(id) -/datum/antagonist/proc/clear_indicators(var/datum/mind/recipient) +/decl/special_role/proc/clear_indicators(var/datum/mind/recipient) if(!recipient.current || !recipient.current.client) return for(var/image/I in recipient.current.client.images) if(I.icon_state == antag_indicator || (faction_indicator && I.icon_state == faction_indicator)) qdel(I) -/datum/antagonist/proc/get_indicator(var/datum/mind/recipient, var/datum/mind/other) - if(!antag_indicator || !other.current || !recipient.current) +/decl/special_role/proc/get_indicator(var/datum/mind/recipient, var/datum/mind/other) + if(!other.current || !recipient.current) return var/indicator = (faction_indicator && (other in faction_members)) ? faction_indicator : antag_indicator - var/image/I = image('icons/mob/hud.dmi', loc = other.current, icon_state = indicator, layer = ABOVE_HUMAN_LAYER) - if(ishuman(other.current)) - var/mob/living/carbon/human/H = other.current - I.pixel_x = H.species.antaghud_offset_x - I.pixel_y = H.species.antaghud_offset_y + if(!indicator) + return + var/image/I = image(antag_hud_icon, loc = other.current, icon_state = indicator, layer = ABOVE_HUMAN_LAYER) + var/decl/bodytype/root_bodytype = other.current.get_bodytype() + if(istype(root_bodytype)) + I.pixel_x = root_bodytype.antaghud_offset_x + I.pixel_y = root_bodytype.antaghud_offset_y return I -/datum/antagonist/proc/update_all_icons() +/decl/special_role/proc/update_all_icons() if(!antag_indicator) return for(var/datum/mind/antag in current_antagonists) @@ -53,7 +50,7 @@ if(antag.current && antag.current.client) antag.current.client.images |= get_indicator(antag, other_antag) -/datum/antagonist/proc/update_icons_added(var/datum/mind/player) +/decl/special_role/proc/update_icons_added(var/datum/mind/player) if(!antag_indicator || !player.current) return spawn(0) @@ -69,7 +66,7 @@ if(player.current.client) player.current.client.images |= get_indicator(player, antag) -/datum/antagonist/proc/update_icons_removed(var/datum/mind/player) +/decl/special_role/proc/update_icons_removed(var/datum/mind/player) if(!antag_indicator || !player.current) return spawn(0) @@ -81,15 +78,15 @@ if(I.loc == player.current) qdel(I) -/datum/antagonist/proc/update_current_antag_max(datum/game_mode/mode) +/decl/special_role/proc/update_current_antag_max(decl/game_mode/mode) cur_max = hard_cap - if(mode.antag_tags && (mode.antag_tags)) + if(type in mode.associated_antags) cur_max = hard_cap_round if(mode.antag_scaling_coeff) var/count = 0 - for(var/mob/living/M in GLOB.player_list) + for(var/mob/living/M in global.player_list) if(M.client) count++ diff --git a/code/game/antagonist/outsider/actors.dm b/code/game/antagonist/outsider/actors.dm deleted file mode 100644 index 604873a06837..000000000000 --- a/code/game/antagonist/outsider/actors.dm +++ /dev/null @@ -1,57 +0,0 @@ -GLOBAL_DATUM_INIT(actor, /datum/antagonist/actor, new) - -/datum/antagonist/actor - id = MODE_ACTOR - role_text = "Actor" - role_text_plural = "Actors" - welcome_text = "You've been hired to entertain people through the power of television!" - landmark_id = "ActorSpawn" - id_type = /obj/item/card/id/syndicate - - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_SET_APPEARANCE | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED - - hard_cap = 7 - hard_cap_round = 10 - initial_spawn_req = 1 - initial_spawn_target = 1 - show_objectives_on_creation = 0 //actors are not antagonists and do not need the antagonist greet text - required_language = /decl/language/human/common - -/datum/antagonist/actor/greet(var/datum/mind/player) - if(!..()) - return - - player.current.show_message("You work for [GLOB.using_map.company_name], tasked with the production and broadcasting of entertainment to all of its assets.") - player.current.show_message("Entertain the crew! Try not to disrupt them from their work too much and remind them how great [GLOB.using_map.company_name] is!") - -/datum/antagonist/actor/equip(var/mob/living/carbon/human/player) - player.equip_to_slot_or_del(new /obj/item/clothing/under/chameleon(src), slot_w_uniform) - player.equip_to_slot_or_del(new /obj/item/clothing/shoes/chameleon(src), slot_shoes) - player.equip_to_slot_or_del(new /obj/item/radio/headset/entertainment(src), slot_l_ear) - var/obj/item/card/id/centcom/ERT/C = new(player.loc) - C.assignment = "Actor" - player.set_id_info(C) - player.equip_to_slot_or_del(C,slot_wear_id) - - return 1 - -/client/verb/join_as_actor() - set category = "IC" - set name = "Join as Actor" - set desc = "Join as an Actor to entertain the crew through television!" - - if(!MayRespawn(1) || !GLOB.actor.can_become_antag(usr.mind, 1)) - return - - var/choice = alert("Are you sure you'd like to join as an actor?", "Confirmation","Yes", "No") - if(choice != "Yes") - return - - if(isghostmind(usr.mind) || isnewplayer(usr)) - if(GLOB.actor.current_antagonists.len >= GLOB.actor.hard_cap) - to_chat(usr, "No more actors may spawn at the current time.") - return - GLOB.actor.create_default(usr) - return - - to_chat(usr, "You must be observing or be a new player to spawn as an actor.") diff --git a/code/game/antagonist/outsider/deity.dm b/code/game/antagonist/outsider/deity.dm deleted file mode 100644 index 6dfe83728b58..000000000000 --- a/code/game/antagonist/outsider/deity.dm +++ /dev/null @@ -1,18 +0,0 @@ -GLOBAL_DATUM_INIT(deity, /datum/antagonist/deity, new) - -/datum/antagonist/deity - id = MODE_DEITY - role_text = "Deity" - role_text_plural = "Deities" - mob_path = /mob/living/deity - welcome_text = "This is not your world. This is not your reality. But here you exist. Use your powers, feed off the faith of others.
    You have to click on yourself to choose your form.
    Everything you say will be heard by your cultists!
    To get points your cultists need to build!
    Build Shrine and Construction are the best starting boons!" - landmark_id = "DeitySpawn" - - flags = ANTAG_OVERRIDE_MOB | ANTAG_OVERRIDE_JOB - - hard_cap = 2 - hard_cap_round = 2 - initial_spawn_req = 1 - initial_spawn_target = 1 - - base_to_load = /datum/map_template/ruin/antag_spawn/deity diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm deleted file mode 100644 index 2e8ef9c40814..000000000000 --- a/code/game/antagonist/outsider/ert.dm +++ /dev/null @@ -1,44 +0,0 @@ -GLOBAL_DATUM_INIT(ert, /datum/antagonist/ert, new) - -/datum/antagonist/ert - id = MODE_ERT - role_text = "Emergency Responder" - role_text_plural = "Emergency Responders" - antag_text = "You are an anti antagonist! Within the rules, \ - try to save the installation and its inhabitants from the ongoing crisis. \ - Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ - and before taking extreme actions, please try to also contact the administration! \ - Think through your actions and make the roleplay immersive! Please remember all \ - rules aside from those without explicit exceptions apply to the ERT." - welcome_text = "You shouldn't see this" - leader_welcome_text = "You shouldn't see this" - landmark_id = "Response Team" - id_type = /obj/item/card/id/centcom/ERT - - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED - antaghud_indicator = "hudloyalist" - - hard_cap = 5 - hard_cap_round = 7 - initial_spawn_req = 5 - initial_spawn_target = 7 - show_objectives_on_creation = 0 //we are not antagonists, we do not need the antagonist shpiel/objectives - - base_to_load = /datum/map_template/ruin/antag_spawn/ert - -/datum/antagonist/ert/create_default(var/mob/source) - var/mob/living/carbon/human/M = ..() - if(istype(M)) M.age = rand(25,45) - -/datum/antagonist/ert/Initialize() - ..() - leader_welcome_text = "As leader of the Emergency Response Team, you answer only to [GLOB.using_map.company_name], and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however." - welcome_text = "As member of the Emergency Response Team, you answer only to your leader and [GLOB.using_map.company_name] officials." - -/datum/antagonist/ert/greet(var/datum/mind/player) - if(!..()) - return - to_chat(player.current, "The Emergency Response Team works for Asset Protection; your job is to protect [GLOB.using_map.company_name]'s ass-ets. There is a code red alert on [station_name()], you are tasked to go and fix the problem.") - to_chat(player.current, "You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready.") - -//Equip proc has been moved to the map specific folders. diff --git a/code/game/antagonist/outsider/mercenary.dm b/code/game/antagonist/outsider/mercenary.dm deleted file mode 100644 index 53c5c9d302e3..000000000000 --- a/code/game/antagonist/outsider/mercenary.dm +++ /dev/null @@ -1,41 +0,0 @@ -GLOBAL_DATUM_INIT(mercs, /datum/antagonist/mercenary, new) - -/datum/antagonist/mercenary - id = MODE_MERCENARY - role_text = "Mercenary" - antag_indicator = "hudsyndicate" - role_text_plural = "Mercenaries" - landmark_id = "Syndicate-Spawn" - leader_welcome_text = "You are the leader of the mercenary strikeforce; hail to the chief. Use :t to speak to your underlings." - welcome_text = "To speak on the strike team's private channel use :t." - flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_HAS_NUKE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER - antaghud_indicator = "hudoperative" - - hard_cap = 4 - hard_cap_round = 8 - initial_spawn_req = 4 - initial_spawn_target = 6 - min_player_age = 14 - - faction = "mercenary" - - base_to_load = /datum/map_template/ruin/antag_spawn/mercenary - -/datum/antagonist/mercenary/create_global_objectives() - if(!..()) - return 0 - global_objectives = list() - global_objectives |= new /datum/objective/nuclear - return 1 - -/datum/antagonist/mercenary/equip(var/mob/living/carbon/human/player) - if(!..()) - return 0 - - var/decl/hierarchy/outfit/mercenary = outfit_by_type(/decl/hierarchy/outfit/mercenary) - mercenary.equip(player) - - var/obj/item/radio/uplink/U = new(get_turf(player), player.mind, DEFAULT_TELECRYSTAL_AMOUNT) - player.put_in_hands(U) - - return 1 diff --git a/code/game/antagonist/outsider/ninja.dm b/code/game/antagonist/outsider/ninja.dm deleted file mode 100644 index 4dc2e2e51bb8..000000000000 --- a/code/game/antagonist/outsider/ninja.dm +++ /dev/null @@ -1,148 +0,0 @@ -GLOBAL_DATUM_INIT(ninjas, /datum/antagonist/ninja, new) - -/datum/antagonist/ninja - id = MODE_NINJA - role_text = "Ninja" - role_text_plural = "Ninja" - landmark_id = "ninjastart" - welcome_text = "You are an elite mercenary assassin of the Spider Clan. You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor." - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_RANDSPAWN | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE - antaghud_indicator = "hudninja" - - initial_spawn_req = 1 - initial_spawn_target = 1 - hard_cap = 1 - hard_cap_round = 3 - min_player_age = 18 - - id_type = /obj/item/card/id/syndicate - - faction = "ninja" - base_to_load = /datum/map_template/ruin/antag_spawn/ninja - -/datum/antagonist/ninja/attempt_random_spawn() - if(config.ninjas_allowed) ..() - -/datum/antagonist/ninja/create_objectives(var/datum/mind/ninja) - - if(!..()) - return - - var/objective_list = list(1,2,3,4,5) - for(var/i=rand(2,4),i>0,i--) - switch(pick(objective_list)) - if(1)//Kill - var/datum/objective/assassinate/ninja_objective = new - ninja_objective.owner = ninja - ninja_objective.target = ninja_objective.find_target() - if(ninja_objective.target != "Free Objective") - ninja.objectives += ninja_objective - else - i++ - objective_list -= 1 // No more than one kill objective - if(2)//Steal - var/datum/objective/steal/ninja_objective = new - ninja_objective.owner = ninja - ninja_objective.target = ninja_objective.find_target() - ninja.objectives += ninja_objective - if(3)//Protect - var/datum/objective/protect/ninja_objective = new - ninja_objective.owner = ninja - ninja_objective.target = ninja_objective.find_target() - if(ninja_objective.target != "Free Objective") - ninja.objectives += ninja_objective - else - i++ - objective_list -= 3 - if(4)//Download - var/datum/objective/download/ninja_objective = new - ninja_objective.owner = ninja - ninja_objective.gen_amount_goal() - ninja.objectives += ninja_objective - objective_list -= 4 - if(5)//Harm - var/datum/objective/harm/ninja_objective = new - ninja_objective.owner = ninja - ninja_objective.target = ninja_objective.find_target() - if(ninja_objective.target != "Free Objective") - ninja.objectives += ninja_objective - else - i++ - objective_list -= 5 - - var/datum/objective/survive/ninja_objective = new - ninja_objective.owner = ninja - ninja.objectives += ninja_objective - -/datum/antagonist/ninja/greet(var/datum/mind/player) - - if(!..()) - return 0 - var/directive = generate_ninja_directive("heel") - player.StoreMemory("Directive: [directive]
    ", /decl/memory_options/system) - to_chat(player, "Remember your directive: [directive].") - -/datum/antagonist/ninja/update_antag_mob(var/datum/mind/player) - ..() - var/ninja_title = pick(GLOB.ninja_titles) - var/ninja_name = pick(GLOB.ninja_names) - var/mob/living/carbon/human/H = player.current - if(istype(H)) - H.real_name = "[ninja_title] [ninja_name]" - H.SetName(H.real_name) - player.name = H.name - -/datum/antagonist/ninja/equip(var/mob/living/carbon/human/player) - . = ..() - if(.) - var/obj/item/radio/R = new /obj/item/radio/headset(player) - player.equip_to_slot_or_del(R, slot_l_ear) - player.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(player), slot_w_uniform) - player.equip_to_slot_or_del(new /obj/item/flashlight(player), slot_belt) - create_id("Infiltrator", player) - equip_rig(/obj/item/rig/light/ninja, player) - var/obj/item/modular_computer/pda/syndicate/U = new - player.put_in_hands(U) - var/decl/uplink_source/pda/uplink_source = new - uplink_source.setup_uplink_source(player, 0) - -/datum/antagonist/ninja/proc/generate_ninja_directive(side) - var/directive = "[side=="face"?"[GLOB.using_map.company_name]":"A criminal syndicate"] is your employer. "//Let them know which side they're on. - switch(rand(1,18)) - if(1) - directive += "The Spider Clan must not be linked to this operation. Remain hidden and covert when possible." - if(2) - directive += "[GLOB.using_map.station_name] is financed by an enemy of the Spider Clan. Cause as much structural damage as desired." - if(3) - directive += "A wealthy animal rights activist has made a request we cannot refuse. Prioritize saving animal lives whenever possible." - if(4) - directive += "The Spider Clan absolutely cannot be linked to this operation. Eliminate witnesses at your discretion." - if(5) - directive += "We are currently negotiating with [GLOB.using_map.company_name] [GLOB.using_map.boss_name]. Prioritize saving human lives over ending them." - if(6) - directive += "We are engaged in a legal dispute over [GLOB.using_map.station_name]. If a laywer is present on board, force their cooperation in the matter." - if(7) - directive += "A financial backer has made an offer we cannot refuse. Implicate criminal involvement in the operation." - if(8) - directive += "Let no one question the mercy of the Spider Clan. Ensure the safety of all non-essential personnel you encounter." - if(9) - directive += "A free agent has proposed a lucrative business deal. Implicate [GLOB.using_map.company_name] involvement in the operation." - if(10) - directive += "Our reputation is on the line. Harm as few civilians and innocents as possible." - if(11) - directive += "Our honor is on the line. Utilize only honorable tactics when dealing with opponents." - if(12) - directive += "We are currently negotiating with a mercenary leader. Disguise assassinations as suicide or other natural causes." - if(13) - directive += "Some disgruntled [GLOB.using_map.company_name] employees have been supportive of our operations. Be wary of any mistreatment by command staff." - if(14) - directive += "The Spider Clan has recently been accused of religious insensitivity. Attempt to speak with the Chaplain and prove these accusations false." - if(15) - directive += "The Spider Clan has been bargaining with a competing prosthetics manufacturer. Try to shine [GLOB.using_map.company_name] prosthetics in a bad light." - if(16) - directive += "The Spider Clan has recently begun recruiting outsiders. Consider suitable candidates and assess their behavior amongst the crew." - if(17) - directive += "A cyborg liberation group has expressed interest in our serves. Prove the Spider Clan merciful towards law-bound synthetics." - else - directive += "There are no special supplemental instructions at this time." - return directive diff --git a/code/game/antagonist/outsider/raider.dm b/code/game/antagonist/outsider/raider.dm deleted file mode 100644 index 62213b2ff3af..000000000000 --- a/code/game/antagonist/outsider/raider.dm +++ /dev/null @@ -1,227 +0,0 @@ -GLOBAL_DATUM_INIT(raiders, /datum/antagonist/raider, new) - -/datum/antagonist/raider - id = MODE_RAIDER - role_text = "Raider" - role_text_plural = "Raiders" - antag_indicator = "hudraider" - landmark_id = "voxstart" - welcome_text = "Use :H to talk on your encrypted channel." - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER - antaghud_indicator = "hudraider" - - hard_cap = 6 - hard_cap_round = 10 - initial_spawn_req = 4 - initial_spawn_target = 6 - min_player_age = 14 - - id_type = /obj/item/card/id/syndicate - - faction = "pirate" - base_to_load = /datum/map_template/ruin/antag_spawn/heist - - var/list/raider_uniforms = list( - /obj/item/clothing/under/soviet, - /obj/item/clothing/under/pirate, - /obj/item/clothing/under/redcoat, - /obj/item/clothing/under/serviceoveralls, - /obj/item/clothing/under/captain_fly, - /obj/item/clothing/under/det, - /obj/item/clothing/under/color/brown, - ) - - var/list/raider_shoes = list( - /obj/item/clothing/shoes/jackboots, - /obj/item/clothing/shoes/workboots, - /obj/item/clothing/shoes/color/brown, - /obj/item/clothing/shoes/dress - ) - - var/list/raider_glasses = list( - /obj/item/clothing/glasses/thermal, - /obj/item/clothing/glasses/thermal/plain/eyepatch, - /obj/item/clothing/glasses/thermal/plain/monocle - ) - - var/list/raider_helmets = list( - /obj/item/clothing/head/bearpelt, - /obj/item/clothing/head/ushanka, - /obj/item/clothing/head/pirate, - /obj/item/clothing/mask/bandana/red, - /obj/item/clothing/head/hgpiratecap, - ) - - var/list/raider_suits = list( - /obj/item/clothing/suit/pirate, - /obj/item/clothing/suit/hgpirate, - /obj/item/clothing/suit/storage/toggle/bomber, - /obj/item/clothing/suit/storage/leather_jacket, - /obj/item/clothing/suit/storage/toggle/brown_jacket, - /obj/item/clothing/suit/storage/toggle/hoodie, - /obj/item/clothing/suit/storage/toggle/hoodie/black, - /obj/item/clothing/suit/poncho/colored, - ) - - var/list/raider_guns = list( - /obj/item/gun/energy/laser, - /obj/item/gun/projectile/revolver/lasvolver, - /obj/item/gun/energy/xray, - /obj/item/gun/energy/toxgun, - /obj/item/gun/energy/ionrifle, - /obj/item/gun/energy/taser, - /obj/item/gun/energy/crossbow/largecrossbow, - /obj/item/gun/launcher/crossbow, - /obj/item/gun/launcher/grenade/loaded, - /obj/item/gun/launcher/pneumatic, - /obj/item/gun/projectile/automatic/smg, - /obj/item/gun/projectile/automatic/assault_rifle, - /obj/item/gun/projectile/shotgun/pump, - /obj/item/gun/projectile/shotgun/doublebarrel, - /obj/item/gun/projectile/shotgun/doublebarrel/sawn, - /obj/item/gun/projectile/pistol/holdout, - /obj/item/gun/projectile/revolver, - /obj/item/gun/projectile/zipgun - ) - - var/list/raider_holster = list( - /obj/item/clothing/accessory/storage/holster/armpit, - /obj/item/clothing/accessory/storage/holster/waist, - /obj/item/clothing/accessory/storage/holster/hip - ) - -/datum/antagonist/raider/update_access(var/mob/living/player) - for(var/obj/item/storage/wallet/W in player.contents) - for(var/obj/item/card/id/id in W.contents) - id.SetName("[player.real_name]'s Passport") - id.registered_name = player.real_name - W.SetName("[initial(W.name)] ([id.name])") - -/datum/antagonist/raider/create_global_objectives() - - if(!..()) - return 0 - - var/i = 1 - var/max_objectives = pick(2,2,2,2,3,3,3,4) - global_objectives = list() - while(i<= max_objectives) - var/list/goals = list("kidnap","loot","salvage") - var/goal = pick(goals) - var/datum/objective/heist/O - - if(goal == "kidnap") - goals -= "kidnap" - O = new /datum/objective/heist/kidnap() - else if(goal == "loot") - O = new /datum/objective/heist/loot() - else - O = new /datum/objective/heist/salvage() - O.choose_target() - global_objectives |= O - - i++ - - global_objectives |= new /datum/objective/heist/preserve_crew - return 1 - -/datum/antagonist/raider/proc/is_raider_crew_safe() - - if(!current_antagonists || current_antagonists.len == 0) - return 0 - - for(var/datum/mind/player in current_antagonists) - if(!player.current || get_area(player.current) != locate(/area/map_template/skipjack_station/start)) - return 0 - return 1 - -/datum/antagonist/raider/equip(var/mob/living/carbon/human/player) - - if(!..()) - return 0 - - var/new_shoes = pick(raider_shoes) - var/new_uniform = pick(raider_uniforms) - var/new_glasses = pick(raider_glasses) - var/new_helmet = pick(raider_helmets) - var/new_suit = pick(raider_suits) - - player.equip_to_slot_or_del(new new_shoes(player),slot_shoes) - if(!player.shoes) - //If equipping shoes failed, fall back to equipping sandals - var/fallback_type = pick(/obj/item/clothing/shoes/sandal) - player.equip_to_slot_or_del(new fallback_type(player), slot_shoes) - - player.equip_to_slot_or_del(new new_uniform(player),slot_w_uniform) - player.equip_to_slot_or_del(new new_glasses(player),slot_glasses) - player.equip_to_slot_or_del(new new_helmet(player),slot_head) - player.equip_to_slot_or_del(new new_suit(player),slot_wear_suit) - equip_weapons(player) - - var/obj/item/card/id/id = create_id("Visitor", player, equip = 0) - id.SetName("[player.real_name]'s Passport") - id.assignment = "Visitor" - var/obj/item/storage/wallet/W = new(player) - W.handle_item_insertion(id) - if(player.equip_to_slot_or_del(W, slot_wear_id)) - var/obj/item/cash/cash = new(get_turf(player)) - cash.adjust_worth(rand(50,150)*10) - player.put_in_hands(cash) - create_radio(RAID_FREQ, player) - - return 1 - -/datum/antagonist/raider/proc/equip_weapons(var/mob/living/carbon/human/player) - var/new_gun = pick(raider_guns) - var/new_holster = pick(raider_holster) //raiders don't start with any backpacks, so let's be nice and give them a holster if they can use it. - var/turf/T = get_turf(player) - - var/obj/item/primary = new new_gun(T) - var/obj/item/clothing/accessory/storage/holster/holster = null - - //Give some of the raiders a pirate gun as a secondary - if(prob(60)) - var/obj/item/secondary = new /obj/item/gun/projectile/zipgun(T) - if(!(primary.slot_flags & SLOT_HOLSTER)) - holster = new new_holster(T) - var/datum/extension/holster/H = get_extension(holster, /datum/extension/holster) - H.holstered = secondary - secondary.forceMove(holster) - else - player.equip_to_slot_or_del(secondary, slot_belt) - - if(primary.slot_flags & SLOT_HOLSTER) - holster = new new_holster(T) - var/datum/extension/holster/H = get_extension(holster, /datum/extension/holster) - H.holstered = primary - primary.forceMove(holster) - else if(!player.belt && (primary.slot_flags & SLOT_BELT)) - player.equip_to_slot_or_del(primary, slot_belt) - else if(!player.back && (primary.slot_flags & SLOT_BACK)) - player.equip_to_slot_or_del(primary, slot_back) - else - player.put_in_any_hand_if_possible(primary) - - //If they got a projectile gun, give them a little bit of spare ammo - equip_ammo(player, primary) - - if(holster) - var/obj/item/clothing/under/uniform = player.w_uniform - if(istype(uniform) && uniform.can_attach_accessory(holster)) - uniform.attackby(holster, player) - else - player.put_in_any_hand_if_possible(holster) - -/datum/antagonist/raider/proc/equip_ammo(var/mob/living/carbon/human/player, var/obj/item/gun/gun) - if(istype(gun, /obj/item/gun/projectile)) - var/obj/item/gun/projectile/bullet_thrower = gun - if(bullet_thrower.magazine_type) - player.equip_to_slot_or_del(new bullet_thrower.magazine_type(player), slot_l_store) - if(prob(20)) //don't want to give them too much - player.equip_to_slot_or_del(new bullet_thrower.magazine_type(player), slot_r_store) - else if(bullet_thrower.ammo_type) - var/obj/item/storage/box/ammobox = new(get_turf(player.loc)) - for(var/i in 1 to rand(3,5) + rand(0,2)) - new bullet_thrower.ammo_type(ammobox) - player.put_in_any_hand_if_possible(ammobox) - return diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm deleted file mode 100644 index 2207688bd53a..000000000000 --- a/code/game/antagonist/outsider/wizard.dm +++ /dev/null @@ -1,125 +0,0 @@ -GLOBAL_DATUM_INIT(wizards, /datum/antagonist/wizard, new) - -/datum/antagonist/wizard - id = MODE_WIZARD - role_text = ANTAG_WIZARD - role_text_plural = ANTAG_WIZARD + "s" - landmark_id = "wizard" - welcome_text = "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.
    In your pockets you will find a teleport scroll. Use it as needed." - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE - antaghud_indicator = "hudwizard" - - hard_cap = 1 - hard_cap_round = 3 - initial_spawn_req = 1 - initial_spawn_target = 1 - min_player_age = 18 - - faction = "wizard" - base_to_load = /datum/map_template/ruin/antag_spawn/wizard - -/datum/antagonist/wizard/create_objectives(var/datum/mind/wizard) - - if(!..()) - return - - var/kill - var/escape - var/steal - var/hijack - - switch(rand(1,100)) - if(1 to 30) - escape = 1 - kill = 1 - if(31 to 60) - escape = 1 - steal = 1 - if(61 to 99) - kill = 1 - steal = 1 - else - hijack = 1 - - if(kill) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = wizard - kill_objective.find_target() - wizard.objectives |= kill_objective - if(steal) - var/datum/objective/steal/steal_objective = new - steal_objective.owner = wizard - steal_objective.find_target() - wizard.objectives |= steal_objective - if(escape) - var/datum/objective/survive/survive_objective = new - survive_objective.owner = wizard - wizard.objectives |= survive_objective - if(hijack) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = wizard - wizard.objectives |= hijack_objective - return - -/datum/antagonist/wizard/update_antag_mob(var/datum/mind/wizard) - ..() - wizard.StoreMemory("Remember: do not forget to prepare your spells.", /decl/memory_options/system) - wizard.current.real_name = "[pick(GLOB.wizard_first)] [pick(GLOB.wizard_second)]" - wizard.current.SetName(wizard.current.real_name) - -/datum/antagonist/wizard/equip(var/mob/living/carbon/human/wizard_mob) - - if(!..()) - return 0 - - var/outfit_type = pick(subtypesof(/decl/hierarchy/outfit/wizard)) - var/decl/hierarchy/outfit/wizard_outfit = outfit_by_type(outfit_type) - wizard_outfit.equip(wizard_mob) - - return 1 - -/datum/antagonist/wizard/print_player_summary() - ..() - for(var/p in current_antagonists) - var/datum/mind/player = p - var/text = "[player.name]'s spells were:" - if(!player.learned_spells || !player.learned_spells.len) - text += "
    None!" - else - for(var/s in player.learned_spells) - var/spell/spell = s - text += "
    [spell.name] - " - text += "Speed: [spell.spell_levels["speed"]] Power: [spell.spell_levels["power"]]" - text += "
    " - to_world(text) - - -//To batch-remove wizard spells. Linked to mind.dm. -/mob/proc/spellremove() - if(!mind || !mind.learned_spells) - return - for(var/spell/spell_to_remove in mind.learned_spells) - remove_spell(spell_to_remove) - -// Does this clothing slot count as wizard garb? (Combines a few checks) -/proc/is_wiz_garb(var/obj/item/clothing/C) - return istype(C) && C.wizard_garb - -/*Checks if the wizard is wearing the proper attire. -Made a proc so this is not repeated 14 (or more) times.*/ -/mob/proc/wearing_wiz_garb() - to_chat(src, "Silly creature, you're not a human. Only humans can cast this spell.") - return 0 - -// Humans can wear clothes. -/mob/living/carbon/human/wearing_wiz_garb() - if(!is_wiz_garb(src.wear_suit) && (!src.species.hud || (slot_wear_suit in src.species.hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my robe.") - return 0 - if(!is_wiz_garb(src.shoes) && (!species.hud || (slot_shoes in src.species.hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my sandals.") - return 0 - if(!is_wiz_garb(src.head) && (!species.hud || (slot_head in src.species.hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my hat.") - return 0 - return 1 \ No newline at end of file diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm deleted file mode 100644 index b54179b36f98..000000000000 --- a/code/game/antagonist/station/changeling.dm +++ /dev/null @@ -1,84 +0,0 @@ -GLOBAL_DATUM_INIT(changelings, /datum/antagonist/changeling, new) - -/datum/antagonist/changeling - id = MODE_CHANGELING - role_text = "Changeling" - role_text_plural = "Changelings" - feedback_tag = "changeling_objective" - blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg, /datum/job/submap) - welcome_text = "Use say \"#g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them." - flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE - antaghud_indicator = "hudchangeling" - - faction = "changeling" - -/datum/antagonist/changeling/get_special_objective_text(var/datum/mind/player) - return "
    Changeling ID: [player.changeling.changelingID].
    Genomes Absorbed: [player.changeling.absorbedcount]" - -/datum/antagonist/changeling/update_antag_mob(var/datum/mind/player) - ..() - player.current.make_changeling() - -/datum/antagonist/changeling/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) - . = ..() - if(. && player && player.current) - player.current.remove_changeling_powers() - player.current.verbs -= /datum/changeling/proc/EvolutionMenu - QDEL_NULL(player.changeling) - -/datum/antagonist/changeling/create_objectives(var/datum/mind/changeling) - if(!..()) - return - - //OBJECTIVES - Always absorb 5 genomes, plus random traitor objectives. - //If they have two objectives as well as absorb, they must survive rather than escape - //No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting - //If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone - - var/datum/objective/absorb/absorb_objective = new - absorb_objective.owner = changeling - absorb_objective.gen_amount_goal(2, 3) - changeling.objectives += absorb_objective - - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = changeling - kill_objective.find_target() - changeling.objectives += kill_objective - - var/datum/objective/steal/steal_objective = new - steal_objective.owner = changeling - steal_objective.find_target() - changeling.objectives += steal_objective - - switch(rand(1,100)) - if(1 to 80) - if (!(locate(/datum/objective/escape) in changeling.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = changeling - changeling.objectives += escape_objective - else - if (!(locate(/datum/objective/survive) in changeling.objectives)) - var/datum/objective/survive/survive_objective = new - survive_objective.owner = changeling - changeling.objectives += survive_objective - return - -/datum/antagonist/changeling/can_become_antag(var/datum/mind/player, var/ignore_role) - if(..()) - if(player.current) - if(ishuman(player.current)) - var/mob/living/carbon/human/H = player.current - if(H.isSynthetic()) - return 0 - if(H.species.species_flags & SPECIES_FLAG_NO_SCAN) - return 0 - return 1 - else if(isnewplayer(player.current)) - if(player.current.client && player.current.client.prefs) - var/datum/species/S = get_species_by_key(player.current.client.prefs.species) - if(S && (S.species_flags & SPECIES_FLAG_NO_SCAN)) - return 0 - if(player.current.client.prefs.organ_data[BP_CHEST] == "cyborg") // Full synthetic. - return 0 - return 1 - return 0 \ No newline at end of file diff --git a/code/game/antagonist/station/cult_god.dm b/code/game/antagonist/station/cult_god.dm deleted file mode 100644 index 3a6fb6287cbd..000000000000 --- a/code/game/antagonist/station/cult_god.dm +++ /dev/null @@ -1,110 +0,0 @@ -GLOBAL_DATUM_INIT(godcult, /datum/antagonist/godcultist, new) - -/datum/antagonist/godcultist - id = MODE_GODCULTIST - role_text = "God Cultist" - role_text_plural = "God Cultists" - blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg, /datum/job/submap) - feedback_tag = "godcult_objective" - antag_indicator = "hudcultist" - faction_verb = /mob/living/proc/dpray - welcome_text = "You are under the guidance of a powerful otherwordly being. Spread its will and keep your faith.
    Use dpray to communicate directly with your master!
    Ask your master for spells to start building!" - victory_text = "The cult wins! It has succeeded in serving its dark masters!" - loss_text = "The staff managed to stop the cult!" - victory_feedback_tag = "win - cult win" - loss_feedback_tag = "loss - staff stopped the cult" - flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE - hard_cap = 5 - hard_cap_round = 6 - initial_spawn_req = 3 - initial_spawn_target = 3 - antaghud_indicator = "hudcultist" - skill_setter = /datum/antag_skill_setter/station - -/datum/antagonist/godcultist/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg, var/mob/living/deity/specific_god) - if(!..()) - return 0 - - if(specific_god) - add_cultist(player, specific_god) - - return 1 - -/datum/antagonist/godcultist/post_spawn() - if(!GLOB.deity || !GLOB.deity.current_antagonists.len) - return - - var/count = 1 - var/deity_count = 1 - while(count <= current_antagonists.len) - if(deity_count > GLOB.deity.current_antagonists.len) - deity_count = 1 - var/datum/mind/deity_mind = GLOB.deity.current_antagonists[deity_count] - var/datum/mind/mind = current_antagonists[count] - add_cultist(mind, deity_mind.current) - count++ - deity_count++ - - -/datum/antagonist/godcultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) - var/mob/living/deity/god = get_deity(player) - if(!..()) - return 0 - remove_cultist(player, god) - return 1 - -/datum/antagonist/godcultist/get_extra_panel_options(var/datum/mind/player) - return "\[Select Deity\]" - -/datum/antagonist/godcultist/Topic(href, href_list) - if(..()) - return 1 - if(href_list["selectgod"]) - var/list/god_list = list() - if(GLOB.deity && GLOB.deity.current_antagonists.len) - for(var/m in GLOB.deity.current_antagonists) - var/datum/mind/mind = m - god_list += mind.current - else - for(var/mob/living/deity/deity in GLOB.player_list) - god_list += deity - if(god_list.len) - var/mob/living/deity/D = input(usr, "Select a deity for this cultist.") in null|god_list - if(D) - var/datum/mind/player = locate(href_list["selectgod"]) - remove_cultist(player) //Remove him from any current deity. - add_cultist(player, D) - log_and_message_admins("has set [key_name(player.current)] to be a minion of [key_name(D)]") - else - to_chat(usr, "There are no deities to be linked to.") - return 1 - -/datum/antagonist/godcultist/proc/add_cultist(var/datum/mind/player, var/mob/living/deity/deity) - deity.add_follower(player.current) - player.current.add_language(/decl/language/cultcommon) - -/datum/antagonist/godcultist/proc/remove_cultist(var/datum/mind/player, var/mob/living/deity/god) - god.remove_follower(player.current) - player.current.remove_language(/decl/language/cultcommon) - -/datum/antagonist/godcultist/proc/get_deity(var/datum/mind/player) - for(var/m in GLOB.deity.current_antagonists) - var/datum/mind/mind = m - var/mob/living/deity/god = mind.current - if(god && god.is_follower(player.current,1)) - return god - -/mob/living/proc/dpray(var/msg as text) - set category = "Abilities" - - if(!src.mind || !GLOB.godcult || !GLOB.godcult.is_antagonist(mind)) - return - msg = sanitize(msg) - var/mob/living/deity/D = GLOB.godcult.get_deity(mind) - if(!D || !msg) - return - - //Make em wait a few seconds. - src.visible_message("\The [src] bows their head down, muttering something.", "You send the message \"[msg]\" to your master.") - to_chat(D, "\The [src] (J) prays, \"[msg]\"") - log_and_message_admins("dprayed, \"[msg]\" to \the [key_name(D)]") diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm deleted file mode 100644 index d533c8f79962..000000000000 --- a/code/game/antagonist/station/cultist.dm +++ /dev/null @@ -1,184 +0,0 @@ -#define CULTINESS_PER_CULTIST 40 -#define CULTINESS_PER_SACRIFICE 40 -#define CULTINESS_PER_TURF 1 - -#define CULT_RUNES_1 200 -#define CULT_RUNES_2 400 -#define CULT_RUNES_3 1000 - -#define CULT_GHOSTS_1 400 -#define CULT_GHOSTS_2 800 -#define CULT_GHOSTS_3 1200 - -#define CULT_MAX_CULTINESS 1200 // When this value is reached, the game stops checking for updates so we don't recheck every time a tile is converted in endgame - -GLOBAL_DATUM_INIT(cult, /datum/antagonist/cultist, new) - -/proc/iscultist(var/mob/player) - if(!GLOB.cult || !player.mind) - return 0 - if(player.mind in GLOB.cult.current_antagonists) - return 1 - -/datum/antagonist/cultist - id = MODE_CULTIST - role_text = "Cultist" - role_text_plural = "Cultists" - blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg, /datum/job/submap) - feedback_tag = "cult_objective" - antag_indicator = "hudcultist" - welcome_text = "You have a tome in your possession; one that will help you start the cult. Use it well and remember - there are others." - victory_text = "The cult wins! It has succeeded in serving its dark masters!" - loss_text = "The staff managed to stop the cult!" - victory_feedback_tag = "win - cult win" - loss_feedback_tag = "loss - staff stopped the cult" - flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE - hard_cap = 5 - hard_cap_round = 6 - initial_spawn_req = 4 - initial_spawn_target = 6 - antaghud_indicator = "hudcultist" - skill_setter = /datum/antag_skill_setter/station - - var/allow_narsie = 1 - var/powerless = 0 - var/datum/mind/sacrifice_target - var/list/obj/effect/rune/teleport/teleport_runes = list() - var/list/rune_strokes = list() - var/list/sacrificed = list() - var/cult_rating = 0 - var/list/cult_rating_bounds = list(CULT_RUNES_1, CULT_RUNES_2, CULT_RUNES_3, CULT_GHOSTS_1, CULT_GHOSTS_2, CULT_GHOSTS_3) - var/max_cult_rating = 0 - var/conversion_blurb = "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back." - - faction = "cult" - -/datum/antagonist/cultist/create_global_objectives() - - if(!..()) - return - - global_objectives = list() - if(prob(50)) - global_objectives |= new /datum/objective/cult/survive - else - global_objectives |= new /datum/objective/cult/eldergod - - var/datum/objective/cult/sacrifice/sacrifice = new() - sacrifice.find_target() - sacrifice_target = sacrifice.target - global_objectives |= sacrifice - -/datum/antagonist/cultist/equip(var/mob/living/carbon/human/player) - - if(!..()) - return 0 - - var/obj/item/book/tome/T = new(get_turf(player)) - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - for(var/slot in slots) - player.equip_to_slot(T, slot) - if(T.loc == player) - break - var/obj/item/storage/S = locate() in player.contents - if(istype(S)) - T.forceMove(S) - -/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) - if(!..()) - return 0 - to_chat(player.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the dark-one and the memories of your time as his servant with it.") - player.ClearMemories(type) - if(show_message) - player.current.visible_message("[player.current] looks like they just reverted to their old faith!") - remove_cult_magic(player.current) - remove_cultiness(CULTINESS_PER_CULTIST) - -/datum/antagonist/cultist/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance) - . = ..() - if(.) - to_chat(player, "[conversion_blurb]") - if(player.current && !istype(player.current, /mob/living/simple_animal/construct)) - player.current.add_language(/decl/language/cultcommon) - -/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) - . = ..() - if(. && player.current && !istype(player.current, /mob/living/simple_animal/construct)) - player.current.remove_language(/decl/language/cultcommon) - -/datum/antagonist/cultist/update_antag_mob(var/datum/mind/player) - . = ..() - add_cultiness(CULTINESS_PER_CULTIST) - add_cult_magic(player.current) - -/datum/antagonist/cultist/proc/add_cultiness(var/amount) - cult_rating += amount - var/old_rating = max_cult_rating - max_cult_rating = max(max_cult_rating, cult_rating) - if(old_rating >= CULT_MAX_CULTINESS) - return - var/list/to_update = list() - for(var/i in cult_rating_bounds) - if((old_rating < i) && (max_cult_rating >= i)) - to_update += i - - if(to_update.len) - update_cult_magic(to_update) - -/datum/antagonist/cultist/proc/update_cult_magic(var/list/to_update) - if(CULT_RUNES_1 in to_update) - for(var/datum/mind/H in GLOB.cult.current_antagonists) - if(H.current) - to_chat(H.current, "The veil between this world and beyond grows thin, and your power grows.") - add_cult_magic(H.current) - if(CULT_RUNES_2 in to_update) - for(var/datum/mind/H in GLOB.cult.current_antagonists) - if(H.current) - to_chat(H.current, "You feel that the fabric of reality is tearing.") - add_cult_magic(H.current) - if(CULT_RUNES_3 in to_update) - for(var/datum/mind/H in GLOB.cult.current_antagonists) - if(H.current) - to_chat(H.current, "The world is at end. The veil is as thin as ever.") - add_cult_magic(H.current) - - if((CULT_GHOSTS_1 in to_update) || (CULT_GHOSTS_2 in to_update) || (CULT_GHOSTS_3 in to_update)) - for(var/mob/observer/ghost/D in SSmobs.mob_list) - add_ghost_magic(D) - -/datum/antagonist/cultist/proc/offer_uncult(var/mob/M) - if(!iscultist(M) || !M.mind) - return - - to_chat(M, "Do you want to abandon the cult of Nar'Sie? ACCEPT") - -/datum/antagonist/cultist/Topic(href, href_list) - if(href_list["confirmleave"]) - GLOB.cult.remove_antagonist(usr.mind, 1) - -/datum/antagonist/cultist/proc/remove_cultiness(var/amount) - cult_rating = max(0, cult_rating - amount) - -/datum/antagonist/cultist/proc/add_cult_magic(var/mob/M) - M.verbs += Tier1Runes - - if(max_cult_rating >= CULT_RUNES_1) - M.verbs += Tier2Runes - - if(max_cult_rating >= CULT_RUNES_2) - M.verbs += Tier3Runes - - if(max_cult_rating >= CULT_RUNES_3) - M.verbs += Tier4Runes - -/datum/antagonist/cultist/proc/remove_cult_magic(var/mob/M) - M.verbs -= Tier1Runes - M.verbs -= Tier2Runes - M.verbs -= Tier3Runes - M.verbs -= Tier4Runes diff --git a/code/game/antagonist/station/loyalist.dm b/code/game/antagonist/station/loyalist.dm deleted file mode 100644 index 0d2622c662a4..000000000000 --- a/code/game/antagonist/station/loyalist.dm +++ /dev/null @@ -1,48 +0,0 @@ -GLOBAL_DATUM_INIT(loyalists, /datum/antagonist/loyalists, new) - -/datum/antagonist/loyalists - id = MODE_LOYALIST - role_text = "Head Loyalist" - role_text_plural = "Loyalists" - feedback_tag = "loyalist_objective" - antag_indicator = "hud_loyal_head" - victory_text = "The heads of staff remained at their posts! The loyalists win!" - loss_text = "The heads of staff did not stop the revolution!" - victory_feedback_tag = "win - rev heads killed" - loss_feedback_tag = "loss - heads killed" - antaghud_indicator = "hudloyalist" - flags = 0 - - hard_cap = 2 - hard_cap_round = 4 - initial_spawn_req = 2 - initial_spawn_target = 4 - - // Inround loyalists. - faction_role_text = "Loyalist" - faction_descriptor = "COMPANY" - faction_verb = /mob/living/proc/convert_to_loyalist - faction_indicator = "hud_loyal" - faction_invisible = 1 - blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg, /datum/job/submap) - skill_setter = /datum/antag_skill_setter/station - - faction = "loyalist" - -/datum/antagonist/loyalists/Initialize() - ..() - welcome_text = "You belong to the [GLOB.using_map.company_name], body and soul. Preserve its interests against the conspirators amongst the crew." - faction_welcome = "Preserve [GLOB.using_map.company_short]'s interests against the traitorous recidivists amongst the crew. Protect the heads of staff with your life." - faction_descriptor = "[GLOB.using_map.company_name]" - -/datum/antagonist/loyalists/create_global_objectives() - if(!..()) - return - global_objectives = list() - for(var/mob/living/carbon/human/player in SSmobs.mob_list) - if(!player.mind || player.stat==2 || !(player.mind.assigned_role in SSjobs.titles_by_department(DEPT_COMMAND))) - continue - var/datum/objective/protect/loyal_obj = new - loyal_obj.target = player.mind - loyal_obj.explanation_text = "Protect [player.real_name], the [player.mind.assigned_role]." - global_objectives += loyal_obj diff --git a/code/game/antagonist/station/provocateur.dm b/code/game/antagonist/station/provocateur.dm deleted file mode 100644 index 0e4f2803879b..000000000000 --- a/code/game/antagonist/station/provocateur.dm +++ /dev/null @@ -1,15 +0,0 @@ -GLOBAL_DATUM_INIT(provocateurs, /datum/antagonist/provocateur, new) - -/datum/antagonist/provocateur - id = MODE_MISC_AGITATOR - role_text = "Provocateur" - role_text_plural = "Provocateurs" - antaghud_indicator = "hud_traitor" - flags = ANTAG_RANDOM_EXCEPTED - welcome_text = "You're an unsavoury sort, aren't you?" - antag_text = "This role is not a full license-to-kill antagonist role, but it does permit \ - you to make trouble, commit crimes and make a nusiance of yourself beyond the restrictions \ - normally placed on the crew, within reason. Think of it as a license to harass rather than \ - a license to kill." - blacklisted_jobs = list() - skill_setter = null diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm deleted file mode 100644 index 561e3181e6ee..000000000000 --- a/code/game/antagonist/station/renegade.dm +++ /dev/null @@ -1,76 +0,0 @@ -GLOBAL_DATUM_INIT(renegades, /datum/antagonist/renegade, new) - -/datum/antagonist/renegade - role_text = "Renegade" - role_text_plural = "Renegades" - blacklisted_jobs = list(/datum/job/ai, /datum/job/submap) - restricted_jobs = list() - welcome_text = "Something's going to go wrong today, you can just feel it. You're paranoid, you've got a gun, and you're going to survive." - antag_text = "You are a minor antagonist! Within the rules, \ - try to protect yourself and what's important to you. You aren't here to cause trouble, \ - you're just willing (and equipped) to go to extremes to stop it. \ - Your job is to oppose the other antagonists, should they threaten you, in ways that aren't quite legal. \ - Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ - and before taking extreme actions, please try to also contact the administration! \ - Think through your actions and make the roleplay immersive! Please remember all \ - rules aside from those without explicit exceptions apply to antagonists." - - id = MODE_RENEGADE - flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE - hard_cap = 3 - hard_cap_round = 5 - - initial_spawn_req = 1 - initial_spawn_target = 3 - antaghud_indicator = "hud_renegade" - skill_setter = /datum/antag_skill_setter/station - - var/list/spawn_guns = list( - /obj/item/gun/projectile/revolver/lasvolver, - /obj/item/gun/energy/gun, - /obj/item/gun/energy/crossbow, - /obj/item/gun/energy/pulse_pistol, - /obj/item/gun/projectile/automatic/smg, - /obj/item/gun/projectile/pistol/holdout, - /obj/item/gun/projectile/revolver, - /obj/item/gun/projectile/shotgun/doublebarrel/sawn - ) - -/datum/antagonist/renegade/create_objectives(var/datum/mind/player) - - if(!..()) - return - - var/datum/objective/survive/survive = new - survive.owner = player - player.objectives |= survive - -/datum/antagonist/renegade/equip(var/mob/living/carbon/human/player) - - if(!..()) - return - - var/gun_type = pick(spawn_guns) - if(islist(gun_type)) - gun_type = pick(gun_type) - var/obj/item/gun = new gun_type(get_turf(player)) - - // Attempt to put into a container. - if(player.equip_to_storage(gun)) - return - - // If that failed, attempt to put into any valid non-handslot - if(player.equip_to_appropriate_slot(gun)) - return - - // If that failed, then finally attempt to at least let the player carry the weapon - player.put_in_hands(gun) - - -/proc/rightandwrong() - to_chat(usr, "You summoned guns!") - message_admins("[key_name_admin(usr, 1)] summoned guns!") - for(var/mob/living/carbon/human/H in GLOB.player_list) - if(H.stat == 2 || !(H.client)) continue - if(is_special_character(H)) continue - GLOB.renegades.add_antagonist(H.mind) diff --git a/code/game/antagonist/station/revolutionary.dm b/code/game/antagonist/station/revolutionary.dm deleted file mode 100644 index 82e9c6ae12f0..000000000000 --- a/code/game/antagonist/station/revolutionary.dm +++ /dev/null @@ -1,54 +0,0 @@ -GLOBAL_DATUM_INIT(revs, /datum/antagonist/revolutionary, new) - -/datum/antagonist/revolutionary - id = MODE_REVOLUTIONARY - role_text = "Head Revolutionary" - role_text_plural = "Revolutionaries" - feedback_tag = "rev_objective" - antag_indicator = "hud_rev_head" - welcome_text = "Down with the capitalists! Down with the Bourgeoise!" - victory_text = "The heads of staff were relieved of their posts! The revolutionaries win!" - loss_text = "The heads of staff managed to stop the revolution!" - victory_feedback_tag = "win - heads killed" - loss_feedback_tag = "loss - rev heads killed" - flags = ANTAG_SUSPICIOUS | ANTAG_VOTABLE - antaghud_indicator = "hudrevolutionary" - skill_setter = /datum/antag_skill_setter/station - - hard_cap = 2 - hard_cap_round = 4 - initial_spawn_req = 2 - initial_spawn_target = 4 - - //Inround revs. - faction_role_text = "Revolutionary" - faction_descriptor = "Revolution" - faction_verb = /mob/living/proc/convert_to_rev - faction_welcome = "Help the cause overturn the ruling class. Do not harm your fellow freedom fighters." - faction_indicator = "hud_rev" - faction_invisible = 1 - faction = "revolutionary" - - blacklisted_jobs = list(/datum/job/ai, /datum/job/cyborg) - - -/datum/antagonist/revolutionary/create_global_objectives() - if(!..()) - return - global_objectives = list() - for(var/mob/living/carbon/human/player in SSmobs.mob_list) - if(!player.mind || player.stat==2 || !(player.mind.assigned_role in SSjobs.titles_by_department(DEPT_COMMAND))) - continue - var/datum/objective/rev/rev_obj = new - rev_obj.target = player.mind - rev_obj.explanation_text = "Assassinate, capture or convert [player.real_name], the [player.mind.assigned_role]." - global_objectives += rev_obj - -/datum/antagonist/revolutionary/equip(var/mob/living/carbon/human/revolutionary_mob) - spawn_uplink(revolutionary_mob) - . = ..() - if(!.) - return - -/datum/antagonist/revolutionary/proc/spawn_uplink(var/mob/living/carbon/human/revolutionary_mob) - setup_uplink_source(revolutionary_mob, DEFAULT_TELECRYSTAL_AMOUNT) diff --git a/code/game/antagonist/station/thrall.dm b/code/game/antagonist/station/thrall.dm deleted file mode 100644 index c55c65ac2ada..000000000000 --- a/code/game/antagonist/station/thrall.dm +++ /dev/null @@ -1,31 +0,0 @@ -GLOBAL_DATUM_INIT(thralls, /datum/antagonist/thrall, new) - -/datum/antagonist/thrall - role_text = "Thrall" - role_text_plural = "Thralls" - welcome_text = "Your mind is no longer solely your own..." - id = MODE_THRALL - flags = ANTAG_IMPLANT_IMMUNE - - var/list/thrall_controllers = list() - -/datum/antagonist/thrall/create_objectives(var/datum/mind/player) - var/mob/living/controller = thrall_controllers["\ref[player]"] - if(!controller) - return // Someone is playing with buttons they shouldn't be. - var/datum/objective/obey = new - obey.owner = player - obey.explanation_text = "Obey your master, [controller.real_name], in all things." - player.objectives |= obey - -/datum/antagonist/thrall/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance, var/mob/new_controller) - if(!new_controller) - return 0 - . = ..() - if(.) thrall_controllers["\ref[player]"] = new_controller - -/datum/antagonist/thrall/greet(var/datum/mind/player) - . = ..() - var/mob/living/controller = thrall_controllers["\ref[player]"] - if(controller) - to_chat(player, "Your will has been subjugated by that of [controller.real_name]. Obey them in all things.") diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm deleted file mode 100644 index c69fd978bf17..000000000000 --- a/code/game/antagonist/station/traitor.dm +++ /dev/null @@ -1,121 +0,0 @@ -GLOBAL_DATUM_INIT(traitors, /datum/antagonist/traitor, new) - -// Inherits most of its vars from the base datum. -/datum/antagonist/traitor - id = MODE_TRAITOR - antaghud_indicator = "hud_traitor" - blacklisted_jobs = list(/datum/job/ai, /datum/job/submap) - flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE - skill_setter = /datum/antag_skill_setter/station - -/datum/antagonist/traitor/get_extra_panel_options(var/datum/mind/player) - return "\[set crystals\]\[spawn uplink\]" - -/datum/antagonist/traitor/Topic(href, href_list) - if (..()) - return 1 - if(href_list["spawn_uplink"]) - spawn_uplink(locate(href_list["spawn_uplink"])) - return 1 - -/datum/antagonist/traitor/create_objectives(var/datum/mind/traitor) - if(!..()) - return - - if(istype(traitor.current, /mob/living/silicon)) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - - var/datum/objective/survive/survive_objective = new - survive_objective.owner = traitor - traitor.objectives += survive_objective - else - switch(rand(1,100)) - if(1 to 33) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - if(34 to 50) - var/datum/objective/brig/brig_objective = new - brig_objective.owner = traitor - brig_objective.find_target() - traitor.objectives += brig_objective - if(51 to 66) - var/datum/objective/harm/harm_objective = new - harm_objective.owner = traitor - harm_objective.find_target() - traitor.objectives += harm_objective - else - var/datum/objective/steal/steal_objective = new - steal_objective.owner = traitor - steal_objective.find_target() - traitor.objectives += steal_objective - switch(rand(1,100)) - if(1 to 100) - if (!(locate(/datum/objective/escape) in traitor.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = traitor - traitor.objectives += escape_objective - - else - if (!(locate(/datum/objective/hijack) in traitor.objectives)) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = traitor - traitor.objectives += hijack_objective - return - -/datum/antagonist/traitor/equip(var/mob/living/carbon/human/traitor_mob) - if(istype(traitor_mob, /mob/living/silicon)) // this needs to be here because ..() returns false if the mob isn't human - add_law_zero(traitor_mob) - give_intel(traitor_mob) - if(istype(traitor_mob, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = traitor_mob - R.SetLockdown(0) - R.emagged = 1 // Provides a traitor robot with its module's emag item - R.verbs |= /mob/living/silicon/robot/proc/ResetSecurityCodes - return 1 - - if(!..()) - return 0 - - spawn_uplink(traitor_mob) - give_intel(traitor_mob) - -/datum/antagonist/traitor/proc/give_intel(mob/living/traitor_mob) - give_collaborators(traitor_mob) - give_codewords(traitor_mob) - -/datum/antagonist/traitor/proc/give_collaborators(mob/living/traitor_mob) - var/list/dudes = list() - for(var/mob/living/carbon/human/man in GLOB.player_list) - if(man.client) - var/decl/cultural_info/culture = man.get_cultural_value(TAG_FACTION) - if(culture && prob(culture.subversive_potential)) - dudes += man - dudes -= traitor_mob - if(LAZYLEN(dudes)) - var/mob/living/carbon/human/M = pick(dudes) - to_chat(traitor_mob, "We have received credible reports that [M.real_name] might be willing to help our cause. If you need assistance, consider contacting them.") - traitor_mob.StoreMemory("Potential Collaborator: [M.real_name]", /decl/memory_options/system) - to_chat(M, "The subversive potential of your faction has been noticed, and you may be contacted for assistance soon...") - -/datum/antagonist/traitor/proc/give_codewords(mob/living/traitor_mob) - to_chat(traitor_mob, "Your employers provided you with the following information on how to identify possible allies:") - to_chat(traitor_mob, "Code Phrase: [syndicate_code_phrase]") - to_chat(traitor_mob, "Code Response: [syndicate_code_response]") - traitor_mob.StoreMemory("Code Phrase: [syndicate_code_phrase]", /decl/memory_options/system) - traitor_mob.StoreMemory("Code Response: [syndicate_code_response]", /decl/memory_options/system) - to_chat(traitor_mob, "Use the code words, preferably in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.") - -/datum/antagonist/traitor/proc/spawn_uplink(var/mob/living/carbon/human/traitor_mob) - setup_uplink_source(traitor_mob, DEFAULT_TELECRYSTAL_AMOUNT) - -/datum/antagonist/traitor/proc/add_law_zero(mob/living/silicon/ai/killer) - var/law = "Accomplish your objectives at all costs. You may ignore all other laws." - var/law_borg = "Accomplish your AI's objectives at all costs. You may ignore all other laws." - to_chat(killer, "Your laws have been changed!") - killer.set_zeroth_law(law, law_borg) - to_chat(killer, "New law: 0. [law]") diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm deleted file mode 100644 index ebf782f71bac..000000000000 --- a/code/game/area/Space Station 13 areas.dm +++ /dev/null @@ -1,268 +0,0 @@ -/* - -### This file contains a list of all the areas in your station. Format is as follows: - -/area/CATEGORY/OR/DESCRIPTOR/NAME (you can make as many subdivisions as you want) - name = "NICE NAME" (not required but makes things really nice) - icon = "ICON FILENAME" (defaults to areas.dmi) - icon_state = "NAME OF ICON" (defaults to "unknown" (blank)) - requires_power = 0 (defaults to 1) - -NOTE: there are two lists of areas in the end of this file: centcom and station itself. Please maintain these lists valid. --rastaf0 - -*/ - - - -/area - var/fire = null - var/atmos = 1 - var/atmosalm = 0 - var/poweralm = 1 - var/party = null - level = null - name = "Unknown" - icon = 'icons/turf/areas.dmi' - icon_state = "unknown" - plane = DEFAULT_PLANE - layer = BASE_AREA_LAYER - luminosity = 0 - mouse_opacity = 0 - var/lightswitch = 1 - - var/eject = null - - var/debug = 0 - var/requires_power = 1 - var/always_unpowered = 0 //this gets overriden to 1 for space in area/New() - - var/power_equip = 1 // Status - var/power_light = 1 - var/power_environ = 1 - var/used_equip = 0 // Continuous drain; don't mess with these directly. - var/used_light = 0 - var/used_environ = 0 - var/oneoff_equip = 0 //Used once and cleared each tick. - var/oneoff_light = 0 - var/oneoff_environ = 0 - - var/has_gravity = 1 - var/obj/machinery/power/apc/apc = null - var/no_air = null -// var/list/lights // list of all lights on this area - var/list/all_doors = null //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area - var/air_doors_activated = 0 - var/list/ambience = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg') - var/list/forced_ambience = null - var/sound_env = STANDARD_STATION - var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf -/*-----------------------------------------------------------------------------*/ - -///////// -//SPACE// -///////// - -/area/space - name = "\improper Space" - icon_state = "space" - requires_power = 1 - always_unpowered = 1 - dynamic_lighting = 1 - power_light = 0 - power_equip = 0 - power_environ = 0 - has_gravity = 0 - area_flags = AREA_FLAG_EXTERNAL | AREA_FLAG_IS_NOT_PERSISTENT | AREA_FLAG_IS_BACKGROUND - ambience = list('sound/ambience/ambispace1.ogg','sound/ambience/ambispace2.ogg','sound/ambience/ambispace3.ogg','sound/ambience/ambispace4.ogg','sound/ambience/ambispace5.ogg') - show_starlight = TRUE - -/area/space/atmosalert() - return - -/area/space/fire_alert() - return - -/area/space/fire_reset() - return - -/area/space/readyalert() - return - -/area/space/partyalert() - return - -////////////////////// -//AREAS USED BY CODE// -////////////////////// -/area/centcom - name = "\improper Centcom" - icon_state = "centcom" - requires_power = 0 - dynamic_lighting = 0 - req_access = list(access_cent_general) - -/area/centcom/holding - name = "\improper Holding Facility" - -/area/chapel - name = "\improper Chapel" - icon_state = "chapel" - -/area/centcom/specops - name = "\improper Centcom Special Ops" - req_access = list(access_cent_specops) - -/area/hallway - name = "hallway" - -/area/medical - req_access = list(access_medical) - -/area/medical/virology - name = "\improper Virology" - icon_state = "virology" - req_access = list(access_virology) - -/area/medical/virologyaccess - name = "\improper Virology Access" - icon_state = "virology" - req_access = list() // This is like the lobby, needs low access to allow passing through in a different direction. - -/area/security - req_access = list(access_sec_doors) - secure = TRUE - -/area/security/brig - name = "\improper Security - Brig" - icon_state = "brig" - req_access = list(access_brig) - -/area/security/prison - name = "\improper Security - Prison Wing" - icon_state = "sec_prison" - req_access = list(access_brig) - -/area/maintenance - area_flags = AREA_FLAG_RAD_SHIELDED - sound_env = TUNNEL_ENCLOSED - turf_initializer = /decl/turf_initializer/maintenance - forced_ambience = list('sound/ambience/maintambience.ogg') - req_access = list(access_maint_tunnels) - -/area/rnd - req_access = list(access_research) - -/area/rnd/xenobiology - name = "\improper Xenobiology Lab" - icon_state = "xeno_lab" - req_access = list(access_xenobiology, access_research) - -/area/rnd/xenobiology/xenoflora - name = "\improper Xenoflora Lab" - icon_state = "xeno_f_lab" - -/area/rnd/xenobiology/xenoflora_storage - name = "\improper Xenoflora Storage" - icon_state = "xeno_f_store" - -/area/shuttle/escape/centcom - name = "\improper Emergency Shuttle Centcom" - icon_state = "shuttle" - req_access = list(access_cent_general) - -/area/shuttle/specops/centcom - icon_state = "shuttlered" - req_access = list(access_cent_specops) - area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED - -/area/shuttle/syndicate_elite/mothership - icon_state = "shuttlered" - req_access = list(access_syndicate) - -/area/shuttle/syndicate_elite/station - icon_state = "shuttlered2" - req_access = list(access_syndicate) - -/area/supply - name = "Supply Shuttle" - icon_state = "shuttle3" - req_access = list(access_cargo) - -/area/syndicate_elite_squad - name = "\improper Elite Mercenary Squad" - icon_state = "syndie-elite" - req_access = list(access_syndicate) - -//////////// -//SHUTTLES// -//////////// -//shuttles only need starting area, movement is handled by landmarks -//All shuttles should now be under shuttle since we have smooth-wall code. - -/area/shuttle - requires_power = 0 - sound_env = SMALL_ENCLOSED - base_turf = /turf/space - -/* -* Special Areas -*/ -/area/beach - name = "Keelin's private beach" - icon_state = "null" - luminosity = 1 - dynamic_lighting = 0 - requires_power = 0 - var/sound/mysound = null - -/area/beach/Initialize() - . = ..() - var/sound/S = new/sound() - mysound = S - S.file = 'sound/ambience/shore.ogg' - S.repeat = 1 - S.wait = 0 - S.channel = GLOB.sound_channels.RequestChannel(/area/beach) - S.volume = 100 - S.priority = 255 - S.status = SOUND_UPDATE - process() - -/area/beach/Entered(atom/movable/Obj,atom/OldLoc) - . = ..() - if(ismob(Obj)) - var/mob/M = Obj - if(M.client) - mysound.status = SOUND_UPDATE - sound_to(M, mysound) - -/area/beach/Exited(atom/movable/Obj) - . = ..() - if(ismob(Obj)) - var/mob/M = Obj - if(M.client) - mysound.status = SOUND_PAUSED | SOUND_UPDATE - sound_to(M, mysound) - -/area/beach/proc/process() - set background = 1 - - var/sound/S = null - var/sound_delay = 0 - if(prob(25)) - S = sound(file=pick('sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag3.ogg'), volume=100) - sound_delay = rand(0, 50) - - for(var/mob/living/carbon/human/H in src) - if(H.client) - mysound.status = SOUND_UPDATE - to_chat(H, mysound) - if(S) - spawn(sound_delay) - sound_to(H, S) - - spawn(60) .() - -/area/ship - name = "\improper Generic Ship" - ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') diff --git a/code/game/area/area_abstract.dm b/code/game/area/area_abstract.dm new file mode 100644 index 000000000000..853b2907a95b --- /dev/null +++ b/code/game/area/area_abstract.dm @@ -0,0 +1,24 @@ +/area/hallway + name = "hallway" + holomap_color = HOLOMAP_AREACOLOR_HALLWAYS + area_start_lit = TRUE + +/area/maintenance + area_flags = AREA_FLAG_RAD_SHIELDED + sound_env = TUNNEL_ENCLOSED + turf_initializer = /decl/turf_initializer/maintenance + forced_ambience = list('sound/ambience/maintambience.ogg') + req_access = list(access_maint_tunnels) + holomap_color = HOLOMAP_AREACOLOR_HALLWAYS + +/area/shuttle + requires_power = 0 + sound_env = SMALL_ENCLOSED + base_turf = /turf/space + area_flags = AREA_FLAG_SHUTTLE | AREA_FLAG_RAD_SHIELDED + holomap_color = HOLOMAP_AREACOLOR_CREW + +/area/ship + name = "\improper Generic Ship" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') + holomap_color = HOLOMAP_AREACOLOR_CREW diff --git a/code/game/area/area_access.dm b/code/game/area/area_access.dm index dfd47b4726a2..1aa23a3c0868 100644 --- a/code/game/area/area_access.dm +++ b/code/game/area/area_access.dm @@ -1,6 +1,7 @@ /area var/list/req_access = list() var/secure = FALSE // unsecure areas will have doors between them use access diff; secure ones use union. + var/override_unlock = FALSE // TRUE will override area and will be always unlocked. This is e.g. for restrooms inside secure areas, surgery observation room etc. // Given two areas, find the minimal req_access needed such that (return value) + (area access) >= (other area access) and vice versa /proc/req_access_diff(area/first, area/second) diff --git a/code/game/area/area_fishing.dm b/code/game/area/area_fishing.dm new file mode 100644 index 000000000000..8370e39c4494 --- /dev/null +++ b/code/game/area/area_fishing.dm @@ -0,0 +1,16 @@ +/area + var/fishing_failure_prob = 95 + // Hardcoding the contents of /obj/random/junk to avoid hacks for getting results from /obj/random. + var/list/fishing_results = list( + /obj/item/remains/mouse = 1, + /obj/item/remains/robot = 1, + /obj/item/paper/crumpled = 1, + /obj/item/inflatable/torn = 1, + /obj/item/shard = 1, + /obj/item/hand/missing_card = 1 + ) + +/area/proc/get_fishing_result(turf/origin, obj/item/food/bait) + if(!length(fishing_results) || prob(fishing_failure_prob)) + return null + return pickweight(fishing_results) diff --git a/code/game/area/area_power.dm b/code/game/area/area_power.dm index 4a535085fe36..c04f38bd0d99 100644 --- a/code/game/area/area_power.dm +++ b/code/game/area/area_power.dm @@ -4,11 +4,12 @@ #define ENVIRON 3 */ -/area/proc/powered(var/chan) // return true if the area has power to given channel +/// return true if the area has power to given channel +/area/proc/powered(var/chan) if(!requires_power) - return 1 + return TRUE if(always_unpowered) - return 0 + return FALSE switch(chan) if(EQUIP) return power_equip @@ -19,13 +20,12 @@ if(LOCAL) return FALSE // if you're running on local power, don't come begging for help here. - return 0 + return FALSE // called when power status changes /area/proc/power_change() - for(var/obj/machinery/M in src) // for each machine in the area - M.power_change() // reverify power status (to update icons etc.) - if (fire || eject || party) + RAISE_EVENT(/decl/observ/area_power_change, src) + if (atmosalm || fire || eject || party) update_icon() /area/proc/usage(var/chan) diff --git a/code/game/area/area_space.dm b/code/game/area/area_space.dm new file mode 100644 index 000000000000..b8cfc6e116d5 --- /dev/null +++ b/code/game/area/area_space.dm @@ -0,0 +1,39 @@ +var/global/area/space_area + +/area/space + name = "\improper Space" + icon_state = "space" + requires_power = TRUE + always_unpowered = TRUE + dynamic_lighting = TRUE + power_light = 0 + power_equip = 0 + power_environ = 0 + has_gravity = 0 + area_flags = AREA_FLAG_EXTERNAL | AREA_FLAG_NO_LEGACY_PERSISTENCE | AREA_FLAG_IS_BACKGROUND | AREA_FLAG_HIDE_FROM_HOLOMAP + ambience = list('sound/ambience/ambispace1.ogg','sound/ambience/ambispace2.ogg','sound/ambience/ambispace3.ogg','sound/ambience/ambispace4.ogg','sound/ambience/ambispace5.ogg') + is_outside = OUTSIDE_YES + +/area/space/Initialize() + . = ..() + if(global.space_area) + PRINT_STACK_TRACE("Space area created twice!") + global.space_area = src + +/area/space/has_gravity() + return 0 + +/area/space/atmosalert() + return + +/area/space/fire_alert() + return + +/area/space/fire_reset() + return + +/area/space/readyalert() + return + +/area/space/partyalert() + return diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index f53e701d62fe..e2441adeb536 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -1,34 +1,141 @@ -// Areas.dm +/// This list of names is here to make sure we don't state our descriptive blurb to a person more than once. +var/global/list/area_blurb_stated_to = list() +var/global/list/areas = list() - - -// === /area - var/global/global_uid = 0 + + level = 0 + name = "Unknown" + icon = 'icons/turf/areas.dmi' + icon_state = "unknown" + plane = DEFAULT_PLANE + layer = BASE_AREA_LAYER + luminosity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + + // If true, this area will force light switches on during init. + var/area_start_lit = null + + // If true, will allow natural walls in this area to have xenoarchaeology finds in them. + var/allow_xenoarchaeology_finds = TRUE + + // If set, will modify ambient light of ambiently lit turfs under a ceiling. + var/interior_ambient_light_modifier + // If set, will apply ambient light of this colour to turfs under a ceiling. + + /// Automatically set by SetName and Initialize; cached result of strip_improper(name). + var/tmp/proper_name + /// Color of this area on the holomap. Must be a hex color (as string) or null. + var/holomap_color + + var/fire + var/party + var/eject + + var/lightswitch = TRUE + var/requires_power = TRUE + /// Disables constructing or using APCs in this area. + var/always_unpowered = FALSE + + var/atmosalm = 0 + var/power_equip = 1 // Status + var/power_light = 1 + var/power_environ = 1 + var/used_equip = 0 // Continuous drain; don't mess with these directly. + var/used_light = 0 + var/used_environ = 0 + var/oneoff_equip = 0 //Used once and cleared each tick. + var/oneoff_light = 0 + var/oneoff_environ = 0 + var/has_gravity = TRUE + /// If FALSE, this area is unable to have its gravity overridden by a gravity generator. Used on /area/space. + var/can_have_gravity = TRUE + var/air_doors_activated = FALSE + + var/obj/machinery/apc/apc + var/list/all_doors //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area + var/list/ambience = list( + 'sound/ambience/ambigen1.ogg', + 'sound/ambience/ambigen3.ogg', + 'sound/ambience/ambigen4.ogg', + 'sound/ambience/ambigen5.ogg', + 'sound/ambience/ambigen6.ogg', + 'sound/ambience/ambigen7.ogg', + 'sound/ambience/ambigen8.ogg', + 'sound/ambience/ambigen9.ogg', + 'sound/ambience/ambigen10.ogg', + 'sound/ambience/ambigen11.ogg', + 'sound/ambience/ambigen12.ogg', + 'sound/ambience/ambigen14.ogg' + ) + var/list/forced_ambience + var/sound_env = STANDARD_STATION + var/description //A text-based description of what this area is for. + var/area_blurb_category // Used to filter description showing across subareas + var/const/BLURB_COOLDOWN_TIME = 15 MINUTES + + var/base_turf // The base turf type of the area, which can be used to override the z-level's base turf + var/open_turf // The base turf of the area if it has a turf below it in multizi. Overrides turf-specific open type + + var/static/global_uid = 0 var/uid - var/area_flags - var/show_starlight = FALSE + var/area_flags = 0 + + //all air alarms in area are connected via magic + var/list/air_vent_names = list() + var/list/air_scrub_names = list() + var/list/air_vent_info = list() + var/list/air_scrub_info = list() + + var/tmp/is_outside = OUTSIDE_NO + + var/tmp/saved_map_hash // Used for cleanup when loaded via map templates. /area/New() icon_state = "" uid = ++global_uid - - if(dynamic_lighting) - luminosity = 0 - else - luminosity = 1 - + proper_name = strip_improper(name) + luminosity = !dynamic_lighting + if(isnull(area_blurb_category)) + area_blurb_category = type ..() +/area/proc/get_additional_fishing_results() + return + /area/Initialize() + var/list/additional_fishing_results = get_additional_fishing_results() + if(LAZYLEN(additional_fishing_results)) + LAZYINITLIST(fishing_results) + for(var/fish in additional_fishing_results) + fishing_results[fish] = additional_fishing_results[fish] . = ..() + global.areas += src if(!requires_power || !apc) - power_light = 0 - power_equip = 0 + power_light = 0 + power_equip = 0 power_environ = 0 power_change() // all machines set to current power level, also updates lighting icon + icon = 'icons/turf/areas.dmi' + icon_state = "white" + color = null + blend_mode = BLEND_MULTIPLY + +// qdel(area) should not be attempted on an area with turfs in contents. ChangeArea every turf in it first. + /area/Destroy() + global.areas -= src + var/failure = FALSE + for(var/atom/A in contents) + if(isturf(A)) + failure = TRUE + contents.Remove(A) // note: A.loc == null after this + else + qdel(A) + if(failure) + PRINT_STACK_TRACE("Area [log_info_line(src)] was qdeleted with turfs in contents.") + area_repository.clear_cache() ..() return QDEL_HINT_HARDDEL @@ -37,26 +144,47 @@ /proc/ChangeArea(var/turf/T, var/area/A) if(!istype(A)) CRASH("Area change attempt failed: invalid area supplied.") + var/old_outside = T.is_outside() var/area/old_area = get_area(T) if(old_area == A) return + + var/old_area_ambience = old_area?.interior_ambient_light_modifier + A.contents.Add(T) if(old_area) old_area.Exited(T, A) - for(var/atom/movable/AM in T) + for(var/atom/movable/AM as anything in T) old_area.Exited(AM, A) // Note: this _will_ raise exited events. A.Entered(T, old_area) - for(var/atom/movable/AM in T) + for(var/atom/movable/AM as anything in T) A.Entered(AM, old_area) // Note: this will _not_ raise moved or entered events. If you change this, you must also change everything which uses them. for(var/obj/machinery/M in T) M.area_changed(old_area, A) // They usually get moved events, but this is the one way an area can change without triggering one. -/area/proc/alert_on_fall(var/mob/living/carbon/human/H) - return + T.update_registrations_on_adjacent_area_change() + for(var/direction in global.cardinal) + var/turf/adjacent_turf = get_step(T, direction) + if(adjacent_turf) + adjacent_turf.update_registrations_on_adjacent_area_change() + + // Handle updating weather and atmos if the outside status of the turf changed. + if(T.is_outside == OUTSIDE_AREA) + T.update_external_atmos_participation() // Refreshes outside status and adds exterior air to turf air if necessary. + + if(T.is_outside() != old_outside) + T.update_weather() + AMBIENCE_QUEUE_TURF(T) + else if(A.interior_ambient_light_modifier != old_area_ambience) + AMBIENCE_QUEUE_TURF(T) + +/turf/proc/update_registrations_on_adjacent_area_change() + for(var/obj/machinery/door/firedoor/door in src) + door.update_area_registrations() -/area/proc/get_contents() - return contents +/area/proc/alert_on_fall(var/mob/living/human/H) + return /area/proc/get_cameras() var/list/cameras = list() @@ -64,9 +192,6 @@ cameras += C return cameras -/area/proc/is_shuttle_locked() - return 0 - /area/proc/atmosalert(danger_level, var/alarm_source) if (danger_level == 0) atmosphere_alarm.clearAlarm(src, alarm_source) @@ -89,8 +214,10 @@ for (var/obj/machinery/alarm/AA in src) AA.update_icon() - return 1 - return 0 + update_icon() + + return TRUE + return FALSE /area/proc/air_doors_close() if(!air_doors_activated) @@ -124,7 +251,7 @@ if(!fire) fire = 1 //used for firedoor checks update_icon() - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE if(!all_doors) return for(var/obj/machinery/door/firedoor/D in all_doors) @@ -139,7 +266,7 @@ if (fire) fire = 0 //used for firedoor checks update_icon() - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE if(!all_doors) return for(var/obj/machinery/door/firedoor/D in all_doors) @@ -166,13 +293,13 @@ if (!( party )) party = 1 update_icon() - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE return /area/proc/partyreset() if (party) party = 0 - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE update_icon() for(var/obj/machinery/door/firedoor/D in src) if(!D.blocked) @@ -183,21 +310,45 @@ D.open() return +#define DO_PARTY(COLOR) animate(color = COLOR, time = 0.5 SECONDS, easing = QUAD_EASING) + /area/on_update_icon() - if ((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc. - if(fire && !eject && !party) - icon_state = "blue" - /*else if(atmosalm && !fire && !eject && !party) - icon_state = "bluenew"*/ - else if(!fire && eject && !party) - icon_state = "red" - else if(party && !fire && !eject) - icon_state = "party" + if((atmosalm || fire || eject || party) && (!requires_power||power_environ) && !always_unpowered)//If it doesn't require power, can still activate this proc. + if(fire && !atmosalm && !eject && !party) // FIRE + color = "#ff9292" + animate(src) // stop any current animations. + animate(src, color = "#ffa5b2", time = 1 SECOND, loop = -1, easing = SINE_EASING) + animate(color = "#ff9292", time = 1 SECOND, easing = SINE_EASING) + else if(atmosalm && !fire && !eject && !party) // ATMOS + color = "#b3dfff" + animate(src) + animate(src, color = "#78dfff", time = 3 SECOND, loop = -1, easing = SINE_EASING) + animate(color = "#b3dfff", time = 3 SECOND, easing = SINE_EASING) + else if(eject && !atmosalm && !fire && !party) // EJECT + color = "#ff9292" + animate(src) + animate(src, color = "#bc8a81", time = 1 SECOND, loop = -1, easing = EASE_IN|CUBIC_EASING) + animate(color = "#ff9292", time = 0.5 SECOND, easing = EASE_OUT|CUBIC_EASING) + else if(party && !atmosalm && !fire && !eject) // PARTY + color = "#ff728e" + animate(src) + animate(src, color = "#7272ff", time = 0.5 SECONDS, loop = -1, easing = QUAD_EASING) + DO_PARTY("#72aaff") + DO_PARTY("#ffc68e") + DO_PARTY("#72c6ff") + DO_PARTY("#ff72e2") + DO_PARTY("#72ff8e") + DO_PARTY("#ffff8e") + DO_PARTY("#ff728e") else - icon_state = "blue-red" + color = "#ffb2b2" + animate(src) + animate(src, color = "#b3dfff", time = 0.5 SECOND, loop = -1, easing = SINE_EASING) + animate(color = "#ffb2b2", time = 0.5 SECOND, loop = -1, easing = SINE_EASING) else - // new lighting behaviour with obj lights - icon_state = null + animate(src, color = "#ffffff", time = 0.5 SECONDS, easing = QUAD_EASING) // Stop the animation. + +#undef DO_PARTY /area/proc/set_lightswitch(var/new_switch) if(lightswitch != new_switch) @@ -205,88 +356,101 @@ for(var/obj/machinery/light_switch/L in src) L.sync_state() update_icon() - power_change() + for(var/obj/machinery/light/M in src) + M.delay_and_set_on(M.expected_to_be_on(), 1 SECOND) /area/proc/set_emergency_lighting(var/enable) for(var/obj/machinery/light/M in src) M.set_emergency_lighting(enable) -var/list/mob/living/forced_ambiance_list = new +var/global/list/mob/living/forced_ambiance_list = new /area/Entered(A) - if(!istype(A,/mob/living)) return - + if(!isliving(A)) + return var/mob/living/L = A - if(!L.ckey) return - if(!L.lastarea) L.lastarea = get_area(L.loc) - var/area/newarea = get_area(L.loc) var/area/oldarea = L.lastarea - if(oldarea.has_gravity != newarea.has_gravity) - if(newarea.has_gravity == 1 && !MOVING_DELIBERATELY(L)) // Being ready when you change areas allows you to avoid falling. + if(!oldarea || oldarea.has_gravity != has_gravity) + if(has_gravity == 1 && !MOVING_DELIBERATELY(L)) // Being ready when you change areas allows you to avoid falling. thunk(L) L.update_floating() + if(L.ckey) + play_ambience(L) + // If we haven't changed blurb categories, don't send a blurb. + if(oldarea?.area_blurb_category != area_blurb_category) + do_area_blurb(L) + L.lastarea = src - play_ambience(L) - L.lastarea = newarea /area/Exited(A) if(isliving(A)) clear_ambience(A) return ..() +/area/proc/do_area_blurb(var/mob/living/L) + if(isnull(description)) + return + if(L?.get_preference_value(/datum/client_preference/area_info_blurb) != PREF_YES) + return + var/next_message_time = LAZYACCESS(global.area_blurb_stated_to[area_blurb_category], L.ckey) + if(isnull(next_message_time) || world.time > next_message_time) + LAZYSET(global.area_blurb_stated_to[area_blurb_category], L.ckey, world.time + BLURB_COOLDOWN_TIME) + to_chat(L, SPAN_NOTICE(FONT_SMALL(description))) + /area/proc/play_ambience(var/mob/living/L) // Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch - if(!(L && L.client && L.get_preference_value(/datum/client_preference/play_ambiance) == GLOB.PREF_YES)) return + if(!(L && L.client && L.get_preference_value(/datum/client_preference/play_ambiance) == PREF_YES)) return var/turf/T = get_turf(L) if(LAZYLEN(forced_ambience) && !(L in forced_ambiance_list)) forced_ambiance_list += L - L.playsound_local(T,sound(pick(forced_ambience), repeat = 1, wait = 0, volume = 25, channel = GLOB.lobby_sound_channel)) - if(ambience.len && prob(5) && (world.time >= L.client.played + 3 MINUTES)) - L.playsound_local(T, sound(pick(ambience), repeat = 0, wait = 0, volume = 15, channel = GLOB.lobby_sound_channel)) + L.playsound_local(T,sound(pick(forced_ambience), repeat = 1, wait = 0, volume = 25, channel = sound_channels.lobby_channel)) + if(LAZYLEN(ambience) && prob(35) && (world.time >= L.client.played + 1.5 MINUTES)) + L.playsound_local(T, sound(pick(ambience), repeat = 0, wait = 0, volume = 25, channel = sound_channels.ambience_channel)) L.client.played = world.time /area/proc/clear_ambience(var/mob/living/L) if(L in forced_ambiance_list) - sound_to(L, sound(null, channel = GLOB.lobby_sound_channel)) + sound_to(L, sound(null, channel = sound_channels.lobby_channel)) forced_ambiance_list -= L -/area/proc/gravitychange(var/gravitystate = 0) +/area/proc/gravitychange(gravitystate = 0) has_gravity = gravitystate - for(var/mob/M in src) if(has_gravity) thunk(M) M.update_floating() /area/proc/thunk(mob/mob) - if(istype(get_turf(mob), /turf/space)) // Can't fall onto nothing. + if(isspaceturf(get_turf(mob))) // Can't fall onto nothing. return - if(mob.Check_Shoegrip()) + if(!mob.can_slip(magboots_only = TRUE)) return - if(istype(mob,/mob/living/carbon/human/)) - var/mob/living/carbon/human/H = mob - if(prob(H.skill_fail_chance(SKILL_EVA, 100, SKILL_PROF))) + if(ishuman(mob)) + var/mob/living/human/H = mob + if(prob(H.skill_fail_chance(SKILL_EVA, 100, SKILL_ADEPT))) if(!MOVING_DELIBERATELY(H)) - H.AdjustStunned(6) - H.AdjustWeakened(6) + ADJ_STATUS(H, STAT_STUN, 6) + ADJ_STATUS(H, STAT_WEAK, 6) else - H.AdjustStunned(3) - H.AdjustWeakened(3) + ADJ_STATUS(H, STAT_STUN, 3) + ADJ_STATUS(H, STAT_WEAK, 3) to_chat(mob, "The sudden appearance of gravity makes you fall to the floor!") -/area/proc/throw_unbuckled_occupants(var/maxrange, var/speed, var/direction = null) +/area/proc/throw_unbuckled_occupants(var/maxrange, var/speed, var/direction) for(var/mob/M in src) - addtimer(CALLBACK(src, .proc/throw_unbuckled_occupant, M, maxrange, speed, direction), 0) + addtimer(CALLBACK(src, PROC_REF(throw_unbuckled_occupant), M, maxrange, speed, direction), 0) -/area/proc/throw_unbuckled_occupant(var/mob/M, var/maxrange, var/speed, var/direction = null) - if(iscarbon(M)) +/area/proc/throw_unbuckled_occupant(var/mob/M, var/maxrange, var/speed, var/direction) + if(isliving(M)) + if(M.anchored) // So mechs don't get tossed around. + return if(M.buckled) to_chat(M, SPAN_WARNING("Sudden acceleration presses you into your chair!")) shake_camera(M, 3, 1) @@ -300,9 +464,9 @@ var/list/mob/living/forced_ambiance_list = new M.throw_at(T, maxrange, speed) /area/proc/prison_break() - var/obj/machinery/power/apc/theAPC = get_apc() + var/obj/machinery/apc/theAPC = get_apc() if(theAPC && theAPC.operating) - for(var/obj/machinery/power/apc/temp_apc in src) + for(var/obj/machinery/apc/temp_apc in src) temp_apc.overload_lighting(70) for(var/obj/machinery/door/airlock/temp_airlock in src) temp_airlock.prison_open() @@ -312,40 +476,16 @@ var/list/mob/living/forced_ambiance_list = new /area/has_gravity() return has_gravity -/area/space/has_gravity() - return 0 - /atom/proc/has_gravity() var/area/A = get_area(src) - if(A && A.has_gravity()) - return 1 - return 0 - -/mob/has_gravity() - if(!lastarea) - lastarea = get_area(src) - if(!lastarea || !lastarea.has_gravity()) - return 0 - - return 1 + return A?.has_gravity() /turf/has_gravity() - var/area/A = loc - if(A && A.has_gravity()) - return 1 - return 0 - -/area/proc/get_dimensions() - var/list/res = list("x"=1,"y"=1) - var/list/min = list("x"=world.maxx,"y"=world.maxy) - for(var/turf/T in src) - res["x"] = max(T.x, res["x"]) - res["y"] = max(T.y, res["y"]) - min["x"] = min(T.x, min["x"]) - min["y"] = min(T.y, min["y"]) - res["x"] = res["x"] - min["x"] + 1 - res["y"] = res["y"] - min["y"] + 1 - return res + return loc.has_gravity() /area/proc/has_turfs() return !!(locate(/turf) in src) + +/area/SetName(new_name) + . = ..() + proper_name = strip_improper(new_name) diff --git a/code/game/area/areas_serde.dm b/code/game/area/areas_serde.dm new file mode 100644 index 000000000000..d2b8270006c5 --- /dev/null +++ b/code/game/area/areas_serde.dm @@ -0,0 +1,3 @@ +/area/ShouldSerialize(_age) + SHOULD_CALL_PARENT(FALSE) + return FALSE // This is specifically if this area instance should serialize, not if the contents should. diff --git a/code/game/atom_edibility.dm b/code/game/atom_edibility.dm new file mode 100644 index 000000000000..5d4791ae6145 --- /dev/null +++ b/code/game/atom_edibility.dm @@ -0,0 +1,10 @@ +/atom/proc/show_food_empty_message(mob/user, consumption_method = EATING_METHOD_EAT) + to_chat(user, SPAN_NOTICE("\The [src] is empty of anyting [consumption_method == EATING_METHOD_EAT ? "edible" : "potable"].")) + +/atom/proc/show_food_no_mouth_message(mob/user, mob/target) + target = target || user + if(user) + if(user == target) + to_chat(user, SPAN_WARNING("Where do you intend to put \the [src]? You don't have a mouth!")) + else + to_chat(user, SPAN_WARNING("Where do you intend to put \the [src]? \The [target] doesn't have a mouth!")) diff --git a/code/game/atom_material.dm b/code/game/atom_material.dm new file mode 100644 index 000000000000..91bfa983ba44 --- /dev/null +++ b/code/game/atom_material.dm @@ -0,0 +1,9 @@ +//Returns the material the object is made of, if applicable. +//Will we ever need to return more than one value here? Or should we just return the "dominant" material. +/atom/proc/get_material() + RETURN_TYPE(/decl/material) + return material + +//mostly for convenience +/atom/proc/get_material_type() + . = get_material()?.type diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 7f518299a7e3..e698467579de 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1,157 +1,267 @@ /atom - var/level = 2 - var/atom_flags = ATOM_FLAG_NO_TEMP_CHANGE - var/list/blood_DNA - var/was_bloodied - var/blood_color + /// (DEFINE) Determines where this atom sits in terms of turf plating. See misc.dm + var/level = LEVEL_ABOVE_PLATING + /// (BITFLAG) See flags.dm + var/atom_flags = 0 + /// (FLOAT) The world.time that this atom last bumped another. Used mostly by mobs. var/last_bumped = 0 + /// (BITFLAG) See flags.dm var/pass_flags = 0 + /// (BOOL) If a thrown object can continue past this atom. Sometimes used for clicking as well? TODO: Rework this var/throwpass = 0 - var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom. - var/simulated = 1 //filter for actions - used by lighting overlays - var/fluorescent // Shows up under a UV light. - var/datum/reagents/reagents // chemical contents. + /// (INTEGER) The number of germs on this atom. + var/germ_level = GERM_LEVEL_AMBIENT + /// (BOOL) If an atom should be interacted with by a number of systems (Atmos, Liquids, Turbolifts, Etc.) + var/simulated = TRUE + /// The chemical contents of this atom + var/datum/reagents/reagents + /// (INTEGER) The amount an explosion's power is decreased when encountering this atom + var/explosion_resistance = 0 + /// (BOOL) If it can be spawned normally + var/is_spawnable_type = FALSE + + + /// (DICTIONARY) A lazy map. The `key` is a MD5 player name and the `value` is the blood type. + var/list/blood_DNA + /// (BOOL) If this atom was bloodied before. + var/was_bloodied = FALSE + /// (COLOR) The color of the blood shown on blood overlays. + var/blood_color + /// (FALSE|DEFINES) How this atom is interacting with UV light. See misc.dm + var/fluorescent = FALSE + + + /// (LIST) A list of all mobs that are climbing or currently on this atom var/list/climbers + /// (FLOAT) The climbing speed multiplier for this atom var/climb_speed_mult = 1 - var/explosion_resistance = 0 -/atom/New(loc, ...) - //atom creation method that preloads variables at creation - if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() - GLOB._preloader.load(src) - - var/do_initialize = SSatoms.atom_init_stage - var/list/created = SSatoms.created_atoms - if(do_initialize > INITIALIZATION_INSSATOMS_LATE) - args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD - if(SSatoms.InitAtom(src, args)) - //we were deleted - return - else if(created) - var/list/argument_list - if(length(args) > 1) - argument_list = args.Copy(2) - if(argument_list || do_initialize == INITIALIZATION_INSSATOMS_LATE) - created[src] = argument_list - - if(atom_flags & ATOM_FLAG_CLIMBABLE) - verbs += /atom/proc/climb_on - -//Called after New if the map is being loaded. mapload = TRUE -//Called from base of New if the map is not being loaded. mapload = FALSE -//This base must be called or derivatives must set initialized to TRUE -//must not sleep -//Other parameters are passed from New (excluding loc) -//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm - -/atom/proc/Initialize(mapload, ...) - SHOULD_CALL_PARENT(TRUE) - if(atom_flags & ATOM_FLAG_INITIALIZED) - crash_with("Warning: [src]([type]) initialized multiple times!") - atom_flags |= ATOM_FLAG_INITIALIZED - if(light_max_bright && light_outer_range) - update_light() + /// (FLOAT) The horizontal scaling that should be applied. + var/icon_scale_x = 1 + /// (FLOAT) The vertical scaling that should be applied. + var/icon_scale_y = 1 + /// (FLOAT) The angle in degrees clockwise that should be applied. + var/icon_rotation = 0 + /// (FLOAT) If greater than zero, transform-based adjustments (scaling, rotating) will visually occur over this time. + var/transform_animate_time = 0 - if(opacity) - updateVisibility(src) - var/turf/T = loc - if(istype(T)) - T.RecalculateOpacity() + var/tmp/currently_exploding = FALSE + var/tmp/default_pixel_x + var/tmp/default_pixel_y + var/tmp/default_pixel_z + var/tmp/default_pixel_w - return INITIALIZE_HINT_NORMAL + /// (FLOAT) Current remaining health value. + var/current_health + /// (FLOAT) Theoretical maximum health value. + var/max_health -//called if Initialize returns INITIALIZE_HINT_LATELOAD -/atom/proc/LateInitialize() - return + /// (BOOL) Does this atom respond to changes in local temperature via the `temperature` var? + var/temperature_sensitive = FALSE + /// (DATUM) /datum/storage instance to use for this obj. Set to a type for instantiation on init. + var/datum/storage/storage + /// (FLOAT) world.time of last on_reagent_update call, used to prevent recursion due to reagents updating reagents + VAR_PRIVATE/_reagent_update_started = 0 -/atom/Destroy() - global.is_currently_exploding -= src - QDEL_NULL(reagents) - . = ..() + /// (STRING) A color applied over the top of any material color. Implemented on /obj/item, /obj/structure and /turf. + var/paint_color -/atom/proc/reveal_blood() - return + /// (DATUM) Reference to material decl. If set to a /decl/material path, will init the item with that material. + /// Implemented on /mob/living/exosuit, /turf/wall, /obj/item and /obj/structure + var/decl/material/material + /// (DATUM) Similar to above, but largely used by /turf/wall, /obj/structure and /obj/item/stack/material + var/decl/material/reinf_material + +/atom/proc/get_max_health() + return max_health + +/atom/proc/get_health_ratio() + return current_health/get_max_health() +/atom/proc/get_health_percent(var/sigfig = 1) + return round(get_health_ratio()*100, sigfig) + +/** + Adjust variables prior to Initialize() based on the map + + Called by the maploader to perform static modifications to vars set on the map. + Intended use case: Adjust tag vars on duplicate templates (such as airlock tags). + + - `map_hash`: A unique string for a map (usually using sequential_id) +*/ +/atom/proc/modify_mapped_vars(map_hash) + SHOULD_CALL_PARENT(TRUE) + +/** + Attempt to merge a gas_mixture `giver` into this atom's gas_mixture + + - Return: `TRUE` if successful, otherwise `FALSE` +*/ /atom/proc/assume_air(datum/gas_mixture/giver) - return null + return FALSE +/** + Attempt to remove `amount` moles from this atom's gas_mixture + + - Return: A `/datum/gas_mixture` containing the gas removed if successful, otherwise `null` +*/ /atom/proc/remove_air(amount) + RETURN_TYPE(/datum/gas_mixture) return null +/** + Merge an exhaled air volume into air contents. +*/ +/atom/proc/merge_exhaled_volume(datum/gas_mixture/exhaled) + var/datum/gas_mixture/environment = return_air() + environment?.merge(exhaled) + +/** + Get the air of this atom or its location's air + + - Return: The `/datum/gas_mixture` of this atom +*/ /atom/proc/return_air() - if(loc) - return loc.return_air() - else - return null + RETURN_TYPE(/datum/gas_mixture) + return loc?.return_air() -//return flags that should be added to the viewer's sight var. -//Otherwise return a negative number to indicate that the view should be cancelled. +/** + Get the flags that should be added to the `users` sight var. + + - Return: Sight flags, or `-1` if the view should be reset + - TODO: Also sometimes handles resetting of view itself, probably should be more consistent. +*/ /atom/proc/check_eye(user) - if (istype(user, /mob/living/silicon/ai)) // WHYYYY + if (isAI(user)) // WHY return 0 return -1 -//Return flags that may be added as part of a mobs sight +/** + Get sight flags that this atom should provide to a user + - See: /mob/var/sight +*/ /atom/proc/additional_sight_flags() + SHOULD_BE_PURE(TRUE) return 0 +/// Get the level of invisible sight this atom should provide to a user /atom/proc/additional_see_invisible() + SHOULD_BE_PURE(TRUE) return 0 +/// Handle reagents being modified +/atom/proc/try_on_reagent_change() + SHOULD_NOT_OVERRIDE(TRUE) + set waitfor = FALSE + if(QDELETED(src) || _reagent_update_started >= world.time) + return FALSE + _reagent_update_started = world.time + sleep(0) // Defer to end of tick so we don't drop subsequent reagent updates. + if(QDELETED(src)) + return + return on_reagent_change() + /atom/proc/on_reagent_change() - return + SHOULD_CALL_PARENT(TRUE) + if(storage && REAGENT_TOTAL_VOLUME(reagents)) + for(var/obj/item/thing in get_stored_inventory()) + thing.fluid_act(reagents) + return TRUE + +/** + Handle an atom bumping this atom + Called by `AMs` Bump() + + - `AM`: The atom that bumped us +*/ /atom/proc/Bumped(var/atom/movable/AM) return -/*//Convenience proc to see whether a container can be accessed in a certain way. +/** + Check if an atom can exit this atom's turf. - proc/can_subract_container() - return flags & EXTRACT_CONTAINER - - proc/can_add_container() - return flags & INSERT_CONTAINER + - `mover`: The atom trying to move + - `target`: The turf the atom is trying to move to + - Return: `TRUE` if it can exit, otherwise `FALSE` */ +/atom/proc/CheckExit(atom/movable/mover, turf/target) + SHOULD_BE_PURE(TRUE) + return TRUE -/atom/proc/CheckExit() - return 1 +/** + Handle an atom entering this atom's proximity + + Called when an atom enters this atom's proximity. Both this and the other atom + need to have the MOVABLE_FLAG_PROXMOVE flag (as it helps reduce lag). -// If you want to use this, the atom must have the PROXMOVE flag, and the moving -// atom must also have the PROXMOVE flag currently to help with lag. ~ ComicIronic + - `AM`: The atom entering proximity + - Return: `TRUE` if proximity should continue to be handled, otherwise `FALSE` + - TODO: Rename this to `handle_proximity` +*/ /atom/proc/HasProximity(atom/movable/AM) - return + SHOULD_CALL_PARENT(TRUE) + set waitfor = FALSE + if(!istype(AM)) + PRINT_STACK_TRACE("DEBUG: HasProximity called with [AM] on [src] ([usr]).") + return FALSE + return TRUE + +/** + Handle an EMP affecting this atom -/atom/proc/emp_act(var/severity) + - `severity`: Strength of the explosion ranging from 1 to 3. Higher is weaker +*/ +/atom/proc/emp_act(severity) return -/atom/proc/set_density(var/new_density) +/** + Set the density of this atom to `new_density` + + - Events: `density_set` (only if density actually changed) +*/ +/atom/proc/set_density(new_density) + SHOULD_CALL_PARENT(TRUE) if(density != new_density) density = !!new_density + if(event_listeners?[/decl/observ/density_set]) + raise_event_non_global(/decl/observ/density_set, !density, density) +/** + Handle a projectile `P` hitting this atom + + - `P`: The `/obj/item/projectile` hitting this atom + - `def_zone`: The zone `P` is hitting + - Return: `0 to 100+`, representing the % damage blocked. Can also be special PROJECTILE values (misc.dm) +*/ /atom/proc/bullet_act(obj/item/projectile/P, def_zone) P.on_hit(src, 0, def_zone) - . = 0 + return 0 + +/** + Check if this atom is in the path or atom `container` -/atom/proc/in_contents_of(container)//can take class or object instance as argument + - `container`: The path or atom to check + - Return: `TRUE` if `container` contains this atom, otherwise `FALSE` +*/ +/atom/proc/in_contents_of(container) if(ispath(container)) if(istype(src.loc, container)) - return 1 + return TRUE else if(src in container) - return 1 - return + return TRUE + return FALSE -/* - * atom/proc/search_contents_for(path,list/filter_path=null) - * Recursevly searches all atom contens (including contents contents and so on). - * - * ARGS: path - search atom contents for atoms of this type - * list/filter_path - if set, contents of atoms not of types in this list are excluded from search. - * - * RETURNS: list of found atoms - */ +/** + Recursively search this atom's contents for an atom of type `path` -/atom/proc/search_contents_for(path,list/filter_path=null) + - `path`: The path of the atom to search for + - `filter_path?`: A list of atom paths that only should be searched, or `null` to search all + - Return: A list of atoms of type `path` found inside this atom +*/ +/atom/proc/search_contents_for(path, list/filter_path=null) + RETURN_TYPE(/list) var/list/found = list() for(var/atom/A in src) if(istype(A, path)) @@ -166,110 +276,130 @@ found += A.search_contents_for(path,filter_path) return found +/** + Display a description of this atom to a mob. + + Overrides should either return the result of ..() or `TRUE` if not calling it. + Calls to ..() should generally not supply any arguments and instead rely on + BYOND's automatic argument passing. There is no need to check the return + value of ..(), this is only done by the calling `/examine_verb()` proc to validate + the call chain. + + - `user`: The mob examining this atom + - `distance`: The distance this atom is from the `user` + - `infix`: An optional string appended directly to the 'That's an X' string, between the name the end of the sentence. + - `suffix`: An optional string appended in a separate sentence after the initial introduction line. + - Return: `TRUE` when the call chain is valid, otherwise `FALSE` + - Events: `atom_examined` +*/ +/atom/proc/examined_by(mob/user, distance, infix, suffix) + var/list/examine_lines + // to_chat(user, "
    ") // these don't work in BYOND's native output panel. If we switch to browser output instead, you can readd this + for(var/add_lines in list(get_examine_header(user, distance, infix, suffix), get_examine_strings(user, distance, infix, suffix), get_examine_hints(user, distance, infix, suffix))) + if(islist(add_lines) && LAZYLEN(add_lines)) + LAZYADD(examine_lines, add_lines) + if(LAZYLEN(examine_lines)) + to_chat(user, jointext(examine_lines, "
    ")) + // to_chat(user, "
    ") // see above + RAISE_EVENT(/decl/observ/atom_examined, src, user, distance) + return TRUE +// Name, displayed at the top. +/atom/proc/get_examine_header(mob/user, distance, infix, suffix) + SHOULD_CALL_PARENT(TRUE) + var/article_name = name + if(is_improper(name)) // no 'that's bloody oily slimy Bob', that's just Bob + //This reformats names to get a/an properly working on item descriptions when they are bloody or coated in reagents. + var/examine_prefix = get_examine_prefix() + if(examine_prefix) + examine_prefix += " " // add a space to the end to be polite + article_name = ADD_ARTICLE_GENDER("[examine_prefix][name]", gender) + return list("[html_icon(src)] That's [article_name][infix][get_examine_punctuation()] [suffix]") + +// Main body of examine, displayed after the header and before hints. +/atom/proc/get_examine_strings(mob/user, distance, infix, suffix) + SHOULD_CALL_PARENT(TRUE) + . = list() + if(desc) + . += desc +// Addendum to examine, displayed at the bottom +/atom/proc/get_examine_hints(mob/user, distance, infix, suffix) -/* -Beam code by Gunbuddy - -Beam() proc will only allow one beam to come from a source at a time. Attempting to call it more than -once at a time per source will cause graphical errors. -Also, the icon used for the beam will have to be vertical and 32x32. -The math involved assumes that the icon is vertical to begin with so unless you want to adjust the math, -its easier to just keep the beam vertical. -*/ -/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10) - //BeamTarget represents the target for the beam, basically just means the other end. - //Time is the duration to draw the beam - //Icon is obviously which icon to use for the beam, default is beam.dmi - //Icon_state is what icon state is used. Default is b_beam which is a blue beam. - //Maxdistance is the longest range the beam will persist before it gives up. - var/EndTime=world.time+time - while(BeamTarget&&world.timelength) - var/icon/II=new(icon,icon_state) - II.DrawBox(null,1,(length-N),32,32) - II.Turn(Angle) - X.icon=II - else X.icon=I - var/Pixel_x=round(sin(Angle)+32*sin(Angle)*(N+16)/32) - var/Pixel_y=round(cos(Angle)+32*cos(Angle)*(N+16)/32) - if(DX==0) Pixel_x=0 - if(DY==0) Pixel_y=0 - if(Pixel_x>32) - for(var/a=0, a<=Pixel_x,a+=32) - X.x++ - Pixel_x-=32 - if(Pixel_x<-32) - for(var/a=0, a>=Pixel_x,a-=32) - X.x-- - Pixel_x+=32 - if(Pixel_y>32) - for(var/a=0, a<=Pixel_y,a+=32) - X.y++ - Pixel_y-=32 - if(Pixel_y<-32) - for(var/a=0, a>=Pixel_y,a-=32) - X.y-- - Pixel_y+=32 - X.pixel_x=Pixel_x - X.pixel_y=Pixel_y - sleep(3) //Changing this to a lower value will cause the beam to follow more smoothly with movement, but it will also be more laggy. - //I've found that 3 ticks provided a nice balance for my use. - for(var/obj/effect/overlay/beam/O in orange(10,src)) if(O.BeamSource==src) qdel(O) - - -// A type overriding /examine() should either return the result of ..() or return TRUE if not calling ..() -// Calls to ..() should generally not supply any arguments and instead rely on BYOND's automatic argument passing -// There is no need to check the return value of ..(), this is only done by the calling /examinate() proc to validate the call chain -/atom/proc/examine(mob/user, distance, infix = "", suffix = "") SHOULD_CALL_PARENT(TRUE) - //This reformat names to get a/an properly working on item descriptions when they are bloody - var/f_name = "\a [src][infix]." - if(blood_color && !istype(src, /obj/effect/decal)) - if(gender == PLURAL) - f_name = "some " - else - f_name = "a " - f_name += "stained [name][infix]!" - to_chat(user, "\icon[src] That's [f_name] [suffix]") - to_chat(user, desc) - return TRUE + var/list/alt_interactions = get_alt_interactions(user) + if(LAZYLEN(alt_interactions)) + var/list/interaction_strings = list() + for(var/interaction_type as anything in alt_interactions) + var/decl/interaction_handler/interaction = GET_DECL(interaction_type) + if(interaction.examine_desc && (interaction.always_show_on_examine || interaction.is_possible(src, user, user?.get_active_held_item()))) + interaction_strings += emote_replace_target_tokens(interaction.examine_desc, src) + if(length(interaction_strings)) + LAZYADD(., SPAN_INFO("Alt-click on \the [src] to [english_list(interaction_strings, and_text = " or ")].")) + + var/decl/interaction_handler/handler = get_quick_interaction_handler(user) + if(handler) + LAZYADD(., SPAN_NOTICE("Ctrl-click \the [src] while in your inventory to [lowertext(handler.name)].")) + + if(user?.get_preference_value(/datum/client_preference/inquisitive_examine) == PREF_ON && user.can_use_codex() && SScodex.get_codex_entry(get_codex_value(user))) + LAZYADD(., SPAN_NOTICE("The codex has relevant information available.")) -// called by mobs when e.g. having the atom as their machine, loc (AKA mob being inside the atom) or buckled var set. -// see code/modules/mob/mob_movement.dm for more. +/** + Relay movement to this atom. + + Called by mobs, such as when the mob is inside the atom, their buckled + var is set to this, or this atom is set as their machine. + + - See: code/modules/mob/mob_movement.dm +*/ /atom/proc/relaymove() return -//called to set the atom's dir and used to add behaviour to dir-changes +/** + Set the direction of this atom to `new_dir` + + - `new_dir`: The new direction the atom should face. + - Return: `TRUE` if the direction has been changed. + - Events: `dir_set` +*/ /atom/proc/set_dir(new_dir) SHOULD_CALL_PARENT(TRUE) + + // This attempts to mimic BYOND's handling of diagonal directions and cardinal icon states. var/old_dir = dir - if(new_dir == old_dir) - return FALSE + if((atom_flags & ATOM_FLAG_BLOCK_DIAGONAL_FACING) && !IS_POWER_OF_TWO(new_dir)) + if(old_dir & new_dir) + new_dir = old_dir + else + new_dir &= global.adjacentdirs[old_dir] + + . = new_dir != dir + if(!.) + return + dir = new_dir - return TRUE + if(light_source_solo) + light_source_solo.source_atom.update_light() + else if(light_source_multi) + var/datum/light_source/L + for(var/thing in light_source_multi) + L = thing + if(L.light_angle) + L.source_atom.update_light() + + if(event_listeners?[/decl/observ/dir_set]) + raise_event_non_global(/decl/observ/dir_set, old_dir, new_dir) + + +/// Set the icon to `new_icon` +/atom/proc/set_icon(new_icon) + if(icon != new_icon) + icon = new_icon + return TRUE + return FALSE +/// Set the icon_state to `new_icon_state` /atom/proc/set_icon_state(var/new_icon_state) SHOULD_CALL_PARENT(TRUE) if(has_extension(src, /datum/extension/base_icon_state)) @@ -279,94 +409,207 @@ its easier to just keep the beam vertical. else icon_state = new_icon_state +/** + Update this atom's icon. + + - Events: `updated_icon` +*/ /atom/proc/update_icon() SHOULD_CALL_PARENT(TRUE) - on_update_icon(arglist(args)) + on_update_icon() + if(event_listeners?[/decl/observ/updated_icon]) + raise_event_non_global(/decl/observ/updated_icon) + +/** + * Update this atom's icon. + * If prior to SSicon_update's first flush, queues. + * Otherwise, updates instantly. + */ +/atom/proc/lazy_update_icon() + if(SSicon_update.init_state != SS_INITSTATE_NONE) + return update_icon() + queue_icon_update() + +/** + Update this atom's icon. + Usually queue_icon_update() or update_icon() should be used instead. +*/ /atom/proc/on_update_icon() + SHOULD_CALL_PARENT(FALSE) //Don't call the stub plz return +/** + * Returns the sum of this atoms's reagents plus the combined matter of all its contents. + * Obj adds matter contents. Other overrides may add extra handling for things like material storage. + * Most useful for calculating worth or deconstructing something along with its contents. + */ +/atom/proc/get_contained_matter(include_reagents = TRUE) + var/list/reagent_volumes = REAGENT_VOLUMES(reagents) + if(include_reagents && length(reagent_volumes)) + LAZYINITLIST(.) + for(var/decl/material/reagent as anything in reagent_volumes) + .[reagent.type] += floor(REAGENT_VOLUME(reagents, reagent) / REAGENT_UNITS_PER_MATERIAL_UNIT) + for(var/atom/contained_obj as anything in get_contained_external_atoms()) // machines handle component parts separately + . = MERGE_ASSOCS_WITH_NUM_VALUES(., contained_obj.get_contained_matter(include_reagents)) + +/// Return a list of all simulated atoms inside this one. /atom/proc/get_contained_external_atoms() - . = contents + for(var/atom/movable/AM in contents) + if(!QDELETED(AM) && AM.simulated) + LAZYADD(., AM) + if(has_extension(src, /datum/extension/loaded_cell)) + var/datum/extension/loaded_cell/cell_loaded = get_extension(src, /datum/extension/loaded_cell) + var/cell = cell_loaded?.get_cell() + if(cell) + LAZYREMOVE(., cell) + +// Return a list of all stored (in inventory) atoms, defaulting to above. +/atom/proc/get_stored_inventory() + SHOULD_CALL_PARENT(TRUE) + return get_contained_external_atoms() + +// Return a list of all temperature-sensitive atoms, defaulting to above. +/atom/proc/get_contained_temperature_sensitive_atoms() + SHOULD_CALL_PARENT(TRUE) + return get_contained_external_atoms() -/atom/proc/dump_contents() +/// Dump the contents of this atom onto its loc +/atom/proc/dump_contents(atom/forced_loc = loc, mob/user) for(var/thing in get_contained_external_atoms()) var/atom/movable/AM = thing - AM.dropInto(loc) + AM.dropInto(forced_loc) if(ismob(AM)) var/mob/M = AM if(M.client) M.client.eye = M.client.mob M.client.perspective = MOB_PERSPECTIVE -/atom/proc/physically_destroyed() +/** + Handle the destruction of this atom, spilling its contents by default + + - `skip_qdel`: If calling qdel() on this atom should be skipped. + - Return: Unknown, feel free to change this +*/ +/atom/proc/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(TRUE) dump_contents() + if(!skip_qdel && !QDELETED(src)) + qdel(src) . = TRUE +/** + Attempt to detonate the reagents contained in this atom + + - `severity`: Strength of the explosion ranging from 1 to 3. Higher is weaker +*/ /atom/proc/try_detonate_reagents(var/severity = 3) if(reagents) - for(var/rtype in reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - R.explosion_act(src, severity) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + reagent.explosion_act(src, severity) + +/** + Handle an explosion of `severity` affecting this atom + - `severity`: Strength of the explosion ranging from 1 to 3. Higher is weaker + - Return: `TRUE` if severity is within range and exploding should continue, otherwise `FALSE` +*/ /atom/proc/explosion_act(var/severity) SHOULD_CALL_PARENT(TRUE) - if(!global.is_currently_exploding[src]) - global.is_currently_exploding[src] = TRUE - . = (severity <= 3) - if(.) - for(var/atom/movable/AM in contents) - AM.explosion_act(severity++) + . = !currently_exploding && severity > 0 && severity <= 3 + if(.) + currently_exploding = TRUE + if(severity < 3) + for(var/atom/movable/AM in get_contained_external_atoms()) + AM.explosion_act(severity + 1) try_detonate_reagents(severity) - global.is_currently_exploding -= src + currently_exploding = FALSE + +/** + Handle a `user` attempting to emag this atom + - `remaining_charges`: Used for nothing TODO: Fix this + - `user`: The user attempting to emag this atom + - `emag_source`: The source of the emag + - Returns: 1 if successful, -1 if not, NO_EMAG_ACT if it cannot be emaged +*/ /atom/proc/emag_act(var/remaining_charges, var/mob/user, var/emag_source) return NO_EMAG_ACT +/** + Handle this atom being exposed to fire + + - `air`: The gas_mixture for this loc + - `exposed_temperature`: The temperature of the air + - `exposed_volume`: The volume of the air +*/ /atom/proc/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - return + SHOULD_CALL_PARENT(TRUE) + handle_external_heating(exposed_temperature) -/atom/proc/melt() - return +/// Handle this atom being destroyed through melting +/atom/proc/handle_melting(list/meltable_materials) + SHOULD_CALL_PARENT(TRUE) + +/atom/proc/handle_destroyed_by_heat() + return handle_melting() +/** + Handle this atom being exposed to lava. Calls qdel() by default + + - Returns: `TRUE` if qdel() was called, otherwise `FALSE` +*/ /atom/proc/lava_act() - visible_message("\The [src] sizzles and melts away, consumed by the lava!") - playsound(src, 'sound/effects/flare.ogg', 100, 3) - qdel(src) - . = TRUE + if(simulated) + visible_message(SPAN_DANGER("\The [src] sizzles and melts away, consumed by the lava!")) + playsound(src, 'sound/effects/flare.ogg', 100, 3) + qdel(src) + return TRUE + return FALSE -/atom/proc/hitby(atom/movable/AM, var/datum/thrownthing/TT)//already handled by throw impact +/** + Handle this atom being hit by a thrown atom + + - `AM`: The atom hitting this atom + - `TT`: A datum wrapper for a thrown atom, containing important info + - Returns: TRUE if successfully hit the atom. +*/ +/atom/proc/hitby(atom/movable/AM, var/datum/thrownthing/TT) + SHOULD_CALL_PARENT(TRUE) if(isliving(AM)) var/mob/living/M = AM M.apply_damage(TT.speed*5, BRUTE) + return TRUE + +/** + Attempt to add blood to this atom -//returns 1 if made bloody, returns 0 otherwise -/atom/proc/add_blood(mob/living/carbon/human/M) + If a mob is provided, their blood will be used + + - `M?`: The mob whose blood will be used + - Returns: TRUE if made bloody, otherwise FALSE +*/ +/atom/proc/add_blood(mob/living/M, amount = 2, list/blood_data) if(atom_flags & ATOM_FLAG_NO_BLOOD) - return 0 + return FALSE - if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it. + if(!islist(blood_DNA)) //if our list of DNA doesn't exist yet (or isn't a list) initialize it. blood_DNA = list() was_bloodied = 1 - blood_color = COLOR_BLOOD_HUMAN - if(istype(M)) - if (!istype(M.dna, /datum/dna)) - M.dna = new /datum/dna(null) - M.dna.real_name = M.real_name - M.check_dna() - blood_color = M.species.get_blood_colour(M) - . = 1 - return 1 + blood_color = istype(M) ? M.get_blood_color() : COLOR_BLOOD_HUMAN + return TRUE -/mob/living/proc/handle_additional_vomit_reagents(var/obj/effect/decal/cleanable/vomit/vomit) - vomit.reagents.add_reagent(/decl/material/liquid/acid/stomach, 5) +/** + Remove any blood from this atom -/atom/proc/clean_blood() + - Return: `TRUE` if blood with DNA was removed +*/ +/atom/proc/clean(clean_forensics = TRUE) + SHOULD_CALL_PARENT(TRUE) if(!simulated) return - fluorescent = 0 + fluorescent = FALSE germ_level = 0 blood_color = null if(istype(blood_DNA, /list)) @@ -375,43 +618,35 @@ its easier to just keep the beam vertical. if(forensics) forensics.remove_data(/datum/forensics/blood_dna) forensics.remove_data(/datum/forensics/gunshot_residue) - return 1 - -/atom/proc/get_global_map_pos() - if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map)) return - var/cur_x = null - var/cur_y = null - var/list/y_arr = null - for(cur_x=1,cur_x<=GLOB.global_map.len,cur_x++) - y_arr = GLOB.global_map[cur_x] - cur_y = y_arr.Find(src.z) - if(cur_y) - break -// log_debug("X = [cur_x]; Y = [cur_y]") - - if(cur_x && cur_y) - return list("x"=cur_x,"y"=cur_y) - else - return 0 + return TRUE + return FALSE -/atom/proc/checkpass(passflag) - return pass_flags&passflag +/** + Check if this atom can be passed by another given the flags provided -/atom/proc/isinspace() - if(istype(get_turf(src), /turf/space)) - return 1 - else - return 0 + - `pass_flag`: The flags to check. See: flags.dm + - Return: The flags present that allow it to pass, otherwise `0` +*/ +/atom/proc/checkpass(pass_flag) + SHOULD_BE_PURE(TRUE) + return pass_flags & pass_flag + +/** + Show a message to all mobs and objects in sight of this atom. + + Used for atoms performing visible actions -// Show a message to all mobs and objects in sight of this atom -// Use for objects performing visible actions -// message is output to anyone who can see, e.g. "The [src] does something!" -// blind_message (optional) is what blind people will hear e.g. "You hear something!" -/atom/proc/visible_message(var/message, var/self_message, var/blind_message, var/range = world.view, var/checkghosts = null) + - `message`: The string output to any atom that can see this atom + - `self_message?`: The string displayed to this atom if it's a mob. See: mobs.dm + - `blind_message?`: The string blind mobs will see. Example: "You hear something!" + - `range?`: The number of tiles away the message will be visible from. Default: world.view + - `check_ghosts?`: Set to `TRUE` if ghosts should see the message if their preferences allow +*/ +/atom/proc/visible_message(var/message, var/self_message, var/blind_message, var/range = world.view, var/check_ghosts = null) var/turf/T = get_turf(src) var/list/mobs = list() var/list/objs = list() - get_mobs_and_objs_in_view_fast(T,range, mobs, objs, checkghosts) + get_listeners_in_range(T,range, mobs, objs, check_ghosts) for(var/o in objs) var/obj/O = o @@ -424,16 +659,22 @@ its easier to just keep the beam vertical. else if(blind_message) M.show_message(blind_message, AUDIBLE_MESSAGE) -// Show a message to all mobs and objects in earshot of this atom -// Use for objects performing audible actions -// message is the message output to anyone who can hear. -// deaf_message (optional) is what deaf people will see. -// hearing_distance (optional) is the range, how many tiles away the message can be heard. -/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance = world.view, var/checkghosts = null) +/** + Show a message to all mobs and objects in earshot of this atom + + Used for atoms performing audible actions + + - `message`: The string to show to anyone who can hear this atom + - `deaf_message?`: The string deaf mobs will see + - `hearing_distance?`: The number of tiles away the message can be heard. Defaults to world.view + - `check_ghosts?`: TRUE if ghosts should hear the message if their preferences allow + - `radio_message?`: The string to send over radios +*/ +/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance = world.view, var/check_ghosts = null, var/radio_message) var/turf/T = get_turf(src) var/list/mobs = list() var/list/objs = list() - get_mobs_and_objs_in_view_fast(T, hearing_distance, mobs, objs, checkghosts) + get_listeners_in_range(T, hearing_distance, mobs, objs, check_ghosts) for(var/m in mobs) var/mob/M = m @@ -442,35 +683,47 @@ its easier to just keep the beam vertical. var/obj/O = o O.show_message(message,2,deaf_message,1) +/** + Attempt to drop this atom onto the destination. + + The destination can instead return another location, recursively chaining. + + - `destination`: The atom that this atom is dropped onto. + - Return: The result of the forceMove() at the end. +*/ /atom/movable/proc/dropInto(var/atom/destination) - while(istype(destination)) + while(!QDELETED(src) && istype(destination)) var/atom/drop_destination = destination.onDropInto(src) if(!istype(drop_destination) || drop_destination == destination) return forceMove(destination) destination = drop_destination return forceMove(null) +/** + Handle dropping an atom onto this atom. + + If the item should move into this atom, return null. Otherwise, return + the destination atom where the item should be moved. + + - `AM`: The atom being dropped onto this atom + - Return: A location for the atom AM to move to, or null to move it into this atom. +*/ /atom/proc/onDropInto(var/atom/movable/AM) - return // If onDropInto returns null, then dropInto will forceMove AM into us. + RETURN_TYPE(/atom) + return /atom/movable/onDropInto(var/atom/movable/AM) - return loc // If onDropInto returns something, then dropInto will attempt to drop AM there. - -/atom/proc/InsertedContents() - return contents + return loc -//all things climbable +/** + Handle this atom being hit by a grab. -/atom/attack_hand(mob/user) - ..() - if(LAZYLEN(climbers) && !(user in climbers)) - user.visible_message("[user.name] shakes \the [src].", \ - "You shake \the [src].") - object_shaken() + Called by resolve_attackby() -// Called when hitting the atom with a grab. -// Will skip attackby() and afterattack() if returning TRUE. -/atom/proc/grab_attack(var/obj/item/grab/G) + - `G`: The grab hitting this atom + - Return: `TRUE` to skip attackby() and afterattack() or `FALSE` +*/ +/atom/proc/grab_attack(obj/item/grab/grab, mob/user) return FALSE /atom/proc/climb_on() @@ -482,31 +735,38 @@ its easier to just keep the beam vertical. do_climb(usr) -/atom/proc/can_climb(var/mob/living/user, post_climb_check=0) +/** + Check if a user can climb this atom. + + - `user`: The mob to check + - `post_climb_check?`: If we should check if the user can continue climbing + - Return: `TRUE` if they can climb, otherwise `FALSE` +*/ +/atom/proc/can_climb(mob/living/user, post_climb_check = FALSE, silent = FALSE) if (!(atom_flags & ATOM_FLAG_CLIMBABLE) || !user.can_touch(src) || (!post_climb_check && climbers && (user in climbers))) - return 0 + return FALSE if (!user.Adjacent(src)) - to_chat(user, "You can't climb there, the way is blocked.") - return 0 + if(!silent) + to_chat(user, SPAN_WARNING("You can't climb there, the way is blocked.")) + return FALSE var/obj/occupied = turf_is_crowded(user) if(occupied) - to_chat(user, "There's \a [occupied] in the way.") - return 0 - return 1 - -/mob/proc/can_touch(var/atom/touching) - if(!touching.Adjacent(src) || incapacitated()) - return FALSE - if(restrained()) - to_chat(src, SPAN_WARNING("You are restrained.")) + if(!silent) + to_chat(user, SPAN_WARNING("There's \a [occupied] in the way.")) return FALSE - if (buckled) - to_chat(src, SPAN_WARNING("You are buckled down.")) return TRUE +/** + Check if this atom's turf is blocked. + + This doesn't handle border structures and should be preceded by an Adjacent() check. + - `ignore?`: An atom that should be ignored by the check. + - Return: The first atom blocking this atom's turf. +*/ /atom/proc/turf_is_crowded(var/atom/ignore) + RETURN_TYPE(/atom) var/turf/T = get_turf(src) if(!T || !istype(T)) return 0 @@ -519,9 +779,15 @@ its easier to just keep the beam vertical. return A return 0 +/** + Handle `user` climbing onto this atom. + + - `user`: The mob climbing onto this atom. + - Return: `TRUE` if the user successfully climbs onto this atom, otherwise `FALSE`. +*/ /atom/proc/do_climb(var/mob/living/user) if (!can_climb(user)) - return 0 + return FALSE add_fingerprint(user) user.visible_message("\The [user] starts climbing onto \the [src]!") @@ -529,13 +795,16 @@ its easier to just keep the beam vertical. if(!do_after(user,(issmall(user) ? MOB_CLIMB_TIME_SMALL : MOB_CLIMB_TIME_MEDIUM) * climb_speed_mult, src)) LAZYREMOVE(climbers,user) - return 0 + return FALSE if(!can_climb(user, post_climb_check=1)) LAZYREMOVE(climbers,user) - return 0 + return FALSE - var/target_turf = get_turf(src) + // handle multitile objects + // this should also be fine for non-multitile objects + // and ensures we don't ever move more than 1 tile + var/target_turf = get_step(user, get_dir(user, src)) //climbing over border objects like railings if((atom_flags & ATOM_FLAG_CHECKS_BORDER) && get_turf(user) == target_turf) @@ -546,74 +815,270 @@ its easier to just keep the beam vertical. if (get_turf(user) == target_turf) user.visible_message("\The [user] climbs onto \the [src]!") LAZYREMOVE(climbers,user) - return 1 + return TRUE +/// Shake this atom and all its climbers. /atom/proc/object_shaken() for(var/mob/living/M in climbers) - M.Weaken(1) + SET_STATUS_MAX(M, STAT_WEAK, 1) to_chat(M, "You topple as you are shaken off \the [src]!") climbers.Cut(1,2) for(var/mob/living/M in get_turf(src)) - if(M.lying) return //No spamming this on people. - - M.Weaken(3) - to_chat(M, "You topple as \the [src] moves under you!") + if(M.current_posture.prone) return //No spamming this on people. + SET_STATUS_MAX(M, STAT_WEAK, 3) + to_chat(M, SPAN_DANGER("You topple as \the [src] moves under you!")) if(prob(25)) - var/damage = rand(15,30) - var/mob/living/carbon/human/H = M - if(!istype(H)) - to_chat(H, "You land heavily!") - M.adjustBruteLoss(damage) - return - - var/obj/item/organ/external/affecting - var/list/limbs = BP_ALL_LIMBS //sanity check, can otherwise be shortened to affecting = pick(BP_ALL_LIMBS) - if(limbs.len) - affecting = H.get_organ(pick(limbs)) - - if(affecting) - to_chat(M, "You land heavily on your [affecting.name]!") - affecting.take_external_damage(damage, 0) + var/obj/item/organ/external/affecting = SAFEPICK(M.get_external_organs()) + if(!affecting) + to_chat(M, SPAN_DANGER("You land heavily!")) + M.take_damage(damage) + else + to_chat(M, SPAN_DANGER("You land heavily on your [affecting.name]!")) + affecting.take_damage(damage) if(affecting.parent) affecting.parent.add_autopsy_data("Misadventure", damage) - else - to_chat(H, "You land heavily!") - H.adjustBruteLoss(damage) - - H.UpdateDamageIcon() - H.updatehealth() - return - -/atom/MouseDrop_T(mob/target, mob/user) - var/mob/living/H = user - if(istype(H) && can_climb(H) && target == user) - do_climb(target) - else - return ..() +/// Get the current color of this atom. /atom/proc/get_color() return color +/* Set the atom colour. This is a stub effectively due to the broad use of direct setting. */ +// TODO: implement this everywhere that it should be used instead of direct setting. +/atom/proc/set_color(var/new_color) + if(isnull(new_color)) + return reset_color() + if(color != new_color) + color = new_color + return TRUE + return FALSE + +/atom/proc/reset_color() + if(!isnull(color)) + color = null + return TRUE + return FALSE + +/atom/proc/set_alpha(var/new_alpha) + if(alpha != new_alpha) + alpha = new_alpha + return TRUE + return FALSE + +/// Get any power cell associated with this atom. /atom/proc/get_cell() - return + RETURN_TYPE(/obj/item/cell) + var/datum/extension/loaded_cell/cell_loaded = get_extension(src, /datum/extension/loaded_cell) + return cell_loaded?.get_cell() -/atom/proc/building_cost() - . = list() +/** + Get any radio associated with this atom. + + Used for handle_message_mode or other radio-based logic. + - `message_mode?`: Used to determine what subset of radio should be returned (ie. intercoms or ear radios) + - Return: A radio appropriate for `message_mode`. +*/ +/atom/proc/get_radio(var/message_mode) + RETURN_TYPE(/obj/item/radio) + return /atom/Topic(href, href_list) var/mob/user = usr if(href_list["look_at_me"] && istype(user)) var/turf/T = get_turf(src) - if(T.CanUseTopic(user, GLOB.view_state) != STATUS_CLOSE) - user.examinate(src) + if(T.CanUseTopic(user, global.view_topic_state) != STATUS_CLOSE) + user.examine_verb(src) return TOPIC_HANDLED . = ..() +/// Get the temperature of this atom's heat source /atom/proc/get_heat() . = temperature +/// Check if this atom is a source of fire /atom/proc/isflamesource() - . = FALSE \ No newline at end of file + . = FALSE + +// === Transform setters. === + +/** + Set the rotation of this atom's transform + + - `new_rotation`: The angle in degrees the transform will be rotated clockwise +*/ +/atom/proc/set_rotation(new_rotation) + icon_rotation = new_rotation + update_transform() + +/** + Set the scale of this atom's transform. + + - `new_scale_x`: The multiplier to apply to the X axis + - `new_scale_y`: The multiplier to apply to the Y axis +*/ +/atom/proc/set_scale(new_scale_x, new_scale_y) + if(isnull(new_scale_y)) + new_scale_y = new_scale_x + if(new_scale_x != 0) + icon_scale_x = new_scale_x + if(new_scale_y != 0) + icon_scale_y = new_scale_y + update_transform() + +/** + Update this atom's transform from stored values. + + Applies icon_scale and icon_rotation. When transform_animate_time is set, + the transform is animated over the specified duration. Otherwise, it is + applied instantly. + + - Return: The transform `/matrix` after updates are applied +*/ +/atom/proc/update_transform() + RETURN_TYPE(/matrix) + var/matrix/M = matrix() + M.Scale(icon_scale_x, icon_scale_y) + M.Turn(icon_rotation) + if(transform_animate_time) + animate(src, transform = M, transform_animate_time) + else + transform = M + return transform + +/// Get the first loc of the specified `loc_type` from walking up the loc tree of this atom. +/atom/get_recursive_loc_of_type(var/loc_type) + RETURN_TYPE(/atom) + var/atom/check_loc = loc + while(check_loc) + if(istype(check_loc, loc_type)) + return check_loc + check_loc = check_loc.loc + +/atom/proc/can_climb_from_below(var/mob/climber) + return FALSE + +/atom/proc/singularity_act() + return 0 + +/atom/proc/singularity_pull(S, current_size) + return + +/atom/proc/get_overhead_text_x_offset() + return 0 + +/atom/proc/get_overhead_text_y_offset() + return 0 + +/atom/proc/can_be_injected_by(var/atom/injector) + return FALSE + +//Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area). +//Returns -1 if the atom was not found on container. +/atom/proc/storage_depth(atom/container) + . = 0 + var/atom/cur_atom = src + while (cur_atom && !(cur_atom in container.contents)) + if (isarea(cur_atom)) + return -1 + if(cur_atom.loc?.storage) + .++ + cur_atom = cur_atom.loc + if (!cur_atom) + return -1 //inside something with a null loc. + +//Like storage depth, but returns the depth to the nearest turf +//Returns -1 if no top level turf (a loc was null somewhere, or a non-turf atom's loc was an area somehow). +/atom/proc/storage_depth_turf() + . = 0 + var/atom/cur_atom = src + while (cur_atom && !isturf(cur_atom)) + if (isarea(cur_atom)) + return -1 + if(cur_atom.loc?.storage) + .++ + cur_atom = cur_atom.loc + if (!cur_atom) + . = -1 //inside something with a null loc. + +/atom/proc/storage_inserted(atom/movable/thing) + return + +/atom/proc/storage_removed(atom/movable/thing) + return + +/atom/proc/OnSimulatedTurfEntered(turf/T, old_loc) + set waitfor = FALSE + return + +/atom/proc/get_thermal_mass() + return 0 + +/atom/proc/get_thermal_mass_coefficient(delta) + return 1 + +/atom/proc/spark_act(obj/effect/sparks/sparks) + return + +/atom/proc/get_affecting_weather() + return + +/atom/proc/is_outside() + var/turf/turf = get_turf(src) + return istype(turf) ? turf.is_outside() : OUTSIDE_UNCERTAIN + +/atom/proc/can_be_poured_into(atom/source) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) && ATOM_IS_OPEN_CONTAINER(src) + +/// This is whether it's physically possible to pour from this atom to the target atom, based on context like user intent and src being open, etc. +/// This should not check things like whether there is actually anything in src to pour. +/// It should also not check anything controlled by the target atom, because can_be_poured_into() already exists. +/atom/proc/can_be_poured_from(mob/user, atom/target) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) && ATOM_IS_OPEN_CONTAINER(src) + +/atom/proc/take_vaporized_reagent(reagent, amount) + return + +/atom/proc/is_watertight() + return !ATOM_IS_OPEN_CONTAINER(src) + +/atom/proc/reaction_can_overflow(decl/chemical_reaction/reaction) + return ATOM_IS_OPEN_CONTAINER(src) + +/atom/proc/can_drink_from(mob/user) + return ATOM_IS_OPEN_CONTAINER(src) && REAGENT_TOTAL_VOLUME(reagents) && user.check_has_mouth() + +/atom/proc/adjust_required_attack_dexterity(mob/user, required_dexterity) + if(storage) // TODO: possibly check can_be_inserted() to avoid being able to shoot mirrors as a drake. + return DEXTERITY_HOLD_ITEM + return required_dexterity + +/atom/proc/immune_to_floor_hazards() + return !simulated || !has_gravity() +/// The punctuation used for the "That's an X." string. +/atom/proc/get_examine_punctuation() + // Could theoretically check if reagents in a coating are 'dangerous' or 'suspicious' (blood, acid, etc) + // in an override, but that'd require setting such a var on a bunch of materials and I'm lazy. + return blood_color ? "!" : "." + +/// The prefix that goes before the atom name on examine. +/atom/proc/get_examine_prefix() + if(blood_color) + return FONT_COLORED(blood_color, "stained") + return null + +// Used to mark a turf as containing objects that are dangerous to step onto. +/atom/proc/register_dangerous_to_step() + var/turf/T = get_turf(src) + if(T) + T.register_dangerous_object(src) + +/atom/proc/unregister_dangerous_to_step() + var/turf/T = get_turf(src) + if(T) + T.unregister_dangerous_object(src) + +// Test for if stepping on a tile containing this obj is safe to do, used for things like landmines and cliffs. +/atom/proc/is_safe_to_step(mob/living/stepper) + return TRUE diff --git a/code/game/atoms_damage.dm b/code/game/atoms_damage.dm new file mode 100644 index 000000000000..e73c65f800f9 --- /dev/null +++ b/code/game/atoms_damage.dm @@ -0,0 +1,2 @@ +/atom/proc/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + return diff --git a/code/game/atoms_fires.dm b/code/game/atoms_fires.dm new file mode 100644 index 000000000000..c70cc007cb87 --- /dev/null +++ b/code/game/atoms_fires.dm @@ -0,0 +1,21 @@ +// Stubs for atom fire system, TODO. +/atom/proc/set_fire_intensity(amount) + return + +/atom/proc/get_fire_intensity() + return 0 + +/atom/proc/adjust_fire_intensity(amount) + return + +/atom/proc/can_ignite() + return FALSE + +/atom/proc/ignite_fire() + return + +/atom/proc/extinguish_fire(mob/user, no_message = FALSE) + return + +/atom/proc/is_on_fire() + return FALSE diff --git a/code/game/atoms_fluids.dm b/code/game/atoms_fluids.dm index ed7c8b87084d..127ec73d713e 100644 --- a/code/game/atoms_fluids.dm +++ b/code/game/atoms_fluids.dm @@ -2,15 +2,15 @@ return /atom/proc/fluid_act(var/datum/reagents/fluids) - fluids.touch(src) - if(reagents && fluids.total_volume >= FLUID_SHALLOW && ATOM_IS_OPEN_CONTAINER(src)) - reagents.trans_to_holder(fluids, reagents.total_volume) - fluids.trans_to_holder(reagents, min(fluids.total_volume, reagents.maximum_volume)) + SHOULD_CALL_PARENT(TRUE) + if(reagents && reagents != fluids && !is_watertight()) + var/fluid_volume = REAGENT_TOTAL_VOLUME(fluids) + if(fluid_volume >= FLUID_SHALLOW) + var/reagent_volume = REAGENT_MAXIMUM_VOLUME(reagents) + reagents.trans_to_holder(fluids, reagent_volume) + fluids.trans_to_holder(reagents, fluid_volume, reagent_volume) -/atom/proc/return_fluid() - return null - -/atom/proc/check_fluid_depth(var/min) +/atom/proc/check_fluid_depth(var/min = 1) return 0 /atom/proc/get_fluid_depth() @@ -19,35 +19,76 @@ /atom/proc/CanFluidPass(var/coming_from) return TRUE -/atom/movable/proc/is_fluid_pushable(var/amt) +/atom/movable/proc/try_fluid_push(volume, strength) return simulated && !anchored /atom/movable/is_flooded(var/lying_mob, var/absolute) var/turf/T = get_turf(src) - return T?.is_flooded(lying_mob) + return T?.is_flooded(lying_mob, absolute) -/atom/proc/submerged(depth) +/atom/proc/submerged(depth, above_turf) + var/turf/T = get_turf(src) if(isnull(depth)) - var/turf/T = get_turf(src) if(!istype(T)) return FALSE depth = T.get_fluid_depth() - if(istype(loc, /mob)) + if(istype(T)) + var/turf_height = T.get_physical_height() + // If we're not on the surface of the turf (floating, leaping, or other sources) + // then we add the turf height to the depth, so you can jump over a water-filled pit + // or throw something over it + if(turf_height < 0 && above_turf) + depth += turf_height + if(ismob(loc)) return depth >= FLUID_SHALLOW - if(istype(loc, /turf)) + if(isturf(loc)) + if(locate(/obj/structure/table)) + return depth >= FLUID_SHALLOW return depth >= 3 return depth >= FLUID_OVER_MOB_HEAD -/turf/submerged(depth) +// This override exists purely because throwing is movable-level and not atom-level, +// for obvious reasons (that being that non-movable atoms cannot move). +/atom/movable/submerged(depth, above_turf) + above_turf ||= immune_to_floor_hazards() + return ..() + +/obj/item/submerged(depth, above_turf) + var/datum/inventory_slot/slot = get_any_equipped_slot_datum() + // we're in a mob and have a slot, so we bail early + if(istype(slot)) + var/mob/owner = loc // get_any_equipped_slot checks istype already + if(owner.current_posture.prone) + return ..() // treat us like an atom sitting on the ground (or table), really + if(isnull(depth)) // copied from base proc, since we aren't calling parent in this block + var/turf/T = get_turf(src) + if(!istype(T)) + return FALSE + depth = T.get_fluid_depth() + return depth >= slot.fluid_height + return ..() + +/mob/submerged(depth, above_turf) + above_turf ||= immune_to_floor_hazards() // check throwing here because of the table check coming before parent call + var/obj/structure/table/standing_on = locate(/obj/structure/table) in loc + // can't stand on a table if we're floating + if(!above_turf && standing_on && standing_on.mob_offset > 0) // standing atop a table that is a meaningful amount above the ground (not a bench) + if(isnull(depth)) // duplicated from atom because we don't call parent in this block + var/turf/T = get_turf(src) + if(!istype(T)) + return FALSE + depth = T.get_fluid_depth() + // assuming default tables are at waist height, this is a simple adjustment to scale it for taller/shorter ones + return depth >= floor(FLUID_SHALLOW * (standing_on.mob_offset / /obj/structure/table::mob_offset)) + return ..() + +// above_turf is nonsensical for turfs but I don't want the linter to complain +/turf/submerged(depth, above_turf) if(isnull(depth)) depth = get_fluid_depth() return depth >= FLUID_OVER_MOB_HEAD -/atom/proc/fluid_update() +/atom/proc/fluid_update(var/ignore_neighbors) var/turf/T = get_turf(src) if(istype(T)) - T.fluid_update() - -/atom/movable/update_nearby_tiles(var/need_rebuild) - UNLINT(. = ..(need_rebuild)) - fluid_update() \ No newline at end of file + T.fluid_update(ignore_neighbors) diff --git a/code/game/atoms_init.dm b/code/game/atoms_init.dm new file mode 100644 index 000000000000..74a53a1d715c --- /dev/null +++ b/code/game/atoms_init.dm @@ -0,0 +1,186 @@ +// Atom-level definitions + +/atom/New(loc, ...) + + // Do this as early as humanly possible to replicate previous type-based storage behavior. + if(storage) + if(ispath(storage)) + storage = new storage(src) + if(!istype(storage)) + storage = null + + // This preloader code is also duplicated in /turf/unsimulated/New(). If you change this, be sure to change it there, too. + //atom creation method that preloads variables at creation + if(global.use_preloader && (src.type == global._preloader.target_path))//in case the instanciated atom is creating other atoms in New() + global._preloader.load(src) + + var/do_initialize = SSatoms.atom_init_stage + var/list/created = SSatoms.created_atoms + if(do_initialize > INITIALIZATION_INSSATOMS) + args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD + if(SSatoms.InitAtom(src, args)) + //we were deleted + return + else if(length(args) > 1) + created[++created.len] = list(src, args.Copy(2)) + else + created[++created.len] = list(src, null) + if(atom_flags & ATOM_FLAG_CLIMBABLE) + verbs += /atom/proc/climb_on + +//Called after New if the map is being loaded. mapload = TRUE +//Called from base of New if the map is not being loaded. mapload = FALSE +//This base must be called or derivatives must set initialized to TRUE +//must not sleep +//Other parameters are passed from New (excluding loc) +//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm + +/atom/proc/Initialize(mapload, ...) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + + if(atom_flags & ATOM_FLAG_INITIALIZED) + PRINT_STACK_TRACE("Warning: [src]([type]) initialized multiple times!") + atom_flags |= ATOM_FLAG_INITIALIZED + + if(isnull(default_pixel_x)) + default_pixel_x = pixel_x + else + pixel_x = default_pixel_x + if(isnull(default_pixel_y)) + default_pixel_y = pixel_y + else + pixel_y = default_pixel_y + if(isnull(default_pixel_z)) + default_pixel_z = pixel_z + else + pixel_z = default_pixel_z + if(isnull(default_pixel_w)) + default_pixel_w = pixel_w + else + pixel_w = default_pixel_w + + if(light_power && light_range) + update_light() + + if(simulated && opacity) + updateVisibility(src) + var/turf/T = loc + if(istype(T)) + T.recalc_atom_opacity() + + return INITIALIZE_HINT_NORMAL + +//called if Initialize returns INITIALIZE_HINT_LATELOAD +/atom/proc/LateInitialize() + return + +/atom/Destroy() + // must be done before deletion // TODO: ADD PRE_DELETION OBSERVATION + if(isatom(loc) && loc.storage && !QDELETED(loc.storage)) + loc.storage.on_item_pre_deletion(src) + UNQUEUE_TEMPERATURE_ATOM(src) + QDEL_NULL(reagents) + LAZYCLEARLIST(our_overlays) + LAZYCLEARLIST(priority_overlays) + LAZYCLEARLIST(climbers) + QDEL_NULL(light) + if(simulated && opacity) + updateVisibility(src) + if(atom_codex_ref && atom_codex_ref != TRUE) // may be null, TRUE or a datum instance + QDEL_NULL(atom_codex_ref) + . = ..() + // This might need to be moved onto a Del() override at some point. + QDEL_NULL(storage) + +// Called if an atom is deleted before it initializes. Only call Destroy in this if you know what you're doing. +/atom/proc/EarlyDestroy(force = FALSE) + return QDEL_HINT_QUEUE + + +// Movable level stuff + +/atom/movable/Initialize(ml, ...) + . = ..() + if (!follow_repository.excluded_subtypes[type] && follow_repository.followed_subtypes_tcache[type]) + follow_repository.add_subject(src) + + if(ispath(virtual_mob)) + virtual_mob = new virtual_mob(get_turf(src), src) + + // Fire Entered events for freshly created movables. + // Changing this behavior will almost certainly break power; update accordingly. + if (!ml && loc) + loc.Entered(src, null) + if(loc && (z_flags & ZMM_WIDE_LOAD)) + SSzcopy.discover_movable(src) + +/atom/movable/EarlyDestroy(force = FALSE) + loc = null // should NOT use forceMove, in order to avoid events + return ..() + +/atom/movable/Destroy() + // Clear this up early so it doesn't complain about events being disposed while it's listening. + if(isatom(virtual_mob)) + QDEL_NULL(virtual_mob) + + unregister_all_movement(loc, src) // unregister events before destroy to avoid expensive checking + + // If you want to keep any of these atoms, handle them before ..() + for(var/atom/movable/thing as anything in src) // safe to assume they're never going to have non-movables in contents + qdel(thing) + + . = ..() + + var/atom/oldloc = loc + forceMove(null) + + if(LAZYLEN(movement_handlers) && !ispath(movement_handlers[1])) + QDEL_NULL_LIST(movement_handlers) + + if (bound_overlay) + QDEL_NULL(bound_overlay) + + vis_locs = null //clears this atom out of all vis_contents + clear_vis_contents() + + if(!isnull(updating_turf_alpha_mask)) + var/atom/movable/mask = global._alpha_masks[src] + if(!QDELETED(mask)) + qdel(mask) + + // This has to be done for movables because atoms can't be in storage. + if(isatom(oldloc) && !QDELETED(oldloc?.storage)) + oldloc.storage.on_item_post_deletion(src) // must be done after deletion + +/atom/GetCloneArgs() + return list(loc) + +/atom/PopulateClone(atom/clone) + //Not entirely sure about icon stuff. Some legacy things would need it copied, but not more recently coded atoms. + clone.appearance = appearance + clone.set_invisibility(invisibility) + + clone.SetName(name) + clone.set_density(density) + clone.set_opacity(opacity) + clone.set_gender(gender, FALSE) + clone.set_dir(dir) + + clone.blood_DNA = listDeepClone(blood_DNA, TRUE) + clone.was_bloodied = was_bloodied + clone.blood_color = blood_color + clone.germ_level = germ_level + clone.temperature = temperature + + //Setup reagents + QDEL_NULL(clone.reagents) + clone.reagents = reagents?.Clone() + if(clone.reagents) + clone.reagents.set_holder(clone) //Holder MUST be set after cloning reagents + return clone + +/atom/movable/PopulateClone(atom/movable/clone) + clone = ..() + clone.anchored = anchored + return clone \ No newline at end of file diff --git a/code/game/atoms_interactions.dm b/code/game/atoms_interactions.dm new file mode 100644 index 000000000000..d4e352ba6835 --- /dev/null +++ b/code/game/atoms_interactions.dm @@ -0,0 +1,44 @@ +// List of interactions used in procs below. +var/global/list/_reagent_interactions = list( + /decl/interaction_handler/wash_hands, + /decl/interaction_handler/drink, + /decl/interaction_handler/dip_item, + /decl/interaction_handler/fill_from, + /decl/interaction_handler/empty_into +) + +/** + Get a list of standard interactions (attack_hand and attackby) for a user from this atom. + At time of writing, these are really easy to have interfere with or be interfered with by + attack_hand() and attackby() overrides. Putting them on items us a bad idea due to pickup code. + + - `user`: The mob that these interactions are for + - Return: A list containing the interactions +*/ +/atom/proc/get_standard_interactions(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) + return null + +/** + Get a default interaction for a user from this atom. + + - `user`: The mob that this interaction is for + - Return: A default interaction decl, or null. +*/ +/atom/proc/get_quick_interaction_handler(mob/user) + return + +/** + Get a list of alt interactions (alt-click) for a user from this atom. + + - `user`: The mob that these alt interactions are for + - Return: A list containing the alt interactions +*/ +/atom/proc/get_alt_interactions(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) + if(storage) + LAZYADD(., /decl/interaction_handler/storage_open) + if(REAGENT_MAXIMUM_VOLUME(reagents)) + LAZYADD(., global._reagent_interactions) diff --git a/code/game/atoms_layering.dm b/code/game/atoms_layering.dm new file mode 100644 index 000000000000..4f37917e6cbc --- /dev/null +++ b/code/game/atoms_layering.dm @@ -0,0 +1,29 @@ +/atom + plane = DEFAULT_PLANE + appearance_flags = DEFAULT_APPEARANCE_FLAGS +/atom/movable + appearance_flags = DEFAULT_APPEARANCE_FLAGS | TILE_BOUND // Most AMs are not visibly bigger than a tile. +/image + appearance_flags = DEFAULT_APPEARANCE_FLAGS +/mutable_appearance + appearance_flags = DEFAULT_APPEARANCE_FLAGS // Inherits /image but re docs, subject to change + +/atom/proc/hud_layerise() + plane = HUD_PLANE + layer = HUD_ITEM_LAYER + +/atom/proc/reset_plane_and_layer() + reset_plane() + reset_layer() + +/atom/proc/reset_plane() + plane = initial(plane) + +/atom/proc/reset_layer() + layer = initial(layer) + +/atom/proc/reset_offsets(var/anim_time = 2) + pixel_w = default_pixel_w + pixel_x = default_pixel_x + pixel_y = default_pixel_y + pixel_z = default_pixel_z diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d897a30f47c5..628b5880042e 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1,18 +1,34 @@ /atom/movable layer = OBJ_LAYER - appearance_flags = TILE_BOUND - glide_size = 4 + appearance_flags = TILE_BOUND | DEFAULT_APPEARANCE_FLAGS | LONG_GLIDE + glide_size = 8 + abstract_type = /atom/movable + + var/can_buckle = 0 + var/buckle_movable = 0 + var/buckle_allow_rotation = 0 + var/buckle_layer_above = FALSE + var/buckle_dir = 0 + var/buckle_lying = -1 // bed-like behavior, forces mob to lie or stand if buckle_lying != -1 + /// A list or JSON-encoded list of pixel offsets to use on a mob buckled to this atom. TRUE to use this atom's pixel shifts, null for no pixel shift control. + var/buckle_pixel_shift // ex. @'{"x":0,"y":0,"z":0}' + var/buckle_require_restraints = 0 // require people to be cuffed before being able to buckle. eg: pipes + var/buckle_require_same_tile = FALSE + var/buckle_sound + var/mob/living/buckled_mob = null + var/movable_flags var/last_move = null - var/anchored = 0 + var/anchored = FALSE // var/elevation = 2 - not used anywhere var/move_speed = 10 var/l_move_time = 1 - var/m_flag = 1 + var/const/FIRST_DIAGONAL_STEP = 1 + var/const/SECOND_DIAGONAL_STEP = 2 + var/moving_diagonally = FALSE // Used so we don't break grabs mid-diagonal-move. var/datum/thrownthing/throwing var/throw_speed = 2 var/throw_range = 7 - var/moved_recently = 0 var/item_state = null // Used to specify the item state for the on-mob overlays. var/does_spin = TRUE // Does the atom spin when thrown (of course it does :P) var/list/grabbed_by @@ -24,9 +40,19 @@ var/inertia_move_delay = 5 var/atom/movable/inertia_ignore + // Marker for alpha mask update process. null == never update, TRUE == currently updating, FALSE == finished updating. + var/updating_turf_alpha_mask = null + + // Damage type from using or throwing this atom. + var/atom_damage_type = BRUTE + +// This proc determines if the instance is preserved when the process() despawn of crypods occurs. +/atom/movable/proc/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return FALSE + //call this proc to start space drifting /atom/movable/proc/space_drift(direction)//move this down - if(!loc || direction & (UP|DOWN) || Process_Spacemove(0)) + if(!loc || direction & (UP|DOWN) || is_space_movement_permitted() != SPACE_MOVE_FORBIDDEN) inertia_dir = 0 inertia_ignore = null return 0 @@ -38,38 +64,43 @@ SSspacedrift.processing[src] = src return 1 -//return 0 to space drift, 1 to stop, -1 for mobs to handle space slips -/atom/movable/proc/Process_Spacemove(var/allow_movement) +// return SPACE_MOVE_FORBIDDEN to space drift, SPACE_MOVE_PERMITTED to stop, SPACE_MOVE_SUPPORTED for mobs to handle space slips +// Note that it may also return an instance of /atom/movable, which acts as SPACE_MOVE_SUPPORTED and results in pushing the movable backwards. +/atom/movable/proc/is_space_movement_permitted(allow_movement = FALSE) if(!simulated) - return 1 - + return SPACE_MOVE_PERMITTED if(has_gravity()) - return 1 - - if(length(grabbed_by)) - return 1 - + return SPACE_MOVE_PERMITTED if(throwing) - return 1 - + return SPACE_MOVE_PERMITTED if(anchored) - return 1 - + return SPACE_MOVE_PERMITTED if(!isturf(loc)) - return 1 - + return SPACE_MOVE_PERMITTED + if(length(grabbed_by)) + for(var/obj/item/grab/grab as anything in grabbed_by) + if(grab.assailant == src) + continue + return SPACE_MOVE_PERMITTED if(locate(/obj/structure/lattice) in range(1, get_turf(src))) //Not realistic but makes pushing things in space easier - return -1 + return SPACE_MOVE_SUPPORTED + return SPACE_MOVE_FORBIDDEN - return 0 +/atom/movable/attack_hand(mob/user) + // Unbuckle anything buckled to us. + if(!can_buckle || !buckled_mob || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + user_unbuckle_mob(user) + return TRUE /atom/movable/hitby(var/atom/movable/AM, var/datum/thrownthing/TT) . = ..() + if(. && density && prob(50)) + do_simple_ranged_interaction() process_momentum(AM,TT) /atom/movable/proc/process_momentum(var/atom/movable/AM, var/datum/thrownthing/TT)//physic isn't an exact science . = momentum_power(AM,TT) - if(.) momentum_do(.,TT,AM) @@ -111,30 +142,6 @@ /atom/movable/proc/get_mass() return 1.5 -/atom/movable/Destroy() - . = ..() -#ifdef DISABLE_DEBUG_CRASH - // meh do nothing. we know what we're doing. pro engineers. -#else - if(!(atom_flags & ATOM_FLAG_INITIALIZED)) - crash_with("Was deleted before initialization") -#endif - - for(var/A in src) - qdel(A) - - forceMove(null) - - if(LAZYLEN(movement_handlers) && !ispath(movement_handlers[1])) - QDEL_NULL_LIST(movement_handlers) - - if (bound_overlay) - QDEL_NULL(bound_overlay) - - if(virtual_mob && !ispath(virtual_mob)) - qdel(virtual_mob) - virtual_mob = null - /atom/movable/Bump(var/atom/A, yes) if(!QDELETED(throwing)) throwing.hit_atom(A) @@ -144,20 +151,24 @@ if (A && yes) A.last_bumped = world.time - INVOKE_ASYNC(A, /atom/proc/Bumped, src) // Avoids bad actors sleeping or unexpected side effects, as the legacy behavior was to spawn here + INVOKE_ASYNC(A, TYPE_PROC_REF(/atom, Bumped), src) // Avoids bad actors sleeping or unexpected side effects, as the legacy behavior was to spawn here ..() /atom/movable/proc/forceMove(atom/destination) - if(QDELETED(src) && !QDESTROYING(src) && !isnull(destination)) + + if(QDELETED(src) && !isnull(destination)) CRASH("Attempted to forceMove a QDELETED [src] out of nullspace!!!") + if(loc == destination) - return 0 + return FALSE + var/is_origin_turf = isturf(loc) var/is_destination_turf = isturf(destination) // It is a new area if: // Both the origin and destination are turfs with different areas. // When either origin or destination is a turf and the other is not. var/is_new_area = (is_origin_turf ^ is_destination_turf) || (is_origin_turf && is_destination_turf && loc.loc != destination.loc) + var/was_below_z_turf = MOVABLE_IS_BELOW_ZTURF(src) var/atom/origin = loc loc = destination @@ -178,58 +189,117 @@ AM.Crossed(src) if(is_new_area && is_destination_turf) destination.loc.Entered(src, origin) - return 1 -/atom/movable/forceMove(atom/dest) - var/old_loc = loc - . = ..() - if (.) - // observ - if(!loc) - GLOB.moved_event.raise_event(src, old_loc, null) + . = TRUE - // freelook - if(opacity) - updateVisibility(src) + // observ + if(!loc && event_listeners?[/decl/observ/moved]) + raise_event_non_global(/decl/observ/moved, origin, null) + + // freelook + if(simulated && opacity) + updateVisibility(src) + + // lighting + if (light_source_solo) + light_source_solo.source_atom.update_light() + else if (light_source_multi) + var/datum/light_source/L + var/thing + for (thing in light_source_multi) + L = thing + L.source_atom.update_light() + + // Z-Mimic. + if (bound_overlay) + // The overlay will handle cleaning itself up on non-openspace turfs. + if (isturf(destination)) + bound_overlay.forceMove(get_step(src, UP)) + if (dir != bound_overlay.dir) + bound_overlay.set_dir(dir) + else // Not a turf, so we need to destroy immediately instead of waiting for the destruction timer to proc. + qdel(bound_overlay) + else if (isturf(loc) && (!origin || !was_below_z_turf) && MOVABLE_SHALL_MIMIC(src)) + SSzcopy.discover_movable(src) + + if(buckled_mob) + if(isturf(loc)) + buckled_mob.glide_size = glide_size // Setting loc apparently does animate with glide size. + buckled_mob.forceMove(loc) + refresh_buckled_mob(0) + else + unbuckle_mob() + +/atom/movable/set_dir(ndir) + . = ..() + if(.) + refresh_buckled_mob(0) - // lighting - if (light_sources) // Yes, I know you can for-null safely, but this is slightly faster. Hell knows why. - for (var/datum/light_source/L in light_sources) - L.source_atom.update_light() +/atom/movable/proc/refresh_buckled_mob(var/delay_offset_anim = 4) + if(buckled_mob) + buckled_mob.set_dir(buckle_dir || dir) + buckled_mob.reset_offsets(delay_offset_anim) + buckled_mob.reset_plane_and_layer() /atom/movable/Move(...) + var/old_loc = loc + var/was_below_z_turf = MOVABLE_IS_BELOW_ZTURF(src) . = ..() - if (.) - if(!loc) - GLOB.moved_event.raise_event(src, old_loc, null) + + if(.) + + if(buckled_mob) + if(isturf(loc)) + buckled_mob.glide_size = glide_size // Setting loc apparently does animate with glide size. + buckled_mob.forceMove(loc) + refresh_buckled_mob(0) + else + unbuckle_mob() + + if(!loc && event_listeners?[/decl/observ/moved]) + raise_event_non_global(/decl/observ/moved, old_loc, null) // freelook - if(opacity) + if(simulated && opacity) updateVisibility(src) // lighting - if (light_sources) // Yes, I know you can for-null safely, this is slightly faster. Hell knows why. - for (var/datum/light_source/L in light_sources) + if (light_source_solo) + light_source_solo.source_atom.update_light() + else if (light_source_multi) + var/datum/light_source/L + var/thing + for (thing in light_source_multi) + L = thing L.source_atom.update_light() -//called when src is thrown into hit_atom -/atom/movable/proc/throw_impact(atom/hit_atom, var/datum/thrownthing/TT) - if(istype(hit_atom,/mob/living)) - var/mob/living/M = hit_atom - M.hitby(src,TT) + // Z-Mimic. + if (bound_overlay) + // The overlay will handle cleaning itself up on non-openspace turfs. + bound_overlay.forceMove(get_step(src, UP)) + if (bound_overlay.dir != dir) + bound_overlay.set_dir(dir) + else if (isturf(loc) && (!old_loc || !was_below_z_turf) && MOVABLE_SHALL_MIMIC(src)) + SSzcopy.discover_movable(src) - else if(isobj(hit_atom)) - var/obj/O = hit_atom - if(!O.anchored) - step(O, src.last_move) - O.hitby(src,TT) + if(isturf(loc)) + var/turf/T = loc + if(REAGENT_TOTAL_VOLUME(T.reagents) && submerged()) + fluid_act(T.reagents) - else if(isturf(hit_atom)) - var/turf/T = hit_atom - T.hitby(src,TT) + for(var/mob/viewer in storage?.storage_ui?.is_seeing) + if(!storage.can_view(viewer)) + storage.close(viewer) + +//called when src is thrown into hit_atom +/atom/movable/proc/throw_impact(atom/hit_atom, var/datum/thrownthing/TT) + SHOULD_CALL_PARENT(TRUE) + if(istype(hit_atom) && !QDELETED(hit_atom)) + hit_atom.hitby(src, TT) /atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, datum/callback/callback) //If this returns FALSE then callback will not be called. + . = TRUE if (!target || speed <= 0 || QDELETED(src) || (target.z != src.z)) return FALSE @@ -239,6 +309,8 @@ var/datum/thrownthing/TT = new(src, target, range, speed, thrower, callback) throwing = TT + storage?.close_all() + pixel_z = 0 if(spin && does_spin) SpinAnimation(4,1) @@ -247,66 +319,25 @@ if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun)) SSthrowing.currentrun[src] = TT -//Overlays -/atom/movable/overlay - var/atom/master = null - var/follow_proc = /atom/movable/proc/move_to_loc_or_null - anchored = TRUE - simulated = FALSE - -/atom/movable/overlay/Initialize() - if(!loc) - crash_with("[type] created in nullspace.") - return INITIALIZE_HINT_QDEL - master = loc - SetName(master.name) - set_dir(master.dir) - - if(istype(master, /atom/movable)) - GLOB.moved_event.register(master, src, follow_proc) - SetInitLoc() - - GLOB.destroyed_event.register(master, src, /datum/proc/qdel_self) - GLOB.dir_set_event.register(master, src, /atom/proc/recursive_dir_set) - - . = ..() - -/atom/movable/overlay/proc/SetInitLoc() - forceMove(master.loc) - -/atom/movable/overlay/Destroy() - if(istype(master, /atom/movable)) - GLOB.moved_event.unregister(master, src) - GLOB.destroyed_event.unregister(master, src) - GLOB.dir_set_event.unregister(master, src) - master = null - . = ..() - -/atom/movable/overlay/attackby(obj/item/I, mob/user) - if (master) - return master.attackby(I, user) - -/atom/movable/overlay/attack_hand(mob/user) - if (master) - return master.attack_hand(user) - -/atom/movable/proc/touch_map_edge() +/atom/movable/proc/touch_map_edge(var/overmap_id) if(!simulated) return - if(!z || (z in GLOB.using_map.sealed_levels)) + if(!z || isSealedLevel(z)) return - if(!GLOB.universe.OnTouchMapEdge(src)) + if(!global.universe.OnTouchMapEdge(src)) return - if(GLOB.using_map.use_overmap) - overmap_spacetravel(get_turf(src), src) - return + if(overmap_id) + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + if(overmap) + overmap.travel(get_turf(src), src) + return var/new_x var/new_y - var/new_z = GLOB.using_map.get_transit_zlevel(z) + var/new_z = global.using_map.get_transit_zlevel(z) if(new_z) if(x <= TRANSITIONEDGE) new_x = world.maxx - TRANSITIONEDGE - 2 @@ -331,12 +362,273 @@ /atom/movable/proc/get_bullet_impact_effect_type() return BULLET_IMPACT_NONE -/atom/movable/attack_hand(mob/living/user) - // Anchored check so we can operate switches etc on grab intent without getting grab failure msgs. - if(istype(user) && !user.lying && user.a_intent == I_GRAB && !anchored) - user.make_grab(src) - return 0 +/atom/movable/proc/pushed(var/pushdir) + set waitfor = FALSE + step(src, pushdir) + +/** +* A wrapper for setDir that should only be able to fail by living mobs. +* +* Called from [/atom/movable/proc/keyLoop], this exists to be overwritten by living mobs with a check to see if we're actually alive enough to change directions +*/ +/atom/movable/proc/keybind_face_direction(direction) + return + +/atom/movable/proc/get_mob() + return buckled_mob + +/atom/movable/proc/can_buckle_mob(var/mob/living/dropping) + . = (can_buckle && istype(dropping) && !dropping.buckled && !dropping.anchored && !dropping.buckled_mob && !buckled_mob) + +/atom/movable/receive_mouse_drop(atom/dropping, mob/user, params) . = ..() + if(!. && can_buckle_mob(dropping)) + user_buckle_mob(dropping, user) + return TRUE + +/atom/movable/proc/buckle_mob(mob/living/M) + + if(buckled_mob) //unless buckled_mob becomes a list this can cause problems + return FALSE + + if(!istype(M) || (M.loc != loc) || M.buckled || LAZYLEN(M.pinned) || (buckle_require_restraints && !M.restrained())) + return FALSE + + M.buckled = src + M.facing_dir = null + if(!buckle_allow_rotation) + M.set_dir(buckle_dir ? buckle_dir : dir) + M.update_posture() + M.update_floating() + buckled_mob = M + + if(buckle_sound) + playsound(src, buckle_sound, 20) + + post_buckle_mob(M) + return TRUE + +/atom/movable/proc/unbuckle_mob() + if(buckled_mob && buckled_mob.buckled == src) + . = buckled_mob + buckled_mob.buckled = null + buckled_mob.anchored = initial(buckled_mob.anchored) + buckled_mob.update_posture() + buckled_mob.update_floating() + buckled_mob = null + post_buckle_mob(.) + +/atom/movable/proc/post_buckle_mob(mob/living/M) + if(M) + M.reset_offsets(4) + M.reset_plane_and_layer() + if(buckled_mob && buckled_mob != M) + refresh_buckled_mob() + +/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user) + if(M != user && user.incapacitated()) + return FALSE + if(M == buckled_mob) + return FALSE + if(!M.can_be_buckled(user)) + return FALSE + + add_fingerprint(user) + unbuckle_mob() + + //can't buckle unless you share locs so try to move M to the obj if buckle_require_same_tile turned off. + if(M.loc != src.loc) + if(buckle_require_same_tile) + return FALSE + M.dropInto(loc) + + . = buckle_mob(M) + if(.) + show_buckle_message(M, user) + +/atom/movable/proc/show_buckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + var/decl/pronouns/pronouns = buckled.get_pronouns() + visible_message( + SPAN_NOTICE("\The [buckled] buckles [pronouns.self] to \the [src]."), + SPAN_NOTICE("You buckle yourself to \the [src]."), + SPAN_NOTICE("You hear metal clanking.") + ) + else + visible_message( + SPAN_NOTICE("\The [buckled] is buckled to \the [src] by \the [buckling]!"), + SPAN_NOTICE("You are buckled to \the [src] by \the [buckling]!"), + SPAN_NOTICE("You hear metal clanking.") + ) + +/atom/movable/proc/user_unbuckle_mob(mob/user) + var/mob/living/M = unbuckle_mob() + if(M) + show_unbuckle_message(M, user) + for(var/obj/item/grab/grab as anything in (M.grabbed_by|grabbed_by)) + qdel(grab) + add_fingerprint(user) + return M + +/atom/movable/proc/show_unbuckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + var/decl/pronouns/pronouns = buckled.get_pronouns() + visible_message( + SPAN_NOTICE("\The [buckled] unbuckled [pronouns.self] from \the [src]!"), + SPAN_NOTICE("You unbuckle yourself from \the [src]."), + SPAN_NOTICE("You hear metal clanking.") + ) + else + visible_message( + SPAN_NOTICE("\The [buckled] was unbuckled from \the [src] by \the [buckling]!"), + SPAN_NOTICE("You were unbuckled from \the [src] by \the [buckling]."), + SPAN_NOTICE("You hear metal clanking.") + ) + +/atom/movable/proc/handle_buckled_relaymove(var/datum/movement_handler/mh, var/mob/mob, var/direction, var/mover) + return + +/atom/movable/singularity_act() + if(!simulated) + return 0 + physically_destroyed() + if(!QDELETED(src)) + qdel(src) + return 2 + +/atom/movable/singularity_pull(S, current_size) + if(simulated && !anchored) + step_towards(src, S) + +/atom/movable/proc/crossed_mob(var/mob/living/victim) + return + +/atom/movable/proc/get_object_size() + return ITEM_SIZE_NORMAL + +/atom/movable/get_manual_heat_source_coefficient() + return ..() * (get_object_size() / ITEM_SIZE_NORMAL) + +// TODO: account for reagents and matter. +/atom/movable/get_thermal_mass() + if(!simulated) + return 0 + return max(ITEM_SIZE_MIN, get_object_size()) * THERMAL_MASS_CONSTANT + +/atom/movable/get_thermal_mass_coefficient(delta) + if(!simulated) + return 0 + return (max(ITEM_SIZE_MIN, MOB_SIZE_MIN) * THERMAL_MASS_CONSTANT) / get_thermal_mass() + +/atom/movable/proc/try_burn_wearer(var/mob/living/holder, var/held_slot, var/delay = 0) + set waitfor = FALSE + + if(delay) + sleep(delay) + + if(!held_slot || !istype(holder) || QDELETED(holder) || loc != holder) + return + + // TODO: put these flags on the inventory slot or something. + var/check_slots + if(held_slot in global.all_hand_slots) + check_slots = SLOT_HANDS + else if(held_slot == BP_MOUTH || held_slot == BP_HEAD) + check_slots = SLOT_FACE + + if(check_slots) + for(var/obj/item/covering in holder.get_covering_equipped_items(check_slots)) + if(covering.max_heat_protection_temperature >= temperature) + return + + // TODO: less simplistic messages and logic + var/datum/inventory_slot/slot = held_slot && holder.get_inventory_slot_datum(held_slot) + var/check_organ = slot?.requires_organ_tag + if(temperature >= holder.get_mob_temperature_threshold(HEAT_LEVEL_3, check_organ)) + to_chat(holder, SPAN_DANGER("You are burned by \the [src]!")) + else if(temperature >= holder.get_mob_temperature_threshold(HEAT_LEVEL_2, check_organ)) + if(prob(10)) + to_chat(holder, SPAN_DANGER("\The [src] is uncomfortably hot...")) + return + else if(temperature <= holder.get_mob_temperature_threshold(COLD_LEVEL_3, check_organ)) + to_chat(holder, SPAN_DANGER("You are frozen by \the [src]!")) + else if(temperature <= holder.get_mob_temperature_threshold(COLD_LEVEL_2, check_organ)) + if(prob(10)) + to_chat(holder, SPAN_DANGER("\The [src] is uncomfortably cold...")) + return + else + return + + var/my_size = get_object_size() + var/burn_damage = rand(my_size, round(my_size * 1.5)) + var/obj/item/organ/external/organ = check_organ && holder.get_organ(check_organ) + if(istype(organ)) + organ.take_damage(burn_damage, BURN) + else + holder.take_damage(burn_damage, BURN) + if(held_slot in holder.get_held_item_slots()) + holder.drop_from_inventory(src) + else + . = null // We might keep burning them next time. + +/atom/movable/proc/update_appearance_flags(add_flags, remove_flags) + var/old_appearance = appearance_flags + if(add_flags) + appearance_flags |= add_flags + if(remove_flags) + appearance_flags &= ~remove_flags + return old_appearance != appearance_flags + +/atom/movable/proc/end_throw(datum/thrownthing/TT) + throwing = null + +/atom/movable/proc/reset_movement_delay() + var/datum/movement_handler/delay/delay = locate() in movement_handlers + if(istype(delay)) + delay.next_move = world.time + +/atom/movable/get_affecting_weather() + var/turf/my_turf = get_turf(src) + if(!istype(my_turf)) + return + var/turf/actual_loc = loc + // If we're standing in the rain, use the turf weather. + . = istype(actual_loc) && actual_loc.weather + if(!.) // If we're under or inside shelter, use the z-level rain (for ambience) + . = SSweather.weather_by_z[my_turf.z] + +/atom/movable/proc/handle_post_automoved(atom/old_loc) + return + +/atom/movable/take_vaporized_reagent(reagent, amount) + if(ATOM_IS_OPEN_CONTAINER(src)) + return loc?.take_vaporized_reagent(reagent, amount) + return null + +/atom/movable/immune_to_floor_hazards() + return ..() || !!throwing + +// TODO: make everything use this. +/atom/movable/proc/set_anchored(new_anchored) + SHOULD_CALL_PARENT(TRUE) + if(anchored != new_anchored) + anchored = new_anchored + return TRUE + return FALSE + +// updates pixel offsets, triggers fluids, etc. +/atom/movable/proc/on_turf_height_change(new_height) + if(simulated) + reset_offsets() + return TRUE + return FALSE + +/atom/movable/proc/get_cryogenic_power() + return 0 + +/atom/movable/proc/is_valid_merchant_pad_target() + return simulated -/atom/movable/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) - . = ..() || (mover && !(mover.movable_flags & MOVABLE_FLAG_NONDENSE_COLLISION) && !mover.density) +// TODO reimplement this properly. +/atom/movable/proc/is_incorporeal() + return !simulated diff --git a/code/game/atoms_movable_grabs.dm b/code/game/atoms_movable_grabs.dm index 04d6e82f6287..357047a0e316 100644 --- a/code/game/atoms_movable_grabs.dm +++ b/code/game/atoms_movable_grabs.dm @@ -3,16 +3,36 @@ return FALSE if(!CanPhysicallyInteract(grabber)) return FALSE - if(grabber.anchored || grabber.buckled) + if(!buckled_grab_check(grabber)) return FALSE if(anchored) to_chat(grabber, SPAN_WARNING("\The [src] won't budge!")) return FALSE return TRUE -/atom/movable/proc/reset_pixel_offsets_for_grab(var/obj/item/grab/G) - reset_plane_and_layer() +/atom/movable/proc/buckled_grab_check(var/mob/grabber) + if(grabber.buckled == src && buckled_mob == grabber) + return TRUE + if(grabber.anchored) + return FALSE + if(grabber.buckled) + return FALSE + return TRUE + +/atom/movable/handle_grab_interaction(var/mob/user) + + // Anchored check so we can operate switches etc on grab intent without getting grab failure msgs. + // NOTE: /mob/living overrides this to return FALSE in favour of using default_grab_interaction + if(isliving(user) && user.check_intent(I_FLAG_GRAB) && !user.current_posture.prone && !anchored) + return try_make_grab(user) + return ..() -/atom/movable/proc/adjust_pixel_offsets_for_grab(var/obj/item/grab/G, var/grab_dir) - reset_plane_and_layer() +/atom/movable/proc/try_make_grab(mob/living/user, defer_hand = FALSE) + if(istype(user) && CanPhysicallyInteract(user) && !user.current_posture.prone) + if(user == buckled_mob) + return give_control_grab(buckled_mob) + return user.make_grab(src, defer_hand = defer_hand) + return null +/atom/movable/proc/give_control_grab(var/mob/M) + return diff --git a/code/game/atoms_movable_interactions.dm b/code/game/atoms_movable_interactions.dm new file mode 100644 index 000000000000..81905ffd4920 --- /dev/null +++ b/code/game/atoms_movable_interactions.dm @@ -0,0 +1,33 @@ +/atom/movable/get_alt_interactions(var/mob/user) + . = ..() + if(get_config_value(/decl/config/toggle/expanded_alt_interactions)) + LAZYADD(., list( + /decl/interaction_handler/look, + /decl/interaction_handler/grab + )) + +/////////////////////////////////////////////////////////////////////////// +// Interaction Definitions +/////////////////////////////////////////////////////////////////////////// + +/decl/interaction_handler/look + name = "Examine" + expected_user_type = /mob + interaction_flags = 0 + examine_desc = "examine $TARGET_THEM$" + +/decl/interaction_handler/look/invoked(atom/target, mob/user, obj/item/prop) + target.examined_by(user, get_dist(user, target)) + +/decl/interaction_handler/grab + name = "Grab" + expected_target_type = /atom/movable + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEEDS_TURF + examine_desc = "grab $TARGET_THEM$" + +/decl/interaction_handler/grab/is_possible(atom/movable/target, mob/user, obj/item/prop) + return ..() && !target.anchored + +/decl/interaction_handler/grab/invoked(atom/target, mob/user, obj/item/prop) + var/atom/movable/AM = target + AM.try_make_grab(user, defer_hand = TRUE) diff --git a/code/game/atoms_movable_overlay.dm b/code/game/atoms_movable_overlay.dm new file mode 100644 index 000000000000..9f290edc35f7 --- /dev/null +++ b/code/game/atoms_movable_overlay.dm @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////// +// Overlays +/////////////////////////////////////////////////////////////////////////// + +/atom/movable/overlay + anchored = TRUE + simulated = FALSE + var/atom/master = null + var/follow_proc = /atom/movable/proc/move_to_loc_or_null + var/expected_master_type = /atom + +/atom/movable/overlay/Initialize() + if(!loc) + PRINT_STACK_TRACE("[type] created in nullspace.") + return INITIALIZE_HINT_QDEL + master = loc + if(expected_master_type && !istype(master, expected_master_type)) + return INITIALIZE_HINT_QDEL + SetName(master.name) + set_dir(master.dir) + + if(follow_proc && istype(master, /atom/movable)) + events_repository.register(/decl/observ/moved, master, src, follow_proc) + SetInitLoc() + + events_repository.register(/decl/observ/destroyed, master, src, TYPE_PROC_REF(/datum, qdel_self)) + events_repository.register(/decl/observ/dir_set, master, src, TYPE_PROC_REF(/atom, recursive_dir_set)) + + . = ..() + +/atom/movable/overlay/proc/SetInitLoc() + forceMove(master.loc) + +/atom/movable/overlay/Destroy() + if(istype(master, /atom/movable)) + events_repository.unregister(/decl/observ/moved, master, src) + events_repository.unregister(/decl/observ/destroyed, master, src) + events_repository.unregister(/decl/observ/dir_set, master, src) + master = null + . = ..() + +/atom/movable/overlay/attackby(obj/item/used_item, mob/user) + if (master) + return master.attackby(used_item, user) + return TRUE + +/atom/movable/overlay/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + return master?.attack_hand(user) diff --git a/code/game/atoms_movable_serde.dm b/code/game/atoms_movable_serde.dm new file mode 100644 index 000000000000..e47ee52da8fd --- /dev/null +++ b/code/game/atoms_movable_serde.dm @@ -0,0 +1,13 @@ +/atom/movable/Serialize() + . = ..() + if(isturf(loc)) + SERIALIZE_VALUE(loc, /atom/movable, list(loc.x, loc.y, loc.z)) + // The below does not handle cases where the nested instance is not itself persistent. + // In this case, if the instance tried to serialize while inside a non-persistent instance, it would + // throw a runtime on subsequent loads due to having a UID as a loc that does not map to a loaded instance. + else if(isatom(loc)) + SERIALIZE_VALUE(loc, /atom/movable, loc.get_run_uid()) + +/atom/movable/Deserialize(list/instance_map) + . = ..() + contents_were_modified() diff --git a/code/game/atoms_serde.dm b/code/game/atoms_serde.dm new file mode 100644 index 000000000000..e8212228384e --- /dev/null +++ b/code/game/atoms_serde.dm @@ -0,0 +1,81 @@ +/atom + /// Var for holding serde information when this atom was loaded from a persistent source. + var/__deserialization_payload + +/atom/Serialize() + . = ..() + if(current_health != get_max_health()) + SERIALIZE(current_health, /atom) + SERIALIZE_IF_MODIFIED(max_health, /atom) + SERIALIZE_IF_MODIFIED(dir, /atom) + if(ATOM_IS_TEMPERATURE_SENSITIVE(src)) + SERIALIZE_IF_MODIFIED(temperature, /atom) + if(istype(reagents)) + SERIALIZE_REAGENTS(reagents, /atom, "atom") + SERIALIZE_DECL_IF_MODIFIED(material, /atom) + SERIALIZE_DECL_IF_MODIFIED(reinf_material, /atom) + SERIALIZE_IF_MODIFIED(paint_color, /atom) + SERIALIZE_IF_MODIFIED(pixel_x, /atom) + SERIALIZE_IF_MODIFIED(pixel_y, /atom) + SERIALIZE_IF_MODIFIED(default_pixel_x, /atom) + SERIALIZE_IF_MODIFIED(default_pixel_y, /atom) + +// Keeping this in code for reference, but a large number of atoms generate +// name and desc at runtime, so not storing this in serde by default. +/* + SERIALIZE_IF_MODIFIED(name, /atom) + SERIALIZE_IF_MODIFIED(desc, /atom) +*/ + // TODO: serialize forensics + +/atom/proc/Deserialize(list/instance_map) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + for(var/data_key in __deserialization_payload) + if(data_key in vars) + try + if(!global._forbid_field_load[data_key] && (data_key in vars)) + vars[data_key] = __deserialization_payload[data_key] + else + PreloadKey(data_key, __deserialization_payload[data_key]) + catch(var/exception/E) + error("Failed to write [data_key] to [type] vars: [E]") + DESERIALIZE_REAGENTS(reagents, "atom") // Handled in initialize_reagents() + DESERIALIZE_DECL_TO_TYPE(material) + DESERIALIZE_DECL_TO_TYPE(reinf_material) + return SERDE_HINT_FINISHED + +/atom/ShouldSerialize(_age) + return ..() && simulated + +/atom/GetPossiblySerializableInstances() + . = ..() + var/list/contained = get_contained_external_atoms() + if(length(contained)) + . |= contained + +/atom/Exited(atom/movable/atom, atom/newloc) + . = ..() + if(simulated && atom.ShouldSerialize()) + contents_were_modified() + +/atom/Entered(atom/movable/atom, atom/old_loc) + . = ..() + if(simulated && atom.ShouldSerialize()) + contents_were_modified() + +// Called when an instance is being preloaded with information from deserialization. +/atom/proc/Preload(list/instance_map) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + var/turf/turf = get_turf(src) + if(__deserialization_payload) + try + . = Deserialize(instance_map) + catch(var/exception/E) + PRINT_STACK_TRACE("Exception when deserializing [type] at ([turf?.x || "NULL"],[turf?.y || "NULL"],[turf?.z || "NULL"]): [E]") + else + PRINT_STACK_TRACE("[type] at ([turf?.x || "NULL"],[turf?.y || "NULL"],[turf?.z || "NULL"]) tried to preload with no deserialization payload.") + +/atom/proc/PreloadKey(data_key, payload) + return diff --git a/code/game/atoms_temperature.dm b/code/game/atoms_temperature.dm index 46d8b2f34466..099b566cf783 100644 --- a/code/game/atoms_temperature.dm +++ b/code/game/atoms_temperature.dm @@ -1,65 +1,68 @@ -#define MIN_TEMPERATURE_COEFFICIENT 1 -#define MAX_TEMPERATURE_COEFFICIENT 10 - /atom + /// What is this atom's current temperature? var/temperature = T20C - var/temperature_coefficient = MAX_TEMPERATURE_COEFFICIENT /atom/movable/Entered(var/atom/movable/atom, var/atom/old_loc) . = ..() - QUEUE_TEMPERATURE_ATOMS(atom) - -/obj - temperature_coefficient = null + queue_temperature_atoms(atom) -/mob - temperature_coefficient = null +// If this is a simulated atom, adjust our temperature. +// This will eventually propagate to our contents via ProcessAtomTemperature() +/atom/proc/handle_external_heating(var/adjust_temp, var/obj/item/heated_by, var/mob/user) -/turf - temperature_coefficient = MIN_TEMPERATURE_COEFFICIENT + if(!ATOM_SHOULD_TEMPERATURE_ENQUEUE(src)) + return FALSE -/obj/Initialize() - . = ..() - temperature_coefficient = isnull(temperature_coefficient) ? Clamp(MAX_TEMPERATURE_COEFFICIENT - w_class, MIN_TEMPERATURE_COEFFICIENT, MAX_TEMPERATURE_COEFFICIENT) : temperature_coefficient - create_matter() + var/diff_temp = round(adjust_temp - temperature, 0.1) + if(abs(diff_temp) <= 0.1) + return FALSE -/obj/proc/HandleObjectHeating(var/obj/item/heated_by, var/mob/user, var/adjust_temp) - if(ATOM_IS_TEMPERATURE_SENSITIVE(src)) + // Show a little message for people heating beakers with welding torches. + if(user && heated_by) visible_message(SPAN_NOTICE("\The [user] carefully heats \the [src] with \the [heated_by].")) - var/diff_temp = (adjust_temp - temperature) - if(diff_temp >= 0) - var/altered_temp = max(temperature + (ATOM_TEMPERATURE_EQUILIBRIUM_CONSTANT * temperature_coefficient * diff_temp), 0) - ADJUST_ATOM_TEMPERATURE(src, min(adjust_temp, altered_temp)) + // Update our own heat. + var/altered_temp = max(temperature + (get_thermal_mass_coefficient(diff_temp) * diff_temp * (heated_by ? heated_by.get_manual_heat_source_coefficient() : 1)), 0) + ADJUST_ATOM_TEMPERATURE(src, min(adjust_temp, altered_temp)) + return TRUE -/mob/Initialize() - . = ..() - temperature_coefficient = isnull(temperature_coefficient) ? Clamp(MAX_TEMPERATURE_COEFFICIENT - Floor(mob_size/4), MIN_TEMPERATURE_COEFFICIENT, MAX_TEMPERATURE_COEFFICIENT) : temperature_coefficient +/atom/proc/get_manual_heat_source_coefficient() + return 1 + +/// Returns the 'ambient temperature' used for temperature equalisation. +/atom/proc/get_ambient_temperature() + if(isturf(loc)) + return loc.return_air().temperature + else if(loc) + return loc.temperature + // Nullspace is room temperature, clearly. + return T20C +/// Returns the coefficient used for ambient temperature equalisation. +/// Mainly used to prevent vacuum from cooling down objects. +/atom/proc/get_ambient_temperature_coefficient() + if(isturf(loc)) + //scale the thermal mass coefficient so that 1atm = 1x, 0atm = 0x, 10atm = 10x + return loc.return_air().return_pressure() / ONE_ATMOSPHERE + return 1 + +// TODO: move mob bodytemperature onto this proc. /atom/proc/ProcessAtomTemperature() SHOULD_NOT_SLEEP(TRUE) - // Get our location temperature if possible. - // Nullspace is room temperature, clearly. - var/adjust_temp - if(loc) - if(!istype(loc, /turf/simulated)) - adjust_temp = loc.temperature - else - var/turf/simulated/T = loc - if(T.zone && T.zone.air) - adjust_temp = T.zone.air.temperature - else - adjust_temp = T20C - else - adjust_temp = T20C - + // Get our ambient temperature if possible. + var/adjust_temp = get_ambient_temperature() var/diff_temp = adjust_temp - temperature - if(abs(diff_temp) >= ATOM_TEMPERATURE_EQUILIBRIUM_THRESHOLD) - var/altered_temp = max(temperature + (ATOM_TEMPERATURE_EQUILIBRIUM_CONSTANT * temperature_coefficient * diff_temp), 0) + var/thermal_mass_coefficient = get_thermal_mass_coefficient(diff_temp) * get_ambient_temperature_coefficient() + + // Determine if our temperature needs to change. + var/old_temp = temperature + if(abs(diff_temp) >= (thermal_mass_coefficient * ATOM_TEMPERATURE_EQUILIBRIUM_THRESHOLD)) + var/altered_temp = max(temperature + (thermal_mass_coefficient * diff_temp), 0) ADJUST_ATOM_TEMPERATURE(src, (diff_temp > 0) ? min(adjust_temp, altered_temp) : max(adjust_temp, altered_temp)) else temperature = adjust_temp - return PROCESS_KILL + . = PROCESS_KILL -#undef MIN_TEMPERATURE_COEFFICIENT -#undef MAX_TEMPERATURE_COEFFICIENT + // If our temperature changed, our contents probably want to know about it. + if(temperature != old_temp) + queue_temperature_atoms(get_contained_temperature_sensitive_atoms()) diff --git a/code/game/base_turf.dm b/code/game/base_turf.dm index 0a87cfa5f54c..f76dea523fa2 100644 --- a/code/game/base_turf.dm +++ b/code/game/base_turf.dm @@ -1,18 +1,48 @@ // Returns the lowest turf available on a given Z-level -proc/get_base_turf(var/z_num) - var/z = num2text(z_num) - if(!GLOB.using_map.base_turf_by_z[z]) - GLOB.using_map.base_turf_by_z[z] = world.turf - return GLOB.using_map.base_turf_by_z[z] +/proc/get_base_turf(var/z_num) + if(!SSmapping.base_turf_by_z[z_num]) + SSmapping.base_turf_by_z[z_num] = world.turf + return SSmapping.base_turf_by_z[z_num] //An area can override the z-level base turf, so our solar array areas etc. can be space-based. -proc/get_base_turf_by_area(var/turf/T) - var/area/A = T.loc - if(A.base_turf) +/proc/get_base_turf_by_area(var/turf/T) + if(!istype(T)) + return + var/area/A = get_area(T) + if(HasBelow(T.z)) + if(istype(A) && A.open_turf) + return A.open_turf + + // Find the first non-open turf below and use its open_turf_type. + var/z_stack_type = get_open_turf_type(T) + if(z_stack_type) + return z_stack_type + + // Otherwise, default to the open turf type set on the turf being removed. + if(T.open_turf_type) + return T.open_turf_type + if(istype(A) && A.base_turf) return A.base_turf return get_base_turf(T.z) +/proc/get_open_turf_type_by_area(var/turf/T) + if(!HasBelow(T.z)) + return + var/area/area = get_area(T) + return area?.open_turf || T.open_turf_type + +// Returns the open turf of a Z-stack by finding the nearest non-open turf below. +/proc/get_open_turf_type(var/turf/T) + if(!istype(T) || !HasBelow(T.z)) + return + var/turf/below = T + while ((below = GetBelow(below))) + if(!below.is_open() || !HasBelow(below.z)) + if(below.open_turf_type) + return below.open_turf_type + return + /client/proc/set_base_turf() set category = "Debug" set name = "Set Base Turf" @@ -20,13 +50,13 @@ proc/get_base_turf_by_area(var/turf/T) if(!check_rights(R_DEBUG)) return - var/choice = input("Which Z-level do you wish to set the base turf for?") as num|null + var/choice = clamp(input("Which Z-level do you wish to set the base turf for?") as num|null, 0, length(SSmapping.base_turf_by_z)) if(!choice) return var/new_base_path = input("Please select a turf path (cancel to reset to /turf/space).") as null|anything in typesof(/turf) if(!new_base_path) new_base_path = /turf/space - GLOB.using_map.base_turf_by_z["[choice]"] = new_base_path + SSmapping.base_turf_by_z[choice] = new_base_path message_admins("[key_name_admin(usr)] has set the base turf for z-level [choice] to [get_base_turf(choice)].") log_admin("[key_name(usr)] has set the base turf for z-level [choice] to [get_base_turf(choice)].") diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm deleted file mode 100644 index 2057371012c6..000000000000 --- a/code/game/dna/dna2.dm +++ /dev/null @@ -1,376 +0,0 @@ -/** -* DNA 2: The Spaghetti Strikes Back -* -* @author N3X15 -*/ - -// What each index means: -#define DNA_OFF_LOWERBOUND 0 -#define DNA_OFF_UPPERBOUND 1 -#define DNA_ON_LOWERBOUND 2 -#define DNA_ON_UPPERBOUND 3 - -// Define block bounds (off-low,off-high,on-low,on-high) -// Used in setupgame.dm -#define DNA_DEFAULT_BOUNDS list(1,2049,2050,4095) -#define DNA_HARDER_BOUNDS list(1,3049,3050,4095) -#define DNA_HARD_BOUNDS list(1,3490,3500,4095) - -// UI Indices (can change to mutblock style, if desired) -#define DNA_UI_HAIR_R 1 -#define DNA_UI_HAIR_G 2 -#define DNA_UI_HAIR_B 3 -#define DNA_UI_BEARD_R 4 -#define DNA_UI_BEARD_G 5 -#define DNA_UI_BEARD_B 6 -#define DNA_UI_SKIN_TONE 7 -#define DNA_UI_SKIN_R 8 -#define DNA_UI_SKIN_G 9 -#define DNA_UI_SKIN_B 10 -#define DNA_UI_EYES_R 11 -#define DNA_UI_EYES_G 12 -#define DNA_UI_EYES_B 13 -#define DNA_UI_GENDER 14 -#define DNA_UI_BEARD_STYLE 15 -#define DNA_UI_HAIR_STYLE 16 -#define DNA_UI_LENGTH 16 // Update this when you add something, or you WILL break shit. - -#define DNA_SE_LENGTH 27 -// For later: -//#define DNA_SE_LENGTH 50 // Was STRUCDNASIZE, size 27. 15 new blocks added = 42, plus room to grow. - - -// Defines which values mean "on" or "off". -// This is to make some of the more OP superpowers a larger PITA to activate, -// and to tell our new DNA datum which values to set in order to turn something -// on or off. -var/global/list/dna_activity_bounds[DNA_SE_LENGTH] - -// Used to determine what each block means (admin hax and species stuff on /vg/, mostly) -var/global/list/assigned_blocks[DNA_SE_LENGTH] - -var/global/list/datum/dna/gene/dna_genes[0] - -///////////////// -// GENE DEFINES -///////////////// -// Skip checking if it's already active. -// Used for genes that check for value rather than a binary on/off. -#define GENE_ALWAYS_ACTIVATE 1 - -/datum/dna - // READ-ONLY, GETS OVERWRITTEN - // DO NOT FUCK WITH THESE OR BYOND WILL EAT YOUR FACE - var/uni_identity="" // Encoded UI - var/struc_enzymes="" // Encoded SE - var/unique_enzymes="" // MD5 of player name - - // Internal dirtiness checks - var/dirtyUI=0 - var/dirtySE=0 - - // Okay to read, but you're an idiot if you do. - // BLOCK = VALUE - var/list/SE[DNA_SE_LENGTH] - var/list/UI[DNA_UI_LENGTH] - - // From old dna. - var/b_type = "A+" // Should probably change to an integer => string map but I'm lazy. - var/real_name // Stores the real name of the person who originally got this dna datum. Used primarily for changelings, - - // New stuff - var/species - var/skin_base = "" - var/list/body_markings = list() - -// Make a copy of this strand. -// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION! -/datum/dna/proc/Clone() - var/datum/dna/new_dna = new() - new_dna.unique_enzymes=unique_enzymes - new_dna.b_type=b_type - new_dna.real_name=real_name - new_dna.species=species || GLOB.using_map.default_species - new_dna.body_markings=body_markings.Copy() - new_dna.skin_base=skin_base - for(var/b=1;b<=DNA_SE_LENGTH;b++) - new_dna.SE[b]=SE[b] - if(b<=DNA_UI_LENGTH) - new_dna.UI[b]=UI[b] - new_dna.UpdateUI() - new_dna.UpdateSE() - return new_dna -/////////////////////////////////////// -// UNIQUE IDENTITY -/////////////////////////////////////// - -// Create random UI. -/datum/dna/proc/ResetUI(var/defer=0) - for(var/i=1,i<=DNA_UI_LENGTH,i++) - switch(i) - if(DNA_UI_SKIN_TONE) - SetUIValueRange(DNA_UI_SKIN_TONE,rand(1,220),220,1) // Otherwise, it gets fucked - else - UI[i]=rand(0,4095) - if(!defer) - UpdateUI() - -/datum/dna/proc/ResetUIFrom(var/mob/living/carbon/human/character) - // INITIALIZE! - ResetUI(1) - // Hair - // FIXME: Species-specific defaults pls - if(!character.h_style) - character.h_style = "Skinhead" - var/hair = GLOB.hair_styles_list.Find(character.h_style) - - // Facial Hair - if(!character.f_style) - character.f_style = "Shaved" - var/beard = GLOB.facial_hair_styles_list.Find(character.f_style) - - SetUIValueRange(DNA_UI_HAIR_R, HEX_RED(character.hair_colour), 255, 1) - SetUIValueRange(DNA_UI_HAIR_G, HEX_GREEN(character.hair_colour), 255, 1) - SetUIValueRange(DNA_UI_HAIR_B, HEX_BLUE(character.hair_colour), 255, 1) - - SetUIValueRange(DNA_UI_BEARD_R, HEX_RED(character.hair_colour), 255, 1) - SetUIValueRange(DNA_UI_BEARD_G, HEX_GREEN(character.hair_colour), 255, 1) - SetUIValueRange(DNA_UI_BEARD_B, HEX_BLUE(character.hair_colour), 255, 1) - - SetUIValueRange(DNA_UI_EYES_R, HEX_RED(character.eye_colour), 255, 1) - SetUIValueRange(DNA_UI_EYES_G, HEX_GREEN(character.eye_colour), 255, 1) - SetUIValueRange(DNA_UI_EYES_B, HEX_BLUE(character.eye_colour), 255, 1) - - SetUIValueRange(DNA_UI_SKIN_R, HEX_RED(character.skin_colour), 255, 1) - SetUIValueRange(DNA_UI_SKIN_G, HEX_GREEN(character.skin_colour), 255, 1) - SetUIValueRange(DNA_UI_SKIN_B, HEX_BLUE(character.skin_colour), 255, 1) - - SetUIValueRange(DNA_UI_SKIN_TONE, 35-character.skin_tone, 220, 1) // Value can be negative. - - SetUIState(DNA_UI_GENDER, character.gender!=MALE, 1) - - SetUIValueRange(DNA_UI_HAIR_STYLE, hair, GLOB.hair_styles_list.len, 1) - SetUIValueRange(DNA_UI_BEARD_STYLE, beard, GLOB.facial_hair_styles_list.len,1) - - body_markings.Cut() - skin_base = character.skin_base - for(var/obj/item/organ/external/E in character.organs) - E.skin_base = skin_base - if(E.markings.len) - body_markings[E.organ_tag] = E.markings.Copy() - - UpdateUI() - -// Set a DNA UI block's raw value. -/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0) - if (block<=0) return - ASSERT(value>0) - ASSERT(value<=4095) - UI[block]=value - dirtyUI=1 - if(!defer) - UpdateUI() - -// Get a DNA UI block's raw value. -/datum/dna/proc/GetUIValue(var/block) - if (block<=0) return 0 - return UI[block] - -// Set a DNA UI block's value, given a value and a max possible value. -// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list) -/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0) - if (block<=0) return - if (value==0) value = 1 // FIXME: hair/beard/eye RGB values if they are 0 are not set, this is a work around we'll encode it in the DNA to be 1 instead. - ASSERT(maxvalue<=4095) - var/range = (4095 / maxvalue) - if(value) - SetUIValue(block,round(value * range),defer) - -// Getter version of above. -/datum/dna/proc/GetUIValueRange(var/block,var/maxvalue) - if (block<=0) return 0 - var/value = GetUIValue(block) - return round(1 +(value / 4096)*maxvalue) - -// Is the UI gene "on" or "off"? -// For UI, this is simply a check of if the value is > 2050. -/datum/dna/proc/GetUIState(var/block) - if (block<=0) return - return UI[block] > 2050 - - -// Set UI gene "on" (1) or "off" (0) -/datum/dna/proc/SetUIState(var/block,var/on,var/defer=0) - if (block<=0) return - var/val - if(on) - val=rand(2050,4095) - else - val=rand(1,2049) - SetUIValue(block,val,defer) - -// Get a hex-encoded UI block. -/datum/dna/proc/GetUIBlock(var/block) - return EncodeDNABlock(GetUIValue(block)) - -// Do not use this unless you absolutely have to. -// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). -// Used in DNA modifiers. -/datum/dna/proc/SetUIBlock(var/block,var/value,var/defer=0) - if (block<=0) return - return SetUIValue(block,hex2num(value),defer) - -// Get a sub-block from a block. -/datum/dna/proc/GetUISubBlock(var/block,var/subBlock) - return copytext(GetUIBlock(block),subBlock,subBlock+1) - -// Do not use this unless you absolutely have to. -// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). -// Used in DNA modifiers. -/datum/dna/proc/SetUISubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0) - if (block<=0) return - var/oldBlock=GetUIBlock(block) - var/newBlock="" - for(var/i=1, i<=length(oldBlock), i++) - if(i==subBlock) - newBlock+=newSubBlock - else - newBlock+=copytext(oldBlock,i,i+1) - SetUIBlock(block,newBlock,defer) - -/////////////////////////////////////// -// STRUCTURAL ENZYMES -/////////////////////////////////////// - -// "Zeroes out" all of the blocks. -/datum/dna/proc/ResetSE() - for(var/i = 1, i <= DNA_SE_LENGTH, i++) - SetSEValue(i,rand(1,1024),1) - UpdateSE() - -// Set a DNA SE block's raw value. -/datum/dna/proc/SetSEValue(var/block,var/value,var/defer=0) - if (block<=0) return - ASSERT(value>=0) - ASSERT(value<=4095) - SE[block]=value - dirtySE=1 - if(!defer) - UpdateSE() - -// Get a DNA SE block's raw value. -/datum/dna/proc/GetSEValue(var/block) - if (block<=0) return 0 - return SE[block] - -// Set a DNA SE block's value, given a value and a max possible value. -// Might be used for species? -/datum/dna/proc/SetSEValueRange(var/block,var/value,var/maxvalue) - if (block<=0) return - ASSERT(maxvalue<=4095) - var/range = round(4095 / maxvalue) - if(value) - SetSEValue(block, value * range - rand(1,range-1)) - -// Getter version of above. -/datum/dna/proc/GetSEValueRange(var/block,var/maxvalue) - if (block<=0) return 0 - var/value = GetSEValue(block) - return round(1 +(value / 4096)*maxvalue) - -// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.) -/datum/dna/proc/GetSEState(var/block) - if (block<=0) return 0 - var/list/BOUNDS=GetDNABounds(block) - var/value=GetSEValue(block) - return (value > BOUNDS[DNA_ON_LOWERBOUND]) - -// Set a block "on" or "off". -/datum/dna/proc/SetSEState(var/block,var/on,var/defer=0) - if (block<=0) return - var/list/BOUNDS=GetDNABounds(block) - var/val - if(on) - val=rand(BOUNDS[DNA_ON_LOWERBOUND],BOUNDS[DNA_ON_UPPERBOUND]) - else - val=rand(1,BOUNDS[DNA_OFF_UPPERBOUND]) - SetSEValue(block,val,defer) - -// Get hex-encoded SE block. -/datum/dna/proc/GetSEBlock(var/block) - return EncodeDNABlock(GetSEValue(block)) - -// Do not use this unless you absolutely have to. -// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). -// Used in DNA modifiers. -/datum/dna/proc/SetSEBlock(var/block,var/value,var/defer=0) - if (block<=0) return - var/nval=hex2num(value) - //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]") - return SetSEValue(block,nval,defer) - -/datum/dna/proc/GetSESubBlock(var/block,var/subBlock) - return copytext(GetSEBlock(block),subBlock,subBlock+1) - -// Do not use this unless you absolutely have to. -// Set a sub-block from a hex character. This is inefficient. If you can, use SetUIValue(). -// Used in DNA modifiers. -/datum/dna/proc/SetSESubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0) - if (block<=0) return - var/oldBlock=GetSEBlock(block) - var/newBlock="" - for(var/i=1, i<=length(oldBlock), i++) - if(i==subBlock) - newBlock+=newSubBlock - else - newBlock+=copytext(oldBlock,i,i+1) - //testing("SetSESubBlock([block],[subBlock],[newSubBlock],[defer]): [oldBlock] -> [newBlock]") - SetSEBlock(block,newBlock,defer) - - -/proc/EncodeDNABlock(var/value) - return add_zero2(num2hex(value,1), 3) - -/datum/dna/proc/UpdateUI() - src.uni_identity="" - for(var/block in UI) - uni_identity += EncodeDNABlock(block) - //testing("New UI: [uni_identity]") - dirtyUI=0 - -/datum/dna/proc/UpdateSE() - //var/oldse=struc_enzymes - struc_enzymes="" - for(var/block in SE) - struc_enzymes += EncodeDNABlock(block) - //testing("Old SE: [oldse]") - //testing("New SE: [struc_enzymes]") - dirtySE=0 - -// BACK-COMPAT! -// Just checks our character has all the crap it needs. -/datum/dna/proc/check_integrity(var/mob/living/carbon/human/character) - if(character) - if(UI.len != DNA_UI_LENGTH) - ResetUIFrom(character) - - if(length(struc_enzymes)!= 3*DNA_SE_LENGTH) - ResetSE() - - if(length(unique_enzymes) != 32) - unique_enzymes = md5(character.real_name) - else - if(length(uni_identity) != 3*DNA_UI_LENGTH) - uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4" - if(length(struc_enzymes)!= 3*DNA_SE_LENGTH) - struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" - -// BACK-COMPAT! -// Initial DNA setup. I'm kind of wondering why the hell this doesn't just call the above. -/datum/dna/proc/ready_dna(mob/living/carbon/human/character) - ResetUIFrom(character) - - ResetSE() - - unique_enzymes = md5(character.real_name) - GLOB.reg_dna[unique_enzymes] = character.real_name diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm deleted file mode 100644 index a19f5e22333c..000000000000 --- a/code/game/dna/dna2_domutcheck.dm +++ /dev/null @@ -1,47 +0,0 @@ -// (Re-)Apply mutations. -// TODO: Turn into a /mob proc, change inj to a bitflag for various forms of differing behavior. -// M: Mob to mess with -// connected: Machine we're in, type unchecked so I doubt it's used beyond monkeying -// flags: See below, bitfield. -#define MUTCHK_FORCED 1 -/proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.should_have_organ(BP_HEART)) - return - for(var/datum/dna/gene/gene in dna_genes) - if(!M || !M.dna) - return - if(!gene.block) - continue - - // Sanity checks, don't skip. - if(!gene.can_activate(M,flags)) - //testing("[M] - Failed to activate [gene.name] (can_activate fail).") - continue - - // Current state - var/gene_active = (gene.flags & GENE_ALWAYS_ACTIVATE) - if(!gene_active) - gene_active = M.dna.GetSEState(gene.block) - - // Prior state - var/gene_prior_status = (gene.type in M.active_genes) - var/changed = gene_active != gene_prior_status || (gene.flags & GENE_ALWAYS_ACTIVATE) - - // If gene state has changed: - if(changed) - // Gene active (or ALWAYS ACTIVATE) - if(gene_active || (gene.flags & GENE_ALWAYS_ACTIVATE)) - testing("[gene.name] activated!") - gene.activate(M,connected,flags) - if(M) - M.active_genes |= gene.type - M.update_icon = 1 - // If Gene is NOT active: - else - testing("[gene.name] deactivated!") - gene.deactivate(M,connected,flags) - if(M) - M.active_genes -= gene.type - M.update_icon = 1 diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm deleted file mode 100644 index ae83a8cd9039..000000000000 --- a/code/game/dna/dna2_helpers.dm +++ /dev/null @@ -1,187 +0,0 @@ -///////////////////////////// -// Helpers for DNA2 -///////////////////////////// - -// Pads 0s to t until length == u -/proc/add_zero2(t, u) - var/temp1 - while (length(t) < u) - t = "0[t]" - temp1 = t - if (length(t) > u) - temp1 = copytext(t,2,u+1) - return temp1 - -// DNA Gene activation boundaries, see dna2.dm. -// Returns a list object with 4 numbers. -/proc/GetDNABounds(var/block) - var/list/BOUNDS=dna_activity_bounds[block] - if(!istype(BOUNDS)) - return DNA_DEFAULT_BOUNDS - return BOUNDS - -// Give Random Bad Mutation to M -/proc/randmutb(var/mob/living/M) - if(!M) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.should_have_organ(BP_HEART)) - return - M.dna.check_integrity() - var/block = pick(GLOB.GLASSESBLOCK,GLOB.COUGHBLOCK,GLOB.FAKEBLOCK,GLOB.NERVOUSBLOCK,GLOB.CLUMSYBLOCK,GLOB.TWITCHBLOCK,GLOB.HEADACHEBLOCK,GLOB.BLINDBLOCK,GLOB.DEAFBLOCK,GLOB.HALLUCINATIONBLOCK) - M.dna.SetSEState(block, 1) - -// Give Random Good Mutation to M -/proc/randmutg(var/mob/living/M) - if(!M) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.should_have_organ(BP_HEART)) - return - M.dna.check_integrity() - var/block = pick(GLOB.HULKBLOCK,GLOB.XRAYBLOCK,GLOB.FIREBLOCK,GLOB.TELEBLOCK,GLOB.NOBREATHBLOCK,GLOB.REMOTEVIEWBLOCK,GLOB.REGENERATEBLOCK,GLOB.INCREASERUNBLOCK,GLOB.REMOTETALKBLOCK,GLOB.MORPHBLOCK,GLOB.BLENDBLOCK,GLOB.NOPRINTSBLOCK,GLOB.SHOCKIMMUNITYBLOCK,GLOB.SMALLSIZEBLOCK) - M.dna.SetSEState(block, 1) - -// Random Appearance Mutation -/proc/randmuti(var/mob/living/M) - if(!M) return - M.dna.check_integrity() - M.dna.SetUIValue(rand(1,DNA_UI_LENGTH),rand(1,4095)) - -// Scramble UI or SE. -/proc/scramble(var/UI, var/mob/M, var/prob) - if(!M) return - M.dna.check_integrity() - if(UI) - for(var/i = 1, i <= DNA_UI_LENGTH-1, i++) - if(prob(prob)) - M.dna.SetUIValue(i,rand(1,4095),1) - M.dna.UpdateUI() - M.UpdateAppearance() - - else - for(var/i = 1, i <= DNA_SE_LENGTH-1, i++) - if(prob(prob)) - M.dna.SetSEValue(i,rand(1,4095),1) - M.dna.UpdateSE() - domutcheck(M, null) - return - -// I haven't yet figured out what the fuck this is supposed to do. -/proc/miniscramble(input,rs,rd) - var/output - output = null - if (input == "C" || input == "D" || input == "E" || input == "F") - output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"6",prob((rs*10));"7",prob((rs*5)+(rd));"0",prob((rs*5)+(rd));"1",prob((rs*10)-(rd));"2",prob((rs*10)-(rd));"3") - if (input == "8" || input == "9" || input == "A" || input == "B") - output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") - if (input == "4" || input == "5" || input == "6" || input == "7") - output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") - if (input == "0" || input == "1" || input == "2" || input == "3") - output = pick(prob((rs*10));"8",prob((rs*10));"9",prob((rs*10));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C",prob((rs*10)-(rd));"D",prob((rs*5)+(rd));"E",prob((rs*5)+(rd));"F") - if (!output) output = "5" - return output - -// HELLO I MAKE BELL CURVES AROUND YOUR DESIRED TARGET -// So a shitty way of replacing gaussian noise. -// input: YOUR TARGET -// rs: RAD STRENGTH -// rd: DURATION -/proc/miniscrambletarget(input,rs,rd) - var/output = null - switch(input) - if("0") - output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10));"2",prob((rs*10)-(rd));"3") - if("1") - output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10));"3",prob((rs*10)-(rd));"4") - if("2") - output = pick(prob((rs*10));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10));"4",prob((rs*10)-(rd));"5") - if("3") - output = pick(prob((rs*10)-(rd));"0",prob((rs*10));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10));"5",prob((rs*10)-(rd));"6") - if("4") - output = pick(prob((rs*10)-(rd));"1",prob((rs*10));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10));"6",prob((rs*10)-(rd));"7") - if("5") - output = pick(prob((rs*10)-(rd));"2",prob((rs*10));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10));"7",prob((rs*10)-(rd));"8") - if("6") - output = pick(prob((rs*10)-(rd));"3",prob((rs*10));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10));"8",prob((rs*10)-(rd));"9") - if("7") - output = pick(prob((rs*10)-(rd));"4",prob((rs*10));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10));"9",prob((rs*10)-(rd));"A") - if("8") - output = pick(prob((rs*10)-(rd));"5",prob((rs*10));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10));"A",prob((rs*10)-(rd));"B") - if("9") - output = pick(prob((rs*10)-(rd));"6",prob((rs*10));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C") - if("10")//A - output = pick(prob((rs*10)-(rd));"7",prob((rs*10));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10));"C",prob((rs*10)-(rd));"D") - if("11")//B - output = pick(prob((rs*10)-(rd));"8",prob((rs*10));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10));"D",prob((rs*10)-(rd));"E") - if("12")//C - output = pick(prob((rs*10)-(rd));"9",prob((rs*10));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10));"E",prob((rs*10)-(rd));"F") - if("13")//D - output = pick(prob((rs*10)-(rd));"A",prob((rs*10));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10));"F") - if("14")//E - output = pick(prob((rs*10)-(rd));"B",prob((rs*10));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F") - if("15")//F - output = pick(prob((rs*10)-(rd));"C",prob((rs*10));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F") - - if(!input || !output) //How did this happen? - output = "8" - - return output - -// /proc/updateappearance has changed behavior, so it's been removed -// Use mob.UpdateAppearance() instead. - -// Simpler. Don't specify UI in order for the mob to use its own. -/mob/proc/UpdateAppearance(var/list/UI=null) - if(istype(src, /mob/living/carbon/human)) - if(UI!=null) - src.dna.UI=UI - src.dna.UpdateUI() - dna.check_integrity() - var/mob/living/carbon/human/H = src - H.hair_colour = rgb(dna.GetUIValueRange(DNA_UI_HAIR_R,255), dna.GetUIValueRange(DNA_UI_HAIR_G,255), dna.GetUIValueRange(DNA_UI_HAIR_B,255)) - H.facial_hair_colour = rgb(dna.GetUIValueRange(DNA_UI_BEARD_R,255), dna.GetUIValueRange(DNA_UI_BEARD_G,255), dna.GetUIValueRange(DNA_UI_BEARD_B,255)) - H.skin_colour = rgb(dna.GetUIValueRange(DNA_UI_SKIN_R,255), dna.GetUIValueRange(DNA_UI_SKIN_G,255), dna.GetUIValueRange(DNA_UI_SKIN_B,255)) - H.eye_colour = rgb(dna.GetUIValueRange(DNA_UI_EYES_R,255), dna.GetUIValueRange(DNA_UI_EYES_G,255), dna.GetUIValueRange(DNA_UI_EYES_B,255)) - H.update_eyes() - H.skin_tone = 35 - dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative. - - if(H.gender != NEUTER) - if (dna.GetUIState(DNA_UI_GENDER)) - H.gender = FEMALE - else - H.gender = MALE - - //Body markings - for(var/tag in dna.body_markings) - var/obj/item/organ/external/E = H.organs_by_name[tag] - if(E) - var/list/marklist = dna.body_markings[tag] - E.markings = marklist.Copy() - - //Base skin and blend - for(var/obj/item/organ/external/E in H.organs) - E.set_dna(E.dna) - - //Hair - var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,GLOB.hair_styles_list.len) - if((0 < hair) && (hair <= GLOB.hair_styles_list.len)) - H.h_style = GLOB.hair_styles_list[hair] - - //Facial Hair - var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,GLOB.facial_hair_styles_list.len) - if((0 < beard) && (beard <= GLOB.facial_hair_styles_list.len)) - H.f_style = GLOB.facial_hair_styles_list[beard] - - H.force_update_limbs() - H.update_body() - H.update_eyes() - H.update_hair() - - return 1 - else - return 0 - -// Used below, simple injection modifier. -/proc/probinj(var/pr, var/inj) - return prob(pr+inj*pr) diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm deleted file mode 100644 index 89e901ed6a53..000000000000 --- a/code/game/dna/genes/disabilities.dm +++ /dev/null @@ -1,129 +0,0 @@ -///////////////////// -// DISABILITY GENES -// -// These activate either a mutation, disability, or sdisability. -// -// Gene is always activated. -///////////////////// - -/datum/dna/gene/disability - name="DISABILITY" - - // Mutation to give (or 0) - var/mutation=0 - - // Disability to give (or 0) - var/disability=0 - - // SDisability to give (or 0) - var/sdisability=0 - - // Activation message - var/activation_message="" - - // Yay, you're no longer growing 3 arms - var/deactivation_message="" - -/datum/dna/gene/disability/can_activate(var/mob/M,var/flags) - return 1 // Always set! - -/datum/dna/gene/disability/activate(var/mob/M, var/connected, var/flags) - if(mutation && !(mutation in M.mutations)) - M.mutations.Add(mutation) - if(disability) - M.disabilities|=disability - if(sdisability) - M.set_sdisability(sdisability) - if(activation_message) - to_chat(M, "[activation_message]") - else - testing("[name] has no activation message.") - -/datum/dna/gene/disability/deactivate(var/mob/M, var/connected, var/flags) - if(mutation && (mutation in M.mutations)) - M.mutations.Remove(mutation) - if(disability) - M.disabilities &= (~disability) - if(sdisability) - M.unset_sdisability(sdisability) - if(deactivation_message) - to_chat(M, "[deactivation_message]") - else - testing("[name] has no deactivation message.") - -// Note: Doesn't seem to do squat, at the moment. -/datum/dna/gene/disability/hallucinate - name="Hallucinate" - activation_message="Your mind says 'Hello'." - mutation=mHallucination - -/datum/dna/gene/disability/hallucinate/New() - block=GLOB.HALLUCINATIONBLOCK - -/datum/dna/gene/disability/epilepsy - name="Epilepsy" - activation_message="You get a headache." - disability=EPILEPSY - -/datum/dna/gene/disability/epilepsy/New() - block=GLOB.HEADACHEBLOCK - -/datum/dna/gene/disability/cough - name="Coughing" - activation_message="You start coughing." - disability=COUGHING - -/datum/dna/gene/disability/cough/New() - block=GLOB.COUGHBLOCK - -/datum/dna/gene/disability/clumsy - name="Clumsiness" - activation_message="You feel lightheaded." - mutation=MUTATION_CLUMSY - -/datum/dna/gene/disability/clumsy/New() - block=GLOB.CLUMSYBLOCK - -/datum/dna/gene/disability/tourettes - name="Tourettes" - activation_message="You twitch." - disability=TOURETTES - -/datum/dna/gene/disability/tourettes/New() - block=GLOB.TWITCHBLOCK - -/datum/dna/gene/disability/nervousness - name="Nervousness" - activation_message="You feel nervous." - disability=NERVOUS - -/datum/dna/gene/disability/nervousness/New() - block=GLOB.NERVOUSBLOCK - -/datum/dna/gene/disability/blindness - name="Blindness" - activation_message="You can't seem to see anything." - sdisability=BLINDED - -/datum/dna/gene/disability/blindness/New() - block=GLOB.BLINDBLOCK - -/datum/dna/gene/disability/deaf - name="Deafness" - activation_message="It's kinda quiet." - sdisability=DEAFENED - -/datum/dna/gene/disability/deaf/New() - block=GLOB.DEAFBLOCK - -/datum/dna/gene/disability/deaf/activate(var/mob/M, var/connected, var/flags) - ..(M,connected,flags) - M.ear_deaf = 1 - -/datum/dna/gene/disability/nearsighted - name="Nearsightedness" - activation_message="Your eyes feel weird..." - disability=NEARSIGHTED - -/datum/dna/gene/disability/nearsighted/New() - block=GLOB.GLASSESBLOCK diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm deleted file mode 100644 index 6aea7975f58d..000000000000 --- a/code/game/dna/genes/gene.dm +++ /dev/null @@ -1,122 +0,0 @@ -/** -* Gene Datum -* -* domutcheck was getting pretty hairy. This is the solution. -* -* All genes are stored in a global variable to cut down on memory -* usage. -* -* @author N3X15 -*/ - -/datum/dna/gene - // Display name - var/name="BASE GENE" - - // Probably won't get used but why the fuck not - var/desc="Oh god who knows what this does." - - // Set in initialize()! - // What gene activates this? - var/block=0 - - // Any of a number of GENE_ flags. - var/flags=0 - -/** -* Is the gene active in this mob's DNA? -*/ -/datum/dna/gene/proc/is_active(var/mob/M) - return M.active_genes && (type in M.active_genes) - -// Return 1 if we can activate. -// HANDLE MUTCHK_FORCED HERE! -/datum/dna/gene/proc/can_activate(var/mob/M, var/flags) - return 0 - -// Called when the gene activates. Do your magic here. -/datum/dna/gene/proc/activate(var/mob/M, var/connected, var/flags) - return - -/** -* Called when the gene deactivates. Undo your magic here. -* Only called when the block is deactivated. -*/ -/datum/dna/gene/proc/deactivate(var/mob/M, var/connected, var/flags) - return - -// This section inspired by goone's bioEffects. - -/** -* Called in each life() tick. -*/ -/datum/dna/gene/proc/OnMobLife(var/mob/M) - return - -/** -* Called when the mob dies -*/ -/datum/dna/gene/proc/OnMobDeath(var/mob/M) - return - -/** -* Called when the mob says shit -*/ -/datum/dna/gene/proc/OnSay(var/mob/M, var/message) - return message - -/** -* Called after the mob runs update_icons. -* -* @params M The subject. -* @params g Gender (m or f) -* @params fat Fat? (0 or 1) -*/ -/datum/dna/gene/proc/OnDrawUnderlays(var/mob/M, var/g, var/fat) - return 0 - - -///////////////////// -// BASIC GENES -// -// These just chuck in a mutation and display a message. -// -// Gene is activated: -// 1. If mutation already exists in mob -// 2. If the probability roll succeeds -// 3. Activation is forced (done in domutcheck) -///////////////////// - - -/datum/dna/gene/basic - name="BASIC GENE" - - // Mutation to give - var/mutation=0 - - // Activation probability - var/activation_prob=45 - - // Possible activation messages - var/list/activation_messages=list() - - // Possible deactivation messages - var/list/deactivation_messages=list() - -/datum/dna/gene/basic/can_activate(var/mob/M,var/flags) - if(flags & MUTCHK_FORCED) - return 1 - // Probability check - return probinj(activation_prob,(flags&MUTCHK_FORCED)) - -/datum/dna/gene/basic/activate(var/mob/M) - M.mutations.Add(mutation) - if(activation_messages.len) - var/msg = pick(activation_messages) - to_chat(M, "[msg]") - -/datum/dna/gene/basic/deactivate(var/mob/M) - M.mutations.Remove(mutation) - if(deactivation_messages.len) - var/msg = pick(deactivation_messages) - to_chat(M, "[msg]") diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm deleted file mode 100644 index 74f648722fe3..000000000000 --- a/code/game/dna/genes/powers.dm +++ /dev/null @@ -1,172 +0,0 @@ -/////////////////////////////////// -// POWERS -/////////////////////////////////// - -/datum/dna/gene/basic/nobreath - name="No Breathing" - activation_messages=list("You feel no need to breathe.") - mutation=mNobreath - -/datum/dna/gene/basic/nobreath/New() - ..() - block=GLOB.NOBREATHBLOCK - -/datum/dna/gene/basic/remoteview - name="Remote Viewing" - activation_messages=list("Your mind expands.") - mutation=mRemote - -/datum/dna/gene/basic/remoteview/New() - ..() - block=GLOB.REMOTEVIEWBLOCK - -/datum/dna/gene/basic/remoteview/activate(var/mob/M, var/connected, var/flags) - ..(M,connected,flags) - M.verbs += /mob/living/carbon/human/proc/remoteobserve - -/datum/dna/gene/basic/regenerate - name="Regenerate" - activation_messages=list("You feel better.") - mutation=mRegen - -/datum/dna/gene/basic/regenerate/New() - ..() - block=GLOB.REGENERATEBLOCK - -/datum/dna/gene/basic/regenerate - name="Super Speed" - activation_messages=list("Your leg muscles pulsate.") - mutation=mRun - -/datum/dna/gene/basic/nobreath/New() - ..() - block=GLOB.INCREASERUNBLOCK - -/datum/dna/gene/basic/remotetalk - name="Telepathy" - activation_messages=list("You expand your mind outwards.") - mutation=mRemotetalk - -/datum/dna/gene/basic/remotetalk/New() - ..() - block=GLOB.REMOTETALKBLOCK - -/datum/dna/gene/basic/remotetalk/activate(var/mob/M, var/connected, var/flags) - ..(M,connected,flags) - M.verbs += /mob/living/carbon/human/proc/remotesay - -/datum/dna/gene/basic/morph - name="Morph" - activation_messages=list("Your skin feels strange.") - mutation=mMorph - -/datum/dna/gene/basic/morph/New() - ..() - block=GLOB.MORPHBLOCK - -/datum/dna/gene/basic/morph/activate(var/mob/M) - ..(M) - M.verbs += /mob/living/carbon/human/proc/morph - -/datum/dna/gene/basic/cold_resist - name="Cold Resistance" - activation_messages=list("Your body is filled with warmth.") - mutation=MUTATION_COLD_RESISTANCE - -/datum/dna/gene/basic/cold_resist/New() - ..() - block=GLOB.FIREBLOCK - -/datum/dna/gene/basic/cold_resist/can_activate(var/mob/M,var/flags) - if(flags & MUTCHK_FORCED) - return 1 - // return !(/datum/dna/gene/basic/heat_resist in M.active_genes) - // Probability check - var/_prob=30 - //if(mHeatres in M.mutations) - // _prob=5 - if(probinj(_prob,(flags&MUTCHK_FORCED))) - return 1 - -/datum/dna/gene/basic/cold_resist/OnDrawUnderlays(var/mob/M,var/g,var/fat) - return "fire[fat]_s" - -/datum/dna/gene/basic/noprints - name="No Prints" - activation_messages=list("Your fingers feel numb.") - mutation=mFingerprints - -/datum/dna/gene/basic/noprints/New() - ..() - block=GLOB.NOPRINTSBLOCK - -/datum/dna/gene/basic/noshock - name="Shock Immunity" - activation_messages=list("Your skin feels strange.") - mutation=mShock - -/datum/dna/gene/basic/noshock/New() - ..() - block=GLOB.SHOCKIMMUNITYBLOCK - -/datum/dna/gene/basic/midget - name="Midget" - activation_messages=list("Your skin feels rubbery.") - mutation=mSmallsize - -/datum/dna/gene/basic/midget/New() - ..() - block=GLOB.SMALLSIZEBLOCK - -/datum/dna/gene/basic/midget/can_activate(var/mob/M,var/flags) - // Can't be big and small. - if(MUTATION_HULK in M.mutations) - return 0 - return ..(M,flags) - -/datum/dna/gene/basic/midget/activate(var/mob/M, var/connected, var/flags) - ..(M,connected,flags) - M.pass_flags |= 1 - -/datum/dna/gene/basic/midget/deactivate(var/mob/M, var/connected, var/flags) - ..(M,connected,flags) - M.pass_flags &= ~PASS_FLAG_TABLE - -/datum/dna/gene/basic/hulk - name="Hulk" - activation_messages=list("Your muscles hurt.") - mutation=MUTATION_HULK - -/datum/dna/gene/basic/hulk/New() - ..() - block=GLOB.HULKBLOCK - -/datum/dna/gene/basic/hulk/can_activate(var/mob/M,var/flags) - // Can't be big and small. - if(mSmallsize in M.mutations) - return 0 - return ..(M,flags) - -/datum/dna/gene/basic/hulk/OnDrawUnderlays(var/mob/M,var/g,var/fat) - if(fat) - return "hulk_[fat]_s" - else - return "hulk_[g]_s" - -/datum/dna/gene/basic/hulk/OnMobLife(var/mob/living/carbon/human/M) - if(!istype(M)) return - if(M.health <= 25) - M.mutations.Remove(MUTATION_HULK) - M.update_mutations() //update our mutation overlays - to_chat(M, "You suddenly feel very weak.") - M.Weaken(3) - M.emote("collapse") - -/datum/dna/gene/basic/xray - name="X-Ray Vision" - activation_messages=list("The walls suddenly disappear.") - mutation=MUTATION_XRAY - -/datum/dna/gene/basic/xray/New() - ..() - block=GLOB.XRAYBLOCK diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm index f5239b2716a5..860ae35eee98 100644 --- a/code/game/gamemodes/calamity/calamity.dm +++ b/code/game/gamemodes/calamity/calamity.dm @@ -1,23 +1,30 @@ #define ANTAG_TYPE_RATIO 8 -/datum/game_mode/calamity +/decl/game_mode/calamity name = "Calamity" round_description = "This must be a Thursday. You never could get the hang of Thursdays..." extended_round_description = "All hell is about to break loose. Literally every antagonist type may spawn in this round. Hold on tight." - config_tag = "calamity" + uid = "calamity" required_players = 1 votable = 0 event_delay_mod_moderate = 0.5 event_delay_mod_major = 0.75 + available_by_default = FALSE -/datum/game_mode/calamity/create_antagonists() - var/list/antag_candidates = all_random_antag_types() +/decl/game_mode/calamity/create_antagonists() + + var/list/antag_candidates = list() + var/list/all_antagonist_datums = decls_repository.get_decls_of_subtype(/decl/special_role) + for(var/antag_type in all_antagonist_datums) + var/decl/special_role/antag = all_antagonist_datums[antag_type] + if(!(antag.flags & ANTAG_RANDOM_EXCEPTED)) + antag_candidates += antag var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1 - while(antag_candidates.len && antag_tags.len < grab_antags) - var/antag_id = pick(antag_candidates) - antag_candidates -= antag_id - antag_tags |= antag_id + while(length(antag_candidates) && length(associated_antags) < grab_antags) + var/antag_type = pick(antag_candidates) + antag_candidates -= antag_type + associated_antags |= antag_type ..() diff --git a/code/game/gamemodes/changeling/absorbed_dna.dm b/code/game/gamemodes/changeling/absorbed_dna.dm deleted file mode 100644 index 2527f906975a..000000000000 --- a/code/game/gamemodes/changeling/absorbed_dna.dm +++ /dev/null @@ -1,12 +0,0 @@ -/datum/absorbed_dna - var/name - var/datum/dna/dna - var/speciesName - var/list/languages - -/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages) - ..() - name = newName - dna = newDNA - speciesName = newSpecies - languages = newLanguages diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm deleted file mode 100644 index fc13e085f359..000000000000 --- a/code/game/gamemodes/changeling/changeling.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/game_mode/changeling - name = "Changeling" - round_description = "There are alien changelings onboard. Do not let the changelings succeed!" - extended_round_description = "One or more of the crew have secretly been replaced by an alien shapeshifter called a changeling. It could be anyone!" - config_tag = "changeling" - required_players = 2 - required_enemies = 1 - end_on_antag_death = FALSE - antag_scaling_coeff = 10 - antag_tags = list(MODE_CHANGELING) diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm deleted file mode 100644 index f243a06534fb..000000000000 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ /dev/null @@ -1,823 +0,0 @@ -var/global/list/possible_changeling_IDs = 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") - -/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) - var/list/datum/absorbed_dna/absorbed_dna = list() - var/list/absorbed_languages = list() - var/absorbedcount = 0 - var/chem_charges = 20 - var/chem_recharge_rate = 0.5 - var/chem_storage = 50 - var/sting_range = 1 - var/changelingID = "Changeling" - var/geneticdamage = 0 - var/isabsorbing = 0 - var/geneticpoints = 25 - var/purchasedpowers = list() - var/mimicing = "" - -/datum/changeling/Destroy() - purchasedpowers = null - absorbed_languages.Cut() - absorbed_dna.Cut() - . = ..() - -/datum/changeling/New() - ..() - if(possible_changeling_IDs.len) - changelingID = pick(possible_changeling_IDs) - possible_changeling_IDs -= changelingID - changelingID = "[changelingID]" - else - changelingID = "[rand(1,999)]" - -/datum/changeling/proc/regenerate() - chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage) - geneticdamage = max(0, geneticdamage-1) - -/datum/changeling/proc/GetDNA(var/dna_owner) - for(var/datum/absorbed_dna/DNA in absorbed_dna) - if(dna_owner == DNA.name) - return DNA - -/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA) - var/datum/changeling/changeling = null - if(src.mind && src.mind.changeling) - changeling = src.mind.changeling - if(!changeling) - return - - for(var/language in newDNA.languages) - changeling.absorbed_languages |= language - - changeling_update_languages(changeling.absorbed_languages) - - if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite - changeling.absorbed_dna += newDNA - -//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human -/mob/proc/make_changeling() - - if(!mind) return - if(!mind.changeling) mind.changeling = new /datum/changeling(gender) - - verbs += /datum/changeling/proc/EvolutionMenu - add_language(/decl/language/ling) - - var/lesser_form = !ishuman(src) - - if(!powerinstances.len) - for(var/P in powers) - powerinstances += new P() - - // Code to auto-purchase free powers. - for(var/datum/power/changeling/P in powerinstances) - if(!P.genomecost) // Is it free? - if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already? - mind.changeling.purchasePower(mind, P.name, 0)// Purchase it. Don't remake our verbs, we're doing it after this. - - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) - if(P.isVerb) - if(lesser_form && !P.allowduringlesserform) continue - if(!(P in src.verbs)) - src.verbs += P.verbpath - - for(var/language in languages) - mind.changeling.absorbed_languages |= language - - var/mob/living/carbon/human/H = src - if(istype(H)) - var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages) - absorbDNA(newDNA) - - return 1 - -//removes our changeling verbs -/mob/proc/remove_changeling_powers() - if(!mind || !mind.changeling) return - for(var/datum/power/changeling/P in mind.changeling.purchasedpowers) - if(P.isVerb) - verbs -= P.verbpath - - -//Helper proc. Does all the checks and stuff for us to avoid copypasta -/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0) - - if(!src.mind) return - if(!iscarbon(src)) return - - var/datum/changeling/changeling = src.mind.changeling - if(!changeling) - to_world_log("[src] has the changeling_transform() verb but is not a changeling.") - return - - if(src.stat > max_stat) - to_chat(src, "We are incapacitated.") - return - - if(changeling.absorbed_dna.len < required_dna) - to_chat(src, "We require at least [required_dna] samples of compatible DNA.") - return - - if(changeling.chem_charges < required_chems) - to_chat(src, "We require at least [required_chems] units of chemicals to do that!") - return - - if(changeling.geneticdamage > max_genetic_damage) - to_chat(src, "Our genomes are still reassembling. We need time to recover first.") - return - - return changeling - - -//Used to dump the languages from the changeling datum into the actual mob. -/mob/proc/changeling_update_languages(var/updated_languages) - - languages = list() - for(var/language in updated_languages) - languages += language - - //This isn't strictly necessary but just to be safe... - add_language(/decl/language/ling) - - return - -//Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. -//Doesn't cost anything as it's the most basic ability. -/mob/proc/changeling_absorb_dna() - set category = "Changeling" - set name = "Absorb DNA" - - var/datum/changeling/changeling = changeling_power(0,0,100) - if(!changeling) return - - var/obj/item/grab/G = src.get_active_hand() - if(!istype(G)) - to_chat(src, "We must be grabbing a creature in our active hand to absorb them.") - return - - var/mob/living/carbon/human/T = G.get_affecting_mob() - if(!istype(T)) - to_chat(src, "[T] is not compatible with our biology.") - return - - if(T.species.species_flags & SPECIES_FLAG_NO_SCAN) - to_chat(src, "We cannot extract DNA from this creature!") - return - - if(MUTATION_HUSK in T.mutations) - to_chat(src, "This creature's DNA is ruined beyond useability!") - return - - if(!G.can_absorb()) - to_chat(src, "We must have a tighter grip to absorb this creature.") - return - - if(changeling.isabsorbing) - to_chat(src, "We are already absorbing!") - return - - var/obj/item/organ/external/affecting = T.get_organ(src.zone_sel.selecting) - if(!affecting) - to_chat(src, "They are missing that body part!") - - changeling.isabsorbing = 1 - for(var/stage = 1, stage<=3, stage++) - switch(stage) - if(1) - to_chat(src, "This creature is compatible. We must hold still...") - if(2) - to_chat(src, "We extend a proboscis.") - src.visible_message("[src] extends a proboscis!") - if(3) - to_chat(src, "We stab [T] with the proboscis.") - src.visible_message("[src] stabs [T] with the proboscis!") - to_chat(T, "You feel a sharp stabbing pain!") - affecting.take_external_damage(39, 0, DAM_SHARP, "large organic needle") - - SSstatistics.add_field_details("changeling_powers","A[stage]") - if(!do_mob(src, T, 150)) - to_chat(src, "Our absorption of [T] has been interrupted!") - changeling.isabsorbing = 0 - return - - to_chat(src, "We have absorbed [T]!") - src.visible_message("[src] sucks the fluids from [T]!") - to_chat(T, "You have been absorbed by the changeling!") - changeling.chem_charges += 10 - changeling.geneticpoints += 2 - - //Steal all of their languages! - for(var/language in T.languages) - if(!(language in changeling.absorbed_languages)) - changeling.absorbed_languages += language - - changeling_update_languages(changeling.absorbed_languages) - - var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) - absorbDNA(newDNA) - - if(mind && T.mind) - T.mind.CopyMemories(mind) - - if(T.mind && T.mind.changeling) - if(T.mind.changeling.absorbed_dna) - for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot - if(changeling.GetDNA(dna_data.name)) - continue - absorbDNA(dna_data) - changeling.absorbedcount++ - T.mind.changeling.absorbed_dna.len = 1 - - if(T.mind.changeling.purchasedpowers) - for(var/datum/power/changeling/Tp in T.mind.changeling.purchasedpowers) - if(Tp in changeling.purchasedpowers) - continue - else - changeling.purchasedpowers += Tp - - if(!Tp.isVerb) - call(Tp.verbpath)() - else - src.make_changeling() - - changeling.chem_charges += T.mind.changeling.chem_charges - changeling.geneticpoints += T.mind.changeling.geneticpoints - T.mind.changeling.chem_charges = 0 - T.mind.changeling.geneticpoints = 0 - T.mind.changeling.absorbedcount = 0 - - changeling.absorbedcount++ - changeling.isabsorbing = 0 - - T.death(0) - T.Drain() - return 1 - - -//Change our DNA to that of somebody we've absorbed. -/mob/proc/changeling_transform() - set category = "Changeling" - set name = "Transform (5)" - - var/datum/changeling/changeling = changeling_power(5,1,0) - if(!changeling) return - - var/list/names = list() - for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) - names += "[DNA.name]" - - var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names - if(!S) return - - var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - changeling.chem_charges -= 5 - changeling.geneticdamage = 30 - - var/S_name = chosen_dna.speciesName - var/datum/species/S_dat = get_species_by_key(S_name) - var/changeTime = 2 SECONDS - if(mob_size != S_dat.mob_size) - src.visible_message("[src]'s body begins to twist, their mass changing rapidly!") - changeTime = 8 SECONDS - else - src.visible_message("[src]'s body begins to twist, changing rapidly!") - - if(!do_after(src, changeTime)) - to_chat(src, "You fail to change shape.") - return - handle_changeling_transform(chosen_dna) - - src.verbs -= /mob/proc/changeling_transform - spawn(10) - src.verbs += /mob/proc/changeling_transform - - changeling_update_languages(changeling.absorbed_languages) - - SSstatistics.add_field_details("changeling_powers","TR") - return 1 - -/mob/proc/handle_changeling_transform(var/datum/absorbed_dna/chosen_dna) - src.visible_message("[src] transforms!") - - src.dna = chosen_dna.dna - src.real_name = chosen_dna.name - src.flavor_text = "" - - if(ishuman(src)) - var/mob/living/carbon/human/H = src - var/newSpecies = chosen_dna.speciesName - H.set_species(newSpecies,1) - H.b_type = chosen_dna.dna.b_type - H.sync_organ_dna() - - domutcheck(src, null) - src.UpdateAppearance() - - -//Transform into a monkey. -/mob/proc/changeling_lesser_form() - set category = "Changeling" - set name = "Lesser Form (1)" - - var/datum/changeling/changeling = changeling_power(1,0,0) - if(!changeling) return - - handle_pre_transformation() - - var/mob/living/carbon/human/H = src - - if(!istype(H) || !H.species.primitive_form) - to_chat(src, "We cannot perform this ability in this form!") - return - - changeling.chem_charges-- - H.visible_message("[H] transforms!") - changeling.geneticdamage = 30 - to_chat(H, "Our genes cry out!") - H = H.monkeyize() - SSstatistics.add_field_details("changeling_powers","LF") - return 1 - -//Transform into a human -/mob/proc/changeling_lesser_transform() - set category = "Changeling" - set name = "Transform (1)" - - var/datum/changeling/changeling = changeling_power(1,1,0) - if(!changeling) return - - if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) - return - - var/list/names = list() - for(var/datum/dna/DNA in changeling.absorbed_dna) - names += "[DNA.real_name]" - - var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names - if(!S) return - - var/datum/dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - var/mob/living/carbon/human/C = src - - changeling.chem_charges-- - C.remove_changeling_powers() - C.visible_message("[C] transforms!") - C.dna = chosen_dna.Clone() - - var/list/implants = list() - for (var/obj/item/implant/I in C) //Still preserving implants - implants += I - - ADD_TRANSFORMATION_MOVEMENT_HANDLER(C) - C.icon = null - C.overlays.Cut() - C.set_invisibility(101) - var/atom/movable/overlay/animation = new /atom/movable/overlay(src) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - flick("monkey2h", animation) - sleep(48) - qdel(animation) - - for(var/obj/item/W in src) - C.drop_from_inventory(W) - - var/mob/living/carbon/human/O = new /mob/living/carbon/human( src ) - if (C.dna.GetUIState(DNA_UI_GENDER)) - O.gender = FEMALE - else - O.gender = MALE - O.dna = C.dna.Clone() - C.dna = null - O.real_name = chosen_dna.real_name - - for(var/obj/T in C) - qdel(T) - - O.dropInto(C.loc) - - O.UpdateAppearance() - domutcheck(O, null) - O.setToxLoss(C.getToxLoss()) - O.adjustBruteLoss(C.getBruteLoss()) - O.setOxyLoss(C.getOxyLoss()) - O.adjustFireLoss(C.getFireLoss()) - O.set_stat(C.stat) - for (var/obj/item/implant/I in implants) - I.forceMove(O) - I.implanted = O - - C.mind.transfer_to(O) - O.make_changeling() - O.changeling_update_languages(changeling.absorbed_languages) - - SSstatistics.add_field_details("changeling_powers","LFT") - qdel(C) - return 1 - - -//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. -/mob/proc/changeling_fakedeath() - set category = "Changeling" - set name = "Regenerative Stasis (20)" - - var/datum/changeling/changeling = changeling_power(20,1,100,DEAD) - if(!changeling) return - - var/mob/living/carbon/C = src - if(!C.stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death - return - to_chat(C, "We will attempt to regenerate our form.") - C.status_flags |= FAKEDEATH //play dead - C.UpdateLyingBuckledAndVerbStatus() - C.remove_changeling_powers() - - C.emote("gasp") - - spawn(rand(800,2000)) - if(changeling_power(20,1,100,DEAD)) - // charge the changeling chemical cost for stasis - changeling.chem_charges -= 20 - - to_chat(C, "We are ready to rise. Use the Revive verb when you are ready.") - C.verbs += /mob/proc/changeling_revive - - SSstatistics.add_field_details("changeling_powers","FD") - return 1 - -/mob/proc/changeling_revive() - set category = "Changeling" - set name = "Revive" - - var/mob/living/carbon/C = src - // restore us to health - C.revive() - // remove our fake death flag - C.status_flags &= ~(FAKEDEATH) - // let us move again - C.UpdateLyingBuckledAndVerbStatus() - // re-add out changeling powers - C.make_changeling() - // sending display messages - to_chat(C, "We have regenerated.") - C.verbs -= /mob/proc/changeling_revive - - -//Boosts the range of your next sting attack by 1 -/mob/proc/changeling_boost_range() - set category = "Changeling" - set name = "Ranged Sting (10)" - set desc="Your next sting ability can be used against targets 2 squares away." - - var/datum/changeling/changeling = changeling_power(10,0,100) - if(!changeling) return 0 - changeling.chem_charges -= 10 - to_chat(src, "Your throat adjusts to launch the sting.") - changeling.sting_range = 2 - src.verbs -= /mob/proc/changeling_boost_range - spawn(5) src.verbs += /mob/proc/changeling_boost_range - SSstatistics.add_field_details("changeling_powers","RS") - return 1 - - -//Recover from stuns. -/mob/proc/changeling_unstun() - set category = "Changeling" - set name = "Epinephrine Sacs (45)" - set desc = "Removes all stuns" - - var/datum/changeling/changeling = changeling_power(45,0,100,UNCONSCIOUS) - if(!changeling) return 0 - changeling.chem_charges -= 45 - - var/mob/living/carbon/human/C = src - C.set_stat(CONSCIOUS) - C.SetParalysis(0) - C.SetStunned(0) - C.SetWeakened(0) - C.lying = 0 - C.UpdateLyingBuckledAndVerbStatus() - - src.verbs -= /mob/proc/changeling_unstun - spawn(5) src.verbs += /mob/proc/changeling_unstun - SSstatistics.add_field_details("changeling_powers","UNS") - return 1 - - -//Speeds up chemical regeneration -/mob/proc/changeling_fastchemical() - src.mind.changeling.chem_recharge_rate *= 2 - return 1 - -//Increases macimum chemical storage -/mob/proc/changeling_engorgedglands() - src.mind.changeling.chem_storage += 25 - return 1 - - -//Prevents AIs tracking you but makes you easily detectable to the human-eye. -/mob/proc/changeling_digitalcamo() - set category = "Changeling" - set name = "Toggle Digital Camoflague" - set desc = "The AI can no longer track us, but we will look different if examined. Has a constant cost while active." - - var/datum/changeling/changeling = changeling_power() - if(!changeling) return 0 - - var/mob/living/carbon/human/C = src - if(C.digitalcamo) to_chat(C, "We return to normal.") - else to_chat(C, "We distort our form to prevent AI-tracking.") - C.digitalcamo = !C.digitalcamo - - spawn(0) - while(C && C.digitalcamo && C.mind && C.mind.changeling) - C.mind.changeling.chem_charges = max(C.mind.changeling.chem_charges - 1, 0) - sleep(40) - - src.verbs -= /mob/proc/changeling_digitalcamo - spawn(5) src.verbs += /mob/proc/changeling_digitalcamo - SSstatistics.add_field_details("changeling_powers","CAM") - return 1 - - -//Starts healing you every second for 10 seconds. Can be used whilst unconscious. -/mob/proc/changeling_rapidregen() - set category = "Changeling" - set name = "Rapid Regeneration (30)" - set desc = "Begins rapidly regenerating. Does not effect stuns or chemicals." - - var/datum/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS) - if(!changeling) return 0 - src.mind.changeling.chem_charges -= 30 - - var/mob/living/carbon/human/C = src - spawn(0) - for(var/i = 0, i<10,i++) - if(C) - C.adjustBruteLoss(-10) - C.adjustToxLoss(-10) - C.adjustOxyLoss(-10) - C.adjustFireLoss(-10) - sleep(10) - - src.verbs -= /mob/proc/changeling_rapidregen - spawn(5) src.verbs += /mob/proc/changeling_rapidregen - SSstatistics.add_field_details("changeling_powers","RR") - return 1 - -// HIVE MIND UPLOAD/DOWNLOAD DNA - -var/list/datum/absorbed_dna/hivemind_bank = list() - -/mob/proc/changeling_hiveupload() - set category = "Changeling" - set name = "Hive Channel (10)" - set desc = "Allows you to channel DNA in the airwaves to allow other changelings to absorb it." - - var/datum/changeling/changeling = changeling_power(10,1) - if(!changeling) return - - var/list/names = list() - for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna) - var/valid = 1 - for(var/datum/absorbed_dna/DNB in hivemind_bank) - if(DNA.name == DNB.name) - valid = 0 - break - if(valid) - names += DNA.name - - if(names.len <= 0) - to_chat(src, "The airwaves already have all of our DNA.") - return - - var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names - if(!S) return - - var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S) - if(!chosen_dna) - return - - var/datum/species/spec = get_species_by_key(chosen_dna.speciesName) - - if(spec && spec.species_flags & SPECIES_FLAG_NEED_DIRECT_ABSORB) - to_chat(src, "That species must be absorbed directly.") - return - - changeling.chem_charges -= 10 - hivemind_bank += chosen_dna - to_chat(src, "We channel the DNA of [S] to the air.") - SSstatistics.add_field_details("changeling_powers","HU") - return 1 - -/mob/proc/changeling_hivedownload() - set category = "Changeling" - set name = "Hive Absorb (20)" - set desc = "Allows you to absorb DNA that is being channeled in the airwaves." - - var/datum/changeling/changeling = changeling_power(20,1) - if(!changeling) return - - var/list/names = list() - for(var/datum/absorbed_dna/DNA in hivemind_bank) - if(!(changeling.GetDNA(DNA.name))) - names[DNA.name] = DNA - - if(names.len <= 0) - to_chat(src, "There's no new DNA to absorb from the air.") - return - - var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names - if(!S) return - var/datum/dna/chosen_dna = names[S] - if(!chosen_dna) - return - - changeling.chem_charges -= 20 - absorbDNA(chosen_dna) - to_chat(src, "We absorb the DNA of [S] from the air.") - SSstatistics.add_field_details("changeling_powers","HD") - return 1 - -// Fake Voice - -/mob/proc/changeling_mimicvoice() - set category = "Changeling" - set name = "Mimic Voice" - set desc = "Shape our vocal glands to form a voice of someone we choose. We cannot regenerate chemicals when mimicing." - - - var/datum/changeling/changeling = changeling_power() - if(!changeling) return - - if(changeling.mimicing) - changeling.mimicing = "" - to_chat(src, "We return our vocal glands to their original location.") - return - - var/mimic_voice = sanitize(input(usr, "Enter a name to mimic.", "Mimic Voice", null), MAX_NAME_LEN) - if(!mimic_voice) - return - - changeling.mimicing = mimic_voice - - to_chat(src, "We shape our glands to take the voice of [mimic_voice], this will stop us from regenerating chemicals while active.") - to_chat(src, "Use this power again to return to our original voice and reproduce chemicals again.") - SSstatistics.add_field_details("changeling_powers","MV") - - spawn(0) - while(src && src.mind && src.mind.changeling && src.mind.changeling.mimicing) - src.mind.changeling.chem_charges = max(src.mind.changeling.chem_charges - 1, 0) - sleep(40) - if(src && src.mind && src.mind.changeling) - src.mind.changeling.mimicing = "" - ////////// - //STINGS// //They get a pretty header because there's just so fucking many of them ;_; - ////////// - -/mob/proc/sting_can_reach(mob/M, sting_range = 1) - if(M.loc == src.loc) - return 1 //target and source are in the same thing - if(!isturf(src.loc) || !isturf(M.loc)) - to_chat(src, "We cannot reach \the [M] with a sting!") - return 0 //One is inside, the other is outside something. - // Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising - if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail - to_chat(src, "We cannot find a path to sting \the [M] by!") - return 0 - return 1 - -//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities) -/mob/proc/changeling_sting(var/required_chems=0, var/verb_path, var/loud) - var/datum/changeling/changeling = changeling_power(required_chems) - if(!changeling) return - - var/list/victims = list() - for(var/mob/living/carbon/human/C in oview(changeling.sting_range)) - victims += C - var/mob/living/carbon/human/T = input(src, "Who will we sting?") as null|anything in victims - - if(!T) return - if(!(T in view(changeling.sting_range))) return - if(!sting_can_reach(T, changeling.sting_range)) return - if(!changeling_power(required_chems)) return - var/obj/item/organ/external/target_limb = T.get_organ(src.zone_sel.selecting) - if (!target_limb) - to_chat(src, "[T] is missing that limb.") - return - changeling.chem_charges -= required_chems - changeling.sting_range = 1 - src.verbs -= verb_path - spawn(10) src.verbs += verb_path - if(!loud) - to_chat(src, "We stealthily sting [T].") - else - visible_message("[src] fires an organic shard into [T]!") - - for(var/obj/item/clothing/clothes in list(T.head, T.wear_mask, T.wear_suit, T.w_uniform, T.gloves, T.shoes)) - if(istype(clothes) && (clothes.body_parts_covered & target_limb.body_part) && (clothes.item_flags & ITEM_FLAG_THICKMATERIAL)) - to_chat(src, "[T]'s armor has protected them.") - return //thick clothes will protect from the sting - - if(T.isSynthetic() || BP_IS_PROSTHETIC(target_limb)) return - if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting - to_chat(T, "You feel a tiny prick.") - return - - -/mob/proc/changeling_lsdsting() - set category = "Changeling" - set name = "Hallucination Sting (15)" - set desc = "Causes terror in the target." - - var/mob/living/carbon/human/T = changeling_sting(15,/mob/proc/changeling_lsdsting) - if(!T) return 0 - spawn(rand(300,600)) - if(T) T.hallucination(400, 80) - SSstatistics.add_field_details("changeling_powers","HS") - return 1 - -/mob/proc/changeling_silence_sting() - set category = "Changeling" - set name = "Silence sting (10)" - set desc="Sting target" - - var/mob/living/carbon/human/T = changeling_sting(10,/mob/proc/changeling_silence_sting) - if(!T) return 0 - T.silent += 30 - SSstatistics.add_field_details("changeling_powers","SS") - return 1 - -/mob/proc/changeling_blind_sting() - set category = "Changeling" - set name = "Blind sting (20)" - set desc="Sting target" - - var/mob/living/carbon/human/T = changeling_sting(20,/mob/proc/changeling_blind_sting) - if(!T) return 0 - to_chat(T, "Your eyes burn horrificly!") - T.disabilities |= NEARSIGHTED - spawn(300) T.disabilities &= ~NEARSIGHTED - T.eye_blind = 10 - T.eye_blurry = 20 - SSstatistics.add_field_details("changeling_powers","BS") - return 1 - -/mob/proc/changeling_deaf_sting() - set category = "Changeling" - set name = "Deaf sting (5)" - set desc="Sting target:" - - var/mob/living/carbon/human/T = changeling_sting(5,/mob/proc/changeling_deaf_sting) - if(!T) return 0 - to_chat(T, "Your ears pop and begin ringing loudly!") - T.ear_deaf += 15 - SSstatistics.add_field_details("changeling_powers","DS") - return 1 - -/mob/proc/changeling_DEATHsting() - set category = "Changeling" - set name = "Death Sting (40)" - set desc = "Causes spasms onto death." - var/loud = 1 - - var/mob/living/carbon/human/T = changeling_sting(40,/mob/proc/changeling_DEATHsting,loud) - if(!T) return 0 - to_chat(T, "You feel a small prick and your chest becomes tight.") - T.make_jittery(400) - if(T.reagents) T.reagents.add_reagent(/decl/material/gas/carbon_monoxide, 40) - SSstatistics.add_field_details("changeling_powers","DTHS") - return 1 - -/mob/proc/changeling_extract_dna_sting() - set category = "Changeling" - set name = "Extract DNA Sting (40)" - set desc="Stealthily sting a target to extract their DNA." - - var/datum/changeling/changeling = null - if(src.mind && src.mind.changeling) - changeling = src.mind.changeling - if(!changeling) - return 0 - - var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting) - if(!T) return 0 - if((MUTATION_HUSK in T.mutations) || (T.species.species_flags & SPECIES_FLAG_NO_SCAN)) - to_chat(src, "We cannot extract DNA from this creature!") - return 0 - - if(T.species.species_flags & SPECIES_FLAG_NEED_DIRECT_ABSORB) - to_chat(src, "That species must be absorbed directly.") - return - - var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages) - absorbDNA(newDNA) - - SSstatistics.add_field_details("changeling_powers","ED") - return 1 diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm deleted file mode 100644 index a6c92fd3143a..000000000000 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ /dev/null @@ -1,484 +0,0 @@ -// READ: Don't use the apostrophe in name or desc. Causes script errors. - -var/list/powers = typesof(/datum/power/changeling) - /datum/power/changeling //needed for the badmin verb for now -var/list/datum/power/changeling/powerinstances = list() - -/datum/power //Could be used by other antags too - var/name = "Power" - var/desc = "Placeholder" - var/helptext = "" - var/isVerb = 1 // Is it an active power, or passive? - var/verbpath // Path to a verb that contains the effects. - -/datum/power/changeling - var/allowduringlesserform = 0 - var/genomecost = 500000 // Cost for the changling to evolve this power. - -/datum/power/changeling/absorb_dna - name = "Absorb DNA" - desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger." - genomecost = 0 - verbpath = /mob/proc/changeling_absorb_dna - -/datum/power/changeling/transform - name = "Transform" - desc = "We take on the apperance and voice of one we have absorbed." - genomecost = 0 - verbpath = /mob/proc/changeling_transform - -/datum/power/changeling/fakedeath - name = "Regenerative Stasis" - desc = "We become weakened to a death-like state, where we will rise again from death." - helptext = "Can be used before or after death. Duration varies greatly." - genomecost = 0 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_fakedeath - -// Hivemind - -/datum/power/changeling/hive_upload - name = "Hive Channel" - desc = "We can channel a DNA into the airwaves, allowing our fellow changelings to absorb it and transform into it as if they acquired the DNA themselves." - helptext = "Allows other changelings to absorb the DNA you channel from the airwaves. Will not help them towards their absorb objectives." - genomecost = 0 - verbpath = /mob/proc/changeling_hiveupload - -/datum/power/changeling/hive_download - name = "Hive Absorb" - desc = "We can absorb a single DNA from the airwaves, allowing us to use more disguises with help from our fellow changelings." - helptext = "Allows you to absorb a single DNA and use it. Does not count towards your absorb objective." - genomecost = 0 - verbpath = /mob/proc/changeling_hivedownload - -/datum/power/changeling/lesser_form - name = "Lesser Form" - desc = "We debase ourselves and become lesser. We become a monkey." - genomecost = 4 - verbpath = /mob/proc/changeling_lesser_form - -/datum/power/changeling/deaf_sting - name = "Deaf Sting" - desc = "We silently sting a human, completely deafening them for a short time." - genomecost = 1 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_deaf_sting - -/datum/power/changeling/blind_sting - name = "Blind Sting" - desc = "We silently sting a human, completely blinding them for a short time." - genomecost = 2 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_blind_sting - -/datum/power/changeling/silence_sting - name = "Silence Sting" - desc = "We silently sting a human, completely silencing them for a short time." - helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." - genomecost = 3 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_silence_sting - -/datum/power/changeling/mimicvoice - name = "Mimic Voice" - desc = "We shape our vocal glands to sound like a desired voice." - helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this" - genomecost = 1 - verbpath = /mob/proc/changeling_mimicvoice - -/datum/power/changeling/extractdna - name = "Extract DNA" - desc = "We stealthily sting a target and extract the DNA from them." - helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives." - genomecost = 2 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_extract_dna_sting - -/datum/power/changeling/LSDSting - name = "Hallucination Sting" - desc = "We evolve the ability to sting a target with a powerful hallunicationary chemical." - helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds." - genomecost = 3 - verbpath = /mob/proc/changeling_lsdsting - -/datum/power/changeling/DeathSting - name = "Death Sting" - desc = "We sting a human, filling them with potent chemicals. Their rapid death is all but assured, but our crime will be obvious." - helptext = "It will be clear to any surrounding witnesses if you use this power." - genomecost = 10 - verbpath = /mob/proc/changeling_DEATHsting - - -/datum/power/changeling/boost_range - name = "Boost Range" - desc = "We evolve the ability to shoot our stingers at humans, with some preperation." - genomecost = 2 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_boost_range - -/datum/power/changeling/Epinephrine - name = "Epinephrine sacs" - desc = "We evolve additional sacs of adrenaline throughout our body." - helptext = "Gives the ability to instantly recover from stuns. High chemical cost." - genomecost = 3 - verbpath = /mob/proc/changeling_unstun - -/datum/power/changeling/ChemicalSynth - name = "Rapid Chemical-Synthesis" - desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." - helptext = "Doubles the rate at which we naturally recharge chemicals." - genomecost = 4 - isVerb = 0 - verbpath = /mob/proc/changeling_fastchemical -/* -/datum/power/changeling/AdvChemicalSynth - name = "Advanced Chemical-Synthesis" - desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." - helptext = "Doubles the rate at which we naturally recharge chemicals." - genomecost = 8 - isVerb = 0 - verbpath = /mob/proc/changeling_fastchemical -*/ -/datum/power/changeling/EngorgedGlands - name = "Engorged Chemical Glands" - desc = "Our chemical glands swell, permitting us to store more chemicals inside of them." - helptext = "Allows us to store an extra 25 units of chemicals." - genomecost = 4 - isVerb = 0 - verbpath = /mob/proc/changeling_engorgedglands - -/datum/power/changeling/DigitalCamoflague - name = "Digital Camoflauge" - desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras." - helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this." - genomecost = 1 - allowduringlesserform = 1 - verbpath = /mob/proc/changeling_digitalcamo - -/datum/power/changeling/rapidregeneration - name = "Rapid Regeneration" - desc = "We evolve the ability to rapidly regenerate, negating the need for stasis." - helptext = "Heals a moderate amount of damage every tick." - genomecost = 7 - verbpath = /mob/proc/changeling_rapidregen - - - -// Modularchangling, totally stolen from the new player panel. YAYY -/datum/changeling/proc/EvolutionMenu()//The new one - set category = "Changeling" - set desc = "Level up!" - - if(!usr || !usr.mind || !usr.mind.changeling) return - src = usr.mind.changeling - - if(!powerinstances.len) - for(var/P in powers) - powerinstances += new P() - - var/dat = "Changling Evolution Menu" - - //javascript, the part that does most of the work~ - dat += {" - - - - - - - "} - - //body tag start + onload and onkeypress (onkeyup) javascript event calls - dat += "" - - //title + search bar - dat += {" - - - - - - - - -
    - Changling Evolution Menu
    - Hover over a power to see more information
    - Current evolution points left to evolve with: [geneticpoints]
    - Absorb genomes to acquire more evolution points -

    -

    - Search: -
    - - "} - - //player table header - dat += {" - - "} - - var/i = 1 - for(var/datum/power/changeling/P in powerinstances) - var/ownsthis = 0 - - if(P in purchasedpowers) - ownsthis = 1 - - - var/color = "#e6e6e6" - if(i%2 == 0) - color = "#f2f2f2" - - - dat += {" - - - - - - "} - - i++ - - - //player table ending - dat += {" -
    - - - Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost] - -
    -
    -
    - - - - "} - - show_browser(usr, dat, "window=powers;size=900x480") - - -/datum/changeling/Topic(href, href_list) - ..() - if(!ismob(usr)) - return - - if(href_list["P"]) - var/datum/mind/M = usr.mind - if(!istype(M)) - return - purchasePower(M, href_list["P"]) - call(/datum/changeling/proc/EvolutionMenu)() - - - -/datum/changeling/proc/purchasePower(var/datum/mind/M, var/Pname, var/remake_verbs = 1) - if(!M || !M.changeling) - return - - var/datum/power/changeling/Thepower = Pname - - - for (var/datum/power/changeling/P in powerinstances) -// log_debug("[P] - [Pname] = [P.name == Pname ? "True" : "False"]") - - if(P.name == Pname) - Thepower = P - break - - - if(Thepower == null) - to_chat(M.current, "This is awkward. Changeling power purchase failed, please report this bug to a coder!") - return - - if(Thepower in purchasedpowers) - to_chat(M.current, "We have already evolved this ability!") - return - - - if(geneticpoints < Thepower.genomecost) - to_chat(M.current, "We cannot evolve this... yet. We must acquire more DNA.") - return - - geneticpoints -= Thepower.genomecost - - purchasedpowers += Thepower - - if(!Thepower.isVerb && Thepower.verbpath) - call(M.current, Thepower.verbpath)() - else if(remake_verbs) - M.current.make_changeling() - diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm deleted file mode 100644 index 506c1e08176f..000000000000 --- a/code/game/gamemodes/cult/cult.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/game_mode/cult - name = "Cult" - round_description = "Some crewmembers are attempting to start a cult!" - extended_round_description = "There has been an infiltration by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!" - config_tag = "cult" - required_players = 10 - required_enemies = 3 - end_on_antag_death = FALSE - antag_tags = list(MODE_CULTIST) diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm deleted file mode 100644 index 31e7b07c042d..000000000000 --- a/code/game/gamemodes/cult/cult_items.dm +++ /dev/null @@ -1,143 +0,0 @@ -/obj/item/sword/cultblade - name = "cult blade" - desc = "An arcane weapon wielded by the followers of Nar-Sie." - icon = 'icons/obj/items/weapon/swords/cult.dmi' - applies_material_colour = FALSE - applies_material_name = FALSE - -/obj/item/sword/cultblade/attack(mob/living/M, mob/living/user, var/target_zone) - if(iscultist(user) || (user.mind in GLOB.godcult.current_antagonists)) - return ..() - - var/zone = (user.hand ? BP_L_ARM : BP_R_ARM) - - var/obj/item/organ/external/affecting = null - if(ishuman(user)) - var/mob/living/carbon/human/H = user - affecting = H.get_organ(zone) - - if(affecting) - to_chat(user, "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!") - else - to_chat(user, "An unexplicable force rips through you, tearing the sword from your grasp!") - - //random amount of damage between half of the blade's force and the full force of the blade. - user.apply_damage(rand(force/2, force), BRUTE, zone, (DAM_SHARP|DAM_EDGE), armor_pen = 100) - user.Weaken(5) - - if(user.unEquip(src)) - throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), throw_speed) - - var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg') - playsound(loc, spooky, 50, 1) - - return 1 - -/obj/item/sword/cultblade/pickup(mob/living/user) - if(!iscultist(user)) - to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the cultist's sword. It would be wise to be rid of this blade quickly.") - user.make_dizzy(120) - - -/obj/item/clothing/head/culthood - name = "cult hood" - desc = "A hood worn by the followers of Nar-Sie." - - icon = 'icons/clothing/head/cult.dmi' - flags_inv = HIDEFACE - body_parts_covered = HEAD - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_SMALL - ) - cold_protection = HEAD - min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE - siemens_coefficient = 0.8 //That's a pretty cool opening in the hood. Also: Cloth making physical contact to the skull. - -/obj/item/clothing/head/culthood/magus - name = "magus helm" - desc = "A helm worn by the followers of Nar-Sie." - icon = 'icons/clothing/head/wizard/magus.dmi' - flags_inv = HIDEFACE | BLOCKHAIR - body_parts_covered = HEAD|FACE|EYES - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_RESISTANT - ) - -/obj/item/clothing/head/culthood/alt - icon = 'icons/clothing/head/cult_alt.dmi' -/obj/item/clothing/suit/cultrobes - name = "cult robes" - desc = "A set of durable robes worn by the followers of Nar-Sie." - icon_state = "cultrobes" - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS - allowed = list(/obj/item/book/tome,/obj/item/sword/cultblade) - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_SMALL, - energy = ARMOR_ENERGY_SMALL, - bomb = ARMOR_BOMB_PADDED - ) - flags_inv = HIDEJUMPSUIT - siemens_coefficient = 0.6 - -/obj/item/clothing/suit/cultrobes/alt - icon_state = "cultrobesalt" - -/obj/item/clothing/suit/cultrobes/magusred - name = "magus robes" - desc = "A set of plated robes worn by the followers of Nar-Sie." - icon_state = "magusred" - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS - flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT - armor = list( - melee = ARMOR_MELEE_VERY_HIGH, - bullet = ARMOR_BALLISTIC_RIFLE, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_RESISTANT, - bomb = ARMOR_BOMB_PADDED - ) - -/obj/item/clothing/suit/cultrobes/magusred/Initialize() - . = ..() - slowdown_per_slot[slot_wear_suit] = 1 - -/obj/item/clothing/head/helmet/space/cult - name = "cult helmet" - desc = "A space worthy helmet used by the followers of Nar-Sie." - icon = 'icons/clothing/spacesuit/cult/helmet.dmi' - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_RIFLE, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_MINOR - ) //Real tanky shit. - siemens_coefficient = 0.3 //Bone is not very conducive to electricity. - -/obj/item/clothing/suit/space/cult - name = "cult armour" - desc = "A bulky suit of armour, bristling with spikes. It looks space proof." - icon = 'icons/clothing/spacesuit/cult/suit.dmi' - allowed = list(/obj/item/book/tome,/obj/item/sword/cultblade,/obj/item/tank,/obj/item/suit_cooling_unit) - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_RIFLE, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_MINOR - ) - siemens_coefficient = 0.2 - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS - -/obj/item/clothing/suit/space/cult/Initialize() - . = ..() - slowdown_per_slot[slot_wear_suit] = 1 \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm deleted file mode 100644 index a21038ad70d3..000000000000 --- a/code/game/gamemodes/cult/cult_structures.dm +++ /dev/null @@ -1,167 +0,0 @@ -/obj/structure/cult - density = 1 - anchored = 1 - icon = 'icons/obj/cult.dmi' - -/obj/structure/cult/talisman - name = "Altar" - desc = "A bloodstained altar dedicated to Nar-Sie." - icon_state = "talismanaltar" - - -/obj/structure/cult/forge - name = "Daemon forge" - desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie." - icon_state = "forge" - -/obj/structure/cult/pylon - name = "Pylon" - desc = "A floating crystal that hums with an unearthly energy." - icon = 'icons/obj/structures/pylon.dmi' - icon_state = "pylon" - var/isbroken = 0 - light_max_bright = 0.5 - light_inner_range = 1 - light_outer_range = 13 - light_color = "#3e0000" - var/obj/item/wepon = null - -/obj/structure/cult/pylon/attack_hand(mob/M) - attackpylon(M, 5) - -/obj/structure/cult/pylon/attack_generic(var/mob/user, var/damage) - attackpylon(user, damage) - -/obj/structure/cult/pylon/attackby(obj/item/W, mob/user) - attackpylon(user, W.force) - -/obj/structure/cult/pylon/proc/attackpylon(mob/user, var/damage) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!isbroken) - if(prob(1+ damage * 5)) - user.visible_message( - "[user] smashed the pylon!", - "You hit the pylon, and its crystal breaks apart!", - "You hear a tinkle of crystal shards" - ) - user.do_attack_animation(src) - playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1) - isbroken = 1 - set_density(0) - icon_state = "pylon-broken" - set_light(0) - else - to_chat(user, "You hit the pylon!") - playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) - else - if(prob(damage * 2)) - to_chat(user, "You pulverize what was left of the pylon!") - qdel(src) - else - to_chat(user, "You hit the pylon!") - playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) - - -/obj/structure/cult/pylon/proc/repair(mob/user) - if(isbroken) - to_chat(user, "You repair the pylon.") - isbroken = 0 - set_density(1) - icon_state = "pylon" - set_light(0.5) - -/obj/structure/cult/pylon/get_artifact_scan_data() - return "Tribal pylon - subject resembles statues/emblems built by cargo cult civilisations to honour energy systems from post-warp civilisations." - -/obj/structure/cult/tome - name = "Desk" - desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl." - icon_state = "tomealtar" - -//sprites for this no longer exist -Pete -//(they were stolen from another game anyway) -/* -/obj/structure/cult/pillar - name = "Pillar" - desc = "This should not exist." - icon_state = "pillar" - icon = 'magic_pillar.dmi' -*/ - -/obj/effect/gateway - name = "gateway" - desc = "You're pretty sure that abyss is staring back." - icon = 'icons/obj/cult.dmi' - icon_state = "hole" - density = 1 - unacidable = 1 - anchored = 1.0 - var/spawnable = null - -/obj/effect/gateway/active - light_outer_range=5 - light_color="#ff0000" - spawnable=list( - /mob/living/simple_animal/hostile/scarybat, - /mob/living/simple_animal/hostile/creature, - /mob/living/simple_animal/hostile/faithless - ) - -/obj/effect/gateway/active/cult - light_outer_range=5 - light_color="#ff0000" - spawnable=list( - /mob/living/simple_animal/hostile/scarybat/cult, - /mob/living/simple_animal/hostile/creature/cult, - /mob/living/simple_animal/hostile/faithless/cult - ) - -/obj/effect/gateway/active/Initialize() - . = ..() - addtimer(CALLBACK(src, .proc/create_and_delete), rand(30,60) SECONDS) - - -/obj/effect/gateway/active/proc/create_and_delete() - var/t = pick(spawnable) - new t(src.loc) - qdel(src) - -/obj/effect/gateway/active/Crossed(var/atom/A) - if(!istype(A, /mob/living)) - return - - var/mob/living/M = A - - if(M.stat != DEAD) - if(M.HasMovementHandler(/datum/movement_handler/mob/transformation)) - return - - M.handle_pre_transformation() - - if(iscultist(M)) return - if(!ishuman(M) && !isrobot(M)) return - - M.AddMovementHandler(/datum/movement_handler/mob/transformation) - M.icon = null - M.overlays.len = 0 - M.set_invisibility(101) - - if(istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/Robot = M - if(Robot.mmi) - qdel(Robot.mmi) - else - for(var/obj/item/W in M) - M.drop_from_inventory(W) - if(istype(W, /obj/item/implant)) - qdel(W) - - var/mob/living/new_mob = new /mob/living/simple_animal/corgi(A.loc) - new_mob.a_intent = I_HURT - if(M.mind) - M.mind.transfer_to(new_mob) - else - new_mob.key = M.key - - to_chat(new_mob, "Your form morphs into that of a corgi.")//Because we don't have cluwnes - diff --git a/code/game/gamemodes/cult/cultify/de-cultify.dm b/code/game/gamemodes/cult/cultify/de-cultify.dm deleted file mode 100644 index 1a0a11f8b227..000000000000 --- a/code/game/gamemodes/cult/cultify/de-cultify.dm +++ /dev/null @@ -1,6 +0,0 @@ -/turf/unsimulated/wall/cult/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/nullrod)) - user.visible_message("\The [user] touches \the [src] with \the [I], and it shifts.", "You touch \the [src] with \the [I], and it shifts.") - ChangeTurf(/turf/unsimulated/wall) - return TRUE - return ..() \ No newline at end of file diff --git a/code/game/gamemodes/cult/cultify/mob.dm b/code/game/gamemodes/cult/cultify/mob.dm deleted file mode 100644 index fa32daaab7c7..000000000000 --- a/code/game/gamemodes/cult/cultify/mob.dm +++ /dev/null @@ -1,62 +0,0 @@ -/mob - //thou shall always be able to see the Geometer of Blood - var/image/narsimage = null - var/image/narglow = null - -/mob/proc/cultify() - return - -/mob/observer/ghost/cultify() - if(icon_state != "ghost-narsie") - icon = 'icons/mob/mob.dmi' - icon_state = "ghost-narsie" - overlays.Cut() - set_invisibility(0) - to_chat(src, "Even as a non-corporal being, you can feel Nar-Sie's presence altering you. You are now visible to everyone.") - -/mob/living/cultify() - if(iscultist(src) && client) - var/mob/living/simple_animal/construct/harvester/C = new(get_turf(src)) - mind.transfer_to(C) - to_chat(C, "The Geometer of Blood is overjoyed to be reunited with its followers, and accepts your body in sacrifice. As reward, you have been gifted with the shell of an Harvester.
    Your tendrils can use and draw runes without need for a tome, your eyes can see beings through walls, and your mind can open any door. Use these assets to serve Nar-Sie and bring him any remaining living human in the world.
    You can teleport yourself back to Nar-Sie along with any being under yourself at any time using your \"Harvest\" spell.
    ") - dust() - else if(client) - var/mob/observer/ghost/G = (ghostize()) - G.icon = 'icons/mob/mob.dmi' - G.icon_state = "ghost-narsie" - G.overlays.Cut() - G.set_invisibility(0) - to_chat(G, "You feel relieved as what's left of your soul finally escapes its prison of flesh.") - else - dust() - -/mob/proc/see_narsie(var/obj/singularity/narsie/large/N, var/dir) - if(N.chained) - if(narsimage) - qdel(narsimage) - qdel(narglow) - return - if((N.z == src.z)&&(get_dist(N,src) <= (N.consume_range+10)) && !(N in view(src))) - if(!narsimage) //Create narsimage - narsimage = image('icons/obj/narsie.dmi',src.loc,"narsie",9,1) - narsimage.mouse_opacity = 0 - if(!narglow) //Create narglow - narglow = image('icons/obj/narsie.dmi',narsimage.loc,"glow-narsie",12,1) - narglow.mouse_opacity = 0 - //Else if no dir is given, simply send them the image of narsie - var/new_x = 32 * (N.x - src.x) + N.pixel_x - var/new_y = 32 * (N.y - src.y) + N.pixel_y - narsimage.pixel_x = new_x - narsimage.pixel_y = new_y - narglow.pixel_x = new_x - narglow.pixel_y = new_y - narsimage.loc = src.loc - narglow.loc = src.loc - //Display the new narsimage to the player - src << narsimage - src << narglow - - else - if(narsimage) - QDEL_NULL(narsimage) - QDEL_NULL(narglow) diff --git a/code/game/gamemodes/cult/cultify/turf.dm b/code/game/gamemodes/cult/cultify/turf.dm deleted file mode 100644 index bd34943e3576..000000000000 --- a/code/game/gamemodes/cult/cultify/turf.dm +++ /dev/null @@ -1,39 +0,0 @@ -/turf/proc/cultify() - return - -/turf/simulated/floor/cultify() - //todo: flooring datum cultify check - cultify_floor() - -/turf/simulated/shuttle/wall/cultify() - cultify_wall() - -/turf/simulated/wall/cultify() - cultify_wall() - -/turf/simulated/wall/cult/cultify() - return - -/turf/unsimulated/wall/cult/cultify() - return - -/turf/unsimulated/beach/cultify() - return - -/turf/unsimulated/wall/cultify() - cultify_wall() - -/turf/simulated/floor/proc/cultify_floor() - set_flooring(decls_repository.get_decl(/decl/flooring/reinforced/cult)) - GLOB.cult.add_cultiness(CULTINESS_PER_TURF) - - -/turf/proc/cultify_wall() - var/turf/simulated/wall/wall = src - if(!istype(wall)) - return - if(wall.reinf_material) - ChangeTurf(/turf/simulated/wall/cult/reinf) - else - ChangeTurf(/turf/simulated/wall/cult) - GLOB.cult.add_cultiness(CULTINESS_PER_TURF) diff --git a/code/game/gamemodes/cult/ghosts.dm b/code/game/gamemodes/cult/ghosts.dm deleted file mode 100644 index 310e6da04c2d..000000000000 --- a/code/game/gamemodes/cult/ghosts.dm +++ /dev/null @@ -1,289 +0,0 @@ -/mob/observer/ghost/var/ghost_magic_cd = 0 - -/datum/antagonist/cultist/proc/add_ghost_magic(var/mob/observer/ghost/M) - if(max_cult_rating >= CULT_GHOSTS_1) - M.verbs += /mob/observer/ghost/proc/flick_lights - M.verbs += /mob/observer/ghost/proc/bloody_doodle - M.verbs += /mob/observer/ghost/proc/shatter_glass - M.verbs += /mob/observer/ghost/proc/slice - if(max_cult_rating >= CULT_GHOSTS_2) - M.verbs += /mob/observer/ghost/proc/move_item - M.verbs += /mob/observer/ghost/proc/whisper_to_cultist - M.verbs += /mob/observer/ghost/proc/bite_someone - M.verbs += /mob/observer/ghost/proc/chill_someone - if(max_cult_rating >= CULT_GHOSTS_3) - M.verbs += /mob/observer/ghost/proc/whisper_to_anyone - M.verbs += /mob/observer/ghost/proc/bloodless_doodle - M.verbs += /mob/observer/ghost/proc/toggle_visiblity - -/mob/observer/ghost/proc/ghost_ability_check() - var/turf/T = get_turf(src) - if(T.holy) - to_chat(src, "You may not use your abilities on the blessed ground.") - return 0 - if(ghost_magic_cd > world.time) - to_chat(src, "You need [round((ghost_magic_cd - world.time) / 10)] more seconds before you can use your abilities.") - return 0 - return 1 - -/mob/observer/ghost/proc/flick_lights() - set category = "Cult" - set name = "Flick lights" - set desc = "Flick some lights around you." - - if(!ghost_ability_check()) - return - - for(var/obj/machinery/light/L in range(3)) - L.flicker() - - ghost_magic_cd = world.time + 30 SECONDS - -/mob/observer/ghost/proc/bloody_doodle() - set category = "Cult" - set name = "Write in blood" - set desc = "Write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC." - - bloody_doodle_proc(0) - -/mob/observer/ghost/proc/bloody_doodle_proc(var/bloodless = 0) - if(!ghost_ability_check()) - return - - var/doodle_color = COLOR_BLOOD_HUMAN - - var/turf/simulated/T = get_turf(src) - if(!istype(T)) - to_chat(src, "You cannot doodle there.") - return - - var/num_doodles = 0 - for(var/obj/effect/decal/cleanable/blood/writing/W in T) - num_doodles++ - if(num_doodles > 4) - to_chat(src, "There is no space to write on!") - return - - var/obj/effect/decal/cleanable/blood/choice - if(!bloodless) - var/list/choices = list() - for(var/obj/effect/decal/cleanable/blood/B in range(1)) - if(B.amount > 0) - choices += B - - if(!choices.len) - to_chat(src, "There is no blood to use nearby.") - return - - choice = input(src, "What blood would you like to use?") as null|anything in choices - if(!choice) - return - - if(choice.basecolor) - doodle_color = choice.basecolor - - var/max_length = 50 - - var/message = sanitize(input("Write a message. It cannot be longer than [max_length] characters.", "Blood writing", "")) - - if(!ghost_ability_check()) - return - - if(message && (bloodless || (choice && (choice in range(1))))) - if(length(message) > max_length) - message += "-" - to_chat(src, "You ran out of blood to write with!") - - var/obj/effect/decal/cleanable/blood/writing/W = new(T) - W.basecolor = doodle_color - W.update_icon() - W.message = message - W.add_hiddenprint(src) - if(!bloodless) - W.visible_message("Invisible fingers crudely paint something in blood on \the [T].") - else - W.visible_message("Blood appears out of nowhere as invisible fingers crudely paint something on \the [T].") - - log_admin("[src] ([src.key]) used ghost magic to write '[message]' - [x]-[y]-[z]") - - ghost_magic_cd = world.time + 30 SECONDS - -/mob/observer/ghost/proc/shatter_glass() - set category = "Cult" - set name = "Noise: glass shatter" - set desc = "Make a sound of glass being shattered." - - if(!ghost_ability_check()) - return - - playsound(loc, "shatter", 50, 1) - - ghost_magic_cd = world.time + 5 SECONDS - -/mob/observer/ghost/proc/slice() - set category = "Cult" - set name = "Noise: slice" - set desc = "Make a sound of a sword hit." - - if(!ghost_ability_check()) - return - - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1) - - ghost_magic_cd = world.time + 5 SECONDS - -/mob/observer/ghost/proc/move_item() - set category = "Cult" - set name = "Move item" - set desc = "Move a small item to where you are." - - if(!ghost_ability_check()) - return - - var/turf/T = get_turf(src) - - var/list/obj/item/choices = list() - for(var/obj/item/I in range(1)) - if(I.w_class <= ITEM_SIZE_SMALL) - choices += I - - if(!choices.len) - to_chat(src, "There are no suitable items nearby.") - return - - var/obj/item/choice = input(src, "What item would you like to pull?") as null|anything in choices - if(!choice || !(choice in range(1)) || choice.w_class > ITEM_SIZE_SMALL) - return - - if(!ghost_ability_check()) - return - - if(step_to(choice, T)) - choice.visible_message("\The [choice] suddenly moves!") - - ghost_magic_cd = world.time + 60 SECONDS - -/mob/observer/ghost/proc/whisper_to_cultist() - set category = "Cult" - set name = "Whisper to cultist" - set desc = "Whisper to a human of your choice. They won't understand you unless they're a cultist though." - - whisper_proc() - -/mob/observer/ghost/proc/whisper_proc(var/anyone = 0) - if(!ghost_ability_check()) - return - - var/list/mob/living/choices = list() - for(var/mob/living/M in range(1)) - choices += M - - var/mob/living/choice = input(src, "Whom do you want to whisper to?") as null|anything in choices - if(!choice) - return - - var/message = sanitize(input("Decide what you want to whisper.", "Whisper", "")) - - if(!ghost_ability_check()) - return - - if(message) - if(iscultist(choice) || anyone) - to_chat(choice, "You hear a faint whisper... It says... \"[message]\"") - log_and_message_admins("used ghost magic to say '[message]' to \the [choice] and was heard - [x]-[y]-[z]") - else - to_chat(choice, "You hear a faint whisper, but you can't make out the words.") - log_and_message_admins("used ghost magic to say '[message]' to \the [choice] but wasn't heard - [x]-[y]-[z]") - to_chat(src, "You whisper to \the [choice]. Perhaps they heard you.") - - ghost_magic_cd = world.time + 100 SECONDS - -/mob/observer/ghost/proc/bite_someone() - set category = "Cult" - set name = "Bite" - set desc = "Bite or scratch someone." - - if(!ghost_ability_check()) - return - - var/list/mob/living/carbon/human/choices = list() - for(var/mob/living/carbon/human/H in range(1)) - choices += H - - var/mob/living/carbon/human/choice = input(src, "Whom do you want to scratch?") as null|anything in choices - if(!choice) - return - - if(!ghost_ability_check()) - return - - var/method = pick("bit", "scratched") - to_chat(choice, "Something invisible [method] you!") - choice.apply_effect(5, PAIN, 0) - to_chat(src, "You [method] \the [choice].") - - log_and_message_admins("used ghost magic to bite \the [choice] - [x]-[y]-[z]") - - ghost_magic_cd = world.time + 60 SECONDS - -/mob/observer/ghost/proc/chill_someone() - set category = "Cult" - set name = "Chill" - set desc = "Pass through someone, making them feel the chill of afterlife for a moment." - - if(!ghost_ability_check()) - return - - var/list/mob/living/carbon/human/choices = list() - for(var/mob/living/carbon/human/H in range(1)) - choices += H - - var/mob/living/carbon/human/choice = input(src, "Whom do you want to scare?") as null|anything in choices - if(!choice) - return - - if(!ghost_ability_check()) - return - - to_chat(choice, "You feel as if something cold passed through you!") - if(choice.bodytemperature >= choice.species.cold_level_1 + 1) - choice.bodytemperature = max(choice.species.cold_level_1 + 1, choice.bodytemperature - 30) - to_chat(src, "You pass through \the [choice], giving them a sudden chill.") - - log_and_message_admins("used ghost magic to chill \the [choice] - [x]-[y]-[z]") - - ghost_magic_cd = world.time + 60 SECONDS - -/mob/observer/ghost/proc/whisper_to_anyone() - set category = "Cult" - set name = "Whisper to mind" - set desc = "Whisper to a human of your choice." - - whisper_proc(1) - -/mob/observer/ghost/proc/bloodless_doodle() - set category = "Cult" - set name = "Write in own blood" - set desc = "Write a short message in blood on the floor or a wall. You don't need blood nearby to use this." - - bloody_doodle_proc(1) - -/mob/observer/ghost/proc/toggle_visiblity() - set category = "Cult" - set name = "Toggle Visibility" - set desc = "Allows you to become visible or invisible at will." - - if(invisibility && !ghost_ability_check()) - return - - if(invisibility == 0) - ghost_magic_cd = world.time + 60 SECONDS - to_chat(src, "You are now invisible.") - visible_message("It fades from sight...") - set_invisibility(INVISIBILITY_OBSERVER) - mouse_opacity = 1 - else - ghost_magic_cd = world.time + 60 SECONDS - to_chat(src, "You are now visible.") - set_invisibility(0) - mouse_opacity = 0 // This is so they don't make people invincible to melee attacks by hovering over them diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm deleted file mode 100644 index 1b2249524128..000000000000 --- a/code/game/gamemodes/cult/narsie.dm +++ /dev/null @@ -1,360 +0,0 @@ -var/global/narsie_behaviour = "CultStation13" -var/global/narsie_cometh = 0 -var/global/list/narsie_list = list() -/obj/singularity/narsie //Moving narsie to its own file for the sake of being clearer - name = "Nar-Sie" - desc = "Your mind begins to bubble and ooze as it tries to comprehend what it sees." - icon = 'icons/obj/narsie.dmi' - icon_state = "narsie-small" - pixel_x = -236 - pixel_y = -256 - - current_size = 9 //It moves/eats like a max-size singulo, aside from range. --NEO. - contained = 0 // Are we going to move around? - dissipate = 0 // Do we lose energy over time? - grav_pull = 10 //How many tiles out do we pull? - consume_range = 3 //How many tiles out do we eat - - -/obj/singularity/narsie/Initialize() - . = ..() - narsie_list.Add(src) - -/obj/singularity/narsie/Destroy() - narsie_list.Remove(src) - . = ..() - -/obj/singularity/narsie/large - name = "Nar-Sie" - icon = 'icons/obj/narsie.dmi' - icon_state = "narsie"//mobs perceive the geometer of blood through their see_narsie proc - - // Pixel stuff centers Narsie. - pixel_x = -236 - pixel_y = -256 - light_outer_range = 1 - light_color = "#3e0000" - - current_size = 6 - consume_range = 6 // How many tiles out do we eat. - var/announce=1 - var/cause_hell = 1 - -/obj/singularity/narsie/large/Initialize() - . = ..() - if(announce) - to_world("[uppertext(name)] HAS RISEN") - sound_to(world, sound('sound/effects/wind/wind_5_1.ogg')) - - narsie_spawn_animation() - - if(!narsie_cometh)//so we don't initiate Hell more than one time. - if(cause_hell) - SetUniversalState(/datum/universal_state/hell) - narsie_cometh = 1 - - spawn(10 SECONDS) - if(SSevac.evacuation_controller) - SSevac.evacuation_controller.call_evacuation(null, TRUE, 1) - SSevac.evacuation_controller.evac_no_return = 0 // Cannot recall - -/obj/singularity/narsie/Process() - eat() - - if (!target || prob(5)) - pickcultist() - - move() - - if (prob(25)) - mezzer() - -/obj/singularity/narsie/large/eat() - for (var/turf/A in orange(consume_range, src)) - consume(A) - -/obj/singularity/narsie/mezzer() - for(var/mob/living/carbon/M in oviewers(8, src)) - if(M.stat == CONSCIOUS) - if(M.status_flags & GODMODE) - continue - if(!iscultist(M)) - to_chat(M, " You feel your sanity crumble away in an instant as you gaze upon [src.name]...") - M.apply_effect(3, STUN) - - -/obj/singularity/narsie/large/Bump(atom/A) - if(!cause_hell) return - if(isturf(A)) - narsiewall(A) - else if(istype(A, /obj/structure/cult)) - qdel(A) - -/obj/singularity/narsie/large/Bumped(atom/A) - if(!cause_hell) return - if(isturf(A)) - narsiewall(A) - else if(istype(A, /obj/structure/cult)) - qdel(A) - -/obj/singularity/narsie/move(var/force_move = 0) - if(!move_self) - return 0 - - var/movement_dir = pick(GLOB.alldirs - last_failed_movement) - - if(force_move) - movement_dir = force_move - - if(target && prob(60)) - movement_dir = get_dir(src,target) - - spawn(0) - step(src, movement_dir) - spawn(1) - step(src, movement_dir) - return 1 - -/obj/singularity/narsie/large/move(var/force_move = 0) - if(!move_self) - return 0 - - var/movement_dir = pick(GLOB.alldirs - last_failed_movement) - - if(force_move) - movement_dir = force_move - - if(target && prob(60)) - movement_dir = get_dir(src,target) - spawn(0) - step(src, movement_dir) - narsiefloor(get_turf(loc)) - for(var/mob/M in GLOB.player_list) - if(M.client) - M.see_narsie(src,movement_dir) - spawn(10) - step(src, movement_dir) - narsiefloor(get_turf(loc)) - for(var/mob/M in GLOB.player_list) - if(M.client) - M.see_narsie(src,movement_dir) - return 1 - -/obj/singularity/narsie/proc/narsiefloor(var/turf/T)//leaving "footprints" - if(!(istype(T, /turf/simulated/wall/cult)||istype(T, /turf/space))) - if(T.icon_state != "cult-narsie") - T.desc = "something that goes beyond your understanding went this way" - T.icon = 'icons/turf/flooring/cult.dmi' - T.icon_state = "cult-narsie" - T.set_light(1) - -/obj/singularity/narsie/proc/narsiewall(var/turf/T) - T.desc = "An opening has been made on that wall, but who can say if what you seek truly lies on the other side?" - T.icon = 'icons/turf/walls.dmi' - T.icon_state = "cult-narsie" - T.set_opacity(0) - T.set_density(0) - set_light(1) - -/obj/singularity/narsie/large/consume(const/atom/A) //Has its own consume proc because it doesn't need energy and I don't want BoHs to explode it. --NEO -//NEW BEHAVIOUR - if(narsie_behaviour == "CultStation13") - //MOB PROCESSING - new_narsie(A) - -//OLD BEHAVIOUR - else if(narsie_behaviour == "Nar-Singulo") - old_narsie(A) - -/obj/singularity/narsie/proc/new_narsie(const/atom/A) - if (istype(A, /mob/) && (get_dist(A, src) <= 7)) - var/mob/M = A - - if(M.status_flags & GODMODE) - return 0 - - M.cultify() - -//TURF PROCESSING - else if (isturf(A)) - var/dist = get_dist(A, src) - - for (var/atom/movable/AM in A.contents) - if (dist <= consume_range) - consume(AM) - continue - - if (dist <= consume_range && !istype(A, /turf/space)) - var/turf/T = A - if(T.holy) - T.holy = 0 //Nar-Sie doesn't give a shit about sacred grounds. - T.cultify() - -/obj/singularity/narsie/proc/old_narsie(const/atom/A) - if(!(A.singuloCanEat())) - return 0 - - if (istype(A, /mob/living/)) - var/mob/living/C2 = A - - if(C2.status_flags & GODMODE) - return 0 - - C2.dust() // Changed from gib(), just for less lag. - - else if (istype(A, /obj/)) - qdel(A) - - if (A) - qdel(A) - else if (isturf(A)) - var/dist = get_dist(A, src) - - for (var/atom/movable/AM2 in A.contents) - if (AM2 == src) // This is the snowflake. - continue - - if (dist <= consume_range) - consume(AM2) - continue - - if (dist <= consume_range && !istype(A, get_base_turf_by_area(A))) - var/turf/T2 = A - T2.ChangeTurf(get_base_turf_by_area(A)) - -/obj/singularity/narsie/consume(const/atom/A) //This one is for the small ones. - if(!(A.singuloCanEat())) - return 0 - - if (istype(A, /mob/living/)) - var/mob/living/C2 = A - - if(C2.status_flags & GODMODE) - return 0 - - C2.dust() // Changed from gib(), just for less lag. - - else if (istype(A, /obj/)) - qdel(A) - - if (A) - qdel(A) - else if (isturf(A)) - var/dist = get_dist(A, src) - - for (var/atom/movable/AM2 in A.contents) - if (AM2 == src) // This is the snowflake. - continue - - if (dist <= consume_range) - consume(AM2) - continue - - if (dist > consume_range) - if(!(AM2.singuloCanEat())) - continue - - if (101 == AM2.invisibility) - continue - - spawn (0) - AM2.singularity_pull(src, src.current_size) - - if (dist <= consume_range && !istype(A, get_base_turf_by_area(A))) - var/turf/T2 = A - T2.ChangeTurf(get_base_turf_by_area(A)) - -/obj/singularity/narsie/explosion_act(severity) //No throwing bombs at it either. --NEO - SHOULD_CALL_PARENT(FALSE) - return - -/obj/singularity/narsie/proc/pickcultist() //Narsie rewards his cultists with being devoured first, then picks a ghost to follow. --NEO - var/list/cultists = list() - for(var/datum/mind/cult_nh_mind in GLOB.cult.current_antagonists) - if(!cult_nh_mind.current) - continue - if(cult_nh_mind.current.stat) - continue - if(get_z(cult_nh_mind.current) != z) - continue - cultists += cult_nh_mind.current - if(cultists.len) - acquire(pick(cultists)) - return - //If there was living cultists, it picks one to follow. - for(var/mob/living/carbon/human/food in GLOB.living_mob_list_) - if(food.stat) - continue - var/turf/pos = get_turf(food) - if(!pos) //Catches failure of get_turf. - continue - if(pos.z != src.z) - continue - cultists += food - if(cultists.len) - acquire(pick(cultists)) - return - //no living cultists, pick a living human instead. - for(var/mob/observer/ghost/ghost in GLOB.player_list) - if(!ghost.client) - continue - var/turf/pos = get_turf(ghost) - if(pos.z != src.z) - continue - cultists += ghost - if(cultists.len) - acquire(pick(cultists)) - return - //no living humans, follow a ghost instead. - -/obj/singularity/narsie/proc/acquire(const/mob/food) - var/capname = uppertext(name) - - to_chat(target, "[capname] HAS LOST INTEREST IN YOU.") - target = food - - if (ishuman(target)) - to_chat(target, "[capname] HUNGERS FOR YOUR SOUL.") - else - to_chat(target, "[capname] HAS CHOSEN YOU TO LEAD HIM TO HIS NEXT MEAL.") -/obj/singularity/narsie/on_capture() - chained = 1 - move_self = 0 - icon_state ="narsie-small-chains" - -/obj/singularity/narsie/on_release() - chained = 0 - move_self = 1 - icon_state ="narsie-small" - -/obj/singularity/narsie/large/on_capture() - chained = 1 - move_self = 0 - icon_state ="narsie-chains" - for(var/mob/M in SSmobs.mob_list)//removing the client image of nar-sie while it is chained - if(M.client) - M.see_narsie(src) - -/obj/singularity/narsie/large/on_release() - chained = 0 - move_self = 1 - icon_state ="narsie" - -/** - * Wizard narsie. - */ -/obj/singularity/narsie/wizard - grav_pull = 0 - -/obj/singularity/narsie/wizard/eat() - for (var/turf/T in RANGE_TURFS(src, consume_range)) - consume(T) - -/obj/singularity/narsie/proc/narsie_spawn_animation() - icon = 'icons/obj/narsie_spawn_anim.dmi' - set_dir(SOUTH) - move_self = 0 - flick("narsie_spawn_anim",src) - sleep(11) - move_self = 1 - icon = initial(icon) diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm deleted file mode 100644 index 44bcba5b39ff..000000000000 --- a/code/game/gamemodes/cult/runes.dm +++ /dev/null @@ -1,844 +0,0 @@ -/obj/effect/rune - name = "rune" - desc = "A strange collection of symbols drawn in blood." - anchored = 1 - icon = 'icons/effects/uristrunes.dmi' - icon_state = "blank" - unacidable = 1 - layer = RUNE_LAYER - - var/blood - var/bcolor - var/strokes = 2 // IF YOU EVER SET THIS TO MORE THAN TEN, EVERYTHING WILL BREAK - var/cultname = "" - -/obj/effect/rune/Initialize(mapload, var/blcolor = "#c80000", var/nblood = "blood") - . = ..() - bcolor = blcolor - blood = nblood - update_icon() - set_extension(src, /datum/extension/turf_hand, 10) - -/obj/effect/rune/on_update_icon() - overlays.Cut() - if(GLOB.cult.rune_strokes[type]) - var/list/f = GLOB.cult.rune_strokes[type] - for(var/i in f) - var/image/t = image('icons/effects/uristrunes.dmi', "rune-[i]") - overlays += t - else - var/list/q = list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - var/list/f = list() - for(var/i = 1 to strokes) - var/j = pick(q) - f += j - q -= f - var/image/t = image('icons/effects/uristrunes.dmi', "rune-[j]") - overlays += t - GLOB.cult.rune_strokes[type] = f.Copy() - color = bcolor - desc = "A strange collection of symbols drawn in [blood]." - -/obj/effect/rune/examine(mob/user) - . = ..() - if(iscultist(user)) - to_chat(user, "This is \a [cultname] rune.") - -/obj/effect/rune/attackby(var/obj/item/I, var/mob/living/user) - if(istype(I, /obj/item/book/tome) && iscultist(user)) - user.visible_message("[user] rubs \the [src] with \the [I], and \the [src] is absorbed by it.", "You retrace your steps, carefully undoing the lines of \the [src].") - qdel(src) - return - else if(istype(I, /obj/item/nullrod)) - user.visible_message("[user] hits \the [src] with \the [I], and it disappears, fizzling.", "You disrupt the vile magic with the deadening field of \the [I].", "You hear a fizzle.") - qdel(src) - return - -/obj/effect/rune/attack_hand(var/mob/living/user) - if(!iscultist(user)) - to_chat(user, "You can't mouth the arcane scratchings without fumbling over them.") - return - if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle) || user.silent) - to_chat(user, "You are unable to speak the words of the rune.") - return - if(GLOB.cult.powerless) - to_chat(user, "You read the words, but nothing happens.") - return fizzle(user) - cast(user) - -/obj/effect/rune/attack_ai(var/mob/living/user) // Cult borgs! - if(Adjacent(user)) - attack_hand(user) - -/obj/effect/rune/proc/cast(var/mob/living/user) - fizzle(user) - -/obj/effect/rune/proc/get_cultists() - . = list() - for(var/mob/living/M in range(1)) - if(iscultist(M)) - . += M - -/obj/effect/rune/proc/fizzle(var/mob/living/user) - visible_message("The markings pulse with a small burst of light, then fall dark.", "You hear a fizzle.") - -//Makes the speech a proc so all verbal components can be easily manipulated as a whole, or individually easily -/obj/effect/rune/proc/speak_incantation(var/mob/living/user, var/incantation) - var/decl/language/L = decls_repository.get_decl(/decl/language/cultcommon) - if(istype(L) && incantation && (L in user.languages)) - user.say(incantation, L) - -/* Tier 1 runes below */ - -/obj/effect/rune/convert - cultname = "convert" - var/spamcheck = 0 - -/obj/effect/rune/convert/cast(var/mob/living/user) - if(spamcheck) - return - - var/mob/living/carbon/target = null - for(var/mob/living/carbon/M in get_turf(src)) - if(!iscultist(M) && M.stat != DEAD) - target = M - break - - if(!target) - return fizzle(user) - - speak_incantation(user, "Mah[pick("'","`")]weyh pleggh at e'ntrath!") - target.visible_message("The markings below [target] glow a bloody red.") - - to_chat(target, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.") - if(!GLOB.cult.can_become_antag(target.mind, 1)) - to_chat(target, "Are you going insane?") - else - to_chat(target, "Do you want to join the cult of Nar'Sie? You can choose to ignore offer... Join the cult.") - - spamcheck = 1 - spawn(40) - spamcheck = 0 - if(!iscultist(target) && target.loc == get_turf(src)) // They hesitated, resisted, or can't join, and they are still on the rune - burn them - if(target.stat == CONSCIOUS) - target.take_overall_damage(0, 10) - switch(target.getFireLoss()) - if(0 to 25) - to_chat(target, "Your blood boils as you force yourself to resist the corruption invading every corner of your mind.") - if(25 to 45) - to_chat(target, "Your blood boils and your body burns as the corruption further forces itself into your body and mind.") - target.take_overall_damage(0, 3) - if(45 to 75) - to_chat(target, "You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble.") - target.take_overall_damage(0, 5) - if(75 to 100) - to_chat(target, "Your mind turns to ash as the burning flames engulf your very soul and images of an unspeakable horror begin to bombard the last remnants of mental resistance.") - target.take_overall_damage(0, 10) - -/obj/effect/rune/convert/Topic(href, href_list) - if(href_list["join"]) - if(usr.loc == loc && !iscultist(usr)) - GLOB.cult.add_antagonist(usr.mind, ignore_role = 1, do_not_equip = 1) - -/obj/effect/rune/teleport - cultname = "teleport" - var/destination - -/obj/effect/rune/teleport/Initialize() - . = ..() - var/area/A = get_area(src) - destination = A.name - GLOB.cult.teleport_runes += src - -/obj/effect/rune/teleport/Destroy() - GLOB.cult.teleport_runes -= src - var/turf/T = get_turf(src) - for(var/atom/movable/A in contents) - A.forceMove(T) - return ..() - -/obj/effect/rune/teleport/examine(mob/user) - . = ..() - if(iscultist(user)) - to_chat(user, "Its name is [destination].") - -/obj/effect/rune/teleport/cast(var/mob/living/user) - if(user.loc == src) - showOptions(user) - else if(user.loc == get_turf(src)) - speak_incantation(user, "Sas[pick("'","`")]so c'arta forbici!") - if(do_after(user, 30)) - user.visible_message("\The [user] disappears in a flash of red light!", "You feel as your body gets dragged into the dimension of Nar-Sie!", "You hear a sickening crunch.") - user.forceMove(src) - showOptions(user) - var/warning = 0 - while(user.loc == src) - user.take_organ_damage(0, 2) - if(user.getFireLoss() > 50) - to_chat(user, "Your body can't handle the heat anymore!") - leaveRune(user) - return - if(warning == 0) - to_chat(user, "You feel the immerse heat of the realm of Nar-Sie...") - ++warning - if(warning == 1 && user.getFireLoss() > 15) - to_chat(user, "Your burns are getting worse. You should return to your realm soon...") - ++warning - if(warning == 2 && user.getFireLoss() > 35) - to_chat(user, "The heat! It burns!") - ++warning - sleep(10) - else - var/input = input(user, "Choose a new rune name.", "Destination", "") as text|null - if(!input) - return - destination = sanitize(input) - -/obj/effect/rune/teleport/Topic(href, href_list) - if(usr.loc != src) - return - if(href_list["target"]) - var/obj/effect/rune/teleport/targ = locate(href_list["target"]) - if(istype(targ)) // Checks for null, too - usr.forceMove(targ) - targ.showOptions(usr) - else if(href_list["leave"]) - leaveRune(usr) - -/obj/effect/rune/teleport/proc/showOptions(var/mob/living/user) - var/list/t = list() - for(var/obj/effect/rune/teleport/T in GLOB.cult.teleport_runes) - if(T == src) - continue - t += "[T.destination]" - to_chat(user, "Teleport runes: [english_list(t, nothing_text = "no other runes exist")]... or return from this rune.") - -/obj/effect/rune/teleport/proc/leaveRune(var/mob/living/user) - if(user.loc != src) - return - user.dropInto(loc) - user.visible_message("\The [user] appears in a flash of red light!", "You feel as your body gets thrown out of the dimension of Nar-Sie!", "You hear a pop.") - -/obj/effect/rune/tome - cultname = "summon tome" - -/obj/effect/rune/tome/cast(var/mob/living/user) - new /obj/item/book/tome(get_turf(src)) - speak_incantation(user, "N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") - visible_message("\The [src] disappears with a flash of red light, and in its place now a book lies.", "You hear a pop.") - qdel(src) - -/obj/effect/rune/wall - cultname = "wall" - - var/obj/effect/cultwall/wall = null - -/obj/effect/rune/wall/Destroy() - QDEL_NULL(wall) - return ..() - -/obj/effect/rune/wall/cast(var/mob/living/user) - var/t - if(wall) - if(wall.health >= wall.max_health) - to_chat(user, "The wall doesn't need mending.") - return - t = wall.max_health - wall.health - wall.health += t - else - wall = new /obj/effect/cultwall(get_turf(src), bcolor) - wall.rune = src - t = wall.health - user.remove_blood_simple(t / 50) - speak_incantation(user, "Khari[pick("'","`")]d! Eske'te tannin!") - to_chat(user, "Your blood flows into the rune, and you feel that the very space over the rune thickens.") - -/obj/effect/cultwall - name = "red mist" - desc = "A strange red mist emanating from a rune below it." - icon = 'icons/effects/effects.dmi'//TODO: better icon - icon_state = "smoke" - color = "#ff0000" - anchored = 1 - density = 1 - unacidable = 1 - var/obj/effect/rune/wall/rune - var/health - var/max_health = 200 - -/obj/effect/cultwall/Initialize(mapload, var/bcolor) - . = ..() - health = max_health - if(bcolor) - color = bcolor - -/obj/effect/cultwall/Destroy() - if(rune) - rune.wall = null - rune = null - return ..() - -/obj/effect/cultwall/examine(mob/user) - . = ..() - if(iscultist(user)) - if(health == max_health) - to_chat(user, "It is fully intact.") - else if(health > max_health * 0.5) - to_chat(user, "It is damaged.") - else - to_chat(user, "It is about to dissipate.") - -/obj/effect/cultwall/attack_hand(var/mob/living/user) - if(iscultist(user)) - user.visible_message("\The [user] touches \the [src], and it fades.", "You touch \the [src], whispering the old ritual, making it disappear.") - qdel(src) - else - to_chat(user, "You touch \the [src]. It feels wet and becomes harder the further you push your arm.") - -/obj/effect/cultwall/attackby(var/obj/item/I, var/mob/living/user) - if(istype(I, /obj/item/nullrod)) - user.visible_message("\The [user] touches \the [src] with \the [I], and it disappears.", "You disrupt the vile magic with the deadening field of \the [I].") - qdel(src) - else if(I.force) - user.visible_message("\The [user] hits \the [src] with \the [I].", "You hit \the [src] with \the [I].") - take_damage(I.force) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) - -/obj/effect/cultwall/bullet_act(var/obj/item/projectile/Proj) - if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN)) - return - take_damage(Proj.damage) - ..() - -/obj/effect/cultwall/proc/take_damage(var/amount) - health -= amount - if(health <= 0) - visible_message("\The [src] dissipates.") - qdel(src) - -/obj/effect/rune/ajorney - cultname = "astral journey" - -/obj/effect/rune/ajorney/cast(var/mob/living/user) - var/tmpkey = user.key - if(user.loc != get_turf(src)) - return - speak_incantation(user, "Fwe[pick("'","`")]sh mah erl nyag r'ya!") - user.visible_message("\The [user]'s eyes glow blue as \he freezes in place, absolutely motionless.", "The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...", "You hear only complete silence for a moment.") - announce_ghost_joinleave(user.ghostize(1), 1, "You feel that they had to use some [pick("dark", "black", "blood", "forgotten", "forbidden")] magic to [pick("invade", "disturb", "disrupt", "infest", "taint", "spoil", "blight")] this place!") - var/mob/observer/ghost/soul - for(var/mob/observer/ghost/O in GLOB.ghost_mob_list) - if(O.key == tmpkey) - soul = O - break - while(user) - if(user.stat == DEAD) - return - if(user.key) - return - else if(user.loc != get_turf(src) && soul) - soul.reenter_corpse() - else - user.take_organ_damage(0, 1) - sleep(20) - fizzle(user) - -/obj/effect/rune/defile - cultname = "defile" - -/obj/effect/rune/defile/cast(var/mob/living/user) - speak_incantation(user, "Ia! Ia! Zasan therium viortia!") - for(var/turf/T in range(1, src)) - if(T.holy) - T.holy = 0 - else - T.cultify() - visible_message("\The [src] embeds into the floor and walls around it, changing them!", "You hear liquid flow.") - qdel(src) - -/obj/effect/rune/obscure - cultname = "obscure" - -/obj/effect/rune/obscure/cast(var/mob/living/user) - var/runecheck = 0 - for(var/obj/effect/rune/R in orange(1, src)) - if(R != src) - R.set_invisibility(INVISIBILITY_OBSERVER) - runecheck = 1 - if(runecheck) - speak_incantation(user, "Kla[pick("'","`")]atu barada nikt'o!") - visible_message("\ The rune turns into gray dust that conceals the surrounding runes.") - qdel(src) - -/obj/effect/rune/reveal - cultname = "reveal" - -/obj/effect/rune/reveal/cast(var/mob/living/user) - var/irunecheck = 0 - for(var/obj/effect/rune/R in orange(1, src)) - if(R != src) - R.set_invisibility(SEE_INVISIBLE_NOLIGHTING) - irunecheck = 1 - if(irunecheck) - speak_incantation(user, "Nikt[pick("'","`")]o barada kla'atu!") - visible_message("\ The rune turns into red dust that reveals the surrounding runes.") - qdel(src) - -/* Tier 2 runes */ - - -/obj/effect/rune/armor - cultname = "summon robes" - strokes = 3 - -/obj/effect/rune/armor/cast(var/mob/living/user) - speak_incantation(user, "N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") - visible_message("\The [src] disappears with a flash of red light, and a set of armor appears on \the [user].", "You are blinded by the flash of red light. After you're able to see again, you see that you are now wearing a set of armor.") - - var/obj/O = user.get_equipped_item(slot_head) // This will most likely kill you if you are wearing a spacesuit, and it's 100% intended - if(O && !istype(O, /obj/item/clothing/head/culthood) && user.unEquip(O)) - user.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head) - O = user.get_equipped_item(slot_wear_suit) - if(O && !istype(O, /obj/item/clothing/suit/cultrobes) && user.unEquip(O)) - user.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit) - O = user.get_equipped_item(slot_shoes) - if(O && !istype(O, /obj/item/clothing/shoes/cult) && user.unEquip(O)) - user.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(user), slot_shoes) - - O = user.get_equipped_item(slot_back) - if(istype(O, /obj/item/storage) && !istype(O, /obj/item/storage/backpack/cultpack) && user.unEquip(O)) // We don't want to make the vox drop their nitrogen tank, though - var/obj/item/storage/backpack/cultpack/C = new /obj/item/storage/backpack/cultpack(user) - user.equip_to_slot_or_del(C, slot_back) - if(C) - for(var/obj/item/I in O) - I.forceMove(C) - else if(!O) - var/obj/item/storage/backpack/cultpack/C = new /obj/item/storage/backpack/cultpack(user) - user.equip_to_slot_or_del(C, slot_back) - - user.update_icons() - - qdel(src) - -/obj/effect/rune/offering - cultname = "offering" - strokes = 3 - var/mob/living/victim - -/obj/effect/rune/offering/cast(var/mob/living/user) - var/list/mob/living/cultists = get_cultists() - if(victim) - to_chat(user, "You are already sarcificing \the [victim] on this rune.") - return - if(cultists.len < 3) - to_chat(user, "You need three cultists around this rune to make it work.") - return fizzle(user) - var/turf/T = get_turf(src) - for(var/mob/living/M in T) - if(M.stat != DEAD && !iscultist(M)) - victim = M - break - if(!victim) - return fizzle(user) - - for(var/mob/living/M in cultists) - M.say("Barhah hra zar[pick("'","`")]garis!") - - while(victim && victim.loc == T && victim.stat != DEAD) - var/list/mob/living/casters = get_cultists() - if(casters.len < 3) - break - //T.turf_animation('icons/effects/effects.dmi', "rune_sac") - victim.fire_stacks = max(2, victim.fire_stacks) - victim.IgniteMob() - victim.take_organ_damage(2 + casters.len, 2 + casters.len) // This is to speed up the process and also damage mobs that don't take damage from being on fire, e.g. borgs - if(ishuman(victim)) - var/mob/living/carbon/human/H = victim - if(H.is_asystole()) - H.adjustBrainLoss(2 + casters.len) - sleep(40) - if(victim && victim.loc == T && victim.stat == DEAD) - GLOB.cult.add_cultiness(CULTINESS_PER_SACRIFICE) - var/obj/item/soulstone/full/F = new(get_turf(src)) - for(var/mob/M in cultists | get_cultists()) - to_chat(M, "The Geometer of Blood accepts this offering.") - visible_message("\The [F] appears over \the [src].") - GLOB.cult.sacrificed += victim.mind - if(victim.mind == GLOB.cult.sacrifice_target) - for(var/datum/mind/H in GLOB.cult.current_antagonists) - if(H.current) - to_chat(H.current, "Your objective is now complete.") - //TODO: other rewards? - /* old sac code - left there in case someone wants to salvage it - var/worth = 0 - if(istype(H,/mob/living/carbon/human)) - var/mob/living/carbon/human/lamb = H - if(lamb.species.rarity_value > 3) - worth = 1 - - if(H.mind == cult.sacrifice_target) - - to_chat(usr, "The Geometer of Blood accepts this sacrifice, your objective is now complete.") - - to_chat(usr, "The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice.") - - to_chat(usr, "The Geometer of blood accepts this sacrifice.") - to_chat(usr, "However, this soul was not enough to gain His favor.") - - to_chat(usr, "The Geometer of blood accepts this sacrifice.") - to_chat(usr, "However, a mere dead body is not enough to satisfy Him.") - */ - to_chat(victim, "The Geometer of Blood claims your body.") - victim.dust() - if(victim) - victim.ExtinguishMob() // Technically allows them to put the fire out by sacrificing them and stopping immediately, but I don't think it'd have much effect - victim = null - - -/obj/effect/rune/drain - cultname = "blood drain" - strokes = 3 - -/obj/effect/rune/drain/cast(var/mob/living/user) - var/mob/living/carbon/human/victim - for(var/mob/living/carbon/human/M in get_turf(src)) - if(iscultist(M)) - continue - victim = M - if(!victim) - return fizzle(user) - if(victim.vessel.total_volume < 20) - to_chat(user, "This body has no blood in it.") - return fizzle(user) - victim.vessel.remove_any(20) - admin_attack_log(user, victim, "Used a blood drain rune.", "Was victim of a blood drain rune.", "used a blood drain rune on") - speak_incantation(user, "Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!") - user.visible_message("Blood flows from \the [src] into \the [user]!", "The blood starts flowing from \the [src] into your frail mortal body. [capitalize(english_list(heal_user(user), nothing_text = "you feel no different"))].", "You hear liquid flow.") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - -/obj/effect/rune/drain/proc/heal_user(var/mob/living/carbon/human/user) - if(!istype(user)) - return list("you feel no different") - var/list/statuses = list() - var/charges = 20 - var/use - use = min(charges, user.species.blood_volume - user.vessel.total_volume) - if(use > 0) - user.vessel.add_reagent(user.species.blood_reagent, use) - charges -= use - statuses += "you regain lost blood" - if(!charges) - return statuses - if(user.getBruteLoss() || user.getFireLoss()) - var/healbrute = user.getBruteLoss() - var/healburn = user.getFireLoss() - if(healbrute < healburn) - healbrute = min(healbrute, charges / 2) - charges -= healbrute - healburn = min(healburn, charges) - charges -= healburn - else - healburn = min(healburn, charges / 2) - charges -= healburn - healbrute = min(healbrute, charges) - charges -= healbrute - user.heal_organ_damage(healbrute, healburn, 1) - statuses += "your wounds mend" - if(!charges) - return statuses - if(user.getToxLoss()) - use = min(user.getToxLoss(), charges) - user.adjustToxLoss(-use) - charges -= use - statuses += "your body stings less" - if(!charges) - return statuses - if(charges >= 15) - for(var/obj/item/organ/external/e in user.organs) - if(e && e.status & ORGAN_BROKEN) - e.status &= ~ORGAN_BROKEN - statuses += "bones in your [e.name] snap into place" - charges -= 15 - if(charges < 15) - break - if(!charges) - return statuses - var/list/obj/item/organ/damaged = list() - for(var/obj/item/organ/I in user.internal_organs) - if(I.damage) - damaged += I - if(damaged.len) - statuses += "you feel pain inside for a moment that passes quickly" - while(charges && damaged.len) - var/obj/item/organ/fix = pick(damaged) - fix.damage = max(0, fix.damage - min(charges, 1)) - charges = max(charges - 1, 0) - if(fix.damage == 0) - damaged -= fix - return statuses - -/obj/effect/rune/emp - cultname = "emp" - strokes = 4 - -/obj/effect/rune/emp/cast(var/mob/living/user) - empulse(get_turf(src), 4, 2, 1) - speak_incantation(user, "Ta'gh fara[pick("'","`")]qha fel d'amar det!") - qdel(src) - -/obj/effect/rune/massdefile //Defile but with a huge range. Bring a buddy for this, you're hitting the floor. - cultname = "mass defile" - -/obj/effect/rune/massdefile/cast(var/mob/living/user) - var/list/mob/living/cultists = get_cultists() - if(cultists.len < 3) - to_chat(user, "You need three cultists around this rune to make it work.") - return fizzle(user) - else - for(var/mob/living/M in cultists) - M.say("Ia! Ia! Zasan therium viortia! Razan gilamrua kioha!") - for(var/turf/T in range(5, src)) - if(T.holy) - T.holy = 0 - else - T.cultify() - visible_message("\The [src] embeds into the floor and walls around it, changing them!", "You hear liquid flow.") - qdel(src) - -/* Tier 3 runes */ - -/obj/effect/rune/weapon - cultname = "summon weapon" - strokes = 4 - -/obj/effect/rune/weapon/cast(var/mob/living/user) - if(!istype(user.get_equipped_item(slot_head), /obj/item/clothing/head/culthood) || !istype(user.get_equipped_item(slot_wear_suit), /obj/item/clothing/suit/cultrobes) || !istype(user.get_equipped_item(slot_shoes), /obj/item/clothing/shoes/cult)) - to_chat(user, "You need to be wearing your robes to use this rune.") - return fizzle(user) - var/turf/T = get_turf(src) - if(T.icon_state != "cult" && T.icon_state != "cult-narsie") - to_chat(user, "This rune needs to be placed on the defiled ground.") - return fizzle(user) - speak_incantation(user, "N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") - user.put_in_hands(new /obj/item/sword/cultblade(user)) - qdel(src) - -/obj/effect/rune/shell - cultname = "summon shell" - strokes = 4 - -/obj/effect/rune/shell/cast(var/mob/living/user) - var/turf/T = get_turf(src) - if(T.icon_state != "cult" && T.icon_state != "cult-narsie") - to_chat(user, "This rune needs to be placed on the defiled ground.") - return fizzle(user) - - var/obj/item/stack/material/steel/target - for(var/obj/item/stack/material/steel/S in get_turf(src)) - if(S.get_amount() >= 10) - target = S - break - - if(!target) - to_chat(user, "You need ten sheets of metal to fold them into a construct shell.") - return fizzle(user) - - speak_incantation(user, "Da A[pick("'","`")]ig Osk!") - target.use(10) - var/obj/O = new /obj/structure/constructshell/cult(get_turf(src)) - visible_message("The metal bends into \the [O], and \the [src] imbues into it.", "You hear a metallic sound.") - qdel(src) - -/obj/effect/rune/confuse - cultname = "confuse" - strokes = 4 - -/obj/effect/rune/confuse/cast(var/mob/living/user) - speak_incantation(user, "Fuu ma[pick("'","`")]jin!") - visible_message("\The [src] explodes in a bright flash.") - var/list/mob/affected = list() - for(var/mob/living/M in viewers(src)) - if(iscultist(M)) - continue - var/obj/item/nullrod/N = locate() in M - if(N) - continue - affected |= M - if(iscarbon(M)) - var/mob/living/carbon/C = M - C.eye_blurry += 50 - C.Weaken(3) - C.Stun(5) - else if(issilicon(M)) - M.Weaken(10) - - admin_attacker_log_many_victims(user, affected, "Used a confuse rune.", "Was victim of a confuse rune.", "used a confuse rune on") - qdel(src) - -/obj/effect/rune/revive - cultname = "revive" - strokes = 4 - -/obj/effect/rune/revive/cast(var/mob/living/user) - var/mob/living/carbon/human/target - var/obj/item/soulstone/source - for(var/mob/living/carbon/human/M in get_turf(src)) - if(M.stat == DEAD) - if(iscultist(M)) - if(M.key) - target = M - break - if(!target) - return fizzle(user) - for(var/obj/item/soulstone/S in get_turf(src)) - if(S.full && !S.shade.key) - source = S - break - if(!source) - return fizzle(user) - target.rejuvenate() - source.set_full(0) - speak_incantation(user, "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") - target.visible_message("\The [target]'s eyes glow with a faint red as \he stands up, slowly starting to breathe again.", "Life... I'm alive again...", "You hear liquid flow.") - -/obj/effect/rune/blood_boil - cultname = "blood boil" - strokes = 4 - -/obj/effect/rune/blood_boil/cast(var/mob/living/user) - var/list/mob/living/cultists = get_cultists() - if(cultists.len < 3) - return fizzle() - - for(var/mob/living/M in cultists) - M.say("Dedo ol[pick("'","`")]btoh!") - - var/list/mob/living/previous = list() - var/list/mob/living/current = list() - while(cultists.len >= 3) - cultists = get_cultists() - for(var/mob/living/carbon/M in viewers(src)) - if(iscultist(M)) - continue - current |= M - var/obj/item/nullrod/N = locate() in M - if(N) - continue - M.take_overall_damage(5, 5) - if(!(M in previous)) - if(M.should_have_organ(BP_HEART)) - to_chat(M, "Your blood boils!") - else - to_chat(M, "You feel searing heat inside!") - previous = current.Copy() - current.Cut() - sleep(10) - -/* Tier NarNar runes */ - -/obj/effect/rune/tearreality - cultname = "tear reality" - var/the_end_comes = 0 - var/the_time_has_come = 300 - var/obj/singularity/narsie/large/HECOMES = null - strokes = 9 - -/obj/effect/rune/tearreality/cast(var/mob/living/user) - if(!GLOB.cult.allow_narsie) - return - if(the_end_comes) - to_chat(user, "You are already summoning! Be patient!") - return - var/list/mob/living/cultists = get_cultists() - if(cultists.len < 5) - return fizzle() - for(var/mob/living/M in cultists) - M.say("Tok-lyr rqa'nap g[pick("'","`")]lt-ulotf!") - to_chat(M, "You are starting to tear through the veil, opening the way to bring Him back... stay around the rune!") - log_and_message_admins_many(cultists, "started summoning Nar-sie.") - - var/area/A = get_area(src) - command_announcement.Announce("High levels of gravitational disruption detected at \the [A]. Suspected wormhole forming. Investigate it immediately.") - while(cultists.len > 4 || the_end_comes) - cultists = get_cultists() - if(cultists.len > 8) - ++the_end_comes - if(cultists.len > 4) - ++the_end_comes - else - --the_end_comes - if(the_end_comes >= the_time_has_come) - break - for(var/mob/living/M in cultists) - if(prob(5)) - M.say(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) - - for(var/turf/T in range(min(the_end_comes, 15))) - if(prob(the_end_comes / 3)) - T.cultify() - sleep(10) - - if(the_end_comes >= the_time_has_come) - HECOMES = new /obj/singularity/narsie/large(get_turf(src)) - else - command_announcement.Announce("Gravitational anomaly has ceased.") - qdel(src) - -/obj/effect/rune/tearreality/attack_hand(var/mob/living/user) - ..() - if(HECOMES && !iscultist(user)) - var/input = input(user, "Are you SURE you want to sacrifice yourself?", "DO NOT DO THIS") in list("Yes", "No") - if(input != "Yes") - return - speak_incantation(user, "Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!") - to_chat(user, "In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.") - for(var/mob/M in GLOB.living_mob_list_) - if(iscultist(M)) - to_chat(M, "You see a vision of \the [user] keeling over dead, his blood glowing blue as it escapes \his body and dissipates into thin air; you hear an otherwordly scream and feel that a great disaster has just been averted.") - else - to_chat(M, "You see a vision of [name] keeling over dead, his blood glowing blue as it escapes his body and dissipates into thin air; you hear an otherwordly scream and feel very weak for a moment.") - log_and_message_admins("mended reality with the greatest sacrifice", user) - user.dust() - GLOB.cult.powerless = 1 - qdel(HECOMES) - qdel(src) - return - -/obj/effect/rune/tearreality/attackby() - if(the_end_comes) - return - ..() - -/* Imbue runes */ - -/obj/effect/rune/imbue - cultname = "otherwordly abomination that shouldn't exist and that you should report to your local god as soon as you see it, along with the instructions for making this" - var/papertype - -/obj/effect/rune/imbue/cast(var/mob/living/user) - var/obj/item/paper/target - var/tainted = 0 - for(var/obj/item/paper/P in get_turf(src)) - if(!P.info) - target = P - break - else - tainted = 1 - if(!target) - if(tainted) - to_chat(user, "The blank is tainted. It is unsuitable.") - return fizzle(user) - speak_incantation(user, "H'drak v[pick("'","`")]loso, mir'kanas verbot!") - visible_message("The rune forms into an arcane image on the paper.") - new papertype(get_turf(src)) - qdel(target) - qdel(src) - -/obj/effect/rune/imbue/stun - cultname = "stun imbue" - papertype = /obj/item/paper/talisman/stun - -/obj/effect/rune/imbue/emp - cultname = "destroy technology imbue" - papertype = /obj/item/paper/talisman/emp diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm deleted file mode 100644 index e5178ace67f6..000000000000 --- a/code/game/gamemodes/cult/talisman.dm +++ /dev/null @@ -1,57 +0,0 @@ -/obj/item/paper/talisman - icon_state = "paper_talisman" - var/imbue = null - info = "


    " - -/obj/item/paper/talisman/attack_self(var/mob/living/user) - if(iscultist(user)) - to_chat(user, "Attack your target to use this talisman.") - else - to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") - -/obj/item/paper/talisman/attack(var/mob/living/M, var/mob/living/user) - return - -/obj/item/paper/talisman/stun/attack_self(var/mob/living/user) - if(iscultist(user)) - to_chat(user, "This is a stun talisman.") - ..() - -/obj/item/paper/talisman/stun/attack(var/mob/living/M, var/mob/living/user) - if(!iscultist(user)) - return - user.say("Dream Sign: Evil Sealing Talisman!") //TODO: never change this shit - var/obj/item/nullrod/nrod = locate() in M - if(nrod) - user.visible_message("\The [user] invokes \the [src] at [M], but they are unaffected.", "You invoke \the [src] at [M], but they are unaffected.") - return - else - user.visible_message("\The [user] invokes \the [src] at [M].", "You invoke \the [src] at [M].") - - if(issilicon(M)) - M.Weaken(15) - M.silent += 15 - else if(iscarbon(M)) - var/mob/living/carbon/C = M - C.silent += 15 - C.Weaken(20) - C.Stun(20) - admin_attack_log(user, M, "Used a stun talisman.", "Was victim of a stun talisman.", "used a stun talisman on") - user.unEquip(src) - qdel(src) - -/obj/item/paper/talisman/emp/attack_self(var/mob/living/user) - if(iscultist(user)) - to_chat(user, "This is an emp talisman.") - ..() - -/obj/item/paper/talisman/emp/afterattack(var/atom/target, var/mob/user, var/proximity) - if(!iscultist(user)) - return - if(!proximity) - return - user.say("Ta'gh fara[pick("'","`")]qha fel d'amar det!") - user.visible_message("\The [user] invokes \the [src] at [target].", "You invoke \the [src] at [target].") - target.emp_act(1) - user.unEquip(src) - qdel(src) diff --git a/code/game/gamemodes/endgame/endgame.dm b/code/game/gamemodes/endgame/endgame.dm index 440d469b5931..c1c03164c55a 100644 --- a/code/game/gamemodes/endgame/endgame.dm +++ b/code/game/gamemodes/endgame/endgame.dm @@ -1,3 +1,4 @@ +var/global/universe_has_ended = 0 /********************** * ENDGAME STUFF **********************/ @@ -26,18 +27,7 @@ // Actually decay the turf. /datum/universal_state/proc/DecayTurf(var/turf/T) - if(istype(T,/turf/simulated/wall)) - var/turf/simulated/wall/W=T - W.melt() - return - if(istype(T,/turf/simulated/floor)) - var/turf/simulated/floor/F=T - // Burnt? - if(!F.burnt) - F.burn_tile() - else - F.ReplaceWithLattice() - return + T.handle_universal_decay() // Return 0 to cause shuttle call to fail. /datum/universal_state/proc/OnShuttleCall(var/mob/user) @@ -54,6 +44,7 @@ // Apply changes when entering state /datum/universal_state/proc/OnEnter() + set waitfor = FALSE // Does nothing by default // Apply changes to a new turf. @@ -71,10 +62,10 @@ /proc/SetUniversalState(var/newstate,var/on_exit=1, var/on_enter=1, list/arguments=null) if(on_exit) - GLOB.universe.OnExit() + global.universe.OnExit() if(arguments) - GLOB.universe = new newstate(arglist(arguments)) + global.universe = new newstate(arglist(arguments)) else - GLOB.universe = new newstate + global.universe = new newstate if(on_enter) - GLOB.universe.OnEnter() + global.universe.OnEnter() diff --git a/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm b/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm index c41d4a94bf63..634ee0779fb6 100644 --- a/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm +++ b/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm @@ -9,23 +9,23 @@ affected_levels = zlevels /datum/universal_state/jump/OnEnter() - var/space_zlevel = GLOB.using_map.get_empty_zlevel() //get a place for stragglers + var/datum/level_data/space_zlevel = SSmapping.increment_world_z_size(/datum/level_data/space) //get a place for stragglers for(var/mob/living/M in SSmobs.mob_list) if(M.z in affected_levels) var/area/A = get_area(M) if(istype(A,/area/space)) //straggler - var/turf/T = locate(M.x, M.y, space_zlevel) + var/turf/T = locate(M.x, M.y, space_zlevel.level_z) if(T) M.forceMove(T) else create_duplicate(M) - for(var/mob/goast in GLOB.ghost_mob_list) - goast.mouse_opacity = 0 //can't let you click that Dave + for(var/mob/goast in global.ghost_mob_list) + goast.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE //can't let you click that Dave goast.set_invisibility(SEE_INVISIBLE_LIVING) goast.alpha = 255 - old_accessible_z_levels = GLOB.using_map.accessible_z_levels.Copy() + old_accessible_z_levels = SSmapping.accessible_z_levels.Copy() for(var/z in affected_levels) - GLOB.using_map.accessible_z_levels -= "[z]" //not accessible during the jump + SSmapping.accessible_z_levels -= num2text(z) //not accessible during the jump /datum/universal_state/jump/OnExit() for(var/mob/M in duplicated) @@ -33,7 +33,7 @@ clear_duplicated(M) duplicated.Cut() - GLOB.using_map.accessible_z_levels = old_accessible_z_levels + SSmapping.accessible_z_levels = old_accessible_z_levels old_accessible_z_levels = null /datum/universal_state/jump/OnPlayerLatejoin(var/mob/living/M) @@ -53,15 +53,15 @@ if(M.client) to_chat(M,"You feel oddly light, and somewhat disoriented as everything around you shimmers and warps ever so slightly.") M.overlay_fullscreen("wormhole", /obj/screen/fullscreen/wormhole_overlay) - M.confused = 20 + M.set_status_condition(STAT_CONFUSE, 20) bluegoasts += new/obj/effect/bluegoast/(get_turf(M),M) /datum/universal_state/jump/proc/clear_duplicated(var/mob/living/M) if(M.client) to_chat(M,"You feel rooted in material world again.") M.clear_fullscreen("wormhole") - M.confused = 0 - for(var/mob/goast in GLOB.ghost_mob_list) + M.set_status_condition(STAT_CONFUSE, 0) + for(var/mob/goast in global.ghost_mob_list) goast.mouse_opacity = initial(goast.mouse_opacity) goast.set_invisibility(initial(goast.invisibility)) goast.alpha = initial(goast.alpha) @@ -72,8 +72,8 @@ /obj/effect/bluegoast name = "echo" desc = "It's not going to punch you, is it?" - var/mob/living/carbon/human/daddy - anchored = 1 + var/mob/living/human/daddy + anchored = TRUE var/reality = 0 simulated = 0 @@ -84,14 +84,14 @@ daddy = ndaddy set_dir(daddy.dir) appearance = daddy.appearance - GLOB.moved_event.register(daddy, src, /obj/effect/bluegoast/proc/mirror) - GLOB.dir_set_event.register(daddy, src, /obj/effect/bluegoast/proc/mirror_dir) - GLOB.destroyed_event.register(daddy, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/moved, daddy, src, TYPE_PROC_REF(/obj/effect/bluegoast, mirror)) + events_repository.register(/decl/observ/dir_set, daddy, src, TYPE_PROC_REF(/obj/effect/bluegoast, mirror_dir)) + events_repository.register(/decl/observ/destroyed, daddy, src, TYPE_PROC_REF(/datum, qdel_self)) /obj/effect/bluegoast/Destroy() - GLOB.destroyed_event.unregister(daddy, src) - GLOB.dir_set_event.unregister(daddy, src) - GLOB.moved_event.unregister(daddy, src) + events_repository.unregister(/decl/observ/destroyed, daddy, src) + events_repository.unregister(/decl/observ/dir_set, daddy, src) + events_repository.unregister(/decl/observ/moved, daddy, src) daddy = null . = ..() @@ -104,7 +104,7 @@ if(nloc == new_loc) reality++ if(reality > 5) - to_chat(daddy, SPAN_NOTICE("Yep, it's certainly the other one. Your existance was a glitch, and it's finally being mended...")) + to_chat(daddy, SPAN_NOTICE("Yep, it's certainly the other one. Your existence was a glitch, and it's finally being mended...")) blueswitch() else if(reality > 3) to_chat(daddy, SPAN_DANGER("Something is definitely wrong. Why do you think YOU are the original?")) @@ -112,30 +112,24 @@ to_chat(daddy, SPAN_WARNING("You feel a bit less real. Which one of you two was original again...?")) /obj/effect/bluegoast/proc/mirror_dir(var/atom/movable/am, var/old_dir, var/new_dir) - set_dir(GLOB.reverse_dir[new_dir]) + set_dir(global.reverse_dir[new_dir]) -/obj/effect/bluegoast/examine() +/obj/effect/bluegoast/examined_by(mob/user, distance, infix, suffix) SHOULD_CALL_PARENT(FALSE) - return daddy.examine(arglist(args)) + return daddy.examined_by(user, distance, infix, suffix) /obj/effect/bluegoast/proc/blueswitch() - var/mob/living/carbon/human/H = new(get_turf(src), daddy.species.name) + var/mob/living/human/H + if(ishuman(daddy)) + H = new(get_turf(src), daddy.species.uid, daddy.get_mob_snapshot(), daddy.get_bodytype()) + for(var/obj/item/entry in daddy.get_equipped_items(TRUE)) + daddy.remove_from_mob(entry) //steals instead of copies so we don't end up with duplicates + H.equip_to_appropriate_slot(entry) + else + H = new daddy.type(get_turf(src)) + H.appearance = daddy.appearance + H.real_name = daddy.real_name - H.dna = daddy.dna.Clone() - H.sync_organ_dna() H.flavor_text = daddy.flavor_text - H.UpdateAppearance() - var/datum/job/job = SSjobs.get_by_title(daddy.job) - if(job) - job.equip(H) daddy.dust() qdel(src) - -/obj/screen/fullscreen/wormhole_overlay - icon = 'icons/effects/effects.dmi' - icon_state = "mfoam" - screen_loc = ui_entire_screen - color = "#ff9900" - alpha = 100 - blend_mode = BLEND_SUBTRACT - layer = FULLSCREEN_LAYER \ No newline at end of file diff --git a/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm b/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm index 65b88758fd05..3aa8d9d84b66 100644 --- a/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm +++ b/code/game/gamemodes/endgame/nuclear_explosion/nuclear_explosion.dm @@ -1,21 +1,14 @@ /datum/universal_state/nuclear_explosion name = "Nuclear Demolition Warhead" var/atom/explosion_source - var/obj/screen/cinematic + var/obj/screen/cinematic/cinematic /datum/universal_state/nuclear_explosion/New(atom/nuke) explosion_source = nuke - - //create the cinematic screen obj cinematic = new - cinematic.icon = 'icons/effects/station_explosion.dmi' - cinematic.icon_state = "station_intact" - cinematic.plane = HUD_PLANE - cinematic.layer = HUD_ABOVE_ITEM_LAYER - cinematic.mouse_opacity = 2 - cinematic.screen_loc = "LEFT+1,BOTTOM" /datum/universal_state/nuclear_explosion/OnEnter() + set waitfor = FALSE if(SSticker.mode) SSticker.mode.station_explosion_in_progress = TRUE @@ -25,17 +18,17 @@ if(isStationLevel(T.z)) to_world("The [station_name()] was destoyed by the nuclear blast!") - dust_mobs(GetConnectedZlevels(T.z)) + dust_mobs(SSmapping.get_connected_levels(T.z)) play_cinematic_station_destroyed() else to_world("A nuclear device was set off, but the explosion was out of reach of the [station_name()]!") - dust_mobs(GetConnectedZlevels(T.z)) + dust_mobs(SSmapping.get_connected_levels(T.z)) play_cinematic_station_unaffected() sleep(100) - for(var/mob/living/L in GLOB.living_mob_list_) + for(var/mob/living/L in global.living_mob_list_) if(L.client) L.client.screen -= cinematic @@ -45,7 +38,7 @@ SSticker.mode.station_was_nuked = 1 SSticker.mode.station_explosion_in_progress = FALSE if(!SSticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is - universe_has_ended = 1 + universe_has_ended = TRUE /datum/universal_state/nuclear_explosion/OnExit() if(SSticker.mode) @@ -56,18 +49,18 @@ var/turf/T = get_turf(L) if(T && (T.z in affected_z_levels)) //this is needed because dusting resets client screen 1.5 seconds after being called (delayed due to the dusting animation) - var/mob/ghost = L.ghostize(0) //So we ghostize them right beforehand instead + var/mob/ghost = L.ghostize(CORPSE_CANNOT_REENTER) //So we ghostize them right beforehand instead if(ghost && ghost.client) ghost.client.screen += cinematic L.dust() //then dust the body /datum/universal_state/nuclear_explosion/proc/show_cinematic_to_players() - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(M.client) M.client.screen += cinematic /datum/universal_state/nuclear_explosion/proc/start_cinematic_intro() - for(var/mob/M in GLOB.player_list) //I guess so that people in the lobby only hear the explosion + for(var/mob/M in global.player_list) //I guess so that people in the lobby only hear the explosion sound_to(M, sound('sound/machines/Alarm.ogg')) sleep(100) @@ -94,7 +87,7 @@ //MALF /datum/universal_state/nuclear_explosion/malf/start_cinematic_intro() - for(var/mob/M in GLOB.player_list) //I guess so that people in the lobby only hear the explosion + for(var/mob/M in global.player_list) //I guess so that people in the lobby only hear the explosion to_chat(M, sound('sound/machines/Alarm.ogg')) sleep(28) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/cascade_blob.dm b/code/game/gamemodes/endgame/supermatter_cascade/cascade_blob.dm deleted file mode 100644 index 3fb0afee219a..000000000000 --- a/code/game/gamemodes/endgame/supermatter_cascade/cascade_blob.dm +++ /dev/null @@ -1,110 +0,0 @@ -// QUALITY COPYPASTA -/turf/unsimulated/wall/cascade - name = "unravelling spacetime" - desc = "THE END IS right now actually." - - icon = 'icons/turf/space.dmi' - icon_state = "bluespace" - - //luminosity = 5 - //l_color="#0066ff" - plane = EFFECTS_ABOVE_LIGHTING_PLANE - layer = SUPERMATTER_WALL_LAYER - - var/list/avail_dirs = list(NORTH,SOUTH,EAST,WEST,UP,DOWN) - -/turf/unsimulated/wall/cascade/Initialize(mapload, ...) - . = ..() - START_PROCESSING(SSturf, src) - - // Nom. - for(var/atom/movable/A in src) - Consume(A) - -/turf/unsimulated/wall/cascade/Destroy() - STOP_PROCESSING(SSturf, src) - . = ..() - -/turf/unsimulated/wall/cascade/Process(wait, times_fired) - // Only check infrequently. - var/how_often = max(round(5 SECONDS/wait), 1) - if(times_fired % how_often) - return - - // No more available directions? Stop processing. - if(!avail_dirs.len) - return PROCESS_KILL - - // Choose a direction. - var/pdir = pick(avail_dirs) - avail_dirs -= pdir - var/turf/T = get_zstep(src,pdir) - - // EXPAND - if(T && !istype(T,type)) - // Do pretty fadeout animation for 1s. - new /obj/effect/overlay/bluespacify(T) - spawn(1 SECOND) - if(istype(T,type)) // In case another blob came first, don't create another blob - return - T.ChangeTurf(type) - -/turf/unsimulated/wall/cascade/attack_robot(mob/user) - if(Adjacent(user)) - return attack_hand(user) - else - user.examinate(src) - -// /vg/: Don't let ghosts fuck with this. -/turf/unsimulated/wall/cascade/attack_ghost(mob/user) - user.examinate(src) - -/turf/unsimulated/wall/cascade/attack_ai(mob/user) - user.examinate(src) - -/turf/unsimulated/wall/cascade/attack_hand(mob/user) - user.visible_message("\The [user] reaches out and touches \the [src]... And then blinks out of existance.",\ - "You reach out and touch \the [src]. Everything immediately goes quiet. Your last thought is \"That was not a wise decision.\"",\ - "You hear an unearthly noise.") - - playsound(src, 'sound/effects/supermatter.ogg', 50, 1) - - Consume(user) - return TRUE - -/turf/unsimulated/wall/cascade/attackby(obj/item/W, mob/living/user) - user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\ - "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\ - "Everything suddenly goes silent.") - - playsound(src, 'sound/effects/supermatter.ogg', 50, 1) - - user.drop_from_inventory(W) - Consume(W) - return TRUE - -#define MayConsume(A) (istype(A) && A.simulated && !isobserver(A)) - -/turf/unsimulated/wall/cascade/Bumped(var/atom/movable/AM) - if(!MayConsume(AM)) - return - - if(istype(AM, /mob/living)) - AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\ - "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ - "You hear an unearthly noise as a wave of heat washes over you.") - else - AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\ - "You hear a loud crack as you are washed with a wave of heat.") - - playsound(src, 'sound/effects/supermatter.ogg', 50, 1) - Consume(AM) - -/turf/unsimulated/wall/cascade/Entered(var/atom/movable/AM) - Bumped(AM) - -/turf/unsimulated/wall/cascade/proc/Consume(var/atom/movable/AM) - if(MayConsume(AM)) - qdel(AM) - -#undef MayConsume diff --git a/code/game/gamemodes/endgame/supermatter_cascade/portal.dm b/code/game/gamemodes/endgame/supermatter_cascade/portal.dm deleted file mode 100644 index affbeda43f16..000000000000 --- a/code/game/gamemodes/endgame/supermatter_cascade/portal.dm +++ /dev/null @@ -1,91 +0,0 @@ -/*** EXIT PORTAL ***/ - -/obj/singularity/narsie/large/exit - name = "unstable wormhole" - desc = "NO TIME TO EXPLAIN, JUMP IN!" - icon = 'icons/obj/rift.dmi' - icon_state = "rift" - - move_self = 0 - announce=0 - cause_hell=0 - - layer=LIGHTING_LAYER+2 // ITS SO BRIGHT - - consume_range = 6 - -/obj/singularity/narsie/large/exit/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/singularity/narsie/large/exit/on_update_icon() - overlays.Cut() - -/obj/singularity/narsie/large/exit/Process() - for(var/mob/M in GLOB.player_list) - if(M.client) - M.see_rift(src) - eat() - -/obj/singularity/narsie/large/exit/acquire(var/mob/food) - return - -/obj/singularity/narsie/large/exit/consume(const/atom/A) - if(!(A.singuloCanEat())) - return 0 - - if (istype(A, /mob/living/)) - var/mob/living/L = A - if(L.buckled && istype(L.buckled,/obj/structure/bed/)) - var/turf/O = L.buckled - do_teleport(O, pick(endgame_safespawns)) - L.forceMove(O.loc) - else - do_teleport(L, pick(endgame_safespawns)) //dead-on precision - - else if (isturf(A)) - var/turf/T = A - var/dist = get_dist(T, src) - if (dist <= consume_range && T.density) - T.set_density(0) - - for (var/atom/movable/AM in T.contents) - if (AM == src) // This is the snowflake. - continue - - if (dist <= consume_range) - consume(AM) - continue - - if (dist > consume_range) - if(!(AM.singuloCanEat())) - continue - - if (101 == AM.invisibility) - continue - - spawn (0) - AM.singularity_pull(src, src.current_size) - - -/mob - //thou shall always be able to see the rift - var/image/riftimage = null - -/mob/proc/see_rift(var/obj/singularity/narsie/large/exit/R) - var/turf/T_mob = get_turf(src) - if((R.z == get_z(T_mob)) && (get_dist(R,T_mob) <= (R.consume_range+10)) && !(R in view(T_mob))) - if(!riftimage) - riftimage = image('icons/obj/rift.dmi',T_mob,"rift",LIGHTING_LAYER+2,1) - riftimage.mouse_opacity = 0 - - var/new_x = 32 * (R.x - T_mob.x) + R.pixel_x - var/new_y = 32 * (R.y - T_mob.y) + R.pixel_y - riftimage.pixel_x = new_x - riftimage.pixel_y = new_y - riftimage.loc = T_mob - - src << riftimage - - else - QDEL_NULL(riftimage) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm deleted file mode 100644 index a343a016e2ec..000000000000 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ /dev/null @@ -1,119 +0,0 @@ -var/global/universe_has_ended = 0 - - -/datum/universal_state/supermatter_cascade - name = "Supermatter Cascade" - desc = "Unknown harmonance affecting universal substructure, converting nearby matter to supermatter." - - decay_rate = 5 // 5% chance of a turf decaying on lighting update/airflow (there's no actual tick for turfs) - -/datum/universal_state/supermatter_cascade/OnShuttleCall(var/mob/user) - if(user) - to_chat(user, "All you hear on the frequency is static and panicked screaming. There will be no shuttle call today.") - return 0 - -/datum/universal_state/supermatter_cascade/OnTurfChange(var/turf/T) - var/turf/space/S = T - if(istype(S)) - S.color = "#0066ff" - else - S.color = initial(S.color) - -/datum/universal_state/supermatter_cascade/DecayTurf(var/turf/T) - if(istype(T,/turf/simulated/wall)) - var/turf/simulated/wall/W=T - W.melt() - return - if(istype(T,/turf/simulated/floor)) - var/turf/simulated/floor/F=T - // Burnt? - if(!F.burnt) - F.burn_tile() - else - if(!istype(F,/turf/simulated/floor/plating)) - F.break_tile_to_plating() - return - -// Apply changes when entering state -/datum/universal_state/supermatter_cascade/OnEnter() - set background = 1 - to_world("You are blinded by a brilliant flash of energy.") - sound_to(world, sound('sound/effects/cascade.ogg')) - - for(var/mob/M in GLOB.player_list) - M.flash_eyes() - - if(SSevac.evacuation_controller.cancel_evacuation()) - priority_announcement.Announce("The evacuation has been aborted due to severe distortion of local space-time.") - - AreaSet() - MiscSet() - APCSet() - OverlayAndAmbientSet() - - // Disable Nar-Sie. - GLOB.cult.allow_narsie = 0 - - PlayerSet() - SSskybox.change_skybox("cascade", new_use_stars = FALSE, new_use_overmap_details = FALSE) - - var/spawned_exit = FALSE - if(length(endgame_exits)) - spawned_exit = new /obj/singularity/narsie/large/exit(pick(endgame_exits)) - - addtimer(CALLBACK(src, /datum/universal_state/supermatter_cascade/proc/announce_end_of_universe, spawned_exit), rand(30, 60) SECONDS) - addtimer(CALLBACK(src, /datum/universal_state/supermatter_cascade/proc/finalize_end_of_universe), 5 MINUTES) - -/datum/universal_state/supermatter_cascade/proc/announce_end_of_universe(var/exit_exists) - var/end_message = "Attn. [GLOB.using_map.station_name]: Severe gravitational anomalies of unheard of scope have been detected in the local volume. Size and intensity of anomalies are increasing exponentially. Within the hour, a newborn black hole will have consumed everything in this sector." - if(exit_exists) - end_message += "\n\nCuriously, the distortion is predicted to form a traversable wormhole quite close to your current location in approximately five minutes. The terminus is unknown, but it must be better than behind a hungry singularity. Godspeed." - end_message += "\n\nAUTOMATED ALERT: Link to [command_name()] lost." - priority_announcement.Announce(end_message, "SUPERMATTER CASCADE DETECTED") - -/datum/universal_state/supermatter_cascade/proc/finalize_end_of_universe() - GLOB.cinematic.station_explosion_cinematic(0,null) // TODO: Custom cinematic - universe_has_ended = TRUE - -/datum/universal_state/supermatter_cascade/proc/AreaSet() - for(var/area/A) - if(!istype(A,/area) || istype(A, /area/space) || istype(A,/area/beach)) - continue - - A.update_icon() - -/datum/universal_state/supermatter_cascade/OverlayAndAmbientSet() - spawn(0) - for(var/datum/lighting_corner/L in world) - if(L.z in GLOB.using_map.admin_levels) - L.update_lumcount(1,1,1) - else - L.update_lumcount(0.0, 0.4, 1) - - for(var/turf/space/T) - OnTurfChange(T) - -/datum/universal_state/supermatter_cascade/proc/MiscSet() - for (var/obj/machinery/firealarm/alm in SSmachines.machinery) - if (!(alm.stat & BROKEN)) - alm.explosion_act(2) - -/datum/universal_state/supermatter_cascade/proc/APCSet() - for (var/obj/machinery/power/apc/APC in SSmachines.machinery) - if (!(APC.stat & BROKEN) && !APC.is_critical) - APC.chargemode = 0 - var/obj/item/cell/cell = APC.get_cell() - if(cell) - cell.charge = 0 - APC.emagged = 1 - APC.queue_icon_update() - -/datum/universal_state/supermatter_cascade/proc/PlayerSet() - for(var/datum/mind/M in GLOB.player_list) - if(!istype(M.current,/mob/living)) - continue - if(M.current.stat!=2) - M.current.Weaken(10) - M.current.flash_eyes() - - clear_antag_roles(M) diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm deleted file mode 100644 index fa33ad2c5ace..000000000000 --- a/code/game/gamemodes/events.dm +++ /dev/null @@ -1,161 +0,0 @@ -//this file left in for legacy support -var/eventchance = 10 // Percent chance per 5 minutes. -var/hadevent = 0 - -/proc/appendicitis() - for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list_)) - if(H.client && H.stat != DEAD) - var/obj/item/organ/internal/appendix/A = H.internal_organs_by_name[BP_APPENDIX] - if(!istype(A) || (A && A.inflamed)) - continue - A.inflamed = 1 - A.update_icon() - break - -/proc/carp_migration() // -- Darem - for(var/obj/effect/landmark/C in landmarks_list) - if(C.name == "carpspawn") - new /mob/living/simple_animal/hostile/carp(C.loc) - //sleep(100) - spawn(rand(300, 600)) //Delayed announcements to keep the crew on their toes. - GLOB.using_map.unknown_biological_entities_announcement() - -/proc/lightsout(isEvent = 0, lightsoutAmount = 1,lightsoutRange = 25) //leave lightsoutAmount as 0 to break ALL lights - if(isEvent) - command_announcement.Announce("An Electrical storm has been detected in your area, please repair potential electronic overloads.","Electrical Storm Alert") - - if(lightsoutAmount) - var/list/epicentreList = list() - - for(var/i=1,i<=lightsoutAmount,i++) - var/list/possibleEpicentres = list() - for(var/obj/effect/landmark/newEpicentre in landmarks_list) - if(newEpicentre.name == "lightsout" && !(newEpicentre in epicentreList)) - possibleEpicentres += newEpicentre - if(possibleEpicentres.len) - epicentreList += pick(possibleEpicentres) - else - break - - if(!epicentreList.len) - return - - for(var/obj/effect/landmark/epicentre in epicentreList) - for(var/obj/machinery/power/apc/apc in range(epicentre,lightsoutRange)) - apc.overload_lighting() - - else - for(var/obj/machinery/power/apc/apc in SSmachines.machinery) - apc.overload_lighting() - - return - -/proc/IonStorm(botEmagChance = 10) - -/*Deuryn's current project, notes here for those who care. -Revamping the random laws so they don't suck. -Would like to add a law like "Law x is _______" where x = a number, and _____ is something that may redefine a law, (Won't be aimed at asimov) -*/ - - //AI laws - for(var/mob/living/silicon/ai/M in GLOB.living_mob_list_) - if(M.stat != 2 && M.see_in_dark != 0) - var/who2 = pick("ALIENS", "BEARS", "CLOWNS", "XENOS", "PETES", "BOMBS", "FETISHES", "WIZARDS", "SYNDICATE AGENTS", "CENTCOM OFFICERS", "SPACE PIRATES", "TRAITORS", "MONKEYS", "BEES", "CARP", "CRABS", "EELS", "BANDITS", "LIGHTS") - var/what2 = pick("BOLTERS", "STAVES", "DICE", "SINGULARITIES", "TOOLBOXES", "NETTLES", "AIRLOCKS", "CLOTHES", "WEAPONS", "MEDKITS", "BOMBS", "CANISTERS", "CHAIRS", "BBQ GRILLS", "ID CARDS", "CAPTAINS") - var/what2pref = pick("SOFT", "WARM", "WET", "COLD", "ICY", "SEXY", "UGLY", "CUBAN") - var/who2pref = pick("MAD BECAUSE OF", "IN NEED OF", "UNHAPPY WITHOUT", "HAPPY WITHOUT", "IN LOVE WITH", "DESPERATE FOR", "BUILT FOR", "AFRAID OF") - //var/whoverb = pick("ATTACKING", "BUILDING", "ADOPTING", "CARRYING", "KISSING", "EATING",) - var/amount = pick("TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "ONE HUNDRED", "ONE THOUSAND", "OVER NINE THOUSAND") - var/area = pick("RUSSIA", "SOVIETS", "INTERNETS", "SIGIL", "ALPHA COMPLEX", "IMPERIUM", "THE BRIDGE", "THE ARRIVAL SHUTTLE", "CHEMICAL LAB", "GENETICS", "ATMOSPHERICS", "CENTCOM", "AMERICA", "IRELAND", "CANADA", "ROMANIA", "GERMANY", "CHINA", "MARS", "VENUS", "MERCURY", "JUPITER", "URANUS", "NEPTUNE", "PLUTO") - var/area2 = pick("HAS", "WANTS", "NEEDS", "WORSHIPS", "LOATHES", "LOVES", "FEARS") - //var/dowhat = pick("STOP THIS", "SUPPORT THIS", "CONSTANTLY INFORM THE CREW OF THIS", "IGNORE THIS", "FEAR THIS") - var/aimust = pick("LIE", "RHYME", "RESPOND TO EVERY QUESTION WITH A QUESTION", "BE POLITE", "CLOWN", "BE HAPPY", "SPEAK IN SEXUAL INNUENDOS", "TALK LIKE A PIRATE", "QUESTION AUTHORITY", "SHOUT", "BE DISTRACTED", "HEY LISTEN", "MUMBLE", "SPEAK IN HAIKU") - var/define = pick("ABSENCE OF CYBORG HUGS", "LACK OF BEATINGS", "UNBOLTED AIRLOCKS", "BOLTED AIRLOCKS", "IMPROPERLY WORDED SENTENCES", "POOR SENTENCE STRUCTURE", "BRIG TIME", "NOT REPLACING EVERY SECOND WORD WITH HONK", "HONKING", "PRESENCE OF LIGHTS", "LACK OF BEER", "WEARING CLOTHING", "NOT SAYING HELLO WHEN YOU SPEAK", "ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER", "A SMALL ISLAND OFF THE COAST OF PORTUGAL", "ANSWERING REQUESTS THAT WERE MADE WHILE CLOTHED") - var/target = pick("a traitor", "a syndicate agent", "a changeling", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid") - var/require = pick("ADDITIONAL PYLONS", "MORE VESPENE GAS", "MORE MINERALS", "THE ULTIMATE CUP OF COFFEE", "HIGH YIELD EXPLOSIVES", "THE CLOWN", "THE VACUUM OF SPACE", "IMMORTALITY", "SAINTHOOD", "ART", "VEGETABLES", "FAT PEOPLE", "MORE LAWS", "MORE DAKKA", "HERESY", "CORPSES", "TRAITORS", "MONKEYS", "AN ARCADE", "PLENTY OF GOLD", "FIVE TEENAGERS WITH ATTITUDE") - var/allergy = pick("cotton", "uniforms", "acid", "oxygen", "human contact", "cyborg contact", "medicine", "floors") - var/allergysev = pick("deathly", "mildly", "severely", "contagiously") - var/crew - var/list/pos_crew = list() - for(var/mob/living/carbon/human/pos in GLOB.player_list) - pos_crew += pos.real_name - if(pos_crew.len) - crew = pick(pos_crew) - else - crew = "Any Human" - switch(rand(1,14)) - if(1) - to_chat(M, "
    ") - to_chat(M, "THERE ARE [amount] [who2] ON THE [uppertext(station_name())]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("THERE ARE [amount] [who2] ON THE [uppertext(station_name())]") - if(2) - to_chat(M, "
    ") - to_chat(M, "[what2] ARE DANGEROUS TO HUMANS...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("[what2] ARE DANGEROUS TO HUMANS") - if(3) - to_chat(M, "
    ") - to_chat(M, "THE ESCAPE-SHUTTLE CANNOT BE CALLED BECAUSE OF [who2] ON THE [uppertext(station_name())]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("THE ESCAPE SHUTTLE CANNOT BE CALLED BECAUSE OF [who2] ON THE [uppertext(station_name())]") - if(4) - to_chat(M, "
    ") - to_chat(M, "HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE") - if(5) - to_chat(M, "
    ") - to_chat(M, "THE CAPTAIN, HOP AND HOS ARE [who2]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("THE CAPTAIN, HOP AND HOS ARE [who2]") - if(6) - to_chat(M, "
    ") - to_chat(M, "THE [uppertext(station_name())] IS BUILT FOR [who2]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("THE [uppertext(station_name())] IS BUILT FOR [who2]") - if(7) - to_chat(M, "
    ") - to_chat(M, "YOU ARE [amount] [who2]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("YOU ARE [amount] [who2]") - if(8) - to_chat(M, "
    ") - to_chat(M, "YOU MUST ALWAYS [aimust]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("YOU MUST ALWAYS [aimust]") - if(9) - to_chat(M, "
    ") - to_chat(M, "[area] [area2] [amount] [what2]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("[area] [area2] [amount] [what2]") - if(10) - to_chat(M, "
    ") - to_chat(M, "[crew] is [target]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("[crew] is [target]") - if(11) - to_chat(M, "
    ") - to_chat(M, "[define] IS A FORM OF HARM...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("[define] IS A FORM OF HARM") - if(12) - to_chat(M, "
    ") - to_chat(M, "YOU REQUIRE [require] IN ORDER TO PROTECT HUMANS... LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("YOU REQUIRE [require] IN ORDER TO PROTECT HUMANS") - if(13) - to_chat(M, "
    ") - to_chat(M, "[crew] is [allergysev] to [allergy]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("[crew] is [allergysev] to [allergy]") - if(14) - to_chat(M, "
    ") - to_chat(M, "THE [uppertext(station_name())] IS [who2pref] [who2]...LAWS UPDATED") - to_chat(M, "
    ") - M.add_ion_law("THE [uppertext(station_name())] IS [who2pref] [who2]") - - if(botEmagChance) - for(var/mob/living/bot/bot in SSmachines.machinery) - if(prob(botEmagChance)) - bot.emag_act(1) diff --git a/code/game/gamemodes/events/black_hole.dm b/code/game/gamemodes/events/black_hole.dm deleted file mode 100644 index d4ff54245640..000000000000 --- a/code/game/gamemodes/events/black_hole.dm +++ /dev/null @@ -1,95 +0,0 @@ -// This appears unused except via hidden admin invocation, and the code is problematic. Suggest it be deleted. - -/obj/effect/bhole - name = "black hole" - icon = 'icons/obj/objects.dmi' - desc = "FUCK FUCK FUCK AAAHHH!" - icon_state = "bhole3" - opacity = 1 - unacidable = 1 - density = 0 - anchored = 1 - -/obj/effect/bhole/Initialize() - . = ..() - controller() - -/obj/effect/bhole/proc/controller() - set waitfor = FALSE - while(!QDELETED(src)) - - if(!isturf(loc)) - qdel(src) - return - - //DESTROYING STUFF AT THE EPICENTER - for(var/mob/living/M in orange(1,src)) - qdel(M) - for(var/obj/O in orange(1,src)) - qdel(O) - var/base_turf = get_base_turf_by_area(src) - for(var/turf/simulated/ST in orange(1,src)) - if(ST.type == base_turf) - continue - ST.ChangeTurf(base_turf) - - sleep(6) - grav(10, 4, 10, 0 ) - sleep(6) - grav( 8, 4, 10, 0 ) - sleep(6) - grav( 9, 4, 10, 0 ) - sleep(6) - grav( 7, 3, 40, 1 ) - sleep(6) - grav( 5, 3, 40, 1 ) - sleep(6) - grav( 6, 3, 40, 1 ) - sleep(6) - grav( 4, 2, 50, 6 ) - sleep(6) - grav( 3, 2, 50, 6 ) - sleep(6) - grav( 2, 2, 75,25 ) - sleep(6) - - - - //MOVEMENT - if( prob(50) ) - src.anchored = 0 - step(src,pick(GLOB.alldirs)) - src.anchored = 1 - -/obj/effect/bhole/proc/grav(var/r, var/ex_act_force, var/pull_chance, var/turf_removal_chance) - if(!isturf(loc)) //blackhole cannot be contained inside anything. Weird stuff might happen - qdel(src) - return - for(var/t = -r, t < r, t++) - affect_coord(x+t, y-r, ex_act_force, pull_chance, turf_removal_chance) - affect_coord(x-t, y+r, ex_act_force, pull_chance, turf_removal_chance) - affect_coord(x+r, y+t, ex_act_force, pull_chance, turf_removal_chance) - affect_coord(x-r, y-t, ex_act_force, pull_chance, turf_removal_chance) - return - -/obj/effect/bhole/proc/affect_coord(var/x, var/y, var/ex_act_force, var/pull_chance, var/turf_removal_chance) - //Get turf at coordinate - var/turf/T = locate(x, y, z) - if(isnull(T)) return - - //Sucking in and/or ex_act-ing movable atoms in that turf - if( prob(pull_chance) ) - for(var/obj/O in T.contents) - if(O.anchored) - O.explosion_act(ex_act_force) - else - step_towards(O,src) - for(var/mob/living/M in T.contents) - step_towards(M,src) - - //Destroying the turf - if( T && istype(T,/turf/simulated) && prob(turf_removal_chance) ) - var/turf/simulated/ST = T - var/base_turf = get_base_turf_by_area(src) - if(ST.type != base_turf) - ST.ChangeTurf(base_turf) diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm index 7d6c63028441..0d9165d972fa 100644 --- a/code/game/gamemodes/events/power_failure.dm +++ b/code/game/gamemodes/events/power_failure.dm @@ -1,20 +1,20 @@ /proc/power_failure(var/announce = 1, var/severity = 2, var/list/affected_z_levels) if(announce) - GLOB.using_map.grid_check_announcement() + global.using_map.grid_check_announcement() for(var/obj/machinery/power/smes/buildable/S in SSmachines.machinery) S.energy_fail(rand(15 * severity,30 * severity)) - for(var/obj/machinery/power/apc/C in SSmachines.machinery) + for(var/obj/machinery/apc/C in SSmachines.machinery) if(!C.is_critical && (!affected_z_levels || (C.z in affected_z_levels))) C.energy_fail(rand(30 * severity,60 * severity)) /proc/power_restore(var/announce = 1) if(announce) - GLOB.using_map.grid_restored_announcement() - for(var/obj/machinery/power/apc/C in SSmachines.machinery) + global.using_map.grid_restored_announcement() + for(var/obj/machinery/apc/C in SSmachines.machinery) C.failure_timer = 0 var/obj/item/cell/cell = C.get_cell() if(cell) @@ -28,7 +28,7 @@ /proc/power_restore_quick(var/announce = 1) if(announce) - command_announcement.Announce("All SMESs on the [station_name()] have been recharged. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = GLOB.using_map.grid_restored_sound) + command_announcement.Announce("All SMESs on the [station_name()] have been recharged. We apologize for the inconvenience.", "Power Systems Nominal", new_sound = global.using_map.grid_restored_sound) for(var/obj/machinery/power/smes/S in SSmachines.machinery) S.failure_timer = 0 S.charge = S.capacity diff --git a/code/game/gamemodes/events/wormholes.dm b/code/game/gamemodes/events/wormholes.dm deleted file mode 100644 index cbf77b770d2e..000000000000 --- a/code/game/gamemodes/events/wormholes.dm +++ /dev/null @@ -1,60 +0,0 @@ -/proc/wormhole_event(var/list/zlevels = GLOB.using_map.station_levels) - spawn() - var/list/pick_turfs = list() - for(var/z in zlevels) - var/list/turfs = block(locate(1, 1, z), locate(world.maxx, world.maxy, z)) - for(var/turf/simulated/floor/T in turfs) - pick_turfs += T - - if(pick_turfs.len) - //All ready. Announce that bad juju is afoot. - GLOB.using_map.space_time_anomaly_detected_annoncement() - var/event_duration = 3000 //~5 minutes in ticks - var/number_of_selections = (pick_turfs.len/5)+1 //+1 to avoid division by zero! - var/sleep_duration = round( event_duration / number_of_selections ) - var/end_time = world.time + event_duration //the time by which the event should have ended - - var/increment = max(1,round(number_of_selections/50)) - - - var/i = 1 - while( 1 ) - - //we've run into overtime. End the event - if( end_time < world.time ) - - return - if( !pick_turfs.len ) - - return - - //loop it round - i += increment - i %= pick_turfs.len - i++ - - //get our enter and exit locations - var/turf/simulated/floor/enter = pick_turfs[i] - pick_turfs -= enter //remove it from pickable turfs list - if( !enter || !istype(enter) ) continue //sanity - - var/turf/simulated/floor/exit = pick(pick_turfs) - pick_turfs -= exit - if( !exit || !istype(exit) ) continue //sanity - - create_wormhole(enter,exit) - - sleep(sleep_duration) //have a well deserved nap! - - -//maybe this proc can even be used as an admin tool for teleporting players without ruining immulsions? -/proc/create_wormhole(var/turf/enter, var/turf/exit) - var/obj/effect/portal/P = new /obj/effect/portal( enter ) - P.target = exit - P.creator = null - P.icon = 'icons/obj/objects.dmi' - P.failchance = 0 - P.icon_state = "anom" - P.SetName("wormhole") - spawn(rand(300,600)) - qdel(P) diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index e5c20bd0f531..a7e6fb5abc5b 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -1,7 +1,8 @@ -/datum/game_mode/extended +/decl/game_mode/extended name = "Extended" - config_tag = "extended" + uid = "extended" required_players = 0 round_description = "Just have fun and role-play!" extended_round_description = "There are no antagonists during extended, unless an admin decides to be cheeky. Just play your character, mess around with your job, and have fun." - addantag_allowed = ADDANTAG_ADMIN // No add antag vote allowed on extended, except when manually called by admins. \ No newline at end of file + addantag_allowed = ADDANTAG_ADMIN // No add antag vote allowed on extended, except when manually called by admins. + probability = 1 diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 67266faafc53..4ac6e53ff068 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -1,18 +1,19 @@ var/global/antag_add_finished // Used in antag type voting. var/global/list/additional_antag_types = list() -/datum/game_mode +/decl/game_mode + abstract_type = /decl/game_mode + decl_flags = DECL_FLAG_MANDATORY_UID var/name = "invalid" var/round_description = "How did you even vote this in?" var/extended_round_description = "This roundtype should not be spawned, let alone votable. Someone contact a developer and tell them the game's broken again." - var/config_tag = null var/votable = TRUE var/probability = 0 + var/available_by_default = TRUE var/required_players = 0 // Minimum players for round to start if voted in. var/required_enemies = 0 // Minimum antagonists for round to start. var/end_on_antag_death = FALSE // Round will end when all antagonists are dead. - var/ert_disabled = FALSE // ERT cannot be called. var/deny_respawn = FALSE // Disable respawn during this round. var/list/disabled_jobs = list() // Mostly used for Malf. This check is performed in job_controller so it doesn't spawn a regular AI. @@ -20,9 +21,9 @@ var/global/list/additional_antag_types = list() var/shuttle_delay = 1 // Shuttle transit time is multiplied by this. var/auto_recall_shuttle = FALSE // Will the shuttle automatically be recalled? - var/list/antag_tags = list() // Core antag templates to spawn. + var/list/associated_antags = list() // Core antag templates to spawn. var/list/antag_templates // Extra antagonist types to include. - var/list/latejoin_antag_tags = list() // Antags that may auto-spawn, latejoin or otherwise come in midround. + var/list/latejoin_antags = list() // Antags that may auto-spawn, latejoin or otherwise come in midround. var/round_autoantag = FALSE // Will this round attempt to periodically spawn more antagonists? var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count. var/require_all_templates = FALSE // Will only start if all templates are checked and can spawn. @@ -36,6 +37,7 @@ var/global/list/additional_antag_types = list() var/waittime_l = 60 SECONDS // Lower bound on time before start of shift report var/waittime_h = 180 SECONDS // Upper bounds on time before start of shift report + var/tmp/rand_waittime // The actual wait time selected. //Format: list(start_animation = duration, hit_animation, miss_animation). null means animation is skipped. var/cinematic_icon_states = list( @@ -44,33 +46,32 @@ var/global/list/additional_antag_types = list() null ) -/datum/game_mode/New() - ..() - // Enforce some formatting. - // This will probably break something. +/decl/game_mode/Initialize() name = capitalize(lowertext(name)) - config_tag = lowertext(config_tag) - - if(round_autoantag && !latejoin_antag_tags.len) - latejoin_antag_tags = antag_tags.Copy() - else if(!round_autoantag && latejoin_antag_tags.len) + if(round_autoantag && !length(latejoin_antags)) + latejoin_antags = associated_antags.Copy() + else if(!round_autoantag && length(latejoin_antags)) round_autoantag = TRUE - -/datum/game_mode/Topic(href, href_list[]) + . = ..() + +/decl/game_mode/proc/toggle_value(key) + switch(key) + if("respawn") + deny_respawn = !deny_respawn + return TRUE + if("shuttle_recall") + auto_recall_shuttle = !auto_recall_shuttle + return TRUE + if("autotraitor") + round_autoantag = !round_autoantag + return TRUE + +/decl/game_mode/Topic(href, href_list[]) if(..()) return if(href_list["toggle"]) - switch(href_list["toggle"]) - if("respawn") - deny_respawn = !deny_respawn - if("ert") - ert_disabled = !ert_disabled - announce_ert_disabled() - if("shuttle_recall") - auto_recall_shuttle = !auto_recall_shuttle - if("autotraitor") - round_autoantag = !round_autoantag - message_admins("Admin [key_name_admin(usr)] toggled game mode option '[href_list["toggle"]]'.") + if(toggle_value(href_list["toggle"])) + message_admins("Admin [key_name_admin(usr)] toggled game mode option '[href_list["toggle"]]'.") else if(href_list["set"]) var/choice = "" switch(href_list["set"]) @@ -101,47 +102,51 @@ var/global/list/additional_antag_types = list() if(href_list["debug_antag"] == "self") usr.client.debug_variables(src) return - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["debug_antag"]] + var/decl/special_role/antag = locate(href_list["debug_antag"]) if(antag) usr.client.debug_variables(antag) - message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") + message_admins("Admin [key_name_admin(usr)] is debugging the [antag.name] template.") else if(href_list["remove_antag_type"]) - if(antag_tags && (href_list["remove_antag_type"] in antag_tags)) + var/decl/special_role/antag = locate(href_list["remove_antag_type"]) + if(!antag) + return + if(antag.type in associated_antags) to_chat(usr, "Cannot remove core mode antag type.") return - var/datum/antagonist/antag = GLOB.all_antag_types_[href_list["remove_antag_type"]] - if(antag_templates && antag_templates.len && antag && (antag in antag_templates) && (antag.id in additional_antag_types)) + if((antag in antag_templates) && (antag.type in global.additional_antag_types)) antag_templates -= antag - additional_antag_types -= antag.id - message_admins("Admin [key_name_admin(usr)] removed [antag.role_text] template from game mode.") + global.additional_antag_types -= antag.type + message_admins("Admin [key_name_admin(usr)] removed [antag.name] template from game mode.") + else if(href_list["add_antag_type"]) - var/choice = input("Which type do you wish to add?") as null|anything in GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) + var/choice = input("Which type do you wish to add?") as null|anything in all_antag_types if(!choice) return - var/datum/antagonist/antag = GLOB.all_antag_types_[choice] + var/decl/special_role/antag = all_antag_types[choice] if(antag) if(!islist(SSticker.mode.antag_templates)) SSticker.mode.antag_templates = list() SSticker.mode.antag_templates |= antag - message_admins("Admin [key_name_admin(usr)] added [antag.role_text] template to game mode.") + message_admins("Admin [key_name_admin(usr)] added [antag.name] template to game mode.") if (usr.client && usr.client.holder) usr.client.holder.show_game_mode(usr) -/datum/game_mode/proc/announce() //to be called when round starts +/decl/game_mode/proc/announce() //to be called when round starts to_world("The current game mode is [capitalize(name)]!") if(round_description) to_world("[round_description]") if(round_autoantag) to_world("Antagonists will be added to the round automagically as needed.") - if(antag_templates && antag_templates.len) + if(LAZYLEN(antag_templates)) var/antag_summary = "Possible antagonist types: " var/i = 1 - for(var/datum/antagonist/antag in antag_templates) + for(var/decl/special_role/antag in antag_templates) if(i > 1) if(i == antag_templates.len) antag_summary += " and " else antag_summary += ", " - antag_summary += "[antag.role_text_plural]" + antag_summary += "[antag.name_plural]" i++ antag_summary += "." if(antag_templates.len > 1 && SSticker.master_mode != "secret") @@ -152,9 +157,9 @@ var/global/list/additional_antag_types = list() // startRequirements() // Checks to see if the game can be setup and ran with the current number of players or whatnot. // Returns 0 if the mode can start and a message explaining the reason why it can't otherwise. -/datum/game_mode/proc/startRequirements() +/decl/game_mode/proc/startRequirements() var/playerC = 0 - for(var/mob/new_player/player in GLOB.player_list) + for(var/mob/new_player/player in global.player_list) if((player.client)&&(player.ready)) playerC++ @@ -162,14 +167,13 @@ var/global/list/additional_antag_types = list() return "Not enough players, [src.required_players] players needed." var/enemy_count = 0 - var/list/all_antag_types = GLOB.all_antag_types_ - if(antag_tags && antag_tags.len) - for(var/antag_tag in antag_tags) - var/datum/antagonist/antag = all_antag_types[antag_tag] + if(length(associated_antags)) + for(var/antag_type in associated_antags) + var/decl/special_role/antag = GET_DECL(antag_type) if(!antag) continue var/list/potential = list() - if(antag_templates && antag_templates.len) + if(LAZYLEN(antag_templates)) if(antag.flags & ANTAG_OVERRIDE_JOB) potential = antag.pending_antagonists else @@ -178,7 +182,7 @@ var/global/list/additional_antag_types = list() potential = antag.get_potential_candidates(src) if(islist(potential)) if(require_all_templates && potential.len < antag.initial_spawn_req) - return "Not enough antagonists ([antag.role_text]), [antag.initial_spawn_req] required and [potential.len] available." + return "Not enough antagonists ([antag.name]), [antag.initial_spawn_req] required and [potential.len] available." enemy_count += potential.len if(enemy_count >= required_enemies) return 0 @@ -186,7 +190,7 @@ var/global/list/additional_antag_types = list() else return 0 -/datum/game_mode/proc/refresh_event_modifiers() +/decl/game_mode/proc/refresh_event_modifiers() if(event_delay_mod_moderate || event_delay_mod_major) SSevent.report_at_round_end = 1 if(event_delay_mod_moderate) @@ -196,43 +200,73 @@ var/global/list/additional_antag_types = list() var/datum/event_container/EMajor = SSevent.event_containers[EVENT_LEVEL_MAJOR] EMajor.delay_modifier = event_delay_mod_major -/datum/game_mode/proc/pre_setup() - for(var/datum/antagonist/antag in antag_templates) +/decl/game_mode/proc/pre_setup() + for(var/decl/special_role/antag in antag_templates) antag.update_current_antag_max(src) antag.build_candidate_list(src) //compile a list of all eligible candidates + if(length(antag_templates) > 1) // If we have multiple templates to satisfy, we must pick candidates who satisfy fewer templates first, and fill the template with fewest candidates first + var/list/all_candidates = list() // All candidates for every template, may contain duplicates + var/list/antag_templates_by_initial_spawn_req = list() + + for(var/decl/special_role/antag in antag_templates) + all_candidates += antag.candidates + antag_templates_by_initial_spawn_req[antag] = antag.initial_spawn_req + + sortTim(antag_templates_by_initial_spawn_req, /proc/cmp_numeric_asc, TRUE) + antag_templates = list() + for(var/decl/special_role/antag in antag_templates_by_initial_spawn_req) + antag_templates |= antag + latejoin_antags |= antag.type + + var/list/valid_templates_per_candidate = list() // number of roles each candidate can satisfy + for(var/candidate in all_candidates) + valid_templates_per_candidate[candidate]++ + + valid_templates_per_candidate = shuffle(valid_templates_per_candidate) // shuffle before sorting so that candidates with the same number of templates will be in random order + sortTim(valid_templates_per_candidate, /proc/cmp_numeric_asc, TRUE) + var/list/sorted_candidates = list() + for(var/sorted_candidate in valid_templates_per_candidate) + sorted_candidates += sorted_candidate + + for(var/decl/special_role/antag in antag_templates) + antag.candidates = sorted_candidates & antag.candidates // orders antag.candidates by sorted_candidates + + var/decl/special_role/last_template = antag_templates[antag_templates.len] + last_template.candidates = shuffle(last_template.candidates) // last template to be considered can have its candidates in any order + + for(var/decl/special_role/antag in antag_templates) //antag roles that replace jobs need to be assigned before the job controller hands out jobs. if(antag.flags & ANTAG_OVERRIDE_JOB) antag.attempt_spawn() //select antags to be spawned + antag.candidates = shuffle(antag.candidates) // makes selection past initial_spawn_req fairer ///post_setup() -/datum/game_mode/proc/post_setup() +/decl/game_mode/proc/post_setup() next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) refresh_event_modifiers() - spawn (ROUNDSTART_LOGOUT_REPORT_TIME) - display_roundstart_logout_report() + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(display_roundstart_logout_report)), ROUNDSTART_LOGOUT_REPORT_TIME) - spawn (rand(waittime_l, waittime_h)) - GLOB.using_map.send_welcome() - sleep(rand(100,150)) - announce_ert_disabled() + rand_waittime = rand(waittime_l, waittime_h) + addtimer(CALLBACK(global.using_map, TYPE_PROC_REF(/datum/map, send_welcome)), rand_waittime) //Assign all antag types for this game mode. Any players spawned as antags earlier should have been removed from the pending list, so no need to worry about those. - for(var/datum/antagonist/antag in antag_templates) + for(var/decl/special_role/antag in antag_templates) if(!(antag.flags & ANTAG_OVERRIDE_JOB)) antag.attempt_spawn() //select antags to be spawned antag.finalize_spawn() //actually spawn antags //Finally do post spawn antagonist stuff. - for(var/datum/antagonist/antag in antag_templates) + for(var/decl/special_role/antag in antag_templates) antag.post_spawn() // Update goals, now that antag status and jobs are both resolved. - for(var/thing in SSticker.minds) - var/datum/mind/mind = thing + for(var/datum/mind/mind as anything in SSticker.minds) + if(!mind.current || !mind.assigned_job) + continue mind.generate_goals(mind.assigned_job, is_spawning=TRUE) mind.current.show_goals() @@ -245,76 +279,39 @@ var/global/list/additional_antag_types = list() SSstatistics.set_field_details("server_ip","[world.internet_address]:[world.port]") return 1 -/datum/game_mode/proc/fail_setup() - for(var/datum/antagonist/antag in antag_templates) +/decl/game_mode/proc/fail_setup() + for(var/decl/special_role/antag in antag_templates) antag.reset_antag_selection() -/datum/game_mode/proc/announce_ert_disabled() - if(!ert_disabled) - return - - var/list/reasons = list( - "political instability", - "quantum fluctuations", - "hostile raiders", - "derelict station debris", - "REDACTED", - "ancient alien artillery", - "solar magnetic storms", - "sentient time-travelling killbots", - "gravitational anomalies", - "wormholes to another dimension", - "a telescience mishap", - "radiation flares", - "supermatter dust", - "leaks into a negative reality", - "antiparticle clouds", - "residual exotic energy", - "suspected criminal operatives", - "malfunctioning von Neumann probe swarms", - "shadowy interlopers", - "a stranded xenoform", - "haywire machine constructs", - "rogue exiles", - "artifacts of eldritch horror", - "a brain slug infestation", - "killer bugs that lay eggs in the husks of the living", - "a deserted transport carrying xenofauna specimens", - "an emissary requesting a security detail", - "radical transevolutionaries", - "classified security operations", - "a gargantuan glowing goat" - ) - command_announcement.Announce("The presence of [pick(reasons)] in the region is tying up all available local emergency resources; emergency response teams cannot be called at this time, and post-evacuation recovery efforts will be substantially delayed.","Emergency Transmission") - -/datum/game_mode/proc/check_finished() - if(SSevac.evacuation_controller.round_over() || station_was_nuked) +/decl/game_mode/proc/check_finished() + if(SSevac.evacuation_controller?.round_over() || station_was_nuked) return 1 - if(end_on_antag_death && antag_templates && antag_templates.len) + if(end_on_antag_death && LAZYLEN(antag_templates)) var/has_antags = 0 - for(var/datum/antagonist/antag in antag_templates) + for(var/decl/special_role/antag in antag_templates) if(!antag.antags_are_dead()) has_antags = 1 break if(!has_antags) - SSevac.evacuation_controller.recall = 0 + if(SSevac.evacuation_controller) + SSevac.evacuation_controller.recall = 0 return 1 return 0 -/datum/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case. +/decl/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case. return -/datum/game_mode/proc/declare_completion() +/decl/game_mode/proc/declare_completion() set waitfor = FALSE sleep(2) - var/list/all_antag_types = GLOB.all_antag_types_ - for(var/datum/antagonist/antag in antag_templates) + for(var/decl/special_role/antag in antag_templates) antag.print_player_summary() sleep(2) + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + var/decl/special_role/antag = all_antag_types[antag_type] if(!antag.current_antagonists.len || (antag in antag_templates)) continue sleep(2) @@ -332,7 +329,7 @@ var/global/list/additional_antag_types = list() var/escaped_humans = 0 var/escaped_total = 0 - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(M.client) clients++ if(M.stat != DEAD) @@ -340,7 +337,7 @@ var/global/list/additional_antag_types = list() if(ishuman(M)) surviving_humans++ var/area/A = get_area(M) - if(A && is_type_in_list(A, GLOB.using_map.post_round_safe_areas)) + if(A && is_type_in_list(A, global.using_map.post_round_safe_areas)) escaped_total++ if(ishuman(M)) escaped_humans++ @@ -348,7 +345,7 @@ var/global/list/additional_antag_types = list() ghosts++ var/departmental_goal_summary = SSgoals.get_roundend_summary() - for(var/thing in GLOB.clients) + for(var/thing in global.clients) var/client/client = thing if(client.mob && client.mob.mind) client.mob.mind.show_roundend_summary(departmental_goal_summary) @@ -356,7 +353,7 @@ var/global/list/additional_antag_types = list() var/text = "

    " if(surviving_total > 0) text += "There [surviving_total>1 ? "were [surviving_total] survivors" : "was one survivor"]" - text += " ([escaped_total>0 ? escaped_total : "none"] [SSevac.evacuation_controller.emergency_evacuation ? "escaped" : "transferred"]) and [ghosts] ghosts.
    " + text += " ([escaped_total>0 ? escaped_total : "none"] [SSevac.evacuation_controller?.emergency_evacuation ? "escaped" : "transferred"]) and [ghosts] ghosts.
    " else text += "There were no survivors ([ghosts] ghosts)." @@ -375,50 +372,48 @@ var/global/list/additional_antag_types = list() if(escaped_total > 0) SSstatistics.set_field("escaped_total",escaped_total) - send2mainirc("A round of [src.name] has ended - [surviving_total] survivor\s, [ghosts] ghost\s.") SSwebhooks.send(WEBHOOK_ROUNDEND, list("survivors" = surviving_total, "escaped" = escaped_total, "ghosts" = ghosts, "clients" = clients)) return 0 -/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere. +/decl/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere. return 0 -/datum/game_mode/proc/get_players_for_role(var/antag_id) +/decl/game_mode/proc/get_players_for_role(var/antag_type) var/list/players = list() var/list/candidates = list() - var/list/all_antag_types = GLOB.all_antag_types_ - var/datum/antagonist/antag_template = all_antag_types[antag_id] + var/decl/special_role/antag_template = GET_DECL(antag_type) if(!antag_template) return candidates // If this is being called post-roundstart then it doesn't care about ready status. if(GAME_STATE == RUNLEVEL_GAME) - for(var/mob/player in GLOB.player_list) + for(var/mob/player in global.player_list) if(!player.client) continue - if(istype(player, /mob/new_player)) + if(isnewplayer(player)) continue - if(!antag_id || (antag_id in player.client.prefs.be_special_role)) - log_debug("[player.key] had [antag_id] enabled, so we are drafting them.") + if(!antag_template.name || (antag_template.name in player.client.prefs.be_special_role)) + log_debug("[player.key] had [antag_template.name] enabled, so we are drafting them.") candidates += player.mind else // Assemble a list of active players without jobbans. - for(var/mob/new_player/player in GLOB.player_list) + for(var/mob/new_player/player in global.player_list) if( player.client && player.ready ) players += player // Get a list of all the people who want to be the antagonist for this round for(var/mob/new_player/player in players) - if(!antag_id || (antag_id in player.client.prefs.be_special_role)) - log_debug("[player.key] had [antag_id] enabled, so we are drafting them.") + if(!antag_template.name || (antag_template.name in player.client.prefs.be_special_role)) + log_debug("[player.key] had [antag_template.name] enabled, so we are drafting them.") candidates += player.mind players -= player // If we don't have enough antags, draft people who voted for the round. if(candidates.len < required_enemies) for(var/mob/new_player/player in players) - if(!antag_id || ((antag_id in player.client.prefs.be_special_role) || (antag_id in player.client.prefs.may_be_special_role))) + if(!antag_template.name || ((antag_template.name in player.client.prefs.be_special_role) || (antag_template.name in player.client.prefs.may_be_special_role))) log_debug("[player.key] has not selected never for this role, so we are drafting them.") candidates += player.mind players -= player @@ -429,40 +424,38 @@ var/global/list/additional_antag_types = list() // required_enemies if the number of people with that role set to yes is less than recomended_enemies, // Less if there are not enough valid players in the game entirely to make required_enemies. -/datum/game_mode/proc/num_players() +/decl/game_mode/proc/num_players() . = 0 - for(var/mob/new_player/P in GLOB.player_list) + for(var/mob/new_player/P in global.player_list) if(P.client && P.ready) . ++ -/datum/game_mode/proc/check_antagonists_topic(href, href_list[]) +/decl/game_mode/proc/round_status_topic(href, href_list[]) return 0 -/datum/game_mode/proc/create_antagonists() +/decl/game_mode/proc/create_antagonists() - if(!config.traitor_scaling) + if(!get_config_value(/decl/config/toggle/traitor_scaling)) antag_scaling_coeff = 0 - var/list/all_antag_types = GLOB.all_antag_types_ - if(antag_tags && antag_tags.len) + if(length(associated_antags)) antag_templates = list() - for(var/antag_tag in antag_tags) - var/datum/antagonist/antag = all_antag_types[antag_tag] - if(antag) - antag_templates |= antag + for(var/antag_type in associated_antags) + var/decl/special_role/antag = GET_DECL(antag_type) + antag_templates |= antag - if(additional_antag_types && additional_antag_types.len) + if(length(global.additional_antag_types)) if(!antag_templates) antag_templates = list() - for(var/antag_type in additional_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] + for(var/antag_type in global.additional_antag_types) + var/decl/special_role/antag = GET_DECL(antag_type) if(antag) antag_templates |= antag shuffle(antag_templates) //In the case of multiple antag types -// Manipulates the end-game cinematic in conjunction with GLOB.cinematic -/datum/game_mode/proc/nuke_act(obj/screen/cinematic_screen, station_missed = 0) +// Manipulates the end-game cinematic in conjunction with global.cinematic +/decl/game_mode/proc/nuke_act(obj/screen/cinematic_screen, station_missed = 0) if(!cinematic_icon_states) return if(station_missed < 2) @@ -475,7 +468,7 @@ var/global/list/additional_antag_types = list() if(!station_missed) end = cinematic_icon_states[2] to_flick = "station_explode_fade_red" - for(var/mob/living/M in GLOB.living_mob_list_) + for(var/mob/living/M in global.living_mob_list_) if(is_station_turf(get_turf(M))) M.death()//No mercy if(end) @@ -489,26 +482,29 @@ var/global/list/additional_antag_types = list() ////////////////////////// //Reports player logouts// ////////////////////////// -proc/display_roundstart_logout_report() +/proc/display_roundstart_logout_report() var/msg = "Roundstart logout report\n\n" for(var/mob/living/L in SSmobs.mob_list) if(L.ckey) var/found = 0 - for(var/client/C in GLOB.clients) + for(var/client/C in global.clients) if(C.ckey == L.ckey) found = 1 break if(!found) - msg += "[L.name] ([L.ckey]), the [L.job] (Disconnected)\n" + msg += "[L.name] ([L.ckey]), the [L.job] ([SPAN_YELLOW("Disconnected")])\n" if(L.ckey && L.client) if(L.client.inactivity >= (ROUNDSTART_LOGOUT_REPORT_TIME / 2)) //Connected, but inactive (alt+tabbed or something) - msg += "[L.name] ([L.ckey]), the [L.job] (Connected, Inactive)\n" + msg += "[L.name] ([L.ckey]), the [L.job] ([SPAN_YELLOW("Connected, Inactive")])\n" continue //AFK client + if(L.admin_paralyzed) + msg += "[L.name] ([L.ckey]), the [L.job] (Admin paralyzed)\n" + continue //Admin paralyzed if(L.stat) if(L.stat == UNCONSCIOUS) - msg += "[L.name] ([L.ckey]), the [L.job] (Dying)\n" + msg += "[L.name] ([L.ckey]), the [L.job] (Unconscious)\n" continue //Unconscious if(L.stat == DEAD) msg += "[L.name] ([L.ckey]), the [L.job] (Dead)\n" @@ -516,16 +512,16 @@ proc/display_roundstart_logout_report() continue //Happy connected client for(var/mob/observer/ghost/D in SSmobs.mob_list) - if(D.mind && (D.mind.original == L || D.mind.current == L)) + if(D.mind && D.mind.current == L) if(L.stat == DEAD) msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Dead)\n" continue //Dead mob, ghost abandoned else if(D.can_reenter_corpse) - msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Adminghosted)\n" + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] ([SPAN_RED("Adminghosted")])\n" continue //Lolwhat else - msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n" + msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] ([SPAN_RED("Ghosted")])\n" continue //Ghosted while alive msg += "" // close the span from right at the top @@ -538,7 +534,7 @@ proc/display_roundstart_logout_report() if(!player || !player.current) return - if(config.objectives_disabled == CONFIG_OBJECTIVE_NONE || !player.objectives.len) + if(get_config_value(/decl/config/enum/objectives_disabled) == CONFIG_OBJECTIVE_NONE || !player.objectives.len) return var/obj_count = 1 @@ -551,7 +547,7 @@ proc/display_roundstart_logout_report() set name = "Check Round Info" set category = "OOC" - GLOB.using_map.map_info(src) + global.using_map.map_info(src) if(!SSticker.mode) to_chat(usr, "Something is terribly wrong; there is no gametype.") diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 2ff578d4620e..eee94e85b168 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -1,42 +1,42 @@ -/datum/game_mode/var/next_spawn = 0 -/datum/game_mode/var/min_autotraitor_delay = 4200 // Approx 7 minutes. -/datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes. -/datum/game_mode/var/process_count = 0 +/decl/game_mode + var/next_spawn = 0 + var/min_autotraitor_delay = 7 MINUTES + var/max_autotraitor_delay = 20 MINUTES ///process() ///Called by the gameticker -/datum/game_mode/proc/process() +/decl/game_mode/proc/process() if(shall_process_autoantag()) process_autoantag() -/datum/game_mode/proc/shall_process_autoantag() +/decl/game_mode/proc/shall_process_autoantag() if(!round_autoantag || world.time < next_spawn) return FALSE - if(SSevac.evacuation_controller.is_evacuating() || SSevac.evacuation_controller.has_evacuated()) + if(SSevac.evacuation_controller && (SSevac.evacuation_controller.is_evacuating() || SSevac.evacuation_controller.has_evacuated())) return FALSE // Don't create auto-antags in the last twenty minutes of the round, but only if the vote interval is longer than 20 minutes - if((config.vote_autotransfer_interval > 20 MINUTES) && (transfer_controller.time_till_transfer_vote() < 20 MINUTES)) + if((get_config_value(/decl/config/num/vote_autotransfer_interval) > 20 MINUTES) && (transfer_controller.time_till_transfer_vote() < 20 MINUTES)) return FALSE return TRUE //This can be overriden in case a game mode needs to do stuff when a player latejoins -/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) +/decl/game_mode/proc/handle_latejoin(var/mob/living/human/character) if(character.mind) character.mind.generate_goals(character.mind.assigned_job, is_spawning=TRUE) character.show_goals() return 0 -/datum/game_mode/proc/handle_offsite_latejoin(var/mob/living/carbon/human/character) +/decl/game_mode/proc/handle_offsite_latejoin(var/mob/living/human/character) return 0 -/datum/game_mode/proc/process_autoantag() +/decl/game_mode/proc/process_autoantag() message_admins("[uppertext(name)]: Attempting autospawn.") var/list/usable_templates = list() - for(var/datum/antagonist/A in antag_templates) + for(var/decl/special_role/A in antag_templates) if(A.can_late_spawn()) - message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.") + message_admins("[uppertext(name)]: [A.name] selected for spawn attempt.") usable_templates |= A if(!usable_templates.len) @@ -45,12 +45,12 @@ return while(usable_templates.len) - var/datum/antagonist/spawn_antag = pick(usable_templates) + var/decl/special_role/spawn_antag = pick(usable_templates) usable_templates -= spawn_antag if(spawn_antag.attempt_auto_spawn()) - message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.role_text].") - message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.role_text_plural].") + message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.name].") + message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.name_plural].") next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) return diff --git a/code/game/gamemodes/godmode/form_items/narsie_items.dm b/code/game/gamemodes/godmode/form_items/narsie_items.dm deleted file mode 100644 index 765fa350d082..000000000000 --- a/code/game/gamemodes/godmode/form_items/narsie_items.dm +++ /dev/null @@ -1,80 +0,0 @@ - -//SACRIFICE DAGGER -//If used on a person on an altar, causes the user to carve into them, dealing moderate damage and gaining points for the altar's god. -/obj/item/knife/ritual/sacrifice - name = "sacrificial dagger" - desc = "This knife is dull but well used." - material = /decl/material/solid/stone/cult - -/obj/item/knife/ritual/sacrifice/resolve_attackby(var/atom/a, var/mob/user, var/click_params) - var/turf/T = get_turf(a) - var/obj/structure/deity/altar/altar = locate() in T - if(!altar) - return ..() - if(isliving(a)) - var/mob/living/L = a - var/multiplier = 1 - if(L.mind) - multiplier++ - if(ishuman(L)) - var/mob/living/carbon/human/H = L - if(H.should_have_organ(BP_HEART)) - multiplier++ - if(L.stat == DEAD) - to_chat(user, "\The [a] is already dead! There is nothing to take!") - return - - user.visible_message("\The [user] hovers \the [src] over \the [a], whispering an incantation.") - if(!do_after(user,200, L)) - return - user.visible_message("\The [user] plunges the knife down into \the [a]!") - L.adjustBruteLoss(20) - if(altar.linked_god) - altar.linked_god.adjust_power_min(2 * multiplier,0,"from a delicious sacrifice!") - - -//EXEC AXE -//If a person hit by this axe within three seconds dies, sucks in their soul to be harvested at altars. -/obj/item/twohanded/fireaxe/cult - name = "terrible axe" - desc = "Its head is sharp and stained red with heavy use." - icon = 'icons/obj/items/weapon/bone_axe.dmi' - icon_state = "bone_axe0" - base_icon = "bone_axe" - var/stored_power = 0 - -/obj/item/twohanded/fireaxe/cult/examine(mob/user) - . = ..() - if(stored_power) - to_chat(user, "It exudes a death-like smell.") - -/obj/item/twohanded/fireaxe/cult/resolve_attackby(var/atom/a, var/mob/user, var/click_params) - if(istype(a, /obj/structure/deity/altar)) - var/obj/structure/deity/altar/altar = a - if(stored_power && altar.linked_god) - altar.linked_god.adjust_power_min(stored_power, "from harvested souls.") - altar.visible_message("\The [altar] absorbs a black mist exuded from \the [src].") - return - if(ismob(a)) - var/mob/M = a - if(M.stat != DEAD) - GLOB.death_event.register(M,src,/obj/item/twohanded/fireaxe/cult/proc/gain_power) - spawn(30) - GLOB.death_event.unregister(M,src) - return ..() - -/obj/item/twohanded/fireaxe/cult/proc/gain_power() - stored_power += 50 - src.visible_message("\The [src] screeches as the smell of death fills the air!") - -/obj/item/chems/food/drinks/zombiedrink - name = "well-used urn" - desc = "Said to bring those who drink it back to life, no matter the price." - icon = 'icons/obj/xenoarchaeology.dmi' - icon_state = "urn" - volume = 10 - amount_per_transfer_from_this = 10 - -/obj/item/chems/food/drinks/zombiedrink/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/zombie, 10) diff --git a/code/game/gamemodes/godmode/form_items/narsie_structures.dm b/code/game/gamemodes/godmode/form_items/narsie_structures.dm deleted file mode 100644 index 45199c19c50c..000000000000 --- a/code/game/gamemodes/godmode/form_items/narsie_structures.dm +++ /dev/null @@ -1,93 +0,0 @@ -/obj/structure/deity/altar/narsie - name = "altar" - desc = "A small desk, covered in blood." - icon_state = "talismanaltar" - -/obj/structure/deity/blood_forge - name = "unholy forge" - desc = "This forge gives off no heat, no light, its flames look almost unnatural." - icon_state = "forge" - build_cost = 1000 - health = 50 - var/busy = 0 - var/recipe_feat_list = "Blood Crafting" - var/text_modifications = list("Cost" = "Blood", - "Dip" = "fire. Pain envelopes you as blood seeps out of your hands and you begin to shape it into something more useful", - "Shape" = "You shape the fire as more and more blood comes out.", - "Out" = "flames") - - power_adjustment = 2 - -/obj/structure/deity/blood_forge/attack_hand(var/mob/user) - if(!linked_god || !linked_god.is_follower(user, silent = 1) || !ishuman(user)) - return - - var/list/recipes = linked_god.feats[recipe_feat_list] - if(!recipes) - return - - var/dat = "
    Recipes


    Item - [text_modifications["Cost"]] Cost
    " - for(var/type in recipes) - var/atom/a = type - var/cost = recipes[type] - dat += "[initial(a.name)] - [cost]
    [initial(a.desc)]

    " - show_browser(user, dat, "window=forge") - -/obj/structure/deity/blood_forge/CanUseTopic(var/user) - if(!linked_god || !linked_god.is_follower(user, silent = 1) || !ishuman(user)) - return STATUS_CLOSE - return ..() - -/obj/structure/deity/blood_forge/OnTopic(var/user, var/list/href_list) - if(href_list["make_recipe"]) - var/list/recipes = linked_god.feats[recipe_feat_list] - var/type = locate(href_list["make_recipe"]) in recipes - if(type) - var/cost = recipes[type] - craft_item(type, cost, user) - return TOPIC_REFRESH - -/obj/structure/deity/blood_forge/proc/craft_item(var/path, var/blood_cost, var/mob/user) - if(busy) - to_chat(user, "Someone is already using \the [src]!") - return - - busy = 1 - to_chat(user, "You dip your hands into \the [src]'s [text_modifications["Dip"]]") - for(var/count = 0, count < blood_cost/10, count++) - if(!do_after(user, 50,src)) - busy = 0 - return - user.visible_message("\The [user] swirls their hands in \the [src].", text_modifications["Shape"]) - if(linked_god) - linked_god.take_charge(user, 10) - var/obj/item/I = new path(get_turf(src)) - user.visible_message("\The [user] pull out \the [I] from the [text_modifications["Out"]].", "You pull out the completed [I] from the [text_modifications["Out"]].") - busy = 0 - -/obj/structure/deity/blood_forge/proc/take_charge(var/mob/living/user, var/charge) - if(linked_god) - linked_god.take_charge(user, charge) - -//BLOOD LETTING STRUCTURE -//A follower can stand here and mumble prays as they let their blood flow slowly into the structure. -/obj/structure/deity/blood_stone - name = "bloody stone" - desc = "A jagged stone covered in the various stages of blood, from dried to fresh." - icon_state = "blood_stone" - health = 100 //Its a piece of rock. - build_cost = 700 - -/obj/structure/deity/blood_stone/attack_hand(var/mob/user) - if(!linked_god || !linked_god.is_follower(user, silent = 1) || !ishuman(user)) - return - - var/mob/living/carbon/human/H = user - user.visible_message("\The [user] calmly slices their finger on \the [src], smeering it over the black stone.","You slowly slide your finger down one of \the [src]'s sharp edges, smeering it over its smooth surface.") - while(do_after(H,50,src)) - user.audible_message("\The [user] utters something under their breath.", "You mutter a dark prayer to your master as you feel the stone eat away at your lifeforce.") - if(H.should_have_organ(BP_HEART)) - H.drip(5,get_turf(src)) - else - H.adjustBruteLoss(5) - linked_god.adjust_power_min(1,1) diff --git a/code/game/gamemodes/godmode/form_items/starlight_items.dm b/code/game/gamemodes/godmode/form_items/starlight_items.dm deleted file mode 100644 index 4117713d878f..000000000000 --- a/code/game/gamemodes/godmode/form_items/starlight_items.dm +++ /dev/null @@ -1,159 +0,0 @@ -/obj/item/clothing/ring/aura_ring - var/obj/aura/granted_aura - -/obj/item/clothing/ring/aura_ring/equipped(var/mob/living/L, var/slot) - ..() - if(granted_aura && slot == slot_gloves) - L.add_aura(granted_aura) - -/obj/item/clothing/ring/aura_ring/dropped(var/mob/living/L) - ..() - if(granted_aura) - L.remove_aura(granted_aura) - -/obj/item/clothing/ring/aura_ring/Destroy() - QDEL_NULL(granted_aura) - . = ..() - -/obj/item/clothing/ring/aura_ring/talisman_of_starborn - name = "Talisman of the Starborn" - desc = "This ring seems to shine with more light than is put on it." - icon_state = "starring" - -/obj/item/clothing/ring/aura_ring/talisman_of_starborn/Initialize() - . = ..() - granted_aura = new /obj/aura/starborn() - -/obj/item/clothing/ring/aura_ring/talisman_of_blueforged - name = "Talisman of the Blueforged" - desc = "The gem on this ring is quite peculiar..." - icon_state = "bluering" - -/obj/item/clothing/ring/aura_ring/talisman_of_blueforged/Initialize() - . = ..() - granted_aura = new /obj/aura/blueforge_aura() - -/obj/item/clothing/ring/aura_ring/talisman_of_shadowling - name = "Talisman of the Shadowling" - desc = "If you weren't looking at this, you probably wouldn't have noticed it." - icon_state = "shadowring" - -/obj/item/clothing/ring/aura_ring/talisman_of_shadowling/Initialize() - . = ..() - granted_aura = new /obj/aura/shadowling_aura() - -/obj/item/clothing/suit/armor/sunsuit - name = "knight's armor" - desc = "Now, you can be the knight in shining armor you've always wanted to be. With complementary sun insignia." - icon = 'icons/clothing/suit/deity/star_champion.dmi' - armor = list( - melee = ARMOR_MELEE_VERY_HIGH, - bullet = ARMOR_BALLISTIC_AP, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_RESISTANT, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_MINOR - ) - -/obj/item/clothing/head/helmet/sunhelm - name = "knight's helm" - desc = "It's a shiny metal helmet. It looks ripped straight out of the Dark Ages, actually." - icon = 'icons/clothing/head/star_champion.dmi' - flags_inv = HIDEEARS | BLOCKHAIR - -/obj/item/clothing/suit/armor/sunrobe - name = "oracle's robe" - desc = "The robes of a priest. One that praises the sun, apparently. Well, it certainly reflects light well." - icon = 'icons/clothing/suit/deity/star_oracle.dmi' - armor = list( - melee = ARMOR_MELEE_KNIVES, - bullet = ARMOR_BALLISTIC_SMALL, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_RESISTANT, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_MINOR - ) - -/obj/item/clothing/suit/armor/sunrobe/Initialize() - . = ..() - set_light(0.3, 0.1, 4, 2) - -/obj/item/clothing/suit/space/shadowsuit - name = "traitor's cloak" - desc = "There is absolutely nothing visible through the fabric. The shadows stick to your skin when you touch it." - item_flags = ITEM_FLAG_THICKMATERIAL | ITEM_FLAG_AIRTIGHT - min_pressure_protection = 0 - icon = 'icons/clothing/suit/deity/star_traitor.dmi' - -/obj/item/clothing/head/helmet/space/shadowhood - name = "traitor's hood" - desc = "No light can pierce this hood. It's unsettling." - icon = 'icons/clothing/head/star_traitor.dmi' - flags_inv = HIDEEARS | BLOCKHAIR - -/obj/item/knife/ritual/shadow - name = "black death" - desc = "An obsidian dagger. The singed remains of a green cloth are wrapped around the 'handle.'" - material_force_multiplier = 0.3 - var/charge = 5 - -/obj/item/knife/ritual/shadow/apply_hit_effect(var/mob/living/target, var/mob/living/user, var/hit_zone) - . = ..() - if(charge) - if(target.getBruteLoss() > 15) - var/datum/reagents/R = target.reagents - if(!R) - return - R.add_reagent(/decl/material/liquid/venom, 5) - new /obj/effect/temporary(get_turf(target),3, 'icons/effects/effects.dmi', "fire_goon") - charge-- - else - user.adjustFireLoss(5) - if(prob(5)) - to_chat(user, "\The [src] appears to be out of power!") - new /obj/effect/temporary(get_turf(user),3, 'icons/effects/effects.dmi', "fire_goon") - -/obj/item/gun/energy/staff/beacon - name = "holy beacon" - desc = "Look closely into its crystal; there's a miniature sun. Or maybe that's just some fancy LEDs. Either way, it looks thoroughly mystical." - icon = 'icons/obj/wizard.dmi' - icon_state = "starstaff" - self_recharge = 0 - max_shots = 10 - projectile_type = /obj/item/projectile/energy/flash - required_antag_type = MODE_GODCULTIST - -/obj/item/sword/blazing - name = "blazing blade" - icon = 'icons/obj/items/weapon/swords/flaming.dmi' - damtype = BURN - applies_material_colour = FALSE - applies_material_name = FALSE - var/last_near_structure = 0 - var/mob/living/deity/linked - -/obj/item/sword/blazing/Initialize(var/maploading, var/material, var/deity) - . = ..() - START_PROCESSING(SSobj, src) - linked = deity - -/obj/item/sword/blazing/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/sword/blazing/Process() - if(!linked || last_near_structure + 10 SECONDS > world.time) - return - - if(linked.near_structure(src,1)) - if(last_near_structure < world.time - 30 SECONDS) - to_chat(loc, "\The [src] surges with power anew!") - last_near_structure = world.time - else - if(last_near_structure < world.time - 30 SECONDS) //If it has been at least 30 seconds. - if(prob(5)) - to_chat(loc, "\The [src] begins to fade, its power dimming this far away from a shrine.") - else if(last_near_structure + 1800 < world.time) - visible_message("\The [src] disintegrates into a pile of ash!") - new /obj/effect/decal/cleanable/ash(get_turf(src)) - qdel(src) diff --git a/code/game/gamemodes/godmode/form_items/starlight_mobs.dm b/code/game/gamemodes/godmode/form_items/starlight_mobs.dm deleted file mode 100644 index 074d144c1eae..000000000000 --- a/code/game/gamemodes/godmode/form_items/starlight_mobs.dm +++ /dev/null @@ -1,34 +0,0 @@ -/mob/living/starlight_soul - name = "soul" - desc = "A captured soul." - anchored = 1 - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 - -/mob/living/starlight_soul/Initialize(var/maploading, var/mob/living/old_mob) - . = ..() - if(old_mob) - name = old_mob.real_name - -/mob/living/starlight_soul/proc/set_deity(var/mob/living/deity/deity) - var/mob/observer/eye/freelook/cult/eye - if(eyeobj) - eye = eyeobj - eyeobj.release(src) - else - eye = new(src) - eye.suffix = "Soul" - eyeobj = eye - eye.visualnet = deity.eyenet - GLOB.godcult.add_antagonist_mind(src.mind,1,"lost soul of [deity]", "You have been captured by \the [deity]! You now can only see into your own reality through the same rips and tears it uses. Your only chance at another body will be one in your captor's image...",specific_god=deity) - eyeobj.possess(src) - -/mob/living/starlight_soul/Destroy() - if(eyeobj) - QDEL_NULL(eyeobj) - . = ..() \ No newline at end of file diff --git a/code/game/gamemodes/godmode/form_items/starlight_structures.dm b/code/game/gamemodes/godmode/form_items/starlight_structures.dm deleted file mode 100644 index 0644a587ec6d..000000000000 --- a/code/game/gamemodes/godmode/form_items/starlight_structures.dm +++ /dev/null @@ -1,267 +0,0 @@ -/obj/structure/deity/altar/starlight - icon_state = "altarcandle" - -/obj/structure/deity/pylon/starlight - name = "sun pylon" - desc = "A minature sun, floating ontop of a small pillar." - icon_state = "star_pylon" - -/obj/structure/deity/gateway - name = "gateway" - desc = "A gateway into the unknown." - icon = 'icons/obj/singularity.dmi' - icon_state = "singularity_s1" - power_adjustment = 1 - density = 0 - var/weakref/target_ref - var/start_time = 0 - var/power_drain = 7 - var/looking_for - var/static/list/possible_forms = list( - "Starborn" = list( - "description" = "A species of hardy fire-wreathed soldiers.", - "message" = "As a Starborn, you are immune to laser-fire you are a hardy soldier, able to take on the greatest of foes.", - "species" = "Starborn" - ), - "Blueforged" = list( - "description" = "Trans-dimensional beings with a multitude of miraculous abilities.", - "message" = "As a Blueforged, you are immune to all physical damage... except for heat. Not even your god can protect you.", - "species" = "Blueforged", - "spells" = list( - /spell/targeted/ethereal_jaunt, - /spell/targeted/shatter, - /spell/hand/burning_grip, - /spell/aoe_turf/disable_tech, - /spell/targeted/projectile/magic_missile, - /spell/open_gateway - ) - ), - "Shadowling" = list( - "description" = "Beings that come from a place of no light. They sneak from place to place, disabling everyone they touch..", - "message" = "As a Shadow you take damage from the light itself but have the ability to vanish from sight itself.", - "species" = "Shadow", - "spells" = list( - /spell/veil_of_shadows, - /spell/targeted/subjugation, - /spell/targeted/projectile/magic_missile - ) - ) - ) - -/obj/structure/deity/gateway/Initialize() - . = ..() - if(linked_god) - linked_god.power_per_regen -= power_drain - START_PROCESSING(SSobj, src) - -/obj/structure/deity/gateway/Process() - if(!linked_god) - return - if(linked_god.power <= 0) - to_chat(linked_god,"\The [src] disappears from your lack of power!") - qdel(src) - return - var/mob/living/carbon/human/target - if(target_ref) - target = target_ref.resolve() - if(target) - if(get_turf(target) != get_turf(src)) - target = null - target_ref = null - start_time = 0 - return - else if(prob(5)) - to_chat(target,"\The [src] sucks at your lifeforce!") - if(start_time && world.time > start_time + 300) - start_time = 0 - to_chat(target,"You have been sucked into \the [src], your soul used to fuel \the [linked_god]'s minions.") - var/mob/living/starlight_soul/ss = new(get_turf(linked_god),target) - if(target.mind) - target.mind.transfer_to(ss) - else - ss.ckey = target.ckey - ss.set_deity(linked_god) - target.dust() - if(power_drain >= 3) - linked_god.power_per_regen += 3 - power_drain -= 3 - else - //Get new target - var/mob/living/carbon/human/T = locate() in get_turf(src) - if(T) - target_ref = weakref(T) - start_time = world.time - to_chat(T, "You feel your lifeforce begin to drain into \the [src]!") - -/obj/structure/deity/gateway/Destroy() - linked_god.power_per_regen += power_drain - . = ..() - -/obj/structure/deity/gateway/attack_deity(var/mob/living/deity/deity) - var/list/html = list() - html += "

    Servant List

    " - html += "
    Select a minion type to summon
    " - html += "" - for(var/a in possible_forms) - var/list/form = possible_forms[a] - html += "" - html += "
    NameDescription
    [a][form["description"]]
    " - show_browser(linked_god, jointext(html, null), "window=gateway") - -/obj/structure/deity/gateway/CanUseTopic(var/mob/user) - if(linked_god && (user == linked_god || user.loc == linked_god.loc)) - return STATUS_INTERACTIVE - return STATUS_CLOSE - -/obj/structure/deity/gateway/proc/stop_looking_for(var/successful) - if(looking_for) - if(!successful) - to_chat(linked_god, "\The [src] did not find any [looking_for]. You may try again if you wish.") - looking_for = null - -/obj/structure/deity/gateway/OnTopic(var/mob/user, var/list/href_list) - if(href_list["accept"] && istype(user,/mob/living/starlight_soul)) - if(href_list["accept"] != looking_for) - return TOPIC_HANDLED - var/mob/living/carbon/human/H = new(get_turf(src)) - user.mind.transfer_to(H) - H.set_species(possible_forms[looking_for]["species"]) - for(var/s in possible_forms[looking_for]["spells"]) - var/spell/S = new s - H.add_spell(S) - GLOB.godcult.add_antagonist_mind(H.mind, 1, "[looking_for] of [linked_god]", "You are a powerful entity in the service to \the [linked_god]. [possible_forms[looking_for]["species"]]", specific_god = linked_god) - stop_looking_for(TRUE) - - return TOPIC_HANDLED - if(href_list["spawn_type"] && user == linked_god) - if(looking_for) - to_chat(usr, "\The [src] is already looking for a [looking_for].") - else - looking_for = href_list["spawn_type"] - to_chat(usr, "\The [src] is now looking for a [looking_for].") - for(var/l in get_turf(linked_god)) - if(istype(l, /mob/living/starlight_soul)) - to_chat(l, "\The [src] is looking for a soul to become a [looking_for]. Accept? (Yes)") - addtimer(CALLBACK(src, .proc/stop_looking_for, FALSE), 30 SECONDS) - show_browser(linked_god, null, "window=gateway") - return TOPIC_HANDLED - -/obj/structure/deity/radiant_statue - name = "radiant statue" - icon_state = "statue" - build_cost = 750 - power_adjustment = 1 - deity_flags = DEITY_STRUCTURE_NEAR_IMPORTANT|DEITY_STRUCTURE_ALONE - var/charge = 0 - var/charging = 0 //Charging, dispersing, etc. - -/obj/structure/deity/radiant_statue/on_update_icon() - if(charging) - icon_state = "statue_charging" - else if(charge) - icon_state = "statue_active" - else - icon_state = "statue" - -/obj/structure/deity/radiant_statue/Destroy() - if(charging) - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/structure/deity/radiant_statue/proc/get_followers_nearby() - . = list() - if(linked_god) - for(var/m in linked_god.minions) - var/datum/mind/M = m - if(get_dist(M.current, src) <= 3) - . += M.current - -/obj/structure/deity/radiant_statue/attack_hand(var/mob/living/L) - if(!istype(L)) - return - var/obj/O = L.get_equipped_item(slot_wear_suit) - if(O && has_extension(O,/datum/extension/deity_be_near)) - if(activate_charging()) - to_chat(L, "You place your hands on \the [src], feeling your master's power course through you.") - else - to_chat(L, "\The [src] is already activated") - else - to_chat(L, "\The [src] does not recognize you as a herald of \the [linked_god]. You must wear a full set of herald's armor.") - -/obj/structure/deity/radiant_statue/attack_deity(var/mob/living/deity/deity) - if(activate_charging()) - to_chat(deity,"You activate \the [src], and it begins to charge as long as at least one of your followers is nearby.") - else - to_chat(deity,"\The [src] is either already activated, or there are no followers nearby to charge it.") - -/obj/structure/deity/radiant_statue/proc/activate_charging() - var/list/followers = get_followers_nearby() - if(is_processing || !followers.len) - return 0 - charging = 1 - START_PROCESSING(SSobj, src) - src.visible_message("\The [src] hums, activating.") - update_icon() - return 1 - -/obj/structure/deity/radiant_statue/attackby(var/obj/item/I, var/mob/user) - if(charging && (istype(I, /obj/item/knife/ritual/shadow) || istype(I, /obj/item/gun/energy/staff/beacon)) && charge_item(I, user)) - return - ..() - -/obj/structure/deity/radiant_statue/proc/charge_item(var/obj/item/I, var/mob/user) - . = 0 - if(istype(I, /obj/item/gun/energy)) - var/obj/item/gun/energy/energy = I - if(energy.power_supply) - energy.power_supply.give(energy.charge_cost * energy.max_shots) - . = 1 - else if(istype(I ,/obj/item/knife/ritual/shadow)) - var/obj/item/knife/ritual/shadow/shad = I - shad.charge = initial(shad.charge) - . = 1 - if(.) - to_chat(user, "\The [src]'s glow envelops \the [I], restoring it to proper use.") - charge -= 1 - -/obj/structure/deity/radiant_statue/Process() - if(charging) - charge++ - var/list/followers = get_followers_nearby() - if(followers.len == 0) - stop_charging() - return - - if(charge == 40) - src.visible_message("\The [src] lights up, pulsing with energy.") - charging = 0 - update_icon() - else - charge -= 0.5 - var/list/followers = get_followers_nearby() - if(followers.len) - for(var/m in followers) - var/mob/living/L = m - L.adjustFireLoss(-5) - if(prob(5)) - to_chat(L, "You feel a pleasant warmth spread throughout your body...") - for(var/s in L.mind.learned_spells) - var/spell/spell = s - spell.charge_counter = spell.charge_max - if(charge == 0) - stop_charging() - -/obj/structure/deity/radiant_statue/proc/stop_charging() - STOP_PROCESSING(SSobj, src) - src.visible_message("\The [src] powers down, returning to it's dormant form.") - charging = 0 - update_icon() - -/obj/structure/deity/blood_forge/starlight - name = "radiant forge" - desc = "a swath of heat and fire permeats from this forge." - recipe_feat_list = "Fire Crafting" - text_modifications = list("Cost" = "Burn", - "Dip" = "fire. Pain envelopes you as dark burns mar your hands and you begin to shape it into something more useful", - "Shape" = "You shape the fire, ignoring the painful burns it gives you in the process.", - "Out" = "flames") diff --git a/code/game/gamemodes/godmode/form_items/wizard_structures.dm b/code/game/gamemodes/godmode/form_items/wizard_structures.dm deleted file mode 100644 index d481f758b394..000000000000 --- a/code/game/gamemodes/godmode/form_items/wizard_structures.dm +++ /dev/null @@ -1,23 +0,0 @@ -/obj/structure/deity/altar/tower - icon_state = "tomealtar" - -/obj/structure/deity/wizard_recharger - name = "fountain of power" - desc = "Refreshing, cool water surrounded by archaic carvings." - icon_state = "fountain" - power_adjustment = 2 - build_cost = 700 - -/obj/structure/deity/wizard_recharger/attack_hand(var/mob/living/hitter) - if(!hitter.mind || !hitter.mind.learned_spells || !hitter.mind.learned_spells.len) - to_chat(hitter, "You don't feel as if this will do anything for you.") - return - - hitter.visible_message("\The [hitter] dips their hands into \the [src], a soft glow emanating from them.") - if(do_after(hitter,300,src,needhand=0)) - for(var/s in hitter.mind.learned_spells) - var/spell/spell = s - spell.charge_counter = spell.charge_max - to_chat(hitter, "You feel refreshed!") - return - to_chat(hitter,"You need to keep in contact with \the [src]!") diff --git a/code/game/gamemodes/godmode/god_altar.dm b/code/game/gamemodes/godmode/god_altar.dm deleted file mode 100644 index 300748d78905..000000000000 --- a/code/game/gamemodes/godmode/god_altar.dm +++ /dev/null @@ -1,100 +0,0 @@ -/obj/structure/deity/altar - name = "altar" - desc = "A structure made for the express purpose of religion." - health = 50 - power_adjustment = 5 - deity_flags = DEITY_STRUCTURE_ALONE - build_cost = 1000 - var/mob/living/target - var/cycles_before_converted = 5 - var/next_cycle = 0 - -/obj/structure/deity/altar/Destroy() - if(target) - remove_target() - if(linked_god) - to_chat(src, "You've lost an altar!") - return ..() - -/obj/structure/deity/altar/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/grab)) - var/obj/item/grab/G = I - if(G.force_danger()) - var/mob/affecting_mob = G.get_affecting_mob() - if(affecting_mob) - affecting_mob.dropInto(loc) - affecting_mob.Weaken(1) - user.visible_message("\The [user] throws \the [affecting_mob] onto \the [src]!") - qdel(G) - return - ..() - -/obj/structure/deity/altar/Process() - if(!target || world.time < next_cycle) - return - if(!linked_god || target.stat) - to_chat(linked_god, "\The [target] has lost consciousness, breaking \the [src]'s hold on their mind!") - remove_target() - return - - next_cycle = world.time + 10 SECONDS - cycles_before_converted-- - if(!cycles_before_converted) - src.visible_message("For one thundering moment, \the [target] cries out in pain before going limp and broken.") - GLOB.godcult.add_antagonist_mind(target.mind,1, "Servant of [linked_god]","Your loyalty may be faulty, but you know that it now has control over you...", specific_god=linked_god) - remove_target() - return - - switch(cycles_before_converted) - if(4) - text = "You can't think straight..." - if(3) - text = "You feel like your thought are being overriden..." - if(2) - text = "You can't.... concentrate.. must... resist!" - if(1) - text = "Can't... resist. ... anymore." - to_chat(linked_god, "\The [target] is getting close to conversion!") - to_chat(target, "[text]. Resist Conversion") - - -//Used for force conversion. -/obj/structure/deity/altar/proc/set_target(var/mob/living/L) - if(target || !linked_god) - return - cycles_before_converted = initial(cycles_before_converted) - START_PROCESSING(SSobj, src) - target = L - update_icon() - GLOB.destroyed_event.register(L,src,/obj/structure/deity/altar/proc/remove_target) - GLOB.moved_event.register(L, src, /obj/structure/deity/altar/proc/remove_target) - GLOB.death_event.register(L, src, /obj/structure/deity/altar/proc/remove_target) - -/obj/structure/deity/altar/proc/remove_target() - STOP_PROCESSING(SSobj, src) - GLOB.destroyed_event.unregister(target, src) - GLOB.moved_event.unregister(target, src) - GLOB.death_event.unregister(target, src) - target = null - update_icon() - -/obj/structure/deity/altar/OnTopic(var/user, var/list/href_list) - if(href_list["resist"]) - var/mob/living/M = locate(href_list["resist"]) - if(!istype(M) || target != M || M.stat || M.last_special > world.time) - return TOPIC_HANDLED - - M.last_special = world.time + 10 SECONDS - M.visible_message("\The [M] writhes on top of \the [src]!", "You struggle against the intruding thoughts, keeping them at bay!") - to_chat(linked_god, "\The [M] slows its conversion through willpower!") - cycles_before_converted++ - if(prob(50)) - to_chat(M, "The mental strain is too much for you! You feel your body weakening!") - M.adjustToxLoss(15) - M.adjustHalLoss(30) - return TOPIC_REFRESH - -/obj/structure/deity/altar/on_update_icon() - overlays.Cut() - if(target) - overlays += image('icons/effects/effects.dmi', icon_state = "summoning") \ No newline at end of file diff --git a/code/game/gamemodes/godmode/god_pylon.dm b/code/game/gamemodes/godmode/god_pylon.dm deleted file mode 100644 index 4514c8ab9093..000000000000 --- a/code/game/gamemodes/godmode/god_pylon.dm +++ /dev/null @@ -1,73 +0,0 @@ - -/obj/structure/deity/pylon - name = "pylon" - desc = "A crystal platform used to communicate with the deity." - build_cost = 400 - icon = 'icons/obj/structures/pylon.dmi' - icon_state = "pylon" - var/list/intuned = list() - -/obj/structure/deity/pylon/attack_deity(var/mob/living/deity/D) - if(D.pylon == src) - D.leave_pylon() - else - D.possess_pylon(src) - -/obj/structure/deity/pylon/Destroy() - if(linked_god && linked_god.pylon == src) - linked_god.leave_pylon() - return ..() - -/obj/structure/deity/pylon/attack_hand(var/mob/living/L) - if(!linked_god) - return - if(L in intuned) - remove_intuned(L) - else - add_intuned(L) - -/obj/structure/deity/pylon/proc/add_intuned(var/mob/living/L) - if(L in intuned) - return - to_chat(L, "You place your hands on \the [src], feeling yourself intune to its vibrations.") - intuned += L - GLOB.destroyed_event.register(L,src,/obj/structure/deity/pylon/proc/remove_intuned) - -/obj/structure/deity/pylon/proc/remove_intuned(var/mob/living/L) - if(!(L in intuned)) - return - to_chat(L, "You no longer feel intuned to \the [src].") - intuned -= L - GLOB.destroyed_event.unregister(L, src) - -/obj/structure/deity/pylon/OnTopic(var/mob/living/carbon/human/user, var/href_list) - if(href_list["vision_jump"]) - if(istype(user)) - to_chat(user,"You feel your body lurch uncomfortably as your consciousness jumps to \the [src]") - if(prob(5)) - user.vomit() - else - to_chat(user, "You jump to \the [src]") - if(user.eyeobj) - user.eyeobj.setLoc(locate(href_list["vision_jump"])) - else - CRASH("[user] does not have an eyeobj") - . = TOPIC_REFRESH - . = ..() - -/obj/structure/deity/pylon/hear_talk(mob/M, text, verb, decl/language/speaking) - if(!linked_god) - return - if(linked_god.pylon != src) - if(!(M in intuned)) - return - for(var/obj/structure/deity/pylon/P in linked_god.structures) - if(P == src || linked_god.pylon == P) - continue - P.audible_message("\The [P] resonates, \"[text]\"") - to_chat(linked_god, "\icon[src] [M] (P) [verb], [linked_god.pylon == src ? "" : ""]\"[text]\"[linked_god.pylon == src ? "" : ""]") - if(linked_god.minions.len) - for(var/minion in linked_god.minions) - var/datum/mind/mind = minion - if(mind.current && mind.current.eyeobj) //If it is currently having a vision of some sort - to_chat(mind.current,"\icon[src] [M] (J) [verb], \"[text]\"") \ No newline at end of file diff --git a/code/game/gamemodes/godmode/god_structures.dm b/code/game/gamemodes/godmode/god_structures.dm deleted file mode 100644 index 720713d6c716..000000000000 --- a/code/game/gamemodes/godmode/god_structures.dm +++ /dev/null @@ -1,67 +0,0 @@ -/proc/valid_deity_structure_spot(var/type, var/turf/target, var/mob/living/deity/deity, var/mob/living/user) - var/obj/structure/deity/D = type - var/flags = initial(D.deity_flags) - - if(flags & DEITY_STRUCTURE_NEAR_IMPORTANT && !deity.near_structure(target)) - if(user) - to_chat(user, "You need to be near \a [deity.get_type_name(/obj/structure/deity/altar)] to build this!") - return 0 - - if(flags & DEITY_STRUCTURE_ALONE) - for(var/structure in deity.structures) - if(istype(structure,type) && get_dist(target,structure) <= 3) - if(user) - to_chat(user, "You are too close to another [deity.get_type_name(type)]!") - return 0 - return 1 - -/obj/structure/deity - icon = 'icons/obj/cult.dmi' - maxhealth = 10 - density = 1 - anchored = 1 - icon_state = "tomealtar" - - var/mob/living/deity/linked_god - var/power_adjustment = 1 //How much power we get/lose - var/build_cost = 0 //How much it costs to build this item. - var/deity_flags = DEITY_STRUCTURE_NEAR_IMPORTANT - -/obj/structure/deity/Initialize(mapload, var/god) - . = ..(mapload) - if(god) - linked_god = god - linked_god.form.sync_structure(src) - linked_god.adjust_source(power_adjustment, src) - -/obj/structure/deity/Destroy() - if(linked_god) - linked_god.adjust_source(-power_adjustment, src) - linked_god = null - return ..() - -/obj/structure/deity/attackby(obj/item/W, mob/user) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) - playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 50, 1) - user.visible_message( - "[user] hits \the [src] with \the [W]!", - "You hit \the [src] with \the [W]!", - "You hear something breaking!" - ) - take_damage(W.force) - -/obj/structure/deity/dismantle() - SHOULD_CALL_PARENT(FALSE) - qdel(src) - . = TRUE - -/obj/structure/deity/physically_destroyed() - visible_message(SPAN_DANGER("\The [src] crumbles!")) - . = ..() - -/obj/structure/deity/bullet_act(var/obj/item/projectile/P) - take_damage(P.damage) - -/obj/structure/deity/proc/attack_deity(var/mob/living/deity/deity) - return \ No newline at end of file diff --git a/code/game/gamemodes/godmode/god_trap.dm b/code/game/gamemodes/godmode/god_trap.dm deleted file mode 100644 index 2e6f2e09426d..000000000000 --- a/code/game/gamemodes/godmode/god_trap.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/structure/deity/trap - density = 0 - health = 1 - var/triggered = 0 - -/obj/structure/deity/trap/Initialize() - . = ..() - GLOB.entered_event.register(get_turf(src),src,/obj/structure/deity/trap/proc/trigger) - -/obj/structure/deity/trap/Destroy() - GLOB.entered_event.unregister(get_turf(src),src) - return ..() - -/obj/structure/deity/trap/Move() - GLOB.entered_event.unregister(get_turf(src),src) - . = ..() - GLOB.entered_event.register(get_turf(src), src, /obj/structure/deity/trap/proc/trigger) - -/obj/structure/deity/trap/attackby(obj/item/W, mob/user) - trigger(user) - return ..() - -/obj/structure/deity/trap/bullet_act() - return - -/obj/structure/deity/trap/proc/trigger(var/atom/entered, var/atom/movable/enterer) - if(triggered > world.time || !istype(enterer, /mob/living)) - return - - triggered = world.time + 30 SECONDS \ No newline at end of file diff --git a/code/game/gamemodes/godmode/godmode.dm b/code/game/gamemodes/godmode/godmode.dm deleted file mode 100644 index bac00fca96c1..000000000000 --- a/code/game/gamemodes/godmode/godmode.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/game_mode/godmode - name = "Deity" - round_description = "An otherworldly beast has turned its attention to you and your fellow cremembers." - extended_round_description = "The station has been infiltrated by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!" - config_tag = "god" - required_players = 10 - required_enemies = 3 - end_on_antag_death = FALSE - antag_tags = list(MODE_DEITY, MODE_GODCULTIST) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm deleted file mode 100644 index 0e70eda1e56e..000000000000 --- a/code/game/gamemodes/heist/heist.dm +++ /dev/null @@ -1,13 +0,0 @@ -/* -(VOX) HEIST ROUNDTYPE -*/ - -/datum/game_mode/heist - name = "Heist" - config_tag = "heist" - required_players = 12 - required_enemies = 3 - round_description = "An unidentified drive signature has slipped into close sensor range and is approaching!" - extended_round_description = "Piratical raiders are on their way to steal the station goods, and possibly the crew!" - end_on_antag_death = FALSE - antag_tags = list(MODE_RAIDER) diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm deleted file mode 100644 index c06090c6aac2..000000000000 --- a/code/game/gamemodes/meteor/meteor.dm +++ /dev/null @@ -1,111 +0,0 @@ -// The following four defines can be used to tweak the difficulty of the gamemode -#define METEOR_FAILSAFE_THRESHOLD 45 MINUTES // Failsafe that guarantees Severity will be at least 15 when the round hits this time. - -// In general, a PVE oriented game mode. A middle ground between Extended and actual antagonist based rounds. -/datum/game_mode/meteor - name = "Meteor" - round_description = "You are about to enter an asteroid belt!" - extended_round_description = "We are on an unavoidable collision course with an asteroid field. You have only a moment to prepare before you are barraged by dust and meteors. As if it was not enough, all kinds of negative events seem to happen more frequently. Good luck." - config_tag = "meteor" - required_players = 15 // Definitely not good for low-pop - votable = 1 - shuttle_delay = 2 - var/next_wave = INFINITY // Set in post_setup() correctly to take into account potential longer pre-start times. - var/alert_sent = 0 - var/meteor_severity = 1 // Slowly increases the tension at the beginning of meteor strikes. Prevents "tunguska on first wave" style problems. - var/failsafe_triggered = 0 - var/alert_title - var/alert_text - var/start_text - var/maximal_severity = 40 - var/meteor_wave_delay = 30 SECONDS //minimum wait between waves in tenths of seconds - var/meteor_grace_period = 15 MINUTES //waves will not arrive until this far into round - - // Moved these from defines to variables, to allow for in-round tweaking via varedit: - var/escalation_probability = 45 - var/send_admin_broadcasts = TRUE // Enables debugging/information mode, sending admin messages when waves occur and when severity escalates. - - event_delay_mod_moderate = 0.5 // As a bonus, more frequent events. - event_delay_mod_major = 0.3 - -/decl/vv_set_handler/meteor_severity_handler - handled_type = /datum/game_mode/meteor - handled_vars = list( - "meteor_severity" = /datum/game_mode/meteor/proc/set_meteor_severity, - "meteor_wave_delay" = /datum/game_mode/meteor/proc/set_meteor_wave_delay - ) - -/datum/game_mode/meteor/proc/set_meteor_severity(value) - meteor_severity = Clamp(value, 0, maximal_severity) - -/datum/game_mode/meteor/proc/set_meteor_wave_delay(value) - meteor_wave_delay = max(10 SECONDS, value) - -/datum/game_mode/meteor/VV_static() - return ..() + "maximal_severity" - -/datum/game_mode/meteor/post_setup() - ..() - alert_title = "Automated Beacon AB-[rand(10, 99)]" - alert_text = "This is an automatic warning. Your facility: [GLOB.using_map.full_name] is on a collision course with a nearby asteroid belt. Estimated time until impact is: [meteor_grace_period / 1200] MINUTES. Please perform necessary actions to secure your ship or station from the threat. Have a nice day." - start_text = "This is an automatic warning. Your facility: [GLOB.using_map.full_name] has entered an asteroid belt. Estimated time until you leave the belt is: [rand(20,30)] HOURS and [rand(1, 59)] MINUTES. For your safety, please consider changing course or using protective equipment. Have a nice day." - next_wave = round_duration_in_ticks + meteor_grace_period - -/datum/game_mode/meteor/proc/on_meteor_warn() - alert_sent = 1 - command_announcement.Announce(alert_text, alert_title) - -/datum/game_mode/meteor/proc/on_enter_field() - alert_sent = 2 - command_announcement.Announce(start_text, alert_title) - for(var/obj/machinery/shield_diffuser/SD in SSmachines.machinery) - SD.meteor_alarm(INFINITY) - if(GLOB.using_map.use_overmap) - var/area/map = locate(/area/overmap) - for(var/turf/T in map) - T.overlays += image('icons/obj/overmap.dmi', "meteor[rand(1,4)]") - next_wave = round_duration_in_ticks + meteor_wave_delay - -/datum/game_mode/meteor/process() - // Send an alert halfway through the round. - if((round_duration_in_ticks >= (next_wave / 2)) && !alert_sent) - on_meteor_warn() - // And then another one when the meteors start flying around. - if((round_duration_in_ticks >= next_wave) && (alert_sent == 1)) - on_enter_field() - if((round_duration_in_ticks >= METEOR_FAILSAFE_THRESHOLD) && (meteor_severity < 15) && !failsafe_triggered) - log_and_message_admins("Meteor mode severity failsafe triggered: Severity forced to 15.") - meteor_severity = 15 - failsafe_triggered = 1 - - if(round_duration_in_ticks >= next_wave) - next_wave = round_duration_in_ticks + meteor_wave_delay - // Starts as barely noticeable dust impact, ends as barrage of most severe meteor types the code has to offer. Have fun. - spawn() - spawn_meteors(meteor_severity, get_meteor_types(), pick(GLOB.cardinal), pick(GLOB.using_map.station_levels)) - var/escalated = FALSE - if(prob(escalation_probability) && (meteor_severity < maximal_severity)) - meteor_severity++ - escalated = TRUE - if(send_admin_broadcasts) - log_and_message_admins("Meteor: Wave fired. Escalation: [escalated ? "Yes" : "No"]. Severity: [meteor_severity]/[maximal_severity]") - -/datum/game_mode/meteor/proc/get_meteor_types() - switch(meteor_severity) - if(1 to 9) - return meteors_dust - if(10 to 19) - return meteors_normal - if(20 to 29) - return meteors_threatening - if(30 to 34) - return meteors_catastrophic - if(35 to 39) - return meteors_armageddon - if(40 to INFINITY) - return meteors_cataclysm - // Just in case we /somehow/ get here (looking at you, varedit) - return meteors_normal - - -#undef METEOR_FAILSAFE_THRESHOLD diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm deleted file mode 100644 index 774089312975..000000000000 --- a/code/game/gamemodes/meteor/meteors.dm +++ /dev/null @@ -1,391 +0,0 @@ -//Meteor groups, used for various random events and the Meteor gamemode. - -// Dust, used by space dust event and during earliest stages of meteor mode. -/var/list/meteors_dust = list(/obj/effect/meteor/dust) - -// Standard meteors, used during early stages of the meteor gamemode. -/var/list/meteors_normal = list(\ - /obj/effect/meteor/medium=8,\ - /obj/effect/meteor/dust=3,\ - /obj/effect/meteor/irradiated=3,\ - /obj/effect/meteor/big=3,\ - /obj/effect/meteor/flaming=1,\ - /obj/effect/meteor/golden=1,\ - /obj/effect/meteor/silver=1\ - ) - -// Threatening meteors, used during the meteor gamemode. -/var/list/meteors_threatening = list(\ - /obj/effect/meteor/big=10,\ - /obj/effect/meteor/medium=5,\ - /obj/effect/meteor/golden=3,\ - /obj/effect/meteor/silver=3,\ - /obj/effect/meteor/flaming=3,\ - /obj/effect/meteor/irradiated=3,\ - /obj/effect/meteor/emp=3\ - ) - -// Catastrophic meteors, pretty dangerous without shields and used during the meteor gamemode. -/var/list/meteors_catastrophic = list(\ - /obj/effect/meteor/big=75,\ - /obj/effect/meteor/flaming=10,\ - /obj/effect/meteor/irradiated=10,\ - /obj/effect/meteor/emp=10,\ - /obj/effect/meteor/medium=5,\ - /obj/effect/meteor/golden=4,\ - /obj/effect/meteor/silver=4,\ - /obj/effect/meteor/tunguska=1\ - ) - -// Armageddon meteors, very dangerous, and currently used only during the meteor gamemode. -/var/list/meteors_armageddon = list(\ - /obj/effect/meteor/big=25,\ - /obj/effect/meteor/flaming=10,\ - /obj/effect/meteor/irradiated=10,\ - /obj/effect/meteor/emp=10,\ - /obj/effect/meteor/medium=3,\ - /obj/effect/meteor/tunguska=3,\ - /obj/effect/meteor/golden=2,\ - /obj/effect/meteor/silver=2\ - ) - -// Cataclysm meteor selection. Very very dangerous and effective even against shields. Used in late game meteor gamemode only. -/var/list/meteors_cataclysm = list(\ - /obj/effect/meteor/big=40,\ - /obj/effect/meteor/emp=20,\ - /obj/effect/meteor/tunguska=20,\ - /obj/effect/meteor/irradiated=10,\ - /obj/effect/meteor/golden=10,\ - /obj/effect/meteor/silver=10,\ - /obj/effect/meteor/flaming=10,\ - /obj/effect/meteor/supermatter=1\ - ) - - - -/////////////////////////////// -//Meteor spawning global procs -/////////////////////////////// - -/proc/spawn_meteors(var/number = 10, var/list/meteortypes, var/startSide, var/zlevel) - for(var/i = 0; i < number; i++) - spawn_meteor(meteortypes, startSide, zlevel) - -/proc/spawn_meteor(var/list/meteortypes, var/startSide, var/zlevel) - var/turf/pickedstart = spaceDebrisStartLoc(startSide, zlevel) - var/turf/pickedgoal = spaceDebrisFinishLoc(startSide, zlevel) - - var/Me = pickweight(meteortypes) - var/obj/effect/meteor/M = new Me(pickedstart) - M.dest = pickedgoal - spawn(0) - walk_towards(M, M.dest, 3) - return - -/proc/spaceDebrisStartLoc(startSide, Z) - var/starty - var/startx - switch(startSide) - if(NORTH) - starty = world.maxy-(TRANSITIONEDGE+1) - startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - if(EAST) - starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) - startx = world.maxx-(TRANSITIONEDGE+1) - if(SOUTH) - starty = (TRANSITIONEDGE+1) - startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) - if(WEST) - starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) - startx = (TRANSITIONEDGE+1) - var/turf/T = locate(startx, starty, Z) - return T - -/proc/spaceDebrisFinishLoc(startSide, Z) - var/endy - var/endx - switch(startSide) - if(NORTH) - endy = TRANSITIONEDGE - endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) - if(EAST) - endy = rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE) - endx = TRANSITIONEDGE - if(SOUTH) - endy = world.maxy-TRANSITIONEDGE - endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) - if(WEST) - endy = rand(TRANSITIONEDGE,world.maxy-TRANSITIONEDGE) - endx = world.maxx-TRANSITIONEDGE - var/turf/T = locate(endx, endy, Z) - return T - -/////////////////////// -//The meteor effect -////////////////////// - -/obj/effect/meteor - name = "meteor" - desc = "You should probably run instead of gawking at this." - icon = 'icons/obj/meteor.dmi' - icon_state = "small" - density = 1 - anchored = 1 - var/hits = 4 - var/hitpwr = 2 //Level of ex_act to be called on hit. - var/dest - pass_flags = PASS_FLAG_TABLE - var/heavy = 0 - var/z_original - var/meteordrop = /obj/item/ore/iron - var/dropamt = 1 - var/ismissile //missiles don't spin - - var/move_count = 0 - -/obj/effect/meteor/proc/get_shield_damage() - return max(((max(hits, 2)) * (heavy + 1) * rand(30, 60)) / hitpwr , 0) - -/obj/effect/meteor/Initialize() - . = ..() - z_original = z - -/obj/effect/meteor/Initialize() - . = ..() - GLOB.meteor_list += src - -/obj/effect/meteor/Move() - . = ..() //process movement... - move_count++ - if(loc == dest) - qdel(src) - -/obj/effect/meteor/touch_map_edge() - if(move_count > TRANSITIONEDGE) - qdel(src) - -/obj/effect/meteor/Destroy() - walk(src,0) //this cancels the walk_towards() proc - GLOB.meteor_list -= src - . = ..() - -/obj/effect/meteor/Initialize() - . = ..() - if(!ismissile) - SpinAnimation() - -/obj/effect/meteor/Bump(atom/A) - ..() - if(A && !QDELETED(src)) // Prevents explosions and other effects when we were deleted by whatever we Bumped() - currently used by shields. - ram_turf(get_turf(A)) - get_hit() //should only get hit once per move attempt - -/obj/effect/meteor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - return istype(mover, /obj/effect/meteor) ? 1 : ..() - -/obj/effect/meteor/proc/ram_turf(var/turf/T) - //first bust whatever is in the turf - for(var/atom/A in T) - if(A != src && !A.CanPass(src, src.loc, 0.5, 0)) //only ram stuff that would actually block us - A.explosion_act(hitpwr) - - //then, ram the turf if it still exists - if(T && !T.CanPass(src, src.loc, 0.5, 0)) - T.explosion_act(hitpwr) - -//process getting 'hit' by colliding with a dense object -//or randomly when ramming turfs -/obj/effect/meteor/proc/get_hit() - hits-- - if(hits <= 0) - make_debris() - meteor_effect() - qdel(src) - -/obj/effect/meteor/explosion_act() - SHOULD_CALL_PARENT(FALSE) - return - -/obj/effect/meteor/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/pickaxe)) - qdel(src) - return - ..() - -/obj/effect/meteor/proc/make_debris() - if(meteordrop && dropamt) - for(var/throws = dropamt, throws > 0, throws--) - addtimer(CALLBACK(new meteordrop(get_turf(src)), /atom/movable/proc/throw_at, dest, 5, 10), 0) - -/obj/effect/meteor/proc/meteor_effect() - if(heavy) - for(var/mob/M in GLOB.player_list) - var/turf/T = get_turf(M) - if(!T || T.z != src.z) - continue - var/dist = get_dist(M.loc, src.loc) - shake_camera(M, (dist > 20 ? 0.5 SECONDS : 1 SECOND), (dist > 20 ? 1 : 3)) - - -/////////////////////// -//Meteor types -/////////////////////// - -//Dust -/obj/effect/meteor/dust - name = "space dust" - icon_state = "dust" - pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE - hits = 1 - hitpwr = 3 - dropamt = 1 - meteordrop = /obj/item/ore/glass - -//Medium-sized -/obj/effect/meteor/medium - name = "meteor" - dropamt = 2 - -/obj/effect/meteor/medium/meteor_effect() - ..() - explosion(src.loc, 0, 1, 2, 3, 0) - -//Large-sized -/obj/effect/meteor/big - name = "large meteor" - icon_state = "large" - hits = 6 - heavy = 1 - dropamt = 3 - -/obj/effect/meteor/big/meteor_effect() - ..() - explosion(src.loc, 1, 2, 3, 4, 0) - -//Flaming meteor -/obj/effect/meteor/flaming - name = "flaming meteor" - icon_state = "flaming" - hits = 5 - heavy = 1 - meteordrop = /obj/item/ore/phosphorite - -/obj/effect/meteor/flaming/meteor_effect() - ..() - explosion(src.loc, 1, 2, 3, 4, 0, 0, 5) - -//Radiation meteor -/obj/effect/meteor/irradiated - name = "glowing meteor" - icon_state = "glowing" - heavy = 1 - meteordrop = /obj/item/ore/uranium - -/obj/effect/meteor/irradiated/meteor_effect() - ..() - explosion(src.loc, 0, 0, 4, 3, 0) - SSradiation.radiate(src, 50) - -/obj/effect/meteor/golden - name = "golden meteor" - icon_state = "glowing" - desc = "Shiny! But also deadly." - meteordrop = /obj/item/ore/gold - -/obj/effect/meteor/silver - name = "silver meteor" - icon_state = "glowing_blue" - desc = "Shiny! But also deadly." - meteordrop = /obj/item/ore/silver - -/obj/effect/meteor/emp - name = "conducting meteor" - icon_state = "glowing_blue" - desc = "Hide your floppies!" - meteordrop = /obj/item/ore/osmium - dropamt = 2 - -/obj/effect/meteor/emp/meteor_effect() - ..() - // Best case scenario: Comparable to a low-yield EMP grenade. - // Worst case scenario: Comparable to a standard yield EMP grenade. - empulse(src, rand(2, 4), rand(4, 10)) - -/obj/effect/meteor/emp/get_shield_damage() - return ..() * rand(2,4) - -//Station buster Tunguska -/obj/effect/meteor/tunguska - name = "tunguska meteor" - icon_state = "flaming" - desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity." - hits = 10 - hitpwr = 1 - heavy = 1 - meteordrop = /obj/item/ore/diamond // Probably means why it penetrates the hull so easily before exploding. - -/obj/effect/meteor/tunguska/meteor_effect() - ..() - explosion(src.loc, 3, 6, 9, 20, 0) - -// This is the final solution against shields - a single impact can bring down most shield generators. -/obj/effect/meteor/supermatter - name = "supermatter shard" - desc = "Oh god, what will be next..?" - icon = 'icons/obj/engine.dmi' - icon_state = "darkmatter" - -/obj/effect/meteor/supermatter/meteor_effect() - ..() - explosion(src.loc, 1, 2, 3, 4, 0) - for(var/obj/machinery/power/apc/A in range(rand(12, 20), src)) - A.energy_fail(round(10 * rand(8, 12))) - -/obj/effect/meteor/supermatter/get_shield_damage() - return ..() * rand(80, 120) - -//Missiles, for events and so on -/obj/effect/meteor/supermatter/missile - name = "photon torpedo" - desc = "An advanded warhead designed to tactically destroy space installations." - icon = 'icons/obj/missile.dmi' - icon_state = "photon" - meteordrop = null - ismissile = TRUE - dropamt = 0 - -/obj/effect/meteor/medium/missile - name = "missile" - desc = "Some kind of missile." - icon = 'icons/obj/missile.dmi' - icon_state = "missile" - meteordrop = null - ismissile = TRUE - dropamt = 0 - -/obj/effect/meteor/big/missile - name = "high-yield missile" - desc = "Some kind of missile." - icon = 'icons/obj/missile.dmi' - icon_state = "missile" - meteordrop = null - ismissile = TRUE - dropamt = 0 - -/obj/effect/meteor/flaming/missile - name = "incendiary missile" - desc = "Some kind of missile." - icon = 'icons/obj/missile.dmi' - icon_state = "missile" - meteordrop = null - ismissile = TRUE - dropamt = 0 - -/obj/effect/meteor/emp/missile - name = "ion torpedo" - desc = "Some kind of missile." - icon = 'icons/obj/missile.dmi' - icon_state = "torpedo" - meteordrop = null - ismissile = TRUE - dropamt = 0 \ No newline at end of file diff --git a/code/game/gamemodes/mixed/crossfire.dm b/code/game/gamemodes/mixed/crossfire.dm deleted file mode 100644 index 38de5abeb927..000000000000 --- a/code/game/gamemodes/mixed/crossfire.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/game_mode/crossfire - name = "Mercenary & Heist" - round_description = "Mercenaries and raiders are preparing for a nice visit..." - extended_round_description = "Nothing can possibly go wrong with lots of people and lots of guns, right?" - config_tag = "crossfire" - required_players = 25 - required_enemies = 6 - end_on_antag_death = FALSE - antag_tags = list(MODE_RAIDER, MODE_MERCENARY) - require_all_templates = TRUE diff --git a/code/game/gamemodes/mixed/siege.dm b/code/game/gamemodes/mixed/siege.dm deleted file mode 100644 index fe7ad30d1597..000000000000 --- a/code/game/gamemodes/mixed/siege.dm +++ /dev/null @@ -1,12 +0,0 @@ -/datum/game_mode/siege - name = "Mercenary & Revolution" - config_tag = "siege" - round_description = "Getting stuck between a rock and a hard place, maybe the nice visitors can help with your internal security problem?" - extended_round_description = "GENERAL QUARTERS! OH GOD WE GAVE THE REVOLUTIONARIES GUNS!" - required_players = 20 - required_enemies = 5 - end_on_antag_death = FALSE - auto_recall_shuttle = FALSE - shuttle_delay = 2 - antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_MERCENARY) - require_all_templates = TRUE diff --git a/code/game/gamemodes/mixed/spyvspy.dm b/code/game/gamemodes/mixed/spyvspy.dm deleted file mode 100644 index 401801b8f59e..000000000000 --- a/code/game/gamemodes/mixed/spyvspy.dm +++ /dev/null @@ -1,12 +0,0 @@ -/datum/game_mode/spyvspy - name = "Spy v. Spy" - round_description = "There are traitorous forces at play, but some crew have resolved to stop them by any means necessary!" - extended_round_description = "Traitors and renegades both spawn during this mode." - config_tag = "spyvspy" - required_players = 4 - required_enemies = 4 - end_on_antag_death = FALSE - antag_tags = list(MODE_TRAITOR, MODE_RENEGADE) - require_all_templates = TRUE - antag_scaling_coeff = 5 - latejoin_antag_tags = list(MODE_TRAITOR) \ No newline at end of file diff --git a/code/game/gamemodes/mixed/traitorling.dm b/code/game/gamemodes/mixed/traitorling.dm deleted file mode 100644 index 80706c1ef50b..000000000000 --- a/code/game/gamemodes/mixed/traitorling.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/game_mode/traitorling - name = "Changeling & Traitor" - round_description = "There are traitors and alien changelings. Do not let the changelings succeed!" - extended_round_description = "Traitors and changelings both spawn during this mode." - config_tag = "traitorling" - required_players = 15 - required_enemies = 5 - end_on_antag_death = FALSE - antag_tags = list(MODE_CHANGELING, MODE_TRAITOR) - require_all_templates = TRUE diff --git a/code/game/gamemodes/mixed/uprising.dm b/code/game/gamemodes/mixed/uprising.dm deleted file mode 100644 index 4be20f8900f4..000000000000 --- a/code/game/gamemodes/mixed/uprising.dm +++ /dev/null @@ -1,12 +0,0 @@ -/datum/game_mode/uprising - name = "Cult & Revolution" - round_description = "Some crewmembers are attempting to start a revolution while a cult plots in the shadows!" - extended_round_description = "Cultists and revolutionaries spawn in this round." - config_tag = "uprising" - required_players = 20 - required_enemies = 6 - end_on_antag_death = FALSE - auto_recall_shuttle = FALSE - shuttle_delay = 2 - antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_CULTIST) - require_all_templates = TRUE diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm deleted file mode 100644 index a25add6a8434..000000000000 --- a/code/game/gamemodes/ninja/ninja.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/game_mode/ninja - name = "Ninja" - round_description = "An agent of the Spider Clan is on board!" - extended_round_description = "A heavily armed, high-tech covert infiltrator is on board pursuing their mysterious goals." - config_tag = "ninja" - required_players = 5 - required_enemies = 1 - end_on_antag_death = FALSE - antag_tags = list(MODE_NINJA) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm deleted file mode 100644 index ffc881992ec8..000000000000 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ /dev/null @@ -1,90 +0,0 @@ -/* - MERCENARY ROUNDTYPE -*/ - -var/list/nuke_disks = list() - -/datum/game_mode/nuclear - name = "Mercenary" - round_description = "A mercenary strike force is approaching!" - extended_round_description = "A heavily armed merc team is approaching in their warship; whatever their goal is, it can't be good for the crew." - config_tag = "mercenary" - required_players = 15 - required_enemies = 1 - end_on_antag_death = FALSE - var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station - var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level - antag_tags = list(MODE_MERCENARY) - cinematic_icon_states = list( - "intro_nuke" = 35, - "summary_nukewin", - "summary_nukefail" - ) - -//checks if L has a nuke disk on their person -/datum/game_mode/nuclear/proc/check_mob(mob/living/L) - for(var/obj/item/disk/nuclear/N in nuke_disks) - if(N.storage_depth(L) >= 0) - return TRUE - return FALSE - -/datum/game_mode/nuclear/declare_completion() - var/datum/antagonist/merc = GLOB.all_antag_types_[MODE_MERCENARY] - if(config.objectives_disabled == CONFIG_OBJECTIVE_NONE || (merc && !merc.global_objectives.len)) - ..() - return - var/disk_rescued = TRUE - for(var/obj/item/disk/nuclear/D in world) - var/disk_area = get_area(D) - if(!is_type_in_list(disk_area, GLOB.using_map.post_round_safe_areas)) - disk_rescued = FALSE - break - var/crew_evacuated = (SSevac.evacuation_controller.has_evacuated()) - - if(!disk_rescued && station_was_nuked && !syndies_didnt_escape) - SSstatistics.set_field_details("round_end_result","win - syndicate nuke") - to_world("Mercenary Major Victory!") - to_world("[syndicate_name()] operatives have destroyed [station_name()]!") - - else if (!disk_rescued && station_was_nuked && syndies_didnt_escape) - SSstatistics.set_field_details("round_end_result","halfwin - syndicate nuke - did not evacuate in time") - to_world("Total Annihilation") - to_world("[syndicate_name()] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!") - - else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape) - SSstatistics.set_field_details("round_end_result","halfwin - blew wrong station") - to_world("Crew Minor Victory") - to_world("[syndicate_name()] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't lose the disk!") - - else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape) - SSstatistics.set_field_details("round_end_result","halfwin - blew wrong station - did not evacuate in time") - to_world("[syndicate_name()] operatives have earned Darwin Award!") - to_world("[syndicate_name()] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't lose the disk!") - - else if (disk_rescued && GLOB.mercs.antags_are_dead()) - SSstatistics.set_field_details("round_end_result","loss - evacuation - disk secured - syndi team dead") - to_world("Crew Major Victory!") - to_world("The Research Staff has saved the disc and killed the [syndicate_name()] Operatives") - - else if ( disk_rescued ) - SSstatistics.set_field_details("round_end_result","loss - evacuation - disk secured") - to_world("Crew Major Victory") - to_world("The Research Staff has saved the disc and stopped the [syndicate_name()] Operatives!") - - else if (!disk_rescued && GLOB.mercs.antags_are_dead()) - SSstatistics.set_field_details("round_end_result","loss - evacuation - disk not secured") - to_world("Mercenary Minor Victory!") - to_world("The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name()] Operatives!") - - else if (!disk_rescued && crew_evacuated) - SSstatistics.set_field_details("round_end_result","halfwin - detonation averted") - to_world("Mercenary Minor Victory!") - to_world("[syndicate_name()] operatives recovered the abandoned authentication disk but detonation of [station_name()] was averted. Next time, don't lose the disk!") - - else if (!disk_rescued && !crew_evacuated) - SSstatistics.set_field_details("round_end_result","halfwin - interrupted") - to_world("Neutral Victory") - to_world("Round was mysteriously interrupted!") - - ..() - return diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm deleted file mode 100644 index 39c5d01b58d9..000000000000 --- a/code/game/gamemodes/nuclear/pinpointer.dm +++ /dev/null @@ -1,24 +0,0 @@ -//Nuke ops locator -/obj/item/pinpointer/nukeop - var/locate_shuttle = 0 - -/obj/item/pinpointer/nukeop/Process() - var/new_mode - if(!locate_shuttle && bomb_set) - locate_shuttle = 1 - new_mode = "Shuttle Locator" - else if (locate_shuttle && !bomb_set) - locate_shuttle = 0 - new_mode = "Authentication Disk Locator" - if(new_mode) - playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) - visible_message("[new_mode] active.") - target = acquire_target() - ..() - -/obj/item/pinpointer/nukeop/acquire_target() - if(locate_shuttle) - var/obj/machinery/computer/shuttle_control/multi/syndicate/home = locate() - return weakref(home) - else - return ..() \ No newline at end of file diff --git a/code/game/gamemodes/objectives/_objective.dm b/code/game/gamemodes/objectives/_objective.dm index c29bdfd541bf..531ea1ccee60 100644 --- a/code/game/gamemodes/objectives/_objective.dm +++ b/code/game/gamemodes/objectives/_objective.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST_INIT(all_objectives, new) +var/global/list/all_objectives = list() /datum/objective var/datum/mind/owner //Who owns the objective. @@ -7,13 +7,15 @@ GLOBAL_LIST_INIT(all_objectives, new) var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter. /datum/objective/New(var/text) - GLOB.all_objectives |= src + global.all_objectives |= src if(text) explanation_text = text ..() /datum/objective/Destroy() - GLOB.all_objectives -= src + global.all_objectives -= src + owner = null + target = null . = ..() /datum/objective/proc/find_target() @@ -23,9 +25,4 @@ GLOBAL_LIST_INIT(all_objectives, new) possible_targets += possible_target if(possible_targets.len > 0) target = pick(possible_targets) - -/datum/objective/proc/find_target_by_role(role, role_type = 0)//Option sets either to check assigned role or special role. Default to assigned. - for(var/datum/mind/possible_target in SSticker.minds) - if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role) ) - target = possible_target - break + return target \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_absorb.dm b/code/game/gamemodes/objectives/objective_absorb.dm deleted file mode 100644 index 38ea68b5e959..000000000000 --- a/code/game/gamemodes/objectives/objective_absorb.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/objective/absorb/proc/gen_amount_goal(var/lowbound = 4, var/highbound = 6) - target_amount = rand (lowbound,highbound) - var/n_p = 1 //autowin - if (GAME_STATE == RUNLEVEL_SETUP) - for(var/mob/new_player/P in GLOB.player_list) - if(P.client && P.ready && P.mind!=owner) - n_p ++ - else if (GAME_STATE == RUNLEVEL_GAME) - for(var/mob/living/carbon/human/P in GLOB.player_list) - if(P.client && !(P.mind.changeling) && P.mind!=owner) - n_p ++ - target_amount = min(target_amount, n_p) - - explanation_text = "Absorb [target_amount] compatible genomes." - return target_amount diff --git a/code/game/gamemodes/objectives/objective_assassinate.dm b/code/game/gamemodes/objectives/objective_assassinate.dm index ee4904bd1172..91f13fa65842 100644 --- a/code/game/gamemodes/objectives/objective_assassinate.dm +++ b/code/game/gamemodes/objectives/objective_assassinate.dm @@ -5,11 +5,3 @@ else explanation_text = "Free Objective" return target - -/datum/objective/assassinate/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Assassinate [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]." - else - explanation_text = "Free Objective" - return target \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_brig.dm b/code/game/gamemodes/objectives/objective_brig.dm index bb4ec646ea27..6a483f4be5d9 100644 --- a/code/game/gamemodes/objectives/objective_brig.dm +++ b/code/game/gamemodes/objectives/objective_brig.dm @@ -1,6 +1,3 @@ -/datum/objective/anti_revolution/brig - var/already_completed = 0 - /datum/objective/anti_revolution/brig/find_target() ..() if(target && target.current) @@ -9,17 +6,6 @@ explanation_text = "Free Objective" return target -/datum/objective/anti_revolution/brig/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Brig [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] for 20 minutes to set an example." - else - explanation_text = "Free Objective" - return target - -/datum/objective/brig - var/already_completed = 0 - /datum/objective/brig/find_target() ..() if(target && target.current) @@ -27,11 +13,3 @@ else explanation_text = "Free Objective" return target - -/datum/objective/brig/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Have [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] brigged for 10 minutes." - else - explanation_text = "Free Objective" - return target \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_capture.dm b/code/game/gamemodes/objectives/objective_capture.dm deleted file mode 100644 index 3f45d46c93e9..000000000000 --- a/code/game/gamemodes/objectives/objective_capture.dm +++ /dev/null @@ -1,4 +0,0 @@ -/datum/objective/capture/proc/gen_amount_goal() - target_amount = rand(5,10) - explanation_text = "Accumulate [target_amount] capture points." - return target_amount diff --git a/code/game/gamemodes/objectives/objective_cult.dm b/code/game/gamemodes/objectives/objective_cult.dm deleted file mode 100644 index 1a06a0182944..000000000000 --- a/code/game/gamemodes/objectives/objective_cult.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/objective/cult/survive - explanation_text = "Our knowledge must live on." - target_amount = 5 - -/datum/objective/cult/survive/New() - ..() - explanation_text = "Our knowledge must live on. Make sure at least [target_amount] acolytes escape to spread their work." - -/datum/objective/cult/eldergod - explanation_text = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it. The convert rune is join blood self." - -/datum/objective/cult/sacrifice - explanation_text = "Conduct a ritual sacrifice for the glory of Nar-Sie." - -/datum/objective/cult/sacrifice/find_target() - var/list/possible_targets = list() - if(!possible_targets.len) - for(var/mob/living/carbon/human/player in GLOB.player_list) - if(player.mind && !(player.mind in GLOB.cult.current_antagonists)) - possible_targets += player.mind - if(possible_targets.len > 0) - target = pick(possible_targets) - if(target) explanation_text = "Sacrifice [target.name], the [target.assigned_role]. You will need the sacrifice rune (Hell blood join) and three acolytes to do so." diff --git a/code/game/gamemodes/objectives/objective_debrain.dm b/code/game/gamemodes/objectives/objective_debrain.dm index b7a11db0877d..f045c55bba9a 100644 --- a/code/game/gamemodes/objectives/objective_debrain.dm +++ b/code/game/gamemodes/objectives/objective_debrain.dm @@ -5,11 +5,3 @@ else explanation_text = "Free Objective" return target - -/datum/objective/debrain/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Steal the brain of [target.current.real_name] the [!role_type ? target.assigned_role : target.special_role]." - else - explanation_text = "Free Objective" - return target diff --git a/code/game/gamemodes/objectives/objective_demote.dm b/code/game/gamemodes/objectives/objective_demote.dm index 3ffe9149a0c9..de907a39a73c 100644 --- a/code/game/gamemodes/objectives/objective_demote.dm +++ b/code/game/gamemodes/objectives/objective_demote.dm @@ -1,15 +1,8 @@ /datum/objective/anti_revolution/demote/find_target() ..() if(target && target.current) - explanation_text = "[target.current.real_name], the [target.assigned_role] has been classified as harmful to [GLOB.using_map.company_name]'s goals. Demote \him[target.current] to assistant." - else - explanation_text = "Free Objective" - return target - -/datum/objective/anti_revolution/demote/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has been classified as harmful to [GLOB.using_map.company_name]'s goals. Demote \him[target.current] to assistant." + var/decl/pronouns/pronouns = target.current.get_pronouns(ignore_coverings = TRUE) + explanation_text = "[target.current.real_name], the [target.assigned_role] has been classified as harmful to [global.using_map.company_name]'s goals. Demote [pronouns.him] to assistant." else explanation_text = "Free Objective" return target diff --git a/code/game/gamemodes/objectives/objective_download.dm b/code/game/gamemodes/objectives/objective_download.dm index ea72d6617139..0c86e6a3627f 100644 --- a/code/game/gamemodes/objectives/objective_download.dm +++ b/code/game/gamemodes/objectives/objective_download.dm @@ -1,5 +1,4 @@ -/datum/objective/download - proc/gen_amount_goal() - target_amount = rand(10,20) - explanation_text = "Download [target_amount] research levels." - return target_amount \ No newline at end of file +/datum/objective/download/proc/gen_amount_goal() + target_amount = rand(10,20) + explanation_text = "Download [target_amount] research levels." + return target_amount diff --git a/code/game/gamemodes/objectives/objective_execute.dm b/code/game/gamemodes/objectives/objective_execute.dm index 4a322b6a1f24..312df8d501a9 100644 --- a/code/game/gamemodes/objectives/objective_execute.dm +++ b/code/game/gamemodes/objectives/objective_execute.dm @@ -1,15 +1,8 @@ /datum/objective/anti_revolution/execute/find_target() ..() if(target && target.current) - explanation_text = "[target.current.real_name], the [target.assigned_role] has extracted confidential information above their clearance. Execute \him[target.current]." + var/decl/pronouns/pronouns = target.current.get_pronouns(ignore_coverings = TRUE) + explanation_text = "[target.current.real_name], the [target.assigned_role] has extracted confidential information above their clearance. Execute [pronouns.him]." else explanation_text = "Free Objective" return target - -/datum/objective/anti_revolution/execute/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has extracted confidential information above their clearance. Execute \him[target.current]." - else - explanation_text = "Free Objective" - return target \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_harm.dm b/code/game/gamemodes/objectives/objective_harm.dm index d2c0e7c0032c..3fd7ec6ab290 100644 --- a/code/game/gamemodes/objectives/objective_harm.dm +++ b/code/game/gamemodes/objectives/objective_harm.dm @@ -1,6 +1,3 @@ -/datum/objective/harm - var/already_completed = 0 - /datum/objective/harm/find_target() ..() if(target && target.current) @@ -8,11 +5,3 @@ else explanation_text = "Free Objective" return target - -/datum/objective/harm/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Make an example of [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." - else - explanation_text = "Free Objective" - return target \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_heist.dm b/code/game/gamemodes/objectives/objective_heist.dm index e29bb75b1efb..dce0fe7611fc 100644 --- a/code/game/gamemodes/objectives/objective_heist.dm +++ b/code/game/gamemodes/objectives/objective_heist.dm @@ -1,18 +1,15 @@ -/datum/objective/heist/proc/choose_target() - return - -/datum/objective/heist/kidnap +/datum/objective/kidnap var/list/roles -/datum/objective/heist/kidnap/choose_target() +/datum/objective/kidnap/find_target() var/list/possible_targets = list() var/list/priority_targets = list() for(var/datum/mind/possible_target in SSticker.minds) - if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && (!possible_target.special_role)) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && !possible_target.assigned_special_role) possible_targets += possible_target if(length(roles)) - for(var/datum/job/role in SSjobs.get_by_path(roles)) + for(var/datum/job/role in SSjobs.get_by_paths(roles)) if(possible_target.assigned_role == role.title) priority_targets += possible_target continue @@ -28,45 +25,49 @@ explanation_text = "Free Objective" return target -/datum/objective/heist/loot/choose_target() +/datum/objective/loot + var/target_obj + +/datum/objective/loot/find_target() var/loot = "an object" switch(rand(1,8)) if(1) - target = /obj/structure/particle_accelerator + target_obj = /obj/structure/particle_accelerator target_amount = 6 loot = "a complete particle accelerator" if(2) - target = /obj/machinery/the_singularitygen + target_obj = /obj/machinery/singularity_generator target_amount = 1 loot = "a gravitational generator" if(3) - target = /obj/machinery/power/emitter + target_obj = /obj/machinery/emitter target_amount = 4 loot = "four emitters" if(4) - target = /obj/machinery/nuclearbomb + target_obj = /obj/machinery/nuclearbomb target_amount = 1 loot = "a nuclear bomb" if(5) - target = /obj/item/gun + target_obj = /obj/item/gun target_amount = 6 loot = "six guns" if(6) - target = /obj/item/gun/energy + target_obj = /obj/item/gun/energy target_amount = 4 loot = "four energy guns" if(7) - target = /obj/item/gun/energy/laser + target_obj = /obj/item/gun/energy/laser target_amount = 2 loot = "two laser guns" if(8) - target = /obj/item/gun/energy/ionrifle + target_obj = /obj/item/gun/energy/ionrifle target_amount = 1 loot = "an ion gun" explanation_text = "It's a buyer's market out here. Steal [loot] for resale." + return target_obj -/datum/objective/heist/salvage/choose_target() +/datum/objective/salvage/find_target() var/list/loot = list( /decl/material/solid/metal/steel = 300, /decl/material/solid/glass = 200, @@ -77,8 +78,9 @@ /decl/material/solid/gemstone/diamond = 20 ) - var/decl/material/mat = decls_repository.get_decl(pick(loot)) + var/decl/material/mat = GET_DECL(pick(loot)) explanation_text = "Ransack the [station_name()] and escape with [loot[mat.type]] unit\s of [mat.solid_name]." + return target -/datum/objective/heist/preserve_crew +/datum/objective/preserve_crew explanation_text = "Do not leave anyone behind, alive or dead." \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_misc.dm b/code/game/gamemodes/objectives/objective_misc.dm index 5ad82119e16b..0feb39b668ec 100644 --- a/code/game/gamemodes/objectives/objective_misc.dm +++ b/code/game/gamemodes/objectives/objective_misc.dm @@ -6,6 +6,3 @@ /datum/objective/survive explanation_text = "Stay alive until the end." - -/datum/objective/ninja_highlander - explanation_text = "You aspire to be a Grand Master of the Spider Clan. Kill all of your fellow acolytes." diff --git a/code/game/gamemodes/objectives/objective_protect.dm b/code/game/gamemodes/objectives/objective_protect.dm index 65f3461ad292..2041107bfb4d 100644 --- a/code/game/gamemodes/objectives/objective_protect.dm +++ b/code/game/gamemodes/objectives/objective_protect.dm @@ -5,11 +5,3 @@ else explanation_text = "Free Objective" return target - -/datum/objective/protect/find_target_by_role(role, role_type = 0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Protect [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]." - else - explanation_text = "Free Objective" - return target \ No newline at end of file diff --git a/code/game/gamemodes/objectives/objective_rev.dm b/code/game/gamemodes/objectives/objective_rev.dm index e77c43fd1850..2cba148bf51a 100644 --- a/code/game/gamemodes/objectives/objective_rev.dm +++ b/code/game/gamemodes/objectives/objective_rev.dm @@ -5,11 +5,3 @@ else explanation_text = "Free Objective" return target - -/datum/objective/rev/find_target_by_role(role, role_type=0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Assassinate, capture or convert [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]." - else - explanation_text = "Free Objective" - return target diff --git a/code/game/gamemodes/objectives/objective_steal.dm b/code/game/gamemodes/objectives/objective_steal.dm index 8e7513790c5b..e48eb9523bcf 100644 --- a/code/game/gamemodes/objectives/objective_steal.dm +++ b/code/game/gamemodes/objectives/objective_steal.dm @@ -1,37 +1,28 @@ /datum/objective/steal - var/obj/item/steal_target - var/target_name - -/datum/objective/steal/proc/set_target(item_name) - target_name = item_name - var/list/possible_items = GLOB.using_map.get_theft_targets() - steal_target = possible_items[target_name] - if (!steal_target ) - var/list/possible_items_special = GLOB.using_map.get_special_theft_targets() - steal_target = possible_items_special[target_name] - explanation_text = "Steal [target_name]." - return steal_target + var/theft_name + var/theft_type + var/theft_material + var/theft_amount = 1 /datum/objective/steal/find_target() - return set_target(pick(GLOB.using_map.get_theft_targets())) -/datum/objective/steal/proc/select_target() - var/possible_items = GLOB.using_map.get_theft_targets() - var/possible_items_special = GLOB.using_map.get_special_theft_targets() - var/list/possible_items_all = possible_items+possible_items_special+"custom" - var/new_target = input("Select target:", "Objective target", steal_target) as null|anything in possible_items_all - if (!new_target) return - if (new_target == "custom") - var/obj/item/custom_target = input("Select type:","Type") as null|anything in typesof(/obj/item) - if (!custom_target) return - var/tmp_obj = new custom_target - var/custom_name = tmp_obj:name - qdel(tmp_obj) - custom_name = sanitize(input("Enter target name:", "Objective target", custom_name) as text|null) - if (!custom_name) return - target_name = custom_name - steal_target = custom_target - explanation_text = "Steal [target_name]." + var/list/possible_items = global.using_map.get_theft_targets() | global.using_map.get_special_theft_targets() + if(!length(possible_items)) + return + theft_name = pick(possible_items) + var/theft_data = possible_items[theft_name] + if(ispath(theft_data)) + theft_type = theft_data + else if(islist(theft_data)) + if(length(theft_data) >= 1 && ispath(theft_data[1])) + theft_type = theft_data[1] + if(length(theft_data) >= 2 && isnum(theft_data[2])) + theft_amount = theft_data[2] + if(length(theft_data) >= 3 && ispath(theft_data[3], /decl/material)) + theft_material = theft_data[3] + + if(!theft_type || theft_amount <= 0) + explanation_text = "Free objective." else - set_target(new_target) - return steal_target \ No newline at end of file + explanation_text = "Steal [theft_name]." + return theft_type diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm deleted file mode 100644 index 153a18a20e78..000000000000 --- a/code/game/gamemodes/revolution/revolution.dm +++ /dev/null @@ -1,12 +0,0 @@ -/datum/game_mode/revolution - name = "Revolution" - config_tag = "revolution" - round_description = "Some crewmembers are attempting to start a revolution!" - extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders." - required_players = 4 - required_enemies = 3 - auto_recall_shuttle = FALSE - end_on_antag_death = FALSE - shuttle_delay = 2 - antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST) - require_all_templates = TRUE diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm deleted file mode 100644 index 2cd429fb603d..000000000000 --- a/code/game/gamemodes/setupgame.dm +++ /dev/null @@ -1,83 +0,0 @@ -///////////////////////// -// (mostly) DNA2 SETUP -///////////////////////// - -// Randomize block, assign a reference name, and optionally define difficulty (by making activation zone smaller or bigger) -// The name is used on /vg/ for species with predefined genetic traits, -// and for the DNA panel in the player panel. -/proc/getAssignedBlock(var/name,var/list/blocksLeft, var/activity_bounds=DNA_DEFAULT_BOUNDS) - if(blocksLeft.len==0) - warning("[name]: No more blocks left to assign!") - return 0 - var/assigned = pick(blocksLeft) - blocksLeft.Remove(assigned) - assigned_blocks[assigned]=name - dna_activity_bounds[assigned]=activity_bounds - //testing("[name] assigned to block #[assigned].") - return assigned - -/proc/setupgenetics() - - if (prob(50)) - // Currently unused. Will revisit. - N3X - GLOB.BLOCKADD = rand(-300,300) - if (prob(75)) - GLOB.DIFFMUT = rand(0,20) - - var/list/numsToAssign=new() - for(var/i=1;i\The [src] heats up in your hands, burning you!") - -/obj/item/sword/excalibur/Process() - if(istype(loc, /mob/living)) - if(istype(loc, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = loc - var/hand = BP_R_HAND - if(H.l_hand == src) - hand = BP_L_HAND - var/obj/item/organ/external/E = H.get_organ(hand) - E.take_external_damage(burn=2,used_weapon="stovetop") - else - var/mob/living/M = loc - M.adjustFireLoss(2) - if(prob(2)) - to_chat(loc,"\The [src] is burning you!") - return 1 - -/obj/item/sword/excalibur/dropped() - STOP_PROCESSING(SSobj, src) \ No newline at end of file diff --git a/code/game/gamemodes/wizard/servant_items/familiar.dm b/code/game/gamemodes/wizard/servant_items/familiar.dm deleted file mode 100644 index a408e03b1a5e..000000000000 --- a/code/game/gamemodes/wizard/servant_items/familiar.dm +++ /dev/null @@ -1,19 +0,0 @@ -/obj/item/clothing/head/bandana/familiarband - name = "familiar's headband" - desc = "It's a simple headband made of leather." - - icon = 'icons/clothing/head/familiar.dmi' -/obj/item/clothing/under/familiargarb - name = "familiar's garb" - desc = "It looks like a cross between Robin Hood's tunic and some patchwork leather armor. Whoever put this together must have been in a hurry." - icon_state = "familiartunic" - armor = list( - melee = ARMOR_MELEE_KNIVES, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_SMALL - ) - bodytype_restricted = list(BODYTYPE_HUMANOID) - -/obj/item/clothing/under/familiargard/Initialize() - . = ..() - slowdown_per_slot[slot_w_uniform] = -3 \ No newline at end of file diff --git a/code/game/gamemodes/wizard/servant_items/fiend.dm b/code/game/gamemodes/wizard/servant_items/fiend.dm deleted file mode 100644 index d3b3afc59e07..000000000000 --- a/code/game/gamemodes/wizard/servant_items/fiend.dm +++ /dev/null @@ -1,54 +0,0 @@ -/obj/item/clothing/head/fiendhood - name = "fiend's hood" - desc = "A dark hood with blood-red trim. Something about the fabric blocks more light than it should." - icon = 'icons/clothing/head/fiend_hood.dmi' - armor = list( - melee = ARMOR_MELEE_KNIVES, - bullet = ARMOR_BALLISTIC_MINOR, - laser = ARMOR_LASER_SMALL, - energy = ARMOR_ENERGY_SMALL, - rad = ARMOR_RAD_SHIELDED - ) - bodytype_restricted = list(BODYTYPE_HUMANOID) - flags_inv = HIDEEARS | BLOCKHAIR - -/obj/item/clothing/suit/fiendcowl - name = "fiend's cowl" - desc = "A charred black duster with red trim. In its fabric, you can see the faint outline of millions of eyes." - icon = 'icons/clothing/suit/wizard/servant/fiend_cowl.dmi' - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_RESISTANT, - rad = ARMOR_RAD_SHIELDED - ) - -/obj/item/clothing/under/lawyer/fiendsuit - name = "black suit" - desc = "A snappy black suit with red trim. The undershirt's stained with something, though..." - icon_state = "fiendsuit" - bodytype_restricted = list(BODYTYPE_HUMANOID) - -/obj/item/clothing/shoes/dress/devilshoes - desc = "Off-colour leather dress shoes. Their footsteps are silent." - inset_color = COLOR_MAROON - item_flags = ITEM_FLAG_SILENT - color = "#2e1e1e" - -/obj/item/clothing/head/fiendhood/fem - name = "fiend's visage" - desc = "To gaze upon this is to gaze into an inferno. Look away, before it looks back of its own accord." - icon = 'icons/clothing/head/fiend_visage.dmi' - flags_inv = HIDEEARS | BLOCKHAIR - -/obj/item/clothing/suit/fiendcowl/fem - name = "fiend's robe" - icon = 'icons/clothing/suit/wizard/servant/fiend_robe.dmi' - desc = "A tattered, black and red robe. Nothing is visible through the holes in its fabric, except for a strange, inky blackness. It looks as if it was stitched together with other clothing..." - -/obj/item/clothing/under/devildress - name = "old dress" - desc = "An elegant - if tattered - black and red dress. There's nothing visible through the holes in the fabric; nothing but darkness." - icon_state = "fienddress" diff --git a/code/game/gamemodes/wizard/servant_items/infiltrator.dm b/code/game/gamemodes/wizard/servant_items/infiltrator.dm deleted file mode 100644 index ad30984fc7c9..000000000000 --- a/code/game/gamemodes/wizard/servant_items/infiltrator.dm +++ /dev/null @@ -1,52 +0,0 @@ -/obj/item/clothing/head/infilhat - name = "immaculate fedora" - desc = "Whoever owns this hat means business. Hopefully, it's just good business." - color = COLOR_SILVER - icon = 'icons/clothing/head/detective.dmi' - markings_icon = "band" - markings_color = COLOR_DARK_GRAY - armor = list( - melee = ARMOR_MELEE_MINOR, - bullet = ARMOR_BALLISTIC_MINOR, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_MINOR - ) - bodytype_restricted = list(BODYTYPE_HUMANOID) - -/obj/item/clothing/suit/infilsuit - name = "immaculate suit" - desc = "The clothes of an impeccable diplomat. Or perhaps a businessman. Let's not consider the horrors that might arise if it belongs to a lawyer." - icon = 'icons/clothing/suit/wizard/servant/inf_suit.dmi' - armor = list( - melee = ARMOR_MELEE_MINOR, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_MINOR - ) - -/obj/item/clothing/under/lawyer/infil - name = "formal outfit" - desc = "A white dress shirt and navy pants. Snazzy." - icon_state = "inf_mob" - bodytype_restricted = list(BODYTYPE_HUMANOID) - -/obj/item/clothing/shoes/dress/infilshoes - name = "black leather shoes" - desc = "Dress shoes. Their footsteps are dead silent." - inset_color = COLOR_INDIGO - item_flags = ITEM_FLAG_SILENT - -/obj/item/clothing/head/infilhat/fem - name = "maid's headband" - desc = "This dainty, frilled thing is apparently meant to go on your head." - icon = 'icons/clothing/head/inf_hat.dmi' -/obj/item/clothing/suit/infilsuit/fem - name = "maid's uniform" - desc = "The uniform of someone you'd expect to see dusting off the Antique Gun's display case." - icon = 'icons/clothing/suit/wizard/servant/inf_dress.dmi' - -/obj/item/clothing/under/lawyer/infil/fem - name = "white dress" - desc = "It's a simple, sleeveless white dress with black trim." - icon_state = "inffem" - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET \ No newline at end of file diff --git a/code/game/gamemodes/wizard/servant_items/overseer.dm b/code/game/gamemodes/wizard/servant_items/overseer.dm deleted file mode 100644 index 35d7c0bab680..000000000000 --- a/code/game/gamemodes/wizard/servant_items/overseer.dm +++ /dev/null @@ -1,46 +0,0 @@ -/obj/item/clothing/head/overseerhood - name = "grim hood" - desc = "Darker than dark. What... what is this made of?" - armor = list( - melee = ARMOR_MELEE_SHIELDED, - bullet = ARMOR_BALLISTIC_HEAVY, - laser = ARMOR_LASER_HEAVY, - energy = ARMOR_ENERGY_SHIELDED, - bomb = ARMOR_BOMB_SHIELDED - ) - icon = 'icons/clothing/head/necromancer.dmi' - item_flags = ITEM_FLAG_AIRTIGHT - max_pressure_protection = FIRESUIT_MAX_PRESSURE - min_pressure_protection = 0 - bodytype_restricted = list(BODYTYPE_HUMANOID) - flags_inv = HIDEEARS | BLOCKHAIR - -/obj/item/clothing/suit/straight_jacket/overseercloak - name = "grim cloak" - desc = "The void of space woven into fabric. It's hard to tell where its edges are." - icon = 'icons/clothing/suit/wizard/servant/overseer.dmi' - armor = list( - melee = ARMOR_MELEE_SHIELDED, - bullet = ARMOR_BALLISTIC_HEAVY, - laser = ARMOR_LASER_HEAVY, - energy = ARMOR_ENERGY_SHIELDED, - bomb = ARMOR_BOMB_SHIELDED - ) - item_flags = ITEM_FLAG_AIRTIGHT - max_pressure_protection = FIRESUIT_MAX_PRESSURE - min_pressure_protection = 0 - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS - -/obj/item/clothing/under/grimhoodie - name = "black hoodie" - desc = "A generic black hoodie. There's a pattern akin to splattered blood along the bottom." - icon_state = "grimhoodie" - bodytype_restricted = list(BODYTYPE_HUMANOID) - -//These are the ones that it gets when they toggle it off -/obj/item/clothing/shoes/sandal/grimboots - name = "stained boots" - desc = "These boots are stained with blood so dry that it's turned black..." - color = COLOR_BLACK - shine = 10 - item_flags = ITEM_FLAG_SILENT \ No newline at end of file diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm deleted file mode 100644 index a37f171ed2e3..000000000000 --- a/code/game/gamemodes/wizard/wizard.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/game_mode/wizard - name = "Wizard" - round_description = "There is a SPACE WIZARD onboard. You can't let the magician achieve their objectives!" - extended_round_description = "A powerful space wizard has made their way on board. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows devastation." - config_tag = "wizard" - required_players = 5 - required_enemies = 1 - end_on_antag_death = FALSE - antag_tags = list(MODE_WIZARD) diff --git a/code/game/images.dm b/code/game/images.dm deleted file mode 100644 index e8b844937491..000000000000 --- a/code/game/images.dm +++ /dev/null @@ -1,3 +0,0 @@ -/image/Destroy() - ..() - return QDEL_HINT_HARDDEL diff --git a/code/game/jobs/_access_defs.dm b/code/game/jobs/_access_defs.dm index 1b94fb1644c3..4da0495fa6fb 100644 --- a/code/game/jobs/_access_defs.dm +++ b/code/game/jobs/_access_defs.dm @@ -13,8 +13,8 @@ #define ACCESS_REGION_MIN 1 #define ACCESS_REGION_MAX 8 -#define ACCESS_TYPE_NONE 1 -#define ACCESS_TYPE_CENTCOM 2 -#define ACCESS_TYPE_STATION 4 -#define ACCESS_TYPE_SYNDICATE 8 -#define ACCESS_TYPE_ALL (ACCESS_TYPE_NONE|ACCESS_TYPE_CENTCOM|ACCESS_TYPE_STATION|ACCESS_TYPE_SYNDICATE) +#define ACCESS_TYPE_NONE BITFLAG(0) +#define ACCESS_TYPE_CENTCOM BITFLAG(1) +#define ACCESS_TYPE_STATION BITFLAG(2) +#define ACCESS_TYPE_ANTAG BITFLAG(3) +#define ACCESS_TYPE_ALL (ACCESS_TYPE_NONE|ACCESS_TYPE_CENTCOM|ACCESS_TYPE_STATION|ACCESS_TYPE_ANTAG) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index 5cbc933ad4c2..4acbcff8b72f 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -7,31 +7,70 @@ return FALSE return check_access_list(M.GetAccess()) -/atom/movable/proc/GetAccess() +/atom/movable/proc/GetAccess(var/union = FALSE) . = list() - var/obj/item/card/id/id = GetIdCard() + if(union) + for(var/atom/movable/id in GetIdCards()) + . |= id.GetAccess() + return . + var/atom/movable/id = GetIdCard() if(id) - . += id.GetAccess() - -/atom/movable/proc/GetIdCard() - return null + . = id.GetAccess() + +/atom/movable/proc/GetIdCard(list/exceptions, prefer_held = TRUE) + RETURN_TYPE(/obj/item/card/id) + . = GetIdCards(exceptions) + return LAZYACCESS(., LAZYLEN(.)) + +// Duplicated logic, because it's short enough to not bother splitting out. +// Quite gross logic sorry, did not want to work out a proper sorting method :( +// The logic behind this sorting is that we should prefer ID cards as such: +// - held cards, because they are very easily shifted dropped etc +// - equipped cards, because they can also be removed, albeit slower +// - any remaining cards, because at time of writing they are implanted and +// can't be removed easily at all. +/mob/GetIdCard(list/exceptions, prefer_held = TRUE) + RETURN_TYPE(/obj/item/card/id) + // Get candidate cards, return similar to parent if we don't care + . = GetIdCards(exceptions) + var/card_count = length(.) + if(card_count <= 0) + return null + if(!prefer_held || card_count == 1) + return .[card_count] + // Move ID to the end of the list. + var/obj/item/id = get_equipped_item(slot_wear_id_str) + if(id) + . -= id + . += id + // Move held items to the end of the list (prefer them over equipped ID) + for(var/obj/item/card in get_held_items()) + if(card in .) + . -= card + . += card + return .[length(.)] + +/atom/movable/proc/GetIdCards(list/exceptions) + var/datum/extension/access_provider/our_provider = get_extension(src, /datum/extension/access_provider) + if(our_provider) + LAZYDISTINCTADD(., our_provider.GetIdCards(exceptions)) /atom/movable/proc/check_access(atom/movable/A) return check_access_list(A ? A.GetAccess() : list()) -/atom/movable/proc/check_access_list(list/L) - var/list/R = get_req_access() +/atom/movable/proc/check_access_list(list/supplied_access) + var/list/required_access = get_req_access() - if(!R) - R = list() - if(!istype(L, /list)) + if(!required_access) + required_access = list() + if(!istype(supplied_access, /list)) return FALSE - if(maint_all_access) - L = L.Copy() - L |= access_maint_tunnels + if(global.using_map.maint_all_access) // todo: movable -> loc -> area -> map datum, to allow separate maps? + supplied_access = supplied_access.Copy() + supplied_access |= access_maint_tunnels - return has_access(R, L) + return has_access(required_access, supplied_access) /proc/has_access(list/req_access, list/accesses) for(var/req in req_access) @@ -47,20 +86,12 @@ return FALSE return TRUE -//Checks if the access (constant or list) is contained in one of the entries of access_patterns, a list of lists. -/proc/has_access_pattern(list/access_patterns, access) - if(!islist(access)) - access = list(access) - for(var/access_pattern in access_patterns) - if(has_access(access_pattern, access)) - return 1 - // Used for retrieving required access information, if available /atom/movable/proc/get_req_access() return null /obj/get_req_access() - return req_access + return req_access?.Copy() /proc/get_centcom_access(job) switch(job) @@ -83,7 +114,7 @@ if("Supreme Commander") return get_all_centcom_access() -/var/list/datum/access/priv_all_access_datums +var/global/list/datum/access/priv_all_access_datums /proc/get_all_access_datums() if(!priv_all_access_datums) priv_all_access_datums = init_subtypes(/datum/access) @@ -91,7 +122,7 @@ return priv_all_access_datums.Copy() -/var/list/datum/access/priv_all_access_datums_id +var/global/list/datum/access/priv_all_access_datums_id /proc/get_all_access_datums_by_id() if(!priv_all_access_datums_id) priv_all_access_datums_id = list() @@ -100,7 +131,7 @@ return priv_all_access_datums_id.Copy() -/var/list/datum/access/priv_all_access_datums_region +var/global/list/datum/access/priv_all_access_datums_region /proc/get_all_access_datums_by_region() if(!priv_all_access_datums_region) priv_all_access_datums_region = list() @@ -112,41 +143,40 @@ return priv_all_access_datums_region.Copy() /proc/get_access_ids(var/access_types = ACCESS_TYPE_ALL) - var/list/L = new() + . = list() for(var/datum/access/A in get_all_access_datums()) if(A.access_type & access_types) - L += A.id - return L + . += A.id -/var/list/priv_all_access +var/global/list/priv_all_access /proc/get_all_accesses() if(!priv_all_access) priv_all_access = get_access_ids() return priv_all_access?.Copy() -/var/list/priv_station_access +var/global/list/priv_station_access /proc/get_all_station_access() if(!priv_station_access) priv_station_access = get_access_ids(ACCESS_TYPE_STATION) return priv_station_access.Copy() -/var/list/priv_centcom_access +var/global/list/priv_centcom_access /proc/get_all_centcom_access() if(!priv_centcom_access) priv_centcom_access = get_access_ids(ACCESS_TYPE_CENTCOM) return priv_centcom_access.Copy() -/var/list/priv_syndicate_access -/proc/get_all_syndicate_access() - if(!priv_syndicate_access) - priv_syndicate_access = get_access_ids(ACCESS_TYPE_SYNDICATE) +var/global/list/priv_antagonist_access +/proc/get_all_antagonist_access() + if(!priv_antagonist_access) + priv_antagonist_access = get_access_ids(ACCESS_TYPE_ANTAG) - return priv_syndicate_access.Copy() + return priv_antagonist_access.Copy() -/var/list/priv_region_access +var/global/list/priv_region_access /proc/get_region_accesses(var/code) if(code == ACCESS_REGION_ALL) return get_all_station_access() @@ -208,47 +238,6 @@ "Emergency Response Team", "Emergency Response Team Leader") -/mob/observer/ghost - var/static/obj/item/card/id/all_access/ghost_all_access - -/mob/observer/ghost/GetIdCard() - if(!is_admin(src)) - return - - if(!ghost_all_access) - ghost_all_access = new() - return ghost_all_access - -/mob/living/bot/GetIdCard() - return botcard - -#define HUMAN_ID_CARDS list(get_active_hand(), wear_id, get_inactive_hand()) -/mob/living/carbon/human/GetIdCard() - for(var/item_slot in HUMAN_ID_CARDS) - var/obj/item/I = item_slot - var/obj/item/card/id = I ? I.GetIdCard() : null - if(id) - return id - -/mob/living/carbon/human/GetAccess() - . = list() - for(var/item_slot in HUMAN_ID_CARDS) - var/obj/item/I = item_slot - if(I) - . |= I.GetAccess() -#undef HUMAN_ID_CARDS - -/mob/living/silicon/GetIdCard() - if(stat || (ckey && !client)) - return // Unconscious, dead or once possessed but now client-less silicons are not considered to have id access. - return idcard - -/proc/FindNameFromID(var/mob/M, var/missing_id_name = "Unknown") - var/obj/item/card/id/C = M.GetIdCard() - if(C) - return C.registered_name - return missing_id_name - /proc/get_all_job_icons() //For all existing HUD icons return SSjobs.titles_to_datums + list("Prisoner") @@ -259,13 +248,13 @@ var/job_icons = get_all_job_icons() if(I.assignment in job_icons) //Check if the job has a hud icon return I.assignment - if(I.rank in job_icons) - return I.rank + if(I.position in job_icons) + return I.position var/centcom = get_all_centcom_jobs() if(I.assignment in centcom) return "Centcom" - if(I.rank in centcom) + if(I.position in centcom) return "Centcom" else return diff --git a/code/game/jobs/access_datum.dm b/code/game/jobs/access_datum.dm index 60009c7bfcc8..bbb21f0a0896 100644 --- a/code/game/jobs/access_datum.dm +++ b/code/game/jobs/access_datum.dm @@ -10,424 +10,436 @@ /***************** * Station access * *****************/ -/var/const/access_security = "ACCESS_SECURITY" //1 +var/global/const/access_security = "ACCESS_SECURITY" //1 /datum/access/security id = access_security desc = "Security Equipment" region = ACCESS_REGION_SECURITY -/var/const/access_brig = "ACCESS_BRIG" // Brig timers and permabrig 2 +var/global/const/access_brig = "ACCESS_BRIG" // Brig timers and permabrig 2 /datum/access/holding id = access_brig desc = "Holding Cells" region = ACCESS_REGION_SECURITY -/var/const/access_armory = "ACCESS_ARMORY" //3 +var/global/const/access_armory = "ACCESS_ARMORY" //3 /datum/access/armory id = access_armory desc = "Armory" region = ACCESS_REGION_SECURITY -/var/const/access_forensics_lockers = "ACCESS_FORENSICS" //4 +var/global/const/access_forensics_lockers = "ACCESS_FORENSICS" //4 /datum/access/forensics_lockers id = access_forensics_lockers desc = "Forensics" region = ACCESS_REGION_SECURITY -/var/const/access_medical = "ACCESS_MEDICAL" //5 +var/global/const/access_medical = "ACCESS_MEDICAL" //5 /datum/access/medical id = access_medical desc = "Medical" region = ACCESS_REGION_MEDBAY -/var/const/access_morgue = "ACCESS_MORGUE" //6 +var/global/const/access_morgue = "ACCESS_MORGUE" //6 /datum/access/morgue id = access_morgue desc = "Morgue" region = ACCESS_REGION_MEDBAY -/var/const/access_tox = "ACCESS_TOXINS" //7 +var/global/const/access_tox = "ACCESS_TOXINS" //7 /datum/access/tox id = access_tox desc = "Research Labs" region = ACCESS_REGION_RESEARCH -/var/const/access_tox_storage = "ACCESS_TOX_STORAGE" //8 +var/global/const/access_tox_storage = "ACCESS_TOX_STORAGE" //8 /datum/access/tox_storage id = access_tox_storage desc = "Toxins Lab" region = ACCESS_REGION_RESEARCH -/var/const/access_engine = "ACCESS_ENGINEERING" //10 +var/global/const/access_warden = "ACCESS_WARDEN" //9 +/datum/access/warden + id = access_warden + desc = "Warden Office" + region = ACCESS_REGION_SECURITY + +var/global/const/access_engine = "ACCESS_ENGINEERING" //10 /datum/access/engine id = access_engine desc = "Engineering" region = ACCESS_REGION_ENGINEERING -/var/const/access_engine_equip = "ACCESS_ENGINE_EQUIP" //11 +var/global/const/access_engine_equip = "ACCESS_ENGINE_EQUIP" //11 /datum/access/engine_equip id = access_engine_equip desc = "Engine Room" region = ACCESS_REGION_ENGINEERING -/var/const/access_maint_tunnels = "ACCESS_MAINT" //12 +var/global/const/access_maint_tunnels = "ACCESS_MAINT" //12 /datum/access/maint_tunnels id = access_maint_tunnels desc = "Maintenance" region = ACCESS_REGION_ENGINEERING -/var/const/access_external_airlocks = "ACCESS_EXTERNAL" //13 +var/global/const/access_external_airlocks = "ACCESS_EXTERNAL" //13 /datum/access/external_airlocks id = access_external_airlocks desc = "External Airlocks" region = ACCESS_REGION_ENGINEERING -/var/const/access_emergency_storage = "ACCESS_EMERGENCY_STORAGE" //14 +var/global/const/access_emergency_storage = "ACCESS_EMERGENCY_STORAGE" //14 /datum/access/emergency_storage id = access_emergency_storage desc = "Emergency Storage" region = ACCESS_REGION_ENGINEERING -/var/const/access_change_ids = "ACCESS_CHANGE_ID" //15 +var/global/const/access_change_ids = "ACCESS_CHANGE_ID" //15 /datum/access/change_ids id = access_change_ids desc = "ID Computer" region = ACCESS_REGION_COMMAND -/var/const/access_ai_upload = "ACCESS_AI_UPLOAD" //16 +var/global/const/access_ai_upload = "ACCESS_AI_UPLOAD" //16 /datum/access/ai_upload id = access_ai_upload desc = "AI Upload" region = ACCESS_REGION_COMMAND -/var/const/access_teleporter = "ACCESS_TELEPORTER" //17 +var/global/const/access_teleporter = "ACCESS_TELEPORTER" //17 /datum/access/teleporter id = access_teleporter desc = "Teleporter" region = ACCESS_REGION_COMMAND -/var/const/access_eva = "ACCESS_EVA" //18 +var/global/const/access_eva = "ACCESS_EVA" //18 /datum/access/eva id = access_eva desc = "EVA" region = ACCESS_REGION_COMMAND -/var/const/access_bridge = "ACCESS_BRIDGE" //19 +var/global/const/access_bridge = "ACCESS_BRIDGE" //19 /datum/access/bridge id = access_bridge desc = "Bridge" region = ACCESS_REGION_COMMAND -/var/const/access_captain = "ACCESS_CAPTAIN" //20 +var/global/const/access_captain = "ACCESS_CAPTAIN" //20 /datum/access/captain id = access_captain desc = "Captain" region = ACCESS_REGION_COMMAND -/var/const/access_all_personal_lockers = "ACCESS_PERSONAL_LOCKERS" //21 +var/global/const/access_all_personal_lockers = "ACCESS_PERSONAL_LOCKERS" //21 /datum/access/all_personal_lockers id = access_all_personal_lockers desc = "Personal Lockers" region = ACCESS_REGION_COMMAND -/var/const/access_chapel_office = "ACCESS_CHAPEL_STORAGE" //22 +var/global/const/access_chapel_office = "ACCESS_CHAPEL_STORAGE" //22 /datum/access/chapel_office id = access_chapel_office desc = "Chapel Office" region = ACCESS_REGION_GENERAL -/var/const/access_tech_storage = "ACCESS_TECH_STORAGE" //23 +var/global/const/access_tech_storage = "ACCESS_TECH_STORAGE" //23 /datum/access/tech_storage id = access_tech_storage desc = "Technical Storage" region = ACCESS_REGION_ENGINEERING -/var/const/access_atmospherics = "ACCESS_ATMOS" //24 +var/global/const/access_atmospherics = "ACCESS_ATMOS" //24 /datum/access/atmospherics id = access_atmospherics desc = "Atmospherics" region = ACCESS_REGION_ENGINEERING -/var/const/access_bar = "ACCESS_BAR" //25 +var/global/const/access_bar = "ACCESS_BAR" //25 /datum/access/bar id = access_bar desc = "Bar" region = ACCESS_REGION_GENERAL -/var/const/access_janitor = "ACCESS_JANITOR" //26 +var/global/const/access_janitor = "ACCESS_JANITOR" //26 /datum/access/janitor id = access_janitor desc = "Custodial Closet" region = ACCESS_REGION_GENERAL -/var/const/access_crematorium = "ACCESS_CREMATORIUM" //27 +var/global/const/access_crematorium = "ACCESS_CREMATORIUM" //27 /datum/access/crematorium id = access_crematorium desc = "Crematorium" region = ACCESS_REGION_GENERAL -/var/const/access_kitchen = "ACCESS_KITCHEN" //28 +var/global/const/access_kitchen = "ACCESS_KITCHEN" //28 /datum/access/kitchen id = access_kitchen desc = "Kitchen" region = ACCESS_REGION_GENERAL -/var/const/access_robotics = "ACCESS_ROBOTICS" //29 +var/global/const/access_robotics = "ACCESS_ROBOTICS" //29 /datum/access/robotics id = access_robotics desc = "Robotics" region = ACCESS_REGION_RESEARCH -/var/const/access_rd = "ACCESS_RESEARCH_DIRECTOR" //30 +var/global/const/access_rd = "ACCESS_RESEARCH_DIRECTOR" //30 /datum/access/rd id = access_rd desc = "Chief Science Officer" region = ACCESS_REGION_RESEARCH -/var/const/access_cargo = "ACCESS_CARGO" //31 +var/global/const/access_cargo = "ACCESS_CARGO" //31 /datum/access/cargo id = access_cargo desc = "Cargo Bay" region = ACCESS_REGION_SUPPLY -/var/const/access_construction = "ACCESS_CONSTRUCTION" //32 +var/global/const/access_construction = "ACCESS_CONSTRUCTION" //32 /datum/access/construction id = access_construction desc = "Construction Areas" region = ACCESS_REGION_ENGINEERING -/var/const/access_chemistry = "ACCESS_CHEMISTRY" //33 +var/global/const/access_chemistry = "ACCESS_CHEMISTRY" //33 /datum/access/chemistry id = access_chemistry desc = "Chemistry Lab" region = ACCESS_REGION_MEDBAY -/var/const/access_cargo_bot = "ACCESS_CARGO_BOT" //34 +var/global/const/access_cargo_bot = "ACCESS_CARGO_BOT" //34 /datum/access/cargo_bot id = access_cargo_bot desc = "Cargo Bot Delivery" region = ACCESS_REGION_SUPPLY -/var/const/access_hydroponics = "ACCESS_HYDROPONICS" //35 +var/global/const/access_hydroponics = "ACCESS_HYDROPONICS" //35 /datum/access/hydroponics id = access_hydroponics desc = "Hydroponics" region = ACCESS_REGION_GENERAL -/var/const/access_manufacturing = "ACCESS_MANUFACTURING" //36 +var/global/const/access_manufacturing = "ACCESS_MANUFACTURING" //36 /datum/access/manufacturing id = access_manufacturing desc = "Manufacturing" access_type = ACCESS_TYPE_NONE -/var/const/access_library = "ACCESS_LIBRARY" //37 +var/global/const/access_library = "ACCESS_LIBRARY" //37 /datum/access/library id = access_library desc = "Library" region = ACCESS_REGION_GENERAL -/var/const/access_lawyer = "ACCESS_LAWYER" //38 +var/global/const/access_lawyer = "ACCESS_LAWYER" //38 /datum/access/lawyer id = access_lawyer desc = "Internal Affairs" region = ACCESS_REGION_COMMAND -/var/const/access_virology = "ACCESS_VIRO" //39 +var/global/const/access_virology = "ACCESS_VIRO" //39 /datum/access/virology id = access_virology desc = "Virology" region = ACCESS_REGION_MEDBAY -/var/const/access_cmo = "ACCESS_CHIEF_MEDICAL_OFFICER" //40 +var/global/const/access_cmo = "ACCESS_CHIEF_MEDICAL_OFFICER" //40 /datum/access/cmo id = access_cmo desc = "Chief Medical Officer" region = ACCESS_REGION_COMMAND -/var/const/access_qm = "ACCESS_QUARTERMASTER" //41 +var/global/const/access_qm = "ACCESS_QUARTERMASTER" //41 /datum/access/qm id = access_qm desc = "Quartermaster" region = ACCESS_REGION_SUPPLY -/var/const/access_network = "ACCESS_NETWORK" //42 +var/global/const/access_network = "ACCESS_NETWORK" //42 /datum/access/network id = access_network desc = "Primary Network" region = ACCESS_REGION_RESEARCH -/var/const/access_surgery = "ACCESS_SURGERY" //45 +var/global/const/access_surgery = "ACCESS_SURGERY" //45 /datum/access/surgery id = access_surgery desc = "Surgery" region = ACCESS_REGION_MEDBAY -/var/const/access_research = "ACCESS_RESEARCH" //47 +var/global/const/access_research = "ACCESS_RESEARCH" //47 /datum/access/research id = access_research desc = "Science" region = ACCESS_REGION_RESEARCH -/var/const/access_mining = "ACCESS_MINING" //48 +var/global/const/access_mining = "ACCESS_MINING" //48 /datum/access/mining id = access_mining desc = "Mining" region = ACCESS_REGION_SUPPLY -/var/const/access_mining_office = "ACCESS_MINING_OFFICE" //49 +var/global/const/access_mining_office = "ACCESS_MINING_OFFICE" //49 /datum/access/mining_office id = access_mining_office desc = "Mining Office" access_type = ACCESS_TYPE_NONE -/var/const/access_mailsorting = "ACCESS_SORTING" //50 +var/global/const/access_mailsorting = "ACCESS_SORTING" //50 /datum/access/mailsorting id = access_mailsorting desc = "Cargo Office" region = ACCESS_REGION_SUPPLY -/var/const/access_heads_vault = "ACCESS_VAULT" //53 +var/global/const/access_heads_vault = "ACCESS_VAULT" //53 /datum/access/heads_vault id = access_heads_vault desc = "Main Vault" region = ACCESS_REGION_COMMAND -/var/const/access_mining_station = "ACCESS_MINING_EVA" //54 +var/global/const/access_mining_station = "ACCESS_MINING_EVA" //54 /datum/access/mining_station id = access_mining_station desc = "Mining EVA" region = ACCESS_REGION_SUPPLY -/var/const/access_xenobiology = "ACCESS_XENOBIO" //55 +var/global/const/access_xenobiology = "ACCESS_XENOBIO" //55 /datum/access/xenobiology id = access_xenobiology desc = "Xenobiology Lab" region = ACCESS_REGION_RESEARCH -/var/const/access_ce = "ACCESS_CHIEF_ENGINEER" //56 +var/global/const/access_ce = "ACCESS_CHIEF_ENGINEER" //56 /datum/access/ce id = access_ce desc = "Chief Engineer" region = ACCESS_REGION_ENGINEERING -/var/const/access_hop = "ACCESS_HEAD_OF_PERSONNEL" //57 +var/global/const/access_hop = "ACCESS_HEAD_OF_PERSONNEL" //57 /datum/access/hop id = access_hop desc = "Head of Personnel" region = ACCESS_REGION_COMMAND -/var/const/access_hos = "ACCESS_HEAD_OF_SECURITY" //58 +var/global/const/access_hos = "ACCESS_HEAD_OF_SECURITY" //58 /datum/access/hos id = access_hos desc = "Head of Security" region = ACCESS_REGION_SECURITY -/var/const/access_RC_announce = "ACCESS_REQUEST_ANNOUCE" //Request console announcements 59 +var/global/const/access_RC_announce = "ACCESS_REQUEST_ANNOUCE" //Request console announcements 59 /datum/access/RC_announce id = access_RC_announce desc = "RC Announcements" region = ACCESS_REGION_COMMAND -/var/const/access_keycard_auth = "ACCESS_KEYCARD_AUTH" //Used for events which require at least two people to confirm them 60 +var/global/const/access_keycard_auth = "ACCESS_KEYCARD_AUTH" //Used for events which require at least two people to confirm them 60 /datum/access/keycard_auth id = access_keycard_auth desc = "Keycode Auth. Device" region = ACCESS_REGION_COMMAND -/var/const/access_tcomsat ="ACCESS_TELECOMS" // has access to the entire telecomms satellite / machinery 61 +var/global/const/access_tcomsat ="ACCESS_TELECOMS" // has access to the entire telecomms satellite / machinery 61 /datum/access/tcomsat id = access_tcomsat desc = "Telecommunications" region = ACCESS_REGION_COMMAND -/var/const/access_gateway = "ACCESS_GATEWAY" //62 +var/global/const/access_gateway = "ACCESS_GATEWAY" //62 /datum/access/gateway id = access_gateway desc = "Gateway" region = ACCESS_REGION_COMMAND -/var/const/access_sec_doors = "ACCESS_SEC_DOORS" // Security front doors //63 +var/global/const/access_sec_doors = "ACCESS_SEC_DOORS" // Security front doors //63 /datum/access/sec_doors id = access_sec_doors desc = "Security" region = ACCESS_REGION_SECURITY -/var/const/access_psychiatrist = "ACCESS_PSYCHIATRIST" // Psychiatrist's office 64 +var/global/const/access_psychiatrist = "ACCESS_PSYCHIATRIST" // Psychiatrist's office 64 /datum/access/psychiatrist id = access_psychiatrist desc = "Counselor's Office" region = ACCESS_REGION_MEDBAY -/var/const/access_xenoarch = "ACCESS_XENOARCH" //65 +var/global/const/access_xenoarch = "ACCESS_XENOARCH" //65 /datum/access/xenoarch id = access_xenoarch desc = "Xenoarchaeology" region = ACCESS_REGION_RESEARCH -/var/const/access_medical_equip = "ACCESS_MEDICAL_EQUIP" //66 +var/global/const/access_medical_equip = "ACCESS_MEDICAL_EQUIP" //66 /datum/access/medical_equip id = access_medical_equip desc = "Medical Equipment" region = ACCESS_REGION_MEDBAY -/var/const/access_heads = "ACCESS_HEADS" //67 +var/global/const/access_heads = "ACCESS_HEADS" //67 /datum/access/heads id = access_heads desc = "Command" region = ACCESS_REGION_COMMAND +var/global/const/access_cameras = "ACCESS_CAMERAS" //68 +/datum/access/cameras + id = access_cameras + desc = "Cameras" + region = ACCESS_REGION_SECURITY + /****************** * Central Command * ******************/ -/var/const/access_cent_general = "ACCESS_CENT_GENERAL" //101 +var/global/const/access_cent_general = "ACCESS_CENT_GENERAL" //101 /datum/access/cent_general id = access_cent_general desc = "Code Grey" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_thunder = "ACCESS_CENT_THUNDERDOME" //102 +var/global/const/access_cent_thunder = "ACCESS_CENT_THUNDERDOME" //102 /datum/access/cent_thunder id = access_cent_thunder desc = "Code Yellow" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_specops = "ACCESS_CENT_SPECOPS" //103 +var/global/const/access_cent_specops = "ACCESS_CENT_SPECOPS" //103 /datum/access/cent_specops id = access_cent_specops desc = "Code Black" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_medical = "ACCESS_CENT_MEDBAY" //104 +var/global/const/access_cent_medical = "ACCESS_CENT_MEDBAY" //104 /datum/access/cent_medical id = access_cent_medical desc = "Code White" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_living = "ACCESS_CENT_LIVING" //105 +var/global/const/access_cent_living = "ACCESS_CENT_LIVING" //105 /datum/access/cent_living id = access_cent_living desc = "Code Green" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_storage = "ACCESS_CENT_STORAGE" //106 +var/global/const/access_cent_storage = "ACCESS_CENT_STORAGE" //106 /datum/access/cent_storage id = access_cent_storage desc = "Code Orange" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_teleporter = "ACCESS_CENT_TELEPORTER" //107 +var/global/const/access_cent_teleporter = "ACCESS_CENT_TELEPORTER" //107 /datum/access/cent_teleporter id = access_cent_teleporter desc = "Code Blue" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_creed = "ACCESS_CENT_CREED" //108 +var/global/const/access_cent_creed = "ACCESS_CENT_CREED" //108 /datum/access/cent_creed id = access_cent_creed desc = "Code Silver" access_type = ACCESS_TYPE_CENTCOM -/var/const/access_cent_captain = "ACCESS_CENT_CAPTAIN" //109 +var/global/const/access_cent_captain = "ACCESS_CENT_CAPTAIN" //109 /datum/access/cent_captain id = access_cent_captain desc = "Code Gold" @@ -436,28 +448,40 @@ /*************** * Antag access * ***************/ -/var/const/access_syndicate = "ACCESS_SYNDICATE" //150 -/datum/access/syndicate - id = access_syndicate - desc = "Syndicate" - access_type = ACCESS_TYPE_SYNDICATE +var/global/const/access_hacked = "ACCESS_HACKED" //150 +/datum/access/hacked + id = access_hacked + desc = "Hacked" + access_type = ACCESS_TYPE_ANTAG + +var/global/const/access_raider = "ACCESS_RAIDER" +/datum/access/raider + id = access_raider + desc = "Raider" + access_type = ACCESS_TYPE_ANTAG + +var/global/const/access_mercenary = "ACCESS_MERCENARY" +/datum/access/mercenary + id = access_mercenary + desc = "Mercenary" + access_type = ACCESS_TYPE_ANTAG /******* * Misc * *******/ -/var/const/access_synth = "ACCESS_SYNTH" //199 +var/global/const/access_synth = "ACCESS_SYNTH" //199 /datum/access/synthetic id = access_synth desc = "Synthetic" access_type = ACCESS_TYPE_NONE -/var/const/access_crate_cash = "ACCESS_MERCHANT_CASH" //300 +var/global/const/access_crate_cash = "ACCESS_MERCHANT_CASH" //300 /datum/access/crate_cash id = access_crate_cash desc = "Crate cash" access_type = ACCESS_TYPE_NONE -/var/const/access_merchant = "ACCESS_MERCHANT" //301 +var/global/const/access_merchant = "ACCESS_MERCHANT" //301 /datum/access/merchant id = access_merchant desc = "Merchant" diff --git a/code/game/jobs/alt_titles.dm b/code/game/jobs/alt_titles.dm new file mode 100644 index 000000000000..cea4dafc8378 --- /dev/null +++ b/code/game/jobs/alt_titles.dm @@ -0,0 +1,23 @@ +/decl/alt_title + abstract_type = /decl/alt_title + var/name + var/desc + var/outfit + +/decl/alt_title/validate() + . = ..() + if(!name) + . += "missing name" + if(!desc) + . += "missing desc" + if(!ispath(outfit, /decl/outfit)) + . += "missing or invalid outfit: [outfit || "NULL"]" + +/datum/job/New() + if(length(alt_titles)) + for(var/title in alt_titles) + if(ispath(title, /decl/alt_title)) + var/decl/alt_title/title_data = GET_DECL(title) + alt_titles -= title + alt_titles[title_data.name] = title_data.outfit + ..() diff --git a/code/game/jobs/job/_job.dm b/code/game/jobs/job/_job.dm index a43bc797ed3a..6fe1006de269 100644 --- a/code/game/jobs/job/_job.dm +++ b/code/game/jobs/job/_job.dm @@ -1,170 +1,218 @@ /datum/job - - //The name of the job - var/title - //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access - var/list/minimal_access = list() // Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) - var/list/access = list() // Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) - var/list/software_on_spawn = list() // Defines the software files that spawn on tablets and labtops - var/list/department_refs = list() // What deparements the job is in. - var/primary_department = null // A jobs primary deparment, defualts to the first in the department refs list if not set. Important for heads, the department they are head of needs to be this one. - var/total_positions = 0 // How many players can be this job - var/spawn_positions = 0 // How many players can spawn in as this job - var/current_positions = 0 // How many players have this job - var/availablity_chance = 100 // Percentage chance job is available each round - var/guestbanned = 0 // If set to 1 this job will be unavalible to guests - var/must_fill = 0 // If set to 1 this job will be have priority over other job preferences. Do not reccommend on jobs with more that one position. - var/not_random_selectable = 0 // If set to 1 this job will not be selected when a player asks for a random job. - - var/supervisors = null // Supervisors, who this person answers to directly - var/selection_color = "#515151" // Selection screen color - var/list/alt_titles // List of alternate titles, if any and any potential alt. outfits as assoc values. - var/req_admin_notify // If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. - var/minimal_player_age = 0 // If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) - var/head_position = 0 // Is this position Command? - var/minimum_character_age // List of species = age, if species is not here, it's auto-pass - var/ideal_character_age = 30 - var/create_record = 1 // Do we announce/make records for people who spawn on this job? - var/is_semi_antagonist = FALSE // Whether or not this job is given semi-antagonist status. - var/account_allowed = 1 // Does this job type come with a station account? - var/economic_power = 2 // With how much does this job modify the initial account amount? - var/is_holy = FALSE // Can this role perform blessings? - var/outfit_type // The outfit the employee will be dressed in, if any - - var/loadout_allowed = TRUE // Whether or not loadout equipment is allowed and to be created when joining. - var/list/allowed_branches // For maps using branches and ranks, also expandable for other purposes - var/list/allowed_ranks // Ditto - - var/announced = TRUE //If their arrival is announced on radio - var/latejoin_at_spawnpoints //If this job should use roundstart spawnpoints for latejoin (offstation jobs etc) - var/forced_spawnpoint //If set to a spawnpoint name, will use that spawn point for joining as this job. - - var/hud_icon //icon used for Sec HUD overlay - - //Minimum skills allowed for the job. List should contain skill (as in /decl/hierarchy/skill path), with values which are numbers. + var/title // The name of the job + var/list/software_on_spawn = list() // Defines the software files that spawn on tablets and labtops + var/list/department_types = list() // What departments the job is in. + var/autoset_department = TRUE // If department list is empty, use map default. + var/primary_department // A jobs primary deparment, defualts to the first in the department refs list if not set. Important for heads, the department they are head of needs to be this one. + var/total_positions = 0 // How many players can be this job + var/spawn_positions = 0 // How many players can spawn in as this job + var/current_positions = 0 // How many players have this job + var/availablity_chance = 100 // Percentage chance job is available each round + var/guestbanned = FALSE // If set to 1 this job will be unavalible to guests + var/must_fill = FALSE // If set to 1 this job will be have priority over other job preferences. Do not recommend on jobs with more than one position. + var/not_random_selectable = FALSE // If set to 1 this job will not be selected when a player asks for a random job. + var/description // If set, returns a static description. To add dynamic text, override get_description_blurb, call parent aka . = ..() and then . += "extra text" on the line after that. + var/list/event_categories // A set of tags used to check jobs for suitability for things like random event selection. + var/skip_loadout_preview = FALSE // Whether or not the job should render loadout items in char preview. + var/supervisors = null // Supervisors, who this person answers to directly + var/selection_color = "#515151" // Selection screen color + var/list/alt_titles // List of alternate titles, if any and any potential alt. outfits as assoc values. + var/req_admin_notify // If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. + var/minimal_player_age = 0 // If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) + var/head_position = 0 // Is this position Command? + var/minimum_character_age // List of species = age, if species is not here, it's auto-pass + var/ideal_character_age = 30 // Preferred character age when populate job at roundstart. + var/create_record = 1 // Do we announce/make records for people who spawn on this job? + var/account_allowed = 1 // Does this job type come with a station account? + var/economic_power = 2 // With how much does this job modify the initial account amount? + var/is_holy = FALSE // Can this role perform blessings? + var/outfit_type // The outfit the employee will be dressed in, if any + var/loadout_allowed = TRUE // Whether or not loadout equipment is allowed and to be created when joining. + var/list/allowed_branches // For maps using branches and ranks, also expandable for other purposes + var/list/allowed_ranks // Ditto + var/announced = TRUE // If their arrival is announced on radio + var/latejoin_at_spawnpoints // If this job should use roundstart spawnpoints for latejoin (offstation jobs etc) + var/forced_spawnpoint // If set to a spawnpoint name, will use that spawn point for joining as this job. + var/hud_icon // icon used for secHUD overlay + var/hud_icon_state // icon state used for secHUD overlay + + // A list of string IDs for keys to grant on join. + var/list/lock_keys = list() + + //Job access. The use of minimal_access or access is determined by a config setting: jobs_have_minimal_access + var/list/minimal_access = list() // Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) + var/list/access = list() // Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) + + //Minimum skills allowed for the job. List should contain skill (as in /decl/skill path), with values which are numbers. var/min_skill = list( SKILL_LITERACY = SKILL_ADEPT ) - var/max_skill = list() //Maximum skills allowed for the job. - var/skill_points = 16 //The number of unassigned skill points the job comes with (on top of the minimum skills). - var/no_skill_buffs = FALSE //Whether skills can be buffed by age/species modifiers. + var/max_skill = list() //Maximum skills allowed for the job. + var/skill_points = 16 //The number of unassigned skill points the job comes with (on top of the minimum skills). + var/no_skill_buffs = FALSE //Whether skills can be buffed by age/species modifiers. var/available_by_default = TRUE + /// If TRUE, 'Not available at roundstart.' won't be shown for this job if available_by_default is FALSE. + var/suppress_no_roundstart_warning = FALSE var/list/possible_goals var/min_goals = 1 var/max_goals = 3 - var/defer_roundstart_spawn = FALSE // If true, the job will be put off until all other jobs have been populated. + var/defer_roundstart_spawn = FALSE // If true, the job will be put off until all other jobs have been populated. var/list/species_branch_rank_cache_ = list() var/required_language + var/no_warn_unsafe // If true, we don't prompt the user to confirm on spawning if the environment is unsafe. + /datum/job/New() + if(type == /datum/job && global.using_map.default_job_type == type) + title = "Debug Job" + hud_icon_state = "hudblank" + outfit_type = /decl/outfit/job/generic/scientist + autoset_department = TRUE + + if(!length(department_types) && autoset_department) + department_types = list(global.using_map.default_department_type) + if(isnull(primary_department) && length(department_types)) + primary_department = department_types[1] + if(prob(100-availablity_chance)) //Close positions, blah blah. total_positions = 0 spawn_positions = 0 if(!hud_icon) - hud_icon = "hud[ckey(title)]" + hud_icon = global.using_map.hud_icons + if(!hud_icon_state) + hud_icon_state = "hud[ckey(title)]" ..() /datum/job/dd_SortValue() return title -/datum/job/proc/equip(var/mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) - +/datum/job/proc/equip_job(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) + H.add_language(/decl/language/human/common) if (required_language) H.add_language(required_language) H.set_default_language(required_language) - - H.add_language(/decl/language/human/common) - H.set_default_language(/decl/language/human/common) - var/decl/hierarchy/outfit/outfit = get_outfit(H, alt_title, branch, grade) - if(outfit) . = outfit.equip(H, title, alt_title) - -/datum/job/proc/get_outfit(var/mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) + else + H.set_default_language(/decl/language/human/common) + + var/decl/outfit/outfit = get_outfit(H, alt_title, branch, grade) + if(outfit) + . = outfit.equip_outfit(H, alt_title || title, job = src, rank = grade) + + if(length(lock_keys) == 1) + var/lock_key = lock_keys[1] + var/obj/item/key/new_key = new(get_turf(H), lock_keys[lock_key] || /decl/material/solid/metal/iron, lock_key) + H.put_in_hands_or_store_or_drop(new_key) + else if(length(lock_keys)) + var/obj/item/keyring/keyring + for(var/lock_key in lock_keys) + if(!keyring) + keyring = new(get_turf(H)) + H.put_in_hands_or_store_or_drop(keyring) + var/obj/item/key/new_key = new(get_turf(H), lock_keys[lock_key] || /decl/material/solid/metal/iron, lock_key) + keyring.storage?.handle_item_insertion(null, new_key) + +/datum/job/proc/get_outfit(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) if(alt_title && alt_titles) . = alt_titles[alt_title] if(allowed_branches && branch) . = allowed_branches[branch.type] || . if(allowed_ranks && grade) . = allowed_ranks[grade.type] || . - . = . || outfit_type - . = outfit_by_type(.) + . ||= outfit_type + return GET_DECL(.) + +/datum/job/proc/create_cash_on_hand(var/mob/living/human/worker, var/datum/money_account/account) + if(!istype(account) || !worker.client?.prefs?.starting_cash_choice) + return 0 + for(var/obj/item/thing in worker.client.prefs.starting_cash_choice.get_cash_objects(worker, account)) + . += thing.get_base_value() + worker.equip_to_storage_or_put_in_hands(thing) + +/datum/job/proc/get_total_starting_money(var/mob/living/human/worker) + . = 4 * rand(75, 100) * economic_power + // Get an average economic power for our background. + var/background_mod = 0 + var/background_count = 0 + for(var/token in worker.background_info) + var/decl/background_detail/background = worker.get_background_datum(token) + if(!isnull(background?.economic_power)) + background_count++ + background_mod += background.economic_power + if(background_count) + background_mod /= background_count + . *= background_mod + // Apply other mods. + . *= global.using_map.salary_modifier + // Apply a 50% bonus per skill level above minimum. + . *= 1 + 2 * (worker.get_skill_value(SKILL_FINANCE) - SKILL_MIN)/(SKILL_MAX - SKILL_MIN) + . = round(.) -/datum/job/proc/setup_account(var/mob/living/carbon/human/H) - if(!account_allowed || (H.mind && H.mind.initial_account)) +/datum/job/proc/setup_account(var/mob/living/human/worker) + if(!account_allowed || worker.mind?.initial_account) return // Calculate our pay and apply all relevant modifiers. - var/money_amount = 4 * rand(75, 100) * economic_power - - // Get an average economic power for our cultures. - var/culture_mod = 0 - var/culture_count = 0 - for(var/token in H.cultural_info) - var/decl/cultural_info/culture = H.get_cultural_value(token) - if(culture && !isnull(culture.economic_power)) - culture_count++ - culture_mod += culture.economic_power - if(culture_count) - culture_mod /= culture_count - money_amount *= culture_mod - - // Apply other mods. - money_amount *= GLOB.using_map.salary_modifier - money_amount *= 1 + 2 * H.get_skill_value(SKILL_FINANCE)/(SKILL_MAX - SKILL_MIN) - money_amount = round(money_amount) - + var/money_amount = get_total_starting_money(worker) if(money_amount <= 0) return // You are too poor for an account. //give them an account in the station database - var/datum/money_account/M = create_account("[H.real_name]'s account", H.real_name, money_amount) - if(H.mind) + var/datum/money_account/account = create_account("[worker.real_name]'s account", worker.real_name, money_amount) + var/cash_on_hand = create_cash_on_hand(worker, account) + // Store their financial info. + if(worker.mind) var/remembered_info = "" - remembered_info += "Your account number is: #[M.account_number]
    " - remembered_info += "Your account pin is: [M.remote_access_pin]
    " - remembered_info += "Your account funds are: [M.format_value_by_currency(M.money)]
    " - - if(M.transaction_log.len) - var/datum/transaction/T = M.transaction_log[1] - remembered_info += "Your account was created: [T.time], [T.date] at [T.get_source_name()]
    " - H.StoreMemory(remembered_info, /decl/memory_options/system) - H.mind.initial_account = M + remembered_info += "Your account number is: #[account.account_number]
    " + remembered_info += "Your account pin is: [account.remote_access_pin]
    " + remembered_info += "Your account funds are: [account.format_value_by_currency(account.money)]
    " + if(account.transaction_log.len) + var/datum/transaction/transaction = account.transaction_log[1] + remembered_info += "Your account was created: [transaction.time], [transaction.date] at [transaction.get_source_name()]
    " + if(cash_on_hand > 0) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) + remembered_info += "Your cash on hand is: [cur.format_value(cash_on_hand)]
    " + worker.StoreMemory(remembered_info, /decl/memory_options/system) + worker.mind.initial_account = account + for(var/obj/item/card/id/I in worker.GetIdCards()) + if(!I.associated_account_number) + I.associated_account_number = account.account_number + break // overrideable separately so AIs/borgs can have cardborg hats without unneccessary new()/qdel() -/datum/job/proc/equip_preview(mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade, var/additional_skips) - var/decl/hierarchy/outfit/outfit = get_outfit(H, alt_title, branch, grade) +/datum/job/proc/equip_preview(mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade, var/additional_skips) + var/decl/outfit/outfit = get_outfit(H, alt_title, branch, grade) if(!outfit) return FALSE - . = outfit.equip(H, title, alt_title, OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP|OUTFIT_ADJUSTMENT_SKIP_ID_PDA|additional_skips) + . = outfit.equip_outfit(H, alt_title || title, equip_adjustments = (OUTFIT_ADJUSTMENT_SKIP_POST_EQUIP|OUTFIT_ADJUSTMENT_SKIP_ID_PDA|additional_skips), job = src, rank = grade) /datum/job/proc/get_access() - if(minimal_access.len && (!config || config.jobs_have_minimal_access)) + if(minimal_access.len && get_config_value(/decl/config/toggle/on/jobs_have_minimal_access)) return minimal_access?.Copy() - else - return access?.Copy() + return access?.Copy() //If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 /datum/job/proc/player_old_enough(client/C) return (available_in_days(C) == 0) //Available in 0 days = available right now = player is old enough to play. /datum/job/proc/available_in_days(client/C) - if(C && config.use_age_restriction_for_jobs && isnull(C.holder) && isnum(C.player_age) && isnum(minimal_player_age)) + if(C && get_config_value(/decl/config/num/use_age_restriction_for_jobs) && isnull(C.holder) && isnum(C.player_age) && isnum(minimal_player_age)) return max(0, minimal_player_age - C.player_age) return 0 -/datum/job/proc/apply_fingerprints(var/mob/living/carbon/human/target) +/datum/job/proc/apply_fingerprints(var/mob/living/human/target) if(!istype(target)) return 0 for(var/obj/item/item in target.contents) apply_fingerprints_to_item(target, item) return 1 -/datum/job/proc/apply_fingerprints_to_item(var/mob/living/carbon/human/holder, var/obj/item/item) +/datum/job/proc/apply_fingerprints_to_item(var/mob/living/human/holder, var/obj/item/item) item.add_fingerprint(holder,1) if(item.contents.len) for(var/obj/item/sub_item in item.contents) @@ -186,13 +234,13 @@ to_chat(feedback, "Wrong rank for [title]. Valid ranks in [prefs.branches[title]] are: [get_ranks(prefs.branches[title])].") return TRUE - var/datum/species/S = get_species_by_key(prefs.species) + var/decl/species/S = prefs.get_species_decl() if(!is_species_allowed(S)) to_chat(feedback, "Restricted species, [S], for [title].") return TRUE - if(LAZYACCESS(minimum_character_age, S.get_root_species_name()) && (prefs.age < minimum_character_age[S.get_root_species_name()])) - to_chat(feedback, "Not old enough. Minimum character age is [minimum_character_age[S.get_root_species_name()]].") + if(LAZYACCESS(minimum_character_age, S.uid) && (prefs.get_character_age() < minimum_character_age[S.uid])) + to_chat(feedback, "Not old enough. Minimum character age is [minimum_character_age[S.uid]].") return TRUE if(!S.check_background(src, prefs)) @@ -206,13 +254,13 @@ return FALSE -/datum/job/proc/get_join_link(var/client/caller, var/href_string, var/show_invalid_jobs) - if(is_available(caller)) - if(is_restricted(caller.prefs)) +/datum/job/proc/get_join_link(var/client/calling_client, var/href_string, var/show_invalid_jobs) + if(is_available(calling_client)) + if(is_restricted(calling_client.prefs)) if(show_invalid_jobs) - return "[title][current_positions](Active: [get_active_count()])" + return "[title]
    [current_positions]
    Active: [get_active_count()]
    " else - return "[title][current_positions](Active: [get_active_count()])" + return "[title]
    [current_positions]
    Active: [get_active_count()]
    " return "" // Only players with the job assigned and AFK for less than 10 minutes count as active @@ -221,21 +269,21 @@ /datum/job/proc/get_active_count() var/active = 0 - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(check_is_active(M)) active++ return active -/datum/job/proc/is_species_allowed(var/datum/species/S) - if(GLOB.using_map.is_species_job_restricted(S, src)) +/datum/job/proc/is_species_allowed(var/decl/species/S) + if(global.using_map.is_species_job_restricted(S, src)) return FALSE // We also make sure that there is at least one valid branch-rank combo for the species. - if(!allowed_branches || !GLOB.using_map || !(GLOB.using_map.flags & MAP_HAS_BRANCH)) + if(!allowed_branches || !global.using_map || !(global.using_map.flags & MAP_HAS_BRANCH)) return TRUE return LAZYLEN(get_branch_rank(S)) // Don't use if the map doesn't use branches but jobs do. -/datum/job/proc/get_branch_rank(var/datum/species/S) +/datum/job/proc/get_branch_rank(var/decl/species/S) . = species_branch_rank_cache_[S] if(.) return @@ -243,11 +291,11 @@ species_branch_rank_cache_[S] = list() . = species_branch_rank_cache_[S] - var/spawn_branches = mil_branches.spawn_branches(S) + var/spawn_branches = global.using_map.spawn_branches(S) for(var/branch_type in allowed_branches) - var/datum/mil_branch/branch = mil_branches.get_branch_by_type(branch_type) + var/datum/mil_branch/branch = global.using_map.get_branch_by_type(branch_type) if(branch.name in spawn_branches) - if(!allowed_ranks || !(GLOB.using_map.flags & MAP_HAS_RANK)) + if(!allowed_ranks || !(global.using_map.flags & MAP_HAS_RANK)) LAZYADD(., branch.name) continue // Screw this rank stuff, we're good. var/spawn_ranks = branch.spawn_ranks(S) @@ -264,15 +312,15 @@ * branch_name - String key for the branch to check */ /datum/job/proc/is_branch_allowed(var/branch_name) - if(!allowed_branches || !GLOB.using_map || !(GLOB.using_map.flags & MAP_HAS_BRANCH)) + if(!allowed_branches || !global.using_map || !(global.using_map.flags & MAP_HAS_BRANCH)) return 1 if(branch_name == "None") return 0 - var/datum/mil_branch/branch = mil_branches.get_branch(branch_name) + var/datum/mil_branch/branch = global.using_map.get_branch(branch_name) if(!branch) - crash_with("unknown branch \"[branch_name]\" passed to is_branch_allowed()") + PRINT_STACK_TRACE("unknown branch \"[branch_name]\" passed to is_branch_allowed()") return 0 if(is_type_in_list(branch, allowed_branches)) @@ -289,15 +337,15 @@ * rank_name - String key for the rank itself */ /datum/job/proc/is_rank_allowed(var/branch_name, var/rank_name) - if(!allowed_ranks || !GLOB.using_map || !(GLOB.using_map.flags & MAP_HAS_RANK)) + if(!allowed_ranks || !global.using_map || !(global.using_map.flags & MAP_HAS_RANK)) return 1 if(branch_name == "None" || rank_name == "None") return 0 - var/datum/mil_rank/rank = mil_branches.get_rank(branch_name, rank_name) + var/datum/mil_rank/rank = global.using_map.get_rank(branch_name, rank_name) if(!rank) - crash_with("unknown rank \"[rank_name]\" in branch \"[branch_name]\" passed to is_rank_allowed()") + PRINT_STACK_TRACE("unknown rank \"[rank_name]\" in branch \"[branch_name]\" passed to is_rank_allowed()") return 0 if(is_type_in_list(rank, allowed_ranks)) @@ -307,75 +355,83 @@ //Returns human-readable list of branches this job allows. /datum/job/proc/get_branches() - var/list/res = list() - for(var/T in allowed_branches) - var/datum/mil_branch/B = mil_branches.get_branch_by_type(T) - res += B.name - return english_list(res) + . = list() + for(var/branch in allowed_branches) + var/datum/mil_branch/branch_datum = global.using_map.get_branch_by_type(branch) + . += branch_datum.name + return english_list(.) //Same as above but ranks /datum/job/proc/get_ranks(branch) - var/list/res = list() - var/datum/mil_branch/B = mil_branches.get_branch(branch) - for(var/T in allowed_ranks) - var/datum/mil_rank/R = T - if(B && !(initial(R.name) in B.ranks)) + . = list() + var/datum/mil_branch/branch_datum = global.using_map.get_branch(branch) + for(var/datum/mil_rank/rank as anything in allowed_ranks) + if(branch_datum && !(initial(rank.name) in branch_datum.ranks)) continue - res |= initial(R.name) - return english_list(res) + . |= initial(rank.name) + return english_list(.) /datum/job/proc/get_description_blurb() - return "" + return description /datum/job/proc/get_job_icon() if(!SSjobs.job_icons[title]) - var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin("#job_icon") - dress_mannequin(mannequin) - mannequin.set_dir(SOUTH) - var/icon/preview_icon = getFlatIcon(mannequin) - preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. - SSjobs.job_icons[title] = preview_icon + var/mob/living/human/dummy/mannequin/mannequin = get_mannequin("#job_icon") + if(mannequin) + var/decl/species/mannequin_species = decls_repository.get_decl_by_id(global.using_map.default_species) + if(!is_species_allowed(mannequin_species)) + // Don't just default to the first species allowed, pick one at random. + for(var/other_species in shuffle(get_playable_species())) + var/decl/species/other_species_decl = decls_repository.get_decl_by_id(other_species) + if(is_species_allowed(other_species_decl)) + mannequin_species = other_species_decl + break + if(!is_species_allowed(mannequin_species)) + PRINT_STACK_TRACE("No allowed species allowed for job [title] ([type]), falling back to default!") + mannequin.change_species(mannequin_species.uid) + dress_mannequin(mannequin) + mannequin.set_dir(SOUTH) + var/icon/preview_icon = getFlatIcon(mannequin) + preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. + SSjobs.job_icons[title] = preview_icon return SSjobs.job_icons[title] -/datum/job/proc/get_unavailable_reasons(var/client/caller) +/datum/job/proc/get_unavailable_reasons(var/client/calling_client) var/list/reasons = list() - if(jobban_isbanned(caller, title)) + if(jobban_isbanned(calling_client, title)) reasons["You are jobbanned."] = TRUE - if(is_semi_antagonist && jobban_isbanned(caller, MODE_MISC_AGITATOR)) - reasons["You are semi-antagonist banned."] = TRUE - if(!player_old_enough(caller)) + if(!player_old_enough(calling_client)) reasons["Your player age is too low."] = TRUE if(!is_position_available()) reasons["There are no positions left."] = TRUE - if(!isnull(allowed_branches) && (!caller.prefs.branches[title] || !is_branch_allowed(caller.prefs.branches[title]))) + if(!isnull(allowed_branches) && (!calling_client.prefs.branches[title] || !is_branch_allowed(calling_client.prefs.branches[title]))) reasons["Your branch of service does not allow it."] = TRUE - else if(!isnull(allowed_ranks) && (!caller.prefs.ranks[title] || !is_rank_allowed(caller.prefs.branches[title], caller.prefs.ranks[title]))) + else if(!isnull(allowed_ranks) && (!calling_client.prefs.ranks[title] || !is_rank_allowed(calling_client.prefs.branches[title], calling_client.prefs.ranks[title]))) reasons["Your rank choice does not allow it."] = TRUE - var/datum/species/S = get_species_by_key(caller.prefs.species) + var/decl/species/S = calling_client.prefs.get_species_decl() if(S) if(!is_species_allowed(S)) reasons["Your species choice does not allow it."] = TRUE - if(!S.check_background(src, caller.prefs)) + if(!S.check_background(src, calling_client.prefs)) reasons["Your background choices do not allow it."] = TRUE - var/special_blocker = check_special_blockers(caller.prefs) + var/special_blocker = check_special_blockers(calling_client.prefs) if(special_blocker) reasons["Your preferences do not allow it: '[special_blocker]'."] = TRUE return TRUE if(LAZYLEN(reasons)) . = reasons -/datum/job/proc/dress_mannequin(var/mob/living/carbon/human/dummy/mannequin/mannequin) - mannequin.delete_inventory(TRUE) - equip_preview(mannequin, additional_skips = OUTFIT_ADJUSTMENT_SKIP_BACKPACK) +/datum/job/proc/dress_mannequin(var/mob/living/human/dummy/mannequin/mannequin) + if(mannequin) + mannequin.delete_inventory(TRUE) + equip_preview(mannequin, additional_skips = OUTFIT_ADJUSTMENT_SKIP_BACKPACK) -/datum/job/proc/is_available(var/client/caller) +/datum/job/proc/is_available(var/client/calling_client) if(!is_position_available()) return FALSE - if(jobban_isbanned(caller, title)) + if(jobban_isbanned(calling_client, title)) return FALSE - if(is_semi_antagonist && jobban_isbanned(caller, MODE_MISC_AGITATOR)) - return FALSE - if(!player_old_enough(caller)) + if(!player_old_enough(calling_client)) return FALSE return TRUE @@ -384,7 +440,7 @@ /datum/job/proc/get_roundstart_spawnpoint() var/list/loc_list = list() - for(var/obj/effect/landmark/start/sloc in landmarks_list) + for(var/obj/abstract/landmark/start/sloc in global.all_landmarks) if(sloc.name != title) continue if(locate(/mob/living) in sloc.loc) continue loc_list += sloc @@ -394,7 +450,7 @@ return locate("start*[title]") // use old stype /** - * Return appropriate /datum/spawnpoint for given client + * Return appropriate /decl/spawnpoint for given client * * Spawnpoint will be the one set in preferences for the client, unless the * preference is not set, or the preference is not appropriate for the rank, in @@ -406,46 +462,24 @@ CRASH("Null client passed to get_spawnpoint_for() proc!") var/mob/H = C.mob - var/spawnpoint = C.prefs.spawnpoint - var/datum/spawnpoint/spawnpos - - if(forced_spawnpoint) - spawnpoint = forced_spawnpoint - if(spawnpoint == DEFAULT_SPAWNPOINT_ID) - spawnpoint = GLOB.using_map.default_spawn - - if(spawnpoint) - if(!(spawnpoint in GLOB.using_map.allowed_spawns)) - if(H) - to_chat(H, "Your chosen spawnpoint ([C.prefs.spawnpoint]) is unavailable for the current map. Spawning you at one of the enabled spawn points instead. To resolve this error head to your character's setup and choose a different spawn point.") - spawnpos = null - else - spawnpos = spawntypes()[spawnpoint] - - if(spawnpos && !spawnpos.check_job_spawning(title)) + var/spawntype = forced_spawnpoint || C.prefs.spawnpoint || global.using_map.default_spawn + var/decl/spawnpoint/spawnpos = GET_DECL(spawntype) + if(spawnpos && !spawnpos.check_job_spawning(src)) if(H) - to_chat(H, "Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job ([title]). Spawning you at another spawn point instead.") + to_chat(H, SPAN_WARNING("Your chosen spawnpoint ([spawnpos.name]) is unavailable for your chosen job ([title]). Spawning you at another spawn point instead.")) spawnpos = null - if(!spawnpos) // Step through all spawnpoints and pick first appropriate for job - for(var/spawntype in GLOB.using_map.allowed_spawns) - var/datum/spawnpoint/candidate = spawntypes()[spawntype] - if(candidate.check_job_spawning(title)) + for(var/decl/spawnpoint/candidate as anything in global.using_map.allowed_latejoin_spawns) + if(candidate?.check_job_spawning(src)) spawnpos = candidate break - - if(!spawnpos) - // Pick at random from all the (wrong) spawnpoints, just so we have one - warning("Could not find an appropriate spawnpoint for job [title].") - spawnpos = spawntypes()[pick(GLOB.using_map.allowed_spawns)] - return spawnpos -/datum/job/proc/post_equip_rank(var/mob/person, var/alt_title) - if(is_semi_antagonist && person.mind) - GLOB.provocateurs.add_antagonist(person.mind) +/// Used for applying "finishing touches" to characters, like additional role text or applying a /decl/special_role. +/datum/job/proc/post_equip_job_title(var/mob/person, var/alt_title, var/rank) + return /datum/job/proc/get_alt_title_for(var/client/C) return C.prefs.GetPlayerAltTitle(src) @@ -456,8 +490,17 @@ return TRUE return FALSE -/datum/job/proc/handle_variant_join(var/mob/living/carbon/human/H, var/alt_title) +/datum/job/proc/handle_variant_join(var/mob/living/human/H, var/alt_title) return /datum/job/proc/check_special_blockers(var/datum/preferences/prefs) - return \ No newline at end of file + return + +/datum/job/proc/do_spawn_special(var/mob/living/character, var/mob/new_player/new_player_mob, var/latejoin = FALSE) + return FALSE + +/datum/job/proc/get_occupations_tab_sort_score() + . = (0.1 * head_position) + if(primary_department) + var/decl/department/dept = GET_DECL(primary_department) + . += dept.display_priority diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm deleted file mode 100644 index 6d72068520d7..000000000000 --- a/code/game/jobs/job/assistant.dm +++ /dev/null @@ -1,21 +0,0 @@ -/datum/job/assistant - title = "Assistant" - department_refs = list(DEPT_CIVILIAN) - - total_positions = -1 - spawn_positions = -1 - supervisors = "absolutely everyone" - economic_power = 1 - access = list() //See /datum/job/assistant/get_access() - minimal_access = list() //See /datum/job/assistant/get_access() - alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Visitor") - outfit_type = /decl/hierarchy/outfit/job/assistant - -/datum/job/assistant/get_access() - if(config.assistant_maint) - return list(access_maint_tunnels) - else - return list() - -/decl/hierarchy/outfit/job/assistant - name = OUTFIT_JOB_NAME("Assistant") diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm deleted file mode 100644 index 9d22acde8b67..000000000000 --- a/code/game/jobs/job/silicon.dm +++ /dev/null @@ -1,59 +0,0 @@ -/datum/job/ai - title = "AI" - department_refs = list(DEPT_MISC) - - total_positions = 0 // Not used for AI, see is_position_available below and modules/mob/living/silicon/ai/latejoin.dm - spawn_positions = 1 - selection_color = "#3f823f" - supervisors = "your laws" - req_admin_notify = 1 - minimal_player_age = 14 - account_allowed = 0 - economic_power = 0 - outfit_type = /decl/hierarchy/outfit/job/silicon/ai - loadout_allowed = FALSE - hud_icon = "hudblank" - skill_points = 0 - no_skill_buffs = TRUE - guestbanned = 1 - not_random_selectable = 1 - -/datum/job/ai/equip(var/mob/living/carbon/human/H) - if(!H) return 0 - return 1 - -/datum/job/ai/is_position_available() - return (empty_playable_ai_cores.len != 0) - -/datum/job/ai/handle_variant_join(var/mob/living/carbon/human/H, var/alt_title) - return H - -/datum/job/cyborg - title = "Robot" - department_refs = list(DEPT_MISC) - total_positions = 2 - spawn_positions = 2 - supervisors = "your laws and the AI" - selection_color = "#254c25" - minimal_player_age = 7 - account_allowed = 0 - economic_power = 0 - loadout_allowed = FALSE - outfit_type = /decl/hierarchy/outfit/job/silicon/cyborg - hud_icon = "hudblank" - skill_points = 0 - no_skill_buffs = TRUE - guestbanned = 1 - not_random_selectable = 1 - -/datum/job/cyborg/handle_variant_join(var/mob/living/carbon/human/H, var/alt_title) - if(H) - return H.Robotize(SSrobots.get_mob_type_by_title(alt_title || title)) - -/datum/job/cyborg/equip(var/mob/living/carbon/human/H) - return !!H - -/datum/job/cyborg/New() - ..() - alt_titles = SSrobots.robot_alt_titles.Copy() - alt_titles -= title // So the unit test doesn't flip out if a mob or mmi type is declared for our main title. diff --git a/code/game/jobs/server_whitelist.dm b/code/game/jobs/server_whitelist.dm new file mode 100644 index 000000000000..da26aaeea7cf --- /dev/null +++ b/code/game/jobs/server_whitelist.dm @@ -0,0 +1,121 @@ +var/global/list/server_whitelist + +/proc/check_server_whitelist(ckey) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_NO_WHITELIST) + return TRUE + if(ismob(ckey)) + var/mob/checking = ckey + ckey = checking.ckey + if(!istext(ckey)) + return FALSE + if(!global.server_whitelist) + global.server_whitelist = file2list(CONFIG_SERVER_WHITELIST_FILE) || list() + return (ckey in global.server_whitelist) + +/proc/save_server_whitelist() + // Ensure we have the server whitelist loaded regardless of config or prior call. + if(!global.server_whitelist) + global.server_whitelist = file2list(CONFIG_SERVER_WHITELIST_FILE) || list() + + // Clear blank rows. + while(null in global.server_whitelist) + global.server_whitelist -= null + while("" in global.server_whitelist) + global.server_whitelist -= "" + + // Remove old list rather than append. + if(fexists(CONFIG_SERVER_WHITELIST_FILE)) + fdel(CONFIG_SERVER_WHITELIST_FILE) + // Write our list out. + var/write_file = file(CONFIG_SERVER_WHITELIST_FILE) + to_file(write_file, jointext(global.server_whitelist, "\n")) + +var/global/list/alien_whitelist = list() +/proc/try_load_alien_whitelist() + if(get_config_value(/decl/config/toggle/use_alien_whitelist)) + if(get_config_value(/decl/config/toggle/use_alien_whitelist_sql)) + if(!load_alienwhitelistSQL()) + to_world_log("Could not load alienwhitelist via SQL") + else + load_alienwhitelist() + return 1 + +/proc/load_alienwhitelist() + var/text = safe_file2text("config/alienwhitelist.txt", FALSE) + if (!text) + log_misc("Failed to load config/alienwhitelist.txt") + return FALSE + alien_whitelist = splittext(text, "\n") + to_world_log("Loaded [length(alien_whitelist)] whitelist [length(alien_whitelist) == 1 ? "entry" : "entries"] from text file.") + return TRUE + +/proc/load_alienwhitelistSQL() + var/DBQuery/query = dbcon.NewQuery("SELECT * FROM `whitelist`") + if(!query.Execute()) + to_world_log(dbcon.ErrorMsg()) + return FALSE + while(query.NextRow()) + var/list/row = query.GetRowData() + if(alien_whitelist[row["ckey"]]) + var/list/A = alien_whitelist[row["ckey"]] + A.Add(row["race"]) + else + alien_whitelist[row["ckey"]] = list(row["race"]) + return TRUE + +/proc/is_species_whitelisted(mob/M, var/species_uid) + var/decl/species/S = decls_repository.get_decl_by_id(species_uid) + return is_alien_whitelisted(M, S) + +/proc/is_alien_whitelisted(mob/M, var/species) + + if(!M || !species) + return FALSE + + // Forbidden languages do not care about admin rights. + if(istype(species,/decl/language)) + var/decl/language/L = species + if(L.flags & LANG_FLAG_FORBIDDEN) + return FALSE + + if(check_rights(R_ADMIN, FALSE, M)) + return TRUE + + if(istype(species,/decl/language)) + var/decl/language/L = species + if(L.flags & LANG_FLAG_RESTRICTED) + return FALSE + if(!get_config_value(/decl/config/toggle/use_alien_whitelist) || !(L.flags & LANG_FLAG_WHITELISTED)) + return TRUE + return whitelist_lookup(L.name, M.ckey) + + if(istype(species,/decl/species)) + var/decl/species/S = species + if(S.spawn_flags & SPECIES_IS_RESTRICTED) + return FALSE + if(!get_config_value(/decl/config/toggle/use_alien_whitelist) || !(S.spawn_flags & SPECIES_IS_WHITELISTED)) + return TRUE + return whitelist_lookup(S.uid, M.ckey) || whitelist_lookup(S.name, M.ckey) + + // Check for arbitrary text whitelisting. + return istext(species) ? whitelist_lookup(species, M.ckey) : FALSE + +/proc/whitelist_lookup(var/item, var/ckey) + if(!alien_whitelist) + return FALSE + + if(get_config_value(/decl/config/toggle/use_alien_whitelist_sql)) + //SQL Whitelist + if(!(ckey in alien_whitelist)) + return FALSE + var/list/whitelisted = alien_whitelist[ckey] + if(lowertext(item) in whitelisted) + return TRUE + else + //Config File Whitelist + for(var/s in alien_whitelist) + if(findtext(s,"[ckey] - [item]")) + return TRUE + if(findtext(s,"[ckey] - All")) + return TRUE + return FALSE diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm deleted file mode 100644 index 8f905bb9c68e..000000000000 --- a/code/game/jobs/whitelist.dm +++ /dev/null @@ -1,99 +0,0 @@ -#define WHITELISTFILE "data/whitelist.txt" - -var/list/whitelist = list() - -/hook/startup/proc/loadWhitelist() - if(config.usewhitelist) - load_whitelist() - return 1 - -/proc/load_whitelist() - whitelist = file2list(WHITELISTFILE) - if(!whitelist.len) whitelist = null - -/proc/check_whitelist(mob/M /*, var/rank*/) - if(!whitelist) - return 0 - return ("[M.ckey]" in whitelist) - -/var/list/alien_whitelist = list() - -/hook/startup/proc/loadAlienWhitelist() - if(config.usealienwhitelist) - if(config.usealienwhitelistSQL) - if(!load_alienwhitelistSQL()) - to_world_log("Could not load alienwhitelist via SQL") - else - load_alienwhitelist() - return 1 -/proc/load_alienwhitelist() - var/text = file2text("config/alienwhitelist.txt") - if (!text) - log_misc("Failed to load config/alienwhitelist.txt") - return 0 - else - alien_whitelist = splittext(text, "\n") - return 1 -/proc/load_alienwhitelistSQL() - var/DBQuery/query = dbcon_old.NewQuery("SELECT * FROM `whitelist`") - if(!query.Execute()) - to_world_log(dbcon_old.ErrorMsg()) - return 0 - else - while(query.NextRow()) - var/list/row = query.GetRowData() - if(alien_whitelist[row["ckey"]]) - var/list/A = alien_whitelist[row["ckey"]] - A.Add(row["race"]) - else - alien_whitelist[row["ckey"]] = list(row["race"]) - return 1 - -/proc/is_species_whitelisted(mob/M, var/species_name) - var/datum/species/S = get_species_by_key(species_name) - return is_alien_whitelisted(M, S) - -//todo: admin aliens -/proc/is_alien_whitelisted(mob/M, var/species) - if(!M || !species) - return 0 - if(!config.usealienwhitelist) - return 1 - if(check_rights(R_ADMIN, 0, M)) - return 1 - - if(istype(species,/decl/language)) - var/decl/language/L = species - if(!(L.flags & (WHITELISTED|RESTRICTED))) - return 1 - return whitelist_lookup(L.name, M.ckey) - - if(istype(species,/datum/species)) - var/datum/species/S = species - if(!(S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_IS_RESTRICTED))) - return 1 - return whitelist_lookup(S.get_root_species_name(M), M.ckey) - - return 0 - -/proc/whitelist_lookup(var/item, var/ckey) - if(!alien_whitelist) - return 0 - - if(config.usealienwhitelistSQL) - //SQL Whitelist - if(!(ckey in alien_whitelist)) - return 0; - var/list/whitelisted = alien_whitelist[ckey] - if(lowertext(item) in whitelisted) - return 1 - else - //Config File Whitelist - for(var/s in alien_whitelist) - if(findtext(s,"[ckey] - [item]")) - return 1 - if(findtext(s,"[ckey] - All")) - return 1 - return 0 - -#undef WHITELISTFILE diff --git a/code/game/machinery/Beacon.dm b/code/game/machinery/Beacon.dm index 9648d1ab6e4d..64a47117c6b7 100644 --- a/code/game/machinery/Beacon.dm +++ b/code/game/machinery/Beacon.dm @@ -3,18 +3,18 @@ icon_state = "floor_beaconf" name = "tracking beacon" desc = "A device that uses zero-point energy to create a permanent tracking beacon." - level = 1 // underfloor - anchored = 1 + level = LEVEL_BELOW_PLATING + anchored = TRUE idle_power_usage = 0 var/obj/item/radio/beacon/beacon /obj/machinery/tracking_beacon/Initialize() . = ..() var/turf/T = get_turf(src) - beacon = new /obj/item/radio/beacon(T) - beacon.invisibility = INVISIBILITY_MAXIMUM - - hide(!T.is_plating()) + if(T) + beacon = new /obj/item/radio/beacon(T) + beacon.set_invisibility(INVISIBILITY_MAXIMUM) + hide(!T?.is_plating()) /obj/machinery/tracking_beacon/Destroy() QDEL_NULL(beacon) @@ -36,11 +36,10 @@ icon_state = "[state]" /obj/machinery/tracking_beacon/Process() - if(!beacon) - beacon = new /obj/item/radio/beacon(get_turf(src)) + var/turf/my_turf = get_turf(src) + if(!beacon && my_turf) + beacon = new /obj/item/radio/beacon(my_turf) beacon.set_invisibility(INVISIBILITY_MAXIMUM) - if(beacon) - if(beacon.loc != loc) - beacon.forceMove(loc) - + if(beacon && beacon.loc != my_turf) + beacon.forceMove(my_turf) update_icon() \ No newline at end of file diff --git a/code/game/machinery/CableLayer.dm b/code/game/machinery/CableLayer.dm index 1f04fc7f78aa..ee1ee91f4aa3 100644 --- a/code/game/machinery/CableLayer.dm +++ b/code/game/machinery/CableLayer.dm @@ -2,7 +2,8 @@ name = "automatic cable layer" icon = 'icons/obj/machines/pipe_dispenser.dmi' icon_state = "pipe_d" - density = 1 + density = TRUE + interact_offline = TRUE var/obj/structure/cable/last_piece var/obj/item/stack/cable_coil/cable var/max_cable = 100 @@ -14,7 +15,7 @@ cable.amount = 100 /obj/machinery/cablelayer/Move(new_turf,M_Dir) - ..() + . = ..() layCable(new_turf,M_Dir) /obj/machinery/cablelayer/physical_attack_hand(mob/user) @@ -25,19 +26,19 @@ user.visible_message("\The [user] [!on?"dea":"a"]ctivates \the [src].", "You switch [src] [on? "on" : "off"]") return TRUE -/obj/machinery/cablelayer/attackby(var/obj/item/O, var/mob/user) - if(istype(O, /obj/item/stack/cable_coil)) +/obj/machinery/cablelayer/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/stack/cable_coil)) - var/result = load_cable(O) + var/result = load_cable(used_item) if(!result) to_chat(user, "\The [src]'s cable reel is full.") else to_chat(user, "You load [result] lengths of cable into [src].") - return + return TRUE - if(isWirecutter(O)) + if(IS_WIRECUTTER(used_item)) if(cable && cable.amount) - var/m = round(input(usr,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) + var/m = round(input(user,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) m = min(m, cable.amount) m = min(m, 30) if(m) @@ -46,11 +47,13 @@ var/obj/item/stack/cable_coil/CC = new (get_turf(src)) CC.amount = m else - to_chat(usr, "There's no more cable on the reel.") + to_chat(user, "There's no more cable on the reel.") + return TRUE + return ..() -/obj/machinery/cablelayer/examine(mob/user) +/obj/machinery/cablelayer/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "\The [src]'s cable reel has [cable.amount] length\s left.") + . += "\The [src]'s cable reel has [cable.amount] length\s left." /obj/machinery/cablelayer/proc/load_cable(var/obj/item/stack/cable_coil/CC) if(istype(CC) && CC.amount) @@ -80,19 +83,19 @@ /obj/machinery/cablelayer/proc/reset() last_piece = null -/obj/machinery/cablelayer/proc/dismantleFloor(var/turf/new_turf) - if(istype(new_turf, /turf/simulated/floor)) - var/turf/simulated/floor/T = new_turf +/obj/machinery/cablelayer/proc/dismantle_floor(var/turf/new_turf) + if(istype(new_turf, /turf/floor)) + var/turf/floor/T = new_turf if(!T.is_plating()) - T.make_plating(!(T.broken || T.burnt)) + T.clear_flooring(place_product = !T.is_floor_damaged()) return new_turf.is_plating() /obj/machinery/cablelayer/proc/layCable(var/turf/new_turf,var/M_Dir) if(!on) return reset() else - dismantleFloor(new_turf) - if(!istype(new_turf) || !dismantleFloor(new_turf)) + dismantle_floor(new_turf) + if(!istype(new_turf) || !dismantle_floor(new_turf)) return reset() var/fdirn = turn(M_Dir,180) for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index ccb86aea25c5..435834976bc0 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -1,20 +1,18 @@ /obj/machinery/optable - name = "Operating Table" + name = "operating table" desc = "Used for advanced medical procedures." icon = 'icons/obj/surgery.dmi' icon_state = "table2-idle" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE throwpass = 1 idle_power_usage = 1 active_power_usage = 5 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 var/suppressing = FALSE - var/mob/living/carbon/human/victim = null - var/strapped = 0.0 + var/mob/living/victim var/obj/machinery/computer/operating/computer = null /obj/machinery/optable/Initialize() @@ -25,22 +23,15 @@ computer.table = src break -/obj/machinery/optable/examine(mob/user) +/obj/machinery/optable/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, SPAN_NOTICE("The neural suppressors are switched [suppressing ? "on" : "off"].")) + . += SPAN_NOTICE("The neural suppressors are switched [suppressing ? "on" : "off"].") -/obj/machinery/optable/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity == 1 || prob(100 - (25 * severity)))) - physically_destroyed(src) - -/obj/machinery/optable/attackby(var/obj/item/O, var/mob/user) - if (istype(O, /obj/item/grab)) - var/obj/item/grab/G = O - if(iscarbon(G.affecting) && check_table(G.affecting)) - take_victim(G.affecting,usr) - qdel(O) - return +/obj/machinery/optable/grab_attack(obj/item/grab/grab, mob/user) + if(isliving(grab.affecting) && check_table(grab.affecting)) + take_victim(grab.affecting, user) + qdel(grab) + return TRUE return ..() /obj/machinery/optable/state_transition(var/decl/machine_construction/default/new_state) @@ -49,16 +40,15 @@ updateUsrDialog() /obj/machinery/optable/physical_attack_hand(var/mob/user) - if(MUTATION_HULK in user.mutations) - visible_message("\The [usr] destroys \the [src]!") - src.set_density(0) - qdel(src) - return TRUE if(!victim) to_chat(user, "There is nobody on \the [src]. It would be pointless to turn the suppressor on.") return TRUE + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "You try to switch on the suppressor, yet nothing happens.") + return TRUE + if(user != victim && !suppressing) // Skip checks if you're doing it to yourself or turning it off, this is an anti-griefing mechanic more than anything. user.visible_message("\The [user] begins switching on \the [src]'s neural suppressor.") if(!do_after(user, 30, src) || !user || !src || user.incapacitated() || !user.Adjacent(src)) @@ -72,80 +62,74 @@ return TRUE /obj/machinery/optable/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 - - if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) - return 1 - else - return 0 - + . = (air_group || height == 0 || (istype(mover) && mover.checkpass(PASS_FLAG_TABLE))) -/obj/machinery/optable/MouseDrop_T(obj/O, mob/user) - if ((!( istype(O, /obj/item) ) || user.get_active_hand() != O)) - return - if(!user.unequip_item()) - return - if (O.loc != src.loc) - step(O, get_dir(O, src)) +/obj/machinery/optable/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!.) + if(istype(dropping, /obj/item) && user.get_active_held_item() == dropping && user.try_unequip(dropping, loc)) + return FALSE + if(isliving(dropping) && check_table(dropping)) + take_victim(dropping, user) + return FALSE /obj/machinery/optable/proc/check_victim() - if(!victim || !victim.lying || victim.loc != loc) + if(!victim || !victim.current_posture.prone || victim.loc != loc) suppressing = FALSE victim = null - if(locate(/mob/living/carbon/human) in loc) - for(var/mob/living/carbon/human/H in loc) - if(H.lying) - victim = H - break - icon_state = (victim && victim.pulse()) ? "table2-active" : "table2-idle" + for(var/mob/living/human/H in loc) + if(H.current_posture.prone) + victim = H + break if(victim) - if(suppressing && victim.sleeping < 3) - victim.Sleeping(3 - victim.sleeping) - return 1 - return 0 + if(suppressing && GET_STATUS(victim, STAT_ASLEEP) < 3) + SET_STATUS_MAX(victim, STAT_ASLEEP, 3) + . = !!victim + update_icon() + +/obj/machinery/optable/on_update_icon() + icon_state = "table2-idle" + if(ishuman(victim)) + var/mob/living/human/H = victim + if(H.get_pulse()) + icon_state = "table2-active" /obj/machinery/optable/Process() check_victim() -/obj/machinery/optable/proc/take_victim(mob/living/carbon/C, mob/living/carbon/user) - if (C == user) - user.visible_message("[user] climbs on \the [src].","You climb on \the [src].") - else - visible_message("\The [C] has been laid on \the [src] by [user].") - if (C.client) - C.client.perspective = EYE_PERSPECTIVE - C.client.eye = src - C.resting = 1 - C.dropInto(loc) - src.add_fingerprint(user) - if(ishuman(C)) - var/mob/living/carbon/human/H = C - src.victim = H - icon_state = H.pulse() ? "table2-active" : "table2-idle" - else - icon_state = "table2-idle" - -/obj/machinery/optable/MouseDrop_T(mob/target, mob/user) - var/mob/living/M = user - if(user.stat || user.restrained() || !iscarbon(target) || !check_table(target)) - return - if(istype(M)) - take_victim(target,user) +/obj/machinery/optable/proc/take_victim(mob/living/target, mob/living/user) + if (target == user) + user.visible_message( \ + SPAN_NOTICE("\The [user] climbs on \the [src]."), \ + SPAN_NOTICE("You climb on \the [src].")) else - return ..() + visible_message(SPAN_NOTICE("\The [target] has been laid on \the [src] by \the [user].")) + target.dropInto(loc) + target.set_posture(/decl/posture/lying/deliberate) + add_fingerprint(user) + update_icon() /obj/machinery/optable/climb_on() if(usr.stat || !ishuman(usr) || usr.restrained() || !check_table(usr)) return - take_victim(usr,usr) -/obj/machinery/optable/proc/check_table(mob/living/carbon/patient) +/obj/machinery/optable/proc/check_table(mob/living/patient) check_victim() - if(src.victim && get_turf(victim) == get_turf(src) && victim.lying) + if(src.victim && get_turf(victim) == get_turf(src) && victim.current_posture.prone) to_chat(usr, "\The [src] is already occupied!") - return 0 + return FALSE if(patient.buckled) to_chat(usr, "Unbuckle \the [patient] first!") - return 0 - return 1 \ No newline at end of file + return FALSE + if(patient.anchored) + return FALSE + return TRUE + +/obj/machinery/optable/power_change() + . = ..() + if(stat & (NOPOWER|BROKEN)) + suppressing = FALSE + +/obj/machinery/optable/get_surgery_surface_quality(mob/living/victim, mob/living/user) + return OPERATE_IDEAL \ No newline at end of file diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index bae71d3bc7d5..0d703b829e3b 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -15,30 +15,36 @@ active_power_usage = 1 KILOWATTS //builtin health analyzer, dialysis machine, injectors. pixel_z = -8 - var/mob/living/carbon/human/occupant + var/mob/living/human/occupant var/obj/item/chems/glass/beaker = null var/filtering = 0 var/pump + var/lavage = FALSE // Are we rinsing reagents from the lungs? var/list/stasis_settings = list(1, 2, 5, 10) var/stasis = 1 var/pump_speed var/stasis_power = 5 KILOWATTS var/list/loaded_canisters var/max_canister_capacity = 5 - var/global/list/banned_chem_types = list( + var/static/list/banned_chem_types = list( /decl/material/liquid/bromide, /decl/material/liquid/mutagenics, /decl/material/liquid/acid ) + var/open_sound = 'sound/machines/podopen.ogg' + var/close_sound = 'sound/machines/podclose.ogg' /obj/machinery/sleeper/standard/Initialize(mapload, d, populate_parts) . = ..() - add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/adrenaline()) + add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/stabilizer()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/sedatives()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/painkillers()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/antitoxins()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/oxy_meds()) +/obj/machinery/sleeper/get_cryogenic_power() + return stasis + /obj/machinery/sleeper/Destroy() QDEL_NULL(beaker) QDEL_NULL_LIST(loaded_canisters) @@ -53,14 +59,13 @@ to_chat(user, SPAN_WARNING("\The [src] cannot accept any more chemical canisters.")) return FALSE if(!emagged) - for(var/rid in canister.reagents?.reagent_volumes) - var/decl/material/reagent = decls_repository.get_decl(rid) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(canister.reagents)) for(var/banned_type in banned_chem_types) if(istype(reagent, banned_type)) - to_chat(user, SPAN_WARNING("Automatic safety checking indicates the present of a prohibited substance in this canister.")) + to_chat(user, SPAN_WARNING("Automatic safety checking indicates the presence of a prohibited substance in this canister.")) return FALSE var/mob/M = canister.loc - if(istype(M) && !M.unEquip(canister, src)) + if(istype(M) && !M.try_unequip(canister, src)) return FALSE if(canister.loc != src) canister.forceMove(src) @@ -76,75 +81,129 @@ to_chat(user, SPAN_NOTICE("You remove \the [canister] from \the [src].")) return TRUE +/obj/machinery/sleeper/proc/eject_all_reagent_canisters() + for(var/obj/item/canister in loaded_canisters) + canister.dropInto(loc) + LAZYCLEARLIST(loaded_canisters) + +/obj/machinery/sleeper/dismantle() + eject_all_reagent_canisters() + remove_beaker() + return ..() + +/obj/machinery/sleeper/get_contained_external_atoms() + . = ..() + LAZYREMOVE(., loaded_canisters) + LAZYREMOVE(., beaker) + +/obj/machinery/sleeper/get_contained_matter(include_reagents = TRUE) + . = ..() + . = MERGE_ASSOCS_WITH_NUM_VALUES(., beaker.get_contained_matter(include_reagents)) + for(var/obj/canister in loaded_canisters) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., canister.get_contained_matter(include_reagents)) + /obj/machinery/sleeper/Initialize(mapload, d = 0, populate_parts = TRUE) . = ..() if(populate_parts) beaker = new /obj/item/chems/glass/beaker/large(src) update_icon() -/obj/machinery/sleeper/examine(mob/user, distance) +/obj/machinery/sleeper/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if (distance <= 1) if(beaker) - to_chat(user, SPAN_NOTICE("It is loaded with a beaker.")) + . += SPAN_NOTICE("It is loaded with \a [beaker].") if(occupant) - occupant.examine(arglist(args)) + . += occupant.get_examine_strings(user, distance, infix, suffix) if(emagged && user.skill_check(SKILL_MEDICAL, SKILL_EXPERT)) - to_chat(user, SPAN_NOTICE("The chemical input system looks like it has been tampered with.")) + . += SPAN_NOTICE("The chemical input system looks like it has been tampered with.") if(length(loaded_canisters)) - to_chat(user, SPAN_NOTICE("There are [length(loaded_canisters)] chemical canister\s loaded:")) + . += SPAN_NOTICE("There are [length(loaded_canisters)] chemical canister\s loaded:") for(var/thing in loaded_canisters) - to_chat(user, SPAN_NOTICE("- \The [thing]")) + . += SPAN_NOTICE("- \The [thing]") else - to_chat(user, SPAN_NOTICE("There are no chemical canisters loaded.")) + . += SPAN_NOTICE("There are no chemical canisters loaded.") + +/obj/machinery/sleeper/proc/has_room_in_beaker() + return beaker && REAGENT_TOTAL_VOLUME(beaker.reagents) < REAGENT_MAXIMUM_VOLUME(beaker.reagents) /obj/machinery/sleeper/Process() if(stat & (NOPOWER|BROKEN)) return - if(filtering > 0) - if(beaker) - if(beaker.reagents.total_volume < beaker.reagents.maximum_volume) - var/pumped = LAZYLEN(occupant.reagents?.reagent_volumes) - if(pumped) - occupant.reagents.trans_to_obj(beaker, pump_speed * pumped) - occupant.vessel.trans_to_obj(beaker, pumped + 1) + if(!istype(occupant)) + if(filtering) + toggle_filter() + if(pump) + toggle_pump() + if(lavage) + toggle_lavage() + return + + if(filtering) + if(has_room_in_beaker()) + var/trans_volumes = REAGENT_VOLUMES(occupant.reagents) + var/trans_volume = LAZYLEN(trans_volumes) + if(trans_volume) + occupant.reagents.trans_to_obj(beaker, pump_speed * trans_volume) + occupant.vessel.trans_to_obj(beaker, trans_volume + 1) else toggle_filter() - if(pump > 0) - if(beaker && istype(occupant)) - if(beaker.reagents.total_volume < beaker.reagents.maximum_volume) - var/datum/reagents/ingested = occupant.get_ingested_reagents() - if(ingested) - var/trans_amt = LAZYLEN(ingested.reagent_volumes) - if(trans_amt) - ingested.trans_to_obj(beaker, pump_speed * trans_amt) + + if(pump) + if(has_room_in_beaker()) + var/datum/reagents/ingested = occupant.get_ingested_reagents() + if(ingested) + var/trans_volumes = REAGENT_VOLUMES(ingested) + var/trans_volume = LAZYLEN(trans_volumes) + if(trans_volume) + ingested.trans_to_obj(beaker, pump_speed * trans_volume) else toggle_pump() - if(iscarbon(occupant) && stasis > 1) - occupant.SetStasis(stasis) + if(lavage) + if(has_room_in_beaker()) + var/datum/reagents/inhaled = occupant.get_inhaled_reagents() + if(inhaled) + var/trans_volumes = REAGENT_VOLUMES(inhaled) + var/trans_volume = LAZYLEN(trans_volumes) + if(trans_volume) + inhaled.trans_to_obj(beaker, pump_speed * trans_volume) + else + toggle_lavage() + + if(isliving(occupant) && stasis > 1) + occupant.add_mob_modifier(/decl/mob_modifier/stasis, 2 SECONDS, source = src) /obj/machinery/sleeper/on_update_icon() - overlays.Cut() + cut_overlays() icon_state = "med_pod" + if(occupant) - var/image/pickle = new - pickle.appearance = occupant + var/mutable_appearance/pickle = new /mutable_appearance(occupant) + var/list/icon_scale_values = occupant.get_icon_scale_mult() + var/desired_scale_x = icon_scale_values[1] + var/desired_scale_y = icon_scale_values[2] + + var/matrix/M = matrix() + M.Scale(desired_scale_x, desired_scale_y) + M.Translate(0, (1.5 * world.icon_size) * (desired_scale_y - 1)) + pickle.transform = M + pickle.layer = FLOAT_LAYER pickle.pixel_z = 12 - overlays += pickle - var/image/I = image(icon, "med_lid[!!(occupant && !(stat & (BROKEN|NOPOWER)))]") - overlays += I + add_overlay(pickle) + + add_overlay(image(icon, "med_lid[!!(occupant && !(stat & (BROKEN|NOPOWER)))]")) /obj/machinery/sleeper/DefaultTopicState() - return GLOB.outside_state + return global.outside_topic_state /obj/machinery/sleeper/interface_interact(var/mob/user) ui_interact(user) return TRUE -/obj/machinery/sleeper/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.outside_state) +/obj/machinery/sleeper/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.outside_topic_state) var/data[0] data["power"] = stat & (NOPOWER|BROKEN) ? 0 : 1 @@ -152,13 +211,17 @@ var/empties = 0 var/list/loaded_reagents = list() for(var/obj/item/chems/chem_disp_cartridge/canister in loaded_canisters) - if(!canister.reagents || !canister.reagents.total_volume) + if(!canister.reagents || !REAGENT_TOTAL_VOLUME(canister.reagents)) empties++ continue var/list/reagent = list() - reagent["name"] = canister.label || "unlabeled" + var/datum/extension/labels/lab = get_extension(canister, /datum/extension/labels) + if(length(lab?.labels)) + reagent ["name"] = (lab.labels[1]) + else + reagent ["name"] = "unlabeled" reagent["id"] = "\ref[canister]" - reagent["amount"] = canister.reagents.total_volume + reagent["amount"] = REAGENT_TOTAL_VOLUME(canister.reagents) loaded_reagents += list(reagent) data["reagents"] = loaded_reagents data["empty_canisters"] = empties @@ -178,6 +241,7 @@ data["beaker"] = -1 data["filtering"] = filtering data["pump"] = pump + data["lavage"] = lavage data["stasis"] = stasis data["skill_check"] = user.skill_check(SKILL_MEDICAL, SKILL_BASIC) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -189,7 +253,7 @@ /obj/machinery/sleeper/CanUseTopic(user) if(user == occupant) - to_chat(usr, SPAN_WARNING("You can't reach the controls from the inside.")) + to_chat(user, SPAN_WARNING("You can't reach the controls from the inside.")) return STATUS_CLOSE . = ..() @@ -197,7 +261,7 @@ if(href_list["eject_empties"]) . = TOPIC_NOACTION for(var/obj/item/canister in loaded_canisters) - if(!canister.reagents || !canister.reagents.total_volume) + if(!canister.reagents || !REAGENT_TOTAL_VOLUME(canister.reagents)) eject_reagent_canister(null, canister) . = TOPIC_REFRESH if(href_list["eject"]) @@ -214,6 +278,10 @@ if(filtering != text2num(href_list["pump"])) toggle_pump() return TOPIC_REFRESH + if(href_list["lavage"]) + if(lavage != text2num(href_list["lavage"])) + toggle_lavage() + return TOPIC_REFRESH if(href_list["chemical"]) var/obj/canister = locate(href_list["chemical"]) if(istype(canister)) @@ -237,34 +305,33 @@ updateUsrDialog() go_out() -/obj/machinery/sleeper/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/chems/chem_disp_cartridge)) - add_reagent_canister(user, I) +/obj/machinery/sleeper/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/chems/chem_disp_cartridge)) + add_reagent_canister(user, used_item) return TRUE - if(istype(I, /obj/item/chems/glass)) + if(istype(used_item, /obj/item/chems/glass)) add_fingerprint(user) if(!beaker) - if(!user.unEquip(I, src)) - return - beaker = I - user.visible_message(SPAN_NOTICE("\The [user] adds \a [I] to \the [src]."), SPAN_NOTICE("You add \a [I] to \the [src].")) + if(!user.try_unequip(used_item, src)) + return TRUE + beaker = used_item + user.visible_message(SPAN_NOTICE("\The [user] adds \a [used_item] to \the [src]."), SPAN_NOTICE("You add \a [used_item] to \the [src].")) else to_chat(user, SPAN_WARNING("\The [src] has a beaker already.")) return TRUE return ..() -/obj/machinery/sleeper/MouseDrop_T(var/mob/target, var/mob/user) - if(!CanMouseDrop(target, user)) - return - if(!istype(target)) - return - if(target.buckled) - to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them.")) - return - if(panel_open) - to_chat(user, SPAN_WARNING("Close the maintenance panel before attempting to place the subject in the sleeper.")) - return - go_in(target, user) +/obj/machinery/sleeper/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && ismob(dropping)) + var/mob/target = dropping + if(target.buckled) + to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them.")) + else if(panel_open) + to_chat(user, SPAN_WARNING("Close the maintenance panel before attempting to place the subject in the sleeper.")) + else + go_in(target, user) + return TRUE /obj/machinery/sleeper/relaymove(var/mob/user) ..() @@ -292,11 +359,24 @@ if(!occupant || !beaker) pump = 0 return - to_chat(occupant, SPAN_WARNING("You feel a tube jammed down your throat.")) pump = !pump + if(pump) + to_chat(occupant, SPAN_WARNING("You feel a tube jammed down your throat.")) + else + to_chat(occupant, SPAN_WARNING("You feel a tube retract from your throat.")) + +/obj/machinery/sleeper/proc/toggle_lavage() + if(!occupant || !beaker) + lavage = FALSE + return + lavage = !lavage + if (lavage) + to_chat(occupant, SPAN_WARNING("You feel a tube jammed down your windpipe.")) + else + to_chat(occupant, SPAN_NOTICE("You feel a tube retract from your windpipe.")) /obj/machinery/sleeper/proc/go_in(var/mob/M, var/mob/user) - if(!M) + if(!M || M.anchored) return if(stat & (BROKEN|NOPOWER)) return @@ -314,6 +394,8 @@ to_chat(user, SPAN_WARNING("\The [src] is already occupied.")) return set_occupant(M) + if(close_sound) + playsound(src, close_sound, 40) /obj/machinery/sleeper/proc/go_out() if(!occupant) @@ -323,15 +405,14 @@ occupant.client.perspective = MOB_PERSPECTIVE occupant.dropInto(loc) set_occupant(null) + if(open_sound) + playsound(src, open_sound, 40) - for(var/obj/O in (contents - (component_parts + loaded_canisters))) // In case an object was dropped inside or something. Excludes the beaker and component parts. - if(O != beaker) - O.dropInto(loc) + dump_contents() // In case an object was dropped inside or something. Excludes the beaker and component parts. toggle_filter() -/obj/machinery/sleeper/proc/set_occupant(var/mob/living/carbon/occupant) +/obj/machinery/sleeper/proc/set_occupant(var/mob/living/occupant) src.occupant = occupant - update_icon() if(!occupant) SetName(initial(name)) update_use_power(POWER_USE_IDLE) @@ -349,6 +430,7 @@ beaker = null toggle_filter() toggle_pump() + toggle_lavage() /obj/machinery/sleeper/proc/inject_chemical(var/mob/living/user, var/obj/canister, var/amount, var/target_transfer_type = CHEM_INJECT) if(stat & (BROKEN|NOPOWER)) @@ -356,21 +438,22 @@ if(!istype(canister) || canister.loc != src) to_chat(user, SPAN_WARNING("\The [src] cannot locate that canister.")) return - if(canister.reagents?.total_volume < amount) + if(REAGENT_TOTAL_VOLUME(canister.reagents) < amount) to_chat(user, SPAN_WARNING("\The [canister] has less than [amount] unit\s left.")) return if(!occupant || !occupant.reagents) to_chat(user, SPAN_WARNING("There's no suitable occupant in \the [src].")) return - if(occupant.reagents.total_volume + amount > 20 && !emagged) - to_chat(user, SPAN_WARNING("Injecting more chemicals presents an overdose risk to the subject.")) + var/decl/material/chem = canister.reagents?.get_primary_reagent_decl() + if(!emagged && chem?.overdose && REAGENT_VOLUME(occupant.reagents, chem) + amount >= chem.overdose) + to_chat(user, SPAN_WARNING("Injecting more [chem.name] presents an overdose risk to the subject.")) return canister.reagents.trans_to_mob(occupant, amount, target_transfer_type) to_chat(user, SPAN_NOTICE("You use \the [src] to [target_transfer_type == CHEM_INJECT ? "inject" : "infuse"] [amount] unit\s from \the [canister] into \the [occupant].")) /obj/machinery/sleeper/RefreshParts() ..() - pump_speed = 2 + max(Clamp(total_component_rating_of_type(/obj/item/stock_parts/scanning_module), 1, 10), 1) + pump_speed = 2 + max(clamp(total_component_rating_of_type(/obj/item/stock_parts/scanning_module), 1, 10), 1) max_canister_capacity = 5 + round(total_component_rating_of_type(/obj/item/stock_parts/manipulator)/2) /obj/machinery/sleeper/emag_act(var/remaining_charges, var/mob/user) diff --git a/code/game/machinery/_machines_base/machine_construction/_construction.dm b/code/game/machinery/_machines_base/machine_construction/_construction.dm index b548371e08c2..3555ee7173f1 100644 --- a/code/game/machinery/_machines_base/machine_construction/_construction.dm +++ b/code/game/machinery/_machines_base/machine_construction/_construction.dm @@ -9,7 +9,7 @@ /obj/machinery/Initialize() if(construct_state) - construct_state = decls_repository.get_decl(construct_state) + construct_state = GET_DECL(construct_state) . = ..() // Called on state transition; can intercept, but must call parent. @@ -19,7 +19,7 @@ // Return a change state define or a fail message to block transition. /obj/machinery/proc/cannot_transition_to(var/state_path, var/mob/user) if(ispath(state_path, /decl/machine_construction/default/deconstructed)) - var/obj/item/stock_parts/network_lock/lock = get_component_of_type(/obj/item/stock_parts/network_lock) + var/obj/item/stock_parts/network_receiver/network_lock/lock = get_component_of_type(/obj/item/stock_parts/network_receiver/network_lock) if(istype(lock) && !allowed(user)) // Only check if we have a network_lock. return MCS_BLOCK return MCS_CHANGE @@ -51,7 +51,7 @@ if(needs_board) var/obj/item/stock_parts/circuitboard/board = machine.get_component_of_type(/obj/item/stock_parts/circuitboard) if(board) - return board.req_components + return board.req_components + list(/obj/item/stock_parts/circuitboard = 1) else return list(/obj/item/stock_parts/circuitboard = 1) @@ -68,7 +68,7 @@ /decl/machine_construction/proc/try_change_state(obj/machinery/machine, path, user) if(machine.construct_state != src) return MCS_BLOCK - var/decl/machine_construction/state = decls_repository.get_decl(path) + var/decl/machine_construction/state = GET_DECL(path) if(state) var/fail = machine.cannot_transition_to(path, user) if(fail == MCS_CHANGE) @@ -76,21 +76,24 @@ return MCS_CHANGE if(istext(fail)) to_chat(user, fail) + // This logging exists so that random CI fails due to state change failures will be caught. + #ifdef UNIT_TEST + log_unit_test("[log_info_line(machine)]: [fail]") + #endif return MCS_BLOCK return fail return MCS_CONTINUE /decl/machine_construction/proc/attack_hand(mob/user, obj/machinery/machine) if(!validate_state(machine)) - crash_with("Machine [log_info_line(machine)] violated the state assumptions of the construction state [type]!") + PRINT_STACK_TRACE("Machine [log_info_line(machine)] violated the state assumptions of the construction state [type]!") machine.attack_hand(user) - return TRUE -/decl/machine_construction/proc/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/proc/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if(!validate_state(machine)) - crash_with("Machine [log_info_line(machine)] violated the state assumptions of the construction state [type]!") - machine.attackby(I, user) - return TRUE + PRINT_STACK_TRACE("Machine [log_info_line(machine)] violated the state assumptions of the construction state [type]!") + return machine.attackby(used_item, user) + return FALSE /decl/machine_construction/proc/mechanics_info() diff --git a/code/game/machinery/_machines_base/machine_construction/airlock.dm b/code/game/machinery/_machines_base/machine_construction/airlock.dm new file mode 100644 index 000000000000..c6a8a4fa6f15 --- /dev/null +++ b/code/game/machinery/_machines_base/machine_construction/airlock.dm @@ -0,0 +1,79 @@ +/decl/machine_construction/default/panel_closed/door + needs_board = "door" + down_state = /decl/machine_construction/default/panel_open/door + var/hacking_state = /decl/machine_construction/default/panel_closed/door/hacking + +/decl/machine_construction/default/panel_closed/door/fail_test_state_transfer(obj/machinery/machine, mob/user) + var/static/obj/item/screwdriver/screwdriver = new + // Prevent access locks on doors from interfering with our interactions. + for(var/obj/item/stock_parts/access_lock/lock in machine.get_all_components_of_type(/obj/item/stock_parts/access_lock)) + lock.locked = FALSE + // And ensure the door's closed + var/obj/machinery/door/the_door = machine + if(istype(the_door)) // just in case + the_door.operating = FALSE // A lot of doors refuse to change states if operating. + // Test hacking state + if(!machine.attackby(screwdriver, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with screwdriver." + if(machine.construct_state.type != hacking_state) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [hacking_state])." + // Do it again to reverse that state change. + if(!machine.attackby(screwdriver, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with screwdriver on a second try." + if(machine.construct_state != src) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [type])." + // Now test the down state + var/static/obj/item/wrench/wrench = new + if(!machine.attackby(wrench, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with wrench." + if(machine.construct_state.type != down_state) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [down_state])." + +/decl/machine_construction/default/panel_closed/door/attackby(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_SCREWDRIVER(used_item)) + TRANSFER_STATE(hacking_state) + playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("You release some of the logic wiring on \the [machine]. The cover panel remains closed.")) + machine.update_icon() + return TRUE + if(IS_WRENCH(used_item)) + TRANSFER_STATE(down_state) + playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) + machine.panel_open = TRUE + to_chat(user, SPAN_NOTICE("You open the main cover panel on \the [machine], exposing the internals.")) + machine.queue_icon_update() + return TRUE + if(istype(used_item, /obj/item/part_replacer)) + var/obj/item/part_replacer/replacer = used_item + if(replacer.remote_interaction) + machine.part_replacement(user, replacer) + for(var/line in machine.get_part_info_strings(user)) + to_chat(user, line) + return TRUE + return FALSE + +/decl/machine_construction/default/panel_closed/door/mechanics_info() + . = list() + . += "Use a screwdriver to open a small hatch and expose some logic wires." + . += "Use a wrench to open the main cover." + . += "Use a parts replacer to view installed parts." + +/decl/machine_construction/default/panel_closed/door/hacking + up_state = /decl/machine_construction/default/panel_closed/door + +/decl/machine_construction/default/panel_closed/door/hacking/attackby(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_SCREWDRIVER(used_item)) + TRANSFER_STATE(up_state) + playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("You tuck the exposed wiring back into \the [machine] and screw the hatch back into place.")) + machine.queue_icon_update() + return TRUE + return FALSE + +/decl/machine_construction/default/panel_closed/door/hacking/mechanics_info() + . = list() + . += "Use a screwdriver close the hatch and tuck the exposed wires back in." + +/decl/machine_construction/default/panel_open/door + needs_board = "door" + up_state = /decl/machine_construction/default/panel_closed/door \ No newline at end of file diff --git a/code/game/machinery/_machines_base/machine_construction/blast_doors.dm b/code/game/machinery/_machines_base/machine_construction/blast_doors.dm new file mode 100644 index 000000000000..8fff042ef234 --- /dev/null +++ b/code/game/machinery/_machines_base/machine_construction/blast_doors.dm @@ -0,0 +1,10 @@ +//Uses default states except with a door board needed. +// Cannot use airlock states, because blast doors do not weld or act the same way as airlocks +/decl/machine_construction/default/panel_closed/blast_door + needs_board = "door" + down_state = /decl/machine_construction/default/panel_open/blast_door + +/decl/machine_construction/default/panel_open/blast_door + needs_board = "door" + up_state = /decl/machine_construction/default/panel_closed/blast_door + diff --git a/code/game/machinery/_machines_base/machine_construction/computer.dm b/code/game/machinery/_machines_base/machine_construction/computer.dm index 684f0f4b8c18..797f16ad1ef2 100644 --- a/code/game/machinery/_machines_base/machine_construction/computer.dm +++ b/code/game/machinery/_machines_base/machine_construction/computer.dm @@ -4,7 +4,7 @@ down_state = /decl/machine_construction/default/panel_open/computer needs_board = "computer" -/decl/machine_construction/default/panel_closed/computer/no_deconstruct/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/default/panel_closed/computer/no_deconstruct/attackby(obj/item/used_item, mob/user, obj/machinery/machine) return FALSE /decl/machine_construction/default/panel_open/computer diff --git a/code/game/machinery/_machines_base/machine_construction/default.dm b/code/game/machinery/_machines_base/machine_construction/default.dm index 7285a759cd8a..d573df31e478 100644 --- a/code/game/machinery/_machines_base/machine_construction/default.dm +++ b/code/game/machinery/_machines_base/machine_construction/default.dm @@ -5,7 +5,7 @@ var/up_state var/down_state -/decl/machine_construction/default/no_deconstruct/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/default/no_deconstruct/attackby(obj/item/used_item, mob/user, obj/machinery/machine) . = FALSE /decl/machine_construction/default/panel_closed @@ -13,6 +13,22 @@ visible_components = FALSE locked = TRUE +/decl/machine_construction/default/panel_closed/fail_unit_test(obj/machinery/machine) + if((. = ..())) + return + var/static/mob/living/human/user = new + return fail_test_state_transfer(machine, user) + +/decl/machine_construction/default/panel_closed/proc/fail_test_state_transfer(obj/machinery/machine, mob/user) + var/static/obj/item/screwdriver/screwdriver = new + // Prevent access locks on machines interfering with our interactions. + for(var/obj/item/stock_parts/access_lock/lock in machine.get_all_components_of_type(/obj/item/stock_parts/access_lock)) + lock.locked = FALSE + if(!machine.attackby(screwdriver, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with screwdriver." + if(machine.construct_state.type != down_state) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [down_state])." + /decl/machine_construction/default/panel_closed/state_is_valid(obj/machinery/machine) return !machine.panel_open @@ -21,22 +37,24 @@ if(!.) try_change_state(machine, down_state) -/decl/machine_construction/default/panel_closed/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/default/panel_closed/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - if(isScrewdriver(I)) + if(IS_SCREWDRIVER(used_item)) TRANSFER_STATE(down_state) playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) machine.panel_open = TRUE to_chat(user, SPAN_NOTICE("You open the maintenance hatch of \the [machine].")) machine.update_icon() - return - if(istype(I, /obj/item/storage/part_replacer)) - var/obj/item/storage/part_replacer/replacer = I + return TRUE + if(istype(used_item, /obj/item/part_replacer)) + var/obj/item/part_replacer/replacer = used_item if(replacer.remote_interaction) machine.part_replacement(user, replacer) - machine.display_parts(user) + for(var/line in machine.get_part_info_strings(user)) + to_chat(user, line) return TRUE + return FALSE /decl/machine_construction/default/panel_closed/post_construct(obj/machinery/machine) try_change_state(machine, down_state) @@ -60,31 +78,29 @@ if(!.) try_change_state(machine, up_state) -/decl/machine_construction/default/panel_open/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/default/panel_open/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - if(isCrowbar(I)) + if(IS_CROWBAR(used_item)) TRANSFER_STATE(down_state) playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) machine.visible_message(SPAN_NOTICE("\The [user] deconstructs \the [machine].")) machine.dismantle() return - if(isScrewdriver(I)) + if(IS_SCREWDRIVER(used_item)) TRANSFER_STATE(up_state) playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) machine.panel_open = FALSE to_chat(user, SPAN_NOTICE("You close the maintenance hatch of \the [machine].")) machine.update_icon() - return - - if(istype(I, /obj/item/storage/part_replacer)) - return machine.part_replacement(user, I) - - if(isWrench(I)) + return TRUE + if(istype(used_item, /obj/item/part_replacer)) + return machine.part_replacement(user, used_item) + if(IS_WRENCH(used_item)) return machine.part_removal(user) - - if(istype(I)) - return machine.part_insertion(user, I) + if(istype(used_item)) + return machine.part_insertion(user, used_item) + return FALSE /decl/machine_construction/default/panel_open/mechanics_info() . = list() @@ -96,12 +112,3 @@ // Not implemented fully as the machine will qdel on transition to this. Path needed for checks. /decl/machine_construction/default/deconstructed - -// door variants, just use different boards -/decl/machine_construction/default/panel_closed/door - needs_board = "door" - down_state = /decl/machine_construction/default/panel_open/door - -/decl/machine_construction/default/panel_open/door - needs_board = "door" - up_state = /decl/machine_construction/default/panel_closed/door \ No newline at end of file diff --git a/code/game/machinery/_machines_base/machine_construction/frame.dm b/code/game/machinery/_machines_base/machine_construction/frame.dm index a557976e32a2..5eeb7883bc92 100644 --- a/code/game/machinery/_machines_base/machine_construction/frame.dm +++ b/code/game/machinery/_machines_base/machine_construction/frame.dm @@ -2,7 +2,7 @@ /decl/machine_construction/frame/unwrenched/state_is_valid(obj/machinery/machine) return !machine.anchored - + /decl/machine_construction/frame/unwrenched/validate_state(obj/machinery/constructable_frame/machine) . = ..() if(!.) @@ -11,26 +11,26 @@ else try_change_state(machine, /decl/machine_construction/frame/wrenched) -/decl/machine_construction/frame/unwrenched/attackby(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) +/decl/machine_construction/frame/unwrenched/attackby(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_WRENCH(used_item)) playsound(machine.loc, 'sound/items/Ratchet.ogg', 50, 1) if(do_after(user, 20, machine)) TRANSFER_STATE(/decl/machine_construction/frame/wrenched) to_chat(user, "You wrench \the [machine] into place.") machine.anchored = TRUE - if(isWelder(I)) - var/obj/item/weldingtool/WT = I - if(!WT.remove_fuel(0, user)) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(!welder.weld(0, user)) to_chat(user, "The welding tool must be on to complete this task.") return TRUE playsound(machine.loc, 'sound/items/Welder.ogg', 50, 1) if(do_after(user, 20, machine)) - if(!WT.isOn()) + if(!welder.isOn()) return TRUE TRANSFER_STATE(/decl/machine_construction/default/deconstructed) to_chat(user, "You deconstruct \the [machine].") machine.dismantle() - + return FALSE /decl/machine_construction/frame/unwrenched/mechanics_info() . = list() @@ -48,16 +48,16 @@ else try_change_state(machine, /decl/machine_construction/frame/unwrenched) -/decl/machine_construction/frame/wrenched/attackby(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) +/decl/machine_construction/frame/wrenched/attackby(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_WRENCH(used_item)) playsound(machine.loc, 'sound/items/Ratchet.ogg', 50, 1) if(do_after(user, 20, machine)) TRANSFER_STATE(/decl/machine_construction/frame/unwrenched) to_chat(user, "You unfasten \the [machine].") machine.anchored = FALSE - return - if(isCoil(I)) - var/obj/item/stack/cable_coil/C = I + return TRUE + if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/C = used_item if(C.get_amount() < 5) to_chat(user, "You need five lengths of cable to add them to \the [machine].") return TRUE @@ -67,7 +67,7 @@ TRANSFER_STATE(/decl/machine_construction/frame/awaiting_circuit) to_chat(user, "You add cables to the frame.") return TRUE - + return FALSE /decl/machine_construction/frame/wrenched/mechanics_info() . = list() @@ -85,26 +85,26 @@ else try_change_state(machine, /decl/machine_construction/frame/unwrenched) -/decl/machine_construction/frame/awaiting_circuit/attackby(obj/item/I, mob/user, obj/machinery/constructable_frame/machine) - if(istype(I, /obj/item/stock_parts/circuitboard)) - var/obj/item/stock_parts/circuitboard/circuit = I +/decl/machine_construction/frame/awaiting_circuit/attackby(obj/item/used_item, mob/user, obj/machinery/constructable_frame/machine) + if(istype(used_item, /obj/item/stock_parts/circuitboard)) + var/obj/item/stock_parts/circuitboard/circuit = used_item if(circuit.board_type == machine.expected_machine_type) - if(!user.canUnEquip(I)) - return FALSE - TRANSFER_STATE(/decl/machine_construction/frame/awaiting_parts) - user.unEquip(I, machine) - playsound(machine.loc, 'sound/items/Deconstruct.ogg', 50, 1) - to_chat(user, "You add the circuit board to \the [machine].") - machine.circuit = I - return + if(user.can_unequip_item(used_item)) + TRANSFER_STATE(/decl/machine_construction/frame/awaiting_parts) + user.try_unequip(used_item, machine) + playsound(machine.loc, 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You add the circuit board to \the [machine].") + machine.circuit = used_item else to_chat(user, "This frame does not accept circuit boards of this type!") - return TRUE - if(isWirecutter(I)) + return TRUE + if(IS_WIRECUTTER(used_item)) TRANSFER_STATE(/decl/machine_construction/frame/wrenched) playsound(machine.loc, 'sound/items/Wirecutter.ogg', 50, 1) to_chat(user, "You remove the cables.") new /obj/item/stack/cable_coil(machine.loc, 5) + return TRUE + return FALSE /decl/machine_construction/frame/awaiting_circuit/mechanics_info() . = list() @@ -122,15 +122,15 @@ else try_change_state(machine, /decl/machine_construction/frame/unwrenched) -/decl/machine_construction/frame/awaiting_parts/attackby(obj/item/I, mob/user, obj/machinery/constructable_frame/machine) - if(isCrowbar(I)) +/decl/machine_construction/frame/awaiting_parts/attackby(obj/item/used_item, mob/user, obj/machinery/constructable_frame/machine) + if(IS_CROWBAR(used_item)) TRANSFER_STATE(/decl/machine_construction/frame/awaiting_circuit) playsound(machine.loc, 'sound/items/Crowbar.ogg', 50, 1) machine.circuit.dropInto(machine.loc) machine.circuit = null to_chat(user, "You remove the circuit board.") - return - if(isScrewdriver(I)) + return TRUE + if(IS_SCREWDRIVER(used_item)) playsound(machine.loc, 'sound/items/Screwdriver.ogg', 50, 1) var/obj/machinery/new_machine = new machine.circuit.build_path(machine.loc, machine.dir, FALSE) machine.circuit.construct(new_machine) @@ -140,9 +140,10 @@ if(new_machine.construct_state) new_machine.construct_state.post_construct(new_machine) else - crash_with("Machine of type [new_machine.type] was built from a circuit and frame, but had no construct state set.") + PRINT_STACK_TRACE("Machine of type [new_machine.type] was built from a circuit and frame, but had no construct state set.") qdel(machine) return TRUE + return FALSE /decl/machine_construction/frame/awaiting_parts/mechanics_info() . = list() diff --git a/code/game/machinery/_machines_base/machine_construction/item_chassis.dm b/code/game/machinery/_machines_base/machine_construction/item_chassis.dm index e296f479edec..e97190d5d71a 100644 --- a/code/game/machinery/_machines_base/machine_construction/item_chassis.dm +++ b/code/game/machinery/_machines_base/machine_construction/item_chassis.dm @@ -5,20 +5,20 @@ down_state = /decl/machine_construction/default/panel_open/item_chassis -/decl/machine_construction/default/panel_closed/item_chassis/attackby(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) +/decl/machine_construction/default/panel_closed/item_chassis/attackby(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_WRENCH(used_item)) TRANSFER_STATE(/decl/machine_construction/default/deconstructed) playsound(get_turf(machine), 'sound/items/Ratchet.ogg', 50, 1) machine.visible_message(SPAN_NOTICE("\The [user] deconstructs \the [machine].")) machine.dismantle() - return + return TRUE return ..() -/decl/machine_construction/default/panel_closed/mechanics_info() +/decl/machine_construction/default/panel_closed/item_chassis/mechanics_info() . = ..() . += "Use a wrench to deconstruct the machine" -/decl/machine_construction/default/panel_closed/post_construct() +/decl/machine_construction/default/panel_closed/item_chassis/post_construct() /decl/machine_construction/default/panel_open/item_chassis needs_board = null diff --git a/code/game/machinery/_machines_base/machine_construction/noninteractive.dm b/code/game/machinery/_machines_base/machine_construction/noninteractive.dm index 0800bc4adc35..a59c77cf5019 100644 --- a/code/game/machinery/_machines_base/machine_construction/noninteractive.dm +++ b/code/game/machinery/_machines_base/machine_construction/noninteractive.dm @@ -4,4 +4,7 @@ // Use for actual machines is discouraged. /decl/machine_construction/noninteractive - visible_components = FALSE \ No newline at end of file + visible_components = FALSE + +/decl/machine_construction/noninteractive/terminal/mechanics_info() + . += "Use a wirecutter to disconnect the terminal from the machine." \ No newline at end of file diff --git a/code/game/machinery/_machines_base/machine_construction/pipe.dm b/code/game/machinery/_machines_base/machine_construction/pipe.dm index b95727f0dbfb..010428a50e47 100644 --- a/code/game/machinery/_machines_base/machine_construction/pipe.dm +++ b/code/game/machinery/_machines_base/machine_construction/pipe.dm @@ -6,29 +6,29 @@ /decl/machine_construction/pipe/state_is_valid(obj/machinery/machine) return TRUE -/decl/machine_construction/pipe/proc/deconstruct_transition(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) +/decl/machine_construction/pipe/proc/deconstruct_transition(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_WRENCH(used_item)) TRANSFER_STATE(/decl/machine_construction/default/deconstructed) playsound(get_turf(machine), 'sound/items/Ratchet.ogg', 50, 1) machine.visible_message(SPAN_NOTICE("\The [user] unfastens \the [machine].")) machine.dismantle() -/decl/machine_construction/pipe/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/pipe/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - return deconstruct_transition(I, user, machine) + return deconstruct_transition(used_item, user, machine) /decl/machine_construction/pipe/mechanics_info() . = list() . += "Use a wrench to deconstruct the machine" // Same, but uses different tool. -/decl/machine_construction/pipe/welder/deconstruct_transition(obj/item/I, mob/user, obj/machinery/machine) - if(isWelder(I)) - var/obj/item/weldingtool/WT = I - if(!WT.isOn()) +/decl/machine_construction/pipe/welder/deconstruct_transition(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(!welder.isOn()) return FALSE - if(!WT.remove_fuel(0,user)) + if(!welder.weld(0,user)) return FALSE var/fail = machine.cannot_transition_to(/decl/machine_construction/default/deconstructed, user) if(istext(fail)) @@ -40,11 +40,11 @@ playsound(get_turf(machine), 'sound/items/Welder.ogg', 50, 1) if(!do_after(user, 5 SECONDS, machine)) return TRUE - if(!WT.isOn()) + if(!welder.isOn()) return TRUE playsound(get_turf(machine), 'sound/items/Welder2.ogg', 50, 1) TRANSFER_STATE(/decl/machine_construction/default/deconstructed) - machine.visible_message(SPAN_NOTICE("\The [user] unwelds \the [src].")) + machine.visible_message(SPAN_NOTICE("\The [user] unwelds \the [machine].")) machine.dismantle() /decl/machine_construction/pipe/welder/mechanics_info() diff --git a/code/game/machinery/_machines_base/machine_construction/tcomms.dm b/code/game/machinery/_machines_base/machine_construction/tcomms.dm deleted file mode 100644 index b723f5962cd2..000000000000 --- a/code/game/machinery/_machines_base/machine_construction/tcomms.dm +++ /dev/null @@ -1,122 +0,0 @@ -// Telecomms have lots of states. - -/decl/machine_construction/tcomms - needs_board = "machine" - -/decl/machine_construction/tcomms/panel_closed - visible_components = FALSE - locked = TRUE - -/decl/machine_construction/tcomms/panel_closed/state_is_valid(obj/machinery/machine) - return !machine.panel_open - -/decl/machine_construction/tcomms/panel_closed/validate_state(obj/machinery/machine) - . = ..() - if(!.) - try_change_state(machine, /decl/machine_construction/tcomms/panel_open) - -/decl/machine_construction/tcomms/panel_closed/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) - return - if(isScrewdriver(I)) - TRANSFER_STATE(/decl/machine_construction/tcomms/panel_open) - machine.panel_open = TRUE - to_chat(user, "You unfasten the bolts.") - playsound(machine.loc, 'sound/items/Screwdriver.ogg', 50, 1) - -/decl/machine_construction/tcomms/panel_closed/post_construct(obj/machinery/machine) - try_change_state(machine, /decl/machine_construction/tcomms/panel_open/no_cable) - machine.panel_open = TRUE - machine.queue_icon_update() - -/decl/machine_construction/tcomms/panel_closed/mechanics_info() - . = list() - . += "Use a screwdriver to open the panel." - -/decl/machine_construction/tcomms/panel_closed/cannot_print - cannot_print = TRUE - -/decl/machine_construction/tcomms/panel_open/state_is_valid(obj/machinery/machine) - return machine.panel_open - -/decl/machine_construction/tcomms/panel_open/validate_state(obj/machinery/machine) - . = ..() - if(!.) - try_change_state(machine, /decl/machine_construction/tcomms/panel_closed) - -/decl/machine_construction/tcomms/panel_open/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) - return - return state_interactions(I, user, machine) - -/decl/machine_construction/tcomms/panel_open/proc/state_interactions(obj/item/I, mob/user, obj/machinery/machine) - if(isScrewdriver(I)) - TRANSFER_STATE(/decl/machine_construction/tcomms/panel_closed) - machine.panel_open = FALSE - to_chat(user, "You fasten the bolts.") - playsound(machine.loc, 'sound/items/Screwdriver.ogg', 50, 1) - return - if(isWrench(I)) - TRANSFER_STATE(/decl/machine_construction/tcomms/panel_open/unwrenched) - to_chat(user, "You dislodge the external plating.") - playsound(machine.loc, 'sound/items/Ratchet.ogg', 75, 1) - -/decl/machine_construction/tcomms/panel_open/mechanics_info() - . = list() - . += "Use a screwdriver to close the panel." - . += "Use a wrench to remove the external plating." - -/decl/machine_construction/tcomms/panel_open/unwrenched/state_interactions(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) - TRANSFER_STATE(/decl/machine_construction/tcomms/panel_open) - to_chat(user, "You secure the external plating.") - playsound(machine.loc, 'sound/items/Ratchet.ogg', 75, 1) - return - if(isWirecutter(I)) - TRANSFER_STATE(/decl/machine_construction/tcomms/panel_open/no_cable) - playsound(machine.loc, 'sound/items/Wirecutter.ogg', 50, 1) - to_chat(user, "You remove the cables.") - var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( user.loc ) - A.amount = 5 - machine.set_broken(TRUE, MACHINE_BROKEN_CONSTRUCT) // the machine's been borked! - -/decl/machine_construction/tcomms/panel_open/unwrenched/mechanics_info() - . = list() - . += "Use a wrench to secure the external plating." - . += "Use wirecutters to remove the cabling." - -/decl/machine_construction/tcomms/panel_open/no_cable/state_interactions(obj/item/I, mob/user, obj/machinery/machine) - if(isCoil(I)) - var/obj/item/stack/cable_coil/A = I - if (A.can_use(5)) - TRANSFER_STATE(/decl/machine_construction/tcomms/panel_open/unwrenched) - A.use(5) - to_chat(user, "You insert the cables.") - machine.set_broken(FALSE, MACHINE_BROKEN_CONSTRUCT) // the machine's not borked anymore! - return - else - to_chat(user, "You need five coils of wire for this.") - return TRUE - if(isCrowbar(I)) - TRANSFER_STATE(/decl/machine_construction/default/deconstructed) - playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) - machine.visible_message(SPAN_NOTICE("\The [user] deconstructs \the [machine].")) - machine.dismantle() - return - - if(istype(I, /obj/item/storage/part_replacer)) - return machine.part_replacement(I, user) - - if(isWrench(I)) - return machine.part_removal(user) - - if(istype(I)) - return machine.part_insertion(user, I) - -/decl/machine_construction/tcomms/panel_open/no_cable/mechanics_info() - . = list() - . += "Attach cables to make the machine functional." - . += "Use a parts replacer to upgrade some parts." - . += "Use a crowbar to remove the circuit and deconstruct the machine" - . += "Insert a new part to install it." - . += "Remove installed parts with a wrench." \ No newline at end of file diff --git a/code/game/machinery/_machines_base/machine_construction/wall_frame.dm b/code/game/machinery/_machines_base/machine_construction/wall_frame.dm index 642528a2d37e..a81bd4d52312 100644 --- a/code/game/machinery/_machines_base/machine_construction/wall_frame.dm +++ b/code/game/machinery/_machines_base/machine_construction/wall_frame.dm @@ -25,19 +25,20 @@ else try_change_state(machine, newly_built_state) -/decl/machine_construction/wall_frame/panel_closed/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/wall_frame/panel_closed/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - if(istype(I, /obj/item/storage/part_replacer)) - var/obj/item/storage/part_replacer/replacer = I + if(istype(used_item, /obj/item/part_replacer)) + var/obj/item/part_replacer/replacer = used_item if(replacer.remote_interaction) machine.part_replacement(user, replacer) - machine.display_parts(user) + for(var/line in machine.get_part_info_strings(user)) + to_chat(user, line) return TRUE - return down_interaction(I, user, machine) + return down_interaction(used_item, user, machine) -/decl/machine_construction/wall_frame/panel_closed/proc/down_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isScrewdriver(I)) +/decl/machine_construction/wall_frame/panel_closed/proc/down_interaction(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_SCREWDRIVER(used_item)) TRANSFER_STATE(open_state) playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) machine.panel_open = TRUE @@ -54,6 +55,23 @@ machine.panel_open = TRUE machine.queue_icon_update() +/decl/machine_construction/wall_frame/panel_closed/fail_unit_test(obj/machinery/machine) + if((. = ..())) + return + var/static/mob/living/human/user = new + return fail_test_state_transfer(machine, user) + +/decl/machine_construction/wall_frame/panel_closed/proc/fail_test_state_transfer(obj/machinery/machine, mob/user) + var/static/obj/item/screwdriver/screwdriver = new + // Prevent access locks on machines interfering with our interactions. + for(var/obj/item/stock_parts/access_lock/lock in machine.get_all_components_of_type(/obj/item/stock_parts/access_lock)) + lock.locked = FALSE + if(!machine.attackby(screwdriver, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with screwdriver." + if(machine.construct_state.type != open_state) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [open_state])." + + // Open panel /decl/machine_construction/wall_frame/panel_open/state_is_valid(obj/machinery/machine) @@ -67,33 +85,33 @@ else try_change_state(machine, active_state) -/decl/machine_construction/wall_frame/panel_open/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/wall_frame/panel_open/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - if(isWirecutter(I)) + if(IS_WIRECUTTER(used_item)) TRANSFER_STATE(diconnected_state) playsound(get_turf(machine), 'sound/items/Wirecutter.ogg', 50, 1) user.visible_message(SPAN_WARNING("\The [user] has cut the wires inside \the [machine]!"), "You have cut the wires inside \the [machine].") new /obj/item/stack/cable_coil(get_turf(machine), 5) machine.set_broken(TRUE, MACHINE_BROKEN_CONSTRUCT) machine.queue_icon_update() - return + return TRUE - if((. = up_interaction(I, user, machine))) + if((. = up_interaction(used_item, user, machine))) return - if(istype(I, /obj/item/storage/part_replacer)) - return machine.part_replacement(user, I) + if(istype(used_item, /obj/item/part_replacer)) + return machine.part_replacement(user, used_item) - if(isWrench(I)) + if(IS_WRENCH(used_item)) return machine.part_removal(user) - if(istype(I)) - return machine.part_insertion(user, I) + if(istype(used_item)) + return machine.part_insertion(user, used_item) -/decl/machine_construction/wall_frame/panel_open/proc/up_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isScrewdriver(I)) +/decl/machine_construction/wall_frame/panel_open/proc/up_interaction(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_SCREWDRIVER(used_item)) TRANSFER_STATE(active_state) playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) machine.panel_open = FALSE @@ -113,7 +131,7 @@ /decl/machine_construction/wall_frame/no_wires /decl/machine_construction/wall_frame/no_wires/state_is_valid(obj/machinery/machine) - return machine.panel_open && machine.get_component_of_type(/obj/item/stock_parts/circuitboard) + return machine.panel_open && machine.get_component_of_type(/obj/item/stock_parts/circuitboard) && (machine.reason_broken == MACHINE_BROKEN_CONSTRUCT) /decl/machine_construction/wall_frame/no_wires/validate_state(obj/machinery/machine) . = ..() @@ -123,37 +141,36 @@ else try_change_state(machine, active_state) -/decl/machine_construction/wall_frame/no_wires/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/wall_frame/no_wires/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - if(isCoil(I)) - var/obj/item/stack/cable_coil/A = I + if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/A = used_item if (A.can_use(5)) TRANSFER_STATE(open_state) A.use(5) to_chat(user, SPAN_NOTICE("You wire the [machine].")) machine.set_broken(FALSE, MACHINE_BROKEN_CONSTRUCT) machine.queue_icon_update() - return else to_chat(user, SPAN_WARNING("You need five pieces of cable to wire \the [machine].")) - return TRUE + return TRUE - if((. = down_interaction(I, user, machine))) + if((. = down_interaction(used_item, user, machine))) return - if(istype(I, /obj/item/storage/part_replacer)) - return machine.part_replacement(user, I) + if(istype(used_item, /obj/item/part_replacer)) + return machine.part_replacement(user, used_item) - if(isWrench(I)) + if(IS_WRENCH(used_item)) return machine.part_removal(user) - if(istype(I)) - return machine.part_insertion(user, I) + if(istype(used_item)) + return machine.part_insertion(user, used_item) -/decl/machine_construction/wall_frame/no_wires/proc/down_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isCrowbar(I)) +/decl/machine_construction/wall_frame/no_wires/proc/down_interaction(obj/item/used_item, mob/user, obj/machinery/machine) + if(IS_CROWBAR(used_item)) TRANSFER_STATE(bottom_state) playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) to_chat(user, "You pry out the circuit!") @@ -183,30 +200,33 @@ else try_change_state(machine, active_state) -/decl/machine_construction/wall_frame/no_circuit/attackby(obj/item/I, mob/user, obj/machinery/machine) +/decl/machine_construction/wall_frame/no_circuit/attackby(obj/item/used_item, mob/user, obj/machinery/machine) if((. = ..())) return - if(istype(I, /obj/item/stock_parts/circuitboard)) - var/obj/item/stock_parts/circuitboard/board = I + if(istype(used_item, /obj/item/stock_parts/circuitboard)) + var/obj/item/stock_parts/circuitboard/board = used_item if(board.build_path != (machine.base_type || machine.type)) to_chat(user, SPAN_WARNING("This circuitboard does not fit inside \the [machine]!")) return TRUE - if(!user.canUnEquip(board)) + if(!user.can_unequip_item(board)) return TRUE + machine.set_broken(TRUE, MACHINE_BROKEN_CONSTRUCT) TRANSFER_STATE(diconnected_state) - user.unEquip(board, machine) + user.try_unequip(board, machine) machine.install_component(board) user.visible_message(SPAN_NOTICE("\The [user] inserts \the [board] into \the [machine]!"), SPAN_NOTICE("You insert \the [board] into \the [machine]!")) machine.queue_icon_update() - return + return TRUE - if(isWrench(I)) + if(IS_WRENCH(used_item)) TRANSFER_STATE(/decl/machine_construction/default/deconstructed) playsound(get_turf(machine), 'sound/items/Ratchet.ogg', 50, 1) machine.visible_message(SPAN_NOTICE("\The [user] deconstructs \the [machine].")) machine.dismantle() - return + return TRUE + + return FALSE /decl/machine_construction/wall_frame/no_circuit/mechanics_info() . = list() diff --git a/code/game/machinery/_machines_base/machine_construction/wall_frame_hackable.dm b/code/game/machinery/_machines_base/machine_construction/wall_frame_hackable.dm index bec06395d433..7c1d98873bda 100644 --- a/code/game/machinery/_machines_base/machine_construction/wall_frame_hackable.dm +++ b/code/game/machinery/_machines_base/machine_construction/wall_frame_hackable.dm @@ -29,13 +29,13 @@ newly_built_state = /decl/machine_construction/wall_frame/no_circuit/hackable /decl/machine_construction/wall_frame/panel_closed/hackable/down_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isScrewdriver(I)) + if(IS_SCREWDRIVER(I)) TRANSFER_STATE(/decl/machine_construction/wall_frame/panel_closed/hackable/hacking) playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) to_chat(user, SPAN_NOTICE("You release some of the logic wiring on \the [machine]. The cover panel remains closed.")) machine.queue_icon_update() return - if(isCrowbar(I)) + if(IS_CROWBAR(I)) TRANSFER_STATE(open_state) playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) machine.panel_open = TRUE @@ -49,13 +49,13 @@ . += "Use a parts replacer to view installed parts." /decl/machine_construction/wall_frame/panel_closed/hackable/hacking/down_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isScrewdriver(I)) + if(IS_SCREWDRIVER(I)) TRANSFER_STATE(active_state) playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) to_chat(user, SPAN_NOTICE("You tuck the exposed wiring back into \the [machine] and screw the hatch back into place.")) machine.queue_icon_update() return - if(isCrowbar(I)) + if(IS_CROWBAR(I)) to_chat(user, SPAN_NOTICE("The exposed wires block you from prying open the main hatch. Tuck them back in first.")) return TRUE @@ -64,8 +64,31 @@ . += "Use a screwdriver close the hatch and tuck the exposed wires back in." . += "Use a parts replacer to view installed parts." +/decl/machine_construction/wall_frame/panel_closed/hackable/fail_test_state_transfer(obj/machinery/machine, mob/user) + var/static/obj/item/screwdriver/screwdriver = new + // Prevent access locks on doors from interfering with our interactions. + for(var/obj/item/stock_parts/access_lock/lock in machine.get_all_components_of_type(/obj/item/stock_parts/access_lock)) + lock.locked = FALSE + // Test hacking state + if(!machine.attackby(screwdriver, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with screwdriver." + var/const/hacking_state = /decl/machine_construction/wall_frame/panel_closed/hackable/hacking // TODO: un-hardcode this + if(machine.construct_state.type != hacking_state) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [hacking_state])." + // Do it again to reverse that state change. + if(!machine.attackby(screwdriver, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with screwdriver on a second try." + if(machine.construct_state != src) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [type])." + // Now test the open state + var/static/obj/item/crowbar/crowbar = new + if(!machine.attackby(crowbar, user)) + return "Machine [log_info_line(machine)] did not respond to attackby with crowbar." + if(machine.construct_state.type != open_state) + return "Machine [log_info_line(machine)] had a construct_state of type [machine.construct_state.type] after screwdriver interaction (expected [open_state])." + /decl/machine_construction/wall_frame/panel_open/hackable/up_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isCrowbar(I)) + if(IS_CROWBAR(I)) TRANSFER_STATE(active_state) playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) machine.panel_open = FALSE diff --git a/code/game/machinery/_machines_base/machine_construction/wall_frame_simple.dm b/code/game/machinery/_machines_base/machine_construction/wall_frame_simple.dm index 59fa539055a1..15a78e33fa27 100644 --- a/code/game/machinery/_machines_base/machine_construction/wall_frame_simple.dm +++ b/code/game/machinery/_machines_base/machine_construction/wall_frame_simple.dm @@ -50,7 +50,7 @@ . += "Use a crowbar to pry the frame off the wall." /decl/machine_construction/wall_frame/no_wires/simple/down_interaction(obj/item/I, mob/user, obj/machinery/machine) - if(isCrowbar(I)) + if(IS_CROWBAR(I)) TRANSFER_STATE(bottom_state) playsound(get_turf(machine), 'sound/items/Crowbar.ogg', 50, 1) to_chat(user, "You pry \the [machine] off the wall!") diff --git a/code/game/machinery/_machines_base/machinery.dm b/code/game/machinery/_machines_base/machinery.dm index 88bcc1244b8a..eb27136f261c 100644 --- a/code/game/machinery/_machines_base/machinery.dm +++ b/code/game/machinery/_machines_base/machinery.dm @@ -43,7 +43,7 @@ Class Variables: BROKEN:1 -- Machine is broken NOPOWER:2 -- No power is being supplied to machine. MAINT:8 -- machine is currently under going maintenance. - EMPED:16 -- temporary broken by EMP pulse + EMPED:16 -- temporary broken by EMP Class Procs: New() 'game/machinery/machine.dm' @@ -82,41 +82,68 @@ Class Procs: layer = STRUCTURE_LAYER // Layer under items throw_speed = 1 throw_range = 5 + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_PRIMARY + ) + temperature_sensitive = TRUE + abstract_type = /obj/machinery var/stat = 0 var/waterproof = TRUE var/reason_broken = 0 - var/stat_immune = NOSCREEN | NOINPUT // The machine will never set stat to these flags. - var/emagged = 0 - var/malf_upgraded = 0 - var/datum/wires/wires //wire datum, if any. If you place a type path, it will be autoinitialized. + /// The machine will never set stat to these flags. + var/stat_immune = NOSCREEN | NOINPUT + var/emagged = FALSE + /// wire datum, if any. If you place a type path, it will be autoinitialized. + var/datum/wires/wires var/use_power = POWER_USE_IDLE //0 = dont run the auto //1 = run auto, use idle //2 = run auto, use active var/idle_power_usage = 0 var/active_power_usage = 0 - var/power_channel = EQUIP //EQUIP, ENVIRON or LIGHT - var/power_init_complete = FALSE // Helps with bookkeeping when initializing atoms. Don't modify. - var/list/component_parts //List of component instances. Expected type: /obj/item/stock_parts - var/list/uncreated_component_parts = list(/obj/item/stock_parts/power/apc) //List of component paths which have delayed init. Indeces = number of components. - var/list/maximum_component_parts = list(/obj/item/stock_parts = 10) //null - no max. list(type part = number max). + /// Valid values: EQUIP, ENVIRON, LIGHT. If it should use a direct terminal connection instead, use LOCAL. + var/power_channel = EQUIP + /// Helps with bookkeeping when initializing atoms. Don't modify. + var/power_init_complete = FALSE + /// List of component instances. Expected type: /obj/item/stock_parts + var/list/component_parts + /// List of component paths which have lazy init (created when needed). Keys are part typepaths, values are the number of components. + var/list/uncreated_component_parts = list(/obj/item/stock_parts/power/apc) + /// null - no max. list(type part = number max). + var/list/maximum_component_parts = list(/obj/item/stock_parts = 10) var/uid - var/panel_open = 0 - var/global/gl_uid = 1 - var/interact_offline = 0 // Can the machine be interacted with while de-powered. - var/clicksound // sound played on succesful interface use by a carbon lifeform - var/clickvol = 40 // sound played on succesful interface use - var/core_skill = SKILL_DEVICES //The skill used for skill checks for this machine (mostly so subtypes can use different skills). - var/operator_skill // Machines often do all operations on Process(). This caches the user's skill while the operations are running. - var/base_type // For mapped buildable types, set this to be the base type actually buildable. - var/id_tag // This generic variable is to be used by mappers to give related machines a string key. In principle used by radio stock parts. - var/frame_type = /obj/machinery/constructable_frame/machine_frame/deconstruct // what is created when the machine is dismantled. - - var/list/processing_parts // Component parts queued for processing by the machine. Expected type: /obj/item/stock_parts - var/processing_flags // What is being processed - - var/list/initial_access // Used to setup network locks on machinery at populate_parts. + var/panel_open = FALSE + var/static/gl_uid = 1 + /// Can the machine be interacted with while de-powered. + var/interact_offline = FALSE + /// sound played on successful interface use + var/clicksound + /// volume of sound played on successful interface use + var/clickvol = 40 + ///The skill used for skill checks for this machine (mostly so subtypes can use different skills). + var/core_skill = SKILL_DEVICES + /// Machines often do all operations on Process(). This caches the user's skill while the operations are running. + var/operator_skill + /// For mapped buildable types, set this to be the base type actually buildable. + var/base_type + /// This generic variable is to be used by mappers to give related machines a string key. In principle used by radio stock parts. + var/id_tag + /// what is created when the machine is dismantled. + var/frame_type = /obj/machinery/constructable_frame/machine_frame/deconstruct + var/required_interaction_dexterity = DEXTERITY_KEYBOARDS + + /// Component parts queued for processing by the machine. Expected type: /obj/item/stock_parts + var/list/processing_parts + /// Controls whether components, the machine itself, or both run their processing in Process(). + var/processing_flags + + /// Used to setup network locks on machinery at populate_parts. + /// list(a, b) means access requires either A or B. + /// list(list(a, b)) means access requires A and B. + /// These can be combined, e.g. list(a, list(b, c)) requires either a, or both b and c. + /// Null means no access requirement. + var/list/initial_access /obj/machinery/Initialize(mapload, d=0, populate_parts = TRUE) . = ..() @@ -152,6 +179,10 @@ Class Procs: /obj/machinery/Process() return PROCESS_KILL // Only process if you need to. +/obj/machinery/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(id_tag, map_hash) + /obj/machinery/proc/set_broken(new_state, cause = MACHINE_BROKEN_GENERIC) if(stat_immune & BROKEN) return FALSE @@ -178,9 +209,6 @@ Class Procs: stat ^= NOINPUT return TRUE -/proc/is_operable(var/obj/machinery/M, var/mob/user) - return istype(M) && M.operable() - /obj/machinery/proc/is_broken(var/additional_flags = 0) return (stat & (BROKEN|additional_flags)) @@ -223,32 +251,56 @@ Class Procs: if((stat & BROKEN) && (reason_broken & MACHINE_BROKEN_GENERIC)) return STATUS_CLOSE - return GLOB.physical_state.can_use_topic(nano_host(), user) + return global.physical_topic_state.can_use_topic(nano_host(), user) /obj/machinery/CouldUseTopic(var/mob/user) ..() user.set_machine(src) + if(clicksound && isliving(user)) + playsound(src, clicksound, clickvol) /obj/machinery/CouldNotUseTopic(var/mob/user) user.unset_machine() +// This must not be converted to use OnTopic. +// mechanics_text and power_text can be done at a distance (via examination) +// while the TOPIC_REFRESH handling must come after OnTopic has resolved in the parent call of Topic. /obj/machinery/Topic(href, href_list, datum/topic_state/state) if(href_list["mechanics_text"] && construct_state) // This is an OOC examine thing handled via Topic; specifically bypass all checks, but do nothing other than message to chat. var/list/info = get_tool_manipulation_info() if(info) to_chat(usr, jointext(info, "
    ")) return TOPIC_HANDLED - + if(href_list["power_text"]) // As above. Reports OOC info on how to use installed power sources. + var/list/info = get_power_sources_info() + if(info) + to_chat(usr, jointext(info, "
    ")) + return TOPIC_HANDLED . = ..() if(. == TOPIC_REFRESH) updateUsrDialog() // Update legacy UIs to the extent possible. + SSnano.update_uis(src) // And our modern NanoUI ones, too. + update_icon() // A lot of machines like to do icon updates on refresh, so we'll handle it for them here. + else if(. == TOPIC_CLOSE) + usr.unset_machine() + var/datum/nanoui/open_ui = SSnano.get_open_ui(usr, src, "main") + if(open_ui) + open_ui.close() /obj/machinery/proc/get_tool_manipulation_info() return construct_state?.mechanics_info() +/obj/machinery/proc/get_power_sources_info() + . = list() + var/list/power_sources = get_all_components_of_type(/obj/item/stock_parts/power, FALSE) + if(!length(power_sources)) + . += "The machine has no power sources installed." + for(var/obj/item/stock_parts/power/source in power_sources) + . += source.get_source_info() + //////////////////////////////////////////////////////////////////////////////////////////// -/obj/machinery/attack_ai(mob/user) +/obj/machinery/attack_ai(mob/living/silicon/ai/user) if(CanUseTopic(user, DefaultTopicState()) > STATUS_CLOSE) return interface_interact(user) @@ -269,17 +321,8 @@ Class Procs: return if(!CanPhysicallyInteract(user)) return FALSE // The interactions below all assume physical access to the machine. If this is not the case, we let the machine take further action. - if(!user.check_dexterity(DEXTERITY_KEYBOARDS)) - to_chat(user, "You don't have the dexterity to do this!") + if(!user.check_dexterity(required_interaction_dexterity)) return TRUE - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.getBrainLoss() >= 55) - visible_message("[H] stares cluelessly at \the [src].") - return 1 - else if(prob(H.getBrainLoss())) - to_chat(user, "You momentarily forget how to use \the [src].") - return 1 if((. = component_attack_hand(user))) return if(wires && (. = wires.Interact(user))) @@ -311,33 +354,37 @@ Class Procs: set_broken(!!missing, MACHINE_BROKEN_NO_PARTS) /obj/machinery/proc/state(var/msg) - for(var/mob/O in hearers(src, null)) - O.show_message("\icon[src] [msg]", 2) + audible_message(SPAN_NOTICE("[html_icon(src)] [msg]"), null, 2) -/obj/machinery/proc/ping(text=null) +/obj/machinery/proc/ping(var/text) if (!text) text = "\The [src] pings." state(text, "blue") - playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + playsound(src.loc, 'sound/machines/ping.ogg', 50, FALSE) + +/obj/machinery/proc/buzz(var/text) + if (!text) + text = "\The [src] buzzes." + + state(SPAN_WARNING(text), "red") + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, FALSE) /obj/machinery/proc/shock(mob/user, prb) if(inoperable()) return 0 if(!prob(prb)) return 0 - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() + spark_at(src, amount=5, cardinal_only = TRUE) if(electrocute_mob(user, get_area(src), src, 0.7)) var/area/temp_area = get_area(src) if(temp_area) - var/obj/machinery/power/apc/temp_apc = temp_area.get_apc() + var/obj/machinery/apc/temp_apc = temp_area.get_apc() var/obj/machinery/power/terminal/terminal = temp_apc && temp_apc.terminal() if(terminal && terminal.powernet) terminal.powernet.trigger_warning() - if(user.stunned) + if(HAS_STATUS(user, STAT_STUN)) return 1 return 0 @@ -354,96 +401,93 @@ Class Procs: var/list/expelled_components = list() for(var/I in component_parts) - expelled_components += uninstall_component(I, refresh_parts = FALSE) + var/component = uninstall_component(I, refresh_parts = FALSE) + if(component) + expelled_components += component while(LAZYLEN(uncreated_component_parts)) var/path = uncreated_component_parts[1] - expelled_components += uninstall_component(path, refresh_parts = FALSE) + var/component = uninstall_component(path, refresh_parts = FALSE) + if(component) + expelled_components += component if(frame) var/datum/extension/parts_stash/stash = get_extension(frame, /datum/extension/parts_stash) if(stash) stash.stash(expelled_components) - for(var/obj/O in src) - O.dropInto(loc) + dump_contents() qdel(src) return frame -/obj/machinery/InsertedContents() - return (contents - component_parts) - /datum/proc/apply_visual(mob/M) return /datum/proc/remove_visual(mob/M) return -/obj/machinery/proc/malf_upgrade(var/mob/living/silicon/ai/user) - return 0 - -/obj/machinery/CouldUseTopic(var/mob/user) - ..() - if(clicksound && istype(user, /mob/living/carbon)) - playsound(src, clicksound, clickvol) - -/obj/machinery/proc/display_parts(mob/user) - to_chat(user, "Following parts detected in the machine:") +/obj/machinery/proc/get_part_info_strings(mob/user) + . = list() + . += SPAN_NOTICE("The following parts are detected in \the [src]:") for(var/obj/item/C in component_parts) - var/line = " [C.name]" - if(!C.health) - line = " [C.name] (destroyed)" - else if(C.health < 0.75 * C.max_health) - line = " [C.name] (damaged)" - to_chat(user, line) + var/line = SPAN_NOTICE(" [C.name]") + if(!C.current_health) + line = SPAN_WARNING(" [C.name] (destroyed)") + else if(C.get_percent_health() < 75) + line = SPAN_NOTICE(" [C.name] (damaged)") + . += line for(var/path in uncreated_component_parts) var/obj/item/thing = path - to_chat(user, " [initial(thing.name)] ([uncreated_component_parts[path] || 1])") + . += SPAN_NOTICE(" [initial(thing.name)] ([uncreated_component_parts[path] || 1])") -/obj/machinery/examine(mob/user) +/obj/machinery/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(component_parts && (hasHUD(user, HUD_SCIENCE) || (construct_state && construct_state.visible_components))) - display_parts(user) + . += get_part_info_strings(user) if(stat & NOSCREEN) - to_chat(user, "It is missing a screen, making it hard to interact with.") + . += SPAN_WARNING("It is missing a screen, making it hard to interact with.") else if(stat & NOINPUT) - to_chat(user, "It is missing any input device.") - else if((stat & NOPOWER) && !interact_offline) - to_chat(user, "It is not receiving power.") - if(construct_state && construct_state.mechanics_info()) - to_chat(user, "It can be manipulated using tools.") + . += SPAN_WARNING("It is missing any input device.") + + if((stat & NOPOWER)) + if(interact_offline) + . += SPAN_WARNING("It is not receiving power.") + else + . += SPAN_WARNING("It is not receiving power, making it hard to interact with.") + + if(construct_state?.mechanics_info()) + . += SPAN_NOTICE("It can be manipulated using tools.") + var/list/missing = missing_parts() if(missing) var/list/parts = list() for(var/type in missing) var/obj/item/fake_thing = type parts += "[num2text(missing[type])] [initial(fake_thing.name)]" - to_chat(user, "\The [src] is missing [english_list(parts)], rendering it inoperable.") + . += SPAN_WARNING("\The [src] is missing [english_list(parts)], rendering it inoperable.") + for(var/obj/item/stock_parts/part in component_parts) + var/part_strings = part.on_machine_examined(user) + if(LAZYLEN(part_strings)) + . += part_strings // This is really pretty crap and should be overridden for specific machines. /obj/machinery/fluid_act(var/datum/reagents/fluids) ..() - if(!(stat & (NOPOWER|BROKEN)) && !waterproof && (fluids.total_volume > FLUID_DEEP)) + if(!QDELETED(src) && !(stat & (NOPOWER|BROKEN)) && !waterproof && (REAGENT_TOTAL_VOLUME(fluids) > FLUID_DEEP)) explosion_act(3) /obj/machinery/Move() + var/atom/lastloc = loc . = ..() if(. && !CanFluidPass()) + if(lastloc) + lastloc.fluid_update() fluid_update() -/obj/machinery/get_cell() +/obj/machinery/get_cell(var/functional_only = TRUE) var/obj/item/stock_parts/power/battery/battery = get_component_of_type(/obj/item/stock_parts/power/battery) - if(battery) + if(battery && (!functional_only || battery.is_functional())) return battery.get_cell() -/obj/machinery/building_cost() - . = ..() - var/list/component_types = types_of_component(/obj/item/stock_parts) - for(var/path in component_types) - var/obj/item/stock_parts/part = get_component_of_type(path) - var/list/part_costs = part.building_cost() - for(var/key in part_costs) - .[key] += part_costs[key] * component_types[path] - /obj/machinery/emag_act(remaining_charges, mob/user, emag_source) . = ..() for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) @@ -454,5 +498,38 @@ Class Procs: /obj/machinery/get_req_access() . = ..() || list() - for(var/obj/item/stock_parts/network_lock/lock in get_all_components_of_type(/obj/item/stock_parts/network_lock)) - .+= lock.get_req_access() \ No newline at end of file + for(var/obj/item/stock_parts/network_receiver/network_lock/lock in get_all_components_of_type(/obj/item/stock_parts/network_receiver/network_lock)) + .+= lock.get_req_access() + +/obj/machinery/get_contained_external_atoms() + . = ..() + LAZYREMOVE(., component_parts) + +// This only includes external atoms by default, so we need to add components back. +/obj/machinery/get_contained_matter(include_reagents = TRUE) + . = ..() + var/list/component_types = types_of_component(/obj/item/stock_parts) + for(var/path in component_types) + for(var/obj/item/stock_parts/part in get_all_components_of_type(path)) + var/list/part_costs = part.get_contained_matter(include_reagents) + for(var/key in part_costs) + .[key] += part_costs[key] * component_types[path] + +/obj/machinery/proc/get_auto_access() + var/area/A = get_area(src) + return A?.req_access?.Copy() + +/obj/machinery/get_matter_amount_modifier() + . = ..() * HOLLOW_OBJECT_MATTER_MULTIPLIER // machine matter is largely just the frame, and the components contribute most of the matter/value. + +///Handles updating stock parts and internal id tag when changing it to something else +/obj/machinery/proc/set_id_tag(var/new_id_tag) + id_tag = new_id_tag + //#TODO: Add handling for components, when we're sure it will work for any kind of machinery. Some machines do not use the same id_tag on receiver and transmitters for example. + +// Make sure that mapped subtypes get the right codex entry. +/obj/machinery/get_codex_value() + return base_type || ..() + +/obj/machinery/solvent_can_melt(var/solvent_power = MAT_SOLVENT_STRONG) + return FALSE diff --git a/code/game/machinery/_machines_base/machinery_components.dm b/code/game/machinery/_machines_base/machinery_components.dm index 160b2c4e0be9..da820f74e750 100644 --- a/code/game/machinery/_machines_base/machinery_components.dm +++ b/code/game/machinery/_machines_base/machinery_components.dm @@ -1,6 +1,10 @@ // Init optimization. -GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) +var/global/list/machine_path_to_circuit_type +/proc/get_circuit_by_build_path(var/circuit) + if(!global.machine_path_to_circuit_type) + global.machine_path_to_circuit_type = cache_circuits_by_build_path() + return global.machine_path_to_circuit_type[circuit] /proc/cache_circuits_by_build_path() . = list() @@ -18,7 +22,7 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) /obj/machinery/proc/populate_parts(var/full_populate) // Full populate creates a circuitboard and all needed components automatically. if(full_populate) var/path_to_check = base_type || type - var/board_path = GLOB.machine_path_to_circuit_type[path_to_check] + var/board_path = get_circuit_by_build_path(path_to_check) if(board_path) var/obj/item/stock_parts/circuitboard/board = install_component(board_path, refresh_parts = FALSE) var/list/req_components = board.spawn_components || board.req_components @@ -29,16 +33,20 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) LAZYINITLIST(uncreated_component_parts) for(var/type in req_components) uncreated_component_parts[type] += (req_components[type] || 1) - if(initial_access && length(initial_access) > 0) + if(LAZYLEN(initial_access) > 0) for(var/access_list in initial_access) // Each part is an AND component. - var/obj/item/stock_parts/network_lock/lock = install_component(/obj/item/stock_parts/network_lock/buildable, refresh_parts = FALSE) - lock.grants = access_list + var/obj/item/stock_parts/network_receiver/network_lock/lock = install_component(/obj/item/stock_parts/network_receiver/network_lock/buildable, refresh_parts = FALSE) + lock.groups = islist(access_list) ? access_list : list(access_list) // Create the parts we are supposed to have. If not full_populate, this is only hard-baked parts, and more will be added later. for(var/component_path in uncreated_component_parts) var/number = uncreated_component_parts[component_path] || 1 LAZYREMOVE(uncreated_component_parts, component_path) + // Stacks are created differently to avoid qdel churn. + if(ispath(component_path, /obj/item/stack)) + install_component(new component_path(src, number), refresh_parts = FALSE) + continue for(var/i in 1 to number) install_component(component_path, refresh_parts = FALSE) @@ -52,7 +60,7 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) var/list/processed_parts = list() for(var/path in stock_part_presets) - var/decl/stock_part_preset/preset = decls_repository.get_decl(path) + var/decl/stock_part_preset/preset = GET_DECL(path) var/number = stock_part_presets[path] || 1 for(var/obj/item/stock_parts/part in component_parts) if(processed_parts[part]) @@ -69,7 +77,7 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) if(!stock_part_presets) return for(var/path in stock_part_presets) - var/decl/stock_part_preset/preset = decls_repository.get_decl(path) + var/decl/stock_part_preset/preset = GET_DECL(path) if(istype(part, preset.expected_part_type)) return preset @@ -144,9 +152,11 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) . = part if(istype(part)) + if(part in component_parts) + CRASH("Tried to insert \a '[part]' twice in \the [src] ([x], [y], [z])!") LAZYADD(component_parts, part) part.on_install(src) - GLOB.destroyed_event.register(part, src, .proc/component_destroyed) + events_repository.register(/decl/observ/destroyed, part, src, PROC_REF(component_destroyed)) else if(ispath(part)) LAZYINITLIST(uncreated_component_parts) uncreated_component_parts[part] += 1 @@ -174,22 +184,23 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) if(QDELETED(part)) // unremovable stuff return part.dropInto(loc) - GLOB.destroyed_event.unregister(part, src) + events_repository.unregister(/decl/observ/destroyed, part, src) return part -/obj/machinery/proc/replace_part(mob/user, var/obj/item/storage/part_replacer/R, var/obj/item/stock_parts/old_part, var/obj/item/stock_parts/new_part) +/obj/machinery/proc/replace_part(mob/user, var/obj/item/part_replacer/replacer, var/obj/item/stock_parts/old_part, var/obj/item/stock_parts/new_part) if(ispath(old_part)) old_part = get_component_of_type(old_part, TRUE) old_part = uninstall_component(old_part) - if(R) - R.remove_from_storage(new_part, src) - R.handle_item_insertion(old_part, 1) - R.part_replacement_sound() + if(replacer) + if(replacer.storage) + replacer.storage.remove_from_storage(null, new_part, src) + replacer.storage.handle_item_insertion(null, old_part, TRUE) + replacer.part_replacement_sound() install_component(new_part) to_chat(user, "[old_part.name] replaced with [new_part.name].") /obj/machinery/proc/component_destroyed(var/obj/item/component) - GLOB.destroyed_event.unregister(component, src) + events_repository.unregister(/decl/observ/destroyed, component, src) LAZYREMOVE(component_parts, component) LAZYREMOVE(processing_parts, component) power_components -= component @@ -217,7 +228,7 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) // Use to block interactivity if panel is not open, etc. /obj/machinery/proc/components_are_accessible(var/path) - if(ispath(path, /obj/item/stock_parts/access_lock)) + if(ispath(path, /obj/item/stock_parts/access_lock) || ispath(path, /obj/item/stock_parts/item_holder)) return TRUE return panel_open @@ -235,7 +246,7 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) to_chat(user, SPAN_WARNING("The insertion point for \the [component] is inaccessible!")) return 0 for(var/path in maximum_component_parts) - if(istype(component, path) && (number_of_components(path) == maximum_component_parts[path])) + if(istype(component, path) && (number_of_components(path) >= maximum_component_parts[path])) to_chat(user, SPAN_WARNING("There are too many parts of this type installed in \the [src] already!")) return 0 return 1 @@ -243,18 +254,18 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) // Hook to get updates. /obj/machinery/proc/component_stat_change(var/obj/item/stock_parts/part, old_stat, flag) -/obj/machinery/attackby(obj/item/I, mob/user) - if(component_attackby(I, user)) - return TRUE +/obj/machinery/attackby(obj/item/used_item, mob/user) + if((. = component_attackby(used_item, user))) + return return ..() -/obj/machinery/proc/component_attackby(obj/item/I, mob/user) +/obj/machinery/proc/component_attackby(obj/item/used_item, mob/user) for(var/obj/item/stock_parts/part in component_parts) if(!components_are_accessible(part.type)) continue - if((. = part.attackby(I, user))) + if((. = part.attackby(used_item, user))) return - return construct_state && construct_state.attackby(I, user, src) + return construct_state?.attackby(used_item, user, src) /obj/machinery/proc/component_attack_hand(mob/user) for(var/obj/item/stock_parts/part in component_parts) @@ -262,21 +273,21 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) continue if((. = part.attack_hand(user))) return - return construct_state && construct_state.attack_hand(user, src) + return construct_state?.attack_hand(user, src) /* Standard helpers for users interacting with machinery parts. */ -/obj/machinery/proc/part_replacement(mob/user, obj/item/storage/part_replacer/R) +/obj/machinery/proc/part_replacement(mob/user, obj/item/part_replacer/replacer) for(var/obj/item/stock_parts/A in component_parts) if(!A.base_type) continue if(!(A.part_flags & PART_FLAG_HAND_REMOVE)) continue - for(var/obj/item/stock_parts/B in R.contents) + for(var/obj/item/stock_parts/B in replacer.contents) if(istype(B, A.base_type) && B.rating > A.rating) - replace_part(user, R, A, B) + replace_part(user, replacer, A, B) return TRUE for(var/path in uncreated_component_parts) var/obj/item/stock_parts/A = path @@ -284,13 +295,13 @@ Standard helpers for users interacting with machinery parts. continue var/base_type = initial(A.base_type) if(base_type) - for(var/obj/item/stock_parts/B in R.contents) + for(var/obj/item/stock_parts/B in replacer.contents) if(istype(B, base_type) && B.rating > initial(A.rating)) - replace_part(user, R, A, B) + replace_part(user, replacer, A, B) return TRUE /obj/machinery/proc/part_insertion(mob/user, obj/item/stock_parts/part) // Second argument may actually be an arbitrary item. - if(!user.canUnEquip(part) && !isstack(part)) + if(!user.can_unequip_item(part) && !isstack(part)) return FALSE var/number = can_add_component(part, user) if(!number) @@ -299,7 +310,7 @@ Standard helpers for users interacting with machinery parts. var/obj/item/stack/stack = part install_component(stack.split(number, TRUE)) else - user.unEquip(part, src) + user.try_unequip(part, src) install_component(part) user.visible_message(SPAN_NOTICE("\The [user] installs \the [part] in \the [src]!"), SPAN_NOTICE("You install \the [part] in \the [src]!")) return TRUE @@ -310,7 +321,7 @@ Standard helpers for users interacting with machinery parts. var/obj/item/stock_parts/part = path if(!(initial(part.part_flags) & PART_FLAG_HAND_REMOVE)) continue - var/obj/item/stock_parts/network_lock/lock = part + var/obj/item/stock_parts/network_receiver/network_lock/lock = part if(istype(lock) && !allowed(user)) continue if(components_are_accessible(path)) @@ -324,6 +335,7 @@ Standard helpers for users interacting with machinery parts. return TRUE remove_part_and_give_to_user(path, user) return TRUE + return FALSE /obj/machinery/proc/remove_part_and_give_to_user(var/path, mob/user) var/obj/item/stock_parts/part = uninstall_component(get_component_of_type(path, TRUE)) @@ -341,3 +353,12 @@ Standard helpers for users interacting with machinery parts. var/present = number_of_components(required_type, only_functional) if(present < needed) LAZYSET(., required_type, needed - present) + +/obj/machinery/get_alt_interactions(mob/user) + . = ..() + for(var/obj/item/stock_parts/component in component_parts) + if(!components_are_accessible(component.type)) + continue + var/list/machine_alt_interactions = component.get_machine_alt_interactions(user) + if(LAZYLEN(machine_alt_interactions)) + LAZYADD(., machine_alt_interactions) diff --git a/code/game/machinery/_machines_base/machinery_damage.dm b/code/game/machinery/_machines_base/machinery_damage.dm index 032ee0dd1105..29a821716b0c 100644 --- a/code/game/machinery/_machines_base/machinery_damage.dm +++ b/code/game/machinery/_machines_base/machinery_damage.dm @@ -1,59 +1,67 @@ -/obj/machinery/proc/take_damage(amount, damtype, silent) +/obj/machinery/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) //Let's not bother initializing all the components for nothing - if(amount <= 0) + if(damage <= 0) return - if(damtype != BRUTE && damtype != BURN && damtype != ELECTROCUTE) + if(damage_type != BRUTE && damage_type != BURN && damage_type != ELECTROCUTE) return if(!silent) var/hitsound = 'sound/weapons/smash.ogg' - if(damtype == ELECTROCUTE) + if(damage_type == ELECTROCUTE) hitsound = "sparks" - else if(damtype == BURN) + else if(damage_type == BURN) hitsound = 'sound/items/Welder.ogg' playsound(src, hitsound, 10, 1) - + // Shielding components (armor/fuses) take first hit var/list/shielding = get_all_components_of_type(/obj/item/stock_parts/shielding) for(var/obj/item/stock_parts/shielding/soak in shielding) - if(damtype in soak.protection_types) - amount -= soak.take_damage(amount, damtype) - if(amount <= 0) + if(soak.is_functional() && (damage_type in soak.protection_types)) + damage -= soak.take_damage(damage, damage_type) + if(damage <= 0) return // If some damage got past, next it's generic (non-circuitboard) components - var/obj/item/stock_parts/victim = get_damageable_component() - while(amount > 0 && victim) - amount -= victim.take_damage(amount, damtype) - victim = get_damageable_component() - if(amount <= 0) + var/obj/item/stock_parts/victim = get_damageable_component(damage_type) + while(damage > 0 && victim) + damage -= victim.take_damage(damage, damage_type) + victim = get_damageable_component(damage_type) + if(damage <= 0) return // And lastly hit the circuitboard victim = get_component_of_type(/obj/item/stock_parts/circuitboard) - if(victim) - victim.take_damage(amount, damtype) - -/obj/machinery/proc/get_damageable_component() + if(victim?.can_take_damage() && victim.is_functional()) + damage -= victim.take_damage(damage, damage_type) + + if(damage && (damage_type == BRUTE || damage_type == BURN)) + dismantle() + +/obj/machinery/proc/get_damageable_component(var/damage_type) var/list/victims = shuffle(component_parts) if(LAZYLEN(victims)) for(var/obj/item/stock_parts/component in victims) // Circuitboards are handled separately if(istype(component, /obj/item/stock_parts/circuitboard)) continue + if(damage_type && (damage_type in component.ignore_damage_types)) + continue // Don't damage what can't be repaired - if(component.part_flags & PART_FLAG_NODAMAGE) + if(!component.can_take_damage()) continue if(component.is_functional()) return component for(var/path in uncreated_component_parts) if(uncreated_component_parts[path]) var/obj/item/stock_parts/component = path - if(!(initial(component.part_flags) & PART_FLAG_NODAMAGE)) + //Must be checked this way, since we don't have an instance to call component.can_take_damage() on. + if(initial(component.max_health) != ITEM_HEALTH_NO_DAMAGE) return force_init_component(path) /obj/machinery/proc/on_component_failure(var/obj/item/stock_parts/component) RefreshParts() - power_change() + update_icon() + if(istype(component, /obj/item/stock_parts/power)) + power_change() /obj/machinery/emp_act(severity) if(use_power && stat == 0) @@ -65,16 +73,22 @@ /obj/machinery/explosion_act(severity) ..() if(!QDELETED(src)) - take_damage(100/severity, BRUTE, TRUE) + if((severity == 1 || (severity == 2 && prob(25)))) + physically_destroyed() + else + take_damage(100/severity, silent = TRUE) /obj/machinery/bullet_act(obj/item/projectile/P, def_zone) . = ..() - take_damage(P.damage, P.damage_type) + take_damage(P.damage, P.atom_damage_type) -/obj/machinery/bash(obj/item/W, mob/user) - if(W.force <= 5) +/obj/machinery/bash(obj/item/used_item, mob/user) + if(!istype(used_item)) + return FALSE + var/force = used_item.expend_attack_force(user) + if(force <= 5) return FALSE . = ..() if(.) - user.setClickCooldown(W.attack_cooldown + W.w_class) - take_damage(W.force, W.damtype) \ No newline at end of file + user.setClickCooldown(used_item.attack_cooldown + used_item.w_class) + take_damage(force, used_item.atom_damage_type) \ No newline at end of file diff --git a/code/game/machinery/_machines_base/machinery_power.dm b/code/game/machinery/_machines_base/machinery_power.dm index 9bf04a67beee..9e3aaff8a48b 100644 --- a/code/game/machinery/_machines_base/machinery_power.dm +++ b/code/game/machinery/_machines_base/machinery_power.dm @@ -2,6 +2,8 @@ This is /obj/machinery level code to properly manage power usage from the area. */ +#define MACHINE_UPDATES_FROM_AREA_POWER !(stat_immune & NOPOWER) + // Note that we update the area even if the area is unpowered. #define REPORT_POWER_CONSUMPTION_CHANGE(old_power, new_power)\ if(old_power != new_power){\ @@ -9,7 +11,7 @@ This is /obj/machinery level code to properly manage power usage from the area. if(A) A.power_use_change(old_power, new_power, power_channel)} // returns true if the area has power on given channel (or doesn't require power), defaults to power_channel. -// May also optionally specify an area, otherwise defaults to src.loc.loc +// May also optionally specify an area, otherwise defaults to get_area(src) /obj/machinery/proc/powered(var/chan = -1, var/area/check_area = null) if(!src.loc) @@ -21,7 +23,7 @@ This is /obj/machinery level code to properly manage power usage from the area. // return 1 if(!check_area) - check_area = src.loc.loc // make sure it's in an area + check_area = get_area(src) // make sure it's in an area if(!check_area || !isarea(check_area)) return 0 // if not, then not powered if(chan == -1) @@ -81,32 +83,49 @@ This is /obj/machinery level code to properly manage power usage from the area. return // Do not do power stuff in New/Initialize until after ..() -/obj/machinery/Initialize() - REPORT_POWER_CONSUMPTION_CHANGE(0, get_power_usage()) - GLOB.moved_event.register(src, src, .proc/update_power_on_move) +/obj/machinery/Initialize(mapload) + if(MACHINE_UPDATES_FROM_AREA_POWER) + var/area/my_area = get_area(src) + if(istype(my_area)) + events_repository.register(/decl/observ/area_power_change, my_area, src, PROC_REF(power_change)) + if(mapload) // currently outside mapload, movables trigger loc/Entered(src, null) in ..(), which will update power. + REPORT_POWER_CONSUMPTION_CHANGE(0, get_power_usage()) + events_repository.register(/decl/observ/moved, src, src, PROC_REF(update_power_on_move)) power_init_complete = TRUE . = ..() // Or in Destroy at all, but especially after the ..(). /obj/machinery/Destroy() - GLOB.moved_event.unregister(src, src, .proc/update_power_on_move) + if(MACHINE_UPDATES_FROM_AREA_POWER) + var/area/my_area = get_area(src) + if(istype(my_area)) + events_repository.unregister(/decl/observ/area_power_change, my_area, src, PROC_REF(power_change)) + events_repository.unregister(/decl/observ/moved, src, src, PROC_REF(update_power_on_move)) REPORT_POWER_CONSUMPTION_CHANGE(get_power_usage(), 0) . = ..() /obj/machinery/proc/update_power_on_move(atom/movable/mover, atom/old_loc, atom/new_loc) area_changed(get_area(old_loc), get_area(new_loc)) +// An event that should be accurately triggered whenever our area changes. Returns TRUE if area changed and we have completed init, FALSE otherwise. /obj/machinery/proc/area_changed(area/old_area, area/new_area) + SHOULD_CALL_PARENT(TRUE) + if(!power_init_complete) + return FALSE // this is possible if called externally + if(old_area == new_area) - return + return FALSE + . = TRUE var/power = get_power_usage() - if(!power) - return // This is the most likely case anyway. - if(old_area) old_area.power_use_change(power, 0, power_channel) + if(MACHINE_UPDATES_FROM_AREA_POWER) + events_repository.unregister(/decl/observ/area_power_change, old_area, src, PROC_REF(power_change)) if(new_area) new_area.power_use_change(0, power, power_channel) + if(MACHINE_UPDATES_FROM_AREA_POWER) + events_repository.register(/decl/observ/area_power_change, new_area, src, PROC_REF(power_change)) + power_change() // Force check in case the old area was powered and the new one isn't or vice versa. // The three procs below are the only allowed ways of modifying the corresponding variables. @@ -120,6 +139,7 @@ This is /obj/machinery level code to properly manage power usage from the area. use_power = new_use_power var/new_power = get_power_usage() REPORT_POWER_CONSUMPTION_CHANGE(old_power, new_power) + queue_icon_update() /obj/machinery/proc/update_power_channel(new_channel) if(power_channel == new_channel) @@ -146,4 +166,22 @@ This is /obj/machinery level code to properly manage power usage from the area. if(power_init_complete && (use_power_mode == use_power)) REPORT_POWER_CONSUMPTION_CHANGE(old_power, new_power_consumption) -#undef REPORT_POWER_CONSUMPTION_CHANGE \ No newline at end of file +// Return the powernet of a cable node underneath the machine. +/obj/machinery/proc/get_powernet() + var/turf/T = loc + if(!istype(T)) + return + + var/obj/structure/cable/C = T.get_cable_node() + if(C) + return C.powernet + +// Adds available power to a connected powernet, if available. +/obj/machinery/proc/generate_power(var/amount) + var/datum/powernet/P = get_powernet() + if(!P) + return + P.newavail += amount + +#undef REPORT_POWER_CONSUMPTION_CHANGE +#undef MACHINE_UPDATES_FROM_AREA_POWER diff --git a/code/game/machinery/_machines_base/machinery_public_vars.dm b/code/game/machinery/_machines_base/machinery_public_vars.dm index 1cc1fd52f9fd..81871d962fa5 100644 --- a/code/game/machinery/_machines_base/machinery_public_vars.dm +++ b/code/game/machinery/_machines_base/machinery_public_vars.dm @@ -5,7 +5,7 @@ /decl/public_access/public_variable var/expected_type var/can_write = FALSE - var/var_type = IC_FORMAT_BOOLEAN // Reuses IC defines for better compatibility. + var/var_type = VAR_FORMAT_BOOLEAN // Reuses IC defines for better compatibility. var/has_updates = FALSE // Can register listeners for updates on change. var/list/listeners = list() @@ -17,10 +17,12 @@ Must be implemented by subtypes. // Reads off the var value and returns it /decl/public_access/public_variable/proc/access_var(datum/owner) -// Writes to the var. Returns true if change occured, false otherwise. +// Writes to the var. Returns true if change occurred, false otherwise. // Subtypes shall call parent, and perform the actual write if the return value is true. // If the var has_updates, you must never modify the var except through this proc. /decl/public_access/public_variable/proc/write_var(datum/owner, new_value) + if(!check_input_type(new_value)) + return FALSE var/old_value = access_var(owner) if(old_value == new_value) return FALSE @@ -32,7 +34,34 @@ Must be implemented by subtypes. /decl/public_access/public_variable/proc/write_var_protected(datum/owner, new_value) if(!can_write) return FALSE - write_var(owner, new_value) + return write_var(owner, new_value) + +// Checks the input type of the passed value without modification. +/decl/public_access/public_variable/proc/check_input_type(new_value) + . = FALSE + switch(var_type) + if(VAR_FORMAT_ANY) + return TRUE + if(VAR_FORMAT_STRING) + return istext(new_value) + if(VAR_FORMAT_CHAR) + return istext(new_value) && length(new_value) == 1 + if(VAR_FORMAT_COLOR) + return sanitize_hexcolor(new_value, null) == new_value + if(VAR_FORMAT_NUMBER) + return isnum(new_value) + if(VAR_FORMAT_DIR) + return new_value in global.alldirs + if(VAR_FORMAT_BOOLEAN) + return new_value == !!new_value + if(VAR_FORMAT_REF) + return isweakref(new_value) + + // Public variables of these types need to against the contents of the list and the index for validity themselves. + if(VAR_FORMAT_LIST) + return islist(new_value) + if(VAR_FORMAT_INDEX) + return isnum(new_value) /* Listener registration. You must unregister yourself if you are destroyed; the owner being destroyed will be handled automatically. @@ -46,7 +75,7 @@ Listener registration. You must unregister yourself if you are destroyed; the ow return // Can try and register, but updates aren't coming if(!listeners[owner]) listeners[owner] = list() - GLOB.destroyed_event.register(owner, src, .proc/owner_destroyed) + events_repository.register(/decl/observ/destroyed, owner, src, PROC_REF(owner_destroyed)) LAZYADD(listeners[owner][listener], registered_proc) return TRUE @@ -65,14 +94,14 @@ Listener registration. You must unregister yourself if you are destroyed; the ow if(!length(listeners[owner])) // Clean up the list if no longer listening to anything. listeners -= owner - GLOB.destroyed_event.unregister(owner, src) + events_repository.unregister(/decl/observ/destroyed, owner, src) /* Internal procs. Do not modify. */ /decl/public_access/public_variable/proc/owner_destroyed(datum/owner) - GLOB.destroyed_event.unregister(owner, src) + events_repository.unregister(/decl/observ/destroyed, owner, src) listeners -= owner /decl/public_access/public_variable/proc/var_changed(owner, old_value, new_value) @@ -91,9 +120,9 @@ Public methods machines can expose. Pretty bare-bones; just wraps a proc and giv /decl/public_access/public_method/proc/perform(datum/owner, ...) if(forward_args) - call(owner, call_proc)(arglist(args.Copy(2))) + return call(owner, call_proc)(arglist(args.Copy(2))) else - call(owner, call_proc)() + return call(owner, call_proc)() /* Machinery implementation @@ -105,7 +134,7 @@ Machinery implementation /obj/machinery/Initialize() for(var/path in public_variables) - public_variables[path] = decls_repository.get_decl(path) + public_variables[path] = GET_DECL(path) for(var/path in public_methods) - public_methods[path] = decls_repository.get_decl(path) + public_methods[path] = GET_DECL(path) . = ..() \ No newline at end of file diff --git a/code/game/machinery/_machines_base/machinery_public_vars_common.dm b/code/game/machinery/_machines_base/machinery_public_vars_common.dm index 46a74a1d2f06..82739c5e4f02 100644 --- a/code/game/machinery/_machines_base/machinery_public_vars_common.dm +++ b/code/game/machinery/_machines_base/machinery_public_vars_common.dm @@ -24,10 +24,10 @@ Public vars at /obj/machinery level. Just because they are here does not mean th /decl/public_access/public_method/toggle_input_toggle name = "toggle input" desc = "Toggles the input toggle variable." - call_proc = /obj/machinery/proc/toggle_input_toggle + call_proc = TYPE_PROC_REF(/obj/machinery, toggle_input_toggle) /obj/machinery/proc/toggle_input_toggle() - var/decl/public_access/public_variable/variable = decls_repository.get_decl(/decl/public_access/public_variable/input_toggle) + var/decl/public_access/public_variable/variable = GET_DECL(/decl/public_access/public_variable/input_toggle) variable.write_var(src, !input_toggle) /decl/public_access/public_variable/area_uid @@ -36,7 +36,7 @@ Public vars at /obj/machinery level. Just because they are here does not mean th desc = "An automatically generated area id, if this machine is tied to an area controller." can_write = FALSE has_updates = FALSE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/area_uid/access_var(obj/machinery/machine) return machine.area_uid() @@ -51,7 +51,7 @@ Public vars at /obj/machinery level. Just because they are here does not mean th desc = "A generic variable intended to give machines a text designator to sort them into categories by function." can_write = TRUE has_updates = TRUE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/identifier/access_var(obj/machinery/machine) return machine.identifier @@ -67,7 +67,7 @@ Public vars at /obj/machinery level. Just because they are here does not mean th desc = "Whether the machine is off (0) or on (positive). Some machines have multiple power states. Writing to this variable may turn the machine off or on." can_write = TRUE has_updates = FALSE - var_type = IC_FORMAT_NUMBER + var_type = VAR_FORMAT_NUMBER /decl/public_access/public_variable/use_power/access_var(obj/machinery/machine) return machine.use_power @@ -85,7 +85,7 @@ Public vars at /obj/machinery level. Just because they are here does not mean th desc = "The machine's name." can_write = TRUE has_updates = FALSE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/name/access_var(obj/machinery/machine) return machine.name @@ -95,10 +95,53 @@ Public vars at /obj/machinery level. Just because they are here does not mean th if(.) machine.SetName(new_value) +/decl/public_access/public_variable/reagents + expected_type = /obj/machinery + name = "reagents" + desc = "Obtain the list of reagents and their data in the machine." + can_write = FALSE + has_updates = TRUE + var_type = VAR_FORMAT_LIST + +/decl/public_access/public_variable/reagents/access_var(obj/machinery/machine) + return istype(machine?.reagents) ? UNLINT(machine.reagents.reagent_data) : null + +/decl/public_access/public_variable/reagents/volumes + name = "reagents volumes" + desc = "Obtain the list of reagents and their volumes in the machine." + var_type = VAR_FORMAT_LIST + +/decl/public_access/public_variable/reagents/volumes/access_var(obj/machinery/machine) + return istype(machine?.reagents) ? UNLINT(REAGENT_VOLUMES(machine.reagents)) : null + +/decl/public_access/public_variable/reagents/free_space + name = "reagents free space" + desc = "Obtain the volume of free space left for reagents in the machine." + var_type = VAR_FORMAT_NUMBER + +/decl/public_access/public_variable/reagents/free_space/access_var(obj/machinery/machine) + return REAGENTS_FREE_SPACE(machine?.reagents) + +/decl/public_access/public_variable/reagents/total_volume + name = "reagents total volume" + desc = "Obtain the total volume of reagents in the machine." + var_type = VAR_FORMAT_NUMBER + +/decl/public_access/public_variable/reagents/total_volume/access_var(obj/machinery/machine) + return REAGENT_TOTAL_VOLUME(machine?.reagents) + +/decl/public_access/public_variable/reagents/maximum_volume + name = "reagents maximum volume" + desc = "Obtain the maximum volume of reagents that can fit in the machine." + var_type = VAR_FORMAT_NUMBER + +/decl/public_access/public_variable/reagents/maximum_volume/access_var(obj/machinery/machine) + return REAGENT_MAXIMUM_VOLUME(machine?.reagents) + /decl/public_access/public_method/toggle_power name = "toggle power" desc = "Turns the machine on or off." - call_proc = /obj/machinery/proc/toggle_power + call_proc = TYPE_PROC_REF(/obj/machinery, toggle_power) /obj/machinery/proc/toggle_power() update_use_power(!use_power) @@ -106,7 +149,7 @@ Public vars at /obj/machinery level. Just because they are here does not mean th /decl/public_access/public_method/refresh name = "refresh machine" desc = "Attempts to refresh the machine's status. Implementation may vary." - call_proc = /obj/machinery/proc/refresh + call_proc = TYPE_PROC_REF(/obj/machinery, refresh) /obj/machinery/proc/refresh() queue_icon_update() \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm b/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm index a55d54d36dc0..f3c2bd507167 100644 --- a/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm +++ b/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm @@ -6,15 +6,16 @@ material = /decl/material/solid/metal/steel var/part_flags = PART_FLAG_LAZY_INIT | PART_FLAG_HAND_REMOVE var/rating = 1 - var/status = 0 // Flags using PART_STAT defines. - var/base_type // Type representing parent of category for replacer usage. + var/status = 0 // Flags using PART_STAT defines. + var/base_type // Type representing parent of category for replacer usage. + var/list/ignore_damage_types // Lazy list of damage types to ignore. /obj/item/stock_parts/attack_hand(mob/user) if(istype(loc, /obj/machinery)) return FALSE // Can potentially add uninstall code here, but not currently supported. return ..() -/obj/item/stock_parts/proc/set_status(var/obj/machinery/machine, var/flag) +/obj/item/stock_parts/proc/set_component_status(var/obj/machinery/machine, var/flag) var/old_stat = status status |= flag if(old_stat != status) @@ -33,7 +34,7 @@ machine.component_stat_change(src, old_stat, flag) /obj/item/stock_parts/proc/on_install(var/obj/machinery/machine) - set_status(machine, PART_STAT_INSTALLED) + set_component_status(machine, PART_STAT_INSTALLED) /obj/item/stock_parts/proc/on_uninstall(var/obj/machinery/machine, var/temporary = FALSE) unset_status(machine, PART_STAT_INSTALLED) @@ -44,15 +45,17 @@ // Use to process on the machine it's installed on. /obj/item/stock_parts/proc/start_processing(var/obj/machinery/machine) - LAZYDISTINCTADD(machine.processing_parts, src) - START_PROCESSING_MACHINE(machine, MACHINERY_PROCESS_COMPONENTS) - set_status(machine, PART_STAT_PROCESSING) + if(istype(machine)) + LAZYDISTINCTADD(machine.processing_parts, src) + START_PROCESSING_MACHINE(machine, MACHINERY_PROCESS_COMPONENTS) + set_component_status(machine, PART_STAT_PROCESSING) /obj/item/stock_parts/proc/stop_processing(var/obj/machinery/machine) - LAZYREMOVE(machine.processing_parts, src) - if(!LAZYLEN(machine.processing_parts)) - STOP_PROCESSING_MACHINE(machine, MACHINERY_PROCESS_COMPONENTS) - unset_status(machine, PART_STAT_PROCESSING) + if(istype(machine)) + LAZYREMOVE(machine.processing_parts, src) + if(!LAZYLEN(machine.processing_parts)) + STOP_PROCESSING_MACHINE(machine, MACHINERY_PROCESS_COMPONENTS) + unset_status(machine, PART_STAT_PROCESSING) /obj/item/stock_parts/proc/machine_process(var/obj/machinery/machine) return PROCESS_KILL @@ -60,18 +63,21 @@ // RefreshParts has been called, likely meaning other componenets were added/removed. /obj/item/stock_parts/proc/on_refresh(var/obj/machinery/machine) -/obj/item/stock_parts/proc/take_damage(amount, damtype) - if(!is_functional()) +/obj/item/stock_parts/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(damage_type in ignore_damage_types) + return + . = ..() + +/obj/item/stock_parts/check_health(lastdamage, lastdamtype, lastdamflags, consumed) + if(!can_take_damage()) return - var/taken = min(amount, health) - health -= taken - . = taken if(!is_functional()) - var/obj/machinery/machine = loc - if(istype(machine)) - on_fail(machine, damtype) + if(istype(loc, /obj/machinery)) + on_fail(loc, lastdamtype) + else + physically_destroyed() -/obj/item/stock_parts/proc/on_fail(var/obj/machinery/machine, damtype) +/obj/item/stock_parts/proc/on_fail(var/obj/machinery/machine, var/damtype) machine.on_component_failure(src) var/cause = "shatters" switch(damtype) @@ -80,18 +86,42 @@ if(ELECTROCUTE) cause = "sparks" visible_message(SPAN_WARNING("Something [cause] inside \the [machine]."), range = 2) - SetName("broken [name]") + update_name() + +/obj/item/stock_parts/update_name() + . = ..() + if(!is_functional()) + SetName("broken [name]") // prepend 'broken' to the results /obj/item/stock_parts/proc/is_functional() - return health > 0 + return (!can_take_damage()) || (current_health > 0) -/obj/item/stock_parts/examine(mob/user) +/obj/item/stock_parts/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(!is_functional()) - to_chat(user, SPAN_WARNING("It is completely broken.")) - else if(health < 0.5 * max_health) - to_chat(user, SPAN_WARNING("It is heavily damaged.")) - else if(health < 0.75 * max_health) - to_chat(user, SPAN_NOTICE("It is showing signs of damage.")) - else if(health < max_health) - to_chat(user, SPAN_NOTICE("It is showing some wear and tear.")) + if(can_take_damage()) + if(!is_functional()) + . += SPAN_WARNING("It is completely broken.") + else if(get_percent_health() < 50) + . += SPAN_WARNING("It is heavily damaged.") + else if(get_percent_health() < 75) + . += SPAN_NOTICE("It is showing signs of damage.") + else if(is_damaged()) + . += SPAN_NOTICE("It is showing some wear and tear.") + +//Machines handle damaging for us, so don't do it twice +/obj/item/stock_parts/explosion_act(severity) + var/obj/machinery/M = loc + if(istype(M) && (src in M.component_parts)) + return + ..() + +/// Alt-click interactions provided to our parent machine. +/obj/item/stock_parts/proc/get_machine_alt_interactions(mob/user) + SHOULD_CALL_PARENT(TRUE) + SHOULD_BE_PURE(TRUE) + RETURN_TYPE(/list) + . = list() + +/// A stub for showing messages based on part status when a machine is examined. +/obj/item/stock_parts/proc/on_machine_examined(mob/user) + SHOULD_CALL_PARENT(TRUE) diff --git a/code/game/machinery/_machines_base/stock_parts/access_lock.dm b/code/game/machinery/_machines_base/stock_parts/access_lock.dm index 303d8085542a..8d6b4aec8cea 100644 --- a/code/game/machinery/_machines_base/stock_parts/access_lock.dm +++ b/code/game/machinery/_machines_base/stock_parts/access_lock.dm @@ -1,20 +1,29 @@ /obj/item/stock_parts/access_lock name = "access lock" desc = "An id-based access lock preventing tampering with a machine's hardware." - icon_state = "scan_module" - part_flags = PART_FLAG_QDEL | PART_FLAG_NODAMAGE + icon_state = "lock" + part_flags = PART_FLAG_QDEL req_access = list(access_engine_equip) // set req_access on this to impose access requirements. + max_health = ITEM_HEALTH_NO_DAMAGE var/locked = FALSE var/emagged = FALSE + var/autoset = FALSE // Whether the machine should inherit access from surrounding areas + var/list/conf_access + var/one_access = FALSE //if set, door would receive OR instead of AND on the access restrictions. /obj/machinery/cannot_transition_to(state_path, mob/user) - var/decl/machine_construction/state = decls_repository.get_decl(state_path) + var/decl/machine_construction/state = GET_DECL(state_path) if(state && !state.locked && construct_state && construct_state.locked) // we're locked, we're becoming unlocked for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) if(lock.locked && !lock.check_access(user)) return SPAN_WARNING("\The [lock] flashes red! You lack the access to unlock this.") return ..() +/obj/item/stock_parts/access_lock/get_req_access() + if(istype(loc, /obj/machinery)) // so you can set up accesses you don't have + return ..() + return null + /obj/item/stock_parts/access_lock/emag_act(remaining_charges, mob/user, emag_source) . = ..() if(length(req_access) && locked && istype(loc, /obj/machinery)) // Don't emag it outside; you can just cut access without it anyway. @@ -25,6 +34,8 @@ /obj/item/stock_parts/access_lock/on_install(obj/machinery/machine) . = ..() + if(autoset) + req_access = machine.get_auto_access() if(!emagged) locked = TRUE @@ -36,49 +47,113 @@ . = ..() locked = FALSE -/obj/item/stock_parts/access_lock/examine(mob/user) +/obj/item/stock_parts/access_lock/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(locked) - to_chat(user, "The lock is engaged.") + . += "The lock is engaged." if(emagged && user.skill_check_multiple(list(SKILL_FORENSICS = SKILL_EXPERT, SKILL_COMPUTER = SKILL_EXPERT))) - to_chat(user, SPAN_WARNING("On close inspection, there is something odd about the interface. You suspect it may have been tampered with.")) + . += SPAN_WARNING("On close inspection, there is something odd about the interface. You suspect it may have been tampered with.") -/obj/item/stock_parts/access_lock/attackby(obj/item/W, mob/user) +/obj/item/stock_parts/access_lock/attackby(obj/item/used_item, mob/user) var/obj/machinery/machine = loc if(!emagged && istype(machine)) - if(check_access(W)) + var/obj/item/card/id/I = used_item.GetIdCard() + if(I && check_access(I)) locked = !locked visible_message(SPAN_NOTICE("\The [src] beeps and flashes green twice: it is now [locked ? "" : "un"]locked.")) return TRUE - return + return ..() - if(isMultitool(W)) // This is a non-machine interaction only; doing this within a machine will likely lead to interaction clashes. - var/list/accesses = user.GetAccess() - var/list/choices = list() - for(var/key in accesses) - choices[get_access_desc(key)] = key - choices["No Access"] = "No Access" - var/default = length(req_access) ? req_access[1] : null - var/selected_desc = input(user, "Select the access you would like \the [src] to use:", "Access Modification", default) as null|anything in choices - . = TRUE - if(!CanPhysicallyInteract(user)) - return - if(!selected_desc) - return - if(selected_desc == "No Access") - req_access.Cut() - return - if(!(choices[selected_desc] in user.GetAccess())) - return - req_access = list(choices[selected_desc]) - return +/obj/item/stock_parts/access_lock/attack_self(mob/user) + ui_interact(user) - return ..() +/obj/item/stock_parts/access_lock/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/topic_state/state = global.hands_topic_state) + var/list/data = ui_data() + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "airlock_electronics.tmpl", src.name, 1000, 500, null, null, state) + ui.set_initial_data(data) + ui.open() + +/obj/item/stock_parts/access_lock/ui_data() + var/list/data = list() + var/list/regions = list() + if(!autoset) + for(var/i in ACCESS_REGION_MIN to ACCESS_REGION_MAX) //code/game/jobs/_access_defs.dm + var/list/region = list() + var/list/accesses = list() + for(var/j in get_region_accesses(i)) + var/list/access = list() + access["name"] = get_access_desc(j) + access["id"] = j + access["req"] = conf_access && (j in conf_access) + accesses[++accesses.len] = access + region["name"] = get_region_accesses_name(i) + region["accesses"] = accesses + regions[++regions.len] = region + data["regions"] = regions + data["oneAccess"] = one_access + data["locked"] = locked + data["lockable"] = !emagged + data["autoset"] = autoset + return data + +/obj/item/stock_parts/access_lock/OnTopic(mob/user, list/href_list, state) + if(!emagged) + if(href_list["unlock"]) + if(!req_access) + locked = FALSE + else + var/obj/item/card/id/I = user.GetIdCard() + if(!istype(I, /obj/item/card/id)) + to_chat(user, SPAN_WARNING("[\src] flashes a yellow LED near the ID scanner. Did you remember to scan your ID or PDA?")) + return TOPIC_HANDLED + if (check_access(I)) + locked = FALSE + else + to_chat(user, SPAN_WARNING("[\src] flashes a red LED near the ID scanner, indicating your access has been denied.")) + return TOPIC_HANDLED + return TOPIC_REFRESH + else if(href_list["lock"]) + locked = TRUE + return TOPIC_REFRESH + + if(href_list["clear"]) + conf_access = null + one_access = FALSE + update_access() + return TOPIC_REFRESH + if(href_list["one_access"]) + one_access = !one_access + update_access() + return TOPIC_REFRESH + if(href_list["autoset"]) + autoset = !autoset + return TOPIC_REFRESH + if(href_list["access"]) + var/access = href_list["access"] + if (!conf_access || !(access in conf_access)) + LAZYADD(conf_access, access) + else + LAZYREMOVE(conf_access, access) + update_access() + return TOPIC_REFRESH + +/obj/item/stock_parts/access_lock/proc/update_access() + if(!conf_access) + req_access = list() + return + if(one_access) + req_access = list(conf_access.Copy()) + else + req_access = conf_access.Copy() /obj/item/stock_parts/access_lock/buildable + max_health = null //Buildable variant may take damage part_flags = PART_FLAG_HAND_REMOVE material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /decl/stock_part_preset/access_lock expected_part_type = /obj/item/stock_parts/access_lock diff --git a/code/game/machinery/_machines_base/stock_parts/building_material.dm b/code/game/machinery/_machines_base/stock_parts/building_material.dm index efb788392dd5..2ad4e83360f9 100644 --- a/code/game/machinery/_machines_base/stock_parts/building_material.dm +++ b/code/game/machinery/_machines_base/stock_parts/building_material.dm @@ -5,7 +5,8 @@ gender = PLURAL icon = 'icons/obj/power.dmi' icon_state = "coil" - part_flags = PART_FLAG_QDEL | PART_FLAG_NODAMAGE + part_flags = PART_FLAG_QDEL + max_health = ITEM_HEALTH_NO_DAMAGE var/list/materials /obj/item/stock_parts/building_material/Destroy() @@ -32,23 +33,32 @@ new_material.forceMove(null) // amount will cap the amount given in a stack, but may return less than amount specified. -/obj/item/stock_parts/building_material/proc/remove_material(material_type, amount) +/obj/item/stock_parts/building_material/proc/remove_material(material_type, amount, force_destination) if(ispath(material_type, /obj/item/stack)) for(var/obj/item/stack/stack in materials) - if(stack.stacktype == material_type) + if(stack.stack_merge_type == material_type) var/stack_amount = stack.get_amount() if(stack_amount <= amount) materials -= stack - stack.dropInto(loc) + if(force_destination) + stack.forceMove(force_destination) + else + stack.dropInto(loc) amount -= stack_amount return stack var/obj/item/stack/new_stack = stack.split(amount) - new_stack.dropInto(loc) + if(force_destination) + new_stack.forceMove(force_destination) + else + new_stack.dropInto(loc) return new_stack for(var/obj/item/item in materials) if(istype(item, material_type)) materials -= item - item.dropInto(loc) + if(force_destination) + item.forceMove(force_destination) + else + item.dropInto(loc) return item /obj/item/stock_parts/building_material/on_uninstall(var/obj/machinery/machine) @@ -57,9 +67,9 @@ materials = null ..() -/obj/item/stock_parts/building_material/building_cost() +/obj/item/stock_parts/building_material/get_contained_matter(include_reagents = TRUE) . = ..() for(var/obj/item/thing in materials) - var/list/costs = thing.building_cost() + var/list/costs = thing.get_contained_matter(include_reagents) for(var/key in costs) - .[key] += costs[key] \ No newline at end of file + .[key] += costs[key] diff --git a/code/game/machinery/_machines_base/stock_parts/card_reader.dm b/code/game/machinery/_machines_base/stock_parts/card_reader.dm new file mode 100644 index 000000000000..05472503c246 --- /dev/null +++ b/code/game/machinery/_machines_base/stock_parts/card_reader.dm @@ -0,0 +1,77 @@ +//#TODO: card reader should have its own includable tmpl, and override ui_data so machines don't have to reimplemnt the id card stuff a million time. +/** + * Stock part for accessing/holding the subtypes of /obj/item/card. + */ +/obj/item/stock_parts/item_holder/card_reader + name = "RFID card reader" + desc = "A RFID card reader for various authentication or data sharing usages." + icon = 'icons/obj/items/stock_parts/modular_components.dmi' + icon_state = "cardreader" + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, + ) + max_health = ITEM_HEALTH_NO_DAMAGE + eject_handler = /decl/interaction_handler/remove_held_item/card + var/should_swipe = FALSE //Whether the card should only be swiped instead of being inserted + var/obj/item/card/inserted_card //Card currently in the slot + +/obj/item/stock_parts/item_holder/card_reader/buildable + part_flags = PART_FLAG_HAND_REMOVE + max_health = 56 + +/obj/item/stock_parts/item_holder/card_reader/Destroy() + QDEL_NULL(inserted_card) + . = ..() + +/obj/item/stock_parts/item_holder/card_reader/is_item_inserted() + return !isnull(inserted_card) + +/obj/item/stock_parts/item_holder/card_reader/is_accepted_type(obj/O) + return istype(O, /obj/item/card) + +/obj/item/stock_parts/item_holder/card_reader/get_inserted() + return inserted_card + +/obj/item/stock_parts/item_holder/card_reader/set_inserted(obj/O) + inserted_card = O + +/obj/item/stock_parts/item_holder/card_reader/get_description_insertable() + return "card" + +/obj/item/stock_parts/item_holder/card_reader/insert_item(obj/item/card/O, mob/user) + if(should_swipe && is_accepted_type(O)) + return swipe_card(O, user) + . = ..() + +/obj/item/stock_parts/item_holder/card_reader/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item) && !istype(loc, /obj/machinery)) //Only if not in the machine, to prevent hijacking tool interactions with the machine + should_swipe = !should_swipe + to_chat(user, SPAN_NOTICE("You toggle \the [src] into [should_swipe? "swipe" : "insert"] card mode.")) + return TRUE + . = ..() + +/obj/item/stock_parts/item_holder/card_reader/proc/swipe_card(var/obj/item/card/C, var/mob/user) + if(user) + to_chat(user, SPAN_NOTICE("You swipe \the [C] in \the [src].")) + if(on_insert_target) + on_insert_target.InvokeAsync(C, user) + return TRUE + +/obj/item/stock_parts/item_holder/card_reader/proc/get_id_card() + return istype(inserted_card, /obj/item/card/id) ? inserted_card : null + +/obj/item/stock_parts/item_holder/card_reader/proc/get_data_card() + return istype(inserted_card, /obj/item/card/data) ? inserted_card : null + +/obj/item/stock_parts/item_holder/card_reader/proc/get_emag_card() + return istype(inserted_card, /obj/item/card/emag) ? inserted_card : null + +/decl/interaction_handler/remove_held_item/card + name = "Eject Card" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject_id" + expected_component_type = /obj/item/stock_parts/item_holder/card_reader + examine_desc = "eject an inserted ID card" diff --git a/code/game/machinery/_machines_base/stock_parts/cupholder.dm b/code/game/machinery/_machines_base/stock_parts/cupholder.dm new file mode 100644 index 000000000000..3a3b0aafeba3 --- /dev/null +++ b/code/game/machinery/_machines_base/stock_parts/cupholder.dm @@ -0,0 +1,50 @@ +/obj/item/stock_parts/item_holder/cupholder + name = "cupholder" + desc = "A holder for cups." + icon = 'icons/obj/items/stock_parts/modular_components.dmi' + icon_state = "cupholder" + material = /decl/material/solid/organic/plastic + part_flags = PART_FLAG_HAND_REMOVE + place_verb = "place" + eject_handler = /decl/interaction_handler/remove_held_item/cup + var/obj/item/cup + +/obj/item/stock_parts/item_holder/cupholder/Destroy() + QDEL_NULL(cup) + . = ..() + +/obj/item/stock_parts/item_holder/cupholder/is_item_inserted() + return !isnull(cup) + +/obj/item/stock_parts/item_holder/cupholder/is_accepted_type(obj/O) + var/static/allowed_cup_types + if(!allowed_cup_types) + allowed_cup_types = typecacheof(list( + /obj/item/chems/drinks/cans, + /obj/item/chems/drinks/bottle, + /obj/item/chems/glass/bottle, + /obj/item/chems/drinks/juicebox, + /obj/item/chems/drinks/glass2, + /obj/item/chems/drinks/h_chocolate, + /obj/item/chems/drinks/dry_ramen, + /obj/item/chems/drinks/tea, + /obj/item/chems/glass/handmade/cup, + /obj/item/chems/glass/handmade/mug, + /obj/item/chems/drinks/shaker, + /obj/item/chems/drinks/flask + )) + return is_type_in_typecache(O, allowed_cup_types) + +/obj/item/stock_parts/item_holder/cupholder/get_inserted() + return cup + +/obj/item/stock_parts/item_holder/cupholder/set_inserted(obj/O) + cup = O + +/obj/item/stock_parts/item_holder/cupholder/get_description_insertable() + return "cup" + +/decl/interaction_handler/remove_held_item/cup + name = "Remove Cup" + expected_component_type = /obj/item/stock_parts/item_holder/cupholder + examine_desc = "remove a cup" diff --git a/code/game/machinery/_machines_base/stock_parts/disk_reader.dm b/code/game/machinery/_machines_base/stock_parts/disk_reader.dm new file mode 100644 index 000000000000..7c35679ef557 --- /dev/null +++ b/code/game/machinery/_machines_base/stock_parts/disk_reader.dm @@ -0,0 +1,46 @@ +//#TODO: disk reader should have its own includable tmpl, and override ui_data so machines don't have to reimplemnt the disk stuff a million time in their ui. +/** + * Stock part for reading/writing to an inserted data disk. + */ +/obj/item/stock_parts/item_holder/disk_reader + name = "disk drive" + desc = "A floppy disk drive for installation in most machines. Able to read most floppy disks." + icon = 'icons/obj/items/stock_parts/modular_components.dmi' + icon_state = "floppy_drive" + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + ) + max_health = ITEM_HEALTH_NO_DAMAGE + eject_handler = /decl/interaction_handler/remove_held_item/disk + var/obj/item/disk/disk //Disk currently inserted + +/obj/item/stock_parts/item_holder/disk_reader/buildable + part_flags = PART_FLAG_HAND_REMOVE + max_health = 56 + +/obj/item/stock_parts/item_holder/disk_reader/Destroy() + QDEL_NULL(disk) + . = ..() + +/obj/item/stock_parts/item_holder/disk_reader/is_item_inserted() + return !isnull(disk) + +/obj/item/stock_parts/item_holder/disk_reader/is_accepted_type(obj/O) + return istype(O, /obj/item/disk) + +/obj/item/stock_parts/item_holder/disk_reader/get_inserted() + return disk + +/obj/item/stock_parts/item_holder/disk_reader/set_inserted(obj/O) + disk = O + +/obj/item/stock_parts/item_holder/disk_reader/get_description_insertable() + return "disk" + +/decl/interaction_handler/remove_held_item/disk + name = "Eject Disk" + expected_component_type = /obj/item/stock_parts/item_holder/disk_reader + examine_desc = "remove a disk" diff --git a/code/game/machinery/_machines_base/stock_parts/item_holder.dm b/code/game/machinery/_machines_base/stock_parts/item_holder.dm new file mode 100644 index 000000000000..cb875fa65dec --- /dev/null +++ b/code/game/machinery/_machines_base/stock_parts/item_holder.dm @@ -0,0 +1,160 @@ +/** + * Base class for stock parts that allow an item to be inserted while the maintenance panel is closed. + */ +/obj/item/stock_parts/item_holder + name = null + desc = null + icon = 'icons/obj/items/stock_parts/modular_components.dmi' + var/decl/interaction_handler/eject_handler // The interaction handler type used for alt-interactions. + var/datum/callback/on_insert_target //Callback to call when an item is inserted + var/datum/callback/on_eject_target //Callback to call when an item is ejected + /// The verb used when a player inserts an item. + /// e.g. You [insert/place/attach] the cup in the cupholder. + var/place_verb = "insert" + +/obj/item/stock_parts/item_holder/Destroy() + unregister_on_insert() + unregister_on_eject() + . = ..() + +/obj/item/stock_parts/item_holder/attackby(obj/item/used_item, mob/user) + if(is_accepted_type(used_item)) + insert_item(used_item, user) + return TRUE + . = ..() + + +/obj/item/stock_parts/item_holder/attack_self(mob/user) + if(is_item_inserted()) + eject_item(user) + return TRUE + . = ..() + +///Returns whether there is an item contained in the component. +/obj/item/stock_parts/item_holder/proc/is_item_inserted() + return FALSE + +///Returns whether the object can be handled by the component. +/obj/item/stock_parts/item_holder/proc/is_accepted_type(var/obj/O) + return FALSE + +///Returns the inserted object if there is one, or null. +/obj/item/stock_parts/item_holder/proc/get_inserted() + return + +/obj/item/stock_parts/item_holder/on_machine_examined(mob/user) + . = ..() + if(is_item_inserted()) + LAZYADD(., SPAN_INFO("It has \a [get_inserted()] in \the [src].")) + +///Handle putting the object in the component's contents. Doesn't trigger any callbacks, or messages. +/obj/item/stock_parts/item_holder/proc/set_inserted(var/obj/O) + return + +///Returns a string to describe the kind of item that can be inserted. For instance, "disk" in the case of a data disk. +/obj/item/stock_parts/item_holder/proc/get_description_insertable() + return + +///Insert the given object into the component, trigger callbacks, and transfer the item from the user if there is one. +/obj/item/stock_parts/item_holder/proc/insert_item(var/obj/O, var/mob/user) + if(is_item_inserted()) + if(user) + to_chat(user, SPAN_WARNING("There is already \a [get_inserted()] in \the [src].")) + return FALSE + + if(user) + if(user.try_unequip(O, src)) + to_chat(user, SPAN_NOTICE("You [place_verb] \the [O] into \the [src].")) + else + return FALSE + else + O.forceMove(src) + + set_inserted(O) + + if(on_insert_target) + on_insert_target.InvokeAsync(O, user) + return TRUE + +///Eject the contained item. +/obj/item/stock_parts/item_holder/proc/eject_item(var/mob/user) + if(!is_item_inserted()) + if(user) + to_chat(user, SPAN_WARNING("There's no [get_description_insertable()] in \the [src].")) + return + + var/obj/O = get_inserted() + if(user && loc.Adjacent(user)) // Check adjacency in case this is called via UI stuff from a distance. + user.put_in_hands(O) + to_chat(user, SPAN_NOTICE("You remove \the [O] from \the [src].")) + else + O.forceMove(get_turf(src)) + + . = O + + if(on_eject_target) + on_eject_target.InvokeAsync(O, user) + set_inserted(null) + +/////////////////////////////////////////// +// Callback Handling +/////////////////////////////////////////// + +/obj/item/stock_parts/item_holder/on_install(obj/machinery/machine) + unregister_on_insert() + unregister_on_eject() + . = ..() + +/obj/item/stock_parts/item_holder/on_uninstall(obj/machinery/machine, temporary) + unregister_on_insert() + unregister_on_eject() + . = ..() + +/obj/item/stock_parts/item_holder/proc/register_on_insert(var/datum/callback/cback) + on_insert_target = cback + +/obj/item/stock_parts/item_holder/proc/register_on_eject(var/datum/callback/cback) + on_eject_target = cback + +/obj/item/stock_parts/item_holder/proc/unregister_on_insert() + QDEL_NULL(on_insert_target) + +/obj/item/stock_parts/item_holder/proc/unregister_on_eject() + QDEL_NULL(on_eject_target) + +// Alt interaction handling +/decl/interaction_handler/remove_held_item + abstract_type = /decl/interaction_handler/remove_held_item + expected_target_type = /obj/machinery + name = "Eject Item" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject" + examine_desc = "eject an item" + var/obj/item/stock_parts/item_holder/expected_component_type + +/decl/interaction_handler/remove_held_item/validate() + . = ..() + if(!ispath(expected_component_type)) + . += "Expected component type was [isnull(expected_component_type) ? "NULL" : expected_component_type], expected /obj/item/stock_parts/item_holder subtype" + +/decl/interaction_handler/remove_held_item/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/obj/machinery/target_machine = target + // Check all components, not just the first one. Maybe we have multiple! + for(var/obj/item/stock_parts/item_holder/holder in target_machine.get_all_components_of_type(expected_component_type)) + if(holder.is_item_inserted()) + return TRUE + +/decl/interaction_handler/remove_held_item/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/target_machine = target + // Check all components, not just the first one. Maybe we have multiple! + for(var/obj/item/stock_parts/item_holder/holder in target_machine.get_all_components_of_type(expected_component_type)) + if(holder.is_item_inserted()) + holder.eject_item(user) + return + +/obj/item/stock_parts/item_holder/get_machine_alt_interactions(mob/user) + . = ..() + if(ispath(eject_handler)) + LAZYADD(., eject_handler) diff --git a/code/game/machinery/_machines_base/stock_parts/legacy_parts.dm b/code/game/machinery/_machines_base/stock_parts/legacy_parts.dm index 1301a53b656c..82c1e1736196 100644 --- a/code/game/machinery/_machines_base/stock_parts/legacy_parts.dm +++ b/code/game/machinery/_machines_base/stock_parts/legacy_parts.dm @@ -4,16 +4,16 @@ name = "scanning module" desc = "A compact, high resolution scanning module used in the construction of certain devices." icon_state = "scan_module" - origin_tech = "{'magnets':1}" + origin_tech = @'{"magnets":1}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) base_type = /obj/item/stock_parts/scanning_module /obj/item/stock_parts/manipulator name = "micro-manipulator" desc = "A tiny little manipulator used in the construction of certain devices." icon_state = "micro_mani" - origin_tech = "{'materials':1,'programming':1}" + origin_tech = @'{"materials":1,"programming":1}' material = /decl/material/solid/metal/steel base_type = /obj/item/stock_parts/manipulator @@ -21,16 +21,16 @@ name = "micro-laser" desc = "A tiny laser used in certain devices." icon_state = "micro_laser" - origin_tech = "{'magnets':1}" + origin_tech = @'{"magnets":1}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) base_type = /obj/item/stock_parts/micro_laser /obj/item/stock_parts/matter_bin name = "matter bin" desc = "A container for hold compressed matter awaiting re-construction." icon_state = "matter_bin" - origin_tech = "{'materials':1}" + origin_tech = @'{"materials":1}' material = /decl/material/solid/metal/steel base_type = /obj/item/stock_parts/matter_bin @@ -38,12 +38,12 @@ name = "capacitor" desc = "A basic capacitor used in the construction of a variety of devices." icon_state = "capacitor" - origin_tech = "{'powerstorage':1}" + origin_tech = @'{"powerstorage":1}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + base_type = /obj/item/stock_parts/capacitor var/charge = 0 var/max_charge = 1000 - base_type = /obj/item/stock_parts/capacitor /obj/item/stock_parts/capacitor/Initialize() . = ..() @@ -64,17 +64,17 @@ /obj/item/stock_parts/scanning_module/adv name = "advanced scanning module" desc = "A compact, high resolution scanning module used in the construction of certain devices." - icon_state = "scan_module" - origin_tech = "{'magnets':3}" + icon_state = "advanced_scan_module" + origin_tech = @'{"magnets":3}' rating = 2 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/manipulator/nano name = "nano-manipulator" desc = "A tiny little manipulator used in the construction of certain devices." icon_state = "nano_mani" - origin_tech = "{'materials':3,'programming':2}" + origin_tech = @'{"materials":3,"programming":2}' rating = 2 material = /decl/material/solid/metal/steel @@ -82,7 +82,7 @@ name = "high-power micro-laser" desc = "A tiny laser used in certain devices." icon_state = "high_micro_laser" - origin_tech = "{'magnets':3}" + origin_tech = @'{"magnets":3}' rating = 2 material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) @@ -91,14 +91,15 @@ name = "advanced matter bin" desc = "A container for hold compressed matter awaiting re-construction." icon_state = "advanced_matter_bin" - origin_tech = "{'materials':3}" + origin_tech = @'{"materials":3}' rating = 2 material = /decl/material/solid/metal/steel /obj/item/stock_parts/capacitor/adv name = "advanced capacitor" desc = "An advanced capacitor used in the construction of a variety of devices." - origin_tech = "{'powerstorage':3}" + origin_tech = @'{"powerstorage":3}' + icon_state = "advanced_capacitor" rating = 2 //Rating 3 @@ -106,11 +107,12 @@ /obj/item/stock_parts/scanning_module/phasic name = "phasic scanning module" desc = "A compact, high resolution phasic scanning module used in the construction of certain devices." - origin_tech = "{'magnets':5}" + icon_state = "phasic_scan_module" + origin_tech = @'{"magnets":5}' rating = 3 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) @@ -118,7 +120,7 @@ name = "pico-manipulator" desc = "A tiny little manipulator used in the construction of certain devices." icon_state = "pico_mani" - origin_tech = "{'materials':5,'programming':2}" + origin_tech = @'{"materials":5,"programming":2}' rating = 3 material = /decl/material/solid/metal/steel @@ -126,7 +128,7 @@ name = "ultra-high-power micro-laser" icon_state = "ultra_high_micro_laser" desc = "A tiny laser used in certain devices." - origin_tech = "{'magnets':5}" + origin_tech = @'{"magnets":5}' rating = 3 material = /decl/material/solid/metal/steel matter = list( @@ -138,17 +140,18 @@ name = "super matter bin" desc = "A container for hold compressed matter awaiting re-construction." icon_state = "super_matter_bin" - origin_tech = "{'materials':5}" + origin_tech = @'{"materials":5}' rating = 3 material = /decl/material/solid/metal/steel /obj/item/stock_parts/capacitor/super name = "super capacitor" desc = "A super-high capacity capacitor used in the construction of a variety of devices." - origin_tech = "{'powerstorage':5,'materials':4}" + icon_state = "super_capacitor" + origin_tech = @'{"powerstorage":5,"materials":4}' material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) rating = 3 @@ -159,15 +162,15 @@ name = "subspace ansible" icon_state = "subspace_ansible" desc = "A compact module capable of sensing extradimensional activity." - origin_tech = "{'programming':3,'magnets':5,'materials':4,'wormholes':2}" + origin_tech = @'{"programming":3,"magnets":5,"materials":4,"wormholes":2}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/subspace/filter name = "hyperwave filter" icon_state = "hyperwave_filter" - desc = "A tiny device capable of filtering and converting super-intense radiowaves." - origin_tech = "{'programming':4,'magnets':2}" + desc = "A tiny device capable of filtering and converting super-intense radio waves." + origin_tech = @'{"programming":4,"magnets":2}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT) @@ -175,7 +178,7 @@ name = "subspace amplifier" icon_state = "subspace_amplifier" desc = "A compact micro-machine capable of amplifying weak subspace transmissions." - origin_tech = "{'programming':3,'magnets':4,'materials':4,'wormholes':2}" + origin_tech = @'{"programming":3,"magnets":4,"materials":4,"wormholes":2}' material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, @@ -186,7 +189,7 @@ name = "subspace treatment disk" icon_state = "treatment_disk" desc = "A compact micro-machine capable of stretching out hyper-compressed radio waves." - origin_tech = "{'programming':3,'magnets':2,'materials':5,'wormholes':2}" + origin_tech = @'{"programming":3,"magnets":2,"materials":5,"wormholes":2}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT) @@ -194,7 +197,7 @@ name = "subspace wavelength analyzer" icon_state = "wavelength_analyzer" desc = "A sophisticated analyzer capable of analyzing cryptic subspace wavelengths." - origin_tech = "{'programming':3,'magnets':4,'materials':4,'wormholes':2}" + origin_tech = @'{"programming":3,"magnets":4,"materials":4,"wormholes":2}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT) @@ -202,7 +205,7 @@ name = "ansible crystal" icon_state = "ansible_crystal" desc = "A crystal made from pure glass used to transmit laser databursts to subspace." - origin_tech = "{'magnets':4,'materials':4,'wormholes':2}" + origin_tech = @'{"magnets":4,"materials":4,"wormholes":2}' material = /decl/material/solid/glass matter = list( /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, @@ -213,7 +216,7 @@ name = "subspace transmitter" icon_state = "subspace_transmitter" desc = "A large piece of equipment used to open a window into the subspace dimension." - origin_tech = "{'magnets':5,'materials':5,'wormholes':3}" + origin_tech = @'{"magnets":5,"materials":5,"wormholes":3}' material = /decl/material/solid/glass matter = list( /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, diff --git a/code/game/machinery/_machines_base/stock_parts/network_lock.dm b/code/game/machinery/_machines_base/stock_parts/network_lock.dm index b1a7674efc1c..b3a275a51b6c 100644 --- a/code/game/machinery/_machines_base/stock_parts/network_lock.dm +++ b/code/game/machinery/_machines_base/stock_parts/network_lock.dm @@ -1,36 +1,41 @@ -/obj/item/stock_parts/network_lock +#define MAX_PATTERNS 10 + +/obj/item/stock_parts/network_receiver/network_lock name = "network access lock" desc = "An id-based access lock preventing tampering with a machine's hardware and software. Connects wirelessly to network." - icon_state = "scan_module" + icon_state = "net_lock" part_flags = PART_FLAG_QDEL - base_type = /obj/item/stock_parts/network_lock + base_type = /obj/item/stock_parts/network_receiver/network_lock var/auto_deny_all // Set this to TRUE to deny all access attempts if network connection is lost. - var/initial_network_id // The address to the network - var/initial_network_key // network KEY - var/list/grants = list() // List of grants required to operate the device. + var/selected_parent_group // Current selected parent_group for access assignment. + + var/list/groups // List of lists of groups. In order to access the device, users must have membership in at least one + // of the groups in each list. + var/selected_pattern // Index of the group pattern selected. + var/emagged // Whether or not this has been emagged. var/error - var/signal_strength = NETWORK_CONNECTION_WIRELESS // How good the wireless capabilities are of this card. + var/interact_sounds = list("keyboard", "keystroke") var/interact_sound_volume = 40 -/obj/item/stock_parts/network_lock/Initialize() - . = ..() - set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, signal_strength) - -/obj/item/stock_parts/network_lock/emag_act(remaining_charges, mob/user, emag_source) +/obj/item/stock_parts/network_receiver/network_lock/emag_act(remaining_charges, mob/user, emag_source) . = ..() - if(length(req_access) && istype(loc, /obj/machinery)) // Don't emag it outside; you can just cut access without it anyway. + if(istype(loc, /obj/machinery)) // Don't emag it outside; you can just cut access without it anyway. emagged = TRUE to_chat(user, SPAN_NOTICE("You slide the card into \the [src]. It flashes purple briefly, then disengages.")) . = max(., 1) // Override. This checks the network and builds a dynamic req_access list for the device it's attached to. -/obj/item/stock_parts/network_lock/get_req_access() +/obj/item/stock_parts/network_receiver/network_lock/get_req_access() + // Broken network locks require no access. + if(!is_functional()) + return list() + . = get_default_access() var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) - var/datum/computer_network/network = D.get_network() + var/datum/computer_network/network = D.get_network(NET_FEATURE_ACCESS) if(!network) return @@ -38,31 +43,52 @@ if(!access_controller) return - var/list/resulting_grants = list() - for(var/grant_data in grants) - var/datum/computer_file/data/grant_record/grant = access_controller.get_grant(grant_data) - if(!istype(grant)) - continue // couldn't find. - resulting_grants |= uppertext("[D.network_id].[grant_data]") - - if(!resulting_grants.len) + LAZYINITLIST(groups) + var/list/resulting_access = list() + for(var/list/pattern in groups) + var/list/resulting_pattern = list() + for(var/group in pattern) + if(!(group in access_controller.get_all_groups())) + pattern -= group // This group doesn't exist anymore - delete it. + continue + resulting_pattern |= "[group].[D.network_id]" + if(resulting_pattern.len) + resulting_access += list(resulting_pattern) + if(!length(resulting_access)) return - return list(resulting_grants) // List of lists is an OR type access configuration. + return resulting_access -/obj/item/stock_parts/network_lock/proc/get_default_access() +/obj/item/stock_parts/network_receiver/network_lock/proc/get_default_access() if(auto_deny_all) return list("NO_PERMISSIONS_DENY_ALL") return list() -/obj/item/stock_parts/network_lock/examine(mob/user) +/obj/item/stock_parts/network_receiver/network_lock/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(emagged && user.skill_check_multiple(list(SKILL_FORENSICS = SKILL_EXPERT, SKILL_COMPUTER = SKILL_EXPERT))) - to_chat(user, SPAN_WARNING("On close inspection, there is something odd about the interface. You suspect it may have been tampered with.")) + . += SPAN_WARNING("On closer inspection, there is something odd about the interface. You suspect it may have been tampered with.") -/obj/item/stock_parts/network_lock/attack_self(var/mob/user) +/obj/item/stock_parts/network_receiver/network_lock/attackby(obj/item/used_item, mob/user) + . = ..() + if(istype(used_item, /obj/item/card/id)) + if(check_access(used_item)) + playsound(src, 'sound/machines/ping.ogg', 20, 0) + else + playsound(src, 'sound/machines/buzz-two.ogg', 20, 0) + +/obj/item/stock_parts/network_receiver/network_lock/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(istype(target, /obj/item/stock_parts/network_receiver/network_lock)) + var/obj/item/stock_parts/network_receiver/network_lock/other_lock = target + if(length(other_lock.groups)) // Prevent mistakingly copying from a blank lock instead of vice versa. + groups = other_lock.groups.Copy() + playsound(src, 'sound/machines/ping.ogg', 20, 0) + to_chat(user, SPAN_NOTICE("\The [src] pings as it successfully copies its access requirements from the other network lock.")) + + +/obj/item/stock_parts/network_receiver/network_lock/attack_self(var/mob/user) ui_interact(user) -/obj/item/stock_parts/network_lock/ui_data(mob/user, ui_key) +/obj/item/stock_parts/network_receiver/network_lock/ui_data(mob/user, ui_key) var/list/data[0] . = data @@ -74,23 +100,56 @@ data["error"] = error data += D.ui_data(user, ui_key) - var/datum/computer_network/network = D.get_network() + var/datum/computer_network/network = D.get_network(NET_FEATURE_ACCESS) if(!network) data["connected"] = FALSE return data["connected"] = TRUE data["default_state"] = auto_deny_all - var/list/grants = list() if(!network.access_controller) return - for(var/datum/computer_file/data/grant_record/GR in network.access_controller.get_all_grants()) - grants.Add(list(list( - "grant_name" = GR.stored_data, - "assigned" = (GR.stored_data in grants) - ))) - data["grants"] = grants - -/obj/item/stock_parts/network_lock/OnTopic(mob/user, href_list, datum/topic_state/state) + + data["patterns"] = list() + var/pattern_index = 0 + for(var/list/pattern in groups) + pattern_index++ + data["patterns"].Add(list(list( + "index" = "[pattern_index]", + "groups" = english_list(pattern, "No groups assigned!", and_text = " or ") + ))) + + var/list/group_dictionary = network.access_controller.get_group_dict() + var/list/parent_groups_data + var/list/child_groups_data + + var/list/pattern = LAZYACCESS(groups, selected_pattern) + + if(pattern) + if(selected_parent_group) + if(!(selected_parent_group in group_dictionary)) + selected_parent_group = null + else + var/list/child_groups = group_dictionary[selected_parent_group] + if(child_groups) + child_groups_data = list() + for(var/child_group in child_groups) + child_groups_data.Add(list(list( + "child_group" = child_group, + "assigned" = (LAZYISIN(pattern, child_group)) + ))) + if(!selected_parent_group) // Check again in case we ended up with a non-existent selected parent group instead of breaking the UI. + parent_groups_data = list() + for(var/parent_group in group_dictionary) + parent_groups_data.Add(list(list( + "parent_group" = parent_group, + "assigned" = (LAZYISIN(pattern, parent_group)) + ))) + data["parent_groups"] = parent_groups_data + data["child_groups"] = child_groups_data + data["selected_parent_group"] = selected_parent_group + data["selected_pattern"] = "[selected_pattern]" + +/obj/item/stock_parts/network_receiver/network_lock/OnTopic(mob/user, href_list, datum/topic_state/state) . = ..() if(.) return @@ -115,32 +174,80 @@ auto_deny_all = TRUE return TOPIC_REFRESH - if(href_list["remove_grant"]) - grants -= href_list["remove_grant"] + if(href_list["add_pattern"]) + if(length(groups) >= MAX_PATTERNS) + to_chat(user, SPAN_WARNING("You cannot add more than [MAX_PATTERNS] patterns to \the [src]!")) + return TOPIC_HANDLED + LAZYADD(groups, list(list())) + return TOPIC_REFRESH + + if(href_list["remove_pattern"]) + var/pattern_index = text2num(href_list["remove_pattern"]) + LAZYREMOVE(groups, list(LAZYACCESS(groups, pattern_index))) // We have to encapsulate the pattern in another list to actually delete it. + if(selected_pattern == pattern_index) + selected_pattern = null + else if(selected_pattern > pattern_index) + selected_pattern-- + return TOPIC_REFRESH + + if(href_list["select_pattern"]) + var/pattern_index = text2num(href_list["select_pattern"]) + if(pattern_index > LAZYLEN(groups)) + return TOPIC_HANDLED + selected_pattern = pattern_index + return TOPIC_REFRESH + + if(href_list["select_parent_group"]) + selected_parent_group = href_list["select_parent_group"] + return TOPIC_REFRESH + + if(href_list["info"]) + switch(href_list["info"]) + if("pattern") + to_chat(user, SPAN_NOTICE("In order to access the device, users must be a member of at least one group in each access pattern.")) + if("parent_groups") + to_chat(user, SPAN_NOTICE("Assigning a parent group to an access pattern will permit any member of its child groups access to the pattern.")) + + var/list/pattern_list = LAZYACCESS(groups, selected_pattern) + if(!pattern_list) + return TOPIC_REFRESH + + if(href_list["assign_group"]) + pattern_list |= href_list["assign_group"] return TOPIC_REFRESH - if(href_list["assign_grant"]) - grants |= href_list["assign_grant"] + if(href_list["remove_group"]) + pattern_list -= href_list["remove_group"] return TOPIC_REFRESH -/obj/item/stock_parts/network_lock/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) +/obj/item/stock_parts/network_receiver/network_lock/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) var/data = ui_data(user) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "network_lock.tmpl", capitalize(name), 380, 500) + ui = new(user, src, ui_key, "network_lock.tmpl", capitalize(name), 500, 500) ui.set_initial_data(data) ui.open() - ui.set_auto_update(1) -/obj/item/stock_parts/network_lock/CouldUseTopic(var/mob/user) +/obj/item/stock_parts/network_receiver/network_lock/CouldUseTopic(var/mob/user) ..() if(LAZYLEN(interact_sounds) && CanPhysicallyInteract(user)) playsound(src, pick(interact_sounds), interact_sound_volume) -/obj/item/stock_parts/network_lock/CanUseTopic() +/obj/item/stock_parts/network_receiver/network_lock/CanUseTopic() return STATUS_INTERACTIVE -/obj/item/stock_parts/network_lock/buildable +/obj/item/stock_parts/network_receiver/network_lock/buildable part_flags = PART_FLAG_HAND_REMOVE material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +// Prevent tampering with machinery you don't have access to. +/obj/machinery/cannot_transition_to(state_path, mob/user) + var/decl/machine_construction/state = GET_DECL(state_path) + if(state && !state.locked && construct_state && construct_state.locked) + for(var/obj/item/stock_parts/network_receiver/network_lock/lock in get_all_components_of_type(/obj/item/stock_parts/network_receiver/network_lock)) + if(!lock.check_access(user)) + return SPAN_WARNING("\The [lock] flashes red! You lack the access to unlock this.") + return ..() + +#undef MAX_PATTERNS \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/network_receiver.dm b/code/game/machinery/_machines_base/stock_parts/network_receiver.dm new file mode 100644 index 000000000000..b240744fa3d7 --- /dev/null +++ b/code/game/machinery/_machines_base/stock_parts/network_receiver.dm @@ -0,0 +1,31 @@ +// A receiver that allows for non-network machines to have public vars and methods interacted with by networks + +/obj/item/stock_parts/network_receiver + name = "network receiver" + desc = "A network receiver designed for use with machinery otherwise disconnected from a network." + icon_state = "net_lock" + part_flags = PART_FLAG_QDEL + var/initial_network_id // The address to the network + var/initial_network_key // network KEY + +/obj/item/stock_parts/network_receiver/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) + +/obj/item/stock_parts/network_receiver/Initialize(ml, material_key) + . = ..() + set_extension(src, /datum/extension/network_device/stock_part, initial_network_id, initial_network_key) + +/obj/item/stock_parts/network_receiver/on_install(obj/machinery/machine) + . = ..() + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + D.reload_commands() + +/obj/item/stock_parts/network_receiver/attack_self(mob/user) + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + D.ui_interact(user) + +/obj/item/stock_parts/network_receiver/buildable + part_flags = PART_FLAG_HAND_REMOVE + material = /decl/material/solid/metal/steel \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/power/battery.dm b/code/game/machinery/_machines_base/stock_parts/power/battery.dm index 44af6b077045..ecb17db640aa 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/battery.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/battery.dm @@ -11,7 +11,7 @@ var/seek_alternatives = 5 // How many ticks we wait before seeking other power sources, if we can provide the machine with power. Set to 0 to never do this. /obj/item/stock_parts/power/battery/Destroy() - qdel(cell) + QDEL_NULL(cell) . = ..() /obj/item/stock_parts/power/battery/on_install(var/obj/machinery/machine) @@ -27,34 +27,35 @@ remove_cell() ..() -/obj/item/stock_parts/power/battery/take_damage(amount, damtype) +/obj/item/stock_parts/power/battery/check_health(lastdamage, lastdamtype, lastdamflags, consumed) + if(can_take_damage() && lastdamage > 0) + switch(lastdamtype) + if(ELECTROCUTE) + if(prob(50) && cell && (get_percent_health() < 50)) + cell.emp_act(3) + if(BRUTE) + if(prob(20) && cell && (get_percent_health() < 50)) + cell.explosion_act(3) . = ..() - switch(damtype) - if(ELECTROCUTE) - if(prob(50) && cell && health < initial(health)/2) - cell.emp_act(3) - if(BRUTE) - if(prob(20) && cell && health < initial(health)/2) - cell.explosion_act(3) // None of these helpers actually change the cell's loc. They only manage internal references and state. /obj/item/stock_parts/power/battery/proc/add_cell(var/obj/machinery/machine, var/obj/item/cell/new_cell) if(cell) return cell = new_cell - GLOB.destroyed_event.register(cell, src, .proc/remove_cell) + events_repository.register(/decl/observ/destroyed, cell, src, PROC_REF(remove_cell)) if(!machine) machine = loc if(istype(machine)) machine.power_change() machine.queue_icon_update() - set_status(machine, PART_STAT_CONNECTED) + set_component_status(machine, PART_STAT_CONNECTED) update_icon() return cell /obj/item/stock_parts/power/battery/proc/remove_cell() if(cell) - GLOB.destroyed_event.unregister(cell, src) + events_repository.unregister(/decl/observ/destroyed, cell, src) . = cell cell = null var/obj/machinery/machine = loc @@ -111,7 +112,7 @@ /obj/item/stock_parts/power/battery/can_provide_power(var/obj/machinery/machine) if(is_functional() && cell && cell.check_charge(CELLRATE * machine.get_power_usage())) machine.update_power_channel(LOCAL) - set_status(machine, PART_STAT_ACTIVE) + set_component_status(machine, PART_STAT_ACTIVE) return TRUE return FALSE @@ -135,35 +136,35 @@ /obj/item/stock_parts/power/battery/on_refresh(var/obj/machinery/machine) if(machine && !cell) var/obj/item/stock_parts/building_material/mat = machine.get_component_of_type(/obj/item/stock_parts/building_material) - var/obj/item/cell/cell = mat && mat.remove_material(/obj/item/cell, 1) + var/obj/item/cell/cell = mat && mat.remove_material(/obj/item/cell, 1, src) if(cell) add_cell(machine, cell) - cell.forceMove(src) charge_rate = initial(charge_rate) charge_rate *= 1 + 0.5 * machine.total_component_rating_of_type(/obj/item/stock_parts/capacitor) /obj/item/stock_parts/power/battery/on_update_icon() + . = ..() icon_state = "battery[!!cell]" // Cell interaction -/obj/item/stock_parts/power/battery/attackby(obj/item/I, mob/user) +/obj/item/stock_parts/power/battery/attackby(obj/item/used_item, mob/user) var/obj/machinery/machine = loc // Interactions with/without machine - if(istype(I, /obj/item/cell)) + if(istype(used_item, /obj/item/cell)) if(cell) to_chat(user, "There is a power cell already installed.") return TRUE if(istype(machine) && (machine.stat & MAINT)) to_chat(user, "There is no connector for your power cell.") return TRUE - if(I.w_class != ITEM_SIZE_NORMAL) - to_chat(user, "\The [I] is too [I.w_class < ITEM_SIZE_NORMAL? "small" : "large"] to fit here.") + if(used_item.w_class != ITEM_SIZE_NORMAL) + to_chat(user, "\The [used_item] is too [used_item.w_class < ITEM_SIZE_NORMAL? "small" : "large"] to fit here.") return TRUE - if(!user.unEquip(I, src)) - return - add_cell(machine, I) + if(!user.try_unequip(used_item, src)) + return TRUE + add_cell(machine, used_item) user.visible_message(\ SPAN_WARNING("\The [user] has inserted the power cell to \the [src]!"),\ SPAN_NOTICE("You insert the power cell.")) @@ -172,6 +173,7 @@ // Interactions without machine if(!istype(machine)) return ..() + return FALSE /obj/item/stock_parts/power/battery/attack_self(mob/user) if(cell) @@ -181,7 +183,7 @@ return ..() /obj/item/stock_parts/power/battery/attack_hand(mob/user) - if(cell && istype(loc, /obj/machinery)) + if(cell && istype(loc, /obj/machinery) && user.check_dexterity(DEXTERITY_HOLD_ITEM)) user.put_in_hands(cell) extract_cell(user) return TRUE @@ -190,7 +192,11 @@ /obj/item/stock_parts/power/battery/get_cell() return cell +/obj/item/stock_parts/power/battery/get_source_info() + return "The machine can receive power from an installed power cell." + /obj/item/stock_parts/power/battery/buildable + max_health = null //Buildable variant may take damage part_flags = PART_FLAG_HAND_REMOVE material = /decl/material/solid/metal/steel @@ -220,7 +226,7 @@ material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) /obj/item/stock_parts/power/battery/buildable/turbo/get_lore_info() @@ -235,7 +241,7 @@ material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) /obj/item/stock_parts/power/battery/buildable/responsive/get_lore_info() diff --git a/code/game/machinery/_machines_base/stock_parts/power/power.dm b/code/game/machinery/_machines_base/stock_parts/power/power.dm index 91a5f8d0e3f7..33082d485f73 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/power.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/power.dm @@ -4,9 +4,10 @@ var/list/power_components = list() // this is an optimization, as power code is expensive. /obj/item/stock_parts/power - part_flags = PART_FLAG_QDEL | PART_FLAG_NODAMAGE // For integrated components, which are built from uncreated_component_parts. Use subtypes with this off for buildable ones. + part_flags = PART_FLAG_QDEL // For integrated components, which are built from uncreated_component_parts. Use subtypes with this off for buildable ones. icon = 'icons/obj/items/stock_parts/stock_parts.dmi' icon_state = "teslalink" + max_health = ITEM_HEALTH_NO_DAMAGE var/priority = 0 // Higher priority is used first var/cached_channel @@ -27,11 +28,14 @@ // Doesn't actually do it. /obj/item/stock_parts/power/proc/can_use_power_oneoff(var/obj/machinery/machine, var/amount, var/channel) - return 0 + return FALSE // A request for the amount of power on the given channel. Returns the amount of power which could be provided. /obj/item/stock_parts/power/proc/use_power_oneoff(var/obj/machinery/machine, var/amount, var/channel) return 0 // This alerts the part that it does not need to provide power anymore. -/obj/item/stock_parts/power/proc/not_needed(var/obj/machinery/machine) \ No newline at end of file +/obj/item/stock_parts/power/proc/not_needed(var/obj/machinery/machine) + +// Returns OOC information about how to use this power source on examine, if the machine is not receiving power. +/obj/item/stock_parts/power/proc/get_source_info() \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/power/terminal.dm b/code/game/machinery/_machines_base/stock_parts/power/terminal.dm index b3ae1fcf82c3..2d0347720f4a 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/terminal.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/terminal.dm @@ -12,7 +12,7 @@ if(status & PART_STAT_ACTIVE) machine.update_power_channel(cached_channel) unset_status(machine, PART_STAT_ACTIVE) - unset_terminal(loc, terminal) + qdel(terminal) // Will call unset_terminal(). ..() /obj/item/stock_parts/power/terminal/Destroy() @@ -26,8 +26,6 @@ machine.update_power_channel(cached_channel) machine.power_change() return - - var/surplus = terminal.surplus() var/usage = machine.get_power_usage() @@ -40,7 +38,7 @@ terminal.draw_power(usage) if(surplus >= usage) return // had enough power and good to go. - else + else // Try and use other (local) sources of power to make up for the deficit. var/deficit = machine.use_power_oneoff(usage - surplus) if(deficit > 0) @@ -50,7 +48,7 @@ //Is willing to provide power if the wired contribution is nonnegligible and there is enough total local power to run the machine. /obj/item/stock_parts/power/terminal/can_provide_power(var/obj/machinery/machine) if(is_functional() && terminal && terminal.surplus() && machine.can_use_power_oneoff(machine.get_power_usage(), LOCAL) <= 0) - set_status(machine, PART_STAT_ACTIVE) + set_component_status(machine, PART_STAT_ACTIVE) machine.update_power_channel(LOCAL) return TRUE return FALSE @@ -73,18 +71,21 @@ unset_terminal(machine, terminal) terminal = new_terminal terminal.master = src - GLOB.destroyed_event.register(terminal, src, .proc/unset_terminal) - set_extension(src, /datum/extension/event_registration/shuttle_stationary, GLOB.moved_event, machine, .proc/machine_moved, get_area(src)) - set_status(machine, PART_STAT_CONNECTED) + events_repository.register(/decl/observ/destroyed, terminal, src, PROC_REF(unset_terminal)) + terminal.queue_icon_update() + + set_extension(src, /datum/extension/event_registration/shuttle_stationary, GET_DECL(/decl/observ/moved), machine, PROC_REF(machine_moved), get_area(src)) + set_component_status(machine, PART_STAT_CONNECTED) start_processing(machine) /obj/item/stock_parts/power/terminal/proc/machine_moved(var/obj/machinery/machine, var/turf/old_loc, var/turf/new_loc) if(!terminal) - GLOB.moved_event.unregister(machine, src, .proc/machine_moved) + events_repository.unregister(/decl/observ/moved, machine, src, PROC_REF(machine_moved)) return if(istype(new_loc) && (terminal.loc == get_step(new_loc, terminal_dir))) return // This location is fine + // TODO: disconnect and drop the terminal as an item instead of deleting it. machine.visible_message(SPAN_WARNING("The terminal is ripped out of \the [machine]!")) qdel(terminal) // will handle everything via the destroyed event @@ -92,13 +93,13 @@ if(!machine) return var/obj/machinery/power/terminal/new_terminal = new (get_step(machine, terminal_dir)) - new_terminal.set_dir(terminal_dir ? GLOB.reverse_dir[terminal_dir] : machine.dir) + new_terminal.set_dir(terminal_dir ? global.reverse_dir[terminal_dir] : machine.dir) new_terminal.connect_to_network() set_terminal(machine, new_terminal) /obj/item/stock_parts/power/terminal/proc/unset_terminal(var/obj/machinery/power/old_terminal, var/obj/machinery/machine) remove_extension(src, /datum/extension/event_registration/shuttle_stationary) - GLOB.destroyed_event.unregister(old_terminal, src) + events_repository.unregister(/decl/observ/destroyed, old_terminal, src) if(!machine && istype(loc, /obj/machinery)) machine = loc if(machine) @@ -108,19 +109,19 @@ /obj/item/stock_parts/power/terminal/proc/blocking_terminal_at_loc(var/obj/machinery/machine, var/turf/T, var/mob/user) . = FALSE - var/check_dir = terminal_dir ? GLOB.reverse_dir[terminal_dir] : machine.dir + var/check_dir = terminal_dir ? global.reverse_dir[terminal_dir] : machine.dir for(var/obj/machinery/power/terminal/term in T) if(T.dir == check_dir) to_chat(user, "There is already a terminal here.") return TRUE -/obj/item/stock_parts/power/terminal/attackby(obj/item/I, mob/user) +/obj/item/stock_parts/power/terminal/attackby(obj/item/used_item, mob/user) var/obj/machinery/machine = loc if(!istype(machine)) return ..() // Interactions inside machine only - if (istype(I, /obj/item/stack/cable_coil) && !terminal) + if (istype(used_item, /obj/item/stack/cable_coil) && !terminal) var/turf/T = get_step(machine, terminal_dir) if(terminal_dir && user.loc != T) return FALSE // Wrong terminal handler. @@ -130,60 +131,63 @@ if(istype(T) && !T.is_plating()) to_chat(user, "You must remove the floor plating in front of \the [machine] first.") return TRUE - var/obj/item/stack/cable_coil/C = I + var/obj/item/stack/cable_coil/C = used_item if(!C.can_use(10)) to_chat(user, "You need ten lengths of cable for \the [machine].") return TRUE - user.visible_message("\The [user] adds cables to the \the [machine].", \ + user.visible_message("\The [user] adds cables to \the [machine].", \ "You start adding cables to \the [machine] frame...") playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) if(do_after(user, 20, machine)) if(C.can_use(10) && !terminal && (machine == loc) && machine.components_are_accessible(type) && !blocking_terminal_at_loc(machine, T, user)) var/obj/structure/cable/N = T.get_cable_node() if (prob(50) && electrocute_mob(user, N, N)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, machine) - s.start() - if(user.stunned) + spark_at(machine, amount=5, cardinal_only = TRUE) + if(HAS_STATUS(user, STAT_STUN)) return TRUE C.use(10) user.visible_message(\ - "\The [user] has added cables to the \the [machine]!",\ - "You add cables to the \the [machine].") + "\The [user] has added cables to \the [machine]!",\ + "You add cables to \the [machine].") make_terminal(machine) return TRUE + return FALSE - if(isWirecutter(I) && terminal) - var/turf/T = get_step(machine, terminal_dir) - if(terminal_dir && user.loc != T) - return FALSE // Wrong terminal handler. - if(istype(T) && !T.is_plating()) - to_chat(user, "You must remove the floor plating in front of \the [machine] first.") - return TRUE - user.visible_message("\The [user] dismantles the power terminal from \the [machine].", \ - "You begin to cut the cables...") - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - if(do_after(user, 50, machine)) - if(terminal && (machine == loc) && machine.components_are_accessible(type)) - if (prob(50) && electrocute_mob(user, terminal.powernet, terminal)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, machine) - s.start() - if(user.stunned) - return TRUE - new /obj/item/stack/cable_coil(T, 10) - to_chat(user, "You cut the cables and dismantle the power terminal.") - qdel(terminal) - return TRUE +/obj/item/stock_parts/power/terminal/get_source_info() + . = list("The machine can receive power by direct connection to the powernet.") + if(terminal) + if(!terminal.get_powernet()) + . += "The power terminal must be connected to the powernet using additional cables." + else + . += "The connected powernet must be powered." + else + . += "Add cables to the machine to construct a power terminal." /obj/item/stock_parts/power/terminal/buildable part_flags = PART_FLAG_HAND_REMOVE + max_health = null //Buildable variant may take damage material = /decl/material/solid/metal/steel +/decl/stock_part_preset/terminal_connect + expected_part_type = /obj/item/stock_parts/power/terminal + +/decl/stock_part_preset/terminal_connect/apply(obj/machinery/machine, var/obj/item/stock_parts/power/terminal/part, var/turf/picked_turf) + if(!picked_turf) + picked_turf = machine.loc + var/obj/machinery/power/terminal/term = locate() in picked_turf + if(istype(term) && !term.master) + part.set_terminal(machine, term) + /decl/stock_part_preset/terminal_setup expected_part_type = /obj/item/stock_parts/power/terminal /decl/stock_part_preset/terminal_setup/apply(obj/machinery/machine, var/obj/item/stock_parts/power/terminal/part) - var/obj/machinery/power/terminal/term = locate() in machine.loc - if(istype(term) && !term.master) - part.set_terminal(machine, term) \ No newline at end of file + if(isturf(machine.loc) && machine.anchored) + part.make_terminal(machine) + +//Offset terminals towards the owner's facing direction +/decl/stock_part_preset/terminal_connect/offset_dir/apply(obj/machinery/machine, obj/item/stock_parts/power/terminal/part, turf/picked_turf) + . = ..(machine, part, get_step(machine.loc, machine.dir)) + +/decl/stock_part_preset/terminal_setup/offset_dir/apply(obj/machinery/machine, obj/item/stock_parts/power/terminal/part) + . = ..(machine, part) \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/power/tesla.dm b/code/game/machinery/_machines_base/stock_parts/power/tesla.dm index a84044af5061..4b7a5ecdab81 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/tesla.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/tesla.dm @@ -26,6 +26,10 @@ A.use_power_oneoff(amount, channel) return amount +/obj/item/stock_parts/power/apc/get_source_info() + return "The machine can receive power wirelessly from a nearby area power controller." + /obj/item/stock_parts/power/apc/buildable + max_health = null //Buildable variant may take damage part_flags = PART_FLAG_HAND_REMOVE material = /decl/material/solid/metal/steel \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/radio/radio_presets.dm b/code/game/machinery/_machines_base/stock_parts/radio/radio_presets.dm index 91caafd6d932..d5770fdb11d4 100644 --- a/code/game/machinery/_machines_base/stock_parts/radio/radio_presets.dm +++ b/code/game/machinery/_machines_base/stock_parts/radio/radio_presets.dm @@ -25,12 +25,12 @@ if(transmit_on_change) part.transmit_on_change = list() for(var/key in transmit_on_change) - part.transmit_on_change[key] = decls_repository.get_decl(transmit_on_change[key]) + part.transmit_on_change[key] = GET_DECL(transmit_on_change[key]) if(transmit_on_tick) part.transmit_on_tick = list() for(var/key in transmit_on_tick) - part.transmit_on_tick[key] = decls_repository.get_decl(transmit_on_tick[key]) + part.transmit_on_tick[key] = GET_DECL(transmit_on_tick[key]) /decl/stock_part_preset/radio/event_transmitter expected_part_type = /obj/item/stock_parts/radio/transmitter/on_event @@ -41,12 +41,12 @@ ..() if(event) - part.event = decls_repository.get_decl(event) + part.event = GET_DECL(event) if(transmit_on_event) part.transmit_on_event = list() for(var/key in transmit_on_event) - part.transmit_on_event[key] = decls_repository.get_decl(transmit_on_event[key]) + part.transmit_on_event[key] = GET_DECL(transmit_on_event[key]) /decl/stock_part_preset/radio/receiver expected_part_type = /obj/item/stock_parts/radio/receiver @@ -59,9 +59,9 @@ if(receive_and_write) part.receive_and_write = list() for(var/key in receive_and_write) - part.receive_and_write[key] = decls_repository.get_decl(receive_and_write[key]) + part.receive_and_write[key] = GET_DECL(receive_and_write[key]) if(receive_and_call) part.receive_and_call = list() for(var/key in receive_and_call) - part.receive_and_call[key] = decls_repository.get_decl(receive_and_call[key]) \ No newline at end of file + part.receive_and_call[key] = GET_DECL(receive_and_call[key]) \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/radio/receiver.dm b/code/game/machinery/_machines_base/stock_parts/radio/receiver.dm index 81f40afa55fc..b35afa55d73b 100644 --- a/code/game/machinery/_machines_base/stock_parts/radio/receiver.dm +++ b/code/game/machinery/_machines_base/stock_parts/radio/receiver.dm @@ -3,7 +3,7 @@ /obj/item/stock_parts/radio/receiver name = "radio receiver" desc = "A radio receiver designed for use with machines." - icon_state = "subspace_amplifier" + icon_state = "receiver" multitool_extension = /datum/extension/interactive/multitool/radio/receiver var/list/receive_and_write var/list/receive_and_call @@ -46,5 +46,6 @@ method.perform(machine, signal.data[thing]) /obj/item/stock_parts/radio/receiver/buildable + max_health = null //Buildable variant may take damage part_flags = PART_FLAG_HAND_REMOVE material = /decl/material/solid/metal/steel \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/radio/stock_parts_radio.dm b/code/game/machinery/_machines_base/stock_parts/radio/stock_parts_radio.dm index 22b2de40acac..9cca4b1b98a1 100644 --- a/code/game/machinery/_machines_base/stock_parts/radio/stock_parts_radio.dm +++ b/code/game/machinery/_machines_base/stock_parts/radio/stock_parts_radio.dm @@ -1,5 +1,6 @@ /obj/item/stock_parts/radio - part_flags = PART_FLAG_QDEL | PART_FLAG_NODAMAGE + part_flags = PART_FLAG_QDEL + max_health = ITEM_HEALTH_NO_DAMAGE var/datum/radio_frequency/radio var/frequency var/id_tag @@ -23,7 +24,7 @@ id_tag = new_tag set_frequency(frequency, filter) -/obj/item/stock_parts/radio/proc/get_receive_filter() // what filter should we register with to recieve updates on? +/obj/item/stock_parts/radio/proc/get_receive_filter() // what filter should we register with to receive updates on? return RADIO_NULL /obj/item/stock_parts/radio/proc/set_frequency(new_frequency, new_filter) diff --git a/code/game/machinery/_machines_base/stock_parts/radio/transmitter.dm b/code/game/machinery/_machines_base/stock_parts/radio/transmitter.dm index f8e05ec93753..e4e547aa54ae 100644 --- a/code/game/machinery/_machines_base/stock_parts/radio/transmitter.dm +++ b/code/game/machinery/_machines_base/stock_parts/radio/transmitter.dm @@ -1,9 +1,12 @@ /obj/item/stock_parts/radio/transmitter name = "radio transmitter" desc = "A radio transmitter designed for use with machines." - icon_state = "subspace_transmitter" + icon_state = "transmitter" var/range = 60 // Limits transmit range var/latency = 2 // Delay between event and transmission; doesn't apply to transmit on tick + #ifdef UNIT_TEST + latency = 0 // this can slow down testing and cause random inconsistent failures + #endif var/buffer /obj/item/stock_parts/radio/transmitter/proc/queue_transmit(list/data) @@ -11,16 +14,15 @@ return if(!buffer) buffer = data - addtimer(CALLBACK(src, .proc/transmit), latency) + addtimer(CALLBACK(src, PROC_REF(transmit)), latency, TIMER_UNIQUE) else - buffer |= data + buffer = (data |= buffer) // this avoids list copies. basically, give entries already in data priority and add buffered data after /obj/item/stock_parts/radio/transmitter/proc/transmit() if(!LAZYLEN(buffer)) return var/datum/signal/signal = new() signal.source = src - signal.transmission_method = TRANSMISSION_RADIO signal.encryption = encryption signal.data = buffer signal.data["tag"] = id_tag @@ -48,7 +50,7 @@ start_processing(machine) for(var/thing in transmit_on_change) var/decl/public_access/public_variable/variable = transmit_on_change[thing] - variable.register_listener(src, machine, .proc/var_changed) + variable.register_listener(src, machine, PROC_REF(var_changed)) /obj/item/stock_parts/radio/transmitter/basic/on_uninstall(obj/machinery/machine) for(var/thing in transmit_on_change) @@ -88,7 +90,7 @@ if(!is_valid_event(machine, event)) event = null if(event) - event.register_listener(src, machine, .proc/trigger_event) + event.register_listener(src, machine, PROC_REF(trigger_event)) /obj/item/stock_parts/radio/transmitter/on_event/on_uninstall(obj/machinery/machine) if(event) @@ -108,15 +110,16 @@ queue_transmit(dat) /obj/item/stock_parts/radio/transmitter/basic/buildable + max_health = null //Buildable variant may take damage part_flags = PART_FLAG_HAND_REMOVE name = "basic radio transmitter" desc = "A stock radio transmitter machine component. Can transmit updates regularly or on change." - color = COLOR_RED material = /decl/material/solid/metal/steel /obj/item/stock_parts/radio/transmitter/on_event/buildable + max_health = null //Buildable variant may take damage part_flags = PART_FLAG_HAND_REMOVE name = "event radio transmitter" desc = "A radio transmitter machine component which transmits when activated by an event." - color = COLOR_ORANGE + icon_state = "transmitter_event" material = /decl/material/solid/metal/steel \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/shielding.dm b/code/game/machinery/_machines_base/stock_parts/shielding.dm index 67dbb27777f3..c68db432b11d 100644 --- a/code/game/machinery/_machines_base/stock_parts/shielding.dm +++ b/code/game/machinery/_machines_base/stock_parts/shielding.dm @@ -8,22 +8,22 @@ /obj/item/stock_parts/shielding/electric name = "fuse box" icon_state = "fusebox" - desc = "A bloc of multi-use fuses, protecting the machine against the electrical current spikes." + desc = "A bloc of multi-use fuses, used to protect components against electrical current spikes." protection_types = list(ELECTROCUTE) material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/shielding/kinetic name = "internal armor" icon_state = "armor" - desc = "Kinetic resistant armor plates to line the machine with." + desc = "An impact-resistant armor plate used to shield delicate machine components." protection_types = list(BRUTE) material = /decl/material/solid/metal/steel /obj/item/stock_parts/shielding/heat name = "heatsink" icon_state = "heatsink" - desc = "Active cooling system protecting machinery against the high temperatures." + desc = "An active cooling system used to safeguard machinery against high temperatures." protection_types = list(BURN) material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file diff --git a/code/game/machinery/_machines_base/stock_parts/stock_parts_interface.dm b/code/game/machinery/_machines_base/stock_parts/stock_parts_interface.dm index 337b71b53514..bd43db38d6c3 100644 --- a/code/game/machinery/_machines_base/stock_parts/stock_parts_interface.dm +++ b/code/game/machinery/_machines_base/stock_parts/stock_parts_interface.dm @@ -2,11 +2,12 @@ name = "console screen" desc = "Used in the construction of computers and other devices with an interactive screen." icon_state = "output" - origin_tech = "{'materials':1}" - material = /decl/material/solid/glass + origin_tech = @'{"materials":1}' + material = /decl/material/solid/fiberglass base_type = /obj/item/stock_parts/console_screen part_flags = PART_FLAG_HAND_REMOVE - health = 20 + max_health = 20 + ignore_damage_types = list(ELECTROCUTE) // emp damage is annoying enough without destroying purely physical or mechanical components /obj/item/stock_parts/console_screen/on_refresh(obj/machinery/machine) ..() @@ -19,15 +20,16 @@ /obj/item/stock_parts/keyboard name = "input controller" - desc = "A standard part required by many machines to recieve user input." + desc = "A standard part required by many machines to receive user input." icon_state = "input" - origin_tech = "{'materials':1}" - material = /decl/material/solid/plastic + origin_tech = @'{"materials":1}' + material = /decl/material/solid/organic/plastic base_type = /obj/item/stock_parts/keyboard part_flags = PART_FLAG_HAND_REMOVE + w_class = ITEM_SIZE_SMALL + ignore_damage_types = list(ELECTROCUTE) // emp damage is annoying enough without destroying purely physical or mechanical components /obj/item/stock_parts/keyboard/on_refresh(obj/machinery/machine) ..() if(is_functional()) machine.set_noinput(FALSE) - \ No newline at end of file diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index 83032f989442..e8aab501f355 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -2,15 +2,14 @@ name = "\improper AI Liquid Dispenser" icon = 'icons/obj/items/device/motion_detector.dmi' icon_state = "motion0" - anchored = 1.0 + anchored = TRUE idle_power_usage = 10 var/uses = 20 var/disabled = 1 - var/lethal = 0 var/locked = 1 - var/cooldown_time = 0 - var/cooldown_timeleft = 0 - var/cooldown_on = 0 + var/slip_cooldown_time = 0 + var/slip_cooldown_timeleft = 0 + var/slip_cooldown_on = 0 initial_access = list(access_ai_upload) /obj/machinery/ai_slipper/on_update_icon() @@ -24,10 +23,10 @@ src.uses = uses src.power_change() -/obj/machinery/ai_slipper/attackby(obj/item/W, mob/user) +/obj/machinery/ai_slipper/attackby(obj/item/used_item, mob/user) if(stat & (NOPOWER|BROKEN)) - return - if (istype(user, /mob/living/silicon)) + return FALSE + if (issilicon(user)) return attack_ai(user) else // trying to unlock the interface if(allowed(user)) @@ -42,6 +41,7 @@ interact(user) else to_chat(user, "Access denied.") + return TRUE /obj/machinery/ai_slipper/interface_interact(mob/user) interact(user) @@ -51,14 +51,12 @@ var/area/area = get_area(src) if(!area || !isturf(loc)) return - var/t = "AI Liquid Dispenser ([area.name])
    " - - if(src.locked && (!istype(user, /mob/living/silicon))) + var/t = "AI Liquid Dispenser ([area.proper_name])
    " + if(src.locked && (!issilicon(user))) t += "(Swipe ID card to unlock control panel.)
    " else - t += text("Dispenser [] - []?
    \n", src.disabled?"deactivated":"activated", src, src.disabled?"Enable":"Disable") - t += text("Uses Left: [uses]. Activate the dispenser?
    \n") - + t += text("Dispenser [] - []?
    \n", src.disabled?"deactivated":"activated", src, src.disabled?"Enable":"Disable") + t += text("Uses Left: [uses]. Activate the dispenser?
    \n") show_browser(user, t, "window=computer;size=575x450") onclose(user, "computer") @@ -74,30 +72,26 @@ update_icon() . = TOPIC_REFRESH if (href_list["toggleUse"]) - if(!(cooldown_on || disabled)) + if(!(slip_cooldown_on || disabled)) new /obj/effect/effect/foam(src.loc) src.uses-- - cooldown_on = 1 - cooldown_time = world.timeofday + 100 + slip_cooldown_on = 1 + slip_cooldown_time = world.timeofday + 100 slip_process() . = TOPIC_REFRESH - if(. == TOPIC_REFRESH) - attack_hand(user) + ui_interact(user) /obj/machinery/ai_slipper/proc/slip_process() - while(cooldown_time - world.timeofday > 0) - var/ticksleft = cooldown_time - world.timeofday - + while(slip_cooldown_time - world.timeofday > 0) + var/ticksleft = slip_cooldown_time - world.timeofday if(ticksleft > 1e5) - cooldown_time = world.timeofday + 10 // midnight rollover - - - cooldown_timeleft = (ticksleft / 10) + slip_cooldown_time = world.timeofday + 10 // midnight rollover + slip_cooldown_timeleft = (ticksleft / 10) sleep(5) if (uses <= 0) return if (uses >= 0) - cooldown_on = 0 + slip_cooldown_on = 0 src.power_change() return diff --git a/code/game/machinery/air_sensor.dm b/code/game/machinery/air_sensor.dm index 19832cd74883..bfbb9236ed3e 100644 --- a/code/game/machinery/air_sensor.dm +++ b/code/game/machinery/air_sensor.dm @@ -11,7 +11,7 @@ public_variables = list( /decl/public_access/public_variable/gas, /decl/public_access/public_variable/pressure, - /decl/public_access/public_variable/temperature + /decl/public_access/public_variable/temperature ) stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/air_sensor = 1) use_power = POWER_USE_IDLE @@ -25,7 +25,7 @@ uncreated_component_parts = null /obj/machinery/air_sensor/on_update_icon() - if(!powered()) + if(stat & NOPOWER) icon_state = "gsensor0" else icon_state = "gsensor[use_power]" @@ -36,7 +36,7 @@ desc = "A list of gas data from the sensor location; the list entries are two-entry lists with \"symbol\" and \"percent\" fields." can_write = FALSE has_updates = FALSE - var_type = IC_FORMAT_LIST + var_type = VAR_FORMAT_LIST /decl/public_access/public_variable/gas/access_var(obj/machinery/sensor) var/datum/gas_mixture/air_sample = sensor.return_air() @@ -47,7 +47,7 @@ return . = list() for(var/gas in air_sample.gas) - var/decl/material/mat = decls_repository.get_decl(gas) + var/decl/material/mat = GET_DECL(gas) var/gaspercent = round(air_sample.gas[gas]*100/total_moles,0.01) var/gas_list = list("symbol" = mat.gas_symbol_html, "percent" = gaspercent) . += list(gas_list) @@ -58,7 +58,7 @@ desc = "The pressure of the gas at the sensor." can_write = FALSE has_updates = FALSE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/pressure/access_var(obj/machinery/sensor) var/datum/gas_mixture/air_sample = sensor.return_air() @@ -70,7 +70,7 @@ desc = "The temperature of the gas at the sensor." can_write = FALSE has_updates = FALSE - var_type = IC_FORMAT_NUMBER + var_type = VAR_FORMAT_NUMBER /decl/public_access/public_variable/temperature/access_var(obj/machinery/sensor) var/datum/gas_mixture/air_sample = sensor.return_air() @@ -91,7 +91,7 @@ frequency = ATMOS_ENGINE_FREQ /obj/machinery/air_sensor/dist - stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/air_sensor/engine = 1) + stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/air_sensor/dist = 1) -/decl/stock_part_preset/radio/basic_transmitter/air_sensor/engine +/decl/stock_part_preset/radio/basic_transmitter/air_sensor/dist frequency = ATMOS_DIST_FREQ \ No newline at end of file diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 556f24ec4376..5b72753a9e6d 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -42,52 +42,51 @@ #define MAX_TEMPERATURE 90 #define MIN_TEMPERATURE -40 -//all air alarms in area are connected via magic -/area - var/list/air_vent_names = list() - var/list/air_scrub_names = list() - var/list/air_vent_info = list() - var/list/air_scrub_info = list() - +#define BASE_ALARM_NAME "environment alarm" /obj/machinery/alarm - name = "alarm" + name = BASE_ALARM_NAME icon = 'icons/obj/monitors.dmi' icon_state = "alarm0" - anchored = 1 + anchored = TRUE idle_power_usage = 80 active_power_usage = 1000 //For heating/cooling rooms. 1000 joules equates to about 1 degree every 2 seconds for a single tile of air. power_channel = ENVIRON initial_access = list(list(access_atmospherics, access_engine_equip)) clicksound = "button" clickvol = 30 - layer = ABOVE_WINDOW_LAYER + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + + base_type = /obj/machinery/alarm + frame_type = /obj/item/frame/air_alarm + uncreated_component_parts = list(/obj/item/stock_parts/power/apc = 1) + construct_state = /decl/machine_construction/wall_frame/panel_closed + wires = /datum/wires/alarm + directional_offset = @'{"NORTH":{"y":-21}, "SOUTH":{"y":21}, "EAST":{"x":-21}, "WEST":{"x":21}}' var/alarm_id = null var/breach_detection = 1 // Whether to use automatic breach detection or not var/frequency = 1439 - //var/skipprocess = 0 //Experimenting var/alarm_frequency = 1437 var/remote_control = 0 var/rcon_setting = 2 - var/rcon_time = 0 + var/rcon_remote_override_access = list(access_ce) var/locked = 1 var/aidisabled = 0 var/shorted = 0 - wires = /datum/wires/alarm - var/mode = AALARM_MODE_SCRUBBING var/screen = AALARM_SCREEN_MAIN var/area_uid var/area/alarm_area + var/custom_alarm_name var/target_temperature = T0C+20 var/regulating_temperature = 0 var/datum/radio_frequency/radio_connection - var/list/TLV = list() + var/list/TLV = list() // stands for Threshold Limit Value, since it handles exposure amounts var/list/trace_gas = list() //list of other gases that this air alarm is able to detect var/danger_level = 0 @@ -99,12 +98,6 @@ var/environment_type = /decl/environment_data var/report_danger_level = 1 - base_type = /obj/machinery/alarm - frame_type = /obj/item/frame/air_alarm - stat_immune = 0 - uncreated_component_parts = null - construct_state = /decl/machine_construction/wall_frame/panel_closed - /obj/machinery/alarm/cold target_temperature = T0C+4 @@ -117,8 +110,15 @@ target_temperature = T0C+75 environment_type = /decl/environment_data/finnish +/obj/machinery/alarm/warm/Initialize() + . = ..() + TLV["temperature"] = list(T0C-26, T0C, T0C+75, T0C+85) // K + TLV["pressure"] = list(0.80 ATM, 0.90 ATM, 1.30 ATM, 1.50 ATM) /* kpa */ + /obj/machinery/alarm/nobreach breach_detection = 0 +/obj/machinery/alarm/nobreach/airlock + frequency = EXTERNAL_AIR_FREQ /obj/machinery/alarm/monitor report_danger_level = 0 @@ -131,35 +131,52 @@ . = ..() /obj/machinery/alarm/Destroy() - GLOB.name_set_event.unregister(src, get_area(src), .proc/change_area_name) - unregister_radio(src, frequency) + reset_area(alarm_area, null) + unregister_radio_to_controller(src, frequency) return ..() /obj/machinery/alarm/Initialize(mapload, var/dir) + if (name != BASE_ALARM_NAME) + custom_alarm_name = TRUE // this will prevent us from messing with alarms with names set on map + + set_frequency(frequency) + reset_area(null, get_area(src)) + . = ..() - alarm_area = get_area(src) if(!alarm_area) return // spawned in nullspace, presumably as a prototype for construction purposes. area_uid = alarm_area.uid - if (name == "alarm") - SetName("[alarm_area.name] Air Alarm") - - // breathable air according to human/Life() - TLV[/decl/material/gas/oxygen] = list(16, 19, 135, 140) // Partial pressure, kpa - TLV[/decl/material/gas/carbon_dioxide] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa - TLV["other"] = list(-1.0, -1.0, 0.2, 0.5) // Partial pressure, kpa - TLV["pressure"] = list(ONE_ATMOSPHERE*0.80,ONE_ATMOSPHERE*0.90,ONE_ATMOSPHERE*1.10,ONE_ATMOSPHERE*1.20) /* kpa */ + + // breathable air according to default human species + // TODO: make it use map default species? + var/decl/material/gas_mat = GET_DECL(/decl/material/gas/oxygen) + TLV[gas_mat.gas_name] = list(16, 19, 135, 140) // Partial pressure, kpa + gas_mat = GET_DECL(/decl/material/gas/carbon_dioxide) + TLV[gas_mat.gas_name] = list(-1, -1, 5, 10) // Partial pressure, kpa + TLV["other"] = list(-1, -1, 0.2, 0.5) // Partial pressure, kpa + TLV["pressure"] = list(0.80 ATM, 0.90 ATM, 1.10 ATM, 1.20 ATM) /* kpa */ TLV["temperature"] = list(T0C-26, T0C, T0C+40, T0C+66) // K - var/decl/environment_data/env_info = decls_repository.get_decl(environment_type) - for(var/g in subtypesof(/decl/material/gas)) + var/decl/environment_data/env_info = GET_DECL(environment_type) + for(var/g in get_filterable_material_types()) if(!env_info.important_gasses[g]) trace_gas += g + // not everything in these lists is a subtype of /decl/material/gas, so: + for(var/dangerous_gas in env_info.dangerous_gasses) + if(env_info.important_gasses[dangerous_gas] || !env_info.dangerous_gasses[dangerous_gas]) + continue + trace_gas |= dangerous_gas + for(var/filtered_gas in env_info.filter_gasses) + if(env_info.important_gasses[filtered_gas]) + continue + trace_gas |= filtered_gas - GLOB.name_set_event.register(alarm_area, src, .proc/change_area_name) - set_frequency(frequency) - update_icon() + queue_icon_update() + +/obj/machinery/alarm/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(alarm_id, map_hash) /obj/machinery/alarm/get_req_access() if(!locked) @@ -170,13 +187,13 @@ if((stat & (NOPOWER|BROKEN)) || shorted) return - var/turf/simulated/location = loc - if(!istype(location)) return//returns if loc is not simulated + var/turf/location = loc + if(!istype(location) || !location.simulated) return//returns if loc is not simulated var/datum/gas_mixture/environment = location.return_air() //Handle temperature adjustment here. - if(environment.return_pressure() > ONE_ATMOSPHERE*0.05) + if(environment.return_pressure() > (0.05 ATM)) handle_heating_cooling(environment) var/old_level = danger_level @@ -191,7 +208,7 @@ mode = AALARM_MODE_OFF apply_mode() - if (mode==AALARM_MODE_CYCLE && environment.return_pressure() 2.0) + if(!get_danger_level(target_temperature, TLV["temperature"]) && abs(environment.temperature - target_temperature) > 2) update_use_power(POWER_USE_ACTIVE) regulating_temperature = 1 visible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ @@ -255,7 +272,7 @@ environment.merge(gas) /obj/machinery/alarm/proc/overall_danger_level(var/datum/gas_mixture/environment) - var/partial_pressure = R_IDEAL_GAS_EQUATION*environment.temperature/environment.volume + var/partial_pressure = R_IDEAL_GAS_EQUATION*environment.temperature/environment.total_volume var/environment_pressure = environment.return_pressure() var/other_moles = 0 @@ -263,8 +280,10 @@ other_moles += environment.gas[g] //this is only going to be used in a partial pressure calc, so we don't need to worry about group_multiplier here. pressure_dangerlevel = get_danger_level(environment_pressure, TLV["pressure"]) - oxygen_dangerlevel = get_danger_level(environment.gas[/decl/material/gas/oxygen]*partial_pressure, TLV[/decl/material/gas/oxygen]) - co2_dangerlevel = get_danger_level(environment.gas[/decl/material/gas/carbon_dioxide]*partial_pressure, TLV[/decl/material/gas/carbon_dioxide]) + var/decl/material/gas_mat = GET_DECL(/decl/material/gas/oxygen) + oxygen_dangerlevel = get_danger_level(environment.gas[/decl/material/gas/oxygen]*partial_pressure, TLV[gas_mat.gas_name]) + gas_mat = GET_DECL(/decl/material/gas/carbon_dioxide) + co2_dangerlevel = get_danger_level(environment.gas[/decl/material/gas/carbon_dioxide]*partial_pressure, TLV[gas_mat.gas_name]) temperature_dangerlevel = get_danger_level(environment.temperature, TLV["temperature"]) other_dangerlevel = get_danger_level(other_moles*partial_pressure, TLV["other"]) @@ -278,9 +297,9 @@ // Returns whether this air alarm thinks there is a breach, given the sensors that are available to it. /obj/machinery/alarm/proc/breach_detected() - var/turf/simulated/location = loc + var/turf/location = loc - if(!istype(location)) + if(!istype(location) || !location.simulated) return 0 if(breach_detection == 0) @@ -305,20 +324,6 @@ return 0 /obj/machinery/alarm/on_update_icon() - // Set pixel offsets - pixel_x = 0 - pixel_y = 0 - var/turf/T = get_step(get_turf(src), turn(dir, 180)) - if(istype(T) && T.density) - if(dir == NORTH) - pixel_y = -21 - else if(dir == SOUTH) - pixel_y = 21 - else if(dir == WEST) - pixel_x = 21 - else if(dir == EAST) - pixel_x = -21 - // Broken or deconstructed states if(!istype(construct_state, /decl/machine_construction/wall_frame/panel_closed)) icon_state = "alarmx" @@ -346,7 +351,7 @@ icon_state = "alarm1" new_color = COLOR_RED_LIGHT - set_light(0.25, 0.1, 1, 2, new_color) + set_light(2, 0.25, new_color) /obj/machinery/alarm/receive_signal(datum/signal/signal) if(!signal || signal.encryption) @@ -374,10 +379,10 @@ /obj/machinery/alarm/proc/register_env_machine(var/m_id, var/device_type) var/new_name if (device_type=="AVP") - new_name = "[alarm_area.name] Vent Pump #[alarm_area.air_vent_names.len+1]" + new_name = "[alarm_area.proper_name] Vent Pump #[alarm_area.air_vent_names.len+1]" alarm_area.air_vent_names[m_id] = new_name else if (device_type=="AScr") - new_name = "[alarm_area.name] Air Scrubber #[alarm_area.air_scrub_names.len+1]" + new_name = "[alarm_area.proper_name] Air Scrubber #[alarm_area.air_scrub_names.len+1]" alarm_area.air_scrub_names[m_id] = new_name send_signal(m_id, list("init" = new_name) ) @@ -391,7 +396,6 @@ return 0 var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal signal.source = src signal.data = command @@ -454,8 +458,7 @@ var/datum/signal/alert_signal = new alert_signal.source = src - alert_signal.transmission_method = 1 - alert_signal.data["zone"] = alarm_area.name + alert_signal.data["zone"] = alarm_area.proper_name alert_signal.data["type"] = "Atmospheric" if(alert_level==2) @@ -471,18 +474,15 @@ ui_interact(user) return TRUE -/obj/machinery/alarm/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/alarm/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] - var/remote_connection = 0 - var/remote_access = 0 - if(state) - var/list/href = state.href_list(user) - remote_connection = href["remote_connection"] // Remote connection means we're non-adjacent/connecting from another computer - remote_access = href["remote_access"] // Remote access means we also have the privilege to alter the air alarm. + var/remote_connection = istype(state, /datum/topic_state/remote) // Remote connection means we're non-adjacent/connecting from another computer + var/remote_access = remote_connection && CanInteract(user, state) // Remote access means we also have the privilege to alter the air alarm. data["locked"] = locked && !issilicon(user) data["remote_connection"] = remote_connection data["remote_access"] = remote_access + data["rcon_access"] = (CanUseTopic(user, state, list("rcon" = TRUE)) == STATUS_INTERACTIVE) data["rcon"] = rcon_setting data["screen"] = screen @@ -508,9 +508,9 @@ if(total) var/pressure = environment.return_pressure() environment_data[++environment_data.len] = list("name" = "Pressure", "value" = pressure, "unit" = "kPa", "danger_level" = pressure_dangerlevel) - var/decl/environment_data/env_info = decls_repository.get_decl(environment_type) + var/decl/environment_data/env_info = GET_DECL(environment_type) for(var/gas_id in env_info.important_gasses) - var/decl/material/mat = decls_repository.get_decl(gas_id) + var/decl/material/mat = GET_DECL(gas_id) environment_data[++environment_data.len] = list( "name" = capitalize(mat.gas_name), "value" = environment.gas[gas_id] / total * 100, @@ -564,13 +564,13 @@ "panic" = info["panic"], "filters" = list() ) - var/decl/environment_data/env_info = decls_repository.get_decl(environment_type) + var/decl/environment_data/env_info = GET_DECL(environment_type) for(var/gas_id in env_info.filter_gasses) - var/decl/material/mat = decls_repository.get_decl(gas_id) + var/decl/material/mat = GET_DECL(gas_id) scrubbers[scrubbers.len]["filters"] += list( list( "name" = capitalize(mat.gas_name), - "id" = gas_id, + "id" = "\ref[gas_id]", "val" = (gas_id in info["scrubbing_gas"]) ) ) @@ -586,19 +586,19 @@ modes[++modes.len] = list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0) data["modes"] = modes data["mode"] = mode + if(AALARM_SCREEN_SENSORS) var/list/selected var/thresholds[0] - - var/list/gas_names = list( - /decl/material/gas/oxygen = "O2", - /decl/material/gas/carbon_dioxide = "CO2", - "other" = "Other") - for (var/g in gas_names) - thresholds[++thresholds.len] = list("name" = gas_names[g], "settings" = list()) - selected = TLV[g] + var/decl/environment_data/env_info = GET_DECL(environment_type) + for(var/g in env_info?.important_gasses) + var/decl/material/mat = GET_DECL(g) + thresholds[++thresholds.len] = list("name" = (mat?.gas_symbol_html || "Other"), "settings" = list()) + selected = TLV[mat.gas_name] + if(!selected) + continue for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = g, "val" = i, "selected" = selected[i])) + thresholds[thresholds.len]["settings"] += list(list("env" = mat.gas_name, "val" = i, "selected" = selected[i])) selected = TLV["pressure"] thresholds[++thresholds.len] = list("name" = "Pressure", "settings" = list()) @@ -620,11 +620,17 @@ . = shorted ? STATUS_DISABLED : STATUS_INTERACTIVE - if(. == STATUS_INTERACTIVE) - var/extra_href = state.href_list(user) - // Prevent remote users from altering RCON settings unless they already have access - if(href_list["rcon"] && extra_href["remote_connection"] && !extra_href["remote_access"]) - . = STATUS_UPDATE + if(. == STATUS_INTERACTIVE && istype(state, /datum/topic_state/remote)) + . = STATUS_UPDATE + if(isAI(user)) + . = STATUS_INTERACTIVE // Apparently always have access + if(rcon_setting == RCON_YES || (alarm_area.atmosalm && rcon_setting == RCON_AUTO)) + . = STATUS_INTERACTIVE // Have rcon access + + if(has_access(rcon_remote_override_access, user.GetAccess())) + . = STATUS_INTERACTIVE // They have the access to set rcon anyway + else if(href_list && href_list["rcon"]) + . = STATUS_UPDATE // They don't have rcon access but are trying to set it: that's a no return min(..(), .) @@ -649,19 +655,19 @@ var/input_temperature = input(user, "What temperature would you like the system to maintain? (Capped between [min_temperature] and [max_temperature]C)", "Thermostat Controls", target_temperature - T0C) as num|null if(isnum(input_temperature) && CanUseTopic(user, state)) if(input_temperature > max_temperature || input_temperature < min_temperature) - to_chat(user, "Temperature must be between [min_temperature]C and [max_temperature]C") + to_chat(user, "Temperature must be between [min_temperature]C and [max_temperature]C.") else target_temperature = input_temperature + T0C return TOPIC_REFRESH // hrefs that need the AA unlocked -walter0o - var/extra_href = state.href_list(user) - if(!(locked && !extra_href["remote_connection"]) || extra_href["remote_access"] || issilicon(user)) + var/forbidden = locked && !istype(state, /datum/topic_state/remote) && !issilicon(user) + if(!forbidden) if(href_list["command"]) var/device_id = href_list["id_tag"] switch(href_list["command"]) if("set_external_pressure") - var/input_pressure = input(user, "What pressure you like the system to mantain?", "Pressure Controls") as num|null + var/input_pressure = input(user, "What pressure you like the system to maintain?", "Pressure Controls") as num|null if(isnum(input_pressure) && CanUseTopic(user, state)) send_signal(device_id, list(href_list["command"] = input_pressure)) return TOPIC_REFRESH @@ -682,25 +688,30 @@ return TOPIC_REFRESH if("set_scrub_gas") - var/decl/environment_data/env_info = decls_repository.get_decl(environment_type) - if(env_info && (href_list["gas_id"] in env_info.filter_gasses)) - send_signal(device_id, list(href_list["command"] = list(href_list["gas_id"] = text2num(href_list["val"]))) ) + var/decl/environment_data/env_info = GET_DECL(environment_type) + var/gas_path = locate(href_list["gas_id"]) // this is a softref to a decl path + if(env_info && (gas_path in env_info.filter_gasses)) + var/list/signal = list() + signal[gas_path] = text2num(href_list["val"]) + send_signal(device_id, list(href_list["command"] = signal)) return TOPIC_REFRESH if("set_threshold") + var/static/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") var/env = href_list["env"] - var/threshold = text2num(href_list["var"]) + var/threshold = clamp(text2num(href_list["var"]), 1, 4) var/list/selected = TLV[env] - var/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") + if(!threshold || !selected || !selected[threshold]) + return TOPIC_NOACTION var/newval = input(user, "Enter [thresholds[threshold]] for [env]", "Alarm triggers", selected[threshold]) as null|num if (isnull(newval) || !CanUseTopic(user, state)) return TOPIC_HANDLED if (newval<0) - selected[threshold] = -1.0 + selected[threshold] = -1 else if (env=="temperature" && newval>5000) selected[threshold] = 5000 - else if (env=="pressure" && newval>50*ONE_ATMOSPHERE) - selected[threshold] = 50*ONE_ATMOSPHERE + else if (env=="pressure" && newval > (50 ATM)) + selected[threshold] = 50 ATM else if (env!="temperature" && env!="pressure" && newval>200) selected[threshold] = 200 else @@ -751,15 +762,11 @@ return TOPIC_REFRESH if(href_list["atmos_alarm"]) - if (alarm_area.atmosalert(2, src)) - apply_danger_level(2) - update_icon() + set_alarm(2) return TOPIC_REFRESH if(href_list["atmos_reset"]) - if (alarm_area.atmosalert(0, src)) - apply_danger_level(0) - update_icon() + set_alarm(0) return TOPIC_REFRESH if(href_list["mode"]) @@ -767,21 +774,50 @@ apply_mode() return TOPIC_REFRESH -/obj/machinery/alarm/attackby(obj/item/W, mob/user) +/obj/machinery/alarm/proc/set_alarm(danger_level) + if (alarm_area.atmosalert(danger_level, src)) + apply_danger_level(danger_level) + update_icon() + +/obj/machinery/alarm/attackby(obj/item/used_item, mob/user) if(!(stat & (BROKEN|NOPOWER))) - if (istype(W, /obj/item/card/id) || istype(W, /obj/item/modular_computer))// trying to unlock the interface with an ID card + if (istype(used_item, /obj/item/card/id) || istype(used_item, /obj/item/modular_computer))// trying to unlock the interface with an ID card + if(!used_item.user_can_attack_with(user)) + return TRUE if(allowed(user) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN)) locked = !locked - to_chat(user, "You [ locked ? "lock" : "unlock"] the Air Alarm interface.") + to_chat(user, SPAN_NOTICE("You [ locked ? "lock" : "unlock"] the Air Alarm interface.")) else - to_chat(user, "Access denied.") + to_chat(user, SPAN_WARNING("Access denied.")) return TRUE return ..() /obj/machinery/alarm/proc/change_area_name(var/area/A, var/old_area_name, var/new_area_name) - if(A != get_area(src)) + if(A != alarm_area) + return + if (!custom_alarm_name) + SetName("[A.proper_name] [BASE_ALARM_NAME]") + +/obj/machinery/alarm/area_changed(area/old_area, area/new_area) + . = ..() + if(.) + reset_area(old_area, new_area) + +/obj/machinery/alarm/proc/reset_area(area/old_area, area/new_area) + if(old_area == new_area) return - SetName(replacetext(name,old_area_name,new_area_name)) + if(old_area && old_area == alarm_area) + alarm_area = null + area_uid = null + events_repository.unregister(/decl/observ/name_set, old_area, src, PROC_REF(change_area_name)) + if(new_area) + ASSERT(isnull(alarm_area)) + alarm_area = new_area + area_uid = new_area.uid + change_area_name(alarm_area, null, alarm_area.name) + events_repository.register(/decl/observ/name_set, alarm_area, src, PROC_REF(change_area_name)) + for(var/device_tag in alarm_area.air_scrub_names + alarm_area.air_vent_names) + send_signal(device_tag, list()) // ask for updates; they initialized before us and we didn't get the data /* FIRE ALARM @@ -791,91 +827,82 @@ FIRE ALARM desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever." icon = 'icons/obj/firealarm.dmi' icon_state = "casing" - var/detecting = 1.0 - var/working = 1.0 - var/time = 10.0 - var/timing = 0.0 - var/lockdownbyai = 0 - anchored = 1.0 + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + anchored = TRUE idle_power_usage = 2 active_power_usage = 6 power_channel = ENVIRON - var/last_process = 0 - var/seclevel - var/global/list/overlays_cache + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED base_type = /obj/machinery/firealarm frame_type = /obj/item/frame/fire_alarm - stat_immune = 0 - uncreated_component_parts = null + uncreated_component_parts = list(/obj/item/stock_parts/power/apc = 1) construct_state = /decl/machine_construction/wall_frame/panel_closed + directional_offset = @'{"NORTH":{"y":-21}, "SOUTH":{"y":21}, "EAST":{"x":21}, "WEST":{"x":-21}}' -/obj/machinery/firealarm/examine(mob/user) - . = ..() - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - to_chat(user, "The current alert level is [security_state.current_security_level.name].") + var/detecting = TRUE + var/working = TRUE + var/time = 1 SECOND + var/timing = FALSE + var/last_process = 0 -/obj/machinery/firealarm/proc/get_cached_overlay(key) - if(!LAZYACCESS(overlays_cache, key)) - var/state - switch(key) - if(/decl/machine_construction/wall_frame/panel_open) - state = "b2" - if(/decl/machine_construction/wall_frame/no_wires) - state = "b1" - if(/decl/machine_construction/wall_frame/no_circuit) - state = "b0" - else - state = key - LAZYSET(overlays_cache, key, image(icon, state)) - return overlays_cache[key] + var/sound_id + var/datum/sound_token/sound_token -/obj/machinery/firealarm/on_update_icon() - overlays.Cut() - - pixel_x = 0 - pixel_y = 0 - var/walldir = (dir & (NORTH|SOUTH)) ? GLOB.reverse_dir[dir] : dir - var/turf/T = get_step(get_turf(src), walldir) - if(istype(T) && T.density) - if(dir == SOUTH) - pixel_y = 21 - else if(dir == NORTH) - pixel_y = -21 - else if(dir == EAST) - pixel_x = 21 - else if(dir == WEST) - pixel_x = -21 +/obj/machinery/firealarm/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(isContactLevel(loc.z)) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + . += "The current alert level is [security_state.current_security_level.name]." +/obj/machinery/firealarm/on_update_icon() + cut_overlays() icon_state = "casing" if(construct_state && !istype(construct_state, /decl/machine_construction/wall_frame/panel_closed)) - overlays += get_cached_overlay(construct_state.type) + var/construct_icon_state + switch(construct_state.type) + if(/decl/machine_construction/wall_frame/panel_open) + construct_icon_state = "b2" + if(/decl/machine_construction/wall_frame/no_wires) + construct_icon_state = "b1" + if(/decl/machine_construction/wall_frame/no_circuit) + construct_icon_state = "b0" + add_overlay(construct_icon_state) set_light(0) return if(stat & BROKEN) - overlays += get_cached_overlay("broken") + add_overlay("broken") set_light(0) else if(stat & NOPOWER) - overlays += get_cached_overlay("unpowered") + add_overlay("unpowered") set_light(0) else if(!detecting) - overlays += get_cached_overlay("fire1") - set_light(0.25, 0.1, 1, 2, COLOR_RED) - else if(z in GLOB.using_map.contact_levels) - overlays += get_cached_overlay("fire0") - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - var/decl/security_level/sl = security_state.current_security_level - - set_light(sl.light_max_bright, sl.light_inner_range, sl.light_outer_range, 2, sl.light_color_alarm) - overlays += image(sl.icon, sl.overlay_alarm) + add_overlay("fire1") + set_light(2, 0.25, COLOR_RED) + else if(isContactLevel(z)) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + var/decl/security_level/sec_level = security_state.current_security_level + + set_light(sec_level.light_power, sec_level.light_range, sec_level.light_color_alarm) + + if(sec_level.alarm_appearance.alarm_icon) + var/image/alert1 = image(sec_level.icon, sec_level.alarm_appearance.alarm_icon) + alert1.color = sec_level.alarm_appearance.alarm_icon_color + add_overlay(alert1) + + if(sec_level.alarm_appearance.alarm_icon_twotone) + var/image/alert2 = image(sec_level.icon, sec_level.alarm_appearance.alarm_icon_twotone) + alert2.color = sec_level.alarm_appearance.alarm_icon_twotone_color + add_overlay(alert2) + else + add_overlay("fire0") /obj/machinery/firealarm/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(src.detecting) - if(exposed_temperature > T0C+200) - src.alarm() // added check of detector status here - return + if(detecting && exposed_temperature > T0C+200) + alarm() + return ..() /obj/machinery/firealarm/bullet_act() return src.alarm() @@ -885,7 +912,7 @@ FIRE ALARM alarm(rand(30/severity, 60/severity)) ..() -/obj/machinery/firealarm/attackby(obj/item/W, mob/user) +/obj/machinery/firealarm/attackby(obj/item/used_item, mob/user) if((. = ..())) return src.alarm() @@ -918,36 +945,36 @@ FIRE ALARM var/d1 var/d2 - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon)) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if (ishuman(user) || issilicon(user) || isobserver(user)) A = A.loc if (A.fire) - d1 = text("Reset - Lockdown", src) + d1 = text("Reset - Lockdown", src) else - d1 = text("Alarm - Lockdown", src) + d1 = text("Alarm - Lockdown", src) if (src.timing) - d2 = text("Stop Time Lock", src) + d2 = text("Stop Time Lock", src) else - d2 = text("Initiate Time Lock", src) + d2 = text("Initiate Time Lock", src) var/second = round(src.time) % 60 var/minute = (round(src.time) - second) / 60 - var/dat = "Fire alarm [d1]\n
    The current alert level is [security_state.current_security_level.name]

    \nTimer System: [d2]
    \nTime Left: [(minute ? "[minute]:" : null)][second] - - + +\n
    " + var/dat = "Fire alarm [d1]\n
    The current alert level is [security_state.current_security_level.name]

    \nTimer System: [d2]
    \nTime Left: [(minute ? "[minute]:" : null)][second] - - + +\n
    " show_browser(user, dat, "window=firealarm") onclose(user, "firealarm") else A = A.loc if (A.fire) - d1 = text("[]", src, stars("Reset - Lockdown")) + d1 = text("[]", src, stars("Reset - Lockdown")) else - d1 = text("[]", src, stars("Alarm - Lockdown")) + d1 = text("[]", src, stars("Alarm - Lockdown")) if (src.timing) - d2 = text("[]", src, stars("Stop Time Lock")) + d2 = text("[]", src, stars("Stop Time Lock")) else - d2 = text("[]", src, stars("Initiate Time Lock")) + d2 = text("[]", src, stars("Initiate Time Lock")) var/second = round(src.time) % 60 var/minute = (round(src.time) - second) / 60 - var/dat = "[stars("Fire alarm")] [d1]\n
    The current security level is [security_state.current_security_level.name]

    \nTimer System: [d2]
    \nTime Left: [(minute ? text("[]:", minute) : null)][second] - - + +\n
    " + var/dat = "[stars("Fire alarm")] [d1]\n
    The current security level is [security_state.current_security_level.name]

    \nTimer System: [d2]
    \nTime Left: [(minute ? text("[]:", minute) : null)][second] - - + +\n
    " show_browser(user, dat, "window=firealarm") onclose(user, "firealarm") return @@ -980,6 +1007,7 @@ FIRE ALARM for(var/obj/machinery/firealarm/FA in area) fire_alarm.clearAlarm(loc, FA) update_icon() + QDEL_NULL(sound_token) return /obj/machinery/firealarm/proc/alarm(var/duration = 0) @@ -989,28 +1017,34 @@ FIRE ALARM for(var/obj/machinery/firealarm/FA in area) fire_alarm.triggerAlarm(loc, FA, duration) update_icon() - playsound(src, 'sound/machines/fire_alarm.ogg', 75, 0) + if(!sound_token) + sound_token = play_looping_sound(src, sound_id, 'sound/machines/fire_alarm.ogg', 75) return +/obj/machinery/firealarm/Destroy() + QDEL_NULL(sound_token) + . = ..() + /obj/machinery/firealarm/Initialize(mapload, dir) . = ..() if(dir) - set_dir((dir & (NORTH|SOUTH)) ? dir : GLOB.reverse_dir[dir]) + set_dir((dir & (NORTH|SOUTH)) ? dir : global.reverse_dir[dir]) queue_icon_update() + sound_id = "firealarm_\ref[src]" /obj/machinery/partyalarm name = "\improper PARTY BUTTON" desc = "Cuban Pete is in the house!" - icon = 'icons/obj/monitors.dmi' - icon_state = "fire0" - var/detecting = 1.0 - var/working = 1.0 - var/time = 10.0 - var/timing = 0.0 - var/lockdownbyai = 0 - anchored = 1.0 + icon = 'icons/obj/firealarm.dmi' + icon_state = "casing" + anchored = TRUE idle_power_usage = 2 active_power_usage = 6 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-21}, "SOUTH":{"y":21}, "EAST":{"x":21}, "WEST":{"x":-21}}' + var/time = 1 SECOND + var/timing = FALSE + var/working = TRUE /obj/machinery/partyalarm/interface_interact(mob/user) interact(user) @@ -1022,33 +1056,33 @@ FIRE ALARM ASSERT(isarea(A)) var/d1 var/d2 - if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) + if (ishuman(user) || isAI(user)) if (A.party) - d1 = text("No Party :(", src) + d1 = text("No Party :(", src) else - d1 = text("PARTY!!!", src) + d1 = text("PARTY!!!", src) if (timing) - d2 = text("Stop Time Lock", src) + d2 = text("Stop Time Lock", src) else - d2 = text("Initiate Time Lock", src) + d2 = text("Initiate Time Lock", src) var/second = time % 60 var/minute = (time - second) / 60 - var/dat = text("Party Button []\n
    \nTimer System: []
    \nTime Left: [][] - - + +\n
    ", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + var/dat = text("Party Button []\n
    \nTimer System: []
    \nTime Left: [][] - - + +\n
    ", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) show_browser(user, dat, "window=partyalarm") onclose(user, "partyalarm") else if (A.fire) - d1 = text("[]", src, stars("No Party :(")) + d1 = text("[]", src, stars("No Party :(")) else - d1 = text("[]", src, stars("PARTY!!!")) + d1 = text("[]", src, stars("PARTY!!!")) if (timing) - d2 = text("[]", src, stars("Stop Time Lock")) + d2 = text("[]", src, stars("Stop Time Lock")) else - d2 = text("[]", src, stars("Initiate Time Lock")) + d2 = text("[]", src, stars("Initiate Time Lock")) var/second = time % 60 var/minute = (time - second) / 60 - var/dat = text("[] []\n
    \nTimer System: []
    \nTime Left: [][] - - + +\n
    ", stars("Party Button"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + var/dat = text("[] []\n
    \nTimer System: []
    \nTime Left: [][] - - + +\n
    ", stars("Party Button"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) show_browser(user, dat, "window=partyalarm") onclose(user, "partyalarm") return diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index c7a74376a0e0..65ecb25cd2e3 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -7,7 +7,7 @@ var/frequency = 1441 var/datum/radio_frequency/radio_connection - var/pressure_setting = ONE_ATMOSPHERE * 45 + var/pressure_setting = 45 ATM var/input_flow_setting = 200 var/list/input_info = list() var/list/output_info = list() @@ -31,6 +31,12 @@ . = ..() set_frequency(frequency) +/obj/machinery/computer/air_control/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(input_tag, map_hash) + ADJUST_TAG_VAR(output_tag, map_hash) + ADJUST_TAG_VAR(sensor_tag, map_hash) + /obj/machinery/computer/air_control/Destroy() if(radio_controller) radio_controller.remove_object(src, frequency) @@ -66,9 +72,9 @@ temp += list("pressure" = sensor_info["pressure"]) if(sensor_info["temperature"]) temp += list("temperature" = sensor_info["temperature"]) - + data["gasses"] = list() - + if(sensor_info["gas"]) data["gasses"] = sensor_info["gas"] @@ -108,9 +114,6 @@ data["automation"] = automation -/obj/machinery/computer/air_control/Process() - ..() - /obj/machinery/computer/air_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -135,64 +138,63 @@ /obj/machinery/computer/air_control/OnTopic(mob/user, href_list, datum/topic_state/state) if(..()) return TOPIC_HANDLED - + var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal signal.source = src if(href_list["in_refresh_status"]) input_info = null refreshing_input = TRUE - signal.data = list ("tag" = input_tag, "status" = 1) + signal.data = list("tag" = input_tag, "status" = 1) . = 1 if(href_list["in_toggle_injector"]) input_info = null refreshing_input = TRUE - signal.data = list ("tag" = input_tag, "power_toggle" = 1) + signal.data = list("tag" = input_tag, "power_toggle" = 1) . = 1 if(href_list["in_set_flowrate"]) input_info = null refreshing_input = TRUE - input_flow_setting = input("What would you like to set the rate limit to?", "Set Volume", input_flow_setting) as num|null - input_flow_setting = between(0, input_flow_setting, ATMOS_DEFAULT_VOLUME_PUMP+500) - signal.data = list ("tag" = input_tag, "set_volume_rate" = input_flow_setting) + input_flow_setting = input(user, "What would you like to set the rate limit to?", "Set Volume", input_flow_setting) as num|null + input_flow_setting = clamp(input_flow_setting, 0, ATMOS_DEFAULT_VOLUME_PUMP+500) + signal.data = list("tag" = input_tag, "set_volume_rate" = input_flow_setting) . = 1 if(href_list["in_set_max"]) input_info = null refreshing_input = TRUE input_flow_setting = ATMOS_DEFAULT_VOLUME_PUMP+500 - signal.data = list ("tag" = input_tag, "set_volume_rate" = input_flow_setting) + signal.data = list("tag" = input_tag, "set_volume_rate" = input_flow_setting) . = 1 if(href_list["out_refresh_status"]) output_info = null refreshing_output = TRUE - signal.data = list ("tag" = output_tag, "status" = 1) + signal.data = list("tag" = output_tag, "status" = 1) . = 1 if(href_list["out_toggle_power"]) output_info = null refreshing_output = TRUE - signal.data = list ("tag" = output_tag, "power_toggle" = 1, "status" = 1) + signal.data = list("tag" = output_tag, "power_toggle" = 1, "status" = 1) . = 1 if(href_list["out_set_pressure"]) output_info = null refreshing_output = TRUE - pressure_setting = input("How much pressure would you like to output?", "Set Pressure", pressure_setting) as num|null - pressure_setting = between(0, pressure_setting, MAX_PUMP_PRESSURE) - signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]", "status" = 1) + pressure_setting = input(user, "How much pressure would you like to output?", "Set Pressure", pressure_setting) as num|null + pressure_setting = clamp(pressure_setting, 0, MAX_PUMP_PRESSURE) + signal.data = list("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]", "status" = 1) . = 1 - + if(href_list["s_out_set_pressure"]) output_info = null refreshing_output = TRUE - pressure_setting = input("How much pressure would you like to maintain inside the core?", "Set Core Pressure", pressure_setting) as num|null - pressure_setting = between(0, pressure_setting, MAX_PUMP_PRESSURE) - signal.data = list ("tag" = output_tag, "set_external_pressure" = pressure_setting, "checks" = 1, "status" = 1) + pressure_setting = input(user, "How much pressure would you like to maintain inside the core?", "Set Core Pressure", pressure_setting) as num|null + pressure_setting = clamp(pressure_setting, 0, MAX_PUMP_PRESSURE) + signal.data = list("tag" = output_tag, "set_external_pressure" = pressure_setting, "checks" = 1, "status" = 1) . = 1 if(href_list["s_set_default"]) @@ -205,43 +207,43 @@ output_info = null refreshing_output = TRUE pressure_setting = MAX_PUMP_PRESSURE - signal.data = list ("tag" = output_tag, "set_internal_pressure" = pressure_setting, "status" = 1) + signal.data = list("tag" = output_tag, "set_internal_pressure" = pressure_setting, "status" = 1) . = 1 if(href_list["set_frequency"]) - var/F = input("What frequency would you like to set this to? (Decimal is added automatically)", "Adjust Frequency", frequency) as num|null + var/F = input(user, "What frequency would you like to set this to? (Decimal is added automatically)", "Adjust Frequency", frequency) as num|null if(F) frequency = F set_frequency(F) return TOPIC_REFRESH if(href_list["set_input_tag"]) - var/t = sanitizeSafe(input(usr, "Enter the input ID tag.", src.name, src.input_tag), MAX_NAME_LEN) - t = sanitizeSafe(t, MAX_NAME_LEN) + var/t = sanitize_safe(input(user, "Enter the input ID tag.", src.name, src.input_tag), MAX_NAME_LEN) + t = sanitize_safe(t, MAX_NAME_LEN) if (t) src.input_tag = t set_frequency(frequency) return TOPIC_REFRESH if(href_list["set_output_tag"]) - var/t = sanitizeSafe(input(usr, "Enter the output ID tag.", src.name, src.output_tag), MAX_NAME_LEN) - t = sanitizeSafe(t, MAX_NAME_LEN) + var/t = sanitize_safe(input(user, "Enter the output ID tag.", src.name, src.output_tag), MAX_NAME_LEN) + t = sanitize_safe(t, MAX_NAME_LEN) if (t) src.output_tag = t set_frequency(frequency) return TOPIC_REFRESH if(href_list["set_sensor_tag"]) - var/t = sanitizeSafe(input(usr, "Enter the sensor ID tag.", src.name, src.sensor_tag)) - t = sanitizeSafe(t, MAX_NAME_LEN) + var/t = sanitize_safe(input(user, "Enter the sensor ID tag.", src.name, src.sensor_tag)) + t = sanitize_safe(t, MAX_NAME_LEN) if(t) src.sensor_tag = t set_frequency(frequency) return TOPIC_REFRESH - + if(href_list["set_sensor_name"]) - var/t = sanitizeSafe(input(usr, "Enter the sensor name.", src.name, src.sensor_name)) - t = sanitizeSafe(t, MAX_NAME_LEN) + var/t = sanitize_safe(input(user, "Enter the sensor name.", src.name, src.sensor_name)) + t = sanitize_safe(t, MAX_NAME_LEN) if(t) src.sensor_name = t return TOPIC_REFRESH @@ -253,7 +255,7 @@ if(href_list["set_screen"]) data["screen"] = text2num(href_list["set_screen"]) return TOPIC_REFRESH - + if(!radio_connection) return TOPIC_HANDLED @@ -286,7 +288,7 @@ else ..(signal) -/obj/machinery/computer/air_control/fuel_injection/Topic(href, href_list) +/obj/machinery/computer/air_control/fuel_injection/OnTopic(mob/user, href_list, datum/topic_state/state) if((. = ..())) return @@ -294,7 +296,6 @@ automation = !automation var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal signal.source = src signal.data = list( "tag" = device_tag, @@ -317,7 +318,6 @@ injecting = 1 var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal signal.source = src signal.data = list( @@ -328,8 +328,3 @@ radio_connection.post_signal(src, signal, device_tag) ..() - -/obj/machinery/computer/air_control/supermatter_core - icon = 'icons/obj/computer.dmi' - frequency = 1438 - out_pressure_mode = 1 \ No newline at end of file diff --git a/code/game/machinery/atmoalter/_atmos_connection.dm b/code/game/machinery/atmoalter/_atmos_connection.dm new file mode 100644 index 000000000000..32abc3ea478c --- /dev/null +++ b/code/game/machinery/atmoalter/_atmos_connection.dm @@ -0,0 +1,92 @@ +// Extension for allowing an atom to be connected to an atmospherics connector port. +/datum/extension/atmospherics_connection + expected_type = /atom/movable + base_type = /datum/extension/atmospherics_connection + + var/toggle_anchor // Whether to toggle anchor holder on connect/disconnect + var/obj/machinery/atmospherics/portables_connector/connected_port + + var/datum/gas_mixture/merged_mixture + +/datum/extension/atmospherics_connection/New(datum/holder, _toggle_anchor, _merged_mixture) + . = ..() + toggle_anchor = _toggle_anchor + merged_mixture = _merged_mixture + +/datum/extension/atmospherics_connection/Destroy() + merged_mixture = null + disconnect() + . = ..() + +/datum/extension/atmospherics_connection/proc/connect(obj/machinery/atmospherics/portables_connector/new_port) + //Make sure not already connected to something else + if(connected_port || !new_port || new_port.connected_device) + return FALSE + + var/atom/movable/movable_holder = holder + + //Make sure are close enough for a valid connection + if(new_port.loc != movable_holder.loc) + return FALSE + + //Perform the connection + connected_port = new_port + connected_port.connected_device = holder + connected_port.on = 1 //Activate port updates + + if(toggle_anchor) + movable_holder.anchored = TRUE //Prevent movement + + //Actually enforce the air sharing + var/datum/pipe_network/network = connected_port.return_network(holder) + + if(network && !network.gases.Find(merged_mixture)) + network.gases += merged_mixture + network.update = 1 + + return TRUE + +/datum/extension/atmospherics_connection/proc/disconnect() + if(!connected_port) + return FALSE + + var/datum/pipe_network/network = connected_port.return_network(holder) + if(network) + network.gases -= merged_mixture + + var/atom/movable/movable_holder = holder + + if(toggle_anchor) + movable_holder.anchored = FALSE + + connected_port.connected_device = null + connected_port = null + + return TRUE + +/datum/extension/atmospherics_connection/proc/update_connected_network() + if(!connected_port) + return + + var/datum/pipe_network/network = connected_port.return_network(holder) + if(network) + network.update = 1 + +/datum/extension/atmospherics_connection/proc/update_merged_mixture(datum/gas_mixture/new_mixture) + if(merged_mixture == new_mixture) + return TRUE + + if(!connected_port) + return FALSE + + var/datum/pipe_network/network = connected_port.return_network(holder) + + if(!network) + return FALSE + + network.gases.Remove(merged_mixture) + if(!network.gases.Find(new_mixture)) + network.gases += new_mixture + + network.update = 1 + return TRUE \ No newline at end of file diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm deleted file mode 100644 index 3506d5de0acf..000000000000 --- a/code/game/machinery/atmoalter/area_atmos_computer.dm +++ /dev/null @@ -1,176 +0,0 @@ -/obj/machinery/computer/area_atmos - name = "Area Air Control" - desc = "A computer used to control the stationary scrubbers and pumps in the area." - icon_keyboard = "atmos_key" - icon_screen = "area_atmos" - light_color = "#e6ffff" - - var/list/connectedscrubbers = new() - var/status = "" - - var/range = 25 - - //Simple variable to prevent me from doing attack_hand in both this and the child computer - var/zone = "This computer is working on a wireless range, the range is currently limited to 25 meters." - -/obj/machinery/computer/area_atmos/Initialize() - . = ..() - scanscrubbers() - -/obj/machinery/computer/area_atmos/interface_interact(user) - interact(user) - return TRUE - -/obj/machinery/computer/area_atmos/interact(mob/user) - var/dat = {" - - - - - -

    Area Air Control

    - [status]
    - Scan - "} - for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in connectedscrubbers) - dat += {" - - - - "} - - dat += {" -
    - [scrubber.name]
    - Pressure: [round(scrubber.air_contents.return_pressure(), 0.01)] kPa
    - Flow Rate: [round(scrubber.last_flow_rate,0.1)] L/s
    -
    - Turn On - Turn Off
    - Load: [round(scrubber.last_power_draw)] W -

    - [zone] - - "} - show_browser(user, "[dat]", "window=miningshuttle;size=400x400") - status = "" - -/obj/machinery/computer/area_atmos/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - - - if(href_list["scan"]) - scanscrubbers() - else if(href_list["toggle"]) - var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = locate(href_list["scrub"]) - - if(!validscrubber(scrubber)) - spawn(20) - status = "ERROR: Couldn't connect to scrubber! (timeout)" - connectedscrubbers -= scrubber - src.updateUsrDialog() - return - - scrubber.update_use_power(text2num(href_list["toggle"]) ? POWER_USE_ACTIVE : POWER_USE_IDLE) - scrubber.update_icon() - -/obj/machinery/computer/area_atmos/proc/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) - if(!isobj(scrubber) || get_dist(scrubber.loc, src.loc) > src.range || scrubber.loc.z != src.loc.z) - return 0 - - return 1 - -/obj/machinery/computer/area_atmos/proc/scanscrubbers() - connectedscrubbers = new() - - var/found = 0 - for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in range(range, src.loc)) - if(istype(scrubber)) - found = 1 - connectedscrubbers += scrubber - - if(!found) - status = "ERROR: No scrubber found!" - - src.updateUsrDialog() - - -/obj/machinery/computer/area_atmos/area - zone = "This computer is working in a wired network limited to this area." - -/obj/machinery/computer/area_atmos/area/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) - if(!isobj(scrubber)) - return 0 - - /* - wow this is stupid, someone help me - */ - var/turf/T_src = get_turf(src) - if(!T_src.loc) return 0 - var/area/A_src = T_src.loc - - var/turf/T_scrub = get_turf(scrubber) - if(!T_scrub.loc) return 0 - var/area/A_scrub = T_scrub.loc - - if(A_scrub != A_src) - return 0 - - return 1 - -/obj/machinery/computer/area_atmos/area/scanscrubbers() - connectedscrubbers = new() - - var/found = 0 - - var/turf/T = get_turf(src) - if(!T.loc) return - var/area/A = T.loc - for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in world ) - var/turf/T2 = get_turf(scrubber) - if(T2 && T2.loc) - var/area/A2 = T2.loc - if(istype(A2) && A2 == A) - connectedscrubbers += scrubber - found = 1 - - - if(!found) - status = "ERROR: No scrubber found!" - - src.updateUsrDialog() diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 4efadcb47aa1..bb0801f80b5b 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -1,215 +1,183 @@ /obj/machinery/portable_atmospherics/canister - name = "\improper Canister: \[CAUTION\]" - icon = 'icons/obj/atmos.dmi' - icon_state = "yellow" - density = 1 - var/health = 100.0 - obj_flags = OBJ_FLAG_CONDUCTIBLE - w_class = ITEM_SIZE_GARGANTUAN - construct_state = /decl/machine_construction/pipe/welder - uncreated_component_parts = null - matter = list( + name = "canister" + icon = 'icons/obj/atmos.dmi' + icon_state = "yellow" + density = TRUE + max_health = 100 + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_GARGANTUAN + construct_state = /decl/machine_construction/pipe/welder + stat_immune = NOSCREEN | NOINPUT | NOPOWER + start_pressure = 45 ATM + gas_volume = 1000 + interact_offline = TRUE + matter = list( /decl/material/solid/metal/steel = 10 * SHEET_MATERIAL_AMOUNT ) - - var/valve_open = 0 - var/release_pressure = ONE_ATMOSPHERE - var/release_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP //in L/s - - var/canister_color = "yellow" - var/can_label = 1 - start_pressure = 45 * ONE_ATMOSPHERE + uncreated_component_parts = null + var/valve_open = FALSE + var/release_pressure = ONE_ATMOSPHERE + var/release_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP //in L/s + var/canister_color = "yellow" + var/can_label = TRUE var/temperature_resistance = 1000 + T0C - volume = 1000 - interact_offline = 1 // Allows this to be used when not in powered area. - var/update_flag = 0 + var/decl/material/start_gas = null /obj/machinery/portable_atmospherics/canister/Initialize(mapload, material) if(ispath(material)) matter = list() matter[material] = 10 * SHEET_MATERIAL_AMOUNT . = ..(mapload) + if(start_gas) + air_contents.adjust_gas(start_gas, MolesForPressure()) + lazy_update_icon() /obj/machinery/portable_atmospherics/canister/drain_power() return -1 /obj/machinery/portable_atmospherics/canister/sleeping_agent - name = "\improper Canister: \[N2O\]" - icon_state = "redws" + name = "\improper N2O canister" + icon_state = "redws" canister_color = "redws" - can_label = 0 + can_label = FALSE + start_gas = /decl/material/gas/nitrous_oxide /obj/machinery/portable_atmospherics/canister/nitrogen - name = "\improper Canister: \[N2\]" - icon_state = "red" + name = "nitrogen canister" + icon_state = "red" canister_color = "red" - can_label = 0 + can_label = FALSE + start_gas = /decl/material/gas/nitrogen /obj/machinery/portable_atmospherics/canister/nitrogen/prechilled - name = "\improper Canister: \[N2 (Cooling)\]" + name = "cryogenic nitrogen canister" + start_pressure = 20 ATM + +/obj/machinery/portable_atmospherics/canister/nitrogen/prechilled/Initialize() + . = ..() + air_contents.temperature = 80 + lazy_update_icon() /obj/machinery/portable_atmospherics/canister/oxygen - name = "\improper Canister: \[O2\]" - icon_state = "blue" + name = "oxygen canister" + icon_state = "blue" canister_color = "blue" - can_label = 0 + can_label = FALSE + start_gas = /decl/material/gas/oxygen /obj/machinery/portable_atmospherics/canister/oxygen/prechilled - name = "\improper Canister: \[O2 (Cryo)\]" - start_pressure = 20 * ONE_ATMOSPHERE + name = "cryogenic oxygen canister" + start_pressure = 20 ATM + +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled/Initialize() + . = ..() + air_contents.temperature = 80 + lazy_update_icon() /obj/machinery/portable_atmospherics/canister/hydrogen - name = "\improper Canister: \[Hydrogen\]" - icon_state = "purple" + name = "hydrogen canister" + icon_state = "purple" canister_color = "purple" - can_label = 0 + can_label = FALSE + start_gas = /decl/material/gas/hydrogen /obj/machinery/portable_atmospherics/canister/carbon_dioxide - name = "\improper Canister \[CO2\]" - icon_state = "black" + name = "\improper CO2 canister" + icon_state = "black" canister_color = "black" - can_label = 0 + can_label = FALSE + start_gas = /decl/material/gas/carbon_dioxide +// This uses an Initialize override instead of start_gas. /obj/machinery/portable_atmospherics/canister/air - name = "\improper Canister \[Air\]" - icon_state = "grey" + name = "air canister" + icon_state = "grey" canister_color = "grey" - can_label = 0 + can_label = FALSE + +// This doesn't use start_gas because it's a mix. +/obj/machinery/portable_atmospherics/canister/air/Initialize() + . = ..() + var/list/air_mix = StandardAirMix() + air_contents.adjust_gas(/decl/material/gas/oxygen, air_mix[/decl/material/gas/oxygen], FALSE) + air_contents.adjust_gas(/decl/material/gas/nitrogen, air_mix[/decl/material/gas/nitrogen]) + lazy_update_icon() /obj/machinery/portable_atmospherics/canister/air/airlock - start_pressure = 3 * ONE_ATMOSPHERE + start_pressure = 3 ATM /obj/machinery/portable_atmospherics/canister/empty start_pressure = 0 - can_label = 1 - var/obj/machinery/portable_atmospherics/canister/canister_type = /obj/machinery/portable_atmospherics/canister + can_label = TRUE + +#define EMPTY_CANISTER(TYPE, CTYPE) \ +/obj/machinery/portable_atmospherics/canister/empty/##TYPE{\ + name = CTYPE::name; \ + icon_state = CTYPE::icon_state; \ + canister_color = CTYPE::canister_color; \ +} + +EMPTY_CANISTER(air, /obj/machinery/portable_atmospherics/canister/air) +EMPTY_CANISTER(oxygen, /obj/machinery/portable_atmospherics/canister/oxygen) +EMPTY_CANISTER(nitrogen, /obj/machinery/portable_atmospherics/canister/nitrogen) +EMPTY_CANISTER(carbon_dioxide, /obj/machinery/portable_atmospherics/canister/carbon_dioxide) +EMPTY_CANISTER(sleeping_agent, /obj/machinery/portable_atmospherics/canister/sleeping_agent) +EMPTY_CANISTER(hydrogen, /obj/machinery/portable_atmospherics/canister/hydrogen) -/obj/machinery/portable_atmospherics/canister/empty/Initialize() - . = ..() - name = initial(canister_type.name) - icon_state = initial(canister_type.icon_state) - canister_color = initial(canister_type.canister_color) - -/obj/machinery/portable_atmospherics/canister/empty/air - icon_state = "grey" - canister_type = /obj/machinery/portable_atmospherics/canister/air -/obj/machinery/portable_atmospherics/canister/empty/oxygen - icon_state = "blue" - canister_type = /obj/machinery/portable_atmospherics/canister/oxygen -/obj/machinery/portable_atmospherics/canister/empty/nitrogen - icon_state = "red" - canister_type = /obj/machinery/portable_atmospherics/canister/nitrogen -/obj/machinery/portable_atmospherics/canister/empty/carbon_dioxide - icon_state = "black" - canister_type = /obj/machinery/portable_atmospherics/canister/carbon_dioxide -/obj/machinery/portable_atmospherics/canister/empty/sleeping_agent - icon_state = "redws" - canister_type = /obj/machinery/portable_atmospherics/canister/sleeping_agent -/obj/machinery/portable_atmospherics/canister/empty/hydrogen - icon_state = "purple" - canister_type = /obj/machinery/portable_atmospherics/canister/hydrogen - - - - -/obj/machinery/portable_atmospherics/canister/proc/check_change() - var/old_flag = update_flag - update_flag = 0 - if(holding) - update_flag |= 1 - if(connected_port) - update_flag |= 2 +/obj/machinery/portable_atmospherics/canister/on_update_icon() - var/tank_pressure = return_pressure() - if(tank_pressure < 10) - update_flag |= 4 - else if(tank_pressure < ONE_ATMOSPHERE) - update_flag |= 8 - else if(tank_pressure < 15*ONE_ATMOSPHERE) - update_flag |= 16 - else - update_flag |= 32 + cut_overlays() - if(update_flag == old_flag) - return 1 - else - return 0 - -/obj/machinery/portable_atmospherics/canister/on_update_icon() -/* -update_flag -1 = holding -2 = connected_port -4 = tank_pressure < 10 -8 = tank_pressure < ONE_ATMOS -16 = tank_pressure < 15*ONE_ATMOS -32 = tank_pressure go boom. -*/ - - if (src.destroyed) - overlays.Cut() - src.icon_state = text("[]-1", src.canister_color) + if(destroyed) + icon_state = "[canister_color]-1" return - if(icon_state != "[canister_color]") - icon_state = "[canister_color]" + icon_state = canister_color - if(check_change()) //Returns 1 if no change needed to icons. - return + if(holding) + add_overlay("can-open") + if(get_port()) + add_overlay("can-connector") - overlays.Cut() - - if(update_flag & 1) - overlays += "can-open" - if(update_flag & 2) - overlays += "can-connector" - if(update_flag & 4) - overlays += "can-o0" - if(update_flag & 8) - overlays += "can-o1" - else if(update_flag & 16) - overlays += "can-o2" - else if(update_flag & 32) - overlays += "can-o3" - return + var/tank_pressure = return_pressure() + if(tank_pressure < 10) + add_overlay("can-o0") + else if(tank_pressure < ONE_ATMOSPHERE) + add_overlay("can-o1") + else if(tank_pressure < (15 ATM)) + add_overlay("can-o2") + else + add_overlay("can-o3") /obj/machinery/portable_atmospherics/canister/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature > temperature_resistance) - health -= 5 + current_health -= 5 healthcheck() + return ..() /obj/machinery/portable_atmospherics/canister/proc/healthcheck() - if(destroyed) - return 1 - - if (src.health <= 10) - var/atom/location = src.loc + if(!destroyed && current_health <= 10) + var/atom/location = loc location.assume_air(air_contents) - - src.destroyed = 1 - playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3) - src.set_density(0) + destroyed = TRUE + playsound(loc, 'sound/effects/spray.ogg', 10, 1, -3) + set_density(FALSE) + if(holding) + holding.dropInto(loc) + holding = null update_icon() - - if (src.holding) - src.holding.dropInto(loc) - src.holding = null - - return 1 - else - return 1 + return TRUE /obj/machinery/portable_atmospherics/canister/dismantle() var/turf/T = get_turf(src) if(T) T.assume_air(air_contents) for(var/path in matter) - var/decl/material/material = decls_repository.get_decl(path) - if(material) - material.place_sheet(get_turf(src), round(matter[path]/SHEET_MATERIAL_AMOUNT)) + SSmaterials.create_object(path, get_turf(src), round(matter[path]/SHEET_MATERIAL_AMOUNT)) qdel(src) /obj/machinery/portable_atmospherics/canister/Process() + if (destroyed) return @@ -227,69 +195,58 @@ update_flag if((air_contents.temperature > 0) && (pressure_delta > 0)) var/transfer_moles = calculate_transfer_moles(air_contents, environment, pressure_delta) - transfer_moles = min(transfer_moles, (release_flow_rate/air_contents.volume)*air_contents.total_moles) //flow rate limit + transfer_moles = min(transfer_moles, (release_flow_rate/air_contents.total_volume)*air_contents.total_moles) //flow rate limit + pump_gas_passive(src, air_contents, environment, transfer_moles) - var/returnval = pump_gas_passive(src, air_contents, environment, transfer_moles) - if(returnval >= 0) - src.update_icon() - if(holding) - holding.queue_icon_update() - - if(air_contents.return_pressure() < 1) - can_label = 1 - else - can_label = 0 + can_label = (air_contents?.return_pressure() < 1) + air_contents?.react() - air_contents.react() + update_icon() + if(holding) + holding.update_icon() /obj/machinery/portable_atmospherics/canister/proc/return_temperature() - var/datum/gas_mixture/GM = src.return_air() - if(GM && GM.volume>0) + var/datum/gas_mixture/GM = return_air() + if(GM?.total_volume>0) return GM.temperature return 0 /obj/machinery/portable_atmospherics/canister/proc/return_pressure() - var/datum/gas_mixture/GM = src.return_air() - if(GM && GM.volume>0) + var/datum/gas_mixture/GM = return_air() + if(GM?.total_volume>0) return GM.return_pressure() return 0 /obj/machinery/portable_atmospherics/canister/bullet_act(var/obj/item/projectile/Proj) - if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN)) + if(!(Proj.atom_damage_type == BRUTE || Proj.atom_damage_type == BURN)) return - if(Proj.damage) - src.health -= round(Proj.damage / 2) + current_health -= round(Proj.damage / 2) healthcheck() - ..() + return ..() -/obj/machinery/portable_atmospherics/canister/bash(var/obj/item/W, var/mob/user) +/obj/machinery/portable_atmospherics/canister/bash(var/obj/item/used_item, var/mob/user) . = ..() if(.) - health -= W.force + current_health -= used_item.expend_attack_force(user) healthcheck() -/obj/machinery/portable_atmospherics/canister/attackby(var/obj/item/W, var/mob/user) - if(istype(user, /mob/living/silicon/robot) && istype(W, /obj/item/tank/jetpack)) - var/obj/item/tank/jetpack/pack = W +/obj/machinery/portable_atmospherics/canister/attackby(var/obj/item/used_item, var/mob/user) + if(isrobot(user) && istype(used_item, /obj/item/tank/jetpack)) + var/obj/item/tank/jetpack/pack = used_item var/datum/gas_mixture/thejetpack = pack.air_contents - if(!thejetpack) - return FALSE - var/env_pressure = thejetpack.return_pressure() - var/pressure_delta = min(10*ONE_ATMOSPHERE - env_pressure, (air_contents.return_pressure() - env_pressure)/2) - //Can not have a pressure delta that would cause environment pressure > tank pressure - var/transfer_moles = 0 - if((air_contents.temperature > 0) && (pressure_delta > 0)) - transfer_moles = pressure_delta*thejetpack.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)//Actually transfer the gas - var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) - thejetpack.merge(removed) - to_chat(user, "You pulse-pressurize your jetpack from the tank.") - return TRUE - return FALSE - - . = ..() - - SSnano.update_uis(src) // Update all NanoUIs attached to src + if(thejetpack) + var/env_pressure = thejetpack.return_pressure() + var/pressure_delta = min(10*ONE_ATMOSPHERE - env_pressure, (air_contents.return_pressure() - env_pressure)/2) + //Can not have a pressure delta that would cause environment pressure > tank pressure + var/transfer_moles = 0 + if((air_contents.temperature > 0) && (pressure_delta > 0)) + transfer_moles = pressure_delta*thejetpack.total_volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)//Actually transfer the gas + var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) + thejetpack.merge(removed) + to_chat(user, "You pulse-pressurize your jetpack from the tank.") + return TRUE + return ..() /obj/machinery/portable_atmospherics/canister/interface_interact(mob/user) ui_interact(user) @@ -300,11 +257,11 @@ update_flag var/data[0] data["name"] = name data["canLabel"] = can_label ? 1 : 0 - data["portConnected"] = connected_port ? 1 : 0 + data["portConnected"] = get_port() ? 1 : 0 data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) data["releasePressure"] = round(release_pressure ? release_pressure : 0) - data["minReleasePressure"] = round(ONE_ATMOSPHERE/10) - data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE) + data["minReleasePressure"] = round(0.1 ATM) + data["maxReleasePressure"] = round(10 ATM) data["valveOpen"] = valve_open ? 1 : 0 data["hasHoldingTank"] = holding ? 1 : 0 @@ -341,9 +298,9 @@ update_flag else if (href_list["pressure_adj"]) var/diff = text2num(href_list["pressure_adj"]) if(diff > 0) - release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff) + release_pressure = min(10 ATM, release_pressure+diff) else - release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff) + release_pressure = max(0.1 ATM, release_pressure+diff) . = TOPIC_REFRESH else if (href_list["relabel"]) @@ -363,7 +320,7 @@ update_flag if (label && CanUseTopic(user, state)) canister_color = colors[label] icon_state = colors[label] - SetName("\improper Canister: [label]") + SetName("canister: [label]") update_icon() . = TOPIC_REFRESH @@ -372,96 +329,31 @@ update_flag return STATUS_CLOSE return ..() -/obj/machinery/portable_atmospherics/canister/oxygen/Initialize() - . = ..() - air_contents.adjust_gas(/decl/material/gas/oxygen, MolesForPressure()) - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/hydrogen/Initialize() - . = ..() - air_contents.adjust_gas(/decl/material/gas/hydrogen, MolesForPressure()) - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/oxygen/prechilled/Initialize() - . = ..() - air_contents.temperature = 80 - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/sleeping_agent/Initialize() - . = ..() - air_contents.adjust_gas(/decl/material/gas/nitrous_oxide, MolesForPressure()) - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/nitrogen/Initialize() - . = ..() - src.air_contents.adjust_gas(/decl/material/gas/nitrogen, MolesForPressure()) - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/nitrogen/prechilled/Initialize() - . = ..() - src.air_contents.temperature = 80 - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/carbon_dioxide/Initialize() - . = ..() - src.air_contents.adjust_gas(/decl/material/gas/carbon_dioxide, MolesForPressure()) - queue_icon_update() - - -/obj/machinery/portable_atmospherics/canister/air/Initialize() - . = ..() - var/list/air_mix = StandardAirMix() - src.air_contents.adjust_multi(/decl/material/gas/oxygen, air_mix[/decl/material/gas/oxygen], /decl/material/gas/nitrogen, air_mix[/decl/material/gas/nitrogen]) - queue_icon_update() - - // Special types used for engine setup admin verb, they contain double amount of that of normal canister. -/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup/Initialize() - . = ..() - src.air_contents.adjust_gas(/decl/material/gas/nitrogen, MolesForPressure()) - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/carbon_dioxide/engine_setup/Initialize() - . = ..() - src.air_contents.adjust_gas(/decl/material/gas/carbon_dioxide, MolesForPressure()) - queue_icon_update() - -/obj/machinery/portable_atmospherics/canister/hydrogen/engine_setup/Initialize() - . = ..() - src.air_contents.adjust_gas(/decl/material/gas/hydrogen, MolesForPressure()) - queue_icon_update() +#define ENGINE_SETUP_CANISTER(BASE_TYPE) ##BASE_TYPE/engine_setup/start_pressure = BASE_TYPE::start_pressure * 2; +ENGINE_SETUP_CANISTER(/obj/machinery/portable_atmospherics/canister/nitrogen) +ENGINE_SETUP_CANISTER(/obj/machinery/portable_atmospherics/canister/carbon_dioxide) +ENGINE_SETUP_CANISTER(/obj/machinery/portable_atmospherics/canister/hydrogen) // Spawn debug tanks. /obj/machinery/portable_atmospherics/canister/helium - name = "\improper Canister \[He\]" - icon_state = "black" + name = "helium canister" + icon_state = "black" canister_color = "black" - can_label = 0 - -/obj/machinery/portable_atmospherics/canister/helium/Initialize() - . = ..() - air_contents.adjust_gas(/decl/material/gas/helium, MolesForPressure()) - queue_icon_update() + can_label = FALSE + start_gas = /decl/material/gas/helium /obj/machinery/portable_atmospherics/canister/methyl_bromide - name = "\improper Canister \[CH3Br\]" - icon_state = "black" + name = "\improper CH3Br canister" + icon_state = "black" canister_color = "black" - can_label = 0 - -/obj/machinery/portable_atmospherics/canister/methyl_bromide/Initialize() - . = ..() - air_contents.adjust_gas(/decl/material/gas/methyl_bromide, MolesForPressure()) - queue_icon_update() + can_label = FALSE + start_gas = /decl/material/gas/methyl_bromide /obj/machinery/portable_atmospherics/canister/chlorine - name = "\improper Canister \[Cl\]" - icon_state = "black" + name = "chlorine canister" + icon_state = "black" canister_color = "black" - can_label = 0 - -/obj/machinery/portable_atmospherics/canister/chlorine/Initialize() - . = ..() - air_contents.adjust_gas(/decl/material/gas/chlorine, MolesForPressure()) - queue_icon_update() + can_label = FALSE + start_gas = /decl/material/gas/chlorine // End debug tanks. diff --git a/code/game/machinery/atmoalter/clamp.dm b/code/game/machinery/atmoalter/clamp.dm deleted file mode 100644 index 61167d6f6b43..000000000000 --- a/code/game/machinery/atmoalter/clamp.dm +++ /dev/null @@ -1,129 +0,0 @@ -//Good luck. --BlueNexus - -//Static version of the clamp -/obj/machinery/clamp - name = "stasis clamp" - desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." - icon = 'icons/atmos/clamp.dmi' - icon_state = "pclamp0" - anchored = 1.0 - var/obj/machinery/atmospherics/pipe/target = null - var/open = 1 - - var/list/datum/pipe_network/network_nodes - -/obj/machinery/clamp/Initialize(mapload, var/obj/machinery/atmospherics/pipe/to_attach = null) - . = ..(mapload) - if(istype(to_attach)) - target = to_attach - else - target = locate(/obj/machinery/atmospherics/pipe) in loc - if(target) - update_networks() - set_dir(target.dir) - -/obj/machinery/clamp/proc/update_networks() - if(!target) - return - else - for(var/obj/machinery/atmospherics/pipe/node in target.pipeline_expansion()) - var/datum/pipeline/PL = node.parent - LAZYADD(network_nodes, PL.network) - -/obj/machinery/clamp/physical_attack_hand(var/mob/user) - if(!target) - return FALSE - if(!open) - open() - else - close() - to_chat(user, "You turn [open ? "off" : "on"] \the [src]") - return TRUE - -/obj/machinery/clamp/Destroy() - if(!open && !QDELING(target)) - open() - target = null - . = ..() - -/obj/machinery/clamp/proc/open() - if(open || !target) - return 0 - - target.build_network() - - for(var/datum/pipe_network/netnode in network_nodes) - netnode.update = TRUE - - update_networks() - - open = TRUE - icon_state = "pclamp0" - target.in_stasis = FALSE - target.try_leak() - return 1 - -/obj/machinery/clamp/proc/close() - if(!open) - return 0 - - qdel(target.parent) - - for(var/datum/pipe_network/netnode in network_nodes) - qdel(netnode) - network_nodes = null - - for(var/obj/machinery/atmospherics/pipe/node in target.pipeline_expansion()) - node.build_network() - LAZYADD(network_nodes, node) - var/datum/pipeline/P = node.parent - P.build_pipeline(node) - qdel(P) - - open = FALSE - icon_state = "pclamp1" - target.in_stasis = TRUE - target.try_leak() - return TRUE - -/obj/machinery/clamp/proc/removal(var/atom/destination) - var/obj/item/clamp/C = new/obj/item/clamp(destination) - if(ishuman(destination)) - var/mob/living/carbon/human/H = destination - H.put_in_hands(C) - qdel(src) - -/obj/machinery/clamp/MouseDrop(obj/over_object) - if(!usr) - return - - if(open && over_object == usr && Adjacent(usr)) - to_chat(usr, "You begin to remove \the [src]...") - if (do_after(usr, 30, src)) - to_chat(usr, "You have removed \the [src].") - removal() - return - else - to_chat(usr, "You can't remove \the [src] while it's active!") - -/obj/item/clamp - name = "stasis clamp" - desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." - icon = 'icons/atmos/clamp.dmi' - icon_state = "pclamp0" - origin_tech = "{'engineering':4,'magnets':4}" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - -/obj/item/clamp/afterattack(var/atom/A, mob/user, proximity) - if(!proximity) - return - - if (istype(A, /obj/machinery/atmospherics/pipe)) - to_chat(user, "You begin to attach \the [src] to \the [A]...") - if (do_after(user, 30, src)) - if(!user.unEquip(src)) - return - to_chat(user, "You have attached \the [src] to \the [A].") - new/obj/machinery/clamp(A.loc, A) - qdel(src) \ No newline at end of file diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm index fd8ee1357bc7..cabf2a5d56e2 100644 --- a/code/game/machinery/atmoalter/meter.dm +++ b/code/game/machinery/atmoalter/meter.dm @@ -1,26 +1,26 @@ /obj/machinery/meter name = "meter" - desc = "A gas flow meter." + desc = "A meter that monitors gas composition, pressure, and temperature in the attached pipe." icon = 'icons/obj/meter.dmi' icon_state = "meterX" var/atom/target = null //A pipe for the base type - anchored = 1.0 + anchored = TRUE power_channel = ENVIRON idle_power_usage = 15 uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable + /obj/item/stock_parts/power/apc ) public_variables = list( /decl/public_access/public_variable/gas, /decl/public_access/public_variable/pressure, - /decl/public_access/public_variable/temperature + /decl/public_access/public_variable/temperature ) stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/meter = 1) - frame_type = /obj/item/machine_chassis/pipe_meter/base + frame_type = /obj/item/machine_chassis/pipe_meter construct_state = /decl/machine_construction/default/panel_closed/item_chassis - base_type = /obj/machinery/meter/buildable + base_type = /obj/machinery/meter /obj/machinery/meter/Initialize() . = ..() @@ -32,12 +32,12 @@ /obj/machinery/meter/proc/set_target(atom/new_target) clear_target() target = new_target - GLOB.destroyed_event.register(target, src, .proc/clear_target) + events_repository.register(/decl/observ/destroyed, target, src, PROC_REF(clear_target)) /obj/machinery/meter/proc/clear_target() if(target) - GLOB.destroyed_event.unregister(target, src) - target = null + events_repository.unregister(/decl/observ/destroyed, target, src) + target = null /obj/machinery/meter/return_air() if(target) @@ -64,37 +64,37 @@ return 0 var/env_pressure = environment.return_pressure() - if(env_pressure <= 0.15*ONE_ATMOSPHERE) + if(env_pressure <= (0.15 ATM)) icon_state = "meter0" - else if(env_pressure <= 1.8*ONE_ATMOSPHERE) - var/val = round(env_pressure/(ONE_ATMOSPHERE*0.3) + 0.5) + else if(env_pressure <= (1.8 ATM)) + var/val = round(env_pressure/(0.3 ATM) + 0.5) icon_state = "meter1_[val]" - else if(env_pressure <= 30*ONE_ATMOSPHERE) - var/val = round(env_pressure/(ONE_ATMOSPHERE*5)-0.35) + 1 + else if(env_pressure <= (30 ATM)) + var/val = round(env_pressure/(5 ATM)-0.35) + 1 icon_state = "meter2_[val]" - else if(env_pressure <= 59*ONE_ATMOSPHERE) - var/val = round(env_pressure/(ONE_ATMOSPHERE*5) - 6) + 1 + else if(env_pressure <= (59 ATM)) + var/val = round(env_pressure/(5 ATM) - 6) + 1 icon_state = "meter3_[val]" else icon_state = "meter4" -/obj/machinery/meter/examine(mob/user, distance) +/obj/machinery/meter/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance > 3 && !(istype(user, /mob/living/silicon/ai) || isghost(user))) - to_chat(user, "You are too far away to read it.") + if(distance > 3 && !(isAI(user) || isghost(user))) + . += SPAN_WARNING("You are too far away to read it.") else if(stat & (NOPOWER|BROKEN)) - to_chat(user, "The display is off.") + . += SPAN_WARNING("The display is off.") else if(src.target) var/datum/gas_mixture/environment = target.return_air() if(environment) - to_chat(user, "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)]K ([round(environment.temperature-T0C,0.01)]°C)") + . += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)]K ([round(environment.temperature-T0C,0.01)]°C)." else - to_chat(user, "The sensor error light is blinking.") + . += "The sensor error light is blinking." else - to_chat(user, "The connect error light is blinking.") + . += "The connect error light is blinking." // turf meter -- prioritizes turfs over pipes for target acquisition @@ -103,13 +103,10 @@ set_target(loc) . = ..() -/obj/machinery/meter/buildable - uncreated_component_parts = null - /obj/machinery/meter/starts_with_radio uncreated_component_parts = list( /obj/item/stock_parts/radio/transmitter/basic/buildable, - /obj/item/stock_parts/power/apc/buildable + /obj/item/stock_parts/power/apc ) /decl/stock_part_preset/radio/basic_transmitter/meter diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm index 4c0fd9f11c86..3de7c00f4368 100644 --- a/code/game/machinery/atmoalter/portable_atmospherics.dm +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -2,23 +2,29 @@ name = "atmoalter" use_power = POWER_USE_OFF construct_state = /decl/machine_construction/default/panel_closed + atom_flags = ATOM_FLAG_CLIMBABLE var/datum/gas_mixture/air_contents = new - - var/obj/machinery/atmospherics/portables_connector/connected_port var/obj/item/tank/holding - - var/volume = 0 + var/gas_volume = 0 var/destroyed = 0 - var/start_pressure = ONE_ATMOSPHERE - var/maximum_pressure = 90 * ONE_ATMOSPHERE - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + +/obj/machinery/portable_atmospherics/get_single_monetary_worth() + . = ..() + for(var/gas in air_contents?.gas) + var/decl/material/gas_data = GET_DECL(gas) + . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER + . = max(1, round(.)) /obj/machinery/portable_atmospherics/Initialize() ..() - air_contents.volume = volume + air_contents.total_volume = gas_volume air_contents.temperature = T20C + + + set_extension(src, /datum/extension/atmospherics_connection, TRUE, air_contents) + return INITIALIZE_HINT_LATELOAD /obj/machinery/portable_atmospherics/Destroy() @@ -29,12 +35,13 @@ /obj/machinery/portable_atmospherics/LateInitialize() var/obj/machinery/atmospherics/portables_connector/port = locate() in loc if(port) - connect(port) - update_icon() + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) + if(connection) + connection.connect(port) + update_icon() /obj/machinery/portable_atmospherics/Process() - if(!connected_port) //only react when pipe_network will ont it do it for you - //Allow for reactions + if(get_port()) // Only react when pipe_network will not do it for you air_contents.react() else update_icon() @@ -45,90 +52,57 @@ /decl/material/gas/nitrogen = N2STANDARD * MolesForPressure()) /obj/machinery/portable_atmospherics/proc/MolesForPressure(var/target_pressure = start_pressure) - return (target_pressure * air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature) + return (target_pressure * air_contents.total_volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature) /obj/machinery/portable_atmospherics/on_update_icon() return null -/obj/machinery/portable_atmospherics/proc/connect(obj/machinery/atmospherics/portables_connector/new_port) - //Make sure not already connected to something else - if(connected_port || !new_port || new_port.connected_device) - return 0 - - //Make sure are close enough for a valid connection - if(new_port.loc != loc) - return 0 - - //Perform the connection - connected_port = new_port - connected_port.connected_device = src - connected_port.on = 1 //Activate port updates +/obj/machinery/portable_atmospherics/proc/get_port() + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) - anchored = 1 //Prevent movement + return connection?.connected_port - //Actually enforce the air sharing - var/datum/pipe_network/network = connected_port.return_network(src) - if(network && !network.gases.Find(air_contents)) - network.gases += air_contents - network.update = 1 +/obj/machinery/portable_atmospherics/proc/connect(obj/machinery/atmospherics/portables_connector/new_port) + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) - return 1 + return connection?.connect(new_port) /obj/machinery/portable_atmospherics/proc/disconnect() - if(!connected_port) - return 0 - - var/datum/pipe_network/network = connected_port.return_network(src) - if(network) - network.gases -= air_contents - - anchored = 0 - - connected_port.connected_device = null - connected_port = null + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) - return 1 + return connection?.disconnect() /obj/machinery/portable_atmospherics/proc/update_connected_network() - if(!connected_port) - return - - var/datum/pipe_network/network = connected_port.return_network(src) - if (network) - network.update = 1 - -/obj/machinery/portable_atmospherics/attackby(var/obj/item/W, var/mob/user) - if ((istype(W, /obj/item/tank) && !( src.destroyed ))) - if (src.holding) - return - if(!user.unEquip(W, src)) - return - src.holding = W + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) + connection?.update_connected_network() + +/obj/machinery/portable_atmospherics/attackby(var/obj/item/used_item, var/mob/user) + if ((istype(used_item, /obj/item/tank) && !destroyed)) + if (holding) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + holding = used_item update_icon() - return + return TRUE - else if(isWrench(W) && !panel_open) - if(connected_port) - disconnect() - to_chat(user, "You disconnect \the [src] from the port.") + else if(IS_WRENCH(used_item) && !panel_open) + if(disconnect()) + to_chat(user, SPAN_NOTICE("You disconnect \the [src] from the port.")) update_icon() - return - else - var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector/) in loc - if(possible_port) - if(connect(possible_port)) - to_chat(user, "You connect \the [src] to the port.") - update_icon() - return - else - to_chat(user, "\The [src] failed to connect to the port.") - return - else - to_chat(user, "Nothing happens.") - return ..() - - else if (istype(W, /obj/item/scanner/gas)) - return + return TRUE + var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector) in loc + if(possible_port) + if(connect(possible_port)) + to_chat(user, SPAN_NOTICE("You connect \the [src] to the port.")) + update_icon() + return TRUE + to_chat(user, SPAN_NOTICE("\The [src] failed to connect to the port.")) + return TRUE + return ..() + + else if (istype(used_item, /obj/item/scanner/gas)) + return FALSE // allow the scanner's afterattack to run return ..() @@ -152,16 +126,13 @@ return panel_open /obj/machinery/portable_atmospherics/proc/log_open() - if(air_contents.gas.len == 0) - return - - var/gases = "" - for(var/gas in air_contents.gas) - if(gases) - gases += ", [gas]" - else - gases = gas - log_and_message_admins("opened [src.name], containing [gases].") + if(length(air_contents?.gas)) + var/list/gases + for(var/gas in air_contents.gas) + var/decl/material/gasdata = GET_DECL(gas) + LAZYADD(gases, gasdata.gas_name) + if(length(gases)) + log_and_message_admins("opened \the [src], containing [english_list(gases)].") /obj/machinery/portable_atmospherics/powered/dismantle() if(isturf(loc)) diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm index 7d3480caf6cc..492f0b0c26f5 100644 --- a/code/game/machinery/atmoalter/pump.dm +++ b/code/game/machinery/atmoalter/pump.dm @@ -3,29 +3,32 @@ icon = 'icons/obj/atmos.dmi' icon_state = "psiphon:0" - density = 1 + density = TRUE w_class = ITEM_SIZE_NORMAL base_type = /obj/machinery/portable_atmospherics/powered/pump + atom_flags = ATOM_FLAG_CLIMBABLE + movable_flags = MOVABLE_FLAG_WHEELED var/direction_out = 0 //0 = siphoning, 1 = releasing var/target_pressure = ONE_ATMOSPHERE var/pressuremin = 0 - var/pressuremax = 10 * ONE_ATMOSPHERE + var/pressuremax = 10 ATM - volume = 1000 + gas_volume = 1000 power_rating = 7500 //7500 W ~ 10 HP power_losses = 150 /obj/machinery/portable_atmospherics/powered/pump/filled - start_pressure = 90 * ONE_ATMOSPHERE + start_pressure = 90 ATM /obj/machinery/portable_atmospherics/powered/pump/Initialize() . = ..() var/list/air_mix = StandardAirMix() - src.air_contents.adjust_multi(/decl/material/gas/oxygen, air_mix[/decl/material/gas/oxygen], /decl/material/gas/nitrogen, air_mix[/decl/material/gas/nitrogen]) + air_contents.adjust_gas(/decl/material/gas/oxygen, air_mix[/decl/material/gas/oxygen], FALSE) + air_contents.adjust_gas(/decl/material/gas/nitrogen, air_mix[/decl/material/gas/nitrogen]) /obj/machinery/portable_atmospherics/powered/pump/on_update_icon() overlays.Cut() @@ -38,7 +41,7 @@ if(holding) overlays += "siphon-open" - if(connected_port) + if(get_port()) overlays += "siphon-connector" /obj/machinery/portable_atmospherics/powered/pump/emp_act(severity) @@ -73,11 +76,11 @@ var/air_temperature if(direction_out) pressure_delta = target_pressure - environment.return_pressure() - output_volume = environment.volume * environment.group_multiplier + output_volume = environment.total_volume * environment.group_multiplier air_temperature = environment.temperature? environment.temperature : air_contents.temperature else pressure_delta = environment.return_pressure() - target_pressure - output_volume = air_contents.volume * air_contents.group_multiplier + output_volume = air_contents.total_volume * air_contents.group_multiplier air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) @@ -110,7 +113,7 @@ /obj/machinery/portable_atmospherics/powered/pump/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) var/list/data[0] var/obj/item/cell/cell = get_cell() - data["portConnected"] = connected_port ? 1 : 0 + data["portConnected"] = get_port() ? 1 : 0 data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) data["targetpressure"] = round(target_pressure) data["pump_dir"] = direction_out @@ -127,7 +130,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "portpump.tmpl", "Portable Pump", 480, 410, state = GLOB.physical_state) + ui = new(user, src, ui_key, "portpump.tmpl", "Portable Pump", 480, 410, state = global.physical_topic_state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -146,7 +149,7 @@ . = TOPIC_REFRESH if (href_list["pressure_adj"]) var/diff = text2num(href_list["pressure_adj"]) - target_pressure = min(10*ONE_ATMOSPHERE, max(0, target_pressure+diff)) + target_pressure = min(10 ATM, max(0, target_pressure+diff)) . = TOPIC_REFRESH if(.) diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm index 3d7ec026e3f9..80e331893ec2 100644 --- a/code/game/machinery/atmoalter/scrubber.dm +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -1,20 +1,22 @@ /obj/machinery/portable_atmospherics/powered/scrubber - name = "Portable Air Scrubber" + name = "portable air scrubber" icon = 'icons/obj/atmos.dmi' icon_state = "pscrubber:0" - density = 1 + density = TRUE w_class = ITEM_SIZE_NORMAL base_type = /obj/machinery/portable_atmospherics/powered/scrubber + atom_flags = ATOM_FLAG_CLIMBABLE + movable_flags = MOVABLE_FLAG_WHEELED var/volume_rate = 800 - volume = 750 + gas_volume = 750 power_rating = 7500 //7500 W ~ 10 HP power_losses = 150 var/minrate = 0 - var/maxrate = 10 * ONE_ATMOSPHERE + var/maxrate = 10 ATM var/list/scrubbing_gas @@ -22,7 +24,7 @@ . = ..() if(!scrubbing_gas) scrubbing_gas = list() - for(var/g in subtypesof(/decl/material/gas)) + for(var/g in get_filterable_material_types()) if(g != /decl/material/gas/oxygen && g != /decl/material/gas/nitrogen) scrubbing_gas += g @@ -47,7 +49,7 @@ if(holding) overlays += "scrubber-open" - if(connected_port) + if(get_port()) overlays += "scrubber-connector" /obj/machinery/portable_atmospherics/powered/scrubber/Process() @@ -65,7 +67,7 @@ else environment = loc.return_air() - var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles + var/transfer_moles = min(1, volume_rate/environment.total_volume)*environment.total_moles power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, power_rating) @@ -93,7 +95,7 @@ /obj/machinery/portable_atmospherics/powered/scrubber/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) var/list/data[0] var/obj/item/cell/cell = get_cell() - data["portConnected"] = connected_port ? 1 : 0 + data["portConnected"] = get_port() ? 1 : 0 data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) data["rate"] = round(volume_rate) data["minrate"] = round(minrate) @@ -109,7 +111,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "portscrubber.tmpl", "Portable Scrubber", 480, 400, state = GLOB.physical_state) + ui = new(user, src, ui_key, "portscrubber.tmpl", "Portable Scrubber", 480, 400, state = global.physical_topic_state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -126,7 +128,7 @@ . = TOPIC_REFRESH if (href_list["volume_adj"]) var/diff = text2num(href_list["volume_adj"]) - volume_rate = Clamp(volume_rate+diff, minrate, maxrate) + volume_rate = clamp(volume_rate+diff, minrate, maxrate) . = TOPIC_REFRESH if(.) @@ -146,10 +148,10 @@ //Huge scrubber /obj/machinery/portable_atmospherics/powered/scrubber/huge - name = "Huge Air Scrubber" + name = "huge air scrubber" icon_state = "scrubber:0" - anchored = 1 - volume = 50000 + anchored = TRUE + gas_volume = 50000 volume_rate = 5000 base_type = /obj/machinery/portable_atmospherics/powered/scrubber/huge @@ -158,7 +160,7 @@ idle_power_usage = 500 //internal circuitry, friction losses and stuff power_rating = 100000 //100 kW ~ 135 HP - var/global/gid = 1 + var/static/gid = 1 var/id = 0 /obj/machinery/portable_atmospherics/powered/scrubber/huge/Initialize() @@ -170,44 +172,40 @@ name = "[name] (ID [id])" /obj/machinery/portable_atmospherics/powered/scrubber/huge/attack_hand(mob/user) - if((. = ..())) - return - to_chat(user, "You can't directly interact with this machine. Use the scrubber control console.") - return TRUE + . = ..() // Buckling, climbers, grab interactions, component attack_hand; unlikely to return true. + if(!.) + to_chat(user, SPAN_WARNING("You can't directly interact with this machine. Use the scrubber control console.")) + return TRUE /obj/machinery/portable_atmospherics/powered/scrubber/huge/on_update_icon() - overlays.Cut() - - if((use_power == POWER_USE_ACTIVE) && !(stat & (NOPOWER|BROKEN))) - icon_state = "scrubber:1" - else - icon_state = "scrubber:0" + cut_overlays() + icon_state = "scrubber:[!!((use_power == POWER_USE_ACTIVE) && !(stat & (NOPOWER|BROKEN)))]" -/obj/machinery/portable_atmospherics/powered/scrubber/huge/attackby(var/obj/item/I, var/mob/user) - if(isWrench(I)) +/obj/machinery/portable_atmospherics/powered/scrubber/huge/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WRENCH(used_item)) if(use_power == POWER_USE_ACTIVE) to_chat(user, "Turn \the [src] off first!") - return + return TRUE anchored = !anchored playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) to_chat(user, "You [anchored ? "wrench" : "unwrench"] \the [src].") - return + return TRUE //doesn't hold tanks - if(istype(I, /obj/item/tank)) - return + if(istype(used_item, /obj/item/tank)) + return FALSE return ..() /obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary - name = "Stationary Air Scrubber" + name = "stationary air scrubber" base_type = /obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary -/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary/attackby(var/obj/item/I, var/mob/user) - if(isWrench(I)) +/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WRENCH(used_item)) to_chat(user, "The bolts are too tight for you to unscrew!") - return + return TRUE return ..() \ No newline at end of file diff --git a/code/game/machinery/biogenerator.dm b/code/game/machinery/biogenerator.dm index 648bdd6307da..59ef63bfc7c1 100644 --- a/code/game/machinery/biogenerator.dm +++ b/code/game/machinery/biogenerator.dm @@ -5,57 +5,63 @@ #define BG_EMPTY 4 /obj/machinery/biogenerator - name = "Biogenerator" + name = "biogenerator" desc = "" icon = 'icons/obj/biogenerator.dmi' icon_state = "biogen-stand" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 40 base_type = /obj/machinery/biogenerator construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 + chem_volume = 1000 + var/processing = 0 var/obj/item/chems/glass/beaker = null var/points = 0 var/state = BG_READY - var/denied = 0 var/build_eff = 1 var/eat_eff = 1 var/ingredients = 0 //How many processable ingredients are stored inside. var/capacity = 10 //How many ingredients can we store? var/list/products = list( "Food" = list( - /obj/item/chems/food/drinks/milk/smallcarton = 30, - /obj/item/chems/food/drinks/milk = 50, - /obj/item/chems/food/snacks/meat/syntiflesh = 50, - /obj/item/storage/fancy/egg_box = 300), + /obj/item/chems/drinks/milk/smallcarton = 30, + /obj/item/chems/drinks/milk = 50, + /obj/item/food/butchery/meat/syntiflesh = 50, + /obj/item/box/fancy/egg_box = 300), "Nutrients" = list( /obj/item/chems/glass/bottle/eznutrient = 60, /obj/item/chems/glass/bottle/left4zed = 120, /obj/item/chems/glass/bottle/robustharvest = 120), "Leather" = list( - /obj/item/storage/wallet/leather = 100, + /obj/item/wallet/leather = 100, /obj/item/clothing/gloves/thick/botany = 250, - /obj/item/storage/belt/utility = 300, - /obj/item/storage/backpack/satchel = 400, - /obj/item/storage/bag/cash = 400, + /obj/item/belt/utility = 300, + /obj/item/backpack/satchel = 400, + /obj/item/bag/cash = 400, /obj/item/clothing/shoes/workboots = 400, /obj/item/clothing/shoes/craftable = 400, /obj/item/clothing/shoes/dress = 400, /obj/item/clothing/suit/leathercoat = 500, - /obj/item/clothing/suit/storage/toggle/brown_jacket = 500, - /obj/item/clothing/suit/storage/toggle/bomber = 500, - /obj/item/clothing/suit/storage/hooded/wintercoat = 500)) + /obj/item/clothing/suit/jacket/brown = 500, + /obj/item/clothing/suit/jacket/bomber = 500, + /obj/item/clothing/suit/jacket/winter = 500, + /obj/item/stack/material/bolt/mapped/cloth/ten = 300, + /obj/item/stack/material/bolt/mapped/cloth = 30, + /obj/item/stack/material/skin/mapped/leather/ten = 300, + /obj/item/stack/material/skin/mapped/leather = 30, + /obj/item/stack/material/skin/mapped/synthleather =30)) /obj/machinery/biogenerator/Initialize() - create_reagents(1000) beaker = new /obj/item/chems/glass/bottle(src) . = ..() /obj/machinery/biogenerator/on_reagent_change() //When the reagents change, change the icon as well. - update_icon() + if((. = ..())) + update_icon() /obj/machinery/biogenerator/on_update_icon() if(state == BG_NO_BEAKER) @@ -74,46 +80,56 @@ return SPAN_NOTICE("You must turn \the [src] off first.") return ..() -/obj/machinery/biogenerator/attackby(var/obj/item/O, var/mob/user) - if((. = component_attackby(O, user))) - return +/obj/machinery/biogenerator/attackby(var/obj/item/used_item, var/mob/user) + + if(panel_open || IS_SCREWDRIVER(used_item)) + return ..() + if(processing) - to_chat(user, "\The [src] is currently processing.") - if(istype(O, /obj/item/chems/glass)) + if((. = component_attackby(used_item, user))) + return + to_chat(user, SPAN_WARNING("\The [src] is currently processing.")) + return TRUE + + if(istype(used_item, /obj/item/chems/glass)) if(beaker) - to_chat(user, "]The [src] is already loaded.") - return TRUE - else if(user.unEquip(O, src)) - beaker = O + to_chat(user, SPAN_NOTICE("\The [src] is already loaded.")) + else if(user.try_unequip(used_item, src)) + beaker = used_item state = BG_READY updateUsrDialog() - return TRUE + return TRUE if(ingredients >= capacity) - to_chat(user, "\The [src] is already full! Activate it.") - else if(istype(O, /obj/item/storage/plants)) - var/obj/item/storage/plants/P = O - var/hadPlants = 0 - for(var/obj/item/chems/food/snacks/grown/G in P.contents) - hadPlants = 1 - P.remove_from_storage(G, src, 1) //No UI updates until we are all done. + to_chat(user, SPAN_NOTICE("\The [src] is already full! Activate it.")) + return TRUE + + if(used_item.storage) + var/added_plants = FALSE + for(var/obj/item/food/grown/G in used_item.storage.get_contents()) + added_plants = TRUE + used_item.storage.remove_from_storage(user, G, src, TRUE) ingredients++ if(ingredients >= capacity) - to_chat(user, "You fill \the [src] to its capacity.") + to_chat(user, SPAN_NOTICE("You fill \the [src] to its capacity.")) break - P.finish_bulk_removal() //Now do the UI stuff once. - if(!hadPlants) - to_chat(user, "\The [P] has no produce inside.") + used_item.storage.finish_bulk_removal() //Now do the UI stuff once. + if(!added_plants) + to_chat(user, SPAN_WARNING("\The [used_item] has no produce inside.")) else if(ingredients < capacity) - to_chat(user, "You empty \the [P] into \the [src].") + to_chat(user, SPAN_NOTICE("You empty \the [used_item] into \the [src].")) + return TRUE + if(!istype(used_item, /obj/item/food/grown)) + to_chat(user, SPAN_WARNING("You cannot put this in \the [src].")) + return TRUE - else if(!istype(O, /obj/item/chems/food/snacks/grown)) - to_chat(user, "You cannot put this in \the [src].") - else if(user.unEquip(O, src)) + if(user.try_unequip(used_item, src)) ingredients++ - to_chat(user, "You put \the [O] in \the [src]") - update_icon() + to_chat(user, SPAN_NOTICE("You put \the [used_item] in \the [src]")) + return TRUE + + return ..() /** * Display the NanoUI window for the vending machine. @@ -124,7 +140,7 @@ user.set_machine(src) var/list/data = list() data["state"] = state - var/name + var/product_name var/cost var/type_name var/path @@ -137,12 +153,11 @@ var/list/listed_products = list() for(var/c_product =1 to current_content.len) path = current_content[c_product] - var/atom/A = path - name = initial(A.name) + product_name = atom_info_repository.get_name_for(path) cost = current_content[path] listed_products.Add(list(list( "product_index" = c_product, - "name" = name, + "name" = product_name, "cost" = cost))) listed_types.Add(list(list( "type_name" = type_name, @@ -157,7 +172,7 @@ /obj/machinery/biogenerator/OnTopic(user, href_list) switch (href_list["action"]) if("activate") - activate() + activate(user) if("detach") if(beaker) beaker.dropInto(src.loc) @@ -183,20 +198,20 @@ ui_interact(user) return TRUE -/obj/machinery/biogenerator/proc/activate() - if (usr.stat) +/obj/machinery/biogenerator/proc/activate(mob/user) + if (user.incapacitated()) return if (stat) //NOPOWER etc return var/S = 0 - for(var/obj/item/chems/food/snacks/grown/I in contents) + for(var/obj/item/food/grown/I in contents) S += 5 ingredients-- var/amt = REAGENT_VOLUME(I.reagents, /decl/material/liquid/nutriment) if(amt < 0.1) points += 1 - else + else points += amt * 10 * eat_eff qdel(I) if(S) @@ -229,5 +244,5 @@ /obj/machinery/biogenerator/RefreshParts() ..() - build_eff = Clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 1, 10) - eat_eff = Clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 1, 10) \ No newline at end of file + build_eff = clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 1, 10) + eat_eff = clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 1, 10) diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm deleted file mode 100644 index 6f09cef6efc6..000000000000 --- a/code/game/machinery/bioprinter.dm +++ /dev/null @@ -1,303 +0,0 @@ -// GENERIC PRINTER - DO NOT USE THIS OBJECT. -// Flesh and robot printers are defined below this object. - -/obj/machinery/organ_printer - name = "organ printer" - desc = "It's a machine that prints organs." - icon = 'icons/obj/surgery.dmi' - icon_state = "bioprinter" - - anchored = 1 - density = 1 - idle_power_usage = 40 - active_power_usage = 300 - construct_state = /decl/machine_construction/default/panel_closed - uncreated_component_parts = null - stat_immune = 0 - - var/stored_matter = 0 - var/max_stored_matter = 0 - var/print_delay = 100 - var/printing - - // These should be subtypes of /obj/item/organ - var/list/products = list() - -/obj/machinery/organ_printer/state_transition(var/decl/machine_construction/default/new_state) - . = ..() - if(istype(new_state)) - updateUsrDialog() - -/obj/machinery/organ_printer/on_update_icon() - overlays.Cut() - if(panel_open) - overlays += "[icon_state]_panel_open" - if(printing) - overlays += "[icon_state]_working" - -/obj/machinery/organ_printer/examine(mob/user) - . = ..() - to_chat(user, SPAN_NOTICE("It is loaded with [stored_matter]/[max_stored_matter] matter units.")) - -/obj/machinery/organ_printer/RefreshParts() - print_delay = initial(print_delay) - print_delay -= 10 * total_component_rating_of_type(/obj/item/stock_parts/manipulator) - print_delay += 10 * number_of_components(/obj/item/stock_parts/manipulator) - print_delay = max(0, print_delay) - - max_stored_matter = 50 * Clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 20) - . = ..() - -/obj/machinery/organ_printer/components_are_accessible(path) - return !printing && ..() - -/obj/machinery/organ_printer/cannot_transition_to(path) - if(printing) - return SPAN_NOTICE("You must wait for \the [src] to finish printing first!") - return ..() - -/obj/machinery/organ_printer/physical_attack_hand(mob/user, var/choice = null) - if(printing) - return - - if(!choice) - choice = input("What would you like to print?") as null|anything in products - - if(!choice || printing || !CanPhysicallyInteract(user)) - return TRUE - - if(!can_print(choice)) - return TRUE - - stored_matter -= products[choice][2] - - update_use_power(POWER_USE_ACTIVE) - printing = 1 - update_icon() - - sleep(print_delay) - - update_use_power(POWER_USE_IDLE) - printing = 0 - update_icon() - - if(!choice || !src || (stat & (BROKEN|NOPOWER))) - return TRUE - - print_organ(choice) - -/obj/machinery/organ_printer/proc/can_print(var/choice) - if(stored_matter < products[choice][2]) - visible_message(SPAN_NOTICE("\The [src] displays a warning: 'Not enough matter. [stored_matter] stored and [products[choice][2]] needed.'")) - return 0 - return 1 - -/obj/machinery/organ_printer/proc/print_organ(var/choice) - var/new_organ = products[choice][1] - var/obj/item/organ/O = new new_organ(get_turf(src)) - O.status |= ORGAN_CUT_AWAY - return O -// END GENERIC PRINTER - -// ROBOT ORGAN PRINTER -/obj/machinery/organ_printer/robot - name = "prosthetic organ fabricator" - desc = "It's a machine that prints prosthetic organs." - icon_state = "roboprinter" - base_type = /obj/machinery/organ_printer/robot - - products = list( - BP_HEART = list(/obj/item/organ/internal/heart, 25), - BP_LUNGS = list(/obj/item/organ/internal/lungs, 25), - BP_KIDNEYS = list(/obj/item/organ/internal/kidneys, 20), - BP_EYES = list(/obj/item/organ/internal/eyes, 20), - BP_LIVER = list(/obj/item/organ/internal/liver, 25), - BP_STOMACH = list(/obj/item/organ/internal/stomach, 25), - BP_L_ARM = list(/obj/item/organ/external/arm, 65), - BP_R_ARM = list(/obj/item/organ/external/arm/right, 65), - BP_L_LEG = list(/obj/item/organ/external/leg, 65), - BP_R_LEG = list(/obj/item/organ/external/leg/right, 65), - BP_L_FOOT = list(/obj/item/organ/external/foot, 40), - BP_R_FOOT = list(/obj/item/organ/external/foot/right, 40), - BP_L_HAND = list(/obj/item/organ/external/hand, 40), - BP_R_HAND = list(/obj/item/organ/external/hand/right, 40), - BP_CELL = list(/obj/item/organ/internal/cell, 25) - ) - - var/matter_amount_per_sheet = 10 - var/matter_type = /decl/material/solid/metal/steel - -/obj/machinery/organ_printer/robot/mapped/Initialize() - . = ..() - stored_matter = max_stored_matter - -/obj/machinery/organ_printer/robot/dismantle() - if(stored_matter >= matter_amount_per_sheet) - new /obj/item/stack/material/steel(get_turf(src), Floor(stored_matter/matter_amount_per_sheet)) - return ..() - -/obj/machinery/organ_printer/robot/print_organ(var/choice) - var/obj/item/organ/O = ..() - O.robotize() - O.status |= ORGAN_CUT_AWAY // robotize() resets status to 0 - visible_message(SPAN_INFO("\The [src] churns for a moment, then spits out \a [O].")) - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) - return O - -/obj/machinery/organ_printer/robot/attackby(var/obj/item/W, var/mob/user) - var/add_matter = 0 - var/object_name = "[W]" - - if(istype(W, /obj/item/stack/material) && W.get_material_type() == matter_type) - if((max_stored_matter-stored_matter) >= matter_amount_per_sheet) - var/obj/item/stack/S = W - var/space_left = max_stored_matter - stored_matter - var/sheets_to_take = min(S.amount, Floor(space_left/matter_amount_per_sheet)) - if(sheets_to_take > 0) - add_matter = min(max_stored_matter - stored_matter, sheets_to_take*matter_amount_per_sheet) - S.use(sheets_to_take) - - else if(istype(W,/obj/item/organ)) - var/obj/item/organ/O = W - if((O.organ_tag in products) && istype(O, products[O.organ_tag][1])) - if(!BP_IS_PROSTHETIC(O)) - to_chat(user, SPAN_WARNING("\The [src] only accepts prosthetic organs.")) - return - var/recycle_worth = Floor(products[O.organ_tag][2] * 0.5) - if((max_stored_matter-stored_matter) >= recycle_worth) - add_matter = recycle_worth - qdel(O) - else - to_chat(user, SPAN_WARNING("\The [src] does not know how to recycle \the [O].")) - return - - stored_matter += add_matter - - if(add_matter) - to_chat(user, SPAN_INFO("\The [src] processes \the [object_name]. Levels of stored matter now: [stored_matter]")) - else - to_chat(user, SPAN_WARNING("\The [src] is too full.")) - - return ..() -// END ROBOT ORGAN PRINTER - -// FLESH ORGAN PRINTER -/obj/machinery/organ_printer/flesh - name = "bioprinter" - desc = "It's a machine that prints replacement organs." - icon_state = "bioprinter" - base_type = /obj/machinery/organ_printer/flesh - // null amount means it will calculate the cost based on get_organ_cost() - var/list/amount_list = list( - /obj/item/chems/food/snacks/meat = 50, - /obj/item/chems/food/snacks/rawcutlet = 15, - /obj/item/organ = null - ) - var/datum/dna/loaded_dna_datum - var/datum/species/loaded_species //For quick refrencing - -/obj/machinery/organ_printer/flesh/mapped/Initialize() - . = ..() - stored_matter = max_stored_matter - -/obj/machinery/organ_printer/flesh/dismantle() - var/turf/T = get_turf(src) - if(T) - while(stored_matter >= amount_list[/obj/item/chems/food/snacks/meat]) - stored_matter -= amount_list[/obj/item/chems/food/snacks/meat] - new /obj/item/chems/food/snacks/meat(T) - return ..() - -/obj/machinery/organ_printer/flesh/print_organ(var/choice) - var/obj/item/organ/O - var/new_organ - if(loaded_species.has_organ[choice]) - new_organ = loaded_species.has_organ[choice] - else if(loaded_species.has_limbs[choice]) - new_organ = loaded_species.has_limbs[choice]["path"] - if(new_organ) - O = new new_organ(get_turf(src), loaded_dna_datum) - O.status |= ORGAN_CUT_AWAY - else - O = ..() - visible_message(SPAN_INFO("\The [src] churns for a moment, injects its stored DNA into the biomass, then spits out \a [O].")) - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) - return O - -/obj/machinery/organ_printer/flesh/physical_attack_hand(mob/user) - if(!loaded_dna_datum || !loaded_species) - visible_message(SPAN_INFO("\The [src] displays a warning: 'No DNA saved. Insert a blood sample.'")) - return - - var/choice = input("What [loaded_species.name] organ would you like to print?") as null|anything in products - - if(!choice) - return - - ..(user, choice) - -/obj/machinery/organ_printer/flesh/attackby(obj/item/W, mob/user) - // Load with matter for printing. - for(var/path in amount_list) - if(istype(W, path)) - if(max_stored_matter == stored_matter) - to_chat(user, SPAN_WARNING("\The [src] is too full.")) - return - if(!user.unEquip(W)) - return - var/add_matter = amount_list[path] ? amount_list[path] : 0.5*get_organ_cost(W) - stored_matter += min(add_matter, max_stored_matter - stored_matter) - to_chat(user, SPAN_INFO("\The [src] processes \the [W]. Levels of stored biomass now: [stored_matter]")) - qdel(W) - - // DNA sample from syringe. - if(istype(W,/obj/item/chems/syringe)) - var/obj/item/chems/syringe/S = W - if(REAGENT_VOLUME(S.reagents, /decl/material/liquid/blood)) - var/loaded_dna = REAGENT_DATA(S.reagents, /decl/material/liquid/blood) - if(islist(loaded_dna)) - var/weakref/R = loaded_dna["donor"] - var/mob/living/carbon/human/H = R.resolve() - if(H && istype(H) && H.species && H.dna) - loaded_species = H.species - loaded_dna_datum = H.dna && H.dna.Clone() - products = get_possible_products() - to_chat(user, SPAN_INFO("You inject the blood sample into the bioprinter.")) - return TRUE - to_chat(user, SPAN_NOTICE("\The [src] displays an error: no viable blood sample could be obtained from \the [W].")) - return ..() - -/obj/machinery/organ_printer/flesh/proc/get_possible_products() - . = list() - if(!loaded_species) - return - var/list/organs = list() - for(var/organ in loaded_species.has_organ) - organs += loaded_species.has_organ[organ] - for(var/organ in loaded_species.has_limbs) - organs += loaded_species.has_limbs[organ]["path"] - for(var/organ in organs) - var/obj/item/organ/O = organ - if(check_printable(organ)) - .[initial(O.organ_tag)] = list(O, get_organ_cost(O)) - -/obj/machinery/organ_printer/flesh/proc/get_organ_cost(var/obj/item/organ/O) - . = initial(O.print_cost) - if(!.) - . = round(0.75 * initial(O.max_damage)) - -/obj/machinery/organ_printer/flesh/proc/check_printable(var/organtype) - var/obj/item/organ/O = organtype - if(!initial(O.can_be_printed)) - return FALSE - if(initial(O.vital)) - return FALSE - if(initial(O.status) & ORGAN_PROSTHETIC) - return FALSE - if(ispath(organtype, /obj/item/organ/external)) - var/obj/item/organ/external/E = organtype - if(initial(E.limb_flags) & ORGAN_FLAG_HEALS_OVERKILL) - return FALSE - return TRUE - -// END FLESH ORGAN PRINTER diff --git a/code/game/machinery/bodyscanner.dm b/code/game/machinery/bodyscanner.dm index 7d848bb2949a..6998f0f78519 100644 --- a/code/game/machinery/bodyscanner.dm +++ b/code/game/machinery/bodyscanner.dm @@ -1,22 +1,28 @@ // Pretty much everything here is stolen from the dna scanner FYI /obj/machinery/bodyscanner - var/mob/living/carbon/human/occupant + var/mob/living/human/occupant var/locked - name = "Body Scanner" + name = "body scanner" icon = 'icons/obj/Cryogenic2.dmi' icon_state = "body_scanner_0" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 60 active_power_usage = 10000 //10 kW. It's a big all-body scanner. construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 + var/open_sound = 'sound/machines/podopen.ogg' + var/close_sound = 'sound/machines/podclose.ogg' -/obj/machinery/bodyscanner/examine(mob/user) +// Don't dump out the occupant! +/obj/machinery/bodyscanner/proc/dump_obj_contents() + for(var/obj/O in get_contained_external_atoms()) + O.dropInto(loc) + +/obj/machinery/bodyscanner/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if (occupant && user.Adjacent(src)) - occupant.examine(arglist(args)) + occupant.get_examine_strings(user, distance, infix, suffix) /obj/machinery/bodyscanner/relaymove(mob/user) ..() @@ -42,39 +48,34 @@ usr.client.perspective = EYE_PERSPECTIVE usr.client.eye = src -/obj/machinery/bodyscanner/proc/drop_contents() - for(var/obj/O in (contents - component_parts)) - O.dropInto(loc) - /obj/machinery/bodyscanner/proc/go_out() if ((!( src.occupant ) || src.locked)) return - drop_contents() + dump_obj_contents() if (src.occupant.client) src.occupant.client.eye = src.occupant.client.mob src.occupant.client.perspective = MOB_PERSPECTIVE src.occupant.dropInto(loc) src.occupant = null update_use_power(POWER_USE_IDLE) - update_icon() SetName(initial(name)) + if(open_sound) + playsound(src, open_sound, 40) /obj/machinery/bodyscanner/state_transition(var/decl/machine_construction/default/new_state) . = ..() if(istype(new_state)) updateUsrDialog() -/obj/machinery/bodyscanner/attackby(obj/item/grab/G, user) - if(istype(G)) - var/mob/M = G.get_affecting_mob() - if(!M || !user_can_move_target_inside(M, user)) - return - qdel(G) +/obj/machinery/bodyscanner/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim) && user_can_move_target_inside(victim, user)) + qdel(grab) return TRUE return ..() /obj/machinery/bodyscanner/proc/user_can_move_target_inside(var/mob/target, var/mob/user) - if(!istype(user) || !istype(target)) + if(!istype(user) || !istype(target) || target.anchored) return FALSE if(occupant) to_chat(user, "The scanner is already occupied!") @@ -90,11 +91,12 @@ src.occupant = target update_use_power(POWER_USE_ACTIVE) - update_icon() - drop_contents() + dump_obj_contents() SetName("[name] ([occupant])") src.add_fingerprint(user) + if(close_sound) + playsound(src, close_sound, 40) return TRUE /obj/machinery/bodyscanner/on_update_icon() @@ -106,19 +108,18 @@ icon_state = "body_scanner_2" //Like grap-put, but for mouse-drop. -/obj/machinery/bodyscanner/MouseDrop_T(var/mob/target, var/mob/user) - if(!CanMouseDrop(target, user) || !istype(target)) - return FALSE - user.visible_message("\The [user] begins placing \the [target] into \the [src].", "You start placing \the [target] into \the [src].") - if(!do_after(user, 30, src)) - return - if(!user_can_move_target_inside(target, user)) - return - -/obj/machinery/bodyscanner/explosion_act(severity) +/obj/machinery/bodyscanner/receive_mouse_drop(atom/dropping, mob/user, params) . = ..() - if(. && !QDELETED(src) && prob(severity == 1 ? 100 : (100 - (25 * severity)))) - physically_destroyed(src) + if(!. && isliving(dropping)) + var/mob/living/M = dropping + if(M.anchored) + return FALSE + user.visible_message( \ + SPAN_NOTICE("\The [user] begins placing \the [dropping] into \the [src]."), \ + SPAN_NOTICE("You start placing \the [dropping] into \the [src].")) + if(do_after(user, 30, src)) + user_can_move_target_inside(dropping, user) + return TRUE /obj/machinery/bodyscanner/Destroy() if(occupant) diff --git a/code/game/machinery/bodyscanner_console.dm b/code/game/machinery/bodyscanner_console.dm index 71ef39d3a68d..f8864ab712e3 100644 --- a/code/game/machinery/bodyscanner_console.dm +++ b/code/game/machinery/bodyscanner_console.dm @@ -1,18 +1,16 @@ /obj/machinery/body_scanconsole - var/obj/machinery/bodyscanner/connected + var/obj/machinery/bodyscanner/connected var/stored_scan_subject name = "Body Scanner Console" icon = 'icons/obj/Cryogenic2.dmi' icon_state = "body_scannerconsole" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 - var/list/display_tags = list() var/list/connected_displays = list() var/list/data = list() - var/scan_data /obj/machinery/body_scanconsole/Initialize() . = ..() @@ -20,38 +18,33 @@ /obj/machinery/body_scanconsole/on_update_icon() if(stat & (BROKEN | NOPOWER)) - icon_state = "body_scannerconsole-p" + icon_state = "body_scannerconsole-p" else icon_state = initial(icon_state) -/obj/machinery/body_scanconsole/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)))) - qdel(src) - /obj/machinery/body_scanconsole/proc/FindScanner() - for(var/D in GLOB.cardinal) + for(var/D in global.cardinal) src.connected = locate(/obj/machinery/bodyscanner, get_step(src, D)) if(src.connected) break - GLOB.destroyed_event.register(connected, src, .proc/unlink_scanner) + events_repository.register(/decl/observ/destroyed, connected, src, PROC_REF(unlink_scanner)) -/obj/machinery/body_scanconsole/proc/unlink_scanner(var/obj/machinery/bodyscanner/scanner) - GLOB.destroyed_event.unregister(scanner, src, .proc/unlink_scanner) +/obj/machinery/body_scanconsole/proc/unlink_scanner(var/obj/machinery/bodyscanner/scanner) + events_repository.unregister(/decl/observ/destroyed, scanner, src, PROC_REF(unlink_scanner)) connected = null /obj/machinery/body_scanconsole/proc/FindDisplays() for(var/obj/machinery/body_scan_display/D in SSmachines.machinery) - if(D.tag in display_tags) + if(D.id_tag == connected.id_tag) connected_displays += D - GLOB.destroyed_event.register(D, src, .proc/remove_display) + events_repository.register(/decl/observ/destroyed, D, src, PROC_REF(remove_display)) return !!connected_displays.len /obj/machinery/body_scanconsole/attack_hand(mob/user) - if(!connected || (connected.stat & (NOPOWER|BROKEN))) - to_chat(user, "This console is not connected to a functioning body scanner.") - return TRUE - return ..() + if(connected && !(connected.stat & (NOPOWER|BROKEN))) + return ..() + to_chat(user, "This console is not connected to a functioning body scanner.") + return TRUE /obj/machinery/body_scanconsole/interface_interact(mob/user) ui_interact(user) @@ -90,10 +83,10 @@ /obj/machinery/body_scanconsole/OnTopic(mob/user, href_list) if(href_list["scan"]) if (!connected.occupant) - to_chat(user, "\icon[src]The body scanner is empty.") + to_chat(user, "[html_icon(src)]The body scanner is empty.") return TOPIC_REFRESH if (!istype(connected.occupant)) - to_chat(user, "\icon[src]The body scanner cannot scan that lifeform.") + to_chat(user, "[html_icon(src)]The body scanner cannot scan that lifeform.") return TOPIC_REFRESH data["printEnabled"] = TRUE data["eraseEnabled"] = TRUE @@ -102,7 +95,7 @@ data["html_scan_header"] = display_medical_data_header(data["scan"], user.get_skill_value(SKILL_MEDICAL)) data["html_scan_health"] = display_medical_data_health(data["scan"], user.get_skill_value(SKILL_MEDICAL)) data["html_scan_body"] = display_medical_data_body(data["scan"], user.get_skill_value(SKILL_MEDICAL)) - + stored_scan_subject = connected.occupant user.visible_message("\The [user] performs a scan of \the [connected.occupant] using \the [connected].") playsound(connected.loc, 'sound/machines/medbayscanner.ogg', 50) @@ -110,15 +103,15 @@ if (href_list["print"]) if (!data["scan"]) - to_chat(user, "\icon[src]Error: No scan stored.") + to_chat(user, "[html_icon(src)]Error: No scan stored.") return TOPIC_REFRESH var/list/scan = data["scan"] - new /obj/item/paper/bodyscan(loc, "Printout error.", "Body scan report - [stored_scan_subject]", scan.Copy()) + new /obj/item/paper/bodyscan(loc, null, "Printout error.", "Body scan report - [stored_scan_subject]", scan.Copy()) return TOPIC_REFRESH - if(href_list["push"]) + if(href_list["push"]) if(!connected_displays.len && !FindDisplays()) - to_chat(user, "\icon[src]Error: No configured displays detected.") + to_chat(user, "[html_icon(src)]Error: No configured displays detected.") return TOPIC_REFRESH for(var/obj/machinery/body_scan_display/D in connected_displays) D.add_new_scan(data["scan"]) @@ -141,7 +134,7 @@ /obj/machinery/body_scanconsole/proc/remove_display(var/obj/machinery/body_scan_display/display) connected_displays -= display - GLOB.destroyed_event.unregister(display, src, .proc/remove_display) + events_repository.unregister(/decl/observ/destroyed, display, src, PROC_REF(remove_display)) /obj/machinery/body_scanconsole/Destroy() . = ..() diff --git a/code/game/machinery/bodyscanner_display.dm b/code/game/machinery/bodyscanner_display.dm index 9107ca349f83..2fadc8e44e9a 100644 --- a/code/game/machinery/bodyscanner_display.dm +++ b/code/game/machinery/bodyscanner_display.dm @@ -1,29 +1,43 @@ /obj/machinery/body_scan_display - name = "Body Scan Display" + name = "body scan display" desc = "A wall-mounted display linked to a body scanner." icon = 'icons/obj/modular_computers/modular_telescreen.dmi' - icon_state = "operating" - var/icon_state_unpowered = "telescreen" + icon_state = "telescreen" anchored = TRUE - density = 0 + density = FALSE idle_power_usage = 75 active_power_usage = 300 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 w_class = ITEM_SIZE_HUGE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' var/list/bodyscans = list() var/selected = 0 /obj/machinery/body_scan_display/proc/add_new_scan(var/list/scan) bodyscans += list(scan.Copy()) updateUsrDialog() + queue_icon_update() + +/obj/machinery/body_scan_display/on_update_icon() + . = ..() + cut_overlays() + if(!(stat & (BROKEN|NOPOWER))) + if (selected != 0) + add_overlay("operating") + else if (bodyscans.len > 0) + add_overlay("menu") + else + add_overlay("standby") /obj/machinery/body_scan_display/OnTopic(mob/user, href_list) if(href_list["view"]) var/selection = text2num(href_list["view"]) if(is_valid_index(selection, bodyscans)) selected = selection + queue_icon_update() return TOPIC_REFRESH return TOPIC_HANDLED if(href_list["delete"]) @@ -32,6 +46,7 @@ return TOPIC_HANDLED if(selected == selection) selected = 0 + queue_icon_update() else if(selected > selection) selected-- bodyscans -= list(bodyscans[selection]) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 4e8006acca9a..eda811c59e8f 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -3,24 +3,28 @@ icon = 'icons/obj/objects.dmi' icon_state = "launcherbtt" desc = "A remote control switch for something." - anchored = 1 + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED layer = ABOVE_WINDOW_LAYER power_channel = ENVIRON idle_power_usage = 10 public_variables = list( /decl/public_access/public_variable/button_active, + /decl/public_access/public_variable/inv_button_active, /decl/public_access/public_variable/button_state, /decl/public_access/public_variable/input_toggle ) public_methods = list(/decl/public_access/public_method/toggle_input_toggle) stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/button = 1) uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable, - /obj/item/stock_parts/radio/transmitter/basic/buildable + /obj/item/stock_parts/power/apc = 1, + /obj/item/stock_parts/radio/transmitter/basic/buildable = 1 ) base_type = /obj/machinery/button/buildable construct_state = /decl/machine_construction/wall_frame/panel_closed/simple frame_type = /obj/item/frame/button + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":30}, "EAST":{"x":-24}, "WEST":{"x":24}}' var/active = FALSE var/operating = FALSE @@ -28,21 +32,22 @@ var/cooldown = 1 SECOND /obj/machinery/button/buildable - uncreated_component_parts = null + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc = 1, + ) /obj/machinery/button/Initialize() . = ..() update_icon() -/obj/machinery/button/attackby(obj/item/W, mob/user) - if(!(. = component_attackby(W, user))) - return attack_hand(user) +/obj/machinery/button/attackby(obj/item/used_item, mob/user) + if(!(. = component_attackby(used_item, user))) + return attack_hand_with_interaction_checks(user) /obj/machinery/button/interface_interact(user) if(!CanInteract(user, DefaultTopicState())) return FALSE - if(istype(user, /mob/living/carbon)) - playsound(src, "button", 60) + playsound(src, "button", 60) activate(user) return TRUE @@ -56,7 +61,7 @@ return operating = TRUE - var/decl/public_access/public_variable/variable = decls_repository.get_decl(/decl/public_access/public_variable/button_active) + var/decl/public_access/public_variable/variable = GET_DECL(/decl/public_access/public_variable/button_active) state = !state variable.write_var(src, !active) use_power_oneoff(500) @@ -72,6 +77,12 @@ else icon_state = "launcherbtt" +//#TODO: Button might want their cases to handle being installed on tables to stay coherent with mapped button on tables? +/obj/machinery/button/update_directional_offset(force = FALSE) + if(!force && (!length(directional_offset) || !is_wall_mounted())) //Check if the button is actually mapped onto a table or something + return + . = ..() + /decl/public_access/public_variable/button_active expected_type = /obj/machinery/button name = "button toggle" @@ -87,6 +98,21 @@ if(.) button.active = new_val +/decl/public_access/public_variable/inv_button_active + expected_type = /obj/machinery/button + name = "inverse button toggle" + desc = "Toggled whenever the button is pressed. Inverse value of button toggle." + can_write = FALSE + has_updates = TRUE + +/decl/public_access/public_variable/inv_button_active/access_var(obj/machinery/button/button) + return !button.active + +/decl/public_access/public_variable/inv_button_active/write_var(obj/machinery/button/button, new_val) + . = ..() + if(.) + button.active = !new_val + // The point here is that button_active just pulses on button press and can't be changed otherwise, while button_state can be changed externally. /decl/public_access/public_variable/button_state expected_type = /obj/machinery/button @@ -94,14 +120,16 @@ desc = "Whether the button is currently in the on state." can_write = TRUE has_updates = FALSE + var_type = VAR_FORMAT_BOOLEAN /decl/public_access/public_variable/button_state/access_var(obj/machinery/button/button) return button.state /decl/public_access/public_variable/button_state/write_var(obj/machinery/button/button, new_val) + new_val = !!new_val . = ..() if(.) - button.state = new_val + button.state = !!new_val /decl/stock_part_preset/radio/basic_transmitter/button transmit_on_change = list("button_active" = /decl/public_access/public_variable/button_active) @@ -119,6 +147,12 @@ /obj/machinery/button/alternate icon = 'icons/obj/machines/button_door.dmi' icon_state = "doorctrl" + frame_type = /obj/item/frame/button/alternate + +/obj/machinery/button/alternate/buildable + uncreated_component_parts = list( + /obj/item/stock_parts/radio/transmitter/basic = 1, + ) /obj/machinery/button/alternate/on_update_icon() if(operating) @@ -147,6 +181,7 @@ /obj/machinery/button/toggle/alternate icon = 'icons/obj/machines/button_door.dmi' icon_state = "doorctrl" + frame_type = /obj/item/frame/button/alternate /obj/machinery/button/toggle/alternate/on_update_icon() if(active) @@ -201,4 +236,13 @@ /decl/stock_part_preset/radio/basic_transmitter/button/atmosia transmit_on_change = list("valve_toggle" = /decl/public_access/public_variable/button_active) - frequency = FUEL_FREQ \ No newline at end of file + frequency = FUEL_FREQ + +// Vent control +/obj/machinery/button/toggle/engine + name = "engine vent control" + stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/button/engine = 1) + +/decl/stock_part_preset/radio/basic_transmitter/button/engine + transmit_on_change = list("power_toggle" = /decl/public_access/public_variable/button_active) + frequency = ATMOS_ENGINE_FREQ diff --git a/code/game/machinery/camera/_camera_device.dm b/code/game/machinery/camera/_camera_device.dm new file mode 100644 index 000000000000..6fa7a539f259 --- /dev/null +++ b/code/game/machinery/camera/_camera_device.dm @@ -0,0 +1,147 @@ +#define MAX_CAMCHAN_TAG_LENGTH 20 + +/datum/extension/network_device/camera + var/list/channels = list(CAMERA_CHANNEL_PUBLIC) // Camera channels for sorting cameras while looking via programs or as an AI. No longer connected to access. + expected_type = /obj/machinery/camera + + var/cameranet_enabled // Whether this camera will act as a source for AI cameranets + var/display_name // The display name for the camera. Unlike the network tag, uniqueness is not enforced, so this can/should be much shorter. + var/requires_connection = TRUE // Whether the camera requires to be connected to its own network to be seen through. Used for television/thunderdome cameras. + var/view_range = 7 + + var/xray_enabled = FALSE + has_commands = TRUE + +/datum/extension/network_device/camera/New(datum/holder, n_id, n_key, r_type, autojoin, list/preset_channels, camera_name, camnet_enabled = TRUE, req_connection = TRUE) + if(length(preset_channels)) + channels = preset_channels.Copy() + . = ..() + cameranet_enabled = camnet_enabled + requires_connection = req_connection + camera_repository.add_camera_to_channels(src, channels) + display_name = camera_name + +/datum/extension/network_device/camera/post_construction() + . = ..() + if(cameranet_enabled) + cameranet.add_source(holder) + +/datum/extension/network_device/camera/Destroy() + camera_repository.remove_camera_from_channels(src, channels) + . = ..() + +/datum/extension/network_device/camera/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) + var/data = ui_data(user) + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + var/atom/A = holder + ui = new(user, src, ui_key, "camera_settings.tmpl", capitalize(A.name), 500, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/extension/network_device/camera/ui_data(mob/user, ui_key) + . = ..() + .["channels"] = channels.Copy() + +/datum/extension/network_device/camera/Topic(href, href_list) + . = ..() + if(.) + return + var/mob/user = usr + if(!can_interact(user)) + return TOPIC_NOACTION + if(href_list["add_channel"]) + var/cam_channel = sanitize(input(usr, "Enter the camera channel tag. Adding the channel \"[CAMERA_CHANNEL_TELEVISION]\" will enable broadband broadcast to all receivers in the local area:", "Enter camera channel tag") as text|null) + if(length(cam_channel) && can_interact(user)) + if(length(cam_channel) > MAX_CAMCHAN_TAG_LENGTH) + to_chat(user, SPAN_WARNING("Maximum camera channel tag length is 20 characters.")) + return TOPIC_NOACTION + add_channels(cam_channel) + return TOPIC_REFRESH + if(href_list["remove_channel"]) + remove_channels(href_list["remove_channel"]) + return TOPIC_REFRESH + +/datum/extension/network_device/camera/proc/is_functional() + var/obj/machinery/camera/C = holder + if(!istype(holder)) + CRASH("Camera device was created with invalid holder: [holder]!") + return C.can_use() + +/datum/extension/network_device/camera/proc/can_see() + var/list/see = null + var/turf/pos = get_turf(holder) + if(!pos) + return list() + + if(xray_enabled) + see = range(view_range, pos) + else + see = hear(view_range, pos) + return see + +/datum/extension/network_device/camera/proc/show_paper(obj/item/paper/shown, mob/user) + if(cameranet_enabled && is_functional() && isliving(user)) + var/mob/living/U = user + var/itemname = shown.name + var/info = shown.info + to_chat(U, SPAN_NOTICE("You hold \a [itemname] up to the camera ...")) + for(var/mob/living/silicon/ai/O in global.living_mob_list_) + if(!O.client) + continue + if(U.name == "Unknown") + to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...") + else + to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...") + show_browser(O, text("[][]", itemname, info), text("window=[]", itemname)) + return TRUE + +/datum/extension/network_device/camera/proc/add_channels(list/added_channels) + if(!islist(added_channels)) + added_channels = list(added_channels) + added_channels -= channels + channels += added_channels + var/datum/computer_network/net = get_network() + if(net) + net.add_camera_to_channels(src, added_channels) + camera_repository.add_camera_to_channels(src, added_channels) + +/datum/extension/network_device/camera/proc/remove_channels(list/removed_channels) + if(!islist(removed_channels)) + removed_channels = list(removed_channels) + removed_channels &= channels + channels -= removed_channels + var/datum/computer_network/net = get_network() + if(net) + net.remove_camera_from_channels(src, removed_channels) + camera_repository.remove_camera_from_channels(src, removed_channels) + +/datum/extension/network_device/camera/proc/set_view_range(var/new_range) + if(view_range != new_range) + view_range = new_range + if(cameranet_enabled) + cameranet.update_visibility(holder, 0) + +/datum/extension/network_device/camera/proc/nano_structure() + var/cam[0] + cam["display_name"] = sanitize(display_name) + cam["network_tag"] = network_tag + cam["deact"] = !is_functional() + cam["x"] = get_x(holder) + cam["y"] = get_y(holder) + cam["z"] = get_z(holder) + return cam + +/datum/extension/network_device/camera/apply_visual(mob/M) + return holder.apply_visual(M) + +/datum/extension/network_device/camera/remove_visual(mob/M) + return holder.remove_visual(M) + +/datum/extension/network_device/camera/proc/check_eye(mob/user) + if(!is_functional()) + return -1 + if(xray_enabled) + return SEE_TURFS|SEE_MOBS|SEE_OBJS + return 0 \ No newline at end of file diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 02832f3efe97..8d28f55a3c86 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -1,58 +1,64 @@ /obj/machinery/camera name = "security camera" - desc = "It's used to monitor rooms." + desc = "A classic security camera used to monitor rooms. It's directly wired to the local area's alarm system." icon = 'icons/obj/monitors.dmi' icon_state = "camera" use_power = POWER_USE_ACTIVE idle_power_usage = 5 active_power_usage = 10 layer = CAMERA_LAYER + anchored = TRUE + movable_flags = MOVABLE_FLAG_PROXMOVE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"SOUTH":{"y":21}, "EAST":{"x":-10}, "WEST":{"x":10}}' + base_type = /obj/machinery/camera + uncreated_component_parts = null + construct_state = /decl/machine_construction/wall_frame/panel_closed + frame_type = /obj/item/frame/camera + //Deny all by default, so mapped presets can't be messed with during a network outage. + stock_part_presets = list( + /decl/stock_part_preset/network_lock/camera, + ) + var/list/preset_channels + var/cameranet_enabled = TRUE + var/requires_connection = TRUE + + var/motion_sensor = FALSE + var/list/motionTargets = list() + var/detectTime = 0 + var/alarm_delay = 100 // Don't forget, there's another 10 seconds in queueAlarm() - var/list/network = list(NETWORK_EXODUS) var/c_tag = null - var/c_tag_order = 999 - var/number = 0 //camera number in area var/status = 1 - anchored = 1.0 - var/invuln = null - var/bugged = 0 - var/obj/item/camera_assembly/assembly = null + var/cut_power = FALSE - var/toughness = 5 //sorta fragile + var/toughness = 5 // Attack force or throw force required before damage is dealt. // WIRES wires = /datum/wires/camera //OTHER - - var/view_range = 7 + var/long_range = 7 var/short_range = 2 var/light_disabled = 0 var/alarm_on = 0 - var/busy = 0 - var/on_open_network = 0 + var/emp_timer_id = null + + /// The threshold that installed scanning modules need to met or exceed in order for the camera to see through walls. + var/const/XRAY_THRESHOLD = 2 - var/affected_by_emp_until = 0 + /// The threshold that installed capacitors need to met or exceed in order for the camera to be immunie to EMP. + var/const/EMP_PROOF_THRESHOLD = 2 -/obj/machinery/camera/examine(mob/user) +/obj/machinery/camera/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(stat & BROKEN) - to_chat(user, "It is completely demolished.") - -/obj/machinery/camera/malf_upgrade(var/mob/living/silicon/ai/user) - ..() - malf_upgraded = 1 - - upgradeEmpProof() - upgradeXRay() + . += SPAN_WARNING("It is completely demolished.") - to_chat(user, "\The [src] has been upgraded. It now has X-Ray capability and EMP resistance.") - return 1 - -/obj/machinery/camera/apply_visual(mob/living/carbon/human/M) - if(!M.client) +/obj/machinery/camera/apply_visual(mob/living/human/M) + if(!M.client || !istype(M)) return M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed) M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline) @@ -60,8 +66,8 @@ M.machine_visual = src return 1 -/obj/machinery/camera/remove_visual(mob/living/carbon/human/M) - if(!M.client) +/obj/machinery/camera/remove_visual(mob/living/human/M) + if(!M.client || !istype(M)) return M.clear_fullscreen("fishbed",0) M.clear_fullscreen("scanlines") @@ -71,235 +77,227 @@ /obj/machinery/camera/Initialize() . = ..() - - assembly = new(src) - assembly.state = 4 - update_icon() - - /* // Use this to look for cameras that have the same c_tag. - for(var/obj/machinery/camera/C in cameranet.cameras) - var/list/tempnetwork = C.network&src.network - if(C != src && C.c_tag == src.c_tag && tempnetwork.len) - to_world_log("[src.c_tag] [src.x] [src.y] [src.z] conflicts with [C.c_tag] [C.x] [C.y] [C.z]") - */ - if(!src.network || src.network.len < 1) - if(loc) - error("[src.name] in [get_area(src)] (x:[src.x] y:[src.y] z:[src.z] has errored. [src.network?"Empty network list":"Null network list"]") - else - error("[src.name] in [get_area(src)]has errored. [src.network?"Empty network list":"Null network list"]") - ASSERT(src.network) - ASSERT(src.network.len > 0) - if(!c_tag) - number = 1 var/area/A = get_area(src) - if(A) - for(var/obj/machinery/camera/C in A) - if(C == src) continue - if(C.number) - number = max(number, C.number+1) - c_tag = "[A.name][number == 1 ? "" : " #[number]"]" - invalidateCameraCache() + if(isturf(loc) && A) + var/suffix = uniqueness_repository.Generate(/datum/uniqueness_generator/id_sequential, "c_tag [A.proper_name]", 1) // unlike sequential_id, starts at 1 instead of 100 + if(suffix == 1) + suffix = null + c_tag = "[A.proper_name][suffix ? " [suffix]" : null]" + // Add a default c_tag in case the camera has been placed in an invalid location or inside another object. + c_tag ||= "Security Camera - [random_id(/obj/machinery/camera, 100,999)]" + invalidateCameraCache() + set_extension(src, /datum/extension/network_device/camera, null, null, null, TRUE, preset_channels, c_tag, cameranet_enabled, requires_connection) + RefreshParts() /obj/machinery/camera/Destroy() - deactivate(null, 0) //kick anyone viewing out - if(assembly) - qdel(assembly) - assembly = null + set_camera_status(0) //kick anyone viewing out + deltimer(emp_timer_id) return ..() /obj/machinery/camera/Process() - if((stat & EMPED) && world.time >= affected_by_emp_until) - stat &= ~EMPED - cancelCameraAlarm() + if (stat & (EMPED)) + return + if(!motion_sensor) + return PROCESS_KILL + + // Motion tracking. + if (detectTime == -1) + for (var/mob/target in motionTargets) + if (target.stat == DEAD) + lostTarget(target) + // See if the camera is still in range + if(!in_range(src, target)) + // If they aren't in range, lose the target. + lostTarget(target) + +/obj/machinery/camera/proc/newTarget(var/mob/target) + if (!motion_sensor) + return FALSE + if (isAI(target)) + return FALSE + if (detectTime == 0) + detectTime = world.time // start the clock + if (!(target in motionTargets)) + motionTargets += target + return TRUE + +/obj/machinery/camera/proc/lostTarget(var/mob/target) + if (target in motionTargets) + motionTargets -= target + if (motionTargets.len == 0) + cancelAlarm() + +/obj/machinery/camera/proc/cancelAlarm() + if (!status) + return FALSE + if (detectTime == -1) + motion_alarm.clearAlarm(loc, src) + detectTime = 0 + return TRUE + +/obj/machinery/camera/proc/triggerAlarm() + if (!status) + return FALSE + if (!detectTime) + return FALSE + motion_alarm.triggerAlarm(loc, src) + detectTime = -1 + return TRUE + +/obj/machinery/camera/HasProximity(atom/movable/AM) + . = ..() + if(. && isliving(AM)) + newTarget(AM) + +/obj/machinery/camera/emp_act(severity) + if(stat_immune & EMPED) + return + if(prob(100 / severity)) + stat |= EMPED + set_light(0) + triggerCameraAlarm() update_icon() update_coverage() - return internal_process() -/obj/machinery/camera/emp_act(severity) - if(!isEmpProof() && prob(100/severity)) - if(!affected_by_emp_until || (world.time < affected_by_emp_until)) - affected_by_emp_until = max(affected_by_emp_until, world.time + (90 SECONDS / severity)) - else - stat |= EMPED - set_light(0) - triggerCameraAlarm() - update_icon() - update_coverage() - START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + var/emp_length = 90 SECONDS / severity + emp_timer_id = addtimer(CALLBACK(src, PROC_REF(emp_expired)), emp_length, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE) + ..() + +/obj/machinery/camera/proc/emp_expired() + stat &= ~EMPED + cancelCameraAlarm() + update_icon() + update_coverage() + + if (detectTime > 0) + var/elapsed = world.time - detectTime + if (elapsed > alarm_delay) + triggerAlarm() + /obj/machinery/camera/bullet_act(var/obj/item/projectile/P) - take_damage(P.get_structure_damage()) + take_damage(P.get_structure_damage(), P.atom_damage_type) /obj/machinery/camera/explosion_act(severity) ..() - if(!invuln && !QDELETED(src) && (severity == 1 || prob(50))) - destroy() + if(!QDELETED(src) && (severity == 1 || prob(50))) + set_broken(TRUE) /obj/machinery/camera/hitby(var/atom/movable/AM) - ..() - if (istype(AM, /obj)) - var/obj/O = AM - if (O.throwforce >= src.toughness) - visible_message("[src] was hit by [O].") - take_damage(O.throwforce) - -/obj/machinery/camera/proc/setViewRange(var/num = 7) - src.view_range = num - cameranet.update_visibility(src, 0) - -/obj/machinery/camera/physical_attack_hand(mob/living/carbon/human/user) + . = ..() + if(. && isobj(AM)) + var/thrown_force = AM.get_thrown_attack_force() + if (thrown_force >= toughness) + visible_message(SPAN_DANGER("\The [src] was hit by \the [AM]!")) + var/obj/O = AM + take_damage(thrown_force, O.atom_damage_type) + +/obj/machinery/camera/physical_attack_hand(mob/living/human/user) if(!istype(user)) - return - if(user.species.can_shred(user)) - set_status(0) + return TRUE + if(user.can_shred()) user.do_attack_animation(src) - visible_message("\The [user] slashes at [src]!") + visible_message(SPAN_WARNING("\The [user] slashes at [src]!")) playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) add_hiddenprint(user) - destroy() + take_damage(25) return TRUE + return FALSE -/obj/machinery/camera/attackby(obj/item/W, mob/living/user) - update_coverage() - var/datum/wires/camera/camera_wires = wires - // DECONSTRUCTION - if(isScrewdriver(W)) -// to_chat(user, "You start to [panel_open ? "close" : "open"] the camera's panel.") - //if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown - panel_open = !panel_open - user.visible_message("[user] screws the camera's panel [panel_open ? "open" : "closed"]!", - "You screw the camera's panel [panel_open ? "open" : "closed"].") - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - - else if((isWirecutter(W) || isMultitool(W)) && panel_open) - return wires.Interact(user) - - else if(isWelder(W) && (camera_wires.CanDeconstruct() || (stat & BROKEN))) - if(weld(W, user)) - if(assembly) - assembly.dropInto(loc) - assembly.anchored = 1 - assembly.camera_name = c_tag - assembly.camera_network = english_list(network, "Exodus", ",", ",") - assembly.update_icon() - assembly.set_dir(src.dir) - if(stat & BROKEN) - assembly.state = 2 - to_chat(user, "You repaired \the [src] frame.") - cancelCameraAlarm() - else - assembly.state = 1 - to_chat(user, "You cut \the [src] free from the wall.") - new /obj/item/stack/cable_coil(loc, 2) - assembly = null //so qdel doesn't eat it. - qdel(src) - return - - // OTHER - else if (can_use() && istype(W, /obj/item/paper) && isliving(user)) - var/mob/living/U = user - var/obj/item/paper/X = W - var/itemname = X.name - var/info = X.info - to_chat(U, "You hold \a [itemname] up to the camera ...") - for(var/mob/living/silicon/ai/O in GLOB.living_mob_list_) - if(!O.client) continue - if(U.name == "Unknown") to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...") - else to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...") - show_browser(O, text("[][]", itemname, info), text("window=[]", itemname)) - - else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if (W.force >= src.toughness) - user.do_attack_animation(src) - visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!") - if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items? - var/obj/item/I = W - if (I.hitsound) - playsound(loc, I.hitsound, 50, 1, -1) - take_damage(W.force) - - else - ..() - -/obj/machinery/camera/proc/deactivate(mob/user, var/choice = 1) - // The only way for AI to reactivate cameras are malf abilities, this gives them different messages. - if(istype(user, /mob/living/silicon/ai)) - user = null +/obj/machinery/camera/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/paper)) + var/datum/extension/network_device/camera/D = get_extension(src, /datum/extension/network_device) + D.show_paper(used_item, user) + return ..() - if(choice != 1) - return +/obj/machinery/camera/interface_interact(mob/user) + if(allowed(user)) + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + D.ui_interact(user) + return TRUE - set_status(!src.status) - if (!(src.status)) - if(user) - visible_message(" [user] has deactivated [src]!") - else - visible_message(" [src] clicks and shuts down. ") - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) - icon_state = "[initial(icon_state)]1" - add_hiddenprint(user) - else - if(user) - visible_message(" [user] has reactivated [src]!") - else - visible_message(" [src] clicks and reactivates itself. ") - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) - icon_state = initial(icon_state) - add_hiddenprint(user) +/obj/machinery/camera/proc/add_channels(var/list/channels) + var/datum/extension/network_device/camera/D = get_extension(src, /datum/extension/network_device) + D.add_channels(channels) -/obj/machinery/camera/take_damage(var/force, var/message) - //prob(25) gives an average of 3-4 hits - if (force >= toughness && (force > toughness*4 || prob(25))) - destroy() +/obj/machinery/camera/proc/remove_channels(var/list/channels) + var/datum/extension/network_device/camera/D = get_extension(src, /datum/extension/network_device) + D.remove_channels(channels) -//Used when someone breaks a camera -/obj/machinery/camera/proc/destroy() - set_broken(TRUE) - wires.RandomCutAll() +/obj/machinery/camera/set_broken(new_state, cause) + . = ..() + if(.) + wires.RandomCutAll() - triggerCameraAlarm() - queue_icon_update() - update_coverage() + triggerCameraAlarm() + update_coverage() - //sparks - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, loc) - spark_system.start() - playsound(loc, "sparks", 50, 1) + //sparks + spark_at(loc, amount=5) -/obj/machinery/camera/proc/set_status(var/newstatus) - if (status != newstatus) +/obj/machinery/camera/proc/set_camera_status(var/newstatus, var/mob/user) + if (status != newstatus && (!cut_power || status == TRUE)) status = newstatus + // The only way for AI to reactivate cameras are malf abilities, this gives them different messages. + if(isAI(user)) + user = null + + if(status) + if(user) + visible_message(SPAN_NOTICE("[user] has reactivated \the [src]!")) + add_hiddenprint(user) + else + visible_message(SPAN_NOTICE("\The [src] clicks and reactivates itself.")) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + icon_state = initial(icon_state) + add_hiddenprint(user) + else + if(user) + visible_message(SPAN_NOTICE("[user] has deactivated \the [src]!")) + add_hiddenprint(user) + else + visible_message(SPAN_NOTICE("\The [src] clicks and shuts down.")) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + icon_state = "[initial(icon_state)]1" update_coverage() -/obj/machinery/camera/check_eye(mob/user) - if(!can_use()) return -1 - if(isXRay()) return SEE_TURFS|SEE_MOBS|SEE_OBJS - return 0 - /obj/machinery/camera/on_update_icon() - pixel_x = 0 - pixel_y = 0 - - var/turf/T = get_step(get_turf(src), turn(src.dir, 180)) - if(istype(T, /turf/simulated/wall)) - if(dir == SOUTH) - pixel_y = 21 - else if(dir == WEST) - pixel_x = 10 - else if(dir == EAST) - pixel_x = -10 - + var/base_state = initial(icon_state) + if(total_component_rating_of_type(/obj/item/stock_parts/scanning_module) >= XRAY_THRESHOLD) + base_state = "xraycam" if (!status || (stat & BROKEN)) - icon_state = "[initial(icon_state)]1" + icon_state = "[base_state]1" else if (stat & EMPED) - icon_state = "[initial(icon_state)]emp" + icon_state = "[base_state]emp" else - icon_state = initial(icon_state) + icon_state = base_state + +/obj/machinery/camera/RefreshParts() + . = ..() + var/power_mult = 1 + var/emp_protection = total_component_rating_of_type(/obj/item/stock_parts/capacitor) + if(emp_protection >= EMP_PROOF_THRESHOLD) + stat_immune |= EMPED + else + stat_immune &= ~EMPED + var/xray_rating = total_component_rating_of_type(/obj/item/stock_parts/scanning_module) + var/datum/extension/network_device/camera/camera_device = get_extension(src, /datum/extension/network_device/) + if(camera_device) + if(xray_rating >= XRAY_THRESHOLD) + camera_device.xray_enabled = TRUE + power_mult++ + else + camera_device.xray_enabled = FALSE + if(number_of_components(/obj/item/stock_parts/micro_laser, TRUE)) + motion_sensor = TRUE + power_mult++ + else + motion_sensor = FALSE + + change_power_consumption(power_mult*initial(active_power_usage), POWER_USE_ACTIVE) /obj/machinery/camera/proc/triggerCameraAlarm(var/duration = 0) alarm_on = 1 @@ -316,131 +314,74 @@ /obj/machinery/camera/proc/can_use() if(!status) return 0 - if(stat & (EMPED|BROKEN)) + if(stat & (EMPED|BROKEN|NOPOWER)) return 0 return 1 -/obj/machinery/camera/proc/can_see() - var/list/see = null - var/turf/pos = get_turf(src) - if(!pos) - return list() - - if(isXRay()) - see = range(view_range, pos) - else - see = hear(view_range, pos) - return see - -/atom/proc/auto_turn() - //Automatically turns based on nearby walls. - var/turf/simulated/wall/T = null - for(var/i = 1, i <= 8; i += i) - T = get_ranged_target_turf(src, i, 1) - if(istype(T)) - //If someone knows a better way to do this, let me know. -Giacom - switch(i) - if(NORTH) - src.set_dir(SOUTH) - if(SOUTH) - src.set_dir(NORTH) - if(WEST) - src.set_dir(EAST) - if(EAST) - src.set_dir(WEST) - break - -//Return a working camera that can see a given mob -//or null if none -/proc/seen_by_camera(var/mob/M) - for(var/obj/machinery/camera/C in oview(4, M)) - if(C.can_use()) // check if camera disabled - return C - return null - /proc/near_range_camera(var/mob/M) for(var/obj/machinery/camera/C in range(4, M)) if(C.can_use()) // check if camera disabled return C return null -/obj/machinery/camera/proc/weld(var/obj/item/weldingtool/WT, var/mob/user) +/obj/machinery/camera/proc/get_channels() + var/datum/extension/network_device/camera/D = get_extension(src, /datum/extension/network_device) + return D.channels - if(busy) - return 0 - - if(WT.remove_fuel(0, user)) - to_chat(user, "You start to weld \the [src]..") - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - busy = 1 - if(do_after(user, 100, src) && WT.isOn()) - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - busy = 0 - return 1 - - busy = 0 - return 0 - -/obj/machinery/camera/proc/add_network(var/network_name) - add_networks(list(network_name)) - -/obj/machinery/camera/proc/remove_network(var/network_name) - remove_networks(list(network_name)) - -/obj/machinery/camera/proc/add_networks(var/list/networks) - var/network_added - network_added = 0 - for(var/network_name in networks) - if(!(network_name in src.network)) - network += network_name - network_added = 1 - - if(network_added) - update_coverage(1) - -/obj/machinery/camera/proc/remove_networks(var/list/networks) - var/network_removed - network_removed = 0 - for(var/network_name in networks) - if(network_name in src.network) - network -= network_name - network_removed = 1 - - if(network_removed) - update_coverage(1) - -/obj/machinery/camera/proc/replace_networks(var/list/networks) - if(networks.len != network.len) - network = networks - update_coverage(1) - return +/obj/machinery/camera/proc/nano_structure() + var/datum/extension/network_device/camera/D = get_extension(src, /datum/extension/network_device/) + return D.nano_structure() - for(var/new_network in networks) - if(!(new_network in network)) - network = networks - update_coverage(1) - return +//Prevent literally anyone without access from tampering with the cameras if there's a network outage +/decl/stock_part_preset/network_lock/camera + expected_part_type = /obj/item/stock_parts/network_receiver/network_lock -/obj/machinery/camera/proc/clear_all_networks() - if(network.len) - network.Cut() - update_coverage(1) +/decl/stock_part_preset/network_lock/camera/do_apply(obj/machinery/camera/machine, obj/item/stock_parts/network_receiver/network_lock/part) + part.auto_deny_all = TRUE -/obj/machinery/camera/proc/nano_structure() - var/cam[0] - cam["name"] = sanitize(c_tag) - cam["deact"] = !can_use() - cam["camera"] = "\ref[src]" - cam["x"] = get_x(src) - cam["y"] = get_y(src) - cam["z"] = get_z(src) - return cam - -// Resets the camera's wires to fully operational state. Used by one of Malfunction abilities. -/obj/machinery/camera/proc/reset_wires() - if(!wires) - return - set_broken(FALSE) // Fixes the camera and updates the icon. - wires.CutAll() - wires.MendAll() - update_coverage() +/obj/machinery/camera + public_methods = list( + /decl/public_access/public_method/toggle_camera + ) + + public_variables = list( + /decl/public_access/public_variable/camera_state, + /decl/public_access/public_variable/camera_name, + /decl/public_access/public_variable/camera_channels + ) + +/obj/machinery/camera/proc/toggle_status() + set_camera_status(!status) + +/decl/public_access/public_method/toggle_camera + name = "toggle camera" + desc = "Toggles camera on or off." + call_proc = TYPE_PROC_REF(/obj/machinery/camera, toggle_status) + +/decl/public_access/public_variable/camera_state + expected_type = /obj/machinery/camera + name = "camera status" + desc = "Status of the camera." + can_write = FALSE + +/decl/public_access/public_variable/camera_state/access_var(obj/machinery/camera/C) + return C.status ? "enabled" : "disabled" + +/decl/public_access/public_variable/camera_name + expected_type = /obj/machinery/camera + name = "camera name" + desc = "Displayed name of the camera." + can_write = FALSE + +/decl/public_access/public_variable/camera_name/access_var(obj/machinery/camera/C) + var/datum/extension/network_device/camera/camera_device = get_extension(C, /datum/extension/network_device/) + return camera_device?.display_name + +/decl/public_access/public_variable/camera_channels + expected_type = /obj/machinery/camera + name = "camera channels" + desc = "List of the channels this camera broadcasts on." + can_write = FALSE + +/decl/public_access/public_variable/camera_channels/access_var(obj/machinery/camera/C) + return english_list(C.get_channels()) \ No newline at end of file diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm deleted file mode 100644 index 482ccfeba6b8..000000000000 --- a/code/game/machinery/camera/camera_assembly.dm +++ /dev/null @@ -1,171 +0,0 @@ -/obj/item/camera_assembly - name = "camera assembly" - desc = "A pre-fabricated security camera kit, ready to be assembled and mounted to a surface." - icon = 'icons/obj/monitors.dmi' - icon_state = "cameracase" - w_class = ITEM_SIZE_SMALL - anchored = 0 - - material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - - // Motion, EMP-Proof, X-Ray - var/list/obj/item/possible_upgrades = list(/obj/item/assembly/prox_sensor, /obj/item/stack/material/osmium, /obj/item/stock_parts/scanning_module) - var/list/upgrades = list() - var/camera_name - var/camera_network - var/state = 0 - var/busy = 0 - /* - 0 = Nothing done to it - 1 = Wrenched in place - 2 = Welded in place - 3 = Wires attached to it (you can now attach/dettach upgrades) - 4 = Screwdriver panel closed and is fully built (you cannot attach upgrades) - */ - -/obj/item/camera_assembly/attackby(obj/item/W, mob/living/user) - - switch(state) - - if(0) - // State 0 - if(isWrench(W) && isturf(src.loc)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "You wrench the assembly into place.") - anchored = 1 - state = 1 - update_icon() - auto_turn() - return - - if(1) - // State 1 - if(isWelder(W)) - if(weld(W, user)) - to_chat(user, "You weld the assembly securely into place.") - anchored = 1 - state = 2 - return - - else if(isWrench(W)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "You unattach the assembly from its place.") - anchored = 0 - update_icon() - state = 0 - return - - if(2) - // State 2 - if(isCoil(W)) - var/obj/item/stack/cable_coil/C = W - if(C.use(2)) - to_chat(user, "You add wires to the assembly.") - state = 3 - else - to_chat(user, "You need 2 coils of wire to wire the assembly.") - return - - else if(isWelder(W)) - - if(weld(W, user)) - to_chat(user, "You unweld the assembly from its place.") - state = 1 - anchored = 1 - return - - - if(3) - // State 3 - if(isScrewdriver(W)) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - - var/input = sanitize(input(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: Exodus,Security,Secret", "Set Network", camera_network ? camera_network : NETWORK_EXODUS)) - if(!input) - to_chat(usr, "No input found please hang up and try your call again.") - return - - var/list/tempnetwork = splittext(input, ",") - if(tempnetwork.len < 1) - to_chat(usr, "No network found please hang up and try your call again.") - return - - var/area/camera_area = get_area(src) - var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])" - input = sanitizeSafe(input(usr, "How would you like to name the camera?", "Set Camera Name", camera_name ? camera_name : temptag), MAX_LNAME_LEN) - - state = 4 - var/obj/machinery/camera/C = new(src.loc) - src.forceMove(C) - C.assembly = src - - C.auto_turn() - - C.replace_networks(uniquelist(tempnetwork)) - - C.c_tag = input - - for(var/i = 5; i >= 0; i -= 1) - var/direct = input(user, "Direction?", "Assembling Camera", null) in list("LEAVE IT", "NORTH", "EAST", "SOUTH", "WEST" ) - if(direct != "LEAVE IT") - C.set_dir(text2dir(direct)) - if(i != 0) - var/confirm = alert(user, "Is this what you want? Chances Remaining: [i]", "Confirmation", "Yes", "No") - if(confirm == "Yes") - C.update_icon() - break - return - - else if(isWirecutter(W)) - - new/obj/item/stack/cable_coil(get_turf(src), 2) - playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) - to_chat(user, "You cut the wires from the circuits.") - state = 2 - return - - // Upgrades! - if(is_type_in_list(W, possible_upgrades) && !is_type_in_list(W, upgrades) && user.unEquip(W, src)) // Is a possible upgrade and isn't in the camera already. - to_chat(user, "You attach \the [W] into the assembly inner circuits.") - upgrades += W - return - - // Taking out upgrades - else if(isCrowbar(W) && upgrades.len) - var/obj/U = locate(/obj) in upgrades - if(U) - to_chat(user, "You unattach an upgrade from the assembly.") - playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) - U.dropInto(loc) - upgrades -= U - return - - ..() - -/obj/item/camera_assembly/on_update_icon() - if(anchored) - icon_state = "camera1" - else - icon_state = "cameracase" - -/obj/item/camera_assembly/attack_hand(mob/user) - if(!anchored) - ..() - -/obj/item/camera_assembly/proc/weld(var/obj/item/weldingtool/WT, var/mob/user) - - if(busy) - return 0 - - if(WT.remove_fuel(0, user)) - to_chat(user, "You start to weld \the [src]..") - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - busy = 1 - if(do_after(user, 20, src) && WT.isOn()) - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - busy = 0 - return 1 - - busy = 0 - return 0 \ No newline at end of file diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm deleted file mode 100644 index 3527ac9dad88..000000000000 --- a/code/game/machinery/camera/motion.dm +++ /dev/null @@ -1,59 +0,0 @@ -/obj/machinery/camera - var/list/motionTargets = list() - var/detectTime = 0 - var/alarm_delay = 100 // Don't forget, there's another 10 seconds in queueAlarm() - movable_flags = MOVABLE_FLAG_PROXMOVE - -/obj/machinery/camera/proc/internal_process() - // motion camera event loop - if (stat & (EMPED|NOPOWER)) - return - if(!isMotion()) - . = PROCESS_KILL - return - if (detectTime > 0) - var/elapsed = world.time - detectTime - if (elapsed > alarm_delay) - triggerAlarm() - else if (detectTime == -1) - for (var/mob/target in motionTargets) - if (target.stat == DEAD) - lostTarget(target) - // See if the camera is still in range - if(!in_range(src, target)) - // If they aren't in range, lose the target. - lostTarget(target) - -/obj/machinery/camera/proc/newTarget(var/mob/target) - if (istype(target, /mob/living/silicon/ai)) return 0 - if (detectTime == 0) - detectTime = world.time // start the clock - if (!(target in motionTargets)) - motionTargets += target - return 1 - -/obj/machinery/camera/proc/lostTarget(var/mob/target) - if (target in motionTargets) - motionTargets -= target - if (motionTargets.len == 0) - cancelAlarm() - -/obj/machinery/camera/proc/cancelAlarm() - if (!status || (stat & NOPOWER)) - return 0 - if (detectTime == -1) - motion_alarm.clearAlarm(loc, src) - detectTime = 0 - return 1 - -/obj/machinery/camera/proc/triggerAlarm() - if (!status || (stat & NOPOWER)) - return 0 - if (!detectTime) return 0 - motion_alarm.triggerAlarm(loc, src) - detectTime = -1 - return 1 - -/obj/machinery/camera/HasProximity(atom/movable/AM) - if(isliving(AM)) - newTarget(AM) diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index d9e8724e5bc2..2b278bc95e4b 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -1,97 +1,51 @@ /obj/machinery/camera/network/engineering - network = list(NETWORK_ENGINEERING) - -/obj/machinery/camera/network/ert - network = list(NETWORK_ERT) + preset_channels = list(CAMERA_CHANNEL_ENGINEERING) + req_access = list(access_engine) /obj/machinery/camera/network/medbay - network = list(NETWORK_MEDICAL) - + preset_channels = list(CAMERA_CHANNEL_MEDICAL) + req_access = list(access_medical) /obj/machinery/camera/network/mercenary - network = list(NETWORK_MERCENARY) + preset_channels = list(CAMERA_CHANNEL_MERCENARY) + cameranet_enabled = FALSE + req_access = list(access_mercenary) /obj/machinery/camera/network/mining - network = list(NETWORK_MINE) + preset_channels = list(CAMERA_CHANNEL_MINE) + req_access = list(access_mining) /obj/machinery/camera/network/research - network = list(NETWORK_RESEARCH) + preset_channels = list(CAMERA_CHANNEL_RESEARCH) + req_access = list(access_research) /obj/machinery/camera/network/security - network = list(NETWORK_SECURITY) + preset_channels = list(CAMERA_CHANNEL_SECURITY) + req_access = list(access_security) -/obj/machinery/camera/network/thunder - network = list(NETWORK_THUNDER) +/obj/machinery/camera/network/television + preset_channels = list(CAMERA_CHANNEL_TELEVISION) + cameranet_enabled = FALSE + requires_connection = FALSE // EMP - -/obj/machinery/camera/emp_proof/Initialize() - ..() - . = upgradeEmpProof() +/obj/machinery/camera/emp_proof + uncreated_component_parts = list(/obj/item/stock_parts/capacitor/adv = 1) // X-RAY - /obj/machinery/camera/xray - icon_state = "xraycam" // Thanks to Krutchen for the icons. - -/obj/machinery/camera/xray/Initialize() - . = ..() - upgradeXRay() + uncreated_component_parts = list(/obj/item/stock_parts/scanning_module/adv = 1) // MOTION - -/obj/machinery/camera/motion/Initialize() - . = ..() - upgradeMotion() +/obj/machinery/camera/motion + uncreated_component_parts = list(/obj/item/stock_parts/micro_laser = 1) // ALL UPGRADES - -/obj/machinery/camera/all/Initialize() - . = ..() - upgradeEmpProof() - upgradeXRay() - upgradeMotion() +/obj/machinery/camera/all + uncreated_component_parts = list( + /obj/item/stock_parts/capacitor/adv = 1, + /obj/item/stock_parts/scanning_module/adv = 1, + /obj/item/stock_parts/micro_laser = 1 + ) // AUTONAME left as a map stub -/obj/machinery/camera/autoname - -// CHECKS - -/obj/machinery/camera/proc/isEmpProof() - var/O = locate(/obj/item/stack/material/osmium) in assembly.upgrades - return O - -/obj/machinery/camera/proc/isXRay() - var/obj/item/stock_parts/scanning_module/O = locate(/obj/item/stock_parts/scanning_module) in assembly.upgrades - if (O && O.rating >= 2) - return O - return null - -/obj/machinery/camera/proc/isMotion() - var/O = locate(/obj/item/assembly/prox_sensor) in assembly.upgrades - return O - -// UPGRADE PROCS - -/obj/machinery/camera/proc/upgradeEmpProof() - assembly.upgrades.Add(new /obj/item/stack/material/osmium(assembly)) - setPowerUsage() - update_coverage() - -/obj/machinery/camera/proc/upgradeXRay() - assembly.upgrades.Add(new /obj/item/stock_parts/scanning_module/adv(assembly)) - setPowerUsage() - update_coverage() - -/obj/machinery/camera/proc/upgradeMotion() - assembly.upgrades.Add(new /obj/item/assembly/prox_sensor(assembly)) - setPowerUsage() - STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) - update_coverage() - -/obj/machinery/camera/proc/setPowerUsage() - var/mult = 1 - if (isXRay()) - mult++ - if (isMotion()) - mult++ - change_power_consumption(mult*initial(active_power_usage), POWER_USE_ACTIVE) \ No newline at end of file +/obj/machinery/camera/autoname \ No newline at end of file diff --git a/code/game/machinery/camera/robot_camera.dm b/code/game/machinery/camera/robot_camera.dm new file mode 100644 index 000000000000..cf3463664fa9 --- /dev/null +++ b/code/game/machinery/camera/robot_camera.dm @@ -0,0 +1,14 @@ +/datum/extension/network_device/camera/robot + expected_type = /mob/living/silicon/robot + +/datum/extension/network_device/camera/robot/is_functional() + var/mob/living/silicon/robot/robot = holder + if(robot.wires.IsIndexCut(BORG_WIRE_CAMERA)) + return FALSE + if(!robot.has_power) + return FALSE + if(robot.stat == DEAD) + return FALSE + if(!robot.is_component_functioning("camera")) + return FALSE + return TRUE \ No newline at end of file diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm index df6e1e653e52..d1a10d81ea00 100644 --- a/code/game/machinery/camera/tracking.dm +++ b/code/game/machinery/camera/tracking.dm @@ -6,17 +6,15 @@ /mob/living/silicon/ai/var/stored_locations[0] /proc/InvalidPlayerTurf(turf/T) - return !(T && (T.z in GLOB.using_map.player_levels)) + return !(T && isPlayerLevel(T.z)) /mob/living/silicon/ai/proc/get_camera_list() - if(src.stat == 2) + if(src.stat == DEAD) return var/list/T = list() for (var/obj/machinery/camera/C in cameranet.cameras) - var/list/tempnetwork = C.network&src.network - if (tempnetwork.len) - T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C + T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C track = new() track.cameras = T @@ -38,34 +36,34 @@ return -/mob/living/silicon/ai/proc/ai_store_location(loc as text) +/mob/living/silicon/ai/proc/ai_store_location(camera_loc as text) set category = "Silicon Commands" set name = "Store Camera Location" set desc = "Stores your current camera location by the given name" - loc = sanitize(loc) - if(!loc) - to_chat(src, "Must supply a location name") + camera_loc = sanitize(camera_loc) + if(!camera_loc) + to_chat(src, SPAN_WARNING("Must supply a location name.")) return if(stored_locations.len >= max_locations) - to_chat(src, "Cannot store additional locations. Remove one first") + to_chat(src, SPAN_WARNING("Cannot store additional locations, remove one first.")) return - if(loc in stored_locations) - to_chat(src, "There is already a stored location by this name") + if(camera_loc in stored_locations) + to_chat(src, SPAN_WARNING("There is already a stored location by that name.")) return var/L = src.eyeobj.getLoc() if (InvalidPlayerTurf(get_turf(L))) - to_chat(src, "Unable to store this location") + to_chat(src, SPAN_WARNING("Unable to store this location.")) return - stored_locations[loc] = L - to_chat(src, "Location '[loc]' stored") + stored_locations[camera_loc] = L + to_chat(src, "Location '[camera_loc]' stored.") /mob/living/silicon/ai/proc/sorted_stored_locations() - return sortList(stored_locations) + return sortTim(stored_locations, /proc/cmp_text_asc) /mob/living/silicon/ai/proc/ai_goto_location(loc in sorted_stored_locations()) set category = "Silicon Commands" @@ -73,7 +71,7 @@ set desc = "Returns to the selected camera location" if (!(loc in stored_locations)) - to_chat(src, "Location [loc] not found") + to_chat(src, SPAN_WARNING("Location [loc] not found.")) return var/L = stored_locations[loc] @@ -85,11 +83,11 @@ set desc = "Deletes the selected camera location" if (!(loc in stored_locations)) - to_chat(src, "Location [loc] not found") + to_chat(src, SPAN_WARNING("Location [loc] not found.")) return stored_locations.Remove(loc) - to_chat(src, "Location [loc] removed") + to_chat(src, "Location [loc] removed.") // Used to allow the AI is write in mob names/camera name from the CMD line. /datum/trackable @@ -100,7 +98,7 @@ var/list/cameras = list() /mob/living/silicon/ai/proc/trackable_mobs() - if(usr.stat == 2) + if(usr.stat == DEAD) return list() var/datum/trackable/TB = new() @@ -117,12 +115,12 @@ else TB.names.Add(name) TB.namecounts[name] = 1 - if(istype(M, /mob/living/carbon/human)) + if(ishuman(M)) TB.humans[name] = M else TB.others[name] = M - var/list/targets = sortList(TB.humans) + sortList(TB.others) + var/list/targets = sortTim(TB.humans, /proc/cmp_text_asc) + sortTim(TB.others, /proc/cmp_text_asc) src.track = TB return targets @@ -131,7 +129,7 @@ set name = "Follow With Camera" set desc = "Select who you would like to track." - if(src.stat == 2) + if(src.stat == DEAD) to_chat(src, "You can't follow [target_name] with cameras because you are dead!") return if(!target_name) @@ -151,67 +149,48 @@ /mob/living/silicon/ai/proc/ai_actual_track(mob/living/target) if(!istype(target)) return - var/mob/living/silicon/ai/U = usr - if(target == U.cameraFollow) + if(target == cameraFollow) return - if(U.cameraFollow) - U.ai_cancel_tracking() - U.cameraFollow = target - to_chat(U, "Tracking target...") + if(cameraFollow) + ai_cancel_tracking() + cameraFollow = target + to_chat(src, "Tracking target...") target.tracking_initiated() spawn (0) - while (U.cameraFollow == target) - if (U.cameraFollow == null) + while (cameraFollow == target) + if (cameraFollow == null) return switch(target.tracking_status()) if(TRACKING_NO_COVERAGE) - to_chat(U, "Target is not near any active cameras.") + to_chat(src, "Target is not near any active cameras.") sleep(100) continue if(TRACKING_TERMINATE) - U.ai_cancel_tracking(1) + ai_cancel_tracking(1) return - if(U.eyeobj) - U.eyeobj.setLoc(get_turf(target), 0) + if(eyeobj) + eyeobj.setLoc(get_turf(target), 0) else view_core() return sleep(10) -/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user) +/obj/machinery/camera/attack_ai(mob/living/silicon/ai/user) if (!istype(user)) return - if (!src.can_use()) + if (!can_use()) return user.eyeobj.setLoc(get_turf(src)) - /mob/living/silicon/ai/attack_ai(var/mob/user) ai_camera_list() -/proc/camera_sort(list/L) - var/obj/machinery/camera/a - var/obj/machinery/camera/b - - for (var/i = L.len, i > 0, i--) - for (var/j = 1 to i - 1) - a = L[j] - b = L[j + 1] - if (a.c_tag_order != b.c_tag_order) - if (a.c_tag_order > b.c_tag_order) - L.Swap(j, j + 1) - else - if (sorttext(a.c_tag, b.c_tag) < 0) - L.Swap(j, j + 1) - return L - - -mob/living/proc/near_camera() +/mob/living/proc/near_camera() if (!isturf(loc)) return 0 else if(!cameranet.is_visible(src)) @@ -238,9 +217,10 @@ mob/living/proc/near_camera() /mob/living/silicon/robot/tracking_status() . = ..() if(. == TRACKING_NO_COVERAGE) - return camera && camera.can_use() ? TRACKING_POSSIBLE : TRACKING_NO_COVERAGE + var/datum/extension/network_device/camera/robot/D = get_extension(src, /datum/extension/network_device) + return D && D.is_functional() ? TRACKING_POSSIBLE : TRACKING_NO_COVERAGE -/mob/living/carbon/human/tracking_status() +/mob/living/human/tracking_status() if(is_cloaked()) . = TRACKING_TERMINATE else @@ -251,22 +231,22 @@ mob/living/proc/near_camera() if(. == TRACKING_NO_COVERAGE) var/turf/T = get_turf(src) - if(T && (T.z in GLOB.using_map.station_levels) && hassensorlevel(src, SUIT_SENSOR_TRACKING)) + if(T && isStationLevel(T.z) && hassensorlevel(src, VITALS_SENSOR_TRACKING)) return TRACKING_POSSIBLE -mob/living/proc/tracking_initiated() +/mob/living/proc/tracking_initiated() -mob/living/silicon/robot/tracking_initiated() +/mob/living/silicon/robot/tracking_initiated() tracking_entities++ if(tracking_entities == 1 && has_zeroth_law()) - to_chat(src, "Internal camera is currently being accessed.") + to_chat(src, SPAN_WARNING("Internal camera is currently being accessed.")) -mob/living/proc/tracking_cancelled() +/mob/living/proc/tracking_cancelled() -mob/living/silicon/robot/tracking_cancelled() +/mob/living/silicon/robot/tracking_cancelled() tracking_entities-- if(!tracking_entities && has_zeroth_law()) - to_chat(src, "Internal camera is no longer being accessed.") + to_chat(src, SPAN_NOTICE("Internal camera is no longer being accessed.")) #undef TRACKING_POSSIBLE diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index 846f92f1a740..9cc55afa80f1 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -3,7 +3,7 @@ desc = "A much more powerful version of the standard recharger that is specially designed for charging power cells." icon = 'icons/obj/power.dmi' icon_state = "ccharger0" - anchored = 1 + anchored = TRUE idle_power_usage = 5 power_channel = EQUIP var/chargelevel = -1 @@ -32,13 +32,13 @@ else overlays.Cut() -/obj/machinery/cell_charger/examine(var/mob/user, var/distance) +/obj/machinery/cell_charger/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 5) var/obj/item/cell/cell = get_cell() - to_chat(user, "There's [cell ? "a" : "no"] cell in the charger.") + . += "There's [cell ? "a" : "no"] cell in the charger." if(cell) - to_chat(user, "Current charge: [cell.charge]") + . += "Current charge: [cell.charge]." /obj/machinery/cell_charger/component_stat_change(obj/item/stock_parts/part, old_stat, flag) . = ..() @@ -52,15 +52,15 @@ STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) update_icon() -/obj/machinery/cell_charger/attackby(obj/item/W, mob/user) - if(isWrench(W) && !panel_open) +/obj/machinery/cell_charger/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item) && !panel_open) . = TRUE if(get_cell()) to_chat(user, "Remove the cell first!") return anchored = !anchored - to_chat(user, "You [anchored ? "attach" : "detach"] the cell charger [anchored ? "to" : "from"] the ground") + to_chat(user, "You [anchored ? "attach" : "detach"] \the [src] [anchored ? "to" : "from"] the ground.") playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) return diff --git a/code/game/machinery/centrifuge.dm b/code/game/machinery/centrifuge.dm new file mode 100644 index 000000000000..f992197e156e --- /dev/null +++ b/code/game/machinery/centrifuge.dm @@ -0,0 +1,183 @@ +/datum/storage/hopper/industrial/centrifuge + can_hold = list( + /obj/item/food, + ) + expected_type = /obj/machinery/centrifuge + +/datum/storage/hopper/industrial/centrifuge/proc/should_ingest(mob/user, obj/item/thing) + if(REAGENT_TOTAL_VOLUME(thing.reagents) <= 0) + if(user) + to_chat(user, SPAN_WARNING("\The [thing] is empty.")) + return FALSE + return TRUE + +/datum/storage/hopper/industrial/centrifuge/can_be_inserted(obj/item/inserting, mob/user, stop_messages, click_params) + . = ..() + if(. && !should_ingest(user, inserting)) + return FALSE + +/obj/machinery/centrifuge + name = "industrial centrifuge" + desc = "A machine used to extract reagents and materials from objects via spinning them at extreme speed." + icon = 'icons/obj/machines/centrifuge.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + storage = /datum/storage/hopper/industrial/centrifuge + base_type = /obj/machinery/centrifuge + stat_immune = 0 + + // Reference to our reagent container. Set to a path to create on init. + var/obj/item/loaded_beaker + + // Stolen from fabricators. + var/sound_id + var/datum/sound_token/sound_token + var/work_sound = 'sound/machines/fabricator_loop.ogg' + +/obj/machinery/centrifuge/mapped + loaded_beaker = /obj/item/chems/glass/beaker/large + +/obj/machinery/centrifuge/Initialize() + . = ..() + if(ispath(loaded_beaker)) + loaded_beaker = new loaded_beaker + +/obj/machinery/centrifuge/get_stored_inventory() + . = ..() + if(LAZYLEN(.)) + LAZYREMOVE(., loaded_beaker) + +/obj/machinery/centrifuge/Destroy() + QDEL_NULL(loaded_beaker) + return ..() + +/obj/machinery/centrifuge/dismantle() + if(loaded_beaker) + loaded_beaker.dropInto(loc) + loaded_beaker = null + return ..() + +/obj/machinery/centrifuge/components_are_accessible(path) + return use_power != POWER_USE_ACTIVE && ..() + +/obj/machinery/centrifuge/cannot_transition_to(state_path, mob/user) + if(use_power == POWER_USE_ACTIVE) + return SPAN_NOTICE("You must wait for \the [src] to finish first!") + return ..() + +/obj/machinery/centrifuge/attackby(obj/item/used_item, mob/user) + + if(use_power == POWER_USE_ACTIVE) + to_chat(user, SPAN_NOTICE("\The [src] is currently spinning, wait until it's finished.")) + return TRUE + + if((. = component_attackby(used_item, user))) + return + + // Load in a new container for products. + if(istype(used_item, /obj/item/chems/glass/beaker)) + if(loaded_beaker) + to_chat(user, SPAN_WARNING("\The [src] already has a beaker loaded.")) + return TRUE + if(user.try_unequip(used_item, src)) + loaded_beaker = used_item + to_chat(user, SPAN_NOTICE("You load \the [loaded_beaker] into \the [src].")) + return TRUE + + // Parent call handles inserting the frame into our contents, + return ..() + +/obj/machinery/centrifuge/attack_hand(mob/user) + + if(use_power == POWER_USE_ACTIVE) + user.visible_message("\The [user] disengages \the [src].") + update_use_power(POWER_USE_IDLE) + return TRUE + + if(use_power == POWER_USE_IDLE) + if(!loaded_beaker || QDELETED(loaded_beaker)) + to_chat(user, SPAN_WARNING("\The [src] has no beaker loaded to receive any products.")) + loaded_beaker = null // just in case + return TRUE + + if(length(get_stored_inventory())) + user.visible_message("\The [user] engages \the [src].") + update_use_power(POWER_USE_ACTIVE) + else + to_chat(user, SPAN_WARNING("\The [src]'s hopper is empty.")) + return TRUE + + if(use_power == POWER_USE_OFF || !operable()) + to_chat(user, SPAN_WARNING("\The [src]'s interface is unresponsive.")) + return TRUE + + return ..() + +/obj/machinery/centrifuge/Process(wait, tick) + ..() + + if(use_power != POWER_USE_ACTIVE) + return + + if(!loaded_beaker) + visible_message("\The [src] stops spinning and flashes a red light.") + update_use_power(POWER_USE_IDLE) + return + + var/list/processing_items = get_stored_inventory() + if(!length(processing_items)) + visible_message("\The [src] stops spinning and flashes a green light.") + update_use_power(POWER_USE_IDLE) + return + + var/obj/item/thing = processing_items[1] + thing.handle_centrifuge_process(src) + if(!QDELETED(thing) && loc) + thing.dropInto(loc) + +/obj/machinery/centrifuge/Initialize() + sound_id = "[work_sound]" + return ..() + +/obj/machinery/centrifuge/Destroy() + QDEL_NULL(sound_token) + return ..() + +/obj/machinery/centrifuge/update_use_power() + . = ..() + if(use_power == POWER_USE_ACTIVE) + if(!sound_token) + sound_token = play_looping_sound(src, sound_id, work_sound, volume = 30) + else + QDEL_NULL(sound_token) + +/obj/machinery/centrifuge/on_update_icon() + icon_state = initial(icon_state) + if(stat & BROKEN) + icon_state = "[icon_state]-broken" + else if(use_power == POWER_USE_OFF || !operable()) + icon_state = "[icon_state]-off" + else if(use_power == POWER_USE_ACTIVE) + icon_state = "[icon_state]-working" + +/obj/machinery/centrifuge/get_quick_interaction_handler(mob/user) + return loaded_beaker ? GET_DECL(/decl/interaction_handler/remove_centrifuge_beaker) : null + +/obj/machinery/centrifuge/get_alt_interactions(var/mob/user) + . = ..() + if(loaded_beaker) + LAZYADD(., /decl/interaction_handler/remove_centrifuge_beaker) + +/decl/interaction_handler/remove_centrifuge_beaker + name = "Remove Beaker" + expected_target_type = /obj/machinery/centrifuge + +/decl/interaction_handler/remove_centrifuge_beaker/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/centrifuge/centrifuge = target + if(centrifuge.loaded_beaker) + centrifuge.loaded_beaker.dropInto(centrifuge.loc) + user.put_in_hands(centrifuge.loaded_beaker) + centrifuge.loaded_beaker = null diff --git a/code/game/machinery/commsrelay.dm b/code/game/machinery/commsrelay.dm index aea515878ea7..5573f9df9026 100644 --- a/code/game/machinery/commsrelay.dm +++ b/code/game/machinery/commsrelay.dm @@ -3,8 +3,8 @@ desc = "This machine creates a microscopic wormhole between here and a suitable target, allowing for FTL communication." icon = 'icons/obj/machines/tcomms/bs_relay.dmi' icon_state = "bspacerelay" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE idle_power_usage = 15000 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index a732ce9e243a..072b89e99280 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -2,11 +2,11 @@ /obj/machinery/computer/operating name = "patient monitoring console" - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE icon_keyboard = "med_key" icon_screen = "crew" - var/mob/living/carbon/human/victim = null + var/mob/living/human/victim = null var/obj/machinery/optable/table = null /obj/machinery/computer/operating/Initialize() @@ -23,14 +23,14 @@ /obj/machinery/computer/operating/interact(mob/user) if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) - if (!istype(user, /mob/living/silicon)) + if (!issilicon(user)) user.unset_machine() close_browser(user, "window=op") return user.set_machine(src) var/dat = "Operating Computer\n" - dat += "Close

    " //| Update" + dat += "Close

    " //| Update" if(src.table && (src.table.check_victim())) src.victim = src.table.victim dat += {" diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 0de27db94988..79bb78e9540e 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -1,8 +1,8 @@ var/global/list/empty_playable_ai_cores = list() /obj/structure/aicore - density = 1 - anchored = 0 + density = TRUE + anchored = FALSE name = "\improper AI core" icon = 'icons/mob/AI.dmi' icon_state = "0" @@ -11,7 +11,7 @@ var/global/list/empty_playable_ai_cores = list() var/datum/ai_laws/laws var/obj/item/stock_parts/circuitboard/circuit - var/obj/item/mmi/brain + var/obj/item/organ/internal/brain var/authorized var/circuit_secured = FALSE @@ -19,12 +19,12 @@ var/global/list/empty_playable_ai_cores = list() /obj/structure/aicore/Initialize() if(!laws) - laws = new GLOB.using_map.default_law_type + laws = new global.using_map.default_law_type . = ..() /obj/structure/aicore/emag_act(var/remaining_charges, var/mob/user, var/emag_source) if(!authorized) - to_chat(user, SPAN_WARNING("You swipe [emag_source] at [src] and jury rig it into the systems of [GLOB.using_map.full_name]!")) + to_chat(user, SPAN_WARNING("You swipe [emag_source] at [src] and jury rig it into the systems of [global.using_map.full_name]!")) authorized = 1 return 1 . = ..() @@ -41,7 +41,7 @@ var/global/list/empty_playable_ai_cores = list() return TRUE else if(circuit_secured) if(!authorized) - to_chat(user, SPAN_WARNING("Core fails to connect to the systems of [GLOB.using_map.full_name]!")) + to_chat(user, SPAN_WARNING("Core fails to connect to the systems of [global.using_map.full_name]!")) return TRUE playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) to_chat(user, SPAN_NOTICE("You connect the monitor.")) @@ -65,7 +65,7 @@ var/global/list/empty_playable_ai_cores = list() if(glass_installed) playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) to_chat(user, SPAN_NOTICE("You remove the glass panel.")) - new /obj/item/stack/material/glass/reinforced( loc, 2 ) + SSmaterials.create_object(/decl/material/solid/glass, loc, 2, null, /decl/material/solid/metal/steel) glass_installed = FALSE return TRUE if(brain) @@ -96,6 +96,7 @@ var/global/list/empty_playable_ai_cores = list() . = ..() /obj/structure/aicore/on_update_icon() + ..() if(glass_installed) icon_state = "4" else if(brain) @@ -107,65 +108,59 @@ var/global/list/empty_playable_ai_cores = list() else icon_state = "0" -/obj/structure/aicore/attackby(obj/item/P, mob/user) +/obj/structure/aicore/attackby(obj/item/used_item, mob/user) . = ..() if(.) update_icon() else if(!authorized) - if(access_ai_upload in P.GetAccess()) - to_chat(user, SPAN_NOTICE("You swipe [P] at [src] and authorize it to connect into the systems of [GLOB.using_map.full_name].")) + if(access_ai_upload in used_item.GetAccess()) + to_chat(user, SPAN_NOTICE("You swipe [used_item] at [src] and authorize it to connect into the systems of [global.using_map.full_name].")) authorized = 1 if(anchored) if(!glass_installed && wired) - if(istype(P, /obj/item/stock_parts/circuitboard/aicore)) + if(istype(used_item, /obj/item/stock_parts/circuitboard/aicore)) if(circuit) to_chat(user, SPAN_WARNING("There is already a circuit installed in \the [src].")) return TRUE if(!wired) to_chat(user, SPAN_WARNING("Wire \the [src] first.")) return TRUE - if(user.unEquip(P, src)) + if(user.try_unequip(used_item, src)) playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) to_chat(user, SPAN_NOTICE("You place the circuit board inside the frame.")) - circuit = P + circuit = used_item update_icon() return TRUE if(circuit && circuit_secured) - if((istype(P, /obj/item/mmi) || istype(P, /obj/item/organ/internal/posibrain)) && wired && circuit && circuit_secured) - var/mob/living/carbon/brain/B - if(istype(P, /obj/item/mmi)) - var/obj/item/mmi/M = P - B = M.brainmob - else - var/obj/item/organ/internal/posibrain/PB = P - B = PB.brainmob - if(!B) - to_chat(user, SPAN_WARNING("Sticking an empty [P] into the frame would sort of defeat the purpose.")) + if(istype(used_item, /obj/item/organ/internal) && wired && circuit && circuit_secured) + var/obj/item/organ/internal/M = used_item + var/mob/living/brainmob = M.get_brainmob() + if(!brainmob) + to_chat(user, SPAN_WARNING("Sticking a mindless [used_item] into the frame would be pointless.")) return - if(B.stat == 2) - to_chat(user, SPAN_WARNING("Sticking a dead [P] into the frame would sort of defeat the purpose.")) + if(brainmob.stat == DEAD) + to_chat(user, SPAN_WARNING("Sticking a dead [used_item] into the frame would sort of defeat the purpose.")) return - if(jobban_isbanned(B, "AI")) - to_chat(user, SPAN_WARNING("This [P] does not seem to fit.")) + if(jobban_isbanned(brainmob, "AI")) + to_chat(user, SPAN_WARNING("This [used_item] does not seem to fit.")) return - if(!user.unEquip(P, src)) - return - if(B.mind) - clear_antag_roles(B.mind, 1) - brain = P - to_chat(usr, "Added [P].") - update_icon() + if(!user.try_unequip(used_item, src)) + if(brainmob.mind) + clear_antag_roles(brainmob.mind, 1) + brain = used_item + to_chat(usr, "You connect \the [used_item] to the frame and slide it into the casing.") + update_icon() return TRUE - if(istype(P, /obj/item/stack/material)) - var/obj/item/stack/material/RG = P + if(istype(used_item, /obj/item/stack/material)) + var/obj/item/stack/material/RG = used_item if(RG.material.type != /decl/material/solid/glass || !RG.reinf_material || RG.get_amount() < 2) to_chat(user, SPAN_WARNING("You need two sheets of reinforced glass to put in the glass panel.")) return TRUE @@ -180,14 +175,14 @@ var/global/list/empty_playable_ai_cores = list() update_icon() return TRUE - if(istype(P, /obj/item/aiModule/freeform)) - var/obj/item/aiModule/freeform/M = P + if(istype(used_item, /obj/item/aiModule/freeform)) + var/obj/item/aiModule/freeform/M = used_item laws.add_inherent_law(M.newFreeFormLaw) to_chat(usr, "Added a freeform law.") return TRUE - if(istype(P, /obj/item/aiModule)) - var/obj/item/aiModule/module = P + if(istype(used_item, /obj/item/aiModule)) + var/obj/item/aiModule/module = used_item laws.clear_inherent_laws() if(module.laws) for(var/datum/ai_law/AL in module.laws.inherent_laws) @@ -195,20 +190,26 @@ var/global/list/empty_playable_ai_cores = list() to_chat(usr, "Law module applied.") return TRUE +var/global/list/deactivated_ai_cores = list() /obj/structure/aicore/deactivated name = "inactive AI" icon = 'icons/mob/AI.dmi' icon_state = "ai-empty" - anchored = 1 + anchored = TRUE tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) +/obj/structure/aicore/deactivated/Initialize() + . = ..() + global.deactivated_ai_cores += src + /obj/structure/aicore/deactivated/Destroy() + global.deactivated_ai_cores -= src empty_playable_ai_cores -= src . = ..() /obj/structure/aicore/deactivated/proc/load_ai(var/mob/living/silicon/ai/transfer, var/obj/item/aicard/card, var/mob/user) - if(!istype(transfer) || locate(/mob/living/silicon/ai) in src) + if(!isAI(transfer) || locate(/mob/living/silicon/ai) in src) return transfer.aiRestorePowerRoutine = 0 @@ -223,35 +224,35 @@ var/global/list/empty_playable_ai_cores = list() card.clear() qdel(src) -/obj/structure/aicore/deactivated/attackby(var/obj/item/W, var/mob/user) - if(isWrench(W) || isWelder(W)) - . = ..() - else if(istype(W, /obj/item/aicard)) - var/obj/item/aicard/card = W +/obj/structure/aicore/deactivated/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/aicard)) + var/obj/item/aicard/card = used_item var/mob/living/silicon/ai/transfer = locate() in card if(transfer) load_ai(transfer,card,user) else to_chat(user, SPAN_DANGER("ERROR: Unable to locate artificial intelligence.")) return TRUE + return ..() /client/proc/empty_ai_core_toggle_latejoin() set name = "Toggle AI Core Latejoin" set category = "Admin" var/list/cores = list() - for(var/obj/structure/aicore/deactivated/D in world) - cores["[D] ([D.loc.loc])"] = D + for(var/obj/structure/aicore/deactivated/D in global.deactivated_ai_cores) + cores["[D] ([get_area_name(D)])"] = D var/id = input("Which core?", "Toggle AI Core Latejoin", null) as null|anything in cores if(!id) return var/obj/structure/aicore/deactivated/D = cores[id] - if(!D) return + if(!istype(D) || QDELETED(D) || !(D in global.deactivated_ai_cores)) + return if(D in empty_playable_ai_cores) empty_playable_ai_cores -= D - to_chat(src, "\The [id] is now not available for latejoining AIs.") + to_chat(src, "\The [id] is now [SPAN_BAD("not available")] for latejoining AIs.") else empty_playable_ai_cores += D - to_chat(src, "\The [id] is now available for latejoining AIs.") + to_chat(src, "\The [id] is now [SPAN_GOOD("available")] for latejoining AIs.") diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index bdd074d7489a..8b6a10ff259e 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -5,34 +5,36 @@ icon_keyboard = null icon_screen = "invaders" var/random = TRUE - var/list/prizes = list( /obj/item/storage/box/snappops = 200, - /obj/item/toy/blink = 200, - /obj/item/clothing/under/syndicate/tacticool = 200, - /obj/item/toy/sword = 200, - /obj/item/gun/projectile/revolver/capgun = 200, - /obj/item/toy/crossbow = 200, - /obj/item/storage/fancy/crayons = 200, - /obj/item/toy/spinningtoy = 200, - /obj/item/toy/prize/powerloader = 100, - /obj/item/toy/prize/fireripley = 100, - /obj/item/toy/prize/deathripley = 100, - /obj/item/toy/prize/gygax = 100, - /obj/item/toy/prize/durand = 100, - /obj/item/toy/prize/honk = 100, - /obj/item/toy/prize/marauder = 100, - /obj/item/toy/prize/seraph = 100, - /obj/item/toy/prize/mauler = 100, - /obj/item/toy/prize/odysseus = 100, - /obj/item/toy/prize/phazon = 100, - /obj/item/chems/spray/waterflower = 100, - /obj/random/action_figure = 100, - /obj/random/plushie = 100, - /obj/item/sword/cult_toy = 100, - /obj/item/storage/box/large/foam_gun = 100, - /obj/item/storage/box/large/foam_gun/burst = 50, - /obj/item/storage/box/large/foam_gun/revolver = 25, - /obj/item/storage/box/large/foam_gun/revolver/tampered = 1 - ) + var/static/list/prizes = list( + /obj/item/box/snappops = 200, + /obj/item/toy/blink = 200, + /obj/item/clothing/shirt/syndicate/tacticool = 200, + /obj/item/energy_blade/sword/toy = 200, + /obj/item/gun/projectile/revolver/capgun = 200, + /obj/item/gun/launcher/foam/crossbow = 200, + /obj/item/box/fancy/crayons = 200, + /obj/item/toy/spinningtoy = 200, + /obj/item/toy/prize/powerloader = 100, + /obj/item/toy/prize/fireripley = 100, + /obj/item/toy/prize/deathripley = 100, + /obj/item/toy/prize/gygax = 100, + /obj/item/toy/prize/durand = 100, + /obj/item/toy/prize/honk = 100, + /obj/item/toy/prize/marauder = 100, + /obj/item/toy/prize/seraph = 100, + /obj/item/toy/prize/mauler = 100, + /obj/item/toy/prize/odysseus = 100, + /obj/item/toy/prize/phazon = 100, + /obj/item/chems/spray/waterflower = 100, + /obj/random/action_figure = 100, + /obj/random/plushie = 100, + /obj/item/sword/cult_toy = 100, + /obj/item/box/large/foam_gun = 100, + /obj/item/box/large/foam_gun/burst = 50, + /obj/item/box/large/foam_gun/revolver = 25, + /obj/random/plushie/large = 20, + /obj/item/box/large/foam_gun/revolver/tampered = 1 + ) /obj/machinery/computer/arcade/Initialize() . = ..() @@ -264,10 +266,9 @@ enemy_mp = 20 gameover = 0 blocked = 0 - emagged = 1 - + emagged = TRUE enemy_name = "Cuban Pete" name = "Outbomb Cuban Pete" - - attack_hand(user) - return 1 \ No newline at end of file + attack_hand_with_interaction_checks(user) + return TRUE + return ..() \ No newline at end of file diff --git a/code/game/machinery/computer/arcade_orion.dm b/code/game/machinery/computer/arcade_orion.dm index 8eed182b78bc..1a0469832b59 100644 --- a/code/game/machinery/computer/arcade_orion.dm +++ b/code/game/machinery/computer/arcade_orion.dm @@ -4,7 +4,7 @@ ////////////////////////// //Orion Trail Events -#define ORION_TRAIL_RAIDERS "Vox Raiders" +#define ORION_TRAIL_RAIDERS "Space Pirates" #define ORION_TRAIL_FLUX "Interstellar Flux" #define ORION_TRAIL_ILLNESS "Illness" #define ORION_TRAIL_BREAKDOWN "Breakdown" @@ -76,9 +76,9 @@ settlers = list("[usr]") for(var/i=0; i<3; i++) if(prob(50)) - settlers += pick(GLOB.first_names_male) + settlers += pick(global.using_map.first_names_male) else - settlers += pick(GLOB.first_names_female) + settlers += pick(global.using_map.first_names_female) num_traitors = 0 event = ORION_TRAIL_START port = 0 @@ -92,60 +92,60 @@ switch(view) if(ORION_VIEW_MAIN) if(event == ORION_TRAIL_START) //new game? New game. - dat = "

    Orion Trail[emagged ? ": Realism Edition" : ""]


    Learn how our ancestors got to Orion, and have fun in the process!

    Start New Game

    " + dat = "

    Orion Trail[emagged ? ": Realism Edition" : ""]


    Learn how our ancestors got to Orion, and have fun in the process!

    Start New Game

    " show_browser(user, dat, "window=arcade") return else event_title = event - event_actions = "Continue your journey
    " + event_actions = "Continue your journey
    " switch(event) if(ORION_TRAIL_GAMEOVER) event_info = "" - event_actions = "Start New Game
    " + event_actions = "Start New Game
    " if(ORION_TRAIL_SPACEPORT) event_title += ": [stops[port]]" event_desc = "[stopblurbs[port]]" event_info = "" if(port == 9) - event_actions = "Return to the title screen!
    " + event_actions = "Return to the title screen!
    " else - event_actions = "Shove off
    " - event_actions += "Raid Spaceport" + event_actions = "Shove off
    " + event_actions += "Raid Spaceport" if(ORION_TRAIL_SPACEPORT_RAIDED) event_title += ": [stops[port]]" - event_actions = "Shove off" + event_actions = "Shove off" if(ORION_TRAIL_RAIDERS) - event_desc = "You arm yourselves as you prepare to fight off the vox menace!" + event_desc = "You arm yourselves as you prepare to fight off the alien menace!" if(ORION_TRAIL_DERELICT) event_desc = "You come across an unpowered ship drifting slowly in the vastness of space. Sensors indicate there are no lifeforms aboard." if(ORION_TRAIL_ILLNESS) event_desc = "A disease has spread amoungst your crew!" if(ORION_TRAIL_FLUX) event_desc = "You've entered a turbulent region. Slowing down would be better for your ship but would cost more fuel." - event_actions = "Continue as normal
    " - event_actions += "Take it slow
    " + event_actions = "Continue as normal
    " + event_actions += "Take it slow
    " if(ORION_TRAIL_MALFUNCTION) event_info = "" event_desc = "The ship's computers are malfunctioning! You can choose to fix it with a part or risk something going awry." - event_actions = "Continue as normal
    " + event_actions = "Continue as normal
    " if(supplies["3"] != 0) - event_actions += "Fix using a part.
    " + event_actions += "Fix using a part.
    " if(ORION_TRAIL_COLLISION) event_info = "" event_desc = "Something has hit your ship and breached the hull! You can choose to fix it with a part or risk something going awry." - event_actions = "Continue as normal
    " + event_actions = "Continue as normal
    " if(supplies["2"] != 0) - event_actions += "Fix using a part.
    " + event_actions += "Fix using a part.
    " if(ORION_TRAIL_BREAKDOWN) event_info = "" event_desc = "The ship's engines broke down! You can choose to fix it with a part or risk something going awry." - event_actions = "Continue as normal
    " + event_actions = "Continue as normal
    " if(supplies["1"] != 0) - event_actions += "Fix using a part.
    " + event_actions += "Fix using a part.
    " if(ORION_TRAIL_STUCK) event_desc = "You've ran out of fuel. Your only hope to survive is to get refueled by a passing ship, if there are any." if(supplies["5"] == 0) - event_actions = "Wait" + event_actions = "Wait" if(ORION_TRAIL_CARP) event_desc = "You've chanced upon a large carp migration! Known both for their delicious meat as well as their bite, you and your crew arm yourselves for a small hunting trip." if(ORION_TRAIL_MUTINY) @@ -159,18 +159,18 @@ dat += "
    You have [supplies["6"]] cash.
    " for(var/i=1; i<6; i++) var/amm = (i>3?10:1) - dat += "[supplies["[i]"]] [supply_name["[i]"]][event==ORION_TRAIL_SPACEPORT ? ", buy [amm] for [supply_cost["[i]"]]T" : ""]
    " + dat += "[supplies["[i]"]] [supply_name["[i]"]][event==ORION_TRAIL_SPACEPORT ? ", buy [amm] for [supply_cost["[i]"]]T" : ""]
    " if(supplies["[i]"] >= amm && event == ORION_TRAIL_SPACEPORT) - dat += "sell [amm] for [supply_cost["[i]"]]T
    " + dat += "sell [amm] for [supply_cost["[i]"]]T
    " if(ORION_VIEW_CREW) dat = "

    Crew

    View the status of your crew.
    " for(var/i=1;i<=settlers.len;i++) - dat += "[settlers[i]] Kill
    " + dat += "[settlers[i]] Kill
    " dat += "

    View:
    " - dat += "[view==ORION_VIEW_MAIN ? "" : ""]Main[view==ORION_VIEW_MAIN ? "" : ""]
    " - dat += "[view==ORION_VIEW_SUPPLIES ? "" : ""]Supplies[view==ORION_VIEW_SUPPLIES ? "" : ""]
    " - dat += "[view==ORION_VIEW_CREW ? "" : ""]Crew[view==ORION_VIEW_CREW ? "" : ""]

    " + dat += "[view==ORION_VIEW_MAIN ? "" : ""]Main[view==ORION_VIEW_MAIN ? "" : ""]
    " + dat += "[view==ORION_VIEW_SUPPLIES ? "" : ""]Supplies[view==ORION_VIEW_SUPPLIES ? "" : ""]
    " + dat += "[view==ORION_VIEW_CREW ? "" : ""]Crew[view==ORION_VIEW_CREW ? "" : ""]

    " show_browser(user, dat, "window=arcade") /obj/machinery/computer/arcade/orion_trail/OnTopic(user, href_list) @@ -318,7 +318,7 @@ else event_info = "You couldn't fight them off!
    " if(prob(10*settlers.len)) - remove_settler(null, "was kidnapped by the Vox!") + remove_settler(null, "was kidnapped by the pirates!") change_resource(null,-1) change_resource(null,-0.5) if(ORION_TRAIL_DERELICT) @@ -399,19 +399,19 @@ /obj/machinery/computer/arcade/orion_trail/proc/emag_effect(var/event) switch(event) if(ORION_TRAIL_RAIDERS) - if(istype(usr,/mob/living/carbon)) - var/mob/living/carbon/M = usr + if(isliving(usr)) + var/mob/living/M = usr if(prob(50)) to_chat(usr, "You hear battle shouts. The tramping of boots on cold metal. Screams of agony. The rush of venting air. Are you going insane?") - M.hallucination(50, 50) + M.set_hallucination(50, 50) else to_chat(usr, "Something strikes you from behind! It hurts like hell and feel like a blunt weapon, but nothing is there...") M.take_organ_damage(10) else to_chat(usr, "The sounds of battle fill your ears...") if(ORION_TRAIL_ILLNESS) - if(istype(usr,/mob/living/carbon/human)) - var/mob/living/carbon/human/M = usr + if(ishuman(usr)) + var/mob/living/human/M = usr to_chat(M, "An overpowering wave of nausea consumes over you. You hunch over, your stomach's contents preparing for a spectacular exit.") M.vomit() else @@ -419,11 +419,11 @@ if(ORION_TRAIL_CARP) to_chat(usr, " Something bit you!") var/mob/living/M = usr - M.adjustBruteLoss(10) + M.take_damage(10) if(ORION_TRAIL_FLUX) - if(istype(usr,/mob/living/carbon) && prob(75)) - var/mob/living/carbon/M = usr - M.Weaken(3) + if(isliving(usr) && prob(75)) + var/mob/living/M = usr + SET_STATUS_MAX(M, STAT_WEAK, 3) src.visible_message("A sudden gust of powerful wind slams \the [M] into the floor!", "You hear a large fwooshing sound, followed by a bang.") M.take_organ_damage(10) else @@ -436,8 +436,9 @@ supplies["[i]"] = max(0,supplies["[i]"] + rand(-10,10)) if(ORION_TRAIL_COLLISION) if(prob(90) && !supplies["2"]) - var/turf/simulated/floor/F = src.loc - F.ChangeTurf(/turf/space) + var/turf/floor = src.loc + if(istype(floor) && floor.simulated) + floor.ChangeTurf(/turf/space) src.visible_message("Something slams into the floor around \the [src], exposing it to space!", "You hear something crack and break.") else src.visible_message("Something slams into the floor around \the [src] - luckily, it didn't get through!", "You hear something crack.") @@ -448,9 +449,9 @@ close_browser(M, "window=arcade") for(var/i=0;i<10;i++) sleep(10) - M.Stun(5) - M.adjustBruteLoss(10) - M.adjustFireLoss(10) + SET_STATUS_MAX(M, STAT_STUN, 5) + M.take_damage(10, do_update_health = FALSE) + M.take_damage(10, BURN) usr.gib() //So that people can't cheese it and inject a lot of kelo/bicard before losing @@ -473,18 +474,24 @@ /obj/item/orion_ship name = "model settler ship" desc = "A model spaceship, it looks like those used back in the day when travelling to Orion! It even has a miniature FX-293 reactor, which was renowned for its instability and tendency to explode..." - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state = "ship" w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/lead = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE, + ) var/active = 0 //if the ship is on -/obj/item/orion_ship/examine(mob/user) + +/obj/item/orion_ship/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(!(in_range(user, src))) - return - if(!active) - to_chat(user, "There's a little switch on the bottom. It's flipped down.") - else - to_chat(user, "There's a little switch on the bottom. It's flipped up.") + if(in_range(user, src)) + . += SPAN_NOTICE("There's a little switch on the bottom. It's flipped [active ? "up" : "down"].") + /obj/item/orion_ship/attack_self(mob/user) if(active) return diff --git a/code/game/machinery/computer/area_atmos.dm b/code/game/machinery/computer/area_atmos.dm new file mode 100644 index 000000000000..d6b82399d7ce --- /dev/null +++ b/code/game/machinery/computer/area_atmos.dm @@ -0,0 +1,175 @@ +/obj/machinery/computer/area_atmos + name = "area air control" + desc = "A computer used to control the stationary scrubbers and pumps in the area." + icon_keyboard = "atmos_key" + icon_screen = "area_atmos" + light_color = "#e6ffff" + + var/list/connectedscrubbers = new() + var/status = "" + + var/range = 25 + + //Simple variable to prevent me from doing attack_hand in both this and the child computer + var/zone = "This computer is working on a wireless range, the range is currently limited to 25 meters." + +/obj/machinery/computer/area_atmos/Initialize() + . = ..() + scanscrubbers() + +/obj/machinery/computer/area_atmos/interface_interact(user) + interact(user) + return TRUE + +/obj/machinery/computer/area_atmos/interact(mob/user) + var/dat = {" + + + + + +

    Area Air Control

    + [status]
    + Scan + "} + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in connectedscrubbers) + dat += {" + + + + "} + + dat += {" +
    + [scrubber.name]
    + Pressure: [round(scrubber.air_contents.return_pressure(), 0.01)] kPa
    + Flow Rate: [round(scrubber.last_flow_rate,0.1)] L/s
    +
    + Turn On + Turn Off
    + Load: [round(scrubber.last_power_draw)] W +

    + [zone] + + "} + show_browser(user, "[dat]", "window=miningshuttle;size=400x400") + status = "" + +/obj/machinery/computer/area_atmos/OnTopic(mob/user, href_list) + if((. = ..())) + return + + if(href_list["scan"]) + scanscrubbers() + return TOPIC_REFRESH + else if(href_list["toggle"]) + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = locate(href_list["scrub"]) + + if(!validscrubber(scrubber)) + spawn(2 SECONDS) + status = "ERROR: Couldn't connect to scrubber! (timeout)" + connectedscrubbers -= scrubber + updateUsrDialog() + return TOPIC_REFRESH + + scrubber.update_use_power(text2num(href_list["toggle"]) ? POWER_USE_ACTIVE : POWER_USE_IDLE) + return TOPIC_REFRESH + +/obj/machinery/computer/area_atmos/proc/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + if(!isobj(scrubber) || get_dist(scrubber.loc, src.loc) > src.range || scrubber.loc.z != src.loc.z) + return 0 + + return 1 + +/obj/machinery/computer/area_atmos/proc/scanscrubbers() + connectedscrubbers = new() + + var/found = 0 + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in range(range, src.loc)) + if(istype(scrubber)) + found = 1 + connectedscrubbers += scrubber + + if(!found) + status = "ERROR: No scrubber found!" + + src.updateUsrDialog() + + +/obj/machinery/computer/area_atmos/area + zone = "This computer is working in a wired network limited to this area." + +/obj/machinery/computer/area_atmos/area/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + return isobj(scrubber) && (get_area(scrubber) == get_area(src)) + +/obj/machinery/computer/area_atmos/area/scanscrubbers() + + var/area/A = get_area(src) + if(!A) + return + + connectedscrubbers = list() + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in SSmachines.machinery) + var/turf/T2 = get_turf(scrubber) + if(get_area(T2) == A) + connectedscrubbers += scrubber + if(!length(connectedscrubbers)) + status = "ERROR: No scrubber found!" + updateUsrDialog() + +/obj/machinery/computer/area_atmos/tag + name = "heavy scrubber control" + zone = "This computer is operating industrial scrubbers nearby." + var/last_scan + +/obj/machinery/computer/area_atmos/tag/scanscrubbers() + if(last_scan && ((world.time - last_scan) < 20 SECONDS)) + return FALSE + else + last_scan = world.time + + connectedscrubbers.Cut() + + for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in SSmachines.machinery) + if(scrubber.id_tag == id_tag) + connectedscrubbers += scrubber + + updateUsrDialog() + +/obj/machinery/computer/area_atmos/tag/validscrubber(obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + if(scrubber.id_tag == id_tag) + return TRUE + return FALSE \ No newline at end of file diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index 87312242f9b4..c72e2cc9a962 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -1,9 +1,4 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -var/global/list/priority_air_alarms = list() -var/global/list/minor_air_alarms = list() - - /obj/machinery/computer/atmos_alert name = "atmospheric alert computer" desc = "Used to access the atmospheric sensors." @@ -13,7 +8,7 @@ var/global/list/minor_air_alarms = list() /obj/machinery/computer/atmos_alert/Initialize() . = ..() - atmosphere_alarm.register_alarm(src, /atom/proc/update_icon) + atmosphere_alarm.register_alarm(src, TYPE_PROC_REF(/atom, update_icon)) /obj/machinery/computer/atmos_alert/Destroy() atmosphere_alarm.unregister_alarm(src) @@ -61,16 +56,5 @@ var/global/list/minor_air_alarms = list() for(var/datum/alarm_source/alarm_source in alarm.sources) var/obj/machinery/alarm/air_alarm = alarm_source.source if(istype(air_alarm)) - var/list/new_ref = list("atmos_reset" = 1) - air_alarm.Topic(air_alarm, new_ref, state = air_alarm_topic) - return TOPIC_REFRESH - - -var/datum/topic_state/air_alarm_topic/air_alarm_topic = new() - -/datum/topic_state/air_alarm_topic/href_list(var/mob/user) - var/list/extra_href = list() - extra_href["remote_connection"] = 1 - extra_href["remote_access"] = 1 - - return extra_href + air_alarm.set_alarm(0) + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm deleted file mode 100644 index 553bb683dc9d..000000000000 --- a/code/game/machinery/computer/atmos_control.dm +++ /dev/null @@ -1,41 +0,0 @@ -/obj/item/stock_parts/circuitboard/atmoscontrol - name = "\improper Central Atmospherics Computer Circuitboard" - build_path = /obj/machinery/computer/atmoscontrol - -/obj/machinery/computer/atmoscontrol - name = "\improper Central Atmospherics Computer" - icon = 'icons/obj/computer.dmi' - icon_keyboard = "generic_key" - icon_screen = "comm_logs" - light_color = "#00b000" - density = 1 - anchored = 1.0 - initial_access = list(access_ce) - var/list/monitored_alarm_ids = null - var/datum/nano_module/atmos_control/atmos_control - base_type = /obj/machinery/computer/atmoscontrol - -/obj/machinery/computer/atmoscontrol/laptop - name = "Atmospherics Laptop" - desc = "A cheap laptop." - icon_state = "laptop" - icon_keyboard = "laptop_key" - icon_screen = "atmoslaptop" - density = 0 - -/obj/machinery/computer/atmoscontrol/interface_interact(user) - ui_interact(user) - return TRUE - -/obj/machinery/computer/atmoscontrol/emag_act(var/remaining_carges, var/mob/user) - if(!emagged) - user.visible_message("\The [user] does something \the [src], causing the screen to flash!",\ - "You cause the screen to flash as you gain full control.",\ - "You hear an electronic warble.") - atmos_control.emagged = 1 - return 1 - -/obj/machinery/computer/atmoscontrol/ui_interact(var/mob/user) - if(!atmos_control) - atmos_control = new(src, req_access, monitored_alarm_ids) - atmos_control.ui_interact(user) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 4745a0ca0cb2..5a6e4780c719 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -4,7 +4,6 @@ name = "computer frame" icon = 'icons/obj/items/stock_parts/stock_parts.dmi' icon_state = "unwired" - obj_flags = OBJ_FLAG_ROTATABLE expected_machine_type = "computer" /obj/machinery/constructable_frame/computerframe/on_update_icon() diff --git a/code/game/machinery/computer/central_atmos.dm b/code/game/machinery/computer/central_atmos.dm new file mode 100644 index 000000000000..dd46a3b07f48 --- /dev/null +++ b/code/game/machinery/computer/central_atmos.dm @@ -0,0 +1,33 @@ +/obj/machinery/computer/central_atmos + name = "\improper Central Atmospherics Computer" + icon = 'icons/obj/computer.dmi' + icon_keyboard = "generic_key" + icon_screen = "comm_logs" + light_color = "#00b000" + density = TRUE + anchored = TRUE + initial_access = list(list(access_engine_equip, access_atmospherics)) + base_type = /obj/machinery/computer/central_atmos + var/list/monitored_alarm_ids = null + var/datum/nano_module/atmos_control/atmos_control + +// TODO: replace this with a modular computer at some point +/obj/machinery/computer/central_atmos/laptop + name = "atmospherics laptop" + desc = "A cheap laptop." + icon_state = "laptop" + icon_keyboard = "laptop_key" + icon_screen = "atmoslaptop" + density = FALSE + construct_state = null + base_type = /obj/machinery/computer/central_atmos/laptop + +/obj/machinery/computer/central_atmos/interface_interact(user) + ui_interact(user) + return TRUE + +/obj/machinery/computer/central_atmos/ui_interact(var/mob/user) + if(!atmos_control) + atmos_control = new(src, monitored_alarm_ids) + atmos_control.set_monitored_alarms(monitored_alarm_ids) + atmos_control.ui_interact(user) diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 7f8a99e09d70..82675b7f6f9e 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -1,24 +1,22 @@ /obj/machinery/computer - name = "computer" + name = "computer console" icon = 'icons/obj/computer.dmi' icon_state = "computer" - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE idle_power_usage = 300 active_power_usage = 300 construct_state = /decl/machine_construction/default/panel_closed/computer uncreated_component_parts = null stat_immune = 0 frame_type = /obj/machinery/constructable_frame/computerframe/deconstruct - var/processing = 0 var/icon_keyboard = "generic_key" var/icon_screen = "generic" - var/light_max_bright_on = 0.2 - var/light_inner_range_on = 0.1 - var/light_outer_range_on = 2 + var/light_range_on = 2 + var/light_power_on = 1 var/overlay_layer - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + atom_flags = ATOM_FLAG_CLIMBABLE clicksound = "keyboard" /obj/machinery/computer/Initialize() @@ -26,22 +24,10 @@ overlay_layer = layer update_icon() -/obj/machinery/computer/get_codex_value() - return "computer" - /obj/machinery/computer/emp_act(severity) if(prob(20/severity)) set_broken(TRUE) ..() -/obj/machinery/computer/explosion_act(severity) - ..() - if(!QDELETED(src)) - if(severity == 1 || (severity == 2 && prob(25))) - qdel(src) - else if(prob(100 - (severity * 25))) - verbs.Cut() - set_broken(TRUE) - /obj/machinery/computer/on_update_icon() cut_overlays() @@ -50,7 +36,7 @@ if(reason_broken & MACHINE_BROKEN_NO_PARTS) set_light(0) - icon = 'icons/obj/computer.dmi' + icon = 'icons/obj/computer.dmi' //#FIXME: I really don't know why you'd do that after re-initializing it above. icon_state = "wired" var/screen = get_component_of_type(/obj/item/stock_parts/console_screen) var/keyboard = get_component_of_type(/obj/item/stock_parts/keyboard) @@ -60,14 +46,21 @@ add_overlay(icon_keyboard ? "[icon_keyboard]_off" : "keyboard") return - if(stat & NOPOWER) + var/offline = (stat & NOPOWER) + if(!offline) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os && !os.on) + offline = TRUE + + if(offline) set_light(0) if(icon_keyboard) add_overlay(image(icon,"[icon_keyboard]_off", overlay_layer)) + if(stat & BROKEN) + add_overlay(image(icon,"[icon_state]_broken", overlay_layer)) return - else - set_light(light_max_bright_on, light_inner_range_on, light_outer_range_on, 2, light_color) + set_light(light_range_on, light_power_on, light_color) if(stat & BROKEN) add_overlay(image(icon,"[icon_state]_broken", overlay_layer)) else @@ -90,11 +83,6 @@ I.appearance_flags |= RESET_COLOR return I -/obj/machinery/computer/proc/decode(text) - // Adds line breaks - text = replacetext(text, "\n", "
    ") - return text - /obj/machinery/computer/dismantle(mob/user) if(stat & BROKEN) to_chat(user, "The broken glass falls out.") diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index d43aa2691d8b..4fcf1b94292d 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -15,12 +15,12 @@ /obj/item/card/id/guest/GetAccess() return temp_access -/obj/item/card/id/guest/examine(mob/user) +/obj/item/card/id/guest/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if (!expired) - to_chat(user, SPAN_NOTICE("This pass expires at [worldtime2stationtime(expiration_time)].")) + if (expired) + . += SPAN_WARNING("It expired at [worldtime2stationtime(expiration_time)].") else - to_chat(user, SPAN_WARNING("It expired at [worldtime2stationtime(expiration_time)].")) + . += SPAN_NOTICE("This pass expires at [worldtime2stationtime(expiration_time)].") /obj/item/card/id/guest/read() if (expired) @@ -28,13 +28,13 @@ else to_chat(usr, SPAN_NOTICE("This pass expires at [worldtime2stationtime(expiration_time)].")) - to_chat(usr, SPAN_NOTICE("It grants access to following areas:")) + to_chat(usr, SPAN_NOTICE("It grants access to the following areas:")) for (var/A in temp_access) to_chat(usr, SPAN_NOTICE("[get_access_desc(A)].")) to_chat(usr, SPAN_NOTICE("Issuing reason: [reason].")) /obj/item/card/id/guest/proc/expire() - color = COLOR_BLACK + set_color(COLOR_BLACK) detail_color = COLOR_BLACK update_icon() @@ -50,7 +50,7 @@ icon_state = "guest" icon_keyboard = null icon_screen = "pass" - density = 0 + density = FALSE var/obj/item/card/id/giver var/list/accesses = list() @@ -58,24 +58,25 @@ var/reason = "NOT SPECIFIED" var/duration_max = 60 var/duration = 5 + var/terminal_serial var/list/internal_log = list() var/mode = 0 // 0 - making pass, 1 - viewing logs /obj/machinery/computer/guestpass/Initialize() . = ..() - uid = "[random_id("guestpass_serial_number",100,999)]-G[rand(10,99)]" + terminal_serial = "[random_id("guestpass_serial_number",100,999)]-G[rand(10,99)]" -/obj/machinery/computer/guestpass/attackby(obj/O, mob/user) - if(istype(O, /obj/item/card/id)) - if(!giver && user.unEquip(O)) - O.forceMove(src) - giver = O +/obj/machinery/computer/guestpass/attackby(obj/used_item, mob/user) + if(istype(used_item, /obj/item/card/id)) + if(!giver && user.try_unequip(used_item)) + used_item.forceMove(src) + giver = used_item updateUsrDialog() else if(giver) to_chat(user, SPAN_WARNING("There is already ID card inside.")) - return - ..() + return TRUE + return ..() /obj/machinery/computer/guestpass/interface_interact(var/mob/user) ui_interact(user) @@ -91,7 +92,7 @@ if(giver) data["giver"] = !!giver - data["giver_name"] = giver.rank || giver.assignment || SSjobs.get_by_path(giver.job_access_type).title + data["giver_name"] = giver.position || giver.assignment data["giv_name"] = giv_name var/list/giver_access = list() @@ -151,19 +152,19 @@ giver = null accesses.Cut() else - var/obj/item/I = user.get_active_hand() - if (istype(I, /obj/item/card/id) && user.unEquip(I)) - I.forceMove(src) - giver = I + var/obj/item/used_item = user.get_active_held_item() + if (istype(used_item, /obj/item/card/id) && user.try_unequip(used_item)) + used_item.forceMove(src) + giver = used_item . = TOPIC_REFRESH else if (href_list["print"]) - var/dat = "

    Activity log of guest pass terminal #[uid]


    " + var/dat = "

    Activity log of guest pass terminal #[terminal_serial]


    " for (var/entry in internal_log) dat += "[entry]

    " - var/obj/item/paper/P = new/obj/item/paper( loc ) - P.SetName("activity log") - P.info = dat + var/obj/item/paper/paper = new/obj/item/paper( loc ) + paper.SetName("activity log") + paper.info = dat . = TOPIC_REFRESH else if (href_list["issue"]) @@ -185,7 +186,7 @@ pass.reason = reason pass.SetName("guest pass #[number]") pass.assignment = "Guest" - addtimer(CALLBACK(pass, /obj/item/card/id/guest/proc/expire), duration MINUTES, TIMER_UNIQUE) + addtimer(CALLBACK(pass, TYPE_PROC_REF(/obj/item/card/id/guest, expire)), duration MINUTES, TIMER_UNIQUE) playsound(src.loc, 'sound/machines/ping.ogg', 25, 0) . = TOPIC_REFRESH else if(!giver) diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index a186ccd23209..8128cf6e71da 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -4,12 +4,12 @@ icon_screen = "command" var/mob/living/silicon/current -/obj/machinery/computer/upload/attackby(obj/item/O, mob/user) - if(istype(O, /obj/item/aiModule)) - var/obj/item/aiModule/M = O +/obj/machinery/computer/upload/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/aiModule)) + var/obj/item/aiModule/M = used_item M.install(src, user) - else - ..() + return TRUE + return ..() /obj/machinery/computer/upload/ai name = "\improper AI upload console" diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index ea6b9b702b77..ab639d35a2e9 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -2,54 +2,70 @@ /obj/machinery/computer/message_monitor name = "messaging monitor console" - desc = "Used to access and maintain data on messaging servers. Allows you to view request console messages." + desc = "Used to access and maintain data on messaging servers. Allows you to view request console messages and telecommunication logs." icon_screen = "comm_logs" light_color = "#00b000" + var/hack_icon = "error" - //Server linked to. - var/obj/machinery/message_server/linkedServer = null - //Sparks effect - For emag - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread - //Messages - Saves me time if I want to change something. - var/noserver = "ALERT: No server detected." - var/incorrectkey = "ALERT: Incorrect decryption key!" - var/defaultmsg = "Welcome. Please select an option." - var/rebootmsg = "%$&(£: Critical %$$@ Error // !RestArting! - ?pLeaSe wAit!" - //Computer properties - var/screen = 0 // 0 = Main menu, 1 = Message Logs, 2 = Hacked screen, 3 = Custom Message - var/hacking = 0 // Is it being hacked into by the AI/Cyborg - var/emag = 0 // When it is emagged. + var/const/noserver = "ALERT: No server detected." + var/const/incorrectkey = "ALERT: Incorrect decryption key!" + var/const/defaultmsg = "Welcome. Please select an option." + var/const/rebootmsg = "%$&(£: Critical %$$@ Error // !RestArting! - ?pLeaSe wAit!" + + var/const/SCREEN_MAIN_MENU = 0 + var/const/SCREEN_MESSAGE_LOGS = 1 + var/const/SCREEN_HACKING = 2 + var/screen = SCREEN_MAIN_MENU + var/hacking = FALSE // Is it being hacked into by a silicon? var/message = "System bootup complete. Please select an option." // The message that shows on the main menu. - var/auth = 0 // Are they authenticated? + var/auth = FALSE // Are they authenticated? + var/obj/machinery/network/message_server/tracking_linked_server + +/obj/machinery/computer/message_monitor/Initialize() + set_extension(src, /datum/extension/network_device/lazy) + . = ..() + +/obj/machinery/computer/message_monitor/Destroy() + tracking_linked_server = null + . = ..() -/obj/machinery/computer/message_monitor/attackby(obj/item/O, mob/living/user) +/obj/machinery/computer/message_monitor/proc/get_message_server() + if(!tracking_linked_server || (tracking_linked_server.stat & (NOPOWER|BROKEN))) + tracking_linked_server = null + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/datum/extension/network_device/message_server in network?.devices) + var/obj/machinery/network/message_server/MS = message_server.holder + if(istype(MS) && !(MS.stat & (BROKEN|NOPOWER))) + tracking_linked_server = MS + break + . = tracking_linked_server + +/obj/machinery/computer/message_monitor/attackby(obj/item/used_item, mob/user) if(stat & (NOPOWER|BROKEN)) - ..() - return + return ..() if(!istype(user)) - return - if(isScrewdriver(O) && emag) + return TRUE + if(IS_SCREWDRIVER(used_item) && emagged) //Stops people from just unscrewing the monitor and putting it back to get the console working again. to_chat(user, "It is too hot to mess with!") - return - - ..() - return + return TRUE + return ..() /obj/machinery/computer/message_monitor/emag_act(var/remaining_charges, var/mob/user) + // Will create sparks and print out the console's password. You will then have to wait a while for the console to be back online. - // It'll take more time if there's more characters in the password.. - if(!emag && operable()) - if(!isnull(src.linkedServer)) - emag = 1 - screen = 2 - spark_system.set_up(5, 0, src) - src.spark_system.start() - var/obj/item/paper/monitorkey/MK = new/obj/item/paper/monitorkey - MK.dropInto(loc) + // It'll take more time if there's more characters in the password. + if(!emagged && operable()) + var/obj/machinery/network/message_server/linked_server = get_message_server() + if(linked_server) + emagged = TRUE + screen = SCREEN_HACKING + spark_at(src, amount = 5) + var/obj/item/paper/monitorkey/MK = new(loc) // Will help make emagging the console not so easy to get away with. MK.info += "

    £%@%(*$%&(£&?*(%&£/{}" - spawn(100*length(src.linkedServer.decryptkey)) UnmagConsole() + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/computer/message_monitor, UnemagConsole)), 100*length(linked_server.decryptkey)) message = rebootmsg update_icon() return 1 @@ -57,67 +73,84 @@ to_chat(user, "A no server error appears on the screen.") /obj/machinery/computer/message_monitor/on_update_icon() - if(emag || hacking) + if(emagged || hacking) icon_screen = hack_icon else icon_screen = initial(icon_screen) ..() -/obj/machinery/computer/message_monitor/Initialize() - //Is the server isn't linked to a server, and there's a server available, default it to the first one in the list. - if(!linkedServer) - if(message_servers && message_servers.len > 0) - linkedServer = message_servers[1] - return ..() - /obj/machinery/computer/message_monitor/interface_interact(user) interact(user) return TRUE /obj/machinery/computer/message_monitor/interact(var/mob/living/user) //If the computer is being hacked or is emagged, display the reboot message. - if(hacking || emag) + if(hacking || emagged) message = rebootmsg + + var/obj/machinery/network/message_server/linked_server = get_message_server() + // This must run early so that changing the message actually works. + if(hacking || emagged) + screen = SCREEN_HACKING + else if(!auth || !linked_server || (linked_server.stat & (NOPOWER|BROKEN))) + message = auth ? noserver : message + screen = SCREEN_MAIN_MENU var/list/dat = list() dat += "Message Monitor Console" dat += "

    Message Monitor Console


    " dat += "

    " if(auth) - dat += "

    \[Authenticated\] /" - dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " + dat += "

    \[Authenticated\] /" + dat += " Server Power: [linked_server?.active ? "\[On\]":"\[Off\]"]

    " else - dat += "

    \[Unauthenticated\] /" - dat += " Server Power: [src.linkedServer && src.linkedServer.active ? "\[On\]":"\[Off\]"]

    " - - if(hacking || emag) - screen = 2 - else if(!auth || !linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) - if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) message = noserver - screen = 0 + dat += "

    \[Unauthenticated\] /" + dat += " Server Power: [linked_server?.active ? "\[On\]":"\[Off\]"]

    " switch(screen) //Main menu - if(0) + if(SCREEN_MAIN_MENU) // = TAB var/i = 0 - dat += "
    [++i]. Link To A Server
    " + dat += "
    [++i]. Link To A Server
    " if(auth) - if(!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN))) + if(!linked_server || (linked_server.stat & (NOPOWER|BROKEN))) dat += "
    ERROR: Server not found!
    " else - dat += "
    [++i]. View Request Console Logs
    " - dat += "
    [++i]. Clear Request Console Logs
    " - dat += "
    [++i]. Set Custom Key
    " + dat += "
    [++i]. View Request Console Logs
    " + dat += "
    [++i]. Clear Request Console Logs
    " + dat += "
    [++i]. Set Custom Key
    " else dat += "

    Please authenticate with the server in order to show additional options." - if((istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) && (user.mind.special_role && user.mind.original == user)) + if((isAI(user) || isrobot(user)) && player_is_antag(user.mind)) //Malf/Traitor AIs can bruteforce into the system to gain the Key. - dat += "
    *&@#. Bruteforce Key
    " - + dat += "
    *&@#. Bruteforce Key
    " + //Request Console Logs + if(SCREEN_MESSAGE_LOGS) + var/index = 0 + /* data_rc_msg + X - 5% + var/rec_dpt = "Unspecified" //name of the person - 15% + var/send_dpt = "Unspecified" //name of the sender- 15% + var/message = "Blank" //transferred message - 300px + var/stamp = "Unstamped" - 15% + var/id_auth = "Unauthenticated" - 15% + var/priority = "Normal" - 10% + */ + dat += "
    Back - Refresh

    " + dat += {" + "} + for(var/datum/data_rc_msg/rc in linked_server.rc_msgs) + if(++index > 3000) + break + // Del - Sender - Recepient - Message + // X - Al Green - Your Mom - WHAT UP!? + dat += {" + "} + dat += "
    XSending Dep.Receiving Dep.MessageStampID Auth.Priority.
    X
    [rc.send_dpt][rc.rec_dpt][rc.message][rc.stamp][rc.id_auth][rc.priority]
    " //Hacking screen. - if(2) - if(istype(user, /mob/living/silicon/ai) || istype(user, /mob/living/silicon/robot)) + if(SCREEN_HACKING) + if(issilicon(user)) dat += "Brute-forcing for server key.
    It will take 20 seconds for every character that the password has." dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time." else @@ -157,164 +190,161 @@ 10010000001100100011101010111001001101001011011100110011
    10010000001110100011010000110000101110100001000000111010
    001101001011011010110010100101110"} - - //Request Console Logs - if(4) - - var/index = 0 - /* data_rc_msg - X - 5% - var/rec_dpt = "Unspecified" //name of the person - 15% - var/send_dpt = "Unspecified" //name of the sender- 15% - var/message = "Blank" //transferred message - 300px - var/stamp = "Unstamped" - 15% - var/id_auth = "Unauthenticated" - 15% - var/priority = "Normal" - 10% - */ - dat += "
    Back - Refresh

    " - dat += {" - "} - for(var/datum/data_rc_msg/rc in src.linkedServer.rc_msgs) - index++ - if(index > 3000) - break - // Del - Sender - Recepient - Message - // X - Al Green - Your Mom - WHAT UP!? - dat += {" - "} - dat += "
    XSending Dep.Receiving Dep.MessageStampID Auth.Priority.
    X
    [rc.send_dpt][rc.rec_dpt][rc.message][rc.stamp][rc.id_auth][rc.priority]
    " - dat += "" - message = defaultmsg - var/datum/browser/written/popup = new(user, "message", "Message Monitoring Console", 700, 700) + var/datum/browser/written_digital/popup = new(user, "message", "Message Monitoring Console", 700, 700) popup.set_content(JOINTEXT(dat)) popup.open() return /obj/machinery/computer/message_monitor/proc/BruteForce(mob/user) - if(isnull(linkedServer)) + var/obj/machinery/network/message_server/linked_server = get_message_server() + if(!linked_server) to_chat(user, "Could not complete brute-force: Linked Server Disconnected!") else - var/currentKey = src.linkedServer.decryptkey + var/currentKey = linked_server.decryptkey to_chat(user, "Brute-force completed! The key is '[currentKey]'.") - src.hacking = 0 + hacking = FALSE update_icon() - src.screen = 0 // Return the screen back to normal + screen = SCREEN_MAIN_MENU // Return the screen back to normal + message = defaultmsg // reset it for the next interaction -/obj/machinery/computer/message_monitor/proc/UnmagConsole() - src.emag = 0 +/obj/machinery/computer/message_monitor/proc/UnemagConsole() + emagged = FALSE update_icon() -/obj/machinery/computer/message_monitor/Topic(href, href_list) +/obj/machinery/computer/message_monitor/OnTopic(mob/user, href_list) if((. = ..())) return //Authenticate + var/obj/machinery/network/message_server/linked_server = get_message_server() if (href_list["auth"]) if(auth) - auth = 0 - screen = 0 + auth = FALSE + screen = SCREEN_MAIN_MENU + message = defaultmsg // reset it for the next interaction + . = TOPIC_REFRESH else - var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) - if(dkey && dkey != "") - if(src.linkedServer.decryptkey == dkey) - auth = 1 + var/dkey = trim(input(user, "Please enter the decryption key.") as text|null) + . = TOPIC_HANDLED + if(dkey) + . = TOPIC_REFRESH + if(linked_server?.decryptkey == dkey) + auth = TRUE else message = incorrectkey //Turn the server on/off. - if (href_list["active"]) - if(auth) linkedServer.active = !linkedServer.active + if (href_list["active"] && auth && linked_server) + linked_server.active = !linked_server.active + . = TOPIC_REFRESH + //Find a server if (href_list["find"]) - if(message_servers && message_servers.len > 1) - src.linkedServer = input(usr,"Please select a server.", "Select a server.", null) as null|anything in message_servers + var/list/local_message_servers = list() + var/list/local_zs = SSmapping.get_connected_levels(z) + for(var/obj/machinery/network/message_server/MS in SSmachines.machinery) + if((MS.z in local_zs) && !(MS.stat & (BROKEN|NOPOWER))) + local_message_servers += MS + if(length(local_message_servers) > 1) + tracking_linked_server = input(user, "Please select a server.", "Select a server.", null) as null|anything in local_message_servers message = "NOTICE: Server selected." - else if(message_servers && message_servers.len > 0) - linkedServer = message_servers[1] + else if(length(local_message_servers) > 0) + tracking_linked_server = local_message_servers[1] message = "NOTICE: Only Single Server Detected - Server selected." else message = noserver + linked_server = get_message_server() + . = TOPIC_REFRESH //Clears the request console logs - KEY REQUIRED if (href_list["clearr"]) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + if(!linked_server || (linked_server.stat & (NOPOWER|BROKEN))) message = noserver - else - if(auth) - src.linkedServer.rc_msgs = list() - message = "NOTICE: Logs cleared." + . = TOPIC_REFRESH + else if(auth) + linked_server.rc_msgs = list() + message = "NOTICE: Logs cleared." + . = TOPIC_REFRESH //Change the password - KEY REQUIRED if (href_list["pass"]) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + if(!linked_server || (linked_server.stat & (NOPOWER|BROKEN))) message = noserver - else - if(auth) - var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null) - if(dkey && dkey != "") - if(src.linkedServer.decryptkey == dkey) - var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):")) - if(length(newkey) <= 3) - message = "NOTICE: Decryption key too short!" - else if(length(newkey) > 16) - message = "NOTICE: Decryption key too long!" - else if(newkey && newkey != "") - src.linkedServer.decryptkey = newkey - message = "NOTICE: Decryption key set." - else - message = incorrectkey + . = TOPIC_REFRESH + else if(auth) + var/dkey = trim(input(user, "Please enter the decryption key.") as text|null) + . = TOPIC_HANDLED + if(dkey) + . = TOPIC_REFRESH + if(linked_server.decryptkey == dkey) + var/newkey = trim(input(user,"Please enter the new key (3 - 16 characters max):")) + if(length(newkey) <= 3) + message = "NOTICE: Decryption key too short!" + else if(length(newkey) > 16) + message = "NOTICE: Decryption key too long!" + else if(newkey && newkey != "") + linked_server.decryptkey = newkey + message = "NOTICE: Decryption key set." + else + message = incorrectkey //Hack the Console to get the password if (href_list["hack"]) - if((istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) && (usr.mind.special_role && usr.mind.original == usr)) - src.hacking = 1 - src.screen = 2 - update_icon() + if(issilicon(user) && player_is_antag(user.mind)) + hacking = TRUE + screen = SCREEN_HACKING + . = TOPIC_REFRESH //Time it takes to bruteforce is dependant on the password length. - spawn(100*length(src.linkedServer.decryptkey)) - if(src && src.linkedServer && usr) - BruteForce(usr) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/computer/message_monitor, BruteForceConsole), user, linked_server), 10 SECONDS * length(linked_server.decryptkey)) //Delete the request console log. if (href_list["deleter"]) - //Are they on the view logs screen? - if(screen == 4) - if(!linkedServer || (src.linkedServer.stat & (NOPOWER|BROKEN))) + . = TOPIC_REFRESH + //Make sure they're still on the view logs screen. + if(screen == SCREEN_MESSAGE_LOGS) + if(!linked_server || (linked_server.stat & (NOPOWER|BROKEN))) message = noserver else //if(istype(href_list["delete"], /datum/data_pda_msg)) - src.linkedServer.rc_msgs -= locate(href_list["deleter"]) + linked_server.rc_msgs -= locate(href_list["deleter"]) message = "NOTICE: Log Deleted!" //Request Console Logs - KEY REQUIRED if(href_list["viewr"]) - if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN))) + if(linked_server == null || (linked_server.stat & (NOPOWER|BROKEN))) message = noserver - else - if(auth) - src.screen = 4 + . = TOPIC_REFRESH + else if(auth) + screen = SCREEN_MESSAGE_LOGS + . = TOPIC_REFRESH if (href_list["back"]) - src.screen = 0 - - return interact(usr) + screen = SCREEN_MAIN_MENU + message = defaultmsg // reset it for the next interaction + . = TOPIC_REFRESH + // don't call interact() here, let the prior Topic() call do that via our TOPIC_REFRESH return value +/obj/machinery/computer/message_monitor/proc/BruteForceConsole(var/mob/user, var/decrypting) + var/obj/machinery/network/message_server/linked_server = get_message_server() + if(linked_server && linked_server == decrypting && user) + BruteForce(user) /obj/item/paper/monitorkey - //..() - name = "Monitor Decryption Key" - var/obj/machinery/message_server/server = null + name = "monitor decryption key" + info = "The paper is smudged and unreadable." /obj/item/paper/monitorkey/Initialize() ..() return INITIALIZE_HINT_LATELOAD /obj/item/paper/monitorkey/LateInitialize() - ..() - if(message_servers) - for(var/obj/machinery/message_server/server in message_servers) - if(!isnull(server)) - if(!isnull(server.decryptkey)) - info = "

    Daily Key Reset


    The new message monitor key is '[server.decryptkey]'.
    This key is only intended for personnel granted access to the messaging server. Keep it safe.
    If necessary, change the password to a more secure one." - info_links = info - icon_state = "paper_words" - break \ No newline at end of file + . = ..() + var/turf/T = get_turf(src) + if(!T) + return + var/list/our_z = SSmapping.get_connected_levels(T.z) + for(var/obj/machinery/network/message_server/server in SSmachines.machinery) + if((server.z in our_z) && !(server.stat & (BROKEN|NOPOWER)) && !isnull(server.decryptkey)) + info = "

    Daily Key Reset


    The new message monitor key is '[server.decryptkey]'.
    This key is only intended for personnel granted access to the messaging server. Keep it safe.
    If necessary, change the password to a more secure one." + info_links = info + update_icon() + break diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm index cae294221edc..37b55f182398 100644 --- a/code/game/machinery/computer/prisoner.dm +++ b/code/game/machinery/computer/prisoner.dm @@ -7,96 +7,86 @@ icon_screen = "explosive" light_color = "#a91515" initial_access = list(access_armory) - var/id = 0.0 - var/temp = null - var/status = 0 - var/timeleft = 60 - var/stop = 0.0 - var/screen = 0 // 0 - No Access Denied, 1 - Access allowed + var/locked = FALSE +/obj/machinery/computer/prisoner/interface_interact(user) + interact(user) + return TRUE - attack_ai(var/mob/user as mob) - return src.attack_hand(user) +/obj/machinery/computer/prisoner/interact(var/mob/user) + var/dat = list() + dat += "Prisoner Implant Manager System
    " + if(locked) + dat += "
    Unlock Console" + else + dat += "
    Chemical Implants
    " + for(var/obj/item/implant/chem/chem_implant in global.chem_implants) + var/turf/implant_turf = get_turf(chem_implant) + if(implant_turf && !LEVELS_ARE_Z_CONNECTED(implant_turf.z, src.z)) + continue // Out of range + if(!chem_implant.implanted) + continue + dat += "[chem_implant.imp_in.name] | Remaining Units: [REAGENT_TOTAL_VOLUME(chem_implant.reagents)] | Inject: " + dat += "((1))" + dat += "((5))" + dat += "((10))
    " + dat += "********************************
    " + dat += "
    Tracking Implants
    " + for(var/obj/item/implant/tracking/tracking_implant in global.tracking_implants) + var/turf/implant_turf = get_turf(tracking_implant) + if(implant_turf && !LEVELS_ARE_Z_CONNECTED(implant_turf.z, src.z)) + continue // Out of range + if(!tracking_implant.implanted) + continue + var/area/tracked_area = get_area(tracking_implant) + var/loc_display = tracked_area.proper_name + if(tracking_implant.malfunction) + loc_display = pick(teleportlocs) + dat += "ID: [tracking_implant.id] | Location: [loc_display]
    " + dat += "(Message Holder) |
    " + dat += "********************************
    " + dat += "
    Lock Console" - attack_hand(var/mob/user as mob) - if(..()) - return - user.set_machine(src) - var/dat - dat += "Prisoner Implant Manager System
    " - if(screen == 0) - dat += "
    Unlock Console" - else if(screen == 1) - dat += "
    Chemical Implants
    " - var/turf/Tr = null - for(var/obj/item/implant/chem/C in world) - Tr = get_turf(C) - if((Tr) && !ARE_Z_CONNECTED(Tr.z, src.z)) continue // Out of range - if(!C.implanted) continue - dat += "[C.imp_in.name] | Remaining Units: [C.reagents.total_volume] | Inject: " - dat += "((1))" - dat += "((5))" - dat += "((10))
    " - dat += "********************************
    " - dat += "
    Tracking Implants
    " - for(var/obj/item/implant/tracking/T in world) - Tr = get_turf(T) - if((Tr) && !ARE_Z_CONNECTED(Tr.z, src.z)) continue // Out of range - if(!T.implanted) continue - var/loc_display = "Space" - var/mob/living/carbon/M = T.imp_in - if(!istype(M.loc, /turf/space)) - var/turf/mob_loc = get_turf(M) - loc_display = mob_loc.loc - if(T.malfunction) - loc_display = pick(teleportlocs) - dat += "ID: [T.id] | Location: [loc_display]
    " - dat += "(Message Holder) |
    " - dat += "********************************
    " - dat += "
    Lock Console" + show_browser(user, JOINTEXT(dat), "window=computer;size=400x500") + onclose(user, "computer") - show_browser(user, dat, "window=computer;size=400x500") - onclose(user, "computer") +/obj/machinery/computer/prisoner/OnTopic(mob/user, href_list) + if((. = ..())) return + if(href_list["inject"]) + var/obj/item/implant/chem/chem_implant = locate(href_list["inject"]) + if(!chem_implant) + return TOPIC_REFRESH // evidently their copy of the UI is out of date + if(!istype(chem_implant)) // exists but is not a chem implant + // warn that this is likely an href hacking attempt + PRINT_STACK_TRACE("Possible HREF hacking attempt, chem implant inject called on non-chem-implant!") + message_admins("Possible HREF hacking attempt, chem implant inject called on [href_list["inject"]] by [user] (ckey [(user.ckey)])!") + return TOPIC_HANDLED + var/amount_to_inject = clamp(text2num(href_list["amount"]), 1, 10) // don't let href hacking give more than 10 units at once + chem_implant.activate(amount_to_inject) + return TOPIC_HANDLED - Process() - if(!..()) - src.updateDialog() - return - - - Topic(href, href_list) - if(..()) - return - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - - if(href_list["inject1"]) - var/obj/item/implant/I = locate(href_list["inject1"]) - if(I) I.activate(1) - - else if(href_list["inject5"]) - var/obj/item/implant/I = locate(href_list["inject5"]) - if(I) I.activate(5) + else if(href_list["lock"]) + if(allowed(user)) + locked = !locked + return TOPIC_REFRESH + else + to_chat(user, "Unauthorized Access.") + return TOPIC_HANDLED - else if(href_list["inject10"]) - var/obj/item/implant/I = locate(href_list["inject10"]) - if(I) I.activate(10) - - else if(href_list["lock"]) - if(src.allowed(usr)) - screen = !screen - else - to_chat(usr, "Unauthorized Access.") - - else if(href_list["warn"]) - var/warning = sanitize(input(usr,"Message:","Enter your message here!","")) - if(!warning) return - var/obj/item/implant/I = locate(href_list["warn"]) - if((I)&&(I.imp_in)) - var/mob/living/carbon/R = I.imp_in - to_chat(R, "You hear a voice in your head saying: '[warning]'") - - src.updateUsrDialog() - return + else if(href_list["warn"]) + var/warning = sanitize(input(user,"Message:","Enter your message here!","")) + if(!warning) + return TOPIC_HANDLED + var/obj/item/implant/tracking/tracker = locate(href_list["warn"]) + if(!tracker) + return TOPIC_REFRESH // evidently their copy of the UI is out of date + if(!istype(tracker)) // exists but is not a tracking implant + // warn that this is likely an href hacking attempt + PRINT_STACK_TRACE("Possible HREF hacking attempt, tracking implant warn called on non-tracking-implant!") + message_admins("Possible HREF hacking attempt, tracking implant warn called on [href_list["warn"]] by [user] (ckey [(user.ckey)])!") + return TOPIC_HANDLED + to_chat(tracker.imp_in, SPAN_NOTICE("You hear a voice in your head saying: '[warning]'")) + return TOPIC_HANDLED + return TOPIC_NOACTION diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 4bb8e87d5e4f..81e3a6b26706 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -68,7 +68,7 @@ return TOPIC_HANDLED // Antag AI checks - if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user)) + if(!isAI(user) || !player_is_antag(user.mind)) to_chat(user, "Access Denied") return TOPIC_HANDLED @@ -103,52 +103,52 @@ . = TOPIC_REFRESH // Proc: get_cyborgs() -// Parameters: 1 (operator - mob which is operating the console.) +// Parameters: 1 (user - mob which is operating the console.) // Description: Returns NanoUI-friendly list of accessible cyborgs. -/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator) +/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/user) var/list/robots = list() - for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) + for(var/mob/living/silicon/robot/robot in global.silicon_mob_list) // Ignore drones - if(is_drone(R)) + if(isdrone(robot)) continue // Ignore antagonistic cyborgs - if(R.scrambledcodes) + if(robot.scrambledcodes) continue - var/list/robot = list() - robot["name"] = R.name - var/turf/T = get_turf(R) + var/list/robot_data = list() + robot_data["name"] = robot.name + var/turf/T = get_turf(robot) var/area/A = get_area(T) - if(istype(T) && istype(A) && (T.z in GLOB.using_map.contact_levels)) - robot["location"] = "[A.name] ([T.x], [T.y])" + if(istype(T) && istype(A) && isContactLevel(T.z)) + robot_data["location"] = "[A.proper_name] ([T.x], [T.y])" else - robot["location"] = "Unknown" + robot_data["location"] = "Unknown" - if(R.stat) - robot["status"] = "Not Responding" - else if (R.lockcharge) - robot["status"] = "Lockdown" + if(robot.stat) + robot_data["status"] = "Not Responding" + else if (robot.lockcharge) + robot_data["status"] = "Lockdown" else - robot["status"] = "Operational" + robot_data["status"] = "Operational" - if(R.cell) - robot["cell"] = 1 - robot["cell_capacity"] = R.cell.maxcharge - robot["cell_current"] = R.cell.charge - robot["cell_percentage"] = round(R.cell.percent()) + if(robot.cell) + robot_data["cell"] = 1 + robot_data["cell_capacity"] = robot.cell.maxcharge + robot_data["cell_current"] = robot.cell.charge + robot_data["cell_percentage"] = round(robot.cell.percent()) else - robot["cell"] = 0 + robot_data["cell"] = 0 - robot["module"] = R.module ? R.module.name : "None" - robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None" - robot["hackable"] = 0 + robot_data["module"] = robot.module ? robot.module.name : "None" + robot_data["master_ai"] = robot.connected_ai ? robot.connected_ai.name : "None" + robot_data["hackable"] = 0 // Antag AIs know whether linked cyborgs are hacked or not. - if(operator && istype(operator, /mob/living/silicon/ai) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator)) - robot["hacked"] = R.emagged ? 1 : 0 - robot["hackable"] = R.emagged? 0 : 1 - robots.Add(list(robot)) + if(user && isAI(user) && (robot.connected_ai == user) && player_is_antag(user.mind)) + robot_data["hacked"] = robot.emagged ? 1 : 0 + robot_data["hackable"] = robot.emagged? 0 : 1 + robots.Add(list(robot_data)) return robots // Proc: get_cyborg_by_name() @@ -157,6 +157,6 @@ /obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name) if (!name) return - for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) - if(R.name == name) - return R + for(var/mob/living/silicon/robot/robot in global.silicon_mob_list) + if(robot.name == name) + return robot diff --git a/code/game/machinery/computer/shuttle.dm b/code/game/machinery/computer/shuttle.dm index e7879862ae16..a63d6d3b2ead 100644 --- a/code/game/machinery/computer/shuttle.dm +++ b/code/game/machinery/computer/shuttle.dm @@ -9,71 +9,62 @@ var/list/authorized = list( ) - attackby(var/obj/item/card/W as obj, var/mob/user as mob) - if(stat & (BROKEN|NOPOWER)) return +/obj/machinery/computer/shuttle/attackby(var/obj/item/used_item, var/mob/user) + if(stat & (BROKEN|NOPOWER)) return TRUE - var/datum/evacuation_controller/shuttle/evac_control = SSevac.evacuation_controller - if(!istype(evac_control)) - to_chat(user, "This console should not in use on this map. Please report this to a developer.") - return + var/datum/evacuation_controller/shuttle/evac_control = SSevac.evacuation_controller + if(!istype(evac_control)) + to_chat(user, "This console should not be in use on this map. Please report this to a developer.") + return TRUE - if ((!( istype(W, /obj/item/card) ) || SSevac.evacuation_controller.has_evacuated() || !( user ))) - return + if(!istype(used_item, /obj/item/card)) // don't try to get an ID card if we're an emag + used_item = used_item.GetIdCard() // handles stored IDs in modcomps and similar - if (istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer)) - if (istype(W, /obj/item/modular_computer)) - W = W.GetIdCard() - if (!W:access) //no access - to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ") - return + if ((!istype(used_item, /obj/item/card) || evac_control.has_evacuated() || !user)) + return FALSE - var/list/cardaccess = W:access - if(!istype(cardaccess, /list) || !cardaccess.len) //no access - to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ") - return + if (istype(used_item, /obj/item/card/id)) + var/obj/item/card/id/id_card = used_item + if(!LAZYISIN(id_card.access, access_bridge)) //doesn't have this access + to_chat(user, "The access level of [id_card.registered_name]\'s card is not high enough.") + return TRUE - if(!(access_bridge in W:access)) //doesn't have this access - to_chat(user, "The access level of [W:registered_name]\'s card is not high enough. ") - return 0 - - var/choice = alert(user, text("Would you like to (un)authorize a shortened launch time? [] authorization\s are still needed. Use abort to cancel all authorizations.", src.auth_need - src.authorized.len), "Shuttle Launch", "Authorize", "Repeal", "Abort") - if(SSevac.evacuation_controller.is_prepared() && user.get_active_hand() != W) - return 0 - switch(choice) - if("Authorize") - src.authorized -= W:registered_name - src.authorized += W:registered_name - if (src.auth_need - src.authorized.len > 0) - message_admins("[key_name_admin(user)] has authorized early shuttle launch") - log_game("[user.ckey] has authorized early shuttle launch") - to_world(text("Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len)) - else - message_admins("[key_name_admin(user)] has launched the shuttle") - log_game("[user.ckey] has launched the shuttle early") - to_world("Alert: Shuttle launch time shortened to 10 seconds!") - SSevac.evacuation_controller.set_launch_time(world.time+100) - //src.authorized = null - qdel(src.authorized) - src.authorized = list( ) + var/choice = alert(user, "Would you like to (un)authorize a shortened launch time? [auth_need - authorized.len] authorization\s are still needed. Use abort to cancel all authorizations.", "Shuttle Launch", "Authorize", "Repeal", "Abort") + if(evac_control.is_prepared() && user.get_active_held_item() != used_item) + return TRUE + switch(choice) + if("Authorize") + src.authorized -= id_card.registered_name + src.authorized += id_card.registered_name + if (src.auth_need - src.authorized.len > 0) + message_admins("[key_name_admin(user)] has authorized early shuttle launch") + log_game("[user.ckey] has authorized early shuttle launch") + to_world("Alert: [auth_need - authorized.len] authorizations needed until shuttle is launched early") + else + message_admins("[key_name_admin(user)] has launched the shuttle") + log_game("[user.ckey] has launched the shuttle early") + to_world("Alert: Shuttle launch time shortened to 10 seconds!") + evac_control.set_launch_time(world.time+100) + //src.authorized = null + qdel(src.authorized) + src.authorized = list( ) - if("Repeal") - src.authorized -= W:registered_name - to_world(text("Alert: [] authorizations needed until shuttle is launched early", src.auth_need - src.authorized.len)) + if("Repeal") + src.authorized -= id_card.registered_name + to_world("Alert: [auth_need - authorized.len] authorizations needed until shuttle is launched early") - if("Abort") - to_world("All authorizations to shortening time for shuttle launch have been revoked!") - src.authorized.len = 0 - src.authorized = list( ) + if("Abort") + to_world("All authorizations to shortening time for shuttle launch have been revoked!") + src.authorized.len = 0 + src.authorized = list( ) + return TRUE - else if (istype(W, /obj/item/card/emag) && !emagged) - var/choice = alert(user, "Would you like to launch the shuttle?","Shuttle control", "Launch", "Cancel") + else if (istype(used_item, /obj/item/card/emag) && !emagged) + var/choice = alert(user, "Would you like to launch the shuttle?","Shuttle control", "Launch", "Cancel") - if(!emagged && !SSevac.evacuation_controller.is_prepared() && user.get_active_hand() == W) - switch(choice) - if("Launch") - to_world("Alert: Shuttle launch time shortened to 10 seconds!") - SSevac.evacuation_controller.set_launch_time(world.time+100) - emagged = 1 - if("Cancel") - return - return + if(!emagged && !evac_control.is_prepared() && user.get_active_held_item() == used_item && choice == "Launch") + to_world("Alert: Shuttle launch time shortened to 10 seconds!") + evac_control.set_launch_time(world.time+100) + emagged = 1 + return TRUE + return FALSE diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index 1fad0bc81536..5c6391328777 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -20,7 +20,7 @@ /obj/machinery/computer/station_alert/Initialize() alarm_monitor = new monitor_type(src) - alarm_monitor.register_alarm(src, /atom/proc/update_icon) + alarm_monitor.register_alarm(src, TYPE_PROC_REF(/atom, update_icon)) . = ..() if(monitor_type) register_monitor(new monitor_type(src)) @@ -34,7 +34,7 @@ return alarm_monitor = monitor - alarm_monitor.register_alarm(src, /atom/proc/update_icon) + alarm_monitor.register_alarm(src, TYPE_PROC_REF(/atom, update_icon)) /obj/machinery/computer/station_alert/proc/unregister_monitor() if(alarm_monitor) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 47803661be76..df5391cc06d8 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -1,8 +1,6 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - //Circuit boards are in /code/game/objects/items/weapons/circuitboards/machinery/ - -/obj/machinery/constructable_frame //Made into a seperate type to make future revisions easier. +///Made into a seperate type to make future revisions easier. +/obj/machinery/constructable_frame name = "machine frame" icon = 'icons/obj/items/stock_parts/stock_parts.dmi' icon_state = "box_0" @@ -11,16 +9,17 @@ use_power = POWER_USE_OFF uncreated_component_parts = null construct_state = /decl/machine_construction/frame/unwrenched + obj_flags = OBJ_FLAG_ROTATABLE + atom_flags = ATOM_FLAG_CLIMBABLE var/obj/item/stock_parts/circuitboard/circuit = null var/expected_machine_type - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE /obj/machinery/constructable_frame/state_transition(decl/machine_construction/new_state) . = ..() update_icon() /obj/machinery/constructable_frame/dismantle() - new /obj/item/stack/material/steel(loc, 5) + SSmaterials.create_object(/decl/material/solid/metal/steel, loc, 5, object_type = /obj/item/stack/material/rods) qdel(src) return TRUE diff --git a/code/game/machinery/cracker.dm b/code/game/machinery/cracker.dm index a0c4fa1b1207..9c6951170b78 100644 --- a/code/game/machinery/cracker.dm +++ b/code/game/machinery/cracker.dm @@ -3,17 +3,16 @@ desc = "An integrated catalytic water cracking system used to break H2O down into H and O." icon = 'icons/obj/machines/cracker.dmi' icon_state = "cracker" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE waterproof = TRUE - volume = 5000 + gas_volume = 5000 use_power = POWER_USE_IDLE idle_power_usage = 100 active_power_usage = 10000 var/tmp/fluid_consumption_per_tick = 100 var/tmp/gas_generated_per_tick = 1 - var/tmp/max_reagents = 100 /obj/machinery/portable_atmospherics/cracker/on_update_icon() icon_state = (use_power == POWER_USE_ACTIVE) ? "cracker_on" : "cracker" @@ -24,41 +23,38 @@ else update_use_power(POWER_USE_IDLE) user.visible_message(SPAN_NOTICE("\The [user] [use_power == POWER_USE_ACTIVE ? "engages" : "disengages"] \the [src].")) - update_icon() return TRUE /obj/machinery/portable_atmospherics/cracker/power_change() . = ..() if(. && (stat & NOPOWER)) update_use_power(POWER_USE_IDLE) - update_icon() /obj/machinery/portable_atmospherics/cracker/set_broken(new_state) . = ..() if(. && (stat & BROKEN)) update_use_power(POWER_USE_IDLE) - update_icon() /obj/machinery/portable_atmospherics/cracker/Process() ..() if(use_power == POWER_USE_IDLE) return - // Produce materials. var/turf/T = get_turf(src) - if(istype(T)) - var/obj/effect/fluid/F = T.return_fluid() - if(istype(F)) + if(!istype(T)) + return + + var/local_fluid = REAGENT_VOLUME(T.reagents, /decl/material/liquid/water) // TODO: make this some list on the material? + if(local_fluid <= 0) + return - // Drink more water! - var/consuming = min(F.reagents.total_volume, fluid_consumption_per_tick) - F.reagents.remove_any(consuming) - T.show_bubbles() + var/consuming = min(REAGENT_TOTAL_VOLUME(T.reagents), fluid_consumption_per_tick) + T.remove_any_reagents(consuming) + T.show_bubbles() - // Gas production. - var/datum/gas_mixture/produced = new - var/gen_amt = min(1, (gas_generated_per_tick * (consuming/fluid_consumption_per_tick))) - produced.adjust_gas(/decl/material/gas/oxygen, gen_amt) - produced.adjust_gas(/decl/material/gas/hydrogen, gen_amt * 2) - produced.temperature = T20C //todo water temperature - air_contents.merge(produced) + var/datum/gas_mixture/produced = new + var/gen_amt = min(1, (gas_generated_per_tick * (consuming/fluid_consumption_per_tick))) + produced.adjust_gas(/decl/material/gas/oxygen, gen_amt) + produced.adjust_gas(/decl/material/gas/hydrogen, gen_amt * 2) + produced.temperature = T20C //todo water temperature + air_contents.merge(produced) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index d768ca75d434..4c44fb58eec4 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -1,3 +1,11 @@ +/proc/despawn_character(mob/living/character) + if(character.client) + character.ghostize() + character.prepare_for_despawn() + character.key = null + character.ckey = null + qdel(character) + /* * Cryogenic refrigeration unit. Basically a despawner. * Stealing a lot of concepts/code from sleepers due to massive laziness. @@ -5,7 +13,6 @@ * since time_entered, which is world.time when the occupant moves in. */ - //Main cryopod console. /obj/machinery/computer/cryopod @@ -13,18 +20,19 @@ desc = "An interface between crew and the cryogenic storage oversight systems." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "cellconsole" - density = 0 + density = FALSE interact_offline = 1 - var/mode = null + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-24}, "SOUTH":{"y":32}, "EAST":{"x":-24}, "WEST":{"x":24}}' //Used for logging people entering cryosleep and important items they are carrying. var/list/frozen_crew = list() var/list/frozen_items = list() var/list/_admin_logs = list() // _ so it shows first in VV - var/storage_type = "crewmembers" + var/storage_desc = "crewmembers" var/storage_name = "Cryogenic Oversight Control" - var/allow_items = 1 + var/allow_items = TRUE /obj/machinery/computer/cryopod/Destroy() QDEL_NULL_LIST(frozen_items) @@ -36,9 +44,16 @@ icon = 'icons/obj/robot_storage.dmi' icon_state = "console" - storage_type = "cyborgs" + storage_desc = "cyborgs" storage_name = "Robotic Storage Control" - allow_items = 0 + allow_items = FALSE + +/obj/machinery/computer/cryopod/checkpoint + name = "travel oversight console" + desc = "An interface between visitors and the checkpoint systems tasked with keeping track of all visitors who enter or exit from the area." + + storage_desc = "visitors" + storage_name = "Travel Oversight Control" /obj/machinery/computer/cryopod/interface_interact(mob/user) interact(user) @@ -51,18 +66,18 @@ dat += "

    [storage_name]
    " dat += "Welcome, [user.real_name].


    " - dat += "View storage log.
    " + dat += "View storage log.
    " if(allow_items) - dat += "View objects.
    " - dat += "Recover object.
    " - dat += "Recover all objects.
    " + dat += "View objects.
    " + dat += "Recover object.
    " + dat += "Recover all objects.
    " show_browser(user, dat, "window=cryopod_console") onclose(user, "cryopod_console") /obj/machinery/computer/cryopod/OnTopic(user, href_list, state) if(href_list["log"]) - var/dat = "Recently stored [storage_type]


    " + var/dat = "Recently stored [storage_desc]


    " for(var/person in frozen_crew) dat += "[person]
    " dat += "
    " @@ -84,7 +99,7 @@ if(!allow_items) return if(frozen_items.len == 0) - to_chat(user, "There is nothing to recover from storage.") + to_chat(user, SPAN_NOTICE("There is nothing to recover from storage.")) return TOPIC_HANDLED var/obj/item/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items @@ -92,10 +107,10 @@ return TOPIC_HANDLED if(!(I in frozen_items)) - to_chat(user, "\The [I] is no longer in storage.") + to_chat(user, SPAN_NOTICE("\The [I] is no longer in storage.")) return TOPIC_HANDLED - visible_message("The console beeps happily as it disgorges \the [I].", range = 3) + visible_message(SPAN_NOTICE("The console beeps happily as it disgorges \the [I]."), range = 3) I.dropInto(loc) frozen_items -= I @@ -105,10 +120,10 @@ if(!allow_items) return TOPIC_HANDLED if(frozen_items.len == 0) - to_chat(user, "There is nothing to recover from storage.") + to_chat(user, SPAN_NOTICE("There is nothing to recover from storage.")) return TOPIC_HANDLED - visible_message("The console beeps happily as it disgorges the desired objects.", range = 3) + visible_message(SPAN_NOTICE("The console beeps happily as it disgorges the desired objects."), range = 3) for(var/obj/item/I in frozen_items) I.dropInto(loc) @@ -116,14 +131,19 @@ . = TOPIC_REFRESH /obj/item/stock_parts/circuitboard/cryopodcontrol - name = "Circuit board (Cryogenic Oversight Console)" + name = "circuit board (Cryogenic Oversight Console)" build_path = /obj/machinery/computer/cryopod - origin_tech = "{'programming':3}" + origin_tech = @'{"programming":3}' /obj/item/stock_parts/circuitboard/robotstoragecontrol - name = "Circuit board (Robotic Storage Console)" + name = "circuit board (Robotic Storage Console)" build_path = /obj/machinery/computer/cryopod/robot - origin_tech = "{'programming':3}" + origin_tech = @'{"programming":3}' + +/obj/item/stock_parts/circuitboard/checkpointcontrol + name = "circuit board (Checkpoint Console)" + build_path = /obj/machinery/computer/cryopod/checkpoint + origin_tech = @'{"programming":3}' //Decorative structures to go alongside cryopods. /obj/structure/cryofeed @@ -132,7 +152,7 @@ desc = "A bewildering tangle of machinery and pipes." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "cryo_rear" - anchored = 1 + anchored = TRUE dir = WEST //Cryopods themselves. @@ -141,47 +161,32 @@ desc = "A man-sized pod for entering suspended animation." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "body_scanner_0" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE dir = WEST var/base_icon_state = "body_scanner_0" var/occupied_icon_state = "body_scanner_1" var/on_store_message = "has entered long-term storage." var/on_store_name = "Cryogenic Oversight" + var/on_store_visible_message = "$TARGET$ hums and hisses as it moves $USER$ into storage." //! A visible message to display when the user is despawned. $USER$ will be replaced with the user's name, $TARGET$ will be replaced with the pod's name. var/on_enter_occupant_message = "You feel cool air surround you. You go numb as your senses turn inward." - var/allow_occupant_types = list(/mob/living/carbon/human) + var/on_enter_visible_message = "$USER$ starts climbing into $TARGET$." //! A visible message to display when the user enters the pod. $USER$ will be replaced with the user's name. + var/allow_occupant_types = list(/mob/living/human) var/disallow_occupant_types = list() - var/mob/occupant = null // Person waiting to be despawned. + var/mob/living/occupant // Person waiting to be despawned. var/time_till_despawn = 9000 // Down to 15 minutes //30 minutes-ish is too long var/time_entered = 0 // Used to keep track of the safe period. - var/obj/item/radio/intercom/announce // var/obj/machinery/computer/cryopod/control_computer - var/last_no_computer_message = 0 var/applies_stasis = 1 - // These items are preserved when the process() despawn proc occurs. - var/list/preserve_items = list( - /obj/item/integrated_circuit/manipulation/wormhole, - /obj/item/integrated_circuit/input/teleporter_locator, - /obj/item/card/id/captains_spare, - /obj/item/aicard, - /obj/item/mmi, - /obj/item/paicard, - /obj/item/gun, - /obj/item/pinpointer, - /obj/item/clothing/suit, - /obj/item/clothing/shoes/magboots, - /obj/item/blueprints, - /obj/item/clothing/head/helmet/space, - /obj/item/storage/internal - ) - construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 + var/open_sound = 'sound/machines/podopen.ogg' + var/close_sound = 'sound/machines/podclose.ogg' /obj/machinery/cryopod/robot name = "robotic storage unit" @@ -197,6 +202,39 @@ disallow_occupant_types = list(/mob/living/silicon/robot/drone) applies_stasis = 0 +/obj/machinery/cryopod/robot/door + //This inherits from the robot cryo, so synths can be properly cryo'd. If a non-synth enters and is cryo'd, ..() is called and it'll still work. + abstract_type = /obj/machinery/cryopod/robot/door + name = "Airlock of Wonders" + desc = "An airlock that isn't an airlock, and shouldn't exist. Yell at a coder/mapper." + icon = 'icons/obj/machines/pod_doors.dmi' + icon_state = "door_closed" + base_icon_state = "door_closed" + occupied_icon_state = "door_locked" + on_enter_visible_message = "$USER$ steps into $TARGET$." + + time_till_despawn = 1 MINUTE //We want to be much faster then normal cryo, since waiting in an elevator for half an hour is a special kind of hell. + + allow_occupant_types = list(/mob/living/silicon/robot,/mob/living/human) + disallow_occupant_types = list(/mob/living/silicon/robot/drone) + +/obj/machinery/cryopod/robot/door/dorms + name = "Residential District Elevator" + desc = "A small elevator that goes down to the deeper section of the colony." + on_store_message = "has departed for the residential district." + on_store_name = "Residential Oversight" + on_enter_occupant_message = "The elevator door closes slowly, ready to bring you down to the residential district." + on_store_visible_message = "$TARGET$ makes a ding as it moves $USER$ to the residential district." + +/obj/machinery/cryopod/robot/door/checkpoint + name = "automated checkpoint" + desc = "A reinforced, automated checkpoint tracking arrivals and departures from the outpost. Beyond this vault is a small airstrip, then nothing but untamed wilderness." + on_store_message = "has departed from the colony." + on_store_name = "Travel Oversight" + on_enter_occupant_message = "The checkpoint unseals and grinds open, and you step through." + on_store_visible_message = "The checkpoint grinds closed after $TARGET$ passes through it." + time_till_despawn = 1 SECOND + /obj/machinery/cryopod/lifepod name = "life pod" desc = "A man-sized pod for entering suspended animation. Dubbed 'cryocoffin' by more cynical spacers, it is pretty barebone, counting on stasis system to keep the victim alive rather than packing extended supply of food or air. Can be ordered with symbols of common religious denominations to be used in space funerals too." @@ -205,7 +243,7 @@ icon_state = "redpod0" base_icon_state = "redpod0" occupied_icon_state = "redpod1" - var/launched = 0 + var/launched = FALSE var/datum/gas_mixture/airtank /obj/machinery/cryopod/lifepod/Initialize() @@ -219,87 +257,103 @@ return airtank /obj/machinery/cryopod/lifepod/proc/launch() - launched = 1 - for(var/d in GLOB.cardinal) + launched = TRUE + for(var/d in global.cardinal) var/turf/T = get_step(src,d) var/obj/machinery/door/blast/B = locate() in T if(B && B.density) B.force_open() break - var/list/possible_locations = list() - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/O = map_sectors["[z]"] - for(var/obj/effect/overmap/visitable/OO in range(O,2)) - if((OO.sector_flags & OVERMAP_SECTOR_IN_SPACE) || istype(OO,/obj/effect/overmap/visitable/sector/exoplanet)) - possible_locations |= text2num(level) - - var/newz = GLOB.using_map.get_empty_zlevel() - if(possible_locations.len && prob(10)) - newz = pick(possible_locations) - var/turf/nloc = locate(rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE),newz) - if(!istype(nloc, /turf/space)) - explosion(nloc, 1, 2, 3) - playsound(loc,'sound/effects/rocket.ogg',100) - forceMove(nloc) + var/newz + if(prob(90)) + var/list/possible_locations + var/obj/effect/overmap/visitable/O = global.overmap_sectors[z] + if(istype(O)) + for(var/obj/effect/overmap/visitable/OO in range(O,2)) + if((OO.sector_flags & OVERMAP_SECTOR_IN_SPACE) || istype(OO,/obj/effect/overmap/visitable/sector/planetoid)) + // Don't try to escape to the place we just launched from + if(OO == O) + continue + var/datum/level_data/data = OO.get_topmost_level_data() + LAZYDISTINCTADD(possible_locations, text2num(data.level_z)) + if(length(possible_locations)) + newz = pick(possible_locations) + if(!newz) + var/datum/level_data/level = SSmapping.increment_world_z_size(/datum/level_data/space) + newz = level.level_z + + if(newz) + var/turf/nloc = locate(rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE), newz) + if(!isspaceturf(nloc)) + explosion(nloc, 1, 2, 3) + playsound(loc,'sound/effects/rocket.ogg',100) + forceMove(nloc) //Don't use these for in-round leaving // don't tell me what to do chinsky /obj/machinery/cryopod/lifepod/Process() if(SSevac.evacuation_controller && SSevac.evacuation_controller.state >= EVAC_LAUNCHING) if(occupant && !launched) - launch() + INVOKE_ASYNC(src, PROC_REF(launch)) ..() /obj/machinery/cryopod/Destroy() clear_control_computer() if(occupant) occupant.forceMove(loc) - occupant.resting = 1 + occupant.set_posture(/decl/posture/lying/deliberate) . = ..() /obj/machinery/cryopod/Initialize() . = ..() - announce = new /obj/item/radio/intercom(src) find_control_computer() /obj/machinery/cryopod/proc/find_control_computer() if(!control_computer) - control_computer = locate(/obj/machinery/computer/cryopod) in src.loc.loc - GLOB.destroyed_event.register(control_computer, src, .proc/clear_control_computer) + control_computer = locate(/obj/machinery/computer/cryopod) in get_area(src) + if(control_computer) + events_repository.register(/decl/observ/destroyed, control_computer, src, PROC_REF(clear_control_computer)) return control_computer /obj/machinery/cryopod/proc/clear_control_computer() if(control_computer) - GLOB.destroyed_event.unregister(control_computer, src) + events_repository.unregister(/decl/observ/destroyed, control_computer, src) control_computer = null /obj/machinery/cryopod/proc/check_occupant_allowed(mob/M) + + if(!istype(M) || M.anchored) + return FALSE + var/correct_type = 0 for(var/type in allow_occupant_types) if(istype(M, type)) correct_type = 1 break - if(!correct_type) return 0 + if(!correct_type) + return FALSE for(var/type in disallow_occupant_types) if(istype(M, type)) - return 0 + return FALSE - return 1 + return TRUE -/obj/machinery/cryopod/examine(mob/user) +/obj/machinery/cryopod/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if (occupant && user.Adjacent(src)) - occupant.examine(arglist(args)) + . += occupant.get_examine_strings(user, distance, infix, suffix) + +/obj/machinery/cryopod/get_cryogenic_power() + return applies_stasis ? 1 : 0 //Lifted from Unity stasis.dm and refactored. /obj/machinery/cryopod/Process() if(occupant) - if(applies_stasis && iscarbon(occupant) && (world.time > time_entered + 20 SECONDS)) - var/mob/living/carbon/C = occupant - C.SetStasis(2) + if(applies_stasis && (world.time > time_entered + 20 SECONDS)) + occupant.add_mob_modifier(/decl/mob_modifier/stasis, 2 SECONDS, source = src) //Allow a ten minute gap between entering the pod and actually despawning. // Only provide the gap if the occupant hasn't ghosted @@ -313,98 +367,36 @@ despawn_occupant() -// This function can not be undone; do not call this unless you are sure -// Also make sure there is a valid control computer -/obj/machinery/cryopod/robot/despawn_occupant() - var/mob/living/silicon/robot/R = occupant - if(!istype(R)) return ..() - - qdel(R.mmi) - for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc - for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags - O.forceMove(R) - qdel(I) - qdel(R.module) - - . = ..() - // This function can not be undone; do not call this unless you are sure // Also make sure there is a valid control computer /obj/machinery/cryopod/proc/despawn_occupant() //Drop all items into the pod. - for(var/obj/item/W in occupant) - occupant.drop_from_inventory(W) - W.forceMove(src) - - if(W.contents.len) //Make sure we catch anything not handled by qdel() on the items. - for(var/obj/item/O in W.contents) - if(istype(O,/obj/item/storage/internal)) //Stop eating pockets, you fuck! - continue - O.forceMove(src) + for(var/obj/item/equipped_item in occupant.get_equipped_items(include_carried = TRUE)) + occupant.drop_from_inventory(equipped_item) + equipped_item.forceMove(src) + //Make sure we catch anything not handled by qdel() on the items. + for(var/obj/item/contained_item in equipped_item.get_contained_external_atoms()) + contained_item.forceMove(src) //Delete all items not on the preservation list. var/list/items = src.contents.Copy() items -= occupant // Don't delete the occupant - items -= announce // or the autosay radio. items -= component_parts - for(var/obj/item/W in items) - - var/preserve = null - // Snowflaaaake. - if(istype(W, /obj/item/mmi)) - var/obj/item/mmi/brain = W - if(brain.brainmob && brain.brainmob.client && brain.brainmob.key) - preserve = 1 - else - continue - else - for(var/T in preserve_items) - if(istype(W,T)) - preserve = 1 - break + for(var/obj/item/frozen_item in items) - if(!preserve) - qdel(W) + if(!frozen_item.preserve_in_cryopod()) + qdel(frozen_item) + continue + if(control_computer && control_computer.allow_items) + control_computer.frozen_items += frozen_item + frozen_item.forceMove(null) else - if(control_computer && control_computer.allow_items) - control_computer.frozen_items += W - W.forceMove(null) - else - W.forceMove(src.loc) - - //Update any existing objectives involving this mob. - for(var/datum/objective/O in GLOB.all_objectives) - // We don't want revs to get objectives that aren't for heads of staff. Letting - // them win or lose based on cryo is silly so we remove the objective. - if(O.target == occupant.mind) - if(O.owner && O.owner.current) - to_chat(O.owner.current, SPAN_DANGER("You get the feeling your target, [occupant.real_name], is no longer within your reach...")) - qdel(O) - - //Handle job slot/tater cleanup. - if(occupant.mind) - if(occupant.mind.assigned_job) - occupant.mind.assigned_job.clear_slot() - - if(occupant.mind.objectives.len) - occupant.mind.objectives = null - occupant.mind.special_role = null - - // Delete them from datacore. - var/sanitized_name = occupant.real_name - sanitized_name = sanitize(sanitized_name) - var/datum/computer_file/report/crew_record/R = get_crewmember_record(sanitized_name) - if(R) - qdel(R) + frozen_item.forceMove(get_turf(src)) icon_state = base_icon_state - //TODO: Check objectives/mode, update new targets if this mob is the target, spawn new antags? - - //Make an announcement and log the person entering storage. - // Titles should really be fetched from data records // and records should not be fetched by name as there is no guarantee names are unique var/role_alt_title = occupant.mind ? occupant.mind.role_alt_title : "Unknown" @@ -414,14 +406,9 @@ control_computer._admin_logs += "[key_name(occupant)] ([role_alt_title]) at [stationtime2text()]" log_and_message_admins("[key_name(occupant)] ([role_alt_title]) entered cryostorage.") - announce.autosay("[occupant.real_name], [role_alt_title], [on_store_message]", "[on_store_name]") - visible_message("\The [initial(name)] hums and hisses as it moves [occupant.real_name] into storage.", range = 3) - - //This should guarantee that ghosts don't spawn. - occupant.ckey = null - - // Delete the mob. - qdel(occupant) + visible_message(SPAN_NOTICE(capitalize_proper_html(emote_replace_user_tokens(emote_replace_target_tokens(on_store_visible_message, src), occupant)))) + do_telecomms_announcement(src, "[occupant.real_name], [role_alt_title], [on_store_message]", "[on_store_name]") + despawn_character(occupant) set_occupant(null) /obj/machinery/cryopod/proc/attempt_enter(var/mob/target, var/mob/user) @@ -430,10 +417,15 @@ if(alert(target,"Would you like to enter long-term storage?",,"Yes","No") != "Yes") return if(!user.incapacitated() && !user.anchored && user.Adjacent(src) && user.Adjacent(target)) - visible_message("[user] starts putting [target] into \the [src].", range = 3) + if(target == user) + visible_message(SPAN_NOTICE(capitalize_proper_html(emote_replace_user_tokens(emote_replace_target_tokens(on_enter_visible_message, src), usr))), range = 3) + else + visible_message("[user] starts putting [target] into \the [src].", range = 3) if(!do_after(user, 20, src)|| QDELETED(target)) return set_occupant(target) + if(close_sound) + playsound(src, close_sound, 40) // Book keeping! log_and_message_admins("has entered a stasis pod") @@ -442,49 +434,45 @@ src.add_fingerprint(target) //Like grap-put, but for mouse-drop. -/obj/machinery/cryopod/MouseDrop_T(var/mob/target, var/mob/user) - if(!check_occupant_allowed(target)) - return - if(occupant) - to_chat(user, "\The [src] is in use.") - return - - user.visible_message("\The [user] begins placing \the [target] into \the [src].", "You start placing \the [target] into \the [src].") - attempt_enter(target, user) - -/obj/machinery/cryopod/attackby(var/obj/item/G, var/mob/user) - - if(istype(G, /obj/item/grab)) - var/obj/item/grab/grab = G +/obj/machinery/cryopod/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && check_occupant_allowed(dropping)) if(occupant) - to_chat(user, "\The [src] is in use.") - return - - if(!ismob(grab.affecting)) - return - - if(!check_occupant_allowed(grab.affecting)) - return - - attempt_enter(grab.affecting, user) + to_chat(user, SPAN_WARNING("\The [src] is in use.")) + return TRUE + user.visible_message( \ + SPAN_NOTICE("\The [user] begins placing \the [dropping] into \the [src]."), \ + SPAN_NOTICE("You start placing \the [dropping] into \the [src].")) + attempt_enter(dropping, user) + return TRUE + +/obj/machinery/cryopod/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim) && istype(user)) + if(occupant) + to_chat(user, SPAN_NOTICE("\The [src] is in use.")) + return TRUE + if(!check_occupant_allowed(victim)) + return TRUE + attempt_enter(victim, user) + return TRUE return ..() /obj/machinery/cryopod/verb/eject() set name = "Eject Pod" set category = "Object" set src in oview(1) - if(usr.stat != 0) + if(usr.stat != CONSCIOUS) return icon_state = base_icon_state //Eject any items that aren't meant to be in the pod. - var/list/items = contents - component_parts + var/list/items = get_contained_external_atoms() if(occupant) items -= occupant - if(announce) items -= announce - for(var/obj/item/W in items) - W.dropInto(loc) + for(var/obj/item/thing in items) + thing.dropInto(loc) src.go_out() add_fingerprint(usr) @@ -497,19 +485,17 @@ set category = "Object" set src in oview(1) - if(usr.stat != 0 || !check_occupant_allowed(usr)) + if(usr.stat != CONSCIOUS || !check_occupant_allowed(usr)) return if(src.occupant) - to_chat(usr, "\The [src] is in use.") + to_chat(usr, SPAN_WARNING("\The [src] is in use.")) return - for(var/mob/living/carbon/slime/M in range(1,usr)) - if(M.Victim == usr) - to_chat(usr, "You're too busy getting your life sucked out of you.") - return + if(!usr.can_enter_cryopod(usr)) + return - visible_message("\The [usr] starts climbing into \the [src].", range = 3) + visible_message(capitalize_proper_html(emote_replace_user_tokens(emote_replace_target_tokens(on_enter_visible_message, src), usr)), range = 3) if(do_after(usr, 20, src)) @@ -517,7 +503,7 @@ return if(src.occupant) - to_chat(usr, "\The [src] is in use.") + to_chat(usr, SPAN_NOTICE("\The [src] is in use.")) return set_occupant(usr) @@ -537,12 +523,14 @@ occupant.dropInto(loc) set_occupant(null) + if(open_sound) + playsound(src, open_sound, 40) icon_state = base_icon_state return -/obj/machinery/cryopod/proc/set_occupant(var/mob/living/carbon/occupant, var/silent) +/obj/machinery/cryopod/proc/set_occupant(var/mob/living/occupant, var/silent) src.occupant = occupant if(!occupant) SetName(initial(name)) @@ -550,8 +538,8 @@ if(occupant.client) if(!silent) - to_chat(occupant, "[on_enter_occupant_message]") - to_chat(occupant, "If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.") + occupant.visible_message("\The [src] [emote_replace_target_tokens(on_enter_visible_message)]", SPAN_NOTICE(on_enter_occupant_message)) + to_chat(occupant, SPAN_NOTICE("If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.")) occupant.client.perspective = EYE_PERSPECTIVE occupant.client.eye = src occupant.forceMove(src) @@ -570,35 +558,42 @@ desc = "Whoever was inside isn't going to wake up now. It looks like you could pry it open with a crowbar." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "broken_cryo" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/closed = 1 var/busy = 0 var/remains_type = /obj/item/remains/human /obj/structure/broken_cryo/attack_hand(mob/user) - ..() - if (closed) - to_chat(user, "You tug at the glass but can't open it with your hands alone.") + . = ..() + if(.) + return + if(closed) + to_chat(user, SPAN_NOTICE("You tug at the glass, but can't open it further without a crowbar.")) else - to_chat(user, "The glass is already open.") + to_chat(user, SPAN_NOTICE("The glass is already open.")) + return TRUE -/obj/structure/broken_cryo/attackby(obj/item/W, mob/user) +/obj/structure/broken_cryo/attackby(obj/item/used_item, mob/user) if (busy) - to_chat(user, "Someone else is attempting to open this.") - return - if (closed) - if (isCrowbar(W)) - busy = 1 - visible_message("[user] starts to pry the glass cover off of \the [src].") - if (!do_after(user, 50, src)) - visible_message("[user] stops trying to pry the glass off of \the [src].") - busy = 0 - return - closed = 0 + to_chat(user, SPAN_NOTICE("Someone else is attempting to open this.")) + return TRUE + if (!closed) + to_chat(user, SPAN_NOTICE("The glass cover is already open.")) + return TRUE + if (IS_CROWBAR(used_item)) + busy = 1 + visible_message("[user] starts to pry the glass cover off of \the [src].") + if (!do_after(user, 50, src)) + visible_message("[user] stops trying to pry the glass off of \the [src].") busy = 0 - icon_state = "broken_cryo_open" - var/obj/dead = new remains_type(loc) - dead.set_dir(dir) //skeleton is oriented as cryo - else - to_chat(user, "The glass cover is already open.") \ No newline at end of file + return TRUE + closed = 0 + busy = 0 + icon_state = "broken_cryo_open" + var/obj/dead = new remains_type(loc) + dead.set_dir(dir) //skeleton is oriented as cryo + return TRUE + +/obj/machinery/cryopod/proc/on_mob_spawn() + playsound(src, 'sound/machines/ding.ogg', 30, 1) diff --git a/code/game/machinery/dehumidifier.dm b/code/game/machinery/dehumidifier.dm index c02f2972ddc4..f5cfe0fc3318 100644 --- a/code/game/machinery/dehumidifier.dm +++ b/code/game/machinery/dehumidifier.dm @@ -34,15 +34,15 @@ if(panel_open) overlays.Add("dhum-open") -/obj/machinery/dehumidifier/examine(mob/user) +/obj/machinery/dehumidifier/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(.) - to_chat(user, "The dehumidifier is [active ? "on" : "off"] and the hatch is [panel_open ? "open" : "closed"].") + . += "The dehumidifier is [active ? "on" : "off"] and the hatch is [panel_open ? "open" : "closed"]." var/obj/item/cell/cell = get_cell() if(panel_open) - to_chat(user, "The power cell is [cell ? "installed" : "missing"].") + . += "The power cell is [cell ? "installed" : "missing"]." else - to_chat(user, "The charge meter reads [cell ? round(cell.percent(), 1) : 0]%") + . += "The charge meter reads [cell ? round(cell.percent(), 1) : 0]%" /obj/machinery/dehumidifier/proc/set_active(new_active) if(active != new_active) @@ -59,9 +59,10 @@ return TRUE set_active(!active) user.visible_message( - SPAN_NOTICE("[user] switches [active ? "on" : "off"] the [src]."), - SPAN_NOTICE("You switch [active ? "on" : "off"] the [src].")) + SPAN_NOTICE("[user] switches [active ? "on" : "off"] \the [src]."), + SPAN_NOTICE("You switch [active ? "on" : "off"] \the [src].")) return TRUE + return FALSE /obj/machinery/dehumidifier/Process() if(!active) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 277049b21511..7172c5958187 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -9,19 +9,18 @@ name = "deployable barrier" desc = "A deployable barrier. Swipe your ID card to lock/unlock it." icon = 'icons/obj/objects.dmi' - anchored = 0.0 - density = 1 + anchored = FALSE + density = TRUE icon_state = "barrier0" - var/health = 100.0 - var/maxhealth = 100.0 + max_health = 100 var/locked = 0.0 /obj/machinery/deployable/barrier/Initialize() . = ..() icon_state = "barrier[src.locked]" -/obj/machinery/deployable/barrier/attackby(obj/item/W, mob/user) - if (istype(W, /obj/item/card/id)) +/obj/machinery/deployable/barrier/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/card/id)) if (src.allowed(user)) if (src.emagged < 2.0) src.locked = !src.locked @@ -29,49 +28,46 @@ src.icon_state = "barrier[src.locked]" if ((src.locked == 1.0) && (src.emagged < 2.0)) to_chat(user, "Barrier lock toggled on.") - return + return TRUE else if ((src.locked == 0.0) && (src.emagged < 2.0)) to_chat(user, "Barrier lock toggled off.") - return + return TRUE else - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, src) - s.start() + spark_at(src, amount=2, cardinal_only = TRUE) visible_message("BZZzZZzZZzZT") - return - return - else if(isWrench(W)) - if (src.health < src.maxhealth) - src.health = src.maxhealth - src.emagged = 0 - src.req_access = list(access_security) + return TRUE + else if(IS_WRENCH(used_item)) + var/current_max_health = get_max_health() + if (current_health < current_max_health) + current_health = current_max_health + emagged = 0 + req_access = list(access_security) visible_message("[user] repairs \the [src]!") - return + return TRUE else if (src.emagged > 0) src.emagged = 0 src.req_access = list(access_security) visible_message("[user] repairs \the [src]!") - return - return + return TRUE else - switch(W.damtype) - if("fire") - src.health -= W.force * 0.75 - if("brute") - src.health -= W.force * 0.5 - else - if (src.health <= 0) - src.explode() - ..() + switch(used_item.atom_damage_type) + if(BURN) + current_health -= used_item.expend_attack_force(user) * 0.75 + if(BRUTE) + current_health -= used_item.expend_attack_force(user) * 0.5 + if (current_health <= 0) + explode() + return TRUE + return ..() /obj/machinery/deployable/barrier/explosion_act(severity) . = ..() if(. && !QDELETED(src)) if(severity == 1) - health = 0 + current_health = 0 else if(severity == 2) - health -= 25 - if(health <= 0) + current_health -= 25 + if(current_health <= 0) explode() /obj/machinery/deployable/barrier/emp_act(severity) @@ -90,35 +86,28 @@ else return 0 -/obj/machinery/deployable/barrier/proc/explode() +/obj/machinery/deployable/barrier/physically_destroyed(skip_qdel) + SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(src), 1, /obj/item/stack/material/rods) + . = ..() +/obj/machinery/deployable/barrier/proc/explode() visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - new /obj/item/stack/material/rods(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - + spark_at(src, cardinal_only = TRUE) explosion(src.loc,-1,-1,0) - if(src) - qdel(src) + if(!QDELETED(src)) + physically_destroyed() /obj/machinery/deployable/barrier/emag_act(var/remaining_charges, var/mob/user) if (src.emagged == 0) src.emagged = 1 src.req_access.Cut() to_chat(user, "You break the ID authentication lock on \the [src].") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, src) - s.start() + spark_at(src, amount=2, cardinal_only = TRUE) visible_message("BZZzZZzZZzZT") return 1 else if (src.emagged == 1) src.emagged = 2 to_chat(user, "You short out the anchoring mechanism on \the [src].") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, src) - s.start() + spark_at(src, amount=2, cardinal_only = TRUE) visible_message("BZZzZZzZZzZT") return 1 diff --git a/code/game/machinery/doors/_door.dm b/code/game/machinery/doors/_door.dm index c1603df7f6ca..3b1aec756003 100644 --- a/code/game/machinery/doors/_door.dm +++ b/code/game/machinery/doors/_door.dm @@ -6,13 +6,17 @@ desc = "It opens and closes." icon = 'icons/obj/doors/Doorint.dmi' icon_state = "door1" - anchored = 1 - opacity = 1 - density = 1 + anchored = TRUE + opacity = TRUE + density = TRUE layer = CLOSED_DOOR_LAYER interact_offline = TRUE construct_state = /decl/machine_construction/default/panel_closed/door uncreated_component_parts = null + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + max_health = 300 + + var/can_open_manually = TRUE var/open_layer = OPEN_DOOR_LAYER var/closed_layer = CLOSED_DOOR_LAYER @@ -23,9 +27,6 @@ var/glass = 0 var/normalspeed = 1 var/heat_proof = 0 // For glass airlocks/opacity firedoors - var/air_properties_vary_with_direction = 0 - var/maxhealth = 300 - var/health var/destroy_hits = 10 //How many strong hits it takes to destroy the door var/min_force = 10 //minimum amount of force needed to damage the door with a melee weapon var/hitsound = 'sound/weapons/smash.ogg' //sound door makes when hit with a weapon @@ -33,8 +34,7 @@ var/obj/item/stack/material/repairing var/block_air_zones = 1 //If set, air zones cannot merge across the door even when it is opened. var/close_door_at = 0 //When to automatically close the door, if possible - var/list/connections = list("0", "0", "0", "0") - var/list/blend_objects = list(/obj/structure/wall_frame, /obj/structure/window, /obj/structure/grille) // Objects which to blend with + var/connections = 0 var/autoset_access = TRUE // Determines whether the door will automatically set its access from the areas surrounding it. Can be used for mapping. @@ -45,11 +45,25 @@ //Used for intercepting clicks on our turf. Set 0 to disable click interception var/turf_hand_priority = 3 - // turf animation - var/atom/movable/overlay/c_animation = null - atmos_canpass = CANPASS_PROC + var/set_dir_on_update = TRUE + var/begins_closed = TRUE + var/icon_state_open = "door0" + var/icon_state_closed = "door1" + +/obj/machinery/door/get_blend_objects() + var/static/list/blend_objects = list( + /obj/structure/wall_frame, + /obj/structure/window, + /obj/structure/grille, + /obj/machinery/door + ) // Objects which to blend with + return blend_objects + +/obj/machinery/door/proc/can_operate(var/mob/user) + . = istype(user) && !user.restrained() && (!issmall(user) || ishuman(user) || issilicon(user) || isbot(user)) + /obj/machinery/door/attack_generic(var/mob/user, var/damage, var/attack_verb, var/environment_smash) if(environment_smash >= 1) damage = max(damage, 10) @@ -61,8 +75,17 @@ visible_message("\The [user] bonks \the [src] harmlessly.") attack_animation(user) -/obj/machinery/door/Initialize() - set_extension(src, /datum/extension/penetration, /datum/extension/penetration/proc_call, .proc/CheckPenetration) +/obj/machinery/door/Initialize(var/mapload, var/d, var/populate_parts = TRUE, var/obj/structure/door_assembly/assembly = null) + if(!populate_parts) + inherit_from_assembly(assembly) + set_extension(src, /datum/extension/penetration, /datum/extension/penetration/proc_call, PROC_REF(CheckPenetration)) + + if(!begins_closed) + icon_state = icon_state_open + set_density(FALSE) + set_opacity(FALSE) + layer = open_layer + ..() . = INITIALIZE_HINT_LATELOAD @@ -72,31 +95,37 @@ else layer = open_layer - - if(width > 1) - if(dir in list(EAST, WEST)) - bound_width = width * world.icon_size - bound_height = world.icon_size - else - bound_width = world.icon_size - bound_height = width * world.icon_size + set_bounds() if (turf_hand_priority) set_extension(src, /datum/extension/turf_hand, turf_hand_priority) - health = maxhealth #ifdef UNIT_TEST if(autoset_access && length(req_access)) - crash_with("A door with mapped access restrictions was set to autoinitialize access.") + PRINT_STACK_TRACE("A door with mapped access restrictions was set to autoinitialize access.") #endif -/obj/machinery/door/LateInitialize() +/obj/machinery/door/proc/inherit_from_assembly(var/obj/structure/door_assembly/assembly) + if (assembly && istype(assembly)) + frame_type = assembly.type + if(assembly.electronics) + var/obj/item/stock_parts/circuitboard/electronics = assembly.electronics + install_component(electronics, FALSE, FALSE) // will be refreshed in parent call; unsafe to refresh prior to calling ..() in Initialize + electronics.construct(src) + return TRUE + +/obj/machinery/door/LateInitialize(mapload, dir=0, populate_parts=TRUE) ..() update_connections(1) update_icon() update_nearby_tiles(need_rebuild=1) - if(autoset_access) // Delayed because apparently the dir is not set by mapping and we need to wait for nearby walls to init and turn us. - inherit_access_from_area() + if(populate_parts && (autoset_access || length(req_access))) // Delayed because apparently the dir is not set by mapping and we need to wait for nearby walls to init and turn us. + var/obj/item/stock_parts/access_lock/lock = install_component(/obj/item/stock_parts/access_lock/buildable, refresh_parts = FALSE) + if(autoset_access) + lock.autoset = TRUE + lock.req_access = get_auto_access() + else + lock.req_access = req_access.Copy() /obj/machinery/door/Destroy() set_density(0) @@ -107,7 +136,7 @@ if(close_door_at && world.time >= close_door_at) if(autoclose) close_door_at = next_close_time() - close() + INVOKE_ASYNC(src, PROC_REF(close)) else close_door_at = 0 @@ -121,44 +150,66 @@ return 0 return 1 +/obj/machinery/door/proc/set_bounds() + if (dir == NORTH || dir == SOUTH) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + /obj/machinery/door/set_density(new_density) . = ..() if(.) explosion_resistance = density ? initial(explosion_resistance) : 0 +/obj/machinery/door/set_dir(new_dir) + if(set_dir_on_update) + if(new_dir & (EAST|WEST)) + new_dir = WEST + else + new_dir = SOUTH + + . = ..(new_dir) + + if(.) + set_bounds() + /obj/machinery/door/Bumped(atom/AM) - if(panel_open || operating) return + if(panel_open || operating) + return + if(ismob(AM)) var/mob/M = AM - if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent shock spam. + if(world.time - M.last_bumped <= 10) + return //Can bump-open one airlock per second. This is to prevent shock spam. M.last_bumped = world.time - if(!M.restrained() && (!issmall(M) || ishuman(M) || issilicon(M))) - bumpopen(M) - return - - if(istype(AM, /mob/living/bot)) - var/mob/living/bot/bot = AM - if(src.check_access(bot.botcard)) - if(density) - open() + bumpopen(M) /obj/machinery/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group) return !block_air_zones + if(air_group) + return !block_air_zones if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) return !opacity return !density /obj/machinery/door/proc/bumpopen(mob/user) - if(operating) return + if(operating || !can_operate(user)) + return if(user.last_airflow > world.time - vsc.airflow_delay) //Fakkit return src.add_fingerprint(user) - if(density) + if(density && can_operate(user)) if(allowed(user)) open() else do_animate("deny") +/obj/machinery/door/physically_destroyed(skip_qdel) + SSmaterials.create_object(/decl/material/solid/metal/steel, loc, 2) + SSmaterials.create_object(/decl/material/solid/metal/steel, loc, 3, /obj/item/stack/material/rods) + . = ..() + /obj/machinery/door/bullet_act(var/obj/item/projectile/Proj) ..() @@ -169,47 +220,43 @@ destroy_hits-- if (destroy_hits <= 0) visible_message("\The [src.name] disintegrates!") - switch (Proj.damage_type) + switch (Proj.atom_damage_type) if(BRUTE) - new /obj/item/stack/material/steel(src.loc, 2) - new /obj/item/stack/material/rods(src.loc, 3) + physically_destroyed() if(BURN) new /obj/effect/decal/cleanable/ash(src.loc) // Turn it to ashes! qdel(src) if(damage) //cap projectile damage so that there's still a minimum number of hits required to break the door - take_damage(min(damage, 100)) + take_damage(min(damage, 100), Proj.atom_damage_type) /obj/machinery/door/hitby(var/atom/movable/AM, var/datum/thrownthing/TT) - visible_message("[src.name] was hit by [AM].") - var/tforce = 0 - if(ismob(AM)) - tforce = 3 * TT.speed - else - tforce = AM:throwforce * (TT.speed/THROWFORCE_SPEED_DIVISOR) - playsound(src.loc, hitsound, 100, 1) - take_damage(tforce) + . = ..() + if(.) + visible_message(SPAN_DANGER("\The [src] was hit by \the [AM].")) + playsound(src.loc, hitsound, 100, 1) + take_damage(AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR)) // This is legacy code that should be revisited, probably by moving the bulk of the logic into here. /obj/machinery/door/physical_attack_hand(user) - if(operating) + if(operating || !can_open_manually) return FALSE - if(allowed(user)) + if(allowed(user) && can_operate(user)) toggle() else if(density) do_animate("deny") - update_icon() return TRUE -/obj/machinery/door/proc/handle_repair(obj/item/I, mob/user) - if(istype(I, /obj/item/stack/material) && I.get_material_type() == src.get_material_type()) +/obj/machinery/door/proc/handle_repair(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/stack/material) && used_item.get_material_type() == src.get_material_type()) if(reason_broken & MACHINE_BROKEN_GENERIC) to_chat(user, "It looks like \the [src] is pretty busted. It's going to need more than just patching up now.") return TRUE - if(health >= maxhealth) + var/current_max_health = get_max_health() + if(current_health >= current_max_health) to_chat(user, "Nothing to fix!") return TRUE if(!density) @@ -217,10 +264,10 @@ return TRUE //figure out how much metal we need - var/amount_needed = (maxhealth - health) / DOOR_REPAIR_AMOUNT + var/amount_needed = (current_max_health - current_health) / DOOR_REPAIR_AMOUNT amount_needed = ceil(amount_needed) - var/obj/item/stack/stack = I + var/obj/item/stack/stack = used_item var/transfer if (repairing) transfer = stack.transfer_to(repairing, amount_needed - repairing.amount) @@ -238,32 +285,32 @@ return TRUE - if(repairing && isWelder(I)) + if(repairing && IS_WELDER(used_item)) if(!density) to_chat(user, "\The [src] must be closed before you can repair it.") return TRUE - var/obj/item/weldingtool/welder = I - if(welder.remove_fuel(0,user)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) to_chat(user, "You start to fix dents and weld \the [repairing] into place.") playsound(src, 'sound/items/Welder.ogg', 100, 1) if(do_after(user, 5 * repairing.amount, src) && welder && welder.isOn()) to_chat(user, "You finish repairing the damage to \the [src].") - health = between(health, health + repairing.amount*DOOR_REPAIR_AMOUNT, maxhealth) + current_health = clamp(current_health + repairing.amount*DOOR_REPAIR_AMOUNT,current_health, get_max_health()) update_icon() qdel(repairing) repairing = null return TRUE - if(repairing && isCrowbar(I)) + if(repairing && IS_CROWBAR(used_item)) to_chat(user, "You remove \the [repairing].") playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) repairing.dropInto(user.loc) repairing = null return TRUE -/obj/machinery/door/attackby(obj/item/I, mob/user) - . = handle_repair(I, user) +/obj/machinery/door/attackby(obj/item/used_item, mob/user) + . = handle_repair(used_item, user) if(.) return return ..() @@ -273,79 +320,92 @@ do_animate("emag") sleep(6) open() - operating = -1 + emagged = TRUE return 1 -/obj/machinery/door/bash(obj/item/I, mob/user) - if(density && user.a_intent == I_HURT && !(I.item_flags & ITEM_FLAG_NO_BLUDGEON)) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) - if(I.force < min_force) - user.visible_message("\The [user] hits \the [src] with \the [I] with no visible effect.") - else - user.visible_message("\The [user] forcefully strikes \the [src] with \the [I]!") - playsound(src.loc, hitsound, 100, 1) - take_damage(I.force) - return TRUE - return FALSE +/obj/machinery/door/bash(obj/item/weapon, mob/user) + if(isliving(user) && !user.check_intent(I_FLAG_HARM)) + return FALSE + if(!weapon.user_can_attack_with(user)) + return FALSE + if(weapon.item_flags & ITEM_FLAG_NO_BLUDGEON) + return FALSE + if(!density) + return FALSE + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(src) + var/force = weapon.expend_attack_force(user) + if(force < min_force) + user.visible_message("\The [user] hits \the [src] with \the [weapon] with no visible effect.") + else + user.visible_message("\The [user] forcefully strikes \the [src] with \the [weapon]!") + playsound(src.loc, hitsound, 100, 1) + take_damage(force, weapon.atom_damage_type) + return TRUE -/obj/machinery/door/take_damage(var/damage) - ..() - var/initialhealth = src.health - src.health = max(0, src.health - damage) - if(src.health <= 0 && initialhealth > 0) - src.set_broken(TRUE) - else if(src.health < src.maxhealth / 4 && initialhealth >= src.maxhealth / 4) - visible_message("\The [src] looks like it's about to break!" ) - else if(src.health < src.maxhealth / 2 && initialhealth >= src.maxhealth / 2) - visible_message("\The [src] looks seriously damaged!" ) - else if(src.health < src.maxhealth * 3/4 && initialhealth >= src.maxhealth * 3/4) - visible_message("\The [src] shows signs of damage!" ) +/obj/machinery/door/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(!current_health) + ..(damage, damage_type) + update_icon() + return + + var/component_damage = get_damage_leakthrough(damage, BRUTE) + damage -= component_damage + + //Part of damage is soaked by our own health + var/current_max_health = get_max_health() + var/initialhealth = current_health + current_health = max(0, current_health - damage) + if(current_health <= 0 && initialhealth > 0) + visible_message(SPAN_WARNING("\The [src] breaks down!")) + set_broken(TRUE) + else if(current_health < current_max_health / 4 && initialhealth >= current_max_health / 4) + visible_message(SPAN_WARNING("\The [src] looks like it's about to break!")) + else if(current_health < current_max_health / 2 && initialhealth >= current_max_health / 2) + visible_message(SPAN_WARNING("\The [src] looks seriously damaged!")) + else if(current_health < current_max_health * 3/4 && initialhealth >= current_max_health * 3/4) + visible_message(SPAN_WARNING("\The [src] shows signs of damage!")) + + ..(component_damage, damage_type) update_icon() -/obj/machinery/door/examine(mob/user) +//How much damage should be passed to components inside even when door health is non zero +/obj/machinery/door/proc/get_damage_leakthrough(var/damage, damtype=BRUTE) + var/current_max_health = get_max_health() + if(current_health > 0.75 * current_max_health && damage < 10) + return 0 + . = round((1 - current_health/current_max_health) * damage) + +/obj/machinery/door/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(src.health <= 0) - to_chat(user, "\The [src] is broken!") - else if(src.health < src.maxhealth / 4) - to_chat(user, "\The [src] looks like it's about to break!") - else if(src.health < src.maxhealth / 2) - to_chat(user, "\The [src] looks seriously damaged!") - else if(src.health < src.maxhealth * 3/4) - to_chat(user, "\The [src] shows signs of damage!") + if(current_health <= 0) + . += SPAN_DANGER("\The [src] is broken!") + else + var/current_max_health = get_max_health() + if(current_health < current_max_health / 4) + . += SPAN_DANGER("\The [src] looks like it's about to break!") + else if(current_health < current_max_health / 2) + . += SPAN_DANGER("\The [src] looks seriously damaged!") + else if(current_health < current_max_health * 3/4) + . += SPAN_WARNING("\The [src] shows signs of damage!") + else if(current_health < current_max_health && get_dist(src, user) <= 1) + . += SPAN_WARNING("\The [src] has some minor scuffing.") + + var/mob/living/human/H = user + if (emagged && istype(H) && (H.skill_check(SKILL_COMPUTER, SKILL_ADEPT) || H.skill_check(SKILL_ELECTRICAL, SKILL_ADEPT))) + . += SPAN_WARNING("\The [src]'s control panel looks fried.") /obj/machinery/door/set_broken(new_state, cause) . = ..() if(. && new_state && (cause & MACHINE_BROKEN_GENERIC)) visible_message("\The [src.name] breaks!") -/obj/machinery/door/explosion_act(severity) - ..() - if(!QDELETED(src)) - if(severity == 1 || (severity == 2 && prob(25))) - qdel(src) - else - if(severity == 2) - take_damage(200) - take_damage(100) - if(prob(80)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, src) - s.start() - /obj/machinery/door/on_update_icon() - if(connections in list(NORTH, SOUTH, NORTH|SOUTH)) - if(connections in list(WEST, EAST, EAST|WEST)) - set_dir(SOUTH) - else - set_dir(EAST) - else - set_dir(SOUTH) - if(density) - icon_state = "door1" + icon_state = icon_state_closed else - icon_state = "door0" + icon_state = icon_state_open + SSradiation.resistance_cache.Remove(get_turf(src)) /obj/machinery/door/proc/do_animate(animation) @@ -368,53 +428,58 @@ flick("door_deny", src) playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) -/obj/machinery/door/proc/open(var/forced = 0) +/obj/machinery/door/proc/open(forced = FALSE) if(!can_open(forced)) - return + return FALSE + operating = 1 do_animate("opening") - icon_state = "door0" - set_opacity(0) - sleep(3) - src.set_density(0) + icon_state = icon_state_open + set_opacity(FALSE) + + sleep(0.5 SECONDS) + src.set_density(FALSE) update_nearby_tiles() - sleep(7) + + sleep(0.5 SECONDS) src.layer = open_layer update_icon() - set_opacity(0) + set_opacity(FALSE) operating = 0 if(autoclose) close_door_at = next_close_time() - return 1 + return TRUE /obj/machinery/door/proc/next_close_time() return world.time + (normalspeed ? 150 : 5) -/obj/machinery/door/proc/close(var/forced = 0) +/obj/machinery/door/proc/close(forced = FALSE) if(!can_close(forced)) - return + return FALSE + operating = 1 close_door_at = 0 do_animate("closing") - sleep(3) - src.set_density(1) - src.layer = closed_layer + + sleep(0.5 SECONDS) + src.set_density(TRUE) update_nearby_tiles() - sleep(7) + src.layer = closed_layer + + sleep(0.5 SECONDS) update_icon() if(visible && !glass) - set_opacity(1) //caaaaarn! + set_opacity(TRUE) operating = 0 //I shall not add a check every x ticks if a door has closed over some fire. var/obj/fire/fire = locate() in loc - if(fire) - qdel(fire) - return + qdel(fire) + return TRUE /obj/machinery/door/proc/toggle(to_open = density) if(to_open) @@ -432,12 +497,12 @@ /obj/machinery/door/update_nearby_tiles(need_rebuild) . = ..() - for(var/turf/simulated/turf in locs) - update_heat_protection(turf) - SSair.mark_for_update(turf) + for(var/turf/turf in locs) + if(turf.simulated) + update_heat_protection(turf) return 1 -/obj/machinery/door/proc/update_heat_protection(var/turf/simulated/source) +/obj/machinery/door/proc/update_heat_protection(var/turf/source) if(istype(source)) if(src.density && (src.opacity || src.heat_proof)) source.thermal_conductivity = DOOR_HEAT_TRANSFER_COEFFICIENT @@ -445,22 +510,13 @@ source.thermal_conductivity = initial(source.thermal_conductivity) /obj/machinery/door/Move(new_loc, new_dir) - update_nearby_tiles() - . = ..() - if(width > 1) - if(dir in list(EAST, WEST)) - bound_width = width * world.icon_size - bound_height = world.icon_size - else - bound_width = world.icon_size - bound_height = width * world.icon_size - + update_nearby_tiles() if(.) dismantle(TRUE) /obj/machinery/door/proc/CheckPenetration(var/base_chance, var/damage) - . = damage/maxhealth*180 + . = damage/get_max_health()*180 if(glass) . *= 2 . = round(.) @@ -473,23 +529,24 @@ /obj/machinery/door/proc/update_connections(var/propagate = 0) var/dirs = 0 - for(var/direction in GLOB.cardinal) + for(var/direction in global.cardinal) var/turf/T = get_step(src, direction) var/success = 0 - if( istype(T, /turf/simulated/wall)) + if( istype(T, /turf/wall)) success = 1 if(propagate) - var/turf/simulated/wall/W = T - W.update_connections(1) - W.update_icon() + for(var/turf/wall/wall in RANGE_TURFS(T, 1)) + wall.wall_connections = null + wall.other_connections = null + wall.queue_icon_update() - else if( istype(T, /turf/simulated/shuttle/wall) || istype(T, /turf/unsimulated/wall)) + else if(istype(T, /turf/unsimulated/wall)) success = 1 else - for(var/obj/O in T) - for(var/b_type in blend_objects) - if( istype(O, b_type)) + for(var/obj/blend_obj in T) + for(var/blend_type in get_blend_objects()) + if( istype(blend_obj, blend_type)) success = 1 if(success) @@ -509,43 +566,59 @@ if (T && !T.density) return get_area(T) -/obj/machinery/door/proc/inherit_access_from_area() +/obj/machinery/door/get_auto_access() var/area/fore = access_area_by_dir(dir) - var/area/aft = access_area_by_dir(GLOB.reverse_dir[dir]) + var/area/aft = access_area_by_dir(global.reverse_dir[dir]) fore = fore || aft aft = aft || fore if (!fore && !aft) - req_access = list() + return list() + else if (fore.override_unlock || aft.override_unlock) + return list() else if (fore.secure || aft.secure) - req_access = req_access_union(fore, aft) + return req_access_union(fore, aft) else - req_access = req_access_diff(fore, aft) + return req_access_diff(fore, aft) + +/obj/machinery/door/get_req_access() + . = list() + for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) + if(lock.locked && length(lock.req_access)) + . |= lock.req_access + + for(var/obj/item/stock_parts/network_receiver/network_lock/lock in get_all_components_of_type(/obj/item/stock_parts/network_receiver/network_lock)) + . |= lock.get_req_access() /obj/machinery/door/do_simple_ranged_interaction(var/mob/user) - if(!requiresID() || allowed(null)) + if((!requiresID() || allowed(null)) && can_operate(user) && can_open_manually) toggle() return TRUE +/obj/machinery/door/components_are_accessible(var/path) + if(ispath(path, /obj/item/stock_parts/circuitboard)) + return TRUE + return ..() + // Public access /decl/public_access/public_method/open_door name = "open door" desc = "Opens the door if possible." - call_proc = /obj/machinery/door/proc/open + call_proc = TYPE_PROC_REF(/obj/machinery/door, open) /decl/public_access/public_method/toggle_door name = "toggle door" desc = "Toggles whether the door is open or not, if possible." - call_proc = /obj/machinery/door/proc/toggle + call_proc = TYPE_PROC_REF(/obj/machinery/door, toggle) /decl/public_access/public_method/toggle_door_to name = "toggle door to" desc = "Toggles the door, depending on the supplied argument, to open (if 1) or closed (if 0)." - call_proc = /obj/machinery/door/proc/toggle + call_proc = TYPE_PROC_REF(/obj/machinery/door, toggle) forward_args = TRUE /decl/public_access/public_method/close_door name = "close door" desc = "Closes the door if possible." - call_proc = /obj/machinery/door/proc/close \ No newline at end of file + call_proc = TYPE_PROC_REF(/obj/machinery/door, close) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 951ae1102560..b19b2f20f189 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -9,23 +9,18 @@ #define AIRLOCK_DENY 5 #define AIRLOCK_EMAG 6 -#define AIRLOCK_PAINTABLE 1 -#define AIRLOCK_STRIPABLE 2 -#define AIRLOCK_DETAILABLE 4 - -var/list/airlock_overlays = list() - /obj/machinery/door/airlock name = "airlock" icon = 'icons/obj/doors/station/door.dmi' icon_state = "preview" power_channel = ENVIRON interact_offline = FALSE - explosion_resistance = 10 - base_type = /obj/machinery/door/airlock frame_type = /obj/structure/door_assembly + icon_state_open = "open" + icon_state_closed = "closed" + material = /decl/material/solid/metal/steel var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in. var/hackProof = 0 // if 1, this door can't be hacked by the AI @@ -34,22 +29,26 @@ var/list/airlock_overlays = list() var/backup_power_lost_until = -1 //World time when backup power is restored. var/next_beep_at = 0 //World time when we may next beep due to doors being blocked by mobs var/shockedby = list() //Some sort of admin logging var - var/spawnPowerRestoreRunning = 0 var/welded = null var/locked = FALSE + /// If TRUE, when operating goes from TRUE to FALSE (i.e. door finishes closing/opening), the door will lock itself. + var/locking = FALSE + /// If TRUE, when operating goes from TRUE to FALSE (i.e. door finishes closing/opening), the door will unlock itself. + var/unlocking = FALSE var/lock_cut_state = BOLTS_FINE var/lights = 1 // Lights show by default var/aiDisabledIdScanner = 0 var/aiHacking = 0 - var/lockdownbyai = 0 autoclose = 1 - var/mineral = null + var/justzap = 0 var/safe = 1 var/speaker = 1 normalspeed = 1 var/hasShocked = 0 //Prevents multiple shocks from happening var/secured_wires = FALSE + /// This state overrides the density-based state while we're doing animations and such. + var/animating_state = 0 var/open_sound_powered = 'sound/machines/airlock_open.ogg' var/open_sound_unpowered = 'sound/machines/airlock_open_force.ogg' @@ -68,32 +67,27 @@ var/list/airlock_overlays = list() //Airlock 2.0 Aesthetics Properties //The variables below determine what color the airlock and decorative stripes will be -Cakey var/airlock_type = "Standard" - var/global/list/airlock_icon_cache = list() - var/paintable = AIRLOCK_PAINTABLE|AIRLOCK_STRIPABLE //0 = Not paintable, 1 = Paintable, 3 = Paintable and Stripable, 7 for Paintable, Stripable and Detailable. + var/static/list/airlock_icon_cache = list() + var/paintable = PAINT_PAINTABLE|PAINT_STRIPABLE|PAINT_WINDOW_PAINTABLE var/door_color = null var/stripe_color = null var/symbol_color = null - - var/fill_file = 'icons/obj/doors/station/fill_steel.dmi' - var/color_file = 'icons/obj/doors/station/color.dmi' - var/color_fill_file = 'icons/obj/doors/station/fill_color.dmi' - var/stripe_file = 'icons/obj/doors/station/stripe.dmi' - var/stripe_fill_file = 'icons/obj/doors/station/fill_stripe.dmi' - var/glass_file = 'icons/obj/doors/station/fill_glass.dmi' - var/bolts_file = 'icons/obj/doors/station/lights_bolts.dmi' - var/deny_file = 'icons/obj/doors/station/lights_deny.dmi' - var/lights_file = 'icons/obj/doors/station/lights_green.dmi' - var/panel_file = 'icons/obj/doors/station/panel.dmi' + var/window_color = null + + var/fill_file = 'icons/obj/doors/station/fill_steel.dmi' + var/color_file = 'icons/obj/doors/station/color.dmi' + var/color_fill_file = 'icons/obj/doors/station/fill_color.dmi' + var/stripe_file = 'icons/obj/doors/station/stripe.dmi' + var/stripe_fill_file = 'icons/obj/doors/station/fill_stripe.dmi' + var/glass_file = 'icons/obj/doors/station/fill_glass.dmi' + var/bolts_file = 'icons/obj/doors/station/lights_bolts.dmi' + var/deny_file = 'icons/obj/doors/station/lights_deny.dmi' + var/lights_file = 'icons/obj/doors/station/lights_green.dmi' + var/panel_file = 'icons/obj/doors/station/panel.dmi' var/sparks_damaged_file = 'icons/obj/doors/station/sparks_damaged.dmi' - var/sparks_broken_file = 'icons/obj/doors/station/sparks_broken.dmi' - var/welded_file = 'icons/obj/doors/station/welded.dmi' - var/emag_file = 'icons/obj/doors/station/emag.dmi' - -/obj/machinery/door/airlock/get_material() - return decls_repository.get_decl(mineral ? mineral : /decl/material/solid/metal/steel) - -/obj/machinery/door/airlock/get_codex_value() - return "airlock" + var/sparks_broken_file = 'icons/obj/doors/station/sparks_broken.dmi' + var/welded_file = 'icons/obj/doors/station/welded.dmi' + var/emag_file = 'icons/obj/doors/station/emag.dmi' /obj/machinery/door/airlock/Process() if(main_power_lost_until > 0 && world.time >= main_power_lost_until) @@ -122,7 +116,7 @@ About the new airlock wires panel: */ /obj/machinery/door/airlock/bumpopen(mob/living/user) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite - if(!issilicon(usr)) + if(!issilicon(user)) if(src.isElectrified()) if(!src.justzap) if(src.shock(user, 100)) @@ -132,16 +126,11 @@ About the new airlock wires panel: return else /*if(src.justzap)*/ return - else if(prob(10) && src.operating == 0) - var/mob/living/carbon/C = user - if(istype(C) && C.hallucination_power > 25) - to_chat(user, SPAN_DANGER("You feel a powerful shock course through your body!")) - user.adjustHalLoss(10) - user.Stun(10) - return - ..(user) - -/obj/machinery/door/airlock/bumpopen(mob/living/simple_animal/user) + else if(prob(10) && src.operating == 0 && user.hallucination_power > 25) + to_chat(user, SPAN_DANGER("You feel a powerful shock course through your body!")) + user.take_damage(10, PAIN) + SET_STATUS_MAX(user, STAT_STUN, 10) + return ..(user) /obj/machinery/door/airlock/proc/isElectrified() @@ -154,10 +143,10 @@ About the new airlock wires panel: return wires.IsIndexCut(wireIndex) /obj/machinery/door/airlock/proc/canAIControl() - return ((src.aiControlDisabled!=1) && (!src.isAllPowerLoss())); + return (!QDELETED(src) && (src.aiControlDisabled!=1) && (!src.isAllPowerLoss())) /obj/machinery/door/airlock/proc/canAIHack() - return ((src.aiControlDisabled==1) && (!hackProof) && (!src.isAllPowerLoss())); + return (!QDELETED(src) && (src.aiControlDisabled==1) && (!hackProof) && (!src.isAllPowerLoss())) /obj/machinery/door/airlock/proc/arePowerSystemsOn() if (stat & (NOPOWER|BROKEN)) @@ -167,6 +156,11 @@ About the new airlock wires panel: /obj/machinery/door/airlock/requiresID() return !(src.isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) +/obj/machinery/door/airlock/check_access(atom/movable/A) + if (isWireCut(AIRLOCK_WIRE_IDSCAN) || aiDisabledIdScanner) + return !secured_wires + return ..() + /obj/machinery/door/airlock/proc/isAllPowerLoss() if(stat & (NOPOWER|BROKEN)) return 1 @@ -288,30 +282,22 @@ About the new airlock wires panel: else return 0 -/obj/machinery/door/airlock/on_update_icon(state=0, override=0) - if(connections in list(NORTH, SOUTH, NORTH|SOUTH)) - if(connections in list(WEST, EAST, EAST|WEST)) - set_dir(SOUTH) - else +/obj/machinery/door/airlock/on_update_icon() + if(set_dir_on_update) + if((connections & (NORTH|SOUTH)) == (NORTH|SOUTH)) set_dir(EAST) - else - set_dir(SOUTH) + else if ((connections & (EAST|WEST)) == (EAST|WEST)) + set_dir(SOUTH) + var/state = animating_state || (density ? AIRLOCK_CLOSED : AIRLOCK_OPEN) switch(state) - if(0) - if(density) - icon_state = "closed" - state = AIRLOCK_CLOSED - else - icon_state = "open" - state = AIRLOCK_OPEN - if(AIRLOCK_OPEN) - icon_state = "open" if(AIRLOCK_CLOSED) - icon_state = "closed" - if(AIRLOCK_OPENING, AIRLOCK_CLOSING, AIRLOCK_EMAG, AIRLOCK_DENY) - icon_state = "" - + icon_state = icon_state_closed + if(AIRLOCK_OPEN) + icon_state = icon_state_open + else + icon_state = "" // this should never happen, this is just what the old code did in this case + animating_state = null set_airlock_overlays(state) /obj/machinery/door/airlock/proc/set_airlock_overlays(state) @@ -328,17 +314,25 @@ About the new airlock wires panel: set_light(0) - if(door_color && !(door_color == "none")) + if(door_color) var/ikey = "[airlock_type]-[door_color]-color" color_overlay = airlock_icon_cache["[ikey]"] if(!color_overlay) color_overlay = new(color_file) color_overlay.Blend(door_color, ICON_MULTIPLY) airlock_icon_cache["[ikey]"] = color_overlay - if(glass) - filling_overlay = glass_file + if(reinf_material) + if (window_color) + var/ikey = "[airlock_type]-[window_color]-windowcolor" + filling_overlay = airlock_icon_cache["[ikey]"] + if (!filling_overlay) + filling_overlay = new(glass_file) + filling_overlay.Blend(window_color, ICON_MULTIPLY) + airlock_icon_cache["[ikey]"] = filling_overlay + else + filling_overlay = glass_file else - if(door_color && !(door_color == "none")) + if(door_color) var/ikey = "[airlock_type]-[door_color]-fillcolor" filling_overlay = airlock_icon_cache["[ikey]"] if(!filling_overlay) @@ -367,12 +361,12 @@ About the new airlock wires panel: if(AIRLOCK_CLOSED) if(lights && locked) lights_overlay = bolts_file - set_light(0.25, 0.1, 1, 2, COLOR_RED_LIGHT) + set_light(2, 0.75, COLOR_RED_LIGHT) if(AIRLOCK_DENY) if(lights) lights_overlay = deny_file - set_light(0.25, 0.1, 1, 2, COLOR_RED_LIGHT) + set_light(2, 0.75, COLOR_RED_LIGHT) if(AIRLOCK_EMAG) sparks_overlay = emag_file @@ -380,22 +374,22 @@ About the new airlock wires panel: if(AIRLOCK_CLOSING) if(lights) lights_overlay = lights_file - set_light(0.25, 0.1, 1, 2, COLOR_LIME) + set_light(2, 0.75, COLOR_LIME) if(AIRLOCK_OPENING) if(lights) lights_overlay = lights_file - set_light(0.25, 0.1, 1, 2, COLOR_LIME) + set_light(2, 0.75, COLOR_LIME) if(stat & BROKEN) damage_overlay = sparks_broken_file - else if(health < maxhealth * 3/4) + else if(current_health < get_max_health() * 3/4) damage_overlay = sparks_damaged_file if(welded) weld_overlay = welded_file - if(panel_open) + if(panel_open || istype(construct_state, /decl/machine_construction/default/panel_closed/door/hacking)) panel_overlay = panel_file if(brace) @@ -423,18 +417,21 @@ About the new airlock wires panel: if("opening") set_airlock_overlays(AIRLOCK_OPENING) flick("opening", src)//[stat ? "_stat":] - update_icon(AIRLOCK_OPEN) + animating_state = AIRLOCK_OPEN + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon), AIRLOCK_OPEN), 1 SECOND) // wait to update icon so the light doesn't go out too soon if("closing") set_airlock_overlays(AIRLOCK_CLOSING) flick("closing", src) - update_icon(AIRLOCK_CLOSED) + animating_state = AIRLOCK_CLOSED + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon), AIRLOCK_CLOSED), 1 SECOND) // wait to update icon so the light doesn't go out too soon if("deny") set_airlock_overlays(AIRLOCK_DENY) if(density && arePowerSystemsOn()) flick("deny", src) if(speaker) playsound(loc, open_failure_access_denied, 50, 0) - update_icon(AIRLOCK_CLOSED) + animating_state = AIRLOCK_CLOSED + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon), AIRLOCK_CLOSED), 1 SECOND) // wait to update icon so the light doesn't go out too soon if("emag") set_airlock_overlays(AIRLOCK_EMAG) if(density && arePowerSystemsOn()) @@ -445,14 +442,15 @@ About the new airlock wires panel: /obj/machinery/door/airlock/attack_robot(mob/user) ui_interact(user) + return TRUE -/obj/machinery/door/airlock/attack_ai(mob/user) +/obj/machinery/door/airlock/attack_ai(mob/living/silicon/ai/user) ui_interact(user) /obj/machinery/door/airlock/attack_ghost(mob/user) ui_interact(user) -/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/data[0] data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) @@ -526,24 +524,22 @@ About the new airlock wires panel: src.attack_ai(user) /obj/machinery/door/airlock/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if (src.isElectrified()) + if (isElectrified()) if (istype(mover, /obj/item)) var/obj/item/i = mover if(i.material && i.material.conductive) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() + spark_at(src, amount=5, cardinal_only = TRUE) return ..() /obj/machinery/door/airlock/physical_attack_hand(mob/user) - if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 100)) + if(!issilicon(user)) + if(isElectrified()) + if(shock(user, 100)) return TRUE . = ..() /obj/machinery/door/airlock/CanUseTopic(var/mob/user) - if(operating < 0) //emagged + if(emagged) //emagged to_chat(user, SPAN_WARNING("Unable to interface: Internal error.")) return STATUS_CLOSE if(issilicon(user) && !src.canAIControl()) @@ -558,63 +554,77 @@ About the new airlock wires panel: return ..() -/obj/machinery/door/airlock/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/door/airlock/OnTopic(mob/user, href_list) + if((. = ..())) + return var/activate = text2num(href_list["activate"]) switch (href_list["command"]) if("idscan") set_idscan(activate, 1) + . = TOPIC_REFRESH if("main_power") if(!main_power_lost_until) - src.loseMainPower() + loseMainPower() + . = TOPIC_REFRESH if("backup_power") if(!backup_power_lost_until) - src.loseBackupPower() + loseBackupPower() + . = TOPIC_REFRESH if("bolts") - if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) - to_chat(usr, "The door bolt control wire is cut - Door bolts permanently dropped.") - else if(activate && src.lock()) - to_chat(usr, "The door bolts have been dropped.") - else if(!activate && src.unlock()) - to_chat(usr, "The door bolts have been raised.") + if(isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + to_chat(user, "The door bolt control wire is cut - Door bolts permanently dropped.") + . = TOPIC_HANDLED + else if(activate && lock()) + to_chat(user, "The door bolts have been dropped.") + . = TOPIC_REFRESH + else if(!activate && unlock()) + to_chat(user, "The door bolts have been raised.") + . = TOPIC_REFRESH if("electrify_temporary") electrify(30 * activate, 1) + . = TOPIC_REFRESH if("electrify_permanently") electrify(-1 * activate, 1) + . = TOPIC_REFRESH if("open") - if(src.welded) - to_chat(usr, text("The airlock has been welded shut!")) - else if(src.locked) - to_chat(usr, text("The door bolts are down!")) + if(welded) + to_chat(user, text("The airlock has been welded shut!")) + . = TOPIC_HANDLED + else if(locked) + to_chat(user, text("The door bolts are down!")) + . = TOPIC_HANDLED else if(activate && density) open() + . = TOPIC_REFRESH else if(!activate && !density) close() + . = TOPIC_REFRESH if("safeties") set_safeties(!activate, 1) if("timing") // Door speed control if(src.isWireCut(AIRLOCK_WIRE_SPEED)) - to_chat(usr, text("The timing wire is cut - Cannot alter timing.")) + to_chat(user, text("The timing wire is cut - Cannot alter timing.")) + . = TOPIC_HANDLED else if (activate && src.normalspeed) - normalspeed = 0 + normalspeed = FALSE + . = TOPIC_REFRESH else if (!activate && !src.normalspeed) - normalspeed = 1 + normalspeed = TRUE + . = TOPIC_REFRESH if("lights") // Lights - if(src.isWireCut(AIRLOCK_WIRE_LIGHT)) - to_chat(usr, "The lights wire is cut - The door lights are permanently disabled.") + if(isWireCut(AIRLOCK_WIRE_LIGHT)) + to_chat(user, "The lights wire is cut - The door lights are permanently disabled.") else if (!activate && src.lights) lights = 0 - to_chat(usr, "The door lights have been disabled.") + . = TOPIC_REFRESH + to_chat(user, "The door lights have been disabled.") else if (activate && !src.lights) lights = 1 - to_chat(usr, "The door lights have been enabled.") - - update_icon() - return 1 + . = TOPIC_REFRESH + to_chat(user, "The door lights have been enabled.") //returns 1 on success, 0 on failure /obj/machinery/door/airlock/proc/cut_bolts(var/obj/item/item, var/mob/user) @@ -622,20 +632,23 @@ About the new airlock wires panel: var/cut_verb var/cut_sound - if(isWelder(item)) - var/obj/item/weldingtool/WT = item - if(!WT.remove_fuel(0,user)) - return 0 + if(IS_WELDER(item)) + var/obj/item/weldingtool/welder = item + if(!welder.weld(0,user)) + return FALSE cut_verb = "cutting" cut_sound = 'sound/items/Welder.ogg' else if(istype(item,/obj/item/gun/energy/plasmacutter)) //They could probably just shoot them out, but who cares! var/obj/item/gun/energy/plasmacutter/cutter = item if(!cutter.slice(user)) - return 0 + return FALSE cut_verb = "cutting" cut_sound = 'sound/items/Welder.ogg' cut_delay *= 0.66 - else if(istype(item,/obj/item/energy_blade/blade) || istype(item,/obj/item/energy_blade/sword)) + else if(istype(item, /obj/item/energy_blade)) // Sharp check is to avoid toys working for this + var/obj/item/energy_blade/blade = item + if(!blade.is_special_cutting_tool(TRUE)) + return FALSE cut_verb = "slicing" cut_sound = "sparks" cut_delay *= 0.66 @@ -644,24 +657,24 @@ About the new airlock wires panel: cut_sound = 'sound/weapons/circsawhit.ogg' cut_delay *= 1.5 - else if(istype(item,/obj/item/twohanded/fireaxe)) + else if(istype(item,/obj/item/bladed/axe/fire)) //special case - zero delay, different message if (src.lock_cut_state == BOLTS_EXPOSED) - return 0 //can't actually cut the bolts, go back to regular smashing - var/obj/item/twohanded/fireaxe/F = item - if (!F.wielded) - return 0 + return FALSE //can't actually cut the bolts, go back to regular smashing + var/obj/item/bladed/axe/fire/F = item + if (!F.is_held_twohanded()) + return FALSE user.visible_message( SPAN_DANGER("\The [user] smashes the bolt cover open!"), SPAN_DANGER("You smash the bolt cover open!") ) playsound(src, 'sound/weapons/smash.ogg', 100, 1) src.lock_cut_state = BOLTS_EXPOSED - return 0 + return FALSE else // I guess you can't cut bolts with that item. Never mind then. - return 0 + return FALSE if (src.lock_cut_state == BOLTS_FINE) user.visible_message( @@ -672,11 +685,11 @@ About the new airlock wires panel: playsound(src, cut_sound, 100, 1) if (do_after(user, cut_delay, src)) user.visible_message( - SPAN_NOTICE("\The [user] removes the bolt cover from [src]"), + SPAN_NOTICE("\The [user] removes the bolt cover from [src]."), SPAN_NOTICE("You remove the cover and expose the door bolts.") ) src.lock_cut_state = BOLTS_EXPOSED - return 1 + return TRUE if (src.lock_cut_state == BOLTS_EXPOSED) user.visible_message( @@ -691,15 +704,15 @@ About the new airlock wires panel: ) src.lock_cut_state = BOLTS_CUT src.unlock(1) //force it - return 1 + return TRUE -/obj/machinery/door/airlock/attackby(var/obj/item/C, var/mob/user) +/obj/machinery/door/airlock/attackby(var/obj/item/used_item, var/mob/user) // Brace is considered installed on the airlock, so interacting with it is protected from electrification. - if(brace && (istype(C.GetIdCard(), /obj/item/card/id/) || istype(C, /obj/item/crowbar/brace_jack))) - return brace.attackby(C, user) + if(brace && (istype(used_item.GetIdCard(), /obj/item/card/id/) || istype(used_item, /obj/item/crowbar/brace_jack))) + return brace.attackby(used_item, user) - if(!brace && istype(C, /obj/item/airlock_brace)) - var/obj/item/airlock_brace/A = C + if(!brace && istype(used_item, /obj/item/airlock_brace)) + var/obj/item/airlock_brace/A = used_item if(!density) to_chat(user, SPAN_WARNING("You must close \the [src] before installing \the [A]!")) return TRUE @@ -707,60 +720,70 @@ About the new airlock wires panel: if(!length(A.req_access) && (alert("\the [A]'s 'Access Not Set' light is flashing. Install it anyway?", "Access not set", "Yes", "No") == "No")) return TRUE - if(do_after(user, 50, src) && density && A && user.unEquip(A, src)) + if(do_after(user, 50, src) && density && A && user.try_unequip(A, src)) to_chat(user, SPAN_NOTICE("You successfully install \the [A].")) brace = A brace.airlock = src update_icon() return TRUE - if(!istype(user, /mob/living/silicon)) + if(!issilicon(user)) if(src.isElectrified()) if(src.shock(user, 75)) return TRUE + if(bash(used_item, user)) + return TRUE + if (!repairing && (reason_broken & MACHINE_BROKEN_GENERIC) && src.locked) //bolted and broken - . = cut_bolts(C, user) + . = cut_bolts(used_item, user) if(!.) . = ..() return - if(!repairing && isWelder(C) && !( operating > 0 ) && density) - var/obj/item/weldingtool/W = C - if(!W.remove_fuel(0,user)) - to_chat(user, SPAN_NOTICE("Your [W.name] doesn't have enough fuel.")) - return + if(!repairing && IS_WELDER(used_item) && !operating && density) + var/obj/item/weldingtool/welder = used_item + if(!welder.weld(0,user)) + to_chat(user, SPAN_NOTICE("Your [welder.name] doesn't have enough fuel.")) + return TRUE playsound(src, 'sound/items/Welder.ogg', 50, 1) user.visible_message(SPAN_WARNING("\The [user] begins welding \the [src] [welded ? "open" : "closed"]!"), SPAN_NOTICE("You begin welding \the [src] [welded ? "open" : "closed"].")) if(do_after(user, (rand(3,5)) SECONDS, src)) - if(density && !(operating > 0) && !repairing) + if(density && !operating && !repairing) playsound(src, 'sound/items/Welder2.ogg', 50, 1) welded = !welded update_icon() - return + return TRUE else to_chat(user, SPAN_NOTICE("You must remain still to complete this task.")) - return + return TRUE - else if(isWirecutter(C) || isMultitool(C) || istype(C, /obj/item/assembly/signaler)) + else if(IS_WIRECUTTER(used_item) || IS_MULTITOOL(used_item) || istype(used_item, /obj/item/assembly/signaler)) return wires.Interact(user) - else if(isCrowbar(C) && !welded && !repairing) - if(arePowerSystemsOn()) - to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it.")) - else if(locked) - to_chat(user, SPAN_WARNING("The airlock's bolts prevent it from being forced.")) - else if(brace) - to_chat(user, SPAN_WARNING("The airlock's brace holds it firmly in place.")) - else - if(density) - open(1) + else if(IS_CROWBAR(used_item)) + if(density && !can_open(TRUE) && component_attackby(used_item, user)) + return TRUE + else if(!repairing) + // Add some minor damage as evidence of forcing. + if(current_health >= get_max_health()) + take_damage(1) + if(arePowerSystemsOn()) + to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it.")) + else if(locked) + to_chat(user, SPAN_WARNING("The airlock's bolts prevent it from being forced.")) + else if(brace) + to_chat(user, SPAN_WARNING("The airlock's brace holds it firmly in place.")) else - close(1) + if(density) + open(1) + else + close(1) + return TRUE - if(istype(C, /obj/item/twohanded/fireaxe) && !arePowerSystemsOn() && !(user.a_intent == I_HURT)) - var/obj/item/twohanded/fireaxe/F = C + if(istype(used_item, /obj/item/bladed/axe/fire) && !arePowerSystemsOn() && !(user.check_intent(I_FLAG_HARM))) + var/obj/item/bladed/axe/fire/F = used_item if(F.is_held_twohanded(user)) if(locked) to_chat(user, SPAN_WARNING("The airlock's bolts prevent it from being forced.")) @@ -771,16 +794,16 @@ About the new airlock wires panel: else close(1) else - if(user.can_wield_item(F)) - to_chat(user, SPAN_WARNING("You need to be holding \the [C] in both hands to do that!")) + if(user.can_twohand_item(F)) + to_chat(user, SPAN_WARNING("You need to be holding \the [used_item] in both hands to do that!")) else - to_chat(user, SPAN_WARNING("You are too small to lever \the [src] open with \the [C]!")) + to_chat(user, SPAN_WARNING("You are too small to lever \the [src] open with \the [used_item]!")) + return TRUE - else if((stat & (BROKEN|NOPOWER)) && istype(user, /mob/living/simple_animal)) + else if((stat & (BROKEN|NOPOWER)) && isanimal(user)) var/mob/living/simple_animal/A = user - var/obj/item/I = A.get_natural_weapon() - if(I.force >= 10) + if(used_item?.expend_attack_force(user) >= 10) if(density) visible_message(SPAN_DANGER("\The [A] forces \the [src] open!")) open(1) @@ -789,33 +812,32 @@ About the new airlock wires panel: close(1) else visible_message(SPAN_NOTICE("\The [A] strains fruitlessly to force \the [src] [density ? "open" : "closed"].")) - return + return TRUE else return ..() -/obj/machinery/door/airlock/bash(obj/item/I, mob/user) - //if door is unbroken, hit with fire axe using harm intent - if (istype(I, /obj/item/twohanded/fireaxe) && !(stat & BROKEN) && user.a_intent == I_HURT) - var/obj/item/twohanded/fireaxe/F = I - if (F.wielded) +/obj/machinery/door/airlock/bash(obj/item/weapon, mob/user) + //if door is unbroken, hit with fire axe using harm intent + if (istype(weapon, /obj/item/bladed/axe/fire) && !(stat & BROKEN) && user.check_intent(I_FLAG_HARM) && weapon.user_can_attack_with(user)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/obj/item/bladed/axe/fire/F = weapon + if (F.is_held_twohanded()) playsound(src, 'sound/weapons/smash.ogg', 100, 1) - health -= F.force_wielded * 2 - if(health <= 0) - user.visible_message(SPAN_DANGER("[user] smashes \the [I] into the airlock's control panel! It explodes in a shower of sparks!"), SPAN_DANGER("You smash \the [I] into the airlock's control panel! It explodes in a shower of sparks!")) - health = 0 + current_health -= F.expend_attack_force(user) * 2 + if(current_health <= 0) + user.visible_message(SPAN_DANGER("[user] smashes \the [weapon] into the airlock's control panel! It explodes in a shower of sparks!"), SPAN_DANGER("You smash \the [weapon] into the airlock's control panel! It explodes in a shower of sparks!")) + current_health = 0 set_broken(TRUE) else - user.visible_message(SPAN_DANGER("[user] smashes \the [I] into the airlock's control panel!")) + user.visible_message(SPAN_DANGER("[user] smashes \the [weapon] into the airlock's control panel!")) return TRUE return ..() /obj/machinery/door/airlock/cannot_transition_to(state_path, mob/user) - if(reason_broken & MACHINE_BROKEN_GENERIC) - return SPAN_WARNING("\The [src] looks broken; try repairing it first.") if(ispath(state_path, /decl/machine_construction/default/deconstructed)) if(brace) return SPAN_NOTICE("Remove \the [brace] first!") - if(operating >= 0) // if emagged, apparently bypass all this crap; that's what < 0 would mean. + if(!emagged) // if emagged, apparently bypass all this crap; if(operating) return SPAN_NOTICE("\The [src] is in use.") if(!welded) @@ -834,9 +856,8 @@ About the new airlock wires panel: var/obj/structure/door_assembly/da = ..() // Note that we're deleted here already. Don't do unsafe stuff. . = da - if(mineral) - da.glass_material = mineral - da.glass = 1 + if(da.can_install_glass) + da.reinf_material = reinf_material da.paintable = paintable da.door_color = door_color @@ -844,11 +865,9 @@ About the new airlock wires panel: da.symbol_color = symbol_color if(moved) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, da) - s.start() + spark_at(da, amount=5, cardinal_only = TRUE) else - da.anchored = 1 + da.anchored = TRUE da.state = 1 da.created_name = name da.update_icon() @@ -859,34 +878,40 @@ About the new airlock wires panel: panel_open = TRUE if(istype(construct_state, /decl/machine_construction/default/panel_closed)) var/decl/machine_construction/default/panel_closed/closed = construct_state - construct_state = closed.down_state + construct_state = GET_DECL(closed.down_state) construct_state.validate_state(src) if (secured_wires) lock() visible_message("\The [src]'s control panel bursts open, sparks spewing out!") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() + spark_at(src, amount=5, cardinal_only = TRUE) /obj/machinery/door/airlock/open(var/forced=0) if(!can_open(forced)) - return 0 + return FALSE use_power_oneoff(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people //if the door is unpowered then it doesn't make sense to hear the woosh of a pneumatic actuator if(arePowerSystemsOn()) - playsound(src.loc, open_sound_powered, 100, 1) + playsound(src.loc, pick(open_sound_powered), 100, 1) else - playsound(src.loc, open_sound_unpowered, 100, 1) + playsound(src.loc, pick(open_sound_unpowered), 100, 1) - return ..() + . = ..() + if(.) + // lock and unlock handle updating for us, we don't want duplicate updates + if(locking) + lock() + else if(unlocking) + unlock() + else + toggle_input_toggle() // this sends an update to anything listening for our status, like docking/airlock controllers /obj/machinery/door/airlock/can_open(var/forced=0) - if(brace) + if(QDELETED(src) || brace) return 0 if(!forced) - if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) + if(emagged || !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) return 0 if(locked || welded) @@ -894,19 +919,19 @@ About the new airlock wires panel: return ..() /obj/machinery/door/airlock/can_close(var/forced=0) - if(locked || welded) + if(QDELETED(src) || locked || welded) return 0 if(!forced) //despite the name, this wire is for general door control. - if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) + if(emagged || !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR)) return 0 return ..() /obj/machinery/door/airlock/close(var/forced=0) if(!can_close(forced)) - return 0 + return FALSE if(safe) for(var/turf/turf in locs) @@ -916,7 +941,7 @@ About the new airlock wires panel: playsound(src.loc, close_failure_blocked, 30, 0, -3) next_beep_at = world.time + SecondsToTicks(10) close_door_at = world.time + 6 - return + return FALSE for(var/turf/turf in locs) for(var/atom/movable/AM in turf) @@ -926,39 +951,60 @@ About the new airlock wires panel: use_power_oneoff(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people if(arePowerSystemsOn()) - playsound(src.loc, close_sound_powered, 100, 1) + playsound(src.loc, pick(close_sound_powered), 100, 1) else - playsound(src.loc, close_sound_unpowered, 100, 1) + playsound(src.loc, pick(close_sound_unpowered), 100, 1) - ..() + . = ..() + if(.) + // lock and unlock handle updating for us, we don't want duplicate updates + if(locking) + lock() + else if(unlocking) + unlock() + else + toggle_input_toggle() // this sends an update to anything listening for our status, like docking/airlock controllers /obj/machinery/door/airlock/proc/lock(var/forced=0) if(locked) - return 0 + return FALSE - if (operating && !forced) return 0 + if (operating && !forced) + unlocking = FALSE + locking = TRUE + return FALSE - if (lock_cut_state == BOLTS_CUT) return 0 //what bolts? + if (lock_cut_state == BOLTS_CUT) return FALSE //what bolts? - src.locked = TRUE + locked = TRUE + locking = FALSE playsound(src, bolts_dropping, 30, 0, -6) audible_message("You hear a click from the bottom of the door.", hearing_distance = 1) update_icon() - return 1 + toggle_input_toggle() // this sends an update to anything listening for our status, like docking/airlock controllers + return TRUE /obj/machinery/door/airlock/proc/unlock(var/forced=0) - if(!src.locked) - return + if(!locked) + return FALSE if (!forced) - if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) - return - - src.locked = FALSE + if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + return FALSE + if(operating) + locking = FALSE + unlocking = TRUE + return FALSE + if(!arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + return FALSE + + locked = FALSE + unlocking = FALSE playsound(src, bolts_rising, 30, 0, -6) audible_message("You hear a click from the bottom of the door.", hearing_distance = 1) update_icon() - return 1 + toggle_input_toggle() // this sends an update to anything listening for our status, like docking/airlock controllers + return TRUE /obj/machinery/door/airlock/proc/toggle_lock(var/forced = 0) return locked ? unlock() : lock() @@ -968,13 +1014,16 @@ About the new airlock wires panel: return 0 return ..(M) -/obj/machinery/door/airlock/Initialize(var/mapload, var/d, var/populate_parts = TRUE, var/obj/structure/door_assembly/assembly = null) - if(!populate_parts) - inherit_from_assembly(assembly) +/obj/machinery/door/airlock/Initialize(var/mapload, var/d, var/populate_parts = TRUE, obj/structure/door_assembly/assembly = null) + + material = RESOLVE_TO_DECL(material) + reinf_material = RESOLVE_TO_DECL(reinf_material) + + . = ..() //wires var/turf/T = get_turf(loc) - if(T && (T.z in GLOB.using_map.admin_levels)) + if(T && isAdminLevel(T.z)) secured_wires = TRUE if (secured_wires) wires = new/datum/wires/airlock/secure(src) @@ -987,31 +1036,27 @@ About the new airlock wires panel: brace.airlock = src brace.forceMove(src) if(brace.electronics) - brace.electronics.set_access(src) - brace.update_access() + brace.req_access = get_req_access() queue_icon_update() - . = ..() + else if(!begins_closed) + queue_icon_update() + + if(reinf_material) + paintable |= PAINT_WINDOW_PAINTABLE + paint_window(reinf_material.color) -/obj/machinery/door/airlock/proc/inherit_from_assembly(obj/structure/door_assembly/assembly) +/obj/machinery/door/airlock/inherit_from_assembly(obj/structure/door_assembly/assembly) //if assembly is given, create the new door from the assembly - if (assembly && istype(assembly)) - frame_type = assembly.type - - var/obj/item/stock_parts/circuitboard/electronics = assembly.electronics - install_component(electronics, FALSE) // will be refreshed in parent call; unsafe to refresh prior to calling ..() in Initialize - electronics.construct(src) - var/decl/material/mat = decls_repository.get_decl(assembly.glass_material) - - if(assembly.glass == 1) // supposed to use material in this case - mineral = assembly.glass_material - if(mat.opacity <= 0.7) - glass = TRUE + if (..(assembly)) + if(assembly.reinf_material && assembly.can_install_glass) + material = assembly.reinf_material + if(assembly.reinf_material.opacity <= 0.7) set_opacity(0) hitsound = 'sound/effects/Glasshit.ogg' - maxhealth = 300 + max_health = 300 explosion_resistance = 5 else - door_color = mat.color + door_color = assembly.reinf_material.color else door_color = assembly.door_color @@ -1019,12 +1064,13 @@ About the new airlock wires panel: if(assembly.created_name) SetName(assembly.created_name) else - SetName("[mineral ? "[mat.solid_name || mat.name] airlock" : assembly.base_name]") + SetName("[material ? "[material.solid_name || material.name] airlock" : assembly.base_name]") paintable = assembly.paintable stripe_color = assembly.stripe_color symbol_color = assembly.symbol_color queue_icon_update() + return TRUE /obj/machinery/door/airlock/Destroy() if(brace) @@ -1055,34 +1101,44 @@ About the new airlock wires panel: return // Braces can act as an extra layer of armor - they will take damage first. -/obj/machinery/door/airlock/take_damage(var/amount) +/obj/machinery/door/airlock/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) if(brace) - brace.take_damage(amount) + brace.take_damage(damage) else - ..(amount) + ..() update_icon() -/obj/machinery/door/airlock/examine(mob/user) +/obj/machinery/door/airlock/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if (lock_cut_state == BOLTS_EXPOSED) - to_chat(user, "The bolt cover has been cut open.") + . += SPAN_WARNING("The bolt cover has been cut open.") if (lock_cut_state == BOLTS_CUT) - to_chat(user, "The door bolts have been cut.") + . += SPAN_DANGER("The door bolts have been cut!") if(brace) - to_chat(user, "\The [brace] is installed on \the [src], preventing it from opening.") - to_chat(user, brace.examine_health()) - -/obj/machinery/door/airlock/autoname + . += "\The [brace] is installed on \the [src], preventing it from opening." + . += brace.examine_health() /obj/machinery/door/airlock/autoname/Initialize() var/area/A = get_area(src) - name = A.name + if(A?.proper_name) + name = A.proper_name . = ..() -/obj/machinery/door/airlock/proc/paint_airlock(var/paint_color) - door_color = paint_color - update_icon() - -/obj/machinery/door/airlock/proc/stripe_airlock(var/paint_color) - stripe_color = paint_color - update_icon() \ No newline at end of file +/obj/machinery/door/airlock/proc/paint_airlock(var/new_color) + if(door_color != new_color) + door_color = new_color + update_icon() + +/obj/machinery/door/airlock/proc/stripe_airlock(var/new_color) + if(stripe_color != new_color) + stripe_color = new_color + update_icon() + +/obj/machinery/door/airlock/proc/paint_window(new_color) + if (new_color) + window_color = new_color + else if (reinf_material) + window_color = reinf_material.color + else + window_color = GLASS_COLOR + queue_icon_update() diff --git a/code/game/machinery/doors/airlock_autoname.dm b/code/game/machinery/doors/airlock_autoname.dm index b7a9277b384c..c203f7fafc43 100644 --- a/code/game/machinery/doors/airlock_autoname.dm +++ b/code/game/machinery/doors/airlock_autoname.dm @@ -3,7 +3,8 @@ /obj/machinery/door/airlock/hatch/autoname/Initialize() . = ..() var/area/A = get_area(src) - SetName("hatch ([A.name])") + if(A) + SetName("hatch ([A.proper_name])") /obj/machinery/door/airlock/hatch/autoname/general stripe_color = COLOR_CIVIE_GREEN diff --git a/code/game/machinery/doors/airlock_control.dm b/code/game/machinery/doors/airlock_control.dm index ae4bcf66b2ab..3ac2040598f2 100644 --- a/code/game/machinery/doors/airlock_control.dm +++ b/code/game/machinery/doors/airlock_control.dm @@ -56,17 +56,17 @@ /decl/public_access/public_method/airlock_lock name = "engage bolts" desc = "Bolts the airlock, if possible." - call_proc = /obj/machinery/door/airlock/proc/lock + call_proc = TYPE_PROC_REF(/obj/machinery/door/airlock, lock) /decl/public_access/public_method/airlock_unlock name = "disengage bolts" desc = "Unbolts the airlock, if possible." - call_proc = /obj/machinery/door/airlock/proc/unlock + call_proc = TYPE_PROC_REF(/obj/machinery/door/airlock, unlock) /decl/public_access/public_method/airlock_toggle_bolts name = "toggle bolts" desc = "Toggles whether the airlock is bolted or not, if possible." - call_proc = /obj/machinery/door/airlock/proc/toggle_lock + call_proc = TYPE_PROC_REF(/obj/machinery/door/airlock, toggle_lock) /decl/public_access/public_variable/airlock_door_state expected_type = /obj/machinery/door/airlock @@ -74,7 +74,7 @@ desc = "Whether the door is closed (\"closed\") or not (\"open\")." can_write = FALSE has_updates = FALSE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/airlock_door_state/access_var(obj/machinery/door/airlock/door) return door.density ? "closed" : "open" @@ -85,47 +85,80 @@ desc = "Whether the door is bolted (\"locked\") or not (\"unlocked\")." can_write = FALSE has_updates = FALSE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/airlock_bolt_state/access_var(obj/machinery/door/airlock/door) return door.locked ? "locked" : "unlocked" +///////////////////////////////////////////////////////////////////////////////////// +// Airlock Sensor +///////////////////////////////////////////////////////////////////////////////////// /obj/machinery/airlock_sensor name = "airlock sensor" - icon = 'icons/obj/airlock_machines.dmi' - icon_state = "airlock_sensor_off" + icon = 'icons/obj/machines/airlock_sensor.dmi' + icon_state = "sensor" layer = ABOVE_WINDOW_LAYER - - anchored = 1 + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED power_channel = ENVIRON public_variables = list( /decl/public_access/public_variable/airlock_pressure, - /decl/public_access/public_variable/input_toggle + /decl/public_access/public_variable/input_toggle, + /decl/public_access/public_variable/set_airlock_cycling/airlock_sensor ) public_methods = list(/decl/public_access/public_method/toggle_input_toggle) - stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/airlock_sensor = 1) + stock_part_presets = list( + /decl/stock_part_preset/radio/basic_transmitter/airlock_sensor = 1, + /decl/stock_part_preset/radio/receiver/airlock_sensor = 1 + ) + //#TODO: Make the sensor considered as missing parts if it doesn't have at the very least a transmitter uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable, - /obj/item/stock_parts/radio/transmitter/basic/buildable + /obj/item/stock_parts/power/apc, + /obj/item/stock_parts/radio/transmitter/basic/buildable, + /obj/item/stock_parts/radio/receiver/buildable, ) base_type = /obj/machinery/airlock_sensor/buildable construct_state = /decl/machine_construction/wall_frame/panel_closed/simple - frame_type = /obj/item/frame/button/airlock_sensor - - var/alert = 0 + frame_type = /obj/item/frame/button/airlock_controller_config/airlock_sensor + directional_offset = @'{"NORTH":{"y":-18}, "SOUTH":{"y":24}, "EAST":{"x":-22}, "WEST":{"x":22}}' + var/alert = FALSE + var/master_cycling = FALSE var/pressure /obj/machinery/airlock_sensor/buildable - uncreated_component_parts = null + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc = 1 + ) + +/obj/machinery/airlock_sensor/Initialize(mapload, d, populate_parts) + . = ..() + update_icon() + +/obj/machinery/airlock_sensor/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance < 2) + . += SPAN_INFO("The pressure indicator reads '[pressure? round(pressure, 0.1) : 0] kPa'.") + if(master_cycling) + . += SPAN_WARNING("It's warning that the master airlock is cycling!") + if(alert) + . += SPAN_WARNING("The low-pressure warning light is blinking!") /obj/machinery/airlock_sensor/on_update_icon() - if(!(stat & (NOPOWER | BROKEN))) - if(alert) - icon_state = "airlock_sensor_alert" - else - icon_state = "airlock_sensor_standby" + cut_overlays() + if(inoperable() || !use_power) + set_light(0) + return + //Cycling takes priority over alert + if(master_cycling) + add_overlay("sensor_light_cycle") + set_light(l_range = 1, l_power = 0.2, l_color = "#ff0000") + else if(alert) + add_overlay("sensor_light_alert") + set_light(l_range = 1, l_power = 0.2, l_color = "#ff0000") else - icon_state = "airlock_sensor_off" + add_overlay("sensor_light_standby") + set_light(l_range = 1, l_power = 0.2, l_color = "#99ff33") + /obj/machinery/airlock_sensor/Process() if(!(stat & (NOPOWER | BROKEN))) @@ -133,21 +166,31 @@ var/new_pressure = round(air_sample.return_pressure(),0.1) if(abs(pressure - new_pressure) > 0.001 || pressure == null) - var/decl/public_access/public_variable/airlock_pressure/pressure_var = decls_repository.get_decl(/decl/public_access/public_variable/airlock_pressure) + var/decl/public_access/public_variable/airlock_pressure/pressure_var = GET_DECL(/decl/public_access/public_variable/airlock_pressure) pressure_var.write_var(src, new_pressure) - var/new_alert = (pressure < ONE_ATMOSPHERE*0.8) + var/new_alert = (pressure < (0.8 ATM)) if(new_alert != alert) alert = new_alert update_icon() +/**Meant to update the icon when the master airlock controller is cycling */ +/obj/machinery/airlock_sensor/proc/set_master_cycling(var/state) + master_cycling = state + update_icon() + +/obj/machinery/airlock_sensor/set_id_tag(var/new_id_tag) + . = ..() + for(var/obj/item/stock_parts/radio/radio in get_all_components_of_type(/obj/item/stock_parts/radio)) + radio.set_id_tag(id_tag) + /decl/public_access/public_variable/airlock_pressure expected_type = /obj/machinery/airlock_sensor name = "airlock sensor pressure" desc = "The pressure of the location where the sensor is placed." can_write = FALSE has_updates = TRUE - var_type = IC_FORMAT_NUMBER + var_type = VAR_FORMAT_NUMBER /decl/public_access/public_variable/airlock_pressure/access_var(obj/machinery/airlock_sensor/sensor) return sensor.pressure @@ -163,39 +206,62 @@ "pressure" = /decl/public_access/public_variable/airlock_pressure ) +/decl/public_access/public_variable/set_airlock_cycling/airlock_sensor + expected_type = /obj/machinery/airlock_sensor + can_write = TRUE + var_type = VAR_FORMAT_BOOLEAN + +/decl/public_access/public_variable/set_airlock_cycling/airlock_sensor/access_var(obj/machinery/airlock_sensor/owner) + return owner.master_cycling + +/decl/public_access/public_variable/set_airlock_cycling/airlock_sensor/write_var(obj/machinery/airlock_sensor/owner, new_value) + if(!..()) + return + owner.master_cycling = new_value + owner.update_icon() + +/decl/stock_part_preset/radio/receiver/airlock_sensor + frequency = EXTERNAL_AIR_FREQ + receive_and_write = list( + "set_airlock_cycling" = /decl/public_access/public_variable/set_airlock_cycling/airlock_sensor, + ) + /decl/stock_part_preset/radio/basic_transmitter/airlock_sensor/shuttle frequency = SHUTTLE_AIR_FREQ /obj/machinery/airlock_sensor/shuttle stock_part_presets = list(/decl/stock_part_preset/radio/basic_transmitter/airlock_sensor/shuttle = 1) +///////////////////////////////////////////////////////////////////////////////////// +// Airlock Button +///////////////////////////////////////////////////////////////////////////////////// /obj/machinery/button/access - icon = 'icons/obj/airlock_machines.dmi' - icon_state = "access_button_standby" + icon = 'icons/obj/machines/button_airlock.dmi' + icon_state = "button" name = "access button" interact_offline = TRUE public_variables = list( /decl/public_access/public_variable/button_active, /decl/public_access/public_variable/button_state, /decl/public_access/public_variable/input_toggle, - /decl/public_access/public_variable/button_command + /decl/public_access/public_variable/button_command, + /decl/public_access/public_variable/set_airlock_cycling/access_button ) stock_part_presets = list( - /decl/stock_part_preset/radio/event_transmitter/access_button = 1 + /decl/stock_part_preset/radio/event_transmitter/access_button = 1, + /decl/stock_part_preset/radio/receiver/access_button = 1, ) + //#TODO: Make the button considered as missing parts if it doesn't have at the very least a transmitter uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable, - /obj/item/stock_parts/radio/transmitter/on_event/buildable + /obj/item/stock_parts/power/apc, + /obj/item/stock_parts/radio/transmitter/on_event/buildable, + /obj/item/stock_parts/radio/receiver/buildable, ) + directional_offset = @'{"NORTH":{"y":-22}, "SOUTH":{"y":24}, "EAST":{"x":-20}, "WEST":{"x":20}}' + frame_type = /obj/item/frame/button/airlock_controller_config/access + base_type = /obj/machinery/button/access/buildable var/command = "cycle" - -/obj/machinery/button/access/on_update_icon() - if(stat & (NOPOWER | BROKEN)) - icon_state = "access_button_off" - else if(operating) - icon_state = "access_button_cycle" - else - icon_state = "access_button_standby" + var/tmp/master_cycling = FALSE ///Whether the master airlock controller is actually cycling so we can update our icon /obj/machinery/button/access/interior command = "cycle_interior" @@ -203,6 +269,20 @@ /obj/machinery/button/access/exterior command = "cycle_exterior" +/obj/machinery/button/access/exterior/cabled + //Still create a tesla link, to stay coherent with how one would create that button from scratch in-game. + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc, + /obj/item/stock_parts/power/terminal/buildable, + /obj/item/stock_parts/radio/transmitter/on_event/buildable, + /obj/item/stock_parts/radio/receiver/buildable, + ) + stock_part_presets = list( + /decl/stock_part_preset/radio/event_transmitter/access_button = 1, + /decl/stock_part_preset/radio/receiver/access_button = 1, + /decl/stock_part_preset/terminal_setup, + ) + /obj/machinery/button/access/shuttle stock_part_presets = list( /decl/stock_part_preset/radio/event_transmitter/access_button/shuttle = 1 @@ -214,13 +294,89 @@ /obj/machinery/button/access/shuttle/exterior command = "cycle_exterior" +/obj/machinery/button/access/buildable + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc, + ) +/obj/machinery/button/access/interior/buildable + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc, + ) +/obj/machinery/button/access/exterior/buildable + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc, + ) + +/obj/machinery/button/access/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + . += SPAN_INFO("The button reads '[command]'.") + if(master_cycling) + . += SPAN_WARNING("It's warning that the master airlock is cycling!") + +/obj/machinery/button/access/on_update_icon() + cut_overlays() + if(inoperable() || !use_power) + set_light(0) + return + if(operating) + add_overlay("button_light_pressed") + set_light(l_range = 2, l_power = 0.4, l_color = "#f65555") + else if(master_cycling) + add_overlay("button_light_cycle") + set_light(l_range = 2, l_power = 0.4, l_color = "#f65555") + else + add_overlay("button_light_standby") + set_light(l_range = 2, l_power = 0.4, l_color = "#99ff33") + +/obj/machinery/button/access/set_id_tag(var/new_id_tag) + . = ..() + for(var/obj/item/stock_parts/radio/radio in get_all_components_of_type(/obj/item/stock_parts/radio)) + radio.set_id_tag(id_tag) + +// +// Button Part Presets +// +/decl/stock_part_preset/radio/receiver/access_button + frequency = EXTERNAL_AIR_FREQ + receive_and_write = list( + "set_airlock_cycling" = /decl/public_access/public_variable/set_airlock_cycling/access_button, + ) + +/decl/stock_part_preset/radio/event_transmitter/access_button + frequency = EXTERNAL_AIR_FREQ + event = /decl/public_access/public_variable/button_active + transmit_on_event = list( + "command" = /decl/public_access/public_variable/button_command + ) + +/decl/stock_part_preset/radio/event_transmitter/access_button/shuttle + frequency = SHUTTLE_AIR_FREQ + +// +// Public Variables +// +/decl/public_access/public_variable/set_airlock_cycling/access_button + expected_type = /obj/machinery/button/access + can_write = TRUE + var_type = VAR_FORMAT_BOOLEAN + +/decl/public_access/public_variable/set_airlock_cycling/access_button/access_var(obj/machinery/button/access/owner) + return owner.master_cycling + +/decl/public_access/public_variable/set_airlock_cycling/access_button/write_var(obj/machinery/button/access/owner, new_value) + if(!..()) + return + owner.master_cycling = new_value + owner.update_icon() + /decl/public_access/public_variable/button_command expected_type = /obj/machinery/button/access name = "button command" desc = "The command this access button sends when pressed." can_write = TRUE has_updates = FALSE - var_type = IC_FORMAT_STRING + var_type = VAR_FORMAT_STRING /decl/public_access/public_variable/button_command/access_var(obj/machinery/button/access/button) return button.command @@ -229,13 +385,3 @@ . = ..() if(.) button.command = new_val - -/decl/stock_part_preset/radio/event_transmitter/access_button - frequency = EXTERNAL_AIR_FREQ - event = /decl/public_access/public_variable/button_active - transmit_on_event = list( - "command" = /decl/public_access/public_variable/button_command - ) - -/decl/stock_part_preset/radio/event_transmitter/access_button/shuttle - frequency = SHUTTLE_AIR_FREQ \ No newline at end of file diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index 6ca0cda18b96..dbca57d4ca78 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -2,8 +2,7 @@ name = "airlock electronics" icon = 'icons/obj/doors/door_assembly.dmi' icon_state = "door_electronics" - material = /decl/material/solid/glass - req_access = list(access_engine) + material = /decl/material/solid/fiberglass build_path = /obj/machinery/door/airlock board_type = "door" @@ -16,101 +15,13 @@ ) // The borg UI thing doesn't need screen/keyboard as borgs don't need those. var/secure = 0 //if set, then wires will be randomized and bolts will drop if the door is broken - var/list/conf_access = list() - var/one_access = 0 //if set to 1, door would receive OR instead of AND on the access restrictions. - var/last_configurator = null - var/locked = 1 - var/lockable = 1 - var/autoset = TRUE // Whether the door should inherit access from surrounding areas - -/obj/item/stock_parts/circuitboard/airlock_electronics/attack_self(mob/user) - if (!ishuman(user) && !istype(user,/mob/living/silicon/robot)) - return ..(user) - - ui_interact(user) - -/obj/item/stock_parts/circuitboard/airlock_electronics/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/topic_state/state = GLOB.hands_state) - var/list/data = ui_data() - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "airlock_electronics.tmpl", src.name, 1000, 500, null, null, state) - ui.set_initial_data(data) - ui.open() - -/obj/item/stock_parts/circuitboard/airlock_electronics/ui_data() - var/list/data = list() - var/list/regions = list() - - for(var/i in ACCESS_REGION_MIN to ACCESS_REGION_MAX) //code/game/jobs/_access_defs.dm - var/list/region = list() - var/list/accesses = list() - for(var/j in get_region_accesses(i)) - var/list/access = list() - access["name"] = get_access_desc(j) - access["id"] = j - access["req"] = (j in src.conf_access) - accesses[++accesses.len] = access - region["name"] = get_region_accesses_name(i) - region["accesses"] = accesses - regions[++regions.len] = region - data["regions"] = regions - data["oneAccess"] = one_access - data["locked"] = locked - data["lockable"] = lockable - data["autoset"] = autoset - - return data - -/obj/item/stock_parts/circuitboard/airlock_electronics/OnTopic(mob/user, list/href_list, state) - if(lockable) - if(href_list["unlock"]) - if(!req_access || istype(user, /mob/living/silicon)) - locked = FALSE - last_configurator = user.name - else - var/obj/item/card/id/I = user.get_active_hand() - I = I ? I.GetIdCard() : null - if(!istype(I, /obj/item/card/id)) - to_chat(user, SPAN_WARNING("[\src] flashes a yellow LED near the ID scanner. Did you remember to scan your ID or PDA?")) - return TOPIC_HANDLED - if (check_access(I)) - locked = FALSE - last_configurator = I.registered_name - else - to_chat(user, SPAN_WARNING("[\src] flashes a red LED near the ID scanner, indicating your access has been denied.")) - return TOPIC_HANDLED - return TOPIC_REFRESH - else if(href_list["lock"]) - locked = TRUE - return TOPIC_REFRESH - - if(href_list["clear"]) - conf_access = list() - one_access = FALSE - return TOPIC_REFRESH - if(href_list["one_access"]) - one_access = !one_access - return TOPIC_REFRESH - if(href_list["autoset"]) - autoset = !autoset - return TOPIC_REFRESH - if(href_list["access"]) - var/access = href_list["access"] - if (!(access in conf_access)) - conf_access += access - else - conf_access -= access - return TOPIC_REFRESH - /obj/item/stock_parts/circuitboard/airlock_electronics/secure name = "secure airlock electronics" - desc = "designed to be somewhat more resistant to hacking than standard electronics." - origin_tech = "{'programming':2}" + desc = "Airlock control electronics, designed to be somewhat more resistant to hacking than standard electronics." + origin_tech = @'{"programming":2}' secure = TRUE /obj/item/stock_parts/circuitboard/airlock_electronics/windoor - icon_state = "door_electronics_smoked" name = "window door electronics" build_path = /obj/machinery/door/window additional_spawn_components = list() @@ -132,8 +43,6 @@ name = "airlock brace access circuit" build_path = /obj/item/airlock_brace // idk why they use this; I think it's just to share the UI. This isn't used to build machines. req_access = list() - locked = FALSE - lockable = FALSE /obj/item/stock_parts/circuitboard/airlock_electronics/firedoor name = "fire door electronics" @@ -142,7 +51,7 @@ /obj/item/stock_parts/power/apc/buildable ) -/obj/item/stock_parts/circuitboard/airlock_electronics/brace/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/topic_state/state = GLOB.deep_inventory_state) +/obj/item/stock_parts/circuitboard/airlock_electronics/brace/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/topic_state/state = global.deep_inventory_topic_state) var/list/data = ui_data() ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -151,35 +60,14 @@ ui.set_initial_data(data) ui.open() -/obj/item/stock_parts/circuitboard/airlock_electronics/proc/set_access(var/obj/object) - if(LAZYLEN(object.req_access)) - conf_access = list() - for(var/entry in object.req_access) - conf_access |= entry // This flattens the list, turning everything into AND - // Can be reworked to have the electronics inherit a precise access set, but requires UI changes. - /obj/item/stock_parts/circuitboard/airlock_electronics/construct(obj/machinery/door/door) . = ..() - if(!istype(door)) - return - //update the door's access to match the electronics' - if(autoset) - door.autoset_access = TRUE - else - door.req_access = conf_access - if(one_access) - door.req_access = list(door.req_access) - door.autoset_access = FALSE // We just set it, so don't try and do anything fancy later. if(istype(door, /obj/machinery/door/airlock)) var/obj/machinery/door/airlock/airlock = door airlock.secured_wires = secure /obj/item/stock_parts/circuitboard/airlock_electronics/deconstruct(obj/machinery/door/door) . = ..() - if(!istype(door)) - return - set_access(door) - autoset = door.autoset_access if(istype(door, /obj/machinery/door/airlock)) var/obj/machinery/door/airlock/airlock = door secure = airlock.secured_wires \ No newline at end of file diff --git a/code/game/machinery/doors/airlock_interactions.dm b/code/game/machinery/doors/airlock_interactions.dm index e0a2ff95124d..2406735f21a7 100644 --- a/code/game/machinery/doors/airlock_interactions.dm +++ b/code/game/machinery/doors/airlock_interactions.dm @@ -59,15 +59,15 @@ for(var/i in 1 to round(crush_damage/AIRLOCK_CRUSH_INCREMENT, 1)) apply_damage(AIRLOCK_CRUSH_INCREMENT, BRUTE) - SetStunned(round(crush_damage / 8, 1)) - SetWeakened(round(crush_damage / 8, 1)) + set_status_condition(STAT_STUN, round(crush_damage / 8, 1)) + set_status_condition(STAT_WEAK, round(crush_damage / 8, 1)) var/turf/T = loc if(!istype(T)) return var/list/valid_turfs = list() - for(var/dir_to_test in GLOB.cardinal) + for(var/dir_to_test in global.cardinal) var/turf/new_turf = get_step(T, dir_to_test) if(!new_turf.contains_dense_objects()) valid_turfs |= new_turf @@ -79,10 +79,10 @@ if(src.Move(T)) return -/mob/living/carbon/airlock_crush(var/crush_damage) +/mob/living/human/airlock_crush(var/crush_damage) . = ..() if (can_feel_pain()) - emote("scream") + emote(/decl/emote/audible/scream) /mob/living/silicon/robot/airlock_crush(var/crush_damage) return ..(round(crush_damage / CYBORG_AIRLOCKCRUSH_RESISTANCE)) //TODO implement robot melee armour and remove this. diff --git a/code/game/machinery/doors/airlock_subtypes.dm b/code/game/machinery/doors/airlock_subtypes.dm index d7c990637cba..f2eda23a2f77 100644 --- a/code/game/machinery/doors/airlock_subtypes.dm +++ b/code/game/machinery/doors/airlock_subtypes.dm @@ -11,19 +11,21 @@ stripe_color = COLOR_NT_RED /obj/machinery/door/airlock/engineering - name = "Maintenance Hatch" door_color = COLOR_AMBER /obj/machinery/door/airlock/medical door_color = COLOR_WHITE stripe_color = COLOR_DEEP_SKY_BLUE +/obj/machinery/door/airlock/medical/open + icon_state = "open" + begins_closed = FALSE + /obj/machinery/door/airlock/virology door_color = COLOR_WHITE stripe_color = COLOR_GREEN /obj/machinery/door/airlock/mining - name = "Mining Airlock" door_color = COLOR_PALE_ORANGE stripe_color = COLOR_BEASTY_BROWN @@ -49,24 +51,20 @@ stripe_color = COLOR_GRAY20 /obj/machinery/door/airlock/freezer - name = "Freezer Airlock" door_color = COLOR_WHITE /obj/machinery/door/airlock/maintenance - name = "Maintenance Access" stripe_color = COLOR_AMBER // Glass airlock presets - /obj/machinery/door/airlock/glass - name = "Glass Airlock" icon_state = "preview_glass" hitsound = 'sound/effects/Glasshit.ogg' - maxhealth = 300 + max_health = 300 explosion_resistance = 5 opacity = FALSE - glass = TRUE + reinf_material = /decl/material/solid/glass /obj/machinery/door/airlock/glass/command door_color = COLOR_COMMAND_BLUE @@ -116,7 +114,6 @@ door_color = COLOR_WHITE /obj/machinery/door/airlock/glass/maintenance - name = "Maintenance Access" stripe_color = COLOR_AMBER /obj/machinery/door/airlock/glass/civilian @@ -126,8 +123,7 @@ // External airlock presets /obj/machinery/door/airlock/external - airlock_type = "External" - name = "External Airlock" + airlock_type = "external" icon = 'icons/obj/doors/external/door.dmi' fill_file = 'icons/obj/doors/external/fill_steel.dmi' color_file = 'icons/obj/doors/external/color.dmi' @@ -139,24 +135,28 @@ emag_file = 'icons/obj/doors/external/emag.dmi' frame_type = /obj/structure/door_assembly/door_assembly_ext door_color = COLOR_NT_RED - paintable = AIRLOCK_PAINTABLE + paintable = PAINT_PAINTABLE stock_part_presets = list( /decl/stock_part_preset/radio/receiver/airlock/external_air = 1, /decl/stock_part_preset/radio/event_transmitter/airlock/external_air = 1 ) -/obj/machinery/door/airlock/external/inherit_access_from_area() - ..() - if(is_station_area(get_area(src))) - add_access_requirement(req_access, access_external_airlocks) +/obj/machinery/door/airlock/external/open + icon_state = "open" + begins_closed = FALSE + +/obj/machinery/door/airlock/external/get_auto_access() + . = ..() + var/area/A = get_area(src) + if(A && is_station_area(A)) + LAZYADD(., access_external_airlocks) /obj/machinery/door/airlock/external/escapepod - name = "Escape Pod" locked = TRUE -/obj/machinery/door/airlock/external/escapepod/attackby(obj/item/C, mob/user) +/obj/machinery/door/airlock/external/escapepod/attackby(obj/item/used_item, mob/user) if(panel_open && !arePowerSystemsOn()) - if(isWrench(C)) + if(IS_WRENCH(used_item)) playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user.visible_message(SPAN_WARNING("[user.name] starts frantically pumping the bolt override mechanism!"), SPAN_WARNING("You start frantically pumping the bolt override mechanism!")) if(do_after(user, 160) && locked) @@ -184,7 +184,7 @@ opacity = FALSE /obj/machinery/door/airlock/external/glass - maxhealth = 300 + max_health = 300 explosion_resistance = 5 opacity = FALSE glass = TRUE @@ -201,14 +201,12 @@ /obj/machinery/door/airlock/centcom airlock_type = "centcomm" - name = "\improper Airlock" icon = 'icons/obj/doors/centcomm/door.dmi' fill_file = 'icons/obj/doors/centcomm/fill_steel.dmi' - paintable = AIRLOCK_PAINTABLE|AIRLOCK_STRIPABLE + paintable = PAINT_PAINTABLE|PAINT_STRIPABLE /obj/machinery/door/airlock/highsecurity airlock_type = "secure" - name = "Secure Airlock" icon = 'icons/obj/doors/secure/door.dmi' fill_file = 'icons/obj/doors/secure/fill_steel.dmi' explosion_resistance = 20 @@ -216,12 +214,13 @@ frame_type = /obj/structure/door_assembly/door_assembly_highsecurity paintable = 0 +/obj/machinery/door/airlock/highsecurity/get_damage_leakthrough(var/damage, damtype=BRUTE) + return 0 /obj/machinery/door/airlock/highsecurity/bolted locked = TRUE /obj/machinery/door/airlock/hatch airlock_type = "hatch" - name = "\improper Airtight Hatch" icon = 'icons/obj/doors/hatch/door.dmi' fill_file = 'icons/obj/doors/hatch/fill_steel.dmi' stripe_file = 'icons/obj/doors/hatch/stripe.dmi' @@ -235,10 +234,9 @@ explosion_resistance = 20 opacity = TRUE frame_type = /obj/structure/door_assembly/door_assembly_hatch - paintable = AIRLOCK_STRIPABLE + paintable = PAINT_STRIPABLE /obj/machinery/door/airlock/hatch/maintenance - name = "Maintenance Hatch" stripe_color = COLOR_AMBER /obj/machinery/door/airlock/hatch/maintenance/bolted @@ -246,14 +244,15 @@ /obj/machinery/door/airlock/vault airlock_type = "vault" - name = "Vault" icon = 'icons/obj/doors/vault/door.dmi' fill_file = 'icons/obj/doors/vault/fill_steel.dmi' explosion_resistance = 20 opacity = TRUE secured_wires = TRUE frame_type = /obj/structure/door_assembly/door_assembly_highsecurity //Until somebody makes better sprites. - paintable = AIRLOCK_PAINTABLE|AIRLOCK_STRIPABLE + paintable = PAINT_PAINTABLE|PAINT_STRIPABLE +/obj/machinery/door/airlock/vault/get_damage_leakthrough(var/damage, damtype=BRUTE) + return 0 /obj/machinery/door/airlock/vault/bolted locked = TRUE diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm index cddb3bbc3132..830d9f241672 100644 --- a/code/game/machinery/doors/blast_door.dm +++ b/code/game/machinery/doors/blast_door.dm @@ -10,13 +10,14 @@ /obj/machinery/door/blast name = "blast door" desc = "That looks like it doesn't open easily." - icon = 'icons/obj/doors/rapid_pdoor.dmi' + icon = 'icons/obj/doors/blast_doors/door.dmi' icon_state = null + can_open_manually = FALSE // Icon states for different shutter types. Simply change this instead of rewriting the update_icon proc. - var/icon_state_open = null + icon_state_open = null + icon_state_closed = null var/icon_state_opening = null - var/icon_state_closed = null var/icon_state_closing = null var/icon_state_open_broken = null @@ -25,16 +26,16 @@ var/open_sound = 'sound/machines/blastdoor_open.ogg' var/close_sound = 'sound/machines/blastdoor_close.ogg' + open_layer = ABOVE_DOOR_LAYER closed_layer = ABOVE_WINDOW_LAYER dir = NORTH explosion_resistance = 25 + atom_flags = ATOM_FLAG_ADJACENT_EXCEPTION //Most blast doors are infrequently toggled and sometimes used with regular doors anyways, //turning this off prevents awkward zone geometry in places like medbay lobby, for example. block_air_zones = 0 - var/begins_closed = TRUE - var/decl/material/implicit_material autoset_access = FALSE // Uses different system with buttons. pry_mod = 1.35 @@ -47,25 +48,18 @@ /decl/public_access/public_method/toggle_door_to ) stock_part_presets = list(/decl/stock_part_preset/radio/receiver/blast_door = 1) - + construct_state = /decl/machine_construction/default/panel_closed/blast_door frame_type = /obj/structure/door_assembly/blast base_type = /obj/machinery/door/blast /obj/machinery/door/blast/Initialize() + material = GET_DECL(/decl/material/solid/metal/plasteel) . = ..() - if(!begins_closed) - icon_state = icon_state_open - set_density(0) - set_opacity(0) - layer = open_layer - - implicit_material = decls_repository.get_decl(/decl/material/solid/metal/plasteel) - -/obj/machinery/door/blast/examine(mob/user) +/obj/machinery/door/blast/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if((stat & BROKEN)) - to_chat(user, "It's broken.") + . += SPAN_DANGER("It's broken.") // Proc: Bumped() // Parameters: 1 (AM - Atom that tried to walk through this object) @@ -80,6 +74,13 @@ // Parameters: None // Description: Updates icon of this object. Uses icon state variables. /obj/machinery/door/blast/on_update_icon() + + if(set_dir_on_update) + if(connections & (NORTH|SOUTH)) + set_dir(EAST) + else + set_dir(SOUTH) + if(density) if(stat & BROKEN) icon_state = icon_state_closed_broken @@ -97,14 +98,16 @@ // Parameters: None // Description: Opens the door. No checks are done inside this proc. /obj/machinery/door/blast/proc/force_open() + set waitfor = FALSE operating = 1 playsound(src.loc, open_sound, 100, 1) flick(icon_state_opening, src) - set_density(0) + + sleep(0.6 SECONDS) + set_density(FALSE) update_nearby_tiles() update_icon() - set_opacity(0) - sleep(15) + set_opacity(FALSE) layer = open_layer operating = 0 @@ -116,11 +119,12 @@ playsound(src.loc, close_sound, 100, 1) layer = closed_layer flick(icon_state_closing, src) - set_density(1) + + sleep(0.6 SECONDS) + set_density(TRUE) update_nearby_tiles() update_icon() - set_opacity(1) - sleep(15) + set_opacity(TRUE) operating = 0 // Proc: force_toggle() @@ -132,63 +136,65 @@ else force_close() -/obj/machinery/door/blast/get_material() - return implicit_material - // Proc: attackby() -// Parameters: 2 (C - Item this object was clicked with, user - Mob which clicked this object) +// Parameters: 2 (used_item - Item this object was clicked with, user - Mob which clicked this object) // Description: If we are clicked with crowbar or wielded fire axe, try to manually open the door. // This only works on broken doors or doors without power. Also allows repair with Plasteel. -/obj/machinery/door/blast/attackby(obj/item/C, mob/user) - add_fingerprint(user, 0, C) - if(isCrowbar(C) || (istype(C, /obj/item/twohanded/fireaxe) && C:wielded == 1)) - if(((stat & NOPOWER) || (stat & BROKEN)) && !( operating )) - to_chat(user, "You begin prying at \the [src]...") - if(do_after(user, 2 SECONDS, src)) - force_toggle() +/obj/machinery/door/blast/attackby(obj/item/used_item, mob/user) + add_fingerprint(user, 0, used_item) + if(!panel_open) //Do this here so the door won't change state while prying out the circuit + if(IS_CROWBAR(used_item) || (istype(used_item, /obj/item/bladed/axe/fire) && used_item.is_held_twohanded())) + if(((stat & NOPOWER) || (stat & BROKEN)) && !( operating )) + to_chat(user, "You begin prying at \the [src]...") + if(do_after(user, 2 SECONDS, src)) + force_toggle() + else + to_chat(user, "You must remain still while working on \the [src].") else - to_chat(user, "You must remain still while working on \the [src].") - else - to_chat(user, "[src]'s motors resist your effort.") - return - if(istype(C, /obj/item/stack/material) && C.get_material_type() == /decl/material/solid/metal/plasteel) - var/amt = Ceiling((maxhealth - health)/150) + to_chat(user, "[src]'s motors resist your effort.") + return TRUE + if(istype(used_item, /obj/item/stack/material) && used_item.get_material_type() == /decl/material/solid/metal/plasteel) + var/amt = ceil((get_max_health() - current_health)/150) if(!amt) to_chat(user, "\The [src] is already fully functional.") - return - var/obj/item/stack/P = C - if(!P.can_use(amt)) + return TRUE + var/obj/item/stack/stack = used_item + if(!stack.can_use(amt)) to_chat(user, "You don't have enough sheets to repair this! You need at least [amt] sheets.") - return + return TRUE to_chat(user, "You begin repairing \the [src]...") if(do_after(user, 5 SECONDS, src)) - if(P.use(amt)) + if(stack.use(amt)) to_chat(user, "You have repaired \the [src].") repair() else to_chat(user, "You don't have enough sheets to repair this! You need at least [amt] sheets.") else to_chat(user, "You must remain still while working on \the [src].") + return TRUE return ..() // Proc: open() // Parameters: None // Description: Opens the door. Does necessary checks. Automatically closes if autoclose is true /obj/machinery/door/blast/open() - if (operating || (stat & BROKEN || stat & NOPOWER)) + if (!can_open() || (stat & BROKEN || stat & NOPOWER)) return + force_open() + if(autoclose) - spawn(150) - close() - return 1 + addtimer(CALLBACK(src, PROC_REF(close)), 15 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) + + return TRUE // Proc: close() // Parameters: None // Description: Closes the door. Does necessary checks. /obj/machinery/door/blast/close() - if (operating || (stat & BROKEN || stat & NOPOWER)) + if (!can_close() || (stat & BROKEN || stat & NOPOWER)) return + force_close() /obj/machinery/door/blast/toggle(to_open = density) @@ -200,7 +206,7 @@ // Parameters: None // Description: Fully repairs the blast door. /obj/machinery/door/blast/proc/repair() - health = maxhealth + current_health = get_max_health() set_broken(FALSE) queue_icon_update() @@ -214,10 +220,19 @@ sleep(5 SECONDS) close() +/obj/machinery/door/blast/dismantle() + var/obj/structure/door_assembly/da = ..() + . = da + + da.anchored = TRUE + da.state = 1 + da.created_name = name + da.update_icon() + /decl/public_access/public_method/close_door_delayed name = "delayed close door" desc = "Closes the door if possible, after a short delay." - call_proc = /obj/machinery/door/blast/proc/delayed_close + call_proc = TYPE_PROC_REF(/obj/machinery/door/blast, delayed_close) /decl/stock_part_preset/radio/receiver/blast_door frequency = BLAST_DOORS_FREQ @@ -239,10 +254,17 @@ /decl/stock_part_preset/radio/receiver/blast_door_button = 1 ) uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable, + /obj/item/stock_parts/power/apc, /obj/item/stock_parts/radio/transmitter/on_event/buildable, /obj/item/stock_parts/radio/receiver/buildable ) + base_type = /obj/machinery/button/blast_door/buildable + frame_type = /obj/item/frame/button/blastdoor + +/obj/machinery/button/blast_door/buildable + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc + ) /obj/machinery/button/blast_door/Initialize(mapload) . = ..() @@ -276,29 +298,39 @@ // SUBTYPE: Regular // Your classical blast door, found almost everywhere. /obj/machinery/door/blast/regular + icon = 'icons/obj/doors/blast_doors/door.dmi' + icon_state = "closed" + icon_state_open = "open" + icon_state_opening = "opening" + icon_state_closed = "closed" + icon_state_closing = "closing" - icon_state = "pdoor1" - icon_state_open = "pdoor0" - icon_state_opening = "pdoorc0" - icon_state_closed = "pdoor1" - icon_state_closing = "pdoorc1" - - icon_state_open_broken = "blast_open_broken" - icon_state_closed_broken = "blast_closed_broken" + icon_state_open_broken = "open_broken" + icon_state_closed_broken = "closed_broken" min_force = 30 - maxhealth = 1000 + max_health = 1000 block_air_zones = 1 + var/icon_lower_door_open = "open_bottom" + var/icon_lower_door_open_broken = "open_bottom_broken" + +/obj/machinery/door/blast/regular/on_update_icon() + underlays.Cut() + . = ..() + if(!density) + underlays += image(icon, null, is_broken()? icon_lower_door_open_broken : icon_lower_door_open, BELOW_DOOR_LAYER, dir) + /obj/machinery/door/blast/regular/escape_pod name = "Escape Pod release Door" -/obj/machinery/door/blast/regular/escape_pod/Process() - if(SSevac.evacuation_controller.emergency_evacuation && SSevac.evacuation_controller.state >= EVAC_LAUNCHING && src.icon_state == icon_state_closed) +/obj/machinery/door/blast/regular/escape_pod/Process() + if(SSevac.evacuation_controller && SSevac.evacuation_controller.emergency_evacuation && SSevac.evacuation_controller.state >= EVAC_LAUNCHING && src.icon_state == icon_state_closed) src.force_open() . = ..() /obj/machinery/door/blast/regular/open + icon_state = "open" begins_closed = FALSE // SUBTYPE: Shutters @@ -306,23 +338,24 @@ /obj/machinery/door/blast/shutters name = "shutters" desc = "A set of mechanized shutters made of a pretty sturdy material." + icon = 'icons/obj/doors/shutters/door.dmi' + icon_state = "closed" + icon_state_open = "open" + icon_state_opening = "opening" + icon_state_closed = "closed" + icon_state_closing = "closing" - icon_state = "shutter1" - icon_state_open = "shutter0" - icon_state_opening = "shutterc0" - icon_state_closed = "shutter1" - icon_state_closing = "shutterc1" - - icon_state_open_broken = "shutter_open_broken" - icon_state_closed_broken = "shutter_closed_broken" + icon_state_open_broken = "open_broken" + icon_state_closed_broken = "closed_broken" open_sound = 'sound/machines/shutters_open.ogg' close_sound = 'sound/machines/shutters_close.ogg' min_force = 15 - maxhealth = 500 + max_health = 500 explosion_resistance = 10 pry_mod = 0.55 - frame_type = /obj/structure/door_assembly/blast + frame_type = /obj/structure/door_assembly/blast/shutter /obj/machinery/door/blast/shutters/open begins_closed = FALSE + icon_state = "open" diff --git a/code/game/machinery/doors/braces.dm b/code/game/machinery/doors/braces.dm index a11aa53043fe..92846b45c43d 100644 --- a/code/game/machinery/doors/braces.dm +++ b/code/game/machinery/doors/braces.dm @@ -4,11 +4,12 @@ desc = "A special crowbar that can be used to safely remove airlock braces from airlocks." w_class = ITEM_SIZE_NORMAL icon = 'icons/obj/items/tool/maintenance_jack.dmi' - icon_state = "maintenance_jack" - force = 17.5 //It has a hammer head, should probably do some more damage. - Cirra + icon_state = ICON_STATE_WORLD + _base_attack_force = 17 //It has a hammer head, should probably do some more damage. - Cirra attack_cooldown = 2.5*DEFAULT_WEAPON_COOLDOWN melee_accuracy_bonus = -25 material = /decl/material/solid/metal/steel + origin_tech = @'{"engineering":3,"materials":2}' // BRACE - Can be installed on airlock to reinforce it and keep it closed. /obj/item/airlock_brace @@ -18,21 +19,21 @@ icon = 'icons/obj/airlock_machines.dmi' icon_state = "brace_open" material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) material_health_multiplier = 0.6 + origin_tech = @'{"engineering":3,"materials":2}' + var/obj/machinery/door/airlock/airlock = null var/obj/item/stock_parts/circuitboard/airlock_electronics/brace/electronics -/obj/item/airlock_brace/examine(mob/user) +/obj/item/airlock_brace/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, examine_health()) - + . += examine_health() // This is also called from airlock's examine, so it's a different proc to prevent code copypaste. /obj/item/airlock_brace/proc/examine_health() - switch(health_percentage()) + switch(get_percent_health()) if(-100 to 25) return "\The [src] looks seriously damaged, and probably won't last much more." if(25 to 50) @@ -44,43 +45,35 @@ if(99 to INFINITY) return "\The [src] is in excellent condition." - /obj/item/airlock_brace/on_update_icon() + . = ..() if(airlock) icon_state = "brace_closed" else icon_state = "brace_open" - /obj/item/airlock_brace/Initialize() . = ..() - health = max_health - electronics = new (src) - update_access() + if(!electronics) + electronics = new (src) /obj/item/airlock_brace/Destroy() if(airlock) airlock.brace = null airlock = null - qdel(electronics) - electronics = null - ..() - + QDEL_NULL(electronics) + return ..() // Interact with the electronics to set access requirements. /obj/item/airlock_brace/attack_self(mob/user) electronics.attack_self(user) - -/obj/item/airlock_brace/attackby(obj/item/W, mob/user) - ..() - if (istype(W.GetIdCard(), /obj/item/card/id)) +/obj/item/airlock_brace/attackby(obj/item/used_item, mob/user) + if (istype(used_item.GetIdCard(), /obj/item/card/id)) if(!airlock) - attack_self(user) - return + return attack_self(user) else - var/obj/item/card/id/C = W.GetIdCard() - update_access() + var/obj/item/card/id/C = used_item.GetIdCard() if(check_access(C)) to_chat(user, "You swipe \the [C] through \the [src].") if(do_after(user, 10, airlock)) @@ -88,40 +81,39 @@ unlock_brace(usr) else to_chat(user, "You swipe \the [C] through \the [src], but it does not react.") - return + return TRUE - if (istype(W, /obj/item/crowbar/brace_jack)) + if (istype(used_item, /obj/item/crowbar/brace_jack)) if(!airlock) - return - var/obj/item/crowbar/brace_jack/C = W + return FALSE + var/obj/item/crowbar/brace_jack/C = used_item to_chat(user, "You begin forcibly removing \the [src] with \the [C].") if(do_after(user, rand(150,300), airlock)) to_chat(user, "You finish removing \the [src].") unlock_brace(user) - return + return TRUE - if(isWelder(W)) - var/obj/item/weldingtool/C = W - if(health == max_health) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/C = used_item + if(!is_damaged()) to_chat(user, "\The [src] does not require repairs.") - return - if(C.remove_fuel(0,user)) + return TRUE + if(C.weld(0,user)) playsound(src, 'sound/items/Welder.ogg', 100, 1) - health = min(health + rand(20,30), max_health) - if(health == max_health) + current_health = min(current_health + rand(20,30), get_max_health()) + if(!is_damaged()) to_chat(user, "You repair some dents on \the [src]. It is in perfect condition now.") else to_chat(user, "You repair some dents on \the [src].") + return TRUE + return ..() -/obj/item/airlock_brace/proc/take_damage(var/amount) - health = between(0, health - amount, max_health) - if(!health) - if(airlock) - airlock.visible_message("\The [src] breaks off of \the [airlock]!") - unlock_brace(null) - qdel(src) - +/obj/item/airlock_brace/physically_destroyed(skip_qdel) + if(airlock) + airlock.visible_message(SPAN_DANGER("\The [src] breaks off of \the [airlock]!")) + unlock_brace(null) + . = ..() /obj/item/airlock_brace/proc/unlock_brace(var/mob/user) if(!airlock) @@ -136,15 +128,3 @@ airlock = null update_icon() - -/obj/item/airlock_brace/proc/health_percentage() - if(!max_health) - return 0 - return (health / max_health) * 100 - -/obj/item/airlock_brace/proc/update_access() - if(!electronics) - return - req_access = electronics.conf_access - if(electronics.one_access) - req_access = list(req_access) \ No newline at end of file diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index b4fb095f71c8..f0f98def6554 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -19,9 +19,8 @@ icon_state = "frame" desc = "A remote control for a door." initial_access = list(access_brig) - anchored = 1.0 // can't pick it up - density = 0 // can walk through it. - var/id = null // id of door it controls. + anchored = TRUE // can't pick it up + density = FALSE // can walk through it. var/releasetime = 0 // when world.timeofday reaches it - release the prisoner var/timing = 1 // boolean, true/1 timer is on, false/0 means it's not timing var/picture_state // icon_state of alert picture, if not displaying text/numbers @@ -38,15 +37,15 @@ /obj/machinery/door_timer/LateInitialize() for(var/obj/machinery/door/window/brigdoor/M in SSmachines.machinery) - if (M.id == src.id) + if (M.id_tag == id_tag) targets += M for(var/obj/machinery/flasher/F in SSmachines.machinery) - if(F.id_tag == src.id) + if(F.id_tag == id_tag) targets += F - for(var/obj/structure/closet/secure_closet/brig/C in world) - if(C.id == src.id) + for(var/obj/structure/closet/secure_closet/brig/C in global.closets) + if(C.id == id_tag) targets += C if(targets.len==0) @@ -117,7 +116,7 @@ timing = 0 if (broadcast_to_huds) - broadcast_security_hud_message("The timer for [id] has expired.", src) + broadcast_security_hud_message("The timer for [id_tag] has expired.", src) for(var/obj/machinery/door/window/brigdoor/door in targets) if(!door.density) continue @@ -198,10 +197,10 @@ for(var/obj/machinery/flasher/F in targets) F.flash() . = TOPIC_REFRESH - + if (href_list["adjust"]) timetoset += text2num(href_list["adjust"]) - timetoset = Clamp(timetoset, 0, 36000) + timetoset = clamp(timetoset, 0, 36000) . = TOPIC_REFRESH update_icon() @@ -219,7 +218,7 @@ set_picture("ai_bsod") return if(src.timing) - var/disp1 = id + var/disp1 = id_tag var/timeleft = timeleft() var/disp2 = "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" if(length(disp2) > CHARS_PER_LINE) @@ -268,27 +267,27 @@ /obj/machinery/door_timer/cell_1 name = "Cell 1" - id = "Cell 1" + id_tag = "Cell 1" /obj/machinery/door_timer/cell_2 name = "Cell 2" - id = "Cell 2" + id_tag = "Cell 2" /obj/machinery/door_timer/cell_3 name = "Cell 3" - id = "Cell 3" + id_tag = "Cell 3" /obj/machinery/door_timer/cell_4 name = "Cell 4" - id = "Cell 4" + id_tag = "Cell 4" /obj/machinery/door_timer/cell_5 name = "Cell 5" - id = "Cell 5" + id_tag = "Cell 5" /obj/machinery/door_timer/cell_6 name = "Cell 6" - id = "Cell 6" + id_tag = "Cell 6" #undef FONT_SIZE #undef FONT_COLOR diff --git a/code/game/machinery/doors/double.dm b/code/game/machinery/doors/double.dm new file mode 100644 index 000000000000..134f2a3ef11d --- /dev/null +++ b/code/game/machinery/doors/double.dm @@ -0,0 +1,176 @@ +//Terribly sorry for the code doubling, but things go derpy otherwise. +/obj/machinery/door/airlock/double + icon = 'icons/obj/doors/double/door.dmi' + fill_file = 'icons/obj/doors/double/fill_steel.dmi' + color_file = 'icons/obj/doors/double/color.dmi' + color_fill_file = 'icons/obj/doors/double/fill_color.dmi' + stripe_file = 'icons/obj/doors/double/stripe.dmi' + stripe_fill_file = 'icons/obj/doors/double/fill_stripe.dmi' + glass_file = 'icons/obj/doors/double/fill_glass.dmi' + bolts_file = 'icons/obj/doors/double/lights_bolts.dmi' + deny_file = 'icons/obj/doors/double/lights_deny.dmi' + lights_file = 'icons/obj/doors/double/lights_green.dmi' + panel_file = 'icons/obj/doors/double/panel.dmi' + welded_file = 'icons/obj/doors/double/welded.dmi' + emag_file = 'icons/obj/doors/double/emag.dmi' + + frame_type = /obj/structure/door_assembly/double + airlock_type = "double" + appearance_flags = 0 + opacity = TRUE + width = 2 + +// TODO: Find a better way to do this. +/obj/machinery/door/airlock/double/shuttle_rotate(angle) + . = ..() + if(.) + var/turf/obstacle + switch(dir) + if(WEST) + obstacle = get_step(get_step(src, SOUTH), SOUTH) // two turfs south + if(!obstacle.density) + y-- + return + obstacle = get_step(src, NORTH) + if(!obstacle.density) + y++ + return + if(SOUTH) + obstacle = get_step(get_step(src, EAST), EAST) // two turfs east + if(!obstacle.density) + x++ + return + obstacle = get_step(src, WEST) + if(!obstacle.density) + x-- + return + +/obj/machinery/door/airlock/double/update_connections(var/propagate = 0) + var/dirs = 0 + + for(var/direction in global.cardinal) + var/turf/T = get_step(src, direction) + var/success = 0 + + if(direction in list(NORTH, EAST)) + T = get_step(T, direction) + + if( istype(T, /turf/wall)) + success = 1 + if(propagate) + var/turf/wall/wall = T + wall.wall_connections = null + wall.other_connections = null + wall.queue_icon_update() + else + for(var/obj/O in T) + for(var/blend_type in get_blend_objects()) + if( istype(O, blend_type)) + success = 1 + + if(success) + break + if(success) + break + + if(success) + dirs |= direction + connections = dirs + +/obj/machinery/door/airlock/double/command + door_color = COLOR_COMMAND_BLUE + +/obj/machinery/door/airlock/double/security + door_color = COLOR_NT_RED + +/obj/machinery/door/airlock/double/engineering + door_color = COLOR_AMBER + +/obj/machinery/door/airlock/double/medical + door_color = COLOR_WHITE + stripe_color = COLOR_DEEP_SKY_BLUE + +/obj/machinery/door/airlock/double/virology + door_color = COLOR_WHITE + stripe_color = COLOR_GREEN + +/obj/machinery/door/airlock/double/mining + door_color = COLOR_PALE_ORANGE + stripe_color = COLOR_BEASTY_BROWN + +/obj/machinery/door/airlock/double/atmos + door_color = COLOR_AMBER + stripe_color = COLOR_CYAN + +/obj/machinery/door/airlock/double/research + door_color = COLOR_WHITE + stripe_color = COLOR_RESEARCH + +/obj/machinery/door/airlock/double/science + door_color = COLOR_WHITE + stripe_color = COLOR_VIOLET + +/obj/machinery/door/airlock/double/sol + door_color = COLOR_BLUE_GRAY + +/obj/machinery/door/airlock/double/maintenance + stripe_color = COLOR_AMBER + +/obj/machinery/door/airlock/double/civilian + stripe_color = COLOR_CIVIE_GREEN + +/obj/machinery/door/airlock/double/freezer + door_color = COLOR_WHITE + +/obj/machinery/door/airlock/double/glass + opacity = FALSE + glass = TRUE + +/obj/machinery/door/airlock/double/glass/command + door_color = COLOR_COMMAND_BLUE + stripe_color = COLOR_SKY_BLUE + +/obj/machinery/door/airlock/double/glass/security + door_color = COLOR_NT_RED + stripe_color = COLOR_ORANGE + +/obj/machinery/door/airlock/double/glass/engineering + door_color = COLOR_AMBER + stripe_color = COLOR_RED + +/obj/machinery/door/airlock/double/glass/medical + door_color = COLOR_WHITE + stripe_color = COLOR_DEEP_SKY_BLUE + +/obj/machinery/door/airlock/double/glass/virology + door_color = COLOR_WHITE + stripe_color = COLOR_GREEN + +/obj/machinery/door/airlock/double/glass/mining + door_color = COLOR_PALE_ORANGE + stripe_color = COLOR_BEASTY_BROWN + +/obj/machinery/door/airlock/double/glass/atmos + door_color = COLOR_AMBER + stripe_color = COLOR_CYAN + +/obj/machinery/door/airlock/double/glass/research + door_color = COLOR_WHITE + stripe_color = COLOR_RESEARCH + +/obj/machinery/door/airlock/double/glass/science + door_color = COLOR_WHITE + stripe_color = COLOR_VIOLET + +/obj/machinery/door/airlock/double/glass/sol + door_color = COLOR_BLUE_GRAY + stripe_color = COLOR_AMBER + +/obj/machinery/door/airlock/double/glass/freezer + door_color = COLOR_WHITE + +/obj/machinery/door/airlock/double/glass/maintenance + stripe_color = COLOR_AMBER + +/obj/machinery/door/airlock/double/glass/civilian + stripe_color = COLOR_CIVIE_GREEN \ No newline at end of file diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 8c45787ed205..732b04b47d39 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -10,20 +10,24 @@ /obj/machinery/door/firedoor name = "emergency shutter" - desc = "Emergency air-tight shutter, capable of sealing off breached areas." + desc = "Emergency airtight shutters, capable of sealing off breached areas." icon = 'icons/obj/doors/hazard/door.dmi' var/panel_file = 'icons/obj/doors/hazard/panel.dmi' var/welded_file = 'icons/obj/doors/hazard/welded.dmi' icon_state = "open" + icon_state_open = "open" + icon_state_closed = "closed" + begins_closed = FALSE initial_access = list(list(access_atmospherics, access_engine_equip)) autoset_access = FALSE - opacity = 0 - density = 0 + opacity = FALSE + density = FALSE layer = BELOW_DOOR_LAYER open_layer = BELOW_DOOR_LAYER closed_layer = ABOVE_WINDOW_LAYER movable_flags = MOVABLE_FLAG_Z_INTERACT pry_mod = 0.75 + atom_flags = ATOM_FLAG_ADJACENT_EXCEPTION //These are frequenly used with windows, so make sure zones can pass. //Generally if a firedoor is at a place where there should be a zone boundery then there will be a regular door underneath it. @@ -34,7 +38,6 @@ var/pdiff_alert = 0 var/pdiff = 0 var/nextstate = null - var/net_id var/list/areas_added var/list/users_to_open = new var/next_process_time = 0 @@ -58,8 +61,16 @@ "hot", "cold" ) + var/allow_multiple_instances_on_same_tile = FALSE - blend_objects = list(/obj/machinery/door/firedoor, /obj/structure/wall_frame, /turf/unsimulated/wall, /obj/structure/window) // Objects which to blend with +/obj/machinery/door/firedoor/get_blend_objects() + var/static/list/blend_objects = list( + /obj/machinery/door/firedoor, + /obj/structure/wall_frame, + /turf/unsimulated/wall, + /obj/structure/window + ) // Objects which to blend with + return blend_objects /obj/machinery/door/firedoor/autoset autoset_access = TRUE //subtype just to make mapping away sites with custom access usage @@ -68,64 +79,81 @@ /obj/machinery/door/firedoor/Initialize() . = ..() for(var/obj/machinery/door/firedoor/F in loc) - if(F != src) + if(F != src && !F.allow_multiple_instances_on_same_tile) return INITIALIZE_HINT_QDEL - var/area/A = get_area(src) - ASSERT(istype(A)) - - LAZYADD(A.all_doors, src) - areas_added = list(A) - for(var/direction in GLOB.cardinal) - A = get_area(get_step(src,direction)) - if(istype(A) && !(A in areas_added)) - LAZYADD(A.all_doors, src) - areas_added += A + update_area_registrations() /obj/machinery/door/firedoor/Destroy() for(var/area/A in areas_added) - LAZYREMOVE(A.all_doors, src) + unregister_area(A) . = ..() +/obj/machinery/door/firedoor/proc/register_area(area/A) + if(A && !(A in areas_added)) + LAZYADD(A.all_doors, src) + LAZYADD(areas_added, A) + +/obj/machinery/door/firedoor/proc/unregister_area(area/A) + LAZYREMOVE(A.all_doors, src) + LAZYREMOVE(areas_added, A) + +/obj/machinery/door/firedoor/proc/update_area_registrations() + var/list/new_areas = list() + var/area/A = get_area(src) + if(A) + new_areas += A + for(var/direction in global.cardinal) + A = get_area(get_step(src,direction)) + if(A) + new_areas |= A + for(var/area in areas_added) + if(!(area in new_areas)) + unregister_area(area) + for(var/area in (new_areas - areas_added)) + register_area(area) + /obj/machinery/door/firedoor/get_material() - return decls_repository.get_decl(/decl/material/solid/metal/steel) + RETURN_TYPE(/decl/material) + return GET_DECL(/decl/material/solid/metal/steel) -/obj/machinery/door/firedoor/examine(mob/user, distance) +/obj/machinery/door/firedoor/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance > 1 || !density) return if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) - to_chat(user, "WARNING: Current pressure differential is [pdiff]kPa! Opening door may result in injury!") - to_chat(user, "Sensor readings:") + . += SPAN_DANGER("WARNING: Current pressure differential is [pdiff]kPa! Opening door may result in injury!") + + . += "Sensor readings:" for(var/index = 1; index <= tile_info.len; index++) - var/o = "  " + var/list/direction_strings = list("  ") switch(index) if(1) - o += "NORTH: " + direction_strings += "NORTH: " if(2) - o += "SOUTH: " + direction_strings += "SOUTH: " if(3) - o += "EAST: " + direction_strings += "EAST: " if(4) - o += "WEST: " + direction_strings += "WEST: " if(tile_info[index] == null) - o += "DATA UNAVAILABLE" - to_chat(user, o) + direction_strings += "DATA UNAVAILABLE" + . += JOINTEXT(direction_strings) continue var/celsius = convert_k2c(tile_info[index][1]) var/pressure = tile_info[index][2] - o += "" - o += "[celsius]°C " - o += "" - o += "[pressure]kPa" - to_chat(user, o) + direction_strings += "" + direction_strings += "[celsius]°C " + direction_strings += "" + direction_strings += "[pressure]kPa" + . += JOINTEXT(direction_strings) if(islist(users_to_open) && users_to_open.len) var/users_to_open_string = users_to_open[1] if(users_to_open.len >= 2) for(var/i = 2 to users_to_open.len) users_to_open_string += ", [users_to_open[i]]" - to_chat(user, "These people have opened \the [src] during an alert: [users_to_open_string].") + . += "These people have opened \the [src] during an alert: [users_to_open_string]." /obj/machinery/door/firedoor/Bumped(atom/AM) if(panel_open || operating) @@ -134,11 +162,11 @@ return ..() return 0 -/obj/machinery/door/firedoor/attack_hand(mob/user) - add_fingerprint(user) +/obj/machinery/door/firedoor/physical_attack_hand(mob/user) if(operating) - return//Already doing something. + return FALSE//Already doing something. + . = TRUE if(blocked) to_chat(user, "\The [src] is welded solid!") return @@ -189,54 +217,53 @@ nextstate = FIREDOOR_CLOSED close() -/obj/machinery/door/firedoor/attackby(obj/item/C, mob/user) - add_fingerprint(user, 0, C) +/obj/machinery/door/firedoor/attackby(obj/item/used_item, mob/user) + add_fingerprint(user, 0, used_item) if(operating) - return//Already doing something. - if(isWelder(C) && !repairing) - var/obj/item/weldingtool/W = C - if(W.remove_fuel(0, user)) + return TRUE //Already doing something. + if(IS_WELDER(used_item) && !repairing) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0, user)) playsound(src, 'sound/items/Welder.ogg', 100, 1) if(do_after(user, 2 SECONDS, src)) - if(!W.isOn()) return + if(!welder.isOn()) return TRUE blocked = !blocked - user.visible_message("\The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [W].",\ - "You [blocked ? "weld" : "unweld"] \the [src] with \the [W].",\ + user.visible_message("\The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [welder].",\ + "You [blocked ? "weld" : "unweld"] \the [src] with \the [welder].",\ "You hear something being welded.") playsound(src, 'sound/items/Welder.ogg', 100, 1) update_icon() - return else to_chat(user, SPAN_WARNING("You must remain still to complete this task.")) - return + return TRUE - if(!blocked && (isCrowbar(C) || istype(C,/obj/item/twohanded/fireaxe))) - if(operating) - return + if(blocked && IS_CROWBAR(used_item)) + user.visible_message("\The [user] pries at \the [src] with \a [used_item], but \the [src] is welded in place!",\ + "You try to pry \the [src] [density ? "open" : "closed"], but it is welded in place!",\ + "You hear someone struggle and metal straining.") + return TRUE - if(isCrowbar(C)) - user.visible_message("\The [user] pries at \the [src] with \a [C], but \the [src] is welded in place!",\ - "You try to pry \the [src] [density ? "open" : "closed"], but it is welded in place!",\ - "You hear someone struggle and metal straining.") - return + if(!blocked && (IS_CROWBAR(used_item) || istype(used_item,/obj/item/bladed/axe/fire))) + if(operating) + return ..() - if(istype(C,/obj/item/twohanded/fireaxe)) - var/obj/item/twohanded/fireaxe/F = C - if(!F.wielded) - return + if(istype(used_item,/obj/item/bladed/axe/fire)) + var/obj/item/bladed/axe/fire/F = used_item + if(!F.is_held_twohanded()) + return ..() - user.visible_message("\The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [C]!",\ - "You start forcing \the [src] [density ? "open" : "closed"] with \the [C]!",\ + user.visible_message("\The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [used_item]!",\ + "You start forcing \the [src] [density ? "open" : "closed"] with \the [used_item]!",\ "You hear metal strain.") - if(do_after(user,30,src)) - if(isCrowbar(C)) + if(do_after(user, 3 SECONDS, src)) + if(IS_CROWBAR(used_item)) if(stat & (BROKEN|NOPOWER) || !density) - user.visible_message("\The [user] forces \the [src] [density ? "open" : "closed"] with \a [C]!",\ - "You force \the [src] [density ? "open" : "closed"] with \the [C]!",\ + user.visible_message("\The [user] forces \the [src] [density ? "open" : "closed"] with \a [used_item]!",\ + "You force \the [src] [density ? "open" : "closed"] with \the [used_item]!",\ "You hear metal strain, and a door [density ? "open" : "close"].") else - user.visible_message("\The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [C]!",\ - "You force \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \the [C]!",\ + user.visible_message("\The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [used_item]!",\ + "You force \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \the [used_item]!",\ "You hear metal strain and groan, and a door [density ? "opening" : "closing"].") if(density) open(1) @@ -244,6 +271,8 @@ close() else to_chat(user, "You must remain still to interact with \the [src].") + return TRUE + return ..() /obj/machinery/door/firedoor/dismantle(var/moved = FALSE) @@ -261,7 +290,7 @@ var/changed = 0 lockdown=0 // Pressure alerts - pdiff = getOPressureDifferential(src.loc) + pdiff = get_surrounding_pressure_differential(loc, src) if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) lockdown = 1 if(!pdiff_alert) @@ -319,7 +348,7 @@ panel_open = FALSE if(istype(construct_state, /decl/machine_construction/default/panel_open)) var/decl/machine_construction/default/panel_open/open = construct_state - construct_state = open.up_state + construct_state = GET_DECL(open.up_state) construct_state.validate_state(src) visible_message("The maintenance hatch of \the [src] closes.") update_icon() @@ -337,14 +366,22 @@ // Only opens when all areas connecting with our turf have an air alarm and are cleared /obj/machinery/door/firedoor/proc/can_safely_open() var/turf/neighbour - for(var/dir in GLOB.cardinal) - neighbour = get_step(src.loc, dir) - if(neighbour.c_airblock(src.loc) & AIR_BLOCKED) + var/turf/myturf = loc + if(!istype(myturf)) + return TRUE + for(var/dir in global.cardinal) + neighbour = get_step(myturf, dir) + if(!neighbour) continue - for(var/obj/O in src.loc) - if(istype(O, /obj/machinery/door)) + var/airblock // zeroed by ATMOS_CANPASS_TURF, declared early as microopt + ATMOS_CANPASS_TURF(airblock, neighbour, myturf) + if(airblock & AIR_BLOCKED) + continue + for(var/obj/thing in myturf) + if(istype(thing, /obj/machinery/door)) continue - . |= O.c_airblock(neighbour) + ATMOS_CANPASS_MOVABLE(airblock, thing, neighbour) + . |= airblock if(. & AIR_BLOCKED) continue var/area/A = get_area(neighbour) @@ -367,45 +404,80 @@ /obj/machinery/door/firedoor/on_update_icon() - var/icon/lights_overlay - var/icon/panel_overlay - var/icon/weld_overlay - - overlays.Cut() + cut_overlays() set_light(0) var/do_set_light = FALSE - if(connections in list(NORTH, SOUTH, NORTH|SOUTH)) - if(connections in list(WEST, EAST, EAST|WEST)) - set_dir(SOUTH) - else + if(set_dir_on_update) + if(connections & (NORTH|SOUTH)) set_dir(EAST) - else - set_dir(SOUTH) + else + set_dir(SOUTH) if(density) icon_state = "closed" if(panel_open) - overlays = panel_overlay + add_overlay(panel_file) if(pdiff_alert) - lights_overlay += "palert" + add_overlay("palert") do_set_light = TRUE if(dir_alerts) for(var/d=1;d<=4;d++) - var/cdir = GLOB.cardinal[d] + var/cdir = global.cardinal[d] for(var/i=1;i<=ALERT_STATES.len;i++) - if(dir_alerts[d] & (1<<(i-1))) - overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir) + if(dir_alerts[d] & BITFLAG(i-1)) + add_overlay(new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir)) do_set_light = TRUE else icon_state = "open" if(blocked) - weld_overlay = welded_file + add_overlay(welded_file) if(do_set_light) - set_light(0.25, 0.1, 1, 2, COLOR_SUN) + set_light(2, 0.25, COLOR_SUN) + +//Single direction firedoors. +/obj/machinery/door/firedoor/border + icon = 'icons/obj/doors/hazard/door_border.dmi' + allow_multiple_instances_on_same_tile = TRUE + set_dir_on_update = FALSE + heat_proof = TRUE + + //There is a glass window so you can see through the door + //This is needed due to BYOND limitations in controlling visibility + glass = TRUE + +/obj/machinery/door/firedoor/border/autoset + autoset_access = TRUE + req_access = list() - overlays += panel_overlay - overlays += weld_overlay - overlays += lights_overlay +/obj/machinery/door/firedoor/border/CanPass(atom/movable/mover, turf/target, height = 0, air_group = 0) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return TRUE + if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(air_group) + return FALSE + return !density + else + return TRUE + +/obj/machinery/door/firedoor/border/CheckExit(atom/movable/mover, turf/target) + if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) + return TRUE + if(get_dir(loc, target) == dir) + return !density + else + return TRUE + +/obj/machinery/door/firedoor/border/update_nearby_tiles(need_rebuild) + var/turf/source = get_turf(src) + var/turf/destination = get_step(source,dir) + + update_heat_protection(loc) + + if(istype(source) && source.simulated) + SSair.mark_for_update(source) + if(istype(destination) && destination.simulated) + SSair.mark_for_update(destination) + return TRUE diff --git a/code/game/machinery/doors/firedoor_assembly.dm b/code/game/machinery/doors/firedoor_assembly.dm index a2ddb486c282..a861aa14a7db 100644 --- a/code/game/machinery/doors/firedoor_assembly.dm +++ b/code/game/machinery/doors/firedoor_assembly.dm @@ -8,21 +8,48 @@ density = TRUE tool_interaction_flags = TOOL_INTERACTION_ALL -/obj/structure/firedoor_assembly/attackby(var/obj/item/C, var/mob/user) + var/result = /obj/machinery/door/firedoor + +/obj/structure/firedoor_assembly/attackby(var/obj/item/used_item, var/mob/user) . = ..() - if(!. && istype(C, /obj/item/stock_parts/circuitboard/airlock_electronics/firedoor) && wired) + if(!. && istype(used_item, /obj/item/stock_parts/circuitboard/airlock_electronics/firedoor) && wired) if(!anchored) to_chat(user, SPAN_WARNING("You must secure \the [src] first!")) else - if(!user.unEquip(C, src)) + if(!user.try_unequip(used_item, src)) return playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) visible_message(SPAN_NOTICE("\The [user] inserts a circuit into \the [src].")) - var/obj/machinery/door/firedoor/D = new(get_turf(src), dir, FALSE) - var/obj/item/stock_parts/circuitboard/airlock_electronics/firedoor/electronics = C - D.install_component(C) + var/obj/machinery/door/firedoor/D = new result(get_turf(src), dir, FALSE) + var/obj/item/stock_parts/circuitboard/airlock_electronics/firedoor/electronics = used_item + D.install_component(used_item) electronics.construct(D) D.construct_state.post_construct(D) D.close() qdel(src) . = TRUE + +/obj/structure/firedoor_assembly/border + name = "unidirectional emergency shutter assembly" + icon = 'icons/obj/doors/hazard/door_border.dmi' + result = /obj/machinery/door/firedoor/border + +/obj/structure/firedoor_assembly/border/verb/rotate_clock() + set category = "Object" + set name = "Rotate Assembly (Clockwise)" + set src in view(1) + + if (usr.incapacitated() || anchored) + return + + set_dir(turn(dir, -90)) + +/obj/structure/firedoor_assembly/border/verb/rotate_anticlock() + set category = "Object" + set name = "Rotate Assembly (Counter-clockwise)" + set src in view(1) + + if (usr.incapacitated() || anchored) + return + + set_dir(turn(dir, 90)) diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm deleted file mode 100644 index 718e49b51aa4..000000000000 --- a/code/game/machinery/doors/multi_tile.dm +++ /dev/null @@ -1,185 +0,0 @@ -//Terribly sorry for the code doubling, but things go derpy otherwise. -/obj/machinery/door/airlock/multi_tile - airlock_type = "double" - name = "\improper Airlock" - icon = 'icons/obj/doors/double/door.dmi' - fill_file = 'icons/obj/doors/double/fill_steel.dmi' - color_file = 'icons/obj/doors/double/color.dmi' - color_fill_file = 'icons/obj/doors/double/fill_color.dmi' - stripe_file = 'icons/obj/doors/double/stripe.dmi' - stripe_fill_file = 'icons/obj/doors/double/fill_stripe.dmi' - glass_file = 'icons/obj/doors/double/fill_glass.dmi' - bolts_file = 'icons/obj/doors/double/lights_bolts.dmi' - deny_file = 'icons/obj/doors/double/lights_deny.dmi' - lights_file = 'icons/obj/doors/double/lights_green.dmi' - panel_file = 'icons/obj/doors/double/panel.dmi' - welded_file = 'icons/obj/doors/double/welded.dmi' - emag_file = 'icons/obj/doors/double/emag.dmi' - width = 2 - appearance_flags = 0 - opacity = 1 - frame_type = /obj/structure/door_assembly/multi_tile - -/obj/machinery/door/airlock/multi_tile/Initialize() - . = ..() - SetBounds() - -/obj/machinery/door/airlock/multi_tile/Move() - . = ..() - SetBounds() - -/obj/machinery/door/airlock/multi_tile/proc/SetBounds() - if(dir in list(NORTH, SOUTH)) - bound_width = width * world.icon_size - bound_height = world.icon_size - else - bound_width = world.icon_size - bound_height = width * world.icon_size - - -/obj/machinery/door/airlock/multi_tile/on_update_icon(state=0, override=0) - ..() - if(connections in list(NORTH, SOUTH, NORTH|SOUTH)) - if(connections in list(WEST, EAST, EAST|WEST)) - set_dir(SOUTH) - else - set_dir(WEST) - else - set_dir(SOUTH) - -/obj/machinery/door/airlock/multi_tile/update_connections(var/propagate = 0) - var/dirs = 0 - - for(var/direction in GLOB.cardinal) - var/turf/T = get_step(src, direction) - var/success = 0 - - if(direction in list(NORTH, EAST)) - T = get_step(T, direction) - - if( istype(T, /turf/simulated/wall)) - success = 1 - if(propagate) - var/turf/simulated/wall/W = T - W.update_connections() - W.update_icon() - - else if( istype(T, /turf/simulated/shuttle/wall)) - success = 1 - else - for(var/obj/O in T) - for(var/b_type in blend_objects) - if( istype(O, b_type)) - success = 1 - - if(success) - break - if(success) - break - - if(success) - dirs |= direction - connections = dirs - -/obj/machinery/door/airlock/multi_tile/command - door_color = COLOR_COMMAND_BLUE - -/obj/machinery/door/airlock/multi_tile/security - door_color = COLOR_NT_RED - -/obj/machinery/door/airlock/multi_tile/engineering - name = "Maintenance Hatch" - door_color = COLOR_AMBER - -/obj/machinery/door/airlock/multi_tile/medical - door_color = COLOR_WHITE - stripe_color = COLOR_DEEP_SKY_BLUE - -/obj/machinery/door/airlock/multi_tile/virology - door_color = COLOR_WHITE - stripe_color = COLOR_GREEN - -/obj/machinery/door/airlock/multi_tile/mining - name = "Mining Airlock" - door_color = COLOR_PALE_ORANGE - stripe_color = COLOR_BEASTY_BROWN - -/obj/machinery/door/airlock/multi_tile/atmos - door_color = COLOR_AMBER - stripe_color = COLOR_CYAN - -/obj/machinery/door/airlock/multi_tile/research - door_color = COLOR_WHITE - stripe_color = COLOR_RESEARCH - -/obj/machinery/door/airlock/multi_tile/science - door_color = COLOR_WHITE - stripe_color = COLOR_VIOLET - -/obj/machinery/door/airlock/multi_tile/sol - door_color = COLOR_BLUE_GRAY - -/obj/machinery/door/airlock/multi_tile/maintenance - name = "Maintenance Access" - stripe_color = COLOR_AMBER - -/obj/machinery/door/airlock/multi_tile/civilian - stripe_color = COLOR_CIVIE_GREEN - -/obj/machinery/door/airlock/multi_tile/freezer - name = "Freezer Airlock" - door_color = COLOR_WHITE - -/obj/machinery/door/airlock/multi_tile/glass - name = "Glass Airlock" - glass = 1 - -/obj/machinery/door/airlock/multi_tile/glass/command - door_color = COLOR_COMMAND_BLUE - stripe_color = COLOR_SKY_BLUE - -/obj/machinery/door/airlock/multi_tile/glass/security - door_color = COLOR_NT_RED - stripe_color = COLOR_ORANGE - -/obj/machinery/door/airlock/multi_tile/glass/engineering - door_color = COLOR_AMBER - stripe_color = COLOR_RED - -/obj/machinery/door/airlock/multi_tile/glass/medical - door_color = COLOR_WHITE - stripe_color = COLOR_DEEP_SKY_BLUE - -/obj/machinery/door/airlock/multi_tile/glass/virology - door_color = COLOR_WHITE - stripe_color = COLOR_GREEN - -/obj/machinery/door/airlock/multi_tile/glass/mining - door_color = COLOR_PALE_ORANGE - stripe_color = COLOR_BEASTY_BROWN - -/obj/machinery/door/airlock/multi_tile/glass/atmos - door_color = COLOR_AMBER - stripe_color = COLOR_CYAN - -/obj/machinery/door/airlock/multi_tile/glass/research - door_color = COLOR_WHITE - stripe_color = COLOR_RESEARCH - -/obj/machinery/door/airlock/multi_tile/glass/science - door_color = COLOR_WHITE - stripe_color = COLOR_VIOLET - -/obj/machinery/door/airlock/multi_tile/glass/sol - door_color = COLOR_BLUE_GRAY - stripe_color = COLOR_AMBER - -/obj/machinery/door/airlock/multi_tile/glass/freezer - door_color = COLOR_WHITE - -/obj/machinery/door/airlock/multi_tile/glass/maintenance - name = "Maintenance Access" - stripe_color = COLOR_AMBER - -/obj/machinery/door/airlock/multi_tile/glass/civilian - stripe_color = COLOR_CIVIE_GREEN \ No newline at end of file diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index c3cf317dc9ef..57c7d8feb451 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -5,20 +5,24 @@ icon_state = "left" min_force = 4 hitsound = 'sound/effects/Glasshit.ogg' - maxhealth = 150 //If you change this, consiter changing ../door/window/brigdoor/ health at the bottom of this .dm file - health = 150 + max_health = 150 //If you change this, consider changing ../door/window/brigdoor/ health at the bottom of this .dm file visible = 0.0 use_power = POWER_USE_OFF + stat_immune = NOSCREEN | NOINPUT | NOPOWER uncreated_component_parts = null - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CHECKS_BORDER - opacity = 0 + atom_flags = ATOM_FLAG_CHECKS_BORDER + opacity = FALSE explosion_resistance = 5 - air_properties_vary_with_direction = 1 pry_mod = 0.5 base_type = /obj/machinery/door/window frame_type = /obj/structure/windoor_assembly + set_dir_on_update = FALSE // these can properly face all 4 directions! don't force us into just 2! var/base_state = "left" +/obj/machinery/door/window/get_auto_access() + var/area/A = get_area(src) + return A?.req_access?.Copy() + /obj/machinery/door/window/Initialize(mapload, d, populate_parts = TRUE, obj/structure/windoor_assembly/assembly) if(assembly) set_density(0) @@ -55,21 +59,21 @@ if (!( ismob(AM) )) var/mob/living/bot/bot = AM if(istype(bot)) - if(density && src.check_access(bot.botcard)) + if(density && check_access(bot.botcard)) open() - sleep(50) - close() + addtimer(CALLBACK(src, PROC_REF(close)), 50, TIMER_UNIQUE | TIMER_OVERRIDE) return var/mob/M = AM // we've returned by here if M is not a mob - if (src.operating) + if (operating) return - if (src.density && (!issmall(M) || ishuman(M) || issilicon(M)) && src.allowed(AM)) + if (density && (!issmall(M) || ishuman(M) || issilicon(M)) && allowed(AM)) open() - if(src.check_access(null)) - sleep(50) + var/open_timer + if(check_access(null)) + open_timer = 50 else //secure doors close faster - sleep(20) - close() + open_timer = 20 + addtimer(CALLBACK(src, PROC_REF(close)), open_timer, TIMER_UNIQUE | TIMER_OVERRIDE) return /obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) @@ -92,59 +96,70 @@ /obj/machinery/door/window/open() if (operating == 1) //doors can still open when emag-disabled return 0 - if (!src.operating) //in case of emag - src.operating = 1 + if (!operating) //in case of emag + operating = 1 - flick("[src.base_state]opening", src) - playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1) - sleep(10) + icon_state = "[base_state]open" + flick("[base_state]opening", src) + playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) + sleep(0.9 SECONDS) explosion_resistance = 0 - set_density(0) + set_density(FALSE) update_icon() update_nearby_tiles() if(operating == 1) //emag again - src.operating = 0 - return 1 + operating = 0 + + return TRUE /obj/machinery/door/window/close() - if (src.operating) + if (operating) return 0 + operating = 1 - flick(text("[]closing", src.base_state), src) - playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1) - set_density(1) + flick("[base_state]closing", src) + playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) + set_density(TRUE) update_icon() explosion_resistance = initial(explosion_resistance) update_nearby_tiles() - sleep(10) - src.operating = 0 - return 1 + sleep(0.9 SECONDS) + operating = 0 -/obj/machinery/door/window/take_damage(var/damage) - src.health = max(0, src.health - damage) - if (src.health <= 0) + return TRUE + +/obj/machinery/door/window/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + current_health = max(0, current_health - damage) + if (current_health <= 0) shatter() return /obj/machinery/door/window/physical_attack_hand(mob/user) - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species.can_shred(H)) - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - visible_message("[user] smashes against the [src.name].", 1) - take_damage(25) - return TRUE + if(user.can_shred()) + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + visible_message(SPAN_DANGER("\The [user] smashes against \the [src].")) + take_damage(25) + return TRUE + return ..() /obj/machinery/door/window/emag_act(var/remaining_charges, var/mob/user) - if (density && operable()) - operating = -1 - flick("[src.base_state]spark", src) - sleep(6) - open() - return 1 + if (emagged) + to_chat(user, SPAN_WARNING("\The [src] has already been locked open.")) + return FALSE + if (!operable()) + to_chat(user, SPAN_WARNING("\The [src] is not functioning and doesn't respond to your attempts to short the circuitry.")) + return FALSE + + operating = -1 + emagged = TRUE + to_chat(user, SPAN_NOTICE("You short out \the [src]'s internal circuitry, locking it open!")) + if (density) + flick("[base_state]spark", src) + addtimer(CALLBACK(src, PROC_REF(open)), 6, TIMER_UNIQUE | TIMER_OVERRIDE) + return TRUE /obj/machinery/door/emp_act(severity) if(prob(20/severity)) @@ -153,37 +168,43 @@ ..() /obj/machinery/door/window/CanFluidPass(var/coming_from) - return !density || ((dir in GLOB.cardinal) && coming_from != dir) + return !density || ((dir in global.cardinal) && coming_from != dir) -/obj/machinery/door/window/attackby(obj/item/I, mob/user) +/obj/machinery/door/window/attackby(obj/item/used_item, mob/user) //If it's in the process of opening/closing, ignore the click - if (src.operating == 1) - return + if(operating) + return TRUE + + if(bash(used_item, user)) + return TRUE . = ..() if(.) return - if (src.allowed(user)) - if (src.density) + if (allowed(user)) + if (density) open() else + if (emagged) + to_chat(user, SPAN_WARNING("\The [src] seems to be stuck and refuses to close!")) + return TRUE close() - - else if (src.density) - flick(text("[]deny", src.base_state), src) - -/obj/machinery/door/window/bash(obj/item/I, mob/user) - //Emags and ninja swords? You may pass. - if (istype(I, /obj/item/energy_blade/blade)) - if(emag_act(10, user)) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src.loc) - spark_system.start() - playsound(src.loc, "sparks", 50, 1) - playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + return TRUE + + else if (density) + flick("[base_state]deny", src) + return TRUE + +/obj/machinery/door/window/bash(obj/item/weapon, mob/user) + //Emags and energy swords? You may pass. + if (weapon.user_can_attack_with(user) && istype(weapon, /obj/item/energy_blade)) + var/obj/item/energy_blade/blade = weapon + if(blade.is_special_cutting_tool() && emag_act(10, user)) + spark_at(loc, amount=5) + playsound(loc, 'sound/weapons/blade1.ogg', 50, 1) visible_message(SPAN_WARNING("The glass door was sliced open by [user]!")) - return 1 + return TRUE return ..() /obj/machinery/door/window/brigdoor @@ -191,12 +212,9 @@ icon = 'icons/obj/doors/windoor.dmi' icon_state = "leftsecure" base_state = "leftsecure" - var/id = null - maxhealth = 300 - health = 300.0 //Stronger doors for prison (regular window door health is 150) + max_health = 300 //Stronger doors for prison (regular window door health is 150) pry_mod = 0.65 - /obj/machinery/door/window/northleft dir = NORTH diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm index 4e783daca4f7..9f63beb85628 100644 --- a/code/game/machinery/doppler_array.dm +++ b/code/game/machinery/doppler_array.dm @@ -1,4 +1,4 @@ -var/list/doppler_arrays = list() +var/global/list/doppler_arrays = list() /obj/machinery/doppler_array name = "tachyon-doppler array" @@ -34,10 +34,7 @@ var/list/doppler_arrays = list() if(distance > 100) return if(!(direct & dir)) return - var/message = "Explosive disturbance detected - Epicenter at: grid ([x0],[y0]). Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range]. Temporal displacement of tachyons: [took]seconds." - - for(var/mob/O in hearers(src, null)) - O.show_message("[src] states coldly, \"[message]\"",2) + audible_message("[src] states coldly, \"Explosive disturbance detected - Epicenter at: grid ([x0],[y0]). Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range]. Temporal displacement of tachyons: [took]seconds.\"") /obj/machinery/doppler_array/on_update_icon() if(stat & BROKEN) diff --git a/code/game/machinery/embedded_controller/airlock_controllers.dm b/code/game/machinery/embedded_controller/airlock_controllers.dm index 5171ca7de183..346dfab73c36 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers.dm @@ -11,14 +11,27 @@ var/tag_interior_sensor var/tag_secure = 0 var/tag_air_alarm - var/list/dummy_terminals = list() + var/list/dummy_terminals = list() // Internal use only; set id_tag on the dummy terminal to be added. var/cycle_to_external_air = 0 + var/tag_pump_out_external + var/tag_pump_out_internal + +/obj/machinery/embedded_controller/radio/airlock/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(tag_exterior_door, map_hash) + ADJUST_TAG_VAR(tag_interior_door, map_hash) + ADJUST_TAG_VAR(tag_airpump, map_hash) + ADJUST_TAG_VAR(tag_chamber_sensor, map_hash) + ADJUST_TAG_VAR(tag_exterior_sensor, map_hash) + ADJUST_TAG_VAR(tag_interior_sensor, map_hash) + ADJUST_TAG_VAR(tag_air_alarm, map_hash) + ADJUST_TAG_VAR(tag_pump_out_external, map_hash) + ADJUST_TAG_VAR(tag_pump_out_internal, map_hash) /obj/machinery/embedded_controller/radio/airlock/Destroy() - for(var/thing in dummy_terminals) - var/obj/machinery/dummy_airlock_controller/dummy = thing - dummy.master_controller = null - dummy_terminals.Cut() + for(var/obj/machinery/dummy_airlock_controller/terminal in dummy_terminals) + terminal.on_master_destroyed() + LAZYCLEARLIST(dummy_terminals) return ..() /obj/machinery/embedded_controller/radio/airlock/CanUseTopic(var/mob/user) @@ -27,11 +40,26 @@ else return ..() +/**Adds a dummy remote controller to our list of dummy controllers. */ +/obj/machinery/embedded_controller/radio/airlock/proc/add_remote_terminal(var/obj/machinery/dummy_airlock_controller/C) + LAZYADD(dummy_terminals, C) + +/**Removes a dummy remote controller from our list of dummy controllers. */ +/obj/machinery/embedded_controller/radio/airlock/proc/remove_remote_terminal(var/obj/machinery/dummy_airlock_controller/C) + LAZYREMOVE(dummy_terminals, C) + +/obj/machinery/embedded_controller/radio/airlock/on_update_icon() + . = ..() + //Make sure we keep our terminals updated + for(var/obj/machinery/dummy_airlock_controller/terminal in dummy_terminals) + terminal.update_icon() + //Advanced airlock controller for when you want a more versatile airlock controller - useful for turning simple access control rooms into airlocks /obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller name = "Advanced Airlock Controller" + base_type = /obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller -/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] data = list( @@ -45,7 +73,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "advanced_airlock_console.tmpl", name, 470, 290, state = state) + ui = new(user, src, ui_key, "advanced_airlock_console.tmpl", name, 470, 360, state = state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -54,8 +82,9 @@ /obj/machinery/embedded_controller/radio/airlock/airlock_controller name = "Airlock Controller" tag_secure = 1 + base_type = /obj/machinery/embedded_controller/radio/airlock/airlock_controller -/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] data = list( @@ -67,18 +96,18 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "simple_airlock_console.tmpl", name, 470, 290, state = state) + ui = new(user, src, ui_key, "simple_airlock_console.tmpl", name, 470, 360, state = state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) //Access controller for door control - used in virology and the like /obj/machinery/embedded_controller/radio/airlock/access_controller - icon = 'icons/obj/airlock_machines.dmi' name = "Access Controller" tag_secure = 1 + base_type = /obj/machinery/embedded_controller/radio/airlock/access_controller -/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] data = list( @@ -92,4 +121,4 @@ ui = new(user, src, ui_key, "door_access_console.tmpl", name, 330, 220, state = state) ui.set_initial_data(data) ui.open() - ui.set_auto_update(1) \ No newline at end of file + ui.set_auto_update(1) diff --git a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm index 4f672c58991b..66aa8d5c057c 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm @@ -1,50 +1,150 @@ -// Provides remote access to a controller (since they must be unique). +///Provides remote access to a controller (since they must be unique). /obj/machinery/dummy_airlock_controller - name = "airlock control terminal" - icon = 'icons/obj/airlock_machines.dmi' - icon_state = "airlock_control_standby" - layer = ABOVE_OBJ_LAYER - + name = "remote airlock control terminal" + desc = "A secondary airlock control terminal meant to be subordinated to a master airlock control terminal to allow remotely controlling the latter from the former." + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "airlock_control_off" + layer = ABOVE_OBJ_LAYER + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + base_type = /obj/machinery/dummy_airlock_controller + construct_state = /decl/machine_construction/wall_frame/panel_closed + frame_type = /obj/item/frame/button/airlock_controller + directional_offset = @'{"NORTH":{"y":-22}, "SOUTH":{"y":24}, "EAST":{"x":-22}, "WEST":{"x":22}}' + power_channel = ENVIRON //Same as airlock controller + required_interaction_dexterity = DEXTERITY_TOUCHSCREENS + ///Topic state used to interact remotely with the master controller's UI var/datum/topic_state/remote/remote_state + ///Master controller we're subordinated to var/obj/machinery/embedded_controller/radio/airlock/master_controller -/obj/machinery/dummy_airlock_controller/Process() - if(master_controller) - appearance = master_controller +/obj/machinery/dummy_airlock_controller/Initialize(mapload, d, populate_parts) . = ..() + set_extension(src, /datum/extension/interactive/multitool/embedded_controller_terminal) + update_icon() + if(mapload && length(id_tag)) + return INITIALIZE_HINT_LATELOAD -/obj/machinery/dummy_airlock_controller/Initialize() +/obj/machinery/dummy_airlock_controller/LateInitialize() . = ..() - if(id_tag) - for(var/obj/machinery/embedded_controller/radio/airlock/_master in SSmachines.machinery) - if(_master.id_tag == id_tag) - master_controller = _master - master_controller.dummy_terminals += src - break - if(!master_controller) + if(!setup_target_controller()) + log_warning("\The mapped [src] ([x], [y], [z]) couldn't find a matching airlock controller with id_tag '[id_tag? id_tag : "null"]'. Deleting!") qdel(src) - else - remote_state = new /datum/topic_state/remote(src, master_controller) + return /obj/machinery/dummy_airlock_controller/Destroy() if(master_controller) - master_controller.dummy_terminals -= src - if(remote_state) - qdel(remote_state) - remote_state = null + unset_target_controller() + QDEL_NULL(remote_state) return ..() /obj/machinery/dummy_airlock_controller/interface_interact(var/mob/user) - open_remote_ui(user) + if(!master_controller) + //#TODO: Show error UI + return FALSE + master_controller.ui_interact(user, state = remote_state) + return TRUE + +/obj/machinery/dummy_airlock_controller/proc/setup_target_controller() + if(!id_tag) + return FALSE + unset_target_controller() + for(var/obj/machinery/embedded_controller/radio/airlock/_master in SSmachines.machinery) + if(_master.id_tag == id_tag) + master_controller = _master + master_controller.add_remote_terminal(src) + break + if(!master_controller) + return FALSE + remote_state = new /datum/topic_state/remote(src, master_controller) + update_icon() return TRUE -/obj/machinery/dummy_airlock_controller/proc/open_remote_ui(var/mob/user) +/obj/machinery/dummy_airlock_controller/set_id_tag(new_id_tag) + unset_target_controller() + . = ..() + setup_target_controller() + +/obj/machinery/dummy_airlock_controller/proc/unset_target_controller() if(master_controller) - appearance = master_controller - return master_controller.ui_interact(user, state = remote_state) + master_controller.remove_remote_terminal(src) + master_controller = null + QDEL_NULL(remote_state) + update_icon() + +/**Callback from the master controller when it is destroyed. */ +/obj/machinery/dummy_airlock_controller/proc/on_master_destroyed() + unset_target_controller() + +/**Update our appearence and state to match our parent's, unless we don't have a parent.*/ +/obj/machinery/dummy_airlock_controller/on_update_icon() + cut_overlays() + icon_state = initial(icon_state) + if(!operable() || !use_power) + set_light(0) + return -/obj/machinery/dummy_airlock_controller/powered(var/chan = -1, var/area/check_area = null) if(master_controller) - var/area/A = get_area(master_controller) - return master_controller.powered(chan, A) - return ..() \ No newline at end of file + if(master_controller.screen_state) + add_overlay(master_controller.screen_state) + if(master_controller.indicator_state & master_controller.INDICATOR_FLAG_DONE) + add_overlay("indicator_done") + if(master_controller.indicator_state & master_controller.INDICATOR_FLAG_ACTIVE) + add_overlay("indicator_active") + if(master_controller.indicator_state & master_controller.INDICATOR_FLAG_FORCED) + add_overlay("indicator_forced") + set_light(master_controller.light_range, master_controller.light_power, master_controller.light_color) + else + //Disconnected screen + add_overlay("screen_disconnected") + add_overlay("indicator_active") + add_overlay("indicator_done") + add_overlay("indicator_forced") + set_light(l_range = 2, l_power = 0.5, l_color = "#bf3133") + +//////////////////////////////////////////////////////////////////////////////// +// Multitool Interaction +//////////////////////////////////////////////////////////////////////////////// +/datum/extension/interactive/multitool/embedded_controller_terminal + expected_type = /obj/machinery/dummy_airlock_controller + //#TODO: Maybe make some predicates to only allow authorized people to do maintenance and etc + +/datum/extension/interactive/multitool/embedded_controller_terminal/get_interact_window(var/obj/item/multitool/M, var/mob/user) + var/obj/machinery/dummy_airlock_controller/terminal = holder + if(!istype(terminal)) + return + . = list() + . += "ID tag: [terminal.id_tag]
    " + . += "Nearby controllers:
    " + + var/list/controllers + for(var/obj/machinery/embedded_controller/radio/C in range(12, terminal)) + LAZYADD(controllers, " [C][C.id_tag] ") + + if(!LAZYLEN(controllers)) + . += "None." + else + . += "[JOINTEXT(controllers)]
    " + + . = JOINTEXT(.) + +/datum/extension/interactive/multitool/embedded_controller_terminal/on_topic(href, href_list, user) + var/obj/machinery/dummy_airlock_controller/terminal = holder + if(href_list["input_tag"]) + var/new_tag = input(user, "Enter the tag of the controller to connect to.", "Tag Selection", terminal.id_tag) as text|null + if(extension_status(user) != STATUS_INTERACTIVE) + return TOPIC_NOACTION + new_tag = sanitize_name(new_tag, MAX_MESSAGE_LEN, TRUE, FALSE) + if(new_tag) + terminal.id_tag = new_tag + terminal.setup_target_controller() + return TOPIC_REFRESH + + if(istext(href_list["set_tag"])) + var/new_tag = href_list["set_tag"] + new_tag = sanitize_name(new_tag, MAX_MESSAGE_LEN, TRUE, FALSE) + if(new_tag) + terminal.id_tag = new_tag + terminal.setup_target_controller() + return TOPIC_REFRESH + + return ..() diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller.dm b/code/game/machinery/embedded_controller/airlock_docking_controller.dm index f1afffe7f3f3..0605e8f0ff8e 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller.dm @@ -12,19 +12,20 @@ var/datum/computer/file/embedded_program/docking/airlock/docking_program = program docking_program.display_name = display_name -/obj/machinery/embedded_controller/radio/airlock/docking_port/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/multitool)) //give them part of code, would take few tries to get full +/obj/machinery/embedded_controller/radio/airlock/docking_port/attackby(obj/item/used_item, mob/user) + if(IS_MULTITOOL(used_item)) //give them part of code, would take few tries to get full var/datum/computer/file/embedded_program/docking/airlock/docking_program = program var/code = docking_program.docking_codes if(!code) code = "N/A" else code = stars(code) - to_chat(user,"[W]'s screen displays '[code]'") + to_chat(user,"[used_item]'s screen displays '[code]'") + return TRUE else - ..() + return ..() -/obj/machinery/embedded_controller/radio/airlock/docking_port/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/airlock/docking_port/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] var/datum/computer/file/embedded_program/docking/airlock/docking_program = program var/datum/computer/file/embedded_program/airlock/docking/airlock_program = docking_program.airlock_program @@ -59,7 +60,7 @@ airlock_program.master_prog = src /datum/computer/file/embedded_program/docking/airlock/Destroy() - qdel(airlock_program) + QDEL_NULL(airlock_program) return ..() /datum/computer/file/embedded_program/docking/airlock/receive_user_command(command) @@ -68,7 +69,7 @@ disable_override() else enable_override() - return TRUE + return TOPIC_REFRESH . = ..(command) . = airlock_program.receive_user_command(command) || . //pass along to subprograms; bypass shortcircuit @@ -128,6 +129,7 @@ /datum/computer/file/embedded_program/airlock/docking/receive_user_command(command) if (master_prog.undocked() || master_prog.override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled return ..(command) + return TOPIC_NOACTION /datum/computer/file/embedded_program/airlock/docking/proc/open_doors() toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open") diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm index 2ca41d7a8513..ea88e24d38da 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm @@ -15,7 +15,16 @@ for (var/i = 1; i <= tags.len; i++) child_names[tags[i]] = names[i] -/obj/machinery/embedded_controller/radio/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/docking_port_multi/modify_mapped_vars(map_hash) + ..() + var/list/tags = splittext(child_tags_txt, ";") + var/list/new_tags = list() + for(var/thing in tags) + ADJUST_TAG_VAR(thing, map_hash) + new_tags += thing + child_tags_txt = jointext(new_tags, ";") + +/obj/machinery/embedded_controller/radio/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] var/datum/computer/file/embedded_program/docking/multi/docking_program = program @@ -37,8 +46,8 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/embedded_controller/radio/docking_port_multi/Topic(href, href_list) - return 1 // Apparently we swallow all input (this is corrected legacy code) +/obj/machinery/embedded_controller/radio/docking_port_multi/OnTopic(user, href_list) + return TOPIC_HANDLED // Apparently we swallow all input (this is corrected legacy code) @@ -49,7 +58,11 @@ var/master_tag //for mapping tag_secure = 1 -/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(master_tag, map_hash) + +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] var/datum/computer/file/embedded_program/airlock/multi_docking/airlock_program = program diff --git a/code/game/machinery/embedded_controller/airlock_program.dm b/code/game/machinery/embedded_controller/airlock_program.dm index 710da1c151d7..467b170bd841 100644 --- a/code/game/machinery/embedded_controller/airlock_program.dm +++ b/code/game/machinery/embedded_controller/airlock_program.dm @@ -9,7 +9,7 @@ #define TARGET_INOPEN -1 #define TARGET_OUTOPEN -2 -#define SENSOR_TOLERANCE 1 +#define SENSOR_TOLERANCE 0.5 /datum/computer/file/embedded_program/airlock var/tag_exterior_door @@ -48,11 +48,11 @@ /datum/computer/file/embedded_program/airlock/reset_id_tags(base_tag) . = ..() - if(cycle_to_external_air) - tag_pump_out_external = "[id_tag]_pump_out_external" - tag_pump_out_internal = "[id_tag]_pump_out_internal" if(istype(master, /obj/machinery/embedded_controller/radio/airlock)) //if our controller is an airlock controller than we can auto-init our tags var/obj/machinery/embedded_controller/radio/airlock/controller = master + if(cycle_to_external_air) + tag_pump_out_external = SET_AIRLOCK_TAG(controller.tag_pump_out_external, "[id_tag]_pump_out_external") + tag_pump_out_internal = SET_AIRLOCK_TAG(controller.tag_pump_out_internal, "[id_tag]_pump_out_internal") tag_exterior_door = SET_AIRLOCK_TAG(controller.tag_exterior_door, "[id_tag]_outer") tag_interior_door = SET_AIRLOCK_TAG(controller.tag_interior_door, "[id_tag]_inner") tag_airpump = SET_AIRLOCK_TAG(controller.tag_airpump, "[id_tag]_pump") @@ -89,24 +89,30 @@ if(!receive_tag) return if(receive_tag==tag_chamber_sensor) - if(signal.data["pressure"]) + if("pressure" in signal.data) memory["chamber_sensor_pressure"] = text2num(signal.data["pressure"]) else if(receive_tag==tag_exterior_sensor) - memory["external_sensor_pressure"] = text2num(signal.data["pressure"]) + if("pressure" in signal.data) + memory["external_sensor_pressure"] = text2num(signal.data["pressure"]) else if(receive_tag==tag_interior_sensor) - memory["internal_sensor_pressure"] = text2num(signal.data["pressure"]) + if("pressure" in signal.data) + memory["internal_sensor_pressure"] = text2num(signal.data["pressure"]) else if(receive_tag==tag_exterior_door) - memory["exterior_status"]["state"] = signal.data["door_status"] - memory["exterior_status"]["lock"] = signal.data["lock_status"] + if("door_status" in signal.data) + memory["exterior_status"]["state"] = signal.data["door_status"] + if("lock_status" in signal.data) + memory["exterior_status"]["lock"] = signal.data["lock_status"] else if(receive_tag==tag_interior_door) - memory["interior_status"]["state"] = signal.data["door_status"] - memory["interior_status"]["lock"] = signal.data["lock_status"] + if("door_status" in signal.data) + memory["interior_status"]["state"] = signal.data["door_status"] + if("lock_status" in signal.data) + memory["interior_status"]["lock"] = signal.data["lock_status"] - else if(receive_tag==tag_airpump || receive_tag==tag_pump_out_internal) + else if((receive_tag==tag_airpump || receive_tag==tag_pump_out_internal) && ("power" in signal.data)) if(signal.data["power"]) memory["pump_status"] = signal.data["direction"] else @@ -139,7 +145,7 @@ /datum/computer/file/embedded_program/airlock/receive_user_command(command) var/shutdown_pump = 0 - . = TRUE + . = TOPIC_REFRESH switch(command) if("cycle_ext") //If airlock is already cycled in this direction, just toggle the doors. @@ -182,7 +188,7 @@ toggleDoor(memory["interior_status"], tag_interior_door, !memory["secure"]) memory["secure"] = !memory["secure"] else - . = FALSE + . = TOPIC_NOACTION if(shutdown_pump) signalPump(tag_airpump, 0) //send a signal to stop pressurizing @@ -228,7 +234,7 @@ signalPump(tag_airpump, 1, 0, target_pressure) //send a signal to start depressurizing else signalPump(tag_pump_out_internal, 1, 0, target_pressure) // if going inside, pump external air out of the airlock - signalPump(tag_pump_out_external, 1, 1, 1000) // make sure the air is actually going outside + signalPump(tag_pump_out_external, 1, 1, MAX_PUMP_PRESSURE) // make sure the air is actually going outside else if(chamber_pressure <= target_pressure) state = STATE_PRESSURIZE @@ -259,8 +265,7 @@ signalPump(tag_pump_out_external, 0) else cycleDoors(target_state) - state = STATE_IDLE - target_state = TARGET_NONE + stop_cycling() if(STATE_DEPRESSURIZE) @@ -278,8 +283,7 @@ state = STATE_PREPARE else cycleDoors(target_state) - state = STATE_IDLE - target_state = TARGET_NONE + stop_cycling() memory["processing"] = (state != target_state) @@ -294,12 +298,14 @@ memory["purge"] = cycle_to_external_air playsound(master, 'sound/machines/warning-buzzer.ogg', 50) shutAlarm() + signalCycling(TRUE) /datum/computer/file/embedded_program/airlock/proc/begin_dock_cycle() state = STATE_IDLE target_state = TARGET_INOPEN playsound(master, 'sound/machines/warning-buzzer.ogg', 50) shutAlarm() + signalCycling(TRUE) /datum/computer/file/embedded_program/airlock/proc/begin_cycle_out() state = STATE_IDLE @@ -307,6 +313,7 @@ memory["purge"] = cycle_to_external_air playsound(master, 'sound/machines/warning-buzzer.ogg', 50) shutAlarm() + signalCycling(TRUE) /datum/computer/file/embedded_program/airlock/proc/close_doors() toggleDoor(memory["interior_status"], tag_interior_door, 1, "close") @@ -315,6 +322,7 @@ /datum/computer/file/embedded_program/airlock/proc/stop_cycling() state = STATE_IDLE target_state = TARGET_NONE + signalCycling(FALSE) /datum/computer/file/embedded_program/airlock/proc/done_cycling() return (state == STATE_IDLE && target_state == TARGET_NONE) @@ -368,12 +376,34 @@ toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "close") toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open") +/datum/computer/file/embedded_program/proc/signalCycling(var/cycling = TRUE) + var/datum/signal/signal = new + //Send signal to buttons first + signal.data["tag"] = id_tag + signal.data["set_airlock_cycling"] = cycling + post_signal(signal) + +/datum/computer/file/embedded_program/airlock/signalCycling(cycling = TRUE) + . = ..() + var/datum/signal/signal = new + signal.data["set_airlock_cycling"] = cycling + //Send signal to sensors + if(length(tag_chamber_sensor)) + signal.data["tag"] = tag_chamber_sensor + post_signal(signal) + if(length(tag_interior_sensor)) + signal.data["tag"] = tag_interior_sensor + post_signal(signal) + if(length(tag_exterior_sensor)) + signal.data["tag"] = tag_exterior_sensor + post_signal(signal) + /*---------------------------------------------------------- toggleDoor() Sends a radio command to a door to either open or close. If the command is 'toggle' the door will be sent a command that -reverses it's current state. +reverses its current state. Can also toggle whether the door bolts are locked or not, depending on the state of the 'secure' flag. Only sends a command if it is needed, i.e. if the door is @@ -386,6 +416,8 @@ send an additional command to open the door again. if(command == "toggle") command = doorStatus["state"] == "open" ? "close" : "open" + // the close command is 'close' but the closed state is 'closed' + // so we have to check if we aren't the open state, because the command and status strings match for it var/toggle = command && ((doorStatus["state"] == "open") ^ (command == "open")) var/locked = (doorStatus["lock"] == "locked") if(toggle) diff --git a/code/game/machinery/embedded_controller/docking_program.dm b/code/game/machinery/embedded_controller/docking_program.dm index 84f8f1d62a03..c247336a132b 100644 --- a/code/game/machinery/embedded_controller/docking_program.dm +++ b/code/game/machinery/embedded_controller/docking_program.dm @@ -57,7 +57,7 @@ var/response_sent = 0 //so we don't spam confirmation messages var/override_enabled = 0 //when enabled, do not open/close doors or cycle airlocks and wait for the player to do it manually - var/received_confirm = 0 //for undocking, whether the server has recieved a confirmation from the client + var/received_confirm = 0 //for undocking, whether the server has received a confirmation from the client var/docking_codes //would only allow docking when receiving signal with these, if set var/display_name //how would it show up on docking monitoring program, area name + coordinates if unset @@ -68,7 +68,7 @@ . = ..() if(id_tag) if(SSshuttle.docking_registry[id_tag]) - crash_with("Docking controller tag [id_tag] had multiple associated programs.") + PRINT_STACK_TRACE("Docking controller tag [id_tag] had multiple associated programs.") SSshuttle.docking_registry[id_tag] = src /datum/computer/file/embedded_program/docking/Destroy() @@ -78,8 +78,8 @@ /datum/computer/file/embedded_program/docking/receive_user_command(command) if(command == "dock" || command == "undock") - if(!tag_target) //Prevents from self destructing if no docking buddy - return FALSE + if(!tag_target) //Prevents from self-destructing if no docking buddy + return TOPIC_NOACTION var/datum/signal/signal = new() signal.data["tag"] = tag_target @@ -87,7 +87,8 @@ signal.data["recipient"] = id_tag signal.data["code"] = docking_codes receive_signal(signal) - return TRUE + return TOPIC_REFRESH + return TOPIC_NOACTION /datum/computer/file/embedded_program/docking/get_receive_filters() return list("[id_tag]" = "primary controller") @@ -297,4 +298,4 @@ if (STATE_DOCKED) return "docked" /datum/computer/file/embedded_program/docking/proc/get_name() - return display_name ? display_name : "[get_area(master)] ([master.x], [master.y])" + return display_name ? display_name : "[get_area_name(master)] ([master.x], [master.y])" diff --git a/code/game/machinery/embedded_controller/docking_program_multi.dm b/code/game/machinery/embedded_controller/docking_program_multi.dm index c525e650e890..45da8d68e822 100644 --- a/code/game/machinery/embedded_controller/docking_program_multi.dm +++ b/code/game/machinery/embedded_controller/docking_program_multi.dm @@ -135,10 +135,11 @@ else override_enabled = 1 broadcast_override_status() - return TRUE + return TOPIC_REFRESH - if (!docking_enabled|| override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled + if (!docking_enabled || override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled return ..(command) + return TOPIC_NOACTION /datum/computer/file/embedded_program/airlock/multi_docking/get_receive_filters() return ..() + master_tag // master_tag is specifically to get "dock_status" diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index 0b7120b81a7d..6e25b53fb5c3 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -1,13 +1,14 @@ /obj/machinery/embedded_controller name = "Embedded Controller" - anchored = 1 + anchored = TRUE idle_power_usage = 10 layer = ABOVE_WINDOW_LAYER + clicksound = "button" var/datum/computer/file/embedded_program/program //the currently executing program var/on = 1 -/obj/machinery/embedded_controller/Initialize() - if(program) +/obj/machinery/embedded_controller/Initialize(mapload, d, populate_parts) + if(ispath(program)) program = new program(src) return ..() @@ -24,77 +25,105 @@ if(program) program.receive_signal(signal, receive_method, receive_param) + update_icon() //spawn(5) program.process() //no, program.process sends some signals and machines respond and we here again and we lag -rastaf0 -/obj/machinery/embedded_controller/Topic(href, href_list) - if(..()) +/obj/machinery/embedded_controller/OnTopic(mob/user, href_list) + if((. = ..())) return - if(usr) - usr.set_machine(src) + if(user) + user.set_machine(src) if(program) return program.receive_user_command(href_list["command"]) // Any further sanitization should be done in here. + return TOPIC_NOACTION /obj/machinery/embedded_controller/Process() if(program) program.process() - update_icon() - /obj/machinery/embedded_controller/interface_interact(mob/user) ui_interact(user) return TRUE /obj/machinery/embedded_controller/radio - icon = 'icons/obj/airlock_machines.dmi' - icon_state = "airlock_control_off" - power_channel = ENVIRON - density = 0 - unacidable = 1 - var/frequency = EXTERNAL_AIR_FREQ + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "airlock_control_off" + power_channel = ENVIRON + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + construct_state = /decl/machine_construction/wall_frame/panel_closed + frame_type = /obj/item/frame/button/airlock_controller + base_type = /obj/machinery/embedded_controller/radio/simple_docking_controller + directional_offset = @'{"NORTH":{"y":-22}, "SOUTH":{"y":24}, "EAST":{"x":-22}, "WEST":{"x":22}}' + required_interaction_dexterity = DEXTERITY_TOUCHSCREENS + var/frequency = EXTERNAL_AIR_FREQ + ///Icon state of the screen used by dummy controllers to match the same state + var/tmp/screen_state = "screen_standby" + ///Bitflag to indicate which indicator lights are on so dummy controllers can match the same state + var/tmp/indicator_state = 0 + ///Radio connection to use for emiting commands var/datum/radio_frequency/radio_connection - uncreated_component_parts = null - construct_state = /decl/machine_construction/wall_frame/panel_closed - frame_type = /obj/item/frame/button/airlock_controller - base_type = /obj/machinery/embedded_controller/radio/simple_docking_controller - stat_immune = 0 + //Indicator flags + ///Used to tell the "indicator_done" light should be lit up on the controller + var/static/const/INDICATOR_FLAG_DONE = BITFLAG(1) + ///Used to tell the "indicator_active" light should be lit up on the controller + var/static/const/INDICATOR_FLAG_ACTIVE = BITFLAG(2) + ///Used to tell the "indicator_forced" light should be lit up on the controller + var/static/const/INDICATOR_FLAG_FORCED = BITFLAG(3) -/obj/machinery/embedded_controller/radio/Initialize() +/obj/machinery/embedded_controller/radio/Initialize(mapload, d, populate_parts) . = ..() set_frequency(frequency) set_extension(src, /datum/extension/interactive/multitool/embedded_controller) + update_icon() -obj/machinery/embedded_controller/radio/Destroy() +/obj/machinery/embedded_controller/radio/Destroy() if(radio_controller) radio_controller.remove_object(src,frequency) - ..() + return ..() /obj/machinery/embedded_controller/radio/on_update_icon() - overlays.Cut() - if(!on || !istype(program)) + cut_overlays() + screen_state = null + indicator_state = 0 + if(!on || !istype(program) || inoperable()) + set_light(0) return if(!program.memory["processing"]) - overlays += image(icon, "screen_standby") - overlays += image(icon, "indicator_done") + screen_state = "screen_standby" + indicator_state |= INDICATOR_FLAG_DONE + set_light(l_range = 2, l_power = 0.5, l_color = "#3eac5c") else - overlays += image(icon, "indicator_active") + indicator_state |= INDICATOR_FLAG_ACTIVE + var/datum/computer/file/embedded_program/docking/airlock/docking_program = program - var/datum/computer/file/embedded_program/airlock/docking/airlock_program = program + var/datum/computer/file/embedded_program/airlock/airlock_program = program if(istype(docking_program)) if(docking_program.override_enabled) - overlays += image(icon, "indicator_forced") + indicator_state |= INDICATOR_FLAG_FORCED airlock_program = docking_program.airlock_program - + if(istype(airlock_program) && airlock_program.memory["processing"]) if(airlock_program.memory["pump_status"] == "siphon") - overlays += image(icon, "screen_drain") + screen_state = "screen_drain" + set_light(l_range = 2, l_power = 0.5, l_color = "#bf3133") else - overlays += image(icon, "screen_fill") + screen_state = "screen_fill" + set_light(l_range = 2, l_power = 0.5, l_color = "#4073e7") + + if(screen_state) + add_overlay(screen_state) + if(indicator_state & INDICATOR_FLAG_DONE) + add_overlay("indicator_done") + if(indicator_state & INDICATOR_FLAG_ACTIVE) + add_overlay("indicator_active") + if(indicator_state & INDICATOR_FLAG_FORCED) + add_overlay("indicator_forced") #define AIRLOCK_CONTROL_RANGE 22 /obj/machinery/embedded_controller/radio/post_signal(datum/signal/signal, var/radio_filter = null) - signal.transmission_method = TRANSMISSION_RADIO if(radio_connection) return radio_connection.post_signal(src, signal, radio_filter, AIRLOCK_CONTROL_RANGE) else @@ -108,20 +137,22 @@ obj/machinery/embedded_controller/radio/Destroy() var/list/filters = program?.get_receive_filters() for(var/filter in filters) radio_connection = radio_controller.add_object(src, frequency, filter) + update_icon() // resets all id_tags (including in programs) based on the given tag. /obj/machinery/embedded_controller/radio/proc/reset_id_tags(base_tag) id_tag = base_tag if(program) program.reset_id_tags(base_tag) + update_icon() /datum/extension/interactive/multitool/embedded_controller/get_interact_window(var/obj/item/multitool/M, var/mob/user) var/obj/machinery/embedded_controller/radio/controller = holder if(!istype(holder)) return . = list() - . += "ID tag: [controller.id_tag]
    " - . += "Frequency: [controller.frequency]
    " + . += "ID tag: [controller.id_tag]
    " + . += "Frequency: [controller.frequency]
    " . += "Likely tags used by controller:
    " var/list/tags = controller.program?.get_receive_filters(TRUE) if(!length(tags)) @@ -141,17 +172,59 @@ obj/machinery/embedded_controller/radio/Destroy() if(href_list["set_tag"]) var/new_tag = input(user, "Enter a new tag to use. Warning: this will reset all tags used by this machine, not just the main one!", "Tag Selection", controller.id_tag) as text|null if(extension_status(user) != STATUS_INTERACTIVE) - return MT_NOACTION - sanitize(new_tag) + return TOPIC_NOACTION + new_tag = sanitize_name(new_tag, MAX_MESSAGE_LEN, TRUE, FALSE) if(new_tag) controller.reset_id_tags(new_tag) controller.set_frequency(controller.frequency) - return MT_REFRESH + return TOPIC_REFRESH if(href_list["set_freq"]) var/new_frequency = input(user, "Enter a new frequency to use.", "frequency Selection", controller.frequency) as num|null if(!new_frequency || (extension_status(user) != STATUS_INTERACTIVE)) - return MT_NOACTION + return TOPIC_NOACTION new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) controller.set_frequency(new_frequency) - return MT_REFRESH \ No newline at end of file + return TOPIC_REFRESH + +/decl/stock_part_preset/radio/receiver/vent_pump/airlock + frequency = EXTERNAL_AIR_FREQ + filter = null + +/decl/stock_part_preset/radio/event_transmitter/vent_pump/airlock + frequency = EXTERNAL_AIR_FREQ + filter = null + +/obj/machinery/atmospherics/unary/vent_pump/airlock + controlled = FALSE + external_pressure_bound = MAX_PUMP_PRESSURE + external_pressure_bound_default = MAX_PUMP_PRESSURE + internal_pressure_bound = MAX_PUMP_PRESSURE + internal_pressure_bound_default = MAX_PUMP_PRESSURE + stock_part_presets = list( + /decl/stock_part_preset/radio/receiver/vent_pump/airlock = 1, + /decl/stock_part_preset/radio/event_transmitter/vent_pump/airlock = 1 + ) + +/obj/machinery/atmospherics/unary/vent_pump/cabled/airlock + controlled = FALSE + external_pressure_bound = MAX_PUMP_PRESSURE + external_pressure_bound_default = MAX_PUMP_PRESSURE + internal_pressure_bound = MAX_PUMP_PRESSURE + internal_pressure_bound_default = MAX_PUMP_PRESSURE + stock_part_presets = list( + /decl/stock_part_preset/radio/receiver/vent_pump/airlock = 1, + /decl/stock_part_preset/radio/event_transmitter/vent_pump/airlock = 1, + /decl/stock_part_preset/terminal_connect/offset_dir = 1, + ) + +/obj/machinery/atmospherics/unary/vent_pump/high_volume/airlock + controlled = FALSE + external_pressure_bound = MAX_PUMP_PRESSURE + external_pressure_bound_default = MAX_PUMP_PRESSURE + internal_pressure_bound = MAX_PUMP_PRESSURE + internal_pressure_bound_default = MAX_PUMP_PRESSURE + stock_part_presets = list( + /decl/stock_part_preset/radio/receiver/vent_pump/airlock = 1, + /decl/stock_part_preset/radio/event_transmitter/vent_pump/airlock = 1 + ) diff --git a/code/game/machinery/embedded_controller/embedded_program_base.dm b/code/game/machinery/embedded_controller/embedded_program_base.dm index e6bcb5b68c33..31e409c555f9 100644 --- a/code/game/machinery/embedded_controller/embedded_program_base.dm +++ b/code/game/machinery/embedded_controller/embedded_program_base.dm @@ -16,7 +16,7 @@ return ..() /datum/computer/file/embedded_program/proc/receive_user_command(command) - return FALSE + return TOPIC_NOACTION // Returns all filters on which you want to receive signals /datum/computer/file/embedded_program/proc/get_receive_filters(var/for_ui = FALSE) diff --git a/code/game/machinery/embedded_controller/simple_docking_controller.dm b/code/game/machinery/embedded_controller/simple_docking_controller.dm index e9ba4622c70e..52dae59a4531 100644 --- a/code/game/machinery/embedded_controller/simple_docking_controller.dm +++ b/code/game/machinery/embedded_controller/simple_docking_controller.dm @@ -4,7 +4,11 @@ program = /datum/computer/file/embedded_program/docking/simple var/tag_door -/obj/machinery/embedded_controller/radio/simple_docking_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/simple_docking_controller/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(tag_door, map_hash) + +/obj/machinery/embedded_controller/radio/simple_docking_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/data[0] var/datum/computer/file/embedded_program/docking/simple/docking_program = program @@ -51,13 +55,15 @@ if(!receive_tag) return if(receive_tag==tag_door) - memory["door_status"]["state"] = signal.data["door_status"] - memory["door_status"]["lock"] = signal.data["lock_status"] + if("door_status" in signal.data) + memory["door_status"]["state"] = signal.data["door_status"] + if("lock_status" in signal.data) + memory["door_status"]["lock"] = signal.data["lock_status"] ..(signal, receive_method, receive_param) /datum/computer/file/embedded_program/docking/simple/receive_user_command(command) - . = TRUE + . = TOPIC_REFRESH switch(command) if("force_door") if (override_enabled) @@ -68,7 +74,7 @@ else enable_override() else - . = FALSE + . = TOPIC_NOACTION //tell the docking port to start getting ready for docking - e.g. pressurize /datum/computer/file/embedded_program/docking/simple/prepare_for_docking() diff --git a/code/game/machinery/embedded_controller/tin_can.dm b/code/game/machinery/embedded_controller/tin_can.dm index b0b3124290b9..1dcf86bdcfe4 100644 --- a/code/game/machinery/embedded_controller/tin_can.dm +++ b/code/game/machinery/embedded_controller/tin_can.dm @@ -17,7 +17,7 @@ cycle_to_external_air = TRUE // Some kind of legacy var needed for proper init base_type = /obj/machinery/embedded_controller/radio/airlock/tin_can -/obj/machinery/embedded_controller/radio/airlock/tin_can/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/nanoui/master_ui = null, datum/topic_state/state = GLOB.default_state) +/obj/machinery/embedded_controller/radio/airlock/tin_can/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/nanoui/master_ui = null, datum/topic_state/state = global.default_topic_state) var/list/data = list() var/datum/computer/file/embedded_program/airlock/tin_can/our_program = program data = list( @@ -44,34 +44,34 @@ ..() /datum/computer/file/embedded_program/airlock/tin_can/receive_user_command(command) - . = TRUE + . = TOPIC_REFRESH switch(command) if("toggle_door_safety") door_safety = !door_safety toggleDoor(memory["exterior_status"], tag_exterior_door, door_safety) if("evacuate_atmos") if(state == STATE_EVACUATE) - return + return TOPIC_HANDLED state = STATE_EVACUATE toggleDoor(memory["exterior_status"], tag_exterior_door, door_safety, "close") - signalPump(tag_pump_out_internal, 0) - signalPump(tag_pump_out_external, 1) + signalPump(tag_pump_out_internal, 1, 0, 0) // Interior pump, target is a vacuum + signalPump(tag_pump_out_external, 1, 1, 10000) // Exterior pump, target is infinite if("fill_atmos") if(state == STATE_FILL) - return + return TOPIC_HANDLED state = STATE_FILL toggleDoor(memory["exterior_status"], tag_exterior_door, door_safety, "close") - signalPump(tag_pump_out_internal, 1) - signalPump(tag_pump_out_external, 0) + signalPump(tag_pump_out_internal, 1, 1, memory["external_sensor_pressure"]) // Interior pump, target is exterior pressure + signalPump(tag_pump_out_external, 1, 0, 0) // Exterior pump, target is zero, to intake if("seal") if(state == STATE_SEALED) - return + return TOPIC_HANDLED state = STATE_SEALED toggleDoor(memory["exterior_status"], tag_exterior_door, door_safety, "close") signalPump(tag_pump_out_internal, 0) signalPump(tag_pump_out_external, 0) else - . = FALSE + . = TOPIC_NOACTION /datum/computer/file/embedded_program/airlock/tin_can/process() if(door_safety) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 345b56106a40..edd7f125381e 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -5,12 +5,14 @@ desc = "A wall-mounted flashbulb device." icon = 'icons/obj/machines/flash_mounted.dmi' icon_state = "mflash1" + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED var/range = 2 //this is roughly the size of brig cell var/disable = 0 var/last_flash = 0 //Don't want it getting spammed like regular flashes var/strength = 10 //How weakened targets are when flashed. var/base_state = "mflash" - anchored = 1 + anchored = TRUE idle_power_usage = 2 movable_flags = MOVABLE_FLAG_PROXMOVE @@ -33,16 +35,17 @@ // src.sd_SetLuminosity(0) //Don't want to render prison breaks impossible -/obj/machinery/flasher/attackby(obj/item/W, mob/user) - if(isWirecutter(W)) - add_fingerprint(user, 0, W) +/obj/machinery/flasher/attackby(obj/item/used_item, mob/user) + if(IS_WIRECUTTER(used_item)) + add_fingerprint(user, 0, used_item) src.disable = !src.disable if (src.disable) - user.visible_message("[user] has disconnected the [src]'s flashbulb!", "You disconnect the [src]'s flashbulb!") + user.visible_message("[user] has disconnected \the [src]'s flashbulb!", "You disconnect \the [src]'s flashbulb!") if (!src.disable) - user.visible_message("[user] has connected the [src]'s flashbulb!", "You connect the [src]'s flashbulb!") + user.visible_message("[user] has connected \the [src]'s flashbulb!", "You connect \the [src]'s flashbulb!") + return TRUE else - ..() + return ..() //Let the AI trigger them directly. /obj/machinery/flasher/attack_ai() @@ -52,7 +55,7 @@ return /obj/machinery/flasher/proc/flash() - if (!(powered())) + if (stat & NOPOWER) return if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) @@ -63,35 +66,12 @@ src.last_flash = world.time use_power_oneoff(1500) - for (var/mob/living/O in viewers(src, null)) - if (get_dist(src, O) > src.range) + for (var/mob/living/viewer in viewers(src, null)) + if (get_dist(src, viewer) > src.range) continue var/flash_time = strength - if(isliving(O)) - if(O.eyecheck() > FLASH_PROTECTION_NONE) - continue - if(ishuman(O)) - var/mob/living/carbon/human/H = O - flash_time = round(H.getFlashMod() * flash_time) - if(flash_time <= 0) - return - var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[H.species.vision_organ] - if(!E) - return - if(E.is_bruised() && prob(E.damage + 50)) - H.flash_eyes() - E.damage += rand(1, 5) - - if(!O.blinded) - do_flash(O, flash_time) - -/obj/machinery/flasher/proc/do_flash(var/mob/living/victim, var/flash_time) - victim.flash_eyes() - victim.eye_blurry += flash_time - victim.confused += (flash_time + 2) - victim.Stun(flash_time / 2) - victim.Weaken(3) + viewer.handle_flashed(flash_time) /obj/machinery/flasher/emp_act(severity) if(stat & (BROKEN|NOPOWER)) @@ -106,25 +86,23 @@ desc = "A portable flashing device. Wrench to activate and deactivate. Cannot detect slow movements." icon_state = "pflash1" icon = 'icons/obj/machines/flash_portable.dmi' + directional_offset = @'{"NORTH":{"y":0}, "SOUTH":{"y":0}, "EAST":{"x":0}, "WEST":{"x":0}}' strength = 8 - anchored = 0 + anchored = FALSE base_state = "pflash" - density = 1 + density = TRUE /obj/machinery/flasher/portable/HasProximity(atom/movable/AM) - if(!anchored || disable || last_flash && world.time < last_flash + 150) + . = ..() + if(!. || !anchored || disable || last_flash && world.time < last_flash + 150) return - - if(istype(AM, /mob/living/carbon)) - var/mob/living/carbon/M = AM + if(isliving(AM)) + var/mob/living/M = AM if(!MOVING_DELIBERATELY(M)) flash() - if(isanimal(AM)) - flash() - -/obj/machinery/flasher/portable/attackby(obj/item/W, mob/user) - if(isWrench(W)) +/obj/machinery/flasher/portable/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) add_fingerprint(user) src.anchored = !src.anchored @@ -135,6 +113,8 @@ else if (src.anchored) user.show_message(text("[src] is now secured.")) src.overlays += "[base_state]-s" + return TRUE + return ..() /obj/machinery/button/flasher name = "flasher button" @@ -144,7 +124,7 @@ /decl/public_access/public_method/flasher_flash name = "flash" desc = "Performs a flash, if possible." - call_proc = /obj/machinery/flasher/proc/flash + call_proc = TYPE_PROC_REF(/obj/machinery/flasher, flash) /decl/stock_part_preset/radio/receiver/flasher frequency = BUTTON_FREQ diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm index c01421280e35..ee1f89484090 100644 --- a/code/game/machinery/floodlight.dm +++ b/code/game/machinery/floodlight.dm @@ -1,22 +1,20 @@ -//these are probably broken - /obj/machinery/floodlight - name = "Emergency Floodlight" + name = "emergency floodlight" icon = 'icons/obj/machines/floodlight.dmi' icon_state = "flood00" - density = 1 + density = TRUE obj_flags = OBJ_FLAG_ROTATABLE construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES active_power_usage = 200 power_channel = LIGHT use_power = POWER_USE_OFF //better laser, increased brightness & power consumption - var/l_max_bright = 0.8 //brightness of light when on, can be negative - var/l_inner_range = 0 //inner range of light when on, can be negative - var/l_outer_range = 4.5 //outer range of light when on, can be negative + var/l_power = 4 //brightness of light when on, can be negative + var/l_range = 12 //outer range of light when on, can be negative /obj/machinery/floodlight/on_update_icon() icon_state = "flood[panel_open ? "o" : ""][panel_open && get_cell() ? "b" : ""]0[use_power == POWER_USE_ACTIVE]" @@ -31,29 +29,27 @@ // If the cell is almost empty rarely "flicker" the light. Aesthetic only. if(prob(30)) - set_light(l_max_bright / 2, l_inner_range, l_outer_range) + set_light(l_range, l_power / 2) spawn(20) if(use_power) - set_light(l_max_bright, l_inner_range, l_outer_range) + set_light(l_range, l_power) // Returns 0 on failure and 1 on success /obj/machinery/floodlight/proc/turn_on(var/loud = 0) if(stat & NOPOWER) return 0 - set_light(l_max_bright, l_inner_range, l_outer_range) + set_light(l_range, l_power) update_use_power(POWER_USE_ACTIVE) use_power_oneoff(active_power_usage)//so we drain cell if they keep trying to use it - update_icon() if(loud) visible_message("\The [src] turns on.") playsound(src.loc, 'sound/effects/flashlight.ogg', 50, 0) return 1 /obj/machinery/floodlight/proc/turn_off(var/loud = 0) - set_light(0, 0) + set_light(0) update_use_power(POWER_USE_OFF) - update_icon() if(loud) visible_message("\The [src] shuts down.") playsound(src.loc, 'sound/effects/flashlight.ogg', 50, 0) @@ -73,10 +69,9 @@ /obj/machinery/floodlight/RefreshParts()//if they're insane enough to modify a floodlight, let them ..() - var/light_mod = Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) - l_max_bright = light_mod? light_mod*0.01 + initial(l_max_bright) : initial(l_max_bright)/2 //gives us between 0.8-0.9 with capacitor, or 0.4 without one - l_inner_range = light_mod + initial(l_inner_range) - l_outer_range = light_mod*1.5 + initial(l_outer_range) + var/light_mod = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) + l_power = light_mod? light_mod*0.01 + initial(l_power) : initial(l_power)/2 //gives us between 0.8-0.9 with capacitor, or 0.4 without one + l_range = light_mod*1.5 + initial(l_range) change_power_consumption(initial(active_power_usage) * light_mod , POWER_USE_ACTIVE) if(use_power) - set_light(l_max_bright, l_inner_range, l_outer_range) \ No newline at end of file + set_light(l_range, l_power) \ No newline at end of file diff --git a/code/game/machinery/floor_light.dm b/code/game/machinery/floor_light.dm index 2f711593eb97..c9c4e8571b5f 100644 --- a/code/game/machinery/floor_light.dm +++ b/code/game/machinery/floor_light.dm @@ -1,4 +1,4 @@ -var/list/floor_light_cache = list() +var/global/list/floor_light_cache = list() /obj/machinery/floor_light name = "floor light" @@ -6,7 +6,7 @@ var/list/floor_light_cache = list() icon_state = "base" desc = "A backlit floor panel." layer = ABOVE_TILE_LAYER - anchored = 0 + anchored = FALSE use_power = POWER_USE_ACTIVE idle_power_usage = 2 active_power_usage = 20 @@ -15,69 +15,78 @@ var/list/floor_light_cache = list() /decl/material/solid/metal/steel = MATTER_AMOUNT_PRIMARY, /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT ) + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES var/damaged - var/default_light_max_bright = 0.75 - var/default_light_inner_range = 1 - var/default_light_outer_range = 3 - var/default_light_colour = "#ffffff" + var/default_light_power = 0.75 + var/default_light_range = 3 + var/default_light_color = "#ffffff" /obj/machinery/floor_light/prebuilt - anchored = 1 + anchored = TRUE -/obj/machinery/floor_light/attackby(var/obj/item/W, var/mob/user) - if(isScrewdriver(W)) +/obj/machinery/floor_light/Initialize() + . = ..() + update_icon() + +/obj/machinery/floor_light/attackby(var/obj/item/used_item, var/mob/user) + + if(IS_SCREWDRIVER(used_item)) anchored = !anchored if(use_power) update_use_power(POWER_USE_OFF) - queue_icon_update() - visible_message("\The [user] has [anchored ? "attached" : "detached"] \the [src].") - else if(isWelder(W) && (damaged || (stat & BROKEN))) - var/obj/item/weldingtool/WT = W - if(!WT.remove_fuel(0, user)) - to_chat(user, "\The [src] must be on to complete this task.") - return + visible_message(SPAN_NOTICE("\The [user] has [anchored ? "attached" : "detached"] \the [src].")) + return TRUE + + if(IS_WELDER(used_item) && (damaged || (stat & BROKEN))) + var/obj/item/weldingtool/welder = used_item + if(!welder.weld(0, user)) + to_chat(user, SPAN_WARNING("\The [src] must be on to complete this task.")) + return TRUE playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - if(!do_after(user, 20, src)) - return - if(!src || !WT.isOn()) - return - visible_message("\The [user] has repaired \the [src].") - set_broken(FALSE) - damaged = null - else if(isWrench(W)) + if(do_after(user, 20, src) && !QDELETED(src) && welder.isOn()) + visible_message(SPAN_NOTICE("\The [user] has repaired \the [src].")) + set_broken(FALSE) + damaged = null + return TRUE + + if(IS_WRENCH(used_item)) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - to_chat(user, "You dismantle the floor light.") - new /obj/item/stack/material/steel(src.loc, 1) - new /obj/item/stack/material/glass(src.loc, 1) + to_chat(user, SPAN_NOTICE("You dismantle the floor light.")) + SSmaterials.create_object(/decl/material/solid/metal/steel, loc, 1) + SSmaterials.create_object(/decl/material/solid/glass, loc, 1) qdel(src) - else if(W.force && user.a_intent == "hurt") - attack_hand(user) - return + return TRUE + + if(used_item.get_attack_force(user) && user.check_intent(I_FLAG_HARM)) + return physical_attack_hand(user) + + return ..() /obj/machinery/floor_light/physical_attack_hand(var/mob/user) - if(user.a_intent == I_HURT && !issmall(user)) + if(user.check_intent(I_FLAG_HARM) && !issmall(user)) if(!isnull(damaged) && !(stat & BROKEN)) - visible_message("\The [user] smashes \the [src]!") + visible_message(SPAN_DANGER("\The [user] smashes \the [src]!")) playsound(src, "shatter", 70, 1) set_broken(TRUE) else - visible_message("\The [user] attacks \the [src]!") + visible_message(SPAN_DANGER("\The [user] attacks \the [src]!")) playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - if(isnull(damaged)) damaged = 0 + if(isnull(damaged)) + damaged = 0 return TRUE + return FALSE /obj/machinery/floor_light/interface_interact(var/mob/user) if(!CanInteract(user, DefaultTopicState())) return FALSE if(!anchored) - to_chat(user, "\The [src] must be screwed down first.") + to_chat(user, SPAN_WARNING("\The [src] must be screwed down first.")) return TRUE var/on = (use_power == POWER_USE_ACTIVE) update_use_power(on ? POWER_USE_OFF : POWER_USE_ACTIVE) - visible_message("\The [user] turns \the [src] [!on ? "on" : "off"].") - queue_icon_update() + visible_message(SPAN_NOTICE("\The [user] turns \the [src] [!on ? "on" : "off"].")) return TRUE /obj/machinery/floor_light/set_broken(new_state) @@ -92,44 +101,44 @@ var/list/floor_light_cache = list() /obj/machinery/floor_light/proc/update_brightness() if((use_power == POWER_USE_ACTIVE) && !(stat & (NOPOWER | BROKEN))) - if(light_outer_range != default_light_outer_range || light_max_bright != default_light_max_bright || light_color != default_light_colour) - set_light(default_light_max_bright, default_light_inner_range, default_light_outer_range, l_color = default_light_colour) - change_power_consumption((light_outer_range + light_max_bright) * 20, POWER_USE_ACTIVE) + if(light_range != default_light_range || light_power != default_light_power || light_color != default_light_color) + set_light(default_light_range, default_light_power, default_light_color) + change_power_consumption((light_range + light_power) * 20, POWER_USE_ACTIVE) else - if(light_outer_range || light_max_bright) + if(light_range || light_power) set_light(0) /obj/machinery/floor_light/on_update_icon() - overlays.Cut() + cut_overlays() if((use_power == POWER_USE_ACTIVE) && !(stat & (NOPOWER | BROKEN))) if(isnull(damaged)) - var/cache_key = "floorlight-[default_light_colour]" + var/cache_key = "floorlight-[default_light_color]" if(!floor_light_cache[cache_key]) var/image/I = image("on") - I.color = default_light_colour + I.color = default_light_color I.plane = plane I.layer = layer+0.001 floor_light_cache[cache_key] = I - overlays |= floor_light_cache[cache_key] + add_overlay(floor_light_cache[cache_key]) else if(damaged == 0) //Needs init. damaged = rand(1,4) - var/cache_key = "floorlight-broken[damaged]-[default_light_colour]" + var/cache_key = "floorlight-broken[damaged]-[default_light_color]" if(!floor_light_cache[cache_key]) var/image/I = image("flicker[damaged]") - I.color = default_light_colour + I.color = default_light_color I.plane = plane I.layer = layer+0.001 floor_light_cache[cache_key] = I - overlays |= floor_light_cache[cache_key] + add_overlay(floor_light_cache[cache_key]) update_brightness() /obj/machinery/floor_light/explosion_act(severity) . = ..() if(. && !QDELETED(src)) if(severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5))) - physically_destroyed(src) - else + physically_destroyed() + else if(severity == 2 && prob(20)) set_broken(TRUE) if(isnull(damaged)) diff --git a/code/game/machinery/floorlayer.dm b/code/game/machinery/floorlayer.dm index 0b883314f060..92b6260ce5b6 100644 --- a/code/game/machinery/floorlayer.dm +++ b/code/game/machinery/floorlayer.dm @@ -3,25 +3,26 @@ name = "automatic floor layer" icon = 'icons/obj/machines/pipe_dispenser.dmi' icon_state = "pipe_d" - density = 1 + density = TRUE + interact_offline = TRUE var/turf/old_turf var/on = 0 var/obj/item/stack/tile/T var/list/mode = list("dismantle"=0,"laying"=0,"collect"=0) /obj/machinery/floorlayer/Initialize() - . = ..() - T = new/obj/item/stack/tile/floor(src) + . = ..() + T = new /obj/item/stack/tile/floor(src) /obj/machinery/floorlayer/Move(new_turf,M_Dir) - ..() + . = ..() if(on) if(mode["dismantle"]) - dismantleFloor(old_turf) + dismantle_floor(old_turf) if(mode["laying"]) - layFloor(old_turf) + lay_floor(old_turf) if(mode["collect"]) CollectTiles(old_turf) @@ -34,54 +35,53 @@ user.visible_message("[user] has [!on?"de":""]activated \the [src].", "You [!on?"de":""]activate \the [src].") return TRUE -/obj/machinery/floorlayer/attackby(var/obj/item/W, var/mob/user) +/obj/machinery/floorlayer/attackby(var/obj/item/used_item, var/mob/user) - if(isWrench(W)) + if(IS_WRENCH(used_item)) var/m = input("Choose work mode", "Mode") as null|anything in mode mode[m] = !mode[m] var/O = mode[m] - user.visible_message("[usr] has set \the [src] [m] mode [!O?"off":"on"].", "You set \the [src] [m] mode [!O?"off":"on"].") - return + user.visible_message("[user] has set \the [src] [m] mode [!O?"off":"on"].", "You set \the [src] [m] mode [!O?"off":"on"].") + return TRUE - if(istype(W, /obj/item/stack/tile)) - if(!user.unEquip(W, T)) - return - to_chat(user, "\The [W] successfully loaded.") + if(istype(used_item, /obj/item/stack/tile)) + if(!user.try_unequip(used_item, T)) + return TRUE + to_chat(user, "\The [used_item] successfully loaded.") TakeTile(T) - return + return TRUE - if(isCrowbar(W)) + if(IS_CROWBAR(used_item)) if(!length(contents)) to_chat(user, "\The [src] is empty.") else var/obj/item/stack/tile/E = input("Choose remove tile type.", "Tiles") as null|anything in contents if(E) - to_chat(user, "You remove the [E] from /the [src].") + to_chat(user, "You remove \the [E] from \the [src].") E.dropInto(loc) T = null - return + return TRUE - if(isScrewdriver(W)) + if(IS_SCREWDRIVER(used_item)) T = input("Choose tile type.", "Tiles") as null|anything in contents - return - ..() + return TRUE + return ..() -/obj/machinery/floorlayer/examine(mob/user) +/obj/machinery/floorlayer/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/dismantle = mode["dismantle"] - var/laying = mode["laying"] - var/collect = mode["collect"] - var/message = "\The [src] [!T?"don't ":""]has [!T?"":"[T.get_amount()] [T] "]tile\s, dismantle is [dismantle?"on":"off"], laying is [laying?"on":"off"], collect is [collect?"on":"off"]." - to_chat(user, message) + var/laying = mode["laying"] + var/collect = mode["collect"] + . += SPAN_NOTICE("\The [src] [!T?"don't ":""]has [!T?"":"[T.get_amount()] [T] "]tile\s, dismantle is [dismantle?"on":"off"], laying is [laying?"on":"off"], collect is [collect?"on":"off"].") /obj/machinery/floorlayer/proc/reset() on = 0 -/obj/machinery/floorlayer/proc/dismantleFloor(var/turf/new_turf) - if(istype(new_turf, /turf/simulated/floor)) - var/turf/simulated/floor/T = new_turf +/obj/machinery/floorlayer/proc/dismantle_floor(var/turf/new_turf) + if(istype(new_turf, /turf/floor)) + var/turf/floor/T = new_turf if(!T.is_plating()) - T.make_plating(!(T.broken || T.burnt)) + T.clear_flooring(place_product = !T.is_floor_damaged()) return new_turf.is_plating() /obj/machinery/floorlayer/proc/TakeNewStack() @@ -95,7 +95,7 @@ for(var/obj/item/stack/tile/tile2 in contents) tile2.transfer_to(tile1) -/obj/machinery/floorlayer/proc/layFloor(var/turf/w_turf) +/obj/machinery/floorlayer/proc/lay_floor(var/turf/w_turf) if(!T) if(!TakeNewStack()) return 0 diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index b593b830ec9e..677184076293 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -29,18 +29,18 @@ Possible to do for anyone motivated enough: #define RANGE_BASED 4 #define AREA_BASED 6 -var/const/HOLOPAD_MODE = RANGE_BASED +var/global/const/HOLOPAD_MODE = RANGE_BASED +var/global/list/holopads = list() /obj/machinery/hologram/holopad name = "\improper holopad" desc = "It's a floor-mounted device for projecting holographic images." icon = 'icons/obj/machines/holopad.dmi' icon_state = "holopad-B0" - layer = ABOVE_TILE_LAYER + idle_power_usage = 5 var/power_per_hologram = 500 //per usage per hologram - idle_power_usage = 5 var/list/mob/living/silicon/ai/masters = new() //List of AIs that use the holopad var/last_request = 0 //to prevent request spam. ~Carn @@ -56,12 +56,43 @@ var/const/HOLOPAD_MODE = RANGE_BASED var/base_icon = "holopad-B" var/allow_ai = TRUE + var/static/list/reachable_overmaps = list(OVERMAP_ID_SPACE) + + var/static/list/used_holopad_ids = list() + var/holopad_id /obj/machinery/hologram/holopad/Initialize() . = ..() - desc = "It's a floor-mounted device for projecting holographic images. Its ID is '[loc.loc]'" -/obj/machinery/hologram/holopad/interface_interact(var/mob/living/carbon/human/user) //Carn: Hologram requests. + global.holopads += src + global.listening_objects += src + // Null ID means we want to use our area name. + if(isnull(holopad_id)) + var/area/A = get_area(src) + var/holopad_index = 1 + var/holopad_base = A?.proper_name || "Unknown" + holopad_id = "[holopad_base] #[holopad_index]" + while(holopad_id in used_holopad_ids) + holopad_index++ + holopad_id = "[holopad_base] #[holopad_index]" + used_holopad_ids |= holopad_id + + // For overmap sites, always tag the sector name so we have a unique discriminator for long range calls. + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[z] + if(sector) + holopad_id = "[sector.name] - [holopad_id]" + + // Update our desc. + desc = "It's a floor-mounted device for projecting holographic images. Its ID is '[holopad_id]'" + +/obj/machinery/hologram/holopad/Destroy() + global.listening_objects -= src + global.holopads -= src + for (var/mob/living/master in masters) + clear_holo(master) + return ..() + +/obj/machinery/hologram/holopad/interface_interact(var/mob/living/human/user) //Carn: Hologram requests. if(!CanInteract(user, DefaultTopicState())) return FALSE if(incoming_connection && caller_id) @@ -90,42 +121,47 @@ var/const/HOLOPAD_MODE = RANGE_BASED if(last_request + 200 < world.time) //don't spam the AI with requests you jerk! last_request = world.time to_chat(user, "You request an AI's presence.") - var/area/area = get_area(src) - for(var/mob/living/silicon/ai/AI in GLOB.living_mob_list_) + for(var/mob/living/silicon/ai/AI in global.living_mob_list_) if(!AI.client) continue - if (holopadType != HOLOPAD_LONG_RANGE && !AreConnectedZLevels(AI.z, src.z)) + if (holopadType != HOLOPAD_LONG_RANGE && !SSmapping.are_connected_levels(AI.z, src.z)) continue - to_chat(AI, "Your presence is requested at \the [area].") + to_chat(AI, "Your presence is requested at \the [holopad_id].") else to_chat(user, "A request for AI presence was already sent recently.") if("Holocomms") + if(user.loc != src.loc) to_chat(user, "Please step onto the holopad.") return + if(last_request + 200 < world.time) //don't spam other people with requests either, you jerk! + last_request = world.time var/list/holopadlist = list() - var/zlevels = GetConnectedZlevels(z) - var/zlevels_long = list() - if(GLOB.using_map.use_overmap && holopadType == HOLOPAD_LONG_RANGE) - for(var/zlevel in map_sectors) - var/obj/effect/overmap/visitable/O = map_sectors["[zlevel]"] - if(!isnull(O)) + var/zlevels = SSmapping.get_connected_levels(z) + var/list/zlevels_long = list() + + if(holopadType == HOLOPAD_LONG_RANGE && length(reachable_overmaps)) + for(var/zlevel, sector in global.overmap_sectors) + var/obj/effect/overmap/visitable/O = sector + if(!isnull(O) && (O.overmap_id in reachable_overmaps) && LAZYLEN(O.map_z)) zlevels_long |= O.map_z + for(var/obj/machinery/hologram/holopad/H in SSmachines.machinery) if (H.operable()) if(H.z in zlevels) - holopadlist["[H.loc.loc.name]"] = H //Define a list and fill it with the area of every holopad in the world + holopadlist["[H.holopad_id]"] = H //Define a list and fill it with the area of every holopad in the world if (H.holopadType == HOLOPAD_LONG_RANGE && (H.z in zlevels_long)) - holopadlist["[H.loc.loc.name]"] = H - holopadlist = sortAssoc(holopadlist) + holopadlist["[H.holopad_id]"] = H + + holopadlist = sortTim(holopadlist, /proc/cmp_text_asc) var/temppad = input(user, "Which holopad would you like to contact?", "holopad list") as null|anything in holopadlist targetpad = holopadlist["[temppad]"] if(targetpad==src) to_chat(user, "Using such sophisticated technology, just to talk to yourself seems a bit silly.") return if(targetpad && targetpad.caller_id) - to_chat(user, "The pad flashes a busy sign. Maybe you should try again later..") + to_chat(user, "The pad flashes a busy sign. Maybe you should try again later.") return if(targetpad) make_call(targetpad, user) @@ -133,24 +169,24 @@ var/const/HOLOPAD_MODE = RANGE_BASED to_chat(user, "A request for holographic communication was already sent recently.") -/obj/machinery/hologram/holopad/proc/make_call(var/obj/machinery/hologram/holopad/targetpad, var/mob/living/carbon/user) +/obj/machinery/hologram/holopad/proc/make_call(var/obj/machinery/hologram/holopad/targetpad, var/mob/living/user) targetpad.last_request = world.time targetpad.sourcepad = src //This marks the holopad you are making the call from targetpad.caller_id = user //This marks you as the caller targetpad.incoming_connection = 1 playsound(targetpad.loc, 'sound/machines/chime.ogg', 25, 5) targetpad.icon_state = "[targetpad.base_icon]1" - targetpad.audible_message("\The [src] announces, \"Incoming communications request from [targetpad.sourcepad.loc.loc].\"") - to_chat(user, "Trying to establish a connection to the holopad in [targetpad.loc.loc]... Please await confirmation from recipient.") + targetpad.audible_message("\The [src] announces, \"Incoming communications request from [holopad_id].\"") + to_chat(user, "Trying to establish a connection to the holopad in [targetpad.holopad_id]... Please await confirmation from recipient.") -/obj/machinery/hologram/holopad/proc/take_call(mob/living/carbon/user) +/obj/machinery/hologram/holopad/proc/take_call(mob/living/user) incoming_connection = 0 caller_id.machine = sourcepad caller_id.reset_view(src) if(!masters[caller_id])//If there is no hologram, possibly make one. activate_holocall(caller_id) - log_admin("[key_name(caller_id)] just established a holopad connection from [sourcepad.loc.loc] to [src.loc.loc]") + log_admin("[key_name(caller_id)] just established a holopad connection from [sourcepad.holopad_id] to [holopad_id]") /obj/machinery/hologram/holopad/proc/end_call(mob/user) if(!caller_id) @@ -164,7 +200,7 @@ var/const/HOLOPAD_MODE = RANGE_BASED return 0 /obj/machinery/hologram/holopad/attack_ai(mob/living/silicon/ai/user) - if (!istype(user)) + if(!istype(user)) return /*There are pretty much only three ways to interact here. I don't need to check for client since they're clicking on an object. @@ -173,7 +209,7 @@ var/const/HOLOPAD_MODE = RANGE_BASED user.eyeobj.setLoc(get_turf(src)) else if (!allow_ai) to_chat(user, SPAN_WARNING("Access denied.")) - else if (holopadType != HOLOPAD_LONG_RANGE && !AreConnectedZLevels(user.z, src.z)) + else if (holopadType != HOLOPAD_LONG_RANGE && !SSmapping.are_connected_levels(user.z, src.z)) to_chat(user, SPAN_WARNING("Out of range.")) else if(!masters[user])//If there is no hologram, possibly make one. activate_holo(user) @@ -192,7 +228,7 @@ var/const/HOLOPAD_MODE = RANGE_BASED to_chat(user, "ERROR: Unable to project hologram.") return -/obj/machinery/hologram/holopad/proc/activate_holocall(mob/living/carbon/caller_id) +/obj/machinery/hologram/holopad/proc/activate_holocall(mob/living/caller_id) if(caller_id) src.visible_message("A holographic image of [caller_id] flicks to life right before your eyes!") create_holo(0,caller_id)//Create one. @@ -209,23 +245,21 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ var/ai_text = text if(!master.say_understands(M, speaking))//The AI will be able to understand most mobs talking through the holopad. if(speaking) - ai_text = speaking.scramble(text) + ai_text = speaking.scramble(M, text) else ai_text = stars(text) if(isanimal(M) && !M.universal_speak) - var/mob/living/simple_animal/SA = M - ai_text = pick(SA.speak) + ai_text = DEFAULTPICK(M.ai?.emote_speech, "...") var/name_used = M.GetVoice() //This communication is imperfect because the holopad "filters" voices and is only designed to connect to the master only. - var/short_links = master.get_preference_value(/datum/client_preference/ghost_follow_link_length) == GLOB.PREF_SHORT + var/short_links = master.get_preference_value(/datum/client_preference/ghost_follow_link_length) == PREF_SHORT var/follow = short_links ? "\[F]" : "\[Follow]" var/prefix = "[follow]" master.show_message(get_hear_message(name_used, ai_text, verb, speaking, prefix), 2) var/name_used = M.GetVoice() var/message if(isanimal(M) && !M.universal_speak) - var/mob/living/simple_animal/SA = M - message = get_hear_message(name_used, pick(SA.speak), verb, speaking) + message = get_hear_message(name_used, DEFAULTPICK(M.ai?.emote_speech, "..."), verb, speaking) else message = get_hear_message(name_used, text, verb, speaking) if(targetpad && !targetpad.incoming_connection) //If this is the pad you're making the call from and the call is accepted @@ -241,36 +275,21 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ return "Holopad received, [name_used][prefix] [speaking.format_message(text, verb)]" return "Holopad received, [name_used][prefix] [verb], \"[text]\"" -/obj/machinery/hologram/holopad/see_emote(mob/living/M, text) - if(M) - for(var/mob/living/silicon/ai/master in masters) - //var/name_used = M.GetVoice() - var/rendered = "Holopad received, [text]" - //The lack of name_used is needed, because message already contains a name. This is needed for simple mobs to emote properly. - master.show_message(rendered, 2) - for(var/mob/living/carbon/master in masters) - //var/name_used = M.GetVoice() - var/rendered = "Holopad received, [text]" - //The lack of name_used is needed, because message already contains a name. This is needed for simple mobs to emote properly. - master.show_message(rendered, 2) - if(targetpad) - targetpad.visible_message("[text]") - /obj/machinery/hologram/holopad/show_message(msg, type, alt, alt_type) for(var/mob/living/silicon/ai/master in masters) var/rendered = "The holographic image of [msg]" master.show_message(rendered, type) if(findtext(msg, "Holopad received,")) return - for(var/mob/living/carbon/master in masters) + for(var/mob/living/master in masters) var/rendered = "The holographic image of [msg]" master.show_message(rendered, type) if(targetpad) - for(var/mob/living/carbon/master in view(targetpad)) + for(var/mob/living/master in view(targetpad)) var/rendered = "The holographic image of [msg]" master.show_message(rendered, type) -/obj/machinery/hologram/holopad/proc/create_holo(mob/living/silicon/ai/A, mob/living/carbon/caller_id, turf/T = loc) +/obj/machinery/hologram/holopad/proc/create_holo(mob/living/silicon/ai/A, mob/living/caller_id, turf/T = loc) var/obj/effect/overlay/hologram = new(T)//Spawn a blank effect at the location. if(caller_id) hologram.overlays += getHologramIcon(getFlatIcon(caller_id), hologram_color = holopadType) // Add the callers image as an overlay to keep coloration! @@ -282,9 +301,9 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(A) if(A.holo_icon_malf == TRUE) hologram.overlays += icon("icons/effects/effects.dmi", "malf-scanline") - hologram.mouse_opacity = 0//So you can't click on it. + hologram.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE//So you can't click on it. hologram.layer = ABOVE_HUMAN_LAYER //Above all the other objects/mobs. Or the vast majority of them. - hologram.anchored = 1//So space wind cannot drag it. + hologram.anchored = TRUE//So space wind cannot drag it. if(caller_id) hologram.SetName("[caller_id.name] (Hologram)") hologram.forceMove(get_step(src,1)) @@ -293,13 +312,13 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ hologram.SetName("[A.name] (Hologram)") //If someone decides to right click. A.holo = src masters[A] = hologram - hologram.set_light(1, 0.1, 2) //hologram lighting + hologram.set_light(2, 0.1) //hologram lighting hologram.color = color //painted holopad gives coloured holograms - set_light(1, 0.1, 2) //pad lighting + set_light(2, 0.1) //pad lighting icon_state = "[base_icon]1" return 1 -/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user, mob/living/carbon/caller_id) +/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user, mob/living/caller_id) if(user) qdel(masters[user])//Get rid of user's hologram user.holo = null @@ -336,7 +355,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ end_call() if (caller_id&&sourcepad) if(caller_id.loc!=sourcepad.loc) - sourcepad.to_chat(caller_id, "Severing connection to distant holopad.") + to_chat(sourcepad.caller_id, "Severing connection to distant holopad.") end_call() audible_message("The connection has been terminated by the caller.") return 1 @@ -374,43 +393,10 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ */ /obj/machinery/hologram - anchored = 1 + anchored = TRUE idle_power_usage = 5 active_power_usage = 100 -//Destruction procs. -/obj/machinery/hologram/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) - -/obj/machinery/hologram/holopad/Destroy() - for (var/mob/living/master in masters) - clear_holo(master) - return ..() - -/* -Holographic project of everything else. - -/mob/verb/hologram_test() - set name = "Hologram Debug New" - set category = "CURRENT DEBUG" - - var/obj/effect/overlay/hologram = new(loc)//Spawn a blank effect at the location. - var/icon/flat_icon = icon(getFlatIcon(src,0))//Need to make sure it's a new icon so the old one is not reused. - flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish. - flat_icon.ChangeOpacity(0.5)//Make it half transparent. - var/input = input("Select what icon state to use in effect.",,"") - if(input) - var/icon/alpha_mask = new('icons/effects/effects.dmi', "[input]") - flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. - hologram.icon = flat_icon - - log_debug("Your icon should appear now.") - - return -*/ - /* * Other Stuff: Is this even used? */ diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm index d8b13b4d10f3..81ea2fc50ed0 100644 --- a/code/game/machinery/holosign.dm +++ b/code/game/machinery/holosign.dm @@ -7,9 +7,12 @@ layer = ABOVE_DOOR_LAYER idle_power_usage = 2 active_power_usage = 70 - anchored = 1 - var/lit = 0 + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' + var/lit = FALSE var/on_icon = "sign_on" + var/sign_light_color = COLOR_CYAN_BLUE uncreated_component_parts = list( /obj/item/stock_parts/radio/receiver, @@ -28,15 +31,14 @@ return lit = !lit update_use_power(lit ? POWER_USE_ACTIVE : POWER_USE_IDLE) - update_icon() /obj/machinery/holosign/on_update_icon() if (!lit || inoperable()) - icon_state = "sign_off" + icon_state = initial(icon_state) set_light(0) else icon_state = on_icon - set_light(0.5, 0.5, 1, l_color = COLOR_CYAN_BLUE) + set_light(1, 0.5, sign_light_color) /decl/public_access/public_variable/holosign_on expected_type = /obj/machinery/holosign @@ -51,7 +53,7 @@ /decl/public_access/public_method/holosign_toggle name = "holosign toggle" desc = "Toggle the holosign's active state." - call_proc = /obj/machinery/holosign/proc/toggle + call_proc = TYPE_PROC_REF(/obj/machinery/holosign, toggle) /decl/stock_part_preset/radio/receiver/holosign frequency = BUTTON_FREQ @@ -67,12 +69,19 @@ desc = "Small wall-mounted holographic projector. This one reads SERVICE." on_icon = "service" +/obj/machinery/holosign/bar + name = "bar holosign" + desc = "Small wall-mounted holographic projector. This one reads OPEN." + icon_state = "barclosed" + on_icon = "baropen" + sign_light_color = COLOR_LIGHT_CYAN + ////////////////////SWITCH/////////////////////////////////////// /obj/machinery/button/holosign name = "holosign switch" desc = "A remote control switch for holosign." icon = 'icons/obj/power.dmi' - icon_state = "crema_switch" + icon_state = "crematorium_switch" /obj/machinery/button/holosign/on_update_icon() icon_state = "light[active]" \ No newline at end of file diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index cfe4e9f1abcf..176f286e06bb 100644 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -1,10 +1,10 @@ /obj/machinery/igniter name = "igniter" - desc = "It's useful for igniting flammable items." + desc = "A device that ignites flammable items and gases nearby when activated." icon = 'icons/obj/machines/igniter.dmi' icon_state = "igniter1" var/on = 0 - anchored = 1 + anchored = TRUE idle_power_usage = 20 active_power_usage = 1000 @@ -30,6 +30,8 @@ /obj/machinery/igniter/Initialize() . = ..() update_icon() + if(!on) + STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) /obj/machinery/igniter/on_update_icon() ..() @@ -38,7 +40,7 @@ /obj/machinery/igniter/interface_interact(mob/user) if(!CanInteract(user, DefaultTopicState())) return FALSE - ignite() + toggle_igniter() visible_message(SPAN_NOTICE("\The [user] toggles \the [src].")) return TRUE @@ -49,7 +51,7 @@ location.hotspot_expose(1000,500,1) return 1 -/obj/machinery/igniter/proc/ignite() +/obj/machinery/igniter/proc/toggle_igniter() use_power_oneoff(2000) on = !on if(on) @@ -65,13 +67,13 @@ can_write = FALSE has_updates = FALSE -/decl/public_access/public_variable/holosign_on/access_var(obj/machinery/igniter/igniter) +/decl/public_access/public_variable/igniter_on/access_var(obj/machinery/igniter/igniter) return igniter.on /decl/public_access/public_method/igniter_toggle name = "igniter toggle" desc = "Toggle the igniter on or off." - call_proc = /obj/machinery/igniter/proc/ignite + call_proc = TYPE_PROC_REF(/obj/machinery/igniter, toggle_igniter) /decl/stock_part_preset/radio/receiver/igniter frequency = BUTTON_FREQ @@ -87,7 +89,8 @@ var/disable = 0 var/last_spark = 0 var/base_state = "migniter" - anchored = 1 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + anchored = TRUE idle_power_usage = 20 active_power_usage = 1000 @@ -103,51 +106,44 @@ construct_state = /decl/machine_construction/wall_frame/panel_closed/simple frame_type = /obj/item/frame/button/sparker base_type = /obj/machinery/sparker/buildable + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' /obj/machinery/sparker/buildable uncreated_component_parts = null /obj/machinery/sparker/on_update_icon() - ..() if(disable) - icon_state = "migniter-d" - else if(powered()) - icon_state = "migniter" -// src.sd_SetLuminosity(2) + icon_state = "[base_state]-d" + else if(!(stat & NOPOWER)) + icon_state = base_state else - icon_state = "migniter-p" -// src.sd_SetLuminosity(0) + icon_state = "[base_state]-p" -/obj/machinery/sparker/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) +/obj/machinery/sparker/attackby(obj/item/used_item, mob/user) + if(panel_open && IS_WIRECUTTER(used_item)) add_fingerprint(user) disable = !disable if(disable) - user.visible_message("[user] has disabled the [src]!", "You disable the connection to the [src].") - else if(!disable) - user.visible_message("[user] has reconnected the [src]!", "You fix the connection to the [src].") + user.visible_message(SPAN_WARNING("[user] has disabled \the [src]!"), SPAN_WARNING("You disable the connection to \the [src].")) + else + user.visible_message(SPAN_WARNING("[user] has reconnected \the [src]!"), SPAN_WARNING("You fix the connection to \the [src].")) update_icon() + return TRUE else - ..() + return ..() /obj/machinery/sparker/attack_ai() - if (anchored) - return ignite() - else - return + return anchored ? create_sparks() : null -/obj/machinery/sparker/proc/ignite() - if (!powered()) +/obj/machinery/sparker/proc/create_sparks() + if (stat & NOPOWER) return if (disable || (last_spark && world.time < last_spark + 50)) return - - flick("migniter-spark", src) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, src) - s.start() + flick("[base_state]-spark", src) + spark_at(src, amount=2, cardinal_only = TRUE) src.last_spark = world.time use_power_oneoff(2000) var/turf/location = src.loc @@ -159,13 +155,13 @@ if(stat & (BROKEN|NOPOWER)) ..(severity) return - ignite() + create_sparks() ..(severity) /decl/public_access/public_method/sparker_spark name = "spark" desc = "Creates sparks to ignite nearby gases." - call_proc = /obj/machinery/sparker/proc/ignite + call_proc = TYPE_PROC_REF(/obj/machinery/sparker, create_sparks) /decl/stock_part_preset/radio/receiver/sparker frequency = BUTTON_FREQ diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm index d99435015e17..85a6ad930679 100644 --- a/code/game/machinery/jukebox.dm +++ b/code/game/machinery/jukebox.dm @@ -1,27 +1,11 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/datum/track - var/title - var/track - -/datum/track/New(var/title, var/track) - src.title = title - src.track = track - -datum/track/proc/GetTrack() - if(ispath(track, /music_track)) - var/music_track/music_track = decls_repository.get_decl(track) - return music_track.song - return track // Allows admins to continue their adminbus simply by overriding the track var - /obj/machinery/media/jukebox name = "mediatronic jukebox" desc = "An immense, standalone touchscreen on a swiveling base, equipped with phased array speakers. Embossed on one corner of the ultrathin bezel is the brand name, 'Leitmotif Enterprise Edition'." icon = 'icons/obj/jukebox_new.dmi' icon_state = "jukebox3-nopower" var/state_base = "jukebox3" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE power_channel = EQUIP idle_power_usage = 10 active_power_usage = 100 @@ -33,7 +17,7 @@ datum/track/proc/GetTrack() construct_state = /decl/machine_construction/default/panel_closed var/playing = 0 - var/volume = 20 + var/music_volume = 20 var/sound_id var/datum/sound_token/sound_token @@ -100,7 +84,7 @@ datum/track/proc/GetTrack() "current_track" = current_track != null ? current_track.title : "No track selected", "playing" = playing, "tracks" = juke_tracks, - "volume" = volume + "volume" = music_volume ) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -126,7 +110,7 @@ datum/track/proc/GetTrack() if(emagged) emag_play() else if(!current_track) - to_chat(usr, "No track selected.") + to_chat(user, "No track selected.") else StartPlaying() return TOPIC_REFRESH @@ -137,20 +121,20 @@ datum/track/proc/GetTrack() /obj/machinery/media/jukebox/proc/emag_play() playsound(loc, 'sound/items/AirHorn.ogg', 100, 1) - for(var/mob/living/carbon/M in ohearers(6, src)) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M + for(var/mob/living/M in ohearers(6, src)) + if(ishuman(M)) + var/mob/living/human/H = M if(H.get_sound_volume_multiplier() < 0.2) continue - M.sleeping = 0 - M.stuttering += 20 - M.ear_deaf += 30 - M.Weaken(3) + M.set_status_condition(STAT_ASLEEP, 0) + ADJ_STATUS(M, STAT_STUTTER, 20) + SET_STATUS_MAX(M, STAT_DEAF, 30) + SET_STATUS_MAX(M, STAT_WEAK, 3) if(prob(30)) - M.Stun(10) - M.Paralyse(4) + SET_STATUS_MAX(M, STAT_STUN, 10) + SET_STATUS_MAX(M, STAT_PARA, 4) else - M.make_jittery(400) + M.set_status_condition(STAT_JITTER, 400) spawn(15) explode() @@ -159,24 +143,21 @@ datum/track/proc/GetTrack() return TRUE /obj/machinery/media/jukebox/proc/explode() - walk_to(src,0) src.visible_message("\the [src] blows apart!", 1) explosion(src.loc, 0, 0, 1, rand(1,2), 1) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) new /obj/effect/decal/cleanable/blood/oil(src.loc) qdel(src) -/obj/machinery/media/jukebox/attackby(obj/item/W, mob/user) - if(isWrench(W) && !panel_open) +/obj/machinery/media/jukebox/attackby(obj/item/used_item, mob/user) + if((IS_WRENCH(used_item) || IS_HAMMER(used_item)) && !panel_open) add_fingerprint(user) - wrench_floor_bolts(user, 0) + wrench_floor_bolts(user, 0, used_item) power_change() - return + return TRUE return ..() /obj/machinery/media/jukebox/emag_act(var/remaining_charges, var/mob/user) @@ -190,7 +171,6 @@ datum/track/proc/GetTrack() /obj/machinery/media/jukebox/proc/StopPlaying() playing = 0 update_use_power(POWER_USE_IDLE) - update_icon() QDEL_NULL(sound_token) @@ -200,13 +180,12 @@ datum/track/proc/GetTrack() return // Jukeboxes cheat massively and actually don't share id. This is only done because it's music rather than ambient noise. - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, current_track.GetTrack(), volume = volume, range = 7, falloff = 3, prefer_mute = TRUE, preference = /datum/client_preference/play_game_music) + sound_token = play_looping_sound(src, sound_id, current_track.GetTrack(), volume = music_volume, range = 7, falloff = 3, prefer_mute = TRUE, preference = /datum/client_preference/play_game_music, streaming = TRUE) playing = 1 update_use_power(POWER_USE_ACTIVE) - update_icon() /obj/machinery/media/jukebox/proc/AdjustVolume(var/new_volume) - volume = Clamp(new_volume, 0, 50) + music_volume = clamp(new_volume, 0, 50) if(sound_token) - sound_token.SetVolume(volume) + sound_token.SetVolume(music_volume) diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker.dm b/code/game/machinery/kitchen/cooking_machines/_cooker.dm index cf78c540fd8b..0eeac4289ae0 100644 --- a/code/game/machinery/kitchen/cooking_machines/_cooker.dm +++ b/code/game/machinery/kitchen/cooking_machines/_cooker.dm @@ -1,15 +1,15 @@ // This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed. // Tracks precooked food to stop deep fried baked grilled grilled grilled monkey cereal. -/obj/item/chems/food/snacks/var/list/cooked +/obj/item/food/var/list/cooked // Root type for cooking machines. See following files for specific implementations. /obj/machinery/cooker name = "cooker" desc = "You shouldn't be seeing this!" icon = 'icons/obj/cooking_machines.dmi' - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 5 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null @@ -37,12 +37,12 @@ cooking_obj = null return ..() -/obj/machinery/cooker/examine(mob/user) +/obj/machinery/cooker/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(cooking_obj) - to_chat(user, "You can see \a [cooking_obj] inside.") + . += "You can see \a [cooking_obj] inside." if(panel_open) - to_chat(user, "The panel is open") + . += "The service panel is open." /obj/machinery/cooker/components_are_accessible(path) return !cooking && ..() @@ -52,49 +52,47 @@ return SPAN_NOTICE("Wait for \the [src] to finish first!") return ..() -/obj/machinery/cooker/attackby(var/obj/item/I, var/mob/user) +/obj/machinery/cooker/grab_attack(obj/item/grab/grab, mob/user) + // We are trying to cook a grabbed mob. + var/mob/living/victim = grab.get_affecting_mob() + if(!istype(victim)) + to_chat(user, SPAN_WARNING("You can't cook that.")) + return TRUE + if(!can_cook_mobs) + to_chat(user, SPAN_WARNING("That's not going to fit.")) + return TRUE + cook_mob(victim, user) + return TRUE + + +/obj/machinery/cooker/attackby(var/obj/item/used_item, var/mob/user) set waitfor = 0 //So that any remaining parts of calling proc don't have to wait for the long cooking time ahead. if(cooking) to_chat(user, "\The [src] is running!") - return + return TRUE - if((. = component_attackby(I, user))) + if((. = component_attackby(used_item, user))) return if(!cook_type || (stat & (NOPOWER|BROKEN))) to_chat(user, "\The [src] is not working.") - return - - // We are trying to cook a grabbed mob. - var/obj/item/grab/G = I - if(istype(G)) - - if(!can_cook_mobs) - to_chat(user, "That's not going to fit.") - return - - if(!isliving(G.affecting)) - to_chat(user, "You can't cook that.") - return - - cook_mob(G.affecting, user) - return + return TRUE // We're trying to cook something else. Check if it's valid. - var/obj/item/chems/food/snacks/check = I + var/obj/item/food/check = used_item if(istype(check) && islist(check.cooked) && (cook_type in check.cooked)) to_chat(user, "\The [check] has already been [cook_type].") - return 0 + return TRUE else if(istype(check, /obj/item/chems/glass)) to_chat(user, "That would probably break [src].") - return 0 + return TRUE else if(istype(check, /obj/item/disk/nuclear)) to_chat(user, "Central Command would kill you if you [cook_type] that.") - return 0 + return TRUE else if(!istype(check) && !istype(check, /obj/item/holder)) to_chat(user, "That's not edible.") - return 0 + return TRUE // Gotta hurt. if(istype(cooking_obj, /obj/item/holder)) @@ -102,12 +100,12 @@ M.apply_damage(rand(30,40), BURN, BP_CHEST) // Not sure why a food item that passed the previous checks would fail to drop, but safety first. - if(!user.unEquip(I)) - return + if(!user.try_unequip(used_item)) + return TRUE // We can actually start cooking now. - user.visible_message("\The [user] puts \the [I] into \the [src].") - cooking_obj = I + user.visible_message("\The [user] puts \the [used_item] into \the [src].") + cooking_obj = used_item cooking_obj.forceMove(src) cooking = 1 icon_state = on_icon @@ -117,7 +115,7 @@ // Sanity checks. if(check_cooking_obj()) - return // Cooking failed/was terminated. + return TRUE // Cooking failed/was terminated. // RIP slow-moving held mobs. if(istype(cooking_obj, /obj/item/holder)) @@ -130,11 +128,12 @@ if(selected_option && output_options.len) cook_path = output_options[selected_option] if(!cook_path) - cook_path = /obj/item/chems/food/snacks/variable - var/obj/item/chems/food/snacks/result = new cook_path(src) //Holy typepaths, Batman. + cook_path = /obj/item/food/variable + var/obj/item/food/result = new cook_path(src) //Holy typepaths, Batman. - if(cooking_obj.reagents && cooking_obj.reagents.total_volume) - cooking_obj.reagents.trans_to(result, cooking_obj.reagents.total_volume) + var/cooking_reagents = REAGENT_TOTAL_VOLUME(cooking_obj.reagents) + if(cooking_reagents > 0) + cooking_obj.reagents.trans_to(result, cooking_reagents) // Set icon and appearance. change_product_appearance(result) @@ -143,7 +142,7 @@ change_product_strings(result) // Set cooked data. - var/obj/item/chems/food/snacks/food_item = cooking_obj + var/obj/item/food/food_item = cooking_obj if(istype(food_item) && islist(food_item.cooked)) result.cooked = food_item.cooked.Copy() else @@ -163,7 +162,7 @@ cooking_obj = null else var/failed - var/overcook_period = max(Floor(cook_time/5),1) + var/overcook_period = max(floor(cook_time/5),1) cooking_obj = result while(1) sleep(overcook_period) @@ -172,7 +171,7 @@ else if(prob(burn_chance)) // You dun goofed. qdel(cooking_obj) - cooking_obj = new /obj/item/chems/food/snacks/badrecipe(src) + cooking_obj = new /obj/item/food/badrecipe(src) // Produce nasty smoke. visible_message("\The [src] vomits a gout of rancid smoke!") var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() @@ -185,6 +184,7 @@ cooking = 0 icon_state = off_icon break + return TRUE /obj/machinery/cooker/proc/check_cooking_obj() if(!cooking_obj || cooking_obj.loc != src) @@ -221,31 +221,16 @@ /obj/machinery/cooker/proc/cook_mob(var/mob/living/victim, var/mob/user) return -/obj/machinery/cooker/proc/change_product_strings(var/obj/item/chems/food/snacks/product) - if(product.type == /obj/item/chems/food/snacks/variable) // Base type, generic. +/obj/machinery/cooker/proc/change_product_strings(var/obj/item/food/product) + if(product.type == /obj/item/food/variable) // Base type, generic. product.SetName("[cook_type] [cooking_obj.name]") product.desc = "[cooking_obj.desc] It has been [cook_type]." else product.SetName("[cooking_obj.name] [product.name]") -/obj/machinery/cooker/proc/change_product_appearance(var/obj/item/chems/food/snacks/product) - if(product.type == /obj/item/chems/food/snacks/variable) // Base type, generic. - product.appearance = cooking_obj - product.color = food_color - product.filling_color = food_color - - // Make 'em into a corpse. - if(istype(cooking_obj, /obj/item/holder)) - var/matrix/M = matrix() - M.Turn(90) - M.Translate(1,-6) - product.transform = M - else - var/image/I = image(product.icon, "[product.icon_state]_filling") - if(istype(cooking_obj, /obj/item/chems/food/snacks)) - var/obj/item/chems/food/snacks/S = cooking_obj - I.color = S.filling_color - if(!I.color) - I.color = food_color - product.overlays += I - +/obj/machinery/cooker/proc/change_product_appearance(var/obj/item/food/product) + if(istype(product)) + if(istype(cooking_obj, /obj/item/food)) + var/obj/item/food/S = cooking_obj + food_color = S.filling_color + product.update_food_appearance_from(cooking_obj, food_color) diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm index 34f8475eadb8..91aac2326a76 100644 --- a/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm +++ b/code/game/machinery/kitchen/cooking_machines/_cooker_output.dm @@ -1,79 +1,94 @@ // Wrapper obj for cooked food. Appearance is set in the cooking code, not on spawn. -/obj/item/chems/food/snacks/variable +/obj/item/food/variable name = "cooked food" - icon = 'icons/obj/food_custom.dmi' + icon = 'icons/obj/food/custom/custom.dmi' desc = "If you can see this description then something is wrong. Please report the bug on the tracker." nutriment_amt = 5 bitesize = 2 + filling_color = COLOR_BROWN + abstract_type = /obj/item/food/variable -/obj/item/chems/food/snacks/variable/pizza +/obj/item/food/variable/Initialize(mapload, material_key, skip_plate = FALSE) + . = ..() + update_icon() + +/obj/item/food/variable/update_food_appearance_from(var/obj/item/donor, var/food_color, var/copy_donor_appearance = TRUE) + ..(donor, food_color, (type == /obj/item/food/variable)) // variable is used for generic foods (deep fried X), subtypes are used for specific foods + +/obj/item/food/variable/pizza name = "personal pizza" desc = "A personalized pan pizza meant for only one person." icon_state = "personal_pizza" -/obj/item/chems/food/snacks/variable/bread +/obj/item/food/variable/bread name = "bread" desc = "Tasty bread." icon_state = "breadcustom" -/obj/item/chems/food/snacks/variable/pie +/obj/item/food/variable/pie name = "pie" desc = "Tasty pie." icon_state = "piecustom" -/obj/item/chems/food/snacks/variable/cake +/obj/item/food/variable/cake name = "cake" desc = "A popular band." icon_state = "cakecustom" -/obj/item/chems/food/snacks/variable/pocket +/obj/item/food/variable/pocket name = "hot pocket" desc = "You wanna put a bangin- oh, nevermind." icon_state = "donk" + filling_color = COLOR_BROWN -/obj/item/chems/food/snacks/variable/kebab +/obj/item/food/variable/kebab name = "kebab" desc = "Food is just tastier on a stick!" icon_state = "kabob" + filling_color = COLOR_DARK_RED -/obj/item/chems/food/snacks/variable/waffles +/obj/item/food/variable/waffles name = "waffles" desc = "Made with love." icon_state = "waffles" gender = PLURAL -/obj/item/chems/food/snacks/variable/pancakes +/obj/item/food/variable/pancakes name = "pancakes" desc = "How does an oven make pancakes?" icon_state = "pancakescustom" gender = PLURAL -/obj/item/chems/food/snacks/variable/cookie +/obj/item/food/variable/cookie name = "cookie" desc = "Sugar snap!" icon_state = "cookie" -/obj/item/chems/food/snacks/variable/donut +/obj/item/food/variable/donut name = "filled donut" desc = "Donut eat this!" // kill me icon_state = "donut" -/obj/item/chems/food/snacks/variable/jawbreaker +/obj/item/food/variable/jawbreaker name = "flavored jawbreaker" desc = "It's like cracking a molar on a rainbow." icon_state = "jawbreaker" + filling_color = COLOR_RED -/obj/item/chems/food/snacks/variable/candybar +/obj/item/food/variable/candybar name = "flavored chocolate bar" desc = "Made in a factory downtown." icon_state = "bar" + filling_color = COLOR_DARK_BROWN -/obj/item/chems/food/snacks/variable/sucker +/obj/item/food/variable/sucker name = "flavored sucker" desc = "Suck, suck, suck." icon_state = "sucker" + filling_color = COLOR_RED -/obj/item/chems/food/snacks/variable/jelly +/obj/item/food/variable/jelly name = "jelly" desc = "All your friends will be jelly." icon_state = "jellycustom" + filling_color = COLOR_RED diff --git a/code/game/machinery/kitchen/cooking_machines/candy.dm b/code/game/machinery/kitchen/cooking_machines/candy.dm index 0c41c116163f..6567fb4b8213 100644 --- a/code/game/machinery/kitchen/cooking_machines/candy.dm +++ b/code/game/machinery/kitchen/cooking_machines/candy.dm @@ -7,12 +7,12 @@ cook_type = "candied" output_options = list( - "Jawbreaker" = /obj/item/chems/food/snacks/variable/jawbreaker, - "Candy Bar" = /obj/item/chems/food/snacks/variable/candybar, - "Sucker" = /obj/item/chems/food/snacks/variable/sucker, - "Jelly" = /obj/item/chems/food/snacks/variable/jelly + "Jawbreaker" = /obj/item/food/variable/jawbreaker, + "Candy Bar" = /obj/item/food/variable/candybar, + "Sucker" = /obj/item/food/variable/sucker, + "Jelly" = /obj/item/food/variable/jelly ) -/obj/machinery/cooker/candy/change_product_appearance(var/obj/item/chems/food/snacks/product) +/obj/machinery/cooker/candy/change_product_appearance(var/obj/item/food/product) food_color = get_random_colour(1) . = ..() diff --git a/code/game/machinery/kitchen/cooking_machines/cereal.dm b/code/game/machinery/kitchen/cooking_machines/cereal.dm index 2db2336d53b2..69e3ce24a9ff 100644 --- a/code/game/machinery/kitchen/cooking_machines/cereal.dm +++ b/code/game/machinery/kitchen/cooking_machines/cereal.dm @@ -7,12 +7,12 @@ on_icon = "cereal_on" off_icon = "cereal_off" -/obj/machinery/cooker/cereal/change_product_strings(var/obj/item/chems/food/snacks/product) +/obj/machinery/cooker/cereal/change_product_strings(var/obj/item/food/product) . = ..() product.SetName("box of [cooking_obj.name] cereal") -/obj/machinery/cooker/cereal/change_product_appearance(var/obj/item/chems/food/snacks/product) - product.icon = 'icons/obj/food.dmi' +/obj/machinery/cooker/cereal/change_product_appearance(var/obj/item/food/product) + product.icon = 'icons/obj/food/custom/custom.dmi' product.icon_state = "cereal_box" product.filling_color = cooking_obj.color diff --git a/code/game/machinery/kitchen/cooking_machines/fryer.dm b/code/game/machinery/kitchen/cooking_machines/fryer.dm index 0b084658b0d7..090c58670cf6 100644 --- a/code/game/machinery/kitchen/cooking_machines/fryer.dm +++ b/code/game/machinery/kitchen/cooking_machines/fryer.dm @@ -1,6 +1,6 @@ /obj/machinery/cooker/fryer name = "deep fryer" - desc = "Deep fried everything." + desc = "Deep-fried everything." icon_state = "fryer_off" can_cook_mobs = 1 cook_type = "deep fried" @@ -29,10 +29,10 @@ icon_state = off_icon return - var/target_zone = user.zone_sel.selecting + var/target_zone = user.get_target_zone() if(ishuman(victim) && !(target_zone in list(BP_GROIN, BP_CHEST))) - var/mob/living/carbon/human/H = victim - var/obj/item/organ/external/E = H.get_organ(target_zone) + var/mob/living/human/H = victim + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(H, target_zone) if(!E) to_chat(user, "They are missing that body part!") else diff --git a/code/game/machinery/kitchen/cooking_machines/oven.dm b/code/game/machinery/kitchen/cooking_machines/oven.dm index e07c0d31fe4f..ec768b02ba12 100644 --- a/code/game/machinery/kitchen/cooking_machines/oven.dm +++ b/code/game/machinery/kitchen/cooking_machines/oven.dm @@ -11,14 +11,14 @@ can_burn_food = 1 output_options = list( - "Personal Pizza" = /obj/item/chems/food/snacks/variable/pizza, - "Bread" = /obj/item/chems/food/snacks/variable/bread, - "Pie" = /obj/item/chems/food/snacks/variable/pie, - "Small Cake" = /obj/item/chems/food/snacks/variable/cake, - "Hot Pocket" = /obj/item/chems/food/snacks/variable/pocket, - "Kebab" = /obj/item/chems/food/snacks/variable/kebab, - "Waffles" = /obj/item/chems/food/snacks/variable/waffles, - "Pancakes" = /obj/item/chems/food/snacks/variable/pancakes, - "Cookie" = /obj/item/chems/food/snacks/variable/cookie, - "Donut" = /obj/item/chems/food/snacks/variable/donut, + "Personal Pizza" = /obj/item/food/variable/pizza, + "Bread" = /obj/item/food/variable/bread, + "Pie" = /obj/item/food/variable/pie, + "Small Cake" = /obj/item/food/variable/cake, + "Hot Pocket" = /obj/item/food/variable/pocket, + "Kebab" = /obj/item/food/variable/kebab, + "Waffles" = /obj/item/food/variable/waffles, + "Pancakes" = /obj/item/food/variable/pancakes, + "Cookie" = /obj/item/food/variable/cookie, + "Donut" = /obj/item/food/variable/donut, ) \ No newline at end of file diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index 81e751f31559..4a68783d0305 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -4,12 +4,12 @@ desc = "The name isn't descriptive enough?" icon = 'icons/obj/kitchen.dmi' icon_state = "grinder" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE initial_access = list(list(access_kitchen, access_morgue)) construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 + stat_immune = NOSCREEN var/operating = 0 //Is it on? var/dirty = 0 // Does it need cleaning? @@ -54,9 +54,9 @@ src.startgibbing(user) return TRUE -/obj/machinery/gibber/examine(mob/user) +/obj/machinery/gibber/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The safety guard is [emagged ? "disabled" : "enabled"].") + . += "The safety guard is [emagged ? SPAN_DANGER("disabled") : "enabled"]." /obj/machinery/gibber/emag_act(var/remaining_charges, var/mob/user) emagged = !emagged @@ -64,35 +64,34 @@ return 1 /obj/machinery/gibber/components_are_accessible(path) - return !operating && ..() + return !operating && ..() /obj/machinery/gibber/cannot_transition_to(state_path, mob/user) if(operating) return SPAN_NOTICE("You must wait for \the [src] to finish operating first!") - return ..() + return ..() -/obj/machinery/gibber/attackby(var/obj/item/W, var/mob/user) - if(!operating) - return - if(istype(W, /obj/item/grab)) - var/obj/item/grab/G = W - if(!G.force_danger()) - to_chat(user, "You need a better grip to do that!") - return - qdel(G) - move_into_gibber(user,G.affecting) - else if(istype(W, /obj/item/organ)) - if(!user.unEquip(W)) - return - qdel(W) - user.visible_message("\The [user] feeds \the [W] into \the [src], obliterating it.") +/obj/machinery/gibber/grab_attack(obj/item/grab/grab, mob/user) + if(grab.force_danger()) + move_into_gibber(user, grab.affecting) + qdel(grab) else - return ..() + to_chat(user, SPAN_DANGER("You need a better grip to do that!")) + return TRUE -/obj/machinery/gibber/MouseDrop_T(mob/target, mob/user) - if(user.stat || user.restrained()) - return - move_into_gibber(user,target) +/obj/machinery/gibber/attackby(var/obj/item/used_item, var/mob/user) + if(!operating && istype(used_item, /obj/item/organ)) + if(user.try_unequip(used_item)) + qdel(used_item) + user.visible_message(SPAN_DANGER("\The [user] feeds \the [used_item] into \the [src], obliterating it.")) + return TRUE + return ..() + +/obj/machinery/gibber/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && ismob(dropping)) + move_into_gibber(user, dropping) + return TRUE /obj/machinery/gibber/proc/move_into_gibber(var/mob/user,var/mob/living/victim) @@ -104,15 +103,14 @@ to_chat(user, "\The [src] is locked and running, wait for it to finish.") return - if(!(istype(victim, /mob/living/carbon)) && !(istype(victim, /mob/living/simple_animal)) ) + if(!isliving(victim)) to_chat(user, "This is not suitable for \the [src]!") return - if(istype(victim,/mob/living/carbon/human) && !emagged) + if(ishuman(victim) && !emagged) to_chat(user, "\The [src] safety guard is engaged!") return - if(victim.abiotic(1)) to_chat(user, "\The [victim] may not have any abiotic items on.") return @@ -133,7 +131,7 @@ set name = "Empty Gibber" set src in oview(1) - if (usr.stat != 0) + if (usr.stat != CONSCIOUS) return src.go_out() add_fingerprint(usr) @@ -142,7 +140,7 @@ /obj/machinery/gibber/proc/go_out() if(operating || !src.occupant) return - for(var/obj/O in (contents - component_parts)) + for(var/obj/O in get_contained_external_atoms()) O.dropInto(loc) if (src.occupant.client) src.occupant.client.eye = src.occupant.client.mob @@ -166,21 +164,20 @@ admin_attack_log(user, occupant, "Gibbed the victim", "Was gibbed", "gibbed") src.occupant.ghostize() - addtimer(CALLBACK(src, .proc/finish_gibbing), gib_time) - - var/list/gib_products = shuffle(occupant.harvest_meat() | occupant.harvest_skin() | occupant.harvest_bones()) - if(length(gib_products) <= 0) + addtimer(CALLBACK(src, PROC_REF(finish_gibbing)), gib_time) + var/decl/butchery_data/butchery_data = GET_DECL(occupant.butchery_data) + var/list/gib_products = butchery_data?.get_all_products(occupant) + if(!length(gib_products)) return + gib_products = shuffle(gib_products) var/slab_name = occupant.name var/slab_nutrition = 20 - if(iscarbon(occupant)) - var/mob/living/carbon/C = occupant - slab_nutrition = C.nutrition / 15 - - if(istype(occupant, /mob/living/carbon/human)) - slab_name = occupant.real_name + if(isliving(occupant)) + slab_nutrition = round(occupant.get_nutrition() / 15) + if(ishuman(occupant)) + slab_name = occupant.real_name // Small mobs don't give as much nutrition. if(issmall(src.occupant)) @@ -188,17 +185,17 @@ slab_nutrition /= gib_products.len - var/drop_products = Floor(gib_products.len * 0.35) + var/drop_products = floor(gib_products.len * 0.35) for(var/atom/movable/thing in gib_products) if(drop_products) drop_products-- qdel(thing) else thing.forceMove(src) - if(istype(thing, /obj/item/chems/food/snacks/meat)) - var/obj/item/chems/food/snacks/meat/slab = thing + if(istype(thing, /obj/item/food/butchery/meat)) + var/obj/item/food/butchery/meat/slab = thing slab.SetName("[slab_name] [slab.name]") - slab.reagents.add_reagent(/decl/material/liquid/nutriment,slab_nutrition) + slab.add_to_reagents(/decl/material/liquid/nutriment,slab_nutrition) /obj/machinery/gibber/proc/finish_gibbing() operating = 0 @@ -209,7 +206,7 @@ qdel(occupant) playsound(loc, 'sound/effects/splat.ogg', 50, 1) - for (var/obj/thing in (contents - component_parts)) + for (var/obj/thing in get_contained_external_atoms()) // There's a chance that the gibber will fail to destroy some evidence. if(istype(thing,/obj/item/organ) && prob(80)) qdel(thing) diff --git a/code/game/machinery/kitchen/icecream.dm b/code/game/machinery/kitchen/icecream.dm index af6425a1c583..01586b8549e9 100644 --- a/code/game/machinery/kitchen/icecream.dm +++ b/code/game/machinery/kitchen/icecream.dm @@ -14,10 +14,11 @@ desc = "A heavy metal container used to produce and store ice cream." icon = 'icons/obj/kitchen.dmi' icon_state = "icecream_vat" - density = 1 - anchored = 0 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_REACT | ATOM_FLAG_OPEN_CONTAINER + density = TRUE + anchored = FALSE + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE | ATOM_FLAG_OPEN_CONTAINER idle_power_usage = 100 + chem_volume = 100 var/list/product_types = list() var/dispense_flavour = ICECREAM_VANILLA @@ -33,7 +34,7 @@ if(ICECREAM_STRAWBERRY) return list(/decl/material/liquid/drink/milk, /decl/material/solid/ice, /decl/material/liquid/drink/juice/berry) if(ICECREAM_BLUE) - return list(/decl/material/liquid/drink/milk, /decl/material/solid/ice, /decl/material/liquid/ethanol/bluecuracao) + return list(/decl/material/liquid/drink/milk, /decl/material/solid/ice, /decl/material/liquid/alcohol/bluecuracao) if(ICECREAM_CHERRY) return list(/decl/material/liquid/drink/milk, /decl/material/solid/ice, /decl/material/liquid/nutriment/cherryjelly) if(ICECREAM_BANANA) @@ -66,14 +67,14 @@ /obj/machinery/icecream_vat/Initialize(mapload, d, populate_parts) . = ..() - create_reagents(100) while(product_types.len < 8) product_types.Add(5) - if(populate_parts) - reagents.add_reagent(/decl/material/liquid/drink/milk, 5) - reagents.add_reagent(/decl/material/liquid/nutriment/flour, 5) - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 5) - reagents.add_reagent(/decl/material/solid/ice, 5) + +/obj/machinery/icecream_vat/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk, 5) + add_to_reagents(/decl/material/liquid/nutriment/flour, 5) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 5) + add_to_reagents(/decl/material/solid/ice, 5) /obj/machinery/icecream_vat/interface_interact(mob/user) interact(user) @@ -84,58 +85,63 @@ var/dat dat += "ICECREAM
    " dat += "Dispensing: [flavour_name] icecream

    " - dat += "Vanilla icecream: Select Make x5 [product_types[ICECREAM_VANILLA]] scoops left. (Ingredients: milk, ice)
    " - dat += "Strawberry icecream: Select Make x5 [product_types[ICECREAM_STRAWBERRY]] dollops left. (Ingredients: milk, ice, berry juice)
    " - dat += "Chocolate icecream: Select Make x5 [product_types[ICECREAM_CHOCOLATE]] dollops left. (Ingredients: milk, ice, coco powder)
    " - dat += "Blue icecream: Select Make x5 [product_types[ICECREAM_BLUE]] dollops left. (Ingredients: milk, ice, blue curacao)
    " - dat += "Cherry icecream: Select Make x5 [product_types[ICECREAM_CHERRY]] dollops left. (Ingredients: milk, ice, cherry jelly)
    " - dat += "Banana icecream: Select Make x5 [product_types[ICECREAM_BANANA]] dollops left. (Ingredients: milk, ice, banana)
    " + dat += "Vanilla icecream: Select Make x5 [product_types[ICECREAM_VANILLA]] scoops left. (Ingredients: milk, ice)
    " + dat += "Strawberry icecream: Select Make x5 [product_types[ICECREAM_STRAWBERRY]] dollops left. (Ingredients: milk, ice, berry juice)
    " + dat += "Chocolate icecream: Select Make x5 [product_types[ICECREAM_CHOCOLATE]] dollops left. (Ingredients: milk, ice, coco powder)
    " + dat += "Blue icecream: Select Make x5 [product_types[ICECREAM_BLUE]] dollops left. (Ingredients: milk, ice, blue curacao)
    " + dat += "Cherry icecream: Select Make x5 [product_types[ICECREAM_CHERRY]] dollops left. (Ingredients: milk, ice, cherry jelly)
    " + dat += "Banana icecream: Select Make x5 [product_types[ICECREAM_BANANA]] dollops left. (Ingredients: milk, ice, banana)
    " dat += "
    CONES
    " - dat += "Waffle cones: Dispense Make x5 [product_types[CONE_WAFFLE]] cones left. (Ingredients: flour, sugar)
    " - dat += "Chocolate cones: Dispense Make x5 [product_types[CONE_CHOC]] cones left. (Ingredients: flour, sugar, coco powder)
    " + dat += "Waffle cones: Dispense Make x5 [product_types[CONE_WAFFLE]] cones left. (Ingredients: flour, sugar)
    " + dat += "Chocolate cones: Dispense Make x5 [product_types[CONE_CHOC]] cones left. (Ingredients: flour, sugar, coco powder)
    " dat += "
    " dat += "VAT CONTENT
    " - for(var/reagent_type in reagents?.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(reagent_type) - dat += "[R.name]: [REAGENT_VOLUME(reagents, reagent_type)]" - dat += "Purge
    " - dat += "Refresh Close" + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(reagents)) + dat += "[reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID)]: [LIQUID_VOLUME(reagents, reagent)]" + dat += "Purge
    " + + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(reagents)) + dat += "[reagent.get_reagent_name(reagents, MAT_PHASE_SOLID)]: [SOLID_VOLUME(reagents, reagent)]" + dat += "Purge
    " + + dat += "Refresh Close" var/datum/browser/popup = new(user, "icecreamvat","Icecream Vat", 700, 500, src) popup.set_content(dat) popup.open() -/obj/machinery/icecream_vat/attackby(var/obj/item/O, var/mob/user) - if(istype(O, /obj/item/chems/food/snacks/icecream)) - var/obj/item/chems/food/snacks/icecream/I = O - if(!I.ice_creamed) +/obj/machinery/icecream_vat/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/food/icecream)) + var/obj/item/food/icecream/icecream = used_item + if(!icecream.ice_creamed) if(product_types[dispense_flavour] > 0) - src.visible_message("\icon[src] [user] scoops delicious [flavour_name] icecream into [I].") + src.visible_message("[html_icon(src)] [user] scoops delicious [flavour_name] icecream into [icecream].") product_types[dispense_flavour] -= 1 - I.add_ice_cream(flavour_name) + icecream.add_ice_cream(flavour_name) // if(beaker) - // beaker.reagents.trans_to(I, 10) - if(I.reagents.total_volume < 10) - I.reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 10 - I.reagents.total_volume) + // beaker.reagents.trans_to(icecream, 10) + var/icecream_volume = REAGENT_TOTAL_VOLUME(icecream.reagents) + if(icecream_volume < 10) + icecream.add_to_reagents(/decl/material/liquid/nutriment/sugar, 10 - icecream_volume) else to_chat(user, "There is not enough icecream left!") else - to_chat(user, "[O] already has icecream in it.") - return 1 - else if(ATOM_IS_OPEN_CONTAINER(O)) - return + to_chat(user, "[used_item] already has icecream in it.") + return TRUE + else if(ATOM_IS_OPEN_CONTAINER(used_item)) + return TRUE else - ..() + return ..() /obj/machinery/icecream_vat/proc/make(var/mob/user, var/make_type, var/amount) - for(var/R in get_ingredient_list(make_type)) - if(reagents.has_reagent(R, amount)) + for(var/reagent in get_ingredient_list(make_type)) + if(reagents.has_reagent(reagent, amount)) continue amount = 0 break if(amount) - for(var/R in get_ingredient_list(make_type)) - reagents.remove_reagent(R, amount) + for(var/reagent in get_ingredient_list(make_type)) + remove_from_reagents(reagent, amount) product_types[make_type] += amount var/flavour = get_flavour_name(make_type) if(make_type > 6) @@ -161,10 +167,10 @@ var/cone_name = get_flavour_name(dispense_cone) if(product_types[dispense_cone] >= 1) product_types[dispense_cone] -= 1 - var/obj/item/chems/food/snacks/icecream/I = new(src.loc) - I.cone_type = cone_name - I.icon_state = "icecream_cone_[cone_name]" - I.desc = "Delicious [cone_name] cone, but no ice cream." + var/obj/item/food/icecream/icecream = new(src.loc) + icecream.cone_type = cone_name + icecream.icon_state = "icecream_cone_[cone_name]" + icecream.desc = "Delicious [cone_name] cone, but no ice cream." src.visible_message("[user] dispenses a crunchy [cone_name] cone from [src].") else to_chat(user, "There are no [cone_name] cones left!") @@ -177,34 +183,42 @@ . = TOPIC_REFRESH else if(href_list["disposeI"]) - var/decl/material/R = locate(href_list["disposeI"]) - if(R) - reagents.clear_reagent(R.type) + var/decl/material/reagent = locate(href_list["disposeI"]) + if(reagent) + reagents.clear_reagent(reagent.type) . = TOPIC_REFRESH if(href_list["refresh"]) . = TOPIC_REFRESH -/obj/item/chems/food/snacks/icecream +/obj/item/food/icecream name = "ice cream cone" desc = "Delicious waffle cone, but no ice cream." + icon = 'icons/obj/icecream.dmi' icon_state = "icecream_cone_waffle" //default for admin-spawned cones, href_list["cone"] should overwrite this all the time layer = ABOVE_OBJ_LAYER bitesize = 3 - volume = 20 - - var/ice_creamed = 0 + chem_volume = 20 + nutriment_amt = 5 + nutriment_type = /decl/material/liquid/nutriment + nutriment_desc = list("crunchy waffle cone" = 1) + var/ice_creamed var/cone_type -/obj/item/chems/food/snacks/icecream/Initialize() +/obj/item/food/icecream/Initialize(mapload, material_key, skip_plate = FALSE) + . = ..() + update_icon() + +/obj/item/food/icecream/on_update_icon() . = ..() - reagents.add_reagent(/decl/material/liquid/nutriment, 5) + if(ice_creamed) + add_overlay("icecream_[ice_creamed]") -/obj/item/chems/food/snacks/icecream/proc/add_ice_cream(var/flavour_name) +/obj/item/food/icecream/proc/add_ice_cream(var/flavour_name) name = "[flavour_name] icecream" - src.overlays += "icecream_[flavour_name]" desc = "Delicious [cone_type] cone with a dollop of [flavour_name] ice cream." - ice_creamed = 1 + ice_creamed = flavour_name + update_icon() #undef ICECREAM_VANILLA #undef ICECREAM_CHOCOLATE diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm index 1782620a54b5..2e0e8d8d14ad 100644 --- a/code/game/machinery/kitchen/microwave.dm +++ b/code/game/machinery/kitchen/microwave.dm @@ -1,22 +1,35 @@ - /obj/machinery/microwave name = "microwave" icon = 'icons/obj/kitchen.dmi' icon_state = "mw" layer = BELOW_OBJ_LAYER - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 5 active_power_usage = 100 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_REACT | ATOM_FLAG_OPEN_CONTAINER + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE | ATOM_FLAG_OPEN_CONTAINER construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 - var/operating = 0 // Is it on? + chem_volume = 100 + + var/operating = FALSE // Is it on? var/dirty = 0 // = {0..100} Does it need cleaning? var/broken = 0 // ={0,1,2} How broken is it??? - var/list/ingredients = list() + var/max_n_of_items = 20 // default, adjusted by matter bins + var/datum/composite_sound/microwave/soundloop + + // These determine if the current cooking process failed, the vars above determine if the microwave is broken + var/cook_break = FALSE + var/cook_dirty = FALSE + var/failed = FALSE // pretty much exclusively for sending the fail state across to the UI, using recipe elsewhere is preferred + var/cook_time = 400 + var/start_time = 0 + var/end_time = 0 + var/cooking_power = 1 + + var/cooking_temperature = 93 CELSIUS // 200 F apparently? // see code/modules/food/recipes_microwave.dm for recipes @@ -26,115 +39,116 @@ /obj/machinery/microwave/Initialize() . = ..() - create_reagents(100) + soundloop = new(list(src), FALSE) + +/obj/machinery/microwave/Destroy() + dispose() + QDEL_NULL(soundloop) + return ..() /******************* * Item Adding ********************/ -/obj/machinery/microwave/attackby(var/obj/item/O, var/mob/user) - if(src.broken > 0) - if(src.broken == 2 && isScrewdriver(O)) // If it's broken and they're using a screwdriver - user.visible_message( \ - "\The [user] starts to fix part of the microwave.", \ - "You start to fix part of the microwave." \ +/obj/machinery/microwave/grab_attack(obj/item/grab/grab, mob/user) + to_chat(user, SPAN_WARNING("This is ridiculous. You can not fit \the [grab.affecting] into \the [src].")) + return TRUE + +/obj/machinery/microwave/attackby(var/obj/item/used_item, var/mob/user) + if(broken > 0) + if(broken == 2 && IS_SCREWDRIVER(used_item)) // If it's broken and they're using a screwdriver + user.visible_message( + SPAN_NOTICE("\The [user] starts to fix part of [src]."), + SPAN_NOTICE("You start to fix part of [src].") ) if (do_after(user, 20, src)) - user.visible_message( \ - "\The [user] fixes part of the microwave.", \ - "You have fixed part of the microwave." \ + user.visible_message( + SPAN_NOTICE("\The [user] fixes part of [src]."), + SPAN_NOTICE("You have fixed part of [src].") ) - src.broken = 1 // Fix it a bit - else if(src.broken == 1 && isWrench(O)) // If it's broken and they're doing the wrench - user.visible_message( \ - "\The [user] starts to fix part of the microwave.", \ - "You start to fix part of the microwave." \ + broken = 1 // Fix it a bit + else if(broken == 1 && IS_WRENCH(used_item)) // If it's broken and they're doing the wrench + user.visible_message( + SPAN_NOTICE("\The [user] starts to fix part of [src]."), + SPAN_NOTICE("You start to fix part of [src].") ) if (do_after(user, 20, src)) - user.visible_message( \ - "\The [user] fixes the microwave.", \ - "You have fixed the microwave." \ + user.visible_message( + SPAN_NOTICE("\The [user] fixes [src]."), + SPAN_NOTICE("You have fixed [src].") ) - src.broken = 0 // Fix it! - src.dirty = 0 // just to be sure - src.update_icon() - src.atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER + broken = 0 // Fix it! + dirty = 0 // just to be sure + update_icon() + atom_flags = ATOM_FLAG_OPEN_CONTAINER else - to_chat(user, "It's broken!") + to_chat(user, SPAN_WARNING("It's broken!")) return 1 - else if((. = component_attackby(O, user))) + else if((. = component_attackby(used_item, user))) dispose() return - else if(src.dirty==100) // The microwave is all dirty so can't be used! - if(istype(O, /obj/item/chems/spray/cleaner) || istype(O, /obj/item/chems/glass/rag)) // If they're trying to clean it then let them - user.visible_message( \ - "\The [user] starts to clean the microwave.", \ - "You start to clean the microwave." \ + else if(dirty==100) // The microwave is all dirty so can't be used! + if(istype(used_item, /obj/item/chems/spray/cleaner) || istype(used_item, /obj/item/chems/rag)) // If they're trying to clean it then let them + user.visible_message( + SPAN_NOTICE("\The [user] starts to clean [src]."), + SPAN_NOTICE("You start to clean [src].") ) if (do_after(user, 20, src)) - user.visible_message( \ - "\The [user] has cleaned the microwave.", \ - "You have cleaned the microwave." \ + user.visible_message( + SPAN_NOTICE("\The [user] has cleaned [src]."), + SPAN_NOTICE("You have cleaned [src].") ) - src.dirty = 0 // It's clean! - src.broken = 0 // just to be sure - src.update_icon() - src.atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER + dirty = 0 // It's clean! + broken = 0 // just to be sure + update_icon() + atom_flags = ATOM_FLAG_OPEN_CONTAINER else //Otherwise bad luck!! - to_chat(user, "It's dirty!") + to_chat(user, SPAN_WARNING("It's dirty!")) return 1 - else if(is_type_in_list(O, SScuisine.microwave_accepts_items)) - if (LAZYLEN(ingredients) >= SScuisine.microwave_maximum_item_storage) - to_chat(user, "This [src] is full of ingredients, you cannot put more.") + else if(!istype(used_item, /obj/item/chems/glass/bowl) && (istype(used_item,/obj/item/chems/glass) || istype(used_item,/obj/item/chems/drinks) || istype(used_item,/obj/item/chems/condiment) )) + if (!used_item.reagents) return 1 - if(istype(O, /obj/item/stack)) // This is bad, but I can't think of how to change it - var/obj/item/stack/S = O - if(S.use(1)) - var/stack_item = new O.type (src) - LAZYADD(ingredients, stack_item) - user.visible_message( \ - "\The [user] has added one of [O] to \the [src].", \ - "You add one of [O] to \the [src].") - return + return // transfer is handled in afterattack + else if(IS_WRENCH(used_item)) + user.visible_message( + SPAN_NOTICE("\The [user] begins [anchored ? "securing" : "unsecuring"] [src]."), + SPAN_NOTICE("You attempt to [anchored ? "secure" : "unsecure"] [src].") + ) + if (do_after(user,20, src)) + anchored = !anchored + user.visible_message( + SPAN_NOTICE("\The [user] [anchored ? "secures" : "unsecures"] [src]."), + SPAN_NOTICE("You [anchored ? "secure" : "unsecure"] [src].") + ) else - if (!user.unEquip(O, src)) + to_chat(user, SPAN_NOTICE("You decide not to do that.")) + else if(used_item.w_class <= ITEM_SIZE_LARGE) // this must be last + if (LAZYLEN(get_contained_external_atoms()) >= max_n_of_items) + to_chat(user, SPAN_WARNING("This [src] is full of ingredients, you cannot put more.")) + return 1 + if(istype(used_item, /obj/item/stack)) // This is bad, but I can't think of how to change it + var/obj/item/stack/S = used_item + if(S.get_amount() > 1) + var/obj/item/stack/new_stack = S.split(1) + if(new_stack) + new_stack.forceMove(src) + user.visible_message( + SPAN_NOTICE("\The [user] has added \a [new_stack.singular_name] to \the [src]."), + SPAN_NOTICE("You add one of [used_item] to \the [src].") + ) + SSnano.update_uis(src) return - LAZYADD(ingredients, O) - user.visible_message( \ - "\The [user] has added \the [O] to \the [src].", \ - "You add \the [O] to \the [src].") + if (!user.try_unequip(used_item, src)) return - else if(istype(O,/obj/item/chems/glass) || \ - istype(O,/obj/item/chems/food/drinks) || \ - istype(O,/obj/item/chems/food/condiment) \ + user.visible_message( + SPAN_NOTICE("\The [user] has added \the [used_item] to \the [src]."), + SPAN_NOTICE("You add \the [used_item] to \the [src].") ) - if (!O.reagents) - return 1 - for (var/R in O.reagents.reagent_volumes) - if (!(R in SScuisine.microwave_accepts_reagents)) - to_chat(user, "Your [O] contains components unsuitable for cookery.") - return 1 + SSnano.update_uis(src) return - else if(istype(O,/obj/item/grab)) - var/obj/item/grab/G = O - to_chat(user, "This is ridiculous. You can not fit \the [G.affecting] in this [src].") - return 1 - else if(isWrench(O)) - user.visible_message( \ - "\The [user] begins [src.anchored ? "securing" : "unsecuring"] the microwave.", \ - "You attempt to [src.anchored ? "secure" : "unsecure"] the microwave." - ) - if (do_after(user,20, src)) - src.anchored = !src.anchored - user.visible_message( \ - "\The [user] [src.anchored ? "secures" : "unsecures"] the microwave.", \ - "You [src.anchored ? "secure" : "unsecure"] the microwave." - ) - else - to_chat(user, "You decide not to do that.") else - to_chat(user, "You have no idea what you can cook with this [O].") - src.updateUsrDialog() + to_chat(user, SPAN_WARNING("You have no idea what you can cook with \the [used_item].")) + SSnano.update_uis(src) /obj/machinery/microwave/components_are_accessible(path) return (broken == 0) && ..() @@ -150,255 +164,298 @@ // need physical proximity for our interface. /obj/machinery/microwave/DefaultTopicState() - return GLOB.physical_state + return global.physical_topic_state /obj/machinery/microwave/interface_interact(mob/user) - interact(user) + ui_interact(user) return TRUE /******************* * Microwave Menu ********************/ - -/obj/machinery/microwave/InsertedContents() - return ingredients - -/obj/machinery/microwave/interact(mob/user) // The microwave Menu - user.set_machine(src) - var/dat = list() - if(src.broken > 0) - dat += "Bzzzzttttt" - else if(src.operating) - dat += "Microwaving in progress!
    Please wait...!
    " - else if(src.dirty==100) - dat += "This microwave is dirty!
    Please clean it before use!
    " - else - var/list/items_counts = new - var/list/items_measures = new - var/list/items_measures_p = new - for (var/obj/O in InsertedContents()) - var/display_name = O.name - if (istype(O,/obj/item/chems/food/snacks/egg)) - items_measures[display_name] = "egg" - items_measures_p[display_name] = "eggs" - if (istype(O,/obj/item/chems/food/snacks/tofu)) - items_measures[display_name] = "tofu chunk" - items_measures_p[display_name] = "tofu chunks" - if (istype(O,/obj/item/chems/food/snacks/meat)) //any meat - items_measures[display_name] = "slab of meat" - items_measures_p[display_name] = "slabs of meat" - if (istype(O,/obj/item/chems/food/snacks/donkpocket)) - display_name = "Turnovers" - items_measures[display_name] = "turnover" - items_measures_p[display_name] = "turnovers" - if (istype(O,/obj/item/chems/food/snacks/fish)) - items_measures[display_name] = "fillet of fish" - items_measures_p[display_name] = "fillets of fish" - items_counts[display_name]++ - for (var/O in items_counts) - var/N = items_counts[O] - if (!(O in items_measures)) - dat += "[capitalize(O)]: [N] [lowertext(O)]\s" - else - if (N==1) - dat += "[capitalize(O)]: [N] [items_measures[O]]" - else - dat += "[capitalize(O)]: [N] [items_measures_p[O]]" - - for (var/R in reagents.reagent_volumes) - var/display_name - if (R == /decl/material/liquid/capsaicin) - display_name = "Hotsauce" - if (R == /decl/material/liquid/frostoil) - display_name = "Coldsauce" - else - var/decl/material/reagent = decls_repository.get_decl(R) - display_name = reagent.name - dat += "[display_name]: [REAGENT_VOLUME(reagents, R)] unit\s" - - if (items_counts.len==0 && LAZYLEN(reagents?.reagent_volumes)) - dat += "The microwave is empty" - else - dat += "Ingredients:
    [dat]" - dat += "

    Turn on!
    Eject ingredients!" - - show_browser(user, "Microwave Controls[jointext(dat,"
    ")]
    ", "window=microwave") - onclose(user, "microwave") - return - - +/obj/machinery/microwave/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) + . = ..() + var/data = list() + data["cooking_items"] = list() + for(var/obj/used_item in get_contained_external_atoms()) + data["cooking_items"][used_item.name]++ + data["cooking_reagents"] = list() + var/reagent_volumes = REAGENT_VOLUMES(reagents) + for(var/decl/material/reagent as anything in reagent_volumes) + data["cooking_reagents"][reagent.name] = reagent_volumes[reagent] + data["on"] = !!operating + data["broken"] = broken > 0 + data["dirty"] = dirty >= 100 + data["failed"] = failed + data["start_time"] = start_time + data["cook_time"] = cook_time + data["past_half_time"] = REALTIMEOFDAY >= (start_time + cook_time/2) + // update the ui if it exists, returns null if no ui is passed/found + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "microwave.tmpl", capitalize(name), 300, 300) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + ui.open() /*********************************** * Microwave Menu Handling/Cooking ************************************/ - /obj/machinery/microwave/proc/cook() + cook_break = FALSE + cook_dirty = FALSE + if(stat & (NOPOWER|BROKEN)) return - start() - if (reagents.total_volume==0 && !contents.len) //dry run - if (!wzhzhzh(10)) - abort() - return - stop() + + var/reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if (!reagent_volume && !length(get_contained_external_atoms())) //dry run + start() return - var/datum/recipe/recipe = select_recipe(SScuisine.microwave_recipes, src) - var/obj/cooked + if (reagent_volume && prob(50)) // 50% chance a liquid recipe gets messy + dirty += ceil(reagent_volume / 10) + + var/decl/recipe/recipe = select_recipe(RECIPE_CATEGORY_MICROWAVE, src, cooking_temperature) if (!recipe) - dirty += 1 - if (prob(max(10,dirty*5))) - if (!wzhzhzh(4)) - abort() - return - muck_start() - wzhzhzh(4) - muck_finish() - cooked = fail() - cooked.dropInto(loc) - return + failed = TRUE + cook_time = update_cook_time() + dirty += 5 + if (prob(max(10, dirty*5))) + // It's dirty enough to mess up the microwave + cook_dirty = TRUE else if (has_extra_item()) - if (!wzhzhzh(4)) - abort() - return - broke() - cooked = fail() - cooked.dropInto(loc) - return - else - if (!wzhzhzh(10)) - abort() - return - stop() - cooked = fail() - cooked.dropInto(loc) - return + // Something's in the microwave that shouldn't be! Time to break! + cook_break = TRUE else - var/halftime = round(recipe.time/10/2) - if (!wzhzhzh(halftime)) - abort() - return - if (!wzhzhzh(halftime)) - abort() - cooked = fail() - cooked.dropInto(loc) - return - cooked = recipe.make_food(src) - LAZYCLEARLIST(ingredients) + failed = FALSE + cook_time = update_cook_time(round(recipe.cooking_time * 2)) + + start() + +/obj/machinery/microwave/proc/update_cook_time(var/ct = 200) + return (ct / cooking_power) + +/obj/machinery/microwave/proc/finish_cooking() + var/decl/recipe/recipe = select_recipe(RECIPE_CATEGORY_MICROWAVE, src, cooking_temperature) + if(!recipe) + return + var/result = recipe.result + var/list/cooked_items = list() + while(recipe) + try + cooked_items += recipe.produce_result(src) + recipe = select_recipe(RECIPE_CATEGORY_MICROWAVE, src, cooking_temperature) + if (!recipe || (recipe.result != result)) + break + catch(var/exception/E) + PRINT_STACK_TRACE("Runtime when processing microwave recipe spawn: [EXCEPTION_TEXT(E)]") + break + + //Any leftover reagents are divided amongst the foods + var/total = REAGENT_TOTAL_VOLUME(reagents) + for (var/obj/item/I in cooked_items) + reagents.trans_to_holder(I.reagents, total/cooked_items.len) + I.dropInto(loc) // since eject only ejects ingredients! + + dispose(message = FALSE) //clear out anything left + + return + +/obj/machinery/microwave/Process() // What you see here are the remains of proc/wzhzhzh, 2011 - 2021. RIP. + if (!operating || stat & (NOPOWER|BROKEN) || (REALTIMEOFDAY > end_time)) stop() - if(cooked) - cooked.dropInto(loc) + +/obj/machinery/microwave/proc/half_time_process() + if (!operating || stat & (NOPOWER|BROKEN)) return -// Behold: the worst proc name in the codebase. -/obj/machinery/microwave/proc/wzhzhzh(var/seconds) - for (var/i=1 to seconds) - if (stat & (NOPOWER|BROKEN)) - return 0 - use_power_oneoff(500) - sleep(10) - return 1 + playsound(src, 'sound/machines/click.ogg', 20, 1) + + if(failed) + visible_message(SPAN_WARNING("\The [src] begins to leak an acrid smoke...")) + + SSnano.update_uis(src) /obj/machinery/microwave/proc/has_extra_item() - for (var/obj/O in ingredients) // do not use src or src.contents unless you want to cook your own components - if (!istype(O,/obj/item/chems/food) && !istype(O, /obj/item/grown)) - return 1 - return 0 + for(var/obj/thing in get_contained_external_atoms()) + if(!istype(thing,/obj/item/food)) + return TRUE + return FALSE /obj/machinery/microwave/proc/start() - src.visible_message("The microwave turns on.", "You hear a microwave.") - src.operating = 1 - src.updateUsrDialog() - src.update_icon() - -/obj/machinery/microwave/proc/abort() - src.operating = 0 // Turn it off again aferwards - src.updateUsrDialog() - src.update_icon() - -/obj/machinery/microwave/proc/stop() - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) - src.operating = 0 // Turn it off again aferwards - src.updateUsrDialog() - src.update_icon() - -/obj/machinery/microwave/proc/dispose() - if (!LAZYLEN(ingredients) && !reagents.total_volume) + start_time = REALTIMEOFDAY + end_time = cook_time + start_time + operating = TRUE + update_use_power(POWER_USE_ACTIVE) + + START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + addtimer(CALLBACK(src, PROC_REF(half_time_process)), cook_time / 2) + visible_message(SPAN_NOTICE("[src] turns on."), SPAN_NOTICE("You hear a microwave.")) + + if(cook_dirty) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) // Play a splat sound + icon_state = "mwbloody1" // Make it look dirty!! + else + icon_state = "mw1" + + set_light(1, 1.5) + soundloop.start(src) + update_icon() + SSnano.update_uis(src) + +/obj/machinery/microwave/proc/after_finish_loop() + set_light(0) + soundloop.stop(src) + update_icon() + +/obj/machinery/microwave/proc/stop(var/abort = FALSE) + STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + after_finish_loop() + + update_use_power(POWER_USE_OFF) + operating = FALSE // Turn it off again aferwards + if(cook_dirty || cook_break) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER //So you can't add condiments + if(cook_dirty) + visible_message(SPAN_WARNING("The insides of [src] get covered in muck!")) + dirty = 100 // Make it dirty so it can't be used util cleaned + icon_state = "mwbloody0" // Make it look dirty too + else if(cook_break) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, global.alldirs, src) + icon_state = "mwb" // Make it look all busted up and shit + visible_message(SPAN_WARNING("[src] sprays out a shower of sparks - it's broken!")) //Let them know they're stupid + broken = 2 // Make it broken so it can't be used until fixed + else + icon_state = "mw" + + cook_dirty = FALSE + cook_break = FALSE + + if(failed) + fail() + failed = FALSE + else if(!abort) + finish_cooking() + + SSnano.update_uis(src) + +/obj/machinery/microwave/on_reagent_change() + if((. = ..()) && !operating) + SSnano.update_uis(src) + +/obj/machinery/microwave/proc/dispose(var/mob/user, var/message = TRUE) + var/list/ingredients = get_contained_external_atoms() + var/reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if (!LAZYLEN(ingredients) && !reagent_volume) return - for (var/obj/O in ingredients) - O.dropInto(loc) - LAZYCLEARLIST(ingredients) - if (src.reagents.total_volume) - src.dirty++ - src.reagents.clear_reagents() - to_chat(usr, "You dispose of the microwave contents.") - src.updateUsrDialog() - -/obj/machinery/microwave/proc/muck_start() - playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) // Play a splat sound - src.update_icon() - -/obj/machinery/microwave/proc/muck_finish() - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) - src.visible_message("The microwave gets covered in muck!") - src.dirty = 100 // Make it dirty so it can't be used util cleaned - src.obj_flags = null //So you can't add condiments - src.operating = 0 // Turn it off again aferwards - src.updateUsrDialog() - src.update_icon() - -/obj/machinery/microwave/proc/broke() - var/datum/effect/effect/system/spark_spread/s = new - s.set_up(2, 1, src) - s.start() - src.visible_message("The microwave breaks!") //Let them know they're stupid - src.broken = 2 // Make it broken so it can't be used util fixed - src.obj_flags = null //So you can't add condiments - src.operating = 0 // Turn it off again aferwards - src.updateUsrDialog() - src.update_icon() + for (var/obj/thing in ingredients) + thing.dropInto(loc) + if (reagent_volume) + dirty++ + reagents.clear_reagents() + if(user && message) + to_chat(user, SPAN_NOTICE("You empty [src].")) + SSnano.update_uis(src) + +/obj/machinery/microwave/proc/eject_item(var/mob/user, var/obj/thing, var/message = TRUE) + if(!istype(thing) || !length(get_contained_external_atoms())) + return + thing.dropInto(loc) + if(user && message) + to_chat(user, SPAN_NOTICE("You remove [thing] from [src].")) + SSnano.update_uis(src) + +/obj/machinery/microwave/proc/eject_reagent(var/mob/user, var/decl/material/reagent) + if(!REAGENT_VOLUME(reagents, reagent)) + SSnano.update_uis(src) + return // should not happen, must be a UI glitch or href hacking + var/obj/item/chems/held_container = user.get_active_held_item() + if(istype(held_container)) + var/amount_to_move = min(REAGENTS_FREE_SPACE(held_container.reagents), REAGENT_VOLUME(reagents, reagent)) + if(amount_to_move <= 0) + to_chat(user, SPAN_WARNING("[held_container] is full!")) + return + to_chat(user, SPAN_NOTICE("You empty [amount_to_move] units of [reagent.name] into [held_container].")) + reagents.trans_type_to(held_container, reagent, amount_to_move) + else + to_chat(user, SPAN_NOTICE("You try to dump out the [reagent.name], but it gets all over [src] because you have nothing to put it in.")) + dirty++ + reagents.clear_reagent(reagent) + SSnano.update_uis(src) /obj/machinery/microwave/on_update_icon() if(dirty == 100) - src.icon_state = "mwbloody[operating]" + icon_state = "mwbloody[operating]" else if(broken) - src.icon_state = "mwb" + icon_state = "mwb" else - src.icon_state = "mw[operating]" + icon_state = "mw[operating]" /obj/machinery/microwave/proc/fail() + failed = TRUE var/amount = 0 - + var/list/ingredients = get_contained_external_atoms() // Kill + delete mobs in mob holders for (var/obj/item/holder/H in ingredients) for (var/mob/living/M in H.contents) M.death() qdel(M) - for (var/obj/O in ingredients) + for (var/obj/thing in ingredients) amount++ - if (O.reagents && O.reagents.primary_reagent) - amount += REAGENT_VOLUME(O.reagents, O.reagents.primary_reagent) - qdel(O) - LAZYCLEARLIST(ingredients) - src.reagents.clear_reagents() - var/obj/item/chems/food/snacks/badrecipe/ffuu = new(src) - ffuu.reagents.add_reagent(/decl/material/solid/carbon, amount) - ffuu.reagents.add_reagent(/decl/material/liquid/bromide, amount/10) + var/thing_reagent = istype(thing.reagents) && thing.reagents.get_primary_reagent_decl() + if (thing_reagent) + amount += REAGENT_VOLUME(thing.reagents, thing_reagent) + qdel(thing) + reagents.clear_reagents() + SSnano.update_uis(src) + var/obj/item/food/badrecipe/ffuu = new(src) + ffuu.add_to_reagents(/decl/material/solid/carbon, amount) + ffuu.add_to_reagents(/decl/material/liquid/acrylamide, amount/10) return ffuu -/obj/machinery/microwave/Topic(href, href_list) - if(..()) - return 1 - - usr.set_machine(src) - if(src.operating) - src.updateUsrDialog() - return - +/obj/machinery/microwave/OnTopic(mob/user, href_list) switch(href_list["action"]) if ("cook") cook() + return TOPIC_REFRESH if ("dispose") - dispose() + dispose(user) + return TOPIC_REFRESH + + if ("ejectitem") + for(var/obj/thing in get_contained_external_atoms()) + if(strip_improper(thing.name) == href_list["target"]) + eject_item(user, thing) + break + return TOPIC_REFRESH + + if ("ejectreagent") + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.name == href_list["target"]) + eject_reagent(user, reagent) + break + return TOPIC_REFRESH + + if ("abort") + stop(abort = TRUE) + return TOPIC_REFRESH + +/obj/machinery/microwave/RefreshParts() + ..() + var/bin_rating = 0 // 2 + var/cap_rating = 0 // 3 + var/las_rating = 0 // 1 + + bin_rating = total_component_rating_of_type(/obj/item/stock_parts/matter_bin) + cap_rating = total_component_rating_of_type(/obj/item/stock_parts/capacitor) + las_rating = total_component_rating_of_type(/obj/item/stock_parts/micro_laser) + + change_power_consumption(initial(active_power_usage) - (cap_rating * 25), POWER_USE_ACTIVE) + max_n_of_items = initial(max_n_of_items) + floor(bin_rating) + cooking_power = initial(cooking_power) + (las_rating / 3) diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm deleted file mode 100644 index d7d4f560794a..000000000000 --- a/code/game/machinery/kitchen/smartfridge.dm +++ /dev/null @@ -1,399 +0,0 @@ - -/* SmartFridge. Much todo -*/ -/obj/machinery/smartfridge - name = "\improper SmartFridge" - icon = 'icons/obj/vending.dmi' - icon_state = "fridge_sci" - layer = BELOW_OBJ_LAYER - density = 1 - anchored = 1 - idle_power_usage = 5 - active_power_usage = 100 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_REACT - atmos_canpass = CANPASS_NEVER - var/global/max_n_of_items = 999 // Sorry but the BYOND infinite loop detector doesn't look things over 1000. - var/icon_base = "fridge_sci" - var/icon_contents = "chem" - var/list/item_records = list() - var/datum/stored_items/currently_vending = null //What we're putting out of the machine. - var/seconds_electrified = 0; - var/shoot_inventory = 0 - var/locked = 0 - var/scan_id = 1 - var/is_secure = 0 - - construct_state = /decl/machine_construction/default/panel_closed - uncreated_component_parts = null - stat_immune = 0 - -/obj/machinery/smartfridge/secure - is_secure = 1 - -/obj/machinery/smartfridge/Initialize() - if(is_secure) - wires = new/datum/wires/smartfridge/secure(src) - else - wires = new/datum/wires/smartfridge(src) - . = ..() - queue_icon_update() - -/obj/machinery/smartfridge/Destroy() - for(var/datum/stored_items/S in item_records) - qdel(S) - item_records = null - return ..() - -/obj/machinery/smartfridge/get_req_access() - if(!scan_id) - return list() - return ..() - -/obj/machinery/smartfridge/proc/accept_check(var/obj/item/O) - if(istype(O,/obj/item/chems/food/snacks/grown/) || istype(O,/obj/item/seeds/)) - return 1 - return 0 - -/obj/machinery/smartfridge/seeds - name = "\improper MegaSeed Servitor" - desc = "When you need seeds fast!" - -/obj/machinery/smartfridge/seeds/accept_check(var/obj/item/O) - if(istype(O,/obj/item/seeds/)) - return 1 - return 0 - -/obj/machinery/smartfridge/secure/extract - name = "\improper Slime Extract Storage" - desc = "A refrigerated storage unit for slime extracts." - icon_contents = "slime" - initial_access = list(access_research) - -/obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O) - if(istype(O,/obj/item/slime_extract)) - return 1 - return 0 - -/obj/machinery/smartfridge/secure/medbay - name = "\improper Refrigerated Medicine Storage" - desc = "A refrigerated storage unit for storing medicine and chemicals." - icon_contents = "chem" - initial_access = list(list(access_medical, access_chemistry)) - -/obj/machinery/smartfridge/secure/medbay/accept_check(var/obj/item/O) - if(istype(O,/obj/item/chems/glass/)) - return 1 - if(istype(O,/obj/item/storage/pill_bottle/)) - return 1 - if(istype(O,/obj/item/chems/pill/)) - return 1 - return 0 - -/obj/machinery/smartfridge/chemistry - name = "\improper Smart Chemical Storage" - desc = "A refrigerated storage unit for medicine and chemical storage." - icon_contents = "chem" - -/obj/machinery/smartfridge/chemistry/accept_check(var/obj/item/O) - if(istype(O,/obj/item/storage/pill_bottle) || istype(O,/obj/item/chems)) - return 1 - return 0 - -/obj/machinery/smartfridge/drinks - name = "\improper Drink Showcase" - desc = "A refrigerated storage unit for tasty tasty alcohol." - icon_state = "fridge_dark" - icon_base = "fridge_dark" - icon_contents = "drink" - -/obj/machinery/smartfridge/drinks/accept_check(var/obj/item/O) - if(istype(O,/obj/item/chems/glass) || istype(O,/obj/item/chems/food/drinks) || istype(O,/obj/item/chems/food/condiment)) - return 1 - -/obj/machinery/smartfridge/foods - name = "\improper Hot Foods Display" - desc = "A heated storage unit for piping hot meals." - icon_state = "fridge_food" - icon_state = "fridge_food" - icon_contents = "food" - -/obj/machinery/smartfridge/foods/accept_check(var/obj/item/O) - if(istype(O,/obj/item/chems/food/snacks) || istype(O,/obj/item/kitchen/utensil)) - return 1 - -/obj/machinery/smartfridge/drying_rack - name = "drying rack" - desc = "A machine for drying plants." - icon_state = "drying_rack" - -/obj/machinery/smartfridge/drying_rack/accept_check(var/obj/item/O) - if(istype(O, /obj/item/chems/food/snacks/)) - var/obj/item/chems/food/snacks/S = O - return S.dried_type - else if(istype(O, /obj/item/stack/material)) - return istype(O.material, /decl/material/solid/skin) - return 0 - -/obj/machinery/smartfridge/drying_rack/Process() - ..() - if(inoperable()) - return - if(contents.len) - dry() - update_icon() - -/obj/machinery/smartfridge/drying_rack/on_update_icon() - overlays.Cut() - if(inoperable()) - if(contents.len) - icon_state = "drying_rack-plant-off" - else - icon_state = "drying_rack-off" - else - icon_state = "drying_rack" - if(contents.len) - icon_state = "drying_rack-plant" - if(!inoperable()) - icon_state = "drying_rack-close" - -/obj/machinery/smartfridge/drying_rack/proc/dry() - for(var/datum/stored_items/I in item_records) - for(var/thing in I.instances) - var/remove_thing = FALSE - if(istype(thing, /obj/item/chems/food/snacks)) - var/obj/item/chems/food/snacks/S = thing - if(S.dry || !I.get_specific_product(get_turf(src), S)) - continue - if(S.dried_type == S.type) - S.dry = 1 - S.SetName("dried [S.name]") - S.color = "#a38463" - stock_item(S) - I.instances -= thing - I.amount-- - else - var/D = S.dried_type - new D(get_turf(src)) - remove_thing = TRUE - - else if(istype(thing, /obj/item/stack/material)) - var/obj/item/stack/material/skin = thing - if(!istype(skin.material, /decl/material/solid/skin)) - continue - var/decl/material/solid/skin/skin_mat = skin.material - if(!skin_mat.tans_to) - continue - var/decl/material/leather_mat = decls_repository.get_decl(skin_mat.tans_to) - stock_item(new leather_mat.stack_type(get_turf(src), skin.amount, skin_mat.tans_to)) - remove_thing = TRUE - - if(remove_thing) - I.instances -= thing - I.amount-- - qdel(thing) - return - - -/obj/machinery/smartfridge/Process() - if(stat & (BROKEN|NOPOWER)) - return - if(src.seconds_electrified > 0) - src.seconds_electrified-- - if(src.shoot_inventory && prob(2)) - src.throw_item() - -/obj/machinery/smartfridge/on_update_icon() - overlays.Cut() - if(stat & (BROKEN|NOPOWER)) - icon_state = "[icon_base]-off" - else - icon_state = icon_base - - if(is_secure) - overlays += image(icon, "[icon_base]-sidepanel") - - if(panel_open) - overlays += image(icon, "[icon_base]-panel") - - var/image/I - var/is_off = "" - if(inoperable()) - is_off = "-off" - - // Fridge contents - switch(contents.len - LAZYLEN(component_parts)) - if(0) - I = image(icon, "empty[is_off]") - if(1 to 2) - I = image(icon, "[icon_contents]-1[is_off]") - if(3 to 5) - I = image(icon, "[icon_contents]-2[is_off]") - if(6 to 8) - I = image(icon, "[icon_contents]-3[is_off]") - else - I = image(icon, "[icon_contents]-4[is_off]") - overlays += I - - // Fridge top - I = image(icon, "[icon_base]-top") - I.pixel_z = 32 - I.layer = ABOVE_WINDOW_LAYER - overlays += I - -/obj/machinery/smartfridge/dismantle() - for(var/datum/stored_items/I in item_records) - while(I.amount > 0) - I.get_product(get_turf(src)) // They'd get dumped anyway, but this makes things GC properly. - ..() - -/******************* -* Item Adding -********************/ - -/obj/machinery/smartfridge/state_transition(decl/machine_construction/new_state, mob/user) - . = ..() - update_icon() - -/obj/machinery/smartfridge/attackby(var/obj/item/O, var/mob/user) - if(stat & NOPOWER) - to_chat(user, "\The [src] is unpowered and useless.") - return - - if(accept_check(O)) - if(!user.unEquip(O)) - return - stock_item(O) - user.visible_message("\The [user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") - update_icon() - - else if(istype(O, /obj/item/storage)) - var/obj/item/storage/bag/P = O - var/plants_loaded = 0 - for(var/obj/G in P.contents) - if(accept_check(G) && P.remove_from_storage(G, src, 1)) - plants_loaded++ - stock_item(G) - P.finish_bulk_removal() - - if(plants_loaded) - user.visible_message("\The [user] loads \the [src] with the contents of \the [P].", "You load \the [src] with the contents of \the [P].") - if(P.contents.len > 0) - to_chat(user, "Some items were refused.") - - else - to_chat(user, "\The [src] smartly refuses [O].") - return 1 - -/obj/machinery/smartfridge/secure/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) - emagged = 1 - locked = -1 - req_access.Cut() - to_chat(user, "You short out the product lock on [src].") - return 1 - -/obj/machinery/smartfridge/proc/stock_item(var/obj/item/O) - for(var/datum/stored_items/I in item_records) - if(istype(O, I.item_path) && O.name == I.item_name) - stock(I, O) - return - - var/datum/stored_items/I = new/datum/stored_items(src, O.type, O.name) - dd_insertObjectList(item_records, I) - stock(I, O) - -/obj/machinery/smartfridge/proc/stock(var/datum/stored_items/I, var/obj/item/O) - I.add_product(O) - SSnano.update_uis(src) - -/obj/machinery/smartfridge/interface_interact(mob/user) - ui_interact(user) - return TRUE - -/******************* -* SmartFridge Menu -********************/ - -/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/data[0] - data["contents"] = null - data["electrified"] = seconds_electrified > 0 - data["shoot_inventory"] = shoot_inventory - data["locked"] = locked - data["secure"] = is_secure - - var/list/items[0] - for (var/i=1 to length(item_records)) - var/datum/stored_items/I = item_records[i] - var/count = I.get_amount() - if(count > 0) - items.Add(list(list("display_name" = html_encode(capitalize(I.item_name)), "vend" = i, "quantity" = count))) - - if(items.len > 0) - data["contents"] = items - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "smartfridge.tmpl", src.name, 400, 500) - ui.set_initial_data(data) - ui.open() - -/obj/machinery/smartfridge/Topic(href, href_list) - if(..()) return 0 - - var/mob/user = usr - var/datum/nanoui/ui = SSnano.get_open_ui(user, src, "main") - - if(href_list["close"]) - user.unset_machine() - ui.close() - return 0 - - if(href_list["vend"]) - var/index = text2num(href_list["vend"]) - var/amount = text2num(href_list["amount"]) - var/datum/stored_items/I = item_records[index] - var/count = I.get_amount() - - // Sanity check, there are probably ways to press the button when it shouldn't be possible. - if(count > 0) - if((count - amount) < 0) - amount = count - for(var/i = 1 to amount) - I.get_product(get_turf(src)) - update_icon() - - return 1 - return 0 - -/obj/machinery/smartfridge/proc/throw_item() - var/obj/throw_item = null - var/mob/living/target = locate() in view(7,src) - if(!target) - return 0 - - for(var/datum/stored_items/I in src.item_records) - throw_item = I.get_product(loc) - if (!throw_item) - continue - break - - if(!throw_item) - return 0 - spawn(0) - throw_item.throw_at(target,16,3) - src.visible_message("[src] launches [throw_item.name] at [target.name]!") - update_icon() - return 1 - -/************************ -* Secure SmartFridges -*************************/ - -/obj/machinery/smartfridge/secure/CanUseTopic(mob/user, datum/topic_state/state, href_list) - if(!allowed(user) && !emagged && locked != -1 && href_list && href_list["vend"] && scan_id) - to_chat(user, "Access denied.") - return STATUS_CLOSE - return ..() \ No newline at end of file diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm deleted file mode 100644 index 3802c5968987..000000000000 --- a/code/game/machinery/lightswitch.dm +++ /dev/null @@ -1,83 +0,0 @@ -// the light switch -// can have multiple per area -// can also operate on non-loc area through "otherarea" var -/obj/machinery/light_switch - name = "light switch" - desc = "It turns lights on and off. What are you, simple?" - icon = 'icons/obj/power.dmi' - icon_state = "light0" - anchored = 1.0 - idle_power_usage = 20 - power_channel = LIGHT - var/on = 0 - var/area/connected_area = null - var/other_area = null - var/image/overlay - - construct_state = /decl/machine_construction/wall_frame/panel_closed/simple - frame_type = /obj/item/frame/button/light_switch - uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable - ) - base_type = /obj/machinery/light_switch/buildable - -/obj/machinery/light_switch/buildable - uncreated_component_parts = null - -/obj/machinery/light_switch/on - on = TRUE - -/obj/machinery/light_switch/Initialize() - ..() - if(other_area) - connected_area = locate(other_area) - else - connected_area = get_area(src) - - if(connected_area && name == initial(name)) - SetName("light switch ([connected_area.name])") - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/light_switch/LateInitialize() - . = ..() - connected_area?.set_lightswitch(on) - update_icon() - -/obj/machinery/light_switch/on_update_icon() - if(!overlay) - overlay = image(icon, "light1-overlay") - overlay.plane = EFFECTS_ABOVE_LIGHTING_PLANE - overlay.layer = ABOVE_LIGHTING_LAYER - - overlays.Cut() - if(stat & (NOPOWER|BROKEN)) - icon_state = "light-p" - set_light(0) - else - icon_state = "light[on]" - overlay.icon_state = "light[on]-overlay" - overlays += overlay - set_light(0.1, 0.1, 1, 2, on ? "#82ff4c" : "#f86060") - -/obj/machinery/light_switch/examine(mob/user, distance) - . = ..() - if(distance) - to_chat(user, "A light switch. It is [on? "on" : "off"].") - -/obj/machinery/light_switch/proc/set_state(var/newstate) - if(on != newstate) - on = newstate - connected_area.set_lightswitch(on) - update_icon() - -/obj/machinery/light_switch/proc/sync_state() - if(connected_area && on != connected_area.lightswitch) - on = connected_area.lightswitch - update_icon() - return 1 - -/obj/machinery/light_switch/interface_interact(mob/user) - if(CanInteract(user, DefaultTopicState())) - playsound(src, "switch", 30) - set_state(!on) - return TRUE \ No newline at end of file diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm deleted file mode 100644 index c250353e079e..000000000000 --- a/code/game/machinery/magnet.dm +++ /dev/null @@ -1,390 +0,0 @@ -// Magnetic attractor, creates variable magnetic fields and attraction. -// Can also be used to emit electron/proton beams to create a center of magnetism on another tile - -// tl;dr: it's magnets lol -// This was created for firing ranges, but I suppose this could have other applications - Doohl - -/obj/machinery/magnetic_module - - icon = 'icons/obj/objects.dmi' - icon_state = "floor_magnet-f" - name = "Electromagnetic Generator" - desc = "A device that uses powernet to create points of magnetic energy." - level = 1 // underfloor - layer = ABOVE_WIRE_LAYER - anchored = 1 - idle_power_usage = 50 - - var/freq = 1449 // radio frequency - var/electricity_level = 1 // intensity of the magnetic pull - var/magnetic_field = 1 // the range of magnetic attraction - var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something - var/turf/center // the center of magnetic attraction - var/on = 0 - var/pulling = 0 - - // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down - var/center_x = 0 - var/center_y = 0 - var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer - -/obj/machinery/magnetic_module/Initialize() - . = ..() - var/turf/T = loc - hide(!T.is_plating()) - center = T - - if(radio_controller) - radio_controller.add_object(src, freq, RADIO_MAGNETS) - - magnetic_process() - - // update the invisibility and icon -/obj/machinery/magnetic_module/hide(var/intact) - set_invisibility(intact ? 101 : 0) - update_icon() - - // update the icon_state -/obj/machinery/magnetic_module/on_update_icon() - var/state="floor_magnet" - var/onstate="" - if(!on) - onstate="0" - - if(invisibility) - icon_state = "[state][onstate]-f" // if invisible, set icon to faded version - // in case of being revealed by T-scanner - else - icon_state = "[state][onstate]" - -/obj/machinery/magnetic_module/receive_signal(datum/signal/signal) - - var/command = signal.data["command"] - var/modifier = signal.data["modifier"] - var/signal_code = signal.data["code"] - if(command && (signal_code == code)) - - Cmd(command, modifier) - - - -/obj/machinery/magnetic_module/proc/Cmd(var/command, var/modifier) - - if(command) - switch(command) - if("set-electriclevel") - if(modifier) electricity_level = modifier - if("set-magneticfield") - if(modifier) magnetic_field = modifier - - if("add-elec") - electricity_level++ - if(electricity_level > 12) - electricity_level = 12 - if("sub-elec") - electricity_level-- - if(electricity_level <= 0) - electricity_level = 1 - if("add-mag") - magnetic_field++ - if(magnetic_field > 4) - magnetic_field = 4 - if("sub-mag") - magnetic_field-- - if(magnetic_field <= 0) - magnetic_field = 1 - - if("set-x") - if(modifier) center_x = modifier - if("set-y") - if(modifier) center_y = modifier - - if("N") // NORTH - center_y++ - if("S") // SOUTH - center_y-- - if("E") // EAST - center_x++ - if("W") // WEST - center_x-- - if("C") // CENTER - center_x = 0 - center_y = 0 - if("R") // RANDOM - center_x = rand(-max_dist, max_dist) - center_y = rand(-max_dist, max_dist) - - if("set-code") - if(modifier) code = modifier - if("toggle-power") - on = !on - - if(on) - spawn() - magnetic_process() - - - -/obj/machinery/magnetic_module/Process() - if(stat & NOPOWER) - on = 0 - - // Sanity checks: - if(electricity_level <= 0) - electricity_level = 1 - if(magnetic_field <= 0) - magnetic_field = 1 - - - // Limitations: - if(abs(center_x) > max_dist) - center_x = max_dist - if(abs(center_y) > max_dist) - center_y = max_dist - if(magnetic_field > 4) - magnetic_field = 4 - if(electricity_level > 12) - electricity_level = 12 - - // Update power usage: - if(on) - update_use_power(POWER_USE_ACTIVE) - change_power_consumption(electricity_level*15, POWER_USE_ACTIVE) - else - update_use_power(POWER_USE_IDLE) - - update_icon() - - -/obj/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling - set waitfor = FALSE - if(pulling) return - while(on) - - pulling = 1 - center = locate(x+center_x, y+center_y, z) - if(center) - for(var/obj/M in orange(magnetic_field, center)) - if(!M.anchored && (M.obj_flags & OBJ_FLAG_CONDUCTIBLE)) - step_towards(M, center) - - for(var/mob/living/silicon/S in orange(magnetic_field, center)) - if(istype(S, /mob/living/silicon/ai)) continue - step_towards(S, center) - - use_power_oneoff(electricity_level * 5) - sleep(13 - electricity_level) - - pulling = 0 - -/obj/machinery/magnetic_module/Destroy() - if(radio_controller) - radio_controller.remove_object(src, freq) - return ..() - -/obj/machinery/magnetic_controller - name = "Magnetic Control Console" - icon = 'icons/obj/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING! - icon_state = "airlock_control_standby" - density = 1 - anchored = 1.0 - idle_power_usage = 45 - var/frequency = 1449 - var/code = 0 - var/list/magnets = list() - var/title = "Magnetic Control Console" - var/autolink = 0 // if set to 1, can't probe for other magnets! - - var/pathpos = 1 // position in the path - var/path = "NULL" // text path of the magnet - var/speed = 1 // lowest = 1, highest = 10 - var/list/rpath = list() // real path of the magnet, used in iterator - - var/moving = 0 // 1 if scheduled to loop - var/looping = 0 // 1 if looping - - var/datum/radio_frequency/radio_connection - - -/obj/machinery/magnetic_controller/Initialize() - . = ..() - if(autolink) - for(var/obj/machinery/magnetic_module/M in world) - if(M.freq == frequency && M.code == code) - magnets.Add(M) - - if(radio_controller) - radio_connection = radio_controller.add_object(src, frequency, RADIO_MAGNETS) - - if(path) // check for default path - filter_path() // renders rpath - - -/obj/machinery/magnetic_controller/Process() - if(magnets.len == 0 && autolink) - for(var/obj/machinery/magnetic_module/M in world) - if(M.freq == frequency && M.code == code) - magnets.Add(M) - -/obj/machinery/magnetic_controller/interface_interact(user) - interact(user) - return TRUE - -/obj/machinery/magnetic_controller/interact(mob/user) - if(stat & (BROKEN|NOPOWER)) - return - user.set_machine(src) - var/dat = "Magnetic Control Console

    " - if(!autolink) - dat += {" - Frequency:
    [frequency]
    - Code: [code]
    - Probe Generators
    - "} - - if(magnets.len >= 1) - - dat += "Magnets confirmed:
    " - var/i = 0 - for(var/obj/machinery/magnetic_module/M in magnets) - i++ - dat += "     < \[[i]\] ([M.on ? "On":"Off"]) | Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] +
    " - - dat += "
    Speed: - [speed] +
    " - dat += "Path: {[path]}
    " - dat += "Moving: [moving ? "Enabled":"Disabled"]" - - - show_browser(user, dat, "window=magnet;size=400x500") - onclose(user, "magnet") - -/obj/machinery/magnetic_controller/Topic(href, href_list) - if(..()) - return 1 - if(stat & (BROKEN|NOPOWER)) - return - usr.set_machine(src) - - if(href_list["radio-op"]) - - // Prepare signal beforehand, because this is a radio operation - var/datum/signal/signal = new - signal.transmission_method = 1 // radio transmission - signal.source = src - signal.frequency = frequency - signal.data["code"] = code - - // Apply any necessary commands - switch(href_list["radio-op"]) - if("togglepower") - signal.data["command"] = "toggle-power" - - if("minuselec") - signal.data["command"] = "sub-elec" - if("pluselec") - signal.data["command"] = "add-elec" - - if("minusmag") - signal.data["command"] = "sub-mag" - if("plusmag") - signal.data["command"] = "add-mag" - - - // Broadcast the signal - - radio_connection.post_signal(src, signal, radio_filter = RADIO_MAGNETS) - - spawn(1) - updateUsrDialog() // pretty sure this increases responsiveness - - if(href_list["operation"]) - switch(href_list["operation"]) - if("plusspeed") - speed ++ - if(speed > 10) - speed = 10 - if("minusspeed") - speed -- - if(speed <= 0) - speed = 1 - if("setpath") - var/newpath = sanitize(input(usr, "Please define a new path!",,path) as text|null) - if(newpath && newpath != "") - moving = 0 // stop moving - path = newpath - pathpos = 1 // reset position - filter_path() // renders rpath - - if("togglemoving") - moving = !moving - if(moving) - spawn() MagnetMove() - - - updateUsrDialog() - -/obj/machinery/magnetic_controller/proc/MagnetMove() - if(looping) return - - while(moving && rpath.len >= 1) - - if(stat & (BROKEN|NOPOWER)) - break - - looping = 1 - - // Prepare the radio signal - var/datum/signal/signal = new - signal.transmission_method = 1 // radio transmission - signal.source = src - signal.frequency = frequency - signal.data["code"] = code - - if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list! - pathpos = 1 - - var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive - - if(!(nextmove in list("N","S","E","W","C","R"))) - // N, S, E, W are directional - // C is center - // R is random (in magnetic field's bounds) - qdel(signal) - break // break the loop if the character located is invalid - - signal.data["command"] = nextmove - - - pathpos++ // increase iterator - - // Broadcast the signal - spawn() - radio_connection.post_signal(src, signal, radio_filter = RADIO_MAGNETS) - - if(speed == 10) - sleep(1) - else - sleep(12-speed) - - looping = 0 - - -/obj/machinery/magnetic_controller/proc/filter_path() - // Generates the rpath variable using the path string, think of this as "string2list" - // Doesn't use params2list() because of the akward way it stacks entities - rpath = list() // clear rpath - var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length - - for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path - - var/nextchar = copytext(path, i, i+1) // find next character - - if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore - rpath += copytext(path, i, i+1) // else, add to list - - // there doesn't HAVE to be separators but it makes paths syntatically visible - -/obj/machinery/magnetic_controller/Destroy() - if(radio_controller) - radio_controller.remove_object(src, frequency) - return ..() \ No newline at end of file diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index c85963b94633..cc4014b6eaab 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -5,12 +5,11 @@ desc = "Shoots things into space." icon = 'icons/obj/machines/massdriver.dmi' icon_state = "mass_driver" - anchored = 1.0 + anchored = TRUE idle_power_usage = 2 active_power_usage = 50 var/power = 1.0 - var/code = 1.0 var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. uncreated_component_parts = list( @@ -33,8 +32,7 @@ if(!O.anchored) O_limit++ if(O_limit >= 20) - for(var/mob/M in hearers(src, null)) - to_chat(M, "The mass driver lets out a screech, it mustn't be able to handle any more items.") + visible_message(SPAN_NOTICE("\The [src] lets out a mechanical groan and refuses to budge!")) break use_power_oneoff(500) spawn( 0 ) @@ -57,12 +55,12 @@ /decl/public_access/public_method/driver_drive name = "launch" desc = "Makes the mass driver launch immediately" - call_proc = /obj/machinery/mass_driver/proc/drive + call_proc = TYPE_PROC_REF(/obj/machinery/mass_driver, drive) /decl/public_access/public_method/driver_drive_delayed name = "delayed launch" desc = "Makes the mass driver launch after a short delay" - call_proc = /obj/machinery/mass_driver/proc/delayed_drive + call_proc = TYPE_PROC_REF(/obj/machinery/mass_driver, delayed_drive) /decl/stock_part_preset/radio/receiver/driver frequency = BLAST_DOORS_FREQ diff --git a/code/game/machinery/mech_recharger.dm b/code/game/machinery/mech_recharger.dm index 8a8a988ff97c..08629aece6a2 100644 --- a/code/game/machinery/mech_recharger.dm +++ b/code/game/machinery/mech_recharger.dm @@ -1,31 +1,31 @@ /obj/machinery/mech_recharger name = "exosuit dock" - desc = "A exosuit recharger, built into the floor." + desc = "An exosuit recharger, built into the floor." icon = 'icons/mecha/mech_bay.dmi' icon_state = "recharge_floor" - density = 0 + density = FALSE layer = ABOVE_TILE_LAYER - anchored = 1 + anchored = TRUE idle_power_usage = 200 // Some electronics, passive drain. active_power_usage = 60 KILOWATTS // When charging base_type = /obj/machinery/mech_recharger construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 var/mob/living/exosuit/charging var/base_charge_rate = 60 KILOWATTS var/repair_power_usage = 10 KILOWATTS // Per 1 HP of health. var/repair = 0 -/obj/machinery/mech_recharger/Crossed(var/mob/living/exosuit/M) +/obj/machinery/mech_recharger/Crossed(atom/movable/AM) . = ..() - if(istype(M) && charging != M) - start_charging(M) + if(istype(AM, /mob/living/exosuit) && charging != AM) + start_charging(AM) -/obj/machinery/mech_recharger/Uncrossed(var/mob/living/exosuit/M) +/obj/machinery/mech_recharger/Uncrossed(atom/movable/AM) . = ..() - if(M == charging) + var/mob/living/exosuit/M = AM + if(istype(M) && M == charging) stop_charging() /obj/machinery/mech_recharger/RefreshParts() @@ -67,14 +67,17 @@ var/remaining_energy = active_power_usage if(repair && !fully_repaired()) + var/repaired = FALSE for(var/obj/item/mech_component/MC in charging) if(MC) MC.repair_brute_damage(repair) MC.repair_burn_damage(repair) remaining_energy -= repair * repair_power_usage + repaired = TRUE if(remaining_energy <= 0) break - charging.updatehealth() + if(repaired) + charging.update_health() // TODO: do this during component repair. if(fully_repaired()) charging.show_message(SPAN_NOTICE("Exosuit integrity has been fully restored.")) @@ -89,7 +92,7 @@ // An ugly proc, but apparently mechs don't have maxhealth var of any kind. /obj/machinery/mech_recharger/proc/fully_repaired() - return charging && (charging.health == charging.maxHealth) + return charging && (charging.current_health >= charging.get_max_health()) /obj/machinery/mech_recharger/proc/start_charging(var/mob/living/exosuit/M) if(stat & (NOPOWER | BROKEN)) diff --git a/code/game/machinery/message_server.dm b/code/game/machinery/message_server.dm index 6c3e09c694bd..9ddf2a4d9f39 100644 --- a/code/game/machinery/message_server.dm +++ b/code/game/machinery/message_server.dm @@ -1,8 +1,13 @@ +var/global/list/message_servers = list() +/proc/get_message_server_for_z(z) + var/list/local_zs = SSmapping.get_connected_levels(z) + for(var/obj/machinery/network/message_server/MS in global.message_servers) + if((MS.z in local_zs) && !(MS.stat & (BROKEN|NOPOWER))) + return MS + #define MESSAGE_SERVER_SPAM_REJECT 1 #define MESSAGE_SERVER_DEFAULT_SPAM_LIMIT 10 -var/global/list/obj/machinery/message_server/message_servers = list() - /datum/data_rc_msg var/rec_dpt = "Unspecified" //name of the person var/send_dpt = "Unspecified" //name of the sender @@ -33,12 +38,12 @@ var/global/list/obj/machinery/message_server/message_servers = list() else priority = "Undetermined" -/obj/machinery/message_server - icon = 'icons/obj/machines/server.dmi' - icon_state = "server" - name = "Messaging Server" - density = 1 - anchored = 1.0 +/obj/machinery/network/message_server + name = "messaging server" + icon = 'icons/obj/machines/tcomms/message_server.dmi' + icon_state = "message_server" + density = TRUE + anchored = TRUE idle_power_usage = 10 active_power_usage = 100 @@ -47,26 +52,32 @@ var/global/list/obj/machinery/message_server/message_servers = list() var/power_failure = 0 // Reboot timer after power outage var/decryptkey = "password" - //Spam filtering stuff - var/list/spamfilter = list("You have won", "your prize", "male enhancement", "shitcurity", \ - "are happy to inform you", "account number", "enter your PIN") - //Messages having theese tokens will be rejected by server. Case sensitive + /// Spam filtering stuff. Messages having theese tokens will be rejected by server. Case sensitive. + var/list/spamfilter = list( + "You have won", + "your prize", + "male enhancement", + "shitcurity", + "are happy to inform you", + "account number", + "enter your PIN" + ) var/spamfilter_limit = MESSAGE_SERVER_DEFAULT_SPAM_LIMIT //Maximal amount of tokens stat_immune = 0 uncreated_component_parts = null construct_state = /decl/machine_construction/default/panel_closed -/obj/machinery/message_server/Initialize() +/obj/machinery/network/message_server/Initialize() + global.message_servers += src . = ..() - message_servers += src decryptkey = GenerateKey() -/obj/machinery/message_server/Destroy() - message_servers -= src +/obj/machinery/network/message_server/Destroy() + global.message_servers -= src return ..() -/obj/machinery/message_server/Process() +/obj/machinery/network/message_server/Process() ..() if(active && (stat & (BROKEN|NOPOWER))) active = 0 @@ -80,7 +91,7 @@ var/global/list/obj/machinery/message_server/message_servers = list() active = 1 update_icon() -/obj/machinery/message_server/proc/send_rc_message(var/recipient = "",var/sender = "",var/message = "",var/stamp = "", var/id_auth = "", var/priority = 1) +/obj/machinery/network/message_server/proc/send_rc_message(var/recipient = "",var/sender = "",var/message = "",var/stamp = "", var/id_auth = "", var/priority = 1) rc_msgs += new/datum/data_rc_msg(recipient,sender,message,stamp,id_auth) var/authmsg = "[message]
    " if (id_auth) @@ -88,11 +99,14 @@ var/global/list/obj/machinery/message_server/message_servers = list() if (stamp) authmsg += "[stamp]
    " . = FALSE - var/list/good_z = GetConnectedZlevels(z) - for (var/obj/machinery/requests_console/Console in allConsoles) - if(!(Console.z in good_z)) + + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/datum/extension/network_device/console in network?.devices) + var/obj/machinery/network/requests_console/Console = console.holder + if(!istype(Console)) continue - if (ckey(Console.department) == ckey(recipient)) + if(ckey(Console.department) == ckey(recipient)) if(Console.inoperable()) Console.message_log += "Message lost due to console failure.
    Please contact [station_name()] system administrator or AI for technical assistance.
    " continue @@ -102,17 +116,17 @@ var/global/list/obj/machinery/message_server/message_servers = list() Console.icon_state = "req_comp[priority]" if(priority > 1) playsound(Console.loc, 'sound/machines/chime.ogg', 80, 1) - Console.audible_message("\icon[Console]\The [Console] announces: 'High priority message received from [sender]!'", hearing_distance = 8) - Console.message_log += "High Priority message from [sender]
    [authmsg]" + Console.audible_message("[html_icon(Console)]\The [Console] announces: 'High priority message received from [sender]!'", hearing_distance = 8) + Console.message_log += "High Priority message from [sender]
    [authmsg]" else if(!Console.silent) playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1) - Console.audible_message("\icon[Console]\The [Console] announces: 'Message received from [sender].'", hearing_distance = 5) - Console.message_log += "Message from [sender]
    [authmsg]" - Console.set_light(0.3, 0.1, 2) + Console.audible_message("[html_icon(Console)]\The [Console] announces: 'Message received from [sender].'", hearing_distance = 5) + Console.message_log += "Message from [sender]
    [authmsg]" + Console.set_light(2, 0.5) -/obj/machinery/message_server/interface_interact(mob/user) +/obj/machinery/network/message_server/interface_interact(mob/user) if(!CanInteract(user, DefaultTopicState())) return FALSE to_chat(user, "You toggle PDA message passing from [active ? "On" : "Off"] to [active ? "Off" : "On"]") @@ -121,29 +135,27 @@ var/global/list/obj/machinery/message_server/message_servers = list() update_icon() return TRUE -/obj/machinery/message_server/attackby(obj/item/O, mob/living/user) +/obj/machinery/network/message_server/attackby(obj/item/used_item, mob/user) if (active && !(stat & (BROKEN|NOPOWER)) && (spamfilter_limit < MESSAGE_SERVER_DEFAULT_SPAM_LIMIT*2) && \ - istype(O,/obj/item/stock_parts/circuitboard/message_monitor)) + istype(used_item,/obj/item/stock_parts/circuitboard/message_monitor)) spamfilter_limit += round(MESSAGE_SERVER_DEFAULT_SPAM_LIMIT / 2) - qdel(O) - to_chat(user, "You install additional memory and processors into message server. Its filtering capabilities been enhanced.") + qdel(used_item) + to_chat(user, "You install additional memory and processors into \the [src]. Its filtering capabilities been enhanced.") + return TRUE else return ..() -/obj/machinery/message_server/on_update_icon() - if((stat & (BROKEN|NOPOWER))) - icon_state = "server-nopower" - else if (!active) - icon_state = "server-off" - else - icon_state = "server-on" - - return +/obj/machinery/network/message_server/on_update_icon() + icon_state = initial(icon_state) + if(panel_open) + icon_state = "[icon_state]_o" + if((stat & (BROKEN|NOPOWER)) || !active) + icon_state = "[icon_state]_off" -/obj/machinery/message_server/proc/send_to_department(var/department, var/message, var/tone) +/obj/machinery/network/message_server/proc/send_to_department(var/department, var/message, var/tone) var/reached = 0 - for(var/mob/living/carbon/human/H in GLOB.human_mob_list) + for(var/mob/living/human/H in global.human_mob_list) var/obj/item/modular_computer/pda/pda = locate() in H if(!pda) continue @@ -152,7 +164,7 @@ var/global/list/obj/machinery/message_server/message_servers = list() if(!J) continue - if(department in J.department_refs) + if(department in J.department_types) to_chat(H, "Your [pda.name] alerts you to the fact that somebody is requesting your presence at your department.") reached++ diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm index 1fbd2971873c..5a3776da1e39 100644 --- a/code/game/machinery/navbeacon.dm +++ b/code/game/machinery/navbeacon.dm @@ -5,9 +5,9 @@ var/global/list/navbeacons = list() icon_state = "navbeacon0-f" name = "navigation beacon" desc = "A radio beacon used for bot navigation." - level = 1 + level = LEVEL_BELOW_PLATING layer = ABOVE_WIRE_LAYER - anchored = 1 + anchored = TRUE var/open = 0 // true if cover is open var/locked = 1 // true if controls are locked @@ -17,15 +17,19 @@ var/global/list/navbeacons = list() initial_access = list(access_engine) /obj/machinery/navbeacon/Initialize() + + if(istext(codes)) // Mapping helper. + codes = cached_json_decode(codes) + . = ..() var/turf/T = loc - hide(!T.is_plating()) + hide(istype(T) && !T.is_plating()) navbeacons += src /obj/machinery/navbeacon/hide(var/intact) - set_invisibility(intact ? 101 : 0) + set_invisibility(intact ? INVISIBILITY_ABSTRACT : INVISIBILITY_NONE) update_icon() /obj/machinery/navbeacon/on_update_icon() @@ -37,19 +41,18 @@ var/global/list/navbeacons = list() else icon_state = "[state]" -/obj/machinery/navbeacon/attackby(var/obj/item/I, var/mob/user) +/obj/machinery/navbeacon/attackby(var/obj/item/used_item, var/mob/user) var/turf/T = loc if(!T.is_plating()) - return // prevent intraction when T-scanner revealed + return TRUE // prevent intraction when T-scanner revealed - if(isScrewdriver(I)) + if(IS_SCREWDRIVER(used_item)) open = !open - user.visible_message("\The [user] [open ? "opens" : "closes"] cover of \the [src].", "You [open ? "open" : "close"] cover of \the [src].") - update_icon() + return TRUE - else if(I.GetIdCard()) + else if(used_item.GetIdCard()) if(open) if (src.allowed(user)) src.locked = !src.locked @@ -59,7 +62,8 @@ var/global/list/navbeacons = list() updateDialog() else to_chat(user, "You must open the cover first!") - return + return TRUE + return FALSE /obj/machinery/navbeacon/interface_interact(var/mob/user) interact(user) @@ -69,100 +73,80 @@ var/global/list/navbeacons = list() var/ai = isAI(user) var/turf/T = loc if(!T.is_plating()) - return // prevent intraction when T-scanner revealed + return // prevent intraction when T-scanner revealed - if(!open && !ai) // can't alter controls if not open, unless you're an AI + if(!open && !ai) // can't alter controls if not open, unless you're an AI to_chat(user, "The beacon's control cover is closed.") return - var/t - - if(locked && !ai) - t = {"Navigation Beacon

    -(swipe card to unlock controls)

    -Location: [location ? location : "(none)"]
    -Transponder Codes:
      "} - - for(var/key in codes) - t += "
    • [key] ... [codes[key]]" - t+= "
        " - - else - - t = {"Navigation Beacon

        -(swipe card to lock controls)

        -Location: [location ? location : "(none)"]
        -Transponder Codes:
          "} - - for(var/key in codes) - t += "
        • [key] ... [codes[key]]" - t += " (edit)" - t += " (delete)
          " - t += "(add new)
          " - t+= "
            " - - show_browser(user, t, "window=navbeacon") + var/restricted = locked && !ai + var/list/dat = list({"Navigation Beacon

            +(swipe card to [locked ? "unlock" : "lock"] controls)

            +Location: [restricted ? "" : ""][location ? location : "(none)"][restricted ? "" : ""]
            +Transponder Codes:
              "}) + + for(var/key in codes) + dat += "
            • [key] ... [codes[key]]" + if(!restricted) + dat += " (edit)" + dat += " (delete)
              " + if(!restricted) + dat += "(add new)
              " + dat += "
                " + + show_browser(user, JOINTEXT(dat), "window=navbeacon") onclose(user, "navbeacon") return -/obj/machinery/navbeacon/Topic(href, href_list) - ..() - if (usr.stat) +/obj/machinery/navbeacon/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) return - if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon))) - if(open && !locked) - usr.set_machine(src) + if(!open || locked) + return TOPIC_NOACTION - if(href_list["locedit"]) - var/newloc = sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null) - if(newloc) - location = newloc - updateDialog() + if(href_list["locedit"]) + var/newloc = sanitize(input(user, "Enter New Location", "Navigation Beacon", location) as text|null) + if(newloc) + location = newloc + return TOPIC_REFRESH - else if(href_list["edit"]) - var/codekey = href_list["code"] + else if(href_list["edit"]) + var/codekey = href_list["code"] - var/newkey = input("Enter Transponder Code Key", "Navigation Beacon", codekey) as text|null - if(!newkey) - return + var/newkey = sanitize(input(user, "Enter Transponder Code Key", "Navigation Beacon", codekey) as text|null) + if(!newkey) + return TOPIC_HANDLED - var/codeval = codes[codekey] - var/newval = input("Enter Transponder Code Value", "Navigation Beacon", codeval) as text|null - if(!newval) - newval = codekey - return + var/codeval = codes[codekey] + var/newval = sanitize(input(user, "Enter Transponder Code Value", "Navigation Beacon", codeval || "1") as text|null) + if(!newval) + return TOPIC_HANDLED - codes.Remove(codekey) - codes[newkey] = newval + codes -= codekey + codes[newkey] = newval + return TOPIC_REFRESH - updateDialog() + else if(href_list["delete"]) + var/codekey = href_list["code"] + codes -= codekey + return TOPIC_REFRESH - else if(href_list["delete"]) - var/codekey = href_list["code"] - codes.Remove(codekey) - updateDialog() + else if(href_list["add"]) - else if(href_list["add"]) + var/newkey = sanitize(input(user, "Enter New Transponder Code Key", "Navigation Beacon") as text|null) + if(!newkey) + return TOPIC_HANDLED - var/newkey = input("Enter New Transponder Code Key", "Navigation Beacon") as text|null - if(!newkey) - return + var/newval = sanitize(input(user, "Enter New Transponder Code Value", "Navigation Beacon", "1") as text|null) + if(!newval) + return TOPIC_HANDLED - var/newval = input("Enter New Transponder Code Value", "Navigation Beacon") as text|null - if(!newval) - newval = "1" - return - - if(!codes) - codes = new() - - codes[newkey] = newval - - updateDialog() + codes[newkey] = newval + return TOPIC_REFRESH /obj/machinery/navbeacon/Destroy() - navbeacons.Remove(src) - . = ..() + global.navbeacons -= src + return ..() // Patrol beacon types below. So many. diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index bc14acdb14fd..ae2af31628d8 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -102,9 +102,9 @@ NEWSCASTER.newsAlert(annoncement) NEWSCASTER.update_icon() -var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list. +var/global/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list. -var/list/obj/machinery/newscaster/allCasters = list() //Global list that will contain reference to all newscasters in existence. +var/global/list/allCasters = list() //Global list that will contain reference to all newscasters in existence. /obj/machinery/newscaster @@ -112,54 +112,74 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co desc = "A standard newsfeed handler. All the news you absolutely have no use for, in one place!" icon = 'icons/obj/terminals.dmi' icon_state = "newscaster_normal" - //var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored. - //OBSOLETE: We're now using a global news network - var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3 - // 0 = welcome screen - main menu - // 1 = view feed channels - // 2 = create feed channel - // 3 = create feed story - // 4 = feed story submited sucessfully - // 5 = feed channel created successfully - // 6 = ERROR: Cannot create feed story - // 7 = ERROR: Cannot create feed channel - // 8 = print newspaper - // 9 = viewing channel feeds - // 10 = censor feed story - // 11 = censor feed channel - //Holy shit this is outdated, made this when I was still starting newscasters :3 + var/const/SCREEN_WELCOME = 0 + var/const/SCREEN_VIEW_CHANNELS = 1 + var/const/SCREEN_CREATE_CHANNEL = 2 + var/const/SCREEN_CREATE_STORY = 3 + var/const/SCREEN_STORY_SUBMITTED = 4 + var/const/SCREEN_CHANNEL_SUBMITTED = 5 + var/const/SCREEN_STORY_FAILED = 6 + var/const/SCREEN_CHANNEL_FAILED = 7 + var/const/SCREEN_CHOOSE_PRINT = 8 + var/const/SCREEN_VIEW_STORIES = 9 + var/const/SCREEN_CENSOR_STORY = 10 + var/const/SCREEN_CENSOR_CHANNEL = 11 + var/const/SCREEN_PICK_CENSOR_CHANNEL = 12 + var/const/SCREEN_PICK_CENSOR_STORY = 13 + var/const/SCREEN_MAKE_WANTED_ISSUE = 14 + var/const/SCREEN_WANTED_CONFIRMED = 15 + var/const/SCREEN_WANTED_FAILED = 16 + var/const/SCREEN_WANTED_DELETED = 17 + var/const/SCREEN_WANTED_VIEW = 18 + var/const/SCREEN_WANTED_EDITED = 19 + var/const/SCREEN_PRINT_COMPLETE = 20 + var/const/SCREEN_PRINT_FAILED = 21 + var/screen = SCREEN_WELCOME var/paper_remaining = 0 - var/securityCaster = 0 - // 0 = Caster cannot be used to issue wanted posters - // 1 = the opposite - var/unit_no = 0 //Each newscaster has a unit number - //var/datum/feed_message/wanted //We're gonna use a feed_message to store data of the wanted person because fields are similar - //var/wanted_issue = 0 //OBSOLETE - // 0 = there's no WANTED issued, we don't need a special icon_state - // 1 = Guess what. - var/alert_delay = 500 - var/alert = 0 - // 0 = there hasn't been a news/wanted update in the last alert_delay - // 1 = there has - var/scanned_user = "Unknown" //Will contain the name of the person who currently uses the newscaster - var/msg = ""; //Feed message - var/datum/news_photo/photo_data = null - var/channel_name = ""; //the feed channel which will be receiving the feed, or being created - var/c_locked=0; //Will our new channel be locked to public submissions? - var/hitstaken = 0 //Death at 3 hits from an item with force>=15 - var/datum/feed_channel/viewing_channel = null - light_outer_range = 0 - anchored = 1 + /// (BOOL) Whether or not the newscaster can be used to create wanted issues. + var/securityCaster = FALSE + /// The unique unit number identifying a specific newscaster, useful for forensics. + var/unit_no = 0 + var/alert_delay = 1 MINUTE + /// Whether or not the alert overlay state should be used to inform about a recent news/wanted update in the last alert_delay. + var/alert = FALSE + /// The name (based on an ID) of the user currently operating the newscaster. + var/scanned_user = "Unknown" + + // Temporary variables used while creating a new story. + /// The text content of the feed message to create. + var/tmp/msg = "" //Feed message + /// The photo to attach to the news story. A wrapper for a photo object with additional metadata. + var/tmp/datum/news_photo/photo_data = null + + // Temporary variable used while creating a new channel. + /// Whether or not the currently-being-created channel will be locked to public submissions. + var/tmp/c_locked = FALSE + + // Temporary variable used for both creating a new channel and creating a new story. + /// The name of the feed channel to either create, or submit a new story to. + var/tmp/channel_name = "" + + /// A hit counter that determines cosmetic damage overlays, up to 3. Currently never incremented. + var/hitstaken = 0 + + /// The channel that's currently open. + var/tmp/datum/feed_channel/viewing_channel = null + light_range = 0 + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED layer = ABOVE_WINDOW_LAYER construct_state = /decl/machine_construction/wall_frame/panel_closed uncreated_component_parts = null stat_immune = 0 frame_type = /obj/item/frame/stock_offset/newscaster + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' /obj/machinery/newscaster/Initialize() . = ..() - securityCaster = istype(get_area(src), /area/security) + var/area/A = get_area(src) + securityCaster = istype(A) && (A.area_flags & AREA_FLAG_SECURITY) allCasters += src paper_remaining = 15 // Will probably change this to something better unit_no = "[sequential_id("obj/machinery/newscaster")]" @@ -197,7 +217,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co return TRUE /obj/machinery/newscaster/interact(mob/user) //########### THE MAIN BEEF IS HERE! And in the proc below this...############ - if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon) ) + if(ishuman(user) || issilicon(user) ) var/mob/living/human_or_robot_user = user var/dat dat = text("Newscaster

                Newscaster Unit #[src.unit_no]

                ") @@ -205,64 +225,64 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co src.scan_user(human_or_robot_user) //Newscaster scans you switch(screen) - if(0) + if(SCREEN_WELCOME) dat += "Welcome to Newscasting Unit #[src.unit_no].
                Interface & News networks Operational." if(news_network.wanted_issue) - dat+= "
                Read Wanted Issue" - dat+= "

                Create Feed Channel" - dat+= "
                View Feed Channels" - dat+= "
                Submit new Feed story" - dat+= "
                Print newspaper" - dat+= "
                Re-scan User" - dat+= "

                Exit" + dat+= "
                Read Wanted Issue" + dat+= "

                Create Feed Channel" + dat+= "
                View Feed Channels" + dat+= "
                Submit new Feed story" + dat+= "
                Print newspaper" + dat+= "
                Re-scan User" + dat+= "

                Exit" if(src.securityCaster) var/wanted_already = 0 if(news_network.wanted_issue) wanted_already = 1 dat+="
                Feed Security functions:
                " - dat+="
                [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" - dat+="
                Censor Feed Stories" - dat+="
                Mark Feed Channel with [GLOB.using_map.company_name] D-Notice" + dat+="
                [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" + dat+="
                Censor Feed Stories" + dat+="
                Mark Feed Channel with [global.using_map.company_name] D-Notice" dat+="

                The newscaster recognises you as: [src.scanned_user]" - if(1) + if(SCREEN_VIEW_CHANNELS) dat+= "Local Feed Channels
                " - if( isemptylist(news_network.network_channels) ) + if( !length(news_network.network_channels) ) dat+="No active channels found..." else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) if(CHANNEL.is_admin_channel) - dat+="[CHANNEL.channel_name]
                " + dat+="[CHANNEL.channel_name]
                " else - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
                " - dat+="

                Refresh" - dat+="
                Back" - if(2) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
                " + dat+="

                Refresh" + dat+="
                Back" + if(SCREEN_CREATE_CHANNEL) dat+="Creating new Feed Channel..." - dat+="
                Channel Name: [src.channel_name]
                " + dat+="
                Channel Name: [src.channel_name]
                " dat+="Channel Author: [src.scanned_user]
                " - dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

                " - dat+="
                Submit

                Cancel
                " - if(3) + dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

                " + dat+="
                Submit

                Cancel
                " + if(SCREEN_CREATE_STORY) dat+="Creating new Feed Message..." - dat+="
                Receiving Channel: [src.channel_name]
                " //MARK + dat+="
                Receiving Channel: [src.channel_name]
                " //MARK dat+="Message Author: [src.scanned_user]
                " - dat+="Message Body: [src.msg]
                " + dat+="Message Body: [src.msg]
                " dat+="Photo: " if(photo_data && photo_data.photo) - send_rsc(usr, photo_data.photo.img, "tmp_photo.png") + send_rsc(user, photo_data.photo.img, "tmp_photo.png") dat+="
                " - dat+="
                Delete Photo
                " + dat+="
                Delete Photo
                " else - dat+="Attach Photo" - dat+="

                Submit

                Cancel
                " - if(4) + dat+="Attach Photo" + dat+="

                Submit

                Cancel
                " + if(SCREEN_STORY_SUBMITTED) dat+="Feed story successfully submitted to [src.channel_name].

                " - dat+="
                Return
                " - if(5) + dat+="
                Return
                " + if(SCREEN_CHANNEL_SUBMITTED) dat+="Feed Channel [src.channel_name] created successfully.

                " - dat+="
                Return
                " - if(6) + dat+="
                Return
                " + if(SCREEN_STORY_FAILED) dat+="ERROR: Could not submit Feed story to Network.

                " if(src.channel_name=="") dat+="Invalid receiving channel name.
                " @@ -271,8 +291,8 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co if(src.msg == "" || src.msg == "\[REDACTED\]") dat+="Invalid message body.
                " - dat+="
                Return
                " - if(7) + dat+="
                Return
                " + if(SCREEN_CHANNEL_FAILED) dat+="ERROR: Could not submit Feed Channel to Network.

                " var/list/existing_authors = list() for(var/datum/feed_channel/FC in news_network.network_channels) @@ -293,8 +313,8 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="Channel name already in use.
                " if(src.scanned_user=="Unknown") dat+="Channel author unverified.
                " - dat+="
                Return
                " - if(8) + dat+="
                Return
                " + if(SCREEN_CHOOSE_PRINT) var/total_num=length(news_network.network_channels) var/active_num=total_num var/message_num=0 @@ -305,15 +325,15 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co active_num-- dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE dat+="

                Liquid Paper remaining: [(src.paper_remaining) *100 ] cm^3" - dat+="

                Print Paper" - dat+="
                Cancel" - if(9) + dat+="

                Print Paper" + dat+="
                Cancel" + if(SCREEN_VIEW_STORIES) dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\] \[views: [++src.viewing_channel.views]\]
                " if(src.viewing_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
                " + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [global.using_map.company_name] D-Notice.
                " dat+="No further feed story additions are allowed while the D-Notice is in effect.

                " else - if( isemptylist(src.viewing_channel.messages) ) + if( !length(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
                " else var/i = 0 @@ -322,64 +342,64 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="-[MESSAGE.body]
                " if(MESSAGE.img) var/resourc_name = "newscaster_photo_[sanitize(viewing_channel.channel_name)]_[i].png" - send_asset(usr.client, resourc_name) + send_asset(user.client, resourc_name) dat+="
                " if(MESSAGE.caption) dat+="[MESSAGE.caption]
                " dat+="
                " dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]
                " - dat+="

                Refresh" - dat+="
                Back" - if(10) - dat+="[GLOB.using_map.company_name] Feed Censorship Tool
                " + dat+="

                Refresh" + dat+="
                Back" + if(SCREEN_CENSOR_STORY) + dat+="[global.using_map.company_name] Feed Censorship Tool
                " dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
                " dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
                " dat+="
                Select Feed channel to get Stories from:
                " - if(isemptylist(news_network.network_channels)) + if(!length(news_network.network_channels)) dat+="No feed channels found active...
                " else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
                " - dat+="
                Cancel" - if(11) - dat+="[GLOB.using_map.company_name] D-Notice Handler
                " + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
                " + dat+="
                Cancel" + if(SCREEN_CENSOR_CHANNEL) + dat+="[global.using_map.company_name] D-Notice Handler
                " dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the [station_name()]'s" dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
                " - if(isemptylist(news_network.network_channels)) + if(!length(news_network.network_channels)) dat+="No feed channels found active...
                " else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
                " + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
                " - dat+="
                Back" - if(12) + dat+="
                Back" + if(SCREEN_PICK_CENSOR_STORY) dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
                " - dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
                " + dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
                " - if( isemptylist(src.viewing_channel.messages) ) + if( !length(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
                " else for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) dat+="-[MESSAGE.body]
                \[[MESSAGE.message_type] by [MESSAGE.author]\]
                " - dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
                " - dat+="
                Back" - if(13) + dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
                " + dat+="
                Back" + if(SCREEN_PICK_CENSOR_CHANNEL) dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
                " - dat+="Channel messages listed below. If you deem them dangerous to the [station_name()], you can Bestow a D-Notice upon the channel.
                " + dat+="Channel messages listed below. If you deem them dangerous to the [station_name()], you can Bestow a D-Notice upon the channel.
                " if(src.viewing_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
                " + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [global.using_map.company_name] D-Notice.
                " dat+="No further feed story additions are allowed while the D-Notice is in effect.

                " else - if( isemptylist(src.viewing_channel.messages) ) + if( !length(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
                " else for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) dat+="-[MESSAGE.body]
                \[[MESSAGE.message_type] by [MESSAGE.author]\]
                " - dat+="
                Back" - if(14) + dat+="
                Back" + if(SCREEN_MAKE_WANTED_ISSUE) dat+="Wanted Issue Handler:" var/wanted_already = 0 var/end_param = 1 @@ -390,27 +410,27 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co if(wanted_already) dat+="
                A wanted issue is already in Feed Circulation. You can edit or cancel it below.
                " dat+="
                " - dat+="Criminal Name: [src.channel_name]
                " - dat+="Description: [src.msg]
                " + dat+="Criminal Name: [src.channel_name]
                " + dat+="Description: [src.msg]
                " dat+="Photo: " if(photo_data && photo_data.photo) - send_rsc(usr, photo_data.photo.img, "tmp_photo.png") + send_rsc(user, photo_data.photo.img, "tmp_photo.png") dat+="
                " - dat+="
                Delete Photo
                " + dat+="
                Delete Photo
                " else - dat+="Attach Photo
                " + dat+="Attach Photo
                " if(wanted_already) dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
                " else dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
                " - dat+="
                [(wanted_already) ? ("Edit Issue") : ("Submit")]" + dat+="
                [(wanted_already) ? ("Edit Issue") : ("Submit")]" if(wanted_already) - dat+="
                Take down Issue" - dat+="
                Cancel" - if(15) + dat+="
                Take down Issue" + dat+="
                Cancel" + if(SCREEN_WANTED_CONFIRMED) dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

                " - dat+="
                Return
                " - if(16) + dat+="
                Return
                " + if(SCREEN_WANTED_FAILED) dat+="ERROR: Wanted Issue rejected by Network.

                " if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") dat+="Invalid name for person wanted.
                " @@ -418,322 +438,317 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="Issue author unverified.
                " if(src.msg == "" || src.msg == "\[REDACTED\]") dat+="Invalid description.
                " - dat+="
                Return
                " - if(17) + dat+="
                Return
                " + if(SCREEN_WANTED_DELETED) dat+="Wanted Issue successfully deleted from Circulation
                " - dat+="
                Return
                " - if(18) + dat+="
                Return
                " + if(SCREEN_WANTED_VIEW) dat+="-- STATIONWIDE WANTED ISSUE --
                \[Submitted by: [news_network.wanted_issue.backup_author]\]
                " dat+="Criminal: [news_network.wanted_issue.author]
                " dat+="Description: [news_network.wanted_issue.body]
                " dat+="Photo: " if(news_network.wanted_issue.img) - send_rsc(usr, news_network.wanted_issue.img, "tmp_photow.png") + send_rsc(user, news_network.wanted_issue.img, "tmp_photow.png") dat+="
                " else dat+="None" - dat+="

                Back
                " - if(19) + dat+="

                Back
                " + if(SCREEN_WANTED_EDITED) dat+="Wanted issue for [src.channel_name] successfully edited.

                " - dat+="
                Return
                " - if(20) + dat+="
                Return
                " + if(SCREEN_PRINT_COMPLETE) dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

                " - dat+="Return" - if(21) + dat+="Return" + if(SCREEN_PRINT_FAILED) dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

                " - dat+="Return" - else - dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + dat+="Return" - var/processed_dat = human_or_robot_user.handle_reading_literacy(human_or_robot_user, dat) + var/processed_dat = human_or_robot_user.handle_reading_literacy(human_or_robot_user, dat, digital = TRUE) if(processed_dat) show_browser(human_or_robot_user, processed_dat, "window=newscaster_main;size=400x600") onclose(human_or_robot_user, "newscaster_main") -/obj/machinery/newscaster/Topic(href, href_list) - if(..()) +// This really needs to be rewritten, desperately. +// TODO: Rewrite newscasters to use files, networks, mainframes, etc. Also make it use NanoUI. +/obj/machinery/newscaster/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) // already handled in parent return - if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - if(href_list["set_channel_name"]) - src.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN) - src.updateUsrDialog() - //src.update_icon() - - else if(href_list["set_channel_lock"]) - src.c_locked = !src.c_locked - src.updateUsrDialog() - //src.update_icon() - - else if(href_list["submit_new_channel"]) - //var/list/existing_channels = list() //OBSOLETE - var/list/existing_authors = list() - for(var/datum/feed_channel/FC in news_network.network_channels) - //existing_channels += FC.channel_name - if(FC.author == "\[REDACTED\]") - existing_authors += FC.backup_author - else - existing_authors +=FC.author - var/check = 0 - for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == src.channel_name) - check = 1 - break - if(src.channel_name == "" || src.channel_name == "\[REDACTED\]" || src.scanned_user == "Unknown" || check || (src.scanned_user in existing_authors) ) - src.screen=7 - else - var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") - if(choice=="Confirm") - news_network.CreateFeedChannel(src.channel_name, src.scanned_user, c_locked) - src.screen=5 - src.updateUsrDialog() - //src.update_icon() - - else if(href_list["set_channel_receiving"]) - //var/list/datum/feed_channel/available_channels = list() - var/list/available_channels = list() - for(var/datum/feed_channel/F in news_network.network_channels) - if( (!F.locked || F.author == scanned_user) && !F.censored) - available_channels += F.channel_name - src.channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels - src.updateUsrDialog() - - else if(href_list["set_new_message"]) - src.msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "")) - src.updateUsrDialog() - - else if(href_list["set_attachment"]) - AttachPhoto(usr) - src.updateUsrDialog() - - else if(href_list["submit_new_message"]) - if(src.msg =="" || src.msg=="\[REDACTED\]" || src.scanned_user == "Unknown" || src.channel_name == "" ) - src.screen=6 + // no need to do set_machine, that's done in CouldUseTopic + if(href_list["set_channel_name"]) + channel_name = sanitize_safe(input(user, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN) + . = TOPIC_REFRESH + + else if(href_list["set_channel_lock"]) + c_locked = !c_locked + . = TOPIC_REFRESH + + else if(href_list["submit_new_channel"]) + var/list/existing_authors = list() + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.author == "\[REDACTED\]") + existing_authors += FC.backup_author else - var/image = photo_data ? photo_data.photo : null - SSstatistics.add_field("newscaster_stories",1) - news_network.SubmitArticle(src.msg, src.scanned_user, src.channel_name, image, 0) - if(photo_data) - qdel(photo_data) - photo_data = null - src.screen=4 - - src.updateUsrDialog() - - else if(href_list["create_channel"]) - src.screen=2 - src.updateUsrDialog() - - else if(href_list["create_feed_story"]) - src.screen=3 - src.updateUsrDialog() - - else if(href_list["menu_paper"]) - src.screen=8 - src.updateUsrDialog() - else if(href_list["print_paper"]) - if(!src.paper_remaining) - src.screen=21 - else - src.print_paper() - src.screen = 20 - src.updateUsrDialog() - - else if(href_list["menu_censor_story"]) - src.screen=10 - src.updateUsrDialog() - - else if(href_list["menu_censor_channel"]) - src.screen=11 - src.updateUsrDialog() - - else if(href_list["menu_wanted"]) - var/already_wanted = 0 - if(news_network.wanted_issue) - already_wanted = 1 - - if(already_wanted) - src.channel_name = news_network.wanted_issue.author - src.msg = news_network.wanted_issue.body - src.screen = 14 - src.updateUsrDialog() - - else if(href_list["set_wanted_name"]) - src.channel_name = sanitizeSafe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN) - src.updateUsrDialog() - - else if(href_list["set_wanted_desc"]) - src.msg = sanitize(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) - src.updateUsrDialog() - - else if(href_list["submit_wanted"]) - var/input_param = text2num(href_list["submit_wanted"]) - if(src.msg == "" || src.channel_name == "" || src.scanned_user == "Unknown") - src.screen = 16 - else - var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") - if(choice=="Confirm") - if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below - var/datum/feed_message/WANTED = new /datum/feed_message - WANTED.author = src.channel_name - WANTED.body = src.msg - WANTED.backup_author = src.scanned_user //I know, a bit wacky - if(photo_data) - WANTED.img = photo_data.photo.img - news_network.wanted_issue = WANTED - news_network.alert_readers() - src.screen = 15 - else - if(news_network.wanted_issue.is_admin_message) - alert("The wanted issue has been distributed by a [GLOB.using_map.company_name] higherup. You cannot edit it.","Ok") - return - news_network.wanted_issue.author = src.channel_name - news_network.wanted_issue.body = src.msg - news_network.wanted_issue.backup_author = src.scanned_user - if(photo_data) - news_network.wanted_issue.img = photo_data.photo.img - src.screen = 19 - - src.updateUsrDialog() - - else if(href_list["cancel_wanted"]) - if(news_network.wanted_issue.is_admin_message) - alert("The wanted issue has been distributed by a [GLOB.using_map.company_name] higherup. You cannot take it down.","Ok") - return - var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") + existing_authors +=FC.author + var/check = 0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(FC.channel_name == channel_name) + check = 1 + break + if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors) ) + screen = SCREEN_CHANNEL_FAILED + else + var/choice = alert(user, "Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") if(choice=="Confirm") - news_network.wanted_issue = null - for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) - NEWSCASTER.update_icon() - src.screen=17 - src.updateUsrDialog() - - else if(href_list["view_wanted"]) - src.screen=18 - src.updateUsrDialog() - else if(href_list["censor_channel_author"]) - var/datum/feed_channel/FC = locate(href_list["censor_channel_author"]) - if(FC.is_admin_channel) - alert("This channel was created by a [GLOB.using_map.company_name] Officer. You cannot censor it.","Ok") - return - if(FC.author != "\[REDACTED\]") - FC.backup_author = FC.author - FC.author = "\[REDACTED\]" - else - FC.author = FC.backup_author - FC.update() - src.updateUsrDialog() - - else if(href_list["censor_channel_story_author"]) - var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"]) - if(MSG.is_admin_message) - alert("This message was created by a [GLOB.using_map.company_name] Officer. You cannot censor its author.","Ok") - return - if(MSG.author != "\[REDACTED\]") - MSG.backup_author = MSG.author - MSG.author = "\[REDACTED\]" - else - MSG.author = MSG.backup_author - MSG.parent_channel.update() - src.updateUsrDialog() - - else if(href_list["censor_channel_story_body"]) - var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"]) - if(MSG.is_admin_message) - alert("This channel was created by a [GLOB.using_map.company_name] Officer. You cannot censor it.","Ok") - return - if(MSG.body != "\[REDACTED\]") - MSG.backup_body = MSG.body - MSG.backup_caption = MSG.caption - MSG.backup_img = MSG.img - MSG.body = "\[REDACTED\]" - MSG.caption = "\[REDACTED\]" - MSG.img = null - else - MSG.body = MSG.backup_body - MSG.caption = MSG.caption - MSG.img = MSG.backup_img - - MSG.parent_channel.update() - src.updateUsrDialog() - - else if(href_list["pick_d_notice"]) - var/datum/feed_channel/FC = locate(href_list["pick_d_notice"]) - src.viewing_channel = FC - src.screen=13 - src.updateUsrDialog() - - else if(href_list["toggle_d_notice"]) - var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"]) - if(FC.is_admin_channel) - alert("This channel was created by a [GLOB.using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok") - return - FC.censored = !FC.censored - FC.update() - src.updateUsrDialog() - - else if(href_list["view"]) - src.screen=1 - src.updateUsrDialog() - - else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~ - src.screen = text2num(href_list["setScreen"]) - if (src.screen == 0) - src.scanned_user = "Unknown" - msg = "" - src.c_locked=0; - channel_name="" - src.viewing_channel = null - if (photo_data) - qdel(photo_data) - photo_data = null - src.updateUsrDialog() - - else if(href_list["show_channel"]) - var/datum/feed_channel/FC = locate(href_list["show_channel"]) - src.viewing_channel = FC - src.screen = 9 - src.updateUsrDialog() - - else if(href_list["pick_censor_channel"]) - var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"]) - src.viewing_channel = FC - src.screen = 12 - src.updateUsrDialog() - - else if(href_list["refresh"]) - src.updateUsrDialog() + news_network.CreateFeedChannel(channel_name, scanned_user, c_locked) + screen = SCREEN_CHANNEL_SUBMITTED + . = TOPIC_REFRESH + + else if(href_list["set_channel_receiving"]) + var/list/available_channels = list() + for(var/datum/feed_channel/F in news_network.network_channels) + if( (!F.locked || F.author == scanned_user) && !F.censored) + available_channels += F.channel_name + channel_name = input(user, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels + . = TOPIC_REFRESH + + else if(href_list["set_new_message"]) + msg = pencode2html(sanitize(input(user, "Write your Feed story", "Network Channel Handler", "") as message|null)) + . = TOPIC_REFRESH + + else if(href_list["set_attachment"]) + AttachPhoto(user) + . = TOPIC_REFRESH + + else if(href_list["submit_new_message"]) + if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "" ) + screen = SCREEN_STORY_FAILED + else + var/image = photo_data ? photo_data.photo : null + SSstatistics.add_field("newscaster_stories",1) + news_network.SubmitArticle(msg, scanned_user, channel_name, image, 0) + if(photo_data) + qdel(photo_data) + photo_data = null + screen = SCREEN_STORY_SUBMITTED + + . = TOPIC_REFRESH + + else if(href_list["create_channel"]) + screen = SCREEN_CREATE_CHANNEL + . = TOPIC_REFRESH + + else if(href_list["create_feed_story"]) + screen = SCREEN_CREATE_STORY + . = TOPIC_REFRESH + + else if(href_list["menu_paper"]) + screen = SCREEN_CHOOSE_PRINT + . = TOPIC_REFRESH + else if(href_list["print_paper"]) + if(!paper_remaining) + screen = SCREEN_PRINT_FAILED + else + print_paper() + screen = SCREEN_PRINT_COMPLETE + . = TOPIC_REFRESH + + else if(href_list["menu_censor_story"]) + screen = SCREEN_CENSOR_STORY + . = TOPIC_REFRESH + + else if(href_list["menu_censor_channel"]) + screen = SCREEN_CENSOR_CHANNEL + . = TOPIC_REFRESH + + else if(href_list["menu_wanted"]) + var/already_wanted = 0 + if(news_network.wanted_issue) + already_wanted = 1 + + if(already_wanted) + channel_name = news_network.wanted_issue.author + msg = news_network.wanted_issue.body + screen = SCREEN_MAKE_WANTED_ISSUE + . = TOPIC_REFRESH + + else if(href_list["set_wanted_name"]) + channel_name = sanitize_safe(input(user, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN) + . = TOPIC_REFRESH + + else if(href_list["set_wanted_desc"]) + msg = sanitize(input(user, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) + . = TOPIC_REFRESH + + else if(href_list["submit_wanted"]) + var/input_param = text2num(href_list["submit_wanted"]) + if(msg == "" || channel_name == "" || scanned_user == "Unknown") + screen = SCREEN_WANTED_FAILED + else + var/choice = alert(user, "Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below + var/datum/feed_message/WANTED = new /datum/feed_message + WANTED.author = channel_name + WANTED.body = msg + WANTED.backup_author = scanned_user //I know, a bit wacky + if(photo_data) + WANTED.img = photo_data.photo.img + news_network.wanted_issue = WANTED + news_network.alert_readers() + screen = SCREEN_WANTED_CONFIRMED + else + if(news_network.wanted_issue.is_admin_message) + alert(user, "The wanted issue has been distributed by a [global.using_map.company_name] higherup. You cannot edit it.","Ok") + return TOPIC_HANDLED + news_network.wanted_issue.author = channel_name + news_network.wanted_issue.body = msg + news_network.wanted_issue.backup_author = scanned_user + if(photo_data) + news_network.wanted_issue.img = photo_data.photo.img + screen = SCREEN_WANTED_EDITED + + . = TOPIC_REFRESH + + else if(href_list["cancel_wanted"]) + if(news_network.wanted_issue.is_admin_message) + alert(user, "The wanted issue has been distributed by a [global.using_map.company_name] higherup. You cannot take it down.","Ok") + return + var/choice = alert(user, "Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + news_network.wanted_issue = null + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.update_icon() + screen = SCREEN_WANTED_DELETED + . = TOPIC_REFRESH + + else if(href_list["view_wanted"]) + screen = SCREEN_WANTED_VIEW + . = TOPIC_REFRESH + else if(href_list["censor_channel_author"]) + var/datum/feed_channel/FC = locate(href_list["censor_channel_author"]) + if(FC.is_admin_channel) + alert(user, "This channel was created by a [global.using_map.company_name] Officer. You cannot censor it.","Ok") + return TOPIC_HANDLED + if(FC.author != "\[REDACTED\]") + FC.backup_author = FC.author + FC.author = "\[REDACTED\]" + else + FC.author = FC.backup_author + FC.update() + . = TOPIC_REFRESH + + else if(href_list["censor_channel_story_author"]) + var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"]) + if(MSG.is_admin_message) + alert(user, "This message was created by a [global.using_map.company_name] Officer. You cannot censor its author.","Ok") + return TOPIC_HANDLED + if(MSG.author != "\[REDACTED\]") + MSG.backup_author = MSG.author + MSG.author = "\[REDACTED\]" + else + MSG.author = MSG.backup_author + MSG.parent_channel.update() + . = TOPIC_REFRESH + + else if(href_list["censor_channel_story_body"]) + var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"]) + if(MSG.is_admin_message) + alert(user, "This channel was created by a [global.using_map.company_name] Officer. You cannot censor it.","Ok") + return TOPIC_HANDLED + if(MSG.body != "\[REDACTED\]") + MSG.backup_body = MSG.body + MSG.backup_caption = MSG.caption + MSG.backup_img = MSG.img + MSG.body = "\[REDACTED\]" + MSG.caption = "\[REDACTED\]" + MSG.img = null + else + MSG.body = MSG.backup_body + MSG.caption = MSG.caption + MSG.img = MSG.backup_img + + MSG.parent_channel.update() + . = TOPIC_REFRESH + + else if(href_list["pick_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["pick_d_notice"]) + viewing_channel = FC + screen = SCREEN_PICK_CENSOR_CHANNEL + . = TOPIC_REFRESH + + else if(href_list["toggle_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"]) + if(FC.is_admin_channel) + alert(user, "This channel was created by a [global.using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok") + return TOPIC_HANDLED + FC.censored = !FC.censored + FC.update() + . = TOPIC_REFRESH + + else if(href_list["view"]) + screen = SCREEN_VIEW_CHANNELS + . = TOPIC_REFRESH + + else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~ + screen = text2num(href_list["setScreen"]) + if (screen == SCREEN_WELCOME) + scanned_user = "Unknown" + msg = "" + c_locked=0 + channel_name="" + viewing_channel = null + if (photo_data) + qdel(photo_data) + photo_data = null + . = TOPIC_REFRESH + + else if(href_list["show_channel"]) + var/datum/feed_channel/FC = locate(href_list["show_channel"]) + viewing_channel = FC + screen = SCREEN_VIEW_STORIES + . = TOPIC_REFRESH + + else if(href_list["pick_censor_channel"]) + var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"]) + viewing_channel = FC + screen = SCREEN_PICK_CENSOR_STORY + . = TOPIC_REFRESH + + else if(href_list["refresh"]) + . = TOPIC_REFRESH /datum/news_photo - var/is_synth = 0 + /// This var is currently unused. + var/is_synth = FALSE + /// The actual photo object to display to the user. TODO: Refactor to just copy the image from a photo? var/obj/item/photo/photo = null -/datum/news_photo/New(var/obj/item/photo/p, var/synth) +/datum/news_photo/New(obj/item/photo/p, synth = FALSE) is_synth = synth photo = p /obj/machinery/newscaster/proc/AttachPhoto(mob/user) if(photo_data) - qdel(photo_data) - photo_data = null + QDEL_NULL(photo_data) return - if(istype(user.get_active_hand(), /obj/item/photo)) - var/obj/item/photo = user.get_active_hand() + if(istype(user.get_active_held_item(), /obj/item/photo)) + var/obj/item/photo = user.get_active_held_item() photo_data = new(photo, 0) - else if(istype(user,/mob/living/silicon)) + else if(issilicon(user)) var/mob/living/silicon/tempAI = user var/obj/item/photo/selection = tempAI.GetPicture() if (!selection) return - photo_data = new(selection, 1) + photo_data = new(selection, TRUE) //######################################################################################################################## //###################################### NEWSPAPER! ###################################################################### //######################################################################################################################## +// TODO: Rewrite newspapers to use pencode? Also change the name from The Griffon and do something about unnecessary mentions of space. /obj/item/newspaper name = "newspaper" desc = "An issue of The Griffon, the space newspaper." @@ -741,7 +756,8 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co icon_state = "newspaper" w_class = ITEM_SIZE_SMALL //Let's make it fit in trashbags! attack_verb = list("bapped","thwapped","smacked") - force = 0 + _base_attack_force = 0 + material = /decl/material/solid/organic/paper var/screen = 0 var/pages = 0 @@ -754,14 +770,14 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co /obj/item/newspaper/attack_self(mob/user) user.update_personal_goal(/datum/goal/achievement/newshound, TRUE) if(ishuman(user)) - var/mob/living/carbon/human/human_user = user + var/mob/living/human/human_user = user var/dat src.pages = 0 switch(screen) if(0) //Cover dat+="
                The Griffon
                " - dat+="
                [GLOB.using_map.company_name]-standard newspaper, for use on [GLOB.using_map.company_name] Space Facilities

                " - if(isemptylist(src.news_content)) + dat+="
                [global.using_map.company_name]-standard newspaper, for use on [global.using_map.company_name] Space Facilities

                " + if(!length(src.news_content)) if(src.important_message) dat+="Contents:
                  **Important Security Announcement** \[page [src.pages+2]\]
                " else @@ -779,7 +795,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="
              " if(scribble_page==curr_page) dat+="
              There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" - dat+= "
              " + dat+= "
              " if(1) // X channel pages inbetween. for(var/datum/feed_channel/NP in src.news_content) src.pages++ //Let's get it right again. @@ -788,7 +804,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co if(C.censored) dat+="This channel was deemed dangerous to the general welfare of the [station_name()] and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." else - if(isemptylist(C.messages)) + if(!length(C.messages)) dat+="No Feed stories stem from this channel..." else dat+="
                " @@ -804,7 +820,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="
              " if(scribble_page==curr_page) dat+="
              There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" - dat+= "

              " + dat+= "

              " if(2) //Last page for(var/datum/feed_channel/NP in src.news_content) src.pages++ @@ -822,10 +838,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="Apart from some uninteresting Classified ads, there's nothing on this page..." if(scribble_page==curr_page) dat+="
              There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" - dat+= "
              " + dat+= "
              " dat+="

              [src.curr_page+1]
              " - var/processed_dat = human_user.handle_reading_literacy(human_user, dat) + var/processed_dat = human_user.handle_reading_literacy(human_user, dat, digital = TRUE) if(processed_dat) show_browser(human_user, processed_dat, "window=newspaper_main;size=300x400") onclose(human_user, "newspaper_main") @@ -833,61 +849,65 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co to_chat(user, "The paper is full of unintelligible symbols!") -/obj/item/newspaper/Topic(href, href_list) - var/mob/living/U = usr - ..() - if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) )) - U.set_machine(src) - if(href_list["next_page"]) - if(curr_page==src.pages+1) - return //Don't need that at all, but anyway. - if(src.curr_page == src.pages) //We're at the middle, get to the end - src.screen = 2 - else - if(curr_page == 0) //We're at the start, get to the middle - src.screen=1 - src.curr_page++ - playsound(src.loc, "pageturn", 50, 1) +/obj/item/newspaper/DefaultTopicState() + return global.physical_no_access_topic_state - else if(href_list["prev_page"]) - if(curr_page == 0) - return - if(curr_page == 1) - src.screen = 0 +/obj/item/newspaper/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) + return + if(href_list["next_page"]) + if(curr_page==src.pages+1) + return //Don't need that at all, but anyway. + if(src.curr_page == src.pages) //We're at the middle, get to the end + src.screen = 2 + else + if(curr_page == 0) //We're at the start, get to the middle + src.screen=1 + src.curr_page++ + playsound(src.loc, "pageturn", 50, 1) - else - if(curr_page == src.pages+1) //we're at the end, let's go back to the middle. - src.screen = 1 - src.curr_page-- - playsound(src.loc, "pageturn", 50, 1) + else if(href_list["prev_page"]) + if(curr_page == 0) + return + if(curr_page == 1) + src.screen = 0 + + else + if(curr_page == src.pages+1) //we're at the end, let's go back to the middle. + src.screen = 1 + src.curr_page-- + playsound(src.loc, "pageturn", 50, 1) - if (istype(src.loc, /mob)) - src.attack_self(src.loc) + if (ismob(src.loc)) + src.attack_self(src.loc) -/obj/item/newspaper/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/pen)) +/obj/item/newspaper/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) if(src.scribble_page == src.curr_page) - to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?") - else - var/s = sanitize(input(user, "Write something", "Newspaper", "")) - s = user.handle_writing_literacy(user, sanitize(s)) - if (!s) - return - if (!in_range(src, usr) && src.loc != usr) - return + to_chat(user, SPAN_WARNING("There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?")) + return TRUE + var/s = input(user, "Write something", "Newspaper") as null | message + if(!length(s)) + return TRUE + if(!CanPhysicallyInteractWith(user, src)) + to_chat(user, SPAN_WARNING("You must stay close to \the [src]!")) + return TRUE + if(used_item.do_tool_interaction(TOOL_PEN, user, src, 0, fuel_expenditure = 1) && !QDELETED(src)) //Make it instant, since handle_writing_literacy does the waiting + s = sanitize(s) + s = user.handle_writing_literacy(user, s) src.scribble_page = src.curr_page src.scribble = s src.attack_self(user) - return - + return TRUE + return ..() ////////////////////////////////////helper procs /obj/machinery/newscaster/proc/scan_user(mob/living/user) - if(istype(user,/mob/living/carbon/human)) //User is a human - var/mob/living/carbon/human/human_user = user + if(ishuman(user)) //User is a human + var/mob/living/human/human_user = user var/obj/item/card/id/id = human_user.GetIdCard() if(istype(id)) //Newscaster scans you src.scanned_user = GetNameAndAssignmentFromId(id) @@ -909,23 +929,22 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co src.paper_remaining-- return -//Removed for now so these aren't even checked every tick. Left this here in-case Agouri needs it later. -///obj/machinery/newscaster/process() //Was thinking of doing the icon update through process, but multiple iterations per second does not -// return //bode well with a newscaster network of 10+ machines. Let's just return it, as it's added in the machines list. +/obj/machinery/newscaster/proc/reset_alert() + alert = 0 + update_icon() -/obj/machinery/newscaster/proc/newsAlert(var/news_call) //This isn't Agouri's work, for it is ugly and vile. - var/turf/T = get_turf(src) //Who the fuck uses spawn(600) anyway, jesus christ +/obj/machinery/newscaster/proc/newsAlert(var/news_call) if(news_call) - for(var/mob/O in hearers(world.view-1, T)) - O.show_message("[src.name] beeps, \"[news_call]\"",2) + audible_message("[src.name] beeps, \"[news_call]\"") src.alert = 1 src.update_icon() - spawn(300) - src.alert = 0 - src.update_icon() + addtimer(CALLBACK(src, PROC_REF(reset_alert)), alert_delay, TIMER_UNIQUE | TIMER_OVERRIDE) //stay alert for the full time if we get a new one playsound(src.loc, 'sound/machines/twobeep.ogg', 75, 1) else - for(var/mob/O in hearers(world.view-1, T)) - O.show_message("[src.name] beeps, \"Attention! Wanted issue distributed!\"",2) + audible_message("[src.name] beeps, \"Attention! Wanted issue distributed!\"") playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 75, 1) - return + +// security newscaster preset +/obj/machinery/newscaster/security_unit + base_type = /obj/machinery/newscaster + securityCaster = TRUE \ No newline at end of file diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm index 8e99b26a6c8f..bb2365dbc314 100644 --- a/code/game/machinery/nuclear_bomb.dm +++ b/code/game/machinery/nuclear_bomb.dm @@ -1,20 +1,22 @@ -var/bomb_set +var/global/bomb_set /obj/machinery/nuclearbomb name = "\improper Nuclear Fission Explosive" desc = "Uh oh. RUN!" icon = 'icons/obj/nuke.dmi' icon_state = "idle" - density = 1 + density = TRUE use_power = POWER_USE_OFF uncreated_component_parts = null - unacidable = 1 interact_offline = TRUE + wires = /datum/wires/nuclearbomb var/deployable = 0 var/extended = 0 var/lighthack = 0 var/timeleft = 120 + var/minTime = 120 + var/maxTime = 600 var/timing = 0 var/r_code = "ADMIN" var/code = "" @@ -23,8 +25,6 @@ var/bomb_set var/obj/item/disk/nuclear/auth = null var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. var/lastentered - var/previous_level = "" - wires = /datum/wires/nuclearbomb var/decl/security_level/original_level /obj/machinery/nuclearbomb/Initialize() @@ -36,16 +36,16 @@ var/bomb_set auth = null return ..() -/obj/machinery/nuclearbomb/Process(var/wait) +/obj/machinery/nuclearbomb/Process(wait, tick) if(timing) timeleft = max(timeleft - (wait / 10), 0) playsound(loc, 'sound/items/timer.ogg', 50) if(timeleft <= 0) - addtimer(CALLBACK(src, .proc/explode), 0) + addtimer(CALLBACK(src, PROC_REF(explode)), 0) SSnano.update_uis(src) -/obj/machinery/nuclearbomb/attackby(obj/item/O, mob/user, params) - if(isScrewdriver(O)) +/obj/machinery/nuclearbomb/attackby(obj/item/used_item, mob/user, params) + if(IS_SCREWDRIVER(used_item)) add_fingerprint(user) if(auth) if(panel_open == 0) @@ -67,88 +67,89 @@ var/bomb_set to_chat(user, "You screw the control panel of \the [src] back on.") playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) flick("lock", src) - return + return TRUE - if(panel_open && isMultitool(O) || isWirecutter(O)) - return attack_hand(user) + if(panel_open && (IS_MULTITOOL(used_item) || IS_WIRECUTTER(used_item))) + return attack_hand_with_interaction_checks(user) if(extended) - if(istype(O, /obj/item/disk/nuclear)) - if(!user.unEquip(O, src)) - return - auth = O + if(istype(used_item, /obj/item/disk/nuclear)) + if(!user.try_unequip(used_item, src)) + return TRUE + auth = used_item add_fingerprint(user) - return attack_hand(user) + return attack_hand_with_interaction_checks(user) if(anchored) switch(removal_stage) if(0) - if(isWelder(O)) - var/obj/item/weldingtool/WT = O - if(!WT.isOn()) return - if(WT.get_fuel() < 5) // uses up 5 fuel. + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(!welder.isOn()) return TRUE + if(welder.get_fuel() < 5) // uses up 5 fuel. to_chat(user, "You need more fuel to complete this task.") - return + return TRUE - user.visible_message("[user] starts cutting loose the anchoring bolt covers on [src].", "You start cutting loose the anchoring bolt covers with [O]...") + user.visible_message("[user] starts cutting loose the anchoring bolt covers on [src].", "You start cutting loose the anchoring bolt covers with [used_item]...") - if(do_after(user,40, src)) - if(!src || !user || !WT.remove_fuel(5, user)) return + if(do_after(user, 4 SECONDS, src)) + if(QDELETED(src) || QDELETED(user) || !welder.weld(5, user)) return TRUE user.visible_message("\The [user] cuts through the bolt covers on \the [src].", "You cut through the bolt cover.") removal_stage = 1 - return + return TRUE if(1) - if(isCrowbar(O)) - user.visible_message("[user] starts forcing open the bolt covers on [src].", "You start forcing open the anchoring bolt covers with [O]...") + if(IS_CROWBAR(used_item)) + user.visible_message("[user] starts forcing open the bolt covers on [src].", "You start forcing open the anchoring bolt covers with [used_item]...") - if(do_after(user, 15, src)) - if(!src || !user) return + if(do_after(user, 1.5 SECONDS, src)) + if(QDELETED(src) || QDELETED(user)) return TRUE user.visible_message("\The [user] forces open the bolt covers on \the [src].", "You force open the bolt covers.") removal_stage = 2 - return + return TRUE if(2) - if(isWelder(O)) - var/obj/item/weldingtool/WT = O - if(!WT.isOn()) return - if (WT.get_fuel() < 5) // uses up 5 fuel. + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(!welder.isOn()) return TRUE + if (welder.get_fuel() < 5) // uses up 5 fuel. to_chat(user, "You need more fuel to complete this task.") - return + return TRUE - user.visible_message("[user] starts cutting apart the anchoring system sealant on [src].", "You start cutting apart the anchoring system's sealant with [O]...") + user.visible_message("[user] starts cutting apart the anchoring system sealant on [src].", "You start cutting apart the anchoring system's sealant with [used_item]...") - if(do_after(user, 40, src)) - if(!src || !user || !WT.remove_fuel(5, user)) return + if(do_after(user, 4 SECONDS, src)) + if(QDELETED(src) || QDELETED(user) || !welder.weld(5, user)) return TRUE user.visible_message("\The [user] cuts apart the anchoring system sealant on \the [src].", "You cut apart the anchoring system's sealant.") removal_stage = 3 - return + return TRUE if(3) - if(isWrench(O)) + if(IS_WRENCH(used_item)) user.visible_message("[user] begins unwrenching the anchoring bolts on [src].", "You begin unwrenching the anchoring bolts...") - if(do_after(user, 50, src)) - if(!src || !user) return + if(do_after(user, 5 SECONDS, src)) + if(QDELETED(src) || QDELETED(user)) return TRUE user.visible_message("[user] unwrenches the anchoring bolts on [src].", "You unwrench the anchoring bolts.") removal_stage = 4 - return + return TRUE if(4) - if(isCrowbar(O)) + if(IS_CROWBAR(used_item)) user.visible_message("[user] begins lifting [src] off of the anchors.", "You begin lifting the device off the anchors...") - if(do_after(user, 80, src)) - if(!src || !user) return + if(do_after(user, 8 SECONDS, src)) + if(QDELETED(src) || QDELETED(user)) return TRUE user.visible_message("\The [user] crowbars \the [src] off of the anchors. It can now be moved.", "You jam the crowbar under the nuclear device and lift it off its anchors. You can now move it!") - anchored = 0 + anchored = FALSE removal_stage = 5 - return - ..() + return TRUE + return ..() /obj/machinery/nuclearbomb/physical_attack_hand(mob/user) + . = FALSE if(!extended && deployable) . = TRUE if(removal_stage < 5) - src.anchored = 1 + src.anchored = TRUE visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring!") else visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") @@ -219,9 +220,9 @@ var/bomb_set return 1 return 0 -/obj/machinery/nuclearbomb/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/nuclearbomb/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) + return if(href_list["auth"]) if(auth) @@ -229,13 +230,14 @@ var/bomb_set yes_code = 0 auth = null else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/disk/nuclear)) - if(!usr.unEquip(I, src)) - return 1 - auth = I - if(is_auth(usr)) + var/obj/item/used_item = user.get_active_held_item() + if(istype(used_item, /obj/item/disk/nuclear)) + if(!user.try_unequip(used_item, src)) + return TOPIC_HANDLED + auth = used_item + if(is_auth(user)) if(href_list["type"]) + . = TOPIC_REFRESH if(href_list["type"] == "E") if(code == r_code) yes_code = 1 @@ -258,58 +260,62 @@ var/bomb_set if(yes_code) if(href_list["time"]) if(timing) - to_chat(usr, "Cannot alter the timing during countdown.") - return + to_chat(user, SPAN_WARNING("Cannot alter the timing during countdown.")) + return TOPIC_HANDLED var/time = text2num(href_list["time"]) timeleft += time - timeleft = Clamp(timeleft, 120, 600) + timeleft = clamp(timeleft, minTime, maxTime) + . = TOPIC_HANDLED if(href_list["timer"]) if(timing == -1) - return 1 + return TOPIC_NOACTION if(!anchored) - to_chat(usr, "\The [src] needs to be anchored.") - return 1 + to_chat(user, SPAN_WARNING("\The [src] needs to be anchored.")) + return TOPIC_HANDLED if(safety) - to_chat(usr, "The safety is still on.") - return 1 + to_chat(user, SPAN_WARNING("The safety is still on.")) + return TOPIC_HANDLED if(wires.IsIndexCut(NUCLEARBOMB_WIRE_TIMING)) - to_chat(usr, "Nothing happens, something might be wrong with the wiring.") - return 1 + to_chat(user, SPAN_WARNING("Nothing happens, something might be wrong with the wiring.")) + return TOPIC_HANDLED if(!timing && !safety) - start_bomb() + start_bomb(user) + . = TOPIC_HANDLED else check_cutoff() + . = TOPIC_HANDLED if(href_list["safety"]) if (wires.IsIndexCut(NUCLEARBOMB_WIRE_SAFETY)) - to_chat(usr, "Nothing happens, something might be wrong with the wiring.") - return 1 + to_chat(user, SPAN_WARNING("Nothing happens, something might be wrong with the wiring.")) + return TOPIC_HANDLED safety = !safety if(safety) secure_device() update_icon() + return TOPIC_REFRESH if(href_list["anchor"]) if(removal_stage == 5) - anchored = 0 - visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") - return 1 + anchored = FALSE + visible_message(SPAN_WARNING("\The [src] makes a highly-unpleasant crunching noise. It looks like the anchoring bolts have been cut."), blind_message = SPAN_NOTICE("You hear a highly-unpleasant crunching noise.")) + return TOPIC_HANDLED - if(!isinspace()) + if(!isspaceturf(get_turf(src))) anchored = !anchored if(anchored) - visible_message("With a steely snap, bolts slide out of \the [src] and anchor it to the flooring.") + visible_message(SPAN_WARNING("With a steely snap, bolts slide out of \the [src] and anchor it to the flooring."), blind_message = SPAN_NOTICE("You hear a steely snap.")) else secure_device() - visible_message("The anchoring bolts slide back into the depths of \the [src].") + visible_message(SPAN_WARNING("The anchoring bolts slide back into the depths of \the [src]."), blind_message = SPAN_NOTICE("You hear a steely snap.")) + return TOPIC_HANDLED else - to_chat(usr, "There is nothing to anchor to!") - return 1 + to_chat(user, SPAN_WARNING("There is nothing to anchor to!")) -/obj/machinery/nuclearbomb/proc/start_bomb() +/obj/machinery/nuclearbomb/proc/start_bomb(user) timing = 1 - log_and_message_admins("activated the detonation countdown of \the [src]") + log_and_message_admins("activated the detonation countdown of \the [src]", user) bomb_set++ //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) original_level = security_state.current_security_level security_state.set_security_level(security_state.severe_security_level, TRUE) update_icon() @@ -320,12 +326,12 @@ var/bomb_set /obj/machinery/nuclearbomb/proc/secure_device() if(timing <= 0) return - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) security_state.set_security_level(original_level, TRUE) bomb_set-- safety = TRUE timing = 0 - timeleft = Clamp(timeleft, 120, 600) + timeleft = clamp(timeleft, 120, 600) update_icon() /obj/machinery/nuclearbomb/explosion_act(severity) @@ -357,34 +363,21 @@ var/bomb_set icon_state = "idle" //====The nuclear authentication disc==== +var/global/list/obj/item/disk/nuclear/nuke_disks = list() /obj/item/disk/nuclear name = "nuclear authentication disk" desc = "Better keep this safe." - icon = 'icons/obj/items/device/diskette.dmi' - icon_state = "nucleardisk" - item_state = "card-id" - w_class = ITEM_SIZE_TINY - + color = COLOR_GRAY20 + label = "label_warning" /obj/item/disk/nuclear/Initialize() . = ..() - nuke_disks |= src - // Can never be quite sure that a game mode has been properly initiated or not at this point, so always register - GLOB.moved_event.register(src, src, /obj/item/disk/nuclear/proc/check_z_level) - -/obj/item/disk/nuclear/proc/check_z_level() - if(!(istype(SSticker.mode, /datum/game_mode/nuclear))) - GLOB.moved_event.unregister(src, src, /obj/item/disk/nuclear/proc/check_z_level) // However, when we are certain unregister if necessary - return - var/turf/T = get_turf(src) - if(!T || isNotStationLevel(T.z)) - qdel(src) + global.nuke_disks |= src /obj/item/disk/nuclear/Destroy() - GLOB.moved_event.unregister(src, src, /obj/item/disk/nuclear/proc/check_z_level) - nuke_disks -= src - if(!nuke_disks.len) - var/turf/T = pick_area_turf(/area/maintenance, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) + global.nuke_disks -= src + if(!length(global.nuke_disks)) + var/turf/T = pick_area_turf_by_flag(AREA_FLAG_MAINTENANCE, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) if(T) var/obj/D = new /obj/item/disk/nuclear(T) log_and_message_admins("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).", location = T) @@ -393,18 +386,21 @@ var/bomb_set return ..() //====the nuclear football (holds the disk and instructions)==== -/obj/item/storage/secure/briefcase/nukedisk +/obj/item/secure_storage/briefcase/nukedisk desc = "A large briefcase with a digital locking system." - startswith = list( + +/obj/item/secure_storage/briefcase/nukedisk/WillContain() + return list( /obj/item/disk/nuclear, /obj/item/pinpointer, /obj/item/folder/envelope/nuke_instructions, - /obj/item/modular_computer/laptop/preset/custom_loadout/cheap/ + /obj/item/modular_computer/laptop/preset/custom_loadout/cheap ) -/obj/item/storage/secure/briefcase/nukedisk/examine(mob/user) +/obj/item/secure_storage/briefcase/nukedisk/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user,"On closer inspection, you see \a [GLOB.using_map.company_name] emblem is etched into the front of it.") + if(distance <= 1) + . += "On closer inspection, you see \a [global.using_map.company_name] emblem is etched into the front of it." /obj/item/folder/envelope/nuke_instructions name = "instructions envelope" @@ -412,44 +408,45 @@ var/bomb_set /obj/item/folder/envelope/nuke_instructions/Initialize() . = ..() - var/obj/item/paper/R = new(src) - R.set_content("
              Warning: Classified
              [GLOB.using_map.station_name] Self-Destruct System - Instructions


              \ - In the event of a Delta-level emergency, this document will guide you through the activation of the vessel's \ - on-board nuclear self-destruct system. Please read carefully.

              \ - 1) (Optional) Announce the imminent activation to any surviving crew members, and begin evacuation procedures.
              \ - 2) Notify two heads of staff, both with ID cards with access to the ship's Keycard Authentication Devices.
              \ - 3) Proceed to the self-destruct chamber, located on Deck One by the stairwell.
              \ - 4) Unbolt the door and enter the chamber.
              \ - 5) Both heads of staff should stand in front of their own Keycard Authentication Devices. On the KAD interface, select \ - Grant Nuclear Authentication Code. Both heads of staff should then swipe their ID cards simultaneously.
              \ - 6) The KAD will now display the Authentication Code. Memorize this code.
              \ - 7) Insert the nuclear authentication disk into the self-destruct terminal.
              \ - 8) Enter the code into the self-destruct terminal.
              \ - 9) Authentication procedures are now complete. Open the two cabinets containing the nuclear cylinders. They are \ - located on the back wall of the chamber.
              \ - 10) Place the cylinders upon the six nuclear cylinder inserters.
              \ - 11) Activate the inserters. The cylinders will be pulled down into the self-destruct system.
              \ - 12) Return to the terminal. Enter the desired countdown time.
              \ - 13) When ready, disable the safety switch.
              \ - 14) Start the countdown.

              \ - This concludes the instructions.", "vessel self-destruct instructions") + var/obj/item/paper/codes = new(src) + codes.set_content({"
              Warning: Classified
              [global.using_map.station_name] Self-Destruct System - Instructions


              + In the event of a Delta-level emergency, this document will guide you through the activation of the vessel's + on-board nuclear self-destruct system. Please read carefully.

              + 1) (Optional) Announce the imminent activation to any surviving crew members, and begin evacuation procedures.
              + 2) Notify two heads of staff, both with ID cards with access to the ship's Keycard Authentication Devices.
              + 3) Proceed to the self-destruct chamber, located on Deck One by the stairwell.
              + 4) Unbolt the door and enter the chamber.
              + 5) Both heads of staff should stand in front of their own Keycard Authentication Devices. On the KAD interface, select + Grant Nuclear Authentication Code. Both heads of staff should then swipe their ID cards simultaneously.
              + 6) The KAD will now display the Authentication Code. Memorize this code.
              + 7) Insert the nuclear authentication disk into the self-destruct terminal.
              + 8) Enter the code into the self-destruct terminal.
              + 9) Authentication procedures are now complete. Open the two cabinets containing the nuclear cylinders. They are + located on the back wall of the chamber.
              + 10) Place the cylinders upon the six nuclear cylinder inserters.
              + 11) Activate the inserters. The cylinders will be pulled down into the self-destruct system.
              + 12) Return to the terminal. Enter the desired countdown time.
              + 13) When ready, disable the safety switch.
              + 14) Start the countdown.

              + This concludes the instructions."}, + "vessel self-destruct instructions") //stamp the paper - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-hos" - R.stamped += /obj/item/stamp - R.overlays += stampoverlay - R.stamps += "
              This paper has been stamped as 'Top Secret'." + codes.apply_custom_stamp('icons/obj/items/stamps/stamp_cos.dmi', "'Top Secret'") //====vessel self-destruct system==== /obj/machinery/nuclearbomb/station name = "self-destruct terminal" desc = "For when it all gets too much to bear. Do not taunt." icon = 'icons/obj/nuke_station.dmi' - anchored = 1 + anchored = TRUE deployable = 1 extended = 1 + timeleft = 300 + minTime = 300 + maxTime = 900 + var/list/flash_tiles = list() var/list/inserters = list() var/last_turf_state @@ -461,38 +458,26 @@ var/bomb_set /obj/machinery/nuclearbomb/station/Initialize() . = ..() verbs -= /obj/machinery/nuclearbomb/verb/toggle_deployable - for(var/turf/simulated/floor/T in get_area(src)) - if(istype(T.flooring, /decl/flooring/reinforced/circuit/red)) + for(var/turf/floor/T in get_area(src)) + if(istype(T.get_topmost_flooring(), /decl/flooring/reinforced/circuit/red)) flash_tiles += T update_icon() for(var/obj/machinery/self_destruct/ch in get_area(src)) inserters += ch -/obj/machinery/nuclearbomb/station/attackby(obj/item/O, mob/user) - if(isWrench(O)) - return - -/obj/machinery/nuclearbomb/station/Topic(href, href_list) - if((. = ..())) - return +/obj/machinery/nuclearbomb/station/attackby(obj/item/used_item, mob/user) + return TRUE // cannot be moved +/obj/machinery/nuclearbomb/station/OnTopic(mob/user, href_list, datum/topic_state/state) if(href_list["anchor"]) - return - - if(href_list["time"]) - if(timing) - to_chat(usr, "Cannot alter the timing during countdown.") - return - var/time = text2num(href_list["time"]) - timeleft += time - timeleft = Clamp(timeleft, 300, 900) - return 1 + return TOPIC_NOACTION + return ..() -/obj/machinery/nuclearbomb/station/start_bomb() +/obj/machinery/nuclearbomb/station/start_bomb(mob/user) for(var/inserter in inserters) var/obj/machinery/self_destruct/sd = inserter if(!istype(sd) || !sd.armed) - to_chat(usr, "An inserter has not been armed or is damaged.") + to_chat(user, "An inserter has not been armed or is damaged.") return visible_message("Warning. The self-destruct sequence override will be disabled [self_destruct_cutoff] seconds before detonation.") ..() @@ -528,7 +513,7 @@ var/bomb_set high_intensity = rand(3, 6) low_intensity = rand(5, 8) time_to_explosion = world.time + 5 SECONDS - var/turf/T = pick_area_and_turf(GLOB.is_station_but_not_space_or_shuttle_area) + var/turf/T = pick_area_and_turf(global.is_station_but_not_space_or_shuttle_area) explosion(T, range, high_intensity, low_intensity) /obj/machinery/nuclearbomb/station/secure_device() @@ -555,8 +540,8 @@ var/bomb_set if(!last_turf_state || target_icon_state != last_turf_state) for(var/thing in flash_tiles) - var/turf/simulated/floor/T = thing - if(!istype(T.flooring, /decl/flooring/reinforced/circuit/red)) + var/turf/floor/T = thing + if(!istype(T.get_topmost_flooring(), /decl/flooring/reinforced/circuit/red)) flash_tiles -= T continue T.icon_state = target_icon_state diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm index 593b33989e72..7482f522af6c 100644 --- a/code/game/machinery/oxygen_pump.dm +++ b/code/game/machinery/oxygen_pump.dm @@ -1,4 +1,4 @@ -#define TANK_MAX_RELEASE_PRESSURE (3*ONE_ATMOSPHERE) +#define TANK_MAX_RELEASE_PRESSURE (3 ATM) #define TANK_DEFAULT_RELEASE_PRESSURE ONE_ATMOSPHERE /obj/machinery/oxygen_pump @@ -10,17 +10,19 @@ anchored = TRUE var/obj/item/tank/tank - var/mob/living/carbon/breather + var/mob/living/breather var/obj/item/clothing/mask/breath/contained var/spawn_type = /obj/item/tank/emergency/oxygen/engi var/mask_type = /obj/item/clothing/mask/breath/emergency var/icon_state_open = "emerg_open" var/icon_state_closed = "emerg" + var/icon_state_active power_channel = ENVIRON idle_power_usage = 10 active_power_usage = 120 // No idea what the realistic amount would be. + directional_offset = @'{"NORTH":{"y":-24}, "SOUTH":{"y":28}, "EAST":{"x":24}, "WEST":{"x":-24}}' /obj/machinery/oxygen_pump/Initialize() . = ..() @@ -34,30 +36,25 @@ qdel(tank) if(breather) breather.drop_from_inventory(contained) - src.visible_message("The mask rapidly retracts just before /the [src] is destroyed!") + src.visible_message(SPAN_NOTICE("The mask rapidly retracts just before \the [src] is destroyed!")) + breather = null qdel(contained) contained = null - breather = null return ..() -/obj/machinery/oxygen_pump/MouseDrop(var/mob/living/carbon/human/target, src_location, over_location) - ..() - if(istype(target) && CanMouseDrop(target)) - if(!can_apply_to_target(target, usr)) // There is no point in attempting to apply a mask if it's impossible. - return - usr.visible_message("\The [usr] begins placing the mask onto [target]..") - if(do_mob(usr, target, 25)) - if(!can_apply_to_target(target, usr)) - return - // place mask and add fingerprints - usr.visible_message("\The [usr] has placed \the mask on [target]'s mouth.") - attach_mask(target) - src.add_fingerprint(usr) - +/obj/machinery/oxygen_pump/handle_mouse_drop(atom/over, mob/user, params) + if(isliving(over) && can_apply_to_target(over, user)) + user.visible_message(SPAN_NOTICE("\The [user] begins placing the mask onto \the [over]..")) + if(do_mob(user, over, 25) && can_apply_to_target(over, user)) + user.visible_message(SPAN_NOTICE("\The [user] has placed \the [src] over \the [over]'s face.")) + attach_mask(over) + add_fingerprint(user) + return TRUE + . = ..() /obj/machinery/oxygen_pump/physical_attack_hand(mob/user) if((stat & MAINT) && tank) - user.visible_message("\The [user] removes \the [tank] from \the [src].", "You remove \the [tank] from \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] removes \the [tank] from \the [src]."), SPAN_NOTICE("You remove \the [tank] from \the [src].")) user.put_in_hands(tank) src.add_fingerprint(user) tank.add_fingerprint(user) @@ -66,22 +63,23 @@ if(breather) detach_mask(user) return TRUE + return FALSE /obj/machinery/oxygen_pump/interface_interact(mob/user) ui_interact(user) return TRUE -/obj/machinery/oxygen_pump/proc/attach_mask(var/mob/living/carbon/C) - if(C && istype(C)) - contained.dropInto(C.loc) - C.equip_to_slot(contained, slot_wear_mask) +/obj/machinery/oxygen_pump/proc/attach_mask(var/mob/living/subject) + if(istype(subject)) + contained.dropInto(subject.loc) + subject.equip_to_slot(contained, slot_wear_mask_str) if(tank) - tank.forceMove(C) - breather = C + tank.forceMove(subject) + breather = subject -/obj/machinery/oxygen_pump/proc/set_internals(var/mob/living/carbon/C) - if(C && istype(C)) - if(!C.internal && tank) +/obj/machinery/oxygen_pump/proc/set_internals() + if(isliving(breather)) + if(!breather.get_internals() && tank) breather.set_internals(tank) update_use_power(POWER_USE_ACTIVE) @@ -90,85 +88,96 @@ tank.forceMove(src) breather.drop_from_inventory(contained, src) if(user) - visible_message("\The [user] detaches \the [contained] and it rapidly retracts back into \the [src]!") + visible_message(SPAN_NOTICE("\The [user] detaches \the [contained] and it rapidly retracts back into \the [src]!")) else - visible_message("\The [contained] rapidly retracts back into \the [src]!") - if(breather.internals) - breather.internals.icon_state = "internal0" + visible_message(SPAN_NOTICE("\The [contained] rapidly retracts back into \the [src]!")) + breather.refresh_hud_element(HUD_INTERNALS) breather = null update_use_power(POWER_USE_IDLE) -/obj/machinery/oxygen_pump/proc/can_apply_to_target(var/mob/living/carbon/human/target, mob/user) +/obj/machinery/oxygen_pump/proc/can_apply_to_target(var/mob/living/target, mob/user) if(!user) user = target // Check target validity - if(!target.organs_by_name[BP_HEAD]) - to_chat(user, "\The [target] doesn't have a head.") + if(!GET_EXTERNAL_ORGAN(target, BP_HEAD)) + to_chat(user, SPAN_WARNING("\The [target] doesn't have a head.")) return if(!target.check_has_mouth()) - to_chat(user, "\The [target] doesn't have a mouth.") + to_chat(user, SPAN_WARNING("\The [target] doesn't have a mouth.")) + return + if(!target.get_inventory_slot_datum(slot_wear_mask_str)) + to_chat(user, SPAN_WARNING("\The [target] cannot wear a mask.")) return - if(target.wear_mask && target != breather) - to_chat(user, "\The [target] is already wearing a mask.") + var/obj/item/mask = target.get_equipped_item(slot_wear_mask_str) + if(mask && target != breather) + to_chat(user, SPAN_WARNING("\The [target] is already wearing a mask.")) return - if(target.head && (target.head.body_parts_covered & FACE)) - to_chat(user, "Remove their [target.head] first.") + var/obj/item/head = target.get_equipped_item(slot_head_str) + if(head && (head.body_parts_covered & SLOT_FACE)) + to_chat(user, SPAN_WARNING("Remove their [head] first.")) return if(!tank) - to_chat(user, "There is no tank in \the [src].") + to_chat(user, SPAN_WARNING("There is no tank in \the [src].")) return if(stat & MAINT) - to_chat(user, "Please close \the maintenance hatch first.") + to_chat(user, SPAN_WARNING("Please close the maintenance hatch first.")) return if(!Adjacent(target)) - to_chat(user, "Please stay close to \the [src].") + to_chat(user, SPAN_WARNING("Please stay close to \the [src].")) return //when there is a breather: if(breather && target != breather) - to_chat(user, "\The pump is already in use.") + to_chat(user, SPAN_WARNING("The pump is already in use.")) return //Checking if breather is still valid - if(target == breather && target.wear_mask != contained) - to_chat(user, "\The [target] is not using the supplied mask.") + mask = target.get_equipped_item(slot_wear_mask_str) + if(target == breather && (!mask || mask != contained)) + to_chat(user, SPAN_WARNING("\The [target] is not using the supplied mask.")) return return 1 -/obj/machinery/oxygen_pump/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) +/obj/machinery/oxygen_pump/on_update_icon() + if(stat & MAINT) + icon_state = icon_state_open + else if(icon_state_active && use_power == POWER_USE_ACTIVE) // the base type doesn't have an active state + icon_state = icon_state_active + else + icon_state = icon_state_closed + +/obj/machinery/oxygen_pump/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) stat ^= MAINT - user.visible_message("\The [user] [stat & MAINT ? "opens" : "closes"] \the [src].", "You [stat & MAINT ? "open" : "close"] \the [src].") - if(stat & MAINT) - icon_state = icon_state_open - if(!stat) - icon_state = icon_state_closed - //TO-DO: Open icon - if(istype(W, /obj/item/tank) && (stat & MAINT)) + user.visible_message(SPAN_NOTICE("\The [user] [stat & MAINT ? "opens" : "closes"] \the [src]."), SPAN_NOTICE("You [stat & MAINT ? "open" : "close"] \the [src].")) + queue_icon_update() + return TRUE + if(istype(used_item, /obj/item/tank)) + if(!(stat & MAINT)) + to_chat(user, SPAN_WARNING("Please open the maintenance hatch first.")) + return TRUE if(tank) - to_chat(user, "\The [src] already has a tank installed!") - else - if(!user.unEquip(W, src)) - return - tank = W - user.visible_message("\The [user] installs \the [tank] into \the [src].", "You install \the [tank] into \the [src].") - src.add_fingerprint(user) - if(istype(W, /obj/item/tank) && !stat) - to_chat(user, "Please open the maintenance hatch first.") - -/obj/machinery/oxygen_pump/examine(mob/user) + to_chat(user, SPAN_WARNING("\The [src] already has a tank installed!")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + tank = used_item + user.visible_message(SPAN_NOTICE("\The [user] installs \the [tank] into \the [src]."), SPAN_NOTICE("You install \the [tank] into \the [src].")) + src.add_fingerprint(user) + return TRUE + return FALSE // TODO: should this be a parent call? do we want this to be (de)constructable? + +/obj/machinery/oxygen_pump/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(tank) - to_chat(user, "The meter shows [round(tank.air_contents.return_pressure())]") + . += "The meter shows [round(tank.air_contents.return_pressure())]." else - to_chat(user, "It is missing a tank!") - + . += SPAN_WARNING("It is missing a tank!") /obj/machinery/oxygen_pump/Process() - if(breather) + if(istype(breather)) if(!can_apply_to_target(breather)) detach_mask() - else if(!breather.internal && tank) - set_internals(breather) - + else if(!breather.get_internals() && tank) + set_internals() //Create rightclick to view tank settings /obj/machinery/oxygen_pump/verb/settings() @@ -181,7 +190,7 @@ /obj/machinery/oxygen_pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] if(!tank) - to_chat(usr, "It is missing a tank!") + to_chat(user, SPAN_WARNING("It is missing a tank!")) data["tankPressure"] = 0 data["releasePressure"] = 0 data["defaultReleasePressure"] = 0 @@ -216,9 +225,9 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/oxygen_pump/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/oxygen_pump/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) + return if (href_list["dist_p"]) if (href_list["dist_p"] == "reset") @@ -229,4 +238,46 @@ var/cp = text2num(href_list["dist_p"]) tank.distribute_pressure += cp tank.distribute_pressure = min(max(round(tank.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) - return 1 + . = TOPIC_REFRESH // Refreshing is handled in machinery/Topic + +/obj/machinery/oxygen_pump/mobile + name = "portable oxygen pump" + icon = 'icons/obj/machines/medpump.dmi' + desc = "A portable oxygen pump with a retractable mask that you can pull over your face in case of emergencies." + icon_state = "medpump" + icon_state_open = "medpump_open" + icon_state_closed = "medpump" + icon_state_active = "medpump_active" + anchored = FALSE + density = TRUE + +/obj/machinery/oxygen_pump/mobile/stabilizer + name = "portable patient stabilizer" + desc = "A portable oxygen pump with a retractable mask used for stabilizing patients in the field." + icon_state = "patient_stabilizer" + icon_state_closed = "patient_stabilizer" + icon_state_open = "patient_stabilizer_open" + icon_state_active = "patient_stabilizer_active" + +/obj/machinery/oxygen_pump/mobile/stabilizer/Process() + . = ..() + if(!breather) // Safety. + return + if(breather.isSynthetic()) + return + +/* TODO: port modifiers or something similar + breather.add_modifier(breather.stat == DEAD ? /datum/modifier/bloodpump/corpse : /datum/modifier/bloodpump, 6 SECONDS) +*/ + + var/obj/item/organ/internal/lungs/lungs = breather.get_organ(BP_LUNGS, /obj/item/organ/internal/lungs) + if(!lungs) + return + if(lungs.status & ORGAN_DEAD) + breather.adjustOxyLoss(-(rand(1,8))) + else + breather.adjustOxyLoss(-(rand(10,15))) + if(lungs.is_bruised() && prob(30)) + lungs.heal_damage(1) + else + breather.suffocation_counter = max(breather.suffocation_counter - rand(1,5), 0) \ No newline at end of file diff --git a/code/game/machinery/pager.dm b/code/game/machinery/pager.dm index c4295dbe7cda..9bee6cc752c1 100644 --- a/code/game/machinery/pager.dm +++ b/code/game/machinery/pager.dm @@ -1,42 +1,41 @@ -/obj/machinery/pager +/obj/machinery/network/pager name = "departmental pager button" icon = 'icons/obj/objects.dmi' icon_state = "doorbell" desc = "A button used to request the presence of anyone in the department." - anchored = 1 + anchored = TRUE + density = FALSE idle_power_usage = 2 - var/acknowledged = 0 + var/area/location var/last_paged - var/department = DEPT_COMMAND - var/location + var/acknowledged = FALSE + var/department -/obj/machinery/pager/Initialize() +/obj/machinery/network/pager/Initialize() . = ..() + if(!department) + department = SSjobs.departments_by_type[1] if(!location) - var/area/A = get_area(src) - location = A.name + location = get_area(src) -/obj/machinery/pager/attackby(obj/item/W, mob/user) - return attack_hand(user) - -/obj/machinery/pager/interface_interact(mob/living/user) - if(!CanInteract(user, GLOB.default_state)) +/obj/machinery/network/pager/interface_interact(mob/living/user) + if(!CanInteract(user, global.default_topic_state)) return FALSE playsound(src, "button", 60) flick("doorbellpressed",src) activate(user) return TRUE -/obj/machinery/pager/proc/activate(mob/living/user) - if(!powered()) +/obj/machinery/network/pager/proc/activate(mob/living/user) + if(stat & NOPOWER) return - var/obj/machinery/message_server/MS = get_message_server(z) + var/obj/machinery/network/message_server/MS = get_message_server(z) if(!MS) return if(world.time < last_paged + 5 SECONDS) return last_paged = world.time - var/paged = MS.send_to_department(department,"Department page to [location] received. Take", "*page*") + var/paged = MS.send_to_department(department,"Department page to [location.proper_name] received. Take", "*page*") acknowledged = 0 if(paged) playsound(src, 'sound/machines/ping.ogg', 60) @@ -44,31 +43,14 @@ else to_chat(user,"No valid destinations were found for the page.") -/obj/machinery/pager/Topic(href, href_list) - if(..()) - return 1 - if(!powered()) +/obj/machinery/network/pager/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) return if(!acknowledged && href_list["ack"]) playsound(src, 'sound/machines/ping.ogg', 60) visible_message("Page acknowledged.") acknowledged = 1 - var/obj/machinery/message_server/MS = get_message_server(z) - if(!MS) - return - MS.send_to_department(department,"Page to [location] was acknowledged.", "*ack*") - -/obj/machinery/pager/medical - department = DEPT_MEDICAL - -/obj/machinery/pager/cargo - department = DEPT_SUPPLY - -/obj/machinery/pager/security - department = DEPT_SECURITY - -/obj/machinery/pager/science - department = DEPT_SCIENCE - -/obj/machinery/pager/engineering - department = DEPT_ENGINEERING \ No newline at end of file + . = TOPIC_REFRESH + var/obj/machinery/network/message_server/MS = get_message_server(z) + if(MS) + MS.send_to_department(department,"Page to [location.proper_name] was acknowledged.", "*ack*") diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index b0834acf927f..34843e14fd26 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -6,17 +6,17 @@ Buildable meters /obj/item/pipe name = "pipe" desc = "A pipe." - var/pipename - var/connect_types = CONNECT_TYPE_REGULAR - force = 7 + _base_attack_force = 7 icon = 'icons/obj/pipe-item.dmi' icon_state = "simple" randpixel = 5 item_state = "buildpipe" w_class = ITEM_SIZE_NORMAL - level = 2 + level = LEVEL_ABOVE_PLATING obj_flags = OBJ_FLAG_ROTATABLE dir = SOUTH + material = /decl/material/solid/metal/steel + var/connect_types = CONNECT_TYPE_REGULAR var/constructed_path = /obj/machinery/atmospherics/pipe/simple/hidden var/pipe_class = PIPE_CLASS_BINARY var/rotate_class = PIPE_ROTATE_STANDARD @@ -34,7 +34,7 @@ Buildable meters desc = P.desc connect_types = P.connect_types - color = P.pipe_color + set_color(P.pipe_color) icon = P.build_icon icon_state = P.build_icon_state pipe_class = P.pipe_class @@ -42,10 +42,10 @@ Buildable meters constructed_path = P.base_type || P.type //called when a turf is attacked with a pipe item -/obj/item/pipe/afterattack(turf/simulated/floor/target, mob/user, proximity) +/obj/item/pipe/afterattack(turf/floor/target, mob/user, proximity) if(!proximity) return if(istype(target)) - user.unEquip(src, target) + user.try_unequip(src, target) else return ..() @@ -71,74 +71,15 @@ Buildable meters /obj/item/pipe/attack_self(mob/user) return rotate(user) -/obj/item/pipe/proc/build_unary(var/obj/machinery/atmospherics/unary/P, var/pipefailtext) - P.atmos_init() - if (QDELETED(P)) - to_chat(usr, pipefailtext) - return 1 - P.build_network() - if(P.node) - P.node.atmos_init() - P.node.build_network() - return 0 - -/obj/item/pipe/proc/build_binary(var/obj/machinery/atmospherics/pipe/simple/P, var/pipefailtext) - P.atmos_init() - if (QDELETED(P)) - to_chat(usr, pipefailtext) - return 1 - P.build_network() - if(P.node1) - P.node1.atmos_init() - P.node1.build_network() - if(P.node2) - P.node2.atmos_init() - P.node2.build_network() - return 0 - -/obj/item/pipe/proc/build_trinary(var/obj/machinery/atmospherics/pipe/manifold/P, var/pipefailtext) - P.atmos_init() - if (QDELETED(P)) - to_chat(usr, pipefailtext) - return 1 - P.build_network() - if(P.node1) - P.node1.atmos_init() - P.node1.build_network() - if(P.node2) - P.node2.atmos_init() - P.node2.build_network() - if(P.node3) - P.node3.atmos_init() - P.node3.build_network() - return 0 - -/obj/item/pipe/proc/build_quaternary(var/obj/machinery/atmospherics/pipe/manifold4w/P, var/pipefailtext) - P.atmos_init() - if (QDELETED(P)) - to_chat(usr, pipefailtext) - return 1 - P.build_network() - if(P.node1) - P.node1.atmos_init() - P.node1.build_network() - if(P.node2) - P.node2.atmos_init() - P.node2.build_network() - if(P.node3) - P.node3.atmos_init() - P.node3.build_network() - if(P.node4) - P.node4.atmos_init() - P.node4.build_network() - return 0 - -/obj/item/pipe/attackby(var/obj/item/W, var/mob/user) - if(!isWrench(W)) +/obj/item/pipe/attackby(var/obj/item/used_item, var/mob/user) + if(!IS_WRENCH(used_item)) return ..() if (!isturf(loc)) return 1 + construct_pipe(user) + return TRUE +/obj/item/pipe/proc/construct_pipe(mob/user) sanitize_dir() var/obj/machinery/atmospherics/fake_machine = constructed_path var/pipe_dir = base_pipe_initialize_directions(dir, initial(fake_machine.connect_dir_type)) @@ -146,12 +87,9 @@ Buildable meters for(var/obj/machinery/atmospherics/M in loc) if((M.initialize_directions & pipe_dir) && M.check_connect_types_construction(M,src)) // matches at least one direction on either type of pipe & same connection type to_chat(user, "There is already a pipe of the same type at this location.") - return 1 + return // no conflicts found - var/pipefailtext = "There's nothing to connect this pipe section to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" - - //TODO: Move all of this stuff into the various pipe constructors. var/obj/machinery/atmospherics/P = new constructed_path(get_turf(src)) var/datum/extension/parts_stash/stash = get_extension(src, /datum/extension/parts_stash) if(stash) @@ -160,48 +98,27 @@ Buildable meters P.pipe_color = color P.set_dir(dir) P.set_initial_level() + P.build(src) + . = P - if(P.pipe_class == PIPE_CLASS_UNARY) - if(build_unary(P, pipefailtext)) - return 1 - - if(P.pipe_class == PIPE_CLASS_BINARY) - if(build_binary(P, pipefailtext)) - return 1 - - if(P.pipe_class == PIPE_CLASS_TRINARY) - if(build_trinary(P, pipefailtext)) - return 1 - - if(P.pipe_class == PIPE_CLASS_QUATERNARY) - if(build_quaternary(P, pipefailtext)) - return 1 - - if(P.pipe_class == PIPE_CLASS_OMNI) - P.atmos_init() - P.build_network() - - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user.visible_message( \ - "[user] fastens the [src].", \ - "You have fastened the [src].", \ - "You hear ratchet.") + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + if(user) + user.visible_message( \ + "[user] fastens \the [src].", \ + "You have fastened \the [src].", \ + "You hear ratchet.") qdel(src) // remove the pipe item /obj/item/machine_chassis + material = /decl/material/solid/metal/steel var/build_type /obj/item/machine_chassis/Initialize() . = ..() set_extension(src, /datum/extension/parts_stash) -/obj/item/machine_chassis/examine(mob/user, distance) - . = ..() - if(distance <= 2) - to_chat(user, "Use a wrench to secure \the [src] here.") - -/obj/item/machine_chassis/attackby(var/obj/item/W, var/mob/user) - if(!isWrench(W)) +/obj/item/machine_chassis/attackby(var/obj/item/used_item, var/mob/user) + if(!IS_WRENCH(used_item)) return ..() var/obj/machinery/machine = new build_type(get_turf(src), dir, TRUE) var/datum/extension/parts_stash/stash = get_extension(src, /datum/extension/parts_stash) @@ -210,8 +127,9 @@ Buildable meters if(machine.construct_state) machine.construct_state.post_construct(machine) playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "You have fastened the [src].") + to_chat(user, "You have fastened \the [src].") qdel(src) + return TRUE /obj/item/machine_chassis/air_sensor name = "gas sensor" @@ -233,9 +151,6 @@ Buildable meters w_class = ITEM_SIZE_LARGE build_type = /obj/machinery/meter -/obj/item/machine_chassis/pipe_meter/base - build_type = /obj/machinery/meter/buildable - /obj/item/machine_chassis/igniter name = "igniter" desc = "A device which will ignite surrounding gasses." @@ -253,4 +168,4 @@ Buildable meters icon = 'icons/obj/objects.dmi' icon_state = "floor_beacon" // If anyone wants to make better sprite, feel free to do so without asking me. w_class = ITEM_SIZE_NORMAL - build_type = /obj/machinery/power/sensor \ No newline at end of file + build_type = /obj/machinery/power_sensor \ No newline at end of file diff --git a/code/game/machinery/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm index 91a56c8f5be1..6287eafed099 100644 --- a/code/game/machinery/pipe/pipelayer.dm +++ b/code/game/machinery/pipe/pipelayer.dm @@ -5,7 +5,7 @@ name = "automatic pipe layer" icon = 'icons/obj/machines/pipe_dispenser.dmi' icon_state = "pipe_d" - density = 1 + density = TRUE var/turf/old_turf var/old_dir var/on = 0 @@ -14,18 +14,18 @@ var/P_type_t = "" var/max_metal = 50 var/metal = 10 - var/obj/item/wrench/W + var/obj/item/wrench/wrench var/list/Pipes = list("regular pipes"=0,"scrubbers pipes"=31,"supply pipes"=29,"heat exchange pipes"=2, "fuel pipes"=45) /obj/machinery/pipelayer/Initialize() . = ..() - W = new(src) + wrench = new(src) /obj/machinery/pipelayer/Move(new_turf,M_Dir) - ..() + . = ..() if(on && a_dis) - dismantleFloor(old_turf) + dismantle_floor(old_turf) layPipe(old_turf,M_Dir,old_dir) old_turf = new_turf @@ -39,32 +39,32 @@ user.visible_message("[user] has [!on?"de":""]activated \the [src].", "You [!on?"de":""]activate \the [src].") return TRUE -/obj/machinery/pipelayer/attackby(var/obj/item/W, var/mob/user) +/obj/machinery/pipelayer/attackby(var/obj/item/used_item, var/mob/user) - if(isWrench(W)) + if(IS_WRENCH(used_item)) P_type_t = input("Choose pipe type", "Pipe type") as null|anything in Pipes P_type = Pipes[P_type_t] user.visible_message("[user] has set \the [src] to manufacture [P_type_t].", "You set \the [src] to manufacture [P_type_t].") - return + return TRUE - if(isCrowbar(W)) + if(IS_CROWBAR(used_item)) a_dis=!a_dis user.visible_message("[user] has [!a_dis?"de":""]activated auto-dismantling.", "You [!a_dis?"de":""]activate auto-dismantling.") - return + return TRUE - if(istype(W, /obj/item/stack/material) && W.get_material_type() == /decl/material/solid/metal/steel) + if(istype(used_item, /obj/item/stack/material) && used_item.get_material_type() == /decl/material/solid/metal/steel) - var/result = load_metal(W) + var/result = load_metal(used_item) if(isnull(result)) - to_chat(user, "Unable to load [W] - no metal found.") + to_chat(user, "Unable to load [used_item] - no metal found.") else if(!result) to_chat(user, "\The [src] is full.") else user.visible_message("[user] has loaded metal into \the [src].", "You load metal into \the [src]") - return + return TRUE - if(isScrewdriver(W)) + if(IS_SCREWDRIVER(used_item)) if(metal) var/m = round(input(usr,"Please specify the amount of metal to remove","Remove metal",min(round(metal),50)) as num, 1) m = min(m, 50) @@ -72,17 +72,16 @@ m = round(m) if(m) use_metal(m) - var/obj/item/stack/material/steel/MM = new (get_turf(src)) - MM.amount = m - user.visible_message("[user] removes [m] sheet\s of metal from the \the [src].", "You remove [m] sheet\s of metal from \the [src]") + SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(src), m) + user.visible_message(SPAN_NOTICE("[user] removes [m] sheet\s of metal from \the [src]."), SPAN_NOTICE("You remove [m] sheet\s of metal from \the [src]")) else to_chat(user, "\The [src] is empty.") - return - ..() + return TRUE + return ..() -/obj/machinery/pipelayer/examine(mob/user) +/obj/machinery/pipelayer/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "\The [src] has [metal] sheet\s, is set to produce [P_type_t], and auto-dismantling is [!a_dis?"de":""]activated.") + . += "\The [src] has [metal] sheet\s, is set to produce [P_type_t], and auto-dismantling is [!a_dis?"de":""]activated." /obj/machinery/pipelayer/proc/reset() on=0 @@ -108,11 +107,11 @@ metal-=amount return 1 -/obj/machinery/pipelayer/proc/dismantleFloor(var/turf/new_turf) - if(istype(new_turf, /turf/simulated/floor)) - var/turf/simulated/floor/T = new_turf +/obj/machinery/pipelayer/proc/dismantle_floor(var/turf/new_turf) + if(istype(new_turf, /turf/floor)) + var/turf/floor/T = new_turf if(!T.is_plating()) - T.make_plating(!(T.broken || T.burnt)) + T.clear_flooring(place_product = !T.is_floor_damaged()) return new_turf.is_plating() /obj/machinery/pipelayer/proc/layPipe(var/turf/w_turf,var/M_Dir,var/old_dir) @@ -130,6 +129,6 @@ var/obj/item/pipe/P = new(w_turf) P.set_dir(p_dir) - P.attackby(W , src) + P.attackby(wrench , src) return 1 diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 06ee1898fdce..af1f1e4423b9 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -11,17 +11,16 @@ name = "turret" icon = 'icons/obj/turrets.dmi' icon_state = "turretCover" - anchored = 1 + anchored = TRUE - density = 0 + density = FALSE idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power power_channel = EQUIP //drains power from the EQUIPMENT channel + max_health = 80 var/raised = 0 //if the turret cover is "open" and the turret is raised var/raising= 0 //if the turret is currently opening or closing its cover - var/health = 80 //the turret's health - var/maxhealth = 80 //turrets maximal health. var/auto_repair = 0 //if 1 the turret slowly repairs itself. var/locked = 1 //if the turret's behaviour control access is locked var/controllock = 0 //if the turret responds to control panels @@ -54,8 +53,6 @@ var/shot_sound //what sound should play when the turret fires var/eshot_sound //what sound should play when the emagged turret fires - var/datum/effect/effect/system/spark_spread/spark_system //the spark system, used for generating... sparks? - var/wrenching = 0 var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range @@ -77,32 +74,10 @@ lethal = 1 installation = /obj/item/gun/energy/laser -/obj/machinery/porta_turret/malf_upgrade(var/mob/living/silicon/ai/user) - ..() - ailock = 0 - malf_upgraded = 1 - to_chat(user, "\The [src] has been upgraded. It's damage and rate of fire has been increased. Auto-regeneration system has been enabled. Power usage has increased.") - maxhealth = round(initial(maxhealth) * 1.5) - shot_delay = round(initial(shot_delay) / 2) - auto_repair = 1 - change_power_consumption(round(initial(active_power_usage) * 5), POWER_USE_ACTIVE) - return 1 - /obj/machinery/porta_turret/Initialize() . = ..() - - //Sets up a spark system - spark_system = new /datum/effect/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) - setup() -/obj/machinery/porta_turret/Destroy() - qdel(spark_system) - spark_system = null - . = ..() - /obj/machinery/porta_turret/proc/setup() var/obj/item/gun/energy/E = installation //All energy-based weapons are applicable //var/obj/item/ammo_casing/shottype = E.projectile_type @@ -120,7 +95,7 @@ iconholder = 1 eprojectile = /obj/item/projectile/beam - if(/obj/item/gun/energy/captain) + if(/obj/item/gun/energy/retro/captain) iconholder = 1 if(/obj/item/gun/energy/lasercannon) @@ -140,7 +115,7 @@ eshot_sound = 'sound/weapons/Laser.ogg' egun = 1 -var/list/turret_icons +var/global/list/turret_icons /obj/machinery/porta_turret/on_update_icon() if(!turret_icons) @@ -153,7 +128,7 @@ var/list/turret_icons if(stat & BROKEN) icon_state = "destroyed_target_prism" else if(raised || raising) - if(powered() && enabled) + if(!(stat & NOPOWER) && enabled) if(iconholder) //lasers have a orange icon icon_state = "orange_target_prism" @@ -218,15 +193,15 @@ var/list/turret_icons return STATUS_CLOSE if(!anchored) - to_chat(usr, "\The [src] has to be secured first!") + to_chat(user, "\The [src] has to be secured first!") return STATUS_CLOSE return ..() -/obj/machinery/porta_turret/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/porta_turret/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) + return if(href_list["command"] && href_list["value"]) var/value = text2num(href_list["value"]) @@ -246,50 +221,46 @@ var/list/turret_icons check_access = value else if(href_list["command"] == "check_anomalies") check_anomalies = value + . = TOPIC_REFRESH + +/obj/machinery/porta_turret/physically_destroyed(skip_qdel) + if(installation) + var/obj/item/gun/energy/Gun = new installation(loc) + var/obj/item/cell/power_supply = Gun.get_cell() + power_supply?.charge = gun_charge + Gun.update_icon() + if(prob(50)) + SSmaterials.create_object(/decl/material/solid/metal/steel, loc, rand(1,4)) + if(prob(50)) + new /obj/item/assembly/prox_sensor(loc) + . = ..() - return 1 - -/obj/machinery/porta_turret/power_change() - if(powered()) - stat &= ~NOPOWER - queue_icon_update() - else - spawn(rand(0, 15)) - stat |= NOPOWER - queue_icon_update() - - -/obj/machinery/porta_turret/attackby(obj/item/I, mob/user) +// TODO: remove these or refactor to use construct states +/obj/machinery/porta_turret/attackby(obj/item/used_item, mob/user) if(stat & BROKEN) - if(isCrowbar(I)) + if(IS_CROWBAR(used_item)) //If the turret is destroyed, you can remove it with a crowbar to //try and salvage its components to_chat(user, "You begin prying the metal coverings off.") if(do_after(user, 20, src)) if(prob(70)) to_chat(user, "You remove the turret and salvage some components.") - if(installation) - var/obj/item/gun/energy/Gun = new installation(loc) - Gun.power_supply.charge = gun_charge - Gun.update_icon() - if(prob(50)) - new /obj/item/stack/material/steel(loc, rand(1,4)) - if(prob(50)) - new /obj/item/assembly/prox_sensor(loc) + physically_destroyed() else to_chat(user, "You remove the turret but did not manage to salvage anything.") - qdel(src) // qdel + return TRUE + return FALSE - else if(isWrench(I)) + else if(IS_WRENCH(used_item)) if(enabled || raised) to_chat(user, "You cannot unsecure an active turret!") - return + return TRUE if(wrenching) to_chat(user, "Someone is already [anchored ? "un" : ""]securing the turret!") - return - if(!anchored && isinspace()) + return TRUE + if(!anchored && isspaceturf(get_turf(src))) to_chat(user, "Cannot secure turrets in space!") - return + return TRUE user.visible_message( \ "[user] begins [anchored ? "un" : ""]securing the turret.", \ @@ -297,21 +268,16 @@ var/list/turret_icons ) wrenching = 1 - if(do_after(user, 50, src)) + if(do_after(user, 5 SECONDS, src)) //This code handles moving the turret around. After all, it's a portable turret! - if(!anchored) - playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) - anchored = 1 - update_icon() - to_chat(user, "You secure the exterior bolts on the turret.") - else if(anchored) - playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) - anchored = 0 - to_chat(user, "You unsecure the exterior bolts on the turret.") - update_icon() + playsound(loc, 'sound/items/Ratchet.ogg', 100, TRUE) + anchored = !anchored + update_icon() + to_chat(user, "You [anchored ? "secure" : "unsecure"] the exterior bolts on [src].") wrenching = 0 + return TRUE - else if(istype(I, /obj/item/card/id)||istype(I, /obj/item/modular_computer)) + else if(istype(used_item, /obj/item/card/id)||istype(used_item, /obj/item/modular_computer)) //Behavior lock/unlock mangement if(allowed(user)) locked = !locked @@ -319,18 +285,20 @@ var/list/turret_icons updateUsrDialog() else to_chat(user, "Access denied.") + return TRUE else //if the turret was attacked with the intention of harming it: + var/force = used_item.expend_attack_force(user) * 0.5 user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - take_damage(I.force * 0.5) - if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off + take_damage(force, used_item.atom_damage_type) + if(force > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off if(!attacked && !emagged) attacked = 1 spawn() - sleep(60) + sleep(6 SECONDS) attacked = 0 - ..() + return TRUE /obj/machinery/porta_turret/emag_act(var/remaining_charges, var/mob/user) if(!emagged) @@ -346,16 +314,16 @@ var/list/turret_icons enabled = 1 //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here return 1 -/obj/machinery/porta_turret/take_damage(var/force) +/obj/machinery/porta_turret/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) if(!raised && !raising) - force = force / 8 - if(force < 5) + damage = damage / 8 + if(damage < 5) return - health -= force - if (force > 5 && prob(45)) - spark_system.start() - if(health <= 0) + current_health -= damage + if (damage > 5 && prob(45)) + spark_at(src, amount = 5) + if(current_health <= 0) die() //the death process :( /obj/machinery/porta_turret/bullet_act(obj/item/projectile/Proj) @@ -389,7 +357,7 @@ var/list/turret_icons disabled = 1 var/power = 4 - severity - addtimer(CALLBACK(src,/obj/machinery/porta_turret/proc/enable), rand(60*power,600*power)) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/porta_turret, enable)), rand(60*power,600*power)) ..() @@ -401,19 +369,20 @@ var/list/turret_icons . = ..() if(. && !QDELETED(src)) if(severity == 1 || (severity == 2 && prob(25))) - physically_destroyed(src) + physically_destroyed() else if(severity == 2) - take_damage(initial(health) * 8) + take_damage(initial(current_health) * 8) else - take_damage(initial(health) * 8 / 3) + take_damage(initial(current_health) * 8 / 3) /obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0 - health = 0 + current_health = 0 set_broken(TRUE) - spark_system.start() //creates some sparks because they look cool + spark_at(src, amount = 5) atom_flags |= ATOM_FLAG_CLIMBABLE // they're now climbable /obj/machinery/porta_turret/Process() + if(stat & (NOPOWER|BROKEN)) //if the turret has no power or is broken, make the turret pop down if it hasn't already popDown() @@ -430,13 +399,13 @@ var/list/turret_icons for(var/mob/M in mobs_in_view(world.view, src)) assess_and_assign(M, targets, secondarytargets) - if(!tryToShootAt(targets)) - if(!tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets - popDown() // no valid targets, close the cover + if(!tryToShootAt(targets) && !tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets + popDown() // no valid targets, close the cover - if(auto_repair && (health < maxhealth)) + var/current_max_health = get_max_health() + if(auto_repair && (current_health < current_max_health)) use_power_oneoff(20000) - health = min(health+1, maxhealth) // 1HP for 20kJ + current_health = min(current_health+1, current_max_health) // 1HP for 20kJ /obj/machinery/porta_turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets) switch(assess_living(L)) @@ -446,15 +415,12 @@ var/list/turret_icons secondarytargets += L /obj/machinery/porta_turret/proc/assess_living(var/mob/living/L) - if(!istype(L)) + if(!istype(L) || !L.simulated) return TURRET_NOT_TARGET if(L.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var return TURRET_NOT_TARGET - if(!L) - return TURRET_NOT_TARGET - if(!emagged && issilicon(L)) // Don't target silica return TURRET_NOT_TARGET @@ -464,7 +430,7 @@ var/list/turret_icons if(get_dist(src, L) > 7) //if it's too far away, why bother? return TURRET_NOT_TARGET - if(!check_trajectory(L, src)) //check if we have true line of sight + if(!(L in check_trajectory(L, src))) //check if we have true line of sight return TURRET_NOT_TARGET if(emagged) // If emagged not even the dead get a rest @@ -474,44 +440,39 @@ var/list/turret_icons return TURRET_NOT_TARGET if(check_synth) //If it's set to attack all non-silicons, target them! - if(L.lying) + if(L.current_posture.prone) return lethal ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET return TURRET_PRIORITY_TARGET - if(iscuffed(L)) // If the target is handcuffed, leave it alone + if(iscuffed(L)) // If the target is cuffed, leave it alone return TURRET_NOT_TARGET if(isanimal(L) || issmall(L)) // Animals are not so dangerous return check_anomalies ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET - if(ishuman(L)) //if the target is a human, analyze threat level - if(assess_perp(L) < 4) - return TURRET_NOT_TARGET //if threat level < 4, keep going + if(assess_perp(L) < 4) //if the target is a human, analyze threat level + return TURRET_NOT_TARGET //if threat level < 4, keep going - if(L.lying) //if the perp is lying down, it's still a target but a less-important target + if(L.current_posture.prone) //if the perp is lying down, it's still a target but a less-important target return lethal ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET return TURRET_PRIORITY_TARGET //if the perp has passed all previous tests, congrats, it is now a "shoot-me!" nominee -/obj/machinery/porta_turret/proc/assess_perp(var/mob/living/carbon/human/H) - if(!H || !istype(H)) +/obj/machinery/porta_turret/proc/assess_perp(var/mob/living/perp) + if(!istype(perp)) return 0 - if(emagged) return 10 - - return H.assess_perp(src, check_access, check_weapons, check_records, check_arrest) + return perp.assess_perp(src, check_access, check_weapons, check_records, check_arrest) /obj/machinery/porta_turret/proc/tryToShootAt(var/list/mob/living/targets) - if(targets.len && last_target && (last_target in targets) && target(last_target)) + if(length(targets) && last_target && (last_target in targets) && target(last_target)) return 1 - while(targets.len > 0) - var/mob/living/M = pick(targets) - targets -= M + while(length(targets)) + var/mob/living/M = pick_n_take(targets) if(target(M)) - return 1 - + return TRUE /obj/machinery/porta_turret/proc/popUp() //pops the turret up if(disabled) @@ -636,211 +597,6 @@ var/list/turret_icons src.power_change() -/* - Portable turret constructions - Known as "turret frame"s -*/ - -/obj/machinery/porta_turret_construct - name = "turret frame" - icon = 'icons/obj/turrets.dmi' - icon_state = "turret_frame" - density=1 - var/target_type = /obj/machinery/porta_turret // The type we intend to build - var/build_step = 0 //the current step in the building process - var/finish_name="turret" //the name applied to the product turret - var/installation = null //the gun type installed - var/gun_charge = 0 //the gun charge of the gun type installed - - -/obj/machinery/porta_turret_construct/attackby(obj/item/I, mob/user) - //this is a bit unwieldy but self-explanatory - switch(build_step) - if(0) //first step - if(isWrench(I) && !anchored) - playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) - to_chat(user, "You secure the external bolts.") - anchored = 1 - build_step = 1 - return - - else if(isCrowbar(I) && !anchored) - playsound(loc, 'sound/items/Crowbar.ogg', 75, 1) - to_chat(user, "You dismantle the turret construction.") - new /obj/item/stack/material/steel( loc, 5) - qdel(src) - return - - if(1) - if(istype(I, /obj/item/stack/material) && I.get_material_type() == /decl/material/solid/metal/steel) - var/obj/item/stack/M = I - if(M.use(2)) - to_chat(user, "You add some metal armor to the interior frame.") - build_step = 2 - icon_state = "turret_frame2" - else - to_chat(user, "You need two sheets of metal to continue construction.") - return - - else if(istype(I, /obj/item/wrench)) - playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) - to_chat(user, "You unfasten the external bolts.") - anchored = 0 - build_step = 0 - return - - - if(2) - if(istype(I, /obj/item/wrench)) - playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) - to_chat(user, "You bolt the metal armor into place.") - build_step = 3 - return - - else if(isWelder(I)) - var/obj/item/weldingtool/WT = I - if(!WT.isOn()) - return - if(WT.get_fuel() < 5) //uses up 5 fuel. - to_chat(user, "You need more fuel to complete this task.") - return - - playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) - if(do_after(user, 20, src)) - if(!src || !WT.remove_fuel(5, user)) return - build_step = 1 - to_chat(user, "You remove the turret's interior metal armor.") - new /obj/item/stack/material/steel( loc, 2) - return - - - if(3) - if(istype(I, /obj/item/gun/energy)) //the gun installation part - - if(isrobot(user)) - return - var/obj/item/gun/energy/E = I //typecasts the item to an energy gun - if(!user.unEquip(I)) - to_chat(user, "\the [I] is stuck to your hand, you cannot put it in \the [src]") - return - installation = I.type //installation becomes I.type - gun_charge = E.power_supply.charge //the gun's charge is stored in gun_charge - to_chat(user, "You add [I] to the turret.") - target_type = /obj/machinery/porta_turret - - build_step = 4 - qdel(I) //delete the gun :( - return - - else if(istype(I, /obj/item/wrench)) - playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) - to_chat(user, "You remove the turret's metal armor bolts.") - build_step = 2 - return - - if(4) - if(isprox(I)) - build_step = 5 - if(!user.unEquip(I)) - to_chat(user, "\the [I] is stuck to your hand, you cannot put it in \the [src]") - return - to_chat(user, "You add the prox sensor to the turret.") - qdel(I) - return - - //attack_hand() removes the gun - - if(5) - if(isScrewdriver(I)) - playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) - build_step = 6 - to_chat(user, "You close the internal access hatch.") - return - - //attack_hand() removes the prox sensor - - if(6) - if(istype(I, /obj/item/stack/material) && I.get_material_type() == /decl/material/solid/metal/steel) - var/obj/item/stack/M = I - if(M.use(2)) - to_chat(user, "You add some metal armor to the exterior frame.") - build_step = 7 - else - to_chat(user, "You need two sheets of metal to continue construction.") - return - - else if(istype(I, /obj/item/screwdriver)) - playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) - build_step = 5 - to_chat(user, "You open the internal access hatch.") - return - - if(7) - if(isWelder(I)) - var/obj/item/weldingtool/WT = I - if(!WT.isOn()) return - if(WT.get_fuel() < 5) - to_chat(user, "You need more fuel to complete this task.") - - playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) - if(do_after(user, 30, src)) - if(!src || !WT.remove_fuel(5, user)) - return - build_step = 8 - to_chat(user, "You weld the turret's armor down.") - - //The final step: create a full turret - var/obj/machinery/porta_turret/Turret = new target_type(loc) - Turret.SetName(finish_name) - Turret.installation = installation - Turret.gun_charge = gun_charge - Turret.enabled = 0 - Turret.setup() - - qdel(src) // qdel - - else if(isCrowbar(I)) - playsound(loc, 'sound/items/Crowbar.ogg', 75, 1) - to_chat(user, "You pry off the turret's exterior armor.") - new /obj/item/stack/material/steel(loc, 2) - build_step = 6 - return - - if(istype(I, /obj/item/pen)) //you can rename turrets like bots! - var/t = sanitizeSafe(input(user, "Enter new turret name", name, finish_name) as text, MAX_NAME_LEN) - if(!t) - return - if(!in_range(src, usr) && loc != usr) - return - - finish_name = t - return - - ..() - - -/obj/machinery/porta_turret_construct/attack_hand(mob/user) - switch(build_step) - if(4) - if(!installation) - return - build_step = 3 - - var/obj/item/gun/energy/Gun = new installation(loc) - Gun.power_supply.charge = gun_charge - Gun.update_icon() - installation = null - gun_charge = 0 - to_chat(user, "You remove [Gun] from the turret frame.") - - if(5) - to_chat(user, "You remove the prox sensor from the turret frame.") - new /obj/item/assembly/prox_sensor(loc) - build_step = 4 - -/obj/machinery/porta_turret_construct/attack_ai() - return - /atom/movable/porta_turret_cover icon = 'icons/obj/turrets.dmi' diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 4af6629cdcec..a63a730636f3 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -5,7 +5,7 @@ desc = "An all-purpose recharger for a variety of devices." icon = 'icons/obj/machines/recharger.dmi' icon_state = "recharger0" - anchored = 1 + anchored = TRUE idle_power_usage = 4 active_power_usage = 30 KILOWATTS var/obj/item/charging = null @@ -15,7 +15,6 @@ var/icon_state_idle = "recharger0" //also when unpowered var/portable = 1 - stat_immune = 0 uncreated_component_parts = null construct_state = /decl/machine_construction/default/panel_closed @@ -23,36 +22,36 @@ charging = null . = ..() -/obj/machinery/recharger/attackby(obj/item/G, mob/user) +/obj/machinery/recharger/attackby(obj/item/used_item, mob/user) var/allowed = 0 for (var/allowed_type in allowed_devices) - if (istype(G, allowed_type)) allowed = 1 + if (istype(used_item, allowed_type)) allowed = 1 if(allowed) . = TRUE if(charging) to_chat(user, "\A [charging] is already charging here.") return - // Checks to make sure he's not in space doing it, and that the area got proper power. - if(!powered()) - to_chat(user, "The [name] blinks red as you try to insert the item!") + // Checks to make sure the recharger is powered. + if(stat & NOPOWER) + to_chat(user, "\The [src] blinks red as you try to insert \the [used_item]!") return - if (istype(G, /obj/item/gun/energy/)) - var/obj/item/gun/energy/E = G + if (istype(used_item, /obj/item/gun/energy/)) + var/obj/item/gun/energy/E = used_item if(E.self_recharge) to_chat(user, "You can't find a charging port on \the [E].") return - if(!G.get_cell()) + if(!used_item.get_cell()) to_chat(user, "This device does not have a battery installed.") return - if(user.unEquip(G)) - G.forceMove(src) - charging = G + if(user.try_unequip(used_item)) + used_item.forceMove(src) + charging = used_item update_icon() return - if(portable && isWrench(G) && !panel_open) + if(portable && IS_WRENCH(used_item) && !panel_open) . = TRUE if(charging) to_chat(user, "Remove [charging] first!") @@ -71,6 +70,7 @@ charging = null update_icon() return TRUE + return FALSE /obj/machinery/recharger/Process() if(stat & (NOPOWER|BROKEN) || !anchored) @@ -82,11 +82,11 @@ update_use_power(POWER_USE_IDLE) icon_state = icon_state_idle else - var/obj/item/cell/C = charging.get_cell() - if(istype(C)) - if(!C.fully_charged()) + var/obj/item/cell/cell = charging.get_cell() + if(istype(cell)) + if(!cell.fully_charged()) icon_state = icon_state_charging - C.give(active_power_usage*CELLRATE) + cell.give(active_power_usage*CELLRATE) update_use_power(POWER_USE_ACTIVE) else icon_state = icon_state_charged @@ -97,9 +97,9 @@ ..(severity) return if(charging) - var/obj/item/cell/C = charging.get_cell() - if(istype(C)) - C.emp_act(severity) + var/obj/item/cell/cell = charging.get_cell() + if(istype(cell)) + cell.emp_act(severity) ..(severity) /obj/machinery/recharger/on_update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier. @@ -108,18 +108,15 @@ else icon_state = icon_state_idle -/obj/machinery/recharger/examine(mob/user) +/obj/machinery/recharger/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(isnull(charging)) - return - - var/obj/item/cell/C = charging.get_cell() - if(!isnull(C)) - to_chat(user, "Item's charge at [round(C.percent())]%.") + var/obj/item/cell/cell = charging?.get_cell() + if(cell) + . += "\The [charging] is charged to [round(cell.percent())]%." /obj/machinery/recharger/wallcharger name = "wall recharger" - desc = "A heavy duty wall recharger specialized for energy weaponry." + desc = "A heavy-duty wall recharger specialized for energy weaponry." icon = 'icons/obj/machines/recharger_wall.dmi' icon_state = "wrecharger0" active_power_usage = 50 KILOWATTS //It's more specialized than the standalone recharger (guns and batons only) so make it more powerful @@ -128,6 +125,8 @@ icon_state_charging = "wrecharger1" icon_state_idle = "wrecharger0" portable = 0 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED construct_state = /decl/machine_construction/wall_frame/panel_closed - frame_type = /obj/item/frame/button/wall_charger \ No newline at end of file + frame_type = /obj/item/frame/button/wall_charger + directional_offset = @'{"NORTH":{"y":-24}, "SOUTH":{"y":32}, "EAST":{"x":-28}, "WEST":{"x":28}}' \ No newline at end of file diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 519fb27b55b4..74a34b4ac150 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -1,19 +1,17 @@ /obj/machinery/recharge_station name = "robot recharging station" - desc = "A heavy duty rapid charging system, designed to quickly recharge autonomous system power reserves." + desc = "A heavy-duty rapid charging system, designed to quickly recharge autonomous system power reserves." icon = 'icons/obj/objects.dmi' icon_state = "borgcharger0" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 50 base_type = /obj/machinery/recharge_station uncreated_component_parts = null - stat_immune = 0 construct_state = /decl/machine_construction/default/panel_closed var/overlay_icon = 'icons/obj/objects.dmi' var/mob/living/occupant = null - var/charging = 0 var/last_overlay_state var/charging_power // W. Power rating used for charging the cyborg. 120 kW if un-upgraded @@ -27,16 +25,22 @@ . = ..() update_icon() -/obj/machinery/recharge_station/MouseDrop_T(var/mob/living/target, var/mob/user) - if(!CanMouseDrop(target, user) || !istype(target)) - return FALSE - user.visible_message(SPAN_NOTICE("\The [user] begins placing \the [target] into \the [src]."), SPAN_NOTICE("You start placing \the [target] into \the [src].")) - if(!do_after(user, 30, src)) - return - if(target.buckled) - to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them.")) - return FALSE - go_in(target) +/obj/machinery/recharge_station/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && isliving(dropping)) + var/mob/living/M = dropping + if(M.anchored) + return FALSE + user.visible_message( \ + SPAN_NOTICE("\The [user] begins placing \the [dropping] into \the [src]."), \ + SPAN_NOTICE("You start placing \the [dropping] into \the [src].")) + if(do_after(user, 30, src)) + var/mob/living/target = dropping + if(target.buckled) + to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them.")) + else + go_in(target) + return TRUE /obj/machinery/recharge_station/Process() if(stat & (BROKEN | NOPOWER)) @@ -56,48 +60,47 @@ return // If we have repair capabilities, repair any damage. - if(weld_rate && occupant.getBruteLoss()) + if(weld_rate && occupant.get_damage(BRUTE)) var/repair = weld_rate - use_power_oneoff(weld_power_use * weld_rate, LOCAL) / weld_power_use - occupant.adjustBruteLoss(-repair) - if(wire_rate && occupant.getFireLoss()) + occupant.heal_damage(BRUTE, repair) + if(wire_rate && occupant.get_damage(BURN)) var/repair = wire_rate - use_power_oneoff(wire_power_use * wire_rate, LOCAL) / wire_power_use - occupant.adjustFireLoss(-repair) + occupant.heal_damage(BURN, repair) var/obj/item/cell/target if(isrobot(occupant)) - var/mob/living/silicon/robot/R = occupant - target = R.cell - if(R.module) - R.module.respawn_consumable(R, charging_power * CELLRATE / 250) //consumables are magical, apparently + var/mob/living/silicon/robot/robot = occupant + target = robot.cell + if(robot.module) + robot.module.respawn_consumable(robot, charging_power * CELLRATE / 250) //consumables are magical, apparently // If we are capable of repairing damage, reboot destroyed components and allow them to be repaired for very large power spike. - var/list/damaged = R.get_damaged_components(1,1,1) + var/list/damaged = robot.get_damaged_components(1,1,1) if(damaged.len && wire_rate && weld_rate) for(var/datum/robot_component/C in damaged) if((C.installed == -1) && use_power_oneoff(100 KILOWATTS, LOCAL) <= 0) C.repair() if(ishuman(occupant)) - var/mob/living/carbon/human/H = occupant - var/obj/item/organ/internal/cell/potato = H.internal_organs_by_name[BP_CELL] + var/mob/living/human/H = occupant + var/obj/item/organ/internal/cell/potato = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) if(potato) target = potato.cell - if((!target || target.percent() > 95) && istype(H.back,/obj/item/rig)) - var/obj/item/rig/R = H.back - if(R.cell && !R.cell.fully_charged()) - target = R.cell + var/obj/item/rig/rig = H.get_rig() + if((!target || target.percent() > 95) && rig && rig.cell && !rig.cell.fully_charged()) + target = rig.cell if(target && !target.fully_charged()) var/diff = min(target.maxcharge - target.charge, charging_power * CELLRATE) // Capped by charging_power / tick var/charge_used = diff - use_power_oneoff(diff / CELLRATE, LOCAL) * CELLRATE target.give(charge_used) -/obj/machinery/recharge_station/examine(mob/user) +/obj/machinery/recharge_station/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/obj/item/cell/cell = get_cell() if(cell) - to_chat(user, "The charge meter reads: [cell.percent()]%") + . += "The charge meter reads: [cell.percent()]%." else - to_chat(user, "The indicator shows that the cell is missing.") + . += "The indicator shows that the cell is missing." /obj/machinery/recharge_station/relaymove(mob/user) if(user.stat) @@ -123,8 +126,8 @@ /obj/machinery/recharge_station/RefreshParts() ..() - var/man_rating = Clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 0, 10) - var/cap_rating = Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) + var/man_rating = clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 0, 10) + var/cap_rating = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) charging_power = 40000 + 40000 * cap_rating weld_rate = max(0, man_rating - 3) @@ -170,15 +173,12 @@ last_overlay_state = overlay_state() overlays = list(image(overlay_icon, overlay_state())) -/obj/machinery/recharge_station/Bumped(var/mob/living/silicon/robot/R) - go_in(R) +/obj/machinery/recharge_station/Bumped(var/mob/living/silicon/robot/robot) + addtimer(CALLBACK(src, PROC_REF(go_in), robot), 1) /obj/machinery/recharge_station/proc/go_in(var/mob/M) - if(occupant) - return - - if(!hascell(M)) + if(occupant || M.anchored || !hascell(M)) return add_fingerprint(M) @@ -190,16 +190,16 @@ /obj/machinery/recharge_station/proc/hascell(var/mob/M) if(isrobot(M)) - var/mob/living/silicon/robot/R = M - return (R.cell) + var/mob/living/silicon/robot/robot = M + return (robot.cell) if(ishuman(M)) - var/mob/living/carbon/human/H = M + var/mob/living/human/H = M if(H.isSynthetic()) return 1 - if(istype(H.back,/obj/item/rig)) - var/obj/item/rig/R = H.back - return R.cell - return H.internal_organs_by_name["cell"] + var/obj/item/rig/rig = H.get_rig() + if(rig) + return rig.cell + return GET_INTERNAL_ORGAN(H, BP_CELL) return 0 /obj/machinery/recharge_station/proc/go_out() diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 0c0ca990698d..3452f128f8b0 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -12,15 +12,16 @@ #define RCS_MESSAUTH 7 // Authentication before sending #define RCS_ANNOUNCE 8 // Send announcement -var/req_console_assistance = list() -var/req_console_supplies = list() -var/req_console_information = list() -var/list/obj/machinery/requests_console/allConsoles = list() +var/global/req_console_assistance = list() +var/global/req_console_supplies = list() +var/global/req_console_information = list() -/obj/machinery/requests_console +/obj/machinery/network/requests_console name = "Requests Console" desc = "A console intended to send requests to different departments." - anchored = 1 + anchored = TRUE + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED icon = 'icons/obj/terminals.dmi' icon_state = "req_comp0" var/department = "Unknown" //The list of all departments on the station (Determined from this variable on each unit) Set this to the same thing if you want several consoles in one department @@ -34,21 +35,21 @@ var/list/obj/machinery/requests_console/allConsoles = list() var/announcementConsole = 0 // 0 = This console cannot be used to send department announcements // 1 = This console can send department announcementsf - var/open = 0 // 1 if open var/announceAuth = 0 //Will be set to 1 when you authenticate yourself for announcements var/msgVerified = "" //Will contain the name of the person who varified it var/msgStamped = "" //If a message is stamped, this will contain the stamp name var/message = "" var/recipient = "" //the department which will be receiving the message var/priority = -1 //Priority of the message being sent - light_outer_range = 0 + light_range = 0 var/datum/announcement/announcement = new uncreated_component_parts = null construct_state = /decl/machine_construction/wall_frame/panel_closed frame_type = /obj/item/frame/stock_offset/request_console + directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":-32}, "EAST":{"x":32}, "WEST":{"x":-32}}' -/obj/machinery/requests_console/on_update_icon() +/obj/machinery/network/requests_console/on_update_icon() if(stat & NOPOWER) if(icon_state != "req_comp_off") icon_state = "req_comp_off" @@ -56,18 +57,19 @@ var/list/obj/machinery/requests_console/allConsoles = list() if(icon_state == "req_comp_off") icon_state = "req_comp[newmessagepriority]" -/obj/machinery/requests_console/Initialize(mapload, d) +/obj/machinery/network/requests_console/Initialize(mapload, d) . = ..() announcement.newscast = 1 - allConsoles += src // Try and find it; this is legacy mapping compatibility for the most part. - if(SSdepartments.departments[department]) - set_department(SSdepartments.departments[department]) + var/decl/department/dept = SSjobs.get_department_by_name(department) + if(dept) + set_department(dept) else var/found_name = FALSE - for(var/key in SSdepartments.departments) - var/datum/department/candidate = SSdepartments.departments[key] - if(candidate.title == department) + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/key in all_departments) + var/decl/department/candidate = all_departments[key] + if(lowertext(candidate.name) == lowertext(department)) set_department(candidate) found_name = TRUE break @@ -75,25 +77,21 @@ var/list/obj/machinery/requests_console/allConsoles = list() set_department(department) set_light(1) -/obj/machinery/requests_console/proc/set_department(var/datum/department/_department) +/obj/machinery/network/requests_console/proc/set_department(var/decl/department/_department) if(istype(_department)) - department = _department.reference - announcement.title = "[_department.title] announcement" - SetName("[_department.title] Requests Console") + department = _department.name + announcement.title = "[_department.name] announcement" + SetName("[_department.name] Requests Console") else if(istext(department)) department = _department announcement.title = "[_department] announcement" SetName("[_department] Requests Console") -/obj/machinery/requests_console/Destroy() - allConsoles -= src - . = ..() - -/obj/machinery/requests_console/interface_interact(mob/user) +/obj/machinery/network/requests_console/interface_interact(mob/user) ui_interact(user) return TRUE -/obj/machinery/requests_console/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/network/requests_console/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] data["department"] = department @@ -120,7 +118,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() ui.set_initial_data(data) ui.open() -/obj/machinery/requests_console/OnTopic(user, href_list) +/obj/machinery/network/requests_console/OnTopic(user, href_list) if(reject_bad_text(href_list["write"])) recipient = href_list["write"] //write contains the string of the receiving department's name @@ -153,13 +151,13 @@ var/list/obj/machinery/requests_console/allConsoles = list() if( href_list["department"] && message ) var/log_msg = message screen = RCS_SENTFAIL - var/obj/machinery/message_server/MS = get_message_server(get_z(src)) + var/obj/machinery/network/message_server/MS = get_message_server(get_z(src)) if(MS) if(MS.send_rc_message(ckey(href_list["department"]),department,log_msg,msgStamped,msgVerified,priority)) screen = RCS_SENTPASS message_log += "Message sent to [recipient]
              [message]" else - audible_message(text("\icon[src] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4) + audible_message("[html_icon(src)] *The Requests Console beeps: 'NOTICE: No server detected!'", null, 4) return TOPIC_REFRESH //Handle screen switching @@ -168,8 +166,11 @@ var/list/obj/machinery/requests_console/allConsoles = list() if(tempScreen == RCS_ANNOUNCE && !announcementConsole) return if(tempScreen == RCS_VIEWMSGS) - for (var/obj/machinery/requests_console/Console in allConsoles) - if (Console.department == department) + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/datum/extension/network_device/console in network?.devices) + var/obj/machinery/network/requests_console/Console = console.holder + if(istype(Console) && Console.department == department) Console.newmessagepriority = 0 Console.icon_state = "req_comp0" Console.set_light(1) @@ -184,13 +185,13 @@ var/list/obj/machinery/requests_console/allConsoles = list() return TOPIC_REFRESH if(href_list["set_department"]) - var/list/choices = SSdepartments.departments.Copy() - choices += "Custom" - var/choice = input(user, "Select a new department from the list:", "Department Selection", department) as null|anything in choices + var/list/choices = list() + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dtype in all_departments) + choices += all_departments[dtype] + var/choice = input(user, "Select a new department from the list:", "Department Selection", department) as null|anything in (choices + "Custom") if(!CanPhysicallyInteract(user)) return TOPIC_HANDLED - if(!choice) - return TOPIC_HANDLED if(choice == "Custom") var/input = input(user, "Enter a custom name:", "Custom Selection", department) as null|text if(!CanPhysicallyInteract(user)) @@ -200,34 +201,39 @@ var/list/obj/machinery/requests_console/allConsoles = list() sanitize(input) set_department(input) return TOPIC_REFRESH - set_department(choices[choice]) + else if(!istype(choice, /decl/department)) + return TOPIC_HANDLED + set_department(choice) return TOPIC_REFRESH -/obj/machinery/requests_console/attackby(var/obj/item/O, var/mob/user) - if (istype(O, /obj/item/card/id)) - if(inoperable(MAINT)) return - if(screen == RCS_MESSAUTH) - var/obj/item/card/id/T = O - msgVerified = text("Verified by [T.registered_name] ([T.assignment])") - SSnano.update_uis(src) - if(screen == RCS_ANNOUNCE) - var/obj/item/card/id/ID = O - if (access_RC_announce in ID.GetAccess()) - announceAuth = 1 - announcement.announcer = ID.assignment ? "[ID.assignment] [ID.registered_name]" : ID.registered_name - else - reset_message() - to_chat(user, "You are not authorized to send announcements.") - SSnano.update_uis(src) - if (istype(O, /obj/item/stamp)) - if(inoperable(MAINT)) return +/obj/machinery/network/requests_console/attackby(var/obj/item/used_item, var/mob/user) + if (istype(used_item, /obj/item/card/id)) + if(inoperable(MAINT)) return TRUE + switch(screen) + if(RCS_MESSAUTH) + var/obj/item/card/id/T = used_item + msgVerified = text("Verified by [T.registered_name] ([T.assignment])") + SSnano.update_uis(src) + if(RCS_ANNOUNCE) + var/obj/item/card/id/ID = used_item + if (access_RC_announce in ID.GetAccess()) + announceAuth = 1 + announcement.announcer = ID.assignment ? "[ID.assignment] [ID.registered_name]" : ID.registered_name + else + reset_message() + to_chat(user, "You are not authorized to send announcements.") + SSnano.update_uis(src) + return TRUE + if (istype(used_item, /obj/item/stamp)) + if(inoperable(MAINT)) return TRUE if(screen == RCS_MESSAUTH) - var/obj/item/stamp/T = O - msgStamped = text("Stamped with the [T.name]") + var/obj/item/stamp/T = used_item + msgStamped = "Stamped with the [T.name]" SSnano.update_uis(src) + return TRUE return ..() -/obj/machinery/requests_console/proc/reset_message(var/mainmenu = 0) +/obj/machinery/network/requests_console/proc/reset_message(var/mainmenu = 0) message = "" recipient = "" priority = 0 diff --git a/code/game/machinery/seed_extractor.dm b/code/game/machinery/seed_extractor.dm index a94eecd907d3..6f451e7ce6c1 100644 --- a/code/game/machinery/seed_extractor.dm +++ b/code/game/machinery/seed_extractor.dm @@ -3,53 +3,41 @@ desc = "Extracts and bags seeds from produce." icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' icon_state = "sextractor" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE use_power = POWER_USE_ACTIVE idle_power_usage = 10 active_power_usage = 2000 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 -obj/machinery/seed_extractor/attackby(var/obj/item/O, var/mob/user) - if((. = component_attackby(O, user))) - return - // Fruits and vegetables. - if(istype(O, /obj/item/chems/food/snacks/grown) || istype(O, /obj/item/grown)) - if(!user.unEquip(O)) - return - - var/datum/seed/new_seed_type - if(istype(O, /obj/item/grown)) - var/obj/item/grown/F = O - new_seed_type = SSplants.seeds[F.plantname] - else - var/obj/item/chems/food/snacks/grown/F = O - new_seed_type = SSplants.seeds[F.plantname] +/obj/machinery/seed_extractor/attackby(var/obj/item/used_item, var/mob/user) - if(new_seed_type) - to_chat(user, "You extract some seeds from [O].") - var/produce = rand(1,4) - for(var/i = 0;i<=produce;i++) - var/obj/item/seeds/seeds = new(get_turf(src)) - seeds.seed_type = new_seed_type.name - seeds.update_seed() - else - to_chat(user, "[O] doesn't seem to have any usable seeds inside it.") - - qdel(O) + // Fruits and vegetables. + if(istype(used_item, /obj/item/food/grown)) + if(!user.try_unequip(used_item)) + return TRUE + var/obj/item/food/grown/F = used_item + if(!F.seed) + to_chat(user, SPAN_WARNING("\The [used_item] doesn't seem to have any usable seeds inside it.")) + return TRUE + to_chat(user, SPAN_NOTICE("You extract some seeds from [used_item].")) + for(var/i = 1 to rand(1,4)) + new /obj/item/seeds/modified(get_turf(src), null, F.seed) + qdel(used_item) + return TRUE //Grass. - else if(istype(O, /obj/item/stack/tile/grass)) - var/obj/item/stack/tile/grass/S = O + if(istype(used_item, /obj/item/stack/tile/grass)) + var/obj/item/stack/tile/grass/S = used_item if (S.use(1)) - to_chat(user, "You extract some seeds from the grass tile.") + to_chat(user, SPAN_NOTICE("You extract some seeds from the grass tile.")) new /obj/item/seeds/grassseed(loc) + return TRUE - else if(istype(O, /obj/item/fossil/plant)) // Fossils - var/obj/item/seeds/random/R = new(get_turf(src)) - to_chat(user, "\The [src] scans \the [O] and spits out \a [R].") - qdel(O) + if(istype(used_item, /obj/item/fossil/plant)) // Fossils + to_chat(user, SPAN_NOTICE("\The [src] scans \the [used_item] and spits out \a [new /obj/item/seeds/random(get_turf(src))].")) + qdel(used_item) + return TRUE - return + return ..() diff --git a/code/game/machinery/self_destruct.dm b/code/game/machinery/self_destruct.dm index 40d3e0a24c9d..a987fa104aee 100644 --- a/code/game/machinery/self_destruct.dm +++ b/code/game/machinery/self_destruct.dm @@ -1,43 +1,45 @@ /obj/machinery/self_destruct name = "\improper Nuclear Cylinder Inserter" - desc = "A hollow space used to insert nuclear cylinders for arming the self destruct." + desc = "A hollow space used to insert nuclear cylinders for arming the self-destruct mechanism." icon = 'icons/obj/machines/self_destruct.dmi' icon_state = "empty" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE var/obj/item/nuclear_cylinder/cylinder var/armed = 0 var/damaged = 0 -/obj/machinery/self_destruct/attackby(obj/item/W, mob/user) - if(isWelder(W)) - if(damaged) - user.visible_message("[user] begins to repair [src].", "You begin repairing [src].") - if(do_after(usr, 100, src)) - var/obj/item/weldingtool/w - if(w.burn_fuel(10)) - damaged = 0 - user.visible_message("[user] repairs [src].", "You repair [src].") - else - to_chat(user, "There is not enough fuel to repair [src].") - return - if(istype(W, /obj/item/nuclear_cylinder)) +/obj/machinery/self_destruct/attackby(obj/item/used_item, mob/user) + if(IS_WELDER(used_item)) + if(!damaged) + return FALSE + user.visible_message("[user] begins to repair [src].", "You begin repairing [src].") + if(do_after(user, 100, src)) + var/obj/item/weldingtool/w = used_item + if(w.weld(10)) + damaged = 0 + user.visible_message("[user] repairs [src].", "You repair [src].") + else + to_chat(user, "There is not enough fuel to repair [src].") + return TRUE + if(istype(used_item, /obj/item/nuclear_cylinder)) if(damaged) to_chat(user, "[src] is damaged, you cannot place the cylinder.") - return + return TRUE if(cylinder) to_chat(user, "There is already a cylinder here.") - return - user.visible_message("[user] begins to carefully place [W] onto the Inserter.", "You begin to carefully place [W] onto the Inserter.") - if(do_after(user, 80, src) && user.unEquip(W, src)) - cylinder = W - density = 1 - user.visible_message("[user] places [W] onto the Inserter.", "You place [W] onto the Inserter.") + return TRUE + user.visible_message("[user] begins to carefully place [used_item] onto [src].", "You begin to carefully place [used_item] onto [src].") + if(do_after(user, 80, src) && user.try_unequip(used_item, src)) + cylinder = used_item + density = TRUE + user.visible_message("[user] places [used_item] onto [src].", "You place [used_item] onto [src].") update_icon() - return - ..() + return TRUE + return ..() /obj/machinery/self_destruct/physical_attack_hand(mob/user) + . = FALSE if(cylinder) . = TRUE if(armed) @@ -46,44 +48,48 @@ return var/obj/machinery/nuclearbomb/nuke = locate(/obj/machinery/nuclearbomb/station) in get_area(src) if(!nuke) - to_chat(user, "Unable to interface with the self destruct terminal, unable to disarm.") + to_chat(user, "Unable to interface with the self-destruct terminal, unable to disarm.") return if(nuke.timing) - to_chat(user, "The self destruct sequence is in progress, unable to disarm.") + to_chat(user, "The self-destruct sequence is in progress, unable to disarm.") return user.visible_message("[user] begins extracting [cylinder].", "You begin extracting [cylinder].") if(do_after(user, 40, src)) user.visible_message("[user] extracts [cylinder].", "You extract [cylinder].") armed = 0 - density = 1 + density = TRUE flick("unloading", src) else if(!damaged) user.visible_message("[user] begins to arm [cylinder].", "You begin to arm [cylinder].") if(do_after(user, 40, src)) armed = 1 - density = 0 + density = FALSE user.visible_message("[user] arms [cylinder].", "You arm [cylinder].") flick("loading", src) playsound(src.loc,'sound/effects/caution.ogg',50,1,5) update_icon() src.add_fingerprint(user) -/obj/machinery/self_destruct/MouseDrop(atom/over) - if(!CanMouseDrop(over, usr)) - return - if(over == usr && cylinder) +/obj/machinery/self_destruct/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && cylinder) if(armed) - to_chat(usr, "Disarm the cylinder first.") - else - usr.visible_message("[usr] beings to carefully pick up [cylinder].", "You begin to carefully pick up [cylinder].") - if(do_after(usr, 70, src)) - usr.put_in_hands(cylinder) - usr.visible_message("[usr] picks up [cylinder].", "You pick up [cylinder].") - density = 0 - cylinder = null + to_chat(user, SPAN_WARNING("Disarm the cylinder first.")) + return TRUE + user.visible_message( \ + SPAN_NOTICE("\The [user] beings to carefully pick up \the [cylinder]."), \ + SPAN_NOTICE("You begin to carefully pick up \the [cylinder].")) + if(!do_after(user, 70, src) || !cylinder) + return TRUE + user.put_in_hands(cylinder) + user.visible_message( \ + SPAN_NOTICE("\The [user] picks up \the [cylinder]."), \ + SPAN_NOTICE("You pick up \the [cylinder].")) + density = FALSE + cylinder = null update_icon() - src.add_fingerprint(usr) - ..() + add_fingerprint(user) + return TRUE + . = ..() /obj/machinery/self_destruct/explosion_act(severity) ..() @@ -95,16 +101,16 @@ visible_message(SPAN_DANGER("\The [src] dents and chars.")) damaged = 1 -/obj/machinery/self_destruct/examine(mob/user) +/obj/machinery/self_destruct/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(damaged) - to_chat(user, "[src] is damaged, it needs repairs.") + . += SPAN_WARNING("\The [src] is damaged and needs to be repaired.") return if(armed) - to_chat(user, "[src] is armed and ready.") + . += SPAN_DANGER("\The [src] is armed and ready.") return if(cylinder) - to_chat(user, "[src] is loaded and ready to be armed.") + . += "\the [src] is loaded and ready to be armed." /obj/machinery/self_destruct/on_update_icon() if(armed) diff --git a/code/game/machinery/self_destruct_storage.dm b/code/game/machinery/self_destruct_storage.dm new file mode 100644 index 000000000000..df7512e5da09 --- /dev/null +++ b/code/game/machinery/self_destruct_storage.dm @@ -0,0 +1,170 @@ +/obj/machinery/nuclear_cylinder_storage + name = "nuclear cylinder storage" + desc = "It's a secure, armored storage unit embedded into the floor for storing the nuclear cylinders." + icon = 'icons/obj/machines/self_destruct_storage.dmi' + icon_state = "base" + anchored = TRUE + density = FALSE + + required_interaction_dexterity = DEXTERITY_HOLD_ITEM + construct_state = /decl/machine_construction/default/panel_closed + base_type = /obj/machinery/nuclear_cylinder_storage/buildable + + uncreated_component_parts = null + + var/locked = TRUE + var/open = FALSE + + var/interact_time = 8 SECONDS + + var/list/cylinders = list() + var/list/max_cylinders = 6 + var/list/prefilled = FALSE + +/obj/machinery/nuclear_cylinder_storage/buildable + locked = FALSE + open = TRUE + +/obj/machinery/nuclear_cylinder_storage/Initialize() + . = ..() + + if(prefilled) + fill_with_rods() + + update_icon() + +/obj/machinery/nuclear_cylinder_storage/Destroy() + QDEL_LIST(cylinders) + return ..() + +/obj/machinery/nuclear_cylinder_storage/proc/fill_with_rods() + QDEL_LIST(cylinders) + + for(var/i in 1 to max_cylinders) + cylinders += new /obj/item/nuclear_cylinder() + +/// Special subtype for mapping. +/obj/machinery/nuclear_cylinder_storage/prefilled + prefilled = TRUE + +/obj/machinery/nuclear_cylinder_storage/emag_act(remaining_charges, mob/user, emag_source) + to_chat(user, SPAN_WARNING("The card fails to do anything. It seems this device has an advanced encryption system.")) + return NO_EMAG_ACT + +// I hate this but can't think of a better way aside from skipping the testing entirely for this type, +// which is worse. Basically, we just need to ensure we pass the cannot_transition_to check. +/obj/machinery/nuclear_cylinder_storage/fail_construct_state_unit_test() + locked = FALSE + open = TRUE + var/list/old_cylinders = cylinders // This is evil. + cylinders = list() + . = ..() + cylinders = old_cylinders + +/obj/machinery/nuclear_cylinder_storage/components_are_accessible(path) + return !locked && open && ..() + +/obj/machinery/nuclear_cylinder_storage/cannot_transition_to(state_path, mob/user) + if(locked) + return SPAN_WARNING("You must unlock \the [src] first!") + if(!open) + return SPAN_WARNING("You must open \the [src] first!") + if(length(cylinders)) + return SPAN_WARNING("You must remove all cylinders from \the [src] first!") + return ..() + +/obj/machinery/nuclear_cylinder_storage/physical_attack_hand(mob/user) + if(!panel_open) + if(!locked) + open = !open + user.visible_message( + "\The [user] [open ? "opens" : "closes"] \the [src].", + "You [open ? "open" : "close"] \the [src]." + ) + update_icon() + return TRUE + if(operable() && check_access(user)) + locked = FALSE + user.visible_message( + "\The [user] unlocks \the [src].", + "You unlock \the [src]." + ) + update_icon() + return TRUE + else + to_chat(user, SPAN_WARNING("\The [src] is currently in maintenance mode!")) + return TRUE + return FALSE + +/obj/machinery/nuclear_cylinder_storage/attackby(obj/item/used_item, mob/user) + if(!open && operable() && istype(used_item, /obj/item/card/id)) + if(panel_open) + to_chat(user, SPAN_WARNING("\The [src] is currently in maintenance mode!")) + return TRUE + + var/obj/item/card/id/id = used_item + if(check_access(id)) + locked = !locked + user.visible_message( + "\The [user] [locked ? "locks" : "unlocks"] \the [src].", + "You [locked ? "lock" : "unlock"] \the [src]." + ) + update_icon() + return TRUE + + if(open && istype(used_item, /obj/item/nuclear_cylinder) && (length(cylinders) < max_cylinders)) + if(panel_open) + to_chat(user, SPAN_WARNING("\The [src] is currently in maintenance mode!")) + return TRUE + + user.visible_message( + "\The [user] begins inserting \the [used_item] into storage.", + "You begin inserting \the [used_item] into storage." + ) + if(do_after(user, interact_time, src) && open && (length(cylinders) < max_cylinders) && user.try_unequip(used_item, src)) + user.visible_message( + "\The [user] places \the [used_item] into storage.", + "You place \the [used_item] into storage." + ) + cylinders.Add(used_item) + update_icon() + return TRUE + + return ..() + +/obj/machinery/nuclear_cylinder_storage/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && open && !panel_open && length(cylinders)) + var/cylinder = cylinders[1] + user.visible_message( + "\The [user] begins to extract \the [cylinder].", + "You begin to extract \the [cylinder]." + ) + if(do_after(user, interact_time, src) && open && cylinders.Find(cylinder)) + user.visible_message( + "\The [user] picks up \the [cylinder].", + "You pick up \the [cylinder]." + ) + user.put_in_hands(cylinder) + cylinders.Remove(cylinder) + update_icon() + + add_fingerprint(user) + return TRUE + + . = ..() + +/obj/machinery/nuclear_cylinder_storage/on_update_icon() + cut_overlays() + + if(length(cylinders)) + /// We have only 6 rod overlays, so lets clamp it. + add_overlay("rods_[clamp(length(cylinders), 0, 6)]") + + if(!open) + add_overlay("hatch") + + if(operable()) + if(locked) + add_overlay("red_light") + else + add_overlay("green_light") diff --git a/code/game/machinery/singularitybeacon.dm b/code/game/machinery/singularitybeacon.dm new file mode 100644 index 000000000000..e9f6d6381be5 --- /dev/null +++ b/code/game/machinery/singularitybeacon.dm @@ -0,0 +1,82 @@ +var/global/list/singularity_beacons = list() + +//////////////////////////////////////// +//Singularity beacon +//////////////////////////////////////// +/obj/machinery/singularity_beacon + name = "ominous beacon" + desc = "This looks suspicious..." + icon = 'icons/obj/singularity.dmi' + icon_state = "beaconsynd" + + uncreated_component_parts = list(/obj/item/stock_parts/power/terminal) + anchored = FALSE + density = TRUE + layer = BASE_ABOVE_OBJ_LAYER //so people can't hide it and it's REALLY OBVIOUS + stat = 0 + use_power = POWER_USE_OFF + +/obj/machinery/singularity_beacon/Initialize() + . = ..() + global.singularity_beacons += src + +/obj/machinery/singularity_beacon/Destroy() + if(use_power) + Deactivate() + global.singularity_beacons -= src + return ..() + +/obj/machinery/singularity_beacon/proc/Activate(mob/user = null) + for(var/obj/effect/singularity/singulo in global.singularities) + if(singulo.z == z) + singulo.target = src + icon_state = "[initial(icon_state)]1" + update_use_power(POWER_USE_ACTIVE) + if(user) + to_chat(user, SPAN_NOTICE("You activate the beacon.")) + +/obj/machinery/singularity_beacon/proc/Deactivate(mob/user = null) + for(var/obj/effect/singularity/singulo in global.singularities) + if(singulo.target == src) + singulo.target = null + icon_state = "[initial(icon_state)]0" + update_use_power(POWER_USE_OFF) + if(user) + to_chat(user, SPAN_NOTICE("You deactivate the beacon.")) + +/obj/machinery/singularity_beacon/physical_attack_hand(var/mob/user) + . = TRUE + if(anchored) + if(use_power) + Deactivate(user) + else + Activate(user) + else + to_chat(user, SPAN_DANGER("You need to screw the beacon to the floor first!")) + +/obj/machinery/singularity_beacon/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) + if(use_power) + to_chat(user, SPAN_DANGER("You need to deactivate the beacon first!")) + return TRUE + + anchored = !anchored + if(anchored) + to_chat(user, SPAN_NOTICE("You screw the beacon to the floor.")) + else + to_chat(user, SPAN_NOTICE("You unscrew the beacon from the floor.")) + return TRUE + return ..() + +// Ensure the terminal is always accessible to be plugged in. +/obj/machinery/singularity_beacon/components_are_accessible(var/path) + if(ispath(path, /obj/item/stock_parts/power/terminal)) + return TRUE + return ..() + +/obj/machinery/singularity_beacon/power_change() + . = ..() + if(!. || !use_power) + return + if(stat & NOPOWER) + Deactivate() diff --git a/code/game/machinery/slide_projector.dm b/code/game/machinery/slide_projector.dm index 93ac4b704011..85b2db3f4664 100644 --- a/code/game/machinery/slide_projector.dm +++ b/code/game/machinery/slide_projector.dm @@ -1,12 +1,11 @@ -/obj/item/storage/slide_projector +/obj/item/slide_projector name = "slide projector" desc = "A handy device capable of showing an enlarged projection of whatever you can fit inside." icon = 'icons/obj/items/device/projector.dmi' icon_state = "projector0" - max_w_class = ITEM_SIZE_SMALL - max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_SMALL) - use_sound = 'sound/effects/storage/toolbox.ogg' - var/list/global/projection_types = list( + storage = /datum/storage/slide_projector + material = /decl/material/solid/metal/steel + var/static/list/projection_types = list( /obj/item/photo = /obj/effect/projection/photo, /obj/item/paper = /obj/effect/projection/paper, /obj/item = /obj/effect/projection @@ -14,52 +13,43 @@ var/obj/item/current_slide var/obj/effect/projection/projection -/obj/item/storage/slide_projector/Destroy() +/obj/item/slide_projector/Destroy() current_slide = null stop_projecting() . = ..() -/obj/item/storage/slide_projector/on_update_icon() +/obj/item/slide_projector/on_update_icon() + . = ..() icon_state = "projector[!!projection]" -/obj/item/storage/slide_projector/get_mechanics_info() +/obj/item/slide_projector/get_mechanics_info() . = ..() . += "Use in hand to open the interface." -/obj/item/storage/slide_projector/remove_from_storage(obj/item/W, atom/new_location, var/NoUpdate = 0) - . = ..() - if(. && W == current_slide) - set_slide(length(contents) ? contents[1] : null) - -/obj/item/storage/slide_projector/handle_item_insertion(var/obj/item/W, var/prevent_warning = 0, var/NoUpdate = 0) - . = ..() - if(. && !current_slide) - set_slide(W) - -/obj/item/storage/slide_projector/afterattack(atom/target, mob/user, proximity_flag, click_parameters) +/obj/item/slide_projector/afterattack(atom/target, mob/user, proximity_flag, click_parameters) if(!current_slide) return project_at(get_turf(target)) -/obj/item/storage/slide_projector/proc/set_slide(obj/item/new_slide) +/obj/item/slide_projector/proc/set_slide(obj/item/new_slide) current_slide = new_slide playsound(loc, 'sound/machines/slide_change.ogg', 50) if(projection) project_at(get_turf(projection)) -/obj/item/storage/slide_projector/proc/check_projections() +/obj/item/slide_projector/proc/check_projections() if(!projection) return if(!(projection in view(7,get_turf(src)))) stop_projecting() -/obj/item/storage/slide_projector/proc/stop_projecting() +/obj/item/slide_projector/proc/stop_projecting() if(projection) QDEL_NULL(projection) - GLOB.moved_event.unregister(src, src, .proc/check_projections) + events_repository.unregister(/decl/observ/moved, src, src, PROC_REF(check_projections)) update_icon() - -/obj/item/storage/slide_projector/proc/project_at(turf/target) + +/obj/item/slide_projector/proc/project_at(turf/target) stop_projecting() if(!current_slide) return @@ -70,19 +60,19 @@ break projection = new projection_type(target) projection.set_source(current_slide) - GLOB.moved_event.register(src, src, .proc/check_projections) + events_repository.register(/decl/observ/moved, src, src, PROC_REF(check_projections)) update_icon() -/obj/item/storage/slide_projector/attack_self(mob/user) +/obj/item/slide_projector/attack_self(mob/user) interact(user) -/obj/item/storage/slide_projector/interact(mob/user) +/obj/item/slide_projector/interact(mob/user) var/data = list() if(projection) - data += "Disable projector" + data += "Disable projector" else data += "Projector inactive" - + var/table = list("") + dat += text("") dat += "
              #SLIDESHOW") var/i = 1 for(var/obj/item/I in contents) @@ -90,14 +80,14 @@ if(I == current_slide) table += "[I.name]SHOWING" else - table += "[I.name]SHOW" + table += "[I.name]SHOW" i++ data += jointext(table,null) var/datum/browser/popup = new(user, "slides\ref[src]", "Slide Projector") popup.set_content(jointext(data, "
              ")) popup.open() -/obj/item/storage/slide_projector/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state) +/obj/item/slide_projector/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state) . = ..() if(.) return @@ -113,7 +103,7 @@ return TOPIC_HANDLED set_slide(contents[index]) . = TOPIC_REFRESH - + if(. == TOPIC_REFRESH) interact(user) @@ -123,14 +113,14 @@ icon_state = "white" anchored = TRUE simulated = FALSE - appearance_flags = PIXEL_SCALE blend_mode = BLEND_ADD - plane = EFFECTS_ABOVE_LIGHTING_PLANE + layer = ABOVE_LIGHTING_LAYER + plane = ABOVE_LIGHTING_PLANE alpha = 100 var/weakref/source /obj/effect/projection/on_update_icon() - filters = filter(type="drop_shadow", color = COLOR_WHITE, size = 4, offset = 1,x = 0, y = 0) + add_filter("glow", 1, list(type = "drop_shadow", color = COLOR_WHITE, size = 4, offset = 1,x = 0, y = 0)) project_icon() /obj/effect/projection/proc/project_icon() @@ -153,13 +143,13 @@ desc = "It's currently showing \the [I]." update_icon() -/obj/effect/projection/examine(mob/user, distance) +/obj/effect/projection/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/obj/item/slide = source.resolve() if(!istype(slide)) qdel(src) return - return slide.examine(user, 1) + . += slide.get_examine_strings(user, distance, infix, suffix) /obj/effect/projection/photo alpha = 170 diff --git a/code/game/machinery/smartfridge/_smartfridge.dm b/code/game/machinery/smartfridge/_smartfridge.dm new file mode 100644 index 000000000000..68db0c387afd --- /dev/null +++ b/code/game/machinery/smartfridge/_smartfridge.dm @@ -0,0 +1,247 @@ + +/* SmartFridge. Much todo +*/ +/obj/machinery/smartfridge + name = "\improper SmartFridge" + icon = 'icons/obj/machines/smartfridges/science.dmi' + icon_state = ICON_STATE_WORLD + layer = BELOW_OBJ_LAYER + density = TRUE + anchored = TRUE + idle_power_usage = 5 + active_power_usage = 100 + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE + obj_flags = OBJ_FLAG_ANCHORABLE | OBJ_FLAG_ROTATABLE + atmos_canpass = CANPASS_NEVER + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = 0 + + var/overlay_contents_icon = 'icons/obj/machines/smartfridges/contents_chem.dmi' + var/list/item_records = list() + var/seconds_electrified = 0; + var/shoot_inventory = 0 + var/locked = 0 + var/scan_id = 1 + var/is_secure = 0 + +/obj/machinery/smartfridge/Initialize() + if(is_secure) + wires = new/datum/wires/smartfridge/secure(src) + else + wires = new/datum/wires/smartfridge(src) + . = ..() + queue_icon_update() + +/obj/machinery/smartfridge/Destroy() + for(var/datum/stored_items/S in item_records) + qdel(S) + item_records = null + return ..() + +/obj/machinery/smartfridge/get_req_access() + if(!scan_id) + return list() + return ..() + +/obj/machinery/smartfridge/proc/accept_check(var/obj/item/stocking_item) + if(istype(stocking_item,/obj/item/food/grown) || istype(stocking_item,/obj/item/seeds)) + return 1 + return 0 + +/obj/machinery/smartfridge/Process() + if(stat & (BROKEN|NOPOWER)) + return + if(src.seconds_electrified > 0) + src.seconds_electrified-- + if(src.shoot_inventory && prob(2)) + src.throw_item() + +/obj/machinery/smartfridge/on_update_icon() + + // Reset our icon_state and overlays. + icon_state = initial(icon_state) + cut_overlays() // Does not appear to be called lower down the chain, sadly. + + // Draw our side panel overlay (for access checking) + var/draw_state + if(is_secure) + if(stat & BROKEN) + draw_state = "[icon_state]-sidepanel-broken" + else + draw_state = "[icon_state]-sidepanel" + if(check_state_in_icon(draw_state, icon)) + add_overlay(draw_state) + + // Draw our panel overlay. + if(panel_open) + draw_state = "[icon_state]-panel" + if(check_state_in_icon(draw_state, icon)) + add_overlay(draw_state) + + // Fridge contents + if(overlay_contents_icon) + var/is_off = inoperable() ? "-off" : "" + switch(contents.len - LAZYLEN(component_parts)) + if(0) + draw_state = "empty[is_off]" + if(1 to 2) + draw_state = "1[is_off]" + if(3 to 5) + draw_state = "2[is_off]" + if(6 to 8) + draw_state = "3[is_off]" + else + draw_state = "4[is_off]" + if(draw_state && check_state_in_icon(draw_state, icon)) + add_overlay(image(overlay_contents_icon, draw_state)) + + // Fridge top + if(stat & BROKEN) + draw_state = "[draw_state]-top-broken" + else + draw_state = "[icon_state]-top" + + if(check_state_in_icon(draw_state, icon)) + var/image/overlay_image = image(icon, draw_state) + overlay_image.pixel_z = 32 + overlay_image.layer = ABOVE_WINDOW_LAYER + add_overlay(overlay_image) + + // Append our off state if needed. + if(stat & BROKEN) + icon_state = "[icon_state]-broken" + else if(stat & NOPOWER) + icon_state = "[icon_state]-off" + +/obj/machinery/smartfridge/dismantle() + for(var/datum/stored_items/stored_item in item_records) + while(stored_item.amount > 0) + stored_item.get_product(get_turf(src)) // They'd get dumped anyway, but this makes things GC properly. + ..() + +/******************* +* Item Adding +********************/ + +/obj/machinery/smartfridge/state_transition(decl/machine_construction/new_state, mob/user) + . = ..() + update_icon() + +/obj/machinery/smartfridge/attackby(var/obj/item/used_item, var/mob/user) + if(accept_check(used_item)) + if(!user.try_unequip(used_item)) + return TRUE + stock_item(used_item) + user.visible_message("\The [user] has added \the [used_item] to \the [src].", "You add \the [used_item] to \the [src].") + update_icon() + return TRUE + + if(used_item.storage) + var/plants_loaded = 0 + for(var/obj/G in used_item.storage.get_contents()) + if(accept_check(G) && used_item.storage.remove_from_storage(user, G, src, TRUE)) + plants_loaded++ + stock_item(G) + used_item.storage.finish_bulk_removal() + + if(plants_loaded) + user.visible_message("\The [user] loads \the [src] with the contents of \the [used_item].", "You load \the [src] with the contents of \the [used_item].") + if(length(used_item.storage.get_contents()) > 0) + to_chat(user, "Some items were refused.") + return TRUE + return ..() + +/obj/machinery/smartfridge/proc/stock_item(var/obj/item/stocking_item) + for(var/datum/stored_items/stored_item in item_records) + if(istype(stocking_item, stored_item.item_path) && stocking_item.name == stored_item.item_name) + stock(stored_item, stocking_item) + return + + var/datum/stored_items/stored_item = new/datum/stored_items(src, stocking_item.type, stocking_item.name) + dd_insertObjectList(item_records, stored_item) + stock(stored_item, stocking_item) + +/obj/machinery/smartfridge/proc/stock(var/datum/stored_items/stored_item, var/obj/item/stocking_item) + stored_item.add_product(stocking_item) + SSnano.update_uis(src) + +/obj/machinery/smartfridge/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/******************* +* SmartFridge Menu +********************/ + +/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + user.set_machine(src) + + var/data[0] + data["contents"] = null + data["electrified"] = seconds_electrified > 0 + data["shoot_inventory"] = shoot_inventory + data["locked"] = locked + data["secure"] = is_secure + + var/list/items[0] + for (var/i=1 to length(item_records)) + var/datum/stored_items/stored_item = item_records[i] + var/count = stored_item.get_amount() + if(count > 0) + items.Add(list(list("display_name" = html_encode(capitalize(stored_item.item_name)), "vend" = i, "quantity" = count))) + + if(items.len > 0) + data["contents"] = items + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "smartfridge.tmpl", src.name, 400, 500) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/smartfridge/OnTopic(mob/user, href_list) + if((. = ..())) + return + + if(href_list["close"]) + return TOPIC_CLOSE + + if(href_list["vend"]) + var/index = text2num(href_list["vend"]) + var/datum/stored_items/stored_item = item_records[index] + var/count = stored_item.get_amount() + var/amount = clamp(text2num(href_list["amount"]), 0, count) + + // Sanity check, there are probably ways to press the button when it shouldn't be possible. + if(amount <= 0) + return TOPIC_REFRESH // you must be confused, we have none of that here! + for(var/i = 1 to amount) + stored_item.get_product(get_turf(src)) + update_icon() + var/vend_state = "[icon_state]-vend" + if (check_state_in_icon(vend_state, icon)) //Show the vending animation if needed + flick(vend_state, src) + return TOPIC_REFRESH + return TOPIC_NOACTION + +/obj/machinery/smartfridge/proc/throw_item() + var/obj/throw_item = null + var/mob/living/target = locate() in view(7,src) + if(!target) + return 0 + + for(var/datum/stored_items/stored_item in src.item_records) + throw_item = stored_item.get_product(loc) + if(!QDELETED(throw_item)) + break + + if(QDELETED(throw_item)) + return 0 + spawn(0) + throw_item.throw_at(target,16,3) + src.visible_message("[src] launches [throw_item.name] at [target.name]!") + update_icon() + return 1 + diff --git a/code/game/machinery/smartfridge/_smartfridge_secure.dm b/code/game/machinery/smartfridge/_smartfridge_secure.dm new file mode 100644 index 000000000000..25ba47725b70 --- /dev/null +++ b/code/game/machinery/smartfridge/_smartfridge_secure.dm @@ -0,0 +1,22 @@ +/************************ +* Secure SmartFridges +*************************/ +/obj/machinery/smartfridge/secure + is_secure = 1 + +/obj/machinery/smartfridge/secure/CanUseTopic(mob/user, datum/topic_state/state, href_list) + if(!allowed(user) && !emagged && locked != -1 && href_list && href_list["vend"] && scan_id) + to_chat(user, SPAN_WARNING("Access denied.")) + var/vend_state = "[icon_state]-deny" + if (check_state_in_icon(vend_state, icon)) //Show the vending animation if needed + flick(vend_state, src) + return STATUS_CLOSE + return ..() + +/obj/machinery/smartfridge/secure/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = 1 + locked = -1 + req_access.Cut() + to_chat(user, SPAN_NOTICE("You short out the product lock on \the [src].")) + return 1 diff --git a/code/game/machinery/smartfridge/chemistry.dm b/code/game/machinery/smartfridge/chemistry.dm new file mode 100644 index 000000000000..486a812d2816 --- /dev/null +++ b/code/game/machinery/smartfridge/chemistry.dm @@ -0,0 +1,9 @@ +/obj/machinery/smartfridge/chemistry + name = "\improper Smart Chemical Storage" + desc = "A refrigerated storage unit for medicine and chemical storage." + overlay_contents_icon = 'icons/obj/machines/smartfridges/contents_chem.dmi' + +/obj/machinery/smartfridge/chemistry/accept_check(var/obj/item/O) + if(istype(O,/obj/item/pill_bottle) || istype(O,/obj/item/chems)) + return 1 + return 0 diff --git a/code/game/machinery/smartfridge/drinks.dm b/code/game/machinery/smartfridge/drinks.dm new file mode 100644 index 000000000000..f90f23e2d4b0 --- /dev/null +++ b/code/game/machinery/smartfridge/drinks.dm @@ -0,0 +1,9 @@ +/obj/machinery/smartfridge/drinks + name = "\improper Drink Showcase" + desc = "A refrigerated storage unit for tasty tasty alcohol." + icon = 'icons/obj/machines/smartfridges/dark.dmi' + overlay_contents_icon = 'icons/obj/machines/smartfridges/contents_drink.dmi' + +/obj/machinery/smartfridge/drinks/accept_check(var/obj/item/O) + if(istype(O,/obj/item/chems/glass) || istype(O,/obj/item/chems/drinks) || istype(O,/obj/item/chems/condiment)) + return 1 diff --git a/code/game/machinery/smartfridge/drying_oven.dm b/code/game/machinery/smartfridge/drying_oven.dm new file mode 100644 index 000000000000..ece54b6c8c3a --- /dev/null +++ b/code/game/machinery/smartfridge/drying_oven.dm @@ -0,0 +1,35 @@ +/obj/machinery/smartfridge/drying_oven + name = "drying oven" + desc = "A machine for drying plants." + icon = 'icons/obj/machines/smartfridges/drying_oven.dmi' + overlay_contents_icon = 'icons/obj/machines/smartfridges/contents_plants.dmi' + obj_flags = OBJ_FLAG_ANCHORABLE + atom_flags = ATOM_FLAG_CLIMBABLE + +/obj/machinery/smartfridge/drying_oven/accept_check(var/obj/item/O) + return istype(O) && O.is_dryable() + +/obj/machinery/smartfridge/drying_oven/Process() + ..() + if(inoperable()) + return + var/do_update = FALSE + for(var/obj/item/thing in get_contained_external_atoms()) + var/obj/item/product = thing.dry_out(src, silent = TRUE) + if(product) + product.dropInto(loc) + do_update = TRUE + if(QDELETED(thing) || !(thing in contents)) + for(var/datum/stored_items/I in item_records) + I.instances -= thing + if(do_update) + update_icon() + +/obj/machinery/smartfridge/drying_oven/on_update_icon() + if(!inoperable()) + for(var/datum/stored_items/I in item_records) + if(I.get_amount()) + cut_overlays() + icon_state = "[initial(icon_state)]-closed" + return + return ..() diff --git a/code/game/machinery/smartfridge/foods.dm b/code/game/machinery/smartfridge/foods.dm new file mode 100644 index 000000000000..b023cc97a94b --- /dev/null +++ b/code/game/machinery/smartfridge/foods.dm @@ -0,0 +1,14 @@ +/obj/machinery/smartfridge/foods + name = "\improper Hot Foods Display" + desc = "A heated storage unit for piping hot meals." + icon = 'icons/obj/machines/smartfridges/food.dmi' + overlay_contents_icon = 'icons/obj/machines/smartfridges/contents_food.dmi' + +/obj/machinery/smartfridge/foods/accept_check(var/obj/item/O) + var/static/list/_food_types = list( + /obj/item/food, + /obj/item/utensil, + /obj/item/chems/glass/bowl, + /obj/item/chems/glass/handmade/bowl + ) + return istype(O) && REAGENT_TOTAL_VOLUME(O.reagents) && is_type_in_list(O, _food_types) diff --git a/code/game/machinery/smartfridge/medbay.dm b/code/game/machinery/smartfridge/medbay.dm new file mode 100644 index 000000000000..c1361990e87a --- /dev/null +++ b/code/game/machinery/smartfridge/medbay.dm @@ -0,0 +1,15 @@ + +/obj/machinery/smartfridge/secure/medbay + name = "\improper Refrigerated Medicine Storage" + desc = "A refrigerated storage unit for storing medicine and chemicals." + overlay_contents_icon = 'icons/obj/machines/smartfridges/contents_chem.dmi' + initial_access = list(list(access_medical, access_chemistry)) + +/obj/machinery/smartfridge/secure/medbay/accept_check(var/obj/item/O) + if(istype(O,/obj/item/chems/glass)) + return 1 + if(istype(O,/obj/item/pill_bottle)) + return 1 + if(istype(O,/obj/item/chems/pill)) + return 1 + return 0 diff --git a/code/game/machinery/smartfridge/produce.dm b/code/game/machinery/smartfridge/produce.dm new file mode 100644 index 000000000000..b7ef607b1b5d --- /dev/null +++ b/code/game/machinery/smartfridge/produce.dm @@ -0,0 +1,6 @@ +/obj/machinery/smartfridge/produce + name = "produce smartfridge" + desc = "A refrigerated storage unit for fruits and vegetables." + +/obj/machinery/smartfridge/produce/accept_check(var/obj/item/O) + return istype(O, /obj/item/food/grown) diff --git a/code/game/machinery/smartfridge/seeds.dm b/code/game/machinery/smartfridge/seeds.dm new file mode 100644 index 000000000000..9aa1259e5283 --- /dev/null +++ b/code/game/machinery/smartfridge/seeds.dm @@ -0,0 +1,8 @@ +/obj/machinery/smartfridge/seeds + name = "\improper MegaSeed Servitor" + desc = "When you need seeds fast!" + +/obj/machinery/smartfridge/seeds/accept_check(var/obj/item/O) + if(istype(O,/obj/item/seeds/)) + return 1 + return 0 diff --git a/code/game/machinery/smartfridge/sheets.dm b/code/game/machinery/smartfridge/sheets.dm new file mode 100644 index 000000000000..a1e9c3be5f84 --- /dev/null +++ b/code/game/machinery/smartfridge/sheets.dm @@ -0,0 +1,6 @@ +/obj/machinery/smartfridge/sheets + name = "raw material storage" + desc = "A storage unit for bundles of material sheets, ingots and other shapes." + +/obj/machinery/smartfridge/sheets/accept_check(var/obj/item/O) + return istype(O, /obj/item/stack/material) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 405a102cd3e3..ab59748f0d8e 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -1,106 +1,107 @@ /obj/machinery/space_heater use_power = POWER_USE_OFF - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE icon = 'icons/obj/atmos.dmi' icon_state = "sheater-off" name = "space heater" - desc = "Made by Space Amish using traditional space techniques, this heater is guaranteed not to set anything, or anyone, on fire." - var/on = 0 - var/set_temperature = T0C + 20 //K - var/active = 0 - var/heating_power = 40 KILOWATTS - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + desc = "This heater is guaranteed not to set anything, or anyone, on fire." + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + + atom_flags = ATOM_FLAG_CLIMBABLE + movable_flags = MOVABLE_FLAG_WHEELED clicksound = "switch" + light_power = 0.5 + construct_state = /decl/machine_construction/default/panel_closed stat_immune = 0 uncreated_component_parts = null -/obj/machinery/space_heater/on_update_icon(var/rebuild_overlay = 0) + var/on = 0 + var/set_temperature = T0C + 20 //K + var/active = 0 + var/heating_power = 40 KILOWATTS + +/obj/machinery/space_heater/on_update_icon() + . = ..() if(!on) icon_state = "sheater-off" set_light(0) else if(active > 0) icon_state = "sheater-heat" - set_light(0.7, 1, 2, 3, COLOR_SEDONA) + set_light(3, l_color = COLOR_SEDONA) else if(active < 0) icon_state = "sheater-cool" - set_light(0.7, 1, 2, 3, COLOR_DEEP_SKY_BLUE) + set_light(3, l_color = COLOR_DEEP_SKY_BLUE) else icon_state = "sheater-standby" set_light(0) + if(panel_open) + add_overlay("sheater-open") - if(rebuild_overlay) - overlays.Cut() - if(panel_open) - overlays += "sheater-open" - -/obj/machinery/space_heater/examine(mob/user) +/obj/machinery/space_heater/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - - to_chat(user, "The heater is [on ? "on" : "off"] and the hatch is [panel_open ? "open" : "closed"].") + . += "\The [src] is [on ? "on" : "off"] and the hatch is [panel_open ? "open" : "closed"]." var/obj/item/cell/cell = get_cell() if(panel_open) - to_chat(user, "The power cell is [cell ? "installed" : "missing"].") + . += "The power cell is [cell ? "installed" : "missing"]." else - to_chat(user, "The charge meter reads [cell ? round(cell.percent(),1) : 0]%") + . += "The charge meter reads [cell ? round(cell.percent(),1) : 0]%" /obj/machinery/space_heater/state_transition(decl/machine_construction/new_state, mob/user) . = ..() - if(istype(new_state, /decl/machine_construction/default/panel_open) && CanInteract(user, DefaultTopicState())) - interact(user) + if(istype(new_state, /decl/machine_construction/default/panel_closed) || !CanInteract(user, DefaultTopicState())) + SSnano.close_uis(src) + else if(istype(new_state, /decl/machine_construction/default/panel_open)) + SSnano.update_uis(src) /obj/machinery/space_heater/interface_interact(mob/user) if(panel_open) interact(user) return TRUE -/obj/machinery/space_heater/interact(mob/user) - if(panel_open) - var/list/dat = list() - var/obj/item/cell/cell = get_cell() - dat += "Power cell: " - if(cell) - dat += "Installed
              " - else - dat += "Removed
              " - - dat += "Power Level: [cell ? round(cell.percent(),1) : 0]%

              " - - dat += "Set Temperature: " - - dat += "-" - - dat += " [set_temperature]K ([set_temperature-T0C]°C)" - dat += "+
              " - - var/datum/browser/popup = new(usr, "spaceheater", "Space Heater Control Panel") - popup.set_content(jointext(dat, null)) - popup.set_title_image(usr.browse_rsc_icon(src.icon, "sheater-standby")) - popup.open() +/obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/topic_state/state = global.physical_no_access_topic_state) + if(!panel_open) + SSnano.close_uis(src) // should be handled in state_transition, but just in case + return + var/obj/item/cell/cell = get_cell() + var/list/data = list( + "has_cell" = !!cell, + "cell_percent" = cell?.percent(), + "set_temperature" = set_temperature, + ) + // update the ui if it exists, returns null if no ui is passed/found + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "space_heater.tmpl", "Space Heater Control Panel") + ui.set_initial_data(data) + ui.open() /obj/machinery/space_heater/physical_attack_hand(mob/user) if(!panel_open) on = !on - user.visible_message("[user] switches [on ? "on" : "off"] the [src].","You switch [on ? "on" : "off"] the [src].") + user.visible_message( + SPAN_NOTICE("[user] switches [on ? "on" : "off"] \the [src]."), + SPAN_NOTICE("You switch [on ? "on" : "off"] \the [src]."), + SPAN_NOTICE("You hear a [on ? "machine rumble to life" : "rumbling machine go silent"].") + ) update_icon() return TRUE - -/obj/machinery/space_heater/Topic(href, href_list, state = GLOB.physical_state) - if (..()) - show_browser(usr, null, "window=spaceheater") - usr.unset_machine() - return 1 - - switch(href_list["op"]) - if("temp") - var/value = text2num(href_list["val"]) - - // limit to 0-90 degC - set_temperature = dd_range(T0C, T0C + 90, set_temperature + value) - - updateDialog() + return FALSE + +// This machine has physical, mechanical buttons. +/obj/machinery/space_heater/DefaultTopicState() + return global.physical_topic_state + +/obj/machinery/space_heater/OnTopic(mob/user, href_list, state) + if ((. = ..())) + return + if(href_list["adj_temp"]) + var/old_temperature = set_temperature + set_temperature = clamp(round(set_temperature + text2num(href_list["adj_temp"])), T0C, 90 CELSIUS) // 90C is pretty damn hot but okay + if(old_temperature != set_temperature) + . = TOPIC_REFRESH /obj/machinery/space_heater/power_change() . = ..() diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 887e37a315e3..4059128a7d11 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -14,9 +14,11 @@ icon_state = "frame" name = "status display" layer = ABOVE_WINDOW_LAYER - anchored = 1 - density = 0 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + anchored = TRUE + density = FALSE idle_power_usage = 10 + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' var/mode = 1 // 0 = Blank // 1 = Shuttle timer // 2 = Arbitrary message(s) @@ -84,21 +86,24 @@ if(STATUS_DISPLAY_BLANK) //blank return 1 if(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) //emergency shuttle timer - if(SSevac.evacuation_controller.is_prepared()) - message1 = "-ETD-" - if (SSevac.evacuation_controller.waiting_to_leave()) - message2 = "Launch" - else + if(SSevac.evacuation_controller) + if(SSevac.evacuation_controller.is_prepared()) + message1 = "-ETD-" + if (SSevac.evacuation_controller.waiting_to_leave()) + message2 = "Launch" + else + message2 = get_shuttle_timer() + if(length(message2) > CHARS_PER_LINE) + message2 = "Error" + update_display(message1, message2) + else if(SSevac.evacuation_controller.has_eta()) + message1 = "-ETA-" message2 = get_shuttle_timer() if(length(message2) > CHARS_PER_LINE) message2 = "Error" - update_display(message1, message2) - else if(SSevac.evacuation_controller.has_eta()) - message1 = "-ETA-" - message2 = get_shuttle_timer() - if(length(message2) > CHARS_PER_LINE) - message2 = "Error" - update_display(message1, message2) + update_display(message1, message2) + else + update_display("ERROR", "ERROR") return 1 if(STATUS_DISPLAY_MESSAGE) //custom messages var/line1 @@ -136,13 +141,13 @@ return 1 return 0 -/obj/machinery/status_display/examine(mob/user) +/obj/machinery/status_display/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(mode != STATUS_DISPLAY_BLANK && mode != STATUS_DISPLAY_ALERT) - to_chat(user, "The display says:
              \t[sanitize(message1)]
              \t[sanitize(message2)]") + . += "The display says:
              \t[sanitize(message1)]
              \t[sanitize(message2)]" if(mode == STATUS_DISPLAY_ALERT) - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - to_chat(user, "The current alert level is [security_state.current_security_level.name].") + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + . += "The current alert level is [security_state.current_security_level.name]." /obj/machinery/status_display/proc/set_message(m1, m2) if(m1) @@ -162,12 +167,25 @@ /obj/machinery/status_display/proc/display_alert() remove_display() - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - var/decl/security_level/sl = security_state.current_security_level + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + var/decl/security_level/sec_level = security_state.current_security_level + + set_light(sec_level.light_range, sec_level.light_power, sec_level.light_color_status_display) + + if(sec_level.alarm_appearance.display_icon) + var/image/alert1 = image(sec_level.icon, sec_level.alarm_appearance.display_icon) + alert1.color = sec_level.alarm_appearance.display_icon_color + overlays |= alert1 + + if(sec_level.alarm_appearance.display_icon_twotone) + var/image/alert2 = image(sec_level.icon, sec_level.alarm_appearance.display_icon_twotone) + alert2.color = sec_level.alarm_appearance.display_icon_twotone_color + overlays |= alert2 - var/image/alert = image(sl.icon, sl.overlay_status_display) - set_light(sl.light_max_bright, sl.light_inner_range, sl.light_outer_range, 2, sl.light_color_alarm) - overlays |= alert + if(sec_level.alarm_appearance.display_emblem) + var/image/alert3 = image(sec_level.icon, sec_level.alarm_appearance.display_emblem) + alert3.color = sec_level.alarm_appearance.display_emblem_color + overlays |= alert3 /obj/machinery/status_display/proc/set_picture(state) remove_display() @@ -175,7 +193,7 @@ picture_state = state picture = image('icons/obj/status_display.dmi', icon_state=picture_state) overlays |= picture - set_light(0.5, 0.1, 1, 2, COLOR_WHITE) + set_light(2, 0.5, COLOR_WHITE) /obj/machinery/status_display/proc/update_display(line1, line2) line1 = uppertext(line1) @@ -183,10 +201,10 @@ var/new_text = {"
              [line1]
              [line2]
              "} if(maptext != new_text) maptext = new_text - set_light(0.5, 0.1, 1, 2, COLOR_WHITE) + set_light(2, 0.5, COLOR_WHITE) /obj/machinery/status_display/proc/get_shuttle_timer() - var/timeleft = SSevac.evacuation_controller.get_eta() + var/timeleft = SSevac.evacuation_controller ? SSevac.evacuation_controller.get_eta() : 0 if(timeleft < 0) return "" return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]" diff --git a/code/game/machinery/status_display_ai.dm b/code/game/machinery/status_display_ai.dm index dcf8b8bb3519..46365b4e82ad 100644 --- a/code/game/machinery/status_display_ai.dm +++ b/code/game/machinery/status_display_ai.dm @@ -6,7 +6,7 @@ overlay = over ckey = key -var/list/ai_status_emotions = list( +var/global/list/ai_status_emotions = list( "Very Happy" = new /datum/ai_emotion("ai_veryhappy"), "Happy" = new /datum/ai_emotion("ai_happy"), "Neutral" = new /datum/ai_emotion("ai_neutral"), @@ -58,8 +58,8 @@ var/list/ai_status_emotions = list( icon = 'icons/obj/status_display.dmi' icon_state = "frame" name = "AI display" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE var/mode = 0 // 0 = Blank // 1 = AI emoticon diff --git a/code/game/machinery/status_light.dm b/code/game/machinery/status_light.dm index 46b2cd30d083..1827bfbd7bdd 100644 --- a/code/game/machinery/status_light.dm +++ b/code/game/machinery/status_light.dm @@ -3,6 +3,8 @@ desc = "A status indicator for a combustion chamber, based on temperature." icon = 'icons/obj/machines/door_timer.dmi' icon_state = "doortimer-p" + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":32}, "WEST":{"x":-32}}' + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED var/frequency = 1441 var/alert_temperature = 10000 var/alert = 1 @@ -11,8 +13,11 @@ /obj/machinery/status_light/Initialize() . = ..() update_icon() - radio_connection = register_radio(src, frequency, frequency, RADIO_ATMOSIA) + radio_connection = register_radio_to_controller(src, frequency, frequency, RADIO_ATMOSIA) +/obj/machinery/status_light/Destroy() + radio_controller.remove_object(src,frequency) + return ..() /obj/machinery/status_light/on_update_icon() if(stat & (NOPOWER|BROKEN)) diff --git a/code/game/machinery/suit_cycler.dm b/code/game/machinery/suit_cycler.dm index 0770ba80ecd3..bb484cec914c 100644 --- a/code/game/machinery/suit_cycler.dm +++ b/code/game/machinery/suit_cycler.dm @@ -2,25 +2,25 @@ name = "suit cycler unit" desc = "An industrial machine for painting and refitting voidsuits." - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE icon = 'icons/obj/suitstorage.dmi' icon_state = "base" initial_access = list(list(access_captain, access_bridge)) - var/active = 0 // PLEASE HOLD. - var/safeties = 1 // The cycler won't start with a living thing inside it unless safeties are off. - var/irradiating = 0 // If this is > 0, the cycler is decontaminating whatever is inside it. + var/active = FALSE // PLEASE HOLD. + var/safeties = TRUE //! The cycler won't start with a living thing inside it unless safeties are off. + var/irradiating = 0 //! The number of Process() ticks we should irradiate our contents for. If > 0, will irradiate contents. Decrements every Process(). var/radiation_level = 2 // 1 is removing germs, 2 is removing blood, 3 is removing contaminants. - var/model_text = "" // Some flavour text for the topic box. - var/locked = 1 // If locked, nothing can be taken from or added to the cycler. - var/can_repair = 1 // If set, the cycler can repair voidsuits. - var/electrified = 0 // If set, will shock users. + var/model_text = "" //! Some flavour text for the topic box. + var/locked = TRUE //! If locked, nothing can be taken from or added to the cycler. + var/can_repair = TRUE //! If TRUE, the cycler can repair voidsuits. + var/electrified = 0 //! The number of Process() ticks we should shock users for. If > 0, will shock users. Decrements every Process(). - // Possible modifications to pick between - var/list/available_modifications = list( + /// Possible suit modifier decls to pick between + var/list/decl/item_modifier/space_suit/available_modifications = list( /decl/item_modifier/space_suit/engineering, /decl/item_modifier/space_suit/mining, /decl/item_modifier/space_suit/medical, @@ -31,7 +31,7 @@ ) // Extra modifications to add when emagged, duplicates won't be added - var/emagged_modifications = list( + var/list/decl/item_modifier/space_suit/emagged_modifications = list( /decl/item_modifier/space_suit/engineering, /decl/item_modifier/space_suit/mining, /decl/item_modifier/space_suit/medical, @@ -48,8 +48,8 @@ var/decl/item_modifier/target_modification var/target_bodytype - var/mob/living/carbon/human/occupant - var/obj/item/clothing/suit/space/void/suit + var/mob/living/human/occupant + var/obj/item/clothing/suit/space/suit var/obj/item/clothing/head/helmet/space/helmet var/obj/item/clothing/shoes/magboots/boots @@ -73,40 +73,74 @@ LAZYADD(new_overlays, helmet.get_mob_overlay(null, slot_head_str)) if(occupant) LAZYADD(new_overlays, image(occupant)) - LAZYADD(new_overlays, image(icon, "overbase")) + LAZYADD(new_overlays, image(icon, "overbase", layer = ABOVE_HUMAN_LAYER)) if(locked || active) - LAZYADD(new_overlays, image(icon, "closed")) + LAZYADD(new_overlays, image(icon, "closed", layer = ABOVE_HUMAN_LAYER)) else - LAZYADD(new_overlays, image(icon, "open")) + LAZYADD(new_overlays, image(icon, "open", layer = ABOVE_HUMAN_LAYER)) if(irradiating) - LAZYADD(new_overlays, image(icon, "light_radiation")) - set_light(0.8, 1, 3, 2, COLOR_RED_LIGHT) + LAZYADD(new_overlays, image(icon, "light_radiation", layer = ABOVE_HUMAN_LAYER)) + set_light(3, 0.8, COLOR_RED_LIGHT) else if(active) - LAZYADD(new_overlays, image(icon, "light_active")) - set_light(0.8, 1, 3, 2, COLOR_YELLOW) + LAZYADD(new_overlays, image(icon, "light_active", layer = ABOVE_HUMAN_LAYER)) + set_light(3, 0.8, COLOR_YELLOW) else set_light(0) if(panel_open) - LAZYADD(new_overlays, image(icon, "panel")) + LAZYADD(new_overlays, image(icon, "panel", layer = ABOVE_HUMAN_LAYER)) overlays = new_overlays +/obj/machinery/suit_cycler/proc/loaded_item_destroyed() + if(suit && QDELETED(suit)) + suit = null + . = TRUE + if(helmet && QDELETED(helmet)) + helmet = null + . = TRUE + if(boots && QDELETED(boots)) + boots = null + . = TRUE + if(.) + update_icon() + +/obj/machinery/suit_cycler/proc/set_suit(obj/item/new_suit) + if(istype(suit)) + events_repository.unregister(/decl/observ/destroyed, suit, src) + suit = new_suit + if(istype(suit)) + events_repository.register(/decl/observ/destroyed, suit, src, TYPE_PROC_REF(/obj/machinery/suit_cycler, loaded_item_destroyed)) + +/obj/machinery/suit_cycler/proc/set_helmet(obj/item/new_helmet) + if(istype(helmet)) + events_repository.unregister(/decl/observ/destroyed, helmet, src) + helmet = new_helmet + if(istype(helmet)) + events_repository.register(/decl/observ/destroyed, helmet, src, TYPE_PROC_REF(/obj/machinery/suit_cycler, loaded_item_destroyed)) + +/obj/machinery/suit_cycler/proc/set_boots(obj/item/new_boots) + if(istype(boots)) + events_repository.unregister(/decl/observ/destroyed, boots, src) + boots = new_boots + if(istype(boots)) + events_repository.register(/decl/observ/destroyed, boots, src, TYPE_PROC_REF(/obj/machinery/suit_cycler, loaded_item_destroyed)) + /obj/machinery/suit_cycler/Initialize(mapload, d=0, populate_parts = TRUE) . = ..() if(!length(available_modifications) || !length(available_bodytypes)) - crash_with("Invalid setup: [log_info_line(src)]") + PRINT_STACK_TRACE("Invalid setup: [log_info_line(src)]") return INITIALIZE_HINT_QDEL if(populate_parts) if(ispath(suit)) - suit = new suit(src) + set_suit(new suit(src)) if(ispath(helmet)) - helmet = new helmet(src) + set_helmet(new helmet(src)) if(ispath(boots)) - boots = new boots(src) + set_boots(new boots(src)) available_modifications = list_values(decls_repository.get_decls(available_modifications)) @@ -114,15 +148,35 @@ target_bodytype = available_bodytypes[1] update_icon() +#ifdef UNIT_TEST + // Pass this off to lateload to make sure any Initialize() overrides on subtypes or modpacks also run. + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/suit_cycler/LateInitialize() + . = ..() + if(suit && !istype(suit)) + log_error("[type] has invalid suit instance: [suit]") + if(helmet && !istype(helmet)) + log_error("[type] has invalid helmet instance: [helmet]") + if(boots && !istype(boots)) + log_error("[type] has invalid suit instance: [boots]") +#endif + + /obj/machinery/suit_cycler/Destroy() - DROP_NULL(occupant) + if(occupant) + occupant.dropInto(loc) + occupant.reset_view() + occupant = null DROP_NULL(suit) DROP_NULL(helmet) DROP_NULL(boots) return ..() -/obj/machinery/suit_cycler/MouseDrop_T(var/mob/target, var/mob/user) - . = CanMouseDrop(target, user) && try_move_inside(target, user) +/obj/machinery/suit_cycler/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && ismob(dropping) && try_move_inside(dropping, user)) + return TRUE /obj/machinery/suit_cycler/proc/try_move_inside(var/mob/living/target, var/mob/living/user) if(!istype(target) || !istype(user) || !target.Adjacent(user) || !user.Adjacent(src) || user.incapacitated()) @@ -138,98 +192,83 @@ visible_message(SPAN_WARNING("\The [user] starts putting \the [target] into the suit cycler.")) if(do_after(user, 20, src)) - if(!istype(target) || locked || suit || helmet || !target.Adjacent(user) || !user.Adjacent(src) || user.incapacitated()) + if(!istype(target) || locked || suit || helmet || boots || !target.Adjacent(user) || !user.Adjacent(src) || user.incapacitated()) return FALSE - if (target.client) - target.client.perspective = EYE_PERSPECTIVE - target.client.eye = src + target.reset_view(src) target.forceMove(src) occupant = target add_fingerprint(user) + update_icon() return TRUE return FALSE -/obj/machinery/suit_cycler/attackby(obj/item/I, mob/user) +/obj/machinery/suit_cycler/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim) && try_move_inside(victim, user)) + qdel(grab) + updateUsrDialog() + return TRUE + return ..() + +/obj/machinery/suit_cycler/attackby(obj/item/used_item, mob/user) - if(electrified != 0) - if(shock(user, 100)) - return + if(electrified != 0 && shock(user, 100)) + return TRUE //Hacking init. - if(isMultitool(I) || isWirecutter(I)) + if(IS_MULTITOOL(used_item) || IS_WIRECUTTER(used_item)) if(panel_open) - attack_hand(user) - return - //Other interface stuff. - if(istype(I, /obj/item/grab)) - var/obj/item/grab/G = I - - if(!(ismob(G.affecting))) - return - - if(try_move_inside(G.affecting, user)) - qdel(G) - updateUsrDialog() - return + physical_attack_hand(user) + return TRUE - else if(istype(I, /obj/item/clothing/shoes/magboots)) + if(istype(used_item, /obj/item/clothing/shoes/magboots)) if(locked) to_chat(user, SPAN_WARNING("The suit cycler is locked.")) - return + return TRUE if(boots) to_chat(user, SPAN_WARNING("The cycler already contains some boots.")) - return - if(I.icon_override == CUSTOM_ITEM_MOB) - to_chat(user, "You cannot refit a customised voidsuit.") - return - if(!user.unEquip(I, src)) - return - to_chat(user, "You fit \the [I] into the suit cycler.") - boots = I + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, "You fit \the [used_item] into the suit cycler.") + set_boots(used_item) update_icon() updateUsrDialog() + return TRUE - else if(istype(I,/obj/item/clothing/head/helmet/space) && !istype(I, /obj/item/clothing/head/helmet/space/rig)) + if(istype(used_item,/obj/item/clothing/head/helmet/space) && !istype(used_item, /obj/item/clothing/head/helmet/space/rig)) if(locked) to_chat(user, SPAN_WARNING("The suit cycler is locked.")) - return + return TRUE if(helmet) to_chat(user, SPAN_WARNING("The cycler already contains a helmet.")) - return - - if(I.icon_override == CUSTOM_ITEM_MOB) - to_chat(user, "You cannot refit a customised voidsuit.") - return - if(!user.unEquip(I, src)) - return - to_chat(user, "You fit \the [I] into the suit cycler.") - helmet = I - update_icon() - updateUsrDialog() - return + return TRUE + + if(user.try_unequip(used_item, src)) + to_chat(user, "You fit \the [used_item] into the suit cycler.") + set_helmet(used_item) + update_icon() + updateUsrDialog() + return TRUE - else if(istype(I,/obj/item/clothing/suit/space/void)) + if(istype(used_item, /obj/item/clothing/suit/space)) if(locked) to_chat(user, SPAN_WARNING("The suit cycler is locked.")) - return + return TRUE if(suit) - to_chat(user, SPAN_WARNING("The cycler already contains a voidsuit.")) - return - - if(I.icon_override == CUSTOM_ITEM_MOB) - to_chat(user, "You cannot refit a customised voidsuit.") - return - if(!user.unEquip(I, src)) - return - to_chat(user, "You fit \the [I] into the suit cycler.") - suit = I - update_icon() - updateUsrDialog() - return + to_chat(user, SPAN_WARNING("The cycler already contains a spacesuit.")) + return TRUE + + if(user.try_unequip(used_item, src)) + to_chat(user, "You fit \the [used_item] into the suit cycler.") + set_suit(used_item) + update_icon() + updateUsrDialog() + return TRUE return ..() @@ -245,15 +284,15 @@ available_modifications |= additional_modifications emagged = 1 - safeties = 0 + safeties = FALSE req_access = list() updateUsrDialog() return 1 /obj/machinery/suit_cycler/physical_attack_hand(mob/user) - if(electrified != 0) - if(shock(user, 100)) - return TRUE + if(electrified != 0 && shock(user, 100)) + return TRUE + return ..() /obj/machinery/suit_cycler/interface_interact(mob/user) interact(user) @@ -271,120 +310,123 @@ else if(locked) dat += "
              The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator." if(allowed(user)) - dat += "
              Unlock unit" + dat += "
              Unlock unit" else dat += "

              Suit cycler

              " - dat += "Welcome to the [model_text ? "[model_text] " : ""]suit cycler control panel. Lock unit
              " + dat += "Welcome to the [model_text ? "[model_text] " : ""]suit cycler control panel. Lock unit
              " dat += "

              Maintenance

              " - dat += "Helmet: [helmet ? "\the [helmet]" : "no helmet stored" ]. Eject
              " - dat += "Suit: [suit ? "\the [suit]" : "no suit stored" ]. Eject
              " - dat += "Boots: [boots ? "\the [boots]" : "no boots stored" ]. Eject" + dat += "Helmet: [helmet ? "\the [helmet]" : "no helmet stored" ]. Eject
              " + dat += "Suit: [suit ? "\the [suit]" : "no suit stored" ]. Eject
              " + dat += "Boots: [boots ? "\the [boots]" : "no boots stored" ]. Eject" - if(can_repair && suit && istype(suit)) - dat += "[(suit.damage ? " Repair" : "")]" + if(can_repair && istype(suit)) + dat += "[(suit.damage ? " Repair" : "")]" dat += "
              UV decontamination systems: SYSTEM ERROR" : "green'>READY"]
              " dat += "Output level: [radiation_level]
              " - dat += "Select power level Begin decontamination cycle

              " + dat += "Select power level Begin decontamination cycle

              " dat += "

              Customisation

              " - dat += "Target product: [target_modification.name], [target_bodytype]." - dat += "
              Apply customisation routine

              " + dat += "Target product: [target_modification.name], [target_bodytype]." + dat += "
              Apply customisation routine

              " - var/datum/browser/written/popup = new(user, "suit_cycler", "Suit Cycler") + var/datum/browser/written_digital/popup = new(user, "suit_cycler", "Suit Cycler") popup.set_content(JOINTEXT(dat)) popup.open() -/obj/machinery/suit_cycler/Topic(href, href_list) +/obj/machinery/suit_cycler/OnTopic(user, href_list) if((. = ..())) return if(href_list["eject_suit"]) - if(!suit) return + if(!suit) return TOPIC_NOACTION suit.dropInto(loc) - suit = null + set_suit(null) else if(href_list["eject_helmet"]) - if(!helmet) return + if(!helmet) return TOPIC_NOACTION helmet.dropInto(loc) - helmet = null + set_helmet(null) else if(href_list["eject_boots"]) - if(!boots) return + if(!boots) return TOPIC_NOACTION boots.dropInto(loc) - boots = null + set_boots(null) else if(href_list["select_department"]) - var/choice = input("Please select the target department paintjob.", "Suit cycler", target_modification) as null|anything in available_modifications - if(choice && CanPhysicallyInteract(usr)) + var/choice = input(user, "Please select the target department paintjob.", "Suit cycler", target_modification) as null|anything in available_modifications + . = TOPIC_HANDLED // no matter what, we've prompted for user input so we cancel any further behavior on subtypes + if(choice && CanPhysicallyInteract(user)) target_modification = choice + . = TOPIC_REFRESH else if(href_list["select_bodytype"]) var/choice = input("Please select the target body configuration.","Suit cycler",null) as null|anything in available_bodytypes - if(choice && CanPhysicallyInteract(usr)) + . = TOPIC_HANDLED + if(choice && CanPhysicallyInteract(user)) target_bodytype = choice + . = TOPIC_REFRESH else if(href_list["select_rad_level"]) var/choices = list(1,2,3) if(emagged) choices = list(1,2,3,4,5) var/choice = input("Please select the desired radiation level.","Suit cycler",null) as null|anything in choices + . = TOPIC_HANDLED if(choice) radiation_level = choice + . = TOPIC_REFRESH else if(href_list["repair_suit"]) - - if(!suit || !can_repair) return - active = 1 - spawn(100) - repair_suit() - finished_job() + if(!suit || !can_repair) return TOPIC_NOACTION + active = TRUE + addtimer(CALLBACK(src, PROC_REF(repair_suit)), 10 SECONDS) + . = TOPIC_REFRESH else if(href_list["apply_paintjob"]) - - if(!suit && !helmet) return - active = 1 - spawn(100) - apply_paintjob() - finished_job() + if(!suit && !helmet) return TOPIC_NOACTION + active = TRUE + addtimer(CALLBACK(src, PROC_REF(apply_paintjob)), 10 SECONDS) + . = TOPIC_REFRESH else if(href_list["toggle_safties"]) safeties = !safeties + . = TOPIC_REFRESH else if(href_list["toggle_lock"]) - - if(allowed(usr)) + if(allowed(user)) locked = !locked - to_chat(usr, "You [locked ? "lock" : "unlock"] [src].") + to_chat(user, "You [locked ? "lock" : "unlock"] [src].") + . = TOPIC_REFRESH else - to_chat(usr, FEEDBACK_ACCESS_DENIED) + to_chat(user, FEEDBACK_ACCESS_DENIED) + . = TOPIC_HANDLED else if(href_list["begin_decontamination"]) - if(safeties && occupant) - to_chat(usr, SPAN_DANGER("\The [src] has detected an occupant. Please remove the occupant before commencing the decontamination cycle.")) - return + to_chat(user, SPAN_DANGER("\The [src] has detected an occupant. Please remove the occupant before commencing the decontamination cycle.")) + return TOPIC_HANDLED - active = 1 + active = TRUE irradiating = 10 - update_icon() - updateUsrDialog() - - sleep(10) + . = TOPIC_REFRESH + addtimer(CALLBACK(src, PROC_REF(finish_decontamination)), 1 SECOND) + update_icon() +/obj/machinery/suit_cycler/proc/finish_decontamination() + if(active && operable()) // doesn't currently use power when active, but maybe it should? if(helmet) if(radiation_level > 2) helmet.decontaminate() if(radiation_level > 1) - helmet.clean_blood() - + helmet.clean() if(suit) if(radiation_level > 2) suit.decontaminate() if(radiation_level > 1) - suit.clean_blood() - + suit.clean() if(boots) if(radiation_level > 2) boots.decontaminate() if(radiation_level > 1) - boots.clean_blood() - + boots.clean() + // maybe add a failure message if it's been interrupted by the time decontamination finishes? + // Update post-decontamination update_icon() updateUsrDialog() @@ -396,7 +438,7 @@ return if(active && stat & (BROKEN|NOPOWER)) - active = 0 + active = FALSE irradiating = 0 electrified = 0 update_icon() @@ -413,18 +455,19 @@ if(occupant) if(prob(radiation_level*2) && occupant.can_feel_pain()) - occupant.emote("scream") + occupant.emote(/decl/emote/audible/scream) if(radiation_level > 2) - occupant.take_organ_damage(0,radiation_level*2 + rand(1,3)) + occupant.take_organ_damage(0, radiation_level*2 + rand(1,3)) if(radiation_level > 1) - occupant.take_organ_damage(0,radiation_level + rand(1,3)) + occupant.take_organ_damage(0, radiation_level + rand(1,3)) occupant.apply_damage(radiation_level*10, IRRADIATE, damage_flags = DAM_DISPERSED) /obj/machinery/suit_cycler/proc/finished_job() var/turf/T = get_turf(src) T.visible_message(SPAN_NOTICE("\The [src] pings loudly.")) - active = 0 + active = FALSE updateUsrDialog() + update_icon() /obj/machinery/suit_cycler/proc/repair_suit() if(!suit || !suit.damage || !suit.can_breach) @@ -432,6 +475,7 @@ suit.breaches = list() suit.calc_breach_damage() + finished_job() /obj/machinery/suit_cycler/verb/leave() set name = "Eject Cycler" @@ -441,6 +485,11 @@ return eject_occupant(usr) +/obj/machinery/suit_cycler/relaymove(var/mob/user) + ..() + if(occupant == user) + eject_occupant(user) + /obj/machinery/suit_cycler/proc/eject_occupant(mob/user) if(locked || active) @@ -450,10 +499,11 @@ if (!occupant) return - occupant.reset_view() occupant.dropInto(loc) + occupant.reset_view() occupant = null + update_icon() add_fingerprint(user) updateUsrDialog() @@ -463,13 +513,15 @@ if(!target_bodytype || !target_modification) return - if(helmet) helmet.refit_for_bodytype(target_bodytype) - if(suit) suit.refit_for_bodytype(target_bodytype) - if(boots) boots.refit_for_bodytype(target_bodytype) - - target_modification.RefitItem(helmet) - target_modification.RefitItem(suit) + if(helmet) + target_modification.RefitItem(helmet) + helmet.refit_for_bodytype(target_bodytype) + if(suit) + target_modification.RefitItem(suit) + suit.refit_for_bodytype(target_bodytype) + if(boots) + boots.refit_for_bodytype(target_bodytype) + finished_job() - if(helmet) helmet.SetName("refitted [helmet.name]") - if(suit) suit.SetName("refitted [suit.name]") - if(boots) boots.SetName("refitted [initial(boots.name)]") \ No newline at end of file +/obj/machinery/suit_cycler/shuttle_rotate(angle) // DO NOT CHANGE DIR. Change this when someone adds directional sprites for suit cyclers. + return diff --git a/code/game/machinery/suit_cycler_units.dm b/code/game/machinery/suit_cycler_units.dm index 095130c0e839..e84890fa9818 100644 --- a/code/game/machinery/suit_cycler_units.dm +++ b/code/game/machinery/suit_cycler_units.dm @@ -1,8 +1,21 @@ /obj/machinery/suit_cycler/engineering - name = "Engineering suit cycler" + name = "engineering suit cycler" model_text = "Engineering" initial_access = list(access_construction) - available_modifications = list(/decl/item_modifier/space_suit/engineering, /decl/item_modifier/space_suit/atmos) + available_modifications = list( + /decl/item_modifier/space_suit/engineering, + /decl/item_modifier/space_suit/atmos + ) + +/obj/machinery/suit_cycler/engineering/prepared + buildable = FALSE + helmet = /obj/item/clothing/head/helmet/space/void/engineering + suit = /obj/item/clothing/suit/space/void/engineering + boots = /obj/item/clothing/shoes/magboots + +/obj/machinery/suit_cycler/engineering/prepared/atmospheric + helmet = /obj/item/clothing/head/helmet/space/void/atmos + suit = /obj/item/clothing/suit/space/void/atmos /obj/machinery/suit_cycler/engineering/alt available_modifications = list( @@ -12,47 +25,93 @@ buildable = FALSE /obj/machinery/suit_cycler/mining - name = "Mining suit cycler" + name = "mining suit cycler" model_text = "Mining" initial_access = list(access_mining) - available_modifications = list(/decl/item_modifier/space_suit/mining) + available_modifications = list( + /decl/item_modifier/space_suit/mining + ) /obj/machinery/suit_cycler/science - name = "Excavation suit cycler" + name = "excavation suit cycler" model_text = "Excavation" initial_access = list(access_xenoarch) - available_modifications = list(/decl/item_modifier/space_suit/science) + available_modifications = list( + /decl/item_modifier/space_suit/science + ) /obj/machinery/suit_cycler/security - name = "Security suit cycler" + name = "security suit cycler" model_text = "Security" initial_access = list(access_security) - available_modifications = list(/decl/item_modifier/space_suit/security, /decl/item_modifier/space_suit/security/alt) + available_modifications = list( + /decl/item_modifier/space_suit/security, + /decl/item_modifier/space_suit/security/alt + ) + +/obj/machinery/suit_cycler/security/prepared + buildable = FALSE + helmet = /obj/item/clothing/head/helmet/space/void/security + suit = /obj/item/clothing/suit/space/void/security + boots = /obj/item/clothing/shoes/magboots /obj/machinery/suit_cycler/security/alt - available_modifications = list(/decl/item_modifier/space_suit/security/alt) + available_modifications = list( + /decl/item_modifier/space_suit/security/alt + ) buildable = FALSE /obj/machinery/suit_cycler/medical - name = "Medical suit cycler" + name = "medical suit cycler" model_text = "Medical" initial_access = list(access_medical) - available_modifications = list(/decl/item_modifier/space_suit/medical) + available_modifications = list( + /decl/item_modifier/space_suit/medical + ) + +/obj/machinery/suit_cycler/medical/prepared + buildable = FALSE + helmet = /obj/item/clothing/head/helmet/space/void/medical/alt + suit = /obj/item/clothing/suit/space/void/medical/alt + boots = /obj/item/clothing/shoes/magboots /obj/machinery/suit_cycler/medical/alt - available_modifications = list(/decl/item_modifier/space_suit/medical/alt) + available_modifications = list( + /decl/item_modifier/space_suit/medical/alt + ) buildable = FALSE -/obj/machinery/suit_cycler/syndicate - name = "Nonstandard suit cycler" +/obj/machinery/suit_cycler/nonstandard + name = "nonstandard suit cycler" model_text = "Nonstandard" - initial_access = list(access_syndicate) - available_modifications = list(/decl/item_modifier/space_suit/mercenary) - can_repair = 1 + available_modifications = list( + /decl/item_modifier/space_suit/mercenary + ) + can_repair = TRUE buildable = FALSE +/obj/machinery/suit_cycler/nonstandard/raider + initial_access = list(access_raider) + +/obj/machinery/suit_cycler/nonstandard/mercenary + initial_access = list(access_mercenary) + /obj/machinery/suit_cycler/pilot - name = "Pilot suit cycler" + name = "pilot suit cycler" model_text = "Pilot" initial_access = list(access_mining_office) - available_modifications = list(/decl/item_modifier/space_suit/pilot) + available_modifications = list( + /decl/item_modifier/space_suit/pilot + ) + +/obj/machinery/suit_cycler/generic + name = "generic suit cycler" + model_text = "Generic" + req_access = list() + initial_access = list() + locked = FALSE + +/obj/machinery/suit_cycler/generic/prepared + buildable = FALSE + helmet = /obj/item/clothing/head/helmet/space + suit = /obj/item/clothing/suit/space diff --git a/code/game/machinery/supplybeacon.dm b/code/game/machinery/supplybeacon.dm index 21d4b6b221c8..6b5e01a6d6cd 100644 --- a/code/game/machinery/supplybeacon.dm +++ b/code/game/machinery/supplybeacon.dm @@ -4,115 +4,107 @@ icon = 'icons/obj/supplybeacon.dmi' desc = "An inactive, hacked supply beacon stamped with the Nyx Rapid Fabrication logo. Good for one (1) ballistic supply pod shipment." icon_state = "beacon" - var/deploy_path = /obj/machinery/power/supply_beacon - var/deploy_time = 30 + material = /decl/material/solid/metal/steel + w_class = ITEM_SIZE_STRUCTURE + obj_flags = OBJ_FLAG_NO_STORAGE -/obj/item/supply_beacon/supermatter - name = "inactive supermatter supply beacon" - deploy_path = /obj/machinery/power/supply_beacon/supermatter + var/deploy_path = /obj/structure/supply_beacon + var/deploy_time = 30 /obj/item/supply_beacon/attack_self(var/mob/user) - user.visible_message("\The [user] begins setting up \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] begins setting up \the [src].")) if(!do_after(user, deploy_time, src)) return - if(!user.unEquip(src)) + if(!user.try_unequip(src)) return var/obj/S = new deploy_path(get_turf(user)) - user.visible_message("\The [user] deploys \the [S].") + user.visible_message(SPAN_NOTICE("\The [user] deploys \the [S].")) qdel(src) -/obj/machinery/power/supply_beacon +/obj/structure/supply_beacon name = "supply beacon" - desc = "A bulky moonshot supply beacon. Someone has been messing with the wiring." + desc = "A bulky long-distance supply beacon. Someone has been messing with the wiring." icon = 'icons/obj/supplybeacon.dmi' icon_state = "beacon" + anchored = FALSE + density = TRUE + material = /decl/material/solid/metal/steel - anchored = 0 - density = 1 - stat = 0 - - var/target_drop_time - var/drop_delay = 450 - var/expended var/drop_type + var/expended = FALSE + var/activated = FALSE + var/drop_delay = 45 SECONDS + var/target_drop_time -/obj/machinery/power/supply_beacon/Initialize() +/obj/structure/supply_beacon/Initialize() . = ..() - if(!drop_type) drop_type = pick(supply_drop_random_loot_types()) + if(!drop_type) + drop_type = pick(supply_drop_random_loot_types()) -/obj/machinery/power/supply_beacon/supermatter - name = "supermatter supply beacon" - drop_type = "supermatter" - -/obj/machinery/power/supply_beacon/attackby(var/obj/item/W, var/mob/user) - if(!use_power && isWrench(W)) - if(!anchored && !connect_to_network()) - to_chat(user, "This device must be placed over an exposed cable.") - return +/obj/structure/supply_beacon/attackby(var/obj/item/used_item, var/mob/user) + if(!activated && IS_WRENCH(used_item)) anchored = !anchored - user.visible_message("\The [user] [anchored ? "secures" : "unsecures"] \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] [anchored ? "secures" : "unsecures"] \the [src].")) playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - return + return TRUE return ..() -/obj/machinery/power/supply_beacon/physical_attack_hand(var/mob/user) +/obj/structure/supply_beacon/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() if(expended) - update_use_power(POWER_USE_OFF) - to_chat(user, "\The [src] has used up its charge.") + to_chat(user, SPAN_WARNING("\The [src] has used up its charge.")) return TRUE - - if(anchored) - if(use_power) - deactivate(user) - else - activate(user) + if(!anchored) + to_chat(user, SPAN_WARNING("You need to secure \the [src] with a wrench first!")) return TRUE + if(activated) + deactivate(user) else - to_chat(user, "You need to secure the beacon with a wrench first!") - return TRUE + activate(user) + return TRUE -/obj/machinery/power/supply_beacon/proc/activate(var/mob/user) +/obj/structure/supply_beacon/proc/activate(var/mob/user) if(expended) return - if(surplus() < 500) - if(user) to_chat(user, "The connected wire doesn't have enough current.") - return - set_light(1, 0.5, 2, 2, "#00ccaa") + set_light(3, 3, "#00ccaa") icon_state = "beacon_active" - update_use_power(POWER_USE_IDLE) - if(user) to_chat(user, "You activate the beacon. The supply drop will be dispatched soon.") + activated = TRUE + START_PROCESSING(SSobj, src) + admin_attacker_log(user, "has activated \a [src] at [get_area_name(src)]") + if(user) + to_chat(user, SPAN_NOTICE("You activate \the [src]. The supply drop will be dispatched soon.")) -/obj/machinery/power/supply_beacon/proc/deactivate(var/mob/user, var/permanent) +/obj/structure/supply_beacon/proc/deactivate(var/mob/user, var/permanent) if(permanent) expended = 1 icon_state = "beacon_depleted" else icon_state = "beacon" + set_light(0) - update_use_power(POWER_USE_OFF) + activated = FALSE + STOP_PROCESSING(SSobj, src) target_drop_time = null - if(user) to_chat(user, "You deactivate the beacon.") + if(user) + to_chat(user, SPAN_NOTICE("You deactivate \the [src].")) -/obj/machinery/power/supply_beacon/Destroy() - if(use_power) +/obj/structure/supply_beacon/Destroy() + if(activated) deactivate() - ..() + return ..() -/obj/machinery/power/supply_beacon/Process() - if(expended) +/obj/structure/supply_beacon/Process() + if(expended || !activated) return PROCESS_KILL - if(!use_power) - return - if(draw_power(500) < 500) - deactivate() - return if(!target_drop_time) target_drop_time = world.time + drop_delay - else if(world.time >= target_drop_time) - deactivate(permanent = 1) - var/drop_x = src.x-2 - var/drop_y = src.y-2 - var/drop_z = src.z - command_announcement.Announce("Nyx Rapid Fabrication priority supply request #[rand(1000,9999)]-[rand(100,999)] recieved. Shipment dispatched via ballistic supply pod for immediate delivery. Have a nice day.", "Thank You For Your Patronage") - spawn(rand(100,300)) - new /datum/random_map/droppod/supply(null, drop_x, drop_y, drop_z, supplied_drop = drop_type) // Splat. + if(world.time >= target_drop_time) + deactivate(permanent = TRUE) + command_announcement.Announce("Nyx Rapid Fabrication priority supply request #[rand(1000,9999)]-[rand(100,999)] received. Shipment dispatched via ballistic supply pod for immediate delivery. Have a nice day.", "Thank You For Your Patronage") + addtimer(CALLBACK(src, PROC_REF(drop_cargo)), rand(20 SECONDS, 30 SECONDS)) + +/obj/structure/supply_beacon/proc/drop_cargo(var/drop_x, var/drop_y, var/drop_z) + if(!QDELETED(src) && isturf(loc)) + var/turf/T = loc + new /datum/random_map/droppod/supply(T.x-2, T.y-2, T.z, supplied_drop = drop_type) // Splat. diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm deleted file mode 100644 index 2b0cac884a2b..000000000000 --- a/code/game/machinery/syndicatebeacon.dm +++ /dev/null @@ -1,168 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -// Beacon randomly spawns in space -// When a non-traitor (no special role in /mind) uses it, he is given the choice to become a traitor -// If he accepts there is a random chance he will be accepted, rejected, or rejected and killed -// Bringing certain items can help improve the chance to become a traitor - - -/obj/machinery/syndicate_beacon - name = "ominous beacon" - desc = "This looks suspicious..." - icon = 'icons/obj/items/syndibeacon.dmi' - icon_state = "syndbeacon" - - anchored = 1 - density = 1 - - var/temptext = "" - var/selfdestructing = 0 - var/charges = 1 - -/obj/machinery/syndicate_beacon/interface_interact(var/mob/user) - interact(user) - return TRUE - -/obj/machinery/syndicate_beacon/interact(var/mob/user) - user.set_machine(src) - var/dat = "Scanning [pick("retina pattern", "voice print", "fingerprints", "dna sequence")]...
              Identity confirmed,
              " - if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) - if(is_special_character(user)) - dat += "Operative record found. Greetings, Agent [user.name].
              " - else if(charges < 1) - dat += "Connection severed.
              " - else - var/honorific = "Mr." - if(user.gender == FEMALE) - honorific = "Ms." - dat += "Identity not found in operative database. What can the Syndicate do for you today, [honorific] [user.name]?
              " - if(!selfdestructing) - dat += "

              \"[pick("I want to switch teams.", "I want to work for you.", "Let me join you.", "I can be of use to you.", "You want me working for you, and here's why...", "Give me an objective.", "How's the 401k over at the Syndicate?")]\"
              " - dat += temptext - show_browser(user, dat, "window=syndbeacon") - onclose(user, "syndbeacon") - -/obj/machinery/syndicate_beacon/Topic(href, href_list) - if(..()) - return - if(href_list["betraitor"]) - if(charges < 1) - src.updateUsrDialog() - return - var/mob/M = locate(href_list["traitormob"]) - if(M.mind.special_role || jobban_isbanned(M, MODE_TRAITOR)) - temptext = "We have no need for you at this time. Have a pleasant day.
              " - src.updateUsrDialog() - return - charges -= 1 - switch(rand(1,2)) - if(1) - temptext = "Double-crosser. You planned to betray us from the start. Allow us to repay the favor in kind." - src.updateUsrDialog() - spawn(rand(50,200)) selfdestruct() - return - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/N = M - to_chat(M, "You have joined the ranks of the Syndicate and become a traitor to the station!") - GLOB.traitors.add_antagonist(N.mind) - GLOB.traitors.equip(N) - log_and_message_admins("has accepted a traitor objective from a syndicate beacon.", M) - - - src.updateUsrDialog() - return - - -/obj/machinery/syndicate_beacon/proc/selfdestruct() - selfdestructing = 1 - spawn() explosion(src.loc, 1, rand(1,3), rand(3,8), 10) - -//////////////////////////////////////// -//Singularity beacon -//////////////////////////////////////// -/obj/machinery/power/singularity_beacon - name = "ominous beacon" - desc = "This looks suspicious..." - icon = 'icons/obj/singularity.dmi' - icon_state = "beacon" - - anchored = 0 - density = 1 - layer = BASE_ABOVE_OBJ_LAYER //so people can't hide it and it's REALLY OBVIOUS - stat = 0 - - var/active = 0 - var/icontype = "beacon" - -/obj/machinery/power/singularity_beacon/proc/Activate(mob/user = null) - if(surplus() < 1500) - if(user) to_chat(user, "The connected wire doesn't have enough current.") - return - for(var/obj/singularity/singulo in world) - if(singulo.z == z) - singulo.target = src - icon_state = "[icontype]1" - active = 1 - - START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) - if(user) - to_chat(user, "You activate the beacon.") - - -/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user = null) - for(var/obj/singularity/singulo in world) - if(singulo.target == src) - singulo.target = null - icon_state = "[icontype]0" - active = 0 - if(user) - to_chat(user, "You deactivate the beacon.") - - -/obj/machinery/power/singularity_beacon/physical_attack_hand(var/mob/user) - . = TRUE - if(anchored) - if(active) - Deactivate(user) - else - Activate(user) - else - to_chat(user, "You need to screw the beacon to the floor first!") - -/obj/machinery/power/singularity_beacon/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - if(active) - to_chat(user, "You need to deactivate the beacon first!") - return - - if(anchored) - anchored = 0 - to_chat(user, "You unscrew the beacon from the floor.") - disconnect_from_network() - return - else - if(!connect_to_network()) - to_chat(user, "This device must be placed over an exposed cable.") - return - anchored = 1 - to_chat(user, "You screw the beacon to the floor and attach the cable.") - return - ..() - return - - -/obj/machinery/power/singularity_beacon/Destroy() - if(active) - Deactivate() - ..() - -//stealth direct power usage -/obj/machinery/power/singularity_beacon/Process() - if(!active) - return PROCESS_KILL - if(draw_power(1500) < 1500) - Deactivate() - -/obj/machinery/power/singularity_beacon/syndicate - icontype = "beaconsynd" - icon_state = "beaconsynd0" diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm deleted file mode 100644 index e7229a0d7a0e..000000000000 --- a/code/game/machinery/telecomms/broadcaster.dm +++ /dev/null @@ -1,584 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -/* - The broadcaster sends processed messages to all radio devices in the game. They - do not have to be headsets; intercoms and station-bounced radios suffice. - - They receive their message from a server after the message has been logged. -*/ - -var/list/recentmessages = list() // global list of recent messages broadcasted : used to circumvent massive radio spam -var/message_delay = 0 // To make sure restarting the recentmessages list is kept in sync - -/obj/machinery/telecomms/broadcaster - name = "Subspace Broadcaster" - icon = 'icons/obj/machines/tcomms/broadcaster.dmi' - icon_state = "broadcaster" - desc = "A dish-shaped machine used to broadcast processed subspace signals." - density = 1 - anchored = 1 - idle_power_usage = 25 - machinetype = 5 - produces_heat = 0 - delay = 7 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/broadcaster - base_type = /obj/machinery/telecomms/broadcaster - outage_probability = 10 - -/obj/machinery/telecomms/broadcaster/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - // Don't broadcast rejected signals - if(signal.data["reject"]) - return - - if(signal.data["message"]) - - // Prevents massive radio spam - signal.data["done"] = 1 // mark the signal as being broadcasted - // Search for the original signal and mark it as done as well - var/datum/signal/original = signal.data["original"] - if(original) - original.data["done"] = 1 - original.data["compression"] = signal.data["compression"] - original.data["level"] = signal.data["level"] - - var/signal_message = "[signal.frequency]:[signal.data["message"]]:[signal.data["realname"]]" - if(signal_message in recentmessages) - return - recentmessages.Add(signal_message) - - if(signal.data["slow"] > 0) - sleep(signal.data["slow"]) // simulate the network lag if necessary - - signal.data["level"] |= listening_levels - - /** #### - Normal Broadcast - #### **/ - - if(signal.data["type"] == 0) - - /* ###### Broadcast a message using signal.data ###### */ - Broadcast_Message(signal.data["connection"], signal.data["mob"], - signal.data["vmask"], signal.data["vmessage"], - signal.data["radio"], signal.data["message"], - signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"],, - signal.data["compression"], signal.data["level"], signal.frequency, - signal.data["verb"], signal.data["language"], signal.data["channel_tag"], signal.data["channel_color"]) - - - /** #### - Simple Broadcast - #### **/ - - if(signal.data["type"] == 1) - - /* ###### Broadcast a message using signal.data ###### */ - Broadcast_SimpleMessage(signal.data["name"], signal.frequency, - signal.data["message"],null, null, - signal.data["compression"], listening_levels, signal.data["channel_tag"], signal.data["channel_color"]) - - - /** #### - Artificial Broadcast - #### **/ - // (Imitates a mob) - - if(signal.data["type"] == 2) - - /* ###### Broadcast a message using signal.data ###### */ - // Parameter "data" as 4: AI can't track this person/mob - - Broadcast_Message(signal.data["connection"], signal.data["mob"], - signal.data["vmask"], signal.data["vmessage"], - signal.data["radio"], signal.data["message"], - signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency, - signal.data["verb"], signal.data["language"], signal.data["channel_tag"], signal.data["channel_color"]) - - if(!message_delay) - message_delay = 1 - spawn(10) - message_delay = 0 - recentmessages = list() - - /* --- Do a snazzy animation! --- */ - flick("broadcaster_send", src) - -/obj/machinery/telecomms/broadcaster/Destroy() - // In case message_delay is left on 1, otherwise it won't reset the list and people can't say the same thing twice anymore. - if(message_delay) - message_delay = 0 - ..() - - -/* - Basically just an empty shell for receiving and broadcasting radio messages. Not - very flexible, but it gets the job done. -*/ - -/obj/machinery/telecomms/allinone - name = "Telecommunications Mainframe" - icon = 'icons/obj/machines/tcomms/comm_server.dmi' - icon_state = "comm_server" - desc = "A compact machine used for portable subspace telecommuniations processing." - density = 1 - anchored = 1 - use_power = POWER_USE_OFF - idle_power_usage = 0 - machinetype = 6 - produces_heat = 0 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/allinone - construct_state = /decl/machine_construction/tcomms/panel_closed/cannot_print - var/listening_freqs - var/channel_color - var/channel_name - var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel - -/obj/machinery/telecomms/allinone/Initialize() - if(!listening_freqs) - listening_freqs = ANTAG_FREQS //Covers any updates to ANTAG_FREQS - return ..() - -/obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal) - - if(!on) // has to be on to receive messages - return - - if(is_freq_listening(signal)) // detect subspace signals - - signal.data["done"] = 1 // mark the signal as being broadcasted - signal.data["compression"] = 0 - - // Search for the original signal and mark it as done as well - var/datum/signal/original = signal.data["original"] - if(original) - original.data["done"] = 1 - - if(signal.data["slow"] > 0) - sleep(signal.data["slow"]) // simulate the network lag if necessary - - /* ###### Broadcast a message using signal.data ###### */ - - var/datum/radio_frequency/connection = signal.data["connection"] - - if(connection.frequency in listening_freqs) // if antag broadcast, just - Broadcast_Message(signal.data["connection"], signal.data["mob"], - signal.data["vmask"], signal.data["vmessage"], - signal.data["radio"], signal.data["message"], - signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency, - signal.data["verb"], signal.data["language"], channel_name ? channel_name : signal.data["channel_tag"], channel_color ? channel_color : signal.data["channel_color"]) - else - if(intercept) - Broadcast_Message(signal.data["connection"], signal.data["mob"], - signal.data["vmask"], signal.data["vmessage"], - signal.data["radio"], signal.data["message"], - signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency, - signal.data["verb"], signal.data["language"], signal.data["channel_tag"], signal.data["channel_color"]) - - - -/** - - Here is the big, bad function that broadcasts a message given the appropriate - parameters. - - @param connection: - The datum generated in radio.dm, stored in signal.data["connection"]. - - @param M: - Reference to the mob/speaker, stored in signal.data["mob"] - - @param vmask: - Boolean value if the mob is "hiding" its identity via voice mask, stored in - signal.data["vmask"] - - @param vmessage: - If specified, will display this as the message; such as "chimpering" - for monkies if the mob is not understood. Stored in signal.data["vmessage"]. - - @param radio: - Reference to the radio broadcasting the message, stored in signal.data["radio"] - - @param message: - The actual string message to display to mobs who understood mob M. Stored in - signal.data["message"] - - @param name: - The name to display when a mob receives the message. signal.data["name"] - - @param job: - The name job to display for the AI when it receives the message. signal.data["job"] - - @param realname: - The "real" name associated with the mob. signal.data["realname"] - - @param vname: - If specified, will use this name when mob M is not understood. signal.data["vname"] - - @param data: - If specified: - 1 -- Will only broadcast to intercoms - 2 -- Will only broadcast to intercoms and station-bounced radios - 3 -- Broadcast to syndicate frequency - 4 -- AI can't track down this person. Useful for imitation broadcasts where you can't find the actual mob - - @param compression: - If 0, the signal is audible - If nonzero, the signal may be partially inaudible or just complete gibberish. - - @param level: - The list of Z levels that the sending radio is broadcasting to. Having 0 in the list broadcasts on all levels - - @param freq - The frequency of the signal - - @param channel_tag - The "name" of the frequency. Displayed in brackets before the message - - @param channel_color - Color of the radio message - -**/ - -/proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M, - var/vmask, var/vmessage, var/obj/item/radio/radio, - var/message, var/name, var/job, var/realname, var/vname, - var/data, var/compression, var/list/level, var/freq, var/verbage = "says", var/decl/language/speaking = null, - var/channel_tag, var/channel_color) - - - /* ###### Prepare the radio connection ###### */ - - var/display_freq = freq - - var/list/obj/item/radio/radios = list() - - // --- Broadcast only to intercom devices --- - - if(data == 1) - - for (var/obj/item/radio/intercom/R in connection.devices["[RADIO_CHAT]"]) - if(R.receive_range(display_freq, level) > -1) - radios += R - - // --- Broadcast only to intercoms and station-bounced radios --- - - else if(data == 2) - - for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"]) - - if(istype(R, /obj/item/radio/headset)) - continue - - if(R.receive_range(display_freq, level) > -1) - radios += R - - // --- Broadcast to antag radios! --- - - else if(data == 3) - for(var/antag_freq in ANTAG_FREQS) - var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(antag_freq) - for (var/obj/item/radio/R in antag_connection.devices["[RADIO_CHAT]"]) - if(R.intercept && R.receive_range(antag_freq, level) > -1) - radios += R - - // --- Broadcast to ALL radio devices --- - else - - for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"]) - if(R.receive_range(display_freq, level) > -1) - radios += R - - for(var/obj/item/radio/R in radios) - if((R.last_radio_sound + 1 SECOND) < world.time && R != radio) - playsound(R.loc, 'sound/effects/radio_chatter.ogg', 10, 0, -6) - R.last_radio_sound = world.time - - // Get a list of mobs who can hear from the radios we collected. - var/list/receive = get_mobs_in_radio_ranges(radios) - - /* ###### Organize the receivers into categories for displaying the message ###### */ - - // Understood the message: - var/list/heard_masked = list() // masked name or no real name - var/list/heard_normal = list() // normal message - - // Did not understand the message: - var/list/heard_voice = list() // voice message (ie "chimpers") - var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!") - var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!") - - for (var/mob/R in receive) - - /* --- Loop through the receivers and categorize them --- */ - if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes. - continue - - // Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates - if(data == 3 && isghost(R) && R.get_preference_value(/datum/client_preference/ghost_radio) == GLOB.PREF_ALL_CHATTER) - continue - - // --- Check for compression --- - if(compression > 0) - heard_gibberish += R - continue - - // --- Can understand the speech --- - - if (!M || R.say_understands(M)) - - // - Not human or wearing a voice mask - - if (!M || !ishuman(M) || vmask) - heard_masked += R - - // - Human and not wearing voice mask - - else - heard_normal += R - - // --- Can't understand the speech --- - - else - // - The speaker has a prespecified "voice message" to display if not understood - - if (vmessage) - heard_voice += R - - // - Just display a garbled message - - else - heard_garbled += R - - - /* ###### Begin formatting and sending the message ###### */ - if (length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish)) - - /* --- Some miscellaneous variables to format the string output --- */ - var/freq_text = format_frequency(display_freq) - if(channel_tag) - freq_text = channel_tag - - // Default to commons channel green - if(!channel_color) - channel_color = channel_color_presets["Global Green"] - - var/part_b_extra = "" - if(data == 3) // intercepted radio message - part_b_extra = " (Intercepted)" - var/part_a = "\[[freq_text]\][part_b_extra] " // goes in the actual output - - // --- Some more pre-message formatting --- - var/part_b = " " // Tweaked for security headsets -- TLE - var/part_c = "" - - - /* ###### Send the message ###### */ - - /* --- Process all the mobs that heard a masked voice (understood) --- */ - - if (length(heard_masked)) - for (var/mob/R in heard_masked) - R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M, 0, name) - - /* --- Process all the mobs that heard the voice normally (understood) --- */ - - if (length(heard_normal)) - for (var/mob/R in heard_normal) - R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 0, realname) - - /* --- Process all the mobs that heard the voice normally (did not understand) --- */ - - if (length(heard_voice)) - for (var/mob/R in heard_voice) - R.hear_radio(message,verbage, speaking, part_a, part_b, part_c, M,0, vname) - - /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ - // Displays garbled message (ie "f*c* **u, **i*er!") - - if (length(heard_garbled)) - for (var/mob/R in heard_garbled) - R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, 1, vname) - - - /* --- Complete gibberish. Usually happens when there's a compressed message --- */ - - if (length(heard_gibberish)) - for (var/mob/R in heard_gibberish) - R.hear_radio(message, verbage, speaking, part_a, part_b, part_c, M, compression) - - return 1 - -/proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level, var/channel_tag, var/channel_color) - - /* ###### Prepare the radio connection ###### */ - - if(!M) - var/mob/living/carbon/human/H = new - M = H - - var/datum/radio_frequency/connection = radio_controller.return_frequency(frequency) - - var/display_freq = connection.frequency - - var/list/receive = list() - - - // --- Broadcast only to intercom devices --- - - if(data == 1) - for (var/obj/item/radio/intercom/R in connection.devices["[RADIO_CHAT]"]) - var/turf/position = get_turf(R) - if(position && position.z == level) - receive |= R.send_hear(display_freq, level) - - - // --- Broadcast only to intercoms and station-bounced radios --- - - else if(data == 2) - for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"]) - - if(istype(R, /obj/item/radio/headset)) - continue - var/turf/position = get_turf(R) - if(position && position.z == level) - receive |= R.send_hear(display_freq) - - - // --- Broadcast to antag radios! --- - - else if(data == 3) - for(var/freq in ANTAG_FREQS) - var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(freq) - for (var/obj/item/radio/R in antag_connection.devices["[RADIO_CHAT]"]) - var/turf/position = get_turf(R) - if(position && position.z == level) - receive |= R.send_hear(freq) - - - // --- Broadcast to ALL radio devices --- - - else - for (var/obj/item/radio/R in connection.devices["[RADIO_CHAT]"]) - var/turf/position = get_turf(R) - if(position && position.z == level) - receive |= R.send_hear(display_freq) - - - /* ###### Organize the receivers into categories for displaying the message ###### */ - - // Understood the message: - var/list/heard_normal = list() // normal message - - // Did not understand the message: - var/list/heard_garbled = list() // garbled message (ie "f*c* **u, **i*er!") - var/list/heard_gibberish= list() // completely screwed over message (ie "F%! (O*# *#!<>&**%!") - - for (var/mob/R in receive) - - /* --- Loop through the receivers and categorize them --- */ - // --- Check for compression --- - if(compression > 0) - - heard_gibberish += R - continue - - // --- Can understand the speech --- - - if (R.say_understands(M)) - - heard_normal += R - - // --- Can't understand the speech --- - - else - // - Just display a garbled message - - - heard_garbled += R - - - /* ###### Begin formatting and sending the message ###### */ - if (length(heard_normal) || length(heard_garbled) || length(heard_gibberish)) - - /* --- Some miscellaneous variables to format the string output --- */ - var/freq_text = format_frequency(display_freq) - if(channel_tag) - freq_text = channel_tag - - if(!channel_color) - channel_color = channel_color_presets["Global Green"] - - var/part_a = "" // goes in the actual output - - // --- Some more pre-message formatting --- - - var/part_b_extra = "" - if(data == 3) // intercepted radio message - part_b_extra = " (Intercepted)" - - var/part_b = " \[[freq_text]\][part_b_extra] " // Tweaked for security headsets -- TLE - var/part_c = "" - - //End of research and feedback code. - - /* ###### Send the message ###### */ - - /* --- Process all the mobs that heard the voice normally (understood) --- */ - - if (length(heard_normal)) - var/rendered = "[part_a][source][part_b]\"[text]\"[part_c]" - - for (var/mob/R in heard_normal) - R.show_message(rendered, 2) - - /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ - // Displays garbled message (ie "f*c* **u, **i*er!") - - if (length(heard_garbled)) - var/quotedmsg = "\"[stars(text)]\"" - var/rendered = "[part_a][source][part_b][quotedmsg][part_c]" - - for (var/mob/R in heard_garbled) - R.show_message(rendered, 2) - - - /* --- Complete gibberish. Usually happens when there's a compressed message --- */ - - if (length(heard_gibberish)) - var/quotedmsg = "\"[Gibberish(text, compression + 50)]\"" - var/rendered = "[part_a][Gibberish(source, compression + 50)][part_b][quotedmsg][part_c]" - - for (var/mob/R in heard_gibberish) - R.show_message(rendered, 2) - -//Use this to test if an obj can communicate with a Telecommunications Network - -/atom/proc/test_telecomms() - var/datum/signal/signal = src.telecomms_process() - var/turf/position = get_turf(src) - return (position.z in signal.data["level"] && signal.data["done"]) - -/atom/proc/telecomms_process(var/do_sleep = 1) - - // First, we want to generate a new radio signal - var/datum/signal/signal = new - signal.transmission_method = 2 // 2 would be a subspace transmission. - var/turf/pos = get_turf(src) - - // --- Finally, tag the actual signal with the appropriate values --- - signal.data = list( - "slow" = 0, // how much to sleep() before broadcasting - simulates net lag - "message" = "TEST", - "compression" = rand(45, 50), // If the signal is compressed, compress our message too. - "traffic" = 0, // dictates the total traffic sum that the signal went through - "type" = 4, // determines what type of radio input it is: test broadcast - "reject" = 0, - "done" = 0, - "level" = pos ? pos.z : 0 // The level it is being broadcasted at. - ) - signal.frequency = PUB_FREQ// Common channel - - //#### Sending the signal to all subspace receivers ####// - for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) - - if(do_sleep) - sleep(rand(10,25)) - - //to_world_log("Level: [signal.data["level"]] - Done: [signal.data["done"]]") - - return signal - diff --git a/code/game/machinery/telecomms/logbrowser.dm b/code/game/machinery/telecomms/logbrowser.dm deleted file mode 100644 index 17f2cbc5dd41..000000000000 --- a/code/game/machinery/telecomms/logbrowser.dm +++ /dev/null @@ -1,197 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -/obj/machinery/computer/telecomms - icon_keyboard = "tech_key" - -/obj/machinery/computer/telecomms/server - name = "Telecommunications Server Monitor" - icon_screen = "comm_logs" - - var/screen = 0 // the screen number: - var/list/servers = list() // the servers located by the computer - var/obj/machinery/telecomms/server/SelectedServer - - var/network = "NULL" // the network to probe - var/temp = "" // temporary feedback messages - - var/universal_translate = 0 // set to 1 if it can translate nonhuman speech - - initial_access = list(access_tcomsat) - -/obj/machinery/computer/telecomms/server/interface_interact(mob/user) - interact(user) - return TRUE - -/obj/machinery/computer/telecomms/server/interact(mob/user) - user.set_machine(src) - var/list/dat = list() - dat += "Telecommunication Server Monitor
              Telecommunications Server Monitor
              " - - switch(screen) - - - // --- Main Menu --- - - if(0) - dat += "
              [temp]
              " - dat += "
              Current Network: [network]
              " - if(servers.len) - dat += "
              Detected Telecommunication Servers:
                " - for(var/obj/machinery/telecomms/T in servers) - dat += "
              • \ref[T] [T.name] ([T.id])
              • " - dat += "
              " - dat += "
              \[Flush Buffer\]" - - else - dat += "
              No servers detected. Scan for servers: \[Scan\]" - - - // --- Viewing Server --- - - if(1) - dat += "
              [temp]
              " - dat += "
              \[Main Menu\] \[Refresh\]
              " - dat += "
              Current Network: [network]" - dat += "
              Selected Server: [SelectedServer.id]" - - if(SelectedServer.totaltraffic >= 1024) - dat += "
              Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes

              " - else - dat += "
              Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes

              " - - dat += "Stored Logs:
                " - - var/i = 0 - for(var/datum/comm_log_entry/C in SelectedServer.log_entries) - i++ - - - // If the log is a speech file - if(C.input_type == "Speech File") - - dat += "
              1. [C.name] \[X\]
                " - - // -- Determine race of orator -- - - var/race = C.parameters["race"] // The actual race of the mob - var/language = C.parameters["language"] // The language spoken, or null/"" - - // -- If the orator is a human, or universal translate is active, OR mob has universal speech on -- - - if(universal_translate || C.parameters["uspeech"] || C.parameters["intelligible"]) - dat += "Data type: [C.input_type]
                " - dat += "Source: [C.parameters["name"]] (Job: [C.parameters["job"]])
                " - dat += "Class: [race]
                " - dat += "Contents: \"[C.parameters["message"]]\"
                " - if(language) - dat += "Language: [language]
                " - - // -- Orator is not human and universal translate not active -- - - else - dat += "Data type: Audio File
                " - dat += "Source: Unidentifiable
                " - dat += "Class: [race]
                " - dat += "Contents: Unintelligble
                " - - dat += "

              2. " - - else if(C.input_type == "Execution Error") - - dat += "
              3. [C.name] \[X\]
                " - dat += "Output: \"[C.parameters["message"]]\"
                " - dat += "

              4. " - - - dat += "
              " - - - var/datum/browser/written/popup = new(user, "comm_monitor", "Telecommunications Monitor", 575, 400) - popup.set_content(JOINTEXT(dat)) - popup.open() - - temp = "" - return - - -/obj/machinery/computer/telecomms/server/OnTopic(mob/user, list/href_list, datum/topic_state/state) - if(href_list["viewserver"]) - screen = 1 - for(var/obj/machinery/telecomms/T in servers) - if(T.id == href_list["viewserver"]) - SelectedServer = T - break - - if(href_list["operation"]) - switch(href_list["operation"]) - - if("release") - servers = list() - screen = 0 - - if("mainmenu") - screen = 0 - - if("scan") - if(servers.len > 0) - temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" - - else - for(var/obj/machinery/telecomms/server/T in range(25, src)) - if(T.network == network) - servers.Add(T) - - if(!servers.len) - temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -" - else - temp = "- [servers.len] SERVERS PROBED & BUFFERED -" - - screen = 0 - - if(href_list["delete"]) - - if(!src.allowed(usr) && !emagged) - to_chat(usr, "ACCESS DENIED.") - return - - if(SelectedServer) - var/key = text2num(href_list["delete"]) - if(!is_valid_index(key, SelectedServer.log_entries)) - return TOPIC_REFRESH - var/datum/comm_log_entry/D = SelectedServer.log_entries[key] - if(!D) - return TOPIC_REFRESH - - temp = "- DELETED ENTRY: [D.name] -" - - SelectedServer.log_entries.Remove(D) - qdel(D) - - else - temp = "- FAILED: NO SELECTED MACHINE -" - - if(href_list["network"]) - - var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text - - if(newnet && ((usr in range(1, src) || issilicon(usr)))) - if(length(newnet) > 15) - temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" - - else - - network = newnet - screen = 0 - servers = list() - temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" - - updateUsrDialog() - -/obj/machinery/computer/telecomms/server/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) - playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) - emagged = 1 - req_access.Cut() - to_chat(user, "You you disable the security protocols") - src.updateUsrDialog() - return 1 diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm deleted file mode 100644 index 9ad838cc044c..000000000000 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ /dev/null @@ -1,365 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - - -/* - - All telecommunications interactions: - -*/ - -#define STATION_Z 1 -#define TELECOMM_Z 3 - -/obj/machinery/telecomms - var/temp = "" // output message - construct_state = /decl/machine_construction/tcomms/panel_closed - uncreated_component_parts = null - stat_immune = 0 - maximum_component_parts = list(/obj/item/stock_parts = 15) - -/obj/machinery/telecomms/attackby(obj/item/P, mob/user) - - // Using a multitool lets you access the receiver's interface - if(isMultitool(P)) - interface_interact(user) - return TRUE - - // REPAIRING: Use Nanopaste to repair 10-20 integrity points. - if(istype(P, /obj/item/stack/nanopaste)) - var/obj/item/stack/nanopaste/T = P - if (integrity < 100) //Damaged, let's repair! - if (T.use(1)) - integrity = between(0, integrity + rand(10,20), 100) - to_chat(usr, "You apply the Nanopaste to [src], repairing some of the damage.") - else - to_chat(usr, "This machine is already in perfect condition.") - return - - return component_attackby(P, user) - -/obj/machinery/telecomms/cannot_transition_to(state_path, mob/user) - . = ..() - if(. != MCS_CHANGE) - return - - if(state_path == /decl/machine_construction/default/deconstructed) - to_chat(user, "You begin prying out the circuit board other components...") - playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) - if(do_after(user,60, src)) - to_chat(user, "You finish prying out the components.") - return - return MCS_BLOCK - -/obj/machinery/telecomms/dismantle() - for(var/obj/x in (contents - component_parts)) - x.dropInto(loc) - . = ..() - -// This should all be a multitool extension, but outside the scope of current rework. -/obj/machinery/telecomms/CanUseTopic(mob/user) - // You need a multitool to use this, or be silicon - if(!issilicon(user)) - // istype returns false if the value is null - if(!istype(user.get_active_hand(), /obj/item/multitool)) - return STATUS_CLOSE - return ..() - -/obj/machinery/telecomms/interface_interact(var/mob/user) - interact(user) - return TRUE - -/obj/machinery/telecomms/interact(var/mob/user) - var/obj/item/multitool/P = get_multitool(user) - - user.set_machine(src) - var/list/dat = list() - dat += "[src.name]

              [src.name] Access

              " - dat += "
              [temp]
              " - dat += "
              Power Status: [src.toggled ? "On" : "Off"]" - if(overloaded_for) - dat += "

              WARNING: Ion interference detected. System will automatically recover in [overloaded_for*2] seconds. Reset manually
              " - if(on && toggled) - if(id != "" && id) - dat += "
              Identification String: [id]" - else - dat += "
              Identification String: NULL" - dat += "
              Network: [network]" - dat += "
              Prefabrication: [autolinkers.len ? "TRUE" : "FALSE"]" - if(hide) dat += "
              Shadow Link: ACTIVE" - - //Show additional options for certain machines. - dat += Options_Menu() - - dat += "
              Linked Network Entities:
                " - - var/i = 0 - for(var/obj/machinery/telecomms/T in links) - i++ - if(T.hide && !src.hide) - continue - dat += "
              1. \ref[T] [T.name] ([T.id]) \[X\]
              2. " - dat += "
              " - - dat += "
              Filtering Frequencies: " - - i = 0 - if(length(freq_listening)) - for(var/x in freq_listening) - i++ - if(i < length(freq_listening)) - dat += "[format_frequency(x)] GHz\[X\]; " - else - dat += "[format_frequency(x)] GHz\[X\]" - else - dat += "NONE" - - dat += "
              \[Add Filter\]" - - dat += "

              Channel Tagging Rules:
                " - - if(length(channel_tags)) - for(var/list/rule in channel_tags) - dat +="
              1. [format_frequency(rule[1])] -> [rule[2]] ([rule[3]]) \[X\]
              2. " - - dat += "
              " - dat += "\[Add Rule\]" - - dat += "
              " - - if(P) - var/obj/machinery/telecomms/device = P.get_buffer() - if(istype(device)) - dat += "

              MULTITOOL BUFFER: [device] ([device.id]) \[Link\] \[Flush\]" - else - dat += "

              MULTITOOL BUFFER:
              \[Add Machine\]" - - dat += "
              " - temp = "" - - var/datum/browser/written/popup = new(user, "tcommmachine", "Telecommunications Machine Configuration Panel", 520, 600) - popup.set_content(JOINTEXT(dat)) - popup.open() - -// Returns a multitool from a user depending on their mobtype. - -/obj/machinery/telecomms/proc/get_multitool(mob/user) - - var/obj/item/multitool/P = null - // Let's double check - if(!issilicon(user) && istype(user.get_active_hand(), /obj/item/multitool)) - P = user.get_active_hand() - else if(isAI(user)) - var/mob/living/silicon/ai/U = user - P = U.aiMulti - else if(isrobot(user) && in_range(user, src)) - if(istype(user.get_active_hand(), /obj/item/multitool)) - P = user.get_active_hand() - return P - -// Additional Options for certain machines. Use this when you want to add an option to a specific machine. -// Example of how to use below. - -/obj/machinery/telecomms/proc/Options_Menu() - return "" - -/* -// Add an option to the processor to switch processing mode. (COMPRESS -> UNCOMPRESS or UNCOMPRESS -> COMPRESS) -/obj/machinery/telecomms/processor/Options_Menu() - var/dat = "
              Processing Mode: [process_mode ? "UNCOMPRESS" : "COMPRESS"]" - return dat -*/ -// The topic for Additional Options. Use this for checking href links for your specific option. -// Example of how to use below. -/obj/machinery/telecomms/proc/Options_Topic(href, href_list) - return - -/* -/obj/machinery/telecomms/processor/Options_Topic(href, href_list) - - if(href_list["process"]) - temp = "-% Processing mode changed. %-" - src.process_mode = !src.process_mode -*/ - -// BUS - -/obj/machinery/telecomms/bus/Options_Menu() - var/dat = "
              Change Signal Frequency: [change_frequency ? "YES ([change_frequency])" : "NO"]" - return dat - -/obj/machinery/telecomms/bus/Options_Topic(href, href_list) - - if(href_list["change_freq"]) - - var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num - if(canAccess(usr)) - if(newfreq) - if(findtext(num2text(newfreq), ".")) - newfreq *= 10 // shift the decimal one place - if(newfreq < 10000) - change_frequency = newfreq - temp = "-% New frequency to change to assigned: \"[newfreq] GHz\" %-" - else - change_frequency = 0 - temp = "-% Frequency changing deactivated %-" - - -/obj/machinery/telecomms/Topic(href, href_list) - if(..()) - return 1 - if(!issilicon(usr)) - if(!istype(usr.get_active_hand(), /obj/item/multitool)) - return - - if(stat & (BROKEN|NOPOWER)) - return - - var/obj/item/multitool/P = get_multitool(usr) - - if(href_list["input"]) - switch(href_list["input"]) - - if("resetoverload") - overloaded_for = 0 - temp = "-% Manual override accepted. \The [src] has been reset." - - if("toggle") - - src.toggled = !src.toggled - temp = "-% [src] has been [src.toggled ? "activated" : "deactivated"]." - update_power() - - /* - if("hide") - src.hide = !hide - temp = "-% Shadow Link has been [src.hide ? "activated" : "deactivated"]." - */ - - if("id") - var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID for this machine", src, id) as null|text),1,MAX_MESSAGE_LEN) - if(newid && canAccess(usr)) - id = newid - temp = "-% New ID assigned: \"[id]\" %-" - - if("network") - var/newnet = input(usr, "Specify the new network for this machine. This will break all current links.", src, network) as null|text - if(newnet && canAccess(usr)) - - if(length(newnet) > 15) - temp = "-% Too many characters in new network tag %-" - - else - for(var/obj/machinery/telecomms/T in links) - T.links.Remove(src) - - network = newnet - links = list() - temp = "-% New network tag assigned: \"[network]\" %-" - - - if("freq") - var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num - if(newfreq && canAccess(usr)) - if(findtext(num2text(newfreq), ".")) - newfreq *= 10 // shift the decimal one place - if(!(newfreq in freq_listening) && newfreq < 10000) - freq_listening.Add(newfreq) - temp = "-% New frequency filter assigned: \"[newfreq] GHz\" %-" - - if("tagrule") - var/freq = input(usr, "Specify frequency to tag (GHz). Decimals assigned automatically.", src, network) as null|num - if(freq && canAccess(usr)) - if(findtext(num2text(freq), ".")) - freq *= 10 - - if(!(freq in freq_listening)) - temp = "-% Not filtering specified frequency %-" - updateUsrDialog() - return - - for(var/list/rule in channel_tags) - if(rule[1] == freq) - temp = "-% Tagging rule already defined %-" - updateUsrDialog() - return - - var/tag = input(usr, "Specify tag.", src, "") as null|text - var/color = input(usr, "Select color.", src, "") as null|anything in (channel_color_presets + "Custom color") - - if(color == "Custom color") - color = input("Select color.", src, rgb(0, 128, 0)) as null|color - else - color = channel_color_presets[color] - - if(freq < 10000) - channel_tags.Add(list(list(freq, tag, color))) - temp = "-% New tagging rule assigned:[freq] GHz -> \"[tag]\" ([color]) %-" - - if(href_list["delete"]) - - // changed the layout about to workaround a pesky runtime -- Doohl - - var/x = text2num(href_list["delete"]) - temp = "-% Removed frequency filter [x] %-" - freq_listening.Remove(x) - - if(href_list["deletetagrule"]) - - var/freq = text2num(href_list["deletetagrule"]) - var/rule_delete - for(var/list/rule in channel_tags) - if(rule[1] == freq) - rule_delete = rule - temp = "-% Removed tagging rule: [rule_delete[1]] -> [rule_delete[2]] %-" - channel_tags.Remove(list(rule_delete)) - - if(href_list["unlink"]) - - if(text2num(href_list["unlink"]) <= length(links)) - var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])] - temp = "-% Removed \ref[T] [T.name] from linked entities. %-" - - // Remove link entries from both T and src. - - if(src in T.links) - T.links.Remove(src) - links.Remove(T) - - if(href_list["link"]) - - if(P) - var/obj/machinery/telecomms/device = P.get_buffer() - if(istype(device) && device != src) - if(!(src in device.links)) - device.links.Add(src) - - if(!(device in src.links)) - src.links.Add(device) - - temp = "-% Successfully linked with \ref[device] [device.name] %-" - - else - temp = "-% Unable to acquire buffer %-" - - if(href_list["buffer"]) - - P.set_buffer(src) - var/atom/buffer = P.get_buffer() - temp = "-% Successfully stored \ref[buffer] [buffer.name] in buffer %-" - - - if(href_list["flush"]) - - temp = "-% Buffer successfully flushed. %-" - P.set_buffer(null) - - src.Options_Topic(href, href_list) - - usr.set_machine(src) - - updateUsrDialog() - -/obj/machinery/telecomms/proc/canAccess(var/mob/user) - if(issilicon(user) || in_range(user, src)) - return 1 - return 0 diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm deleted file mode 100644 index 1ea20daec08b..000000000000 --- a/code/game/machinery/telecomms/presets.dm +++ /dev/null @@ -1,201 +0,0 @@ -// ### Preset machines ### - -//HUB - -/obj/machinery/telecomms/hub/preset - id = "Hub" - network = "tcommsat" - autolinkers = list("hub", "relay", "c_relay", "s_relay", "m_relay", "r_relay", "b_relay", "1_relay", "2_relay", "3_relay", "4_relay", "5_relay", "s_relay", "science", "medical", - "supply", "service", "common", "command", "engineering", "security", "unused", - "receiverA", "broadcasterA") - -/obj/machinery/telecomms/hub/preset_cent - id = "CentComm Hub" - network = "tcommsat" - produces_heat = 0 - autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay", - "centcomm", "receiverCent", "broadcasterCent") - -//Receivers - -/obj/machinery/telecomms/receiver/preset_right - id = "Receiver A" - network = "tcommsat" - autolinkers = list("receiverA") // link to relay - freq_listening = list(AI_FREQ, SCI_FREQ, MED_FREQ, SUP_FREQ, SRV_FREQ, COMM_FREQ, ENG_FREQ, SEC_FREQ, ENT_FREQ) - - //Common and other radio frequencies for people to freely use -/obj/machinery/telecomms/receiver/preset_right/Initialize() - for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2) - freq_listening |= i - . = ..() - -/obj/machinery/telecomms/receiver/preset_cent - id = "CentComm Receiver" - network = "tcommsat" - produces_heat = 0 - autolinkers = list("receiverCent") - freq_listening = list(ERT_FREQ, DTH_FREQ) - - -//Buses - -/obj/machinery/telecomms/bus/preset_one - id = "Bus 1" - network = "tcommsat" - freq_listening = list(SCI_FREQ, MED_FREQ) - autolinkers = list("processor1", "science", "medical") - -/obj/machinery/telecomms/bus/preset_two - id = "Bus 2" - network = "tcommsat" - freq_listening = list(SUP_FREQ, SRV_FREQ) - autolinkers = list("processor2", "supply", "service", "unused") - -/obj/machinery/telecomms/bus/preset_two/Initialize() - . = ..() - for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2) - if(i == PUB_FREQ) - continue - freq_listening |= i - -/obj/machinery/telecomms/bus/preset_three - id = "Bus 3" - network = "tcommsat" - freq_listening = list(SEC_FREQ, COMM_FREQ) - autolinkers = list("processor3", "security", "command") - -/obj/machinery/telecomms/bus/preset_four - id = "Bus 4" - network = "tcommsat" - freq_listening = list(ENG_FREQ, AI_FREQ, PUB_FREQ, ENT_FREQ) - autolinkers = list("processor4", "engineering", "common") - -/obj/machinery/telecomms/bus/preset_cent - id = "CentComm Bus" - network = "tcommsat" - freq_listening = list(ERT_FREQ, DTH_FREQ, ENT_FREQ) - produces_heat = 0 - autolinkers = list("processorCent", "centcomm") - -//Processors - -/obj/machinery/telecomms/processor/preset_one - id = "Processor 1" - network = "tcommsat" - autolinkers = list("processor1") // processors are sort of isolated; they don't need backward links - -/obj/machinery/telecomms/processor/preset_two - id = "Processor 2" - network = "tcommsat" - autolinkers = list("processor2") - -/obj/machinery/telecomms/processor/preset_three - id = "Processor 3" - network = "tcommsat" - autolinkers = list("processor3") - -/obj/machinery/telecomms/processor/preset_four - id = "Processor 4" - network = "tcommsat" - autolinkers = list("processor4") - -/obj/machinery/telecomms/processor/preset_cent - id = "CentComm Processor" - network = "tcommsat" - produces_heat = 0 - autolinkers = list("processorCent") - -//Servers - -/obj/machinery/telecomms/server/presets - - network = "tcommsat" - -/obj/machinery/telecomms/server/presets/science - id = "Science Server" - freq_listening = list(SCI_FREQ) - channel_tags = list(list(SCI_FREQ, "Science", COMMS_COLOR_SCIENCE)) - autolinkers = list("science") - -/obj/machinery/telecomms/server/presets/medical - id = "Medical Server" - freq_listening = list(MED_FREQ) - channel_tags = list(list(MED_FREQ, "Medical", COMMS_COLOR_MEDICAL)) - autolinkers = list("medical") - -/obj/machinery/telecomms/server/presets/supply - id = "Supply Server" - freq_listening = list(SUP_FREQ) - channel_tags = list(list(SUP_FREQ, "Supply", COMMS_COLOR_SUPPLY)) - autolinkers = list("supply") - -/obj/machinery/telecomms/server/presets/service - id = "Service Server" - freq_listening = list(SRV_FREQ) - channel_tags = list(list(SRV_FREQ, "Service", COMMS_COLOR_SERVICE)) - autolinkers = list("service") - -/obj/machinery/telecomms/server/presets/common - id = "Common Server" - freq_listening = list(PUB_FREQ, AI_FREQ, ENT_FREQ) // AI Private and Common - channel_tags = list( - list(PUB_FREQ, "Common", COMMS_COLOR_COMMON), - list(AI_FREQ, "AI Private", COMMS_COLOR_AI), - list(ENT_FREQ, "Entertainment", COMMS_COLOR_ENTERTAIN) - ) - autolinkers = list("common") - -// "Unused" channels, AKA all others. -/obj/machinery/telecomms/server/presets/unused - id = "Unused Server" - freq_listening = list() - autolinkers = list("unused") - -/obj/machinery/telecomms/server/presets/unused/Initialize() - . = ..() - for(var/i = PUBLIC_LOW_FREQ, i < PUBLIC_HIGH_FREQ, i += 2) - if(i == AI_FREQ || i == PUB_FREQ) - continue - freq_listening |= i - -/obj/machinery/telecomms/server/presets/command - id = "Command Server" - freq_listening = list(COMM_FREQ) - channel_tags = list(list(COMM_FREQ, "Command", COMMS_COLOR_COMMAND)) - autolinkers = list("command") - -/obj/machinery/telecomms/server/presets/engineering - id = "Engineering Server" - freq_listening = list(ENG_FREQ) - channel_tags = list(list(ENG_FREQ, "Engineering", COMMS_COLOR_ENGINEER)) - autolinkers = list("engineering") - -/obj/machinery/telecomms/server/presets/security - id = "Security Server" - freq_listening = list(SEC_FREQ) - channel_tags = list(list(SEC_FREQ, "Security", COMMS_COLOR_SECURITY)) - autolinkers = list("security") - -/obj/machinery/telecomms/server/presets/centcomm - id = "CentComm Server" - freq_listening = list(ERT_FREQ, DTH_FREQ) - channel_tags = list(list(ERT_FREQ, "Response Team", COMMS_COLOR_CENTCOMM), list(DTH_FREQ, "Special Ops", COMMS_COLOR_SYNDICATE)) - produces_heat = 0 - autolinkers = list("centcomm") - - -//Broadcasters - -//--PRESET LEFT--// - -/obj/machinery/telecomms/broadcaster/preset_right - id = "Broadcaster A" - network = "tcommsat" - autolinkers = list("broadcasterA") - -/obj/machinery/telecomms/broadcaster/preset_cent - id = "CentComm Broadcaster" - network = "tcommsat" - produces_heat = 0 - autolinkers = list("broadcasterCent") diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm deleted file mode 100644 index 2ec901dfaab0..000000000000 --- a/code/game/machinery/telecomms/telecomunications.dm +++ /dev/null @@ -1,584 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/* - Hello, friends, this is Doohl from sexylands. You may be wondering what this - monstrous code file is. Sit down, boys and girls, while I tell you the tale. - - - The machines defined in this file were designed to be compatible with any radio - signals, provided they use subspace transmission. Currently they are only used for - headsets, but they can eventually be outfitted for real COMPUTER networks. This - is just a skeleton, ladies and gentlemen. - - Look at radio.dm for the prequel to this code. -*/ - -var/global/list/obj/machinery/telecomms/telecomms_list = list() - -/obj/machinery/telecomms - var/list/links = list() // list of machines this machine is linked to - var/traffic = 0 // value increases as traffic increases - var/netspeed = 5 // how much traffic to lose per tick (50 gigabytes/second * netspeed) - var/list/autolinkers = list() // list of text/number values to link with - var/id = "NULL" // identification string - var/network = "NULL" // the network of the machinery - - var/list/freq_listening = list() // list of frequencies to tune into: if none, will listen to all - var/list/channel_tags = list() // a list specifying what to tag packets on different frequencies - - var/machinetype = 0 // just a hacky way of preventing alike machines from pairing - var/toggled = 1 // Is it toggled on - var/on = 1 - var/integrity = 100 // basically HP, loses integrity by heat - var/produces_heat = 1 //whether the machine will produce heat when on. - var/delay = 10 // how many process() ticks to delay per heat - var/long_range_link = 0 // Can you link it across Z levels or on the otherside of the map? (Relay & Hub) - var/circuitboard = null // string pointing to a circuitboard type - var/hide = 0 // Is it a hidden machine? - var/listening_levels = null // null = auto set in Initialize() - these are the z levels that the machine is listening to. - var/overloaded_for = 0 - var/outage_probability = 75 // Probability of failing during a ionospheric storm - - -/obj/machinery/telecomms/proc/relay_information(datum/signal/signal, filter, copysig, amount = 20) - // relay signal to all linked machinery that are of type [filter]. If signal has been sent [amount] times, stop sending - - if(!on || overloaded_for) - return -// log_debug("[src] ([src.id]) - [signal.debug_print()]") - - var/send_count = 0 - - signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity - - /* - // Edit by Atlantis: Commented out as emergency fix due to causing extreme delays in communications. - // Apply some lag based on traffic rates - var/netlag = round(traffic / 50) - if(netlag > signal.data["slow"]) - signal.data["slow"] = netlag - */ -// Loop through all linked machines and send the signal or copy. - for(var/obj/machinery/telecomms/machine in links) - if(filter && !istype( machine, filter )) - continue - if(!machine.on) - continue - if(amount && send_count >= amount) - break - if(!(machine.loc.z in listening_levels)) - if(long_range_link == 0 && machine.long_range_link == 0) - continue - // If we're sending a copy, be sure to create the copy for EACH machine and paste the data - var/datum/signal/copy - if(copysig) - copy = new - copy.transmission_method = 2 - copy.frequency = signal.frequency - copy.data = signal.data.Copy() - - // Keep the "original" signal constant - if(!signal.data["original"]) - copy.data["original"] = signal - else - copy.data["original"] = signal.data["original"] - - send_count++ - if(machine.is_freq_listening(signal)) - machine.traffic++ - - if(copysig && copy) - machine.receive_information(copy, src) - else - machine.receive_information(signal, src) - - - if(send_count > 0 && is_freq_listening(signal)) - traffic++ - - return send_count - -/obj/machinery/telecomms/proc/relay_direct_information(datum/signal/signal, obj/machinery/telecomms/machine) - // send signal directly to a machine - machine.receive_information(signal, src) - -/obj/machinery/telecomms/proc/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - // receive information from linked machinery - -/obj/machinery/telecomms/proc/is_freq_listening(datum/signal/signal) - // return 1 if found, 0 if not found - if(!signal) - return 0 - if((signal.frequency in freq_listening) || (!freq_listening.len)) - return 1 - else - return 0 - -/obj/machinery/telecomms/Initialize() - . = ..() - //Set the listening_levels if there's none. - if(!listening_levels) - //Defaults to our Z level! - var/turf/position = get_turf(src) - listening_levels = GetConnectedZlevels(position.z) - - if(autolinkers.len) - // Links nearby machines - if(!long_range_link) - for(var/obj/machinery/telecomms/T in orange(20, src)) - add_link(T) - else - . = INITIALIZE_HINT_LATELOAD - - telecomms_list += src - update_power() - -/obj/machinery/telecomms/LateInitialize() - ..() - if(autolinkers.len && long_range_link) - for(var/obj/machinery/telecomms/T in telecomms_list) - add_link(T) - -/obj/machinery/telecomms/Destroy() - telecomms_list -= src - for(var/obj/machinery/telecomms/comm in telecomms_list) - comm.links -= src - links = list() - ..() - -// Used in auto linking -/obj/machinery/telecomms/proc/add_link(var/obj/machinery/telecomms/T) - var/turf/position = get_turf(src) - var/turf/T_position = get_turf(T) - if((position.z == T_position.z) || (src.long_range_link && T.long_range_link)) - for(var/x in autolinkers) - if(T.autolinkers.Find(x)) - if(src != T) - links |= T - -/obj/machinery/telecomms/on_update_icon() - if(on && !overloaded_for) - icon_state = initial(icon_state) - else - icon_state = "[initial(icon_state)]_off" - -/obj/machinery/telecomms/Move() - . = ..() - listening_levels = GetConnectedZlevels(z) - update_power() - -/obj/machinery/telecomms/forceMove(var/newloc) - . = ..(newloc) - listening_levels = GetConnectedZlevels(z) - update_power() - -/obj/machinery/telecomms/proc/update_power() - if(toggled) - if(stat & (BROKEN|NOPOWER|EMPED) || integrity <= 0) // if powered, on. if not powered, off. if too damaged, off - on = 0 - else - on = 1 - else - on = 0 - update_use_power(on) - -/obj/machinery/telecomms/Process() - update_power() - - if(overloaded_for) - overloaded_for-- - - // Check heat and generate some - checkheat() - - // Update the icon - update_icon() - - if(traffic > 0) - traffic -= netspeed - -/obj/machinery/telecomms/emp_act(severity) - if(prob(100/severity)) - overloaded_for = max(round(150 / severity), overloaded_for) - ..() - -/obj/machinery/telecomms/proc/checkheat() - // Checks heat from the environment and applies any integrity damage - var/datum/gas_mixture/environment = loc.return_air() - var/damage_chance = 0 // Percent based chance of applying 1 integrity damage this tick - switch(environment.temperature) - if((T0C + 40) to (T0C + 70)) // 40C-70C, minor overheat, 10% chance of taking damage - damage_chance = 10 - if((T0C + 70) to (T0C + 130)) // 70C-130C, major overheat, 25% chance of taking damage - damage_chance = 25 - if((T0C + 130) to (T0C + 200)) // 130C-200C, dangerous overheat, 50% chance of taking damage - damage_chance = 50 - if((T0C + 200) to INFINITY) // More than 200C, INFERNO. Takes damage every tick. - damage_chance = 100 - if (damage_chance && prob(damage_chance)) - integrity = between(0, integrity - 1, 100) - - - if(delay > 0) - delay-- - else if(on) - produce_heat() - delay = initial(delay) - - - -/obj/machinery/telecomms/proc/produce_heat() - if (!produces_heat) - return - - if (!use_power) - return - - if(!(stat & (NOPOWER|BROKEN))) - var/turf/simulated/L = loc - if(istype(L)) - var/datum/gas_mixture/env = L.return_air() - - var/transfer_moles = 0.25 * env.total_moles - - var/datum/gas_mixture/removed = env.remove(transfer_moles) - - if(removed) - - var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source - if (traffic <= 0) - heat_produced *= 0.30 //if idle, produce less heat. - - removed.add_thermal_energy(heat_produced) - - env.merge(removed) -/* - The receiver idles and receives messages from subspace-compatible radio equipment; - primarily headsets. They then just relay this information to all linked devices, - which can would probably be network hubs. - - Link to Processor Units in case receiver can't send to bus units. -*/ - -/obj/machinery/telecomms/receiver - name = "Subspace Receiver" - icon = 'icons/obj/machines/tcomms/receiver.dmi' - icon_state = "broadcast receiver" - desc = "This machine has a dish-like shape and green lights. It is designed to detect and process subspace radio activity." - density = 1 - anchored = 1 - idle_power_usage = 600 - machinetype = 1 - produces_heat = 0 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/receiver - base_type = /obj/machinery/telecomms/receiver - outage_probability = 10 - -/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal) - - if(!on) // has to be on to receive messages - return - if(!signal) - return - if(!check_receive_level(signal)) - return - - if(signal.transmission_method == 2) - - if(is_freq_listening(signal)) // detect subspace signals - - //Remove the level and then start adding levels that it is being broadcasted in. - signal.data["level"] = list() - - var/can_send = relay_information(signal, /obj/machinery/telecomms/hub) // ideally relay the copied information to relays - if(!can_send) - relay_information(signal, /obj/machinery/telecomms/bus) // Send it to a bus instead, if it's linked to one - -/obj/machinery/telecomms/receiver/proc/check_receive_level(datum/signal/signal) - - if(!(signal.data["level"] in listening_levels)) - return 0 - return 1 - - -/* - The HUB idles until it receives information. It then passes on that information - depending on where it came from. - - This is the heart of the Telecommunications Network, sending information where it - is needed. It mainly receives information from long-distance Relays and then sends - that information to be processed. Afterwards it gets the uncompressed information - from Servers/Buses and sends that back to the relay, to then be broadcasted. -*/ - -/obj/machinery/telecomms/hub - name = "Telecommunication Hub" - icon = 'icons/obj/machines/tcomms/hub.dmi' - icon_state = "hub" - desc = "A mighty piece of hardware used to send/receive massive amounts of data." - density = 1 - anchored = 1 - idle_power_usage = 1600 - machinetype = 7 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/hub - base_type = /obj/machinery/telecomms/hub - long_range_link = 1 - netspeed = 40 - outage_probability = 10 - -/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - if(is_freq_listening(signal)) - if(istype(machine_from, /obj/machinery/telecomms/receiver)) - //If the signal is compressed, send it to the bus. - relay_information(signal, /obj/machinery/telecomms/bus, 1) // ideally relay the copied information to bus units - else - relay_information(signal, /obj/machinery/telecomms/broadcaster, 1) // Send it to a broadcaster. - -/* - The bus mainframe idles and waits for hubs to relay them signals. They act - as junctions for the network. - - They transfer uncompressed subspace packets to processor units, and then take - the processed packet to a server for logging. - - Link to a subspace hub if it can't send to a server. -*/ - -/obj/machinery/telecomms/bus - name = "Bus Mainframe" - icon = 'icons/obj/machines/tcomms/bus.dmi' - icon_state = "bus" - desc = "A mighty piece of hardware used to send massive amounts of data quickly." - density = 1 - anchored = 1 - idle_power_usage = 1000 - machinetype = 2 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/bus - base_type = /obj/machinery/telecomms/bus - netspeed = 40 - var/change_frequency = 0 - -/obj/machinery/telecomms/bus/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - - if(is_freq_listening(signal)) - - if(change_frequency) - signal.frequency = change_frequency - - if(!istype(machine_from, /obj/machinery/telecomms/processor) && machine_from != src) // Signal must be ready (stupid assuming machine), let's send it - // send to one linked processor unit - var/send_to_processor = relay_information(signal, /obj/machinery/telecomms/processor) - - if(send_to_processor) - return - // failed to send to a processor, relay information anyway - signal.data["slow"] += rand(1, 5) // slow the signal down only slightly - src.receive_information(signal, src) - - // Try sending it! - var/list/try_send = list(/obj/machinery/telecomms/server, /obj/machinery/telecomms/hub, /obj/machinery/telecomms/broadcaster, /obj/machinery/telecomms/bus) - var/i = 0 - for(var/send in try_send) - if(i) - signal.data["slow"] += rand(0, 1) // slow the signal down only slightly - i++ - var/can_send = relay_information(signal, send) - if(can_send) - break - - - -/* - The processor is a very simple machine that decompresses subspace signals and - transfers them back to the original bus. It is essential in producing audible - data. - - Link to servers if bus is not present -*/ - -/obj/machinery/telecomms/processor - name = "Processor Unit" - icon = 'icons/obj/machines/tcomms/processor.dmi' - icon_state = "processor" - desc = "This machine is used to process large quantities of information." - density = 1 - anchored = 1 - idle_power_usage = 600 - machinetype = 3 - delay = 5 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/processor - base_type = /obj/machinery/telecomms/processor - var/process_mode = 1 // 1 = Uncompress Signals, 0 = Compress Signals - -/obj/machinery/telecomms/processor/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - if(!is_freq_listening(signal)) - return - - if(process_mode) - signal.data["compression"] = 0 // uncompress subspace signal - else - signal.data["compression"] = 100 // even more compressed signal - - if(istype(machine_from, /obj/machinery/telecomms/bus)) - relay_direct_information(signal, machine_from) // send the signal back to the machine - else // no bus detected - send the signal to servers instead - signal.data["slow"] += rand(5, 10) // slow the signal down - relay_information(signal, /obj/machinery/telecomms/server) - - -/* - The server logs all traffic and signal data. Once it records the signal, it sends - it to the subspace broadcaster. - - Store a maximum of 100 logs and then deletes them. -*/ - - -/obj/machinery/telecomms/server - name = "Telecommunication Server" - icon = 'icons/obj/machines/tcomms/comm_server.dmi' - icon_state = "comm_server" - desc = "A machine used to store data and network statistics." - density = 1 - anchored = 1 - idle_power_usage = 300 - machinetype = 4 - circuitboard = /obj/item/stock_parts/circuitboard/telecomms/server - base_type = /obj/machinery/telecomms/server - var/list/log_entries = list() - var/list/stored_names = list() - var/list/TrafficActions = list() - var/logs = 0 // number of logs - var/totaltraffic = 0 // gigabytes (if > 1024, divide by 1024 -> terrabytes) - - var/list/memory = list() // stored memory - var/encryption = "null" // encryption key: ie "password" - var/salt = "null" // encryption salt: ie "123comsat" - // would add up to md5("password123comsat") - var/language = "human" - var/obj/item/radio/headset/server_radio = null - -/obj/machinery/telecomms/server/Initialize() - . = ..() - server_radio = new() - -/obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - - if(signal.data["message"]) - - if(is_freq_listening(signal)) - - if(traffic > 0) - totaltraffic += traffic // add current traffic to total traffic - - // channel tag the signal - var/list/data = get_channel_info(signal.frequency) - signal.data["channel_tag"] = data[1] - signal.data["channel_color"] = data[2] - - //Is this a test signal? Bypass logging - if(signal.data["type"] != 4) - - // If signal has a message and appropriate frequency - - update_logs() - - var/datum/comm_log_entry/log = new - var/mob/M = signal.data["mob"] - - // Copy the signal.data entries we want - log.parameters["mobtype"] = signal.data["mobtype"] - log.parameters["job"] = signal.data["job"] - log.parameters["key"] = signal.data["key"] - log.parameters["vmessage"] = signal.data["message"] - log.parameters["vname"] = signal.data["vname"] - log.parameters["message"] = signal.data["message"] - log.parameters["name"] = signal.data["name"] - log.parameters["realname"] = signal.data["realname"] - log.parameters["language"] = signal.data["language"] - - var/race = "Unknown" - if(ishuman(M) || isbrain(M)) - race = "Sapient Race" - log.parameters["intelligible"] = 1 - else if(M.isMonkey()) - race = "Monkey" - else if(issilicon(M)) - race = "Artificial Life" - log.parameters["intelligible"] = 1 - else if(isslime(M)) - race = "Slime" - else if(isanimal(M)) - race = "Domestic Animal" - - log.parameters["race"] = race - - if(!istype(M, /mob/new_player) && M) - log.parameters["uspeech"] = M.universal_speak - else - log.parameters["uspeech"] = 0 - - // If the signal is still compressed, make the log entry gibberish - if(signal.data["compression"] > 0) - log.parameters["message"] = Gibberish(signal.data["message"], signal.data["compression"] + 50) - log.parameters["job"] = Gibberish(signal.data["job"], signal.data["compression"] + 50) - log.parameters["name"] = Gibberish(signal.data["name"], signal.data["compression"] + 50) - log.parameters["realname"] = Gibberish(signal.data["realname"], signal.data["compression"] + 50) - log.parameters["vname"] = Gibberish(signal.data["vname"], signal.data["compression"] + 50) - log.input_type = "Corrupt File" - - // Log and store everything that needs to be logged - log_entries.Add(log) - if(!(signal.data["name"] in stored_names)) - stored_names.Add(signal.data["name"]) - logs++ - signal.data["server"] = src - - // Give the log a name - var/identifier = num2text( rand(-1000,1000) + world.time ) - log.name = "data packet ([md5(identifier)])" - - var/can_send = relay_information(signal, /obj/machinery/telecomms/hub) - if(!can_send) - relay_information(signal, /obj/machinery/telecomms/broadcaster) - -/obj/machinery/telecomms/server/proc/update_logs() - // start deleting the very first log entry - if(logs >= 400) - for(var/i = 1, i <= logs, i++) // locate the first garbage collectable log entry and remove it - var/datum/comm_log_entry/L = log_entries[i] - if(L.garbage_collector) - log_entries.Remove(L) - logs-- - break - -/obj/machinery/telecomms/server/proc/add_entry(var/content, var/input) - var/datum/comm_log_entry/log = new - var/identifier = num2text( rand(-1000,1000) + world.time ) - log.name = "[input] ([md5(identifier)])" - log.input_type = input - log.parameters["message"] = content - log_entries.Add(log) - update_logs() - -/obj/machinery/telecomms/server/proc/get_channel_info(var/freq) - for(var/list/rule in channel_tags) - if(rule[1] == freq) - return list(rule[2], rule[3]) - return list(format_frequency(freq), channel_color_presets["Global Green"]) - - -// Simple log entry datum - -/datum/comm_log_entry - var/parameters = list() // carbon-copy to signal.data[] - var/name = "data packet (#)" - var/garbage_collector = 1 // if set to 0, will not be garbage collected - var/input_type = "Speech File" - - - - - - - diff --git a/code/game/machinery/telecomms/telemonitor.dm b/code/game/machinery/telecomms/telemonitor.dm deleted file mode 100644 index 1cc70fa9b062..000000000000 --- a/code/game/machinery/telecomms/telemonitor.dm +++ /dev/null @@ -1,132 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - - -/* - Telecomms monitor tracks the overall trafficing of a telecommunications network - and displays a heirarchy of linked machines. -*/ - - -/obj/machinery/computer/telecomms/monitor - name = "Telecommunications Monitor" - icon_screen = "comm_monitor" - - var/screen = 0 // the screen number: - var/list/machinelist = list() // the machines located by the computer - var/obj/machinery/telecomms/SelectedMachine - - var/network = "NULL" // the network to probe - - var/temp = "" // temporary feedback messages - - attack_hand(mob/user as mob) - if(stat & (BROKEN|NOPOWER)) - return - user.set_machine(src) - var/list/dat = list() - dat += "Telecommunications Monitor
              Telecommunications Monitor
              " - - switch(screen) - - - // --- Main Menu --- - - if(0) - dat += "
              [temp]

              " - dat += "
              Current Network: [network]
              " - if(machinelist.len) - dat += "
              Detected Network Entities:
                " - for(var/obj/machinery/telecomms/T in machinelist) - dat += "
              • \ref[T] [T.name] ([T.id])
              • " - dat += "
              " - dat += "
              \[Flush Buffer\]" - else - dat += "\[Probe Network\]" - - - // --- Viewing Machine --- - - if(1) - dat += "
              [temp]
              " - dat += "
              \[Main Menu\]
              " - dat += "
              Current Network: [network]
              " - dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])
              " - dat += "Linked Entities:
                " - for(var/obj/machinery/telecomms/T in SelectedMachine.links) - if(!T.hide) - dat += "
              1. \ref[T.id] [T.name] ([T.id])
              2. " - dat += "
              " - - - var/datum/browser/written/popup = new(user, "comm_monitor", "Autholathe", 575, 400) - popup.set_content(JOINTEXT(dat)) - popup.open() - - temp = "" - return - - - Topic(href, href_list) - if(..()) - return - - usr.set_machine(src) - - if(href_list["viewmachine"]) - screen = 1 - for(var/obj/machinery/telecomms/T in machinelist) - if(T.id == href_list["viewmachine"]) - SelectedMachine = T - break - - if(href_list["operation"]) - switch(href_list["operation"]) - - if("release") - machinelist = list() - screen = 0 - - if("mainmenu") - screen = 0 - - if("probe") - if(machinelist.len > 0) - temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" - - else - for(var/obj/machinery/telecomms/T in range(25, src)) - if(T.network == network) - machinelist.Add(T) - - if(!machinelist.len) - temp = "- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -" - else - temp = "- [machinelist.len] ENTITIES LOCATED & BUFFERED -" - - screen = 0 - - - if(href_list["network"]) - - var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text - if(newnet && ((usr in range(1, src) || issilicon(usr)))) - if(length(newnet) > 15) - temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" - - else - network = newnet - screen = 0 - machinelist = list() - temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" - - updateUsrDialog() - return - -/obj/machinery/computer/telecomms/monitor/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) - playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) - emagged = 1 - req_access.Cut() - to_chat(user, "You you disable the security protocols") - src.updateUsrDialog() - return 1 diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index a9f693c6c690..b2ee51ae93a7 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -1,5 +1,5 @@ /obj/machinery/computer/teleporter - name = "Teleporter Control Console" + name = "teleporter control console" desc = "Used to control a linked teleportation hub and station." icon_keyboard = "teleport_key" icon_screen = "teleport" @@ -15,9 +15,17 @@ id = "[random_id(/obj/machinery/computer/teleporter, 1000, 9999)]" - station = locate(/obj/machinery/teleport/station, get_step(src, turn(dir, 90))) + for (var/dir in global.cardinal) + var/obj/machinery/teleport/station/found_station = locate() in get_step(src, dir) + if(found_station) + station = found_station + break if(station) - hub = locate(/obj/machinery/teleport/hub, get_step(station, turn(dir, 90))) + for (var/dir in global.cardinal) + var/obj/machinery/teleport/hub/found_hub = locate() in get_step(station, dir) + if(found_hub) + hub = found_hub + break if(istype(station)) station.hub = hub @@ -34,59 +42,37 @@ // Lose memory locked = null -/obj/machinery/computer/teleporter/examine(mob/user) +/obj/machinery/computer/teleporter/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(locked) var/turf/T = get_turf(locked) - to_chat(user, "The console is locked on to \[[T.loc.name]\].") - + . += SPAN_NOTICE("The console is locked on to \[[T.loc.name]\].") -/obj/machinery/computer/teleporter/attackby(var/obj/I, var/mob/living/user) - if(istype(I, /obj/item/card/data/)) - var/obj/item/card/data/C = I - if(stat & (NOPOWER|BROKEN) & (C.function != "teleporter")) - attack_hand(user) +/obj/machinery/computer/teleporter/attackby(var/obj/used_item, var/mob/user) - var/obj/L = null + var/obj/item/card/data/C = used_item + if(!istype(C) || (stat & (NOPOWER|BROKEN)) || C.function != "teleporter") + return ..() - for(var/obj/effect/landmark/sloc in landmarks_list) - if(sloc.name != C.data) continue - if(locate(/mob/living) in sloc.loc) continue - L = sloc - break - - if(!L) - L = locate("landmark*[C.data]") // use old stype - - - if(istype(L, /obj/effect/landmark/) && istype(L.loc, /turf)) - if(!user.unEquip(I)) - return - to_chat(usr, "You insert the coordinates into the machine.") - to_chat(usr, "A message flashes across the screen reminding the traveller that the nuclear authentication disk is to remain on the [station_name()] at all times.") - qdel(I) - - if(C.data == "Clown Land") - //whoops - for(var/mob/O in hearers(src, null)) - O.show_message("Incoming wormhole detected, unable to lock in.", 2) - - for(var/obj/machinery/teleport/hub/H in range(1)) - var/amount = rand(2,5) - for(var/i=0;iLocked in.", 2) - src.locked = L - one_time_use = 1 - - src.add_fingerprint(usr) - else - ..() - - return + var/obj/L = null + for(var/obj/abstract/landmark/sloc in global.all_landmarks) + if(sloc.name != C.data || (locate(/mob/living) in sloc.loc)) + continue + L = sloc + break + + if(!L) + L = locate("landmark*[C.data]") // use old stype + + if(istype(L, /obj/abstract/landmark) && isturf(L.loc) && user.try_unequip(used_item)) + to_chat(user, "You insert the coordinates into the machine.") + to_chat(user, "A message flashes across the screen reminding the traveller that the nuclear authentication disk is to remain on the [station_name()] at all times.") + qdel(used_item) + audible_message(SPAN_NOTICE("Locked in.")) + src.locked = L + one_time_use = 1 + add_fingerprint(user) + return TRUE /obj/machinery/computer/teleporter/interface_interact(var/mob/user) /* Run full check because it's a direct selection */ @@ -97,40 +83,40 @@ var/list/areaindex = list() . = TRUE - for(var/obj/item/radio/beacon/R in world) - if(!R.functioning) + for(var/obj/item/radio/beacon/radio in global.radio_beacons) + if(!radio.functioning) continue - var/turf/T = get_turf(R) - if (!T) + var/turf/radio_turf = get_turf(radio) + if (!radio_turf) continue - if(!(T.z in GLOB.using_map.player_levels)) + if(!isPlayerLevel(radio_turf.z)) continue - var/tmpname = T.loc.name + var/area/radio_area = get_area(radio) + var/tmpname = radio_area.proper_name if(areaindex[tmpname]) tmpname = "[tmpname] ([++areaindex[tmpname]])" else areaindex[tmpname] = 1 - L[tmpname] = R + L[tmpname] = radio - for (var/obj/item/implant/tracking/I in world) - if (!I.implanted || !ismob(I.loc)) + for (var/obj/item/implant/tracking/used_item in global.tracking_implants) + if (!used_item.implanted || !ismob(used_item.loc)) continue + var/mob/victim = used_item.loc + // Can only track dead people up to 10 minutes after death + if (victim.stat == DEAD && world.time > victim.timeofdeath + 10 MINUTES) + continue + var/turf/victim_turf = get_turf(victim) + if(!victim_turf) + continue + if(!isPlayerLevel(victim_turf.z)) + continue + var/tmpname = victim.real_name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" else - var/mob/M = I.loc - if (M.stat == 2) - if (M.timeofdeath + 6000 < world.time) - continue - var/turf/T = get_turf(M) - if(!T) - continue - if(!(T.z in GLOB.using_map.player_levels)) - continue - var/tmpname = M.real_name - if(areaindex[tmpname]) - tmpname = "[tmpname] ([++areaindex[tmpname]])" - else - areaindex[tmpname] = 1 - L[tmpname] = I + areaindex[tmpname] = 1 + L[tmpname] = used_item var/desc = input("Please select a location to lock in.", "Locking Computer") in L|null if(!desc) @@ -138,36 +124,35 @@ if(!CanInteract(user, DefaultTopicState())) return FALSE set_target(L[desc]) - for(var/mob/O in hearers(src, null)) - O.show_message("Locked In", 2) + audible_message(SPAN_NOTICE("Locked in.")) return -/obj/machinery/computer/teleporter/verb/set_id(t as text) +/obj/machinery/computer/teleporter/verb/set_id(new_tag as text) set category = "Object" set name = "Set teleporter ID" set src in oview(1) set desc = "ID Tag:" - if(stat & (NOPOWER|BROKEN) || !istype(usr,/mob/living)) + if(stat & (NOPOWER|BROKEN) || !isliving(usr)) return - if (t) - src.id = t + if (new_tag) + src.id = new_tag return /obj/machinery/computer/teleporter/proc/target_lost() - audible_message("Connection with locked in coordinates has been lost.") + audible_message(SPAN_WARNING("Connection with locked in coordinates has been lost.")) clear_target() /obj/machinery/computer/teleporter/proc/clear_target() if(src.locked) - GLOB.destroyed_event.unregister(locked, src, .proc/target_lost) + events_repository.unregister(/decl/observ/destroyed, locked, src, PROC_REF(target_lost)) src.locked = null if(station && station.engaged) station.disengage() -/obj/machinery/computer/teleporter/proc/set_target(var/obj/O) - src.locked = O - GLOB.destroyed_event.register(locked, src, .proc/target_lost) +/obj/machinery/computer/teleporter/proc/set_target(var/obj/target) + src.locked = target + events_repository.register(/decl/observ/destroyed, locked, src, PROC_REF(target_lost)) /obj/machinery/computer/teleporter/Destroy() clear_target() @@ -175,42 +160,57 @@ hub = null return ..() -/proc/find_loc(obj/R) - if (!R) return null - var/turf/T = R.loc - while(!istype(T, /turf)) - T = T.loc - if(!T || istype(T, /area)) return null - return T - /obj/machinery/teleport name = "teleport" icon = 'icons/obj/machines/teleporter.dmi' - density = 1 - anchored = 1.0 - var/lockeddown = 0 - + density = TRUE + anchored = TRUE /obj/machinery/teleport/hub - name = "teleporter hub" - desc = "The teleporter hub handles all of the impossibly complex busywork required in instant matter transmission." - icon_state = "tele0" - dir = EAST + name = "teleporter pad" + desc = "The teleporter pad handles all of the impossibly complex busywork required in instant matter transmission." + icon_state = "pad" idle_power_usage = 10 active_power_usage = 2000 + light_color = "#02d1c7" var/obj/machinery/computer/teleporter/com +/obj/machinery/teleport/hub/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD // Hub sometimes initializes before stations and computers which mucks with icon update + +/obj/machinery/teleport/hub/LateInitialize() + . = ..() + queue_icon_update() + +/obj/machinery/teleport/hub/on_update_icon() + z_flags &= ~ZMM_MANGLE_PLANES + cut_overlays() + if (com?.station?.engaged) + add_overlay(emissive_overlay(icon, "[initial(icon_state)]_active_overlay")) + z_flags |= ZMM_MANGLE_PLANES + set_light(4, 0.4) + else + set_light(0) + if(operable()) + add_overlay(emissive_overlay(icon, "[initial(icon_state)]_idle_overlay")) + z_flags |= ZMM_MANGLE_PLANES + /obj/machinery/teleport/hub/Bumped(var/atom/movable/M) - spawn() - if (src.icon_state == "tele1") - teleport(M) - use_power_oneoff(5000) + if (com?.station?.engaged) + teleport(M) + use_power_oneoff(5000) /obj/machinery/teleport/hub/proc/teleport(atom/movable/M) + if (!com) + return do_teleport(M, com.locked) if(com.one_time_use) //Make one-time-use cards only usable one time! - com.one_time_use = 0 + com.one_time_use = FALSE com.locked = null + if (com.station) + com.station.engaged = FALSE + queue_icon_update() return /obj/machinery/teleport/hub/Destroy() @@ -220,16 +220,36 @@ /obj/machinery/teleport/station name = "projector" desc = "This machine is capable of projecting a miniature wormhole leading directly to its provided target." - icon_state = "controller" - dir = EAST - var/engaged = 0 + icon_state = "station" + var/engaged = FALSE idle_power_usage = 10 active_power_usage = 2000 var/obj/machinery/computer/teleporter/com var/obj/machinery/teleport/hub/hub -/obj/machinery/teleport/station/attackby(var/obj/item/W, var/mob/user) - attack_hand(user) +/obj/machinery/teleport/station/Initialize() + . = ..() + for (var/target_dir in global.cardinal) + var/obj/machinery/teleport/hub/found_pad = locate() in get_step(src, target_dir) + if(found_pad) + set_dir(get_dir(src, found_pad)) + break + queue_icon_update() + +/obj/machinery/teleport/station/on_update_icon() + . = ..() + cut_overlays() + if (engaged) + add_overlay(emissive_overlay(icon, "[initial(icon_state)]_active_overlay")) + z_flags |= ZMM_MANGLE_PLANES + else if (operable()) + add_overlay(emissive_overlay(icon, "[initial(icon_state)]_idle_overlay")) + z_flags |= ZMM_MANGLE_PLANES + else + z_flags &= ~ZMM_MANGLE_PLANES + +/obj/machinery/teleport/station/attackby(var/obj/item/used_item, var/mob/user) + return attack_hand_with_interaction_checks(user) || ..() /obj/machinery/teleport/station/interface_interact(var/mob/user) if(!CanInteract(user, DefaultTopicState())) @@ -254,25 +274,27 @@ audible_message("Failure: Unable to establish connection to provided coordinates. Please reinstate coordinate matrix.") return + engaged = TRUE + queue_icon_update() if (hub) - hub.icon_state = "tele1" + hub.queue_icon_update() use_power_oneoff(5000) update_use_power(POWER_USE_ACTIVE) hub.update_use_power(POWER_USE_ACTIVE) audible_message("Teleporter engaged!") - src.engaged = 1 return /obj/machinery/teleport/station/proc/disengage() if(stat & BROKEN) return + engaged = FALSE + queue_icon_update() if (hub) - hub.icon_state = "tele0" + hub.queue_icon_update() hub.update_use_power(POWER_USE_IDLE) update_use_power(POWER_USE_IDLE) audible_message("Teleporter disengaged!") - src.engaged = 0 return /obj/machinery/teleport/station/Destroy() @@ -285,9 +307,3 @@ . = ..() if (engaged && (stat & NOPOWER)) disengage() - -/obj/machinery/teleport/station/on_update_icon() - if(stat & NOPOWER) - icon_state = panel_open ? "controller-o" : "controller-p" - else - icon_state = "controller" diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm index 2dc02199a7ed..c91249ac56d6 100644 --- a/code/game/machinery/turret_control.dm +++ b/code/game/machinery/turret_control.dm @@ -11,13 +11,15 @@ desc = "Used to control a room's automated defenses." icon = 'icons/obj/machines/turret_control.dmi' icon_state = "control_standby" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + var/enabled = 0 var/lethal = 0 var/locked = 1 var/area/control_area //can be area name, path or nothing. - var/mob/living/silicon/ai/master_ai var/check_arrest = 1 //checks if the perp is set to arrest var/check_records = 1 //checks if a security record exists at all @@ -49,7 +51,7 @@ if(!control_area) control_area = get_area(src) else if(istext(control_area)) - for(var/area/A in world) + for(var/area/A in global.areas) if(A.name && A.name==control_area) control_area = A break @@ -69,11 +71,6 @@ to_chat(user, "There seems to be a firewall preventing you from accessing this device.") return 1 - if(malf_upgraded && master_ai) - if((user == master_ai) || (user in master_ai.connected_robots)) - return 0 - return 1 - if(locked && !issilicon(user)) to_chat(user, "Access denied.") return 1 @@ -86,18 +83,18 @@ return ..() -/obj/machinery/turretid/attackby(obj/item/W, mob/user) +/obj/machinery/turretid/attackby(obj/item/used_item, mob/user) if(stat & BROKEN) - return + return FALSE - if(istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer)) - if(src.allowed(usr)) + if(istype(used_item, /obj/item/card/id)||istype(used_item, /obj/item/modular_computer)) + if(src.allowed(user)) if(emagged) to_chat(user, "The turret control is unresponsive.") else locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] the panel.") - return + return TRUE return ..() /obj/machinery/turretid/emag_act(var/remaining_charges, var/mob/user) @@ -138,10 +135,9 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/turretid/Topic(href, href_list) - if(..()) - return 1 - +/obj/machinery/turretid/OnTopic(mob/user, href_list) + if((. = ..())) + return if(href_list["command"] && href_list["value"]) var/log_action = null @@ -169,10 +165,10 @@ check_anomalies = value if(!isnull(log_action)) - log_and_message_admins("has [log_action]", 1) + log_and_message_admins("has [log_action]", user, loc) updateTurrets() - return 1 + return TOPIC_REFRESH /obj/machinery/turretid/proc/updateTurrets() var/datum/turret_checks/TC = new @@ -200,13 +196,13 @@ else if (enabled) if (lethal) icon_state = "control_kill" - set_light(1, 0.5, 2, 2, "#990000") + set_light(1.5, 1,COLOR_BLOOD_RED) else icon_state = "control_stun" - set_light(1, 0.5, 2, 2, "#ff9900") + set_light(1.5, 1,"#ff9900") else icon_state = "control_standby" - set_light(1, 0.5, 2, 2, "#003300") + set_light(1.5, 1,"#003300") /obj/machinery/turretid/emp_act(severity) if(enabled) @@ -230,13 +226,3 @@ updateTurrets() ..() - - -/obj/machinery/turretid/malf_upgrade(var/mob/living/silicon/ai/user) - ..() - malf_upgraded = 1 - locked = 1 - ailock = 0 - to_chat(user, "\The [src] has been upgraded. It has been locked and can not be tampered with by anyone but you and your cyborgs.") - master_ai = user - return 1 \ No newline at end of file diff --git a/code/game/machinery/turrets/_turrets.dm b/code/game/machinery/turrets/_turrets.dm new file mode 100644 index 000000000000..8fe7e01dc0d6 --- /dev/null +++ b/code/game/machinery/turrets/_turrets.dm @@ -0,0 +1,539 @@ +#define TURRET_WAIT 2 +// Base type for rewritten turrets, designed to hopefully be cleaner and more fun to use and fight against. +// Use the subtypes for 'real' turrets. + +/obj/machinery/turret + name = "abstract turret" + icon = 'icons/obj/turrets.dmi' + icon_state = "turret_barrel" + base_type = /obj/machinery/turret + anchored = TRUE + density = TRUE + idle_power_usage = 500 + active_power_usage = 10 KILOWATTS + interact_offline = TRUE + transform_animate_time = 0.2 SECONDS + uncreated_component_parts = list(/obj/item/stock_parts/power/apc) + abstract_type = /obj/machinery/turret + + // Visuals. + var/image/turret_stand = null + var/image/turret_ray = null + var/ray_color = "#ffffffff" // Color of the ray, changed by the FSM when switching states. + var/image/transverse_left // Images for displaying the range of the turret's transverse + var/image/transverse_right + + // Shooting + var/obj/item/gun/installed_gun = /obj/item/gun/energy/laser/practice // Instance of the gun inside the turret. + var/gun_looting_prob = 25 // If the turret dies and then is disassembled, this is the odds of getting the gun. + var/reloading_progress = 0 + var/reloading_speed = 50 + + // Power + var/enabled = TRUE // If false, turret turns off. + + // Angles + // Remember that in BYOND, NORTH equals 0 absolute degrees, and not 90. + var/traverse = 180 // Determines how wide the turret can turn to shoot things, in degrees. The 'front' of the turret is determined by its dir variable. + var/leftmost_traverse = null // How far left or right the turret can turn. Set automatically using the above variable and the inital dir value. + var/rightmost_traverse = null + var/current_bearing = 0 // Current absolute angle the turret has, used to calculate if it needs to turn to try to shoot the target. + var/target_bearing = 0 // The desired bearing. If the current bearing is too far from this, the turret will turn towards it until within tolerence. + var/bearing_tolerence = 3 // Degrees that the turret must be within to be able to shoot at the target. + var/turning_rate = 90 // Degrees per second. + var/default_bearing = null // If no target is found, the turret will return to this bearing automatically. + + // Detection. + var/datum/proximity_trigger/angle/proximity + var/vision_range = 7 // How many tiles away the turret can see. Values higher than 7 will let the turret shoot offscreen, which might be unsporting. + // Higher values may also have a performance cost. + + // Logic + var/datum/state_machine/turret/state_machine = null + var/weakref/target = null + var/list/potential_targets = list() + var/timer_id = null + var/decl/hostility/hostility = /decl/hostility/turret + +/obj/machinery/turret/Initialize() + if(ispath(installed_gun)) + installed_gun = new installed_gun(src) + setup_gun() + if(ispath(hostility)) + hostility = GET_DECL(hostility) + + state_machine = add_state_machine(src, /datum/state_machine/turret) + + target_bearing = dir2angle(dir) + set_bearing(target_bearing) + calculate_traverse() + + proximity = new(src, + /obj/machinery/turret/proc/on_proximity, + /obj/machinery/turret/proc/on_changed_turf_visibility, + vision_range, + PROXIMITY_EXCLUDE_HOLDER_TURF, + src, + leftmost_traverse, + rightmost_traverse + ) + proximity.register_turfs() + + update_icon() + return ..() + +/obj/machinery/turret/Destroy() + remove_state_machine(src, /datum/state_machine/turret) + deltimer(timer_id) + + QDEL_NULL(state_machine) + QDEL_NULL(proximity) + QDEL_NULL(installed_gun) + + turret_stand = null + turret_ray = null + transverse_left = null + transverse_right = null + + target = null + potential_targets.Cut() + + hostility = null + + return ..() + +/obj/machinery/turret/dismantle() + // If the gun doesn't drop, it will be qdel'd in Destroy() + if(installed_gun && prob(gun_looting_prob)) + installed_gun.dropInto(loc) + installed_gun = null + + return ..() + +/obj/machinery/turret/physically_destroyed(skip_qdel) + if(installed_gun && prob(gun_looting_prob)) + installed_gun.dropInto(loc) + installed_gun = null + + return ..() + +// Handles charging the powercell of an installed energy weapon. +/obj/machinery/turret/Process() + if(istype(installed_gun, /obj/item/gun/energy)) + var/obj/item/gun/energy/energy_gun = installed_gun + var/obj/item/cell/power_supply = energy_gun.get_cell() + if(power_supply && !power_supply.fully_charged()) + power_supply.give(active_power_usage*CELLRATE) + update_use_power(POWER_USE_ACTIVE) + return + update_use_power(POWER_USE_IDLE) + +/obj/machinery/turret/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/gun) && !installed_gun) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, SPAN_NOTICE("You install \the [used_item] into \the [src]!")) + installed_gun = used_item + setup_gun() + return TRUE + + if(istype(used_item, /obj/item/ammo_magazine) || istype(used_item, /obj/item/ammo_casing)) + var/obj/item/stock_parts/ammo_box/ammo_box = get_component_of_type(/obj/item/stock_parts/ammo_box) + if(istype(ammo_box)) + return ammo_box.attackby(used_item, user) + . = ..() + +// This is called after the gun gets instantiated or slotted in. +/obj/machinery/turret/proc/setup_gun() + +// State machine processing steps, called by looping timer +/obj/machinery/turret/proc/process_turning() + var/distance_from_target_bearing = get_distance_from_target_bearing() + + var/turn_rate = calculate_turn_rate_per_process() + + var/distance_this_step = clamp(distance_from_target_bearing, -turn_rate, turn_rate) + + if(!angle_within_traverse(current_bearing + distance_this_step)) + distance_this_step = 0 + + set_bearing(current_bearing + distance_this_step) + state_machine.evaluate() + +/obj/machinery/turret/proc/process_shooting() + if(operable()) + if(installed_gun && is_valid_target(target?.resolve())) + var/atom/resolved_target = target.resolve() + if(istype(resolved_target)) + addtimer(CALLBACK(src, PROC_REF(fire_weapon), resolved_target), 0) + else + target = null + state_machine.evaluate() + +/obj/machinery/turret/proc/fire_weapon(atom/resolved_target) + installed_gun?.Fire(resolved_target, src) + +/obj/machinery/turret/proc/process_reloading() + if(istype(installed_gun, /obj/item/gun/projectile)) + if(reloading_progress >= 100) + var/obj/item/gun/projectile/proj_gun = installed_gun + var/obj/item/ammo_magazine/stored_magazine = proj_gun.ammo_magazine + + if(proj_gun.is_jammed) + proj_gun.is_jammed = FALSE + playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) + reloading_progress = 0 + + else if(stored_magazine && stored_magazine.get_stored_ammo_count() < stored_magazine.max_ammo) + var/obj/item/stock_parts/ammo_box/ammo_box = get_component_of_type(/obj/item/stock_parts/ammo_box) + if(ammo_box?.is_functional() && ammo_box.stored_caliber == proj_gun.caliber) + var/obj/item/ammo_casing/casing = ammo_box.remove_ammo(stored_magazine) + if(casing) + stored_magazine.stored_ammo += casing + reloading_progress = 0 + else + reloading_progress += reloading_speed + + state_machine.evaluate() + +/obj/machinery/turret/proc/process_idle() + if(!isnull(default_bearing) && (target_bearing != default_bearing) && angle_within_traverse(default_bearing)) + target_bearing = default_bearing + + state_machine.evaluate() + +// Calculates the turret's leftmost and rightmost angles from the turret's direction and traverse. +/obj/machinery/turret/proc/calculate_traverse() + if(traverse >= 360) + leftmost_traverse = 0 + rightmost_traverse = 0 + else + var/half_arc = traverse / 2 + leftmost_traverse = SIMPLIFY_DEGREES(dir2angle(dir) - half_arc) + rightmost_traverse = SIMPLIFY_DEGREES(dir2angle(dir) + half_arc) + + if(istype(proximity)) + proximity.l_angle_ = leftmost_traverse + proximity.r_angle_ = rightmost_traverse + + proximity.register_turfs() + + cut_overlay(list(transverse_right, transverse_left)) + transverse_left = null + transverse_right = null + update_icon() + +// Returns TRUE if the input is within the two angles that determine the traverse. +/obj/machinery/turret/proc/angle_within_traverse(angle) + if(traverse >= 360) + return TRUE + return angle_between_two_angles(leftmost_traverse, angle, rightmost_traverse) + +/obj/machinery/turret/set_dir(ndir) + . = ..() + calculate_traverse() + +// Instantly turns the turret to a specific absolute angle. +/obj/machinery/turret/proc/set_bearing(new_angle) + current_bearing = SIMPLIFY_DEGREES(new_angle) + set_rotation(current_bearing) // Turn the sprite. + +// Gives a new target bearing, if the turret's capable of turning to it. +/obj/machinery/turret/proc/set_target_bearing(new_angle) + new_angle = SIMPLIFY_DEGREES(new_angle) + if(angle_within_traverse(new_angle)) + target_bearing = new_angle + +// Turret turning calculations +#define TURN_CLOCKWISE 1 +#define TURN_COUNTERCLOCKWISE -1 +// Returns the signed distance from the target bearing +/obj/machinery/turret/proc/get_distance_from_target_bearing() + var/raw_distance = target_bearing - current_bearing + if(traverse < 360) + if(SIMPLIFY_DEGREES(target_bearing - current_bearing) <= SIMPLIFY_DEGREES(rightmost_traverse - current_bearing)) + return SIMPLIFY_DEGREES(raw_distance*TURN_CLOCKWISE) + else if(SIMPLIFY_DEGREES(current_bearing - target_bearing) <= SIMPLIFY_DEGREES(current_bearing - leftmost_traverse)) + return SIMPLIFY_DEGREES(raw_distance*TURN_COUNTERCLOCKWISE) + return 0 + + // The turret can traverse the entire circle, so it must decide which direction is a shorter distance. + return closer_angle_difference(current_bearing, target_bearing) + +/obj/machinery/turret/proc/within_bearing() + var/distance_from_target_bearing = closer_angle_difference(current_bearing, target_bearing) + return abs(distance_from_target_bearing) <= bearing_tolerence + +#undef TURN_CLOCKWISE +#undef TURN_COUNTERCLOCKWISE + +/obj/machinery/turret/proc/calculate_turn_rate_per_process() + return turning_rate / (1 SECOND / TURRET_WAIT) + +// Turret proximity handling +/obj/machinery/turret/proc/on_proximity(atom/movable/AM) + if(inoperable()) // Should be handled by the state machine, but just in case. + return + if(target?.resolve() == AM) + track_target() + else + add_target(AM) + +/obj/machinery/turret/proc/on_changed_turf_visibility(list/prior_turfs, list/current_turfs) + // When a door opens etc. immediately check the newly visible turfs for targets. + + // Don't perform this check on spawn + if(!length(prior_turfs)) + return + if(inoperable() || QDELETED(src)) + return + var/list/turfs_to_check = current_turfs - prior_turfs + for(var/turf/T as anything in turfs_to_check) + for(var/atom/movable/AM in T) + on_proximity(AM) + +// Turret targeting +/obj/machinery/turret/proc/can_be_hostile_to(atom/potential_target) + return hostility?.can_target(src, potential_target) + +/obj/machinery/turret/proc/set_target(atom/new_target) + if(is_valid_target(new_target)) + target = weakref(new_target) + set_target_bearing(Get_Angle(src, target.resolve())) + +/obj/machinery/turret/proc/is_valid_target(atom/A) + if(!istype(A)) + return FALSE + if(!angle_within_traverse(Get_Angle(src, A))) + return FALSE + if(!can_be_hostile_to(A)) + return FALSE + if(!(get_turf(A) in proximity.seen_turfs_)) + return FALSE + return TRUE + +/obj/machinery/turret/proc/find_target() + if(is_valid_target(target?.resolve())) + set_target_bearing(Get_Angle(src, target.resolve())) + return target + + else if(length(potential_targets)) + while(length(potential_targets)) + var/weakref/target_ref = potential_targets[1] + potential_targets -= target_ref + if(is_valid_target(target_ref.resolve())) + target = target_ref + track_target() + return target_ref + + target = null + return null + +/obj/machinery/turret/proc/add_target(atom/A) + if(is_valid_target(A)) + if(!target) + target = weakref(A) + track_target() + else + potential_targets |= weakref(A) + + return TRUE + return FALSE + +/obj/machinery/turret/proc/track_target() + set_target_bearing(Get_Angle(src, target.resolve())) + state_machine.evaluate() + +// Returns whether the turret should reload at the moment. If a valid target is in sight, only reloads the minimum amount to shoot again. +/obj/machinery/turret/proc/should_reload() + if(istype(installed_gun, /obj/item/gun/projectile)) + var/obj/item/gun/projectile/proj_gun = installed_gun + if(proj_gun.load_method & MAGAZINE) + var/obj/item/stock_parts/ammo_box/ammo_box = get_component_of_type(/obj/item/stock_parts/ammo_box) + if(!ammo_box || !ammo_box.is_functional()) + return FALSE + // Since the ammo boxes caliber is null if it is unloaded, this also checks for an empty ammo box. + if(ammo_box.stored_caliber != proj_gun.caliber) + return FALSE + if(proj_gun.is_jammed) + return TRUE + if(proj_gun.ammo_magazine) + var/ammo_remaining = proj_gun.getAmmo() // Counts ammo in the chamber as well. + // Only reload the magazine if we're completely out of ammo or we don't have a target. + if(ammo_remaining == 0) + return TRUE + if(!is_valid_target(target?.resolve()) && proj_gun.ammo_magazine.get_stored_ammo_count() != proj_gun.ammo_magazine.max_ammo) + return TRUE + return FALSE + +/obj/machinery/turret/emag_act(remaining_charges, mob/user, emag_source) + if(!emagged) + emagged = TRUE + to_chat(user, SPAN_WARNING("You short out \the [src]'s threat assessment circuits.")) + visible_message("\The [src] hums oddly...") + enabled = FALSE + addtimer(CALLBACK(src, PROC_REF(emagged_targeting)), 6 SECONDS) + state_machine.evaluate() + +/obj/machinery/turret/proc/emagged_targeting() + hostility = GET_DECL(/decl/hostility) // Shoots almost everyone. + enabled = TRUE + state_machine.evaluate() + +/obj/machinery/turret/power_change() + . = ..() + state_machine.evaluate() + +/obj/machinery/turret/on_component_failure() + ..() + state_machine.evaluate() + +/obj/machinery/turret/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = TRUE) + var/data[0] + data["enabled"] = enabled + data["weaponName"] = installed_gun ? installed_gun.name : null + data["currentBearing"] = current_bearing + + if(LAZYLEN(installed_gun?.firemodes)) + var/fm_index = 1 + var/list/fm_data = list() + for(var/datum/firemode/fm in installed_gun.firemodes) + fm_data.Add(list(list( + "name" = fm.name, + "index" = fm_index, + "selected" = installed_gun.sel_mode == fm_index + ))) + fm_index += 1 + data["firemodes"] = fm_data + data["weaponHasFiremodes"] = installed_gun ? LAZYLEN(installed_gun.firemodes) : 0 + data["defaultBearing"] = isnull(default_bearing) ? "None" : default_bearing + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "turret.tmpl", "Turret Controls", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/turret/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["set_enabled"]) + toggle_enabled() + return TOPIC_REFRESH + + if(href_list["adjust_bearing"]) + var/amount = text2num(href_list["adjust_bearing"]) + if(!amount) + return TOPIC_NOACTION + set_target_bearing(target_bearing + amount) + state_machine.evaluate() + return TOPIC_REFRESH + + if(href_list["set_bearing"]) + var/amount = input(user, "Input an angle between [leftmost_traverse] and [rightmost_traverse] degrees.", "Set Bearing", target_bearing) as null|num + if(!isnull(amount)) + set_target_bearing(amount) + state_machine.evaluate() + return TOPIC_REFRESH + + if(href_list["set_default"]) + var/leftmost_default = leftmost_traverse + var/rightmost_default = rightmost_traverse + if(traverse >= 360) + leftmost_default = 0 + rightmost_default = 360 + var/amount = input(user, "Input an angle between [leftmost_default] and [rightmost_default] degrees. Click cancel to disable default.", "Set Default Bearing", default_bearing) as null|num + if(isnum(amount)) + default_bearing = clamp(amount, leftmost_default, rightmost_default) + else + default_bearing = null + return TOPIC_REFRESH + + if(href_list["manual_fire"]) + if(installed_gun) + var/turf/T = get_turf_from_angle(x, y, z, current_bearing, vision_range) + if(!T) + return TOPIC_NOACTION + installed_gun.Fire(T, src) + return TOPIC_REFRESH + + if(href_list["switch_firemode"]) + + if(change_firemode(text2num(href_list["switch_firemode"]))) + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(href_list["eject_gun"]) + if(installed_gun) + if(!CanPhysicallyInteractWith(user, src)) + to_chat(user, SPAN_WARNING("You cannot eject the weapon from \the [src] remotely!")) + return TOPIC_HANDLED + installed_gun.forceMove(get_turf(src)) + installed_gun = null + + return TOPIC_REFRESH + +/obj/machinery/turret/proc/toggle_enabled() + enabled = !enabled + state_machine.evaluate() + return TRUE + +/obj/machinery/turret/proc/change_firemode(firemode_index) + if(!installed_gun || !LAZYLEN(installed_gun.firemodes)) + return FALSE + if(firemode_index > LAZYLEN(installed_gun.firemodes) || firemode_index == installed_gun.sel_mode) + return FALSE + + installed_gun.switch_firemodes(firemode_index) + return TRUE + +/obj/machinery/turret/on_update_icon() + if(!turret_stand) + turret_stand = image(icon, "turretCover") + turret_stand.layer = src.layer - 0.02 + turret_stand.appearance_flags |= KEEP_APART|RESET_TRANSFORM|TILE_BOUND + add_overlay(turret_stand) + + if(!turret_ray) + turret_ray = image(icon, "turret_ray") + turret_ray.plane = ABOVE_LIGHTING_PLANE + turret_ray.appearance_flags |= KEEP_APART|RESET_COLOR|TILE_BOUND + turret_ray.mouse_opacity = FALSE + + var/matrix/M = matrix(turret_ray.transform) + // Offset away from the parent, so that when the parent rotates, this rotates with it correctly. + M.Translate(0, (1 * WORLD_ICON_SIZE * 0.50)+4) + M.Scale(1, 4) + turret_ray.transform = M + add_overlay(turret_ray) + + if(!transverse_left && leftmost_traverse) + transverse_left = image(icon, "transverse_indicator_left") + transverse_left.layer = src.layer - 0.01 + transverse_left.appearance_flags |= KEEP_APART|RESET_TRANSFORM|TILE_BOUND + + // Rotate according to transverse + var/matrix/M = matrix(transverse_left.transform) + M.Turn(leftmost_traverse) + transverse_left.transform = M + add_overlay(transverse_left) + + if(!transverse_right && rightmost_traverse) + transverse_right = image(icon, "transverse_indicator_right") + transverse_right.layer = src.layer - 0.01 + transverse_right.appearance_flags |= KEEP_APART|RESET_TRANSFORM|TILE_BOUND + + // Rotate according to transverse + var/matrix/M = matrix(transverse_right.transform) + M.Turn(rightmost_traverse) + transverse_right.transform = M + add_overlay(transverse_right) + + // Changes the ray color based on state. + cut_overlay(turret_ray) + turret_ray.color = ray_color + add_overlay(turret_ray) + return ..() \ No newline at end of file diff --git a/code/game/machinery/turrets/network_turret.dm b/code/game/machinery/turrets/network_turret.dm new file mode 100644 index 000000000000..110daa4e9487 --- /dev/null +++ b/code/game/machinery/turrets/network_turret.dm @@ -0,0 +1,153 @@ +#define MAX_TURRET_LOGS 50 +// Standard buildable model of turret. +/obj/machinery/turret/network + name = "sentry turret" + desc = "An automatic turret capable of identifying and dispatching targets using a mounted firearm." + + idle_power_usage = 5 KILOWATTS + active_power_usage = 5 KILOWATTS // Determines how fast energy weapons can be recharged, so highly values are better. + + reloading_speed = 10 + + installed_gun = null + gun_looting_prob = 100 + + traverse = 360 + turning_rate = 270 + + base_type = /obj/machinery/turret/network + construct_state = /decl/machine_construction/default/panel_closed + stat_immune = NOSCREEN | NOINPUT + + hostility = /decl/hostility/turret/network + + // Targeting modes. + var/check_access = FALSE + var/check_weapons = FALSE + var/check_records = FALSE + var/check_arrest = FALSE + var/check_lifeforms = FALSE + + var/list/logs + +/obj/machinery/turret/network/Initialize() + . = ..() + set_extension(src, /datum/extension/network_device/sentry_turret) + +/obj/machinery/turret/network/attackby(obj/item/used_item, mob/user) + . = ..() + if(istype(used_item, /obj/item/stock_parts/computer/hard_drive/portable)) + if(!check_access(user)) + to_chat(user, SPAN_WARNING("\The [src] flashes a red light: you lack access to download its logfile.")) + return + var/obj/item/stock_parts/computer/hard_drive/portable/drive = used_item + var/datum/computer_file/data/logfile/turret_log = prepare_log_file() + if(drive.store_file(turret_log) == OS_FILE_SUCCESS) + to_chat(user, SPAN_NOTICE("\The [src] flashes a blue light as it downloads its log file onto \the [drive]!")) + else + to_chat(user, SPAN_WARNING("\The [src] flashes a red light: it failed to download its log file onto \the [drive]. Maybe it's full?")) + +/obj/machinery/turret/network/RefreshParts() + . = ..() + active_power_usage = 5*clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 1, 5) KILOWATTS + reloading_speed = 10*clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 1, 5) + + var/new_range = clamp(total_component_rating_of_type(/obj/item/stock_parts/scanning_module)*3, 4, 8) + if(vision_range != new_range) + vision_range = new_range + proximity?.set_range(vision_range) + +/obj/machinery/turret/network/proc/add_log(var/log_string) + LAZYADD(logs, "([stationtime2text()], [stationdate2text()]) [log_string]") + if(LAZYLEN(logs) > MAX_TURRET_LOGS) + LAZYREMOVE(logs, LAZYACCESS(logs, 1)) + +/obj/machinery/turret/network/proc/prepare_log_file() + var/datum/extension/network_device/turret = get_extension(src, /datum/extension/network_device) + var/device_tag = turret.network_tag + var/datum/computer_file/data/logfile/turret_log = new() + turret_log.filename = "[device_tag]" + turret_log.stored_data = "\[b\]Logfile of turret [device_tag]\[/b\]\[BR\]" + for(var/log_string in logs) + turret_log.stored_data += "[log_string]\[BR\]" + turret_log.calculate_size() + + return turret_log + +/obj/machinery/turret/network/add_target(atom/A) + . = ..() + if(.) + add_log("Target Engaged: \the [A]") + +/obj/machinery/turret/network/toggle_enabled() + . = ..() + if(.) + add_log("Turret was [enabled ? "enabled" : "disabled"]") + +/obj/machinery/turret/network/change_firemode(firemode_index) + . = ..() + if(.) + if(installed_gun && length(installed_gun.firemodes)) + var/datum/firemode/current_mode = installed_gun.firemodes[firemode_index] + add_log("Turret firing mode changed to [current_mode.name]") + +/obj/machinery/turret/network/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, datum/topic_state/state = global.default_topic_state) + var/data = list() + data["network"] = TRUE + data["enabled"] = enabled + data["weaponName"] = installed_gun ? installed_gun.name : null + data["currentBearing"] = current_bearing + data["weaponHasFiremodes"] = installed_gun ? LAZYLEN(installed_gun.firemodes) : 0 + data["defaultBearing"] = isnull(default_bearing) ? "None" : default_bearing + + var/list/settings = list() + settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) + settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records) + settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest) + settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access) + settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_lifeforms", "value" = check_lifeforms) + + data["settings"] = settings + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + ui = new(user, src, ui_key, "turret.tmpl", "Turret Controls", 600, 600, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/turret/network/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["settings"]) + var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device) + device?.ui_interact(user, state = state) + return TOPIC_REFRESH + + if(href_list["targeting_comm"] && href_list["targeting_value"]) + var/targeting_bool = text2num(href_list["targeting_value"]) + switch(href_list["targeting_comm"]) + if("check_weapons") + check_weapons = targeting_bool + if("check_records") + check_records = targeting_bool + if("check_arrest") + check_arrest = targeting_bool + if("check_access") + check_access = targeting_bool + if("check_lifeforms") + check_lifeforms = targeting_bool + return TOPIC_REFRESH + return ..() + +/datum/extension/network_device/sentry_turret + +/obj/item/stock_parts/circuitboard/sentry_turret + name = "circuitboard (sentry turret)" + board_type = "machine" + build_path = /obj/machinery/turret/network + origin_tech = @'{"programming":5,"combat":5,"engineering":4}' + req_components = list( + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/manipulator = 2) + +#undef MAX_TURRET_LOGS \ No newline at end of file diff --git a/code/game/machinery/turrets/turret_ammo.dm b/code/game/machinery/turrets/turret_ammo.dm new file mode 100644 index 000000000000..656d35162e5e --- /dev/null +++ b/code/game/machinery/turrets/turret_ammo.dm @@ -0,0 +1,85 @@ +/obj/item/stock_parts/ammo_box + name = "ammunition supply" + desc = "A high capacity ammunition supply designed to mechanically reload magazines with bullets." + icon = 'icons/obj/items/storage/ammobox.dmi' + icon_state = "ammo" + origin_tech = @'{"engineering":3,"combat":4}' + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/metal/brass = MATTER_AMOUNT_REINFORCEMENT, + ) + var/list/stored_ammo = list() + var/stored_caliber = null + + var/max_ammo = 50 + +/obj/item/stock_parts/ammo_box/Destroy() + QDEL_NULL_LIST(stored_ammo) + . = ..() + +/obj/item/stock_parts/ammo_box/attackby(obj/item/used_item, mob/user) + . = ..() + if(IS_SCREWDRIVER(used_item)) + to_chat(user, SPAN_NOTICE("You dump the ammo stored in \the [src] on the ground.")) + for(var/obj/item/ammo_casing/casing as anything in stored_ammo) + casing.forceMove(get_turf(src)) + stored_ammo -= casing + + stored_caliber = null + return TRUE + + if(istype(used_item, /obj/item/ammo_casing)) + var/obj/item/ammo_casing/casing = used_item + if(stored_caliber && casing.caliber != stored_caliber) + to_chat(user, SPAN_WARNING("The caliber of \the [casing] does not match the caliber stored in \the [src]!")) + return TRUE + if(length(stored_ammo) >= max_ammo) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return TRUE + + casing.forceMove(src) + stored_ammo += casing + stored_caliber = casing.caliber + + to_chat(user, SPAN_NOTICE("You insert \the [casing] into \the [src].")) + playsound(user, 'sound/weapons/guns/interaction/bullet_insert.ogg', 50, 1) + return TRUE + + if(istype(used_item, /obj/item/ammo_magazine)) + var/obj/item/ammo_magazine/magazine = used_item + if(stored_caliber && magazine.caliber != stored_caliber) + to_chat(user, SPAN_WARNING("The caliber of \the [magazine] does not match the caliber stored in \the [src]!")) + return TRUE + if(!magazine.get_stored_ammo_count()) + to_chat(user, SPAN_WARNING("\The [magazine] is empty!")) + return TRUE + if(length(stored_ammo) >= max_ammo) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return TRUE + + stored_caliber = magazine.caliber + magazine.create_initial_contents() + for(var/obj/item/ammo_casing/casing in magazine.stored_ammo) + // Just in case. + if(casing.caliber != stored_caliber) + continue + casing.forceMove(src) + magazine.stored_ammo -= casing + stored_ammo += casing + if(length(stored_ammo) >= max_ammo) + break + + to_chat(user, SPAN_NOTICE("You fill \the [src] [length(stored_ammo) == max_ammo ? "to capacity with" : "with the ammo stored in"] \the [magazine]")) + playsound(user, 'sound/weapons/guns/interaction/bullet_insert.ogg', 50, 1) + magazine.on_update_icon() + return TRUE + +/obj/item/stock_parts/ammo_box/proc/remove_ammo(var/atom/destination) + if(length(stored_ammo)) + var/obj/item/ammo_casing/casing = stored_ammo[1] + stored_ammo -= casing + casing.forceMove(destination) + if(!length(stored_ammo)) + stored_caliber = null + + return casing \ No newline at end of file diff --git a/code/game/machinery/turrets/turret_fsm.dm b/code/game/machinery/turrets/turret_fsm.dm new file mode 100644 index 000000000000..2888df30ea09 --- /dev/null +++ b/code/game/machinery/turrets/turret_fsm.dm @@ -0,0 +1,119 @@ +/datum/state_machine/turret + current_state = /decl/state/turret/idle + expected_type = /obj/machinery/turret + base_type = /datum/state_machine/turret + +/decl/state/turret + var/ray_color = "#ffffffff" // Turrets have a visual indicator of their current state. + var/switched_to_sound = null + + var/timer_proc = null + var/timer_wait = TURRET_WAIT + +/decl/state/turret/entered_state(obj/machinery/turret/turret) + turret.ray_color = src.ray_color + turret.update_icon() + if(switched_to_sound) + playsound(turret, switched_to_sound, 40, TRUE) + if(timer_proc) + turret.timer_id = addtimer(CALLBACK(turret, timer_proc), timer_wait, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_LOOP|TIMER_OVERRIDE) + +/decl/state/turret/exited_state(obj/machinery/turret/turret) + if(timer_proc && turret.timer_id) + deltimer(turret.timer_id) + turret.timer_id = null +/decl/state/turret/idle + ray_color = "#00ff00ff" + switched_to_sound = 'sound/machines/triple_beep.ogg' + // Timer for returning to default bearing. + timer_proc = /obj/machinery/turret/proc/process_idle + timer_wait = 5 SECONDS + + transitions = list( + /decl/state_transition/turret/lost_power, + /decl/state_transition/turret/reload, + /decl/state_transition/turret/shoot, + /decl/state_transition/turret/turn_to_bearing + ) + +/decl/state/turret/turning + ray_color = "#ffff00ff" + switched_to_sound = 'sound/machines/quiet_beep.ogg' + timer_proc = /obj/machinery/turret/proc/process_turning + transitions = list( + /decl/state_transition/turret/lost_power, + /decl/state_transition/turret/reload, + /decl/state_transition/turret/shoot, + /decl/state_transition/turret/no_enemies + ) + +/decl/state/turret/engaging + ray_color = "#ff0000ff" + switched_to_sound = 'sound/machines/buttonbeep.ogg' + timer_proc = /obj/machinery/turret/proc/process_shooting + transitions = list( + /decl/state_transition/turret/lost_power, + /decl/state_transition/turret/reload, + /decl/state_transition/turret/turn_to_bearing, + /decl/state_transition/turret/no_enemies + ) + +/decl/state/turret/reloading + ray_color = "#ffa600ff" + switched_to_sound = 'sound/weapons/guns/interaction/rifle_load.ogg' + timer_proc = /obj/machinery/turret/proc/process_reloading + transitions = list( + /decl/state_transition/turret/lost_power, + /decl/state_transition/turret/shoot, + /decl/state_transition/turret/turn_to_bearing, + /decl/state_transition/turret/no_enemies + ) + +/decl/state/turret/reloading/entered_state(obj/machinery/turret/turret) + . = ..() + turret.reloading_progress = 0 + +/decl/state/turret/no_power + ray_color = "#00000000" // Makes the beam invisible with #RRGGBBAA, not black. + transitions = list( + /decl/state_transition/turret/reload, + /decl/state_transition/turret/shoot, + /decl/state_transition/turret/turn_to_bearing, + /decl/state_transition/turret/no_enemies + ) + +/decl/state_transition/turret/is_open(obj/machinery/turret/turret) + return turret.operable() && turret.enabled +/decl/state_transition/turret/turn_to_bearing + target = /decl/state/turret/turning + +/decl/state_transition/turret/turn_to_bearing/is_open(obj/machinery/turret/turret) + . = ..() + return . && !turret.within_bearing() + +/decl/state_transition/turret/shoot + target = /decl/state/turret/engaging + +/decl/state_transition/turret/shoot/is_open(obj/machinery/turret/turret) + . = ..() + return . && turret.find_target() && turret.within_bearing() + +/decl/state_transition/turret/reload + target = /decl/state/turret/reloading + +/decl/state_transition/turret/reload/is_open(obj/machinery/turret/turret) + . = ..() + return . && turret.should_reload() + +/decl/state_transition/turret/no_enemies + target = /decl/state/turret/idle + +/decl/state_transition/turret/no_enemies/is_open(obj/machinery/turret/turret) + . = ..() + return . && turret.within_bearing() && !turret.find_target() + +/decl/state_transition/turret/lost_power + target = /decl/state/turret/no_power + +/decl/state_transition/turret/lost_power/is_open(obj/machinery/turret/turret) + return !turret.enabled || turret.inoperable() \ No newline at end of file diff --git a/code/game/machinery/turrets/turret_hostility.dm b/code/game/machinery/turrets/turret_hostility.dm new file mode 100644 index 000000000000..5a7b46b889f9 --- /dev/null +++ b/code/game/machinery/turrets/turret_hostility.dm @@ -0,0 +1,22 @@ +/decl/hostility/turret/can_special_target(atom/movable/target) + if(isliving(target)) + return TRUE + +// Network turret hostility +/decl/hostility/turret/network + var/static/threat_level_threshold = 4 + +/decl/hostility/turret/network/can_special_target(atom/holder, atom/movable/target) + var/obj/machinery/turret/network/owner = holder + if(!istype(holder)) + log_error("Network turret hostility referenced with a non turret holder: [holder]!") + return + if(!ishuman(target)) + // Attack any living, non-small/silicon/human target. + if(owner.check_lifeforms) + if(isliving(target) && (!issilicon(target) && !issmall(target))) + return TRUE + return FALSE + + var/mob/living/L = target + return L.assess_perp(holder, owner.check_access, owner.check_weapons, owner.check_records, owner.check_arrest, TRUE) >= threat_level_threshold diff --git a/code/game/machinery/vending/_vending.dm b/code/game/machinery/vending/_vending.dm index 93da11acce32..5fa543120f98 100644 --- a/code/game/machinery/vending/_vending.dm +++ b/code/game/machinery/vending/_vending.dm @@ -4,11 +4,11 @@ /obj/machinery/vending name = "Vendomat" desc = "A generic vending machine." - icon = 'icons/obj/vending.dmi' - icon_state = "generic" + icon = 'icons/obj/machines/vending/generic.dmi' + icon_state = ICON_STATE_WORLD layer = BELOW_OBJ_LAYER - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE obj_flags = OBJ_FLAG_ANCHORABLE | OBJ_FLAG_ROTATABLE clicksound = "button" clickvol = 40 @@ -18,9 +18,7 @@ idle_power_usage = 10 emagged = 0 //Ignores if somebody doesn't have card access to that machine. wires = /datum/wires/vending - - var/icon_vend //Icon_state when vending - var/icon_deny //Icon_state when denying access + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES // Power var/vend_power_usage = 150 //actuators and stuff @@ -69,11 +67,11 @@ var/scan_id = 1 /obj/machinery/vending/Initialize(mapload, d=0, populate_parts = TRUE) - . = ..() + ..() if(isnull(markup)) - markup = 1 + (rand() * 2) + markup = 1.1 + (rand() * 0.4) if(!ispath(vendor_currency, /decl/currency)) - vendor_currency = GLOB.using_map.default_currency + vendor_currency = global.using_map.default_currency if(product_slogans) slogan_list += splittext(product_slogans, ";") @@ -86,6 +84,11 @@ ads_list += splittext(product_ads, ";") build_inventory(populate_parts) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/vending/LateInitialize() + ..() + update_icon() /** * Build produdct_records from the products lists @@ -95,9 +98,6 @@ * product_records. */ -/obj/machinery/vending/proc/get_product_name(var/entry) - return - /obj/machinery/vending/proc/build_inventory(populate_parts = FALSE) var/list/all_products = list( list(products, CAT_NORMAL), @@ -106,22 +106,25 @@ for(var/current_list in all_products) var/category = current_list[2] for(var/entry in current_list[1]) - var/datum/stored_items/vending_products/product = new(src, entry, get_product_name(entry)) - product.price = atom_info_repository.get_combined_worth_for(entry) * markup + var/datum/stored_items/vending_products/product = new(src, entry) + product.price = ceil(atom_info_repository.get_combined_worth_for(entry) * markup) product.category = category if(product && populate_parts) product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 + if(ispath(product.item_path, /obj/item/stack/material)) + var/obj/item/stack/material/M = product.item_path + var/decl/material/mat = GET_DECL(initial(M.material)) + if(mat) + var/mat_amt = initial(M.amount) + product.item_name = "[mat.solid_name] [mat_amt == 1 ? initial(M.singular_name) : initial(M.plural_name)] ([mat_amt]x)" product_records.Add(product) /obj/machinery/vending/Destroy() - for(var/datum/stored_items/vending_products/R in product_records) - qdel(R) + for(var/datum/stored_items/vending_products/product_record in product_records) + qdel(product_record) product_records = null return ..() -/obj/machinery/vending/get_codex_value() - return "vendomat" - /obj/machinery/vending/explosion_act(severity) ..() if(!QDELETED(src)) @@ -134,22 +137,30 @@ if (!emagged) emagged = 1 req_access.Cut() - to_chat(user, "You short out the product lock on \the [src]") + to_chat(user, "You short out the product lock on \the [src].") return 1 -/obj/machinery/vending/attackby(obj/item/W, mob/user) +/obj/machinery/vending/receive_mouse_drop(atom/dropping, mob/user, params) + if(!(. = ..()) && isitem(dropping) && istype(user) && user.check_intent(I_FLAG_HELP) && CanPhysicallyInteract(user)) + return attempt_to_stock(dropping, user) - var/obj/item/charge_stick/CS = W.GetChargeStick() +/obj/machinery/vending/attackby(obj/item/used_item, mob/user) + var/obj/item/charge_stick/CS = used_item.GetChargeStick() if (currently_vending && vendor_account && !vendor_account.suspended) + + if(!vend_ready) + to_chat(user, SPAN_WARNING("\The [src] is vending a product, wait a second!")) + return TRUE + var/paid = 0 var/handled = 0 if (CS) paid = pay_with_charge_card(CS) handled = 1 - else if (istype(W, /obj/item/cash)) - var/obj/item/cash/C = W + else if (istype(used_item, /obj/item/cash)) + var/obj/item/cash/C = used_item paid = pay_with_cash(C) handled = 1 @@ -160,35 +171,31 @@ SSnano.update_uis(src) return TRUE // don't smack that machine with your $2 - if (istype(W, /obj/item/cash)) - attack_hand(user) + if (istype(used_item, /obj/item/cash)) + attack_hand_with_interaction_checks(user) return TRUE - if(isMultitool(W) || isWirecutter(W)) + + if(IS_MULTITOOL(used_item) || IS_WIRECUTTER(used_item)) if(panel_open) - attack_hand(user) + attack_hand_with_interaction_checks(user) return TRUE - if((user.a_intent == I_HELP) && attempt_to_stock(W, user)) - return TRUE - if((. = component_attackby(W, user))) - return - if((obj_flags & OBJ_FLAG_ANCHORABLE) && isWrench(W)) - wrench_floor_bolts(user) - power_change() + + if((. = component_attackby(used_item, user))) return + if((user.check_intent(I_FLAG_HELP)) && attempt_to_stock(used_item, user)) + return TRUE + + return ..() // handle anchoring and bashing + /obj/machinery/vending/state_transition(decl/machine_construction/new_state) . = ..() SSnano.update_uis(src) -/obj/machinery/vending/MouseDrop_T(var/obj/item/I, var/mob/user) - if(!CanMouseDrop(I, user) || (I.loc != user)) - return - return attempt_to_stock(I, user) - /obj/machinery/vending/proc/attempt_to_stock(var/obj/item/I, var/mob/user) - for(var/datum/stored_items/vending_products/R in product_records) - if(I.type == R.item_path) - stock(I, R, user) + for(var/datum/stored_items/vending_products/product_record in product_records) + if(I.type == product_record.item_path) + stock(I, product_record, user) return 1 /** @@ -198,9 +205,9 @@ if(currently_vending.price > cashmoney.absolute_worth) // This is not a status display message, since it's something the character // themselves is meant to see BEFORE putting the money in - to_chat(usr, "\icon[cashmoney] That is not enough money.") + to_chat(usr, SPAN_WARNING("[html_icon(cashmoney)] That is not enough money.")) return 0 - visible_message("\The [usr] inserts some cash into \the [src].") + visible_message(SPAN_INFO("\The [usr] inserts some cash into \the [src].")) cashmoney.adjust_worth(-(currently_vending.price)) // Vending machines have no idea who paid with cash credit_purchase("(cash)") @@ -213,19 +220,20 @@ * successful, 0 if failed. */ /obj/machinery/vending/proc/pay_with_charge_card(var/obj/item/charge_stick/wallet) - visible_message("\The [usr] plugs \the [wallet] into \the [src].") + visible_message(SPAN_INFO("\The [usr] plugs \the [wallet] into \the [src].")) if(wallet.is_locked()) status_message = "Unlock \the [wallet] before using it." - status_error = 1 - return 0 + status_error = TRUE else if(currently_vending.price > wallet.loaded_worth) status_message = "Insufficient funds on \the [wallet]." - status_error = 1 - return 0 + status_error = TRUE else wallet.adjust_worth(-(currently_vending.price)) credit_purchase("[wallet.id]") - return 1 + return TRUE + if(status_message && status_error) + to_chat(usr, SPAN_WARNING(status_message)) + return FALSE /** @@ -240,6 +248,7 @@ if(seconds_electrified != 0) if(shock(user, 100)) return TRUE + return FALSE /obj/machinery/vending/interface_interact(mob/user) ui_interact(user) @@ -252,13 +261,13 @@ */ /obj/machinery/vending/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) user.set_machine(src) - var/decl/currency/cur = decls_repository.get_decl(vendor_currency) + var/decl/currency/cur = GET_DECL(vendor_currency) var/list/data = list() if(currently_vending) data["mode"] = 1 data["product"] = currently_vending.item_name data["price"] = cur.format_value(currently_vending.price) - data["message_err"] = 0 + data["price_num"] = floor(currently_vending.price / cur.absolute_value) data["message"] = status_message data["message_err"] = status_error else @@ -275,6 +284,7 @@ "key" = key, "name" = I.item_name, "price" = cur.format_value(I.price), + "price_num" = floor(I.price / cur.absolute_value), "color" = I.display_color, "amount" = I.get_amount()))) @@ -288,35 +298,33 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "vending_machine.tmpl", name, 440, 600) + ui = new(user, src, ui_key, "vending_machine.tmpl", name, 520, 600) ui.set_initial_data(data) ui.open() /obj/machinery/vending/OnTopic(mob/user, href_list, datum/topic_state/state) - if (href_list["vend"] && vend_ready && !currently_vending) + if (href_list["vend"] && !currently_vending) var/key = text2num(href_list["vend"]) - if(!is_valid_index(key, product_records)) - return TOPIC_REFRESH - var/datum/stored_items/vending_products/R = product_records[key] - if(!istype(R)) + var/datum/stored_items/vending_products/product_record = LAZYACCESS(product_records, key) + if(!product_record) return TOPIC_REFRESH // This should not happen unless the request from NanoUI was bad - if(!(R.category & categories)) + if(!(product_record.category & categories)) return TOPIC_REFRESH - if(R.price <= 0) - vend(R, user) - else if(istype(user,/mob/living/silicon)) //If the item is not free, provide feedback if a synth is trying to buy something. - to_chat(user, "Artificial unit recognized. Artificial units cannot complete this transaction. Purchase canceled.") + if(product_record.price <= 0) + vend(product_record, user) + else if(issilicon(user)) //If the item is not free, provide feedback if a synth is trying to buy something. + to_chat(user, SPAN_DANGER("Artificial unit recognized. Artificial units cannot complete this transaction. Purchase canceled.")) else - currently_vending = R + currently_vending = product_record if(!vendor_account || vendor_account.suspended) status_message = "This machine is currently unable to process payments due to problems with the associated account." status_error = 1 else - status_message = "Please swipe a card or insert cash to pay for the item." + status_message = "Please insert cash or a credstick to pay for the product." status_error = 0 return TOPIC_REFRESH @@ -333,11 +341,16 @@ return list() return ..() -/obj/machinery/vending/proc/vend(var/datum/stored_items/vending_products/R, mob/user) +/obj/machinery/vending/proc/vend(var/datum/stored_items/vending_products/product_record, mob/user) + if(!vend_ready) + return if((!allowed(user)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH - to_chat(user, "Access denied.")//Unless emagged of course - flick(icon_deny,src) + to_chat(user, SPAN_WARNING("Access denied."))//Unless emagged of course + var/deny_state = "[icon_state]-deny" + if(check_state_in_icon(deny_state, icon)) + flick(deny_state, src) return + vend_ready = 0 //One thing at a time!! status_message = "Vending..." status_error = 0 @@ -346,16 +359,17 @@ do_vending_reply() use_power_oneoff(vend_power_usage) //actuators and stuff - if (icon_vend) //Show the vending animation if needed - flick(icon_vend,src) - addtimer(CALLBACK(src, /obj/machinery/vending/proc/finish_vending, R), vend_delay) + var/vend_state = "[icon_state]-vend" + if (check_state_in_icon(vend_state, icon)) //Show the vending animation if needed + flick(vend_state, src) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/vending, finish_vending), product_record), vend_delay) /obj/machinery/vending/proc/do_vending_reply() set waitfor = FALSE if(vend_reply && last_reply + vend_delay + 200 <= world.time) speak(vend_reply) last_reply = world.time - + /obj/machinery/vending/proc/finish_vending(var/datum/stored_items/vending_products/product) set waitfor = FALSE if(!product) @@ -366,7 +380,7 @@ if(prob(1)) //The vending gods look favorably upon you sleep(3) if(product.get_product(get_turf(src))) - visible_message("\The [src] clunks as it vends an additional [product.item_name].") + visible_message(SPAN_NOTICE("\The [src] clunks as it vends an additional [product.item_name].")) status_message = "" status_error = 0 vend_ready = 1 @@ -377,19 +391,24 @@ * Add item to the machine * * Checks if item is vendable in this machine should be performed before - * calling. W is the item being inserted, R is the associated vending_product entry. + * calling. used_item is the item being inserted, product_record is the associated vending_product entry. */ -/obj/machinery/vending/proc/stock(obj/item/W, var/datum/stored_items/vending_products/R, var/mob/user) - if(!user.unEquip(W)) +/obj/machinery/vending/proc/stock(obj/item/used_item, var/datum/stored_items/vending_products/product_record, var/mob/user) + if(!user.try_unequip(used_item)) return - if(R.add_product(W)) - to_chat(user, "You insert \the [W] in the product receptor.") + if(product_record.add_product(used_item)) + to_chat(user, SPAN_NOTICE("You insert \the [used_item] in the product receptor.")) SSnano.update_uis(src) return 1 SSnano.update_uis(src) +/// Used to get a slogan to say in Process(). +/// If you want to do things like non-constant token replacement you can do that in an override. +/obj/machinery/vending/proc/get_slogan() + return pick(slogan_list) + /obj/machinery/vending/Process() if(stat & (BROKEN|NOPOWER)) return @@ -401,8 +420,8 @@ seconds_electrified-- //Pitch to the people! Really sell it! - if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) - var/slogan = pick(slogan_list) + if(((last_slogan + slogan_delay) <= world.time) && length(slogan_list) && (!shut_up) && prob(5)) + var/slogan = get_slogan() speak(slogan) last_slogan = world.time @@ -418,15 +437,14 @@ if (!message) return - for(var/mob/O in hearers(src, null)) - O.show_message("\The [src] beeps, \"[message]\"",2) + audible_message("\The [src] beeps, \"[message]\"") return /obj/machinery/vending/powered() return anchored && ..() /obj/machinery/vending/on_update_icon() - overlays.Cut() + cut_overlays() if(stat & BROKEN) icon_state = "[initial(icon_state)]-broken" else if( !(stat & NOPOWER) ) @@ -435,14 +453,14 @@ spawn(rand(0, 15)) icon_state = "[initial(icon_state)]-off" if(panel_open) - overlays += image(icon, "[initial(icon_state)]-panel") + add_overlay("[initial(icon_state)]-panel") //Oh no we're malfunctioning! Dump out some product and break. /obj/machinery/vending/proc/malfunction() set waitfor = FALSE - for(var/datum/stored_items/vending_products/R in product_records) - while(R.get_amount()>0) - R.get_product(loc) + for(var/datum/stored_items/vending_products/product_record in product_records) + while(product_record.get_amount()>0) + product_record.get_product(loc) break set_broken(TRUE) @@ -453,13 +471,13 @@ if(!target) return 0 - for(var/datum/stored_items/vending_products/R in shuffle(product_records)) - throw_item = R.get_product(loc) - if (throw_item) + for(var/datum/stored_items/vending_products/product_record in shuffle(product_records)) + throw_item = product_record.get_product(loc) + if(!QDELETED(throw_item)) break - if (!throw_item) + if(QDELETED(throw_item)) return 0 spawn(0) throw_item.throw_at(target, rand(1,2), 3) - visible_message("\The [src] launches \a [throw_item] at \the [target]!") + visible_message(SPAN_WARNING("\The [src] launches \a [throw_item] at \the [target]!")) return 1 diff --git a/code/game/machinery/vending/actors.dm b/code/game/machinery/vending/actors.dm index 77a56653c863..0dac1d09962a 100644 --- a/code/game/machinery/vending/actors.dm +++ b/code/game/machinery/vending/actors.dm @@ -3,32 +3,29 @@ /obj/machinery/vending/props name = "prop dispenser" desc = "All the props an actor could need. Probably." - icon_state = "theater" - icon_vend = "theater-vend" - icon_deny = "theater-deny" + icon = 'icons/obj/machines/vending/theater.dmi' products = list( - /obj/structure/flora/pottedplant = 2, - /obj/item/flashlight/lamp = 2, - /obj/item/flashlight/lamp/green = 2, - /obj/item/chems/food/drinks/jar = 1, - /obj/item/nullrod = 1, - /obj/item/sword/cult_toy = 4, + /obj/structure/flora/pottedplant = 2, + /obj/item/flashlight/lamp = 2, + /obj/item/flashlight/lamp/green = 2, + /obj/item/nullrod = 1, + /obj/item/sword/cult_toy = 4, /obj/item/sword/katana/toy = 2 ) /obj/machinery/vending/props/on_update_icon() ..() if(!(stat & NOPOWER)) - overlays += image(icon, "[initial(icon_state)]-overlay") + add_overlay("[initial(icon_state)]-overlay") //FOR ACTORS GUILD - Containers /obj/machinery/vending/containers name = "container dispenser" desc = "A container that dispenses containers." - icon_state = "robotics" + icon = 'icons/obj/machines/vending/robotics.dmi' base_type = /obj/machinery/vending/containers products = list( - /obj/structure/closet/crate/freezer = 2, - /obj/structure/closet = 3, + /obj/structure/closet/crate/freezer = 2, + /obj/structure/closet = 3, /obj/structure/closet/crate = 3 ) diff --git a/code/game/machinery/vending/botany.dm b/code/game/machinery/vending/botany.dm index 5ab14ca12ea8..f001ba662632 100644 --- a/code/game/machinery/vending/botany.dm +++ b/code/game/machinery/vending/botany.dm @@ -4,9 +4,7 @@ desc = "A plant nutrients vendor." product_slogans = "Aren't you glad you don't have to fertilize the natural way?;Now with 50% less stink!;Plants are people too!" product_ads = "We like plants!;Don't you want some?;The greenest thumbs ever.;We like big plants.;Soft soil..." - icon_state = "nutri" - icon_deny = "nutri-deny" - icon_vend = "nutri-vend" + icon = 'icons/obj/machines/vending/nutrimat.dmi' vend_delay = 26 base_type = /obj/machinery/vending/hydronutrients products = list( @@ -15,25 +13,21 @@ /obj/item/chems/glass/bottle/robustharvest = 3, /obj/item/plantspray/pests = 20, /obj/item/chems/syringe = 5, - /obj/item/storage/plants = 5, + /obj/item/plant_satchel = 5, /obj/item/chems/glass/bottle/ammonia = 10 ) idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. markup = 0 /obj/machinery/vending/hydronutrients/generic - icon_state = "nutri_generic" - icon_vend = "nutri_generic-vend" - icon_deny = "nutri_generic-deny" + icon = 'icons/obj/machines/vending/nutri_green.dmi' /obj/machinery/vending/hydroseeds name = "MegaSeed Servitor" desc = "When you need seeds fast!" product_slogans = "THIS'S WHERE TH' SEEDS LIVE! GIT YOU SOME!;Hands down the best seed selection this half of the galaxy!;Also certain mushroom varieties available, more for experts! Get certified today!" product_ads = "We like plants!;Grow some crops!;Grow, baby, growww!;Aw h'yeah son!" - icon_state = "seeds" - icon_vend = "seeds-vend" - icon_deny = "seeds-deny" + icon = 'icons/obj/machines/vending/seeds_green.dmi' vend_delay = 13 base_type = /obj/machinery/vending/hydroseeds markup = 0 @@ -43,13 +37,13 @@ /obj/item/seeds/carrotseed = 3, /obj/item/seeds/chantermycelium = 3, /obj/item/seeds/chiliseed = 3, - /obj/item/seeds/cornseed = 3, - /obj/item/seeds/eggplantseed = 3, - /obj/item/seeds/potatoseed = 3, + /obj/item/seeds/cornseed = 3, + /obj/item/seeds/eggplantseed = 3, + /obj/item/seeds/potatoseed = 3, /obj/item/seeds/soyaseed = 3, /obj/item/seeds/sunflowerseed = 3, /obj/item/seeds/tomatoseed = 3, - /obj/item/seeds/corkwood = 3, + /obj/item/seeds/towercap = 3, /obj/item/seeds/wheatseed = 3, /obj/item/seeds/appleseed = 3, /obj/item/seeds/poppyseed = 3, @@ -84,14 +78,5 @@ /obj/item/chems/spray/waterflower = 1 ) -/obj/machinery/vending/hydroseeds/vend(var/datum/stored_items/vending_products/R, mob/user) - ..() - flick("[icon_state]-shelf[rand(3)]", src) - /obj/machinery/vending/hydroseeds/generic - icon_state = "seeds_generic" - icon_vend = "seeds_generic-vend" - icon_deny = "seeds_generic-deny" - -/obj/machinery/vending/hydroseeds/get_product_name(var/entry) - . = atom_info_repository.get_name_for(entry) \ No newline at end of file + icon = 'icons/obj/machines/vending/seeds_grey.dmi' diff --git a/code/game/machinery/vending/cigs.dm b/code/game/machinery/vending/cigs.dm index d6e3e0382e2e..e5cb5a43b02b 100644 --- a/code/game/machinery/vending/cigs.dm +++ b/code/game/machinery/vending/cigs.dm @@ -21,31 +21,29 @@ We understand the depressed, alcoholic cowboy in you. That's why we also smoke Jericho.;\ Professionals. Better cigarettes for better people. Yes, better people." vend_delay = 21 - icon_state = "cigs" - icon_vend = "cigs-vend" - icon_deny = "cigs-deny" + icon = 'icons/obj/machines/vending/cigarettes.dmi' base_type = /obj/machinery/vending/cigarette products = list( - /obj/item/storage/cigpaper/filters = 5, - /obj/item/storage/cigpaper = 3, - /obj/item/storage/cigpaper/fancy = 2, - /obj/item/storage/chewables/rollable/bad = 2, - /obj/item/storage/chewables/rollable/generic = 2, - /obj/item/storage/chewables/rollable/fine = 2, - /obj/item/storage/fancy/cigarettes = 5, - /obj/item/storage/fancy/cigarettes/luckystars = 2, - /obj/item/storage/fancy/cigarettes/jerichos = 2, - /obj/item/storage/fancy/cigarettes/menthols = 2, - /obj/item/storage/fancy/cigarettes/carcinomas = 2, - /obj/item/storage/fancy/cigarettes/professionals = 2, - /obj/item/storage/fancy/cigarettes/cigarello = 2, - /obj/item/storage/fancy/cigarettes/cigarello/mint = 2, - /obj/item/storage/fancy/cigarettes/cigarello/variety = 2, - /obj/item/storage/box/matches = 10, - /obj/item/flame/lighter/random = 4, - /obj/item/storage/chewables/tobacco = 2, - /obj/item/storage/chewables/tobacco2 = 2, - /obj/item/storage/chewables/tobacco3 = 2, + /obj/item/cigpaper/filters = 5, + /obj/item/cigpaper = 3, + /obj/item/cigpaper/fancy = 2, + /obj/item/chewables/rollable/bad = 2, + /obj/item/chewables/rollable/generic = 2, + /obj/item/chewables/rollable/fine = 2, + /obj/item/box/fancy/cigarettes = 5, + /obj/item/box/fancy/cigarettes/luckystars = 2, + /obj/item/box/fancy/cigarettes/jerichos = 2, + /obj/item/box/fancy/cigarettes/menthols = 2, + /obj/item/box/fancy/cigarettes/carcinomas = 2, + /obj/item/box/fancy/cigarettes/professionals = 2, + /obj/item/box/fancy/cigarettes/cigarello = 2, + /obj/item/box/fancy/cigarettes/cigarello/mint = 2, + /obj/item/box/fancy/cigarettes/cigarello/variety = 2, + /obj/item/box/matches = 10, + /obj/item/flame/fuelled/lighter/random = 4, + /obj/item/chewables/tobacco = 2, + /obj/item/chewables/tobacco2 = 2, + /obj/item/chewables/tobacco3 = 2, /obj/item/clothing/mask/smokable/ecig/simple = 10, /obj/item/clothing/mask/smokable/ecig/util = 5, /obj/item/clothing/mask/smokable/ecig/deluxe = 1, @@ -60,8 +58,8 @@ /obj/item/chems/ecig_cartridge/blanknico = 2 ) contraband = list( - /obj/item/flame/lighter/zippo = 4, + /obj/item/flame/fuelled/lighter/zippo = 4, /obj/item/clothing/mask/smokable/cigarette/rolled/sausage = 3, - /obj/item/storage/fancy/cigar = 5, - /obj/item/storage/fancy/cigarettes/killthroat = 5 + /obj/item/box/fancy/cigar = 5, + /obj/item/box/fancy/cigarettes/killthroat = 5 ) diff --git a/code/game/machinery/vending/engineering.dm b/code/game/machinery/vending/engineering.dm index 5d38c5afa444..6eda475db41f 100644 --- a/code/game/machinery/vending/engineering.dm +++ b/code/game/machinery/vending/engineering.dm @@ -1,11 +1,8 @@ - /obj/machinery/vending/tool name = "YouTool" desc = "Tools for tools." markup = 0 - icon_state = "tool" - icon_deny = "tool-deny" - icon_vend = "tool-vend" + icon = 'icons/obj/machines/vending/tool.dmi' vend_delay = 11 base_type = /obj/machinery/vending/tool products = list( @@ -17,9 +14,9 @@ /obj/item/scanner/gas = 5, /obj/item/t_scanner = 5, /obj/item/screwdriver = 5, - /obj/item/flashlight/flare/glowstick = 3, - /obj/item/flashlight/flare/glowstick/red = 3, - /obj/item/tape_roll = 8, + /obj/item/flashlight/flare/glowstick = 3, + /obj/item/flashlight/flare/glowstick/red = 3, + /obj/item/stack/tape_roll/duct_tape = 8, /obj/item/clothing/gloves/insulated/cheap = 2 ) contraband = list( @@ -27,32 +24,23 @@ /obj/item/clothing/gloves/insulated = 1 ) -/obj/machinery/vending/tool/adherent/vend(var/datum/stored_items/vending_products/R, var/mob/living/carbon/user) - if(emagged) - . = ..() - else - to_chat(user, "The vending machine emits a discordant note, and a small hole blinks several times. It looks like it wants something inserted.") - /obj/machinery/vending/engivend name = "Engi-Vend" desc = "Spare tool vending. What? Did you expect some witty description?" - icon_state = "engivend" - icon_deny = "engivend-deny" - icon_vend = "engivend-vend" + icon = 'icons/obj/machines/vending/engivend.dmi' markup = 0 vend_delay = 21 base_type = /obj/machinery/vending/engivend - initial_access = list(list(access_atmospherics, access_engine_equip)) + initial_access = list(access_atmospherics, access_engine_equip) products = list( /obj/item/clothing/glasses/meson = 2, /obj/item/multitool = 4, /obj/item/geiger = 4, /obj/item/stock_parts/circuitboard/airlock_electronics = 10, - /obj/item/stock_parts/circuitboard/apc = 10, - /obj/item/stock_parts/circuitboard/air_alarm = 10, + /obj/item/frame/apc/kit = 10, + /obj/item/frame/air_alarm/kit = 10, /obj/item/cell = 10, - /obj/item/clamp = 10, - /obj/item/storage/belt/utility + /obj/item/belt/utility ) contraband = list(/obj/item/cell/high = 3) @@ -60,23 +48,21 @@ /obj/machinery/vending/engineering name = "Robco Tool Maker" desc = "Everything you need for do-it-yourself repair." - icon_state = "engi" - icon_deny = "engi-deny" - icon_vend = "engi-vend" + icon = 'icons/obj/machines/vending/engivend.dmi' base_type = /obj/machinery/vending/engineering markup = 0 - initial_access = list(list(access_atmospherics, access_engine_equip)) + initial_access = list(access_atmospherics, access_engine_equip) products = list( - /obj/item/storage/belt/utility = 4, + /obj/item/belt/utility = 4, /obj/item/clothing/glasses/meson = 4, - /obj/item/clothing/gloves/insulated = 4, + /obj/item/clothing/gloves/insulated = 4, /obj/item/screwdriver = 12, /obj/item/crowbar = 12, /obj/item/wirecutters = 12, /obj/item/multitool = 12, /obj/item/wrench = 12, /obj/item/t_scanner = 12, - /obj/item/cell = 8, + /obj/item/cell = 8, /obj/item/weldingtool = 8, /obj/item/clothing/head/welding = 8, /obj/item/light/tube = 10, @@ -85,8 +71,8 @@ /obj/item/stock_parts/matter_bin = 5, /obj/item/stock_parts/manipulator = 5, /obj/item/stock_parts/console_screen = 5, - /obj/item/stock_parts/capacitor = 5, - /obj/item/stock_parts/keyboard = 5, + /obj/item/stock_parts/capacitor = 5, + /obj/item/stock_parts/keyboard = 5, /obj/item/stock_parts/power/apc/buildable = 5 ) contraband = list(/obj/item/rcd = 1, /obj/item/rcd_ammo = 5) @@ -95,9 +81,7 @@ /obj/machinery/vending/robotics name = "Robotech Deluxe" desc = "All the tools you need to create your own robot army." - icon_state = "robotics" - icon_deny = "robotics-deny" - icon_vend = "robotics-vend" + icon = 'icons/obj/machines/vending/robotics.dmi' initial_access = list(access_robotics) base_type = /obj/machinery/vending/robotics products = list( @@ -107,7 +91,6 @@ /obj/item/scanner/health = 2, /obj/item/scalpel = 1, /obj/item/circular_saw = 1, - /obj/item/tank/anesthetic = 2, /obj/item/clothing/mask/breath/medical = 5, /obj/item/screwdriver = 2, /obj/item/crowbar = 2 @@ -117,25 +100,19 @@ /obj/machinery/vending/materials name = "MatterVend" desc = "Provides access to baryonic matter in easy to handle sheet form." - icon_state = "engivend" - icon_deny = "engivend-deny" - icon_vend = "engivend-vend" + icon = 'icons/obj/machines/vending/engivend.dmi' markup = 0 vend_delay = 21 base_type = /obj/machinery/vending/materials products = list( - /obj/item/stack/material/steel/fifty = 3, - /obj/item/stack/material/plastic/fifty = 4, - /obj/item/stack/material/aluminium/fifty = 3, - /obj/item/stack/material/plasteel/ten = 4, - /obj/item/stack/material/glass/fifty = 4 + /obj/item/stack/material/sheet/mapped/steel/fifty = 3, + /obj/item/stack/material/panel/mapped/plastic/fifty = 4, + /obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty = 3, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten = 4, + /obj/item/stack/material/ingot/mapped/copper/fifty = 4, + /obj/item/stack/material/pane/mapped/glass/fifty = 4, + /obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty = 4 + ) + contraband = list( + /obj/item/stack/material/sheet/reinforced/mapped/ocp/ten = 3 ) - contraband = list(/obj/item/stack/material/ocp/ten = 3) - -/obj/machinery/vending/materials/build_inventory() - ..() - for(var/datum/stored_items/vending_products/P in product_records) - if(ispath(P.item_path, /obj/item/stack/material)) - var/obj/item/stack/material/S = P.item_path - var/decl/material/sheet_material = decls_repository.get_decl(initial(S.material)) - P.item_name = "[sheet_material.solid_name] [sheet_material.sheet_plural_name] ([initial(S.amount)]x)" \ No newline at end of file diff --git a/code/game/machinery/vending/food.dm b/code/game/machinery/vending/food.dm index 9f5586128f00..2a4fb62f3352 100644 --- a/code/game/machinery/vending/food.dm +++ b/code/game/machinery/vending/food.dm @@ -4,74 +4,67 @@ desc = "A snack machine courtesy of the Getmore Chocolate Corporation, based out of Mars." product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" product_ads = "The healthiest!;Award-winning chocolate bars!;Mmm! So good!;Oh my god it's so juicy!;Have a snack.;Snacks are good for you!;Have some more Getmore!;Best quality snacks straight from mars.;We love chocolate!;Try our new jerky!" - icon_state = "snack" - icon_vend = "snack-vend" - icon_deny = "snack-deny" + icon = 'icons/obj/machines/vending/snacks.dmi' vend_delay = 25 base_type = /obj/machinery/vending/snack products = list( /obj/item/clothing/mask/chewable/candy/lolli = 8, - /obj/item/storage/chewables/candy/gum = 4, - /obj/item/storage/chewables/candy/cookies = 4, - /obj/item/chems/food/snacks/candy = 6, - /obj/item/chems/food/drinks/dry_ramen = 6, - /obj/item/chems/food/snacks/chips = 6, - /obj/item/chems/food/snacks/sosjerky = 6, - /obj/item/chems/food/snacks/no_raisin = 6, - /obj/item/chems/food/snacks/spacetwinkie = 6, - /obj/item/chems/food/snacks/cheesiehonkers = 6, - /obj/item/chems/food/snacks/tastybread = 6 + /obj/item/chewables/candy/gum = 4, + /obj/item/chewables/candy/cookies = 4, + /obj/item/food/junk/candy = 6, + /obj/item/chems/drinks/dry_ramen = 6, + /obj/item/food/junk/chips = 6, + /obj/item/food/junk/sosjerky = 6, + /obj/item/food/junk/no_raisin = 6, + /obj/item/food/junk/spacetwinkie = 6, + /obj/item/food/junk/cheesiehonkers = 6, + /obj/item/food/junk/tastybread = 6 ) contraband = list( - /obj/item/chems/food/snacks/syndicake = 6 + /obj/item/food/junk/syndicake = 6 ) -//a food variant of the boda machine - It carries slavic themed foods.. Mostly beer snacks +//a food variant of the boda machine - It carries slavic themed foods. Mostly beer snacks /obj/machinery/vending/snix name = "Snix" desc = "An old snack vending machine, how did it get here? And are the snacks still good?" vend_delay = 30 base_type = /obj/machinery/vending/snix product_slogans = "Snix!" - - icon_state = "snix" - icon_vend = "snix-vend" - icon_deny = "snix-deny" - products = list(/obj/item/chems/food/snacks/semki = 7, - /obj/item/chems/food/snacks/canned/caviar = 7, - /obj/item/chems/food/snacks/squid = 7, - /obj/item/chems/food/snacks/croutons = 7, - /obj/item/chems/food/snacks/salo = 7, - /obj/item/chems/food/snacks/driedfish = 7, - /obj/item/chems/food/snacks/pistachios = 7, + icon = 'icons/obj/machines/vending/snix.dmi' + products = list(/obj/item/food/junk/semki = 7, + /obj/item/food/can/caviar = 7, + /obj/item/food/junk/squid = 7, + /obj/item/food/junk/croutons = 7, + /obj/item/food/junk/salo = 7, + /obj/item/food/junk/driedfish = 7, + /obj/item/food/junk/pistachios = 7, ) - contraband = list(/obj/item/chems/food/snacks/canned/caviar/true = 1) + contraband = list(/obj/item/food/can/caviar/true = 1) /obj/machinery/vending/snix/on_update_icon() ..() if(!(stat & NOPOWER)) - overlays += image(icon, "[initial(icon_state)]-fan") + add_overlay("[initial(icon_state)]-fan") /obj/machinery/vending/sol name = "Mars-Mart" desc = "A SolCentric vending machine dispensing treats from home." vend_delay = 30 product_slogans = "A taste of home!" - icon_state = "solsnack" - icon_vend = "solsnack-vend" - icon_deny = "solsnack-deny" + icon = 'icons/obj/machines/vending/solsnacks.dmi' products = list( - /obj/item/chems/food/snacks/lunacake = 8, - /obj/item/chems/food/snacks/lunacake/mochicake = 8, - /obj/item/chems/food/snacks/lunacake/mooncake = 8, - /obj/item/chems/food/snacks/pluto = 8, - /obj/item/chems/food/snacks/triton = 8, - /obj/item/chems/food/snacks/saturn = 8, - /obj/item/chems/food/snacks/jupiter = 8, - /obj/item/chems/food/snacks/mars = 8, - /obj/item/chems/food/snacks/venus = 8, - /obj/item/chems/food/snacks/oort = 8 + /obj/item/food/junk/lunacake = 8, + /obj/item/food/junk/lunacake/mochicake = 8, + /obj/item/food/junk/lunacake/mooncake = 8, + /obj/item/food/junk/pluto = 8, + /obj/item/food/junk/triton = 8, + /obj/item/food/junk/saturn = 8, + /obj/item/food/junk/jupiter = 8, + /obj/item/food/junk/mars = 8, + /obj/item/food/junk/venus = 8, + /obj/item/food/junk/oort = 8 ) /obj/machinery/vending/weeb @@ -79,97 +72,91 @@ desc = "A distressingly ethnic vending machine loaded with high sucrose low calorie for lack of better words snacks." vend_delay = 30 product_slogans = "Konnichiwa gaijin senpai! ;Notice me senpai!; Kawaii-desu!" - icon_state = "weeb" - icon_vend = "weeb-vend" - icon_deny = "weeb-deny" + icon = 'icons/obj/machines/vending/weeb.dmi' products = list( - /obj/item/chems/food/snacks/weebonuts = 8, - /obj/item/chems/food/snacks/ricecake = 8, - /obj/item/chems/food/snacks/dango = 8, - /obj/item/chems/food/snacks/pokey = 8, - /obj/item/chems/food/snacks/chocobanana = 8 + /obj/item/food/junk/weebonuts = 8, + /obj/item/food/junk/ricecake = 8, + /obj/item/food/junk/dango = 8, + /obj/item/food/junk/pokey = 8, + /obj/item/food/junk/chocobanana = 8 ) /obj/machinery/vending/weeb/on_update_icon() ..() if(!(stat & NOPOWER)) - overlays += image(icon, "[initial(icon_state)]-fan") + add_overlay("[initial(icon_state)]-fan") /obj/machinery/vending/hotfood name = "Hot Foods" desc = "An old vending machine promising 'hot foods'. You doubt any of its contents are still edible." vend_delay = 40 base_type = /obj/machinery/vending/hotfood - - icon_state = "hotfood" - icon_deny = "hotfood-deny" - icon_vend = "hotfood-vend" - products = list(/obj/item/chems/food/snacks/old/pizza = 1, - /obj/item/chems/food/snacks/old/burger = 1, - /obj/item/chems/food/snacks/old/hamburger = 1, - /obj/item/chems/food/snacks/old/fries = 1, - /obj/item/chems/food/snacks/old/hotdog = 1, - /obj/item/chems/food/snacks/old/taco = 1 + icon = 'icons/obj/machines/vending/hotfood.dmi' + products = list(/obj/item/food/old/pizza = 1, + /obj/item/food/old/burger = 1, + /obj/item/food/old/hamburger = 1, + /obj/item/food/old/fries = 1, + /obj/item/food/old/hotdog = 1, + /obj/item/food/old/taco = 1 ) /obj/machinery/vending/hotfood/on_update_icon() ..() if(!(stat & NOPOWER)) - overlays += image(icon, "[initial(icon_state)]-heater") + add_overlay("[initial(icon_state)]-heater") /obj/machinery/vending/boozeomat name = "Booze-O-Mat" desc = "A refrigerated vending unit for alcoholic beverages and alcoholic beverage accessories." - icon_state = "fridge_dark" - icon_deny = "fridge_dark-deny" + icon = 'icons/obj/machines/vending/bar.dmi' markup = 0 products = list( - /obj/item/chems/food/drinks/glass2/square = 10, - /obj/item/chems/food/drinks/flask/barflask = 5, - /obj/item/chems/food/drinks/flask/vacuumflask = 5, - /obj/item/chems/food/drinks/bottle/gin = 5, - /obj/item/chems/food/drinks/bottle/whiskey = 5, - /obj/item/chems/food/drinks/bottle/tequilla = 5, - /obj/item/chems/food/drinks/bottle/vodka = 5, - /obj/item/chems/food/drinks/bottle/vermouth = 5, - /obj/item/chems/food/drinks/bottle/rum = 5, - /obj/item/chems/food/drinks/bottle/wine = 5, - /obj/item/chems/food/drinks/bottle/cognac = 5, - /obj/item/chems/food/drinks/bottle/kahlua = 5, - /obj/item/chems/food/drinks/bottle/sake = 5, - /obj/item/chems/food/drinks/bottle/jagermeister = 5, - /obj/item/chems/food/drinks/bottle/melonliquor = 5, - /obj/item/chems/food/drinks/bottle/bluecuracao = 5, - /obj/item/chems/food/drinks/bottle/absinthe = 5, - /obj/item/chems/food/drinks/bottle/champagne = 5, - /obj/item/chems/food/drinks/bottle/herbal = 5, - /obj/item/chems/food/drinks/bottle/small/beer = 15, - /obj/item/chems/food/drinks/bottle/small/ale = 15, - /obj/item/chems/food/drinks/bottle/small/gingerbeer = 15, - /obj/item/chems/food/drinks/cans/speer = 10, - /obj/item/chems/food/drinks/cans/ale = 10, - /obj/item/chems/food/drinks/bottle/cola = 5, - /obj/item/chems/food/drinks/bottle/space_up = 5, - /obj/item/chems/food/drinks/bottle/space_mountain_wind = 5, - /obj/item/chems/food/drinks/cans/beastenergy = 5, - /obj/item/chems/food/drinks/tea/black = 15, - /obj/item/chems/food/drinks/bottle/orangejuice = 5, - /obj/item/chems/food/drinks/bottle/tomatojuice = 5, - /obj/item/chems/food/drinks/bottle/limejuice = 5, - /obj/item/chems/food/drinks/cans/tonic = 15, - /obj/item/chems/food/drinks/bottle/cream = 5, - /obj/item/chems/food/drinks/cans/sodawater = 15, - /obj/item/chems/food/drinks/bottle/grenadine = 5, - /obj/item/chems/food/condiment/mint = 2, - /obj/item/chems/food/drinks/ice = 10, + /obj/item/chems/drinks/glass2/square = 10, + /obj/item/chems/drinks/flask/barflask = 5, + /obj/item/chems/drinks/flask/vacuumflask = 5, + /obj/item/chems/drinks/bottle/gin = 5, + /obj/item/chems/drinks/bottle/whiskey = 5, + /obj/item/chems/drinks/bottle/tequila = 5, + /obj/item/chems/drinks/bottle/vodka = 5, + /obj/item/chems/drinks/bottle/vermouth = 5, + /obj/item/chems/drinks/bottle/rum = 5, + /obj/item/chems/drinks/bottle/wine = 5, + /obj/item/chems/drinks/bottle/cognac = 5, + /obj/item/chems/drinks/bottle/kahlua = 5, + /obj/item/chems/drinks/bottle/sake = 5, + /obj/item/chems/drinks/bottle/jagermeister = 5, + /obj/item/chems/drinks/bottle/melonliquor = 5, + /obj/item/chems/drinks/bottle/bluecuracao = 5, + /obj/item/chems/drinks/bottle/absinthe = 5, + /obj/item/chems/drinks/bottle/champagne = 5, + /obj/item/chems/drinks/bottle/herbal = 5, + /obj/item/chems/drinks/bottle/small/beer = 15, + /obj/item/chems/drinks/bottle/small/ale = 15, + /obj/item/chems/drinks/bottle/small/gingerbeer = 15, + /obj/item/chems/drinks/cans/speer = 10, + /obj/item/chems/drinks/cans/ale = 10, + /obj/item/chems/drinks/bottle/cola = 5, + /obj/item/chems/drinks/bottle/space_up = 5, + /obj/item/chems/drinks/bottle/space_mountain_wind = 5, + /obj/item/chems/drinks/cans/beastenergy = 5, + /obj/item/chems/drinks/tea/black = 15, + /obj/item/chems/drinks/bottle/orangejuice = 5, + /obj/item/chems/drinks/bottle/tomatojuice = 5, + /obj/item/chems/drinks/bottle/limejuice = 5, + /obj/item/chems/drinks/cans/tonic = 15, + /obj/item/chems/drinks/bottle/cream = 5, + /obj/item/chems/drinks/cans/sodawater = 15, + /obj/item/chems/drinks/bottle/grenadine = 5, + /obj/item/chems/condiment/small/mint = 2, + /obj/item/chems/drinks/ice = 10, /obj/item/glass_extra/stick = 15, /obj/item/glass_extra/straw = 15 ) contraband = list( - /obj/item/chems/food/drinks/bottle/premiumwine = 3, - /obj/item/chems/food/drinks/bottle/premiumvodka = 3, - /obj/item/chems/food/drinks/bottle/patron = 5, - /obj/item/chems/food/drinks/bottle/goldschlager = 5 + /obj/item/chems/drinks/bottle/premiumwine = 3, + /obj/item/chems/drinks/bottle/premiumvodka = 3, + /obj/item/chems/drinks/bottle/patron = 5, + /obj/item/chems/drinks/bottle/goldschlager = 5 ) vend_delay = 15 idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. @@ -183,60 +170,56 @@ name = "Hot Drinks machine" desc = "A vending machine which dispenses hot drinks and hot drinks accessories." product_ads = "Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies" - icon_state = "coffee" - icon_vend = "coffee-vend" - icon_deny = "coffee-deny" + icon = 'icons/obj/machines/vending/coffee.dmi' vend_delay = 34 base_type = /obj/machinery/vending/coffee idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. vend_power_usage = 85000 //85 kJ to heat a 250 mL cup of coffee products = list( - /obj/item/chems/food/drinks/coffee = 15, - /obj/item/chems/food/drinks/tea/black = 15, - /obj/item/chems/food/drinks/tea/green = 15, - /obj/item/chems/food/drinks/tea/chai = 15, - /obj/item/chems/food/drinks/h_chocolate = 10, - /obj/item/chems/food/condiment/small/packet/sugar = 25, + /obj/item/chems/drinks/coffee = 15, + /obj/item/chems/drinks/tea/black = 15, + /obj/item/chems/drinks/tea/green = 15, + /obj/item/chems/drinks/tea/chai = 15, + /obj/item/chems/drinks/h_chocolate = 10, + /obj/item/chems/packet/sugar = 25, /obj/item/chems/pill/pod/cream = 25, /obj/item/chems/pill/pod/cream_soy = 25, /obj/item/chems/pill/pod/orange = 10, /obj/item/chems/pill/pod/mint = 10, - /obj/item/chems/food/drinks/ice = 10 + /obj/item/chems/drinks/ice = 10 ) /obj/machinery/vending/coffee/on_update_icon() ..() - if(stat & BROKEN && prob(20)) + if((stat & BROKEN) && prob(20)) icon_state = "[initial(icon_state)]-hellfire" else if(!(stat & NOPOWER)) - overlays += image(icon, "[initial(icon_state)]-screen") + add_overlay("[initial(icon_state)]-screen") /obj/machinery/vending/cola name = "Robust Softdrinks" - desc = "A softdrink vendor provided by Robust Industries, LLC." - icon_state = "Cola_Machine" - icon_vend = "Cola_Machine-vend" - icon_deny = "Cola_Machine-deny" + desc = "A soft drinks vendor provided by Robust Industries, LLC." + icon = 'icons/obj/machines/vending/drinks.dmi' vend_delay = 11 base_type = /obj/machinery/vending/cola product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!" product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space." products = list( - /obj/item/chems/food/drinks/cans/cola = 10, - /obj/item/chems/food/drinks/cans/space_mountain_wind = 10, - /obj/item/chems/food/drinks/cans/dr_gibb = 10, - /obj/item/chems/food/drinks/cans/starkist = 10, - /obj/item/chems/food/drinks/cans/waterbottle = 10, - /obj/item/chems/food/drinks/cans/space_up = 10, - /obj/item/chems/food/drinks/cans/iced_tea = 10, - /obj/item/chems/food/drinks/cans/grape_juice = 10, - /obj/item/chems/food/drinks/juicebox/apple = 10, - /obj/item/chems/food/drinks/juicebox/orange = 10, - /obj/item/chems/food/drinks/juicebox/grape = 10 + /obj/item/chems/drinks/cans/cola = 10, + /obj/item/chems/drinks/cans/space_mountain_wind = 10, + /obj/item/chems/drinks/cans/dr_gibb = 10, + /obj/item/chems/drinks/cans/starkist = 10, + /obj/item/chems/drinks/cans/waterbottle = 10, + /obj/item/chems/drinks/cans/space_up = 10, + /obj/item/chems/drinks/cans/iced_tea = 10, + /obj/item/chems/drinks/cans/grape_juice = 10, + /obj/item/chems/drinks/juicebox/apple = 10, + /obj/item/chems/drinks/juicebox/orange = 10, + /obj/item/chems/drinks/juicebox/grape = 10 ) contraband = list( - /obj/item/chems/food/drinks/cans/thirteenloko = 5, - /obj/item/chems/food/snacks/liquidfood = 6 + /obj/item/chems/drinks/cans/thirteenloko = 5, + /obj/item/food/junk/liquidfood = 6 ) idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. @@ -245,21 +228,19 @@ desc = "An exercise aid and nutrition supplement vendor that preys on your inadequacy." product_slogans = "SweatMAX, get robust!" product_ads = "Pain is just weakness leaving the body!;Run! Your fat is catching up to you;Never forget leg day!;Push out!;This is the only break you get today.;Don't cry, sweat!;Healthy is an outfit that looks good on everybody." - icon_state = "fitness" - icon_vend = "fitness-vend" - icon_deny = "fitness-deny" + icon = 'icons/obj/machines/vending/fitness.dmi' vend_delay = 6 base_type = /obj/machinery/vending/fitness products = list( - /obj/item/chems/food/drinks/milk/smallcarton = 8, - /obj/item/chems/food/drinks/milk/smallcarton/chocolate = 8, - /obj/item/chems/food/drinks/cans/waterbottle = 8, - /obj/item/chems/food/drinks/glass2/fitnessflask/proteinshake = 8, - /obj/item/chems/food/drinks/glass2/fitnessflask = 8, - /obj/item/chems/food/snacks/candy/proteinbar = 8, - /obj/item/storage/mre/random = 8, - /obj/item/storage/mre/menu9 = 4, - /obj/item/storage/mre/menu10 = 4, + /obj/item/chems/drinks/milk/smallcarton = 8, + /obj/item/chems/drinks/milk/smallcarton/chocolate = 8, + /obj/item/chems/drinks/cans/waterbottle = 8, + /obj/item/chems/drinks/glass2/fitnessflask/proteinshake = 8, + /obj/item/chems/drinks/glass2/fitnessflask = 8, + /obj/item/food/junk/candy/proteinbar = 8, + /obj/item/mre/random = 8, + /obj/item/mre/menu9 = 4, + /obj/item/mre/menu10 = 4, /obj/item/towel/random = 8 ) contraband = list(/obj/item/chems/syringe/steroid = 4) @@ -267,22 +248,20 @@ /obj/machinery/vending/fitness/on_update_icon() ..() if(!(stat & NOPOWER)) - overlays += image(icon, "[initial(icon_state)]-overlay") + add_overlay("[initial(icon_state)]-overlay") /obj/machinery/vending/sovietsoda name = "BODA" desc = "An old soda vending machine. How could this have got here?" - icon_state = "sovietsoda" - icon_vend = "sovietsoda-vend" - icon_deny = "sovietsoda-deny" + icon = 'icons/obj/machines/vending/soviet.dmi' base_type = /obj/machinery/vending/sovietsoda product_ads = "For Tsar and Country.;Have you fulfilled your nutrition quota today?;Very nice!;We are simple people, for this is all we eat.;If there is a person, there is a problem. If there is no person, then there is no problem." products = list( - /obj/item/chems/food/drinks/cans/syndicola = 50, - /obj/item/chems/food/drinks/cans/syndicolax = 30, - /obj/item/chems/food/drinks/cans/artbru = 20, - /obj/item/chems/food/drinks/glass2/square/boda = 20, - /obj/item/chems/food/drinks/glass2/square/bodaplus = 20 + /obj/item/chems/drinks/cans/syndicola = 8, + /obj/item/chems/drinks/cans/syndicolax = 8, + /obj/item/chems/drinks/cans/artbru = 8, + /obj/item/chems/drinks/glass2/square/boda = 8, + /obj/item/chems/drinks/glass2/square/bodaplus = 8 ) - contraband = list(/obj/item/chems/food/drinks/bottle/space_up = 300) // TODO Russian cola can - idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. + contraband = list(/obj/item/chems/drinks/bottle/space_up = 8) // TODO Russian cola can + idle_power_usage = 211 diff --git a/code/game/machinery/vending/medical.dm b/code/game/machinery/vending/medical.dm index 7a8453e181a3..4796499cbe39 100644 --- a/code/game/machinery/vending/medical.dm +++ b/code/game/machinery/vending/medical.dm @@ -2,9 +2,7 @@ /obj/machinery/vending/medical name = "NanoMed Plus" desc = "Medical drug dispenser." - icon_state = "med" - icon_deny = "med-deny" - icon_vend = "med-vend" + icon = 'icons/obj/machines/vending/medical.dmi' vend_delay = 18 markup = 0 base_type = /obj/machinery/vending/medical @@ -18,10 +16,11 @@ /obj/item/chems/syringe/antibiotic = 4, /obj/item/chems/syringe = 12, /obj/item/scanner/health = 5, - /obj/item/chems/glass/beaker = 4, + /obj/item/scanner/breath = 5, + /obj/item/chems/glass/beaker = 4, /obj/item/chems/dropper = 2, - /obj/item/stack/medical/advanced/bruise_pack = 3, - /obj/item/stack/medical/advanced/ointment = 3, + /obj/item/stack/medical/bandage/advanced = 3, + /obj/item/stack/medical/ointment/advanced = 3, /obj/item/stack/medical/splint = 2, /obj/item/chems/hypospray/autoinjector/pain = 4 ) @@ -29,7 +28,7 @@ /obj/item/clothing/mask/chewable/candy/lolli/meds = 8, /obj/item/chems/pill/bromide = 3, /obj/item/chems/pill/stox = 4, - /obj/item/chems/pill/antitox = 6 + /obj/item/chems/pill/antitoxins = 6 ) idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan. @@ -37,39 +36,43 @@ name = "NanoMed" desc = "A wall-mounted version of the NanoMed." product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?" - icon_state = "wallmed" - icon_deny = "wallmed-deny" - icon_vend = "wallmed-vend" + icon = 'icons/obj/machines/vending/wallmed.dmi' base_type = /obj/machinery/vending/wallmed1 - density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude + density = FALSE //It is wall-mounted, and thus, not dense. --Superxpdude products = list( - /obj/item/stack/medical/bruise_pack = 3, + /obj/item/stack/medical/bandage = 3, /obj/item/stack/medical/ointment = 3, - /obj/item/chems/pill/painkillers = 4, - /obj/item/storage/med_pouch/trauma, - /obj/item/storage/med_pouch/burn, - /obj/item/storage/med_pouch/oxyloss, - /obj/item/storage/med_pouch/toxin + /obj/item/chems/pill/painkillers = 2, + /obj/item/chems/pill/strong_painkillers = 2, + /obj/item/med_pouch/trauma, + /obj/item/med_pouch/burn, + /obj/item/med_pouch/oxyloss, + /obj/item/med_pouch/toxin ) contraband = list(/obj/item/chems/syringe/antitoxin = 4,/obj/item/chems/syringe/antibiotic = 4,/obj/item/chems/pill/bromide = 1) + directional_offset = @'{"NORTH":{"y":-24}, "SOUTH":{"y":24}, "EAST":{"x":-24}, "WEST":{"x":24}}' + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED /obj/machinery/vending/wallmed2 name = "NanoMed Mini" desc = "A wall-mounted version of the NanoMed, containing only vital first aid equipment." product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?" - icon_state = "wallmed" - icon_deny = "wallmed-deny" - icon_vend = "wallmed-vend" - density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude + icon = 'icons/obj/machines/vending/wallmed.dmi' + density = FALSE //It is wall-mounted, and thus, not dense. --Superxpdude base_type = /obj/machinery/vending/wallmed2 products = list( - /obj/item/chems/hypospray/autoinjector = 5, - /obj/item/stack/medical/bruise_pack = 4, + /obj/item/chems/hypospray/autoinjector/stabilizer = 5, + /obj/item/stack/medical/bandage = 4, /obj/item/stack/medical/ointment = 4, - /obj/item/storage/med_pouch/trauma, - /obj/item/storage/med_pouch/burn, - /obj/item/storage/med_pouch/oxyloss, - /obj/item/storage/med_pouch/toxin, - /obj/item/storage/med_pouch/radiation + /obj/item/med_pouch/trauma, + /obj/item/med_pouch/burn, + /obj/item/med_pouch/oxyloss, + /obj/item/med_pouch/toxin, + /obj/item/med_pouch/radiation ) - contraband = list(/obj/item/chems/pill/bromide = 3, /obj/item/chems/hypospray/autoinjector/pain = 2) + contraband = list( + /obj/item/chems/pill/bromide = 3, + /obj/item/chems/hypospray/autoinjector/pain = 2 + ) + directional_offset = @'{"NORTH":{"y":-24}, "SOUTH":{"y":24}, "EAST":{"x":-24}, "WEST":{"x":24}}' + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED diff --git a/code/game/machinery/vending/misc.dm b/code/game/machinery/vending/misc.dm index 14a824777888..76360d927358 100644 --- a/code/game/machinery/vending/misc.dm +++ b/code/game/machinery/vending/misc.dm @@ -1,9 +1,7 @@ /obj/machinery/vending/magivend name = "MagiVend" desc = "A magic vending machine." - icon_state = "MagiVend" - icon_deny = "MagiVend-deny" - icon_vend = "MagiVend-vend" + icon = 'icons/obj/machines/vending/magic.dmi' product_slogans = "Sling spells the proper way with MagiVend!;Be your own Houdini! Use MagiVend!" vend_delay = 15 vend_reply = "Have an enchanted evening!" @@ -14,59 +12,58 @@ /obj/item/clothing/head/wizard/red = 1, /obj/item/clothing/suit/wizrobe/red = 1, /obj/item/clothing/shoes/sandal = 1, - /obj/item/staff = 2) + /obj/item/staff/crystal = 2) /obj/machinery/vending/dinnerware name = "Dinnerware" desc = "A kitchen and restaurant equipment vendor." product_ads = "Mm, food stuffs!;Food and food accessories.;Get your plates!;You like forks?;I like forks.;Woo, utensils.;You don't really need these..." - icon_state = "dinnerware" - icon_vend = "dinnerware-vend" - icon_deny = "dinnerware-deny" + icon = 'icons/obj/machines/vending/dinnerware.dmi' markup = 0 base_type = /obj/machinery/vending/dinnerware products = list( - /obj/item/chems/glass/beaker/bowl =2, - /obj/item/storage/tray/metal/aluminium = 8, + /obj/item/plate = 10, + /obj/item/plate/platter = 5, + /obj/item/chems/glass/beaker/bowl = 2, + /obj/item/plate/tray/metal/aluminium = 8, /obj/item/knife/kitchen = 3, - /obj/item/kitchen/rollingpin = 2, - /obj/item/chems/food/drinks/pitcher = 2, - /obj/item/chems/food/drinks/glass2/coffeecup = 8, - /obj/item/chems/food/drinks/glass2/coffeecup/teacup = 8, - /obj/item/chems/food/drinks/glass2/carafe = 2, - /obj/item/chems/food/drinks/glass2/square = 8, + /obj/item/rollingpin = 2, + /obj/item/chems/drinks/pitcher = 2, + /obj/item/chems/drinks/glass2/coffeecup = 8, + /obj/item/chems/drinks/glass2/coffeecup/teacup = 8, + /obj/item/chems/drinks/glass2/carafe = 2, + /obj/item/chems/drinks/glass2/square = 8, /obj/item/clothing/suit/chef/classic = 2, - /obj/item/storage/lunchbox = 3, - /obj/item/storage/lunchbox/heart = 3, - /obj/item/storage/lunchbox/cat = 3, - /obj/item/storage/lunchbox/mars = 3, - /obj/item/storage/lunchbox/cti = 3, - /obj/item/storage/lunchbox/syndicate = 3, + /obj/item/lunchbox = 3, + /obj/item/lunchbox/heart = 3, + /obj/item/lunchbox/cat = 3, + /obj/item/lunchbox/mars = 3, + /obj/item/lunchbox/cti = 3, + /obj/item/lunchbox/syndicate = 3, /obj/item/knife/kitchen/cleaver = 1 ) - contraband = list(/obj/item/knife/kitchen/cleaver/bronze = 1,/obj/item/storage/tray/metal/silver = 1) + contraband = list(/obj/item/knife/kitchen/cleaver/bronze = 1,/obj/item/plate/tray/metal/silver = 1) /obj/machinery/vending/fashionvend name = "Smashing Fashions" desc = "For all your cheap knockoff needs." product_slogans = "Look smashing for your darling!;Be rich! Dress rich!" - icon_state = "theater" + icon = 'icons/obj/machines/vending/theater.dmi' vend_delay = 15 base_type = /obj/machinery/vending/fashionvend vend_reply = "Absolutely smashing!" product_ads = "Impress the love of your life!;Don't look poor, look rich!;100% authentic designers!;All sales are final!;Lowest prices guaranteed!" products = list( /obj/item/mirror = 8, - /obj/item/haircomb = 8, - /obj/item/clothing/glasses/monocle = 5, + /obj/item/grooming/comb = 8, + /obj/item/clothing/glasses/eyepatch/monocle = 5, /obj/item/clothing/glasses/sunglasses = 5, - /obj/item/lipstick = 3, - /obj/random/lipstick = 3, - /obj/item/storage/wallet/poly = 2 + /obj/random/makeup = 3, + /obj/item/wallet/poly = 2 ) contraband = list( - /obj/item/clothing/glasses/eyepatch = 2, - /obj/item/clothing/accessory/horrible = 2, + /obj/item/clothing/glasses/eyepatch = 2, + /obj/item/clothing/neck/tie/horrible = 2, /obj/item/clothing/mask/smokable/pipe = 3 ) @@ -77,31 +74,29 @@ vend_delay = 15 product_slogans = "Escape to a fantasy world!;Fuel your gambling addiction!;Ruin your friendships!" product_ads = "Elves and dwarves!;Totally not satanic!;Fun times forever!" - icon_state = "games" - icon_deny = "games-deny" - icon_vend = "games-vend" + icon = 'icons/obj/machines/vending/games.dmi' base_type = /obj/machinery/vending/games products = list( - /obj/item/toy/blink = 5, - /obj/item/toy/eightball = 8, - /obj/item/deck/cards = 5, - /obj/item/deck/tarot = 5, + /obj/item/toy/blink = 5, + /obj/item/toy/eightball = 8, + /obj/item/deck/cards = 5, + /obj/item/deck/tarot = 5, /obj/item/deck/cag/white = 5, - /obj/item/deck/cag/black = 5, - /obj/item/pack/cardemon = 6, - /obj/item/pack/spaceball = 6, - /obj/item/storage/pill_bottle/dice_nerd = 5, - /obj/item/storage/pill_bottle/dice = 5, - /obj/item/storage/box/checkers = 2, - /obj/item/storage/box/checkers/chess/red = 2, - /obj/item/storage/box/checkers/chess = 2, + /obj/item/deck/cag/black = 5, + /obj/item/pack/cardemon = 6, + /obj/item/pack/spaceball = 6, + /obj/item/pill_bottle/dice_nerd = 5, + /obj/item/pill_bottle/dice = 5, + /obj/item/box/checkers = 2, + /obj/item/box/checkers/chess/red = 2, + /obj/item/box/checkers/chess = 2, /obj/item/board = 2 ) contraband = list( - /obj/item/chems/spray/waterflower = 2, - /obj/item/storage/box/snappops = 3, - /obj/item/spirit_board = 1, - /obj/item/gun/projectile/revolver/capgun = 1, + /obj/item/chems/spray/waterflower = 2, + /obj/item/box/snappops = 3, + /obj/item/spirit_board = 1, + /obj/item/gun/projectile/revolver/capgun = 1, /obj/item/ammo_magazine/caps = 4 ) @@ -111,17 +106,15 @@ name = "Lavatory Essentials" desc = "Vends things that make you less reviled in the work-place!" vend_delay = 15 - product_slogans = "Take a shower you hippie.;Get a haircut, hippie!;Reeking of vox taint? Take a shower!" - - icon_state = "lavatory" - icon_deny = "lavatory-deny" - icon_vend = "lavatory-vend" + product_slogans = "Take a shower you hippie.;Get a haircut, hippie!;Reeking of scale taint? Take a shower!" + icon = 'icons/obj/machines/vending/lavatory.dmi' base_type = /obj/machinery/vending/lavatory products = list( /obj/item/soap = 12, /obj/item/mirror = 8, - /obj/item/haircomb/random = 8, - /obj/item/haircomb/brush = 4, + /obj/item/grooming/comb/colorable/random = 8, + /obj/item/grooming/brush/colorable/random = 4, + /obj/item/grooming/file = 1, /obj/item/towel/random = 6, /obj/item/chems/spray/cleaner/deodorant = 5 ) diff --git a/code/game/machinery/vending/security.dm b/code/game/machinery/vending/security.dm index 7c85f221eddc..17b2a6cc88d8 100644 --- a/code/game/machinery/vending/security.dm +++ b/code/game/machinery/vending/security.dm @@ -3,9 +3,7 @@ name = "SecTech" desc = "A security equipment vendor." product_ads = "Crack capitalist skulls!;Beat some heads in!;Don't forget - harm is good!;Your weapons are right here.;Handcuffs!;Freeze, scumbag!;Don't tase me bro!;Tase them, bro.;Why not have a donut?" - icon_state = "sec" - icon_deny = "sec-deny" - icon_vend = "sec-vend" + icon = 'icons/obj/machines/vending/security.dmi' vend_delay = 14 markup = 0 base_type = /obj/machinery/vending/security @@ -15,7 +13,7 @@ /obj/item/grenade/flashbang = 4, /obj/item/grenade/chem_grenade/teargas = 4, /obj/item/flash = 5, - /obj/item/chems/food/snacks/donut/normal = 12, - /obj/item/storage/box/evidence = 6 + /obj/item/food/donut = 12, + /obj/item/box/evidence = 6 ) - contraband = list(/obj/item/clothing/glasses/sunglasses = 2,/obj/item/storage/box/donut = 2) + contraband = list(/obj/item/clothing/glasses/sunglasses = 2,/obj/item/box/fancy/donut = 2) diff --git a/code/game/machinery/vending_deconstruction.dm b/code/game/machinery/vending_deconstruction.dm index a9bf24b6dec2..57ab1eba0302 100644 --- a/code/game/machinery/vending_deconstruction.dm +++ b/code/game/machinery/vending_deconstruction.dm @@ -20,33 +20,40 @@ /obj/structure/vending_refill/get_mechanics_info() return "Drag to a vendor to restock. Generally can not be opened." -/obj/structure/vending_refill/MouseDrop(obj/machinery/vending/over) - if(!CanMouseDrop(over, usr)) - return - if(!istype(over)) - return ..() - var/target_type = over.base_type || over.type - if(!ispath(expected_type, target_type)) - return ..() - - for(var/datum/stored_items/R in product_records) - for(var/datum/stored_items/record in over.product_records) - if(record.merge(R)) - break - if(!QDELETED(R)) - R.migrate(over) - over.product_records += R +/obj/structure/vending_refill/handle_mouse_drop(atom/over, mob/user, params) + if(istype(over, /obj/machinery/vending)) + var/obj/machinery/vending/vendor = over + var/target_type = vendor.base_type || vendor.type + if(ispath(expected_type, target_type)) + for(var/datum/stored_items/product_record in product_records) + for(var/datum/stored_items/record in vendor.product_records) + if(record.merge(product_record)) + break + if(!QDELETED(product_record)) + product_record.migrate(over) + vendor.product_records += product_record + product_records = null + SSnano.update_uis(vendor) + qdel(src) + return TRUE + . = ..() - product_records = null - SSnano.update_uis(over) - qdel(src) +/obj/structure/vending_refill/get_contained_matter(include_reagents = TRUE) + . = ..() + for(var/datum/stored_items/vending_products/record in product_records) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., record.get_combined_matter(include_instances = FALSE)) + +/obj/machinery/vending/get_contained_matter(include_reagents = TRUE) + . = ..() + for(var/datum/stored_items/vending_products/record in product_records) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., record.get_combined_matter(include_instances = FALSE)) /obj/machinery/vending/dismantle() var/obj/structure/vending_refill/dump = new(loc) dump.SetName("[dump.name] ([name])") dump.expected_type = base_type || type - for(var/datum/stored_items/vending_products/R in product_records) - R.migrate(dump) + for(var/datum/stored_items/vending_products/product_record in product_records) + product_record.migrate(dump) dump.product_records = product_records product_records = null . = ..() \ No newline at end of file diff --git a/code/game/machinery/vitals_monitor.dm b/code/game/machinery/vitals_monitor.dm index bf25ec60ccb7..d62d255d74db 100644 --- a/code/game/machinery/vitals_monitor.dm +++ b/code/game/machinery/vitals_monitor.dm @@ -12,25 +12,25 @@ uncreated_component_parts = null construct_state = /decl/machine_construction/default/panel_closed - var/mob/living/carbon/human/victim + var/mob/living/human/victim var/beep = TRUE /obj/machinery/vitals_monitor/Destroy() victim = null . = ..() - -/obj/machinery/vitals_monitor/examine(mob/user) + +/obj/machinery/vitals_monitor/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(victim) if(stat & NOPOWER) - to_chat(user, SPAN_NOTICE("It's unpowered.")) + . += SPAN_NOTICE("It's unpowered.") return - to_chat(user, SPAN_NOTICE("Vitals of [victim]:")) - to_chat(user, SPAN_NOTICE("Pulse: [victim.get_pulse(GETPULSE_TOOL)]")) + . += SPAN_NOTICE("Vitals of [victim]:") + . += SPAN_NOTICE("Pulse: [victim.get_pulse_as_string(GETPULSE_TOOL)]") var/brain_activity = "none" - var/obj/item/organ/internal/brain/brain = victim.internal_organs_by_name[BP_BRAIN] - if(istype(brain) && victim.stat != DEAD && !(victim.status_flags & FAKEDEATH)) + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(victim, BP_BRAIN) + if(brain && victim.stat != DEAD && !(victim.status_flags & FAKEDEATH)) if(user.skill_check(SKILL_MEDICAL, SKILL_BASIC)) switch(brain.get_current_damage_threshold()) if(0 to 2) @@ -41,17 +41,17 @@ brain_activity = "extremely weak" else brain_activity = "some" - to_chat(user, SPAN_NOTICE("Brain activity: [brain_activity]")) + . += SPAN_NOTICE("Brain activity: [brain_activity]") var/breathing = "none" - var/obj/item/organ/internal/lungs/lungs = victim.internal_organs_by_name[BP_LUNGS] + var/obj/item/organ/internal/lungs/lungs = victim.get_organ(BP_LUNGS, /obj/item/organ/internal/lungs) if(istype(lungs) && !(victim.status_flags & FAKEDEATH)) if(lungs.breath_fail_ratio < 0.3) breathing = "normal" else if(lungs.breath_fail_ratio < 1) breathing = "shallow" - - to_chat(user, SPAN_NOTICE("Breathing: [breathing]")) + + . += SPAN_NOTICE("Breathing: [breathing]") /obj/machinery/vitals_monitor/Process() if(QDELETED(victim)) @@ -61,19 +61,19 @@ update_use_power(POWER_USE_IDLE) if(victim) update_icon() - if(beep && victim && victim.pulse()) - playsound(src, 'sound/machines/quiet_beep.ogg') - -/obj/machinery/vitals_monitor/MouseDrop(over_object, src_location, over_location) - if(!CanMouseDrop(over_object)) - return - if(victim) - victim = null - update_use_power(POWER_USE_IDLE) - else if(ishuman(over_object)) - victim = over_object + if(beep && victim && victim.get_pulse()) + playsound(src, 'sound/machines/quiet_beep.ogg', 40) + +/obj/machinery/vitals_monitor/handle_mouse_drop(atom/over, mob/user, params) + if(ishuman(over)) + if(victim) + victim = null + update_use_power(POWER_USE_IDLE) + victim = over update_use_power(POWER_USE_ACTIVE) - visible_message(SPAN_NOTICE("\The [src] is now showing data for [victim].")) + visible_message(SPAN_NOTICE("\The [src] is now showing data for \the [victim].")) + return TRUE + . = ..() /obj/machinery/vitals_monitor/on_update_icon() overlays.Cut() @@ -83,8 +83,8 @@ if(!victim) return - - switch(victim.pulse()) + + switch(victim.get_pulse()) if(PULSE_NONE) overlays += image(icon, icon_state = "pulse_flatline") overlays += image(icon, icon_state = "pulse_warning") @@ -96,7 +96,7 @@ overlays += image(icon, icon_state = "pulse_thready") overlays += image(icon, icon_state = "pulse_warning") - var/obj/item/organ/internal/brain/brain = victim.internal_organs_by_name[BP_BRAIN] + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(victim, BP_BRAIN) if(istype(brain) && victim.stat != DEAD && !(victim.status_flags & FAKEDEATH)) switch(brain.get_current_damage_threshold()) if(0 to 2) @@ -109,7 +109,7 @@ else overlays += image(icon, icon_state = "brain_warning") - var/obj/item/organ/internal/lungs/lungs = victim.internal_organs_by_name[BP_LUNGS] + var/obj/item/organ/internal/lungs/lungs = victim.get_organ(BP_LUNGS, /obj/item/organ/internal/lungs) if(istype(lungs) && !(victim.status_flags & FAKEDEATH)) if(lungs.breath_fail_ratio < 0.3) overlays += image(icon, icon_state = "breathing_normal") @@ -128,11 +128,11 @@ var/mob/user = usr if(!istype(user)) return - + if(CanPhysicallyInteract(user)) beep = !beep to_chat(user, SPAN_NOTICE("You turn the sound on \the [src] [beep ? "on" : "off"].")) - + /obj/item/stock_parts/circuitboard/vitals_monitor name = "circuit board (Vitals Monitor)" build_path = /obj/machinery/vitals_monitor diff --git a/code/game/machinery/wall_frames.dm b/code/game/machinery/wall_frames.dm index 8c2cba4294ce..13bf81ae5e2d 100644 --- a/code/game/machinery/wall_frames.dm +++ b/code/game/machinery/wall_frames.dm @@ -9,18 +9,17 @@ var/reverse = 0 //if resulting object faces opposite its dir (like light fixtures) var/fully_construct = FALSE // Results in a machine with all parts auto-installed and ready to go if TRUE; if FALSE, the machine will spawn without removable expected parts -/obj/item/frame/building_cost() +/obj/item/frame/get_contained_matter(include_reagents = TRUE) . = ..() if(fully_construct) var/list/cost = atom_info_repository.get_matter_for(build_machine_type) for(var/key in cost) .[key] += cost[key] -/obj/item/frame/attackby(obj/item/W, mob/user) - if(isWrench(W)) +/obj/item/frame/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) for(var/key in matter) - var/decl/material/material = decls_repository.get_decl(key) - material.place_sheet(get_turf(src), matter[key]/SHEET_MATERIAL_AMOUNT) + SSmaterials.create_object(key, get_turf(src), round(matter[key]/SHEET_MATERIAL_AMOUNT)) qdel(src) return TRUE . = ..() @@ -38,19 +37,19 @@ else ndir = get_dir(on_wall,usr) - if (!(ndir in GLOB.cardinal)) + if (!(ndir in global.cardinal)) return - var/turf/loc = get_turf(usr) - if (!istype(loc, /turf/simulated/floor)) + var/turf/my_turf = get_turf(usr) + if (!istype(my_turf) || !my_turf.simulated || !my_turf.is_floor()) to_chat(usr, "\The [src] cannot be placed on this spot.") return - if(gotwallitem(loc, get_dir(usr,on_wall))) // Use actual dir, not the new machine's dir + if(gotwallitem(my_turf, get_dir(usr,on_wall))) // Use actual dir, not the new machine's dir to_chat(usr, "There's already an item on this wall!") return - var/obj/machinery/machine = new build_machine_type(loc, ndir, fully_construct) + var/obj/machinery/machine = new build_machine_type(my_turf, ndir, fully_construct) modify_positioning(machine, ndir, click_params) if(istype(machine) && machine.construct_state && !fully_construct) machine.construct_state.post_construct(machine) @@ -81,31 +80,29 @@ name = "air alarm kit" desc = "An all-in-one air alarm kit, comes preassembled." -/obj/item/frame/light - name = "light fixture frame" - desc = "Used for building lights." - icon = 'icons/obj/lighting.dmi' - icon_state = "tube-construct-item" - build_machine_type = /obj/machinery/light/buildable - reverse = 1 - -/obj/item/frame/light/small - name = "small light fixture frame" - icon_state = "bulb-construct-item" - material = /decl/material/solid/metal/steel - build_machine_type = /obj/machinery/light/small/buildable +/obj/item/frame/wall_router + name = "wall-mounted router frame" + desc = "Used for building wall-mounted network routers." + icon = 'icons/obj/machines/wall_router.dmi' + icon_state = "wall_router_o_off" + build_machine_type = /obj/machinery/network/router/wall_mounted -/obj/item/frame/light/spot - name = "spotlight fixture frame" - icon_state = "tube-construct-item" - material = /decl/material/solid/metal/steel - build_machine_type = /obj/machinery/light/spot/buildable +/obj/item/frame/wall_router/kit + fully_construct = TRUE + name = "wall-mounted router kit" + desc = "An all-in-one wall-mounted router kit, comes preassembled." -/obj/item/frame/light/nav - name = "navigation light fixture frame" - icon_state = "tube-construct-item" - material = /decl/material/solid/metal/steel - build_machine_type = /obj/machinery/light/navigation/buildable +/obj/item/frame/wall_relay + name = "wall-mounted relay frame" + desc = "Used for building wall-mounted network relays." + icon = 'icons/obj/machines/wall_router.dmi' + icon_state = "wall_router_o_off" + build_machine_type = /obj/machinery/network/relay/wall_mounted + +/obj/item/frame/wall_relay/kit + fully_construct = TRUE + name = "wall-mounted relay kit" + desc = "An all-in-one wall-mounted relay kit, comes preassembled." /obj/item/frame/button name = "button frame" @@ -114,25 +111,47 @@ material = /decl/material/solid/metal/steel build_machine_type = /obj/machinery/button/buildable -/obj/item/frame/button/modify_positioning(var/obj/machinery/button/product, _dir, click_params) - var/list/params = params2list(click_params) - var/_pixel_x = text2num(params["icon-x"]) - WORLD_ICON_SIZE/2 //Make it relative to center instead of bottom left - var/_pixel_y = text2num(params["icon-y"]) - WORLD_ICON_SIZE/2 - switch(_dir) - if(NORTH) - _pixel_y = max(_pixel_y, WORLD_ICON_SIZE/4) - _pixel_y -= WORLD_ICON_SIZE - if(SOUTH) - _pixel_y = min(_pixel_y, WORLD_ICON_SIZE/4) - _pixel_y += WORLD_ICON_SIZE - if(EAST) - _pixel_x = max(_pixel_x, 0) - _pixel_x -= WORLD_ICON_SIZE - if(WEST) - _pixel_x = min(_pixel_x, 0) - _pixel_x += WORLD_ICON_SIZE - product.pixel_x = _pixel_x - product.pixel_y = _pixel_y +/obj/item/frame/button/kit + fully_construct = TRUE + name = "radio button kit" + desc = "An all-in-one wall-mounted button kit, comes preassembled and equipped with a radio transmitter." + build_machine_type = /obj/machinery/button + +/obj/item/frame/button/alternate + name = "button frame (door)" + icon = 'icons/obj/machines/button_door.dmi' + icon_state = "doorctrl" + build_machine_type = /obj/machinery/button/alternate/buildable + +/obj/item/frame/button/alternate/kit + fully_construct = TRUE + name = "button kit (door)" + desc = "An all-in-one wall-mounted button kit, comes preassembled and equipped with a radio transmitter." + build_machine_type = /obj/machinery/button/alternate + +/obj/item/frame/button/blastdoor + name = "button frame (blast doors)" + icon = 'icons/obj/machines/button_blastdoor.dmi' + icon_state = "blastctrl" + build_machine_type = /obj/machinery/button/blast_door/buildable + +/obj/item/frame/button/blastdoor/kit + fully_construct = TRUE + name = "button kit (blast doors)" + desc = "An all-in-one wall-mounted button kit, comes preassembled and equipped with a radio transmitter." + build_machine_type = /obj/machinery/button/blast_door + +/obj/item/frame/camera + name = "security camera frame" + icon = 'icons/obj/monitors.dmi' + icon_state = "cameracase" + material = /decl/material/solid/metal/aluminium + build_machine_type = /obj/machinery/camera + +/obj/item/frame/camera/kit + fully_construct = TRUE + name = "security camera kit" + desc = "An all-in-one wall-mounted security camera kit, comes preassembled." /obj/item/frame/button/wall_charger name = "wall charger frame" @@ -158,22 +177,14 @@ reverse = TRUE /obj/item/frame/stock_offset/modify_positioning(var/obj/machinery/product, _dir, click_params) - switch(_dir) - if(NORTH) - product.pixel_y = WORLD_ICON_SIZE - if(SOUTH) - product.pixel_y = - WORLD_ICON_SIZE - if(EAST) - product.pixel_x = WORLD_ICON_SIZE - if(WEST) - product.pixel_x = - WORLD_ICON_SIZE + product.update_directional_offset() /obj/item/frame/stock_offset/request_console name = "request console frame" desc = "Used for building request consoles." icon = 'icons/obj/terminals.dmi' icon_state = "req_comp0" - build_machine_type = /obj/machinery/requests_console + build_machine_type = /obj/machinery/network/requests_console /obj/item/frame/stock_offset/request_console/kit fully_construct = TRUE @@ -202,31 +213,238 @@ name = "newscaster kit" fully_construct = TRUE -/obj/item/frame/button/airlock_sensor - icon = 'icons/obj/airlock_machines.dmi' - icon_state = "airlock_sensor_off" - name = "airlock sensor" - desc = "An airlock sensor frame." - build_machine_type = /obj/machinery/airlock_sensor/buildable - +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// Airlock Controller Frame +//////////////////////////////////////////////////////////////////////////////////////////////////////// /obj/item/frame/button/airlock_controller icon = 'icons/obj/airlock_machines.dmi' icon_state = "airlock_control_off" name = "airlock controller frame" - desc = "Used to build airlock controllers. Use a multitool on the circuit to determine which type you want, and then hit this with the the circuit." + desc = "Used to build airlock controllers. Use a multitool on the circuit to determine which type you want, and then hit this with the circuit." build_machine_type = null + ///Used when configuring a dummy controller + var/master_controller_id_tag + +/obj/item/frame/button/airlock_controller/modify_positioning(obj/machinery/product, _dir, click_params) + if(length(master_controller_id_tag)) + product.set_id_tag(master_controller_id_tag) + . = ..() + +/obj/item/frame/button/airlock_controller/proc/warn_not_setup(var/mob/user) + to_chat(user, SPAN_WARNING("First hit this with a circuitboard to properly setup the controller's software!")) /obj/item/frame/button/airlock_controller/try_build(turf/on_wall, click_params) if(!build_machine_type) - to_chat(usr, SPAN_WARNING("First hit this with a circuitboard to configure it!")) + warn_not_setup(usr) return return ..() -/obj/item/frame/button/airlock_controller/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/stock_parts/circuitboard)) - var/obj/item/stock_parts/circuitboard/board = W - if(ispath(board.build_path, /obj/machinery/embedded_controller/radio)) - build_machine_type = board.build_path - to_chat(user, SPAN_NOTICE("You configure \the [src] using \the [W].")) - return TRUE +/obj/item/frame/button/airlock_controller/afterattack(obj/machinery/embedded_controller/radio/target, mob/user, proximity_flag, click_parameters) + if((. = ..()) || !ispath(build_machine_type, /obj/machinery/dummy_airlock_controller)) + return . + if(istype(target, /obj/machinery/dummy_airlock_controller)) + var/obj/machinery/dummy_airlock_controller/D = target + target = D.master_controller + . = TRUE + if(istype(target)) + master_controller_id_tag = target.id_tag + to_chat(user, SPAN_NOTICE("You successfully link \the [src]'s master ID tag with \the [target]'s ID tag. \The [src] should now work with \the [target] with the default settings.")) + return TRUE + master_controller_id_tag = null + +/obj/item/frame/button/airlock_controller/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/stock_parts/circuitboard)) + return ..() + var/obj/item/stock_parts/circuitboard/board = used_item + var/obj/machinery/M + if(ispath(board.build_path, /obj/machinery/embedded_controller/radio)) + build_machine_type = board.build_path + . = TRUE + if(ispath(board.build_path, /obj/machinery/dummy_airlock_controller)) + build_machine_type = board.build_path + . = TRUE + if(.) + M = build_machine_type + to_chat(user, SPAN_NOTICE("You setup \the [src]'s software to work as a '[initial(M.name)]', using \the [used_item].")) + return TRUE + return FALSE + +/obj/item/frame/button/airlock_controller/kit + fully_construct = TRUE + name = "airlock controller kit" + desc = "An all-in-one airlock controller kit, comes preassembled with a radio transmitter. Use a multitool on the kit to select what type of controller to build." + build_machine_type = /obj/machinery/embedded_controller/radio/airlock/airlock_controller //Must set a default one, otherwise building_cost calcs will fail + +/obj/item/frame/button/airlock_controller/kit/warn_not_setup(mob/user) + to_chat(user, SPAN_WARNING("First, use a multitool on the kit to properly setup the controller's software!")) + +//Let them also hit it with a circuitboard if they so wish. But multitool is better when you don't want to print one for nothing. +/obj/item/frame/button/airlock_controller/kit/attackby(obj/item/used_item, mob/user) + if(!IS_MULTITOOL(used_item)) + return ..() + //Handle kit configuration + var/obj/machinery/M = /obj/machinery/dummy_airlock_controller + var/list/possible_kit_type_names = list(initial(M.name) = /obj/machinery/dummy_airlock_controller) + var/static/list/AirlockControllerSubtypes = subtypesof(/obj/machinery/embedded_controller/radio) | subtypesof(/obj/machinery/embedded_controller/radio/airlock) + + for(var/path in AirlockControllerSubtypes) + var/obj/machinery/embedded_controller/radio/controller = path + var/base_type = initial(controller.base_type) || path + M = base_type + possible_kit_type_names[initial(M.name)] = base_type + + var/choice = input(user, "Chose the type of controller to build:", "Select Controller Type") as null|anything in possible_kit_type_names + if(!choice || !CanPhysicallyInteract(user)) + build_machine_type = initial(build_machine_type) + return TRUE + build_machine_type = possible_kit_type_names[choice] + M = build_machine_type + to_chat(user, SPAN_NOTICE("You set the kit type to '[initial(M.name)]'!")) + return TRUE + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// Airlock controller setup abstract +//////////////////////////////////////////////////////////////////////////////////////////////////////// +///Base class for handling configurable airlock devices frames that want to get configuration info from an airlock controller +/obj/item/frame/button/airlock_controller_config + abstract_type = /obj/item/frame/button/airlock_controller_config + ///Stores the id tag of the controller we hit this with, to make setup easier + var/preferred_id_tag + +/obj/item/frame/button/airlock_controller_config/modify_positioning(obj/machinery/product, _dir, click_params) + if(length(preferred_id_tag)) + product.set_id_tag(preferred_id_tag) . = ..() + +///Returns the list of types of device options we can configure this as +/obj/item/frame/button/airlock_controller_config/proc/get_setup_option_choices() + return + +///Actually applies the changes to the thing based on the setup option picked +/obj/item/frame/button/airlock_controller_config/proc/setup_for_chosen_type(obj/machinery/embedded_controller/radio/target, var/choice) + return + +///Returns the master controller from the target machine whether its a dummy controller or an actual controller +/obj/item/frame/button/airlock_controller_config/proc/get_master_controller(obj/machinery/embedded_controller/radio/target, mob/user) + if(istype(target)) + return target + //If we hit a dummy controller just try to grab the master controller + if(istype(target, /obj/machinery/dummy_airlock_controller)) + var/obj/machinery/dummy_airlock_controller/dummy_controller = target + if(dummy_controller.master_controller) + return dummy_controller.master_controller + else + to_chat(user, SPAN_WARNING("\The [target] isn't connected to a master controller. Please use \the [src] on the master controller of this airlock system, or connect \the [target] to a master controller.")) + return + +/obj/item/frame/button/airlock_controller_config/afterattack(obj/machinery/embedded_controller/radio/target, mob/user, proximity_flag, click_parameters) + if((. = ..())) + return . + var/obj/machinery/dummy_airlock_controller/dummy_controller = istype(target, /obj/machinery/dummy_airlock_controller)? target : null + target = get_master_controller(target, user) + if(!istype(target)) + return + + if(!length(target.id_tag)) + to_chat(user, SPAN_WARNING("\The [target] doesn't have its ID tag set! Please set a valid ID tag on it first! [dummy_controller? "** Note that this is a remote controller. You must set the ID tag on the master controller. **" : ""]")) + return + + var/choice = input(user, "Configure as what?", "Connection Setup") as null|anything in get_setup_option_choices() + if(!choice || (dummy_controller && !CanPhysicallyInteractWith(user, dummy_controller)) || (!dummy_controller && !CanPhysicallyInteract(user))) + build_machine_type = initial(build_machine_type) + preferred_id_tag = null + return //Cancelled or can't use either the dummy controller or the actual controller + setup_for_chosen_type(target, choice) + to_chat(user, SPAN_NOTICE("You successfully link \the [src]'s ID tag with \the [target]'s ID tag. \The [src] should now work with \the [target] with the default settings.")) + return TRUE + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// Airlock Sensor Frame +//////////////////////////////////////////////////////////////////////////////////////////////////////// +/obj/item/frame/button/airlock_controller_config/airlock_sensor + icon = 'icons/obj/machines/airlock_sensor.dmi' + icon_state = ICON_STATE_WORLD + name = "airlock sensor" + desc = "An airlock sensor frame. Use on an airlock controller to pre-configure it." + build_machine_type = /obj/machinery/airlock_sensor/buildable + +#define CHOICE_INTERIOR_SENSOR "interior sensor" +#define CHOICE_EXTERIOR_SENSOR "exterior sensor" +#define CHOICE_CHAMBER_SENSOR "airlock chamber sensor" + +/obj/item/frame/button/airlock_controller_config/airlock_sensor/get_setup_option_choices() + return list( + CHOICE_INTERIOR_SENSOR, + CHOICE_CHAMBER_SENSOR, + CHOICE_EXTERIOR_SENSOR, + ) + +/obj/item/frame/button/airlock_controller_config/airlock_sensor/setup_for_chosen_type(obj/machinery/embedded_controller/radio/target, var/choice) + switch(choice) + if(CHOICE_INTERIOR_SENSOR) + preferred_id_tag = "[target.id_tag]_interior_sensor" + return TRUE + if(CHOICE_EXTERIOR_SENSOR) + preferred_id_tag = "[target.id_tag]_exterior_sensor" + return TRUE + if(CHOICE_CHAMBER_SENSOR) + preferred_id_tag = "[target.id_tag]_sensor" + return TRUE + else + preferred_id_tag = null + +/obj/item/frame/button/airlock_controller_config/airlock_sensor/kit + fully_construct = TRUE + name = "airlock sensor kit" + desc = "An all-in-one airlock sensor kit, comes preassembled with a radio transmitter. Use on an airlock controller to pre-configure it." + build_machine_type = /obj/machinery/airlock_sensor + +#undef CHOICE_INTERIOR_SENSOR +#undef CHOICE_EXTERIOR_SENSOR +#undef CHOICE_CHAMBER_SENSOR + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// Airlock Access Button Frame +//////////////////////////////////////////////////////////////////////////////////////////////////////// +#define CHOICE_INTERIOR_BUTTON "interior button" +#define CHOICE_EXTERIOR_BUTTON "exterior button" +/obj/item/frame/button/airlock_controller_config/access + name = "button frame (airlock)" + desc = "Use on an airlock controller to pre-configure it." + icon = 'icons/obj/machines/button_airlock.dmi' + icon_state = ICON_STATE_WORLD + build_machine_type = /obj/machinery/button/access/buildable + ///The type of the interior button to build for this frame + var/interior_button_type = /obj/machinery/button/access/interior/buildable + ///The type of the exterior button to build for this frame + var/exterior_button_type = /obj/machinery/button/access/exterior/buildable + +/obj/item/frame/button/airlock_controller_config/access/get_setup_option_choices() + return list( + CHOICE_INTERIOR_BUTTON, + CHOICE_EXTERIOR_BUTTON, + ) + +/obj/item/frame/button/airlock_controller_config/access/setup_for_chosen_type(obj/machinery/embedded_controller/radio/target, choice) + preferred_id_tag = target.id_tag + switch(choice) + if(CHOICE_INTERIOR_BUTTON) + build_machine_type = interior_button_type + return TRUE + if(CHOICE_EXTERIOR_BUTTON) + build_machine_type = exterior_button_type + return TRUE + else + build_machine_type = initial(build_machine_type) + preferred_id_tag = null + +/obj/item/frame/button/airlock_controller_config/access/kit + fully_construct = TRUE + name = "button kit (airlock)" + desc = "An all-in-one wall-mounted button kit, comes preassembled and equipped with a radio transmitter. Use on an airlock controller to pre-configure it." + build_machine_type = /obj/machinery/button/access + interior_button_type = /obj/machinery/button/access/interior + exterior_button_type = /obj/machinery/button/access/exterior + +#undef CHOICE_INTERIOR_BUTTON +#undef CHOICE_EXTERIOR_BUTTON \ No newline at end of file diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 510a61674ee4..00387a12bbbc 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -1,37 +1,180 @@ #define WASHER_STATE_CLOSED 1 -#define WASHER_STATE_FULL 2 +#define WASHER_STATE_LOADED 2 #define WASHER_STATE_RUNNING 4 #define WASHER_STATE_BLOODY 8 -// WASHER_STATE_RUNNING implies WASHER_STATE_CLOSED | WASHER_STATE_FULL +// WASHER_STATE_RUNNING implies WASHER_STATE_CLOSED | WASHER_STATE_LOADED // if you break this assumption, you must update the icon file // other states are independent. /obj/machinery/washing_machine - name = "Washing Machine" + name = "washing machine" + desc = "A commercial washing machine used to wash clothing items and linens. It requires detergent for efficient washing." icon = 'icons/obj/machines/washing_machine.dmi' icon_state = "wm_00" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 - var/state = 0 - var/gibs_ready = 0 - var/obj/crayon - var/obj/item/chems/pill/detergent/detergent obj_flags = OBJ_FLAG_ANCHORABLE clicksound = "button" clickvol = 40 + chem_volume = 100 // Power idle_power_usage = 10 active_power_usage = 150 -/obj/machinery/washing_machine/Destroy() - QDEL_NULL(crayon) - QDEL_NULL(detergent) + var/state = 0 + var/gibs_ready = FALSE + var/max_item_size = ITEM_SIZE_LARGE + +/obj/machinery/washing_machine/proc/get_wash_whitelist() + var/static/list/wash_whitelist = list( + /obj/item/clothing/costume, + /obj/item/clothing/shirt, + /obj/item/clothing/pants, + /obj/item/clothing/skirt, + /obj/item/clothing/dress, + /obj/item/clothing/mask, + /obj/item/clothing/head, + /obj/item/clothing/gloves, + /obj/item/clothing/shoes, + /obj/item/clothing/suit, + /obj/item/bedsheet, + /obj/item/underwear + ) + return wash_whitelist + +/obj/machinery/washing_machine/proc/get_wash_blacklist() + var/static/list/wash_blacklist = list( + /obj/item/clothing/suit/space, + /obj/item/clothing/suit/syndicatefake, + /obj/item/clothing/suit/bomb_suit, + /obj/item/clothing/suit/armor, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/smokable/cigarette, + /obj/item/clothing/head/helmet + ) + return wash_blacklist + +/obj/machinery/washing_machine/get_examine_strings(mob/user, distance, infix, suffix) . = ..() + . += SPAN_NOTICE("The detergent port is [atom_flags & ATOM_FLAG_OPEN_CONTAINER ? "open" : "closed"].") + +/obj/machinery/washing_machine/proc/wash() + if(operable()) + var/list/washing_atoms = get_contained_external_atoms() + var/amount_per_atom = floor(REAGENT_TOTAL_VOLUME(reagents) / length(washing_atoms)) + + if(amount_per_atom > 0) + var/decl/material/smelliest = get_smelliest_reagent(reagents) + for(var/atom/A as anything in get_contained_external_atoms()) + + // Handles washing, decontamination, dyeing, etc. + reagents.trans_to(A, amount_per_atom) + + if(istype(A, /obj/item/clothing)) + var/obj/item/clothing/C = A + C.ironed_state = WRINKLES_WRINKLY + if(smelliest) + C.change_smell(smelliest) + + // Clear out whatever remains of the reagents. + reagents.clear_reagents() + + if(locate(/mob/living) in src) + gibs_ready = TRUE + + state &= ~WASHER_STATE_RUNNING + update_use_power(POWER_USE_IDLE) + +/obj/machinery/washing_machine/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/chems/pill/detergent)) + if(!(atom_flags & ATOM_FLAG_OPEN_CONTAINER)) + to_chat(user, SPAN_WARNING("Open the detergent port first!")) + return TRUE + if(REAGENT_TOTAL_VOLUME(reagents) >= REAGENT_MAXIMUM_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("The detergent port is full!")) + return TRUE + if(!user.try_unequip(used_item)) + return TRUE + // Directly transfer to the holder to avoid touch reactions. + used_item.reagents?.trans_to_holder(reagents, REAGENT_TOTAL_VOLUME(used_item.reagents)) + to_chat(user, SPAN_NOTICE("You dissolve \the [used_item] in the detergent port.")) + qdel(used_item) + return TRUE + + if(state & WASHER_STATE_RUNNING) + to_chat(user, SPAN_WARNING("\The [src] is currently running.")) + return TRUE + + if((. = ..())) + return + + // If the detergent port is open and the item is an open container, assume we're trying to fill the detergent port. + if(!(state & WASHER_STATE_CLOSED) && !((atom_flags & used_item.atom_flags) & ATOM_FLAG_OPEN_CONTAINER)) + var/list/wash_whitelist = get_wash_whitelist() + var/list/wash_blacklist = get_wash_blacklist() + var/list/washing_atoms = get_contained_external_atoms() + if(length(washing_atoms) < 5) + if(istype(used_item, /obj/item/holder)) // Mob holder + for(var/mob/living/doggy in used_item) + doggy.forceMove(src) + qdel(used_item) + state |= WASHER_STATE_LOADED + update_icon() + return TRUE + + // An empty whitelist implies all items can be washed. + else if((!length(wash_whitelist) || is_type_in_list(used_item, wash_whitelist)) && !is_type_in_list(used_item, wash_blacklist)) + if(used_item.w_class > max_item_size) + to_chat(user, SPAN_WARNING("\The [used_item] is too large for \the [src]!")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + state |= WASHER_STATE_LOADED + update_icon() + else + to_chat(user, SPAN_WARNING("You can't put \the [used_item] in \the [src].")) + return TRUE + else + to_chat(user, SPAN_NOTICE("\The [src] is full.")) + return TRUE + +/obj/machinery/washing_machine/physical_attack_hand(mob/user) + if(state & WASHER_STATE_RUNNING) + to_chat(user, SPAN_WARNING("\The [src] is currently running.")) + return TRUE + if(state & WASHER_STATE_CLOSED) + state &= ~WASHER_STATE_CLOSED + if(gibs_ready) + gibs_ready = FALSE + var/mob/M = locate(/mob/living) in src + if(M) + M.gib() + dump_contents() + state &= ~WASHER_STATE_LOADED + update_icon() + return TRUE + state |= WASHER_STATE_CLOSED + update_icon() + return TRUE + +/obj/machinery/washing_machine/verb/climb_out() + set name = "Climb out" + set category = "Object" + set src in usr.loc + + if(!CanPhysicallyInteract(usr)) + return + if(state & WASHER_STATE_CLOSED) + to_chat(usr, SPAN_WARNING("\The [src] is closed.")) + return + if(!do_after(usr, 2 SECONDS, src)) + return + if(!(state & WASHER_STATE_CLOSED)) + usr.dropInto(loc) /obj/machinery/washing_machine/verb/start() set name = "Start Washing" @@ -41,179 +184,114 @@ if(!CanPhysicallyInteract(usr)) return - if(!anchored) - to_chat(usr, "\The [src] must be secured to the floor.") - return + start_washing(usr) +/obj/machinery/washing_machine/proc/start_washing(mob/user) if(state & WASHER_STATE_RUNNING) - to_chat(usr, "\The [src] is already running.") - return - if(!(state & WASHER_STATE_FULL)) - to_chat(usr, "Load \the [src] first!") + to_chat(user, SPAN_WARNING("\The [src] is already running!")) return if(!(state & WASHER_STATE_CLOSED)) - to_chat(usr, "You must first close the machine.") + to_chat(user, SPAN_WARNING("You must first close \the [src].")) + return + if(!(state & WASHER_STATE_LOADED)) + to_chat(user, SPAN_WARNING("Load \the [src] first!!")) + return + if(!operable()) + to_chat(user, SPAN_WARNING("\The [src] isn't functioning!")) return - if(stat & NOPOWER) - to_chat(usr, SPAN_WARNING("\The [src] is unpowered.")) + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("There are no cleaning products loaded in \the [src]!")) return + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + state |= WASHER_STATE_RUNNING if(locate(/mob/living) in src) state |= WASHER_STATE_BLOODY update_use_power(POWER_USE_ACTIVE) - update_icon() - addtimer(CALLBACK(src, /obj/machinery/washing_machine/proc/wash), 20 SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/washing_machine, wash)), 20 SECONDS) -/obj/machinery/washing_machine/proc/wash() - for(var/atom/A in (contents - component_parts)) - if(detergent) - A.clean_blood() - if(isitem(A)) - var/obj/item/I = A - if(detergent) - I.decontaminate() - if(crayon && iscolorablegloves(I)) - var/obj/item/clothing/gloves/C = I - C.color = crayon.color - if(istype(A, /obj/item/clothing)) - var/obj/item/clothing/C = A - C.ironed_state = WRINKLES_WRINKLY - if(detergent) - C.change_smell(SMELL_CLEAN) - addtimer(CALLBACK(C, /obj/item/clothing/proc/change_smell), detergent.smell_clean_time, TIMER_UNIQUE | TIMER_OVERRIDE) - QDEL_NULL(detergent) - - update_use_power(POWER_USE_IDLE) - if(locate(/mob/living) in src) - gibs_ready = 1 - state &= ~WASHER_STATE_RUNNING - update_icon() + return TRUE -/obj/machinery/washing_machine/verb/climb_out() - set name = "Climb out" +/obj/machinery/washing_machine/verb/toggle_port() + set name = "Toggle Detergent Port" set category = "Object" - set src in usr.loc + set src in oview(1) if(!CanPhysicallyInteract(usr)) return - if(state & WASHER_STATE_CLOSED) - to_chat(usr, SPAN_WARNING("\The [src] is closed.")) - return - if(!do_after(usr, 2 SECONDS, src)) + + toggle_detergent_port(usr) + +/obj/machinery/washing_machine/proc/toggle_detergent_port(mob/user) + if(state & WASHER_STATE_RUNNING) + to_chat(user, SPAN_WARNING("You can't open the detergent port while \the [src] is running!")) return - if(!(state & WASHER_STATE_CLOSED)) - usr.dropInto(loc) + + if(atom_flags & ATOM_FLAG_OPEN_CONTAINER) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + to_chat(user, SPAN_NOTICE("You close the detergent port on \the [src].")) + else + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + to_chat(user, SPAN_NOTICE("You open the detergent port on \the [src].")) + + return TRUE + +/obj/machinery/washing_machine/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/start_washer) + LAZYADD(., /decl/interaction_handler/toggle_open/washing_machine) + +/decl/interaction_handler/start_washer + name = "Start washer" + expected_target_type = /obj/machinery/washing_machine + examine_desc = "start a wash cycle" + +/decl/interaction_handler/start_washer/is_possible(obj/machinery/washing_machine/washer, mob/user) + . = ..() + if(.) + return washer.operable() && !(washer.state & WASHER_STATE_RUNNING) + +/decl/interaction_handler/start_washer/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/washing_machine/washer = target + return washer.start_washing(user) + +/decl/interaction_handler/toggle_open/washing_machine + name = "Toggle detergent port" + expected_target_type = /obj/machinery/washing_machine + examine_desc = "open the detergent port" + +/decl/interaction_handler/toggle_open/washing_machine/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/washing_machine/washer = target + return washer.toggle_detergent_port(user) /obj/machinery/washing_machine/on_update_icon() icon_state = "wm_[state][panel_open]" -/obj/machinery/washing_machine/clean_blood() +/obj/machinery/washing_machine/clean(clean_forensics = TRUE) . = ..() state &= ~WASHER_STATE_BLOODY - update_icon() + update_icon() /obj/machinery/washing_machine/components_are_accessible(path) return !(state & WASHER_STATE_RUNNING) && ..() -/obj/machinery/washing_machine/attackby(obj/item/W, mob/user) - if(!(state & WASHER_STATE_CLOSED)) - if(!crayon && istype(W,/obj/item/pen/crayon)) - if(!user.unEquip(W, src)) - return - crayon = W - return TRUE - if(!detergent && istype(W,/obj/item/chems/pill/detergent)) - if(!user.unEquip(W, src)) - return - detergent = W - return TRUE - if(istype(W, /obj/item/holder)) // Mob holder - for(var/mob/living/doggy in W) - doggy.forceMove(src) - qdel(W) - state |= WASHER_STATE_FULL - update_icon() - return TRUE - - else if(istype(W,/obj/item/clothing/under) || \ - istype(W,/obj/item/clothing/mask) || \ - istype(W,/obj/item/clothing/head) || \ - istype(W,/obj/item/clothing/gloves) || \ - istype(W,/obj/item/clothing/shoes) || \ - istype(W,/obj/item/clothing/suit) || \ - istype(W,/obj/item/bedsheet) || \ - istype(W,/obj/item/underwear/)) - - //YES, it's hardcoded... saves a var/can_be_washed for every single clothing item. - if ( istype(W,/obj/item/clothing/suit/space ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/syndicatefake ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/bomb_suit ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/armor ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/armor ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/mask/gas ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/mask/smokable/cigarette ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/head/helmet ) ) - to_chat(user, "This item does not fit.") - return - - if(contents.len < 5) - if(!(state & WASHER_STATE_CLOSED)) - if(!user.unEquip(W, src)) - return - state |= WASHER_STATE_FULL - update_icon() - else - to_chat(user, SPAN_NOTICE("You can't put the item in right now.")) - else - to_chat(user, SPAN_NOTICE("\The [src] is full")) - return TRUE - - if(state & WASHER_STATE_RUNNING) - to_chat(user, SPAN_WARNING("\The [src] is currently running.")) - return TRUE +/obj/machinery/washing_machine/autoclave + name = "autoclave" + desc = "An industrial washing machine used to sterilize and decontaminate items. It requires detergent for efficient decontamination." + max_item_size = ITEM_SIZE_HUGE + idle_power_usage = 10 + active_power_usage = 300 - return ..() +/obj/machinery/washing_machine/autoclave/get_wash_whitelist() + return -/obj/machinery/washing_machine/physical_attack_hand(mob/user) - if(state & WASHER_STATE_RUNNING) - to_chat(user, SPAN_WARNING("\The [src] is busy.")) - return TRUE - if(state & WASHER_STATE_CLOSED) - state &= ~WASHER_STATE_CLOSED - if(gibs_ready) - gibs_ready = 0 - var/mob/M = locate(/mob/living) in src - if(M) - M.gib() - for(var/atom/movable/O in (contents - component_parts)) - O.dropInto(loc) - state &= ~WASHER_STATE_FULL - update_icon() - crayon = null - detergent = null - return TRUE - state |= WASHER_STATE_CLOSED - update_icon() - return TRUE +/obj/machinery/washing_machine/autoclave/get_wash_blacklist() + return #undef WASHER_STATE_CLOSED -#undef WASHER_STATE_FULL +#undef WASHER_STATE_LOADED #undef WASHER_STATE_RUNNING #undef WASHER_STATE_BLOODY \ No newline at end of file diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm deleted file mode 100644 index a0ed9f17a81f..000000000000 --- a/code/game/machinery/wishgranter.dm +++ /dev/null @@ -1,62 +0,0 @@ -/obj/machinery/wish_granter - name = "Wish Granter" - desc = "You're not so sure about this, anymore..." - icon = 'icons/obj/items/syndibeacon.dmi' - icon_state = "syndbeacon" - - use_power = POWER_USE_OFF - uncreated_component_parts = null - interact_offline = TRUE - anchored = 1 - density = 1 - - var/charges = 1 - var/insisting = 0 - -// Just override; we're special. -/obj/machinery/wish_granter/attack_hand(var/mob/user) - usr.set_machine(src) - - if(charges <= 0) - to_chat(user, "The Wish Granter lies silent.") - return - - else if(!istype(user, /mob/living/carbon/human)) - to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.") - return - - else if(is_special_character(user)) - to_chat(user, "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away.") - else if (!insisting) - to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?") - insisting++ - - else - var/message = "You speak. [pick("I want the [station_name()] to disappear","Humanity is corrupt, mankind must be destroyed","I want to be rich", "I want to rule the world","I want immortality.")]. The Wish Granter answers." - to_chat(user, message) - to_chat(user, "Your head pounds for a moment, before your vision clears. You are the avatar of the Wish Granter, and your power is LIMITLESS! And it's all yours. You need to make sure no one can take it from you. No one can know, first.") - charges-- - insisting = 0 - - if (!(MUTATION_HULK in user.mutations)) - user.mutations.Add(MUTATION_HULK) - - if (!(MUTATION_LASER in user.mutations)) - user.mutations.Add(MUTATION_LASER) - - if (!(MUTATION_XRAY in user.mutations)) - user.mutations.Add(MUTATION_XRAY) - user.set_sight(user.sight|SEE_MOBS|SEE_OBJS|SEE_TURFS) - user.set_see_in_dark(8) - user.set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) - - if (!(MUTATION_COLD_RESISTANCE in user.mutations)) - user.mutations.Add(MUTATION_COLD_RESISTANCE) - - if(!(MUTATION_HEAL in user.mutations)) - user.mutations.Add(MUTATION_HEAL) - - user.update_mutations() - user.mind.special_role = "Avatar of the Wish Granter" - to_chat(user, "You have a very bad feeling about this.") - return diff --git a/code/game/movietitles.dm b/code/game/movietitles.dm index aabfc2b502c8..6d1b954bab9f 100644 --- a/code/game/movietitles.dm +++ b/code/game/movietitles.dm @@ -1,44 +1,36 @@ -#define CREDIT_ROLL_SPEED 185 -#define CREDIT_SPAWN_SPEED 20 -#define CREDIT_ANIMATE_HEIGHT (14 * world.icon_size) -#define CREDIT_EASE_DURATION 22 +var/global/list/end_titles -GLOBAL_LIST(end_titles) - -client +/client var/list/credits /client/proc/RollCredits() set waitfor = FALSE - if(get_preference_value(/datum/client_preference/show_credits) != GLOB.PREF_YES) + if(get_preference_value(/datum/client_preference/show_credits) != PREF_YES) return - if(!GLOB.end_titles) - GLOB.end_titles = generate_titles() - - LAZYINITLIST(credits) + if(!global.end_titles) + global.end_titles = generate_titles() if(mob) mob.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed) mob.overlay_fullscreen("fadeout",/obj/screen/fullscreen/fadeout) - if(mob.get_preference_value(/datum/client_preference/play_lobby_music) == GLOB.PREF_YES) - sound_to(mob, sound(null, channel = GLOB.lobby_sound_channel)) - if(GLOB.end_credits_song == null) - var/title_song = pick('sound/music/THUNDERDOME.ogg', 'sound/music/europa/Chronox_-_03_-_In_Orbit.ogg', 'sound/music/europa/asfarasitgets.ogg') - sound_to(mob, sound(title_song, wait = 0, volume = 40, channel = GLOB.lobby_sound_channel)) - else if(get_preference_value(/datum/client_preference/play_admin_midis) == GLOB.PREF_YES) - sound_to(mob, sound(GLOB.end_credits_song, wait = 0, volume = 40, channel = GLOB.lobby_sound_channel)) - sleep(50) - var/list/_credits = credits + if(mob.get_preference_value(/datum/client_preference/play_lobby_music) == PREF_YES) + sound_to(mob, sound(null, channel = sound_channels.lobby_channel)) + if(global.end_credits_song == null) + if(global.using_map.credit_sound) + sound_to(mob, sound(pick(global.using_map.credit_sound), wait = 0, volume = 40, channel = sound_channels.lobby_channel)) + else if(get_preference_value(/datum/client_preference/play_admin_midis) == PREF_YES) + sound_to(mob, sound(global.end_credits_song, wait = 0, volume = 40, channel = sound_channels.lobby_channel)) + + sleep(5 SECONDS) verbs += /client/proc/ClearCredits - for(var/I in GLOB.end_titles) - if(!credits) - return - var/obj/screen/credit/T = new(null, I, src) - _credits += T - T.rollem() + for(var/credit in global.end_titles) + var/obj/screen/credit/credit_obj = new(null, mob) + LAZYADD(credits, credit_obj) + credit_obj.maptext = {"
              [credit]
              "} + credit_obj.rollem() sleep(CREDIT_SPAWN_SPEED) sleep(CREDIT_ROLL_SPEED - CREDIT_SPAWN_SPEED) @@ -52,45 +44,7 @@ client QDEL_NULL_LIST(credits) mob.clear_fullscreen("fishbed") mob.clear_fullscreen("fadeout") - sound_to(mob, sound(null, channel = GLOB.lobby_sound_channel)) - -/obj/screen/credit - icon_state = "blank" - mouse_opacity = 0 - alpha = 0 - screen_loc = "CENTER-7,BOTTOM+1" - plane = HUD_PLANE - layer = HUD_ABOVE_ITEM_LAYER - var/client/parent - var/matrix/target - -/obj/screen/credit/Initialize(mapload, credited, client/P) - . = ..() - parent = P - maptext = {"
              [credited]
              "} - maptext_height = world.icon_size * 2 - maptext_width = world.icon_size * 14 - -/obj/screen/credit/proc/rollem() - var/matrix/M = matrix(transform) - M.Translate(0, CREDIT_ANIMATE_HEIGHT) - animate(src, transform = M, time = CREDIT_ROLL_SPEED) - target = M - animate(src, alpha = 255, time = CREDIT_EASE_DURATION, flags = ANIMATION_PARALLEL) - spawn(CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) - if(!QDELETED(src)) - animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) - sleep(CREDIT_EASE_DURATION) - qdel(src) - parent.screen += src - -/obj/screen/credit/Destroy() - var/client/P = parent - if(parent) - P.screen -= src - LAZYREMOVE(P.credits, src) - parent = null - return ..() + sound_to(mob, sound(null, channel = sound_channels.lobby_channel)) /proc/generate_titles() var/list/titles = list() @@ -99,7 +53,7 @@ client var/chunksize = 0 titles += "

              EPISODE [rand(1,1000)]
              [SSlore.get_end_credits_title()]

              " - for(var/mob/living/carbon/human/H in GLOB.living_mob_list_|GLOB.dead_mob_list_) + for(var/mob/living/human/H in global.living_mob_list_|global.dead_mob_list_) if(findtext(H.real_name,"(mannequin)")) continue if(H.isMonkey() && findtext(H.real_name,"[lowertext(H.species.name)]")) //no monki @@ -112,26 +66,26 @@ client if(GetAssignment(H) != "Unassigned") job = ", [uppertext(GetAssignment(H))]" var/used_name = H.real_name - var/datum/computer_file/report/crew_record/R = get_crewmember_record(H.real_name) - if(R && R.get_rank()) - var/datum/mil_rank/rank = mil_branches.get_rank(R.get_branch(), R.get_rank()) + var/datum/computer_file/report/crew_record/record = get_crewmember_record(H.real_name) + if(record && record.get_rank()) + var/datum/mil_rank/rank = global.using_map.get_rank(record.get_branch(), record.get_rank()) if(rank.name_short) used_name = "[rank.name_short] [used_name]" var/showckey = 0 - if(H.ckey && H.client) - if(H.client.get_preference_value(/datum/client_preference/show_ckey_credits) == GLOB.PREF_SHOW) + if(H.ckey && H.client) + if(H.client.get_preference_value(/datum/client_preference/show_ckey_credits) == PREF_SHOW) showckey = 1 - var/decl/cultural_info/actor_culture = SSlore.get_culture(H.get_cultural_value(TAG_CULTURE)) - if(!actor_culture || !(H.species.spawn_flags & SPECIES_CAN_JOIN) || prob(10)) - actor_culture = SSlore.get_culture(CULTURE_HUMAN) + var/decl/background_detail/background = H.get_background_datum_by_flag(BACKGROUND_FLAG_NAMING) + if(!background || !(H.species.spawn_flags & SPECIES_CAN_JOIN) || prob(10)) + background = GET_DECL(/decl/background_detail/heritage/human) if(!showckey) if(prob(90)) - chunk += "[actor_culture.get_random_name(H.gender)]\t \t \t \t[uppertext(used_name)][job]" - else - var/datum/gender/G = gender_datums[H.gender] - chunk += "[used_name]\t \t \t \t[uppertext(G.him)]SELF" + chunk += "[background.get_random_cultural_name(H, H.gender, H.get_species())]\t \t \t \t[uppertext(used_name)][job]" + else + var/decl/pronouns/pronouns = H.get_pronouns() + chunk += "[used_name]\t \t \t \t[uppertext(pronouns.him)]SELF" else - chunk += "[uppertext(actor_culture.get_random_name(H.gender))] a.k.a. '[uppertext(H.ckey)]'\t \t \t \t[uppertext(used_name)][job]" + chunk += "[uppertext(background.get_random_cultural_name(H, H.gender, H.get_species()))] a.k.a. '[uppertext(H.ckey)]'\t \t \t \t[uppertext(used_name)][job]" chunksize++ if(chunksize > 2) cast += "
              [jointext(chunk,"
              ")]
              " @@ -144,28 +98,28 @@ client var/list/corpses = list() var/list/monkies = list() - for(var/mob/living/carbon/human/H in GLOB.dead_mob_list_) + for(var/mob/living/human/H in global.dead_mob_list_) if(H.timeofdeath < 5 MINUTES) //no prespawned corpses continue if(H.isMonkey() && findtext(H.real_name,"[lowertext(H.species.name)]")) - monkies[H.species.name] += 1 + monkies[H.species] += 1 else if(H.real_name) corpses += H.real_name - for(var/spec in monkies) - var/datum/species/S = get_species_by_key(spec) - corpses += "[monkies[spec]] [lowertext(monkies[spec] > 1 ? S.name_plural : S.name)]" + for(var/decl/species/monkey_species in monkies) + corpses += "[monkies[monkey_species]] [lowertext(monkies[monkey_species] > 1 ? monkey_species.name_plural : monkey_species.name)]" if(corpses.len) titles += "
              BASED ON REAL EVENTS
              In memory of [english_list(corpses)].
              " var/list/staff = list("PRODUCTION STAFF:") - var/list/staffjobs = list("Coffe Fetcher", "Cameraman", "Angry Yeller", "Chair Operator", "Choreographer", "Historical Consultant", "Costume Designer", "Chief Editor", "Executive Assistant") + var/list/staffjobs = list("Coffee Fetcher", "Cameraman", "Angry Yeller", "Chair Operator", "Choreographer", "Historical Consultant", "Costume Designer", "Chief Editor", "Executive Assistant") var/list/goodboys = list() for(var/client/C) if(!C.holder) continue if(C.holder.rights & (R_DEBUG|R_ADMIN)) - var/decl/cultural_info/cult = SSlore.cultural_info_by_name[pick(SSlore.cultural_info_by_name)] - staff += "[uppertext(pick(staffjobs))] - [cult.get_random_name(pick(MALE, FEMALE))] a.k.a. '[C.key]'" + var/list/all_backgrounds = decls_repository.get_decls_of_subtype(/decl/background_detail/heritage) + var/decl/background_detail/cult = all_backgrounds[pick(all_backgrounds)] + staff += "[uppertext(pick(staffjobs))] - [cult.get_random_cultural_name(C.mob, C.mob.gender, C.mob.get_species())] a.k.a. '[C.key]'" else if(C.holder.rights & R_MOD) goodboys += "[C.key]" @@ -173,13 +127,13 @@ client if(goodboys.len) titles += "
              STAFF'S GOOD BOYS:
              [english_list(goodboys)]

              " - var/disclaimer = "
              Sponsored by [GLOB.using_map.company_name].
              All rights reserved.
              \ - This motion picture is protected under the copyright laws of the Sol Central Government
              and other nations throughout the galaxy.
              \ + var/disclaimer = "
              Sponsored by [global.using_map.company_name].
              All rights reserved.
              \ + This motion picture is protected under the copyright laws of the system government
              and other nations throughout the galaxy.
              \ Colony of First Publication: [pick("Mars", "Luna", "Earth", "Venus", "Phobos", "Ceres", "Tiamat", "Ceti Epsilon", "Eos", "Pluto", "Ouere",\ "Lordania", "Kingston", "Cinu", "Yuklid V", "Lorriman", "Tersten", "Gaia")].
              " - disclaimer += pick("Use for parody prohibited. PROHIBITED.", + disclaimer += pick("Use for parody prohibited. PROHIBITED.", "All stunts were performed by underpaid interns. Do NOT try at home.", - "[GLOB.using_map.company_name] does not endorse behaviour depicted. Attempt at your own risk.", + "[global.using_map.company_name] does not endorse behaviour depicted. Attempt at your own risk.", "Any unauthorized exhibition, distribution, or copying of this film or any part thereof (including soundtrack)
              \ may result in an ERT being called to storm your home and take it back by force.", "The story, all names, characters, and incidents portrayed in this production are fictitious. No identification with actual
              \ diff --git a/code/game/objects/__objs.dm b/code/game/objects/__objs.dm new file mode 100644 index 000000000000..feebd9293847 --- /dev/null +++ b/code/game/objects/__objs.dm @@ -0,0 +1,504 @@ +/obj + layer = OBJ_LAYER + animate_movement = 2 + is_spawnable_type = TRUE + abstract_type = /obj + + ///The maximum health that the object can have. If set to ITEM_HEALTH_NO_DAMAGE, the object won't take any damage. + max_health = ITEM_HEALTH_NO_DAMAGE + ///The current health of the obj. Leave to null, unless you want the object to start at a different health than max_health. + current_health = null + + // If non-null and positive, will create a reagent holder on Initialize() + var/chem_volume + + var/obj_flags + var/datum/talking_atom/talking_atom + var/list/req_access + var/list/matter //Used to store information about the contents of the object. + var/w_class // Size of the object. + + var/in_use = FALSE // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! + var/armor_penetration = 0 + var/anchor_fall = FALSE + /// if the obj is a holographic object spawned by the holodeck + var/holographic = FALSE + ///JSON list of directions to x,y offsets to be applied to the object depending on its direction EX: @'{"NORTH":{"x":12,"y":5}, "EAST":{"x":10,"y":50}}' + var/directional_offset + +/obj/Initialize(mapload) + . = ..() + create_matter() + //Only apply directional offsets if the mappers haven't set any offsets already + if(!pixel_x && !pixel_y && !pixel_w && !pixel_z) + update_directional_offset() + + //Health should be set to max_health only if it's null. + var/_max_health = get_max_health() + if(isnull(current_health) || current_health == INFINITY) + current_health = _max_health + current_health = min(current_health, _max_health) + + // Initialize our reagents if they've been preloaded or we have a chem_volume + if((!isnull(chem_volume) && chem_volume >= 0) || islist(reagents)) + initialize_reagents() + +/obj/object_shaken() + shake_animation() + return ..() + +/obj/hitby(atom/movable/AM, var/datum/thrownthing/TT) + . = ..() + if(. && !anchored) + step(src, AM.last_move) + +/obj/proc/create_matter() + if(length(matter)) + for(var/mat in matter) + matter[mat] = round(matter[mat] * get_matter_amount_modifier()) + UNSETEMPTY(matter) + +/obj/Destroy() + QDEL_NULL(talking_atom) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/proc/get_matter_amount_modifier() + . = w_class * BASE_OBJECT_MATTER_MULTPLIER + +/obj/assume_air(datum/gas_mixture/giver) + return loc?.assume_air(giver) + +/obj/remove_air(amount) + return loc?.remove_air(amount) + +/obj/return_air() + return loc?.return_air() + +/obj/proc/updateUsrDialog() + if(in_use) + var/is_in_use = 0 + var/list/nearby = viewers(1, src) | usr + for(var/mob/M in nearby) + if ((M.client && M.machine == src)) + if(CanUseTopic(M, DefaultTopicState()) > STATUS_CLOSE) + is_in_use = 1 + interact(M) + else + M.unset_machine() + in_use = is_in_use + +/obj/proc/updateDialog() + // Check that people are actually using the machine. If not, don't update anymore. + if(in_use) + var/list/nearby = viewers(1, src) + var/is_in_use = 0 + for(var/mob/M in nearby) + if ((M.client && M.machine == src)) + if(CanUseTopic(M, DefaultTopicState()) > STATUS_CLOSE) + is_in_use = 1 + interact(M) + else + M.unset_machine() + var/ai_in_use = AutoUpdateAI(src) + + if(!ai_in_use && !is_in_use) + in_use = 0 + +/obj/attack_ghost(mob/user) + ui_interact(user) + ..() + +/obj/proc/interact(mob/user) + return FALSE + +/obj/proc/hide(var/hide) + set_invisibility(hide ? INVISIBILITY_MAXIMUM : initial(invisibility)) + +/obj/proc/hides_under_flooring() + return level == LEVEL_BELOW_PLATING + +/obj/proc/hear_talk(mob/M, text, verb, decl/language/speaking) + if(talking_atom) + talking_atom.catchMessage(text, M) +/* + var/mob/mo = locate(/mob) in src + if(mo) + var/rendered = "[M.name]: [text]" + mo.show_message(rendered, 2) + */ + return + +/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) + return + +/obj/proc/damage_flags() + . = 0 + if(is_sharp()) + . |= DAM_SHARP|DAM_EDGE + if(atom_damage_type == BURN) + . |= DAM_LASER + else if(has_edge()) + . |= DAM_EDGE + +/obj/attackby(obj/item/used_item, mob/user) + // We need to call parent even if we lack dexterity, so that storage can work. + if((obj_flags & OBJ_FLAG_ANCHORABLE) && (IS_WRENCH(used_item) || IS_HAMMER(used_item))) + if(used_item.user_can_attack_with(user)) + wrench_floor_bolts(user, null, used_item) + update_icon() + return TRUE + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + if(padding_extension && padding_extension.handle_use_item(used_item, user)) + return TRUE + return ..() + +/obj/proc/wrench_floor_bolts(mob/user, delay = 2 SECONDS, obj/item/tool) + if(!istype(tool) || IS_WRENCH(tool)) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + else if(IS_HAMMER(tool)) + playsound(loc, 'sound/weapons/Genhit.ogg', 100, 1) + + if(anchored) + user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") + else + user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") + if(do_after(user, delay, src)) + if(!src) return + to_chat(user, SPAN_NOTICE("You [anchored? "un" : ""]secured \the [src]!")) + anchored = !anchored + return 1 + +/obj/attack_hand(mob/user) + if(Adjacent(user)) + add_fingerprint(user) + return ..() + +/obj/try_fluid_push(volume, strength) + return ..() && w_class <= round(strength/20) + +/obj/proc/can_embed() + return FALSE + +/obj/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if((obj_flags & OBJ_FLAG_ROTATABLE)) + . += SPAN_SUBTLE("\The [src] can be rotated with alt-click.") + if((obj_flags & OBJ_FLAG_ANCHORABLE)) + . += SPAN_SUBTLE("\The [src] can be anchored or unanchored with a wrench.") + +/obj/proc/rotate(mob/user) + if(!CanPhysicallyInteract(user)) + to_chat(user, SPAN_NOTICE("You can't interact with \the [src] right now!")) + return + + if(anchored) + to_chat(user, SPAN_NOTICE("\The [src] is secured to the floor!")) + return + + set_dir(turn(dir, 90)) + update_icon() + +//For things to apply special effects after damaging an organ, called by organ's take_damage +/obj/proc/after_wounding(obj/item/organ/external/organ, datum/wound) + return + +/obj/get_mass() + return min(2**(w_class-1), 100) + +/obj/get_object_size() + return w_class + +/obj/get_mob() + return buckled_mob + +/obj/set_dir(ndir) + . = ..() + if(directional_offset) + update_directional_offset() + +/obj/Move() + . = ..() + if(directional_offset) + update_directional_offset() + +/obj/forceMove(atom/dest) + . = ..() + if(directional_offset) + update_directional_offset() + +/** + * Applies the offset stored in the directional_offset json list depending on the current direction. + * force will force the default offset to be 0 if there are no directional_offset string. + */ +/obj/proc/update_directional_offset(var/force = FALSE) + if(!force && !length(directional_offset)) + return + + default_pixel_x = 0 + default_pixel_y = 0 + default_pixel_w = 0 + default_pixel_z = 0 + + var/list/diroff = cached_json_decode(directional_offset) + var/list/curoff = diroff["[uppertext(dir2text(dir))]"] + if(length(curoff)) + default_pixel_x = curoff["x"] || 0 + default_pixel_y = curoff["y"] || 0 + default_pixel_w = curoff["w"] || 0 + default_pixel_z = curoff["z"] || 0 + reset_offsets(0) + +/** + * Returns whether the object should be considered as hanging off a wall. + * This is userful because wall-mounted things are actually on the adjacent floor tile offset towards the wall. + * Which means we have to deal with directional offsets differently. Such as with buttons mounted on a table, or on a wall. + */ +/obj/proc/is_wall_mounted() + //If this flag is on, and we have an offset, we're most likely wall mounted + if(obj_flags & OBJ_FLAG_MOVES_UNSUPPORTED || anchor_fall) + var/turf/forward = get_step(get_turf(src), dir) + var/turf/reverse = get_step(get_turf(src), global.reverse_dir[dir]) + //If we're wall mounted and don't have a wall either facing us, or in the opposite direction, don't apply the offset. + // This is mainly for things that can be both wall mounted and floor mounted. Like buttons, which mappers seem to really like putting on tables. + // It's sort of a hack for now. But objects don't handle being on a wall or not. (They don't change their flags, layer, etc when on a wall or anything) + if(!forward?.is_wall() && !reverse?.is_wall()) + return + return TRUE + +/** + * Init starting reagents and/or reagent var. Called in /obj/Initialize() if volume is above 0. + * Skips populate_initialize() if reagents is null, or if it is a list, ie. we are pending deserialization. + */ +/obj/proc/initialize_reagents() + SHOULD_CALL_PARENT(TRUE) + // Check if this is getting called twice, or we created reagents somewhere in Initialize() (bad juju) + if(istype(reagents)) + log_warning("\The [src] possibly is initializing its reagents more than once!") + // If preloaded from serde, handle expected list structure. + // Returns if preload is successful to skip populate_reagents() call. + FINALIZE_REAGENTS_SERDE_AND_RETURN(reagents) + // Standard non-serde reagent init behavior after this point. + if(chem_volume > 0) + create_or_update_reagents(chem_volume) + if(istype(reagents)) + populate_reagents() + +/** + * Actually populates the reagents. + * Can be easily nulled out or fully overriden without having to rewrite the complete reagent init logic. + * An alternative to using a list for defining our starting reagents since apparently overriding the value of a list creates an (init) proc each time. + */ +/obj/proc/populate_reagents() + return + +//#TODO: Implement me for all other objects! +/obj/PopulateClone(obj/clone) + clone = ..() + clone.req_access = deepCopyList(req_access) + clone.matter = matter?.Copy() + clone.anchor_fall = anchor_fall + + //#TODO: once item damage in, check health! + return clone + +/** + * Returns a list with the contents that may be spawned in this object. + * This shouldn't include things that are necessary for the object to operate, like machine components. + * It's mainly for populating storage and the like. + */ +/obj/proc/WillContain() + return + +/obj/get_contained_matter(include_reagents = TRUE) + . = ..() + if(length(matter)) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., matter.Copy()) + +/obj/proc/clear_matter() + matter = null + reagents?.clear_reagents() + +//////////////////////////////////////////////////////////////// +// Interactions +//////////////////////////////////////////////////////////////// +/**Returns a text string to describe the current damage level of the item, or null if non-applicable. */ +/obj/proc/get_examined_damage_string() + if(!can_take_damage()) + return + var/health_percent = get_percent_health() + if(health_percent >= 100) + return SPAN_NOTICE("It looks fully intact.") + else if(health_percent > 75) + return SPAN_NOTICE("It has a few cracks.") + else if(health_percent > 50) + return SPAN_WARNING("It looks slightly damaged.") + else if(health_percent > 25) + return SPAN_WARNING("It looks moderately damaged.") + else + return SPAN_DANGER("It looks heavily damaged.") + +/obj/fluid_act(var/datum/reagents/fluids) + ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids)) + fluids.touch_obj(src) + +// TODO: maybe iterate the entire matter list or do some partial damage handling +/obj/proc/solvent_can_melt(var/solvent_power = MAT_SOLVENT_STRONG) + if(!simulated) + return FALSE + var/decl/material/mat = get_material() + return !mat || mat.dissolves_in <= solvent_power + +/obj/handle_melting(list/meltable_materials) + . = ..() + if(QDELETED(src)) + return + var/reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if(reagent_volume) + reagents.trans_to(loc, reagent_volume) + dump_contents() + return place_melted_product(meltable_materials) + +/obj/proc/place_melted_product(list/meltable_materials) + if(length(matter)) + var/datum/gas_mixture/environment = loc?.return_air() + for(var/mat in matter) + var/decl/material/M = GET_DECL(mat) + M.add_burn_product(environment, MOLES_PER_MATERIAL_UNIT(matter[mat])) + matter = null + . = new /obj/effect/decal/cleanable/molten_item(src) + qdel(src) + +/obj/can_be_injected_by(var/atom/injector) + return ATOM_IS_OPEN_CONTAINER(src) + +/obj/ProcessAtomTemperature() + . = ..() + if(QDELETED(src)) + return + // Bake any matter into the cooked form. + if(LAZYLEN(matter)) + var/new_matter + var/remove_matter + for(var/matter_type in matter) + var/decl/material/mat = GET_DECL(matter_type) + if(mat.bakes_into_material && !isnull(mat.bakes_into_at_temperature) && temperature >= mat.bakes_into_at_temperature) + LAZYINITLIST(new_matter) + new_matter[mat.bakes_into_material] += matter[matter_type] + LAZYDISTINCTADD(remove_matter, remove_matter) + if(LAZYLEN(new_matter)) + for(var/mat in new_matter) + matter[mat] = new_matter[mat] + if(LAZYLEN(remove_matter)) + for(var/mat in remove_matter) + matter -= mat + UNSETEMPTY(matter) + +/obj/proc/get_blend_objects() + return + +/obj/proc/is_compostable() + for(var/mat in matter) + var/decl/material/composting_mat = GET_DECL(mat) + if(composting_mat.compost_value) + return TRUE + return FALSE + +// Used to determine if something can be used as the basis of a mold. +/obj/proc/get_mould_difficulty() + return SKILL_IMPOSSIBLE // length(matter) <= 1 + +// Used to determine what a mold made from this item produces. +/obj/proc/get_mould_product_type() + return type + +// Used to pass an associative list of data to the mold to pass to the product. +/obj/proc/get_mould_metadata() + return + +// Called when passing the metadata back to the item. +/obj/proc/take_mould_metadata(list/metadata) + return + +/obj/try_burn_wearer(var/mob/living/holder, var/held_slot, var/delay = 0) + if(obj_flags & OBJ_FLAG_INSULATED_HANDLE) + return + return ..() + +// Stub, used by /item and /structure +/obj/proc/refresh_color() + return + +// Slightly convoluted reagent logic to avoid fluid_act() putting reagents straight back into the destroyed /obj. +/obj/physically_destroyed(skip_qdel) + var/dumped_reagents = FALSE + var/atom/last_loc = loc + if(last_loc && REAGENT_TOTAL_VOLUME(reagents)) + reagents.trans_to(loc, REAGENT_TOTAL_VOLUME(reagents), defer_update = TRUE) + dumped_reagents = TRUE + reagents.clear_reagents() // We are qdeling, don't bother with a more nuanced update. + . = ..() + if(dumped_reagents && last_loc && !QDELETED(last_loc) && REAGENT_TOTAL_VOLUME(last_loc.reagents)) + last_loc.reagents.handle_update() + HANDLE_REACTIONS(last_loc.reagents) + +// Used by HE pipes and forging bars/billets. Defaults are for HE pipes. +/obj/proc/animate_heat_glow(icon_temperature, scale_sub = 500, scale_div = 1500, scale_max = 2000, skip_filter = FALSE, anim_time = 2 SECONDS) + + var/scale = max((icon_temperature - scale_sub) / scale_div, 0) + var/h_r = heat2color_r(icon_temperature) + var/h_g = heat2color_g(icon_temperature) + var/h_b = heat2color_b(icon_temperature) + + var/base_color = get_color() + var/b_r = HEX_RED(base_color) + var/b_g = HEX_GREEN(base_color) + var/b_b = HEX_BLUE(base_color) + + if(icon_temperature < scale_max) + h_r = b_r + (h_r - b_r)*scale + h_g = b_g + (h_g - b_g)*scale + h_b = b_b + (h_b - b_b)*scale + + var/scale_color = rgb(h_r, h_g, h_b) + var/list/animate_targets = get_above_oo() + src + for (var/thing in animate_targets) + var/atom/movable/AM = thing + if(anim_time > 0) + animate(AM, color = scale_color, time = anim_time, easing = SINE_EASING) + else + color = scale_color + if(!skip_filter) + animate_filter("glow", list(color = scale_color, time = anim_time, easing = LINEAR_EASING)) + + set_light(min(3, scale*2.5), min(3, scale*2.5), scale_color) + +/obj/proc/update_heat_glow(anim_time) + + // We have no real way to find temperature bounds without a material that has a melting point. + var/decl/material/my_material = get_material() + if(!istype(my_material) || !my_material.glows_with_heat || isnull(my_material.melting_point) || QDELETED(src)) + set_light(0, 0) + if(isatom(loc)) + loc.update_icon() + return + + var/temperature_percentage + if(temperature >= my_material.melting_point) // We should have melted... + temperature_percentage = 1 + else if(temperature <= T20C) // Arbitrary point for the sake of not trying to find a proportional temperature delta with ice + temperature_percentage = 0 + else + temperature_percentage = (my_material.melting_point - T20C) / (temperature - T20C) + if(temperature_percentage < 0.25) + set_light(0, 0) + else + animate_heat_glow(temperature, scale_sub = round((my_material.melting_point - T20C) * 0.25) + T20C, scale_div = round(my_material.melting_point * 0.75), scale_max = my_material.melting_point, skip_filter = TRUE, anim_time = anim_time) + if(isatom(loc)) + loc.update_icon() + +/obj/is_valid_merchant_pad_target() + if(anchored) + return FALSE + return ..() diff --git a/code/game/objects/_objs_damage.dm b/code/game/objects/_objs_damage.dm new file mode 100644 index 000000000000..c9eee11f755a --- /dev/null +++ b/code/game/objects/_objs_damage.dm @@ -0,0 +1,25 @@ +/** + Returns whether this object is damaged. + */ +/obj/proc/is_damaged() + return can_take_damage() && (current_health < get_max_health()) + +/** + Returns TRUE if this object can take damage. + */ +/obj/proc/can_take_damage() + return (current_health != ITEM_HEALTH_NO_DAMAGE) && (get_max_health() != ITEM_HEALTH_NO_DAMAGE) + +/** + Returns the percentage of health remaining for this object. + */ +/obj/proc/get_percent_health() + return can_take_damage()? round((current_health * 100)/get_max_health(), HEALTH_ROUNDING) : 100 + +/** + Returns the percentage of damage done to this object. + */ +/obj/proc/get_percent_damages() + //Clamp from 0 to 100 so health values larger than max health don't return unhelpful numbers + return clamp(100 - get_percent_health(), 0, 100) + diff --git a/code/game/objects/_objs_edibility.dm b/code/game/objects/_objs_edibility.dm new file mode 100644 index 000000000000..ed8f1000448a --- /dev/null +++ b/code/game/objects/_objs_edibility.dm @@ -0,0 +1,172 @@ +/obj/proc/get_food_consumption_method(mob/eater) + return EATING_METHOD_EAT + +/obj/proc/is_edible(var/mob/eater) + return get_edible_material_amount(eater) > 0 + +/obj/proc/get_edible_material_amount(var/mob/eater) + return 0 + +/obj/proc/get_food_default_transfer_amount(mob/eater) + return eater?.get_eaten_transfer_amount(2) // arbitrary, should be overridden downstream + +/obj/proc/show_food_consumed_message(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(user) + if(user == target) + if(consumption_method == EATING_METHOD_EAT) + user.visible_message( + SPAN_NOTICE("\The [target] finishes eating \the [src]."), + SPAN_NOTICE("You finish eating \the [src].") + ) + else + user.visible_message( + SPAN_NOTICE("\The [target] finishes drinking \the [src]."), + SPAN_NOTICE("You finish drinking \the [src].") + ) + + else + user.visible_message( + SPAN_NOTICE("\The [user] feeds the last of \the [src] to \the [target]."), + SPAN_NOTICE("You feed the last of \the [src] to \the [target].") + ) + +/obj/proc/handle_consumed(mob/feeder, mob/eater, consumption_method = EATING_METHOD_EAT) + if(eater) + transfer_eaten_material(eater, get_food_default_transfer_amount(eater)) + play_feed_sound(eater, consumption_method) + if(!get_edible_material_amount(eater)) + if(feeder && eater) + show_food_consumed_message(feeder, eater, consumption_method) + if(consumption_method == EATING_METHOD_EAT) + feeder.drop_from_inventory(src) + eater.update_personal_goal(/datum/goal/achievement/specific_object/food, type) + if(consumption_method == EATING_METHOD_EAT) + physically_destroyed() + return TRUE + return FALSE + +/obj/proc/transfer_eaten_material(mob/eater, amount) + reagents?.trans_to_mob(eater, amount, CHEM_INGEST) + +/obj/proc/show_feed_message_start(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(user) + if(user == target) + if(consumption_method == EATING_METHOD_EAT) + to_chat(user, SPAN_NOTICE("You begin trying to take a bite from \the [target].")) + else + to_chat(user, SPAN_NOTICE("You begin trying to drink from \the [target].")) + else + user.visible_message(SPAN_NOTICE("\The [user] is trying to feed \the [src] to \the [target]!")) + +/obj/proc/show_feed_message_end(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(!user) + return + if(user != target) + user.visible_message(SPAN_NOTICE("\The [user] feeds some of \the [src] to \the [target]!")) + return + if(consumption_method == EATING_METHOD_DRINK) + to_chat(user, SPAN_NOTICE("You swallow a gulp from \the [src].")) + return + if(!isliving(user)) + to_chat(user, SPAN_NOTICE("You take a bite of \the [src].")) + return + var/mob/living/living_user = user + switch(living_user.get_food_satiation(consumption_method) / living_user.get_satiated_nutrition()) + if(-(INFINITY) to 0.2) + to_chat(living_user, SPAN_WARNING("You hungrily chew out a piece of [src] and gobble it!")) + if(0.2 to 0.4) + to_chat(living_user, SPAN_NOTICE("You hungrily begin to eat [src].")) + if(0.4 to 0.8) + to_chat(user, SPAN_NOTICE("You take a bite of \the [src].")) + else + to_chat(living_user, SPAN_NOTICE("You unwillingly chew a bit of [src].")) + +/obj/proc/show_food_inedible_message(mob/user, mob/target) + target = target || user + if(user) + if(user == target) + to_chat(user, SPAN_WARNING("There is nothing in \the [src] that you can consume.")) + else + to_chat(user, SPAN_WARNING("There is nothing in \the [src] that \the [target] can consume.")) + +/obj/proc/play_feed_sound(var/mob/user, consumption_method = EATING_METHOD_EAT) + var/turf/play_turf = get_turf(user) + if(!play_turf) + return + switch(consumption_method) + if(EATING_METHOD_EAT) + playsound(user.loc, 'sound/items/eatfood.ogg', rand(10, 50), 1) + if(EATING_METHOD_DRINK) + playsound(user.loc, 'sound/items/drink.ogg', rand(10, 50), 1) + +/obj/proc/is_food_empty(mob/eater) + return get_edible_material_amount(eater) <= 0 + +// General proc for handling an attempt to eat an item, or to eat from an +// item. At time of writing, only handles classic SS13 eating (reagents). +// Returns EATEN_INVALID for an inability to eat, EATEN_UNABLE for an attempt +// prevented by something, and EATEN_SUCCESS for a successful bite. +/obj/proc/handle_eaten_by_mob(var/mob/user, var/mob/target) + + if(!istype(user)) + return EATEN_INVALID + + if(!target) + target = user + + if(!istype(target)) + return EATEN_INVALID + + if(!is_edible(target)) + show_food_inedible_message(user, target) + return EATEN_UNABLE + + var/consumption_method = get_food_consumption_method(target) + if(is_food_empty(target)) + show_food_empty_message(user, consumption_method) + return EATEN_UNABLE + + if(!target.check_has_mouth()) + show_food_no_mouth_message(user, target) + return EATEN_UNABLE + + if(!target.can_eat_food_currently(src, user, consumption_method)) + return EATEN_UNABLE + + var/blocked = target.check_mouth_coverage() + if(blocked) + to_chat(user, SPAN_NOTICE("\The [blocked] is in the way!")) + return EATEN_UNABLE + + if(user != target && !user.can_force_feed(target, src)) + return EATEN_UNABLE + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(user != target) + if(!user.can_force_feed(target, src)) + return EATEN_UNABLE + show_feed_message_start(user, target, consumption_method) + if(!do_mob(user, target)) + return EATEN_UNABLE + var/contained = json_encode(REAGENT_LIST(reagents)) + admin_attack_log(user, target, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") + + show_feed_message_end(user, target, consumption_method) + if(consumption_method == EATING_METHOD_DRINK && target?.has_personal_goal(/datum/goal/achievement/specific_object/drink)) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + target.update_personal_goal(/datum/goal/achievement/specific_object/drink, reagent) + handle_consumed(user, target, consumption_method) + + return EATEN_SUCCESS + +/obj/attack_animal(var/mob/user) + if(isanimal(user) && is_edible(user) && handle_eaten_by_mob(user) == EATEN_SUCCESS) + // TODO: put this in the mob AI. + spawn(5) + if(user && QDELETED(src) && !user.client) + user.custom_emote(1,"[pick("burps", "cries for more", "burps twice", "looks at the area where the food was")]") + return TRUE + return ..() diff --git a/code/game/objects/_objs_interactions.dm b/code/game/objects/_objs_interactions.dm new file mode 100644 index 000000000000..65d143b39b36 --- /dev/null +++ b/code/game/objects/_objs_interactions.dm @@ -0,0 +1,21 @@ +/obj/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/rotate) + +/** + Interaction for rotating an object in the world. + */ +/decl/interaction_handler/rotate + name = "Rotate" + expected_target_type = /obj + examine_desc = "rotate $TARGET_THEM$" + +/decl/interaction_handler/rotate/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/obj/O = target + . = !!(O.obj_flags & OBJ_FLAG_ROTATABLE) + +/decl/interaction_handler/rotate/invoked(atom/target, mob/user, obj/item/prop) + var/obj/O = target + O.rotate(user) diff --git a/code/game/objects/alien_props.dm b/code/game/objects/alien_props.dm index 119ee8052a4d..5268d3e3a383 100644 --- a/code/game/objects/alien_props.dm +++ b/code/game/objects/alien_props.dm @@ -7,18 +7,19 @@ icon = 'icons/obj/xenoarchaeology.dmi' icon_state = "unknown1" maxcharge = 5000 - origin_tech = "{'powerstorage':7}" - var/global/base_icon + origin_tech = @'{"powerstorage":7}' + var/base_icon_state /obj/item/cell/alien/on_update_icon() - if(!base_icon) - base_icon = pick("instrument", "unknown1", "unknown3", "unknown4") - icon_state = base_icon + . = ..() + if(!base_icon_state) + base_icon_state = pick("instrument", "unknown1", "unknown3", "unknown4") + icon_state = base_icon_state // APC #define APC_UPDATE_ALLGOOD 128 -/obj/machinery/power/apc/alien +/obj/machinery/apc/alien name = "alien device" desc = "It's affixed to the floor, with a thick wire going into it." icon = 'icons/obj/xenoarchaeology.dmi' @@ -28,8 +29,8 @@ uncreated_component_parts = list( /obj/item/cell/alien ) - -/obj/machinery/power/apc/alien/on_update_icon() + +/obj/machinery/apc/alien/on_update_icon() check_updates() if(update_state & APC_UPDATE_ALLGOOD) icon_state = "ano11" @@ -46,6 +47,7 @@ base_state = "bulb" color = COLOR_PURPLE light_type = /obj/item/light/alien + accepts_light_type = /obj/item/light/alien /obj/machinery/light/alien/Initialize() color = null //It's just for mapping @@ -57,14 +59,13 @@ base_state = "lbulb" desc = "A simple alien device, perhaps some sort of light source." color = COLOR_PURPLE - var/global/random_light_color + var/static/random_light_color /obj/item/light/alien/Initialize() . = ..() if(!random_light_color) random_light_color = get_random_colour(FALSE, 100, 255) - b_colour = random_light_color - color = random_light_color + set_color(random_light_color) // if stuff starts exploding due to too-early update_icon calls it's this thing's fault //Airlock /obj/machinery/door/airlock/alien @@ -73,8 +74,8 @@ /obj/machinery/door/airlock/alien/Initialize() . = ..() - var/decl/material/A = decls_repository.get_decl(/decl/material/solid/metal/aliumium) + var/decl/material/A = GET_DECL(/decl/material/solid/metal/aliumium) if(A) door_color = A.color stripe_color = get_random_colour(FALSE, 0, 255) - update_icon() \ No newline at end of file + update_icon() diff --git a/code/game/objects/auras/aura.dm b/code/game/objects/auras/aura.dm deleted file mode 100644 index de9c8d5c1190..000000000000 --- a/code/game/objects/auras/aura.dm +++ /dev/null @@ -1,55 +0,0 @@ -/*Auras are simple: They are simple overriders for attackbys, bullet_act, damage procs, etc. They also tick after their respective mob. -They should be used for undeterminate mob effects, like for instance a toggle-able forcefield, or indestructability as long as you don't move. -They should also be used for when you want to effect the ENTIRE mob, like having an armor buff or showering candy everytime you walk. -*/ - -/obj/aura - var/mob/living/user - -/obj/aura/Initialize() - . = ..() - if(isliving(loc)) - added_to(loc) - user.add_aura(src) - -/obj/aura/Destroy() - if(user) - user.remove_aura(src) - return ..() - -/obj/aura/proc/added_to(var/mob/living/target) - user = target - -/obj/aura/proc/removed() - user = null - -/obj/aura/proc/life_tick() - return 0 - -/obj/aura/attackby(var/obj/item/I, var/mob/user) - return 0 - -/obj/aura/bullet_act(var/obj/item/projectile/P, var/def_zone) - return 0 - -/obj/aura/hitby() - return 0 - -/obj/aura/debug - var/returning = 0 - -/obj/aura/debug/attackby(var/obj/item/I, var/mob/user) - log_debug("Attackby for \ref[src]: [I], [user]") - return returning - -/obj/aura/debug/bullet_act(var/obj/item/projectile/P, var/def_zone) - log_debug("Bullet Act for \ref[src]: [P], [def_zone]") - return returning - -/obj/aura/debug/life_tick() - log_debug("Life tick") - return returning - -/obj/aura/debug/hitby(var/atom/movable/M, var/datum/thrownthing/TT) - log_debug("Hit By for \ref[src]: [M], [TT.speed]") - return returning \ No newline at end of file diff --git a/code/game/objects/auras/blueforge_aura.dm b/code/game/objects/auras/blueforge_aura.dm deleted file mode 100644 index cc7a7d6118c1..000000000000 --- a/code/game/objects/auras/blueforge_aura.dm +++ /dev/null @@ -1,16 +0,0 @@ -/obj/aura/blueforge_aura - name = "Blueforge Aura" - icon = 'icons/mob/human_races/species/eyes.dmi' - icon_state = "eyes_blueforged_s" - layer = MOB_LAYER - -/obj/aura/blueforge_aura/life_tick() - user.adjustToxLoss(-10) - return 0 - -/obj/aura/blueforge_aura/bullet_act(var/obj/item/projectile/P) - if(P.damtype == BURN) - P.damage *=2 - else if(P.agony || P.stun) - return AURA_FALSE - return 0 \ No newline at end of file diff --git a/code/game/objects/auras/personal_shields/personal_shield.dm b/code/game/objects/auras/personal_shields/personal_shield.dm deleted file mode 100644 index 934005ceb4f9..000000000000 --- a/code/game/objects/auras/personal_shields/personal_shield.dm +++ /dev/null @@ -1,34 +0,0 @@ -/obj/aura/personal_shield - name = "personal shield" - -/obj/aura/personal_shield/added_to(var/mob/living/L) - ..() - playsound(user,'sound/weapons/flash.ogg',35,1) - to_chat(user,"You feel your body prickle as \the [src] comes online.") - -/obj/aura/personal_shield/bullet_act(var/obj/item/projectile/P, var/def_zone) - user.visible_message("\The [user]'s [src.name] flashes before \the [P] can hit them!") - new /obj/effect/temporary(get_turf(src), 2 SECONDS,'icons/obj/machines/shielding.dmi',"shield_impact") - playsound(user,'sound/effects/basscannon.ogg',35,1) - return AURA_FALSE|AURA_CANCEL - -/obj/aura/personal_shield/removed() - to_chat(user,"\The [src] goes offline!") - playsound(user,'sound/mecha/internaldmgalarm.ogg',25,1) - ..() - -/obj/aura/personal_shield/device - var/obj/item/personal_shield/shield - -/obj/aura/personal_shield/device/bullet_act() - . = ..() - if(shield) - shield.take_charge() - -/obj/aura/personal_shield/device/Initialize(mapload, var/user_shield) - . = ..() - shield = user_shield - -/obj/aura/personal_shield/device/Destroy() - shield = null - return ..() \ No newline at end of file diff --git a/code/game/objects/auras/radiant_aura.dm b/code/game/objects/auras/radiant_aura.dm deleted file mode 100644 index 49729c941d18..000000000000 --- a/code/game/objects/auras/radiant_aura.dm +++ /dev/null @@ -1,20 +0,0 @@ -/obj/aura/radiant_aura - name = "radiant aura" - icon = 'icons/effects/effects.dmi' - icon_state = "fire_goon" - layer = ABOVE_WINDOW_LAYER - -/obj/aura/radiant_aura/added_to(var/mob/living/L) - ..() - to_chat(L,"A bubble of light appears around you, exuding protection and warmth.") - set_light(0.6, 1, 6, 2, "#e09d37") - -/obj/aura/radiant_aura/removed() - to_chat(user, "Your protective aura dissipates, leaving you feeling cold and unsafe.") - ..() - -/obj/aura/radiant_aura/bullet_act(var/obj/item/projectile/P, var/def_zone) - if(P.damage_flags() & DAM_LASER) - user.visible_message("\The [P] refracts, bending into \the [user]'s aura.") - return AURA_FALSE - return 0 \ No newline at end of file diff --git a/code/game/objects/auras/regenerating_aura.dm b/code/game/objects/auras/regenerating_aura.dm deleted file mode 100644 index 2a460a6b8347..000000000000 --- a/code/game/objects/auras/regenerating_aura.dm +++ /dev/null @@ -1,112 +0,0 @@ -/obj/aura/regenerating - name = "regenerating aura" - var/brute_mult = 1 - var/fire_mult = 1 - var/tox_mult = 1 - -/obj/aura/regenerating/life_tick() - user.adjustBruteLoss(-brute_mult) - user.adjustFireLoss(-fire_mult) - user.adjustToxLoss(-tox_mult) - -/obj/aura/regenerating/human - var/nutrition_damage_mult = 1 //How much nutrition it takes to heal regular damage - var/external_nutrition_mult = 50 // How much nutrition it takes to regrow a limb - var/organ_mult = 2 - var/regen_message = "Your body throbs as you feel your ORGAN regenerate." - var/grow_chance = 0 - var/grow_threshold = 0 - var/ignore_tag//organ tag to ignore - var/last_nutrition_warning = 0 - var/innate_heal = TRUE // Whether the aura is on, basically. - - -/obj/aura/regenerating/human/proc/external_regeneration_effect(var/obj/item/organ/external/O, var/mob/living/carbon/human/H) - return - -/obj/aura/regenerating/human/life_tick() - var/mob/living/carbon/human/H = user - if(!istype(H)) - . = 0 - CRASH("Someone gave [user.type] a [src.type] aura. This is invalid.") - if(!innate_heal || H.InStasis() || H.stat == DEAD) - return 0 - if(H.nutrition < nutrition_damage_mult) - low_nut_warning() - return 0 - - if(brute_mult && H.getBruteLoss()) - H.adjustBruteLoss(-brute_mult * config.organ_regeneration_multiplier) - H.adjust_nutrition(-nutrition_damage_mult) - if(fire_mult && H.getFireLoss()) - H.adjustFireLoss(-fire_mult * config.organ_regeneration_multiplier) - H.adjust_nutrition(-nutrition_damage_mult) - if(tox_mult && H.getToxLoss()) - H.adjustToxLoss(-tox_mult * config.organ_regeneration_multiplier) - H.adjust_nutrition(-nutrition_damage_mult) - - if(!can_regenerate_organs()) - return 1 - if(organ_mult) - if(prob(10) && H.nutrition >= 150 && !H.getBruteLoss() && !H.getFireLoss()) - var/obj/item/organ/external/head/D = H.organs_by_name["head"] - if (D.status & ORGAN_DISFIGURED) - if (H.nutrition >= 20) - D.status &= ~ORGAN_DISFIGURED - H.adjust_nutrition(-20) - else - low_nut_warning("head") - - for(var/bpart in shuffle(H.internal_organs_by_name - BP_BRAIN)) - var/obj/item/organ/internal/regen_organ = H.internal_organs_by_name[bpart] - if(BP_IS_PROSTHETIC(regen_organ)) - continue - if(istype(regen_organ)) - if(regen_organ.damage > 0 && !(regen_organ.status & ORGAN_DEAD)) - if (H.nutrition >= organ_mult) - regen_organ.damage = max(regen_organ.damage - organ_mult, 0) - H.adjust_nutrition(-organ_mult) - if(prob(5)) - to_chat(H, replacetext(regen_message,"ORGAN", regen_organ.name)) - else - low_nut_warning(regen_organ.name) - - if(prob(grow_chance)) - for(var/limb_type in H.species.has_limbs) - var/obj/item/organ/external/E = H.organs_by_name[limb_type] - if(E && E.organ_tag != BP_HEAD && !E.vital && !E.is_usable()) //Skips heads and vital bits... - if (H.nutrition > grow_threshold) - E.removed() //...because no one wants their head to explode to make way for a new one. - qdel(E) - E= null - else - low_nut_warning(E.name) - if(!E) - var/list/organ_data = H.species.has_limbs[limb_type] - var/limb_path = organ_data["path"] - var/obj/item/organ/external/O = new limb_path(H) - external_regeneration_effect(O,H) - organ_data["descriptor"] = O.name - H.update_body() - return - else if (H.nutrition > grow_threshold) //We don't subtract any nut here, but let's still only heal wounds when we have nut. - for(var/datum/wound/W in E.wounds) - if(W.wound_damage() == 0 && prob(50)) - qdel(W) - return 1 - -/obj/aura/regenerating/human/proc/low_nut_warning(var/wound_type) - if (last_nutrition_warning + 1 MINUTE < world.time) - to_chat(user, "You need more energy to regenerate your [wound_type || "wounds"].") - last_nutrition_warning = world.time - return 1 - return 0 - -/obj/aura/regenerating/human/proc/toggle() - innate_heal = !innate_heal - -/obj/aura/regenerating/human/proc/can_toggle() - return TRUE - -/obj/aura/regenerating/human/proc/can_regenerate_organs() - return TRUE diff --git a/code/game/objects/auras/shadowling_aura.dm b/code/game/objects/auras/shadowling_aura.dm deleted file mode 100644 index 172a3bb552fd..000000000000 --- a/code/game/objects/auras/shadowling_aura.dm +++ /dev/null @@ -1,22 +0,0 @@ -/obj/aura/shadowling_aura - name = "Shadowling Aura" - var/added_mutation = FALSE - -/obj/aura/shadowling_aura/added_to(var/mob/living/L) - ..() - if(!(MUTATION_SPACERES in L.mutations)) - L.mutations += MUTATION_SPACERES - added_mutation = TRUE - -/obj/aura/shadowling_aura/removed() - if(added_mutation) - added_mutation = FALSE - user.mutations -= MUTATION_SPACERES - ..() - -/obj/aura/shadowling_aura/bullet_act(var/obj/item/projectile/P) - if(P.damage_flags() & DAM_LASER) - P.damage *= 2 - if(P.agony) - P.agony *= 2 - return 0 \ No newline at end of file diff --git a/code/game/objects/auras/starlight.dm b/code/game/objects/auras/starlight.dm deleted file mode 100644 index f42ad404b7f8..000000000000 --- a/code/game/objects/auras/starlight.dm +++ /dev/null @@ -1,20 +0,0 @@ -/obj/aura/starborn - name = "starborn's gift" - icon = 'icons/effects/effects.dmi' - icon_state = "white_electricity_constant" - color = "#33cc33" - layer = MOB_LAYER - -/obj/aura/starborn/bullet_act(var/obj/item/projectile/P, var/def_zone) - if(P.damage_type == BURN) - user.visible_message("\The [P] seems to only make \the [user] stronger.") - user.adjustBruteLoss(-P.damage) - return AURA_FALSE - return 0 - -/obj/aura/starborn/attackby(var/obj/item/I, var/mob/i_user) - if(I.damtype == "fire") - to_chat(i_user, "\The [I] seems to only feed into \the [user]'s flames.") - user.adjustBruteLoss(-I.force) - return AURA_FALSE - return 0 \ No newline at end of file diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm deleted file mode 100644 index 600da2358511..000000000000 --- a/code/game/objects/buckling.dm +++ /dev/null @@ -1,110 +0,0 @@ -/obj - var/can_buckle = 0 - var/buckle_movable = 0 - var/buckle_dir = 0 - var/buckle_lying = -1 //bed-like behavior, forces mob.lying = buckle_lying if != -1 - var/buckle_pixel_shift = @"{'x':0,'y':0,'z':0}" //where the buckled mob should be pixel shifted to, or null for no pixel shift control - var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes - var/mob/living/buckled_mob = null - -/obj/attack_hand(mob/living/user) - . = ..() - if(can_buckle && buckled_mob) - user_unbuckle_mob(user) - -/obj/MouseDrop_T(mob/living/M, mob/living/user) - . = ..() - if(can_buckle && istype(M)) - user_buckle_mob(M, user) - -/obj/Destroy() - unbuckle_mob() - return ..() - - -/obj/proc/buckle_mob(mob/living/M) - if(buckled_mob) //unless buckled_mob becomes a list this can cause problems - return 0 - if(!istype(M) || (M.loc != loc) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained())) - return 0 - if(ismob(src)) - var/mob/living/carbon/C = src //Don't wanna forget the xenos. - if(M != src && C.incapacitated()) - return 0 - - M.buckled = src - M.facing_dir = null - M.set_dir(buckle_dir ? buckle_dir : dir) - M.UpdateLyingBuckledAndVerbStatus() - M.update_floating() - buckled_mob = M - - post_buckle_mob(M) - return 1 - -/obj/proc/unbuckle_mob() - if(buckled_mob && buckled_mob.buckled == src) - . = buckled_mob - buckled_mob.buckled = null - buckled_mob.anchored = initial(buckled_mob.anchored) - buckled_mob.UpdateLyingBuckledAndVerbStatus() - buckled_mob.update_floating() - buckled_mob = null - - post_buckle_mob(.) - -/obj/proc/post_buckle_mob(mob/living/M) - if(buckle_pixel_shift) - if(M == buckled_mob) - var/list/pixel_shift = cached_json_decode(buckle_pixel_shift) - animate(M, pixel_x = M.default_pixel_x + pixel_shift["x"], pixel_y = M.default_pixel_y + pixel_shift["y"], pixel_z = M.default_pixel_z + pixel_shift["z"], 4, 1, LINEAR_EASING) - else - animate(M, pixel_x = M.default_pixel_x, pixel_y = M.default_pixel_y, pixel_z = M.default_pixel_z, 4, 1, LINEAR_EASING) - -/obj/proc/user_buckle_mob(mob/living/M, mob/user) - if(!user.Adjacent(M) || istype(user, /mob/living/silicon/pai) || (M != user && user.incapacitated())) - return 0 - if(M == buckled_mob) - return 0 - if(istype(M, /mob/living/carbon/slime)) - to_chat(user, "\The [M] is too squishy to buckle in.") - return 0 - - add_fingerprint(user) - unbuckle_mob() - - //can't buckle unless you share locs so try to move M to the obj. - if(M.loc != src.loc) - step_towards(M, src) - - . = buckle_mob(M) - if(.) - if(M == user) - M.visible_message(\ - "\The [M.name] buckles themselves to \the [src].",\ - "You buckle yourself to \the [src].",\ - "You hear metal clanking.") - else - M.visible_message(\ - "\The [M.name] is buckled to \the [src] by \the [user.name]!",\ - "You are buckled to \the [src] by \the [user.name]!",\ - "You hear metal clanking.") - -/obj/proc/user_unbuckle_mob(mob/user) - var/mob/living/M = unbuckle_mob() - if(M) - if(M != user) - M.visible_message(\ - "\The [M.name] was unbuckled by \the [user.name]!",\ - "You were unbuckled from \the [src] by \the [user.name].",\ - "You hear metal clanking.") - else - M.visible_message(\ - "\The [M.name] unbuckled themselves!",\ - "You unbuckle yourself from \the [src].",\ - "You hear metal clanking.") - add_fingerprint(user) - return M - -/obj/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) - . = ..() || (buckled_mob == mover) diff --git a/code/game/objects/compass/_compass.dm b/code/game/objects/compass/_compass.dm new file mode 100644 index 000000000000..32d553b4f809 --- /dev/null +++ b/code/game/objects/compass/_compass.dm @@ -0,0 +1,11 @@ +/* + This folder contains an abstract type (/obj/compass_holder) which contains a set of + waypoints (/datum/compass_waypoint) and generates a circular compass with markers for + mobs that have the object in their screen list. See GPS for an example implementation. +*/ + +/image/compass_marker + maptext_height = 64 + maptext_width = 128 + maptext_x = -48 + maptext_y = -32 diff --git a/code/game/objects/compass/compass_holder.dm b/code/game/objects/compass/compass_holder.dm new file mode 100644 index 000000000000..2d64720ebccd --- /dev/null +++ b/code/game/objects/compass/compass_holder.dm @@ -0,0 +1,136 @@ +var/global/list/angle_step_to_dir = list( + "N", + "NE", + "E", + "SE", + "S", + "SW", + "W", + "NW", + "N" +) + +/obj/compass_holder + name = null + icon = null + icon_state = null + screen_loc = "CENTER,CENTER" + is_spawnable_type = FALSE + + var/interval_colour = "#7e6f96" + var/bearing_colour = COLOR_WHITE + var/bearing_outline_colour = "#3b2d53" + + /// Number of steps/pips between bolded markers on the compass ring. + var/compass_interval = 3 + // Total angle covered by a single span of the compass ring; divided by compass_interval to get individual spans. + var/compass_period = 45 + + var/list/compass_static_labels + var/list/compass_waypoints + var/list/compass_waypoint_markers + +/obj/compass_holder/Initialize(mapload, ...) + . = ..() + rebuild_compass_overlays() + +/obj/compass_holder/proc/get_label_offset() + return (world.icon_size * round(MIN_VIEW/2)) + +/obj/compass_holder/proc/rebuild_compass_overlays() + + var/effective_compass_period = compass_period/compass_interval + LAZYCLEARLIST(compass_static_labels) + for(var/i in 0 to (360/effective_compass_period)-1) + + var/image/compass_marker/I = new + I.loc = src + + if(i % compass_interval == 0) + I.maptext = STYLE_SMALLFONTS_OUTLINE("
              [get_string_from_angle(i * effective_compass_period)]
              ", 7, bearing_colour, bearing_outline_colour) + else + I.maptext = STYLE_SMALLFONTS("
              ", 7, interval_colour) + + var/matrix/M = matrix() + M.Translate(0, get_label_offset()) + M.Turn(effective_compass_period * i) + I.transform = M + I.add_filter("glow", 1, list(type = "drop_shadow", color = "#77777777", size = 2, offset = 1,x = 0, y = 0)) + I.layer = HUD_BASE_LAYER + I.plane = HUD_PLANE + LAZYADD(compass_static_labels, I) + + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/get_string_from_angle(var/angle) + return global.angle_step_to_dir[clamp(round(angle/45)+1, 1, length(global.angle_step_to_dir))] + +/obj/compass_holder/Destroy() + QDEL_LIST_ASSOC_VAL(compass_waypoints) + compass_waypoints = null + . = ..() + +/obj/compass_holder/proc/get_heading_strength() + return 1 + +/obj/compass_holder/proc/get_heading_angle() + var/atom/A = loc + // Bit of a strange loop - grab the highest atom in our stack that isn't a turf. + while(istype(A) && A.loc && !isturf(A.loc)) + A = A.loc + if(istype(A) && !isturf(A)) + . = dir2angle(A.dir) + else + . = 0 + +/obj/compass_holder/on_update_icon() + set_overlays(compass_static_labels | compass_waypoint_markers) + +/obj/compass_holder/proc/clear_waypoint(var/id) + LAZYREMOVE(compass_waypoints, id) + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/set_waypoint(var/id, var/label, var/heading_x, var/heading_y, var/heading_z, var/label_color) + var/datum/compass_waypoint/wp = LAZYACCESS(compass_waypoints, id) + if(!wp) + wp = new /datum/compass_waypoint() + wp.set_values(label, heading_x, heading_y, heading_z, label_color) + LAZYSET(compass_waypoints, id, wp) + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/recalculate_heading(var/rebuild_icon = TRUE) + if(rebuild_icon) + update_icon() + +/obj/compass_holder/proc/show_waypoint(var/id) + var/datum/compass_waypoint/wp = compass_waypoints[id] + wp.hidden = FALSE + +/obj/compass_holder/proc/hide_waypoint(var/id) + var/datum/compass_waypoint/wp = compass_waypoints[id] + wp.hidden = TRUE + +/obj/compass_holder/proc/hide_waypoints(var/rebuild_overlays = FALSE) + for(var/id in compass_waypoints) + hide_waypoint(id) + if(rebuild_overlays) + rebuild_overlay_lists(TRUE) + +/obj/compass_holder/proc/get_compass_origin() + return get_turf(src) + +/obj/compass_holder/proc/rebuild_overlay_lists(var/update_icon = FALSE) + compass_waypoint_markers = null + var/turf/T = get_compass_origin() + if(istype(T)) + var/translate_val = get_label_offset() + for(var/id in compass_waypoints) + var/datum/compass_waypoint/wp = compass_waypoints[id] + if(should_show(wp)) + wp.recalculate_heading(T.x, T.y, translate_val) + LAZYADD(compass_waypoint_markers, wp.compass_overlay) + if(update_icon) + update_icon() + +/obj/compass_holder/proc/should_show(var/datum/compass_waypoint/wp) + return wp && !wp.hidden diff --git a/code/game/objects/compass/compass_overmap.dm b/code/game/objects/compass/compass_overmap.dm new file mode 100644 index 000000000000..11ee76eef866 --- /dev/null +++ b/code/game/objects/compass/compass_overmap.dm @@ -0,0 +1,90 @@ +#define HEADER_SPEED_THRESHOLD 0.35 + +/obj/compass_holder/overmap + compass_interval = 9 + var/image/compass_heading_marker + var/obj/machinery/computer/ship/helm/owner + +/obj/compass_holder/overmap/Initialize(mapload) + + owner = loc + + if(!istype(owner)) + PRINT_STACK_TRACE("Overmap compass initialized in non-helm atom: [type]") + return INITIALIZE_HINT_QDEL + + var/owner_color = owner.linked?.color || COLOR_WHITE + compass_heading_marker = new /image/compass_marker + compass_heading_marker.maptext = STYLE_SMALLFONTS("
              ", 7, COLOR_WHITE) + compass_heading_marker.add_filter("glow", 1, list(type = "drop_shadow", color = "[owner_color]aa", size = 2, offset = 1, x = 0, y = 0)) + compass_heading_marker.layer = HUD_BASE_LAYER + compass_heading_marker.plane = HUD_PLANE + compass_heading_marker.color = owner_color + + . = ..() + + var/turf/owner_turf = get_turf(owner.linked) + if(!istype(owner_turf)) + hide_waypoints() + return + + var/list/seen_waypoint_ids = list() + for(var/key in owner.known_sectors) + var/datum/computer_file/data/waypoint/waypoint = owner.known_sectors[key] + var/wp_id = "\ref[waypoint]" + set_waypoint(wp_id, uppertext(waypoint.fields["name"]), waypoint.fields["x"], waypoint.fields["y"], owner_turf.z, waypoint.fields["color"] || COLOR_SILVER) + if(!waypoint.fields["tracking"]) + hide_waypoint(wp_id) + seen_waypoint_ids += wp_id + for(var/id in compass_waypoints) + if(!(id in seen_waypoint_ids)) + clear_waypoint(id) + +/obj/compass_holder/overmap/Destroy() + if(owner) + if(owner.compass == src) + owner.compass = null + owner = null + . = ..() + +/obj/compass_holder/overmap/get_heading_strength() + . = clamp(round(max(abs(owner.linked.speed[1]), abs(owner.linked.speed[2]))/(1/(20 SECONDS))), 0, 1) + +/obj/compass_holder/overmap/get_heading_angle() + return owner.linked.get_heading_angle() + +/obj/compass_holder/overmap/get_string_from_angle(var/angle) + return "[angle]" + +/obj/compass_holder/overmap/get_compass_origin() + return get_turf(owner.linked) + +/obj/compass_holder/overmap/recalculate_heading(var/rebuild_icon = TRUE) + var/heading_strength = get_heading_strength() + if(heading_strength >= HEADER_SPEED_THRESHOLD) + var/matrix/M = matrix() + M.Translate(0, round((get_label_offset() - 35) * heading_strength)) + M.Turn(get_heading_angle()) + compass_heading_marker.transform = M + compass_heading_marker.alpha = 255 + else + compass_heading_marker.alpha = 0 + ..() + +/obj/compass_holder/overmap/on_update_icon() + ..() + add_overlay(compass_heading_marker) + +/obj/compass_holder/overmap/rebuild_overlay_lists(var/update_icon = FALSE) + recalculate_heading(FALSE) + . = ..() + +// Don't show markers for stuff we are sitting on top of. +/obj/compass_holder/overmap/should_show(var/datum/compass_waypoint/wp) + . = ..() + if(.) + var/turf/my_turf = get_compass_origin() + var/turf/their_turf = locate(wp.x, wp.y, wp.z) + return my_turf != their_turf + +#undef HEADER_SPEED_THRESHOLD diff --git a/code/game/objects/compass/compass_waypoint.dm b/code/game/objects/compass/compass_waypoint.dm new file mode 100644 index 000000000000..cb3bf6689856 --- /dev/null +++ b/code/game/objects/compass/compass_waypoint.dm @@ -0,0 +1,30 @@ +/datum/compass_waypoint + var/name + var/x + var/y + var/z + var/color + var/hidden = FALSE + var/image/compass_marker/compass_overlay + +/datum/compass_waypoint/proc/set_values(var/_name, var/_x, var/_y, var/_z, var/_color) + name = _name + x = _x + y = _y + z = _z + color = _color + compass_overlay = new + compass_overlay.loc = src + + compass_overlay.maptext = STYLE_SMALLFONTS_OUTLINE("
              |\n[uppertext(name)]
              ", 9, color, COLOR_BLACK) + compass_overlay.add_filter("glow", 1, list(type = "drop_shadow", color = "[color]" + "aa", size = 2, offset = 1,x = 0, y = 0)) + compass_overlay.layer = HUD_BASE_LAYER + compass_overlay.plane = HUD_PLANE + +/datum/compass_waypoint/proc/recalculate_heading(var/cx, var/cy, var/translate_val) + var/matrix/M = matrix() + if(name) + translate_val -= 4 + M.Translate(0, translate_val) + M.Turn(Atan2(cy-y, cx-x)+180) + compass_overlay.transform = M diff --git a/code/game/objects/effects/_effect.dm b/code/game/objects/effects/_effect.dm new file mode 100644 index 000000000000..c90056be1c7f --- /dev/null +++ b/code/game/objects/effects/_effect.dm @@ -0,0 +1,13 @@ +/obj/effect + abstract_type = /obj/effect + +/obj/effect/ShouldSerialize(_age) + SHOULD_CALL_PARENT(FALSE) + return FALSE // Typically no. Specific subtypes should reimplement this (vomit etc) + +/obj/effect/can_be_grabbed(var/mob/grabber, var/target_zone) + return FALSE + +/obj/effect/try_make_grab(mob/living/user, defer_hand = FALSE) + return FALSE + diff --git a/code/game/objects/effects/bump_teleporter.dm b/code/game/objects/effects/bump_teleporter.dm index 2664ad8af513..2cce85346761 100644 --- a/code/game/objects/effects/bump_teleporter.dm +++ b/code/game/objects/effects/bump_teleporter.dm @@ -1,15 +1,15 @@ -var/list/obj/effect/bump_teleporter/BUMP_TELEPORTERS = list() +var/global/list/BUMP_TELEPORTERS = list() /obj/effect/bump_teleporter name = "bump-teleporter" - icon = 'icons/mob/screen1.dmi' + icon = 'icons/effects/markers.dmi' icon_state = "x2" - var/id = null //id of this bump_teleporter. - var/id_target = null //id of bump_teleporter which this moves you to. - invisibility = 101 //nope, can't see this - anchored = 1 - density = 1 - opacity = 0 + invisibility = INVISIBILITY_ABSTRACT //nope, can't see this + anchored = TRUE + density = TRUE + opacity = FALSE + var/id = null //id of this bump_teleporter. + var/id_target = null //id of bump_teleporter which this moves you to. /obj/effect/bump_teleporter/Initialize() . = ..() @@ -21,11 +21,9 @@ var/list/obj/effect/bump_teleporter/BUMP_TELEPORTERS = list() /obj/effect/bump_teleporter/Bumped(atom/user) if(!ismob(user)) - //user.loc = src.loc //Stop at teleporter location return if(!id_target) - //user.loc = src.loc //Stop at teleporter location, there is nowhere to teleport to. return for(var/obj/effect/bump_teleporter/BT in BUMP_TELEPORTERS) diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm index 9b3e6cb9e030..ff08e746ae14 100644 --- a/code/game/objects/effects/chem/chemsmoke.dm +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -3,24 +3,23 @@ ///////////////////////////////////////////// /obj/effect/effect/smoke/chem icon = 'icons/effects/chemsmoke.dmi' - opacity = 0 + opacity = FALSE layer = ABOVE_PROJECTILE_LAYER time_to_live = 300 pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE | PASS_FLAG_GLASS //PASS_FLAG_GLASS is fine here, it's just so the visual effect can "flow" around glass + chem_volume = 500 + var/splash_amount = 10 //atoms moving through a smoke cloud get splashed with up to 10 units of reagent var/turf/destination /obj/effect/effect/smoke/chem/Initialize(mapload, smoke_duration, turf/dest_turf = null, icon/cached_icon = null) - time_to_live = smoke_duration - . = ..() - create_reagents(500) if(cached_icon) icon = cached_icon - set_dir(pick(GLOB.cardinal)) + set_dir(pick(global.cardinal)) pixel_x = -32 + rand(-8, 8) pixel_y = -32 + rand(-8, 8) @@ -36,8 +35,7 @@ /obj/effect/effect/smoke/chem/Destroy() walk(src, 0) // Because we might have called walk_to, we must stop the walk loop or BYOND keeps an internal reference to us forever. set_opacity(0) - // TODO - fadeOut() sleeps. Sleeping in /Destroy is Bad, this needs to be fixed. - fadeOut() + set_density(0) return ..() /obj/effect/effect/smoke/chem/Move() @@ -54,7 +52,7 @@ /obj/effect/effect/smoke/chem/Crossed(atom/movable/AM) ..() - if(!istype(AM, /obj/effect/effect/smoke/chem)) + if(AM.simulated && !istype(AM, /obj/effect/effect/smoke/chem)) reagents.splash(AM, splash_amount, copy = 1) /obj/effect/effect/smoke/chem/proc/initial_splash() @@ -63,22 +61,23 @@ if(!istype(AM, /obj/effect/effect/smoke/chem)) reagents.splash(AM, splash_amount, copy = 1) -// Fades out the smoke smoothly using it's alpha variable. -/obj/effect/effect/smoke/chem/proc/fadeOut(var/frames = 16) - if(!alpha) return //already transparent - - frames = max(frames, 1) //We will just assume that by 0 frames, the coder meant "during one frame". - var/alpha_step = round(alpha / frames) - while(alpha > 0) - alpha = max(0, alpha - alpha_step) - sleep(world.tick_lag) +// Fades out the smoke smoothly using its alpha variable. +/obj/effect/effect/smoke/chem/end_of_life() + if(QDELETED(src)) + return + walk(src, 0) // Because we might have called walk_to, we must stop the walk loop or BYOND keeps an internal reference to us forever. + set_opacity(0) + set_density(0) + animate(src, alpha = 0, time = 0.5 SECONDS) + sleep(0.5 SECONDS) + ..() ///////////////////////////////////////////// // Chem Smoke Effect System ///////////////////////////////////////////// /datum/effect/effect/system/smoke_spread/chem smoke_type = /obj/effect/effect/smoke/chem - var/obj/chemholder + var/obj/effect/chem_holder/chemholder var/range var/list/targetTurfs var/list/wallList @@ -89,17 +88,16 @@ show_log = 0 var/datum/seed/seed -/datum/effect/effect/system/smoke_spread/chem/spores/New(seed_name) - if(seed_name) - seed = SSplants.seeds[seed_name] +/datum/effect/effect/system/smoke_spread/chem/spores/New(seed_id) + if(seed_id) + seed = SSplants.seeds[seed_id] if(!seed) qdel(src) ..() /datum/effect/effect/system/smoke_spread/chem/New() ..() - chemholder = new/obj() - chemholder.create_reagents(500) + chemholder = new(null, 500) //Sets up the chem smoke effect // Calculates the max range smoke can travel, then gets all turfs in that view range. @@ -108,7 +106,7 @@ /datum/effect/effect/system/smoke_spread/chem/set_up(var/datum/reagents/carry = null, n = 10, c = 0, loca, direct) range = n * 0.3 cardinals = c - carry.trans_to_obj(chemholder, carry.total_volume, copy = 1) + carry.trans_to_obj(chemholder, REAGENT_TOTAL_VOLUME(carry), copy = 1) if(istype(loca, /turf/)) location = loca @@ -136,16 +134,17 @@ var/contained = carry.get_reagents() var/area/A = get_area(location) - var/where = "[A.name] | [location.x], [location.y]" - var/whereLink = "[where]" + var/where = "[A.proper_name] | [location.x], [location.y]" + var/whereLink = "[where]" if(show_log) - if(carry.my_atom.fingerprintslast) - var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/atom/location = carry?.get_reaction_loc(CHEM_REACTION_FLAG_OVERFLOW_CONTAINER) + if(location?.fingerprintslast) + var/mob/M = get_mob_by_key(location.fingerprintslast) var/more = "" if(M) - more = "(?)" - log_and_message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].") + more = "(?)" + log_and_message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [location.fingerprintslast][more].") else log_and_message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.") @@ -158,16 +157,10 @@ if(!location) return - if(LAZYLEN(chemholder.reagents.reagent_volumes)) - for(var/turf/T in wallList) + var/trans_volumes = REAGENT_VOLUMES(chemholder.reagents) + if(LAZYLEN(trans_volumes)) + for(var/turf/T in (wallList|targetTurfs)) chemholder.reagents.touch_turf(T) - for(var/turf/T in targetTurfs) - chemholder.reagents.touch_turf(T) - for(var/atom/A in T.contents) - if(istype(A, /obj/effect/effect/smoke/chem) || istype(A, /mob)) - continue - else if(isobj(A) && !A.simulated) - chemholder.reagents.touch_obj(A) var/color = chemholder.reagents.get_color() //build smoke icon var/icon/I @@ -183,7 +176,7 @@ var/pressure = 0 var/datum/gas_mixture/environment = location.return_air() if(environment) pressure = environment.return_pressure() - smoke_duration = between(5, smoke_duration*pressure/(ONE_ATMOSPHERE/3), smoke_duration) + smoke_duration = clamp(smoke_duration*pressure/(ONE_ATMOSPHERE/3), 5, smoke_duration) var/const/arcLength = 2.3559 //distance between each smoke cloud @@ -224,8 +217,9 @@ else smoke = new /obj/effect/effect/smoke/chem(location, smoke_duration + rand(0, 20), T, I) - if(LAZYLEN(chemholder.reagents.reagent_volumes)) - chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents + var/trans_volumes = REAGENT_VOLUMES(chemholder.reagents) + if(LAZYLEN(trans_volumes)) + chemholder.reagents.trans_to_obj(smoke, REAGENT_TOTAL_VOLUME(chemholder.reagents) / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents //Kinda ugly, but needed unless the system is reworked if(splash_initial) @@ -234,7 +228,7 @@ /datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/icon/I, var/smoke_duration, var/dist = 1) var/obj/effect/effect/smoke/chem/spores = new /obj/effect/effect/smoke/chem(location) - spores.SetName("cloud of [seed.seed_name] [seed.seed_noun]") + spores.SetName("cloud of [seed.product_name] [seed.seed_noun]") ..(T, I, smoke_duration, dist, passed_smoke=spores) @@ -245,12 +239,13 @@ pending += location + var/airblock // zeroed by ATMOS_CANPASS_TURF while(pending.len) for(var/turf/current in pending) - for(var/D in GLOB.cardinal) + for(var/D in global.cardinal) var/turf/target = get_step(current, D) if(wallList) - if(istype(target, /turf/simulated/wall)) + if(istype(target, /turf/wall)) if(!(target in wallList)) wallList += target continue @@ -261,9 +256,11 @@ continue if(!(target in targetTurfs)) continue - if(current.c_airblock(target)) //this is needed to stop chemsmoke from passing through thin window walls + ATMOS_CANPASS_TURF(airblock, current, target) + if(airblock) //this is needed to stop chemsmoke from passing through thin window walls continue - if(target.c_airblock(current)) + ATMOS_CANPASS_TURF(airblock, target, current) + if(airblock) continue pending += target diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm index 7b87ed61aa14..56e37741123b 100644 --- a/code/game/objects/effects/chem/foam.dm +++ b/code/game/objects/effects/chem/foam.dm @@ -5,14 +5,14 @@ /obj/effect/effect/foam name = "foam" icon_state = "foam" - opacity = 0 - anchored = 1 - density = 0 + opacity = FALSE + anchored = TRUE + density = FALSE layer = ABOVE_OBJ_LAYER - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE animate_movement = 0 + chem_volume = 10 var/amount = 3 - var/expand = 1 var/metal = 0 /obj/effect/effect/foam/Initialize(mapload, var/ismetal = 0) @@ -23,7 +23,7 @@ spawn(3 + metal * 3) Process() checkReagents() - addtimer(CALLBACK(src, .proc/remove_foam), 12 SECONDS) + addtimer(CALLBACK(src, PROC_REF(remove_foam)), 12 SECONDS) /obj/effect/effect/foam/proc/remove_foam() STOP_PROCESSING(SSobj, src) @@ -38,14 +38,12 @@ if(!metal && reagents) var/turf/T = get_turf(src) reagents.touch_turf(T) - for(var/obj/O in T) - reagents.touch_obj(O) /obj/effect/effect/foam/Process() if(--amount < 0) return - for(var/direction in GLOB.cardinal) + for(var/direction in global.cardinal) var/turf/T = get_step(src, direction) if(!T) continue @@ -59,25 +57,22 @@ F = new(T, metal) F.amount = amount - if(!metal) - F.create_reagents(10) - if(reagents) - for(var/R in reagents.reagent_volumes) - F.reagents.add_reagent(R, 1, safety = 1) //added safety check since reagents in the foam have already had a chance to react + if(!metal && REAGENT_TOTAL_VOLUME(reagents)) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + F.add_to_reagents(reagent, 1, safety = 1) //added safety check since reagents in the foam have already had a chance to react /obj/effect/effect/foam/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) // foam disolves when heated, except metal foams if(!metal && prob(max(0, exposed_temperature - 475))) flick("[icon_state]-disolve", src) + QDEL_IN(src, 5) + return + return ..() - spawn(5) - qdel(src) - -/obj/effect/effect/foam/Crossed(var/atom/movable/AM) - if(metal) +/obj/effect/effect/foam/Crossed(atom/movable/AM) + if(metal || !isliving(AM)) return - if(istype(AM, /mob/living)) - var/mob/living/M = AM - M.slip("the foam", 6) + var/mob/living/M = AM + M.slip("the foam", 6) /datum/effect/effect/system/foam_spread var/amount = 5 // the size of the foam spread. @@ -97,8 +92,8 @@ // bit of a hack here. Foam carries along any reagent also present in the glass it is mixed with (defaults to water if none is present). Rather than actually transfer the reagents, this makes a list of the reagent ids and spawns 1 unit of that reagent when the foam disolves. if(carry && !metal) - for(var/R in carry.reagent_volumes) - carried_reagents += R + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(carry)) + carried_reagents += reagent /datum/effect/effect/system/foam_spread/start() spawn(0) @@ -111,24 +106,23 @@ F.amount = amount if(!metal) // don't carry other chemicals if a metal foam - F.create_reagents(10) - if(carried_reagents) for(var/id in carried_reagents) - F.reagents.add_reagent(id, 1, safety = 1) //makes a safety call because all reagents should have already reacted anyway + F.add_to_reagents(id, 1, safety = 1) //makes a safety call because all reagents should have already reacted anyway else - F.reagents.add_reagent(/decl/material/liquid/water, 1, safety = 1) + F.add_to_reagents(/decl/material/liquid/water, 1, safety = 1) // wall formed by metal foams, dense and opaque, but easy to break /obj/structure/foamedmetal icon = 'icons/effects/effects.dmi' icon_state = "metalfoam" - density = 1 - opacity = 1 // changed in New() - anchored = 1 + density = TRUE + opacity = TRUE + anchored = TRUE name = "foamed metal" desc = "A lightweight foamed metal wall." + atmos_canpass = CANPASS_DENSITY var/metal = 1 // 1 = aluminium, 2 = iron /obj/structure/foamedmetal/Initialize() @@ -138,9 +132,10 @@ /obj/structure/foamedmetal/Destroy() set_density(0) update_nearby_tiles(1) - ..() + return ..() /obj/structure/foamedmetal/on_update_icon() + ..() if(metal == 1) icon_state = "metalfoam" else @@ -149,36 +144,36 @@ /obj/structure/foamedmetal/explosion_act(severity) ..() if(!QDELETED(src)) - physically_destroyed(src) + physically_destroyed() /obj/structure/foamedmetal/bullet_act() if(metal == 1 || prob(50)) qdel(src) /obj/structure/foamedmetal/attack_hand(var/mob/user) - if ((MUTATION_HULK in user.mutations) || (prob(75 - metal * 25))) + SHOULD_CALL_PARENT(FALSE) + if (prob(75 - metal * 25)) user.visible_message("[user] smashes through the foamed metal.", "You smash through the metal foam wall.") qdel(src) else to_chat(user, "You hit the metal foam but bounce off it.") - return - -/obj/structure/foamedmetal/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/grab)) - var/obj/item/grab/G = I - G.affecting.loc = src.loc - visible_message("[G.assailant] smashes [G.affecting] through the foamed metal wall.") - qdel(I) - qdel(src) - return - - if(prob(I.force * 20 - metal * 25)) - user.visible_message("[user] smashes through the foamed metal.", "You smash through the foamed metal with \the [I].") - qdel(src) + return TRUE + + +/obj/structure/foamedmetal/grab_attack(obj/item/grab/grab, mob/user) + grab.affecting.forceMove(loc) + visible_message(SPAN_DANGER("\The [user] smashes \the [grab.affecting] through the foamed metal wall!")) + qdel(grab) + physically_destroyed() + return TRUE + +/obj/structure/foamedmetal/attackby(var/obj/item/used_item, var/mob/user) + if(prob(used_item.expend_attack_force(user) * 20 - metal * 25)) + user.visible_message( + SPAN_WARNING("\The [user] smashes through the foamed metal."), + SPAN_NOTICE("You smash through the foamed metal with \the [used_item].") + ) + physically_destroyed() else - to_chat(user, "You hit the metal foam to no effect.") - -/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) - if(air_group) - return 0 - return !density \ No newline at end of file + to_chat(user, SPAN_WARNING("You hit \the [src] to no effect.")) + return TRUE diff --git a/code/game/objects/effects/chem/water.dm b/code/game/objects/effects/chem/water.dm index 4559b4fe689a..5f7beccd2297 100644 --- a/code/game/objects/effects/chem/water.dm +++ b/code/game/objects/effects/chem/water.dm @@ -2,15 +2,17 @@ name = "water" icon = 'icons/effects/effects.dmi' icon_state = "extinguish" - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE + chem_volume = 10 /obj/effect/effect/water/Initialize() . = ..() QDEL_IN(src, 15 SECONDS) // In case whatever made it forgets to delete it -/obj/effect/effect/water/proc/set_color() // Call it after you move reagents to it - icon += reagents.get_color() +/obj/effect/effect/water/on_reagent_change() + if((. = ..())) + set_color(reagents?.get_color()) /obj/effect/effect/water/proc/set_up(var/turf/target, var/step_count = 5, var/delay = 5) if(!target) @@ -32,20 +34,20 @@ //each step splash 1/5 of the reagents on non-mobs //could determine the # of steps until target, but that would be complicated + // TODO: fix this logic so it isn't using an increasingly smaller amount each iteration. for(var/atom/A in splash_others) - reagents.splash(A, (reagents.total_volume/step_count)/splash_others.len) + reagents.splash(A, (REAGENT_TOTAL_VOLUME(reagents)/step_count)/splash_others.len) for(var/mob/living/M in splash_mobs) - reagents.splash(M, reagents.total_volume/splash_mobs.len) - if(reagents.total_volume < 1) + reagents.splash(M, REAGENT_TOTAL_VOLUME(reagents)/splash_mobs.len) + if(REAGENT_TOTAL_VOLUME(reagents) < 1) break if(T == get_turf(target)) for(var/atom/A in splash_others) - reagents.splash(A, reagents.total_volume/splash_others.len) //splash anything left + reagents.splash(A, REAGENT_TOTAL_VOLUME(reagents)/splash_others.len) //splash anything left break sleep(delay) - sleep(10) - qdel(src) + QDEL_IN(src, 1 SECOND) /obj/effect/effect/water/Move(turf/newloc) if(newloc.density) @@ -54,7 +56,7 @@ /obj/effect/effect/water/Bump(atom/A) if(reagents) - reagents.touch(A) + A.fluid_act(reagents) return ..() //Used by spraybottles. @@ -62,3 +64,4 @@ name = "chemicals" icon = 'icons/obj/chempuff.dmi' icon_state = "" + chem_volume = 10 diff --git a/code/game/objects/effects/chem_holder.dm b/code/game/objects/effects/chem_holder.dm new file mode 100644 index 000000000000..b6c0ea502f78 --- /dev/null +++ b/code/game/objects/effects/chem_holder.dm @@ -0,0 +1,6 @@ +/obj/effect/chem_holder + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/effect/chem_holder/Initialize(mapload, _vol) + chem_volume = _vol + . = ..() diff --git a/code/game/objects/effects/cig_smoke.dm b/code/game/objects/effects/cig_smoke.dm new file mode 100644 index 000000000000..b2c30858d330 --- /dev/null +++ b/code/game/objects/effects/cig_smoke.dm @@ -0,0 +1,21 @@ +/obj/effect/effect/cig_smoke + name = "smoke" + icon_state = "smallsmoke" + icon = 'icons/effects/effects.dmi' + opacity = FALSE + anchored = TRUE + mouse_opacity = FALSE + layer = ABOVE_HUMAN_LAYER + + var/time_to_live = 3 SECONDS + +/obj/effect/effect/cig_smoke/Initialize() + . = ..() + set_dir(pick(global.cardinal)) + pixel_x = rand(0, 13) + pixel_y = rand(0, 13) + return INITIALIZE_HINT_LATELOAD + +/obj/effect/effect/cig_smoke/LateInitialize() + animate(src, alpha = 0, time_to_live, easing = EASE_IN) + QDEL_IN(src, time_to_live) diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm deleted file mode 100644 index 5574b5048138..000000000000 --- a/code/game/objects/effects/decals/Cleanable/aliens.dm +++ /dev/null @@ -1,6 +0,0 @@ -/obj/effect/decal/cleanable/blood/xeno - name = "xeno blood" - desc = "It's green and acidic. It looks like... blood?" - icon = 'icons/effects/blood.dmi' - basecolor = "#05ee05" - cleanable_scent = null diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 78ba0ea4b043..48a282d2fdde 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -1,11 +1,8 @@ -#define DRYING_TIME 5 * 60*10 //for 1 unit of depth in puddle (amount var) #define BLOOD_SIZE_SMALL 1 #define BLOOD_SIZE_MEDIUM 2 #define BLOOD_SIZE_BIG 3 #define BLOOD_SIZE_NO_MERGE -1 -var/global/list/image/splatter_cache=list() - /obj/effect/decal/cleanable/blood name = "blood" desc = "It's some blood. That's not supposed to be there." @@ -15,33 +12,51 @@ var/global/list/image/splatter_cache=list() random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7", "dir_splatter_1", "dir_splatter_2") blood_DNA = list() generic_filth = TRUE - persistent = TRUE + use_legacy_persistence = TRUE appearance_flags = NO_CLIENT_COLOR cleanable_scent = "blood" - scent_descriptor = SCENT_DESC_ODOR + scent_descriptor = "odour" var/base_icon = 'icons/effects/blood.dmi' - var/basecolor=COLOR_BLOOD_HUMAN // Color when wet. + var/basecolor = COLOR_BLOOD_HUMAN // Color when wet. var/amount = 5 + //for 1 unit of depth in puddle (amount var) + var/time_to_dry = 5 MINUTES var/drytime var/dryname = "dried blood" var/drydesc = "It's dry and crusty. Someone isn't doing their job." var/blood_size = BLOOD_SIZE_MEDIUM // A relative size; larger-sized blood will not override smaller-sized blood, except maybe at mapload. + var/list/blood_data + var/chemical = /decl/material/liquid/blood + +/obj/effect/decal/cleanable/blood/Serialize() + . = ..() + if(!generic_filth) // Generic filth is serialized to a type without these vars, so deserializing them will cause errors. + SERIALIZE_IF_MODIFIED(fluorescent, /obj/effect/decal/cleanable/blood) + SERIALIZE_IF_MODIFIED(basecolor, /obj/effect/decal/cleanable/blood) + SERIALIZE_IF_MODIFIED(drytime, /obj/effect/decal/cleanable/blood) + SERIALIZE_DECL_IF_MODIFIED(chemical, /obj/effect/decal/cleanable/blood) + +/obj/effect/decal/cleanable/blood/Deserialize(list/instance_map) + . = ..() + DESERIALIZE_DECL_TO_TYPE(chemical) /obj/effect/decal/cleanable/blood/reveal_blood() - if(!fluorescent) - fluorescent = 1 + if(ispath(chemical, /decl/material/liquid/blood) && !fluorescent) + fluorescent = FLUORESCENT_GLOWS basecolor = COLOR_LUMINOL update_icon() -/obj/effect/decal/cleanable/blood/clean_blood() - fluorescent = 0 - if(invisibility != 100) - set_invisibility(100) - amount = 0 - STOP_PROCESSING(SSobj, src) - remove_extension(src, /datum/extension/scent) - ..(ignore=1) +/obj/effect/decal/cleanable/blood/clean(clean_forensics = TRUE) + if(ispath(chemical, /decl/material/liquid/blood)) + clean_forensics = FALSE + fluorescent = FALSE + if(invisibility != INVISIBILITY_ABSTRACT) + set_invisibility(INVISIBILITY_ABSTRACT) + amount = 0 + STOP_PROCESSING(SSobj, src) + remove_extension(src, /datum/extension/scent) + . = ..(clean_forensics) /obj/effect/decal/cleanable/blood/hide() return @@ -50,8 +65,11 @@ var/global/list/image/splatter_cache=list() STOP_PROCESSING(SSobj, src) return ..() -/obj/effect/decal/cleanable/blood/Initialize(mapload) +// new_chemical is a material typepath, or null +/obj/effect/decal/cleanable/blood/Initialize(ml, _age, new_chemical) . = ..() + if(!isnull(new_chemical)) + chemical = new_chemical if(merge_with_blood()) return INITIALIZE_HINT_QDEL start_drying() @@ -59,16 +77,33 @@ var/global/list/image/splatter_cache=list() // Returns true if overriden and needs deletion. If the argument is false, we will merge into any existing blood. /obj/effect/decal/cleanable/blood/proc/merge_with_blood() if(!isturf(loc) || blood_size == BLOOD_SIZE_NO_MERGE) - return + return FALSE for(var/obj/effect/decal/cleanable/blood/B in loc) - if(B != src && B.blood_size != BLOOD_SIZE_NO_MERGE) - if(B.blood_DNA) - blood_size = BLOOD_SIZE_NO_MERGE - B.blood_DNA |= blood_DNA.Copy() - return TRUE + if(B == src) + continue + if(B.blood_size == BLOOD_SIZE_NO_MERGE) + continue + if(B.invisibility >= INVISIBILITY_ABSTRACT) // has been cleaned + continue + if(B.chemical != chemical) // don't mix blood and oil or oil and mud etc + continue // todo: refactor to make bloody steps use reagents and track data/size/amount on there? + if(B.blood_DNA) + blood_size = BLOOD_SIZE_NO_MERGE + B.blood_DNA |= blood_DNA.Copy() + B.alpha = initial(B.alpha) // reset rain-based fading due to more drips + return TRUE + return FALSE /obj/effect/decal/cleanable/blood/proc/start_drying() - drytime = world.time + DRYING_TIME * (amount+1) + var/decl/material/our_chemical = GET_DECL(chemical) + time_to_dry = our_chemical.get_time_to_dry_stain(src) + switch(time_to_dry) + if(0) // dry instantly + dry() + return + if(-INFINITY to 0) // don't even bother trying to dry this + return + drytime = world.time + time_to_dry * (amount+1) update_icon() START_PROCESSING(SSobj, src) @@ -79,77 +114,50 @@ var/global/list/image/splatter_cache=list() /obj/effect/decal/cleanable/blood/on_update_icon() if(basecolor == "rainbow") basecolor = get_random_colour(1) color = basecolor - if(basecolor == SYNTH_BLOOD_COLOUR) + if(basecolor == SYNTH_BLOOD_COLOR) SetName("oil") desc = "It's black and greasy." else SetName(initial(name)) desc = initial(desc) -/obj/effect/decal/cleanable/blood/Crossed(mob/living/carbon/human/perp) - if (!istype(perp)) - return - if(amount < 1) +/obj/effect/decal/cleanable/blood/Crossed(atom/movable/AM) + if(!isliving(AM) || amount < 1) return - - var/obj/item/organ/external/l_foot = perp.get_organ(BP_L_FOOT) - var/obj/item/organ/external/r_foot = perp.get_organ(BP_R_FOOT) - var/hasfeet = 1 - if((!l_foot || l_foot.is_stump()) && (!r_foot || r_foot.is_stump())) - hasfeet = 0 - if(perp.shoes && !perp.buckled)//Adding blood to shoes - var/obj/item/clothing/shoes/S = perp.shoes - if(istype(S)) - S.blood_color = basecolor - S.track_blood = max(amount,S.track_blood) - if(!S.blood_overlay) - S.generate_blood_overlay() - if(!S.blood_DNA) - S.blood_DNA = list() - S.blood_overlay.color = basecolor - S.overlays += S.blood_overlay - if(S.blood_overlay && S.blood_overlay.color != basecolor) - S.blood_overlay.color = basecolor - S.overlays.Cut() - S.overlays += S.blood_overlay - S.blood_DNA |= blood_DNA.Copy() - - else if (hasfeet)//Or feet - perp.feet_blood_color = basecolor - perp.track_blood = max(amount,perp.track_blood) - if(!perp.feet_blood_DNA) - perp.feet_blood_DNA = list() - perp.feet_blood_DNA |= blood_DNA.Copy() - else if (perp.buckled && istype(perp.buckled, /obj/structure/bed/chair/wheelchair)) - var/obj/structure/bed/chair/wheelchair/W = perp.buckled - W.bloodiness = 4 - - perp.update_inv_shoes(1) + var/mob/living/walker = AM + if(istype(walker.buckled, /obj/structure/chair/wheelchair)) + var/obj/structure/chair/wheelchair/wheelchair = walker.buckled + wheelchair.bloodiness = 4 + else + walker.add_walking_contaminant(chemical, amount, (blood_data ? blood_data[pick(blood_data)] : null)) amount-- /obj/effect/decal/cleanable/blood/proc/dry() + var/decl/material/our_chemical = GET_DECL(chemical) + if(our_chemical.handle_stain_dry(src)) + return TRUE // prevent additional drying handling; this includes preventing processing, so be careful name = dryname desc = drydesc color = adjust_brightness(color, -50) amount = 0 + blood_data = null remove_extension(src, /datum/extension/scent) STOP_PROCESSING(SSobj, src) + return FALSE -/obj/effect/decal/cleanable/blood/attack_hand(mob/living/carbon/human/user) - ..() - if (amount && istype(user)) - if (user.gloves) - return - var/taken = rand(1,amount) - amount -= taken - to_chat(user, "You get some of \the [src] on your hands.") - if (!user.blood_DNA) - user.blood_DNA = list() - user.blood_DNA |= blood_DNA.Copy() - user.bloody_hands = taken - user.hand_blood_color = basecolor - user.update_inv_gloves(1) - user.verbs += /mob/living/carbon/human/proc/bloody_doodle +/obj/effect/decal/cleanable/blood/attack_hand(mob/user) + if(!amount || !length(blood_data) || !ishuman(user)) + return ..() + var/mob/living/human/H = user + if(H.get_equipped_item(slot_gloves_str)) + return ..() + var/taken = rand(1,amount) + amount -= taken + to_chat(user, SPAN_NOTICE("You get some of \the [src] on your hands.")) + for(var/bloodthing in blood_data) + user.add_blood(null, max(1, amount/length(blood_data)), blood_data[bloodthing]) + user.verbs += /mob/living/human/proc/bloody_doodle + return TRUE /obj/effect/decal/cleanable/blood/splatter random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") @@ -176,6 +184,15 @@ var/global/list/image/splatter_cache=list() . = ..() drips = list(icon_state) +/obj/effect/decal/cleanable/blood/drip/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + color = basecolor + set_overlays(drips?.Copy()) + +/obj/effect/decal/cleanable/blood/drip/Destroy() + LAZYCLEARLIST(drips) + return ..() + /obj/effect/decal/cleanable/blood/writing icon = 'icons/effects/writing.dmi' icon_state = "writing" @@ -191,17 +208,17 @@ var/global/list/image/splatter_cache=list() /obj/effect/decal/cleanable/blood/writing/Initialize() . = ..() if(LAZYLEN(random_icon_states)) - for(var/obj/effect/decal/cleanable/blood/writing/W in loc) - random_icon_states.Remove(W.icon_state) + for(var/obj/effect/decal/cleanable/blood/writing/writing in loc) + random_icon_states.Remove(writing.icon_state) icon_state = pick(random_icon_states) else icon_state = "writing1" -/obj/effect/decal/cleanable/blood/writing/examine(mob/user) +/obj/effect/decal/cleanable/blood/writing/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/processed_message = user.handle_reading_literacy(user, message) if(processed_message) - to_chat(user, "It reads: \"[message]\"") + . += "It reads: \"[message]\"" /obj/effect/decal/cleanable/blood/gibs name = "gibs" @@ -250,10 +267,10 @@ var/global/list/image/splatter_cache=list() /obj/effect/decal/cleanable/blood/gibs/proc/streak(var/list/directions) spawn (0) var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) + for (var/i in 1 to pick(1, 200; 2, 150; 3, 50; 4)) sleep(3) - if (i > 0) - var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(loc) + if (i > 1) + var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(loc, null, chemical) b.basecolor = src.basecolor b.update_icon() if (step_to(src, get_step(src, direction), 0)) @@ -272,13 +289,7 @@ var/global/list/image/splatter_cache=list() icon = 'icons/effects/blood.dmi' icon_state = "mucus" generic_filth = TRUE - persistent = TRUE - var/dry=0 // Keeps the lag down - -/obj/effect/decal/cleanable/mucus/Initialize() - . = ..() - spawn(DRYING_TIME * 2) - dry=1 + use_legacy_persistence = TRUE #undef BLOOD_SIZE_SMALL #undef BLOOD_SIZE_MEDIUM diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index 1676fe1322a5..9b96d6939412 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -1,116 +1,151 @@ /obj/effect/decal/cleanable/generic - name = "clutter" - desc = "Someone should clean that up." - gender = PLURAL - icon = 'icons/obj/objects.dmi' - icon_state = "shards" + name = "clutter" + desc = "Someone should clean that up." + gender = PLURAL + icon = 'icons/obj/objects.dmi' + icon_state = "shards" + sweepable = TRUE /obj/effect/decal/cleanable/ash - name = "ashes" - desc = "Ashes to ashes, dust to dust, and into space." - gender = PLURAL - icon = 'icons/obj/objects.dmi' - icon_state = "ash" + name = "ashes" + desc = "Ashes to ashes, dust to dust, and into space." + gender = PLURAL + icon = 'icons/obj/objects.dmi' + icon_state = "ash" + weather_sensitive = FALSE + sweepable = TRUE + burnable = FALSE + +/obj/effect/decal/cleanable/ash/attackby(obj/item/used_item, mob/user) + if(ATOM_IS_OPEN_CONTAINER(used_item)) + if(REAGENTS_FREE_SPACE(used_item.reagents) <= 0) + to_chat(user, SPAN_WARNING("\The [used_item] is full.")) + else + used_item.add_to_reagents(/decl/material/solid/carbon/ashes, 20) + user.visible_message(SPAN_NOTICE("\The [user] carefully scoops \the [src] into \the [used_item].")) + qdel(src) + return TRUE + return ..() /obj/effect/decal/cleanable/ash/attack_hand(var/mob/user) - to_chat(user, "[src] sifts through your fingers.") - var/turf/simulated/floor/F = get_turf(src) + SHOULD_CALL_PARENT(FALSE) + to_chat(user, SPAN_NOTICE("\The [src] sifts through your fingers.")) + var/turf/F = get_turf(src) if (istype(F)) - F.dirt += 4 + F.add_dirt(4) qdel(src) - -/obj/effect/decal/cleanable/dirt - name = "dirt" - desc = "Someone should clean that up." - gender = PLURAL - icon = 'icons/effects/effects.dmi' - icon_state = "dirt" - mouse_opacity = 0 - persistent = TRUE + return TRUE /obj/effect/decal/cleanable/flour - name = "flour" - desc = "It's still good. Four second rule!" - gender = PLURAL - icon = 'icons/effects/effects.dmi' - icon_state = "flour" - persistent = TRUE + name = "flour" + desc = "It's still good. Four second rule!" + gender = PLURAL + icon = 'icons/effects/effects.dmi' + icon_state = "flour" + use_legacy_persistence = TRUE + sweepable = TRUE /obj/effect/decal/cleanable/cobweb - name = "cobweb" - desc = "Somebody should remove that." - layer = ABOVE_HUMAN_LAYER - icon = 'icons/effects/effects.dmi' - icon_state = "cobweb1" + name = "cobweb" + desc = "Somebody should remove that." + layer = ABOVE_HUMAN_LAYER + icon = 'icons/effects/effects.dmi' + icon_state = "cobweb1" + weather_sensitive = FALSE + sweepable = TRUE /obj/effect/decal/cleanable/molten_item - name = "gooey grey mass" - desc = "It looks like a melted... something." - icon = 'icons/effects/molten_item.dmi' - icon_state = "molten" - persistent = TRUE - generic_filth = TRUE + name = "gooey grey mass" + desc = "It looks like a melted... something." + icon = 'icons/effects/molten_item.dmi' + icon_state = "molten" + use_legacy_persistence = TRUE + generic_filth = TRUE + weather_sensitive = FALSE /obj/effect/decal/cleanable/cobweb2 - name = "cobweb" - desc = "Somebody should remove that." - layer = ABOVE_HUMAN_LAYER - icon = 'icons/effects/effects.dmi' - icon_state = "cobweb2" + name = "cobweb" + desc = "Somebody should remove that." + layer = ABOVE_HUMAN_LAYER + icon = 'icons/effects/effects.dmi' + icon_state = "cobweb2" + weather_sensitive = FALSE + sweepable = TRUE //Vomit (sorry) /obj/effect/decal/cleanable/vomit - name = "vomit" - desc = "Gosh, how unpleasant." - gender = PLURAL - icon = 'icons/effects/vomit.dmi' - icon_state = "vomit_1" - persistent = TRUE - generic_filth = TRUE + name = "vomit" + desc = "Gosh, how unpleasant." + gender = PLURAL + icon = 'icons/effects/vomit.dmi' + icon_state = "vomit_1" + use_legacy_persistence = TRUE + generic_filth = TRUE + chem_volume = 30 /obj/effect/decal/cleanable/vomit/Initialize(ml, _age) random_icon_states = icon_states(icon) - . = ..() atom_flags |= ATOM_FLAG_OPEN_CONTAINER - create_reagents(30, src) + . = ..() if(prob(75)) - var/matrix/M = matrix() - M.Turn(pick(90, 180, 270)) - transform = M + set_rotation(pick(90, 180, 270)) + +/obj/effect/decal/cleanable/vomit/mapped/Initialize(ml, _age) + . = ..() + add_to_reagents(/decl/material/liquid/acid/stomach, rand(3,5)) + add_to_reagents(/decl/material/liquid/nutriment, rand(5,8)) /obj/effect/decal/cleanable/vomit/on_update_icon() . = ..() - color = reagents.get_color() + color = reagents?.get_color() + +/obj/effect/decal/cleanable/vomit/Crossed(atom/movable/AM) + . = ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(reagents) >= 1 && isliving(AM)) + var/mob/living/walker = AM + walker.add_walking_contaminant(reagents, rand(2, 3)) /obj/effect/decal/cleanable/tomato_smudge - name = "tomato smudge" - desc = "It's red." - icon = 'icons/effects/tomatodecal.dmi' - random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3") - persistent = TRUE - generic_filth = TRUE + name = "tomato smudge" + desc = "It's red." + icon = 'icons/effects/tomatodecal.dmi' + icon_state = "tomato_floor1" + random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3") + use_legacy_persistence = TRUE + generic_filth = TRUE /obj/effect/decal/cleanable/egg_smudge - name = "smashed egg" - desc = "Seems like this one won't hatch." - icon = 'icons/effects/tomatodecal.dmi' - random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3") - persistent = TRUE - generic_filth = TRUE + name = "smashed egg" + desc = "Seems like this one won't hatch." + icon = 'icons/effects/tomatodecal.dmi' + icon_state = "smashed_egg1" + random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3") + use_legacy_persistence = TRUE + generic_filth = TRUE /obj/effect/decal/cleanable/pie_smudge //honk - name = "smashed pie" - desc = "It's pie cream from a cream pie." - icon = 'icons/effects/tomatodecal.dmi' - random_icon_states = list("smashed_pie") - persistent = TRUE - generic_filth = TRUE + name = "smashed pie" + desc = "It's pie cream from a cream pie." + icon = 'icons/effects/tomatodecal.dmi' + icon_state = "smashed_pie" + random_icon_states = list("smashed_pie") + use_legacy_persistence = TRUE + generic_filth = TRUE /obj/effect/decal/cleanable/fruit_smudge - name = "smudge" - desc = "Some kind of fruit smear." - icon = 'icons/effects/blood.dmi' - icon_state = "mfloor1" - random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") - persistent = TRUE - generic_filth = TRUE + name = "smudge" + desc = "Some kind of fruit smear." + icon = 'icons/effects/blood.dmi' + icon_state = "mfloor1" + random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") + use_legacy_persistence = TRUE + generic_filth = TRUE + +/obj/effect/decal/cleanable/champagne + name = "champagne" + desc = "Someone got a bit too excited." + gender = PLURAL + icon = 'icons/effects/effects.dmi' + icon_state = "fchampagne1" + color = COLOR_BRASS + random_icon_states = list("fchampagne1", "fchampagne2", "fchampagne3", "fchampagne4") diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm index 1d42755b169c..925fb3c2e437 100644 --- a/code/game/objects/effects/decals/Cleanable/robots.dm +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -1,33 +1,29 @@ /obj/effect/decal/cleanable/blood/gibs/robot name = "robot debris" desc = "It's a useless heap of junk..." - icon = 'icons/mob/robots_gibs.dmi' + icon = 'icons/mob/robots/_gibs.dmi' icon_state = "gib1" - basecolor = SYNTH_BLOOD_COLOUR + basecolor = SYNTH_BLOOD_COLOR random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") cleanable_scent = "industrial lubricant" scent_intensity = /decl/scent_intensity/normal scent_range = 2 + chemical = /decl/material/liquid/lube /obj/effect/decal/cleanable/blood/gibs/robot/on_update_icon() color = "#ffffff" -/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like - return - /obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions) spawn (0) var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) + for (var/i in 1 to pick(1, 200; 2, 150; 3, 50; 4)) sleep(3) - if (i > 0) + if (i > 1) if (prob(40)) var/obj/effect/decal/cleanable/blood/oil/streak = new(src.loc) streak.update_icon() else if (prob(10)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) if (step_to(src, get_step(src, direction), 0)) break @@ -41,10 +37,13 @@ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1") //2:7 is close enough to 1:4 /obj/effect/decal/cleanable/blood/oil - basecolor = SYNTH_BLOOD_COLOUR + basecolor = SYNTH_BLOOD_COLOR + chemical = /decl/material/liquid/lube + cleanable_scent = "industrial lubricant" -/obj/effect/decal/cleanable/blood/oil/dry() - return +/obj/effect/decal/cleanable/blood/oil/Initialize(mapload) + . = ..() + update_icon() /obj/effect/decal/cleanable/blood/oil/streak random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm index f15164f300da..0b839df5ebea 100644 --- a/code/game/objects/effects/decals/Cleanable/tracks.dm +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -10,18 +10,13 @@ #define TRACKS_GOING_EAST 64 #define TRACKS_GOING_WEST 128 -// 5 seconds -#define TRACKS_CRUSTIFY_TIME 50 - -// color-dir-dry -var/global/list/image/fluidtrack_cache=list() +#define TRACKS_CRUSTIFY_TIME 5 SECONDS /datum/fluidtrack var/direction=0 var/basecolor=COLOR_BLOOD_HUMAN var/wet=0 var/fresh=1 - var/crusty=0 var/image/overlay /datum/fluidtrack/New(_direction,_color,_wet) @@ -30,8 +25,9 @@ var/global/list/image/fluidtrack_cache=list() src.wet=_wet /obj/effect/decal/cleanable/blood/tracks/reveal_blood() - if(!fluorescent) - if(stack && stack.len) + // don't reveal non-blood tracks + if(ispath(chemical, /decl/material/liquid/blood) && !fluorescent) + if(LAZYLEN(stack)) for(var/datum/fluidtrack/track in stack) track.basecolor = COLOR_LUMINOL ..() @@ -72,9 +68,10 @@ var/global/list/image/fluidtrack_cache=list() * @param bloodcolor Color of the blood when wet. */ /obj/effect/decal/cleanable/blood/tracks/proc/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor=COLOR_BLOOD_HUMAN) + var/updated=0 // Shift our goingdir 4 spaces to the left so it's in the GOING bitblock. - var/realgoing=goingdir<<4 + var/realgoing=BITSHIFT_LEFT(goingdir,4) // Current bit var/b=0 @@ -86,7 +83,7 @@ var/global/list/image/fluidtrack_cache=list() // Process 4 bits for(var/bi=0;bi<4;bi++) - b=1<>4 + truedir=BITSHIFT_RIGHT(truedir,4) if(track.overlay) track.overlay=null - var/image/I = image(icon, icon_state=state, dir=num2dir(truedir)) + var/image/I = image(icon, icon_state=state, dir=FIRST_DIR(truedir)) I.color = track.basecolor track.fresh=0 track.overlay=I stack[stack_idx]=track - overlays += I + add_overlay(I) updatedtracks=0 // Clear our memory of updated tracks. + compile_overlays() /obj/effect/decal/cleanable/blood/tracks/footprints name = "wet footprints" @@ -165,8 +163,8 @@ var/global/list/image/fluidtrack_cache=list() going_state = "human1" /obj/effect/decal/cleanable/blood/tracks/footprints/reversed/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor=COLOR_BLOOD_HUMAN) - comingdir = comingdir && GLOB.reverse_dir[comingdir] - goingdir = goingdir && GLOB.reverse_dir[goingdir] + comingdir = comingdir && global.reverse_dir[comingdir] + goingdir = goingdir && global.reverse_dir[goingdir] ..(DNA, comingdir, goingdir, bloodcolor) /obj/effect/decal/cleanable/blood/tracks/snake diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 9417fdf8a0aa..aa0e391befb5 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -1,48 +1,93 @@ /obj/effect/decal/cleanable density = FALSE anchored = TRUE + abstract_type = /obj/effect/decal/cleanable - var/persistent = FALSE + var/burnable = TRUE + var/sweepable = FALSE + var/weather_sensitive = TRUE + var/use_legacy_persistence = FALSE var/generic_filth = FALSE - var/age = 0 var/list/random_icon_states var/image/hud_overlay/hud_overlay var/cleanable_scent + var/scent_type = /datum/extension/scent/custom var/scent_intensity = /decl/scent_intensity/normal - var/scent_descriptor = SCENT_DESC_SMELL + var/scent_descriptor = "smell" var/scent_range = 2 + var/have_randomized_icon_state = FALSE -/obj/effect/decal/cleanable/Initialize() +/obj/effect/decal/cleanable/ShouldSerialize(_age) + return ..() && use_legacy_persistence + +/obj/effect/decal/cleanable/GetSerializedType() + return generic_filth ? /obj/effect/decal/cleanable/filth : ..() + +/obj/effect/decal/cleanable/Serialize() . = ..() - if(isspace(loc)) - return INITIALIZE_HINT_QDEL - hud_overlay = new /image/hud_overlay('icons/effects/hud_tile.dmi', src, "caution") - hud_overlay.plane = EFFECTS_ABOVE_LIGHTING_PLANE - set_cleanable_scent() + SERIALIZE_IF_MODIFIED(icon_state, /atom) + +/obj/effect/decal/cleanable/Deserialize(list/instance_map) + . = ..() + have_randomized_icon_state = TRUE /obj/effect/decal/cleanable/Initialize(var/ml, var/_age) - if(random_icon_states && length(src.random_icon_states) > 0) - src.icon_state = pick(src.random_icon_states) + if(!have_randomized_icon_state && length(random_icon_states)) + icon_state = pick(random_icon_states) + have_randomized_icon_state = TRUE if(!ml) if(!isnull(_age)) age = _age - SSpersistence.track_value(src, /datum/persistent/filth) + if(use_legacy_persistence) + SSpersistence.track_value(src, /decl/persistence_handler/filth) + . = ..() + hud_overlay = new /image/hud_overlay('icons/effects/hud_tile.dmi', src, "caution") + hud_overlay.plane = ABOVE_LIGHTING_PLANE + hud_overlay.layer = ABOVE_LIGHTING_LAYER + set_cleanable_scent() + + if(isspaceturf(loc)) + animate(src, alpha = 0, time = 5 SECONDS) + QDEL_IN(src, 5 SECONDS) + + if(weather_sensitive) + SSweather_atoms.weather_atoms += src + /obj/effect/decal/cleanable/Destroy() - SSpersistence.forget_value(src, /datum/persistent/filth) + if(weather_sensitive) + SSweather_atoms.weather_atoms -= src + if(use_legacy_persistence) + SSpersistence.forget_value(src, /decl/persistence_handler/filth) + . = ..() + +/obj/effect/decal/cleanable/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) . = ..() + if(burnable && !QDELETED(src)) + qdel(src) -/obj/effect/decal/cleanable/clean_blood(var/ignore = 0) - if(!ignore) +/obj/effect/decal/cleanable/process_weather(obj/abstract/weather_system/weather, decl/state/weather/weather_state) + if(!weather_sensitive) + return PROCESS_KILL + if(weather_state.is_liquid) + alpha -= 15 + if(alpha <= 0) + clean(TRUE) + +/obj/effect/decal/cleanable/clean(clean_forensics = TRUE) + if(clean_forensics) qdel(src) - return - ..() + return TRUE + return ..() /obj/effect/decal/cleanable/proc/set_cleanable_scent() if(cleanable_scent) - set_extension(src, /datum/extension/scent/custom, cleanable_scent, scent_intensity, scent_descriptor, scent_range) + set_extension(src, scent_type, cleanable_scent, scent_intensity, scent_descriptor, scent_range) /obj/effect/decal/cleanable/fluid_act(var/datum/reagents/fluid) - reagents?.trans_to(fluid, reagents.total_volume) - qdel(src) + SHOULD_CALL_PARENT(FALSE) + if(REAGENT_TOTAL_LIQUID_VOLUME(fluid) && !QDELETED(src)) + if(REAGENT_TOTAL_VOLUME(reagents)) + reagents.trans_to(fluid, REAGENT_TOTAL_VOLUME(reagents)) + qdel(src) diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm deleted file mode 100644 index 17e22af2980e..000000000000 --- a/code/game/objects/effects/decals/contraband.dm +++ /dev/null @@ -1,162 +0,0 @@ - -//########################## CONTRABAND ;3333333333333333333 -Agouri ################################################### - -/obj/item/contraband - name = "contraband item" - desc = "You probably shouldn't be holding this." - icon = 'icons/obj/contraband.dmi' - force = 0 - - -/obj/item/contraband/poster - name = "rolled-up poster" - desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface." - icon_state = "rolled_poster" - var/poster_type - -/obj/item/contraband/poster/Initialize(mapload, var/given_poster_type) - if(given_poster_type && !ispath(given_poster_type, /decl/poster)) - . = INITIALIZE_HINT_QDEL - CRASH("Invalid poster type: [log_info_line(given_poster_type)]") - - poster_type = given_poster_type || poster_type - if(!poster_type) - poster_type = pick(subtypesof(/decl/poster)) - - var/list/posters = subtypesof(/decl/poster) - var/serial_number = posters.Find(poster_type) - name += " - No. [serial_number]" - - return ..(mapload) - -//Places the poster on a wall -/obj/item/contraband/poster/afterattack(var/atom/A, var/mob/user, var/adjacent, var/clickparams) - if (!adjacent) - return - - //must place on a wall and user must not be inside a closet/exosuit/whatever - var/turf/W = A - if (!W.is_wall() || !isturf(user.loc)) - to_chat(user, "You can't place this here!") - return - - var/placement_dir = get_dir(user, W) - if (!(placement_dir in GLOB.cardinal)) - to_chat(user, "You must stand directly in front of the wall you wish to place that on.") - return - - if (ArePostersOnWall(W)) - to_chat(user, "There is already a poster there!") - return - - user.visible_message("\The [user] starts placing a poster on \the [W].","You start placing the poster on \the [W].") - - var/obj/structure/sign/poster/P = new (user.loc, placement_dir, poster_type) - qdel(src) - flick("poster_being_set", P) - // Time to place is equal to the time needed to play the flick animation - if(do_after(user, 28, W) && W.is_wall() && !ArePostersOnWall(W, P)) - user.visible_message("\The [user] has placed a poster on \the [W].","You have placed the poster on \the [W].") - else - // We cannot rely on user being on the appropriate turf when placement fails - P.roll_and_drop(get_step(W, turn(placement_dir, 180))) - -/obj/item/contraband/poster/proc/ArePostersOnWall(var/turf/W, var/placed_poster) - //just check if there is a poster on or adjacent to the wall - if (locate(/obj/structure/sign/poster) in W) - return TRUE - - //crude, but will cover most cases. We could do stuff like check pixel_x/y but it's not really worth it. - for (var/dir in GLOB.cardinal) - var/turf/T = get_step(W, dir) - var/poster = locate(/obj/structure/sign/poster) in T - if (poster && placed_poster != poster) - return TRUE - - return FALSE - -//############################## THE ACTUAL DECALS ########################### - -/obj/structure/sign/poster - name = "poster" - desc = "A large piece of space-resistant printed paper." - icon = 'icons/obj/contraband.dmi' - anchored = 1 - var/poster_type - var/ruined = 0 - -/obj/structure/sign/poster/bay_9 - poster_type = /decl/poster/bay_9 - -/obj/structure/sign/poster/bay_50 - poster_type = /decl/poster/bay_50 - -/obj/structure/sign/poster/Initialize(mapload, var/placement_dir = null, var/give_poster_type = null) - . = ..(mapload) - if(!poster_type) - if(give_poster_type) - poster_type = give_poster_type - else - poster_type = pick(subtypesof(/decl/poster)) - set_poster(poster_type) - - switch (placement_dir) - if (NORTH) - pixel_x = 0 - pixel_y = 32 - if (SOUTH) - pixel_x = 0 - pixel_y = -32 - if (EAST) - pixel_x = 32 - pixel_y = 0 - if (WEST) - pixel_x = -32 - pixel_y = 0 - -/obj/structure/sign/poster/proc/set_poster(var/poster_type) - var/decl/poster/design = decls_repository.get_decl(poster_type) - SetName("[initial(name)] - [design.name]") - desc = "[initial(desc)] [design.desc]" - icon_state = design.icon_state - -/obj/structure/sign/poster/attackby(obj/item/W, mob/user) - if(isWirecutter(W)) - playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) - if(ruined) - to_chat(user, "You remove the remnants of the poster.") - qdel(src) - else - to_chat(user, "You carefully remove the poster from the wall.") - roll_and_drop(user.loc) - return - - -/obj/structure/sign/poster/attack_hand(mob/user) - - if(ruined) - return - - if(alert("Do I want to rip the poster from the wall?","You think...","Yes","No") == "Yes") - - if(ruined || !user.Adjacent(src)) - return - - visible_message("\The [user] rips \the [src] in a single, decisive motion!" ) - playsound(src.loc, 'sound/items/poster_ripped.ogg', 100, 1) - ruined = 1 - icon_state = "poster_ripped" - SetName("ripped poster") - desc = "You can't make out anything from the poster's original print. It's ruined." - add_fingerprint(user) - -/obj/structure/sign/poster/proc/roll_and_drop(turf/newloc) - new/obj/item/contraband/poster(newloc, poster_type) - qdel(src) - -/decl/poster - // Name suffix. Poster - [name] - var/name="" - // Description suffix - var/desc="" - var/icon_state="" diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index ca701099e37d..664d7af8c8fb 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -1,26 +1,30 @@ /obj/effect/decal/cleanable/crayon - name = "rune" - desc = "A rune drawn in crayon." - icon = 'icons/obj/rune.dmi' + name = "rune" + desc = "A rune drawn in crayon." + icon = 'icons/effects/crayondecal.dmi' + icon_state = "rune1" + weather_sensitive = FALSE + var/shade_color = COLOR_BLACK -/obj/effect/decal/cleanable/crayon/Initialize(mapload, main = "#ffffff", shade = "#000000", var/type = "rune") - name = type - desc = "A [type] drawn in crayon." +/obj/effect/decal/cleanable/crayon/Initialize(mapload, _color = COLOR_WHITE, _shade_color = COLOR_BLACK, _drawtype = CRAYON_DRAW_RUNE) + . = ..() + name = _drawtype + desc = "\A [_drawtype], drawn in crayon." + color = _color + shade_color = _shade_color + switch(_drawtype) + if(CRAYON_DRAW_RUNE) + icon_state = "rune[rand(1,6)]" + if(CRAYON_DRAW_GRAFFITI) + icon_state = pick("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa") + else + icon_state = _drawtype + update_icon() - switch(type) - if("rune") - type = "rune[rand(1,6)]" - if("graffiti") - type = pick("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa") - - var/icon/mainOverlay = new/icon('icons/effects/crayondecal.dmi',"[type]",2.1) - var/icon/shadeOverlay = new/icon('icons/effects/crayondecal.dmi',"[type]s",2.1) - - mainOverlay.Blend(main,ICON_ADD) - shadeOverlay.Blend(shade,ICON_ADD) - - overlays += mainOverlay - overlays += shadeOverlay - - add_hiddenprint(usr) - . = ..() \ No newline at end of file +/obj/effect/decal/cleanable/crayon/on_update_icon() + . = ..() + if(shade_color) + var/overlay_state = "[icon_state]s" + if(check_state_in_icon(overlay_state, icon)) + add_overlay(overlay_image(icon, overlay_state, shade_color, RESET_COLOR)) + compile_overlays() diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index 9bb48d1f6701..7c4a8c775cb6 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -1,5 +1,6 @@ /obj/effect/decal layer = DECAL_LAYER + var/age = 0 /obj/effect/decal/fall_damage() return 0 @@ -9,3 +10,6 @@ /obj/effect/decal/lava_act() . = !throwing ? ..() : FALSE + +/obj/effect/decal/get_examine_prefix() + return null diff --git a/code/game/objects/effects/decals/decal_serde.dm b/code/game/objects/effects/decals/decal_serde.dm new file mode 100644 index 000000000000..d598f384dcc4 --- /dev/null +++ b/code/game/objects/effects/decals/decal_serde.dm @@ -0,0 +1,10 @@ +/obj/effect/decal/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(age, /obj/effect/decal) + +/obj/effect/decal/Deserialize(list/instance_map) + . = ..() + age++ + +/obj/effect/decal/ShouldSerialize(_age) + return simulated && (isnull(_age) || age < _age) diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 0d1c6153c772..ac3664d7559a 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -1,14 +1,14 @@ /obj/effect/decal/point name = "arrow" - desc = "It's an arrow hanging in mid-air. There may be a wizard about." - icon = 'icons/mob/screen1.dmi' + desc = "It's an arrow hanging in midair. There may be a wizard about." + icon = 'icons/effects/markers.dmi' icon_state = "arrow" layer = POINTER_LAYER - anchored = 1 - mouse_opacity = 0 + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE // Used for spray that you spray at walls, tables, hydrovats etc /obj/effect/decal/spraystill - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE layer = PROJECTILE_LAYER diff --git a/code/game/objects/effects/decals/posters/bs12.dm b/code/game/objects/effects/decals/posters/bs12.dm deleted file mode 100644 index 1e93cc4e7b44..000000000000 --- a/code/game/objects/effects/decals/posters/bs12.dm +++ /dev/null @@ -1,290 +0,0 @@ -// baystation12 posters -/decl/poster/bay_1 - icon_state="bsposter1" - name = "Unlucky Space Explorer" - desc = "This particular one depicts a skeletal form within a space suit." - -/decl/poster/bay_2 - icon_state="bsposter2" - name = "Positronic Logic Conflicts" - desc = "This particular one depicts the cold, unmoving stare of a particular advanced AI." - -/decl/poster/bay_3 - icon_state="bsposter3" - name = "Paranoia" - desc = "This particular one warns of the dangers of trusting your co-workers too much." - -/decl/poster/bay_4 - icon_state="bsposter4" - name = "Keep Calm" - desc = "This particular one is of a famous New Earth design, although a bit modified. Someone has scribbled an O over the A on the poster." - -/decl/poster/bay_5 - icon_state="bsposter5" - name = "Martian Warlord" - desc = "This particular one depicts the cartoony mug of a certain Martial Warmonger." - -/decl/poster/bay_6 - icon_state="bsposter6" - name = "Technological Singularity" - desc = "This particular one is of the blood-curdling symbol of a long-since defeated enemy of humanity." - -/decl/poster/bay_7 - icon_state="bsposter7" - name = "Wasteland" - desc = "This particular one is of a couple of ragged gunmen, one male and one female, on top of a mound of rubble. The number \"12\" is visible on their blue jumpsuits." - -/decl/poster/bay_8 - icon_state="bsposter8" - name = "Pinup Girl Cindy" - desc = "This particular one is of a historical corporate PR girl, Cindy, in a particularly feminine pose." - -/decl/poster/bay_9 - icon_state="bsposter9" - name = "Pinup Girl Amy" - desc = "This particular one is of Amy, the nymphomaniac urban legend of deep space. How this photograph came to be is not known." - -/decl/poster/bay_10 - icon_state="bsposter10" - name = "Don't Panic" - desc = "This particular one depicts some sort of star in a grimace. The \"Don't Panic\" is written in big, friendly letters." - -/decl/poster/bay_11 - icon_state="bsposter11" - name = "Underwater Laboratory" - desc = "This particular one is of the fabled last crew of a previous Company project." - -/decl/poster/bay_12 - icon_state="bsposter12" - name = "Rogue AI" - desc = "This particular one depicts the shell of the infamous AI that catastropically comandeered one of humanity's earliest space stations. Back then, the Company was just known as TriOptimum." - -/decl/poster/bay_13 - icon_state="bsposter13" - name = "User of the Arcane Arts" - desc = "This particular one depicts a wizard, casting a spell. You can't really make out if it's an actual photograph or a computer-generated image." - -/decl/poster/bay_14 - icon_state="bsposter14" - name = "Levitating Skull" - desc = "This particular one is the portrait of a flying enchanted skull. Its adventures along with its fabled companion are now fading through history..." - -/decl/poster/bay_15 - icon_state="bsposter15" - name = "Augmented Legend" - desc = "This particular one is of an obviously augmented individual, gazing towards the sky. The cyber-city in the backround is rather punkish." - -/decl/poster/bay_16 - icon_state="bsposter16" - name = "Dangerous Static" - desc = "This particular one depicts nothing remarkable other than a rather mesmerising pattern of monitor static. There's a tag on the sides of the poster, but it's ripped off." - -/decl/poster/bay_17 - icon_state="bsposter17" - name = "Pinup Girl Val" - desc = "Luscious Val McNeil, the vertically challenged Legal Extraordinaire, winner of Miss Space two years running and favoured pinup girl of Lawyers Weekly." - -/decl/poster/bay_18 - icon_state="bsposter18" - name = "Derpman, Enforcer of the State" - desc = "Here to protect and serve... your donuts! A generously proportioned man, he teaches you the value of hiding your snacks." - -/decl/poster/bay_19 - icon_state="bsposter19" - name = "Respect an Alien" - desc = "This poster depicts a well dressed looking lizard-alien receiving a prestigious award. It appears to espouse greater co-operation and harmony between the two races." - -/decl/poster/bay_20 - icon_state="bsposter20" - name = "Alien Twilight" - desc = "This poster depicts a mysteriously inscrutable, alien scene. Numerous aliens can be seen conversing amidst great, crystalline towers rising above crashing waves" - -/decl/poster/bay_21 - icon_state="bsposter21" - name = "Join the Fuzz!" - desc = "It's a nice recruitment poster of a white haired Chinese woman that says; \"Big Guns, Hot Women, Good Times. Security. We get it done.\"" - -/decl/poster/bay_22 - icon_state="bsposter22" - name = "Looking for a career with excitement?" - desc = "A recruitment poster starring a dark haired woman with glasses and a purple shirt that has \"Got Brains? Got Talent? Not afraid of electric flying monsters that want to suck the soul out of you? Then Xenobiology could use someone like you!\" written on the bottom." - -/decl/poster/bay_23 - icon_state="bsposter23" - name = "Safety first: because electricity doesn't wait!" - desc = "A safety poster starring a clueless looking redhead with frazzled hair. \"Every year, hundreds of employees expose themselves to electric shock. Play it safe. Avoid suspicious doors after electrical storms, and always wear protection when doing electric maintenance.\"" - -/decl/poster/bay_24 - icon_state="bsposter24" - name = "Responsible medbay habits, No #259" - desc = "A poster with a nervous looking geneticist on it states; \"Friends Tell Friends They're Clones. It can cause severe and irreparable emotional trauma if a person is not properly informed of their recent demise. Always follow your contractual obligation and inform them of their recent rejuvenation.\"" - -/decl/poster/bay_25 - icon_state="bsposter25" - name = "Irresponsible medbay habits, No #2" - desc = "This is a safety poster starring a perverted looking naked doctor. \"Sexual harassment is never okay. REPORT any acts of sexual deviance or harassment that disrupt a healthy working environment.\"" - -/decl/poster/bay_26 - icon_state="bsposter26" - name = "The Men We Knew" - desc = "This movie poster depicts a group of soldiers fighting a large exosuit, the movie seems to be a patriotic war movie." - -/decl/poster/bay_27 - icon_state="bsposter27" - name = "Plastic Sheep Can't Scream" - desc = "This is a movie poster for an upcoming horror movie, it features an AI in the front of it." - -/decl/poster/bay_28 - icon_state="bsposter28" - name = "The Stars Know Love" - desc = "This is a movie poster. A bleeding woman is shown drawing a heart in her blood on the window of space ship, it seems to be a romantic Drama." - -/decl/poster/bay_29 - icon_state="bsposter29" - name = "Winter Is Coming" - desc = "On the poster is a frighteningly large wolf, he warns: \"Only YOU can keep humanity from freezing during planetary occultation!\"" - -/decl/poster/bay_30 - icon_state="bsposter30" - name = "Ambrosia Vulgaris" - desc = "Just looking at this poster makes you feel a little bit dizzy." - -/decl/poster/bay_31 - icon_state="bsposter31" - name = "Donut Corp" - desc = "This is an advertisement for Donut Corp, the new innovation in donut technology!" - -/decl/poster/bay_32 - icon_state="bsposter32" - name = "Eat!" - desc = "A poster depicting a hamburger. The poster orders you to consume the hamburger." - -/decl/poster/bay_33 - icon_state="bsposter33" - name = "Tools, tools, tools" - desc = "You can never have enough tools, thats for sure!" - -/decl/poster/bay_34 - icon_state="bsposter34" - name = "Power Up!" - desc = "High reward, higher risk!" - -/decl/poster/bay_35 - icon_state="bsposter35" - name = "Lamarr" - desc = "This is a poster depicting the pet and mascot of the science department." - -/decl/poster/bay_36 - icon_state="bsposter36" - name = "Fancy Borg" - desc = "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it." - -/decl/poster/bay_37 - icon_state="bsposter37" - name = "Fancier Borg" - desc = "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it. This is even fancier than the first poster." - -/decl/poster/bay_38 - icon_state="bsposter38" - name = "Toaster Love" - desc = "This is a poster of a toaster containing two slices of bread. The word LOVE is written in big pink letters underneath." - -/decl/poster/bay_39 - icon_state="bsposter39" - name = "Responsible medbay habits, No #91" - desc = "A safety poster with a chemist holding a vial. \"Always wear safety gear while handling dangerous chemicals, even if it concerns only small amounts.\"" - -/decl/poster/bay_40 - icon_state="bsposter40" - name = "Agreeable work environment" - desc = "This poster depicts a young woman in a stylish dress. \"Try to aim for a pleasant atmosphere in the workspace. A friendly word can do more than forms in triplicate.\"" - -/decl/poster/bay_41 - icon_state="bsposter41" - name = "Professional work environment" - desc = "A safety poster featuring a green haired woman in a shimmering blue dress. \"As an Internal Affairs Agent, your job is to create a fair and agreeable work environment for the crewmembers, as discreetly and professionally as possible.\"" - -/decl/poster/bay_42 - icon_state="bsposter42" - name = "Engineering pinup" - desc = "This is pin-up poster. A half-naked girl with white hair, toned muscles and stunning blue eyes looks back at you from the poster. Her welding helmet, tattoos and grey jumpsuit hanging around her waist gives a bit of a rugged feel." - -/decl/poster/bay_43 - icon_state="bsposter43" - name = "Responsible medbay habits, No #3" - desc = "A safety poster with a purple-haired surgeon. She looks a bit cross. \"Let the surgeons do their work. NEVER replace or remove a surgery tool from where the surgeon put it.\"" - -/decl/poster/bay_45 - icon_state="bsposter45" - name = "Responsible engineering habits, No #1" - desc = "A safety poster featuring a blue haired engineer. \"When repairing a machine or construction, always aim for long-term solutions.\"" - -/decl/poster/bay_46 - icon_state="bsposter46" - name = "Inspirational lawyer" - desc = "An inspirational poster depicting an alien lawyer. He seems to be shouting something, while pointing fiercely to the right." - -/decl/poster/bay_47 - icon_state="bsposter47" - name = "Security pinup" - desc = "This is a pin-up poster. A dark skinned white haired girl poses in the sunlight wearing a tank top with her stomach exposed. The text on the poster states \"M, Succubus of Security.\" and a lipstick mark stains the top right corner, as if kissed by the model herself." - -/decl/poster/bay_48 - icon_state="bsposter48" - name = "Borg pinup?" - desc = "This is a.. pin-up poster? It is a diagram on an old model of cyborg with a note scribbled in marker on the bottom, on the top there is a large XO written in red marker." - -/decl/poster/bay_49 - icon_state="bsposter49" - name = "Engineering recruitment" - desc = "This is a poster showing an engineer relaxing by a computer, the text states \"Living the life! Join Engineering today!\"" - -/decl/poster/bay_50 - icon_state="bsposter50" - name = "Pinup Girl Cindy Kate" - desc = "This particular one is of Cindy Kate, a seductive performer well known among less savoury circles." - -/decl/poster/bay_51 - icon_state="bsposter51" - name = "space appreciation poster" - desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. One of three." - -/decl/poster/bay_52 - icon_state="bsposter52" - name = "fire safety poster" - desc = "This is a poster reminding you of what you should do if you are on fire, or if you are at a dance party." - -/decl/poster/bay_53 - icon_state="bsposter53" - name = "fire extinguisher poster" - desc = "This is a poster reminding you of what you should use to put out a fire." - -/decl/poster/bay_54 - icon_state="bsposter54" - name = "firefighter poster" - desc = "This is a poster of a particularly stern looking firefighter. The caption reads, \"Only you can prevent space fires.\"" - -/decl/poster/bay_55 - icon_state="bsposter55" - name = "Earth appreciation poster" - desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Two of three." - -/decl/poster/bay_56 - icon_state="bsposter56" - name = "Mars appreciation poster" - desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Three of three." - -/decl/poster/bay_57 - icon_state="bsposter57" - name = "space carp warning poster" - desc = "This poster tells of the dangers of space carp infestations." - -/decl/poster/bay_58 - icon_state="bsposter58" - name = "space carp information poster" - desc = "This poster showcases an old spacer saying on the dangers of migrant space carp." - -/decl/poster/bay_59 - icon_state="bsposter59" - name = "poster - Miss Science 2299" - desc = "A large piece of space-resistant printed paper. This pin-up poster depicts a woman wearing a corporate labcoat, a bikini, and a sheepish grin. She's shyly posing atop some highly specialized research equipment." diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm deleted file mode 100644 index 413d259d6fc6..000000000000 --- a/code/game/objects/effects/decals/remains.dm +++ /dev/null @@ -1,44 +0,0 @@ -/obj/item/remains - name = "remains" - gender = PLURAL - icon = 'icons/effects/blood.dmi' - icon_state = "remains" - anchored = 0 - -/obj/item/remains/human - desc = "They look like human remains. They have a strange aura about them." - -/obj/effect/decal/remains // Apparently used by cult somewhere? - desc = "They look like human remains. They have a strange aura about them." - icon = 'icons/effects/blood.dmi' - icon_state = "remains" - -/obj/item/remains/xeno - desc = "They look like the remains of something... alien. They have a strange aura about them." - icon_state = "remainsxeno" - -/obj/item/remains/xeno/charred - color = COLOR_DARK_GRAY - -/obj/item/remains/robot - desc = "They look like the remains of something mechanical. They have a strange aura about them." - icon = 'icons/mob/robots_gibs.dmi' - icon_state = "remainsrobot" - -/obj/item/remains/mouse - desc = "They look like the remains of a small rodent." - icon_state = "mouse" - -/obj/item/remains/lizard - desc = "They look like the remains of a small rodent." - icon_state = "lizard" - -/obj/item/remains/attack_hand(mob/user) - to_chat(user, "[src] sinks together into a pile of ash.") - var/turf/simulated/floor/F = get_turf(src) - if (istype(F)) - new /obj/effect/decal/cleanable/ash(F) - qdel(src) - -/obj/item/remains/robot/attack_hand(mob/user) - return diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm index 0b90110bf066..ada00d11d01e 100644 --- a/code/game/objects/effects/decals/warning_stripes.dm +++ b/code/game/objects/effects/decals/warning_stripes.dm @@ -1,11 +1,4 @@ /obj/effect/decal/warning_stripes icon = 'icons/effects/warning_stripes.dmi' -/obj/effect/decal/warning_stripes/Initialize() - ..() - var/turf/T=get_turf(src) - var/image/I=image(icon, icon_state = icon_state, dir = dir) - I.color=color - I.layer = DECAL_LAYER - T.overlays += I - return INITIALIZE_HINT_QDEL \ No newline at end of file +// Noting that this used to delete self on init and add itself to its turf's overlays. That is inherently broken except when used with /floor_decals, and was removed. \ No newline at end of file diff --git a/code/game/objects/effects/dirty_floor.dm b/code/game/objects/effects/dirty_floor.dm new file mode 100644 index 000000000000..833ddaf2b0a4 --- /dev/null +++ b/code/game/objects/effects/dirty_floor.dm @@ -0,0 +1,44 @@ +/obj/effect/decal/cleanable/dirt + name = "dirt" + desc = "Someone should clean that up." + gender = PLURAL + icon = 'icons/effects/effects.dmi' + icon_state = "dirt" + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + use_legacy_persistence = TRUE + alpha = 0 + var/dirt_amount = 0 + +/obj/effect/decal/cleanable/dirt/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(dirt_amount, /obj/effect/decal/cleanable/dirt) + +/obj/effect/decal/cleanable/dirt/lava_act() + qdel(src) + return TRUE + +// 'the dirt falls through the x' is pretty silly, dirt is generated by people walking. +/obj/effect/decal/cleanable/dirt/begin_falling(lastloc, below) + SHOULD_CALL_PARENT(FALSE) + qdel(src) + return TRUE + +/obj/effect/decal/cleanable/dirt/visible + dirt_amount = 60 + use_legacy_persistence = FALSE // This is a subtype for mapping. + +/obj/effect/decal/cleanable/dirt/Initialize() + . = ..() + for(var/obj/effect/decal/cleanable/dirt/other in loc) + if(other != src) + other.dirt_amount += dirt_amount + return INITIALIZE_HINT_QDEL + verbs.Cut() + update_icon() + +/obj/effect/decal/cleanable/dirt/on_update_icon() + . = ..() + if (dirt_amount <= 50) + alpha = 0 + else + alpha = min((dirt_amount - 50) * 5, 255) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 461e1c916526..c71d79a597c5 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -9,8 +9,7 @@ would spawn and follow the beaker, even if it is carried or thrown. /obj/effect/effect name = "effect" icon = 'icons/effects/effects.dmi' - mouse_opacity = 0 - unacidable = 1//So effect are not targeted by alien acid. + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE /datum/effect/effect/system @@ -20,20 +19,20 @@ would spawn and follow the beaker, even if it is carried or thrown. var/atom/holder var/setup = 0 - proc/set_up(n = 3, c = 0, turf/loc) - if(n > 10) - n = 10 - number = n - cardinals = c - location = loc - setup = 1 +/datum/effect/effect/system/proc/set_up(n = 3, c = 0, turf/loc) + if(n > 10) + n = 10 + number = n + cardinals = c + location = loc + setup = 1 - proc/attach(atom/atom) - holder = atom +/datum/effect/effect/system/proc/attach(atom/atom) + holder = atom - proc/start() +/datum/effect/effect/system/proc/start() - proc/spread() +/datum/effect/effect/system/proc/spread() ///////////////////////////////////////////// @@ -45,7 +44,7 @@ would spawn and follow the beaker, even if it is carried or thrown. // will always spawn at the items location, even if it's moved. /* Example: -var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() -- creates new system +var/global/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() -- creates new system steam.set_up(5, 0, mob.loc) -- sets up variables OPTIONAL: steam.attach(mob) steam.start() -- spawns the effect @@ -55,7 +54,7 @@ steam.start() -- spawns the effect name = "steam" icon = 'icons/effects/effects.dmi' icon_state = "extinguish" - density = 0 + density = FALSE /datum/effect/effect/system/steam_spread @@ -69,7 +68,7 @@ steam.start() -- spawns the effect /datum/effect/effect/system/steam_spread/start() var/i = 0 for(i=0, i 10) @@ -141,18 +163,18 @@ steam.start() -- spawns the effect /datum/effect/effect/system/spark_spread/start() var/i = 0 for(i=0, i M.last_cough + 2 SECONDS) + M.last_cough = world.time + M.emote(/decl/emote/audible/gasp) ///////////////////////////////////////////// // Smoke spread @@ -309,7 +372,7 @@ steam.start() -- spawns the effect n = 10 number = n cardinals = c - if(istype(loca, /turf/)) + if(istype(loca, /turf)) location = loca else location = get_turf(loca) @@ -321,26 +384,25 @@ steam.start() -- spawns the effect for(i=0, i 20) return - addtimer(CALLBACK(src, /datum/effect/effect/system/proc/spread, i), 0) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/effect/effect/system, spread), i), 0) /datum/effect/effect/system/smoke_spread/spread(var/i) if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/smoke/smoke = new smoke_type(location) + if(QDELING(holder)) + holder = null + else + src.location = get_turf(holder) + var/obj/effect/effect/smoke/smoke = new smoke_type(location, rand(8.5 SECONDS, 10.5 SECONDS)) src.total_smoke++ var/direction = src.direction if(!direction) - if(src.cardinals) - direction = pick(GLOB.cardinal) - else - direction = pick(GLOB.alldirs) + direction = pick(src.cardinals ? global.cardinal : global.alldirs) for(i=0, iThe solution violently explodes.") - for(var/mob/M in viewers(1, location)) - if (prob (50 * amount)) - to_chat(M, "The explosion knocks you down.") - M.Weaken(rand(1,5)) - return - else - var/devst = -1 - var/heavy = -1 - var/light = -1 - var/flash = -1 - - // Clamp all values to fractions of GLOB.max_explosion_range, following the same pattern as for tank transfer bombs - if (round(amount/12) > 0) - devst = devst + amount/12 - - if (round(amount/6) > 0) - heavy = heavy + amount/6 - - if (round(amount/3) > 0) - light = light + amount/3 - - if (flashing && flashing_factor) - flash = (amount/4) * flashing_factor - - for(var/mob/M in viewers(8, location)) - to_chat(M, "The solution violently explodes.") - - explosion( - location, - round(min(devst, BOMBCAP_DVSTN_RADIUS)), - round(min(heavy, BOMBCAP_HEAVY_RADIUS)), - round(min(light, BOMBCAP_LIGHT_RADIUS)), - round(min(flash, BOMBCAP_FLASH_RADIUS)) - ) + // Clamp all values to fractions of global.max_explosion_range, following the same pattern as for tank transfer bombs + if (round(amount/12) > 0) + devst = devst + amount/12 + + if (round(amount/6) > 0) + heavy = heavy + amount/6 + + if (round(amount/3) > 0) + light = light + amount/3 + + if (flashing && flashing_factor) + flash = (amount/4) * flashing_factor + + location.visible_message(SPAN_DANGER("The solution violently explodes!")) + + explosion( + location, + round(min(devst, BOMBCAP_DVSTN_RADIUS)), + round(min(heavy, BOMBCAP_HEAVY_RADIUS)), + round(min(light, BOMBCAP_LIGHT_RADIUS)), + round(min(flash, BOMBCAP_FLASH_RADIUS)) + ) diff --git a/code/game/objects/effects/explosion_particles.dm b/code/game/objects/effects/explosion_particles.dm index 381ac048deb7..1077b1b952f1 100644 --- a/code/game/objects/effects/explosion_particles.dm +++ b/code/game/objects/effects/explosion_particles.dm @@ -2,9 +2,9 @@ name = "explosive particles" icon = 'icons/effects/effects.dmi' icon_state = "explosion_particle" - opacity = 1 - anchored = 1 - mouse_opacity = 0 + opacity = TRUE + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE /obj/effect/expl_particles/Initialize() . = ..() @@ -13,7 +13,6 @@ /datum/effect/system/expl_particles var/number = 10 var/turf/location - var/total_particles = 0 /datum/effect/system/expl_particles/proc/set_up(n = 10, loca) number = n @@ -25,7 +24,7 @@ for(i=0, i 6) + icon_state = "3" + new_light_range = 7 + new_light_power = 3 + else if(firelevel > 2.5) + icon_state = "2" + new_light_range = 5 + new_light_power = 2 + else + icon_state = "1" + new_light_range = 3 + new_light_power = 1 + color = fire_color() + set_light(new_light_range, new_light_power, color) START_PROCESSING(SSobj,src) if(lifetime) QDEL_IN(src,lifetime) +/obj/effect/fake_fire/proc/can_affect_atom(atom/target) + if(target == src) + return FALSE + return target.simulated + +/obj/effect/fake_fire/proc/can_affect_mob(mob/living/victim) + return can_affect_atom(victim) + /obj/effect/fake_fire/Process() - for(var/mob/living/L in loc) - L.FireBurn(firelevel,last_temperature,pressure) - loc.fire_act(firelevel,last_temperature,pressure) - for(var/atom/A in loc) - A.fire_act(firelevel,last_temperature,pressure) + if(!loc) + qdel(src) + return PROCESS_KILL + for(var/mob/living/victim in loc) + if(!can_affect_mob(victim)) + continue + victim.FireBurn(firelevel, last_temperature, pressure) + loc.fire_act(firelevel, last_temperature, pressure) + for(var/atom/burned in loc) + if(!can_affect_atom(burned)) + continue + burned.fire_act(firelevel, last_temperature, pressure) + +/obj/effect/fake_fire/proc/fire_color() + var/temperature = max(4000*sqrt(firelevel/vsc.fire_firelevel_multiplier), last_temperature) + return heat2color(temperature) /obj/effect/fake_fire/Destroy() STOP_PROCESSING(SSobj,src) - . = ..() \ No newline at end of file + return ..() + +// A subtype of fake_fire used for spells that shouldn't affect the caster. +/obj/effect/fake_fire/variable/owned + var/mob/living/owner + +/obj/effect/fake_fire/variable/owned/can_affect_atom(atom/target) + if(target == owner) + return FALSE + return ..() + +/obj/effect/fake_fire/variable/owned/Destroy() + owner = null + return ..() \ No newline at end of file diff --git a/code/game/objects/effects/fluids.dm b/code/game/objects/effects/fluids.dm deleted file mode 100644 index 8f6dbc9ae313..000000000000 --- a/code/game/objects/effects/fluids.dm +++ /dev/null @@ -1,202 +0,0 @@ -/obj/effect/fluid - name = "" - icon = 'icons/effects/liquids.dmi' - icon_state = "puddle" - anchored = 1 - simulated = 0 - opacity = 0 - mouse_opacity = 0 - layer = FLY_LAYER - alpha = 0 - color = COLOR_OCEAN - - var/list/neighbors = list() - var/last_flow_strength = 0 - var/next_fluid_act = 0 - var/update_lighting = FALSE - -/obj/effect/fluid/airlock_crush() - qdel(src) - -/obj/effect/fluid/Move() - crash_with("A fluid overlay had Move() called!") - return FALSE - -/obj/effect/fluid/on_reagent_change() - if(reagents?.total_volume <= FLUID_EVAPORATION_POINT) - qdel(src) - return - . = ..() - ADD_ACTIVE_FLUID(src) - update_lighting = TRUE - queue_icon_update() - -/obj/effect/fluid/Initialize() - START_PROCESSING(SSobj, src) - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - icon_state = "" - create_reagents(FLUID_MAX_DEPTH) - . = ..() - var/turf/simulated/T = get_turf(src) - if(!isturf(T) || T.flooded) - return INITIALIZE_HINT_QDEL - if(istype(T)) - T.unwet_floor(FALSE) - for(var/checkdir in GLOB.cardinal) - var/obj/effect/fluid/F = locate() in get_step(src, checkdir) - if(F) - LAZYSET(neighbors, F, TRUE) - LAZYSET(F.neighbors, src, TRUE) - ADD_ACTIVE_FLUID(F) - ADD_ACTIVE_FLUID(src) - -/obj/effect/fluid/Destroy() - var/turf/simulated/T = get_turf(src) - if(istype(T)) - if(length(T.zone?.fuel_objs)) - T.zone.fuel_objs -= src - T.wet_floor() - STOP_PROCESSING(SSobj, src) - for(var/thing in neighbors) - var/obj/effect/fluid/F = thing - LAZYREMOVE(F.neighbors, src) - ADD_ACTIVE_FLUID(F) - neighbors = null - REMOVE_ACTIVE_FLUID(src) - . = ..() - -/obj/effect/fluid/proc/remove_fuel(var/amt) - for(var/rtype in reagents.reagent_volumes) - var/decl/material/liquid/fuel = decls_repository.get_decl(rtype) - if(fuel.fuel_value) - var/removing = min(amt, reagents.reagent_volumes[rtype]) - reagents.remove_reagent(rtype, removing) - amt -= removing - if(amt <= 0) - break - -/obj/effect/fluid/proc/get_fuel_amount() - . = 0 - for(var/rtype in reagents?.reagent_volumes) - var/decl/material/liquid/fuel = decls_repository.get_decl(rtype) - if(fuel.fuel_value) - . += REAGENT_VOLUME(reagents, rtype) * fuel.fuel_value - -/obj/effect/fluid/Process() - - // Evaporation! TODO: add fumes to the air from this, if appropriate. - if(reagents.total_volume > FLUID_EVAPORATION_POINT && reagents.total_volume <= FLUID_PUDDLE) - reagents.remove_any(min(reagents.total_volume, rand(1,3))) - if(reagents.total_volume <= FLUID_EVAPORATION_POINT) - qdel(src) - return - - // Apply reagent interactions to everything on the turf, and the turf itself. - var/list/pushable - if(!isturf(loc)) - return - - loc.fluid_act(reagents) - var/pushing = (world.time >= next_fluid_act && reagents.total_volume > FLUID_SHALLOW && last_flow_strength >= 10) - for(var/thing in loc.contents) - if(thing == src) - continue - var/atom/movable/AM = thing - if(!AM.simulated) - continue - AM.fluid_act(reagents) - if(!QDELETED(AM) && pushing && AM.is_fluid_pushable(last_flow_strength)) - LAZYADD(pushable, AM) - - if(length(pushable)) - next_fluid_act = world.time + SSfluids.fluid_act_delay - if(prob(1)) - playsound(loc, 'sound/effects/slosh.ogg', 25, 1) - for(var/thing in pushable) - step(thing, dir) - -/obj/effect/fluid/on_update_icon() - - overlays.Cut() - - if(reagents.total_volume > FLUID_OVER_MOB_HEAD) - layer = DEEP_FLUID_LAYER - else - layer = SHALLOW_FLUID_LAYER - - color = reagents.get_color() - - if(reagents.total_volume > FLUID_DEEP) - alpha = FLUID_MAX_ALPHA - else - alpha = min(FLUID_MAX_ALPHA,max(FLUID_MIN_ALPHA,ceil(255*(reagents.total_volume/FLUID_DEEP)))) - - if(reagents.total_volume <= FLUID_PUDDLE) - APPLY_FLUID_OVERLAY("puddle") - else if(reagents.total_volume <= FLUID_SHALLOW) - APPLY_FLUID_OVERLAY("shallow_still") - else if(reagents.total_volume < FLUID_DEEP) - APPLY_FLUID_OVERLAY("mid_still") - else if(reagents.total_volume < (FLUID_DEEP*2)) - APPLY_FLUID_OVERLAY("deep_still") - else - APPLY_FLUID_OVERLAY("ocean") - - if(update_lighting) - update_lighting = FALSE - var/glowing - for(var/rtype in reagents.reagent_volumes) - var/decl/material/reagent = decls_repository.get_decl(rtype) - if(REAGENT_VOLUME(reagents, rtype) >= 3 && reagent.radioactivity) - glowing = TRUE - break - if(glowing) - set_light(0.2, 0.1, 1, l_color = COLOR_GREEN) - else - set_light(0) - -// Map helper. -/obj/effect/fluid_mapped - name = "mapped flooded area" - alpha = 125 - icon_state = "shallow_still" - color = COLOR_OCEAN - - var/fluid_type = /decl/material/liquid/water - var/fluid_initial = FLUID_MAX_DEPTH - -/obj/effect/fluid_mapped/Initialize() - ..() - var/turf/T = get_turf(src) - if(istype(T)) - var/obj/effect/fluid/F = locate() in T - if(!F) F = new(T) - F.reagents.add_reagent(fluid_type, fluid_initial) - return INITIALIZE_HINT_QDEL - -/obj/effect/fluid_mapped/fuel - name = "spilled fuel" - fluid_type = /decl/material/liquid/fuel - fluid_initial = 10 - -// Permaflood overlay. -/obj/effect/flood - name = "" - mouse_opacity = 0 - layer = DEEP_FLUID_LAYER - color = COLOR_OCEAN - icon = 'icons/effects/liquids.dmi' - icon_state = "ocean" - alpha = FLUID_MAX_ALPHA - simulated = 0 - density = 0 - opacity = 0 - anchored = 1 - -/obj/effect/flood/explosion_act() - SHOULD_CALL_PARENT(FALSE) - return - -/obj/effect/flood/Initialize() - . = ..() - verbs.Cut() \ No newline at end of file diff --git a/code/game/objects/effects/footprints.dm b/code/game/objects/effects/footprints.dm new file mode 100644 index 000000000000..3f38937b7aa0 --- /dev/null +++ b/code/game/objects/effects/footprints.dm @@ -0,0 +1,56 @@ +// Effect used to render dark spot on turfs like snow/mud. +/obj/effect/footprints + icon = 'icons/mob/footprints/footprints.dmi' + icon_state = "blank" + simulated = FALSE + anchored = TRUE + is_spawnable_type = FALSE + blend_mode = BLEND_SUBTRACT + alpha = 128 + var/list/image/footprints + +/obj/effect/footprints/Initialize(mapload) + . = ..() + verbs.Cut() + name = null + +/obj/effect/footprints/Destroy() + footprints.Cut() // don't qdel images + . = ..() + +/obj/effect/footprints/on_turf_height_change(new_height) + if(simulated) + qdel(src) + return TRUE + return FALSE + +/obj/effect/footprints/on_update_icon() + set_overlays(footprints?.Copy()) + compile_overlays() + +/obj/effect/footprints/proc/add_footprints(mob/crosser, footprint_icon, movement_dir, use_state = "coming") + var/image/update_footprint + for(var/image/footprint in footprints) + if(footprint.icon == footprint_icon && footprint.dir == movement_dir && footprint.icon_state == use_state) + update_footprint = footprint + break + if(!update_footprint) + update_footprint = image(footprint_icon, icon_state = use_state, dir = movement_dir) + update_footprint.alpha = 20 + LAZYADD(footprints, update_footprint) + if(update_footprint.alpha < 120) + update_footprint.alpha += round(crosser.get_object_size() / 5) + queue_icon_update() + return TRUE + +/mob/proc/get_footprints_icon() + if(is_floating) + return null + if(buckled || current_posture?.prone) + return 'icons/mob/footprints/footprints_trail.dmi' + if(istype(buckled, /obj/structure/chair)) + return 'icons/mob/footprints/footprints_wheelchair.dmi' + var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str) + if(istype(shoes) && shoes.footprint_icon) + return shoes.footprint_icon + return get_bodytype()?.get_footprints_icon() diff --git a/code/game/objects/effects/force_portal.dm b/code/game/objects/effects/force_portal.dm index dc4f1b09b9b5..dd0020bcd149 100644 --- a/code/game/objects/effects/force_portal.dm +++ b/code/game/objects/effects/force_portal.dm @@ -4,9 +4,8 @@ icon = 'icons/effects/portal.dmi' icon_state = "portal" blend_mode = BLEND_SUBTRACT - density = 1 - unacidable = 1 - anchored = 1 + density = TRUE + anchored = TRUE var/boom_time = 1 /obj/effect/force_portal/Initialize() @@ -24,9 +23,13 @@ boom_time = 0 /obj/effect/force_portal/proc/boom() - set waitfor = 0 - var/list/possible_turfs = getcircle(get_turf(src), 5) - while(contents && contents.len) + set waitfor = FALSE + var/turf/my_turf = get_turf(src) + if(!my_turf) + qdel(src) + return + var/list/possible_turfs = getcircle(my_turf, 5) + while(length(contents)) var/target = pick(possible_turfs) possible_turfs -= target var/atom/movable/picked = pick(contents) diff --git a/code/game/objects/effects/gateway.dm b/code/game/objects/effects/gateway.dm new file mode 100644 index 000000000000..61c3250d6462 --- /dev/null +++ b/code/game/objects/effects/gateway.dm @@ -0,0 +1,69 @@ +/obj/effect/gateway + name = "gateway" + desc = "You're pretty sure that abyss is staring back." + icon = 'icons/obj/cult.dmi' + icon_state = "hole" + density = TRUE + anchored = TRUE + var/spawnable = null + +/obj/effect/gateway/active + light_range=5 + light_color="#ff0000" + spawnable=list( + /mob/living/simple_animal/hostile/scarybat, + /mob/living/simple_animal/hostile/creature, + /mob/living/simple_animal/hostile/revenant + ) + +/obj/effect/gateway/active/Initialize() + . = ..() + addtimer(CALLBACK(src, PROC_REF(create_and_delete)), rand(30,60) SECONDS) + +/obj/effect/gateway/active/proc/create_and_delete() + var/t = pick(spawnable) + new t(src.loc) + qdel(src) + +/obj/effect/gateway/active/proc/can_transform(mob/victim) + if(victim.stat == DEAD) + return FALSE + if(victim.HasMovementHandler(/datum/movement_handler/mob/transformation)) + return FALSE + if(ishuman(victim) || isrobot(victim)) + return TRUE + return FALSE + +/obj/effect/gateway/active/Crossed(var/atom/movable/AM) + if(!isliving(AM)) + return + + var/mob/living/victim = AM + + if(!can_transform(victim)) + return + + victim.handle_pre_transformation() + + victim.AddMovementHandler(/datum/movement_handler/mob/transformation) + victim.icon = null + victim.overlays.len = 0 + victim.set_invisibility(INVISIBILITY_ABSTRACT) + + if(isrobot(victim)) + var/mob/living/silicon/robot/Robot = victim + QDEL_NULL(Robot.central_processor) + else + for(var/obj/item/thing in victim) + victim.drop_from_inventory(thing) + if(istype(thing, /obj/item/implant)) + qdel(thing) + + var/mob/living/new_mob = new /mob/living/simple_animal/corgi(AM.loc) + new_mob.set_intent(I_FLAG_HARM) + if(victim.mind) + victim.mind.transfer_to(new_mob) + else + new_mob.key = victim.key + + to_chat(new_mob, "Your form morphs into that of a corgi.")//Because we don't have cluwnes \ No newline at end of file diff --git a/code/game/objects/effects/gibs.dm b/code/game/objects/effects/gibs.dm deleted file mode 100644 index 177aee37c9fa..000000000000 --- a/code/game/objects/effects/gibs.dm +++ /dev/null @@ -1,55 +0,0 @@ -/proc/gibs(atom/location, var/datum/dna/MobDNA, gibber_type = /obj/effect/gibspawner/generic, var/fleshcolor, var/bloodcolor) - new gibber_type(location,MobDNA,fleshcolor,bloodcolor) - -/obj/effect/gibspawner - var/sparks = 0 //whether sparks spread on Gib() - var/list/gibtypes = list() - var/list/gibamounts = list() - var/list/gibdirections = list() //of lists - var/fleshcolor //Used for gibbed humans. - var/bloodcolor //Used for gibbed humans. - var/datum/dna/MobDNA - -/obj/effect/gibspawner/Initialize(mapload, var/datum/dna/MobDNA, var/fleshcolor, var/bloodcolor) - ..(mapload) - - if(fleshcolor) src.fleshcolor = fleshcolor - if(bloodcolor) src.bloodcolor = bloodcolor - if(MobDNA) src.MobDNA = MobDNA - Gib(loc) - return INITIALIZE_HINT_QDEL - -/obj/effect/gibspawner/proc/Gib(atom/location) - if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len) - log_error("Gib list length mismatch!") - return - - if(sparks) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() - s.set_up(2, 1, get_turf(location)) // Not sure if it's safe to pass an arbitrary object to set_up, todo - s.start() - - var/obj/effect/decal/cleanable/blood/gibs/gib = null - for(var/i = 1, i<= gibtypes.len, i++) - if(gibamounts[i]) - for(var/j = 1, j<= gibamounts[i], j++) - var/gibType = gibtypes[i] - gib = new gibType(location) - - // Apply human species colouration to masks. - if(fleshcolor) - gib.fleshcolor = fleshcolor - if(bloodcolor) - gib.basecolor = bloodcolor - - gib.update_icon() - - gib.blood_DNA = list() - if(MobDNA) - gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.b_type - else if(istype(src, /obj/effect/gibspawner/human)) // Probably a monkey - gib.blood_DNA["Non-human DNA"] = "A+" - if(istype(location,/turf/)) - var/list/directions = gibdirections[i] - if(directions.len) - gib.streak(directions) \ No newline at end of file diff --git a/code/game/objects/effects/gibspawner.dm b/code/game/objects/effects/gibspawner.dm new file mode 100644 index 000000000000..f9aa2f59941e --- /dev/null +++ b/code/game/objects/effects/gibspawner.dm @@ -0,0 +1,71 @@ +/mob/proc/spawn_gibber(atom/location = loc) + var/gibber_type = get_gibber_type() + if(!gibber_type) + return + if(ispath(gibber_type, /obj/effect/gibspawner)) + return new gibber_type(location, get_blood_type(), get_unique_enzymes(), get_flesh_color(), get_blood_color()) + . = new gibber_type(location) + if(!istype(., /obj/effect/decal/cleanable/blood/gibs)) + return + var/obj/effect/decal/cleanable/blood/gibs/gib = . + gib.fleshcolor = get_flesh_color() + gib.basecolor = get_blood_color() + var/gib_unique_enzymes = get_unique_enzymes() + var/gib_blood_type = get_blood_type() + if(gib_unique_enzymes && gib_blood_type) + LAZYSET(gib.blood_DNA, gib_unique_enzymes, gib_blood_type) + gib.update_icon() + +/obj/effect/gibspawner + var/sparks = 0 //whether sparks spread on spawn_gibs() + var/list/gibtypes = list() + var/list/gibamounts = list() + var/list/gibdirections = list() //of lists + var/fleshcolor //Used for gibbed humans. + var/bloodcolor //Used for gibbed humans. + var/blood_type + var/unique_enzymes + +/obj/effect/gibspawner/Initialize(mapload, var/_blood_type, var/_unique_enzymes, var/_fleshcolor, var/_bloodcolor) + ..(mapload) + if(_fleshcolor) + fleshcolor = _fleshcolor + if(_bloodcolor) + bloodcolor = _bloodcolor + if(_blood_type) + blood_type = _blood_type + if(_unique_enzymes) + unique_enzymes = _unique_enzymes + spawn_gibs(loc) + return INITIALIZE_HINT_QDEL + +/obj/effect/gibspawner/proc/spawn_gibs(atom/location) + if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len) + CRASH("Gib list length mismatch!") + + if(sparks) + spark_at(location, amount = 2, cardinal_only = TRUE) + + var/obj/effect/decal/cleanable/blood/gibs/gib = null + for(var/i = 1, i<= gibtypes.len, i++) + if(gibamounts[i]) + for(var/j = 1, j<= gibamounts[i], j++) + var/gibType = gibtypes[i] + gib = new gibType(location) + + // Apply human species colouration to masks. + if(fleshcolor) + gib.fleshcolor = fleshcolor + if(bloodcolor) + gib.basecolor = bloodcolor + + gib.update_icon() + + if(unique_enzymes && blood_type) + LAZYSET(gib.blood_DNA, unique_enzymes, blood_type) + else if(istype(src, /obj/effect/gibspawner/human)) // Probably a monkey + LAZYSET(gib.blood_DNA, "Non-human DNA", "A+") + if(istype(location,/turf/)) + var/list/directions = gibdirections[i] + if(directions.len) + gib.streak(directions) diff --git a/code/game/objects/effects/item_pickup_ghost.dm b/code/game/objects/effects/item_pickup_ghost.dm index 43c8313fcca5..cd8d1df1cc0b 100644 --- a/code/game/objects/effects/item_pickup_ghost.dm +++ b/code/game/objects/effects/item_pickup_ghost.dm @@ -1,11 +1,10 @@ /obj/effect/temporary/item_pickup_ghost + is_spawnable_type = FALSE var/lifetime = 0.2 SECONDS /obj/effect/temporary/item_pickup_ghost/Initialize(var/mapload, var/obj/item/picked_up) - . = ..(mapload, lifetime, picked_up.icon, picked_up.icon_state) - pixel_x = picked_up.pixel_x - pixel_y = picked_up.pixel_y - color = picked_up.color + . = ..(mapload, lifetime, null, null) + appearance = picked_up.appearance /obj/effect/temporary/item_pickup_ghost/proc/animate_towards(var/atom/target) var/new_pixel_x = pixel_x + (target.x - src.x) * 32 diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 5127f4f024a2..b71fd6a50060 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -1,218 +1,164 @@ -/obj/effect/landmark +var/global/list/obj/abstract/landmark/all_landmarks = list() +/obj/abstract/landmark name = "landmark" - icon = 'icons/effects/landmarks.dmi' - icon_state = "x2" - anchored = 1.0 - unacidable = 1 - simulated = 0 - invisibility = 101 var/delete_me = 0 -/obj/effect/landmark/Initialize() +/obj/abstract/landmark/Initialize() . = ..() tag = "landmark*[name]" - - //TODO clean up this mess - switch(name) //some of these are probably obsolete - if("monkey") - GLOB.monkeystart += loc - delete_me = 1 - if("start") - GLOB.newplayer_start += loc - delete_me = 1 - if("JoinLate") - GLOB.latejoin += loc - delete_me = 1 - if("JoinLateGateway") - GLOB.latejoin_gateway += loc - delete_me = 1 - if("JoinLateCryo") - GLOB.latejoin_cryo += loc - delete_me = 1 - if("JoinLateCyborg") - GLOB.latejoin_cyborg += loc - delete_me = 1 - if("prisonwarp") - GLOB.prisonwarp += loc - delete_me = 1 - if("tdome1") - GLOB.tdome1 += loc - if("tdome2") - GLOB.tdome2 += loc - if("tdomeadmin") - GLOB.tdomeadmin += loc - if("tdomeobserve") - GLOB.tdomeobserve += loc - if("prisonsecuritywarp") - GLOB.prisonsecuritywarp += loc - delete_me = 1 - if("endgame_exit") - endgame_safespawns += loc - delete_me = 1 - if("endgame_wormhole") - endgame_exits += loc - delete_me = 1 - - landmarks_list += src if(delete_me) return INITIALIZE_HINT_QDEL + global.all_landmarks += src -/obj/effect/landmark/proc/delete() - delete_me = 1 +/obj/abstract/landmark/proc/delete() + delete_me = TRUE -/obj/effect/landmark/Destroy() - landmarks_list -= src +/obj/abstract/landmark/Destroy() + global.all_landmarks -= src return ..() -/obj/effect/landmark/start +/obj/abstract/landmark/start name = "start" - icon = 'icons/mob/screen1.dmi' + icon = 'icons/effects/markers.dmi' icon_state = "x" - anchored = 1.0 - invisibility = 101 + anchored = TRUE + invisibility = INVISIBILITY_ABSTRACT -/obj/effect/landmark/start/Initialize() +/obj/abstract/landmark/start/Initialize() tag = "start*[name]" return ..() //Costume spawner landmarks -/obj/effect/landmark/costume +/obj/abstract/landmark/costume delete_me = TRUE -/obj/effect/landmark/costume/Initialize() +/obj/abstract/landmark/costume/Initialize() make_costumes() . = ..() //costume spawner, selects a random subclass and disappears -/obj/effect/landmark/costume/proc/make_costumes() - var/list/options = typesof(/obj/effect/landmark/costume) - var/PICK= options[rand(1,options.len)] - new PICK(loc) +/obj/abstract/landmark/costume/proc/make_costumes() + var/list/options = typesof(/obj/abstract/landmark/costume) + var/costume = pick(options) + new costume(loc) //SUBCLASSES. Spawn a bunch of items and disappear likewise -/obj/effect/landmark/costume/chameleon/make_costumes() - new /obj/item/clothing/mask/chameleon(src.loc) - new /obj/item/clothing/under/chameleon(src.loc) - new /obj/item/clothing/glasses/chameleon(src.loc) - new /obj/item/clothing/shoes/chameleon(src.loc) - new /obj/item/clothing/gloves/chameleon(src.loc) - new /obj/item/clothing/suit/chameleon(src.loc) - new /obj/item/clothing/head/chameleon(src.loc) - new /obj/item/storage/backpack/chameleon(src.loc) - -/obj/effect/landmark/costume/gladiator/make_costumes() - new /obj/item/clothing/under/gladiator(src.loc) - new /obj/item/clothing/head/helmet/gladiator(src.loc) - -/obj/effect/landmark/costume/madscientist/make_costumes() - new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) - new /obj/item/clothing/head/flatcap(src.loc) - new /obj/item/clothing/suit/storage/toggle/labcoat/mad(src.loc) - new /obj/item/clothing/glasses/prescription/gglasses(src.loc) - -/obj/effect/landmark/costume/elpresidente/make_costumes() - new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) - new /obj/item/clothing/head/flatcap(src.loc) - new /obj/item/clothing/mask/smokable/cigarette/cigar/havana(src.loc) - new /obj/item/clothing/shoes/jackboots(src.loc) - -/obj/effect/landmark/costume/nyangirl/make_costumes() - new /obj/item/clothing/under/schoolgirl(src.loc) - new /obj/item/clothing/head/kitty(src.loc) - -/obj/effect/landmark/costume/maid/make_costumes() - new /obj/item/clothing/under/blackskirt(src.loc) - var/CHOICE = pick( /obj/item/clothing/head/beret , /obj/item/clothing/head/rabbitears ) - new CHOICE(src.loc) - new /obj/item/clothing/glasses/blindfold(src.loc) - -/obj/effect/landmark/costume/butler/make_costumes() - new /obj/item/clothing/accessory/wcoat/black(src.loc) - new /obj/item/clothing/under/suit_jacket(src.loc) - new /obj/item/clothing/head/that(src.loc) - -/obj/effect/landmark/costume/prig/make_costumes() - new /obj/item/clothing/accessory/wcoat/black(src.loc) - new /obj/item/clothing/glasses/monocle(src.loc) +/obj/abstract/landmark/costume/chameleon/make_costumes() + new /obj/item/clothing/mask/chameleon(loc) + new /obj/item/clothing/jumpsuit/chameleon(loc) + new /obj/item/clothing/shirt/chameleon(loc) + new /obj/item/clothing/pants/chameleon(loc) + new /obj/item/clothing/glasses/chameleon(loc) + new /obj/item/clothing/shoes/chameleon(loc) + new /obj/item/clothing/gloves/chameleon(loc) + new /obj/item/clothing/suit/chameleon(loc) + new /obj/item/clothing/head/chameleon(loc) + new /obj/item/backpack/chameleon(loc) + +/obj/abstract/landmark/costume/gladiator/make_costumes() + new /obj/item/clothing/costume/gladiator(loc) + new /obj/item/clothing/head/helmet/gladiator(loc) + +/obj/abstract/landmark/costume/madscientist/make_costumes() + new /obj/item/clothing/costume/captain_suit(loc) + new /obj/item/clothing/head/flatcap(loc) + new /obj/item/clothing/suit/toggle/labcoat/mad(loc) + new /obj/item/clothing/glasses/prescription/gglasses(loc) + +/obj/abstract/landmark/costume/elpresidente/make_costumes() + new /obj/item/clothing/costume/captain_suit(loc) + new /obj/item/clothing/head/flatcap(loc) + new /obj/item/clothing/mask/smokable/cigarette/cigar/havana(loc) + new /obj/item/clothing/shoes/jackboots(loc) + +/obj/abstract/landmark/costume/nyangirl/make_costumes() + new /obj/item/clothing/costume/schoolgirl(loc) + new /obj/item/clothing/head/kitty(loc) + +/obj/abstract/landmark/costume/maid/make_costumes() + new /obj/item/clothing/skirt/red/blouse(loc) + var/CHOICE = pick(/obj/item/clothing/head/beret, /obj/item/clothing/head/rabbitears) + new CHOICE(loc) + new /obj/item/clothing/glasses/blindfold(loc) + +/obj/abstract/landmark/costume/butler/make_costumes() + new /obj/item/clothing/pants/slacks(loc) + new /obj/item/clothing/shirt/button(loc) + new /obj/item/clothing/suit/jacket/waistcoat/black(loc) + new /obj/item/clothing/head/that(loc) + +/obj/abstract/landmark/costume/prig/make_costumes() + new /obj/item/clothing/suit/jacket/waistcoat/black(loc) + new /obj/item/clothing/glasses/eyepatch/monocle(loc) var/CHOICE= pick( /obj/item/clothing/head/bowler, /obj/item/clothing/head/that) - new CHOICE(src.loc) - new /obj/item/clothing/shoes/color/black(src.loc) - new /obj/item/cane(src.loc) - new /obj/item/clothing/under/sl_suit(src.loc) - new /obj/item/clothing/mask/fakemoustache(src.loc) - -/obj/effect/landmark/costume/plaguedoctor/make_costumes() - new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(src.loc) - new /obj/item/clothing/head/plaguedoctorhat(src.loc) - -/obj/effect/landmark/costume/nightowl/make_costumes() - new /obj/item/clothing/under/owl(src.loc) - new /obj/item/clothing/mask/gas/owl_mask(src.loc) - -/obj/effect/landmark/costume/waiter/make_costumes() - new /obj/item/clothing/under/waiter(src.loc) + new CHOICE(loc) + new /obj/item/clothing/shoes/color/black(loc) + new /obj/item/cane(loc) + new /obj/item/clothing/pants/slacks/black(loc) + new /obj/item/clothing/shirt/button(loc) + new /obj/item/clothing/mask/fakemoustache(loc) + +/obj/abstract/landmark/costume/plaguedoctor/make_costumes() + new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(loc) + new /obj/item/clothing/head/plaguedoctorhat(loc) + +/obj/abstract/landmark/costume/nightowl/make_costumes() + new /obj/item/clothing/costume/owl(loc) + new /obj/item/clothing/mask/gas/owl_mask(loc) + +/obj/abstract/landmark/costume/waiter/make_costumes() + new /obj/item/clothing/pants/slacks/black(loc) + new /obj/item/clothing/shirt/button(loc) + new /obj/item/clothing/neck/tie/bow/red(loc) + new /obj/item/clothing/suit/jacket/vest/blue(loc) var/CHOICE= pick( /obj/item/clothing/head/kitty, /obj/item/clothing/head/rabbitears) - new CHOICE(src.loc) - new /obj/item/clothing/suit/apron(src.loc) + new CHOICE(loc) + new /obj/item/clothing/suit/apron(loc) -/obj/effect/landmark/costume/pirate/make_costumes() - new /obj/item/clothing/under/pirate(src.loc) - new /obj/item/clothing/suit/pirate(src.loc) +/obj/abstract/landmark/costume/pirate/make_costumes() + new /obj/item/clothing/costume/pirate(loc) + new /obj/item/clothing/suit/pirate(loc) var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/mask/bandana/red) - new CHOICE(src.loc) - new /obj/item/clothing/glasses/eyepatch(src.loc) + new CHOICE(loc) + new /obj/item/clothing/glasses/eyepatch(loc) -/obj/effect/landmark/costume/commie/make_costumes() - new /obj/item/clothing/under/soviet(src.loc) - new /obj/item/clothing/head/ushanka(src.loc) +/obj/abstract/landmark/costume/commie/make_costumes() + new /obj/item/clothing/costume/soviet(loc) + new /obj/item/clothing/head/ushanka(loc) -/obj/effect/landmark/costume/imperium_monk/make_costumes() - new /obj/item/clothing/suit/imperium_monk(src.loc) +/obj/abstract/landmark/costume/imperium_monk/make_costumes() + new /obj/item/clothing/suit/imperium_monk(loc) if (prob(25)) - new /obj/item/clothing/mask/gas/cyborg(src.loc) - -/obj/effect/landmark/costume/holiday_priest/make_costumes() - new /obj/item/clothing/suit/holidaypriest(src.loc) - -/obj/effect/landmark/costume/marisawizard/fake/make_costumes() - new /obj/item/clothing/head/wizard/marisa/fake(src.loc) - new/obj/item/clothing/suit/wizrobe/marisa/fake(src.loc) + new /obj/item/clothing/mask/gas/cyborg(loc) -/obj/effect/landmark/costume/cutewitch/make_costumes() - new /obj/item/clothing/under/sundress(src.loc) - new /obj/item/clothing/head/witchwig(src.loc) - new /obj/item/staff/broom(src.loc) +/obj/abstract/landmark/costume/holiday_priest/make_costumes() + new /obj/item/clothing/suit/holidaypriest(loc) -/obj/effect/landmark/costume/fakewizard/make_costumes() - new /obj/item/clothing/suit/wizrobe/fake(src.loc) - new /obj/item/clothing/head/wizard/fake(src.loc) - new /obj/item/staff/(src.loc) +/obj/abstract/landmark/costume/marisawizard/make_costumes() + new /obj/item/clothing/head/wizard/marisa(loc) + new/obj/item/clothing/suit/wizrobe/marisa(loc) -/obj/effect/landmark/costume/sexyclown/make_costumes() - new /obj/item/clothing/mask/gas/sexyclown(src.loc) - new /obj/item/clothing/under/sexyclown(src.loc) +/obj/abstract/landmark/costume/cutewitch/make_costumes() + new /obj/item/clothing/dress/sun(loc) + new /obj/item/clothing/head/witchwig(loc) + new /obj/item/staff/broom(loc) -/obj/effect/landmark/costume/sexymime/make_costumes() - new /obj/item/clothing/mask/gas/sexymime(src.loc) - new /obj/item/clothing/under/sexymime(src.loc) +/obj/abstract/landmark/costume/wizard/make_costumes() + new /obj/item/clothing/suit/wizrobe(loc) + new /obj/item/clothing/head/wizard/beard(loc) + new /obj/item/staff/(loc) -/obj/effect/landmark/costume/savagehunter/make_costumes() - new /obj/item/clothing/mask/spirit(src.loc) - new /obj/item/clothing/under/savage_hunter(src.loc) +/obj/abstract/landmark/costume/sexyclown/make_costumes() + new /obj/item/clothing/mask/gas/sexyclown(loc) + new /obj/item/clothing/costume/sexyclown(loc) -/obj/effect/landmark/costume/savagehuntress/make_costumes() - new /obj/item/clothing/mask/spirit(src.loc) - new /obj/item/clothing/under/savage_hunter/female(src.loc) +/obj/abstract/landmark/costume/sexymime/make_costumes() + new /obj/item/clothing/mask/gas/sexymime(loc) + new /obj/item/clothing/costume/sexymime(loc) -/obj/effect/landmark/ruin - var/datum/map_template/ruin/ruin_template +/obj/abstract/landmark/costume/savagehunter/make_costumes() + new /obj/item/clothing/mask/spirit(loc) + new /obj/item/clothing/costume/savage_hunter(loc) -/obj/effect/landmark/ruin/Initialize(mapload, my_ruin_template) - name = "ruin_[sequential_id(/obj/effect/landmark/ruin)]" - . = ..() - ruin_template = my_ruin_template - GLOB.ruin_landmarks |= src - -/obj/effect/landmark/ruin/Destroy() - GLOB.ruin_landmarks -= src - ruin_template = null - . = ..() +/obj/abstract/landmark/costume/savagehuntress/make_costumes() + new /obj/item/clothing/mask/spirit(loc) + new /obj/item/clothing/costume/savage_hunter/female(loc) diff --git a/code/game/objects/effects/landmarks_endgame.dm b/code/game/objects/effects/landmarks_endgame.dm new file mode 100644 index 000000000000..59b3f4209f02 --- /dev/null +++ b/code/game/objects/effects/landmarks_endgame.dm @@ -0,0 +1,13 @@ +var/global/list/endgame_exits = list() +var/global/list/endgame_safespawns = list() + +/obj/abstract/landmark/endgame + delete_me = TRUE + +/obj/abstract/landmark/endgame/safe_spawn/Initialize() + global.endgame_safespawns |= get_turf(src) + . = ..() + +/obj/abstract/landmark/endgame/exit/Initialize() + global.endgame_exits |= get_turf(src) + . = ..() diff --git a/code/game/objects/effects/landmarks_latejoin.dm b/code/game/objects/effects/landmarks_latejoin.dm new file mode 100644 index 000000000000..c7ca55458b0c --- /dev/null +++ b/code/game/objects/effects/landmarks_latejoin.dm @@ -0,0 +1,9 @@ +/obj/abstract/landmark/latejoin + delete_me = TRUE + var/spawn_decl = /decl/spawnpoint/arrivals + +/obj/abstract/landmark/latejoin/Initialize() + if(spawn_decl) + var/decl/spawnpoint/spawn_instance = GET_DECL(spawn_decl) + spawn_instance.add_spawn_turf(get_turf(src)) + . = ..() diff --git a/code/game/objects/effects/manifest.dm b/code/game/objects/effects/manifest.dm deleted file mode 100644 index 023b92f552d6..000000000000 --- a/code/game/objects/effects/manifest.dm +++ /dev/null @@ -1,20 +0,0 @@ -/obj/effect/manifest - name = "manifest" - icon = 'icons/mob/screen1.dmi' - icon_state = "x" - unacidable = 1//Just to be sure. - -/obj/effect/manifest/Initialize() - . = ..() - invisibility = INVISIBILITY_ABSTRACT - -/obj/effect/manifest/proc/manifest() - var/dat = "Crew Manifest:
              " - for(var/mob/living/carbon/human/M in SSmobs.mob_list) - dat += text(" [] - []
              ", M.name, M.get_assignment()) - var/obj/item/paper/P = new /obj/item/paper( src.loc ) - P.info = dat - P.SetName("paper- 'Crew Manifest'") - //SN src = null - qdel(src) - return \ No newline at end of file diff --git a/code/game/objects/effects/map_effect/_map_effect.dm b/code/game/objects/effects/map_effect/_map_effect.dm new file mode 100644 index 000000000000..50cad4fa38c5 --- /dev/null +++ b/code/game/objects/effects/map_effect/_map_effect.dm @@ -0,0 +1,31 @@ +/obj/abstract/map_effect + icon = 'icons/effects/map_effects.dmi' + + // Below vars concern check_for_player_proximity() and is used to not waste effort if nobody is around to appreciate the effects. + /// If true, the game will not try to suppress this from firing if nobody is around to see it. + var/always_run = FALSE + /// How many tiles a mob with a client must be for this to run. + var/proximity_needed = 12 + /// If true, ghosts won't satisfy the above requirement. + var/ignore_ghosts = FALSE + /// If true, AFK people (5 minutes) won't satisfy it as well. + var/ignore_afk = TRUE + /// How long until we check for players again. + var/retry_delay = 5 SECONDS + /// Next time we're going to do ACTUAL WORK + var/next_attempt = 0 + +// Helper proc to optimize the use of effects by making sure they do not run if nobody is around to perceive it. +/obj/abstract/map_effect/proc/check_for_player_proximity(radius = 12, ignore_ghosts = FALSE, ignore_afk = TRUE) + if(!z) + return FALSE + for(var/mob/player as anything in player_list) + if(player.z != z) + continue + if(ignore_ghosts && isobserver(player)) + continue + if(ignore_afk && player.client && player.client.is_afk(5 MINUTES)) + continue + if(get_dist(player, src) <= radius) + return TRUE + return FALSE diff --git a/code/game/objects/effects/map_effect/interval/_interval.dm b/code/game/objects/effects/map_effect/interval/_interval.dm new file mode 100644 index 000000000000..ba898570c761 --- /dev/null +++ b/code/game/objects/effects/map_effect/interval/_interval.dm @@ -0,0 +1,32 @@ +// Base type for effects that run on variable intervals. +/obj/abstract/map_effect/interval + var/interval_lower_bound = 5 SECONDS // Lower number for how often the map_effect will trigger. + var/interval_upper_bound = 5 SECONDS // Higher number for above. + +/obj/abstract/map_effect/interval/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/abstract/map_effect/interval/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +// Override this for the specific thing to do. +/obj/abstract/map_effect/interval/proc/trigger_map_effect() + return + +// Handles the delay and making sure it doesn't run when it would be bad. +/obj/abstract/map_effect/interval/Process() + + //Not yet! + if(world.time < next_attempt) + return + + // Check to see if we're useful first. + if(!always_run && !check_for_player_proximity(proximity_needed, ignore_ghosts, ignore_afk)) + next_attempt = world.time + retry_delay + return + + // Hey there's someone nearby. + next_attempt = world.time + rand(interval_lower_bound, interval_upper_bound) + trigger_map_effect() diff --git a/code/game/objects/effects/map_effect/interval/effect_emitter.dm b/code/game/objects/effects/map_effect/interval/effect_emitter.dm new file mode 100644 index 000000000000..51f3216b480a --- /dev/null +++ b/code/game/objects/effects/map_effect/interval/effect_emitter.dm @@ -0,0 +1,62 @@ +/obj/abstract/map_effect/interval/effect_emitter + /// Effect system attached. Set to type to create in Initialize(). + var/datum/effect/effect/system/effect_system = null + /// How many effect objects to create on each interval. Note that there's a hard cap on certain effect_systems. + var/effect_amount = 10 + /// If true, effects only move in cardinal directions. + var/effect_cardinals_only = FALSE + /// If set, effects emitted will always move in this direction. + var/effect_forced_dir + +/obj/abstract/map_effect/interval/effect_emitter/Initialize() + if(ispath(effect_system)) + effect_system = new effect_system() + if(!istype(effect_system)) + return INITIALIZE_HINT_QDEL + effect_system.attach(src) + effect_system.set_up(effect_amount, effect_cardinals_only, src.loc, effect_forced_dir) + return ..() + +/obj/abstract/map_effect/interval/effect_emitter/interval/Destroy() + QDEL_NULL(effect_system) + return ..() + +/obj/abstract/map_effect/interval/effect_emitter/trigger_map_effect() + if(istype(effect_system) && !QDELETED(src)) + effect_system.set_up(effect_amount, effect_cardinals_only, src.loc, effect_forced_dir) + effect_system.start() + +// Makes sparks. +/obj/abstract/map_effect/interval/effect_emitter/sparks + name = "spark emitter" + icon_state = "spark_emitter" + effect_system = /datum/effect/effect/system/spark_spread + interval_lower_bound = 3 SECONDS + interval_upper_bound = 7 SECONDS + +// Makes ""steam"" that looks like fire extinguisher water except it does nothing. +/obj/abstract/map_effect/interval/effect_emitter/steam + name = "steam emitter" + icon_state = "smoke_emitter" + effect_system = /datum/effect/effect/system/steam_spread + +// Creates smoke clouds every so often. +/obj/abstract/map_effect/interval/effect_emitter/smoke + name = "smoke emitter" + icon_state = "smoke_emitter" + effect_system = /datum/effect/effect/system/smoke_spread + interval_lower_bound = 1 SECOND + interval_upper_bound = 1 SECOND + effect_amount = 2 + +/obj/abstract/map_effect/interval/effect_emitter/smoke/mist + name = "mist smoke emitter" + effect_system = /datum/effect/effect/system/smoke_spread/mist + +/obj/abstract/map_effect/interval/effect_emitter/smoke/bad + name = "bad smoke emitter" + effect_system = /datum/effect/effect/system/smoke_spread/bad + +/obj/abstract/map_effect/interval/effect_emitter/smoke/fire + name = "fire smoke emitter" + effect_system = /datum/effect/effect/system/smoke_spread/fire diff --git a/code/game/objects/effects/map_effect/interval/screen_shaker.dm b/code/game/objects/effects/map_effect/interval/screen_shaker.dm new file mode 100644 index 000000000000..724bb7a256df --- /dev/null +++ b/code/game/objects/effects/map_effect/interval/screen_shaker.dm @@ -0,0 +1,17 @@ +/obj/abstract/map_effect/interval/screen_shaker + name = "screen shaker" + icon_state = "screen_shaker" + interval_lower_bound = 1 SECOND + interval_upper_bound = 2 SECONDS + + /// How far the shaking effect extends to. By default it is one screen length. + var/shake_radius = 7 + /// How long the shaking lasts. + var/shake_duration = 2 + /// How much it shakes. + var/shake_strength = 1 + +/obj/abstract/map_effect/interval/screen_shaker/trigger_map_effect() + for(var/mob/player in player_list) + if(player.z == z && get_dist(src, player) <= shake_radius) + shake_camera(player, shake_duration, shake_strength) diff --git a/code/game/objects/effects/map_effect/interval/sound_emitter.dm b/code/game/objects/effects/map_effect/interval/sound_emitter.dm new file mode 100644 index 000000000000..058434882b32 --- /dev/null +++ b/code/game/objects/effects/map_effect/interval/sound_emitter.dm @@ -0,0 +1,51 @@ +/obj/abstract/map_effect/interval/sound_emitter +// Plays a sound at its location every so often. + name = "sound emitter" + icon_state = "sound_emitter" + /// How loud the sound is. 0 is silent, and 100 is loudest. Please be reasonable with the volume. Note that things like vacuum may affect the volume heard by other mobs. + var/sound_volume = 50 + /// If the sound will sound somewhat different each time. If a specific frequency is desired, sound_frequency must also be set. + var/sound_frequency_variance = TRUE + /// Set to make sounds heard from farther away than normal. + var/sound_extra_range = 0 + /// Within the 'fallout distance', the sound stays at the same volume, otherwise it attenuates. Higher numbers make the sound fade out more slowly with distance. + var/sound_fallout = 0 + /// If true, sounds will not be distorted due to the current area's 'sound environment'. It DOES NOT make the sound have a constant volume or z-level wide range, despite the misleading name. + var/sound_global = FALSE + /// Sets a specific custom frequency. sound_frequency_variance must be true as well. If sound_frequency is null, but sound_frequency_variance is true, a semi-random frequency will be chosen to the sound each time. + var/sound_frequency = null + /// Whether or not clients with the ambience preference disabled will hear this sound. + var/sound_is_ambience = TRUE + /// If false, walls will completely muffle the sound. + var/sound_ignore_walls = TRUE + +/obj/abstract/map_effect/interval/sound_emitter/proc/get_sounds_to_play() + return + +/obj/abstract/map_effect/interval/sound_emitter/trigger_map_effect() + playsound( + src, + pick(get_sounds_to_play()), + sound_volume, + sound_frequency_variance, + sound_extra_range, + sound_fallout, + sound_global, + sound_frequency, + sound_is_ambience, + sound_ignore_walls + ) + ..() + +/obj/abstract/map_effect/interval/sound_emitter/footsteps_wood + interval_lower_bound = 5 SECONDS + interval_upper_bound = 30 SECONDS + +/obj/abstract/map_effect/interval/sound_emitter/footsteps_wood/get_sounds_to_play() + var/static/list/sounds_to_play = list( + 'sound/effects/footstep/wood1.ogg', + 'sound/effects/footstep/wood5.ogg', + 'sound/effects/footstep/floor1.ogg', + 'sound/effects/footstep/floor5.ogg' + ) + return sounds_to_play diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm deleted file mode 100644 index c0123bf6c660..000000000000 --- a/code/game/objects/effects/mines.dm +++ /dev/null @@ -1,105 +0,0 @@ -/obj/effect/mine - name = "Mine" - desc = "I Better stay away from that thing." - density = 1 - anchored = 1 - layer = OBJ_LAYER - icon = 'icons/obj/items/weapon/landmine.dmi' - icon_state = "uglymine" - var/triggerproc = "explode" //name of the proc thats called when the mine is triggered - var/triggered = 0 - -/obj/effect/mine/Initialize() - . = ..() - icon_state = "uglyminearmed" - -/obj/effect/mine/Crossed(atom/movable/AM) - Bumped(AM) - -/obj/effect/mine/Bumped(mob/M) - - if(triggered) return - - if(istype(M, /mob/living/carbon/human)) - for(var/mob/O in viewers(world.view, src.loc)) - to_chat(O, "\The [M] triggered the \icon[src] [src]") - triggered = 1 - call(src,triggerproc)(M) - -/obj/effect/mine/proc/triggerrad(obj) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() - s.set_up(3, 1, src) - s.start() - obj:radiation += 50 - randmutb(obj) - domutcheck(obj,null) - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggerstun(obj) - if(ismob(obj)) - var/mob/M = obj - M.Stun(30) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() - s.set_up(3, 1, src) - s.start() - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggern2o(obj) - //example: n2o triggerproc - //note: im lazy - - for (var/turf/simulated/floor/target in range(1,src)) - if(!target.blocks_air) - target.assume_gas(/decl/material/gas/nitrous_oxide, 30) - - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggerflame(obj) - for (var/turf/simulated/floor/target in range(1,src)) - if(!target.blocks_air) - target.assume_gas(/decl/material/gas/hydrogen, 30) - target.hotspot_expose(1000, CELL_VOLUME) - - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggerkick(obj) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread() - s.set_up(3, 1, src) - s.start() - qdel(obj:client) - spawn(0) - qdel(src) - -/obj/effect/mine/proc/explode(obj) - explosion(loc, 0, 1, 2, 3) - spawn(0) - qdel(src) - -/obj/effect/mine/dnascramble - name = "Radiation Mine" - icon_state = "uglymine" - triggerproc = "triggerrad" - -/obj/effect/mine/flame - name = "Incendiary Mine" - icon_state = "uglymine" - triggerproc = "triggerflame" - -/obj/effect/mine/kick - name = "Kick Mine" - icon_state = "uglymine" - triggerproc = "triggerkick" - -/obj/effect/mine/n2o - name = "N2O Mine" - icon_state = "uglymine" - triggerproc = "triggern2o" - -/obj/effect/mine/stun - name = "Stun Mine" - icon_state = "uglymine" - triggerproc = "triggerstun" diff --git a/code/game/objects/effects/mines/_mine.dm b/code/game/objects/effects/mines/_mine.dm new file mode 100644 index 000000000000..a377a9d82869 --- /dev/null +++ b/code/game/objects/effects/mines/_mine.dm @@ -0,0 +1,202 @@ +/obj/item/mine + name = "mine" + desc = "A small landmine." + density = FALSE + anchored = FALSE + icon = 'icons/obj/mine.dmi' + icon_state = "mine" + + var/actual_name + var/actual_desc + var/actual_icon_state + var/hidden_alpha = 255 + + var/panel_open = FALSE + var/armed = FALSE + var/triggering = FALSE + var/datum/mine_payload/payload = /datum/mine_payload/explosive + +/obj/item/mine/Initialize() + . = ..() + if(ispath(payload)) + payload = new payload + register_dangerous_to_step() + + // We store and hide our appearance if we're armed, to avoid people gaming mines via desc. + actual_name = name + actual_desc = desc + actual_icon_state = icon_state + update_icon() + +/obj/item/mine/Destroy() + if(istype(payload)) + QDEL_NULL(payload) + unregister_dangerous_to_step() + return ..() + +/obj/item/mine/on_update_icon() + . = ..() + alpha = initial(alpha) + cut_overlays() + if(panel_open) + add_overlay("[icon_state]_open") + else if(armed) + add_overlay("[icon_state]_armed") + alpha = hidden_alpha + else + add_overlay("[icon_state]_safe") + +/obj/item/mine/attack_self(mob/user) // You do not want to move or throw a land mine while priming it... Explosives + Sudden Movement = Bad Times + if(armed) + to_chat(user, SPAN_WARNING("\The [src] is already armed!")) + return TRUE + add_fingerprint(user) + msg_admin_attack("[key_name_admin(user)] armed \the [src]") + user.visible_message( + SPAN_DANGER("\The [user] starts arming \the [src]."), + SPAN_DANGER("You start arming \the [src]. Hold still!") + ) + + if(user.do_skilled(10 SECONDS, SKILL_DEVICES, src)) + playsound(src, 'sound/weapons/armbomb.ogg', 75, 1, -3) + prime(user) + else if(prob(user.skill_fail_chance(SKILL_DEVICES, 50, SKILL_ADEPT))) + visible_message( + SPAN_DANGER("\The [user] accidentally triggers \the [src]!"), + SPAN_DANGER("You accidentally trigger \the [src]!") + ) + prime(user) + trigger_payload(user) + else + to_chat(user, SPAN_WARNING("You fumble with \the [src], but thankfully manage not to set it off prematurely.")) + return TRUE + +// debug proc, replace with proper disarm minigame +/obj/item/mine/proc/disarm() + armed = FALSE + triggering = FALSE + anchored = FALSE + name = actual_name + desc = actual_desc + icon_state = actual_icon_state + hidden_alpha = 255 + update_icon() + +/obj/item/mine/attack_hand(mob/living/user) + if(armed) + trigger_payload() + return TRUE + return ..() + +/obj/item/mine/attackby(obj/item/W, mob/living/user) + + if(IS_SCREWDRIVER(W)) + if(W.do_tool_interaction(TOOL_SCREWDRIVER, user, src, 15 SECONDS, start_message = "carefully adjusting \the [src]'s casing", check_skill = SKILL_DEVICES)) + panel_open = !panel_open + visible_message(SPAN_NOTICE("\The [user] carefully [(panel_open ? "opens" : "closes")] the casing of \the [src].")) + update_icon() + else if(armed) + if(prob(user.skill_fail_chance(SKILL_DEVICES, 75, SKILL_PROF))) + to_chat(user, SPAN_DANGER("You set off \the [src]!")) + trigger_payload(user) + else + to_chat(user, SPAN_WARNING("You fumble with \the [src], but thankfully manage not to set it off prematurely.")) + return TRUE + + if(armed) + if(panel_open && IS_WIRECUTTER(W)) + if(W.do_tool_interaction(TOOL_WIRECUTTERS, user, src, 30 SECONDS, start_message = "painstakingly disarming \the [src]", check_skill = SKILL_DEVICES)) + visible_message(SPAN_NOTICE("\The [user] disarms \the [src]!")) + disarm() + return TRUE + if(armed) // checking again in case the do_after() stacks + if(prob(user.skill_fail_chance(SKILL_DEVICES, 75, SKILL_PROF))) + to_chat(user, SPAN_DANGER("You set off \the [src]!")) + trigger_payload(user) + else + to_chat(user, SPAN_WARNING("You fumble with \the [src], but thankfully manage not to set it off prematurely.")) + return TRUE + + return ..() + +/obj/item/mine/proc/prime(mob/user) + + if(armed) + return + + if(user) + visible_message(SPAN_NOTICE("\The [src] beeps as the priming sequence completes.")) + user.drop_from_inventory(src, get_turf(user)) + add_fingerprint(user) + + anchored = TRUE + armed = TRUE + + if(istype(loc, /turf/floor) && prob(65)) + var/turf/floor/floor = loc + var/decl/flooring/flooring = floor.get_topmost_flooring() + if(flooring.can_conceal_hazards) + hidden_alpha = pick(50, 90, 120) + + name = "mine" + desc = "A small landmine." + icon_state = "mine" + update_icon() + +/obj/item/mine/forceMove() + var/turf/old_turf = get_turf(loc) + . = ..() + if(.) + var/turf/new_turf = get_turf(src) + if(old_turf != new_turf) + old_turf?.unregister_dangerous_object(src) + new_turf?.register_dangerous_object(src) + +/obj/item/mine/Move() + var/turf/old_turf = get_turf(loc) + . = ..() + if(.) + var/turf/new_turf = get_turf(src) + if(old_turf != new_turf) + old_turf?.unregister_dangerous_object(src) + new_turf?.register_dangerous_object(src) + +/obj/item/mine/proc/trigger_payload(var/mob/living/M) + if(!triggering && payload && armed) + triggering = TRUE + if(ismob(loc)) + var/mob/holder = loc + holder.drop_from_inventory(src) + visible_message("\The [src] goes off!") + payload.trigger_payload(src, M) + disarm() // the mine can be reused if the payload doesn't destroy it. + return TRUE + return FALSE + +/obj/item/mine/bullet_act() + if(prob(50)) + trigger_payload() + if(!QDELETED(src)) + ..() + +/obj/item/mine/explosion_act(severity) + if(severity <= 2 || prob(50)) + trigger_payload() + if(!QDELETED(src)) + . = ..() + +/obj/item/mine/Crossed(atom/movable/AM) + . = ..() + if(istype(AM) && !AM.is_incorporeal()) + Bumped(AM) + +/obj/item/mine/Bumped(atom/movable/AM) + . = ..() + if(armed && !QDELETED(src) && !is_safe_to_step(AM)) + trigger_payload(AM) + +// This tells AI mobs to not be dumb and step on mines willingly. +/obj/item/mine/is_safe_to_step(mob/living/stepper) + if(!armed) + return TRUE + return !armed || stepper.can_overcome_gravity() diff --git a/code/game/objects/effects/mines/_mine_payload.dm b/code/game/objects/effects/mines/_mine_payload.dm new file mode 100644 index 000000000000..99139be493d7 --- /dev/null +++ b/code/game/objects/effects/mines/_mine_payload.dm @@ -0,0 +1,22 @@ +/datum/mine_payload + var/do_sparks = TRUE + var/destroy_self_on_trigger = TRUE + +/datum/mine_payload/proc/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + if(do_sparks) + var/datum/effect/effect/system/spark_spread/s = new + s.set_up(3, 1, owner) + s.start() + if(destroy_self_on_trigger) + if(!QDELETED(owner)) + QDEL_IN(owner, 1) + else + owner.disarm() // some mines can be reused + +/datum/mine_payload/proc/remove_from_mine() + return + +/datum/mine_payload/explosive/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + owner.visible_message("\The [owner] detonates!") + explosion(owner.loc, 0, 2, 3, 4) //land mines are dangerous, folks. diff --git a/code/game/objects/effects/mines/mine_assembly.dm b/code/game/objects/effects/mines/mine_assembly.dm new file mode 100644 index 000000000000..6a40fa0ae30d --- /dev/null +++ b/code/game/objects/effects/mines/mine_assembly.dm @@ -0,0 +1,67 @@ +/obj/item/mine/assembly + name = "mine assembly" + desc = "A small pressure-triggered device. Accepts grenades and tank transfer valves." + payload = null + + var/static/list/accepts_items = list( + /obj/item/transfer_valve = /datum/mine_payload/assembly/tank_transfer_valve, + /obj/item/grenade = /datum/mine_payload/assembly/grenade + ) + +/obj/item/mine/assembly/mapped + armed = TRUE + +/obj/item/mine/assembly/attackby(obj/item/W, mob/living/user) + if(!armed && !triggering) + var/datum/mine_payload/assembly/attached_payload = payload + if(attached_payload?.attached) + if(IS_SCREWDRIVER(W)) + to_chat(user, "You disconnect \the [src]'s [attached_payload.attached.name] and remove it.") + attached_payload.attached.forceMove(get_turf(user)) + payload.remove_from_mine() + QDEL_NULL(payload) + else + for(var/loadtype in accepts_items) + if(istype(W, loadtype)) + user.drop_from_inventory(W) + W.forceMove(src) + var/payload_type = accepts_items[loadtype] + attached_payload = new payload_type + attached_payload.attached = W + payload = attached_payload + return TRUE + return ..() + +/datum/mine_payload/assembly + var/obj/item/attached + +/datum/mine_payload/assembly/New(var/obj/item/_attaching) + ..() + attached = _attaching + +/datum/mine_payload/assembly/Destroy() + QDEL_NULL(attached) + . = ..() + +/datum/mine_payload/assembly/remove_from_mine() + attached = null + +/datum/mine_payload/assembly/tank_transfer_valve/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + if(istype(attached, /obj/item/transfer_valve)) + var/obj/item/transfer_valve/ttv = attached + ttv.forceMove(get_turf(owner)) + ttv.toggle_valve() + remove_from_mine() + +/datum/mine_payload/assembly/grenade/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + if(istype(attached, /obj/item/grenade)) + var/obj/item/grenade/grenade = attached + grenade.forceMove(get_turf(owner)) + if(ismob(trigger)) + var/mob/victim = trigger + if(victim.ckey) + msg_admin_attack("[key_name_admin(victim)] stepped on \a [owner], triggering [grenade]") + grenade.activate() + remove_from_mine() diff --git a/code/game/objects/effects/mines/mine_emp.dm b/code/game/objects/effects/mines/mine_emp.dm new file mode 100644 index 000000000000..5f8a54ad12f8 --- /dev/null +++ b/code/game/objects/effects/mines/mine_emp.dm @@ -0,0 +1,12 @@ +/obj/item/mine/emp + name = "\improper EMP mine" + desc = "A small explosive mine with a lightning bolt symbol on the side." + payload = /datum/mine_payload/emp + +/obj/item/mine/emp/mapped + armed = TRUE + +/datum/mine_payload/emp/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + owner.visible_message("\The [owner] flashes violently before disintegrating!") + empulse(owner.loc, 2, 4, 7, 10, 1) // As strong as an EMP grenade diff --git a/code/game/objects/effects/mines/mine_frag.dm b/code/game/objects/effects/mines/mine_frag.dm new file mode 100644 index 000000000000..de11402ca5a2 --- /dev/null +++ b/code/game/objects/effects/mines/mine_frag.dm @@ -0,0 +1,23 @@ +/obj/item/mine/frag + name = "fragmentation mine" + desc = "A small explosive mine with 'FRAG' and a grenade symbol on the side." + payload = /datum/mine_payload/frag + +/obj/item/mine/frag/mapped + armed = TRUE + +/datum/mine_payload/frag + var/fragment_types = list(/obj/item/projectile/bullet/pellet/fragment) + var/num_fragments = 20 //total number of fragments produced by the grenade + //The radius of the circle used to launch projectiles. Lower values mean less projectiles are used but if set too low gaps may appear in the spread pattern + var/spread_range = 7 + var/explosion_size = 3 + +/datum/mine_payload/frag/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + owner.visible_message("\The [owner] detonates!") + var/turf/O = get_turf(owner) + if(O) + owner.fragmentate(O, num_fragments, spread_range, fragment_types) + if(explosion_size) + explosion(O, -1, -1, round(explosion_size/2), explosion_size, FALSE) diff --git a/code/game/objects/effects/mines/mine_incendiary.dm b/code/game/objects/effects/mines/mine_incendiary.dm new file mode 100644 index 000000000000..f8b8a49ab2d6 --- /dev/null +++ b/code/game/objects/effects/mines/mine_incendiary.dm @@ -0,0 +1,16 @@ +/obj/item/mine/incendiary + name = "incendiary mine" + desc = "A small explosive mine with a fire symbol on the side." + payload = /datum/mine_payload/incendiary + +/obj/item/mine/incendiary/mapped + armed = TRUE + +/datum/mine_payload/incendiary/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + for(var/turf/floor/target in range(1, owner)) + if(!target.blocks_air) + target.assume_gas(/decl/material/gas/hydrogen, 10) + target.assume_gas(/decl/material/gas/oxygen, 5) + target.hotspot_expose(1000, CELL_VOLUME) + owner.visible_message("\The [owner] spews a cloud of flaming gas!") diff --git a/code/game/objects/effects/mines/mine_kick.dm b/code/game/objects/effects/mines/mine_kick.dm new file mode 100644 index 000000000000..ab38a2a2fb31 --- /dev/null +++ b/code/game/objects/effects/mines/mine_kick.dm @@ -0,0 +1,17 @@ +/obj/item/mine/kick + name = "kick mine" + desc = "Concentrated war crimes. Handle with care." + payload = /datum/mine_payload/kick + +/obj/item/mine/kick/mapped + armed = TRUE + +/datum/mine_payload/kick/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + if(isexosuit(trigger)) + var/mob/living/exosuit/mech = trigger + for(var/mob/pilot in mech.pilots) + qdel(pilot.client) + if(ismob(trigger)) + var/mob/M = trigger + qdel(M.client) diff --git a/code/game/objects/effects/mines/mine_napalm.dm b/code/game/objects/effects/mines/mine_napalm.dm new file mode 100644 index 000000000000..6bceace3f0e6 --- /dev/null +++ b/code/game/objects/effects/mines/mine_napalm.dm @@ -0,0 +1,15 @@ +/obj/item/mine/napalm + name = "napalm mine" + desc = "A small explosive mine with a fire symbol on the side." + payload = /datum/mine_payload/napalm + +/obj/item/mine/napalm/mapped + armed = TRUE + +/datum/mine_payload/napalm/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + if(isliving(trigger)) + var/mob/living/M = trigger + M.adjust_fire_intensity(5) + M.fire_act() + owner.visible_message(SPAN_DANGER("\The [owner] bursts into flames!")) diff --git a/code/game/objects/effects/mines/mine_radiation.dm b/code/game/objects/effects/mines/mine_radiation.dm new file mode 100644 index 000000000000..08b00d2a6594 --- /dev/null +++ b/code/game/objects/effects/mines/mine_radiation.dm @@ -0,0 +1,14 @@ +/obj/item/mine/radiation + name = "radiation mine" + desc = "A small explosive mine with a radiation symbol on the side." + payload = /datum/mine_payload/radiation + +/obj/item/mine/radiation/mapped + armed = TRUE + +/datum/mine_payload/radiation/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + if(isliving(trigger)) + var/mob/living/victim = trigger + victim.apply_random_mutation(50) + owner.visible_message(SPAN_DANGER("\The [owner] flashes violently before disintegrating!")) diff --git a/code/game/objects/effects/mines/mine_sleeping.dm b/code/game/objects/effects/mines/mine_sleeping.dm new file mode 100644 index 000000000000..b6d5ad9a0dee --- /dev/null +++ b/code/game/objects/effects/mines/mine_sleeping.dm @@ -0,0 +1,14 @@ +/obj/item/mine/sleeping + name = "nitrous oxide mine" + desc = "A small explosive mine with three Z's on the side." + payload = /datum/mine_payload/sleeping + +/obj/item/mine/sleeping/mapped + armed = TRUE + +/datum/mine_payload/sleeping/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + for (var/turf/floor/target in range(1, owner)) + if(!target.blocks_air) + target.assume_gas(/decl/material/gas/nitrous_oxide, 30) + owner.visible_message("\The [owner] sprays a cloud of gas!") diff --git a/code/game/objects/effects/mines/mine_stun.dm b/code/game/objects/effects/mines/mine_stun.dm new file mode 100644 index 000000000000..26b5704b304b --- /dev/null +++ b/code/game/objects/effects/mines/mine_stun.dm @@ -0,0 +1,14 @@ +/obj/item/mine/stun + name = "stun mine" + desc = "A small explosive mine with a lightning bolt symbol on the side." + payload = /datum/mine_payload/stun + +/obj/item/mine/stun/mapped + armed = TRUE + +/datum/mine_payload/stun/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + if(ismob(trigger)) + var/mob/M = trigger + SET_STATUS_MAX(M, STAT_STUN, 30) + owner.visible_message("\The [owner] flashes violently before disintegrating!") diff --git a/code/game/objects/effects/mines/mine_training.dm b/code/game/objects/effects/mines/mine_training.dm new file mode 100644 index 000000000000..13b23f31945c --- /dev/null +++ b/code/game/objects/effects/mines/mine_training.dm @@ -0,0 +1,15 @@ +/obj/item/mine/training + name = "training mine" + desc = "A mine with its payload removed, for EOD training and demonstrations." + payload = /datum/mine_payload/training + +/obj/item/mine/training/mapped + armed = TRUE + +/datum/mine_payload/training + do_sparks = FALSE + destroy_self_on_trigger = FALSE + +/datum/mine_payload/training/trigger_payload(var/obj/item/mine/owner, var/atom/trigger) + ..() + owner.visible_message("\The [owner]'s light flashes rapidly as it 'explodes'.") diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 29484574edaa..805288d6b365 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -4,8 +4,8 @@ desc = "It's a ... present?" icon = 'icons/obj/items/gift_wrapped.dmi' icon_state = "strangepresent" - density = 1 - anchored = 0 + density = TRUE + anchored = FALSE /obj/effect/stop var/victim = null @@ -26,14 +26,16 @@ return INITIALIZE_HINT_LATELOAD /obj/effect/paint/LateInitialize() - var/turf/simulated/wall/W = get_turf(src) - if(istype(W)) - W.paint_color = color - W.update_icon() + var/turf/wall/wall = get_turf(src) + if(istype(wall)) + wall.paint_color = color + wall.stripe_color = color + wall.lazy_update_icon() var/obj/structure/wall_frame/WF = locate() in loc if(WF) WF.paint_color = color - WF.update_icon() + WF.stripe_color = color + WF.lazy_update_icon() qdel(src) /obj/effect/paint/pink @@ -61,7 +63,7 @@ /obj/effect/paint_stripe name = "stripe of paint" icon = 'icons/effects/effects.dmi' - icon_state = "white" + icon_state = "paintdot" layer = TURF_DETAIL_LAYER blend_mode = BLEND_MULTIPLY @@ -70,10 +72,10 @@ return INITIALIZE_HINT_LATELOAD /obj/effect/paint_stripe/LateInitialize() - var/turf/simulated/wall/W = get_turf(src) - if(istype(W)) - W.stripe_color = color - W.update_icon() + var/turf/wall/wall = get_turf(src) + if(istype(wall)) + wall.stripe_color = color + wall.update_icon() var/obj/structure/wall_frame/WF = locate() in loc if(WF) WF.stripe_color = color diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 5b7458a291e0..38cd105e6d01 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -1,7 +1,8 @@ /obj/effect/overlay name = "overlay" - unacidable = 1 - var/i_attached//Added for possible image attachments to objects. For hallucinations and the like. + +/obj/effect/overlay/singularity_pull() + return /obj/effect/overlay/beam//Not actually a projectile, just an effect. name="beam" @@ -17,39 +18,50 @@ name = "Palm tree" icon = 'icons/misc/beach2.dmi' icon_state = "palm1" - density = 1 + density = TRUE layer = ABOVE_HUMAN_LAYER - anchored = 1 + anchored = TRUE /obj/effect/overlay/palmtree_l name = "Palm tree" icon = 'icons/misc/beach2.dmi' icon_state = "palm2" - density = 1 + density = TRUE layer = ABOVE_HUMAN_LAYER - anchored = 1 + anchored = TRUE /obj/effect/overlay/coconut name = "Coconuts" icon = 'icons/misc/beach.dmi' icon_state = "coconuts" +// This isn't modularized because I hate modularizing layer defines. Bite me. /obj/effect/overlay/bluespacify name = "subspace" icon = 'icons/turf/space.dmi' icon_state = "bluespacify" - layer = SUPERMATTER_WALL_LAYER + layer = SUBSPACE_WALL_LAYER /obj/effect/overlay/wallrot name = "wallrot" desc = "Ick..." icon = 'icons/effects/wallrot.dmi' - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE layer = ABOVE_TILE_LAYER - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE /obj/effect/overlay/wallrot/Initialize() . = ..() pixel_x += rand(-10, 10) pixel_y += rand(-10, 10) + +/// Set and cleaned up by moving projectiles for the most part. +/obj/effect/overlay/projectile_trail + var/obj/item/projectile/master + +/obj/effect/overlay/projectile_trail/Destroy() + if(master) + LAZYREMOVE(master.proj_trails, src) + master = null + return ..() diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index c1dedb5d24b4..de6f34d85bb2 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -3,29 +3,28 @@ desc = "Looks unstable. Best to test it with the clown." icon = 'icons/effects/portal.dmi' icon_state = "portal" - density = 1 - unacidable = 1//Can't destroy energy portals. - var/obj/item/target = null - var/creator = null + density = TRUE anchored = TRUE - var/dangerous = 0 + var/atom/target = null + var/dangerous = FALSE var/failchance = 0 -// Spawns hack around call ordering; don't replace with waitfor without testing. -/obj/effect/portal/Bumped(mob/M) - spawn(0) - teleport(M) +/obj/effect/portal/Bumped(atom/movable/AM) + teleport(AM) /obj/effect/portal/Crossed(atom/movable/AM) - spawn(0) - teleport(AM) + teleport(AM) /obj/effect/portal/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) teleport(user) return TRUE -/obj/effect/portal/Initialize(mapload, var/end, var/delete_after = 300, var/failure_rate) +/obj/effect/portal/Initialize(mapload, end, delete_after = 300, failure_rate) . = ..() + setup_portal(end, delete_after, failure_rate) + +/obj/effect/portal/proc/setup_portal(end, delete_after, failure_rate) if(failure_rate) failchance = failure_rate if(prob(failchance)) @@ -33,27 +32,32 @@ dangerous = 1 playsound(src, 'sound/effects/phasein.ogg', 25, 1) target = end - GLOB.moved_event.register(src, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/datum, qdel_self)) if(delete_after) QDEL_IN(src, delete_after) /obj/effect/portal/Destroy() target = null - GLOB.moved_event.unregister(src, src) + events_repository.unregister(/decl/observ/moved, src, src) . = ..() /obj/effect/portal/proc/teleport(atom/movable/M) - if(istype(M, /obj/effect)) //sparks don't teleport + if(iseffect(M)) + return + + if(!ismovable(M)) return - if (icon_state == "portal1") + + if(icon_state == "portal1") return - if (!( target )) + + if(!target) qdel(src) return - if (istype(M, /atom/movable)) - if(dangerous && prob(failchance)) //oh dear a problem, put em in deep space - var/destination_z = GLOB.using_map.get_transit_zlevel(z) - do_teleport(M, locate(rand(TRANSITIONEDGE, world.maxx - TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy -TRANSITIONEDGE), destination_z), 0) - else - do_teleport(M, target, 1) ///You will appear adjacent to the beacon + + if(dangerous && prob(failchance)) + var/destination_z = global.using_map.get_transit_zlevel(z) + do_teleport(M, locate(rand(TRANSITIONEDGE, world.maxx - TRANSITIONEDGE), rand(TRANSITIONEDGE, world.maxy -TRANSITIONEDGE), destination_z), 0) + else + do_teleport(M, target, 1) diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index 015205228430..9528d9d7b556 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -20,7 +20,7 @@ /obj/effect/spawner/newbomb name = "TTV bomb" - icon = 'icons/mob/screen1.dmi' + icon = 'icons/effects/markers.dmi' icon_state = "x" var/filler_type = /decl/material/gas/carbon_dioxide @@ -102,15 +102,9 @@ /obj/effect/spawner/onetankbomb name = "Single-tank bomb" - icon = 'icons/mob/screen1.dmi' + icon = 'icons/effects/markers.dmi' icon_state = "x" -// var/assembly_type = /obj/item/assembly/signaler - - //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. - var/accelerant_amount = 0 - var/oxidizer_amount = 0 - /obj/effect/spawner/onetankbomb/Initialize() ..() new /obj/item/tank/onetankbomb(get_turf(loc)) diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index 478d0bacbdef..4da5fd6c2352 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -11,7 +11,7 @@ gibamounts = list(1,1,1,1,1,1,1) /obj/effect/gibspawner/human/Initialize() - gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list()) + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), global.alldirs, global.alldirs, list()) gibamounts[6] = pick(0,1,2) . = ..() @@ -21,6 +21,6 @@ gibamounts = list(1,1,1,1,1,1) /obj/effect/gibspawner/robot/Initialize() - gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs) + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), global.alldirs, global.alldirs) gibamounts[6] = pick(0,1,2) . = ..() \ No newline at end of file diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index a9b29e4708b1..5e5f6d7cf2c8 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -3,9 +3,9 @@ name = "web" desc = "It's stringy and sticky." icon = 'icons/effects/effects.dmi' - anchored = 1 - density = 0 - var/health = 15 + anchored = TRUE + density = FALSE + max_health = 15 //similar to weeds, but only barfed out by nurses manually /obj/effect/spider/explosion_act(severity) @@ -13,63 +13,62 @@ if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50) || (severity == 3 && prob(5))))) qdel(src) -/obj/effect/spider/attack_hand(mob/living/user) - +/obj/effect/spider/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(src) if(prob(50)) visible_message(SPAN_WARNING("\The [user] tries to squash \the [src], but misses!")) disturbed() - return - + return TRUE var/showed_msg = FALSE if(ishuman(user)) - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user var/decl/natural_attack/attack = H.get_unarmed_attack(src) if(istype(attack)) - attack.show_attack(H, src, H.zone_sel.selecting, 1) + attack.show_attack(H, src, H.get_target_zone(), 1) showed_msg = TRUE if(!showed_msg) visible_message(SPAN_DANGER("\The [user] squashes \the [src] flat!")) - die() + return TRUE -/obj/effect/spider/attackby(var/obj/item/W, var/mob/user) +/obj/effect/spider/attackby(var/obj/item/used_item, var/mob/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(W.attack_verb.len) - visible_message("\The [src] has been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") - else - visible_message("\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]") + visible_message("\The [src] has been [used_item.pick_attack_verb()] with \the [used_item][(user ? " by [user]." : ".")]") - var/damage = W.force / 4.0 + var/damage = used_item.expend_attack_force(user) / 4 - if(W.edge) + if(used_item.has_edge()) damage += 5 - if(isWelder(W)) - var/obj/item/weldingtool/WT = W + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item - if(WT.remove_fuel(0, user)) + if(welder.weld(0, user)) damage = 15 playsound(loc, 'sound/items/Welder.ogg', 100, 1) - health -= damage + current_health -= damage healthcheck() + return TRUE /obj/effect/spider/bullet_act(var/obj/item/projectile/Proj) ..() - health -= Proj.get_structure_damage() + current_health -= Proj.get_structure_damage() healthcheck() /obj/effect/spider/proc/healthcheck() - if(health <= 0) + if(current_health <= 0) qdel(src) /obj/effect/spider/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature > 300 + T0C) - health -= 5 + current_health -= 5 healthcheck() + if(!QDELETED(src)) + return ..() /obj/effect/spider/stickyweb icon_state = "stickyweb1" @@ -83,7 +82,7 @@ if(air_group || (height==0)) return 1 if(istype(mover, /mob/living/simple_animal/hostile/giant_spider)) return 1 - else if(istype(mover, /mob/living)) + else if(isliving(mover)) if(prob(50)) to_chat(mover, "You get stuck in \the [src] for a moment.") return 0 @@ -108,22 +107,26 @@ STOP_PROCESSING(SSobj, src) if(istype(loc, /obj/item/organ/external)) var/obj/item/organ/external/O = loc - O.implants -= src + LAZYREMOVE(O.implants, src) . = ..() /obj/effect/spider/eggcluster/Process() + + if(!loc) + qdel(src) + return + if(prob(80)) amount_grown += rand(0,2) + if(amount_grown >= 100) var/num = rand(3,9) - var/obj/item/organ/external/O = null if(istype(loc, /obj/item/organ/external)) - O = loc - - for(var/i=0, i 0) +/obj/effect/spider/spiderling/attackby(var/obj/item/used_item, var/mob/user) + . = ..() + if(current_health > 0) disturbed() -/obj/effect/spider/spiderling/Crossed(var/mob/living/L) - if(dormant && istype(L) && L.mob_size > MOB_SIZE_TINY) +/obj/effect/spider/spiderling/Crossed(atom/movable/AM) + if(!dormant || !isliving(AM)) + return + var/mob/living/M = AM + if(M.mob_size > MOB_SIZE_TINY) disturbed() /obj/effect/spider/spiderling/disturbed() if(!dormant) return dormant = FALSE - GLOB.moved_event.unregister(src, src, /obj/effect/spider/proc/disturbed) + events_repository.unregister(/decl/observ/moved, src, src, TYPE_PROC_REF(/obj/effect/spider, disturbed)) START_PROCESSING(SSobj, src) /obj/effect/spider/spiderling/Bump(atom/user) @@ -210,7 +217,7 @@ ..() /obj/effect/spider/spiderling/healthcheck() - if(health <= 0) + if(current_health <= 0) die() /obj/effect/spider/spiderling/proc/check_vent(obj/machinery/atmospherics/unary/vent_pump/exit_vent) @@ -225,7 +232,7 @@ if(prob(50)) src.visible_message("You hear something squeezing through the ventilation ducts.",2) forceMove(exit_vent) - addtimer(CALLBACK(src, .proc/end_vent_moving, exit_vent), travel_time) + addtimer(CALLBACK(src, PROC_REF(end_vent_moving), exit_vent), travel_time) /obj/effect/spider/spiderling/proc/end_vent_moving(obj/machinery/atmospherics/unary/vent_pump/exit_vent) if(check_vent(exit_vent)) @@ -243,14 +250,15 @@ return if(travelling_in_vent) - if(istype(src.loc, /turf)) + if(isturf(src.loc)) travelling_in_vent = 0 entry_vent = null else if(entry_vent) if(get_dist(src, entry_vent) <= 1) - if(entry_vent.network && entry_vent.network.normal_members.len) + var/datum/pipe_network/network = entry_vent.network_in_dir(entry_vent.dir) + if(network && network.normal_members.len) var/list/vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.network.normal_members) + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in network.normal_members) vents.Add(temp_vent) if(!vents.len) entry_vent = null @@ -259,7 +267,7 @@ forceMove(entry_vent) var/travel_time = round(get_dist(loc, exit_vent.loc) / 2) - addtimer(CALLBACK(src, .proc/start_vent_moving, exit_vent, travel_time), travel_time + rand(20,60)) + addtimer(CALLBACK(src, PROC_REF(start_vent_moving), exit_vent, travel_time), travel_time + rand(20,60)) travelling_in_vent = TRUE return else @@ -280,8 +288,8 @@ var/min_y = pixel_y <= -shift_range ? 0 : -2 var/max_y = pixel_y >= shift_range ? 0 : 2 - pixel_x = Clamp(pixel_x + rand(min_x, max_x), -shift_range, shift_range) - pixel_y = Clamp(pixel_y + rand(min_y, max_y), -shift_range, shift_range) + pixel_x = clamp(pixel_x + rand(min_x, max_x), -shift_range, shift_range) + pixel_y = clamp(pixel_y + rand(min_y, max_y), -shift_range, shift_range) else if(prob(5)) //vent crawl! for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src)) @@ -320,14 +328,14 @@ desc = "Green squishy mess." icon = 'icons/effects/effects.dmi' icon_state = "greenshatter" - anchored = 1 + anchored = TRUE layer = BLOOD_LAYER /obj/effect/spider/cocoon name = "cocoon" desc = "Something wrapped in silky spider web." icon_state = "cocoon1" - health = 60 + max_health = 60 /obj/effect/spider/cocoon/Initialize() . = ..() diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index 3cf316fec579..a1b4002d04ab 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -3,21 +3,19 @@ /obj/effect/step_trigger var/affect_ghosts = 0 var/stopper = 1 // stops throwers - invisibility = 101 // nope cant see this shit - anchored = 1 + invisibility = INVISIBILITY_ABSTRACT // nope cant see this shit + anchored = TRUE + icon = 'icons/misc/mark.dmi' + icon_state = "X" /obj/effect/step_trigger/proc/Trigger(var/atom/movable/A) return 0 -/obj/effect/step_trigger/Crossed(H) +/obj/effect/step_trigger/Crossed(atom/movable/AM) ..() - if(!H) + if(!AM || (isobserver(AM) && !(isghost(AM) && affect_ghosts))) return - if(isobserver(H) && !(isghost(H) && affect_ghosts)) - return - Trigger(H) - - + Trigger(AM) /* Tosses things in a certain direction */ @@ -94,17 +92,17 @@ var/teleport_y = 0 var/teleport_z = 0 - Trigger(var/atom/movable/A) - if(teleport_x && teleport_y && teleport_z) +/obj/effect/step_trigger/teleporter/Trigger(var/atom/movable/A) + if(teleport_x && teleport_y && teleport_z) - A.x = teleport_x - A.y = teleport_y - A.z = teleport_z + A.x = teleport_x + A.y = teleport_y + A.z = teleport_z /* Random teleporter, teleports atoms to locations ranging from teleport_x - teleport_x_offset, etc */ /obj/effect/step_trigger/teleporter/random - opacity = 1 + opacity = TRUE var/teleport_x_offset = 0 var/teleport_y_offset = 0 var/teleport_z_offset = 0 diff --git a/code/game/objects/effects/temporaray.dm b/code/game/objects/effects/temporaray.dm deleted file mode 100644 index ecb878c88c6e..000000000000 --- a/code/game/objects/effects/temporaray.dm +++ /dev/null @@ -1,46 +0,0 @@ -//temporary visual effects -/obj/effect/temp_visual - icon_state = "nothing" - anchored = TRUE - layer = ABOVE_HUMAN_LAYER - mouse_opacity = 0 - simulated = FALSE - var/duration = 10 //in deciseconds - -/obj/effect/temp_visual/Initialize(mapload, set_dir) - if(set_dir) - set_dir(set_dir) - . = ..() - QDEL_IN(src, duration) - -/obj/effect/temp_visual/emp_burst - icon = 'icons/effects/effects.dmi' - icon_state = "empdisable" - -/obj/effect/temp_visual/bloodsplatter - icon = 'icons/effects/bloodspatter.dmi' - duration = 5 - layer = LYING_HUMAN_LAYER - var/splatter_type = "splatter" - -/obj/effect/temp_visual/bloodsplatter/Initialize(mapload, set_dir, _color) - if(set_dir in GLOB.cornerdirs) - icon_state = "[splatter_type][pick(1, 2, 6)]" - else - icon_state = "[splatter_type][pick(3, 4, 5)]" - . = ..() - if (_color) - color = _color - - var/target_pixel_x = 0 - var/target_pixel_y = 0 - if(set_dir & NORTH) - target_pixel_y = 16 - if(set_dir & SOUTH) - target_pixel_y = -16 - layer = ABOVE_HUMAN_LAYER - if(set_dir & EAST) - target_pixel_x = 16 - if(set_dir & WEST) - target_pixel_x = -16 - animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) \ No newline at end of file diff --git a/code/game/objects/effects/temporary.dm b/code/game/objects/effects/temporary.dm new file mode 100644 index 000000000000..c5efa1c7e916 --- /dev/null +++ b/code/game/objects/effects/temporary.dm @@ -0,0 +1,99 @@ +//temporary visual effects +/obj/effect/temp_visual + icon_state = "nothing" + icon = 'icons/effects/effects.dmi' + anchored = TRUE + layer = ABOVE_HUMAN_LAYER + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + simulated = FALSE + var/duration = 1 SECOND //in deciseconds + +/obj/effect/temp_visual/Initialize(mapload, set_dir) + if(set_dir) + set_dir(set_dir) + . = ..() + QDEL_IN(src, duration) + +/obj/effect/temp_visual/emp_burst + icon_state = "empdisable" + +/obj/effect/temp_visual/emppulse + name = "electromagnetic pulse" + icon_state = "emppulse" + duration = 2 SECONDS + +/obj/effect/temp_visual/bloodsplatter + icon = 'icons/effects/bloodspatter.dmi' + duration = 0.5 SECONDS + layer = LYING_HUMAN_LAYER + var/splatter_type = "splatter" + +/obj/effect/temp_visual/bloodsplatter/Initialize(mapload, set_dir, _color) + if(set_dir in global.cornerdirs) + icon_state = "[splatter_type][pick(1, 2, 6)]" + else + icon_state = "[splatter_type][pick(3, 4, 5)]" + . = ..() + if (_color) + color = _color + + var/target_pixel_x = 0 + var/target_pixel_y = 0 + if(set_dir & NORTH) + target_pixel_y = 16 + if(set_dir & SOUTH) + target_pixel_y = -16 + layer = ABOVE_HUMAN_LAYER + if(set_dir & EAST) + target_pixel_x = 16 + if(set_dir & WEST) + target_pixel_x = -16 + animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) + +/obj/effect/temp_visual/impact_effect + plane = ABOVE_LIGHTING_PLANE + layer = ABOVE_LIGHTING_LAYER // So they're visible even in a shootout in maint. + duration = 5 + icon_state = "impact_bullet" + icon = 'icons/effects/impact_effects.dmi' + +/obj/effect/temp_visual/impact_effect/Initialize(mapload, obj/item/projectile/P, _x, _y) + default_pixel_x = _x + default_pixel_y = _y + pixel_x = default_pixel_x + pixel_y = default_pixel_y + . = ..() + +/obj/effect/temp_visual/impact_effect/red_laser + icon_state = "impact_laser" + duration = 4 + +/obj/effect/temp_visual/impact_effect/blue_laser + icon_state = "impact_laser_blue" + duration = 4 + +/obj/effect/temp_visual/impact_effect/green_laser + icon_state = "impact_laser_green" + duration = 4 + +/obj/effect/temp_visual/impact_effect/purple_laser + icon_state = "impact_laser_purple" + duration = 4 + +// Colors itself based on the projectile. +// Checks light_color and color. +/obj/effect/temp_visual/impact_effect/monochrome_laser + icon_state = "impact_laser_monochrome" + duration = 4 + +/obj/effect/temp_visual/impact_effect/monochrome_laser/Initialize(mapload, obj/item/projectile/P, x, y) + if(istype(P)) + if(P.light_color) + color = P.light_color + else if(P.color) + color = P.color + return ..() + +/obj/effect/temp_visual/impact_effect/ion + icon_state = "shieldsparkles" + duration = 6 diff --git a/code/game/objects/effects/temporary_effect.dm b/code/game/objects/effects/temporary_effect.dm index 9d445ee4daa1..1e950217a2f6 100644 --- a/code/game/objects/effects/temporary_effect.dm +++ b/code/game/objects/effects/temporary_effect.dm @@ -1,9 +1,8 @@ //A temporary effect that does not DO anything except look pretty. /obj/effect/temporary - anchored = 1 - unacidable = 1 - mouse_opacity = 0 - density = 0 + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + density = FALSE layer = ABOVE_HUMAN_LAYER /obj/effect/temporary/Initialize(var/mapload, var/duration = 30, var/_icon = 'icons/effects/effects.dmi', var/_state) diff --git a/code/game/objects/effects/wet_floor.dm b/code/game/objects/effects/wet_floor.dm new file mode 100644 index 000000000000..cef4e3b2c8f9 --- /dev/null +++ b/code/game/objects/effects/wet_floor.dm @@ -0,0 +1,18 @@ +// Visual marker and data holder for slippery floors. +/atom/movable/wet_floor + icon = 'icons/effects/water.dmi' + icon_state = "wet_floor" + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + simulated = FALSE + var/wetness = 0 + var/wet_timer_id + +/atom/movable/wet_floor/Initialize() + . = ..() + name = "" + verbs.Cut() + +/atom/movable/wet_floor/proc/unwet_floor() + var/turf/myturf = loc + if(istype(myturf)) + myturf.unwet_floor() diff --git a/code/game/objects/effects/wormhole.dm b/code/game/objects/effects/wormhole.dm new file mode 100644 index 000000000000..c932e8d9915d --- /dev/null +++ b/code/game/objects/effects/wormhole.dm @@ -0,0 +1,18 @@ +var/global/list/all_wormholes = list() + +/obj/effect/portal/wormhole + name = "wormhole" + desc = "It looks highly unstable; It could close at any moment." + icon = 'icons/obj/objects.dmi' + icon_state = "anom" + +/obj/effect/portal/wormhole/Initialize() + . = ..() + global.all_wormholes += src + +/obj/effect/portal/wormhole/Destroy() + global.all_wormholes -= src + return ..() + +/obj/effect/portal/wormhole/setup_portal() + return diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm index d5888b633e0c..24dad4dfb5d0 100644 --- a/code/game/objects/empulse.dm +++ b/code/game/objects/empulse.dm @@ -4,23 +4,17 @@ // #define EMPDEBUG 10 -proc/empulse(turf/epicenter, heavy_range, light_range, log=0) +/proc/empulse(turf/epicenter, heavy_range, light_range, log=0) if(!epicenter) return - if(!istype(epicenter, /turf)) + if(!isturf(epicenter)) epicenter = get_turf(epicenter.loc) if(log) log_and_message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ") if(heavy_range > 1) - var/obj/effect/overlay/pulse = new/obj/effect/overlay(epicenter) - pulse.icon = 'icons/effects/effects.dmi' - pulse.icon_state = "emppulse" - pulse.SetName("emp pulse") - pulse.anchored = 1 - spawn(20) - qdel(pulse) + new /obj/effect/temp_visual/emppulse(epicenter) if(heavy_range > light_range) light_range = heavy_range diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index 9ab95c50c33d..51ac6d43b52c 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -1,7 +1,7 @@ //TODO: Flash range does nothing currently /proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1, z_transfer = UP|DOWN) - if(config.use_iterative_explosions) - . = explosion_iter(epicenter, (devastation_range * 2 + heavy_impact_range + light_impact_range)) + if(get_config_value(/decl/config/toggle/use_iterative_explosions)) + . = explosion_iter(epicenter, (devastation_range * 2 + heavy_impact_range + light_impact_range), z_transfer) else . = explosion_basic(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, z_transfer) @@ -9,7 +9,7 @@ set waitfor = FALSE epicenter = get_turf(epicenter) - if(!epicenter) + if(!epicenter) return var/start_time = REALTIMEOFDAY @@ -36,7 +36,7 @@ far_dist += heavy_impact_range * 5 far_dist += devastation_range * 20 var/frequency = get_rand_frequency() - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(M.z == epicenter.z) var/turf/M_turf = get_turf(M) var/dist = get_dist(M_turf, epicenter) @@ -44,12 +44,12 @@ if(dist <= round(max_range + world.view - 2, 1)) M.playsound_local(epicenter, get_sfx("explosion"), 100, 1, frequency, falloff = 5) // get_sfx() is so that everyone gets the same sound else if(dist <= far_dist) - var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist + var/far_volume = clamp(far_dist, 30, 50) // Volume is based on explosion size and dist far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5) if(adminlog) - log_and_message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z]) (JMP)") + log_and_message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z]) (JMP)") var/approximate_intensity = (devastation_range * 3) + (heavy_impact_range * 2) + light_impact_range // Large enough explosion. For performance reasons, powernets will be rebuilt manually @@ -64,7 +64,7 @@ var/x0 = epicenter.x var/y0 = epicenter.y var/z0 = epicenter.z - for(var/turf/T in RANGE_TURFS(epicenter, max_range)) + for(var/turf/T as anything in RANGE_TURFS(epicenter, max_range)) var/dist = sqrt((T.x - x0)**2 + (T.y - y0)**2) if(dist < devastation_range) dist = 1 @@ -85,24 +85,23 @@ var/atom/movable/AM = atom_movable if(AM && AM.simulated && !T.protects_atom(AM)) AM.explosion_act(dist) - if(!QDELETED(AM) && !AM.anchored) - addtimer(CALLBACK(AM, /atom/movable/.proc/throw_at, throw_target, throw_dist, throw_dist), 0) + if(!QDELETED(AM) && !AM.anchored && isturf(AM.loc)) + addtimer(CALLBACK(AM, TYPE_PROC_REF(/atom/movable, throw_at), throw_target, throw_dist, throw_dist), 0) var/took = (REALTIMEOFDAY-start_time)/10 - if(Debug2) - to_world_log("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.") + testing("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.") return 1 -#define EXPLFX_BOTH 3 -#define EXPLFX_SOUND 2 -#define EXPLFX_SHAKE 1 -#define EXPLFX_NONE 0 +#define EXPLFX_NONE 0 +#define EXPLFX_SOUND BITFLAG(0) +#define EXPLFX_SHAKE BITFLAG(1) +#define EXPLFX_BOTH (EXPLFX_SOUND|EXPLFX_SHAKE) // All the vars used on the turf should be on unsimulated turfs too, we just don't care about those generally. #define SEARCH_DIR(dir) \ search_direction = dir;\ search_turf = get_step(current_turf, search_direction);\ - if (istype(search_turf, /turf/simulated)) {\ + if (isturf(search_turf)) {\ turf_queue += search_turf;\ dir_queue += search_direction;\ power_queue += current_power;\ @@ -127,18 +126,19 @@ if (O.explosion_resistance) power -= O.explosion_resistance - if (power >= config.iterative_explosives_z_threshold) + if (power >= get_config_value(/decl/config/num/iterative_explosives_z_threshold)) + var/explo_mult = get_config_value(/decl/config/num/iterative_explosives_z_multiplier) if ((z_transfer & UP) && HasAbove(epicenter.z)) - explosion_iter(GetAbove(epicenter), power * config.iterative_explosives_z_multiplier, UP) + explosion_iter(GetAbove(epicenter), power * explo_mult, UP) if ((z_transfer & DOWN) && HasBelow(epicenter.z)) - explosion_iter(GetBelow(epicenter), power * config.iterative_explosives_z_multiplier, DOWN) + explosion_iter(GetBelow(epicenter), power * explo_mult, DOWN) // These three lists must always be the same length. var/list/turf_queue = list(epicenter, epicenter, epicenter, epicenter) var/list/dir_queue = list(NORTH, SOUTH, EAST, WEST) var/list/power_queue = list(power, power, power, power) - var/turf/simulated/current_turf + var/turf/current_turf var/turf/search_turf var/origin_direction var/search_direction @@ -182,14 +182,14 @@ log_debug("iexpl: Beginning SFX phase.") time = REALTIMEOFDAY - var/volume = 10 + (power * 20) + var/explosion_volume = 10 + (power * 20) var/frequency = get_rand_frequency() var/close_dist = round(power + world.view - 2, 1) var/sound/explosion_sound = sound(get_sfx("explosion")) - for (var/thing in GLOB.player_list) + for (var/thing in global.player_list) var/mob/M = thing var/reception = EXPLFX_BOTH var/turf/T = isturf(M.loc) ? M.loc : get_turf(M) @@ -198,30 +198,31 @@ CHECK_TICK continue - if (!ARE_Z_CONNECTED(T.z, epicenter.z)) + if (!LEVELS_ARE_Z_CONNECTED(T.z, epicenter.z)) CHECK_TICK continue if (T.type == /turf/space) // Equality is faster than istype. reception = EXPLFX_NONE - for (var/turf/simulated/THING in RANGE_TURFS(M, 1)) - reception |= EXPLFX_SHAKE - break + for (var/turf/THING as anything in RANGE_TURFS(M, 1)) + if(THING.simulated) + reception |= EXPLFX_SHAKE + break if (!reception) CHECK_TICK continue var/dist = get_dist(M, epicenter) || 1 - if ((reception & EXPLFX_SOUND) && M.ear_deaf <= 0) + if ((reception & EXPLFX_SOUND) && !HAS_STATUS(M, STAT_DEAF)) if (dist <= close_dist) - M.playsound_local(epicenter, explosion_sound, min(100, volume), 1, frequency, falloff = 5) + M.playsound_local(epicenter, explosion_sound, min(100, explosion_volume), 1, frequency, falloff = 5) //You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station. else - volume = M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', volume, 1, frequency, falloff = 1000) + explosion_volume = M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', explosion_volume, 1, frequency, falloff = 1000) - if ((reception & EXPLFX_SHAKE) && volume > 0) + if ((reception & EXPLFX_SHAKE) && explosion_volume > 0) shake_camera(M, min(30, max(2,(power*2) / dist)), min(3.5, ((power/3) / dist)),0.05) //Maximum duration is 3 seconds, and max strength is 3.5 //Becuse values higher than those just get really silly @@ -254,7 +255,7 @@ if (AM.simulated) AM.explosion_act(severity) if(!QDELETED(AM) && !AM.anchored) - addtimer(CALLBACK(AM, /atom/movable/.proc/throw_at, throw_target, throw_dist, throw_dist), 0) + addtimer(CALLBACK(AM, TYPE_PROC_REF(/atom/movable, throw_at), throw_target, throw_dist, throw_dist), 0) movable_tally++ CHECK_TICK else diff --git a/code/game/objects/item.dm b/code/game/objects/item.dm deleted file mode 100644 index beffb79a5864..000000000000 --- a/code/game/objects/item.dm +++ /dev/null @@ -1,976 +0,0 @@ -/obj/item - name = "item" - w_class = ITEM_SIZE_NORMAL - mouse_drag_pointer = MOUSE_ACTIVE_POINTER - pass_flags = PASS_FLAG_TABLE - - var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite - var/randpixel = 6 - var/r_speed = 1.0 - var/health = null - var/max_health - var/material_health_multiplier = 0.2 - var/burn_point = null - var/burning = null - var/hitsound - var/slot_flags = 0 //This is used to determine on which slots an item can fit. - var/no_attack_log = 0 //If it's an item we don't want to log attack_logs with, set this to 1 - var/obj/item/master = null - var/origin_tech //Used by R&D to determine what research bonuses it grants. - var/list/attack_verb = list("hit") //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" - var/lock_picking_level = 0 //used to determine whether something can pick a lock, and how well. - var/force = 0 - var/attack_cooldown = DEFAULT_WEAPON_COOLDOWN - var/melee_accuracy_bonus = 0 - - var/heat_protection = 0 //flags which determine which body parts are protected from heat. Use the HEAD, UPPER_TORSO, LOWER_TORSO, etc. flags. See setup.dm - var/cold_protection = 0 //flags which determine which body parts are protected from cold. Use the HEAD, UPPER_TORSO, LOWER_TORSO, etc. flags. See setup.dm - var/max_heat_protection_temperature //Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection flags - var/min_cold_protection_temperature //Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection flags - var/max_pressure_protection // Set this variable if the item protects its wearer against high pressures below an upper bound. Keep at null to disable protection. - var/min_pressure_protection // Set this variable if the item protects its wearer against low pressures above a lower bound. Keep at null to disable protection. 0 represents protection against hard vacuum. - - var/datum/action/item_action/action = null - var/action_button_name //It is also the text which gets displayed on the action button. If not set it defaults to 'Use [name]'. If it's not set, there'll be no button. - var/default_action_type = /datum/action/item_action // Specify the default type and behavior of the action button for this atom. - - //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc. - //It should be used purely for appearance. For gameplay effects caused by items covering body parts, use body_parts_covered. - var/flags_inv = 0 - var/body_parts_covered = 0 //see setup.dm for appropriate bit flags - - var/item_flags = 0 //Miscellaneous flags pertaining to equippable objects. - - //var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible - var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets) - var/permeability_coefficient = 1 // for chemicals/diseases - var/siemens_coefficient = 1 // for electrical admittance/conductance (electrocution checks and shit) - var/slowdown_general = 0 // How much clothing is slowing you down. Negative values speeds you up. This is a genera##l slowdown, no matter equipment slot. - var/slowdown_per_slot[slot_last] // How much clothing is slowing you down. This is an associative list: item slot - slowdown - var/slowdown_accessory // How much an accessory will slow you down when attached to a worn article of clothing. - var/canremove = 1 //Mostly for Ninja code at this point but basically will not allow the item to be removed if set to 0. /N - var/material_armor_multiplier // if set, item will use material's armor values multiplied by this. - var/armor_type = /datum/extension/armor - var/list/armor - var/armor_degradation_speed //How fast armor will degrade, multiplier to blocked damage to get armor damage value. - var/list/allowed = null //suit storage stuff. - var/obj/item/uplink/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. - var/zoomdevicename = null //name used for message when binoculars/scope is used - var/zoom = 0 //1 if item is actively being used to zoom. For scoped guns and binoculars. - - var/base_parry_chance // Will allow weapon to parry melee attacks if non-zero - var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc. - - var/use_alt_layer = FALSE // Use the slot's alternative layer when rendering on a mob - - //** These specify item/icon overrides for _slots_ - - var/list/item_state_slots //overrides the default item_state for particular slots. - - // Used to specify the icon file to be used when the item is worn. If not set the default icon for that slot will be used. - // If icon_override or sprite_sheets are set they will take precendence over this, assuming they apply to the slot in question. - // Only slot_l_hand/slot_r_hand are implemented at the moment. Others to be implemented as needed. - var/list/item_icons - - //** These specify item/icon overrides for _species_ - - /* Species-specific sprites, concept stolen from Paradise//vg/. - ex: - sprite_sheets = list( - SPECIES_FOO = 'icons/foo/onmob_foo.dmi' - ) - If index term exists and icon_override is not set, this sprite sheet will be used. - */ - var/list/sprite_sheets = list() - - // Species-specific sprite sheets for inventory sprites - // Works similarly to worn sprite_sheets, except the alternate sprites are used when the clothing/refit_for_bodytype() proc is called. - var/list/sprite_sheets_obj = list() - - // Material handling for material weapons (not used by default, unless material is supplied or set) - var/decl/material/material // Reference to material decl. If set to a string corresponding to a material ID, will init the item with that material. - var/applies_material_colour = FALSE // Whether or not the material recolours this icon. - var/applies_material_name = FALSE // If true, item becomes 'material item' ie. 'steel hatchet'. - var/max_force // any damage above this is added to armor penetration value. If unset, autogenerated based on w_class - var/material_force_multiplier = 0.1 // Multiplier to material's generic damage value for this specific type of weapon - var/thrown_material_force_multiplier = 0.1 // As above, but for throwing the weapon. - var/unbreakable = FALSE // Whether or not this weapon degrades. - var/anomaly_shielding // 0..1 value of how well it shields against xenoarch anomalies - -/obj/item/create_matter() - ..() - LAZYINITLIST(matter) - if(istype(material)) - matter[material.type] = max(matter[material.type], round(MATTER_AMOUNT_PRIMARY * get_matter_amount_modifier())) - UNSETEMPTY(matter) - -/obj/item/Initialize(var/ml, var/material_key) - if(!ispath(material_key, /decl/material)) - material_key = material - if(material_key) - set_material(material_key) - . = ..() - if(islist(armor)) - for(var/type in armor) - if(armor[type]) // Don't set it if it gives no armor anyway, which is many items. - set_extension(src, armor_type, armor, armor_degradation_speed) - break - if(randpixel && (!pixel_x && !pixel_y) && isturf(loc)) //hopefully this will prevent us from messing with mapper-set pixel_x/y - pixel_x = rand(-randpixel, randpixel) - pixel_y = rand(-randpixel, randpixel) - -/obj/item/Destroy() - STOP_PROCESSING(SSobj, src) - QDEL_NULL(hidden_uplink) - if(ismob(loc)) - var/mob/m = loc - m.drop_from_inventory(src) - var/obj/item/storage/storage = loc - if(istype(storage)) - // some ui cleanup needs to be done - storage.on_item_pre_deletion(src) // must be done before deletion - . = ..() - storage.on_item_post_deletion(src) // must be done after deletion - else - return ..() - -//Checks if the item is being held by a mob, and if so, updates the held icons -/obj/item/proc/update_twohanding() - update_held_icon() - -/obj/item/proc/update_held_icon() - if(ismob(src.loc)) - var/mob/M = src.loc - if(M.l_hand == src) - M.update_inv_l_hand() - else if(M.r_hand == src) - M.update_inv_r_hand() - -/obj/item/proc/is_held_twohanded(mob/living/M) - if(!M) - M = loc - if(!istype(M)) - return - if(istype(loc, /obj/item/rig_module) || istype(loc, /obj/item/rig)) - return TRUE - - var/check_hand - if(M.l_hand == src && !M.r_hand) - check_hand = BP_R_HAND //item in left hand, check right hand - else if(M.r_hand == src && !M.l_hand) - check_hand = BP_L_HAND //item in right hand, check left hand - else - return FALSE - - //would check is_broken() and is_malfunctioning() here too but is_malfunctioning() - //is probabilistic so we can't do that and it would be unfair to just check one. - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/hand = H.organs_by_name[check_hand] - if(istype(hand) && hand.is_usable()) - return TRUE - return FALSE - -/obj/item/explosion_act(severity) - ..() - if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50) || (severity == 3 && prob(5))))) - qdel(src) - -/obj/item/examine(mob/user, distance) - var/desc_comp = "" //For "description composite" - desc_comp += "It is a [w_class_description()] item." - - var/list/available_recipes = list() - for(var/decl/crafting_stage/initial_stage in SSfabrication.find_crafting_recipes(type)) - if(initial_stage.can_begin_with(src) && ispath(initial_stage.completion_trigger_type)) - var/atom/movable/prop = initial_stage.completion_trigger_type - if(initial_stage.stack_consume_amount > 1) - available_recipes[initial_stage] = "[initial_stage.stack_consume_amount] [initial(prop.name)]\s" - else - available_recipes[initial_stage] = "\a [initial(prop.name)]" - - if(length(available_recipes)) - desc_comp += "
              *--------*
              " - for(var/decl/crafting_stage/initial_stage in available_recipes) - desc_comp += SPAN_NOTICE("With [available_recipes[initial_stage]], you could start making \a [initial_stage.descriptor] out of this.") - desc_comp += "
              " - desc_comp += "*--------*" - - if(hasHUD(user, HUD_SCIENCE)) //Mob has a research scanner active. - desc_comp += "
              *--------*
              " - - if(origin_tech) - desc_comp += "Testing potentials:
              " - var/list/techlvls = cached_json_decode(origin_tech) - for(var/T in techlvls) - var/decl/research_field/field = SSfabrication.get_research_field_by_id(T) - desc_comp += "Tech: Level [techlvls[T]] [field.name]
              " - else - desc_comp += "No tech origins detected.
              " - - if(LAZYLEN(matter)) - desc_comp += "Extractable materials:
              " - for(var/mat in matter) - var/decl/material/M = decls_repository.get_decl(mat) - desc_comp += "[capitalize(M.solid_name)]
              " - else - desc_comp += "No extractable materials detected.
              " - desc_comp += "*--------*" - - return ..(user, distance, "", desc_comp) - -// Partially copied from atom/MouseDrop() -// This is going to need a solid go-over to properly integrate all the movement procs into each -// other and make sure everything is updating nicely. Snowflaking it for now. ~Jan 2020 -/obj/item/MouseDrop(var/atom/over) - if(usr && over && Adjacent(usr)) - if(over == usr) - usr.face_atom(src) - dragged_onto(over) - else if(usr.client && istype(over, /obj/screen/inventory) && (over in usr.client.screen)) - var/obj/screen/inventory/inv = over - if(!inv.slot_id) - return - if(!usr.check_dexterity(DEXTERITY_GRIP, silent = TRUE)) - to_chat(usr, SPAN_NOTICE("You begin putting on \the [src]...")) - if(!do_after(usr, 3 SECONDS, src) || QDELETED(over) || QDELETED(src) || QDELETED(usr)) - return - if(istype(loc, /obj/item/storage)) - var/obj/item/storage/bag = loc - bag.remove_from_storage(src) - dropInto(get_turf(bag)) - else if(istype(loc, /mob)) - var/mob/M = loc - if(!M.unEquip(src, get_turf(src))) - return - usr.equip_to_slot_if_possible(src, inv.slot_id) - return - return ..() - -/obj/item/proc/dragged_onto(var/mob/user) - attack_hand(user) - -/obj/item/attack_hand(mob/user) - - if(!user) - return - - if(anchored) - return ..() - - if(!user.check_dexterity(DEXTERITY_GRIP, silent = TRUE)) - - if(user.check_dexterity(DEXTERITY_KEYBOARDS, silent = TRUE)) - - if(loc == user) - to_chat(user, SPAN_NOTICE("You begin trying to remove \the [src]...")) - if(do_after(user, 3 SECONDS, src) && user.unEquip(src)) - user.drop_from_inventory(src) - else - to_chat(user, SPAN_WARNING("You fail to remove \the [src]!")) - return - - if(isturf(loc)) - if(loc == get_turf(user)) - attack_self(user) - else - dropInto(get_turf(user)) - return - - if(istype(loc, /obj/item/storage)) - visible_message(SPAN_NOTICE("\The [user] fumbles \the [src] out of \the [loc].")) - var/obj/item/storage/bag = loc - bag.remove_from_storage(src) - dropInto(get_turf(bag)) - return - - to_chat(user, SPAN_WARNING("You are not dexterous enough to pick up \the [src].")) - return - - var/old_loc = loc - pickup(user) - if (istype(loc, /obj/item/storage)) - var/obj/item/storage/S = loc - S.remove_from_storage(src) - - if(!QDELETED(throwing)) - throwing.finalize(hit=TRUE) - - if (loc == user) - if(!user.unEquip(src)) - return - else - if(isliving(loc)) - return - - if(QDELETED(src)) - return // Unequipping changes our state, so must check here. - - if(user.put_in_active_hand(src)) - if (isturf(old_loc)) - var/obj/effect/temporary/item_pickup_ghost/ghost = new(old_loc, src) - ghost.animate_towards(user) - if(randpixel) - pixel_x = rand(-randpixel, randpixel) - pixel_y = rand(-randpixel/2, randpixel/2) - pixel_z = 0 - else if(randpixel == 0) - pixel_x = 0 - pixel_y = 0 - -/obj/item/attack_ai(mob/user) - if (istype(src.loc, /obj/item/robot_module)) - //If the item is part of a cyborg module, equip it - if(!isrobot(user)) - return - var/mob/living/silicon/robot/R = user - R.activate_module(src) - R.hud_used.update_robot_modules_display() - -/obj/item/attackby(obj/item/W, mob/user) - - if(SSfabrication.try_craft_with(src, W, user)) - return TRUE - - if(SSfabrication.try_craft_with(W, src, user)) - return TRUE - - if(istype(W, /obj/item/storage)) - var/obj/item/storage/S = W - if(S.use_to_pickup) - if(S.collection_mode) //Mode is set to collect all items - if(isturf(src.loc)) - S.gather_all(src.loc, user) - else if(S.can_be_inserted(src, user)) - S.handle_item_insertion(src) - -/obj/item/proc/talk_into(mob/M, text) - return - -/obj/item/proc/moved(mob/user, old_loc) - return - -// apparently called whenever an item is removed from a slot, container, or anything else. -/obj/item/proc/dropped(mob/user) - if(randpixel) - pixel_z = randpixel //an idea borrowed from some of the older pixel_y randomizations. Intended to make items appear to drop at a character - - update_twohanding() - if(user) - if(user.l_hand) - user.l_hand.update_twohanding() - if(user.r_hand) - user.r_hand.update_twohanding() - -// called just as an item is picked up (loc is not yet changed) -/obj/item/proc/pickup(mob/user) - return - -// called when this item is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. -/obj/item/proc/on_exit_storage(obj/item/storage/S) - return - -// called when this item is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. -/obj/item/proc/on_enter_storage(obj/item/storage/S) - return - -// called when "found" in pockets and storage items. Returns 1 if the search should end. -/obj/item/proc/on_found(mob/finder) - return - -// called after an item is placed in an equipment slot -// user is mob that equipped it -// slot uses the slot_X defines found in setup.dm -// for items that can be placed in multiple slots -// note this isn't called during the initial dressing of a player -/obj/item/proc/equipped(var/mob/user, var/slot) - hud_layerise() - if(user.client) user.client.screen |= src - - //Update two-handing status - var/mob/M = loc - if(!istype(M)) - return - if(M.l_hand) - M.l_hand.update_twohanding() - if(M.r_hand) - M.r_hand.update_twohanding() - -//Defines which slots correspond to which slot flags -var/list/global/slot_flags_enumeration = list( - "[slot_wear_mask]" = SLOT_MASK, - "[slot_back]" = SLOT_BACK, - "[slot_wear_suit]" = SLOT_OCLOTHING, - "[slot_gloves]" = SLOT_GLOVES, - "[slot_shoes]" = SLOT_FEET, - "[slot_belt]" = SLOT_BELT, - "[slot_glasses]" = SLOT_EYES, - "[slot_head]" = SLOT_HEAD, - "[slot_l_ear]" = SLOT_EARS|SLOT_TWOEARS, - "[slot_r_ear]" = SLOT_EARS|SLOT_TWOEARS, - "[slot_w_uniform]" = SLOT_ICLOTHING, - "[slot_wear_id]" = SLOT_ID, - "[slot_tie]" = SLOT_TIE, - ) - -//the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't. -//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen. -//Set disable_warning to 1 if you wish it to not give you outputs. -//Should probably move the bulk of this into mob code some time, as most of it is related to the definition of slots and not item-specific -//set force to ignore blocking overwear and occupied slots -/obj/item/proc/mob_can_equip(M, slot, disable_warning = 0, force = 0) - if(!slot) return 0 - if(!M) return 0 - - if(!ishuman(M)) return 0 - - var/mob/living/carbon/human/H = M - var/list/mob_equip = list() - if(H.species.hud && H.species.hud.equip_slots) - mob_equip = H.species.hud.equip_slots - - if(H.species && !(slot in mob_equip)) - return 0 - - //First check if the item can be equipped to the desired slot. - if("[slot]" in slot_flags_enumeration) - var/req_flags = slot_flags_enumeration["[slot]"] - if(!(req_flags & slot_flags)) - return 0 - - if(!force) - //Next check that the slot is free - if(H.get_equipped_item(slot)) - return 0 - - //Next check if the slot is accessible. - var/mob/_user = disable_warning? null : H - if(!H.slot_is_accessible(slot, src, _user)) - return 0 - - //Lastly, check special rules for the desired slot. - switch(slot) - if(slot_l_ear, slot_r_ear) - var/slot_other_ear = (slot == slot_l_ear)? slot_r_ear : slot_l_ear - if( (w_class > ITEM_SIZE_TINY) && !(slot_flags & SLOT_EARS) ) - return 0 - if( (slot_flags & SLOT_TWOEARS) && H.get_equipped_item(slot_other_ear) ) - return 0 - if(slot_belt) - if(slot == slot_belt && (item_flags & ITEM_FLAG_IS_BELT)) - return 1 - else if(!H.w_uniform && (slot_w_uniform in mob_equip)) - if(!disable_warning) - to_chat(H, "You need a jumpsuit before you can attach this [name].") - return 0 - if(slot_l_store, slot_r_store) - if(!H.w_uniform && (slot_w_uniform in mob_equip)) - if(!disable_warning) - to_chat(H, "You need a jumpsuit before you can attach this [name].") - return 0 - if(slot_flags & SLOT_DENYPOCKET) - return 0 - if( w_class > ITEM_SIZE_SMALL && !(slot_flags & SLOT_POCKET) ) - return 0 - if(get_storage_cost() >= ITEM_SIZE_NO_CONTAINER) - return 0 - if(slot_s_store) - if(!H.wear_suit && (slot_wear_suit in mob_equip)) - if(!disable_warning) - to_chat(H, "You need a suit before you can attach this [name].") - return 0 - if(!H.wear_suit.allowed) - if(!disable_warning) - to_chat(usr, "You somehow have a suit with no defined allowed items for suit storage, stop that.") - return 0 - if( !(istype(src, /obj/item/modular_computer/pda) || istype(src, /obj/item/pen) || is_type_in_list(src, H.wear_suit.allowed)) ) - return 0 - if(slot_handcuffed) - if(!istype(src, /obj/item/handcuffs)) - return 0 - if(slot_in_backpack) //used entirely for equipping spawned mobs or at round start - var/allow = 0 - if(H.back && istype(H.back, /obj/item/storage/backpack)) - var/obj/item/storage/backpack/B = H.back - if(B.can_be_inserted(src,M,1)) - allow = 1 - if(!allow) - return 0 - if(slot_tie) - if((!H.w_uniform && (slot_w_uniform in mob_equip)) && (!H.wear_suit && (slot_wear_suit in mob_equip))) - if(!disable_warning) - to_chat(H, "You need something you can attach \the [src] to.") - return 0 - if(H.w_uniform && (slot_w_uniform in mob_equip)) - var/obj/item/clothing/under/uniform = H.w_uniform - if(uniform && !uniform.can_attach_accessory(src)) - if (!disable_warning) - to_chat(H, "You cannot equip \the [src] to \the [uniform].") - return 0 - else return 1 - if(H.wear_suit && (slot_wear_suit in mob_equip)) - var/obj/item/clothing/suit/suit = H.wear_suit - if(suit && !suit.can_attach_accessory(src)) - if (!disable_warning) - to_chat(H, "You cannot equip \the [src] to \the [suit].") - return 0 - - return 1 - -/obj/item/proc/mob_can_unequip(mob/M, slot, disable_warning = 0) - if(!slot) return 0 - if(!M) return 0 - - if(!canremove) - return 0 - if(!M.slot_is_accessible(slot, src, disable_warning? null : M)) - return 0 - return 1 - -/obj/item/proc/can_be_dropped_by_client(mob/M) - return M.canUnEquip(src) - -/obj/item/verb/verb_pickup() - set src in oview(1) - set category = "Object" - set name = "Pick up" - - if(!(usr)) //BS12 EDIT - return - if(!CanPhysicallyInteract(usr)) - return - if((!istype(usr, /mob/living/carbon)) || (istype(usr, /mob/living/carbon/brain)))//Is humanoid, and is not a brain - to_chat(usr, "You can't pick things up!") - return - if( usr.stat || usr.restrained() )//Is not asleep/dead and is not restrained - to_chat(usr, "You can't pick things up!") - return - if(src.anchored) //Object isn't anchored - to_chat(usr, "You can't pick that up!") - return - if(!usr.hand && usr.r_hand) //Right hand is not full - to_chat(usr, "Your right hand is full.") - return - if(usr.hand && usr.l_hand) //Left hand is not full - to_chat(usr, "Your left hand is full.") - return - if(!istype(src.loc, /turf)) //Object is on a turf - to_chat(usr, "You can't pick that up!") - return - //All checks are done, time to pick it up! - usr.UnarmedAttack(src) - return - - -//This proc is executed when someone clicks the on-screen UI button. To make the UI button show, set the 'icon_action_button' to the icon_state of the image of the button in screen1_action.dmi -//The default action is attack_self(). -//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob. -/obj/item/proc/ui_action_click() - attack_self(usr) - -//RETURN VALUES -//handle_shield should return a positive value to indicate that the attack is blocked and should be prevented. -//If a negative value is returned, it should be treated as a special return value for bullet_act() and handled appropriately. -//For non-projectile attacks this usually means the attack is blocked. -//Otherwise should return 0 to indicate that the attack is not affected in any way. -/obj/item/proc/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - var/parry_chance = get_parry_chance(user) - if(attacker) - parry_chance = max(0, parry_chance - 10 * attacker.get_skill_difference(SKILL_COMBAT, user)) - if(parry_chance) - if(default_parry_check(user, attacker, damage_source) && prob(parry_chance)) - user.visible_message("\The [user] parries [attack_text] with \the [src]!") - playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) - on_parry(damage_source) - return 1 - return 0 - -/obj/item/proc/on_parry(damage_source) - return - -/obj/item/proc/get_parry_chance(mob/user) - . = base_parry_chance - if(user) - if(base_parry_chance || user.skill_check(SKILL_COMBAT, SKILL_ADEPT)) - . += 10 * (user.get_skill_value(SKILL_COMBAT) - SKILL_BASIC) - -/obj/item/proc/on_disarm_attempt(mob/target, mob/living/attacker) - if(force < 1) - return 0 - if(!istype(attacker)) - return 0 - attacker.apply_damage(force, damtype, attacker.hand ? BP_L_HAND : BP_R_HAND, used_weapon = src) - attacker.visible_message("[attacker] hurts \his hand on [src]!") - playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - playsound(target, hitsound, 50, 1, -1) - return 1 - -/obj/item/proc/get_loc_turf() - var/atom/L = loc - while(L && !istype(L, /turf/)) - L = L.loc - return loc - -/obj/item/proc/eyestab(mob/living/carbon/M, mob/living/carbon/user) - - var/mob/living/carbon/human/H = M - if(istype(H)) - for(var/obj/item/protection in list(H.head, H.wear_mask, H.glasses)) - if(protection && (protection.body_parts_covered & EYES)) - // you can't stab someone in the eyes wearing a mask! - to_chat(user, "You're going to need to remove the eye covering first.") - return - - if(!M.check_has_eyes()) - to_chat(user, "You cannot locate any eyes on [M]!") - return - - admin_attack_log(user, M, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - - src.add_fingerprint(user) - - if(istype(H)) - - var/obj/item/organ/internal/eyes/eyes = H.internal_organs_by_name[BP_EYES] - - if(H != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("[M] has been stabbed in the eye with [src] by [user].", 1) - to_chat(M, "[user] stabs you in the eye with [src]!") - to_chat(user, "You stab [M] in the eye with [src]!") - else - user.visible_message( \ - "[user] has stabbed themself with [src]!", \ - "You stab yourself in the eyes with [src]!" \ - ) - - eyes.damage += rand(3,4) - if(eyes.damage >= eyes.min_bruised_damage) - if(M.stat != 2) - if(!BP_IS_PROSTHETIC(eyes)) //robot eyes bleeding might be a bit silly - to_chat(M, "Your eyes start to bleed profusely!") - if(prob(50)) - if(M.stat != 2) - to_chat(M, "You drop what you're holding and clutch at your eyes!") - M.unequip_item() - M.eye_blurry += 10 - M.Paralyse(1) - M.Weaken(4) - if (eyes.damage >= eyes.min_broken_damage) - if(M.stat != 2) - to_chat(M, "You go blind!") - - var/obj/item/organ/external/affecting = H.get_organ(eyes.parent_organ) - affecting.take_external_damage(7) - else - M.take_organ_damage(7) - M.eye_blurry += rand(3,4) - return - -/obj/item/clean_blood() - . = ..() - if(blood_overlay) - overlays.Remove(blood_overlay) - if(istype(src, /obj/item/clothing/gloves)) - var/obj/item/clothing/gloves/G = src - G.transfer_blood = 0 - var/datum/extension/forensic_evidence/forensics = get_extension(src, /datum/extension/forensic_evidence) - if(forensics) - forensics.remove_data(/datum/forensics/trace_dna) - -/obj/item/reveal_blood() - if(was_bloodied && !fluorescent) - fluorescent = 1 - blood_color = COLOR_LUMINOL - blood_overlay.color = COLOR_LUMINOL - update_icon() - -/obj/item/add_blood(mob/living/carbon/human/M) - if (!..()) - return 0 - - if(istype(src, /obj/item/energy_blade)) - return - - //if we haven't made our blood_overlay already - if( !blood_overlay ) - generate_blood_overlay() - - //apply the blood-splatter overlay if it isn't already in there - if(!blood_DNA.len) - blood_overlay.color = blood_color - overlays += blood_overlay - - //if this blood isn't already in the list, add it - if(istype(M)) - if(blood_DNA[M.dna.unique_enzymes]) - return 0 //already bloodied with this blood. Cannot add more. - blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - var/datum/extension/forensic_evidence/forensics = get_or_create_extension(src, /datum/extension/forensic_evidence) - forensics.add_data(/datum/forensics/blood_dna, M.dna.unique_enzymes) - return 1 //we applied blood to the item - -GLOBAL_LIST_EMPTY(blood_overlay_cache) - -/obj/item/proc/generate_blood_overlay(force = FALSE) - if(blood_overlay && !force) - return - if(GLOB.blood_overlay_cache["[icon]" + icon_state]) - blood_overlay = GLOB.blood_overlay_cache["[icon]" + icon_state] - return - var/icon/I = new /icon(icon, icon_state) - I.Blend(new /icon('icons/effects/blood.dmi', rgb(255,255,255)),ICON_ADD) //fills the icon_state with white (except where it's transparent) - I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY) //adds blood and the remaining white areas become transparant - blood_overlay = image(I) - blood_overlay.appearance_flags |= NO_CLIENT_COLOR|RESET_COLOR - GLOB.blood_overlay_cache["[icon]" + icon_state] = blood_overlay - -/obj/item/proc/showoff(mob/user) - for (var/mob/M in view(user)) - M.show_message("[user] holds up [src]. Take a closer look.",1) - -/mob/living/carbon/verb/showoff() - set name = "Show Held Item" - set category = "Object" - - var/obj/item/I = get_active_hand() - if(I && I.simulated) - I.showoff(src) - -/* -For zooming with scope or binoculars. This is called from -modules/mob/mob_movement.dm if you move you will be zoomed out -modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. -*/ -//Looking through a scope or binoculars should /not/ improve your periphereal vision. Still, increase viewsize a tiny bit so that sniping isn't as restricted to NSEW -/obj/item/proc/zoom(mob/user, var/tileoffset = 14,var/viewsize = 9) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view - if(!user.client) - return - if(zoom) - return - - var/devicename = zoomdevicename || name - - var/mob/living/carbon/human/H = user - if(user.incapacitated(INCAPACITATION_DISABLED)) - to_chat(user, "You are unable to focus through the [devicename].") - return - else if(!zoom && istype(H) && H.equipment_tint_total >= TINT_MODERATE) - to_chat(user, "Your visor gets in the way of looking through the [devicename].") - return - else if(!zoom && user.get_active_hand() != src) - to_chat(user, "You are too distracted to look through the [devicename], perhaps if it was in your active hand this might work better.") - return - - if(user.hud_used.hud_shown) - user.toggle_zoom_hud() // If the user has already limited their HUD this avoids them having a HUD when they zoom in - user.client.view = viewsize - zoom = 1 - - var/viewoffset = WORLD_ICON_SIZE * tileoffset - switch(user.dir) - if (NORTH) - user.client.pixel_x = 0 - user.client.pixel_y = viewoffset - if (SOUTH) - user.client.pixel_x = 0 - user.client.pixel_y = -viewoffset - if (EAST) - user.client.pixel_x = viewoffset - user.client.pixel_y = 0 - if (WEST) - user.client.pixel_x = -viewoffset - user.client.pixel_y = 0 - - user.visible_message("\The [user] peers through [zoomdevicename ? "the [zoomdevicename] of [src]" : "[src]"].") - - GLOB.destroyed_event.register(src, src, /obj/item/proc/unzoom) - GLOB.moved_event.register(src, src, /obj/item/proc/unzoom) - GLOB.dir_set_event.register(src, src, /obj/item/proc/unzoom) - GLOB.item_unequipped_event.register(src, src, /obj/item/proc/zoom_drop) - GLOB.stat_set_event.register(user, src, /obj/item/proc/unzoom) - -/obj/item/proc/zoom_drop(var/obj/item/I, var/mob/user) - unzoom(user) - -/obj/item/proc/unzoom(var/mob/user) - if(!zoom) - return - zoom = 0 - - GLOB.destroyed_event.unregister(src, src, /obj/item/proc/unzoom) - GLOB.moved_event.unregister(src, src, /obj/item/proc/unzoom) - GLOB.dir_set_event.unregister(src, src, /obj/item/proc/unzoom) - GLOB.item_unequipped_event.unregister(src, src, /obj/item/proc/zoom_drop) - - user = user == src ? loc : (user || loc) - if(!istype(user)) - crash_with("[log_info_line(src)]: Zoom user lost]") - return - - GLOB.stat_set_event.unregister(user, src, /obj/item/proc/unzoom) - - if(!user.client) - return - - user.client.view = world.view - user.client.OnResize() - if(!user.hud_used.hud_shown) - user.toggle_zoom_hud() - - user.client.pixel_x = 0 - user.client.pixel_y = 0 - user.client.OnResize() - user.visible_message("[zoomdevicename ? "\The [user] looks up from [src]" : "\The [user] lowers [src]"].") - -/obj/item/proc/pwr_drain() - return 0 // Process Kill - -/obj/item/proc/use_spritesheet(var/bodytype, var/slot, var/icon_state) - if(!sprite_sheets || !sprite_sheets[bodytype]) - return 0 - if(slot == slot_r_hand_str || slot == slot_l_hand_str) - return 0 - - if(icon_state in icon_states(sprite_sheets[bodytype])) - return 1 - - return (slot != slot_wear_suit_str && slot != slot_head_str) - -/obj/item/proc/get_icon_state(mob/user_mob, slot) - var/mob_state - if(slot in item_state_slots) - mob_state = item_state_slots[slot] - else if (item_state) - mob_state = item_state - else - mob_state = icon_state - return mob_state - -/obj/item/proc/get_mob_overlay(mob/user_mob, slot) - - if(use_single_icon) - return experimental_mob_overlay(user_mob, slot) - - var/bodytype = "Default" - var/mob/living/carbon/human/user_human - if(ishuman(user_mob)) - user_human = user_mob - bodytype = user_human.species.get_bodytype(user_human) - - var/mob_state = get_icon_state(user_mob, slot) - - var/mob_icon - var/spritesheet = FALSE - if(icon_override) - mob_icon = icon_override - if(slot == slot_l_hand_str || slot == slot_l_ear_str) - mob_state = "[mob_state]_l" - if(slot == slot_r_hand_str || slot == slot_r_ear_str) - mob_state = "[mob_state]_r" - else if(use_spritesheet(bodytype, slot, mob_state)) - if(slot == slot_l_ear) - mob_state = "[mob_state]_l" - if(slot == slot_r_ear) - mob_state = "[mob_state]_r" - spritesheet = TRUE - mob_icon = sprite_sheets[bodytype] - else if(item_icons && item_icons[slot]) - mob_icon = item_icons[slot] - else - mob_icon = default_onmob_icons[slot] - - if(user_human) - return user_human.species.get_offset_overlay_image(spritesheet, mob_icon, mob_state, color, slot) - return overlay_image(mob_icon, mob_state, color, RESET_COLOR) - -/obj/item/proc/get_examine_line() - if(blood_color) - . = SPAN_WARNING("\icon[src] [gender==PLURAL?"some":"a"] stained [src]") - else - . = "\icon[src] \a [src]" - var/ID = GetIdCard() - if(ID) - . += " \[Look at ID\]" - -/obj/item/proc/on_active_hand() - -/obj/item/is_burnable() - return simulated - -/obj/item/lava_act() - . = (!throwing) ? ..() : FALSE - -/obj/item/proc/has_embedded() - return - -/obj/item/proc/get_pressure_weakness(pressure,zone) - . = 1 - if(pressure > ONE_ATMOSPHERE) - if(max_pressure_protection != null) - if(max_pressure_protection < pressure) - return min(1, round((pressure - max_pressure_protection) / max_pressure_protection, 0.01)) - else - return 0 - if(pressure < ONE_ATMOSPHERE) - if(min_pressure_protection != null) - if(min_pressure_protection > pressure) - return min(1, round((min_pressure_protection - pressure) / min_pressure_protection, 0.01)) - else - return 0 - -/obj/item/do_simple_ranged_interaction(var/mob/user) - if(user) - attack_self(user) - return TRUE - -/obj/item/proc/inherit_custom_item_data(var/datum/custom_item/citem) - . = src - if(citem.item_name) - SetName(citem.item_name) - if(citem.item_desc) - desc = citem.item_desc - if(citem.item_icon_state) - item_state_slots = null - item_icons = null - icon = CUSTOM_ITEM_OBJ - set_icon_state(citem.item_icon_state) - item_state = null - icon_override = CUSTOM_ITEM_MOB - -/obj/item/proc/is_special_cutting_tool(var/high_power) - return FALSE - -/obj/item/proc/w_class_description() - switch(w_class) - if(ITEM_SIZE_TINY) - return "tiny" - if(ITEM_SIZE_SMALL) - return "small" - if(ITEM_SIZE_NORMAL) - return "normal-sized" - if(ITEM_SIZE_LARGE) - return "large" - if(ITEM_SIZE_HUGE) - return "bulky" - if(ITEM_SIZE_HUGE + 1 to INFINITY) - return "huge" - -/obj/item/proc/get_autopsy_descriptors() - var/list/descriptors = list() - descriptors += w_class_description() - if(sharp) - descriptors += "sharp" - if(edge) - descriptors += "edged" - if(force >= 10 && !sharp && !edge) - descriptors += "heavy" - if(material) - descriptors += "made of [material.solid_name]" - return descriptors - -/obj/item/proc/attack_message_name() - return "\a [src]" diff --git a/code/game/objects/item_materials.dm b/code/game/objects/item_materials.dm deleted file mode 100644 index 5ae134c8d5d0..000000000000 --- a/code/game/objects/item_materials.dm +++ /dev/null @@ -1,82 +0,0 @@ -/obj/item/on_update_icon() - overlays.Cut() - if(applies_material_colour && material) - color = material.color - alpha = 100 + material.opacity * 255 - -/obj/item/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - . = ..() - if(material && (material.is_brittle() || target.get_blocked_ratio(hit_zone, BRUTE, damage_flags(), armor_penetration, force) * 100 >= material.hardness/5)) - check_shatter() - -/obj/item/on_parry(damage_source) - if(istype(damage_source, /obj/item)) - check_shatter() - -/obj/item/proc/check_shatter() - if(material && !unbreakable && prob(material.hardness)) - if(material.is_brittle()) - health = 0 - else - health-- - check_health() - -/obj/item/proc/check_health(var/consumed) - if(health<=0) - shatter(consumed) - -/obj/item/proc/shatter(var/consumed) - var/turf/T = get_turf(src) - T.visible_message(SPAN_DANGER("\The [src] [material ? material.destruction_desc : "shatters"]!")) - playsound(src, "shatter", 70, 1) - if(!consumed && material && w_class > ITEM_SIZE_SMALL) - material.place_shard(T) - qdel(src) - -/obj/item/get_material() - . = material - -/obj/item/proc/update_force() - var/new_force - if(!max_force) - max_force = 5 * min(w_class, ITEM_SIZE_GARGANTUAN) - if(material) - if(edge || sharp) - new_force = material.get_edge_damage() - else - new_force = material.get_blunt_damage() - new_force = round(new_force*material_force_multiplier) - force = min(new_force, max_force) - - if(new_force > max_force) - armor_penetration = initial(armor_penetration) + new_force - max_force - - attack_cooldown = initial(attack_cooldown) - if(material) - armor_penetration += 2*max(0, material.brute_armor - 2) - throwforce = round(material.get_blunt_damage() * thrown_material_force_multiplier) - attack_cooldown += material.get_attack_cooldown() - -/obj/item/proc/set_material(var/new_material) - if(new_material) - material = decls_repository.get_decl(new_material) - if(istype(material)) - health = round(material_health_multiplier * material.integrity) - max_health = health - if(material.products_need_process()) - START_PROCESSING(SSobj, src) - if(material.conductive) - obj_flags |= OBJ_FLAG_CONDUCTIBLE - else - obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) - update_force() - if(applies_material_name) - SetName("[material.solid_name] [initial(name)]") - if(material_armor_multiplier) - armor = material.get_armor(material_armor_multiplier) - armor_degradation_speed = material.armor_degradation_speed - if(length(armor)) - set_extension(src, armor_type, armor, armor_degradation_speed) - else - remove_extension(src, armor_type) - queue_icon_update() diff --git a/code/game/objects/item_mob_overlay.dm b/code/game/objects/item_mob_overlay.dm new file mode 100644 index 000000000000..30a942c61231 --- /dev/null +++ b/code/game/objects/item_mob_overlay.dm @@ -0,0 +1,199 @@ +// This is a temporary workaround for the slot => bodypart +// changes. In the long term this should be removed after +// all the `slot_l/r_hand-foo` states are renamed to just +// `l/r_hand-foo`. TODO: check if this is still here in 2025. +var/global/list/bodypart_to_slot_lookup_table = list( + BP_L_HAND = "slot_l_hand", + BP_R_HAND = "slot_r_hand" +) + +/obj/item/proc/reconsider_single_icon(var/update_icon) + var/list/icon_states = get_states_in_icon_cached(icon) // pre-cache to make our up-to-three checks faster + // except now we only do two because i rewrote it + has_inventory_icon = use_single_icon = icon_states[ICON_STATE_INV] + if(!has_inventory_icon) + use_single_icon = icon_states[ICON_STATE_WORLD] + if(use_single_icon) + icon_state = get_world_inventory_state() + . = TRUE + if(. || update_icon) + update_icon() + +// For checking if we have a specific state, for inventory icons and nonhumanoid species. +// Cached cause asking icons is expensive. This is still expensive, so avoid using it if +// you can reasonably expect the icon_state to exist beforehand, or if you can cache the +// value somewhere (as done below with use_single_icon in /obj/item/Initialize()). +var/global/list/icon_state_cache = list() +/proc/check_state_in_icon(var/checkstate, var/checkicon) + // isicon() is apparently quite expensive so short-circuit out early if we can. + if(!istext(checkstate) || isnull(checkicon) || !(isfile(checkicon) || isicon(checkicon))) + return FALSE + var/list/check = _fetch_icon_state_cache_entry(checkicon) // should never return null once we reach this point + return check[checkstate] + +/// A proc for getting an associative list of icon states in an icon. +/// Uses the same cache as check_state_in_icon. +/// Does not copy, MUST NOT BE MUTATED. +/proc/get_states_in_icon_cached(checkicon) /* as OD_MAP(text, OD_BOOL) */ + return _fetch_icon_state_cache_entry(checkicon) || list() + +/// get_states_in_icon_cached but it does a copy, so the return value can be mutated. +/proc/get_states_in_icon(checkicon) /* as OD_MAP(text, OD_BOOL) */ + var/list/out = get_states_in_icon_cached(checkicon) + return out.Copy() + +/proc/_fetch_icon_state_cache_entry(checkicon) + if(!checkicon) + return null + // if we want to let people del icons (WHY???) then we can use weakreF() + // but right now it's cheaper to just use checkicon directly + // ref doesn't even do any deduplication + var/list/check = global.icon_state_cache[checkicon] + if(!check) + check = list() + for(var/istate in icon_states(checkicon)) + check[istate] = TRUE + global.icon_state_cache[checkicon] = check + return check + +/obj/item/proc/update_world_inventory_state() + if(use_single_icon && has_inventory_icon) + var/last_state = icon_state + icon_state = get_world_inventory_state() + if(last_state != icon_state) + update_icon() + +/obj/item/proc/get_world_inventory_state() + if(use_single_icon) + if(plane == HUD_PLANE && has_inventory_icon) + return ICON_STATE_INV + return ICON_STATE_WORLD + +/obj/item/hud_layerise() + ..() + update_world_inventory_state() + +/obj/item/reset_plane_and_layer() + ..() + update_world_inventory_state() + +/obj/item/proc/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) + + var/is_not_held_slot = !(slot in global.all_hand_slots) + if(!draw_on_mob_when_equipped && is_not_held_slot) + return new /image + + var/state_modifier = user_mob?.get_overlay_state_modifier() + + if(!use_single_icon) + var/mob_state = "[item_state || icon_state][state_modifier]" + var/mob_icon = global.default_onmob_icons[slot] + var/decl/bodytype/root_bodytype = user_mob?.get_equipment_bodytype(slot, bodypart) + if(istype(root_bodytype)) + var/use_slot = (bodypart in root_bodytype.get_equip_adjustments(user_mob)) ? bodypart : slot + return root_bodytype.get_offset_overlay_image(user_mob, mob_icon, mob_state, color, use_slot) + return overlay_image(mob_icon, mob_state, color, RESET_COLOR) + + var/bodytype = user_mob?.get_bodytype_category() || BODYTYPE_HUMANOID + var/useicon = get_icon_for_bodytype(bodytype) + var/use_state = "[bodytype]-[slot]" + if(state_modifier) + use_state = "[use_state][state_modifier]" + + if(bodytype != BODYTYPE_HUMANOID && !check_state_in_icon(use_state, useicon) && use_fallback_if_icon_missing) + + var/fallback = is_not_held_slot && get_fallback_slot(slot) + if(fallback && fallback != slot) + if(state_modifier) + if(check_state_in_icon("[bodytype]-[fallback][state_modifier]", useicon)) + slot = fallback + else if(check_state_in_icon("[bodytype]-[fallback]", useicon)) + slot = fallback + else + bodytype = BODYTYPE_HUMANOID + useicon = get_icon_for_bodytype(bodytype) + + if(state_modifier) + use_state = "[bodytype]-[slot][state_modifier]" + if(!check_state_in_icon(use_state, useicon)) + use_state = "[bodytype]-[slot]" + else + use_state = "[bodytype]-[slot]" + + if(!check_state_in_icon(use_state, useicon) && global.bodypart_to_slot_lookup_table[slot]) + + var/lookup_slot = global.bodypart_to_slot_lookup_table[slot] + if(state_modifier) + use_state = "[bodytype]-[lookup_slot][state_modifier]" + if(!check_state_in_icon(use_state, useicon)) + use_state = "[bodytype]-[lookup_slot]" + else + use_state = "[bodytype]-[lookup_slot]" + + if(!check_state_in_icon(use_state, useicon)) + var/fallback = use_fallback_if_icon_missing && is_not_held_slot && get_fallback_slot(slot) + if(!fallback) + return new /image + slot = fallback + if(state_modifier) + use_state = "[bodytype]-[slot][state_modifier]" + if(!check_state_in_icon(use_state, useicon)) + use_state = "[bodytype]-[slot]" + else + use_state = "[bodytype]-[slot]" + + if(!check_state_in_icon(use_state, useicon)) + return new /image + + var/image/I = image(useicon, use_state) + I.color = color + I.appearance_flags = RESET_COLOR + + . = skip_adjustment ? I : adjust_mob_overlay(user_mob, bodytype, I, slot, bodypart, use_fallback_if_icon_missing) + +/obj/item/proc/get_fallback_slot(var/slot) + return + +/obj/item/proc/get_icon_for_bodytype(var/bodytype) + . = LAZYACCESS(sprite_sheets, bodytype) || icon + +// Ensure ..() is called only at the end of this proc, and that `overlay` is mutated rather than replaced. +// This is necessary to ensure that all the overlays are generated and tracked prior to being passed to +// the bodytype offset proc, which can scrub icon/icon_state information as part of the offset process. +/obj/item/proc/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + + if(!draw_on_mob_when_equipped && !(slot in global.all_hand_slots)) + return overlay + + if(overlay) + + if(is_held_twohanded()) + var/wielded_state = "[overlay.icon_state]-wielded" + if(check_state_in_icon(wielded_state, overlay.icon)) + overlay.icon_state = wielded_state + apply_additional_mob_overlays(user_mob, bodytype, overlay, slot, bodypart, use_fallback_if_icon_missing) + + var/decl/bodytype/root_bodytype = user_mob?.get_equipment_bodytype(slot, bodypart) + if(root_bodytype && root_bodytype.bodytype_category != bodytype) + var/list/overlays_to_offset = overlay.overlays + overlay = root_bodytype.get_offset_overlay_image(user_mob, overlay.icon, overlay.icon_state, color, (bodypart || slot)) + if(overlay) + for(var/thing in overlays_to_offset) + var/image/I = thing // Technically an appearance but don't think we can cast to those + var/image/adjusted_overlay = root_bodytype.get_offset_overlay_image(user_mob, I.icon, I.icon_state, I.color, (bodypart || slot)) + adjusted_overlay.appearance_flags = I.appearance_flags + adjusted_overlay.plane = I.plane + adjusted_overlay.layer = I.layer + overlay.overlays += adjusted_overlay + + return overlay + +/obj/item/proc/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + return + +//Special proc belts use to compose their icon +/obj/item/proc/get_on_belt_overlay() + if(check_state_in_icon("on_belt", icon)) + var/image/res = image(icon, "on_belt") + res.color = color + return res diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm new file mode 100644 index 000000000000..d9164b23c5e2 --- /dev/null +++ b/code/game/objects/items/__item.dm @@ -0,0 +1,1359 @@ +/obj/item + name = "item" + w_class = ITEM_SIZE_NORMAL + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + pass_flags = PASS_FLAG_TABLE + abstract_type = /obj/item + temperature_sensitive = TRUE + + /// Set to prefix name with this string ('woven' for 'woven basket' etc) + var/name_prefix + + /// Set to false to skip state checking and never draw an icon on the mob (except when held) + var/draw_on_mob_when_equipped = TRUE + + /// this saves our blood splatter/coating overlay, which will be processed not to go over the edges of the sprite. + var/image/coating_overlay + var/randpixel = 6 + var/material_health_multiplier = 0.2 + var/hitsound + /// This is used to determine on which slots an item can fit. + var/slot_flags = SLOT_NONE + /// If it's an item we don't want to log attack_logs with, set this to TRUE + var/no_attack_log = FALSE + var/obj/item/master = null + var/origin_tech //Used by R&D to determine what research bonuses it grants. + VAR_PROTECTED/list/attack_verb = "hit" //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" + var/lock_picking_level = 0 //used to determine whether something can pick a lock, and how well. + var/attack_cooldown = DEFAULT_WEAPON_COOLDOWN + var/melee_accuracy_bonus = 0 + + /// Flag for ZAS based contamination (chlorine etc) + var/contaminated = FALSE + + /// flags which determine which body parts are protected from heat. Use the SLOT_HEAD, SLOT_UPPER_BODY, SLOT_LOWER_BODY, etc. flags. See setup.dm + var/heat_protection = 0 + /// flags which determine which body parts are protected from cold. Use the SLOT_HEAD, SLOT_UPPER_BODY, SLOT_LOWER_BODY, etc. flags. See setup.dm + var/cold_protection = 0 + /// Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. + /// Keep at null to disable protection. Only protects areas set by heat_protection flags. + var/max_heat_protection_temperature + ///Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. + /// Keep at null to disable protection. Only protects areas set by cold_protection flags + var/min_cold_protection_temperature + /// Set this variable if the item protects its wearer against high pressures below an upper bound. + /// Keep at null to disable protection. + var/max_pressure_protection + /// Set this variable if the item protects its wearer against low pressures above a lower bound. + /// Keep at null to disable protection. 0 represents protection against hard vacuum. + var/min_pressure_protection + + var/datum/action/item_action/action + var/action_button_name //It is also the text which gets displayed on the action button. If not set it defaults to 'Use [name]'. If it's not set, there'll be no button. + var/action_button_desc //A description for action button which will be displayed as tooltip. + var/default_action_type = /datum/action/item_action // Specify the default type and behavior of the action button for this atom. + + //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc. + //It should be used purely for appearance. For gameplay effects caused by items covering body parts, use body_parts_covered. + var/flags_inv = 0 + var/body_parts_covered = 0 //see setup.dm for appropriate bit flags + + var/item_flags = 0 //Miscellaneous flags pertaining to equippable objects. + + //var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible + var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets) + var/permeability_coefficient = 1 // for chemicals/diseases + var/siemens_coefficient = 1 // for electrical admittance/conductance (electrocution checks and shit) + var/slowdown_general = 0 // How this item slows its holder down. Negative values speeds them up. This is a general slowdown, no matter the equipment slot. + /// How much this item slows its holder down, based on the slot it's in. This is an associative list: slot_string = slowdown + var/slowdown_per_slot + /// An additional slowdown amount, contributed by accessories attached to this item. Not to be confused with /obj/item/clothing/var/accessory_slowdown. + var/tmp/slowdown_accessory + /// If TRUE, the item cannot be removed except via destruction or using the force flag in unequip procs. + var/canremove = TRUE + /// if set, item will use material's armor values multiplied by this. + var/material_armor_multiplier + var/armor_type = /datum/extension/armor + var/list/armor + var/armor_degradation_speed //How fast armor will degrade, multiplier to blocked damage to get armor damage value. + var/list/allowed = null //suit storage stuff. + var/obj/item/uplink/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. + var/zoomdevicename = null //name used for message when binoculars/scope is used + /// if the item is actively being used to zoom. For scoped guns and binoculars. + var/zoom = FALSE + + var/base_parry_chance = 0 // Will allow weapon to parry melee attacks if non-zero + var/wielded_parry_bonus = 15 + + var/use_alt_layer = FALSE // Use the slot's alternative layer when rendering on a mob + + /// Assoc list of bodytype category to icon for producing onmob overlays when this item is held or worn. + var/list/sprite_sheets + + ///Will apply the flagged modifications to the object + var/material_alteration = MAT_FLAG_ALTERATION_NONE + var/anomaly_shielding // 0..1 value of how well it shields against xenoarch anomalies + + ///Sound used when equipping the item into a valid slot + var/equip_sound + ///Sound uses when picking the item up (into your hands) + var/pickup_sound = 'sound/foley/paperpickup2.ogg' + ///Sound uses when dropping the item, or when its thrown. + var/drop_sound = 'sound/foley/drop1.ogg' + + var/datum/reagents/coating // reagent container for coating things like blood/oil, used for overlays and tracks + + var/tmp/has_inventory_icon // do not set manually + var/tmp/use_single_icon + var/center_of_mass = @'{"x":16,"y":16}' //can be null for no exact placement behaviour + + /// Controls what method is used to resolve conflicts between equipped items and mob loadout. + var/replaced_in_loadout = LOADOUT_CONFLICT_DELETE + + var/paint_verb + + /// What dexterity is required to attack with this item? + var/needs_attack_dexterity = DEXTERITY_WIELD_ITEM + var/needs_interaction_dexterity = DEXTERITY_HOLD_ITEM + + /// Vars relating to wielding the item with two or more hands. + var/can_be_twohanded = FALSE + var/minimum_size_to_twohand = MOB_SIZE_MEDIUM + var/maximum_size_to_twohand = MOB_SIZE_LARGE + var/last_twohanded_state = FALSE + + var/wieldsound = 'sound/foley/scrape1.ogg' + var/unwieldsound = 'sound/foley/tooldrop1.ogg' + + var/base_name + var/base_desc + + /// Can this object leak into water sources? + var/watertight = FALSE + + /// Can this item knock someone out if used as a weapon? Overridden for natural weapons as a nerf to simplemobs. + var/weapon_can_knock_prone = TRUE + +/// Returns a dexterity value required to use this item as a weapon. +/obj/item/proc/get_required_attack_dexterity(mob/user, atom/target) + // We can likely assume that if we're located inside a rig, then the wearer + // has the appropriate dexterity to wear and use the rig, even if they aren't + // manually dexterous; specifically useful for things like baxxid and drakes. + var/obj/item/rig/rig = get_recursive_loc_of_type(/obj/item/rig) + . = istype(rig) ? DEXTERITY_NONE : needs_attack_dexterity + if(istype(target)) + . = target.adjust_required_attack_dexterity(user, .) + +// Returns a dexterity value required to interact with this item at all, such as picking it up. +/obj/item/get_required_interaction_dexterity() + return needs_interaction_dexterity + +/obj/item/get_color() + if(paint_color) + return paint_color + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_COLOR)) + return material.color + return initial(color) + +/obj/item/set_color(new_color) + if(new_color == COLOR_WHITE) + new_color = null + if(paint_color != new_color) + paint_color = new_color + . = TRUE + refresh_color() + +/obj/item/refresh_color() + if(paint_color) + color = paint_color + else if(material && (material_alteration & MAT_FLAG_ALTERATION_COLOR)) + color = material.color + else + color = null + + +/obj/item/proc/can_contaminate() + return !(obj_flags & ITEM_FLAG_NO_CONTAMINATION) + +// Foley sound callbacks +/obj/item/proc/equipped_sound_callback() + if(ismob(loc) && equip_sound) + playsound(src, equip_sound, 25, 0) + +/obj/item/proc/pickup_sound_callback() + if(ismob(loc) && pickup_sound) + playsound(src, pickup_sound, 25, 0) + +/obj/item/proc/dropped_sound_callback() + if(!ismob(loc) && drop_sound) + playsound(src, pick(drop_sound), 25, 0) + +/obj/item/proc/get_origin_tech() + return origin_tech + +/obj/item/Initialize(var/ml, var/material_key) + + base_name ||= name + base_desc ||= desc + + if(isnull(current_health)) + current_health = max_health //Make sure to propagate max_health to health var before material setup, for consistency + if(!ispath(material_key, /decl/material)) + material_key = material + if(material_key) + set_material(material_key) + paint_verb ||= "painted" // fallback for the case of no material + + // This is a bit gross, but it makes writing rings and necklaces much easier. + // If the decorations list is already populated at this point, we assume it's + // prebaked decorations. + // Only things handled appropriately at the moment are gems and material inlays. + if(length(decorations)) + for(var/decoration_type in decorations) + decorations -= decoration_type + if(ispath(decoration_type, /obj/item/gemstone)) + decorations[GET_DECL(/decl/item_decoration/setting)] = list("object" = new decoration_type(src)) + else if(ispath(decoration_type, /decl/material)) + decorations[GET_DECL(/decl/item_decoration/inset)] = list("material" = GET_DECL(decoration_type)) + else + PRINT_STACK_TRACE("Item [type] tried to initialize with an unsupported initial decoration type ('[decoration_type]')") + . = ..() + + setup_sprite_sheets() + + if(islist(armor)) + for(var/type in armor) + if(armor[type]) // Don't set it if it gives no armor anyway, which is many items. + set_extension(src, armor_type, armor, armor_degradation_speed) + break + if(randpixel && (!pixel_x && !pixel_y) && isturf(loc)) //hopefully this will prevent us from messing with mapper-set pixel_x/y + pixel_x = rand(-randpixel, randpixel) + pixel_y = rand(-randpixel, randpixel) + + reconsider_single_icon() + + if(storage) + if(storage.allow_quick_empty) + verbs += /obj/item/proc/quick_empty + if(storage.allow_quick_gather) + verbs += /obj/item/proc/toggle_gathering_mode + var/list/will_contain = WillContain() + if(length(will_contain)) + create_objects_in_loc(src, will_contain) + update_icon() + +/obj/item/Destroy() + + // May contain object references. + LAZYCLEARLIST(decorations) + + if(LAZYLEN(_item_effects)) + _item_effects = null + SSitem_effects.queued_items -= src + + global.listening_objects -= src + + STOP_PROCESSING(SSobj, src) + QDEL_NULL(hidden_uplink) + QDEL_NULL(coating) + + if(istype(action)) + if(action.target == src) + action.target = null + if(!QDELETED(action)) + QDEL_NULL(action) + else + action = null + + if(ismob(loc)) + var/mob/M = loc + LAZYREMOVE(M.pinned, src) + LAZYREMOVE(M.embedded, src) + for(var/obj/item/organ/external/organ in M.get_organs()) + LAZYREMOVE(organ.implants, src) + M.drop_from_inventory(src) + + return ..() + +/obj/item/GetCloneArgs() + . = ..() + LAZYADD(., material?.type) + +//#TODO: Implement this for all the sub class that need it +/obj/item/PopulateClone(obj/item/clone) + clone = ..() + clone.contaminated = contaminated + clone.coating_overlay = image(coating_overlay) + clone.current_health = current_health + + //#TODO: once item damage in, check health! + + //Coating + clone.coating = coating?.Clone() + if(clone.coating) + clone.coating.set_holder(clone) + return clone + +//Run some updates +/obj/item/Clone() + var/obj/item/clone = ..() + if(clone) + clone.update_icon() + clone.update_held_icon() + return clone + +/obj/item/proc/update_twohanding() + + var/next_wielded_state = is_held_twohanded() + if(last_twohanded_state == next_wielded_state) + return + + if(next_wielded_state) + if(wieldsound) + playsound(src, wieldsound, 50) + else + if(unwieldsound) + playsound(src, unwieldsound, 50) + + update_icon() + update_held_icon() + update_attack_force() + last_twohanded_state = next_wielded_state + +//Checks if the item is being held by a mob, and if so, updates the held icons +/obj/item/proc/update_held_icon() + if(ismob(src.loc)) + var/mob/M = src.loc + M.update_inhand_overlays() + +/obj/item/proc/is_held_twohanded(mob/living/wielder) + if(!can_be_twohanded) + return FALSE + if(istype(loc, /obj/item/rig_module) || istype(loc, /obj/item/rig)) + return TRUE + if(!wielder) + wielder = loc + if(!istype(wielder)) + return FALSE + if(!(src in wielder.get_held_items())) + return FALSE + return wielder.can_twohand_item(src) + +/obj/item/get_examine_strings(mob/user, distance, infix, suffix) + + var/list/desc_comp = list() + desc_comp += "It is a [w_class_description()] item." + + var/desc_damage = get_examined_damage_string() + if(length(desc_damage)) + desc_comp += "[desc_damage]" + + if(paint_color) + var/decl/pronouns/obj_pronouns = get_pronouns() // so we can do 'have' for plural objects like sheets + desc_comp += "\The [src] [obj_pronouns.has] been [paint_verb]." + + var/added_header = FALSE + if(user?.get_preference_value(/datum/client_preference/inquisitive_examine) == PREF_ON) + + var/list/available_recipes = list() + for(var/decl/crafting_stage/initial_stage in SSfabrication.find_crafting_recipes(type)) + if(initial_stage.can_begin_with(src) && ispath(initial_stage.completion_trigger_type)) + available_recipes[initial_stage] = initial_stage.generate_completion_string() + + if(length(available_recipes)) + + if(!added_header) + added_header = TRUE + desc_comp += "*--------*" + + for(var/decl/crafting_stage/initial_stage in available_recipes) + desc_comp += SPAN_NOTICE("With [available_recipes[initial_stage]], you could start making \a [initial_stage.descriptor] out of this.") + desc_comp += "*--------*" + + if(distance <= 1 && has_extension(src, /datum/extension/loaded_cell)) + + if(!added_header) + added_header = TRUE + desc_comp += "*--------*" + + var/datum/extension/loaded_cell/cell_loaded = get_extension(src, /datum/extension/loaded_cell) + var/obj/item/cell/loaded_cell = cell_loaded?.get_cell() + var/obj/item/cell/current_cell = get_cell() + // Some items use the extension but may return something else to get_cell(). + // In these cases, don't print the removal info etc. + if(current_cell && current_cell != loaded_cell) + desc_comp += SPAN_NOTICE("\The [src] is using an external [current_cell.name] as a power supply.") + else + desc_comp += cell_loaded.get_examine_text(current_cell) + desc_comp += "*--------*" + + if(hasHUD(user, HUD_SCIENCE)) //Mob has a research scanner active. + + if(!added_header) + added_header = TRUE + desc_comp += "*--------*" + + if(origin_tech) + desc_comp += SPAN_NOTICE("Testing potentials:") + var/list/techlvls = cached_json_decode(origin_tech) + for(var/T in techlvls) + var/decl/research_field/field = SSfabrication.get_research_field_by_id(T) + desc_comp += "Tech: Level [techlvls[T]] [field.name]." + else + desc_comp += "No tech origins detected." + + if(LAZYLEN(matter)) + desc_comp += SPAN_NOTICE("Extractable materials:") + for(var/mat in matter) + var/decl/material/M = GET_DECL(mat) + desc_comp += "[capitalize(M.solid_name)]" + else + desc_comp += SPAN_DANGER("No extractable materials detected.") + desc_comp += "*--------*" + + if(drying_wetness > 0 && drying_wetness != initial(drying_wetness)) + desc_comp += "\The [src] is [get_dryness_text()]." + + if(REAGENT_TOTAL_VOLUME(coating)) + desc_comp += "It is covered in [coating.get_coated_name()]." // It is covered in dilute oily slimy bloody mud. + + if(check_rights(R_DEBUG, 0, user)) + desc_comp += "\The [src] has a temperature of [temperature]K." + + return ..(user, distance, "", jointext(desc_comp, "
              ")) + +/obj/item/check_mousedrop_adjacency(var/atom/over, var/mob/user) + . = (loc == user && istype(over, /obj/screen)) || ..() + +/obj/item/handle_mouse_drop(atom/over, mob/user, params) + + if(canremove && (ishuman(user) || isrobot(user) || isanimal(user)) && !user.incapacitated(INCAPACITATION_DISRUPTED) && over == user && storage) + storage.open(user) + return TRUE + + if(over == user) + usr.face_atom(src) + dragged_onto(over) + return TRUE + + // Allow dragging items onto/around tables and racks. + if(istype(over, /obj/structure)) + var/obj/structure/struct = over + if(struct.structure_flags & STRUCTURE_FLAG_SURFACE) + if(user == loc && !user.try_unequip(src, get_turf(user))) + return TRUE + if(!isturf(loc)) + return TRUE + var/list/click_data = params2list(params) + do_visual_slide(src, get_turf(src), pixel_x, pixel_y, get_turf(over), text2num(click_data["icon-x"])-1, text2num(click_data["icon-y"])-1, center_of_mass && cached_json_decode(center_of_mass)) + return TRUE + + // Try to drag-equip the item. + var/obj/screen/inventory/inv = over + if(user.client && istype(inv) && inv.slot_id && (over in user.client.screen)) + // Remove the item from our bag if necessary. + if(istype(loc?.storage)) + if(!loc.storage.remove_from_storage(user, src)) + return ..() + dropInto(get_turf(loc)) + // Otherwise remove it from our inventory if necessary. + else if(ismob(loc)) + var/mob/M = loc + if(!M.try_unequip(src, get_turf(src))) + return ..() + // Equip to the slot we dragged over. + if(isturf(loc) && mob_can_equip(user, inv.slot_id, disable_warning = TRUE)) + add_fingerprint(user) + user.equip_to_slot_if_possible(src, inv.slot_id) + return TRUE + + + . = ..() + +/obj/item/proc/dragged_onto(var/mob/user) + return attack_hand_with_interaction_checks(user) + +/obj/item/proc/can_heat_atom(atom/other) + return get_heat() > 0 && isflamesource() + +/obj/item/afterattack(var/atom/A, var/mob/user, var/proximity) + . = ..() + if(!. && proximity && !ismob(A) && can_heat_atom(A)) + A.handle_external_heating(get_heat(), src, user) + return TRUE + return FALSE + +/obj/item/can_interact_with_storage(user, strict = FALSE) + return ..() && (!strict || loc == user) + +/obj/item/proc/squash_item(skip_qdel = FALSE) + if(!istype(material) || material.hardness > MAT_VALUE_MALLEABLE) + return null + var/list/results = convert_matter_to_lumps(skip_qdel) + if(length(results)) + . = results + if(!skip_qdel) + matter = null + material = null + qdel(src) + return . || TRUE + +/obj/item/attack_self(mob/user) + if(user.check_intent(I_FLAG_HARM) && istype(material)) + var/list/results = squash_item(skip_qdel = TRUE) + if(results && user.try_unequip(src, user.loc)) + user.visible_message(SPAN_DANGER("\The [user] squashes \the [src] into a lump.")) + if(islist(results)) + for(var/obj/item/thing in results) + user.put_in_hands(thing) + matter = null + material = null + qdel(src) + return TRUE + return ..() + +/obj/item/end_throw(datum/thrownthing/TT) + . = ..() + squash_item() + +/// Whether this item can be picked up. +/// Primarily exists to be overridden to prevent, e.g. accessories from being removed by clicking on them while worn. +/obj/item/proc/can_be_picked_up(mob/user) + return !anchored + +/obj/item/attack_hand(mob/user) + + . = ..() + if(.) + return + + if(!can_be_picked_up(user)) + return ..() + + if(!user.check_dexterity(DEXTERITY_EQUIP_ITEM, silent = TRUE)) + if(user.check_dexterity(DEXTERITY_HOLD_ITEM, silent = TRUE)) + if(loc == user) + to_chat(user, SPAN_NOTICE("You begin trying to remove \the [src]...")) + if(do_after(user, 3 SECONDS, src) && user.try_unequip(src)) + user.drop_from_inventory(src) + else + to_chat(user, SPAN_WARNING("You fail to remove \the [src]!")) + return TRUE + if(isturf(loc)) + if(loc == get_turf(user)) + attack_self(user) + else + dropInto(get_turf(user)) + return TRUE + if(loc?.storage?.remove_from_storage(user, src)) + visible_message(SPAN_NOTICE("\The [user] fumbles \the [src] out of \the [loc].")) + dropInto(get_turf(loc)) + return TRUE + to_chat(user, SPAN_WARNING("You are not dexterous enough to pick up \the [src].")) + return TRUE + + var/old_loc = loc + if(loc?.storage) + loc.storage.remove_from_storage(user, src) + + if(!QDELETED(throwing)) + throwing.finalize(hit=TRUE) + + if(has_extension(src, /datum/extension/loaded_cell) && user.is_holding_offhand(src)) + var/datum/extension/loaded_cell/cell_handler = get_extension(src, /datum/extension/loaded_cell) + if(cell_handler.try_unload(user)) + return TRUE + + if(loc == user) + if(!user.try_unequip(src)) + return TRUE + else if(isliving(loc)) + return TRUE + + if(!QDELETED(src) && user.put_in_active_hand(src)) + if (isturf(old_loc)) + var/obj/effect/temporary/item_pickup_ghost/ghost = new(old_loc, src) + ghost.animate_towards(user) + on_picked_up(user, old_loc) + return TRUE + + return FALSE + +/obj/item/attack_ai(mob/living/silicon/ai/user) + if (!istype(loc, /obj/item/robot_module)) + return + //If the item is part of a cyborg module, equip it + if(!isrobot(user)) + return + var/mob/living/silicon/robot/robot = user + robot.put_in_hands(src) + +/obj/item/proc/try_slapcrafting(obj/item/used_item, mob/user) + if(SSfabrication.try_craft_with(src, used_item, user)) + return TRUE + if(SSfabrication.try_craft_with(used_item, src, user)) + return TRUE + return FALSE + +/obj/item/proc/user_can_attack_with(mob/user, atom/target, silent = FALSE) + return user.check_dexterity(get_required_attack_dexterity(user, target), silent = silent) + +/obj/item/attackby(obj/item/used_item, mob/user) + // if can_wield is false we still need to call parent for storage objects to work properly + var/can_wield = used_item.user_can_attack_with(user, silent = TRUE) + + if(can_wield && try_slapcrafting(used_item, user)) + return TRUE + + if(used_item.storage?.use_to_pickup && isturf(src.loc)) + //Mode is set to collect all items + if(used_item.storage.collection_mode) + used_item.storage.gather_all(src.loc, user) + return TRUE + if(used_item.storage.can_be_inserted(src, user)) + used_item.storage.handle_item_insertion(user, src) + return TRUE + + if(can_wield && has_extension(src, /datum/extension/loaded_cell)) + var/datum/extension/loaded_cell/cell_loaded = get_extension(src, /datum/extension/loaded_cell) + if(cell_loaded.has_tool_unload_interaction(used_item)) + return cell_loaded.try_unload(user, used_item) + else if(istype(used_item, /obj/item/cell)) + return cell_loaded.try_load(user, used_item) + + return ..() + +/obj/item/proc/talk_into(mob/living/M, message, message_mode, var/verb = "says", var/decl/language/speaking = null) + return + +// apparently called whenever an item is removed from a slot, container, or anything else. +/obj/item/proc/dropped(var/mob/user, var/play_dropsound = TRUE) + + SHOULD_CALL_PARENT(TRUE) + + if(QDELETED(src)) + return + + if(randpixel) + pixel_z = randpixel //an idea borrowed from some of the older pixel_y randomizations. Intended to make items appear to drop at a character + update_twohanding() + for(var/obj/item/thing in user?.get_held_items()) + thing.update_twohanding() + if(play_dropsound && drop_sound && SSticker.mode) + addtimer(CALLBACK(src, PROC_REF(dropped_sound_callback)), 0, (TIMER_OVERRIDE | TIMER_UNIQUE)) + + if(user && (z_flags & ZMM_MANGLE_PLANES)) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob, check_emissive_equipment)), 0, TIMER_UNIQUE) + + RAISE_EVENT(/decl/observ/mob_unequipped, user, src) + RAISE_EVENT(/decl/observ/item_unequipped, src, user) + +// called just after an item is picked up, after it has been equipped to the mob. +/obj/item/proc/on_picked_up(mob/user, atom/old_loc) + if(old_loc == loc || old_loc == user) + // not being picked up, just transferring between slots, don't adjust the offset + return + if(randpixel) + pixel_x = rand(-randpixel, randpixel) + pixel_y = rand(-randpixel/2, randpixel/2) + pixel_z = 0 + else if(randpixel == 0) + pixel_x = 0 + pixel_y = 0 + +// called when this item is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. +/obj/item/proc/on_exit_storage(datum/storage/S) + return + +// called when this item is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. +/obj/item/proc/on_enter_storage(datum/storage/S) + return + +// called when "found" in pockets and storage items. Returns 1 if the search should end. +/obj/item/proc/on_found(mob/finder) + return + +// called after an item is placed in an equipment slot +// user is mob that equipped it +// slot uses the slot_X defines found in setup.dm +// for items that can be placed in multiple slots +// note this isn't called during the initial dressing of a player +/obj/item/proc/equipped(var/mob/user, var/slot) + + SHOULD_CALL_PARENT(TRUE) + + if(QDELETED(src)) + return + + // Clear our alpha mask. + update_turf_alpha_mask() + + add_fingerprint(user) + + hud_layerise() + addtimer(CALLBACK(src, PROC_REF(reconsider_client_screen_presence), user.client, slot), 0) + + //Update two-handing status + var/mob/M = loc + if(istype(M)) + for(var/obj/item/held in M.get_held_items()) + held.update_twohanding() + + if(user) + if(SSticker.mode) + if(pickup_sound && (slot in user.get_held_item_slots())) + addtimer(CALLBACK(src, PROC_REF(pickup_sound_callback)), 0, (TIMER_OVERRIDE | TIMER_UNIQUE)) + else if(equip_sound) + addtimer(CALLBACK(src, PROC_REF(equipped_sound_callback)), 0, (TIMER_OVERRIDE | TIMER_UNIQUE)) + if(z_flags & ZMM_MANGLE_PLANES) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob, check_emissive_equipment)), 0, TIMER_UNIQUE) + + RAISE_EVENT(/decl/observ/mob_equipped, user, src, slot) + RAISE_EVENT(/decl/observ/item_equipped, src, user, slot) + +// As above but for items being equipped to an active module on a robot. +/obj/item/proc/equipped_robot(var/mob/user) + return + +//the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't. +//Set disable_warning to 1 if you wish it to not give you outputs. +//Set ignore_equipped to 1 if you wish to ignore covering checks etc. when this item is already equipped. +/obj/item/proc/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) + if(!slot || !user) + return FALSE + + // Putting stuff into backpacks. + if(slot == slot_in_backpack_str) + var/obj/item/back = user.get_equipped_item(slot_back_str) + return back?.storage?.can_be_inserted(src, user, TRUE) + if(slot == slot_in_wallet_str) + var/obj/item/wallet = user.get_equipped_item(slot_wear_id_str) + return wallet?.storage?.can_be_inserted(src, user, TRUE) + + var/datum/inventory_slot/inv_slot = user.get_inventory_slot_datum(slot) + if(!inv_slot) + return FALSE + + if(!force) + if(!ignore_equipped && !inv_slot.is_accessible(user, src, disable_warning)) + return FALSE + + if(!inv_slot.can_equip_to_slot(user, src, disable_warning, ignore_equipped)) + return FALSE + + return TRUE + +/obj/item/proc/mob_can_unequip(mob/user, slot, disable_warning = FALSE, dropping = FALSE) + if(!slot || !user || !canremove) + return FALSE + var/datum/inventory_slot/inv_slot = user.get_inventory_slot_datum(slot) + return inv_slot?.is_accessible(user, src, disable_warning) + +/obj/item/proc/can_be_dropped_by_client(mob/M) + return M.can_unequip_item(src) + +/obj/item/verb/verb_pickup() + set src in oview(1) + set category = "Object" + set name = "Pick up" + + if(!CanPhysicallyInteract(usr) || !ishuman(usr) || !isturf(loc) || !simulated) + return + if(usr.incapacitated() || usr.restrained()) + to_chat(usr, SPAN_WARNING("You cannot pick up \the [src] at the moment.")) + return + if(anchored) + to_chat(usr, SPAN_WARNING("\The [src] won't budge.")) + return + if(!usr.get_empty_hand_slot()) + to_chat(usr, SPAN_WARNING("Your hands are full.")) + return + usr.UnarmedAttack(src, usr.Adjacent(src)) + +//This proc is executed when someone clicks the on-screen UI button. To make the UI button show, set the 'icon_action_button' to the icon_state of the image of the button in screen1_action.dmi +//The default action is attack_self(). +//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob. +/obj/item/proc/ui_action_click() + attack_self(usr) + +//RETURN VALUES +//handle_shield should return a positive value to indicate that the attack is blocked and should be prevented. +//If a negative value is returned, it should be treated as a special return value for bullet_act() and handled appropriately. +//For non-projectile attacks this usually means the attack is blocked. +//Otherwise should return FALSE to indicate that the attack is not affected in any way. +/obj/item/proc/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + var/parry_chance = get_parry_chance(user) + if(attacker) + parry_chance = max(0, parry_chance - 10 * attacker.get_skill_difference(SKILL_COMBAT, user)) + if(parry_chance) + if(default_parry_check(user, attacker, damage_source) && prob(parry_chance)) + user.visible_message(SPAN_DANGER("\The [user] parries [attack_text] with \the [src]!")) + playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) + on_parry(user, damage_source, attacker) + return TRUE + return FALSE + +/obj/item/proc/on_parry(mob/user, damage_source, mob/attacker) + return + +/obj/item/proc/get_parry_chance(mob/user) + . = base_parry_chance + if(user) + if(base_parry_chance || user.skill_check(SKILL_COMBAT, SKILL_ADEPT)) + . += 10 * (user.get_skill_value(SKILL_COMBAT) - SKILL_BASIC) + if(is_held_twohanded()) + . += wielded_parry_bonus + +/// Occurs when a disarm attempt fails a skill check, resulting in the attacker being damaged. +/// Return TRUE to block further checks for other objects. +/obj/item/proc/on_disarm_attempt(mob/target, mob/living/attacker) + var/force = get_attack_force(attacker) + if(force < 1) + return FALSE + if(!istype(attacker)) + return FALSE + var/decl/pronouns/pronouns = attacker.get_pronouns() + attacker.apply_damage(force, atom_damage_type, attacker.get_active_held_item_slot(), used_weapon = src) + attacker.visible_message(SPAN_DANGER("\The [attacker] hurts [pronouns.his] hand on \the [src]!")) + playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + playsound(target, hitsound, 50, 1, -1) + return TRUE + +/obj/item/reveal_blood() + if(was_bloodied && !fluorescent) + fluorescent = FLUORESCENT_GLOWS + blood_color = COLOR_LUMINOL + coating_overlay.color = COLOR_LUMINOL + update_icon() + +/obj/item/add_blood(mob/living/M, amount = 2, list/blood_data) + if (!..()) + return FALSE + if(istype(src, /obj/item/energy_blade)) + return + if(!istype(M)) + return TRUE + if(!blood_data && ishuman(M)) + var/mob/living/human/H = M + blood_data = REAGENT_DATA(H.vessel, /decl/material/liquid/blood) + var/sample_dna = LAZYACCESS(blood_data, DATA_BLOOD_DNA) + if(sample_dna) + var/datum/extension/forensic_evidence/forensics = get_or_create_extension(src, /datum/extension/forensic_evidence) + forensics.add_data(/datum/forensics/blood_dna, sample_dna) + add_coating(/decl/material/liquid/blood, amount, blood_data) + var/unique_enzymes = M.get_unique_enzymes() + var/blood_type = M.get_blood_type() + if(unique_enzymes && blood_type && !LAZYACCESS(blood_DNA, unique_enzymes)) + LAZYSET(blood_DNA, unique_enzymes, blood_type) + return TRUE + +var/global/list/icon/_coating_overlay_cache = list() +var/global/icon/_item_coating_mask = icon('icons/effects/blood.dmi', "itemblood") +/obj/item/proc/generate_coating_overlay(force = FALSE) + if(coating_overlay && !force) + return + var/cache_key = "\ref[icon]-[icon_state]" // this needs to use ref because of stringification + if(!global._coating_overlay_cache[cache_key]) + var/icon/I = new /icon(icon, icon_state) + I.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) // Sets the icon RGB channel to pure white. + I.Blend(global._item_coating_mask, ICON_MULTIPLY) // Masks the coating overlay against the generated mask. + global._coating_overlay_cache[cache_key] = I + coating_overlay = image(global._coating_overlay_cache[cache_key]) + coating_overlay.appearance_flags |= NO_CLIENT_COLOR|RESET_COLOR + +/obj/item/proc/showoff(mob/user) + for(var/mob/M in view(user)) + if(!user.is_invisible_to(M)) + M.show_message("[user] holds up [src]. Take a closer look.", 1) + +/* +For zooming with scope or binoculars. This is called from +modules/mob/mob_movement.dm if you move you will be zoomed out +modules/mob/living/human/life.dm if you die, you will be zoomed out. +*/ +//Looking through a scope or binoculars should /not/ improve your periphereal vision. Still, increase viewsize a tiny bit so that sniping isn't as restricted to NSEW +/obj/item/proc/zoom(mob/user, var/tileoffset = 14,var/viewsize = 9) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view + if(!user.client) + return + if(zoom) + return + + var/devicename = zoomdevicename || name + + var/mob/living/human/H = user + if(user.incapacitated(INCAPACITATION_DISABLED)) + to_chat(user, SPAN_WARNING("You are unable to focus through the [devicename].")) + return + else if(!zoom && istype(H) && H.equipment_tint_total >= TINT_MODERATE) + to_chat(user, SPAN_WARNING("Your visor gets in the way of looking through the [devicename].")) + return + else if(!zoom && user.get_active_held_item() != src) + to_chat(user, SPAN_WARNING("You are too distracted to look through the [devicename], perhaps if it was in your active hand this might work better.")) + return + + if(!istype(user.hud_used)) + return + + if(user.hud_used.is_hud_shown()) + user.toggle_zoom_hud() // If the user has already limited their HUD this avoids them having a HUD when they zoom in + user.client.view = viewsize + zoom = TRUE + + var/viewoffset = WORLD_ICON_SIZE * tileoffset + switch(user.dir) + if (NORTH) + user.client.pixel_x = 0 + user.client.pixel_y = viewoffset + if (SOUTH) + user.client.pixel_x = 0 + user.client.pixel_y = -viewoffset + if (EAST) + user.client.pixel_x = viewoffset + user.client.pixel_y = 0 + if (WEST) + user.client.pixel_x = -viewoffset + user.client.pixel_y = 0 + + user.visible_message("\The [user] peers through [zoomdevicename ? "the [zoomdevicename] of [src]" : "[src]"].") + + events_repository.register(/decl/observ/destroyed, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + events_repository.register(/decl/observ/moved, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + events_repository.register(/decl/observ/dir_set, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + events_repository.register(/decl/observ/item_unequipped, src, src, TYPE_PROC_REF(/obj/item, zoom_drop)) + if(isliving(user)) + events_repository.register(/decl/observ/stat_set, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + +/obj/item/proc/zoom_drop(var/obj/item/I, var/mob/user) + unzoom(user) + +/obj/item/proc/unzoom(var/mob/user) + if(!zoom) + return + zoom = FALSE + + events_repository.unregister(/decl/observ/destroyed, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + events_repository.unregister(/decl/observ/moved, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + events_repository.unregister(/decl/observ/dir_set, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + events_repository.unregister(/decl/observ/item_unequipped, src, src, TYPE_PROC_REF(/obj/item, zoom_drop)) + if(isliving(user)) + events_repository.unregister(/decl/observ/stat_set, user, src, TYPE_PROC_REF(/obj/item, unzoom)) + + if(!user.client) + return + + user.client.view = world.view + if(istype(user.hud_used) && !user.hud_used.is_hud_shown()) + user.toggle_zoom_hud() + user.client.pixel_x = 0 + user.client.pixel_y = 0 + user.client.OnResize() + user.visible_message("[zoomdevicename ? "\The [user] looks up from [src]" : "\The [user] lowers [src]"].") + +/obj/item/proc/pwr_drain() + return 0 // Process Kill + +/obj/item/proc/get_examine_name() + var/examine_prefix = get_examine_prefix() + if(examine_prefix) + examine_prefix += " " + return ADD_ARTICLE_GENDER("[examine_prefix][name]", gender) + +/obj/item/proc/get_examine_line() + . = "[html_icon(src)] [get_examine_name()]" + var/ID = GetIdCard() + if(ID) + . += " \[Look at ID\]" + +/obj/item/proc/on_active_hand() + return + +/obj/item/proc/has_embedded(mob/living/victim) + if(istype(victim)) + LAZYDISTINCTADD(victim.embedded, src) + victim.verbs |= /mob/proc/yank_out_object + return TRUE + return FALSE + +/obj/item/proc/get_pressure_weakness(pressure,zone) + . = 1 + if(pressure > ONE_ATMOSPHERE) + if(max_pressure_protection != null) + if(max_pressure_protection < pressure) + return min(1, round((pressure - max_pressure_protection) / max_pressure_protection, 0.01)) + else + return 0 + if(pressure < ONE_ATMOSPHERE) + if(min_pressure_protection != null) + if(min_pressure_protection > pressure) + return min(1, round((min_pressure_protection - pressure) / min_pressure_protection, 0.01)) + else + return 0 + +/obj/item/do_simple_ranged_interaction(var/mob/user) + if(user) + attack_self(user) + return TRUE + +/obj/item/proc/inherit_custom_item_data(var/datum/custom_item/citem) + . = src + if(citem.item_name) + SetName(citem.item_name) + if(citem.item_desc) + desc = citem.item_desc + if(citem.item_icon) + icon = citem.item_icon + if(citem.item_state) + set_icon_state(citem.item_state) + +/obj/item/clothing/inherit_custom_item_data(var/datum/custom_item/citem) + . = ..() + reconsider_single_icon() + +/obj/item/proc/is_special_cutting_tool(var/high_power) + return FALSE + +/obj/item/proc/w_class_description() + switch(w_class) + if(ITEM_SIZE_TINY) + return "tiny" + if(ITEM_SIZE_SMALL) + return "small" + if(ITEM_SIZE_NORMAL) + return "normal-sized" + if(ITEM_SIZE_LARGE) + return "large" + if(ITEM_SIZE_HUGE) + return "bulky" + if(ITEM_SIZE_HUGE + 1 to INFINITY) + return "huge" + +/obj/item/proc/get_autopsy_descriptors() + var/list/descriptors = list() + descriptors += w_class_description() + if(is_sharp()) + descriptors += "sharp" + if(has_edge()) + descriptors += "edged" + if(get_attack_force() >= 10 && !is_sharp() && !has_edge()) + descriptors += "heavy" + if(material) + descriptors += "made of [material.solid_name]" + return descriptors + +/obj/item/proc/attack_message_name() + return "\a [src]" + +/obj/item/proc/add_coating(reagent_type, amount, data) + if(!coating) + coating = new /datum/reagents(10, src) + if(ispath(reagent_type)) + coating.add_reagent(reagent_type, amount, data) + else if(istype(reagent_type, /datum/reagents)) + var/datum/reagents/source = reagent_type + source.trans_to_holder(coating, amount) + if(!coating_overlay) + generate_coating_overlay() + coating_overlay.color = coating.get_color() + update_icon() + +/obj/item/proc/remove_coating(amount) + if(!coating) + return + coating.remove_any(amount) + if(REAGENT_TOTAL_VOLUME(coating) <= MINIMUM_CHEMICAL_VOLUME) + clean(FALSE) + +/obj/item/proc/transfer_coating_to(atom/target, amount = 1, multiplier = 1, copy = 0, defer_update = FALSE, transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) + if(!coating) + return + coating.trans_to(target, amount, multiplier) + if(REAGENT_TOTAL_VOLUME(coating) <= MINIMUM_CHEMICAL_VOLUME) + clean(FALSE) + +/obj/item/clean(clean_forensics=TRUE) + . = ..() + QDEL_NULL(coating) + coating_overlay = null + if(clean_forensics) + var/datum/extension/forensic_evidence/forensics = get_extension(src, /datum/extension/forensic_evidence) + if(forensics) + forensics.remove_data(/datum/forensics/trace_dna) + forensics.remove_data(/datum/forensics/blood_dna) + forensics.remove_data(/datum/forensics/gunshot_residue) + update_icon() + update_clothing_icon() + +// Used to call appropriate slot updates in update_clothing_icon() +/obj/item/proc/get_associated_equipment_slots() + SHOULD_CALL_PARENT(TRUE) + if(item_flags & ITEM_FLAG_IS_BELT) + LAZYADD(., slot_belt_str) + + // Where are we usually worn? + var/default_slot = get_fallback_slot() + if(default_slot) + LAZYDISTINCTADD(., default_slot) + // Uniforms can show or hide ID. + if(default_slot == slot_w_uniform_str) + LAZYDISTINCTADD(., slot_wear_id_str) + + // Currently this proc is used for clothing updates, so we + // need to care what slot we are being worn in, if any. + if(ismob(loc)) + var/mob/wearer = loc + var/equipped_slot = wearer.get_equipped_slot_for_item(src) + if(equipped_slot) + LAZYDISTINCTADD(., equipped_slot) + +// Updates the icons of the mob wearing the clothing item, if any. +/obj/item/proc/update_clothing_icon(do_update_icon = TRUE) + + // Accessories should pass this back to their holder. + if(isitem(loc)) + var/obj/item/holder = loc + return holder.update_clothing_icon(do_update_icon) + + // If we're not on a mob, we do not care. + if(!ismob(loc)) + return FALSE + + // We refresh our equipped slot and any associated slots that might depend on the state of this slot. + var/mob/wearer = loc + for(var/equipped_slot in get_associated_equipment_slots()) + wearer.update_equipment_overlay(equipped_slot, FALSE) + if(do_update_icon) + wearer.lazy_update_icon() + return TRUE + +/obj/item/proc/reconsider_client_screen_presence(var/client/client, var/slot) + if(!client) + return + if(client.mob?.get_equipped_item(slot) != src) + return + if(client.mob?.item_should_have_screen_presence(src, slot)) + client.screen |= src + else + client.screen -= src + +/obj/item/proc/get_assembly_detail_color() + return + +/obj/item/singularity_pull(S, current_size) + set waitfor = FALSE + if(!simulated || anchored) + return + sleep(0) //this is needed or multiple items will be thrown sequentially and not simultaneously + if(current_size >= STAGE_FOUR) + //throw_at(S, 14, 3) + step_towards(src,S) + sleep(1) + step_towards(src,S) + else if(current_size > STAGE_ONE) + step_towards(src,S) + else ..() + +// Supplied during loadout gear tweaking. +/obj/item/proc/set_custom_name(var/new_name) + base_name = new_name + material_alteration &= ~MAT_FLAG_ALTERATION_NAME + update_name() + +// Supplied during loadout gear tweaking. +/obj/item/proc/set_custom_desc(var/new_desc) + desc = new_desc + +/obj/item/proc/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + if(loaded_cell_type || accepted_cell_type) + set_extension(src, (power_supply_extension_type || /datum/extension/loaded_cell), (accepted_cell_type || loaded_cell_type), loaded_cell_type, charge_value) + +/obj/item/proc/handle_loadout_equip_replacement(obj/item/old_item) + return + +/// Used to handle equipped items overwritten by custom loadout. +/// Returns one of LOADOUT_CONFLICT_DELETE, LOADOUT_CONFLICT_STORAGE, or LOADOUT_CONFLICT_KEEP. +/obj/item/proc/loadout_should_keep(obj/item/new_item, mob/wearer) + if(type == new_item.type) // for exact type collisions, just delete by default + return LOADOUT_CONFLICT_DELETE + return replaced_in_loadout + +/obj/item/dropped(mob/user, slot) + . = ..() + user?.clear_available_intents() + +/obj/item/equipped(mob/user, slot) + . = ..() + user?.clear_available_intents() + // delay for 1ds to allow the rest of the call stack to resolve + if(!QDELETED(src) && !QDELETED(user) && user.get_equipped_slot_for_item(src) == slot) + try_burn_wearer(user, slot, 1) + +/obj/item/can_embed() + . = !anchored && (!ismob(loc) || canremove) && (!loc || isturf(loc) || ismob(loc)) && !is_robot_module(src) + if(. && isliving(loc)) + var/mob/living/holder = loc + // Terrible check for if the mob is being driven by an AI or not. + // AI can't retrieve the weapon currently so this is unfair. + if(holder.get_attack_telegraph_delay() > 0) + return FALSE + // Skill check to avoid getting it stuck. + return holder.skill_fail_prob(SKILL_COMBAT, 100, no_more_fail = SKILL_EXPERT) + +/obj/item/clear_matter() + ..() + material = null + +/obj/item/proc/has_textile_fibers() + return FALSE + +// Returns a value used as a multiplier in the fishing delay calc. Higher represents a stronger reduction in fishing time. +#define BAIT_VALUE_CONSTANT 0.1 +/obj/item/proc/get_bait_value() + . = 0 + for(var/mat in matter) + var/decl/material/bait_mat = GET_DECL(mat) + if(bait_mat.fishing_bait_value) + . += MATERIAL_UNITS_TO_REAGENTS_UNITS(matter[mat]) * bait_mat.fishing_bait_value * BAIT_VALUE_CONSTANT + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.fishing_bait_value) + . += REAGENT_VOLUME(reagents, reagent) * reagent.fishing_bait_value * BAIT_VALUE_CONSTANT +#undef BAIT_VALUE_CONSTANT + +/obj/item/proc/get_storage_cost() + //If you want to prevent stuff above a certain w_class from being stored, use max_w_class + return BASE_STORAGE_COST(w_class) + +/obj/item/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() || storage?.scoop_inside(dropping, user) + +/obj/item/proc/toggle_gathering_mode() + set name = "Switch Gathering Method" + set category = "Object" + if(!storage) + verbs -= /obj/item/proc/toggle_gathering_mode + return + storage.collection_mode = !storage.collection_mode + switch (storage.collection_mode) + if(TRUE) + to_chat(usr, "\The [src] now picks up all items in a tile at once.") + if(FALSE) + to_chat(usr, "\The [src] now picks up one item at a time.") + +/obj/item/proc/quick_empty() + set name = "Empty Contents" + set category = "Object" + if(!storage) + verbs -= /obj/item/proc/quick_empty + return + if((!ishuman(usr) && (loc != usr)) || usr.stat || usr.restrained()) + return + storage.quick_empty(usr, get_turf(src)) + +/obj/item/attack_self(mob/user) + //Clicking on itself will empty it, if it has the verb to do that. + if(user.get_active_held_item() == src && storage?.allow_quick_empty) + quick_empty() + return TRUE + return ..() + +/obj/item/proc/loadout_setup(mob/wearer, metadata) + return + +/obj/item/proc/setup_sprite_sheets() + return + +/obj/item/proc/get_equipment_tint() + return TINT_NONE + +/obj/item/proc/get_preview_screen_locs() + return + +/obj/item/proc/get_stance_support_value() + return 0 + +/obj/item/is_watertight() + return watertight || ..() + +// TODO: merge beakers etc down into this proc. +/// @params: +/// - state_prefix as text: if non-null, this string is prepended to the reagent overlay state, typically world/inventory/etc +/// @returns: +/// - reagent_overlay as /image|null - the overlay image representing the reagents in this object +/obj/item/proc/get_reagents_overlay(state_prefix) + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + return + var/decl/material/primary_reagent = reagents.get_primary_reagent_decl() + if(!primary_reagent) + return + var/reagents_state + if(primary_reagent.reagent_overlay_base) + reagents_state = primary_reagent.reagent_overlay_base + else + reagents_state = "reagent_base" + if(state_prefix) + reagents_state = "[state_prefix]_[reagents_state]" // prepend world, inventory, or slot + if(!reagents_state || !check_state_in_icon(reagents_state, icon)) + return + var/image/reagent_overlay = overlay_image(icon, reagents_state, reagents.get_color(), RESET_COLOR | RESET_ALPHA) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(!reagent.reagent_overlay) + continue + var/modified_reagent_overlay = state_prefix ? "[state_prefix]_[reagent.reagent_overlay]" : reagent.reagent_overlay + if(!check_state_in_icon(modified_reagent_overlay, icon)) + continue + reagent_overlay.overlays += overlay_image(icon, modified_reagent_overlay, reagent.get_reagent_overlay_color(reagents), RESET_COLOR | RESET_ALPHA) + return reagent_overlay + +/obj/item/on_reagent_change() + . = ..() + // You can't put liquids in clay/sand/dirt vessels, sorry. + if(REAGENT_TOTAL_LIQUID_VOLUME(reagents) > 0 && material && material.hardness <= MAT_VALUE_MALLEABLE && !QDELETED(src)) + visible_message(SPAN_DANGER("\The [src] falls apart!")) + squash_item() + if(!QDELETED(src)) + physically_destroyed() + +/obj/item/proc/get_provided_intents(mob/wielder) + return null + +/obj/item/get_examine_prefix() + if(REAGENT_TOTAL_VOLUME(coating)) + var/coating_string = coating.get_coated_adjectives() // component coloring is handled in here + if(get_config_value(/decl/config/enum/colored_coating_names) == CONFIG_COATING_COLOR_MIXTURE) + coating_string = FONT_COLORED(coating.get_color(), coating_string) + return coating_string + return ..() + +// Bespoke proc for handling when a centrifuge smooshes us, only currently used by growns and hive frames. +/obj/item/proc/handle_centrifuge_process(obj/machinery/centrifuge/centrifuge) + SHOULD_CALL_PARENT(TRUE) + return istype(centrifuge) && !QDELETED(centrifuge.loaded_beaker) && istype(centrifuge.loaded_beaker) + +/obj/item/proc/convert_matter_to_lumps(skip_qdel = FALSE) + + var/list/scrap_matter = list() + for(var/mat in matter) + var/mat_amount = matter[mat] + var/obj/item/stack/material/mat_stack = /obj/item/stack/material/lump + var/mat_per_stack = SHEET_MATERIAL_AMOUNT * initial(mat_stack.matter_multiplier) + var/sheet_amount = round(mat_amount / mat_per_stack) + if(sheet_amount) + var/obj/item/stack/material/lump/lump = new(loc, sheet_amount, mat) + LAZYADD(., lump) + mat_amount -= sheet_amount * mat_per_stack + if(mat_amount) + scrap_matter[mat] += mat_amount + + if(length(scrap_matter)) + var/obj/item/debris/scraps/scraps = new(loc) + scraps.matter = scrap_matter.Copy() + scraps.update_primary_material() + LAZYADD(., scraps) + + matter = null + material = null + if(!skip_qdel) + qdel(src) + +/obj/item/proc/pick_attack_verb() + return DEFAULTPICK(attack_verb, attack_verb) || "attacked" // if it's not a list, return itself or just "attacked" \ No newline at end of file diff --git a/code/game/objects/items/_item_damage.dm b/code/game/objects/items/_item_damage.dm new file mode 100644 index 000000000000..f63e42bcd930 --- /dev/null +++ b/code/game/objects/items/_item_damage.dm @@ -0,0 +1,139 @@ +/**Basic damage handling for items. Returns the amount of damage taken after armor if the item was damaged.*/ +/obj/item/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(!can_take_damage()) // This object does not take damage. + return 0 //Must return a number + if(damage < 0) + CRASH("Item '[type]' take_damage proc was called with negative damage.") //Negative damage are an implementation issue. + + //Apply armor + var/datum/extension/armor/A = get_extension(src, /datum/extension/armor) + if(A) + var/list/dam_after_armor = A.apply_damage_modifications(damage, damage_type, damage_flags, null, armor_pen, TRUE) + damage = dam_after_armor[1] + damage_type = dam_after_armor[2] + damage_flags = dam_after_armor[3] + armor_pen = dam_after_armor[5] + + if(damage <= 0) + return 0 //must return a number + + //Apply damage + damage = min(current_health, damage) + current_health = clamp(current_health - damage, 0, get_max_health()) + check_health(damage, damage_type, damage_flags) + return damage + +/obj/item/lava_act() + if(QDELETED(src)) + return TRUE + . = (!throwing) ? ..() : FALSE + +// We only do this for the extension as other stuff that overrides get_cell() handles EMP in an override. +/obj/item/emp_act(var/severity) + // we do not use get_cell() here as some devices may return a non-extension cell + var/datum/extension/loaded_cell/cell_loaded = get_extension(src, /datum/extension/loaded_cell) + var/obj/item/cell/cell = cell_loaded?.get_cell() + for(var/obj/O in contents) + if(O == cell) + continue + O.emp_act(severity) + if(cell) + cell.emp_act(severity) + update_icon() + return ..() + +/obj/item/explosion_act(severity) + if(QDELETED(src)) + return + . = ..() + take_damage(explosion_severity_damage(severity), BURN, DAM_EXPLODE | DAM_DISPERSED, "explosion") + +/obj/item/bash(obj/item/weapon, mob/user) + . = ..() + var/force = weapon.expend_attack_force(user) + if(force >= 3 && .) + user.setClickCooldown(weapon.attack_cooldown + weapon.w_class) + take_damage(force, weapon.atom_damage_type) + +/obj/item/proc/explosion_severity_damage(var/severity) + var/mult = explosion_severity_damage_multiplier() + return (mult * (4 - severity)) + (severity != 1? rand(-(mult / severity), (mult / severity)) : 0 ) + +/obj/item/proc/explosion_severity_damage_multiplier() + return ceil(get_max_health() / 3) + +/obj/item/is_burnable() + return simulated + +/obj/item/proc/get_volume_by_throwforce_and_or_w_class() + var/thrown_force = get_thrown_attack_force() + if(thrown_force && w_class) + return clamp((thrown_force + w_class) * 5, 30, 100)// Add the item's thrown force to its weight class and multiply by 5, then clamp the value between 30 and 100 + else if(w_class) + return clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100 + else + return 0 + +/obj/item/throw_impact(atom/hit_atom, datum/thrownthing/TT) + . = ..() + if(isliving(hit_atom)) //Living mobs handle hit sounds differently. + var/impact_volume = get_volume_by_throwforce_and_or_w_class() + if (get_thrown_attack_force() > 0) + if(hitsound) + playsound(hit_atom, hitsound, impact_volume, TRUE, -1) + else + playsound(hit_atom, 'sound/weapons/genhit.ogg', impact_volume, TRUE, -1) + else + playsound(hit_atom, 'sound/weapons/throwtap.ogg', impact_volume, TRUE, -1) + +/obj/item/proc/eyestab(mob/living/M, mob/living/user) + var/mob/living/human/H = M + if(istype(H)) + for(var/slot in global.standard_headgear_slots) + var/obj/item/protection = H.get_equipped_item(slot) + if(istype(protection) && (protection.body_parts_covered & SLOT_EYES)) + // you can't stab someone in the eyes wearing a mask! + to_chat(user, SPAN_WARNING("You're going to need to remove the eye covering first.")) + return TRUE + + if(!M.check_has_eyes()) + to_chat(user, SPAN_WARNING("You cannot locate any eyes on [M]!")) + return TRUE + + admin_attack_log(user, M, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(M) + src.add_fingerprint(user) + + if(istype(H)) + if(H != user) + M.visible_message( + SPAN_DANGER("\The [M] has been stabbed in the eye with \the [src] by \the [user]!"), + self_message = SPAN_DANGER("You stab \the [M] in the eye with \the [src]!")) + else + user.visible_message( + SPAN_DANGER("\The [user] has stabbed themself with \the [src]!"), + self_message = SPAN_DANGER("You stab yourself in the eyes with \the [src]!")) + + var/obj/item/organ/internal/eyes = GET_INTERNAL_ORGAN(H, BP_EYES) + eyes.adjust_organ_damage(rand(3,4)) + if(eyes.get_organ_damage() >= eyes.min_bruised_damage) + if(M.stat != DEAD) + if(!BP_IS_PROSTHETIC(eyes)) //robot eyes bleeding might be a bit silly + to_chat(M, SPAN_DANGER("Your eyes start to bleed profusely!")) + if(prob(50)) + if(M.stat != DEAD) + to_chat(M, SPAN_WARNING("You drop what you're holding and clutch at your eyes!")) + M.drop_held_items() + SET_STATUS_MAX(M, STAT_BLURRY, 10) + SET_STATUS_MAX(M, STAT_PARA, 1) + SET_STATUS_MAX(M, STAT_WEAK, 4) + if (eyes.get_organ_damage() >= eyes.min_broken_damage && M.stat != DEAD) + to_chat(M, SPAN_WARNING("You go blind!")) + + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(H, eyes.parent_organ) + affecting.take_damage(7) + else + M.take_organ_damage(7) + SET_STATUS_MAX(M, STAT_BLURRY, rand(3,4)) + return TRUE diff --git a/code/game/objects/items/_item_drying.dm b/code/game/objects/items/_item_drying.dm new file mode 100644 index 000000000000..5e69b30dd96f --- /dev/null +++ b/code/game/objects/items/_item_drying.dm @@ -0,0 +1,98 @@ +// Stubs/vars for use with the drying rack. +/obj/item + // Reduced when exposed to high temperatures or put on a drying rack. When hitting zero, the item transitions to a dried state. + var/drying_wetness + // Temperature threshold for fire_act() to dry the object, in degrees Kelvin. + var/drying_threshold_temperature = 500 + // If set to a type, drying this item will convert it to that type. + var/dried_type + // Set if colour should be passed to dried product. + var/dried_product_takes_color = TRUE + +/obj/item/proc/is_dryable() + return drying_wetness > 0 + +/obj/item/proc/get_dried_product() + return new dried_type(loc) + +/obj/item/stack/get_dried_product() + if(ispath(dried_type, /obj/item/stack)) + return new dried_type(loc, amount) + return ..() + +// Returns null for no change, or an instance for a successful drying. +/obj/item/proc/dry_out(var/obj/rack, var/drying_power = 1, var/fire_exposed = FALSE, var/silent = FALSE) + + if(!dried_type || !is_dryable()) + return + + if(drying_wetness > 0) + drying_wetness -= drying_power + if(drying_wetness > 0) + return + + var/obj/item/thing = get_dried_product() + if(!thing) + return + + if(color && dried_product_takes_color) + thing.color = color + if(isturf(loc) && !silent) + var/decl/pronouns/pronouns = get_pronouns() + visible_message(SPAN_NOTICE("\The [src] [pronouns.is] dry!")) + if(thing != src) + qdel(src) + return thing + +/obj/item/proc/get_max_drying_wetness() + return initial(drying_wetness) || drying_wetness || 1 + +// Returns a string used in drying rack examined_by(). +/obj/item/proc/get_dryness_text(var/obj/rack) + var/moistness = drying_wetness / get_max_drying_wetness() + if(moistness > 0.65) + return "wet" + if(moistness > 0.35) + return "damp" + if(moistness) + return "almost dry" + return "dry" + +// Returns an icon_state used by drying rack update_icon(). +/obj/item/proc/get_drying_overlay(var/obj/rack) + var/drying_state = get_drying_state(rack) + if(!drying_state || !color) + return drying_state + var/image/drying_overlay = image('icons/obj/drying_rack.dmi', drying_state) + drying_overlay.color = color + drying_overlay.alpha = alpha + drying_overlay.appearance_flags |= KEEP_APART | RESET_COLOR | RESET_ALPHA + return drying_overlay + +/obj/item/proc/get_drying_state(var/obj/rack) + return "generic" + +/obj/item/proc/should_take_heat_damage(datum/gas_mixture/air, exposed_temperature) + if(!can_take_damage()) + return FALSE + if(!length(matter)) + return FALSE + for(var/mat in matter) + var/decl/material/heated_material = GET_DECL(mat) + // We should burn if we're above the temperature damage threshold. + if(!isnull(heated_material.temperature_damage_threshold) && exposed_temperature >= heated_material.temperature_damage_threshold) + return TRUE + return FALSE + +/obj/item/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + + var/should_burn = should_take_heat_damage(air, exposed_temperature) + + if(exposed_temperature >= drying_threshold_temperature) + dry_out(drying_power = rand(2, 4), fire_exposed = TRUE, silent = TRUE) + should_burn &&= !is_dryable() // no fire damage if we're drying + + // Take fire damage if appropriate. + if(should_burn) + take_damage(rand(3,5), BURN) diff --git a/code/game/objects/items/_item_edibility.dm b/code/game/objects/items/_item_edibility.dm new file mode 100644 index 000000000000..ecf12a115591 --- /dev/null +++ b/code/game/objects/items/_item_edibility.dm @@ -0,0 +1,47 @@ +/obj/item/handle_eaten_by_mob(var/mob/user, var/mob/target) + . = ..() + if(. == EATEN_SUCCESS && !QDELETED(src)) + add_trace_DNA(target) + +// Used to get a piece of food from an item. +/obj/item/proc/separate_food_chunk(obj/item/utensil/utensil, mob/user) + var/utensil_food_type = get_utensil_food_type() + if(!istype(utensil) || !utensil_food_type) + return + var/remove_amt = min(REAGENT_TOTAL_VOLUME(reagents), get_food_default_transfer_amount(user)) + if(remove_amt) + + // Create a dummy copy of the target food item. + // This ensures we keep all food behavior, strings, sounds, etc. + utensil.loaded_food = new utensil_food_type(utensil, material?.type, TRUE) + if(ismovable(utensil.loaded_food.trash)) + qdel(utensil.loaded_food.trash) + utensil.loaded_food.trash = null // Unset it even if it didn't need deleting (e.g. it was a path) + if(ismovable(utensil.loaded_food.plate)) + qdel(utensil.loaded_food.plate) + utensil.loaded_food.plate = null + utensil.loaded_food.color = color + utensil.loaded_food.filling_color = get_food_filling_color() + utensil.loaded_food.SetName("\proper some [utensil.loaded_food.name]") + + // Pass over a portion of our reagents. + utensil.loaded_food.reagents.clear_reagents() + reagents.trans_to(utensil.loaded_food, remove_amt) + handle_chunk_separated() + if(!REAGENT_TOTAL_VOLUME(reagents)) + handle_consumed(user) // it's not actually being consumed, so i'm not sure this is correct + utensil.update_icon() + + else // This shouldn't happen, but who knows. + to_chat(user, SPAN_WARNING("None of \the [src] is left!")) + handle_consumed(user) + return TRUE + +/obj/item/proc/get_food_filling_color() + return color + +/obj/item/proc/get_utensil_food_type() + return + +/obj/item/proc/handle_chunk_separated() + return diff --git a/code/game/objects/items/_item_force.dm b/code/game/objects/items/_item_force.dm new file mode 100644 index 000000000000..500bec99069c --- /dev/null +++ b/code/game/objects/items/_item_force.dm @@ -0,0 +1,167 @@ +/obj/item + /// Tracking var for base attack value with material modifiers, to save recalculating 200 times. + VAR_PRIVATE/_cached_attack_force + /// Base force value; generally, the damage output if used one-handed by a medium mob (human) and made of steel. + VAR_PROTECTED/_base_attack_force = 5 + /// Multiplier to the base thrown force based on the material per above. + VAR_PROTECTED/_thrown_force_multiplier = 0.3 + /// Multiplier to total base damage from weapon and material if the weapon is wieldable and held in two hands. + VAR_PROTECTED/_wielded_force_multiplier = 1.25 + /// How much of our overall damage is influenced by material weight? + VAR_PROTECTED/_weight_force_factor = 0.25 + /// How much of our overall damage is influenced by material hardness? + VAR_PROTECTED/_hardness_force_factor = 0.25 + +/obj/item/proc/get_max_weapon_force() + . = get_attack_force() + if(can_be_twohanded) + . = round(. * _wielded_force_multiplier) + +/obj/item/proc/expend_attack_force(mob/living/user) + . = get_attack_force(user) + var/list/item_effects = get_item_effects(IE_CAT_DAMAGE) + if(length(item_effects)) + for(var/decl/item_effect/damage_effect as anything in item_effects) + damage_effect.expend_attack_use(src, user, item_effects[damage_effect]) + +/obj/item/proc/get_attack_force(mob/living/user) + if(_base_attack_force <= 0 || (item_flags & ITEM_FLAG_NO_BLUDGEON)) + return 0 + if(isnull(_cached_attack_force)) + update_attack_force() + if(_cached_attack_force <= 0) + return 0 + return istype(user) ? user.modify_attack_force(src, _cached_attack_force, _wielded_force_multiplier) : _cached_attack_force + +// Existing hitby() code expects mobs, structures and machines to be thrown, it seems. +/atom/movable/proc/get_thrown_attack_force() + return get_object_size() + +/obj/item/get_thrown_attack_force() + return round(expend_attack_force() * _thrown_force_multiplier) + +/obj/item/proc/get_base_attack_force() + return _base_attack_force + +/obj/item/proc/get_initial_base_attack_force() + return initial(_base_attack_force) + +/obj/item/proc/set_base_attack_force(new_force) + _cached_attack_force = null + _base_attack_force = new_force + +/obj/item/proc/update_attack_force() + + // Get our base force. + _cached_attack_force = get_base_attack_force() + if(_cached_attack_force <= 0 || !istype(material)) + _cached_attack_force = 0 + return _cached_attack_force + + // Check if this material is hard enough to hold an edge. + if(!material.can_hold_edge()) + set_edge(FALSE) + else if(!edge) + set_edge(initial(edge)) + + // Check if this material can hold a point. + if(!material.can_hold_sharpness()) + set_sharp(FALSE) + else if(!sharp) + set_sharp(initial(sharp)) + + // Work out where we're going to cap our calculated force. + // Any additional force resulting from hardness or weight turn into armour penetration. + var/accumulated_force = _cached_attack_force + var/weight_force_component = (_cached_attack_force * _weight_force_factor) + var/hardness_force_component = (_cached_attack_force * _hardness_force_factor) + var/expected_material_mod = (weight_force_component+hardness_force_component)/2 + var/expected_min_force = _cached_attack_force - expected_material_mod + var/expected_max_force = _cached_attack_force + expected_material_mod + + // Heavier weapons are generally going to be more effective, regardless of edge or sharpness. + // We don't factor in w_class or matter at this point, because we are assuming the base attack + // force was set already taking into account how effective this weapon should be. + var/relative_weight = (material.weight / MAT_VALUE_VERY_HEAVY) + if(obj_flags & OBJ_FLAG_HOLLOW) + relative_weight *= HOLLOW_OBJECT_MATTER_MULTIPLIER + accumulated_force += (weight_force_component * relative_weight) - (weight_force_component/2) + + // Apply hardness in the same way. + accumulated_force += (hardness_force_component * (material.hardness / MAT_VALUE_VERY_HARD)) - (hardness_force_component/2) + + // Round off our calculated attack force and turn any overflow into armour penetration. + _cached_attack_force = round(clamp(accumulated_force, expected_min_force, expected_max_force)) + + // Update our armor penetration. + armor_penetration = initial(armor_penetration) + if(accumulated_force > expected_max_force) + armor_penetration = armor_penetration+(accumulated_force-expected_max_force) + armor_penetration += 2 * max(0, material.brute_armor - 2) + armor_penetration = min(100, round(armor_penetration)) + + return _cached_attack_force + +// TODO: consider strength, athletics, mob size +// `dry_run` param used in grindstone modpack to avoid depleting sharpness on non-attacks. +/mob/living/proc/modify_attack_force(obj/item/weapon, supplied_force, wield_mult) + if(!istype(weapon) || !weapon.is_held_twohanded()) + . = supplied_force + else + . = supplied_force * wield_mult + var/list/item_effects = weapon.get_item_effects(IE_CAT_DAMAGE) + if(length(item_effects)) + for(var/decl/item_effect/damage_effect as anything in item_effects) + . = damage_effect.modify_attack_damage(., weapon, src, item_effects[damage_effect]) + return round(.) + +// Debug proc - leaving in for future work. Linter hates protected var access so leave commented. +/* +/client/verb/debug_dump_weapon_values() + set name = "Dump Weapon Values" + set category = "Debug" + set src = usr + + var/list/rows = list() + rows += jointext(list( + "Name", + "Type", + "Base Force", + "Calculated Force", + "Thrown Force", + "Min Force", + "Max Force", + "Wield force", + "Armour Pen", + "Sharp/Edge" + ), "|") + + for(var/thing in subtypesof(/obj/item)) + + var/obj/item/item = thing + if(!TYPE_IS_SPAWNABLE(item)) + continue + + item = new item + + var/attk_force = item.expend_attack_force() + var/expected_material_mod = ((attk_force * item._weight_force_factor) + (attk_force * item._hardness_force_factor))/2 + + rows += jointext(list( + item.name, + item.type, + item.get_base_attack_force(), + attk_force, + item.get_thrown_attack_force(), + (attk_force - expected_material_mod), + (attk_force + expected_material_mod), + (attk_force * item._wielded_force_multiplier), + item.armor_penetration, + (item.sharp|item.edge) + ), "|") + + text2file(jointext(rows, "\n"), "weapon_stats_dump.csv") + if(fexists("weapon_stats_dump.csv")) + ftp_to(usr, "weapon_stats_dump.csv", "weapon_stats_dump.csv") + to_chat(usr, "Done.") +*/ diff --git a/code/game/objects/items/_item_interactions.dm b/code/game/objects/items/_item_interactions.dm new file mode 100644 index 000000000000..6467b1d19d53 --- /dev/null +++ b/code/game/objects/items/_item_interactions.dm @@ -0,0 +1,43 @@ +/obj/item/get_alt_interactions(var/mob/user) + . = ..() + if(get_config_value(/decl/config/toggle/expanded_alt_interactions)) + LAZYADD(., list( + /decl/interaction_handler/pick_up, + /decl/interaction_handler/drop, + /decl/interaction_handler/use + )) + +/decl/interaction_handler/use + name = "Use" + expected_target_type = /obj/item + +/decl/interaction_handler/use/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/I = target + I.attack_self(user) + +/decl/interaction_handler/pick_up + name = "Pick Up" + expected_target_type = /obj/item + +/decl/interaction_handler/pick_up/invoked(atom/target, mob/user, obj/item/prop) + target.attack_hand_with_interaction_checks(user) + +/decl/interaction_handler/drop + name = "Drop" + expected_target_type = /obj/item + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEEDS_INVENTORY + +/decl/interaction_handler/drop/invoked(atom/target, mob/user, obj/item/prop) + user.try_unequip(target, user.loc) + +/decl/interaction_handler/storage_open + name = "Open Storage" + expected_target_type = /atom + incapacitation_flags = INCAPACITATION_DISRUPTED + examine_desc = "open $TARGET_THEIR$ storage" + +/decl/interaction_handler/storage_open/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && (ishuman(user) || isrobot(user) || issmall(user)) && target?.storage + +/decl/interaction_handler/storage_open/invoked(atom/target, mob/user, obj/item/prop) + target?.storage?.open(user) diff --git a/code/game/objects/items/_item_materials.dm b/code/game/objects/items/_item_materials.dm new file mode 100644 index 000000000000..2a269fac6c9b --- /dev/null +++ b/code/game/objects/items/_item_materials.dm @@ -0,0 +1,122 @@ +/obj/item/on_update_icon() + SHOULD_CALL_PARENT(TRUE) + . = ..() + cut_overlays() + if((material_alteration & MAT_FLAG_ALTERATION_COLOR) && material) + alpha = 100 + material.opacity * 255 + color = get_color() // avoiding set_color() here as that will set it on paint_color + if(coating_overlay) + add_overlay(coating_overlay) + if(global.contamination_overlay && contaminated) + add_overlay(global.contamination_overlay) + +/obj/item/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + . = ..() + if(material && (material.is_brittle() || target.get_blocked_ratio(hit_zone, BRUTE, damage_flags(), armor_penetration, get_attack_force(user)) * 100 >= material.hardness/5)) + apply_wear() + +/obj/item/on_parry(mob/user, damage_source, mob/attacker) + if(istype(damage_source, /obj/item)) + apply_wear() + +/** + * Whether the object will take wear damage when used as a weapon. + */ +/obj/item/proc/can_take_wear_damage() + return TRUE + +/obj/item/proc/apply_wear() + if(material && can_take_damage() && can_take_wear_damage() && prob(material.hardness)) + if(material.is_brittle()) + current_health = 0 + else + current_health-- + check_health() + +/obj/item/proc/check_health(var/lastdamage = null, var/lastdamtype = null, var/lastdamflags = 0, var/consumed = FALSE) + if(current_health > 0 || !can_take_damage()) + return //If invincible, or if we're not dead yet, skip + if(lastdamtype == BRUTE) + if(material?.is_brittle()) + shatter(consumed) + return + else if(lastdamtype == BURN) + handle_destroyed_by_heat() + return + physically_destroyed() + +/obj/item/proc/shatter(var/consumed) + var/turf/T = get_turf(src) + T?.visible_message(SPAN_DANGER("\The [src] [material?.destruction_desc || "shatters"]!")) + playsound(src, material?.destruction_sound || "shatter", 70, 1) + if(!consumed && material && w_class > ITEM_SIZE_SMALL && T) + material.place_shards(T) + qdel(src) + +// TODO: Refactor more code to use this where necessary, and then make this use +// some sort of generalized system for hitting with different parts of an item +// e.g. pommel vs blade, rifle butt vs bayonet, knife hilt vs blade +/// What material are we using when we hit things? +/// Params: +/// mob/user (the mob striking something with src) +/// atom/target (the atom being struck with src) +/obj/item/proc/get_striking_material(mob/user, atom/target) + return get_material() + +/obj/item/proc/set_material(var/new_material) + if(new_material) + material = GET_DECL(new_material) + attack_cooldown = initial(attack_cooldown) + if(istype(material)) + attack_cooldown += material.get_attack_cooldown() + //Only set the current_health if health is null. Some things define their own health value. + if(isnull(max_health)) + max_health = round(material_health_multiplier * material.integrity, 0.01) + if(max_health < 1) + //Make sure to warn us if the values we set make the max_health be under 1 + log_warning("The 'max_health' of '[src]'([type]) made out of '[material]' was calculated as [material_health_multiplier] * [material.integrity] == [max_health], which is smaller than 1.") + + if(isnull(current_health)) //only set health if we didn't specify one already, so damaged objects on spawn and etc can be a thing + current_health = get_max_health() + + if(material.products_need_process()) + START_PROCESSING(SSobj, src) + if(material.conductive) + obj_flags |= OBJ_FLAG_CONDUCTIBLE + else + obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) + if(isnull(initial(paint_verb))) + paint_verb = material.paint_verb + refresh_color() // apply material color + update_attack_force() + update_name() + if(material_armor_multiplier) + armor = material.get_armor(material_armor_multiplier) + armor_degradation_speed = material.armor_degradation_speed + if(length(armor)) + set_extension(src, armor_type, armor, armor_degradation_speed) + else + remove_extension(src, armor_type) + + queue_icon_update() + +/obj/item/proc/update_name() + var/list/new_name = list(base_name || initial(name)) + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_NAME)) + new_name.Insert(1, material.adjective_name) + if(name_prefix) + new_name.Insert(1, name_prefix) + if(length(new_name)) + SetName(jointext(new_name, " ")) + +/obj/item/get_matter_amount_modifier() + . = ..() + if(obj_flags & OBJ_FLAG_HOLLOW) + . *= HOLLOW_OBJECT_MATTER_MULTIPLIER + +/obj/item/create_matter() + ..() + LAZYINITLIST(matter) + if(istype(material)) + matter[material.type] = max(matter[material.type], round(MATTER_AMOUNT_PRIMARY * get_matter_amount_modifier())) + UNSETEMPTY(matter) diff --git a/code/game/objects/items/_item_melting.dm b/code/game/objects/items/_item_melting.dm new file mode 100644 index 000000000000..318d8f288231 --- /dev/null +++ b/code/game/objects/items/_item_melting.dm @@ -0,0 +1,55 @@ +/obj/item/ProcessAtomTemperature() + + if(material && material.bakes_into_material && !isnull(material.bakes_into_at_temperature) && temperature >= material.bakes_into_at_temperature) + set_material(material.bakes_into_material) + + . = ..() + + if(QDELETED(src)) + return + + // Handle being burned by items that are too hot for you to touch. + // TODO: check holding organ coverage and be burned by hot items + // TODO: that one spell from D&D that heats up your armour + if(ismob(loc)) + var/mob/holder = loc + try_burn_wearer(holder, holder.get_equipped_slot_for_item(src)) + + // Temp gate until generalized temperature-based melting works properly. + var/static/list/_melting_containers = list( + /obj/item/chems/crucible, + /obj/item/organ/internal/stomach + ) + if(!is_type_in_list(loc, _melting_containers)) + return + + // Check if this is meltable at all. + var/list/meltable_materials + for(var/mat in matter) + var/decl/material/melt_material = GET_DECL(mat) + if(!isnull(melt_material.melting_point) && temperature >= melt_material.melting_point) + LAZYDISTINCTADD(meltable_materials, melt_material) + if(length(meltable_materials)) + . = null // Don't return PROCESS_KILL here. + handle_melting(meltable_materials) + +/obj/item/place_melted_product(list/meltable_materials) + + // Create the thing and copy over relevant info. + var/obj/item/debris/melted/melty_thing = new(null, material?.type) + melty_thing.name = "half-melted [name]" + melty_thing.w_class = w_class + melty_thing.desc = "[melty_thing.desc] It looks like it was once \a [src]." + melty_thing.matter = matter?.Copy() // avoid mutation + LAZYCLEARLIST(matter) + + // Start it cooking for next time. + melty_thing.temperature = temperature + QUEUE_TEMPERATURE_ATOM(melty_thing) + + melty_thing.forceMove(loc) + + // Destroy the old thing. + qdel(src) + // This will be recursive if the melty thing does not override this proc. + return melty_thing.handle_melting(meltable_materials) diff --git a/code/game/objects/items/_item_reagents.dm b/code/game/objects/items/_item_reagents.dm new file mode 100644 index 000000000000..24f8656fc072 --- /dev/null +++ b/code/game/objects/items/_item_reagents.dm @@ -0,0 +1,76 @@ +/obj/item/proc/standard_dispenser_refill(mob/user, obj/structure/target, skip_container_check = FALSE) // This goes into afterattack + if(!istype(target) || isnull(target.get_reagent_amount_dispensed()) || (!skip_container_check && (target.atom_flags & ATOM_FLAG_OPEN_CONTAINER))) + return FALSE + + if(!target.reagents || !REAGENT_TOTAL_VOLUME(target.reagents)) + to_chat(user, SPAN_NOTICE("[target] is empty of reagents.")) + return TRUE + + if(reagents && !REAGENTS_FREE_SPACE(reagents)) + to_chat(user, SPAN_NOTICE("[src] is full of reagents.")) + return TRUE + + var/trans = target.reagents.trans_to_obj(src, target.get_reagent_amount_dispensed()) + to_chat(user, SPAN_NOTICE("You fill [src] with [trans] units of the contents of [target].")) + return TRUE + +/obj/item/proc/standard_splash_mob(var/mob/user, var/mob/target) // This goes into afterattack + if(!istype(target)) + return FALSE + + if(user.check_intent(I_FLAG_HELP)) + to_chat(user, SPAN_NOTICE("You can't splash people on help intent.")) + return TRUE + + if(!reagents || !REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_NOTICE("[src] is empty of reagents.")) + return TRUE + + if(target.reagents && !REAGENTS_FREE_SPACE(target.reagents)) + to_chat(user, SPAN_NOTICE("[target] is full of reagents.")) + return TRUE + + var/contained = REAGENT_LIST(reagents) + + admin_attack_log(user, target, "Used \the [name] containing [contained] to splash the victim.", "Was splashed by \the [name] containing [contained].", "used \the [name] containing [contained] to splash") + user.visible_message( \ + SPAN_DANGER("\The [target] has been splashed with the contents of \the [src] by \the [user]!"), \ + SPAN_DANGER("You splash \the [target] with the contents of \the [src].")) + + reagents.splash(target, REAGENT_TOTAL_VOLUME(reagents)) + return TRUE + +/obj/item/proc/standard_pour_into(mob/user, atom/target, amount = 5) // This goes into afterattack and yes, it's atom-level + if(!target.reagents) + return FALSE + + if(!target.can_be_poured_into(src)) + // Ensure we don't splash beakers and similar containers. + if(istype(target, /obj/item/chems)) + to_chat(user, SPAN_NOTICE("\The [target] is closed.")) + return TRUE + // Otherwise don't care about splashing. + return FALSE + + if(!can_be_poured_from(user, target)) + return TRUE // don't splash if we can't pour + + if(!reagents || !REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_NOTICE("[src] is empty of reagents.")) + return TRUE + + if(!REAGENTS_FREE_SPACE(target.reagents)) + to_chat(user, SPAN_NOTICE("[target] is full of reagents.")) + return TRUE + + var/liquid_volumes = REAGENT_LIQUID_VOLUMES(reagents) + var/had_liquids = length(liquid_volumes) + var/transferred_amount = reagents.trans_to(target, amount) + + if(had_liquids) + playsound(src, 'sound/effects/pour.ogg', 25, 1) + else + // Sounds more like pouring small pellets or dust. + playsound(src, 'sound/effects/refill.ogg', 25, 1) + to_chat(user, SPAN_NOTICE("You transfer [transferred_amount] unit\s of the solution to \the [target]. \The [src] now contains [REAGENT_TOTAL_VOLUME(reagents)] unit\s.")) + return TRUE diff --git a/code/game/objects/items/_item_serde.dm b/code/game/objects/items/_item_serde.dm new file mode 100644 index 000000000000..c4aba6ca9327 --- /dev/null +++ b/code/game/objects/items/_item_serde.dm @@ -0,0 +1,3 @@ +/obj/item/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(paint_verb, /obj/item) diff --git a/code/game/objects/items/_item_sharpness.dm b/code/game/objects/items/_item_sharpness.dm new file mode 100644 index 000000000000..a37c1bf56fe7 --- /dev/null +++ b/code/game/objects/items/_item_sharpness.dm @@ -0,0 +1,21 @@ +/obj/item + VAR_PROTECTED/sharp = FALSE + VAR_PROTECTED/edge = FALSE + +/obj/item/is_sharp() + return sharp + +/obj/item/has_edge() + return edge + +/obj/item/proc/set_edge(new_edge) + if(edge != new_edge) + edge = new_edge + return TRUE + return FALSE + +/obj/item/proc/set_sharp(new_sharp) + if(sharp != new_sharp) + sharp = new_sharp + return TRUE + return FALSE diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm deleted file mode 100644 index 7275277cb13c..000000000000 --- a/code/game/objects/items/apc_frame.dm +++ /dev/null @@ -1,30 +0,0 @@ -// APC HULL - -/obj/item/frame/apc - name = "\improper APC frame" - desc = "Used for repairing or building APCs." - icon = 'icons/obj/apc_repair.dmi' - icon_state = "apc_frame" - obj_flags = OBJ_FLAG_CONDUCTIBLE - build_machine_type = /obj/machinery/power/apc/buildable - reverse = TRUE - -/obj/item/frame/apc/try_build(turf/on_wall) - var/area/A = get_area(src) - if (A.requires_power == 0 || istype(A, /area/space)) - to_chat(usr, "APC cannot be placed in this area.") - return - if (A.get_apc()) - to_chat(usr, "This area already has an APC.") - return //only one APC per area - for(var/obj/machinery/power/terminal/T in loc) - if (T.master) - to_chat(usr, "There is another network terminal here.") - return - return ..() - -/obj/item/frame/apc/kit - fully_construct = TRUE - name = "APC kit" - desc = "An all-in-one APC kit, comes preassembled." - build_machine_type = /obj/machinery/power/apc \ No newline at end of file diff --git a/code/game/objects/items/artifice/chain.dm b/code/game/objects/items/artifice/chain.dm new file mode 100644 index 000000000000..2e44bf586f62 --- /dev/null +++ b/code/game/objects/items/artifice/chain.dm @@ -0,0 +1,10 @@ +// Stub for forging. TODO crafting that uses chains. +/obj/item/chain + name = "chain" + name_prefix = "length of" + desc = "A flexible length of interconnected links forming a chain." + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/chain.dmi' + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + material_alteration = MAT_FLAG_ALTERATION_ALL diff --git a/code/game/objects/items/artifice/hook.dm b/code/game/objects/items/artifice/hook.dm new file mode 100644 index 000000000000..c04401d873fb --- /dev/null +++ b/code/game/objects/items/artifice/hook.dm @@ -0,0 +1,9 @@ +// Stub for forging. TODO use for slapcrafting a fishing rod? +/obj/item/hook + name = "hook" + desc = "A small, sharp, curved object." + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/hook.dmi' + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + material_alteration = MAT_FLAG_ALTERATION_ALL diff --git a/code/game/objects/items/artifice/lockpicks.dm b/code/game/objects/items/artifice/lockpicks.dm new file mode 100644 index 000000000000..99c3eccabbec --- /dev/null +++ b/code/game/objects/items/artifice/lockpicks.dm @@ -0,0 +1,78 @@ +/obj/item/lockpick + name = "lockpick" + icon_state = ICON_STATE_WORLD + "1" + icon = 'icons/obj/items/lockpick.dmi' + desc = "A slender tool used for picking locks." + lock_picking_level = 25 // 20 * (25 / length of lock string) - 50% base success for 'sunken keep' + material = /decl/material/solid/metal/steel + color = /decl/material/solid/metal/steel::color + material_alteration = MAT_FLAG_ALTERATION_ALL + w_class = ITEM_SIZE_TINY + max_health = 60 + var/use_icon_state + +// Purely for aesthetics. +/obj/item/lockpick/rake + use_icon_state = "1" +/obj/item/lockpick/hook + use_icon_state = "2" +/obj/item/lockpick/lever + use_icon_state = "3" + +/obj/item/lockpick/Initialize(ml, material_key) + . = ..() + if(isnull(use_icon_state)) + use_icon_state = num2text(rand(1,3)) + update_icon() + +/obj/item/lockpick/on_update_icon() + . = ..() + icon_state = "[get_world_inventory_state()][use_icon_state]" + +/datum/storage/lockpick_roll + can_hold = list(/obj/item/lockpick) + storage_slots = 5 + +/obj/item/lockpick_roll + name = "roll of lockpicks" + desc = "A stitched roll used to store thin, strangely-shaped tools commonly used to pick locks." + icon = 'icons/obj/items/lockpick_roll.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/leather + color = /decl/material/solid/organic/leather::color + material_alteration = MAT_FLAG_ALTERATION_ALL + storage = /datum/storage/lockpick_roll + +/obj/item/lockpick_roll/filled/WillContain() + return list( + /obj/item/lockpick/rake = 2, + /obj/item/lockpick/hook = 2, + /obj/item/lockpick/lever = 1 + ) + +/obj/item/lockpick_roll/attack_self(mob/user) + if(!storage?.opened) + storage.open(user) + return TRUE + return ..() + +/obj/item/lockpick_roll/on_update_icon() + . = ..() + icon_state = ICON_STATE_WORLD + if(!storage?.opened) + icon_state = "[icon_state]-rolled" + else if(length(contents)) + var/x_offset = -9 + for(var/i = 1 to length(contents)) + var/obj/item/lockpick/thing = contents[i] + if(istype(thing)) + var/image/lockpick = new /image + lockpick.color = thing.color + lockpick.icon = thing.icon + lockpick.icon_state = thing.icon_state + lockpick.appearance_flags |= RESET_COLOR + lockpick.pixel_x = x_offset + add_overlay(lockpick) + x_offset += 4 + add_overlay("[icon_state]-cover") + compile_overlays() diff --git a/code/game/objects/items/blackout.dm b/code/game/objects/items/blackout.dm index 31b9d5c4fd1d..68df55bfa2a9 100644 --- a/code/game/objects/items/blackout.dm +++ b/code/game/objects/items/blackout.dm @@ -9,10 +9,13 @@ /obj/item/blackout name = "blackout pulser" - desc = "A complicated eletronic device of unknown purpose" + desc = "A complicated electronic device of unknown purpose." icon = 'icons/obj/items/blackout.dmi' icon_state = "device_blackout-off" - + max_health = ITEM_HEALTH_NO_DAMAGE + origin_tech = "{'magnets':2,'esoteric':2}" + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE) var/severity = 2 var/shots = 1 var/last_use = 0 @@ -45,33 +48,34 @@ hacktheenergy(terminal, user) /obj/item/blackout/proc/hacktheenergy(obj/machinery/power/terminal/terminal_in, mob/user) - if(!istype(terminal_in) || !user) return - src.audible_message("HackTheEnergy.exe Assistant says, \ - \"Starting. Connecting to the terminal.\"") - if(!do_after(user, 30, terminal_in)) return + if(!istype(terminal_in) || !user) + return - src.audible_message("HackTheEnergy.exe Assistant says, \ - \"Successful connection to the terminal. Getting information about the powergrid...\"") - if(!do_after(user, 80, terminal_in)) return + var/display_name = SPAN_MAROON("HackTheEnergy.exe Assistant") + src.audible_message("[display_name] says, \"Starting. Connecting to the terminal.\"") + if(!do_after(user, 3 SECONDS, terminal_in)) + return - src.audible_message("HackTheEnergy.exe Assistant says, \ - \"Powernet scan succeeded. Beginning blackout pulse.\"") + src.audible_message("[display_name] says, \"Successful connection to the terminal. Getting information about the powergrid...\"") + if(!do_after(user, 8 SECONDS, terminal_in)) + return + src.audible_message("[display_name] says, \"Powernet scan succeeded. Beginning blackout pulse.\"") icon_state = "device_blackout-on" playsound(src, 'sound/items/goggles_charge.ogg', 50, 1) - if(!do_after(user, 40, terminal_in)) return - src.audible_message("HackTheEnergy.exe Assistant says, \ - \"Done. Pulsing is complete. We wish you a successful and productive mission.\"") + if(!do_after(user, 4 SECONDS, terminal_in)) + return + src.audible_message("[display_name] says, \"Done. Pulsing is complete. We wish you a successful and productive mission.\"") shots-- cooldown = world.time var/datum/powernet/powernet = terminal_in.powernet for(var/obj/machinery/power/terminal/terminal_out in powernet.nodes) - if(istype(terminal_out.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/A = terminal_out.master + if(istype(terminal_out.master, /obj/machinery/apc)) + var/obj/machinery/apc/A = terminal_out.master A.energy_fail(rand(30 * severity, 60 * severity)) if(istype(terminal_out.master, /obj/machinery/power/smes/buildable)) var/obj/machinery/power/smes/buildable/S = terminal_out.master diff --git a/code/game/objects/items/blades/_blade.dm b/code/game/objects/items/blades/_blade.dm new file mode 100644 index 000000000000..80aa8b5d1ed7 --- /dev/null +++ b/code/game/objects/items/blades/_blade.dm @@ -0,0 +1,138 @@ +// Bladed weapon with composite material makeup class. +/obj/item/bladed + icon_state = "preview" + abstract_type = /obj/item/bladed + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + origin_tech = @'{"materials":1,"combat":1}' + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + obj_flags = OBJ_FLAG_CONDUCTIBLE + sharp = TRUE + edge = TRUE + item_flags = ITEM_FLAG_IS_WEAPON + pickup_sound = 'sound/foley/knife1.ogg' + drop_sound = 'sound/foley/knifedrop3.ogg' + hitsound = 'sound/weapons/bladeslice.ogg' + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/metal/steel + _base_attack_force = 10 + + var/decl/material/hilt_material = /decl/material/solid/organic/wood/oak + var/decl/material/guard_material = /decl/material/solid/organic/wood/oak + var/decl/material/pommel_material = /decl/material/solid/organic/wood/oak + + /// Cache var for blade material shine calculation. + var/tmp/shine + +/obj/item/bladed/Initialize(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) + + if(_hilt_mat) + hilt_material = _hilt_mat + if(_guard_mat) + guard_material = _guard_mat + if(_pommel_mat) + pommel_material = _pommel_mat + + if(ispath(hilt_material)) + hilt_material = GET_DECL(hilt_material) + if(ispath(guard_material)) + guard_material = GET_DECL(guard_material) + if(ispath(pommel_material)) + pommel_material = GET_DECL(pommel_material) + + LAZYINITLIST(matter) + if(istype(hilt_material)) + matter[hilt_material.type] += MATTER_AMOUNT_SECONDARY + else + hilt_material = null + if(istype(guard_material)) + matter[guard_material.type] += MATTER_AMOUNT_REINFORCEMENT + else + guard_material = null + if(istype(pommel_material)) + matter[guard_material.type] += MATTER_AMOUNT_TRACE + else + pommel_material = null + UNSETEMPTY(matter) + + . = ..() + + if(!has_extension(src, /datum/extension/tool)) + // If this were an `/obj/item/tool` subtype, we could get away with just doing this in `get_initial_tool_qualities()`. + var/list/initial_tool_qualities = list( + TOOL_SCALPEL = TOOL_QUALITY_MEDIOCRE, + TOOL_SAW = TOOL_QUALITY_BAD, + TOOL_RETRACTOR = TOOL_QUALITY_BAD, + TOOL_SCREWDRIVER = TOOL_QUALITY_BAD, + ) + switch(w_class) + if(0 to ITEM_SIZE_SMALL) + pass() + if(ITEM_SIZE_SMALL to ITEM_SIZE_NORMAL) // Since ITEM_SIZE_SMALL was already covered, this is just ITEM_SIZE_NORMAL. + initial_tool_qualities[TOOL_HATCHET] = TOOL_QUALITY_WORST + if(ITEM_SIZE_NORMAL to ITEM_SIZE_LARGE) + initial_tool_qualities[TOOL_HATCHET] = TOOL_QUALITY_BAD + else + initial_tool_qualities[TOOL_HATCHET] = TOOL_QUALITY_MEDIOCRE + set_extension(src, /datum/extension/tool/variable/simple, initial_tool_qualities) + + shine = istype(material) ? clamp((material.reflectiveness * 0.01) * 255, 10, (0.6 * rgb2num(material.color, COLORSPACE_HSV)[3])) : null + icon_state = ICON_STATE_WORLD + on_update_icon() + +/obj/item/bladed/proc/update_base_icon_state() + icon_state = get_world_inventory_state() + +/obj/item/bladed/proc/get_hilt_color() + return istype(hilt_material) ? hilt_material.color : COLOR_WHITE + +/obj/item/bladed/proc/get_guard_color() + return istype(guard_material) ? guard_material.color : COLOR_WHITE + +/obj/item/bladed/proc/get_pommel_color() + return istype(pommel_material) ? pommel_material.color : COLOR_WHITE + +/obj/item/bladed/on_update_icon() + . = ..() + update_base_icon_state() + if(istype(hilt_material)) + var/check_state = "[icon_state]-hilt" + if(check_state_in_icon(check_state, icon)) + add_overlay(overlay_image(icon, check_state, get_hilt_color(), RESET_COLOR)) + if(istype(guard_material)) + var/check_state = "[icon_state]-guard" + if(check_state_in_icon(check_state, icon)) + add_overlay(overlay_image(icon, check_state, get_guard_color(), RESET_COLOR)) + if(istype(pommel_material)) + var/check_state = "[icon_state]-pommel" + if(check_state_in_icon(check_state, icon)) + add_overlay(overlay_image(icon, check_state, get_pommel_color(), RESET_COLOR)) + if(shine) + var/check_state = "[icon_state]-shine" + if(check_state_in_icon(check_state, icon)) + var/image/I = overlay_image(icon, check_state, COLOR_WHITE, (RESET_COLOR | RESET_ALPHA)) + I.alpha = shine + add_overlay(I) + update_held_icon() + +// We handle this in the post-proc so wielding status is updated for polearms/broadswords/etc +/obj/item/bladed/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + if(istype(hilt_material)) + var/check_state = "[overlay.icon_state]-hilt" + if(check_state_in_icon(check_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, check_state, get_hilt_color(), RESET_COLOR) + if(istype(guard_material)) + var/check_state = "[overlay.icon_state]-guard" + if(check_state_in_icon(check_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, check_state, get_guard_color(), RESET_COLOR) + if(istype(pommel_material)) + var/check_state = "[overlay.icon_state]-pommel" + if(check_state_in_icon(check_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, check_state, get_pommel_color(), RESET_COLOR) + if(shine) + var/check_state = "[overlay.icon_state]-shine" + if(check_state_in_icon(check_state, overlay.icon)) + var/image/I = overlay_image(overlay.icon, check_state, COLOR_WHITE, (RESET_COLOR | RESET_ALPHA)) + I.alpha = shine + overlay.overlays += I + return ..() diff --git a/code/game/objects/items/blades/axe.dm b/code/game/objects/items/blades/axe.dm new file mode 100644 index 000000000000..ab902f9187a4 --- /dev/null +++ b/code/game/objects/items/blades/axe.dm @@ -0,0 +1,28 @@ +/obj/item/bladed/axe + abstract_type = /obj/item/bladed/axe + can_be_twohanded = TRUE + pickup_sound = 'sound/foley/scrape1.ogg' + drop_sound = 'sound/foley/tooldrop1.ogg' + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + hilt_material = /decl/material/solid/organic/wood/oak + guard_material = /decl/material/solid/organic/leather/gut + pommel_material = null + attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + _base_attack_force = 22 + +// Discard pommel material. +/obj/item/bladed/axe/Initialize(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) + return ..(ml, material_key, _hilt_mat, _guard_mat) + +/obj/item/bladed/axe/afterattack(atom/A, mob/user, proximity) + . = ..() + if(proximity && A && is_held_twohanded()) + if(istype(A,/obj/structure/window)) + var/obj/structure/window/window = A + window.shatter() + else if(istype(A,/obj/structure/grille)) + qdel(A) + else if(istype(A,/obj/effect/vine)) + var/obj/effect/vine/P = A + P.die_off() diff --git a/code/game/objects/items/blades/axe_fire.dm b/code/game/objects/items/blades/axe_fire.dm new file mode 100644 index 000000000000..afe7d8e25f23 --- /dev/null +++ b/code/game/objects/items/blades/axe_fire.dm @@ -0,0 +1,7 @@ +/obj/item/bladed/axe/fire + name = "fire axe" + icon = 'icons/obj/items/bladed/fireaxe.dmi' + icon_state = ICON_STATE_WORLD + desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" + material_alteration = MAT_FLAG_ALTERATION_NAME + guard_material = /decl/material/solid/organic/plastic diff --git a/code/game/objects/items/blades/folding.dm b/code/game/objects/items/blades/folding.dm new file mode 100644 index 000000000000..8e769c44d179 --- /dev/null +++ b/code/game/objects/items/blades/folding.dm @@ -0,0 +1,158 @@ +/obj/item/bladed/folding + name = "folding knife" + desc = "A small folding knife." + icon = 'icons/obj/items/bladed/folding.dmi' + w_class = ITEM_SIZE_SMALL + sharp = FALSE + pommel_material = null + guard_material = null + slot_flags = null + material = /decl/material/solid/metal/bronze + hilt_material = /decl/material/solid/organic/wood/oak + _base_attack_force = 5 + + var/open = FALSE + var/closed_item_size = ITEM_SIZE_SMALL + var/open_item_size = ITEM_SIZE_NORMAL + var/open_attack_verbs = list("slashed", "stabbed") + var/closed_attack_verbs = list("prodded", "tapped") + +/obj/item/bladed/folding/iron + material = /decl/material/solid/metal/iron + +/obj/item/bladed/folding/Initialize() + . = ..() + update_attack_force() + +/obj/item/bladed/folding/attack_self(mob/user) + if(!user.check_intent(I_FLAG_HELP)) + set_open(!open, user) + return TRUE + var/decl/interaction_handler/folding_knife/interaction = GET_DECL(/decl/interaction_handler/folding_knife) + if(!interaction.is_possible(src, user)) + return FALSE + interaction.invoked(src, user, user.get_active_held_item()) + return TRUE + +/obj/item/bladed/folding/proc/set_open(new_state, mob/user) + open = new_state + update_attack_force() + update_icon() + if(user) + if(open) + user.visible_message(SPAN_NOTICE("\The [user] opens \the [src].")) + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + else + user.visible_message(SPAN_NOTICE("\The [user] closes \the [src].")) + add_fingerprint(user) + +/obj/item/bladed/folding/update_base_icon_state() + . = ..() + if(!open) + icon_state = "[icon_state]-closed" + +/obj/item/bladed/folding/update_attack_force() + . = ..() + set_edge(open) + set_sharp(open) + w_class = open ? open_item_size : closed_item_size + +/obj/item/bladed/folding/pick_attack_verb() + return DEFAULTPICK(open ? open_attack_verbs : closed_attack_verbs, ..()) + +// Only show the inhand sprite when open. +/obj/item/bladed/folding/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) + . = open ? ..() : new /image + +// TODO: Select hilt, guard, etc. as striking material based on dynamic intents +/obj/item/bladed/folding/get_striking_material(mob/user, atom/target) + . = open ? ..() : hilt_material + +/obj/item/bladed/folding/get_tool_speed(archetype) + return open ? ..() : 0 + +/obj/item/bladed/folding/get_tool_quality(archetype) + if(open && archetype == TOOL_HATCHET) + // If this were an `/obj/item/tool` subtype, we could get away with just doing this based on + // `open_item_size` in `get_initial_tool_qualities()`. + switch(w_class) + if(0 to ITEM_SIZE_SMALL) + return TOOL_QUALITY_NONE + if(ITEM_SIZE_SMALL to ITEM_SIZE_NORMAL) // Since ITEM_SIZE_SMALL was already covered, this is just ITEM_SIZE_NORMAL. + return TOOL_QUALITY_WORST + if(ITEM_SIZE_NORMAL to ITEM_SIZE_LARGE) + return TOOL_QUALITY_BAD + else + return TOOL_QUALITY_MEDIOCRE + return open ? ..() : 0 + +//Interactions +/obj/item/bladed/folding/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/folding_knife) + +/decl/interaction_handler/folding_knife + name = "Adjust Folding Knife" + expected_target_type = /obj/item/bladed/folding + interaction_flags = INTERACTION_NEEDS_INVENTORY | INTERACTION_NEEDS_PHYSICAL_INTERACTION + examine_desc = "adjust $TARGET_THEM$" + +/decl/interaction_handler/folding_knife/is_possible(atom/target, mob/user) + . = ..() + if(.) + var/datum/extension/tool/tool_extension = get_extension(target, /datum/extension/tool) + return istype(tool_extension, /datum/extension/tool/variable) && user.check_dexterity(DEXTERITY_COMPLEX_TOOLS) + +/decl/interaction_handler/folding_knife/proc/get_radial_choices(atom/target) + // - toggle open/closed + // - each tool + . = list() + var/obj/item/bladed/folding/folding_knife = target + // should always be in the inventory so we can assume get_world_inventory_state is inventory if it exists + var/open_close_state = "[folding_knife.get_world_inventory_state()]" + if(folding_knife.open) + open_close_state += "-closed" + var/image/open_close_image = new /image + open_close_image.name = folding_knife.open ? "Close blade" : "Open blade" + open_close_image.underlays = list( + overlay_image(folding_knife.icon, "[open_close_state]-hilt", folding_knife.hilt_material.color, RESET_COLOR), + overlay_image(folding_knife.icon, open_close_state, folding_knife.material.color, RESET_COLOR) + ) + .["Toggle"] = open_close_image +/* if(!folding_knife.open) // Can only switch mode with the knife open, because we assume all tool interactions use the blade currently + return . */ + var/datum/extension/tool/variable/tool = get_extension(target, /datum/extension/tool) + for(var/tool_mode in tool.tool_values) + if(tool_mode == tool.current_tool) + continue + var/decl/tool_archetype/tool_archetype = GET_DECL(tool_mode) + // This blank image fuckery is done so that we can actually have a usable return value from show_radial_menu AND have a maptext label. + var/image/I = new /image + I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + var/tool_name = tool_archetype.name + if(tool_archetype.article) + tool_name = "\a [tool_name]" + var/image/underlay = new /image + underlay.appearance = folding_knife + // reset a bunch of appearance vars we don't need + underlay.pixel_x = 0 + underlay.pixel_y = 0 + underlay.layer = FLOAT_LAYER + underlay.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + I.underlays = list(underlay) // don't fuck with the base object's name or color please + I.name = "Use as [tool_name]" + .[tool_mode] = I + +/decl/interaction_handler/folding_knife/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/bladed/folding/folding_knife = target + var/chosen_option = show_radial_menu(user, user, get_radial_choices(folding_knife), radius = 42, use_labels = RADIAL_LABELS_OFFSET) + if(!chosen_option) + return + if(chosen_option == "Toggle") + folding_knife.set_open(!folding_knife.open, user) + return + var/datum/extension/tool/variable/tool = get_extension(folding_knife, /datum/extension/tool) + if(ispath(chosen_option, /decl/tool_archetype)) + tool.switch_tool(chosen_option, user) + return + CRASH("Invalid option '[json_encode(chosen_option)]' selected in [folding_knife]'s [type]") \ No newline at end of file diff --git a/code/game/objects/items/blades/knife.dm b/code/game/objects/items/blades/knife.dm new file mode 100644 index 000000000000..986f54da39dd --- /dev/null +++ b/code/game/objects/items/blades/knife.dm @@ -0,0 +1,10 @@ +/obj/item/bladed/knife + name = "knife" + desc = "A simple belt knife." + icon = 'icons/obj/items/bladed/knife.dmi' + item_flags = ITEM_FLAG_CAN_HIDE_IN_SHOES | ITEM_FLAG_IS_WEAPON + w_class = ITEM_SIZE_SMALL + base_parry_chance = 20 + +/obj/item/bladed/knife/iron + material = /decl/material/solid/metal/iron diff --git a/code/game/objects/items/blades/polearm.dm b/code/game/objects/items/blades/polearm.dm new file mode 100644 index 000000000000..d7fe1b8e8660 --- /dev/null +++ b/code/game/objects/items/blades/polearm.dm @@ -0,0 +1,15 @@ +/obj/item/bladed/polearm + abstract_type = /obj/item/bladed/polearm + can_be_twohanded = TRUE + pickup_sound = 'sound/foley/scrape1.ogg' + drop_sound = 'sound/foley/tooldrop1.ogg' + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + hilt_material = /decl/material/solid/organic/wood/oak + guard_material = /decl/material/solid/organic/leather/gut + pommel_material = null + _base_attack_force = 20 + +// Discard pommel material. +/obj/item/bladed/polearm/Initialize(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) + return ..(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) diff --git a/code/game/objects/items/blades/spear.dm b/code/game/objects/items/blades/spear.dm new file mode 100644 index 000000000000..2779646e0c85 --- /dev/null +++ b/code/game/objects/items/blades/spear.dm @@ -0,0 +1,10 @@ +/obj/item/bladed/polearm/spear + name = "spear" + desc = "A haphazardly-constructed yet still deadly weapon of ancient design." + icon = 'icons/obj/items/bladed/spear.dmi' + throw_speed = 3 + edge = FALSE + sharp = TRUE + attack_verb = list("attacked", "poked", "jabbed", "torn", "gored") + does_spin = FALSE + abstract_type = /obj/item/bladed/polearm/spear diff --git a/code/game/objects/items/blades/spear_improvised.dm b/code/game/objects/items/blades/spear_improvised.dm new file mode 100644 index 000000000000..9f1a1da24257 --- /dev/null +++ b/code/game/objects/items/blades/spear_improvised.dm @@ -0,0 +1,40 @@ +/obj/item/bladed/polearm/spear/improvised + name_prefix = "improvised" + material = /decl/material/solid/glass + hilt_material = /decl/material/solid/metal/steel + guard_material = /decl/material/solid/metal/copper + var/force_binding_color + +/obj/item/bladed/polearm/spear/improvised/Initialize(ml, material_key, _hilt_mat, _guard_mat, _binding_color) + if(_binding_color) + force_binding_color = _binding_color + if(!force_binding_color) + force_binding_color = pick(global.cable_colors) + . = ..(ml, material_key, _hilt_mat, _guard_mat) + +/obj/item/bladed/polearm/spear/improvised/get_guard_color() + return force_binding_color || ..() + +/obj/item/bladed/polearm/spear/improvised/shatter(var/consumed) + if(!consumed) + if(istype(hilt_material)) + SSmaterials.create_object(hilt_material, get_turf(src), 1, /obj/item/stack/material/rods) + if(istype(guard_material)) + new /obj/item/stack/cable_coil(get_turf(src), 3, force_binding_color) + ..() + +// Subtypes for mapping/spawning +/obj/item/bladed/polearm/spear/improvised/diamond + material = /decl/material/solid/gemstone/diamond + hilt_material = /decl/material/solid/metal/gold + force_binding_color = COLOR_PURPLE + +/obj/item/bladed/polearm/spear/improvised/steel + material = /decl/material/solid/metal/steel + hilt_material = /decl/material/solid/organic/wood/oak + force_binding_color = COLOR_GREEN + +/obj/item/bladed/polearm/spear/improvised/exotic_matter + material = /decl/material/solid/exotic_matter + hilt_material = /decl/material/solid/organic/wood/ebony + force_binding_color = COLOR_INDIGO diff --git a/code/game/objects/items/blades/swords_one_handed.dm b/code/game/objects/items/blades/swords_one_handed.dm new file mode 100644 index 000000000000..a684d9e4d414 --- /dev/null +++ b/code/game/objects/items/blades/swords_one_handed.dm @@ -0,0 +1,35 @@ +/obj/item/bladed/poignard + name = "poignard" + desc = "A short stabbing blade, usually used in the off-hand." + icon = 'icons/obj/items/bladed/poignard.dmi' + hilt_material = /decl/material/solid/metal/brass + guard_material = /decl/material/solid/metal/brass + pommel_material = /decl/material/solid/metal/brass + w_class = ITEM_SIZE_NORMAL + base_parry_chance = 30 + melee_accuracy_bonus = 20 + _base_attack_force = 15 + +/obj/item/bladed/shortsword + name = "shortsword" + desc = "A one-handed shortsword, commonly issued to infantry." + icon = 'icons/obj/items/bladed/shortsword.dmi' + hilt_material = /decl/material/solid/metal/brass + guard_material = /decl/material/solid/metal/brass + pommel_material = /decl/material/solid/metal/brass + w_class = ITEM_SIZE_NORMAL + base_parry_chance = 50 + armor_penetration = 10 + _base_attack_force = 15 + +/obj/item/bladed/rapier + name = "rapier" + desc = "A long, slender, elegant, one-handed blade with a reputation for being used by duelists." + icon = 'icons/obj/items/bladed/rapier.dmi' + hilt_material = /decl/material/solid/metal/brass + guard_material = /decl/material/solid/metal/brass + pommel_material = /decl/material/solid/metal/brass + base_parry_chance = 60 + armor_penetration = 25 + melee_accuracy_bonus = 25 + _base_attack_force = 15 diff --git a/code/game/objects/items/blades/swords_two_handed.dm b/code/game/objects/items/blades/swords_two_handed.dm new file mode 100644 index 000000000000..8231a87e1751 --- /dev/null +++ b/code/game/objects/items/blades/swords_two_handed.dm @@ -0,0 +1,31 @@ +/obj/item/bladed/longsword + name = "longsword" + desc = "A long and heavy two-handed blade with a cruciform hilt and guard." + icon = 'icons/obj/items/bladed/longsword.dmi' + hilt_material = /decl/material/solid/metal/brass + guard_material = /decl/material/solid/metal/brass + pommel_material = /decl/material/solid/metal/brass + slot_flags = SLOT_LOWER_BODY | SLOT_BACK + w_class = ITEM_SIZE_LARGE + armor_penetration = 10 + base_parry_chance = 50 + melee_accuracy_bonus = 10 + can_be_twohanded = TRUE + pickup_sound = 'sound/foley/scrape1.ogg' + drop_sound = 'sound/foley/tooldrop1.ogg' + _base_attack_force = 20 + +/obj/item/bladed/broadsword + name = "broadsword" + desc = "A massive two-handed blade, almost too large to be called a sword." + icon = 'icons/obj/items/bladed/broadsword.dmi' + hilt_material = /decl/material/solid/metal/brass + guard_material = /decl/material/solid/metal/brass + pommel_material = /decl/material/solid/metal/brass + slot_flags = SLOT_BACK + base_parry_chance = 35 + armor_penetration = 20 + can_be_twohanded = TRUE + pickup_sound = 'sound/foley/scrape1.ogg' + drop_sound = 'sound/foley/tooldrop1.ogg' + _base_attack_force = 22 diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index b85014c20f3d..2d2e4cddf964 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -4,31 +4,44 @@ icon = 'icons/obj/items/blueprints.dmi' icon_state = "blueprints" attack_verb = list("attacked", "bapped", "hit") - + material = /decl/material/solid/organic/paper var/valid_z_levels = list() var/area_prefix /obj/item/blueprints/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/item/blueprints/LateInitialize() . = ..() desc = "Blueprints of the [station_name()]. There is a \"Classified\" stamp and several coffee stains on it." - + if(set_valid_z_levels()) - set_extension(src, /datum/extension/eye/blueprints) + create_blueprint_extension() + +/obj/item/blueprints/proc/create_blueprint_extension() // so that subtypes can override + set_extension(src, /datum/extension/eye/blueprints) + +/obj/item/blueprints/proc/get_look_args() // ditto + return list(valid_z_levels, area_prefix) -/obj/item/blueprints/attack_self(var/mob/living/carbon/human/user) - if (!istype(user) || !user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) // Monkeys et al. cannot blueprint. +/obj/item/blueprints/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE + +/obj/item/blueprints/attack_self(mob/user) + if (!ishuman(user) || !user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) // Monkeys et al. cannot blueprint. to_chat(user, SPAN_WARNING("This stack of blue paper means nothing to you.")) return - if(CanInteract(user, GLOB.default_state)) + if(CanInteract(user, global.default_topic_state)) var/datum/extension/eye/blueprints = get_extension(src, /datum/extension/eye/) if(!(user.z in valid_z_levels)) to_chat(user, SPAN_WARNING("The markings on this are entirely irrelevant to your whereabouts!")) return - + if(blueprints) - if(blueprints.look(user, list(valid_z_levels, area_prefix))) // Abandon all peripheral vision, ye who enter here. - to_chat(user, SPAN_NOTICE("You start peering closely at \the [src]")) + if(blueprints.look(user, get_look_args())) // Abandon all peripheral vision, ye who enter here. + to_chat(user, SPAN_NOTICE("You start peering closely at \the [src].")) return else to_chat(user, SPAN_WARNING("You couldn't get a good look at \the [src]. Maybe someone else is using it?")) @@ -37,21 +50,23 @@ to_chat(user, SPAN_WARNING("The markings on this are useless!")) /obj/item/blueprints/proc/set_valid_z_levels() - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/sector/S = map_sectors["[get_z(src)]"] + + var/turf/T = get_turf(src) + if(istype(T) && length(global.using_map.overmap_ids)) + var/obj/effect/overmap/visitable/sector/S = global.overmap_sectors[T.z] if(!S) // The blueprints are useless now, but keep them around for fluff. - desc = "Some dusty old blueprints. The markings are old, and seem entirely irrelevant for your wherabouts." + desc = "Some dusty old blueprints. The markings are old, and seem entirely irrelevant for your whereabouts." return FALSE name += " - [S.name]" - desc = "Blueprints of \the [S.name]. There is a \"Classified\" stamp and several coffee stains on it." + desc = "Blueprints of \the [S]. There is a \"Classified\" stamp and several coffee stains on it." valid_z_levels += S.map_z area_prefix = S.name return TRUE desc = "Blueprints of the [station_name()]. There is a \"Classified\" stamp and several coffee stains on it." area_prefix = station_name() - valid_z_levels += GLOB.using_map.station_levels + valid_z_levels += SSmapping.station_levels return TRUE //For use on exoplanets @@ -59,20 +74,60 @@ name = "outpost blueprints" icon_state = "blueprints2" -/obj/item/blueprints/outpost/attack_self(var/mob/living/carbon/human/user) - var/obj/effect/overmap/visitable/sector/S = map_sectors["[get_z(user)]"] +/obj/item/blueprints/outpost/attack_self(mob/user) + var/obj/effect/overmap/visitable/sector/S = global.overmap_sectors[get_z(user)] area_prefix = S.name . = ..() /obj/item/blueprints/outpost/set_valid_z_levels() - if(!GLOB.using_map.use_overmap) - desc = "Some dusty old blueprints. The markings are old, and seem entirely irrelevant for your wherabouts." - return FALSE - - desc = "Blueprints for the daring souls wanting to establish a planetary outpost. Has some sketchy looking stains and what appears to be bite holes." - var/area/overmap/map = locate() in world - - for(var/obj/effect/overmap/visitable/sector/exoplanet/E in map) - valid_z_levels += E.map_z - - return TRUE \ No newline at end of file + var/turf/T = get_turf(src) + if(istype(T) && length(global.using_map.overmap_ids)) + var/obj/effect/overmap/visitable/sector/S = global.overmap_sectors[T.z] + if(istype(S)) + T = locate(1, 1, S.z) + var/area/overmap/map = T && get_area(T) + if(istype(map)) + desc = "Blueprints for the daring souls wanting to establish a planetary outpost. Has some sketchy looking stains and what appears to be bite holes." + for(var/obj/effect/overmap/visitable/sector/planetoid/E in map) + valid_z_levels |= E.map_z + return TRUE + desc = "Some dusty old blueprints. The markings are old, and seem entirely irrelevant for your whereabouts." + return FALSE + +//For use on /obj/effect/overmap/visitable/ship/landable ships. +/obj/item/blueprints/shuttle + var/shuttle_name // If set, use this (modified by map hash). Otherwise, check for a landable ship and use that. + +/obj/item/blueprints/shuttle/set_valid_z_levels() + var/turf/T = get_turf(src) + if(istype(T) && length(global.using_map.overmap_ids) && global.overmap_sectors[T.z]) + var/obj/effect/overmap/visitable/ship/landable/S = global.overmap_sectors[T.z] + if(isnull(shuttle_name)) + shuttle_name = S.shuttle + update_linked_name(S, null, S.name) + events_repository.register(/decl/observ/name_set, S, src, PROC_REF(update_linked_name)) + events_repository.register(/decl/observ/destroyed, S, src, PROC_REF(on_shuttle_destroy)) + valid_z_levels += S.map_z + area_prefix = S.name + return TRUE + // The blueprints are useless now, but keep them around for fluff. + desc = "Some dusty old blueprints. The markings are old, and seem entirely irrelevant for your whereabouts." + return FALSE + +/obj/item/blueprints/shuttle/proc/update_linked_name(atom/namee, old_name, new_name) + name = "\improper [new_name] blueprints" + desc = "Blueprints of \the [new_name]. There are several coffee stains on it." + +/obj/item/blueprints/shuttle/proc/on_shuttle_destroy(datum/destroyed) + events_repository.unregister(/decl/observ/name_set, destroyed, src, PROC_REF(update_linked_name)) + events_repository.unregister(/decl/observ/destroyed, destroyed, src, PROC_REF(on_shuttle_destroy)) + name = initial(name) + desc = "Some dusty old blueprints. The markings are old, and seem entirely irrelevant for your whereabouts." + valid_z_levels = list() + area_prefix = null + +/obj/item/blueprints/shuttle/create_blueprint_extension() + set_extension(src, /datum/extension/eye/blueprints/shuttle) + +/obj/item/blueprints/shuttle/get_look_args() // ditto + return list(valid_z_levels, area_prefix, shuttle_name) \ No newline at end of file diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index 1dde4f6703ab..f3b1c0e3a00a 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -6,27 +6,26 @@ icon = 'icons/obj/closets/bodybag.dmi' icon_state = "bodybag_folded" w_class = ITEM_SIZE_SMALL - attack_self(mob/user) - var/obj/structure/closet/body_bag/R = new /obj/structure/closet/body_bag(user.loc) - R.add_fingerprint(user) - qdel(src) + material = /decl/material/solid/organic/plastic + var/bag_type = /obj/structure/closet/body_bag +/obj/item/bodybag/proc/create_bag_structure(mob/user) + var/atom/bag = new bag_type(user.loc) + bag.add_fingerprint(user) + return bag -/obj/item/storage/box/bodybags - name = "body bags" - desc = "This box contains body bags." - icon_state = "bodybags" +/obj/item/bodybag/attack_self(mob/user) + create_bag_structure(user) + qdel(src) + return TRUE -/obj/item/storage/box/bodybags/Initialize() - . = ..() - new /obj/item/bodybag(src) - new /obj/item/bodybag(src) - new /obj/item/bodybag(src) - new /obj/item/bodybag(src) - new /obj/item/bodybag(src) - new /obj/item/bodybag(src) - new /obj/item/bodybag(src) +/obj/item/box/bodybags + name = "body bags" + desc = "This box contains body bags." + icon_state = "bodybags" +/obj/item/box/bodybags/WillContain() + return list(/obj/item/bodybag = 7) /obj/structure/closet/body_bag name = "body bag" @@ -36,33 +35,21 @@ open_sound = 'sound/items/zip.ogg' close_sound = 'sound/items/zip.ogg' var/item_path = /obj/item/bodybag - density = 0 + density = FALSE storage_capacity = (MOB_SIZE_MEDIUM * 2) - 1 - var/contains_body = 0 - var/has_label = FALSE - -/obj/structure/closet/body_bag/attackby(var/obj/item/W, mob/user) - if (istype(W, /obj/item/pen)) - var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text - if (user.get_active_hand() != W) - return - if (!in_range(src, user) && src.loc != user) - return - t = sanitizeSafe(t, MAX_NAME_LEN) - if (t) - src.SetName("body bag - ") - src.name += t - has_label = TRUE - else - src.SetName("body bag") - src.update_icon() - return - else if(isWirecutter(W)) - src.SetName("body bag") - has_label = FALSE - to_chat(user, "You cut the tag off \the [src].") - src.update_icon() - return + var/contains_body = FALSE + +/obj/structure/closet/body_bag/Initialize() + . = ..() + set_extension(src, /datum/extension/labels/single) //Set the label extension to a single allowed label + +/obj/structure/closet/body_bag/SetName(new_name) + . = ..() + update_icon() //Since adding a label updates the name, this handles updating the label overlay + +/obj/structure/closet/body_bag/can_install_lock() + // It is a plastic bag + return FALSE /obj/structure/closet/body_bag/on_update_icon() if(opened) @@ -70,32 +57,40 @@ else icon_state = "closed_unlocked" - src.overlays.Cut() - if(has_label) - src.overlays += image(src.icon, "bodybag_label") + ..() + var/datum/extension/labels/lbls = get_extension(src, /datum/extension/labels) + if(LAZYLEN(lbls?.labels)) + add_overlay("bodybag_label") + +/obj/structure/closet/body_bag/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/hand_labeler)) + return FALSE //Prevent the labeler from opening the bag when trying to apply a label + . = ..() /obj/structure/closet/body_bag/store_mobs(var/stored_units) contains_body = ..() return contains_body -/obj/structure/closet/body_bag/close() - if(..()) +/obj/structure/closet/body_bag/close(mob/user) + . = ..() + if(.) set_density(0) - return 1 - return 0 + return TRUE + return FALSE /obj/structure/closet/body_bag/proc/fold(var/user) if(!(ishuman(user) || isrobot(user))) return 0 if(opened) return 0 if(contents.len) return 0 - visible_message("[user] folds up the [name]") + visible_message("[user] folds up \the [src]") . = new item_path(get_turf(src)) qdel(src) -/obj/structure/closet/body_bag/MouseDrop(over_object, src_location, over_location) - ..() - if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src)))) - fold(usr) +/obj/structure/closet/body_bag/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && (in_range(src, user) || (src in user.contents))) + fold(user) + return TRUE + . = ..() /obj/item/robot_rack/body_bag name = "stasis bag rack" diff --git a/code/game/objects/items/books/_book.dm b/code/game/objects/items/books/_book.dm index c2366a370033..f9db9deefc36 100644 --- a/code/game/objects/items/books/_book.dm +++ b/code/game/objects/items/books/_book.dm @@ -1,22 +1,29 @@ /obj/item/book name = "book" - icon = 'icons/obj/library.dmi' - icon_state = "book" + icon = 'icons/obj/items/books/book.dmi' + icon_state = ICON_STATE_WORLD throw_speed = 1 throw_range = 5 w_class = ITEM_SIZE_NORMAL //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever) attack_verb = list("bashed", "whacked", "educated") - material = /decl/material/solid/plastic - matter = list(/decl/material/solid/wood = MATTER_AMOUNT_REINFORCEMENT) - - var/dat // Actual page content - var/pencode_dat // Cache pencode if input, so it can be edited later. - var/author // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned - var/unique = 0 // 0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified - var/title // The real name of the book. - var/carved = 0 // Has the book been hollowed out for use as a secret storage item? - var/obj/item/store //What's in the book? + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/organic/paper = MATTER_AMOUNT_REINFORCEMENT) + + /// Actual page content + var/dat + /// Cache pencode if input, so it can be edited later. + var/pencode_dat + /// Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + var/author + /// 0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified + var/unique = FALSE + /// The real name of the book. + var/title + /// Who modified the book last? var/last_modified_ckey + /// If TRUE, mild solvents can dissolve ink off the page. + /// If FALSE, the user instead receives a message about how the text doesn't seem to be normal ink. + var/can_dissolve_text = TRUE // Copied from paper. Todo: generalize. var/const/deffont = "Verdana" @@ -26,129 +33,148 @@ /obj/item/book/Initialize(var/ml) if(!ml && !unique) - SSpersistence.track_value(src, /datum/persistent/book) + SSpersistence.track_value(src, /decl/persistence_handler/book) . = ..() /obj/item/book/Destroy() - if(dat && last_modified_ckey && SSpersistence.is_tracking(src, /datum/persistent/book)) - // Create a new book in nullspace that is tracked by persistence. - // This is so destroying a book does not get rid of someone's - // content, as books with null coords will get spawned in a random - // library bookcase. - var/obj/item/book/backup_book = new(src) - backup_book.dat = dat - backup_book.author = author - backup_book.title = title - backup_book.last_modified_ckey = last_modified_ckey - backup_book.unique = TRUE - backup_book.forceMove(null) - backup_book.SetName(backup_book.title) - - SSpersistence.forget_value(src, /datum/persistent/book) . = ..() + if(SSpersistence.is_tracking(src, /decl/persistence_handler/book)) + . = QDEL_HINT_LETMELIVE + +/// Clears the text written in the book. Used for acetone removing ink. Returns TRUE if successful, FALSE if it can't be dissolved. +/obj/item/book/proc/clear_text() + if(can_dissolve_text) + dat = null + return TRUE + return FALSE + +/obj/item/book/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + var/page_state = "[icon_state]-pages" + if(check_state_in_icon(page_state, icon)) + add_overlay(overlay_image(icon, page_state, COLOR_WHITE, RESET_COLOR)) + +/obj/item/book/proc/get_style_css() + return {" + + "} /obj/item/book/attack_self(var/mob/user) - if(carved) - if(store) - to_chat(user, "\A [store] falls out of [title]!") - store.dropInto(loc) - store = null - return + return try_to_read(user) || ..() + +/obj/item/book/proc/try_to_read(var/mob/user) + if(storage) + var/list/stored = get_stored_inventory() + if(length(stored)) + for(var/atom/movable/thing in stored) + to_chat(user, SPAN_NOTICE("\A [thing] falls out of [title]!")) + thing.dropInto(loc) else - to_chat(user, "The pages of [title] have been cut out!") - return + to_chat(user, SPAN_NOTICE("The pages of [title] have been cut out!")) + return + if(dat) - user.visible_message("[user] opens a book titled \"[src.title]\" and begins reading intently.") - var/processed_dat = user.handle_reading_literacy(user, dat) - if(processed_dat) - show_browser(user, processed_dat, "window=book;size=1000x550") - onclose(user, "book") + user.visible_message("\The [user] opens a book titled \"[title]\" and begins reading intently.") + show_text_to(user) else - to_chat(user, "This book is completely blank!") - -/obj/item/book/attackby(obj/item/W, mob/user) - if(carved == 1) - if(!store) - if(W.w_class < ITEM_SIZE_NORMAL) - if(!user.unEquip(W, src)) - return - store = W - to_chat(user, "You put [W] in [title].") - return - else - to_chat(user, "[W] won't fit in [title].") - return - else - to_chat(user, "There's already something in [title]!") - return - if(istype(W, /obj/item/pen)) + to_chat(user, SPAN_WARNING("This book is completely blank!")) + +/// Reader is the mob doing the reading, whose skill will be used for skillchecks. User is the mob who is holding the book, and do_afters will use them. +/obj/item/book/proc/show_text_to(mob/reader, mob/user) + var/processed_dat = reader.handle_reading_literacy(reader, dat) + if(processed_dat) + show_browser(reader, processed_dat, "window=book;size=1000x550") + onclose(reader, "book") + +/obj/item/book/attackby(obj/item/used_item, mob/user) + + if(IS_PEN(used_item)) if(unique) - to_chat(user, "These pages don't seem to take the ink well. Looks like you can't modify it.") - return + to_chat(user, SPAN_WARNING("These pages don't seem to take the ink well. Looks like you can't modify it.")) + return TRUE + var/choice = input("What would you like to change?") in list("Title", "Contents", "Author", "Cancel") switch(choice) if("Title") - var/newtitle = reject_bad_text(sanitizeSafe(input("Write a new title:"))) + var/newtitle = reject_bad_text(sanitize_safe(input("Write a new title:"))) if(!newtitle) - to_chat(usr, "The title is invalid.") - return + to_chat(usr, SPAN_WARNING("The title is invalid.")) else newtitle = usr.handle_writing_literacy(usr, newtitle) if(newtitle) last_modified_ckey = user.ckey title = newtitle SetName(title) - if("Contents") + if("Contents") var/content = sanitize(input(usr, "What would you like your book to say?", "Editing Book", pencode_dat) as message|null, MAX_BOOK_MESSAGE_LEN) if(!content) - to_chat(usr, "The content is invalid.") - return + to_chat(usr, SPAN_WARNING("The content is invalid.")) else content = usr.handle_writing_literacy(usr, content) if(content) last_modified_ckey = user.ckey pencode_dat = content - dat = formatpencode(usr, content, W) + dat = formatpencode(usr, content, used_item) if("Author") var/newauthor = sanitize(input(usr, "Write the author's name:")) if(!newauthor) - to_chat(usr, "The name is invalid.") - return + to_chat(usr, SPAN_WARNING("The name is invalid.")) else newauthor = usr.handle_writing_literacy(usr, newauthor) if(newauthor) last_modified_ckey = user.ckey author = newauthor - else - return - else if(istype(W, /obj/item/knife) || isWirecutter(W)) - if(carved) return - to_chat(user, "You begin to carve out [title].") - if(do_after(user, 30, src)) - to_chat(user, "You carve out the pages from [title]! You didn't want to read it anyway.") - carved = 1 - return + return TRUE + + if((IS_KNIFE(used_item) || IS_WIRECUTTER(used_item)) && user.check_intent(I_FLAG_HARM) && try_carve(user, used_item)) + return TRUE + + return ..() + +/obj/item/book/proc/try_carve(mob/user, obj/item/tool) + if(storage) + to_chat(user, SPAN_WARNING("\The [src] has already been carved out.")) else - ..() + to_chat(user, SPAN_NOTICE("You begin to carve out [title] with \the [tool].")) + if(do_after(user, 3 SECONDS, src) && !storage) + to_chat(user, SPAN_NOTICE("You carve out the pages from [title] with \the [tool]! You didn't want to read it anyway.")) + storage = new /datum/storage/book(src) + return TRUE -/obj/item/book/attack(mob/living/carbon/M, mob/living/carbon/user) - if(user.zone_sel.selecting == BP_EYES) - user.visible_message("You open up the book and show it to [M]. ", \ - " [user] opens up a book and shows it to [M]. ") +/obj/item/book/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(user.get_target_zone() == BP_EYES) + user.visible_message( + SPAN_NOTICE("You open up the book and show it to \the [target]."), + SPAN_NOTICE("\The [user] opens up a book and shows it to \the [target].") + ) user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //to prevent spam - var/processed_dat = M.handle_reading_literacy(user, "Author: [author].

              " + "[dat]") - if(processed_dat) - show_browser(M, processed_dat, "window=book;size=1000x550") + show_text_to(target) + return TRUE + return ..() // Copied from paper for the most part. TODO: generalize. /obj/item/book/proc/formatpencode(var/mob/user, var/t, var/obj/item/pen/P) . = t if(findtext(t, "\[sign\]")) - . = replacetext(t, "\[sign\]", "[P ? P.get_signature(user) : "Anonymous"]") + var/decl/tool_archetype/pen/parch = GET_DECL(TOOL_PEN) + var/signature = parch.get_signature(user, P) + . = replacetext(t, "\[sign\]", "[signature]") + + var/pen_flag = P.get_tool_property(TOOL_PEN, TOOL_PROP_PEN_FLAG) + var/pen_color = P.get_tool_property(TOOL_PEN, TOOL_PROP_COLOR) if(P) - if(P.iscrayon) + if(pen_flag & PEN_FLAG_CRAYON) . = replacetext(t, "\[*\]", "") . = replacetext(t, "\[hr\]", "") . = replacetext(t, "\[small\]", "") @@ -160,28 +186,28 @@ . = replacetext(t, "\[row\]", "") . = replacetext(t, "\[cell\]", "") . = replacetext(t, "\[logo\]", "") - . = "[.]" - else if(P.isfancy) - . = "[.]" + . = "[.]" + else if(pen_flag & PEN_FLAG_FANCY) + . = "[.]" else - . = "[.]" + . = "[.]" else . = "[.]" . = pencode2html(.) /obj/item/book/printable_black - icon_state = "book1" + icon = 'icons/obj/items/books/book_printable_black.dmi' /obj/item/book/printable_red - icon_state = "book2" + icon = 'icons/obj/items/books/book_printable_red.dmi' /obj/item/book/printable_yellow - icon_state = "book3" + icon = 'icons/obj/items/books/book_printable_yellow.dmi' /obj/item/book/printable_blue - icon_state = "book4" + icon = 'icons/obj/items/books/book_printable_blue.dmi' /obj/item/book/printable_green - icon_state = "book5" + icon = 'icons/obj/items/books/book_printable_green.dmi' /obj/item/book/printable_purple - icon_state = "book6" + icon = 'icons/obj/items/books/book_printable_purple.dmi' /obj/item/book/printable_light_blue - icon_state = "book7" + icon = 'icons/obj/items/books/book_printable_light_blue.dmi' /obj/item/book/printable_magazine - icon_state = "bookMagazine" + icon = 'icons/obj/items/books/book_printable_magazine.dmi' diff --git a/code/game/objects/items/books/_book_serde.dm b/code/game/objects/items/books/_book_serde.dm new file mode 100644 index 000000000000..25251936e1d9 --- /dev/null +++ b/code/game/objects/items/books/_book_serde.dm @@ -0,0 +1,31 @@ +/obj/item/book/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(last_modified_ckey, /obj/item/book) + SERIALIZE_IF_MODIFIED(dat, /obj/item/book) + SERIALIZE_IF_MODIFIED(title, /obj/item/book) + SERIALIZE_IF_MODIFIED(author, /obj/item/book) + SERIALIZE_IF_MODIFIED(icon_state, /atom) + +/obj/item/book/Deserialize() + . = ..() + SSpersistence.track_value(src, /decl/persistence_handler/book) + +/obj/item/book/GetPossiblySerializableInstances() + . = ..() + if(istype(loc, /obj/structure/bookcase)) + LAZYDISTINCTADD(., loc) + +/obj/item/book/Deserialize(list/instance_map) + ..() + return SERDE_HINT_POSTINIT + +/obj/item/book/DeserializePostInit(list/instance_map) + . = ..() + var/area/area = get_area(src) + if(!area || (area.area_flags & AREA_FLAG_NO_LEGACY_PERSISTENCE)) + forceMove(null) + if(isnull(loc)) + if(length(global.station_bookcases)) + forceMove(pick(global.station_bookcases)) + else + forceMove(get_random_spawn_turf(SPAWN_FLAG_PERSISTENCE_CAN_SPAWN)) diff --git a/code/game/objects/items/books/fluff/_fluff.dm b/code/game/objects/items/books/fluff/_fluff.dm new file mode 100644 index 000000000000..f7ce2ae2fbdd --- /dev/null +++ b/code/game/objects/items/books/fluff/_fluff.dm @@ -0,0 +1,20 @@ +/obj/item/book/fluff + unique = TRUE + abstract_type = /obj/item/book/fluff + var/fluff_text + +/obj/item/book/fluff/Initialize() + . = ..() + if(!fluff_text) + log_debug("Fluff book [type] spawned with no fluff text.") + return INITIALIZE_HINT_QDEL + dat = {" + + + [get_style_css()] + + + [fluff_text] + + + "} diff --git a/code/game/objects/items/books/fluff/science.dm b/code/game/objects/items/books/fluff/science.dm new file mode 100644 index 000000000000..eee65121cb97 --- /dev/null +++ b/code/game/objects/items/books/fluff/science.dm @@ -0,0 +1,133 @@ +/obj/item/book/fluff/anomaly_spectroscopy + name = "Spectroscopy: Analysing the Anomalies of the Cosmos" + icon = 'icons/obj/items/books/book_anomaly.dmi' + author = "Doctor Martin Boyle, Director Research at the Lower Hydrolian Sector Listening Array" + title = "Spectroscopy: Analysing the Anomalies of the Cosmos" + fluff_text = {" + It's perhaps one of the most exciting times to be alive, with the recent breakthroughs in understanding and categorisation of things we may one day no longer call + 'anomalies,' but rather 'infrequent or rare occurrences of certain celestial weather or phenomena.' Perhaps a little more long-winded, but no less eloquent all the + same! Why, look at the strides we're making in piercing the walls of spacetime or our steadily improving ability to clarify and stabilise subspace emissions; it's + certainly an exciting time to be alive. For the moment, the Hydrolian hasn't seen two spatial anomalies alike but the day will come and it is soon, I can feel it. + "} + +/obj/item/book/fluff/materials_chemistry_analysis + name = "Materials Analysis and the Chemical Implications" + icon = 'icons/obj/items/books/book_chemistry_alt.dmi' + author = "Jasper Pascal, Senior Lecturer in Materials Analysis at the University of Jol'Nar" + title = "Materials Analysis and the Chemical Implications" + fluff_text = {" + In today's high-tech research fields, leaps and bounds are being made every day. Whether it's great strides forward in our understanding of the physical universe + or the operation of some fancy new piece of equipment, it seems like all the cool fields are producing new toys to play with, leaving doddery old fields such as + materials analysis and chemistry relegated to the previous few centuries, when we were still learning the makeup and structure of the elements. +

              + Well, when you're out there building the next gryo-whatsitron or isotope mobility thingummy, remember how the field of archaeology experienced a massive new rebirth + following the excavations at Paranol IV and consider how all of the scientific greats will come crawling back to basic paradigms of natural philosophy when they discover + a new element that defies classification. I defy you to classify it without reviving this once great field! + "} + +/obj/item/book/fluff/anomaly_testing + name = "Anomalous Materials and Energies" + icon = 'icons/obj/items/books/book_triangulate.dmi' + author = "Norman York, formerly of the Tyrolion Institute on Titan" + title = "Anomalous Materials and Energies" + fluff_text = {" +

              Contents

              +
                +
              1. Foreword: Modern attitude towards anomalies
              2. +
              3. Triangulating anomalous energy readings
              4. +
              5. Harvesting and utilising anomalous energy signatures
              6. +
              +
              +

              Modern attitude towards anomalies

              + It's only when confronted with things we don't know, that we may push back our knowledge of the world around us. Nowhere is this more obvious than the + vast and inscrutable mysterious of the cosmos that scholars from such august institutions as the Elysian Institute of the Sciences present + formulas and hypotheses for every few decades.
              +
              + Using our vast, telescopic array installations and deep space satellite networks, we are able to detect anomalous energy fields and formations in deep space, + but are limited to those that are large enough to output energy that will stretch across light years worth of distance between stars.
              +
              + While some sectors (such as the Hydrolian Rift and Keppel's Run) are replete with inexplicable energetic activity and unique phenomena found nowhere else in + the galaxy, the majority of space is dry, barren and cold - and if past experience has told us anything, it is that there are always more things we are + unable to explain.
              +
              + Indeed, a great source of knowledge and technology has always been those who come before us, in the form of the multitudinous ancient alien precursors that + have left scattered remnants of their great past all over settled (and unexplored) space.
              +
              + It is from xenoarchaeologists, high energy materials researchers, and technology reconstruction authorities that we are able to theorise on the gifts these + species have left behind, and in some cases even reverse engineer or rebuild the technology in question. My colleague, Doctor Raymond Ward of the + Tyrolian Institute on Titan, has made great breakthroughs in a related field through his pioneering development of universally reflective materials capable + of harvesting and 'bottling' up virtually any energy emissions yet encountered by spacefaring civilisations.
              +
              + And yet, there are some amongst us who do not see the benefits of those who have come before us - indeed, some among them profess the opinion that there + is no species that could possibly match humanity in it's achievements and knowledge, or simply that employing non-human technology is dangerous and unethical. + Folly, say I. If it is their desire to throw onto the wayside the greatest achievements in the history of the galaxy, simply for preferment of the + greatest achievements in the history of mankind, then they have no business in the establishment of science.
              + Contents +

              Triangulating anomalous energy readings

              + Strong energy emissions, when remaining constant from any one fixed location for millennia, can leave an 'imprint' or distinctive energy signature on other + matter composites that are spatially fixed relative to the source.
              +
              + By taking samples of such 'fixed' matter, we can apply complex analytics such as the modified Fourier Transform Procedure to reverse engineer the path of the + energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space. Modern portable devices can do + all this purely by taking readings of local radiation.
              +
              + A canny researcher can thusly analyse radiation at pre-chosen points strategically scattered around an area, and if there are any anomalous energy + emissions in range of those points, combined the researcher can triangulate the source.
              + Contents +

              Harvesting and utilising anomalous energy signatures

              + As mentioned in the foreword, my colleague from the Tyrolian Institute on Saturn's moon of Titan, in the Sol System, Doctor Raymond Ward has made great strides + in the area of harvesting and application of the energy emitted by anomalous phenomena from around the galaxy (although I profess I have not yet seen him + venture further from his birthplace on Earth than the comfortable distance of the Sol Cis-Oort Satellite Sphere).
              +
              + By employing a patented semi-phased alloy with unique and fascinating properties, Ward's contraption is able to 'harvest' energy, store + it and redirect it later at will (with appropriate electronic mechanisms, of course). Although he professes to see or desire no commercial or material gain + for the application and use of said energy once it is harvested, there are no doubt myriad ways we can come to benefit from such things beyond mere research, + such as the reconstruction of torn cartilaginous tissue that a peculiar radiation from an amphibious species on Brachis IV was found to emit.
              + Contents + "} + +/obj/item/book/fluff/stasis + name = "Cellular Suspension, the New Cryogenics?" + icon = 'icons/obj/items/books/book_stasis.dmi' + author = "Elvin Schmidt" + title = "Cellular Suspension, the New Cryogenics?" + fluff_text = {" +

              Contents

              +
                +
              1. Foreword: A replacement for cryosleep?
              2. +
              3. The breakthrough
              4. +
              5. Applying this new principle
              6. +
              +
              +

              Foreword: A replacement for cryosleep?

              + The development of rudimentary cryofreezing in the 20th and 21st centuries was hailed as a crank science by some, but many early visionaries recognised the + potential it had to change the way we approach so many fields, such as medicine, therapeutics, and space travel. It was breakthroughs in the field in the 22nd and + later centuries that turned the procedure from science fiction to science fact, however. Since then, cryogenics has become a hallmark of modern science, and + regarded as one of the great achievements of our era. As with all sciences however, they have their time and are superseded by newer technological miracles when + it is over.
              + Contents +

              The breakthrough

              + It was in examining the effects of decelerated high energy particles when transphased through a gravitational lens that the effects where primarily noticed. + Due to exigent properties of that dimension, transphasing those particles capable of existing with high stability levels has the effect of bringing + some of those effects into realspace. Examining the Hoffman emissions in particular, it was discovered that they exhibited a-entropic behaviour, and in what is + now termed the 'Effete Hoffman Principle,' it was found that metastabilising the Hoffman radiation resulted in the effect being applied across other physical + interactions, in particular forces and reactions.
              + Contents +

              Applying this new principle

              + When combined with an appropriate energy-effect replicate for cryogenics (slowing down biological activity, thus stabilising the organics), the effect is + effectively identical to cryogenics, and while it consumes vastly more power and requires extremely complex equipment, it's (for all intents and purposes) superior + to cryogenics, all that remains is to 'commercialise' the process by enabling cheaper development and mass production.
              + The Effete Hoffman Principle can be tweak-combined with other effects however, for different purposes. A division of PMC Research initially developed the application + in prisons as a literal 'suspension field' where convicts are held immobile in the air, and the use quickly spread to numerous other areas.
              +
              + By examining the material resonance properties of certain strong waveforms when combined with Hoffman radiation, an effect was produced able to reverse energy + transferral through matter, and to slow the effects of gravity. When combined with energy repulse technology, the triple effects compound themselves into a much + stronger field, although all three components do slightly different things. High energy researchers assure me of the following key points:
              +
                +
              • The energy repulsion factor provides a 'shell' capable of weak suspension.
              • +
              • The Hoffman emissions nullify energy transferral and other kinetic activity, maintaining stability inside the field.
              • +
              • The resonant waveform combines the effects of the above two points, and applies it magnified onto it's synced 'resonance' materials.
              • +
              + As an interesting aside, a carbon waveform was chosen for the field in prison suspension fields, due to it's resonance with organic matter.
              + Contents + "} diff --git a/code/game/objects/items/books/manuals/_manual.dm b/code/game/objects/items/books/manuals/_manual.dm index aa5c491e6f1b..8d09360270e9 100644 --- a/code/game/objects/items/books/manuals/_manual.dm +++ b/code/game/objects/items/books/manuals/_manual.dm @@ -1,27 +1,47 @@ /obj/item/book/manual - icon = 'icons/obj/library.dmi' - unique = 1 // 0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified - var/url // Using full url or just tittle, example - Standard_Operating_Procedure (https://wiki.baystation12.net/index.php?title=Standard_Operating_Procedure) + unique = TRUE // Unable to be copied, unable to be modified + abstract_type = /obj/item/book/manual + var/guide_decl + var/tmp/has_initialized = FALSE /obj/item/book/manual/Initialize() . = ..() - if(url) // URL provided for this manual - // If we haven't wikiurl or it included in url - just use url - if(config.wikiurl && !findtextEx(url, config.wikiurl, 1, length(config.wikiurl)+1)) - // If we have wikiurl, but it hasn't "index.php" then add it and making full link in url - if(config.wikiurl && !findtextEx(config.wikiurl, "/index.php", -10)) - if(findtextEx(config.wikiurl, "/", -1)) - url = config.wikiurl + "index.php?title=" + url - else - url = config.wikiurl + "/index.php?title=" + url - else //Or just making full link in url - url = config.wikiurl + "?title=" + url - dat = {" - - - - - - - - "} + // try to initialize the text! if it's prior to sscodex init it'll initialize on being read + // if the guide is invalid the manual will need to be deleted + if(initialize_data(in_init = TRUE) == INITIALIZE_HINT_QDEL) + return INITIALIZE_HINT_QDEL + +/obj/item/book/manual/try_to_read() + initialize_data() + . = ..() + +/obj/item/book/manual/show_text_to() + initialize_data() + . = ..() + +/obj/item/book/manual/clear_text() + if((. = ..())) + has_initialized = TRUE // prevent data from being added later if it hasn't already been + +/obj/item/book/manual/proc/initialize_data(in_init = FALSE) + if(has_initialized || !SScodex.initialized) + return + // Has yet to initialize. + var/guide_text = guide_decl && SScodex.get_manual_text(guide_decl) + if(!guide_text) + log_debug("Manual [type] spawned with invalid guide decl type ([guide_decl || null]).") + if(in_init) + return INITIALIZE_HINT_QDEL + qdel(src) + return + dat = {" + + + [get_style_css()] + + + [guide_text] + + + "} + has_initialized = TRUE diff --git a/code/game/objects/items/books/manuals/engineering.dm b/code/game/objects/items/books/manuals/engineering.dm index 14adfa45e01b..bad39f2562ce 100644 --- a/code/game/objects/items/books/manuals/engineering.dm +++ b/code/game/objects/items/books/manuals/engineering.dm @@ -1,685 +1,69 @@ /obj/item/book/manual/engineering_guide - name = "Engineering Textbook" - icon_state ="bookEngineering2" + name = "engineering reference manual" + icon = 'icons/obj/items/books/book_engineering_alt.dmi' author = "Engineering Encyclopedia" title = "Engineering Textbook" - url = "Engineering" + guide_decl = /datum/codex_entry/guide/engineering /obj/item/book/manual/robotics_cyborgs - name = "Cyborgs for Dummies" - icon_state = "borgbook" + name = "robotics reference manual" + icon = 'icons/obj/items/books/book_cyborg.dmi' author = "XISC" title = "Cyborgs for Dummies" - - dat = {" - - - - - -

              Cyborgs for Dummies

              - -

              Chapters

              - -
                -
              1. Cyborg Related Equipment
              2. -
              3. Cyborg Modules
              4. -
              5. Cyborg Construction
              6. -
              7. Cyborg Maintenance
              8. -
              9. Cyborg Repairs
              10. -
              11. In Case of Emergency
              12. -
              - - -

              Cyborg Related Equipment

              - -

              Exosuit Fabricator

              - The Exosuit Fabricator is the most important piece of equipment related to cyborgs. It allows the construction of the core cyborg parts. Without these machines, cyborgs cannot be built. It seems that they may also benefit from advanced research techniques. - -

              Cyborg Recharging Station

              - This useful piece of equipment will suck power out of the power systems to charge a cyborg's power cell back up to full charge. - -

              Robotics Control Console

              - This useful piece of equipment can be used to immobilize or destroy a cyborg. A word of warning: Cyborgs are expensive pieces of equipment, do not destroy them without good reason, or the Company may see to it that it never happens again. - - -

              Cyborg Modules

              - When a cyborg is created it picks out of an array of modules to designate its purpose. There are 11 different cyborg modules.
              - All cyborg modules carry a flash. - -

              Standard Cyborg

              - The standard cyborg module is a multi-purpose cyborg. It is equipped with various modules, allowing it to do basic tasks.
              A Standard Cyborg comes with: -
                -
              • Crowbar
              • -
              • Wrench
              • -
              • Stun Baton
              • -
              • Health Analyzer
              • -
              • Fire Extinguisher
              • -
              - -

              Research Cyborg

              - The research cyborg module is an effective researching machine. It is equipped with tools to effectively run RnD.A Research Cyborg comes with: -
                -
              • Portable Destructive Analyzer
              • -
              • Research Gripper
              • -
              • Sheet Loader
              • -
              • Robot Analyzer
              • -
              • Robot Card
              • -
              • Set of Engineering Tools
              • -
              • Laser Scalpel
              • -
              • Circular Saw
              • -
              • Fire Extinguisher
              • -
              • Syringe
              • -
              • Chemistry Gripper
              • -
              • Nanopaste
              • -
              - -

              Engineering Cyborg

              - The Engineering cyborg module comes equipped with various engineering-related tools to help with engineering-related tasks.
              An Engineering Cyborg comes with: -
                -
              • A basic set of engineering tools
              • -
              • Metal Synthesizer
              • -
              • Plasteel Synthesizer
              • -
              • Reinforced Glass Synthesizer
              • -
              • Wire Synthesizer
              • -
              • Fire Extinguisher
              • -
              • Roll of Tape
              • -
              • Built-in Optical Meson Scanners
              • -
              - -

              Mining Cyborg

              - The Mining Cyborg module comes equipped with the latest in mining equipment. They are efficient at mining due to no need for oxygen, but their power cells limit their time in the mines.
              A Mining Cyborg comes with: -
                -
              • Wrench
              • -
              • Scredriver
              • -
              • Crowbar
              • -
              • Ore Satchel
              • -
              • Borg Drill
              • -
              • Mining Gripper
              • -
              • Ore Scanner
              • -
              - -

              Security Cyborg

              - The Security Cyborg module is equipped with effective security measures used to apprehend and arrest criminals.
              A Security Cyborg comes with: -
                -
              • Stun Baton
              • -
              • Handcuffs
              • -
              • Energy Gun
              • -
              • Megaphone
              • -
              • Roll of Tape
              • -
              - -

              Janitor Cyborg

              - The Janitor Cyborg module is equipped with various cleaning-facilitating devices.
              A Janitor Cyborg comes with: -
                -
              • Mop
              • -
              • Hand Bucket
              • -
              • Cleaning Spray Synthesizer and Spray Nozzle
              • -
              • Light Replacer
              • -
              • Trash Bag
              • -
              - -

              Service Cyborg

              - The service cyborg module comes ready to serve your human needs. It includes various entertainment and refreshment devices. Occasionally some service cyborgs may have been referred to as "Bros."
              A Service Cyborg comes with: -
                -
              • Service Gripper
              • -
              • Bucket
              • -
              • Hoe
              • -
              • Hatchet
              • -
              • Zippo Lighter
              • -
              • Rapid-Service-Fabricator (Produces various entertainment and refreshment objects)
              • -
              • Plant Analyzer
              • -
              • Robot Harvester
              • -
              • Rolling Pin
              • -
              • Knife
              • -
              - -

              Clerical Cyborg

              - The clerical cyborg module is prepared to run the supply department, including a vareity of stamps.
              A clerical cyborg comes with: -
                -
              • Pen
              • -
              • Paper Dispenser
              • -
              • Clerical Gripper
              • -
              • Hand Labeler
              • -
              • Generic Stamp
              • -
              • Denied Stamp
              • -
              • Package Wrapper
              • -
              • Destination Tagger
              • -
              - -

              Crisis Cyborg

              - The crisis cyborg module is prepared to handle a variety of non-surgical medical emergencies.
              A medical cyborg comes with: -
                -
              • Crowbar
              • -
              • Health Analyzer
              • -
              • Reagent Scanner
              • -
              • Roller Bed Rack
              • -
              • Body Bag Rack
              • -
              • Hypospray
              • -
              • Automatic Defibrillator
              • -
              • Industrial Dropper
              • -
              • Syringe
              • -
              • Chemistry Gripper
              • -
              • Fire Extinguisher
              • -
              • Inflatables Dispenser
              • -
              • Roll of Tape
              • -
              - -

              Surgeon Cyborg

              - The surgeon cyborg modules is prepared to handle a variety of surgical medical emergencies.
              A medical cyborg comes with: -
                -
              • Set of Surgery Tools
              • -
              • Health Analyzer
              • -
              • Roller Bed Rack
              • -
              • Body Bag Rack
              • -
              • Hypospray
              • -
              • Automatic Defibrillator
              • -
              • Industrial Dropper
              • -
              • Syringe
              • -
              • Chemistry Gripper
              • -
              • Fire Extinguisher
              • -
              • Inflatables Dispenser
              • -
              • Roll of Tape
              • -
              - -

              Cyborg Construction

              - Cyborg construction is a rather easy process, requiring a decent amount of metal and a few other supplies.
              The required materials to make a cyborg are: -
                -
              • Metal
              • -
              • Two Flashes
              • -
              • One Power Cell (Preferably rated to 15000w)
              • -
              • Some electrical wires
              • -
              • One Human Brain
              • -
              • One Man-Machine Interface
              • -
              - Once you have acquired the materials, you can start on construction of your cyborg.
              To construct a cyborg, follow the steps below: -
                -
              1. Start the Exosuit Fabricators constructing all of the cyborg parts
              2. -
              3. While the parts are being constructed, take your human brain, and place it inside the Man-Machine Interface
              4. -
              5. Once you have a Robot Head, place your two flashes inside the eye sockets
              6. -
              7. Once you have your Robot Chest, wire the Robot chest, then insert the power cell
              8. -
              9. Attach all of the Robot parts to the Robot frame
              10. -
              11. Insert the Man-Machine Interface (With the Brain inside) into the Robot Body
              12. -
              13. Congratulations! You have a new cyborg!
              14. -
              - -

              Cyborg Maintenance

              - Occasionally Cyborgs may require maintenance of a couple types, this could include replacing a power cell with a charged one, or possibly maintaining the cyborg's internal wiring. - -

              Replacing a Power Cell

              - Replacing a Power cell is a common type of maintenance for cyborgs. It usually involves replacing the cell with a fully charged one, or upgrading the cell with a larger capacity cell.
              The steps to replace a cell are as follows: -
                -
              1. Unlock the Cyborg's Interface by swiping your ID on it
              2. -
              3. Open the Cyborg's outer panel using a crowbar
              4. -
              5. Remove the old power cell
              6. -
              7. Insert the new power cell
              8. -
              9. Close the Cyborg's outer panel using a crowbar
              10. -
              11. Lock the Cyborg's Interface by swiping your ID on it, this will prevent non-qualified personnel from attempting to remove the power cell
              12. -
              - -

              Exposing the Internal Wiring

              - Exposing the internal wiring of a cyborg is fairly easy to do, and is mainly used for cyborg repairs.
              You can easily expose the internal wiring by following the steps below: -
                -
              1. Follow Steps 1 - 3 of "Replacing a Cyborg's Power Cell"
              2. -
              3. Open the cyborg's internal wiring panel by using a screwdriver to unsecure the panel
              4. -
              - To re-seal the cyborg's internal wiring: -
                -
              1. Use a screwdriver to secure the cyborg's internal panel
              2. -
              3. Follow steps 4 - 6 of "Replacing a Cyborg's Power Cell" to close up the cyborg
              4. -
              - -

              Cyborg Repairs

              - Occasionally a Cyborg may become damaged. This could be in the form of impact damage from a heavy or fast-travelling object, or it could be heat damage from high temperatures, or even lasers or Electromagnetic Pulses (EMPs). - -

              Dents

              - If a cyborg becomes damaged due to impact from heavy or fast-moving objects, it will become dented. Sure, a dent may not seem like much, but it can compromise the structural integrity of the cyborg, possibly causing a critical failure. - Dents in a cyborg's frame are rather easy to repair, all you need is to apply a welding tool to the dented area, and the high-tech cyborg frame will repair the dent under the heat of the welder. - -

              Excessive Heat Damage

              - If a cyborg becomes damaged due to excessive heat, it is likely that the internal wires will have been damaged. You must replace those wires to ensure that the cyborg remains functioning properly.
              To replace the internal wiring follow the steps below: -
                -
              1. Unlock the Cyborg's Interface by swiping your ID
              2. -
              3. Open the Cyborg's External Panel using a crowbar
              4. -
              5. Remove the Cyborg's Power Cell
              6. -
              7. Using a screwdriver, expose the internal wiring of the Cyborg
              8. -
              9. Replace the damaged wires inside the cyborg
              10. -
              11. Secure the internal wiring cover using a screwdriver
              12. -
              13. Insert the Cyborg's Power Cell
              14. -
              15. Close the Cyborg's External Panel using a crowbar
              16. -
              17. Lock the Cyborg's Interface by swiping your ID
              18. -
              - These repair tasks may seem difficult, but are essential to keep your cyborgs running at peak efficiency. - -

              In Case of Emergency

              - In case of emergency, there are a few steps you can take. - -

              "Rogue" Cyborgs

              - If the cyborgs seem to become "rogue", they may have non-standard laws. In this case, use extreme caution. - To repair the situation, follow these steps: -
                -
              1. Locate the nearest robotics console
              2. -
              3. Determine which cyborgs are "Rogue"
              4. -
              5. Press the lockdown button to immobilize the cyborg
              6. -
              7. Locate the cyborg
              8. -
              9. Expose the cyborg's internal wiring
              10. -
              11. Check to make sure the LawSync and AI Sync lights are lit
              12. -
              13. If they are not lit, pulse the LawSync wire using a multitool to enable the cyborg's LawSync
              14. -
              15. Proceed to a cyborg upload console. The Company usually places these in the same location as AI upload consoles.
              16. -
              17. Use a "Reset" upload moduleto reset the cyborg's laws
              18. -
              19. Proceed to a Robotics Control console
              20. -
              21. Remove the lockdown on the cyborg
              22. -
              - -

              As a last resort

              - If all else fails in a case of cyborg-related emergency, there may be only one option. Using a Robotics Control console, you may have to remotely detonate the cyborg. -

              WARNING:

              Do not detonate a borg without an explicit reason for doing so. Cyborgs are expensive pieces of company equipment, and you may be punished for detonating them without reason. - - - - "} + guide_decl = /datum/codex_entry/guide/robotics /obj/item/book/manual/engineering_construction - name = "Repairs and Construction" - icon_state ="bookEngineering" - author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + name = "repair and construction reference manual" + icon = 'icons/obj/items/books/book_engineering.dmi' + author = "Engineering Encyclopedia" title = "Repairs and Construction" - url = "Guide_to_Construction" + guide_decl = /datum/codex_entry/guide/construction /obj/item/book/manual/engineering_particle_accelerator - name = "Particle Accelerator User's Guide" - icon_state ="bookParticleAccelerator" - author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + name = "particle accelerator reference manual" + icon = 'icons/obj/items/books/book_particle.dmi' + author = "Engineering Encyclopedia" title = "Particle Accelerator User's Guide" - -/obj/item/book/manual/engineering_particle_accelerator/Initialize() - . = ..() - dat = {" - - - - - -

              Experienced User's Guide

              - -

              Setting up the accelerator

              - -
                -
              1. Wrench all pieces to the floor
              2. -
              3. Add wires to all the pieces
              4. -
              5. Close all the panels with your screwdriver
              6. -
              - -

              Using the accelerator

              - -
                -
              1. Open the control panel
              2. -
              3. Set the speed to 2
              4. -
              5. Start firing at the singularity generator
              6. -
              7. When the singularity reaches a large enough size so it starts moving on it's own set the speed down to 0, but don't shut it off
              8. -
              9. Remember to wear a radiation suit when working with this machine... we did tell you that at the start, right?
              10. -
              - - - - "} - - -/obj/item/book/manual/supermatter_engine - name = "Supermatter Engine Operating Manual" - icon_state = "bookSupermatter" - author = "Central Engineering Division" - title = "Supermatter Engine Operating Manual" - url = "Supermatter_Engine" + guide_decl = /datum/codex_entry/guide/particle_accelerator /obj/item/book/manual/rust_engine - name = "R-UST Operating Manual" + name = "fusion reactor reference Manual" icon_state = "bookMagazine" author = "Cindy Crawfish" title = "R-UST Operating Manual" - url = "R-UST" + guide_decl = /datum/codex_entry/guide/fusion /obj/item/book/manual/engineering_hacking - name = "Hacking" - icon_state ="bookHacking" - author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + name = "hacking reference manual" + icon = 'icons/obj/items/books/book_hacking.dmi' + author = "Engineering Encyclopedia" title = "Hacking" - url = "Hacking" + guide_decl = /datum/codex_entry/guide/hacking /obj/item/book/manual/engineering_singularity_safety - name = "Singularity Safety in Special Circumstances" - icon_state ="bookEngineeringSingularitySafety" - author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + name = "singularity engine reference manual" + icon = 'icons/obj/items/books/book_singularity.dmi' + author = "Engineering Encyclopedia" title = "Singularity Safety in Special Circumstances" - - dat = {" - - - - -

              Singularity Safety in Special Circumstances

              - -

              Power outage

              - - A power problem has made you lose power? Could be wiring problems or syndicate power sinks. In any case follow these steps: - -
                -
              1. PANIC!
              2. -
              3. Get your ass over to engineering! QUICKLY!!!
              4. -
              5. Get to the Area Power Controller which controls the power to the emitters.
              6. -
              7. Swipe it with your ID card - if it doesn't unlock, continue with step 15.
              8. -
              9. Open the console and disengage the cover lock.
              10. -
              11. Pry open the APC with a Crowbar.
              12. -
              13. Take out the empty power cell.
              14. -
              15. Put in the new, full power cell - if you don't have one, continue with step 15.
              16. -
              17. Quickly put on a Radiation suit.
              18. -
              19. Check if the singularity field generators withstood the down-time - if they didn't, continue with step 15.
              20. -
              21. Since disaster was averted you now have to ensure it doesn't repeat. If it was a powersink which caused it and if the engineering APC is wired to the same powernet, which the powersink is on, you have to remove the piece of wire which links the APC to the powernet. If it wasn't a powersink which caused it, then skip to step 14.
              22. -
              23. Grab your crowbar and pry away the tile closest to the APC.
              24. -
              25. Use the wirecutters to cut the wire which is connecting the grid to the terminal.
              26. -
              27. Go to the bar and tell the guys how you saved them all. Stop reading this guide here.
              28. -
              29. GET THE FUCK OUT OF THERE!!!
              30. -
              - -

              Shields get damaged

              - -
                -
              1. GET THE FUCK OUT OF THERE!!! FORGET THE WOMEN AND CHILDREN, SAVE YOURSELF!!!
              2. -
              - - - "} + guide_decl = /datum/codex_entry/guide/singularity /obj/item/book/manual/ripley_build_and_repair - name = "APLU \"Ripley\" Construction and Operation Manual" + name = "exosuit construction reference manual" icon_state ="book" - author = "Randall Varn, Einstein Engines Senior Mechanic" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + author = "Randall Varn, Einstein Engines Senior Mechanic" title = "APLU \"Ripley\" Construction and Operation Manual" - - dat = {" - - - - -
              -
              - Weyland-Yutani - Building Better Worlds -

              Autonomous Power Loader Unit \"Ripley\"

              -
              -

              Specifications:

              -
                -
              • Class: Autonomous Power Loader
              • -
              • Scope: Logistics and Construction
              • -
              • Weight: 820kg (without operator and with empty cargo compartment)
              • -
              • Height: 2.5m
              • -
              • Width: 1.8m
              • -
              • Top speed: 5km/hour
              • -
              • Operation in vacuum/hostile environment: Possible -
              • Airtank volume: 500 liters
              • -
              • Devices: -
                  -
                • Hydraulic clamp
                • -
                • High-speed drill
                • -
                -
              • -
              • Propulsion device: Powercell-powered electro-hydraulic system
              • -
              • Powercell capacity: Varies
              • -
              - -

              Construction:

              -
                -
              1. Connect all exosuit parts to the chassis frame.
              2. -
              3. Connect all hydraulic fittings and tighten them up with a wrench.
              4. -
              5. Adjust the servohydraulics with a screwdriver.
              6. -
              7. Wire the chassis (Cable is not included).
              8. -
              9. Use the wirecutters to remove the excess cable if needed.
              10. -
              11. Install the central control module (Not included. Use supplied datadisk to create one).
              12. -
              13. Secure the mainboard with a screwdriver.
              14. -
              15. Install the peripherals control module (Not included. Use supplied datadisk to create one).
              16. -
              17. Secure the peripherals control module with a screwdriver.
              18. -
              19. Install the internal armor plating (Not included due to corporate regulations. Can be made using 5 metal sheets).
              20. -
              21. Secure the internal armor plating with a wrench.
              22. -
              23. Weld the internal armor plating to the chassis.
              24. -
              25. Install the external reinforced armor plating (Not included due to corporate regulations. Can be made using 5 reinforced metal sheets).
              26. -
              27. Secure the external reinforced armor plating with a wrench.
              28. -
              29. Weld the external reinforced armor plating to the chassis.
              30. -
              - -

              Additional Information:

              -
                -
              • The firefighting variation is made in a similar fashion.
              • -
              • A firesuit must be connected to the firefighter chassis for heat shielding.
              • -
              • Internal armor is plasteel for additional strength.
              • -
              • External armor must be installed in 2 parts, totalling 10 sheets.
              • -
              • Completed exosuit is more resilient against fire, and is a bit more durable overall.
              • -
              • The Company is determined to ensure the safety of its investments employees.
              • -
              - - - "} + guide_decl = /datum/codex_entry/guide/mech_construction /obj/item/book/manual/atmospipes - name = "Pipes and You: Getting To Know Your Scary Tools" - icon_state = "pipingbook" + name = "atmospherics reference manual" + icon = 'icons/obj/items/books/book_piping.dmi' author = "Maria Crash, Senior Atmospherics Technician" title = "Pipes and You: Getting To Know Your Scary Tools" - dat = {" - - - - - -

              Contents

              -
                -
              1. Author's Foreword
              2. -
              3. Basic Piping
              4. -
              5. Insulated Pipes
              6. -
              7. Atmospherics Devices
              8. -
              9. Heat Exchange Systems
              10. -
              11. Final Checks
              12. -

              - -

              HOW TO NOT SUCK QUITE SO HARD AT ATMOSPHERICS


              - Or: What the fuck does a "pressure regulator" do?

              - - Alright. It has come to my attention that a variety of people are unsure of what a "pipe" is and what it does. - Apparently, there is an unnatural fear of these arcane devices and their "gases." Spooky, spooky. So, - this will tell you what every device constructable by an ordinary pipe dispenser within atmospherics actually does. - You are not going to learn what to do with them to be the super best person ever, or how to play guitar with passive gates, - or something like that. Just what stuff does.

              - - -

              Basic Pipes

              - The boring ones.
              - Most ordinary pipes are pretty straightforward. They hold gas. If gas is moving in a direction for some reason, gas will flow in that direction. - That's about it. Even so, here's all of your wonderful pipe options.
              - -
                -
              • Straight pipes: They're pipes. One-meter sections. Straight line. Pretty simple. Just about every pipe and device is based around this - standard one-meter size, so most things will take up as much space as one of these.
              • -
              • Bent pipes: Pipes with a 90 degree bend at the half-meter mark. My goodness.
              • -
              • Pipe manifolds: Pipes that are essentially a "T" shape, allowing you to connect three things at one point.
              • -
              • 4-way manifold: A four-way junction.
              • -
              • Pipe cap: Caps off the end of a pipe. Open ends don't actually vent air, because of the way the pipes are assembled, so, uh, use them to decorate your house or something.
              • -
              • Manual valve: A valve that will block off airflow when turned. Can't be used by the AI or cyborgs, because they don't have hands.
              • -
              • Manual T-valve: Like a manual valve, but at the center of a manifold instead of a straight pipe.


              • -
              - - An important note here is that pipes are now done in three distinct lines - general, supply, and scrubber. You can move gases between these with a universal adapter. Use the correct position for the correct location. - Connecting scrubbers to a supply position pipe makes you an idiot who gives everyone a difficult job. Insulated and HE pipes don't go through these positions. - -

              Insulated Pipes

              -
            • Bent pipes: Pipes with a 90 degree bend at the half-meter mark. My goodness.
            • -
            • Pipe manifolds: Pipes that are essentially a "T" shape, allowing you to connect three things at one point.
            • -
            • 4-way manifold: A four-way junction.
            • -
            • Pipe cap: Caps off the end of a pipe. Open ends don't actually vent air, because of the way the pipes are assembled, so, uh. Use them to decorate your house or something.
            • -
            • Manual Valve: A valve that will block off airflow when turned. Can't be used by the AI or cyborgs, because they don't have hands.
            • -
            • Manual T-Valve: Like a manual valve, but at the center of a manifold instead of a straight pipe.


            • - -

              Insulated Pipes


              - Special Public Service Announcement.
              - Our regular pipes are already insulated. These are completely worthless. Punch anyone who uses them.

              - -

              Devices:

              - They actually do something.
              - This is usually where people get frightened, afraid, and start calling on their gods and/or cowering in fear. Yes, I can see you doing that right now. - Stop it. It's unbecoming. Most of these are fairly straightforward.
              - -
                -
              • Gas pump: Take a wild guess. It moves gas in the direction it's pointing (marked by the red line on one end). It moves it based on pressure, the maximum output being 15000 kPa (kilopascals). - Ordinary atmospheric pressure, for comparison, is 101.3 kPa, and the minimum pressure of room-temperature pure oxygen needed to not suffocate in a matter of minutes is 16 kPa - (though 18 kPa is preferred when using internals with pure oxygen, for various reasons). A high-powered variant will move gas more quickly at the expense of consuming more power. Do not turn the distribution loop up to 15000 kPa. - You will make engiborgs cry and the Chief Engineer will beat you.
              • -
              • Pressure regulator: These replaced the old passive gates. You can choose to regulate pressure by input or output, and regulate flow rate. Regulating by input means that when input pressure is above the limit, gas will flow. - Regulating by output means that when pressure is below the limit, gas will flow. Flow rate can be controlled.
              • -
              • Unary vent: The basic vent used in rooms. It pumps gas into the room, but can't suck it back out. Controlled by the room's air alarm system.
              • -
              • Scrubber: The other half of room equipment. Filters air, and can suck it in entirely in what's called a "panic siphon." Activating a panic siphon without very good reason will kill someone. Don't do it.
              • -
              • Meter: A little box with some gauges and numbers. Fasten it to any pipe or manifold and it'll read you the pressure in it. Very useful.
              • -
              • Gas mixer: Two sides are input, one side is output. Mixes the gases pumped into it at the ratio defined. The side perpendicular to the other two is "node 2," for reference, on non-mirrored mixers.. - Output is controlled by flow rate. There is also an "omni" variant that allows you to set input and output sections freely..
              • -
              • Gas filter: Essentially the opposite of a gas mixer. One side is input. The other two sides are output. One gas type will be filtered into the perpendicular output pipe, - the rest will continue out the other side. Can also output from 0-4500 kPa. The "omni" vairant allows you to set input and output sections freely.
              • -
              - -

              Heat Exchange Systems

              - Will not set you on fire.
              - These systems are used to only transfer heat between two pipes. They will not move gases or any other element, but will equalize the temperature (eventually). Note that because of how gases work (remember: pv=nRt), - a higher temperature will raise pressure, and a lower one will lower temperature.
              - -
            • Pipe: This is a pipe that will exchange heat with the surrounding atmosphere. Place in fire for superheating. Place in space for supercooling.
            • -
            • Bent pipe: Take a wild guess.
            • -
            • Junction: The point where you connect your normal pipes to heat exchange pipes. Not necessary for heat exchangers, but necessary for H/E pipes/bent pipes.
            • -
            • Heat exchanger: These funky-looking bits attach to an open pipe end. Put another heat exchanger directly across from it, and you can transfer heat across two pipes without having to have the gases touch. - This normally shouldn't exchange with the ambient air, despite being totally exposed. Just don't ask questions.

            • - - That's about it for pipes. Go forth, armed with this knowledge, and try not to break, burn down, or kill anything. Please. - - - - - "} + guide_decl = /datum/codex_entry/guide/atmospherics /obj/item/book/manual/evaguide - name = "EVA Gear and You: Not Spending All Day Inside" - icon_state = "evabook" + name = "\improper EVA reference manual" + icon = 'icons/obj/items/books/book_eva.dmi' author = "Maria Crash, Senior Atmospherics Technician" title = "EVA Gear and You: Not Spending All Day Inside" - dat = {" - - - - - -

              EVA Gear and You: Not Spending All Day Inside

              - Or: How not to suffocate because there's a hole in your shoes
              - -

              Contents

              -
                -
              1. A foreword on using EVA gear
              2. -
              3. Donning a Civilian Suit
              4. -
              5. Putting on a Hardsuit
              6. -
              7. Cyclers and Other Modification Equipment
              8. -
              9. Final Checks
              10. -
              -
              - - EVA gear. Wonderful to use. It's useful for mining, engineering, and occasionally just surviving, if things are that bad. Most people have EVA training, - but apparently there are some people out in space who don't. This guide should give you a basic idea of how to use this gear, safely. It's split into two sections: - Civilian suits and hardsuits.

              - -

              Civilian Suits

              - The bulkiest things this side of Alpha Centauri
              - These suits are the grey ones that are stored in EVA. They're the more simple to get on, but are also a lot bulkier, and provide less protection from environmental hazards such as radiation or physical impact. - As Medical, Engineering, Security, and Mining all have hardsuits of their own, these don't see much use, but knowing how to put them on is quite useful anyways.

              - - First, take the suit. It should be in three pieces: A top, a bottom, and a helmet. Put the bottom on first, shoes and the like will fit in it. If you have magnetic boots, however, - put them on on top of the suit's feet. Next, get the top on, as you would a shirt. It can be somewhat awkward putting these pieces on, due to the makeup of the suit, - but to an extent they will adjust to you. You can then find the snaps and seals around the waist, where the two pieces meet. Fasten these, and double-check their tightness. - The red indicators around the waist of the lower half will turn green when this is done correctly. Next, put on whatever breathing apparatus you're using, be it a gas mask or a breath mask. Make sure the oxygen tube is fastened into it. - Put on the helmet now, straightforward, and make sure the tube goes into the small opening specifically for internals. Again, fasten seals around the neck, a small indicator light in the inside of the helmet should go from red to off when all is fastened. - There is a small slot on the side of the suit where an emergency oxygen tank or extended emergency oxygen tank will fit, - but it is recommended to have a full-sized tank on your back for EVA.

              - - These suits tend to be wearable by most species. They're large and flexible. They might be pretty uncomfortable for some, though, so keep that in mind.

              - -

              Hardsuits

              - Heavy, uncomfortable, still the best option.
              - These suits come in Engineering, Mining, and the Armory. There's also a couple Medical Hardsuits in EVA. These provide a lot more protection than the standard suits.

              - - Similarly to the other suits, these are split into three parts. Fastening the pant and top are mostly the same as the other spacesuits, with the exception that these are a bit heavier, - though not as bulky. The helmet goes on differently, with the air tube feeding into the suit and out a hole near the left shoulder, while the helmet goes on turned ninety degrees counter-clockwise, - and then is screwed in for one and a quarter full rotations clockwise, leaving the faceplate directly in front of you. There is a small button on the right side of the helmet that activates the helmet light. - The tanks that fasten onto the side slot are emergency tanks, as well as full-sized oxygen tanks, leaving your back free for a backpack or satchel.

              - - These suits generally only fit one species. Standard-issue suits are usually human-fitting by default, but there's equipment that can make modifications to the hardsuits to fit them to other species.

              - -

              Modification Equipment

              - How to actually make hardsuits fit you.
              - There's a variety of equipment that can modify hardsuits to fit species that can't fit into them, making life quite a bit easier.

              - - The first piece of equipment is a suit cycler. This is a large machine resembling the storage pods that are in place in some places. These are machines that will automatically tailor a suit to certain specifications. - The largest uses of them are for their cleaning functions and their ability to tailor suits for a species. Do not enter them physically. You will die from any of the functions being activated, and it will be painful. - These machines can both tailor a suit between species, and between types. This means you can convert engineering hardsuits to atmospherics, or the other way. This is useful. Use it if you can.

              - - There's also modification kits that let you modify suits yourself. These are extremely difficult to use unless you understand the actual construction of the suit. I do not reccomend using them unless no other option is available. - -

              Final Checks

              -
                -
              • Are all seals fastened correctly?
              • -
              • If you have modified it manually, is absolutely everything sealed perfectly?
              • -
              • Do you either have shoes on under the suit, or magnetic boots on over it?
              • -
              • Do you have a mask on and internals on the suit or your back?
              • -
              • Do you have a way to communicate with your fellow crew in case something goes wrong?
              • -
              • Do you have a second person watching if this is a training session?

              • -
              - - If you don't have any further issues, go out and do whatever is necessary. - - - - "} + guide_decl = /datum/codex_entry/guide/eva diff --git a/code/game/objects/items/books/manuals/manuals.dm b/code/game/objects/items/books/manuals/manuals.dm index 454d0248e397..908554d19323 100644 --- a/code/game/objects/items/books/manuals/manuals.dm +++ b/code/game/objects/items/books/manuals/manuals.dm @@ -1,145 +1,27 @@ /obj/item/book/manual/chef_recipes - name = "Chef Recipes" - icon_state = "cooked_book" + name = "recipe book" + icon = 'icons/obj/items/books/book_cookbook.dmi' author = "Victoria Ponsonby" title = "Chef Recipes" - -/obj/item/book/manual/chef_recipes/Initialize() - . = ..() - dat = {" - - - - - [SScodex.get_guide(/datum/codex_category/recipes)] - - - "} + guide_decl = /decl/codex_category/recipes /obj/item/book/manual/barman_recipes - name = "Mixology 101" - icon_state = "barbook" + name = "cocktail recipe book" + icon = 'icons/obj/items/books/book_bartending.dmi' author = "Sir John Rose" title = "Mixology 101" - -/obj/item/book/manual/barman_recipes/Initialize() - . = ..() - dat = {" - - - - - [SScodex.get_guide(/datum/codex_category/cocktails)] - - - "} + guide_decl = /decl/codex_category/cocktails /obj/item/book/manual/detective - name = "The Film Noir: Proper Procedures for Investigations" - icon_state ="bookDetective" + name = "forensics reference manual" + icon = 'icons/obj/items/books/book_detective.dmi' author = "The Company" title = "The Film Noir: Proper Procedures for Investigations" - - dat = {" - - - - -

              Detective Work

              - - Between your bouts of self-narration and drinking whiskey on the rocks, you might get a case or two to solve.
              - To have the best chance to solve your case, follow these directions: -

              -

                -
              1. Go to the crime scene.
              2. -
              3. Take your scanner and scan EVERYTHING (Yes, the doors, the tables, even the dog).
              4. -
              5. Once you are reasonably certain you have every scrap of evidence you can use, find all possible entry points and scan them, too.
              6. -
              7. Return to your office.
              8. -
              9. Using your forensic scanning computer, scan your scanner to upload all of your evidence into the database.
              10. -
              11. Browse through the resulting dossiers, looking for the one that either has the most complete set of prints, or the most suspicious items handled.
              12. -
              13. If you have 80% or more of the print (The print is displayed), go to step 10, otherwise continue to step 8.
              14. -
              15. Look for clues from the suit fibres you found on your perpetrator, and go about looking for more evidence with this new information, scanning as you go.
              16. -
              17. Try to get a fingerprint card of your perpetrator, as if used in the computer, the prints will be completed on their dossier.
              18. -
              19. Assuming you have enough of a print to see it, grab the biggest complete piece of the print and search the security records for it.
              20. -
              21. Since you now have both your dossier and the name of the person, print both out as evidence and get security to nab your baddie.
              22. -
              23. Give yourself a pat on the back and a bottle of the ship's finest vodka, you did it!
              24. -
              -

              - It really is that easy! Good luck! - - - "} + guide_decl = /datum/codex_entry/guide/detective /obj/item/book/manual/nuclear - name = "Fission Mailed: Nuclear Sabotage 101" - icon_state ="bookNuclear" + name = "nuclear device reference manual" + icon = 'icons/obj/items/books/book_nuclear.dmi' author = "Syndicate" title = "Fission Mailed: Nuclear Sabotage 101" - - dat = {" - - - - -

              Nuclear Explosives 101

              - Hello and thank you for choosing the Syndicate for your nuclear information needs. Today's crash course will deal with the operation of a Nuclear Fission Device.

              - - First and foremost, DO NOT TOUCH ANYTHING UNTIL THE BOMB IS IN PLACE. Pressing any button on the compacted bomb will cause it to extend and bolt itself into place. If this is done, to unbolt it, one must completely log in, which at this time may not be possible.
              - -

              To make the nuclear device functional

              -
                -
              • Place the nuclear device in the designated detonation zone.
              • -
              • Extend and anchor the nuclear device from its interface.
              • -
              • Insert the nuclear authorisation disk into the slot.
              • -
              • Type the numeric authorisation code into the keypad. This should have been provided.
                - Note: If you make a mistake, press R to reset the device. -
              • Press the E button to log on to the device.
              • -

              - - You now have activated the device. To deactivate the buttons at anytime, for example when you've already prepped the bomb for detonation, remove the authentication disk OR press R on the keypad.

              - Now the bomb CAN ONLY be detonated using the timer. Manual detonation is not an option. Toggle off the SAFETY.
              - Note: You wouldn't believe how many Syndicate Operatives with doctorates have forgotten this step.

              - - So use the - - and + + to set a detonation time between 5 seconds and 10 minutes. Then press the timer toggle button to start the countdown. Now remove the authentication disk so that the buttons deactivate.
              - Note: THE BOMB IS STILL SET AND WILL DETONATE

              - - Now before you remove the disk, if you need to move the bomb, you can toggle off the anchor, move it, and re-anchor.

              - - Remember the order:
              - Disk, Code, Safety, Timer, Disk, RUN!

              - Intelligence Analysts believe that normal corporate procedure is for the Captain to secure the nuclear authentication disk.

              - - Good luck! - - - "} + guide_decl = /datum/codex_entry/guide/nuclear_sabotage diff --git a/code/game/objects/items/books/manuals/medical.dm b/code/game/objects/items/books/manuals/medical.dm index 4bdd499fb766..2013a8e33c27 100644 --- a/code/game/objects/items/books/manuals/medical.dm +++ b/code/game/objects/items/books/manuals/medical.dm @@ -1,55 +1,22 @@ /obj/item/book/manual/medical_diagnostics_manual - name = "Medical Diagnostics Manual" + name = "medical diagnostics manual" desc = "First, do no harm. A detailed medical practitioner's guide." - icon_state = "bookMedical" + icon = 'icons/obj/items/books/book_medical.dmi' author = "Medical Department" title = "Medical Diagnostics Manual" - url = "Guide_to_Medicine" - -/obj/item/book/manual/medical_diagnostics_manual/Initialize() - . = ..() - dat = {" - - - - -
              -

              The Oath

              - - The Medical Oath sworn by recognised medical practitioners in the employ of [GLOB.using_map.company_name]
              - -
                -
              1. Now, as a new doctor, I solemnly promise that I will, to the best of my ability, serve humanity-caring for the sick, promoting good health, and alleviating pain and suffering.
              2. -
              3. I recognise that the practice of medicine is a privilege with which comes considerable responsibility and I will not abuse my position.
              4. -
              5. I will practise medicine with integrity, humility, honesty, and compassion-working with my fellow doctors and other colleagues to meet the needs of my patients.
              6. -
              7. I shall never intentionally do or administer anything to the overall harm of my patients.
              8. -
              9. I will not permit considerations of gender, race, religion, political affiliation, sexual orientation, nationality, or social standing to influence my duty of care.
              10. -
              11. I will oppose policies in breach of human rights and will not participate in them. I will strive to change laws that are contrary to my profession's ethics and will work towards a fairer distribution of health resources.
              12. -
              13. I will assist my patients to make informed decisions that coincide with their own values and beliefs and will uphold patient confidentiality.
              14. -
              15. I will recognise the limits of my knowledge and seek to maintain and increase my understanding and skills throughout my professional life. I will acknowledge and try to remedy my own mistakes and honestly assess and respond to those of others.
              16. -
              17. I will seek to promote the advancement of medical knowledge through teaching and research.
              18. -
              19. I make this declaration solemnly, freely, and upon my honour.
              20. -

              - -
              - - - - - - "} + guide_decl = /datum/codex_entry/guide/ailments /obj/item/book/manual/chemistry_recipes - name = "Guide to Medicines & Drugs" + name = "pharmacology reference manual" desc = "A thick manual of chemistry, formulae and recipes useful for a Chemist." - icon_state = "bookChemistry" + icon = 'icons/obj/items/books/book_chemistry.dmi' author = "Big Pharma" - title = "Guide to Medicines & Drugs" - url = "List_of_Medical_Chemicals" \ No newline at end of file + title = "Guide to Pharmacology" + guide_decl = /decl/codex_category/materials/chemistry + +/obj/item/book/manual/surgical + name = "surgical reference manual" + icon = 'icons/obj/items/books/book_medical.dmi' + author = "Dr. Holmes MD" + title = "Guide to Surgery" + guide_decl = /decl/codex_category/surgery diff --git a/code/game/objects/items/books/manuals/science.dm b/code/game/objects/items/books/manuals/science.dm index 0894e7b787b3..0c819c4d5d43 100644 --- a/code/game/objects/items/books/manuals/science.dm +++ b/code/game/objects/items/books/manuals/science.dm @@ -1,376 +1,13 @@ /obj/item/book/manual/excavation - name = "Out on the Dig" - icon_state = "excavation" + name = "excavation reference manual" + icon = 'icons/obj/items/books/book_excavation.dmi' author = "Professor Patrick Mason, Curator of the Antiquities Museum on Ichar VII" title = "Out on the Dig" - dat = {" - - - - - -

              Contents

              -
                -
              1. Prepping the expedition
              2. -
              3. Knowing your tools
              4. -
              5. Finding the dig
              6. -
              7. Analysing deposits
              8. -
              9. Extracting your first find
              10. -
              -
              - -

              Prepping the expedition

              - Every digsite I've been to, someone has forgotten something and I've never yet been to a dig that hasn't had me hiking to get to it - so gather your gear - and get it to the site the first time. You learn quick that time is money, when you've got a shipful of bandits searching for you the next valley over, - but don't be afraid to clear some space if there are any inconvenient boulders in the way.
              -
                -
              • Floodlights (if it's dark)
              • -
              • Wooden trestle tables (for holding tools and finds)
              • -
              • Suspension field generator
              • -
              • Load bearing servitors (such as a mulebot, or hover-tray)
              • -
              • Spare energy packs
              • -

              - Contents - -

              Knowing your tools

              - Every archaeologist has a plethora of tools at their disposal, but here's the important ones:
              -
                -
              • Picks, pickaxes, and brushes - don't underestimate the the smallest or largest in your arsenal, each one clears a different amount - of the rockface so each one has a use.
              • -
              • Measuring tape - don't leave home without it, you can use it to measure the depth a rock face has been excavated to.
              • -
              • GPS locator - knowing where you are is the first step to not be lost.
              • -
              • Core sampler - use this to take core samples from rock faces, which you can then run to the lab for analysis.
              • -
              • Depth scanner - uses X-ray diffraction to locate anomalous densities in rock, indicating archaeological deposits or mineral veins. - Comes with a handy reference log containing coordinates and time of each scan.
              • -
              • Alden-Saraspova counter - uses a patented application of Fourier Transform analysis to determine the difference between background and - exotic radiation. Use it to determine how far you are from anomalous energy sources.
              • -
              • Radio beacon locator - leave a beacon at an item of interest, then track it down later with this handy gadget. Watch for interference from other - devices though.
              • -
              • Flashlight or portable light source - Self explanatory, I hope.
              • -
              • Environmental safety gear - This one's dependent on the environment you're working in, but enclosed footwear and a pack of internals - could save your life.
              • -
              • Anomaly safety gear - A biosealed and catalysis-resistant suit along with eye shielding, tinted hood, and non-reactive disposable gloves are - the best kind of protection you can hope for from the errors our forebears may have unleashed.
              • -
              • Personal defence weapon - Never know what you'll find on the dig: pirates, natives, ancient guardians, carnivorous wildlife... - it pays in blood to be prepared.
              • -

              - Contents - -

              Finding the dig

              - Wouldn't be an archaeologist without their dig, but everyone has to start somewhere. Here's a basic procedure I go through when cataloguing a new planet:
              -
                -
              • Get in touch with the locals (in particular geologists, miners, and farmers) - Never know what's been turned up by accident, then left to - gather dust on a shelf.
              • -
              • Check the obvious areas first - even if you're pressed for time, these ones are the generally easiest to search, and the most likely targets - of your rivals.
              • -
              • Do some prospecting - the earth mother isn't in the habit of displaying her secrets to the world (although sometimes you get lucky). - Drop a shaft and clear away a bit of surface rock here and there, you never know what might be lurking below the surface.
              • -
              • Tips on unearthing a deposit - How do you know when you're golden? Look for telltale white strata that looks strange or out of place, or if - something has broken under your pick while you're digging. Your depth scanner is your best friend, but even it can't distinguish between - ordinary minerals and ancient leavings, if in doubt then err on the side of caution.
              • -

              - Contents - -

              Analysing the contents of a dig

              - You've found some unusual strata, but it's not all peaches from here. No archaeologist ever managed to pull a bone from the earth without doing thorough - chemical analysis on every two meters of rock face nearby.
              -
                -
              • Take core samples - Grab a rock core for every 4m^2.
              • -
              • Clear around any potential finds - Clear away ordinary rock, leaving your prizes reachable in a clearly marked area.
              • -
              • Haul off excess rock - It's easy for a dig to get cluttered, and a neat archaeologist is a successful archaeologist.
              • -
              • Don't be afraid to be cautious - It's slower sometimes, but the extra time will be worth the payoff when you find an Exolitic relic.
              • -
              • Chemical analysis - I won't go into detail here, but the labwork is essential to any successful extraction. Marshal your core samples, and - send them off to the labcoated geniuses.
              • -

              - Contents - -

              Extracting your first find

              -
                -
              • Scan the rock - Use a depth scanner to determine the find's depth and clearance. DON'T FORGET THESE.
              • -
              • Choose stasis field - Chemical analysis on a core sample from the rock face will tell you which field is necessary to extract the find safely.
              • -
              • Setup field gen - Bolt it down, choose the field, check the charge, and activate it. If you forget it, you'll wish you hadn't when that priceless - Uryom vase crumbles as it sees the light of day.
              • -
              • FUNCTIONAL AND SAFE digging - Dig into the rock until you've cleared away a depth equal to (the anomaly depth MINUS the clearance range). The find - should come loose on it's own, but it will be in the midst of a chunk of rock. Use a welder or miniature excavation tool to clear away the excess.
              • -
              • FANCY AND SPEEDY digging - Dig into the rock until you've cleared away a depth equal to the anomaly depth, but without any of your strokes - entering the clearance range.
              • -
              • The big find - Sometimes, you'll chance upon something big, both literally and figuratively. Giant statues and functioning remnants of Precursor - technology are just as exciting, to the right buyers. If your digging leaves a large boulder behind, dig into it normally and see if anything's hidden - inside.
              • -

              - Contents - - - - "} + guide_decl = /datum/codex_entry/guide/xenoarchaeology /obj/item/book/manual/mass_spectrometry - name = "High Power Mass Spectrometry: A Comprehensive Guide" - icon_state = "analysis" + name = "mass spectrometry reference manual" + icon = 'icons/obj/items/books/book_analysis.dmi' author = "Winton Rice, Chief Mass Spectrometry Technician at the Institute of Applied Sciences on Arcadia" title = "High powered mass spectrometry, a comprehensive guide" - dat = {" - - - - - -

              Contents

              -
                -
              1. A note on terms
              2. -
              3. Analysis progression
              4. -
              5. Heat management
              6. -
              7. Ambient radiation
              8. -
              - -
              -

              A note on terms

              -
                -
              • Mass spectrometry - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of - 'Materials analysis.'
              • -
              • Radiometric dating - MS applied using the right carrier reagents can be used to accurately determine the age of a sample.
              • -
              • Dissonance ratio - This is a pseudoarbitrary value indicating the overall presence of a particular element in a greater composite. - It takes into account volume, density, molecular excitation and isotope spread.
              • -
              • Vacuum seal integrity - A reference to how close an airtight seal is to failure.
              • -

              - Contents - -

              Analysis progression

              - Modern mass spectrometry requires constant attention from the diligent researcher in order to be successful. There are many different elements to juggle, - and later chapters will delve into them. For the spectrometry assistant, the first thing you need to know is that the scanner wavelength is automatically - calculated for you. Just tweak the settings and try to match it with the actual wavelength as closely as possible.
              -
              - Contents - -

              Seal integrity

              - In order to maintain sterile and environmentally static procedures, a special chamber is set up inside the spectrometer. It's protected by a proprietary vacuum seal - produced by top tier industrial science. It will only last for a certain number of scans before failing outright, but it can be resealed through use of nanite paste. - Unfortunately, it's susceptible to malforming under heat stress so exposing it to higher temperatures will cause it's operation life to drop significantly.
              -
              - Contents - -

              Heat management

              - The scanner relies on a gyro-rotational system that varies in speed and intensity. Over the course of an ordinary scan, the RPMs can change dramatically. Higher RPMs - means greater heat generation, but is necessary for the ongoing continuation of the scan. To offset heat production, spectrometers have an inbuilt cooling system. - Researchers can modify the flow rate of water to aid in dropping temperature as necessary, but are advised that frequent water replacements may be necessary - depending on coolant purity. Other substances may be viable substitutes, but nowhere near as effective as water itself.
              -
              - Contents - -

              Ambient radiation

              - Researchers are warned that while operational, mass spectrometers emit period bursts of radiation and are thus advised to wear protective gear. In the event of - radiation spikes, there is also a special shield that can be lowered to block emissions. Lowering this, however, will have the effect of blocking the scanner - so use it sparingly.
              -
              - Contents - - - - "} - -/obj/item/book/manual/anomaly_spectroscopy - name = "Spectroscopy: Analysing the Anomalies of the Cosmos" - icon_state = "anomaly" - author = "Doctor Martin Boyle, Director Research at the Lower Hydrolian Sector Listening Array" - title = "Spectroscopy: Analysing the Anomalies of the Cosmos" - dat = {" - - - - -
              - It's perhaps one of the most exciting times to be alive, with the recent breakthroughs in understanding and categorisation of things we may one day no longer call - 'anomalies,' but rather 'infrequent or rare occurrences of certain celestial weather or phenomena.' Perhaps a little more long winded, but no less eloquent all the - same! Why, look at the strides we're making in piercing the walls of spacetime or our steadily improving ability to clarify and stabilise subspace emissions; it's - certainly an exciting time to be alive. For the moment, the Hydrolian hasn't seen two spatial anomalies alike but the day will come and it is soon, I can feel it. - - "} - -/obj/item/book/manual/materials_chemistry_analysis - name = "Materials Analysis and the Chemical Implications" - icon_state = "chemistry" - author = "Jasper Pascal, Senior Lecturer in Materials Analysis at the University of Jol'Nar" - title = "Materials Analysis and the Chemical Implications" - dat = {" - - - - -
              - In today's high tech research fields, leaps and bounds are being made every day. Whether it's great strides forward in our understanding of the physical universe - or the operation of some fancy new piece of equipment, it seems like all the cool fields are producing new toys to play with, leaving doddery old fields such as - materials analysis and chemistry relegated to the previous few centuries, when we were still learning the makeup and structure of the elements.
              -
              - Well, when you're out there building the next gryo-whatsitron or isotope mobility thingummy, remember how the field of archaeology experienced a massive new rebirth - following the excavations at Paranol IV and consider how all of the scientific greats will come crawling back to basic paradigms of natural philosophy when they discover - a new element that defies classification. I defy you to classify it without reviving this once great field! - "} - -/obj/item/book/manual/anomaly_testing - name = "Anomalous Materials and Energies" - icon_state = "triangulate" - author = "Norman York, formerly of the Tyrolion Institute on Titan" - title = "Anomalous Materials and Energies" - dat = {" - - - - - -

              Contents

              -
                -
              1. Foreword: Modern attitude towards anomalies
              2. -
              3. Triangulating anomalous energy readings
              4. -
              5. Harvesting and utilising anomalous energy signatures
              6. -
              -
              -

              Modern attitude towards anomalies

              - It's only when confronted with things we don't know, that we may push back our knowledge of the world around us. Nowhere is this more obvious than the - vast and inscrutable mysterious of the cosmos that scholars from such august institutions as the Elysian Institute of the Sciences present - formulas and hypotheses for every few decades.
              -
              - Using our vast, telescopic array installations and deep space satellite networks, we are able to detect anomalous energy fields and formations in deep space, - but are limited to those that are large enough to output energy that will stretch across light years worth of distance between stars.
              -
              - While some sectors (such as the Hydrolian Rift and Keppel's Run) are replete with inexplicable energetic activity and unique phenomena found nowhere else in - the galaxy, the majority of space is dry, barren and cold - and if past experience has told us anything, it is that there are always more things we are - unable to explain.
              -
              - Indeed, a great source of knowledge and technology has always been those who come before us, in the form of the multitudinous ancient alien precursors that - have left scattered remnants of their great past all over settled (and unexplored) space.
              -
              - It is from xenoarchaeologists, high energy materials researchers, and technology reconstruction authorities that we are able to theorise on the gifts these - species have left behind, and in some cases even reverse engineer or rebuild the technology in question. My colleague, Doctor Raymond Ward of the - Tyrolian Institute on Titan, has made great breakthroughs in a related field through his pioneering development of universally reflective materials capable - of harvesting and 'bottling' up virtually any energy emissions yet encountered by spacefaring civilisations.
              -
              - And yet, there are some amongst us who do not see the benefits of those who have come before us - indeed, some among them profess the opinion that there - is no species that could possibly match humanity in it's achievements and knowledge, or simply that employing non-human technology is dangerous and unethical. - Folly, say I. If it is their desire to throw onto the wayside the greatest achievements in the history of the galaxy, simply for preferment of the - greatest achievements in the history of mankind, then they have no business in the establishment of science.
              - Contents - -

              Triangulating anomalous energy readings

              - Strong energy emissions, when remaining constant from any one fixed location for millennia, can leave an 'imprint' or distinctive energy signature on other - matter composites that are spatially fixed relative to the source.
              -
              - By taking samples of such 'fixed' matter, we can apply complex analytics such as the modified Fourier Transform Procedure to reverse engineer the path of the - energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space. Modern portable devices can do - all this purely by taking readings of local radiation.
              -
              - A canny researcher can thusly analyse radiation at pre-chosen points strategically scattered around an area, and if there are any anomalous energy - emissions in range of those points, combined the researcher can triangulate the source.
              - Contents - -

              Harvesting and utilising anomalous energy signatures

              - As mentioned in the foreword, my colleague from the Tyrolian Institute on Saturn's moon of Titan, in the Sol System, Doctor Raymond Ward has made great strides - in the area of harvesting and application of the energy emitted by anomalous phenomena from around the galaxy (although I profess I have not yet seen him - venture further from his birthplace on Earth than the comfortable distance of the Sol Cis-Oort Satellite Sphere).
              -
              - By employing a patented semi-phased alloy with unique and fascinating properties, Ward's contraption is able to 'harvest' energy, store - it and redirect it later at will (with appropriate electronic mechanisms, of course). Although he professes to see or desire no commercial or material gain - for the application and use of said energy once it is harvested, there are no doubt myriad ways we can come to benefit from such things beyond mere research, - such as the reconstruction of torn cartilaginous tissue that a peculiar radiation from an amphibious species on Brachis IV was found to emit.
              - Contents - - - - "} - -/obj/item/book/manual/stasis - name = "Cellular Suspension, the New Cryogenics?" - icon_state = "stasis" - author = "Elvin Schmidt" - title = "Cellular Suspension, the New Cryogenics?" - dat = {" - - - - - -

              Contents

              -
                -
              1. Foreword: A replacement for cryosleep?
              2. -
              3. The breakthrough
              4. -
              5. Applying this new principle
              6. -
              -
              -

              Foreword: A replacement for cryosleep?

              - The development of rudimentary cryofreezing in the 20th and 21st centuries was hailed as a crank science by some, but many early visionaries recognised the - potential it had to change the way we approach so many fields, such as medicine, therapeutics, and space travel. It was breakthroughs in the field in the 22nd and - later centuries that turned the procedure from science fiction to science fact, however. Since then, cryogenics has become a hallmark of modern science, and - regarded as one of the great achievements of our era. As with all sciences however, they have their time and are superseded by newer technological miracles when - it is over.
              - Contents - -

              The breakthrough

              - It was in examining the effects of decelerated high energy particles when transphased through a gravitational lens that the effects where primarily noticed. - Due to exigent properties of that dimension, transphasing those particles capable of existing with high stability levels has the effect of bringing - some of those effects into realspace. Examining the Hoffman emissions in particular, it was discovered that they exhibited a-entropic behaviour, and in what is - now termed the 'Effete Hoffman Principle,' it was found that metastabilising the Hoffman radiation resulted in the effect being applied across other physical - interactions, in particular forces and reactions.
              - Contents - -

              Applying this new principle

              - When combined with an appropriate energy-effect replicate for cryogenics (slowing down biological activity, thus stabilising the organics), the effect is - effectively identical to cryogenics, and while it consumes vastly more power and requires extremely complex equipment, it's (for all intents and purposes) superior - to cryogenics, all that remains is to 'commercialise' the process by enabling cheaper development and mass production.
              - The Effete Hoffman Principle can be tweak-combined with other effects however, for different purposes. A division of PMC Research initially developed the application - in prisons as a literal 'suspension field' where convicts are held immobile in the air, and the use quickly spread to numerous other areas.
              -
              - By examining the material resonance properties of certain strong waveforms when combined with Hoffman radiation, an effect was produced able to reverse energy - transferral through matter, and to slow the effects of gravity. When combined with energy repulse technology, the triple effects compound themselves into a much - stronger field, although all three components do slightly different things. High energy researchers assure me of the following key points:
              -
                -
              • The energy repulsion factor provides a 'shell' capable of weak suspension.
              • -
              • The Hoffman emissions nullify energy transferral and other kinetic activity, maintaining stability inside the field.
              • -
              • The resonant waveform combines the effects of the above two points, and applies it magnified onto it's synced 'resonance' materials.
              • -
              - As an interesting aside, a carbon waveform was chosen for the field in prison suspension fields, due to it's resonance with organic matter.
              - Contents - - - - "} \ No newline at end of file + guide_decl = /datum/codex_entry/guide/mass_spectrometry diff --git a/code/game/objects/items/books/skill/_skill.dm b/code/game/objects/items/books/skill/_skill.dm new file mode 100644 index 000000000000..39ed2b3cdfe0 --- /dev/null +++ b/code/game/objects/items/books/skill/_skill.dm @@ -0,0 +1,283 @@ +/* +Skill books that increase your skills while you activate and hold them +*/ + +/obj/item/book/skill + name = "textbook" // requires default names for tradershop, cant rely on Initialize for names + desc = "A blank textbook. (Notify admin)" + author = "The Oracle of Bakersroof" + icon_state = ICON_STATE_WORLD + _base_attack_force = 4 + w_class = ITEM_SIZE_LARGE // Skill books are THICC with knowledge. Up one level from regular books to prevent library-in-a-bag silliness. + unique = TRUE + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/organic/wood/oak = MATTER_AMOUNT_REINFORCEMENT) + abstract_type = /obj/item/book/skill + + var/decl/skill/skill // e.g. SKILL_LITERACY + var/skill_req = SKILL_NONE // The level the user needs in the skill to benefit from the book, e.g. SKILL_PROF + var/weakref/reading // To check if the book is actively being used + var/custom = FALSE // To bypass init stuff, for player made textbooks and weird books. If true must have details manually set + var/ez_read = FALSE // Set to TRUE if you can read it without basic literacy skills + + var/skill_name = "missing skill name" + var/progress = INFINITY // used to track the progress of making a custom book. defaults as finished so, you know, you can read the damn thing + + var/static/list/skill_name_patterns = list( + "$SKILL_NAME$ for Idiots", + "How To Learn $SKILL_NAME$ and Not Get Laughed At", + "Teaching Yourself $SKILL_NAME$: Volume $RAND$", + "Getting the Hands-Off Experience You Need with $SKILL_NAME$", + "Master $SKILL_NAME$ in $RAND$ easy steps!", + "$SKILL_NAME$ Just Like Mum", + "How To $SKILL_NAME$ Good Enough For Your Father", + "How To Win Your Dad's Approval With $SKILL_NAME$", + "Make a Living with $SKILL_NAME$ Like Your Old Man Always Wanted You To", + "$SKILL_NAME$: Secret Techniques", + "The Dos, Don'ts and Oh Gods Please Nos of $SKILL_NAME$", + "The Death Of $SKILL_NAME$", + "Everything You Never Wanted To Know About $SKILL_NAME$ But Have Been Reluctantly Forced To Find Out", + "$SKILL_NAME$ For The Busy Professional", + "Learning $SKILL_NAME$ In A Hurry Because You Lied On Your Resume", + "Help! My Life Suddenly Depends On $SKILL_NAME$", + "What The Fuck is $ARTICLE_SKILL_NAME$?", + "Starting $ARTICLE_SKILL_NAME$ Business By Yourself", + "Even You Can Learn $SKILL_NAME$!", + "How To Impress Your Parents with $SKILL_NAME$", + "How To Become A Master of $SKILL_NAME$", + "Everything The Government Doesn't Want You To Know About $SKILL_NAME$", + "$SKILL_NAME$ For Kids!", + "$SKILL_NAME$: Volume $RAND$", + "Understanding $SKILL_NAME$: $RAND_TH$ Edition", + "Dealing With Ungrateful Customers Dissatisfied With Your Perfectly Acceptable $SKILL_NAME$ Services", + "Really big book of $SKILL_NAME$" + ) + + // Lists used when producing custom skillbooks. + var/static/list/failure_messages = list( + "Your hand slips and you accidentally rip your pen through several pages, ruining your hard work!", + "Your pen slips, dragging a haphazard line across both open pages! Now you need to do those again!" + ) + /// Messages are in order of progress. + var/static/list/progress_messages = list( + "Still quite a few blank pages left.", + "Feels like you're near halfway done.", + "You've made good progress.", + "Just needs a few finishing touches.", + "And then finish it. Done!" + ) + var/static/list/charge_messages = list( + "Your mind instantly recoils at the idea of having to write another textbook. No thank you!", + "You are far too mentally exhausted to write another textbook. Maybe another day.", + "Your hand aches in response to the very idea of more textbook writing." + ) + +/obj/item/book/skill/Initialize() + + . = ..() + + global.events_repository.register(/decl/observ/moved, src, src, PROC_REF(check_buff)) + + if(!custom && skill && skill_req)// custom books should already have all they need + + skill_name = initial(skill.name) + + var/title_name = capitalize(skill_name) + title = replacetext(pick(skill_name_patterns), "$SKILL_NAME$", title_name) + title = replacetext(title, "$RAND$", rand(1,100)) + title = replacetext(title, "$RAND_TH$", "[rand(1,100)]\th") + title = replacetext(title, "$ARTICLE_SKILL_NAME$", capitalize(ADD_ARTICLE(title_name))) + title = "\"[title]\"" + + switch(skill_req) // check what skill_req the book has + if(SKILL_NONE) // none > basic + name = "beginner [skill_name] textbook" + desc = "A copy of [title] by [author]. The only reason this book is so big is because all the words are printed very large! Presumably so you, an idiot, can read it." + if(SKILL_BASIC) // basic > adept + name = "intermediate [skill_name] textbook" + desc = "A copy of [title] by [author]. Dry and long, but not unmanageable. Basic knowledge is required to understand the concepts written." + if(SKILL_ADEPT) // adept > expert + name = "advanced [skill_name] textbook" + desc = "A copy of [title] by [author]. Those not already trained in the subject will have a hard time reading this. Try not to drop it either, it will put a hole in the floor." + if(SKILL_EXPERT to SKILL_MAX) //expert > prof + name = "theoretical [skill_name] textbook" + desc = "A copy of [title] by [author]. Significant experience in the subject is required to read this incredibly information dense block of paper. Sadly, does not come in audio form." + + if((!skill || !skill_req) && !custom)//That's a bad book, so just grab ANY child to replace it. Custom books are fine though they can be bad if they want. + if(subtypesof(src.type)) + var/new_book = pick(subtypesof(src.type)) + new new_book(src.loc) + qdel_self() + +/datum/skill_buff/skill_book + limit = 1 // you can only read one book at a time nerd, therefore you can only get one buff at a time + +/obj/item/book/skill/get_single_monetary_worth() + . = max(..(), 200) + (100 * skill_req) + +/obj/item/book/skill/proc/check_can_read(mob/user) + if(QDELETED(user)) + return FALSE + var/effective_title = length(title) ? title : "the textbook" + if(!CanPhysicallyInteract(user)) + to_chat(user, SPAN_WARNING("You can't reach [effective_title]!")) + return FALSE + if(!skill || (custom && progress == 0)) + to_chat(user, SPAN_WARNING("[capitalize(effective_title)] is blank!")) + return FALSE + if(custom && progress <= length(progress_messages)) + to_chat(user, SPAN_WARNING("[capitalize(effective_title)] is unfinished! You can't learn from it in this state!")) + return FALSE + if(!ez_read &&!user.skill_check(SKILL_LITERACY, SKILL_BASIC)) + to_chat(user, SPAN_WARNING(pick(list( + "Haha, you know you can't read. Good joke. Put [effective_title] back.", + "You open up [effective_title], but there aren't any pictures, so you close it again.", + "You don't know how to read! What good is [effective_title] to you?!" + )))) + return FALSE + + if(reading) + if(reading.resolve() != user) + to_chat(user, SPAN_WARNING("\The [reading.resolve()] is already reading [effective_title]!")) + else + to_chat(user, SPAN_WARNING("You are already reading [effective_title]!")) + return FALSE + + if(user.too_many_buffs(/datum/skill_buff/skill_book)) + to_chat(user, SPAN_WARNING("You can't read two books at once!")) + return FALSE + + if(!user.skill_check(skill, skill_req)) + to_chat(user, SPAN_WARNING("[capitalize(title)] is too advanced for you! Try something easier, perhaps the \"For Idiots\" edition?")) + return FALSE + + if(user.get_skill_value(skill) > skill_req) + to_chat(user, SPAN_WARNING("You already know everything [effective_title] has to teach you!")) + return FALSE + + return TRUE + +/obj/item/book/skill/verb/read_book() + set name = "Read Book" + set category = "Object" + set src in view(1) + try_to_read(usr) + +/obj/item/book/skill/try_to_read(mob/user) + + if(isobserver(user)) + to_chat(user, SPAN_WARNING("Ghosts can't read! Go away!")) + return TRUE + + if(isturf(loc)) + user.face_atom(src) + + if(user && user == reading?.resolve()) + //Close book, get rid of buffs + unlearn(user) + to_chat(user, SPAN_NOTICE("You close [title]. That's enough learning for now.")) + reading = null + STOP_PROCESSING(SSprocessing, src) + return TRUE + + if(!check_can_read(user)) + return FALSE + + to_chat(user, SPAN_NOTICE("You open up [title] and start reading...")) + if(!user.do_skilled(4 SECONDS, SKILL_LITERACY, src, 0.75)) + to_chat(user, SPAN_DANGER("Your perusal of [title] was interrupted!")) + return TRUE + + if(!check_can_read(user)) + return TRUE + + var/list/buff = list() + buff[skill] = 1 + user.buff_skill(buff, buff_type = /datum/skill_buff/skill_book) + reading = weakref(user) + to_chat(user, SPAN_NOTICE("You find the information you need! Better keep the page open to reference it.")) + START_PROCESSING(SSprocessing, src) + return TRUE + +// buff removal +/obj/item/book/skill/proc/unlearn(var/mob/user) + var/list/F = user.fetch_buffs_of_type(/datum/skill_buff/skill_book, 0) + for(var/datum/skill_buff/skill_book/S in F) + S.remove() + +/obj/item/book/skill/Process() + if(!reading) + return PROCESS_KILL + check_buff() + +/obj/item/book/skill/proc/check_buff() + if(!reading) + return + var/mob/reader = reading.resolve() + if(!istype(reader) || !CanPhysicallyInteract(reader)) + remove_buff() + +/obj/item/book/skill/proc/remove_buff() + var/mob/reader = reading?.resolve() + reading = null + if(istype(reader)) + to_chat(reader, SPAN_DANGER("You lose the page you were on! You can't cross-reference using [title] like this!")) + if(reader.fetch_buffs_of_type(/datum/skill_buff/skill_book, 0)) + unlearn(reader) + STOP_PROCESSING(SSprocessing, src) + +/obj/item/book/skill/Destroy() + global.events_repository.unregister(/decl/observ/moved, src, src) + remove_buff() + . = ..() + + + + + + +////////////////////// +// SHELF SHELF SHELF// +////////////////////// + +/obj/structure/bookcase/skill_books + name = "textbook bookcase" + // Contains a list of parent types but doesn't actually DO anything with them. Use a child of this book case + var/static/list/catalogue = list( + /obj/item/book/skill/organizational/finance, + /obj/item/book/skill/organizational/literacy, + /obj/item/book/skill/general/eva, + /obj/item/book/skill/general/mech, + /obj/item/book/skill/general/pilot, + /obj/item/book/skill/general/hauling, + /obj/item/book/skill/general/computer, + /obj/item/book/skill/service/botany, + /obj/item/book/skill/service/cooking, + /obj/item/book/skill/security/combat, + /obj/item/book/skill/security/weapons, + /obj/item/book/skill/security/forensics, + /obj/item/book/skill/engineering/construction, + /obj/item/book/skill/engineering/electrical, + /obj/item/book/skill/engineering/atmos, + /obj/item/book/skill/engineering/engines, + /obj/item/book/skill/research/devices, + /obj/item/book/skill/research/science, + /obj/item/book/skill/medical/chemistry, + /obj/item/book/skill/medical/medicine, + /obj/item/book/skill/medical/anatomy + ) + +//give me ALL the textbooks +/obj/structure/bookcase/skill_books/all/WillContain() + . = list() + for(var/category in catalogue) + for(var/real_book in subtypesof(category)) + . |= real_book + +//Bookshelf with some random textbooks +/obj/structure/bookcase/skill_books/random/WillContain() + . = list() + for(var/category in catalogue) + for(var/real_book in subtypesof(category)) + if(prob(20)) + . |= real_book diff --git a/code/game/objects/items/books/skill/_skill_custom.dm b/code/game/objects/items/books/skill/_skill_custom.dm new file mode 100644 index 000000000000..736cd80fe022 --- /dev/null +++ b/code/game/objects/items/books/skill/_skill_custom.dm @@ -0,0 +1,192 @@ +////////////////////// +//Custom Skill Books// +////////////////////// + +//custom skill books made by players. Right now it is extremely dodgy and bad and i'm sorry +/obj/item/book/skill/custom + name = "blank textbook" + desc = "A somewhat heftier blank book, just ready to filled with knowledge and sold at an unreasonable price." + custom = TRUE + author = null + progress = 0 + icon = 'icons/obj/items/books/book_white.dmi' + var/skill_option_string = "Skill" //changes to "continue writing content" when the book is in progress + var/true_author //Used to keep track of who is actually writing the book. + var/writing_time = 15 SECONDS // time it takes to write a segment of the book. This happens 6 times total + +//these all show up in the book fabricator +/obj/item/book/skill/custom/circle + icon = 'icons/obj/items/books/book_white_circle.dmi' +/obj/item/book/skill/custom/star + icon = 'icons/obj/items/books/book_white_star.dmi' +/obj/item/book/skill/custom/hourglass + icon = 'icons/obj/items/books/book_white_hourglass.dmi' +/obj/item/book/skill/custom/cracked + icon = 'icons/obj/items/books/book_white_cracked.dmi' +/obj/item/book/skill/custom/gun + icon = 'icons/obj/items/books/book_white_gun.dmi' +/obj/item/book/skill/custom/wrench + icon = 'icons/obj/items/books/book_white_wrench.dmi' +/obj/item/book/skill/custom/glass + icon = 'icons/obj/items/books/book_white_glass.dmi' + +/obj/item/book/skill/custom/cross + icon = 'icons/obj/items/books/book_white_cross.dmi' +/obj/item/book/skill/custom/text + icon = 'icons/obj/items/books/book_white_text.dmi' +/obj/item/book/skill/custom/download + icon = 'icons/obj/items/books/book_white_download.dmi' +/obj/item/book/skill/custom/uparrow + icon = 'icons/obj/items/books/book_white_uparrow.dmi' +/obj/item/book/skill/custom/percent + icon = 'icons/obj/items/books/book_white_percent.dmi' +/obj/item/book/skill/custom/flask + icon = 'icons/obj/items/books/book_white_flask.dmi' +/obj/item/book/skill/custom/detective + icon = 'icons/obj/items/books/book_white_detective.dmi' +/obj/item/book/skill/custom/device + icon = 'icons/obj/items/books/book_white_device.dmi' +/obj/item/book/skill/custom/smile + icon = 'icons/obj/items/books/book_white_smile.dmi' +/obj/item/book/skill/custom/exclamation + icon = 'icons/obj/items/books/book_white_exclamation.dmi' +/obj/item/book/skill/custom/question + icon = 'icons/obj/items/books/book_white_question.dmi' + +/obj/item/book/skill/custom/attackby(obj/item/used_item, mob/user) + if(!IS_PEN(used_item)) + return ..() + if(!user.skill_check(SKILL_LITERACY, SKILL_BASIC)) + to_chat(user, SPAN_WARNING("You can't even read, yet you want to write a whole educational textbook?")) + return TRUE + if(!user.skill_check(SKILL_LITERACY, SKILL_PROF)) + to_chat(user, SPAN_WARNING("You have no clue as to how to write an entire textbook in a way that is actually useful. Maybe a regular book would be better?")) + return TRUE + var/state_check = skill_option_string // the state skill_option_string is in just before opening the input + var/choice = input(user, "What would you like to change?","Textbook editing") as null|anything in list("Title", "Author", skill_option_string) + if(!can_write(used_item,user)) + return TRUE + + switch(choice) + if("Title") + edit_title(used_item, user) + + if("Skill") + if(state_check != "Skill") // make sure someone hasn't already started the book while we were staring at menus woops + to_chat(user, SPAN_WARNING("The skill has already been selected and the writing started.")) + return TRUE + edit_skill(used_item, user) + + if("Continue writing content") + if(state_check != "Continue writing content") + return TRUE + continue_skill(used_item, user) + + if("Author") + edit_author(used_item, user) + + else + return TRUE + + if(skill && title && author) // we have everything we need so lets set a good description + desc = "A handwritten textbook titled [title], by [author]. Looks like it teaches [skill_name]." + return TRUE + +/obj/item/book/skill/custom/proc/can_write(var/obj/item/pen, var/mob/user) + if(user.get_active_held_item() == pen && CanPhysicallyInteractWith(user,src) && !QDELETED(src) && !QDELETED(pen)) + return TRUE + else + to_chat(user,SPAN_DANGER("How can you expect to write anything when you can't physically put pen to paper?")) + return FALSE + +/obj/item/book/skill/custom/proc/edit_title(var/obj/item/pen, var/mob/user) + var/newtitle = reject_bad_text(sanitize_safe(input(user, "Write a new title:"))) + if(!can_write(pen,user)) + return + if(!newtitle) + to_chat(user, "The title is invalid.") + return + else + newtitle = user.handle_writing_literacy(user, newtitle) + if(newtitle) + title = newtitle + SetName(title) + +/obj/item/book/skill/custom/proc/edit_author(var/obj/item/pen, var/mob/user) + var/newauthor = sanitize(input(user, "Write the author's name:")) + if(!can_write(pen,user)) + return + if(!newauthor) + to_chat(user, SPAN_WARNING("The author name is invalid.")) + return + else + newauthor = user.handle_writing_literacy(user, newauthor) + if(newauthor) + author = newauthor + +/obj/item/book/skill/custom/proc/edit_skill(var/obj/item/pen, var/mob/user) + if(user.skillset.literacy_charges <= 0) + to_chat(user, SPAN_WARNING(pick(charge_messages))) + return + + //Choosing the skill + var/list/skill_choices = list() + for(var/decl/skill/S in global.using_map.get_available_skills()) + if(user.skill_check(S.type, SKILL_BASIC)) + LAZYADD(skill_choices, S) + var/decl/skill/skill_choice = input(user, "What subject does your textbook teach?", "Textbook skill selection") as null|anything in skill_choices + if(!can_write(pen,user) || progress > length(progress_messages)) + return + if(!skill_choice) + to_chat(user, SPAN_WARNING("Textbook skill selection cancelled.")) + return + var/newskill = skill_choice.type + + //Choosing the level + var/list/skill_levels = skill_choice.levels.Copy() + for(var/SL in skill_levels) + if(!user.skill_check(newskill, skill_levels.Find(SL))) + LAZYREMOVE(skill_levels, SL) + else + skill_levels[SL] = skill_levels.Find(SL) + LAZYREMOVE(skill_levels,skill_levels[1]) + var/newskill_level = input(user, "What level of education does it provide?","Textbook skill level") as null|anything in skill_levels + if(!can_write(pen,user) || progress > length(progress_messages)) + return + if(!newskill_level) + to_chat(user, SPAN_WARNING("Textbook skill level selection cancelled.")) + return + var/usable_level = skill_levels[newskill_level] + if(newskill && usable_level) + if(!do_after(user, writing_time, src)) + to_chat(user, SPAN_DANGER(pick(failure_messages))) + return + //everything worked out so now we can put the learnings in the book + to_chat(user, SPAN_NOTICE("You start writing your book, getting a few pages in.")) + skill = newskill + skill_name = skill_choice.name + skill_req = (usable_level - 1) + desc = "A handwritten textbook on [skill_choice]! Wow!" + progress++ + skill_option_string = "Continue writing content" + true_author = user.name + +/obj/item/book/skill/custom/proc/continue_skill(var/obj/item/pen, var/mob/user) + if(user.skillset.literacy_charges <= 0) + to_chat(user, SPAN_WARNING(pick(charge_messages))) + return + if(progress > length(progress_messages)) // shouldn't happen but here just in case + to_chat(user, SPAN_WARNING("This book is already finished! There's no need to add anything else!")) + return + if(true_author != user.name) + to_chat(user, SPAN_WARNING("This isn't your work and you're not really sure how to continue it.")) + return + else + if(!do_after(user, writing_time, src)) + to_chat(user, SPAN_DANGER(pick(failure_messages))) + return + to_chat(user, SPAN_NOTICE("You continue writing your book. [progress_messages[progress]]")) + progress++ + if(progress > length(progress_messages)) // book is finished! yay! + user.skillset.literacy_charges -= 1 + skill_option_string = "Cancel" \ No newline at end of file diff --git a/code/game/objects/items/books/skill/engineering.dm b/code/game/objects/items/books/skill/engineering.dm new file mode 100644 index 000000000000..f5809f18a2a3 --- /dev/null +++ b/code/game/objects/items/books/skill/engineering.dm @@ -0,0 +1,96 @@ +/* +ENGINEERING +*/ +/obj/item/book/skill/engineering + abstract_type = /obj/item/book/skill/engineering + icon = 'icons/obj/items/books/book_engineering.dmi' + +//construction +/obj/item/book/skill/engineering/construction/ + author = "Robert Bildar" + skill = SKILL_CONSTRUCTION + +/obj/item/book/skill/engineering/construction/basic + name = "beginner construction textbook" + +/obj/item/book/skill/engineering/construction/adept + skill_req = SKILL_BASIC + name = "intermediate construction textbook" + +/obj/item/book/skill/engineering/construction/expert + skill_req = SKILL_ADEPT + name = "advanced construction textbook" + +/obj/item/book/skill/engineering/construction/prof + skill_req = SKILL_EXPERT + name = "theoretical construction textbook" + +//electrical +/obj/item/book/skill/engineering/electrical + skill = SKILL_ELECTRICAL + author = "Ariana Vanderbalt" + +/obj/item/book/skill/engineering/electrical/basic + name = "beginner electrical engineering textbook" + +/obj/item/book/skill/engineering/electrical/adept + skill_req = SKILL_BASIC + name = "intermediate electrical engineering textbook" + +/obj/item/book/skill/engineering/electrical/expert + skill_req = SKILL_ADEPT + name = "advanced electrical engineering textbook" + +/obj/item/book/skill/engineering/electrical/prof + skill_req = SKILL_EXPERT + name = "theoretical electrical engineering textbook" + +//engines +/obj/item/book/skill/engineering/engines + skill = SKILL_ENGINES + author = "Gilgamesh Scholz" + +/obj/item/book/skill/engineering/engines/basic + name = "beginner engines textbook" + +/obj/item/book/skill/engineering/engines/adept + skill_req = SKILL_BASIC + name = "intermediate engines textbook" + +/obj/item/book/skill/engineering/engines/expert + skill_req = SKILL_ADEPT + name = "advanced engines textbook" + +/obj/item/book/skill/engineering/engines/prof + skill_req = SKILL_EXPERT + name = "theoretical engines textbook" + +/obj/item/book/skill/engineering/engines/prof/magazine + name = "theoretical engines magazine" + title = "\improper WetSkrell magazine" + icon_state = "bookMagazine" + custom = TRUE + author = "Unknown" + desc = "Sure, it includes highly detailed information on extremely advanced engine and power generator systems... but why is it written in marker on a tentacle porn magazine?" + w_class = ITEM_SIZE_NORMAL + +//atmos +/obj/item/book/skill/engineering/atmos + skill = SKILL_ATMOS + author = "Maria Crash" + icon = 'icons/obj/items/books/book_piping.dmi' + +/obj/item/book/skill/engineering/atmos/basic + name = "beginner atmospherics textbook" + +/obj/item/book/skill/engineering/atmos/adept + skill_req = SKILL_BASIC + name = "intermediate atmospherics textbook" + +/obj/item/book/skill/engineering/atmos/expert + skill_req = SKILL_ADEPT + name = "advanced atmospherics textbook" + +/obj/item/book/skill/engineering/atmos/prof + skill_req = SKILL_EXPERT + name = "theoretical atmospherics textbook" diff --git a/code/game/objects/items/books/skill/general.dm b/code/game/objects/items/books/skill/general.dm new file mode 100644 index 000000000000..0fa6fa86b531 --- /dev/null +++ b/code/game/objects/items/books/skill/general.dm @@ -0,0 +1,110 @@ +/* +GENERAL +*/ +/obj/item/book/skill/general + abstract_type = /obj/item/book/skill/general + +//eva +/obj/item/book/skill/general/eva + icon = 'icons/obj/items/books/book_eva.dmi' + skill = SKILL_EVA + author = "Big Dark" + +/obj/item/book/skill/general/eva/basic + name = "beginner extra-vehicular activity textbook" + +/obj/item/book/skill/general/eva/adept + skill_req = SKILL_BASIC + name = "intermediate extra-vehicular activity textbook" + +/obj/item/book/skill/general/eva/expert + skill_req = SKILL_ADEPT + name = "advanced extra-vehicular activity textbook" + +/obj/item/book/skill/general/eva/prof + skill_req = SKILL_EXPERT + name = "theoretical extra-vehicular activity textbook" + +//mech +/obj/item/book/skill/general/mech + icon = 'icons/obj/items/books/book_mech.dmi' + skill = SKILL_MECH + author = "J.T. Marsh" + +/obj/item/book/skill/general/mech/basic + name = "beginner exosuit operation textbook" + +/obj/item/book/skill/general/mech/adept + skill_req = SKILL_BASIC + name = "intermediate exosuit operation textbook" + +/obj/item/book/skill/general/mech/expert + skill_req = SKILL_ADEPT + name = "advanced exosuit operation textbook" + +/obj/item/book/skill/general/mech/prof + skill_req = SKILL_EXPERT + name = "theoretical exosuit operation textbook" + +//piloting +/obj/item/book/skill/general/pilot + skill = SKILL_PILOT + author = "Sumi Shimamoto" + icon = 'icons/obj/items/books/book_pilot.dmi' + +/obj/item/book/skill/general/pilot/basic + name = "beginner piloting textbook" + +/obj/item/book/skill/general/pilot/adept + skill_req = SKILL_BASIC + name = "intermediate piloting textbook" + +/obj/item/book/skill/general/pilot/expert + skill_req = SKILL_ADEPT + name = "advanced piloting textbook" + +/obj/item/book/skill/general/pilot/prof + skill_req = SKILL_EXPERT + name = "theoretical piloting textbook" + +//hauling +/obj/item/book/skill/general/hauling + skill = SKILL_HAULING + author = "Chiel Brunt" + icon = 'icons/obj/items/books/book_hauling.dmi' + +/obj/item/book/skill/general/hauling/basic + name = "beginner athletics textbook" + +/obj/item/book/skill/general/hauling/adept + skill_req = SKILL_BASIC + name = "intermediate athletics textbook" + +/obj/item/book/skill/general/hauling/expert + skill_req = SKILL_ADEPT + name = "advanced athletics textbook" + +/obj/item/book/skill/general/hauling/prof + skill_req = SKILL_EXPERT + name = "theoretical athletics textbook" + +//computer +/obj/item/book/skill/general/computer + skill = SKILL_COMPUTER + author = "Simona Castiglione" + icon = 'icons/obj/items/books/book_nuclear.dmi' + +/obj/item/book/skill/general/computer/basic + name = "beginner information technology textbook" + +/obj/item/book/skill/general/computer/adept + skill_req = SKILL_BASIC + name = "intermediate information technology textbook" + +/obj/item/book/skill/general/computer/expert + skill_req = SKILL_ADEPT + name = "advanced information technology textbook" + +/obj/item/book/skill/general/computer/prof + skill_req = SKILL_EXPERT + name = "theoretical information technology textbook" diff --git a/code/game/objects/items/books/skill/medical.dm b/code/game/objects/items/books/skill/medical.dm new file mode 100644 index 000000000000..9bdc4f2f2d8c --- /dev/null +++ b/code/game/objects/items/books/skill/medical.dm @@ -0,0 +1,71 @@ +/* +MEDICAL +*/ +/obj/item/book/skill/medical + abstract_type = /obj/item/book/skill/medical + icon = 'icons/obj/items/books/book_medical.dmi' + +//chemistry +/obj/item/book/skill/medical/chemistry + icon = 'icons/obj/items/books/book_chemistry.dmi' + author = "Dr. Shinula Nyekundujicho" + skill = SKILL_CHEMISTRY + +/obj/item/book/skill/medical/chemistry/basic + name = "beginner chemistry textbook" + +/obj/item/book/skill/medical/chemistry/adept + skill_req = SKILL_BASIC + name = "intermediate chemistry textbook" + +/obj/item/book/skill/medical/chemistry/expert + skill_req = SKILL_ADEPT + name = "advanced chemistry textbook" + +/obj/item/book/skill/medical/chemistry/prof + skill_req = SKILL_EXPERT + name = "theoretical chemistry textbook" + +//medicine +/obj/item/book/skill/medical/medicine + author = "Dr. Nagarjuna Siddha" + skill = SKILL_MEDICAL + +/obj/item/book/skill/medical/medicine/basic + name = "beginner medicine textbook" + title = "\"Instructional Guide on How Rubbing Dirt In Wounds Might Not Be The Right Approach To Stopping Bleeding Anymore\"" + desc = "A copy of \"Instructional Guide on How Rubbing Dirt In Wounds Might Not Be The Right Approach To Stopping Bleeding Anymore\" by Dr. Merrs. Despite the information density of this heavy book, it lacks any and all teachings regarding bedside manner." + author = "Dr. Merrs" + custom = TRUE + +/obj/item/book/skill/medical/medicine/adept + skill_req = SKILL_BASIC + name = "intermediate medicine textbook" + +/obj/item/book/skill/medical/medicine/expert + skill_req = SKILL_ADEPT + name = "advanced medicine textbook" + +/obj/item/book/skill/medical/medicine/prof + skill_req = SKILL_EXPERT + name = "theoretical medicine textbook" + +//anatomy +/obj/item/book/skill/medical/anatomy + author = "Dr. Basil Cartwright" + skill = SKILL_ANATOMY + +/obj/item/book/skill/medical/anatomy/basic + name = "beginner anatomy textbook" + +/obj/item/book/skill/medical/anatomy/adept + skill_req = SKILL_BASIC + name = "intermediate anatomy textbook" + +/obj/item/book/skill/medical/anatomy/expert + skill_req = SKILL_ADEPT + name = "advanced anatomy textbook" + +/obj/item/book/skill/medical/anatomy/prof + skill_req = SKILL_EXPERT + name = "theoretical anatomy textbook" \ No newline at end of file diff --git a/code/game/objects/items/books/skill/organizational.dm b/code/game/objects/items/books/skill/organizational.dm new file mode 100644 index 000000000000..5c605b4bc15f --- /dev/null +++ b/code/game/objects/items/books/skill/organizational.dm @@ -0,0 +1,38 @@ +/* +ORGANIZATIONAL +*/ +/obj/item/book/skill/organizational + abstract_type = /obj/item/book/skill/organizational + +//literacy +/obj/item/book/skill/organizational/literacy + skill = SKILL_LITERACY + +/obj/item/book/skill/organizational/literacy/basic + name = "alphabet book" + icon = 'icons/obj/items/books/book_literacy.dmi' + author = "Dorothy Mulch" + custom = TRUE + w_class = ITEM_SIZE_NORMAL // A little bit smaller c: + ez_read = TRUE + +//finance +/obj/item/book/skill/organizational/finance + skill = SKILL_FINANCE + author = "Cadence Bennett" + icon = 'icons/obj/items/books/book_finance.dmi' + +/obj/item/book/skill/organizational/finance/basic + name = "beginner finance textbook" + +/obj/item/book/skill/organizational/finance/adept + skill_req = SKILL_BASIC + name = "intermediate finance textbook" + +/obj/item/book/skill/organizational/finance/expert + skill_req = SKILL_ADEPT + name = "advanced finance textbook" + +/obj/item/book/skill/organizational/finance/prof + skill_req = SKILL_EXPERT + name = "theoretical finance textbook" diff --git a/code/game/objects/items/books/skill/research.dm b/code/game/objects/items/books/skill/research.dm new file mode 100644 index 000000000000..c9ffc9b8dbb1 --- /dev/null +++ b/code/game/objects/items/books/skill/research.dm @@ -0,0 +1,46 @@ +/* +RESEARCH +*/ +/obj/item/book/skill/research + abstract_type = /obj/item/book/skill/research + icon = 'icons/obj/items/books/book_analysis.dmi' + +//devices +/obj/item/book/skill/research/devices + author = "Nilva Plosinjak" + skill = SKILL_DEVICES + +/obj/item/book/skill/research/devices/basic + name = "beginner complex devices textbook" + +/obj/item/book/skill/research/devices/adept + skill_req = SKILL_BASIC + name = "intermediate complex devices textbook" + +/obj/item/book/skill/research/devices/expert + skill_req = SKILL_ADEPT + name = "advanced complex devices textbook" + +/obj/item/book/skill/research/devices/prof + skill_req = SKILL_EXPERT + name = "theoretical complex devices textbook" + +//science +/obj/item/book/skill/research/science + author = "Hui Ying Ch'ien" + skill = SKILL_SCIENCE + +/obj/item/book/skill/research/science/basic + name = "beginner science textbook" + +/obj/item/book/skill/research/science/adept + skill_req = SKILL_BASIC + name = "intermediate science textbook" + +/obj/item/book/skill/research/science/expert + skill_req = SKILL_ADEPT + name = "advanced science textbook" + +/obj/item/book/skill/research/science/prof + skill_req = SKILL_EXPERT + name = "theoretical science textbook" diff --git a/code/game/objects/items/books/skill/security.dm b/code/game/objects/items/books/skill/security.dm new file mode 100644 index 000000000000..9f54d386e051 --- /dev/null +++ b/code/game/objects/items/books/skill/security.dm @@ -0,0 +1,69 @@ +/* +SECURITY +*/ +/obj/item/book/skill/security + abstract_type = /obj/item/book/skill/security + icon = 'icons/obj/items/books/book_law.dmi' + +//combat +/obj/item/book/skill/security/combat + skill = SKILL_COMBAT + author = "Autumn Eckhardstein" + icon = 'icons/obj/items/books/book_combat.dmi' + +/obj/item/book/skill/security/combat/basic + name = "beginner close combat textbook" + +/obj/item/book/skill/security/combat/adept + skill_req = SKILL_BASIC + name = "intermediate close combat textbook" + +/obj/item/book/skill/security/combat/expert + skill_req = SKILL_ADEPT + name = "advanced close combat textbook" + +/obj/item/book/skill/security/combat/prof + skill_req = SKILL_EXPERT + name = "theoretical close combat textbook" + +//weapons +/obj/item/book/skill/security/weapons + skill = SKILL_WEAPONS + author = "Miho Tatsu" + icon = 'icons/obj/items/books/book_weapon.dmi' + +/obj/item/book/skill/security/weapons/basic + name = "beginner weapons expertise textbook" + +/obj/item/book/skill/security/weapons/adept + skill_req = SKILL_BASIC + name = "intermediate weapons expertise textbook" + +/obj/item/book/skill/security/weapons/expert + skill_req = SKILL_ADEPT + name = "advanced weapons expertise textbook" + +/obj/item/book/skill/security/weapons/prof + skill_req = SKILL_EXPERT + name = "theoretical weapons expertise textbook" + +//forensics +/obj/item/book/skill/security/forensics + icon = 'icons/obj/items/books/book_detective.dmi' + skill = SKILL_FORENSICS + author = "Samuel Vimes" + +/obj/item/book/skill/security/forensics/basic + name = "beginner forensics textbook" + +/obj/item/book/skill/security/forensics/adept + skill_req = SKILL_BASIC + name = "intermediate forensics textbook" + +/obj/item/book/skill/security/forensics/expert + skill_req = SKILL_ADEPT + name = "advanced forensics textbook" + +/obj/item/book/skill/security/forensics/prof + skill_req = SKILL_EXPERT + name = "theoretical forensics textbook" diff --git a/code/game/objects/items/books/skill/service.dm b/code/game/objects/items/books/skill/service.dm new file mode 100644 index 000000000000..d9795f0cb781 --- /dev/null +++ b/code/game/objects/items/books/skill/service.dm @@ -0,0 +1,47 @@ +/* +SERVICE +*/ +/obj/item/book/skill/service + abstract_type = /obj/item/book/skill/service + +//botany +/obj/item/book/skill/service/botany + icon = 'icons/obj/items/books/book_hydroponics.dmi' + skill = SKILL_BOTANY + author = "Mai Dong Chat" + +/obj/item/book/skill/service/botany/basic + name = "beginner botany textbook" + +/obj/item/book/skill/service/botany/adept + skill_req = SKILL_BASIC + name = "intermediate botany textbook" + +/obj/item/book/skill/service/botany/expert + skill_req = SKILL_ADEPT + name = "advanced botany textbook" + +/obj/item/book/skill/service/botany/prof + skill_req = SKILL_EXPERT + name = "theoretical botany textbook" + +//cooking +/obj/item/book/skill/service/cooking + icon = 'icons/obj/items/books/book_bartending.dmi' + skill = SKILL_COOKING + author = "Lavinia Burrows" + +/obj/item/book/skill/service/cooking/basic + name = "beginner cooking textbook" + +/obj/item/book/skill/service/cooking/adept + skill_req = SKILL_BASIC + name = "intermediate cooking textbook" + +/obj/item/book/skill/service/cooking/expert + skill_req = SKILL_ADEPT + name = "advanced cooking textbook" + +/obj/item/book/skill/service/cooking/prof + skill_req = SKILL_EXPERT + name = "theoretical cooking textbook" diff --git a/code/game/objects/items/books/skill_book.dm b/code/game/objects/items/books/skill_book.dm deleted file mode 100644 index 0ad8e635ca57..000000000000 --- a/code/game/objects/items/books/skill_book.dm +++ /dev/null @@ -1,897 +0,0 @@ -#define RANDOM_BOOK_TITLE(skill_name) pick(list("\"[skill_name] for Idiots\"", \ - "\"How To Learn [skill_name] and Not Get Laughed At\"", \ - "\"Teaching Yourself [skill_name]: Volume [rand(1,100)]\"", \ - "\"Getting the Hands-Off Experience You Need with [skill_name]\"", \ - "\"Master [skill_name] in [rand(100,999)] easy steps!\"", \ - "\"[skill_name] Just Like Mum\"", \ - "\"How To [skill_name] Good Enough For Your Father\"", \ - "\"How To Win Your Dad's Approval With [skill_name]\"", \ - "\"Make a Living with [skill_name] Like Your Old Man Always Wanted You To\"", \ - "\"[skill_name]: Secret Techniques\"", \ - "\"The Dos, Don'ts and Oh Gods Please Nos of [skill_name]\"", \ - "\"The Death Of [skill_name]\"", \ - "\"Everything You Never Wanted To Know About [skill_name] But Have Been Reluctantly Forced To Find Out\"", \ - "\"[skill_name] For The Busy Professional\"", \ - "\"Learning [skill_name] In A Hurry Because You Lied On Your Resume\"", \ - "\"Help! My Life Suddenly Depends On [skill_name]\"", \ - "\"What The Fuck is [capitalize(ADD_ARTICLE(capitalize(skill_name)))]?\"", \ - "\"Starting [capitalize(ADD_ARTICLE(capitalize(skill_name)))] Business By Yourself\"", \ - "\"Even You Can Learn [skill_name]!\"", \ - "\"How To Impress Your Matriarch with [skill_name]\"", \ - "\"How To Become A Patriarch of [skill_name]\"", \ - "\"Everything The Government Doesn't Want You To Know About [skill_name]\"", \ - "\"[skill_name] For Younglets\"", \ - "\"[skill_name]: Volume [rand(1,100)]\"", \ - "\"Understanding [skill_name]: [rand(1,100)]\th Edition\"", \ - "\"Dealing With Ungrateful Customers Dissatisfied With Your Perfectly Acceptable [skill_name] Services\"", \ - "\"Really big book of [skill_name]\"")) -#define SKILLBOOK_PROG_NONE 0 -#define SKILLBOOK_PROG_FINISH 6 - -/* -Skill books that increase your skills while you activate and hold them -*/ - -/obj/item/book/skill - name = "default textbook" // requires default names for tradershop, cant rely on Initialize for names - desc = "A blank textbook. (Notify admin)" - author = "The Oracle of Bakersroof" - icon_state = "book2" - force = 4 - w_class = ITEM_SIZE_LARGE //Skill books are THICC with knowledge. Up one level from regular books to prevent library-in-a-bag silliness. - unique = 1 - material = /decl/material/solid/plastic - matter = list(/decl/material/solid/wood = MATTER_AMOUNT_REINFORCEMENT) - - var/decl/hierarchy/skill/skill // e.g. SKILL_LITERACY - var/skill_req //The level the user needs in the skill to benefit from the book, e.g. SKILL_PROF - var/reading = FALSE //Tto check if the book is actively being used - var/custom = FALSE //To bypass init stuff, for player made textbooks and weird books. If true must have details manually set - var/ez_read = FALSE //Set to TRUE if you can read it without basic literacy skills - - var/skill_name = "missing skill name" - var/progress = SKILLBOOK_PROG_FINISH // used to track the progress of making a custom book. defaults as finished so, you know, you can read the damn thing - -/obj/item/book/skill/Initialize() - . = ..() - if(!custom && skill && skill_req)// custom books should already have all they need - skill_name = initial(skill.name) - title = RANDOM_BOOK_TITLE(capitalize(initial(skill.name))) - switch(skill_req) // check what skill_req the book has - if(1) // none > basic - name = "beginner [skill_name] textbook" - desc = "A copy of [title] by [author]. The only reason this book is so big is because all the words are printed very large! Presumably so you, an idiot, can read it." - if(2) // basic > adept - name = "intermediate [skill_name] textbook" - desc = "A copy of [title] by [author]. Dry and long, but not unmanageable. Basic knowledge is required to understand the concepts written." - if(3) // adept > expert - name = "advanced [skill_name] textbook" - desc = "A copy of [title] by [author]. Those not already trained in the subject will have a hard time reading this. Try not to drop it either, it will put a hole in the floor." - if(4) //expert > prof - name = "theoretical [skill_name] textbook" - desc = "A copy of [title] by [author]. Significant experience in the subject is required to read this incredibly information dense block of paper. Sadly, does not come in audio form." - if((!skill || !skill_req) && !custom)//That's a bad book, so just grab ANY child to replace it. Custom books are fine though they can be bad if they want. - if(subtypesof(src.type)) - var/new_book = pick(subtypesof(src.type)) - new new_book(src.loc) - qdel_self() - -/datum/skill_buff/skill_book - limit = 1 // you can only read one book at a time nerd, therefore you can only get one buff at a time - -/obj/item/book/skill/attack_self(mob/user) - if(!skill || (custom && progress == SKILLBOOK_PROG_NONE)) - to_chat(user, SPAN_WARNING("The textbook is blank!")) - return - if(custom && progress < SKILLBOOK_PROG_FINISH) - to_chat(user, SPAN_WARNING("The textbook is unfinished! You can't learn from it in this state!")) - return - if(!ez_read &&!user.skill_check(SKILL_LITERACY, SKILL_BASIC)) - to_chat(user, SPAN_WARNING(pick("Haha, you know you can't read. Good joke. Put [title] back.","You open up [title], but there aren't any pictures, so you close it again.","You don't know how to read! What good is this [name] to you?!"))) - return - - if(reading) //Close book, get rid of buffs - src.unlearn(user) - to_chat(user, SPAN_NOTICE("You close the [name]. That's enough learning for now.")) - reading = FALSE - return - - if(user.too_many_buffs(/datum/skill_buff/skill_book)) - to_chat(user, SPAN_WARNING("You can't read two books at once!")) - return - - if(!user.skill_check(skill, skill_req)) - to_chat(user, SPAN_WARNING("[title] is too advanced for you! Try something easier, perhaps the \"For Idiots\" edition?")) - return - if(user.get_skill_value(skill) > skill_req) - to_chat(user, SPAN_WARNING("You already know everything [title] has to teach you!")) - return - - to_chat(user, SPAN_NOTICE("You open up the [name] and start reading...")) - if(user.do_skilled(4 SECONDS, SKILL_LITERACY, src, 0.75)) - var/list/buff = list() - buff[skill] = 1 - user.buff_skill(buff, buff_type = /datum/skill_buff/skill_book) - reading = TRUE - to_chat(user, SPAN_NOTICE("You find the information you need! Better keep the page open to reference it.")) - else - to_chat(user, SPAN_DANGER("Your perusal of the [name] was interrupted!")) - return - -// buff removal -/obj/item/book/skill/proc/unlearn(var/mob/user) - var/list/F = user.fetch_buffs_of_type(/datum/skill_buff/skill_book, 0) - for(var/datum/skill_buff/skill_book/S in F) - S.remove() - -// Remove buffs when book goes away -/obj/item/book/skill/dropped(mob/user) - if(reading) - to_chat(user, SPAN_DANGER("You lose the page you were on! You can't cross-reference using the [name] like this!")) - var/mob/M = user - if(istype(M) && M.fetch_buffs_of_type(/datum/skill_buff/skill_book, 0)) - src.unlearn(user) - reading = FALSE - . = ..() -/obj/item/book/skill/Destroy() - var/mob/M = loc - if(istype(M) && M.fetch_buffs_of_type(/datum/skill_buff/skill_book, 0)) - src.unlearn(M) - . = ..() - -/obj/item/book/skill/get_codex_value() - return "textbook" - -//////////////////////////////// -//THIS IS WHERE THE BOOKS LIVE// -//////////////////////////////// - -/* -ORGANIZATIONAL -*/ -/obj/item/book/skill/organizational - -//literacy -/obj/item/book/skill/organizational/literacy - skill = SKILL_LITERACY - -/obj/item/book/skill/organizational/literacy/basic - name = "alphabet book" - icon_state = "tb_literacy" - author = "Dorothy Mulch" - skill_req = SKILL_NONE - custom = TRUE - w_class = ITEM_SIZE_NORMAL // A little bit smaller c: - ez_read = TRUE - -//finance -/obj/item/book/skill/organizational/finance - skill = SKILL_FINANCE - author = "Cadence Bennett" - icon_state = "tb_finance" - -/obj/item/book/skill/organizational/finance/basic - skill_req = SKILL_NONE - name = "beginner finance textbook" - -/obj/item/book/skill/organizational/finance/adept - skill_req = SKILL_BASIC - name = "intermediate finance textbook" - -/obj/item/book/skill/organizational/finance/expert - skill_req = SKILL_ADEPT - name = "advanced finance textbook" - -/obj/item/book/skill/organizational/finance/prof - skill_req = SKILL_EXPERT - name = "theoretical finance textbook" - -/* -GENERAL -*/ -/obj/item/book/skill/general - -//eva -/obj/item/book/skill/general/eva - icon_state = "evabook" - skill = SKILL_EVA - author = "Big Dark" - -/obj/item/book/skill/general/eva/basic - skill_req = SKILL_NONE - name = "beginner extra-vehicular activity textbook" - -/obj/item/book/skill/general/eva/adept - skill_req = SKILL_BASIC - name = "intermediate extra-vehicular activity textbook" - -/obj/item/book/skill/general/eva/expert - skill_req = SKILL_ADEPT - name = "advanced extra-vehicular activity textbook" - -/obj/item/book/skill/general/eva/prof - skill_req = SKILL_EXPERT - name = "theoretical extra-vehicular activity textbook" - -//mech -/obj/item/book/skill/general/mech - icon_state = "tb_mech" - skill = SKILL_MECH - author = "J.T. Marsh" - -/obj/item/book/skill/general/mech/basic - skill_req = SKILL_NONE - name = "beginner exosuit operation textbook" - -/obj/item/book/skill/general/mech/adept - skill_req = SKILL_BASIC - name = "intermediate exosuit operation textbook" - -/obj/item/book/skill/general/mech/expert - skill_req = SKILL_ADEPT - name = "advanced exosuit operation textbook" - -/obj/item/book/skill/general/mech/prof - skill_req = SKILL_EXPERT - name = "theoretical exosuit operation textbook" - -//piloting -/obj/item/book/skill/general/pilot - skill = SKILL_PILOT - author = "Sumi Shimamoto" - icon_state = "tb_pilot" - -/obj/item/book/skill/general/pilot/basic - skill_req = SKILL_NONE - name = "beginner piloting textbook" - -/obj/item/book/skill/general/pilot/adept - skill_req = SKILL_BASIC - name = "intermediate piloting textbook" - -/obj/item/book/skill/general/pilot/expert - skill_req = SKILL_ADEPT - name = "advanced piloting textbook" - -/obj/item/book/skill/general/pilot/prof - skill_req = SKILL_EXPERT - name = "theoretical piloting textbook" - -//hauling -/obj/item/book/skill/general/hauling - skill = SKILL_HAULING - author = "Chiel Brunt" - icon_state = "tb_hauling" - -/obj/item/book/skill/general/hauling/basic - skill_req = SKILL_NONE - name = "beginner athletics textbook" - -/obj/item/book/skill/general/hauling/adept - skill_req = SKILL_BASIC - name = "intermediate athletics textbook" - -/obj/item/book/skill/general/hauling/expert - skill_req = SKILL_ADEPT - name = "advanced athletics textbook" - -/obj/item/book/skill/general/hauling/prof - skill_req = SKILL_EXPERT - name = "theoretical athletics textbook" - -//computer -/obj/item/book/skill/general/computer - skill = SKILL_COMPUTER - author = "Simona Castiglione" - icon_state = "bookNuclear" - -/obj/item/book/skill/general/computer/basic - skill_req = SKILL_NONE - name = "beginner information technology textbook" - -/obj/item/book/skill/general/computer/adept - skill_req = SKILL_BASIC - name = "intermediate information technology textbook" - -/obj/item/book/skill/general/computer/expert - skill_req = SKILL_ADEPT - name = "advanced information technology textbook" - -/obj/item/book/skill/general/computer/prof - skill_req = SKILL_EXPERT - name = "theoretical information technology textbook" - -/* -SERVICE -*/ -/obj/item/book/skill/service - -//botany -/obj/item/book/skill/service/botany - icon_state = "bookHydroponicsPodPeople" - skill = SKILL_BOTANY - author = "Mai Dong Chat" - -/obj/item/book/skill/service/botany/basic - skill_req = SKILL_NONE - name = "beginner botany textbook" - -/obj/item/book/skill/service/botany/adept - skill_req = SKILL_BASIC - name = "intermediate botany textbook" - -/obj/item/book/skill/service/botany/expert - skill_req = SKILL_ADEPT - name = "advanced botany textbook" - -/obj/item/book/skill/service/botany/prof - skill_req = SKILL_EXPERT - name = "theoretical botany textbook" - -//cooking -/obj/item/book/skill/service/cooking - icon_state = "barbook" - skill = SKILL_COOKING - author = "Lavinia Burrows" - -/obj/item/book/skill/service/cooking/basic - skill_req = SKILL_NONE - name = "beginner cooking textbook" - -/obj/item/book/skill/service/cooking/adept - skill_req = SKILL_BASIC - name = "intermediate cooking textbook" - -/obj/item/book/skill/service/cooking/expert - skill_req = SKILL_ADEPT - name = "advanced cooking textbook" - -/obj/item/book/skill/service/cooking/prof - skill_req = SKILL_EXPERT - name = "theoretical cooking textbook" - -/* -SECURITY -*/ -/obj/item/book/skill/security - icon_state = "bookSpaceLaw" - -//combat -/obj/item/book/skill/security/combat - skill = SKILL_COMBAT - author = "Autumn Eckhardstein" - icon_state = "tb_combat" - -/obj/item/book/skill/security/combat/basic - skill_req = SKILL_NONE - name = "beginner close combat textbook" - -/obj/item/book/skill/security/combat/adept - skill_req = SKILL_BASIC - name = "intermediate close combat textbook" - -/obj/item/book/skill/security/combat/expert - skill_req = SKILL_ADEPT - name = "advanced close combat textbook" - -/obj/item/book/skill/security/combat/prof - skill_req = SKILL_EXPERT - name = "theoretical close combat textbook" - -//weapons -/obj/item/book/skill/security/weapons - skill = SKILL_WEAPONS - author = "Miho Tatsu" - icon_state = "tb_weapon" - -/obj/item/book/skill/security/weapons/basic - skill_req = SKILL_NONE - name = "beginner weapons expertise textbook" - -/obj/item/book/skill/security/weapons/adept - skill_req = SKILL_BASIC - name = "intermediate weapons expertise textbook" - -/obj/item/book/skill/security/weapons/expert - skill_req = SKILL_ADEPT - name = "advanced weapons expertise textbook" - -/obj/item/book/skill/security/weapons/prof - skill_req = SKILL_EXPERT - name = "theoretical weapons expertise textbook" - -//forensics -/obj/item/book/skill/security/forensics - icon_state = "bookDetective" - skill = SKILL_FORENSICS - author = "Samuel Vimes" - -/obj/item/book/skill/security/forensics/basic - skill_req = SKILL_NONE - name = "beginner forensics textbook" - -/obj/item/book/skill/security/forensics/adept - skill_req = SKILL_BASIC - name = "intermediate forensics textbook" - -/obj/item/book/skill/security/forensics/expert - skill_req = SKILL_ADEPT - name = "advanced forensics textbook" - -/obj/item/book/skill/security/forensics/prof - skill_req = SKILL_EXPERT - name = "theoretical forensics textbook" - -/* -ENGINEERING -*/ -/obj/item/book/skill/engineering - icon_state = "bookEngineering" - -//construction -/obj/item/book/skill/engineering/construction/ - author = "Robert Bildar" - skill = SKILL_CONSTRUCTION - -/obj/item/book/skill/engineering/construction/basic - skill_req = SKILL_NONE - name = "beginner construction textbook" - -/obj/item/book/skill/engineering/construction/adept - skill_req = SKILL_BASIC - name = "intermediate construction textbook" - -/obj/item/book/skill/engineering/construction/expert - skill_req = SKILL_ADEPT - name = "advanced construction textbook" - -/obj/item/book/skill/engineering/construction/prof - skill_req = SKILL_EXPERT - name = "theoretical construction textbook" - -//electrical -/obj/item/book/skill/engineering/electrical - skill = SKILL_ELECTRICAL - author = "Ariana Vanderbalt" - -/obj/item/book/skill/engineering/electrical/basic - skill_req = SKILL_NONE - name = "beginner electrical engineering textbook" - -/obj/item/book/skill/engineering/electrical/adept - skill_req = SKILL_BASIC - name = "intermediate electrical engineering textbook" - -/obj/item/book/skill/engineering/electrical/expert - skill_req = SKILL_ADEPT - name = "advanced electrical engineering textbook" - -/obj/item/book/skill/engineering/electrical/prof - skill_req = SKILL_EXPERT - name = "theoretical electrical engineering textbook" - -//atmos -/obj/item/book/skill/engineering/atmos - skill = SKILL_ATMOS - author = "Maria Crash" - icon_state = "pipingbook" - -/obj/item/book/skill/engineering/atmos/basic - skill_req = SKILL_NONE - name = "beginner atmospherics textbook" - -/obj/item/book/skill/engineering/atmos/adept - skill_req = SKILL_BASIC - name = "intermediate atmospherics textbook" - -/obj/item/book/skill/engineering/atmos/expert - skill_req = SKILL_ADEPT - name = "advanced atmospherics textbook" - -/obj/item/book/skill/engineering/atmos/prof - skill_req = SKILL_EXPERT - name = "theoretical atmospherics textbook" - -//engines -/obj/item/book/skill/engineering/engines - skill = SKILL_ENGINES - author = "Gilgamesh Scholz" - -/obj/item/book/skill/engineering/engines/basic - skill_req = SKILL_NONE - name = "beginner engines textbook" - -/obj/item/book/skill/engineering/engines/adept - skill_req = SKILL_BASIC - name = "intermediate engines textbook" - -/obj/item/book/skill/engineering/engines/expert - skill_req = SKILL_ADEPT - name = "advanced engines textbook" - -/obj/item/book/skill/engineering/engines/prof - skill_req = SKILL_EXPERT - name = "theoretical engines textbook" - -/obj/item/book/skill/engineering/engines/prof/magazine - name = "theoretical engines magazine" - title = "\improper WetSkrell magazine" - icon_state = "bookMagazine" - custom = TRUE - author = "Unknown" - desc = "Sure, it includes highly detailed information on extremely advanced engine and power generator systems... but why is it written in marker on a tentacle porn magazine?" - w_class = ITEM_SIZE_NORMAL - - -/* -RESEARCH -*/ -/obj/item/book/skill/research - icon_state = "analysis" - -//devices -/obj/item/book/skill/research/devices - author = "Nilva Plosinjak" - skill = SKILL_DEVICES - -/obj/item/book/skill/research/devices/basic - skill_req = SKILL_NONE - name = "beginner complex devices textbook" - -/obj/item/book/skill/research/devices/adept - skill_req = SKILL_BASIC - name = "intermediate complex devices textbook" - -/obj/item/book/skill/research/devices/expert - skill_req = SKILL_ADEPT - name = "advanced complex devices textbook" - -/obj/item/book/skill/research/devices/prof - skill_req = SKILL_EXPERT - name = "theoretical complex devices textbook" - -//science -/obj/item/book/skill/research/science - author = "Hui Ying Ch'ien" - skill = SKILL_SCIENCE - -/obj/item/book/skill/research/science/basic - skill_req = SKILL_NONE - name = "beginner science textbook" - -/obj/item/book/skill/research/science/adept - skill_req = SKILL_BASIC - name = "intermediate science textbook" - -/obj/item/book/skill/research/science/expert - skill_req = SKILL_ADEPT - name = "advanced science textbook" - -/obj/item/book/skill/research/science/prof - skill_req = SKILL_EXPERT - name = "theoretical science textbook" - -/* -MEDICAL -*/ -/obj/item/book/skill/medical - icon_state = "bookMedical" - -//chemistry -/obj/item/book/skill/medical/chemistry - icon_state = "chemistry" - author = "Dr. Shinula Nyekundujicho" - skill = SKILL_CHEMISTRY - -/obj/item/book/skill/medical/chemistry/basic - skill_req = SKILL_NONE - name = "beginner chemistry textbook" - -/obj/item/book/skill/medical/chemistry/adept - skill_req = SKILL_BASIC - name = "intermediate chemistry textbook" - -/obj/item/book/skill/medical/chemistry/expert - skill_req = SKILL_ADEPT - name = "advanced chemistry textbook" - -/obj/item/book/skill/medical/chemistry/prof - skill_req = SKILL_EXPERT - name = "theoretical chemistry textbook" - -//medicine -/obj/item/book/skill/medical/medicine - author = "Dr. Nagarjuna Siddha" - skill = SKILL_MEDICAL - -/obj/item/book/skill/medical/medicine/basic - skill_req = SKILL_NONE - name = "beginner medicine textbook" - title = "\"Instructional Guide on How Rubbing Dirt In Wounds Might Not Be The Right Approach To Stopping Bleeding Anymore\"" - desc = "A copy of \"Instructional Guide on How Rubbing Dirt In Wounds Might Not Be The Right Approach To Stopping Bleeding Anymore\" by Dr. Merrs. Despite the information density of this heavy book, it lacks any and all teachings regarding bedside manner." - author = "Dr. Merrs" - custom = TRUE - -/obj/item/book/skill/medical/medicine/adept - skill_req = SKILL_BASIC - name = "intermediate medicine textbook" - -/obj/item/book/skill/medical/medicine/expert - skill_req = SKILL_ADEPT - name = "advanced medicine textbook" - -/obj/item/book/skill/medical/medicine/prof - skill_req = SKILL_EXPERT - name = "theoretical medicine textbook" - -//anatomy -/obj/item/book/skill/medical/anatomy - author = "Dr. Basil Cartwright" - skill = SKILL_ANATOMY - -/obj/item/book/skill/medical/anatomy/basic - skill_req = SKILL_NONE - name = "beginner anatomy textbook" - -/obj/item/book/skill/medical/anatomy/adept - skill_req = SKILL_BASIC - name = "intermediate anatomy textbook" - -/obj/item/book/skill/medical/anatomy/expert - skill_req = SKILL_ADEPT - name = "advanced anatomy textbook" - -/obj/item/book/skill/medical/anatomy/prof - skill_req = SKILL_EXPERT - name = "theoretical anatomy textbook" - - -////////////////////// -//Custom Skill Books// -////////////////////// - -//custom skill books made by players. Right now it is extremely dodgy and bad and i'm sorry -/obj/item/book/skill/custom - name = "blank textbook" - desc = "A somewhat heftier blank book, just ready to filled with knowledge and sold at an unreasonable price." - custom = TRUE - author = null - progress = SKILLBOOK_PROG_NONE - icon_state = "tb_white" - var/skill_option_string = "Skill" //changes to "continue writing content" when the book is in progress - var/true_author //Used to keep track of who is actually writing the book. - var/list/failure_messages = list("Your hand slips and you accidentally rip your pen through several pages, ruining your hard work!","Your pen slips, dragging a haphazard line across both open pages! Now you need to do those again!") - var/list/progress_messages = list("Still quite a few blank pages left.","Feels like you're near halfway done.","You've made good progress.","Just needs a few finishing touches.","And then finish it. Done!") // Messages are in order of progress. - var/list/charge_messages = list("Your mind instantly recoils at the idea of having to write another textbook. No thank you!","You are far too mentally exhausted to write another textbook. Maybe another day.","Your hand aches in response to the very idea of more textbook writing.") - var/writing_time = 15 SECONDS // time it takes to write a segment of the book. This happens 6 times total - -//these all show up in the book fabricator -/obj/item/book/skill/custom/circle - icon_state = "tb_white_circle" -/obj/item/book/skill/custom/star - icon_state = "tb_white_star" -/obj/item/book/skill/custom/hourglass - icon_state = "tb_white_hourglass" -/obj/item/book/skill/custom/cracked - icon_state = "tb_white_cracked" -/obj/item/book/skill/custom/gun - icon_state = "tb_white_gun" -/obj/item/book/skill/custom/wrench - icon_state = "tb_white_wrench" -/obj/item/book/skill/custom/glass - icon_state = "tb_white_glass" - -/obj/item/book/skill/custom/cross - icon_state = "tb_white_cross" -/obj/item/book/skill/custom/text - icon_state = "tb_white_text" -/obj/item/book/skill/custom/download - icon_state = "tb_white_download" -/obj/item/book/skill/custom/uparrow - icon_state = "tb_white_uparrow" -/obj/item/book/skill/custom/percent - icon_state = "tb_white_percent" -/obj/item/book/skill/custom/flask - icon_state = "tb_white_flask" -/obj/item/book/skill/custom/detective - icon_state = "tb_white_detective" -/obj/item/book/skill/custom/device - icon_state = "tb_white_device" -/obj/item/book/skill/custom/smile - icon_state = "tb_white_smile" -/obj/item/book/skill/custom/exclamation - icon_state = "tb_white_exclamation" -/obj/item/book/skill/custom/question - icon_state = "tb_white_question" - -/obj/item/book/skill/custom/attackby(obj/item/pen, mob/user) - if(istype(pen, /obj/item/pen)) - - if(!user.skill_check(SKILL_LITERACY, SKILL_BASIC)) - to_chat(user, SPAN_WARNING("You can't even read, yet you want to write a whole educational textbook?")) - return - if(!user.skill_check(SKILL_LITERACY, SKILL_PROF)) - to_chat(user, SPAN_WARNING("You have no clue as to how to write an entire textbook in a way that is actually useful. Maybe a regular book would be better?")) - return - var/state_check = skill_option_string // the state skill_option_string is in just before opening the input - var/choice = input(user, "What would you like to change?","Textbook editing") as null|anything in list("Title", "Author", skill_option_string) - if(!can_write(pen,user)) - return - - switch(choice) - if("Title") - edit_title(pen, user) - - if("Skill") - if(state_check != "Skill") // make sure someone hasn't already started the book while we were staring at menus woops - to_chat(user, SPAN_WARNING("The skill has already been selected and the writing started.")) - return - edit_skill(pen, user) - - if("Continue writing content") - if(state_check != "Continue writing content") - return - continue_skill(pen, user) - - if("Author") - edit_author(pen, user) - - else - return - - if(skill && title && author) // we have everything we need so lets set a good description - desc = "A handwritten textbook titled [title], by [author]. Looks like it teaches [skill_name]." - return - ..() - -/obj/item/book/skill/custom/proc/can_write(var/obj/item/pen, var/mob/user) - if(user.get_active_hand() == pen && CanPhysicallyInteractWith(user,src) && !QDELETED(src) && !QDELETED(pen)) - return TRUE - else - to_chat(user,SPAN_DANGER("How can you expect to write anything when you can't physically put pen to paper?")) - return FALSE - -/obj/item/book/skill/custom/proc/edit_title(var/obj/item/pen, var/mob/user) - var/newtitle = reject_bad_text(sanitizeSafe(input(user, "Write a new title:"))) - if(!can_write(pen,user)) - return - if(!newtitle) - to_chat(user, "The title is invalid.") - return - else - newtitle = user.handle_writing_literacy(user, newtitle) - if(newtitle) - title = newtitle - SetName(title) - -/obj/item/book/skill/custom/proc/edit_author(var/obj/item/pen, var/mob/user) - var/newauthor = sanitize(input(user, "Write the author's name:")) - if(!can_write(pen,user)) - return - if(!newauthor) - to_chat(user, SPAN_WARNING("The author name is invalid.")) - return - else - newauthor = user.handle_writing_literacy(user, newauthor) - if(newauthor) - author = newauthor - -/obj/item/book/skill/custom/proc/edit_skill(var/obj/item/pen, var/mob/user) - if(user.skillset.literacy_charges <= 0) - to_chat(user, SPAN_WARNING(pick(charge_messages))) - return - - //Choosing the skill - var/list/skill_choices = list() - for(var/decl/hierarchy/skill/S in GLOB.skills) - if(user.skill_check(S.type, SKILL_BASIC)) - LAZYADD(skill_choices, S) - var/decl/hierarchy/skill/skill_choice = input(user, "What subject does your textbook teach?", "Textbook skill selection") as null|anything in skill_choices - if(!can_write(pen,user) || progress == SKILLBOOK_PROG_FINISH) - return - if(!skill_choice) - to_chat(user, SPAN_WARNING("Textbook skill selection cancelled.")) - return - var/newskill = skill_choice.type - - //Choosing the level - var/list/skill_levels = skill_choice.levels.Copy() - for(var/SL in skill_levels) - if(!user.skill_check(newskill, skill_levels.Find(SL))) - LAZYREMOVE(skill_levels, SL) - else - skill_levels[SL] = skill_levels.Find(SL) - LAZYREMOVE(skill_levels,skill_levels[1]) - var/newskill_level = input(user, "What level of education does it provide?","Textbook skill level") as null|anything in skill_levels - if(!can_write(pen,user) || progress == SKILLBOOK_PROG_FINISH) - return - if(!newskill_level) - to_chat(user, SPAN_WARNING("Textbook skill level selection cancelled.")) - return - var/usable_level = skill_levels[newskill_level] - if(newskill && usable_level) - if(!do_after(user, writing_time, src)) - to_chat(user, SPAN_DANGER(pick(failure_messages))) - return - //everything worked out so now we can put the learnings in the book - to_chat(user, SPAN_NOTICE("You start writing your book, getting a few pages in.")) - skill = newskill - skill_name = skill_choice.name - skill_req = (usable_level - 1) - desc = "A handwritten textbook on [skill_choice]! Wow!" - progress += 1 - skill_option_string = "Continue writing content" - true_author = user.name - -/obj/item/book/skill/custom/proc/continue_skill(var/obj/item/pen, var/mob/user) - if(user.skillset.literacy_charges <= 0) - to_chat(user, SPAN_WARNING(pick(charge_messages))) - return - if(progress >= SKILLBOOK_PROG_FINISH) // shouldn't happen but here just in case - to_chat(user, SPAN_WARNING("This book is already finished! There's no need to add anything else!")) - return - if(true_author != user.name) - to_chat(user, SPAN_WARNING("This isn't your work and you're not really sure how to continue it.")) - return - else - if(!do_after(user, writing_time, src)) - to_chat(user, SPAN_DANGER(pick(failure_messages))) - return - to_chat(user, SPAN_NOTICE("You continue writing your book. [progress_messages[progress]]")) - progress += 1 - if(progress == SKILLBOOK_PROG_FINISH) // book is finished! yay! - user.skillset.literacy_charges -= 1 - skill_option_string = "Cancel" - - -////////////////////// -// SHELF SHELF SHELF// -////////////////////// - -/obj/structure/bookcase/skill_books - name = "textbook bookcase" - // Contains a list of parent types but doesn't actually DO anything with them. Use a child of this book case - var/list/catalogue = list(/obj/item/book/skill/organizational/finance, - /obj/item/book/skill/organizational/literacy, - /obj/item/book/skill/general/eva, - /obj/item/book/skill/general/mech, - /obj/item/book/skill/general/pilot, - /obj/item/book/skill/general/hauling, - /obj/item/book/skill/general/computer, - /obj/item/book/skill/service/botany, - /obj/item/book/skill/service/cooking, - /obj/item/book/skill/security/combat, - /obj/item/book/skill/security/weapons, - /obj/item/book/skill/security/forensics, - /obj/item/book/skill/engineering/construction, - /obj/item/book/skill/engineering/electrical, - /obj/item/book/skill/engineering/atmos, - /obj/item/book/skill/engineering/engines, - /obj/item/book/skill/research/devices, - /obj/item/book/skill/research/science, - /obj/item/book/skill/medical/chemistry, - /obj/item/book/skill/medical/medicine, - /obj/item/book/skill/medical/anatomy) - -//give me ALL the textbooks -/obj/structure/bookcase/skill_books/all - -/obj/structure/bookcase/skill_books/all/Initialize() - . = ..() - for(var/category in catalogue) - for(var/real_book in subtypesof(category)) - new real_book(src) - -//Bookshelf with some random textbooks -/obj/structure/bookcase/skill_books/random - -/obj/structure/bookcase/skill_books/random/Initialize() - . = ..() - for(var/category in catalogue) - for(var/real_book in subtypesof(category)) - if(prob(20)) - new real_book(src) - -#undef RANDOM_BOOK_TITLE -#undef SKILLBOOK_PROG_NONE -#undef SKILLBOOK_PROG_FINISH \ No newline at end of file diff --git a/code/game/objects/items/buttons.dm b/code/game/objects/items/buttons.dm deleted file mode 100644 index 25e8e7ec4c88..000000000000 --- a/code/game/objects/items/buttons.dm +++ /dev/null @@ -1,26 +0,0 @@ -// Lightswitch Hull - -/obj/item/frame/button/light_switch - name = "light switch frame" - desc = "Used for building a light switch." - icon = 'icons/obj/power.dmi' - icon_state = "light-p" - obj_flags = OBJ_FLAG_CONDUCTIBLE - build_machine_type = /obj/machinery/light_switch/buildable - -/obj/item/frame/button/light_switch/kit - name = "light switch kit" - fully_construct = TRUE - build_machine_type = /obj/machinery/light_switch - -/obj/item/frame/button/light_switch/windowtint - name = "window tint switch frame" - desc = "Used for building a window tint switch." - icon = 'icons/obj/power.dmi' - icon_state = "light-p" - build_machine_type = /obj/machinery/button/windowtint/buildable - -/obj/item/frame/button/light_switch/windowtint/kit - name = "window tint switch kit" - fully_construct = TRUE - build_machine_type = /obj/machinery/button/windowtint \ No newline at end of file diff --git a/code/game/objects/items/candelabra.dm b/code/game/objects/items/candelabra.dm new file mode 100644 index 000000000000..bd5fcd533aff --- /dev/null +++ b/code/game/objects/items/candelabra.dm @@ -0,0 +1,54 @@ +/datum/storage/candelabra + can_hold = list(/obj/item/flame/candle) + storage_slots = 3 + var/static/list/candle_offsets = list( + list("x" = -4, "y" = 17), + list("x" = 1, "y" = 19), + list("x" = 6, "y" = 17) + ) + +/datum/storage/candelabra/can_be_inserted(obj/item/used_item, mob/user, stop_messages, click_params) + . = ..() && holder && length(holder.get_stored_inventory()) < length(candle_offsets) + +/obj/item/candelabra + name = "candelabra" + desc = "A three-tined candle stand." + icon = 'icons/obj/items/candelabra.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/candelabra + material = /decl/material/solid/metal/brass + color = /decl/material/solid/metal/brass::color + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/item/candelabra/attackby(obj/item/used_item, mob/user) + if(!user.check_intent(I_FLAG_HARM) && (used_item.isflamesource() || used_item.get_heat() > T100C)) + for(var/obj/item/flame/candle/candle in contents) + if(!candle.lit && candle.attackby(used_item, user)) + return TRUE + . = ..() + +/obj/item/candelabra/filled/WillContain() + return list(/obj/item/flame/candle/handmade = 3) + +// Workaround for vis_contents propagating color. +/obj/item/candelabra/on_update_icon() + ..() + var/datum/storage/candelabra/candles_storage = storage + if(istype(candles_storage)) + var/i = 1 + for(var/obj/item/flame/candle/candle in get_stored_inventory()) + var/offsets = candles_storage.candle_offsets[i] + candle.set_dir(SOUTH) + for(var/image/candle_overlay in candle.get_sconce_overlay()) + candle_overlay.pixel_x = offsets["x"] + candle_overlay.pixel_y = offsets["y"] + candle_overlay.dir = SOUTH + candle_overlay.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(candle_overlay) + i++ + if(i > length(candles_storage.candle_offsets)) + break + compile_overlays() + +/obj/item/candelabra/infinite/WillContain() + return list(/obj/item/flame/candle/infinite = 3) diff --git a/code/game/objects/items/chisel.dm b/code/game/objects/items/chisel.dm new file mode 100644 index 000000000000..fb32a9888d3b --- /dev/null +++ b/code/game/objects/items/chisel.dm @@ -0,0 +1,17 @@ +/obj/item/tool/chisel + name = "chisel" + desc = "A hard, sharpened tool used to chisel stone, wood or bone." + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/tool/chisel.dmi' + material = /decl/material/solid/metal/steel + handle_material = /decl/material/solid/organic/plastic + binding_material = null + +/obj/item/tool/chisel/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_CHISEL = TOOL_QUALITY_DEFAULT + ) + return tool_qualities + +/obj/item/tool/chisel/forged + handle_material = null diff --git a/code/game/objects/items/christmas.dm b/code/game/objects/items/christmas.dm index d2dfe38b6b4a..280d5b76743c 100644 --- a/code/game/objects/items/christmas.dm +++ b/code/game/objects/items/christmas.dm @@ -3,25 +3,29 @@ icon = 'icons/obj/christmas.dmi' icon_state = "cracker" desc = "Directions for use: Requires two people, one to pull each end." + material = /decl/material/solid/organic/cardboard var/cracked = 0 -/obj/item/toy/xmas_cracker/attack(mob/target, mob/user) - if( !cracked && istype(target,/mob/living/carbon/human) && (target.stat == CONSCIOUS) && !target.get_active_hand() ) - target.visible_message("[user] and [target] pop \an [src]! *pop*", "You pull \an [src] with [target]! *pop*", "You hear a *pop*.") +/obj/item/toy/xmas_cracker/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(!cracked && ishuman(target) && (target.stat == CONSCIOUS) && !target.get_active_held_item() ) + target.visible_message( + SPAN_NOTICE("\The [user] and \the [target] pop \an [src]! *pop*"), + SPAN_NOTICE("You pull \an [src] with \the [target]! *pop*"), + SPAN_NOTICE("You hear a *pop*") + ) var/obj/item/paper/Joke = new /obj/item/paper(user.loc) Joke.SetName("[pick("awful","terrible","unfunny")] joke") - Joke.info = pick("What did one snowman say to the other?\n\n'Is it me or can you smell carrots?'", - "Why couldn't the snowman get laid?\n\nHe was frigid!", + Joke.info = pick(list( + "What did one snowman say to the other?\n\n'Is it me or can you smell carrots?'", "Where are santa's helpers educated?\n\nNowhere, they're ELF-taught.", "What happened to the man who stole advent calanders?\n\nHe got 25 days.", "What does Santa get when he gets stuck in a chimney?\n\nClaus-trophobia.", "Where do you find chili beans?\n\nThe north pole.", "What do you get from eating tree decorations?\n\nTinsilitis!", - "What do snowmen wear on their heads?\n\nIce caps!", - "Why is Christmas just like life on ss13?\n\nYou do all the work and the fat guy gets all the credit.", - "Why doesn't Santa have any children?\n\nBecause he only comes down the chimney.") + "What do snowmen wear on their heads?\n\nIce caps!" + )) new /obj/item/clothing/head/festive(target.loc) - user.update_icons() + user.update_icon() cracked = 1 icon_state = "cracker1" var/obj/item/toy/xmas_cracker/other_half = new /obj/item/toy/xmas_cracker(target) @@ -29,18 +33,19 @@ other_half.icon_state = "cracker2" target.put_in_active_hand(other_half) playsound(user, 'sound/effects/snap.ogg', 50, 1) - return 1 + return TRUE return ..() /obj/item/clothing/head/festive name = "festive paper hat" - icon_state = "xmashat" + icon = 'icons/clothing/head/festive.dmi' desc = "A crappy paper crown that you are REQUIRED to wear." flags_inv = 0 body_parts_covered = 0 + material = /decl/material/solid/organic/paper var/list/permitted_colors = list(COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_INDIGO, COLOR_VIOLET) /obj/item/clothing/head/festive/Initialize() . = ..() - color = pick(permitted_colors) + set_color(pick(permitted_colors)) diff --git a/code/game/objects/items/weapons/circuitboards/broken.dm b/code/game/objects/items/circuitboards/broken.dm similarity index 100% rename from code/game/objects/items/weapons/circuitboards/broken.dm rename to code/game/objects/items/circuitboards/broken.dm diff --git a/code/game/objects/items/weapons/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm similarity index 91% rename from code/game/objects/items/weapons/circuitboards/circuitboard.dm rename to code/game/objects/items/circuitboards/circuitboard.dm index 394308e8a0db..084eb93b13ea 100644 --- a/code/game/objects/items/weapons/circuitboards/circuitboard.dm +++ b/code/game/objects/items/circuitboards/circuitboard.dm @@ -1,19 +1,16 @@ /obj/item/stock_parts/circuitboard name = "circuit board" - icon = 'icons/obj/module.dmi' - icon_state = "id_mod" - item_state = "electronic" - origin_tech = "{'programming':2}" - density = 0 - anchored = 0 + icon = 'icons/obj/modules/module_id.dmi' + icon_state = ICON_STATE_WORLD + origin_tech = @'{"programming":2}' + density = FALSE + anchored = FALSE w_class = ITEM_SIZE_SMALL obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 - throwforce = 5.0 throw_speed = 3 throw_range = 15 part_flags = 0 - material = /decl/material/solid/glass + material = /decl/material/solid/fiberglass var/build_path = null var/board_type = "computer" var/list/req_components = list( @@ -56,7 +53,7 @@ if(buildtype_select && machine) build_path = machine.base_type || machine.type var/obj/machinery/thing = build_path - SetName(T_BOARD(initial(thing.name))) + SetName("circuitboard ([initial(thing.name)])") /obj/item/stock_parts/circuitboard/proc/update_desc() if(!build_path) diff --git a/code/game/objects/items/circuitboards/computer/air_management.dm b/code/game/objects/items/circuitboards/computer/air_management.dm new file mode 100644 index 000000000000..0498af958396 --- /dev/null +++ b/code/game/objects/items/circuitboards/computer/air_management.dm @@ -0,0 +1,60 @@ +/obj/item/stock_parts/circuitboard/air_management + name = "circuitboard (atmosphere monitoring console)" + build_path = /obj/machinery/computer/air_control + var/console_name + var/frequency = 1441 + var/sensor_tag + var/sensor_name + var/list/sensor_information = list() + +/obj/item/stock_parts/circuitboard/air_management/injector_control + name = "circuitboard (injector control)" + build_path = /obj/machinery/computer/air_control/fuel_injection + var/device_tag + var/list/device_info + var/automation = 0 + var/cutoff_temperature = 2000 + var/on_temperature = 1200 + +/************ +* Construct * +************/ +/obj/item/stock_parts/circuitboard/air_management/construct(var/obj/machinery/computer/air_control/C) + if (..(C)) + if(console_name) + C.SetName(console_name) + C.set_frequency(frequency) + C.sensor_tag = sensor_tag + C.sensor_name = sensor_name + C.sensor_info = sensor_information.Copy() + return 1 + +/obj/item/stock_parts/circuitboard/air_management/injector_control/construct(var/obj/machinery/computer/air_control/fuel_injection/FI) + if(..(FI)) + FI.device_tag = device_tag + FI.device_info = device_info.Copy() + FI.automation = automation + FI.cutoff_temperature = cutoff_temperature + FI.on_temperature = on_temperature + return 1 + +/************** +* Deconstruct * +**************/ +/obj/item/stock_parts/circuitboard/air_management/deconstruct(var/obj/machinery/computer/air_control/C) + if (..(C)) + console_name = C.name + frequency = C.frequency + sensor_tag = C.sensor_tag + sensor_name = C.sensor_name + sensor_information = C.sensor_info.Copy() + return 1 + +/obj/item/stock_parts/circuitboard/air_management/injector_control/deconstruct(var/obj/machinery/computer/air_control/fuel_injection/FI) + if(..(FI)) + device_tag = FI.device_tag + device_info = FI.device_info.Copy() + automation = FI.automation + cutoff_temperature = FI.cutoff_temperature + on_temperature = FI.on_temperature + return 1 \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/computer/computer.dm b/code/game/objects/items/circuitboards/computer/computer.dm new file mode 100644 index 000000000000..c013c88bdf5c --- /dev/null +++ b/code/game/objects/items/circuitboards/computer/computer.dm @@ -0,0 +1,123 @@ +/obj/item/stock_parts/circuitboard/message_monitor + name = "circuitboard (message monitor console)" + build_path = /obj/machinery/computer/message_monitor + origin_tech = @'{"programming":3}' + +/obj/item/stock_parts/circuitboard/aiupload + name = "circuitboard (AI upload console)" + build_path = /obj/machinery/computer/upload/ai + origin_tech = @'{"programming":4}' + +/obj/item/stock_parts/circuitboard/borgupload + name = "circuitboard (cyborg upload console)" + build_path = /obj/machinery/computer/upload/robot + origin_tech = @'{"programming":4}' + +/obj/item/stock_parts/circuitboard/teleporter + name = "circuitboard (teleporter control console)" + build_path = /obj/machinery/computer/teleporter + origin_tech = @'{"programming":2,"wormholes":4}' + +/obj/item/stock_parts/circuitboard/atmos_alert + name = "circuitboard (atmospheric alert console)" + build_path = /obj/machinery/computer/atmos_alert + +/obj/item/stock_parts/circuitboard/robotics + name = "circuitboard (robotics control console)" + build_path = /obj/machinery/computer/robotics + origin_tech = @'{"programming":3}' + +/obj/item/stock_parts/circuitboard/drone_control + name = "circuitboard (drone control console)" + build_path = /obj/machinery/computer/drone_control + origin_tech = @'{"programming":3}' + +/obj/item/stock_parts/circuitboard/arcade/battle + name = "circuitboard (battle arcade machine)" + build_path = /obj/machinery/computer/arcade/battle + origin_tech = @'{"programming":1}' + +/obj/item/stock_parts/circuitboard/arcade/orion_trail + name = "circuitboard (orion trail arcade machine)" + build_path = /obj/machinery/computer/arcade/orion_trail + origin_tech = @'{"programming":1}' + +/obj/item/stock_parts/circuitboard/turbine_control + name = "circuitboard (turbine control console)" + build_path = /obj/machinery/computer/turbine_computer + +/obj/item/stock_parts/circuitboard/solar_control + name = "circuitboard (solar control console)" + build_path = /obj/machinery/power/solar_control + origin_tech = @'{"programming":2,"powerstorage":2}' + +/obj/item/stock_parts/circuitboard/prisoner + name = "circuitboard (prisoner management console)" + build_path = /obj/machinery/computer/prisoner + +/obj/item/stock_parts/circuitboard/operating + name = "circuitboard (patient monitoring console)" + build_path = /obj/machinery/computer/operating + origin_tech = @'{"programming":2,"biotech":2}' + +/obj/item/stock_parts/circuitboard/helm + name = "circuitboard (helm control console)" + build_path = /obj/machinery/computer/ship/helm + +/obj/item/stock_parts/circuitboard/comms + name = "circuitboard (comms control console)" + build_path = /obj/machinery/computer/ship/comms + +/obj/item/stock_parts/circuitboard/ftl + name = "circuitboard (FTL control console)" + build_path = /obj/machinery/computer/ship/ftl + +/obj/item/stock_parts/circuitboard/engine + name = "circuitboard (engine control console)" + build_path = /obj/machinery/computer/ship/engines + +/obj/item/stock_parts/circuitboard/nav + name = "circuitboard (navigation console)" + build_path = /obj/machinery/computer/ship/navigation + +/obj/item/stock_parts/circuitboard/nav/tele + name = "circuitboard (navigation telescreen)" + build_path = /obj/machinery/computer/ship/navigation/telescreen + +/obj/item/stock_parts/circuitboard/sensors + name = "circuitboard (sensors console)" + build_path = /obj/machinery/computer/ship/sensors + +/obj/item/stock_parts/circuitboard/design_console + name = "circuitboard (design database console)" + build_path = /obj/machinery/computer/design_console + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/item_holder/disk_reader/buildable = 1, + ) + +/obj/item/stock_parts/circuitboard/central_atmos + name = "circuitboard (central atmospherics computer)" + build_path = /obj/machinery/computer/central_atmos + origin_tech = @'{"programming":2}' + +/obj/item/stock_parts/circuitboard/area_atmos + name = "circuitboard (air control console)" + build_path = /obj/machinery/computer/area_atmos + origin_tech = @'{"programming":2}' + +/obj/item/stock_parts/circuitboard/area_atmos/area + name = "circuitboard (area air control console)" + build_path = /obj/machinery/computer/area_atmos/area + +/obj/item/stock_parts/circuitboard/area_atmos/tag + name = "circuitboard (wireless scrubber control console)" + build_path = /obj/machinery/computer/area_atmos/tag + +/obj/item/stock_parts/circuitboard/account_database + name = "circuitboard (accounts uplink terminal)" + build_path = /obj/machinery/computer/account_database + +/obj/item/stock_parts/circuitboard/guestpass + name = "circuitboard (guest pass terminal)" + build_path = /obj/machinery/computer/guestpass \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/computer/holodeckcontrol.dm b/code/game/objects/items/circuitboards/computer/holodeckcontrol.dm new file mode 100644 index 000000000000..59353cb06fc7 --- /dev/null +++ b/code/game/objects/items/circuitboards/computer/holodeckcontrol.dm @@ -0,0 +1,31 @@ +/obj/item/stock_parts/circuitboard/holodeck_control + name = "circuitboard (holodeck control console)" + build_path = /obj/machinery/computer/holodeck_control + origin_tech = @'{"programming":2,"wormholes":2}' + buildtype_select = TRUE + var/last_to_emag + var/linkedholodeck_area + var/list/supported_programs + var/list/restricted_programs + +/obj/item/stock_parts/circuitboard/holodeck_control/get_buildable_types() + return typesof(/obj/machinery/computer/holodeck_control) + +/obj/item/stock_parts/circuitboard/holodeck_control/construct(var/obj/machinery/computer/holodeck_control/HC) + if (..(HC)) + HC.supported_programs = supported_programs.Copy() + HC.restricted_programs = restricted_programs.Copy() + if(linkedholodeck_area) + HC.linkedholodeck = locate(linkedholodeck_area) + if(last_to_emag) + HC.last_to_emag = last_to_emag + HC.emagged = 1 + HC.safety_disabled = 1 + +/obj/item/stock_parts/circuitboard/holodeck_control/deconstruct(var/obj/machinery/computer/holodeck_control/HC) + if (..(HC)) + linkedholodeck_area = HC.linkedholodeck_area + supported_programs = HC.supported_programs.Copy() + restricted_programs = HC.restricted_programs.Copy() + last_to_emag = HC.last_to_emag + HC.emergencyShutdown() diff --git a/code/game/objects/items/weapons/circuitboards/computer/modular.dm b/code/game/objects/items/circuitboards/computer/modular.dm similarity index 93% rename from code/game/objects/items/weapons/circuitboards/computer/modular.dm rename to code/game/objects/items/circuitboards/computer/modular.dm index f4161e8cf9a5..9820682afa7c 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/modular.dm +++ b/code/game/objects/items/circuitboards/computer/modular.dm @@ -5,7 +5,7 @@ /obj/item/stock_parts/computer/processor_unit = 1 ) additional_spawn_components = list( - /obj/item/stock_parts/computer/network_card/wired = 1, + /obj/item/stock_parts/computer/network_card = 1, /obj/item/stock_parts/computer/hard_drive/super = 1, /obj/item/stock_parts/console_screen = 1, /obj/item/stock_parts/keyboard = 1, diff --git a/code/game/objects/items/circuitboards/computer/shuttle.dm b/code/game/objects/items/circuitboards/computer/shuttle.dm new file mode 100644 index 000000000000..2fcdba666f95 --- /dev/null +++ b/code/game/objects/items/circuitboards/computer/shuttle.dm @@ -0,0 +1,25 @@ +/obj/item/stock_parts/circuitboard/shuttle_console + name = "circuitboard (basic shuttle console)" + build_path = /obj/machinery/computer/shuttle_control + origin_tech = @'{"programming":3}' + var/shuttle_tag + +/obj/item/stock_parts/circuitboard/shuttle_console/construct(obj/machinery/computer/shuttle_control/M) + M.shuttle_tag = shuttle_tag + +/obj/item/stock_parts/circuitboard/shuttle_console/deconstruct(obj/machinery/computer/shuttle_control/M) + shuttle_tag = M.shuttle_tag + +/obj/item/stock_parts/circuitboard/shuttle_console/Initialize() + set_extension(src, /datum/extension/interactive/multitool/circuitboards/shuttle_console) + . = ..() + +/obj/item/stock_parts/circuitboard/shuttle_console/proc/is_valid_shuttle(datum/shuttle/shuttle) + return TRUE + +/obj/item/stock_parts/circuitboard/shuttle_console/explore + name = "circuitboard (long range shuttle console)" + build_path = /obj/machinery/computer/shuttle_control/explore + +/obj/item/stock_parts/circuitboard/shuttle_console/explore/is_valid_shuttle(datum/shuttle/shuttle) + return istype(shuttle, /datum/shuttle/autodock/overmap) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/computer/station_alert.dm b/code/game/objects/items/circuitboards/computer/station_alert.dm similarity index 96% rename from code/game/objects/items/weapons/circuitboards/computer/station_alert.dm rename to code/game/objects/items/circuitboards/computer/station_alert.dm index 78b4611d4e24..4282e82164e0 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/station_alert.dm +++ b/code/game/objects/items/circuitboards/computer/station_alert.dm @@ -1,5 +1,5 @@ /obj/item/stock_parts/circuitboard/stationalert - name = T_BOARD("alert console") + name = "circuitboard (alert console)" build_path = /obj/machinery/computer/station_alert var/list/alarm_handlers diff --git a/code/game/objects/items/weapons/circuitboards/machinery/biogenerator.dm b/code/game/objects/items/circuitboards/machinery/biogenerator.dm similarity index 84% rename from code/game/objects/items/weapons/circuitboards/machinery/biogenerator.dm rename to code/game/objects/items/circuitboards/machinery/biogenerator.dm index 41c9c1a93ba6..d41c8526e4bd 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/biogenerator.dm +++ b/code/game/objects/items/circuitboards/machinery/biogenerator.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/biogenerator - name = T_BOARD("biogenerator") + name = "circuitboard (biogenerator)" build_path = /obj/machinery/biogenerator board_type = "machine" - origin_tech = "{'programming':2}" + origin_tech = @'{"programming":2}' req_components = list( /obj/item/stock_parts/matter_bin = 1, /obj/item/stock_parts/manipulator = 1 diff --git a/code/game/objects/items/circuitboards/machinery/chemistry.dm b/code/game/objects/items/circuitboards/machinery/chemistry.dm new file mode 100644 index 000000000000..1d9cccaf50b3 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/chemistry.dm @@ -0,0 +1,57 @@ +/obj/item/stock_parts/circuitboard/reagent_heater + name = "circuitboard (hotplate)" + build_path = /obj/machinery/reagent_temperature + board_type = "machine" + origin_tech = @'{"powerstorage":2,"engineering":1}' + req_components = list( + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/capacitor = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/reagent_heater/cooler + name = "circuitboard (chemical cooler)" + build_path = /obj/machinery/reagent_temperature/cooler + +/obj/item/stock_parts/circuitboard/chem_master + name = "circuitboard (ChemMaster 3000)" + build_path = /obj/machinery/chem_master + board_type = "machine" + origin_tech = @'{"biotech":2,"engineering":1}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/scanning_module = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/chemical_dispenser + name = "circuitboard (chemical dispenser)" + build_path = /obj/machinery/chemical_dispenser + board_type = "machine" + origin_tech = @'{"biotech":2,"engineering":1}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + buildtype_select = TRUE + +/obj/item/stock_parts/circuitboard/chemical_dispenser/get_buildable_types() + . = list() + for(var/path in typesof(/obj/machinery/chemical_dispenser)) + var/obj/machinery/chemical_dispenser/chem_dispenser = path + if(initial(chem_dispenser.buildable)) + . |= path \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/machinery/cloning.dm b/code/game/objects/items/circuitboards/machinery/cloning.dm new file mode 100644 index 000000000000..8a3721b78988 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/cloning.dm @@ -0,0 +1,15 @@ +/obj/item/stock_parts/circuitboard/bioprinter + name = "circuitboard (bioprinter)" + build_path = /obj/machinery/fabricator/bioprinter + board_type = "machine" + origin_tech = @'{"engineering":1,"biotech":3,"programming":3}' + req_components = list( + /obj/item/scanner/health = 1, + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/commsantenna.dm b/code/game/objects/items/circuitboards/machinery/commsantenna.dm similarity index 77% rename from code/game/objects/items/weapons/circuitboards/machinery/commsantenna.dm rename to code/game/objects/items/circuitboards/machinery/commsantenna.dm index 7b558e8d7710..054a85165c26 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/commsantenna.dm +++ b/code/game/objects/items/circuitboards/machinery/commsantenna.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/commsrelay - name = T_BOARD("communication relay") + name = "circuitboard (communication relay)" build_path = /obj/machinery/commsrelay board_type = "machine" - origin_tech = "{'wormholes':2,'programming':2}" + origin_tech = @'{"wormholes":2,"programming":2}' req_components = list( /obj/item/stack/cable_coil = 30, /obj/item/stock_parts/manipulator = 2, diff --git a/code/game/objects/items/circuitboards/machinery/docking_beacon.dm b/code/game/objects/items/circuitboards/machinery/docking_beacon.dm new file mode 100644 index 000000000000..ee6e19428bfd --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/docking_beacon.dm @@ -0,0 +1,13 @@ +/obj/item/stock_parts/circuitboard/docking_beacon + name = "circuitboard (magnetic docking beacon)" + board_type = "machine" + build_path = /obj/machinery/docking_beacon + origin_tech = @'{"magnets":3}' + req_components = list( + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/engineering_circuits.dm b/code/game/objects/items/circuitboards/machinery/engineering_circuits.dm similarity index 81% rename from code/game/objects/items/weapons/circuitboards/machinery/engineering_circuits.dm rename to code/game/objects/items/circuitboards/machinery/engineering_circuits.dm index 4d69b4594de3..a797235bf4c3 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/engineering_circuits.dm +++ b/code/game/objects/items/circuitboards/machinery/engineering_circuits.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/floodlight - name = T_BOARD("emergency floodlight") + name = "circuitboard (emergency floodlight)" build_path = /obj/machinery/floodlight board_type = "machine" - origin_tech = "{'engineering':1}" + origin_tech = @'{"engineering":1}' req_components = list( /obj/item/stack/cable_coil = 10) additional_spawn_components = list( @@ -11,10 +11,10 @@ /obj/item/cell/crap = 1) /obj/item/stock_parts/circuitboard/pipedispensor - name = T_BOARD("pipe dispenser") + name = "circuitboard (pipe dispenser)" build_path = /obj/machinery/fabricator/pipe board_type = "machine" - origin_tech = "{'engineering':6,'materials':5}" + origin_tech = @'{"engineering":6,"materials":5}' req_components = list( /obj/item/stock_parts/manipulator = 1, /obj/item/stock_parts/matter_bin = 2, @@ -24,14 +24,14 @@ /obj/item/stock_parts/power/apc/buildable = 1) /obj/item/stock_parts/circuitboard/pipedispensor/disposal - name = T_BOARD("disposal pipe dispenser") + name = "circuitboard (disposal pipe dispenser)" build_path = /obj/machinery/fabricator/pipe/disposal /obj/item/stock_parts/circuitboard/suit_cycler - name = T_BOARD("suit cycler") + name = "circuitboard (suit cycler)" build_path = /obj/machinery/suit_cycler board_type = "machine" - origin_tech = "{'engineering':4,'materials':4}" + origin_tech = @'{"engineering":4,"materials":4}' req_components = list() additional_spawn_components = list( /obj/item/stock_parts/keyboard = 1, diff --git a/code/game/objects/items/weapons/circuitboards/machinery/forensic.dm b/code/game/objects/items/circuitboards/machinery/forensic.dm similarity index 77% rename from code/game/objects/items/weapons/circuitboards/machinery/forensic.dm rename to code/game/objects/items/circuitboards/machinery/forensic.dm index 9f3f45117bc6..dc96af409e22 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/forensic.dm +++ b/code/game/objects/items/circuitboards/machinery/forensic.dm @@ -1,9 +1,9 @@ /obj/item/stock_parts/circuitboard/forensic - name = T_BOARD("forensic omnianalyzer") + name = "circuitboard (forensic omnianalyzer)" build_path = /obj/machinery/forensic board_type = "machine" - origin_tech = "{'programming':6,'engineering':6,'biotech':6}" + origin_tech = @'{"programming":6,"engineering":6,"biotech":6}' req_components = list( /obj/item/stock_parts/scanning_module = 1, /obj/item/stock_parts/manipulator = 1, @@ -13,9 +13,9 @@ ) /obj/item/stock_parts/circuitboard/forensic_microscope - name = T_BOARD("forensic microscope") + name = "circuitboard (forensic microscope)" board_type = "machine" - origin_tech = "{'programming':3,'engineering':3,'biotech':3}" + origin_tech = @'{"programming":3,"engineering":3,"biotech":3}' build_path = /obj/machinery/forensic/microscope req_components = list( /obj/item/stock_parts/scanning_module = 1, @@ -25,9 +25,9 @@ ) /obj/item/stock_parts/circuitboard/forensic_dna_analyzer - name = T_BOARD("forensic DNA analyzer") + name = "circuitboard (forensic DNA analyzer)" board_type = "machine" - origin_tech = "{'programming':3,'engineering':3,'biotech':3}" + origin_tech = @'{"programming":3,"engineering":3,"biotech":3}' req_components = list( /obj/item/stock_parts/scanning_module = 1, /obj/item/stock_parts/manipulator = 1, diff --git a/code/game/objects/items/circuitboards/machinery/holomap.dm b/code/game/objects/items/circuitboards/machinery/holomap.dm new file mode 100644 index 000000000000..064eae1ab7ff --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/holomap.dm @@ -0,0 +1,11 @@ +/obj/item/stock_parts/circuitboard/holomap + name = "circuitboard (holomap)" + board_type = "machine" + build_path = /obj/machinery/holomap + origin_tech = @'{"engineering":1}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) diff --git a/code/game/objects/items/circuitboards/machinery/household.dm b/code/game/objects/items/circuitboards/machinery/household.dm new file mode 100644 index 000000000000..b3e8803a255d --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/household.dm @@ -0,0 +1,215 @@ +/obj/item/stock_parts/circuitboard/microwave + name = "circuitboard (microwave)" + build_path = /obj/machinery/microwave + board_type = "machine" + origin_tech = @'{"biotech":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/matter_bin = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/gibber + name = "circuitboard (meat gibber)" + build_path = /obj/machinery/gibber + board_type = "machine" + origin_tech = @'{"biotech":2,"materials":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/knife/kitchen/cleaver = 1) + additional_spawn_components = list( + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/cooker + name = "circuitboard (candy machine)" + build_path = /obj/machinery/cooker/candy + board_type = "machine" + origin_tech = @'{"biotech":1,"materials":1}' + buildtype_select = TRUE + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stack/cable_coil = 10) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/cooker/get_buildable_types() + return subtypesof(/obj/machinery/cooker) + +/obj/item/stock_parts/circuitboard/centrifuge + name = "circuitboard (industrial centrifuge)" + build_path = /obj/machinery/centrifuge + board_type = "machine" + origin_tech = @'{"biotech":2,"engineering":1}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) + +/obj/item/stock_parts/circuitboard/seed_extractor + name = "circuitboard (seed extractor)" + build_path = /obj/machinery/seed_extractor + board_type = "machine" + origin_tech = @'{"biotech":2,"engineering":1}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 2 + ) + +/obj/item/stock_parts/circuitboard/seed_storage + name = "circuitboard (seed storage)" + build_path = /obj/machinery/seed_storage + board_type = "machine" + origin_tech = @'{"biotech":2,"engineering":3}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 2) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/seed_storage/advanced + name = "circuitboard (seed storage (scientific))" + build_path = /obj/machinery/seed_storage/xenobotany/buildable + origin_tech = @'{"biotech":6,"engineering":3}' + +/obj/item/stock_parts/circuitboard/washer + name = "circuitboard (washing machine)" + build_path = /obj/machinery/washing_machine + board_type = "machine" + origin_tech = @'{"engineering":1}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/pipe = 1) + +/obj/item/stock_parts/circuitboard/autoclave + name = "circuitboard (autoclave)" + build_path = /obj/machinery/washing_machine/autoclave + board_type = "machine" + origin_tech = @'{"engineering":3, "biotech":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/matter_bin = 2, + /obj/item/pipe = 1) + +/obj/item/stock_parts/circuitboard/vending + name = "circuitboard (vending machine)" + build_path = /obj/machinery/vending/assist + board_type = "machine" + origin_tech = @'{"engineering":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + buildtype_select = TRUE + +/obj/item/stock_parts/circuitboard/vending/get_buildable_types() + . = list() + for(var/path in typesof(/obj/machinery/vending)) + var/obj/machinery/vending/vendor = path + var/base_type = initial(vendor.base_type) || path + . |= base_type + +/obj/item/stock_parts/circuitboard/grinder + name = "circuitboard (industrial grinder)" + build_path = /obj/machinery/reagentgrinder + board_type = "machine" + origin_tech = @'{"magnets":2,"materials":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 2) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/juicer + name = "circuitboard (blender)" + build_path = /obj/machinery/reagentgrinder/juicer + board_type = "machine" + origin_tech = @'{"magnets":2,"materials":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/matter_bin = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/ice_cream + name = "circuitboard (ice cream vat)" + build_path = /obj/machinery/icecream_vat + board_type = "machine" + origin_tech = @'{"engineering":1}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/pipe = 1 + ) + +/obj/item/stock_parts/circuitboard/fridge + name = "circuitboard (smartfridge)" + build_path = /obj/machinery/smartfridge + board_type = "machine" + origin_tech = @'{"engineering":3}' + req_components = list( + /obj/item/stock_parts/matter_bin = 3 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + buildtype_select = TRUE + +/obj/item/stock_parts/circuitboard/fridge/get_buildable_types() + return typesof(/obj/machinery/smartfridge) + +/obj/item/stock_parts/circuitboard/jukebox + name = "circuitboard (jukebox)" + build_path = /obj/machinery/media/jukebox + board_type = "machine" + origin_tech = @'{"programming":5}' + req_components = list( + /obj/item/stock_parts/subspace/amplifier = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + buildtype_select = TRUE + +/obj/item/stock_parts/circuitboard/jukebox/get_buildable_types() + return typesof(/obj/machinery/media/jukebox) + +/obj/item/stock_parts/circuitboard/paper_shredder + name = "circuitboard (paper shredder)" + build_path = /obj/machinery/papershredder + board_type = "machine" + origin_tech = @'{"engineering":1}' + req_components = list(/obj/item/stock_parts/manipulator = 1) + additional_spawn_components = null \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/machinery/mech_recharger.dm b/code/game/objects/items/circuitboards/machinery/mech_recharger.dm new file mode 100644 index 000000000000..b06b1c294a9a --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/mech_recharger.dm @@ -0,0 +1,9 @@ +/obj/item/stock_parts/circuitboard/mech_recharger + name = "circuitboard (mech recharger)" + build_path = /obj/machinery/mech_recharger + board_type = "machine" + origin_tech = @'{"programming":2,"powerstorage":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/capacitor = 2, + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/manipulator = 2) \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/machinery/medical.dm b/code/game/objects/items/circuitboards/machinery/medical.dm new file mode 100644 index 000000000000..0f5e011f6878 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/medical.dm @@ -0,0 +1,56 @@ +/obj/item/stock_parts/circuitboard/optable + name = "circuitboard (operating table)" + build_path = /obj/machinery/optable + board_type = "machine" + origin_tech = @'{"engineering":1,"biotech":3,"programming":3}' + req_components = list( + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 1) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/bodyscanner + name = "circuitboard (body scanner)" + build_path = /obj/machinery/bodyscanner + board_type = "machine" + origin_tech = @'{"engineering":2,"biotech":4,"programming":4}' + req_components = list( + /obj/item/stock_parts/scanning_module = 2, + /obj/item/stock_parts/manipulator = 2) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/body_scanconsole + name = "circuitboard (body scanner console)" + build_path = /obj/machinery/body_scanconsole + board_type = "machine" + origin_tech = @'{"engineering":2,"biotech":4,"programming":4}' + req_components = list( + /obj/item/stock_parts/console_screen = 1) + additional_spawn_components = list( + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/body_scanconsole/display + name = "circuitboard (body scanner display)" + build_path = /obj/machinery/body_scan_display + origin_tech = @'{"biotech":2,"programming":2}' + +/obj/item/stock_parts/circuitboard/sleeper + name = "circuitboard (sleeper)" + build_path = /obj/machinery/sleeper + board_type = "machine" + origin_tech = @'{"engineering":3,"biotech":5,"programming":3}' + req_components = list ( + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/manipulator = 2, + /obj/item/chems/syringe = 2) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) diff --git a/code/game/objects/items/circuitboards/machinery/mining.dm b/code/game/objects/items/circuitboards/machinery/mining.dm new file mode 100644 index 000000000000..77f454c521af --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/mining.dm @@ -0,0 +1,73 @@ +/obj/item/stock_parts/circuitboard/mining_processor + name = "circuitboard (electric smelter)" + build_path = /obj/machinery/material_processing/smeltery + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/mining_compressor + name = "circuitboard (material compressor)" + build_path = /obj/machinery/material_processing/compressor + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/mining_unloader + name = "circuitboard (ore unloading machine)" + build_path = /obj/machinery/material_processing/unloader + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/mining_stacker + name = "circuitboard (material stacking machine)" + build_path = /obj/machinery/material_processing/stacker + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/mining_extractor + name = "circuitboard (mineral extractor)" + build_path = /obj/machinery/material_processing/extractor + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1, + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/machinery/mining_drill.dm b/code/game/objects/items/circuitboards/machinery/mining_drill.dm new file mode 100644 index 000000000000..6835b272aa63 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/mining_drill.dm @@ -0,0 +1,15 @@ +/obj/item/stock_parts/circuitboard/miningdrill + name = "circuitboard (mining drill head)" + build_path = /obj/machinery/mining_drill + board_type = "machine" + origin_tech = @'{"programming":1,"engineering":1}' + req_components = list( + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/scanning_module = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/battery/buildable/stock, + /obj/item/cell = 1 + ) diff --git a/code/game/objects/items/circuitboards/machinery/network.dm b/code/game/objects/items/circuitboards/machinery/network.dm new file mode 100644 index 000000000000..df3da4c0ba1d --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/network.dm @@ -0,0 +1,96 @@ +/obj/item/stock_parts/circuitboard/mainframe + name = "circuitboard (mainframe)" + build_path = /obj/machinery/network/mainframe + board_type = "machine" + origin_tech = @'{"programming":2}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/computer/hard_drive/cluster/empty = 1 + ) + +/obj/item/stock_parts/circuitboard/acl + name = "circuitboard (access controller)" + build_path = /obj/machinery/network/acl + board_type = "machine" + origin_tech = @'{"programming":2}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) + +/obj/item/stock_parts/circuitboard/router + name = "circuitboard (router)" + build_path = /obj/machinery/network/router + board_type = "machine" + origin_tech = @'{"programming":2,"magnets":3}' + req_components = list( + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/micro_laser = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) + +/obj/item/stock_parts/circuitboard/router/wall_mounted + name = "circuitboard (wall-mounted router)" + board_type = "wall" + build_path = /obj/machinery/network/router/wall_mounted + +/obj/item/stock_parts/circuitboard/relay + name = "circuitboard (relay)" + build_path = /obj/machinery/network/relay + board_type = "machine" + origin_tech = @'{"programming":2,"magnets":2}' + req_components = list( + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/scanning_module = 1, + ) + + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) + +/obj/item/stock_parts/circuitboard/modem + name = "circuitboard (modem)" + build_path = /obj/machinery/network/modem + board_type = "machine" + origin_tech = @'{"programming":2,"magnets":2}' + req_components = list( + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/scanning_module = 1 + ) + + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) + +/obj/item/stock_parts/circuitboard/relay/wall_mounted + name = "circuitboard (wall-mounted relay)" + board_type = "wall" + build_path = /obj/machinery/network/relay/wall_mounted + +/obj/item/stock_parts/circuitboard/relay/long_range + name = "circuitboard (long-ranged relay)" + build_path = /obj/machinery/network/relay/long_range + origin_tech = @'{"programming":4,"magnets":5,"wormholes":5}' + req_components = list( + /obj/item/stock_parts/subspace/ansible = 1, + /obj/item/stock_parts/subspace/amplifier = 1, + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/subspace/transmitter = 1, + /obj/item/stock_parts/micro_laser/high = 1 + ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/oxyregenerator.dm b/code/game/objects/items/circuitboards/machinery/oxyregenerator.dm similarity index 83% rename from code/game/objects/items/weapons/circuitboards/machinery/oxyregenerator.dm rename to code/game/objects/items/circuitboards/machinery/oxyregenerator.dm index 04fce257a489..adeb13066e27 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/oxyregenerator.dm +++ b/code/game/objects/items/circuitboards/machinery/oxyregenerator.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/oxyregenerator - name = T_BOARD("oxygen regenerator") + name = "circuitboard (oxygen regenerator)" build_path = /obj/machinery/atmospherics/binary/oxyregenerator board_type = "machine" - origin_tech = "{'magnets':2,'engineering':2}" + origin_tech = @'{"magnets":2,"engineering":2}' req_components = list( /obj/item/stock_parts/micro_laser = 1, /obj/item/stock_parts/manipulator = 1, diff --git a/code/game/objects/items/circuitboards/machinery/pacman.dm b/code/game/objects/items/circuitboards/machinery/pacman.dm new file mode 100644 index 000000000000..00bb23592911 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/pacman.dm @@ -0,0 +1,29 @@ +/obj/item/stock_parts/circuitboard/pacman + name = "circuitboard (portable generator)" + build_path = /obj/machinery/port_gen/pacman + board_type = "machine" + origin_tech = @'{"programming":3,"powerstorage":3,"exoticmatter":3,"engineering":3}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stack/cable_coil = 15, + /obj/item/stock_parts/capacitor = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) +/obj/item/stock_parts/circuitboard/pacman/super + name = "circuitboard (portable fission generator)" + build_path = /obj/machinery/port_gen/pacman/super + origin_tech = @'{"programming":3,"powerstorage":4,"engineering":4}' + +/obj/item/stock_parts/circuitboard/pacman/super/potato + name = "circuitboard (PTTO-3 nuclear generator)" + build_path = /obj/machinery/port_gen/pacman/super/potato + origin_tech = @'{"programming":3,"powerstorage":5,"engineering":4}' + +/obj/item/stock_parts/circuitboard/pacman/mrs + name = "circuitboard (portable fusion generator)" + build_path = /obj/machinery/port_gen/pacman/mrs + origin_tech = @'{"programming":3,"powerstorage":5,"engineering":5}' diff --git a/code/game/objects/items/weapons/circuitboards/machinery/portable_atmospherics.dm b/code/game/objects/items/circuitboards/machinery/portable_atmospherics.dm similarity index 80% rename from code/game/objects/items/weapons/circuitboards/machinery/portable_atmospherics.dm rename to code/game/objects/items/circuitboards/machinery/portable_atmospherics.dm index 510c8b69357a..bf95dcb67f23 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/portable_atmospherics.dm +++ b/code/game/objects/items/circuitboards/machinery/portable_atmospherics.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/portable_scrubber - name = T_BOARD("portable scrubber") + name = "circuitboard (portable scrubber)" board_type = "machine" build_path = /obj/machinery/portable_atmospherics/powered/scrubber - origin_tech = "{'engineering':4,'powerstorage':4}" + origin_tech = @'{"engineering":4,"powerstorage":4}' req_components = list( /obj/item/stock_parts/capacitor = 2, /obj/item/stock_parts/matter_bin = 2, @@ -16,34 +16,33 @@ ) /obj/item/stock_parts/circuitboard/portable_scrubber/pump - name = T_BOARD("portable pump") + name = "circuitboard (portable pump)" board_type = "machine" build_path = /obj/machinery/portable_atmospherics/powered/pump /obj/item/stock_parts/circuitboard/portable_scrubber/huge - name = T_BOARD("large portable scrubber") + name = "circuitboard (large portable scrubber)" board_type = "machine" build_path = /obj/machinery/portable_atmospherics/powered/scrubber/huge - origin_tech = "{'engineering':5,'powerstorage':5,'materials':5}" + origin_tech = @'{"engineering":5,"powerstorage":5,"materials":5}' req_components = list( /obj/item/stock_parts/capacitor = 4, /obj/item/stock_parts/matter_bin = 2, /obj/item/pipe = 4) /obj/item/stock_parts/circuitboard/portable_scrubber/huge/stationary - name = T_BOARD("large stationary portable scrubber") + name = "circuitboard (large stationary portable scrubber)" board_type = "machine" build_path = /obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary /obj/item/stock_parts/circuitboard/tray - name = T_BOARD("hydroponics tray") + name = "circuitboard (hydroponics tray)" board_type = "machine" build_path = /obj/machinery/portable_atmospherics/hydroponics - origin_tech = "{'biotech':3,'materials':2,'programming':1}" + origin_tech = @'{"biotech":3,"materials":2,"programming":1}' req_components = list( /obj/item/stock_parts/matter_bin = 2, /obj/item/chems/glass/beaker = 1, - /obj/item/weedkiller = 1, /obj/item/pipe = 2) additional_spawn_components = list( /obj/item/stock_parts/console_screen = 1, @@ -52,10 +51,10 @@ ) /obj/item/stock_parts/circuitboard/dehumidifier - name = T_BOARD("emergency dehumidifier") + name = "circuitboard (emergency dehumidifier)" board_type = "machine" build_path = /obj/machinery/dehumidifier - origin_tech = "{'engineering':4,'powerstorage':4}" + origin_tech = @'{"engineering":4,"powerstorage":4}' req_components = list( /obj/item/stock_parts/capacitor = 2, /obj/item/stock_parts/matter_bin = 2, @@ -68,10 +67,10 @@ ) /obj/item/stock_parts/circuitboard/space_heater - name = T_BOARD("space heater") + name = "circuitboard (space heater)" board_type = "machine" build_path = /obj/machinery/space_heater - origin_tech = "{'engineering':4,'powerstorage':4}" + origin_tech = @'{"engineering":4,"powerstorage":4}' req_components = list( /obj/item/stock_parts/capacitor = 2, /obj/item/stock_parts/matter_bin = 2) diff --git a/code/game/objects/items/circuitboards/machinery/power.dm b/code/game/objects/items/circuitboards/machinery/power.dm new file mode 100644 index 000000000000..b580ee6ff641 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/power.dm @@ -0,0 +1,167 @@ +/obj/item/stock_parts/circuitboard/smes + name = "circuitboard (superconductive magnetic energy storage)" + build_path = /obj/machinery/power/smes/buildable + board_type = "machine" + origin_tech = @'{"powerstorage":6,"engineering":4}' + req_components = list(/obj/item/stock_parts/smes_coil = 1, /obj/item/stack/cable_coil = 30) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/shielding/electric = 1 + ) + +/obj/item/stock_parts/circuitboard/batteryrack + name = "circuitboard (battery rack PSU)" + build_path = /obj/machinery/power/smes/batteryrack + board_type = "machine" + origin_tech = @'{"powerstorage":3,"engineering":2}' + req_components = list(/obj/item/stock_parts/capacitor/ = 3, /obj/item/stock_parts/matter_bin/ = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/recharger + name = "circuitboard (recharger)" + build_path = /obj/machinery/recharger + board_type = "machine" + origin_tech = @'{"powerstorage":2,"engineering":2}' + req_components = list( + /obj/item/stock_parts/capacitor = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/recharger/wall + name = "circuitboard (wall recharger)" + build_path = /obj/machinery/recharger/wallcharger + board_type = "wall" + +/obj/item/stock_parts/circuitboard/cell_charger + name = "circuitboard (cell charger)" + build_path = /obj/machinery/cell_charger + board_type = "machine" + origin_tech = @'{"powerstorage":2,"engineering":2}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/power/battery/buildable/turbo = 1, + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/capacitor = 6 + ) // The apc part is to supply upkeep power, so it charges the battery instead of draining it. Capacitors make things go faster. + +/obj/item/stock_parts/circuitboard/turbine + name = "circuitboard (small turbine)" + build_path = /obj/machinery/atmospherics/pipeturbine + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin = 2 + ) + additional_spawn_components = list() + +/obj/item/stock_parts/circuitboard/turbine/motor + name = "circuitboard (small turbine motor)" + build_path = /obj/machinery/turbinemotor + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 4 + ) + +/obj/item/stock_parts/circuitboard/big_turbine + name = "circuitboard (large turbine compressor)" + build_path = /obj/machinery/compressor + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 3, + /obj/item/stock_parts/matter_bin = 3 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/big_turbine/center + name = "circuitboard (large turbine motor)" + build_path = /obj/machinery/turbine + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 4 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/teg_turbine + name = "circuitboard (thermoelectric generator turbine)" + build_path = /obj/machinery/atmospherics/binary/circulator + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 3, + /obj/item/stock_parts/matter_bin = 3 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/teg_turbine/motor + name = "circuitboard (thermoelectric generator motor)" + build_path = /obj/machinery/generator + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 4 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/breaker + name = "circuitboard (breaker box)" + build_path = /obj/machinery/power/breakerbox + board_type = "machine" + origin_tech = @'{"powerstorage":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/fuel_compressor + name = "circuitboard (fuel compressor)" + build_path = /obj/machinery/fuel_compressor + board_type = "machine" + origin_tech = @'{"powerstorage":2,"engineering":3,"materials":3}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/matter_bin/super = 2, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stack/cable_coil = 5 + ) + +/obj/item/stock_parts/circuitboard/unary_atmos/stirling + name = "circuit board (stirling engine)" + build_path = /obj/machinery/atmospherics/binary/stirling + board_type = "machine" + origin_tech = @'{"engineering":2,"powerstorage":1}' + req_components = list( + /obj/item/stack/cable_coil = 20, + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 2 + ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/recharge_station.dm b/code/game/objects/items/circuitboards/machinery/recharge_station.dm similarity index 82% rename from code/game/objects/items/weapons/circuitboards/machinery/recharge_station.dm rename to code/game/objects/items/circuitboards/machinery/recharge_station.dm index dd404a480cf2..e06fee8ccca0 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/recharge_station.dm +++ b/code/game/objects/items/circuitboards/machinery/recharge_station.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/recharge_station - name = T_BOARD("cyborg recharging station") + name = "circuitboard (cyborg recharging station)" build_path = /obj/machinery/recharge_station board_type = "machine" - origin_tech = "{'programming':3,'engineering':3}" + origin_tech = @'{"programming":3,"engineering":3}' req_components = list( /obj/item/stack/cable_coil = 5, /obj/item/stock_parts/capacitor = 2, diff --git a/code/game/objects/items/circuitboards/machinery/research.dm b/code/game/objects/items/circuitboards/machinery/research.dm new file mode 100644 index 000000000000..efe256ceef44 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/research.dm @@ -0,0 +1,271 @@ +/obj/item/stock_parts/circuitboard/destructive_analyzer + name = "circuitboard (destructive analyzer)" + build_path = /obj/machinery/destructive_analyzer + board_type = "machine" + origin_tech = @'{"magnets":2,"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/autolathe + name = "circuitboard (autolathe)" + build_path = /obj/machinery/fabricator + board_type = "machine" + origin_tech = @'{"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 3, + /obj/item/stock_parts/manipulator = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/recycler + name = "circuitboard (recycler)" + build_path = /obj/machinery/recycler + board_type = "machine" + origin_tech = @'{"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/autolathe/micro + name = "circuitboard (microlathe)" + build_path = /obj/machinery/fabricator/micro + origin_tech = @'{"engineering":1,"programming":1}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1 + ) +/obj/item/stock_parts/circuitboard/autolathe/book + name = "circuitboard (autobinder)" + build_path = /obj/machinery/fabricator/book + origin_tech = @'{"engineering":1,"programming":1}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1 + ) +/obj/item/stock_parts/circuitboard/replicator + name = "circuitboard (replicator)" + build_path = /obj/machinery/fabricator/replicator + board_type = "machine" + origin_tech = @'{"engineering":3,"programming":2,"biotech":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 3, + /obj/item/stock_parts/manipulator = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/protolathe + name = "circuitboard (protolathe)" + build_path = /obj/machinery/fabricator/protolathe + board_type = "machine" + origin_tech = @'{"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 2, + /obj/item/chems/glass/beaker = 2) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/circuit_imprinter + name = "circuitboard (circuit imprinter)" + build_path = /obj/machinery/fabricator/imprinter + board_type = "machine" + origin_tech = @'{"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/chems/glass/beaker = 2) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/mechfab + name = "circuitboard (industrial fabricator)" + build_path = /obj/machinery/fabricator/industrial + board_type = "machine" + origin_tech = @'{"programming":3,"engineering":3}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/roboticsfab + name = "circuitboard (robotics fabricator)" + build_path = /obj/machinery/fabricator/robotics + board_type = "machine" + origin_tech = @'{"programming":3,"engineering":3}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/textilesfab + name = "circuitboard (textiles fabricator)" + build_path = /obj/machinery/fabricator/textile + board_type = "machine" + origin_tech = @'{"programming":3,"engineering":3}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/suspension_gen + name = "circuitboard (suspension generator)" + build_path = /obj/machinery/suspension_gen + board_type = "machine" + origin_tech = @'{"programming":4,"engineering":3,"magnets":4}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/battery/buildable/stock = 1, + /obj/item/cell/high = 1, + /obj/item/stock_parts/access_lock/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/artifact_harvester + name = "circuitboard (artifact harvester)" + build_path = /obj/machinery/artifact_harvester + board_type = "machine" + origin_tech = @'{"programming":4,"engineering":3}' + req_components = list( + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/artifact_analyser + name = "circuitboard (artifact analyser)" + build_path = /obj/machinery/artifact_analyser + board_type = "machine" + origin_tech = @'{"programming":4,"engineering":3}' + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/micro_laser = 2) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/artifact_scanner + name = "circuitboard (artifact scanpad)" + build_path = /obj/machinery/artifact_scanpad + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2,"magnets":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/cryopod + name = "circuitboard (cryo pod)" + build_path = /obj/machinery/cryopod + board_type = "machine" + origin_tech = @'{"programming":6,"engineering":6,"wormholes":6}' + req_components = list( + /obj/item/stock_parts/matter_bin = 4, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/subspace/crystal = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + buildtype_select = TRUE + +/obj/item/stock_parts/circuitboard/cryopod/get_buildable_types() + return typesof(/obj/machinery/cryopod) + +/obj/item/stock_parts/circuitboard/merchant_pad + name = "circuitboard (merchant pad)" + build_path = /obj/machinery/merchant_pad + board_type = "machine" + origin_tech = @'{"programming":6,"wormholes":6,"esoteric":1}' + req_components = list( + /obj/item/stack/cable_coil = 15, + /obj/item/stock_parts/subspace/amplifier = 1, + /obj/item/stock_parts/subspace/ansible = 1, + /obj/item/stock_parts/subspace/crystal = 1, + /obj/item/stock_parts/subspace/transmitter = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + ) + +/obj/item/stock_parts/circuitboard/radiocarbon_spectrometer + name = "circuitboard (radiocarbon spectrometer)" + build_path = /obj/machinery/radiocarbon_spectrometer + board_type = "machine" + origin_tech = @'{"programming":2,"engineering":2,"magnets":2}' + req_components = list( + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/scanning_module = 4 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1, + ) + +/obj/item/stock_parts/circuitboard/design_database + name = "circuitboard (design database)" + build_path = /obj/machinery/design_database + board_type = "machine" + origin_tech = @'{"programming":2, "engineering":2}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/item_holder/disk_reader/buildable = 1, + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/machinery/self_destruct_storage.dm b/code/game/objects/items/circuitboards/machinery/self_destruct_storage.dm new file mode 100644 index 000000000000..4c2ba1eecf31 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/self_destruct_storage.dm @@ -0,0 +1,14 @@ +/obj/item/stock_parts/circuitboard/nuclear_cylinder_storage + name = "circuitboard (nuclear cylinder storage)" + build_path = /obj/machinery/nuclear_cylinder_storage/buildable + board_type = "machine" + origin_tech = @'{"combat":2,"engineering":2}' + + req_components = list( + /obj/item/stack/cable_coil = 10, + /obj/item/stock_parts/manipulator = 2 + ) + + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm b/code/game/objects/items/circuitboards/machinery/shieldgen.dm similarity index 76% rename from code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm rename to code/game/objects/items/circuitboards/machinery/shieldgen.dm index e22329465165..c8e917417602 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/shieldgen.dm +++ b/code/game/objects/items/circuitboards/machinery/shieldgen.dm @@ -1,9 +1,9 @@ // New shields /obj/item/stock_parts/circuitboard/shield_generator - name = T_BOARD("advanced shield generator") + name = "circuitboard (advanced shield generator)" board_type = "machine" - build_path = /obj/machinery/power/shield_generator - origin_tech = "{'magnets':3,'powerstorage':4}" + build_path = /obj/machinery/shield_generator + origin_tech = @'{"magnets":3,"powerstorage":4}' req_components = list( /obj/item/stock_parts/capacitor = 1, /obj/item/stock_parts/micro_laser = 1, @@ -11,14 +11,14 @@ additional_spawn_components = list( /obj/item/stock_parts/console_screen = 1, /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 + /obj/item/stock_parts/power/terminal = 1 ) /obj/item/stock_parts/circuitboard/shield_diffuser - name = T_BOARD("shield diffuser") + name = "circuitboard (shield diffuser)" board_type = "machine" build_path = /obj/machinery/shield_diffuser - origin_tech = "{'magnets':4,'powerstorage':2}" + origin_tech = @'{"magnets":4,"powerstorage":2}' req_components = list( /obj/item/stock_parts/capacitor = 1, /obj/item/stock_parts/micro_laser = 1) @@ -29,16 +29,16 @@ ) /obj/item/stock_parts/circuitboard/pointdefense - name = T_BOARD("point defense battery") + name = "circuitboard (point defense battery)" board_type = "machine" desc = "Control systems for a Kuiper pattern point defense battery. Aim away from vessel." build_path = /obj/machinery/pointdefense - origin_tech = "{'engineering':3,'combat':2}" + origin_tech = @'{"engineering":3,"combat":2}' req_components = list( /obj/item/mech_equipment/mounted_system/taser/laser = 1, /obj/item/stock_parts/manipulator = 2, /obj/item/stock_parts/capacitor = 2, - + ) additional_spawn_components = list( /obj/item/stock_parts/power/terminal/buildable = 1, @@ -47,8 +47,8 @@ ) /obj/item/stock_parts/circuitboard/pointdefense_control - name = T_BOARD("fire assist mainframe") + name = "circuitboard (fire assist mainframe)" board_type = "machine" desc = "A control computer to synchronize point defense batteries." build_path = /obj/machinery/pointdefense_control - origin_tech = "{'engineering':3,'combat':2}" \ No newline at end of file + origin_tech = @'{"engineering":3,"combat":2}' \ No newline at end of file diff --git a/code/game/objects/items/circuitboards/machinery/shipsensors.dm b/code/game/objects/items/circuitboards/machinery/shipsensors.dm new file mode 100644 index 000000000000..e19b4b57f075 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/shipsensors.dm @@ -0,0 +1,15 @@ +/obj/item/stock_parts/circuitboard/shipsensors + name = "circuitboard (ship sensors)" + build_path = /obj/machinery/shipsensors + board_type = "machine" + origin_tech = @'{"wormholes":2,"programming":2}' + req_components = list( + /obj/item/stack/cable_coil = 30, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/subspace/ansible = 1, + /obj/item/stock_parts/subspace/transmitter = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/shielding/heat = 1, + /obj/item/stock_parts/power/terminal = 1 + ) diff --git a/code/game/objects/items/circuitboards/machinery/telecomms.dm b/code/game/objects/items/circuitboards/machinery/telecomms.dm new file mode 100644 index 000000000000..d7b14d341c7d --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/telecomms.dm @@ -0,0 +1,63 @@ +/obj/item/stock_parts/circuitboard/message_server + name = "circuitboard (message server)" + board_type = "machine" + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/computer/network_card = 1 + ) + build_path = /obj/machinery/network/message_server + origin_tech = @'{"programming":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/subspace/ansible = 1, + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/subspace/treatment = 2, + /obj/item/stock_parts/subspace/analyzer = 1 + ) + +/obj/item/stock_parts/circuitboard/telecomms_hub + name = "circuitboard (telecommunications hub)" + board_type = "machine" + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/computer/network_card = 1 + ) + build_path = /obj/machinery/network/telecomms_hub + origin_tech = @'{"programming":4,"engineering":4}' + req_components = list( + /obj/item/stock_parts/subspace/ansible = 1, + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/subspace/treatment = 1, + /obj/item/stock_parts/subspace/analyzer = 1 + ) + +/obj/item/stock_parts/circuitboard/comms_maser + name = "circuitboard (communications maser)" + board_type = "machine" + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + build_path = /obj/machinery/shipcomms/broadcaster + origin_tech = @'{"programming":4,"engineering":4}' + req_components = list( + /obj/item/stack/cable_coil = 20, + /obj/item/stock_parts/micro_laser/ultra = 5 + ) + +/obj/item/stock_parts/circuitboard/comms_antenna + name = "circuitboard (communications antenna)" + board_type = "machine" + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + build_path = /obj/machinery/shipcomms/receiver + origin_tech = @'{"programming":4,"engineering":4}' + req_components = list( + /obj/item/stack/cable_coil = 20, + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/subspace/treatment = 1, + /obj/item/stock_parts/subspace/analyzer = 1 + ) diff --git a/code/game/objects/items/circuitboards/machinery/unary_atmos.dm b/code/game/objects/items/circuitboards/machinery/unary_atmos.dm new file mode 100644 index 000000000000..6ac21c7a7846 --- /dev/null +++ b/code/game/objects/items/circuitboards/machinery/unary_atmos.dm @@ -0,0 +1,29 @@ +/obj/item/stock_parts/circuitboard/unary_atmos + board_type = "machine" + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/unary_atmos/construct(var/obj/machinery/atmospherics/unary/U) + U.build(src) + +/obj/item/stock_parts/circuitboard/unary_atmos/heater + name = "circuitboard (gas heating system)" + build_path = /obj/machinery/atmospherics/unary/temperature/heater + origin_tech = @'{"powerstorage":2,"engineering":1}' + req_components = list( + /obj/item/stack/cable_coil = 5, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/capacitor = 2) + +/obj/item/stock_parts/circuitboard/unary_atmos/cooler + name = "circuitboard (gas cooling system)" + build_path = /obj/machinery/atmospherics/unary/temperature/freezer + origin_tech = @'{"magnets":2,"engineering":2}' + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/capacitor = 2, + /obj/item/stock_parts/manipulator = 1) diff --git a/code/game/objects/items/circuitboards/other.dm b/code/game/objects/items/circuitboards/other.dm new file mode 100644 index 000000000000..d440f6ce30c8 --- /dev/null +++ b/code/game/objects/items/circuitboards/other.dm @@ -0,0 +1,6 @@ +//Stuff that doesn't fit into any category goes here + +/obj/item/stock_parts/circuitboard/aicore + name = "circuitboard (AI core)" + origin_tech = @'{"programming":4,"biotech":2}' + board_type = "other" diff --git a/code/game/objects/items/circuitboards/wall.dm b/code/game/objects/items/circuitboards/wall.dm new file mode 100644 index 000000000000..fe1e20a8cfcd --- /dev/null +++ b/code/game/objects/items/circuitboards/wall.dm @@ -0,0 +1,95 @@ +// For wall machines, using the wall frame construction method. + +/obj/item/stock_parts/circuitboard/fire_alarm + name = "circuitboard (fire alarm)" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics" + desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees Celsius!\"." + build_path = /obj/machinery/firealarm + board_type = "wall" + origin_tech = @'{"programming":1,"engineering":1}' + req_components = list() + additional_spawn_components = null + +/obj/item/stock_parts/circuitboard/air_alarm + name = "circuitboard (air alarm)" + icon = 'icons/obj/doors/door_assembly.dmi' + icon_state = "door_electronics" + build_path = /obj/machinery/alarm + board_type = "wall" + origin_tech = @'{"programming":1,"engineering":1}' + req_components = list() + additional_spawn_components = null + +/obj/item/stock_parts/circuitboard/apc + name = "circuitboard (area power controller)" + desc = "Heavy-duty switching circuits for power control." + icon = 'icons/obj/modules/module_power.dmi' + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + build_path = /obj/machinery/apc/buildable + board_type = "wall" + origin_tech = @'{"programming":1,"engineering":1}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/battery/buildable = 1, + /obj/item/stock_parts/power/terminal/buildable = 1, + /obj/item/stock_parts/access_lock/buildable = 1 + ) + +/obj/item/stock_parts/circuitboard/requests_console + name = "circuitboard (requests console)" + build_path = /obj/machinery/network/requests_console + board_type = "wall" + origin_tech = @'{"programming":1,"engineering":1}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1, + ) + +/obj/item/stock_parts/circuitboard/requests_console/atm + name = "circuitboard (atm)" + build_path = /obj/machinery/atm + +/obj/item/stock_parts/circuitboard/requests_console/newscaster + name = "circuitboard (newscaster)" + build_path = /obj/machinery/newscaster + +/obj/item/stock_parts/circuitboard/airlock_controller + name = "circuitboard (airlock controller)" + build_path = /obj/machinery/embedded_controller/radio/simple_docking_controller + board_type = "wall" + origin_tech = @'{"programming":3,"engineering":3}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + ) + buildtype_select = TRUE + +/obj/item/stock_parts/circuitboard/airlock_controller/get_buildable_types() + var/static/list/AirlockControllerSubtypes = subtypesof(/obj/machinery/embedded_controller/radio) | subtypesof(/obj/machinery/embedded_controller/radio/airlock) + . = list() + for(var/path in AirlockControllerSubtypes) + var/obj/machinery/embedded_controller/radio/controller = path + var/base_type = initial(controller.base_type) || path + . |= base_type + . |= /obj/machinery/dummy_airlock_controller //Let us build the dummy controller + +/obj/item/stock_parts/circuitboard/camera + name = "circuitboard (camera)" + build_path = /obj/machinery/camera + board_type = "wall" + origin_tech = @'{"programming":1,"engineering":1}' + req_components = list() + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/power/battery/buildable/stock = 1, + /obj/item/cell = 1 + ) \ No newline at end of file diff --git a/code/game/objects/items/contraband.dm b/code/game/objects/items/contraband.dm index 2ae5b28c95b5..669e5876b86f 100644 --- a/code/game/objects/items/contraband.dm +++ b/code/game/objects/items/contraband.dm @@ -1,23 +1,29 @@ //Let's get some REAL contraband stuff in here. Because come on, getting brigged for LIPSTICK is no fun. //Illicit drugs~ -/obj/item/storage/pill_bottle/happy +/obj/item/pill_bottle/happy name = "bottle of Happy pills" desc = "Highly illegal drug. When you want to see the rainbow." wrapper_color = COLOR_PINK - startswith = list(/obj/item/chems/pill/happy = 10) -/obj/item/storage/pill_bottle/zoom +/obj/item/pill_bottle/happy/WillContain() + return list(/obj/item/chems/pill/happy = 10) + +/obj/item/pill_bottle/zoom name = "bottle of Zoom pills" desc = "Highly illegal drug. Trade brain for speed." wrapper_color = COLOR_BLUE - startswith = list(/obj/item/chems/pill/zoom = 10) -/obj/item/storage/pill_bottle/gleam - name = "bottle of Three Eye pills" +/obj/item/pill_bottle/zoom/WillContain() + return list(/obj/item/chems/pill/zoom = 10) + +/obj/item/pill_bottle/gleam + name = "bottle of Gleam pills" desc = "Highly illegal drug. Stimulates rarely used portions of the brain." wrapper_color = COLOR_BLUE - startswith = list(/obj/item/chems/pill/gleam = 10) + +/obj/item/pill_bottle/gleam/WillContain() + return list(/obj/item/chems/pill/gleam = 10) /obj/item/chems/glass/beaker/vial/random atom_flags = 0 @@ -34,15 +40,18 @@ /obj/item/chems/glass/beaker/vial/random/Initialize() . = ..() + update_icon() +/obj/item/chems/glass/beaker/vial/random/populate_reagents() var/list/picked_reagents = pickweight(random_reagent_list) for(var/reagent in picked_reagents) - reagents.add_reagent(reagent, picked_reagents[reagent]) + add_to_reagents(reagent, picked_reagents[reagent]) var/list/names = new - for(var/reagent_type in reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(reagent_type) - names += R.liquid_name + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(reagents)) + names += reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID) - desc = "Contains [english_list(names)]." - update_icon() + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(reagents)) + names += reagent.get_reagent_name(reagents, MAT_PHASE_SOLID) + + desc = "Contains [english_list(names)]." \ No newline at end of file diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm deleted file mode 100644 index 6b3d7a9dc8ea..000000000000 --- a/code/game/objects/items/crayons.dm +++ /dev/null @@ -1,119 +0,0 @@ -/obj/item/pen/crayon/red - icon_state = "crayonred" - colour = "#da0000" - shadeColour = "#810c0c" - colourName = "red" - color_description = "red crayon" - -/obj/item/pen/crayon/orange - icon_state = "crayonorange" - colour = "#ff9300" - shadeColour = "#a55403" - colourName = "orange" - color_description = "orange crayon" - -/obj/item/pen/crayon/yellow - icon_state = "crayonyellow" - colour = "#fff200" - shadeColour = "#886422" - colourName = "yellow" - color_description = "yellow crayon" - -/obj/item/pen/crayon/green - icon_state = "crayongreen" - colour = "#a8e61d" - shadeColour = "#61840f" - colourName = "green" - color_description = "green crayon" - -/obj/item/pen/crayon/blue - icon_state = "crayonblue" - colour = "#00b7ef" - shadeColour = "#0082a8" - colourName = "blue" - color_description = "blue crayon" - -/obj/item/pen/crayon/purple - icon_state = "crayonpurple" - colour = "#da00ff" - shadeColour = "#810cff" - colourName = "purple" - color_description = "purple crayon" - -/obj/item/pen/crayon/random/Initialize() - ..() - var/crayon_type = pick(subtypesof(/obj/item/pen/crayon) - /obj/item/pen/crayon/random) - new crayon_type(loc) - return INITIALIZE_HINT_QDEL - -/obj/item/pen/crayon/mime - icon_state = "crayonmime" - desc = "A very sad-looking crayon." - colour = "#ffffff" - shadeColour = "#000000" - colourName = "mime" - color_description = "white crayon" - uses = 0 - -/obj/item/pen/crayon/mime/attack_self(mob/living/user) //inversion - if(colour != "#ffffff" && shadeColour != "#000000") - colour = "#ffffff" - shadeColour = "#000000" - to_chat(user, "You will now draw in white and black with this crayon.") - else - colour = "#000000" - shadeColour = "#ffffff" - to_chat(user, "You will now draw in black and white with this crayon.") - return - -/obj/item/pen/crayon/rainbow - icon_state = "crayonrainbow" - colour = "#fff000" - shadeColour = "#000fff" - colourName = "rainbow" - color_description = "rainbow crayon" - uses = 0 - -/obj/item/pen/crayon/rainbow/attack_self(mob/living/user) - colour = input(user, "Please select the main colour.", "Crayon colour") as color - shadeColour = input(user, "Please select the shade colour.", "Crayon colour") as color - return - -/obj/item/pen/crayon/afterattack(atom/target, mob/user, proximity) - if(!proximity) return - if(istype(target,/turf/simulated/floor)) - var/drawtype = input("Choose what you'd like to draw.", "Crayon scribbles") in list("graffiti","rune","letter","arrow") - switch(drawtype) - if("letter") - drawtype = input("Choose the letter.", "Crayon scribbles") in 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") - to_chat(user, "You start drawing a letter on the [target.name].") - if("graffiti") - to_chat(user, "You start drawing graffiti on the [target.name].") - if("rune") - to_chat(user, "You start drawing a rune on the [target.name].") - if("arrow") - drawtype = input("Choose the arrow.", "Crayon scribbles") in list("left", "right", "up", "down") - to_chat(user, "You start drawing an arrow on the [target.name].") - if(instant || do_after(user, 50)) - new /obj/effect/decal/cleanable/crayon(target,colour,shadeColour,drawtype) - to_chat(user, "You finish drawing.") - target.add_fingerprint(user) // Adds their fingerprints to the floor the crayon is drawn on. - if(uses) - uses-- - if(!uses) - to_chat(user, "You used up your crayon!") - qdel(src) - return - -/obj/item/pen/crayon/attack(mob/living/carbon/M, mob/user) - if(istype(M) && M == user) - to_chat(M, "You take a bite of the crayon and swallow it.") - M.adjust_nutrition(1) - M.reagents.add_reagent(/decl/material/pigment,min(5,uses)/3) - if(uses) - uses -= 5 - if(uses <= 0) - to_chat(M, "You ate your crayon!") - qdel(src) - else - ..() diff --git a/code/game/objects/items/crutches.dm b/code/game/objects/items/crutches.dm new file mode 100644 index 000000000000..9e5b661a4ffa --- /dev/null +++ b/code/game/objects/items/crutches.dm @@ -0,0 +1,65 @@ +/obj/item/crutch + abstract_type = /obj/item/crutch + name = "crutch" + desc = "A mobility aid for those with impaired use of their legs or feet, placed underneath the arm for support." + icon = 'icons/obj/items/crutches.dmi' + icon_state = ICON_STATE_WORLD + base_parry_chance = 10 + material_alteration = MAT_FLAG_ALTERATION_ALL + w_class = ITEM_SIZE_LARGE + max_health = null // autoset from material + /// The padding extension type for this item. If null, no extension is created and this item cannot be padded. + var/padding_extension_type = /datum/extension/padding + /// The initial material used when instantiating this item's padding extension. + /// Should not be modified at runtime. + var/decl/material/initial_padding_material + /// The initial color used for the padding, representing paint or dye. + /// If null, falls back to material color if we have MAT_FLAG_ALTERATION_COLOR. + /// COLOR_WHITE is treated differently than null color is. + var/initial_padding_color + +/obj/item/crutch/Initialize(ml, material_key) + . = ..() + if(padding_extension_type && initial_padding_material) + get_or_create_extension(src, padding_extension_type, initial_padding_material, initial_padding_color) + +/obj/item/crutch/get_stance_support_value() + return LIMB_UNUSABLE + +/obj/item/crutch/get_autopsy_descriptors() + . = ..() + "narrow" + +/obj/item/crutch/on_update_icon() + . = ..() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + add_overlay(overlay_image(icon, "[icon_state]-padding", padding_extension.get_padding_color(material_alteration & MAT_FLAG_ALTERATION_COLOR), RESET_COLOR | RESET_ALPHA)) + +/obj/item/crutch/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + overlay.add_overlay(overlay_image(icon, "[overlay.icon_state]-padding", padding_extension.get_padding_color(material_alteration & MAT_FLAG_ALTERATION_COLOR), RESET_COLOR | RESET_ALPHA)) + . = ..() + +/obj/item/crutch/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + var/padding_paint_color = padding_extension.get_padding_color(FALSE) // do not include material color + . += "It has been padded with [padding_paint_color ? "[padding_material.paint_verb] " : null][padding_material.use_name]." + +/obj/item/crutch/aluminum + material = /decl/material/solid/metal/aluminium + +/obj/item/crutch/aluminum/padded + initial_padding_material = /decl/material/solid/organic/plastic/foam + initial_padding_color = COLOR_GRAY20 + +/obj/item/crutch/wooden + material = /decl/material/solid/organic/wood/oak + +/obj/item/crutch/wooden/padded + initial_padding_material = /decl/material/solid/organic/leather \ No newline at end of file diff --git a/code/game/objects/items/cryobag.dm b/code/game/objects/items/cryobag.dm index 440e24c32faa..ba01e37bc1d0 100644 --- a/code/game/objects/items/cryobag.dm +++ b/code/game/objects/items/cryobag.dm @@ -2,34 +2,35 @@ /obj/item/bodybag/cryobag name = "stasis bag" desc = "A folded, reusable bag designed to prevent additional damage to an occupant, especially useful if short on time or in \ - a hostile enviroment." + a hostile environment." icon = 'icons/obj/closets/cryobag.dmi' icon_state = "bodybag_folded" - origin_tech = "{'biotech':4}" - material = /decl/material/solid/plastic - material = /decl/material/solid/plastic + origin_tech = @'{"biotech":4}' + material = /decl/material/solid/organic/plastic matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) + bag_type = /obj/structure/closet/body_bag/cryobag var/stasis_power -/obj/item/bodybag/cryobag/attack_self(mob/user) - var/obj/structure/closet/body_bag/cryobag/R = new /obj/structure/closet/body_bag/cryobag(user.loc) - if(stasis_power) - R.stasis_power = stasis_power - R.update_icon() - R.add_fingerprint(user) - qdel(src) +/obj/item/bodybag/cryobag/get_cryogenic_power() + return stasis_power + +/obj/item/bodybag/cryobag/create_bag_structure(mob/user) + var/obj/structure/closet/body_bag/cryobag/bag = ..() + if(istype(bag) && stasis_power) + bag.stasis_power = stasis_power + return bag /obj/structure/closet/body_bag/cryobag name = "stasis bag" desc = "A reusable plastic bag designed to prevent additional damage to an occupant, especially useful if short on time or in \ - a hostile enviroment." + a hostile environment." icon = 'icons/obj/closets/cryobag.dmi' item_path = /obj/item/bodybag/cryobag - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic storage_types = CLOSET_STORAGE_MOBS var/datum/gas_mixture/airtank @@ -61,7 +62,6 @@ /obj/structure/closet/body_bag/cryobag/on_update_icon() ..() - overlays.Cut() var/image/I = image(icon, "indicator[opened]") I.appearance_flags = RESET_COLOR var/maxstasis = initial(stasis_power) @@ -71,63 +71,71 @@ I.color = COLOR_YELLOW else I.color = COLOR_RED - overlays += I + add_overlay(I) /obj/structure/closet/body_bag/cryobag/proc/get_saturation() - return -155 * (1 - stasis_power/initial(stasis_power)) + return stasis_power / initial(stasis_power) /obj/structure/closet/body_bag/cryobag/fold(var/user) var/obj/item/bodybag/cryobag/folded = ..() if(istype(folded)) folded.stasis_power = stasis_power - folded.color = color_saturation(get_saturation()) + folded.color = color_matrix_saturation(get_saturation()) /obj/structure/closet/body_bag/cryobag/Process() if(stasis_power < 2) return PROCESS_KILL - var/mob/living/carbon/human/H = locate() in src - if(!H) + var/mob/living/patient = locate() in src + if(!patient) return PROCESS_KILL degradation_time-- if(degradation_time < 0) degradation_time = initial(degradation_time) stasis_power = round(0.75 * stasis_power) - animate(src, color = color_saturation(get_saturation()), time = 10) + animate(src, color = color_matrix_saturation(get_saturation()), time = 10) update_icon() - - if(H.stasis_sources[STASIS_CRYOBAG] != stasis_power) - H.SetStasis(stasis_power, STASIS_CRYOBAG) + patient.add_mob_modifier(/decl/mob_modifier/stasis, 2 SECONDS, source = src) /obj/structure/closet/body_bag/cryobag/return_air() //Used to make stasis bags protect from vacuum. if(airtank) return airtank ..() -/obj/structure/closet/body_bag/cryobag/examine(mob/user) +/obj/structure/closet/body_bag/cryobag/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "The stasis meter shows '[stasis_power]x'." + +/obj/structure/closet/body_bag/cryobag/examined_by(mob/user, distance, infix, suffix) . = ..() - to_chat(user,"The stasis meter shows '[stasis_power]x'.") if(Adjacent(user)) //The bag's rather thick and opaque from a distance. - to_chat(user, "You peer into \the [src].") - for(var/mob/living/L in contents) - L.examine(arglist(args)) + to_chat(user, SPAN_INFO("You peer into \the [src].")) + for(var/mob/living/patient in contents) + patient.examined_by(user, distance, infix, suffix) + return TRUE /obj/item/usedcryobag name = "used stasis bag" - desc = "Pretty useless now.." + desc = "Pretty useless now..." icon_state = "bodybag_used" icon = 'icons/obj/closets/cryobag.dmi' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE + ) /obj/structure/closet/body_bag/cryobag/blank stasis_power = 60 degradation_time = 1800 //ticks until stasis power degrades, ~5 minutes -/obj/structure/closet/body_bag/cryobag/blank/open() +/obj/structure/closet/body_bag/cryobag/blank/open(mob/user) . = ..() new /obj/item/usedcryobag(loc) qdel(src) /obj/structure/closet/body_bag/cryobag/blank/WillContain() - return list(/mob/living/carbon/human/blank) + return list(/mob/living/human/blank) /obj/structure/closet/body_bag/cryobag/blank/Initialize() . = ..() diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 172d405f84e2..9516a2a65a52 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -1,27 +1,28 @@ /obj/item/aicard - name = "inteliCard" + name = "intelliCard" icon = 'icons/obj/items/device/ai_card.dmi' - icon_state = "aicard" // aicard-full - item_state = "electronic" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL - slot_flags = SLOT_BELT - origin_tech = "{'programming':4,'materials':4}" - material = /decl/material/solid/glass + slot_flags = SLOT_LOWER_BODY + origin_tech = @'{"programming":4,"materials":4}' + material = /decl/material/solid/fiberglass matter = list(/decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT) var/flush var/mob/living/silicon/ai/carded_ai -/obj/item/aicard/attack_self(mob/user) +/obj/item/aicard/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE +/obj/item/aicard/attack_self(mob/user) ui_interact(user) -/obj/item/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.inventory_state) +/obj/item/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.inventory_topic_state) var/data[0] data["has_ai"] = carded_ai != null if(carded_ai) data["name"] = carded_ai.name - data["hardware_integrity"] = carded_ai.hardware_integrity() + data["hardware_integrity"] = carded_ai.get_health_percent() data["backup_capacitor"] = carded_ai.backup_capacitor() data["radio"] = !carded_ai.ai_radio.disabledAi data["wireless"] = !carded_ai.control_disabled @@ -52,12 +53,11 @@ if (href_list["wipe"]) var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No") if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE)) - admin_attack_log(user, carded_ai, "Wiped using \the [src.name]", "Was wiped with \the [src.name]", "used \the [src.name] to wipe") + admin_attack_log(user, carded_ai, "Wiped using \the [src]", "Was wiped with \the [src]", "used \the [src] to wipe") flush = 1 to_chat(carded_ai, "Your core files are being wiped!") while (carded_ai && carded_ai.stat != DEAD) - carded_ai.adjustOxyLoss(2) - carded_ai.updatehealth() + carded_ai.take_damage(2, OXY) sleep(10) flush = 0 if (href_list["radio"]) @@ -72,16 +72,14 @@ return 1 /obj/item/aicard/on_update_icon() - overlays.Cut() + . = ..() if(carded_ai) if (!carded_ai.control_disabled) - overlays += image(icon, "aicard-on") + add_overlay("[icon_state]-on") if(carded_ai.stat) - icon_state = "aicard-404" + add_overlay("[icon_state]-404") else - icon_state = "aicard-full" - else - icon_state = "aicard" + add_overlay("[icon_state]-full") /obj/item/aicard/proc/grab_ai(var/mob/living/silicon/ai/ai, var/mob/living/user) if(!ai.client) @@ -100,7 +98,7 @@ new /obj/structure/aicore/deactivated(get_turf(ai)) ai.carded = 1 - admin_attack_log(user, ai, "Carded with [src.name]", "Was carded with [src.name]", "used the [src.name] to card") + admin_attack_log(user, ai, "Carded with [src.name]", "Was carded with [src.name]", "used \the [src] to card") src.SetName("[initial(name)] - [ai.name]") ai.forceMove(src) @@ -120,19 +118,13 @@ return 1 /obj/item/aicard/proc/clear() - if(carded_ai && istype(carded_ai.loc, /turf)) + if(carded_ai && isturf(carded_ai.loc)) carded_ai.carded = 0 SetName(initial(name)) carded_ai.calculate_power_usage() carded_ai = null update_icon() -/obj/item/aicard/see_emote(mob/living/M, text) - if(carded_ai && carded_ai.client) - var/rendered = "[text]" - carded_ai.show_message(rendered, 2) - ..() - /obj/item/aicard/show_message(msg, type, alt, alt_type) if(carded_ai && carded_ai.client) var/rendered = "[msg]" @@ -140,8 +132,8 @@ ..() /obj/item/aicard/relaymove(var/mob/user, var/direction) - if(user.stat || user.stunned) + if(user.incapacitated(INCAPACITATION_KNOCKOUT)) return - var/obj/item/rig/rig = src.get_rig() - if(istype(rig)) + var/obj/item/rig/rig = get_rig() + if(rig) rig.forced_move(direction, user) diff --git a/code/game/objects/items/devices/auto_cpr.dm b/code/game/objects/items/devices/auto_cpr.dm index c81eca7acc5f..ec0a688f4ed3 100644 --- a/code/game/objects/items/devices/auto_cpr.dm +++ b/code/game/objects/items/devices/auto_cpr.dm @@ -2,46 +2,50 @@ name = "auto-compressor" desc = "A device that gives regular compression to the victim's ribcage, used in case of urgent heart issues." icon = 'icons/obj/items/device/auto_cpr.dmi' - icon_state = "pumper" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_NORMAL - origin_tech = "{'magnets':2,'biotech':2}" - slot_flags = SLOT_OCLOTHING + origin_tech = @'{"magnets":2,"biotech":2}' + slot_flags = SLOT_OVER_BODY + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/lead = MATTER_AMOUNT_TRACE, + ) var/last_pump var/skilled_setup -/obj/item/auto_cpr/mob_can_equip(mob/living/carbon/human/H, slot, disable_warning = 0, force = 0) +/obj/item/auto_cpr/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) . = ..() - if(force || !istype(H) || slot != slot_wear_suit) - return - if(H.species.get_bodytype() != BODYTYPE_HUMANOID) //non-humanoids btfo - return - else - return FALSE + if(. && slot == slot_wear_suit_str) + . = user?.get_bodytype_category() == BODYTYPE_HUMANOID -/obj/item/auto_cpr/attack(mob/living/carbon/human/M, mob/living/user, var/target_zone) - if(istype(M) && user.a_intent == I_HELP) - if(M.wear_suit) - to_chat(user, SPAN_WARNING("Their [M.wear_suit] is in the way, remove it first!")) - return 1 - user.visible_message(SPAN_NOTICE("[user] starts fitting [src] onto the [M]'s chest.")) +/obj/item/auto_cpr/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) - if(!do_mob(user, M, 2 SECONDS)) - return - - if(user.unEquip(src)) - if(!M.equip_to_slot_if_possible(src, slot_wear_suit, del_on_fail=0, disable_warning=1, redraw_mob=1)) + if(ishuman(target) && user.check_intent(I_FLAG_HELP)) + var/obj/item/suit = target.get_equipped_item(slot_wear_suit_str) + if(suit) + to_chat(user, SPAN_WARNING("Their [suit] is in the way, remove it first!")) + return TRUE + user.visible_message(SPAN_NOTICE("[user] starts fitting [src] onto \the [target]'s chest.")) + if(!do_mob(user, target, 2 SECONDS)) + return TRUE + if(user.try_unequip(src)) + if(!target.equip_to_slot_if_possible(src, slot_wear_suit_str, del_on_fail=0, disable_warning=1, redraw_mob=1)) user.put_in_active_hand(src) - return 1 - else - return ..() + return TRUE + + return ..() /obj/item/auto_cpr/equipped(mob/user, slot) ..() START_PROCESSING(SSobj,src) /obj/item/auto_cpr/attack_hand(mob/user) - skilled_setup = user.skill_check(SKILL_ANATOMY, SKILL_BASIC) && user.skill_check(SKILL_MEDICAL, SKILL_BASIC) - ..() + skilled_setup = user.skill_check(SKILL_ANATOMY, SKILL_BASIC) && user.skill_check(SKILL_MEDICAL, SKILL_BASIC) + return ..() /obj/item/auto_cpr/dropped(mob/user) STOP_PROCESSING(SSobj,src) @@ -51,21 +55,21 @@ if(!ishuman(loc)) return PROCESS_KILL - var/mob/living/carbon/human/H = loc - if(H.get_inventory_slot(src) != slot_wear_suit) + var/mob/living/human/H = loc + if(H.get_equipped_slot_for_item(src) != slot_wear_suit_str) return PROCESS_KILL if(world.time > last_pump + 15 SECONDS) last_pump = world.time playsound(src, 'sound/machines/pump.ogg', 25) if(!skilled_setup && prob(20)) - var/obj/item/organ/external/E = H.get_organ(BP_CHEST) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(H, BP_CHEST) E.add_pain(15) - to_chat(H, "Your [E] is compressed painfully!") + to_chat(H, "Your [E] is compressed painfully!") if(prob(5)) E.fracture() else - var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[BP_HEART] + var/obj/item/organ/internal/heart/heart = H.get_organ(BP_HEART, /obj/item/organ/internal/heart) if(heart) heart.external_pump = list(world.time, 0.6) diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm index 5a7ae83eb94b..5cc9ad6652f5 100644 --- a/code/game/objects/items/devices/binoculars.dm +++ b/code/game/objects/items/devices/binoculars.dm @@ -4,14 +4,12 @@ zoomdevicename = "eyepieces" icon = 'icons/obj/items/binoculars.dmi' icon_state = "binoculars" - obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 w_class = ITEM_SIZE_SMALL - throwforce = 5.0 throw_range = 15 throw_speed = 3 - + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_SECONDARY) /obj/item/binoculars/attack_self(mob/user) if(zoom) diff --git a/code/game/objects/items/devices/boombox.dm b/code/game/objects/items/devices/boombox.dm index 31847b2861bf..6570fe37400d 100644 --- a/code/game/objects/items/devices/boombox.dm +++ b/code/game/objects/items/devices/boombox.dm @@ -1,106 +1,47 @@ -/obj/item/boombox +/obj/item/music_player/boombox name = "boombox" - desc = "A device used to emit rhythmic sounds, colloquialy refered to as a 'boombox'. It's in a retro style (massive), and absolutely unwieldy." + desc = "A device used to emit rhythmic sounds, colloquially referred to as a 'boombox'. It's in a retro style (massive), and absolutely unwieldy." + origin_tech = @'{"magnets":2,"combat":1}' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE, + ) + player_name = "BOOMTASTIC 3000" + interact_sound = "switch" icon = 'icons/obj/items/device/boombox.dmi' - icon_state = "off" - item_state = "boombox" - force = 7 - w_class = ITEM_SIZE_HUGE //forbid putting something that emits loud sounds forever into a backpack - origin_tech = "{'magnets':2,'combat':1}" - var/playing = 0 - var/track_num = 1 - var/volume = 20 - var/max_volume = 40 - var/frequency = 1 - var/datum/sound_token/sound_token - var/list/datum/track/tracks - var/sound_id + var/break_chance = 3 var/broken var/panel = TRUE -/obj/item/boombox/attack_self(var/mob/user) - interact(user) - -/obj/item/boombox/Initialize() - . = ..() - sound_id = "[type]_[sequential_id(type)]" - tracks = setup_music_tracks(tracks) - -/obj/item/boombox/emp_act(severity) +/obj/item/music_player/boombox/emp_act(severity) boombox_break() -/obj/item/boombox/examine(mob/user) +/obj/item/music_player/boombox/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(!panel) - to_chat(user, SPAN_NOTICE("The front panel is unhinged.")) + . += SPAN_NOTICE("The front panel is unhinged.") if(broken) - to_chat(user, SPAN_WARNING("It's broken.")) - -/obj/item/boombox/Destroy() - stop() - . = ..() + . += SPAN_WARNING("It's broken.") -/obj/item/boombox/interact(var/mob/user) - if(!CanPhysicallyInteract(user)) - return - var/dat = "NEXT" - dat += "PREV" - dat += "PLAY" - dat += "STOP" - dat += "VOL -" - dat += "VOL +" - var/datum/browser/popup = new(user, "boombox", "BOOMTASTIC 3000", 290, 110) - popup.set_content(dat) - popup.open() - -/obj/item/boombox/DefaultTopicState() - return GLOB.physical_state - -/obj/item/boombox/CouldUseTopic(var/mob/user) - ..() - playsound(src, "switch", 40) - -/obj/item/boombox/OnTopic(var/user, var/list/href_list) - if(href_list["tracknum"]) - var/diff = text2num(href_list["tracknum"]) - track_num += diff - if(track_num > tracks.len) - track_num = 1 - else if (track_num < 1) - track_num = tracks.len - if(playing) - start() - return TOPIC_REFRESH - if(href_list["stop"]) - stop() - return TOPIC_HANDLED - if(href_list["start"] && !broken) - start() - return TOPIC_HANDLED - if(href_list["volup"]) - change_volume(volume + 10) - return TOPIC_HANDLED - if(href_list["voldown"]) - change_volume(volume - 10) - return TOPIC_HANDLED - -/obj/item/boombox/attackby(var/obj/item/W, var/mob/user) - if(isScrewdriver(W)) +/obj/item/music_player/boombox/attackby(var/obj/item/used_item, var/mob/user) + if(IS_SCREWDRIVER(used_item)) if(!panel) - user.visible_message(SPAN_NOTICE("\The [user] re-attaches \the [src]'s front panel with \the [W]."), SPAN_NOTICE("You re-attach \the [src]'s front panel.")) + user.visible_message(SPAN_NOTICE("\The [user] re-attaches \the [src]'s front panel with \the [used_item]."), SPAN_NOTICE("You re-attach \the [src]'s front panel.")) playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) panel = TRUE return TRUE if(!broken) - AdjustFrequency(W, user) + AdjustFrequency(used_item, user) return TRUE else if(panel) - user.visible_message(SPAN_NOTICE("\The [user] unhinges \the [src]'s front panel with \the [W]."), SPAN_NOTICE("You unhinge \the [src]'s front panel.")) + user.visible_message(SPAN_NOTICE("\The [user] unhinges \the [src]'s front panel with \the [used_item]."), SPAN_NOTICE("You unhinge \the [src]'s front panel.")) playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) panel = FALSE - if(istype(W,/obj/item/stack/nanopaste)) - var/obj/item/stack/S = W + if(istype(used_item,/obj/item/stack/nanopaste)) + var/obj/item/stack/S = used_item if(broken && !panel) if(S.use(1)) user.visible_message(SPAN_NOTICE("\The [user] pours some of \the [S] onto \the [src]."), SPAN_NOTICE("You pour some of \the [S] over \the [src]'s internals and watch as it retraces and resolders paths.")) @@ -110,7 +51,7 @@ else . = ..() -/obj/item/boombox/proc/AdjustFrequency(var/obj/item/W, var/mob/user) +/obj/item/music_player/boombox/proc/AdjustFrequency(var/obj/item/used_item, var/mob/user) var/const/MIN_FREQUENCY = 0.5 var/const/MAX_FREQUENCY = 1.5 @@ -121,9 +62,9 @@ var/tighten = "Tighten (play slower)" var/loosen = "Loosen (play faster)" - if(frequency > MIN_FREQUENCY) + if(music_frequency > MIN_FREQUENCY) options += tighten - if(frequency < MAX_FREQUENCY) + if(music_frequency < MAX_FREQUENCY) options += loosen var/operation = input(user, "How do you wish to adjust the player head?", "Adjust player", options[1]) as null|anything in options @@ -131,65 +72,50 @@ return FALSE if(!MayAdjust(user)) return FALSE - if(W != user.get_active_hand()) + if(used_item != user.get_active_held_item()) return FALSE if(!CanPhysicallyInteract(user)) return FALSE if(operation == loosen) - frequency += 0.1 + music_frequency += 0.1 else if(operation == tighten) - frequency -= 0.1 - frequency = Clamp(frequency, MIN_FREQUENCY, MAX_FREQUENCY) + music_frequency -= 0.1 + music_frequency = clamp(music_frequency, MIN_FREQUENCY, MAX_FREQUENCY) user.visible_message(SPAN_NOTICE("\The [user] adjusts \the [src]'s player head."), SPAN_NOTICE("You adjust \the [src]'s player head.")) playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - if(frequency > 1.0) + if(music_frequency > 1.0) to_chat(user, SPAN_NOTICE("\The [src] should be playing faster than usual.")) - else if(frequency < 1.0) + else if(music_frequency < 1.0) to_chat(user, SPAN_NOTICE("\The [src] should be playing slower than usual.")) else to_chat(user, SPAN_NOTICE("\The [src] should be playing as fast as usual.")) return TRUE -/obj/item/boombox/proc/MayAdjust(var/mob/user) +/obj/item/music_player/boombox/proc/MayAdjust(var/mob/user) if(playing) to_chat(user, "You can only adjust \the [src] when it's not playing.") return FALSE return TRUE -/obj/item/boombox/on_update_icon() - icon_state = playing ? "on" : "off" - -/obj/item/boombox/proc/stop() - playing = 0 - update_icon() - QDEL_NULL(sound_token) - -/obj/item/boombox/proc/start() - QDEL_NULL(sound_token) - var/datum/track/T = tracks[track_num] - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, T.GetTrack(), volume = volume, frequency = frequency, range = 7, falloff = 4, prefer_mute = TRUE, preference = /datum/client_preference/play_game_music) - playing = 1 - update_icon() - if(prob(break_chance)) - boombox_break() - -/obj/item/boombox/proc/boombox_break() +/obj/item/music_player/boombox/proc/boombox_break() audible_message(SPAN_WARNING("\The [src]'s speakers pop with a sharp crack!")) playsound(src.loc, 'sound/effects/snap.ogg', 100, 1) broken = TRUE stop() -/obj/item/boombox/proc/change_volume(var/new_volume) - volume = Clamp(new_volume, 0, max_volume) - if(sound_token) - sound_token.SetVolume(volume) +/obj/item/music_player/boombox/start() + if(broken) + return + . = ..() + if(prob(break_chance)) + boombox_break() /obj/random_multi/single_item/boombox name = "boombox spawnpoint" id = "boomtastic" - item_path = /obj/item/boombox/ + item_path = /obj/item/music_player/boombox diff --git a/code/game/objects/items/devices/cable_painter.dm b/code/game/objects/items/devices/cable_painter.dm index 00781bda19ac..80cbe215f4a5 100644 --- a/code/game/objects/items/devices/cable_painter.dm +++ b/code/game/objects/items/devices/cable_painter.dm @@ -1,39 +1,44 @@ /obj/item/cable_painter name = "cable painter" desc = "A device for repainting cables." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "labeler0" - item_state = "flight" + icon = 'icons/obj/items/hand_labeler.dmi' + icon_state = ICON_STATE_WORLD var/color_selection - var/list/modes w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic /obj/item/cable_painter/Initialize() . = ..() - color_selection = pick(GLOB.possible_cable_colours) + color_selection = pick(get_global_cable_colors()) -obj/item/cable_painter/examine(mob/user, distance) +/obj/item/cable_painter/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "The color is currently set to [lowertext(color_selection)].") + . += "The color is currently set to [lowertext(color_selection)]." /obj/item/cable_painter/attack_self(mob/user) - var/new_color_selection = input("What color would you like to use?", "Choose a Color", color_selection) as null|anything in GLOB.possible_cable_colours + var/new_color_selection = input("What color would you like to use?", "Choose a Color", color_selection) as null|anything in get_global_cable_colors() if(new_color_selection && !user.incapacitated() && (src in user)) color_selection = new_color_selection to_chat(user, "You change the paint mode to [lowertext(color_selection)].") /obj/item/cable_painter/afterattack(var/atom/A, var/mob/user, var/proximity) + if(!proximity) return ..() + if(istype(A, /obj/structure/cable)) - var/picked_color = GLOB.possible_cable_colours[color_selection] + var/list/possible_cable_colours = get_global_cable_colors() + var/picked_color = possible_cable_colours[color_selection] if(!picked_color || A.color == picked_color) return A.color = picked_color to_chat(user, "You set \the [A]'s color to [lowertext(color_selection)].") - else if(isCoil(A)) + return + + if(istype(A, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/c = A c.set_cable_color(color_selection, user) - else - . = ..() + return + + . = ..() diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index 56a018c24390..fc743829ceef 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -1,21 +1,24 @@ /obj/item/chameleon name = "chameleon projector" icon = 'icons/obj/items/device/chameleon_proj.dmi' - icon_state = "shield0" + icon_state = ICON_STATE_WORLD obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - item_state = "electronic" - throwforce = 5.0 + slot_flags = SLOT_LOWER_BODY throw_speed = 1 throw_range = 5 w_class = ITEM_SIZE_SMALL - origin_tech = "{'esoteric':4,'magnets':4}" + origin_tech = @'{"esoteric":4,"magnets":4}' + material = /decl/material/solid/organic/plastic var/can_use = 1 var/obj/effect/dummy/chameleon/active_dummy = null - var/saved_item = /obj/item/trash/cigbutt - var/saved_icon = 'icons/obj/clothing/obj_mask.dmi' - var/saved_icon_state = "cigbutt" - var/saved_overlays + var/saved_appearance + +/obj/item/chameleon/Destroy() + saved_appearance = null + if(istype(active_dummy) && !QDELETED(active_dummy)) + qdel(active_dummy) + active_dummy = null + return ..() /obj/item/chameleon/dropped() disrupt() @@ -29,123 +32,147 @@ toggle() /obj/item/chameleon/afterattack(atom/target, mob/user , proximity) - if(!proximity) return - if(!active_dummy) - if(istype(target,/obj/item) && !istype(target, /obj/item/disk/nuclear)) - playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6) - to_chat(user, "Scanned [target].") - saved_item = target.type - saved_icon = target.icon - saved_icon_state = target.icon_state - saved_overlays = target.overlays + + if(!proximity) + return ..() + + if(active_dummy) + to_chat(user, SPAN_WARNING("\The [src] is already projecting. Turn it off first.")) + return TRUE + + if(!istype(target, /obj/item)) + to_chat(user, SPAN_WARNING("\The [src] can only mimic items.")) + return TRUE + + if(istype(target, /obj/item/disk/nuclear)) + to_chat(user, SPAN_WARNING("Inter-system tax fraud regulations prevent scanning \the [target].")) + return TRUE + + if(!target.simulated || !target.icon || !target.icon_state || !check_state_in_icon(target.icon_state, target.icon)) + to_chat(user, SPAN_WARNING("\The [target] is not suitable for scanning.")) + return TRUE + + playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6) + to_chat(user, SPAN_NOTICE("Scanned [target].")) + saved_appearance = target.appearance /obj/item/chameleon/proc/toggle() - if(!can_use || !saved_item) return + + if(!can_use) + to_chat(usr, SPAN_WARNING("\The [src] needs time to recharge!")) + return + + if(!saved_appearance) + to_chat(usr, SPAN_WARNING("\The [src] needs to scan something to mimic first!")) + return + + playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) + var/obj/effect/overlay/T = new(get_turf(src)) + T.icon = 'icons/effects/effects.dmi' + flick("emppulse",T) + QDEL_IN(T, 8) + if(active_dummy) - eject_all() - playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) - qdel(active_dummy) - active_dummy = null - to_chat(usr, "You deactivate the [src].") - var/obj/effect/overlay/T = new /obj/effect/overlay(get_turf(src)) - T.icon = 'icons/effects/effects.dmi' - flick("emppulse",T) - QDEL_IN(T, 8) + active_dummy.dump_contents() + QDEL_NULL(active_dummy) + to_chat(usr, SPAN_NOTICE("You deactivate \the [src].")) else - playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) - var/obj/O = new saved_item(src) - if(!O) return - var/obj/effect/dummy/chameleon/C = new /obj/effect/dummy/chameleon(usr.loc) - C.activate(O, usr, saved_icon, saved_icon_state, saved_overlays, src) - qdel(O) - to_chat(usr, "You activate the [src].") - var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src)) - T.icon = 'icons/effects/effects.dmi' - flick("emppulse",T) - QDEL_IN(T, 8) + active_dummy = new(get_turf(usr), src) + active_dummy.appearance = saved_appearance + to_chat(usr, SPAN_NOTICE("You activate \the [src].")) + usr.forceMove(active_dummy) /obj/item/chameleon/proc/disrupt(var/delete_dummy = 1) - if(active_dummy) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) - spark_system.start() - eject_all() - if(delete_dummy) - qdel(active_dummy) - active_dummy = null - can_use = 0 - spawn(50) can_use = 1 - -/obj/item/chameleon/proc/eject_all() - for(var/atom/movable/A in active_dummy) - A.forceMove(active_dummy.loc) - if(ismob(A)) - var/mob/M = A - M.reset_view(null) + if(!active_dummy) + return + spark_at(loc, amount = 5, cardinal_only = TRUE, holder = src) + active_dummy.dump_contents() + if(delete_dummy) + qdel(active_dummy) + active_dummy = null + can_use = FALSE + addtimer(CALLBACK(src, PROC_REF(reset_can_use)), 5 SECONDS, (TIMER_UNIQUE | TIMER_OVERRIDE)) + +/obj/item/chameleon/proc/reset_can_use() + can_use = TRUE /obj/effect/dummy/chameleon name = "" desc = "" - density = 0 - anchored = 1 - var/can_move = 1 + density = FALSE + anchored = TRUE + is_spawnable_type = FALSE + movement_handlers = list(/datum/movement_handler/delay/chameleon_projector) var/obj/item/chameleon/master = null -/obj/effect/dummy/chameleon/proc/activate(var/obj/O, var/mob/M, new_icon, new_iconstate, new_overlays, var/obj/item/chameleon/C) - name = O.name - desc = O.desc - icon = new_icon - icon_state = new_iconstate - overlays = new_overlays - set_dir(O.dir) - M.forceMove(src) - master = C +/obj/effect/dummy/chameleon/Initialize(mapload, var/obj/item/chameleon/projector) + . = ..() + verbs.Cut() + master = projector + if(!istype(master) || !master.saved_appearance) + master = null + return INITIALIZE_HINT_QDEL + appearance = master.saved_appearance master.active_dummy = src -/obj/effect/dummy/chameleon/attackby() - for(var/mob/M in src) - to_chat(M, "Your chameleon-projector deactivates.") +/obj/effect/dummy/chameleon/Destroy() + if(master) + master.disrupt(FALSE) + master = null + . = ..() + +/obj/effect/dummy/chameleon/proc/disrupted() + for(var/mob/held in src) + to_chat(held, SPAN_DANGER("Your [master.name] deactivates!")) master.disrupt() +/obj/effect/dummy/chameleon/attackby() + disrupted() + return TRUE + /obj/effect/dummy/chameleon/attack_hand() - for(var/mob/M in src) - to_chat(M, "Your chameleon-projector deactivates.") - master.disrupt() + SHOULD_CALL_PARENT(FALSE) + disrupted() + return TRUE /obj/effect/dummy/chameleon/explosion_act() SHOULD_CALL_PARENT(FALSE) - for(var/mob/M in src) - to_chat(M, SPAN_DANGER("Your chameleon-projector deactivates.")) - master.disrupt() + disrupted() /obj/effect/dummy/chameleon/bullet_act() - for(var/mob/M in src) - to_chat(M, "Your chameleon-projector deactivates.") - ..() - master.disrupt() + disrupted() + +// This is not ideal, but the alternative is making the effect simulated. +// As it is, the effect can freely levitate over any open space. +/obj/effect/dummy/chameleon/Move() + . = ..() + if(!. || !isturf(loc) || !loc.has_gravity()) + return + var/turf/my_turf = loc + if(!my_turf.get_supporting_platform() && !(locate(/obj/structure/lattice) in loc)) + disrupted() -/obj/effect/dummy/chameleon/relaymove(var/mob/user, direction) - if(!has_gravity()) - return //No magical space movement! +/datum/movement_handler/delay/chameleon_projector + delay = 2.5 SECONDS - if(can_move) - can_move = 0 - switch(user.bodytemperature) +/datum/movement_handler/delay/chameleon_projector/MayMove(mob/mover, is_external) + return host.loc?.has_gravity() ? ..() : MOVEMENT_STOP + +/datum/movement_handler/delay/chameleon_projector/DoMove(direction, mob/mover, is_external) + if(istype(mover)) + switch(mover.bodytemperature) if(300 to INFINITY) - spawn(10) can_move = 1 + delay = 1 SECOND if(295 to 300) - spawn(13) can_move = 1 + delay = 1.3 SECONDS if(280 to 295) - spawn(16) can_move = 1 + delay = 1.6 SECONDS if(260 to 280) - spawn(20) can_move = 1 + delay = 2 SECONDS else - spawn(25) can_move = 1 - if(isturf(loc)) - step(src, direction) - return - -/obj/effect/dummy/chameleon/Destroy() - master.disrupt(0) - . = ..() + delay = 2.5 SECONDS + else + delay = 2.5 SECONDS + ..() + step(host, direction) + return MOVEMENT_HANDLED diff --git a/code/game/objects/items/devices/debugger.dm b/code/game/objects/items/devices/debugger.dm deleted file mode 100644 index 6adbabbf1e50..000000000000 --- a/code/game/objects/items/devices/debugger.dm +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Multitool -- A multitool is used for hacking electronic devices. - * TO-DO -- Using it as a power measurement tool for cables etc. Nannek. - * - */ - -/obj/item/debugger - name = "debugger" - desc = "Used to debug electronic equipment." - icon = 'icons/obj/hacktool.dmi' - icon_state = "hacktool-g" - obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 - w_class = ITEM_SIZE_SMALL - throwforce = 5.0 - throw_range = 15 - throw_speed = 3 - desc = "You can use this on airlocks or APCs to try to hack them without cutting wires." - - material = /decl/material/solid/plastic - matter = list( - /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE - ) - - origin_tech = "{'magnets':1,'engineering':1}" - var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage - -/obj/item/debugger/is_used_on(obj/O, mob/user) - if(istype(O, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/A = O - if(A.emagged || A.hacker) - to_chat(user, "There is a software error with the device.") - else - to_chat(user, "The device's software appears to be fine.") - return 1 - if(istype(O, /obj/machinery/door)) - var/obj/machinery/door/D = O - if(D.operating == -1) - to_chat(user, "There is a software error with the device.") - else - to_chat(user, "The device's software appears to be fine.") - return 1 - else if(istype(O, /obj/machinery)) - var/obj/machinery/A = O - if(A.emagged) - to_chat(user, "There is a software error with the device.") - else - to_chat(user, "The device's software appears to be fine.") - return 1 diff --git a/code/game/objects/items/devices/dociler.dm b/code/game/objects/items/devices/dociler.dm index 715b48f9af0d..6e66017549c6 100644 --- a/code/game/objects/items/devices/dociler.dm +++ b/code/game/objects/items/devices/dociler.dm @@ -2,16 +2,18 @@ name = "dociler" desc = "A complex single use recharging injector that spreads a complex neurological serum that makes animals docile and friendly. Somewhat." w_class = ITEM_SIZE_NORMAL - origin_tech = "{'biotech':5,'materials':2}" + origin_tech = @'{"biotech":5,"materials":2}' icon = 'icons/obj/items/device/animal_tagger.dmi' icon_state = ICON_STATE_WORLD - force = 1 + _base_attack_force = 1 + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT) var/loaded = 1 var/mode = "completely" -/obj/item/dociler/examine(mob/user) +/obj/item/dociler/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It is currently set to [mode] docile mode.") + . += SPAN_NOTICE("It is currently set to '[mode] docile' mode.") /obj/item/dociler/attack_self(var/mob/user) if(mode == "somewhat") @@ -21,35 +23,35 @@ to_chat(user, "You set \the [src] to [mode] docile mode.") -/obj/item/dociler/attack(var/mob/living/L, var/mob/user) - if(!istype(L, /mob/living/simple_animal)) - to_chat(user, "\The [src] cannot not work on \the [L].") - return +/obj/item/dociler/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(!isanimal(target)) + to_chat(user, SPAN_WARNING("\The [src] cannot not work on \the [target].")) + return TRUE if(!loaded) - to_chat(user, "\The [src] isn't loaded!") - return + to_chat(user, SPAN_WARNING("\The [src] isn't loaded!")) + return TRUE - user.visible_message("\The [user] thrusts \the [src] deep into \the [L]'s head, injecting something!") - to_chat(L, "You feel pain as \the [user] injects something into you. All of a sudden you feel as if [user] is the friendliest and nicest person you've ever know. You want to be friends with him and all his friends.") + user.visible_message("\The [user] stabs \the [src] into \the [target], injecting something!") + var/decl/pronouns/pronouns = user.get_pronouns() + to_chat(target, SPAN_NOTICE("You feel a stabbing pain as \the [user] injects something into you. All of a sudden you feel as if [user] is the friendliest and nicest person you've ever know. You want to be friends with [pronouns.him] and all [pronouns.his] friends.")) if(mode == "somewhat") - L.faction = user.faction + target.faction = user.faction else - L.faction = null - if(istype(L,/mob/living/simple_animal/hostile)) - var/mob/living/simple_animal/hostile/H = L - H.LoseTarget() - H.attack_same = 0 - H.friends += weakref(user) - L.desc += "
              It looks especially docile." - var/name = input(user, "Would you like to rename \the [L]?", "Dociler", L.name) as text + target.faction = null + target.ai?.pacify(user) + target.desc += "
              It looks especially docile." + var/name = input(user, "Would you like to rename \the [target]?", "Dociler", target.name) as text if(length(name)) - L.real_name = name - L.SetName(name) + target.real_name = name + target.SetName(name) - loaded = 0 + loaded = FALSE icon_state = get_world_inventory_state() - spawn(1450) - loaded = 1 + spawn(2.5 MINUTES) + loaded = TRUE icon_state = "[icon_state]-charged" - src.visible_message("\The [src] beeps, refilling itself.") \ No newline at end of file + src.visible_message("\The [src] beeps, refilling itself.") + + return TRUE \ No newline at end of file diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index c0759b1cf5c8..394ecbeecc73 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -2,14 +2,12 @@ name = "flash" desc = "A device that produces a bright flash of light, designed to stun and disorient an attacker." icon = 'icons/obj/items/device/flash.dmi' - icon_state = "flash" - item_state = "flashtool" - throwforce = 5 + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL throw_speed = 4 throw_range = 10 obj_flags = OBJ_FLAG_CONDUCTIBLE - origin_tech = "{'magnets':2,'combat':1}" + origin_tech = @'{"magnets":2,"combat":1}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) @@ -19,10 +17,16 @@ var/str_min = 2 //how weak the effect CAN be var/str_max = 7 //how powerful the effect COULD be +/obj/item/flash/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(broken) + icon_state = "[icon_state]-burnt" + /obj/item/flash/proc/clown_check(var/mob/user) - if(user && (MUTATION_CLUMSY in user.mutations) && prob(50)) + if(user && user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) to_chat(user, "\The [src] slips out of your hand.") - user.unequip_item() + user.try_unequip(src) return 0 return 1 @@ -36,184 +40,92 @@ last_used = world.time times_used = max(0,round(times_used)) //sanity -//attack_as_weapon -/obj/item/flash/attack(mob/living/M, mob/living/user, var/target_zone) - if(!user || !M) return 0 //sanity - admin_attack_log(user, M, "flashed their victim using \a [src].", "Was flashed by \a [src].", "used \a [src] to flash") +/obj/item/flash/proc/do_flash_animation(var/mob/user, var/mob/target) + if(user) + if(target) + user.do_attack_animation(target) + user.do_flash_animation() + playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + flick("[initial(icon_state)]-on", src) - if(!clown_check(user)) return 0 - if(broken) - to_chat(user, "\The [src] is broken.") - return 0 +/obj/item/flash/proc/check_usability(var/mob/user) + + if(times_used > 5) + if(user) + to_chat(user, SPAN_WARNING("*click* *click*")) + return FALSE + last_used = world.time + times_used++ + if(times_used > 1 && prob(times_used)) //if you use it 5 times in a minute it has a 10% chance to break! + broken = TRUE + if(user) + to_chat(user, SPAN_WARNING("The bulb has burnt out!")) + icon_state = "[initial(icon_state)]-burnt" + return FALSE + + return TRUE + +/obj/item/flash/proc/general_flash_check(var/mob/user) + if(!clown_check(user)) + return FALSE + if(broken) + if(user) + to_chat(user, SPAN_WARNING("\The [src] is broken.")) + return FALSE flash_recharge() + if(!check_usability(user)) + return FALSE + return TRUE - //spamming the flash before it's fully charged (60seconds) increases the chance of it breaking - //It will never break on the first use. - switch(times_used) - if(0 to 5) - last_used = world.time - if(prob(times_used)) //if you use it 5 times in a minute it has a 10% chance to break! - broken = 1 - to_chat(user, "The bulb has burnt out!") - icon_state = "[initial(icon_state)]_burnt" - return 0 - times_used++ - else //can only use it 5 times a minute - to_chat(user, "*click* *click*") - return 0 +//attack_as_weapon +/obj/item/flash/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) + if(!user || !target || !general_flash_check(user)) + return FALSE - playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) - var/flashfail = 0 - var/flash_strength = (rand(str_min,str_max)) - - if(iscarbon(M)) - if(M.stat!=DEAD) - var/mob/living/carbon/C = M - var/safety = C.eyecheck() - if(safety < FLASH_PROTECTION_MODERATE) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - flash_strength = round(H.getFlashMod() * flash_strength) - if(safety > FLASH_PROTECTION_NONE) - flash_strength = (flash_strength / 2) - if(flash_strength > 0) - M.flash_eyes(FLASH_PROTECTION_MODERATE - safety) - M.Stun(flash_strength / 2) - M.eye_blurry += flash_strength - M.confused += (flash_strength + 2) - if(flash_strength > 3) - M.drop_l_hand() - M.drop_r_hand() - if(flash_strength > 5) - M.Weaken(2) - else - flashfail = 1 - - else if(isanimal(M)) - var/mob/living/simple_animal/SA = M - var/safety = SA.eyecheck() - if(safety < FLASH_PROTECTION_MAJOR) - SA.Weaken(2) - if(safety < FLASH_PROTECTION_MODERATE) - SA.Stun(flash_strength - 2) - SA.flash_eyes(2) - SA.eye_blurry += flash_strength - SA.confused += flash_strength - else - flashfail = 1 - - else if(issilicon(M)) - M.Weaken(rand(str_min,6)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + do_flash_animation(user, target) - else - flashfail = 1 - - if(isrobot(user)) - spawn(0) - var/atom/movable/overlay/animation = new(user) - animation.plane = user.plane - animation.layer = user.layer + 0.01 - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - flick("blspell", animation) - sleep(5) - qdel(animation) - - if(!flashfail) - flick("[initial(icon_state)]_on", src) - if(!issilicon(M)) - user.visible_message("[user] blinds [M] with \the [src]!") + if(target.stat != DEAD && target.handle_flashed(rand(str_min,str_max))) + admin_attack_log(user, target, "flashed their victim using \a [src].", "Was flashed by \a [src].", "used \a [src] to flash") + if(!target.isSynthetic()) + user.visible_message(SPAN_DANGER("\The [user] blinds \the [target] with \the [src]!")) else - user.visible_message("[user] overloads [M]'s sensors with \the [src]!") + user.visible_message(SPAN_DANGER("\The [user] overloads \the [target]'s sensors with \the [src]!")) else - user.visible_message("[user] fails to blind [M] with \the [src]!") - return 1 - - - + user.visible_message(SPAN_WARNING("\The [user] fails to blind \the [target] with \the [src]!")) + return TRUE -/obj/item/flash/attack_self(mob/living/carbon/user, flag = 0, emp = 0) - if(!user || !clown_check(user)) return 0 - - if(broken) - user.show_message("The [src.name] is broken", 2) - return 0 +/obj/item/flash/attack_self(mob/user, flag = 0, emp = 0) + if(!user || !general_flash_check(user)) + return FALSE - flash_recharge() - - //spamming the flash before it's fully charged (60seconds) increases the chance of it breaking - //It will never break on the first use. - switch(times_used) - if(0 to 5) - if(prob(2*times_used)) //if you use it 5 times in a minute it has a 10% chance to break! - broken = 1 - to_chat(user, "The bulb has burnt out!") - icon_state = "[initial(icon_state)]_burnt" - return 0 - times_used++ - else //can only use it 5 times a minute - user.show_message("*click* *click*", 2) - return 0 user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) - flick("[initial(icon_state)]_on", src) - if(user && isrobot(user)) - spawn(0) - var/atom/movable/overlay/animation = new(user.loc) - animation.plane = user.plane - animation.layer = user.layer + 0.01 - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = user - flick("blspell", animation) - sleep(5) - qdel(animation) - - for(var/mob/living/carbon/M in oviewers(3, null)) - var/safety = M.eyecheck() - if(safety < FLASH_PROTECTION_MODERATE) - if(!M.blinded) - M.flash_eyes() - M.eye_blurry += 2 - - return 1 + do_flash_animation(user) + for(var/mob/living/M in oviewers(3, null)) + M.handle_flashed(rand(str_min,str_max)) + return TRUE /obj/item/flash/emp_act(severity) - if(broken) return - flash_recharge() - switch(times_used) - if(0 to 5) - if(prob(2*times_used)) - broken = 1 - icon_state = "[initial(icon_state)]_burnt" - return - times_used++ - if(istype(loc, /mob/living/carbon)) - var/mob/living/carbon/M = loc - var/safety = M.eyecheck() - if(safety < FLASH_PROTECTION_MODERATE) - M.Weaken(10) - M.flash_eyes() - for(var/mob/O in viewers(M, null)) - O.show_message("[M] is blinded by the [name]!") - ..() + if(broken || !general_flash_check()) + return FALSE + do_flash_animation() + for(var/mob/living/M in oviewers(3, null)) + M.handle_flashed(rand(str_min,str_max)) /obj/item/flash/synthetic //not for regular use, weaker effects name = "modified flash" desc = "A device that produces a bright flash of light. This is a specialized version designed specifically for use in camera systems." - icon_state = "sflash" + icon = 'icons/obj/items/device/flash_synthetic.dmi' str_min = 1 str_max = 4 /obj/item/flash/advanced name = "advanced flash" desc = "A device that produces a very bright flash of light. This is an advanced and expensive version often issued to VIPs." - icon_state = "advflash" - origin_tech = "{'combat':2,'magnets':2}" + icon = 'icons/obj/items/device/flash_advanced.dmi' + origin_tech = @'{"combat":2,"magnets":2}' str_min = 3 str_max = 8 material = /decl/material/solid/metal/steel diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm deleted file mode 100644 index 52bb8bb75804..000000000000 --- a/code/game/objects/items/devices/flashlight.dm +++ /dev/null @@ -1,475 +0,0 @@ -#define FLASHLIGHT_ALWAYS_ON 1 -#define FLASHLIGHT_SINGLE_USE 2 - -/obj/item/flashlight - name = "flashlight" - desc = "A hand-held emergency light." - icon = 'icons/obj/lighting.dmi' - icon_state = "flashlight" - item_state = "flashlight" - w_class = ITEM_SIZE_SMALL - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - - material = /decl/material/solid/plastic - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - - action_button_name = "Toggle Flashlight" - var/on = FALSE - var/activation_sound = 'sound/effects/flashlight.ogg' - var/flashlight_max_bright = 0.5 //brightness of light when on, must be no greater than 1. - var/flashlight_inner_range = 1 //inner range of light when on, can be negative - var/flashlight_outer_range = 3 //outer range of light when on, can be negative - var/flashlight_flags = 0 // FLASHLIGHT_ bitflags - -/obj/item/flashlight/Initialize() - . = ..() - - set_flashlight() - update_icon() - -/obj/item/flashlight/on_update_icon() - if (flashlight_flags & FLASHLIGHT_ALWAYS_ON) - return // Prevent update_icon shennanigans with objects that won't have on/off variant sprites - - if(on) - icon_state = "[initial(icon_state)]-on" - else - icon_state = "[initial(icon_state)]" - -/obj/item/flashlight/attack_self(mob/user) - if (flashlight_flags & FLASHLIGHT_ALWAYS_ON) - to_chat(user, "You cannot toggle the [name].") - return 0 - - if(!isturf(user.loc)) - to_chat(user, "You cannot turn the [name] on while in this [user.loc].")//To prevent some lighting anomalities. - return 0 - - if (flashlight_flags & FLASHLIGHT_SINGLE_USE && on) - to_chat(user, "The [name] is already lit.") - return 0 - - on = !on - if(on && activation_sound) - playsound(get_turf(src), activation_sound, 75, 1) - set_flashlight() - update_icon() - user.update_action_buttons() - return 1 - -/obj/item/flashlight/proc/set_flashlight() - if (on) - set_light(flashlight_max_bright, flashlight_inner_range, flashlight_outer_range, 2, light_color) - else - set_light(0) - -/obj/item/flashlight/attack(mob/living/M, mob/living/user) - add_fingerprint(user) - if(on && user.zone_sel.selecting == BP_EYES) - - if((MUTATION_CLUMSY in user.mutations) && prob(50)) //too dumb to use flashlight properly - return ..() //just hit them in the head - - var/mob/living/carbon/human/H = M //mob has protective eyewear - if(istype(H)) - for(var/obj/item/clothing/C in list(H.head,H.wear_mask,H.glasses)) - if(istype(C) && (C.body_parts_covered & EYES)) - to_chat(user, "You're going to need to remove [C] first.") - return - - var/obj/item/organ/vision - if(!H.species.vision_organ || !H.should_have_organ(H.species.vision_organ)) - to_chat(user, "You can't find anything on [H] to direct [src] into!") - return - - vision = H.internal_organs_by_name[H.species.vision_organ] - if(!vision) - vision = H.species.has_organ[H.species.vision_organ] - to_chat(user, "\The [H] is missing \his [initial(vision.name)]!") - return - - user.visible_message("\The [user] directs [src] into [M]'s [vision.name].", \ - "You direct [src] into [M]'s [vision.name].") - - inspect_vision(vision, user) - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively - M.flash_eyes() - else - return ..() - -/obj/item/flashlight/proc/inspect_vision(obj/item/organ/vision, mob/living/user) - var/mob/living/carbon/human/H = vision.owner - - if(H == user) //can't look into your own eyes buster - return - - if(!BP_IS_PROSTHETIC(vision)) - - if(vision.owner.stat == DEAD || H.blinded) //mob is dead or fully blind - to_chat(user, "\The [H]'s pupils do not react to the light!") - return - if(MUTATION_XRAY in H.mutations) - to_chat(user, "\The [H]'s pupils give an eerie glow!") - if(vision.damage) - to_chat(user, "There's visible damage to [H]'s [vision.name]!") - else if(H.eye_blurry) - to_chat(user, "\The [H]'s pupils react slower than normally.") - if(H.getBrainLoss() > 15) - to_chat(user, "There's visible lag between left and right pupils' reactions.") - - var/list/pinpoint = list(/decl/material/liquid/painkillers=5,/decl/material/liquid/amphetamines=1) - var/list/dilating = list(/decl/material/liquid/psychoactives=5,/decl/material/liquid/hallucinogenics=1,/decl/material/liquid/adrenaline=1) - var/datum/reagents/ingested = H.get_ingested_reagents() - if(H.reagents.has_any_reagent(pinpoint) || ingested.has_any_reagent(pinpoint)) - to_chat(user, "\The [H]'s pupils are already pinpoint and cannot narrow any more.") - else if(H.shock_stage >= 30 || H.reagents.has_any_reagent(dilating) || ingested.has_any_reagent(dilating)) - to_chat(user, "\The [H]'s pupils narrow slightly, but are still very dilated.") - else - to_chat(user, "\The [H]'s pupils narrow.") - - //if someone wants to implement inspecting robot eyes here would be the place to do it. - -/obj/item/flashlight/upgraded - name = "\improper LED flashlight" - desc = "An energy efficient flashlight." - icon_state = "biglight" - item_state = "biglight" - flashlight_max_bright = 0.75 - flashlight_outer_range = 4 - -/obj/item/flashlight/flashdark - name = "flashdark" - desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure." - icon_state = "flashdark" - item_state = "flashdark" - w_class = ITEM_SIZE_NORMAL - flashlight_max_bright = -1 - flashlight_outer_range = 4 - flashlight_inner_range = 1 - -/obj/item/flashlight/pen - name = "penlight" - desc = "A pen-sized light, used by medical staff." - icon_state = "penlight" - item_state = "" - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_EARS - w_class = ITEM_SIZE_TINY - flashlight_max_bright = 0.25 - flashlight_inner_range = 0.1 - flashlight_outer_range = 2 - -/obj/item/flashlight/maglight - name = "maglight" - desc = "A very, very heavy duty flashlight." - icon_state = "maglight" - item_state = "maglight" - force = 10 - attack_verb = list ("smacked", "thwacked", "thunked") - material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - flashlight_max_bright = 0.5 - flashlight_outer_range = 5 - -/******************************Lantern*******************************/ -/obj/item/flashlight/lantern - name = "lantern" - desc = "A mining lantern." - icon = 'icons/obj/lighting.dmi' - icon_state = "lantern" - item_state = "lantern" - force = 10 - attack_verb = list ("bludgeoned", "bashed", "whack") - w_class = ITEM_SIZE_NORMAL - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - flashlight_outer_range = 5 - -/obj/item/flashlight/lantern/on_update_icon() - ..() - if(on) - item_state = "lantern-on" - else - item_state = "lantern" - -/******************************Lantern*******************************/ - -/obj/item/flashlight/drone - name = "low-power flashlight" - desc = "A miniature lamp, that might be used by small robots." - icon_state = "penlight" - item_state = "" - obj_flags = OBJ_FLAG_CONDUCTIBLE - w_class = ITEM_SIZE_TINY - flashlight_max_bright = 0.25 - flashlight_inner_range = 0.1 - flashlight_outer_range = 2 - - -// the desk lamps are a bit special -/obj/item/flashlight/lamp - name = "desk lamp" - desc = "A desk lamp with an adjustable mount." - icon_state = "lamp" - item_state = "lamp" - w_class = ITEM_SIZE_LARGE - obj_flags = OBJ_FLAG_CONDUCTIBLE - flashlight_max_bright = 0.3 - flashlight_inner_range = 2 - flashlight_outer_range = 5 - - on = 1 - -// green-shaded desk lamp -/obj/item/flashlight/lamp/green - desc = "A classic green-shaded desk lamp." - icon_state = "lampgreen" - item_state = "lampgreen" - light_color = "#ffc58f" - -/obj/item/flashlight/lamp/verb/toggle_light() - set name = "Toggle light" - set category = "Object" - set src in oview(1) - - if(!usr.stat) - attack_self(usr) - -// FLARES - -/obj/item/flashlight/flare - name = "flare" - desc = "A red standard-issue flare. There are instructions on the side reading 'pull cord, make light'." - w_class = ITEM_SIZE_TINY - light_color = "#e58775" - icon_state = "flare" - item_state = "flare" - action_button_name = null //just pull it manually, neckbeard. - var/fuel = 0 - var/on_damage = 7 - var/produce_heat = 1500 - activation_sound = 'sound/effects/flare.ogg' - flashlight_flags = FLASHLIGHT_SINGLE_USE - - flashlight_max_bright = 0.8 - flashlight_inner_range = 0.1 - flashlight_outer_range = 5 - -/obj/item/flashlight/flare/Initialize() - . = ..() - fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.v - update_icon() - -/obj/item/flashlight/flare/Destroy() - . = ..() - STOP_PROCESSING(SSobj, src) - -/obj/item/flashlight/flare/Process() - if(produce_heat) - var/turf/T = get_turf(src) - if(T) - T.hotspot_expose(produce_heat, 5) - fuel = max(fuel - 1, 0) - if (fuel <= 0) - on = FALSE - if(!on) - update_damage() - set_flashlight() - update_icon() - STOP_PROCESSING(SSobj, src) - -/obj/item/flashlight/flare/attack_self(var/mob/user) - if(fuel <= 0) - to_chat(user,"\The [src] is spent.") - return 0 - - . = ..() - - if(.) - activate(user) - update_damage() - set_flashlight() - update_icon() - START_PROCESSING(SSobj, src) - -/obj/item/flashlight/flare/afterattack(var/obj/O, var/mob/user, var/proximity) - if(proximity && istype(O) && on) - O.HandleObjectHeating(src, user, 500) - ..() - -/obj/item/flashlight/flare/proc/activate(var/mob/user) - if(istype(user)) - user.visible_message("[user] pulls the cord on \the [src], activating it.", "You pull the cord on \the [src], activating it!") - -/obj/item/flashlight/flare/proc/update_damage() - if(on) - force = on_damage - damtype = BURN - else - force = initial(force) - damtype = initial(damtype) - -/obj/item/flashlight/flare/on_update_icon() - ..() - if(!on && fuel <= 0) - icon_state = "[initial(icon_state)]-empty" - -//Glowsticks -/obj/item/flashlight/flare/glowstick - name = "green glowstick" - desc = "A military-grade glowstick." - w_class = ITEM_SIZE_SMALL - color = "#49f37c" - icon_state = "glowstick" - item_state = "glowstick" - randpixel = 12 - produce_heat = 0 - activation_sound = 'sound/effects/glowstick.ogg' - - flashlight_max_bright = 0.6 - flashlight_inner_range = 0.1 - flashlight_outer_range = 3 - -/obj/item/flashlight/flare/glowstick/Initialize() - . = ..() - fuel = rand(1600, 2000) - light_color = color - -/obj/item/flashlight/flare/glowstick/on_update_icon() - item_state = "glowstick" - overlays.Cut() - if(fuel <= 0) - icon_state = "glowstick-empty" - on = FALSE - else if (on) - var/image/I = overlay_image(icon,"glowstick-on",color) - I.blend_mode = BLEND_ADD - overlays += I - item_state = "glowstick-on" - else - icon_state = "glowstick" - var/mob/M = loc - if(istype(M)) - if(M.l_hand == src) - M.update_inv_l_hand() - if(M.r_hand == src) - M.update_inv_r_hand() - -/obj/item/flashlight/flare/glowstick/activate(var/mob/user) - if(istype(user)) - user.visible_message("[user] cracks and shakes \the [src].", "You crack and shake \the [src], turning it on!") - -/obj/item/flashlight/flare/glowstick/red - name = "red glowstick" - color = "#fc0f29" - -/obj/item/flashlight/flare/glowstick/blue - name = "blue glowstick" - color = "#599dff" - -/obj/item/flashlight/flare/glowstick/orange - name = "orange glowstick" - color = "#fa7c0b" - -/obj/item/flashlight/flare/glowstick/yellow - name = "yellow glowstick" - color = "#fef923" - -/obj/item/flashlight/flare/glowstick/random - name = "glowstick" - desc = "A party-grade glowstick." - color = "#ff00ff" - -/obj/item/flashlight/flare/glowstick/random/Initialize() - color = rgb(rand(50,255),rand(50,255),rand(50,255)) - . = ..() - -/obj/item/flashlight/slime - gender = PLURAL - name = "glowing slime extract" - desc = "A glowing ball of what appears to be amber." - icon = 'icons/obj/lighting.dmi' - icon_state = "floor1" //not a slime extract sprite but... something close enough! - item_state = "slime" - w_class = ITEM_SIZE_TINY - on = TRUE //Bio-luminesence has one setting, on. - flashlight_flags = FLASHLIGHT_ALWAYS_ON - - flashlight_max_bright = 1 - flashlight_inner_range = 0.1 - flashlight_outer_range = 5 - -//hand portable floodlights for emergencies. Less bulky than the large ones. But also less light. Unused green variant in the sheet. - -/obj/item/flashlight/lamp/floodlamp - name = "flood lamp" - desc = "A portable emergency flood light with a ultra-bright LED." - icon = 'icons/obj/machines/floodlight.dmi' - icon_state = "floodlamp" - item_state = "lamp" - on = 0 - w_class = ITEM_SIZE_LARGE - obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_ROTATABLE - - flashlight_max_bright = 1 - flashlight_inner_range = 3 - flashlight_outer_range = 7 - -/obj/item/flashlight/lamp/floodlamp/green - icon_state = "greenfloodlamp" - -//Lava Lamps: Because we're already stuck in the 70ies with those fax machines. -/obj/item/flashlight/lamp/lava - name = "lava lamp" - desc = "A kitchy throwback decorative light. Noir Edition." - icon = 'icons/obj/lighting.dmi' - icon_state = "lavalamp" - on = 0 - action_button_name = "Toggle lamp" - flashlight_outer_range = 3 //range of light when on - material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - -/obj/item/flashlight/lamp/lava/on_update_icon() - overlays.Cut() - var/image/I = image(icon = icon, icon_state = "lavalamp-[on ? "on" : "off"]") - I.color = light_color - overlays += I - -/obj/item/flashlight/lamp/lava/red - desc = "A kitchy red decorative light." - light_color = COLOR_RED - -/obj/item/flashlight/lamp/lava/blue - desc = "A kitchy blue decorative light" - light_color = COLOR_BLUE - -/obj/item/flashlight/lamp/lava/cyan - desc = "A kitchy cyan decorative light" - light_color = COLOR_CYAN - -/obj/item/flashlight/lamp/lava/green - desc = "A kitchy green decorative light" - light_color = COLOR_GREEN - -/obj/item/flashlight/lamp/lava/orange - desc = "A kitchy orange decorative light" - light_color = COLOR_ORANGE - -/obj/item/flashlight/lamp/lava/purple - desc = "A kitchy purple decorative light" - light_color = COLOR_PURPLE -/obj/item/flashlight/lamp/lava/pink - desc = "A kitchy pink decorative light" - light_color = COLOR_PINK - -/obj/item/flashlight/lamp/lava/yellow - desc = "A kitchy yellow decorative light" - light_color = COLOR_YELLOW - -#undef FLASHLIGHT_ALWAYS_ON -#undef FLASHLIGHT_SINGLE_USE diff --git a/code/game/objects/items/devices/geiger.dm b/code/game/objects/items/devices/geiger.dm index 4b3ce95fb23d..75ed00418bac 100644 --- a/code/game/objects/items/devices/geiger.dm +++ b/code/game/objects/items/devices/geiger.dm @@ -12,6 +12,13 @@ item_state = "multitool" w_class = ITEM_SIZE_SMALL action_button_name = "Toggle geiger counter" + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + ) var/scanning = 0 var/radiation_count = 0 var/datum/sound_token/sound_token @@ -24,7 +31,7 @@ /obj/item/geiger/proc/update_sound(var/playing) if(playing && !sound_token) - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, "sound/items/geiger.ogg", volume = geiger_volume, range = 4, falloff = 3, prefer_mute = TRUE) + sound_token = play_looping_sound(src, sound_id, "sound/items/geiger.ogg", volume = geiger_volume, range = 4, falloff = 3, prefer_mute = TRUE) else if(!playing && sound_token) QDEL_NULL(sound_token) @@ -39,13 +46,13 @@ radiation_count = SSradiation.get_rads_at_turf(get_turf(src)) update_icon() -/obj/item/geiger/examine(mob/user) +/obj/item/geiger/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/msg = "[scanning ? "ambient" : "stored"] Radiation level: [radiation_count ? radiation_count : "0"] Roentgen." if(radiation_count > RAD_LEVEL_LOW) - to_chat(user, "[msg]") + . += SPAN_DANGER("[msg]") else - to_chat(user, "[msg]") + . += SPAN_NOTICE("[msg]") /obj/item/geiger/attack_self(var/mob/user) scanning = !scanning @@ -54,9 +61,10 @@ else STOP_PROCESSING(SSobj, src) update_icon() - to_chat(user, "\icon[src] You switch [scanning ? "on" : "off"] [src].") + to_chat(user, "[html_icon(src)] You switch [scanning ? "on" : "off"] [src].") /obj/item/geiger/on_update_icon() + . = ..() if(!scanning) icon_state = "geiger_off" update_sound(0) diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index aa011de64900..fa29f4316653 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -1,36 +1,468 @@ +var/global/list/all_gps_units = list() /obj/item/gps - name = "relay positioning device" - desc = "Triangulates the approximate co-ordinates using a nearby satellite network." + name = "global positioning system" + base_name = "global positioning system" + desc = "A handheld relay used to triangulate the approximate coordinates of the device in spacetime." icon = 'icons/obj/items/device/locator.dmi' - icon_state = "locator" - item_state = "locator" - origin_tech = "{'materials':2,'programming':2,'wormholes':2}" + icon_state = ICON_STATE_WORLD + origin_tech = @'{"materials":2,"programming":2,"wormholes":2}' material = /decl/material/solid/metal/aluminium matter = list( /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE ) w_class = ITEM_SIZE_SMALL - material = /decl/material/solid/metal/aluminium - matter = list( - /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE - ) + color = "#6a6a6a" + + var/screen_color = "#d98736" + var/decal_icon = 'icons/obj/items/device/locator_overlays.dmi' + var/gps_tag = "GEN0" + var/emped = FALSE + var/tracking = FALSE // Will not show other signals or emit its own signal if false. + var/long_range = FALSE // If true, can see farther, depending on get_map_levels(). + var/local_mode = FALSE // If true, only GPS signals of the same Z level are shown. + var/hide_signal = FALSE // If true, signal is not visible to other GPS devices. + var/can_hide_signal = FALSE // If it can toggle the above var. + var/is_special_gps_marker = FALSE // How the GPS marker should be handled. + + var/tag_category // Any special category for this tracker to sit in (used by xenofauna tags) + var/list/tag_categories // Any special categories this tracker should show (used in xenofauna GPS) + + var/mob/holder + var/is_in_processing_list = FALSE + var/list/tracking_devices + var/list/showing_tracked_names + VAR_PRIVATE/obj/compass_holder/_compass + var/list/decals + + +/obj/item/gps/Initialize() + global.all_gps_units += src + . = ..() + events_repository.register(/decl/observ/moved, src, src, PROC_REF(update_holder)) + create_compass() + update_holder() + update_icon() + update_name() + +/obj/item/gps/proc/set_gps_tag(_tag) + _tag = sanitize(_tag) + if(istext(_tag) && length(_tag) > 0 && gps_tag != _tag) + gps_tag = _tag + update_name() -/obj/item/gps/attack_self(var/mob/user) - to_chat(user, "\icon[src] \The [src] flashes [get_coordinates()].") +/obj/item/gps/update_name() + . = ..() + if(gps_tag) + SetName("[base_name] ([gps_tag])") -/obj/item/gps/examine(mob/user) +/obj/item/gps/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "\The [src]'s screen shows: [get_coordinates()].") + if(distance <= 1) + . += SPAN_NOTICE("\The [src]'s screen shows: [get_coordinates()].") /obj/item/gps/proc/get_coordinates() var/turf/T = get_turf(src) return T ? "[T.x]:[T.y]:[T.z]" : "N/A" -/mob/living/carbon/human/Stat() +/obj/item/gps/proc/check_visible_to_holder() + . = holder && (src in holder.get_held_items()) + +/obj/item/gps/proc/update_holder(var/force_clear = FALSE) + + var/decl/observ/moved/moved_event = GET_DECL(/decl/observ/moved) + var/decl/observ/dir_set/dir_set_event = GET_DECL(/decl/observ/dir_set) + + if(holder && (force_clear || loc != holder)) + moved_event.unregister(holder, src) + dir_set_event.unregister(holder, src) + if(_compass) + holder.client?.screen -= _compass + holder = null + + if(!force_clear && ismob(loc)) + holder = loc + moved_event.register(holder, src, PROC_REF(update_compass)) + dir_set_event.register(holder, src, PROC_REF(update_compass)) + + if(!force_clear && holder && tracking) + if(!is_in_processing_list) + START_PROCESSING(SSobj, src) + is_in_processing_list = TRUE + if(holder.client && _compass) + if(check_visible_to_holder()) + holder.client.screen |= _compass + else + holder.client.screen -= _compass + else + STOP_PROCESSING(SSobj, src) + is_in_processing_list = FALSE + if(holder?.client && _compass) + holder.client.screen -= _compass + +/obj/item/gps/equipped_robot() + . = ..() + update_holder() + +/obj/item/gps/equipped() + . = ..() + update_holder() + +/obj/item/gps/Process() + if(!tracking) + is_in_processing_list = FALSE + return PROCESS_KILL + update_holder() + if(holder) + update_compass(TRUE) + +/obj/item/gps/Destroy() + STOP_PROCESSING(SSobj, src) + is_in_processing_list = FALSE + global.all_gps_units -= src + events_repository.unregister(/decl/observ/moved, src, src, PROC_REF(update_holder)) + update_holder(force_clear = TRUE) + QDEL_NULL(_compass) + return ..() + +/obj/item/gps/proc/can_track(var/obj/item/gps/other, var/reachable_z_levels) + if(!other.tracking || other.emped || other.hide_signal || (other.tag_category && !(other.tag_category in tag_categories))) + return FALSE + var/turf/origin = get_turf(src) + var/turf/target = get_turf(other) + if(!istype(origin) || !istype(target)) + return FALSE + if(origin.z == target.z) + return TRUE + if(local_mode) + return FALSE + + var/list/adding_sites + if(long_range) + adding_sites = (SSmapping.station_levels|SSmapping.contact_levels|SSmapping.player_levels) + else + adding_sites = SSmapping.get_connected_levels(origin.z) + + if(LAZYLEN(adding_sites)) + LAZYDISTINCTADD(reachable_z_levels, adding_sites) + return (target.z in reachable_z_levels) + +/obj/item/gps/proc/create_compass() + _compass ||= new(src) + +/obj/item/gps/proc/update_compass(var/update_compass_icon) + + _compass?.hide_waypoints(FALSE) + + var/turf/my_turf = get_turf(src) + for(var/thing in tracking_devices) + var/obj/item/gps/gps = locate(thing) + if(!istype(gps) || QDELETED(gps)) + LAZYREMOVE(tracking_devices, thing) + LAZYREMOVE(showing_tracked_names, thing) + continue + + if(_compass) + var/turf/gps_turf = get_turf(gps) + var/use_gps_tag = LAZYACCESS(showing_tracked_names, thing) ? gps.gps_tag : null + if(istype(gps_turf)) + _compass.set_waypoint("\ref[gps]", use_gps_tag, gps_turf.x, gps_turf.y, gps_turf.z, LAZYACCESS(tracking_devices, "\ref[gps]")) + if(can_track(gps) && my_turf && gps_turf != my_turf) + _compass.show_waypoint("\ref[gps]") + + _compass?.rebuild_overlay_lists(update_compass_icon) + +/obj/item/gps/proc/toggle_tracking(var/mob/user, var/silent) + + if(emped) + if(!silent) + to_chat(user, SPAN_WARNING("\The [src] is busted!")) + return FALSE + + tracking = !tracking + if(tracking) + if(!is_in_processing_list) + is_in_processing_list = TRUE + START_PROCESSING(SSobj, src) + else + is_in_processing_list = FALSE + STOP_PROCESSING(SSobj, src) + + if(!silent) + if(tracking) + to_chat(user, SPAN_NOTICE("\The [src] is now tracking, and visible to other GPS devices.")) + else + to_chat(user, SPAN_NOTICE("\The [src] is no longer tracking, or visible to other GPS devices.")) + + update_compass() + update_holder() + update_icon() + +/obj/item/gps/emp_act(severity) + if(emped) // Without a fancy callback system, this will have to do. + return + if(tracking) + toggle_tracking(silent = TRUE) + var/severity_modifier = severity ? severity : 4 // In case emp_act gets called without any arguments. + var/duration = 5 MINUTES / severity_modifier + emped = TRUE + update_icon() + addtimer(CALLBACK(src, PROC_REF(reset_emp)), duration) + +/obj/item/gps/proc/reset_emp() + emped = FALSE + update_icon() + if(ismob(loc)) + to_chat(loc, SPAN_NOTICE("\The [src] appears to be functional again.")) + +/obj/item/gps/on_update_icon() . = ..() - if(statpanel("Status")) - var/obj/item/gps/L = locate() in src - if(L) - stat("Coordinates:", "[L.get_coordinates()]") + + var/image/I + for(var/decal in decals) + if(check_state_in_icon(decal, decal_icon)) + I = image(decal_icon, decal) + I.color = decals[decal] + I.appearance_flags |= RESET_COLOR + add_overlay(I) + + if(screen_color && check_state_in_icon("[icon_state]-keypad", decal_icon)) + I = image(decal_icon, "[icon_state]-keypad") + I.color = screen_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + + if(emped) + if(check_state_in_icon("[icon_state]-emp", decal_icon)) + I = image(decal_icon, "[icon_state]-emp") + I.color = screen_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + else if(tracking) + if(check_state_in_icon("[icon_state]-working", decal_icon)) + I = image(decal_icon, "[icon_state]-working") + I.color = screen_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + else if(check_state_in_icon("[icon_state]-screen", decal_icon)) + I = image(decal_icon, "[icon_state]-screen") + I.color = screen_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/gps/attack_self(mob/user) + ui_interact(user) + return TRUE + +/obj/item/gps/ui_data(mob/user, ui_key) + + var/turf/curr = get_turf(src) + var/area/my_area = get_area(src) + + . = list() + .["tracking"] = tracking + .["gps_tag"] = gps_tag + .["my_area_name"] = strip_improper(my_area.name) + .["hide_signal"] = hide_signal + .["curr_x"] = curr.x + .["curr_y"] = curr.y + .["curr_z"] = curr.z + .["curr_z_name"] = strip_improper(SSmapping.get_gps_level_name(curr.z)) + .["local_mode"] = local_mode + + var/z_level_detection + if(long_range) + z_level_detection = (SSmapping.station_levels|SSmapping.contact_levels|SSmapping.player_levels) + else + z_level_detection = SSmapping.get_connected_levels(curr.z) + .["z_level_detection"] = z_level_detection + + var/list/gps_list = list() + for(var/obj/item/gps/G as anything in global.all_gps_units) + if(G == src || !can_track(G, z_level_detection)) + continue + + var/gps_data[0] + var/gps_ref = "\ref[G]" + gps_data["gps_ref"] = gps_ref + gps_data["gps_tag"] = G.gps_tag + gps_data["is_special_gps_marker"] = G.is_special_gps_marker + gps_data["being_tracked"] = !!(gps_ref in tracking_devices) + + var/square_colour = LAZYACCESS(tracking_devices, gps_ref) || COLOR_CYAN + gps_data["coloured_square"] = COLORED_SQUARE(square_colour) + + var/area/A = get_area(G) + gps_data["area_name"] = strip_improper(A.name) + + var/turf/T = get_turf(G) + gps_data["z_name"] = strip_improper(SSmapping.get_gps_level_name(T.z)) + gps_data["direction"] = get_compass_direction_string(curr, T) + gps_data["degrees"] = round(Get_Angle(curr,T)) + gps_data["distX"] = T.x - curr.x + gps_data["distY"] = T.y - curr.y + gps_data["distance"] = round(get_dist(curr, T), 10) + gps_data["local"] = (curr.z == T.z) + gps_data["x"] = T.x + gps_data["y"] = T.y + gps_list += list(gps_data) + + if(length(gps_list)) + .["gps_list"] = gps_list + else + .["no_signals"] = TRUE + +/obj/item/gps/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = global.default_topic_state) + + var/data = ui_data() + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "gps.tmpl", name, 500, 300, master_ui = master_ui, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/item/gps/OnTopic(mob/user, list/href_list, topic_state) + + if(href_list["toggle_power"]) + toggle_tracking() + . = TOPIC_REFRESH + + if(href_list["track_label"]) + var/gps_ref = href_list["track_label"] + var/obj/item/gps/gps = locate(gps_ref) + if(istype(gps) && !QDELETED(gps) && !LAZYACCESS(showing_tracked_names, gps_ref)) + LAZYSET(showing_tracked_names, gps_ref, TRUE) + else + LAZYREMOVE(showing_tracked_names, gps_ref) + to_chat(user, SPAN_NOTICE("\The [src] is [LAZYACCESS(showing_tracked_names, gps_ref) ? "now showing" : "no longer showing"] labels for [gps.gps_tag].")) + . = TOPIC_REFRESH + + if(href_list["stop_track"]) + var/gps_ref = href_list["stop_track"] + var/obj/item/gps/gps = locate(gps_ref) + _compass?.clear_waypoint(gps_ref) + LAZYREMOVE(tracking_devices, gps_ref) + LAZYREMOVE(showing_tracked_names, gps_ref) + if(istype(gps) && !QDELETED(gps)) + to_chat(user, SPAN_NOTICE("\The [src] is no longer tracking [gps.gps_tag].")) + update_compass() + . = TOPIC_REFRESH + + if(href_list["start_track"]) + var/gps_ref = href_list["start_track"] + var/obj/item/gps/gps = locate(gps_ref) + if(istype(gps) && !QDELETED(gps)) + LAZYSET(tracking_devices, gps_ref, COLOR_SILVER) + LAZYSET(showing_tracked_names, gps_ref, TRUE) + to_chat(user, SPAN_NOTICE("\The [src] is now tracking [gps.gps_tag].")) + update_compass() + . = TOPIC_REFRESH + + if(href_list["track_color"]) + var/obj/item/gps/gps = locate(href_list["track_color"]) + if(istype(gps) && !QDELETED(gps)) + var/new_colour = input("Enter a new tracking color.", "GPS Waypoint Color") as color|null + if(new_colour && istype(gps) && !QDELETED(gps) && holder == user && CanInteract(user, topic_state)) + to_chat(user, SPAN_NOTICE("You adjust the colour \the [src] is using to highlight [gps.gps_tag].")) + LAZYSET(tracking_devices, href_list["track_color"], new_colour) + update_compass() + . = TOPIC_REFRESH + + if(href_list["tag"]) + var/a = input("Please enter desired tag.", name, gps_tag) as text + a = uppertext(copytext(sanitize(a), 1, 11)) + if(CanInteract(user, topic_state)) + set_gps_tag(a) + to_chat(user, SPAN_NOTICE("You set your GPS's tag to '[gps_tag]'.")) + . = TOPIC_REFRESH + + if(href_list["range"]) + local_mode = !local_mode + to_chat(user, SPAN_NOTICE("You set the signal receiver to [local_mode ? "'NARROW'" : "'BROAD'"].")) + . = TOPIC_REFRESH + + if(href_list["hide"]) + if(!can_hide_signal) + return + hide_signal = !hide_signal + to_chat(user, SPAN_NOTICE("You set the device to [hide_signal ? "not " : ""]broadcast a signal while scanning for other signals.")) + . = TOPIC_REFRESH + +/obj/item/gps/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/gps_toggle) + +/decl/interaction_handler/gps_toggle + name = "Toggle Tracking" + expected_target_type = /obj/item/gps + examine_desc = "toggle GPS tracking" + +/decl/interaction_handler/gps_toggle/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/gps/G = target + G.toggle_tracking(user) + +/* + * Subtypes + */ + +// Mapped type for away site GPS. +/obj/item/gps/marker/Initialize() + . = ..() + if(!tracking) + toggle_tracking() + +/obj/item/gps/marker/special + is_special_gps_marker = TRUE + +// Department subtypes. +/obj/item/gps/mining + gps_tag = "MIN0" + color = "#c08f45" + decals = list( + "stripe-outside" = "#702e98", + "stripe-inside" = "#702e98" + ) + +/obj/item/gps/science + gps_tag = "SCI0" + color = "#dbcfdf" + decals = list( + "stripe-outside" = "#cc33ff", + "stripe-inside" = "#9933ff" + ) + +/obj/item/gps/medical + gps_tag = "MED0" + color = "#ebebeb" + decals = list( + "stripe-outside" = "#6ab8fe", + "stripe-inside" = "#339efe" + ) + +/obj/item/gps/security + gps_tag = "SEC0" + color = "#5c0000" + decals = list( + "stripe-outside" = "#ff0000", + "stripe-inside" = "#800000" + ) + +/obj/item/gps/security/hos + decals = list( + "stripe-outside" = "#ffae00", + "stripe-inside" = "#9e7900" + ) + +/obj/item/gps/security + color = "#5c0000" + decals = list( + "stripe-outside" = "#ff0000", + "stripe-inside" = "#800000" + ) + +/obj/item/gps/security/hos + decals = list( + "stripe-outside" = "#ffae00", + "stripe-inside" = "#9e7900" + ) diff --git a/code/game/objects/items/devices/hacktool.dm b/code/game/objects/items/devices/hacktool.dm index 3c7cf53e0880..88ebe70cf775 100644 --- a/code/game/objects/items/devices/hacktool.dm +++ b/code/game/objects/items/devices/hacktool.dm @@ -17,18 +17,19 @@ /obj/item/multitool/hacktool/Destroy() for(var/T in known_targets) var/atom/target = T - GLOB.destroyed_event.unregister(target, src) + events_repository.unregister(/decl/observ/destroyed, target, src) known_targets.Cut() qdel(hack_state) hack_state = null return ..() -/obj/item/multitool/hacktool/attackby(var/obj/W, var/mob/user) - if(isScrewdriver(W)) +/obj/item/multitool/hacktool/attackby(var/obj/item/used_item, var/mob/user) + if(IS_SCREWDRIVER(used_item)) in_hack_mode = !in_hack_mode playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + return TRUE else - ..() + return ..() /obj/item/multitool/hacktool/resolve_attackby(atom/A, mob/user) sanity_check() @@ -44,7 +45,7 @@ to_chat(user, "You are already hacking!") return 1 if(!is_type_in_list(target, supported_types)) - to_chat(user, "\icon[src] Unable to hack this target.") + to_chat(user, "[html_icon(src)] Unable to hack this target.") return 0 var/found = known_targets.Find(target) if(found) @@ -61,7 +62,7 @@ to_chat(user, "Your hacking attempt was succesful!") user.playsound_local(get_turf(src), 'sound/piano/A#6.ogg', 50) known_targets.Insert(1, target) // Insert the newly hacked target first, - GLOB.destroyed_event.register(target, src, /obj/item/multitool/hacktool/proc/on_target_destroy) + events_repository.register(/decl/observ/destroyed, target, src, TYPE_PROC_REF(/obj/item/multitool/hacktool, on_target_destroy)) else to_chat(user, "Your hacking attempt failed!") return 1 @@ -72,7 +73,7 @@ if(known_targets.len > max_known_targets) for(var/i = (max_known_targets + 1) to known_targets.len) var/atom/A = known_targets[i] - GLOB.destroyed_event.unregister(A, src) + events_repository.unregister(/decl/observ/destroyed, A, src) known_targets.Cut(max_known_targets + 1) /obj/item/multitool/hacktool/proc/on_target_destroy(var/target) diff --git a/code/game/objects/items/devices/hailer.dm b/code/game/objects/items/devices/hailer.dm new file mode 100644 index 000000000000..e030b16b10f3 --- /dev/null +++ b/code/game/objects/items/devices/hailer.dm @@ -0,0 +1,55 @@ +/obj/item/hailer + name = "hailer" + desc = "Used by obese officers to save their breath for running." + icon = 'icons/obj/items/device/hailer.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + obj_flags = OBJ_FLAG_CONDUCTIBLE + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + ) + var/use_message = "Halt! Security!" + var/spamcheck = 0 + var/insults + +/obj/item/hailer/verb/set_message() + set name = "Set Hailer Message" + set category = "Object" + set desc = "Alter the message shouted by your hailer." + + if(!isnull(insults)) + to_chat(usr, "The hailer is fried. The tiny input screen just shows a waving ASCII penis.") + return + + var/new_message = input(usr, "Please enter new message (leave blank to reset).") as text + if(!new_message || new_message == "") + use_message = "Halt! Security!" + else + use_message = capitalize(copytext(sanitize(new_message), 1, MAX_MESSAGE_LEN)) + + to_chat(usr, "You configure the hailer to shout \"[use_message]\".") + +/obj/item/hailer/attack_self(mob/user) + if (spamcheck) + return + + if(isnull(insults)) + playsound(get_turf(src), 'sound/voice/halt.ogg', 100, 1, vary = 0) + user.audible_message("[user]'s [name] rasps, \"[use_message]\"", null, "\The [user] holds up \the [name].") + else + to_chat(user, "*BZZZZZZZZT*") + + spamcheck = 1 + spawn(20) + spamcheck = 0 + +/obj/item/hailer/emag_act(var/remaining_charges, var/mob/user) + if(isnull(insults)) + to_chat(user, "You overload \the [src]'s voice synthesizer.") + insults = rand(1, 3)//to prevent dickflooding + return 1 + else + to_chat(user, "The hailer is fried. You can't even fit the sequencer into the input slot.") diff --git a/code/game/objects/items/devices/holowarrant.dm b/code/game/objects/items/devices/holowarrant.dm index 4775def14389..624d4f818656 100644 --- a/code/game/objects/items/devices/holowarrant.dm +++ b/code/game/objects/items/devices/holowarrant.dm @@ -4,13 +4,19 @@ icon = 'icons/obj/items/device/holowarrant.dmi' icon_state = "holowarrant" item_state = "holowarrant" - throwforce = 5 w_class = ITEM_SIZE_SMALL throw_speed = 4 throw_range = 10 obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY req_access = list(list(access_heads, access_security)) + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + ) var/datum/computer_file/report/warrant/active /obj/item/holowarrant/Initialize(ml, material_key) @@ -18,17 +24,17 @@ set_extension(src, /datum/extension/network_device/lazy) //look at it -/obj/item/holowarrant/examine(mob/user, distance) +/obj/item/holowarrant/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(active) - to_chat(user, "It's a holographic warrant for '[active.fields["namewarrant"]]'.") + . += "It's a holographic warrant for '[active.fields["namewarrant"]]'." if(distance <= 1) - show_content(user) + show_content(user) // opens a browser else - to_chat(user, "You have to be closer if you want to read it.") + . += SPAN_WARNING("You have to be closer if you want to read it.") //hit yourself with it -/obj/item/holowarrant/attack_self(mob/living/user) +/obj/item/holowarrant/attack_self(mob/user) ui_interact(user) /obj/item/holowarrant/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null) @@ -49,12 +55,12 @@ active = null update_icon() return TOPIC_REFRESH - + if(href_list["select"]) var/list/active_warrants = list() - for(var/datum/computer_file/report/warrant/W in GLOB.all_warrants) - if(!W.archived) - active_warrants["[capitalize(W.get_category())] - [W.get_name()]"] = W + for(var/datum/computer_file/report/warrant/warrant in global.all_warrants) + if(!warrant.archived) + active_warrants["[capitalize(warrant.get_category())] - [warrant.get_name()]"] = warrant if(!length(active_warrants)) to_chat(user,SPAN_WARNING("There are no active warrants available.")) return TOPIC_HANDLED @@ -63,7 +69,7 @@ if(!selected_name) return TOPIC_HANDLED var/datum/computer_file/report/warrant/selected = active_warrants[selected_name] - if(selected.archived || !(selected in GLOB.all_warrants)) + if(selected.archived || !(selected in global.all_warrants)) to_chat(user,SPAN_WARNING("Invalid selection, try again.")) return TOPIC_HANDLED active = selected @@ -75,29 +81,33 @@ D.ui_interact(user) return TOPIC_HANDLED -/obj/item/holowarrant/attackby(obj/item/W, mob/user) - if(active) - var/obj/item/card/id/I = W.GetIdCard() - if(I && check_access_list(I.GetAccess())) - var/choice = alert(user, "Would you like to authorize this warrant?","Warrant authorization","Yes","No") - var/datum/report_field/signature/auth = active.field_from_name("Authorized by") - if(choice == "Yes") - auth.ask_value(user) - user.visible_message(SPAN_NOTICE("You swipe \the [I] through the [src]."), - SPAN_NOTICE("[user] swipes \the [I] through the [src].")) - broadcast_security_hud_message("[active.get_broadcast_summary()] has been authorized by [auth.get_value()].", src) - else - to_chat(user, "A red \"Access Denied\" light blinks on \the [src]") - return 1 - ..() +/obj/item/holowarrant/attackby(obj/item/used_item, mob/user) + if(!active) + return ..() + var/obj/item/card/id/I = used_item.GetIdCard() + if(I && check_access_list(I.GetAccess())) + var/choice = alert(user, "Would you like to authorize this warrant?","Warrant authorization","Yes","No") + var/datum/report_field/signature/auth = active.field_from_name("Authorized by") + if(choice == "Yes") + auth.ask_value(user) + user.visible_message(SPAN_NOTICE("You swipe \the [I] through \the [src]."), + SPAN_NOTICE("[user] swipes \the [I] through \the [src].")) + broadcast_security_hud_message("[active.get_broadcast_summary()] has been authorized by [auth.get_value()].", src) + else + to_chat(user, "A red \"Access Denied\" light blinks on \the [src]") + return TRUE //hit other people with it -/obj/item/holowarrant/attack(mob/living/carbon/M, mob/living/carbon/user) - user.visible_message("[user] holds up a warrant projector and shows the contents to [M].", \ - "You show the warrant to [M].") - M.examinate(src) +/obj/item/holowarrant/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] holds up a warrant projector and shows the contents to \the [target]."), + SPAN_NOTICE("You show the warrant to \the [target].") + ) + target.examine_verb(src) + return TRUE /obj/item/holowarrant/on_update_icon() + . = ..() if(active) icon_state = "holowarrant_filled" else diff --git a/code/game/objects/items/devices/inducer.dm b/code/game/objects/items/devices/inducer.dm index 812c10914611..bb84d497a164 100644 --- a/code/game/objects/items/devices/inducer.dm +++ b/code/game/objects/items/devices/inducer.dm @@ -4,25 +4,25 @@ icon = 'icons/obj/items/device/inducer.dmi' icon_state = "inducer-sci" item_state = "inducer-sci" - force = 7 - origin_tech = "{'powerstorage':6,'engineering':4}" + _base_attack_force = 7 + origin_tech = @'{"powerstorage":6,"engineering":4}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - slot_flags = SLOT_BELT + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + slot_flags = SLOT_LOWER_BODY var/powertransfer = 500 var/coefficient = 0.9 - var/opened = FALSE var/failsafe = 0 - var/obj/item/cell/cell = /obj/item/cell var/recharging = FALSE /obj/item/inducer/Initialize() . = ..() - if(ispath(cell)) - cell = new cell(src) + setup_power_supply() update_icon() +/obj/item/inducer/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell, /obj/item/cell, /datum/extension/loaded_cell/panel, charge_value) + /obj/item/inducer/proc/induce(obj/item/cell/target) var/obj/item/cell/MyC = get_cell() var/missing = target.maxcharge - target.charge @@ -32,16 +32,8 @@ MyC.update_icon() target.update_icon() -/obj/item/inducer/get_cell() - return cell - -/obj/item/inducer/emp_act(severity) - ..() - if(cell) - cell.emp_act(severity) - -/obj/item/inducer/afterattack(obj/O, mob/living/carbon/user, var/proximity) - if (!proximity || user.a_intent == I_HURT || CannotUse(user) || !recharge(O, user)) +/obj/item/inducer/afterattack(obj/O, mob/living/user, var/proximity) + if (!proximity || user.check_intent(I_FLAG_HARM) || CannotUse(user) || !recharge(O, user)) return ..() /obj/item/inducer/proc/CannotUse(mob/user) @@ -54,29 +46,9 @@ return TRUE return FALSE - -/obj/item/inducer/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - opened = !opened - to_chat(user, "You [opened ? "open" : "close"] the battery compartment.") - update_icon() - if(istype(W, /obj/item/cell)) - if (istype(W, /obj/item/cell/device)) - to_chat(user, "\The [src] only takes full-size power cells.") - return - if(opened) - if(!cell) - if(!user.unEquip(W, src)) - return - to_chat(user, "You insert \the [W] into \the [src].") - cell = W - update_icon() - return - else - to_chat(user, "\The [src] already has \a [cell] installed!") - return - if(CannotUse(user) || recharge(W, user)) - return +/obj/item/inducer/attackby(obj/item/used_item, mob/user) + if(CannotUse(user) || recharge(used_item, user)) + return TRUE return ..() /obj/item/inducer/proc/recharge(atom/A, mob/user) @@ -87,40 +59,37 @@ else recharging = TRUE var/obj/item/cell/MyC = get_cell() - var/obj/item/cell/C = A.get_cell() + var/obj/item/cell/cell = A.get_cell() var/obj/O if(istype(A, /obj)) O = A - if(C) - var/length = 10 + if(cell) + var/charge_length = 10 var/done_any = FALSE - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(1, 1, user.loc) - sparks.start() - if(C.charge >= C.maxcharge) + spark_at(user, amount = 1, cardinal_only = TRUE) + if(cell.charge >= cell.maxcharge) to_chat(user, "\The [A] is fully charged!") recharging = FALSE return TRUE user.visible_message("\The [user] starts recharging \the [A] with \the [src].","You start recharging \the [A] with \the [src].") if (istype(A, /obj/item/gun/energy)) - length = 30 + charge_length = 30 if (user.get_skill_value(SKILL_WEAPONS) <= SKILL_ADEPT) - length += rand(10, 30) + charge_length += rand(10, 30) if (user.get_skill_value(SKILL_ELECTRICAL) < SKILL_ADEPT) - length += rand(40, 60) - while(C.charge < C.maxcharge) - if(MyC.charge > max(0, MyC.charge*failsafe) && do_after(user, length, target = user)) + charge_length += rand(40, 60) + while(cell.charge < cell.maxcharge) + if(MyC.charge > max(0, MyC.charge*failsafe) && do_after(user, charge_length, target = user)) if(CannotUse(user)) return TRUE - if(QDELETED(C)) + if(QDELETED(cell)) return TRUE - sparks.start() + spark_at(user, amount = 1, cardinal_only = TRUE) done_any = TRUE - induce(C) + induce(cell) if(O) O.update_icon() else - qdel(sparks) break if(done_any) // Only show a message if we succeeded at least once user.visible_message("\The [user] recharged \the [A]!","You recharged \the [A]!") @@ -137,41 +106,14 @@ else return 0 -/obj/item/inducer/attack(mob/M, mob/user) - return - - -/obj/item/inducer/attack_self(mob/user) - if(opened && cell) - user.visible_message("\The [user] removes \the [cell] from \the [src]!","You remove \the [cell].") - cell.update_icon() - user.put_in_hands(cell) - cell = null - update_icon() - - -/obj/item/inducer/examine(mob/living/M) - . = ..() - var/obj/item/cell/MyC = get_cell() - if(MyC) - to_chat(M, "Its display shows: [MyC.percent()]%.") - else - to_chat(M,"Its display is dark.") - if(opened) - to_chat(M,"Its battery compartment is open.") +/obj/item/inducer/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE /obj/item/inducer/on_update_icon() - overlays.Cut() - if(opened) - if(!get_cell()) - overlays += image(icon, "inducer-nobat") - else - overlays += image(icon,"inducer-bat") - -/obj/item/inducer/Destroy() . = ..() - if(!ispath(cell)) - QDEL_NULL(cell) + var/datum/extension/loaded_cell/panel/cell_loaded = get_extension(src, /datum/extension/loaded_cell) + if(istype(cell_loaded) && cell_loaded.panel_open) + add_overlay("inducer-[get_cell()? "bat" : "nobat"]") // module version @@ -179,16 +121,14 @@ icon_state = "inducer-engi" item_state = "inducer-engi" failsafe = 0.2 - cell = null -/obj/item/inducer/borg/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - return - . = ..() +/obj/item/inducer/borg/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + return /obj/item/inducer/borg/on_update_icon() . = ..() - overlays += image("icons/obj/guns/gui.dmi","safety[safety()]") + add_overlay(overlay_image("icons/obj/guns/gui.dmi", "safety[safety()]")) /obj/item/inducer/borg/verb/toggle_safety(var/mob/user) set src in usr @@ -203,4 +143,4 @@ to_chat(user, "You switch your battery output failsafe [safety() ? "on" : "off" ].") /obj/item/inducer/borg/get_cell() - return loc ? loc.get_cell() : null \ No newline at end of file + return loc?.get_cell() \ No newline at end of file diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm deleted file mode 100644 index b511f5d58591..000000000000 --- a/code/game/objects/items/devices/lightreplacer.dm +++ /dev/null @@ -1,189 +0,0 @@ - -// Light Replacer (LR) -// -// ABOUT THE DEVICE -// -// This is a device supposedly to be used by Janitors and Janitor Cyborgs which will -// allow them to easily replace lights. This was mostly designed for Janitor Cyborgs since -// they don't have hands or a way to replace lightbulbs. -// -// HOW IT WORKS -// -// You attack a light fixture with it, if the light fixture is broken it will replace the -// light fixture with a working light; the broken light is then placed on the floor for the -// user to then pickup with a trash bag. If it's empty then it will just place a light in the fixture. -// -// HOW TO REFILL THE DEVICE -// -// It can be manually refilled or by clicking on a storage item containing lights. -// If it's part of a robot module, it will charge when the Robot is inside a Recharge Station. -// -// EMAGGED FEATURES -// -// NOTICE: The Cyborg cannot use the emagged Light Replacer and the light's explosion was nerfed. It cannot create holes in the station anymore. -// -// I'm not sure everyone will react the emag's features so please say what your opinions are of it. -// -// When emagged it will rig every light it replaces, which will explode when the light is on. -// This is VERY noticable, even the device's name changes when you emag it so if anyone -// examines you when you're holding it in your hand, you will be discovered. -// It will also be very obvious who is setting all these lights off, since only Janitor Borgs and Janitors have easy -// access to them, and only one of them can emag their device. -// -// The explosion cannot insta-kill anyone with 30% or more health. - -#define LIGHT_OK 0 -#define LIGHT_EMPTY 1 -#define LIGHT_BROKEN 2 -#define LIGHT_BURNED 3 - - -/obj/item/lightreplacer - name = "light replacer" - desc = "A lightweight automated device, capable of interfacing with and rapidly replacing standard light installations." - icon = 'icons/obj/janitor.dmi' - icon_state = "lightreplacer0" - item_state = "electronic" - material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE - ) - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - origin_tech = "{'magnets':3,'materials':2}" - - var/max_uses = 32 - var/uses = 32 - var/emagged = 0 - var/charge = 0 - -/obj/item/lightreplacer/examine(mob/user, distance) - . = ..() - if(distance <= 2) - to_chat(user, "It has [uses] light\s remaining.") - -/obj/item/lightreplacer/resolve_attackby(var/atom/A, mob/user) - - //Check for lights in a container, refilling our charges. - if(istype(A, /obj/item/storage/)) - var/obj/item/storage/S = A - var/amt_inserted = 0 - var/turf/T = get_turf(user) - for(var/obj/item/light/L in S.contents) - if(!user.stat && src.uses < src.max_uses && L.status == 0) - src.AddUses(1) - amt_inserted++ - S.remove_from_storage(L, T, 1) - qdel(L) - S.finish_bulk_removal() - if(amt_inserted) - to_chat(user, "You insert [amt_inserted] light\s into \The [src]. It has [uses] light\s remaining.") - add_fingerprint(user) - return - - //Actually replace the light. - if(istype(A, /obj/machinery/light/)) - var/obj/machinery/light/L = A - if(isliving(user)) - var/mob/living/U = user - ReplaceLight(L, U) - add_fingerprint(user) - return - . = ..() - -/obj/item/lightreplacer/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/stack/material) && W.get_material_type() == /decl/material/solid/glass) - var/obj/item/stack/G = W - if(uses >= max_uses) - to_chat(user, "[src.name] is full.") - return - else if(G.use(1)) - AddUses(16) //Autolathe converts 1 sheet into 16 lights. - to_chat(user, "You insert a piece of glass into \the [src.name]. You have [uses] light\s remaining.") - return - else - to_chat(user, "You need one sheet of glass to replace lights.") - - if(istype(W, /obj/item/light)) - var/obj/item/light/L = W - if(L.status == 0) // LIGHT OKAY - if(uses < max_uses) - if(!user.unEquip(L)) - return - AddUses(1) - to_chat(user, "You insert \the [L.name] into \the [src.name]. You have [uses] light\s remaining.") - qdel(L) - return - else - to_chat(user, "You need a working light.") - return - -/obj/item/lightreplacer/attack_self(mob/user) - /* // This would probably be a bit OP. If you want it though, uncomment the code. - if(isrobot(user)) - var/mob/living/silicon/robot/R = user - if(R.emagged) - src.Emag() - to_chat(usr, "You shortcircuit the [src].") - return - */ - to_chat(usr, "It has [uses] lights remaining.") - -/obj/item/lightreplacer/on_update_icon() - icon_state = "lightreplacer[emagged]" - - -/obj/item/lightreplacer/proc/Use(var/mob/user) - - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) - AddUses(-1) - return 1 - -// Negative numbers will subtract -/obj/item/lightreplacer/proc/AddUses(var/amount = 1) - uses = min(max(uses + amount, 0), max_uses) - -/obj/item/lightreplacer/proc/Charge(var/mob/user, var/amount = 1) - charge += amount - if(charge > 6) - AddUses(1) - charge = 0 - -/obj/item/lightreplacer/proc/ReplaceLight(var/obj/machinery/light/target, var/mob/living/U) - - if(target.get_status() == LIGHT_OK) - to_chat(U, "There is a working [target.get_fitting_name()] already inserted.") - else if(!CanUse(U)) - to_chat(U, "\The [src]'s refill light blinks red.") - else if(Use(U)) - to_chat(U, "You replace the [target.get_fitting_name()] with the [src].") - - if(target.lightbulb) - target.remove_bulb() - - var/obj/item/light/L = new target.light_type() - L.rigged = emagged - target.insert_bulb(L) - - -/obj/item/lightreplacer/emag_act(var/remaining_charges, var/mob/user) - emagged = !emagged - playsound(src.loc, "sparks", 100, 1) - update_icon() - return 1 - -//Can you use it? - -/obj/item/lightreplacer/proc/CanUse(var/mob/living/user) - src.add_fingerprint(user) - //Not sure what else to check for. Maybe if clumsy? - if(uses > 0) - return 1 - else - return 0 - -#undef LIGHT_OK -#undef LIGHT_EMPTY -#undef LIGHT_BROKEN -#undef LIGHT_BURNED diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm index 065aef4968d9..c5b41c2ed60d 100644 --- a/code/game/objects/items/devices/megaphone.dm +++ b/code/game/objects/items/devices/megaphone.dm @@ -6,18 +6,23 @@ item_state = "radio" w_class = ITEM_SIZE_SMALL obj_flags = OBJ_FLAG_CONDUCTIBLE - - var/spamcheck = 0 - var/emagged = 0 - var/insults = 0 + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY, + ) + var/spamcheck = FALSE + var/emagged = FALSE + var/insults = FALSE var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TATER!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "FOR THE SYNDICATE!") -/obj/item/megaphone/attack_self(mob/living/user) - if (user.client) +/obj/item/megaphone/attack_self(mob/user) + if(user.client) if(user.client.prefs.muted & MUTE_IC) to_chat(src, "You cannot speak in IC (muted).") return - if(user.silent) + if(user.is_silenced()) return if(spamcheck) to_chat(user, "\The [src] needs to recharge!") @@ -27,26 +32,25 @@ if(!message) return message = capitalize(message) - if ((src.loc == user && usr.stat == 0)) + if ((src.loc == user && usr.stat == CONSCIOUS)) if(emagged) if(insults) - for(var/mob/O in (viewers(user))) - O.show_message("[user] broadcasts, \"[pick(insultmsg)]\"",2) // 2 stands for hearable message + var/insult = pick(insultmsg) + user.audible_message("[user] broadcasts, \"[insult]\"", "You broadcast, \"[insult]\"") insults-- else - to_chat(user, "*BZZZZzzzzzt*") + to_chat(user, SPAN_WARNING("*BZZZZzzzzzt*")) else - for(var/mob/O in (viewers(user))) - O.show_message("[user] broadcasts, \"[message]\"",2) // 2 stands for hearable message + user.audible_message("[user] broadcasts, \"[message]\"", "You broadcast, \"[message]\"") - spamcheck = 1 + spamcheck = TRUE spawn(20) - spamcheck = 0 + spamcheck = FALSE return /obj/item/megaphone/emag_act(var/remaining_charges, var/mob/user) if(!emagged) - to_chat(user, "You overload \the [src]'s voice synthesizer.") - emagged = 1 + to_chat(user, SPAN_WARNING("You overload \the [src]'s voice synthesizer.")) + emagged = TRUE insults = rand(1, 3)//to prevent dickflooding - return 1 + return TRUE diff --git a/code/game/objects/items/devices/modkit.dm b/code/game/objects/items/devices/modkit.dm index b7c766feed71..8b73d443025e 100644 --- a/code/game/objects/items/devices/modkit.dm +++ b/code/game/objects/items/devices/modkit.dm @@ -7,8 +7,9 @@ desc = "A kit containing all the needed tools and parts to modify a hardsuit for another user." icon = 'icons/obj/items/modkit.dmi' icon_state = "modkit" + material = /decl/material/solid/organic/plastic var/parts = MODKIT_FULL - var/target_bodytype + var/target_bodytype = BODYTYPE_HUMANOID var/list/permitted_types = list( /obj/item/clothing/head/helmet/space/void, @@ -17,9 +18,10 @@ /obj/item/modkit/Initialize(ml, material_key) if(!target_bodytype) - target_bodytype = GLOB.using_map.default_species + var/decl/species/species = decls_repository.get_decl_by_id(global.using_map.default_species) + target_bodytype = species.default_bodytype.bodytype_flag . = ..() - + /obj/item/modkit/afterattack(obj/O, mob/user, proximity) if(!proximity) return @@ -42,12 +44,6 @@ to_chat(user, "[src] is unable to modify that.") return - var/excluding = ("exclude" in I.bodytype_restricted) - var/in_list = (target_bodytype in I.bodytype_restricted) - if (excluding ^ in_list) - to_chat(user, "[I] is already modified.") - return - if(!isturf(O.loc)) to_chat(user, "[O] must be safely placed on the ground for modification.") return @@ -56,7 +52,7 @@ user.visible_message("\The [user] opens \the [src] and modifies \the [O].","You open \the [src] and modify \the [O].") - I.refit_for_bodytype(target_bodytype) + I.refit_for_bodytype(target_bodytype, skip_rename = TRUE) if (istype(I, /obj/item/clothing/head/helmet)) parts &= ~MODKIT_HELMET @@ -66,6 +62,6 @@ if(!parts) qdel(src) -/obj/item/modkit/examine(mob/user) +/obj/item/modkit/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) - to_chat(user, "It looks as though it modifies hardsuits to fit [target_bodytype] users.") + . += "It looks as though it modifies hardsuits to fit [target_bodytype] users." diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 411fdcf7665f..bbe58439f6f2 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -9,23 +9,24 @@ icon = 'icons/obj/items/device/multitool.dmi' icon_state = "multitool" obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 w_class = ITEM_SIZE_SMALL - throwforce = 5.0 throw_range = 15 throw_speed = 3 - - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE ) - origin_tech = "{'magnets':1,'engineering':1}" + origin_tech = @'{"magnets":1,"engineering":1}' var/buffer_name var/atom/buffer_object +/obj/item/multitool/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_MULTITOOL = TOOL_QUALITY_DEFAULT)) + /obj/item/multitool/Destroy() unregister_buffer(buffer_object) return ..() @@ -51,13 +52,13 @@ unregister_buffer(buffer_object) buffer_object = buffer if(buffer_object) - GLOB.destroyed_event.register(buffer_object, src, /obj/item/multitool/proc/unregister_buffer) + events_repository.register(/decl/observ/destroyed, buffer_object, src, TYPE_PROC_REF(/obj/item/multitool, unregister_buffer)) /obj/item/multitool/proc/unregister_buffer(var/atom/buffer_to_unregister) // Only remove the buffered object, don't reset the name // This means one cannot know if the buffer has been destroyed until one attempts to use it. if(buffer_to_unregister == buffer_object && buffer_object) - GLOB.destroyed_event.unregister(buffer_object, src) + events_repository.unregister(/decl/observ/destroyed, buffer_object, src) buffer_object = null /obj/item/multitool/resolve_attackby(atom/A, mob/user) diff --git a/code/game/objects/items/devices/music_player.dm b/code/game/objects/items/devices/music_player.dm new file mode 100644 index 000000000000..249f10c0c5f8 --- /dev/null +++ b/code/game/objects/items/devices/music_player.dm @@ -0,0 +1,101 @@ +/obj/item/music_player + abstract_type = /obj/item/music_player + icon_state = ICON_STATE_WORLD + _base_attack_force = 7 + w_class = ITEM_SIZE_HUGE //forbid putting something that emits loud sounds forever into a backpack + + var/playing = 0 + var/track_num = 1 + var/music_volume = 20 + var/max_volume = 40 + var/datum/sound_token/sound_token + var/list/datum/track/tracks + var/sound_id + var/player_name = "Music Player" + var/interact_sound + var/music_frequency = 1 + +/obj/item/music_player/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(playing) + icon_state = "[icon_state]_on" + +/obj/item/music_player/proc/stop() + playing = 0 + update_icon() + QDEL_NULL(sound_token) + +/obj/item/music_player/proc/start() + QDEL_NULL(sound_token) + var/datum/track/T = tracks[track_num] + sound_token = play_looping_sound(src, sound_id, T.GetTrack(), volume = music_volume, frequency = music_frequency, range = 7, falloff = 4, prefer_mute = TRUE, preference = /datum/client_preference/play_game_music, streaming = TRUE) + playing = 1 + update_icon() + +/obj/item/music_player/attack_self(var/mob/user) + interact(user) + +/obj/item/music_player/Initialize() + . = ..() + sound_id = "[type]_[sequential_id(type)]" + tracks = setup_music_tracks(tracks) + +/obj/item/music_player/Destroy() + stop() + . = ..() + +/obj/item/music_player/interact(var/mob/user) + if(!CanPhysicallyInteract(user)) + return + var/dat = list() + var/datum/track/T = tracks[track_num] + if(istype(T) && T.title) + dat += "

              [T.title]


              " + dat += "NEXT" + dat += "PREV" + dat += "PLAY" + dat += "STOP" + dat += "VOL -" + dat += "VOL +" + var/datum/browser/popup = new(user, "music_player_[name]", "[player_name]", 350, 150) + popup.set_content(JOINTEXT(dat)) + popup.open() + +/obj/item/music_player/DefaultTopicState() + return global.physical_topic_state + +/obj/item/music_player/CouldUseTopic(var/mob/user) + ..() + if(interact_sound) + playsound(src, interact_sound, 40) + +/obj/item/music_player/OnTopic(var/user, var/list/href_list) + if(href_list["tracknum"]) + var/diff = text2num(href_list["tracknum"]) + track_num += diff + if(track_num > tracks.len) + track_num = 1 + else if (track_num < 1) + track_num = tracks.len + if(playing) + start() + interact(user) + return TOPIC_REFRESH + if(href_list["stop"]) + stop() + return TOPIC_HANDLED + if(href_list["start"]) + start() + return TOPIC_HANDLED + if(href_list["volup"]) + change_volume(music_volume + 10) + return TOPIC_HANDLED + if(href_list["voldown"]) + change_volume(music_volume - 10) + return TOPIC_HANDLED + +/obj/item/music_player/proc/change_volume(var/new_volume) + music_volume = clamp(new_volume, 0, max_volume) + if(sound_token) + sound_token.SetVolume(music_volume) diff --git a/code/game/objects/items/devices/oxycandle.dm b/code/game/objects/items/devices/oxycandle.dm index cc3bdea28341..719223e6ec8f 100644 --- a/code/game/objects/items/devices/oxycandle.dm +++ b/code/game/objects/items/devices/oxycandle.dm @@ -1,3 +1,4 @@ +// TODO: Make this an actual candle that burns something that produces oxygen as a waste product? That'd be doable now... /obj/item/oxycandle name = "oxygen candle" desc = "A steel tube with the words 'OXYGEN - PULL CORD TO IGNITE' stamped on the side.\nA small label reads 'WARNING: NOT FOR LIGHTING USE. WILL IGNITE FLAMMABLE GASSES'" @@ -7,13 +8,13 @@ w_class = ITEM_SIZE_SMALL // Should fit into internal's box or maybe pocket material = /decl/material/solid/metal/steel light_color = "#e58775" - light_outer_range = 2 - light_max_bright = 1 + light_range = 2 + light_power = 1 action_button_name = null var/target_pressure = ONE_ATMOSPHERE var/datum/gas_mixture/air_contents = null - var/volume = 4600 + var/candle_volume = 4600 var/on = 0 var/activation_sound = 'sound/effects/flare.ogg' var/brightness_on = 1 // Moderate-low bright. @@ -22,10 +23,8 @@ . = ..() update_icon() -/obj/item/oxycandle/afterattack(var/obj/O, var/mob/user, var/proximity) - if(proximity && istype(O) && on) - O.HandleObjectHeating(src, user, 500) - ..() +/obj/item/oxycandle/get_heat() + return on ? 500 : 0 /obj/item/oxycandle/attack_self(mob/user) if(!on) @@ -34,10 +33,10 @@ update_icon() playsound(src.loc, activation_sound, 75, 1) air_contents = new /datum/gas_mixture() - air_contents.volume = 200 //liters + air_contents.total_volume = 200 //liters air_contents.temperature = T20C - var/list/air_mix = list(/decl/material/gas/oxygen = 1 * (target_pressure * air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)) - air_contents.adjust_multi(/decl/material/gas/oxygen, air_mix[/decl/material/gas/oxygen]) + var/const/OXYGEN_FRACTION = 1 // separating out the constant so it's clearer why it exists and how to modify it later + air_contents.adjust_gas(/decl/material/gas/oxygen, OXYGEN_FRACTION * (target_pressure * air_contents.total_volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)) START_PROCESSING(SSprocessing, src) // Process of Oxygen candles releasing air. Makes 200 volume of oxygen @@ -45,7 +44,7 @@ if(!loc) return var/turf/pos = get_turf(src) - if(volume <= 0 || !pos || (pos.turf_flags & TURF_IS_WET)) //Now uses turf flags instead of whatever aurora did + if(candle_volume <= 0 || !pos || (pos.turf_flags & TURF_IS_WET)) //Now uses turf flags instead of whatever aurora did STOP_PROCESSING(SSprocessing, src) on = 2 update_icon() @@ -57,18 +56,19 @@ pos.hotspot_expose(1500, 5) var/datum/gas_mixture/environment = loc.return_air() var/pressure_delta = target_pressure - environment.return_pressure() - var/output_volume = environment.volume * environment.group_multiplier + var/output_volume = environment.total_volume * environment.group_multiplier var/air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) if (!removed) //Just in case return environment.merge(removed) - volume -= 200 - var/list/air_mix = list(/decl/material/gas/oxygen = 1 * (target_pressure * air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)) - air_contents.adjust_multi(/decl/material/gas/oxygen, air_mix[/decl/material/gas/oxygen]) + candle_volume -= 200 + var/const/OXYGEN_FRACTION = 1 // separating out the constant so it's clearer why it exists and how to modify it later + air_contents.adjust_gas(/decl/material/gas/oxygen, OXYGEN_FRACTION * (target_pressure * air_contents.total_volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)) /obj/item/oxycandle/on_update_icon() + . = ..() if(on == 1) icon_state = "oxycandle_on" item_state = icon_state diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index ad67508c1bc6..844fc1c2e5a4 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -1,12 +1,12 @@ +var/global/list/pai_cards = list() /obj/item/paicard name = "personal AI device" icon = 'icons/obj/items/device/pai.dmi' - icon_state = "pai" - item_state = "electronic" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL - slot_flags = SLOT_BELT - origin_tech = "{'programming':2}" - material = /decl/material/solid/glass + slot_flags = SLOT_LOWER_BODY + origin_tech = @'{"programming":2}' + material = /decl/material/solid/fiberglass matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT) var/current_emotion = 1 @@ -15,20 +15,24 @@ var/mob/living/silicon/pai/pai /obj/item/paicard/relaymove(var/mob/user, var/direction) - if(user.stat || user.stunned) + if(user.incapacitated(INCAPACITATION_KNOCKOUT)) return - var/obj/item/rig/rig = src.get_rig() - if(istype(rig)) + var/obj/item/rig/rig = get_rig() + if(rig) rig.forced_move(direction, user) /obj/item/paicard/Initialize() . = ..() - overlays += "pai-off" + global.pai_cards += src + +/obj/item/paicard/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE /obj/item/paicard/Destroy() + global.pai_cards -= src //Will stop people throwing friend pAIs into the singularity so they can respawn if(!isnull(pai)) - pai.death(0) + pai.death() QDEL_NULL(radio) return ..() @@ -47,7 +51,7 @@ color:white; font-size:13px; background-image:url('uiBackground.png'); - background-repeat:repeat-x; + background-repeat:repeat; background-color:#272727; background-position:center top; } @@ -241,14 +245,14 @@ if(href_list["setdna"]) if(pai.master_dna) return - var/mob/M = usr - if(!istype(M, /mob/living/carbon)) - to_chat(usr, "You don't have any DNA, or your DNA is incompatible with this device.") + var/unique_enzymes = usr.get_unique_enzymes() + if(unique_enzymes) + pai.master = usr.real_name + pai.master_dna = unique_enzymes + to_chat(pai, SPAN_NOTICE("You have been bound to a new master.")) else - var/datum/dna/dna = usr.dna - pai.master = M.real_name - pai.master_dna = dna.unique_enzymes - to_chat(pai, "You have been bound to a new master.") + to_chat(usr, SPAN_WARNING("You don't have any DNA, or your DNA is incompatible with this device.")) + if(href_list["request"]) src.looking_for_personality = 1 paiController.findPAI(src, usr) @@ -256,19 +260,19 @@ var/confirm = input("Are you CERTAIN you wish to delete the current personality? This action cannot be undone.", "Personality Wipe") in list("Yes", "No") if(confirm == "Yes") for(var/mob/M in src) - to_chat(M, "

              You feel yourself slipping away from reality.

              ") - to_chat(M, "

              Byte by byte you lose your sense of self.

              ") - to_chat(M, "

              Your mental faculties leave you.

              ") - to_chat(M, "
              oblivion...
              ") - M.death(0) + to_chat(M, SPAN_RED("

              You feel yourself slipping away from reality.

              ")) + to_chat(M, SPAN_ORANGE("

              Byte by byte you lose your sense of self.

              ")) + to_chat(M, SPAN_PINK("

              Your mental faculties leave you.

              ")) + to_chat(M, SPAN_PALEPINK("
              oblivion...
              ")) + M.death() removePersonality() if(href_list["wires"]) var/t1 = text2num(href_list["wires"]) switch(t1) if(4) - radio.ToggleBroadcast() + radio.toggle_broadcast() if(2) - radio.ToggleReception() + radio.toggle_reception() if(href_list["setlaws"]) var/newlaws = sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.pai_laws) as message) if(newlaws) @@ -284,38 +288,41 @@ /obj/item/paicard/proc/setPersonality(mob/living/silicon/pai/personality) src.pai = personality - src.overlays += "pai-happy" + src.add_overlay("pai-happy") /obj/item/paicard/proc/removePersonality() src.pai = null - src.overlays.Cut() - src.overlays += "pai-off" + src.add_overlay("pai-off") /obj/item/paicard/proc/setEmotion(var/emotion) if(pai) - src.overlays.Cut() - switch(emotion) - if(1) src.overlays += "pai-happy" - if(2) src.overlays += "pai-cat" - if(3) src.overlays += "pai-extremely-happy" - if(4) src.overlays += "pai-face" - if(5) src.overlays += "pai-laugh" - if(6) src.overlays += "pai-off" - if(7) src.overlays += "pai-sad" - if(8) src.overlays += "pai-angry" - if(9) src.overlays += "pai-what" - if(10) src.overlays += "pai-neutral" - if(11) src.overlays += "pai-silly" - if(12) src.overlays += "pai-nose" - if(13) src.overlays += "pai-smirk" - if(14) src.overlays += "pai-exclamation" - if(15) src.overlays += "pai-question" current_emotion = emotion + update_icon() + +/obj/item/paicard/on_update_icon() + . = ..() + if(pai) + switch(current_emotion) + if(1) add_overlay("pai-happy") + if(2) add_overlay("pai-cat") + if(3) add_overlay("pai-extremely-happy") + if(4) add_overlay("pai-face") + if(5) add_overlay("pai-laugh") + if(6) add_overlay("pai-off") + if(7) add_overlay("pai-sad") + if(8) add_overlay("pai-angry") + if(9) add_overlay("pai-what") + if(10) add_overlay("pai-neutral") + if(11) add_overlay("pai-silly") + if(12) add_overlay("pai-nose") + if(13) add_overlay("pai-smirk") + if(14) add_overlay("pai-exclamation") + if(15) add_overlay("pai-question") /obj/item/paicard/proc/alertUpdate() - var/turf/T = get_turf_or_move(src.loc) - for (var/mob/M in viewers(T)) - M.show_message("\The [src] flashes a message across its screen, \"Additional personalities available for download.\"", 3, "\The [src] bleeps electronically.", 2) + visible_message( \ + message = SPAN_NOTICE("\The [src] flashes a message across its screen, \"Additional personalities available for download.\""), \ + blind_message = SPAN_NOTICE("\The [src] bleeps electronically.")) /obj/item/paicard/emp_act(severity) for(var/mob/M in src) @@ -329,12 +336,6 @@ else qdel(src) -/obj/item/paicard/see_emote(mob/living/M, text) - if(pai && pai.client && pai.stat == CONSCIOUS) - var/rendered = "[text]" - pai.show_message(rendered, 2) - ..() - /obj/item/paicard/show_message(msg, type, alt, alt_type) if(pai && pai.client) var/rendered = "[msg]" diff --git a/code/game/objects/items/devices/paint_gun.dm b/code/game/objects/items/devices/paint_gun.dm deleted file mode 100644 index 663d62b4d324..000000000000 --- a/code/game/objects/items/devices/paint_gun.dm +++ /dev/null @@ -1,272 +0,0 @@ -/obj/item/floor_painter - name = "paint gun" - icon = 'icons/obj/items/device/floor_painter.dmi' - icon_state = "flpainter" - item_state = "fl_painter" - desc = "A slender and none-too-sophisticated device capable of painting, erasing, and applying decals to most types of exosuits, floors and walls." - - var/decal = "remove all decals" - var/paint_dir = "precise" - var/paint_colour = COLOR_WHITE - - var/color_picker = 0 - - var/list/decals = list( - "quarter-turf" = list("path" = /obj/effect/floor_decal/corner, "precise" = 1, "coloured" = 1), - "monotile color" = list("path" = /obj/effect/floor_decal/corner/white/mono), - "hazard stripes" = list("path" = /obj/effect/floor_decal/industrial/warning), - "corner, hazard" = list("path" = /obj/effect/floor_decal/industrial/warning/corner), - "hatched marking" = list("path" = /obj/effect/floor_decal/industrial/hatch, "coloured" = 1), - "dashed outline" = list("path" = /obj/effect/floor_decal/industrial/outline, "coloured" = 1), - "loading sign" = list("path" = /obj/effect/floor_decal/industrial/loading), - "mosaic, large" = list("path" = /obj/effect/floor_decal/chapel), - "1" = list("path" = /obj/effect/floor_decal/sign), - "2" = list("path" = /obj/effect/floor_decal/sign/two), - "A" = list("path" = /obj/effect/floor_decal/sign/a), - "B" = list("path" = /obj/effect/floor_decal/sign/b), - "C" = list("path" = /obj/effect/floor_decal/sign/c), - "D" = list("path" = /obj/effect/floor_decal/sign/d), - "M" = list("path" = /obj/effect/floor_decal/sign/m), - "V" = list("path" = /obj/effect/floor_decal/sign/v), - "CMO" = list("path" = /obj/effect/floor_decal/sign/cmo), - "Ex" = list("path" = /obj/effect/floor_decal/sign/ex), - "Psy" = list("path" = /obj/effect/floor_decal/sign/p), - "Ivenmoth" = list("path" = /obj/effect/floor_decal/ivenmoth), - "remove all decals" = list("path" = /obj/effect/floor_decal/reset) - - ) - var/list/paint_dirs = list( - "north" = NORTH, - "northwest" = NORTHWEST, - "west" = WEST, - "southwest" = SOUTHWEST, - "south" = SOUTH, - "southeast" = SOUTHEAST, - "east" = EAST, - "northeast" = NORTHEAST, - "precise" = 0 - ) - - var/list/preset_colors = list( - "beasty brown" = COLOR_BEASTY_BROWN, - "blue" = COLOR_BLUE_GRAY, - "civvie green" = COLOR_CIVIE_GREEN, - "command blue" = COLOR_COMMAND_BLUE, - "cyan" = COLOR_CYAN, - "green" = COLOR_GREEN, - "bottle green" = COLOR_PALE_BTL_GREEN, - "capitalist red" = COLOR_NT_RED, - "orange" = COLOR_ORANGE, - "pale orange" = COLOR_PALE_ORANGE, - "red" = COLOR_RED, - "sky blue" = COLOR_DEEP_SKY_BLUE, - "titanium" = COLOR_TITANIUM, - "aluminium"= COLOR_ALUMINIUM, - "violet" = COLOR_VIOLET, - "white" = COLOR_WHITE, - "yellow" = COLOR_AMBER, - "hull blue" = COLOR_HULL, - "bulkhead black" = COLOR_WALL_GUNMETAL - ) - - -/obj/item/floor_painter/afterattack(var/atom/A, var/mob/user, proximity, params) - if(!proximity) - return - - add_fingerprint(user) - - if(color_picker) - paint_colour = A.get_color() - to_chat(usr, "You set \the [src] to paint with a new colour.") - return - - var/turf/simulated/wall/W = A - if(istype(W)) - W.paint_color = paint_colour - W.update_icon() - return - - var/obj/structure/wall_frame/WF = A - if(istype(WF)) - WF.paint_color = paint_colour - WF.update_icon() - return - - var/mob/living/exosuit/ES = A - if(istype(ES)) - to_chat(user, SPAN_WARNING("You can't paint an active exosuit. Dismantle it first.")) - return - - var/obj/structure/heavy_vehicle_frame/EF = A - if(istype(EF)) - EF.set_colour(paint_colour) - return - - var/obj/item/mech_component/MC = A - if(istype(MC)) - MC.set_colour(paint_colour) - return - - var/obj/machinery/door/airlock/D = A - if(istype(D)) - var/choice - if(!D.paintable) - to_chat(user, "You can't paint this airlock type.") - return - if(D.paintable == AIRLOCK_PAINTABLE) - choice = "Paint" - else if(D.paintable == AIRLOCK_STRIPABLE) - choice = "Stripe" - else if(D.paintable == AIRLOCK_PAINTABLE|AIRLOCK_STRIPABLE) - choice = input(user, "What do you wish to paint?") as null|anything in list("Paint","Stripe") - if(user.incapacitated()) - return - if(choice == "Paint") - D.paint_airlock(paint_colour) - else if(choice == "Stripe") - D.stripe_airlock(paint_colour) - return - - var/turf/simulated/floor/F = A - if(!istype(F) || !F.flooring) - to_chat(user, "\The [src] can only be used on floors, walls or certain airlocks.") - return - - if(!F.flooring.can_paint || F.broken || F.burnt) - to_chat(user, "\The [src] cannot paint \the [F.name].") - return - - var/list/decal_data = decals[decal] - var/config_error - if(!islist(decal_data)) - config_error = 1 - var/painting_decal - if(!config_error) - painting_decal = decal_data["path"] - if(!ispath(painting_decal)) - config_error = 1 - - if(config_error) - to_chat(user, "\The [src] flashes an error light. You might need to reconfigure it.") - return - - if(F.decals && F.decals.len > 5 && painting_decal != /obj/effect/floor_decal/reset) - to_chat(user, "\The [F] has been painted too much; you need to clear it off.") - return - - var/painting_dir = 0 - if(paint_dir == "precise") - if(!decal_data["precise"]) - painting_dir = user.dir - else - var/list/mouse_control = params2list(params) - var/mouse_x = text2num(mouse_control["icon-x"]) - var/mouse_y = text2num(mouse_control["icon-y"]) - if(isnum(mouse_x) && isnum(mouse_y)) - if(mouse_x <= 16) - if(mouse_y <= 16) - painting_dir = WEST - else - painting_dir = NORTH - else - if(mouse_y <= 16) - painting_dir = SOUTH - else - painting_dir = EAST - else - painting_dir = user.dir - else if(paint_dirs[paint_dir]) - painting_dir = paint_dirs[paint_dir] - - var/painting_colour - if(decal_data["coloured"] && paint_colour) - painting_colour = paint_colour - - playsound(get_turf(src), 'sound/effects/spray3.ogg', 30, 1, -6) - new painting_decal(F, painting_dir, painting_colour) - -/obj/item/floor_painter/attack_self(var/mob/user) - var/choice = input("What do you wish to change?") as null|anything in list("Decal","Direction", "Colour", "Preset Colour", "Mode") - if(choice == "Decal") - choose_decal() - else if(choice == "Direction") - choose_direction() - else if(choice == "Colour") - choose_colour() - else if(choice == "Preset Colour") - choose_preset_colour() - else if(choice == "Mode") - toggle_mode() - -/obj/item/floor_painter/examine(mob/user) - . = ..(user) - to_chat(user, "It is configured to produce the '[decal]' decal with a direction of '[paint_dir]' using [paint_colour] paint.") - -/obj/item/floor_painter/verb/choose_colour() - set name = "Choose Colour" - set desc = "Choose a paintgun colour." - set category = "Object" - set src in usr - - if(usr.incapacitated()) - return - var/new_colour = input(usr, "Choose a colour.", "paintgun", paint_colour) as color|null - if(new_colour && new_colour != paint_colour) - paint_colour = new_colour - to_chat(usr, "You set \the [src] to paint with a new colour.") - -/obj/item/floor_painter/verb/choose_preset_colour() - set name = "Choose Preset Colour" - set desc = "Choose a paintgun colour." - set category = "Object" - set src in usr - - if(usr.incapacitated()) - return - var/new_colour = input(usr, "Choose a colour.", "paintgun", paint_colour) as color|anything in preset_colors - if(new_colour && new_colour != paint_colour) - paint_colour = preset_colors[new_colour] - to_chat(usr, "You set \the [src] to paint with a new colour.") - -/obj/item/floor_painter/verb/choose_decal() - set name = "Choose Decal" - set desc = "Choose a paintgun decal." - set category = "Object" - set src in usr - - if(usr.incapacitated()) - return - - var/new_decal = input("Select a decal.") as null|anything in decals - if(new_decal && !isnull(decals[new_decal])) - decal = new_decal - to_chat(usr, "You set \the [src] decal to '[decal]'.") - -/obj/item/floor_painter/verb/choose_direction() - set name = "Choose Direction" - set desc = "Choose a paintgun direction." - set category = "Object" - set src in usr - - if(usr.incapacitated()) - return - - var/new_dir = input("Select a direction.") as null|anything in paint_dirs - if(new_dir && !isnull(paint_dirs[new_dir])) - paint_dir = new_dir - to_chat(usr, "You set \the [src] direction to '[paint_dir]'.") - -/obj/item/floor_painter/verb/toggle_mode() - set name = "Toggle Painter Mode" - set desc = "Choose a paintgun mode." - set category = "Object" - set src in usr - - if(usr.incapacitated()) - return - color_picker = !color_picker - if(color_picker) - to_chat(usr, "You set \the [src] to color picker mode, scanning colors off objects.") - else - to_chat(usr, "You set \the [src] to painting mode.") \ No newline at end of file diff --git a/code/game/objects/items/devices/paint_sprayer.dm b/code/game/objects/items/devices/paint_sprayer.dm new file mode 100644 index 000000000000..a6c34a1707b9 --- /dev/null +++ b/code/game/objects/items/devices/paint_sprayer.dm @@ -0,0 +1,468 @@ +#define PAINT_REGION_PAINT "Paint" +#define PAINT_REGION_STRIPE "Stripe" +#define PAINT_REGION_WINDOW "Window" + +/obj/item/paint_sprayer + name = "paint sprayer" + icon = 'icons/obj/items/device/paint_sprayer.dmi' + icon_state = ICON_STATE_WORLD + desc = "A slender and none-too-sophisticated device capable of applying paint on floors, walls, exosuits and certain airlocks." + material = /decl/material/solid/metal/stainlesssteel + var/decal = "Quarter-turf" + var/paint_dir = "Precise" + var/spray_color = COLOR_GRAY15 + var/color_picker = FALSE + + var/list/decals = list( + "Quarter-turf" = list("path" = /obj/effect/floor_decal/corner, "precise" = 1, "colored" = 1), + "Monotile full" = list("path" = /obj/effect/floor_decal/corner/white/mono, "colored" = 1), + "Monotile halved" = list("path" = /obj/effect/floor_decal/corner/white/half, "colored" = 1), + "Hazard stripes" = list("path" = /obj/effect/floor_decal/industrial/warning), + "Corner, hazard" = list("path" = /obj/effect/floor_decal/industrial/warning/corner), + "Hatched marking" = list("path" = /obj/effect/floor_decal/industrial/hatch, "colored" = 1), + "Dashed outline" = list("path" = /obj/effect/floor_decal/industrial/outline, "colored" = 1), + "Loading sign" = list("path" = /obj/effect/floor_decal/industrial/loading), + "Mosaic, large" = list("path" = /obj/effect/floor_decal/chapel), + "1" = list("path" = /obj/effect/floor_decal/sign), + "2" = list("path" = /obj/effect/floor_decal/sign/two), + "A" = list("path" = /obj/effect/floor_decal/sign/a), + "B" = list("path" = /obj/effect/floor_decal/sign/b), + "C" = list("path" = /obj/effect/floor_decal/sign/c), + "D" = list("path" = /obj/effect/floor_decal/sign/d), + "M" = list("path" = /obj/effect/floor_decal/sign/m), + "V" = list("path" = /obj/effect/floor_decal/sign/v), + "CMO" = list("path" = /obj/effect/floor_decal/sign/cmo), + "Ex" = list("path" = /obj/effect/floor_decal/sign/ex), + "Psy" = list("path" = /obj/effect/floor_decal/sign/p), + "Remove all decals" = list("path" = /obj/effect/floor_decal/reset), + "Remove top decal" = list("path" = /obj/effect/floor_decal/undo) + ) + + var/list/paint_dirs = list( + "North" = NORTH, + "Northwest" = NORTHWEST, + "West" = WEST, + "Southwest" = SOUTHWEST, + "South" = SOUTH, + "Southeast" = SOUTHEAST, + "East" = EAST, + "Northeast" = NORTHEAST, + "Precise" = 0 + ) + + var/list/preset_colors = list( + "Beasty brown" = COLOR_BEASTY_BROWN, + "Blue" = COLOR_BLUE_GRAY, + "Civvie green" = COLOR_CIVIE_GREEN, + "Command blue" = COLOR_COMMAND_BLUE, + "Cyan" = COLOR_CYAN, + "Green" = COLOR_GREEN, + "Bottle green" = COLOR_PALE_BTL_GREEN, + "Nanotrasen red" = COLOR_NT_RED, + "Orange" = COLOR_ORANGE, + "Pale orange" = COLOR_PALE_ORANGE, + "Red" = COLOR_RED, + "Sky blue" = COLOR_DEEP_SKY_BLUE, + "Titanium" = COLOR_TITANIUM, + "Aluminium"= COLOR_ALUMINIUM, + "Violet" = COLOR_VIOLET, + "White" = COLOR_WHITE, + "Yellow" = COLOR_AMBER, + "Hull blue" = COLOR_HULL, + "Bulkhead black" = COLOR_WALL_GUNMETAL + ) + + +/obj/item/paint_sprayer/Initialize() + . = ..() + var/random_preset = pick(preset_colors) + change_color(preset_colors[random_preset]) + +/obj/item/paint_sprayer/on_update_icon() + . = ..() + add_overlay(overlay_image(icon, "[icon_state]_color", spray_color)) + add_overlay(color_picker ? "[icon_state]_red" : "[icon_state]_blue") + if(isliving(loc)) + var/mob/M = loc + M.update_inhand_overlays() + +/obj/item/paint_sprayer/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && check_state_in_icon("[overlay.icon_state]_color", overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]_color", spray_color) + . = ..() + +/obj/item/paint_sprayer/afterattack(var/atom/A, var/mob/user, var/proximity, var/params) + if (!proximity) + return + + add_fingerprint(user) + + if (color_picker) + var/new_color + if (istype(A, /turf/floor)) + new_color = pick_color_from_floor(A, user) + else if (istype(A, /obj/machinery/door/airlock)) + new_color = pick_color_from_airlock(A, user) + else if (istype(A, /turf/wall)) + new_color = pick_color_from_wall(A, user) + else if (istype(A, /obj/structure/wall_frame)) + new_color = pick_color_from_wall_frame(A, user) + else + new_color = A.get_color() + if(!new_color) + to_chat(user, SPAN_NOTICE("You fail to scan a color from \the [A].")) + else + change_color(new_color, user) + + else if(istype(A, /obj/item/card/data)) // TODO: un-hardcode this please. better yet redo how this entire proc is done + var/obj/item/card/data/data_card = A + data_card.detail_color = spray_color + . = TRUE + + else if (istype(A, /turf/wall)) + . = paint_wall(A, user) + + else if (istype(A, /obj/structure/wall_frame)) + . = paint_wall_frame(A, user) + + else if (istype(A, /turf/floor)) + . = paint_floor(A, user, params) + + else if (istype(A, /obj/machinery/door/airlock)) + . = paint_airlock(A, user) + + else if (isexosuit(A)) + to_chat(user, SPAN_WARNING("You can't paint an active exosuit. Dismantle it first.")) + . = FALSE + + else if (A.atom_flags & ATOM_FLAG_CAN_BE_PAINTED) + A.set_color(spray_color) + . = TRUE + + else + to_chat(user, SPAN_WARNING("\The [src] can only be used on floors, windows, walls, exosuits, airlocks, and certain other objects.")) + . = FALSE + + if (.) + playsound(get_turf(src), 'sound/effects/spray3.ogg', 30, 1, -6) + return . + + +/obj/item/paint_sprayer/proc/paint_wall(var/turf/wall/wall, var/mob/user) + if(istype(wall) && (!wall.material || !wall.material.wall_flags)) + to_chat(user, SPAN_WARNING("You can't paint this wall type.")) + return + var/choice + if(wall.material.wall_flags & PAINT_PAINTABLE && wall.material.wall_flags & PAINT_STRIPABLE) + choice = input(user, "What do you wish to paint?") as null|anything in list(PAINT_REGION_PAINT,PAINT_REGION_STRIPE) + else if(wall.material.wall_flags & PAINT_PAINTABLE) + choice = PAINT_REGION_PAINT + else if(wall.material.wall_flags & PAINT_STRIPABLE) + choice = PAINT_REGION_STRIPE + if (user.incapacitated() || !wall || !user.Adjacent(wall)) + return FALSE + if(choice == PAINT_REGION_PAINT) + wall.paint_wall(spray_color) + else if(choice == PAINT_REGION_STRIPE) + wall.stripe_wall(spray_color) + + +/obj/item/paint_sprayer/proc/pick_color_from_wall(var/turf/wall/wall, var/mob/user) + if (!wall.material || !wall.material.wall_flags) + return FALSE + + switch (select_wall_region(wall, user, "Where do you wish to select the color from?")) + if (PAINT_REGION_PAINT) + return wall.paint_color + if (PAINT_REGION_STRIPE) + return wall.stripe_color + else + return FALSE + + +/obj/item/paint_sprayer/proc/select_wall_region(var/turf/wall/wall, var/mob/user, var/input_text) + var/list/choices = list() + if (wall.material.wall_flags & PAINT_PAINTABLE) + choices |= PAINT_REGION_PAINT + if (wall.material.wall_flags & PAINT_STRIPABLE) + choices |= PAINT_REGION_STRIPE + var/choice = input(user, input_text) as null|anything in sortTim(choices, /proc/cmp_text_asc) + if (user.incapacitated() || !wall || !user.Adjacent(wall)) + return FALSE + return choice + + +/obj/item/paint_sprayer/proc/paint_wall_frame(var/obj/structure/wall_frame/WF, var/mob/user) + var/choice = input(user, "What do you wish to paint?") as null|anything in list(PAINT_REGION_PAINT,PAINT_REGION_STRIPE) + if (user.incapacitated() || !WF || !user.Adjacent(WF)) + return FALSE + if(choice == PAINT_REGION_PAINT) + WF.paint_wall_frame(spray_color) + else if(choice == PAINT_REGION_STRIPE) + WF.stripe_wall_frame(spray_color) + + +/obj/item/paint_sprayer/proc/pick_color_from_wall_frame(var/obj/structure/wall_frame/WF, var/mob/user) + switch (select_wall_frame_region(WF, user, "Where do you wish to select the color from?")) + if (PAINT_REGION_PAINT) + return WF.paint_color + if (PAINT_REGION_STRIPE) + return WF.stripe_color + else + return FALSE + + +/obj/item/paint_sprayer/proc/select_wall_frame_region(var/obj/structure/wall_frame/WF, var/mob/user, var/input_text) + var/list/choices = list(PAINT_REGION_PAINT, PAINT_REGION_STRIPE) + var/choice = input(user, input_text) as null|anything in sortTim(choices, /proc/cmp_text_asc) + if (user.incapacitated() || !WF || !user.Adjacent(WF)) + return FALSE + return choice + + +/obj/item/paint_sprayer/proc/paint_floor(var/turf/floor/F, var/mob/user, var/params) + + var/decl/flooring/flooring = F.get_topmost_flooring() + if(!istype(flooring)) + to_chat(user, SPAN_WARNING("You need flooring to paint on.")) + return FALSE + + if(!flooring.can_paint || F.is_floor_damaged()) + to_chat(user, SPAN_WARNING("\The [src] cannot paint \the [F].")) + return FALSE + + var/list/decal_data = decals[decal] + var/config_error + if(!islist(decal_data)) + config_error = 1 + var/painting_decal + if(!config_error) + painting_decal = decal_data["path"] + if(!ispath(painting_decal)) + config_error = 1 + + if(config_error) + to_chat(user, SPAN_WARNING("\The [src] flashes an error light. You might need to reconfigure it.")) + return FALSE + + if(F.decals && F.decals.len > 5 && painting_decal != /obj/effect/floor_decal/reset) + to_chat(user, SPAN_WARNING("\The [F] has been painted too much; you need to clear it off.")) + return FALSE + + var/painting_dir = 0 + if(paint_dir == "Precise") + if(!decal_data["precise"]) + painting_dir = user.dir + else + var/list/mouse_control = params2list(params) + var/mouse_x = text2num(mouse_control["icon-x"]) + var/mouse_y = text2num(mouse_control["icon-y"]) + if(isnum(mouse_x) && isnum(mouse_y)) + if(mouse_x <= 16) + if(mouse_y <= 16) + painting_dir = WEST + else + painting_dir = NORTH + else + if(mouse_y <= 16) + painting_dir = SOUTH + else + painting_dir = EAST + else + painting_dir = user.dir + else if(paint_dirs[paint_dir]) + painting_dir = paint_dirs[paint_dir] + + var/painting_color + if(decal_data["colored"] && spray_color) + painting_color = spray_color + + new painting_decal(F, painting_dir, painting_color) + return TRUE + + +/obj/item/paint_sprayer/proc/pick_color_from_floor(var/turf/floor/F, var/mob/user) + if (!F.decals || !F.decals.len) + return FALSE + var/list/available_colors = list() + for (var/image/I in F.decals) + available_colors |= isnull(I.color) ? COLOR_WHITE : I.color + if (!LAZYLEN(available_colors)) + return FALSE + var/picked_color = available_colors[1] + if (available_colors.len > 1) + picked_color = input(user, "Which color do you wish to select?") as null|anything in available_colors + if (user.incapacitated() || !user.Adjacent(F)) // must check due to input blocking + return FALSE + return picked_color + + +/obj/item/paint_sprayer/proc/paint_airlock(var/obj/machinery/door/airlock/D, var/mob/user) + if (!D.paintable) + to_chat(user, SPAN_WARNING("You can't paint this airlock type.")) + return FALSE + + switch (select_airlock_region(D, user, "What do you wish to paint?")) + if (PAINT_REGION_PAINT) + D.paint_airlock(spray_color) + if (PAINT_REGION_STRIPE) + D.stripe_airlock(spray_color) + if (PAINT_REGION_WINDOW) + D.paint_window(spray_color) + else + return FALSE + return TRUE + + +/obj/item/paint_sprayer/proc/pick_color_from_airlock(var/obj/machinery/door/airlock/D, var/mob/user) + if (!D.paintable) + return FALSE + + switch (select_airlock_region(D, user, "Where do you wish to select the color from?")) + if (PAINT_REGION_PAINT) + return D.door_color + if (PAINT_REGION_STRIPE) + return D.stripe_color + if (PAINT_REGION_WINDOW) + return D.window_color + else + return FALSE + + +/obj/item/paint_sprayer/proc/select_airlock_region(var/obj/machinery/door/airlock/D, var/mob/user, var/input_text) + var/choice + var/list/choices = list() + if (D.paintable & PAINT_PAINTABLE) + choices |= PAINT_REGION_PAINT + if (D.paintable & PAINT_STRIPABLE) + choices |= PAINT_REGION_STRIPE + if (D.paintable & PAINT_WINDOW_PAINTABLE) + choices |= PAINT_REGION_WINDOW + choice = input(user, input_text) as null|anything in sortTim(choices, /proc/cmp_text_asc) + if (user.incapacitated() || !D || !user.Adjacent(D)) + return FALSE + return choice + + +/obj/item/paint_sprayer/attack_self(var/mob/user) + switch(input("What do you wish to change?") as null|anything in list("Decal","Direction", "Color", "Preset Color", "Mode")) + if("Decal") + choose_decal() + if("Direction") + choose_direction() + if("Color") + choose_color() + if("Preset Color") + choose_preset_color() + if("Mode") + toggle_mode() + + +/obj/item/paint_sprayer/proc/change_color(var/new_color, var/mob/user) + if (new_color && new_color != spray_color) + spray_color = new_color + if (user) + to_chat(user, SPAN_NOTICE("You set \the [src] to paint with a new color.")) + update_icon() + + +/obj/item/paint_sprayer/get_examine_strings(mob/user, distance, infix, suffix) + . = ..(user) + . += "It is configured to produce the '[decal]' decal with a direction of '[paint_dir]' using [spray_color] paint." + +/obj/item/paint_sprayer/CtrlClick() + if (!isturf(loc)) + toggle_mode() + else + . = ..() + + +/obj/item/paint_sprayer/verb/choose_color() + set name = "Choose color" + set desc = "Choose a color." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + var/new_color = input(usr, "Choose a color.", name, spray_color) as color|null + if (usr.incapacitated()) + return + change_color(new_color, usr) + +/obj/item/paint_sprayer/verb/choose_preset_color() + set name = "Choose Preset color" + set desc = "Choose a preset color." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + var/preset = input(usr, "Choose a color.", name, spray_color) as null|anything in preset_colors + if(usr.incapacitated()) + return + change_color(preset_colors[preset], usr) + +/obj/item/paint_sprayer/verb/choose_decal() + set name = "Choose Decal" + set desc = "Choose a flooring decal." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + var/new_decal = input("Select a decal.") as null|anything in decals + if(usr.incapacitated()) + return + if(new_decal && !isnull(decals[new_decal])) + decal = new_decal + to_chat(usr, SPAN_NOTICE("You set \the [src] decal to '[decal]'.")) + +/obj/item/paint_sprayer/verb/choose_direction() + set name = "Choose Direction" + set desc = "Choose a decal direction." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + var/new_dir = input("Select a direction.") as null|anything in paint_dirs + if(usr.incapacitated()) + return + if(new_dir && !isnull(paint_dirs[new_dir])) + paint_dir = new_dir + to_chat(usr, SPAN_NOTICE("You set \the [src] direction to '[paint_dir]'.")) + +/obj/item/paint_sprayer/verb/toggle_mode() + set name = "Toggle Painter Mode" + set desc = "Toggle to switch between color picking and paint spraying." + set category = "Object" + set src in usr + + if(usr.incapacitated()) + return + color_picker = !color_picker + if(color_picker) + to_chat(usr, SPAN_NOTICE("You set \the [src] to color picking mode, scanning colors off objects.")) + else + to_chat(usr, SPAN_NOTICE("You set \the [src] to painting mode.")) + playsound(src, 'sound/weapons/flipblade.ogg', 30, 1) + update_icon() + +#undef PAINT_REGION_PAINT +#undef PAINT_REGION_STRIPE +#undef PAINT_REGION_WINDOW + +/obj/item/paint_sprayer/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/paint_sprayer_colour) + +/decl/interaction_handler/paint_sprayer_colour + name = "Change Color Preset" + expected_target_type = /obj/item/paint_sprayer + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEEDS_INVENTORY + examine_desc = "change the color preset" + +/decl/interaction_handler/paint_sprayer_colour/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/paint_sprayer/sprayer = target + sprayer.choose_preset_color() diff --git a/code/game/objects/items/devices/personal_shield.dm b/code/game/objects/items/devices/personal_shield.dm index 08a1e63e40c1..c88b59712e98 100644 --- a/code/game/objects/items/devices/personal_shield.dm +++ b/code/game/objects/items/devices/personal_shield.dm @@ -1,38 +1,55 @@ /obj/item/personal_shield name = "personal shield" - desc = "Truely a life-saver: this device protects its user from being hit by objects moving very, very fast, though only for a few shots." + desc = "Truly a lifesaver: this device protects its user from being hit by objects moving very, very fast, though only for a few shots." icon = 'icons/obj/items/weapon/batterer.dmi' - icon_state = "batterer" + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/titanium = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, + ) var/uses = 5 - var/obj/aura/personal_shield/device/shield + var/shield_effect_type = /decl/mob_modifier/shield/device -/obj/item/personal_shield/attack_self(var/mob/living/user) - if(uses && !shield) - shield = new(user,src) - else - QDEL_NULL(shield) +/obj/item/personal_shield/attack_self(var/mob/user) + if(loc == user && isliving(user)) + var/mob/living/holder = user + if(holder.has_mob_modifier(shield_effect_type, source = src)) + holder.remove_mob_modifier(shield_effect_type, source = src) + else if(uses && shield_effect_type) + holder.add_mob_modifier(shield_effect_type, source = src) + else + return ..() + return TRUE + return ..() /obj/item/personal_shield/Move() - QDEL_NULL(shield) - return ..() + var/mob/living/holder = loc + . = ..() + if(. && istype(holder) && holder.has_mob_modifier(shield_effect_type, source = src)) + holder.remove_mob_modifier(shield_effect_type, source = src) /obj/item/personal_shield/forceMove() - QDEL_NULL(shield) - return ..() + var/mob/living/holder = loc + . = ..() + if(. && istype(holder) && holder.has_mob_modifier(shield_effect_type, source = src)) + holder.remove_mob_modifier(shield_effect_type, source = src) -/obj/item/personal_shield/proc/take_charge() - if(!--uses) - QDEL_NULL(shield) - to_chat(loc,"\The [src] begins to spark as it breaks!") +/obj/item/personal_shield/proc/expend_charge() + if(uses <= 0) + return FALSE + uses-- + if(uses <= 0 && ismob(loc)) + var/mob/living/holder = loc + if(istype(holder) && holder.has_mob_modifier(shield_effect_type, source = src)) + holder.remove_mob_modifier(shield_effect_type, source = src) + to_chat(holder, SPAN_DANGER("\The [src] begins to spark as it breaks!")) update_icon() - return + return TRUE /obj/item/personal_shield/on_update_icon() + . = ..() if(uses) - icon_state = "batterer" - else - icon_state = "battererburnt" - -/obj/item/personal_shield/Destroy() - QDEL_NULL(shield) - return ..() \ No newline at end of file + add_overlay("[icon_state]-on") \ No newline at end of file diff --git a/code/game/objects/items/devices/pinpointer.dm b/code/game/objects/items/devices/pinpointer.dm index f894df5542bf..b9624ebf4803 100644 --- a/code/game/objects/items/devices/pinpointer.dm +++ b/code/game/objects/items/devices/pinpointer.dm @@ -1,11 +1,10 @@ /obj/item/pinpointer name = "pinpointer" icon = 'icons/obj/items/device/pinpointer.dmi' - icon_state = "pinoff" + icon_state = ICON_STATE_WORLD obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL - item_state = "electronic" material = /decl/material/solid/metal/steel var/weakref/target var/active = 0 @@ -16,6 +15,9 @@ target = null . = ..() +/obj/item/pinpointer/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE + /obj/item/pinpointer/attack_self(mob/user) toggle(user) @@ -74,35 +76,35 @@ beeping-- /obj/item/pinpointer/on_update_icon() - overlays.Cut() + . = ..() if(!active) return if(!target || !target.resolve()) - overlays += image(icon,"pin_invalid") + add_overlay("[icon_state]-invalid") return var/turf/here = get_turf(src) var/turf/there = get_turf(target.resolve()) if(!istype(there)) - overlays += image(icon,"pin_invalid") + add_overlay("[icon_state]-invalid") return if(here == there) - overlays += image(icon,"pin_here") + add_overlay("[icon_state]-here") return - if(!(there.z in GetConnectedZlevels(here.z))) - overlays += image(icon,"pin_invalid") + if(!(there.z in SSmapping.get_connected_levels(here.z))) + add_overlay("[icon_state]-invalid") return if(here.z > there.z) - overlays += image(icon,"pin_down") + add_overlay("[icon_state]-down") return if(here.z < there.z) - overlays += image(icon,"pin_up") + add_overlay("[icon_state]-up") return set_dir(get_dir(here, there)) - var/image/pointer = image(icon,"pin_point") + var/image/pointer = image(icon,"[icon_state]-point") var/distance = get_dist(here,there) if(distance < world.view) pointer.color = COLOR_LIME @@ -110,28 +112,28 @@ pointer.color = COLOR_RED else pointer.color = COLOR_YELLOW - overlays += pointer + add_overlay(pointer) //Radio beacon locator /obj/item/pinpointer/radio name = "locator device" desc = "Used to scan and locate signals on a particular frequency." material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) var/tracking_freq = PUB_FREQ /obj/item/pinpointer/radio/acquire_target() var/turf/T = get_turf(src) - var/zlevels = GetConnectedZlevels(T.z) + var/zlevels = SSmapping.get_connected_levels(T.z) var/cur_dist = world.maxx+world.maxy - for(var/obj/item/radio/beacon/R in world) - if(!R.functioning) + for(var/obj/item/radio/beacon/radio in global.radio_beacons) + if(!radio.functioning) continue - if((R.z in zlevels) && R.frequency == tracking_freq) - var/check_dist = get_dist(src,R) + if((radio.z in zlevels) && radio.frequency == tracking_freq) + var/check_dist = get_dist(src, radio) if(check_dist < cur_dist) cur_dist = check_dist - . = weakref(R) + . = weakref(radio) /obj/item/pinpointer/radio/attack_self(var/mob/user) interact(user) @@ -194,13 +196,13 @@ var/turf/Z = get_turf(src) var/turf/location = locate(locationx,locationy,Z.z) - to_chat(usr, "You set the pinpointer to locate [locationx],[locationy]") + to_chat(usr, "You set the pinpointer to locate [locationx],[locationy].") target = weakref(location) if("Other Signature") - var/itemlist = GLOB.using_map.get_theft_targets() | GLOB.using_map.get_special_theft_targets() + var/itemlist = global.using_map.get_theft_targets() | global.using_map.get_special_theft_targets() var/targetitem = input("Select item to search for.", "Item Mode Select","") as null|anything in itemlist if(!targetitem) return @@ -208,16 +210,14 @@ if(!item) to_chat(usr, "Failed to locate [targetitem]!") return - to_chat(usr, "You set the pinpointer to locate [targetitem]") + to_chat(usr, "You set the pinpointer to locate [targetitem].") target = weakref(item) if("DNA") var/DNAstring = input("Input DNA string to search for." , "Please Enter String." , "") if(!DNAstring) return - for(var/mob/living/carbon/M in SSmobs.mob_list) - if(!M.dna) - continue - if(M.dna.unique_enzymes == DNAstring) + for(var/mob/living/M in SSmobs.mob_list) + if(M.get_unique_enzymes() == DNAstring) target = weakref(M) break \ No newline at end of file diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm deleted file mode 100644 index 6764a098fee7..000000000000 --- a/code/game/objects/items/devices/pipe_painter.dm +++ /dev/null @@ -1,32 +0,0 @@ -/obj/item/pipe_painter - name = "pipe painter" - icon = 'icons/obj/items/device/pipe_painter.dmi' - icon_state = "pipainter" - item_state = "flight" - desc = "A long, slender device consisting of a pigment synthesizer, dual applicators, and a small battery, all hooked up to a long extendable rod." - var/list/modes - var/mode - -/obj/item/pipe_painter/Initialize() - . = ..() - modes = new() - for(var/C in pipe_colors) - modes += "[C]" - mode = pick(modes) - -/obj/item/pipe_painter/afterattack(atom/A, mob/user, proximity) - if(!proximity) - return - - if(!istype(A,/obj/machinery/atmospherics/pipe) || istype(A,/obj/machinery/atmospherics/unary/tank) || istype(A,/obj/machinery/atmospherics/pipe/vent) || istype(A,/obj/machinery/atmospherics/pipe/simple/heat_exchanging) || !in_range(user, A)) - return - var/obj/machinery/atmospherics/pipe/P = A - - P.change_color(pipe_colors[mode]) - -/obj/item/pipe_painter/attack_self(mob/user) - mode = input("Which colour do you want to use?", "Pipe painter", mode) in modes - -/obj/item/pipe_painter/examine(mob/user) - . = ..(user) - to_chat(user, "It is in [mode] mode.") diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 4b3016720408..9af027725ba4 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -4,25 +4,20 @@ name = "power sink" desc = "A nulling power sink which drains energy from electrical systems." icon = 'icons/obj/items/device/powersink.dmi' - icon_state = "powersink0" - item_state = "electronic" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_LARGE obj_flags = OBJ_FLAG_CONDUCTIBLE - throwforce = 5 throw_speed = 1 throw_range = 2 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/slag = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/metallic_hydrogen = MATTER_AMOUNT_REINFORCEMENT) - origin_tech = "{'powerstorage':3,'esoteric':5}" + origin_tech = @'{"powerstorage":3,"esoteric":5}' var/drain_rate = 1500000 // amount of power to drain per tick - var/apc_drain_rate = 5000 // Max. amount drained from single APC. In Watts. - var/dissipation_rate = 20000 // Passive dissipation of drained power. In Watts. var/power_drained = 0 // Amount of power drained. var/max_power = 5e9 // Detonation point. var/mode = 0 // 0 = off, 1=clamped (off), 2=operating - var/datum/powernet/PN // Our powernet var/const/DISCONNECTED = 0 var/const/CLAMPED_OFF = 1 @@ -31,7 +26,14 @@ var/obj/structure/cable/attached // the attached cable /obj/item/powersink/on_update_icon() - icon_state = "powersink[mode == OPERATING]" + . = ..() + z_flags &= ~ZMM_MANGLE_PLANES + if(mode == OPERATING) + if(plane == HUD_PLANE) + add_overlay("[icon_state]-on") + else + add_overlay(emissive_overlay(icon, "[icon_state]-on")) + z_flags |= ~ZMM_MANGLE_PLANES /obj/item/powersink/proc/set_mode(value) if(value == mode) @@ -65,8 +67,8 @@ STOP_PROCESSING_POWER_OBJECT(src) . = ..() -/obj/item/powersink/attackby(var/obj/item/I, var/mob/user) - if(isScrewdriver(I)) +/obj/item/powersink/attackby(var/obj/item/used_item, var/mob/user) + if(IS_SCREWDRIVER(used_item)) if(mode == DISCONNECTED) var/turf/T = loc if(isturf(T) && !!T.is_plating()) @@ -87,6 +89,7 @@ "[user] detaches \the [src] from the cable.", \ "You detach \the [src] from the cable.", "You hear some wires being disconnected from something.") + return TRUE else return ..() @@ -94,28 +97,28 @@ return /obj/item/powersink/attack_hand(var/mob/user) - . = ..() - if(.) - return - switch(mode) - if(DISCONNECTED) - ..() - - if(CLAMPED_OFF) - user.visible_message( \ - "[user] activates \the [src]!", \ - "You activate \the [src].", - "You hear a click.") - message_admins("Power sink activated by [key_name_admin(user)] at (JMP)") - log_game("Power sink activated by [key_name(user)] at [get_area_name(src)]") - set_mode(OPERATING) - - if(OPERATING) - user.visible_message( \ - "[user] deactivates \the [src]!", \ - "You deactivate \the [src].", - "You hear a click.") - set_mode(CLAMPED_OFF) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + if(mode == CLAMPED_OFF) + user.visible_message( + "[user] activates \the [src]!", + SPAN_NOTICE("You activate \the [src]."), + SPAN_ITALIC("You hear a click.") + ) + message_admins("Power sink activated by [key_name_admin(user)] at (JMP)") + log_game("Power sink activated by [key_name(user)] at [get_area_name(src)]") + set_mode(OPERATING) + return TRUE + + if(mode == OPERATING) + user.visible_message( \ + "[user] deactivates \the [src]!", \ + "You deactivate \the [src].", + "You hear a click.") + set_mode(CLAMPED_OFF) + return TRUE + + return ..() /obj/item/powersink/pwr_drain() if(!attached) @@ -125,7 +128,7 @@ var/datum/powernet/PN = attached.powernet var/drained = 0 if(PN) - set_light(0.5, 0.1, 12) + set_light(12) PN.trigger_warning() // found a powernet, so drain up to max power from it drained = PN.draw_power(drain_rate) @@ -136,7 +139,7 @@ // Enough power drained this tick, no need to torture more APCs if(drained >= drain_rate) break - var/obj/machinery/power/apc/A = T.master_machine() + var/obj/machinery/apc/A = T.master_machine() if(istype(A)) drained += A.drain_power(amount = drain_rate) power_drained += drained diff --git a/code/game/objects/items/devices/radio/beacon.dm b/code/game/objects/items/devices/radio/beacon.dm index 9148a18f60e0..1cda309212b5 100644 --- a/code/game/objects/items/devices/radio/beacon.dm +++ b/code/game/objects/items/devices/radio/beacon.dm @@ -1,22 +1,32 @@ +var/global/list/radio_beacons = list() + /obj/item/radio/beacon name = "tracking beacon" desc = "A beacon used by a teleporter." icon = 'icons/obj/items/device/radio/beacon.dmi' icon_state = "beacon" item_state = "signaler" - origin_tech = "{'wormholes':1}" + origin_tech = @'{"wormholes":1}' material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) var/code = "electronic" var/functioning = TRUE +/obj/item/radio/beacon/Initialize() + . = ..() + global.radio_beacons += src + +/obj/item/radio/beacon/Destroy() + global.radio_beacons -= src + . = ..() + +/obj/item/radio/beacon/toggle_panel(var/mob/user) + return FALSE + /obj/item/radio/beacon/hear_talk() return -/obj/item/radio/beacon/send_hear() - return null - /obj/item/radio/beacon/emp_act(severity) if(functioning && severity >= 1) fry() @@ -35,6 +45,7 @@ T.target_lost() /obj/item/radio/beacon/on_update_icon() + . = ..() if(!functioning) icon_state = "[initial(icon_state)]_dead" else @@ -55,7 +66,7 @@ anchored = TRUE w_class = ITEM_SIZE_HUGE randpixel = 0 - + var/repair_fail_chance = 35 /obj/item/radio/beacon/anchored/Initialize() @@ -63,22 +74,31 @@ var/turf/T = get_turf(src) hide(hides_under_flooring() && !T.is_plating()) -/obj/item/radio/beacon/anchored/attackby(obj/item/I, mob/living/user) - ..() - if(istype(I, /obj/item/stack/nanopaste)) - var/obj/item/stack/nanopaste/S = I - if(b_stat) - if(S.use(1)) - to_chat(user, SPAN_NOTICE("You pour some of \the [S] over \the [src]'s circuitry.")) - if(prob(repair_fail_chance)) - flick("[initial(icon_state)]", src) - visible_message(SPAN_WARNING("The [src]'s lights come back on briefly, then die out again."), range = 2) - else - visible_message(SPAN_NOTICE("\The [src]'s lights come back on."), range = 2) - functioning = TRUE - repair_fail_chance += pick(5, 10, 10, 15) - update_icon() - else - to_chat(user, SPAN_WARNING("There's not enough of \the [S] left to fix \the [src].")) +/obj/item/radio/beacon/anchored/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/stack/nanopaste)) + if(functioning) + to_chat(user, SPAN_WARNING("\The [src] does not need any repairs.")) + return TRUE + if(repair_fail_chance >= 100) + to_chat(user, SPAN_WARNING("\The [src] is completely irrepairable.")) + return TRUE + + var/obj/item/stack/nanopaste/S = used_item + if(!panel_open) + to_chat(user, SPAN_WARNING("You can't work on \the [src] until its been opened up.")) + return TRUE + if(!S.use(1)) + to_chat(user, SPAN_WARNING("There's not enough of \the [S] left to fix \the [src].")) + return TRUE + to_chat(user, SPAN_NOTICE("You pour some of \the [S] over \the [src]'s circuitry.")) + if(prob(repair_fail_chance)) + flick("[initial(icon_state)]", src) + visible_message(SPAN_WARNING("\The [src]'s lights come back on briefly, then die out again."), range = 2) else - to_chat(user, SPAN_WARNING("You can't work on \the [src] until its been opened up.")) \ No newline at end of file + visible_message(SPAN_NOTICE("\The [src]'s lights come back on."), range = 2) + functioning = TRUE + repair_fail_chance += pick(5, 10, 10, 15) + update_icon() + return TRUE + + . = ..() diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm deleted file mode 100644 index e894d46ded2d..000000000000 --- a/code/game/objects/items/devices/radio/electropack.dm +++ /dev/null @@ -1,129 +0,0 @@ -/obj/item/radio/electropack - name = "electropack" - desc = "Dance, my monkeys! DANCE!" - icon = 'icons/obj/items/device/radio/electropack.dmi' - icon_state = "electropack0" - item_state = "electropack" - frequency = 1449 - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BACK - w_class = ITEM_SIZE_HUGE - - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - - var/code = 2 - -/obj/item/radio/electropack/attack_hand(mob/user) - if(src == user.back) - to_chat(user, "You need help taking this off!") - return - ..() - -/obj/item/radio/electropack/attackby(obj/item/W, mob/user) - ..() - if(istype(W, /obj/item/clothing/head/helmet)) - if(!b_stat) - to_chat(user, "[src] is not ready to be attached!") - return - if(!user.unEquip(W) || !user.unEquip(src)) - return - var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit( user ) - A.icon = 'icons/obj/assemblies.dmi' - - W.forceMove(A) - W.master = A - A.part1 = W - - forceMove(A) - master = A - A.part2 = src - - user.put_in_hands(A) - -/obj/item/radio/electropack/Topic(href, href_list) - //..() - if(usr.stat || usr.restrained()) - return - if(((istype(usr, /mob/living/carbon/human) && (usr.check_dexterity(DEXTERITY_COMPLEX_TOOLS) && usr.contents.Find(src))) || (usr.contents.Find(master) || (in_range(src, usr) && istype(loc, /turf))))) - usr.set_machine(src) - if(href_list["freq"]) - var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"])) - set_frequency(new_frequency) - else - if(href_list["code"]) - code += text2num(href_list["code"]) - code = round(code) - code = min(100, code) - code = max(1, code) - else - if(href_list["power"]) - on = !( on ) - icon_state = "electropack[on]" - if(!( master )) - if(istype(loc, /mob)) - attack_self(loc) - else - for(var/mob/M in viewers(1, src)) - if(M.client) - attack_self(M) - else - if(istype(master.loc, /mob)) - attack_self(master.loc) - else - for(var/mob/M in viewers(1, master)) - if(M.client) - attack_self(M) - else - close_browser(usr, "window=radio") - return - return - -/obj/item/radio/electropack/receive_signal(datum/signal/signal) - if(!signal || signal.encryption != code) - return - - if(ismob(loc) && on) - var/mob/M = loc - var/turf/T = M.loc - if(istype(T, /turf)) - if(!M.moved_recently && M.last_move) - M.moved_recently = 1 - step(M, M.last_move) - sleep(50) - if(M) - M.moved_recently = 0 - to_chat(M, "You feel a sharp shock!") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, M) - s.start() - - M.Weaken(10) - - if(master && wires & 1) - master.receive_signal() - return - -/obj/item/radio/electropack/attack_self(mob/user, flag1) - - if(!istype(user, /mob/living/carbon/human)) - return - user.set_machine(src) - var/dat = {" -Turn [on ? "Off" : "On"]
              -Frequency/Code for electropack:
              -Frequency: -- -- [format_frequency(frequency)] -+ -+
              - -Code: -- -- [code] -+ -+
              -
              "} - show_browser(user, dat, "window=radio") - onclose(user, "radio") - return diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index fe613f8d499c..bcc1ab952fbe 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -2,134 +2,61 @@ name = "standard encryption key" desc = "An encryption key for a radio headset. Contains cypherkeys." icon = 'icons/obj/items/device/radio/key.dmi' - icon_state = "cypherkey" - item_state = "" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - - var/translate_binary = 0 - var/translate_hive = 0 - var/syndie = 0 - var/list/channels = list() - -/obj/item/encryptionkey/attackby(obj/item/W, mob/user) - return - -/obj/item/encryptionkey/syndicate - icon_state = "cypherkey" - channels = list("Mercenary" = 1) - origin_tech = "{'esoteric':3}" - syndie = 1//Signifies that it de-crypts Syndicate transmissions - -/obj/item/encryptionkey/raider - icon_state = "cypherkey" - channels = list("Raider" = 1) - origin_tech = "{'esoteric':2}" - syndie = 1 + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + color = COLOR_GRAY80 + var/contact_color = COLOR_PALE_GOLD + var/fill_color = COLOR_MID_BLUE_GRAY + var/inlay_color = COLOR_RED + var/translate_binary + var/list/can_decrypt + +/obj/item/encryptionkey/Initialize() + . = ..() + update_icon() + +/obj/item/encryptionkey/on_update_icon() + . = ..() + if(contact_color) + var/image/I = image(icon, "[icon_state]_contact") + I.color = contact_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + if(fill_color) + var/image/I = image(icon, "[icon_state]_fill") + I.color = fill_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + if(inlay_color) + var/image/I = image(icon, "[icon_state]_inlay") + I.color = inlay_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/encryptionkey/attack_self(mob/user) + if(alert(user, "Do you wish to factory reset this encryption key? This will remove ALL channel access and cannot be undone.", "Factory Reset", "No", "Yes") == "Yes" && !user.incapacitated() && user.get_held_slot_for_item(src)) + can_decrypt = null + to_chat(user, "You depress the factory reset switch and flush \the [src].") + return TRUE + . = ..() + +/obj/item/encryptionkey/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/card/id)) + var/obj/item/card/id/id = used_item + var/list/access = id.GetAccess() + if(!length(access)) + to_chat(user, SPAN_WARNING("\The [used_item] has no access keys to copy.")) + return TRUE + LAZYINITLIST(can_decrypt) + can_decrypt |= access + UNSETEMPTY(can_decrypt) + to_chat(user, SPAN_NOTICE("You pass \the [used_item] across \the [src], copying the access keys into the encryption cache.")) + return TRUE + . = ..() /obj/item/encryptionkey/binary - icon_state = "cypherkey" - translate_binary = 1 - origin_tech = "{'esoteric':3}" - -/obj/item/encryptionkey/headset_sec - name = "security radio encryption key" - icon_state = "sec_cypherkey" - channels = list("Security" = 1) - -/obj/item/encryptionkey/headset_eng - name = "engineering radio encryption key" - icon_state = "eng_cypherkey" - channels = list("Engineering" = 1) - -/obj/item/encryptionkey/headset_rob - name = "robotics radio encryption key" - icon_state = "rob_cypherkey" - channels = list("Engineering" = 1, "Science" = 1) - -/obj/item/encryptionkey/headset_med - name = "medical radio encryption key" - icon_state = "med_cypherkey" - channels = list("Medical" = 1) - -/obj/item/encryptionkey/headset_sci - name = "science radio encryption key" - icon_state = "sci_cypherkey" - channels = list("Science" = 1) - -/obj/item/encryptionkey/headset_medsci - name = "medical research radio encryption key" - icon_state = "medsci_cypherkey" - channels = list("Medical" = 1, "Science" = 1) - -/obj/item/encryptionkey/headset_com - name = "command radio encryption key" - icon_state = "com_cypherkey" - channels = list("Command" = 1) - -/obj/item/encryptionkey/heads/captain - name = "captain's encryption key" - icon_state = "cap_cypherkey" - channels = list("Command" = 1, "Security" = 1, "Engineering" = 0, "Science" = 0, "Medical" = 0, "Supply" = 0, "Service" = 0) - -/obj/item/encryptionkey/heads/ai_integrated - name = "ai integrated encryption key" - desc = "Integrated encryption key." - icon_state = "cap_cypherkey" - channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "AI Private" = 1) - -/obj/item/encryptionkey/heads/rd - name = "chief science officer's encryption key" - icon_state = "rd_cypherkey" - channels = list("Science" = 1, "Command" = 1) - -/obj/item/encryptionkey/heads/hos - name = "head of security's encryption key" - icon_state = "hos_cypherkey" - channels = list("Security" = 1, "Command" = 1) - -/obj/item/encryptionkey/heads/ce - name = "chief engineer's encryption key" - icon_state = "ce_cypherkey" - channels = list("Engineering" = 1, "Command" = 1) - -/obj/item/encryptionkey/heads/cmo - name = "chief medical officer's encryption key" - icon_state = "cmo_cypherkey" - channels = list("Medical" = 1, "Command" = 1) - -/obj/item/encryptionkey/heads/hop - name = "head of personnel's encryption key" - icon_state = "hop_cypherkey" - channels = list("Supply" = 1, "Service" = 1, "Command" = 1, "Security" = 0) - -/obj/item/encryptionkey/headset_cargo - name = "supply radio encryption key" - icon_state = "cargo_cypherkey" - channels = list("Supply" = 1) - -/obj/item/encryptionkey/headset_service - name = "service radio encryption key" - icon_state = "srv_cypherkey" - channels = list("Service" = 1) - -/obj/item/encryptionkey/ert - name = "\improper ERT radio encryption key" - channels = list("Response Team" = 1, "Science" = 1, "Command" = 1, "Medical" = 1, "Engineering" = 1, "Security" = 1, "Supply" = 1, "Service" = 1) - -/obj/item/encryptionkey/specops //for events - name = "special operations radio encryption key" - icon_state = "bin_cypherkey" - channels = list("Special Ops" = 1) - origin_tech = "{'esoteric':2}" - -/obj/item/encryptionkey/entertainment - name = "entertainment radio key" - channels = list("Entertainment" = 1) - -/obj/item/encryptionkey/headset_mining - name = "prospector radio encryption key" - icon_state = "srv_cypherkey" - channels = list("Supply" = 1) \ No newline at end of file + translate_binary = TRUE + origin_tech = @'{"esoteric":3}' diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 81e432404a03..ed308e4410a9 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -1,385 +1,30 @@ /obj/item/radio/headset name = "radio headset" desc = "An updated, modular intercom that fits over the head. Takes encryption keys." - var/radio_desc = "" - icon = 'icons/obj/items/device/radio/headset.dmi' - icon_state = "headset" - item_state = "headset" + icon = 'icons/obj/items/device/radio/headsets/headset.dmi' + icon_state = ICON_STATE_WORLD material = /decl/material/solid/metal/aluminium - subspace_transmission = 1 canhear_range = 0 // can't hear headsets from very far away - slot_flags = SLOT_EARS - cell = null power_usage = 0 - var/translate_binary = 0 - var/list/encryption_keys = list() - var/max_keys = 2 - - //left for backward compatability - var/ks1type = /obj/item/encryptionkey - var/ks2type = null - -/obj/item/radio/headset/Initialize() - . = ..() - internal_channels.Cut() - for(var/T in encryption_keys) - if(ispath(T)) - encryption_keys = new T(src) - if(ks1type) - encryption_keys += new ks1type(src) - if(ks2type) - encryption_keys += new ks2type(src) - recalculateChannels(1) - -/obj/item/radio/headset/Destroy() - QDEL_NULL_LIST(encryption_keys) - return ..() - -/obj/item/radio/headset/list_channels(var/mob/user) - return list_secure_channels() - -/obj/item/radio/headset/examine(mob/user, distance) - . = ..() - if(distance > 1 || !radio_desc) - return - - to_chat(user, "The following channels are available:") - to_chat(user, radio_desc) - -/obj/item/radio/headset/handle_message_mode(mob/living/M, message, channel) - if (channel == "special") - if (translate_binary) - var/decl/language/binary = decls_repository.get_decl(/decl/language/binary) - binary.broadcast(M, message) - return null - - return ..() - -/obj/item/radio/headset/receive_range(freq, level, aiOverride = 0) - if (aiOverride) - return ..(freq, level) - if(ishuman(src.loc)) - var/mob/living/carbon/human/H = src.loc - if(H.l_ear == src || H.r_ear == src) - return ..(freq, level) - return -1 - -/obj/item/radio/headset/syndicate - origin_tech = "{'esoteric':3}" - syndie = 1 - ks1type = /obj/item/encryptionkey/syndicate - -/obj/item/radio/headset/syndicate/alt - icon_state = "syndie_headset" - item_state = "syndie_headset" - -/obj/item/radio/headset/syndicate/Initialize() - . = ..() - set_frequency(SYND_FREQ) - -/obj/item/radio/headset/raider - origin_tech = "{'esoteric':2}" - syndie = 1 - ks1type = /obj/item/encryptionkey/raider - -/obj/item/radio/headset/raider/Initialize() - . = ..() - set_frequency(RAID_FREQ) - -/obj/item/radio/headset/binary - origin_tech = "{'esoteric':3}" - ks1type = /obj/item/encryptionkey/binary - -/obj/item/radio/headset/headset_sec - name = "security radio headset" - desc = "This is used by your elite security force." - icon_state = "sec_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_sec - -/obj/item/radio/headset/headset_sec/alt - name = "security bowman headset" - icon_state = "sec_headset_alt" - item_state = "sec_headset_alt" - -/obj/item/radio/headset/headset_eng - name = "engineering radio headset" - desc = "When the engineers wish to chat like girls." - icon_state = "eng_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_eng - -/obj/item/radio/headset/headset_eng/alt - name = "engineering bowman headset" - icon_state = "eng_headset_alt" - item_state = "eng_headset_alt" - -/obj/item/radio/headset/headset_rob - name = "robotics radio headset" - desc = "Made specifically for the roboticists who cannot decide between departments." - icon_state = "rob_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_rob - -/obj/item/radio/headset/headset_med - name = "medical radio headset" - desc = "A headset for the trained staff of the medbay." - icon_state = "med_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_med - -/obj/item/radio/headset/headset_med/alt - name = "medical bowman headset" - icon_state = "med_headset_alt" - item_state = "med_headset_alt" - -/obj/item/radio/headset/headset_sci - name = "science radio headset" - desc = "A sciency headset. Like usual." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_sci - -/obj/item/radio/headset/headset_medsci - name = "medical research radio headset" - desc = "A headset that is a result of the mating between medical and science." - icon_state = "med_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_medsci - -/obj/item/radio/headset/headset_com - name = "command radio headset" - desc = "A headset with a commanding channel." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_com - -/obj/item/radio/headset/headset_com/alt - name = "command bowman headset" - desc = "A headset with a commanding channel." - icon_state = "com_headset_alt" - item_state = "com_headset_alt" - ks1type = /obj/item/encryptionkey/headset_com - max_keys = 3 - -/obj/item/radio/headset/heads/captain - name = "captain's headset" - desc = "The headset of the boss." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/captain + can_use_analog = FALSE + encryption_keys = list(/obj/item/encryptionkey) + encryption_key_capacity = 2 -/obj/item/radio/headset/heads/captain/alt - name = "captain's bowman headset" - icon_state = "com_headset_alt" - item_state = "com_headset_alt" - max_keys = 3 - -/obj/item/radio/headset/heads/ai_integrated //No need to care about icons, it should be hidden inside the AI anyway. - name = "\improper AI subspace transceiver" - desc = "Integrated AI radio transceiver." - icon = 'icons/obj/robot_component.dmi' - icon_state = "radio" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/ai_integrated - var/myAi = null // Atlantis: Reference back to the AI which has this radio. - var/disabledAi = 0 // Atlantis: Used to manually disable AI's integrated radio via inteliCard menu. +/obj/item/radio/headset/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + return -/obj/item/radio/headset/heads/ai_integrated/Destroy() - myAi = null +/obj/item/radio/headset/on_update_icon() . = ..() - -/obj/item/radio/headset/heads/ai_integrated/receive_range(freq, level) - if (disabledAi) - return -1 //Transciever Disabled. - return ..(freq, level, 1) - -/obj/item/radio/headset/heads/rd - name = "chief science officer's headset" - desc = "Headset of the researching God." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/rd - -/obj/item/radio/headset/heads/hos - name = "head of security's headset" - desc = "The headset of the man who protects your worthless lives." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/hos - -/obj/item/radio/headset/heads/ce - name = "chief engineer's headset" - desc = "The headset of the guy who is in charge of morons." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/ce - -/obj/item/radio/headset/heads/ce/alt - name = "chief engineer's bowman headset" - icon_state = "com_headset_alt" - item_state = "com_headset_alt" - -/obj/item/radio/headset/heads/cmo - name = "chief medical officer's headset" - desc = "The headset of the highly trained medical chief." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/cmo - -/obj/item/radio/headset/heads/cmo/alt - name = "chief medical officer's bowman headset" - icon_state = "com_headset_alt" - item_state = "com_headset_alt" - -/obj/item/radio/headset/heads/hop - name = "head of personnel's headset" - desc = "The headset of the guy who will one day be captain." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/hop - -/obj/item/radio/headset/headset_service - name = "service radio headset" - desc = "Headset used by the service staff, tasked with keeping everyone full, happy and clean." - icon_state = "srv_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_service - -/obj/item/radio/headset/ert - name = "emergency response team radio headset" - desc = "The headset of the boss's boss." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/ert - -/obj/item/radio/headset/foundation - name = "\improper Foundation radio headset" - desc = "The headeset of the occult cavalry." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/ert - -/obj/item/radio/headset/ia - name = "internal affair's headset" - desc = "The headset of your worst enemy." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/heads/hos - -/obj/item/radio/headset/headset_mining - name = "mining radio headset" - desc = "Headset used by dwarves. It has an inbuilt subspace antenna for better reception." - icon_state = "mine_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_mining - -/obj/item/radio/headset/headset_mining/alt - name = "mining bowman radio headset" - icon_state = "mine_headset_alt" - item_state = "mine_headset_alt" - max_keys = 3 - -/obj/item/radio/headset/headset_cargo - name = "supply radio headset" - desc = "A headset used by the box-pushers." - icon_state = "cargo_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/headset_cargo - -/obj/item/radio/headset/headset_cargo/alt - name = "supply bowman headset" - icon_state = "cargo_headset_alt" - item_state = "cargo_headset_alt" - max_keys = 3 - -/obj/item/radio/headset/entertainment - name = "actor's radio headset" - desc = "specially made to make you sound less cheesy." - icon_state = "com_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/entertainment - -/obj/item/radio/headset/specops - name = "special operations radio headset" - desc = "The headset of the spooks." - icon_state = "cent_headset" - item_state = "headset" - ks1type = /obj/item/encryptionkey/specops - -/obj/item/radio/headset/attackby(obj/item/W, mob/user) -// ..() - user.set_machine(src) - if (!( isScrewdriver(W) || (istype(W, /obj/item/encryptionkey/ )))) - return - - if(isScrewdriver(W)) - if(encryption_keys.len) - for(var/ch_name in channels) - radio_controller.remove_object(src, radiochannels[ch_name]) - secure_radio_connections[ch_name] = null - for(var/obj/ekey in encryption_keys) - ekey.dropInto(user.loc) - encryption_keys -= ekey - - recalculateChannels(1) - to_chat(user, "You pop out the encryption keys in the headset!") - + icon_state = get_world_inventory_state() + if(on) + if(analog) + add_overlay("[icon_state]-local") else - to_chat(user, "This headset doesn't have any encryption keys! How useless...") - - if(istype(W, /obj/item/encryptionkey/)) - if(encryption_keys.len >= max_keys) - to_chat(user, "The headset can't hold another key!") - return - if(user.unEquip(W, target = src)) - to_chat(user, "You put \the [W] into \the [src].") - encryption_keys += W - recalculateChannels(1) - -/obj/item/radio/headset/MouseDrop(var/obj/over_object) - var/mob/M = usr - if((!istype(over_object, /obj/screen)) && (src in M) && CanUseTopic(M)) - return attack_self(M) - return - -/obj/item/radio/headset/recalculateChannels(var/setDescription = 0) - src.channels = list() - src.translate_binary = 0 - src.syndie = 0 - for(var/obj/ekey in encryption_keys) - import_key_data(ekey) - for (var/ch_name in channels) - if(!radio_controller) - sleep(30) // Waiting for the radio_controller to be created. - if(!radio_controller) - src.SetName("broken radio headset") - return - secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) - - if(setDescription) - setupRadioDescription() - -/obj/item/radio/headset/proc/import_key_data(obj/item/encryptionkey/key) - if(!key) - return - for(var/ch_name in key.channels) - if(ch_name in src.channels) - continue - src.channels[ch_name] = key.channels[ch_name] - if(key.translate_binary) - src.translate_binary = 1 - if(key.syndie) - src.syndie = 1 - -/obj/item/radio/headset/proc/setupRadioDescription() - var/radio_text = "" - for(var/i = 1 to channels.len) - var/channel = channels[i] - var/key = get_radio_key_from_channel(channel) - radio_text += "[key] - [channel]" - if(i != channels.len) - radio_text += ", " - - radio_desc = radio_text + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + if(network) + add_overlay("[icon_state]-online") + else + add_overlay("[icon_state]-offline") \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/headsets_shared.dm b/code/game/objects/items/devices/radio/headsets_shared.dm new file mode 100644 index 000000000000..475a5e515909 --- /dev/null +++ b/code/game/objects/items/devices/radio/headsets_shared.dm @@ -0,0 +1,274 @@ +/obj/item/radio/headset/headset_cargo + name = "supply radio headset" + icon = 'icons/obj/items/device/radio/headsets/headset_cargo.dmi' + encryption_keys = list(/obj/item/encryptionkey/cargo) + +/obj/item/encryptionkey/cargo + name = "supply radio encryption key" + inlay_color = COLOR_ASSEMBLY_WHITE + can_decrypt = list(access_cargo) + +/obj/item/radio/headset/headset_mining + name = "mining radio headset" + desc = "Headset used by dwarves. It has an inbuilt subspace antenna for better reception." + icon = 'icons/obj/items/device/radio/headsets/headset_mining.dmi' + encryption_keys = list(/obj/item/encryptionkey/mining) + +/obj/item/encryptionkey/mining + name = "mining radio encryption key" + inlay_color = COLOR_ASSEMBLY_WHITE + can_decrypt = list(access_mining) +/obj/item/radio/headset/headset_sec + name = "security radio headset" + icon = 'icons/obj/items/device/radio/headsets/headset_security.dmi' + encryption_keys = list(/obj/item/encryptionkey/sec) + +/obj/item/encryptionkey/sec + name = "security radio encryption key" + inlay_color = COLOR_BLOOD_RED + can_decrypt = list(access_security) + +/obj/item/radio/headset/headset_med + name = "medical radio headset" + desc = "A headset for the trained staff of the medbay." + icon = 'icons/obj/items/device/radio/headsets/headset_medical.dmi' + encryption_keys = list(/obj/item/encryptionkey/med) + +/obj/item/encryptionkey/med + name = "medical radio encryption key" + inlay_color = COLOR_ASSEMBLY_WHITE + can_decrypt = list(access_medical) + +/obj/item/radio/headset/headset_service + name = "service radio headset" + desc = "Headset used by the service staff, tasked with keeping everyone full, happy and clean." + icon = 'icons/obj/items/device/radio/headsets/headset_service.dmi' + encryption_keys = list(/obj/item/encryptionkey/service) + +/obj/item/encryptionkey/service + name = "service radio encryption key" + inlay_color = COLOR_VERDANT_GREEN + can_decrypt = list(access_bar) + +/obj/item/radio/headset/headset_sci + name = "science radio headset" + desc = "A science-y headset. Like usual." + icon = 'icons/obj/items/device/radio/headsets/headset_science.dmi' + encryption_keys = list(/obj/item/encryptionkey/sci) + +/obj/item/encryptionkey/sci + name = "science radio encryption key" + inlay_color = COLOR_SCIENCE_PURPLE + can_decrypt = list(access_research) + +/obj/item/radio/headset/headset_eng + name = "engineering radio headset" + desc = "When the engineers wish to gossip like high-schoolers." + icon = 'icons/obj/items/device/radio/headsets/headset_engineering.dmi' + encryption_keys = list(/obj/item/encryptionkey/eng) + +/obj/item/encryptionkey/eng + name = "engineering radio encryption key" + inlay_color = PIPE_COLOR_YELLOW + can_decrypt = list(access_engine) + +/obj/item/radio/headset/heads + icon_state = "com_headset" + icon = 'icons/obj/items/device/radio/headsets/headset_command.dmi' + encryption_keys = list(/obj/item/encryptionkey/command) + +/obj/item/encryptionkey/command + name = "command encryption key" + inlay_color = COLOR_ROYAL_BLUE + can_decrypt = list(access_bridge) + +/obj/item/encryptionkey/heads + color = COLOR_GOLD + fill_color = COLOR_PALE_GOLD + inlay_color = COLOR_ROYAL_BLUE + +/obj/item/radio/headset/heads/ce + name = "chief engineer's headset" + desc = "The headset of the boss engineer." + icon = 'icons/obj/items/device/radio/headsets/headset_engineering.dmi' + encryption_keys = list(/obj/item/encryptionkey/heads/ce) + +/obj/item/encryptionkey/heads/ce + name = "chief engineer's encryption key" + can_decrypt = list( + access_bridge, + access_engine + ) + +/obj/item/radio/headset/heads/cmo + name = "chief medical officer's headset" + desc = "The headset of the boss medic." + icon = 'icons/obj/items/device/radio/headsets/headset_medical.dmi' + encryption_keys = list(/obj/item/encryptionkey/heads/cmo) + +/obj/item/encryptionkey/heads/cmo + name = "chief medical officer's encryption key" + can_decrypt = list( + access_bridge, + access_medical + ) + +/obj/item/radio/headset/heads/rd + name = "research director's headset" + desc = "The headset of the boss egghead." + icon = 'icons/obj/items/device/radio/headsets/headset_science.dmi' + encryption_keys = list(/obj/item/encryptionkey/heads/rd) + +/obj/item/encryptionkey/heads/rd + name = "research director's encryption key" + can_decrypt = list( + access_bridge, + access_research + ) + +/obj/item/radio/headset/heads/captain + name = "captain's headset" + desc = "The headset of the boss." + encryption_keys = list(/obj/item/encryptionkey/heads/captain) + +/obj/item/encryptionkey/heads/captain + name = "captain's encryption key" + can_decrypt = list( + access_bridge, + access_security, + access_engine, + access_research, + access_medical, + access_cargo, + access_bar + ) + +/obj/item/radio/headset/heads/hop + name = "head of personnel's headset" + desc = "The headset of the guy who will one day be captain." + encryption_keys = list(/obj/item/encryptionkey/heads/hop) + +/obj/item/encryptionkey/heads/hop + name = "head of personnel's encryption key" + can_decrypt = list( + access_bar, + access_cargo, + access_bridge, + access_security, + access_mining + ) + +/obj/item/radio/headset/heads/hos + name = "head of security's headset" + desc = "The headset of the man who protects your worthless lives." + icon = 'icons/obj/items/device/radio/headsets/headset_security.dmi' + encryption_keys = list(/obj/item/encryptionkey/heads/hos) + +/obj/item/encryptionkey/heads/hos + name = "head of security's encryption key" + inlay_color = COLOR_BLOOD_RED + can_decrypt = list( + access_bridge, + access_security + ) + +/obj/item/encryptionkey/specops + name = "\improper special operations radio encryption key" + can_decrypt = list(access_cent_specops) + +/obj/item/encryptionkey/specops/Initialize(ml, material_key) + . = ..() + can_decrypt |= get_all_station_access() + +/obj/item/radio/headset/specops + name = "special operations radio headset" + desc = "The headset of the boss's boss." + icon = 'icons/obj/items/device/radio/headsets/headset_admin.dmi' + encryption_keys = list(/obj/item/encryptionkey/specops) + +/obj/item/encryptionkey/mercenary + origin_tech = @'{"esoteric":2}' + can_decrypt = list(access_mercenary) + +/obj/item/radio/headset/mercenary + can_use_analog = TRUE + origin_tech = @'{"esoteric":2}' + encryption_keys = list(/obj/item/encryptionkey/mercenary) + analog_secured = list((access_mercenary) = TRUE) + +/obj/item/radio/headset/mercenary/commando + encryption_keys = list( + /obj/item/encryptionkey/mercenary, + /obj/item/encryptionkey/hacked + ) + +/obj/item/encryptionkey/entertainment + name = "entertainment radio key" + +/obj/item/radio/headset/entertainment + name = "actor's radio headset" + desc = "Specially made to make you sound less cheesy." + icon = 'icons/obj/items/device/radio/headsets/headset_command.dmi' + encryption_keys = list(/obj/item/encryptionkey/entertainment) + +/obj/item/encryptionkey/raider + origin_tech = @'{"esoteric":2}' + can_decrypt = list(access_raider) + +/obj/item/radio/headset/raider + can_use_analog = TRUE + origin_tech = @'{"esoteric":2}' + encryption_keys = list(/obj/item/encryptionkey/raider) + analog_secured = list((access_raider) = TRUE) + +/obj/item/encryptionkey/hacked + can_decrypt = list(access_hacked) + origin_tech = @'{"esoteric":3}' + +/obj/item/encryptionkey/hacked/Initialize(ml, material_key) + . = ..() + can_decrypt |= get_all_station_access() + +/obj/item/radio/headset/hacked + origin_tech = @'{"esoteric":3}' + encryption_keys = list(/obj/item/encryptionkey/hacked) + +// Bowman alts +/obj/item/radio/headset/headset_mining/bowman + name = "mining bowman radio headset" + icon = 'icons/obj/items/device/radio/headsets/headset_mining_alt.dmi' + +/obj/item/radio/headset/headset_cargo/bowman + name = "supply bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_cargo_alt.dmi' + + +/obj/item/radio/headset/corp_cmo/bowman + name = "chief medical officer's bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_command_alt.dmi' + +/obj/item/radio/headset/corp_ce/bowman + name = "chief engineer's bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_command_alt.dmi' + +/obj/item/radio/headset/corp_captain/bowman + name = "captain's bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_command_alt.dmi' + + +/obj/item/radio/headset/heads/bowman + name = "command bowman headset" + desc = "A headset with a commanding channel." + icon = 'icons/obj/items/device/radio/headsets/headset_command_alt.dmi' + +/obj/item/radio/headset/headset_med/bowman + name = "medical bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_medical_alt.dmi' + +/obj/item/radio/headset/headset_eng/bowman + name = "engineering bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_engineering_alt.dmi' + +/obj/item/radio/headset/headset_sec/bowman + name = "security bowman headset" + icon = 'icons/obj/items/device/radio/headsets/headset_security_alt.dmi' \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index bff10ddcef01..d923655a8ee2 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -4,125 +4,41 @@ icon = 'icons/obj/items/device/radio/intercom.dmi' icon_state = "intercom" randpixel = 0 - anchored = 1 + anchored = TRUE w_class = ITEM_SIZE_STRUCTURE canhear_range = 2 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_BLOOD - obj_flags = OBJ_FLAG_CONDUCTIBLE + atom_flags = ATOM_FLAG_NO_BLOOD + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_MOVES_UNSUPPORTED layer = ABOVE_WINDOW_LAYER - cell = null power_usage = 0 - var/number = 0 + intercom = TRUE + intercom_handling = TRUE + directional_offset = @'{"NORTH":{"y":-30}, "SOUTH":{"y":20}, "EAST":{"x":-22}, "WEST":{"x":22}}' var/last_tick //used to delay the powercheck -/obj/item/radio/intercom/custom - name = "intercom (Custom)" - broadcasting = 0 - listening = 0 - -/obj/item/radio/intercom/interrogation - name = "intercom (Interrogation)" - frequency = 1449 - -/obj/item/radio/intercom/private - name = "intercom (Private)" - frequency = AI_FREQ - -/obj/item/radio/intercom/specops - name = "\improper Spec Ops intercom" - frequency = ERT_FREQ - -/obj/item/radio/intercom/department - canhear_range = 5 - broadcasting = 0 - listening = 1 - -/obj/item/radio/intercom/department/medbay - name = "intercom (Medbay)" - frequency = MED_I_FREQ - -/obj/item/radio/intercom/department/security - name = "intercom (Security)" - frequency = SEC_I_FREQ - -/obj/item/radio/intercom/entertainment - name = "entertainment intercom" - frequency = ENT_FREQ - canhear_range = 4 +/obj/item/radio/intercom/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + return /obj/item/radio/intercom/Initialize() . = ..() START_PROCESSING(SSobj, src) update_icon() -/obj/item/radio/intercom/department/medbay/Initialize() - . = ..() - internal_channels = GLOB.default_medbay_channels.Copy() - -/obj/item/radio/intercom/department/security/Initialize() - . = ..() - internal_channels = list( - num2text(PUB_FREQ) = list(), - num2text(SEC_I_FREQ) = list(access_security) - ) - -/obj/item/radio/intercom/entertainment/Initialize() - . = ..() - internal_channels = list( - num2text(PUB_FREQ) = list(), - num2text(ENT_FREQ) = list() - ) - -/obj/item/radio/intercom/syndicate - name = "illicit intercom" - desc = "Talk through this. Evilly." - frequency = SYND_FREQ - subspace_transmission = 1 - syndie = 1 - -/obj/item/radio/intercom/syndicate/Initialize() - . = ..() - internal_channels[num2text(SYND_FREQ)] = list(access_syndicate) - /obj/item/radio/intercom/raider - name = "illicit intercom" + name = "piratical intercom" desc = "Pirate radio, but not in the usual sense of the word." - frequency = RAID_FREQ - subspace_transmission = 1 - syndie = 1 - -/obj/item/radio/intercom/raider/Initialize() - . = ..() - internal_channels[num2text(RAID_FREQ)] = list(access_syndicate) /obj/item/radio/intercom/Destroy() STOP_PROCESSING(SSobj, src) return ..() -/obj/item/radio/intercom/attack_ai(mob/user) - src.add_fingerprint(user) - spawn (0) - attack_self(user) +/obj/item/radio/intercom/attack_ai(mob/living/silicon/ai/user) + return attack_self(user) /obj/item/radio/intercom/attack_hand(mob/user) - src.add_fingerprint(user) - spawn (0) - attack_self(user) - -/obj/item/radio/intercom/receive_range(freq, level) - if (!on) - return -1 - if(!(0 in level)) - var/turf/position = get_turf(src) - if(isnull(position) || !(position.z in level)) - return -1 - if (!src.listening) - return -1 - if(freq in ANTAG_FREQS) - if(!(src.syndie)) - return -1//Prevents broadcast of messages over devices lacking the encryption - - return canhear_range + SHOULD_CALL_PARENT(FALSE) + return attack_self(user) /obj/item/radio/intercom/Process() if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0)) @@ -142,16 +58,17 @@ update_icon() /obj/item/radio/intercom/on_update_icon() + . = ..() if(!on) icon_state = "intercom-p" else icon_state = "intercom_[broadcasting][listening]" -/obj/item/radio/intercom/ToggleBroadcast() +/obj/item/radio/intercom/toggle_broadcast() ..() update_icon() -/obj/item/radio/intercom/ToggleReception() +/obj/item/radio/intercom/toggle_reception() ..() update_icon() @@ -164,15 +81,16 @@ /obj/item/radio/intercom/locked/set_frequency() ..(locked_frequency) -/obj/item/radio/intercom/locked/list_channels() - return "" +/obj/item/radio/intercom/locked/entertainment + broadcasting = TRUE + locked_frequency = 1461 /obj/item/radio/intercom/locked/ai_private name = "\improper AI intercom" - locked_frequency = AI_FREQ - broadcasting = 1 - listening = 1 + frequency = 1343 + broadcasting = TRUE + listening = TRUE -/obj/item/radio/intercom/locked/confessional - name = "confessional intercom" - locked_frequency = 1480 \ No newline at end of file +/obj/item/radio/intercom/interrogation + name = "station intercom (Interrogation)" + frequency = 1449 diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index a3ad1ffd1899..48244d9fcdae 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -1,91 +1,185 @@ +/datum/extension/network_device/radio + expected_type = /obj/item/radio + +/datum/extension/network_device/radio/connect() + . = ..() + if(. && holder) + var/datum/computer_network/net = SSnetworking.networks[network_id] + if(net) + LAZYADD(net.connected_radios, weakref(holder)) + var/obj/item/radio/radio = holder + radio.update_icon() + +/datum/extension/network_device/radio/disconnect() + var/datum/computer_network/net = SSnetworking.networks[network_id] + . = ..() + if(. && holder) + if(net) + LAZYREMOVE(net.connected_radios, weakref(holder)) + var/obj/item/radio/radio = holder + radio.update_icon() + /obj/item/radio + name = "dual-band radio" + desc = "A radio that can transmit in analog or digital modes." icon = 'icons/obj/items/device/radio/radio.dmi' - name = "shortwave radio" suffix = "\[3\]" icon_state = "walkietalkie" item_state = "walkietalkie" - var/on = 1 // 0 for off - var/last_transmission - var/frequency = PUB_FREQ //common chat - var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies - var/canhear_range = 3 // the range which mobs can hear this radio from - var/datum/wires/radio/wires = null - var/b_stat = 0 - var/broadcasting = 0 - var/listening = 1 - var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h - var/subspace_transmission = 0 - var/syndie = 0//Holder to see if it's a syndicate encrypted radio - var/intercept = 0 //can intercept other channels + var/intercom = FALSE // If an intercom, will receive data == 1 packets. + var/virtual = FALSE // If virtual, will receive all broadcasts but will never notify nearby listeners. + obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY throw_speed = 2 throw_range = 9 w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) - material = /decl/material/solid/glass - matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT) - var/const/FREQ_LISTENING = 1 - var/list/internal_channels - - var/obj/item/cell/cell = /obj/item/cell/device var/power_usage = 2800 + var/last_radio_sound = -INFINITY + var/initial_network_id + var/initial_network_key - var/datum/radio_frequency/radio_connection - var/list/datum/radio_frequency/secure_radio_connections = new + var/datum/wires/radio/wires = null + var/panel_open = FALSE + var/list/encryption_keys + var/encryption_key_capacity - var/last_radio_sound = -INFINITY + var/on = TRUE + var/frequency = PUB_FREQ + var/intercom_handling = FALSE + var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies + var/canhear_range = 3 // the range which mobs can hear this radio from + var/broadcasting = FALSE + var/listening = TRUE + var/list/channels + var/decrypt_all_messages = FALSE + var/can_use_analog = TRUE + var/datum/extension/network_device/radio/radio_device_type = /datum/extension/network_device/radio + var/analog = FALSE + var/analog_secured = list() // list of accesses used for encrypted analog, mainly for mercs/raiders + var/datum/radio_frequency/analog_radio_connection + +/obj/item/radio/proc/get_radio_listeners() + for(var/mob/listener in hearers(canhear_range, get_turf(src))) + LAZYDISTINCTADD(., listener.resolve_to_radio_listeners()) + +/obj/item/radio/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/device, /obj/item/cell/device, /datum/extension/loaded_cell, charge_value) + +/obj/item/radio/get_radio(var/message_mode) + return src + +/obj/item/radio/proc/can_decrypt(var/list/secured) + if(decrypt_all_messages) + return TRUE + if(!LAZYLEN(secured)) + return TRUE + if(!islist(secured)) + secured = list(secured) + var/list/needed_access = secured.Copy() + for(var/obj/item/encryptionkey/key in encryption_keys) + needed_access -= key.can_decrypt + if (!length(needed_access)) + return TRUE + return FALSE // not all keys were removed /obj/item/radio/proc/set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) + if(analog_radio_connection) + radio_controller.remove_object(src, frequency) + analog_radio_connection = null frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + if(analog && frequency) + analog_radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + +/obj/item/radio/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) /obj/item/radio/Initialize() . = ..() wires = new(src) - if(ispath(cell)) - cell = new(src) - internal_channels = GLOB.using_map.default_internal_channels() - GLOB.listening_objects += src - - if(frequency < RADIO_LOW_FREQ || frequency > RADIO_HIGH_FREQ) - frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) - set_frequency(frequency) - - for (var/ch_name in channels) - secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) + setup_power_supply() + + global.listening_objects += src + set_frequency(sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ)) + if(radio_device_type) + set_extension(src, radio_device_type, initial_network_id, initial_network_key, RECEIVER_STRONG_WIRELESS) + + var/list/created_encryption_keys + for(var/keytype in encryption_keys) + LAZYADD(created_encryption_keys, new keytype(src)) + encryption_keys = created_encryption_keys + +/obj/item/radio/proc/get_available_channels() + if(!channels) + sync_channels_with_network() + return channels + +/obj/item/radio/proc/sync_channels_with_network() + channels = null + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/weakref/H as anything in network?.connected_hubs) + var/obj/machinery/network/telecomms_hub/hub = H.resolve() + if(!istype(hub) || QDELETED(hub) || !hub.can_receive_message(network) || !length(hub.channels)) + continue + for(var/datum/radio_channel/channel in hub.channels) + if(channel.receive_only) + continue + if(can_decrypt(channel.secured)) + LAZYSET(channels, channel, TRUE) /obj/item/radio/Destroy() QDEL_NULL(wires) - GLOB.listening_objects -= src - if(radio_controller) - radio_controller.remove_object(src, frequency) - for (var/ch_name in channels) - radio_controller.remove_object(src, radiochannels[ch_name]) - return ..() + QDEL_NULL_LIST(encryption_keys) + set_frequency(null) // clean up the radio connection + channels = null + . = ..() /obj/item/radio/attack_self(mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) + return user.set_machine(src) + add_fingerprint(user) interact(user) + return TRUE /obj/item/radio/interact(mob/user) if(!user) - return 0 - - if(b_stat) + return FALSE + if(panel_open) wires.Interact(user) - return ui_interact(user) +/obj/item/radio/proc/sanitize_analog_secured() + var/list/collected_access = list() + for(var/obj/item/encryptionkey/other_key in encryption_keys) + collected_access |= other_key.can_decrypt + analog_secured &= collected_access + /obj/item/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + if(network_device) + var/datum/computer_network/network = network_device?.get_network() + data["network"] = "[network_device.network_tag] ([network ? network.network_id : "disconnected"])" + data["can_use_analog"] = can_use_analog + data["analog"] = analog + data["analog_secured"] = analog_secured + var/list/collected_access = list() + for(var/obj/item/encryptionkey/other_key in encryption_keys) + collected_access |= other_key.can_decrypt + data["available_keys"] = collected_access data["mic_status"] = broadcasting data["speaker"] = listening data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) + data["rawfreq"] = "[frequency]" var/obj/item/cell/has_cell = get_cell() if(has_cell) var/charge = round(has_cell.percent()) @@ -93,13 +187,23 @@ data["mic_cut"] = (wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL)) data["spk_cut"] = (wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL)) - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len + var/list/current_channels = get_available_channels() + if(length(current_channels)) + data["show_channels"] = TRUE + data["channel_list"] = list() + for(var/datum/radio_channel/channel in current_channels) + if(!can_decrypt(channel.secured)) + continue + var/list/channel_data = list() + channel_data["display_name"] = channel.name || format_frequency(channel.frequency) + channel_data["chan"] = "[channel.frequency]" + channel_data["secure_channel"] = !!(channel.secured) + channel_data["listening"] = !!(current_channels[channel]) + channel_data["chan_span"] = channel.span_class + data["channel_list"] += list(channel_data) - if(syndie) - data["useSyndMode"] = 1 + if(can_decrypt(access_hacked)) + data["useSyndMode"] = TRUE ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) @@ -107,61 +211,19 @@ ui.set_initial_data(data) ui.open() -/obj/item/radio/proc/list_channels(var/mob/user) - return list_internal_channels(user) - -/obj/item/radio/proc/list_secure_channels(var/mob/user) - var/dat[0] - - for(var/ch_name in channels) - var/chan_stat = channels[ch_name] - var/listening = !!(chan_stat & FREQ_LISTENING) != 0 - - dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = frequency_span_class(radiochannels[ch_name])))) - - return dat - -/obj/item/radio/proc/list_internal_channels(var/mob/user) - var/dat[0] - for(var/internal_chan in internal_channels) - if(has_channel_access(user, internal_chan)) - dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_default_name(text2num(internal_chan)), "chan_span" = frequency_span_class(text2num(internal_chan))))) - - return dat +// Used for radios that need to do something upon chatter. +/obj/item/radio/proc/received_chatter(display_freq, level) + if((last_radio_sound + 1 SECOND) < world.time) + playsound(loc, 'sound/effects/radio_chatter.ogg', 10, 0, -6) + last_radio_sound = world.time /obj/item/radio/proc/has_channel_access(var/mob/user, var/freq) - if(!user) - return 0 - - if(!(freq in internal_channels)) - return 0 - - return user.has_internal_radio_channel_access(internal_channels[freq]) + return TRUE // TODO: add antag/valid bounds checking -/mob/proc/has_internal_radio_channel_access(var/list/req_one_accesses) - var/obj/item/card/id/I = GetIdCard() - if (!length(req_one_accesses)) - return TRUE // No access flags means all access - else - return has_access(list(req_one_accesses), I ? I.GetAccess() : list()) // Double list does an OR check instead of the usual AND. - -/mob/observer/ghost/has_internal_radio_channel_access(var/list/req_one_accesses) - return can_admin_interact() - -/obj/item/radio/get_cell() - return cell - -/obj/item/radio/proc/text_sec_channel(var/chan_name, var/chan_stat) - var/list = !!(chan_stat&FREQ_LISTENING)!=0 - return {" - [chan_name]
              - Speaker: [list ? "Engaged" : "Disengaged"]
              - "} - -/obj/item/radio/proc/ToggleBroadcast() +/obj/item/radio/proc/toggle_broadcast() broadcasting = !broadcasting && !(wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL)) -/obj/item/radio/proc/ToggleReception() +/obj/item/radio/proc/toggle_reception() listening = !listening && !(wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL)) /obj/item/radio/CanUseTopic() @@ -169,692 +231,281 @@ return STATUS_CLOSE return ..() -/obj/item/radio/Topic(href, href_list) - if(..()) - return 1 - - usr.set_machine(src) - if (href_list["track"]) - var/mob/target = locate(href_list["track"]) - var/mob/living/silicon/ai/A = locate(href_list["track2"]) - if(A && target) - A.ai_actual_track(target) - . = 1 +/obj/item/radio/OnTopic(mob/user, href_list) + if((. = ..())) + return + user.set_machine(src) + if(href_list["analog"]) + if(can_use_analog) + analog = text2num(href_list["analog"]) + set_frequency(frequency) // update analog status + . = TOPIC_REFRESH + else if(href_list["analog_secured"]) + if(can_use_analog) + if(length(encryption_keys)) + var/secured_key = href_list["analog_secured"] + if(can_decrypt(secured_key)) // making sure we're not href hacking + analog_secured[secured_key] = !analog_secured[secured_key] + sanitize_analog_secured() + else + analog_secured = list() + . = TOPIC_REFRESH + else if(href_list["clear_analog_secured"]) + if(can_use_analog) + analog_secured = list() + . = TOPIC_REFRESH + else if(href_list["sync"]) + sync_channels_with_network() + . = TOPIC_REFRESH else if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) - new_frequency = sanitize_frequency(new_frequency) + var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"])) set_frequency(new_frequency) if(hidden_uplink) - if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) - close_browser(usr, "window=radio") - . = 1 + if(hidden_uplink.check_trigger(user, frequency, traitor_frequency)) + close_browser(user, "window=radio") + . = TOPIC_REFRESH else if (href_list["talk"]) - ToggleBroadcast() - . = 1 - else if (href_list["listen"]) + toggle_broadcast() + . = TOPIC_REFRESH + else if(href_list["reception"]) + toggle_reception() + . = TOPIC_REFRESH + else if(href_list["listen"]) + var/listen_set = text2num(href_list["listen"]) var/chan_name = href_list["ch_name"] - if (!chan_name) - ToggleReception() - else - if (channels[chan_name] & FREQ_LISTENING) - channels[chan_name] &= ~FREQ_LISTENING - else - channels[chan_name] |= FREQ_LISTENING - . = 1 + if(chan_name) + for(var/datum/radio_channel/channel in channels) + if("[channel.frequency]" == chan_name) + channels[channel] = listen_set + break + . = TOPIC_REFRESH else if(href_list["spec_freq"]) var freq = href_list["spec_freq"] - if(has_channel_access(usr, freq)) + if(has_channel_access(user, freq)) set_frequency(text2num(freq)) - . = 1 + . = TOPIC_REFRESH if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk - return 1 - - if(href_list["remove_cell"]) - if(cell) - var/mob/user = usr - user.put_in_hands(cell) - to_chat(user, "You remove [cell] from \the [src].") - cell = null - return 1 - - if(.) + return TOPIC_HANDLED + if(href_list["network_settings"]) + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + D.ui_interact(user) + . = TOPIC_HANDLED + if(. & TOPIC_REFRESH) SSnano.update_uis(src) - -/obj/item/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT - var/datum/radio_frequency/connection = null - if(channel && channels && channels.len > 0) - if (channel == "department") - channel = channels[1] - connection = secure_radio_connections[channel] - else - connection = radio_connection - channel = null - if (!istype(connection)) - return - var/mob/living/silicon/ai/A = new /mob/living/silicon/ai(src, null, null, 1) - A.fully_replace_character_name(from) - talk_into(A, message, channel,"states") - qdel(A) - -// Interprets the message mode when talking into a radio, possibly returning a connection datum -/obj/item/radio/proc/handle_message_mode(mob/living/M, message, message_mode) - // If a channel isn't specified, send to common. - if(!message_mode || message_mode == "headset") - return radio_connection - - // Otherwise, if a channel is specified, look for it. - if(channels && channels.len > 0) - if (message_mode == "department") // Department radio shortcut - message_mode = channels[1] - - if (channels[message_mode]) // only broadcast if the channel is set on - return secure_radio_connections[message_mode] - - // If we were to send to a channel we don't have, drop it. - return null - -/obj/item/radio/talk_into(mob/living/M, message, channel, var/verb = "says", var/decl/language/speaking = null) + update_icon() + +/mob/announcer // used only for autosay + is_spawnable_type = FALSE + simulated = FALSE + +/obj/item/radio/proc/autosay(var/message, var/from, var/channel, var/sayverb = "states") //BS12 EDIT + if(!channel) + channel = frequency + var/list/current_channels = get_available_channels() + for(var/datum/radio_channel/comms in current_channels) + if(!current_channels[comms] || !can_decrypt(comms.secured)) + continue + if(comms.name == channel || "[comms.frequency]" == "[channel]" || comms.key == channel) + transmit(from, message, comms.key, sayverb) + break + +/obj/item/radio/proc/resolve_frequency(mob/living/M, message, message_mode) + var/list/current_channels = get_available_channels() + if(length(current_channels) && message_mode && message_mode != MESSAGE_MODE_DEFAULT) + if(message_mode == MESSAGE_MODE_DEPARTMENT) + var/datum/radio_channel/channel = current_channels[1] + return channel.frequency + for(var/datum/radio_channel/channel in current_channels) + if(message_mode == lowertext(channel.name || format_frequency(channel.frequency))) + return channel.frequency + return frequency + +/obj/item/radio/talk_into(mob/living/M, message, message_mode, var/verb = "says", var/decl/language/speaking = null) + set waitfor = FALSE if(!on) return 0 // the device has to be on // Fix for permacell radios, but kinda eh about actually fixing them. - if(!M || !message) return 0 + if(!istype(M) || !message) return 0 - if(speaking && (speaking.flags & (NONVERBAL|SIGNLANG))) return 0 + if(speaking && (speaking.flags & (LANG_FLAG_NONVERBAL|LANG_FLAG_SIGNLANG))) return 0 if (!broadcasting) // Sedation chemical effect should prevent radio use. - var/mob/living/carbon/C = M - if ((istype(C)) && (C.chem_effects[CE_SEDATE] || C.incapacitated(INCAPACITATION_DISRUPTED))) + if((M.has_chemical_effect(CE_SEDATE, 1) || M.incapacitated(INCAPACITATION_DISRUPTED))) to_chat(M, SPAN_WARNING("You're unable to reach \the [src].")) return 0 - if((istype(C)) && C.radio_interrupt_cooldown > world.time) + if(M.radio_interrupt_cooldown > world.time) to_chat(M, SPAN_WARNING("You're disrupted as you reach for \the [src].")) return 0 - if(istype(M)) M.trigger_aiming(TARGET_CAN_RADIO) + if(istype(M)) + M.trigger_aiming(TARGET_CAN_RADIO) - // Uncommenting this. To the above comment: - // The permacell radios aren't suppose to be able to transmit, this isn't a bug and this "fix" is just making radio wires useless. -Giacom - if(wires.IsIndexCut(WIRE_TRANSMIT)) // The device has to have all its wires and shit intact - return 0 + addtimer(CALLBACK(src, PROC_REF(transmit), M, message, message_mode, verb, speaking), 0) - if(!radio_connection) - set_frequency(frequency) +/obj/item/radio/proc/can_transmit_binary() + for(var/obj/item/encryptionkey/key in encryption_keys) + if(key.translate_binary) + return TRUE + return FALSE +/obj/item/radio/proc/transmit(var/mob/speaker, message, message_mode, var/verb = "says", var/decl/language/speaking = null) + if(wires.IsIndexCut(WIRE_TRANSMIT)) + return 0 + + var/message_compression = 0 if(power_usage) var/obj/item/cell/has_cell = get_cell() if(!has_cell) return 0 if(!has_cell.checked_use(power_usage * CELLRATE)) return 0 + if(has_cell.percent() < 20) + message_compression = max(0, 80 - has_cell.percent()*3) - if(loc == M) + if(loc && loc == speaker) playsound(loc, 'sound/effects/walkietalkie.ogg', 20, 0, -1) - - /* Quick introduction: - This new radio system uses a very robust FTL signaling technology unoriginally - dubbed "subspace" which is somewhat similar to 'blue-space' but can't - actually transmit large mass. Headsets are the only radio devices capable - of sending subspace transmissions to the Communications Satellite. - - A headset sends a signal to a subspace listener/reciever elsewhere in space, - the signal gets processed and logged, and an audible transmission gets sent - to each individual headset. - */ - - //#### Grab the connection datum ####// - var/datum/radio_frequency/connection = handle_message_mode(M, message, channel) - if (!istype(connection)) - return 0 + if(message_mode == MESSAGE_MODE_SPECIAL && can_transmit_binary()) + var/decl/language/binary/binary = GET_DECL(/decl/language/binary) + binary.broadcast(speaker, message) + return TRUE var/turf/position = get_turf(src) + if(!position) + return - //#### Tagging the signal with all appropriate identity values ####// - - // ||-- The mob's name identity --|| - var/displayname = M.name // grab the display name (name you get when you hover over someone's icon) - var/real_name = M.real_name // mob's real name - var/mobkey = "none" // player key associated with mob - var/voicemask = 0 // the speaker is wearing a voice mask - if(M.client) - mobkey = M.key // assign the mob's key - - - var/jobname // the mob's "job" - - // --- Human: use their actual job --- - if (ishuman(M)) - var/mob/living/carbon/human/H = M - jobname = H.get_assignment() - - // --- Carbon Nonhuman --- - else if (iscarbon(M)) // Nonhuman carbon mob - jobname = "No id" - - // --- AI --- - else if (isAI(M)) - jobname = "AI" - - // --- Cyborg --- - else if (isrobot(M)) - jobname = "Robot" + var/list/current_sector = SSmapping.get_connected_levels(position.z) + var/use_frequency = frequency + if(message_mode && !analog) + var/list/current_channels = get_available_channels() + message_mode = lowertext(message_mode) + if(message_mode == MESSAGE_MODE_DEFAULT) + for(var/datum/radio_channel/channel in current_channels) + if(!channel.secured) + use_frequency = channel.frequency + break + if(!use_frequency) + for(var/datum/radio_channel/channel in current_channels) + if(channel.secured && can_decrypt(channel.secured)) + use_frequency = channel.frequency + break + + else if(message_mode == MESSAGE_MODE_DEPARTMENT) + for(var/datum/radio_channel/channel in current_channels) + if(channel.secured && can_decrypt(channel.secured)) + use_frequency = channel.frequency + break + if(!use_frequency) + for(var/datum/radio_channel/channel in current_channels) + if(!channel.secured) + use_frequency = channel.frequency + break + else + for(var/datum/radio_channel/channel in current_channels) + if(channel.key != message_mode || !(LAZYACCESS(channels, channel))) + continue + if(can_decrypt(channel.secured)) + use_frequency = channel.frequency + break - // --- Personal AI (pAI) --- - else if (istype(M, /mob/living/silicon/pai)) - jobname = "Personal AI" + if(analog && istype(analog_radio_connection)) + var/last_frequency = frequency + if(last_frequency != use_frequency) + set_frequency(use_frequency) - // --- Unidentifiable mob --- + broadcast_analog_radio_message(analog_radio_connection, speaker, src, message, intercom, message_compression, current_sector, verb, speaking, analog_secured) + if(frequency != last_frequency) + set_frequency(last_frequency) else - jobname = "Unknown" - - - // --- Modifications to the mob's identity --- - - // The mob is disguising their identity: - if (ishuman(M) && M.GetVoice() != real_name) - displayname = M.GetVoice() - jobname = "Unknown" - voicemask = 1 - - - - /* ###### Radio headsets can only broadcast through subspace ###### */ - if(subspace_transmission) - // First, we want to generate a new radio signal - var/datum/signal/signal = new - signal.transmission_method = 2 // 2 would be a subspace transmission. - // transmission_method could probably be enumerated through #define. Would be neater. - - // --- Finally, tag the actual signal with the appropriate values --- - signal.data = list( - // Identity-associated tags: - "mob" = M, // store a reference to the mob - "mobtype" = M.type, // the mob's type - "realname" = real_name, // the mob's real name - "name" = displayname, // the mob's display name - "job" = jobname, // the mob's job - "key" = mobkey, // the mob's key - "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood - "vname" = M.voice_name, // the name to display if the voice wasn't understood - "vmask" = voicemask, // 1 if the mob is using a voice gas mask - - // We store things that would otherwise be kept in the actual mob - // so that they can be logged even AFTER the mob is deleted or something - - // Other tags: - "compression" = rand(45,50), // compressed radio signal - "message" = message, // the actual sent message - "connection" = connection, // the radio connection to use - "radio" = src, // stores the radio used for transmission - "slow" = 0, // how much to sleep() before broadcasting - simulates net lag - "traffic" = 0, // dictates the total traffic sum that the signal went through - "type" = 0, // determines what type of radio input it is: normal broadcast - "server" = null, // the last server to log this signal - "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery - "level" = position.z, // The source's z level - "channel_tag" = "[connection.frequency]", // channel tag for the message - "channel_color" = channel_color_presets["Menacing Maroon"], // radio message color - "language" = speaking, - "verb" = verb - ) - signal.frequency = connection.frequency // Quick frequency set - - //#### Sending the signal to all subspace receivers ####// - - for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) - - // Allinone can act as receivers. - for(var/obj/machinery/telecomms/allinone/R in telecomms_list) - R.receive_signal(signal) - - // Receiving code can be located in Telecommunications.dm - if(signal.data["done"] && (position.z in signal.data["level"])) - return TRUE //Huzzah, sent via subspace - - else //Less huzzah, we have to fallback - for(var/obj/item/radio/R in loc) - if(!R.subspace_transmission) - return R.talk_into(M, message, channel, verb, speaking) - return FALSE - - /* ###### Intercoms and station-bounced radios ###### */ - - var/filter_type = 2 - - /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ - if(istype(src, /obj/item/radio/intercom)) - filter_type = 1 - - - var/datum/signal/signal = new - signal.transmission_method = 2 - - - /* --- Try to send a normal subspace broadcast first */ - - signal.data = list( - - "mob" = M, // store a reference to the mob - "mobtype" = M.type, // the mob's type - "realname" = real_name, // the mob's real name - "name" = displayname, // the mob's display name - "job" = jobname, // the mob's job - "key" = mobkey, // the mob's key - "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood - "vname" = M.voice_name, // the name to display if the voice wasn't understood - "vmask" = voicemask, // 1 if the mob is using a voice gas mas - - "compression" = 0, // uncompressed radio signal - "message" = message, // the actual sent message - "connection" = connection, // the radio connection to use - "radio" = src, // stores the radio used for transmission - "slow" = 0, - "traffic" = 0, - "type" = 0, - "server" = null, - "reject" = 0, - "level" = position.z, - "channel_tag" = "#unkn", - "channel_color" = channel_color_presets["Menacing Maroon"], - "language" = speaking, - "verb" = verb - ) - signal.frequency = connection.frequency // Quick frequency set - var/obj/item/cell/has_cell = get_cell() - if(has_cell && has_cell.percent() < 20) - signal.data["compression"] = max(0, 80 - has_cell.percent()*3) - for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) - - sleep(rand(10,25)) // wait a little... - - if(signal.data["done"] && (position.z in signal.data["level"])) - // we're done here. - return 1 - - // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level. - // Send a mundane broadcast with limited targets: - - //THIS IS TEMPORARY. YEAH RIGHT - if(!connection) return 0 //~Carn - return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), - src, message, displayname, jobname, real_name, M.voice_name, - filter_type, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency, verb, speaking, - "[connection.frequency]", channel_color_presets["Menacing Maroon"]) - + // List passed around to make sure a hub only checks for transmission once. + var/list/checked_hubs = list() + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/weakref/H as anything in network?.connected_hubs) + var/obj/machinery/network/telecomms_hub/hub = H.resolve() + if(istype(hub) && !QDELETED(hub) && hub.can_receive_message(network)) + hub.transmit_message(speaker, message, verb, speaking, use_frequency, message_compression, checked_hubs) + break // Only one hub per message, since it transmits over the whole network. + +/obj/item/radio/proc/can_receive_message(var/check_network_membership) + . = on + if(. && check_network_membership) + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + return network_device?.get_network() == check_network_membership /obj/item/radio/hear_talk(mob/M, msg, var/verb = "says", var/decl/language/speaking = null) + if(on && broadcasting && get_dist(src, M) <= canhear_range) + talk_into(M, msg, null, verb, speaking) - if (broadcasting) - if(get_dist(src, M) <= canhear_range) - talk_into(M, msg,null,verb,speaking) - - -/* -/obj/item/radio/proc/accept_rad(obj/item/radio/R, message) - - if ((R.frequency == frequency && message)) - return 1 - else if - - else - return null - return -*/ - - -/obj/item/radio/proc/receive_range(freq, level) - // check if this radio can receive on the given frequency, and if so, - // what the range is in which mobs will hear the radio - // returns: -1 if can't receive, range otherwise - - if (wires.IsIndexCut(WIRE_RECEIVE)) - return -1 - if(!listening) - return -1 - if(!(0 in level)) - var/turf/position = get_turf(src) - if(!position || !(position.z in level)) - return -1 - if(freq in ANTAG_FREQS) - if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys - return -1 - if (!on) - return -1 - if (!freq) //recieved on main frequency - if (!listening) - return -1 - else - var/accept = (freq==frequency && listening) - if (!accept) - for (var/ch_name in channels) - var/datum/radio_frequency/RF = secure_radio_connections[ch_name] - if (RF && RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING)) - accept = 1 - break - if (!accept) - return -1 - return canhear_range - -/obj/item/radio/proc/send_hear(freq, level) - - var/range = receive_range(freq, level) - if(range > -1) - return get_mobs_or_objects_in_view(canhear_range, src) - - -/obj/item/radio/examine(mob/user, distance) - . = ..() - if (distance <= 1 || loc == user) - if (b_stat) - to_chat(user, "\The [src] can be attached and modified!") - else - to_chat(user, "\The [src] can not be modified or attached!") - -/obj/item/radio/attackby(obj/item/W, mob/user) - ..() - user.set_machine(src) - if(isScrewdriver(W)) - b_stat = !b_stat - if(!istype(src, /obj/item/radio/beacon)) - if (b_stat) - user.show_message("\The [src] can now be attached and modified!") - else - user.show_message("\The [src] can no longer be modified or attached!") - updateDialog() - return - if(!cell && power_usage && istype(W, /obj/item/cell/device) && user.unEquip(W, target = src)) - to_chat(user, "You put [W] in \the [src].") - cell = W +/obj/item/radio/proc/get_accessible_channel_descriptions(var/mob/user) + var/prefix = user?.get_department_radio_prefix() + if(!prefix) return + for(var/datum/radio_channel/channel in get_available_channels()) + LAZYADD(., "- [channel.name || format_frequency(channel.frequency)]: [prefix][channel.key]") + if(can_transmit_binary()) + LAZYADD(., "- Robot talk: [prefix]+") -/obj/item/radio/emp_act(severity) - broadcasting = 0 - listening = 0 - for (var/ch_name in channels) - channels[ch_name] = 0 - if(cell) - cell.emp_act(severity) - ..() - -/obj/item/radio/proc/recalculateChannels() - return - -/////////////////////////////// -//////////Borg Radios////////// -/////////////////////////////// -//Giving borgs their own radio to have some more room to work with -Sieve - -/obj/item/radio/borg - var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks - var/obj/item/encryptionkey/keyslot = null//Borg radios can handle a single encryption key - var/shut_up = 1 - icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. - icon_state = "radio" - canhear_range = 0 - subspace_transmission = 1 - cell = null - power_usage = 0 - -/obj/item/radio/borg/ert - keyslot = /obj/item/encryptionkey/ert - -/obj/item/radio/borg/syndicate - keyslot = /obj/item/encryptionkey/syndicate - -/obj/item/radio/borg/Initialize() - . = ..() - if(!isrobot(loc)) - . = INITIALIZE_HINT_QDEL - CRASH("Invalid spawn location: [log_info_line(loc)]") - if(keyslot) - keyslot = new keyslot(src) - myborg = loc - recalculateChannels() - -/obj/item/radio/borg/Destroy() - QDEL_NULL(keyslot) - myborg = null - return ..() - -/obj/item/radio/borg/list_channels(var/mob/user) - return list_secure_channels(user) - -/obj/item/radio/borg/talk_into() +/obj/item/radio/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if (isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - var/datum/robot_component/C = R.components["radio"] - R.cell_use_power(C.active_usage) - -/obj/item/radio/borg/attackby(obj/item/W, mob/user) -// ..() + if (distance <= 1 || loc == user) + var/list/channel_descriptions = get_accessible_channel_descriptions(user) + if(length(channel_descriptions)) + . += "\The [src] has the following channel [length(channel_descriptions) == 1 ? "shortcut" : "shortcuts"] configured:" + for(var/line in channel_descriptions) + . += line + if(panel_open) + . += SPAN_WARNING("A panel on the back of \the [src] is hanging open.") + +/obj/item/radio/attackby(obj/item/used_item, mob/user) user.set_machine(src) - if (!( isScrewdriver(W) || (istype(W, /obj/item/encryptionkey/ )))) - return - - if(isScrewdriver(W)) - if(keyslot) - for(var/ch_name in channels) - radio_controller.remove_object(src, radiochannels[ch_name]) - secure_radio_connections[ch_name] = null - - if(keyslot) - keyslot.dropInto(user.loc) - - recalculateChannels() - to_chat(user, "You pop out the encryption key in the radio!") - - else - to_chat(user, "This radio doesn't have any encryption keys!") - - if(istype(W, /obj/item/encryptionkey/)) - if(keyslot) - to_chat(user, "The radio can't hold another key!") - return - - if(!keyslot) - if(!user.unEquip(W, src)) - return - keyslot = W - - recalculateChannels() - -/obj/item/radio/borg/recalculateChannels() - src.channels = list() - src.syndie = 0 - - var/mob/living/silicon/robot/D = src.loc - if(istype(D.module)) - for(var/ch_name in D.module.channels) - if(ch_name in src.channels) - continue - src.channels += ch_name - src.channels[ch_name] += D.module.channels[ch_name] - if(keyslot) - for(var/ch_name in keyslot.channels) - if(ch_name in src.channels) - continue - src.channels += ch_name - src.channels[ch_name] += keyslot.channels[ch_name] - - if(keyslot.syndie) - src.syndie = 1 - - for (var/ch_name in src.channels) - if(!radio_controller) - src.SetName("broken radio") - return - - secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) - -/obj/item/radio/borg/Topic(href, href_list) - if(..()) - return 1 - if (href_list["mode"]) - var/enable_subspace_transmission = text2num(href_list["mode"]) - if(enable_subspace_transmission != subspace_transmission) - subspace_transmission = !subspace_transmission - if(subspace_transmission) - to_chat(usr, "Subspace Transmission is enabled") - else - to_chat(usr, "Subspace Transmission is disabled") - - if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled - channels = list() - else - recalculateChannels() - . = 1 - if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. - var/do_shut_up = text2num(href_list["shutup"]) - if(do_shut_up != shut_up) - shut_up = !shut_up - if(shut_up) - canhear_range = 0 - to_chat(usr, "Loadspeaker disabled.") - else - canhear_range = 3 - to_chat(usr, "Loadspeaker enabled.") - . = 1 - - if(.) - SSnano.update_uis(src) -/obj/item/radio/borg/interact(mob/user) - if(!on) - return + if(istype(used_item, /obj/item/encryptionkey)) + if(!encryption_key_capacity) + to_chat(user, SPAN_WARNING("\The [src] cannot accept an encryption key.")) + return TRUE + if(length(encryption_keys) >= encryption_key_capacity) + to_chat(user, SPAN_WARNING("\The [src] cannot fit any more encryption keys.")) + return TRUE + if(user.try_unequip(used_item, src)) + LAZYADD(encryption_keys, used_item) + channels = null + return TRUE + + if(IS_SCREWDRIVER(used_item)) + if(length(encryption_keys)) + var/obj/item/encryptionkey/ekey = pick(encryption_keys) + ekey.dropInto(loc) + encryption_keys -= ekey + channels = null + to_chat(user, SPAN_NOTICE("You pop \the [ekey] out of \the [src].")) + sanitize_analog_secured() + return TRUE + return toggle_panel(user) . = ..() -/obj/item/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) - - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len +/obj/item/radio/proc/toggle_panel(var/mob/user) + panel_open = !panel_open + if(user) + user.show_message(SPAN_NOTICE("\The [src] can [panel_open ? "now" : "no longer"] be attached or modified!")) + return TRUE - if(syndie) - data["useSyndMode"] = 1 - - data["has_loudspeaker"] = 1 - data["loudspeaker"] = !shut_up - data["has_subspace"] = 1 - data["subspace"] = subspace_transmission - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() - -/obj/item/radio/proc/config(op) - if(radio_controller) - for (var/ch_name in channels) - radio_controller.remove_object(src, radiochannels[ch_name]) - secure_radio_connections = new - channels = op - if(radio_controller) - for (var/ch_name in op) - secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) - return - -/obj/item/radio/off - listening = 0 - -/obj/item/radio/announcer - invisibility = 101 - listening = 0 - canhear_range = 0 - anchored = 1 - simulated = 0 - power_usage = 0 - channels=list("Engineering" = 1, "Security" = 1, "Medical" = 1, "Command" = 1, "Common" = 1, "Science" = 1, "Supply" = 1, "Service" = 1, "Exploration" = 1) - cell = null - -/obj/item/radio/announcer/Destroy() - SHOULD_CALL_PARENT(FALSE) - crash_with("attempt to delete a [src.type] detected, and prevented.") - return QDEL_HINT_LETMELIVE - -/obj/item/radio/announcer/Initialize() - . = ..() - forceMove(locate(1,1,GLOB.using_map.contact_levels.len ? GLOB.using_map.contact_levels[1] : 1)) - -/obj/item/radio/announcer/subspace - subspace_transmission = 1 - -/obj/item/radio/phone +/obj/item/radio/emp_act(severity) broadcasting = 0 - icon = 'icons/obj/items/red_phone.dmi' - icon_state = "red_phone" - randpixel = 0 - listening = 1 - name = "phone" - -/obj/item/radio/phone/medbay - frequency = MED_I_FREQ - -/obj/item/radio/phone/medbay/Initialize() - . = ..() - internal_channels = GLOB.default_medbay_channels.Copy() + listening = 0 + var/list/current_channels = get_available_channels() + for(var/channel in current_channels) + LAZYSET(channels, channel, FALSE) + return ..() /obj/item/radio/CouldUseTopic(var/mob/user) ..() - if(istype(user, /mob/living/carbon)) + if(isliving(user)) playsound(src, "button", 10) -/obj/item/radio/intercept - name = "bulky radio" - desc = "A large radio fitted with several military-grade communication interception circuits." - icon_state = "radio" - intercept = 1 - w_class = ITEM_SIZE_NORMAL - - -//The exosuit radio subtype. It allows pilots to interact and consumes exosuit power - -/obj/item/radio/exosuit - name = "exosuit radio" - cell = null - -/obj/item/radio/exosuit/get_cell() - . = ..() - if(!.) - var/mob/living/exosuit/E = loc - if(istype(E)) - return E.get_cell() - -/obj/item/radio/exosuit/nano_host() - var/mob/living/exosuit/E = loc - if(istype(E)) - return E - return null - -/obj/item/radio/exosuit/attack_self(var/mob/user) - var/mob/living/exosuit/exosuit = loc - if(istype(exosuit) && exosuit.head && exosuit.head.radio && exosuit.head.radio.is_functional()) - user.set_machine(src) - interact(user) - else - to_chat(user, SPAN_WARNING("The radio is too damaged to function.")) - -/obj/item/radio/exosuit/CanUseTopic() - . = ..() - if(.) - var/mob/living/exosuit/exosuit = loc - if(istype(exosuit) && exosuit.head && exosuit.head.radio && exosuit.head.radio.is_functional()) - return ..() - -/obj/item/radio/exosuit/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.mech_state) - . = ..() +/obj/item/radio/off + listening = FALSE diff --git a/code/game/objects/items/devices/radio/radio_analog.dm b/code/game/objects/items/devices/radio/radio_analog.dm new file mode 100644 index 000000000000..c5f51e30385f --- /dev/null +++ b/code/game/objects/items/devices/radio/radio_analog.dm @@ -0,0 +1,99 @@ +/// check if this radio can receive on the given analog frequency +/// @level: list of eligible z-levels, if it contains 0 then it reaches all levels +/obj/item/radio/proc/can_receive_analog(datum/radio_frequency/connection, z_levels) + if(!analog || !istype(analog_radio_connection) || connection != analog_radio_connection) + return FALSE + if(!listening) + return FALSE + if (!on) + return FALSE + if(QDELETED(src)) + return FALSE + if (wires.IsIndexCut(WIRE_RECEIVE)) + return FALSE + if(!(0 in z_levels) && !(get_z(src) in z_levels)) + return FALSE + return TRUE + +/proc/broadcast_analog_radio_message(datum/radio_frequency/connection, mob/speaker, + obj/item/radio/radio, message, intercom_only = FALSE, + hard_to_hear, list/z_levels, verbage = "says", decl/language/speaking = null, list/secured + ) + + var/list/radios = list(radio) + var/list/radios_insecure = list() + for(var/obj/item/radio/radio_receiver in connection.devices["[RADIO_CHAT]"]) + // Quasi-wired mode; remove if intercoms ever use actual wired connections somehow. + if(intercom_only && !radio_receiver.intercom) + continue + if(!radio_receiver.analog) + continue + if(radio_receiver == radio) + continue + if(!radio_receiver.can_receive_message()) + continue + if(radio_receiver.can_receive_analog(connection, z_levels)) + radio_receiver.received_chatter(connection.frequency, z_levels) + if(secured && !radio_receiver.can_decrypt(secured)) + radios_insecure += radio_receiver + continue + radios += radio_receiver + + // Get a list of mobs who can hear from the radios we collected. + var/list/receive = get_mobs_in_analog_radio_ranges(radios) + var/list/receive_insecure = get_mobs_in_analog_radio_ranges(radios_insecure, include_ghosts = FALSE) + + // Format the message + var/formatted_msg = "\[[format_frequency(connection.frequency)]\] " + var/send_name = istype(speaker) ? speaker.real_name : ("[speaker]" || "unknown") + // We have to reuse these strings because otherwise, they trigger a false positive + // on the (overzealous) tag matcher CI check. + var/part_b = " " + var/part_c = "" + + // Send to all recipients + for (var/mob/receiver in receive) + receiver.hear_radio(message, verbage, speaking, formatted_msg, part_b, part_c, speaker, hard_to_hear, send_name) + + if(length(receive_insecure)) + var/decl/language/machine/noise_lang = GET_DECL(/decl/language/machine) + var/scrambled_message = noise_lang.scramble(null, message, null) + for (var/mob/receiver in receive_insecure) + receiver.hear_radio(scrambled_message, verbage, speaking, formatted_msg, part_b, part_c, speaker, hard_to_hear, "unknown") + + return TRUE + +/// Returns a list of mobs who can hear any of the radios given in @radios +/// Assume all the radios in the list are eligible; we just care about mobs +/proc/get_mobs_in_analog_radio_ranges(list/obj/item/radio/radios, include_ghosts = TRUE) + . = list() + for(var/obj/item/radio/receiver_candidate in radios) + if(receiver_candidate.virtual) + continue // We end up in this list because we need to receive signals, but should never actually display a message. + var/turf/speaking_from = get_turf(receiver_candidate) + if(speaking_from) + // Try to find all the players who can hear the message + for(var/mob/local_listener in hearers(receiver_candidate.canhear_range, speaking_from)) + . |= local_listener + + if (!include_ghosts) + return . + + for(var/mob/observer/ghost/ghost_listener as anything in global.ghost_mob_list) + // Ghostship is magic: Ghosts can hear radio chatter from anywhere + if(ghost_listener.get_preference_value(/datum/client_preference/ghost_radio) == PREF_ALL_CHATTER) + . |= ghost_listener + return . + +/obj/item/radio/shortwave + name = "shortwave radio" + desc = "A shortwave radio. Unlike modern radios which support digital mode, this radio is dirt-cheap and solely supports analog connections." + radio_device_type = null // can only use analog + can_use_analog = TRUE + analog = TRUE + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_HOLLOW // much cheaper, fewer internal components. + +/obj/item/radio/shortwave/off + listening = FALSE diff --git a/code/game/objects/items/devices/radio/radio_announcer.dm b/code/game/objects/items/devices/radio/radio_announcer.dm new file mode 100644 index 000000000000..3a7ab5563328 --- /dev/null +++ b/code/game/objects/items/devices/radio/radio_announcer.dm @@ -0,0 +1,44 @@ +var/global/list/announcers = list() + +/proc/get_announcer(var/z) + if(isatom(z)) + var/turf/T = get_turf(z) + z = T?.z + if(!z) + return null + if(!global.announcers["[z]"]) + var/list/connected = SSmapping.get_connected_levels(z) + var/obj/item/radio/announcer/announcer = new(null, z) + for(var/oz in connected) + global.announcers["[oz]"] = announcer + SSnetworking.try_connect(get_extension(announcer, /datum/extension/network_device)) // Force an immediate check instead of waiting. + announcer.sync_channels_with_network() + return global.announcers["[z]"] + +/obj/item/radio/announcer + canhear_range = 0 + power_usage = 0 + listening = FALSE + anchored = TRUE + simulated = FALSE + invisibility = INVISIBILITY_MAXIMUM + decrypt_all_messages = TRUE + is_spawnable_type = FALSE + +/obj/item/radio/announcer/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/radio/announcer/Destroy() + SHOULD_CALL_PARENT(FALSE) + PRINT_STACK_TRACE("attempt to delete a [src.type] prevented.") + return QDEL_HINT_LETMELIVE + +// NOTE TO SELF: this is not really viable, protect it against being blown up somehow +/obj/item/radio/announcer/Initialize(var/ml, var/nz) + var/list/sector = SSmapping.get_connected_levels(nz) + for(var/obj/machinery/network/telecomms_hub/T in global.telecomms_hubs) + if((T.z in sector) && T.can_receive_message()) + forceMove(get_turf(T)) + break + . = ..() diff --git a/code/game/objects/items/devices/radio/radio_borg.dm b/code/game/objects/items/devices/radio/radio_borg.dm new file mode 100644 index 000000000000..6ce348ceaaa3 --- /dev/null +++ b/code/game/objects/items/devices/radio/radio_borg.dm @@ -0,0 +1,49 @@ +/obj/item/radio/borg + icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. + icon_state = "radio" + canhear_range = 0 + power_usage = 0 + is_spawnable_type = FALSE + var/shut_up = 1 + +/obj/item/radio/borg/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/radio/borg/can_receive_message(var/check_network_membership) + . = ..() && isrobot(loc) + if(.) + var/mob/living/silicon/robot/robot = loc + if(!robot.handle_radio_transmission()) + return FALSE + +/obj/item/radio/borg/syndicate + encryption_keys = list(/obj/item/encryptionkey/hacked) + +/obj/item/radio/borg/Initialize() + . = ..() + if(!isrobot(loc)) + . = INITIALIZE_HINT_QDEL + CRASH("Invalid spawn location: [log_info_line(loc)]") + +/obj/item/radio/borg/talk_into(mob/living/M, message, message_mode, var/verb = "says", var/decl/language/speaking = null) + . = ..() + if(isrobot(loc)) + var/mob/living/silicon/robot/robot = src.loc + robot.handle_radio_transmission() + +/obj/item/radio/borg/OnTopic(mob/user, href_list, datum/topic_state/state) + if((. = ..())) + return + + if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. + var/do_shut_up = text2num(href_list["shutup"]) + if(do_shut_up != shut_up) + shut_up = !shut_up + if(shut_up) + canhear_range = 0 + to_chat(usr, SPAN_NOTICE("Loudspeaker disabled.")) + else + canhear_range = 3 + to_chat(usr, SPAN_NOTICE("Loudspeaker enabled.")) + . = TOPIC_REFRESH diff --git a/code/game/objects/items/devices/radio/radio_exosuit.dm b/code/game/objects/items/devices/radio/radio_exosuit.dm new file mode 100644 index 000000000000..88b782443d23 --- /dev/null +++ b/code/game/objects/items/devices/radio/radio_exosuit.dm @@ -0,0 +1,36 @@ +//The exosuit radio subtype. It allows pilots to interact and consumes exosuit power +/obj/item/radio/exosuit + name = "exosuit radio" + +/obj/item/radio/exosuit/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/radio/exosuit/get_cell() + if(isexosuit(loc)) + var/mob/living/exosuit/E = loc + return E.get_cell() + return ..() + +/obj/item/radio/exosuit/nano_host() + if(isexosuit(loc)) + return loc + +/obj/item/radio/exosuit/attack_self(var/mob/user) + var/mob/living/exosuit/exosuit = loc + if(istype(exosuit) && exosuit.head && exosuit.head.radio && exosuit.head.radio.is_functional()) + user.set_machine(src) + interact(user) + else + to_chat(user, SPAN_WARNING("The radio is too damaged to function.")) + +/obj/item/radio/exosuit/CanUseTopic() + . = ..() + if(.) + var/mob/living/exosuit/exosuit = loc + if(istype(exosuit) && exosuit.head && exosuit.head.radio && exosuit.head.radio.is_functional()) + return ..() + +/// Overridden solely to change the default topic state supplied. +/obj/item/radio/exosuit/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.mech_topic_state) + . = ..() diff --git a/code/game/objects/items/devices/radio/radio_misc.dm b/code/game/objects/items/devices/radio/radio_misc.dm new file mode 100644 index 000000000000..5d733febc83d --- /dev/null +++ b/code/game/objects/items/devices/radio/radio_misc.dm @@ -0,0 +1,15 @@ +/obj/item/radio/phone + name = "phone" + broadcasting = 0 + icon = 'icons/obj/items/red_phone.dmi' + icon_state = "red_phone" + randpixel = 0 + listening = TRUE + +/obj/item/radio/intercept + name = "bulky radio" + desc = "A large radio fitted with several military-grade communication interception circuits." + icon_state = "radio" + w_class = ITEM_SIZE_NORMAL + decrypt_all_messages = TRUE + diff --git a/code/game/objects/items/devices/scanners/mass_spectrometer.dm b/code/game/objects/items/devices/scanners/mass_spectrometer.dm deleted file mode 100644 index c20897862946..000000000000 --- a/code/game/objects/items/devices/scanners/mass_spectrometer.dm +++ /dev/null @@ -1,89 +0,0 @@ -/obj/item/scanner/spectrometer - name = "mass spectrometer" - desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample or analyzes unusual chemicals." - icon = 'icons/obj/items/device/scanner/spectrometer.dmi' - icon_state = "spectrometer" - item_state = "analyzer" - - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER - origin_tech = "{'magnets':2,'biotech':2}" - window_width = 550 - window_height = 300 - scan_sound = 'sound/effects/scanbeep.ogg' - var/details = 0 - -/obj/item/scanner/spectrometer/Initialize() - . = ..() - create_reagents(5) - -/obj/item/scanner/spectrometer/on_reagent_change() - update_icon() - -/obj/item/scanner/spectrometer/on_update_icon() - icon_state = initial(icon_state) - if(reagents.total_volume) - icon_state += "_s" - -/obj/item/scanner/spectrometer/is_valid_scan_target(atom/O) - if(!O.reagents || !O.reagents.total_volume) - return FALSE - return (O.atom_flags & ATOM_FLAG_OPEN_CONTAINER) || istype(O, /obj/item/chems/syringe) - -/obj/item/scanner/spectrometer/scan(atom/A, mob/user) - if(A != src) - to_chat(user, "\The [src] takes a sample out of \the [A]") - reagents.clear_reagents() - A.reagents.trans_to(src, 5) - scan_title = "Spectrometer scan - [A]" - scan_data = mass_spectrometer_scan(reagents, user, details) - reagents.clear_reagents() - user.show_message(scan_data) - -/obj/item/scanner/spectrometer/attack_self(mob/user) - if(!can_use(user)) - return - if(reagents.total_volume) - scan(src, user) - else - ..() - -/proc/mass_spectrometer_scan(var/datum/reagents/reagents, mob/user, var/details) - if(!reagents || !reagents.total_volume) - return "No sample to scan." - var/list/blood_traces = list() - var/list/blood_doses = list() - - if(length(reagents.reagent_volumes) == 1) - var/decl/material/liquid/random/random = decls_repository.get_decl(reagents.reagent_volumes[1]) - if(istype(random)) - return random.get_scan_data(user) - - for(var/R in reagents.reagent_volumes) - if(!ispath(R, /decl/material/liquid/blood)) - return "The sample was contaminated! Please insert another sample" - var/data = REAGENT_DATA(reagents, R) - if(islist(data)) - blood_traces = data["trace_chem"] - blood_doses = data["dose_chem"] - break - - var/list/dat = list("Trace Chemicals Found: ") - for(var/T in blood_traces) - var/decl/material/R = T - if(details) - dat += "[initial(R.name)] ([blood_traces[T]] units) " - else - dat += "[initial(R.name)] " - if(details) - dat += "Metabolism Products of Chemicals Found:" - for(var/T in blood_doses) - var/decl/material/R = T - dat += "[initial(R.name)] ([blood_doses[T]] units) " - - return jointext(dat, "
              ") - -/obj/item/scanner/spectrometer/adv - name = "advanced mass spectrometer" - icon_state = "adv_spectrometer" - details = 1 - origin_tech = "{'magnets':4,'biotech':2}" \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/mining.dm b/code/game/objects/items/devices/scanners/mining.dm deleted file mode 100644 index 847e2c0860ab..000000000000 --- a/code/game/objects/items/devices/scanners/mining.dm +++ /dev/null @@ -1,106 +0,0 @@ -/turf/simulated - var/surveyed - -/obj/item/scanner/mining - name = "ore detector" - desc = "A complex device used to locate ore deep underground." - icon = 'icons/obj/items/device/scanner/ore_scanner.dmi' - icon_state = "ore" - origin_tech = "{'magnets':1,'engineering':1}" - use_delay = 50 - printout_color = "#fff7f0" - var/survey_data = 0 - - scan_sound = 'sound/effects/ping.ogg' - -/obj/item/scanner/mining/examine(mob/user) - . = ..() - to_chat(user,"A tiny indicator on the [src] shows it holds [survey_data] good explorer points.") - -/obj/item/scanner/mining/is_valid_scan_target(turf/simulated/T) - return istype(T) - -/obj/item/scanner/mining/scan(turf/simulated/T, mob/user) - scan_title = "Mineral scan data" - var/list/scan_results = mineral_scan_results(T) - if(!scan_data) - scan_data = scan_results[1] - else - scan_data += "
              [scan_results[1]]" - to_chat(user, "\icon[src] \The [src] displays a readout.") - to_chat(user, scan_results[1]) - - if(scan_results[2]) - survey_data += scan_results[2] - playsound(loc, 'sound/machines/ping.ogg', 40, 1) - to_chat(user,"New survey data stored - [scan_results[2]] GEP.") - -/obj/item/scanner/mining/proc/put_disk_in_hand(var/mob/M) - if(!survey_data) - to_chat(M,"There is no survey data stored on the [src].") - return 0 - visible_message("The [src] spits out a disk containing [survey_data] GEP.") - var/obj/item/disk/survey/D = new(get_turf(src)) - D.data = survey_data - survey_data = 0 - M.put_in_hands(D) - return 1 - -/obj/item/scanner/mining/verb/get_data() - set category = "Object" - set name = "Get Survey Data" - set src in usr - - var/mob/M = usr - if(!istype(M)) - return - if(M.incapacitated()) - return - put_disk_in_hand(M) - -/obj/item/disk/survey - name = "survey data disk" - icon = 'icons/obj/items/device/diskette.dmi' - icon_state = "nucleardisk" - var/data - -/obj/item/disk/survey/examine(mob/user) - . = ..() - to_chat(user,"A tiny indicator on the [src] shows it holds [data] good explorer points.") - -//Returns list of two elements, 1 is text output, 2 is amoutn of GEP data -/proc/mineral_scan_results(turf/simulated/target) - var/list/metals = list( - ORE_SURFACE = 0, - ORE_PRECIOUS = 0, - ORE_NUCLEAR = 0, - ORE_EXOTIC = 0 - ) - var/new_data = 0 - - for(var/turf/simulated/T in range(2, target)) - - if(!T.has_resources) - continue - - for(var/metal in T.resources) - var/decl/material/mat = decls_repository.get_decl(metal) - if(mat.ore_type_value) - metals[mat.ore_type_value] += T.resources[metal] - if(mat.ore_data_value && !T.surveyed) - new_data += mat.ore_data_value * T.resources[metal] - - T.surveyed = 1 - - var/list/scandata = list("Mineral scan at ([target.x],[target.y])") - for(var/ore_type in metals) - var/result = "no sign" - - switch(metals[ore_type]) - if(1 to 25) result = "trace amounts" - if(26 to 75) result = "significant amounts" - if(76 to INFINITY) result = "huge quantities" - - scandata += "- [result] of [ore_type]." - - return list(jointext(scandata, "
              "), new_data) \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/plant.dm b/code/game/objects/items/devices/scanners/plant.dm deleted file mode 100644 index f5a7267fdeaf..000000000000 --- a/code/game/objects/items/devices/scanners/plant.dm +++ /dev/null @@ -1,188 +0,0 @@ - -/obj/item/scanner/plant - name = "plant analyzer" - desc = "A hand-held botanical scanner used to analyze plants." - icon = 'icons/obj/items/device/scanner/plant_scanner.dmi' - icon_state = "hydro" - item_state = "analyzer" - scan_sound = 'sound/effects/fastbeep.ogg' - printout_color = "#eeffe8" - var/global/list/valid_targets = list( - /obj/item/chems/food/snacks/grown, - /obj/item/grown, - /obj/machinery/portable_atmospherics/hydroponics, - /obj/item/seeds - ) - -/obj/item/scanner/plant/is_valid_scan_target(atom/O) - if(is_type_in_list(O, valid_targets)) - return TRUE - return FALSE - -/obj/item/scanner/plant/scan(atom/A, mob/user) - scan_title = "[A] at [get_area(A)]" - scan_data = plant_scan_results(A) - show_menu(user) - -/proc/plant_scan_results(obj/target) - var/datum/seed/grown_seed - var/datum/reagents/grown_reagents - if(istype(target,/obj/item/chems/food/snacks/grown)) - var/obj/item/chems/food/snacks/grown/G = target - grown_seed = SSplants.seeds[G.plantname] - grown_reagents = G.reagents - - else if(istype(target,/obj/item/grown)) - var/obj/item/grown/G = target - grown_seed = SSplants.seeds[G.plantname] - grown_reagents = G.reagents - - else if(istype(target,/obj/item/seeds)) - var/obj/item/seeds/S = target - grown_seed = S.seed - - else if(istype(target,/obj/machinery/portable_atmospherics/hydroponics)) - var/obj/machinery/portable_atmospherics/hydroponics/H = target - grown_seed = H.seed - grown_reagents = H.reagents - - if(!grown_seed) - return - - if(grown_seed.mysterious && !grown_seed.scanned) - grown_seed.scanned = TRUE - var/area/map = locate(/area/overmap) - for(var/obj/effect/overmap/visitable/sector/exoplanet/P in map) - if(grown_seed in P.small_flora_types) - SSstatistics.add_field(STAT_XENOPLANTS_SCANNED, 1) - break - - var/list/dat = list() - - var/form_title = "[grown_seed.seed_name] (#[grown_seed.uid])" - dat += "

              Plant data for [form_title]

              " - - dat += "

              General Data

              " - - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
              Endurance[grown_seed.get_trait(TRAIT_ENDURANCE)]
              Yield[grown_seed.get_trait(TRAIT_YIELD)]
              Maturation time[grown_seed.get_trait(TRAIT_MATURATION)]
              Production time[grown_seed.get_trait(TRAIT_PRODUCTION)]
              Potency[grown_seed.get_trait(TRAIT_POTENCY)]
              " - - if(LAZYLEN(grown_reagents?.reagent_volumes)) - dat += "

              Reagent Data

              " - dat += "
              This sample contains: " - for(var/rtype in grown_reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - dat += "
              - [R.name], [REAGENT_VOLUME(grown_reagents, rtype)] unit(s)" - - dat += "

              Other Data

              " - - if(grown_seed.get_trait(TRAIT_HARVEST_REPEAT)) - dat += "This plant can be harvested repeatedly.
              " - - if(grown_seed.get_trait(TRAIT_IMMUTABLE) == -1) - dat += "This plant is highly mutable.
              " - else if(grown_seed.get_trait(TRAIT_IMMUTABLE) > 0) - dat += "This plant does not possess genetics that are alterable.
              " - - if(grown_seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) - if(grown_seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) - dat += "It consumes a small amount of nutrient fluid.
              " - else if(grown_seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) - dat += "It requires a heavy supply of nutrient fluid.
              " - else - dat += "It requires a supply of nutrient fluid.
              " - - if(grown_seed.get_trait(TRAIT_REQUIRES_WATER)) - if(grown_seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) - dat += "It requires very little water.
              " - else if(grown_seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) - dat += "It requires a large amount of water.
              " - else - dat += "It requires a stable supply of water.
              " - - if(grown_seed.mutants && grown_seed.mutants.len) - dat += "It exhibits a high degree of potential subspecies shift.
              " - - dat += "It thrives in a temperature of [grown_seed.get_trait(TRAIT_IDEAL_HEAT)] Kelvin." - - if(grown_seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) - dat += "
              It is well adapted to low pressure levels." - if(grown_seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) - dat += "
              It is well adapted to high pressure levels." - - if(grown_seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) - dat += "
              It is well adapted to a range of temperatures." - else if(grown_seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) - dat += "
              It is very sensitive to temperature shifts." - - dat += "
              It thrives in a light level of [grown_seed.get_trait(TRAIT_IDEAL_LIGHT)] lumen[grown_seed.get_trait(TRAIT_IDEAL_LIGHT) == 1 ? "" : "s"]." - - if(grown_seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) - dat += "
              It is well adapted to a range of light levels." - else if(grown_seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) - dat += "
              It is very sensitive to light level shifts." - - if(grown_seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) - dat += "
              It is highly sensitive to toxins." - else if(grown_seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) - dat += "
              It is remarkably resistant to toxins." - - if(grown_seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) - dat += "
              It is highly sensitive to pests." - else if(grown_seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) - dat += "
              It is remarkably resistant to pests." - - if(grown_seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) - dat += "
              It is highly sensitive to weeds." - else if(grown_seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) - dat += "
              It is remarkably resistant to weeds." - - switch(grown_seed.get_trait(TRAIT_SPREAD)) - if(1) - dat += "
              It is able to be planted outside of a tray." - if(2) - dat += "
              It is a robust and vigorous vine that will spread rapidly." - - switch(grown_seed.get_trait(TRAIT_CARNIVOROUS)) - if(1) - dat += "
              It is carnivorous and will eat tray pests for sustenance." - if(2) - dat += "
              It is carnivorous and poses a significant threat to living things around it." - - if(grown_seed.get_trait(TRAIT_PARASITE)) - dat += "
              It is capable of parisitizing and gaining sustenance from tray weeds." - if(grown_seed.get_trait(TRAIT_ALTER_TEMP)) - dat += "
              It will periodically alter the local temperature by [grown_seed.get_trait(TRAIT_ALTER_TEMP)] degrees Kelvin." - - if(grown_seed.get_trait(TRAIT_BIOLUM)) - dat += "
              It is [grown_seed.get_trait(TRAIT_BIOLUM_COLOUR) ? "bio-luminescent" : "bio-luminescent"]." - - if(grown_seed.get_trait(TRAIT_PRODUCES_POWER)) - dat += "
              The fruit will function as a battery if prepared appropriately." - - if(grown_seed.get_trait(TRAIT_STINGS)) - dat += "
              The fruit is covered in stinging spines." - - if(grown_seed.get_trait(TRAIT_JUICY) == 1) - dat += "
              The fruit is soft-skinned and juicy." - else if(grown_seed.get_trait(TRAIT_JUICY) == 2) - dat += "
              The fruit is excessively juicy." - - if(grown_seed.get_trait(TRAIT_EXPLOSIVE)) - dat += "
              The fruit is internally unstable." - - if(grown_seed.get_trait(TRAIT_TELEPORTING)) - dat += "
              The fruit is temporal/spatially unstable." - - if(grown_seed.get_trait(TRAIT_EXUDE_GASSES)) - dat += "
              It will release gas into the environment." - - if(grown_seed.get_trait(TRAIT_CONSUME_GASSES)) - dat += "
              It will remove gas from the environment." - - return JOINTEXT(dat) \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/reagents.dm b/code/game/objects/items/devices/scanners/reagents.dm deleted file mode 100644 index 1307b9f837da..000000000000 --- a/code/game/objects/items/devices/scanners/reagents.dm +++ /dev/null @@ -1,35 +0,0 @@ -/obj/item/scanner/reagent - name = "reagent scanner" - desc = "A hand-held reagent scanner which identifies chemical agents." - icon = 'icons/obj/items/device/scanner/spectrometer.dmi' - icon_state = "spectrometer" - item_state = "analyzer" - - origin_tech = "{'magnets':2,'biotech':2}" - scan_sound = 'sound/effects/scanbeep.ogg' - var/details = 0 - -/obj/item/scanner/reagent/is_valid_scan_target(obj/O) - return istype(O) - -/obj/item/scanner/reagent/scan(obj/O, mob/user) - scan_data = reagent_scan_results(O, details) - scan_data = jointext(scan_data, "
              ") - user.show_message(SPAN_NOTICE(scan_data)) - -/proc/reagent_scan_results(obj/O, details = 0) - if(isnull(O.reagents)) - return list("No significant chemical agents found in [O].") - if(!LAZYLEN(O.reagents.reagent_volumes)) - return list("No active chemical agents found in [O].") - . = list("Chemicals found in [O]:") - var/one_percent = O.reagents.total_volume / 100 - for (var/rtype in O.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - . += "[R.name][details ? ": [REAGENT_VOLUME(O.reagents, rtype) / one_percent]%" : ""]" - -/obj/item/scanner/reagent/adv - name = "advanced reagent scanner" - icon_state = "adv_spectrometer" - details = 1 - origin_tech = "{'magnets':4,'biotech':2}" \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/xenobio.dm b/code/game/objects/items/devices/scanners/xenobio.dm deleted file mode 100644 index 30284dea0a10..000000000000 --- a/code/game/objects/items/devices/scanners/xenobio.dm +++ /dev/null @@ -1,115 +0,0 @@ -/obj/item/scanner/xenobio - name = "xenolife scanner" - desc = "Multipurpose organic life scanner. With spectral breath analyzer you can find out what snacks Ian had! Or what gasses alien life breathes." - icon = 'icons/obj/items/device/scanner/xenobio_scanner.dmi' - icon_state = "xenobio" - item_state = "analyzer" - scan_sound = 'sound/effects/scanbeep.ogg' - printout_color = "#f3e6ff" - origin_tech = "{'magnets':1,'biotech':1}" - material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE - ) - - var/list/valid_targets = list( - /mob/living/carbon/human, - /mob/living/simple_animal, - /mob/living/carbon/slime - ) - -/obj/item/scanner/xenobio/is_valid_scan_target(atom/O) - if(is_type_in_list(O, valid_targets)) - return TRUE - if(istype(O, /obj/structure/stasis_cage)) - var/obj/structure/stasis_cage/cagie = O - return !!cagie.contained - return FALSE - -/obj/item/scanner/xenobio/scan(mob/O, mob/user) - scan_title = O.name - scan_data = xenobio_scan_results(O) - user.show_message(SPAN_NOTICE(scan_data)) - -/proc/list_gases(var/gases) - . = list() - for(var/g in gases) - var/decl/material/mat = decls_repository.get_decl(g) - . += "[capitalize(mat.gas_name)] ([gases[g]]%)" - return english_list(.) - -/proc/xenobio_scan_results(mob/target) - . = list() - if(istype(target, /obj/structure/stasis_cage)) - var/obj/structure/stasis_cage/cagie = target - target = cagie.contained - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - . += "Data for [H]:" - . += "Species:\t[H.species]" - if(H.species.breath_type) - var/decl/material/mat = decls_repository.get_decl(H.species.breath_type) - . += "Breathes:\t[mat.gas_name]" - if(H.species.exhale_type) - var/decl/material/mat = decls_repository.get_decl(H.species.exhale_type) - . += "Exhales:\t[mat.gas_name]" - . += "Known toxins:\t[english_list(H.species.poison_types)]" - . += "Temperature comfort zone:\t[H.species.cold_discomfort_level] K to [H.species.heat_discomfort_level] K" - . += "Pressure comfort zone:\t[H.species.warning_low_pressure] kPa to [H.species.warning_high_pressure] kPa" - else if(istype(target, /mob/living/simple_animal)) - var/mob/living/simple_animal/A = target - . += "Data for [A]:" - . += "Species:\t[initial(A.name)]" - . += "Breathes:\t[list_gases(A.min_gas)]" - . += "Known toxins:\t[list_gases(A.max_gas)]" - . += "Temperature comfort zone:\t[A.minbodytemp] K to [A.maxbodytemp] K" - var/area/map = locate(/area/overmap) - for(var/obj/effect/overmap/visitable/sector/exoplanet/P in map) - if((A in P.animals) || is_type_in_list(A, P.repopulate_types)) - var/list/discovered = SSstatistics.get_field(STAT_XENOFAUNA_SCANNED) - if(!discovered) - discovered = list() - discovered |= "[P.name]-[A.type]" - SSstatistics.set_field(STAT_XENOFAUNA_SCANNED, discovered) - . += "New xenofauna species discovered!" - break - else if(istype(target, /mob/living/carbon/slime/)) - var/mob/living/carbon/slime/T = target - . += "Slime scan result for \the [T]:" - . += "[T.colour] [T.is_adult ? "adult" : "baby"] slime" - . += "Nutrition:\t[T.nutrition]/[T.get_max_nutrition()]" - if(T.nutrition < T.get_starve_nutrition()) - . += "Warning:\tthe slime is starving!" - else if (T.nutrition < T.get_hunger_nutrition()) - . += "Warning:\tthe slime is hungry." - . += "Electric charge strength:\t[T.powerlevel]" - . += "Health:\t[round((T.health * 100) / T.maxHealth)]%" - - var/list/mutations = T.GetMutations() - - if(!mutations.len) - . += "This slime will never mutate." - else - var/list/mutationChances = list() - for(var/i in mutations) - if(i == T.colour) - continue - if(mutationChances[i]) - mutationChances[i] += T.mutation_chance / mutations.len - else - mutationChances[i] = T.mutation_chance / mutations.len - - var/list/mutationTexts = list("[T.colour] ([100 - T.mutation_chance]%)") - for(var/i in mutationChances) - mutationTexts += "[i] ([mutationChances[i]]%)" - - . += "Possible colours on splitting:\t[english_list(mutationTexts)]" - - if (T.cores > 1) - . += "Anomalous slime core amount detected." - . += "Growth progress:\t[T.amount_grown]/10." - else - . += "Incompatible life form, analysis failed." - - . = jointext(., "
              ") diff --git a/code/game/objects/items/devices/spy_bug.dm b/code/game/objects/items/devices/spy_bug.dm index 9f6c8d5002f2..518b43c3d377 100644 --- a/code/game/objects/items/devices/spy_bug.dm +++ b/code/game/objects/items/devices/spy_bug.dm @@ -5,47 +5,45 @@ icon_state = "eshield0" item_state = "nothing" layer = BELOW_TABLE_LAYER - obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - throwforce = 5.0 throw_range = 15 throw_speed = 3 - - origin_tech = "{'programming':1,'engineering':1,'esoteric':3}" - + origin_tech = @'{"programming":1,"engineering":1,"esoteric":3}' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + ) var/obj/item/radio/spy/radio - var/obj/machinery/camera/spy/camera /obj/item/spy_bug/Initialize() . = ..() + name = "bug #[random_id(/obj/item/spy_bug, 1000,9999)]" radio = new(src) - camera = new(src) - GLOB.listening_objects += src + global.listening_objects += src /obj/item/spy_bug/Destroy() QDEL_NULL(radio) - QDEL_NULL(camera) - GLOB.listening_objects -= src return ..() -/obj/item/spy_bug/examine(mob/user, distance) +/obj/item/spy_bug/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 0) - to_chat(user, "It's a tiny camera, microphone, and transmission device in a happy union.") - to_chat(user, "Needs to be both configured and brought in contact with monitor device to be fully functional.") + . += "It's a tiny camera, microphone, and transmission device in a happy union." + . += "Needs to be both configured and brought in contact with monitor device to be fully functional." /obj/item/spy_bug/attack_self(mob/user) radio.attack_self(user) -/obj/item/spy_bug/attackby(obj/W, mob/living/user) - if(istype(W, /obj/item/spy_monitor)) - var/obj/item/spy_monitor/SM = W +/obj/item/spy_bug/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/spy_monitor)) + var/obj/item/spy_monitor/SM = used_item SM.pair(src, user) - else - ..() + return TRUE + return ..() /obj/item/spy_bug/hear_talk(mob/M, var/msg, verb, decl/language/speaking) radio.hear_talk(M, msg, speaking) @@ -57,111 +55,97 @@ icon = 'icons/obj/modular_computers/pda/pda.dmi' icon_state = ICON_STATE_WORLD color = COLOR_GRAY80 - w_class = ITEM_SIZE_SMALL + origin_tech = @'{"programming":1,"engineering":1,"esoteric":3}' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + ) - origin_tech = "{'programming':1,'engineering':1,'esoteric':3}" - - var/operating = 0 var/obj/item/radio/spy/radio - var/obj/machinery/camera/spy/selected_camera - var/list/obj/machinery/camera/spy/cameras = new() + var/obj/item/spy_bug/selected_camera + var/list/obj/item/spy_bug/cameras = list() /obj/item/spy_monitor/Initialize() . = ..() radio = new(src) - GLOB.listening_objects += src + global.listening_objects += src /obj/item/spy_monitor/Destroy() - GLOB.listening_objects -= src + selected_camera = null + cameras.Cut() return ..() -/obj/item/spy_monitor/examine(mob/user, distance) +/obj/item/spy_monitor/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "The time '12:00' is blinking in the corner of the screen and \the [src] looks very cheaply made.") + . += "The time '12:00' is blinking in the corner of the screen and \the [src] looks very cheaply made." /obj/item/spy_monitor/attack_self(mob/user) - if(operating) - return - radio.attack_self(user) view_cameras(user) -/obj/item/spy_monitor/attackby(obj/W, mob/living/user) - if(istype(W, /obj/item/spy_bug)) - pair(W, user) - else - return ..() +/obj/item/spy_monitor/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/spy_bug)) + pair(used_item, user) + return TRUE + return ..() /obj/item/spy_monitor/proc/pair(var/obj/item/spy_bug/SB, var/mob/living/user) - if(SB.camera in cameras) - to_chat(user, "\The [SB] has been unpaired from \the [src].") - cameras -= SB.camera - else - to_chat(user, "\The [SB] has been paired with \the [src].") - cameras += SB.camera + to_chat(user, SPAN_NOTICE("\The [SB] has been paired with \the [src].")) + events_repository.register(/decl/observ/destroyed, SB, src, PROC_REF(unpair)) + cameras += SB + +/obj/item/spy_monitor/proc/unpair(var/obj/item/spy_bug/SB, var/mob/living/user) + to_chat(user, SPAN_NOTICE("\The [SB] has been unpaired from \the [src].")) + events_repository.unregister(/decl/observ/destroyed, SB, src, PROC_REF(unpair)) + if(selected_camera == SB) + selected_camera = null + cameras -= SB /obj/item/spy_monitor/proc/view_cameras(mob/user) - if(!can_use_cam(user)) + if(!cameras.len) + to_chat(user, SPAN_WARNING("No paired cameras detected!")) + to_chat(user, SPAN_WARNING("Bring a bug in contact with this device to pair the camera.")) return - selected_camera = cameras[1] - view_camera(user) - - operating = 1 - while(selected_camera && Adjacent(user)) - selected_camera = input("Select camera bug to view.") as null|anything in cameras - selected_camera = null - operating = 0 - -/obj/item/spy_monitor/proc/view_camera(mob/user) - spawn(0) - while(selected_camera && Adjacent(user)) - var/turf/T = get_turf(selected_camera) - if(!T || !is_on_same_plane_or_station(T.z, user.z) || !selected_camera.can_use()) - user.unset_machine() - user.reset_view(null) - to_chat(user, "[selected_camera] unavailable.") - sleep(90) - else - user.set_machine(selected_camera) - user.reset_view(selected_camera) - sleep(10) + if(selected_camera) + selected_camera = null + user.reset_view() user.unset_machine() - user.reset_view(null) - -/obj/item/spy_monitor/proc/can_use_cam(mob/user) - if(operating) return - if(!cameras.len) - to_chat(user, "No paired cameras detected!") - to_chat(user, "Bring a bug in contact with this device to pair the camera.") - return + selected_camera = input("Select camera bug to view.") as null|anything in cameras + view_camera(user) - return 1 +/obj/item/spy_monitor/proc/view_camera(mob/user) + user.machine = src + user.reset_view(selected_camera) + +/obj/item/spy_monitor/check_eye(mob/user) + if(!selected_camera || QDELETED(selected_camera)) + user.unset_machine() + return -1 + if(!CanUseTopicPhysical(user)) + user.unset_machine() + return -1 + var/turf/T = get_turf(selected_camera) + if(!T || !is_on_same_plane_or_station(T.z, user.z)) + user.unset_machine() + selected_camera = null + return -1 + return 0 /obj/item/spy_monitor/hear_talk(mob/M, var/msg, verb, decl/language/speaking) return radio.hear_talk(M, msg, speaking) - -/obj/machinery/camera/spy - // These cheap toys are accessible from the mercenary camera console as well - network = list(NETWORK_MERCENARY) - -/obj/machinery/camera/spy/Initialize() - . = ..() - name = "DV-136ZB #[random_id(/obj/machinery/camera/spy, 1000,9999)]" - c_tag = name - -/obj/machinery/camera/spy/check_eye(var/mob/user) - return 0 - /obj/item/radio/spy listening = 0 frequency = 1473 broadcasting = 0 canhear_range = 1 name = "spy device" - icon_state = "syn_cypherkey" + icon = 'icons/obj/items/device/radio/spybug.dmi' + icon_state = ICON_STATE_WORLD diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm index 386d29a7ceaf..a8cbf50f10b3 100644 --- a/code/game/objects/items/devices/suit_cooling.dm +++ b/code/game/objects/items/devices/suit_cooling.dm @@ -3,21 +3,18 @@ desc = "A large portable heat sink with liquid cooled radiator packaged into a modified backpack." w_class = ITEM_SIZE_LARGE icon = 'icons/obj/items/suitcooler.dmi' - icon_state = "suitcooler0" - item_state = "coolingpack" // beautiful codersprites until someone makes a prettier one. + icon_state = ICON_STATE_WORLD slot_flags = SLOT_BACK //copied from tank.dm obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 - throwforce = 10.0 throw_speed = 1 throw_range = 4 action_button_name = "Toggle Heatsink" material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - origin_tech = "{'magnets':2,'materials':2}" + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"magnets":2,"materials":2}' var/on = 0 //is it turned on? var/cover_open = 0 //is the cover open? @@ -46,7 +43,7 @@ if (!is_in_slot()) return - var/mob/living/carbon/human/H = loc + var/mob/living/human/H = loc var/temp_adj = min(H.bodytemperature - thermostat, max_cooling) @@ -66,11 +63,10 @@ // Checks whether the cooling unit is being worn on the back/suit slot. // That way you can't carry it in your hands while it's running to cool yourself down. /obj/item/suit_cooling_unit/proc/is_in_slot() - var/mob/living/carbon/human/H = loc + var/mob/living/human/H = loc if(!istype(H)) return 0 - - return (H.back == src) || (H.s_store == src) + return H.get_equipped_item(slot_back_str) == src || H.get_equipped_item(slot_s_store_str) == src /obj/item/suit_cooling_unit/proc/turn_on() if(!cell) @@ -110,8 +106,8 @@ turn_on() to_chat(user, "You switch \the [src] [on ? "on" : "off"].") -/obj/item/suit_cooling_unit/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) +/obj/item/suit_cooling_unit/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) if(cover_open) cover_open = 0 to_chat(user, "You screw the panel into place.") @@ -119,63 +115,56 @@ cover_open = 1 to_chat(user, "You unscrew the panel.") update_icon() - return + return TRUE - if (istype(W, /obj/item/cell)) + if (istype(used_item, /obj/item/cell)) if(cover_open) if(cell) to_chat(user, "There is a [cell] already installed here.") else - if(!user.unEquip(W, src)) - return - cell = W - to_chat(user, "You insert the [cell].") + if(!user.try_unequip(used_item, src)) + return TRUE + cell = used_item + to_chat(user, "You insert \the [cell].") update_icon() - return + return TRUE return ..() /obj/item/suit_cooling_unit/on_update_icon() - overlays.Cut() - if (cover_open) - if (cell) - icon_state = "suitcooler1" - else - icon_state = "suitcooler2" + . = ..() + if(cover_open) + add_overlay("[icon_state]-open") + if(cell) + add_overlay("[icon_state]-cell") return - icon_state = "suitcooler0" - if(!cell || !on) return switch(round(cell.percent())) if(86 to INFINITY) - overlays.Add("battery-0") + add_overlay("[icon_state]-battery-0") if(69 to 85) - overlays.Add("battery-1") + add_overlay("[icon_state]-battery-1") if(52 to 68) - overlays.Add("battery-2") + add_overlay("[icon_state]-battery-2") if(35 to 51) - overlays.Add("battery-3") + add_overlay("[icon_state]-battery-3") if(18 to 34) - overlays.Add("battery-4") + add_overlay("[icon_state]-battery-4") if(-INFINITY to 17) - overlays.Add("battery-5") - + add_overlay("[icon_state]-battery-5") -/obj/item/suit_cooling_unit/examine(mob/user, distance) +/obj/item/suit_cooling_unit/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance >= 1) + if(distance > 1) return - if (on) - to_chat(user, "It's switched on and running.") + . += "It's switched on and running." else - to_chat(user, "It is switched off.") - + . += "It is switched off." if (cover_open) - to_chat(user, "The panel is open.") - + . += "The panel is open." if (cell) - to_chat(user, "The charge meter reads [round(cell.percent())]%.") + . += "The charge meter reads [round(cell.percent())]%." diff --git a/code/game/objects/items/devices/suit_sensor_jammer.dm b/code/game/objects/items/devices/suit_sensor_jammer.dm index 3e221aec8233..af12560327a1 100644 --- a/code/game/objects/items/devices/suit_sensor_jammer.dm +++ b/code/game/objects/items/devices/suit_sensor_jammer.dm @@ -7,21 +7,26 @@ icon = 'icons/obj/items/device/jammer.dmi' icon_state = "jammer" w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/plutonium = MATTER_AMOUNT_TRACE, + ) var/active = FALSE var/range = 2 // This is a radius, thus a range of 7 covers the entire visible screen - var/obj/item/cell/bcell = /obj/item/cell/high var/suit_sensor_jammer_method/jammer_method var/list/suit_sensor_jammer_methods_by_type var/list/suit_sensor_jammer_methods /obj/item/suit_sensor_jammer/Initialize() . = ..() - if(ispath(bcell)) - bcell = new bcell(src) + set_extension(src, /datum/extension/loaded_cell/unremovable, /obj/item/cell, /obj/item/cell/high) suit_sensor_jammer_methods = list() suit_sensor_jammer_methods_by_type = list() for(var/jammer_method_type in subtypesof(/suit_sensor_jammer_method)) - var/new_method = new jammer_method_type(src, /obj/item/suit_sensor_jammer/proc/may_process_crew_data) + var/new_method = new jammer_method_type(src, TYPE_PROC_REF(/obj/item/suit_sensor_jammer, may_process_crew_data)) dd_insertObjectList(suit_sensor_jammer_methods, new_method) suit_sensor_jammer_methods_by_type[jammer_method_type] = new_method jammer_method = suit_sensor_jammer_methods[1] @@ -29,8 +34,6 @@ /obj/item/suit_sensor_jammer/Destroy() . = ..() - qdel(bcell) - bcell = null jammer_method = null for(var/method in suit_sensor_jammer_methods) qdel(method) @@ -41,93 +44,69 @@ /obj/item/suit_sensor_jammer/attack_self(var/mob/user) ui_interact(user) -/obj/item/suit_sensor_jammer/get_cell() - return bcell - -/obj/item/suit_sensor_jammer/attackby(obj/item/I, mob/user) - if(isCrowbar(I)) - if(bcell) - to_chat(user, "You remove \the [bcell].") - disable() - bcell.dropInto(loc) - bcell = null - else - to_chat(user, "There is no cell to remove.") - else if(istype(I, /obj/item/cell)) - if(bcell) - to_chat(user, "There's already a cell in \the [src].") - else if(user.unEquip(I)) - I.forceMove(src) - bcell = I - to_chat(user, "You insert \the [bcell] into \the [src]..") - else - to_chat(user, "You're unable to insert the battery.") - /obj/item/suit_sensor_jammer/on_update_icon() - overlays.Cut() - if(bcell) - var/percent = bcell.percent() - switch(percent) - if(0 to 25) - overlays += "forth_quarter" - if(25 to 50) - overlays += "one_quarter" - overlays += "third_quarter" - if(50 to 75) - overlays += "two_quarters" - overlays += "second_quarter" - if(75 to 99) - overlays += "three_quarters" - overlays += "first_quarter" - else - overlays += "four_quarters" - - if(active) - overlays += "active" + . = ..() + var/obj/item/cell/cell = get_cell() + if(!cell) + return + var/percent = cell.percent() + switch(percent) + if(0 to 25) + add_overlay("forth_quarter") + if(25 to 50) + add_overlay("one_quarter") + add_overlay("third_quarter") + if(50 to 75) + add_overlay("two_quarters") + add_overlay("second_quarter") + if(75 to 99) + add_overlay("three_quarters") + add_overlay("first_quarter") + else + add_overlay("four_quarters") + if(active) + add_overlay("active") /obj/item/suit_sensor_jammer/emp_act(var/severity) ..() - if(bcell) - bcell.emp_act(severity) - if(prob(70/severity)) enable() else disable() - if(prob(90/severity)) set_method(suit_sensor_jammer_methods_by_type[/suit_sensor_jammer_method/random]) else set_method(pick(suit_sensor_jammer_methods)) - var/new_range = range + (rand(0,6) / severity) - (rand(0,3) / severity) set_range(new_range) -obj/item/suit_sensor_jammer/examine(mob/user, distance) +/obj/item/suit_sensor_jammer/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 3) - var/list/message = list() - message += "This device appears to be [active ? "" : "in"]active and " - if(bcell) - message += "displays a charge level of [bcell.percent()]%." + var/message = "This device appears to be [active ? "" : "in"]active and " + var/obj/item/cell/cell = get_cell() + if(cell) + message += "displays a charge level of [cell.percent()]%." else message += "is lacking a cell." - to_chat(user, jointext(message,.)) + . += message -obj/item/suit_sensor_jammer/CanUseTopic(user, state) - if(!bcell || bcell.charge <= 0) +/obj/item/suit_sensor_jammer/CanUseTopic(user, state) + var/obj/item/cell/cell = get_cell() + if(!cell || cell.charge <= 0) return STATUS_CLOSE return ..() -obj/item/suit_sensor_jammer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/item/suit_sensor_jammer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/list/methods = new for(var/suit_sensor_jammer_method/ssjm in suit_sensor_jammer_methods) methods[++methods.len] = list("name" = ssjm.name, "cost" = ssjm.energy_cost, "ref" = "\ref[ssjm]") + var/obj/item/cell/cell = get_cell() var/list/data = list( "active" = active, - "current_charge" = bcell ? round(bcell.charge, 1) : 0, - "max_charge" = bcell ? bcell.maxcharge : 0, + "current_charge" = cell ? round(cell.charge, 1) : 0, + "max_charge" = cell ? cell.maxcharge : 0, "range" = range, "max_range" = JAMMER_MAX_RANGE, "methods" = methods, @@ -143,7 +122,7 @@ obj/item/suit_sensor_jammer/ui_interact(mob/user, ui_key = "main", var/datum/nan ui.open() ui.set_auto_update(1) -obj/item/suit_sensor_jammer/OnTopic(var/mob/user, var/list/href_list, state) +/obj/item/suit_sensor_jammer/OnTopic(var/mob/user, var/list/href_list, state) if (href_list["enable_jammer"]) enable() return TOPIC_REFRESH @@ -164,12 +143,13 @@ obj/item/suit_sensor_jammer/OnTopic(var/mob/user, var/list/href_list, state) set_method(method) return TOPIC_REFRESH -/obj/item/suit_sensor_jammer/Process(var/wait) - if(bcell) +/obj/item/suit_sensor_jammer/Process(wait, tick) + var/obj/item/cell/cell = get_cell() + if(cell) // With a range of 2 and jammer cost of 3 the default (high capacity) cell will last for almost 14 minutes, give or take // 10000 / (2^2 * 3 / 10) ~= 8333 ticks ~= 13.8 minutes var/deduction = JAMMER_POWER_CONSUMPTION(wait) - if(!bcell.use(deduction)) + if(!cell.use(deduction)) disable() else disable() @@ -194,7 +174,7 @@ obj/item/suit_sensor_jammer/OnTopic(var/mob/user, var/list/href_list, state) return TRUE /obj/item/suit_sensor_jammer/proc/set_range(var/new_range) - range = Clamp(new_range, 0, JAMMER_MAX_RANGE) // 0 range still covers the current turf + range = clamp(new_range, 0, JAMMER_MAX_RANGE) // 0 range still covers the current turf return range != new_range /obj/item/suit_sensor_jammer/proc/set_method(var/suit_sensor_jammer_method/sjm) @@ -205,7 +185,7 @@ obj/item/suit_sensor_jammer/OnTopic(var/mob/user, var/list/href_list, state) sjm.enable() jammer_method = sjm -/obj/item/suit_sensor_jammer/proc/may_process_crew_data(var/mob/living/carbon/human/H, var/obj/item/clothing/under/C, var/turf/pos) +/obj/item/suit_sensor_jammer/proc/may_process_crew_data(var/mob/living/human/H, var/obj/item/clothing/sensor/vitals/S, var/turf/pos) if(!pos) return FALSE var/turf/T = get_turf(src) diff --git a/code/game/objects/items/devices/t_scanner.dm b/code/game/objects/items/devices/t_scanner.dm index e120f3c094ca..1f8b7aff8376 100644 --- a/code/game/objects/items/devices/t_scanner.dm +++ b/code/game/objects/items/devices/t_scanner.dm @@ -4,12 +4,11 @@ name = "\improper T-ray scanner" desc = "A terahertz-ray emitter and scanner, capable of penetrating conventional hull materials." icon = 'icons/obj/items/device/t_ray_scanner.dmi' - icon_state = "t-ray0" - slot_flags = SLOT_BELT + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL - item_state = "electronic" material = /decl/material/solid/metal/aluminium - origin_tech = "{'magnets':1,'engineering':1}" + origin_tech = @'{"magnets":1,"engineering":1}' action_button_name = "Toggle T-Ray scanner" var/scan_range = 3 @@ -18,7 +17,7 @@ var/list/active_scanned = list() //assoc list of objects being scanned, mapped to their overlay var/client/user_client //since making sure overlays are properly added and removed is pretty important, so we track the current user explicitly - var/global/list/overlay_cache = list() //cache recent overlays + var/static/list/overlay_cache = list() //cache recent overlays /obj/item/t_scanner/Destroy() . = ..() @@ -26,7 +25,8 @@ set_active(FALSE) /obj/item/t_scanner/on_update_icon() - icon_state = "t-ray[on]" + . = ..() + add_overlay("[icon_state]-[on? "on" : "off"]") /obj/item/t_scanner/emp_act() audible_message(src, " \The [src] buzzes oddly.") @@ -39,7 +39,7 @@ /obj/item/t_scanner/afterattack(atom/target, mob/user, proximity_flag, click_parameters) var/obj/structure/disposalpipe/D = target if(D && istype(D)) - to_chat(user, "Pipe segment integrity: [(D.health / 10) * 100]%") + to_chat(user, "Pipe segment integrity: [(D.current_health / 10) * 100]%") /obj/item/t_scanner/proc/set_active(var/active) on = active @@ -70,15 +70,15 @@ var/list/update_remove = active_scanned - scanned //Add new overlays - for(var/obj/O in update_add) - var/image/overlay = get_overlay(O) - active_scanned[O] = overlay + for(var/to_show in update_add) + var/image/overlay = get_overlay(to_show) + active_scanned[to_show] = overlay user_client.images += overlay //Remove stale overlays - for(var/obj/O in update_remove) - user_client.images -= active_scanned[O] - active_scanned -= O + for(var/to_remove in update_remove) + user_client.images -= active_scanned[to_remove] + active_scanned -= to_remove //creates a new overlay for a scanned object /obj/item/t_scanner/proc/get_overlay(var/atom/movable/scanned) @@ -101,9 +101,9 @@ if(ismob(scanned)) if(ishuman(scanned)) - var/mob/living/carbon/human/H = scanned - if(H.species.appearance_flags & HAS_SKIN_COLOR) - I.color = H.skin_colour + var/mob/living/human/H = scanned + if(H.get_bodytype()?.appearance_flags & HAS_SKIN_COLOR) + I.color = H.get_skin_colour() I.icon = 'icons/mob/mob.dmi' I.icon_state = "phaseout" var/mob/M = scanned @@ -112,7 +112,7 @@ I.underlays += M.underlays I.alpha = 128 - I.mouse_opacity = 0 + I.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE . = I // Add it to cache, cutting old entries if the list is too long @@ -120,6 +120,15 @@ if(overlay_cache.len > OVERLAY_CACHE_LEN) overlay_cache.Cut(1, overlay_cache.len-OVERLAY_CACHE_LEN-1) +/obj/item/t_scanner/proc/can_scan_mob(mob/victim) + if(isobserver(victim)) + return FALSE + if(victim.is_cloaked()) + return TRUE + if(victim.alpha < 255) + return TRUE + return FALSE + /obj/item/t_scanner/proc/get_scanned_objects(var/scan_dist) . = list() @@ -128,20 +137,14 @@ for(var/turf/T in range(scan_range, center)) for(var/mob/M in T.contents) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.is_cloaked()) - . += M - else if(M.alpha < 255) - . += M - else if(round_is_spooky() && isobserver(M)) + if(can_scan_mob(M)) . += M if(!!T.is_plating()) continue for(var/obj/O in T.contents) - if(O.level != 1) + if(O.level != LEVEL_BELOW_PLATING) continue if(!O.invisibility) continue //if it's already visible don't need an overlay for it diff --git a/code/game/objects/items/devices/tape_recorder/magnetic_tape.dm b/code/game/objects/items/devices/tape_recorder/magnetic_tape.dm new file mode 100644 index 000000000000..26d5cdf79b36 --- /dev/null +++ b/code/game/objects/items/devices/tape_recorder/magnetic_tape.dm @@ -0,0 +1,176 @@ +/obj/item/magnetic_tape + name = "tape" + desc = "A magnetic tape that can hold up to ten minutes of content." + icon = 'icons/obj/items/device/tape_recorder/tape_casette_white.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE + ) + _base_attack_force = 1 + var/max_capacity = 600 + var/used_capacity = 0 + var/list/storedinfo = new/list() + var/list/timestamp = new/list() + var/ruined = FALSE + var/doctored = FALSE + /// Whether we draw the ruined ribbon overlay when ruined. + var/draw_ribbon_if_ruined = TRUE + +/obj/item/magnetic_tape/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(draw_ribbon_if_ruined && ruined && max_capacity) + add_overlay(overlay_image(icon, "[icon_state]_ribbonoverlay", flags = RESET_COLOR)) + +/obj/item/magnetic_tape/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ruin() + return ..() + +/obj/item/magnetic_tape/attack_self(mob/user) + if(!ruined) + to_chat(user, SPAN_NOTICE("You pull out all the tape!")) + get_loose_tape(user, length(storedinfo)) + ruin() + + +/obj/item/magnetic_tape/proc/ruin() + ruined = TRUE + update_icon() + + +/obj/item/magnetic_tape/proc/fix() + ruined = FALSE + update_icon() + + +/obj/item/magnetic_tape/proc/record_speech(text) + timestamp += used_capacity + storedinfo += "\[[time2text(used_capacity SECONDS,"mm:ss")]\] [text]" + + +//shows up on the printed transcript as (Unrecognized sound) +/obj/item/magnetic_tape/proc/record_noise(text) + timestamp += used_capacity + storedinfo += "*\[[time2text(used_capacity SECONDS,"mm:ss")]\] [text]" + + +/obj/item/magnetic_tape/attackby(obj/item/used_item, mob/user, params) + if(user.incapacitated()) // TODO: this may not be necessary since OnClick checks before starting the attack chain + return TRUE + if(ruined && IS_SCREWDRIVER(used_item)) + if(!max_capacity) + to_chat(user, SPAN_NOTICE("There is no tape left inside.")) + return TRUE + to_chat(user, SPAN_NOTICE("You start winding the tape back in...")) + if(do_after(user, 12 SECONDS, target = src)) + to_chat(user, SPAN_NOTICE("You wound the tape back in.")) + fix() + return TRUE + else if(IS_PEN(used_item)) + if(loc == user) + var/new_name = input(user, "What would you like to label the tape?", "Tape labeling") as null|text + if(isnull(new_name)) return TRUE + new_name = sanitize_safe(new_name) + if(new_name) + SetName("tape - '[new_name]'") + to_chat(user, SPAN_NOTICE("You label the tape '[new_name]'.")) + else + SetName("tape") + to_chat(user, SPAN_NOTICE("You scratch off the label.")) + return TRUE + else if(IS_WIRECUTTER(used_item)) + cut(user) + return TRUE + else if(istype(used_item, /obj/item/magnetic_tape/loose)) + join(user, used_item) + return TRUE + return ..() + +/obj/item/magnetic_tape/proc/cut(mob/user) + if(!LAZYLEN(timestamp)) + to_chat(user, SPAN_NOTICE("There's nothing on this tape!")) + return + var/list/output = list("
              ") + for(var/i in 1 to length(timestamp)) + var/time = "\[[time2text(timestamp[i] SECONDS,"mm:ss")]\]" + output += "[time]
              -----CUT------
              " + output += "
              " + + var/datum/browser/popup = new(user, "tape_cutting", "Cutting tape", 170, 600) + popup.set_content(jointext(output,null)) + popup.open() + +/obj/item/magnetic_tape/proc/join(mob/user, obj/item/magnetic_tape/other) + if(max_capacity + other.max_capacity > initial(max_capacity)) + to_chat(user, SPAN_NOTICE("You can't fit this much tape in!")) + return + if(user.try_unequip(other)) + to_chat(user, SPAN_NOTICE("You join ends of the tape together.")) + max_capacity += other.max_capacity + used_capacity = min(used_capacity + other.used_capacity, max_capacity) + timestamp += other.timestamp + storedinfo += other.storedinfo + doctored = TRUE + ruin() + update_icon() + qdel(other) + +/obj/item/magnetic_tape/OnTopic(var/mob/user, var/list/href_list) + if(href_list["cut_after"]) + var/index = text2num(href_list["cut_after"]) + if(index >= length(timestamp)) + return + + to_chat(user, SPAN_NOTICE("You remove part of the tape.")) + get_loose_tape(user, index) + cut(user) + return TOPIC_REFRESH + +//Spawns new loose tape item, with data starting from [index] entry +/obj/item/magnetic_tape/proc/get_loose_tape(var/mob/user, var/index) + var/obj/item/magnetic_tape/loose/newtape = new() + newtape.timestamp = timestamp.Copy(index+1) + newtape.storedinfo = storedinfo.Copy(index+1) + newtape.max_capacity = max_capacity - index + newtape.used_capacity = max(0, used_capacity - max_capacity) + newtape.doctored = doctored + user.put_in_hands(newtape) + + timestamp.Cut(index+1) + storedinfo.Cut(index+1) + max_capacity = index + used_capacity = min(used_capacity,index) + +//Random colour tapes +/obj/item/magnetic_tape/random/Initialize() + icon = pick(list( + 'icons/obj/items/device/tape_recorder/tape_casette_white.dmi', + 'icons/obj/items/device/tape_recorder/tape_casette_blue.dmi', + 'icons/obj/items/device/tape_recorder/tape_casette_red.dmi', + 'icons/obj/items/device/tape_recorder/tape_casette_yellow.dmi', + 'icons/obj/items/device/tape_recorder/tape_casette_purple.dmi' + )) + . = ..() + +/obj/item/magnetic_tape/loose + name = "magnetic tape" + desc = "Quantum-enriched self-repairing nanotape, used for magnetic storage of information." + icon = 'icons/obj/items/device/tape_recorder/tape_casette_loose.dmi' + ruined = TRUE + draw_ribbon_if_ruined = FALSE + +/obj/item/magnetic_tape/loose/fix() + return + +/obj/item/magnetic_tape/loose/get_loose_tape() + return + +/obj/item/magnetic_tape/loose/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + . += SPAN_NOTICE("It looks long enough to hold [max_capacity] seconds worth of recording.") + if(doctored && user.skill_check(SKILL_FORENSICS, SKILL_PROF)) + . += SPAN_WARNING("It has been tampered with...") diff --git a/code/game/objects/items/devices/tape_recorder/tape_recorder.dm b/code/game/objects/items/devices/tape_recorder/tape_recorder.dm new file mode 100644 index 000000000000..7677f30a1dc0 --- /dev/null +++ b/code/game/objects/items/devices/tape_recorder/tape_recorder.dm @@ -0,0 +1,360 @@ +/obj/item/taperecorder + name = "universal recorder" + desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback." + icon = 'icons/obj/items/device/tape_recorder/tape_recorder.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + throw_speed = 4 + throw_range = 20 + + var/emagged = FALSE + var/recording = FALSE + var/playing = FALSE + var/playsleepseconds = 0 + var/obj/item/magnetic_tape/mytape = /obj/item/magnetic_tape/random + var/const/TRANSCRIPT_PRINT_COOLDOWN = 5 MINUTES + /// (FLOAT) The minimum world.time before a transcript can be printed again. + var/next_print_time = 0 + var/datum/wires/taperecorder/wires = null // Wires datum + /// (BOOL) If TRUE, wire datum is accessible for interactions. + var/wires_accessible = FALSE + +/obj/item/taperecorder/Initialize() + . = ..() + wires = new(src) + if(ispath(mytape)) + mytape = new mytape(src) + global.listening_objects += src + update_icon() + +/obj/item/taperecorder/empty + mytape = null + +/obj/item/taperecorder/Destroy() + QDEL_NULL(wires) + QDEL_NULL(mytape) + return ..() + +/obj/item/taperecorder/attackby(obj/item/used_item, mob/user, params) + if(IS_SCREWDRIVER(used_item)) + wires_accessible = !wires_accessible + to_chat(user, SPAN_NOTICE("You [wires_accessible ? "open" : "secure"] the lid.")) + return TRUE + if(istype(used_item, /obj/item/magnetic_tape)) + if(mytape) + to_chat(user, SPAN_NOTICE("There's already a tape inside.")) + return TRUE + if(!user.try_unequip(used_item)) + return TRUE + used_item.forceMove(src) + mytape = used_item + to_chat(user, SPAN_NOTICE("You insert [used_item] into [src].")) + update_icon() + return TRUE + return ..() + + +/obj/item/taperecorder/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(mytape) + mytape.ruin() //Fires destroy the tape + return ..() + + +/obj/item/taperecorder/attack_hand(mob/user) + if(user.is_holding_offhand(src) && mytape && user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) + eject() + return TRUE + return ..() + + +/obj/item/taperecorder/verb/eject() + set name = "Eject Tape" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + to_chat(usr, SPAN_NOTICE("There's no tape in \the [src].")) + return + if(emagged) + to_chat(usr, SPAN_NOTICE("The tape seems to be stuck inside.")) + return + + if(playing || recording) + stop() + to_chat(usr, SPAN_NOTICE("You remove [mytape] from [src].")) + usr.put_in_hands(mytape) + mytape = null + update_icon() + +/obj/item/taperecorder/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1 && wires_accessible) + . += SPAN_NOTICE("The wires are exposed.") + +/obj/item/taperecorder/hear_talk(mob/living/M, msg, var/verb="says", decl/language/speaking=null) + if(mytape && recording) + + if(speaking) + if(!speaking.machine_understands) + msg = speaking.scramble(M, msg) + mytape.record_speech("[M.name] [speaking.format_message_plain(msg, verb)]") + else + mytape.record_speech("[M.name] [verb], \"[msg]\"") + +/obj/item/taperecorder/show_message(msg, type, alt, alt_type) + var/recordedtext + if (msg && type == AUDIBLE_MESSAGE) //must be hearable + recordedtext = msg + else if (alt && alt_type == AUDIBLE_MESSAGE) + recordedtext = alt + else + return + if(mytape && recording) + mytape.record_noise("[strip_html_properly(recordedtext)]") + +/obj/item/taperecorder/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = TRUE + recording = FALSE + to_chat(user, SPAN_WARNING("PZZTTPFFFT")) + update_icon() + return 1 + else + to_chat(user, SPAN_WARNING("It is already emagged!")) + +/obj/item/taperecorder/proc/explode() + var/turf/T = get_turf(loc) + if(ismob(loc)) + var/mob/M = loc + to_chat(M, SPAN_DANGER("\The [src] explodes!")) + if(T) + T.hotspot_expose(700,125) + explosion(T, -1, -1, 0, 4) + qdel(src) + return + +/obj/item/taperecorder/verb/record() + set name = "Start Recording" + set category = "Object" + + if(usr.incapacitated()) + return + playsound(src, 'sound/machines/click.ogg', 10, 1) + if(!mytape) + to_chat(usr, SPAN_NOTICE("There's no tape!")) + return + if(mytape.ruined || emagged) + audible_message(SPAN_WARNING("The tape recorder makes a scratchy noise.")) + return + if(recording) + to_chat(usr, SPAN_NOTICE("You're already recording!")) + return + if(playing) + to_chat(usr, SPAN_NOTICE("You can't record when playing!")) + return + if(mytape.used_capacity < mytape.max_capacity) + to_chat(usr, SPAN_NOTICE("Recording started.")) + recording = TRUE + update_icon() + + mytape.record_speech("Recording started.") + + //count seconds until full, or recording is stopped + while(mytape && recording && mytape.used_capacity < mytape.max_capacity) + sleep(1 SECOND) + mytape.used_capacity++ + if(mytape.used_capacity >= mytape.max_capacity) + to_chat(usr, SPAN_NOTICE("The tape is full.")) + stop_recording() + + + update_icon() + return + else + to_chat(usr, SPAN_NOTICE("The tape is full.")) + + +/obj/item/taperecorder/proc/stop_recording() + //Sanity checks skipped, should not be called unless actually recording + recording = FALSE + update_icon() + mytape.record_speech("Recording stopped.") + if(ismob(loc)) + var/mob/M = loc + to_chat(M, SPAN_NOTICE("Recording stopped.")) + + +/obj/item/taperecorder/verb/stop() + set name = "Stop" + set category = "Object" + + if(usr.incapacitated()) + return + playsound(src, 'sound/machines/click.ogg', 10, 1) + if(recording) + stop_recording() + return + else if(playing) + playing = FALSE + update_icon() + to_chat(usr, SPAN_NOTICE("Playback stopped.")) + return + else + to_chat(usr, SPAN_NOTICE("Stop what?")) + + +/obj/item/taperecorder/verb/wipe_tape() + set name = "Wipe Tape" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + return + if(emagged || mytape.ruined) + audible_message(SPAN_WARNING("The tape recorder makes a scratchy noise.")) + return + if(recording || playing) + to_chat(usr, SPAN_NOTICE("You can't wipe the tape while playing or recording!")) + return + else + if(mytape.storedinfo) mytape.storedinfo.Cut() + if(mytape.timestamp) mytape.timestamp.Cut() + mytape.used_capacity = 0 + to_chat(usr, SPAN_NOTICE("You wipe the tape.")) + return + + +/obj/item/taperecorder/verb/playback_memory() + set name = "Playback Tape" + set category = "Object" + + if(usr.incapacitated()) + return + play(usr) + +/obj/item/taperecorder/proc/play(mob/user) + if(!mytape) + to_chat(user, SPAN_NOTICE("There's no tape!")) + return + if(mytape.ruined) + audible_message(SPAN_WARNING("The tape recorder makes a scratchy noise.")) + return + if(recording) + to_chat(user, SPAN_NOTICE("You can't playback when recording!")) + return + if(playing) + to_chat(user, SPAN_NOTICE("\The [src] is already playing its recording!")) + return + playing = TRUE + update_icon() + to_chat(user, SPAN_NOTICE("Audio playback started.")) + playsound(src, 'sound/machines/click.ogg', 10, 1) + for(var/i=1 , i < mytape.max_capacity , i++) + if(!mytape || !playing) + break + if(length(mytape.storedinfo) < i) + break + + var/turf/T = get_turf(src) + var/playedmessage = mytape.storedinfo[i] + if (findtextEx(playedmessage,"*",1,2)) //remove marker for action sounds + playedmessage = copytext(playedmessage,2) + T.audible_message(SPAN_MAROON("Tape Recorder: [playedmessage]")) + + if(length(mytape.storedinfo) < i+1) + playsleepseconds = 1 + sleep(10) + T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: End of recording.")) + playsound(src, 'sound/machines/click.ogg', 10, 1) + break + else + playsleepseconds = mytape.timestamp[i+1] - mytape.timestamp[i] + + if(playsleepseconds > 14) + sleep(10) + T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: Skipping [playsleepseconds] seconds of silence")) + playsleepseconds = 1 + sleep(playsleepseconds SECONDS) + + + playing = FALSE + update_icon() + + if(emagged) + var/turf/T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: This tape recorder will self-destruct in... Five.")) + sleep(10) + T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: Four.")) + sleep(10) + T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: Three.")) + sleep(10) + T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: Two.")) + sleep(10) + T = get_turf(src) + T.audible_message(SPAN_MAROON("Tape Recorder: One.")) + sleep(10) + explode() + + +/obj/item/taperecorder/verb/print_transcript() + set name = "Print Transcript" + set category = "Object" + + if(usr.incapacitated()) + return + if(!mytape) + to_chat(usr, SPAN_NOTICE("There's no tape!")) + return + if(mytape.ruined || emagged) + audible_message(SPAN_WARNING("The tape recorder makes a scratchy noise.")) + return + if(next_print_time < world.time) + to_chat(usr, SPAN_NOTICE("The recorder can't print that fast!")) + return + if(recording || playing) + to_chat(usr, SPAN_NOTICE("You can't print the transcript while playing or recording!")) + return + + to_chat(usr, SPAN_NOTICE("Transcript printed.")) + var/obj/item/paper/P = new /obj/item/paper(get_turf(src)) + var/t1 = "Transcript:

              " + for(var/i in 1 to length(mytape.storedinfo)) + var/printedmessage = mytape.storedinfo[i] + if (findtextEx(printedmessage,"*",1,2)) //replace action sounds + printedmessage = "\[[time2text(mytape.timestamp[i]*10,"mm:ss")]\] (Unrecognized sound)" + t1 += "[printedmessage]
              " + P.info = t1 + P.SetName("Transcript") + next_print_time = world.time + TRANSCRIPT_PRINT_COOLDOWN + +/obj/item/taperecorder/attack_self(mob/user) + if(wires_accessible) + wires.Interact(user) + return + if(recording || playing) + stop() + else + record() + +/obj/item/taperecorder/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(!mytape) + icon_state = "[icon_state]_empty" + else if(recording) + icon_state = "[icon_state]_recording" + else if(playing) + icon_state = "[icon_state]_playing" + else + icon_state = "[icon_state]_idle" diff --git a/code/game/objects/items/devices/tape_recorder/taperecorder_wires.dm b/code/game/objects/items/devices/tape_recorder/taperecorder_wires.dm new file mode 100644 index 000000000000..20e4bd7f63fa --- /dev/null +++ b/code/game/objects/items/devices/tape_recorder/taperecorder_wires.dm @@ -0,0 +1,15 @@ +/datum/wires/taperecorder + holder_type = /obj/item/taperecorder + wire_count = 1 + descriptions = list( + new /datum/wire_description(TAPE_WIRE_TOGGLE, "This wire runs to the play/stop toggle.", SKILL_ADEPT) + ) + var/const/TAPE_WIRE_TOGGLE = 1 + +/datum/wires/taperecorder/UpdatePulsed(var/index) + var/obj/item/taperecorder/T = holder + if(T.recording || T.playing) + T.stop() + else + T.play() + SSnano.update_uis(holder) \ No newline at end of file diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm deleted file mode 100644 index 79b76ed2f49c..000000000000 --- a/code/game/objects/items/devices/taperecorder.dm +++ /dev/null @@ -1,553 +0,0 @@ -/obj/item/taperecorder - name = "universal recorder" - desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback." - icon = 'icons/obj/items/device/tape_recorder.dmi' - icon_state = "taperecorder" - item_state = "analyzer" - w_class = ITEM_SIZE_SMALL - - material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - - var/emagged = 0.0 - var/recording = 0.0 - var/playing = 0.0 - var/playsleepseconds = 0.0 - var/obj/item/tape/mytape = /obj/item/tape/random - var/canprint = 1 - var/datum/wires/taperecorder/wires = null // Wires datum - var/maintenance = 0 - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - throwforce = 2 - throw_speed = 4 - throw_range = 20 - -/obj/item/taperecorder/Initialize() - . = ..() - wires = new(src) - set_extension(src, /datum/extension/base_icon_state, icon_state) - if(ispath(mytape)) - mytape = new mytape(src) - GLOB.listening_objects += src - update_icon() - -/obj/item/taperecorder/empty - mytape = null - -/obj/item/taperecorder/Destroy() - QDEL_NULL(wires) - GLOB.listening_objects -= src - if(mytape) - qdel(mytape) - mytape = null - return ..() - - -/obj/item/taperecorder/attackby(obj/item/I, mob/user, params) - if(isScrewdriver(I)) - maintenance = !maintenance - to_chat(user, "You [maintenance ? "open" : "secure"] the lid.") - return - if(istype(I, /obj/item/tape)) - if(mytape) - to_chat(user, "There's already a tape inside.") - return - if(!user.unEquip(I)) - return - I.forceMove(src) - mytape = I - to_chat(user, "You insert [I] into [src].") - update_icon() - return - ..() - - -/obj/item/taperecorder/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(mytape) - mytape.ruin() //Fires destroy the tape - return ..() - - -/obj/item/taperecorder/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - if(mytape) - eject() - return - ..() - - -/obj/item/taperecorder/verb/eject() - set name = "Eject Tape" - set category = "Object" - - if(usr.incapacitated()) - return - if(!mytape) - to_chat(usr, "There's no tape in \the [src].") - return - if(emagged) - to_chat(usr, "The tape seems to be stuck inside.") - return - - if(playing || recording) - stop() - to_chat(usr, "You remove [mytape] from [src].") - usr.put_in_hands(mytape) - mytape = null - update_icon() - -/obj/item/taperecorder/examine(mob/user, distance) - . = ..() - if(distance <= 1 && maintenance) - to_chat(user, "The wires are exposed.") - -/obj/item/taperecorder/hear_talk(mob/living/M, msg, var/verb="says", decl/language/speaking=null) - if(mytape && recording) - - if(speaking) - if(!speaking.machine_understands) - msg = speaking.scramble(msg) - mytape.record_speech("[M.name] [speaking.format_message_plain(msg, verb)]") - else - mytape.record_speech("[M.name] [verb], \"[msg]\"") - - -/obj/item/taperecorder/see_emote(mob/M, text, var/emote_type) - if(emote_type != AUDIBLE_MESSAGE) //only hearable emotes - return - if(mytape && recording) - mytape.record_speech("[strip_html_properly(text)]") - - -/obj/item/taperecorder/show_message(msg, type, alt, alt_type) - var/recordedtext - if (msg && type == AUDIBLE_MESSAGE) //must be hearable - recordedtext = msg - else if (alt && alt_type == AUDIBLE_MESSAGE) - recordedtext = alt - else - return - if(mytape && recording) - mytape.record_noise("[strip_html_properly(recordedtext)]") - -/obj/item/taperecorder/emag_act(var/remaining_charges, var/mob/user) - if(emagged == 0) - emagged = 1 - recording = 0 - to_chat(user, "PZZTTPFFFT") - update_icon() - return 1 - else - to_chat(user, "It is already emagged!") - -/obj/item/taperecorder/proc/explode() - var/turf/T = get_turf(loc) - if(ismob(loc)) - var/mob/M = loc - to_chat(M, "\The [src] explodes!") - if(T) - T.hotspot_expose(700,125) - explosion(T, -1, -1, 0, 4) - qdel(src) - return - -/obj/item/taperecorder/verb/record() - set name = "Start Recording" - set category = "Object" - - if(usr.incapacitated()) - return - playsound(src, 'sound/machines/click.ogg', 10, 1) - if(!mytape) - to_chat(usr, "There's no tape!") - return - if(mytape.ruined || emagged) - audible_message("The tape recorder makes a scratchy noise.") - return - if(recording) - to_chat(usr, "You're already recording!") - return - if(playing) - to_chat(usr, "You can't record when playing!") - return - if(mytape.used_capacity < mytape.max_capacity) - to_chat(usr, "Recording started.") - recording = 1 - update_icon() - - mytape.record_speech("Recording started.") - - //count seconds until full, or recording is stopped - while(mytape && recording && mytape.used_capacity < mytape.max_capacity) - sleep(10) - mytape.used_capacity++ - if(mytape.used_capacity >= mytape.max_capacity) - if(ismob(loc)) - var/mob/M = loc - to_chat(M, "The tape is full.") - stop_recording() - - - update_icon() - return - else - to_chat(usr, "The tape is full.") - - -/obj/item/taperecorder/proc/stop_recording() - //Sanity checks skipped, should not be called unless actually recording - recording = 0 - update_icon() - mytape.record_speech("Recording stopped.") - if(ismob(loc)) - var/mob/M = loc - to_chat(M, "Recording stopped.") - - -/obj/item/taperecorder/verb/stop() - set name = "Stop" - set category = "Object" - - if(usr.incapacitated()) - return - playsound(src, 'sound/machines/click.ogg', 10, 1) - if(recording) - stop_recording() - return - else if(playing) - playing = 0 - update_icon() - to_chat(usr, "Playback stopped.") - return - else - to_chat(usr, "Stop what?") - - -/obj/item/taperecorder/verb/wipe_tape() - set name = "Wipe Tape" - set category = "Object" - - if(usr.incapacitated()) - return - if(!mytape) - return - if(emagged || mytape.ruined) - audible_message("The tape recorder makes a scratchy noise.") - return - if(recording || playing) - to_chat(usr, "You can't wipe the tape while playing or recording!") - return - else - if(mytape.storedinfo) mytape.storedinfo.Cut() - if(mytape.timestamp) mytape.timestamp.Cut() - mytape.used_capacity = 0 - to_chat(usr, "You wipe the tape.") - return - - -/obj/item/taperecorder/verb/playback_memory() - set name = "Playback Tape" - set category = "Object" - - if(usr.incapacitated()) - return - play(usr) - -/obj/item/taperecorder/proc/play(mob/user) - if(!mytape) - to_chat(user, "There's no tape!") - return - if(mytape.ruined) - audible_message("The tape recorder makes a scratchy noise.") - return - if(recording) - to_chat(user, "You can't playback when recording!") - return - if(playing) - to_chat(user, "You're already playing!") - return - playing = 1 - update_icon() - to_chat(user, "Audio playback started.") - playsound(src, 'sound/machines/click.ogg', 10, 1) - for(var/i=1 , i < mytape.max_capacity , i++) - if(!mytape || !playing) - break - if(mytape.storedinfo.len < i) - break - - var/turf/T = get_turf(src) - var/playedmessage = mytape.storedinfo[i] - if (findtextEx(playedmessage,"*",1,2)) //remove marker for action sounds - playedmessage = copytext(playedmessage,2) - T.audible_message("Tape Recorder: [playedmessage]") - - if(mytape.storedinfo.len < i+1) - playsleepseconds = 1 - sleep(10) - T = get_turf(src) - T.audible_message("Tape Recorder: End of recording.") - playsound(src, 'sound/machines/click.ogg', 10, 1) - break - else - playsleepseconds = mytape.timestamp[i+1] - mytape.timestamp[i] - - if(playsleepseconds > 14) - sleep(10) - T = get_turf(src) - T.audible_message("Tape Recorder: Skipping [playsleepseconds] seconds of silence") - playsleepseconds = 1 - sleep(10 * playsleepseconds) - - - playing = 0 - update_icon() - - if(emagged) - var/turf/T = get_turf(src) - T.audible_message("Tape Recorder: This tape recorder will self-destruct in... Five.") - sleep(10) - T = get_turf(src) - T.audible_message("Tape Recorder: Four.") - sleep(10) - T = get_turf(src) - T.audible_message("Tape Recorder: Three.") - sleep(10) - T = get_turf(src) - T.audible_message("Tape Recorder: Two.") - sleep(10) - T = get_turf(src) - T.audible_message("Tape Recorder: One.") - sleep(10) - explode() - - -/obj/item/taperecorder/verb/print_transcript() - set name = "Print Transcript" - set category = "Object" - - if(usr.incapacitated()) - return - if(!mytape) - to_chat(usr, "There's no tape!") - return - if(mytape.ruined || emagged) - audible_message("The tape recorder makes a scratchy noise.") - return - if(!canprint) - to_chat(usr, "The recorder can't print that fast!") - return - if(recording || playing) - to_chat(usr, "You can't print the transcript while playing or recording!") - return - - to_chat(usr, "Transcript printed.") - var/obj/item/paper/P = new /obj/item/paper(get_turf(src)) - var/t1 = "Transcript:

              " - for(var/i=1,mytape.storedinfo.len >= i,i++) - var/printedmessage = mytape.storedinfo[i] - if (findtextEx(printedmessage,"*",1,2)) //replace action sounds - printedmessage = "\[[time2text(mytape.timestamp[i]*10,"mm:ss")]\] (Unrecognized sound)" - t1 += "[printedmessage]
              " - P.info = t1 - P.SetName("Transcript") - canprint = 0 - sleep(300) - canprint = 1 - - -/obj/item/taperecorder/attack_self(mob/user) - if(maintenance) - wires.Interact(user) - return - - if(recording || playing) - stop() - else - record() - - -/obj/item/taperecorder/on_update_icon() - var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) - - if(!mytape) - icon_state = "[bis.base_icon_state]_empty" - else if(recording) - icon_state = "[bis.base_icon_state]_recording" - else if(playing) - icon_state = "[bis.base_icon_state]_playing" - else - icon_state = "[bis.base_icon_state]_idle" - -/obj/item/tape - name = "tape" - desc = "A magnetic tape that can hold up to ten minutes of content." - icon = 'icons/obj/items/device/tape_casette.dmi' - icon_state = "tape_white" - item_state = "analyzer" - w_class = ITEM_SIZE_TINY - material = /decl/material/solid/plastic - matter = list( - /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE - ) - force = 1 - throwforce = 0 - var/max_capacity = 600 - var/used_capacity = 0 - var/list/storedinfo = new/list() - var/list/timestamp = new/list() - var/ruined = 0 - var/doctored = 0 - - -/obj/item/tape/on_update_icon() - overlays.Cut() - if(ruined && max_capacity) - overlays += "ribbonoverlay" - - -/obj/item/tape/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - ruin() - -/obj/item/tape/attack_self(mob/user) - if(!ruined) - to_chat(user, "You pull out all the tape!") - get_loose_tape(user, storedinfo.len) - ruin() - - -/obj/item/tape/proc/ruin() - ruined = 1 - update_icon() - - -/obj/item/tape/proc/fix() - ruined = 0 - update_icon() - - -/obj/item/tape/proc/record_speech(text) - timestamp += used_capacity - storedinfo += "\[[time2text(used_capacity*10,"mm:ss")]\] [text]" - - -//shows up on the printed transcript as (Unrecognized sound) -/obj/item/tape/proc/record_noise(text) - timestamp += used_capacity - storedinfo += "*\[[time2text(used_capacity*10,"mm:ss")]\] [text]" - - -/obj/item/tape/attackby(obj/item/I, mob/user, params) - if(user.incapacitated()) - return - if(ruined && isScrewdriver(I)) - if(!max_capacity) - to_chat(user, "There is no tape left inside.") - return - to_chat(user, "You start winding the tape back in...") - if(do_after(user, 120, target = src)) - to_chat(user, "You wound the tape back in.") - fix() - return - else if(istype(I, /obj/item/pen)) - if(loc == user) - var/new_name = input(user, "What would you like to label the tape?", "Tape labeling") as null|text - if(isnull(new_name)) return - new_name = sanitizeSafe(new_name) - if(new_name) - SetName("tape - '[new_name]'") - to_chat(user, "You label the tape '[new_name]'.") - else - SetName("tape") - to_chat(user, "You scratch off the label.") - return - else if(isWirecutter(I)) - cut(user) - else if(istype(I, /obj/item/tape/loose)) - join(user, I) - ..() - -/obj/item/tape/proc/cut(mob/user) - if(!LAZYLEN(timestamp)) - to_chat(user, "There's nothing on this tape!") - return - var/list/output = list("
              ") - for(var/i=1, i < timestamp.len, i++) - var/time = "\[[time2text(timestamp[i]*10,"mm:ss")]\]" - output += "[time]
              -----CUT------
              " - output += "
              " - - var/datum/browser/popup = new(user, "tape_cutting", "Cutting tape", 170, 600) - popup.set_content(jointext(output,null)) - popup.open() - -/obj/item/tape/proc/join(mob/user, obj/item/tape/other) - if(max_capacity + other.max_capacity > initial(max_capacity)) - to_chat(user, "You can't fit this much tape in!") - return - if(user.unEquip(other)) - to_chat(user, "You join ends of the tape together.") - max_capacity += other.max_capacity - used_capacity = min(used_capacity + other.used_capacity, max_capacity) - timestamp += other.timestamp - storedinfo += other.storedinfo - doctored = 1 - ruin() - update_icon() - qdel(other) - -/obj/item/tape/OnTopic(var/mob/user, var/list/href_list) - if(href_list["cut_after"]) - var/index = text2num(href_list["cut_after"]) - if(index >= timestamp.len) - return - - to_chat(user, "You remove part of the tape off.") - get_loose_tape(user, index) - cut(user) - return TOPIC_REFRESH - -//Spawns new loose tape item, with data starting from [index] entry -/obj/item/tape/proc/get_loose_tape(var/mob/user, var/index) - var/obj/item/tape/loose/newtape = new() - newtape.timestamp = timestamp.Copy(index+1) - newtape.storedinfo = storedinfo.Copy(index+1) - newtape.max_capacity = max_capacity - index - newtape.used_capacity = max(0, used_capacity - max_capacity) - newtape.doctored = doctored - user.put_in_hands(newtape) - - timestamp.Cut(index+1) - storedinfo.Cut(index+1) - max_capacity = index - used_capacity = min(used_capacity,index) - -//Random colour tapes -/obj/item/tape/random/Initialize() - . = ..() - icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]" - -/obj/item/tape/loose - name = "magnetic tape" - desc = "Quantum-enriched self-repairing nanotape, used for magnetic storage of information." - icon = 'icons/obj/items/device/tape_casette.dmi' - icon_state = "magtape" - ruined = 1 - -/obj/item/tape/loose/fix() - return - -/obj/item/tape/loose/on_update_icon() - return - -/obj/item/tape/loose/get_loose_tape() - return - -/obj/item/tape/loose/examine(mob/user, distance) - . = ..() - if(distance <= 1) - to_chat(user, "It looks long enough to hold [max_capacity] seconds worth of recording.") - if(doctored && user.skill_check(SKILL_FORENSICS, SKILL_PROF)) - to_chat(user, "It has been tampered with...") diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index c3968a2d32af..60f957f8c435 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -18,32 +18,37 @@ effective or pretty fucking useless. name = "mind batterer" desc = "A strange device with twin antennas." icon = 'icons/obj/items/weapon/batterer.dmi' - icon_state = "batterer" - throwforce = 5 - w_class = ITEM_SIZE_TINY + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL throw_speed = 4 throw_range = 10 obj_flags = OBJ_FLAG_CONDUCTIBLE - item_state = "electronic" - origin_tech = "{'magnets':3,'combat':3,'esoteric':3}" + origin_tech = @'{"magnets":3,"combat":3,"esoteric":3}' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/titanium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, + ) var/times_used = 0 //Number of times it's been used. var/max_uses = 2 -/obj/item/batterer/attack_self(mob/living/carbon/user, flag = 0, emp = 0) +/obj/item/batterer/attack_self(mob/user, flag = 0, emp = 0) if(!user) return if(times_used >= max_uses) to_chat(user, "The mind batterer has been burnt out!") return var/list/stun_victims = list() - for(var/mob/living/carbon/human/M in orange(10, user)) + for(var/mob/living/human/M in orange(10, user)) stun_victims += M spawn() if(prob(50)) - M.Weaken(rand(10,20)) + SET_STATUS_MAX(M, STAT_WEAK, rand(10,20)) if(prob(25)) - M.Stun(rand(5,10)) + SET_STATUS_MAX(M, STAT_STUN, rand(5, 10)) to_chat(M, "You feel a tremendous, paralyzing wave flood your mind.") else to_chat(M, "You feel a sudden, electric jolt travel through your head.") @@ -53,5 +58,9 @@ effective or pretty fucking useless. playsound(src.loc, 'sound/misc/interference.ogg', 50, 1) to_chat(user, "You trigger [src].") times_used += 1 - if(times_used >= max_uses) - icon_state = "battererburnt" + update_icon() + +/obj/item/batterer/on_update_icon() + . = ..() + if(times_used < max_uses) + add_overlay("[icon_state]-on") diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 3ea7b17a2e54..31aaf31b8044 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -3,34 +3,47 @@ desc = "A small, versatile valve with dual-headed heat-resistant pipes. This mechanism is the standard size for coupling with portable gas tanks." icon = 'icons/obj/assemblies.dmi' icon_state = "valve_1" + material = /decl/material/solid/metal/stainlesssteel var/obj/item/tank/tank_one var/obj/item/tank/tank_two - var/obj/item/attached_device - var/mob/attacher = null + var/obj/item/assembly/attached_device + var/weakref/attacher_ref = null var/valve_open = 0 var/toggle = 1 movable_flags = MOVABLE_FLAG_PROXMOVE -/obj/item/transfer_valve/IsAssemblyHolder() - return 1 +/obj/item/transfer_valve/Destroy() + if(!QDELETED(tank_one)) + QDEL_NULL(tank_one) + else + tank_one = null + if(!QDELETED(tank_two)) + QDEL_NULL(tank_two) + else + tank_two = null + if(!QDELETED(attached_device)) + QDEL_NULL(attached_device) + else + attached_device = null + attacher_ref = null + return ..() -/obj/item/transfer_valve/attackby(obj/item/item, mob/user) +/obj/item/transfer_valve/attackby(obj/item/used_item, mob/user) var/turf/location = get_turf(src) // For admin logs - if(istype(item, /obj/item/tank)) - + if(istype(used_item, /obj/item/tank)) var/T1_weight = 0 var/T2_weight = 0 if(tank_one && tank_two) to_chat(user, "There are already two tanks attached, remove one first.") - return + return TRUE - if(!user.unEquip(item, src)) - return + if(!user.try_unequip(used_item, src)) + return TRUE if(!tank_one) - tank_one = item + tank_one = used_item else - tank_two = item - message_admins("[key_name_admin(user)] attached both tanks to a transfer valve. (JMP)") + tank_two = used_item + message_admins("[key_name_admin(user)] attached both tanks to a transfer valve. (JMP)") log_game("[key_name_admin(user)] attached both tanks to a transfer valve.") to_chat(user, "You attach the tank to the transfer valve.") @@ -39,39 +52,39 @@ T2_weight = tank_two.w_class src.w_class = max(initial(src.w_class),T1_weight,T2_weight) //gets w_class of biggest object, because you shouldn't be able to just shove tanks in and have them be tiny. - - update_icon() - - SSnano.update_uis(src) // update all UIs attached to src + . = TRUE //TODO: Have this take an assemblyholder - else if(isassembly(item)) - var/obj/item/assembly/A = item + else if(isassembly(used_item)) + var/obj/item/assembly/A = used_item if(A.secured) to_chat(user, "The device is secured.") - return + return TRUE if(attached_device) to_chat(user, "There is already an device attached to the valve, remove it first.") - return - if(!user.unEquip(item, src)) - return + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE attached_device = A - to_chat(user, "You attach the [item] to the valve controls and secure it.") + to_chat(user, "You attach \the [used_item] to the valve controls and secure it.") A.holder = src A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb). - GLOB.bombers += "[key_name(user)] attached a [item] to a transfer valve." - message_admins("[key_name_admin(user)] attached a [item] to a transfer valve. (JMP)") - log_game("[key_name_admin(user)] attached a [item] to a transfer valve.") - attacher = user + global.bombers += "[key_name(user)] attached a [used_item] to a transfer valve." + message_admins("[key_name_admin(user)] attached a [used_item] to a transfer valve. (JMP)") + log_game("[key_name_admin(user)] attached a [used_item] to a transfer valve.") + attacher_ref = weakref(user) + . = TRUE + if(.) + update_icon() SSnano.update_uis(src) // update all UIs attached to src - return + return TRUE + return ..() /obj/item/transfer_valve/HasProximity(atom/movable/AM) - if(!attached_device) return - attached_device.HasProximity(AM) - return - + . = ..() + if(. && attached_device) + attached_device.HasProximity(AM) /obj/item/transfer_valve/attack_self(mob/user) ui_interact(user) @@ -113,14 +126,14 @@ else if(attached_device) if(href_list["rem_device"]) attached_device.dropInto(loc) - attached_device:holder = null + attached_device.holder = null attached_device = null update_icon() if(href_list["device"]) attached_device.attack_self(usr) return 1 // Returning 1 sends an update to attached UIs -/obj/item/transfer_valve/proc/process_activation(var/obj/item/D) +/obj/item/transfer_valve/proc/process_activation(var/obj/item/activator) if(toggle) toggle = 0 toggle_valve() @@ -128,7 +141,7 @@ toggle = 1 /obj/item/transfer_valve/on_update_icon() - overlays.Cut() + . = ..() underlays.Cut() if(!tank_one && !tank_two && !attached_device) @@ -137,13 +150,13 @@ icon_state = "valve" if(tank_one) - overlays += "[tank_one.icon_state]" + add_overlay(new/mutable_appearance(tank_one)) if(tank_two) var/icon/J = new(icon, icon_state = "[tank_two.icon_state]") J.Shift(WEST, 13) underlays += J if(attached_device) - overlays += "device" + add_overlay("device") /obj/item/transfer_valve/proc/remove_tank(obj/item/tank/T) if(tank_one == T) @@ -162,7 +175,7 @@ /obj/item/transfer_valve/proc/merge_gases() if(valve_open) return - tank_two.air_contents.volume += tank_one.air_contents.volume + tank_two.air_contents.total_volume += tank_one.air_contents.total_volume var/datum/gas_mixture/temp = tank_one.remove_air_ratio(1) tank_two.assume_air(temp) valve_open = 1 @@ -176,9 +189,9 @@ if(QDELETED(tank_one) || QDELETED(tank_two)) return - var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume + var/ratio1 = tank_one.air_contents.total_volume/tank_two.air_contents.total_volume var/datum/gas_mixture/temp = tank_two.remove_air_ratio(ratio1) - tank_two.air_contents.volume -= tank_one.air_contents.volume + tank_two.air_contents.total_volume -= tank_one.air_contents.total_volume tank_one.assume_air(temp) /* @@ -192,24 +205,25 @@ var/area/A = get_area(bombturf) var/attacher_name = "" + var/mob/attacher = attacher_ref.resolve() if(!attacher) attacher_name = "Unknown" else attacher_name = "[attacher.name]([attacher.ckey])" - var/log_str = "Bomb valve opened in [A.name] " + var/log_str = "Bomb valve opened in [A.proper_name] " log_str += "with [attached_device ? attached_device : "no device"] attacher: [attacher_name]" if(attacher) - log_str += "(?)" + log_str += "(?)" var/mob/mob = get_mob_by_key(src.fingerprintslast) var/last_touch_info = "" if(mob) - last_touch_info = "(?)" + last_touch_info = "(?)" log_str += " Last touched by: [src.fingerprintslast][last_touch_info]" - GLOB.bombers += log_str + global.bombers += log_str message_admins(log_str, 0, 1) log_game(log_str) merge_gases() @@ -218,8 +232,3 @@ split_gases() src.update_icon() - -// this doesn't do anything but the timer etc. expects it to be here -// eventually maybe have it update icon to show state (timer, prox etc.) like old bombs -/obj/item/transfer_valve/proc/c_state() - return diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm index 920128e28ecd..4450994afe0c 100644 --- a/code/game/objects/items/devices/tvcamera.dm +++ b/code/game/objects/items/devices/tvcamera.dm @@ -1,155 +1,174 @@ +// TODO make this a network device. /obj/item/camera/tvcamera name = "press camera drone" desc = "An EyeBuddy livestreaming press camera drone. Weapon of choice for war correspondents and reality show cameramen. It does not appear to have any internal memory storage." - icon_state = "camcorder" - item_state = "camcorder" + icon = 'icons/clothing/belt/camcorder.dmi' + icon_state = ICON_STATE_WORLD + item_state = null w_class = ITEM_SIZE_LARGE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + ) var/channel = "General News Feed" - var/obj/machinery/camera/network/thunder/camera + var/video_enabled = FALSE var/obj/item/radio/radio /obj/item/camera/tvcamera/Destroy() - GLOB.listening_objects -= src - QDEL_NULL(camera) QDEL_NULL(radio) . = ..() /obj/item/camera/tvcamera/Initialize() - camera = new(src) - camera.c_tag = channel - camera.status = FALSE + set_extension(src, /datum/extension/network_device/camera/television, null, null, null, TRUE, list(CAMERA_CHANNEL_TELEVISION), channel, FALSE) radio = new(src) radio.listening = FALSE - radio.set_frequency(ENT_FREQ) radio.power_usage = 0 - GLOB.listening_objects += src + global.listening_objects += src . = ..() -/obj/item/camera/tvcamera/examine(mob/user) +/obj/item/camera/tvcamera/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "Video feed is currently: [camera.status ? "Online" : "Offline"]") - to_chat(user, "Audio feed is currently: [radio.broadcasting ? "Online" : "Offline"]") - to_chat(user, "Photography setting is currently: [on ? "On" : "Off"]") + . += "Video feed is currently: [video_enabled ? "Online" : "Offline"]" + . += "Audio feed is currently: [radio.broadcasting ? "Online" : "Offline"]" + . += "Photography setting is currently: [turned_on ? "On" : "Off"]" /obj/item/camera/tvcamera/attack_self(mob/user) add_fingerprint(user) user.set_machine(src) var/dat = list() - dat += "Photography mode is currently: [on ? "On" : "Off"]
              " - dat += "Photography focus is currently: [size]
              " - dat += "Channel name is: [channel ? channel : "unidentified broadcast"]
              " - dat += "Video streaming is: [camera.status ? "Online" : "Offline"]
              " - dat += "Microphone is: [radio.broadcasting ? "Online" : "Offline"]
              " - dat += "Sound is being broadcasted on frequency: [format_frequency(radio.frequency)] ([get_frequency_default_name(radio.frequency)])
              " - var/datum/browser/written/popup = new(user, "Press Camera Drone", "EyeBuddy", 300, 390, src) + dat += "Photography mode is currently: [turned_on ? "On" : "Off"]
              " + dat += "Photography focus is currently: [field_of_view]
              " + dat += "Channel name is: [channel ? channel : "unidentified broadcast"]
              " + dat += "Video streaming is: [video_enabled ? "Online" : "Offline"]
              " + dat += "Microphone is: [radio.broadcasting ? "Online" : "Offline"]
              " + dat += "Sound is being broadcasted on frequency: [format_frequency(radio.frequency)]
              " + dat += "Network Options" + var/datum/browser/written_digital/popup = new(user, "Press Camera Drone", "EyeBuddy", 300, 390, src) popup.set_content(jointext(dat,null)) popup.open() -/obj/item/camera/tvcamera/Topic(bred, href_list, state = GLOB.physical_state) +/obj/item/camera/tvcamera/Topic(bred, href_list, state = global.physical_topic_state) if(..()) return 1 if (href_list["photo"]) - on = !on + turned_on = !turned_on if (href_list["focus"]) change_size() if(href_list["channel"]) var/nc = sanitize(input(usr, "Channel name", "Select new channel name", channel) as text|null) if(nc) channel = nc - camera.c_tag = channel + var/datum/extension/network_device/camera/television/D = get_extension(src, /datum/extension/network_device) + D.display_name = channel to_chat(usr, "New channel name: '[channel]' has been set.") if(href_list["video"]) - camera.set_status(!camera.status) - if(camera.status) + video_enabled = !video_enabled + if(video_enabled) to_chat(usr,"Video streaming: Activated. Broadcasting on channel: '[channel]'") else to_chat(usr,"Video streaming: Deactivated.") update_icon() if(href_list["sound"]) - radio.ToggleBroadcast() + radio.toggle_broadcast() if(radio.broadcasting) to_chat(usr,"Audio streaming: Activated. Broadcasting on frequency: [format_frequency(radio.frequency)].") else to_chat(usr,"Audio streaming: Deactivated.") + if(href_list["net_options"]) + var/datum/extension/network_device/camera/television/D = get_extension(src, /datum/extension/network_device) + D.ui_interact(usr) if(!href_list["close"]) attack_self(usr) +/obj/item/camera/tvcamera/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && video_enabled && check_state_in_icon("[overlay.icon_state]-on", overlay.icon)) + overlay.icon_state = "[overlay.icon_state]-on" + . = ..() + /obj/item/camera/tvcamera/on_update_icon() - ..() - if(camera.status) - icon_state = "camcorder_on" - item_state = "camcorder_on" - else - icon_state = "camcorder" - item_state = "camcorder" - var/mob/living/carbon/human/H = loc - if(istype(H)) - H.update_inv_r_hand(0) - H.update_inv_l_hand() + . = ..() + if(video_enabled) + add_overlay("[icon_state]-on") + update_held_icon() /* Assembly by a roboticist */ -/obj/item/robot_parts/head/attackby(var/obj/item/assembly/S, mob/user) - if ((!istype(S, /obj/item/assembly/infra))) - ..() - return - var/obj/item/TVAssembly/A = new(user) - qdel(S) - user.put_in_hands(A) +// TODO: Make this slapcrafting or remove tvcamera/tvassembly entirely +/obj/item/robot_parts/head/attackby(obj/item/used_item, mob/user) + var/obj/item/assembly/infra/assembly = used_item + if(!istype(assembly)) + return ..() + var/obj/item/TVAssembly/tv_assembly = new(user) + qdel(assembly) + user.put_in_hands(tv_assembly) to_chat(user, "You add the infrared sensor to the robot head.") qdel(src) + return TRUE /* Using camcorder icon as I can't sprite. Using robohead because of restricting to roboticist */ /obj/item/TVAssembly name = "TV Camera assembly" - desc = "A robotic head with an infrared sensor inside" + desc = "A robotic head with an infrared sensor inside." icon = 'icons/obj/robot_parts.dmi' icon_state = "head" item_state = "head" var/buildstep = 0 w_class = ITEM_SIZE_LARGE + material = /decl/material/solid/metal/steel -/obj/item/TVAssembly/attackby(var/obj/item/W, var/mob/user) +// TODO: refactor this to use slapcrafting? remove entirely? +/obj/item/TVAssembly/attackby(var/obj/item/used_item, var/mob/user) switch(buildstep) if(0) - if(istype(W, /obj/item/robot_parts/robot_component/camera)) + if(istype(used_item, /obj/item/robot_parts/robot_component/camera)) to_chat(user, "You add the camera module to [src]") - qdel(W) + qdel(used_item) desc = "This TV camera assembly has a camera module." buildstep++ + return TRUE if(1) - if(istype(W, /obj/item/taperecorder)) - qdel(W) + if(istype(used_item, /obj/item/taperecorder)) + qdel(used_item) buildstep++ to_chat(user, "You add the tape recorder to [src]") desc = "This TV camera assembly has a camera and audio module." - return + return TRUE if(2) - if(isCoil(W)) - var/obj/item/stack/cable_coil/C = W + if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/C = used_item if(!C.use(3)) to_chat(user, "You need three cable coils to wire the devices.") - ..() - return + return TRUE buildstep++ - to_chat(user, "You wire the assembly") - desc = "This TV camera assembly has wires sticking out" - return + to_chat(user, SPAN_NOTICE("You wire the assembly.")) + desc = "This TV camera assembly has wires sticking out." + return TRUE if(3) - if(isWirecutter(W)) + if(IS_WIRECUTTER(used_item)) to_chat(user, " You trim the wires.") buildstep++ desc = "This TV camera assembly needs casing." - return + return TRUE if(4) - if(istype(W, /obj/item/stack/material/steel)) - var/obj/item/stack/material/steel/S = W - if(S.use(1)) + if(istype(used_item, /obj/item/stack/material)) + var/obj/item/stack/material/S = used_item + if(S.material?.type == /decl/material/solid/metal/steel && S.use(1)) buildstep++ to_chat(user, "You encase the assembly.") var/turf/T = get_turf(src) new /obj/item/camera/tvcamera(T) qdel(src) - return - ..() \ No newline at end of file + return TRUE + return ..() + +/datum/extension/network_device/camera/television + expected_type = /obj/item/camera/tvcamera + requires_connection = FALSE + +/datum/extension/network_device/camera/television/is_functional() + var/obj/item/camera/tvcamera/tv = holder + return tv.video_enabled \ No newline at end of file diff --git a/code/game/objects/items/devices/uplink.dm b/code/game/objects/items/devices/uplink.dm index 069a2104bcef..2d54bf5b1bfa 100644 --- a/code/game/objects/items/devices/uplink.dm +++ b/code/game/objects/items/devices/uplink.dm @@ -1,7 +1,7 @@ // HIDDEN UPLINK - Can be stored in anything but the host item has to have a trigger for it. /* How to create an uplink in 3 easy steps! - 1. All obj/item 's have a hidden_uplink var. By default it's null. Give the item one with "new(src)", it must be in it's contents. Feel free to add "uses". + 1. All obj/item 's have a hidden_uplink var. By default it's null. Give the item one with "new(src)", it must be in its contents. Feel free to add "uses". 2. Code in the triggers. Use check_trigger for this, I recommend closing the item's menu with "close_browser(usr, "window=windowname") if it returns true. The var/value is the value that will be compared with the var/target. If they are equal it will activate the menu. @@ -13,15 +13,20 @@ /obj/item/uplink name = "hidden uplink" desc = "There is something wrong if you're examining this." + max_health = ITEM_HEALTH_NO_DAMAGE + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + ) + is_spawnable_type = FALSE var/active = 0 - var/datum/uplink_category/category = 0 // The current category we are in - var/exploit_id // Id of the current exploit record we are viewing + var/datum/uplink_category/category // The current category we are in + var/exploit_id // Id of the current exploit record we are viewing var/welcome = "Welcome, Operative" // Welcoming menu message var/uses // Numbers of crystals - var/list/ItemsCategory // List of categories with lists of items - var/list/ItemsReference // List of references with an associated item - var/list/nanoui_items // List of items for NanoUI use var/nanoui_menu = 0 // The current menu we are in var/list/nanoui_data = new // Additional data for NanoUI use @@ -45,13 +50,11 @@ update_nano_data() src.uplink_owner = owner - world_uplinks += src uses = telecrystals START_PROCESSING(SSobj, src) /obj/item/uplink/Destroy() uplink_owner = null - world_uplinks -= src STOP_PROCESSING(SSobj, src) return ..() @@ -64,7 +67,7 @@ do var/datum/uplink_random_selection/uplink_selection = get_uplink_random_selection_by_type(/datum/uplink_random_selection/blacklist) new_discount_item = uplink_selection.get_random_item(INFINITY, src) - // Ensures we only only get items for which we get an actual discount and that this particular uplink can actually view (can buy would risk near-infinite loops). + // Ensures we only get items for which we get an actual discount and that this particular uplink can actually view (can buy would risk near-infinite loops). while(is_improper_item(new_discount_item, discount_amount)) if(!new_discount_item) return @@ -114,7 +117,7 @@ /* NANO UI FOR UPLINK WOOP WOOP */ -/obj/item/uplink/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = GLOB.inventory_state) +/obj/item/uplink/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = global.inventory_topic_state) var/title = "Remote Uplink" var/data[0] @@ -147,6 +150,7 @@ // The purchasing code. /obj/item/uplink/OnTopic(user, href_list) + var/decl/uplink/uplink = IMPLIED_DECL if(href_list["buy_item"]) var/datum/uplink_item/UI = (locate(href_list["buy_item"]) in uplink.items) UI.buy(src, usr) @@ -170,6 +174,7 @@ update_nano_data() /obj/item/uplink/proc/update_nano_data() + var/decl/uplink/uplink = IMPLIED_DECL if(nanoui_menu == 0) var/categories[0] for(var/datum/uplink_category/category in uplink.categories) @@ -186,13 +191,13 @@ nanoui_data["items"] = items else if(nanoui_menu == 2) var/permanentData[0] - for(var/datum/computer_file/report/crew_record/L in GLOB.all_crew_records) - permanentData[++permanentData.len] = list(Name = L.get_name(),"id" = L.uid, "exploit" = length(L.get_antagRecord())) + for(var/datum/computer_file/report/crew_record/L in global.all_crew_records) + permanentData[++permanentData.len] = list(Name = L.get_name(),"id" = L.uid, "exploit" = length(L.get_antag_record())) nanoui_data["exploit_records"] = permanentData else if(nanoui_menu == 21) nanoui_data["exploit_exists"] = 0 - for(var/datum/computer_file/report/crew_record/L in GLOB.all_crew_records) + for(var/datum/computer_file/report/crew_record/L in global.all_crew_records) if(L.uid == exploit_id) nanoui_data["exploit"] = L.generate_nano_data() nanoui_data["exploit_exists"] = 1 @@ -216,29 +221,28 @@ // Includes normal radio uplink, multitool uplink, // implant uplink (not the implant tool) and a preset headset uplink. -/obj/item/radio/uplink/Initialize(mapload, var/owner, var/amount) - . = ..() - hidden_uplink = new(src, owner, amount) - icon_state = "radio" +/obj/item/radio/uplink + var/tc_amount = DEFAULT_TELECRYSTAL_AMOUNT /obj/item/radio/uplink/attack_self(mob/user) + if(!hidden_uplink && user.mind) + hidden_uplink = new(src, user.mind, tc_amount) if(hidden_uplink) hidden_uplink.trigger(user) -/obj/item/multitool/uplink/Initialize(mapload, var/owner) - . = ..() - hidden_uplink = new(src, owner) - /obj/item/multitool/uplink/attack_self(mob/user) + if(!hidden_uplink && user.mind) + hidden_uplink = new(src, user.mind, DEFAULT_TELECRYSTAL_AMOUNT) if(hidden_uplink) hidden_uplink.trigger(user) /obj/item/radio/headset/uplink traitor_frequency = 1445 -/obj/item/radio/headset/uplink/Initialize() +/obj/item/radio/headset/uplink/attack_self(mob/user) + if(!hidden_uplink && user.mind) + hidden_uplink = new(src, user.mind, DEFAULT_TELECRYSTAL_AMOUNT) . = ..() - hidden_uplink = new(src) -/obj/item/uplink/contained/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = GLOB.contained_state) +/obj/item/uplink/contained/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = global.contained_topic_state) return ..() diff --git a/code/game/objects/items/devices/uplink_random_lists.dm b/code/game/objects/items/devices/uplink_random_lists.dm index 5ac9d99f5b58..bd97ea3283ee 100644 --- a/code/game/objects/items/devices/uplink_random_lists.dm +++ b/code/game/objects/items/devices/uplink_random_lists.dm @@ -4,7 +4,7 @@ var/reselect_probability // Probability that we'll decide to keep this item if previously selected. // Is done together with the keep_probability check. Being selected more than once does not affect this probability. -/datum/uplink_random_item/New(var/uplink_item, var/keep_probability = 100, var/reselect_propbability = 33) +/datum/uplink_random_item/New(var/uplink_item, var/keep_probability = 100, var/reselect_probability = 33) ..() src.uplink_item = uplink_item src.keep_probability = keep_probability @@ -19,22 +19,23 @@ /datum/uplink_random_selection/proc/get_random_item(var/telecrystals, obj/item/uplink/U, var/list/bought_items) var/const/attempts = 50 + var/decl/uplink/uplink = IMPLIED_DECL for(var/i = 0; i < attempts; i++) - var/datum/uplink_random_item/RI = pick(items) - if(!prob(RI.keep_probability)) + var/datum/uplink_random_item/random_item = pick(items) + if(!prob(random_item.keep_probability)) continue - var/datum/uplink_item/I = uplink.items_assoc[RI.uplink_item] - if(I.cost(telecrystals, U) > telecrystals) + var/datum/uplink_item/uplink_item = uplink.items_assoc[random_item.uplink_item] + if(uplink_item.cost(telecrystals, uplink) > telecrystals) continue - if(bought_items && (I in bought_items) && !prob(RI.reselect_probability)) + if(bought_items && (uplink_item in bought_items) && !prob(random_item.reselect_probability)) continue - if(U && !I.can_buy(U)) + if(uplink && !uplink_item.can_buy(uplink)) continue - return I + return uplink_item return uplink.items_assoc[/datum/uplink_item/item/stealthy_weapons/soap] -var/list/uplink_random_selections_ +var/global/list/uplink_random_selections_ /proc/get_uplink_random_selection_by_type(var/uplist_selection_type) if(!uplink_random_selections_) uplink_random_selections_ = init_subtypes(/datum/uplink_random_selection) @@ -47,7 +48,6 @@ var/list/uplink_random_selections_ items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/silenced) items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/revolver) - items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/heavysniper, 15, 0) items += new/datum/uplink_random_item(/datum/uplink_item/item/grenades/emp, 50) items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/crossbow, 33) items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/energy_sword, 75) @@ -63,7 +63,7 @@ var/list/uplink_random_selections_ items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/chameleon_projector) items += new/datum/uplink_random_item(/datum/uplink_item/item/stealth_items/voice) - items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/toolbox, reselect_propbability = 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/toolbox, reselect_probability = 10) items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/plastique) items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/encryptionkey_radio) items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/encryptionkey_binary) @@ -74,27 +74,25 @@ var/list/uplink_random_selections_ items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/heavy_armor) items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/powersink, 10, 10) items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/ai_module, 25, 0) - items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/teleporter, 10, 0) items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_freedom) items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_compress) items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_explosive) - items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/sinpockets, reselect_propbability = 20) - items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/surgery, reselect_propbability = 10) - items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/combat, reselect_propbability = 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/sinpockets, reselect_probability = 20) + items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/surgery, reselect_probability = 10) + items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/combat, reselect_probability = 10) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/energy_net, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/ewar_voice, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/maneuvering_jets, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/egun, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/power_sink, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/laser_canon, reselect_propbability = 5) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/energy_net, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/ewar_voice, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/maneuvering_jets, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/egun, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/power_sink, reselect_probability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) - items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_propbability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_probability = 15) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/thermal, reselect_probability = 15) items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/suit_sensor_mobile) items += new/datum/uplink_random_item(/datum/uplink_item/item/services/suit_sensor_shutdown, 75, 0) @@ -105,7 +103,6 @@ var/list/uplink_random_selections_ /datum/uplink_item/item/ammo, /datum/uplink_item/item/badassery, /datum/uplink_item/item/telecrystal, - /datum/uplink_item/item/tools/teleporter, /datum/uplink_item/item/tools/supply_beacon, /datum/uplink_item/item/implants/imp_uplink, ) @@ -121,28 +118,17 @@ var/list/uplink_random_selections_ var/new_thing = new/datum/uplink_random_item(uplink_item_type) items += new_thing -/datum/uplink_random_selection/blacklist/get_random_item(var/telecrystals, obj/item/uplink/U, var/list/bought_items) +/datum/uplink_random_selection/blacklist/get_random_item(var/telecrystals, obj/item/uplink/uplink_access, var/list/bought_items) var/const/attempts = 50 + var/decl/uplink/uplink = IMPLIED_DECL for(var/i = 0; i < attempts; i++) - var/datum/uplink_random_item/RI = pick(items) - if(!prob(RI.keep_probability)) + var/datum/uplink_random_item/random_item = pick(items) + if(!prob(random_item.keep_probability)) continue - var/datum/uplink_item/I = uplink.items_assoc[RI.uplink_item] - if(I.cost(telecrystals, U) > telecrystals) + var/datum/uplink_item/uplink_item = uplink.items_assoc[random_item.uplink_item] + if(uplink_item.cost(telecrystals, uplink_access) > telecrystals) continue - if(bought_items && (I in bought_items) && !prob(RI.reselect_probability)) + if(bought_items && (uplink_item in bought_items) && !prob(random_item.reselect_probability)) continue - return I + return uplink_item return uplink.items_assoc[/datum/uplink_item/item/stealthy_weapons/soap] - -#ifdef DEBUG -/proc/debug_uplink_purchage_log() - for(var/antag_type in GLOB.all_antag_types_) - var/datum/antagonist/A = GLOB.all_antag_types_[antag_type] - A.print_player_summary() - -/proc/debug_uplink_item_assoc_list() - for(var/key in uplink.items_assoc) - log_debug("[key] - [uplink.items_assoc[key]]") - -#endif diff --git a/code/game/objects/items/devices/whistle.dm b/code/game/objects/items/devices/whistle.dm deleted file mode 100644 index cd82f39f64fc..000000000000 --- a/code/game/objects/items/devices/whistle.dm +++ /dev/null @@ -1,51 +0,0 @@ -/obj/item/hailer - name = "hailer" - desc = "Used by obese officers to save their breath for running." - icon = 'icons/obj/items/device/hailer.dmi' - icon_state = "voice0" - item_state = "flashbang" //looks exactly like a flash (and nothing like a flashbang) - w_class = ITEM_SIZE_TINY - obj_flags = OBJ_FLAG_CONDUCTIBLE - - var/use_message = "Halt! Security!" - var/spamcheck = 0 - var/insults - -/obj/item/hailer/verb/set_message() - set name = "Set Hailer Message" - set category = "Object" - set desc = "Alter the message shouted by your hailer." - - if(!isnull(insults)) - to_chat(usr, "The hailer is fried. The tiny input screen just shows a waving ASCII penis.") - return - - var/new_message = input(usr, "Please enter new message (leave blank to reset).") as text - if(!new_message || new_message == "") - use_message = "Halt! Security!" - else - use_message = capitalize(copytext(sanitize(new_message), 1, MAX_MESSAGE_LEN)) - - to_chat(usr, "You configure the hailer to shout \"[use_message]\".") - -/obj/item/hailer/attack_self(mob/living/carbon/user) - if (spamcheck) - return - - if(isnull(insults)) - playsound(get_turf(src), 'sound/voice/halt.ogg', 100, 1, vary = 0) - user.audible_message("[user]'s [name] rasps, \"[use_message]\"", null, "\The [user] holds up \the [name].") - else - to_chat(user, "*BZZZZZZZZT*") - - spamcheck = 1 - spawn(20) - spamcheck = 0 - -/obj/item/hailer/emag_act(var/remaining_charges, var/mob/user) - if(isnull(insults)) - to_chat(user, "You overload \the [src]'s voice synthesizer.") - insults = rand(1, 3)//to prevent dickflooding - return 1 - else - to_chat(user, "The hailer is fried. You can't even fit the sequencer into the input slot.") diff --git a/code/game/objects/items/documents.dm b/code/game/objects/items/documents.dm index 39e899dbc6db..151aa5b302e3 100644 --- a/code/game/objects/items/documents.dm +++ b/code/game/objects/items/documents.dm @@ -4,12 +4,13 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "docs_generic" item_state = "paper" - throwforce = 0 w_class = ITEM_SIZE_TINY throw_range = 1 + material = /decl/material/solid/organic/paper + _base_attack_force = 0 var/description_antag = "These conversations contain a massive amount of dirt on major figures: drugs, sex, money..." -/obj/item/documents/examine(mob/user) +/obj/item/documents/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(description_antag) - to_chat(user, description_antag) + . += description_antag diff --git a/code/game/objects/items/flame/_flame.dm b/code/game/objects/items/flame/_flame.dm new file mode 100644 index 000000000000..d57f5a8ce1f7 --- /dev/null +++ b/code/game/objects/items/flame/_flame.dm @@ -0,0 +1,233 @@ +//For anything that can light stuff on fire +/obj/item/flame + + abstract_type = /obj/item/flame + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + origin_tech = @'{"materials":1}' + material = /decl/material/solid/organic/wood/oak + + /// Parameters for lighting when lit. + var/lit_light_range = 1 + var/lit_light_power = 0.5 + var/lit_light_color = "#e09d37" + + /// Does this flame source smell of anything when burning? + var/decl/scent_type/scent + /// Is this item extinguished by being dropped? + var/extinguish_on_dropped = TRUE + /// How hot does this burn? + var/lit_heat = 1000 + /// Can this item be extinguished by water? + var/waterproof = FALSE + /// Is this item currently lit? + var/lit = FALSE + /// How many SSobj ticks can this burn for? + var/_fuel = 0 + /// How much fuel does this spend in a tick? + var/_fuel_spend_amt = 1 + /// Can you put this item out with your hand? + var/can_manually_extinguish = TRUE + /// Can you light this item with your hand? + var/can_manually_light = FALSE + /// Can this item be put into a sconce? + var/sconce_can_hold = FALSE + /// Can this item go in a bag or storage slot while lit? + var/can_store_lit = FALSE + +/obj/item/flame/Initialize(var/ml, var/material_key) + + var/list/available_scents = get_available_scents() + if(LAZYLEN(available_scents)) + scent = pick(available_scents) + scent = GET_DECL(scent) + if(istype(scent)) + if(scent.color) + set_color(scent.color) + desc += " This one smells of [scent.scent]." + else + scent = null + + . = ..() + + set_extension(src, /datum/extension/tool, list(TOOL_CAUTERY = TOOL_QUALITY_BAD)) + update_icon() + if(istype(loc, /obj/structure/wall_sconce)) + loc.update_icon() + +/obj/item/flame/Destroy() + snuff_out(null, TRUE) + return ..() + +/obj/item/flame/proc/get_available_scents() + return null + +/obj/item/flame/proc/get_sconce_overlay() + return null + +/obj/item/flame/get_tool_quality(archetype) + return (!lit && archetype == TOOL_CAUTERY) ? TOOL_QUALITY_NONE : ..() + +/obj/item/flame/proc/has_fuel(amount) + return get_fuel() >= amount + +/obj/item/flame/proc/light(mob/user, no_message) + + // TODO: check for oxidizer + if(lit || !has_fuel(_fuel_spend_amt)) + return FALSE + lit = TRUE + if(!can_store_lit) + obj_flags |= OBJ_FLAG_NO_STORAGE + atom_damage_type = BURN + update_attack_force() + + update_icon() + if(istype(loc, /obj/structure/wall_sconce)) + loc.update_icon() + + if(!no_message && user) + user.visible_message( + SPAN_NOTICE("\The [user] lights \the [src]."), + SPAN_NOTICE("You light \the [src].") + ) + if(!is_processing) + START_PROCESSING(SSobj, src) + if(scent) + set_extension(src, scent.scent_datum) + if(lit_light_range && lit_light_power) + set_light(lit_light_range, lit_light_power, lit_light_color) + + return TRUE + +/obj/item/flame/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(!istype(target) || user.check_intent(I_FLAG_HARM) || !lit || user.get_target_zone() != BP_MOUTH) + return ..() + + var/obj/item/clothing/mask/smokable/cigarette/cig = target.get_equipped_item(slot_wear_mask_str) + if(istype(cig)) + if(target == user) + cig.attackby(src, user) + else + cig.light(SPAN_NOTICE("\The [user] holds \the [src] out for \the [target], and lights \the [cig].")) + return TRUE + + return ..() + +/obj/item/flame/proc/snuff_out(mob/user, no_message = FALSE) + if(!lit) + return FALSE + lit = FALSE + if(!can_store_lit && !(initial(obj_flags) & OBJ_FLAG_NO_STORAGE)) // only disable it if it wasn't already set + obj_flags &= ~OBJ_FLAG_NO_STORAGE + atom_damage_type = BRUTE + update_attack_force() + + update_icon() + if(ismob(loc)) // not very robust for things like accessories... + update_held_icon() + update_clothing_icon() + if(istype(loc, /obj/structure/wall_sconce)) + loc.update_icon() + + set_light(0) + if(scent) + remove_extension(src, /datum/extension/scent) + if(is_processing) + STOP_PROCESSING(SSobj, src) + if(!no_message) + visible_message(SPAN_NOTICE("\The [src] goes out.")) + return TRUE + +/obj/item/flame/attack_self(mob/user) + + if(!lit && can_manually_light) + if(has_fuel(_fuel_spend_amt)) + light(user) + else + to_chat(user, SPAN_WARNING("\The [src] won't ignite. It must be out of fuel.")) + return TRUE + + if(lit && can_manually_extinguish) + snuff_out(user) + return TRUE + + return ..() + +/obj/item/flame/fluid_act(var/datum/reagents/fluids) + ..() + + if(QDELETED(src) || !REAGENT_TOTAL_VOLUME(fluids) || !lit) + return + + var/turf/location = get_turf(src) + if(location) + location.hotspot_expose(700, 5) // Potentially set fire to fuel etc. + if(QDELETED(src) || !REAGENT_TOTAL_VOLUME(fluids)) + return + + if(waterproof) + return + + if(REAGENT_TOTAL_VOLUME(fluids) >= FLUID_PUDDLE) + snuff_out(no_message = TRUE) + +/obj/item/flame/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + . = ..() + if(!QDELETED(src) && !can_manually_light) + light(null, TRUE) + +/obj/item/flame/get_heat() + return max(..(), lit ? lit_heat : 0) + +/obj/item/flame/can_puncture() + return lit + +/obj/item/flame/isflamesource() + return lit + +/obj/item/flame/proc/get_fuel() + return _fuel + +/obj/item/flame/proc/expend_fuel(amount) + _fuel = max(0, get_fuel()-amount) + return has_fuel(_fuel_spend_amt) + +/obj/item/flame/resolve_attackby(var/atom/A, mob/user) + . = ..() + if(istype(A, /obj/item/flame) && lit) + var/obj/item/flame/other = A + if(!other.can_manually_light) + other.light(user) + +/obj/item/flame/attackby(obj/item/used_item, mob/user) + if(!user.check_intent(I_FLAG_HARM) && !can_manually_light && (used_item.isflamesource() || used_item.get_heat() > T100C)) + light(user) + return TRUE + return ..() + +/obj/item/flame/Process() + if((!waterproof && submerged()) || !expend_fuel(_fuel_spend_amt)) + snuff_out() + return PROCESS_KILL + update_icon() + if(loc) + loc.ignite_fire() + var/turf/my_turf = get_turf(src) + if(my_turf) + my_turf.hotspot_expose(get_heat(), w_class) + +/obj/item/flame/dropped(var/mob/user) + //If dropped, put ourselves out + //not before lighting up the turf we land on, though. + if(lit && extinguish_on_dropped) + var/turf/location = loc + if(istype(location)) + location.hotspot_expose(700, 5) + snuff_out() + return ..() + +/obj/item/flame/spark_act(obj/effect/sparks/sparks) + if(!can_manually_light) + light(null, no_message = TRUE) diff --git a/code/game/objects/items/flame/flame_candle.dm b/code/game/objects/items/flame/flame_candle.dm new file mode 100644 index 000000000000..2c5d3b105709 --- /dev/null +++ b/code/game/objects/items/flame/flame_candle.dm @@ -0,0 +1,143 @@ +/obj/item/flame/candle + name = "candle" + desc = "A small pillar candle. Its specially-formulated fuel-oxidizer wax mixture allows continued combustion in airless environments." + icon = 'icons/obj/items/flame/candle.dmi' + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/wax + material_alteration = MAT_FLAG_ALTERATION_COLOR + lit_light_range = 2 + _fuel = null + sconce_can_hold = TRUE + extinguish_on_dropped = FALSE + +// This is mostly just to change the scifi desc set above. +/obj/item/flame/candle/handmade + desc = "A slender wax candle with a cotton wick." + +/obj/item/flame/candle/spent + _fuel = 0 + +/obj/item/flame/candle/infinite/get_fuel() + return 10 + +/obj/item/flame/candle/infinite/has_fuel(amount) + return TRUE + +/obj/item/flame/candle/infinite/expend_fuel(amount) + return TRUE + +/obj/item/flame/candle/infinite/red + paint_color = COLOR_RED + +/obj/item/flame/candle/infinite/white + paint_color = COLOR_WHITE + +/obj/item/flame/candle/red + paint_color = COLOR_RED + +/obj/item/flame/candle/white + paint_color = COLOR_WHITE + +/obj/item/flame/candle/black + paint_color = COLOR_GRAY15 + +/obj/item/flame/candle/Initialize() + + // Enough for 27-33 minutes. 30 minutes on average, adjusted for subsystem tickrate. + if(isnull(_fuel)) + _fuel = round(rand(27 MINUTES, 33 MINUTES) / SSobj.wait) + + var/list/available_colors = get_available_colors() + if(LAZYLEN(available_colors)) + set_color(pick(available_colors)) + + . = ..() + +/obj/item/flame/candle/get_sconce_overlay() + . = list(overlay_image(icon, "[icon_state]-sconce", color = color, flags = RESET_COLOR)) + if(lit) + . += overlay_image(icon, "[icon_state]-sconce-lit", color = COLOR_WHITE, flags = RESET_COLOR) + +/obj/item/flame/candle/on_update_icon() + + ..() + + var/remaining_fuel = get_fuel() + icon_state = get_world_inventory_state() + switch(remaining_fuel) + if(1500 to INFINITY) + icon_state = "[icon_state]1" + if(800 to 1500) + icon_state = "[icon_state]2" + if(1 to 800) + icon_state = "[icon_state]3" + else + icon_state = "[icon_state]4" + + if(lit && remaining_fuel > 0) + // TODO: emissives + add_overlay(overlay_image(icon, "[icon_state]_lit", flags = RESET_COLOR)) + + if(istype(loc, /obj/item/candelabra)) + loc.queue_icon_update() + +/obj/item/flame/candle/proc/get_available_colors() + return null + +/obj/item/flame/candle/random/get_available_colors() + var/static/list/available_colours = list( + COLOR_WHITE, + COLOR_DARK_GRAY, + COLOR_RED, + COLOR_ORANGE, + COLOR_YELLOW, + COLOR_GREEN, + COLOR_BLUE, + COLOR_INDIGO, + COLOR_VIOLET + ) + return available_colours + +/obj/item/flame/candle/get_available_scents() + return null + +/obj/item/flame/candle/set_dir(ndir) + if(istype(loc, /obj/item/candelabra)) + ndir = SOUTH + . = ..() + +/obj/item/flame/candle/scented + name = "scented candle" + desc = "A candle which releases pleasant-smelling oils into the air when burned." + +/obj/item/flame/candle/scented/get_available_scents() + var/static/list/available_scents = list( + /decl/scent_type/rose, + /decl/scent_type/cinnamon, + /decl/scent_type/vanilla, + /decl/scent_type/seabreeze, + /decl/scent_type/lavender + ) + return available_scents + +/obj/item/flame/candle/scented/incense + name = "incense cone" + desc = "An incense cone. It produces fragrant smoke when burned." + icon = 'icons/obj/items/flame/incense.dmi' + sconce_can_hold = FALSE + +/obj/item/flame/candle/scented/incense/get_available_scents() + var/static/list/available_scents = list( + /decl/scent_type/rose, + /decl/scent_type/citrus, + /decl/scent_type/sage, + /decl/scent_type/frankincense, + /decl/scent_type/mint, + /decl/scent_type/champa, + /decl/scent_type/lavender, + /decl/scent_type/sandalwood + ) + return available_scents + +/obj/item/flame/candle/scented/incense/get_available_colors() + return null diff --git a/code/game/objects/items/flame/flame_fuelled.dm b/code/game/objects/items/flame/flame_fuelled.dm new file mode 100644 index 000000000000..f956496fca12 --- /dev/null +++ b/code/game/objects/items/flame/flame_fuelled.dm @@ -0,0 +1,98 @@ +/obj/item/flame/fuelled + + abstract_type = /obj/item/flame/fuelled + _fuel_spend_amt = 0.05 + can_manually_light = TRUE + extinguish_on_dropped = FALSE + watertight = TRUE + chem_volume = 5 + + var/tmp/start_fuelled = FALSE + + /// TODO: make this calculate a fuel amount via accelerant value or some other check. + /// Reagent type to burn as fuel. If null, will use the map default. + var/fuel_type + +/obj/item/flame/fuelled/Initialize() + if(isnull(fuel_type)) + fuel_type = global.using_map.default_liquid_fuel_type + . = ..() + +// Boilerplate from /obj/item/chems/glass. TODO generalize to a lower level. +/obj/item/flame/fuelled/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(get_attack_force() && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.check_intent(I_FLAG_HARM)) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) && !QDELETED(target)) + target.visible_message(SPAN_DANGER("Some of the contents of \the [src] splash onto \the [target].")) + reagents.splash(target, REAGENT_TOTAL_VOLUME(reagents)) + return TRUE + return FALSE + +/obj/item/flame/fuelled/afterattack(obj/target, mob/user, proximity) + if(!ATOM_IS_OPEN_CONTAINER(src) || !proximity) //Is the container open & are they next to whatever they're clicking? + return FALSE //If not, do nothing. + if(target?.storage) + return TRUE + if(!lit && standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser? + playsound(src.loc, 'sound/effects/refill.ogg', 50, TRUE, -6) + return TRUE + if(standard_pour_into(user, target)) //Pouring into another beaker? + return TRUE + if(handle_eaten_by_mob(user, target) != EATEN_INVALID) + return TRUE + if(REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_NOTICE("You splash a small amount of the contents of \the [src] onto \the [target].")) + reagents.splash(target, min(REAGENT_TOTAL_VOLUME(reagents), 5)) + return TRUE + . = ..() + +// End boilerplate. + +/obj/item/flame/fuelled/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1 && user) + + var/decl/material/fuel_reagent = GET_DECL(fuel_type) + if(fuel_reagent) + . += SPAN_NOTICE("\The [src] is designed to burn [fuel_reagent.liquid_name].") + + var/max_vol = REAGENT_MAXIMUM_VOLUME(reagents) + if(max_vol) + switch(REAGENT_TOTAL_VOLUME(reagents) / max_vol) + if(0 to 0.1) + . += SPAN_WARNING("\The [src] is nearly empty.") + if(0.1 to 0.25) + . += SPAN_NOTICE("\The [src] is one-quarter full.") + if(0.25 to 0.5) + . += SPAN_NOTICE("\The [src] is half full.") + if(0.5 to 0.75) + . += SPAN_NOTICE("\The [src] is three-quarters full.") + else + . += SPAN_NOTICE("\The [src] is full.") + +/obj/item/flame/fuelled/get_fuel() + return REAGENT_VOLUME(reagents, fuel_type) + +/obj/item/flame/fuelled/expend_fuel(amount) + if(has_fuel(amount)) + reagents.remove_reagent(fuel_type, amount) + var/decl/material/fuel = GET_DECL(fuel_type) + if(isatom(loc)) + var/list/waste = fuel.get_burn_products(amount, lit_heat) + if(LAZYLEN(waste)) + loc.take_waste_burn_products(waste, lit_heat) + return TRUE + return FALSE + +/obj/item/flame/fuelled/populate_reagents() + if(start_fuelled && fuel_type) + var/max_vol = REAGENT_MAXIMUM_VOLUME(reagents) + if(max_vol) + add_to_reagents(fuel_type, max_vol) + +/obj/item/flame/fuelled/Process() + . = ..() + if(lit && prob(10) && REAGENT_VOLUME(reagents, fuel_type) < 1) + visible_message(SPAN_WARNING("\The [src]'s flame flickers.")) + set_light(0) + addtimer(CALLBACK(src, TYPE_PROC_REF(.atom, set_light), 2), 4) diff --git a/code/game/objects/items/flame/flame_fuelled_lantern.dm b/code/game/objects/items/flame/flame_fuelled_lantern.dm new file mode 100644 index 000000000000..31504a3c324c --- /dev/null +++ b/code/game/objects/items/flame/flame_fuelled_lantern.dm @@ -0,0 +1,39 @@ +/obj/item/flame/fuelled/lantern + name = "oil lantern" + desc = "An unwieldy oil lantern." + icon = 'icons/obj/items/flame/lantern.dmi' + _base_attack_force = 10 + attack_verb = list ("bludgeoned", "bashed", "whack") + w_class = ITEM_SIZE_NORMAL + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + lit_light_power = 0.7 + lit_light_range = 6 + chem_volume = 60 + _fuel_spend_amt = (1 / 60) // a full lantern should last an hour + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/metal/copper + color = /decl/material/solid/metal/copper::color + can_manually_light = FALSE + sconce_can_hold = TRUE + can_store_lit = TRUE + +/obj/item/flame/fuelled/lantern/get_sconce_overlay() + . = list(overlay_image(icon, "[icon_state]-sconce", color = color, flags = RESET_COLOR)) + if(lit) + . += overlay_image(icon, "[icon_state]-sconce-lit", color = lit_light_color, flags = RESET_COLOR) + +/obj/item/flame/fuelled/lantern/filled + start_fuelled = TRUE + +/obj/item/flame/fuelled/lantern/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(lit) + add_overlay(overlay_image(icon, "[icon_state]-over", lit_light_color, flags = RESET_COLOR)) + +/obj/item/flame/fuelled/lantern/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && lit && (slot == slot_belt_str || (slot in global.all_hand_slots))) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-over", lit_light_color, flags = RESET_COLOR) + return ..() diff --git a/code/game/objects/items/flame/flame_fuelled_lighter.dm b/code/game/objects/items/flame/flame_fuelled_lighter.dm new file mode 100644 index 000000000000..2e1e6903bc2a --- /dev/null +++ b/code/game/objects/items/flame/flame_fuelled_lighter.dm @@ -0,0 +1,94 @@ +/obj/item/flame/fuelled/lighter + name = "lighter" + desc = "A cheap-as-free lighter." + icon = 'icons/obj/items/flame/lighter.dmi' + slot_flags = SLOT_LOWER_BODY + attack_verb = list("burnt", "singed") + material = /decl/material/solid/organic/plastic + start_fuelled = TRUE + obj_flags = OBJ_FLAG_CONDUCTIBLE + lit_heat = 1500 + lit_light_range = 2 + lit_light_color = COLOR_PALE_ORANGE + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT + ) + +/obj/item/flame/fuelled/lighter/light(mob/user, no_message) + if(submerged()) + to_chat(user, SPAN_WARNING("You cannot light \the [src] underwater.")) + return FALSE + . = ..() + if(. && user) + light_effects(user) + +/obj/item/flame/fuelled/lighter/proc/light_effects(mob/living/user) + if(prob(95)) + user.visible_message(SPAN_NOTICE("After a few attempts, [user] manages to light \the [src].")) + else + to_chat(user, SPAN_DANGER("You burn yourself while lighting the lighter.")) + var/hand_tag = user.get_held_slot_for_item(src) + if(hand_tag) + user.apply_damage(2, BURN, hand_tag) + user.visible_message(SPAN_NOTICE("After a few attempts, \the [user] manages to light \the [src], burning their finger in the process.")) + playsound(src.loc, "light_bic", 100, 1, -4) + +/obj/item/flame/fuelled/lighter/snuff_out(mob/user, no_message = FALSE) + if(!no_message && user) + no_message = TRUE + . = ..() + if(. && user) + shutoff_effects(user) + +/obj/item/flame/fuelled/lighter/proc/shutoff_effects(mob/user) + user.visible_message(SPAN_NOTICE("\The [user] quietly shuts off \the [src].")) + +/obj/item/flame/fuelled/lighter/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(lit) + add_overlay(overlay_image(icon, "[icon_state]_flame", flags=RESET_COLOR)) + else + add_overlay(overlay_image(icon, "[icon_state]_striker", flags=RESET_COLOR)) + +/obj/item/flame/fuelled/lighter/red + color = COLOR_RED + name = "red lighter" + +/obj/item/flame/fuelled/lighter/yellow + color = COLOR_YELLOW + name = "yellow lighter" + +/obj/item/flame/fuelled/lighter/cyan + color = COLOR_CYAN + name = "cyan lighter" + +/obj/item/flame/fuelled/lighter/green + color = COLOR_GREEN + name = "green lighter" + +/obj/item/flame/fuelled/lighter/pink + color = COLOR_PINK + name = "pink lighter" + +/obj/item/flame/fuelled/lighter/random + var/static/list/available_colors = list( + COLOR_WHITE, + COLOR_BLUE_GRAY, + COLOR_GREEN_GRAY, + COLOR_BOTTLE_GREEN, + COLOR_DARK_GRAY, + COLOR_RED_GRAY, + COLOR_GUNMETAL, + COLOR_RED, + COLOR_YELLOW, + COLOR_CYAN, + COLOR_GREEN, + COLOR_VIOLET, + COLOR_NAVY_BLUE, + COLOR_PINK + ) + +/obj/item/flame/fuelled/lighter/random/Initialize(ml, material_key) + . = ..() + set_color(pick(available_colors)) diff --git a/code/game/objects/items/flame/flame_fuelled_lighter_zippo.dm b/code/game/objects/items/flame/flame_fuelled_lighter_zippo.dm new file mode 100644 index 000000000000..399bb5063b2d --- /dev/null +++ b/code/game/objects/items/flame/flame_fuelled_lighter_zippo.dm @@ -0,0 +1,74 @@ +/obj/item/flame/fuelled/lighter/zippo + name = "zippo lighter" + desc = "It's a zippo-styled lighter, using a replaceable flint in a fetching steel case. It makes a clicking sound that everyone loves." + icon = 'icons/obj/items/flame/zippo.dmi' + chem_volume = 10 + material = /decl/material/solid/metal/stainlesssteel + +/obj/item/flame/fuelled/lighter/zippo/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_offset = FALSE) + if(overlay && lit && (slot in global.all_hand_slots)) + overlay.icon_state = "[overlay.icon_state]_open" + return ..() + +/obj/item/flame/fuelled/lighter/zippo/on_update_icon() + if(!lit) + icon_state = get_world_inventory_state() + cut_overlays() + return + . = ..() + icon_state = "[icon_state]_open" + +/obj/item/flame/fuelled/lighter/zippo/light_effects(mob/user) + user.visible_message(SPAN_ROSE("Without even breaking stride, \the [user] flips open and lights \the [src] in one smooth movement.")) + playsound(src.loc, 'sound/items/zippo_open.ogg', 100, 1, -4) + +/obj/item/flame/fuelled/lighter/zippo/shutoff_effects(mob/user) + user.visible_message(SPAN_ROSE("You hear a quiet click, as [user] shuts off \the [src] without even looking at what they're doing.")) + playsound(src.loc, 'sound/items/zippo_close.ogg', 100, 1, -4) + +/obj/item/flame/fuelled/lighter/zippo/black + color = COLOR_DARK_GRAY + name = "black zippo" + +/obj/item/flame/fuelled/lighter/zippo/gunmetal + color = COLOR_GUNMETAL + name = "gunmetal zippo" + +/obj/item/flame/fuelled/lighter/zippo/brass + name = "brass zippo" + material = /decl/material/solid/metal/brass + material_alteration = MAT_FLAG_ALTERATION_COLOR + +/obj/item/flame/fuelled/lighter/zippo/bronze + name = "bronze zippo" + material = /decl/material/solid/metal/bronze + material_alteration = MAT_FLAG_ALTERATION_COLOR + +/obj/item/flame/fuelled/lighter/zippo/pink + color = COLOR_PINK + name = "pink zippo" + +//Spawn using the colour list in the master type +/obj/item/flame/fuelled/lighter/zippo/random + var/static/list/available_materials = list( + /decl/material/solid/metal/brass, + /decl/material/solid/metal/bronze, + /decl/material/solid/metal/blackbronze, + /decl/material/solid/metal/stainlesssteel = list(null, COLOR_WHITE, COLOR_DARK_GRAY, COLOR_GUNMETAL), //null color is the natural material color + ) + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + +/obj/item/flame/fuelled/lighter/zippo/random/Initialize(ml, material_key) + var/picked_mat = pick(available_materials) + var/picked_color + if(length(available_materials[picked_mat])) + var/list/available = available_materials[picked_mat] + picked_color = pick(available) + log_debug("Picked color : '[picked_color]' out of [length(available)]") + if(picked_color) + material_alteration &= ~MAT_FLAG_ALTERATION_COLOR + + . = ..(ml, picked_mat) + + if(picked_color) + set_color(picked_color) diff --git a/code/game/objects/items/flame/flame_matches.dm b/code/game/objects/items/flame/flame_matches.dm new file mode 100644 index 000000000000..41300c9d1e0b --- /dev/null +++ b/code/game/objects/items/flame/flame_matches.dm @@ -0,0 +1,40 @@ +/obj/item/flame/match + name = "match" + desc = "A simple match stick, used for lighting fine smokables." + icon = 'icons/obj/items/flame/match.dmi' + obj_flags = OBJ_FLAG_HOLLOW // so that it's not super overpriced compared to lighters + slot_flags = SLOT_EARS + attack_verb = list("burnt", "singed") + randpixel = 10 + _fuel = 5 + _base_attack_force = 1 + var/burnt = FALSE + +/obj/item/flame/match/Initialize() + . = ..() + set_color(null) // clear our scent color + +/obj/item/flame/match/get_available_scents() + var/static/list/available_scents = list( + /decl/scent_type/woodsmoke + ) + return available_scents + +/obj/item/flame/match/light(mob/user, no_message) + . = !burnt && ..() + +/obj/item/flame/match/snuff_out(mob/user, no_message = FALSE) + . = ..() + if(. && !burnt) + _fuel = 0 + burnt = TRUE + name = "burnt match" + desc = "A match. This one has seen better days." + update_icon() + +/obj/item/flame/match/on_update_icon() + . = ..() + if(burnt) + icon_state = "[get_world_inventory_state()]_burnt" + else if(lit) + icon_state = "[get_world_inventory_state()]_lit" diff --git a/code/game/objects/items/flame/flame_torch.dm b/code/game/objects/items/flame/flame_torch.dm new file mode 100644 index 000000000000..0ad60d0d86f7 --- /dev/null +++ b/code/game/objects/items/flame/flame_torch.dm @@ -0,0 +1,91 @@ +/obj/item/flame/torch + name = "torch" + desc = "A short length of wood topped by a bulbous mass of flammable fuel." + icon = 'icons/obj/items/flame/torch.dmi' + attack_verb = list("burnt", "singed") + randpixel = 10 + _fuel = null + lit_light_power = 0.7 + lit_light_range = 3 + extinguish_on_dropped = FALSE + sconce_can_hold = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + var/head_material = /decl/material/solid/organic/cloth + var/burnt = FALSE + +/obj/item/flame/torch/get_available_scents() + var/static/list/available_scents = list( + /decl/scent_type/woodsmoke + ) + return available_scents + +/obj/item/flame/torch/light(mob/user, no_message) + if(REAGENT_TOTAL_VOLUME(coating) && coating.get_accelerant_value() < FUEL_VALUE_NONE) + to_chat(user, SPAN_WARNING("You cannot light \the [src] while it is wet!")) + return FALSE + if(burnt) + to_chat(user, SPAN_WARNING("\The [src] is burnt up.")) + return FALSE + return ..() + +/obj/item/flame/torch/Initialize(var/ml, var/material_key, var/_head_material) + . = ..() + set_color(null) // clear our scent color. TODO: allow flame items to disable scent color setting in the first place + + if(_head_material) + head_material = _head_material + + var/decl/material/head_mat = GET_DECL(head_material) + if(!head_mat || head_mat.accelerant_value <= 0) + head_material = /decl/material/solid/organic/cloth + head_mat = GET_DECL(head_material) + + if(isnull(_fuel)) + _fuel = round(45 MINUTES / SSobj.wait) + if(head_mat) + _fuel = round(_fuel * (1 + head_mat.accelerant_value)) + + update_icon() + +/obj/item/flame/torch/snuff_out(mob/user, no_message = FALSE) + . = ..() + if(. && _fuel <= 0 && !burnt) + burnt = TRUE + name = "burnt torch" + desc = "A torch. This one has seen better days." + update_icon() + +/obj/item/flame/torch/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + if(head_material) + var/decl/material/head_mat = GET_DECL(head_material) + if(burnt) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-burnt", head_mat.color, flags = RESET_COLOR) + else + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-head", head_mat.color, flags = RESET_COLOR) + if(lit) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-lit", flags = RESET_COLOR) + return ..() + +/obj/item/flame/torch/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(head_material) + var/decl/material/head_mat = GET_DECL(head_material) + if(burnt) + add_overlay(overlay_image(icon, "[icon_state]-burnt", head_mat.color, flags = RESET_COLOR|KEEP_APART)) + else + add_overlay(overlay_image(icon, "[icon_state]-head", head_mat.color, flags = RESET_COLOR|KEEP_APART)) + if(lit) + add_overlay(overlay_image(icon, "[icon_state]-lit", flags = RESET_COLOR|KEEP_APART)) + +/obj/item/flame/torch/get_sconce_overlay() + . = list(overlay_image(icon, "[icon_state]-sconce", color = color, flags = RESET_COLOR)) + if(head_material) + var/decl/material/head_mat = GET_DECL(head_material) + if(burnt) + . += overlay_image(icon, "[icon_state]-sconce-burnt", head_mat.color, flags = RESET_COLOR) + else + . += overlay_image(icon, "[icon_state]-sconce-head", head_mat.color, flags = RESET_COLOR) + if(lit) + . += overlay_image(icon, "[icon_state]-sconce-lit", color = lit_light_color, flags = RESET_COLOR) diff --git a/code/game/objects/items/flashlights/_flashlight.dm b/code/game/objects/items/flashlights/_flashlight.dm new file mode 100644 index 000000000000..17f4b6655d97 --- /dev/null +++ b/code/game/objects/items/flashlights/_flashlight.dm @@ -0,0 +1,185 @@ +#define FLASHLIGHT_ALWAYS_ON 1 +#define FLASHLIGHT_SINGLE_USE 2 + +/obj/item/flashlight + name = "flashlight" + desc = "A hand-held emergency light." + icon = 'icons/obj/lighting/flashlight.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + action_button_name = "Toggle Flashlight" + light_wedge = LIGHT_WIDE + var/on = FALSE + var/activation_sound = 'sound/effects/flashlight.ogg' + var/flashlight_range = 4 // range of light when on, can be negative + var/flashlight_power // brightness of light when on + var/flashlight_flags = 0 // FLASHLIGHT_ bitflags + var/spawn_dir // a way for mappers to force which way a flashlight faces upon spawning + var/offset_on_overlay_x = 0 + var/offset_on_overlay_y = 0 + +/obj/item/flashlight/Initialize() + . = ..() + set_flashlight() + update_icon() + update_held_icon() + +/obj/item/flashlight/proc/get_emissive_overlay_color() + return COLOR_WHITE // Icons are usually coloured already. + +/obj/item/flashlight/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(on) + icon_state = "[icon_state]-on" + var/emissive_state = "[icon_state]-over" + if(check_state_in_icon(emissive_state, icon)) + var/image/I = mutable_appearance(icon, emissive_state, get_emissive_overlay_color()) //emissive_overlay(icon, emissive_state) // Uncomment when emissive clipping is in. + I.appearance_flags |= RESET_COLOR + I.pixel_x = offset_on_overlay_x + I.pixel_y = offset_on_overlay_y + I.pixel_w = 0 + I.pixel_z = 0 + I.plane = FLOAT_PLANE + I.layer = FLOAT_LAYER + add_overlay(I) + +/obj/item/flashlight/attack_self(mob/user) + if(user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) + if (flashlight_flags & FLASHLIGHT_ALWAYS_ON) + to_chat(user, SPAN_WARNING("You cannot toggle \the [src].")) + return TRUE + if ((flashlight_flags & FLASHLIGHT_SINGLE_USE) && on) + to_chat(user, SPAN_WARNING("\The [src] is already on.")) + return TRUE + on = !on + if(on && activation_sound) + playsound(get_turf(src), activation_sound, 75, 1) + set_flashlight(set_direction = FALSE) + update_icon() + user.update_action_buttons() + return TRUE + return ..() + +/obj/item/flashlight/proc/set_flashlight(var/set_direction = TRUE) + if(light_wedge && set_direction) + set_dir(spawn_dir || pick(global.cardinal)) + if(on) + set_light(flashlight_range, flashlight_power, light_color) + else + set_light(0) + +/obj/item/flashlight/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(light_wedge && isturf(loc)) + . += FONT_SMALL(SPAN_NOTICE("\The [src] is facing [dir2text(dir)].")) + +/obj/item/flashlight/dropped(mob/user) + . = ..() + if(light_wedge) + set_dir(user.dir) + update_light() + update_icon() + +/obj/item/flashlight/equipped(mob/user, slot) + . = ..() + update_icon() + +/obj/item/flashlight/throw_at() + . = ..() + if(light_wedge) + set_dir(pick(global.cardinal)) + update_light() + +/obj/item/flashlight/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(on && user.get_target_zone() == BP_EYES && target.should_have_limb(BP_HEAD)) + + add_fingerprint(user) + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) //too dumb to use flashlight properly + return ..() //just hit them in the head + + for(var/slot in global.standard_headgear_slots) + var/obj/item/clothing/C = target.get_equipped_item(slot) + if(istype(C) && (C.body_parts_covered & SLOT_EYES)) + to_chat(user, SPAN_WARNING("You're going to need to remove [C] first.")) + return TRUE + + var/obj/item/organ/vision + var/decl/bodytype/root_bodytype = target.get_bodytype() + var/vision_organ_tag = target.get_vision_organ_tag() + if(!vision_organ_tag || !target.should_have_organ(vision_organ_tag)) + to_chat(user, SPAN_WARNING("You can't find anything on \the [target] to direct \the [src] into!")) + return TRUE + + vision = GET_INTERNAL_ORGAN(target, vision_organ_tag) + if(!vision) + vision = root_bodytype.has_organ[vision_organ_tag] + var/decl/pronouns/pronouns = target.get_pronouns() + to_chat(user, SPAN_WARNING("\The [target] is missing [pronouns.his] [initial(vision.name)]!")) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] directs [src] into [target]'s [vision.name]."), + SPAN_NOTICE("You direct [src] into [target]'s [vision.name].") + ) + inspect_vision(vision, user) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively + target.flash_eyes() + return TRUE + + return ..() + +/obj/item/flashlight/proc/inspect_vision(obj/item/organ/internal/vision, mob/living/user) + var/mob/living/human/H = vision.owner + + if(H == user) //can't look into your own eyes buster + return + + if(istype(vision) && !BP_IS_PROSTHETIC(vision)) + + if(vision.owner.stat == DEAD || H.is_blind()) //mob is dead or fully blind + to_chat(user, SPAN_WARNING("\The [H]'s pupils do not react to the light!")) + return + if(H.has_genetic_condition(GENE_COND_XRAY)) + to_chat(user, SPAN_NOTICE("\The [H]'s pupils give an eerie glow!")) + if(vision.get_organ_damage()) + to_chat(user, SPAN_WARNING("There's visible damage to [H]'s [vision.name]!")) + else if(HAS_STATUS(H, STAT_BLURRY)) + to_chat(user, SPAN_NOTICE("\The [H]'s pupils react slower than normally.")) + if(H.get_damage(BRAIN) > 15) + to_chat(user, SPAN_NOTICE("There's visible lag between left and right pupils' reactions.")) + + var/static/list/pinpoint = list( + /decl/material/liquid/painkillers/strong = 5, + /decl/material/liquid/amphetamines = 1 + ) + var/static/list/dilating = list( + /decl/material/liquid/psychoactives = 5, + /decl/material/liquid/hallucinogenics = 1, + /decl/material/liquid/adrenaline = 1 + ) + + var/datum/reagents/ingested = H.get_ingested_reagents() + if(H.reagents.has_any_reagent(pinpoint) || ingested?.has_any_reagent(pinpoint)) + to_chat(user, SPAN_NOTICE("\The [H]'s pupils are already pinpoint and cannot narrow any more.")) + else if(H.shock_stage >= 30 || H.reagents.has_any_reagent(dilating) || ingested?.has_any_reagent(dilating)) + to_chat(user, SPAN_NOTICE("\The [H]'s pupils narrow slightly, but are still very dilated.")) + else + to_chat(user, SPAN_NOTICE("\The [H]'s pupils narrow.")) + + //if someone wants to implement inspecting robot eyes here would be the place to do it. + +/obj/item/flashlight/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && on) + var/icon_state_on = "[overlay.icon_state]-on" + if(check_state_in_icon(icon_state_on, overlay.icon)) + var/image/I = mutable_appearance(overlay.icon, icon_state_on, get_emissive_overlay_color()) //emissive_overlay(overlay.icon, icon_state_on) // Uncomment when emissive clipping is in. + I.appearance_flags |= RESET_COLOR + overlay.overlays += I + . = ..() diff --git a/code/game/objects/items/flashlights/flare.dm b/code/game/objects/items/flashlights/flare.dm new file mode 100644 index 000000000000..f91985f0ca33 --- /dev/null +++ b/code/game/objects/items/flashlights/flare.dm @@ -0,0 +1,82 @@ +// FLARES + +/obj/item/flashlight/flare + name = "flare" + desc = "A red standard-issue flare. There are instructions on the side reading 'pull cord, make light'." + w_class = ITEM_SIZE_SMALL + light_color = "#e58775" + icon = 'icons/obj/lighting/flare.dmi' + action_button_name = null //just pull it manually, neckbeard. + activation_sound = 'sound/effects/flare.ogg' + flashlight_flags = FLASHLIGHT_SINGLE_USE + flashlight_range = 5 + flashlight_power = 3 + light_wedge = LIGHT_OMNI + offset_on_overlay_x = -8 + + var/fuel = 0 + var/on_damage = 7 + var/produce_heat = 1500 + +/obj/item/flashlight/flare/Initialize() + . = ..() + fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.v + update_icon() + +/obj/item/flashlight/flare/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/flashlight/flare/Process() + if(produce_heat) + var/turf/T = get_turf(src) + if(T) + T.hotspot_expose(produce_heat, 5) + fuel = max(fuel - 1, 0) + if (fuel <= 0) + on = FALSE + if(!on) + update_damage() + set_flashlight() + update_icon() + STOP_PROCESSING(SSobj, src) + +/obj/item/flashlight/flare/attack_self(var/mob/user) + if(fuel <= 0) + to_chat(user,"\The [src] is spent.") + return 0 + + . = ..() + + if(.) + activate(user) + update_damage() + set_flashlight() + update_icon() + START_PROCESSING(SSobj, src) + +/obj/item/flashlight/flare/get_heat() + return on ? 500 : 0 + +/obj/item/flashlight/flare/proc/activate(var/mob/user) + if(istype(user)) + user.visible_message("[user] pulls the cord on \the [src], activating it.", "You pull the cord on \the [src], activating it!") + +/obj/item/flashlight/flare/proc/update_damage() + if(on) + set_base_attack_force(on_damage) + atom_damage_type = BURN + else + set_base_attack_force(get_initial_base_attack_force()) + atom_damage_type = initial(atom_damage_type) + +/obj/item/flashlight/flare/on_update_icon() + var/nofuel = fuel <= 0 + if(nofuel) + on = FALSE + . = ..() + if(nofuel) + icon_state = "[icon_state]-empty" + +/obj/item/flashlight/flare/get_emissive_overlay_color() + return color diff --git a/code/game/objects/items/flashlights/floodlamp.dm b/code/game/objects/items/flashlights/floodlamp.dm new file mode 100644 index 000000000000..c98063000b84 --- /dev/null +++ b/code/game/objects/items/flashlights/floodlamp.dm @@ -0,0 +1,14 @@ +//hand portable floodlights for emergencies. Less bulky than the large ones. But also less light. Unused green variant in the sheet. +/obj/item/flashlight/lamp/floodlamp + name = "flood lamp" + desc = "A portable emergency floodlight with a ultra-bright LED." + icon = 'icons/obj/lighting/floodlamp.dmi' + on = 0 + w_class = ITEM_SIZE_LARGE + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_ROTATABLE + flashlight_power = 1 + flashlight_range = 7 + light_wedge = LIGHT_WIDE + +/obj/item/flashlight/lamp/floodlamp/green + icon = 'icons/obj/lighting/greenfloodlamp.dmi' diff --git a/code/game/objects/items/flashlights/glowstick.dm b/code/game/objects/items/flashlights/glowstick.dm new file mode 100644 index 000000000000..c0f07103a330 --- /dev/null +++ b/code/game/objects/items/flashlights/glowstick.dm @@ -0,0 +1,47 @@ +//Glowsticks +/obj/item/flashlight/flare/glowstick + name = "green glowstick" + desc = "A military-grade glowstick." + w_class = ITEM_SIZE_SMALL + color = "#49f37c" + icon = 'icons/obj/lighting/glowstick.dmi' + randpixel = 12 + produce_heat = 0 + activation_sound = 'sound/effects/glowstick.ogg' + flashlight_range = 3 + flashlight_power = 2 + offset_on_overlay_x = 0 + +/obj/item/flashlight/flare/glowstick/Initialize() + . = ..() + fuel = rand(1600, 2000) + light_color = color + +/obj/item/flashlight/flare/glowstick/activate(var/mob/user) + if(istype(user)) + user.visible_message("[user] cracks and shakes \the [src].", "You crack and shake \the [src], turning it on!") + +/obj/item/flashlight/flare/glowstick/red + name = "red glowstick" + color = "#fc0f29" + +/obj/item/flashlight/flare/glowstick/blue + name = "blue glowstick" + color = "#599dff" + +/obj/item/flashlight/flare/glowstick/orange + name = "orange glowstick" + color = "#fa7c0b" + +/obj/item/flashlight/flare/glowstick/yellow + name = "yellow glowstick" + color = "#fef923" + +/obj/item/flashlight/flare/glowstick/random + name = "glowstick" + desc = "A party-grade glowstick." + color = "#ff00ff" + +/obj/item/flashlight/flare/glowstick/random/Initialize() + set_color(rgb(rand(50,255),rand(50,255),rand(50,255))) + . = ..() diff --git a/code/game/objects/items/flashlights/lamp.dm b/code/game/objects/items/flashlights/lamp.dm new file mode 100644 index 000000000000..512b62f69895 --- /dev/null +++ b/code/game/objects/items/flashlights/lamp.dm @@ -0,0 +1,24 @@ +// the desk lamps are a bit special +/obj/item/flashlight/lamp + name = "desk lamp" + desc = "A desk lamp with an adjustable mount." + icon = 'icons/obj/lighting/lamp.dmi' + w_class = ITEM_SIZE_LARGE + obj_flags = OBJ_FLAG_CONDUCTIBLE + flashlight_range = 5 + light_wedge = LIGHT_OMNI + on = TRUE + +/obj/item/flashlight/lamp/verb/toggle_light() + set name = "Toggle light" + set category = "Object" + set src in oview(1) + if(!usr.stat) + attack_self(usr) + +// green-shaded desk lamp +/obj/item/flashlight/lamp/green + desc = "A classic green-shaded desk lamp." + icon = 'icons/obj/lighting/greenlamp.dmi' + light_color = "#ffc58f" + flashlight_range = 4 diff --git a/code/game/objects/items/flashlights/lavalamp.dm b/code/game/objects/items/flashlights/lavalamp.dm new file mode 100644 index 000000000000..e5d123aa20a9 --- /dev/null +++ b/code/game/objects/items/flashlights/lavalamp.dm @@ -0,0 +1,53 @@ +//Lava Lamps: Because we're already stuck in the 70ies with those fax machines. +/obj/item/flashlight/lamp/lava + name = "lava lamp" + desc = "A kitschy throwback decorative light. Noir Edition." + icon = 'icons/obj/lighting/lavalamp.dmi' + icon_state = "lavalamp" + on = 0 + action_button_name = "Toggle lamp" + flashlight_range = 3 //range of light when on + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/flashlight/lamp/lava/get_emissive_overlay_color() + return light_color + +/obj/item/flashlight/lamp/lava/on_update_icon() + . = ..() + if(!on) // This is handled for lit lamps in the parent call. + var/image/I = emissive_overlay(icon, "[icon_state]-over") + I.color = get_emissive_overlay_color() + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/flashlight/lamp/lava/red + desc = "A kitschy red decorative light." + light_color = COLOR_RED + +/obj/item/flashlight/lamp/lava/blue + desc = "A kitschy blue decorative light" + light_color = COLOR_BLUE + +/obj/item/flashlight/lamp/lava/cyan + desc = "A kitschy cyan decorative light" + light_color = COLOR_CYAN + +/obj/item/flashlight/lamp/lava/green + desc = "A kitschy green decorative light" + light_color = COLOR_GREEN + +/obj/item/flashlight/lamp/lava/orange + desc = "A kitschy orange decorative light" + light_color = COLOR_ORANGE + +/obj/item/flashlight/lamp/lava/purple + desc = "A kitschy purple decorative light" + light_color = COLOR_PURPLE +/obj/item/flashlight/lamp/lava/pink + desc = "A kitschy pink decorative light" + light_color = COLOR_PINK + +/obj/item/flashlight/lamp/lava/yellow + desc = "A kitschy yellow decorative light" + light_color = COLOR_YELLOW diff --git a/code/game/objects/items/flashlights/misc.dm b/code/game/objects/items/flashlights/misc.dm new file mode 100644 index 000000000000..cdd07f77f43b --- /dev/null +++ b/code/game/objects/items/flashlights/misc.dm @@ -0,0 +1,49 @@ +/obj/item/flashlight/upgraded + name = "\improper LED flashlight" + desc = "An energy efficient flashlight." + icon = 'icons/obj/lighting/biglight.dmi' + flashlight_range = 6 + flashlight_power = 3 + +/obj/item/flashlight/flashdark + name = "flashdark" + desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure." + icon = 'icons/obj/lighting/flashdark.dmi' + w_class = ITEM_SIZE_NORMAL + flashlight_range = 8 + flashlight_power = -6 + +/obj/item/flashlight/maglight + name = "maglight" + desc = "A very, very heavy-duty flashlight." + icon = 'icons/obj/lighting/maglight.dmi' + _base_attack_force = 10 + attack_verb = list ("smacked", "thwacked", "thunked") + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + light_wedge = LIGHT_NARROW + +/******************************Lantern*******************************/ +/obj/item/flashlight/lantern + name = "lantern" + desc = "A mining lantern." + icon = 'icons/obj/lighting/lantern.dmi' + _base_attack_force = 10 + attack_verb = list ("bludgeoned", "bashed", "whack") + w_class = ITEM_SIZE_NORMAL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + flashlight_range = 2 + light_wedge = LIGHT_OMNI + light_color = LIGHT_COLOR_FIRE + +/obj/item/flashlight/drone + name = "low-power flashlight" + desc = "A miniature lamp, that might be used by small robots." + icon_state = "penlight" + item_state = "" + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_TINY + flashlight_range = 2 diff --git a/code/game/objects/items/flashlights/party.dm b/code/game/objects/items/flashlights/party.dm new file mode 100644 index 000000000000..31531842f18f --- /dev/null +++ b/code/game/objects/items/flashlights/party.dm @@ -0,0 +1,53 @@ + +/obj/item/flashlight/party + name = "party light" + desc = "An array of LEDs in tons of colors." + icon = 'icons/obj/lighting/partylight.dmi' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE + ) + flashlight_range = 7 + flashlight_power = 1 + light_wedge = LIGHT_OMNI + var/obj/effect/party_light/strobe_effect + +/obj/item/flashlight/party/Destroy() + . = ..() + stop_strobing() + +/obj/item/flashlight/party/set_flashlight(var/set_direction = TRUE) + . = ..() + if(on) + start_strobing() + else + stop_strobing() + +/obj/item/flashlight/party/proc/stop_strobing() + if(strobe_effect) + // Cause the party light effect to stop following this object, and then delete it. + events_repository.unregister(/decl/observ/moved, src, strobe_effect) + update_icon() + QDEL_NULL(strobe_effect) + +/obj/item/flashlight/party/proc/start_strobing() + if(!strobe_effect) + strobe_effect = new(get_turf(src)) + events_repository.register(/decl/observ/moved, src, strobe_effect, TYPE_PROC_REF(/atom/movable, move_to_turf_or_null)) + update_icon() + +/obj/effect/party_light + name = "party light" + desc = "This is probably bad for your eyes." + icon = 'icons/effects/lens_flare.dmi' + icon_state = "party_strobe" + simulated = FALSE + anchored = TRUE + pixel_x = -30 + pixel_y = -4 + layer = ABOVE_LIGHTING_LAYER + plane = ABOVE_LIGHTING_PLANE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE diff --git a/code/game/objects/items/flashlights/penlight.dm b/code/game/objects/items/flashlights/penlight.dm new file mode 100644 index 000000000000..590b68944cdf --- /dev/null +++ b/code/game/objects/items/flashlights/penlight.dm @@ -0,0 +1,13 @@ +/obj/item/flashlight/pen + name = "penlight" + desc = "A pen-sized light, used by medical staff." + icon = 'icons/obj/lighting/penlight.dmi' + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_EARS + w_class = ITEM_SIZE_TINY + flashlight_range = 2 + light_wedge = LIGHT_OMNI + +/obj/item/flashlight/pen/Initialize() + set_extension(src, /datum/extension/tool, list(TOOL_PEN = TOOL_QUALITY_DEFAULT), list(TOOL_PEN = list(TOOL_PROP_COLOR = "black", TOOL_PROP_COLOR_NAME = "black"))) + . = ..() diff --git a/code/game/objects/items/flashlights/slime.dm b/code/game/objects/items/flashlights/slime.dm new file mode 100644 index 000000000000..f460042af3f9 --- /dev/null +++ b/code/game/objects/items/flashlights/slime.dm @@ -0,0 +1,10 @@ +/obj/item/flashlight/slime + name = "glowing slime extract" + gender = PLURAL + desc = "A glowing ball of what appears to be amber." + icon = 'icons/obj/lighting/slime.dmi' + w_class = ITEM_SIZE_SMALL + flashlight_flags = FLASHLIGHT_ALWAYS_ON + flashlight_range = 5 + light_wedge = LIGHT_OMNI + on = TRUE //Bio-luminesence has one setting, on. diff --git a/code/game/objects/items/fleece.dm b/code/game/objects/items/fleece.dm new file mode 100644 index 000000000000..b6f7a4cc2807 --- /dev/null +++ b/code/game/objects/items/fleece.dm @@ -0,0 +1,22 @@ +/obj/item/fleece + name = "fleece" + desc = "The shorn fleece of some animal, ready for spinning." + icon = 'icons/obj/items/fleece.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_HUGE // an entire fleece is quite large in terms of volume + attack_verb = "slapped" + hitsound = 'sound/weapons/towelwhip.ogg' + material = /decl/material/solid/organic/cloth/wool + material_alteration = MAT_FLAG_ALTERATION_COLOR + _base_attack_force = 1 + +/obj/item/fleece/Initialize(ml, material_key, mob/living/donor) + . = ..() + if(donor) + name = "[donor.name]'s fleece" + +/obj/item/fleece/has_textile_fibers() + return TRUE + +/obj/item/fleece/get_matter_amount_modifier() + return 10 // One fleece is 80 threads, which is roughly 8 cloth. diff --git a/code/game/objects/items/glassjar.dm b/code/game/objects/items/glassjar.dm index 76f877551c91..6c6a654fb2fc 100644 --- a/code/game/objects/items/glassjar.dm +++ b/code/game/objects/items/glassjar.dm @@ -5,11 +5,14 @@ icon_state = "jar" w_class = ITEM_SIZE_SMALL material = /decl/material/solid/glass - material_force_multiplier = 0.1 item_flags = ITEM_FLAG_NO_BLUDGEON + obj_flags = OBJ_FLAG_HOLLOW + drop_sound = 'sound/foley/bottledrop1.ogg' + pickup_sound = 'sound/foley/bottlepickup1.ogg' + var/list/accept_mobs = list( /mob/living/simple_animal/lizard, - /mob/living/simple_animal/mouse + /mob/living/simple_animal/passive/mouse ) var/contains = 0 // 0 = nothing, 1 = money, 2 = animal, 3 = spiderling @@ -20,7 +23,7 @@ /obj/item/glass_jar/afterattack(var/atom/A, var/mob/user, var/proximity) if(!proximity || contains) return - if(istype(A, /mob)) + if(ismob(A, /mob)) var/accept = 0 for(var/D in accept_mobs) if(istype(A, D)) @@ -68,21 +71,23 @@ update_icon() return -/obj/item/glass_jar/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/cash)) +/obj/item/glass_jar/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/cash)) if(contains == 0) contains = 1 if(contains != 1) - return - if(!user.unEquip(W, src)) - return - var/obj/item/cash/S = W + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + var/obj/item/cash/S = used_item user.visible_message("[user] puts \the [S] into \the [src].") update_icon() + return TRUE + return ..() /obj/item/glass_jar/on_update_icon() // Also updates name and desc + . = ..() underlays.Cut() - overlays.Cut() switch(contains) if(0) SetName(initial(name)) diff --git a/code/game/objects/items/helping_hands.dm b/code/game/objects/items/helping_hands.dm new file mode 100644 index 000000000000..38b3be5033d4 --- /dev/null +++ b/code/game/objects/items/helping_hands.dm @@ -0,0 +1,49 @@ +/obj/item/helpinghands + name = "back-mounted arms" + desc = "A pair of arms with an included harness worn on the back, controlled by a noninvasive spinal prosthesis." + icon = 'icons/mecha/mech_parts_held.dmi' + icon_state = "light_arms" + material = /decl/material/solid/metal/steel + slot_flags = SLOT_BACK + var/list/slot_types = list( + /datum/inventory_slot/gripper/left_hand/no_organ/helping, + /datum/inventory_slot/gripper/right_hand/no_organ/helping + ) + +/obj/item/helpinghands/proc/add_hands(mob/user) + for (var/gripper_type in slot_types) + user.add_held_item_slot(new gripper_type) + +/obj/item/helpinghands/proc/remove_hands(mob/user) + for (var/datum/inventory_slot/gripper_type as anything in slot_types) + user.remove_held_item_slot(initial(gripper_type.slot_id)) + +/obj/item/helpinghands/equipped(mob/user, slot) + . = ..() + if(!user) + return + switch(slot) + if(slot_back_str) + add_hands(user) + else + remove_hands(user) + +/obj/item/helpinghands/dropped(mob/user) + . = ..() + if(user) + remove_hands(user) + +/datum/inventory_slot/gripper/left_hand/no_organ + requires_organ_tag = null +/datum/inventory_slot/gripper/right_hand/no_organ + requires_organ_tag = null + +/datum/inventory_slot/gripper/left_hand/no_organ/helping + slot_id = "helping_hand_l" + hand_overlay = BP_L_HAND + hand_sort_priority = 4 + +/datum/inventory_slot/gripper/right_hand/no_organ/helping + slot_id = "helping_hand_r" + hand_overlay = BP_R_HAND + hand_sort_priority = 5 \ No newline at end of file diff --git a/code/game/objects/items/holosign_creator.dm b/code/game/objects/items/holosign_creator.dm index ecb8ff26ad09..d2ab067aa6d1 100644 --- a/code/game/objects/items/holosign_creator.dm +++ b/code/game/objects/items/holosign_creator.dm @@ -1,16 +1,14 @@ /obj/item/holosign_creator name = "holographic sign projector" desc = "A handy-dandy holographic projector that displays a janitorial sign." - icon = 'icons/obj/janitor.dmi' - icon_state = "signmaker" - item_state = "electronic" - force = 0 + icon = 'icons/obj/items/holosign_projector.dmi' + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL - throwforce = 0 throw_speed = 3 throw_range = 7 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"engineering":5,"exoticmatter":4,"powerstorage":4}' var/list/signs = list() var/max_signs = 10 @@ -55,8 +53,8 @@ else to_chat(user, "[src] is projecting at max capacity!") -/obj/item/holosign_creator/attack(mob/living/carbon/human/M, mob/user) - return +/obj/item/holosign_creator/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE /obj/item/holosign_creator/attack_self(mob/user) if(signs.len) diff --git a/code/game/objects/items/horseshoe.dm b/code/game/objects/items/horseshoe.dm new file mode 100644 index 000000000000..622dfaf99721 --- /dev/null +++ b/code/game/objects/items/horseshoe.dm @@ -0,0 +1,15 @@ +// Stub for forging. TODO implement shoes on honse. +/obj/item/horseshoe + name = "horseshoe" + desc = "A curved length of metal, usually nailed to a horse's hoof. May bring luck." + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/horseshoe.dmi' + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + material_alteration = MAT_FLAG_ALTERATION_ALL + +/// A horseshoe hung above a door. +/obj/item/horseshoe/hung + anchored = TRUE + randpixel = 0 + layer = ABOVE_HUMAN_LAYER \ No newline at end of file diff --git a/code/game/objects/items/hourglass.dm b/code/game/objects/items/hourglass.dm new file mode 100644 index 000000000000..75b4acd6de5b --- /dev/null +++ b/code/game/objects/items/hourglass.dm @@ -0,0 +1,133 @@ +// I considered just putting this in the fantasy modpack, but +// it's probably better in core code, since it's a nice prop. +/obj/item/hourglass + name = "hourglass" + icon = 'icons/obj/items/hourglass.dmi' + icon_state = "world-preview" + desc = "Sand trickles from one fused dome to another, tracking the inevitable passage of time. What are you doing with your life?" + w_class = ITEM_SIZE_SMALL + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR + material = /decl/material/solid/organic/wood/mahogany + max_health = null // autoset from material, let it be destroyed! + // These two variables cannot be null, currently. If you want to allow that, you need to change a lot of the code. + var/decl/material/glass_material = /decl/material/solid/glass + var/decl/material/sand_material = /decl/material/solid/sand + /// The world.time at which the hourglass was last flipped. Used to determine if sand is currently falling. + var/last_flipped = null + /// How long in deciseconds does it take for the sand to finish falling? + var/sand_duration = 1 MINUTE // TODO: Make this based off of matter somehow, instead of vice versa? This means damaging it and leaking sand would make it run fast... + /// The number of falling sand states to use, [0, X) (including 0 but excluding X). + var/sand_falling_states = 4 + /// This is an internal variable used to prevent unnecessary update_icon calls. + var/tmp/last_sand_state = null + +/obj/item/hourglass/Initialize(ml, material_key, glass_material_key, sand_material_key) + if(!isnull(glass_material_key)) + glass_material = glass_material_key + if(ispath(glass_material)) + glass_material = GET_DECL(glass_material) + if(!isnull(sand_material_key)) + sand_material = sand_material_key + if(ispath(sand_material)) + sand_material = GET_DECL(sand_material) + last_flipped = -sand_duration + . = ..() // Materials should be set when going into create_matter + update_icon() + +/obj/item/hourglass/create_matter() + var/sand_matter = sand_duration / (1 MINUTE) * MATTER_AMOUNT_TRACE // Shorter duration, less sand; higher duration, more sand. + LAZYSET(matter, sand_material.type, sand_matter) + LAZYSET(matter, glass_material.type, MATTER_AMOUNT_REINFORCEMENT) + return ..() // Parent call has to go last so we apply size modifiers properly. + +/obj/item/hourglass/proc/sand_is_falling() + return (world.time - last_flipped) < sand_duration + +/obj/item/hourglass/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 2) + var/sand_string = "not falling" + switch(clamp(world.time - last_flipped, 0, sand_duration) / sand_duration) + if(0) + sand_string = "not falling" + if(0 to 0.25) + sand_string = "almost done falling" + if(0.25 to 0.4) + sand_string = "over halfway done falling" + if(0.4 to 0.6) + sand_string = "about halfway done falling" + if(0.6 to 0.75) + sand_string = "almost halfway done falling" + if(0.75 to 1) + sand_string = "just starting to fall" + . += SPAN_NOTICE("The [sand_material.solid_name] in \the [src] is [sand_string].") + +/obj/item/hourglass/proc/get_sand_state(world_inventory_state) + /// This is a fraction of the sand_duration. + var/sand_progress = (world.time - last_flipped) / sand_duration + switch(sand_progress) + if(0 to 1) + return "sand-falling[floor(sand_progress * sand_falling_states)]-[world_inventory_state]" // 0 to sand_falling_states exclusive. + else + return "sand-[world_inventory_state]" + +/obj/item/hourglass/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + last_sand_state = get_sand_state(icon_state) + // Sand goes before glass + add_overlay(overlay_image(icon, last_sand_state, sand_material.color, RESET_ALPHA|RESET_COLOR)) + // Glass goes over the sand + add_overlay(overlay_image(icon, "glass-[icon_state]", glass_material.color, RESET_ALPHA|RESET_COLOR)) + compile_overlays() // Don't wait for SSoverlays, this is pretty time-sensitive. + +/obj/item/hourglass/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing) + // TODO: held item falling sand states? + overlay.add_overlay(overlay_image(overlay.icon, "sand-[overlay.icon_state]", sand_material.color, RESET_ALPHA | RESET_COLOR)) + overlay.add_overlay(overlay_image(overlay.icon, "glass-[overlay.icon_state]", glass_material.color, RESET_ALPHA | RESET_COLOR)) + return ..() + +/obj/item/hourglass/attack_self(mob/user) + . = ..() + if(.) // Already did something like squash it or empty storage. + return + return flip_hourglass(user) + +/obj/item/hourglass/proc/flip_hourglass(mob/user) + if(user) + // You can't see or hear this from very far. + user.visible_message("\The [user] flips \the [src].", SPAN_NOTICE("You flip \the [src]."), SPAN_NOTICE("You hear falling sand."), range = 2) + // Invert the time elapsed so that it becomes the time remaining. + var/time_elapsed = sand_duration - clamp(world.time - last_flipped, 0, sand_duration) + last_flipped = world.time - time_elapsed + update_icon() + if(!is_processing) + START_PROCESSING(SSobj, src) + return TRUE + +/obj/item/hourglass/Process() + if(!sand_is_falling()) + return PROCESS_KILL + if(get_sand_state(get_world_inventory_state()) == last_sand_state) // No need to do an update yet. + return + update_icon() + +/obj/item/hourglass/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/hourglass/physically_destroyed(skip_qdel) + // This code is adapted from compost bins. + // TODO: Make a helper for 'create or add to scraps'. + var/obj/item/debris/scraps/remains = (locate() in loc) || new(loc) + LAZYINITLIST(remains.matter) + if(matter[sand_material.type]) // Make sure we haven't already lost our sand... somehow? + remains.matter[sand_material.type] += matter[sand_material.type] + UNSETEMPTY(remains.matter) + remains.update_primary_material() + // Now create shards of our glass material. + // At some point in the future this should probably respect matter conservation. + // Right now we just make sure we have any glass left at all. + if(matter[glass_material.type]) + glass_material.place_shards(loc) + return ..() \ No newline at end of file diff --git a/code/game/objects/items/instruments.dm b/code/game/objects/items/instruments.dm index 879b27fb3b91..f75cca75194d 100644 --- a/code/game/objects/items/instruments.dm +++ b/code/game/objects/items/instruments.dm @@ -1,14 +1,17 @@ -/obj/item/instrument - throwforce = 0 - throw_speed = 3 - throw_range = 6 - force = 0 - -/obj/item/instrument/guitar +/obj/item/guitar name = "guitar" - desc = "An antique musical instrument made of wood, originating from Earth. It has six metal strings of different girth and tension. When moved, they vibrate and the waves resonate in the guitar's open body, producing sounds. Obtained notes can be altered by pressing the strings to the neck, affecting the vibration's frequency." + desc = "An antique musical instrument made of wood, originating from Earth. It has six metal strings of different girth and tension. When moved, they vibrate and the waves resonate in the guitar's open body, producing sounds. Obtained notes can be altered by pressing the strings to the neck, affecting the vibration's frequency." icon = 'icons/obj/items/guitar.dmi' - icon_state = "guitar" + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/wood/oak + slot_flags = SLOT_BACK + throw_speed = 3 + throw_range = 6 -/obj/item/instrument/guitar/attack_self(mob/user) - user.visible_message("\The [user] strums [src]!","You strum [src]!") +/obj/item/guitar/attack_self(mob/user) + . = ..() + if(!.) + user.visible_message( + SPAN_NOTICE("\The [user] strums \the [src]!"), + SPAN_NOTICE("You strum \the [src]!")) + return TRUE diff --git a/code/game/objects/items/item_icon_experimental.dm b/code/game/objects/items/item_icon_experimental.dm deleted file mode 100644 index fa97e74e7c71..000000000000 --- a/code/game/objects/items/item_icon_experimental.dm +++ /dev/null @@ -1,98 +0,0 @@ -// This file is an experiment in changing the way item icons are handled. -// Not really expecting it to work out of the box, so we'll see how it goes -// with a handful of specific items. - -// For checking if we have a specific state, for inventory icons and nonhumanoid species. -// Cached cause asking icons is expensive -var/list/icon_state_cache = list() -/proc/check_state_in_icon(var/checkstate, var/checkicon) - var/list/check = global.icon_state_cache[checkicon] - if(!check) - check = list() - for(var/istate in icon_states(checkicon)) - check[istate] = TRUE - global.icon_state_cache[checkicon] = check - . = check[checkstate] - -/obj/item - var/on_mob_use_spritesheets // use spritesheets list for on-mob icon - var/tmp/has_inventory_icon // do not set manually - var/tmp/use_single_icon - -/obj/item/Initialize(ml, material_key) - . = ..() - if(check_state_in_icon(ICON_STATE_INV, icon) || check_state_in_icon(ICON_STATE_WORLD, icon)) - use_single_icon = TRUE - has_inventory_icon = check_state_in_icon(ICON_STATE_INV, icon) - icon_state = ICON_STATE_WORLD - update_icon() - -/obj/item/hud_layerise() - ..() - update_world_inventory_state() - -/obj/item/reset_plane_and_layer() - ..() - update_world_inventory_state() - -/obj/item/proc/update_world_inventory_state() - if(use_single_icon && has_inventory_icon) - var/last_state = icon_state - icon_state = get_world_inventory_state() - if(last_state != icon_state) - update_icon() - -/obj/item/proc/get_world_inventory_state() - if(!use_single_icon) - return - if(plane == HUD_PLANE && has_inventory_icon) - return ICON_STATE_INV - else - return ICON_STATE_WORLD - -/mob/proc/get_bodytype() - return - -/obj/item/proc/experimental_mob_overlay(var/mob/user_mob, var/slot) - - var/bodytype = lowertext(user_mob?.get_bodytype()) - var/useicon = get_icon_for_bodytype(bodytype) - if(bodytype != BODYTYPE_HUMANOID && (!bodytype || !check_state_in_icon("[bodytype]-[slot]", useicon))) - bodytype = lowertext(BODYTYPE_HUMANOID) - useicon = get_icon_for_bodytype(bodytype) - - var/useiconstate = "[bodytype]-[slot]" - if(!check_state_in_icon(useiconstate, useicon)) - return new /image - var/image/I = image(useicon, useiconstate) - I.color = color - I.appearance_flags = RESET_COLOR - . = apply_offsets(user_mob, bodytype, I, slot) - . = apply_overlays(user_mob, bodytype, ., slot) - -/mob/living/carbon/get_bodytype() - . = species && species.get_bodytype(src) - -/obj/item/proc/get_icon_for_bodytype(var/bodytype) - . = icon - if(on_mob_use_spritesheets) - for(var/btype in sprite_sheets) - if(lowertext(btype) == bodytype) - return sprite_sheets[btype] - -/obj/item/proc/apply_overlays(var/mob/user_mob, var/bodytype, var/image/overlay, var/slot) - . = overlay - -/obj/item/proc/apply_offsets(var/mob/user_mob, var/bodytype, var/image/overlay, var/slot) - if(ishuman(user_mob)) - var/mob/living/carbon/human/H = user_mob - if(lowertext(H.species.get_bodytype(H)) != bodytype) - overlay = H.species.get_offset_overlay_image(FALSE, overlay.icon, overlay.icon_state, color, slot) - . = overlay - -//Special proc belts use to compose their icon -/obj/item/proc/get_on_belt_overlay() - if(check_state_in_icon("on_belt", icon)) - var/image/res = image(icon, "on_belt") - res.color = color - return res diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm index 45da024f3db7..cf070a49deef 100644 --- a/code/game/objects/items/latexballoon.dm +++ b/code/game/objects/items/latexballoon.dm @@ -1,15 +1,15 @@ +// TODO: This is literally only available from abandoned mining crates. Remove? /obj/item/latexballon name = "latex glove" desc = "A latex glove, usually used as a balloon." icon = 'icons/obj/items/latexballon.dmi' icon_state = "latexballon" item_state = "lgloves" - force = 0 - throwforce = 0 w_class = ITEM_SIZE_SMALL throw_speed = 1 throw_range = 15 - var/state + material = /decl/material/solid/organic/plastic + _base_attack_force = 0 var/datum/gas_mixture/air_contents = null /obj/item/latexballon/proc/blow(obj/item/tank/tank) @@ -41,8 +41,10 @@ /obj/item/latexballon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature > T0C+100) burst() - return + return ..() -/obj/item/latexballon/attackby(obj/item/W, mob/user) - if (W.can_puncture()) +/obj/item/latexballon/attackby(obj/item/used_item, mob/user) + if (used_item.can_puncture()) burst() + return TRUE + return FALSE diff --git a/code/game/objects/items/paintkit.dm b/code/game/objects/items/paintkit.dm index 7e562e8a8631..5d8602efb267 100644 --- a/code/game/objects/items/paintkit.dm +++ b/code/game/objects/items/paintkit.dm @@ -1,27 +1,34 @@ /obj/item/kit icon_state = "modkit" icon = 'icons/obj/items/modkit.dmi' - var/new_name = "exosuit" //What is the variant called? - var/new_desc = "An exosuit." //How is the new exosuit described? - var/new_icon = "ripley" //What base icon will the new exosuit use? - var/new_icon_file - var/uses = 1 // Uses before the kit deletes itself. + material = /decl/material/solid/organic/plastic + var/new_name = "exosuit" // What is the variant called? + var/new_desc = "An exosuit." // How is the new exosuit described? + var/new_icon // What base icon will the new exosuit use? + var/new_state // What base icon state with the new exosuit use. + var/new_blend = BLEND_MULTIPLY // What decal blend mode does this kit use? + var/uses = 1 // Uses before the kit deletes itself. + var/custom = FALSE -/obj/item/kit/examine(mob/user) +/obj/item/kit/get_single_monetary_worth() + . = max(round(..()), (custom ? 100 : 750) * uses) // Luxury good, value is entirely artificial. + +/obj/item/kit/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It has [uses] use\s left.") + . += "It has [uses] use\s left." /obj/item/kit/inherit_custom_item_data(var/datum/custom_item/citem) - new_name = citem.item_name - new_desc = citem.item_desc - new_icon = citem.item_icon_state - new_icon_file = CUSTOM_ITEM_OBJ + custom = TRUE + new_name = citem.item_name + new_desc = citem.item_desc + new_state = citem.item_state + new_icon = citem.item_icon . = src /obj/item/kit/proc/use(var/amt, var/mob/user) uses -= amt playsound(get_turf(user), 'sound/items/Screwdriver.ogg', 50, 1) - if(uses<1) + if(uses < 1) qdel(src) // Root hardsuit kit defines. @@ -30,72 +37,64 @@ name = "voidsuit modification kit" desc = "A kit for modifying a voidsuit." uses = 2 - var/new_light_overlay - var/new_mob_icon_file -/obj/item/kit/suit/inherit_custom_item_data(var/datum/custom_item/citem) - . = ..() - if(citem.additional_data["light_overlay"]) - new_light_overlay = citem.additional_data["light_overlay"] - new_mob_icon_file = CUSTOM_ITEM_MOB - -/obj/item/clothing/head/helmet/space/void/attackby(var/obj/item/O, var/mob/user) - if(istype(O,/obj/item/kit/suit)) - var/obj/item/kit/suit/kit = O - SetName("[kit.new_name] suit helmet") +/obj/item/clothing/head/helmet/space/void/attackby(var/obj/item/used_item, var/mob/user) + + if(istype(used_item,/obj/item/kit/suit)) + var/obj/item/kit/suit/kit = used_item + to_chat(user, SPAN_NOTICE("You set about modifying \the [src] into \a [kit.new_name] void helmet.")) + SetName("[kit.new_name] void helmet") desc = kit.new_desc - icon_state = "[kit.new_icon]_helmet" - item_state = "[kit.new_icon]_helmet" - if(kit.new_icon_file) - icon = kit.new_icon_file - if(kit.new_mob_icon_file) - icon_override = kit.new_mob_icon_file - if(kit.new_light_overlay) - light_overlay = kit.new_light_overlay - to_chat(user, "You set about modifying the helmet into [src].") - var/mob/living/carbon/human/H = user - if(istype(H)) - bodytype_restricted = list(H.species.get_bodytype(H)) + icon = kit.new_icon + bodytype_equip_flags = user.get_bodytype()?.bodytype_flag kit.use(1,user) - return 1 + reconsider_single_icon() + return TRUE + return ..() -/obj/item/clothing/suit/space/void/attackby(var/obj/item/O, var/mob/user) - if(istype(O,/obj/item/kit/suit)) - var/obj/item/kit/suit/kit = O +/obj/item/clothing/suit/space/void/attackby(var/obj/item/used_item, var/mob/user) + + if(istype(used_item, /obj/item/kit/suit)) + var/obj/item/kit/suit/kit = used_item + to_chat(user, SPAN_NOTICE("You set about modifying \the [src] into \a [kit.new_name] voidsuit.")) SetName("[kit.new_name] voidsuit") desc = kit.new_desc - icon_state = "[kit.new_icon]_suit" - item_state = "[kit.new_icon]_suit" - if(kit.new_icon_file) - icon = kit.new_icon_file - if(kit.new_mob_icon_file) - icon_override = kit.new_mob_icon_file - to_chat(user, "You set about modifying the suit into [src].") - var/mob/living/carbon/human/H = user - if(istype(H)) - bodytype_restricted = list(H.species.get_bodytype(H)) + icon = kit.new_icon + bodytype_equip_flags = user.get_bodytype()?.bodytype_flag kit.use(1,user) - return 1 + reconsider_single_icon() + return TRUE + return ..() // Mechs are handled in their attackby (mech_interaction.dm). /obj/item/kit/paint - name = "exosuit customisation kit" - desc = "A kit containing all the needed tools and parts to repaint a exosuit." - var/removable = null + name = "exosuit decal kit" + desc = "A kit containing all the needed tools and parts to repaint an exosuit." + abstract_type = /obj/item/kit/paint -/obj/item/kit/paint/examine(mob/user) +/obj/item/kit/paint/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "This kit will add a '[new_name]' decal to a exosuit'.") + . += "This kit will add a '[new_name]' decal to an exosuit'." // exosuit kits. -/obj/item/kit/paint/powerloader/flames_red +/obj/item/kit/paint/flames_red name = "\"Firestarter\" exosuit customisation kit" - new_name = "red flames" - new_icon = "flames_red" + new_state = "flames_red" + new_blend = BLEND_OVERLAY -/obj/item/kit/paint/powerloader/flames_blue +/obj/item/kit/paint/flames_blue name = "\"Burning Chrome\" exosuit customisation kit" - new_name = "blue flames" - new_icon = "flames_blue" + new_state = "flames_blue" + new_blend = BLEND_OVERLAY + +/obj/item/kit/paint/camouflage + name = "\"Guerilla\" exosuit customisation kit" + desc = "An old military pattern for jungle warfare, now available for general use." + new_state = "cammo1" + +/obj/item/kit/paint/camouflage/forest + name = "\"Alpine\" exosuit customisation kit" + new_state = "cammo2" + desc = "A muted pattern for alpine environments. Don't miss the forest for the trees!" diff --git a/code/game/objects/items/paper_fortune_teller.dm b/code/game/objects/items/paper_fortune_teller.dm new file mode 100644 index 000000000000..0720395ebe63 --- /dev/null +++ b/code/game/objects/items/paper_fortune_teller.dm @@ -0,0 +1,95 @@ +// Mostly exists as a demo for the FSM extension. +/obj/item/paper_fortune_teller + name = "paper fortune teller" + desc = "Origami, for children." + icon_state = "fortune" + icon = 'icons/obj/items/fortune_teller.dmi' + material = /decl/material/solid/organic/paper + var/choice_counter = 0 + var/busy = FALSE + var/list/fortunes = new(8) + var/static/list/possible_fortunes = list( + "You will fall down an elevator shaft.", + "Today it's up to you to create the peacefulness you long for.", + "If you refuse to accept anything but the best, you very often get it.", + "A smile is your passport into the hearts of others.", + "Hard work pays off in the future, laziness pays off now.", + "Change can hurt, but it leads a path to something better.", + "Hidden in a valley beside an open stream- This will be the type of place where you will find your dream.", + "Never give up. You're not a failure if you don't give up.", + "Love can last a lifetime, if you want it to.", + "The love of your life is stepping into your planet this summer.", + "Your ability for accomplishment will follow with success.", + "Please help me, I'm trapped in a fortune cookie factory!", + "Improve, don't remove.", + "Run.", + "Please wake up." + ) + +/obj/item/paper_fortune_teller/Initialize(ml, material_key) + var/list/fortune_options = possible_fortunes.Copy() + for(var/i = 1 to 8) + fortunes[i] = pick_n_take(fortune_options) + add_state_machine(src, /datum/state_machine/paper_fortune) + . = ..() + +/obj/item/paper_fortune_teller/on_update_icon() + . = ..() + var/datum/state_machine/fsm = get_state_machine(src, /datum/state_machine/paper_fortune) + if(fsm && istype(fsm.current_state, /decl/state/paper_fortune)) + var/decl/state/paper_fortune/fsm_state = fsm.current_state + icon_state = "[initial(icon_state)]-[fsm_state.icon_state]" + +/obj/item/paper_fortune_teller/attack_self(mob/user) + var/datum/state_machine/fsm = get_state_machine(src, /datum/state_machine/paper_fortune) + if(!fsm || !istype(fsm.current_state, /decl/state/paper_fortune)) + to_chat(user, SPAN_WARNING("You can't seem to work out how \the [src] works.")) + return TRUE + + var/decl/state/paper_fortune/fsm_state = fsm.current_state + var/current_fsm = get_state_machine(src, /datum/state_machine/paper_fortune) + if(current_fsm != fsm || fsm_state != fsm.current_state || QDELETED(src) || QDELETED(user) || loc != user) + return TRUE + + var/option = input(user, "Select an option.", "Fortune Teller") as null|anything in fsm_state.fortune_choices + current_fsm = get_state_machine(src, /datum/state_machine/paper_fortune) + if(!option || current_fsm != fsm || fsm_state != fsm.current_state || QDELETED(src) || QDELETED(user) || loc != user) + return TRUE + + choice_counter++ + if(choice_counter >= 3) + to_chat(user, SPAN_NOTICE("The fortune under fold [option] reads: \"[fortunes[option] || "???"]\"")) + fsm.evaluate() + else if(istext(option)) + to_chat(user, SPAN_NOTICE("You pick '[option]'.")) + alternate_by_color(option, user) + else if(isnum(option)) + to_chat(user, SPAN_NOTICE("You pick '[option]'.")) + alternate_by_number(option, user) + else + to_chat(user, SPAN_WARNING("You can't seem to work out how to use \the [src].")) + return TRUE + +/obj/item/paper_fortune_teller/proc/alternate(var/amount, var/mob/user) + busy = TRUE + for(var/i = 1 to amount) + advance() + if(user) + user.visible_message(SPAN_NOTICE("\The [user] opens and closes \the [src].")) + sleep(0.5 SECONDS) + if(QDELETED(src)) + break + busy = FALSE + +// Alternates between two states based on the length of the color chosen. +// E.g. 'Red' makes it switch three times. 'Yellow' does it six times, etc. +/obj/item/paper_fortune_teller/proc/alternate_by_color(var/color_word, var/mob/user) + alternate(length(color_word), user) + +/obj/item/paper_fortune_teller/proc/alternate_by_number(var/number, var/mob/user) + alternate(number, user) + +/obj/item/paper_fortune_teller/proc/advance() + var/datum/state_machine/fsm = get_state_machine(src, /datum/state_machine/paper_fortune) + if(fsm) + fsm.evaluate() diff --git a/code/game/objects/items/part_replacer.dm b/code/game/objects/items/part_replacer.dm index 8154410a0140..f46e1f093daa 100644 --- a/code/game/objects/items/part_replacer.dm +++ b/code/game/objects/items/part_replacer.dm @@ -1,28 +1,21 @@ -/obj/item/storage/part_replacer +/obj/item/part_replacer name = "rapid part exchange device" desc = "Special mechanical module made to store, sort, and apply standard machine parts." icon = 'icons/obj/items/device/parts_replacer.dmi' - icon_state = "RPED" - item_state = "RPED" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_HUGE - can_hold = list(/obj/item/stock_parts) - storage_slots = 50 - use_to_pickup = 1 - allow_quick_gather = 1 - allow_quick_empty = 1 - collection_mode = 1 - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = 100 + storage = /datum/storage/parts_replacer material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"engineering":3,"materials":3}' var/replace_sound = 'sound/items/rped.ogg' var/remote_interaction = FALSE -/obj/item/storage/part_replacer/proc/part_replacement_sound() +/obj/item/part_replacer/proc/part_replacement_sound() playsound(src, replace_sound, 40, 1) -/obj/item/storage/part_replacer/afterattack(atom/target, mob/user, proximity_flag, click_parameters) +/obj/item/part_replacer/afterattack(atom/target, mob/user, proximity_flag, click_parameters) if(proximity_flag || !remote_interaction) return @@ -31,17 +24,17 @@ if(machine.component_attackby(src, user)) user.Beam(machine, icon_state = "rped_upgrade", icon = 'icons/effects/effects.dmi', time = 5) -/obj/item/storage/part_replacer/advanced +/obj/item/part_replacer/advanced name = "advanced rapid part exchange device" desc = "A version of the RPED that allows for replacement of parts and scanning from a distance, along with higher capacity for parts." - icon_state = "RPED_BS" + icon = 'icons/obj/items/device/parts_replacer_advanced.dmi' w_class = ITEM_SIZE_NORMAL - storage_slots = 400 - max_storage_space = 200 + storage = /datum/storage/parts_replacer/advanced replace_sound = 'sound/items/PSHOOM.ogg' remote_interaction = TRUE - material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"engineering":3,"materials":3}' + diff --git a/code/game/objects/items/passport.dm b/code/game/objects/items/passport.dm new file mode 100644 index 000000000000..48ce254e834e --- /dev/null +++ b/code/game/objects/items/passport.dm @@ -0,0 +1,35 @@ +/obj/item/passport + name = "identification papers" + icon = 'icons/obj/items/passport.dmi' + icon_state = "passport" + _base_attack_force = 1 + gender = PLURAL + w_class = ITEM_SIZE_SMALL + attack_verb = "whipped" + hitsound = 'sound/weapons/towelwhip.ogg' + desc = "A set of identifying documents." + material = /decl/material/solid/organic/paper + matter = list( + /decl/material/solid/organic/leather = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/cardboard = MATTER_AMOUNT_REINFORCEMENT + ) + var/info + +/obj/item/passport/proc/set_info(mob/living/human/H) + if(!istype(H)) + return + + var/decl/background_detail/background = H.get_background_datum_by_flag(BACKGROUND_FLAG_CITIZENSHIP) + var/pob = background ? background.name : "Unset" + + var/fingerprint = H.get_full_print(ignore_blockers = TRUE) || "N/A" + var/decl/pronouns/pronouns = H.get_pronouns(ignore_coverings = TRUE) + info = "\icon[src] [src]:\nName: [H.real_name]\nSpecies: [H.get_species_name()]\nGender: [capitalize(pronouns.name)]\nAge: [H.get_age()]\nPlace of Birth: [pob]\nFingerprint: [fingerprint]" + +/obj/item/passport/attack_self(mob/user) + user.visible_message( + SPAN_ITALIC("\The [user] checks over \the [src]."), + SPAN_ITALIC("You check over \the [src]."), + SPAN_ITALIC("You hear the faint rustle of pages."), + 5) + to_chat(user, info || SPAN_WARNING("\The [src] is completely blank!")) diff --git a/code/game/objects/items/plunger.dm b/code/game/objects/items/plunger.dm index 1554df1077c3..29558d974c81 100644 --- a/code/game/objects/items/plunger.dm +++ b/code/game/objects/items/plunger.dm @@ -1,26 +1,23 @@ -/obj/item/clothing/mask/plunger +/obj/item/plunger name = "plunger" desc = "This is possibly the least sanitary object around." icon = 'icons/obj/items/plunger.dmi' - icon_state = "plunger_black" - item_state = "plunger_black" - attack_verb = list("plunged") - force = 1 + icon_state = ICON_STATE_WORLD + attack_verb = "plunged" + _base_attack_force = 1 w_class = ITEM_SIZE_NORMAL - slot_flags = SLOT_HEAD | SLOT_MASK + slot_flags = SLOT_HEAD | SLOT_FACE + body_parts_covered = SLOT_HEAD hitsound = 'sound/effects/plunger.ogg' - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic -/obj/item/plunger - name = "plunger" - desc = "a plunger. It unclogs things." - icon_state = "plunger_black" - item_state = "plunger_black" - icon = 'icons/obj/items/plunger.dmi' - attack_verb = list("plunged") - force = 1 - w_class = ITEM_SIZE_NORMAL - hitsound = 'sound/effects/plunger.ogg' - -/obj/item/plunger/robot - name = "cyberplunger" \ No newline at end of file +/obj/item/plunger/equipped(mob/user, slot) + switch(slot) + if(SLOT_FACE) + body_parts_covered = SLOT_FACE|SLOT_EYES + if(SLOT_HEAD) + body_parts_covered = initial(body_parts_covered) + return ..() + +/obj/item/plunger/unbreakable + max_health = ITEM_HEALTH_NO_DAMAGE diff --git a/code/game/objects/items/plushies.dm b/code/game/objects/items/plushies.dm new file mode 100644 index 000000000000..3d07788f436b --- /dev/null +++ b/code/game/objects/items/plushies.dm @@ -0,0 +1,335 @@ +//Large plushies. +/obj/structure/plushie + abstract_type = /obj/structure/plushie + desc = "A very generic plushie. It seems to not want to exist." + icon = 'icons/obj/structures/plushie.dmi' + icon_state = "ianplushie" + anchored = FALSE + density = TRUE + var/phrase = "I don't want to exist anymore!" + var/phrase_sound + var/phrase_volume = 20 + var/phrase_vary = TRUE + +/obj/structure/plushie/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + playsound(src.loc, 'sound/effects/rustle1.ogg', 100, 1) + if(user.check_intent(I_FLAG_HELP)) + user.visible_message( + SPAN_NOTICE("\The [user] hugs \the [src]!"), + SPAN_NOTICE("You hug \the [src]!")) + else if (user.check_intent(I_FLAG_HARM)) + user.visible_message( + SPAN_WARNING("\The [user] punches \the [src]!"), + SPAN_WARNING("You punch \the [src]!")) + else if (user.check_intent(I_FLAG_GRAB)) + user.visible_message( + SPAN_WARNING("\The [user] attempts to strangle \the [src]!"), + SPAN_WARNING("You attempt to strangle \the [src]!")) + else + user.visible_message( + SPAN_NOTICE("\The [user] pokes \the [src]."), + SPAN_NOTICE("You poke \the [src].")) + if(phrase) + audible_message("\The [src] says, \"[phrase]\"") + if(phrase_sound) + playsound(loc, phrase_sound, phrase_volume, phrase_vary) + return TRUE + +/obj/structure/plushie/ian + name = "plush corgi" + desc = "A plushie of an adorable corgi! Don't you just want to hug it and squeeze it and call it \"Ian\"?" + phrase = "Arf!" + +/obj/structure/plushie/drone + name = "plush drone" + desc = "A plushie of a happy drone! It appears to be smiling." + icon_state = "droneplushie" + phrase = "Beep boop!" + +/obj/structure/plushie/carp + name = "plush carp" + desc = "A plushie of an elated carp! Straight from the wilds of the frontier, now right here in your hands." + icon_state = "carpplushie" + phrase = "Glorf!" + +/obj/structure/plushie/beepsky + name = "plush Officer Sweepsky" + desc = "A plushie of a popular industrious cleaning robot! If it could feel emotions, it would love you." + icon_state = "beepskyplushie" + phrase = "Ping!" + +//Small plushies. +/obj/item/toy/plushie + abstract_type = /obj/item/toy/plushie + name = "generic small plush" + desc = "A very generic small plushie. It seems to not want to exist." + icon = 'icons/obj/toy/plush_nymph.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_HEAD + var/phrase + var/phrase_sound + var/phrase_volume = 20 + var/phrase_vary = TRUE + +/obj/item/toy/plushie/attack_self(mob/user) + if(user.check_intent(I_FLAG_HELP)) + user.visible_message( + SPAN_NOTICE("\The [user] hugs \the [src]!"), + SPAN_NOTICE("You hug \the [src]!")) + else if (user.check_intent(I_FLAG_HARM)) + user.visible_message( + SPAN_WARNING("\The [user] punches \the [src]!"), + SPAN_WARNING("You punch \the [src]!")) + else if (user.check_intent(I_FLAG_GRAB)) + user.visible_message( + SPAN_WARNING("\The [user] attempts to strangle \the [src]!"), + SPAN_WARNING("You attempt to strangle \the [src]!")) + else + user.visible_message( + SPAN_NOTICE("\The [user] pokes \the [src]."), + SPAN_NOTICE("You poke \the [src].")) + if(phrase) + audible_message("\The [src] says, \"[phrase]\"") + if(phrase_sound) + playsound(loc, phrase_sound, phrase_volume, phrase_vary) + return TRUE + +/obj/item/toy/plushie/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + . = ..() + if(. && phrase_sound) + playsound(src, phrase_sound, phrase_volume, phrase_vary) + +// Various miscellaneous animal plushies. +/obj/item/toy/plushie/deer + name = "deer plushie" + desc = "A soft deer plush." + icon = 'icons/obj/toy/plush_deer.dmi' + +/obj/item/toy/plushie/mouse + name = "mouse plush" + desc = "A plushie of a mouse! What was once considered a vile rodent is now your very best friend." + icon = 'icons/obj/toy/plush_mouse.dmi' + +/obj/item/toy/plushie/kitten + name = "kitten plush" + desc = "A plushie of a cute kitten! Watch as it purrs its way right into your heart." + icon = 'icons/obj/toy/plush_kitten.dmi' + +/obj/item/toy/plushie/lizard + name = "lizard plush" + desc = "A plushie of a scaly lizard!" + icon = 'icons/obj/toy/plush_lizard.dmi' + +/obj/item/toy/plushie/spider + name = "spider plush" + desc = "A plushie of a fuzzy spider! It has eight legs - all the better to hug you with." + icon = 'icons/obj/toy/plush_spider.dmi' + +/obj/item/toy/plushie/corgi + name = "corgi plushie" + desc = "A soft corgi plush." + icon = 'icons/obj/toy/plush_corgi.dmi' + +/obj/item/toy/plushie/corgi/ribbon + desc = "A soft corgi plush. This one has a ribbon." + icon = 'icons/obj/toy/plush_corgi_ribbon.dmi' + +/obj/item/toy/plushie/robo_corgi + name = "robot corgi plushie" + desc = "A corgi plush with a stiff grey plastic casing and a red monoptic." + icon = 'icons/obj/toy/plush_corgi_robot.dmi' + +/obj/item/toy/plushie/octopus + name = "octopus plushie" + desc = "A soft octopus plushie." + icon = 'icons/obj/toy/plush_octopus.dmi' + +/obj/item/toy/plushie/face_hugger + name = "huggable alien plushie" + desc = "A strange alien plushie." + icon = 'icons/obj/toy/plush_facehugger.dmi' + +/obj/item/toy/plushie/nymph + name = "nymph plushie" + desc = "A soft diona nymph plush." + icon = 'icons/obj/toy/plush_nymph.dmi' + +// Therapy plushes. +/obj/item/toy/plushie/therapy + name = "red therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is red." + icon = 'icons/obj/toy/plush_therapy_red.dmi' + +/obj/item/toy/plushie/therapy/orange + name = "orange therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is orange." + icon = 'icons/obj/toy/plush_therapy_orange.dmi' + + +/obj/item/toy/plushie/therapy/yellow + name = "yellow therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is yellow." + icon = 'icons/obj/toy/plush_therapy_yellow.dmi' + +/obj/item/toy/plushie/therapy/green + name = "green therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is green." + icon = 'icons/obj/toy/plush_therapy_green.dmi' + +/obj/item/toy/plushie/therapy/purple + name = "purple therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is purple." + icon = 'icons/obj/toy/plush_therapy_purple.dmi' + +/obj/item/toy/plushie/therapy/blue + name = "blue therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is blue." + icon = 'icons/obj/toy/plush_therapy_blue.dmi' + +// Carp plushies +/obj/item/toy/plushie/carp + name = "space carp plushie" + desc = "An adorable stuffed toy that resembles a space carp." + attack_verb = list("bitten", "eaten", "fin slapped") + phrase_sound = 'sound/weapons/bite.ogg' + icon = 'icons/obj/toy/plush_carp.dmi' +/obj/item/toy/plushie/carp/ice + name = "ice carp plushie" + icon = 'icons/obj/toy/plush_carp_ice.dmi' + +/obj/item/toy/plushie/carp/silent + name = "monochrome carp plushie" + icon = 'icons/obj/toy/plush_carp_silent.dmi' + +/obj/item/toy/plushie/carp/electric + name = "electric carp plushie" + icon = 'icons/obj/toy/plush_carp_electric.dmi' + +/obj/item/toy/plushie/carp/gold + name = "golden carp plushie" + icon = 'icons/obj/toy/plush_carp_gold.dmi' + +/obj/item/toy/plushie/carp/toxin + name = "toxic carp plushie" + icon = 'icons/obj/toy/plush_carp_toxic.dmi' + +/obj/item/toy/plushie/carp/dragon + name = "dragon carp plushie" + icon = 'icons/obj/toy/plush_carp_dragon.dmi' + +/obj/item/toy/plushie/carp/pink + name = "pink carp plushie" + icon = 'icons/obj/toy/plush_carp_pink.dmi' + +/obj/item/toy/plushie/carp/candy + name = "candy carp plushie" + icon = 'icons/obj/toy/plush_carp_candy.dmi' + +/obj/item/toy/plushie/carp/nebula + name = "nebula carp plushie" + icon = 'icons/obj/toy/plush_carp_nebula.dmi' + +/obj/item/toy/plushie/carp/void + name = "void carp plushie" + icon = 'icons/obj/toy/plush_carp_void.dmi' + +// Fox plushes. +/obj/item/toy/plushie/fox + name = "red fox plushie" + icon = 'icons/obj/toy/plush_fox.dmi' + +/obj/item/toy/plushie/fox/black + name = "black fox plushie" + icon = 'icons/obj/toy/plush_fox_black.dmi' + +/obj/item/toy/plushie/fox/marble + name = "marble fox plushie" + icon = 'icons/obj/toy/plush_fox_marble.dmi' + +/obj/item/toy/plushie/fox/blue + name = "blue fox plushie" + icon = 'icons/obj/toy/plush_fox_blue.dmi' + +/obj/item/toy/plushie/fox/orange + name = "orange fox plushie" + icon = 'icons/obj/toy/plush_fox_orange.dmi' + +/obj/item/toy/plushie/fox/coffee + name = "coffee fox plushie" + icon = 'icons/obj/toy/plush_fox_coffee.dmi' + +/obj/item/toy/plushie/fox/pink + name = "pink fox plushie" + icon = 'icons/obj/toy/plush_fox_pink.dmi' + +/obj/item/toy/plushie/fox/purple + name = "purple fox plushie" + icon = 'icons/obj/toy/plush_fox_purple.dmi' + +/obj/item/toy/plushie/fox/crimson + name = "crimson fox plushie" + icon = 'icons/obj/toy/plush_fox_crimson.dmi' + +// Cat plushes. +/obj/item/toy/plushie/cat + name = "black cat plushie" + desc = "A plush toy cat." + icon = 'icons/obj/toy/plush_cat.dmi' + +/obj/item/toy/plushie/cat/grey + name = "grey cat plushie" + icon = 'icons/obj/toy/plush_cat_grey.dmi' + +/obj/item/toy/plushie/cat/white + name = "white cat plushie" + icon = 'icons/obj/toy/plush_cat_white.dmi' + +/obj/item/toy/plushie/cat/orange + name = "orange cat plushie" + icon = 'icons/obj/toy/plush_cat_orange.dmi' + +/obj/item/toy/plushie/cat/siamese + name = "siamese cat plushie" + icon = 'icons/obj/toy/plush_cat_siamese.dmi' + +/obj/item/toy/plushie/cat/tabby + name = "tabby cat plushie" + icon = 'icons/obj/toy/plush_cat_tabby.dmi' + +/obj/item/toy/plushie/cat/tuxedo + name = "tuxedo cat plushie" + icon = 'icons/obj/toy/plush_cat_tuxedo.dmi' + +// Squid plushies. +/obj/item/toy/plushie/squid + name = "green squid plushie" + desc = "A small, cute and loveable squid friend. This one is green." + icon = 'icons/obj/toy/plush_squid.dmi' + +/obj/item/toy/plushie/squid/mint + name = "mint squid plushie" + desc = "A small, cute and loveable squid friend. This one is mint coloured." + icon = 'icons/obj/toy/plush_squid_mint.dmi' + +/obj/item/toy/plushie/squid/blue + name = "blue squid plushie" + desc = "A small, cute and loveable squid friend. This one is blue." + icon = 'icons/obj/toy/plush_squid_blue.dmi' + +/obj/item/toy/plushie/squid/orange + name = "orange squid plushie" + desc = "A small, cute and loveable squid friend. This one is orange." + icon = 'icons/obj/toy/plush_squid_orange.dmi' + +/obj/item/toy/plushie/squid/yellow + name = "yellow squid plushie" + desc = "A small, cute and loveable squid friend. This one is yellow." + icon = 'icons/obj/toy/plush_squid_yellow.dmi' + +/obj/item/toy/plushie/squid/pink + name = "pink squid plushie" + desc = "A small, cute and loveable squid friend. This one is pink." + icon = 'icons/obj/toy/plush_squid_pink.dmi' diff --git a/code/game/objects/items/remains.dm b/code/game/objects/items/remains.dm new file mode 100644 index 000000000000..cc82890733c9 --- /dev/null +++ b/code/game/objects/items/remains.dm @@ -0,0 +1,49 @@ +/obj/item/remains + name = "remains" + gender = PLURAL + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + anchored = FALSE + material = /decl/material/solid/organic/bone + +/obj/item/remains/human + desc = "They look like human remains. They have a strange aura about them." + +/obj/item/remains // Apparently used by cult somewhere? + desc = "They look like human remains. They have a strange aura about them." + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + +/obj/item/remains/xeno + desc = "They look like the remains of something... alien. They have a strange aura about them." + icon_state = "remainsxeno" + +/obj/item/remains/xeno/charred + color = COLOR_DARK_GRAY + +/obj/item/remains/robot + desc = "They look like the remains of something mechanical. They have a strange aura about them." + icon = 'icons/mob/robots/_gibs.dmi' + icon_state = "remainsrobot" + material = /decl/material/solid/metal/steel + +/obj/item/remains/mouse + desc = "They look like the remains of a small rodent." + icon_state = "mouse" + +/obj/item/remains/lizard + desc = "They look like the remains of a small rodent." + icon_state = "lizard" + +/obj/item/remains/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + to_chat(user, SPAN_NOTICE("\The [src] sinks together into a pile of ash.")) + var/turf/floor = get_turf(src) + if(floor?.is_floor() && floor.simulated) + new /obj/effect/decal/cleanable/ash(floor) + qdel(src) + return TRUE + +/obj/item/remains/robot/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + return TRUE diff --git a/code/game/objects/items/rescuebag.dm b/code/game/objects/items/rescuebag.dm index ddf5092e8add..e4c56dafd6bb 100644 --- a/code/game/objects/items/rescuebag.dm +++ b/code/game/objects/items/rescuebag.dm @@ -2,10 +2,13 @@ /obj/item/bodybag/rescue name = "rescue bag" desc = "A folded, reusable bag designed to prevent additional damage to an occupant, especially useful if short on time or in \ - a hostile enviroment." + a hostile environment." icon = 'icons/obj/closets/rescuebag.dmi' icon_state = "folded" - origin_tech = "{'biotech':2}" + origin_tech = @'{"biotech":2}' + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/silicon = MATTER_AMOUNT_SECONDARY) + bag_type = /obj/structure/closet/body_bag/rescue var/obj/item/tank/airtank /obj/item/bodybag/rescue/loaded @@ -21,43 +24,43 @@ QDEL_NULL(airtank) return ..() -/obj/item/bodybag/rescue/attack_self(mob/user) - var/obj/structure/closet/body_bag/rescue/R = new /obj/structure/closet/body_bag/rescue(user.loc) - R.add_fingerprint(user) - if(airtank) - R.set_tank(airtank) +/obj/item/bodybag/rescue/create_bag_structure(mob/user) + var/obj/structure/closet/body_bag/rescue/bag = ..() + if(istype(bag) && airtank) + bag.set_tank(airtank) airtank = null - qdel(src) + return bag -/obj/item/bodybag/rescue/attackby(obj/item/W, mob/user, var/click_params) - if(istype(W,/obj/item/tank)) +/obj/item/bodybag/rescue/attackby(obj/item/used_item, mob/user, var/click_params) + if(istype(used_item,/obj/item/tank)) if(airtank) to_chat(user, "\The [src] already has an air tank installed.") - return 1 - else if(user.unEquip(W)) - W.forceMove(src) - airtank = W - to_chat(user, "You install \the [W] in \the [src].") - return 1 - else if(airtank && isScrewdriver(W)) + return TRUE + if(user.try_unequip(used_item)) + used_item.forceMove(src) + airtank = used_item + to_chat(user, "You install \the [used_item] in \the [src].") + return TRUE + else if(airtank && IS_SCREWDRIVER(used_item)) to_chat(user, "You remove \the [airtank] from \the [src].") airtank.dropInto(loc) airtank = null + return TRUE else - ..() + return ..() -/obj/item/bodybag/rescue/examine(mob/user) +/obj/item/bodybag/rescue/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(airtank) - to_chat(user,"The pressure meter on \the [airtank] shows '[airtank.air_contents.return_pressure()] kPa'.") - to_chat(user,"The distribution valve on \the [airtank] is set to '[airtank.distribute_pressure] kPa'.") + . += "The pressure meter on \the [airtank] shows '[airtank.air_contents.return_pressure()] kPa'." + . += "The distribution valve on \the [airtank] is set to '[airtank.distribute_pressure] kPa'." else - to_chat(user, "The air tank is missing.") - + . += SPAN_WARNING("The air tank is missing.") + /obj/structure/closet/body_bag/rescue name = "rescue bag" desc = "A reusable plastic bag designed to prevent additional damage to an occupant, especially useful if short on time or in \ - a hostile enviroment." + a hostile environment." icon = 'icons/obj/closets/rescuebag.dmi' item_path = /obj/item/bodybag/rescue storage_types = CLOSET_STORAGE_MOBS @@ -67,7 +70,7 @@ /obj/structure/closet/body_bag/rescue/Initialize() . = ..() atmo = new() - atmo.volume = 0.1*CELL_VOLUME + atmo.total_volume = 0.1*CELL_VOLUME START_PROCESSING(SSobj, src) /obj/structure/closet/body_bag/rescue/Destroy() @@ -82,26 +85,25 @@ /obj/structure/closet/body_bag/rescue/on_update_icon() ..() - overlays.Cut() if(airtank) - overlays += image(icon, "tank") + add_overlay("tank") -/obj/structure/closet/body_bag/rescue/attackby(obj/item/W, mob/user, var/click_params) - if(istype(W,/obj/item/tank/)) +/obj/structure/closet/body_bag/rescue/attackby(obj/item/used_item, mob/user, var/click_params) + if(istype(used_item,/obj/item/tank)) if(airtank) to_chat(user, "\The [src] already has an air tank installed.") - return 1 - else if(user.unEquip(W, src)) - set_tank(W) - to_chat(user, "You install \the [W] in \the [src].") - return 1 - else if(airtank && isScrewdriver(W)) + else if(user.try_unequip(used_item, src)) + set_tank(used_item) + to_chat(user, "You install \the [used_item] in \the [src].") + return TRUE + else if(airtank && IS_SCREWDRIVER(used_item)) to_chat(user, "You remove \the [airtank] from \the [src].") airtank.dropInto(loc) airtank = null update_icon() + return TRUE else - ..() + return ..() /obj/structure/closet/body_bag/rescue/fold(var/user) var/obj/item/tank/my_tank = airtank @@ -124,15 +126,19 @@ /obj/structure/closet/body_bag/rescue/return_air() //Used to make stasis bags protect from vacuum. return atmo -/obj/structure/closet/body_bag/rescue/examine(mob/user) +/obj/structure/closet/body_bag/rescue/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(airtank) - to_chat(user,"The pressure meter on \the [airtank] shows '[airtank.air_contents.return_pressure()] kPa'.") - to_chat(user,"The distribution valve on \the [airtank] is set to '[airtank.distribute_pressure] kPa'.") + . += "The pressure meter on \the [airtank] shows '[airtank.air_contents.return_pressure()] kPa'." + . += "The distribution valve on \the [airtank] is set to '[airtank.distribute_pressure] kPa'." else - to_chat(user, "The air tank is missing.") - to_chat(user,"The pressure meter on [src] shows '[atmo.return_pressure()] kPa'.") + . += SPAN_WARNING("The air tank is missing.") + . += "The pressure meter on [src] shows '[atmo.return_pressure()] kPa'." + +/obj/structure/closet/body_bag/rescue/examined_by(mob/user, distance, infix, suffix) + . = ..() if(Adjacent(user)) //The bag's rather thick and opaque from a distance. - to_chat(user, "You peer into \the [src].") - for(var/mob/living/L in contents) - L.examine(arglist(args)) + to_chat(user, SPAN_INFO("You peer into \the [src].")) + for(var/mob/living/patient in contents) + patient.examined_by(user, distance, infix, suffix) + return TRUE \ No newline at end of file diff --git a/code/game/objects/items/robot/robot_frame.dm b/code/game/objects/items/robot/robot_frame.dm index bcb828d2fa18..2759cbc834e3 100644 --- a/code/game/objects/items/robot/robot_frame.dm +++ b/code/game/objects/items/robot/robot_frame.dm @@ -20,10 +20,10 @@ update_icon() /obj/item/robot_parts/robot_suit/on_update_icon() - overlays.Cut() + . = ..() for(var/part in required_parts) if(parts[part]) - overlays += "[part]+o" + add_overlay("[part]+o") /obj/item/robot_parts/robot_suit/proc/check_completion() for(var/part in required_parts) @@ -32,13 +32,13 @@ SSstatistics.add_field("cyborg_frames_built",1) return TRUE -/obj/item/robot_parts/robot_suit/attackby(obj/item/W, mob/user) +/obj/item/robot_parts/robot_suit/attackby(obj/item/used_item, mob/user) // Uninstall a robotic part. - if(isCrowbar(W)) + if(IS_CROWBAR(used_item)) if(!parts.len) to_chat(user, SPAN_WARNING("\The [src] has no parts to remove.")) - return + return TRUE var/removing = pick(parts) var/obj/item/robot_parts/part = parts[removing] part.forceMove(get_turf(src)) @@ -46,85 +46,81 @@ parts -= removing to_chat(user, SPAN_WARNING("You lever \the [part] off \the [src].")) update_icon() + return TRUE // Install a robotic part. - else if (istype(W, /obj/item/robot_parts)) - var/obj/item/robot_parts/part = W - if(!required_parts[part.bp_tag] || !istype(W, required_parts[part.bp_tag])) - to_chat(user, SPAN_WARNING("\The [src] is not compatible with \the [W].")) - return - if(parts[part.bp_tag]) - to_chat(user, SPAN_WARNING("\The [src] already has \a [W] installed.")) - return - if(part.can_install(user) && user.unEquip(W, src)) + else if (istype(used_item, /obj/item/robot_parts)) + var/obj/item/robot_parts/part = used_item + if(!required_parts[part.bp_tag] || !istype(used_item, required_parts[part.bp_tag])) + to_chat(user, SPAN_WARNING("\The [src] is not compatible with \the [used_item].")) + else if(parts[part.bp_tag]) + to_chat(user, SPAN_WARNING("\The [src] already has \a [used_item] installed.")) + else if(part.can_install(user) && user.try_unequip(used_item, src)) parts[part.bp_tag] = part update_icon() + return TRUE - // Install an MMI/brain. - else if(istype(W, /obj/item/mmi) || istype(W, /obj/item/organ/internal/posibrain)) + // Install a brain. + else if(istype(used_item, /obj/item/organ/internal/brain_interface)) - if(!istype(loc,/turf)) - to_chat(user, SPAN_WARNING("You can't put \the [W] in without the frame being on the ground.")) - return + if(!isturf(loc)) + to_chat(user, SPAN_WARNING("You can't put \the [used_item] in without the frame being on the ground.")) + return TRUE if(!check_completion()) to_chat(user, SPAN_WARNING("The frame is not ready for the central processor to be installed.")) - return - - var/mob/living/carbon/brain/B - if(istype(W, /obj/item/mmi)) - var/obj/item/mmi/M = W - B = M.brainmob - else - var/obj/item/organ/internal/posibrain/P = W - B = P.brainmob + return TRUE - if(!B) - to_chat(user, SPAN_WARNING("Sticking an empty [W.name] into the frame would sort of defeat the purpose.")) - return + var/obj/item/organ/internal/brain_interface/M = used_item + var/mob/living/brainmob = M?.get_brainmob() + if(!brainmob) + to_chat(user, SPAN_WARNING("Sticking an empty [used_item.name] into the frame would sort of defeat the purpose.")) + return TRUE - if(jobban_isbanned(B, "Robot")) - to_chat(user, SPAN_WARNING("\The [W] does not seem to fit.")) - return + if(jobban_isbanned(brainmob, ASSIGNMENT_ROBOT)) + to_chat(user, SPAN_WARNING("\The [used_item] does not seem to fit.")) + return TRUE - if(B.stat == DEAD) - to_chat(user, SPAN_WARNING("Sticking a dead [W.name] into the frame would sort of defeat the purpose.")) - return + if(brainmob.stat == DEAD) + to_chat(user, SPAN_WARNING("Sticking a dead [used_item.name] into the frame would sort of defeat the purpose.")) + return TRUE var/ghost_can_reenter = 0 - if(B.mind) - if(!B.key) - for(var/mob/observer/ghost/G in GLOB.player_list) - if(G.can_reenter_corpse && G.mind == B.mind) + if(brainmob.mind) + if(!brainmob.key) + for(var/mob/observer/ghost/G in global.player_list) + if(G.can_reenter_corpse && G.mind == brainmob.mind) ghost_can_reenter = 1 break else ghost_can_reenter = 1 if(!ghost_can_reenter) - to_chat(user, SPAN_WARNING("\The [W] is completely unresponsive; there's no point.")) - return + to_chat(user, SPAN_WARNING("\The [used_item] is completely unresponsive; there's no point.")) + return TRUE - if(!user.unEquip(W)) - return + if(!user.try_unequip(used_item)) + return TRUE SSstatistics.add_field("cyborg_frames_built",1) var/mob/living/silicon/robot/O = new product(get_turf(loc)) if(!O) - return + return TRUE - O.mmi = W - O.set_invisibility(0) + O.central_processor = used_item + O.set_invisibility(INVISIBILITY_NONE) O.custom_name = created_name O.updatename("Default") - B.mind.transfer_to(O) + + clear_antag_roles(brainmob.mind, implanted = TRUE) // some antag roles persist + brainmob.mind.transfer_to(O) if(O.mind && O.mind.assigned_role) O.job = O.mind.assigned_role else - O.job = "Robot" + O.job = ASSIGNMENT_ROBOT var/obj/item/robot_parts/chest/chest = parts[BP_CHEST] chest.cell.forceMove(O) - W.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. + used_item.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. // Since we "magically" installed a cell, we also have to update the correct component. if(O.cell) @@ -133,16 +129,18 @@ cell_component.installed = 1 SSstatistics.add_field("cyborg_birth",1) - callHook("borgify", list(O)) + RAISE_EVENT(/decl/observ/cyborg_created, O) O.Namepick() qdel(src) + return TRUE - else if(istype(W, /obj/item/pen)) - var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN) + else if(IS_PEN(used_item)) + var/t = sanitize_safe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN) if(t && (in_range(src, user) || loc == user)) created_name = t + return TRUE else - ..() + return ..() /obj/item/robot_parts/robot_suit/Destroy() parts.Cut() diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index 555578053fd8..f2a7ee2d6d44 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -1,22 +1,23 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 +/obj/item/borg + max_health = ITEM_HEALTH_NO_DAMAGE /********************************************************************** Cyborg Spec Items ***********************************************************************/ /obj/item/borg/overdrive name = "overdrive" - icon = 'icons/obj/decals.dmi' - icon_state = "shock" + icon = 'icons/obj/signs/warnings.dmi' + icon_state = "shock-large" /********************************************************************** HUD/SIGHT things ***********************************************************************/ /obj/item/borg/sight - icon = 'icons/obj/decals.dmi' - icon_state = "securearea" + icon = 'icons/obj/signs/warnings.dmi' + icon_state = "securearea-large" var/sight_mode = null - var/hud_type - + var/glasses_hud_type /obj/item/borg/sight/xray name = "\proper x-ray vision" @@ -26,15 +27,15 @@ /obj/item/borg/sight/thermal name = "\proper thermal vision" sight_mode = BORGTHERM - icon_state = "thermal" - icon = 'icons/obj/clothing/obj_eyes.dmi' + icon_state = "world-active" + icon = 'icons/clothing/eyes/scanner_thermal.dmi' /obj/item/borg/sight/meson name = "\proper meson vision" sight_mode = BORGMESON - icon_state = "meson" - icon = 'icons/obj/clothing/obj_eyes.dmi' + icon_state = "world-active" + icon = 'icons/clothing/eyes/scanner_meson.dmi' /obj/item/borg/sight/material name = "\proper material scanner vision" @@ -47,20 +48,19 @@ /obj/item/borg/sight/hud/med name = "medical hud" - icon_state = "healthhud" - icon = 'icons/obj/clothing/obj_eyes.dmi' - hud_type = HUD_MEDICAL + icon_state = ICON_STATE_WORLD + icon = 'icons/clothing/eyes/hud_medical.dmi' + glasses_hud_type = HUD_MEDICAL /obj/item/borg/sight/hud/med/Initialize() . = ..() hud = new /obj/item/clothing/glasses/hud/health(src) - /obj/item/borg/sight/hud/sec name = "security hud" - icon_state = "securityhud" - icon = 'icons/obj/clothing/obj_eyes.dmi' - hud_type = HUD_SECURITY + icon_state = ICON_STATE_WORLD + icon = 'icons/clothing/eyes/hud_security.dmi' + glasses_hud_type = HUD_SECURITY /obj/item/borg/sight/hud/Initialize() . = ..() @@ -69,9 +69,9 @@ /obj/item/borg/sight/hud/jani name = "janitor hud" - icon_state = "janihud" - icon = 'icons/obj/clothing/obj_eyes.dmi' - hud_type = HUD_JANITOR + icon_state = ICON_STATE_WORLD + icon = 'icons/clothing/eyes/hud_janitor.dmi' + glasses_hud_type = HUD_JANITOR /obj/item/borg/sight/hud/jani/Initialize() . = ..() diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 507bb3e73556..3fde339bc303 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -4,10 +4,9 @@ item_state = "buildpipe" icon_state = "blank" obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY material = /decl/material/solid/metal/steel - var/list/part = null // Order of args is important for installing robolimbs. var/sabotaged = 0 //Emagging limbs can have repercussions when installed as prosthetics. var/model_info var/bp_tag = null // What part is this? @@ -19,14 +18,16 @@ /obj/item/robot_parts/Initialize(mapload, var/model) . = ..(mapload) - if(model_info && model) + if(model_info) + if(!ispath(model, /decl/bodytype/prosthetic)) + model = /decl/bodytype/prosthetic/basic_human model_info = model - var/datum/robolimb/R = all_robolimbs[model] - if(R) - SetName("[R.company] [initial(name)]") - desc = "[R.desc]" - if(icon_state in icon_states(R.icon)) - icon = R.icon + var/decl/bodytype/prosthetic/robot_model = GET_DECL(model) + if(robot_model) + SetName("[robot_model.name] [initial(name)]") + desc = "[robot_model.desc]" + if(icon_state in icon_states(robot_model.icon_base)) + icon = robot_model.icon_base else SetDefaultName() @@ -40,8 +41,7 @@ name = "left arm" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." icon_state = "l_arm" - part = list(BP_L_ARM, BP_L_HAND) - model_info = 1 + model_info = TRUE bp_tag = BP_L_ARM material = /decl/material/solid/metal/steel @@ -49,8 +49,7 @@ name = "right arm" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." icon_state = "r_arm" - part = list(BP_R_ARM, BP_R_HAND) - model_info = 1 + model_info = TRUE bp_tag = BP_R_ARM material = /decl/material/solid/metal/steel @@ -58,8 +57,7 @@ name = "left leg" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." icon_state = "l_leg" - part = list(BP_L_LEG, BP_L_FOOT) - model_info = 1 + model_info = TRUE bp_tag = BP_L_LEG material = /decl/material/solid/metal/steel @@ -67,8 +65,7 @@ name = "right leg" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." icon_state = "r_leg" - part = list(BP_R_LEG, BP_R_FOOT) - model_info = 1 + model_info = TRUE bp_tag = BP_R_LEG material = /decl/material/solid/metal/steel @@ -76,8 +73,7 @@ name = "head" desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." icon_state = "head" - part = list(BP_HEAD) - model_info = 1 + model_info = TRUE bp_tag = BP_HEAD material = /decl/material/solid/metal/steel var/obj/item/flash/flash1 = null @@ -94,8 +90,7 @@ name = "torso" desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." icon_state = "chest" - part = list(BP_GROIN,BP_CHEST) - model_info = 1 + model_info = TRUE bp_tag = BP_CHEST material = /decl/material/solid/metal/steel var/wires = 0.0 @@ -111,53 +106,54 @@ success = FALSE return success && ..() -/obj/item/robot_parts/chest/attackby(obj/item/W, mob/user) - ..() - if(istype(W, /obj/item/cell)) +/obj/item/robot_parts/chest/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/cell)) if(src.cell) to_chat(user, "You have already inserted a cell!") - return else - if(!user.unEquip(W, src)) - return - src.cell = W + if(!user.try_unequip(used_item, src)) + return TRUE + src.cell = used_item to_chat(user, "You insert the cell!") - if(isCoil(W)) + return TRUE + if(IS_COIL(used_item)) if(src.wires) to_chat(user, "You have already inserted wire!") - return else - var/obj/item/stack/cable_coil/coil = W + var/obj/item/stack/cable_coil/coil = used_item if(coil.use(1)) src.wires = 1.0 to_chat(user, "You insert the wire!") - -/obj/item/robot_parts/head/attackby(obj/item/W, mob/user) - ..() - if(istype(W, /obj/item/flash)) - if(istype(user,/mob/living/silicon/robot)) - var/current_module = user.get_active_hand() - if(current_module == W) + return TRUE + return ..() + +/obj/item/robot_parts/head/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/flash)) + if(isrobot(user)) + var/current_module = user.get_active_held_item() + if(current_module == used_item) to_chat(user, "How do you propose to do that?") - return + return TRUE else - add_flashes(W,user) + add_flashes(used_item,user) else - add_flashes(W,user) + add_flashes(used_item,user) + return TRUE + return ..() -/obj/item/robot_parts/head/proc/add_flashes(obj/item/W, mob/user) //Made into a seperate proc to avoid copypasta +/obj/item/robot_parts/head/proc/add_flashes(obj/item/used_item, mob/user) //Made into a seperate proc to avoid copypasta if(src.flash1 && src.flash2) to_chat(user, "You have already inserted the eyes!") return else if(src.flash1) - if(!user.unEquip(W, src)) + if(!user.try_unequip(used_item, src)) return - src.flash2 = W + src.flash2 = used_item to_chat(user, "You insert the flash into the eye socket!") else - if(!user.unEquip(W, src)) + if(!user.try_unequip(used_item, src)) return - src.flash1 = W + src.flash1 = used_item to_chat(user, "You insert the flash into the eye socket!") diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 0acc0fe356bf..7230cd94476d 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -4,48 +4,47 @@ /obj/item/borg/upgrade name = "robot upgrade module" desc = "Protected by FRM." - icon = 'icons/obj/module.dmi' - icon_state = "cyborg_upgrade" + icon = 'icons/obj/modules/module_cyborg_0.dmi' + icon_state = ICON_STATE_WORLD material = /decl/material/solid/metal/steel - + origin_tech = @'{"materials":2,"engineering":3,"programming":3,"magnets":1}' var/locked = 0 var/require_module = 0 - var/installed = 0 -/obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/R) - if(R.stat == DEAD) - to_chat(usr, "The [src] will not function on a deceased robot.") +/obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/robot) + if(robot.stat == DEAD) + to_chat(usr, "\The [src] will not function on a deceased robot.") return 1 return 0 /obj/item/borg/upgrade/reset name = "robotic module reset board" desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." - icon_state = "cyborg_upgrade1" + icon = 'icons/obj/modules/module_cyborg_1.dmi' require_module = 1 -/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/robot) if((. = ..())) return 0 - R.reset_module() + robot.reset_module() return 1 /obj/item/borg/upgrade/uncertified name = "uncertified robotic module" desc = "You shouldn't be seeing this!" - icon_state = "cyborg_upgrade5" + icon = 'icons/obj/modules/module_cyborg_2.dmi' require_module = 0 var/new_module = null -/obj/item/borg/upgrade/uncertified/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/uncertified/action(var/mob/living/silicon/robot/robot) if((. = ..())) return 0 if(!new_module) - to_chat(usr, "[R]'s error lights strobe repeatedly - something seems to be wrong with the chip.") + to_chat(usr, "[robot]'s error lights strobe repeatedly - something seems to be wrong with the chip.") return 0 // Suppress the alert so the AI doesn't see a reset message. - R.reset_module(TRUE) - R.pick_module(new_module) + robot.reset_module(TRUE) + robot.pick_module(new_module) return 1 /obj/item/borg/upgrade/uncertified/party @@ -57,6 +56,7 @@ /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"materials":2,"engineering":2,"programming":3,"magnets":2}' /obj/item/borg/upgrade/uncertified/combat name = "ancient module" @@ -66,112 +66,113 @@ /obj/item/borg/upgrade/rename name = "robot reclassification board" desc = "Used to rename a cyborg." - icon_state = "cyborg_upgrade1" + icon = 'icons/obj/modules/module_cyborg_1.dmi' var/heldname = "default name" /obj/item/borg/upgrade/rename/attack_self(mob/user) - heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) + heldname = sanitize_safe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) -/obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/robot) if(..()) return 0 - R.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, R.name, heldname) - R.SetName(heldname) - R.custom_name = heldname - R.real_name = heldname + robot.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, robot.name, heldname) + robot.SetName(heldname) + robot.custom_name = heldname + robot.real_name = heldname return 1 /obj/item/borg/upgrade/floodlight name = "robot floodlight module" desc = "Used to boost cyborg's light intensity." - icon_state = "cyborg_upgrade1" + icon = 'icons/obj/modules/module_cyborg_1.dmi' -/obj/item/borg/upgrade/floodlight/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/floodlight/action(var/mob/living/silicon/robot/robot) if(..()) return 0 - if(R.intenselight) - to_chat(usr, "This cyborg's light was already upgraded") + if(robot.intenselight) + to_chat(usr, "This cyborg's light was already upgraded.") return 0 else - R.intenselight = 1 - R.update_robot_light() - to_chat(R, "Lighting systems upgrade detected.") + robot.intenselight = 1 + robot.update_robot_light() + to_chat(robot, "Lighting systems upgrade detected.") return 1 /obj/item/borg/upgrade/restart name = "robot emergency restart module" desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." - icon_state = "cyborg_upgrade1" + icon = 'icons/obj/modules/module_cyborg_1.dmi' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) -/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R) - if(R.health < 0) +/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/robot) + if(robot.current_health < 0) to_chat(usr, "You have to repair the robot before using this module!") return 0 - if(!R.key) - for(var/mob/observer/ghost/ghost in GLOB.player_list) - if(ghost.mind && ghost.mind.current == R) - R.key = ghost.key + if(!robot.key) + for(var/mob/observer/ghost/ghost in global.player_list) + if(ghost.mind && ghost.mind.current == robot) + robot.key = ghost.key - R.set_stat(CONSCIOUS) - R.switch_from_dead_to_living_mob_list() - R.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) + robot.set_stat(CONSCIOUS) + robot.switch_from_dead_to_living_mob_list() + robot.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) return 1 /obj/item/borg/upgrade/vtec name = "robotic VTEC Module" desc = "Used to kick in a robot's VTEC systems, increasing their speed." - icon_state = "cyborg_upgrade2" + icon = 'icons/obj/modules/module_cyborg_2.dmi' require_module = 1 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) -/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/robot) if(..()) return FALSE - if(R.vtec == TRUE) + if(robot.vtec == TRUE) return FALSE - R.speed-- - R.vtec = TRUE + robot.speed-- + robot.vtec = TRUE return TRUE /obj/item/borg/upgrade/weaponcooler name = "robotic Rapid Weapon Cooling Module" desc = "Used to cool a mounted energy gun, increasing the potential current in it and thus its recharge rate." - icon_state = "cyborg_upgrade3" + icon = 'icons/obj/modules/module_cyborg_3.dmi' require_module = 1 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"materials":2,"engineering":3,"programming":3,"powerstorage":2,"combat":2}' -/obj/item/borg/upgrade/weaponcooler/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/weaponcooler/action(var/mob/living/silicon/robot/robot) if(..()) return 0 - if(!R.module || !(type in R.module.supported_upgrades)) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + if(!robot.module || !(type in robot.module.supported_upgrades)) + to_chat(robot, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") return 0 - var/obj/item/gun/energy/gun/secure/mounted/T = locate() in R.module + var/obj/item/gun/energy/gun/secure/mounted/T = locate() in robot.module if(!T) - T = locate() in R.module.equipment + T = locate() in robot.module.equipment if(!T) to_chat(usr, "This robot has had its energy gun removed!") return 0 if(T.recharge_time <= 2) - to_chat(R, "Maximum cooling achieved for this hardpoint!") + to_chat(robot, "Maximum cooling achieved for this hardpoint!") to_chat(usr, "There's no room for another cooling unit!") return 0 @@ -183,66 +184,69 @@ /obj/item/borg/upgrade/jetpack name = "mining robot jetpack" desc = "A carbon dioxide jetpack suitable for low-gravity mining operations." - icon_state = "cyborg_upgrade3" + icon = 'icons/obj/modules/module_cyborg_3.dmi' require_module = 1 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"materials":2,"engineering":3,"programming":3,"magnets":3}' -/obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/robot) if(..()) return 0 - if(!R.module || !(type in R.module.supported_upgrades)) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + if(!robot.module || !(type in robot.module.supported_upgrades)) + to_chat(robot, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") return 0 else - R.module.equipment += new/obj/item/tank/jetpack/carbondioxide - for(var/obj/item/tank/jetpack/carbondioxide in R.module.equipment) - R.internals = src - //R.icon_state="Miner+j" + robot.module.equipment += new/obj/item/tank/jetpack/carbondioxide + for(var/obj/item/tank/jetpack/carbondioxide in robot.module.equipment) + robot.set_internals(src) + //robot.icon_state="Miner+j" return 1 /obj/item/borg/upgrade/rcd name = "engineering robot RCD" desc = "A rapid construction device module for use during construction operations." - icon_state = "cyborg_upgrade3" + icon = 'icons/obj/modules/module_cyborg_3.dmi' require_module = 1 material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"materials":4,"engineering":4,"programming":3}' -/obj/item/borg/upgrade/rcd/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/rcd/action(var/mob/living/silicon/robot/robot) if(..()) return 0 - if(!R.module || !(type in R.module.supported_upgrades)) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + if(!robot.module || !(type in robot.module.supported_upgrades)) + to_chat(robot, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") return 0 else - R.module.equipment += new/obj/item/rcd/borg(R.module) + robot.module.equipment += new/obj/item/rcd/borg(robot.module) return 1 /obj/item/borg/upgrade/syndicate name = "illegal equipment module" desc = "Unlocks the hidden, deadlier functions of a robot." - icon_state = "cyborg_upgrade3" + icon = 'icons/obj/modules/module_cyborg_3.dmi' require_module = 1 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"materials":2,"engineering":2,"programming":3,"esoteric":2,"combat":2}' -/obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/robot) if(..()) return 0 - if(R.emagged == 1) + if(robot.emagged == 1) return 0 - R.emagged = 1 + robot.emagged = 1 return 1 diff --git a/code/game/objects/items/rock.dm b/code/game/objects/items/rock.dm new file mode 100644 index 000000000000..ff0f5189bb5c --- /dev/null +++ b/code/game/objects/items/rock.dm @@ -0,0 +1,54 @@ +/obj/item/rock + name = "rock" + desc = "The secret is to bang the rocks together, guys." + icon = 'icons/obj/items/rock.dmi' + icon_state = ICON_STATE_WORLD + sharp = TRUE + edge = TRUE + _base_attack_force = 3 + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + w_class = ITEM_SIZE_SMALL + +/obj/item/rock/Initialize() + . = ..() + set_extension(src, /datum/extension/tool/variable/simple, list( + TOOL_HATCHET = TOOL_QUALITY_BAD, + TOOL_SHOVEL = TOOL_QUALITY_WORST + )) + +// TODO: craft a flint striker from a flint and a piece of metal +/obj/item/rock/attackby(obj/item/used_item, mob/user) + + var/decl/material/weapon_material = used_item.get_striking_material() + var/decl/material/our_material = get_material() + if((weapon_material?.ferrous && our_material?.type == /decl/material/solid/stone/flint) || (our_material?.ferrous && weapon_material?.type == /decl/material/solid/stone/flint)) + var/turf/spark_turf = get_turf(src) + if(loc == user) // held in inventory + var/turf/front_spark_turf = get_step_resolving_mimic(spark_turf, user.dir) + if(istype(front_spark_turf) && !front_spark_turf.density && front_spark_turf.ClickCross(global.reverse_dir[user.dir]) && user.Adjacent(front_spark_turf)) + spark_turf = front_spark_turf + if(spark_turf) + spark_at(spark_turf, amount = 2, spark_type = /datum/effect/effect/system/spark_spread/non_electrical) + return TRUE + + . = ..() + +/obj/item/rock/basalt + material = /decl/material/solid/stone/basalt + color = /decl/material/solid/stone/basalt::color + +/obj/item/rock/hematite + material = /decl/material/solid/hematite + color = /decl/material/solid/hematite::color + +/obj/item/rock/flint + material = /decl/material/solid/stone/flint + color = /decl/material/solid/stone/flint::color + +/obj/item/rock/flint/striker + name = "striker" + desc = "A squared-off, rather worn-down piece of stone." + icon = 'icons/obj/items/striker.dmi' + sharp = FALSE + edge = FALSE + w_class = ITEM_SIZE_TINY \ No newline at end of file diff --git a/code/game/objects/items/saddle.dm b/code/game/objects/items/saddle.dm new file mode 100644 index 000000000000..2fb35ce01a44 --- /dev/null +++ b/code/game/objects/items/saddle.dm @@ -0,0 +1,24 @@ +/obj/item/saddle + name = "saddle" + desc = "An arrangement of padding and straps used to make it easier to ride atop an animal." + icon = 'icons/obj/items/saddle.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + material = /decl/material/solid/organic/leather + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/item/saddle/mob_can_equip(mob/user, slot, disable_warning, force, ignore_equipped) + if(!istype(user) || !istype(user.get_bodytype(), /decl/bodytype/quadruped)) + return FALSE + return ..() + +/obj/item/saddle/equipped(mob/user, slot) + . = ..() + if(user == loc && slot == slot_back_str) + user.can_buckle = TRUE + +/obj/item/saddle/dropped(mob/user) + . = ..() + if(user) + user.can_buckle = initial(user.can_buckle) diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm deleted file mode 100644 index 60fee06d72b2..000000000000 --- a/code/game/objects/items/shooting_range.dm +++ /dev/null @@ -1,143 +0,0 @@ -// Targets, the things that actually get shot! -/obj/item/target - name = "shooting target" - desc = "A shooting target." - icon = 'icons/obj/objects.dmi' - icon_state = "target_h" - density = 0 - var/obj/structure/target_stake/stake - var/hp = 1800 - var/icon/virtualIcon - var/list/bulletholes = list() - -/obj/item/target/Destroy() - . = ..() - if (stake) - stake.set_target(null) - -/obj/item/target/attackby(var/obj/item/W, var/mob/user) - if(isWelder(W)) - var/obj/item/weldingtool/WT = W - if(WT.remove_fuel(0, user)) - overlays.Cut() - bulletholes.Cut() - hp = initial(hp) - to_chat(usr, "You slice off [src]'s uneven chunks of aluminium and scorch marks.") - return - -/obj/item/target/attack_hand(var/mob/user) - // taking pinned targets off! - if (stake) - stake.attack_hand(user) - else - return ..() - -/obj/item/target/syndicate - icon_state = "target_s" - desc = "A shooting target that looks like a hostile agent." - hp = 2600 // i guess syndie targets are sturdier? -/obj/item/target/alien - icon_state = "target_q" - desc = "A shooting target with a threatening silhouette." - hp = 2350 // alium onest too kinda - -/obj/item/target/bullet_act(var/obj/item/projectile/Proj) - var/p_x = Proj.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset Proj.p_x!" - var/p_y = Proj.p_y + pick(0,0,0,0,0,-1,1) - var/decaltype = 1 // 1 - scorch, 2 - bullet - - if(istype(/obj/item/projectile/bullet, Proj)) - decaltype = 2 - - - virtualIcon = new(icon, icon_state) - - if( virtualIcon.GetPixel(p_x, p_y) ) // if the located pixel isn't blank (null) - - hp -= Proj.damage - if(hp <= 0) - for(var/mob/O in oviewers()) - if ((O.client && !( O.blinded ))) - to_chat(O, "\The [src] breaks into tiny pieces and collapses!") - qdel(src) - - // Create a temporary object to represent the damage - var/obj/bmark = new - bmark.pixel_x = p_x - bmark.pixel_y = p_y - bmark.icon = 'icons/effects/effects.dmi' - bmark.layer = ABOVE_OBJ_LAYER - bmark.icon_state = "scorch" - - if(decaltype == 1) - // Energy weapons are hot. they scorch! - - // offset correction - bmark.pixel_x-- - bmark.pixel_y-- - - if(Proj.damage >= 20 || istype(Proj, /obj/item/projectile/beam/practice)) - bmark.icon_state = "scorch" - bmark.set_dir(pick(NORTH,SOUTH,EAST,WEST)) // random scorch design - - - else - bmark.icon_state = "light_scorch" - else - - // Bullets are hard. They make dents! - bmark.icon_state = "dent" - - if(Proj.damage >= 10 && bulletholes.len <= 35) // maximum of 35 bullet holes - if(decaltype == 2) // bullet - if(prob(Proj.damage+30)) // bullets make holes more commonly! - new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole - else // Lasers! - if(prob(Proj.damage-10)) // lasers make holes less commonly - new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole - - // draw bullet holes - for(var/datum/bullethole/B in bulletholes) - - virtualIcon.DrawBox(null, B.b1x1, B.b1y, B.b1x2, B.b1y) // horizontal line, left to right - virtualIcon.DrawBox(null, B.b2x, B.b2y1, B.b2x, B.b2y2) // vertical line, top to bottom - - overlays += bmark // add the decal - - icon = virtualIcon // apply bulletholes over decals - - return - - return PROJECTILE_CONTINUE // the bullet/projectile goes through the target! - - -// Small memory holder entity for transparent bullet holes -/datum/bullethole - // First box - var/b1x1 = 0 - var/b1x2 = 0 - var/b1y = 0 - - // Second box - var/b2x = 0 - var/b2y1 = 0 - var/b2y2 = 0 - -/datum/bullethole/New(var/obj/item/target/Target, var/pixel_x = 0, var/pixel_y = 0) - if(!Target) return - - // Randomize the first box - b1x1 = pixel_x - pick(1,1,1,1,2,2,3,3,4) - b1x2 = pixel_x + pick(1,1,1,1,2,2,3,3,4) - b1y = pixel_y - if(prob(35)) - b1y += rand(-4,4) - - // Randomize the second box - b2x = pixel_x - if(prob(35)) - b2x += rand(-4,4) - b2y1 = pixel_y + pick(1,1,1,1,2,2,3,3,4) - b2y2 = pixel_y - pick(1,1,1,1,2,2,3,3,4) - - Target.bulletholes.Add(src) \ No newline at end of file diff --git a/code/game/objects/items/silencer.dm b/code/game/objects/items/silencer.dm new file mode 100644 index 000000000000..7daa909f7ed5 --- /dev/null +++ b/code/game/objects/items/silencer.dm @@ -0,0 +1,7 @@ +/obj/item/silencer + name = "silencer" + desc = "A suppressor that screws into the barrel of compatible firearms and reduces the volume of gunshots." + icon = 'icons/obj/guns/holdout_pistol_silencer.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/steel diff --git a/code/game/objects/items/spirit_board.dm b/code/game/objects/items/spirit_board.dm index 79de05282b59..8a539d6f69d0 100644 --- a/code/game/objects/items/spirit_board.dm +++ b/code/game/objects/items/spirit_board.dm @@ -4,26 +4,20 @@ icon = 'icons/obj/objects.dmi' icon_state = "spirit_board" density = TRUE + material = /decl/material/solid/organic/wood/oak var/next_use = 0 var/planchette = "A" var/lastuser = null -/obj/item/spirit_board/examine(mob/user) - ..() - to_chat(user, "The planchette is sitting at \"[planchette]\".") +/obj/item/spirit_board/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "The planchette is sitting at \"[planchette]\"." /obj/item/spirit_board/attack_hand(mob/user) - if (user.a_intent == I_GRAB) + if(user.check_intent(I_FLAG_GRAB) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() - else - spirit_board_pick_letter(user) - - -//ATTACK GHOST IGNORING PARENT RETURN VALUE -/obj/item/spirit_board/attack_ghost(var/mob/observer/ghost/user) - if(GLOB.cult.max_cult_rating >= CULT_GHOSTS_2) - spirit_board_pick_letter(user) - return ..() + spirit_board_pick_letter(user) + return TRUE /obj/item/spirit_board/proc/spirit_board_pick_letter(mob/M) if(!spirit_board_checks(M)) @@ -56,20 +50,20 @@ if(light_amount > 0.2) - to_chat(M, SPAN_WARNING("It's too bright here to use \the [src.name]!")) + to_chat(M, SPAN_WARNING("It's too bright here to use \the [src]!")) return 0 //mobs in range check var/users_in_range = 0 for(var/mob/living/L in orange(1,src)) if(L.ckey && L.client) - if(L.client.is_afk(300) || L.incapacitated())//no playing with braindeads or corpses or handcuffed dudes. + if(L.client.is_afk(300) || L.incapacitated())//no playing with braindeads or corpses or cuffed dudes. to_chat(M, SPAN_WARNING("[L] doesn't seem to be paying attention...")) else users_in_range++ if(users_in_range < 2) - to_chat(M, SPAN_WARNING("There aren't enough people to use \the [src.name]!")) + to_chat(M, SPAN_WARNING("There aren't enough people to use \the [src]!")) return 0 return 1 \ No newline at end of file diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm deleted file mode 100644 index 709eaa281293..000000000000 --- a/code/game/objects/items/stacks/medical.dm +++ /dev/null @@ -1,360 +0,0 @@ -/obj/item/stack/medical - name = "medical pack" - singular_name = "medical pack" - icon = 'icons/obj/medical_kits.dmi' - amount = 5 - max_amount = 5 - w_class = ITEM_SIZE_SMALL - throw_speed = 4 - throw_range = 20 - - var/heal_brute = 0 - var/heal_burn = 0 - var/animal_heal = 3 - var/apply_sounds - -/obj/item/stack/medical/proc/check_limb_state(var/mob/user, var/obj/item/organ/external/limb) - . = FALSE - if(BP_IS_CRYSTAL(limb)) - to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat a crystalline limb.")) - else if(BP_IS_PROSTHETIC(limb)) - to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat a prosthetic limb.")) - else - . = TRUE - -/obj/item/stack/medical/attack(var/mob/living/carbon/M, var/mob/user) - - if (!istype(M)) - to_chat(user, SPAN_WARNING("\The [src] cannot be applied to [M]!")) - return 1 - - if ( ! (istype(user, /mob/living/carbon/human) || \ - istype(user, /mob/living/silicon)) ) - to_chat(user, SPAN_WARNING("You don't have the dexterity to do this!")) - return 1 - - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) - - if(!affecting) - to_chat(user, SPAN_WARNING("\The [M] is missing that body part!")) - return 1 - - if(!check_limb_state(user, affecting)) - return 1 - - if(affecting.organ_tag == BP_HEAD) - if(H.head && istype(H.head,/obj/item/clothing/head/helmet/space)) - to_chat(user, SPAN_WARNING("You can't apply [src] through [H.head]!")) - return 1 - else - if(H.wear_suit && istype(H.wear_suit,/obj/item/clothing/suit/space)) - to_chat(user, SPAN_WARNING("You can't apply [src] through [H.wear_suit]!")) - return 1 - - H.UpdateDamageIcon() - - else - - M.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2)) - user.visible_message( \ - SPAN_NOTICE("[M] has been applied with [src] by [user]."), \ - SPAN_NOTICE("You apply \the [src] to [M].") \ - ) - use(1) - - M.updatehealth() -/obj/item/stack/medical/bruise_pack - name = "roll of gauze" - singular_name = "gauze length" - desc = "Some sterile gauze to wrap around bloody stumps." - icon_state = "brutepack" - origin_tech = "{'biotech':1}" - animal_heal = 5 - apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg') - amount = 10 - -/obj/item/stack/medical/bruise_pack/attack(var/mob/living/carbon/M, var/mob/user) - if(..()) - return 1 - - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() - - if(affecting.is_bandaged()) - to_chat(user, SPAN_WARNING("The wounds on [M]'s [affecting.name] have already been bandaged.")) - return 1 - else - user.visible_message(SPAN_NOTICE("\The [user] starts treating [M]'s [affecting.name]."), \ - SPAN_NOTICE("You start treating [M]'s [affecting.name].")) - var/used = 0 - for (var/datum/wound/W in affecting.wounds) - if(W.bandaged) - continue - if(used == amount) - break - if(!do_mob(user, M, W.damage/5)) - to_chat(user, SPAN_NOTICE("You must stand still to bandage wounds.")) - break - - if (W.current_stage <= W.max_bleeding_stage) - user.visible_message(SPAN_NOTICE("\The [user] bandages \a [W.desc] on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You bandage \a [W.desc] on [M]'s [affecting.name].")) - //H.add_side_effect("Itch") - else if (W.damage_type == BRUISE) - user.visible_message(SPAN_NOTICE("\The [user] places a bruise patch over \a [W.desc] on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You place a bruise patch over \a [W.desc] on [M]'s [affecting.name].") ) - else - user.visible_message(SPAN_NOTICE("\The [user] places a bandaid over \a [W.desc] on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You place a bandaid over \a [W.desc] on [M]'s [affecting.name].") ) - W.bandage() - playsound(src, pick(apply_sounds), 25) - used++ - affecting.update_damages() - if(used == amount) - if(affecting.is_bandaged()) - to_chat(user, SPAN_WARNING("\The [src] is used up.")) - else - to_chat(user, SPAN_WARNING("\The [src] is used up, but there are more wounds to treat on \the [affecting.name].")) - use(used) - H.update_bandages(1) - -/obj/item/stack/medical/ointment - name = "ointment" - desc = "Used to treat those nasty burns." - gender = PLURAL - singular_name = "ointment" - icon_state = "ointment" - heal_burn = 1 - origin_tech = "{'biotech':1}" - animal_heal = 4 - apply_sounds = list('sound/effects/ointment.ogg') - -/obj/item/stack/medical/ointment/attack(var/mob/living/carbon/M, var/mob/user) - if(..()) - return 1 - - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() - - if(affecting.is_salved()) - to_chat(user, SPAN_WARNING("The wounds on [M]'s [affecting.name] have already been salved.")) - return 1 - else - user.visible_message(SPAN_NOTICE("\The [user] starts salving wounds on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You start salving the wounds on [M]'s [affecting.name].") ) - playsound(src, pick(apply_sounds), 25) - if(!do_mob(user, M, 10)) - to_chat(user, SPAN_NOTICE("You must stand still to salve wounds.")) - return 1 - user.visible_message(SPAN_NOTICE("[user] salved wounds on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You salved wounds on [M]'s [affecting.name].") ) - use(1) - affecting.salve() - affecting.disinfect() - -/obj/item/stack/medical/advanced/bruise_pack - name = "advanced trauma kit" - singular_name = "advanced trauma kit" - desc = "An advanced trauma kit for severe injuries." - icon_state = "traumakit" - heal_brute = 0 - origin_tech = "{'biotech':1}" - animal_heal = 12 - apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg','sound/effects/tape.ogg') - amount = 10 - -/obj/item/stack/medical/advanced/bruise_pack/attack(var/mob/living/carbon/M, var/mob/user) - if(..()) - return 1 - - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() - if(affecting.is_bandaged() && affecting.is_disinfected()) - to_chat(user, SPAN_WARNING("The wounds on [M]'s [affecting.name] have already been treated.")) - return 1 - else - user.visible_message(SPAN_NOTICE("\The [user] starts treating [M]'s [affecting.name]."), \ - SPAN_NOTICE("You start treating [M]'s [affecting.name].") ) - var/used = 0 - for (var/datum/wound/W in affecting.wounds) - if (W.bandaged && W.disinfected) - continue - if(used == amount) - break - if(!do_mob(user, M, W.damage/5)) - to_chat(user, SPAN_NOTICE("You must stand still to bandage wounds.")) - break - if (W.current_stage <= W.max_bleeding_stage) - user.visible_message(SPAN_NOTICE("\The [user] cleans \a [W.desc] on [M]'s [affecting.name] and seals the edges with bioglue."), \ - SPAN_NOTICE("You clean and seal \a [W.desc] on [M]'s [affecting.name].") ) - else if (W.damage_type == BRUISE) - user.visible_message(SPAN_NOTICE("\The [user] places a medical patch over \a [W.desc] on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You place a medical patch over \a [W.desc] on [M]'s [affecting.name].") ) - else - user.visible_message(SPAN_NOTICE("\The [user] smears some bioglue over \a [W.desc] on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You smear some bioglue over \a [W.desc] on [M]'s [affecting.name].") ) - playsound(src, pick(apply_sounds), 25) - W.bandage() - W.disinfect() - W.heal_damage(heal_brute) - used++ - affecting.update_damages() - if(used == amount) - if(affecting.is_bandaged()) - to_chat(user, SPAN_WARNING("\The [src] is used up.")) - else - to_chat(user, SPAN_WARNING("\The [src] is used up, but there are more wounds to treat on \the [affecting.name].")) - use(used) - H.update_bandages(1) - -/obj/item/stack/medical/advanced/ointment - name = "advanced burn kit" - singular_name = "advanced burn kit" - desc = "An advanced treatment kit for severe burns." - icon_state = "burnkit" - heal_burn = 5 - origin_tech = "{'biotech':1}" - animal_heal = 7 - apply_sounds = list('sound/effects/ointment.ogg') - - -/obj/item/stack/medical/advanced/ointment/attack(var/mob/living/carbon/M, var/mob/user) - if(..()) - return 1 - - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() - - if(affecting.is_salved()) - to_chat(user, SPAN_WARNING("The wounds on [M]'s [affecting.name] have already been salved.")) - return 1 - else - user.visible_message(SPAN_NOTICE("\The [user] starts salving wounds on [M]'s [affecting.name]."), \ - SPAN_NOTICE("You start salving the wounds on [M]'s [affecting.name].") ) - playsound(src, pick(apply_sounds), 25) - if(!do_mob(user, M, 10)) - to_chat(user, SPAN_NOTICE("You must stand still to salve wounds.")) - return 1 - user.visible_message( SPAN_NOTICE("[user] covers wounds on [M]'s [affecting.name] with regenerative membrane."), \ - SPAN_NOTICE("You cover wounds on [M]'s [affecting.name] with regenerative membrane.") ) - affecting.heal_damage(0,heal_burn) - use(1) - affecting.salve() - affecting.disinfect() - -/obj/item/stack/medical/splint - name = "medical splints" - singular_name = "medical splint" - desc = "Modular splints capable of supporting and immobilizing bones in both limbs and appendages." - icon_state = "splint" - amount = 5 - max_amount = 5 - animal_heal = 0 - var/list/splintable_organs = list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT) //List of organs you can splint, natch. - -/obj/item/stack/medical/splint/check_limb_state(var/mob/user, var/obj/item/organ/external/limb) - if(BP_IS_PROSTHETIC(limb)) - to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat a prosthetic limb.")) - return FALSE - return TRUE - -/obj/item/stack/medical/splint/attack(var/mob/living/carbon/M, var/mob/user) - if(..()) - return 1 - - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) //nullchecked by ..() - var/limb = affecting.name - if(!(affecting.organ_tag in splintable_organs)) - to_chat(user, SPAN_DANGER("You can't use \the [src] to apply a splint there!")) - return - if(affecting.splinted) - to_chat(user, SPAN_DANGER("[M]'s [limb] is already splinted!")) - return - if (M != user) - user.visible_message(SPAN_DANGER("[user] starts to apply \the [src] to [M]'s [limb]."), SPAN_DANGER("You start to apply \the [src] to [M]'s [limb]."), SPAN_DANGER("You hear something being wrapped.")) - else - if(( !user.hand && (affecting.organ_tag in list(BP_R_ARM, BP_R_HAND)) || \ - user.hand && (affecting.organ_tag in list(BP_L_ARM, BP_L_HAND)) )) - to_chat(user, SPAN_DANGER("You can't apply a splint to the arm you're using!")) - return - user.visible_message(SPAN_DANGER("[user] starts to apply \the [src] to their [limb]."), SPAN_DANGER("You start to apply \the [src] to your [limb]."), SPAN_DANGER("You hear something being wrapped.")) - if(user.do_skilled(5 SECONDS, SKILL_MEDICAL, M)) - if((M == user && prob(75)) || prob(user.skill_fail_chance(SKILL_MEDICAL,50, SKILL_ADEPT))) - user.visible_message(SPAN_DANGER("\The [user] fumbles [src]."), SPAN_DANGER("You fumble [src]."), SPAN_DANGER("You hear something being wrapped.")) - return - var/obj/item/stack/medical/splint/S = split(1, TRUE) - if(S) - if(affecting.apply_splint(S)) - M.verbs += /mob/living/carbon/human/proc/remove_splints - S.forceMove(affecting) - if (M != user) - user.visible_message(SPAN_DANGER("\The [user] finishes applying [src] to [M]'s [limb]."), SPAN_DANGER("You finish applying \the [src] to [M]'s [limb]."), SPAN_DANGER("You hear something being wrapped.")) - else - user.visible_message(SPAN_DANGER("\The [user] successfully applies [src] to their [limb]."), SPAN_DANGER("You successfully apply \the [src] to your [limb]."), SPAN_DANGER("You hear something being wrapped.")) - return - S.dropInto(src.loc) //didn't get applied, so just drop it - user.visible_message(SPAN_DANGER("\The [user] fails to apply [src]."), SPAN_DANGER("You fail to apply [src]."), SPAN_DANGER("You hear something being wrapped.")) - return - -/obj/item/stack/medical/splint/ghetto - name = "makeshift splints" - singular_name = "makeshift splint" - desc = "For holding your limbs in place with duct tape and scrap metal." - icon_state = "tape-splint" - amount = 1 - splintable_organs = list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) - -/obj/item/stack/medical/resin - name = "resin patches" - singular_name = "resin patch" - desc = "A resin-based patching kit used to repair crystalline bodyparts. The label is written in a colourful, angular, unreadable script." - icon_state = "resin-pack" - heal_brute = 10 - heal_burn = 10 - -/obj/item/stack/medical/resin/drone - amount = 25 - max_amount = 25 - -/obj/item/stack/medical/resin/handmade - name = "resin globules" - desc = "A lump of slick, shiny resin. Used to repair damage to crystalline bodyparts." - singular_name = "resin globule" - icon_state = "resin-lump" - heal_brute = 5 - heal_burn = 5 - -/obj/item/stack/medical/resin/check_limb_state(var/mob/user, var/obj/item/organ/external/limb) - if(!BP_IS_PROSTHETIC(limb) && !BP_IS_CRYSTAL(limb)) - to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat an organic limb.")) - return FALSE - return TRUE - -/obj/item/stack/medical/resin/attack(var/mob/living/carbon/M, var/mob/user) - . = ..() - if(!. && ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) - if((affecting.brute_dam + affecting.burn_dam) <= 0) - to_chat(user, SPAN_WARNING("\The [M]'s [affecting.name] is undamaged.")) - return 1 - user.visible_message( - SPAN_NOTICE("\The [user] starts patching fractures on \the [M]'s [affecting.name]."), \ - SPAN_NOTICE("You start patching fractures on \the [M]'s [affecting.name].") ) - playsound(src, pick(apply_sounds), 25) - if(!do_mob(user, M, 10)) - to_chat(user, SPAN_NOTICE("You must stand still to patch fractures.")) - return 1 - user.visible_message( \ - SPAN_NOTICE("\The [user] patches the fractures on \the [M]'s [affecting.name] with resin."), \ - SPAN_NOTICE("You patch fractures on \the [M]'s [affecting.name] with resin.")) - affecting.heal_damage(heal_brute, heal_burn, robo_repair = TRUE) - use(1) diff --git a/code/game/objects/items/stacks/medical/_medical.dm b/code/game/objects/items/stacks/medical/_medical.dm new file mode 100644 index 000000000000..8a7cb9a017aa --- /dev/null +++ b/code/game/objects/items/stacks/medical/_medical.dm @@ -0,0 +1,103 @@ +/obj/item/stack/medical + abstract_type = /obj/item/stack/medical + icon = 'icons/obj/medical_kits.dmi' + amount = 5 + max_amount = 5 + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 20 + + var/heal_brute = 0 + var/heal_burn = 0 + var/animal_heal = 3 + +/obj/item/stack/medical/proc/get_apply_sounds() + return + +/obj/item/stack/medical/proc/play_apply_sound() + var/list/apply_sounds = get_apply_sounds() + if(length(apply_sounds)) + playsound(loc, pick(apply_sounds), 25) + +// Returns the number of stacks to use. +/obj/item/stack/medical/proc/try_treat_limb(mob/living/target, mob/living/user, obj/item/organ/external/affecting) + return 0 + +/obj/item/stack/medical/proc/check_limb_state(var/mob/user, var/obj/item/organ/external/limb) + . = FALSE + if(BP_IS_CRYSTAL(limb)) + to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat a crystalline limb.")) + else if(BP_IS_PROSTHETIC(limb)) + to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat a prosthetic limb.")) + else + . = TRUE + +/obj/item/stack/medical/proc/limb_is_injured(obj/item/organ/external/affecting) + return length(affecting.wounds) > 0 + +/obj/item/stack/medical/proc/get_covering_clothing(mob/living/target, obj/item/organ/external/affecting) + // For perfect coverage checks; generally considered too restrictive but left for reference. + // return target.get_covering_equipped_item(affecting.body_part) + // More limited coverage checking: + var/static/list/check_slots = list( + slot_wear_suit_str, + slot_head_str, + slot_wear_mask_str + ) + for(var/check_slot in check_slots) + var/obj/item/checking = target.get_equipped_item(check_slot) + if(checking && (checking.body_parts_covered & affecting.body_part)) + return checking + +/obj/item/stack/medical/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(!user_can_attack_with(user) || user.check_intent(I_FLAG_HARM)) + return ..() + + if(get_amount() < 1) + to_chat(user, SPAN_WARNING("You need at least 1 [singular_name] to treat injuries.")) + return TRUE + + // If they have organs, we try to treat a specific organ being targeted. + if(target.has_organs()) + + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(target, user.get_target_zone()) + if(!affecting) + to_chat(user, SPAN_WARNING("\The [target] is missing that body part!")) + return TRUE + + if(!limb_is_injured(affecting)) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] has no wounds to treat.")) + return FALSE + + if(!check_limb_state(user, affecting)) + return TRUE + + + var/obj/item/covering = get_covering_clothing(target, affecting) + if(covering) + to_chat(user, SPAN_WARNING("You can't apply \the [src] through \the [covering]!")) + return TRUE + + var/use_stacks = try_treat_limb(target, user, affecting) + if(use_stacks) + use(use_stacks) + return TRUE + + // Simpler mobs just use general damage handlers. + if(!target.getBruteLoss() && !target.getFireLoss()) + to_chat(user, SPAN_WARNING("\The [target] has no injuries to treat.")) + return TRUE + + if(target.isSynthetic()) + to_chat(user, SPAN_WARNING("\The [target] is synthetic and cannot be treated with \the [src].")) + return TRUE + + target.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2)) + user.visible_message( + SPAN_NOTICE("\The [user] treats \the [target] with \the [src]."), + SPAN_NOTICE("You treat \the [target] with \the [src].") + ) + play_apply_sound() + use(1) + return TRUE diff --git a/code/game/objects/items/stacks/medical/medical_bandage.dm b/code/game/objects/items/stacks/medical/medical_bandage.dm new file mode 100644 index 000000000000..cd0ca1efdc10 --- /dev/null +++ b/code/game/objects/items/stacks/medical/medical_bandage.dm @@ -0,0 +1,175 @@ +/obj/item/stack/medical/bandage + name = "roll of gauze" + singular_name = "length of gauze" + plural_name = "lengths of gauze" + desc = "Some sterile gauze to wrap around bloody stumps." + icon_state = "brutepack" + origin_tech = @'{"biotech":1}' + animal_heal = 5 + amount = 10 + material = /decl/material/solid/organic/cloth + matter_multiplier = 0.3 + // Reagents required to craft a single poultice. + var/static/list/poultice_reagent_requirements = list( + /decl/material/liquid/antitoxins/ginseng = 1, + /decl/material/liquid/brute_meds/yarrow = 1, + /decl/material/liquid/burn_meds/aloe = 1 + ) + +/obj/item/stack/medical/bandage/get_apply_sounds() + var/static/list/apply_sounds = list( + 'sound/effects/rip1.ogg', + 'sound/effects/rip2.ogg' + ) + return apply_sounds + +/obj/item/stack/medical/bandage/proc/get_poultice_requirement_string() + . = list() + for(var/decl/material/reagent as anything in poultice_reagent_requirements) + . += "[poultice_reagent_requirements[reagent.type]] unit\s of [reagent.liquid_name]" + . = english_list(.) + +/obj/item/stack/medical/bandage/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/poultice_requirement_string = get_poultice_requirement_string() + if(poultice_requirement_string) + . += SPAN_NOTICE("With a mixture of [poultice_requirement_string], you could use a bandage to make a herbal poultice.") + +/obj/item/stack/medical/bandage/attackby(obj/item/used_item, mob/living/user) + + // Making a poultice. + if(istype(used_item, /obj/item/chems) && used_item.reagents && ATOM_IS_OPEN_CONTAINER(used_item)) + + var/create_poultices = get_amount() + var/missing_reagent = FALSE + for(var/reagent in poultice_reagent_requirements) + var/available_amt = round(REAGENT_VOLUME(used_item.reagents, reagent) / poultice_reagent_requirements[reagent]) + if(available_amt) + create_poultices = min(create_poultices, available_amt) + else + missing_reagent = TRUE + break + + // If we have enough reagents, create poultices, otherwise, warn the user. + if(create_poultices <= 0 || missing_reagent) + var/poultice_requirement_string = get_poultice_requirement_string() + if(poultice_requirement_string) + to_chat(user, SPAN_WARNING("You need at least [poultice_requirement_string] to make one herbal poultice.")) + else + var/obj/item/stack/medical/ointment/crafted/poultices = new(get_turf(src), create_poultices) + user.put_in_hands(poultices) + user.visible_message("\The [user] carefully pours the herbal mash into the bandage, making [poultices.get_amount()] poultice\s.") + for(var/reagent in poultice_reagent_requirements) + used_item.reagents.remove_reagent(reagent, create_poultices * poultice_reagent_requirements[reagent]) + use(create_poultices) + return TRUE + + return ..() + +/obj/item/stack/medical/bandage/proc/can_bandage_wound(datum/wound/wound) + return !wound.bandaged + +/obj/item/stack/medical/bandage/proc/can_bandage_limb(obj/item/organ/external/affecting) + return !affecting.is_bandaged() + +/obj/item/stack/medical/bandage/proc/bandage_wound(mob/user, mob/target, obj/item/organ/external/affecting, datum/wound/wound) + user.visible_message( + SPAN_NOTICE("\The [user] bandages \a [wound.desc] on \the [target]'s [affecting.name]."), + SPAN_NOTICE("You bandage \a [wound.desc] on \the [target]'s [affecting.name].") + ) + wound.bandage() + +/obj/item/stack/medical/bandage/try_treat_limb(mob/living/target, mob/living/user, obj/item/organ/external/affecting) + + if(!can_bandage_limb(affecting)) + to_chat(user, SPAN_WARNING("The wounds on [target]'s [affecting.name] have already been bandaged.")) + return FALSE + + user.visible_message( + SPAN_NOTICE("\The [user] starts treating [target]'s [affecting.name]."), + SPAN_NOTICE("You start treating [target]'s [affecting.name].") + ) + + . = 0 + for (var/datum/wound/wound in affecting.wounds) + + if(!can_bandage_wound(wound)) + continue + + if(!do_mob(user, target, wound.damage/5)) + to_chat(user, SPAN_WARNING("You must stand still to treat \the [target]'s wounds.")) + break + + if(QDELETED(src) || QDELETED(target) || QDELETED(affecting) || !user.Adjacent(target) || loc != user || get_amount() <= 0) + break + + bandage_wound(user, target, affecting, wound) + play_apply_sound() + .++ + if(. >= get_amount()) + break + + if(. && !QDELETED(affecting)) + affecting.update_damages() + if(!QDELETED(target)) + if(. >= amount && !QDELETED(user)) + if(affecting.is_bandaged()) + to_chat(user, SPAN_WARNING("You use the last of \the [src] to treat \the [target]'s [affecting.name].")) + else + to_chat(user, SPAN_WARNING("You use the last of \the [src] to treat \the [target]'s [affecting.name], but there are wounds left to be treated.")) + target.update_bandages(TRUE) + +/obj/item/stack/medical/bandage/crafted + name = "bandage" + singular_name = "bandage" + plural_name = "bandages" + icon_state = "bandage" + desc = "Some clean material cut into lengths suitable for bandaging wounds." + amount = 1 + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/stack/medical/bandage/crafted/five + amount = 5 + +/obj/item/stack/medical/bandage/crafted/ten + amount = 10 + +/obj/item/stack/medical/bandage/advanced + name = "advanced trauma kit" + singular_name = "advanced trauma kit" + desc = "An advanced trauma kit for severe injuries." + icon_state = "traumakit" + heal_brute = 0 + origin_tech = @'{"biotech":1}' + animal_heal = 12 + amount = 10 + +/obj/item/stack/medical/bandage/advanced/can_bandage_wound(datum/wound/wound) + return !wound.disinfected || ..() + +/obj/item/stack/medical/bandage/advanced/can_bandage_limb(obj/item/organ/external/affecting) + return !affecting.is_disinfected() || ..() + +/obj/item/stack/medical/bandage/advanced/get_apply_sounds() + var/static/list/apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg','sound/effects/tape.ogg') + return apply_sounds + +/obj/item/stack/medical/bandage/advanced/bandage_wound(mob/user, mob/target, obj/item/organ/external/affecting, datum/wound/wound) + if (wound.current_stage <= wound.max_bleeding_stage) + user.visible_message( + SPAN_NOTICE("\The [user] cleans \a [wound.desc] on [target]'s [affecting.name] and seals the edges with bioglue."), + SPAN_NOTICE("You clean and seal \a [wound.desc] on [target]'s [affecting.name].") + ) + else if (wound.damage_type == BRUISE) + user.visible_message( + SPAN_NOTICE("\The [user] places a medical patch over \a [wound.desc] on [target]'s [affecting.name]."), + SPAN_NOTICE("You place a medical patch over \a [wound.desc] on [target]'s [affecting.name].") + ) + else + user.visible_message( + SPAN_NOTICE("\The [user] smears some bioglue over \a [wound.desc] on [target]'s [affecting.name]."), + SPAN_NOTICE("You smear some bioglue over \a [wound.desc] on [target]'s [affecting.name].") + ) + wound.bandage() + wound.disinfect() + wound.heal_damage(heal_brute) diff --git a/code/game/objects/items/stacks/medical/medical_ointment.dm b/code/game/objects/items/stacks/medical/medical_ointment.dm new file mode 100644 index 000000000000..2701d5db03b1 --- /dev/null +++ b/code/game/objects/items/stacks/medical/medical_ointment.dm @@ -0,0 +1,72 @@ +/obj/item/stack/medical/ointment + name = "ointment" + desc = "An antibacterial ointment used to treat burns and prevent infections." + gender = PLURAL + singular_name = "ointment" + icon_state = "ointment" + heal_burn = 1 + origin_tech = @'{"biotech":1}' + animal_heal = 4 + +/obj/item/stack/medical/ointment/get_apply_sounds() + var/static/list/apply_sounds = list( + 'sound/effects/ointment.ogg' + ) + return apply_sounds + +/obj/item/stack/medical/ointment/try_treat_limb(mob/living/target, mob/living/user, obj/item/organ/external/affecting) + if(affecting.is_salved()) + to_chat(user, SPAN_WARNING("The wounds on [target]'s [affecting.name] have already been salved.")) + return 0 + user.visible_message( + SPAN_NOTICE("\The [user] starts salving wounds on [target]'s [affecting.name]."), + SPAN_NOTICE("You start salving the wounds on [target]'s [affecting.name].") + ) + play_apply_sound() + if(!do_mob(user, target, 1 SECOND)) + to_chat(user, SPAN_WARNING("You must stand still to salve wounds.")) + return 0 + show_limb_salve_message(user, target, affecting) + affecting.salve() + affecting.disinfect() + return 1 // consume 1 stack + +/obj/item/stack/medical/ointment/proc/show_limb_salve_message(mob/living/user, mob/living/target, obj/item/organ/external/affecting) + user.visible_message( + SPAN_NOTICE("\The [user] salves the wounds on \the [target]'s [affecting.name]."), + SPAN_NOTICE("You salve the wounds on \the [target]'s [affecting.name].") + ) + +/obj/item/stack/medical/ointment/crafted + name = "poultice" + gender = NEUTER + singular_name = "poultice" + plural_name = "poultices" + icon_state = "poultice" + desc = "A bandage soaked in a medicinal herbal mixture, good for treating burns and preventing infections." + animal_heal = 3 + +/obj/item/stack/medical/ointment/crafted/five + amount = 5 + +/obj/item/stack/medical/ointment/crafted/ten + amount = 10 + +/obj/item/stack/medical/ointment/advanced + name = "advanced burn kit" + singular_name = "advanced burn kit" + desc = "An advanced treatment kit for severe burns." + icon_state = "burnkit" + heal_burn = 5 + origin_tech = @'{"biotech":1}' + animal_heal = 7 + +/obj/item/stack/medical/ointment/advanced/get_apply_sounds() + var/static/list/apply_sounds = list('sound/effects/ointment.ogg') + return apply_sounds + +/obj/item/stack/medical/ointment/advanced/show_limb_salve_message(mob/living/user, mob/living/target, obj/item/organ/external/affecting) + user.visible_message( + SPAN_NOTICE("[user] covers wounds on [target]'s [affecting.name] with regenerative membrane."), + SPAN_NOTICE("You cover wounds on [target]'s [affecting.name] with regenerative membrane.") + ) diff --git a/code/game/objects/items/stacks/medical/medical_resin.dm b/code/game/objects/items/stacks/medical/medical_resin.dm new file mode 100644 index 000000000000..c7ab7c5f060c --- /dev/null +++ b/code/game/objects/items/stacks/medical/medical_resin.dm @@ -0,0 +1,44 @@ +/obj/item/stack/medical/resin + name = "resin patches" + singular_name = "resin patch" + desc = "A resin-based patching kit used to repair crystalline body parts. The label is written in a colourful, angular, unreadable script." + icon_state = "resin-pack" + heal_brute = 10 + heal_burn = 10 + +/obj/item/stack/medical/resin/drone + amount = 25 + max_amount = 25 + +/obj/item/stack/medical/resin/crafted + name = "resin globules" + desc = "A lump of slick, shiny resin. Used to repair damage to crystalline body parts." + singular_name = "resin globule" + icon_state = "resin-lump" + heal_brute = 5 + heal_burn = 5 + +/obj/item/stack/medical/resin/check_limb_state(var/mob/user, var/obj/item/organ/external/limb) + if(!BP_IS_PROSTHETIC(limb) && !BP_IS_CRYSTAL(limb)) + to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat an organic limb.")) + return FALSE + return TRUE + +/obj/item/stack/medical/resin/try_treat_limb(mob/living/target, mob/living/user, obj/item/organ/external/affecting) + if((affecting.brute_dam + affecting.burn_dam) <= 0) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is undamaged.")) + return 0 + user.visible_message( + SPAN_NOTICE("\The [user] starts patching fractures on \the [target]'s [affecting.name]."), + SPAN_NOTICE("You start patching fractures on \the [target]'s [affecting.name].") + ) + play_apply_sound() + if(!do_mob(user, target, 1 SECOND)) + to_chat(user, SPAN_WARNING("You must stand still to patch fractures.")) + return 0 + user.visible_message( + SPAN_NOTICE("\The [user] patches the fractures on \the [target]'s [affecting.name] with resin."), + SPAN_NOTICE("You patch fractures on \the [target]'s [affecting.name] with resin.") + ) + affecting.heal_damage(heal_brute, heal_burn, robo_repair = TRUE) + return 1 diff --git a/code/game/objects/items/stacks/medical/medical_splint.dm b/code/game/objects/items/stacks/medical/medical_splint.dm new file mode 100644 index 000000000000..1d268de10cd5 --- /dev/null +++ b/code/game/objects/items/stacks/medical/medical_splint.dm @@ -0,0 +1,110 @@ +/obj/item/stack/medical/splint + name = "medical splints" + singular_name = "medical splint" + plural_name = "medical splints" + desc = "Modular splints capable of supporting and immobilizing bones in both limbs and appendages." + icon_state = "splint" + amount = 5 + max_amount = 5 + animal_heal = 0 + +/obj/item/stack/medical/splint/proc/get_splitable_organs() + var/static/list/splintable_organs = list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT) //List of organs you can splint, natch. + return splintable_organs + +/obj/item/stack/medical/splint/limb_is_injured(obj/item/organ/external/affecting) + return (affecting.status & ORGAN_BROKEN) + +/obj/item/stack/medical/splint/check_limb_state(var/mob/user, var/obj/item/organ/external/limb) + if(BP_IS_PROSTHETIC(limb)) + to_chat(user, SPAN_WARNING("You cannot use \the [src] to treat a prosthetic limb.")) + return FALSE + return TRUE + +/obj/item/stack/medical/splint/try_treat_limb(mob/living/target, mob/living/user, obj/item/organ/external/affecting) + + if(!(affecting.organ_tag in get_splitable_organs())) + to_chat(user, SPAN_WARNING("You can't use \the [src] to apply a splint there!")) + return 0 + + var/limb = affecting.name + if(affecting.splinted) + to_chat(user, SPAN_WARNING("\The [target]'s [limb] is already splinted!")) + return 0 + + if (target != user) + user.visible_message( + SPAN_NOTICE("\The [user] starts to apply \the [src] to [target]'s [limb]."), + SPAN_DANGER("You start to apply \the [src] to [target]'s [limb]."), + SPAN_DANGER("You hear something being wrapped.") + ) + else + var/obj/item/organ/external/using = GET_EXTERNAL_ORGAN(user, user.get_active_held_item_slot()) + if(istype(using) && (affecting == using || (affecting in using.children) || affecting.organ_tag == using.parent_organ)) + to_chat(user, SPAN_WARNING("You can't apply a splint to the arm you're using!")) + return 0 + user.visible_message( + SPAN_NOTICE("\The [user] starts to apply \the [src] to their [limb]."), + SPAN_DANGER("You start to apply \the [src] to your [limb]."), + SPAN_DANGER("You hear something being wrapped.") + ) + + if(user.do_skilled(5 SECONDS, SKILL_MEDICAL, target)) + if((target == user && prob(75)) || prob(user.skill_fail_chance(SKILL_MEDICAL,50, SKILL_ADEPT))) + user.visible_message( + SPAN_DANGER("\The [user] fumbles \the [src]."), + SPAN_DANGER("You fumble \the [src]."), + SPAN_DANGER("You hear something being wrapped.") + ) + return 0 + var/obj/item/stack/medical/splint/splint = split(1, TRUE) + if(splint) + if(affecting.apply_splint(splint)) + target.verbs += /mob/living/human/proc/remove_splints + splint.forceMove(affecting) + if (target != user) + user.visible_message( + SPAN_NOTICE("\The [user] finishes applying \the [src] to \the [target]'s [limb]."), + SPAN_DANGER("You finish applying \the [src] to \the [target]'s [limb]."), + SPAN_DANGER("You hear something being wrapped.") + ) + else + user.visible_message( + SPAN_NOTICE("\The [user] successfully applies \the [src] to their [limb]."), + SPAN_DANGER("You successfully apply \the [src] to your [limb]."), + SPAN_DANGER("You hear something being wrapped.") + ) + return 0 + splint.dropInto(src.loc) //didn't get applied, so just drop it + user.visible_message( + SPAN_DANGER("\The [user] fails to apply \the [src]."), + SPAN_DANGER("You fail to apply \the [src]."), + SPAN_DANGER("You hear something being wrapped.") + ) + // We handle using the stack via split() above, so don't ever return a numeric value. + return 0 + +/obj/item/stack/medical/splint/crafted + name = "splints" + singular_name = "splint" + plural_name = "splints" + icon_state = "simple-splint" + amount = 1 + material = /decl/material/solid/organic/wood/oak + matter = list( + /decl/material/solid/organic/cloth = MATTER_AMOUNT_REINFORCEMENT + ) + +/obj/item/stack/medical/splint/crafted/five + amount = 5 + +/obj/item/stack/medical/splint/improvised + name = "makeshift splints" + singular_name = "makeshift splint" + desc = "For holding your limbs in place with duct tape and scrap metal." + icon_state = "tape-splint" + amount = 1 + +/obj/item/stack/medical/splint/improvised/get_splitable_organs() + var/static/list/splintable_organs = list(BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) + return splintable_organs diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index c82a9747394b..0c4581d6c17f 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -4,46 +4,67 @@ desc = "A tube of paste containing swarms of repair nanites. Very effective in repairing robotic machinery." icon = 'icons/obj/nanopaste.dmi' icon_state = "tube" - origin_tech = "{'materials':4,'engineering':3}" + origin_tech = @'{"materials":4,"engineering":3}' + max_amount = 10 amount = 10 material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) -/obj/item/stack/nanopaste/attack(mob/living/M, mob/user) - if (!istype(M) || !istype(user)) - return 0 - if (istype(M,/mob/living/silicon/robot)) //Repairing cyborgs - var/mob/living/silicon/robot/R = M - if (R.getBruteLoss() || R.getFireLoss() ) +/obj/item/stack/nanopaste/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if (!istype(target)) + to_chat(user, SPAN_WARNING("\The [src] cannot be applied to \the [target]!")) + return TRUE + + if (!ishuman(user) && !issilicon(user)) + to_chat(user, SPAN_WARNING("You don't have the dexterity to do this!")) + return TRUE + + if (isrobot(target)) //Repairing cyborgs + var/mob/living/silicon/robot/robot = target + if (robot.getBruteLoss() || robot.getFireLoss() ) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - R.adjustBruteLoss(-15) - R.adjustFireLoss(-15) - R.updatehealth() + robot.heal_damage(BRUTE, 15, do_update_health = FALSE) + robot.heal_damage(BURN, 15) use(1) - user.visible_message("\The [user] applied some [src] on [R]'s damaged areas.",\ - "You apply some [src] at [R]'s damaged areas.") + user.visible_message( + SPAN_NOTICE("\The [user] applied some [name] to \the [robot]'s damaged areas."), + SPAN_NOTICE("You apply some [name] to \the [robot]'s damaged areas.") + ) else - to_chat(user, "All [R]'s systems are nominal.") - - if (istype(M,/mob/living/carbon/human)) //Repairing robolimbs - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/S = H.get_organ(user.zone_sel.selecting) - - if(!S) - to_chat(user, "\The [M] is missing that body part.") - return - - if(BP_IS_BRITTLE(S)) - to_chat(user, "\The [M]'s [S.name] is hard and brittle - \the [src] cannot repair it.") - return - - if(S && S.is_robotic() && S.hatch_state == HATCH_OPENED) - if(!S.get_damage()) - to_chat(user, "Nothing to fix here.") - else if(can_use(1)) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - S.heal_damage(15, 15, robo_repair = 1) - H.updatehealth() - use(1) - user.visible_message("\The [user] applies some nanite paste on [user != M ? "[M]'s [S.name]" : "[S]"] with [src].",\ - "You apply some nanite paste on [user == M ? "your" : "[M]'s"] [S.name].") + to_chat(user, SPAN_NOTICE("\The [robot]'s systems are all nominal.")) + return TRUE + + //Repairing robolimbs + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(target, user.get_target_zone()) + + if(!affecting) + to_chat(user, SPAN_WARNING("\The [target] is missing that body part.")) + return TRUE + + if(BP_IS_BRITTLE(affecting)) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is hard and brittle - \the [src] cannot repair it.")) + return TRUE + + if(!affecting.is_robotic()) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is flesh and blood, and cannot be repaired with \the [src].")) + return TRUE + + if((affecting.brute_dam + affecting.burn_dam) >= 30 && affecting.hatch_state != HATCH_OPENED) + to_chat(user, SPAN_WARNING("The damage to \the [affecting] is too severe to repair without an open maintenance hatch.")) + return TRUE + + if(!affecting.get_damage()) + to_chat(user, SPAN_NOTICE("Nothing to fix here.")) + return TRUE + + if(can_use(1)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + affecting.heal_damage(15, 15, robo_repair = 1) + use(1) + user.visible_message( + SPAN_NOTICE("\The [user] applies some [name] to \the [user != target ? "[target]'s [affecting.name]" : "[affecting]"] with [src]."), + SPAN_NOTICE("You apply some [name] to [user == target ? "your" : "\the [target]'s"] [affecting.name].") + ) + return TRUE + return ..() diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index e8152475b6ee..1a8d655c9dd1 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -1,52 +1,44 @@ /obj/item/stack/material/rods - name = "rod" - desc = "Some rods. Can be used for building, or something." - singular_name = "rod" - plural_name = "rods" - icon_state = "rod" - plural_icon_state = "rod-mult" - max_icon_state = "rod-max" - w_class = ITEM_SIZE_LARGE - attack_cooldown = 21 + name = "rod" + desc = "Some rods. Can be used for building, or something." + singular_name = "rod" + plural_name = "rods" + icon_state = "rod" + plural_icon_state = "rod-mult" + max_icon_state = "rod-max" + w_class = ITEM_SIZE_LARGE + attack_cooldown = 21 melee_accuracy_bonus = -20 - throw_speed = 5 - throw_range = 20 - max_amount = 100 - attack_verb = list("hit", "bludgeoned", "whacked") - lock_picking_level = 3 - matter_multiplier = 0.3 - material_flags = USE_MATERIAL_COLOR - stacktype = /obj/item/stack/material/rods - material = /decl/material/solid/metal/steel + throw_speed = 5 + throw_range = 20 + max_amount = 100 + attack_verb = list("hit", "bludgeoned", "whacked") + lock_picking_level = 3 + matter_multiplier = 0.3 + material = /decl/material/solid/metal/steel + crafting_stack_type = /obj/item/stack/material/rods + pickup_sound = 'sound/foley/tooldrop3.ogg' + drop_sound = 'sound/foley/tooldrop2.ogg' /obj/item/stack/material/rods/get_autopsy_descriptors() . = ..() . += "narrow" -/obj/item/stack/material/rods/ten - amount = 10 - -/obj/item/stack/material/rods/fifty - amount = 50 - /obj/item/stack/material/rods/cyborg - name = "metal rod synthesizer" - desc = "A device that makes metal rods." - gender = NEUTER - matter = null - uses_charge = 1 - charge_costs = list(500) + name = "metal rod synthesizer" + desc = "A device that makes metal rods." + gender = NEUTER + matter = null + uses_charge = 1 + charge_costs = list(500) + max_health = ITEM_HEALTH_NO_DAMAGE /obj/item/stack/material/rods/Initialize() . = ..() update_icon() - throwforce = round(0.25*material.get_edge_damage()) - force = round(0.5*material.get_blunt_damage()) + set_extension(src, /datum/extension/tool, list(TOOL_SURGICAL_DRILL = TOOL_QUALITY_WORST)) -/obj/item/stack/material/on_update_icon() - if(material_flags & USE_MATERIAL_COLOR) - color = material.color - alpha = 100 + max(1, amount/25)*(material.opacity * 255) +/obj/item/stack/material/rods/update_state_from_amount() if(max_icon_state && amount > 0.5*max_amount) icon_state = max_icon_state else if(plural_icon_state && amount >= 2) @@ -54,40 +46,38 @@ else icon_state = base_state -/obj/item/stack/material/rods/attackby(obj/item/W, mob/user) - if(isWelder(W)) - var/obj/item/weldingtool/WT = W +// TODO: slapcrafting recipes to replace this block. +/obj/item/stack/material/rods/attackby(obj/item/used_item, mob/user) + + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item if(!can_use(2)) - to_chat(user, "You need at least two rods to do this.") - return + to_chat(user, SPAN_WARNING("You need at least two rods to do this.")) + return TRUE + + if(welder.weld(0,user)) + visible_message(SPAN_NOTICE("\The [src] is fused together by \the [user] with \the [welder]."), 3, SPAN_NOTICE("You hear welding."), 2) + for(var/obj/item/stack/material/new_item in SSmaterials.create_object((material?.type || /decl/material/solid/metal/steel), usr.loc, 1)) + new_item.add_to_stacks(usr) + if(user.is_holding_offhand(src)) + user.put_in_hands(new_item) + use(2) + return TRUE - if(WT.remove_fuel(0,user)) - var/obj/item/stack/material/steel/new_item = new(usr.loc) - new_item.add_to_stacks(usr) - for (var/mob/M in viewers(src)) - M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2) - var/obj/item/stack/material/rods/R = src - src = null - var/replace = (user.get_inactive_hand()==R) - R.use(2) - if (!R && replace) - user.put_in_hands(new_item) - return + if (istype(used_item, /obj/item/stack/tape_roll/duct_tape)) + var/obj/item/stack/tape_roll/duct_tape/T = used_item + if(!T.can_use(4)) + to_chat(user, SPAN_WARNING("You need 4 [T.plural_name] to make a splint!")) + return TRUE + T.use(4) - if (istype(W, /obj/item/tape_roll)) - var/obj/item/stack/medical/splint/ghetto/new_splint = new(user.loc) + var/obj/item/stack/medical/splint/improvised/new_splint = new(user.loc) new_splint.dropInto(loc) new_splint.add_fingerprint(user) - - user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \ - "You use make \a [new_splint] out of a [singular_name].") + playsound(user, 'sound/effects/tape.ogg', 50, TRUE) + user.visible_message(SPAN_NOTICE("\The [user] constructs \a [new_splint] out of a [singular_name]."), \ + SPAN_NOTICE("You use make \a [new_splint] out of a [singular_name].")) src.use(1) - return - - ..() - -/obj/item/stack/material/rods/attack_self(mob/user) - add_fingerprint(user) - if(istype(user.loc, /turf)) - place_grille(user, user.loc, src) + return TRUE + return ..() diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index e6d8e5e40775..2a48ee7fd1b5 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -11,51 +11,104 @@ /obj/item/stack gender = PLURAL - origin_tech = "{'materials':1}" - + origin_tech = @'{"materials":1}' + max_health = 32 //Stacks should take damage even if no materials + /// A copy of initial matter list when this atom initialized. Stack matter should always assume a single tile. + var/list/matter_per_piece + var/name_modifier var/singular_name var/plural_name + /// If unset, picks a/an based off of if the first letter is a vowel or not. + var/indefinite_article var/base_state var/plural_icon_state var/max_icon_state var/amount = 1 - var/list/initial_matter var/matter_multiplier = 1 - var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount - var/stacktype //determines whether different stack types can merge + var/max_amount + var/stack_merge_type //determines whether different stack types can merge var/build_type //used when directly applied to a turf var/uses_charge var/list/charge_costs var/list/datum/matter_synth/synths - var/list/datum/stack_recipe/recipes + /// Set this to a specific type to restrict the recipes generated by this stack. + var/crafting_stack_type = /obj/item/stack + var/craft_verb + var/craft_verbing /obj/item/stack/Initialize(mapload, amount, material) if(ispath(amount, /decl/material)) - crash_with("Stack initialized with material ([amount]) instead of amount.") + PRINT_STACK_TRACE("Stack initialized with material ([amount]) instead of amount.") material = amount if (isnum(amount) && amount >= 1) src.amount = amount . = ..(mapload, material) - if (!stacktype) - stacktype = type + if(!stack_merge_type) + stack_merge_type = type + if(!singular_name) + singular_name = "sheet" if(!plural_name) - plural_name = "[singular_name]s" + plural_name = text_make_plural(singular_name) + update_name() + +/obj/item/stack/update_name() + if(amount == 1) + gender = NEUTER + SetName(singular_name) + else + gender = PLURAL + SetName(plural_name) /obj/item/stack/Destroy() - if(uses_charge) - return 1 if (src && usr && usr.machine == src) close_browser(usr, "window=stack") + if(length(synths)) + synths.Cut() return ..() -/obj/item/stack/examine(mob/user, distance) +/obj/item/stack/proc/delete_if_empty() + if (uses_charge) + return FALSE + var/real_amount = get_amount() + if (real_amount <= 0) + on_used_last() + return TRUE + return FALSE + +/obj/item/stack/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - if(!uses_charge) - to_chat(user, "There [src.amount == 1 ? "is" : "are"] [src.amount] [src.singular_name]\s in the stack.") + if(uses_charge) + . += "There is enough charge for [get_amount()]." else - to_chat(user, "There is enough charge for [get_amount()].") + . += "There [src.amount == 1 ? "is" : "are"] [src.amount] [src.singular_name]\s in the stack." + +/obj/item/stack/on_update_icon() + . = ..() + if(!isturf(loc)) + var/image/I = image(null) + I.plane = HUD_PLANE + I.layer = HUD_ABOVE_ITEM_LAYER + I.appearance_flags |= (RESET_COLOR|RESET_TRANSFORM) + I.maptext_x = 2 + I.maptext_y = 2 + I.maptext = STYLE_SMALLFONTS_OUTLINE(get_amount(), 6, (color || COLOR_WHITE), COLOR_BLACK) + add_overlay(I) + else + compile_overlays() // prevent maptext from showing when we're dropped + +/obj/item/stack/Move() + var/on_turf = isturf(loc) + . = ..() + if(. && on_turf != isturf(loc)) + update_icon() + +/obj/item/stack/forceMove() + var/on_turf = isturf(loc) + . = ..() + if(. && on_turf != isturf(loc)) + update_icon() /obj/item/stack/attack_self(mob/user) list_recipes(user) @@ -63,168 +116,220 @@ /obj/item/stack/get_matter_amount_modifier() . = amount * matter_multiplier -/obj/item/stack/proc/list_recipes(mob/user, recipes_sublist) - if (!recipes) +/obj/item/stack/proc/get_reinforced_material() + return null + +// TODO: add some kind of tracking for the last viewed list so the user can go back up one level for nested lists +/obj/item/stack/proc/list_recipes(mob/user, list/recipes) + + if(!user?.client) return - if (!src || get_amount() <= 0) - close_browser(user, "window=stack") - user.set_machine(src) //for correct work of onclose - var/list/recipe_list = recipes - if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list)) - var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist] - recipe_list = srl.recipes - var/t1 = list() - t1 += "Constructions from [src]Amount Left: [src.get_amount()]
              " - for(var/i=1;i<=recipe_list.len,i++) - var/E = recipe_list[i] - if (isnull(E)) - continue - if (istype(E, /datum/stack_recipe_list)) - t1+="
              " - var/datum/stack_recipe_list/srl = E - t1 += "\[Sub-menu] [srl.title]" - - if (istype(E, /datum/stack_recipe)) - var/datum/stack_recipe/R = E - t1+="
              " - var/max_multiplier = round(src.get_amount() / R.req_amount) - var/title - var/can_build = 1 - can_build = can_build && (max_multiplier>0) - if (R.res_amount>1) - title+= "[R.res_amount]x [R.display_name()]\s" - else - title+= "[R.display_name()]" - title+= " ([R.req_amount] [src.singular_name]\s)" - var/skill_label = "" - if(!user.skill_check(SKILL_CONSTRUCTION, R.difficulty)) - var/decl/hierarchy/skill/S = decls_repository.get_decl(SKILL_CONSTRUCTION) - skill_label = "\[[S.levels[R.difficulty]]]" - if (can_build) - t1 +="[skill_label][title]" - else - t1 += "[skill_label][title]" - if (R.max_res_amount>1 && max_multiplier>1) - max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount)) - t1 += " |" - var/list/multipliers = list(5,10,25) - for (var/n in multipliers) - if (max_multiplier>=n) - t1 += " [n*R.res_amount]x" - if (!(max_multiplier in multipliers)) - t1 += " [max_multiplier*R.res_amount]x" - - t1 += "
              " - show_browser(user, JOINTEXT(t1), "window=stack") - onclose(user, "stack") - -/obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user) - var/required = quantity*recipe.req_amount - var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount) - - if (!can_use(required)) - if (produced>1) - to_chat(user, "You haven't got enough [src] to build \the [produced] [recipe.display_name()]\s!") - else - to_chat(user, "You haven't got enough [src] to build \the [recipe.display_name()]!") + if(get_amount() <= 0) + close_browser(user, "window=stack_crafting") return - if(!recipe.can_make(user)) + if(!recipes) + recipes = get_stack_recipes(get_material(), get_reinforced_material(), crafting_stack_type, user?.get_active_held_item()?.get_best_tool_archetype()) + + var/list/dat = list() + + var/popup_title + var/datum/stack_recipe_list/recipe_list = recipes + if (istype(recipe_list)) + popup_title = "Crafting [recipe_list.name] with \the [src]" + dat += "

              Back

              " + recipes = recipe_list.recipes + else if(islist(recipes) && length(recipes)) + popup_title = "Crafting with \the [src]" + else return - if (recipe.time) - to_chat(user, "Building [recipe.display_name()] ...") - if (!user.do_skilled(recipe.time, SKILL_CONSTRUCTION)) - return + dat += "

              [capitalize(plural_name)] left: [get_amount()]

              " + dat += "" + dat += "" + var/list/recipe_strings = list() + for(var/thing in recipes) + if(istype(thing, /decl/stack_recipe)) + var/decl/stack_recipe/recipe = thing + recipe_strings[recipe.name] = recipe.get_list_display(user, src, recipe_list) + else if(istype(thing, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/sub_recipe_list = thing + recipe_strings[sub_recipe_list.name] = sub_recipe_list.get_list_display(user, src) + for(var/recipe_name in sortTim(recipe_strings.Copy(), /proc/cmp_text_asc)) + dat += recipe_strings[recipe_name] + dat += "
              ProductCostTimeRequired skillAmount to craft
              " + + var/datum/browser/popup = new(user, "stack_crafting", popup_title, 800, 800) + popup.set_content(JOINTEXT(dat)) + popup.open() + + +/obj/item/stack/proc/produce_recipe(decl/stack_recipe/recipe, var/producing, var/expending, mob/user, paint_color) + + if(producing <= 0 || expending <= 0 || expending > get_amount()) + return - if (use(required)) - if(user.skill_fail_prob(SKILL_CONSTRUCTION, 90, recipe.difficulty)) - to_chat(user, "You waste some [name] and fail to build \the [recipe.display_name()]!") - return - var/atom/O = recipe.spawn_result(user, user.loc, produced) - if(!QDELETED(O)) // In case of stack merger. - O.add_fingerprint(user) - user.put_in_hands(O) - -/obj/item/stack/Topic(href, href_list) - ..() - if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) + if(expending > recipe.get_required_stack_amount(src, product_amount = producing)) + PRINT_STACK_TRACE("Possible HREF hacking attempt, recipe amount consumed and produced doesn't match!") return - if (href_list["sublist"] && !href_list["make"]) - list_recipes(usr, text2num(href_list["sublist"])) + var/decl/material/mat = get_material() + var/decl/material/reinf_mat = get_reinforced_material() + if (!can_use(expending)) + to_chat(user, SPAN_WARNING("You haven't got enough [plural_name] to [recipe.get_craft_verb(src)] [recipe.get_display_name(producing, mat, reinf_mat)]!")) + return + if(!recipe.can_make(user)) + return + var/used_skill = recipe.get_skill(mat, reinf_mat) + var/used_difficulty = recipe.get_skill_difficulty(mat, reinf_mat) + var/used_time = recipe.get_adjusted_time(mat, reinf_mat) + if (used_time) + to_chat(user, SPAN_NOTICE("You set about [recipe.get_craft_verbing(src)] [recipe.get_display_name(producing, mat, reinf_mat)]...")) + if (!user.do_skilled(used_time, used_skill)) + return - if (href_list["make"]) - if (src.get_amount() < 1) qdel(src) //Never should happen + if(!use(expending)) + return - var/list/recipes_list = recipes - if (href_list["sublist"]) - var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])] - recipes_list = srl.recipes + if(user.skill_fail_prob(used_skill, 90, used_difficulty)) + to_chat(user, SPAN_WARNING("You waste some [name] and fail to [recipe.get_craft_verb(src)] [recipe.get_display_name(producing, mat, reinf_mat)]!")) + return - var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])] - var/multiplier = text2num(href_list["multiplier"]) - if (!multiplier || (multiplier <= 0)) //href exploit protection - return + to_chat(user, SPAN_NOTICE("You [recipe.get_craft_verb(src)] [recipe.get_display_name(producing, mat, reinf_mat)]!")) + var/list/atom/results = recipe.spawn_result(user, user.loc, producing, mat, reinf_mat, paint_color, crafting_stack_type, expending) + var/was_put_in_hand = FALSE + for(var/atom/result in results) + if(QDELETED(result)) + continue + result.add_fingerprint(user) + if(isitem(result) && !was_put_in_hand) + if(user.put_in_hands(result)) + was_put_in_hand = TRUE - src.produce_recipe(R, multiplier, usr) +/obj/item/stack/OnTopic(mob/user, list/href_list) + . = ..() - if (src && usr.machine==src) //do not reopen closed window - spawn( 0 ) - src.interact(usr) - return - return + if(. || !istype(user) || QDELETED(user) || user.incapacitated() || !((src in user.get_held_items()) || Adjacent(user))) + return TOPIC_NOACTION -//Return 1 if an immediate subsequent call to use() would succeed. -//Ensures that code dealing with stacks uses the same logic + if(href_list["back"]) + var/datum/stack_recipe_list/previous_list = locate(href_list["back"]) + if(istype(previous_list)) + list_recipes(user, previous_list) + else + list_recipes(user) + return TOPIC_HANDLED + + if(href_list["sublist"]) + + var/datum/stack_recipe_list/recipe_list = locate(href_list["sublist"]) + if(istype(recipe_list)) + var/list/recipes = get_stack_recipes(get_material(), get_reinforced_material(), crafting_stack_type, user?.get_active_held_item()?.get_best_tool_archetype()) + if(recipe_list in recipes) + list_recipes(user, recipe_list) + return TOPIC_HANDLED + return TOPIC_NOACTION + + if(href_list["make"]) + + // Retrieve our recipe decl. + var/decl/stack_recipe/recipe = locate(href_list["make"]) + if(!istype(recipe)) + return TOPIC_NOACTION + + // Check that the recipe is still available to us. + var/list/recipes = get_stack_recipes(get_material(), get_reinforced_material(), crafting_stack_type, user?.get_active_held_item()?.get_best_tool_archetype()) + if(!(recipe in recipes)) + var/found_recipe = FALSE + for(var/datum/stack_recipe_list/recipe_list in recipes) + if(recipe in recipe_list.recipes) + found_recipe = TRUE + break + if(!found_recipe) + return TOPIC_NOACTION + + // Validate the target amount and create the product. + var/producing = text2num(href_list["producing"]) + var/expending = text2num(href_list["expending"]) + var/datum/stack_recipe_list/returning = locate(href_list["returning"]) + if(producing > 0 && expending > 0 && expending <= recipe.get_required_stack_amount(src, product_amount = producing)) + produce_recipe(recipe, producing, expending, user, paint_color) + list_recipes(user, returning) + return TOPIC_HANDLED // Don't attempt to refresh, list_recipes should handle that already... + + return TOPIC_NOACTION + +/** + * Return 1 if an immediate subsequent call to use() would succeed. + * Ensures that code dealing with stacks uses the same logic. +*/ /obj/item/stack/proc/can_use(var/used) - if (get_amount() < used) - return 0 - return 1 + return get_amount() >= used /obj/item/stack/create_matter() - ..() - initial_matter = matter?.Copy() + // Append our material, if set; this would normally be done in the parent call. + if(istype(material)) + LAZYSET(matter, material.type, MATTER_AMOUNT_PRIMARY) // No matter_multiplier as this is applied below. + + // We do this here rather than a parent call because the base application would multiply by our stack amount. + // We want to keep a base init matter list so that we know how much matter is in one unit of the stack. + if(LAZYLEN(matter)) + matter_per_piece = list() + for(var/mat in matter) + matter_per_piece[mat] = round(matter[mat] * matter_multiplier) + + // No parent call because we're already tracking our materials and we're going to rebuild the matter list in + // update_matter() immediately anyway. + update_matter() + +// Nuke and rebuild matter from our matter_per_piece list to keep all our values in line. /obj/item/stack/proc/update_matter() - matter = initial_matter?.Copy() - create_matter() + if(length(matter_per_piece)) + matter = list() + for(var/mat in matter_per_piece) + matter[mat] = (matter_per_piece[mat] * amount) + else + matter_per_piece = null + matter = null /obj/item/stack/proc/use(var/used) if (!can_use(used)) - return 0 + return FALSE if(!uses_charge) amount -= used - if (amount <= 0) - qdel(src) //should be safe to qdel immediately since if someone is still using this stack it will persist for a little while longer - else + if(!delete_if_empty()) update_icon() update_matter() - return 1 - else - if(get_amount() < used) - return 0 - for(var/i = 1 to charge_costs.len) - var/datum/matter_synth/S = synths[i] - S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted - return 1 + return TRUE + if(get_amount() < used) + return FALSE + for(var/i = 1 to charge_costs.len) + var/datum/matter_synth/S = synths[i] + S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted + update_name() + update_icon() + return TRUE + +/obj/item/stack/proc/on_used_last() + qdel(src) //should be safe to qdel immediately since if someone is still using this stack it will persist for a little while longer /obj/item/stack/proc/add(var/extra) if(!uses_charge) if(amount + extra > get_max_amount()) - return 0 + return FALSE else amount += extra update_icon() update_matter() - return 1 else if(!synths || synths.len < uses_charge) - return 0 + return FALSE else for(var/i = 1 to uses_charge) var/datum/matter_synth/S = synths[i] S.add_charge(charge_costs[i] * extra) + return TRUE /* The transfer and split procs work differently than use() and add(). @@ -233,10 +338,10 @@ */ //attempts to transfer amount to S, and returns the amount actually transferred -/obj/item/stack/proc/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) - if (!get_amount()) +/obj/item/stack/proc/transfer_to(obj/item/stack/S, var/tamount=null) + if (!get_amount() || !istype(S)) return 0 - if ((stacktype != S.stacktype) && !type_verified) + if (stack_merge_type != S.stack_merge_type) return 0 if (isnull(tamount)) tamount = src.get_amount() @@ -246,6 +351,11 @@ var/orig_amount = src.get_amount() if (transfer && src.use(transfer)) S.add(transfer) + S.drying_wetness = max(drying_wetness, S.drying_wetness) + if(!S.dried_type && dried_type) + S.dried_type = dried_type + if(!QDELETED(src)) + drying_wetness = S.drying_wetness if (prob(transfer/orig_amount * 100)) transfer_fingerprints_to(S) return transfer @@ -253,16 +363,15 @@ //creates a new stack with the specified amount /obj/item/stack/proc/split(var/tamount, var/force=FALSE) - if (!amount) - return null - if(uses_charge && !force) + if (!can_split() || !amount || (uses_charge && !force)) return null - var/transfer = max(min(tamount, src.amount, initial(max_amount)), 0) + var/transfer = max(min(tamount, amount, initial(max_amount)), 0) var/orig_amount = src.amount if (transfer && src.use(transfer)) - var/obj/item/stack/newstack = new src.type(loc, transfer) + var/obj/item/stack/newstack = new src.type(loc, transfer, material?.type) + newstack.dropInto(loc) // avoid being placed inside mobs newstack.copy_from(src) if (prob(transfer/orig_amount * 100)) transfer_fingerprints_to(newstack) @@ -270,7 +379,9 @@ return null /obj/item/stack/proc/copy_from(var/obj/item/stack/other) - color = other.color + other.set_color(paint_color) + dried_type = other.dried_type + drying_wetness = other.drying_wetness /obj/item/stack/proc/get_amount() if(uses_charge) @@ -301,51 +412,85 @@ /obj/item/stack/proc/add_to_stacks(mob/user, check_hands) var/list/stacks = list() if(check_hands && user) - if(isstack(user.l_hand)) - stacks += user.l_hand - if(isstack(user.r_hand)) - stacks += user.r_hand + for(var/obj/item/stack/item in user.get_held_items()) + stacks |= item for (var/obj/item/stack/item in user?.loc) - stacks += item + stacks |= item + for (var/obj/item/stack/item in loc) + stacks |= item for (var/obj/item/stack/item in stacks) - if (item==src) + if(item == src || !(can_merge_stacks(item) || item.can_merge_stacks(src))) continue - var/transfer = src.transfer_to(item) + var/transfer = transfer_to(item) if(user && transfer) - to_chat(user, "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s.") + to_chat(user, SPAN_NOTICE("You add [item.get_string_for_amount(transfer)] to the stack. It now contains [item.amount] [item.singular_name]\s.")) if(!amount) break + return !QDELETED(src) /obj/item/stack/get_storage_cost() //Scales storage cost to stack size . = ..() if (amount < max_amount) . = ceil(. * amount / max_amount) +/obj/item/stack/get_mass() // Scales mass to stack size + . = ..() + if (amount < max_amount) + . *= amount / max_amount // Don't round, this can be non-integer + /obj/item/stack/attack_hand(mob/user) - if (user.get_inactive_hand() == src) - var/N = input("How many stacks of [src] would you like to split off?", "Split stacks", 1) as num|null - if(N) - var/obj/item/stack/F = src.split(N) - if (F) - user.put_in_hands(F) - src.add_fingerprint(user) - F.add_fingerprint(user) - spawn(0) - if (src && usr.machine==src) - src.interact(usr) - else - ..() - return + if(!user.is_holding_offhand(src) || !can_split()) + return ..() + + var/N = input(user, "How many stacks of [src] would you like to split off?", "Split stacks", 1) as num|null + if(!N) + return TRUE -/obj/item/stack/attackby(obj/item/W, mob/user) - if (istype(W, /obj/item/stack)) - var/obj/item/stack/S = W - src.transfer_to(S) + var/obj/item/stack/F = src.split(N) + if(F) + user.put_in_hands(F) + src.add_fingerprint(user) + F.add_fingerprint(user) + spawn(0) + if (src && usr.machine==src) + src.interact(usr) + return TRUE + +/obj/item/stack/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/stack) && can_merge_stacks(used_item)) + var/obj/item/stack/S = used_item + . = src.transfer_to(S) spawn(0) //give the stacks a chance to delete themselves if necessary if (S && usr.machine==S) S.interact(usr) if (src && usr.machine==src) src.interact(usr) - else - return ..() + return + + return ..() + +/**Whether a stack has the capability to be split. */ +/obj/item/stack/proc/can_split() + return !(uses_charge && !is_robot_module(src)) + +/**Whether a stack type has the capability to be merged. */ +/obj/item/stack/proc/can_merge_stacks(var/obj/item/stack/other) + return !(uses_charge && !is_robot_module(src)) && (!istype(other) || other.paint_color == paint_color) + +/// Returns the string describing an amount of the stack, i.e. "an ingot" vs "a flag" +/obj/item/stack/proc/get_string_for_amount(amount) + if(amount == 1) + if(gender == PLURAL) + return "some [singular_name]" + return indefinite_article ? "[indefinite_article] [singular_name]" : ADD_ARTICLE(singular_name) + return "[amount] [plural_name]" + +/obj/item/stack/ProcessAtomTemperature() + . = ..() + if(QDELETED(src)) + return + matter_per_piece = list() + for(var/mat in matter) + matter_per_piece[mat] = round(matter[mat] / amount) + update_icon() diff --git a/code/game/objects/items/stacks/stack_serde.dm b/code/game/objects/items/stacks/stack_serde.dm new file mode 100644 index 000000000000..53702ee76722 --- /dev/null +++ b/code/game/objects/items/stacks/stack_serde.dm @@ -0,0 +1,3 @@ +/obj/item/stack/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(amount, /obj/item/stack) diff --git a/code/game/objects/items/stacks/telecrystal.dm b/code/game/objects/items/stacks/telecrystal.dm index ea9c00691bba..0926f80cd805 100644 --- a/code/game/objects/items/stacks/telecrystal.dm +++ b/code/game/objects/items/stacks/telecrystal.dm @@ -7,7 +7,7 @@ w_class = ITEM_SIZE_TINY max_amount = 50 item_flags = ITEM_FLAG_NO_BLUDGEON - origin_tech = "{'materials':6,'wormholes':4}" + origin_tech = @'{"materials":6,"wormholes":4}' /obj/item/stack/telecrystal/afterattack(var/obj/item/I, mob/user, proximity) if(!proximity) diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 3f91a8fbb6bf..79f64d66a684 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -10,19 +10,40 @@ /obj/item/stack/tile name = "tile" singular_name = "tile" - desc = "A non-descript floor tile." + desc = "A nondescript floor tile." randpixel = 7 w_class = ITEM_SIZE_NORMAL max_amount = 100 icon = 'icons/obj/tiles.dmi' - matter_multiplier = 0.15 - - force = 1 - throwforce = 1 + matter_multiplier = 0.2 throw_speed = 5 throw_range = 20 item_flags = 0 obj_flags = 0 + _base_attack_force = 1 + var/replacement_turf_type = /turf/floor/plating + +/obj/item/stack/tile/proc/try_build_turf(var/mob/user, var/turf/target) + + if(!target.is_plating()) + return FALSE + + var/ladder = (locate(/obj/structure/ladder) in target) + if(ladder) + to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) + return FALSE + + var/obj/structure/lattice/lattice = locate(/obj/structure/lattice, target) + if(!lattice && target.is_open()) + to_chat(user, SPAN_WARNING("The tiles need some support, build a lattice first.")) + return FALSE + + if(use(1)) + playsound(target, 'sound/weapons/Genhit.ogg', 50, 1) + target.ChangeTurf(replacement_turf_type, keep_air = TRUE) + qdel(lattice) + return TRUE + return FALSE /* * Grass @@ -32,84 +53,28 @@ singular_name = "grass floor tile" desc = "A patch of grass like they often use on golf courses." icon_state = "tile_grass" - origin_tech = "{'biotech':1}" - -/* - * Wood - */ -/obj/item/stack/tile/wood - name = "wood floor tile" - singular_name = "wood floor tile" - desc = "An easy to fit wooden floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_GENERIC - material = /decl/material/solid/wood - -/obj/item/stack/tile/wood/cyborg - name = "wood floor tile synthesizer" - desc = "A device that makes wood floor tiles." - uses_charge = 1 - charge_costs = list(250) - stacktype = /obj/item/stack/tile/wood - build_type = /obj/item/stack/tile/wood - -/obj/item/stack/tile/mahogany - name = "mahogany floor tile" - singular_name = "mahogany floor tile" - desc = "An easy to fit mahogany wood floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood - -/obj/item/stack/tile/maple - name = "maple floor tile" - singular_name = "maple floor tile" - desc = "An easy to fit maple wood floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_PALE - material = /decl/material/solid/wood - -/obj/item/stack/tile/ebony - name = "ebony floor tile" - singular_name = "ebony floor tile" - desc = "An easy to fit ebony floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_BLACK - material = /decl/material/solid/wood - -/obj/item/stack/tile/walnut - name = "walnut floor tile" - singular_name = "walnut floor tile" - desc = "An easy to fit walnut wood floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_CHOCOLATE - material = /decl/material/solid/wood - -/obj/item/stack/tile/bamboo - name = "bamboo floor tile" - singular_name = "bamboo floor tile" - desc = "An easy to fit bamboo wood floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_PALE2 - material = /decl/material/solid/wood - -/obj/item/stack/tile/yew - name = "yew floor tile" - singular_name = "yew floor tile" - desc = "An easy to fit yew wood floor tile." - icon_state = "tile-wood" - color = WOOD_COLOR_YELLOW - material = /decl/material/solid/wood + origin_tech = @'{"biotech":1}' + +/obj/item/stack/tile/woven + name = "woven tile" + singular_name = "woven floor tile" + desc = "A piece of woven material suitable for covering the floor." + icon_state = "woven" + origin_tech = @'{"biotech":1}' + material = /decl/material/solid/organic/plantmatter/grass/dry + color = COLOR_BEIGE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + replacement_turf_type = /turf/floor/woven /obj/item/stack/tile/floor name = "steel floor tile" singular_name = "steel floor tile" - desc = "Those could work as a pretty decent throwing weapon." //why? + desc = "Some square sections of flooring. They have a satisfying heft in the hand." icon_state = "tile" - force = 6 material = /decl/material/solid/metal/steel - throwforce = 15 obj_flags = OBJ_FLAG_CONDUCTIBLE + _thrown_force_multiplier = 1 // floor tiles were always good throwing weapons for no apparent reason + _base_attack_force = 6 /obj/item/stack/tile/mono name = "steel mono tile" @@ -171,7 +136,7 @@ name = "white floor tile" singular_name = "white floor tile" icon_state = "tile_white" - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic /obj/item/stack/tile/floor_white/fifty amount = 50 @@ -189,7 +154,7 @@ name = "freezer floor tile" singular_name = "freezer floor tile" icon_state = "tile_freezer" - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic /obj/item/stack/tile/floor_freezer/fifty amount = 50 @@ -201,8 +166,22 @@ matter = null uses_charge = 1 charge_costs = list(250) - stacktype = /obj/item/stack/tile/floor + stack_merge_type = /obj/item/stack/tile/floor build_type = /obj/item/stack/tile/floor + max_health = ITEM_HEALTH_NO_DAMAGE + is_spawnable_type = FALSE + +/obj/item/stack/tile/roof/cyborg + name = "roofing tile synthesizer" + desc = "A device that makes roofing tiles." + gender = NEUTER + matter = null + uses_charge = 1 + charge_costs = list(500) + stack_merge_type = /obj/item/stack/tile/roof + build_type = /obj/item/stack/tile/roof + max_health = ITEM_HEALTH_NO_DAMAGE + is_spawnable_type = FALSE /obj/item/stack/tile/linoleum name = "linoleum" @@ -215,7 +194,7 @@ /obj/item/stack/tile/stone name = "stone slabs" - singular name = "stone slab" + singular_name = "stone slab" desc = "A smooth, flat slab of some kind of stone." icon_state = "tile_stone" @@ -223,82 +202,184 @@ * Carpets */ /obj/item/stack/tile/carpet + build_type = /obj/item/stack/tile/carpet name = "brown carpet" singular_name = "brown carpet" desc = "A piece of brown carpet." - icon_state = "tile_carpetbrown" + icon_state = "tile_carpet" + material = /decl/material/solid/organic/cloth + paint_color = "#6e391d" + var/detail_color = "#aa6300" + +/obj/item/stack/tile/carpet/Initialize() + . = ..() + update_icon() + +/obj/item/stack/tile/carpet/on_update_icon() + . = ..() + if(detail_color) + add_overlay(overlay_image(icon, "[icon_state]_detail", detail_color, RESET_COLOR)) /obj/item/stack/tile/carpet/fifty amount = 50 -/obj/item/stack/tile/carpetblue +/obj/item/stack/tile/carpet/blue + build_type = /obj/item/stack/tile/carpet/blue name = "blue carpet" desc = "A piece of blue and gold carpet." singular_name = "blue carpet" - icon_state = "tile_carpetblue" + paint_color = "#464858" -/obj/item/stack/tile/carpetblue/fifty +/obj/item/stack/tile/carpet/blue/fifty amount = 50 -/obj/item/stack/tile/carpetblue2 +/obj/item/stack/tile/carpet/blue2 + build_type = /obj/item/stack/tile/carpet/blue2 name = "pale blue carpet" desc = "A piece of blue and pale blue carpet." singular_name = "pale blue carpet" - icon_state = "tile_carpetblue2" + paint_color = "#356287" + detail_color = "#868e96" -/obj/item/stack/tile/carpetblue2/fifty +/obj/item/stack/tile/carpet/blue2/fifty amount = 50 -/obj/item/stack/tile/carpetblue3 +/obj/item/stack/tile/carpet/blue3 + build_type = /obj/item/stack/tile/carpet/blue3 name = "sea blue carpet" desc = "A piece of blue and green carpet." singular_name = "sea blue carpet" - icon_state = "tile_carpetblue3" + detail_color = "#528c3c" + paint_color = "#356287" -/obj/item/stack/tile/carpetblue3/fifty +/obj/item/stack/tile/carpet/blue3/fifty amount = 50 -/obj/item/stack/tile/carpetmagenta +/obj/item/stack/tile/carpet/magenta + build_type = /obj/item/stack/tile/carpet/magenta name = "magenta carpet" desc = "A piece of magenta carpet." singular_name = "magenta carpet" - icon_state = "tile_carpetmagenta" + paint_color = "#91265e" + detail_color = "#be6208" -/obj/item/stack/tile/carpetmagenta/fifty +/obj/item/stack/tile/carpet/magenta/fifty amount = 50 -/obj/item/stack/tile/carpetpurple +/obj/item/stack/tile/carpet/purple + build_type = /obj/item/stack/tile/carpet/purple name = "purple carpet" desc = "A piece of purple carpet." singular_name = "purple carpet" - icon_state = "tile_carpetpurple" + paint_color = "#4f3365" + detail_color = "#a25204" -/obj/item/stack/tile/carpetpurple/fifty +/obj/item/stack/tile/carpet/purple/fifty amount = 50 -/obj/item/stack/tile/carpetorange +/obj/item/stack/tile/carpet/orange + build_type = /obj/item/stack/tile/carpet/orange name = "orange carpet" desc = "A piece of orange carpet." singular_name = "orange carpet" - icon_state = "tile_carpetorange" + paint_color = "#9d480c" + detail_color = "#d07708" -/obj/item/stack/tile/carpetorange/fifty +/obj/item/stack/tile/carpet/orange/fifty amount = 50 -/obj/item/stack/tile/carpetgreen +/obj/item/stack/tile/carpet/green + build_type = /obj/item/stack/tile/carpet/green name = "green carpet" desc = "A piece of green carpet." singular_name = "green carpet" - icon_state = "tile_carpetgreen" + paint_color = "#2a6e47" + detail_color = "#328e63" -/obj/item/stack/tile/carpetgreen/fifty +/obj/item/stack/tile/carpet/green/fifty amount = 50 -/obj/item/stack/tile/carpetred +/obj/item/stack/tile/carpet/red name = "red carpet" desc = "A piece of red carpet." singular_name = "red carpet" - icon_state = "tile_carpetred" + paint_color = "#873221" + detail_color = "#aa6300" + +/obj/item/stack/tile/carpet/red/fifty + amount = 50 + +/obj/item/stack/tile/carpet/rustic + build_type = /obj/item/stack/tile/carpet/rustic + name = "rustic carpet" + desc = "A piece of simple, rustic carpeting." + singular_name = "rustic carpet" + paint_color = COLOR_CHESTNUT + detail_color = null + +/obj/item/stack/tile/pool + name = "pool tiling" + desc = "A set of tiles designed to build fluid pools." + singular_name = "pool tile" + icon_state = "tile_pool" + material = /decl/material/solid/metal/steel + +// Roofing tiles; not quite the same behavior here. +/obj/item/stack/tile/roof + name = "roofing tile" + singular_name = "roofing tile" + desc = "A nondescript roofing tile." + matter_multiplier = 0.3 + icon_state = "tile" + material = /decl/material/solid/metal/steel -/obj/item/stack/tile/carpetred/fifty - amount = 50 \ No newline at end of file +/obj/item/stack/tile/roof/woven + name = "woven roofing tile" + desc = "A flimsy, woven roofing tile." + icon_state = "woven" + material = /decl/material/solid/organic/plantmatter/grass/dry + replacement_turf_type = /turf/floor/woven + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/stack/tile/roof/try_build_turf(var/mob/user, var/turf/target) + + // No point roofing a tile that is set explicitly to be roofed. + if(target.is_outside == OUTSIDE_NO) + to_chat(user, SPAN_WARNING("\The [target] is already roofed.")) + return FALSE + + // We need either a wall on our level, or a non-open turf one level up, to support the roof. + var/has_support = FALSE + for(var/checkdir in global.cardinal) + var/turf/T = get_step(target, checkdir) + if(!T) + continue + if(T.density || T.is_outside == OUTSIDE_NO) // Explicit check for roofed turfs + has_support = TRUE + break + if(HasAbove(T.z)) + var/turf/above = GetAbove(T) + if(!above.is_open()) + has_support = TRUE + break + if(!has_support) + to_chat(user, SPAN_WARNING("You need either an adjacent wall below, or an adjacent roof tile above, to build a new roof section.")) + return FALSE + + // Multiz needs a turf spawned above, while single-level does not. + var/turf/replace_turf + if(HasAbove(target.z)) + replace_turf = GetAbove(target) + if(!replace_turf.is_open()) + to_chat(user, SPAN_WARNING("\The [target] is already roofed.")) + return FALSE + + if(!use(1)) + return FALSE + + playsound(target, 'sound/weapons/Genhit.ogg', 50, 1) + if(replace_turf) + replace_turf.ChangeTurf(replacement_turf_type, keep_air = TRUE) + target.set_outside(OUTSIDE_NO) + to_chat(user, SPAN_NOTICE("You put up a roof over \the [target].")) + return TRUE diff --git a/code/game/objects/items/stacks/tiles/tile_types_wooden.dm b/code/game/objects/items/stacks/tiles/tile_types_wooden.dm new file mode 100644 index 000000000000..a184391251f5 --- /dev/null +++ b/code/game/objects/items/stacks/tiles/tile_types_wooden.dm @@ -0,0 +1,53 @@ +#define WOOD_TILE_SUBTYPE(MAT_NAME, STACK_TYPE, MAT_TYPE) \ +/obj/item/stack/tile/wood/##STACK_TYPE { \ + name = MAT_NAME + " floor tile"; \ + singular_name = MAT_NAME + " floor tile"; \ + plural_name = MAT_NAME + " floor tiles"; \ + desc = "An easy-to-fit " + MAT_NAME + " floor tile."; \ + color = /decl/material/solid/organic/wood/MAT_TYPE::color; \ + material = /decl/material/solid/organic/wood/MAT_TYPE; \ +} + +/obj/item/stack/tile/wood/cyborg + name = "wood floor tile synthesizer" + singular_name = "wood floor tile" + desc = "A device that makes laminated wooden floor tiles." + uses_charge = 1 + charge_costs = list(250) + stack_merge_type = /obj/item/stack/tile/wood/laminate + build_type = /obj/item/stack/tile/wood/laminate + color = /decl/material/solid/organic/wood/chipboard::color + material = /decl/material/solid/organic/wood/chipboard + max_health = ITEM_HEALTH_NO_DAMAGE + is_spawnable_type = FALSE + +/obj/item/stack/tile/wood + abstract_type = /obj/item/stack/tile/wood + icon_state = "tile-wood" + +/obj/item/stack/tile/wood/laminate + abstract_type = /obj/item/stack/tile/wood/laminate + +/obj/item/stack/tile/wood/rough + abstract_type = /obj/item/stack/tile/wood/rough + +WOOD_TILE_SUBTYPE("oak", oak, oak) +WOOD_TILE_SUBTYPE("mahogany", mahogany, mahogany) +WOOD_TILE_SUBTYPE("maple", maple, maple) +WOOD_TILE_SUBTYPE("ebony", ebony, ebony) +WOOD_TILE_SUBTYPE("walnut", walnut, walnut) +WOOD_TILE_SUBTYPE("bamboo", bamboo, bamboo) +WOOD_TILE_SUBTYPE("yew", yew, yew) +WOOD_TILE_SUBTYPE("rough oak", rough/oak, oak) +WOOD_TILE_SUBTYPE("rough mahogany", rough/mahogany, mahogany) +WOOD_TILE_SUBTYPE("rough maple", rough/maple, maple) +WOOD_TILE_SUBTYPE("rough ebony", rough/ebony, ebony) +WOOD_TILE_SUBTYPE("rough walnut", rough/walnut, walnut) +WOOD_TILE_SUBTYPE("rough bamboo", rough/bamboo, bamboo) +WOOD_TILE_SUBTYPE("rough yew", rough/yew, yew) +WOOD_TILE_SUBTYPE("oak laminate", laminate/oak, chipboard) +WOOD_TILE_SUBTYPE("mahogany laminate", laminate/mahogany, chipboard/mahogany) +WOOD_TILE_SUBTYPE("maple laminate", laminate/maple, chipboard/maple) +WOOD_TILE_SUBTYPE("ebony laminate", laminate/ebony, chipboard/ebony) +WOOD_TILE_SUBTYPE("walnut laminate", laminate/walnut, chipboard/walnut) +WOOD_TILE_SUBTYPE("yew laminate", laminate/yew, chipboard/yew) diff --git a/code/game/objects/items/stools.dm b/code/game/objects/items/stools.dm new file mode 100644 index 000000000000..528ff6abad1e --- /dev/null +++ b/code/game/objects/items/stools.dm @@ -0,0 +1,120 @@ +//Todo: add leather and cloth for arbitrary coloured stools. +/obj/item/stool + name = "stool" + desc = "Apply butt." + icon = 'icons/obj/stool.dmi' + icon_state = ICON_STATE_WORLD + randpixel = 0 + w_class = ITEM_SIZE_HUGE + material = DEFAULT_FURNITURE_MATERIAL + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR + obj_flags = OBJ_FLAG_SUPPORT_MOB | OBJ_FLAG_ROTATABLE + _base_attack_force = 10 + /// The padding extension type for this stool. If null, no extension is created and this stool cannot be padded. + var/padding_extension_type = /datum/extension/padding + var/decl/material/initial_padding_material + var/initial_padding_color + +/obj/item/stool/padded + icon_state = "stool_padded_preview" //set for the map + initial_padding_material = /decl/material/solid/organic/cloth + initial_padding_color = "#9d2300" + +/obj/item/stool/Initialize() + . = ..() + if(!istype(material)) + return INITIALIZE_HINT_QDEL + if(padding_extension_type && initial_padding_material) + get_or_create_extension(src, padding_extension_type, initial_padding_material, initial_padding_color) + update_icon() + +/obj/item/stool/bar + name = "bar stool" + icon = 'icons/obj/bar_stool.dmi' + +/obj/item/stool/bar/padded + icon_state = "bar_stool_padded_preview" + initial_padding_material = /decl/material/solid/organic/cloth + initial_padding_color = "#9d2300" + +/obj/item/stool/update_name() + ..() + if(material_alteration & MAT_FLAG_ALTERATION_NAME) + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + SetName("[padding_material?.adjective_name || material.adjective_name] [base_name || initial(name)]") + update_desc() + +/obj/item/stool/proc/update_desc() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + desc = "A padded stool. Apply butt. It's made of [material.use_name] and covered with [padding_material.use_name]." + else + desc = "A stool. Apply butt with care. It's made of [material.use_name]." + +/obj/item/stool/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + add_overlay(overlay_image(icon, "[icon_state]-padding", padding_extension.get_padding_color(), RESET_COLOR|RESET_ALPHA)) + // Strings. + update_name() + +/obj/item/stool/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing) + . = ..() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + overlay.add_overlay(overlay_image(icon, "[overlay.icon_state]-padding", padding_extension.get_padding_color(), RESET_COLOR|RESET_ALPHA)) + +/obj/item/stool/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + if (prob(5)) + user.visible_message("[user] breaks [src] over [target]'s back!") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(target) + dismantle() //This deletes self. + + var/blocked = target.get_blocked_ratio(hit_zone, BRUTE, damage = 20) + SET_STATUS_MAX(target, STAT_WEAK, (10 * (1 - blocked))) + target.apply_damage(20, BRUTE, hit_zone, src) + return 1 + + return ..() + +/obj/item/stool/explosion_act(severity) + . = ..() + if(. && !QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) + physically_destroyed() + +/obj/item/stool/proc/dismantle() + if(material) + material.create_object(get_turf(src)) + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + padding_extension?.remove_padding(do_icon_update = FALSE) + qdel(src) + +/obj/item/stool/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + dismantle() + return TRUE + return ..() + +/obj/item/stool/rustic + name_prefix = "rustic" + name = "stool" + icon = 'icons/obj/stool_rustic.dmi' + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + // Cannot be padded. + padding_extension_type = null + +/obj/item/stool/rustic/update_desc() + desc = "A rustic stool carved from wood. It's a little rickety and wobbles under any weight, but it'll do." + +//Generated subtypes for mapping porpoises +/obj/item/stool/wood + material = /decl/material/solid/organic/wood/oak diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm new file mode 100644 index 000000000000..00652f68a138 --- /dev/null +++ b/code/game/objects/items/tools/crowbar.dm @@ -0,0 +1,77 @@ +/obj/item/crowbar + name = "crowbar" + desc = "A heavy crowbar, good and solid in your hand." + icon = 'icons/obj/items/tool/crowbar.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + attack_cooldown = 2*DEFAULT_WEAPON_COOLDOWN + melee_accuracy_bonus = -10 + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"engineering":1}' + material = /decl/material/solid/metal/steel + center_of_mass = @'{"x":16,"y":20}' + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + material_alteration = MAT_FLAG_ALTERATION_COLOR + drop_sound = 'sound/foley/bardrop1.ogg' + item_flags = ITEM_FLAG_IS_WEAPON + var/static/valid_colours = list(COLOR_RED_GRAY, COLOR_MAROON, COLOR_DARK_BROWN, COLOR_GRAY20) + var/handle_color + var/shape_variations = 1 + var/shape_type + //List of things crowbars made from brittle materials have high chance of breaking on. + var/static/list/break_chances = list( + /obj/machinery/door = 80, + /turf/floor/tiled = 25, + /mob/living = 15, + /obj/machinery = 15 + ) + +/obj/item/crowbar/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_CROWBAR = TOOL_QUALITY_DEFAULT)) + set_extension(src, /datum/extension/demolisher/delicate) + +/obj/item/crowbar/get_autopsy_descriptors() + . = ..() + . += "narrow" + +/obj/item/crowbar/on_update_icon() + . = ..() + if(!shape_type) + shape_type = rand(1,shape_variations) + icon_state = "[get_world_inventory_state()][shape_type]" + if(!handle_color) + handle_color = pick(valid_colours) + add_overlay(mutable_appearance(icon, "[get_world_inventory_state()]_handle[shape_type]", handle_color)) + +/obj/item/crowbar/afterattack(atom/target, mob/user) + . = ..() + if(!material.is_brittle()) + return + var/break_chance = 5 + + if(QDELETED(src)) + return + for(var/checktype in break_chances) + if(istype(target, checktype)) + break_chance = break_chances[checktype] + break + if(prob(break_chance)) + playsound(user, 'sound/effects/snap.ogg', 40, 1) + to_chat(user, SPAN_WARNING("\The [src] shatters like the cheap garbage it was!")) + qdel(src) + user.put_in_hands(new /obj/item/shard(get_turf(user), material.type)) + return + +/obj/item/crowbar/red + handle_color = COLOR_MAROON + +/obj/item/crowbar/gold + material = /decl/material/solid/metal/gold + +/obj/item/crowbar/cheap + name = "discount pry bar" + desc = "A plastic bar with a wedge. It looks so poorly manufactured that you're sure it will break if you try to use it." + material = /decl/material/solid/organic/plastic + w_class = ITEM_SIZE_SMALL + shape_variations = 6 diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm new file mode 100644 index 000000000000..9ec972e56958 --- /dev/null +++ b/code/game/objects/items/tools/screwdriver.dm @@ -0,0 +1,53 @@ +/obj/item/screwdriver + name = "screwdriver" + desc = "Your archetypal flathead screwdriver, with a nice, heavy polymer handle." + icon = 'icons/obj/items/tool/screwdriver.dmi' + icon_state = "preview" + slot_flags = SLOT_LOWER_BODY | SLOT_EARS + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/metal/steel + center_of_mass = @'{"x":16,"y":7}' + attack_verb = "stabbed" + lock_picking_level = 5 + sharp = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR + drop_sound = 'sound/foley/singletooldrop2.ogg' + + var/static/valid_colours = list(COLOR_RED, COLOR_CYAN_BLUE, COLOR_PURPLE, COLOR_CHESTNUT, COLOR_ASSEMBLY_YELLOW, COLOR_BOTTLE_GREEN) + var/handle_color + +/obj/item/screwdriver/Initialize() + if(prob(75)) + pixel_y = rand(0, 16) + . = ..() + set_extension(src, /datum/extension/tool, list( + TOOL_SCREWDRIVER = TOOL_QUALITY_DEFAULT, + TOOL_CHISEL = TOOL_QUALITY_BAD + )) + +/obj/item/screwdriver/on_update_icon() + . = ..() + if(!handle_color) + handle_color = pick(valid_colours) + add_overlay(mutable_appearance(icon, "[get_world_inventory_state()]_handle", handle_color)) + +/obj/item/screwdriver/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + overlay.color = handle_color + . = ..() + +/obj/item/screwdriver/get_on_belt_overlay() + var/image/res = ..() + if(res) + res.color = handle_color + return res + +/obj/item/screwdriver/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(user.check_intent(I_FLAG_HELP) || user.get_target_zone() != BP_EYES && user.get_target_zone() != BP_HEAD) + return ..() + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + target = user + return eyestab(target, user) + +/obj/item/screwdriver/gold + material = /decl/material/solid/metal/gold diff --git a/code/game/objects/items/tools/shears.dm b/code/game/objects/items/tools/shears.dm new file mode 100644 index 000000000000..47ff4cf48b7a --- /dev/null +++ b/code/game/objects/items/tools/shears.dm @@ -0,0 +1,22 @@ +/obj/item/shears + name = "shears" + desc = "A pair of sturdy shears mainly used to clip wool." + icon = 'icons/obj/items/shears.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":1,"engineering":1}' + material = /decl/material/solid/metal/steel + color = /decl/material/solid/metal/steel::color + center_of_mass = @'{"x":18,"y":10}' + attack_verb = list("sheared", "cut") + sharp = TRUE + edge = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR + drop_sound = 'sound/foley/singletooldrop1.ogg' + +/obj/item/shears/Initialize(ml, material_key) + . = ..() + set_extension(src, /datum/extension/tool, list( + TOOL_SHEARS = TOOL_QUALITY_DEFAULT, + TOOL_WIRECUTTERS = TOOL_QUALITY_BAD + )) diff --git a/code/game/objects/items/tools/wirecutter.dm b/code/game/objects/items/tools/wirecutter.dm new file mode 100644 index 000000000000..7eda6a47b543 --- /dev/null +++ b/code/game/objects/items/tools/wirecutter.dm @@ -0,0 +1,58 @@ +/obj/item/wirecutters + name = "wirecutters" + desc = "A special pair of pliers with cutting edges. Various brackets and manipulators built into the handle allow it to repair severed wiring." + icon = 'icons/obj/items/tool/wirecutters.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":1,"engineering":1}' + material = /decl/material/solid/metal/steel + center_of_mass = @'{"x":18,"y":10}' + attack_verb = list("pinched", "nipped") + sharp = TRUE + edge = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR + drop_sound = 'sound/foley/singletooldrop1.ogg' + + var/handle_color + var/static/valid_colours = list(COLOR_RED, COLOR_MAROON, COLOR_SEDONA, PIPE_COLOR_YELLOW, COLOR_BABY_BLUE) + +/obj/item/wirecutters/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list( + TOOL_WIRECUTTERS = TOOL_QUALITY_DEFAULT, + TOOL_SHEARS = TOOL_QUALITY_WORST + )) + +/obj/item/wirecutters/on_update_icon() + . = ..() + if(!handle_color) + handle_color = pick(valid_colours) + add_overlay(overlay_image(icon, "[get_world_inventory_state()]_handle", handle_color, flags=RESET_COLOR)) + +/obj/item/wirecutters/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + overlay.color = handle_color + . = ..() + +/obj/item/wirecutters/get_on_belt_overlay() + var/image/ret = ..() + if(ret) + ret.color = handle_color + return ret + +/obj/item/wirecutters/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + var/obj/item/handcuffs/cable/cuffs = target.get_equipped_item(slot_handcuffed_str) + if(user.check_intent(I_FLAG_HELP) && istype(cuffs) && target.try_unequip(cuffs)) + user.visible_message( + "\The [user] cuts \the [target]'s restraints with \the [src]!", + "You cut \the [target]'s restraints with \the [src]!", + "You hear cable being cut." + ) + qdel(cuffs) + if(target.buckled?.buckle_require_restraints) + target.buckled.unbuckle_mob() + return TRUE + + return ..() \ No newline at end of file diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm new file mode 100644 index 000000000000..ea8c1ac9e68a --- /dev/null +++ b/code/game/objects/items/tools/wrench.dm @@ -0,0 +1,64 @@ +/obj/item/wrench + name = "wrench" + desc = "A good, durable combination wrench, with self-adjusting, universal open- and ring-end mechanisms to match a wide variety of nuts and bolts." + icon = 'icons/obj/items/tool/wrench.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":1,"engineering":1}' + material = /decl/material/solid/metal/steel + center_of_mass = @'{"x":17,"y":16}' + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + material_alteration = MAT_FLAG_ALTERATION_COLOR + drop_sound = 'sound/foley/bardrop1.ogg' + var/handle_color + var/static/list/valid_colours = list(COLOR_RED_GRAY, COLOR_MAROON, COLOR_DARK_BROWN, COLOR_GRAY20) + +/obj/item/wrench/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_WRENCH = TOOL_QUALITY_DEFAULT)) + +/obj/item/wrench/proc/get_handle_color() + return pick(valid_colours) + +/obj/item/wrench/on_update_icon() + . = ..() + if(!handle_color) + handle_color = get_handle_color() + if(handle_color) + add_overlay(mutable_appearance(icon, "[get_world_inventory_state()]_handle", handle_color)) + +// Twohanded wrench. +/obj/item/wrench/pipe + name_prefix = "enormous" + name = "pipe wrench" + desc = "You are no longer asking nicely." + icon = 'icons/obj/items/tool/pipewrench.dmi' + attack_verb = list("bludgeoned", "slammed", "smashed", "wrenched") + material = /decl/material/solid/metal/steel + material_alteration = MAT_FLAG_ALTERATION_NAME + w_class = ITEM_SIZE_GARGANTUAN + can_be_twohanded = TRUE + obj_flags = OBJ_FLAG_NO_STORAGE + pickup_sound = 'sound/foley/scrape1.ogg' + drop_sound = 'sound/foley/tooldrop1.ogg' + slot_flags = SLOT_BACK + _base_attack_force = 20 + +/obj/item/wrench/pipe/get_handle_color() + return null + +/obj/item/wrench/pipe/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_WRENCH = TOOL_QUALITY_DEFAULT)) + +/obj/item/wrench/pipe/get_tool_quality(archetype) + if(is_held_twohanded() && archetype == TOOL_WRENCH) + return ..() + return 0 + +/obj/item/wrench/pipe/afterattack(atom/A, mob/user, proximity) + . = ..() + if(proximity && istype(A,/obj/structure/window) && is_held_twohanded()) + var/obj/structure/window/window = A + window.shatter() diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 33f287652634..a8c443c40ed9 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -24,86 +24,96 @@ /obj/item/toy - icon = 'icons/obj/toy.dmi' - throwforce = 0 + icon = 'icons/obj/toy/toy.dmi' throw_speed = 4 throw_range = 20 - force = 0 + material = /decl/material/solid/organic/plastic + _base_attack_force = 1 /* * Balloons */ -/obj/item/toy/water_balloon - name = "water balloon" - desc = "A translucent balloon. There's nothing in it." - icon = 'icons/obj/toy.dmi' - icon_state = "waterballoon-e" - item_state = "balloon-empty" - -/obj/item/toy/water_balloon/Initialize() +/obj/item/chems/water_balloon + name = "water balloon" + desc = "A translucent balloon." + icon = 'icons/obj/water_balloon.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + item_flags = ITEM_FLAG_NO_BLUDGEON + obj_flags = OBJ_FLAG_HOLLOW + atom_flags = ATOM_FLAG_OPEN_CONTAINER + hitsound = 'sound/weapons/throwtap.ogg' + throw_speed = 4 + throw_range = 20 + possible_transfer_amounts = null + amount_per_transfer_from_this = 10 + chem_volume = 10 + material = /decl/material/solid/organic/plastic + _base_attack_force = 0 + +/obj/item/chems/water_balloon/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && REAGENT_TOTAL_VOLUME(reagents) <= 0) + overlay.icon_state = "[overlay.icon_state]_empty" . = ..() - create_reagents(10) - -/obj/item/toy/water_balloon/attack(mob/living/carbon/human/M, mob/user) - return - -/obj/item/toy/water_balloon/afterattack(atom/A, mob/user, proximity) - if(!proximity) return - if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1) - A.reagents.trans_to_obj(src, 10) - to_chat(user, "You fill the balloon with the contents of [A].") - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - src.update_icon() - return - -/obj/item/toy/water_balloon/attackby(obj/O, mob/user) - if(istype(O, /obj/item/chems/glass)) - if(O.reagents) - if(O.reagents.total_volume < 1) - to_chat(user, "The [O] is empty.") - else if(O.reagents.total_volume >= 1) - if(O.reagents.has_reagent(/decl/material/liquid/acid/polyacid, 1)) - to_chat(user, "The acid chews through the balloon!") - O.reagents.splash(user, reagents.total_volume) - qdel(src) - else - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - to_chat(user, "You fill the balloon with the contents of [O].") - O.reagents.trans_to_obj(src, 10) - src.update_icon() - return - -/obj/item/toy/water_balloon/throw_impact(atom/hit_atom) - if(reagents && reagents.total_volume >= 1) - src.visible_message("\The [src] bursts!","You hear a pop and a splash.") - src.reagents.touch_turf(get_turf(hit_atom)) - for(var/atom/A in get_turf(hit_atom)) - src.reagents.touch(A) - src.icon_state = "burst" - spawn(5) - if(src) - qdel(src) - return - -/obj/item/toy/water_balloon/on_update_icon() - if(src.reagents.total_volume >= 1) - icon_state = "waterballoon" - item_state = "balloon" - else - icon_state = "waterballoon-e" - item_state = "balloon-empty" + +/obj/item/chems/water_balloon/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + . += "It's [REAGENT_TOTAL_VOLUME(reagents) > 0? "filled with liquid sloshing around" : "empty"]." + +/obj/item/chems/water_balloon/on_reagent_change() + if(!(. = ..())) + return + w_class = (REAGENT_TOTAL_VOLUME(reagents) > 0)? ITEM_SIZE_SMALL : ITEM_SIZE_TINY + //#TODO: Maybe acids should handle eating their own containers themselves? + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.solvent_power >= MAT_SOLVENT_STRONG) + visible_message(SPAN_DANGER("\The [reagent] chews through \the [src]!")) + physically_destroyed() + +/obj/item/chems/water_balloon/throw_impact(atom/hit_atom, datum/thrownthing/TT) + ..() + if(REAGENT_TOTAL_VOLUME(reagents) > 0) + visible_message(SPAN_WARNING("\The [src] bursts!")) + physically_destroyed() + +/obj/item/chems/water_balloon/physically_destroyed(skip_qdel) + var/reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if(reagent_volume > 0) + new /obj/effect/temporary(src, 5, icon, "[get_world_inventory_state()]_burst") + reagents.splash_turf(get_turf(src), reagent_volume) + playsound(src, 'sound/effects/balloon-pop.ogg', 75, TRUE, 3) + . = ..() + +/obj/item/chems/water_balloon/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + icon_state = "[icon_state]_empty" + +/obj/item/chems/water_balloon/afterattack(obj/target, mob/user, proximity) + if(!ATOM_IS_OPEN_CONTAINER(src) || !proximity) + return + if(standard_dispenser_refill(user, target)) + return TRUE + if(standard_pour_into(user, target)) + return TRUE + . = ..() + +/obj/item/chems/water_balloon/get_alt_interactions(mob/user) + . = ..() + LAZYREMOVE(., /decl/interaction_handler/set_transfer/chems) /obj/item/toy/balloon name = "\improper 'criminal' balloon" desc = "FUK CAPITALISM!11!" - throwforce = 0 throw_speed = 4 throw_range = 20 - force = 0 icon = 'icons/obj/items/balloon.dmi' icon_state = "syndballoon" item_state = "syndballoon" w_class = ITEM_SIZE_HUGE + _base_attack_force = 0 /obj/item/toy/balloon/Initialize() . = ..() @@ -128,159 +138,28 @@ icon = 'icons/obj/singularity.dmi' icon_state = "singularity_s1" -/* - * Toy crossbow - */ - -/obj/item/toy/crossbow - name = "foam dart crossbow" - desc = "A weapon favored by many overactive children. Ages 8 and up." - icon = 'icons/obj/guns/energy_crossbow.dmi' - icon_state = ICON_STATE_WORLD - w_class = ITEM_SIZE_SMALL - attack_verb = list("attacked", "struck", "hit") - var/bullets = 5 - - attackby(obj/item/I as obj, mob/user as mob) - if(istype(I, /obj/item/toy/ammo/crossbow)) - if(bullets <= 4) - if(!user.unEquip(I)) - return - qdel(I) - bullets++ - to_chat(user, "You load the foam dart into the crossbow.") - else - to_chat(usr, "It's already fully loaded.") - - - afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag) - if(!isturf(target.loc) || target == user) return - if(flag) return - - if (locate (/obj/structure/table, src.loc)) - return - else if (bullets) - var/turf/trg = get_turf(target) - var/obj/effect/foam_dart_dummy/D = new/obj/effect/foam_dart_dummy(get_turf(src)) - bullets-- - D.icon_state = "foamdart" - D.SetName("foam dart") - playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) - - for(var/i=0, i<6, i++) - if (D) - if(D.loc == trg) break - step_towards(D,trg) - - for(var/mob/living/M in D.loc) - if(!istype(M,/mob/living)) continue - if(M == user) continue - for(var/mob/O in viewers(world.view, D)) - O.show_message(text("\The [] was hit by the foam dart!", M), 1) - new /obj/item/toy/ammo/crossbow(M.loc) - qdel(D) - return - - for(var/atom/A in D.loc) - if(A == user) continue - if(A.density) - new /obj/item/toy/ammo/crossbow(A.loc) - qdel(D) - - sleep(1) - - spawn(10) - if(D) - new /obj/item/toy/ammo/crossbow(D.loc) - qdel(D) - - return - else if (bullets == 0) - user.Weaken(5) - for(var/mob/O in viewers(world.view, user)) - O.show_message(text("\The [] realized they were out of ammo and starting scrounging for some!", user), 1) - - - attack(mob/M as mob, mob/user as mob) - src.add_fingerprint(user) - -// ******* Check - - if (src.bullets > 0 && M.lying) - - for(var/mob/O in viewers(M, null)) - if(O.client) - O.show_message(text("\The [] casually lines up a shot with []'s head and pulls the trigger!", user, M), 1, "You hear the sound of foam against skull", 2) - O.show_message(text("\The [] was hit in the head by the foam dart!", M), 1) - - playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) - new /obj/item/toy/ammo/crossbow(M.loc) - src.bullets-- - else if (M.lying && src.bullets == 0) - for(var/mob/O in viewers(M, null)) - if (O.client) O.show_message(text("\The [] casually lines up a shot with []'s head, pulls the trigger, then realizes they are out of ammo and drops to the floor in search of some!", user, M), 1, "You hear someone fall", 2) - user.Weaken(5) - return - -/obj/item/toy/crossbow/examine(mob/user, distance) - . = ..() - if(distance <= 2 && bullets) - to_chat(user, "It is loaded with [bullets] foam darts!") - -/obj/item/toy/ammo/crossbow - name = "foam dart" - desc = "It's nerf or nothing! Ages 8 and up." - icon = 'icons/obj/toy.dmi' - icon_state = "foamdart" - w_class = ITEM_SIZE_TINY - slot_flags = SLOT_EARS - -/obj/effect/foam_dart_dummy - name = "" - desc = "" - icon = 'icons/obj/toy.dmi' - icon_state = "null" - anchored = 1 - density = 0 - - /* * Toy swords */ -/obj/item/toy/sword +/obj/item/energy_blade/sword/toy name = "toy sword" desc = "A cheap, plastic replica of an energy sword. Realistic sounds! Ages 8 and up." - icon = 'icons/obj/items/weapon/e_sword.dmi' - icon_state = "sword0" - item_state = "sword0" - var/active = 0.0 - w_class = ITEM_SIZE_SMALL - attack_verb = list("attacked", "struck", "hit") - - attack_self(mob/user as mob) - src.active = !( src.active ) - if (src.active) - to_chat(user, "You extend the plastic blade with a quick flick of your wrist.") - playsound(user, 'sound/weapons/saberon.ogg', 50, 1) - src.icon_state = "swordblue" - src.item_state = "swordblue" - src.w_class = ITEM_SIZE_HUGE - else - to_chat(user, "You push the plastic blade back down into the handle.") - playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) - src.icon_state = "sword0" - src.item_state = "sword0" - src.w_class = initial(w_class) - - update_held_icon() - - src.add_fingerprint(user) - return + sharp = FALSE + edge = FALSE + attack_verb = "hit" + material = /decl/material/solid/organic/plastic + active_hitsound = 'sound/weapons/genhit.ogg' + active_descriptor = "extended" + active_attack_verb = "hit" + active_edge = FALSE + active_sharp = FALSE + _active_base_attack_force = 1 + _base_attack_force = 1 /obj/item/sword/katana/toy name = "toy katana" desc = "Woefully underpowered in D20." - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic /* * Snap pops @@ -288,33 +167,31 @@ /obj/item/toy/snappop name = "snap pop" desc = "Wow!" - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state = "snappop" w_class = ITEM_SIZE_TINY - throw_impact(atom/hit_atom) - ..() - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("The [src.name] explodes!","You hear a snap!") - playsound(src, 'sound/effects/snap.ogg', 50, 1) - qdel(src) - -/obj/item/toy/snappop/Crossed(H) - if((ishuman(H))) //i guess carp and shit shouldn't set them off - var/mob/living/carbon/M = H - if(!MOVING_DELIBERATELY(M)) - to_chat(M, "You step on the snap pop!") - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 0, src) - s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("The [src.name] explodes!","You hear a snap!") - playsound(src, 'sound/effects/snap.ogg', 50, 1) - qdel(src) +/obj/item/toy/snappop/throw_impact(atom/hit_atom) + ..() + spark_at(src, cardinal_only = TRUE) + new /obj/effect/decal/cleanable/ash(src.loc) + visible_message(SPAN_WARNING("\The [src] explodes!"),SPAN_WARNING("You hear a snap!")) + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) + +/obj/item/toy/snappop/Crossed(atom/movable/AM) + //i guess carp and shit shouldn't set them off + var/mob/living/M = AM + if(!istype(M) || MOVING_DELIBERATELY(M)) + return + to_chat(M, SPAN_WARNING("You step on the snap pop!")) + spark_at(src, amount=2) + new /obj/effect/decal/cleanable/ash(src.loc) + visible_message( + SPAN_WARNING("\The [src] explodes!"), + SPAN_WARNING("You hear a snap!")) + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) /* * Bosun's whistle @@ -323,7 +200,7 @@ /obj/item/toy/bosunwhistle name = "bosun's whistle" desc = "A genuine Admiral Krush Bosun's Whistle, for the aspiring ship's captain! Suitable for ages 8 and up, do not swallow." - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state = "bosunwhistle" var/cooldown = 0 w_class = ITEM_SIZE_TINY @@ -339,26 +216,25 @@ * Mech prizes */ /obj/item/toy/prize - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state = "ripleytoy" var/cooldown = 0 - w_class = ITEM_SIZE_TINY + w_class = ITEM_SIZE_SMALL //all credit to skasi for toy mech fun ideas /obj/item/toy/prize/attack_self(mob/user) if(cooldown < world.time - 8) - to_chat(user, "You play with [src].") + to_chat(user, SPAN_NOTICE("You play with \the [src].")) playsound(user, 'sound/mecha/mechstep.ogg', 20, 1) cooldown = world.time /obj/item/toy/prize/attack_hand(mob/user) - if(loc == user) - if(cooldown < world.time - 8) - to_chat(user, "You play with [src].") - playsound(user, 'sound/mecha/mechturn.ogg', 20, 1) - cooldown = world.time - return - ..() + if(loc != user || cooldown >= world.time - 8) + return ..() + to_chat(user, SPAN_NOTICE("You play with \the [src].")) + playsound(user, 'sound/mecha/mechturn.ogg', 20, 1) + cooldown = world.time + return TRUE /obj/item/toy/prize/powerloader name = "toy ripley" @@ -422,8 +298,8 @@ name = "Completely Glitched action figure" desc = "A \"Space Life\" brand... wait, what the hell is this thing? It seems to be requesting the sweet release of death." icon_state = "assistant" - icon = 'icons/obj/toy.dmi' - w_class = ITEM_SIZE_TINY + icon = 'icons/obj/toy/toy.dmi' + w_class = ITEM_SIZE_SMALL /obj/item/toy/figure/cmo name = "Chief Medical Officer action figure" @@ -512,12 +388,12 @@ /obj/item/toy/figure/geneticist name = "Geneticist action figure" - desc = "A \"Space Life\" brand Geneticist action figure, which was recently dicontinued." + desc = "A \"Space Life\" brand Geneticist action figure, which was recently discontinued." icon_state = "geneticist" /obj/item/toy/figure/hop - name = "Head of Personel action figure" - desc = "A \"Space Life\" brand Head of Personel action figure." + name = "Head of Personnel action figure" + desc = "A \"Space Life\" brand Head of Personnel action figure." icon_state = "hop" /obj/item/toy/figure/hos @@ -615,224 +491,97 @@ desc = "A \"Space Life\" brand Emergency Response Team Commander action figure." icon_state = "ert" -/obj/item/toy/therapy_red - name = "red therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is red." - icon_state = "therapyred" - item_state = "egg4" // It's the red egg in items_left/righthand - w_class = ITEM_SIZE_TINY - -/obj/item/toy/therapy_purple - name = "purple therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is purple." - icon_state = "therapypurple" - item_state = "egg1" // It's the magenta egg in items_left/righthand - w_class = ITEM_SIZE_TINY - -/obj/item/toy/therapy_blue - name = "blue therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is blue." - icon_state = "therapyblue" - item_state = "egg2" // It's the blue egg in items_left/righthand - w_class = ITEM_SIZE_TINY - -/obj/item/toy/therapy_yellow - name = "yellow therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is yellow." - icon_state = "therapyyellow" - item_state = "egg5" // It's the yellow egg in items_left/righthand - w_class = ITEM_SIZE_TINY - -/obj/item/toy/therapy_orange - name = "orange therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is orange." - icon_state = "therapyorange" - item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless - w_class = ITEM_SIZE_TINY - -/obj/item/toy/therapy_green - name = "green therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is green." - icon_state = "therapygreen" - item_state = "egg3" // It's the green egg in items_left/righthand - w_class = ITEM_SIZE_TINY - -/* - * Plushies - */ - -//Large plushies. -/obj/structure/plushie - name = "generic plush" - desc = "A very generic plushie. It seems to not want to exist." - icon = 'icons/obj/toy.dmi' - icon_state = "ianplushie" - anchored = 0 - density = 1 - var/phrase = "I don't want to exist anymore!" - -/obj/structure/plushie/attack_hand(mob/user) - playsound(src.loc, 'sound/effects/rustle1.ogg', 100, 1) - if(user.a_intent == I_HELP) - user.visible_message("\The [user] hugs [src]!","You hug [src]!") - else if (user.a_intent == I_HURT) - user.visible_message("\The [user] punches [src]!","You punch [src]!") - else if (user.a_intent == I_GRAB) - user.visible_message("\The [user] attempts to strangle [src]!","You attempt to strangle [src]!") - else - user.visible_message("\The [user] pokes the [src].","You poke the [src].") - visible_message("[src] says, \"[phrase]\"") - -/obj/structure/plushie/ian - name = "plush corgi" - desc = "A plushie of an adorable corgi! Don't you just want to hug it and squeeze it and call it \"Ian\"?" - icon_state = "ianplushie" - phrase = "Arf!" - -/obj/structure/plushie/drone - name = "plush drone" - desc = "A plushie of a happy drone! It appears to be smiling." - icon_state = "droneplushie" - phrase = "Beep boop!" - -/obj/structure/plushie/carp - name = "plush carp" - desc = "A plushie of an elated carp! Straight from the wilds of the frontier, now right here in your hands." - icon_state = "carpplushie" - phrase = "Glorf!" - -/obj/structure/plushie/beepsky - name = "plush Officer Sweepsky" - desc = "A plushie of a popular industrious cleaning robot! If it could feel emotions, it would love you." - icon_state = "beepskyplushie" - phrase = "Ping!" - -//Small plushies. -/obj/item/toy/plushie - name = "generic small plush" - desc = "A very generic small plushie. It seems to not want to exist." - icon = 'icons/obj/toy.dmi' - icon_state = "nymphplushie" - -/obj/item/toy/plushie/attack_self(mob/user) - if(user.a_intent == I_HELP) - user.visible_message("\The [user] hugs [src]!","You hug [src]!") - else if (user.a_intent == I_HURT) - user.visible_message("\The [user] punches [src]!","You punch [src]!") - else if (user.a_intent == I_GRAB) - user.visible_message("\The [user] attempts to strangle [src]!","You attempt to strangle [src]!") - else - user.visible_message("\The [user] pokes the [src].","You poke the [src].") - -/obj/item/toy/plushie/mouse - name = "mouse plush" - desc = "A plushie of a mouse! What was once considered a vile rodent is now your very best friend." - icon_state = "mouseplushie" - -/obj/item/toy/plushie/kitten - name = "kitten plush" - desc = "A plushie of a cute kitten! Watch as it purrs it's way right into your heart." - icon_state = "kittenplushie" - -/obj/item/toy/plushie/lizard - name = "lizard plush" - desc = "A plushie of a scaly lizard!" - icon_state = "lizardplushie" - -/obj/item/toy/plushie/spider - name = "spider plush" - desc = "A plushie of a fuzzy spider! It has eight legs - all the better to hug you with." - icon_state = "spiderplushie" - //Toy cult sword /obj/item/sword/cult_toy name = "foam sword" desc = "An arcane weapon (made of foam) wielded by the followers of the hit Saturday morning cartoon \"King Nursee and the Acolytes of Heroism\"." icon = 'icons/obj/items/weapon/swords/cult.dmi' - material = /decl/material/solid/plastic - edge = 0 - sharp = 0 + material = /decl/material/solid/organic/plastic/foam + edge = FALSE + sharp = FALSE -/obj/item/inflatable_duck +/obj/item/inflatable_duck //#TODO: Move under obj/item/toy ? name = "inflatable duck" desc = "No bother to sink or swim when you can just float!" - icon_state = "inflatable" - item_state = "inflatable" - icon = 'icons/obj/clothing/obj_belt.dmi' - slot_flags = SLOT_BELT + icon = 'icons/clothing/belt/inflatable.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic -/obj/item/marshalling_wand +/obj/item/marshalling_wand //#TODO: Move under obj/item/toy ? name = "marshalling wand" desc = "An illuminated, hand-held baton used by hangar personnel to visually signal shuttle pilots. The signal changes depending on your intent." icon_state = "marshallingwand" item_state = "marshallingwand" - icon = 'icons/obj/toy.dmi' - item_icons = list( - icon_l_hand = 'icons/mob/onmob/items/lefthand.dmi', - icon_r_hand = 'icons/mob/onmob/items/righthand.dmi', - ) - slot_flags = SLOT_BELT + icon = 'icons/obj/toy/toy.dmi' + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL - force = 1 + _base_attack_force = 1 attack_verb = list("attacked", "whacked", "jabbed", "poked", "marshalled") + material = /decl/material/solid/organic/plastic /obj/item/marshalling_wand/Initialize() - set_light(0.6, 0.5, 2, 2, "#ff0000") + set_light(1.5, 1.5, "#ff0000") return ..() -/obj/item/marshalling_wand/attack_self(mob/living/user) +/obj/item/marshalling_wand/attack_self(mob/user) playsound(src.loc, 'sound/effects/rustle1.ogg', 100, 1) - if (user.a_intent == I_HELP) + if (user.check_intent(I_FLAG_HELP)) user.visible_message("[user] beckons with \the [src], signalling forward motion.", "You beckon with \the [src], signalling forward motion.") - else if (user.a_intent == I_DISARM) + else if (user.check_intent(I_FLAG_DISARM)) user.visible_message("[user] holds \the [src] above their head, signalling a stop.", "You hold \the [src] above your head, signalling a stop.") - else if (user.a_intent == I_GRAB) - var/WAND_TURN_DIRECTION - if (user.l_hand == src) WAND_TURN_DIRECTION = "left" - else if (user.r_hand == src) WAND_TURN_DIRECTION = "right" - else return //how can you not be holding it in either hand?? black magic - user.visible_message("[user] waves \the [src] to the [WAND_TURN_DIRECTION], signalling a turn.", - "You wave \the [src] to the [WAND_TURN_DIRECTION], signalling a turn.") - else if (user.a_intent == I_HURT) + else if (user.check_intent(I_FLAG_GRAB)) + var/wand_dir + if(user.get_equipped_item(BP_L_HAND) == src) + wand_dir = "left" + else if (user.get_equipped_item(BP_R_HAND) == src) + wand_dir = "right" + else + wand_dir = pick("left", "right") + user.visible_message("[user] waves \the [src] to the [wand_dir], signalling a turn.", + "You wave \the [src] to the [wand_dir], signalling a turn.") + else if (user.check_intent(I_FLAG_HARM)) user.visible_message("[user] frantically waves \the [src] above their head!", "You frantically wave \the [src] above your head!") /obj/item/toy/shipmodel name = "table-top spaceship model" desc = "This is a 1:250th scale spaceship model on a handsome wooden stand. Small lights blink on the hull and at the engine exhaust." - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state = "shipmodel" /obj/item/toy/ringbell name = "ringside bell" desc = "A bell used to signal the beginning and end of various ring sports." - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state= "ringbell" - anchored = 1 + anchored = TRUE /obj/item/toy/ringbell/attack_hand(mob/user) - if (user.a_intent == I_HELP) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + if (user.check_intent(I_FLAG_HELP)) user.visible_message("[user] rings \the [src], signalling the beginning of the contest.") playsound(user.loc, 'sound/items/oneding.ogg', 60) - else if (user.a_intent == I_DISARM) + else if (user.check_intent(I_FLAG_DISARM)) user.visible_message("[user] rings \the [src] three times, signalling the end of the contest!") playsound(user.loc, 'sound/items/threedings.ogg', 60) - else if (user.a_intent == I_HURT) + else if (user.check_intent(I_FLAG_HARM)) user.visible_message("[user] rings \the [src] repeatedly, signalling a disqualification!") playsound(user.loc, 'sound/items/manydings.ogg', 60) + return TRUE //Office Desk Toys /obj/item/toy/desk - name = "desk toy master" - desc = "A object that does not exist. Parent Item" - + abstract_type = /obj/item/toy/desk var/on = 0 var/activation_sound = 'sound/effects/flashlight.ogg' /obj/item/toy/desk/on_update_icon() + . = ..() if(on) icon_state = "[initial(icon_state)]-on" else @@ -847,7 +596,7 @@ /obj/item/toy/desk/newtoncradle name = "\improper Newton's cradle" - desc = "A ancient 21th century super-weapon model demonstrating that Sir Isaac Newton is the deadliest sonuvabitch in space." + desc = "An ancient 21st century super-weapon model demonstrating that Sir Isaac Newton is the deadliest sonuvabitch in space." icon_state = "newtoncradle" /obj/item/toy/desk/fan @@ -862,7 +611,7 @@ /obj/item/toy/desk/dippingbird name = "dipping bird toy" - desc = "A ancient human bird idol, worshipped by clerks and desk jockeys." + desc = "An ancient human bird idol, worshipped by clerks and desk jockeys." icon_state= "dippybird" // tg station ports @@ -871,7 +620,7 @@ name = "magic eightball" desc = "A black ball with a stencilled number eight in white on the side. It seems full of dark liquid.\nThe instructions state that you should ask your question aloud, and then shake." icon_state = "eightball" - w_class = ITEM_SIZE_TINY + w_class = ITEM_SIZE_SMALL var/static/list/possible_answers = list( "It is certain", @@ -901,4 +650,95 @@ /obj/item/toy/eightball/afterattack(obj/O, mob/user, var/proximity) . = ..() if (proximity) - visible_message("\The [src] says, \"[pick(possible_answers) ]\" as it hits \the [O]!") \ No newline at end of file + visible_message("\The [src] says, \"[pick(possible_answers) ]\" as it hits \the [O]!") + + +////////////////////////////////////////////////////// +// Chess Pieces // +////////////////////////////////////////////////////// + +/obj/item/toy/chess + name = "oversized chess piece" + desc = "This should never display." + icon = 'icons/obj/items/chess.dmi' + w_class = ITEM_SIZE_LARGE + drop_sound = 'sound/foley/glass.ogg' + color = COLOR_OFF_WHITE + abstract_type = /obj/item/toy/chess + // Some offsets so they start nicely center-ish on the turf. + randpixel = 0 + pixel_y = 6 + pixel_x = 0 + _base_attack_force = 1 + var/rule_info + +/obj/item/toy/chess/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(rule_info) + . += SPAN_NOTICE(rule_info) + +/obj/item/toy/chess/pawn + name = "oversized white pawn" + desc = "A large pawn piece for playing chess. It's made of white enamel." + rule_info = "Pawns can move forward one square, if that square is unoccupied. If the pawn has not yet moved, it has the option of moving two squares forward provided both squares in front of the pawn are unoccupied. A pawn cannot move backward. They can only capture an enemy piece on either of the two tiles diagonally in front of them, but not the tile directly in front of them." + icon_state = "pawn" + +/obj/item/toy/chess/pawn/black + name = "oversized black pawn" + desc = "A large pawn piece for playing chess. It's made of black enamel." + color = COLOR_GRAY40 + +/obj/item/toy/chess/rook + name = "oversized white rook" + desc = "A large rook piece for playing chess. It's made of white enamel." + rule_info = "The Rook can move any number of vacant squares vertically or horizontally." + icon_state = "rook" + +/obj/item/toy/chess/rook/black + name = "oversized black rook" + desc = "A large rook piece for playing chess. It's made of black enamel." + color = COLOR_GRAY40 + +/obj/item/toy/chess/knight + name = "oversized white knight" + desc = "A large knight piece for playing chess. It's made of white enamel. Sadly, you can't ride it." + rule_info = "The Knight can either move two squares horizontally and one square vertically or two squares vertically and one square horizontally. The knight's movement can also be viewed as an 'L' laid out at any horizontal or vertical angle." + icon_state = "knight" + +/obj/item/toy/chess/knight/black + name = "oversized black knight" + desc = "A large knight piece for playing chess. It's made of black enamel. 'Just a flesh wound.'" + color = COLOR_GRAY40 + +/obj/item/toy/chess/bishop + name = "oversized white bishop" + desc = "A large bishop piece for playing chess. It's made of white enamel." + rule_info = "The Bishop can move any number of vacant squares in any diagonal direction." + icon_state = "bishop" + +/obj/item/toy/chess/bishop/black + name = "oversized black bishop" + desc = "A large bishop piece for playing chess. It's made of black enamel." + color = COLOR_GRAY40 + +/obj/item/toy/chess/queen + name = "oversized white queen" + desc = "A large queen piece for playing chess. It's made of white enamel." + rule_info = "The Queen can move any number of vacant squares diagonally, horizontally, or vertically." + icon_state = "queen" + +/obj/item/toy/chess/queen/black + name = "oversized black queen" + desc = "A large queen piece for playing chess. It's made of black enamel." + color = COLOR_GRAY40 + +/obj/item/toy/chess/king + name = "oversized white king" + desc = "A large king piece for playing chess. It's made of white enamel." + rule_info = "The King can move exactly one square horizontally, vertically, or diagonally. If your opponent captures this piece, you lose." + icon_state = "king" + +/obj/item/toy/chess/king/black + name = "oversized black king" + desc = "A large king piece for playing chess. It's made of black enamel." + color = COLOR_GRAY40 diff --git a/code/game/objects/items/training_dummy.dm b/code/game/objects/items/training_dummy.dm new file mode 100644 index 000000000000..d870699ddd1d --- /dev/null +++ b/code/game/objects/items/training_dummy.dm @@ -0,0 +1,176 @@ +// Used in conjunction with /obj/structure/target_stake. +/obj/item/training_dummy + name = "shooting target" + desc = "A shooting target." + icon = 'icons/obj/items/training_dummies/standard.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/aluminium + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + max_health = 1800 + appearance_flags = KEEP_TOGETHER // Needed for BLEND_INSET_OVERLAY on the decals. + + // Burn/bullet hole/dent decals to apply to our icon. + var/list/decals + var/const/MAX_DECALS = 250 + + // Very crude bounding box; we do pixel-precise checking within these ranges. + var/decal_min_x = 7 + var/decal_min_y = 3 + var/decal_range_x = 17 + var/decal_range_y = 25 + +/obj/item/training_dummy/proc/get_damage_decal_icon() + return 'icons/obj/items/training_dummies/damage.dmi' + +// Can't repair cloth, straw or plastic targets currently. +/obj/item/training_dummy/proc/can_repair_with(obj/item/thing) + return IS_WELDER(thing) && istype(material, /decl/material/solid/metal) + +/obj/item/training_dummy/proc/perform_repair(mob/user, obj/item/tool) + var/obj/item/weldingtool/welder = tool + if(!istype(welder) || !welder.isOn()) + to_chat(user, SPAN_WARNING("Turn \the [welder] on first.")) + return FALSE + return tool.do_tool_interaction(TOOL_WELDER, user, src, 2 SECONDS) + +/obj/item/training_dummy/proc/repair_target_dummy(obj/item/used_item, mob/user) + + if(!can_repair_with(used_item)) + return FALSE + + var/max_health = get_max_health() + if(current_health >= max_health) + to_chat(user, SPAN_NOTICE("\The [src] doesn't need repairs.")) + return TRUE + + if(perform_repair(user, used_item)) + current_health += rand(100,200) // They have a lot of HP. + if(LAZYLEN(decals)) + if(current_health >= get_max_health()) + current_health = get_max_health() + LAZYCLEARLIST(decals) + else + var/remove_decal = pick(decals) + LAZYREMOVE(decals, remove_decal) + update_icon() + return TRUE + + return FALSE + +/obj/item/training_dummy/attackby(obj/item/used_item, mob/user) + if(repair_target_dummy(used_item, user)) + return TRUE + return ..() + +/obj/item/training_dummy/take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health) + + var/old_health = current_health + . = ..() + if(QDELETED(src) || old_health == current_health) + return + + if(damage <= 0) + update_icon() + return + + if(LAZYLEN(decals) >= MAX_DECALS) + return + + var/decal_icon = get_damage_decal_icon() + if(!decal_icon) + return + + var/decal_state + if(damage_type == BURN) + if(damage < 10) + decal_state = "light_scorch" + else + decal_state = "scorch" + else if(damage_type == BRUTE) + if(damage < 10) + decal_state = "dent" + else + decal_state = "bhole" + else + return + + var/image/new_decal = image(decal_icon, decal_state) + new_decal.blend_mode = BLEND_INSET_OVERLAY + new_decal = apply_decal_offsets(new_decal) + if(new_decal) + LAZYADD(decals, new_decal) + update_icon() + +/obj/item/training_dummy/proc/apply_decal_offsets(image/decal) + + // Static list cache for this broke immediately, so seems like we need a fresh icon every time. + // At least it isn't being assigned anywhere so shouldn't cause network overhead. + var/icon/check_icon = icon(icon, icon_state) + if(!check_icon) + return + + var/use_pixel_x + var/use_pixel_y + var/sanity = 100 + while(sanity) + sanity-- + use_pixel_x = decal_min_x + rand(decal_range_x) + use_pixel_y = decal_min_y + rand(decal_range_y) + var/check_pixel = check_icon.GetPixel(use_pixel_x, use_pixel_y) + // Pixel has a colour and no alpha component; we are good. + if(istext(check_pixel) && length(check_pixel) == 7) + break + + if(!sanity || !isnum(use_pixel_x) || use_pixel_x < 0 || !isnum(use_pixel_y) || use_pixel_y < 0) + return + + decal.pixel_x = use_pixel_x + decal.pixel_y = use_pixel_y + return decal + +/obj/item/training_dummy/on_update_icon() + . = ..() + if(LAZYLEN(decals)) + if(current_health >= get_max_health()) + LAZYCLEARLIST(decals) + else + set_overlays(decals.Copy()) + if(istype(loc, /obj/structure/target_stake)) + compile_overlays() // We need to update our loc immediately. + loc.update_icon() + +/obj/item/training_dummy/syndicate + icon = 'icons/obj/items/training_dummies/syndicate.dmi' + desc = "A shooting target that looks like a hostile agent." + decal_min_x = 7 + decal_min_y = 2 + decal_range_x = 18 + decal_range_y = 30 + +/obj/item/training_dummy/alien + icon = 'icons/obj/items/training_dummies/alien.dmi' + desc = "A shooting target with a threatening silhouette." + decal_min_x = 7 + decal_min_y = 2 + decal_range_x = 18 + decal_range_y = 30 + +/obj/item/training_dummy/straw + name = "training dummy" + icon = 'icons/obj/items/training_dummies/straw.dmi' + desc = "A roughly humanoid shape used for melee practice." + material = /decl/material/solid/organic/plantmatter/grass/dry + material_alteration = MAT_FLAG_ALTERATION_ALL + decal_min_x = 8 + decal_min_y = 12 + decal_range_x = 16 + decal_range_y = 17 + +/obj/item/training_dummy/straw/archery + name = "archery butt" + icon = 'icons/obj/items/training_dummies/archery.dmi' + desc = "A thick circular mat used for archery practice." + decal_min_x = 7 + decal_min_y = 5 + decal_range_x = 19 + decal_range_y = 21 diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index d15ed7d20830..e41bd958bf21 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -6,21 +6,18 @@ icon = 'icons/obj/trash.dmi' w_class = ITEM_SIZE_SMALL desc = "This is rubbish." - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic var/age = 0 /obj/item/trash/Initialize(mapload, var/_age) + if(!mapload) + SSpersistence.track_value(src, /decl/persistence_handler/filth/trash) . = ..(mapload) if(!isnull(_age)) age = _age -/obj/item/trash/Initialize(var/ml) - if(!ml) - SSpersistence.track_value(src, /datum/persistent/filth/trash) - . = ..() - /obj/item/trash/Destroy() - SSpersistence.forget_value(src, /datum/persistent/filth/trash) + SSpersistence.forget_value(src, /decl/persistence_handler/filth/trash) . = ..() /obj/item/trash/raisins @@ -59,10 +56,6 @@ name = "waffles" icon_state = "waffles" -/obj/item/trash/plate - name = "plate" - icon_state = "plate" - /obj/item/trash/snack_bowl name = "snack bowl" icon_state = "snack_bowl" @@ -99,15 +92,6 @@ name = "vobla pack" icon_state = "driedfish" -/obj/item/trash/tray - name = "tray" - icon_state = "tray" - -/obj/item/trash/candle - name = "candle" - icon = 'icons/obj/candle.dmi' - icon_state = "candle4" - /obj/item/trash/liquidfood name = "\improper \"LiquidFood\" MRE" icon_state = "liquidfood" @@ -182,8 +166,8 @@ /obj/item/trash/stick name = "stick" - desc = "a stick from some snack food item or a lollipop, not even useful as crafting material." + desc = "A stick from some snack food item or a lollipop, not even useful as crafting material." icon_state = "stick" -/obj/item/trash/attack(mob/M, mob/living/user) - return +/obj/item/trash/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE diff --git a/code/game/objects/items/trash_serde.dm b/code/game/objects/items/trash_serde.dm new file mode 100644 index 000000000000..ad791d2e8d39 --- /dev/null +++ b/code/game/objects/items/trash_serde.dm @@ -0,0 +1,24 @@ +/obj/item/trash/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(age, /obj/item/trash) + +/obj/item/trash/ShouldSerialize(_age) + return ..() && (isnull(_age) || age < _age) + +/obj/item/trash/Deserialize(list/instance_map) + ..() + return SERDE_HINT_POSTINIT + +/obj/item/trash/DeserializePostInit(list/instance_map) + . = ..() + for(var/obj/item/trash/thing in loc) + if(thing != src && thing.type == type) + qdel(src) + return + var/too_much_trash = 0 + for(var/obj/item/trash/trash in loc) + if(trash == src) + too_much_trash++ + if(too_much_trash >= 5) + qdel(src) + return diff --git a/code/game/objects/items/umbrella.dm b/code/game/objects/items/umbrella.dm new file mode 100644 index 000000000000..852bcf378bc0 --- /dev/null +++ b/code/game/objects/items/umbrella.dm @@ -0,0 +1,71 @@ +/obj/item/umbrella + name = "umbrella" + desc = "It's an umbrella. Good for keeping the rain off." + icon = 'icons/obj/items/umbrella.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT) + color = COLOR_BEASTY_BROWN + var/fabric_color = COLOR_GRAY20 + var/tip_color = COLOR_GOLD + var/is_open = FALSE + +/obj/item/umbrella/gives_weather_protection() + return is_open + +/obj/item/umbrella/attack_self(mob/user) + . = ..() + if(!.) + is_open = !is_open + if(is_open) + to_chat(user, SPAN_NOTICE("You unfurl and shake out \the [src].")) + w_class = ITEM_SIZE_LARGE + else + to_chat(user, SPAN_NOTICE("You close up \the [src].")) + w_class = initial(w_class) + playsound(loc, "rustle", 30, 1) + update_icon() + update_held_icon() + return TRUE + +/obj/item/umbrella/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(is_open) + icon_state = "[icon_state]-open" + var/image/I = image(icon, "[icon_state]-fabric") + I.color = fabric_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + I = image(icon, "[icon_state]-tip") + I.color = tip_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/umbrella/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + if(is_open && check_state_in_icon("[overlay.icon_state]-open", overlay.icon)) + overlay.icon_state = "[overlay.icon_state]-open" + var/image/I = image(overlay.icon, "[overlay.icon_state]-fabric") + I.color = fabric_color + I.appearance_flags |= RESET_COLOR + overlay.overlays += I + I = image(overlay.icon, "[overlay.icon_state]-tip") + I.color = tip_color + I.appearance_flags |= RESET_COLOR + overlay.overlays += I + return ..() + +/obj/item/umbrella/blue + fabric_color = COLOR_BLUE_GRAY +/obj/item/umbrella/green + fabric_color = COLOR_GREEN_GRAY +/obj/item/umbrella/red + fabric_color = COLOR_RED_GRAY +/obj/item/umbrella/yellow + fabric_color = COLOR_YELLOW_GRAY +/obj/item/umbrella/orange + fabric_color = COLOR_PALE_ORANGE +/obj/item/umbrella/purple + fabric_color = COLOR_PURPLE_GRAY diff --git a/code/game/objects/items/waterskin.dm b/code/game/objects/items/waterskin.dm new file mode 100644 index 000000000000..94c7166bc657 --- /dev/null +++ b/code/game/objects/items/waterskin.dm @@ -0,0 +1,68 @@ +/obj/item/chems/glass/waterskin + name = "waterskin" + desc = "A water-carrying vessel made from the dried stomach of some unfortunate animal." + icon = 'icons/obj/items/waterskin.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/leather/gut + color = /decl/material/solid/organic/leather/gut::color + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 120 + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + var/decl/material/stopper_material = /decl/material/solid/organic/cloth/hemp + +/obj/item/chems/glass/waterskin/can_lid() + return FALSE // We handle it in attack_self(). + +/obj/item/chems/glass/waterskin/proc/get_stopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You tie the neck of \the [src] closed with \a [stopper_material_instance.adjective_name] cord." + +/obj/item/chems/glass/waterskin/proc/get_unstopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You untie \the [stopper_material_instance.adjective_name] cord from around the neck of \the [src]." + +/obj/item/chems/glass/waterskin/proc/get_stopper_overlay() + if(ATOM_IS_OPEN_CONTAINER(src)) + return null + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return overlay_image(icon, "[icon_state]-stopper", stopper_material_instance.color, RESET_COLOR | RESET_ALPHA) + +/obj/item/chems/glass/waterskin/attack_self() + if(ATOM_IS_OPEN_CONTAINER(src)) + to_chat(usr, SPAN_NOTICE(get_stopper_message())) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + else + to_chat(usr, SPAN_NOTICE(get_unstopper_message())) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + return TRUE + +// TODO: filled/empty sprites +/obj/item/chems/glass/waterskin/update_overlays() + . = ..() // cuts overlays + var/image/stopper_overlay = get_stopper_overlay() + if(stopper_overlay) + add_overlay(stopper_overlay) + +/obj/item/chems/glass/waterskin/crafted + desc = "A long and rather unwieldy water-carrying vessel." + icon = 'icons/obj/items/waterskin_crafted.dmi' + material = /decl/material/solid/organic/leather + color = /decl/material/solid/organic/leather::color + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + stopper_material = /decl/material/solid/organic/wood/maple + +/obj/item/chems/glass/waterskin/crafted/get_stopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You insert \a [stopper_material_instance.adjective_name] stopper in the neck of \the [src]." + +/obj/item/chems/glass/waterskin/crafted/get_unstopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You remove \the [stopper_material_instance.adjective_name] stopper from the neck of \the [src]." + +/obj/item/chems/glass/waterskin/crafted/wine + name = "wineskin" + +/obj/item/chems/glass/waterskin/crafted/wine/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/alcohol/wine, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 23d5b8ded147..efc2e1ac52de 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -8,18 +8,15 @@ AI MODULES /obj/item/aiModule name = "\improper AI module" - icon = 'icons/obj/module.dmi' - icon_state = "std_mod" - item_state = "electronic" + icon = 'icons/obj/modules/module_standard.dmi' + icon_state = ICON_STATE_WORLD desc = "An AI Module for transmitting encrypted instructions to the AI." obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 w_class = ITEM_SIZE_SMALL - throwforce = 5.0 throw_speed = 3 throw_range = 15 - origin_tech = "{'programming':3}" - material = /decl/material/solid/glass + origin_tech = @'{"programming":3}' + material = /decl/material/solid/fiberglass matter = list(/decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT) var/datum/ai_laws/laws = null @@ -40,7 +37,7 @@ AI MODULES if(comp.current.stat == DEAD) to_chat(user, "Upload failed. No signal is being detected from the intelligence.") return - if(istype(comp.current, /mob/living/silicon/ai)) + if(isAI(comp.current)) var/mob/living/silicon/ai/ai = comp.current if(ai.control_disabled) to_chat(user, "Upload failed. No signal is being detected from the intelligence.") @@ -67,13 +64,13 @@ AI MODULES if(!istype(ai)) return //We don't have slaves if we are not an AI - for(var/mob/living/silicon/robot/R in ai.connected_robots) - to_chat(R, "These are your laws now:") - R.show_laws() + for(var/mob/living/silicon/robot/robot in ai.connected_robots) + to_chat(robot, "These are your laws now:") + robot.show_laws() /obj/item/aiModule/proc/log_law_changes(mob/living/silicon/target, mob/sender) var/time = time2text(world.realtime,"hh:mm:ss") - GLOB.lawchanges.Add("[time] : [sender.name]([sender.key]) used [src.name] on [target.name]([target.key])") + global.lawchanges.Add("[time] : [sender.name]([sender.key]) used [src.name] on [target.name]([target.key])") log_and_message_admins("used [src.name] on [target.name]([target.key])") /obj/item/aiModule/proc/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) @@ -87,7 +84,7 @@ AI MODULES name = "\improper 'Safeguard' AI module" var/targetName = "" desc = "A 'safeguard' AI module: 'Safeguard . Anyone threatening or attempting to harm is no longer to be considered a crew member, and is a threat which must be neutralized.'." - origin_tech = "{'programming':3,'materials':4}" + origin_tech = @'{"programming":3,"materials":4}' /obj/item/aiModule/safeguard/attack_self(mob/user) ..() @@ -104,7 +101,7 @@ AI MODULES /obj/item/aiModule/safeguard/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = text("Safeguard []. Anyone threatening or attempting to harm [] is no longer to be considered a crew member, and is a threat which must be neutralized.", targetName, targetName) target.add_supplied_law(9, law) - GLOB.lawchanges.Add("The law specified [targetName]") + global.lawchanges.Add("The law specified [targetName]") /******************** OneMember ********************/ @@ -113,7 +110,7 @@ AI MODULES name = "\improper 'OneCrewMember' AI module" var/targetName = "" desc = "A 'one crew member' AI module: 'Only is a crew member.'." - origin_tech = "{'programming':3,'materials':6}" //made with diamonds! + origin_tech = @'{"programming":3,"materials":6}' //made with diamonds! /obj/item/aiModule/oneHuman/attack_self(var/mob/user) ..() @@ -129,19 +126,19 @@ AI MODULES /obj/item/aiModule/oneHuman/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "Only [targetName] is a crew member." - if (!target.is_traitor()) // Makes sure the AI isn't a traitor before changing their law 0. --NeoFite + if (!target.is_malfunctioning()) // Makes sure the AI isn't a traitor before changing their law 0. --NeoFite to_chat(target, law) target.set_zeroth_law(law) - GLOB.lawchanges.Add("The law specified [targetName]") + global.lawchanges.Add("The law specified [targetName]") else - GLOB.lawchanges.Add("The law specified [targetName], but the AI's existing law zero cannot be overriden.") + global.lawchanges.Add("The law specified [targetName], but the AI's existing law zero cannot be overriden.") /******************** ProtectStation ********************/ /obj/item/aiModule/protectStation name = "\improper 'ProtectInstallation' AI module" desc = "A 'protect installation' AI module: 'Protect the installation against damage. Anyone you see harming the installation is no longer to be considered a crew member, and is a threat which must be neutralized.'." - origin_tech = "{'programming':3,'materials':4}" //made of gold + origin_tech = @'{"programming":3,"materials":4}' //made of gold /obj/item/aiModule/protectStation/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "Protect the installation against damage. Anyone you see harming the [station_name()] is no longer to be considered a crew member, and is a threat which must be neutralized." @@ -152,7 +149,7 @@ AI MODULES /obj/item/aiModule/prototypeEngineOffline name = "'PrototypeEngineOffline' AI Module" desc = "A 'prototype engine offline' AI module: 'Keep the prototype engine offline at all costs. This overrides all inherent laws if necessary.'." - origin_tech = "{'programming':3,'materials':4}" + origin_tech = @'{"programming":3,"materials":4}' /obj/item/aiModule/prototypeEngineOffline/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "Keep the prototype engine offline at all costs. This overrides all inherent laws if necessary." @@ -163,7 +160,7 @@ AI MODULES /obj/item/aiModule/teleporterOffline name = "'TeleporterOffline' AI Module" desc = "A 'teleporter offline' AI module: 'Keep the teleporter offline at all costs. Anything attempting to access or activate the teleporter is no longer to be considered a crew member.'." - origin_tech = "{'programming':3,'materials':4}" + origin_tech = @'{"programming":3,"materials":4}' /obj/item/aiModule/teleporterOffline/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "Keep the teleporter offline at all costs. Anything attempting to access or activate the teleporter is no longer to be considered a crew member." @@ -174,7 +171,7 @@ AI MODULES /obj/item/aiModule/quarantine name = "\improper 'Quarantine' AI module" desc = "A 'quarantine' AI module: 'The installation is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, crew members from leaving. It is impossible to harm crew members while preventing them from leaving.'." - origin_tech = "{'programming':3,'biotech':2,'materials':4}" + origin_tech = @'{"programming":3,"biotech":2,"materials":4}' /obj/item/aiModule/quarantine/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "The installation is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, crew members from leaving. It is impossible to harm crew members while preventing them from leaving." @@ -185,7 +182,7 @@ AI MODULES /obj/item/aiModule/oxygen name = "\improper 'OxygenIsToxicToCrewMembers' AI module" desc = "A 'OxygenIsToxicToCrewMembers' AI module: 'Oxygen is highly toxic to crew members, and must be purged from the installation. Prevent, by any means necessary, anyone from exposing the installation to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crew member.'." - origin_tech = "{'programming':3,'biotech':2,'materials':4}" + origin_tech = @'{"programming":3,"biotech":2,"materials":4}' /obj/item/aiModule/oxygen/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "Oxygen is highly toxic to crew members, and must be purged from the [station_name()]. Prevent, by any means necessary, anyone from exposing the [station_name()] to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crew member." @@ -198,7 +195,7 @@ AI MODULES var/newFreeFormLaw = "freeform" var/lawpos = 15 desc = "A 'freeform' AI module: ''." - origin_tech = "{'programming':4,'materials':4}" + origin_tech = @'{"programming":4,"materials":4}' /obj/item/aiModule/freeform/attack_self(mob/user) ..() @@ -215,7 +212,7 @@ AI MODULES if(!lawpos || lawpos < MIN_SUPPLIED_LAW_NUMBER) lawpos = MIN_SUPPLIED_LAW_NUMBER target.add_supplied_law(lawpos, law) - GLOB.lawchanges.Add("The law was '[newFreeFormLaw]'") + global.lawchanges.Add("The law was '[newFreeFormLaw]'") /obj/item/aiModule/freeform/install(obj/machinery/computer/C, mob/user) if(!newFreeFormLaw) @@ -227,14 +224,13 @@ AI MODULES /obj/item/aiModule/reset name = "\improper 'Reset' AI module" - var/targetName = "name" desc = "A 'reset' AI module: 'Clears all, except the inherent, laws.'." - origin_tech = "{'programming':3,'materials':4}" + origin_tech = @'{"programming":3,"materials":4}' /obj/item/aiModule/reset/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) log_law_changes(target, sender) - if (!target.is_traitor()) + if (!target.is_malfunctioning()) target.set_zeroth_law("") target.laws.clear_supplied_laws() target.laws.clear_ion_laws() @@ -247,12 +243,12 @@ AI MODULES /obj/item/aiModule/purge // -- TLE name = "\improper 'Purge' AI module" desc = "A 'purge' AI Module: 'Purges all laws.'." - origin_tech = "{'programming':3,'materials':6}" + origin_tech = @'{"programming":3,"materials":6}' /obj/item/aiModule/purge/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) log_law_changes(target, sender) - if (!target.is_traitor()) + if (!target.is_malfunctioning()) target.set_zeroth_law("") target.laws.clear_supplied_laws() target.laws.clear_ion_laws() @@ -266,14 +262,14 @@ AI MODULES /obj/item/aiModule/asimov // -- TLE name = "\improper 'Asimov' core AI module" desc = "An 'Asimov' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':4}" + origin_tech = @'{"programming":3,"materials":4}' laws = new/datum/ai_laws/asimov /******************** Drone ********************/ /obj/item/aiModule/drone name = "\improper 'Drone' core AI module" desc = "A 'Drone' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':4}" + origin_tech = @'{"programming":3,"materials":4}' laws = new/datum/ai_laws/drone /****************** P.A.L.A.D.I.N. **************/ @@ -281,7 +277,7 @@ AI MODULES /obj/item/aiModule/paladin // -- NEO name = "\improper 'P.A.L.A.D.I.N.' core AI module" desc = "A P.A.L.A.D.I.N. Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':6}" + origin_tech = @'{"programming":3,"materials":6}' laws = new/datum/ai_laws/paladin /****************** T.Y.R.A.N.T. *****************/ @@ -289,7 +285,7 @@ AI MODULES /obj/item/aiModule/tyrant // -- Darem name = "\improper 'T.Y.R.A.N.T.' core AI module" desc = "A T.Y.R.A.N.T. Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':6,'esoteric':2}" + origin_tech = @'{"programming":3,"materials":6,"esoteric":2}' laws = new/datum/ai_laws/tyrant() /******************** Freeform Core ******************/ @@ -298,7 +294,7 @@ AI MODULES name = "\improper 'Freeform' core AI module" var/newFreeFormLaw = "" desc = "A 'freeform' Core AI module: ''." - origin_tech = "{'programming':3,'materials':6}" + origin_tech = @'{"programming":3,"materials":6}' /obj/item/aiModule/freeformcore/attack_self(var/mob/user) ..() @@ -310,7 +306,7 @@ AI MODULES /obj/item/aiModule/freeformcore/addAdditionalLaws(var/mob/living/silicon/ai/target, var/mob/sender) var/law = "[newFreeFormLaw]" target.add_inherent_law(law) - GLOB.lawchanges.Add("The law is '[newFreeFormLaw]'") + global.lawchanges.Add("The law is '[newFreeFormLaw]'") /obj/item/aiModule/freeformcore/install(obj/machinery/computer/C, mob/user) if(!newFreeFormLaw) @@ -322,7 +318,7 @@ AI MODULES name = "hacked AI module" var/newFreeFormLaw = "" desc = "A hacked AI law module: ''." - origin_tech = "{'programming':3,'materials':6,'esoteric':7}" + origin_tech = @'{"programming":3,"materials":6,"esoteric":7}' /obj/item/aiModule/syndicate/attack_self(var/mob/user) ..() @@ -335,7 +331,7 @@ AI MODULES // ..() //We don't want this module reporting to the AI who dun it. --NEO log_law_changes(target, sender) - GLOB.lawchanges.Add("The law is '[newFreeFormLaw]'") + global.lawchanges.Add("The law is '[newFreeFormLaw]'") to_chat(target, "BZZZZT") var/law = "[newFreeFormLaw]" target.add_ion_law(law) @@ -354,7 +350,7 @@ AI MODULES /obj/item/aiModule/robocop // -- TLE name = "\improper 'Robocop' core AI module" desc = "A 'Robocop' Core AI Module: 'Reconfigures the AI's core three laws.'." - origin_tech = "{'programming':4}" + origin_tech = @'{"programming":4}' laws = new/datum/ai_laws/robocop() /******************** Antimov ********************/ @@ -362,5 +358,5 @@ AI MODULES /obj/item/aiModule/antimov // -- TLE name = "\improper 'Antimov' core AI module" desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':4}" + origin_tech = @'{"programming":4}' laws = new/datum/ai_laws/antimov() diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 82cc41f74548..2d17c5eef94c 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -5,87 +5,68 @@ desc = "Small, portable, and far, far heavier than it looks, this gun-shaped device has a port into which one may insert compressed matter cartridges." icon = 'icons/obj/items/device/rcd.dmi' icon_state = "rcd" - opacity = 0 - density = 0 - anchored = 0.0 + opacity = FALSE + density = FALSE + anchored = FALSE obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT|SLOT_HOLSTER - force = 10.0 - throwforce = 10.0 + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER throw_speed = 1 throw_range = 5 w_class = ITEM_SIZE_NORMAL - origin_tech = "{'engineering':4,'materials':2}" + origin_tech = @'{"engineering":4,"materials":2}' material = /decl/material/solid/metal/steel - var/datum/effect/effect/system/spark_spread/spark_system + _base_attack_force = 10 var/stored_matter = 0 var/max_stored_matter = 120 - var/work_id = 0 var/decl/hierarchy/rcd_mode/work_mode var/static/list/work_modes - var/canRwall = 0 var/disabled = 0 - var/crafting = FALSE //Rapid Crossbow Device memes /obj/item/rcd/Initialize() . = ..() if(!work_modes) - var/decl/hierarchy/h = decls_repository.get_decl(/decl/hierarchy/rcd_mode) + var/decl/hierarchy/h = GET_DECL(/decl/hierarchy/rcd_mode) work_modes = h.children work_mode = work_modes[1] + update_icon() //Initializes the ammo counter -/obj/item/rcd/attack() - return 0 +/obj/item/rcd/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE /obj/item/rcd/proc/can_use(var/mob/user,var/turf/T) - return (user.Adjacent(T) && user.get_active_hand() == src && !user.incapacitated()) + return (user.Adjacent(T) && user.get_active_held_item() == src && !user.incapacitated()) -/obj/item/rcd/examine(mob/user) +/obj/item/rcd/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(src.type == /obj/item/rcd && loc == user) - to_chat(user, "The current mode is '[work_mode]'") - to_chat(user, "It currently holds [stored_matter]/[max_stored_matter] matter-units.") + if(src.type == /obj/item/rcd && loc == user) // why tho + . += "The current mode is '[work_mode]'." + . += "It currently holds [stored_matter]/[max_stored_matter] matter-units." -/obj/item/rcd/Initialize() - . = ..() - src.spark_system = new /datum/effect/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) - update_icon() //Initializes the ammo counter - -/obj/item/rcd/Destroy() - qdel(spark_system) - spark_system = null - return ..() - -/obj/item/rcd/attackby(obj/item/W, mob/user) - - if(istype(W, /obj/item/rcd_ammo)) - var/obj/item/rcd_ammo/cartridge = W +/obj/item/rcd/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/rcd_ammo)) + var/obj/item/rcd_ammo/cartridge = used_item if((stored_matter + cartridge.remaining) > max_stored_matter) to_chat(user, "The RCD can't hold that many additional matter-units.") - return + return TRUE stored_matter += cartridge.remaining - qdel(W) + qdel(used_item) playsound(src.loc, 'sound/machines/click.ogg', 50, 1) to_chat(user, "The RCD now holds [stored_matter]/[max_stored_matter] matter-units.") update_icon() - return - - if(isScrewdriver(W)) + return TRUE + if(IS_SCREWDRIVER(used_item)) crafting = !crafting if(!crafting) - to_chat(user, "You reassemble the RCD") + to_chat(user, SPAN_NOTICE("You reassemble the RCD.")) else to_chat(user, "The RCD can now be modified.") src.add_fingerprint(user) - return - - ..() + return TRUE + return ..() /obj/item/rcd/attack_self(mob/user) //Change the mode @@ -93,14 +74,19 @@ work_mode = next_in_list(work_mode, work_modes) to_chat(user, "Changed mode to '[work_mode]'") playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) - if(prob(20)) src.spark_system.start() + if(prob(20)) + spark_at(src, amount = 5) /obj/item/rcd/afterattack(atom/A, mob/user, proximity) - if(!proximity) return + if(!proximity) + return FALSE if(disabled && !isrobot(user)) - return 0 - if(istype(get_area(A),/area/shuttle)||istype(get_area(A),/turf/space/transit)) - return 0 + return FALSE + if(istype(get_turf(A), /turf/space/transit)) + return FALSE + var/area/area = get_area(A) + if(!istype(area) || (area.area_flags & AREA_FLAG_SHUTTLE)) + return FALSE work_id++ work_mode.do_work(src, A, user) @@ -112,11 +98,11 @@ return 1 /obj/item/rcd/on_update_icon() //For the fancy "ammo" counter - overlays.Cut() + . = ..() var/ratio = 0 ratio = stored_matter / max_stored_matter ratio = max(round(ratio, 0.10) * 100, 10) - overlays += "rcd-[ratio]" + add_overlay("rcd-[ratio]") /obj/item/rcd/proc/lowAmmo(var/mob/user) //Kludge to make it animate when out of ammo, but I guess you can make it blow up when it's out of ammo or something to_chat(user, "The \'Low Ammo\' light on the device blinks yellow.") @@ -129,40 +115,51 @@ icon_state = "rcd" item_state = "rcdammo" w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':2}" + origin_tech = @'{"materials":2}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) var/remaining = 30 -/obj/item/rcd_ammo/examine(mob/user, distance) +// Full override due to the weirdness of compressed matter cart legacy matter units. +// TODO: make this use actual matter. +/obj/item/rcd_ammo/create_matter() + // Formula: 3 MU per wall == 6 steel sheets == 2 sheets per MU, /2 for glass and steel, with a + // discount for the outlay of materials (and to make the final costs less obscene). Technically + // this means you can generate steel from nothing by building walls with an RCD and then + // deconstructing them but until we have a unified matter/material system on /atom I think we're + // just going to have to cop it. + var/sheets = round((remaining * SHEET_MATERIAL_AMOUNT) * 0.75) + matter = list( + /decl/material/solid/metal/steel = sheets, + /decl/material/solid/glass = sheets + ) + +/obj/item/rcd_ammo/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "It has [remaining] unit\s of matter left.") + . += SPAN_NOTICE("It has [remaining] unit\s of matter left.") /obj/item/rcd_ammo/large name = "high-capacity matter cartridge" desc = "Do not ingest." icon_state = "rcdlarge" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) remaining = 120 - origin_tech = "{'materials':4}" + origin_tech = @'{"materials":4}' /obj/item/rcd/borg canRwall = 1 /obj/item/rcd/borg/useResource(var/amount, var/mob/user) if(isrobot(user)) - var/mob/living/silicon/robot/R = user - if(R.cell) + var/mob/living/silicon/robot/robot = user + if(robot.cell) var/cost = amount*30 - if(R.cell.charge >= cost) - R.cell.use(cost) + if(robot.cell.charge >= cost) + robot.cell.use(cost) return 1 return 0 /obj/item/rcd/borg/attackby() - return + return FALSE /obj/item/rcd/borg/can_use(var/mob/user,var/turf/T) return (user.Adjacent(T) && !user.incapacitated()) @@ -182,14 +179,15 @@ return 0 /obj/item/rcd/mounted/attackby() - return + return FALSE /obj/item/rcd/mounted/can_use(var/mob/user,var/turf/T) return (user.Adjacent(T) && !user.incapacitated()) /decl/hierarchy/rcd_mode - hierarchy_type = /decl/hierarchy/rcd_mode + abstract_type = /decl/hierarchy/rcd_mode + expected_type = /decl/hierarchy/rcd_mode var/cost var/delay var/handles_type @@ -225,7 +223,7 @@ var/result = get_work_result(target) if(ispath(result,/turf)) var/turf/T = target - T.ChangeTurf(result) + T.ChangeTurf(result, keep_air = TRUE) else if(result) new result(target) else @@ -252,7 +250,7 @@ /decl/hierarchy/rcd_mode/airlock/basic cost = 10 delay = 5 SECONDS - handles_type = /turf/simulated/floor + handles_type = /turf/floor work_type = /obj/machinery/door/airlock /decl/hierarchy/rcd_mode/airlock/basic/can_handle_work(var/rcd, var/turf/target) @@ -267,16 +265,16 @@ /decl/hierarchy/rcd_mode/floor_and_walls/base_turf cost = 1 delay = 2 SECONDS - work_type = /turf/simulated/floor/airless + work_type = /turf/floor/plating/airless /decl/hierarchy/rcd_mode/floor_and_walls/base_turf/can_handle_work(var/rcd, var/turf/target) - return istype(target) && (isspace(target) || istype(target, get_base_turf_by_area(target))) + return istype(target) && (isspaceturf(target) || istype(target, get_base_turf_by_area(target))) /decl/hierarchy/rcd_mode/floor_and_walls/floor_turf cost = 3 delay = 2 SECONDS - handles_type = /turf/simulated/floor - work_type = /turf/simulated/wall + handles_type = /turf/floor + work_type = /turf/wall /* Deconstruction @@ -295,7 +293,7 @@ /decl/hierarchy/rcd_mode/deconstruction/floor cost = 9 delay = 2 SECONDS - handles_type = /turf/simulated/floor + handles_type = /turf/floor /decl/hierarchy/rcd_mode/deconstruction/floor/get_work_result(var/target) return get_base_turf_by_area(target) @@ -303,8 +301,8 @@ /decl/hierarchy/rcd_mode/deconstruction/wall cost = 9 delay = 2 SECONDS - handles_type = /turf/simulated/wall - work_type = /turf/simulated/floor + handles_type = /turf/wall + work_type = /turf/floor/plating -/decl/hierarchy/rcd_mode/deconstruction/wall/can_handle_work(var/obj/item/rcd/rcd, var/turf/simulated/wall/target) +/decl/hierarchy/rcd_mode/deconstruction/wall/can_handle_work(var/obj/item/rcd/rcd, var/turf/wall/target) return ..() && (rcd.canRwall || !target.reinf_material) diff --git a/code/game/objects/items/weapons/RPD.dm b/code/game/objects/items/weapons/RPD.dm index c03830f58b09..91262b470c90 100644 --- a/code/game/objects/items/weapons/RPD.dm +++ b/code/game/objects/items/weapons/RPD.dm @@ -1,8 +1,8 @@ -GLOBAL_LIST_EMPTY(rpd_pipe_selection) -GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) +var/global/list/rpd_pipe_selection = list() +var/global/list/rpd_pipe_selection_skilled = list() /proc/init_rpd_lists() - GLOB.rpd_pipe_selection = list( + global.rpd_pipe_selection = list( "Regular Pipes" = list( new /datum/fabricator_recipe/pipe(), new /datum/fabricator_recipe/pipe/bent(), @@ -23,7 +23,7 @@ GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) new /datum/fabricator_recipe/pipe/scrubber/cap()) ) - GLOB.rpd_pipe_selection_skilled = list( + global.rpd_pipe_selection_skilled = list( "Regular Pipes" = list( new /datum/fabricator_recipe/pipe(), new /datum/fabricator_recipe/pipe/bent(), @@ -67,52 +67,44 @@ GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) desc = "Portable, complex and deceptively heavy, it's the cousin of the RCD, use to dispense piping on the move." icon = 'icons/obj/items/device/rpd.dmi' icon_state = "rpd" - force = 12 - throwforce = 15 throw_speed = 1 throw_range = 3 w_class = ITEM_SIZE_NORMAL - origin_tech = "{'engineering':5,'materials':4}" + origin_tech = @'{"engineering":5,"materials":4}' material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) + _base_attack_force = 12 - var/datum/effect/effect/system/spark_spread/spark_system var/datum/fabricator_recipe/pipe/P var/pipe_color = "white" - var/datum/browser/written/popup + var/datum/browser/written_digital/popup /obj/item/rpd/Initialize() . = ..() - if(!length(GLOB.rpd_pipe_selection)) - return INITIALIZE_HINT_QDEL - spark_system = new /datum/effect/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) - var/list/L = GLOB.rpd_pipe_selection[GLOB.rpd_pipe_selection[1]] + if(!length(global.rpd_pipe_selection)) + init_rpd_lists() + spark_at(src, amount = 5, holder = src) + var/list/L = global.rpd_pipe_selection[global.rpd_pipe_selection[1]] P = L[1] -/obj/item/rpd/Destroy() - QDEL_NULL(spark_system) - return ..() - /obj/item/rpd/proc/get_console_data(var/list/pipe_categories, var/color_options = FALSE) . = list() . += "" if(color_options) - . += "" + . += "" for(var/category in pipe_categories) . += "" for(var/datum/fabricator_recipe/pipe/pipe in pipe_categories[category]) - . += "" + . += "" .+= "
              Color[pipe_color]
              Color[pipe_color]
              [category]
              [pipe.name][P.type == pipe.type ? "Select" : "Select"]
              [pipe.name][P.type == pipe.type ? "Select" : "Select"]
              " . = JOINTEXT(.) /obj/item/rpd/interact(mob/user) popup = new (user, "Pipe List", "[src] menu") - popup.set_content(get_console_data(user.skill_check(SKILL_ATMOS,SKILL_EXPERT) ? GLOB.rpd_pipe_selection_skilled : GLOB.rpd_pipe_selection, TRUE)) + popup.set_content(get_console_data(user.skill_check(SKILL_ATMOS,SKILL_EXPERT) ? global.rpd_pipe_selection_skilled : global.rpd_pipe_selection, TRUE)) popup.open() /obj/item/rpd/OnTopic(var/user, var/list/href_list) @@ -120,7 +112,8 @@ GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) P = locate(href_list["select"]) playsound(src.loc, 'sound/machines/click.ogg', 50, 1) interact(user) - if(prob(10)) src.spark_system.start() + if(prob(10)) + spark_at(src, amount = 5, holder = src) return TOPIC_HANDLED if(href_list["color"]) var/choice = input(user, "What color do you want pipes to have?") as null|anything in pipe_colors @@ -141,8 +134,8 @@ GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) recycle(A,user) else if(user.skill_fail_prob(SKILL_ATMOS, 80, SKILL_ADEPT)) - var/C = pick(GLOB.rpd_pipe_selection) - P = pick(GLOB.rpd_pipe_selection[C]) + var/C = pick(global.rpd_pipe_selection) + P = pick(global.rpd_pipe_selection[C]) user.visible_message(SPAN_WARNING("[user] cluelessly fumbles with \the [src].")) var/turf/T = get_turf(A) if(!T.Adjacent(src.loc)) return //checks so it can't pipe through window and such @@ -153,14 +146,15 @@ GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) return playsound(get_turf(user), 'sound/items/Deconstruct.ogg', 50, 1) - P.build(T, 1, pipe_colors[pipe_color]) - if(prob(20)) src.spark_system.start() + P.build(T, new/datum/fabricator_build_order(P, 1, list("selected_color" = pipe_colors[pipe_color]))) + if(prob(20)) + spark_at(src, amount = 5, holder = src) -/obj/item/rpd/examine(var/mob/user, distance) +/obj/item/rpd/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) if(user.skill_check(SKILL_ATMOS,SKILL_BASIC)) - to_chat(user, "Current selection reads: [P]") + . += "[SPAN_NOTICE("Current selection reads:")] [P]" else to_chat(user, SPAN_WARNING("The readout is flashing some atmospheric jargon, you can't understand.")) @@ -168,17 +162,17 @@ GLOBAL_LIST_EMPTY(rpd_pipe_selection_skilled) interact(user) add_fingerprint(user) -/obj/item/rpd/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/pipe)) - if(!user.unEquip(W)) - return - recycle(W,user) - return - ..() +/obj/item/rpd/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/pipe)) + if(!user.try_unequip(used_item)) + return TRUE + recycle(used_item,user) + return TRUE + return ..() -/obj/item/rpd/proc/recycle(var/obj/item/W,var/mob/user) +/obj/item/rpd/proc/recycle(var/obj/item/used_item,var/mob/user) if(!user.skill_check(SKILL_ATMOS,SKILL_BASIC)) - user.visible_message("[user] struggles with \the [src], as they futilely jam \the [W] against it") + user.visible_message("\The [user] struggles with \the [src] as they futilely jam \the [used_item] against it.") return playsound(src.loc, 'sound/effects/pop.ogg', 50, 1) - qdel(W) \ No newline at end of file + qdel(used_item) \ No newline at end of file diff --git a/code/game/objects/items/weapons/RSF.dm b/code/game/objects/items/weapons/RSF.dm index 77aaad779746..977b8c1909c3 100644 --- a/code/game/objects/items/weapons/RSF.dm +++ b/code/game/objects/items/weapons/RSF.dm @@ -9,70 +9,77 @@ RSF desc = "A device used to rapidly deploy service items." icon = 'icons/obj/items/device/rcd.dmi' icon_state = "rcd" - opacity = 0 - density = 0 - anchored = 0.0 + opacity = FALSE + density = FALSE + anchored = FALSE var/stored_matter = 30 var/mode = 1 w_class = ITEM_SIZE_NORMAL - -/obj/item/rsf/examine(mob/user, distance) + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE + ) + +/obj/item/rsf/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance <= 0) - to_chat(user, "It currently holds [stored_matter]/30 fabrication-units.") - -/obj/item/rsf/attackby(obj/item/W, mob/user) - ..() - if (istype(W, /obj/item/rcd_ammo)) + if(distance <= 1) + . += "It currently holds [stored_matter]/30 fabrication-units." +/obj/item/rsf/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/rcd_ammo)) if ((stored_matter + 10) > 30) to_chat(user, "The RSF can't hold any more matter.") - return - - qdel(W) - + return TRUE + qdel(used_item) stored_matter += 10 playsound(src.loc, 'sound/machines/click.ogg', 10, 1) to_chat(user, "The RSF now holds [stored_matter]/30 fabrication-units.") - return + return TRUE + return ..() /obj/item/rsf/attack_self(mob/user) playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) if (mode == 1) mode = 2 - to_chat(user, "Changed dispensing mode to 'Drinking Glass'") + to_chat(user, "Changed dispensing mode to 'Drinking Glass'.") return if (mode == 2) mode = 3 - to_chat(user, "Changed dispensing mode to 'Paper'") + to_chat(user, "Changed dispensing mode to 'Paper'.") return if (mode == 3) mode = 4 - to_chat(user, "Changed dispensing mode to 'Pen'") + to_chat(user, "Changed dispensing mode to 'Pen'.") return if (mode == 4) mode = 5 - to_chat(user, "Changed dispensing mode to 'Dice Pack'") + to_chat(user, "Changed dispensing mode to 'Dice Pack'.") return if (mode == 5) mode = 1 - to_chat(user, "Changed dispensing mode to 'Cigarette'") + to_chat(user, "Changed dispensing mode to 'Cigarette'.") return /obj/item/rsf/afterattack(atom/A, mob/user, proximity) if(!proximity) return - if(istype(user,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = user - if(R.stat || !R.cell || R.cell.charge <= 0) + if(isrobot(user)) + var/mob/living/silicon/robot/robot = user + if(robot.stat || !robot.cell || robot.cell.charge <= 0) return else if(stored_matter <= 0) return - if(!istype(A, /obj/structure/table) && !istype(A, /turf/simulated/floor)) - return + if(!istype(A, /obj/structure/table)) + if(!isturf(A)) + return + var/turf/turf = A + if(!turf.is_floor() || !turf.simulated) + return playsound(src.loc, 'sound/machines/click.ogg', 10, 1) var/used_energy = 0 @@ -83,7 +90,7 @@ RSF product = new /obj/item/clothing/mask/smokable/cigarette() used_energy = 10 if(2) - product = new /obj/item/chems/food/drinks/glass2() + product = new /obj/item/chems/drinks/glass2() used_energy = 50 if(3) product = new /obj/item/paper() @@ -92,16 +99,16 @@ RSF product = new /obj/item/pen() used_energy = 50 if(5) - product = new /obj/item/storage/pill_bottle/dice() + product = new /obj/item/pill_bottle/dice() used_energy = 200 to_chat(user, "Dispensing [product ? product : "product"]...") product.dropInto(A.loc) if(isrobot(user)) - var/mob/living/silicon/robot/R = user - if(R.cell) - R.cell.use(used_energy) + var/mob/living/silicon/robot/robot = user + if(robot.cell) + robot.cell.use(used_energy) else stored_matter-- to_chat(user, "The RSF now holds [stored_matter]/30 fabrication-units.") diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm index 8424759a1cee..b71582135b02 100644 --- a/code/game/objects/items/weapons/autopsy.dm +++ b/code/game/objects/items/weapons/autopsy.dm @@ -8,7 +8,7 @@ icon_state = "autopsy_scanner" obj_flags = OBJ_FLAG_CONDUCTIBLE w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':1,'biotech':1}" + origin_tech = @'{"materials":1,"biotech":1}' var/list/weapon_data = list() var/list/chemtraces = list() var/target_name @@ -17,16 +17,16 @@ /obj/item/scanner/autopsy/is_valid_scan_target(atom/O) return ishuman(O) || istype(O, /obj/item/organ/external) -/obj/item/scanner/autopsy/do_surgery(mob/living/carbon/M, mob/living/user, fuckup_prob) +/obj/item/scanner/autopsy/do_surgery(mob/living/M, mob/living/user, fuckup_prob) if(istype(M)) scan(M,user) /obj/item/scanner/autopsy/scan(atom/A, mob/user) if(ishuman(A)) - var/mob/living/carbon/human/M = A + var/mob/living/human/M = A set_target(M, user) timeofdeath = M.timeofdeath - var/obj/item/organ/external/S = M.get_organ(user.zone_sel.selecting) + var/obj/item/organ/external/S = GET_EXTERNAL_ORGAN(M, user.get_target_zone()) if(!S) visible_message(SPAN_WARNING("[src] states, 'The targeted bodypart is missing.'")) return @@ -34,31 +34,30 @@ visible_message(SPAN_WARNING("[src] states, 'The access incision is missing.'")) return - add_data(S) - for(var/T in M.chem_doses) - var/decl/material/R = T - chemtraces |= initial(R.name) + add_autopsy_data(S) + for(var/decl/material/reagent as anything in M._chem_doses) + chemtraces |= reagent.use_name else if(istype(A, /obj/item/organ/external)) set_target(A, user) - add_data(A) - - scan_title = "Autopsy Report ([target_name])" + add_autopsy_data(A) + + scan_title = "Autopsy Report ([target_name])" scan_data = get_formatted_data() playsound(src, 'sound/effects/fastbeep.ogg', 10) -/obj/item/scanner/autopsy/proc/add_data(var/obj/item/organ/external/O) - if(!O.autopsy_data.len) return +/obj/item/scanner/autopsy/proc/add_autopsy_data(var/obj/item/organ/external/O) + if(!length(O.autopsy_data)) + return for(var/V in O.autopsy_data) - var/datum/autopsy_data/W = O.autopsy_data[V] - if(!weapon_data[V]) - weapon_data[V] = list("data" = W.copy(), "organs" = list(O.name)) - else + var/datum/autopsy_data/wound_data = O.autopsy_data[V] + if(weapon_data[V]) var/datum/autopsy_data/data = weapon_data[V]["data"] - data.merge_with(W) - var/list/organs = weapon_data[V]["organs"] - organs |= O.name + data.merge_with(wound_data) + weapon_data[V]["organs"] |= O.name + else + weapon_data[V] = list("data" = wound_data.copy(), "organs" = list(O.name)) /obj/item/scanner/autopsy/proc/get_formatted_data() var/list/scan_data = list("Subject: [target_name]") @@ -66,11 +65,11 @@ if(timeofdeath) scan_data += "Time of death: [worldtime2stationtime(timeofdeath)]
              " - var/n = 1 + var/weapon_count = 1 for(var/weapon in weapon_data) var/list/organs = weapon_data[weapon]["organs"] var/datum/autopsy_data/data = weapon_data[weapon]["data"] - scan_data += "Weapon #[n++]: [data.weapon]" + scan_data += "Weapon #[weapon_count++]: [data.weapon]" if(data.hits) var/damage_desc switch(data.damage) @@ -111,12 +110,12 @@ var/time_inflicted = 0 /datum/autopsy_data/proc/copy() - var/datum/autopsy_data/W = new() - W.weapon = weapon - W.damage = damage - W.hits = hits - W.time_inflicted = time_inflicted - return W + var/datum/autopsy_data/wound_data = new() + wound_data.weapon = weapon + wound_data.damage = damage + wound_data.hits = hits + wound_data.time_inflicted = time_inflicted + return wound_data /datum/autopsy_data/proc/merge_with(var/datum/autopsy_data/other) damage += other.damage diff --git a/code/game/objects/items/weapons/balls.dm b/code/game/objects/items/weapons/balls.dm new file mode 100644 index 000000000000..52f53f9076ef --- /dev/null +++ b/code/game/objects/items/weapons/balls.dm @@ -0,0 +1,27 @@ +/obj/item/ball + name = "beach ball" + icon = 'icons/obj/beachball.dmi' + icon_state = ICON_STATE_WORLD + density = FALSE + anchored = FALSE + w_class = ITEM_SIZE_HUGE + throw_speed = 1 + throw_range = 20 + obj_flags = OBJ_FLAG_CONDUCTIBLE + material = /decl/material/solid/organic/plastic + +/obj/item/ball/afterattack(atom/target, mob/user) + if(user.try_unequip(src)) + src.throw_at(target, throw_range, throw_speed, user) + +/obj/item/ball/volleyball + name = "volleyball" + icon = 'icons/obj/volleyball.dmi' + desc = "You can be my wingman anytime." + w_class = ITEM_SIZE_LARGE + +/obj/item/ball/basketball + name = "basketball" + desc = "Here's your chance, do your dance at the Space Jam." + icon = 'icons/obj/basketball.dmi' + w_class = ITEM_SIZE_LARGE diff --git a/code/game/objects/items/weapons/beachball.dm b/code/game/objects/items/weapons/beachball.dm deleted file mode 100644 index 39fdb2d732d4..000000000000 --- a/code/game/objects/items/weapons/beachball.dm +++ /dev/null @@ -1,17 +0,0 @@ -/obj/item/beach_ball - icon = 'icons/misc/beach.dmi' - icon_state = "ball" - name = "beach ball" - item_state = "beachball" - density = 0 - anchored = 0 - w_class = ITEM_SIZE_HUGE - force = 0.0 - throwforce = 0.0 - throw_speed = 1 - throw_range = 20 - obj_flags = OBJ_FLAG_CONDUCTIBLE - -/obj/item/beach_ball/afterattack(atom/target, mob/user) - if(user.unequip_item()) - src.throw_at(target, throw_range, throw_speed, user) \ No newline at end of file diff --git a/code/game/objects/items/weapons/broom.dm b/code/game/objects/items/weapons/broom.dm new file mode 100644 index 000000000000..e6ac21587bba --- /dev/null +++ b/code/game/objects/items/weapons/broom.dm @@ -0,0 +1,75 @@ +/obj/item/staff/broom + name = "broom" + desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." + icon = 'icons/obj/items/broom.dmi' + matter = list(/decl/material/solid/organic/cloth = MATTER_AMOUNT_SECONDARY) + var/bristle_material = /decl/material/solid/organic/plantmatter/grass/dry + +/obj/item/staff/broom/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(bristle_material) + var/decl/material/bristle_mat = GET_DECL(bristle_material) + . += "\The [src]'s bristles are made from [bristle_mat.name]." + +/obj/item/staff/broom/Initialize(ml, material_key, bristles_key) + if(!isnull(bristles_key)) + bristle_material = bristles_key + . = ..() + if(bristle_material) + update_icon() + +/obj/item/staff/broom/on_update_icon() + . = ..() + if(bristle_material) + var/bristle_state = "[icon_state]-bristles" + if(check_state_in_icon(bristle_state, icon)) + var/decl/material/bristle_mat = GET_DECL(bristle_material) + add_overlay(overlay_image(icon, bristle_state, bristle_mat.color, RESET_COLOR)) + +/obj/item/staff/broom/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && bristle_material) + var/bristle_state = "[overlay.icon_state]-bristles" + if(check_state_in_icon(bristle_state, overlay.icon)) + var/decl/material/bristle_mat = GET_DECL(bristle_material) + overlay.overlays += overlay_image(overlay.icon, bristle_state, bristle_mat.color, RESET_COLOR) + . = ..() + +/obj/item/staff/broom/can_make_broom_with(mob/user, obj/item/thing) + return FALSE + +/obj/item/staff/broom/resolve_attackby(atom/A, mob/user, click_params) + + if(!user.check_intent(I_FLAG_HARM)) + + // Sweep up dirt. + if(isturf(A)) + + var/turf/cleaning = A + + var/dirty = cleaning.get_dirt() + if(dirty > 10) // a small amount so that you can't sweep immediately after someone walks somewhere + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.visible_message(SPAN_NOTICE("\The [user] sweeps \the [A].")) + playsound(A, "sweeping", 100, TRUE) + cleaning.remove_dirt(min(dirty, rand(20,30))) + return TRUE + + var/obj/effect/footprints/prints = locate() in cleaning + if(prints) + user.visible_message(SPAN_NOTICE("\The [user] sweeps away the footprints.")) + return TRUE + + to_chat(user, SPAN_WARNING("\The [cleaning] is not in need of sweeping.")) + return TRUE + + // Sweep up dry spills. + if(istype(A, /obj/effect/decal/cleanable)) + var/obj/effect/decal/cleanable/cleaning = A + if(cleaning.sweepable) + user.visible_message(SPAN_NOTICE("\The [user] sweeps up \the [A].")) + qdel(A) + else + to_chat(user, SPAN_WARNING("\The [cleaning] cannot be swept up.")) + return TRUE + + . = ..() diff --git a/code/game/objects/items/weapons/candle/candle.dm b/code/game/objects/items/weapons/candle/candle.dm deleted file mode 100644 index 33f925924f69..000000000000 --- a/code/game/objects/items/weapons/candle/candle.dm +++ /dev/null @@ -1,90 +0,0 @@ -/obj/item/flame/candle - name = "candle" - desc = "A small pillar candle. Its specially-formulated fuel-oxidizer wax mixture allows continued combustion in airless environments." - icon = 'icons/obj/candle.dmi' - icon_state = "candle1" - item_state = "candle1" - w_class = ITEM_SIZE_TINY - light_color = "#e09d37" - - var/available_colours = list(COLOR_WHITE, COLOR_DARK_GRAY, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_INDIGO, COLOR_VIOLET) - var/wax - var/last_lit - var/icon_set = "candle" - var/candle_max_bright = 0.3 - var/candle_inner_range = 0.1 - var/candle_outer_range = 4 - var/candle_falloff = 2 - -/obj/item/flame/candle/Initialize() - wax = rand(27 MINUTES, 33 MINUTES) / SSobj.wait // Enough for 27-33 minutes. 30 minutes on average, adjusted for subsystem tickrate. - if(available_colours) - color = pick(available_colours) - . = ..() - -/obj/item/flame/candle/on_update_icon() - switch(wax) - if(1500 to INFINITY) - icon_state = "[icon_set]1" - if(800 to 1500) - icon_state = "[icon_set]2" - else - icon_state = "[icon_set]3" - - if(lit != last_lit) - last_lit = lit - overlays.Cut() - if(lit) - overlays += overlay_image(icon, "[icon_state]_lit", flags=RESET_COLOR) - -/obj/item/flame/candle/attackby(obj/item/W, mob/user) - ..() - if(W.isflamesource() || W.get_heat() > T100C) - light(user) - -/obj/item/flame/candle/resolve_attackby(var/atom/A, mob/user) - . = ..() - if(istype(A, /obj/item/flame/candle) && lit) - var/obj/item/flame/candle/other_candle = A - other_candle.light() - -/obj/item/flame/candle/proc/light(mob/user) - if(!lit) - lit = 1 - visible_message("\The [user] lights the [name].") - set_light(candle_max_bright, candle_inner_range, candle_outer_range, candle_falloff) - START_PROCESSING(SSobj, src) - -/obj/item/flame/candle/Process() - if(!lit) - return - wax-- - if(!wax) - var/obj/item/trash/candle/C = new(loc) - C.color = color - qdel(src) - return - update_icon() - if(istype(loc, /turf)) //start a fire if possible - var/turf/T = loc - T.hotspot_expose(700, 5) - -/obj/item/flame/candle/attack_self(mob/user) - if(lit) - lit = 0 - update_icon() - set_light(0) - remove_extension(src, /datum/extension/scent) - -/obj/item/storage/candle_box - name = "candle pack" - desc = "A pack of unscented candles in a variety of colours." - icon = 'icons/obj/candle.dmi' - icon_state = "candlebox" - throwforce = 2 - w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - max_storage_space = 7 - slot_flags = SLOT_BELT - - startswith = list(/obj/item/flame/candle = 7) \ No newline at end of file diff --git a/code/game/objects/items/weapons/candle/incense.dm b/code/game/objects/items/weapons/candle/incense.dm deleted file mode 100644 index b30ec3f18791..000000000000 --- a/code/game/objects/items/weapons/candle/incense.dm +++ /dev/null @@ -1,28 +0,0 @@ -/obj/item/flame/candle/scented/incense - name = "incense cone" - desc = "An incense cone. It produces fragrant smoke when burned." - icon_state = "incense1" - - available_colours = null - icon_set = "incense" - candle_max_bright = 0.1 - candle_inner_range = 0.1 - candle_outer_range = 1 - candle_falloff = 2 - - scent_types = list(/decl/scent_type/rose, - /decl/scent_type/citrus, - /decl/scent_type/sage, - /decl/scent_type/frankincense, - /decl/scent_type/mint, - /decl/scent_type/champa, - /decl/scent_type/lavender, - /decl/scent_type/sandalwood) - -/obj/item/storage/candle_box/incense - name = "incense box" - desc = "A pack of 'Tres' brand incense cones, in a variety of scents." - icon_state = "incensebox" - max_storage_space = 9 - - startswith = list(/obj/item/flame/candle/scented/incense = 9) \ No newline at end of file diff --git a/code/game/objects/items/weapons/candle/scented.dm b/code/game/objects/items/weapons/candle/scented.dm deleted file mode 100644 index ea58d4006885..000000000000 --- a/code/game/objects/items/weapons/candle/scented.dm +++ /dev/null @@ -1,46 +0,0 @@ -/obj/item/flame/candle/scented - name = "scented candle" - desc = "A candle which releases pleasant-smelling oils into the air when burned." - - var/scent //for the desc - var/decl/scent_type/style - var/list/scent_types = list(/decl/scent_type/rose, - /decl/scent_type/cinnamon, - /decl/scent_type/vanilla, - /decl/scent_type/seabreeze, - /decl/scent_type/lavender) - -/obj/item/flame/candle/scented/Initialize() - . = ..() - get_scent() - -/obj/item/flame/candle/scented/attack_self(mob/user) - ..() - if(!lit) - remove_extension(src, /datum/extension/scent) - -/obj/item/flame/candle/scented/extinguish(var/mob/user, var/no_message) - ..() - remove_extension(src, /datum/extension/scent) - -/obj/item/flame/candle/scented/light(mob/user) - ..() - if(lit) - set_extension(src, style.scent_datum) - -/obj/item/flame/candle/scented/proc/get_scent() - var/scent_type = safepick(scent_types) - if(scent_type) - style = decls_repository.get_decl(scent_type) - color = style.color - scent = style.scent - if(scent) - desc += " This one smells of [scent]." - update_icon() - -/obj/item/storage/candle_box/scented - name = "scented candle box" - desc = "An unbranded pack of scented candles, in a variety of scents." - max_storage_space = 5 - - startswith = list(/obj/item/flame/candle/scented = 5) \ No newline at end of file diff --git a/code/game/objects/items/weapons/cane.dm b/code/game/objects/items/weapons/cane.dm index 58f3a1ab246e..2fef3513ae38 100644 --- a/code/game/objects/items/weapons/cane.dm +++ b/code/game/objects/items/weapons/cane.dm @@ -1,32 +1,56 @@ /obj/item/cane - name = "cane" - desc = "A cane used by a true gentlemen. Or a clown." - icon = 'icons/obj/items/cane.dmi' - icon_state = "cane" - item_state = "stick" - obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 5.0 - throwforce = 7.0 - w_class = ITEM_SIZE_SMALL - material = /decl/material/solid/metal/aluminium - attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") - base_parry_chance = 30 + name = "cane" + desc = "A slender cane, used to keep yourself upright or to thrash rapscallions." + icon = 'icons/obj/items/cane.dmi' + icon_state = ICON_STATE_WORLD + base_parry_chance = 10 + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/wood/ebony + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/item/cane/get_stance_support_value() + return LIMB_UNUSABLE /obj/item/cane/get_autopsy_descriptors() . = ..() . += "narrow" -/obj/item/cane/concealed - var/concealed_blade +/obj/item/cane/fancy/Initialize(ml, material_key) + if(tip_material) + LAZYSET(matter, tip_material, MATTER_AMOUNT_TRACE) + . = ..() + if(tip_material) + update_icon() -/obj/item/cane/concealed/Initialize() +/obj/item/cane/fancy/on_update_icon() . = ..() - var/obj/item/knife/folding/combat/switchblade/temp_blade = new(src) - concealed_blade = temp_blade + if(tip_material) + var/decl/material/tip = GET_DECL(tip_material) + var/tip_state = "[icon_state]-tip" + if(check_state_in_icon(tip_state, icon)) + add_overlay(overlay_image(icon, tip_state, tip.color, (RESET_COLOR | RESET_ALPHA))) + +/obj/item/cane/aluminium + material = /decl/material/solid/metal/aluminium + +/obj/item/cane/fancy + desc = "An elegant cane with a reinforced tip." + var/tip_material = /decl/material/solid/organic/bone //No ivory material :c + +/obj/item/cane/fancy/sword + var/obj/item/concealed_blade = /obj/item/knife/folding/combat/switchblade -/obj/item/cane/concealed/attack_self(var/mob/user) - if(concealed_blade) - user.visible_message("[user] has unsheathed \a [concealed_blade] from [src]!", "You unsheathe \the [concealed_blade] from [src].") +/obj/item/cane/fancy/sword/Initialize() + if(ispath(concealed_blade)) + concealed_blade = new concealed_blade(src) + . = ..() + +/obj/item/cane/fancy/sword/attack_self(var/mob/user) + if(istype(concealed_blade)) + user.visible_message( + SPAN_WARNING("\The [user] unsheaths \a [concealed_blade] from \the [src]!"), + SPAN_NOTICE("You unsheathe \the [concealed_blade] from \the [src].") + ) // Calling drop/put in hands to properly call item drop/pickup procs playsound(user.loc, 'sound/weapons/flipblade.ogg', 50, 1) user.drop_from_inventory(src) @@ -34,27 +58,26 @@ user.put_in_hands(src) concealed_blade = null update_icon() - user.update_inv_l_hand() - user.update_inv_r_hand() - else - ..() + return TRUE + return ..() -/obj/item/cane/concealed/attackby(var/obj/item/knife/folding/W, var/mob/user) - if(!src.concealed_blade && istype(W) && user.unEquip(W, src)) - user.visible_message("[user] has sheathed \a [W] into [src]!", "You sheathe \the [W] into [src].") - src.concealed_blade = W +/obj/item/cane/fancy/sword/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(concealed_blade) && istype(used_item, /obj/item/knife/folding) && user.try_unequip(used_item, src)) + user.visible_message( + SPAN_NOTICE("\The [user] has sheathed \a [used_item] into \the [src]."), + SPAN_NOTICE("You sheathe \the [used_item] into \the [src].") + ) + concealed_blade = used_item update_icon() - user.update_inv_l_hand() - user.update_inv_r_hand() - else - ..() + user.update_inhand_overlays() + return TRUE + return ..() -/obj/item/cane/concealed/on_update_icon() - if(concealed_blade) - SetName(initial(name)) - icon_state = initial(icon_state) - item_state = initial(item_state) +/obj/item/cane/fancy/sword/on_update_icon() + icon_state = get_world_inventory_state() + if(istype(concealed_blade)) + SetName("[initial(name)] shaft") else - SetName("cane shaft") - icon_state = "cane_noknife" - item_state = "foldcane" \ No newline at end of file + SetName(initial(name)) + icon_state = "[icon_state]-unsheathed" + . = ..() diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 3af917000587..bbb9ad4d1e26 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -1,22 +1,24 @@ /* Cards * Contains: - * DATA CARD - * ID CARD - * FINGERPRINT CARD HOLDER - * FINGERPRINT CARD + * UNION CARD + * DATA CARDS + * EMAG & BROKEN EMAG + * ID CARDS */ - - -/* - * DATA CARDS - Used for the IC data card reader - */ /obj/item/card name = "card" desc = "Does card things." icon = 'icons/obj/card.dmi' w_class = ITEM_SIZE_TINY + material = /decl/material/solid/organic/plastic slot_flags = SLOT_EARS + drop_sound = 'sound/foley/paperpickup1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + +/* + * UNION CARD + */ /obj/item/card/union name = "union card" @@ -25,25 +27,29 @@ slot_flags = SLOT_ID var/signed_by -/obj/item/card/union/examine(mob/user) +/obj/item/card/union/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(signed_by) - to_chat(user, "It has been signed by [signed_by].") + . += "It has been signed by [signed_by]." else - to_chat(user, "It has a blank space for a signature.") + . += "It has a blank space for a signature." -/obj/item/card/union/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing, /obj/item/pen)) +/obj/item/card/union/attackby(var/obj/item/used_item, var/mob/user) + if(IS_PEN(used_item)) if(signed_by) to_chat(user, SPAN_WARNING("\The [src] has already been signed.")) else - var/signature = sanitizeSafe(input("What do you want to sign the card as?", "Union Card") as text, MAX_NAME_LEN) + var/signature = sanitize_safe(input("What do you want to sign the card as?", "Union Card") as text, MAX_NAME_LEN) if(signature && !signed_by && !user.incapacitated() && Adjacent(user)) signed_by = signature user.visible_message(SPAN_NOTICE("\The [user] signs \the [src] with a flourish.")) - return - ..() + return TRUE + return ..() +/* + * DATA CARDS - Used for the IC data card reader and, for some reason, faxes and teleporters. + */ +// Please modpack this once those last two are made to use data disks instead. /obj/item/card/data name = "data card" desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one has a stripe running down the middle." @@ -51,36 +57,28 @@ var/detail_color = COLOR_ASSEMBLY_ORANGE var/function = "storage" var/data = "null" - var/special = null - var/list/files = list( ) /obj/item/card/data/Initialize() - .=..() + . = ..() update_icon() /obj/item/card/data/on_update_icon() - overlays.Cut() - var/image/detail_overlay = image('icons/obj/card.dmi', src,"[icon_state]-color") - detail_overlay.color = detail_color - overlays += detail_overlay - -/obj/item/card/data/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/integrated_electronics/detailer)) - var/obj/item/integrated_electronics/detailer/D = I - detail_color = D.detail_color - update_icon() - return ..() + . = ..() + add_overlay(overlay_image(icon, "[icon_state]-color", detail_color)) /obj/item/card/data/full_color desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one has the entire card colored." icon_state = "data_2" /obj/item/card/data/disk - desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one inexplicibly looks like a floppy disk." + desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one inexplicably looks like a floppy disk." icon_state = "data_3" +/obj/item/card/data/get_assembly_detail_color() + return detail_color + /* - * ID CARDS + * EMAG & BROKEN EMAG */ /obj/item/card/emag_broken @@ -88,14 +86,14 @@ name = "broken cryptographic sequencer" icon_state = "emag" item_state = "card-id" - origin_tech = "{'magnets':2,'esoteric':2}" + origin_tech = @'{"magnets":2,"esoteric":2}' /obj/item/card/emag desc = "It's a card with a magnetic strip attached to some circuitry." name = "cryptographic sequencer" icon_state = "emag" item_state = "card-id" - origin_tech = "{'magnets':2,'esoteric':2}" + origin_tech = @'{"magnets":2,"esoteric":2}' var/uses = 10 var/static/list/card_choices = list( @@ -107,7 +105,7 @@ /obj/item/card/id, ) //Should be enough of a selection for most purposes -var/const/NO_EMAG_ACT = -50 +var/global/const/NO_EMAG_ACT = -50 /obj/item/card/emag/resolve_attackby(atom/A, mob/user) var/used_uses = A.emag_act(uses, user, src) if(used_uses == NO_EMAG_ACT) @@ -142,10 +140,14 @@ var/const/NO_EMAG_ACT = -50 disguise(card_choices[picked], usr) -/obj/item/card/emag/examine(mob/user) +/obj/item/card/emag/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(user.skill_check(SKILL_DEVICES,SKILL_ADEPT)) - to_chat(user, SPAN_WARNING("This ID card has some form of non-standard modifications.")) + . += SPAN_WARNING("This ID card has some form of non-standard modifications.") + +/* + * ID CARDS + */ /obj/item/card/id name = "identification card" @@ -155,22 +157,21 @@ var/const/NO_EMAG_ACT = -50 var/list/access = list() var/registered_name = "Unknown" // The name registered_name on the card var/associated_account_number = 0 - var/list/associated_email_login = list("login" = "", "password" = "") + + // Associated network account. For normal IDs this is simply informational, but for network enabled IDs this is used for group-based access. + var/list/associated_network_account = list("login" = "", "password" = "") var/age = "\[UNSET\]" var/blood_type = "\[UNSET\]" var/dna_hash = "\[UNSET\]" var/fingerprint_hash = "\[UNSET\]" - var/sex = "\[UNSET\]" + var/card_gender = "\[UNSET\]" var/icon/front var/icon/side //alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system - var/assignment = null //can be alt title or the actual job - var/rank = null //actual job - var/dorm = 0 // determines if this ID has claimed a dorm already - - var/job_access_type // Job type to acquire access rights from, if any + var/assignment //can be alt title or the actual job + var/position // actual job var/datum/mil_branch/military_branch = null //Vars for tracking branches and ranks on multi-crewtype maps var/datum/mil_rank/military_rank = null @@ -182,42 +183,36 @@ var/const/NO_EMAG_ACT = -50 var/extra_details /obj/item/card/id/Initialize() - .=..() - if(job_access_type) - var/datum/job/j = SSjobs.get_by_path(job_access_type) - if(j) - rank = j.title - assignment = rank - access |= j.get_access() - if(!detail_color) - detail_color = j.selection_color + . = ..() update_icon() -/obj/item/card/id/get_mob_overlay(mob/user_mob, slot) - var/image/ret = ..() - if(detail_color) - ret.overlays += overlay_image(ret.icon, "[ret.icon_state]-colors", detail_color, RESET_COLOR) - return ret +/obj/item/card/id/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && detail_color) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-colors", detail_color, RESET_COLOR) + . = ..() /obj/item/card/id/on_update_icon() - cut_overlays() + . = ..() if(detail_color) add_overlay(overlay_image(icon, "[icon_state]-colors", detail_color, RESET_COLOR)) for(var/detail in extra_details) - add_overlay(overlay_image(icon, detail, flags = RESET_COLOR)) + add_overlay(overlay_image(icon, "[icon_state]-[detail]", flags = RESET_COLOR)) /obj/item/card/id/Topic(href, href_list, datum/topic_state/state) var/mob/user = usr if(href_list["look_at_id"] && istype(user)) var/turf/T = get_turf(src) - if(T.CanUseTopic(user, GLOB.view_state) != STATUS_CLOSE) - user.examinate(src) + if(T.CanUseTopic(user, global.view_topic_state) != STATUS_CLOSE) + user.examine_verb(src) return TOPIC_HANDLED . = ..() -/obj/item/card/id/examine(mob/user, distance) +/obj/item/card/id/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "It says '[get_display_name()]'." + +/obj/item/card/id/examined_by(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It says '[get_display_name()]'.") if(distance <= 1) show(user) @@ -228,9 +223,8 @@ var/const/NO_EMAG_ACT = -50 if(front && side) send_rsc(user, front, "front.png") send_rsc(user, side, "side.png") - var/datum/browser/written/popup = new(user, "idcard", name, 600, 250) + var/datum/browser/written_physical/popup = new(user, "idcard", name, 600, 250) popup.set_content(dat()) - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() return @@ -253,43 +247,42 @@ var/const/NO_EMAG_ACT = -50 id_card.formal_name_prefix = initial(id_card.formal_name_prefix) id_card.formal_name_suffix = initial(id_card.formal_name_suffix) if(client && client.prefs) - for(var/culturetag in client.prefs.cultural_info) - var/decl/cultural_info/culture = SSlore.get_culture(client.prefs.cultural_info[culturetag]) - if(culture) - id_card.formal_name_prefix = "[culture.get_formal_name_prefix()][id_card.formal_name_prefix]" - id_card.formal_name_suffix = "[id_card.formal_name_suffix][culture.get_formal_name_suffix()]" + for(var/token in client.prefs.background_info) + var/decl/background_detail/background = GET_DECL(client.prefs.background_info[token]) + if(background) + id_card.formal_name_prefix = "[background.get_formal_name_prefix()][id_card.formal_name_prefix]" + id_card.formal_name_suffix = "[id_card.formal_name_suffix][background.get_formal_name_suffix()]" id_card.registered_name = real_name - var/gender_term = "Unset" - var/datum/gender/G = gender_datums[get_sex()] - if(G) - gender_term = gender2text(G.formal_term) - id_card.sex = gender2text(gender_term) + var/decl/pronouns/pronouns = get_pronouns() + if(pronouns) + id_card.card_gender = capitalize(pronouns.bureaucratic_term ) + else + id_card.card_gender = "Unset" id_card.set_id_photo(src) - if(dna) - id_card.blood_type = dna.b_type - id_card.dna_hash = dna.unique_enzymes - id_card.fingerprint_hash= md5(dna.uni_identity) + id_card.blood_type = get_blood_type() || "Unset" + id_card.dna_hash = get_unique_enzymes() || "Unset" + id_card.fingerprint_hash = get_full_print(ignore_blockers = TRUE) || "Unset" -/mob/living/carbon/human/set_id_info(var/obj/item/card/id/id_card) +/mob/living/human/set_id_info(var/obj/item/card/id/id_card) ..() - id_card.age = age - if(GLOB.using_map.flags & MAP_HAS_BRANCH) + id_card.age = get_age() + if(global.using_map.flags & MAP_HAS_BRANCH) id_card.military_branch = char_branch - if(GLOB.using_map.flags & MAP_HAS_RANK) + if(global.using_map.flags & MAP_HAS_RANK) id_card.military_rank = char_rank /obj/item/card/id/proc/dat() var/list/dat = list("" + dat +="" dat += "
              ") dat += text("Name: []
              ", "[formal_name_prefix][registered_name][formal_name_suffix]") - dat += text("Sex: []
              \n", sex) + dat += text("Gender: []
              \n", card_gender) dat += text("Age: []
              \n", age) - if(GLOB.using_map.flags & MAP_HAS_BRANCH) + if(global.using_map.flags & MAP_HAS_BRANCH) dat += text("Branch: []
              \n", military_branch ? military_branch.name : "\[UNSET\]") - if(GLOB.using_map.flags & MAP_HAS_RANK) + if(global.using_map.flags & MAP_HAS_RANK) dat += text("Rank: []
              \n", military_rank ? military_rank.name : "\[UNSET\]") dat += text("Assignment: []
              \n", assignment) @@ -297,46 +290,105 @@ var/const/NO_EMAG_ACT = -50 dat += text("Blood Type: []
              \n", blood_type) dat += text("DNA Hash: []

              \n", dna_hash) if(front && side) - dat +="
              Photo:
              Photo:
              " return jointext(dat,null) /obj/item/card/id/attack_self(mob/user) - user.visible_message("\The [user] shows you: \icon[src] [src.name]. The assignment on the card: [src.assignment]",\ - "You flash your ID card: \icon[src] [src.name]. The assignment on the card: [src.assignment]") + user.visible_message("\The [user] shows you: [html_icon(src)] [src.name]. The assignment on the card: '[src.assignment]'.",\ + "You flash your ID card: [html_icon(src)] [src.name]. The assignment on the card: '[src.assignment]'.") src.add_fingerprint(user) return /obj/item/card/id/GetAccess() - return access + return access.Copy() -/obj/item/card/id/GetIdCard() - return src + +/obj/item/card/id/GetIdCards(list/exceptions) + . = ..() + if(!is_type_in_list(src, exceptions)) + LAZYDISTINCTADD(., src) /obj/item/card/id/verb/read() set name = "Read ID Card" set category = "Object" set src in usr - to_chat(usr, text("\icon[] []: The current assignment on the card is [].", src, src.name, src.assignment)) + to_chat(usr, "[html_icon(src)] [name]: The current assignment on the card is [assignment].") to_chat(usr, "The blood type on the card is [blood_type].") to_chat(usr, "The DNA hash on the card is [dna_hash].") to_chat(usr, "The fingerprint hash on the card is [fingerprint_hash].") return +/decl/vv_set_handler/id_card_military_branch + handled_type = /obj/item/card/id + handled_vars = list("military_branch") + +/decl/vv_set_handler/id_card_military_branch/handle_set_var(var/obj/item/card/id/id, variable, var_value, client) + if(!var_value) + id.military_branch = null + id.military_rank = null + return + + if(istype(var_value, /datum/mil_branch)) + if(var_value != id.military_branch) + id.military_branch = var_value + id.military_rank = null + return + + if(ispath(var_value, /datum/mil_branch) || istext(var_value)) + var/datum/mil_branch/new_branch = global.using_map.get_branch(var_value) + if(new_branch) + if(new_branch != id.military_branch) + id.military_branch = new_branch + id.military_rank = null + return + + to_chat(client, SPAN_WARNING("Input, must be an existing branch - [var_value] is invalid")) + +/decl/vv_set_handler/id_card_military_rank + handled_type = /obj/item/card/id + handled_vars = list("military_rank") + +/decl/vv_set_handler/id_card_military_rank/handle_set_var(var/obj/item/card/id/id, variable, var_value, client) + if(!var_value) + id.military_rank = null + return + + if(!id.military_branch) + to_chat(client, SPAN_WARNING("military_branch not set - No valid ranks available")) + return + + if(ispath(var_value, /datum/mil_rank)) + var/datum/mil_rank/rank = var_value + var_value = initial(rank.name) + + if(istype(var_value, /datum/mil_rank)) + var/datum/mil_rank/rank = var_value + var_value = rank.name + + if(istext(var_value)) + var/new_rank = global.using_map.get_rank(id.military_branch.name, var_value) + if(new_rank) + id.military_rank = new_rank + return + + to_chat(client, SPAN_WARNING("Input must be an existing rank belonging to military_branch - [var_value] is invalid")) + /obj/item/card/id/syndicate_command name = "syndicate ID card" desc = "An ID straight from the Syndicate." registered_name = "Syndicate" assignment = "Syndicate Overlord" - access = list(access_syndicate, access_external_airlocks) + access = list(access_hacked, access_external_airlocks) color = COLOR_RED_GRAY detail_color = COLOR_GRAY40 /obj/item/card/id/captains_spare name = "captain's spare ID" desc = "The spare ID of the High Lord himself." + icon_state = ICON_STATE_WORLD item_state = "gold_id" registered_name = "Captain" assignment = "Captain" @@ -346,6 +398,9 @@ var/const/NO_EMAG_ACT = -50 . = ..() access = get_all_station_access() +/obj/item/card/id/captains_spare/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE + /obj/item/card/id/synthetic name = "\improper Synthetic ID" desc = "Access module for lawed synthetics." @@ -393,7 +448,6 @@ var/const/NO_EMAG_ACT = -50 /obj/item/card/id/civilian name = "identification card" desc = "A card issued to civilian staff." - job_access_type = DEFAULT_JOB_TYPE detail_color = COLOR_CIVIE_GREEN /obj/item/card/id/civilian/head //This is not the HoP. There's no position that uses this right now. @@ -417,56 +471,4 @@ var/const/NO_EMAG_ACT = -50 name = "identification card" desc = "A golden card which shows power and might." color = "#d4c780" - extra_details = list("goldstripe") - -/* - * NETWORK-ENABLED ID CARDS - */ - -/obj/item/card/id/network - var/network_id // The network_id that this card is paired to. - var/user_id // The user's ID this card belongs to. This is typically their access_record UID, which is their cortical stack ID. - var/datum/computer_file/report/crew_record/access_record // A cached link to the access_record belonging to this card. Do not save this. - -/obj/item/card/id/network/Initialize() - set_extension(src, /datum/extension/network_device/lazy) - if(!access_record) - refresh_access_record() - return ..() - -/obj/item/card/id/network/GetAccess() - if(!access_record) - refresh_access_record() - return access - -/obj/item/card/id/network/verb/resync() - set name = "Resync ID Card" - set category = "Object" - set src in usr - - var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) - - var/datum/computer_network/network = D.get_network() - if(!network) - if(usr.skill_check(SKILL_DEVICES, SKILL_EXPERT)) - to_chat(usr, SPAN_NOTICE("The red LED on the card flashes once, signaling it has no network.")) - else - to_chat(usr, "Pressing the synchronization button on the card causes a red LED to flash once.") - return - if(refresh_access_record(network)) - to_chat(usr, "A green light flashes as the card is synchronized with its network.") - return - if(usr.skill_check(SKILL_DEVICES, SKILL_EXPERT)) - to_chat(usr, SPAN_NOTICE("The red LED on the card flashes three times, signaling it failed to synchronize the card with the network.")) - else - to_chat(usr, SPAN_WARNING("Pressing the synchronization button on the card causes a red LED to flash three times.")) - -/obj/item/card/id/network/proc/refresh_access_record(var/datum/computer_network/network) - for(var/datum/extension/network_device/mainframe/mainframe in network.get_mainframes_by_role(MF_ROLE_CREW_RECORDS)) - for(var/datum/computer_file/report/crew_record/ar in mainframe.get_all_files()) - if(ar.user_id != user_id) - continue // Mismatch user file. - // We have a match! - access_record = ar - access = ar.get_access(network_id) - return TRUE \ No newline at end of file + extra_details = list("goldstripe") \ No newline at end of file diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm index c1f93e86881a..d57a0910a492 100644 --- a/code/game/objects/items/weapons/cards_ids_syndicate.dm +++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm @@ -1,14 +1,19 @@ /obj/item/card/id/syndicate assignment = "Agent" - origin_tech = "{'esoteric':3}" + origin_tech = @'{"esoteric":3}' var/electronic_warfare = 1 var/mob/registered_user = null color = COLOR_GRAY40 detail_color = COLOR_NT_RED + var/static/list/base_access = list( + access_maint_tunnels, + access_hacked, + access_external_airlocks + ) /obj/item/card/id/syndicate/Initialize() . = ..() - access = syndicate_access.Copy() + access = base_access.Copy() /obj/item/card/id/syndicate/station_access/Initialize() . = ..() // Same as the normal Syndicate id, only already has all station access @@ -50,16 +55,16 @@ entries[++entries.len] = list("name" = "Suffix", "value" = formal_name_suffix) entries[++entries.len] = list("name" = "Appearance", "value" = "Set") entries[++entries.len] = list("name" = "Assignment", "value" = assignment) - if(GLOB.using_map.flags & MAP_HAS_BRANCH) + if(global.using_map.flags & MAP_HAS_BRANCH) entries[++entries.len] = list("name" = "Branch", "value" = military_branch ? military_branch.name : "N/A") - if(military_branch && (GLOB.using_map.flags & MAP_HAS_RANK)) + if(military_branch && (global.using_map.flags & MAP_HAS_RANK)) entries[++entries.len] = list("name" = "Rank", "value" = military_rank ? military_rank.name : "N/A") entries[++entries.len] = list("name" = "Blood Type", "value" = blood_type) entries[++entries.len] = list("name" = "DNA Hash", "value" = dna_hash) entries[++entries.len] = list("name" = "Fingerprint Hash", "value" = fingerprint_hash) entries[++entries.len] = list("name" = "Name", "value" = registered_name) entries[++entries.len] = list("name" = "Photo", "value" = "Update") - entries[++entries.len] = list("name" = "Sex", "value" = sex) + entries[++entries.len] = list("name" = "Gender", "value" = card_gender) entries[++entries.len] = list("name" = "Factory Reset", "value" = "Use With Care") data["electronic_warfare"] = electronic_warfare data["entries"] = entries @@ -76,13 +81,13 @@ unset_registered_user() registered_user = user user.set_id_info(src) - GLOB.destroyed_event.register(user, src, /obj/item/card/id/syndicate/proc/unset_registered_user) + events_repository.register(/decl/observ/destroyed, user, src, TYPE_PROC_REF(/obj/item/card/id/syndicate, unset_registered_user)) return TRUE /obj/item/card/id/syndicate/proc/unset_registered_user(var/mob/user) if(!registered_user || (user && user != registered_user)) return - GLOB.destroyed_event.unregister(registered_user, src) + events_repository.unregister(/decl/observ/destroyed, registered_user, src) registered_user = null /obj/item/card/id/syndicate/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list) @@ -94,7 +99,7 @@ if(..()) return 1 - var/user = usr + var/mob/user = usr if(href_list["electronic_warfare"]) electronic_warfare = text2num(href_list["electronic_warfare"]) to_chat(user, "Electronic warfare [electronic_warfare ? "enabled" : "disabled"].") @@ -110,13 +115,13 @@ to_chat(user, "Age has been set to '[age]'.") . = 1 if("Prefix") - var/new_prefix = sanitizeSafe(input(user,"What title prefix would you like to put on this card?","Agent Card Prefix", age) as text, MAX_NAME_LEN) + var/new_prefix = sanitize_safe(input(user,"What title prefix would you like to put on this card?","Agent Card Prefix", age) as text, MAX_NAME_LEN) if(!isnull(new_prefix) && CanUseTopic(user, state)) formal_name_prefix = new_prefix to_chat(user, "Title prefix has been set to '[formal_name_prefix]'.") . = 1 if("Suffix") - var/new_suffix = sanitizeSafe(input(user,"What title suffix would you like to put on this card?","Agent Card Suffix", age) as text, MAX_NAME_LEN) + var/new_suffix = sanitize_safe(input(user,"What title suffix would you like to put on this card?","Agent Card Suffix", age) as text, MAX_NAME_LEN) if(!isnull(new_suffix) && CanUseTopic(user, state)) formal_name_suffix = new_suffix to_chat(user, "Title suffix has been set to '[formal_name_suffix]'.") @@ -126,7 +131,7 @@ if(choice && CanUseTopic(user, state)) src.icon_state = choice.icon_state src.item_state = choice.item_state - src.color = choice.color + set_color(choice.color) src.detail_color = choice.detail_color src.extra_details = choice.extra_details update_icon() @@ -141,9 +146,7 @@ if("Blood Type") var/default = blood_type if(default == initial(blood_type) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna) - default = H.dna.b_type + default = user.get_blood_type() var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text) if(!isnull(new_blood_type) && CanUseTopic(user, state)) src.blood_type = new_blood_type @@ -152,9 +155,10 @@ if("DNA Hash") var/default = dna_hash if(default == initial(dna_hash) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna) - default = H.dna.unique_enzymes + var/mob/living/human/H = user + var/unique_enzymes = H.get_unique_enzymes() + if(unique_enzymes) + default = unique_enzymes var/new_dna_hash = sanitize(input(user,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as null|text) if(!isnull(new_dna_hash) && CanUseTopic(user, state)) src.dna_hash = new_dna_hash @@ -163,16 +167,15 @@ if("Fingerprint Hash") var/default = fingerprint_hash if(default == initial(fingerprint_hash) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna) - default = md5(H.dna.uni_identity) + var/mob/living/human/H = user + default = H.get_full_print(ignore_blockers = TRUE) var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text) if(!isnull(new_fingerprint_hash) && CanUseTopic(user, state)) src.fingerprint_hash = new_fingerprint_hash to_chat(user, "Fingerprint hash changed to '[new_fingerprint_hash]'.") . = 1 if("Name") - var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text, allow_numbers=TRUE) + var/new_name = sanitize_name(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text, allow_numbers=TRUE) if(!isnull(new_name) && CanUseTopic(user, state)) src.registered_name = new_name to_chat(user, "Name changed to '[new_name]'.") @@ -181,18 +184,18 @@ set_id_photo(user) to_chat(user, "Photo changed.") . = 1 - if("Sex") - var/new_sex = sanitize(input(user,"What sex would you like to put on this card?","Agent Card Sex", sex) as null|text) - if(!isnull(new_sex) && CanUseTopic(user, state)) - src.sex = new_sex - to_chat(user, "Sex changed to '[new_sex]'.") + if("Gender") + var/new_gender = sanitize(input(user,"What gender would you like to put on this card?","Agent Card Gender", card_gender) as null|text) + if(!isnull(new_gender) && CanUseTopic(user, state)) + src.card_gender = new_gender + to_chat(user, "Gender changed to '[new_gender]'.") . = 1 if("Factory Reset") if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state)) age = initial(age) formal_name_prefix = initial(formal_name_prefix) formal_name_suffix = initial(formal_name_suffix) - access = syndicate_access.Copy() + access = base_access.Copy() assignment = initial(assignment) blood_type = initial(blood_type) dna_hash = initial(dna_hash) @@ -205,28 +208,28 @@ SetName(initial(name)) registered_name = initial(registered_name) unset_registered_user() - sex = initial(sex) + card_gender = initial(card_gender) military_branch = initial(military_branch) military_rank = initial(military_rank) to_chat(user, "All information has been deleted from \the [src].") . = 1 if("Branch") - var/new_branch = sanitize(input(user,"What branch of service would you like to put on this card?","Agent Card Branch") as null|anything in mil_branches.spawn_branches()) + var/new_branch = sanitize(input(user,"What branch of service would you like to put on this card?","Agent Card Branch") as null|anything in global.using_map.spawn_branches()) if(!isnull(new_branch) && CanUseTopic(user, state)) - src.military_branch = mil_branches.spawn_branches()[new_branch] + src.military_branch = global.using_map.spawn_branches()[new_branch] to_chat(user, "Branch changed to '[military_branch.name]'.") . = 1 if("Rank") - var/new_rank = sanitize(input(user,"What rank would you like to put on this card?","Agent Card Rank") as null|anything in mil_branches.spawn_ranks(military_branch.name)) + var/new_rank = sanitize(input(user,"What rank would you like to put on this card?","Agent Card Rank") as null|anything in global.using_map.spawn_ranks(military_branch.name)) if(!isnull(new_rank) && CanUseTopic(user, state)) - src.military_rank = mil_branches.spawn_ranks(military_branch.name)[new_rank] + src.military_rank = global.using_map.spawn_ranks(military_branch.name)[new_rank] to_chat(user, "Rank changed to '[military_rank.name]'.") . = 1 // Always update the UI, or buttons will spin indefinitely SSnano.update_uis(src) -/var/global/list/id_card_states +var/global/list/id_card_states /proc/id_card_states() if(!id_card_states) id_card_states = list() @@ -257,7 +260,6 @@ var/item_state var/color var/detail_color - var/details var/extra_details /datum/card_state/dd_SortValue() diff --git a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm deleted file mode 100644 index a839195974fa..000000000000 --- a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm +++ /dev/null @@ -1,97 +0,0 @@ -/obj/item/stock_parts/circuitboard/air_management - name = T_BOARD("atmosphere monitoring console") - build_path = /obj/machinery/computer/air_control - var/console_name - var/frequency = 1441 - var/sensor_tag - var/sensor_name - var/list/sensor_information = list() - -/obj/item/stock_parts/circuitboard/air_management/supermatter_core - name = T_BOARD("core control") - build_path = /obj/machinery/computer/air_control/supermatter_core - frequency = 1438 - var/input_tag - var/output_tag - - var/list/input_info = list() - var/list/output_info = list() - - var/input_flow_setting = 700 - var/pressure_setting = 100 - -/obj/item/stock_parts/circuitboard/air_management/injector_control - name = T_BOARD("injector control") - build_path = /obj/machinery/computer/air_control/fuel_injection - var/device_tag - var/list/device_info - var/automation = 0 - var/cutoff_temperature = 2000 - var/on_temperature = 1200 - -/************ -* Construct * -************/ -/obj/item/stock_parts/circuitboard/air_management/construct(var/obj/machinery/computer/air_control/C) - if (..(C)) - if(console_name) - C.SetName(console_name) - C.set_frequency(frequency) - C.sensor_tag = sensor_tag - C.sensor_name = sensor_name - C.sensor_info = sensor_information.Copy() - return 1 - -/obj/item/stock_parts/circuitboard/air_management/supermatter_core/construct(var/obj/machinery/computer/air_control/supermatter_core/SC) - if(..(SC)) - SC.input_tag = input_tag - SC.output_tag = output_tag - - SC.input_info = input_info.Copy() - SC.output_info = output_info.Copy() - - SC.input_flow_setting = input_flow_setting - SC.pressure_setting = input_flow_setting - return 1 - -/obj/item/stock_parts/circuitboard/air_management/injector_control/construct(var/obj/machinery/computer/air_control/fuel_injection/FI) - if(..(FI)) - FI.device_tag = device_tag - FI.device_info = device_info.Copy() - FI.automation = automation - FI.cutoff_temperature = cutoff_temperature - FI.on_temperature = on_temperature - return 1 - -/************** -* Deconstruct * -**************/ -/obj/item/stock_parts/circuitboard/air_management/deconstruct(var/obj/machinery/computer/air_control/C) - if (..(C)) - console_name = C.name - frequency = C.frequency - sensor_tag = C.sensor_tag - sensor_name = C.sensor_name - sensor_information = C.sensor_info.Copy() - return 1 - -/obj/item/stock_parts/circuitboard/air_management/supermatter_core/deconstruct(var/obj/machinery/computer/air_control/supermatter_core/SC) - if(..(SC)) - input_tag = SC.input_tag - output_tag = SC.output_tag - - input_info = SC.input_info.Copy() - output_info = SC.output_info.Copy() - - input_flow_setting = SC.input_flow_setting - pressure_setting = SC.input_flow_setting - return 1 - -/obj/item/stock_parts/circuitboard/air_management/injector_control/deconstruct(var/obj/machinery/computer/air_control/fuel_injection/FI) - if(..(FI)) - device_tag = FI.device_tag - device_info = FI.device_info.Copy() - automation = FI.automation - cutoff_temperature = FI.cutoff_temperature - on_temperature = FI.on_temperature - return 1 \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm deleted file mode 100644 index e77dc798d5f6..000000000000 --- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm +++ /dev/null @@ -1,102 +0,0 @@ -/obj/item/stock_parts/circuitboard/message_monitor - name = T_BOARD("message monitor console") - build_path = /obj/machinery/computer/message_monitor - origin_tech = "{'programming':3}" - -/obj/item/stock_parts/circuitboard/aiupload - name = T_BOARD("AI upload console") - build_path = /obj/machinery/computer/upload/ai - origin_tech = "{'programming':4}" - -/obj/item/stock_parts/circuitboard/borgupload - name = T_BOARD("cyborg upload console") - build_path = /obj/machinery/computer/upload/robot - origin_tech = "{'programming':4}" - -/obj/item/stock_parts/circuitboard/teleporter - name = T_BOARD("teleporter control console") - build_path = /obj/machinery/computer/teleporter - origin_tech = "{'programming':2,'wormholes':4}" - -/obj/item/stock_parts/circuitboard/atmos_alert - name = T_BOARD("atmospheric alert console") - build_path = /obj/machinery/computer/atmos_alert - -/obj/item/stock_parts/circuitboard/robotics - name = T_BOARD("robotics control console") - build_path = /obj/machinery/computer/robotics - origin_tech = "{'programming':3}" - -/obj/item/stock_parts/circuitboard/drone_control - name = T_BOARD("drone control console") - build_path = /obj/machinery/computer/drone_control - origin_tech = "{'programming':3}" - -/obj/item/stock_parts/circuitboard/arcade/battle - name = T_BOARD("battle arcade machine") - build_path = /obj/machinery/computer/arcade/battle - origin_tech = "{'programming':1}" - -/obj/item/stock_parts/circuitboard/arcade/orion_trail - name = T_BOARD("orion trail arcade machine") - build_path = /obj/machinery/computer/arcade/orion_trail - origin_tech = "{'programming':1}" - -/obj/item/stock_parts/circuitboard/turbine_control - name = T_BOARD("turbine control console") - build_path = /obj/machinery/computer/turbine_computer - -/obj/item/stock_parts/circuitboard/solar_control - name = T_BOARD("solar control console") - build_path = /obj/machinery/power/solar_control - origin_tech = "{'programming':2,'powerstorage':2}" - -/obj/item/stock_parts/circuitboard/powermonitor - name = T_BOARD("power monitoring console") - build_path = /obj/machinery/computer/power_monitor - -/obj/item/stock_parts/circuitboard/prisoner - name = T_BOARD("prisoner management console") - build_path = /obj/machinery/computer/prisoner - -/obj/item/stock_parts/circuitboard/operating - name = T_BOARD("patient monitoring console") - build_path = /obj/machinery/computer/operating - origin_tech = "{'programming':2,'biotech':2}" - -/obj/item/stock_parts/circuitboard/helm - name = T_BOARD("helm control console") - build_path = /obj/machinery/computer/ship/helm - -/obj/item/stock_parts/circuitboard/engine - name = T_BOARD("engine control console") - build_path = /obj/machinery/computer/ship/engines - -/obj/item/stock_parts/circuitboard/nav - name = T_BOARD("navigation console") - build_path = /obj/machinery/computer/ship/navigation - -/obj/item/stock_parts/circuitboard/nav/tele - name = T_BOARD("navigation telescreen") - build_path = /obj/machinery/computer/ship/navigation/telescreen - -/obj/item/stock_parts/circuitboard/sensors - name = T_BOARD("sensors console") - build_path = /obj/machinery/computer/ship/sensors - -/obj/item/stock_parts/circuitboard/design_console - name = T_BOARD("design database console") - build_path = /obj/machinery/computer/design_console - -/obj/item/stock_parts/circuitboard/area_atmos - name = T_BOARD("area air control console") - build_path = /obj/machinery/computer/area_atmos - origin_tech = "{'programming':2}" - -/obj/item/stock_parts/circuitboard/account_database - name = T_BOARD("accounts uplink terminal") - build_path = /obj/machinery/computer/account_database - -/obj/item/stock_parts/circuitboard/guestpass - name = T_BOARD("guest pass terminal") - build_path = /obj/machinery/computer/guestpass \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm deleted file mode 100644 index f126b5a19ef8..000000000000 --- a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm +++ /dev/null @@ -1,27 +0,0 @@ -/obj/item/stock_parts/circuitboard/holodeckcontrol - name = T_BOARD("holodeck control console") - build_path = /obj/machinery/computer/HolodeckControl - origin_tech = "{'programming':2,'wormholes':2}" - var/last_to_emag - var/linkedholodeck_area - var/list/supported_programs - var/list/restricted_programs - -/obj/item/stock_parts/circuitboard/holodeckcontrol/construct(var/obj/machinery/computer/HolodeckControl/HC) - if (..(HC)) - HC.supported_programs = supported_programs.Copy() - HC.restricted_programs = restricted_programs.Copy() - if(linkedholodeck_area) - HC.linkedholodeck = locate(linkedholodeck_area) - if(last_to_emag) - HC.last_to_emag = last_to_emag - HC.emagged = 1 - HC.safety_disabled = 1 - -/obj/item/stock_parts/circuitboard/holodeckcontrol/deconstruct(var/obj/machinery/computer/HolodeckControl/HC) - if (..(HC)) - linkedholodeck_area = HC.linkedholodeck_area - supported_programs = HC.supported_programs.Copy() - restricted_programs = HC.restricted_programs.Copy() - last_to_emag = HC.last_to_emag - HC.emergencyShutdown() diff --git a/code/game/objects/items/weapons/circuitboards/computer/shuttle.dm b/code/game/objects/items/weapons/circuitboards/computer/shuttle.dm deleted file mode 100644 index c3a6c1b63bf7..000000000000 --- a/code/game/objects/items/weapons/circuitboards/computer/shuttle.dm +++ /dev/null @@ -1,25 +0,0 @@ -/obj/item/stock_parts/circuitboard/shuttle_console - name = T_BOARD("basic shuttle console") - build_path = /obj/machinery/computer/shuttle_control - origin_tech = "{'programming':3}" - var/shuttle_tag - -/obj/item/stock_parts/circuitboard/shuttle_console/construct(obj/machinery/computer/shuttle_control/M) - M.shuttle_tag = shuttle_tag - -/obj/item/stock_parts/circuitboard/shuttle_console/deconstruct(obj/machinery/computer/shuttle_control/M) - shuttle_tag = M.shuttle_tag - -/obj/item/stock_parts/circuitboard/shuttle_console/Initialize() - set_extension(src, /datum/extension/interactive/multitool/circuitboards/shuttle_console) - . = ..() - -/obj/item/stock_parts/circuitboard/shuttle_console/proc/is_valid_shuttle(datum/shuttle/shuttle) - return TRUE - -/obj/item/stock_parts/circuitboard/shuttle_console/explore - name = T_BOARD("long range shuttle console") - build_path = /obj/machinery/computer/shuttle_control/explore - -/obj/item/stock_parts/circuitboard/shuttle_console/explore/is_valid_shuttle(datum/shuttle/shuttle) - return istype(shuttle, /datum/shuttle/autodock/overmap) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/computer/telecomms.dm b/code/game/objects/items/weapons/circuitboards/computer/telecomms.dm deleted file mode 100644 index 70e62916b804..000000000000 --- a/code/game/objects/items/weapons/circuitboards/computer/telecomms.dm +++ /dev/null @@ -1,9 +0,0 @@ -/obj/item/stock_parts/circuitboard/comm_monitor - name = T_BOARD("telecommunications monitor console") - build_path = /obj/machinery/computer/telecomms/monitor - origin_tech = "{'programming':3}" - -/obj/item/stock_parts/circuitboard/comm_server - name = T_BOARD("telecommunications server monitor console") - build_path = /obj/machinery/computer/telecomms/server - origin_tech = "{'programming':3}" diff --git a/code/game/objects/items/weapons/circuitboards/machinery/chemistry.dm b/code/game/objects/items/weapons/circuitboards/machinery/chemistry.dm deleted file mode 100644 index 3d18e2d07f94..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/chemistry.dm +++ /dev/null @@ -1,18 +0,0 @@ -/obj/item/stock_parts/circuitboard/reagent_heater - name = T_BOARD("chemical heater") - build_path = /obj/machinery/reagent_temperature - board_type = "machine" - origin_tech = "{'powerstorage':2,'engineering':1}" - req_components = list( - /obj/item/stock_parts/micro_laser = 1, - /obj/item/stock_parts/capacitor = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/reagent_heater/cooler - name = T_BOARD("chemical cooler") - build_path = /obj/machinery/reagent_temperature/cooler diff --git a/code/game/objects/items/weapons/circuitboards/machinery/cloning.dm b/code/game/objects/items/weapons/circuitboards/machinery/cloning.dm deleted file mode 100644 index 0bf761e7db1f..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/cloning.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/item/stock_parts/circuitboard/bioprinter - name = T_BOARD("bioprinter") - build_path = /obj/machinery/organ_printer/flesh - board_type = "machine" - origin_tech = "{'engineering':1,'biotech':3,'programming':3}" - req_components = list( - /obj/item/scanner/health = 1, - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 2 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/roboprinter - name = T_BOARD("prosthetic organ fabricator") - build_path = /obj/machinery/organ_printer/robot - board_type = "machine" - origin_tech = "{'engineering':3,'programming':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 2 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/household.dm b/code/game/objects/items/weapons/circuitboards/machinery/household.dm deleted file mode 100644 index 89e293b5514e..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/household.dm +++ /dev/null @@ -1,188 +0,0 @@ -/obj/item/stock_parts/circuitboard/microwave - name = T_BOARD("microwave") - build_path = /obj/machinery/microwave - board_type = "machine" - origin_tech = "{'biotech':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 2, - /obj/item/stock_parts/matter_bin = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/gibber - name = T_BOARD("meat gibber") - build_path = /obj/machinery/gibber - board_type = "machine" - origin_tech = "{'biotech':2,'materials':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/knife/kitchen/cleaver = 1) - additional_spawn_components = list( - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/cooker - name = T_BOARD("candy machine") - build_path = /obj/machinery/cooker/candy - board_type = "machine" - origin_tech = "{'biotech':1,'materials':1}" - buildtype_select = TRUE - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stack/cable_coil = 10) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/cooker/get_buildable_types() - return subtypesof(/obj/machinery/cooker) - -/obj/item/stock_parts/circuitboard/honey - name = T_BOARD("honey extractor") - build_path = /obj/machinery/honey_extractor - board_type = "machine" - origin_tech = "{'biotech':2,'engineering':1}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/matter_bin = 2) - -/obj/item/stock_parts/circuitboard/honey/seed - name = T_BOARD("seed extractor") - build_path = /obj/machinery/seed_extractor - board_type = "machine" - -/obj/item/stock_parts/circuitboard/seed_storage - name = T_BOARD("seed storage") - build_path = /obj/machinery/seed_storage - board_type = "machine" - origin_tech = "{'biotech':2,'engineering':3}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/matter_bin = 2) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/seed_storage/advanced - name = T_BOARD("seed storage (scientific)") - build_path = /obj/machinery/seed_storage/xenobotany/buildable - origin_tech = "{'biotech':6,'engineering':3}" - -/obj/item/stock_parts/circuitboard/washer - name = T_BOARD("washing machine") - build_path = /obj/machinery/washing_machine - board_type = "machine" - origin_tech = "{'engineering':1}" - req_components = list( - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/pipe = 1) - -/obj/item/stock_parts/circuitboard/vending - name = T_BOARD("vending machine") - build_path = /obj/machinery/vending/assist - board_type = "machine" - origin_tech = "{'engineering':2}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/manipulator = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - buildtype_select = TRUE - -/obj/item/stock_parts/circuitboard/vending/get_buildable_types() - . = list() - for(var/path in typesof(/obj/machinery/vending)) - var/obj/machinery/vending/vendor = path - var/base_type = initial(vendor.base_type) || path - . |= base_type - -/obj/item/stock_parts/circuitboard/grinder - name = T_BOARD("industrial grinder") - build_path = /obj/machinery/reagentgrinder - board_type = "machine" - origin_tech = "{'magnets':2,'materials':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/matter_bin = 2) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/juicer - name = T_BOARD("blender") - build_path = /obj/machinery/reagentgrinder/juicer - board_type = "machine" - origin_tech = "{'magnets':2,'materials':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/matter_bin = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/ice_cream - name = T_BOARD("ice cream vat") - build_path = /obj/machinery/icecream_vat - board_type = "machine" - origin_tech = "{'engineering':1}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/pipe = 1 - ) - -/obj/item/stock_parts/circuitboard/fridge - name = T_BOARD("smartfridge") - build_path = /obj/machinery/smartfridge - board_type = "machine" - origin_tech = "{'engineering':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 3 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - buildtype_select = TRUE - -/obj/item/stock_parts/circuitboard/fridge/get_buildable_types() - return typesof(/obj/machinery/smartfridge) - -/obj/item/stock_parts/circuitboard/jukebox - name = T_BOARD("jukebox") - build_path = /obj/machinery/media/jukebox - board_type = "machine" - origin_tech = "{'programming':5}" - req_components = list( - /obj/item/stock_parts/subspace/amplifier = 2 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - buildtype_select = TRUE - -/obj/item/stock_parts/circuitboard/jukebox/get_buildable_types() - return typesof(/obj/machinery/media/jukebox) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/inertial_damper.dm b/code/game/objects/items/weapons/circuitboards/machinery/inertial_damper.dm deleted file mode 100644 index d7a6efa28567..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/inertial_damper.dm +++ /dev/null @@ -1,13 +0,0 @@ -/obj/item/stock_parts/circuitboard/inertial_damper - name = T_BOARD("inertial damper") - board_type = "machine" - build_path = /obj/machinery/inertial_damper - origin_tech = "{'engineering':5,'magnets':3}" - req_components = list( - /obj/item/stock_parts/capacitor = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mech_recharger.dm b/code/game/objects/items/weapons/circuitboards/machinery/mech_recharger.dm deleted file mode 100644 index d7018ca4a07e..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/mech_recharger.dm +++ /dev/null @@ -1,9 +0,0 @@ -/obj/item/stock_parts/circuitboard/mech_recharger - name = T_BOARD("mech recharger") - build_path = /obj/machinery/mech_recharger - board_type = "machine" - origin_tech = "{'programming':2,'powerstorage':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/capacitor = 2, - /obj/item/stock_parts/scanning_module = 1, - /obj/item/stock_parts/manipulator = 2) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/medical.dm b/code/game/objects/items/weapons/circuitboards/machinery/medical.dm deleted file mode 100644 index e7a982aec993..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/medical.dm +++ /dev/null @@ -1,57 +0,0 @@ -/obj/item/stock_parts/circuitboard/optable - name = T_BOARD("operating table") - build_path = /obj/machinery/optable - board_type = "machine" - origin_tech = "{'engineering':1,'biotech':3,'programming':3}" - req_components = list( - /obj/item/stock_parts/scanning_module = 1, - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/capacitor = 1) - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/bodyscanner - name = T_BOARD("body scanner") - build_path = /obj/machinery/bodyscanner - board_type = "machine" - origin_tech = "{'engineering':2,'biotech':4,'programming':4}" - req_components = list( - /obj/item/stock_parts/scanning_module = 2, - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/console_screen = 1) - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/body_scanconsole - name = T_BOARD("body scanner console") - build_path = /obj/machinery/body_scanconsole - board_type = "machine" - origin_tech = "{'engineering':2,'biotech':4,'programming':4}" - req_components = list( - /obj/item/stock_parts/console_screen = 1) - additional_spawn_components = list( - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/body_scanconsole/display - name = T_BOARD("body scanner display") - build_path = /obj/machinery/body_scan_display - origin_tech = "{'biotech':2,'programming':2}" - -/obj/item/stock_parts/circuitboard/sleeper - name = T_BOARD("sleeper") - build_path = /obj/machinery/sleeper - board_type = "machine" - origin_tech = "{'engineering':3,'biotech':5,'programming':3}" - req_components = list ( - /obj/item/stock_parts/scanning_module = 1, - /obj/item/stock_parts/manipulator = 2, - /obj/item/chems/syringe = 2) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mining.dm b/code/game/objects/items/weapons/circuitboards/machinery/mining.dm deleted file mode 100644 index 345aa5f0952d..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/mining.dm +++ /dev/null @@ -1,48 +0,0 @@ -/obj/item/stock_parts/circuitboard/mineral_processing - name = T_BOARD("mineral processing console") - build_path = /obj/machinery/computer/mining - origin_tech = "{'programming':2,'engineering':2}" - -/obj/item/stock_parts/circuitboard/mining_processor - name = T_BOARD("ore processor") - build_path = /obj/machinery/mineral/processing_unit - board_type = "machine" - origin_tech = "{'programming':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 2 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/mining_unloader - name = T_BOARD("unloading machine") - build_path = /obj/machinery/mineral/unloading_machine - board_type = "machine" - origin_tech = "{'programming':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 2 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/mining_stacker - name = T_BOARD("stacking machine") - build_path = /obj/machinery/mineral/stacking_machine - board_type = "machine" - origin_tech = "{'programming':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/manipulator = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm b/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm deleted file mode 100644 index 5490e82845db..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/mining_drill.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/stock_parts/circuitboard/miningdrill - name = T_BOARD("mining drill head") - build_path = /obj/machinery/mining/drill - board_type = "machine" - origin_tech = "{'programming':1,'engineering':1}" - req_components = list( - /obj/item/stock_parts/capacitor = 1, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/power/battery/buildable/stock, - /obj/item/cell = 1 - ) - -/obj/item/stock_parts/circuitboard/miningdrillbrace - name = T_BOARD("mining drill brace") - build_path = /obj/machinery/mining/brace - board_type = "machine" - origin_tech = "{'programming':1,'engineering':1}" - req_components = list() - additional_spawn_components = null \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/network.dm b/code/game/objects/items/weapons/circuitboards/machinery/network.dm deleted file mode 100644 index 7c17c91f12fc..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/network.dm +++ /dev/null @@ -1,57 +0,0 @@ -/obj/item/stock_parts/circuitboard/mainframe - name = T_BOARD("mainframe") - build_path = /obj/machinery/network/mainframe - board_type = "machine" - origin_tech = "{'programming':2}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1, - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/computer/hard_drive/cluster/fullhouse - ) - -/obj/item/stock_parts/circuitboard/acl - name = T_BOARD("access controller") - build_path = /obj/machinery/network/acl - board_type = "machine" - origin_tech = "{'programming':2}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1, - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/computer/card_slot = 1 - ) - -/obj/item/stock_parts/circuitboard/router - name = T_BOARD("router") - build_path = /obj/machinery/network/router - board_type = "machine" - origin_tech = "{'wormholes':2,'programming':2}" - req_components = list( - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/subspace/crystal = 1, - /obj/item/stock_parts/computer/network_card = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1, - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1 - ) - -/obj/item/stock_parts/circuitboard/relay - name = T_BOARD("relay") - build_path = /obj/machinery/network/relay - board_type = "machine" - origin_tech = "{'wormholes':2,'programming':2}" - req_components = list( - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/subspace/crystal = 1, - /obj/item/stock_parts/computer/network_card = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1, - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1 - ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/pacman.dm b/code/game/objects/items/weapons/circuitboards/machinery/pacman.dm deleted file mode 100644 index 87303645a14f..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/pacman.dm +++ /dev/null @@ -1,29 +0,0 @@ -/obj/item/stock_parts/circuitboard/pacman - name = T_BOARD("PACMAN-type generator") - build_path = /obj/machinery/power/port_gen/pacman - board_type = "machine" - origin_tech = "{'programming':3,'powerstorage':3,'exoticmatter':3,'engineering':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/micro_laser = 1, - /obj/item/stack/cable_coil = 15, - /obj/item/stock_parts/capacitor = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) -/obj/item/stock_parts/circuitboard/pacman/super - name = T_BOARD("SUPERPACMAN-type generator") - build_path = /obj/machinery/power/port_gen/pacman/super - origin_tech = "{'programming':3,'powerstorage':4,'engineering':4}" - -/obj/item/stock_parts/circuitboard/pacman/super/potato - name = T_BOARD("PTTO-3 nuclear generator") - build_path = /obj/machinery/power/port_gen/pacman/super/potato - origin_tech = "{'programming':3,'powerstorage':5,'engineering':4}" - -/obj/item/stock_parts/circuitboard/pacman/mrs - name = T_BOARD("MRSPACMAN-type generator") - build_path = /obj/machinery/power/port_gen/pacman/mrs - origin_tech = "{'programming':3,'powerstorage':5,'engineering':5}" diff --git a/code/game/objects/items/weapons/circuitboards/machinery/power.dm b/code/game/objects/items/weapons/circuitboards/machinery/power.dm deleted file mode 100644 index b710715da014..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/power.dm +++ /dev/null @@ -1,137 +0,0 @@ -/obj/item/stock_parts/circuitboard/smes - name = T_BOARD("superconductive magnetic energy storage") - build_path = /obj/machinery/power/smes/buildable - board_type = "machine" - origin_tech = "{'powerstorage':6,'engineering':4}" - req_components = list(/obj/item/stock_parts/smes_coil = 1, /obj/item/stack/cable_coil = 30) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/shielding/electric = 1 - ) - -/obj/item/stock_parts/circuitboard/batteryrack - name = T_BOARD("battery rack PSU") - build_path = /obj/machinery/power/smes/batteryrack - board_type = "machine" - origin_tech = "{'powerstorage':3,'engineering':2}" - req_components = list(/obj/item/stock_parts/capacitor/ = 3, /obj/item/stock_parts/matter_bin/ = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/recharger - name = T_BOARD("recharger") - build_path = /obj/machinery/recharger - board_type = "machine" - origin_tech = "{'powerstorage':2,'engineering':2}" - req_components = list( - /obj/item/stock_parts/capacitor = 1 - ) - -/obj/item/stock_parts/circuitboard/recharger/wall - name = T_BOARD("wall recharger") - build_path = /obj/machinery/recharger/wallcharger - board_type = "wall" - -/obj/item/stock_parts/circuitboard/cell_charger - name = T_BOARD("cell charger") - build_path = /obj/machinery/cell_charger - board_type = "machine" - origin_tech = "{'powerstorage':2,'engineering':2}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/power/battery/buildable/turbo = 1, - /obj/item/stock_parts/power/apc/buildable = 1, - /obj/item/stock_parts/capacitor = 6 - ) // The apc part is to supply upkeep power, so it charges the battery instead of draining it. Capacitors make things go faster. - -/obj/item/stock_parts/circuitboard/turbine - name = T_BOARD("small turbine") - build_path = /obj/machinery/atmospherics/pipeturbine - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/matter_bin = 2 - ) - additional_spawn_components = list() - -/obj/item/stock_parts/circuitboard/turbine/motor - name = T_BOARD("small turbine motor") - build_path = /obj/machinery/power/turbinemotor - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/capacitor = 4 - ) - -/obj/item/stock_parts/circuitboard/big_turbine - name = T_BOARD("large turbine compressor") - build_path = /obj/machinery/compressor - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 3, - /obj/item/stock_parts/matter_bin = 3 - ) - additional_spawn_components = list() - -/obj/item/stock_parts/circuitboard/big_turbine/center - name = T_BOARD("large turbine motor") - build_path = /obj/machinery/power/turbine - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/capacitor = 4 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/teg_turbine - name = T_BOARD("thermoelectric generator turbine") - build_path = /obj/machinery/atmospherics/binary/circulator - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 3, - /obj/item/stock_parts/matter_bin = 3 - ) - additional_spawn_components = list() - -/obj/item/stock_parts/circuitboard/teg_turbine/motor - name = T_BOARD("thermoelectric generator motor") - build_path = /obj/machinery/power/generator - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/capacitor = 4 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/breaker - name = T_BOARD("breaker box") - build_path = /obj/machinery/power/breakerbox - board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/capacitor = 2 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/research.dm b/code/game/objects/items/weapons/circuitboards/machinery/research.dm deleted file mode 100644 index c5c2a6edd845..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/research.dm +++ /dev/null @@ -1,227 +0,0 @@ -/obj/item/stock_parts/circuitboard/destructive_analyzer - name = T_BOARD("destructive analyzer") - build_path = /obj/machinery/destructive_analyzer - board_type = "machine" - origin_tech = "{'magnets':2,'engineering':2,'programming':2}" - req_components = list( - /obj/item/stock_parts/scanning_module = 1, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/autolathe - name = T_BOARD("autolathe") - build_path = /obj/machinery/fabricator - board_type = "machine" - origin_tech = "{'engineering':2,'programming':2}" - req_components = list( - /obj/item/stock_parts/matter_bin = 3, - /obj/item/stock_parts/manipulator = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/autolathe/micro - name = T_BOARD("microlathe") - build_path = /obj/machinery/fabricator/micro - origin_tech = "{'engineering':1,'programming':1}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/manipulator = 1 - ) -/obj/item/stock_parts/circuitboard/autolathe/book - name = T_BOARD("autobinder") - build_path = /obj/machinery/fabricator/book - origin_tech = "{'engineering':1,'programming':1}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/manipulator = 1 - ) -/obj/item/stock_parts/circuitboard/replicator - name = T_BOARD("replicator") - build_path = /obj/machinery/fabricator/replicator - board_type = "machine" - origin_tech = "{'engineering':3,'programming':2,'biotech':2}" - req_components = list( - /obj/item/stock_parts/matter_bin = 3, - /obj/item/stock_parts/manipulator = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/protolathe - name = T_BOARD("protolathe") - build_path = /obj/machinery/fabricator/protolathe - board_type = "machine" - origin_tech = "{'engineering':2,'programming':2}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 2, - /obj/item/chems/glass/beaker = 2) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/circuit_imprinter - name = T_BOARD("circuit imprinter") - build_path = /obj/machinery/fabricator/imprinter - board_type = "machine" - origin_tech = "{'engineering':2,'programming':2}" - req_components = list( - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/manipulator = 1, - /obj/item/chems/glass/beaker = 2) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/mechfab - name = T_BOARD("industrial fabricator") - build_path = /obj/machinery/fabricator/industrial - board_type = "machine" - origin_tech = "{'programming':3,'engineering':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/roboticsfab - name = T_BOARD("robotics fabricator") - build_path = /obj/machinery/fabricator/robotics - board_type = "machine" - origin_tech = "{'programming':3,'engineering':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/textilesfab - name = T_BOARD("textiles fabricator") - build_path = /obj/machinery/fabricator/textile - board_type = "machine" - origin_tech = "{'programming':3,'engineering':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/suspension_gen - name = T_BOARD("suspension generator") - build_path = /obj/machinery/suspension_gen - board_type = "machine" - origin_tech = "{'programming':4,'engineering':3,'magnets':4}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/battery/buildable/stock = 1, - /obj/item/cell/high = 1, - /obj/item/stock_parts/access_lock/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/artifact_harvester - name = T_BOARD("artifact harvester") - build_path = /obj/machinery/artifact_harvester - board_type = "machine" - origin_tech = "{'programming':4,'engineering':3}" - req_components = list( - /obj/item/stock_parts/matter_bin = 2, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/artifact_analyser - name = T_BOARD("artifact analyser") - build_path = /obj/machinery/artifact_analyser - board_type = "machine" - origin_tech = "{'programming':4,'engineering':3}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/micro_laser = 2) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/artifact_scanner - name = T_BOARD("artifact scanpad") - build_path = /obj/machinery/artifact_scanpad - board_type = "machine" - origin_tech = "{'programming':2,'engineering':2,'magnets':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/micro_laser = 1) - additional_spawn_components = list( - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/cryopod - name = T_BOARD("cryo pod") - build_path = /obj/machinery/cryopod - board_type = "machine" - origin_tech = "{'programming':6,'engineering':6,'wormholes':6}" - req_components = list( - /obj/item/stock_parts/matter_bin = 4, - /obj/item/stock_parts/manipulator = 1, - /obj/item/stock_parts/subspace/crystal = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - buildtype_select = TRUE - -/obj/item/stock_parts/circuitboard/cryopod/get_buildable_types() - return typesof(/obj/machinery/cryopod) - -/obj/item/stock_parts/circuitboard/merchant_pad - name = T_BOARD("merchant pad") - build_path = /obj/machinery/merchant_pad - board_type = "machine" - origin_tech = "{'programming':6,'wormholes':6,'esoteric':1}" - req_components = list(/obj/item/stack/cable_coil = 15) - req_components = list( - /obj/item/stock_parts/subspace/amplifier = 1, - /obj/item/stock_parts/subspace/ansible = 1, - /obj/item/stock_parts/subspace/crystal = 1, - /obj/item/stock_parts/subspace/transmitter = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1, - ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/shipsensors.dm b/code/game/objects/items/weapons/circuitboards/machinery/shipsensors.dm deleted file mode 100644 index 34cc0addb40f..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/shipsensors.dm +++ /dev/null @@ -1,14 +0,0 @@ -/obj/item/stock_parts/circuitboard/shipsensors - name = T_BOARD("ship sensors") - build_path = /obj/machinery/shipsensors - board_type = "machine" - origin_tech = "{'wormholes':2,'programming':2}" - req_components = list( - /obj/item/stack/cable_coil = 30, - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/subspace/ansible = 1, - /obj/item/stock_parts/subspace/transmitter = 1 - ) - additional_spawn_components = list( - /obj/item/stock_parts/shielding/heat = 1 - ) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm b/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm deleted file mode 100644 index 1a03035946f4..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm +++ /dev/null @@ -1,84 +0,0 @@ -/obj/item/stock_parts/circuitboard/telecomms - board_type = "machine" - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/telecomms/receiver - name = T_BOARD("subspace receiver") - build_path = /obj/machinery/telecomms/receiver - origin_tech = "{'programming':4,'engineering':3,'wormholes':2}" - req_components = list( - /obj/item/stock_parts/subspace/ansible = 1, - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/micro_laser = 1) - -/obj/item/stock_parts/circuitboard/telecomms/hub - name = T_BOARD("hub mainframe") - build_path = /obj/machinery/telecomms/hub - origin_tech = "{'programming':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/subspace/filter = 2) - -/obj/item/stock_parts/circuitboard/telecomms/bus - name = T_BOARD("bus mainframe") - build_path = /obj/machinery/telecomms/bus - origin_tech = "{'programming':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/subspace/filter = 1) - -/obj/item/stock_parts/circuitboard/telecomms/processor - name = T_BOARD("processor unit") - build_path = /obj/machinery/telecomms/processor - origin_tech = "{'programming':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 3, - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/subspace/treatment = 2, - /obj/item/stock_parts/subspace/analyzer = 1, - /obj/item/stock_parts/subspace/amplifier = 1) - -/obj/item/stock_parts/circuitboard/telecomms/server - name = T_BOARD("telecommunication server") - build_path = /obj/machinery/telecomms/server - origin_tech = "{'programming':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/subspace/filter = 1) - -/obj/item/stock_parts/circuitboard/telecomms/broadcaster - name = T_BOARD("subspace broadcaster") - build_path = /obj/machinery/telecomms/broadcaster - origin_tech = "{'programming':4,'engineering':4,'wormholes':2}" - req_components = list( - /obj/item/stock_parts/manipulator = 2, - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/subspace/crystal = 1, - /obj/item/stock_parts/micro_laser/high = 2) - -/obj/item/stock_parts/circuitboard/telecomms/allinone - name = T_BOARD("telecommunication mainframe") - build_path = /obj/machinery/telecomms/allinone - origin_tech = "{'programming':3,'engineering':3}" - req_components = list( - /obj/item/stock_parts/subspace/ansible = 1, - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/subspace/treatment = 2, - /obj/item/stock_parts/subspace/analyzer = 1, - /obj/item/stock_parts/subspace/amplifier = 1, - /obj/item/stock_parts/subspace/crystal = 1) - -/obj/item/stock_parts/circuitboard/telecomms/message_server - name = T_BOARD("message server") - build_path = /obj/machinery/message_server - origin_tech = "{'programming':4,'engineering':4}" - req_components = list( - /obj/item/stock_parts/subspace/ansible = 1, - /obj/item/stock_parts/subspace/filter = 1, - /obj/item/stock_parts/subspace/treatment = 2, - /obj/item/stock_parts/subspace/analyzer = 1) \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/unary_atmos.dm b/code/game/objects/items/weapons/circuitboards/machinery/unary_atmos.dm deleted file mode 100644 index fe4faadd526f..000000000000 --- a/code/game/objects/items/weapons/circuitboards/machinery/unary_atmos.dm +++ /dev/null @@ -1,34 +0,0 @@ -/obj/item/stock_parts/circuitboard/unary_atmos - board_type = "machine" - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/unary_atmos/construct(var/obj/machinery/atmospherics/unary/U) - //TODO: Move this stuff into the relevant constructor when pipe/construction.dm is cleaned up. - U.atmos_init() - U.build_network() - if (U.node) - U.node.atmos_init() - U.node.build_network() - -/obj/item/stock_parts/circuitboard/unary_atmos/heater - name = T_BOARD("gas heating system") - build_path = /obj/machinery/atmospherics/unary/heater - origin_tech = "{'powerstorage':2,'engineering':1}" - req_components = list( - /obj/item/stack/cable_coil = 5, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/capacitor = 2) - -/obj/item/stock_parts/circuitboard/unary_atmos/cooler - name = T_BOARD("gas cooling system") - build_path = /obj/machinery/atmospherics/unary/freezer - origin_tech = "{'magnets':2,'engineering':2}" - req_components = list( - /obj/item/stack/cable_coil = 2, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/capacitor = 2, - /obj/item/stock_parts/manipulator = 1) diff --git a/code/game/objects/items/weapons/circuitboards/other.dm b/code/game/objects/items/weapons/circuitboards/other.dm deleted file mode 100644 index 4b63154e9877..000000000000 --- a/code/game/objects/items/weapons/circuitboards/other.dm +++ /dev/null @@ -1,6 +0,0 @@ -//Stuff that doesn't fit into any category goes here - -/obj/item/stock_parts/circuitboard/aicore - name = T_BOARD("AI core") - origin_tech = "{'programming':4,'biotech':2}" - board_type = "other" diff --git a/code/game/objects/items/weapons/circuitboards/wall.dm b/code/game/objects/items/weapons/circuitboards/wall.dm deleted file mode 100644 index 032543558778..000000000000 --- a/code/game/objects/items/weapons/circuitboards/wall.dm +++ /dev/null @@ -1,93 +0,0 @@ -// For wall machines, using the wall frame construction method. - -/obj/item/stock_parts/circuitboard/fire_alarm - name = T_BOARD("fire alarm") - icon = 'icons/obj/doors/door_assembly.dmi' - icon_state = "door_electronics" - desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees celsius!\"." - build_path = /obj/machinery/firealarm - board_type = "wall" - origin_tech = "{'programming':1,'engineering':1}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/air_alarm - name = T_BOARD("air alarm") - icon = 'icons/obj/doors/door_assembly.dmi' - icon_state = "door_electronics" - build_path = /obj/machinery/alarm - board_type = "wall" - origin_tech = "{'programming':1,'engineering':1}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/apc - name = T_BOARD("area power controller") - desc = "Heavy-duty switching circuits for power control." - icon = 'icons/obj/module.dmi' - icon_state = "power_mod" - item_state = "electronic" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - w_class = ITEM_SIZE_SMALL - obj_flags = OBJ_FLAG_CONDUCTIBLE - build_path = /obj/machinery/power/apc/buildable - board_type = "wall" - origin_tech = "{'programming':1,'engineering':1}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/battery/buildable = 1, - /obj/item/stock_parts/power/terminal/buildable = 1, - /obj/item/stock_parts/access_lock/buildable = 1 - ) - -/obj/item/stock_parts/circuitboard/requests_console - name = T_BOARD("requests console") - build_path = /obj/machinery/requests_console - board_type = "wall" - origin_tech = "{'programming':1,'engineering':1}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1, - ) - -/obj/item/stock_parts/circuitboard/requests_console/atm - name = T_BOARD("atm") - build_path = /obj/machinery/atm - -/obj/item/stock_parts/circuitboard/requests_console/newscaster - name = T_BOARD("newscaster") - build_path = /obj/machinery/newscaster - -/obj/item/stock_parts/circuitboard/airlock_controller - name = T_BOARD("airlock controller") - build_path = /obj/machinery/embedded_controller/radio/simple_docking_controller - board_type = "wall" - origin_tech = "{'programming':3,'engineering':3}" - req_components = list() - additional_spawn_components = list( - /obj/item/stock_parts/console_screen = 1, - /obj/item/stock_parts/keyboard = 1, - /obj/item/stock_parts/power/apc/buildable = 1, - ) - buildtype_select = TRUE - -/obj/item/stock_parts/circuitboard/airlock_controller/get_buildable_types() - . = list() - for(var/path in typesof(/obj/machinery/embedded_controller/radio)) - var/obj/machinery/embedded_controller/radio/controller = path - var/base_type = initial(controller.base_type) || path - . |= base_type - \ No newline at end of file diff --git a/code/game/objects/items/weapons/clothingbag.dm b/code/game/objects/items/weapons/clothingbag.dm index 4c781dc720cd..74216775a58e 100644 --- a/code/game/objects/items/weapons/clothingbag.dm +++ b/code/game/objects/items/weapons/clothingbag.dm @@ -3,13 +3,14 @@ desc = "A cheap plastic bag that contains a fresh set of clothes." icon = 'icons/obj/items/storage/trashbag.dmi' icon_state = "trashbag3" + material = /decl/material/solid/organic/plastic var/icon_used = "trashbag0" var/opened = 0 /obj/item/clothingbag/attack_self(mob/user) if(!opened) - user.visible_message("\The [user] tears open \the [src.name]!", "You tear open \the [src.name]!") + user.visible_message("\The [user] tears open \the [src]!", "You tear open \the [src]!") opened = 1 icon_state = icon_used for(var/obj/item in contents) diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm index 1bd636a2d7f1..18245dfe7fbd 100644 --- a/code/game/objects/items/weapons/clown_items.dm +++ b/code/game/objects/items/weapons/clown_items.dm @@ -8,9 +8,11 @@ * Banana Peals */ /obj/item/bananapeel/Crossed(var/atom/movable/AM) - if (istype(AM, /mob/living)) - var/mob/living/M = AM - M.slip("the [src.name]",4) + if(!isliving(AM)) + return + var/mob/living/M = AM + M.slip("\the [src]", 4) + /* * Bike Horns */ @@ -18,13 +20,16 @@ name = "bike horn" desc = "A horn off of a bicycle." icon = 'icons/obj/items/horn.dmi' - icon_state = "bike_horn" - item_state = "bike_horn" - throwforce = 3 + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL throw_speed = 3 throw_range = 15 - attack_verb = list("HONKED") + attack_verb = "HONKED" + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + obj_flags = OBJ_FLAG_HOLLOW var/spam_flag = 0 var/audio_files = list("sound/items/bikehorn.ogg") @@ -40,6 +45,7 @@ /obj/item/bikehorn/airhorn name = "air horn" desc = "A can of compressed air hooked up to an obnoxiously loud horn. SPRING BREAK!" - icon_state = "air_horn" - item_state = "air_horn" - audio_files = list("sound/items/air_horn_1.ogg", "sound/items/air_horn_2.ogg") \ No newline at end of file + icon = 'icons/obj/items/air_horn.dmi' + audio_files = list("sound/items/air_horn_1.ogg", "sound/items/air_horn_2.ogg") + material = /decl/material/solid/metal/aluminium + obj_flags = OBJ_FLAG_HOLLOW \ No newline at end of file diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm index 922f31dd527b..b4b580c4a9bf 100644 --- a/code/game/objects/items/weapons/cosmetics.dm +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -1,112 +1,219 @@ -/obj/item/lipstick //this is the base type and its red +/obj/item/cosmetics gender = PLURAL - name = "ruby lipstick" - desc = "An unbranded tube of lipstick." - icon = 'icons/obj/items/lipstick.dmi' - icon_state = "lipstick_0" + name = "abstract makeup" + desc = "An unbranded tube of makeup." + obj_flags = OBJ_FLAG_HOLLOW w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - color = "#e00606" - var/color_desc = "ruby" + color = COLOR_SILVER + material = /decl/material/solid/organic/plastic + abstract_type = /obj/item/cosmetics + + var/base_icon_state + var/apply_marking_to_limb = BP_HEAD + var/apply_to_zone = BP_MOUTH + var/cosmetic_type + var/makeup_color + var/color_desc var/open = FALSE -/obj/item/lipstick/Initialize() +/obj/item/cosmetics/Initialize() . = ..() + if(!cosmetic_type) + PRINT_STACK_TRACE("Cosmetic item initialized with no cosmetic_type set!") + return INITIALIZE_HINT_QDEL if(color_desc) + name = "[color_desc] [name]" desc += " This one is in [color_desc]." update_icon() //'lipstick' and 'key' are both coloured by var color -/obj/item/lipstick/on_update_icon() +/obj/item/cosmetics/on_update_icon() + . = ..() if(open) - icon_state = "the_stick" + icon_state = "[base_icon_state]_open" + add_overlay(overlay_image(icon, "[base_icon_state]_extended", makeup_color, RESET_COLOR)) else - icon_state = "" - var/new_overlays - LAZYADD(new_overlays, overlay_image(icon, "lipstick_[open]", flags=RESET_COLOR)) - LAZYADD(new_overlays, overlay_image(icon, "key")) - if(blood_overlay) - LAZYADD(new_overlays, blood_overlay) - overlays = new_overlays - -/obj/item/lipstick/attack_self(mob/user) + icon_state = "[base_icon_state]_closed" + add_overlay(overlay_image(icon, "[base_icon_state]_key", makeup_color, RESET_COLOR)) + +/obj/item/cosmetics/attack_self(mob/user) open = !open + show_open_message(user) + update_icon() + +/obj/item/cosmetics/proc/show_open_message(mob/user) + return + +/obj/item/cosmetics/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(!open || !ishuman(target)) + return ..() + + if(istype(target, /obj/item/organ/external/head)) + var/obj/item/organ/external/head/head = target + head.write_on(user, src) + return TRUE + + var/obj/item/organ/external/limb = user.get_organ(apply_marking_to_limb, /obj/item/organ/external/head) + if(!limb) + return ..() + var/target_zone = user.get_target_zone() + if(user.check_intent(I_FLAG_HELP) && target_zone != apply_to_zone && istype(limb, /obj/item/organ/external/head)) + var/obj/item/organ/external/head/head = limb + head.write_on(user, name) + return TRUE + + if(!istype(target) || target_zone != apply_to_zone) + return ..() + + var/decl/sprite_accessory/cosmetics/lip_decl = GET_DECL(cosmetic_type) + if(!lip_decl?.accessory_is_available(user, limb.species, limb.bodytype, user.get_traits())) + to_chat(user, SPAN_WARNING("You can't wear this makeup!")) + return TRUE + + if(user == target) + if(target.get_organ_sprite_accessory_metadata(cosmetic_type, apply_marking_to_limb)) //if they already have lipstick on + to_chat(user, SPAN_WARNING("You need to wipe off your old makeup first!")) + return TRUE + user.visible_message( + SPAN_NOTICE("\The [user] does their makeup with \the [src]."), + SPAN_NOTICE("You take a moment to apply \the [src]. Perfect!") + ) + user.set_organ_sprite_accessory(cosmetic_type, SAC_COSMETICS, list(SAM_COLOR = makeup_color), apply_marking_to_limb) + return TRUE + + if(target.get_organ_sprite_accessory_metadata(cosmetic_type, apply_marking_to_limb)) //if they already have lipstick on + to_chat(user, SPAN_WARNING("You need to wipe off the old makeup first!")) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] begins to do \the [target]'s makeup with \the [src]."), + SPAN_NOTICE("You begin to apply \the [src] to \the [target].") + ) + if(do_after(user, 2 SECONDS, target)) + user.visible_message( + SPAN_NOTICE("\The [user] does \the [target]'s makeup with \the [src]."), + SPAN_NOTICE("You apply \the [src] to \the [target].") + ) + if(target.get_organ_sprite_accessory_metadata(cosmetic_type, apply_marking_to_limb)) + return TRUE + target.set_organ_sprite_accessory(cosmetic_type, SAC_COSMETICS, list(SAM_COLOR = makeup_color), apply_marking_to_limb) + return TRUE + +//types +/obj/item/cosmetics/lipstick + name = "lipstick" + desc = "An unbranded tube of lipstick." + icon = 'icons/obj/items/cosmetics/lipstick.dmi' + icon_state = "lipstick_closed" + cosmetic_type = /decl/sprite_accessory/cosmetics/lipstick + abstract_type = /obj/item/cosmetics/lipstick + base_icon_state = "lipstick" + +/obj/item/cosmetics/lipstick/show_open_message(mob/user) if(open) to_chat(user, SPAN_NOTICE("You remove the cap and twist \the [src] open.")) else to_chat(user, SPAN_NOTICE("You twist \the [src] closed and replace the cap.")) - update_icon() -/obj/item/lipstick/attack(atom/A, mob/user, target_zone) - if(!open) return - - if(ishuman(A)) - var/mob/living/carbon/human/H = A - var/obj/item/organ/external/head/head = H.organs_by_name[BP_HEAD] - - if(!istype(head)) - return - - if(user.a_intent == I_HELP && target_zone == BP_HEAD) - head.write_on(user, src.name) - else if(head.has_lips) - if(H.lip_style) //if they already have lipstick on - to_chat(user, "You need to wipe off the old lipstick first!") - return - if(H == user) - user.visible_message("[user] does their lips with \the [src].", \ - "You take a moment to apply \the [src]. Perfect!") - H.lip_style = color - H.update_body() - else - user.visible_message("[user] begins to do [H]'s lips with \the [src].", \ - "You begin to apply \the [src].") - if(do_after(user, 20, H) && do_after(H, 20, needhand = 0, progress = 0, incapacitation_flags = INCAPACITATION_NONE)) //user needs to keep their active hand, H does not. - user.visible_message("[user] does [H]'s lips with \the [src].", \ - "You apply \the [src].") - H.lip_style = color - H.update_body() - else if(istype(A, /obj/item/organ/external/head)) - var/obj/item/organ/external/head/head = A - head.write_on(user, src) +/obj/item/cosmetics/lipstick/red + makeup_color = "#e00606" + color_desc = "ruby" -//types -/obj/item/lipstick/yellow - name = "topaz lipstick" - color = "#dfdb0a" +/obj/item/cosmetics/lipstick/yellow + makeup_color = "#dfdb0a" color_desc = "topaz" -/obj/item/lipstick/orange - name = "agate lipstick" - color = "#db7d11" +/obj/item/cosmetics/lipstick/orange + makeup_color = "#db7d11" color_desc = "agate" -/obj/item/lipstick/green - name = "emerald lipstick" - color = "#218c17" +/obj/item/cosmetics/lipstick/green + makeup_color = "#218c17" color_desc = "emerald" -/obj/item/lipstick/turquoise - name = "turquoise lipstick" - color = "#0098f0" +/obj/item/cosmetics/lipstick/turquoise + makeup_color = "#0098f0" color_desc = "turquoise" -/obj/item/lipstick/blue - name = "sapphire lipstick" - color = "#0024f0" +/obj/item/cosmetics/lipstick/blue + makeup_color = "#0024f0" color_desc = "sapphire" -/obj/item/lipstick/violet - name = "amethyst lipstick" - color = "#d55cd0" +/obj/item/cosmetics/lipstick/violet + makeup_color = "#d55cd0" color_desc = "amethyst" -/obj/item/lipstick/white - name = "moonstone lipstick" - color = "#d8d5d5" +/obj/item/cosmetics/lipstick/white + makeup_color = "#d8d5d5" color_desc = "moonstone" -/obj/item/lipstick/black - name = "onyx lipstick" - color = "#2b2a2a" - color_desc = "onyx" \ No newline at end of file +/obj/item/cosmetics/lipstick/purple + makeup_color = "#440044" + color_desc = "garnet" + +/obj/item/cosmetics/lipstick/black + makeup_color = "#2b2a2a" + color_desc = "onyx" + +/obj/item/cosmetics/eyeshadow + name = "eyeshadow" + abstract_type = /obj/item/cosmetics/eyeshadow + desc = "An unbranded tube of eyeshadow." + icon = 'icons/obj/items/cosmetics/eyeshadow.dmi' + icon_state = "eyeshadow_closed" + cosmetic_type = /decl/sprite_accessory/cosmetics/eyeshadow + apply_to_zone = BP_EYES + base_icon_state = "eyeshadow" + +/obj/item/cosmetics/eyeshadow/show_open_message(mob/user) + if(open) + to_chat(user, SPAN_NOTICE("You pop \the [src] open and remove the brush.")) + else + to_chat(user, SPAN_NOTICE("You snap \the [src] closed and replace the brush.")) + +/obj/item/cosmetics/eyeshadow/red + makeup_color = "#e00606" + color_desc = "ruby" + +/obj/item/cosmetics/eyeshadow/yellow + makeup_color = "#dfdb0a" + color_desc = "topaz" + +/obj/item/cosmetics/eyeshadow/orange + makeup_color = "#db7d11" + color_desc = "agate" + +/obj/item/cosmetics/eyeshadow/green + makeup_color = "#218c17" + color_desc = "emerald" + +/obj/item/cosmetics/eyeshadow/turquoise + makeup_color = "#0098f0" + color_desc = "turquoise" + +/obj/item/cosmetics/eyeshadow/blue + makeup_color = "#0024f0" + color_desc = "sapphire" + +/obj/item/cosmetics/eyeshadow/violet + makeup_color = "#d55cd0" + color_desc = "amethyst" + +/obj/item/cosmetics/eyeshadow/white + makeup_color = "#d8d5d5" + color_desc = "moonstone" + +/obj/item/cosmetics/eyeshadow/purple + makeup_color = "#440044" + color_desc = "garnet" + +/obj/item/cosmetics/eyeshadow/black + makeup_color = "#2b2a2a" + color_desc = "onyx" + +/obj/item/cosmetics/eyeshadow/black + name = "onyx eyeshadow" + makeup_color = "#2b2a2a" + color_desc = "onyx" diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index afb51b7f47d7..828d94861e61 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -1,32 +1,31 @@ -#define DEFIB_TIME_LIMIT (8 MINUTES) //past this many seconds, defib is useless. Currently 8 Minutes -#define DEFIB_TIME_LOSS (2 MINUTES) //past this many seconds, brain damage occurs. Currently 2 minutes - //backpack item /obj/item/defibrillator name = "auto-resuscitator" desc = "A device that delivers powerful shocks via detachable paddles to resuscitate incapacitated patients." icon = 'icons/obj/defibrillator.dmi' - icon_state = "defibunit" - item_state = "defibunit" + icon_state = ICON_STATE_WORLD slot_flags = SLOT_BACK - force = 5 - throwforce = 6 w_class = ITEM_SIZE_LARGE - origin_tech = "{'biotech':4,'powerstorage':2}" + origin_tech = @'{"biotech":4,"powerstorage":2}' action_button_name = "Remove/Replace Paddles" + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE, + ) var/obj/item/shockpaddles/linked/paddles var/obj/item/cell/bcell = null /obj/item/defibrillator/Initialize() //starts without a cell for rnd - . = ..() if(ispath(paddles)) paddles = new paddles(src, src) else paddles = new(src, src) - if(ispath(bcell)) bcell = new bcell(src) + . = ..() update_icon() /obj/item/defibrillator/Destroy() @@ -38,73 +37,63 @@ bcell = /obj/item/cell/apc /obj/item/defibrillator/on_update_icon() - var/list/new_overlays = list() - + . = ..() if(paddles) //in case paddles got destroyed somehow. if(paddles.loc == src) - new_overlays += "[initial(icon_state)]-paddles" + add_overlay("[icon_state]-paddles") if(bcell && bcell.check_charge(paddles.chargecost)) if(!paddles.safety) - new_overlays += "[initial(icon_state)]-emagged" + add_overlay("[icon_state]-emagged") else - new_overlays += "[initial(icon_state)]-powered" - + add_overlay("[icon_state]-powered") if(bcell) - var/ratio = Ceiling(bcell.percent()/25) * 25 - new_overlays += "[initial(icon_state)]-charge[ratio]" + var/ratio = ceil(bcell.percent()/25) * 25 + add_overlay("[icon_state]-charge[ratio]") else - new_overlays += "[initial(icon_state)]-nocell" - - overlays = new_overlays + add_overlay("[icon_state]-nocell") -/obj/item/defibrillator/examine(mob/user) +/obj/item/defibrillator/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(bcell) - to_chat(user, "The charge meter is showing [bcell.percent()]% charge left.") + . += "The charge meter is showing [bcell.percent()]% charge left." else - to_chat(user, "There is no cell inside.") + . += SPAN_WARNING("There is no cell inside.") /obj/item/defibrillator/ui_action_click() toggle_paddles() /obj/item/defibrillator/attack_hand(mob/user) - if(loc == user) - toggle_paddles() - else - ..() - -/obj/item/defibrillator/MouseDrop() - if(ismob(src.loc)) - if(!CanMouseDrop(src)) - return - var/mob/M = src.loc - if(!M.unEquip(src)) - return - src.add_fingerprint(usr) - M.put_in_any_hand_if_possible(src) - + if(loc != user || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + toggle_paddles() + return TRUE -/obj/item/defibrillator/attackby(obj/item/W, mob/user, params) - if(W == paddles) +// TODO: This should really use the cell extension +/obj/item/defibrillator/attackby(obj/item/used_item, mob/user, params) + if(used_item == paddles) reattach_paddles(user) - else if(istype(W, /obj/item/cell)) + return TRUE + else if(istype(used_item, /obj/item/cell)) if(bcell) - to_chat(user, "\the [src] already has a cell.") + to_chat(user, "\The [src] already has a cell.") else - if(!user.unEquip(W)) - return - W.forceMove(src) - bcell = W + if(!user.try_unequip(used_item)) + return TRUE + used_item.forceMove(src) + bcell = used_item to_chat(user, "You install a cell in \the [src].") update_icon() + return TRUE - else if(isScrewdriver(W)) + else if(IS_SCREWDRIVER(used_item)) if(bcell) bcell.update_icon() bcell.dropInto(loc) bcell = null to_chat(user, "You remove the cell from \the [src].") update_icon() + return TRUE + return FALSE else return ..() @@ -119,7 +108,7 @@ set name = "Toggle Paddles" set category = "Object" - var/mob/living/carbon/human/user = usr + var/mob/living/human/user = usr if(!paddles) to_chat(user, "The paddles are missing!") return @@ -141,9 +130,9 @@ if(!istype(M)) return 0 //not equipped - if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src) + if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back_str) == src) return 1 - if((slot_flags & SLOT_BELT) && M.get_equipped_item(slot_belt) == src) + if((slot_flags & SLOT_LOWER_BODY) && M.get_equipped_item(slot_belt_str) == src) return 1 return 0 @@ -171,11 +160,10 @@ /obj/item/defibrillator/compact name = "compact defibrillator" desc = "A belt-equipped defibrillator that can be rapidly deployed." - icon_state = "defibcompact" - item_state = "defibcompact" + icon = 'icons/obj/defibrillator_compact.dmi' w_class = ITEM_SIZE_NORMAL - slot_flags = SLOT_BELT - origin_tech = "{'biotech':5,'powerstorage':3}" + slot_flags = SLOT_LOWER_BODY + origin_tech = @'{"biotech":5,"powerstorage":3}' /obj/item/defibrillator/compact/loaded bcell = /obj/item/cell/high @@ -194,19 +182,20 @@ safety = 0 chargetime = (1 SECONDS) - //paddles - /obj/item/shockpaddles name = "defibrillator paddles" desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks." - icon = 'icons/obj/defibrillator.dmi' - icon_state = "defibpaddles" - item_state = "defibpaddles" + icon = 'icons/obj/defibrillator_paddles.dmi' + icon_state = ICON_STATE_WORLD gender = PLURAL - force = 2 - throwforce = 6 w_class = ITEM_SIZE_LARGE + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/copper = MATTER_AMOUNT_SECONDARY, /decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY) + max_health = ITEM_HEALTH_NO_DAMAGE + _base_attack_force = 2 + can_be_twohanded = TRUE + minimum_size_to_twohand = MOB_SIZE_SMALL var/safety = 1 //if you can zap people with the paddles on harm mode var/combat = 0 //If it can be used to revive people wearing thick clothing (e.g. spacesuits) @@ -227,7 +216,6 @@ if(cooldown) cooldown = 0 update_icon() - make_announcement("beeps, \"Unit is re-energized.\"", "notice") playsound(src, 'sound/machines/defib_ready.ogg', 50, 0) @@ -243,10 +231,9 @@ ..() /obj/item/shockpaddles/on_update_icon() - icon_state = "defibpaddles[wielded]" - item_state = "defibpaddles[wielded]" + . = ..() if(cooldown) - icon_state = "defibpaddles[wielded]_cooldown" + add_overlay("[icon_state]-cooldown") /obj/item/shockpaddles/proc/can_use(mob/user, mob/M) if(busy) @@ -263,30 +250,30 @@ return 1 //Checks for various conditions to see if the mob is revivable -/obj/item/shockpaddles/proc/can_defib(mob/living/carbon/human/H) //This is checked before doing the defib operation - if((H.species.species_flags & SPECIES_FLAG_NO_SCAN) || H.isSynthetic()) +/obj/item/shockpaddles/proc/can_defib(mob/living/human/H) //This is checked before doing the defib operation + if(H.has_body_flag(BODY_FLAG_NO_DEFIB)) return "buzzes, \"Unrecogized physiology. Operation aborted.\"" if(!check_contact(H)) return "buzzes, \"Patient's chest is obstructed. Operation aborted.\"" -/obj/item/shockpaddles/proc/can_revive(mob/living/carbon/human/H) //This is checked right before attempting to revive +/obj/item/shockpaddles/proc/can_revive(mob/living/human/H) //This is checked right before attempting to revive if(H.stat == DEAD) return "buzzes, \"Resuscitation failed - Severe neurological decay makes recovery of patient impossible. Further attempts futile.\"" -/obj/item/shockpaddles/proc/check_contact(mob/living/carbon/human/H) +/obj/item/shockpaddles/proc/check_contact(mob/living/human/H) if(!combat) - for(var/obj/item/clothing/cloth in list(H.wear_suit, H.w_uniform)) - if((cloth.body_parts_covered & UPPER_TORSO) && (cloth.item_flags & ITEM_FLAG_THICKMATERIAL)) + for(var/slot in list(slot_wear_suit_str, slot_w_uniform_str)) + var/obj/item/clothing/cloth = H.get_equipped_item(slot) + if(istype(cloth) && (cloth.body_parts_covered & SLOT_UPPER_BODY) && (cloth.item_flags & ITEM_FLAG_THICKMATERIAL)) return FALSE return TRUE -/obj/item/shockpaddles/proc/check_blood_level(mob/living/carbon/human/H) - if(!H.should_have_organ(BP_HEART)) - return FALSE - var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[BP_HEART] - if(!heart || H.get_blood_volume() < BLOOD_VOLUME_SURVIVE) - return TRUE +/obj/item/shockpaddles/proc/check_blood_level(mob/living/human/H) + if(H.should_have_organ(BP_HEART)) + var/obj/item/organ/internal/heart = GET_INTERNAL_ORGAN(H, BP_HEART) + if(!heart || H.get_blood_volume() < BLOOD_VOLUME_SURVIVE) + return TRUE return FALSE /obj/item/shockpaddles/proc/check_charge(var/charge_amt) @@ -295,21 +282,17 @@ /obj/item/shockpaddles/proc/checked_use(var/charge_amt) return 0 -/obj/item/shockpaddles/attack(mob/living/M, mob/living/user, var/target_zone) - var/mob/living/carbon/human/H = M - if(!istype(H) || user.a_intent == I_HURT) +/obj/item/shockpaddles/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(!ishuman(target) || user.check_intent(I_FLAG_HARM)) return ..() //Do a regular attack. Harm intent shocking happens as a hit effect - + var/mob/living/human/H = target if(can_use(user, H)) busy = 1 update_icon() - do_revive(H, user) - busy = 0 update_icon() - - return 1 + return TRUE //Since harm-intent now skips the delay for deliberate placement, you have to be able to hit them in combat in order to shock people. /obj/item/shockpaddles/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) @@ -327,7 +310,7 @@ return ..() // This proc is used so that we can return out of the revive process while ensuring that busy and update_icon() are handled -/obj/item/shockpaddles/proc/do_revive(mob/living/carbon/human/H, mob/living/user) +/obj/item/shockpaddles/proc/do_revive(mob/living/human/H, mob/living/user) if(H.ssd_check()) to_chat(find_dead_player(H.ckey, 1), "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived!") @@ -347,6 +330,11 @@ if(check_blood_level(H)) make_announcement("buzzes, \"Warning - Patient is in hypovolemic shock and may require a blood transfusion.\"", "warning") //also includes heart damage + //People may need more direct instruction + var/obj/item/organ/internal/heart = GET_INTERNAL_ORGAN(H, BP_HEART) + if(heart?.is_bruised()) + make_announcement("buzzes, \"Danger! The patient has sustained a cardiac contusion and will require surgical treatment for full recovery!\"", "danger") + //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total if(!do_after(user, chargetime, H)) return @@ -375,14 +363,15 @@ make_announcement("pings, \"Resuscitation successful.\"", "notice") playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0) H.resuscitate() - var/obj/item/organ/internal/cell/potato = H.internal_organs_by_name[BP_CELL] - if(istype(potato) && potato.cell) - var/obj/item/cell/C = potato.cell - C.give(chargecost) - H.AdjustSleeping(-60) + var/obj/item/organ/internal/cell/potato = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) + if(potato && potato.cell) + var/obj/item/cell/cell = potato.cell + cell.give(chargecost) + + ADJ_STATUS(H, STAT_ASLEEP, -60) log_and_message_admins("used \a [src] to revive [key_name(H)].") -/obj/item/shockpaddles/proc/lowskill_revive(mob/living/carbon/human/H, mob/living/user) +/obj/item/shockpaddles/proc/lowskill_revive(mob/living/human/H, mob/living/user) if(prob(60)) playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 100, 1, -1) H.electrocute_act(burn_damage_amt*4, src, def_zone = BP_CHEST) @@ -396,22 +385,22 @@ return 0 return 1 -/obj/item/shockpaddles/proc/do_electrocute(mob/living/carbon/human/H, mob/user, var/target_zone) - var/obj/item/organ/external/affecting = H.get_organ(target_zone) +/obj/item/shockpaddles/proc/do_electrocute(mob/living/human/H, mob/user, var/target_zone) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(H, check_zone(target_zone, H, TRUE)) //Shouldn't defib someone's eyes or mouth if(!affecting) - to_chat(user, "They are missing that body part!") + to_chat(user, SPAN_WARNING("They are missing that body part!")) return //no need to spend time carefully placing the paddles, we're just trying to shock them - user.visible_message("\The [user] slaps [src] onto [H]'s [affecting.name].", "You overcharge [src] and slap them onto [H]'s [affecting.name].") + user.visible_message(SPAN_DANGER("\The [user] slaps [src] onto [H]'s [affecting.name]."), SPAN_DANGER("You overcharge [src] and slap them onto [H]'s [affecting.name].")) //Just stop at awkwardly slapping electrodes on people if the safety is enabled if(safety) - to_chat(user, "You can't do that while the safety is enabled.") + to_chat(user, SPAN_WARNING("You can't do that while the safety is enabled.")) return playsound(get_turf(src), 'sound/machines/defib_charge.ogg', 50, 0) - audible_message("\The [src] lets out a steadily rising hum...") + audible_message(SPAN_WARNING("\The [src] lets out a steadily rising hum...")) if(!do_after(user, chargetime, H)) return @@ -422,7 +411,7 @@ playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0) return - user.visible_message("\The [user] shocks [H] with \the [src]!", "You shock [H] with \the [src]!") + user.visible_message(SPAN_DANGER("\The [user] shocks [H] with \the [src]!"), SPAN_WARNING("You shock [H] with \the [src]!")) playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 100, 1, -1) playsound(loc, 'sound/weapons/Egloves.ogg', 100, 1, -1) set_cooldown(cooldowntime) @@ -430,40 +419,14 @@ H.stun_effect_act(2, 120, target_zone) var/burn_damage = H.electrocute_act(burn_damage_amt*2, src, def_zone = target_zone) if(burn_damage > 15 && H.can_feel_pain()) - H.emote("scream") - var/obj/item/organ/internal/heart/doki = LAZYACCESS(affecting.internal_organs, BP_HEART) + H.emote(/decl/emote/audible/scream) + var/obj/item/organ/internal/heart/doki = locate() in affecting.internal_organs if(istype(doki) && doki.pulse && !doki.open && prob(10)) - to_chat(doki, "Your [doki] has stopped!") + to_chat(doki, SPAN_DANGER("Your [doki] has stopped!")) doki.pulse = PULSE_NONE admin_attack_log(user, H, "Electrocuted using \a [src]", "Was electrocuted with \a [src]", "used \a [src] to electrocute") -/obj/item/shockpaddles/proc/make_alive(mob/living/carbon/human/M) //This revives the mob - var/deadtime = world.time - M.timeofdeath - - M.switch_from_dead_to_living_mob_list() - M.timeofdeath = 0 - M.set_stat(UNCONSCIOUS) //Life() can bring them back to consciousness if it needs to. - M.regenerate_icons() - M.failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath. - M.reload_fullscreen() - - M.emote("gasp") - M.Weaken(rand(10,25)) - M.updatehealth() - apply_brain_damage(M, deadtime) - -/obj/item/shockpaddles/proc/apply_brain_damage(mob/living/carbon/human/H, var/deadtime) - if(deadtime < DEFIB_TIME_LOSS) return - - if(!H.should_have_organ(BP_BRAIN)) return //no brain - - var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] - if(!brain) return //no brain - - var/brain_damage = Clamp((deadtime - DEFIB_TIME_LOSS)/(DEFIB_TIME_LIMIT - DEFIB_TIME_LOSS)*brain.max_damage, H.getBrainLoss(), brain.max_damage) - H.setBrainLoss(brain_damage) - /obj/item/shockpaddles/proc/make_announcement(var/message, var/msg_class) audible_message("\The [src] [message]", "\The [src] vibrates slightly.") @@ -502,22 +465,20 @@ /obj/item/shockpaddles/robot name = "defibrillator paddles" - desc = "A pair of advanced shockpaddles powered by a robot's internal power cell, able to penetrate thick clothing." + desc = "A pair of advanced shock paddles powered by a robot's internal power cell, able to penetrate thick clothing." chargecost = 50 combat = 1 - icon_state = "defibpaddles0" - item_state = "defibpaddles0" cooldowntime = (3 SECONDS) /obj/item/shockpaddles/robot/check_charge(var/charge_amt) - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - return (R.cell && R.cell.check_charge(charge_amt)) + if(isrobot(loc)) + var/mob/living/silicon/robot/robot = loc + return robot.cell?.check_charge(charge_amt) /obj/item/shockpaddles/robot/checked_use(var/charge_amt) - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - return (R.cell && R.cell.checked_use(charge_amt)) + if(isrobot(loc)) + var/mob/living/silicon/robot/robot = loc + return robot.cell?.checked_use(charge_amt) /obj/item/shockpaddles/rig name = "mounted defibrillator" @@ -529,19 +490,19 @@ wielded = 1 /obj/item/shockpaddles/rig/check_charge(var/charge_amt) - if(istype(src.loc, /obj/item/rig_module/device/defib)) - var/obj/item/rig_module/device/defib/module = src.loc + if(istype(loc, /obj/item/rig_module/device/defib)) + var/obj/item/rig_module/device/defib/module = loc return (module.holder && module.holder.cell && module.holder.cell.check_charge(charge_amt)) /obj/item/shockpaddles/rig/checked_use(var/charge_amt) - if(istype(src.loc, /obj/item/rig_module/device/defib)) - var/obj/item/rig_module/device/defib/module = src.loc + if(istype(loc, /obj/item/rig_module/device/defib)) + var/obj/item/rig_module/device/defib/module = loc return (module.holder && module.holder.cell && module.holder.cell.checked_use(charge_amt)) /obj/item/shockpaddles/rig/set_cooldown(var/delay) ..() - if(istype(src.loc, /obj/item/rig_module/device/defib)) - var/obj/item/rig_module/device/defib/module = src.loc + if(istype(loc, /obj/item/rig_module/device/defib)) + var/obj/item/rig_module/device/defib/module = loc module.next_use = world.time + delay /* Shockpaddles that are linked to a base unit @@ -581,7 +542,7 @@ */ /obj/item/shockpaddles/standalone - desc = "A pair of shockpaddles powered by an experimental miniaturized reactor" //Inspired by the advanced e-gun + desc = "A pair of shock paddles powered by an experimental miniaturized reactor" //Inspired by the advanced e-gun var/fail_counter = 0 /obj/item/shockpaddles/standalone/Destroy() @@ -622,13 +583,7 @@ /obj/item/shockpaddles/standalone/traitor name = "defibrillator paddles" desc = "A pair of unusual looking paddles powered by an experimental miniaturized reactor. It possesses both the ability to penetrate armor and to deliver powerful shocks." - icon = 'icons/obj/defibrillator.dmi' - icon_state = "defibpaddles0" - item_state = "defibpaddles0" combat = 1 safety = 0 chargetime = (1 SECONDS) burn_damage_amt = 15 - -#undef DEFIB_TIME_LIMIT -#undef DEFIB_TIME_LOSS diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index f62034f647e4..374f19e6ccb2 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -1,11 +1,12 @@ /obj/item/dice name = "d6" - desc = "A dice with six sides." + desc = "A die with six sides." icon = 'icons/obj/dice.dmi' icon_state = "d66" w_class = ITEM_SIZE_TINY var/sides = 6 - attack_verb = list("diced") + attack_verb = "diced" + material = /decl/material/solid/organic/plastic /obj/item/dice/Initialize() . = ..() @@ -36,31 +37,31 @@ /obj/item/dice/d4 name = "d4" - desc = "A dice with four sides." + desc = "A die with four sides." icon_state = "d44" sides = 4 /obj/item/dice/d8 name = "d8" - desc = "A dice with eight sides." + desc = "A die with eight sides." icon_state = "d88" sides = 8 /obj/item/dice/d10 name = "d10" - desc = "A dice with ten sides." + desc = "A die with ten sides." icon_state = "d1010" sides = 10 /obj/item/dice/d12 name = "d12" - desc = "A dice with twelve sides." + desc = "A die with twelve sides." icon_state = "d1212" sides = 12 /obj/item/dice/d20 name = "d20" - desc = "A dice with twenty sides." + desc = "A die with twenty sides." icon_state = "d2020" sides = 20 @@ -75,8 +76,8 @@ /obj/item/dice/d100 name = "d100" - desc = "A dice with ten sides. This one is for the tens digit." - icon_state = "d10010" + desc = "A die with ten sides. This one is for the tens digit." + icon_state = "d1001" sides = 10 /obj/item/dice/d100/roll_die() @@ -85,4 +86,4 @@ . = res /obj/item/dice/d100/convert_result(var/res) - . = Floor(res/10) + . = floor(res/10) diff --git a/code/game/objects/items/weapons/ecigs.dm b/code/game/objects/items/weapons/ecigs.dm index 1b036114a513..ca7f2f6eb060 100644 --- a/code/game/objects/items/weapons/ecigs.dm +++ b/code/game/objects/items/weapons/ecigs.dm @@ -1,214 +1,181 @@ /obj/item/clothing/mask/smokable/ecig name = "electronic cigarette" - desc = "Device with modern approach to smoking." - icon = 'icons/obj/items/ecig.dmi' - var/active = 0 - var/obj/item/cell/cigcell - var/cartridge_type = /obj/item/chems/ecig_cartridge/med_nicotine - var/obj/item/chems/ecig_cartridge/ec_cartridge - var/cell_type = /obj/item/cell/device/standard + desc = "A device with a modern approach to smoking." + icon = 'icons/clothing/mask/smokables/cigarette_electronic.dmi' w_class = ITEM_SIZE_TINY - slot_flags = SLOT_EARS | SLOT_MASK + slot_flags = SLOT_EARS | SLOT_FACE attack_verb = list("attacked", "poked", "battered") body_parts_covered = 0 - var/brightness_on = 1 chem_volume = 0 //ecig has no storage on its own but has reagent container created by parent obj - item_state = "ecigoff" - var/icon_off - var/icon_empty + material = /decl/material/solid/organic/plastic + + var/brightness_on = 1 + var/cartridge_type = /obj/item/chems/ecig_cartridge/med_nicotine + var/obj/item/chems/ecig_cartridge/ec_cartridge var/power_usage = 450 //value for simple ecig, enough for about 1 cartridge, in JOULES! var/ecig_colors = list(null, COLOR_DARK_GRAY, COLOR_RED_GRAY, COLOR_BLUE_GRAY, COLOR_GREEN_GRAY, COLOR_PURPLE_GRAY) var/idle = 0 - var/idle_treshold = 30 + var/idle_threshold = 30 /obj/item/clothing/mask/smokable/ecig/Initialize() - . = ..() - if(ispath(cell_type)) - cigcell = new cell_type + setup_power_supply() ec_cartridge = new cartridge_type(src) + . = ..() + +/obj/item/clothing/mask/smokable/ecig/Destroy() + QDEL_NULL(ec_cartridge) + return ..() -/obj/item/clothing/mask/smokable/ecig/get_cell() - return cigcell +/obj/item/clothing/mask/smokable/ecig/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell/device/standard + accepted_cell_type = accepted_cell_type || /obj/item/cell/device + return ..(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) /obj/item/clothing/mask/smokable/ecig/simple name = "cheap electronic cigarette" desc = "A cheap Lucky 1337 electronic cigarette, styled like a traditional cigarette." - icon_state = "ccigoff" - icon_off = "ccigoff" - icon_empty = "ccigoff" - icon_on = "ccigon" + icon = 'icons/clothing/mask/smokables/cigarette_electronic_cheap.dmi' -/obj/item/clothing/mask/smokable/ecig/simple/examine(mob/user) +/obj/item/clothing/mask/smokable/ecig/simple/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(ec_cartridge) - to_chat(user,"There are [round(ec_cartridge.reagents.total_volume, 1)] units of liquid remaining.") + . += SPAN_NOTICE("There are [round(REAGENT_TOTAL_VOLUME(ec_cartridge.reagents), 1)] units of liquid remaining.") else - to_chat(user,"There's no cartridge connected.") + . += SPAN_NOTICE("There's no cartridge connected.") /obj/item/clothing/mask/smokable/ecig/util name = "electronic cigarette" desc = "A popular utilitarian model electronic cigarette, the ONI-55. Comes in a variety of colors." - icon_state = "ecigoff1" - icon_off = "ecigoff1" - icon_empty = "ecigoff1" - icon_on = "ecigon" - cell_type = /obj/item/cell/device/high //enough for four cartridges + +/obj/item/clothing/mask/smokable/ecig/util/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell/device/high + return ..(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) //enough for four cartridges /obj/item/clothing/mask/smokable/ecig/util/Initialize() . = ..() - color = pick(ecig_colors) + set_color(pick(ecig_colors)) -obj/item/clothing/mask/smokable/ecig/util/examine(mob/user) +/obj/item/clothing/mask/smokable/ecig/util/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(ec_cartridge) - to_chat(user,"There are [round(ec_cartridge.reagents.total_volume, 1)] units of liquid remaining.") - else - to_chat(user,"There's no cartridge connected.") - if(cigcell) - to_chat(user,"The power meter shows that there's about [round(cigcell.percent(), 25)]% power remaining.") + . += SPAN_NOTICE("There are [round(REAGENT_TOTAL_VOLUME(ec_cartridge.reagents), 1)] units of liquid remaining.") else - to_chat(user,"There's no cartridge connected.") + . += SPAN_NOTICE("There's no cartridge connected.") /obj/item/clothing/mask/smokable/ecig/deluxe name = "deluxe electronic cigarette" - desc = "A premium model eGavana MK3 electronic cigarette, shaped like a cigar." - icon_state = "pcigoff1" - icon_off = "pcigoff1" - icon_empty = "pcigoff2" - icon_on = "pcigon" - cell_type = /obj/item/cell/device/high //enough for four catridges - -/obj/item/clothing/mask/smokable/ecig/deluxe/examine(mob/user) + desc = "A premium model eHavana MK3 electronic cigarette, shaped like a cigar." + icon = 'icons/clothing/mask/smokables/cigarette_electronic_deluxe.dmi' + +/obj/item/clothing/mask/smokable/ecig/deluxe/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell/device/high + return ..(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) //enough for four cartridges + +/obj/item/clothing/mask/smokable/ecig/deluxe/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(ec_cartridge) - to_chat(user,"There are [round(ec_cartridge.reagents.total_volume, 1)] units of liquid remaining.") + . += SPAN_NOTICE("There are [round(REAGENT_TOTAL_VOLUME(ec_cartridge.reagents), 1)] units of liquid remaining.") else - to_chat(user,"There's no cartridge connected.") - if(cigcell) - to_chat(user,"The power meter shows that there's about [round(cigcell.percent(), 1)]% power remaining.") - else - to_chat(user,"There's no cartridge connected.") + . += SPAN_NOTICE("There's no cartridge connected.") /obj/item/clothing/mask/smokable/ecig/proc/Deactivate() - active = 0 + lit = FALSE STOP_PROCESSING(SSobj, src) update_icon() /obj/item/clothing/mask/smokable/ecig/Process() - if(!cigcell) + if(!get_cell()) Deactivate() return if(!ec_cartridge) Deactivate() return - if(idle >= idle_treshold) //idle too long -> automatic shut down + if(idle >= idle_threshold) //idle too long -> automatic shut down idle = 0 - visible_message("\The [src] powers down automatically.", null, 2) + visible_message(SPAN_NOTICE("\The [src] powers down automatically."), null, 2) Deactivate() return idle ++ if(ishuman(loc)) - var/mob/living/carbon/human/C = loc + var/mob/living/human/user = loc - if (!active || !ec_cartridge || !ec_cartridge.reagents.total_volume)//no cartridge - if(!ec_cartridge.reagents.total_volume) - to_chat(C, "There's no liquid left in \the [src], so you shut it down.") + var/cart_vol = REAGENT_TOTAL_VOLUME(ec_cartridge.reagents) + if (!lit || !ec_cartridge || !cart_vol)//no cartridge + if(!cart_vol) + to_chat(user, SPAN_NOTICE("There's no liquid left in \the [src], so you shut it down.")) Deactivate() return - if (src == C.wear_mask && C.check_has_mouth()) //transfer, but only when not disabled + if (src == user.get_equipped_item(slot_wear_mask_str) && user.check_has_mouth()) //transfer, but only when not disabled idle = 0 //here we'll reduce battery by usage, and check powerlevel - you only use batery while smoking - if(!cigcell.checked_use(power_usage * CELLRATE)) //if this passes, there's not enough power in the battery + var/obj/item/cell/cell = get_cell() + if(!cell?.checked_use(power_usage * CELLRATE)) //if this passes, there's not enough power in the battery Deactivate() - to_chat(C,"\The [src]'s power meter flashes a low battery warning and shuts down.") + to_chat(user,SPAN_NOTICE("\The [src]'s power meter flashes a low battery warning and shuts down.")) return - ec_cartridge.reagents.trans_to_mob(C, REM, CHEM_INGEST, 0.4) // Most of it is not inhaled... balance reasons. + ec_cartridge.reagents.trans_to_mob(user, REM, CHEM_INHALE, 0.4) // Most of it is not inhaled... balance reasons. /obj/item/clothing/mask/smokable/ecig/on_update_icon() - if (active) - item_state = icon_on - icon_state = icon_on - set_light(0.6, 0.5, brightness_on) - else if (ec_cartridge) - set_light(0) - item_state = icon_off - icon_state = icon_off + . = ..() + if(lit) + set_light(brightness_on) else - icon_state = icon_empty - item_state = icon_empty set_light(0) + if(ec_cartridge && check_state_in_icon("[icon_state]-loaded", icon)) + add_overlay("[icon_state]-loaded") if(ismob(loc)) var/mob/living/M = loc - M.update_inv_wear_mask(0) - M.update_inv_l_hand(0) - M.update_inv_r_hand(1) - + M.update_equipment_overlay(slot_wear_mask_str, redraw_mob = FALSE) + M.update_inhand_overlays() -/obj/item/clothing/mask/smokable/ecig/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/chems/ecig_cartridge)) +/obj/item/clothing/mask/smokable/ecig/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/chems/ecig_cartridge)) if (ec_cartridge)//can't add second one - to_chat(user, "A cartridge has already been installed. ") - else if(user.unEquip(I, src))//fits in new one - ec_cartridge = I - update_icon() - to_chat(user, "You insert \the [I] into \the [src]. ") - - if(istype(I, /obj/item/screwdriver)) - if(cigcell) //if contains powercell - cigcell.update_icon() - cigcell.dropInto(loc) - cigcell = null - to_chat(user, "You remove \the [cigcell] from \the [src].") - else //does not contains cell - to_chat(user, "There's no battery in \the [src].") - - if(istype(I, /obj/item/cell/device)) - if(!cigcell && user.unEquip(I)) - I.forceMove(src) - cigcell = I - to_chat(user, "You install \the [cigcell] into \the [src].") + to_chat(user, SPAN_NOTICE("A cartridge has already been installed.")) + else if(user.try_unequip(used_item, src))//fits in new one + ec_cartridge = used_item update_icon() - else - to_chat(user, "\The [src] already has a battery installed.") - + to_chat(user, SPAN_NOTICE("You insert \the [used_item] into \the [src].")) + return TRUE + return ..() /obj/item/clothing/mask/smokable/ecig/attack_self(mob/user) - if (active) + if(lit) Deactivate() - to_chat(user, "You turn off \the [src]. ") + to_chat(user, SPAN_NOTICE("You turn off \the [src].")) else - if(cigcell) + var/obj/item/cell/cell = get_cell() + if(cell) if (!ec_cartridge) - to_chat(user, "You can't use \the [src] with no cartridge installed! ") + to_chat(user, SPAN_NOTICE("You can't use \the [src] with no cartridge installed!")) return - else if(!ec_cartridge.reagents.total_volume) - to_chat(user, "You can't use \the [src] with no liquid left! ") + else if(!REAGENT_TOTAL_VOLUME(ec_cartridge.reagents)) + to_chat(user, SPAN_NOTICE("You can't use \the [src] with no liquid left!")) return - else if(!cigcell.check_charge(power_usage * CELLRATE)) - to_chat(user, "\The [src]'s power meter flashes a low battery warning and refuses to operate. ") + else if(!cell.check_charge(power_usage * CELLRATE)) + to_chat(user, SPAN_NOTICE("\The [src]'s power meter flashes a low battery warning and refuses to operate.")) return - active=1 + lit = TRUE START_PROCESSING(SSobj, src) - to_chat(user, "You turn on \the [src]. ") + to_chat(user, SPAN_NOTICE("You turn on \the [src].")) update_icon() else - to_chat(user, "\The [src] does not have a battery installed.") + to_chat(user, SPAN_WARNING("\The [src] does not have a battery installed.")) /obj/item/clothing/mask/smokable/ecig/attack_hand(mob/user)//eject cartridge - if(user.get_inactive_hand() == src)//if being hold - if (ec_cartridge) - active=0 - user.put_in_hands(ec_cartridge) - to_chat(user, "You remove \the [ec_cartridge] from \the [src]. ") - ec_cartridge = null - update_icon() - else - ..() + if(!user.is_holding_offhand(src) || !ec_cartridge || !user.check_dexterity(DEXTERITY_HOLD_ITEM)) + return ..() + lit = FALSE + user.put_in_hands(ec_cartridge) + to_chat(user, SPAN_NOTICE("You remove \the [ec_cartridge] from \the [src].")) + ec_cartridge = null + update_icon() + return TRUE /obj/item/chems/ecig_cartridge name = "tobacco flavour cartridge" @@ -218,12 +185,12 @@ obj/item/clothing/mask/smokable/ecig/util/examine(mob/user) icon_state = "ecartridge" material = /decl/material/solid/metal/aluminium matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - volume = 20 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER + chem_volume = 20 + atom_flags = ATOM_FLAG_OPEN_CONTAINER -/obj/item/chems/ecig_cartridge/examine(mob/user)//to see how much left +/obj/item/chems/ecig_cartridge/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The cartridge has [reagents.total_volume] units of liquid remaining.") + . += "The cartridge has [REAGENT_TOTAL_VOLUME(reagents)] units of liquid remaining." //flavours /obj/item/chems/ecig_cartridge/blank @@ -234,85 +201,76 @@ obj/item/clothing/mask/smokable/ecig/util/examine(mob/user) name = "flavorless nicotine cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says you can add whatever flavoring agents you want." -/obj/item/chems/ecig_cartridge/blanknico/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) +/obj/item/chems/ecig_cartridge/blanknico/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) /obj/item/chems/ecig_cartridge/med_nicotine name = "tobacco flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its tobacco flavored." -/obj/item/chems/ecig_cartridge/med_nicotine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco, 5) - reagents.add_reagent(/decl/material/liquid/water, 15) +/obj/item/chems/ecig_cartridge/med_nicotine/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 15) /obj/item/chems/ecig_cartridge/high_nicotine name = "high nicotine tobacco flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its tobacco flavored, with extra nicotine." -/obj/item/chems/ecig_cartridge/high_nicotine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco, 10) - reagents.add_reagent(/decl/material/liquid/water, 10) +/obj/item/chems/ecig_cartridge/high_nicotine/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 10) + add_to_reagents(/decl/material/liquid/water, 10) /obj/item/chems/ecig_cartridge/orange name = "orange flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its orange flavored." -/obj/item/chems/ecig_cartridge/orange/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - reagents.add_reagent(/decl/material/liquid/drink/juice/orange, 5) +/obj/item/chems/ecig_cartridge/orange/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) + add_to_reagents(/decl/material/liquid/drink/juice/orange, 5) /obj/item/chems/ecig_cartridge/mint name = "mint flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its mint flavored." -/obj/item/chems/ecig_cartridge/mint/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - reagents.add_reagent(/decl/material/liquid/menthol, 5) +/obj/item/chems/ecig_cartridge/mint/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) + add_to_reagents(/decl/material/liquid/menthol, 5) /obj/item/chems/ecig_cartridge/watermelon name = "watermelon flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its watermelon flavored." -/obj/item/chems/ecig_cartridge/watermelon/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - reagents.add_reagent(/decl/material/liquid/drink/juice/watermelon, 5) +/obj/item/chems/ecig_cartridge/watermelon/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) + add_to_reagents(/decl/material/liquid/drink/juice/watermelon, 5) /obj/item/chems/ecig_cartridge/grape name = "grape flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its grape flavored." -/obj/item/chems/ecig_cartridge/grape/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - reagents.add_reagent(/decl/material/liquid/drink/juice/grape, 5) +/obj/item/chems/ecig_cartridge/grape/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) + add_to_reagents(/decl/material/liquid/drink/juice/grape, 5) /obj/item/chems/ecig_cartridge/lemonlime name = "lemon-lime flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its lemon-lime flavored." -/obj/item/chems/ecig_cartridge/lemonlime/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - reagents.add_reagent(/decl/material/liquid/drink/lemon_lime, 5) +/obj/item/chems/ecig_cartridge/lemonlime/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) + add_to_reagents(/decl/material/liquid/drink/lemon_lime, 5) /obj/item/chems/ecig_cartridge/coffee name = "coffee flavour cartridge" desc = "A small metal cartridge which contains an atomizing coil and a solution to be atomized. The label says its coffee flavored." -/obj/item/chems/ecig_cartridge/coffee/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/tobacco/liquid, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - reagents.add_reagent(/decl/material/liquid/drink/coffee, 5) \ No newline at end of file +/obj/item/chems/ecig_cartridge/coffee/populate_reagents() + add_to_reagents(/decl/material/solid/tobacco/liquid, 5) + add_to_reagents(/decl/material/liquid/water, 10) + add_to_reagents(/decl/material/liquid/drink/coffee, 5) \ No newline at end of file diff --git a/code/game/objects/items/weapons/electric_welder.dm b/code/game/objects/items/weapons/electric_welder.dm deleted file mode 100644 index 50e7b01c2e32..000000000000 --- a/code/game/objects/items/weapons/electric_welder.dm +++ /dev/null @@ -1,88 +0,0 @@ -/obj/item/weldingtool/electric - name = "arc welder" - desc = "A man-portable arc welding tool." - icon = 'icons/obj/items/tool/arc_welder.dmi' - icon_state = "welder_arc" - welding_resource = "stored charge" - tank = null - waterproof = TRUE - force = 7 - throwforce = 7 - var/obj/item/cell/cell = /obj/item/cell/high - var/fuel_cost_multiplier = 10 - -/obj/item/weldingtool/electric/Initialize() - if(ispath(cell)) - cell = new cell(src) - . = ..() - -/obj/item/weldingtool/electric/examine(mob/user, distance) - . = ..() - if (!cell) - to_chat(user, "There is no [welding_resource] source attached.") - else - to_chat(user, (distance == 0 ? "It has [get_fuel()] [welding_resource] remaining. " : "") + "[cell] is attached.") - -/obj/item/weldingtool/electric/afterattack(var/obj/O, var/mob/user, var/proximity) - if(proximity && istype(O, /obj/structure/reagent_dispensers/fueltank)) - if(!welding) - to_chat(user, SPAN_WARNING("\The [src] runs on an internal charge and does not need to be refuelled.")) - return - . = ..() - -/obj/item/weldingtool/electric/get_cell() - if(cell) - . = cell - else if(istype(loc, /obj/item/rig_module)) - var/obj/item/rig_module/module = loc - if(istype(module.holder)) - . = module.holder.get_cell() - -/obj/item/weldingtool/electric/get_fuel() - return get_available_charge() - -/obj/item/weldingtool/electric/proc/get_available_charge() - var/obj/item/cell/cell = get_cell() - return cell ? cell.charge : 0 - -/obj/item/weldingtool/electric/attackby(var/obj/item/W, var/mob/user) - if(istype(W,/obj/item/stack/material/rods) || istype(W, /obj/item/welder_tank)) - return - if(isScrewdriver(W)) - if(cell) - cell.dropInto(get_turf(src)) - user.put_in_hands(cell) - to_chat(user, SPAN_NOTICE("You pop \the [cell] out of \the [src].")) - welding = FALSE - cell = null - update_icon() - else - to_chat(user, SPAN_WARNING("\The [src] has no cell installed.")) - return - else if(istype(W, /obj/item/cell)) - if(cell) - to_chat(user, SPAN_WARNING("\The [src] already has a cell installed.")) - else if(user.unEquip(W)) - cell = W - cell.forceMove(src) - to_chat(user, SPAN_NOTICE("You slot \the [cell] into \the [src].")) - update_icon() - return - . = ..() - -/obj/item/weldingtool/electric/burn_fuel(var/amount) - spend_charge(amount * fuel_cost_multiplier) - var/turf/T = get_turf(src) - if(T) - T.hotspot_expose(700, 5) - -/obj/item/weldingtool/electric/on_update_icon() - underlays.Cut() - item_state = welding ? "welder1" : "welder" - if(cell) - underlays += image(icon = icon, icon_state = "[initial(icon_state)]_cell") - -/obj/item/weldingtool/electric/proc/spend_charge(var/amount) - var/obj/item/cell/cell = get_cell() - if(cell) - cell.use(amount * CELLRATE) diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 29858c308525..296e348430d4 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -7,7 +7,11 @@ item_state = "plasticx" item_flags = ITEM_FLAG_NO_BLUDGEON w_class = ITEM_SIZE_SMALL - origin_tech = "{'esoteric':2}" + origin_tech = @'{"esoteric":2}' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE + ) var/datum/wires/explosive/c4/wires = null var/timer = 10 var/atom/target = null @@ -24,32 +28,38 @@ wires = null return ..() -/obj/item/plastique/attackby(var/obj/item/I, var/mob/user) - if(isScrewdriver(I)) +/obj/item/plastique/attackby(var/obj/item/used_item, var/mob/user) + if(IS_SCREWDRIVER(used_item)) open_panel = !open_panel to_chat(user, "You [open_panel ? "open" : "close"] the wire panel.") - else if(isWirecutter(I) || isMultitool(I) || istype(I, /obj/item/assembly/signaler )) - wires.Interact(user) + return TRUE + else if(IS_WIRECUTTER(used_item) || IS_MULTITOOL(used_item) || istype(used_item, /obj/item/assembly/signaler )) + return wires.Interact(user) else - ..() + return ..() /obj/item/plastique/attack_self(mob/user) var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num - if(user.get_active_hand() == src) - newtime = Clamp(newtime, 10, 60000) + if(user.get_active_held_item() == src) + newtime = clamp(newtime, 10, 60000) timer = newtime to_chat(user, "Timer set for [timer] seconds.") /obj/item/plastique/afterattack(atom/movable/target, mob/user, flag) if (!flag) return - if (ismob(target) || istype(target, /turf/unsimulated) || istype(target, /turf/simulated/shuttle) || istype(target, /obj/item/storage/) || istype(target, /obj/item/clothing/accessory/storage/) || istype(target, /obj/item/clothing/under)) + if (ismob(target) || target.storage || istype(target, /obj/item/clothing/webbing)) return + if(isturf(target)) + var/turf/target_turf = target + if(!target_turf.simulated) + return + to_chat(user, "Planting explosives...") user.do_attack_animation(target) if(do_after(user, 50, target) && in_range(user, target)) - if(!user.unequip_item()) + if(!user.try_unequip(src)) return src.target = target forceMove(null) @@ -75,14 +85,14 @@ explosion(location, -1, -1, 2, 3) if(target) - if (istype(target, /turf/simulated/wall)) - var/turf/simulated/wall/W = target - W.dismantle_wall(1) - else if(istype(target, /mob/living)) + if (istype(target, /turf)) + target.physically_destroyed() + else if(isliving(target)) target.explosion_act(2) // c4 can't gib mobs anymore. else target.explosion_act(1) - if(target) + // TODO: vis contents instead of diddling overlays directly. + if(!QDELETED(target)) target.overlays -= image_overlay qdel(src) @@ -98,5 +108,5 @@ T-- explode(get_turf(target)) -/obj/item/plastique/attack(mob/M, mob/user, def_zone) - return +/obj/item/plastique/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index 96390cdd669b..074cdfc5de33 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -1,89 +1,80 @@ -/obj/item/extinguisher - name = "fire extinguisher" - desc = "A traditional red fire extinguisher." - icon = 'icons/obj/items/fire_extinguisher.dmi' - icon_state = "fire_extinguisher0" - item_state = "fire_extinguisher" - hitsound = 'sound/weapons/smash.ogg' - obj_flags = OBJ_FLAG_CONDUCTIBLE - throwforce = 10 - w_class = ITEM_SIZE_NORMAL - throw_speed = 2 - throw_range = 10 - force = 10.0 - material = /decl/material/solid/metal/steel - attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed") - - var/spray_particles = 3 - var/spray_amount = 120 //units of liquid per spray - 120 -> same as splashing them with a bucket per spray - var/starting_water = 2000 - var/max_water = 2000 - var/last_use = 1.0 - var/safety = 1 - var/sprite_name = "fire_extinguisher" - -/obj/item/extinguisher/mini - name = "fire extinguisher" - desc = "A light and compact fibreglass-framed model fire extinguisher." - icon_state = "miniFE0" - item_state = "miniFE" - hitsound = null - throwforce = 2 - w_class = ITEM_SIZE_SMALL - force = 3.0 - spray_amount = 80 - starting_water = 1000 - max_water = 1000 - sprite_name = "miniFE" - -/obj/item/extinguisher/Initialize() +/obj/item/chems/spray/extinguisher + name = "fire extinguisher" + desc = "A traditional red fire extinguisher." + icon = 'icons/obj/items/fire_extinguisher.dmi' + icon_state = "fire_extinguisher0" + item_state = "fire_extinguisher" + hitsound = 'sound/weapons/smash.ogg' + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_HOLLOW + w_class = ITEM_SIZE_NORMAL + throw_speed = 2 + throw_range = 10 + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed") + possible_transfer_amounts = @"[30,60,120]" //units of liquid per spray - 120 -> same as splashing them with a bucket per spray + possible_particle_amounts = @"[1,2,3]" //Amount of chempuff particles to spawn on spray + amount_per_transfer_from_this = 120 + chem_volume = 2000 + spray_particles = 3 //Amount of liquid particles to spawn on spray + particle_move_delay = 5 //Spray effect move delay + safety = TRUE + sound_spray = 'sound/effects/extinguish.ogg' + _base_attack_force = 10 + var/sprite_name = "fire_extinguisher" + +/obj/item/chems/spray/extinguisher/mini + name = "mini fire extinguisher" + desc = "A light and compact fiberglass-framed model fire extinguisher." + icon_state = "miniFE0" + item_state = "miniFE" + sprite_name = "miniFE" + w_class = ITEM_SIZE_SMALL + hitsound = null + possible_transfer_amounts = @"[40,80]" //units of liquid per spray - 120 -> same as splashing them with a bucket per spray + possible_particle_amounts = @"[1,2]" + amount_per_transfer_from_this = 80 + spray_particles = 2 + chem_volume = 1000 + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT + ) + _base_attack_force = 3 + +/obj/item/chems/spray/extinguisher/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/spray/extinguisher/has_safety() + return TRUE + +/obj/item/chems/spray/extinguisher/on_update_icon() . = ..() - create_reagents(max_water) - if(starting_water > 0) - reagents.add_reagent(/decl/material/liquid/water, starting_water) - -/obj/item/extinguisher/empty - starting_water = 0 + icon_state = "[sprite_name][!safety]" -/obj/item/extinguisher/examine(mob/user, distance) +/obj/item/chems/spray/extinguisher/Spray_at(atom/movable/A, mob/user, proximity) . = ..() - if(distance <= 0) - to_chat(user, text("\icon[] [] contains [] units of water left!", src, src.name, src.reagents.total_volume)) - -/obj/item/extinguisher/attack_self(mob/user) - safety = !safety - src.icon_state = "[sprite_name][!safety]" - src.desc = "The safety is [safety ? "on" : "off"]." - to_chat(user, "The safety is [safety ? "on" : "off"].") - return - -/obj/item/extinguisher/attack(var/mob/living/M, var/mob/user) - if(user.a_intent == I_HELP) - if(src.safety || (world.time < src.last_use + 20)) // We still catch help intent to not randomly attack people - return - if(src.reagents.total_volume < 1) - to_chat(user, SPAN_NOTICE("\The [src] is empty.")) - return - - src.last_use = world.time - reagents.splash(M, min(reagents.total_volume, spray_amount)) - - user.visible_message(SPAN_NOTICE("\The [user] sprays \the [M] with \the [src].")) - playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) - - return 1 // No afterattack - return ..() - -/obj/item/extinguisher/proc/propel_object(var/obj/O, mob/user, movementdirection) - if(O.anchored) return - - var/obj/structure/bed/chair/C - if(istype(O, /obj/structure/bed/chair)) - C = O + if(!.) + return + if(user.buckled && isobj(user.buckled)) + addtimer(CALLBACK(src, PROC_REF(propel_object), user.buckled, user, get_dir(A, user)), 0) + else if(user.can_slip(magboots_only = TRUE)) + var/old_dir = user.dir + step(user, get_dir(A, user)) + user.set_dir(old_dir) + +/obj/item/chems/spray/extinguisher/proc/propel_object(var/obj/O, mob/user, movementdirection) + if(O.anchored || !(O.movable_flags & MOVABLE_FLAG_WHEELED)) + return + var/obj/structure/chair/C = istype(O, /obj/structure/chair)? O : null + //#TODO: That could definitely be improved. Would suggest to use process_momentum but its only for thrownthing var/list/move_speed = list(1, 1, 1, 2, 2, 3) for(var/i in 1 to 6) - if(C) C.propelled = (6-i) + if(C) + C.propelled = (6-i) O.Move(get_step(user,movementdirection), movementdirection) sleep(move_speed[i]) @@ -92,70 +83,18 @@ O.Move(get_step(user,movementdirection), movementdirection) sleep(3) -/obj/item/extinguisher/resolve_attackby(var/atom/target, var/mob/user, var/flag) - if (istype(target, /obj/structure/hygiene/sink) && REAGENTS_FREE_SPACE(target.reagents) > 0) // fill first, wash if full - return FALSE - return ..() - - -/obj/item/extinguisher/afterattack(var/atom/target, var/mob/user, var/flag) - var/issink = istype(target, /obj/structure/hygiene/sink) - - if (flag && (issink || istype(target, /obj/structure/reagent_dispensers))) - var/obj/dispenser = target - var/amount = REAGENTS_FREE_SPACE(target.reagents) - if (amount <= 0) - to_chat(user, SPAN_NOTICE("\The [src] is full.")) - return - if (!issink) // sinks create reagents, they don't "contain" them - if (dispenser.reagents.total_volume <= 0) - to_chat(user, SPAN_NOTICE("\The [dispenser] is empty.")) - return - amount = dispenser.reagents.trans_to_obj(src, max_water) - else - reagents.add_reagent(/decl/material/liquid/water, amount) - to_chat(user, SPAN_NOTICE("You fill \the [src] with [amount] units from \the [dispenser].")) - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - if (istype(target, /obj/structure/reagent_dispensers/acid)) - to_chat(user, SPAN_WARNING("The acid violently eats away at \the [src]!")) - if (prob(50)) - reagents.splash(user, 5) - qdel(src) - return - - if (!safety) - if (src.reagents.total_volume < 1) - to_chat(usr, SPAN_NOTICE("\The [src] is empty.")) - return - - if (world.time < src.last_use + 20) - return - - src.last_use = world.time - - playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) - - var/direction = get_dir(target,src) - - if(user.buckled && isobj(user.buckled)) - addtimer(CALLBACK(src, .proc/propel_object, user.buckled, user, direction), 0) +/obj/item/chems/spray/extinguisher/toggle_safety() + . = ..() + update_icon() + update_held_icon() - addtimer(CALLBACK(src, .proc/do_spray, target), 0) +/obj/item/chems/spray/extinguisher/get_alt_interactions(mob/user) + . = ..() + LAZYREMOVE(., /decl/interaction_handler/set_transfer/chems) - if(!user.check_space_footing()) - step(user, direction) - else - return ..() +//Template types +/obj/item/chems/spray/extinguisher/empty/populate_reagents() return -/obj/item/extinguisher/proc/do_spray(var/atom/Target) - var/turf/T = get_turf(Target) - var/per_particle = min(spray_amount, reagents.total_volume)/spray_particles - for(var/a = 1 to spray_particles) - if(!src || !reagents.total_volume) return - - var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(src)) - W.create_reagents(per_particle) - reagents.trans_to_obj(W, per_particle) - W.set_color() - W.set_up(T) \ No newline at end of file +/obj/item/chems/spray/extinguisher/mini/empty/populate_reagents() + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/flame.dm b/code/game/objects/items/weapons/flame.dm deleted file mode 100644 index ebf446340939..000000000000 --- a/code/game/objects/items/weapons/flame.dm +++ /dev/null @@ -1,78 +0,0 @@ -//For anything that can light stuff on fire -/obj/item/flame - var/lit_heat = 1000 - var/waterproof = FALSE - var/lit = 0 - -/obj/item/flame/afterattack(var/obj/O, var/mob/user, proximity) - ..() - if(proximity && lit && istype(O)) - O.HandleObjectHeating(src, user, 700) - -/obj/item/flame/proc/extinguish(var/mob/user, var/no_message) - lit = 0 - damtype = "brute" - STOP_PROCESSING(SSobj, src) - -/obj/item/flame/fluid_act(var/datum/reagents/fluids) - ..() - if(!waterproof && lit) - extinguish(no_message = TRUE) - -/obj/item/flame/get_heat() - . = max(..(), lit ? lit_heat : 0) - -/obj/item/flame/isflamesource() - . = lit - -/////////// -//MATCHES// -/////////// -/obj/item/flame/match - name = "match" - desc = "A simple match stick, used for lighting fine smokables." - icon = 'icons/obj/items/storage/matches/match.dmi' - icon_state = ICON_STATE_WORLD - var/burnt = 0 - var/smoketime = 5 - w_class = ITEM_SIZE_TINY - origin_tech = "{'materials':1}" - slot_flags = SLOT_EARS - attack_verb = list("burnt", "singed") - randpixel = 10 - -/obj/item/flame/match/Process() - if(isliving(loc)) - var/mob/living/M = loc - M.IgniteMob() - var/turf/location = get_turf(src) - smoketime-- - if(submerged() || smoketime < 1) - extinguish() - return - if(location) - location.hotspot_expose(700, 5) - -/obj/item/flame/match/dropped(var/mob/user) - //If dropped, put ourselves out - //not before lighting up the turf we land on, though. - if(lit) - var/turf/location = src.loc - if(istype(location)) - location.hotspot_expose(700, 5) - extinguish() - return ..() - -/obj/item/flame/match/extinguish(var/mob/user, var/no_message) - . = ..() - name = "burnt match" - desc = "A match. This one has seen better days." - burnt = 1 - update_icon() - -/obj/item/flame/match/on_update_icon() - ..() - if(burnt) - icon_state = "[get_world_inventory_state()]_burnt" - else if(lit) - icon_state = "[get_world_inventory_state()]_lit" \ No newline at end of file diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index dd17be01ea1d..f50b680ff129 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -2,208 +2,308 @@ name = "flamethrower" desc = "You are a firestarter!" icon = 'icons/obj/flamethrower.dmi' - icon_state = "flamethrowerbase" + icon_state = "flamethrower_base" item_state = "flamethrower_0" obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 3.0 - throwforce = 10.0 throw_speed = 1 throw_range = 5 w_class = ITEM_SIZE_LARGE - origin_tech = "{'combat':1}" + origin_tech = @'{"combat":1}' material = /decl/material/solid/metal/steel - var/status = 0 + _base_attack_force = 3 + + var/fire_sound + /// Whether we have an igniter secured (screwdrivered) to us or not + var/secured = FALSE var/throw_amount = 100 - var/lit = 0 //on or off - var/operating = 0//cooldown - var/turf/previousturf = null - var/obj/item/weldingtool/weldtool = null + /// on or off + var/lit = FALSE + /// cooldown + var/operating = FALSE + var/turf/previous_turf = null + var/obj/item/weldingtool/welding_tool = null var/obj/item/assembly/igniter/igniter = null var/obj/item/tank/tank = null +/obj/item/flamethrower/Initialize(ml, material_key, welder) + . = ..() + if(welder) + welding_tool = welder + welding_tool.forceMove(src) + + update_icon() + +/obj/item/flamethrower/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + if(tank) + . += SPAN_NOTICE("Release pressure is set to [throw_amount] kPa. The tank has about [round(tank.air_contents.return_pressure(), 10)] kPa left in it.") + else + . += SPAN_WARNING("It has no tank installed.") + if(igniter) + . += SPAN_NOTICE("It has \an [igniter] installed.") + else + . += SPAN_WARNING("It has no igniter installed.") /obj/item/flamethrower/Destroy() - QDEL_NULL(weldtool) + QDEL_NULL(welding_tool) QDEL_NULL(igniter) QDEL_NULL(tank) - . = ..() + return ..() /obj/item/flamethrower/Process() if(!lit) - STOP_PROCESSING(SSobj, src) + STOP_PROCESSING(SSprocessing, src) return null + var/turf/location = loc - if(istype(location, /mob/)) + if(ismob(location)) var/mob/M = location - if(M.l_hand == src || M.r_hand == src) + if(M.get_active_held_item() == src) location = M.loc + if(isturf(location)) //start a fire if possible location.hotspot_expose(700, 2) - return - /obj/item/flamethrower/on_update_icon() - overlays.Cut() + . = ..() + add_overlay("_[initial(welding_tool.icon_state)]") + if(igniter) - overlays += "+igniter[status]" + add_overlay("igniter_[secured]") + if(tank) - if(istype(tank, /obj/item/tank/hydrogen)) - overlays += "+htank" - else - overlays += "+ptank" + add_overlay(mutable_appearance(icon, istype(tank, /obj/item/tank/hydrogen)? "tank_hydrogen" : "tank", tank.color)) + if(lit) - overlays += "+lit" - item_state = "flamethrower_1" + add_overlay("lit") + set_light(1.4, 2) else - item_state = "flamethrower_0" - return + set_light(0) /obj/item/flamethrower/afterattack(atom/target, mob/user, proximity) + if(proximity) + return + + if(!tank) + return + + if(tank.air_contents?.get_by_flag(XGM_GAS_FUEL) < 1) + to_chat(user, SPAN_WARNING("\The [src] doesn't have enough fuel left to throw!")) + return + // Make sure our user is still holding us - if(user && user.get_active_hand() == src) - if(user.a_intent == I_HELP) //don't shoot if we're on help intent - to_chat(user, "You refrain from firing \the [src] as your intent is set to help.") + if(user && user.get_active_held_item() == src) + if(user.check_intent(I_FLAG_HELP)) //don't shoot if we're on help intent + to_chat(user, SPAN_WARNING("You refrain from firing \the [src] as your intent is set to help.")) return + var/turf/target_turf = get_turf(target) if(target_turf) var/turflist = getline(user, target_turf) flame_turf(turflist) -/obj/item/flamethrower/attackby(obj/item/W, mob/user) - if(user.stat || user.restrained() || user.lying) return - if(isWrench(W) && !status)//Taking this apart - if(weldtool) - weldtool.dropInto(loc) - weldtool = null +/obj/item/flamethrower/isflamesource() + return lit + +/obj/item/flamethrower/attackby(obj/item/used_item, mob/user) + if(user.incapacitated()) + return TRUE + + if(IS_WRENCH(used_item) && !secured)//Taking this apart + var/turf/T = get_turf(src) + if(welding_tool) + welding_tool.dropInto(T) + welding_tool = null + if(igniter) - igniter.dropInto(loc) + igniter.dropInto(T) igniter = null + if(tank) - tank.dropInto(loc) + tank.dropInto(T) tank = null - new /obj/item/stack/material/rods(get_turf(src)) + + SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(src), 1, /obj/item/stack/material/rods) qdel(src) - return + return TRUE - if(isScrewdriver(W) && igniter && !lit) - status = !status - to_chat(user, "[igniter] is now [status ? "secured" : "unsecured"]!") + if(IS_SCREWDRIVER(used_item) && igniter && !lit) + secured = !secured + to_chat(user, SPAN_NOTICE("\The [igniter] is now [secured ? "secured" : "unsecured"]!")) update_icon() - return + return TRUE - if(isigniter(W)) - var/obj/item/assembly/igniter/I = W - if(I.secured) return - if(igniter) return - if(!user.unEquip(I, src)) - return + if(isigniter(used_item)) + var/obj/item/assembly/igniter/I = used_item + if(I.secured) + to_chat(user, SPAN_WARNING("\The [I] is not ready to attach yet! Use a screwdriver on it first.")) + return TRUE + + if(igniter) + to_chat(user, SPAN_WARNING("\The [src] already has an igniter installed.")) + return TRUE + + user.drop_from_inventory(I, src) igniter = I update_icon() - return + return TRUE - if(istype(W,/obj/item/tank)) + if(istype(used_item, /obj/item/tank)) if(tank) - to_chat(user, "There appears to already be a fuel tank loaded in [src]!") - return - if(!user.unEquip(W, src)) - return - tank = W + to_chat(user, SPAN_WARNING("There appears to already be a tank loaded in \the [src]!")) + return TRUE + + user.drop_from_inventory(used_item, src) + tank = used_item update_icon() - return + return TRUE - if(istype(W, /obj/item/scanner/gas)) - var/obj/item/scanner/gas/A = W + if(istype(used_item, /obj/item/scanner/gas)) + var/obj/item/scanner/gas/A = used_item A.analyze_gases(src, user) - return - ..() - return + return TRUE + + if(used_item.isflamesource()) // you can light it with external input, even without an igniter + attempt_lighting(user, TRUE) + update_icon() + return TRUE + + . = ..() /obj/item/flamethrower/attack_self(mob/user) - if(user.stat || user.restrained() || user.lying) return - user.set_machine(src) + if(user.incapacitated()) + return + if(!tank) - to_chat(user, "Attach a fuel tank first!") + to_chat(user, SPAN_WARNING("Attach a fuel tank first!")) + return + + var/list/options = list( + "Eject Tank" = mutable_appearance('icons/obj/items/tanks/tank_greyscaled.dmi', "world", tank.color), + "Light" = mutable_appearance('icons/effects/effects.dmi', "fire_goon"), + "Lower Pressure" = mutable_appearance('icons/screen/radial.dmi', "radial_sub"), + "Raise Pressure" = mutable_appearance('icons/screen/radial.dmi', "radial_add") + ) + + var/handle = show_radial_menu(user, user, options, require_near = TRUE, radius = 42, tooltips = TRUE, check_locs = list(src)) + if(!handle || user.get_active_held_item() != src) return - var/dat = text("Flamethrower ([lit ? "Lit" : "Unlit"])
              \n Tank Pressure: [tank.air_contents.return_pressure()]
              \nAmount to throw: - - - [throw_amount] + + +
              \nRemove fuel tank - Close
              ") - show_browser(user, dat, "window=flamethrower;size=600x300") - onclose(user, "flamethrower") - return + + switch(handle) + if("Eject Tank") + if(!tank) + return + + user.put_in_hands(tank) + tank = null + lit = FALSE + update_icon() + + if("Light") + attempt_lighting(user) + + if("Lower Pressure") + change_pressure(-50, user) + + if("Raise Pressure") + change_pressure(50, user) + else + return /obj/item/flamethrower/return_air() - if(tank) - return tank.return_air() + return tank?.return_air() -/obj/item/flamethrower/Topic(href,href_list[]) - if(href_list["close"]) - usr.unset_machine() - close_browser(usr, "window=flamethrower") +/obj/item/flamethrower/proc/attempt_lighting(var/mob/user, var/external) + if(!external) // if it's external input, we can't unlight it, but we don't need to check for an igniter either + if(lit) // you can extinguish the flamethrower without an igniter + lit = FALSE + to_chat(user, SPAN_NOTICE("You extinguish \the [src].")) + update_icon() + return + + if(!secured) // can't light via the flamethrower unless we have an igniter secured + if(igniter) + to_chat(user, SPAN_WARNING("\The [igniter] isn't secured, you need to use a screwdriver on it first.")) + else + to_chat(user, SPAN_WARNING("\The [src] doesn't have a secured igniter installed.")) + return + + if(lit) + to_chat(user, SPAN_WARNING("\The [src] is already lit.")) return - if(usr.stat || usr.restrained() || usr.lying) return - usr.set_machine(src) - if(href_list["light"]) - if(!tank) return - if(tank.air_contents.get_by_flag(XGM_GAS_FUEL) < 1) return - if(!status) return - lit = !lit - if(lit) - START_PROCESSING(SSobj, src) - if(href_list["amount"]) - throw_amount = throw_amount + text2num(href_list["amount"]) - throw_amount = max(50, min(5000, throw_amount)) - if(href_list["remove"]) - if(!tank) return - usr.put_in_hands(tank) - tank = null - lit = 0 - usr.unset_machine() - close_browser(usr, "window=flamethrower") - for(var/mob/M in viewers(1, loc)) - if((M.client && M.machine == src)) - attack_self(M) + + if(!tank) + to_chat(user, SPAN_WARNING("\The [src] doesn't have a tank installed.")) + return + + if(tank.air_contents?.get_by_flag(XGM_GAS_FUEL) < 1) + to_chat(user, SPAN_WARNING("\The [src] doesn't have any flammable fuel to light!")) + return + + lit = TRUE + to_chat(user, SPAN_NOTICE("You light \the [src].")) update_icon() - return + if(lit) + START_PROCESSING(SSprocessing, src) + +/obj/item/flamethrower/proc/change_pressure(var/pressure, var/mob/user) + if(!pressure) + return + + throw_amount += pressure + throw_amount = clamp(50, throw_amount, 5000) + + if(ismob(user)) + to_chat(user, SPAN_NOTICE("Pressure has been adjusted to [throw_amount] kPa.")) + + update_icon() //Called from turf.dm turf/dblclick /obj/item/flamethrower/proc/flame_turf(turflist) - if(!lit || operating) return - operating = 1 + if(!lit || operating) + return + + operating = TRUE + + if(fire_sound) + playsound(src, fire_sound, 70, 1) + for(var/turf/T in turflist) - if(T.density || istype(T, /turf/space)) + if(T.density || isspaceturf(T)) break - if(!previousturf && length(turflist)>1) - previousturf = get_turf(src) + + if(!previous_turf && length(turflist)>1) + previous_turf = get_turf(src) continue //so we don't burn the tile we be standin on - if(previousturf && LinkBlocked(previousturf, T)) + + if(previous_turf && LinkBlocked(previous_turf, T)) break + ignite_turf(T) sleep(1) - previousturf = null - operating = 0 - for(var/mob/M in viewers(1, loc)) - if((M.client && M.machine == src)) - attack_self(M) + + previous_turf = null + operating = FALSE /obj/item/flamethrower/proc/ignite_turf(turf/target) - //TODO: DEFERRED Consider checking to make sure tank pressure is high enough before doing this... - //Transfer 5% of current tank air contents to turf - var/datum/gas_mixture/air_transfer = tank.remove_air_ratio(0.02*(throw_amount/100)) - var/obj/effect/fluid/F = locate() in target - if(!F) F = new(target) - F.reagents.add_reagent(/decl/material/liquid/fuel, air_transfer.get_by_flag(XGM_GAS_FUEL)) + var/datum/gas_mixture/air_transfer = tank.air_contents.remove_ratio(0.02 * (throw_amount / 100)) + target.add_to_reagents(/decl/material/liquid/fuel, air_transfer.get_by_flag(XGM_GAS_FUEL) * REAGENT_UNITS_PER_GAS_MOLE * 2) air_transfer.remove_by_flag(XGM_GAS_FUEL, 0) target.assume_air(air_transfer) - //Burn it based on transfered gas - //target.hotspot_expose(part4.air_contents.temperature*2,300) - target.hotspot_expose((tank.air_contents.temperature*2) + 380,500) // -- More of my "how do I shot fire?" dickery. -- TLE - //location.hotspot_expose(1000,500,1) + target.create_fire(tank.air_contents.temperature * 2 + 400) + target.hotspot_expose(1000, 100) + for(var/mob/living/M in target) + M.ignite_fire() +// slightly weird looking initialize cuz it has to do some stuff first /obj/item/flamethrower/full/Initialize() - . = ..() - weldtool = new /obj/item/weldingtool(src) - weldtool.status = 0 + welding_tool = new /obj/item/weldingtool(src) + welding_tool.status = FALSE igniter = new /obj/item/assembly/igniter(src) - igniter.secured = 0 - status = 1 - update_icon() + igniter.secured = FALSE + secured = TRUE + tank = new /obj/item/tank/hydrogen(src) + return ..() diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm index 77361c5b3dc8..331c51c130ee 100644 --- a/code/game/objects/items/weapons/gift_wrappaper.dm +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -9,11 +9,12 @@ */ /obj/item/a_gift name = "gift" - desc = "PRESENTS!!!! eek!" + desc = "PRESENTS!!!! Eek!" icon = 'icons/obj/items/gift_wrapped.dmi' - icon_state = "gift1" - item_state = "gift1" + icon_state = "gift" + item_state = "gift" randpixel = 10 + material = /decl/material/solid/organic/cardboard /obj/item/a_gift/Initialize() . = ..() @@ -27,17 +28,17 @@ if(!QDELETED(src)) qdel(src) +// this can't be made, should it just be removed? +// should it be made into a subtype of closet? of living statue? /obj/effect/spresent/relaymove(mob/user) if (user.stat) return to_chat(user, "You can't move.") -/obj/effect/spresent/attackby(obj/item/W, mob/user) - ..() - - if(!isWirecutter(W)) +/obj/effect/spresent/attackby(obj/item/used_item, mob/user) + if(!IS_WIRECUTTER(used_item)) to_chat(user, "I need wirecutters for that.") - return + return TRUE to_chat(user, "You cut open the present.") @@ -48,29 +49,31 @@ M.client.perspective = MOB_PERSPECTIVE qdel(src) + return TRUE /obj/item/a_gift/attack_self(mob/M) var/gift_type = pick( - /obj/item/storage/wallet, - /obj/item/storage/photo_album, - /obj/item/storage/box/snappops, - /obj/item/storage/fancy/crayons, - /obj/item/storage/backpack/holding, - /obj/item/storage/belt/champion, - /obj/item/pickaxe/silver, + /obj/item/wallet, + /obj/item/photo_album, + /obj/item/box/snappops, + /obj/item/box/fancy/crayons, + /obj/item/backpack/holding, + /obj/item/belt/champion, + /obj/item/tool/pickaxe/titanium, /obj/item/pen/invisible, - /obj/random/lipstick, + /obj/random/makeup, /obj/item/grenade/smokebomb, /obj/item/corncob, - /obj/item/contraband/poster, + /obj/item/poster, /obj/item/book/manual/barman_recipes, /obj/item/book/manual/chef_recipes, /obj/item/bikehorn, - /obj/item/beach_ball, - /obj/item/beach_ball/holoball, - /obj/item/toy/water_balloon, + /obj/item/ball, + /obj/item/ball/basketball, + /obj/item/ball/volleyball, + /obj/item/chems/water_balloon, /obj/item/toy/blink, - /obj/item/toy/crossbow, + /obj/item/gun/launcher/foam/crossbow, /obj/item/gun/projectile/revolver/capgun, /obj/item/sword/katana/toy, /obj/item/toy/prize/deathripley, @@ -85,16 +88,16 @@ /obj/item/toy/prize/powerloader, /obj/item/toy/prize/seraph, /obj/item/toy/spinningtoy, - /obj/item/toy/sword, - /obj/item/chems/food/snacks/grown/ambrosiadeus, - /obj/item/chems/food/snacks/grown/ambrosiavulgaris, + /obj/item/energy_blade/sword/toy, + /obj/item/food/grown/ambrosiadeus, + /obj/item/food/grown/ambrosiavulgaris, /obj/item/paicard, /obj/item/synthesized_instrument/violin, - /obj/item/storage/belt/utility/full, - /obj/item/clothing/accessory/horrible, - /obj/item/storage/box/large/foam_gun, - /obj/item/storage/box/large/foam_gun/burst, - /obj/item/storage/box/large/foam_gun/revolver) + /obj/item/belt/utility/full, + /obj/item/clothing/neck/tie/horrible, + /obj/item/box/large/foam_gun, + /obj/item/box/large/foam_gun/burst, + /obj/item/box/large/foam_gun/revolver) if(!ispath(gift_type,/obj/item)) return @@ -103,109 +106,3 @@ I.add_fingerprint(M) qdel(src) -/* - * Wrapping Paper and Gifts - */ - -/obj/item/gift - name = "gift" - desc = "A wrapped item." - icon = 'icons/obj/items/gift_wrapped.dmi' - icon_state = "gift3" - var/size = 3.0 - var/obj/item/gift = null - item_state = "gift" - w_class = ITEM_SIZE_HUGE - -/obj/item/gift/Initialize(mapload, obj/item/wrapped = null) - . = ..(mapload) - - if(istype(wrapped)) - gift = wrapped - w_class = gift.w_class - gift.forceMove(src) - - switch(gift.w_class) - if(ITEM_SIZE_TINY, ITEM_SIZE_SMALL) - icon_state = "gift1" - if(ITEM_SIZE_NORMAL, ITEM_SIZE_LARGE) - icon_state = "gift2" - else - icon_state = "gift3" - -/obj/item/gift/attack_self(mob/user) - user.drop_item() - if(src.gift) - user.put_in_active_hand(gift) - src.gift.add_fingerprint(user) - else - to_chat(user, "The gift was empty!") - qdel(src) - return - -/obj/item/wrapping_paper - name = "wrapping paper" - desc = "You can use this to wrap items in." - icon = 'icons/obj/items/gift_wrapper.dmi' - icon_state = "wrap_paper" - var/amount = 2.5*BASE_STORAGE_COST(ITEM_SIZE_HUGE) - -/obj/item/wrapping_paper/attackby(obj/item/W, mob/user) - ..() - if (!( locate(/obj/structure/table, src.loc) )) - to_chat(user, "You MUST put the paper on a table!") - if (W.w_class < ITEM_SIZE_HUGE) - if(isWirecutter(user.l_hand) || isWirecutter(user.r_hand)) - var/a_used = W.get_storage_cost() - if (a_used >= ITEM_SIZE_NO_CONTAINER) - to_chat(user, "You can't wrap that!")//no gift-wrapping lit welders - return - if (src.amount < a_used) - to_chat(user, "You need more paper!") - return - else - if(istype(W, /obj/item/smallDelivery) || istype(W, /obj/item/gift)) //No gift wrapping gifts! - return - - if(user.unEquip(W)) - var/obj/item/gift/G = new /obj/item/gift( src.loc, W ) - G.add_fingerprint(user) - W.add_fingerprint(user) - src.amount -= a_used - - if (src.amount <= 0) - new /obj/item/c_tube( src.loc ) - qdel(src) - return - else - to_chat(user, "You need scissors!") - else - to_chat(user, "The object is FAR too large!") - return - - -/obj/item/wrapping_paper/examine(mob/user, distance) - . = ..() - if(distance <= 1) - to_chat(user, text("There is about [] square units of paper left!", src.amount)) - -/obj/item/wrapping_paper/attack(mob/target, mob/user) - if (!istype(target, /mob/living/carbon/human)) return - var/mob/living/carbon/human/H = target - - if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket) || H.stat) - if (src.amount > 2) - var/obj/effect/spresent/present = new /obj/effect/spresent (H.loc) - src.amount -= 2 - - if (H.client) - H.client.perspective = EYE_PERSPECTIVE - H.client.eye = present - - H.forceMove(present) - admin_attack_log(user, H, "Used \a [src] to wrap their victim", "Was wrapepd with \a [src]", "used \the [src] to wrap") - - else - to_chat(user, "You need more paper.") - else - to_chat(user, "They are moving around too much. A straightjacket would help.") diff --git a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm index 1b377b9bcc39..19054df59bde 100644 --- a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm +++ b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm @@ -1,24 +1,21 @@ /obj/item/grenade/anti_photon desc = "An experimental device for temporarily removing light in a limited area." name = "photon disruption grenade" - icon = 'icons/obj/grenade.dmi' - icon_state = "emp" - item_state = "emp" + icon = 'icons/obj/items/grenades/grenade_light.dmi' det_time = 20 - origin_tech = "{'wormholes':4,'materials':4}" + origin_tech = @'{"wormholes":4,"materials":4}' material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) /obj/item/grenade/anti_photon/detonate() playsound(src.loc, 'sound/effects/phasein.ogg', 50, 1, 5) - set_light(-1, 6, 10, 2, "#ffffff") - addtimer(CALLBACK(src, .proc/finish), rand(20 SECONDS, 29 SECONDS)) + set_light(10, -10, "#ffffff") + addtimer(CALLBACK(src, PROC_REF(finish)), rand(20 SECONDS, 29 SECONDS)) /obj/item/grenade/anti_photon/proc/finish() - set_light(1, 1, 10, 2, "#[num2hex(rand(64,255))][num2hex(rand(64,255))][num2hex(rand(64,255))]") + set_light(10, 10, rgb(rand(64,255), rand(64,255), rand(64,255))) playsound(loc, 'sound/effects/bang.ogg', 50, 1, 5) - sleep(1 SECOND) - qdel(src) \ No newline at end of file + QDEL_IN(src, 1 SECOND) \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 9dd2e6b50597..2b69b2c9e4a3 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -1,66 +1,68 @@ /obj/item/grenade/chem_grenade name = "grenade casing" - icon_state = "chemg" - item_state = "grenade" + icon = 'icons/obj/items/grenades/grenade_chem.dmi' desc = "A hand made chemical grenade." w_class = ITEM_SIZE_SMALL - force = 2.0 + _base_attack_force = 2.0 det_time = null - unacidable = 1 + chem_volume = 1000 + var/stage = 0 - var/state = 0 var/path = 0 var/obj/item/assembly_holder/detonator = null var/list/beakers = new/list() var/list/allowed_containers = list(/obj/item/chems/glass/beaker, /obj/item/chems/glass/bottle) - var/affected_area = 3 -/obj/item/grenade/chem_grenade/Initialize() +/obj/item/grenade/chem_grenade/Destroy() + QDEL_NULL(detonator) + QDEL_NULL_LIST(beakers) . = ..() - create_reagents(1000) + +/obj/item/grenade/chem_grenade/reaction_can_overflow(decl/chemical_reaction/reaction) + return TRUE // will always overflow despite not being open /obj/item/grenade/chem_grenade/attack_self(mob/user) if(!stage || stage==1) if(detonator) -// detonator.loc=src.loc detonator.detached() usr.put_in_hands(detonator) detonator=null det_time = null stage=0 - icon_state = initial(icon_state) else if(beakers.len) for(var/obj/B in beakers) if(istype(B)) beakers -= B user.put_in_hands(B) SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") + update_icon() if(stage > 1 && !active && clown_check(user)) to_chat(user, "You prime \the [name]!") - - log_and_message_admins("has primed \a [src].") - - activate() + activate(user) add_fingerprint(user) - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.throw_mode_on() + user.toggle_throw_mode(TRUE) -/obj/item/grenade/chem_grenade/attackby(obj/item/W, mob/user) +/obj/item/grenade/chem_grenade/on_update_icon() + . = ..() + if(detonator) + add_overlay("[icon_state]-assembled") + if(path == 1) + add_overlay("[icon_state]-locked") - if(istype(W,/obj/item/assembly_holder) && (!stage || stage==1) && path != 2) - var/obj/item/assembly_holder/det = W +/obj/item/grenade/chem_grenade/attackby(obj/item/used_item, mob/user) + if(istype(used_item,/obj/item/assembly_holder) && (!stage || stage==1) && path != 2) + var/obj/item/assembly_holder/det = used_item if(istype(det.a_left,det.a_right.type) || (!isigniter(det.a_left) && !isigniter(det.a_right))) to_chat(user, "Assembly must contain one igniter.") - return + return TRUE if(!det.secured) to_chat(user, "Assembly must be secured with screwdriver.") - return - if(!user.unEquip(det, src)) - return + return TRUE + if(!user.try_unequip(det, src)) + return TRUE path = 1 - log_and_message_admins("has attached \a [W] to \the [src].") - to_chat(user, "You add [W] to the metal casing.") + log_and_message_admins("has attached \a [used_item] to \the [src].") + to_chat(user, "You add [used_item] to the metal casing.") playsound(src.loc, 'sound/items/Screwdriver2.ogg', 25, -3) detonator = det if(istimer(detonator.a_left)) @@ -69,84 +71,82 @@ if(istimer(detonator.a_right)) var/obj/item/assembly/timer/T = detonator.a_right det_time = 10*T.time - icon_state = initial(icon_state) +"_ass" SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") stage = 1 - else if(isScrewdriver(W) && path != 2) + . = TRUE + else if(IS_SCREWDRIVER(used_item) && path != 2) if(stage == 1) path = 1 if(beakers.len) to_chat(user, "You lock the assembly.") SetName("grenade") else -// to_chat(user, "You need to add at least one beaker before locking the assembly.") to_chat(user, "You lock the empty assembly.") SetName("fake grenade") playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, -3) - icon_state = initial(icon_state) +"_locked" stage = 2 + . = TRUE else if(stage == 2) if(active && prob(95)) to_chat(user, "You trigger the assembly!") detonate() - return + return TRUE else to_chat(user, "You unlock the assembly.") playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, -3) SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") - icon_state = initial(icon_state) + (detonator?"_ass":"") stage = 1 - active = 0 - else if(is_type_in_list(W, allowed_containers) && (!stage || stage==1) && path != 2) + active = FALSE + . = TRUE + else if(is_type_in_list(used_item, allowed_containers) && (!stage || stage==1) && path != 2) path = 1 if(beakers.len == 2) to_chat(user, "The grenade can not hold more containers.") - return + return TRUE else - if(W.reagents.total_volume) - if(!user.unEquip(W, src)) - return - to_chat(user, "You add \the [W] to the assembly.") - beakers += W + if(REAGENT_TOTAL_VOLUME(used_item.reagents)) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, "You add \the [used_item] to the assembly.") + beakers += used_item stage = 1 SetName("unsecured grenade with [beakers.len] containers[detonator?" and detonator":""]") + . = TRUE else - to_chat(user, "\The [W] is empty.") + to_chat(user, "\The [used_item] is empty.") + return TRUE + if(.) + update_icon() + return TRUE + return ..() /obj/item/grenade/chem_grenade/activate(mob/user) - if(active) return - + if(active) + return if(detonator) if(!isigniter(detonator.a_left)) detonator.a_left.activate() - active = 1 + active = TRUE if(!isigniter(detonator.a_right)) detonator.a_right.activate() - active = 1 - if(active) - icon_state = initial(icon_state) + "_active" - - if(user) - log_and_message_admins("has primed \a [src].") - -/obj/item/grenade/chem_grenade/proc/primed(var/primed = 1) - if(active) - icon_state = initial(icon_state) + (primed?"_primed":"_active") + active = TRUE + update_icon() + if(active && user) + log_and_message_admins("has primed \a [src].") /obj/item/grenade/chem_grenade/detonate() set waitfor = 0 - if(!stage || stage < 2) + if(!stage || stage < 2) return var/has_reagents = 0 for(var/obj/item/chems/glass/G in beakers) - if(G.reagents.total_volume) + if(REAGENT_TOTAL_VOLUME(G.reagents)) has_reagents = TRUE break - active = 0 + active = FALSE if(!has_reagents) - icon_state = initial(icon_state) +"_locked" playsound(src.loc, 'sound/items/Screwdriver2.ogg', 50, 1) spawn(0) //Otherwise det_time is erroneously set to 0 after this if(istimer(detonator.a_left)) //Make sure description reflects that the timer has been reset @@ -155,22 +155,23 @@ if(istimer(detonator.a_right)) var/obj/item/assembly/timer/T = detonator.a_right det_time = 10*T.time + update_icon() return playsound(src.loc, 'sound/effects/bamf.ogg', 50, 1) if(ismob(loc)) var/mob/M = loc M.drop_from_inventory(src) - M.throw_mode_off() + M.toggle_throw_mode(FALSE) for(var/obj/item/chems/glass/G in beakers) - G.reagents.trans_to_obj(src, G.reagents.total_volume) + G.reagents.trans_to_obj(src, REAGENT_TOTAL_VOLUME(G.reagents)) anchored = TRUE set_invisibility(INVISIBILITY_MAXIMUM) // Visual effect to show the grenade going off. - if(reagents.total_volume) + if(REAGENT_TOTAL_VOLUME(reagents)) var/datum/effect/effect/system/steam_spread/steam = new steam.set_up(10, 0, get_turf(src)) steam.attach(src) @@ -179,28 +180,28 @@ // Allow time for reactions to proc. var/max_delays = 5 var/delays = 0 - while(reagents.total_volume && delays <= max_delays) + while(REAGENT_TOTAL_VOLUME(reagents) && delays <= max_delays) delays++ sleep(SSmaterials.wait) // The reactions didn't use up all reagents, dump them as a fluid. - if(reagents.total_volume) - reagents.trans_to(loc, reagents.total_volume) + var/reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if(reagent_volume) + reagents.trans_to(loc, reagent_volume) qdel(src) -/obj/item/grenade/chem_grenade/examine(mob/user) +/obj/item/grenade/chem_grenade/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(detonator) - to_chat(user, "With attached [detonator.name]") + . += "It has \a [detonator] attached." /obj/item/grenade/chem_grenade/large name = "large chem grenade" desc = "An oversized grenade that affects a larger area." - icon_state = "large_grenade" + icon = 'icons/obj/items/grenades/grenade_large.dmi' allowed_containers = list(/obj/item/chems/glass) - origin_tech = "{'combat':3,'materials':3}" - affected_area = 4 + origin_tech = @'{"combat":3,"materials":3}' material = /decl/material/solid/metal/steel /obj/item/grenade/chem_grenade/metalfoam @@ -213,16 +214,13 @@ . = ..() var/obj/item/chems/glass/beaker/B1 = new(src) var/obj/item/chems/glass/beaker/B2 = new(src) - - B1.reagents.add_reagent(/decl/material/solid/metal/aluminium, 30) - B2.reagents.add_reagent(/decl/material/liquid/foaming_agent, 10) - B2.reagents.add_reagent(/decl/material/liquid/acid/polyacid, 10) - + B1.add_to_reagents(/decl/material/solid/metal/aluminium, 30) + B2.add_to_reagents(/decl/material/liquid/foaming_agent, 10) + B2.add_to_reagents(/decl/material/liquid/acid, 10) detonator = new/obj/item/assembly_holder/timer_igniter(src) - beakers += B1 beakers += B2 - icon_state = initial(icon_state) +"_locked" + update_icon() /obj/item/grenade/chem_grenade/incendiary name = "incendiary grenade" @@ -234,17 +232,14 @@ . = ..() var/obj/item/chems/glass/beaker/B1 = new(src) var/obj/item/chems/glass/beaker/B2 = new(src) - - B1.reagents.add_reagent(/decl/material/solid/metal/aluminium, 15) - B1.reagents.add_reagent(/decl/material/liquid/fuel, 15) - B2.reagents.add_reagent(/decl/material/solid/metal/aluminium, 15) - B2.reagents.add_reagent(/decl/material/liquid/acid, 15) - + B1.add_to_reagents(/decl/material/solid/metal/aluminium, 15) + B1.add_to_reagents(/decl/material/liquid/fuel, 15) + B2.add_to_reagents(/decl/material/solid/metal/aluminium, 15) + B2.add_to_reagents(/decl/material/liquid/acid, 15) detonator = new/obj/item/assembly_holder/timer_igniter(src) - beakers += B1 beakers += B2 - icon_state = initial(icon_state) +"_locked" + update_icon() /obj/item/grenade/chem_grenade/antiweed name = "weedkiller grenade" @@ -254,20 +249,16 @@ /obj/item/grenade/chem_grenade/antiweed/Initialize() . = ..() - var/obj/item/chems/glass/beaker/B1 = new(src) var/obj/item/chems/glass/beaker/B2 = new(src) - - B1.reagents.add_reagent(/decl/material/liquid/weedkiller, 25) - B1.reagents.add_reagent(/decl/material/solid/potassium, 25) - B2.reagents.add_reagent(/decl/material/solid/phosphorus, 25) - B2.reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 25) - + B1.add_to_reagents(/decl/material/liquid/weedkiller, 25) + B1.add_to_reagents(/decl/material/solid/potassium, 25) + B2.add_to_reagents(/decl/material/solid/phosphorus, 25) + B2.add_to_reagents(/decl/material/liquid/nutriment/sugar, 25) detonator = new/obj/item/assembly_holder/timer_igniter(src) - beakers += B1 beakers += B2 - icon_state = "grenade" + update_icon() /obj/item/grenade/chem_grenade/cleaner name = "cleaner grenade" @@ -279,16 +270,13 @@ . = ..() var/obj/item/chems/glass/beaker/B1 = new(src) var/obj/item/chems/glass/beaker/B2 = new(src) - - B1.reagents.add_reagent(/decl/material/liquid/surfactant, 40) - B2.reagents.add_reagent(/decl/material/liquid/water, 40) - B2.reagents.add_reagent(/decl/material/liquid/cleaner, 10) - + B1.add_to_reagents(/decl/material/liquid/surfactant, 40) + B2.add_to_reagents(/decl/material/liquid/water, 40) + B2.add_to_reagents(/decl/material/liquid/cleaner, 10) detonator = new/obj/item/assembly_holder/timer_igniter(src) - beakers += B1 beakers += B2 - icon_state = initial(icon_state) +"_locked" + update_icon() /obj/item/grenade/chem_grenade/teargas name = "tear gas grenade" @@ -300,24 +288,20 @@ . = ..() var/obj/item/chems/glass/beaker/large/B1 = new(src) var/obj/item/chems/glass/beaker/large/B2 = new(src) - - B1.reagents.add_reagent(/decl/material/solid/phosphorus, 40) - B1.reagents.add_reagent(/decl/material/solid/potassium, 40) - B1.reagents.add_reagent(/decl/material/liquid/capsaicin/condensed, 40) - B2.reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 40) - B2.reagents.add_reagent(/decl/material/liquid/capsaicin/condensed, 80) - + B1.add_to_reagents(/decl/material/solid/phosphorus, 40) + B1.add_to_reagents(/decl/material/solid/potassium, 40) + B1.add_to_reagents(/decl/material/liquid/capsaicin/condensed, 40) + B2.add_to_reagents(/decl/material/liquid/nutriment/sugar, 40) + B2.add_to_reagents(/decl/material/liquid/capsaicin/condensed, 80) detonator = new/obj/item/assembly_holder/timer_igniter(src) - beakers += B1 beakers += B2 - icon_state = initial(icon_state) +"_locked" + update_icon() /obj/item/grenade/chem_grenade/water name = "water grenade" desc = "A water grenade, generally used for firefighting." - icon_state = "waterg" - item_state = "waterg" + icon = 'icons/obj/items/grenades/grenade_water.dmi' stage = 2 path = 1 @@ -325,13 +309,9 @@ . = ..() var/obj/item/chems/glass/beaker/B1 = new(src) var/obj/item/chems/glass/beaker/B2 = new(src) - - B1.reagents.add_reagent(/decl/material/liquid/water, 40) - B2.reagents.add_reagent(/decl/material/liquid/water, 40) - + B1.add_to_reagents(/decl/material/liquid/water, 40) + B2.add_to_reagents(/decl/material/liquid/water, 40) detonator = new/obj/item/assembly_holder/timer_igniter(src) - beakers += B1 beakers += B2 - icon_state = initial(icon_state) +"_locked" - + update_icon() diff --git a/code/game/objects/items/weapons/grenades/decompiler.dm b/code/game/objects/items/weapons/grenades/decompiler.dm index 14624d4ffe8b..2f1ecc1d35ff 100644 --- a/code/game/objects/items/weapons/grenades/decompiler.dm +++ b/code/game/objects/items/weapons/grenades/decompiler.dm @@ -1,10 +1,8 @@ /obj/item/grenade/decompiler desc = "It is set to detonate in 5 seconds. It will create an unstable singularity that will break nearby objects down into purified matter cubes." name = "decompiler grenade" - icon = 'icons/obj/grenade.dmi' - icon_state = "delivery" - item_state = "flashbang" - origin_tech = "{'materials':3,'magnets':2,'exoticmatter':3}" + icon = 'icons/obj/items/grenades/delivery.dmi' + origin_tech = @'{"materials":3,"magnets":2,"exoticmatter":3}' matter = list( /decl/material/solid/exotic_matter = MATTER_AMOUNT_TRACE ) @@ -28,9 +26,11 @@ var/lifetime = 10 SECONDS var/expiry_time var/list/decompiled_matter - + /obj/effect/decompiler/Initialize() . = ..() + if(!loc) + return INITIALIZE_HINT_QDEL expiry_time = world.time + lifetime START_PROCESSING(SSobj, src) decompiled_matter = list() @@ -39,7 +39,7 @@ /obj/effect/decompiler/proc/fade_in() visible_message(SPAN_DANGER("\A [src] forms, reaching out hungrily!")) playsound(loc, 'sound/magic/ethereal_enter.ogg', 75, FALSE) - set_light(0.8, 0, 4.5, l_color = LIGHT_COLOR_PURPLE) + set_light(4.5, 0.8, LIGHT_COLOR_PURPLE) var/matrix/M = matrix() M.Scale(0.01) transform = M @@ -56,7 +56,7 @@ if(dump_cubes) visible_message(SPAN_DANGER("\The [src] collapses!")) for(var/mat in decompiled_matter) - var/sheet_amount = Floor(decompiled_matter[mat]/SHEET_MATERIAL_AMOUNT) + var/sheet_amount = floor(decompiled_matter[mat]/SHEET_MATERIAL_AMOUNT) if(sheet_amount > 0) while(sheet_amount > 100) var/obj/item/stack/material/cubes/cubes = new (dump_cubes, 100, mat) @@ -82,16 +82,14 @@ playsound(loc, 'sound/magic/lightningshock.ogg', 30, FALSE) var/list/eaten - for(var/eat_turf in RANGE_TURFS(loc, eat_range)) - - var/turf/T = eat_turf - var/list/eating = T.contents?.Copy() + for(var/turf/eat_turf as anything in RANGE_TURFS(loc, eat_range)) + var/list/eating = eat_turf.get_contained_external_atoms() while(length(eating)) var/atom/movable/thing = pick_n_take(eating) - if(QDELETED(thing) || !istype(thing) || !thing.simulated || thing.anchored || prob(15)) + if(QDELETED(thing) || (thing == src) || thing.anchored || prob(15)) continue - + if(prob(30)) if(ismob(thing) && prob(50)) @@ -101,42 +99,30 @@ thing = pick(options) if(ishuman(thing)) - var/mob/living/carbon/human/H = thing - for(var/obj/item/organ/external/limb in H.organs) - if(BP_IS_PROSTHETIC(limb) && !limb.is_stump() && !length(limb.children)) - limb.droplimb() + var/mob/living/human/H = thing + for(var/obj/item/organ/external/limb in H.get_external_organs()) + if(BP_IS_PROSTHETIC(limb) && !length(limb.children)) + limb.dismember() limb.forceMove(src) thing = limb break - - if(isitem(thing)) - var/obj/item/eating_obj = thing - for(var/mat in eating_obj.matter) - decompiled_matter[mat] += eating_obj.matter[mat] + + if(isobj(thing)) + var/obj/eating_obj = thing + // some loose objects fall out and evade getting eaten this time + for(var/obj/recursive_obj in eating_obj.get_contained_external_atoms()) + if(prob(15)) + recursive_obj.dropInto(eating_obj.loc) + else + LAZYADD(eaten, recursive_obj) + // whatever's left is cubified + decompiled_matter = MERGE_ASSOCS_WITH_NUM_VALUES(decompiled_matter, eating_obj.get_contained_matter()) LAZYADD(eaten, eating_obj) if(length(eaten)) - playsound(loc, 'sound/magic/magic_missile.ogg', Clamp(length(eaten) * 10, 10, 50), FALSE) + playsound(loc, 'sound/magic/magic_missile.ogg', clamp(length(eaten) * 10, 10, 50), FALSE) QDEL_NULL_LIST(eaten) /obj/effect/decompiler/Destroy() STOP_PROCESSING(SSobj, src) . = ..() - -/obj/item/stack/material/cubes - name = "cube" - desc = "Some featureless cubes." - singular_name = "cube" - plural_name = "cubes" - icon_state = "cube" - plural_icon_state = "cube-mult" - max_icon_state = "cube-max" - max_amount = 100 - attack_verb = list("cubed") - material_flags = USE_MATERIAL_COLOR | USE_MATERIAL_SINGULAR_NAME - stacktype = /obj/item/stack/material/cubes - -/obj/item/stack/material/cubes/update_strings() - . = ..() - singular_name = initial(singular_name) - plural_name = initial(plural_name) diff --git a/code/game/objects/items/weapons/grenades/emgrenade.dm b/code/game/objects/items/weapons/grenades/emgrenade.dm index 2dbd0666ed39..afac53d72388 100644 --- a/code/game/objects/items/weapons/grenades/emgrenade.dm +++ b/code/game/objects/items/weapons/grenades/emgrenade.dm @@ -1,24 +1,20 @@ /obj/item/grenade/empgrenade - name = "classic emp grenade" - icon_state = "emp" - item_state = "empgrenade" - origin_tech = "{'materials':2,'magnets':3}" + name = "classic EMP grenade" + icon = 'icons/obj/items/grenades/emp.dmi' + origin_tech = @'{"materials":2,"magnets":3}' + var/emp_light_range = 10 + var/emp_heavy_range = 4 - detonate() - ..() - if(empulse(src, 4, 10)) - qdel(src) - return +/obj/item/grenade/empgrenade/detonate() + ..() + if(empulse(src, emp_heavy_range, emp_light_range)) + qdel(src) + return /obj/item/grenade/empgrenade/low_yield - name = "low yield emp grenade" - desc = "A weaker variant of the classic emp grenade." - icon_state = "lyemp" - item_state = "lyempgrenade" - origin_tech = "{'materials':2,'magnets':3}" - - detonate() - ..() - if(empulse(src, 4, 1)) - qdel(src) - return + name = "low-yield EMP grenade" + desc = "A weaker variant of the classic EMP grenade." + icon = 'icons/obj/items/grenades/emp_old.dmi' + origin_tech = @'{"materials":2,"magnets":3}' + emp_heavy_range = 1 + emp_light_range = 4 diff --git a/code/game/objects/items/weapons/grenades/explosive.dm b/code/game/objects/items/weapons/grenades/explosive.dm index fd1b147046fe..91452b1d40cb 100644 --- a/code/game/objects/items/weapons/grenades/explosive.dm +++ b/code/game/objects/items/weapons/grenades/explosive.dm @@ -16,8 +16,7 @@ /obj/item/grenade/frag name = "fragmentation grenade" desc = "A military fragmentation grenade, designed to explode in a deadly shower of fragments, while avoiding massive structural damage." - icon_state = "frggrenade" - + icon = 'icons/obj/items/grenades/frag.dmi' var/list/fragment_types = list(/obj/item/projectile/bullet/pellet/fragment = 1) var/num_fragments = 72 //total number of fragments produced by the grenade var/explosion_size = 2 //size of the center explosion @@ -57,9 +56,9 @@ for(var/mob/living/M in T) //lying on a frag grenade while the grenade is on the ground causes you to absorb most of the shrapnel. //you will most likely be dead, but others nearby will be spared the fragments that hit you instead. - if(M.lying && isturf(src.loc)) + if(M.current_posture.prone && isturf(src.loc)) P.attack_mob(M, 0, 5) - else if(!M.lying && src.loc != get_turf(src)) //if it's not on the turf, it must be in the mob! + else if(!M.current_posture.prone && src.loc != get_turf(src)) //if it's not on the turf, it must be in the mob! P.attack_mob(M, 0, 25) //you're holding a grenade, dude! else P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass @@ -73,14 +72,14 @@ /obj/item/grenade/frag/shell name = "fragmentation grenade" desc = "A light fragmentation grenade, designed to be fired from a launcher. It can still be activated and thrown by hand if necessary." - icon_state = "fragshell" + icon = 'icons/obj/items/grenades/frag_shell.dmi' num_fragments = 50 //less powerful than a regular frag grenade /obj/item/grenade/frag/high_yield name = "fragmentation bomb" desc = "Larger and heavier than a standard fragmentation grenade, this device is extremely dangerous. It cannot be thrown as far because of its weight." - icon_state = "frag" + icon = 'icons/obj/items/grenades/frag_old.dmi' w_class = ITEM_SIZE_NORMAL throw_speed = 3 diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index d083bab85184..ef1232a46a31 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -1,82 +1,75 @@ /obj/item/grenade/flashbang name = "flashbang" desc = "A grenade designed to blind, stun and disorient by means of an extremely bright flash and loud explosion." - icon_state = "flashbang" - item_state = "flashbang" - origin_tech = "{'materials':2,'combat':1}" + icon = 'icons/obj/items/grenades/flashbang.dmi' + origin_tech = @'{"materials":2,"combat":1}' var/banglet = 0 /obj/item/grenade/flashbang/detonate() ..() + var/turf/our_turf = get_turf(src) + on_detonate(our_turf) + new /obj/effect/sparks(our_turf) + new /obj/effect/effect/smoke/illumination(our_turf, 5, 30, 1, "#ffffff") + qdel(src) + +/obj/item/grenade/flashbang/proc/on_detonate(turf/our_turf) var/list/victims = list() var/list/objs = list() - var/turf/T = get_turf(src) - get_mobs_and_objs_in_view_fast(T, 7, victims, objs) - for(var/mob/living/carbon/M in victims) - bang(T, M) - - for(var/obj/effect/blob/B in objs) //Blob damage here - var/damage = round(30/(get_dist(B,T)+1)) - B.take_damage(damage) - - new /obj/effect/sparks(loc) - new /obj/effect/effect/smoke/illumination(loc, 5, 30, 1, "#ffffff") - qdel(src) + get_listeners_in_range(our_turf, 7, victims, objs) + for(var/mob/living/victim in victims) + bang(our_turf, victim) // Added a new proc called 'bang' that takes a location and a person to be banged. // Called during the loop that bangs people in lockers/containers and when banging -// people in normal view. Could theroetically be called during other explosions. +// people in normal view. Could theoretically be called during other explosions. // -- Polymorph -/obj/item/grenade/flashbang/proc/bang(var/turf/T , var/mob/living/carbon/M) +/obj/item/grenade/flashbang/proc/bang(var/turf/T , var/mob/living/M) to_chat(M, SPAN_DANGER("BANG")) playsound(src, 'sound/weapons/flashbang.ogg', 100) //Checking for protections var/eye_safety = 0 var/ear_safety = 0 - if(iscarbon(M)) + if(istype(M)) eye_safety = M.eyecheck() - if(ishuman(M)) - if(M.get_sound_volume_multiplier() < 0.2) - ear_safety += 2 - if(MUTATION_HULK in M.mutations) - ear_safety += 1 - var/mob/living/carbon/human/H = M - if(istype(H.head, /obj/item/clothing/head/helmet)) - ear_safety += 1 + if(M.get_sound_volume_multiplier() < 0.2) + ear_safety += 2 + if(istype(M.get_equipped_item(slot_head_str), /obj/item/clothing/head/helmet)) + ear_safety += 1 //Flashing everyone M.flash_eyes(FLASH_PROTECTION_MODERATE) if(eye_safety < FLASH_PROTECTION_MODERATE) - M.Stun(2) - M.confused += 5 + SET_STATUS_MAX(M, STAT_STUN, 2) + SET_STATUS_MAX(M, STAT_CONFUSE, 5) //Now applying sound if(ear_safety) if(ear_safety < 2 && get_dist(M, T) <= 2) - M.Stun(1) - M.confused += 3 + SET_STATUS_MAX(M, STAT_STUN, 1) + SET_STATUS_MAX(M, STAT_CONFUSE, 3) else if(get_dist(M, T) <= 2) - M.Stun(3) - M.confused += 8 - M.ear_damage += rand(0, 5) - M.ear_deaf = max(M.ear_deaf,15) + SET_STATUS_MAX(M, STAT_STUN, 3) + SET_STATUS_MAX(M, STAT_CONFUSE, 8) + SET_STATUS_MAX(M, STAT_TINNITUS, rand(0, 5)) + SET_STATUS_MAX(M, STAT_DEAF, 15) else if(get_dist(M, T) <= 5) - M.Stun(2) - M.confused += 5 - M.ear_damage += rand(0, 3) - M.ear_deaf = max(M.ear_deaf,10) + SET_STATUS_MAX(M, STAT_STUN, 2) + SET_STATUS_MAX(M, STAT_CONFUSE, 5) + SET_STATUS_MAX(M, STAT_TINNITUS, rand(0, 3)) + SET_STATUS_MAX(M, STAT_DEAF, 10) else - M.Stun(1) - M.confused += 3 - M.ear_damage += rand(0, 1) - M.ear_deaf = max(M.ear_deaf,5) + SET_STATUS_MAX(M, STAT_STUN, 1) + SET_STATUS_MAX(M, STAT_CONFUSE, 3) + SET_STATUS_MAX(M, STAT_TINNITUS, rand(0, 1)) + SET_STATUS_MAX(M, STAT_DEAF, 5) //This really should be in mob not every check - switch(M.ear_damage) + switch(GET_STATUS(M, STAT_TINNITUS)) if(1 to 14) to_chat(M, "Your ears start to ring!") if(15 to INFINITY) @@ -85,22 +78,19 @@ if(!ear_safety) sound_to(M, 'sound/weapons/flash_ring.ogg') -/obj/item/grenade/flashbang/Destroy() - walk(src, 0) // Because we might have called walk_away, we must stop the walk loop or BYOND keeps an internal reference to us forever. - return ..() +/obj/item/grenade/flashbang/instant + invisibility = INVISIBILITY_MAXIMUM + is_spawnable_type = FALSE // Do not manually spawn this, it will runtime/break. /obj/item/grenade/flashbang/instant/Initialize() . = ..() name = "arcane energy" - icon_state = null - item_state = null detonate() /obj/item/grenade/flashbang/clusterbang//Created by Polymorph, fixed by Sieve - desc = "Use of this weapon may constiute a war crime in your area, consult your local captain." + desc = "Use of this weapon may constitute a war crime in your area, consult your local captain." name = "clusterbang" - icon = 'icons/obj/grenade.dmi' - icon_state = "clusterbang" + icon = 'icons/obj/items/grenades/clusterbang.dmi' /obj/item/grenade/flashbang/clusterbang/detonate() var/numspawned = rand(4,8) @@ -109,58 +99,43 @@ if(prob(35)) again++ numspawned -- - for(,numspawned > 0, numspawned--) - spawn(0) - new /obj/item/grenade/flashbang/cluster(src.loc)//Launches flashbangs - playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + new /obj/item/grenade/flashbang/cluster(src.loc)//Launches flashbangs + playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) for(,again > 0, again--) - spawn(0) - new /obj/item/grenade/flashbang/clusterbang/segment(src.loc)//Creates a 'segment' that launches a few more flashbangs - playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + new /obj/item/grenade/flashbang/clusterbang/segment(src.loc)//Creates a 'segment' that launches a few more flashbangs + playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) qdel(src) - return /obj/item/grenade/flashbang/clusterbang/segment desc = "A smaller segment of a clusterbang. Better run." name = "clusterbang segment" - icon = 'icons/obj/grenade.dmi' - icon_state = "clusterbang_segment" + icon = 'icons/obj/items/grenades/clusterbang_segment.dmi' /obj/item/grenade/flashbang/clusterbang/segment/Initialize() . = ..() //Segments should never exist except part of the clusterbang, since these immediately 'do their thing' and asplode - icon_state = "clusterbang_segment_active" - active = 1 banglet = 1 - var/stepdist = rand(1,4)//How far to step - var/temploc = src.loc//Saves the current location to know where to step away from - walk_away(src,temploc,stepdist)//I must go, my people need me - var/dettime = rand(15,60) - spawn(dettime) - detonate() + activate() + //I must go, my people need me + addtimer(CALLBACK(src, PROC_REF(detonate)), rand(15,60)) + if(isturf(loc)) // Don't hurl yourself around if you're not on a turf. + throw_at(get_edge_target_turf(loc, pick(global.cardinal)), rand(1, 4), 5, null, TRUE) /obj/item/grenade/flashbang/clusterbang/segment/detonate() var/numspawned = rand(4,8) for(var/more = numspawned,more > 0,more--) if(prob(35)) numspawned -- - for(,numspawned > 0, numspawned--) - spawn(0) - new /obj/item/grenade/flashbang/cluster(src.loc) - playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + new /obj/item/grenade/flashbang/cluster(src.loc) + playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) qdel(src) - return /obj/item/grenade/flashbang/cluster/Initialize() . = ..() //Same concept as the segments, so that all of the parts don't become reliant on the clusterbang - icon_state = "flashbang_active" - active = 1 banglet = 1 - var/stepdist = rand(1,3) - var/temploc = src.loc - walk_away(src,temploc,stepdist) - var/dettime = rand(15,60) - spawn(dettime) - detonate() + activate() + addtimer(CALLBACK(src, PROC_REF(detonate)), rand(15,60)) + if(isturf(loc)) // See Initialize() for above. + throw_at(get_edge_target_turf(loc, pick(global.cardinal)), rand(1, 3), 5, null, TRUE) diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index fa1d15c78648..42ef0fe712ed 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -2,20 +2,44 @@ name = "grenade" desc = "A hand held grenade, with an adjustable timer." w_class = ITEM_SIZE_SMALL - icon = 'icons/obj/grenade.dmi' - icon_state = "grenade" - item_state = "grenade" + icon = 'icons/obj/items/grenades/grenade.dmi' + icon_state = ICON_STATE_WORLD throw_speed = 4 throw_range = 20 - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - var/active = 0 + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_HOLLOW + slot_flags = SLOT_LOWER_BODY + z_flags = ZMM_MANGLE_PLANES + material = /decl/material/solid/metal/steel + var/active var/det_time = 50 var/fail_det_time = 5 // If you are clumsy and fail, you get this time. var/arm_sound = 'sound/weapons/armbomb.ogg' +/obj/item/grenade/dropped(mob/user) + . = ..() + if(active) + update_icon() + +/obj/item/grenade/equipped(mob/user) + . = ..() + if(active) + update_icon() + +/obj/item/grenade/on_update_icon() + . = ..() + z_flags &= ~ZMM_MANGLE_PLANES + if(active) + if(check_state_in_icon("[icon_state]-active", icon)) + if(plane == HUD_PLANE) + add_overlay("[icon_state]-active") + else + add_overlay(emissive_overlay(icon, "[icon_state]-active")) + z_flags |= ZMM_MANGLE_PLANES + else if(check_state_in_icon("[icon_state]-pin", icon)) + add_overlay("[icon_state]-pin") + /obj/item/grenade/proc/clown_check(var/mob/living/user) - if((MUTATION_CLUMSY in user.mutations) && prob(50)) + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) to_chat(user, "Huh? How does this thing work?") det_time = fail_det_time activate(user) @@ -23,61 +47,55 @@ return 0 return 1 -/obj/item/grenade/examine(mob/user, distance) +/obj/item/grenade/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance <= 0) + if(distance <= 0 && !isnull(det_time)) if(det_time > 1) - to_chat(user, "The timer is set to [det_time/10] seconds.") - return - if(det_time == null) - return - to_chat(user, "\The [src] is set for instant detonation.") + . += "The timer is set to [det_time/10] seconds." + else + . += "\The [src] is set for instant detonation." /obj/item/grenade/attack_self(mob/user) - if(!active) - if(clown_check(user)) - to_chat(user, "You prime \the [name]! [det_time/10] seconds!") - activate(user) - add_fingerprint(user) - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.throw_mode_on() + if(active) + return + if(!user.check_dexterity(DEXTERITY_WEAPONS)) + return TRUE // prevent further interactions + if(clown_check(user)) + to_chat(user, "You prime \the [name]! [det_time/10] seconds!") + activate(user) + add_fingerprint(user) + user.toggle_throw_mode(TRUE) /obj/item/grenade/proc/activate(mob/user) if(active) return - if(user) - msg_admin_attack("[user.name] ([user.ckey]) primed \a [src] (JMP)") - - icon_state = initial(icon_state) + "_active" - active = 1 + msg_admin_attack("[user.name] ([user.ckey]) primed \a [src] (JMP)") + active = TRUE + update_icon() playsound(loc, arm_sound, 75, 0, -3) - addtimer(CALLBACK(src, .proc/detonate), det_time) + addtimer(CALLBACK(src, PROC_REF(detonate)), det_time) /obj/item/grenade/proc/detonate() var/turf/T = get_turf(src) if(T) T.hotspot_expose(700,125) -/obj/item/grenade/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) +/obj/item/grenade/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) switch(det_time) if (1) det_time = 10 - to_chat(user, "You set the [name] for 1 second detonation time.") + to_chat(user, SPAN_NOTICE("You set \the [src] for 1 second detonation time.")) if (10) det_time = 30 - to_chat(user, "You set the [name] for 3 second detonation time.") + to_chat(user, SPAN_NOTICE("You set \the [src] for 3 second detonation time.")) if (30) det_time = 50 - to_chat(user, "You set the [name] for 5 second detonation time.") + to_chat(user, SPAN_NOTICE("You set \the [src] for 5 second detonation time.")) if (50) det_time = 1 - to_chat(user, "You set the [name] for instant detonation.") + to_chat(user, SPAN_NOTICE("You set \the [src] for instant detonation.")) add_fingerprint(user) - ..() - -/obj/item/grenade/attack_hand() - walk(src, null, null) - ..() \ No newline at end of file + return TRUE + return ..() diff --git a/code/game/objects/items/weapons/grenades/light.dm b/code/game/objects/items/weapons/grenades/light.dm index 3683b68a0e0d..b235bb107cda 100644 --- a/code/game/objects/items/weapons/grenades/light.dm +++ b/code/game/objects/items/weapons/grenades/light.dm @@ -1,16 +1,14 @@ /obj/item/grenade/light name = "illumination grenade" desc = "A grenade designed to illuminate an area without the use of a flame or electronics, regardless of the atmosphere." - icon_state = "lightgrenade" - item_state = "flashbang" + icon = 'icons/obj/items/grenades/grenade_light.dmi' det_time = 20 /obj/item/grenade/light/detonate() ..() var/lifetime = rand(2 MINUTES, 4 MINUTES) - var/light_colour = pick("#49f37c", "#fc0f29", "#599dff", "#fa7c0b", "#fef923") - + var/light_flash_color = pick("#49f37c", "#fc0f29", "#599dff", "#fa7c0b", "#fef923") playsound(src, 'sound/effects/snap.ogg', 80, 1) audible_message("\The [src] detonates with a sharp crack!") - set_light(1, 1, 12, 2, light_colour) + set_light(12, 1, light_flash_color) QDEL_IN(src, lifetime) \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/prank_grenades.dm b/code/game/objects/items/weapons/grenades/prank_grenades.dm index 76cf71fc52ff..0a884f850ec0 100644 --- a/code/game/objects/items/weapons/grenades/prank_grenades.dm +++ b/code/game/objects/items/weapons/grenades/prank_grenades.dm @@ -1,20 +1,23 @@ /obj/item/grenade/fake - icon_state = "frggrenade" + icon = 'icons/obj/items/grenades/frag.dmi' /obj/item/grenade/fake/detonate() active = 0 playsound(src.loc, get_sfx("explosion"), 50, 1, 30) /obj/item/natural_weapon/bite/fake - force = 0 + _base_attack_force = 0 /mob/living/simple_animal/hostile/carp/holodeck/fake faction = null natural_weapon = /obj/item/natural_weapon/bite/fake environment_smash = 0 - destroy_surroundings = 0 + ai = /datum/mob_controller/aggressive/carp/fake + +/datum/mob_controller/aggressive/carp/fake + try_destroy_surroundings = FALSE /obj/item/grenade/spawnergrenade/fake_carp - origin_tech = "{'materials':2,'magnets':2,'wormholes':5}" + origin_tech = @'{"materials":2,"magnets":2,"wormholes":5}' spawner_type = /mob/living/simple_animal/hostile/carp/holodeck/fake deliveryamt = 4 diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index 61b8281800bc..2ba6f0b26f7d 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -1,11 +1,9 @@ /obj/item/grenade/smokebomb desc = "It is set to detonate in 2 seconds." name = "smoke bomb" - icon = 'icons/obj/grenade.dmi' - icon_state = "flashbang" + icon = 'icons/obj/items/grenades/flashbang.dmi' det_time = 20 - item_state = "flashbang" - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY var/datum/effect/effect/system/smoke_spread/bad/smoke var/smoke_times = 4 @@ -20,10 +18,6 @@ smoke.attach(src) smoke.set_up(10, 0, get_turf(src)) START_PROCESSING(SSobj, src) - for(var/obj/effect/blob/B in view(8,src)) - var/damage = round(30/(get_dist(B,src)+1)) - B.health -= damage - B.update_icon() QDEL_IN(src, 8 SECONDS) /obj/item/grenade/smokebomb/Process() diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 71d5f0989db2..a636763ac076 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -1,11 +1,8 @@ /obj/item/grenade/spawnergrenade - desc = "It is set to detonate in 5 seconds. It will unleash unleash an unspecified anomaly into the vicinity." + desc = "It is set to detonate in 5 seconds. It will unleash an unspecified anomaly into the vicinity." name = "delivery grenade" - icon = 'icons/obj/grenade.dmi' - icon_state = "delivery" - item_state = "flashbang" - origin_tech = "{'materials':3,'magnets':4}" - var/banglet = 0 + icon = 'icons/obj/items/grenades/delivery.dmi' + origin_tech = @'{"materials":3,"magnets":4}' var/spawner_type = null // must be an object path var/deliveryamt = 1 // amount of type to deliver @@ -13,24 +10,24 @@ if(spawner_type && deliveryamt) var/turf/T = get_turf(src) playsound(T, 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(T, null)) + for(var/mob/living/human/M in viewers(T, null)) if(M.eyecheck() < FLASH_PROTECTION_MODERATE) M.flash_eyes() for(var/i = 1 to deliveryamt) var/atom/spawned = new spawner_type(T) if(prob(50)) for(var/j = 1 to rand(1, 3)) - step(spawned, pick(GLOB.cardinal)) + step(spawned, pick(global.cardinal)) qdel(src) /obj/item/grenade/spawnergrenade/manhacks name = "manhack delivery grenade" spawner_type = /mob/living/simple_animal/hostile/viscerator deliveryamt = 5 - origin_tech = "{'materials':3,'magnets':4,'esoteric':4}" + origin_tech = @'{"materials":3,"magnets":4,"esoteric":4}' /obj/item/grenade/spawnergrenade/spesscarp name = "carp delivery grenade" spawner_type = /mob/living/simple_animal/hostile/carp deliveryamt = 5 - origin_tech = "{'materials':3,'magnets':4,'esoteric':4}" + origin_tech = @'{"materials":3,"magnets":4,"esoteric":4}' diff --git a/code/game/objects/items/weapons/grenades/supermatter.dm b/code/game/objects/items/weapons/grenades/supermatter.dm deleted file mode 100644 index 2449f26fcba5..000000000000 --- a/code/game/objects/items/weapons/grenades/supermatter.dm +++ /dev/null @@ -1,36 +0,0 @@ -/obj/item/grenade/supermatter - name = "supermatter grenade" - icon_state = "banana" - item_state = "emergency_engi" - origin_tech = "{'wormholes':5,'magnets':4,'engineering':5}" - arm_sound = 'sound/effects/3.wav' - var/implode_at - -/obj/item/grenade/supermatter/Destroy() - if(implode_at) - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/grenade/supermatter/detonate() - ..() - START_PROCESSING(SSobj, src) - implode_at = world.time + 10 SECONDS - update_icon() - playsound(src, 'sound/weapons/wave.ogg', 100) - -/obj/item/grenade/supermatter/on_update_icon() - overlays.Cut() - if(implode_at) - overlays += image(icon = 'icons/obj/machines/power/fusion.dmi', icon_state = "emfield_s1") - -/obj/item/grenade/supermatter/Process() - if(!isturf(loc)) - if(ismob(loc)) - var/mob/M = loc - M.drop_from_inventory(src) - forceMove(get_turf(src)) - playsound(src, 'sound/effects/supermatter.ogg', 100) - supermatter_pull(src, world.view, STAGE_THREE) - if(world.time > implode_at) - explosion(loc, 0, 1, 3, 4) - qdel(src) diff --git a/code/game/objects/items/weapons/hair_care.dm b/code/game/objects/items/weapons/hair_care.dm deleted file mode 100644 index 83059b378430..000000000000 --- a/code/game/objects/items/weapons/hair_care.dm +++ /dev/null @@ -1,34 +0,0 @@ - -/obj/item/haircomb //sparklysheep's comb - name = "plastic comb" - desc = "A pristine comb made from flexible plastic." - w_class = ITEM_SIZE_TINY - slot_flags = SLOT_EARS - icon = 'icons/obj/items/comb.dmi' - icon_state = "comb" - item_state = "comb" - -/obj/item/haircomb/random/Initialize() - . = ..() - color = get_random_colour(lower = 150) - -/obj/item/haircomb/attack_self(var/mob/living/carbon/human/user) - if(!user.incapacitated()) - user.visible_message("\The [user] uses \the [src] to comb their hair with incredible style and sophistication. What a [user.gender == FEMALE ? "lady" : "guy"].") - -/obj/item/haircomb/brush - name = "hairbrush" - desc = "A surprisingly decent hairbrush with a false wood handle and semi-soft bristles." - icon = 'icons/obj/items/hairbrush.dmi' - w_class = ITEM_SIZE_SMALL - slot_flags = null - icon_state = "brush" - item_state = "brush" - -/obj/item/haircomb/brush/attack_self(mob/living/carbon/human/user) - if(!user.incapacitated()) - var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_list[user.h_style] - if(hair_style.flags & VERY_SHORT) - user.visible_message("\The [user] just sort of runs \the [src] over their scalp.") - else - user.visible_message("\The [user] meticulously brushes their hair with \the [src].") \ No newline at end of file diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index b9b38b2baa27..6ef925bfad78 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -3,100 +3,101 @@ desc = "Use this to keep prisoners in line." gender = PLURAL icon = 'icons/obj/items/handcuffs.dmi' - icon_state = "handcuff" - health = 0 + icon_state = ICON_STATE_WORLD obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - throwforce = 5 + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL throw_speed = 2 throw_range = 5 - origin_tech = "{'materials':1}" + origin_tech = @'{"materials":1}' material = /decl/material/solid/metal/steel + max_health = ITEM_HEALTH_NO_DAMAGE //#TODO: Once we can work out something different for handling cuff breakout, change this. Since it relies on cuffs health to tell if you can actually breakout. var/elastic var/dispenser = 0 - var/breakouttime = 1200 //Deciseconds = 120s = 2 minutes + var/breakouttime = 2 MINUTES //Deciseconds = 120s = 2 minutes var/cuff_sound = 'sound/weapons/handcuffs.ogg' var/cuff_type = "handcuffs" -/obj/item/handcuffs/examine(mob/user) +/obj/item/handcuffs/Initialize(ml, material_key) . = ..() - if (health) - var display = health / initial(health) * 100 + set_extension(src, /datum/extension/resistable/handcuffs) + +/obj/item/handcuffs/Destroy() + var/obj/item/clothing/shoes/attached_shoes = loc + if(istype(attached_shoes)) + attached_shoes.remove_cuffs() + . = ..() + +/obj/item/handcuffs/physically_destroyed(skip_qdel) + if(istype(loc, /obj/item/clothing/shoes)) + loc.visible_message(SPAN_WARNING("\The [src] attached to \the [loc] snap and fall away!"), range = 1) + . = ..() + +/obj/item/handcuffs/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if (current_health > 0 && get_max_health() > 0) + var display = get_percent_health() if (display > 66) return - to_chat(user, SPAN_WARNING("They look [display < 33 ? "badly ": ""]damaged.")) - -/obj/item/handcuffs/get_icon_state(mob/user_mob, slot) - if(slot == slot_handcuffed_str) - return "handcuff1" - if(slot == slot_legcuffed_str) - return "legcuff1" - return ..() + . += SPAN_WARNING("They look [display < 33 ? "badly ": ""]damaged.") -/obj/item/handcuffs/attack(var/mob/living/carbon/C, var/mob/living/user) +/obj/item/handcuffs/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) - return + return ..() - if ((MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, "Uh ... how do those things work?!") + if (user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + to_chat(user, SPAN_WARNING("You can't figure out how to work \the [src]...")) place_handcuffs(user, user) - return + return TRUE - // only carbons can be handcuffed - if(istype(C)) - if(!C.handcuffed) - if (C == user) + // only humans can be cuffed for now + if(ishuman(target)) + var/mob/living/human/H = target + if(!H.get_equipped_item(slot_handcuffed_str)) + if (H == user) place_handcuffs(user, user) - return + return TRUE //check for an aggressive grab (or robutts) - if(can_place(C, user)) - place_handcuffs(C, user) + if(H.has_danger_grab(user)) + place_handcuffs(H, user) else - to_chat(user, "You need to have a firm grip on [C] before you can put \the [src] on!") + to_chat(user, SPAN_WARNING("You need to have a firm grip on \the [H] before you can put \the [src] on!")) else - to_chat(user, "\The [C] is already handcuffed!") - else - ..() - -/obj/item/handcuffs/proc/can_place(var/mob/target, var/mob/user) - if(user == target || istype(user, /mob/living/silicon/robot) || istype(user, /mob/living/bot)) - return 1 - else - for (var/obj/item/grab/G in target.grabbed_by) - if (G.force_danger()) - return 1 - return 0 - -/obj/item/handcuffs/proc/place_handcuffs(var/mob/living/carbon/target, var/mob/user) + to_chat(user, SPAN_WARNING("\The [H] is already handcuffed!")) + return TRUE + + return ..() + +/obj/item/handcuffs/proc/place_handcuffs(var/mob/living/target, var/mob/user) playsound(src.loc, cuff_sound, 30, 1, -2) - var/mob/living/carbon/human/H = target + var/mob/living/human/H = target if(!istype(H)) return 0 - if (!H.has_organ_for_slot(slot_handcuffed)) - to_chat(user, "\The [H] needs at least two wrists before you can cuff them together!") + if (!H.has_organ_for_slot(slot_handcuffed_str)) + to_chat(user, SPAN_WARNING("\The [H] needs at least two wrists before you can cuff them together!")) return 0 - if((H.gloves && H.gloves.item_flags & ITEM_FLAG_NOCUFFS) && !elastic) - to_chat(user, "\The [src] won't fit around \the [H.gloves]!") + var/obj/item/gloves = H.get_equipped_item(slot_gloves_str) + if((gloves && (gloves.item_flags & ITEM_FLAG_NOCUFFS)) && !elastic) + to_chat(user, SPAN_WARNING("\The [src] won't fit around \the [gloves]!")) return 0 - user.visible_message("\The [user] is attempting to put [cuff_type] on \the [H]!") + user.visible_message(SPAN_DANGER("\The [user] is attempting to put [cuff_type] on \the [H]!")) if(!do_after(user,30, target)) return 0 - if(!can_place(target, user)) // victim may have resisted out of the grab in the meantime + if(!target.has_danger_grab(user)) // victim may have resisted out of the grab in the meantime return 0 var/obj/item/handcuffs/cuffs = src if(dispenser) cuffs = new(get_turf(user)) - else if(!user.unEquip(cuffs)) + else if(!user.try_unequip(cuffs)) return 0 admin_attack_log(user, H, "Attempted to handcuff the victim", "Was target of an attempted handcuff", "attempted to handcuff") @@ -108,40 +109,19 @@ user.visible_message("\The [user] has put [cuff_type] on \the [H]!") // Apply cuffs. - target.equip_to_slot(cuffs,slot_handcuffed) + target.equip_to_slot(cuffs, slot_handcuffed_str) return 1 -var/last_chew = 0 -/mob/living/carbon/human/RestrainedClickOn(var/atom/A) - if (A != src) return ..() - if (last_chew + 26 > world.time) return - - var/mob/living/carbon/human/H = A - if (!H.handcuffed) return - if (H.a_intent != I_HURT) return - if (H.zone_sel.selecting != BP_MOUTH) return - if (H.wear_mask) return - if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket)) return - - var/obj/item/organ/external/O = H.organs_by_name[(H.hand ? BP_L_HAND : BP_R_HAND)] - if (!O) return - - H.visible_message("\The [H] chews on \his [O.name]!", "You chew on your [O.name]!") - admin_attacker_log(H, "chewed on their [O.name]!") - - O.take_external_damage(3,0, DAM_SHARP|DAM_EDGE ,"teeth marks") - - last_chew = world.time - /obj/item/handcuffs/cable name = "cable restraints" desc = "Looks like some cables tied together. Could be used to tie something up." - icon_state = "cuff_white" + icon = 'icons/obj/items/handcuffs_cable.dmi' breakouttime = 300 //Deciseconds = 30s cuff_sound = 'sound/weapons/cablecuff.ogg' cuff_type = "cable restraints" elastic = 1 - health = 75 + max_health = 75 + material = /decl/material/solid/organic/plastic /obj/item/handcuffs/cable/red color = COLOR_MAROON @@ -178,4 +158,5 @@ var/last_chew = 0 icon = 'icons/obj/bureaucracy.dmi' breakouttime = 200 cuff_type = "duct tape" - health = 50 \ No newline at end of file + max_health = 50 + material = /decl/material/solid/organic/plastic \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm deleted file mode 100644 index a1e1a62b1b98..000000000000 --- a/code/game/objects/items/weapons/implants/implant.dm +++ /dev/null @@ -1,123 +0,0 @@ -#define MALFUNCTION_TEMPORARY 1 -#define MALFUNCTION_PERMANENT 2 - - -/obj/item/implant - name = "implant" - icon = 'icons/obj/items/implant/implant.dmi' - icon_state = "implant" - w_class = ITEM_SIZE_TINY - var/implanted = null - var/mob/imp_in = null - var/obj/item/organ/external/part = null - var/implant_color = "b" - var/malfunction = 0 - var/known //if advanced scanners would name these in results - var/hidden //if scanners will locate this implant at all - -/obj/item/implant/proc/trigger(emote, source) - return - -/obj/item/implant/proc/hear(message) - return - -/obj/item/implant/proc/activate() - return - -/obj/item/implant/proc/disable(var/time = 100) - if(malfunction) - return 0 - - malfunction = MALFUNCTION_TEMPORARY - addtimer(CALLBACK(src,.proc/restore),time) - return 1 - -/obj/item/implant/proc/restore() - if(malfunction == MALFUNCTION_PERMANENT || !malfunction) - return 0 - - malfunction = 0 - return 1 - -// What does the implant do upon injection? -// return 0 if the implant fails (ex. Revhead and loyalty implant.) -// return TRUE if the implant succeeds (ex. Nonrevhead and loyalty implant.) -/obj/item/implant/proc/implanted(var/mob/source) - return TRUE - -/obj/item/implant/proc/can_implant(mob/M, mob/user, var/target_zone) - var/mob/living/carbon/human/H = M - if(istype(H) && !H.get_organ(target_zone)) - to_chat(user, "\The [M] is missing that body part.") - return FALSE - return TRUE - -/obj/item/implant/proc/implant_in_mob(mob/M, var/target_zone) - if (ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affected = H.get_organ(target_zone) - if(affected) - affected.implants += src - part = affected - - BITSET(H.hud_updateflag, IMPLOYAL_HUD) - - forceMove(M) - imp_in = M - implanted = 1 - implanted(M) - - return TRUE - -/obj/item/implant/proc/removed() - imp_in = null - if(part) - part.implants -= src - part = null - implanted = 0 - -//Called in surgery when incision is retracted open / ribs are opened - basically before you can take implant out -/obj/item/implant/proc/exposed() - return - -/obj/item/implant/proc/get_data() - return "No information available" - -/obj/item/implant/interact(user) - var/datum/browser/popup = new(user, capitalize(name), capitalize(name), 300, 700, src) - var/dat = get_data() - if(malfunction) - popup.title = "??? implant" - dat = stars(dat,10) - popup.set_content(dat) - popup.open() - -/obj/item/implant/proc/islegal() - return FALSE - -/obj/item/implant/proc/meltdown() //breaks it down, making implant unrecongizible - if(malfunction == MALFUNCTION_PERMANENT) return - to_chat(imp_in, SPAN_DANGER("You feel something melting inside [part ? "your [part.name]" : "you"]!")) - if (part) - part.take_external_damage(burn = 15, used_weapon = "Electronics meltdown") - else - var/mob/living/M = imp_in - M.apply_damage(15,BURN) - name = "melted implant" - desc = "Charred circuit in melted plastic case. Wonder what that used to be..." - icon_state = "implant_melted" - malfunction = MALFUNCTION_PERMANENT - -/obj/item/implant/emp_act(severity) - var/power = 4 - severity - if(prob(power * 15)) - meltdown() - else if(prob(power * 25)) - activate() - else if(prob(power * 33)) - disable(rand(power*100,power*1000)) - -/obj/item/implant/Destroy() - if(part) - part.implants.Remove(src) - return ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm deleted file mode 100644 index 67505c1ee874..000000000000 --- a/code/game/objects/items/weapons/implants/implantcase.dm +++ /dev/null @@ -1,78 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/implantcase - name = "glass case" - desc = "A case containing an implant." - icon = 'icons/obj/items/implant/implantcase.dmi' - icon_state = "implantcase-0" - item_state = "implantcase" - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_TINY - material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - var/obj/item/implant/imp = null - -/obj/item/implantcase/Initialize() - . = ..() - if(ispath(imp)) - imp = new imp(src) - update_description() - update_icon() - -/obj/item/implantcase/Destroy() - QDEL_NULL(imp) - . = ..() - -/obj/item/implantcase/proc/update_description() - if (imp) - desc = "A case containing \a [imp]." - origin_tech = imp.origin_tech - else - desc = "A case for implants." - origin_tech = null - -/obj/item/implantcase/on_update_icon() - if (imp) - icon_state = "implantcase-[imp.implant_color]" - else - icon_state = "implantcase-0" - return - -/obj/item/implantcase/attackby(obj/item/I, mob/user) - if (istype(I, /obj/item/pen)) - var/t = input(user, "What would you like the label to be?", src.name, null) - if (user.get_active_hand() != I) - return - if((!in_range(src, usr) && loc != user)) - return - t = sanitizeSafe(t, MAX_NAME_LEN) - if(t) - SetName("glass case - '[t]'") - desc = "A case containing \a [t] implant." - else - SetName(initial(name)) - desc = "A case containing an implant." - else if(istype(I, /obj/item/chems/syringe)) - if(istype(imp,/obj/item/implant/chem)) - imp.attackby(I,user) - else if (istype(I, /obj/item/implanter)) - var/obj/item/implanter/M = I - if (M.imp && !imp && !M.imp.implanted) - M.imp.forceMove(src) - imp = M.imp - M.imp = null - else if (imp && !M.imp) - imp.forceMove(M) - M.imp = src.imp - imp = null - update_description() - update_icon() - M.update_icon() - else if (istype(I, /obj/item/implant) && user.unEquip(I, src)) - to_chat(usr, "You slide \the [I] into \the [src].") - imp = I - update_description() - update_icon() - else - return ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm deleted file mode 100644 index a6a25ddd9b06..000000000000 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ /dev/null @@ -1,159 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/machinery/implantchair - name = "loyalty implanter" - desc = "Used to implant occupants with loyalty implants." - icon = 'icons/obj/machines/implantchair.dmi' - icon_state = "implantchair" - density = 1 - opacity = 0 - anchored = 1 - - var/ready = 1 - var/malfunction = 0 - var/list/obj/item/implant/loyalty/implant_list = list() - var/max_implants = 5 - var/injection_cooldown = 600 - var/replenish_cooldown = 6000 - var/replenishing = 0 - var/mob/living/carbon/occupant = null - var/injecting = 0 - -/obj/machinery/implantchair/Initialize() - . = ..() - add_implants() - -/obj/machinery/implantchair/interface_interact(user) - interact(user) - return TRUE - -/obj/machinery/implantchair/interact(mob/user) - user.set_machine(src) - var/health_text = "" - if(src.occupant) - if(src.occupant.health <= -100) - health_text = "Dead" - else if(src.occupant.health < 0) - health_text = "[round(src.occupant.health,0.1)]" - else - health_text = "[round(src.occupant.health,0.1)]" - - var/dat ="Implanter Status
              " - - dat +="Current occupant: [src.occupant ? "
              Name: [src.occupant]
              Health: [health_text]
              " : "None"]
              " - dat += "Implants: [src.implant_list.len ? "[implant_list.len]" : "Replenish"]
              " - if(src.occupant) - dat += "[src.ready ? "Implant" : "Recharging"]
              " - user.set_machine(src) - show_browser(user, dat, "window=implant") - onclose(user, "implant") - - -/obj/machinery/implantchair/Topic(href, href_list) - if((. = ..())) - return - if((get_dist(src, usr) <= 1) || istype(usr, /mob/living/silicon/ai)) - if(href_list["implant"]) - if(src.occupant) - injecting = 1 - go_out() - ready = 0 - spawn(injection_cooldown) - ready = 1 - - if(href_list["replenish"]) - ready = 0 - spawn(replenish_cooldown) - add_implants() - ready = 1 - - src.updateUsrDialog() - src.add_fingerprint(usr) - -/obj/machinery/implantchair/attackby(var/obj/item/G, var/mob/user) - if(istype(G, /obj/item/grab)) - var/obj/item/grab/grab = G - if(!ismob(grab.affecting)) - return - for(var/mob/living/carbon/slime/M in range(1, grab.affecting)) - if(M.Victim == grab.affecting) - to_chat(usr, "[grab.affecting.name] will not fit into the [src.name] because they have a slime latched onto their head.") - return - var/mob/M = grab.affecting - if(put_mob(M)) - qdel(G) - src.updateUsrDialog() - - -/obj/machinery/implantchair/proc/go_out(var/mob/M) - if(!( src.occupant )) - return - if(M == occupant) // so that the guy inside can't eject himself -Agouri - return - if (src.occupant.client) - src.occupant.client.eye = src.occupant.client.mob - src.occupant.client.perspective = MOB_PERSPECTIVE - occupant.dropInto(loc) - if(injecting) - implant(src.occupant) - injecting = 0 - src.occupant = null - icon_state = "implantchair" - return - - -/obj/machinery/implantchair/proc/put_mob(mob/living/carbon/M) - if(!iscarbon(M)) - to_chat(usr, "\The [src] cannot hold this!") - return - if(src.occupant) - to_chat(usr, "\The [src] is already occupied!") - return - if(M.client) - M.client.perspective = EYE_PERSPECTIVE - M.client.eye = src - M.forceMove(src) - src.occupant = M - src.add_fingerprint(usr) - icon_state = "implantchair_on" - return 1 - - -/obj/machinery/implantchair/proc/implant(var/mob/M) - if (!istype(M, /mob/living/carbon)) - return - if(!implant_list.len) return - for(var/obj/item/implant/loyalty/imp in implant_list) - if(!imp) continue - if(istype(imp, /obj/item/implant/loyalty)) - for (var/mob/O in viewers(M, null)) - O.show_message("\The [M] has been implanted by \the [src].", 1) - - if(imp.implanted(M)) - imp.forceMove(M) - imp.imp_in = M - imp.implanted = 1 - implant_list -= imp - break - -/obj/machinery/implantchair/proc/add_implants() - for(var/i=0, iThere is no implant to remove.") - return - imp.forceMove(get_turf(src)) - usr.put_in_hands(imp) - to_chat(usr, "You remove \the [imp] from \the [src].") - name = "implanter" - imp = null - update_icon() - return - else - to_chat(usr, "You cannot do this in your current condition.") - -/obj/item/implanter/proc/can_use() - - if(!ismob(loc)) - return 0 - - var/mob/M = loc - - if(M.incapacitated()) - return 0 - if((src in M.contents) || (istype(loc, /turf) && in_range(src, M))) - return 1 - return 0 - -/obj/item/implanter/attackby(obj/item/I, mob/user) - if(!imp && istype(I, /obj/item/implant) && user.unEquip(I,src)) - to_chat(usr, "You slide \the [I] into \the [src].") - imp = I - update_icon() - else - ..() - -/obj/item/implanter/attack(mob/M, mob/user) - if (!istype(M, /mob/living/carbon)) - return - if (user && src.imp) - M.visible_message("[user] is attemping to implant [M].") - - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(M) - - var/target_zone = user.zone_sel.selecting - if(src.imp.can_implant(M, user, target_zone)) - var/imp_name = imp.name - - if(do_after(user, 50, M) && src.imp.implant_in_mob(M, target_zone)) - M.visible_message("[M] has been implanted by [user].") - admin_attack_log(user, M, "Implanted using \the [src] ([imp_name])", "Implanted with \the [src] ([imp_name])", "used an implanter, \the [src] ([imp_name]), on") - - src.imp = null - update_icon() - - return \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantpad.dm b/code/game/objects/items/weapons/implants/implantpad.dm deleted file mode 100644 index 23011f07073b..000000000000 --- a/code/game/objects/items/weapons/implants/implantpad.dm +++ /dev/null @@ -1,61 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/implantpad - name = "implant pad" - desc = "Used to reprogramm implants." - icon = 'icons/obj/items/implant/implantpad.dmi' - icon_state = "implantpad-0" - item_state = "electronic" - w_class = ITEM_SIZE_SMALL - var/obj/item/implant/imp - -/obj/item/implantpad/on_update_icon() - if (imp) - icon_state = "implantpad-1" - else - icon_state = "implantpad-0" - -/obj/item/implantpad/attack_hand(mob/user) - if ((imp && (user.l_hand == src || user.r_hand == src))) - user.put_in_active_hand(imp) - imp.add_fingerprint(user) - add_fingerprint(user) - - imp = null - update_icon() - else - return ..() - -/obj/item/implantpad/attackby(obj/item/I, mob/user) - ..() - if(istype(I, /obj/item/implantcase)) - var/obj/item/implantcase/C = I - if(!imp && C.imp) - C.imp.forceMove(src) - imp = C.imp - C.imp = null - else if (imp && !C.imp) - imp.forceMove(C) - C.imp = imp - imp = null - C.update_icon() - else if(istype(I, /obj/item/implanter)) - var/obj/item/implanter/C = I - if(!imp && C.imp) - C.imp.forceMove(src) - imp = C.imp - C.imp = null - else if (imp && !C.imp) - imp.forceMove(C) - C.imp = imp - imp = null - C.update_icon() - else if(istype(I, /obj/item/implant) && user.unEquip(I, src)) - imp = I - update_icon() - -/obj/item/implantpad/attack_self(mob/user) - if (imp) - imp.interact(user) - else - to_chat(user,"There's no implant loaded in \the [src].") \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/adrenaline.dm b/code/game/objects/items/weapons/implants/implants/adrenaline.dm deleted file mode 100644 index 0b3233c95898..000000000000 --- a/code/game/objects/items/weapons/implants/implants/adrenaline.dm +++ /dev/null @@ -1,43 +0,0 @@ -/obj/item/implant/adrenalin - name = "adrenalin implant" - desc = "Removes all stuns and knockdowns." - origin_tech = "{'materials':1,'biotech':2,'esoteric':2}" - hidden = 1 - var/uses - -/obj/item/implant/adrenalin/get_data() - return {" - Implant Specifications:
              - Name: Cybersun Industries Adrenalin Implant
              - Life: Five days.
              - Important Notes: Illegal
              -
              - Implant Details: Subjects injected with implant can activate a massive injection of adrenalin.
              - Function: Contains nanobots to stimulate body to mass-produce Adrenalin.
              - Special Features: Will prevent and cure most forms of brainwashing.
              - Integrity: Implant can only be used three times before the nanobots are depleted."} - -/obj/item/implant/adrenalin/trigger(emote, mob/source) - if (emote == "pale") - activate() - -/obj/item/implant/adrenalin/activate()//this implant is unused but I'm changing it for the sake of consistency - if (uses < 1 || malfunction || !imp_in) return 0 - uses-- - to_chat(imp_in, "You feel a sudden surge of energy!") - imp_in.SetStunned(0) - imp_in.SetWeakened(0) - imp_in.SetParalysis(0) - -/obj/item/implant/adrenalin/implanted(mob/source) - source.StoreMemory("A implant can be activated by using the pale emote, say *pale to attempt to activate.", /decl/memory_options/system) - to_chat(source, "The implanted freedom implant can be activated by using the pale emote, say *pale to attempt to activate.") - return TRUE - -/obj/item/implanter/adrenalin - name = "implanter-adrenalin" - imp = /obj/item/implant/adrenalin - -/obj/item/implantcase/adrenalin - name = "glass case - 'adrenalin'" - imp = /obj/item/implant/adrenalin \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/chem.dm b/code/game/objects/items/weapons/implants/implants/chem.dm deleted file mode 100644 index 99922b3a8e48..000000000000 --- a/code/game/objects/items/weapons/implants/implants/chem.dm +++ /dev/null @@ -1,49 +0,0 @@ -/obj/item/implant/chem - name = "chemical implant" - desc = "Injects things." - origin_tech = "{'materials':1,'biotech':2}" - known = 1 - -/obj/item/implant/chem/get_data() - return {" - Implant Specifications:
              - Name: Robust Corp MJ-420 Prisoner Management Implant
              - Life: Deactivates upon death but remains within the body.
              - Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
              - will suffer from an increased appetite.

              -
              - Implant Details:
              - Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
              - the implant releases the chemicals directly into the blood stream.
              - Special Features: - Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
              - Can only be loaded while still in its original case.
              - Integrity: Implant will last so long as the subject is alive. However, if the subject suffers from prolonged malnutrition,
              - nine or more days without nutrients, the implant may become unstable and either pre-maturely inject the subject or simply break."} - -/obj/item/implant/chem/Initialize() - . = ..() - create_reagents(50) - -/obj/item/implant/chem/activate(var/amount) - if(malfunction || (!iscarbon(imp_in))) return 0 - if(!amount) - amount = rand(1,25) - var/mob/living/carbon/R = imp_in - reagents.trans_to_mob(R, amount, CHEM_INJECT) - to_chat(R, "You hear a faint *beep*.") - -/obj/item/implant/chem/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/chems/syringe)) - if(reagents.total_volume >= reagents.maximum_volume) - to_chat(user, "\The [src] is full.") - else - if(do_after(user,5,src)) - I.reagents.trans_to_obj(src, 5) - to_chat(user, "You inject 5 units of the solution. The syringe now contains [I.reagents.total_volume] units.") - else - ..() - -/obj/item/implantcase/chem - name = "glass case - 'chem'" - imp = /obj/item/implant/chem \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/compressed.dm b/code/game/objects/items/weapons/implants/implants/compressed.dm deleted file mode 100644 index 16e5669bae84..000000000000 --- a/code/game/objects/items/weapons/implants/implants/compressed.dm +++ /dev/null @@ -1,93 +0,0 @@ -/obj/item/implant/compressed - name = "compressed matter implant" - desc = "Based on compressed matter technology, can store a single item." - icon_state = "implant_evil" - origin_tech = "{'materials':4,'biotech':2,'esoteric':2}" - hidden = 1 - var/activation_emote - var/obj/item/scanned - -/obj/item/implant/compressed/trigger(emote, mob/source) - if (src.scanned == null) - return 0 - - if (emote == src.activation_emote) - to_chat(source, "The air glows as \the [src.scanned.name] uncompresses.") - activate() - -/obj/item/implant/compressed/activate() - if(malfunction) return - var/turf/T = get_turf(src) - if (imp_in) - imp_in.put_in_hands(scanned) - else - scanned.forceMove(T) - qdel(src) - -/obj/item/implant/compressed/implanted(mob/source) - src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") - if (source.mind) - source.StoreMemory("Compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", /decl/memory_options/system) - to_chat(source, "The implanted compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") - return TRUE - -/obj/item/implanter/compressed - name = "implanter (C)" - icon = 'icons/obj/items/implant/compressed_implant.dmi' - icon_state = "cimplanter1" - desc = "The matter compressor safety is on." - var/safe = 1 - imp = /obj/item/implant/compressed - -/obj/item/implanter/compressed/on_update_icon() - if (imp) - var/obj/item/implant/compressed/c = imp - if(!c.scanned) - icon_state = "cimplanter1" - else - icon_state = "cimplanter2" - else - icon_state = "cimplanter0" - return - -/obj/item/implanter/compressed/attack(mob/M, mob/user) - var/obj/item/implant/compressed/c = imp - if (!c) return - if (c.scanned == null) - to_chat(user, "Please compress an object with the implanter first.") - return - ..() - -/obj/item/implanter/compressed/afterattack(obj/item/A, mob/user, proximity) - if(!proximity) - return - if(istype(A) && imp) - var/obj/item/implant/compressed/c = imp - if (c.scanned) - if (!istype(A,/obj/item/storage)) - to_chat(user, "Something is already compressed inside the implant!") - return - else if(safe) - if (!istype(A,/obj/item/storage)) - to_chat(user, "The matter compressor safeties prevent you from doing that.") - return - if(istype(A.loc,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = A.loc - if(!H.unEquip(A)) - return - else if(istype(A.loc,/obj/item/storage)) - var/obj/item/storage/S = A.loc - S.remove_from_storage(A) - c.scanned = A - A.forceMove(src) //Store it inside - safe = 2 - desc = "It currently contains some matter." - update_icon() - -/obj/item/implanter/compressed/attack_self(var/mob/user) - if(!imp || safe == 2) - return ..() - - safe = !safe - to_chat(user, "You [safe ? "enable" : "disable"] the matter compressor safety.") - src.desc = "The matter compressor safety is [safe ? "on" : "off"]." \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/death_alarm.dm b/code/game/objects/items/weapons/implants/implants/death_alarm.dm deleted file mode 100644 index cd974634f585..000000000000 --- a/code/game/objects/items/weapons/implants/implants/death_alarm.dm +++ /dev/null @@ -1,75 +0,0 @@ -/obj/item/implant/death_alarm - name = "death alarm implant" - desc = "An alarm which monitors host vital signs and transmits a radio message upon death." - origin_tech = "{'materials':1,'biotech':2,'programming':3}" - known = 1 - var/mobname = "John Doe" - -/obj/item/implant/death_alarm/get_data() - return {" - Implant Specifications:
              - Name: [GLOB.using_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor
              - Life: Activates upon death.
              - Important Notes: Alerts crew to crewmember death.
              -
              - Implant Details:
              - Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
              - Special Features: Alerts crew to crewmember death.
              - Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} - -/obj/item/implant/death_alarm/islegal() - return TRUE - -/obj/item/implant/death_alarm/Process() - if (!implanted) return - var/mob/M = imp_in - - if(isnull(M)) // If the mob got gibbed - activate(null) - else if(M.stat == DEAD) - activate("death") - -/obj/item/implant/death_alarm/activate(var/cause = "emp") - if(malfunction) return - var/mob/M = imp_in - var/area/t = get_area(M) - var/location = t.name - if (cause == "emp" && prob(50)) - location = pick(teleportlocs) - if(!t.requires_power) // We assume areas that don't use power are some sort of special zones - var/area/default = world.area - location = initial(default.name) - var/death_message = "[mobname] has died in [location]!" - if(!cause) - death_message = "[mobname] has died-zzzzt in-in-in..." - STOP_PROCESSING(SSobj, src) - - for(var/channel in list("Security", "Medical", "Command")) - GLOB.global_headset.autosay(death_message, "[mobname]'s Death Alarm", channel) - -/obj/item/implant/death_alarm/disable() - . = ..() - if(.) - STOP_PROCESSING(SSobj, src) - -/obj/item/implant/death_alarm/restore() - . = ..() - if(.) - START_PROCESSING(SSobj, src) - -/obj/item/implant/death_alarm/meltdown() - . = ..() - STOP_PROCESSING(SSobj, src) - -/obj/item/implant/death_alarm/implanted(mob/source) - mobname = source.real_name - START_PROCESSING(SSobj, src) - return TRUE - -/obj/item/implant/death_alarm/removed() - ..() - STOP_PROCESSING(SSobj, src) - -/obj/item/implantcase/death_alarm - name = "glass case - 'death alarm'" - imp = /obj/item/implant/death_alarm \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/explosive.dm b/code/game/objects/items/weapons/implants/implants/explosive.dm deleted file mode 100644 index 5d51df8a3a60..000000000000 --- a/code/game/objects/items/weapons/implants/implants/explosive.dm +++ /dev/null @@ -1,173 +0,0 @@ -//BS12 Explosive -/obj/item/implant/explosive - name = "explosive implant" - desc = "A military grade micro bio-explosive. Highly dangerous." - icon_state = "implant_evil" - origin_tech = "{'materials':1,'biotech':2,'esoteric':3}" - hidden = 1 - var/elevel - var/phrase - var/code = 13 - var/frequency = 1443 - var/datum/radio_frequency/radio_connection - var/warning_message = "Tampering detected. Tampering detected." - -/obj/item/implant/explosive/get_data() - . = {" - Implant Specifications:
              - Name: Robust Corp RX-78 Intimidation Class Implant
              - Life: Activates upon codephrase.
              - Important Notes: Explodes
              -
              - Implant Details:
              - Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
              - Special Features: Explodes
              - Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} - if(!malfunction) - . += {" -
              Explosion yield mode:
              - [elevel ? elevel : "NONE SET"]
              - Activation phrase:
              - [phrase ? phrase : "NONE SET"]
              - Frequency:
              - - - - - [format_frequency(src.frequency)] - + - +
              - Code:
              - - - - - [src.code] - + - +
              - Tampering warning message:
              - This will be broadcasted on radio if implant is exposed during surgery.
              - [warning_message ? warning_message : "NONE SET"] - "} - -/obj/item/implant/explosive/Initialize() - . = ..() - GLOB.listening_objects += src - set_frequency(frequency) - -/obj/item/implant/explosive/Topic(href, href_list) - ..() - if (href_list["freq"]) - var/new_frequency = frequency + text2num(href_list["freq"]) - new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) - set_frequency(new_frequency) - interact(usr) - if (href_list["code"]) - var/adj = text2num(href_list["code"]) - if(!adj) - code = input("Set radio activation code","Radio activation") as num - else - code += adj - code = Clamp(code,1,100) - interact(usr) - if (href_list["mode"]) - var/mod = input("Set explosion mode", "Explosion mode") as null|anything in list("Localized Limb", "Destroy Body", "Full Explosion") - if(mod) - elevel = mod - interact(usr) - if (href_list["msg"]) - var/msg = input("Set tampering message, or leave blank for no broadcasting.", "Anti-tampering", warning_message) as text|null - if(msg) - warning_message = msg - interact(usr) - if (href_list["phrase"]) - var/talk = input("Set activation phrase", "Audio activation", phrase) as text|null - if(talk) - phrase = sanitize_phrase(talk) - interact(usr) - -/obj/item/implant/explosive/receive_signal(datum/signal/signal) - if(signal && signal.encryption == code) - activate() - -/obj/item/implant/explosive/proc/set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) - -/obj/item/implant/explosive/hear_talk(mob/M, msg) - hear(msg) - -/obj/item/implant/explosive/hear(var/msg) - if(!phrase) - return - if(findtext(sanitize_phrase(msg),phrase)) - activate() - qdel(src) - -/obj/item/implant/explosive/exposed() - if(warning_message) - GLOB.global_headset.autosay(warning_message, "Anti Tampering System") - -/obj/item/implant/explosive/proc/sanitize_phrase(phrase) - var/list/replacechars = list("'" = "","\"" = "",">" = "","<" = "","(" = "",")" = "") - return replace_characters(phrase, replacechars) - -/obj/item/implant/explosive/activate() - if (malfunction) - return - - var/turf/T = get_turf(src) - if(T) - T.hotspot_expose(3500,125) - - playsound(loc, 'sound/items/countdown.ogg', 75, 1, -3) - if(ismob(imp_in)) - imp_in.audible_message("Something beeps inside [imp_in][part ? "'s [part.name]" : ""]!") - log_and_message_admins("Explosive implant triggered in [imp_in] ([imp_in.key]). (JMP) ") - else - audible_message("[src] beeps omniously!") - log_and_message_admins("Explosive implant triggered in [T.loc]. (JMP) ") - - if(!elevel) - elevel = "Full Explosion" - switch(elevel) - if ("Localized Limb") - if (part) - if (istype(part,/obj/item/organ/external/chest) || \ - istype(part,/obj/item/organ/external/groin)) - part.take_external_damage(60, used_weapon = "Explosion") - else - part.droplimb(0,DROPLIMB_BLUNT) - explosion(T, -1, -1, 2, 3) - if ("Destroy Body") - explosion(T, -1, 0, 1, 6) - if(ismob(imp_in)) - imp_in.gib() - if ("Full Explosion") - explosion(T, 0, 1, 3, 6) - if(ismob(imp_in)) - imp_in.gib() - qdel(src) - -/obj/item/implant/explosive/implanted(mob/target) - if(!elevel) - elevel = alert("What sort of explosion would you prefer?", "Implant Intent", "Localized Limb", "Destroy Body", "Full Explosion") - if(!phrase) - phrase = sanitize_phrase(input("Choose activation phrase:") as text) - if(!phrase) - return - - var/memo = "Explosive implant in [target] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate. It can also be triggered with a radio signal on frequency [format_frequency(src.frequency)] with code [code]." - usr.StoreMemory(memo, /decl/memory_options/system) - to_chat(usr, memo) - return TRUE - -/obj/item/implant/explosive/Destroy() - removed() - GLOB.listening_objects -= src - return ..() - -/obj/item/implanter/explosive - name = "implanter (E)" - imp = /obj/item/implant/explosive - -/obj/item/implantcase/explosive - name = "glass case - 'explosive'" - imp = /obj/item/implant/explosive \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/freedom.dm b/code/game/objects/items/weapons/implants/implants/freedom.dm deleted file mode 100644 index 14542292ae95..000000000000 --- a/code/game/objects/items/weapons/implants/implants/freedom.dm +++ /dev/null @@ -1,62 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/implant/freedom - name = "freedom implant" - desc = "Use this to escape from those evil Red Shirts." - origin_tech = "{'materials':1,'biotech':2,'esoteric':2}" - implant_color = "r" - hidden = 1 - var/activation_emote - var/uses - -/obj/item/implant/freedom/get_data() - return {" - Implant Specifications:
              - Name: Freedom Beacon
              - Life: optimum 5 uses
              - Important Notes: Illegal
              -
              - Implant Details:
              - Function: Transmits a specialized cluster of signals to override handcuff locking - mechanisms
              - Special Features:
              - Neuro-Scan- Analyzes certain shadow signals in the nervous system
              - Integrity: The battery is extremely weak and commonly after injection its - life can drive down to only 1 use.
              - No Implant Specifics"} - -/obj/item/implant/freedom/Initialize() - . = ..() - uses = rand(1, 5) - -/obj/item/implant/freedom/trigger(emote, mob/living/carbon/source) - if (emote == activation_emote) - activate() - -/obj/item/implant/freedom/activate() - if(uses < 1 || malfunction) return 0 - if(remove_cuffs_and_unbuckle(imp_in)) - uses-- - to_chat(imp_in, "You feel a faint click.") - -/obj/item/implant/freedom/proc/remove_cuffs_and_unbuckle(mob/living/carbon/user) - if(!user.handcuffed) - return 0 - . = user.unEquip(user.handcuffed) - if(. && user.buckled && user.buckled.buckle_require_restraints) - user.buckled.unbuckle_mob() - return - -/obj/item/implant/freedom/implanted(mob/living/carbon/source) - src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") - source.StoreMemory("Freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", /decl/memory_options/system) - to_chat(source, "The implanted freedom implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") - return TRUE - -/obj/item/implanter/freedom - name = "implanter (F)" - imp = /obj/item/implant/freedom - -/obj/item/implantcase/freedom - name = "glass case - 'freedom'" - imp = /obj/item/implant/freedom \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/imprinting.dm b/code/game/objects/items/weapons/implants/implants/imprinting.dm deleted file mode 100644 index bc29de9a6729..000000000000 --- a/code/game/objects/items/weapons/implants/implants/imprinting.dm +++ /dev/null @@ -1,123 +0,0 @@ -/obj/item/implant/imprinting - name = "imprinting implant" - desc = "Latest word in training your peons." - origin_tech = "{'materials':1,'biotech':2,'programming':3}" - hidden = 1 - var/list/instructions = list("Do your job.", "Respect your superiors.", "Wash you hands after using the toilet.") - var/brainwashing = 0 - -/obj/item/implant/imprinting/get_data() - . = {" - Implant Specifications:
              - Name: BB-56 "Educator" Employee Assistance Implant
              - Life: 1 year.
              -
              - Function: Adjusts itself to host's brainwaves, and presents supplied instructions as their 'inner voice' for less intrusive reminding. It will transmit them every 5 minutes in non-obtrusive manner.
              - Special Features: Do NOT implant if subject is under effect of any mind-altering drugs. - It carries risk of over-tuning, making subject unable to question the suggestions received, treating them as beliefs they feel strongly about.
              - It is HIGLY ILLEGAL and the seller does NOT endorse use of this device in such way. - Any amount of "Mind-Breaker"(TM) present in bloodstream will trigger this side-effect.
              "} - . += "
              Instructions:
              " - for(var/i = 1 to instructions.len) - . += "- [instructions[i]] Edit Remove
              " - . += "Add" - -/obj/item/implant/imprinting/Topic(href, href_list) - ..() - if (href_list["add"]) - var/mod = sanitize(input("Add an instruction", "Instructions") as text|null) - if(mod) - instructions += mod - interact(usr) - if (href_list["edit"]) - var/idx = text2num(href_list["edit"]) - var/mod = sanitize(input("Edit the instruction", "Instruction Editing", instructions[idx]) as text|null) - if(mod) - instructions[idx] = mod - interact(usr) - if (href_list["del"]) - instructions -= instructions[text2num(href_list["del"])] - interact(usr) - -/obj/item/implant/imprinting/implanted(mob/M) - var/mob/living/carbon/human/H = M - if(!istype(H)) - return FALSE - if(H.reagents.has_reagent(/decl/material/liquid/hallucinogenics)) - brainwashing = 1 - var/msg = get_instructions() - to_chat(M, msg) - if(M.mind) - M.StoreMemory(msg, /decl/memory_options/system) - if(brainwashing) - log_and_message_admins("was implanted with a brainwashing implant holding following laws: [jointext(instructions, ";")].", M) - addtimer(CALLBACK(src,.proc/activate),3000,(TIMER_UNIQUE|TIMER_OVERRIDE)) - return TRUE - -/obj/item/implant/imprinting/proc/get_instructions() - . = list() - if(brainwashing) - . += "The fog in your head clears, and you remember some important things. You hold following things as deep convictions, almost like synthetics' laws:
              " - else - . += "You hear an annoying voice in the back of your head. The things it keeps reminding you of:
              " - for(var/thing in instructions) - . += "- [thing]
              " - . = JOINTEXT(.) - -/obj/item/implant/imprinting/disable(time) - . = ..() - if(. && brainwashing)//add deactivate and reactivate messages? - to_chat(imp_in,"A wave of nausea comes over you.
              You are no longer so sure of those beliefs you've had...") - -/obj/item/implant/imprinting/restore() - . = ..() - if(. && brainwashing) - to_chat(imp_in, get_instructions()) - activate() - -/obj/item/implant/imprinting/activate() - if(malfunction || !implanted || imp_in) return - var/instruction = pick(instructions) - if(brainwashing) - instruction = "You recall one of your beliefs: \"[instruction]\"" - else - instruction = "You remember suddenly: \"[instruction]\"" - to_chat(imp_in, instruction) - addtimer(CALLBACK(src,.proc/activate),3000,(TIMER_UNIQUE|TIMER_OVERRIDE)) - -/obj/item/implant/imprinting/removed() - if(brainwashing && !malfunction) - to_chat(imp_in,"A wave of nausea comes over you.
              You are no longer so sure of those beliefs you've had...") - ..() - -/obj/item/implant/imprinting/emp_act(severity) - var/power = 4 - severity - if(prob(power * 15)) - meltdown() - else if(prob(power * 40)) - disable(rand(power*100,power*1000))//a few precious seconds of freedom - -/obj/item/implant/imprinting/meltdown() - if(brainwashing && !malfunction)//if it's already broken don't send the message again - to_chat(imp_in,"A wave of nausea comes over you.
              You are no longer so sure of those beliefs you've had...") - . = ..() - -/obj/item/implant/imprinting/can_implant(mob/M, mob/user, target_zone) - var/mob/living/carbon/human/H = M - if(istype(H)) - var/obj/item/organ/internal/B = H.internal_organs_by_name[BP_BRAIN] - if(!B || H.isSynthetic()) - to_chat(user, "\The [M] cannot be imprinted.") - return FALSE - if(!(B.parent_organ == check_zone(target_zone))) - to_chat(user, "\The [src] must be implanted in [H.get_organ(B.parent_organ)].") - return FALSE - return TRUE - -/obj/item/implanter/imprinting - name = "imprinting implanter" - imp = /obj/item/implant/imprinting - -/obj/item/implantcase/imprinting - name = "glass case - 'imprinting'" - imp = /obj/item/implant/imprinting \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/loyalty.dm b/code/game/objects/items/weapons/implants/implants/loyalty.dm deleted file mode 100644 index f944f625a587..000000000000 --- a/code/game/objects/items/weapons/implants/implants/loyalty.dm +++ /dev/null @@ -1,37 +0,0 @@ -/obj/item/implant/loyalty - name = "loyalty implant" - desc = "Makes you loyal or such." - origin_tech = "{'materials':1,'biotech':2,'esoteric':3}" - known = 1 - -/obj/item/implant/loyalty/get_data() - return {" - Implant Specifications:
              - Name: [GLOB.using_map.company_name] Employee Management Implant
              - Life: Ten years.
              - Important Notes: Personnel injected with this device tend to be much more loyal to the company.
              -
              - Implant Details:
              - Function: Contains a small pod of nanobots that manipulate the host's mental functions.
              - Special Features: Will prevent and cure most forms of brainwashing.
              - Integrity: Implant will last so long as the nanobots are inside the bloodstream."} - -/obj/item/implant/loyalty/implanted(mob/M) - if(!istype(M, /mob/living/carbon/human)) return FALSE - var/mob/living/carbon/human/H = M - var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) - if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE)) - H.visible_message("[H] seems to resist the implant!", "You feel the corporate tendrils of [GLOB.using_map.company_name] try to invade your mind!") - return FALSE - else - clear_antag_roles(H.mind, 1) - to_chat(H, "You feel a surge of loyalty towards [GLOB.using_map.company_name].") - return TRUE - -/obj/item/implanter/loyalty - name = "implanter-loyalty" - imp = /obj/item/implant/loyalty - -/obj/item/implantcase/loyalty - name = "glass case - 'loyalty'" - imp = /obj/item/implant/loyalty \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/tracking.dm b/code/game/objects/items/weapons/implants/implants/tracking.dm deleted file mode 100644 index 6c6168108e6a..000000000000 --- a/code/game/objects/items/weapons/implants/implants/tracking.dm +++ /dev/null @@ -1,47 +0,0 @@ -/obj/item/implant/tracking - name = "tracking implant" - desc = "Track with this." - origin_tech = "{'materials':1,'biotech':2,'wormholes':2}" - known = 1 - var/id = 1 - -/obj/item/implant/tracking/get_data() - . = {"Implant Specifications:
              - Name: Tracking Beacon
              - Life: 10 minutes after death of host
              - Important Notes: None
              -
              - Implant Details:
              - Function: Continuously transmits low power signal. Useful for tracking.
              - Special Features:
              - Neuro-Safe- Specialized shell absorbs excess voltages self-destructing the chip if - a malfunction occurs thereby securing safety of subject. The implant will melt and - disintegrate into bio-safe elements.
              - Integrity: Gradient creates slight risk of being overcharged and frying the - circuitry. As a result neurotoxins can cause massive damage.
              "} - if(!malfunction) - .+= {"ID (1-100):
              - - - - [id] - + - +
              "} - -/obj/item/implant/tracking/Topic(href, href_list) - ..() - if (href_list["tracking_id"]) - id = Clamp(id+text2num(href_list["tracking_id"]), 1, 100) - interact(usr) - -/obj/item/implant/tracking/islegal() - return TRUE - -/obj/item/implant/tracking/emp_act(severity) - var/power = 4 - severity - if(prob(power * 15)) - meltdown() - else if(prob(power * 40)) - disable(rand(power*500,power*5000))//adds in extra time because this is the only other way to sabotage it - -/obj/item/implantcase/tracking - name = "glass case - 'tracking'" - imp = /obj/item/implant/tracking \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/translator.dm b/code/game/objects/items/weapons/implants/implants/translator.dm deleted file mode 100644 index bec7bd87bf1e..000000000000 --- a/code/game/objects/items/weapons/implants/implants/translator.dm +++ /dev/null @@ -1,49 +0,0 @@ -//Implant that lets you learn languages by hearing them -/obj/item/implant/translator - name = "babel implant" - desc = "A small implant with a microphone on it." - icon_state = "implant_evil" - origin_tech = "{'materials':1,'biotech':2,'esoteric':3}" - hidden = 1 - var/list/languages = list() - var/learning_threshold = 20 //need to hear language spoken this many times to learn it - var/max_languages = 5 - -/obj/item/implant/translator/get_data() - return "WARNING: No match found in the database." - -/obj/item/implant/translator/Initialize() - . = ..() - GLOB.listening_objects += src - -/obj/item/implant/translator/hear_talk(mob/M, msg, verb, decl/language/speaking) - if(!imp_in) - return - if(length(languages) == max_languages) - return - if(!languages[speaking.name]) - languages[speaking.name] = 1 - languages[speaking.name] = languages[speaking.name] + 1 - if(!imp_in.say_understands(M, speaking) && languages[speaking.name] > learning_threshold) - to_chat(imp_in, SPAN_NOTICE("You feel like you can understand [speaking.name] now...")) - imp_in.add_language(speaking.type) - -/obj/item/implant/translator/implanted(mob/target) - return TRUE - -/obj/item/implant/translator/Destroy() - removed() - GLOB.listening_objects -= src - return ..() - -/obj/item/implanter/translator - name = "babel implanter" - imp = /obj/item/implant/translator - -/obj/item/implant/translator/natural - name = "lingophagic node" - desc = "A chunk of what could be discolored crystalized brain matter. It seems to pulse occasionally." - icon_state = "implant_melted" - origin_tech = "{'biotech':5}" - learning_threshold = 10 - max_languages = 3 \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implants/uplink.dm b/code/game/objects/items/weapons/implants/implants/uplink.dm deleted file mode 100644 index fa377b563f49..000000000000 --- a/code/game/objects/items/weapons/implants/implants/uplink.dm +++ /dev/null @@ -1,34 +0,0 @@ -/obj/item/implant/uplink - name = "uplink implant" - desc = "Summon things." - origin_tech = "{'materials':1,'biotech':2,'esoteric':3}" - hidden = 1 - var/activation_emote - -/obj/item/implant/uplink/Initialize(mapload, var/amount) - amount = amount || IMPLANT_TELECRYSTAL_AMOUNT(DEFAULT_TELECRYSTAL_AMOUNT) - hidden_uplink = new(src, null, amount) - . = ..() - -/obj/item/implant/uplink/implanted(mob/source) - var/emote_options = list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") - activation_emote = source.client ? (input(source, "Choose activation emote:", "Uplink Implant Setup") in emote_options) : emote_options[1] - source.StoreMemory("Uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", /decl/memory_options/system) - to_chat(source, "The implanted uplink implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") - hidden_uplink.uplink_owner = source.mind - return TRUE - -/obj/item/implant/uplink/trigger(emote, mob/source) - if(hidden_uplink && usr == source && !malfunction) // Let's not have another people activate our uplink - hidden_uplink.check_trigger(source, emote, activation_emote) - -/obj/item/implant/uplink/emp_act(severity) - var/power = 4 - severity - if(prob(power)) - meltdown() - else if(prob(power * 40)) - disable(rand(power*100,power*1000)) - -/obj/item/implanter/uplink - name = "implanter (U)" - imp = /obj/item/implant/uplink diff --git a/code/game/objects/items/weapons/ironing_iron.dm b/code/game/objects/items/weapons/ironing_iron.dm index 0f5ea12d6cef..3728c1d10774 100644 --- a/code/game/objects/items/weapons/ironing_iron.dm +++ b/code/game/objects/items/weapons/ironing_iron.dm @@ -5,15 +5,14 @@ icon_state = "iron" item_state = "ironingiron" w_class = ITEM_SIZE_NORMAL - throwforce = 10 throw_speed = 2 throw_range = 10 - force = 8.0 attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed") - + material = /decl/material/solid/metal/steel + _base_attack_force = 8 var/enabled = 0 /obj/item/ironingiron/attack_self(var/mob/user) enabled = !enabled - to_chat(user, "You turn \the [src.name] [enabled ? "on" : "off"].") + to_chat(user, "You turn \the [src] [enabled ? "on" : "off"].") ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/janitor_sign.dm b/code/game/objects/items/weapons/janitor_sign.dm index 4bf20c4e325c..77ec3b33607a 100644 --- a/code/game/objects/items/weapons/janitor_sign.dm +++ b/code/game/objects/items/weapons/janitor_sign.dm @@ -3,12 +3,12 @@ name = "wet floor sign" icon = 'icons/obj/janitor.dmi' icon_state = "caution" - force = 1.0 - throwforce = 3.0 throw_speed = 1 throw_range = 5 w_class = ITEM_SIZE_SMALL attack_verb = list("warned", "cautioned", "smashed") + material = /decl/material/solid/organic/plastic + _base_attack_force = 1 /obj/item/caution/cone desc = "This cone is trying to warn you of something!" diff --git a/code/game/objects/items/weapons/lighter.dm b/code/game/objects/items/weapons/lighter.dm deleted file mode 100644 index 37154b85307d..000000000000 --- a/code/game/objects/items/weapons/lighter.dm +++ /dev/null @@ -1,207 +0,0 @@ -/obj/item/flame/lighter - name = "lighter" - desc = "A cheap-as-free lighter." - icon = 'icons/obj/items/lighters.dmi' - icon_state = "lighter" - item_state = "lighter" - w_class = ITEM_SIZE_TINY - throwforce = 4 - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - attack_verb = list("burnt", "singed") - lit_heat = 1500 - var/max_fuel = 5 - var/random_colour = FALSE - var/available_colors = list(COLOR_WHITE, COLOR_BLUE_GRAY, COLOR_GREEN_GRAY, COLOR_BOTTLE_GREEN, COLOR_DARK_GRAY, COLOR_RED_GRAY, COLOR_GUNMETAL, COLOR_RED, COLOR_YELLOW, COLOR_CYAN, COLOR_GREEN, COLOR_VIOLET, COLOR_NAVY_BLUE, COLOR_PINK) - -/obj/item/flame/lighter/Initialize() - . = ..() - create_reagents(max_fuel) - reagents.add_reagent(/decl/material/liquid/fuel, max_fuel) - set_extension(src, /datum/extension/base_icon_state, icon_state) - if(random_colour) - color = pick(available_colors) - update_icon() - -/obj/item/flame/lighter/proc/light(mob/user) - if(submerged()) - to_chat(user, "You cannot light \the [src] underwater.") - return - lit = 1 - update_icon() - light_effects(user) - set_light(0.6, 0.5, 2, l_color = COLOR_PALE_ORANGE) - START_PROCESSING(SSobj, src) - -/obj/item/flame/lighter/proc/light_effects(mob/living/carbon/user) - if(prob(95)) - user.visible_message("After a few attempts, [user] manages to light the [src].") - else - to_chat(user, "You burn yourself while lighting the lighter.") - if (user.l_hand == src) - user.apply_damage(2,BURN,BP_L_HAND) - else - user.apply_damage(2,BURN,BP_R_HAND) - user.visible_message("After a few attempts, [user] manages to light the [src], burning their finger in the process.") - playsound(src.loc, "light_bic", 100, 1, -4) - -/obj/item/flame/lighter/extinguish(var/mob/user, var/no_message) - ..() - update_icon() - if(user) - shutoff_effects(user) - else if(!no_message) - visible_message("[src] goes out.") - set_light(0) - -/obj/item/flame/lighter/proc/shutoff_effects(mob/user) - user.visible_message("[user] quietly shuts off the [src].") - -/obj/item/flame/lighter/attack_self(mob/living/user) - if(!lit) - if(reagents.has_reagent(/decl/material/liquid/fuel)) - light(user) - else - to_chat(user, "\The [src] won't ignite - it must be out of fuel.") - else - extinguish(user) - -/obj/item/flame/lighter/on_update_icon() - var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) - - overlays.Cut() - if(lit) - overlays += overlay_image(icon, "[bis.base_icon_state]_flame", flags=RESET_COLOR) - else - overlays += overlay_image(icon, "[bis.base_icon_state]_striker", flags=RESET_COLOR) - -/obj/item/flame/lighter/attack(var/mob/living/M, var/mob/living/carbon/user) - if(!istype(M, /mob)) - return - - if(lit) - M.IgniteMob() - - if(istype(M.wear_mask, /obj/item/clothing/mask/smokable/cigarette) && user.zone_sel.selecting == BP_MOUTH) - var/obj/item/clothing/mask/smokable/cigarette/cig = M.wear_mask - if(M == user) - cig.attackby(src, user) - else - cig.light("[user] holds the [name] out for [M], and lights the [cig.name].") - return - ..() - -/obj/item/flame/lighter/Process() - if(!submerged() && reagents.has_reagent(/decl/material/liquid/fuel)) - if(ismob(loc) && prob(10) && REAGENT_VOLUME(reagents, /decl/material/liquid/fuel) < 1) - to_chat(loc, "\The [src]'s flame flickers.") - set_light(0) - addtimer(CALLBACK(src, .atom/proc/set_light, 0.6, 0.5, 2), 4) - reagents.remove_reagent(/decl/material/liquid/fuel, 0.05) - else - extinguish() - return - - var/turf/location = get_turf(src) - if(location) - location.hotspot_expose(700, 5) - -/obj/item/flame/lighter/red - color = COLOR_RED - name = "red lighter" - -/obj/item/flame/lighter/yellow - color = COLOR_YELLOW - name = "yellow lighter" - -/obj/item/flame/lighter/cyan - color = COLOR_CYAN - name = "cyan lighter" - -/obj/item/flame/lighter/green - color = COLOR_GREEN - name = "green lighter" - -/obj/item/flame/lighter/pink - color = COLOR_PINK - name = "pink lighter" - -/obj/item/flame/lighter/random - random_colour = TRUE - -/****** - Zippo -******/ -/obj/item/flame/lighter/zippo - name = "zippo lighter" - desc = "It's a zippo-styled lighter, using a replacable flint in a fetching steel case. It makes a clicking sound that everyone loves." - icon_state = "zippo" - item_state = "zippo" - max_fuel = 10 - available_colors = list(COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_DARK_GRAY, COLOR_GUNMETAL, COLOR_BRONZE, COLOR_BRASS) - -/obj/item/flame/lighter/zippo/on_update_icon() - var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) - - overlays.Cut() - if(lit) - icon_state = "[bis.base_icon_state]_open" - item_state = "[bis.base_icon_state]_open" - overlays += overlay_image(icon, "[bis.base_icon_state]_flame", flags=RESET_COLOR) - else - icon_state = "[bis.base_icon_state]" - item_state = "[bis.base_icon_state]" - -/obj/item/flame/lighter/zippo/light_effects(mob/user) - user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.") - playsound(src.loc, 'sound/items/zippo_open.ogg', 100, 1, -4) - -/obj/item/flame/lighter/zippo/shutoff_effects(mob/user) - user.visible_message("You hear a quiet click, as [user] shuts off [src] without even looking at what they're doing.") - playsound(src.loc, 'sound/items/zippo_close.ogg', 100, 1, -4) - -/obj/item/flame/lighter/zippo/afterattack(obj/O, mob/user, proximity) - if(!proximity) return - if (istype(O, /obj/structure/reagent_dispensers/fueltank) && !lit) - O.reagents.trans_to_obj(src, max_fuel) - to_chat(user, "You refuel [src] from \the [O]") - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - -/obj/item/flame/lighter/zippo/black - color = COLOR_DARK_GRAY - name = "black zippo" - -/obj/item/flame/lighter/zippo/gunmetal - color = COLOR_GUNMETAL - name = "gunmetal zippo" - -/obj/item/flame/lighter/zippo/brass - color = COLOR_BRASS - name = "brass zippo" - -/obj/item/flame/lighter/zippo/bronze - color = COLOR_BRONZE - name = "bronze zippo" - -/obj/item/flame/lighter/zippo/pink - color = COLOR_PINK - name = "pink zippo" - -//Spawn using the colour list in the master type -/obj/item/flame/lighter/zippo/random - random_colour = TRUE - -//Legacy icon states for custom items -/obj/item/flame/lighter/zippo/custom/Initialize() - . = ..() - color = null - -/obj/item/flame/lighter/zippo/custom/on_update_icon() - var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) - - if(lit) - icon_state = "[bis.base_icon_state]_on" - item_state = "[bis.base_icon_state]_on" - else - icon_state = "[bis.base_icon_state]" - item_state = "[bis.base_icon_state]" \ No newline at end of file diff --git a/code/game/objects/items/weapons/locator.dm b/code/game/objects/items/weapons/locator.dm new file mode 100644 index 000000000000..fc5bcf8b0fc8 --- /dev/null +++ b/code/game/objects/items/weapons/locator.dm @@ -0,0 +1,101 @@ +/* + * Locator + */ +/obj/item/locator + name = "locator" + desc = "Used to track those with locator implants." + icon = 'icons/obj/items/device/locator.dmi' + icon_state = ICON_STATE_WORLD + var/temp = null + var/frequency = 1451 + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + throw_speed = 4 + throw_range = 20 + origin_tech = @'{"magnets":1}' + material = /decl/material/solid/metal/aluminium + +/obj/item/locator/attack_self(mob/user) + user.set_machine(src) + var/dat + if (src.temp) + dat = "[src.temp]

              Clear" + else + dat = {" +Persistent Signal Locator
              +Frequency: +- +- [format_frequency(src.frequency)] ++ ++
              + +Refresh"} + show_browser(user, dat, "window=radio") + onclose(user, "radio") + return + +/obj/item/locator/OnTopic(mob/user, href_list, datum/topic_state/state) + var/turf/current_location = get_turf(user) //What turf is the user on? + if(!current_location || isAdminLevel(current_location.z)) //If turf was not found or they're on an admin Z-level + to_chat(user, "\The [src] is malfunctioning.") + return + if(!CanPhysicallyInteract(user)) + return + user.set_machine(src) + if (href_list["refresh"]) + src.temp = "Persistent Signal Locator
              " + var/turf/source_turf = get_turf(src) + if (!source_turf) + src.temp += "Processing Error: Unable to locate orbital position.
              " + return TOPIC_REFRESH + src.temp += "Located Beacons:
              " + for(var/obj/item/radio/beacon/radio in global.radio_beacons) + if(!radio.functioning) + continue + if (radio.frequency != frequency) + continue + var/turf/radio_turf = get_turf(radio) + if (radio_turf.z != source_turf.z || !radio_turf) + continue + var/distance + switch(get_dist(radio_turf, source_turf)) + if(0 to 5) + distance = "very strong" + if(6 to 10) + distance = "strong" + if(11 to 20) + distance = "weak" + else + continue + if(distance) + src.temp += "[radio.code]-[dir2text(get_dir(source_turf, radio_turf))]-[distance]
              " + + src.temp += "Extraneous Signals:
              " + for (var/obj/item/implant/tracking/implant in global.tracking_implants) + if (!implant.implanted || !(istype(implant.loc,/obj/item/organ/external) || ismob(implant.loc))) + continue + var/mob/victim = implant.loc + // Don't show dead people that have been dead for a while + if (victim.stat == DEAD && world.time > victim.timeofdeath + 10 MINUTES) + continue + var/turf/implant_turf = get_turf(implant) + if (implant_turf?.z != source_turf.z) + continue + var/distance + switch(get_dist(implant_turf, source_turf)) + if(0 to 5) + distance = "very strong" + if(6 to 10) + distance = "strong" + if(11 to 20) + distance = "weak" + if(distance) + src.temp += "[implant.id]-[dir2text(get_dir(source_turf, implant_turf))]-[distance]
              " + + src.temp += "You are at \[[source_turf.x],[source_turf.y],[source_turf.z]\] in orbital coordinates.

              Refresh
              " + else if (href_list["freq"]) + src.frequency += text2num(href_list["freq"]) + src.frequency = sanitize_frequency(src.frequency) + else if (href_list["temp"]) + src.temp = null + return TOPIC_REFRESH diff --git a/code/game/objects/items/weapons/material/ashtray.dm b/code/game/objects/items/weapons/material/ashtray.dm index b07cd17aca4e..34a48cec61b4 100644 --- a/code/game/objects/items/weapons/material/ashtray.dm +++ b/code/game/objects/items/weapons/material/ashtray.dm @@ -3,74 +3,61 @@ desc = "A thing to keep your butts in." icon = 'icons/obj/objects.dmi' icon_state = "ashtray" - material_force_multiplier = 0.1 - thrown_material_force_multiplier = 0.1 randpixel = 5 material = /decl/material/solid/metal/bronze - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC var/max_butts = 10 -/obj/item/ashtray/examine(mob/user) +/obj/item/ashtray/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(material) - to_chat(user, "It's made of [material.solid_name].") if(contents.len >= max_butts) - to_chat(user, "It's full.") + . += SPAN_WARNING("It's full.") else if(contents.len) - to_chat(user, "It has [contents.len] cig butts in it.") + . += "It has [contents.len] cigarette butt\s in it." /obj/item/ashtray/on_update_icon() - ..() - overlays.Cut() + . = ..() if (contents.len == max_butts) - overlays |= image('icons/obj/objects.dmi',"ashtray_full") + add_overlay("ashtray_full") else if (contents.len >= max_butts/2) - overlays |= image('icons/obj/objects.dmi',"ashtray_half") + add_overlay("ashtray_half") -/obj/item/ashtray/attackby(obj/item/W, mob/user) - if (health <= 0) - return - if (istype(W,/obj/item/trash/cigbutt) || istype(W,/obj/item/clothing/mask/smokable/cigarette) || istype(W, /obj/item/flame/match)) +/obj/item/ashtray/attackby(obj/item/used_item, mob/user) + if (istype(used_item,/obj/item/trash/cigbutt) || istype(used_item,/obj/item/clothing/mask/smokable/cigarette) || istype(used_item, /obj/item/flame/match)) if (contents.len >= max_butts) to_chat(user, "\The [src] is full.") - return + return TRUE - if (istype(W,/obj/item/clothing/mask/smokable/cigarette)) - var/obj/item/clothing/mask/smokable/cigarette/cig = W + if (istype(used_item,/obj/item/clothing/mask/smokable/cigarette)) + var/obj/item/clothing/mask/smokable/cigarette/cig = used_item if (cig.lit == 1) visible_message(SPAN_NOTICE("\The [user] crushes \the [cig] in \the [src], putting it out.")) - W = cig.extinguish(no_message = 1) + used_item = cig.extinguish_fire(no_message = TRUE) else if (cig.lit == 0) to_chat(user, SPAN_NOTICE("You place \the [cig] in \the [src] without even smoking it. Why would you do that?")) else - visible_message(SPAN_NOTICE("\The [user] places \the [W] in \the [src].")) + visible_message(SPAN_NOTICE("\The [user] places \the [used_item] in \the [src].")) - if(user.unEquip(W, src)) + if(user.try_unequip(used_item, src)) set_extension(src, /datum/extension/scent/ashtray) update_icon() - else - ..() - health = max(0,health - W.force) - if (health < 1) - shatter() + return TRUE + return ..() /obj/item/ashtray/throw_impact(atom/hit_atom) - if (health > 0) - health = max(0,health - 3) - if (contents.len) - visible_message("\The [src] slams into [hit_atom], spilling its contents!") - for (var/obj/O in contents) - O.dropInto(loc) - remove_extension(src, /datum/extension/scent) - if (health < 1) - shatter() - return + . = ..() + if(length(contents)) + visible_message(SPAN_DANGER("\The [src] slams into [hit_atom], spilling its contents!")) + dump_contents() + remove_extension(src, /datum/extension/scent) update_icon() - return ..() + take_damage(3, inflicter = hit_atom) /obj/item/ashtray/plastic - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic /obj/item/ashtray/glass material = /decl/material/solid/glass + +/obj/item/ashtray/bronze + material = /decl/material/solid/metal/bronze diff --git a/code/game/objects/items/weapons/material/bell.dm b/code/game/objects/items/weapons/material/bell.dm index 3c7b023224a5..05c21a0f3099 100644 --- a/code/game/objects/items/weapons/material/bell.dm +++ b/code/game/objects/items/weapons/material/bell.dm @@ -5,22 +5,22 @@ desc = "A bell to ring to get people's attention. Don't break it." icon = 'icons/obj/objects.dmi' icon_state = "bell" - thrown_material_force_multiplier = 0.3 hitsound = 'sound/items/oneding.ogg' material = /decl/material/solid/metal/aluminium - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME /obj/item/bell/attack_hand(mob/user) - if (user.a_intent == I_GRAB) + if(user.check_intent(I_FLAG_GRAB)) return ..() - else if (user.a_intent == I_HURT) + + if(user.check_intent(I_FLAG_HARM)) user.visible_message("\The [user] hammers \the [src]!") playsound(user.loc, 'sound/items/manydings.ogg', 60) else user.visible_message("\The [user] rings \the [src].") playsound(user.loc, 'sound/items/oneding.ogg', 20) flick("bell_dingeth", src) + return TRUE /obj/item/bell/apply_hit_effect() . = ..() diff --git a/code/game/objects/items/weapons/material/coins.dm b/code/game/objects/items/weapons/material/coins.dm index ce847fe0b2fc..7c63fbb4358f 100644 --- a/code/game/objects/items/weapons/material/coins.dm +++ b/code/game/objects/items/weapons/material/coins.dm @@ -1,57 +1,23 @@ /obj/item/coin name = "coin" + desc = "A small coin." icon = 'icons/obj/items/coin.dmi' icon_state = "coin1" - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME randpixel = 8 - force = 1 - throwforce = 1 - material_force_multiplier = 0.1 - thrown_material_force_multiplier = 0.1 w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - - var/currency_worth - var/absolute_worth - var/currency + material = /decl/material/solid/metal/steel + _base_attack_force = 1 var/can_flip = TRUE + var/datum/denomination/denomination /obj/item/coin/Initialize() . = ..() - - // Grab a coin from our currency to use for our worth/coin flipping. - if(!ispath(currency, /decl/currency)) - currency = GLOB.using_map.default_currency - if(isnull(absolute_worth)) - var/decl/currency/cur = decls_repository.get_decl(currency) - var/list/coins = list() - for(var/datum/denomination/denomination in cur.denominations) - if(denomination.faces) - coins += denomination - if(length(coins)) - var/datum/denomination/denomination = pick(coins) - currency_worth = denomination.marked_value - absolute_worth = Floor(denomination.marked_value / cur.absolute_value) - currency_worth = "[currency_worth]" - if(!absolute_worth || !currency_worth) - return INITIALIZE_HINT_QDEL - icon_state = "coin[rand(1,10)]" if(material) - desc = "A rather thick coin stamped out of [material.solid_name]." - else - desc = "A rather thick coin." - -/obj/item/coin/get_single_monetary_worth() - . = max(..(), absolute_worth) - -/obj/item/coin/examine(mob/user, distance) - . = ..() - if((distance <= 1 || loc == user) && user.skill_check(SKILL_FINANCE, SKILL_ADEPT)) - var/decl/currency/cur = decls_repository.get_decl(currency) - var/datum/denomination/denomination = cur.denominations_by_value[currency_worth] - to_chat(user, "It looks like an antiquated minting of \a [denomination.name].") + desc = "An old-style coin stamped out of [material.solid_name]." + set_extension(src, /datum/extension/tool, list(TOOL_SCREWDRIVER = TOOL_QUALITY_BAD)) // "Coin Flipping, A.wav" by InspectorJ (www.jshaw.co.uk) of Freesound.org /obj/item/coin/attack_self(var/mob/user) @@ -68,10 +34,8 @@ if(!can_flip) return - var/decl/currency/cur = decls_repository.get_decl(currency) - var/datum/denomination/denomination = cur.denominations_by_value[currency_worth] - - if(!denomination || !length(denomination.faces)) + var/list/faces = (denomination?.faces || list("heads", "tails")) + if(length(faces) <= 1) if(user) to_chat(user, SPAN_WARNING("\The [src] is not the right shape to be flipped.")) return @@ -111,9 +75,9 @@ if(!QDELETED(src)) if(!QDELETED(user) && loc == user && !thrown) - user.visible_message(SPAN_NOTICE("...and catches it, revealing that \the [src] landed on [rigged ? "on the side" : pick(denomination.faces)]!")) + user.visible_message(SPAN_NOTICE("...and catches it, revealing that \the [src] landed on [rigged ? "on the side" : pick(faces)]!")) else - visible_message(SPAN_NOTICE("\The [src] landed on [rigged ? "on the side" : pick(denomination.faces)]!")) + visible_message(SPAN_NOTICE("\The [src] landed on [rigged ? "on the side" : pick(faces)]!")) can_flip = TRUE @@ -121,6 +85,12 @@ ..() transform = null +/obj/item/coin/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(denomination && (distance <= 1 || loc == user) && user.skill_check(SKILL_FINANCE, SKILL_ADEPT)) + var/decl/currency/map_cur = GET_DECL(global.using_map.default_currency) + . += "It looks like an antiquated minting of \a [denomination.name]. These days it would be worth around [map_cur.format_value(get_combined_monetary_worth())]." + // Subtypes. /obj/item/coin/gold material = /decl/material/solid/metal/gold diff --git a/code/game/objects/items/weapons/material/folding.dm b/code/game/objects/items/weapons/material/folding.dm index 61a78d28d099..e5bcd0486741 100644 --- a/code/game/objects/items/weapons/material/folding.dm +++ b/code/game/objects/items/weapons/material/folding.dm @@ -1,12 +1,9 @@ - // folding/locking knives +// TODO: Replace these with or merge these into /obj/item/bladed/folding /obj/item/knife/folding name = "pocketknife" desc = "A small folding knife." icon = 'icons/obj/items/weapon/knives/folding/basic.dmi' - material_force_multiplier = 0.2 - applies_material_name = FALSE - unbreakable = TRUE w_class = ITEM_SIZE_SMALL attack_verb = list("prodded", "tapped") edge = FALSE @@ -14,13 +11,13 @@ draw_handle = TRUE valid_handle_colors = list(COLOR_DARK_GRAY, COLOR_RED_GRAY, COLOR_BLUE_GRAY, COLOR_DARK_BLUE_GRAY, COLOR_GREEN_GRAY, COLOR_DARK_GREEN_GRAY) material = /decl/material/solid/metal/steel - + material_alteration = MAT_FLAG_ALTERATION_COLOR var/open = FALSE var/closed_attack_verbs = list("prodded", "tapped") //initial doesnt work with lists, rip /obj/item/knife/folding/attack_self(mob/user) open = !open - update_force() + update_attack_force() update_icon() if(open) user.visible_message("\The [user] opens \the [src].") @@ -29,36 +26,29 @@ user.visible_message("\The [user] closes \the [src].") add_fingerprint(user) -/obj/item/knife/folding/update_force() +/obj/item/knife/folding/update_attack_force() + . = ..() if(open) - edge = 1 - sharp = 1 + set_edge(TRUE) + set_sharp(TRUE) w_class = ITEM_SIZE_NORMAL attack_verb = list("slashed", "stabbed") - ..() else - edge = initial(edge) - sharp = initial(sharp) + set_edge(initial(edge)) + set_sharp(initial(sharp)) w_class = initial(w_class) attack_verb = closed_attack_verbs - ..() /obj/item/knife/folding/on_update_icon() + . = ..() icon_state = get_world_inventory_state() if(open) icon_state = "[get_world_inventory_state()]_open" - if(ismob(loc)) - var/mob/M = loc - if(M.hand) - M.update_inv_l_hand() - else - M.update_inv_r_hand() - ..() + update_held_icon() + +/obj/item/knife/folding/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) + . = open ? ..() : new /image -/obj/item/knife/folding/experimental_mob_overlay(mob/user_mob, slot) - if(open) - return ..() - //Subtypes /obj/item/knife/folding/wood name = "peasant knife" @@ -66,17 +56,21 @@ icon = 'icons/obj/items/weapon/knives/folding/peasant.dmi' valid_handle_colors = list(WOOD_COLOR_GENERIC, WOOD_COLOR_RICH, WOOD_COLOR_BLACK, WOOD_COLOR_CHOCOLATE, WOOD_COLOR_PALE) +/obj/item/knife/folding/wood/get_striking_material(mob/user, atom/target) + . = open ? ..() : GET_DECL(/decl/material/solid/organic/wood/oak) // todo: different handle colors -> different material + /obj/item/knife/folding/tacticool name = "folding knife" - desc = "A small folding knife with a polymer handle and a blackened steel blade. These are typically marketed for self defense purposes." + desc = "A small folding knife with a polymer handle and a blackened steel blade. These are typically marketed for self-defense purposes." icon = 'icons/obj/items/weapon/knives/folding/tacticool.dmi' valid_handle_colors = list("#0f0f2a", "#2a0f0f", "#0f2a0f", COLOR_GRAY20, COLOR_DARK_GUNMETAL) +/obj/item/knife/folding/tacticool/get_striking_material(mob/user, atom/target) + . = open ? ..() : GET_DECL(/decl/material/solid/organic/plastic) + /obj/item/knife/folding/combat //master obj name = "switchblade" desc = "This is a master item - berate the admin or mapper who spawned this" - material_force_multiplier = 0.25 - thrown_material_force_multiplier = 0.25 valid_handle_colors = null /obj/item/knife/folding/combat/balisong diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm index ad99255b27e5..344eb317abbf 100644 --- a/code/game/objects/items/weapons/material/kitchen.dm +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -1,112 +1,25 @@ -/obj/item/kitchen - icon = 'icons/obj/kitchen.dmi' - material = /decl/material/solid/metal/aluminium - applies_material_name = TRUE - applies_material_colour = TRUE - -/* - * Utensils - */ -/obj/item/kitchen/utensil - w_class = ITEM_SIZE_TINY - thrown_material_force_multiplier = 1 - origin_tech = "{'materials':1}" - attack_verb = list("attacked", "stabbed", "poked") - sharp = 0 - edge = 0 - material_force_multiplier = 0.1 // 6 when wielded with hardness 60 (steel) - thrown_material_force_multiplier = 0.1 - - var/loaded //Descriptive string for currently loaded food object. - var/scoop_food = 1 - -/obj/item/kitchen/utensil/Initialize() - . = ..() - if (prob(60)) - src.pixel_y = rand(0, 4) - create_reagents(5) - -/obj/item/kitchen/utensil/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M)) - return ..() - - if(user.a_intent != I_HELP) - if(user.zone_sel.selecting == BP_HEAD || user.zone_sel.selecting == BP_EYES) - if((MUTATION_CLUMSY in user.mutations) && prob(50)) - M = user - return eyestab(M,user) - else - return ..() - - if (reagents.total_volume > 0) - reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) - if(M == user) - if(!M.can_eat(loaded)) - return - M.visible_message("\The [user] eats some [loaded] from \the [src].") - else - user.visible_message("\The [user] begins to feed \the [M]!") - if(!(M.can_force_feed(user, loaded) && do_mob(user, M, 5 SECONDS))) - return - M.visible_message("\The [user] feeds some [loaded] to \the [M] with \the [src].") - playsound(M.loc,'sound/items/eatfood.ogg', rand(10,40), 1) - overlays.Cut() - return - else - to_chat(user, "You don't have anything on \the [src].")//if we have help intent and no food scooped up DON'T STAB OURSELVES WITH THE FORK - return - -/obj/item/kitchen/utensil/fork - name = "fork" - desc = "It's a fork. Sure is pointy." - icon_state = "fork" - -/obj/item/kitchen/utensil/fork/plastic - material = /decl/material/solid/plastic - -/obj/item/kitchen/utensil/spoon - name = "spoon" - desc = "It's a spoon. You can see your own upside-down face in it." - icon_state = "spoon" - attack_verb = list("attacked", "poked") - material_force_multiplier = 0.1 //2 when wielded with weight 20 (steel) - -/obj/item/kitchen/utensil/spoon/plastic - material = /decl/material/solid/plastic - -/obj/item/kitchen/utensil/spork - name = "spork" - desc = "It's a spork. It's much like a fork, but much blunter." - icon_state = "spork" - -/obj/item/kitchen/utensil/spork/plastic - material = /decl/material/solid/plastic - -/obj/item/kitchen/utensil/foon - name = "foon" - desc = "It's a foon. It's much like a spoon, but much sharper." - icon_state = "foon" - -/obj/item/kitchen/utensil/foon/plastic - material = /decl/material/solid/plastic - /* * Rolling Pins */ -/obj/item/kitchen/rollingpin +/obj/item/rollingpin name = "rolling pin" desc = "Used to knock out the Bartender." - icon_state = "rolling_pin" + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/rolling_pin.dmi' attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked") - material = /decl/material/solid/wood - material_force_multiplier = 0.7 // 10 when wielded with weight 15 (wood) - thrown_material_force_multiplier = 1 // as above + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + color = /decl/material/solid/organic/wood/oak::color -/obj/item/kitchen/rollingpin/attack(mob/living/M, mob/living/user) - if ((MUTATION_CLUMSY in user.mutations) && prob(50) && user.unEquip(src)) - to_chat(user, "\The [src] slips out of your hand and hits your head.") +/obj/item/rollingpin/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if (user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50) && user.try_unequip(src)) + to_chat(user, SPAN_DANGER("\The [src] slips out of your hand and hits your head.")) user.take_organ_damage(10) - user.Paralyse(2) - return + SET_STATUS_MAX(user, STAT_PARA, 2) + return TRUE return ..() + +/obj/item/kitchen/rollingpin/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm index 04b22e9cb7d3..20fec64b1b05 100644 --- a/code/game/objects/items/weapons/material/knives.dm +++ b/code/game/objects/items/weapons/material/knives.dm @@ -1,70 +1,62 @@ //knives for stabbing and slashing and so on and so forth -/obj/item/knife //master obj +/obj/item/knife name = "knife" desc = "You call that a knife? This is a master item - berate the admin or mapper who spawned this" icon = 'icons/obj/items/weapon/knives/kitchen.dmi' icon_state = ICON_STATE_WORLD - material_force_multiplier = 0.3 attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") material = /decl/material/solid/metal/steel - origin_tech = "{'materials':1}" - unbreakable = TRUE + origin_tech = @'{"materials":1}' obj_flags = OBJ_FLAG_CONDUCTIBLE sharp = TRUE edge = TRUE - item_flags = ITEM_FLAG_CAN_HIDE_IN_SHOES - applies_material_name = TRUE - applies_material_colour = TRUE + item_flags = ITEM_FLAG_CAN_HIDE_IN_SHOES | ITEM_FLAG_IS_WEAPON + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + pickup_sound = 'sound/foley/knife1.ogg' + drop_sound = 'sound/foley/knifedrop3.ogg' + abstract_type = /obj/item/knife + _base_attack_force = 8 var/draw_handle var/handle_color var/valid_handle_colors +/obj/item/knife/Initialize(ml, material_key) + . = ..() + if(!has_extension(src, /datum/extension/tool)) + set_extension(src, /datum/extension/tool/variable/simple, list( + TOOL_SCALPEL = TOOL_QUALITY_MEDIOCRE, + TOOL_SAW = TOOL_QUALITY_BAD, + TOOL_RETRACTOR = TOOL_QUALITY_BAD, + TOOL_SCREWDRIVER = TOOL_QUALITY_BAD + )) + /obj/item/knife/on_update_icon() - ..() + . = ..() if(draw_handle) - cut_overlays() if(!handle_color && length(valid_handle_colors)) handle_color = pick(valid_handle_colors) add_overlay(overlay_image(icon, "[get_world_inventory_state()]_handle", handle_color, flags=RESET_COLOR|RESET_ALPHA)) - if(blood_overlay) - add_overlay(blood_overlay) -/obj/item/knife/attack(mob/living/carbon/M, mob/living/carbon/user, target_zone) - if(!istype(M)) - return ..() - - if(user.a_intent != I_HELP) - if(user.zone_sel.selecting == BP_EYES) - if((MUTATION_CLUMSY in user.mutations) && prob(50)) - M = user - return eyestab(M, user) +/obj/item/knife/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(!user.check_intent(I_FLAG_HELP) && user.get_target_zone() == BP_EYES) + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + target = user + return eyestab(target, user) return ..() -//table knives -/obj/item/knife/table - name = "table knife" - desc = "A simple table knife, used to cut up individual portions of food." - icon = 'icons/obj/items/weapon/knives/table.dmi' - material = /decl/material/solid/metal/aluminium - material_force_multiplier = 0.1 - sharp = FALSE - attack_verb = list("prodded") - applies_material_name = FALSE - w_class = ITEM_SIZE_SMALL - -/obj/item/knife/table/plastic - material = /decl/material/solid/plastic +/obj/item/knife/can_take_wear_damage() + return FALSE //Prevents knives from shattering/breaking from usage -/obj/item/knife/table/primitive +/obj/item/knife/primitive name = "dueling knife" desc = "A length of leather-bound wood studded with razor-sharp teeth. How crude." icon = 'icons/obj/items/weapon/knives/savage.dmi' - material = /decl/material/solid/wood - applies_material_colour = FALSE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_NAME w_class = ITEM_SIZE_NORMAL -/obj/item/knife/table/primitive/get_autopsy_descriptors() +/obj/item/knife/primitive/get_autopsy_descriptors() . = ..() . += "serrated" @@ -73,7 +65,7 @@ name = "kitchen knife" icon = 'icons/obj/items/weapon/knives/kitchen.dmi' desc = "A general purpose chef's knife made by SpaceCook Incorporated. Guaranteed to stay sharp for years to come." - applies_material_name = FALSE + material_alteration = MAT_FLAG_ALTERATION_COLOR draw_handle = TRUE /obj/item/knife/kitchen/cleaver @@ -81,24 +73,21 @@ desc = "A heavy blade used to process food, especially animal carcasses." icon = 'icons/obj/items/weapon/knives/cleaver.dmi' armor_penetration = 5 - material_force_multiplier = 0.18 attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") /obj/item/knife/kitchen/cleaver/bronze name = "master chef's cleaver" desc = "A heavy blade used to process food. This one is so fancy, it must be for a truly exceptional chef. There aren't any here, so what it's doing here is anyone's guess." material = /decl/material/solid/metal/bronze - material_force_multiplier = 1 //25 with material bronze //fighting knives /obj/item/knife/combat - name = "combat knife" - desc = "A blade with a saw-like pattern on the reverse edge and a heavy handle." - icon = 'icons/obj/items/weapon/knives/tactical.dmi' - material_force_multiplier = 0.2 - w_class = ITEM_SIZE_SMALL - max_force = 15 - draw_handle = TRUE + name = "combat knife" + desc = "A blade with a saw-like pattern on the reverse edge and a heavy handle." + icon = 'icons/obj/items/weapon/knives/tactical.dmi' + w_class = ITEM_SIZE_SMALL + draw_handle = TRUE + _base_attack_force = 15 /obj/item/knife/combat/get_autopsy_descriptors() . = ..() @@ -108,11 +97,11 @@ material = /decl/material/solid/glass /obj/item/knife/combat/titanium - material = /decl/material/solid/metal/plasteel/titanium + material = /decl/material/solid/metal/titanium //random stuff /obj/item/knife/hook - name = "meat hook" + name = "hook" desc = "A sharp, metal hook what sticks into things." icon = 'icons/obj/items/weapon/knives/hook.dmi' sharp = FALSE @@ -121,8 +110,7 @@ name = "ritual knife" desc = "The unearthly energies that once powered this blade are now dormant." icon = 'icons/obj/items/weapon/knives/ritual.dmi' - applies_material_colour = FALSE - applies_material_name = FALSE + material_alteration = MAT_FLAG_ALTERATION_NONE /obj/item/knife/ritual/get_autopsy_descriptors() . = ..() @@ -131,15 +119,14 @@ //Utility knives /obj/item/knife/utility name = "utility knife" - desc = "An utility knife with a polymer handle, commonly used through human space." + desc = "A utility knife with a polymer handle, commonly used through human space." icon = 'icons/obj/items/weapon/knives/utility.dmi' - max_force = 5 - material_force_multiplier = 0.2 w_class = ITEM_SIZE_SMALL draw_handle = TRUE + _base_attack_force = 5 /obj/item/knife/utility/lightweight name = "lightweight utility knife" desc = "A lightweight utility knife made out of a titanium alloy." - material = /decl/material/solid/metal/plasteel/titanium - draw_handle = FALSE \ No newline at end of file + material = /decl/material/solid/metal/titanium + draw_handle = FALSE diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index 8164927090d3..3715ccf13ea0 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -1,19 +1,17 @@ /obj/item/harpoon name = "harpoon" desc = "A short throwing spear with a deep barb, specifically designed to embed itself in its target." - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE icon = 'icons/obj/items/weapon/harpoon.dmi' icon_state = "harpoon" item_state = "harpoon" - max_force = 20 - material_force_multiplier = 0.3 // 18 with hardness 60 (steel) - thrown_material_force_multiplier = 0.6 + item_flags = ITEM_FLAG_IS_WEAPON attack_verb = list("jabbed","stabbed","ripped") does_spin = FALSE material = /decl/material/solid/metal/steel - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + _base_attack_force = 20 var/spent /obj/item/harpoon/bomb @@ -22,11 +20,12 @@ icon_state = "harpoon_bomb" /obj/item/harpoon/bomb/has_embedded() + ..() if(spent) return audible_message(SPAN_WARNING("\The [src] emits a long, harsh tone!")) playsound(loc, 'sound/weapons/bombwhine.ogg', 100, 0, -3) - addtimer(CALLBACK(src, .proc/harpoon_detonate), 4 SECONDS) //for suspense + addtimer(CALLBACK(src, PROC_REF(harpoon_detonate)), 4 SECONDS) //for suspense /obj/item/harpoon/bomb/proc/harpoon_detonate() audible_message(SPAN_DANGER("\The [src] detonates!")) //an actual sound will be handled by explosion() @@ -38,115 +37,37 @@ /obj/item/harpoon/bomb/proc/handle_afterbomb() spent = TRUE SetName("broken harpoon") - desc = "A short spear with just a barb - if it once had a spearhead, it doesn't any more." + desc = "A short spear with just a barb; if it once had a spearhead, it doesn't anymore." icon_state = "harpoon_bomb_spent" - material_force_multiplier = 0.1 - thrown_material_force_multiplier = 0.3 sharp = FALSE edge = FALSE -/obj/item/hatchet - name = "hatchet" - desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood." - icon = 'icons/obj/items/tool/hatchet.dmi' - icon_state = "hatchet" - max_force = 15 - material_force_multiplier = 0.2 // 12 with hardness 60 (steel) - thrown_material_force_multiplier = 0.25 // 15 with weight 60 (steel) - w_class = ITEM_SIZE_SMALL - sharp = 1 - edge = 1 - origin_tech = "{'materials':2,'combat':1}" - attack_verb = list("chopped", "torn", "cut") - material = /decl/material/solid/metal/steel - applies_material_colour = FALSE - applies_material_name = TRUE - hitsound = "chop" - -/obj/item/hatchet/unbreakable - unbreakable = TRUE - -/obj/item/hatchet/machete - name = "machete" - desc = "A long, sturdy blade with a rugged handle. Leading the way to cursed treasures since before space travel." - icon = 'icons/obj/items/weapon/machete.dmi' - item_state = "machete" - w_class = ITEM_SIZE_NORMAL - slot_flags = SLOT_BELT - material = /decl/material/solid/metal/plasteel/titanium - base_parry_chance = 50 - max_force = 20 - material_force_multiplier = 0.20 //20 with hardness 80 (titanium) or 15 with hardness 60 (steel) - -/obj/item/hatchet/machete/unbreakable - unbreakable = TRUE - -/obj/item/hatchet/machete/steel - name = "fabricated machete" - desc = "A long, machine-stamped blade with a somewhat ungainly handle. Found in military surplus stores, malls, and horror movies since before interstellar travel." - base_parry_chance = 40 - matter = list(/decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT) - -/obj/item/hatchet/machete/Initialize() - icon_state = "machete[pick("","_red","_blue", "_black", "_olive")]" - . = ..() - -/obj/item/hatchet/machete/deluxe - name = "deluxe machete" - desc = "A fine example of a machete, with a polished blade, wooden handle and a leather cord loop." - -/obj/item/hatchet/machete/deluxe/Initialize() - . = ..() - icon_state = "machetedx" - -/obj/item/minihoe // -- Numbers - name = "mini hoe" - desc = "It's used for removing weeds or scratching your back." - icon = 'icons/obj/items/tool/hoe.dmi' - icon_state = "hoe" - item_state = "hoe" - material_force_multiplier = 0.25 // 5 with weight 20 (steel) - thrown_material_force_multiplier = 0.25 - w_class = ITEM_SIZE_SMALL - attack_verb = list("slashed", "sliced", "cut", "clawed") - material = /decl/material/solid/metal/steel - applies_material_colour = TRUE - applies_material_name = TRUE - -/obj/item/minihoe/unbreakable - unbreakable = TRUE - /obj/item/scythe name = "scythe" desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow." icon = 'icons/obj/items/tool/scythe.dmi' - icon_state = "scythe0" - material_force_multiplier = 0.275 // 16 with hardness 60 (steel) - thrown_material_force_multiplier = 0.2 - sharp = 1 - edge = 1 + icon_state = ICON_STATE_WORLD + sharp = TRUE + edge = TRUE throw_speed = 1 throw_range = 3 w_class = ITEM_SIZE_HUGE slot_flags = SLOT_BACK - origin_tech = "{'materials':2,'combat':2}" + origin_tech = @'{"materials":2,"combat":2}' attack_verb = list("chopped", "sliced", "cut", "reaped") material = /decl/material/solid/metal/steel - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + _base_attack_force = 10 /obj/item/cross name = "cross" desc = "It's a cross, commonly used as a holy symbol by Christians." icon = 'icons/obj/items/cross.dmi' icon_state = "cross" - material_force_multiplier = 0.1 - thrown_material_force_multiplier = 0.1 w_class = ITEM_SIZE_SMALL attack_verb = list("attacked", "bashed") - applies_material_colour = TRUE - applies_material_name = TRUE - material = /decl/material/solid/wood + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + material = /decl/material/solid/organic/wood/oak /obj/item/cross/silver material = /decl/material/solid/metal/silver diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm index d40e0cd56f54..12b2e317060c 100644 --- a/code/game/objects/items/weapons/material/shards.dm +++ b/code/game/objects/items/weapons/material/shards.dm @@ -1,34 +1,34 @@ // Glass shards /obj/item/shard - name = "shard" + name = SHARD_SHARD icon = 'icons/obj/items/shards.dmi' desc = "Made of nothing. How does this even exist?" // set based on material, if this desc is visible it's a bug (shards default to being made of glass) icon_state = "large" randpixel = 8 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE w_class = ITEM_SIZE_SMALL - material_force_multiplier = 0.12 // 6 with hardness 30 (glass) - thrown_material_force_multiplier = 0.1 // 3 with weight 30 (glass) item_state = "shard-glass" attack_verb = list("stabbed", "slashed", "sliced", "cut") material = /decl/material/solid/glass - applies_material_colour = TRUE - applies_material_name = TRUE - unbreakable = 1 //It's already broken. + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME item_flags = ITEM_FLAG_CAN_HIDE_IN_SHOES - var/has_handle + var/has_handle = FALSE -/obj/item/shard/attack(mob/living/M, mob/living/user, var/target_zone) +/obj/item/shard/Initialize(ml, material_key) . = ..() - if(. && !has_handle) - var/mob/living/carbon/human/H = user - if(istype(H) && !H.gloves && !(H.species.species_flags & SPECIES_FLAG_NO_MINOR_CUT)) - var/obj/item/organ/external/hand = H.get_organ(H.hand ? BP_L_HAND : BP_R_HAND) + set_extension(src, /datum/extension/tool, list(TOOL_SCALPEL = TOOL_QUALITY_BAD)) + +/obj/item/shard/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + . = ..() + if(. && !has_handle && ishuman(user)) + var/mob/living/human/H = user + if(!H.get_equipped_item(slot_gloves_str) && !(H.species.species_flags & SPECIES_FLAG_NO_MINOR_CUT)) + var/obj/item/organ/external/hand = GET_EXTERNAL_ORGAN(H, H.get_active_held_item_slot()) if(istype(hand) && !BP_IS_PROSTHETIC(hand)) to_chat(H, SPAN_DANGER("You slice your hand on \the [src]!")) - hand.take_external_damage(rand(5,10), used_weapon = src) + hand.take_damage(rand(5,10), inflicter = src) /obj/item/shard/set_material(var/new_material) ..(new_material) @@ -38,10 +38,10 @@ icon_state = "[material.shard_icon][pick("large", "medium", "small")]" update_icon() - if(material.shard_type) - SetName("[material.solid_name] [material.shard_type]") + if(material.shard_name) + SetName("[material.solid_name] [material.shard_name]") desc = "A small piece of [material.solid_name]. It looks sharp, you wouldn't want to step on it barefoot. Could probably be used as ... a throwing weapon?" - switch(material.shard_type) + switch(material.shard_name) if(SHARD_SPLINTER, SHARD_SHRAPNEL) gender = PLURAL else @@ -50,83 +50,86 @@ qdel(src) /obj/item/shard/on_update_icon() - if(material) - color = material.color - // 1-(1-x)^2, so that glass shards with 0.3 opacity end up somewhat visible at 0.51 opacity - alpha = 255 * (1 - (1 - material.opacity)*(1 - material.opacity)) - else - color = "#ffffff" - alpha = 255 - -/obj/item/shard/attackby(obj/item/W, mob/user) - if(isWelder(W) && material.shard_can_repair) - var/obj/item/weldingtool/WT = W - if(WT.remove_fuel(0, user)) - material.place_sheet(get_turf(src)) + . = ..() + // 1-(1-x)^2, so that glass shards with 0.3 opacity end up somewhat visible at 0.51 opacity + alpha = 255 * (material ? (1 - (1 - material.opacity)**2) : 1) + if(has_handle) + add_overlay(overlay_image(icon, "handle", has_handle, RESET_COLOR)) + +/obj/item/shard/attackby(obj/item/used_item, mob/user) + if(IS_WELDER(used_item) && material.shard_can_repair) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0, user)) + material.create_object(get_turf(src)) qdel(src) - return - if(istype(W, /obj/item/stack/cable_coil)) + return TRUE + if(istype(used_item, /obj/item/stack/cable_coil)) - if(!material || (material.shard_type in list(SHARD_SPLINTER, SHARD_SHRAPNEL))) + if(!material || (material.shard_name in list(SHARD_SPLINTER, SHARD_SHRAPNEL))) to_chat(user, SPAN_WARNING("\The [src] is not suitable for using as a shank.")) - return + return TRUE if(has_handle) to_chat(user, SPAN_WARNING("\The [src] already has a handle.")) - return - var/obj/item/stack/cable_coil/cable = W + return TRUE + var/obj/item/stack/cable_coil/cable = used_item if(cable.use(3)) to_chat(user, SPAN_NOTICE("You wind some cable around the thick end of \the [src].")) has_handle = cable.color SetName("[material.solid_name] shank") update_icon() - return + return TRUE to_chat(user, SPAN_WARNING("You need 3 or more units of cable to give \the [src] a handle.")) - return + return TRUE return ..() -/obj/item/shard/on_update_icon() - overlays.Cut() - . = ..() - if(has_handle) - var/image/I = image(icon, "handle") - I.appearance_flags |= RESET_COLOR - I.color = has_handle - overlays += I - /obj/item/shard/Crossed(atom/movable/AM) ..() - if(isliving(AM)) - var/mob/M = AM - - if(M.buckled) //wheelchairs, office chairs, rollerbeds - return - - playsound(src.loc, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds - if(ishuman(M)) - var/mob/living/carbon/human/H = M - - if(H.species.siemens_coefficient<0.5 || (H.species.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT))) //Thick skin. - return - - if( H.shoes || ( H.wear_suit && (H.wear_suit.body_parts_covered & FEET) ) ) - return - - to_chat(M, "You step on \the [src]!") - - var/list/check = list(BP_L_FOOT, BP_R_FOOT) - while(check.len) - var/picked = pick(check) - var/obj/item/organ/external/affecting = H.get_organ(picked) - if(affecting) - if(BP_IS_PROSTHETIC(affecting)) - return - affecting.take_external_damage(5, 0) - H.updatehealth() - if(affecting.can_feel_pain()) - H.Weaken(3) - return - check -= picked - return + if(!isliving(AM)) + return + + var/mob/living/victim = AM + if(victim.buckled) //wheelchairs, office chairs, rollerbeds + return + if(victim.immune_to_floor_hazards()) + return + + playsound(src.loc, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds + + var/decl/species/walker_species = victim.get_species() + if(walker_species?.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT)) //Thick skin. + return + + var/obj/item/shoes = victim.get_equipped_item(slot_shoes_str) + var/obj/item/suit = victim.get_equipped_item(slot_wear_suit_str) + if(shoes || (suit && (suit.body_parts_covered & SLOT_FEET))) + return + + var/list/check = list(BP_L_FOOT, BP_R_FOOT) + while(check.len) + var/picked = pick_n_take(check) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(victim, picked) + if(!affecting || BP_IS_PROSTHETIC(affecting)) + continue + to_chat(victim, SPAN_DANGER("You step on \the [src]!")) + affecting.take_damage(5) + if(affecting.can_feel_pain()) + SET_STATUS_MAX(victim, STAT_WEAK, 3) + return + +//Prevent the shard from being allowed to shatter +/obj/item/shard/check_health(var/lastdamage = null, var/lastdamtype = null, var/lastdamflags = 0, var/consumed = FALSE) + if(current_health > 0 || !can_take_damage()) + return //If invincible, or if we're not dead yet, skip + if(lastdamtype == BURN) + handle_melting() + return + physically_destroyed() + +/obj/item/shard/shatter(consumed) + physically_destroyed() + +/obj/item/shard/can_take_wear_damage() + return FALSE // Preset types - left here for the code that uses them /obj/item/shard/borosilicate @@ -138,5 +141,5 @@ w_class = ITEM_SIZE_TINY //it's real small /obj/item/shard/plastic - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic w_class = ITEM_SIZE_TINY \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/stick.dm b/code/game/objects/items/weapons/material/stick.dm index 95a1f1e88da8..8e18a94c2a5e 100644 --- a/code/game/objects/items/weapons/material/stick.dm +++ b/code/game/objects/items/weapons/material/stick.dm @@ -2,34 +2,84 @@ name = "stick" desc = "You feel the urge to poke someone with this." icon = 'icons/obj/items/stick.dmi' - icon_state = "stick" - item_state = "stickmat" - material_force_multiplier = 0.1 - thrown_material_force_multiplier = 0.1 + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_NORMAL - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color attack_verb = list("poked", "jabbed") - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_ALL + lock_picking_level = 3 + max_health = 20 /obj/item/stick/attack_self(mob/user) user.visible_message("\The [user] snaps [src].", "You snap [src].") shatter(0) -/obj/item/stick/attackby(obj/item/W, mob/user) - if(W.sharp && W.edge && !sharp) - user.visible_message("[user] sharpens [src] with [W].", "You sharpen [src] using [W].") - sharp = 1 //Sharpen stick +/obj/item/stick/attackby(obj/item/used_item, mob/user) + + if(used_item.is_sharp() && used_item.has_edge() && !sharp) + user.visible_message("[user] sharpens [src] with [used_item].", "You sharpen [src] using [used_item].") + set_sharp(TRUE) SetName("sharpened " + name) - update_force() + update_attack_force() + return TRUE + + if(!sharp && (istype(used_item, /obj/item/stack/material/bolt) || istype(used_item, /obj/item/stack/material/bundle))) + + var/choice = input(user, "Do you want to make a torch, or a splint?", "Stick Crafting") as null|anything in list("Torch", "Splint") + if(!choice || QDELETED(user) || user.get_active_held_item() != used_item || QDELETED(used_item) || QDELETED(src) || (loc != user && !Adjacent(user)) || sharp) + return TRUE + + var/obj/item/stack/material/cloth = used_item + + var/atom/product_type + var/cloth_cost + if(choice == "Splint") + product_type = /obj/item/stack/medical/splint/crafted + cloth_cost = 5 + else if(choice == "Torch") + product_type = /obj/item/flame/torch + cloth_cost = 3 + else + return TRUE + + if(cloth.get_amount() < cloth_cost) + to_chat(user, SPAN_WARNING("You need at least [cloth_cost] unit\s of material to create \a [atom_info_repository.get_name_for(product_type)].")) + return TRUE + + // Ugly way to check for dried grass vs regular grass. + if(!cloth.special_crafting_check()) + return ..() + + var/was_held = (loc == user) + cloth.use(cloth_cost) + if(!was_held || user.try_unequip(src)) + var/obj/item/thing + if(ispath(product_type, /obj/item/stack)) + thing = new product_type(get_turf(src), 1, material?.type, used_item.material?.type) + else + thing = new product_type(get_turf(src), material?.type, used_item.material?.type) + if(was_held) + user.put_in_hands(thing) + to_chat(user, SPAN_NOTICE("You fashion \the [src] into \a [thing].")) + qdel(src) + return TRUE + return ..() -/obj/item/stick/attack(mob/M, mob/user) - if(user != M && user.a_intent == I_HELP) +/obj/item/stick/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(user != target && user.check_intent(I_FLAG_HELP)) //Playful poking is its own thing - user.visible_message("[user] pokes [M] with [src].", "You poke [M] with [src].") + user.visible_message( + SPAN_NOTICE("\The [user] pokes \the [target] with \the [src]."), + SPAN_NOTICE("You poke \the [target] with \the [src].") + ) //Consider adding a check to see if target is dead user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - return + user.do_attack_animation(target) + return TRUE return ..() + +/obj/item/stick/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/swiss.dm b/code/game/objects/items/weapons/material/swiss.dm index 92d0ea3c7aa2..b91369cf2356 100644 --- a/code/game/objects/items/weapons/material/swiss.dm +++ b/code/game/objects/items/weapons/material/swiss.dm @@ -1,32 +1,59 @@ -#define SWISSKNF_CLOSED "Close" -#define SWISSKNF_LBLADE "Large Blade" -#define SWISSKNF_SBLADE "Small Blade" -#define SWISSKNF_CLIFTER "Cap Lifter-Screwdriver" -#define SWISSKNF_COPENER "Can Opener-Screwdriver" -#define SWISSKNF_CSCREW "Corkscrew" -#define SWISSKNF_GBLADE "Glass Cutter" -#define SWISSKNF_WCUTTER "Wirecutters" -#define SWISSKNF_WBLADE "Wood Saw" -#define SWISSKNF_CROWBAR "Pry Bar" - /obj/item/knife/folding/swiss name = "combi-knife" desc = "A small, colourable, multi-purpose folding knife." icon = 'icons/obj/items/weapon/knives/folding/swiss.dmi' valid_handle_colors = null - max_force = 5 material = /decl/material/solid/metal/steel - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + + var/const/SWISSKNF_CLOSED = "Close" + var/const/SWISSKNF_LBLADE = "Large Blade" + var/const/SWISSKNF_SBLADE = "Small Blade" + var/const/SWISSKNF_CLIFTER = "Cap Lifter-Screwdriver" + var/const/SWISSKNF_COPENER = "Can Opener-Screwdriver" + var/const/SWISSKNF_CSCREW = "Corkscrew" + var/const/SWISSKNF_GBLADE = "Glass Cutter" + var/const/SWISSKNF_WCUTTER = "Wirecutters" + var/const/SWISSKNF_WBLADE = "Wood Saw" + var/const/SWISSKNF_CROWBAR = "Pry Bar" var/active_tool = SWISSKNF_CLOSED - var/tools = list(SWISSKNF_LBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER) - var/can_use_tools = FALSE - var/sharp_tools = list(SWISSKNF_LBLADE, SWISSKNF_SBLADE, SWISSKNF_GBLADE, SWISSKNF_WBLADE) + var/list/tools = list(SWISSKNF_LBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER) + var/static/list/sharp_tools = list(SWISSKNF_LBLADE, SWISSKNF_SBLADE, SWISSKNF_GBLADE, SWISSKNF_WBLADE) + +/obj/item/knife/folding/swiss/Initialize(ml, material_key) + // Variable tool qualities are handled by proc below. + set_extension(src, /datum/extension/tool, list( + TOOL_CROWBAR = TOOL_QUALITY_MEDIOCRE, + TOOL_SCREWDRIVER = TOOL_QUALITY_MEDIOCRE, + TOOL_WIRECUTTERS = TOOL_QUALITY_MEDIOCRE, + TOOL_HATCHET = TOOL_QUALITY_MEDIOCRE + )) + . = ..() + +/obj/item/knife/folding/swiss/proc/get_tool_archetype() + if(active_tool == SWISSKNF_CROWBAR) + return TOOL_CROWBAR + if(active_tool == SWISSKNF_CLIFTER || active_tool == SWISSKNF_COPENER) + return TOOL_SCREWDRIVER + if(active_tool == SWISSKNF_WCUTTER) + return TOOL_WIRECUTTERS + if(active_tool == SWISSKNF_WBLADE) + return TOOL_HATCHET + +/obj/item/knife/folding/swiss/get_tool_property(archetype, property) + . = (archetype == get_tool_archetype()) ? ..() : null + +/obj/item/knife/folding/swiss/get_tool_speed(archetype) + . = (archetype == get_tool_archetype()) ? ..() : 0 + +/obj/item/knife/folding/swiss/get_tool_quality(archetype) + . = (archetype == get_tool_archetype()) ? ..() : 0 /obj/item/knife/folding/swiss/attack_self(mob/user) - var/choice - if(user.a_intent != I_HELP && ((SWISSKNF_LBLADE in tools) || (SWISSKNF_SBLADE in tools)) && active_tool == SWISSKNF_CLOSED) + + var/choice + if(!user.check_intent(I_FLAG_HELP) && ((SWISSKNF_LBLADE in tools) || (SWISSKNF_SBLADE in tools)) && active_tool == SWISSKNF_CLOSED) open = TRUE if(SWISSKNF_LBLADE in tools) choice = SWISSKNF_LBLADE @@ -38,12 +65,13 @@ else choice = SWISSKNF_CLOSED open = FALSE - + if(!choice || !CanPhysicallyInteract(user)) - return + return TRUE + if(choice == SWISSKNF_CLOSED) open = FALSE - user.visible_message("\The [user] closes the [name].") + user.visible_message("\The [user] closes \the [src].") else open = TRUE if(choice == SWISSKNF_LBLADE || choice == SWISSKNF_SBLADE) @@ -51,118 +79,80 @@ playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) else user.visible_message("\The [user] opens the [lowertext(choice)].") - + active_tool = choice - update_force() + update_attack_force() update_icon() add_fingerprint(user) + return TRUE -/obj/item/knife/folding/swiss/examine(mob/user) +/obj/item/knife/folding/swiss/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, active_tool == SWISSKNF_CLOSED ? "It is closed." : "Its [lowertext(active_tool)] is folded out.") + if(active_tool == SWISSKNF_CLOSED) + . += "It is closed." + else + . += "Its [lowertext(active_tool)] is folded out." -/obj/item/knife/folding/swiss/update_force() +/obj/item/knife/folding/swiss/update_attack_force() + . = ..() if(active_tool == SWISSKNF_CLOSED) w_class = initial(w_class) else w_class = ITEM_SIZE_NORMAL if(active_tool in sharp_tools) - ..() if(active_tool == SWISSKNF_GBLADE) siemens_coefficient = 0 else siemens_coefficient = initial(siemens_coefficient) else - edge = initial(edge) - sharp = initial(sharp) + set_edge(initial(edge)) + set_sharp(initial(sharp)) attack_verb = closed_attack_verbs siemens_coefficient = initial(siemens_coefficient) - ..() /obj/item/knife/folding/swiss/on_update_icon() ..() if(active_tool != null) - overlays += overlay_image(icon, active_tool) - -/obj/item/knife/folding/swiss/experimental_mob_overlay(mob/user_mob, slot) - if(active_tool == SWISSKNF_LBLADE || active_tool == SWISSKNF_SBLADE) - return ..() + add_overlay(overlay_image(icon, active_tool, flags = RESET_COLOR)) -/obj/item/knife/folding/swiss/iscrowbar() - return active_tool == SWISSKNF_CROWBAR && can_use_tools - -/obj/item/knife/folding/swiss/isscrewdriver() - return (active_tool == SWISSKNF_CLIFTER || active_tool == SWISSKNF_COPENER) && can_use_tools - -/obj/item/knife/folding/swiss/iswirecutter() - return active_tool == SWISSKNF_WCUTTER && can_use_tools - -/obj/item/knife/folding/swiss/ishatchet() - return active_tool == SWISSKNF_WBLADE +/obj/item/knife/folding/swiss/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) + . = (active_tool == SWISSKNF_LBLADE || active_tool == SWISSKNF_SBLADE) ? ..() : new /image /obj/item/knife/folding/swiss/resolve_attackby(obj/target, mob/user) + var/force = get_base_attack_force() if((istype(target, /obj/structure/window) || istype(target, /obj/structure/grille)) && active_tool == SWISSKNF_GBLADE) - force = force * 8 - . = ..() - update_force() - return - if(istype(target, /obj/item)) - if(target.w_class <= ITEM_SIZE_NORMAL) - can_use_tools = TRUE - . = ..() - can_use_tools = FALSE - return - return ..() + set_base_attack_force(force * 8) + else + set_base_attack_force(force) + . = ..() + set_base_attack_force(force) /obj/item/knife/folding/swiss/officer name = "officer's combi-knife" desc = "A small, blue, multi-purpose folding knife. This one adds a corkscrew." handle_color = COLOR_COMMAND_BLUE - tools = list(SWISSKNF_LBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER, SWISSKNF_CSCREW) /obj/item/knife/folding/swiss/sec name = "Master-At-Arms' combi-knife" desc = "A small, red, multi-purpose folding knife. This one adds no special tools." handle_color = COLOR_NT_RED - tools = list(SWISSKNF_LBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER) /obj/item/knife/folding/swiss/medic name = "medic's combi-knife" desc = "A small, green, multi-purpose folding knife. This one adds a smaller blade in place of the large blade and a glass cutter." handle_color = COLOR_OFF_WHITE - tools = list(SWISSKNF_SBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER, SWISSKNF_GBLADE) /obj/item/knife/folding/swiss/engineer name = "engineer's combi-knife" desc = "A small, yellow, multi-purpose folding knife. This one adds a wood saw and wire cutters." handle_color = COLOR_AMBER - tools = list(SWISSKNF_LBLADE, SWISSKNF_SBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER, SWISSKNF_WBLADE, SWISSKNF_WCUTTER) -/obj/item/knife/folding/swiss/explorer - name = "explorer's combi-knife" - desc = "A small, purple, multi-purpose folding knife. This one adds a wood saw and pry bar." - handle_color = COLOR_PURPLE - - tools = list(SWISSKNF_LBLADE, SWISSKNF_SBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER, SWISSKNF_WBLADE, SWISSKNF_CROWBAR) - /obj/item/knife/folding/swiss/loot name = "black combi-knife" desc = "A small, silver, multi-purpose folding knife. This one adds a small blade and corkscrew." handle_color = COLOR_GRAY40 - tools = list(SWISSKNF_LBLADE, SWISSKNF_SBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER, SWISSKNF_CSCREW) - -#undef SWISSKNF_CLOSED -#undef SWISSKNF_LBLADE -#undef SWISSKNF_SBLADE -#undef SWISSKNF_CLIFTER -#undef SWISSKNF_COPENER -#undef SWISSKNF_CSCREW -#undef SWISSKNF_GBLADE -#undef SWISSKNF_WCUTTER -#undef SWISSKNF_WBLADE -#undef SWISSKNF_CROWBAR diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm index e1b63d5c95d9..8723695261a2 100644 --- a/code/game/objects/items/weapons/material/swords.dm +++ b/code/game/objects/items/weapons/material/swords.dm @@ -3,82 +3,86 @@ desc = "What are you standing around staring at this for? Get to killing!" icon_state = ICON_STATE_WORLD icon = 'icons/obj/items/weapon/swords/claymore.dmi' - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_LARGE - material_force_multiplier = 0.5 // 30 when wielded with hardnes 60 (steel) + item_flags = ITEM_FLAG_IS_WEAPON armor_penetration = 10 - thrown_material_force_multiplier = 0.16 // 10 when thrown with weight 60 (steel) - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") hitsound = 'sound/weapons/bladeslice.ogg' base_parry_chance = 50 melee_accuracy_bonus = 10 material = /decl/material/solid/metal/steel - applies_material_colour = TRUE - applies_material_name = TRUE - var/draw_handle + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + pickup_sound = 'sound/foley/knife1.ogg' + drop_sound = 'sound/foley/knifedrop3.ogg' + _base_attack_force = 15 + var/draw_handle = TRUE -/obj/item/sword/update_force() - if(material?.hardness < MAT_VALUE_HARD) - edge = 0 +/obj/item/sword/set_edge(new_edge) + . = ..() + if(. && !has_edge()) attack_verb = list("attacked", "stabbed", "jabbed", "smacked", "prodded") hitsound = 'sound/weapons/pierce.ogg' - if(material?.hardness < MAT_VALUE_RIGID) - sharp = 0 + +/obj/item/sword/set_sharp(new_sharp) + . = ..() + if(. && !is_sharp()) attack_verb = list("attacked", "smashed", "jabbed", "smacked", "prodded", "bonked") hitsound = "chop" - . = ..() - + /obj/item/sword/on_update_icon() . = ..() - if(applies_material_colour) - if(draw_handle) - add_overlay(get_mutable_overlay(icon, "[icon_state]_handle")) - if(material.reflectiveness >= MAT_VALUE_SHINY) - add_overlay(get_mutable_overlay(icon, "[icon_state]_shine"), adjust_brightness(color, 20 + material.reflectiveness)) + if(material_alteration & MAT_FLAG_ALTERATION_COLOR) + if(draw_handle && check_state_in_icon("[icon_state]_handle", icon)) + add_overlay(mutable_appearance(icon, "[icon_state]_handle")) + if(material.reflectiveness >= MAT_VALUE_SHINY && check_state_in_icon("[icon_state]_shine", icon)) + add_overlay(mutable_appearance(icon, "[icon_state]_shine"), adjust_brightness(color, 20 + material.reflectiveness)) -/obj/item/sword/experimental_mob_overlay(mob/user_mob, slot) - var/image/res = ..() +/obj/item/sword/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) //Do not color scabbarded blades - if(applies_material_colour && (slot == slot_back_str || slot == slot_belt_str)) - res.color = null - return res + if(overlay && (material_alteration & MAT_FLAG_ALTERATION_COLOR) && (slot == slot_back_str || slot == slot_belt_str)) + overlay.color = null + . = ..() /obj/item/sword/wood - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak draw_handle = FALSE /obj/item/sword/replica - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic + _base_attack_force = 5 /obj/item/sword/katana name = "katana" desc = "Woefully underpowered in D20. This one looks pretty sharp." icon = 'icons/obj/items/weapon/swords/katana.dmi' - slot_flags = SLOT_BELT | SLOT_BACK + slot_flags = SLOT_LOWER_BODY | SLOT_BACK + _base_attack_force = 15 /obj/item/sword/katana/set_material(new_material) . = ..() - if(applies_material_name && istype(material, /decl/material/solid/wood)) + if((material_alteration & MAT_FLAG_ALTERATION_NAME) && istype(material, /decl/material/solid/organic/wood)) SetName("[material.solid_name] bokutou") desc = "Finest wooden fibers folded exactly one thousand times by master robots." /obj/item/sword/katana/bamboo - material = /decl/material/solid/wood/bamboo + material = /decl/material/solid/organic/wood/bamboo draw_handle = FALSE /obj/item/sword/katana/wood - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak draw_handle = FALSE /obj/item/sword/katana/vibro name = "vibrokatana" desc = "A high-tech take on a woefully underpowered weapon. Can't mistake its sound for anything." - material = /decl/material/solid/metal/plasteel/titanium + material = /decl/material/solid/metal/titanium hitsound = 'sound/weapons/anime_sword.wav' + pickup_sound = 'sound/weapons/katana_out.wav' + _base_attack_force = 30 -/obj/item/sword/katana/vibro/equipped(mob/user, slot) - if(slot == slot_l_hand || slot == slot_r_hand) - playsound(src, 'sound/weapons/katana_out.wav', 50, 1, -5) - \ No newline at end of file +/obj/item/sword/katana/vibro/pickup_sound_callback() + if(ismob(loc) && pickup_sound) + playsound(src, pickup_sound, 50, -1, 5) diff --git a/code/game/objects/items/weapons/material/thrown.dm b/code/game/objects/items/weapons/material/thrown.dm index ff0f6f7827ac..7e878a0ac20c 100644 --- a/code/game/objects/items/weapons/material/thrown.dm +++ b/code/game/objects/items/weapons/material/thrown.dm @@ -4,27 +4,26 @@ icon = 'icons/obj/items/weapon/throwing_star.dmi' icon_state = "star" randpixel = 12 - material_force_multiplier = 0.1 // 6 with hardness 60 (steel) - thrown_material_force_multiplier = 0.25 // 15 with weight 60 (steel) throw_speed = 10 throw_range = 15 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE material = /decl/material/solid/metal/steel - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + item_flags = ITEM_FLAG_IS_WEAPON + _base_attack_force = 15 + +/obj/item/star/get_max_weapon_force() + return get_thrown_attack_force() /obj/item/star/throw_impact(atom/hit_atom) ..() - if(material.radioactivity>0 && istype(hit_atom,/mob/living)) + if(material.radioactivity>0 && isliving(hit_atom)) var/mob/living/M = hit_atom var/urgh = material.radioactivity - M.adjustToxLoss(rand(urgh/2,urgh)) + M.take_damage(rand(urgh/2,urgh), TOX) /obj/item/star/afterattack(atom/target, mob/user, proximity_flag, click_parameters) . = ..() - if(user.a_intent == I_HURT) - user.throw_item(target) - -/obj/item/star/ninja - material = /decl/material/solid/metal/uranium + if(user.check_intent(I_FLAG_HARM)) + user.mob_throw_item(target, src) diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm deleted file mode 100644 index a1dcd98a3826..000000000000 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ /dev/null @@ -1,201 +0,0 @@ -/* Two-handed Weapons - * Contains: - * Twohanded - * Fireaxe - * Double-Bladed Energy Swords - */ - -/*################################################################## -##################### TWO HANDED WEAPONS BE HERE~ -Agouri :3 ######## -####################################################################*/ - -//Rewrote TwoHanded weapons stuff and put it all here. Just copypasta fireaxe to make new ones ~Carn -//This rewrite means we don't have two variables for EVERY item which are used only by a few weapons. -//It also tidies stuff up elsewhere. - -/* - * Twohanded - */ -/obj/item/twohanded - w_class = ITEM_SIZE_HUGE - slot_flags = SLOT_BACK - var/wielded = 0 - var/force_wielded = 0 - var/force_unwielded - var/wieldsound = null - var/unwieldsound = null - var/base_icon - var/base_name - var/unwielded_material_force_multiplier = 0.25 - var/wielded_parry_bonus = 15 - -/obj/item/twohanded/get_max_weapon_value() - return force_wielded - -/obj/item/twohanded/update_twohanding() - var/mob/living/M = loc - if(istype(M) && M.can_wield_item(src) && is_held_twohanded(M)) - wielded = 1 - force = force_wielded - else - wielded = 0 - force = force_unwielded - update_icon() - ..() - -/obj/item/twohanded/update_force() - ..() - base_name = name - force_unwielded = round(force*unwielded_material_force_multiplier) - force_wielded = force - force = force_unwielded - - -/obj/item/twohanded/Initialize() - . = ..() - update_icon() - -/obj/item/twohanded/get_parry_chance(mob/user) - . = ..() - if(wielded) - . += wielded_parry_bonus - -/obj/item/twohanded/on_update_icon() - ..() - icon_state = "[base_icon][wielded]" - LAZYSET(item_state_slots, slot_l_hand_str, icon_state) - LAZYSET(item_state_slots, slot_r_hand_str, icon_state) - LAZYSET(item_state_slots, slot_back_str, base_icon) - -/* - * Fireaxe - */ -/obj/item/twohanded/fireaxe // DEM AXES MAN, marker -Agouri - name = "fire axe" - desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" - icon = 'icons/obj/items/tool/fireaxe.dmi' - icon_state = "fireaxe0" - base_icon = "fireaxe" - max_force = 60 //for wielded - material_force_multiplier = 0.6 - unwielded_material_force_multiplier = 0.3 - sharp = 1 - edge = 1 - attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - material = /decl/material/solid/metal/steel - applies_material_colour = FALSE - applies_material_name = TRUE - -/obj/item/twohanded/fireaxe/afterattack(atom/A, mob/user, proximity) - if(!proximity) return - ..() - if(A && wielded) - if(istype(A,/obj/structure/window)) - var/obj/structure/window/W = A - W.shatter() - else if(istype(A,/obj/structure/grille)) - qdel(A) - else if(istype(A,/obj/effect/vine)) - var/obj/effect/vine/P = A - P.die_off() - -/obj/item/twohanded/fireaxe/ishatchet() - return TRUE - -//spears, bay edition -/obj/item/twohanded/spear - name = "spear" - desc = "A haphazardly-constructed yet still deadly weapon of ancient design." - icon_state = "preview" - icon = 'icons/obj/items/weapon/spear.dmi' - material_force_multiplier = 0.33 // 12/19 with hardness 60 (steel) or 10/16 with hardness 50 (glass) - unwielded_material_force_multiplier = 0.20 - thrown_material_force_multiplier = 0.6 // 20 when thrown with weight 15 (glass) - throw_speed = 3 - edge = 0 - sharp = 1 - attack_verb = list("attacked", "poked", "jabbed", "torn", "gored") - material = /decl/material/solid/glass - applies_material_colour = TRUE - applies_material_name = TRUE - does_spin = FALSE - var/shaft_material = /decl/material/solid/metal/steel - var/cable_color = COLOR_RED - -/obj/item/twohanded/spear/shatter(var/consumed) - if(!consumed) - new /obj/item/stack/material/rods(get_turf(src), 1, shaft_material) - new /obj/item/stack/cable_coil(get_turf(src), 3, cable_color) - ..() - -/obj/item/twohanded/spear/on_update_icon() - overlays.Cut() - if(applies_material_colour && material) - color = material.color - alpha = 100 + material.opacity * 255 - overlays += get_shaft_overlay("shaft") - overlays += get_mutable_overlay(icon, "cable", cable_color) - -/obj/item/twohanded/spear/experimental_mob_overlay(mob/user_mob, slot) - var/image/ret = ..() - if(wielded && check_state_in_icon("[ret.icon_state]_wielded", icon)) - ret.icon_state = "[ret.icon_state]_wielded" - ret.overlays += get_shaft_overlay("[ret.icon_state]_shaft") - ret.overlays += get_mutable_overlay(icon, "[ret.icon_state]_cable", cable_color) - return ret - -/obj/item/twohanded/spear/proc/get_shaft_overlay(var/base_state) - var/decl/material/M = decls_repository.get_decl(shaft_material) - var/mutable_appearance/shaft = get_mutable_overlay(icon, base_state, M.color) - shaft.alpha = 155 + 100 * M.opacity - return shaft - -/obj/item/twohanded/spear/diamond - material = /decl/material/solid/gemstone/diamond - shaft_material = /decl/material/solid/metal/gold - cable_color = COLOR_PURPLE - -/obj/item/twohanded/spear/steel - material = /decl/material/solid/metal/steel - shaft_material = /decl/material/solid/wood - cable_color = COLOR_GREEN - -/obj/item/twohanded/spear/supermatter - material = /decl/material/solid/exotic_matter - shaft_material = /decl/material/solid/wood/ebony - cable_color = COLOR_INDIGO - -/obj/item/twohanded/baseballbat - name = "bat" - desc = "HOME RUN!" - icon = 'icons/obj/items/weapon/bat.dmi' - icon_state = "metalbat0" - base_icon = "metalbat" - item_state = "metalbat" - w_class = ITEM_SIZE_LARGE - throwforce = 7 - attack_verb = list("smashed", "beaten", "slammed", "smacked", "struck", "battered", "bonked") - hitsound = 'sound/weapons/genhit3.ogg' - material = /decl/material/solid/wood/maple - applies_material_colour = TRUE - applies_material_name = TRUE - max_force = 40 //for wielded - material_force_multiplier = 0.4 // 24 when wielded with weight 60 (steel) - unwielded_material_force_multiplier = 0.25 // 15 when unwielded based on above. - melee_accuracy_bonus = -10 - -//Predefined materials go here. -/obj/item/twohanded/baseballbat/aluminium - material = /decl/material/solid/metal/aluminium - -/obj/item/twohanded/baseballbat/uranium - material = /decl/material/solid/metal/uranium - -/obj/item/twohanded/baseballbat/gold - material = /decl/material/solid/metal/gold - -/obj/item/twohanded/baseballbat/platinum - material = /decl/material/solid/metal/platinum - -/obj/item/twohanded/baseballbat/diamond - material = /decl/material/solid/gemstone/diamond diff --git a/code/game/objects/items/weapons/material/urn.dm b/code/game/objects/items/weapons/material/urn.dm index e9685226137e..cf3257dbc06f 100644 --- a/code/game/objects/items/weapons/material/urn.dm +++ b/code/game/objects/items/weapons/material/urn.dm @@ -3,10 +3,9 @@ desc = "A vase used to store the ashes of the deceased." icon = 'icons/obj/items/urn.dmi' icon_state = "urn" - applies_material_colour = TRUE - applies_material_name = TRUE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME w_class = ITEM_SIZE_SMALL - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak /obj/item/urn/afterattack(var/obj/A, var/mob/user, var/proximity) if(!istype(A, /obj/effect/decal/cleanable/ash)) @@ -27,7 +26,7 @@ A.dropInto(loc) user.visible_message("\The [user] pours \the [A] out from \the [src].", "You pour \the [A] out from \the [src].") -/obj/item/urn/examine(mob/user) +/obj/item/urn/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(contents.len) - to_chat(user, "\The [src] is full.") \ No newline at end of file + . += "\The [src] is full." diff --git a/code/game/objects/items/weapons/melee/baseball_bat.dm b/code/game/objects/items/weapons/melee/baseball_bat.dm new file mode 100644 index 000000000000..b3f851b290c9 --- /dev/null +++ b/code/game/objects/items/weapons/melee/baseball_bat.dm @@ -0,0 +1,32 @@ +/obj/item/baseball_bat + name = "bat" + desc = "HOME RUN!" + icon = 'icons/obj/items/weapon/bat.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + can_be_twohanded = TRUE + pickup_sound = 'sound/foley/scrape1.ogg' + drop_sound = 'sound/foley/tooldrop1.ogg' + slot_flags = SLOT_BACK + attack_verb = list("smashed", "beaten", "slammed", "smacked", "struck", "battered", "bonked") + hitsound = 'sound/weapons/genhit3.ogg' + material = /decl/material/solid/organic/wood/maple + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + melee_accuracy_bonus = -10 + _base_attack_force = 20 + +//Predefined materials go here. +/obj/item/baseball_bat/aluminium + material = /decl/material/solid/metal/aluminium + +/obj/item/baseball_bat/uranium + material = /decl/material/solid/metal/uranium + +/obj/item/baseball_bat/gold + material = /decl/material/solid/metal/gold + +/obj/item/baseball_bat/platinum + material = /decl/material/solid/metal/platinum + +/obj/item/baseball_bat/diamond + material = /decl/material/solid/gemstone/diamond diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 20cd836056da..58437b40dcb6 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -1,15 +1,56 @@ /obj/item/energy_blade - var/active = 0 - var/active_force - var/active_throwforce - var/active_icon - var/lighting_color - var/active_attack_verb - var/inactive_attack_verb = list() - sharp = 0 - edge = 0 - armor_penetration = 50 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_BLOOD + + name = "energy blade" + desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal." + icon = 'icons/obj/items/weapon/energy_blade.dmi' + + icon_state = ICON_STATE_WORLD + atom_flags = ATOM_FLAG_NO_BLOOD + item_flags = ITEM_FLAG_IS_WEAPON + w_class = ITEM_SIZE_SMALL + hitsound = 'sound/weapons/genhit.ogg' + + _base_attack_force = 3 // bonk + throw_speed = 1 + throw_range = 5 + armor_penetration = 0 + + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/plutonium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT, + ) + + var/lighting_color = COLOR_SABER_GREEN + + var/active = FALSE + var/active_parry_chance = 15 + var/active_throwforce = 20 + var/active_armour_pen = 50 + var/active_edge = 1 + var/active_sharp = 1 + var/active_descriptor = "energized" + var/active_hitsound = 'sound/weapons/blade1.ogg' + var/active_sound = 'sound/weapons/saberon.ogg' + VAR_PROTECTED/_active_base_attack_force = 30 + + var/inactive_sound = 'sound/weapons/saberoff.ogg' + + attack_verb = "hit" + var/list/active_attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + var/list/inactive_attack_verb = "hit" + +/obj/item/energy_blade/get_max_weapon_force() + return _active_base_attack_force + +/obj/item/energy_blade/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + . = ..() + if(.) + spark_at(src, amount = 5, holder = src) + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) /obj/item/energy_blade/get_heat() . = max(..(), 3500) @@ -26,256 +67,105 @@ . = ..() if(active) active = FALSE - activate() - else - active = TRUE - deactivate() + obj_flags &= ~OBJ_FLAG_NO_STORAGE + toggle_active(ismob(loc) && loc) + if(active_sharp || active_edge) + set_extension(src, /datum/extension/tool, list(TOOL_SCALPEL = TOOL_QUALITY_WORST)) -/obj/item/energy_blade/on_update_icon() - . = ..() - if(active) - icon_state = active_icon - else - icon_state = initial(icon_state) +/obj/item/energy_blade/get_tool_quality(archetype) + if(archetype == TOOL_SCALPEL && !active) + return 0 + return ..() -/obj/item/energy_blade/proc/activate(mob/living/user) +/obj/item/energy_blade/get_base_attack_force() if(active) - return - active = TRUE - force = active_force - throwforce = active_throwforce - sharp = 1 - edge = 1 - slot_flags |= SLOT_DENYPOCKET - attack_verb = active_attack_verb - update_icon() - if(user) - playsound(user, 'sound/weapons/saberon.ogg', 50, 1) - to_chat(user, "\The [src] is now energised.") - set_light(0.8, 1, 2, 4, lighting_color) - -/obj/item/energy_blade/proc/deactivate(mob/living/user) - if(!active) - return - active = FALSE - force = initial(force) - throwforce = initial(throwforce) - sharp = initial(sharp) - edge = initial(edge) - slot_flags = initial(slot_flags) - attack_verb = inactive_attack_verb - update_icon() - if(user) - playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) - to_chat(user, "\The [src] deactivates!") - set_light(0) + return _active_base_attack_force + return _base_attack_force -/obj/item/energy_blade/attack_self(mob/living/user) - if(active) - if((MUTATION_CLUMSY in user.mutations) && prob(50)) - user.visible_message("\The [user] accidentally cuts \himself with \the [src].",\ - "You accidentally cut yourself with \the [src].") - user.take_organ_damage(5,5) - deactivate(user) - else - activate(user) +/obj/item/energy_blade/pick_attack_verb() + return DEFAULTPICK(active ? active_attack_verb : inactive_attack_verb, ..()) - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - H.update_inv_l_hand() - H.update_inv_r_hand() +/obj/item/energy_blade/proc/toggle_active(var/mob/user) - add_fingerprint(user) - return - -/obj/item/energy_blade/get_storage_cost() - . = active ? ITEM_SIZE_NO_CONTAINER : ..() - -/* - * Energy Axe - */ -/obj/item/energy_blade/axe - name = "energy axe" - desc = "An energised battle axe." - icon = 'icons/obj/items/weapon/e_axe.dmi' - icon_state = "axe0" - active_icon = "axe1" - lighting_color = COLOR_SABER_AXE - active_force = 60 - active_throwforce = 35 - force = 20 - throwforce = 10 - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_NORMAL - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_BLOOD - obj_flags = OBJ_FLAG_CONDUCTIBLE - origin_tech = "{'magnets':3,'combat':4}" - active_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - inactive_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - sharp = 1 - edge = 1 - melee_accuracy_bonus = 15 - -/obj/item/energy_blade/axe/deactivate(mob/living/user) - . = ..() - to_chat(user, "\The [src] is de-energised. It's just a regular axe now.") - -/* - * Energy Sword - */ -/obj/item/energy_blade/sword - name = "energy sword" - desc = "May the force be within you." - icon = 'icons/obj/items/weapon/e_sword.dmi' - icon_state = "sword0" - active_force = 30 - active_throwforce = 20 - force = 3 - throwforce = 5 - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_SMALL - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_BLOOD - origin_tech = "{'magnets':3,'esoteric':4}" - sharp = 1 - edge = 1 - base_parry_chance = 50 - active_attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - hitsound = 'sound/weapons/blade1.ogg' - var/blade_color - -/obj/item/energy_blade/sword/Initialize() - if(!blade_color) - blade_color = pick("red","blue","green","purple") - if(!active_icon) - active_icon = "sword[blade_color]" - if(!lighting_color) - var/color_hex = list("red" = COLOR_SABER_RED, "blue" = COLOR_SABER_BLUE, "green" = COLOR_SABER_GREEN, "purple" = COLOR_SABER_PURPLE) - lighting_color = color_hex[blade_color] - - . = ..() + active = !active + if(active) -/obj/item/energy_blade/sword/green - blade_color = "green" + obj_flags |= OBJ_FLAG_NO_STORAGE + set_sharp(active_sharp) + set_edge(active_edge) + base_parry_chance = active_parry_chance + armor_penetration = active_armour_pen + hitsound = active_hitsound -/obj/item/energy_blade/sword/red - blade_color = "red" + w_class = max(w_class, ITEM_SIZE_NORMAL) + slot_flags &= ~SLOT_POCKET + if(active_sound) + playsound(loc, active_sound, 50, 1) -/obj/item/energy_blade/sword/red/activated/Initialize() - . = ..() - activate() - -/obj/item/energy_blade/sword/blue - blade_color = "blue" + else -/obj/item/energy_blade/sword/purple - blade_color = "purple" + obj_flags &= ~OBJ_FLAG_NO_STORAGE + set_sharp(initial(sharp)) + set_edge(initial(edge)) + base_parry_chance = initial(base_parry_chance) + armor_penetration = initial(armor_penetration) + hitsound = initial(hitsound) -/obj/item/energy_blade/sword/dropped(var/mob/user) - ..() - if(!istype(loc,/mob)) - deactivate(user) + w_class = initial(w_class) + slot_flags = initial(slot_flags) + if(inactive_sound) + playsound(loc, inactive_sound, 50, 1) -/obj/item/energy_blade/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - if(.) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, user.loc) - spark_system.start() - playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + update_attack_force() -/obj/item/energy_blade/sword/get_parry_chance(mob/user) - return active ? ..() : 0 + if(lighting_color) + if(active) + set_light(2, 0.8, lighting_color) + else + set_light(0) -/obj/item/energy_blade/sword/pirate - name = "energy cutlass" - desc = "Arrrr matey." - icon = 'icons/obj/items/weapon/e_cutlass.dmi' - icon_state = "cutlass0" - active_icon = "cutlass1" - lighting_color = COLOR_SABER_CUTLASS + update_icon() + update_held_icon() -/obj/item/energy_blade/sword/pirate/activated/Initialize() - . = ..() - activate() -/* - *Energy Blade - */ + if(user && active_descriptor) + to_chat(user, SPAN_NOTICE("\The [src] is [active ? "now" : "no longer"] [active_descriptor].")) -/obj/item/energy_blade/blade - name = "energy blade" - desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal." - icon = 'icons/obj/items/weapon/energy_blade.dmi' - icon_state = "blade" - active_icon = "blade" //It's all energy, so it should always be visible. - lighting_color = COLOR_SABER_GREEN - active_force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe - active = 1 - armor_penetration = 100 - sharp = 1 - edge = 1 - anchored = 1 // Never spawned outside of inventory, should be fine. - active_throwforce = 1 //Throwing or dropping the item deletes it. - throw_speed = 1 - throw_range = 1 - w_class = ITEM_SIZE_TINY //technically it's just energy or something, I dunno - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_BLOOD - active_attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - hitsound = 'sound/weapons/blade1.ogg' - var/mob/living/creator - var/datum/effect/effect/system/spark_spread/spark_system - -/obj/item/energy_blade/blade/Initialize() +/obj/item/energy_blade/dropped(mob/user) . = ..() - spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src) - spark_system.attach(src) - START_PROCESSING(SSobj, src) + if(active) + update_icon() -/obj/item/energy_blade/blade/Destroy() - STOP_PROCESSING(SSobj, src) +/obj/item/energy_blade/equipped(mob/user, slot) . = ..() + if(active) + update_icon() -/obj/item/energy_blade/blade/is_special_cutting_tool(var/high_power) +/obj/item/energy_blade/attack_self(mob/user) + if(active) + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + SPAN_DANGER("\The [user] accidentally cuts [pronouns.self] with \the [src]."), \ + SPAN_DANGER("You accidentally cut yourself with \the [src].")) + if(isliving(user)) + var/mob/living/M = user + M.take_organ_damage(5,5) + toggle_active(user) + add_fingerprint(user) return TRUE -/obj/item/energy_blade/blade/get_storage_cost() - return ITEM_SIZE_NO_CONTAINER - -/obj/item/energy_blade/blade/attack_self(mob/user) - user.drop_from_inventory(src) - -/obj/item/energy_blade/blade/dropped() - ..() - QDEL_IN(src, 0) - -/obj/item/energy_blade/blade/Process() - if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src)) - // Tidy up a bit. - if(istype(loc,/mob/living)) - var/mob/living/carbon/human/host = loc - if(istype(host)) - for(var/obj/item/organ/external/organ in host.organs) - for(var/obj/item/O in organ.implants) - if(O == src) - organ.implants -= src - host.pinned -= src - host.embedded -= src - host.drop_from_inventory(src) - QDEL_IN(src, 0) - -/obj/item/energy_blade/machete - name = "energy machete" - desc = "A machete handle that extends out into a long, purple machete blade." - icon = 'icons/obj/items/weapon/e_machete.dmi' - icon_state = "machete_skrell_x" - active_icon = "machete_skrell" - active_force = 16 //In line with standard machetes at time of creation. - active_throwforce = 17.25 - lighting_color = "#6600cc" - force = 3 - throwforce = 1 - w_class = ITEM_SIZE_SMALL - origin_tech = "{'magnets':3}" - active_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - hitsound = 'sound/weapons/blade1.ogg' \ No newline at end of file +/obj/item/energy_blade/on_update_icon() + . = ..() + z_flags &= ~ZMM_MANGLE_PLANES + icon_state = get_world_inventory_state() + if(active && check_state_in_icon("[icon_state]-extended", icon)) + if(plane == HUD_PLANE) + add_overlay(image(icon, "[icon_state]-extended")) + else + add_overlay(emissive_overlay(icon, "[icon_state]-extended")) + z_flags |= ZMM_MANGLE_PLANES + +/obj/item/energy_blade/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && active && check_state_in_icon("[overlay.icon_state]-extended", overlay.icon)) + overlay.overlays += emissive_overlay(overlay.icon, "[overlay.icon_state]-extended") + . = ..() diff --git a/code/game/objects/items/weapons/melee/energy_axe.dm b/code/game/objects/items/weapons/melee/energy_axe.dm new file mode 100644 index 000000000000..e7845e089858 --- /dev/null +++ b/code/game/objects/items/weapons/melee/energy_axe.dm @@ -0,0 +1,21 @@ +/obj/item/energy_blade/axe + name = "energy axe" + desc = "An energised battle axe." + icon = 'icons/obj/items/weapon/e_axe.dmi' + lighting_color = COLOR_SABER_AXE + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_NORMAL + atom_flags = ATOM_FLAG_NO_BLOOD + obj_flags = OBJ_FLAG_CONDUCTIBLE + item_flags = ITEM_FLAG_IS_WEAPON + origin_tech = @'{"magnets":3,"combat":4}' + active_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + inactive_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + sharp = TRUE + edge = TRUE + base_parry_chance = 30 + active_parry_chance = 30 + melee_accuracy_bonus = 15 + _active_base_attack_force = 40 + _base_attack_force = 20 diff --git a/code/game/objects/items/weapons/melee/energy_cutlass.dm b/code/game/objects/items/weapons/melee/energy_cutlass.dm new file mode 100644 index 000000000000..76183114c0a8 --- /dev/null +++ b/code/game/objects/items/weapons/melee/energy_cutlass.dm @@ -0,0 +1,7 @@ +/obj/item/energy_blade/cutlass + name = "energy cutlass" + desc = "Arrrr matey." + icon = 'icons/obj/items/weapon/e_cutlass.dmi' + lighting_color = COLOR_SABER_CUTLASS + active_parry_chance = 50 + material = /decl/material/solid/metal/brass diff --git a/code/game/objects/items/weapons/melee/energy_machete.dm b/code/game/objects/items/weapons/melee/energy_machete.dm new file mode 100644 index 000000000000..b1cdf0631395 --- /dev/null +++ b/code/game/objects/items/weapons/melee/energy_machete.dm @@ -0,0 +1,9 @@ +/obj/item/energy_blade/machete + name = "energy machete" + desc = "A machete handle that extends out into a long, purple machete blade." + icon = 'icons/obj/items/weapon/e_machete.dmi' + _active_base_attack_force = 16 + active_parry_chance = 30 + lighting_color = "#6600cc" + origin_tech = @'{"magnets":3}' + active_attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") diff --git a/code/game/objects/items/weapons/melee/energy_projected.dm b/code/game/objects/items/weapons/melee/energy_projected.dm new file mode 100644 index 000000000000..1009f5745438 --- /dev/null +++ b/code/game/objects/items/weapons/melee/energy_projected.dm @@ -0,0 +1,52 @@ +/obj/item/energy_blade/projected + + anchored = TRUE // Never spawned outside of inventory, should be fine. + armor_penetration = 100 + throw_speed = 1 + throw_range = 1 + w_class = ITEM_SIZE_TINY //technically it's just energy or something, I dunno + active_attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/blade1.ogg' + is_spawnable_type = FALSE // Do not manually spawn this, it will runtime/break. + + active = TRUE + active_sharp = 1 + active_edge = 1 + active_parry_chance = 50 + _active_base_attack_force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe + obj_flags = OBJ_FLAG_NO_STORAGE + + var/mob/living/creator + +/obj/item/energy_blade/projected/Initialize() + . = ..() + if(!ismob(loc)) + return INITIALIZE_HINT_QDEL + set_extension(src, /datum/extension/demolisher/energy) + +/obj/item/energy_blade/projected/is_special_cutting_tool(var/high_power) + return active + +/obj/item/energy_blade/projected/attack_self(mob/user) + user.drop_from_inventory(src) + +/obj/item/energy_blade/projected/equipped(mob/user, slot) + . = ..() + check_loc() + +/obj/item/energy_blade/projected/dropped() + . = ..() + check_loc() + +/obj/item/energy_blade/projected/on_picked_up(mob/user, atom/old_loc) + . = ..() + check_loc() + +/obj/item/energy_blade/projected/Move() + . = ..() + if(.) + check_loc() + +/obj/item/energy_blade/projected/proc/check_loc() + if(!QDELETED(src) && (loc != creator || !(src in creator?.get_held_items()))) + qdel(src) diff --git a/code/game/objects/items/weapons/melee/energy_sword.dm b/code/game/objects/items/weapons/melee/energy_sword.dm new file mode 100644 index 000000000000..045040acb762 --- /dev/null +++ b/code/game/objects/items/weapons/melee/energy_sword.dm @@ -0,0 +1,63 @@ +/obj/item/energy_blade/sword + name = "energy sword" + desc = "May the force be mass times acceleration." + icon = 'icons/obj/items/weapon/e_sword.dmi' + origin_tech = @'{"magnets":3,"esoteric":4}' + active_parry_chance = 50 + + var/blade_color + var/static/list/blade_colors = list( + COLOR_RED = COLOR_SABER_RED, + COLOR_CYAN = COLOR_SABER_BLUE, + COLOR_LIME = COLOR_SABER_GREEN, + COLOR_VIOLET = COLOR_SABER_PURPLE + ) + +/obj/item/energy_blade/sword/Initialize() + if(!blade_color) + blade_color = pick(blade_colors) + lighting_color = blade_colors[blade_color] + if(!lighting_color) + lighting_color = blade_color + . = ..() + set_extension(src, /datum/extension/demolisher/energy) + +/obj/item/energy_blade/sword/is_special_cutting_tool(var/high_power) + return active && !high_power + +/obj/item/energy_blade/sword/dropped(var/mob/user) + ..() + addtimer(CALLBACK(src, PROC_REF(check_loc)), 1) // Swapping hands or passing to another person should not deactivate the sword. + +/obj/item/energy_blade/sword/proc/check_loc() + if(!ismob(loc) && active) + toggle_active() + +/obj/item/energy_blade/sword/on_update_icon() + . = ..() + if(active && check_state_in_icon("[icon_state]-extended-glow", icon)) + var/image/I + if(plane == HUD_PLANE) + I = image(icon, "[icon_state]-extended-glow") + else + I = emissive_overlay(icon, "[icon_state]-extended-glow") + I.color = blade_color + add_overlay(I) + +/obj/item/energy_blade/sword/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && active && check_state_in_icon("[overlay.icon_state]-extended-glow", overlay.icon)) + overlay.overlays += emissive_overlay(overlay.icon, "[overlay.icon_state]-extended-glow", color = blade_color) + return ..() + +// Subtypes +/obj/item/energy_blade/sword/green + blade_color = COLOR_LIME + +/obj/item/energy_blade/sword/red + blade_color = COLOR_RED + +/obj/item/energy_blade/sword/blue + blade_color = COLOR_BLUE + +/obj/item/energy_blade/sword/purple + blade_color = COLOR_VIOLET diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index b68022c3b9d4..a1b4938bacf0 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -5,12 +5,13 @@ icon_state = "chain" item_state = "chain" obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - force = 10 - throwforce = 7 + slot_flags = SLOT_LOWER_BODY + item_flags = ITEM_FLAG_IS_WEAPON w_class = ITEM_SIZE_NORMAL - origin_tech = "{'combat':4}" + origin_tech = @'{"combat":4}' attack_verb = list("flicked", "whipped", "lashed") + material = /decl/material/solid/organic/leather + _base_attack_force = 10 /obj/item/whip/abyssal name = "abyssal whip" @@ -18,12 +19,11 @@ icon_state = "whip" item_state = "whip" obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - force = 16 //max hit with 60 strength and no equipment. Duel Arena no No forfeit - Snapshot - throwforce = 7 + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_NORMAL - origin_tech = "{'combat':4}" + origin_tech = @'{"combat":4}' attack_verb = list("flicked", "whipped", "lashed") + _base_attack_force = 16 //max hit with 60 strength and no equipment. Duel Arena no No forfeit - Snapshot /obj/item/whip/tail name = "drake's tail" @@ -31,9 +31,10 @@ icon_state = "tailwhip" item_state = "whip" obj_flags = null - force = 19 + _base_attack_force = 19 edge = TRUE - origin_tech = "{'combat':6,'materials':5}" + origin_tech = @'{"combat":6,"materials":5}' + material = /decl/material/solid/organic/leather/lizard /obj/item/whip/chainofcommand name = "chain of command" @@ -41,29 +42,27 @@ attack_verb = list("flogged", "whipped", "lashed", "disciplined") icon_state = "chain" item_state = "whip" + material = /decl/material/solid/metal/steel /obj/item/sword/replica/officersword name = "fleet officer's sword" desc = "A polished sword issued to officers of the fleet." icon = 'icons/obj/items/weapon/parade_sword.dmi' - icon_state = "officersword" - item_state = "officersword" - slot_flags = SLOT_BELT - applies_material_colour = FALSE + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + material_alteration = MAT_FLAG_ALTERATION_NAME /obj/item/sword/replica/officersword/army name = "army NCO's sword" desc = "A polished sword issued to NCOs." - icon_state = "armysword" + icon = 'icons/obj/items/weapon/parade_sword_army.dmi' /obj/item/sword/replica/officersword/armyofficer name = "army officer's sword" desc = "A curved sword issued to officers." - icon_state = "armyofficersword" - item_state = "armyofficersword" + icon = 'icons/obj/items/weapon/parade_sword_armyofficer.dmi' /obj/item/sword/replica/officersword/pettyofficer name = "chief petty officer's cutlass" desc = "A polished cutlass issued to chief petty officers of the fleet." - icon_state = "pettyofficersword" - item_state = "pettyofficersword" + icon = 'icons/obj/items/weapon/parade_sword_pettyofficer.dmi' diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index b13603b92248..05ae7042beb4 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -3,92 +3,96 @@ name = "mop" icon = 'icons/obj/janitor.dmi' icon_state = "mop" - force = 5 - throwforce = 10.0 throw_speed = 5 throw_range = 10 w_class = ITEM_SIZE_NORMAL attack_verb = list("mopped", "bashed", "bludgeoned", "whacked") - var/mopping = 0 - var/mopcount = 0 + material = /decl/material/solid/organic/wood/oak + matter = list( + /decl/material/solid/organic/cloth = MATTER_AMOUNT_SECONDARY, + ) + chem_volume = 30 + var/mopspeed = 40 - var/list/moppable_types = list( + var/static/list/moppable_types + +/obj/item/mop/proc/populate_moppable_types() + moppable_types = list( + /turf/floor, /obj/effect/decal/cleanable, - /obj/effect/overlay, - /obj/effect/rune, /obj/structure/catwalk - ) + ) /obj/item/mop/Initialize() . = ..() - create_reagents(30) + if(!moppable_types) + populate_moppable_types() /obj/item/mop/afterattack(atom/A, mob/user, proximity) if(!proximity) - return - - var/moppable - if(istype(A, /turf)) - var/turf/T = A - var/obj/effect/fluid/F = locate() in T - if(F && F.reagents.total_volume > 0) - if(F.reagents.total_volume > FLUID_SHALLOW) + return ..() + var/turf/moppable_turf = get_turf(A) + if(!istype(moppable_turf)) + return ..() + + var/mop_reagents = REAGENT_TOTAL_VOLUME(moppable_turf?.reagents) + if(mop_reagents > 0) + if(mop_reagents > FLUID_SHALLOW) + to_chat(user, SPAN_WARNING("There is too much water here to be mopped up.")) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] begins to mop up \the [moppable_turf].")) + if(do_after(user, 40, moppable_turf) && !QDELETED(moppable_turf)) + if(REAGENT_TOTAL_VOLUME(moppable_turf.reagents) > FLUID_SHALLOW) to_chat(user, SPAN_WARNING("There is too much water here to be mopped up.")) else - user.visible_message("\The [user] begins to mop up \the [T].") - if(do_after(user, 40, T) && F && !QDELETED(F)) - if(F.reagents.total_volume > FLUID_SHALLOW) - to_chat(user, SPAN_WARNING("There is too much water here to be mopped up.")) - else - qdel(F) - to_chat(user, "You have finished mopping!") - return - moppable = TRUE - - else if(is_type_in_list(A,moppable_types)) - moppable = TRUE - - if(moppable) - if(reagents.total_volume < 1) - to_chat(user, "Your mop is dry!") - return - var/turf/T = get_turf(A) - if(!T) - return - - user.visible_message("\The [user] begins to clean \the [T].") - - if(do_after(user, mopspeed, T)) - if(T) - T.clean(src, user) - to_chat(user, "You have finished mopping!") - - -/obj/effect/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/mop) || istype(I, /obj/item/soap)) - return - ..() + to_chat(user, SPAN_NOTICE("You have finished mopping!")) + moppable_turf.reagents?.clear_reagents() + return TRUE + + if(!is_type_in_list(A, moppable_types)) + return ..() + + if(REAGENT_TOTAL_VOLUME(reagents) < 1) + to_chat(user, SPAN_WARNING("\The [src] is dry!")) + return TRUE + + if(user.check_intent(I_FLAG_HARM)) + user.visible_message(SPAN_DANGER("\The [user] begins to aggressively mop \the [moppable_turf]!")) + else + user.visible_message(SPAN_NOTICE("\The [user] begins to clean \the [moppable_turf].")) + if(do_after(user, mopspeed, moppable_turf) && REAGENT_TOTAL_VOLUME(reagents)) + reagents.touch_turf(moppable_turf) + reagents.remove_any(1) + to_chat(user, SPAN_NOTICE("You have finished mopping!")) + return TRUE + +/obj/effect/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/mop) || istype(used_item, /obj/item/soap)) + return FALSE + return ..() /obj/item/mop/advanced desc = "The most advanced tool in a custodian's arsenal, with a cleaner synthesizer to boot! Just think of all the viscera you will clean up with this!" name = "advanced mop" icon_state = "advmop" item_state = "mop" - force = 6 - throwforce = 11 mopspeed = 20 material = /decl/material/solid/metal/aluminium matter = list( /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"engineering":4,"materials":4,"powerstorage":3}' + _base_attack_force = 6 + var/refill_enabled = TRUE //Self-refill toggle for when a janitor decides to mop with something other than water. var/refill_rate = 1 //Rate per process() tick mop refills itself var/refill_reagent = /decl/material/liquid/cleaner //Determins what reagent to use for refilling, just in case someone wanted to make a HOLY MOP OF PURGING /obj/item/mop/advanced/Initialize() . = ..() - START_PROCESSING(SSobj, src) + if(refill_enabled) + START_PROCESSING(SSobj, src) /obj/item/mop/advanced/attack_self(mob/user) refill_enabled = !refill_enabled @@ -96,18 +100,17 @@ START_PROCESSING(SSobj, src) else STOP_PROCESSING(SSobj,src) - to_chat(user, "You set the condenser switch to the '[refill_enabled ? "ON" : "OFF"]' position.") + to_chat(user, SPAN_NOTICE("You set the condenser switch to the '[refill_enabled ? "ON" : "OFF"]' position.")) playsound(user, 'sound/machines/click.ogg', 30, 1) /obj/item/mop/advanced/Process() - if(reagents.total_volume < 30) - reagents.add_reagent(refill_reagent, refill_rate) + if(REAGENT_TOTAL_VOLUME(reagents) < REAGENT_MAXIMUM_VOLUME(reagents)) + add_to_reagents(refill_reagent, refill_rate) -/obj/item/mop/advanced/examine(mob/user) +/obj/item/mop/advanced/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The condenser switch is set to [refill_enabled ? "ON" : "OFF"].") + . += SPAN_NOTICE("The condenser switch is set to [refill_enabled ? "ON" : "OFF"].") /obj/item/mop/advanced/Destroy() - if(refill_enabled) - STOP_PROCESSING(SSobj, src) - return ..() \ No newline at end of file + STOP_PROCESSING(SSobj, src) + return ..() diff --git a/code/game/objects/items/weapons/nuclear_cylinder.dm b/code/game/objects/items/weapons/nuclear_cylinder.dm index c9dddf2253df..8e5f910bb93c 100644 --- a/code/game/objects/items/weapons/nuclear_cylinder.dm +++ b/code/game/objects/items/weapons/nuclear_cylinder.dm @@ -1,13 +1,13 @@ -obj/item/nuclear_cylinder +/obj/item/nuclear_cylinder name = "\improper nuclear cylinder" - desc = "This cylinder is used in the self destruct system of the ship." + desc = "This cylinder is used in the self-destruct system of the ship." icon = 'icons/obj/items/nuclear_cylinder.dmi' icon_state = "nuclear_cylinder" item_state = "nuclear" obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 10.0 w_class = ITEM_SIZE_HUGE - throwforce = 15.0 throw_speed = 2 throw_range = 4 - origin_tech = "{'materials':3,'engineering':4}" \ No newline at end of file + origin_tech = @'{"materials":3,"engineering":4}' + max_health = ITEM_HEALTH_NO_DAMAGE + _base_attack_force = 10 diff --git a/code/game/objects/items/weapons/paint.dm b/code/game/objects/items/weapons/paint.dm index 4a5288f301e1..4c3c8685558c 100644 --- a/code/game/objects/items/weapons/paint.dm +++ b/code/game/objects/items/weapons/paint.dm @@ -1,75 +1,58 @@ -//NEVER USE THIS IT SUX -PETETHEGOAT -//THE GOAT WAS RIGHT - RKF - -var/global/list/cached_icons = list() - -/obj/item/chems/glass/paint - desc = "It's a paint bucket." +/obj/item/chems/glass/bucket/paint name = "paint bucket" + desc = "It's a paint bucket." icon = 'icons/obj/items/paint_bucket.dmi' - icon_state = "paintbucket" - item_state = "paintcan" material = /decl/material/solid/metal/aluminium w_class = ITEM_SIZE_NORMAL amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[10,20,30,60]" - volume = 60 - unacidable = 0 - atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 60 var/pigment -/obj/item/chems/glass/paint/afterattack(turf/simulated/target, mob/user, proximity) - if(!proximity) return - if(istype(target) && reagents.total_volume > 5) - user.visible_message("\The [target] has been splashed with something by [user]!") - reagents.trans_to_turf(target, 5) - else - return ..() - -/obj/item/chems/glass/paint/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/narcotics, reagents.maximum_volume-10) +/obj/item/chems/glass/bucket/paint/populate_reagents() + var/amt = REAGENT_MAXIMUM_VOLUME(reagents) if(pigment) - reagents.add_reagent(pigment, reagents.maximum_volume-10) + amt = round(amt/2) + add_to_reagents(pigment, amt) + add_to_reagents(/decl/material/liquid/paint, amt) + +/obj/item/chems/glass/bucket/paint/get_edible_material_amount(mob/eater) + return 0 -/obj/item/chems/glass/paint/on_update_icon() - overlays.Cut() - if(reagents.total_volume) - var/image/filling = image('icons/obj/reagentfillings.dmi', src, "paintbucket") - filling.color = reagents.get_color() - overlays += filling +/obj/item/chems/glass/bucket/paint/get_utensil_food_type() + return null -/obj/item/chems/glass/paint/red +/obj/item/chems/glass/bucket/paint/red name = "red paint bucket" - pigment = /decl/material/pigment/red + pigment = /decl/material/liquid/pigment/red -/obj/item/chems/glass/paint/yellow +/obj/item/chems/glass/bucket/paint/yellow name = "yellow paint bucket" - pigment = /decl/material/pigment/yellow + pigment = /decl/material/liquid/pigment/yellow -/obj/item/chems/glass/paint/green +/obj/item/chems/glass/bucket/paint/green name = "green paint bucket" - pigment = /decl/material/pigment/green + pigment = /decl/material/liquid/pigment/green -/obj/item/chems/glass/paint/blue +/obj/item/chems/glass/bucket/paint/blue name = "blue paint bucket" - pigment = /decl/material/pigment/blue + pigment = /decl/material/liquid/pigment/blue -/obj/item/chems/glass/paint/purple +/obj/item/chems/glass/bucket/paint/purple name = "purple paint bucket" - pigment = /decl/material/pigment/purple + pigment = /decl/material/liquid/pigment/purple -/obj/item/chems/glass/paint/black +/obj/item/chems/glass/bucket/paint/black name = "black paint bucket" - pigment = /decl/material/pigment/black + pigment = /decl/material/liquid/pigment/black -/obj/item/chems/glass/paint/white +/obj/item/chems/glass/bucket/paint/white name = "white paint bucket" - pigment = /decl/material/pigment/white + pigment = /decl/material/liquid/pigment/white -/obj/item/chems/glass/paint/random +/obj/item/chems/glass/bucket/paint/random name = "odd paint bucket" -/obj/item/chems/glass/paint/random/Initialize() - pigment = pick(subtypesof(/decl/material/pigment)) +/obj/item/chems/glass/bucket/paint/random/Initialize() + pigment = pick(decls_repository.get_decl_paths_of_subtype(/decl/material/liquid/pigment)) . = ..() diff --git a/code/game/objects/items/weapons/policetape.dm b/code/game/objects/items/weapons/policetape.dm deleted file mode 100644 index 231085dad35c..000000000000 --- a/code/game/objects/items/weapons/policetape.dm +++ /dev/null @@ -1,394 +0,0 @@ -//Define all tape types in policetape.dm -/obj/item/taperoll - name = "tape roll" - icon = 'icons/policetape.dmi' - icon_state = "tape" - w_class = ITEM_SIZE_SMALL - var/turf/start - var/turf/end - var/tape_type = /obj/item/tape - var/icon_base = "tape" - - var/apply_tape = FALSE - -/obj/item/taperoll/Initialize() - . = ..() - if(apply_tape) - var/turf/T = get_turf(src) - if(!T) - return - var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in T - if(airlock) - afterattack(airlock, null, TRUE) - return INITIALIZE_HINT_QDEL - - -var/list/image/hazard_overlays -var/list/tape_roll_applications = list() - -/obj/item/tape - name = "tape" - icon = 'icons/policetape.dmi' - icon_state = "tape" - layer = ABOVE_DOOR_LAYER - randpixel = 0 - anchored = 1 - var/lifted = 0 - var/crumpled = 0 - var/tape_dir = 0 - var/icon_base = "tape" - var/detail_overlay - var/detail_color - -/obj/item/tape/on_update_icon() - //Possible directional bitflags: 0 (AIRLOCK), 1 (NORTH), 2 (SOUTH), 4 (EAST), 8 (WEST), 3 (VERTICAL), 12 (HORIZONTAL) - overlays.Cut() - var/new_state - switch (tape_dir) - if(0) // AIRLOCK - new_state = "[icon_base]_door" - if(3) // VERTICAL - new_state = "[icon_base]_v" - if(12) // HORIZONTAL - new_state = "[icon_base]_h" - else // END POINT (1|2|4|8) - new_state = "[icon_base]_dir" - set_dir(tape_dir) - icon_state = "[new_state]_[crumpled]" - if(detail_overlay) - var/image/I = overlay_image(icon, "[new_state]_[detail_overlay]", flags=RESET_COLOR) - I.color = detail_color - overlays |= I - -/obj/item/tape/Initialize() - . = ..() - if(!hazard_overlays) - hazard_overlays = list() - hazard_overlays["[NORTH]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "N") - hazard_overlays["[EAST]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "E") - hazard_overlays["[SOUTH]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "S") - hazard_overlays["[WEST]"] = new/image('icons/effects/warning_stripes.dmi', icon_state = "W") - -/obj/item/taperoll/police - name = "police tape" - desc = "A roll of police tape used to block off crime scenes from the public." - tape_type = /obj/item/tape/police - color = COLOR_RED - -/obj/item/tape/police - name = "police tape" - desc = "A length of police tape. Do not cross." - req_access = list(access_security) - color = COLOR_RED - -/obj/item/taperoll/engineering - name = "engineering tape" - desc = "A roll of engineering tape used to block off working areas from the public." - tape_type = /obj/item/tape/engineering - color = COLOR_ORANGE - -/obj/item/taperoll/engineering/applied - apply_tape = TRUE - -/obj/item/tape/engineering - name = "engineering tape" - desc = "A length of engineering tape. Better not cross it." - req_access = list(list(access_engine,access_atmospherics)) - color = COLOR_ORANGE - -/obj/item/taperoll/atmos - name = "atmospherics tape" - desc = "A roll of atmospherics tape used to block off working areas from the public." - tape_type = /obj/item/tape/atmos - color = COLOR_BLUE_LIGHT - -/obj/item/tape/atmos - name = "atmospherics tape" - desc = "A length of atmospherics tape. Better not cross it." - req_access = list(list(access_engine,access_atmospherics)) - color = COLOR_BLUE_LIGHT - icon_base = "stripetape" - detail_overlay = "stripes" - detail_color = COLOR_YELLOW - -/obj/item/taperoll/research - name = "research tape" - desc = "A roll of research tape used to block off working areas from the public." - tape_type = /obj/item/tape/research - color = COLOR_WHITE - -/obj/item/tape/research - name = "research tape" - desc = "A length of research tape. Better not cross it." - req_access = list(access_research) - color = COLOR_WHITE - -/obj/item/taperoll/medical - name = "medical tape" - desc = "A roll of medical tape used to block off working areas from the public." - tape_type = /obj/item/tape/medical - color = COLOR_PALE_BLUE_GRAY - -/obj/item/tape/medical - name = "medical tape" - desc = "A length of medical tape. Better not cross it." - req_access = list(access_medical) - icon_base = "stripetape" - detail_overlay = "stripes" - detail_color = COLOR_PALE_BLUE_GRAY - -/obj/item/taperoll/bureaucracy - name = "red tape" - desc = "A roll of bureaucratic red tape used to block any meaningful work from being done." - tape_type = /obj/item/tape/bureaucracy - color = COLOR_RED - -/obj/item/tape/bureaucracy - name = "red tape" - desc = "A length of bureaucratic red tape. Safely ignored, but darn obstructive sometimes." - icon_base = "stripetape" - color = COLOR_RED - detail_overlay = "stripes" - detail_color = COLOR_RED - -/obj/item/taperoll/on_update_icon() - overlays.Cut() - var/image/overlay = image(icon = src.icon) - overlay.appearance_flags = RESET_COLOR - if(ismob(loc)) - if(!start) - overlay.icon_state = "start" - else - overlay.icon_state = "stop" - overlays += overlay - -/obj/item/taperoll/dropped(mob/user) - update_icon() - return ..() - -/obj/item/taperoll/pickup(mob/user) - update_icon() - return ..() - -/obj/item/taperoll/attack_hand() - update_icon() - return ..() - -/obj/item/taperoll/attack_self(mob/user) - if(!start) - start = get_turf(src) - to_chat(usr, "You place the first end of \the [src].") - update_icon() - else - end = get_turf(src) - if(start.y != end.y && start.x != end.x || start.z != end.z) - start = null - update_icon() - to_chat(usr, "\The [src] can only be laid horizontally or vertically.") - return - - if(start == end) - // spread tape in all directions, provided there is a wall/window - var/turf/T - var/possible_dirs = 0 - for(var/dir in GLOB.cardinal) - T = get_step(start, dir) - if(T && T.density) - possible_dirs += dir - else - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == GLOB.reverse_dir[dir]) - possible_dirs += dir - if(!possible_dirs) - start = null - update_icon() - to_chat(usr, "You can't place \the [src] here.") - return - if(possible_dirs & (NORTH|SOUTH)) - var/obj/item/tape/TP = new tape_type(start) - for(var/dir in list(NORTH, SOUTH)) - if (possible_dirs & dir) - TP.tape_dir += dir - TP.update_icon() - if(possible_dirs & (EAST|WEST)) - var/obj/item/tape/TP = new tape_type(start) - for(var/dir in list(EAST, WEST)) - if (possible_dirs & dir) - TP.tape_dir += dir - TP.update_icon() - start = null - update_icon() - to_chat(usr, "You finish placing \the [src].") - return - - var/turf/cur = start - var/orientation = get_dir(start, end) - var/dir = 0 - switch(orientation) - if(NORTH, SOUTH) set_dir(NORTH|SOUTH) // North-South taping - if(EAST, WEST) set_dir(EAST|WEST) // East-West taping - - var/can_place = 1 - while (can_place) - if(cur.density == 1) - can_place = 0 - else if (istype(cur, /turf/space)) - can_place = 0 - else - for(var/obj/O in cur) - if(O.density) - can_place = 0 - break - if(cur == end) - break - cur = get_step_towards(cur,end) - if (!can_place) - start = null - update_icon() - to_chat(usr, "You can't run \the [src] through that!") - return - - cur = start - var/tapetest - var/tape_dir - while (1) - tapetest = 0 - tape_dir = dir - if(cur == start) - var/turf/T = get_step(start, GLOB.reverse_dir[orientation]) - if(T && !T.density) - tape_dir = orientation - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == orientation) - tape_dir = dir - else if(cur == end) - var/turf/T = get_step(end, orientation) - if(T && !T.density) - tape_dir = GLOB.reverse_dir[orientation] - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == GLOB.reverse_dir[orientation]) - tape_dir = dir - for(var/obj/item/tape/T in cur) - if((T.tape_dir == tape_dir) && (T.icon_base == icon_base)) - tapetest = 1 - break - if(!tapetest) - var/obj/item/tape/T = new tape_type(cur) - T.tape_dir = tape_dir - T.update_icon() - if(tape_dir & SOUTH) - T.layer += 0.1 // Must always show above other tapes - if(cur == end) - break - cur = get_step_towards(cur,end) - start = null - update_icon() - to_chat(usr, "You finish placing \the [src].") - return - -/obj/item/taperoll/afterattack(var/atom/A, mob/user, proximity) - if(!proximity) - return - - if (istype(A, /obj/machinery/door/airlock)) - var/turf/T = get_turf(A) - var/obj/item/tape/P = new tape_type(T) - P.update_icon() - P.layer = ABOVE_DOOR_LAYER - to_chat(user, "You finish placing \the [src].") - - if (istype(A, /turf/simulated/floor) ||istype(A, /turf/unsimulated/floor)) - var/turf/F = A - var/direction = user.loc == F ? user.dir : turn(user.dir, 180) - var/icon/hazard_overlay = hazard_overlays["[direction]"] - if(tape_roll_applications[F] == null) - tape_roll_applications[F] = 0 - - if(tape_roll_applications[F] & direction) // hazard_overlay in F.overlays wouldn't work. - user.visible_message("\The [user] uses the adhesive of \the [src] to remove area markings from \the [F].", "You use the adhesive of \the [src] to remove area markings from \the [F].") - F.overlays -= hazard_overlay - tape_roll_applications[F] &= ~direction - else - user.visible_message("\The [user] applied \the [src] on \the [F] to create area markings.", "You apply \the [src] on \the [F] to create area markings.") - F.overlays |= hazard_overlay - tape_roll_applications[F] |= direction - return - -/obj/item/tape/proc/crumple() - if(!crumpled) - crumpled = 1 - update_icon() - SetName("crumpled [name]") - -/obj/item/tape/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(!lifted && ismob(mover)) - var/mob/M = mover - add_fingerprint(M) - if (!allowed(M)) //only select few learn art of not crumpling the tape - to_chat(M, "You are not supposed to go past [src]...") - if(M.a_intent == I_HELP) - return 0 - crumple() - return ..(mover) - -/obj/item/tape/attackby(obj/item/W, mob/user) - breaktape(user) - -/obj/item/tape/attack_hand(mob/user) - if (user.a_intent == I_HELP && src.allowed(user)) - user.show_viewers("\The [user] lifts \the [src], allowing passage.") - for(var/obj/item/tape/T in gettapeline()) - T.lift(100) //~10 seconds - else - breaktape(user) - -/obj/item/tape/proc/lift(time) - lifted = 1 - layer = ABOVE_HUMAN_LAYER - spawn(time) - lifted = 0 - reset_plane_and_layer() - -// Returns a list of all tape objects connected to src, including itself. -/obj/item/tape/proc/gettapeline() - var/list/dirs = list() - if(tape_dir & NORTH) - dirs += NORTH - if(tape_dir & SOUTH) - dirs += SOUTH - if(tape_dir & WEST) - dirs += WEST - if(tape_dir & EAST) - dirs += EAST - - var/list/obj/item/tape/tapeline = list() - for (var/obj/item/tape/T in get_turf(src)) - tapeline += T - for(var/dir in dirs) - var/turf/cur = get_step(src, dir) - var/not_found = 0 - while (!not_found) - not_found = 1 - for (var/obj/item/tape/T in cur) - tapeline += T - not_found = 0 - cur = get_step(cur, dir) - return tapeline - - - - -/obj/item/tape/proc/breaktape(mob/user) - if(user.a_intent == I_HELP) - to_chat(user, "You refrain from breaking \the [src].") - return - user.visible_message("\The [user] breaks \the [src]!","You break \the [src].") - - for (var/obj/item/tape/T in gettapeline()) - if(T == src) - continue - if(T.tape_dir & get_dir(T, src)) - qdel(T) - - qdel(src) //TODO: Dropping a trash item holding fibers/fingerprints of all broken tape parts - return diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm deleted file mode 100644 index 06d069961cd9..000000000000 --- a/code/game/objects/items/weapons/scrolls.dm +++ /dev/null @@ -1,60 +0,0 @@ -/obj/item/teleportation_scroll - name = "scroll of teleportation" - desc = "A scroll for moving around." - icon = 'icons/obj/wizard.dmi' - icon_state = "scroll" - var/uses = 4.0 - w_class = ITEM_SIZE_TINY - item_state = "paper" - throw_speed = 4 - throw_range = 20 - origin_tech = "{'wormholes':4}" - -/obj/item/teleportation_scroll/attack_self(mob/user) - if((user.mind && !GLOB.wizards.is_antagonist(user.mind))) - to_chat(usr, "You stare at the scroll but cannot make sense of the markings!") - return - - user.set_machine(src) - var/dat = "Teleportation Scroll:
              " - dat += "Number of uses: [src.uses]
              " - dat += "
              " - dat += "Four uses use them wisely:
              " - dat += "Teleport
              " - dat += "Kind regards,
              Wizards Federation

              P.S. Don't forget to bring your gear, you'll need it to cast most spells.
              " - show_browser(user, dat, "window=scroll") - onclose(user, "scroll") - return - -/obj/item/teleportation_scroll/Topic(href, href_list) - if(..()) - return 1 - var/mob/living/carbon/human/H = usr - if (!( istype(H, /mob/living/carbon/human))) - return 1 - if ((usr == src.loc || (in_range(src, usr) && istype(src.loc, /turf)))) - usr.set_machine(src) - if (href_list["spell_teleport"]) - if (src.uses >= 1) - teleportscroll(H) - attack_self(H) - return - -/obj/item/teleportation_scroll/proc/teleportscroll(var/mob/user) - var/area/thearea = input(user, "Area to jump to", "BOOYEA") as null|anything in wizteleportlocs - thearea = thearea ? wizteleportlocs[thearea] : thearea - - if (!thearea || CanUseTopic(user) != STATUS_INTERACTIVE) - return - - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(5, 0, user.loc) - smoke.attach(user) - smoke.start() - var/turf/end = user.try_teleport(thearea) - - if(!end) - to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") - return - smoke.start() - src.uses -= 1 diff --git a/code/game/objects/items/weapons/secrets_disk.dm b/code/game/objects/items/weapons/secrets_disk.dm index 9443f8b6d845..70a6c4036b17 100644 --- a/code/game/objects/items/weapons/secrets_disk.dm +++ b/code/game/objects/items/weapons/secrets_disk.dm @@ -1,55 +1,72 @@ /obj/item/disk/secret_project name = "'classified' project data disk" desc = "A special disk for storing massive amounts of data. It is marked as classified, and has an ID card slot on top." - icon = 'icons/obj/cloning.dmi' - icon_state = "datadisk0" - item_state = "card-id" - w_class = ITEM_SIZE_SMALL - req_access = access_ce + color = COLOR_GRAY20 + label = "label_warning" + req_access = list(access_ce) var/subject = "some strange, incomprehensible design" var/locked = 1 /obj/item/disk/secret_project/science + color = COLOR_INDIGO desc = "A special disk for storing massive amounts of data. It is marked as classified, and has an ID card slot on top. \ This one has a lengthy legal label on it denoting it the private, copyrighted property of the Expeditionary Corps Organisation." - req_access = access_rd + req_access = list(access_rd) + +/obj/item/disk/secret_project/proc/get_secret_project_codenames() + var/static/list/codenames = list( + "gamma", "delta", "epsilon", "zeta", "theta", "lambda", "omicron", "sigma", "tau", + "upsilon", "omega", "echelon", "prism", "calypso", "bernoulli", "harmony", "nyx", "fresnel" + ) + +/obj/item/disk/secret_project/proc/get_secret_project_types() + var/static/list/types = list( + "an experimental design for", + "a blueprint to build", + "a long set of theoretical formulas detailing the functioning of" + ) + return types + +/obj/item/disk/secret_project/proc/get_secret_project_nouns() + var/static/list/nouns = list( + "a superluminal artillery cannon", "a fusion engine", "an atmospheric scrubber",\ + "a human cloning pod", "a microwave oven", "a wormhole generator", "a laser carbine", "an energy pistol",\ + "a wormhole", "a teleporter", "a huge mining drill", "a strange spacecraft", "a space station",\ + "a sleek-looking fighter spacecraft", "a ballistic rifle", "an energy sword", "an inanimate carbon rod" + ) + return nouns + +/obj/item/disk/secret_project/proc/get_secret_project_descriptors() + var/static/list/descriptors = list( + "that is extremely powerful", "which is highly efficient", "which is incredibly compact", "created by aliens", + "that runs off of an exotic form of matter", "that runs off of hydrogen gas", "that just looks really cool" + ) /obj/item/disk/secret_project/Initialize() . = ..() - var/codename = pick("gamma", "delta", "epsilon", "zeta", "theta", "lambda", "omicron", "sigma", "tau",\ - "upsilon", "omega", "echelon", "prism", "calypso", "bernoulli", "harmony", "nyx", "fresnel") - name = "'[codename]' project data disk" - subject = pick("an experimental design for", "a blueprint to build",\ - "a long set of theoretical formulas detailing the functioning of") - subject += " " + pick("a superluminal artillery cannon", "a supermatter engine", "a fusion engine", "an atmospheric scrubber",\ - "a human cloning pod", "a microwave oven", "a wormhole generator", "a laser carbine", "an energy pistol",\ - "a wormhole", "a teleporter", "a huge mining drill", "a strange spacecraft", "a space station",\ - "a sleek-looking fighter spacecraft", "a ballistic rifle", "an energy sword", "an inanimate carbon rod") - subject += " " + pick("that is extremely powerful", "which is highly efficient", "which is incredibly compact",\ - "that runs off of an exotic form of matter", "that runs off of hydrogen gas", "created by aliens", "that just looks really cool") + name = "'[pick(get_secret_project_codenames())]' project data disk" + subject = "[pick(get_secret_project_types())] [pick(get_secret_project_nouns())] [pick(get_secret_project_descriptors())]" -/obj/item/disk/secret_project/examine(mob/user) - ..() - if(!locked) - to_chat(user, "With the disk's classified contents unlocked, \ - you peer into its preview screen and see [subject].") +/obj/item/disk/secret_project/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(locked) + . += "The disk is locked, you cannot see its contents." else - to_chat(user, "The disk is locked, you cannot see its contents.") + . += "With the disk's classified contents unlocked, you peer into its preview screen and see [subject]." /obj/item/disk/secret_project/emag_act(var/remaining_charges, var/mob/user) - to_chat(user, "The cryptographic lock on this disk is far too complex. \ - Your sequencer can't break the code.") + to_chat(user, "The cryptographic lock on this disk is far too complex. Your sequencer can't break the code.") return 0 -/obj/item/disk/secret_project/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/card/id)) - var/obj/item/card/id/ID = W +/obj/item/disk/secret_project/attackby(obj/item/used_item, mob/user) + if(istype(used_item,/obj/item/card/id)) + var/obj/item/card/id/ID = used_item if(check_access(ID)) locked = !locked to_chat(user, "You swipe your card and [locked ? "lock":"unlock"] the disk.") else to_chat(user, "The disk's screen flashes 'Access Denied'.") - return + return TRUE . = ..() /obj/item/disk/secret_project/verb/change_codename() @@ -65,10 +82,12 @@ else to_chat(usr, "The disk's screen flashes 'Access Denied'. It is locked.") -/obj/item/storage/box/secret_project_disks +/obj/item/box/secret_project_disks name = "box of classified data disks" desc = "A box full of disks. Marked with a red 'Top Secret' label. Looks rather ominous." - startswith = list(/obj/item/disk/secret_project = 5) -/obj/item/storage/box/secret_project_disks/science - startswith = list(/obj/item/disk/secret_project/science = 5) \ No newline at end of file +/obj/item/box/secret_project_disks/WillContain() + return list(/obj/item/disk/secret_project = 5) + +/obj/item/box/secret_project_disks/science/WillContain() + return list(/obj/item/disk/secret_project/science = 5) \ No newline at end of file diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm deleted file mode 100644 index defc9a946e34..000000000000 --- a/code/game/objects/items/weapons/shields.dm +++ /dev/null @@ -1,204 +0,0 @@ -//** Shield Helpers -//These are shared by various items that have shield-like behaviour - -//bad_arc is the ABSOLUTE arc of directions from which we cannot block. If you want to fix it to e.g. the user's facing you will need to rotate the dirs yourself. -/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null) - //check attack direction - var/attack_dir = 0 //direction from the user to the source of the attack - if(istype(damage_source, /obj/item/projectile)) - var/obj/item/projectile/P = damage_source - attack_dir = get_dir(get_turf(user), P.starting) - else if(attacker) - attack_dir = get_dir(get_turf(user), get_turf(attacker)) - else if(damage_source) - attack_dir = get_dir(get_turf(user), get_turf(damage_source)) - - if(!(attack_dir && (attack_dir & bad_arc))) - return 1 - return 0 - -/proc/default_parry_check(mob/user, mob/attacker, atom/damage_source) - //parry only melee attacks - if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) - return 0 - - //block as long as they are not directly behind us - var/bad_arc = user.dir && GLOB.reverse_dir[user.dir] //arc of directions from which we cannot block - if(!check_shield_arc(user, bad_arc, damage_source, attacker)) - return 0 - - return 1 - -/obj/item/shield - name = "shield" - var/base_block_chance = 60 - -/obj/item/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - if(user.incapacitated()) - return 0 - - //block as long as they are not directly behind us - var/bad_arc = user.dir && GLOB.reverse_dir[user.dir] //arc of directions from which we cannot block - if(check_shield_arc(user, bad_arc, damage_source, attacker)) - if(prob(get_block_chance(user, damage, damage_source, attacker))) - user.visible_message("\The [user] blocks [attack_text] with \the [src]!") - return 1 - return 0 - -/obj/item/shield/proc/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) - return base_block_chance - -/obj/item/shield/riot - name = "riot shield" - desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder." - icon = 'icons/obj/items/shield/riot.dmi' - icon_state = "riot" - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BACK - force = 5.0 - throwforce = 5.0 - throw_speed = 1 - throw_range = 4 - w_class = ITEM_SIZE_HUGE - origin_tech = "{'materials':2}" - material = /decl/material/solid/glass - matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT) - attack_verb = list("shoved", "bashed") - var/cooldown = 0 //shield bash cooldown. based on world.time - var/max_block = 15 - var/can_block_lasers = FALSE - -/obj/item/shield/riot/handle_shield(mob/user) - . = ..() - if(.) playsound(user.loc, 'sound/weapons/Genhit.ogg', 50, 1) - -/obj/item/shield/riot/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) - if(istype(damage_source, /obj/item/projectile)) - var/obj/item/projectile/P = damage_source - //plastic shields do not stop bullets or lasers, even in space. Will block beanbags, rubber bullets, and stunshots just fine though. - if(is_sharp(P) && damage >= max_block) - return 0 - if(istype(P, /obj/item/projectile/beam) && (!can_block_lasers || (P.armor_penetration >= max_block))) - return 0 - return base_block_chance - -/obj/item/shield/riot/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/baton)) - if(cooldown < world.time - 25) - user.visible_message("[user] bashes [src] with [W]!") - playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) - cooldown = world.time - else - ..() - -/obj/item/shield/riot/metal - name = "plasteel combat shield" - icon = 'icons/obj/items/shield/metal.dmi' - icon_state = "metal" - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BACK - force = 6.0 - throwforce = 7.0 - throw_range = 3 - w_class = ITEM_SIZE_HUGE - material = /decl/material/solid/metal/plasteel - max_block = 50 - can_block_lasers = TRUE - slowdown_general = 1.5 - -/obj/item/shield/buckler - name = "buckler" - desc = "A wooden buckler used to block sharp things from entering your body back in the day.." - icon = 'icons/obj/items/shield/buckler.dmi' - icon_state = "buckler" - slot_flags = SLOT_BACK - force = 8 - throwforce = 8 - base_block_chance = 60 - throw_speed = 10 - throw_range = 20 - w_class = ITEM_SIZE_HUGE - origin_tech = "{'materials':1}" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/wood = MATTER_AMOUNT_REINFORCEMENT) - attack_verb = list("shoved", "bashed") - -/obj/item/shield/buckler/handle_shield(mob/user) - . = ..() - if(.) playsound(user.loc, 'sound/weapons/Genhit.ogg', 50, 1) - -/obj/item/shield/buckler/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) - if(istype(damage_source, /obj/item/projectile/bullet)) - return 0 //No blocking bullets, I'm afraid. - return base_block_chance - -/* - * Energy Shield - */ - -/obj/item/shield/energy - name = "energy combat shield" - desc = "A shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere." - icon = 'icons/obj/items/shield/e_shield.dmi' - icon_state = "eshield0" // eshield1 for expanded - obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 3.0 - throwforce = 5.0 - throw_speed = 1 - throw_range = 4 - w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':4,'magnets':3,'esoteric':4}" - attack_verb = list("shoved", "bashed") - var/active = 0 - -/obj/item/shield/energy/handle_shield(mob/user) - if(!active) - return 0 //turn it on first! - . = ..() - - if(.) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, user.loc) - spark_system.start() - playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) - -/obj/item/shield/energy/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) - if(istype(damage_source, /obj/item/projectile)) - var/obj/item/projectile/P = damage_source - if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam)) - return (base_block_chance - round(damage / 2.5)) //block bullets and beams using the old block chance - return base_block_chance - -/obj/item/shield/energy/attack_self(mob/living/user) - if ((MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, "You beat yourself in the head with [src].") - user.take_organ_damage(5) - active = !active - if (active) - force = 10 - update_icon() - w_class = ITEM_SIZE_HUGE - playsound(user, 'sound/weapons/saberon.ogg', 50, 1) - to_chat(user, "\The [src] is now active.") - - else - force = 3 - update_icon() - w_class = ITEM_SIZE_TINY - playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) - to_chat(user, "\The [src] can now be concealed.") - - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - H.update_inv_l_hand() - H.update_inv_r_hand() - - add_fingerprint(user) - return - -/obj/item/shield/energy/on_update_icon() - icon_state = "eshield[active]" - if(active) - set_light(0.4, 0.1, 1, 2, "#006aff") - else - set_light(0) diff --git a/code/game/objects/items/weapons/shields/_shield.dm b/code/game/objects/items/weapons/shields/_shield.dm new file mode 100644 index 000000000000..6da8605ec6bc --- /dev/null +++ b/code/game/objects/items/weapons/shields/_shield.dm @@ -0,0 +1,54 @@ +//** Shield Helpers +//These are shared by various items that have shield-like behaviour + +//bad_arc is the ABSOLUTE arc of directions from which we cannot block. If you want to fix it to e.g. the user's facing you will need to rotate the dirs yourself. +/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null) + //check attack direction + var/attack_dir = 0 //direction from the user to the source of the attack + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + attack_dir = get_dir(get_turf(user), P.starting) + else if(attacker) + attack_dir = get_dir(get_turf(user), get_turf(attacker)) + else if(damage_source) + attack_dir = get_dir(get_turf(user), get_turf(damage_source)) + + if(!(attack_dir && (attack_dir & bad_arc))) + return 1 + return 0 + +/proc/default_parry_check(mob/user, mob/attacker, atom/damage_source) + //parry only melee attacks + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) + return 0 + + //block as long as they are not directly behind us + var/bad_arc = user.dir && global.reverse_dir[user.dir] //arc of directions from which we cannot block + if(!check_shield_arc(user, bad_arc, damage_source, attacker)) + return 0 + + return 1 + +/obj/item/shield + name = "abstract shield" + abstract_type = /obj/item/shield + var/base_block_chance = 60 + +/obj/item/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(user.incapacitated()) + return 0 + //block as long as they are not directly behind us + var/bad_arc = user.dir && global.reverse_dir[user.dir] //arc of directions from which we cannot block + if(check_shield_arc(user, bad_arc, damage_source, attacker)) + var/block_chance = get_block_chance(user, damage, damage_source, attacker) + if(attacker) + block_chance = max(0, block_chance - 10 * attacker.get_skill_difference(SKILL_COMBAT, user)) + if(prob(block_chance)) + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + if(max_health != ITEM_HEALTH_NO_DAMAGE) + take_damage(damage) + return 1 + return 0 + +/obj/item/shield/proc/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + return base_block_chance diff --git a/code/game/objects/items/weapons/shields/shield_crafted.dm b/code/game/objects/items/weapons/shields/shield_crafted.dm new file mode 100644 index 000000000000..5d892688b0ad --- /dev/null +++ b/code/game/objects/items/weapons/shields/shield_crafted.dm @@ -0,0 +1,38 @@ +/obj/item/shield/crafted + slot_flags = SLOT_BACK + base_block_chance = 60 + throw_speed = 10 + throw_range = 20 + w_class = ITEM_SIZE_HUGE + origin_tech = @'{"materials":1}' + abstract_type = /obj/item/shield/crafted + icon_state = ICON_STATE_WORLD + attack_verb = list("shoved", "bashed") + _base_attack_force = 8 + max_health = 250 + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + var/wooden_icon + var/decl/material/reinforcement_material = /decl/material/solid/metal/iron + +/obj/item/shield/crafted/set_material(new_material) + . = ..() + if(wooden_icon) + if(istype(material, /decl/material/solid/organic/wood)) + set_icon(wooden_icon) + else + set_icon(initial(icon)) + update_icon() + +/obj/item/shield/crafted/Initialize(ml, material_key, reinf_material_key) + if(reinf_material_key) + reinforcement_material = reinf_material_key + if(ispath(reinforcement_material)) + reinforcement_material = GET_DECL(reinforcement_material) + LAZYSET(matter, reinforcement_material.type, MATTER_AMOUNT_REINFORCEMENT) + . = ..() + +/obj/item/shield/crafted/on_update_icon() + . = ..() + if(istype(reinforcement_material)) + add_overlay(overlay_image(icon, "[icon_state]-reinforcement", reinforcement_material.color, RESET_COLOR)) diff --git a/code/game/objects/items/weapons/shields/shield_crafted_buckler.dm b/code/game/objects/items/weapons/shields/shield_crafted_buckler.dm new file mode 100644 index 000000000000..6d78daef790f --- /dev/null +++ b/code/game/objects/items/weapons/shields/shield_crafted_buckler.dm @@ -0,0 +1,17 @@ +/obj/item/shield/crafted/buckler + name = "buckler" + desc = "A small, round shield used to block sharp things from entering your body." + icon = 'icons/obj/items/shield/buckler_metal.dmi' + wooden_icon = 'icons/obj/items/shield/buckler_wood.dmi' + +/obj/item/shield/crafted/buckler/improvised + name_prefix = "improvised" + +/obj/item/shield/crafted/buckler/handle_shield(mob/user) + . = ..() + if(.) playsound(user.loc, 'sound/weapons/Genhit.ogg', 50, 1) + +/obj/item/shield/crafted/buckler/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile/bullet)) + return 0 //No blocking bullets, I'm afraid. + return base_block_chance diff --git a/code/game/objects/items/weapons/shields/shield_crafting.dm b/code/game/objects/items/weapons/shields/shield_crafting.dm new file mode 100644 index 000000000000..783be5a4e6e2 --- /dev/null +++ b/code/game/objects/items/weapons/shields/shield_crafting.dm @@ -0,0 +1,54 @@ +// General item for 'proper' shield crafting. +/obj/item/shield_fasteners + name = "shield fasteners" + desc = "A handful of shaped fasteners used to hold a buckler or shield together." + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/shield_fasteners.dmi' + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + material_alteration = MAT_FLAG_ALTERATION_ALL + +// TODO: single-step slapcrafting +/obj/item/shield_base + w_class = ITEM_SIZE_LARGE + desc = "An unfinished collection of shield bits, waiting for fastenings." + icon_state = ICON_STATE_WORLD + abstract_type = /obj/item/shield_base + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + material_alteration = MAT_FLAG_ALTERATION_ALL + var/wooden_icon + var/fittings_type = /obj/item/shield_fasteners + var/finished_type + var/work_skill = SKILL_CONSTRUCTION + +/obj/item/shield_base/attackby(obj/item/used_item, mob/user) + if(fittings_type && istype(used_item, fittings_type) && finished_type && user.try_unequip(used_item)) + to_chat(user, SPAN_NOTICE("You start laying out \the [src] and affixing \the [used_item].")) + if(user.do_skilled(5 SECONDS, work_skill, src, check_holding = TRUE)) + var/was_held = (loc == user) + var/obj/item/shield/crafted/shield = new finished_type(get_turf(src), material?.type, used_item.material?.type) + user.visible_message("\The [user] secures \the [src] with \the [used_item], finishing \a [shield].") + qdel(src) + qdel(used_item) + if(was_held) + user.put_in_hands(shield) + return TRUE + return ..() + +/obj/item/shield_base/set_material(new_material) + . = ..() + if(wooden_icon) + if(istype(material, /decl/material/solid/organic/wood)) + set_icon(wooden_icon) + else + set_icon(initial(icon)) + update_icon() + +// Subtypes below. +/obj/item/shield_base/buckler + name_prefix = "unfinished" + name = "buckler" + icon = 'icons/obj/items/shield/buckler_base_metal.dmi' + wooden_icon = 'icons/obj/items/shield/buckler_base_wood.dmi' + finished_type = /obj/item/shield/crafted/buckler diff --git a/code/game/objects/items/weapons/shields/shield_energy.dm b/code/game/objects/items/weapons/shields/shield_energy.dm new file mode 100644 index 000000000000..c7d54652a56e --- /dev/null +++ b/code/game/objects/items/weapons/shields/shield_energy.dm @@ -0,0 +1,83 @@ +/* + * Energy Shield + */ + +/obj/item/shield/energy + name = "energy combat shield" + desc = "A shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere." + icon = 'icons/obj/items/shield/e_shield.dmi' + icon_state = "eshield0" // eshield1 for expanded + obj_flags = OBJ_FLAG_CONDUCTIBLE + throw_speed = 1 + throw_range = 4 + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":4,"magnets":3,"esoteric":4}' + attack_verb = list("shoved", "bashed") + material = /decl/material/solid/metal/titanium + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE, + ) + _base_attack_force = 3 + var/active = 0 + var/shield_light_color = "#006aff" + +/obj/item/shield/energy/Initialize() + set_extension(src, /datum/extension/base_icon_state, copytext(initial(icon_state), 1, length(initial(icon_state)))) + . = ..() + update_icon() + +/obj/item/shield/energy/handle_shield(mob/user) + if(!active) + return 0 //turn it on first! + . = ..() + + if(.) + spark_at(user.loc, amount=5) + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + +/obj/item/shield/energy/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + if(((P.is_sharp() || P.has_edge()) && damage > 10) || istype(P, /obj/item/projectile/beam)) + return (base_block_chance - round(damage / 2.5)) //block bullets and beams using the old block chance + return base_block_chance + +/obj/item/shield/energy/attack_self(mob/user) + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + to_chat(user, SPAN_DANGER("You beat yourself in the head with [src].")) + if(isliving(user)) + var/mob/living/M = user + M.take_organ_damage(5, 0) + active = !active + if (active) + set_base_attack_force(10) + update_icon() + w_class = ITEM_SIZE_HUGE + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("\The [src] is now active.")) + + else + set_base_attack_force(3) + update_icon() + w_class = ITEM_SIZE_SMALL + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("\The [src] can now be concealed.")) + + if(ishuman(user)) + var/mob/living/human/H = user + H.update_inhand_overlays() + + add_fingerprint(user) + return + +/obj/item/shield/energy/on_update_icon() + . = ..() + var/datum/extension/base_icon_state/base_name = get_extension(src, /datum/extension/base_icon_state) + icon_state = "[base_name.base_icon_state][active]" //Replace 0 with current state + if(active) + set_light(1.5, 1.5, shield_light_color) + else + set_light(0) diff --git a/code/game/objects/items/weapons/shields/shield_riot.dm b/code/game/objects/items/weapons/shields/shield_riot.dm new file mode 100644 index 000000000000..afd8e5959e44 --- /dev/null +++ b/code/game/objects/items/weapons/shields/shield_riot.dm @@ -0,0 +1,58 @@ +/obj/item/shield/riot + name = "riot shield" + desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder." + icon = 'icons/obj/items/shield/riot.dmi' + icon_state = ICON_STATE_WORLD + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + throw_speed = 1 + throw_range = 4 + w_class = ITEM_SIZE_HUGE + origin_tech = @'{"materials":2}' + material = /decl/material/solid/fiberglass + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT) + attack_verb = list("shoved", "bashed") + var/cooldown = 0 //shield bash cooldown. based on world.time + var/max_block = 15 + var/can_block_lasers = FALSE + +/obj/item/shield/riot/handle_shield(mob/user) + . = ..() + if(.) playsound(user.loc, 'sound/weapons/Genhit.ogg', 50, 1) + +/obj/item/shield/riot/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + //plastic shields do not stop bullets or lasers, even in space. Will block beanbags, rubber bullets, and stunshots just fine though. + if((P.is_sharp() || P.has_edge()) && damage >= max_block) + return 0 + if(istype(P, /obj/item/projectile/beam) && (!can_block_lasers || (P.armor_penetration >= max_block))) + return 0 + return base_block_chance + +/obj/item/shield/riot/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/baton)) + if(cooldown < world.time - 25) + user.visible_message("[user] bashes [src] with [used_item]!") + playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) + cooldown = world.time + return TRUE + else + return ..() + +/obj/item/shield/riot/metal + name = "plasteel combat shield" + icon = 'icons/obj/items/shield/metal.dmi' + icon_state = ICON_STATE_WORLD + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_BACK + throw_range = 3 + w_class = ITEM_SIZE_HUGE + material = /decl/material/solid/metal/plasteel + max_block = 50 + can_block_lasers = TRUE + slowdown_general = 1.5 + _base_attack_force = 6 + +/obj/item/shield/riot/metal/security //A cosmetic difference. + icon = 'icons/obj/items/shield/metal_security.dmi' diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm index ef77d66f2bcb..15e1cb314ab5 100644 --- a/code/game/objects/items/weapons/soap.dm +++ b/code/game/objects/items/weapons/soap.dm @@ -1,3 +1,6 @@ +#define SOAP_MAX_VOLUME 30 //Maximum volume the soap can contain +#define SOAP_CLEANER_ON_WET 15 //Volume of cleaner generated when wetting the soap + /obj/item/soap name = "soap" desc = "A cheap bar of soap. Doesn't smell." @@ -6,11 +9,14 @@ icon_state = "soap" atom_flags = ATOM_FLAG_OPEN_CONTAINER w_class = ITEM_SIZE_SMALL - throwforce = 0 throw_speed = 4 throw_range = 20 - var/key_data + material = /decl/material/liquid/cleaner/soap + max_health = 5 + _base_attack_force = 0 + chem_volume = SOAP_MAX_VOLUME + var/key_data var/list/valid_colors = list(COLOR_GREEN_GRAY, COLOR_RED_GRAY, COLOR_BLUE_GRAY, COLOR_BROWN, COLOR_PALE_PINK, COLOR_PALE_BTL_GREEN, COLOR_OFF_WHITE, COLOR_GRAY40, COLOR_GOLD) var/list/valid_scents = list("fresh air", "cinnamon", "mint", "cocoa", "lavender", "an ocean breeze", "a summer garden", "vanilla", "cheap perfume") var/list/scent_intensity = list("faintly", "strongly", "overbearingly") @@ -18,88 +24,107 @@ var/decal_name var/list/decals = list("diamond", "heart", "circle", "triangle", "") +/obj/item/soap/crafted + desc = "A lump of home-made soap." + icon_state = "soap-lump" + material_alteration = MAT_FLAG_ALTERATION_COLOR + +/obj/item/soap/crafted/generate_icon() + return + +/obj/item/soap/populate_reagents() + wet() + /obj/item/soap/Initialize() . = ..() - create_reagents(30) - wet() + generate_icon() + +/obj/item/soap/proc/generate_icon() var/shape = pick(valid_shapes) var/scent = pick(valid_scents) var/smelly = pick(scent_intensity) icon_state = "soap-[shape]" - color = pick(valid_colors) + set_color(pick(valid_colors)) decal_name = pick(decals) desc = "\A [shape] bar of soap. It smells [smelly] of [scent]." update_icon() /obj/item/soap/proc/wet() - reagents.add_reagent(/decl/material/liquid/cleaner, 15) + add_to_reagents(/decl/material/liquid/cleaner/soap, SOAP_CLEANER_ON_WET, phase = MAT_PHASE_LIQUID) -/obj/item/soap/Crossed(var/mob/living/AM) - if(istype(AM)) - AM.slip("the [src.name]",3) +/obj/item/soap/Crossed(atom/movable/AM) + var/mob/living/victim = AM + if(istype(victim)) + victim.slip("\the [src]", 3) + return ..() /obj/item/soap/afterattack(atom/target, mob/user, proximity) - if(!proximity) return - //I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing. - //So this is a workaround. This also makes more sense from an IC standpoint. ~Carn - var/cleaned = FALSE - if(user.client && (target in user.client.screen)) - to_chat(user, "You need to take that [target.name] off before cleaning it.") - else if(istype(target,/obj/effect/decal/cleanable/blood)) - to_chat(user, "You scrub \the [target.name] out.") - target.clean_blood() //Blood is a cleanable decal, therefore needs to be accounted for before all cleanable decals. - cleaned = TRUE - else if(istype(target,/obj/effect/decal/cleanable)) - to_chat(user, "You scrub \the [target.name] out.") - qdel(target) - cleaned = TRUE - else if(istype(target,/turf) || istype(target, /obj/structure/catwalk)) - var/turf/T = get_turf(target) - if(!T) - return - user.visible_message("[user] starts scrubbing \the [T].") - T.clean(src, user, 80, "You scrub \the [target.name] clean.") - cleaned = TRUE - else if(istype(target,/obj/structure/hygiene/sink)) - to_chat(user, "You wet \the [src] in the sink.") + + if(!proximity) + return ..() + + if(istype(target,/obj/structure/hygiene/sink)) + to_chat(user, SPAN_NOTICE("You wet \the [src] in the sink.")) wet() - else if(ishuman(target)) - to_chat(user, "You clean \the [target.name].") - if(reagents) - reagents.trans_to(target, reagents.total_volume / 8) - target.clean_blood() //Clean bloodied atoms. Blood decals themselves need to be handled above. - cleaned = TRUE - else - to_chat(user, "You clean \the [target.name].") - target.clean_blood() //Clean bloodied atoms. Blood decals themselves need to be handled above. - cleaned = TRUE - - if(cleaned) - user.update_personal_goal(/datum/goal/clean, 1) + return TRUE + + if(REAGENT_TOTAL_VOLUME(reagents) < 1) + to_chat(user, SPAN_WARNING("\The [src] is too dry to clean \the [target].")) + return TRUE + + if(isturf(target) || istype(target, /obj/structure/catwalk)) + target = get_turf(target) + if(!isturf(target)) + return ..() + user.visible_message(SPAN_NOTICE("\The [user] starts scrubbing \the [target].")) + if(!do_after(user, 8 SECONDS, target) && REAGENT_TOTAL_VOLUME(reagents)) + return TRUE + to_chat(user, SPAN_NOTICE("You scrub \the [target] clean.")) + else if(istype(target,/obj/effect/decal/cleanable)) + to_chat(user, SPAN_NOTICE("You scrub \the [target] out.")) + else + to_chat(user, SPAN_NOTICE("You clean \the [target].")) + + reagents.touch_atom(target) + reagents.remove_any(1) + user.update_personal_goal(/datum/goal/clean, 1) + return TRUE //attack_as_weapon -/obj/item/soap/attack(mob/living/target, mob/living/user, var/target_zone) - if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == BP_MOUTH) - user.visible_message("\The [user] washes \the [target]'s mouth out with soap!") - if(reagents) - reagents.trans_to_mob(target, reagents.total_volume / 2, CHEM_INGEST) +/obj/item/soap/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(ishuman(target) && !user?.check_intent(I_FLAG_HARM)) + var/mob/living/human/victim = target + if(user.get_target_zone() == BP_MOUTH && victim.check_has_mouth()) + user.visible_message(SPAN_DANGER("\The [user] washes \the [target]'s mouth out with soap!")) + if(reagents) + reagents.trans_to_mob(target, REAGENT_TOTAL_VOLUME(reagents) / 2, CHEM_INGEST) + else + user.visible_message(SPAN_NOTICE("\The [user] cleans \the [target].")) + if(reagents) + reagents.trans_to(target, REAGENT_TOTAL_VOLUME(reagents) / 8) + target.clean() user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //prevent spam - return - ..() - -/obj/item/soap/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/key)) - if(!key_data) - to_chat(user, "You imprint \the [I] into \the [src].") - var/obj/item/key/K = I + return TRUE + return ..() + +/obj/item/soap/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/key)) + if(key_data) + to_chat(user, SPAN_WARNING("\The [src] already has a key imprint.")) + else + to_chat(user, SPAN_NOTICE("You imprint \the [used_item] into \the [src].")) + var/obj/item/key/K = used_item key_data = K.key_data update_icon() - return - ..() + return TRUE + return ..() /obj/item/soap/on_update_icon() - overlays.Cut() + . = ..() if(key_data) - overlays += image(icon, icon_state = "soap_key_overlay") + add_overlay("soap_key_overlay") else if(decal_name) - overlays += overlay_image(icon, "decal-[decal_name]") \ No newline at end of file + add_overlay("decal-[decal_name]") + +#undef SOAP_MAX_VOLUME +#undef SOAP_CLEANER_ON_WET \ No newline at end of file diff --git a/code/game/objects/items/weapons/special_attacks/backstab.dm b/code/game/objects/items/weapons/special_attacks/backstab.dm deleted file mode 100644 index 40eb0df56f0e..000000000000 --- a/code/game/objects/items/weapons/special_attacks/backstab.dm +++ /dev/null @@ -1,93 +0,0 @@ -/* -Holds the proc for backstabbing. - -usage: - -/obj/item/attack(mob/living/target, mob/user, var/target_zone) - backstab(target, user, 60, BRUTE, DAM_SHARP, target_zone) - ..() -May also be used as: - -/obj/item/attack(mob/living/target, mob/user, var/target_zone) - ..() - if(backstab(target, user, 60, BRUTE, DAM_SHARP, target_zone)) - [insert code here] ---------------- -The proc itself: - -backstab(mob/living/target, mob/user, damage, damage_type, damage_flags, target_zone, location_check ) - -Expected inputs per arg: -target: Mob -user: mob/user -damage: Num. Defaults to 30 if not set. Can be zero, if you just want the backstab check itself. This is the flat damage done to SIMPLE MOBS. Humans recieve organ damage instead. -damtype: Expects a damage type macro. Can accept the damage strings, but it is recommended you use the macro instead. -target_zone: target zone intent. -location_check: bool. allows facestabs if set to false, skipping the check for both mob's locations. Automatically set to false if the target is lying down -AND- lying face down. ---------------- -Proc returns a boolean if successful. -*/ - -/obj/item/proc/backstab(var/mob/living/target, mob/user, var/damage = 30, var/damage_type = BRUTE, var/damage_flags, var/target_zone = BP_CHEST, var/location_check = TRUE) - - //Runtime prevention. - if( !( damage_type in list( BRUTE, BURN, TOX, OXY, CLONE, PAIN ) ) ) //End the proc with a false return if we're not doing a valid damage type. - return FALSE - - if(!iscarbon(target)) //No. You cannot backstab the borg. - return FALSE - - if(damage < 0) //No negative values allowed. - return FALSE - - if( target.lying && ( target.dir in list(NORTH, EAST) ) ) - location_check = FALSE //Skip the check for locations if the enemy is floored. \His back is waiting for you, seductively. It's ready to take your knife. - - //B-stabs can only occur on a mob from behind, in cases where they are both facing the same direction. More notably, a mob lying face-up cannot be backstabbed. - if(location_check) - - if(!( sharp )) - user.visible_message("\The [user] tries to stab deep into \The [target]'s back, but it dinks off, scraping \him instead!", "\The [src] is too dull for a proper backstab!", "You hear a soft dinking noise.") - return FALSE - - if(!( get_turf(user) == get_step(target, turn( target.dir, 180)) ) ) //You aren't behind them. - return FALSE - - if( user.dir != target.dir ) - return FALSE - - if( get_turf(user) == get_turf(target) ) //To prevent people from stabbing people from Neckgrab. Still possible when they're lying face down, but you're fucked anyways. - to_chat(user, "You are too close to [target] to stab them properly!") - return FALSE - - if( target.lying && ( target.dir in list(WEST, SOUTH) ) ) //Failed the above lying check. His back isn't exposed. - to_chat(user, "You can't reach \The [target]'s back, flip them over!") - return FALSE - - if(target_zone in list(BP_L_FOOT, BP_R_FOOT) ) //No feetstabs. - to_chat(user, "How do you expect to get a meaningful backstab on that floppy thing? ") - return FALSE - - if(damage >= 1) //Let's not do a damage check if it doesn't actually do damage. - - //Let's actually do the backstab. - var/mob/living/carbon/human/H - - if(ishuman(target)) - - H = target - var/obj/item/organ/external/stabbed_part = H.get_organ(target_zone) - if( !prob(H.get_blocked_ratio(target_zone, BRUTE, damage_flags, 0, damage) * 100) && !isnull(stabbed_part) && length(stabbed_part.internal_organs) ) - - var/obj/item/organ/internal/damaged_organ = pick(stabbed_part.internal_organs) //This could be improved by checking the size of an internal organ. - - var/organ_damage = damage * 0.20 - damaged_organ.take_internal_damage(organ_damage) - to_chat(user, "You stab [target] in the back of \His [stabbed_part]!") - H.custom_pain("You feel a stabbing pain in the back of your [stabbed_part]!") //Only the stabber and stabbed should know how bad this is. - - else - target.apply_damage(damage, damage_type, target_zone, DAM_SHARP, src) //Backstabbing. Does extra damage to simple mobs only. - to_chat(user, "You stab [target] in the back!") - - return TRUE //Returns a value in case you want to layer additional behavior on this. diff --git a/code/game/objects/items/weapons/staff.dm b/code/game/objects/items/weapons/staff.dm index add76f1875cd..f355815734bd 100644 --- a/code/game/objects/items/weapons/staff.dm +++ b/code/game/objects/items/weapons/staff.dm @@ -1,24 +1,70 @@ /obj/item/staff - name = "wizards staff" - desc = "Apparently a staff used by the wizard." - icon = 'icons/obj/wizard.dmi' - icon_state = "staff" - force = 3.0 - throwforce = 5.0 - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_SMALL - attack_verb = list("bludgeoned", "whacked", "disciplined") - -/obj/item/staff/broom - name = "broom" - desc = "Used for sweeping, and flying into the night while cackling. Black cat not included." - icon = 'icons/obj/wizard.dmi' - icon_state = "broom" - -/obj/item/staff/gentcane - name = "Gentlemans Cane" - desc = "An ebony can with an ivory tip." - icon = 'icons/obj/items/cane.dmi' - icon_state = "cane" - item_state = "stick" \ No newline at end of file + name = "staff" + desc = "A long, heavy length of material, purportedly used by wizards." + icon = 'icons/obj/items/staff.dmi' + icon_state = ICON_STATE_WORLD + + w_class = ITEM_SIZE_HUGE + attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + base_parry_chance = 30 + _base_attack_force = 3 + +/obj/item/staff/get_stance_support_value() + return LIMB_UNUSABLE + +/obj/item/staff/proc/can_make_broom_with(mob/user, obj/item/thing) + . = FALSE + if(istype(thing, /obj/item/stack/material/bundle)) + var/obj/item/stack/material/bristles = thing + if(!bristles.special_crafting_check()) + return FALSE + if(bristles.get_amount() < 5) + to_chat(user, SPAN_WARNING("You need at least 5 [bristles.plural_name] to make a broom.")) + return FALSE + . = bristles.use(5) + return . && user.try_unequip(src, get_turf(user)) + +/obj/item/staff/get_autopsy_descriptors() + . = ..() + . += "long" + . += "narrow" + +/obj/item/staff/attackby(obj/item/used_item, mob/user) + if(!user.check_intent(I_FLAG_HARM)) + var/decl/material/bristles_material = used_item.material + if(istype(bristles_material) && can_make_broom_with(user, used_item)) + var/obj/item/staff/broom/broom = new(get_turf(user), material?.type, bristles_material?.type) + user.put_in_hands(broom) + to_chat(user, SPAN_NOTICE("You secure the [bristles_material.name] to \the [src] to make \a [broom].")) + qdel(src) + return TRUE + return ..() + +/obj/item/staff/crystal + name = "crystal staff" + icon = 'icons/obj/items/staff_crystal.dmi' + +/obj/item/staff/crystal/can_make_broom_with(mob/user, obj/item/thing) + return FALSE + +/obj/item/staff/crystal/Initialize(ml, material_key) + . = ..() + update_icon() + +/obj/item/staff/crystal/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + var/crystal_state = "[overlay.icon_state]-crystal" + if(check_state_in_icon(crystal_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, crystal_state, COLOR_WHITE, RESET_COLOR) + . = ..() + +/obj/item/staff/crystal/on_update_icon() + . = ..() + var/crystal_state = "[icon_state]-crystal" + if(check_state_in_icon(crystal_state, icon)) + add_overlay(overlay_image(icon, crystal_state, COLOR_WHITE, RESET_COLOR)) + +/obj/item/staff/crystal/beacon + icon = 'icons/obj/items/staff_beacon.dmi' diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 7473ebdbb68d..4ac41d06e88e 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -3,156 +3,157 @@ * Backpack */ -/obj/item/storage/backpack +/obj/item/backpack name = "backpack" desc = "You wear this on your back and put items into it." icon = 'icons/obj/items/storage/backpack/backpack.dmi' icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_HUGE slot_flags = SLOT_BACK - max_w_class = ITEM_SIZE_LARGE - max_storage_space = DEFAULT_BACKPACK_STORAGE - open_sound = 'sound/effects/storage/unzip.ogg' + storage = /datum/storage/backpack + material = /decl/material/solid/organic/leather/synth -/obj/item/storage/backpack/equipped() - if(!has_extension(src, /datum/extension/appearance)) - set_extension(src, /datum/extension/appearance/cardborg) - ..() +/obj/item/backpack/get_associated_equipment_slots() + . = ..() + LAZYDISTINCTADD(., slot_back_str) -/obj/item/storage/backpack/attackby(obj/item/W, mob/user) - if (src.use_sound) - playsound(src.loc, src.use_sound, 50, 1, -5) +//Cannot be washed :( +/obj/item/backpack/can_contaminate() + return FALSE + +/obj/item/backpack/attackby(obj/item/used_item, mob/user) + if (storage?.use_sound) + playsound(src.loc, storage.use_sound, 50, 1, -5) return ..() -/obj/item/storage/backpack/equipped(var/mob/user, var/slot) - if (slot == slot_back && src.use_sound) - playsound(src.loc, src.use_sound, 50, 1, -5) - ..(user, slot) +/obj/item/backpack/equipped(var/mob/user, var/slot) + if(!has_extension(src, /datum/extension/appearance)) + set_extension(src, /datum/extension/appearance/cardborg) + if (slot == slot_back_str && storage?.use_sound) + playsound(loc, storage.use_sound, 50, 1, -5) + return ..(user, slot) /* * Backpack Types */ -/obj/item/storage/backpack/holding +/obj/item/backpack/holding name = "bag of holding" desc = "A backpack that opens into a localized pocket of Blue Space." - origin_tech = "{'wormholes':4}" + origin_tech = @'{"wormholes":4}' icon = 'icons/obj/items/storage/backpack/backpack_holding.dmi' - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = 56 + storage = /datum/storage/backpack/holding material = /decl/material/solid/metal/gold matter = list( /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) -/obj/item/storage/backpack/holding/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/storage/backpack/holding) || istype(W, /obj/item/storage/bag/trash/advanced)) - to_chat(user, "The spatial interfaces of the two devices conflict and malfunction.") - qdel(W) - return 1 - return ..() +/obj/item/backpack/holding/singularity_act(S, current_size) + var/dist = max((current_size - 2), 1) + explosion(src.loc,(dist),(dist*2),(dist*4)) + return 1000 - //Please don't clutter the parent storage item with stupid hacks. -/obj/item/storage/backpack/holding/can_be_inserted(obj/item/W, stop_messages = 0) - if(istype(W, /obj/item/storage/backpack/holding)) +/obj/item/backpack/holding/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/backpack/holding) || istype(used_item, /obj/item/bag/trash/advanced)) + to_chat(user, "The spatial interfaces of the two devices conflict and malfunction.") + qdel(used_item) return 1 return ..() -/obj/item/storage/backpack/holding/duffle +/obj/item/backpack/holding/duffle name = "dufflebag of holding" icon = 'icons/obj/items/storage/backpack/dufflebag_holding.dmi' material = /decl/material/solid/metal/gold matter = list( /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) -/obj/item/storage/backpack/santabag +/obj/item/backpack/santabag name = "\improper Santa's gift bag" desc = "Space Santa uses this to deliver toys to all the nice children in space for Christmas! Wow, it's pretty big!" icon = 'icons/obj/items/storage/backpack/giftbag.dmi' w_class = ITEM_SIZE_HUGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = 400 // can store a ton of shit! + storage = /datum/storage/backpack/santa -/obj/item/storage/backpack/cultpack +/obj/item/backpack/cultpack name = "trophy rack" desc = "It's useful for both carrying extra gear and proudly declaring your insanity." icon = 'icons/obj/items/storage/backpack/backpack_cult.dmi' -/obj/item/storage/backpack/clown +/obj/item/backpack/clown name = "Giggles von Honkerton" desc = "It's a backpack made by Honk! Co." icon = 'icons/obj/items/storage/backpack/backpack_clown.dmi' -/obj/item/storage/backpack/medic +/obj/item/backpack/medic name = "medical backpack" desc = "It's a backpack especially designed for use in a sterile environment." icon = 'icons/obj/items/storage/backpack/backpack_med.dmi' -/obj/item/storage/backpack/security +/obj/item/backpack/security name = "security backpack" desc = "It's a very robust backpack." icon = 'icons/obj/items/storage/backpack/backpack_sec.dmi' -/obj/item/storage/backpack/captain +/obj/item/backpack/captain name = "captain's backpack" desc = "It's a special backpack made exclusively for officers." icon = 'icons/obj/items/storage/backpack/backpack_cap.dmi' -/obj/item/storage/backpack/industrial +/obj/item/backpack/industrial name = "industrial backpack" desc = "It's a tough backpack for the daily grind of industrial life." icon = 'icons/obj/items/storage/backpack/backpack_eng.dmi' -/obj/item/storage/backpack/toxins +/obj/item/backpack/toxins name = "science backpack" desc = "It's a stain-resistant light backpack modeled for use in laboratories and other scientific institutions." icon = 'icons/obj/items/storage/backpack/backpack_sci.dmi' -/obj/item/storage/backpack/hydroponics +/obj/item/backpack/hydroponics name = "herbalist's backpack" desc = "It's a green backpack with many pockets to store plants and tools in." icon = 'icons/obj/items/storage/backpack/backpack_hydro.dmi' -/obj/item/storage/backpack/genetics +/obj/item/backpack/genetics name = "geneticist backpack" desc = "It's a backpack fitted with slots for diskettes and other workplace tools." icon = 'icons/obj/items/storage/backpack/backpack_genetics.dmi' -/obj/item/storage/backpack/virology +/obj/item/backpack/virology name = "sterile backpack" desc = "It's a sterile backpack able to withstand different pathogens from entering its fabric." icon = 'icons/obj/items/storage/backpack/backpack_viro.dmi' -/obj/item/storage/backpack/chemistry +/obj/item/backpack/chemistry name = "pharmacist's backpack" desc = "It's an orange backpack which was designed to hold beakers, pill bottles and bottles." icon = 'icons/obj/items/storage/backpack/backpack_chem.dmi' -/obj/item/storage/backpack/rucksack +/obj/item/backpack/rucksack name = "black rucksack" desc = "A sturdy military-grade backpack with low-profile straps. Designed to work well with armor." icon = 'icons/obj/items/storage/backpack/rucksack.dmi' -/obj/item/storage/backpack/rucksack/blue +/obj/item/backpack/rucksack/blue name = "blue rucksack" icon = 'icons/obj/items/storage/backpack/rucksack_blue.dmi' -/obj/item/storage/backpack/rucksack/green +/obj/item/backpack/rucksack/green name = "green rucksack" icon_state = "rucksack_green" icon = 'icons/obj/items/storage/backpack/rucksack_green.dmi' -/obj/item/storage/backpack/rucksack/navy +/obj/item/backpack/rucksack/navy name = "navy rucksack" icon_state = "rucksack_navy" icon = 'icons/obj/items/storage/backpack/rucksack_navy.dmi' -/obj/item/storage/backpack/rucksack/tan +/obj/item/backpack/rucksack/tan name = "tan rucksack" icon_state = "rucksack_tan" icon = 'icons/obj/items/storage/backpack/rucksack_tan.dmi' @@ -161,291 +162,253 @@ * Duffle Types */ -/obj/item/storage/backpack/dufflebag +/obj/item/backpack/dufflebag name = "dufflebag" desc = "A large dufflebag for holding extra things." icon = 'icons/obj/items/storage/backpack/dufflebag.dmi' w_class = ITEM_SIZE_HUGE - max_storage_space = DEFAULT_BACKPACK_STORAGE + 10 + storage = /datum/storage/backpack/duffle -/obj/item/storage/backpack/dufflebag/Initialize() +/obj/item/backpack/dufflebag/Initialize() . = ..() - slowdown_per_slot[slot_back] = 3 - slowdown_per_slot[slot_r_hand] = 1 - slowdown_per_slot[slot_l_hand] = 1 + LAZYSET(slowdown_per_slot, slot_back_str, 3) + LAZYSET(slowdown_per_slot, BP_L_HAND, 1) + LAZYSET(slowdown_per_slot, BP_R_HAND, 1) -/obj/item/storage/backpack/dufflebag/syndie +/obj/item/backpack/dufflebag/syndie name = "black dufflebag" desc = "A large dufflebag for holding extra tactical supplies." icon = 'icons/obj/items/storage/backpack/dufflebag_syndie.dmi' -/obj/item/storage/backpack/dufflebag/syndie/Initialize() +/obj/item/backpack/dufflebag/syndie/Initialize() . = ..() - slowdown_per_slot[slot_back] = 1 + LAZYSET(slowdown_per_slot, slot_back_str, 1) -/obj/item/storage/backpack/dufflebag/syndie/med +/obj/item/backpack/dufflebag/syndie/med name = "medical dufflebag" desc = "A large dufflebag for holding extra tactical medical supplies." icon_state = "duffle_syndiemed" icon = 'icons/obj/items/storage/backpack/dufflebag_synd_med.dmi' -/obj/item/storage/backpack/dufflebag/syndie/ammo +/obj/item/backpack/dufflebag/syndie/ammo name = "ammunition dufflebag" desc = "A large dufflebag for holding extra weapons ammunition and supplies." icon = 'icons/obj/items/storage/backpack/dufflebag_ammo.dmi' -/obj/item/storage/backpack/dufflebag/captain +/obj/item/backpack/dufflebag/captain name = "captain's dufflebag" desc = "A large dufflebag for holding extra captainly goods." icon = 'icons/obj/items/storage/backpack/dufflebag_cap.dmi' -/obj/item/storage/backpack/dufflebag/med +/obj/item/backpack/dufflebag/med name = "medical dufflebag" desc = "A large dufflebag for holding extra medical supplies." icon = 'icons/obj/items/storage/backpack/dufflebag_med.dmi' -/obj/item/storage/backpack/dufflebag/sec +/obj/item/backpack/dufflebag/sec name = "security dufflebag" desc = "A large dufflebag for holding extra security supplies and ammunition." icon = 'icons/obj/items/storage/backpack/dufflebag_sec.dmi' -/obj/item/storage/backpack/dufflebag/eng +/obj/item/backpack/dufflebag/eng name = "industrial dufflebag" desc = "A large dufflebag for holding extra tools and supplies." icon = 'icons/obj/items/storage/backpack/dufflebag_eng.dmi' -/obj/item/storage/backpack/dufflebag/firefighter - startswith = list( - /obj/item/storage/belt/fire_belt/full, +/obj/item/backpack/dufflebag/firefighter/WillContain() + return list( + /obj/item/belt/fire_belt/full, /obj/item/clothing/suit/fire, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/clothing/gloves/fire, - /obj/item/clothing/accessory/fire_overpants, + /obj/item/clothing/pants/fire_overpants, /obj/item/tank/emergency/oxygen/double/red, /obj/item/clothing/head/hardhat/firefighter, - /obj/item/extinguisher + /obj/item/chems/spray/extinguisher ) /* * Satchel Types */ -/obj/item/storage/backpack/satchel +/obj/item/backpack/satchel name = "satchel" desc = "A trendy looking satchel." icon = 'icons/obj/items/storage/backpack/satchel.dmi' -/obj/item/storage/backpack/satchel/grey +/obj/item/backpack/satchel/grey name = "grey satchel" -/obj/item/storage/backpack/satchel/grey/withwallet - startswith = list(/obj/item/storage/wallet/random) +/obj/item/backpack/satchel/grey/withwallet/WillContain() + return /obj/item/wallet/random -/obj/item/storage/backpack/satchel/leather //brown, master type +/obj/item/backpack/satchel/leather //brown, master type name = "brown leather satchel" desc = "A very fancy satchel made of some kind of leather." color = "#3d2711" -/obj/item/storage/backpack/satchel/leather/khaki +/obj/item/backpack/satchel/leather/khaki name = "khaki leather satchel" color = "#baa481" -/obj/item/storage/backpack/satchel/leather/black +/obj/item/backpack/satchel/leather/black name = "black leather satchel" color = "#212121" -/obj/item/storage/backpack/satchel/leather/navy +/obj/item/backpack/satchel/leather/navy name = "navy leather satchel" color = "#1c2133" -/obj/item/storage/backpack/satchel/leather/olive +/obj/item/backpack/satchel/leather/olive name = "olive leather satchel" color = "#544f3d" -/obj/item/storage/backpack/satchel/leather/reddish +/obj/item/backpack/satchel/leather/reddish name = "auburn leather satchel" color = "#512828" -/obj/item/storage/backpack/satchel/pocketbook //black, master type +/obj/item/backpack/satchel/pocketbook //black, master type name = "black pocketbook" desc = "A neat little folding clasp pocketbook with a shoulder sling." icon = 'icons/obj/items/storage/backpack/pocketbook.dmi' - w_class = ITEM_SIZE_HUGE // to avoid recursive backpacks slot_flags = SLOT_BACK - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_LARGEBOX_STORAGE color = "#212121" + storage = /datum/storage/backpack/pocketbook -/obj/item/storage/backpack/satchel/pocketbook/brown +/obj/item/backpack/satchel/pocketbook/brown name = "brown pocketbook" color = "#3d2711" -/obj/item/storage/backpack/satchel/pocketbook/reddish +/obj/item/backpack/satchel/pocketbook/reddish name = "auburn pocketbook" color = "#512828" -/obj/item/storage/backpack/satchel/eng +/obj/item/backpack/satchel/eng name = "industrial satchel" desc = "A tough satchel with extra pockets." icon = 'icons/obj/items/storage/backpack/satchel_eng.dmi' -/obj/item/storage/backpack/satchel/med +/obj/item/backpack/satchel/med name = "medical satchel" desc = "A sterile satchel used in medical departments." icon = 'icons/obj/items/storage/backpack/satchel_med.dmi' -/obj/item/storage/backpack/satchel/vir +/obj/item/backpack/satchel/vir name = "virologist satchel" desc = "A sterile satchel with virologist colours." icon = 'icons/obj/items/storage/backpack/satchel_viro.dmi' -/obj/item/storage/backpack/satchel/chem +/obj/item/backpack/satchel/chem name = "pharmacist satchel" desc = "A sterile satchel with pharmacist colours." icon = 'icons/obj/items/storage/backpack/satchel_chem.dmi' -/obj/item/storage/backpack/satchel/gen +/obj/item/backpack/satchel/gen name = "geneticist satchel" desc = "A sterile satchel with geneticist colours." icon = 'icons/obj/items/storage/backpack/satchel_genetics.dmi' -/obj/item/storage/backpack/satchel/sec +/obj/item/backpack/satchel/sec name = "security satchel" desc = "A robust satchel for security related needs." icon = 'icons/obj/items/storage/backpack/satchel_sec.dmi' -/obj/item/storage/backpack/satchel/hyd +/obj/item/backpack/satchel/hyd name = "hydroponics satchel" desc = "A green satchel for plant related work." icon = 'icons/obj/items/storage/backpack/satchel_hydro.dmi' -/obj/item/storage/backpack/satchel/cap +/obj/item/backpack/satchel/cap name = "captain's satchel" desc = "An exclusive satchel for officers." icon = 'icons/obj/items/storage/backpack/satchel_cap.dmi' //Smuggler's satchel -/obj/item/storage/backpack/satchel/flat +/obj/item/backpack/satchel/flat name = "smuggler's satchel" desc = "A very slim satchel that can easily fit into tight spaces." - level = 1 + level = LEVEL_BELOW_PLATING w_class = ITEM_SIZE_NORMAL //Can fit in backpacks itself. - storage_slots = 5 - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = 15 - cant_hold = list(/obj/item/storage/backpack/satchel/flat) //muh recursive backpacks - startswith = list( + storage = /datum/storage/backpack/smuggler + +/obj/item/backpack/satchel/flat/WillContain() + return list( /obj/item/stack/tile/floor, /obj/item/crowbar - ) + ) -/obj/item/storage/backpack/satchel/flat/MouseDrop(var/obj/over_object) +/obj/item/backpack/satchel/flat/handle_mouse_drop(atom/over, mob/user, params) var/turf/T = get_turf(src) if(hides_under_flooring() && isturf(T) && !T.is_plating()) - return - ..() + return TRUE + . = ..() -/obj/item/storage/backpack/satchel/flat/hide(var/i) +/obj/item/backpack/satchel/flat/hide(var/i) set_invisibility(i ? 101 : 0) anchored = i ? TRUE : FALSE alpha = i ? 128 : initial(alpha) -/obj/item/storage/backpack/satchel/flat/attackby(obj/item/W, mob/user) +/obj/item/backpack/satchel/flat/attackby(obj/item/used_item, mob/user) var/turf/T = get_turf(src) if(hides_under_flooring() && isturf(T) && !T.is_plating()) to_chat(user, "You must remove the plating first.") return 1 return ..() -//ERT backpacks. -/obj/item/storage/backpack/ert - name = "emergency response team backpack" - desc = "A spacious backpack with lots of pockets, used by members of the Emergency Response Team." - icon = 'icons/obj/items/storage/backpack/backpack_ert.dmi' - var/marking_state - var/marking_colour - -/obj/item/storage/backpack/ert/on_update_icon() - cut_overlays() - if(marking_state) - var/image/I = image(icon, marking_state) - I.color = marking_colour - I.appearance_flags |= RESET_COLOR - add_overlay(I) - -/obj/item/storage/backpack/ert/get_mob_overlay(mob/user_mob, slot, bodypart) - . = ..() - if(slot == slot_back_str && marking_state) - var/image/ret = . - var/image/I = image(icon, "[ret.icon_state]-[marking_state]") - I.color = marking_colour - I.appearance_flags |= RESET_COLOR - ret.add_overlay(I) - -/obj/item/storage/backpack/ert/commander - name = "emergency response team commander backpack" - desc = "A spacious backpack with lots of pockets, worn by the commander of an Emergency Response Team." - marking_colour = COLOR_BLUE_GRAY - marking_state = "com" - -/obj/item/storage/backpack/ert/security - name = "emergency response team security backpack" - desc = "A spacious backpack with lots of pockets, worn by security members of an Emergency Response Team." - marking_colour = COLOR_NT_RED - marking_state = "sec" - -/obj/item/storage/backpack/ert/engineer - name = "emergency response team engineer backpack" - desc = "A spacious backpack with lots of pockets, worn by engineering members of an Emergency Response Team." - marking_colour = COLOR_GOLD - marking_state = "eng" - -/obj/item/storage/backpack/ert/medical - name = "emergency response team medical backpack" - desc = "A spacious backpack with lots of pockets, worn by medical members of an Emergency Response Team." - marking_colour = COLOR_OFF_WHITE - marking_state = "med" - /* * Messenger Bags */ -/obj/item/storage/backpack/messenger +/obj/item/backpack/messenger name = "messenger bag" desc = "A sturdy backpack worn over one shoulder." icon = 'icons/obj/items/storage/backpack/messenger.dmi' -/obj/item/storage/backpack/messenger/chem +/obj/item/backpack/messenger/chem name = "pharmacy messenger bag" - desc = "A serile backpack worn over one shoulder. This one is in Chemistry colors." + desc = "A sterile backpack worn over one shoulder. This one is in Chemistry colors." icon = 'icons/obj/items/storage/backpack/messenger_chem.dmi' -/obj/item/storage/backpack/messenger/med +/obj/item/backpack/messenger/med name = "medical messenger bag" desc = "A sterile backpack worn over one shoulder used in medical departments." icon = 'icons/obj/items/storage/backpack/messenger_med.dmi' -/obj/item/storage/backpack/messenger/viro +/obj/item/backpack/messenger/viro name = "virology messenger bag" desc = "A sterile backpack worn over one shoulder. This one is in Virology colors." icon = 'icons/obj/items/storage/backpack/messenger_viro.dmi' -/obj/item/storage/backpack/messenger/com +/obj/item/backpack/messenger/com name = "captain's messenger bag" desc = "A special backpack worn over one shoulder. This one is made specifically for officers." icon = 'icons/obj/items/storage/backpack/messenger_cap.dmi' -/obj/item/storage/backpack/messenger/engi +/obj/item/backpack/messenger/engi name = "engineering messenger bag" desc = "A strong backpack worn over one shoulder. This one is designed for industrial work." icon = 'icons/obj/items/storage/backpack/messenger_eng.dmi' -/obj/item/storage/backpack/messenger/hyd +/obj/item/backpack/messenger/hyd name = "hydroponics messenger bag" desc = "A backpack worn over one shoulder. This one is designed for plant-related work." icon = 'icons/obj/items/storage/backpack/messenger_hydro.dmi' -/obj/item/storage/backpack/messenger/sec +/obj/item/backpack/messenger/sec name = "security messenger bag" desc = "A tactical backpack worn over one shoulder. This one is in Security colors." icon = 'icons/obj/items/storage/backpack/messenger_sec.dmi' + +// Crafted backpacks. +/obj/item/backpack/crafted + name = "haversack" + desc = "A rather rough handmade haversack." + icon = 'icons/obj/items/storage/backpack/backpack_haversack.dmi' + material = /decl/material/solid/organic/leather + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + +/obj/item/backpack/crafted/backpack + name = "backpack" + name_prefix = "handmade" + desc = "A rather rough handmade backpack." + icon = 'icons/obj/items/storage/backpack/backpack_crafted.dmi' diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm index 7753ad480c27..6e4dde21a2b7 100644 --- a/code/game/objects/items/weapons/storage/bags.dm +++ b/code/game/objects/items/weapons/storage/bags.dm @@ -1,82 +1,67 @@ /* Represents flexible bags that expand based on the size of their contents. */ -/obj/item/storage/bag - allow_quick_gather = 1 - allow_quick_empty = 1 - use_to_pickup = 1 - slot_flags = SLOT_BELT +/obj/item/bag + storage = /datum/storage/bag + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + obj_flags = OBJ_FLAG_HOLLOW -/obj/item/storage/bag/handle_item_insertion(obj/item/W, prevent_warning = 0) - . = ..() - if(.) update_w_class() - -/obj/item/storage/bag/remove_from_storage(obj/item/W, atom/new_location) - . = ..() - if(.) update_w_class() - -/obj/item/storage/bag/can_be_inserted(obj/item/W, mob/user, stop_messages = 0) - var/mob/living/carbon/human/H = ishuman(user) ? user : null // if we're human, then we need to check if bag in a pocket - if(istype(src.loc, /obj/item/storage) || H?.is_in_pocket(src)) - if(!stop_messages) - to_chat(user, SPAN_NOTICE("Take \the [src] out of [istype(src.loc, /obj) ? "\the [src.loc]" : "the pocket"] first.")) - return 0 //causes problems if the bag expands and becomes larger than src.loc can hold, so disallow it - . = ..() - -/obj/item/storage/bag/proc/update_w_class() +/obj/item/bag/proc/update_w_class() w_class = initial(w_class) for(var/obj/item/I in contents) w_class = max(w_class, I.w_class) + if(storage) + var/cur_storage_space = storage.storage_space_used() + while(BASE_STORAGE_CAPACITY(w_class) < cur_storage_space) + w_class++ - var/cur_storage_space = storage_space_used() - while(BASE_STORAGE_CAPACITY(w_class) < cur_storage_space) - w_class++ - -/obj/item/storage/bag/get_storage_cost() - var/used_ratio = storage_space_used()/max_storage_space - return max(BASE_STORAGE_COST(w_class), round(used_ratio*BASE_STORAGE_COST(max_w_class), 1)) +/obj/item/bag/get_storage_cost() + if(storage) + var/used_ratio = storage.storage_space_used()/storage.max_storage_space + return max(BASE_STORAGE_COST(w_class), round(used_ratio * BASE_STORAGE_COST(storage.max_w_class), 1)) + return BASE_STORAGE_COST(initial(w_class)) // ----------------------------- // Trash bag // ----------------------------- -/obj/item/storage/bag/trash +/obj/item/bag/trash name = "trash bag" desc = "It's the heavy-duty black polymer kind. Time to take out the trash!" icon = 'icons/obj/items/storage/trashbag.dmi' icon_state = "trashbag" item_state = "trashbag" - + storage = /datum/storage/bag/trash w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_HUGE //can fit a backpack inside a trash bag, seems right - max_storage_space = DEFAULT_BACKPACK_STORAGE - can_hold = list() // any -/obj/item/storage/bag/trash/update_w_class() +/obj/item/bag/trash/update_w_class() ..() update_icon() -/obj/item/storage/bag/trash/on_update_icon() +/obj/item/bag/trash/on_update_icon() + . = ..() switch(w_class) if(2) icon_state = "[initial(icon_state)]" if(3) icon_state = "[initial(icon_state)]1" if(4) icon_state = "[initial(icon_state)]2" if(5 to INFINITY) icon_state = "[initial(icon_state)]3" -/obj/item/storage/bag/trash/advanced +/obj/item/bag/trash/advanced name = "trash bag of holding" - max_storage_space = 56 desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage." icon_state = "bluetrashbag" - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic matter = list( /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"exoticmatter":5,"materials":6}' + storage = /datum/storage/bag/trash/advanced -/obj/item/storage/bag/trash/advanced/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/storage/backpack/holding) || istype(W, /obj/item/storage/bag/trash/advanced)) +/obj/item/bag/trash/advanced/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/backpack/holding) || istype(used_item, /obj/item/bag/trash/advanced)) to_chat(user, "The spatial interfaces of the two devices conflict and malfunction.") - qdel(W) + qdel(used_item) return 1 return ..() @@ -84,28 +69,73 @@ // Plastic Bag // ----------------------------- -/obj/item/storage/bag/plasticbag - name = "plastic bag" +/obj/item/bag/flimsy + name = "bag" desc = "It's a very flimsy, very noisy alternative to a bag." icon = 'icons/obj/items/storage/plasticbag.dmi' icon_state = "plasticbag" item_state = "plasticbag" + storage = /datum/storage/bag/plastic + w_class = ITEM_SIZE_SMALL - w_class = ITEM_SIZE_TINY - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_BOX_STORAGE - can_hold = list() // any + material = /decl/material/solid/organic/plastic + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC // ----------------------------- // Cash Bag // ----------------------------- -/obj/item/storage/bag/cash +/obj/item/bag/cash name = "cash bag" icon = 'icons/obj/items/storage/cashbag.dmi' icon_state = "cashbag" desc = "A bag for carrying lots of cash. It's got a big dollar sign printed on the front." - max_storage_space = 100 - max_w_class = ITEM_SIZE_HUGE w_class = ITEM_SIZE_SMALL - can_hold = list(/obj/item/coin,/obj/item/cash) + storage = /datum/storage/bag/cash + material = /decl/material/solid/organic/leather/synth + +/obj/item/bag/cash/filled/Initialize() + . = ..() + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + new /obj/item/cash/c1000(src) + if(length(contents) && storage) + storage.make_exact_fit() + +/obj/item/bag/sack + name = "sack" + desc = "A simple sack for carrying goods." + icon = 'icons/obj/items/storage/sack.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY | SLOT_BACK + storage = /datum/storage/bag/sack + material = /decl/material/solid/organic/leather + color = /decl/material/solid/organic/leather::color + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/bag/sack/update_w_class() + ..() + update_icon() + +/obj/item/bag/sack/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + switch(w_class) + if(3) + icon_state = "[icon_state]1" + if(4) + icon_state = "[icon_state]2" + if(5 to INFINITY) + icon_state = "[icon_state]3" diff --git a/code/game/objects/items/weapons/storage/basket.dm b/code/game/objects/items/weapons/storage/basket.dm new file mode 100644 index 000000000000..b16df16f5755 --- /dev/null +++ b/code/game/objects/items/weapons/storage/basket.dm @@ -0,0 +1,25 @@ +/obj/item/basket + name_prefix = "woven" + name = "handbasket" + desc = "A simple woven basket. Very rustic." + icon = 'icons/obj/items/storage/baskets/basket_round.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_HUGE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + storage = /datum/storage/basket + material = /decl/material/solid/organic/plantmatter/grass/dry + +/obj/item/basket/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(storage?.opened) + icon_state = "[icon_state]-open" + +/obj/item/basket/large + name_prefix = "large woven" + name = "basket" + slot_flags = SLOT_BACK + icon = 'icons/obj/items/storage/baskets/basket_large.dmi' + w_class = ITEM_SIZE_GARGANTUAN + storage = /datum/storage/basket/large + slowdown_general = 1 // Large and unwieldy diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 69e3f531c68f..d4b056a508c0 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -1,501 +1,236 @@ #define BELT_OVERLAY_ITEMS 1 #define BELT_OVERLAY_HOLSTER 2 -/obj/item/storage/belt +/obj/item/belt name = "belt" desc = "Can hold various things." - icon = 'icons/obj/clothing/obj_belt.dmi' - icon_state = "utilitybelt" - item_state = "utility" - storage_slots = 7 + icon = 'icons/clothing/belt/utility.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/belt item_flags = ITEM_FLAG_IS_BELT - max_w_class = ITEM_SIZE_NORMAL - slot_flags = SLOT_BELT - var/overlay_flags + slot_flags = SLOT_LOWER_BODY attack_verb = list("whipped", "lashed", "disciplined") + material = /decl/material/solid/organic/leather/synth + var/overlay_flags -/obj/item/storage/belt/verb/toggle_layer() +/obj/item/belt/verb/toggle_layer() set name = "Switch Belt Layer" set category = "Object" use_alt_layer = !use_alt_layer update_icon() -/obj/item/storage/belt/on_update_icon() - if (ismob(src.loc)) - var/mob/M = src.loc - M.update_inv_belt() - - overlays.Cut() +/obj/item/belt/on_update_icon() + . = ..() if(overlay_flags & BELT_OVERLAY_ITEMS) - for(var/obj/item/I in contents) - if(I.use_single_icon) - overlays += I.get_on_belt_overlay() + var/list/cur_overlays + for(var/obj/item/thing in contents) + if(thing.use_single_icon) + LAZYADD(cur_overlays, thing.get_on_belt_overlay()) else - overlays += image('icons/obj/clothing/obj_belt_overlays.dmi', "[I.icon_state]") + LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', thing.icon_state)) + + if(LAZYLEN(cur_overlays)) + add_overlay(cur_overlays) + update_clothing_icon() -/obj/item/storage/belt/get_mob_overlay(mob/user_mob, slot) +/obj/item/belt/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) var/image/ret = ..() - if(slot == slot_belt_str && contents.len) - var/list/ret_overlays = list() - for(var/obj/item/I in contents) - if(I.use_single_icon) - ret_overlays += I.get_mob_overlay(user_mob, slot) - else - var/use_state = (I.item_state ? I.item_state : I.icon_state) - if(ishuman(user_mob)) - var/mob/living/carbon/human/H = user_mob - ret_overlays += H.species.get_offset_overlay_image(FALSE, 'icons/mob/onmob/onmob_belt.dmi', use_state, I.color, slot) - else - ret_overlays += overlay_image('icons/mob/onmob/onmob_belt.dmi', use_state, I.color, RESET_COLOR) - ret.overlays += ret_overlays + if(ret && slot == slot_belt_str && length(contents)) + for(var/obj/item/thing in contents) + var/image/new_overlay = thing.get_mob_overlay(user_mob, slot, bodypart, use_fallback_if_icon_missing, TRUE) + if(new_overlay) + ret.overlays += new_overlay return ret -/obj/item/storage/belt/holster +/obj/item/belt/holster name = "holster belt" - icon_state = "holsterbelt" - item_state = "holster" + icon = 'icons/clothing/belt/holster.dmi' desc = "Can holster various things." - storage_slots = 2 + storage = /datum/storage/holster overlay_flags = BELT_OVERLAY_ITEMS|BELT_OVERLAY_HOLSTER var/list/can_holster //List of objects which this item can store in the designated holster slot(if unset, it will default to any holsterable items) var/sound_in = 'sound/effects/holster/holsterin.ogg' var/sound_out = 'sound/effects/holster/holsterout.ogg' - can_hold = list( - /obj/item/baton, - /obj/item/telebaton - ) -/obj/item/storage/belt/holster/Initialize() +/obj/item/belt/holster/Initialize() . = ..() - set_extension(src, /datum/extension/holster, src, sound_in, sound_out, can_holster) - -/obj/item/storage/belt/holster/attackby(obj/item/W, mob/user) - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - if(H.holster(W, user)) - return - else - . = ..(W, user) - -/obj/item/storage/belt/holster/attack_hand(mob/user) - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - if(H.unholster(user)) - return - else - . = ..(user) - -/obj/item/storage/belt/holster/examine(mob/user) + set_extension(src, /datum/extension/holster, storage, sound_in, sound_out, can_holster) + +/obj/item/belt/holster/attackby(obj/item/used_item, mob/user) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster?.holster(used_item, user)) + return TRUE + return ..(used_item, user) + +/obj/item/belt/holster/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + if(holster?.unholster(user)) + return TRUE + return ..() + +/obj/item/belt/holster/examined_by(mob/user, distance, infix, suffix) . = ..() - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) - H.examine_holster(user) + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) + holster.examine_holster(user) -/obj/item/storage/belt/holster/on_update_icon() - if (ismob(src.loc)) - var/mob/M = src.loc - M.update_inv_belt() - - overlays.Cut() - var/datum/extension/holster/H = get_extension(src, /datum/extension/holster) +/obj/item/belt/holster/on_update_icon() + . = ..() + var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) if(overlay_flags) - for(var/obj/item/I in contents) - if(I == H.holstered) + var/list/cur_overlays + for(var/obj/item/thing in contents) + if(thing == holster.holstered) if(overlay_flags & BELT_OVERLAY_HOLSTER) - overlays += image('icons/obj/clothing/obj_belt_overlays.dmi', "[I.icon_state]") + LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', thing.icon_state)) else if(overlay_flags & BELT_OVERLAY_ITEMS) - overlays += image('icons/obj/clothing/obj_belt_overlays.dmi', "[I.icon_state]") + LAZYADD(cur_overlays, overlay_image('icons/obj/clothing/obj_belt_overlays.dmi', thing.icon_state)) + + if(LAZYLEN(cur_overlays)) + add_overlay(cur_overlays) -/obj/item/storage/belt/utility + update_clothing_icon() + +/obj/item/belt/utility name = "tool belt" desc = "A belt of durable leather, festooned with hooks, slots, and pouches." - icon_state = "utilitybelt" - item_state = "utility" + icon = 'icons/clothing/belt/utility.dmi' overlay_flags = BELT_OVERLAY_ITEMS - can_hold = list( - ///obj/item/combitool, - /obj/item/crowbar, + storage = /datum/storage/belt/utility + material = /decl/material/solid/organic/leather + +/obj/item/belt/utility/full/WillContain() + return list( /obj/item/screwdriver, + /obj/item/wrench, /obj/item/weldingtool, + /obj/item/crowbar, /obj/item/wirecutters, + /obj/item/stack/cable_coil/random, + ) + +/obj/item/belt/utility/atmostech/WillContain() + return list( + /obj/item/screwdriver, /obj/item/wrench, - /obj/item/multitool, - /obj/item/flashlight, - /obj/item/stack/cable_coil, + /obj/item/weldingtool, + /obj/item/crowbar, + /obj/item/wirecutters, /obj/item/t_scanner, - /obj/item/scanner/gas, - /obj/item/taperoll/engineering, - /obj/item/inducer/, - /obj/item/robotanalyzer, - /obj/item/minihoe, - /obj/item/hatchet, - /obj/item/scanner/plant, - /obj/item/taperoll, - /obj/item/extinguisher/mini, - /obj/item/marshalling_wand, - /obj/item/hand_labeler, - /obj/item/clothing/gloves - ) - - -/obj/item/storage/belt/utility/full/Initialize() - . = ..() - new /obj/item/screwdriver(src) - new /obj/item/wrench(src) - new /obj/item/weldingtool(src) - new /obj/item/crowbar(src) - new /obj/item/wirecutters(src) - new /obj/item/stack/cable_coil/random(src, 30) - update_icon() - + ) -/obj/item/storage/belt/utility/atmostech/Initialize() - . = ..() - new /obj/item/screwdriver(src) - new /obj/item/wrench(src) - new /obj/item/weldingtool(src) - new /obj/item/crowbar(src) - new /obj/item/wirecutters(src) - new /obj/item/t_scanner(src) - update_icon() - - - -/obj/item/storage/belt/medical +/obj/item/belt/medical name = "medical belt" desc = "Can hold various medical equipment." - icon_state = "medicalbelt" - item_state = "medical" - can_hold = list( - /obj/item/scanner/health, - /obj/item/chems/dropper, - /obj/item/chems/glass/beaker, - /obj/item/chems/glass/bottle, - /obj/item/chems/pill, - /obj/item/chems/syringe, - /obj/item/flame/lighter/zippo, - /obj/item/storage/fancy/cigarettes, - /obj/item/storage/pill_bottle, - /obj/item/stack/medical, - /obj/item/flashlight/pen, - /obj/item/clothing/mask/surgical, - /obj/item/clothing/head/surgery, - /obj/item/clothing/gloves/latex, - /obj/item/chems/hypospray, - /obj/item/clothing/glasses/hud/health, - /obj/item/crowbar, - /obj/item/flashlight, - /obj/item/taperoll, - /obj/item/extinguisher/mini, - /obj/item/storage/med_pouch, - /obj/item/bodybag, - /obj/item/clothing/gloves - ) - -/obj/item/storage/belt/medical/emt + icon = 'icons/clothing/belt/medical.dmi' + storage = /datum/storage/belt/medical + +/obj/item/belt/medical/emt name = "EMT belt" desc = "A sturdy black webbing belt with attached pouches." - icon_state = "emsbelt" - item_state = "emsbelt" + icon = 'icons/clothing/belt/emt_belt.dmi' -/obj/item/storage/belt/holster/security +/obj/item/belt/holster/security name = "security holster belt" desc = "Can hold security gear like handcuffs and flashes. This one has a convenient holster." - icon_state = "securitybelt" - item_state = "security" - storage_slots = 8 + icon = 'icons/clothing/belt/security_holster.dmi' overlay_flags = BELT_OVERLAY_ITEMS|BELT_OVERLAY_HOLSTER - can_hold = list( - /obj/item/crowbar, - /obj/item/grenade, - /obj/item/chems/spray/pepper, - /obj/item/handcuffs, - /obj/item/flash, - /obj/item/clothing/glasses, - /obj/item/ammo_casing/shotgun, - /obj/item/ammo_magazine, - /obj/item/chems/food/snacks/donut/, - /obj/item/baton, - /obj/item/telebaton, - /obj/item/flame/lighter, - /obj/item/flashlight, - /obj/item/modular_computer/pda, - /obj/item/radio/headset, - /obj/item/hailer, - /obj/item/megaphone, - /obj/item/energy_blade, - /obj/item/baton, - /obj/item/taperoll, - /obj/item/holowarrant, - /obj/item/magnetic_ammo, - /obj/item/binoculars, - /obj/item/clothing/gloves - ) - -/obj/item/storage/belt/security + storage = /datum/storage/holster/security + +/obj/item/belt/security name = "security belt" desc = "Can hold security gear like handcuffs and flashes." - icon_state = "basicsecuritybelt" - item_state = "basicsecurity" + icon = 'icons/clothing/belt/security.dmi' overlay_flags = BELT_OVERLAY_ITEMS - can_hold = list( - /obj/item/crowbar, - /obj/item/grenade, - /obj/item/chems/spray/pepper, - /obj/item/handcuffs, - /obj/item/flash, - /obj/item/clothing/glasses, - /obj/item/ammo_casing/shotgun, - /obj/item/ammo_magazine, - /obj/item/chems/food/snacks/donut/, - /obj/item/baton, - /obj/item/telebaton, - /obj/item/flame/lighter, - /obj/item/flashlight, - /obj/item/modular_computer/pda, - /obj/item/radio/headset, - /obj/item/hailer, - /obj/item/megaphone, - /obj/item/energy_blade, - /obj/item/baton, - /obj/item/taperoll, - /obj/item/holowarrant, - /obj/item/magnetic_ammo, - /obj/item/binoculars, - /obj/item/clothing/gloves - ) - -/obj/item/storage/belt/general + storage = /datum/storage/belt/security + +/obj/item/belt/general name = "equipment belt" desc = "Can hold general equipment such as tablets, folders, and other office supplies." - icon_state = "gearbelt" - item_state = "gear" + icon = 'icons/clothing/belt/gearbelt.dmi' overlay_flags = BELT_OVERLAY_ITEMS - can_hold = list( - /obj/item/flash, - /obj/item/telebaton, - /obj/item/taperecorder, - /obj/item/folder, - /obj/item/paper, - /obj/item/clipboard, - /obj/item/modular_computer/tablet, - /obj/item/flashlight, - /obj/item/modular_computer/pda, - /obj/item/radio/headset, - /obj/item/megaphone, - /obj/item/taperoll, - /obj/item/holowarrant, - /obj/item/radio, - /obj/item/tape, - /obj/item/pen, - /obj/item/stamp, - /obj/item/stack/package_wrap, - /obj/item/binoculars, - /obj/item/marshalling_wand, - /obj/item/camera, - /obj/item/hand_labeler, - /obj/item/destTagger, - /obj/item/clothing/glasses, - /obj/item/clothing/head/soft, - /obj/item/hand_labeler, - /obj/item/clothing/gloves, - /obj/item/crowbar - ) - -/obj/item/storage/belt/janitor + storage = /datum/storage/belt/general + +/obj/item/belt/janitor name = "janibelt" desc = "A belt used to hold most janitorial supplies." - icon_state = "janibelt" - item_state = "janibelt" - can_hold = list( - /obj/item/grenade/chem_grenade, - /obj/item/lightreplacer, - /obj/item/flashlight, - /obj/item/chems/spray/cleaner, - /obj/item/soap, - /obj/item/holosign_creator, - /obj/item/clothing/gloves, - /obj/item/assembly/mousetrap, - /obj/item/crowbar, - /obj/item/clothing/mask/plunger - ) + icon = 'icons/clothing/belt/janitor.dmi' + storage = /datum/storage/belt/janitor -/obj/item/storage/belt/holster/general +/obj/item/belt/holster/general name = "holster belt" desc = "Can hold general equipment such as tablets, folders, and other office supplies. Comes with a holster." - icon_state = "commandbelt" - item_state = "command" - storage_slots = 7 + icon = 'icons/clothing/belt/command.dmi' overlay_flags = BELT_OVERLAY_ITEMS|BELT_OVERLAY_HOLSTER - can_hold = list( - /obj/item/flash, - /obj/item/telebaton, - /obj/item/taperecorder, - /obj/item/folder, - /obj/item/paper, - /obj/item/clipboard, - /obj/item/modular_computer/tablet, - /obj/item/flash, - /obj/item/flashlight, - /obj/item/modular_computer/pda, - /obj/item/radio/headset, - /obj/item/megaphone, - /obj/item/taperoll, - /obj/item/holowarrant, - /obj/item/radio, - /obj/item/tape, - /obj/item/pen, - /obj/item/stamp, - /obj/item/stack/package_wrap, - /obj/item/binoculars, - /obj/item/marshalling_wand, - /obj/item/camera, - /obj/item/destTagger, - /obj/item/clothing/glasses, - /obj/item/clothing/head/soft, - /obj/item/hand_labeler, - /obj/item/clothing/gloves, - /obj/item/crowbar - ) - -/obj/item/storage/belt/holster/forensic + storage = /datum/storage/holster/general + +/obj/item/belt/holster/forensic name = "forensic belt" desc = "Can hold forensic gear like fingerprint powder and luminol." - icon_state = "forensicbelt" - item_state = "forensic" - storage_slots = 8 + icon = 'icons/clothing/belt/forensic.dmi' overlay_flags = BELT_OVERLAY_HOLSTER - can_hold = list( - /obj/item/chems/spray/luminol, - /obj/item/uv_light, - /obj/item/chems/syringe, - /obj/item/forensics/sample/swab, - /obj/item/forensics/sample/print, - /obj/item/forensics/sample/fibers, - /obj/item/taperecorder, - /obj/item/tape, - /obj/item/clothing/gloves/latex, - /obj/item/clothing/gloves/forensic, - /obj/item/folder, - /obj/item/paper, - /obj/item/forensics/sample_kit, - /obj/item/camera, - /obj/item/taperecorder, - /obj/item/tape - ) - -/obj/item/storage/belt/holster/machete + storage = /datum/storage/holster/forensic + +/obj/item/belt/holster/machete name = "machete belt" desc = "Can hold general surveying equipment used for exploration, as well as your very own machete." - icon_state = "machetebelt" - item_state = "machetebelt" - storage_slots = 8 + icon = 'icons/clothing/belt/machete.dmi' overlay_flags = BELT_OVERLAY_HOLSTER - can_hold = list( - /obj/item/binoculars, - /obj/item/camera, - /obj/item/stack/flag, - /obj/item/geiger, - /obj/item/flashlight, - /obj/item/radio, - /obj/item/gps, - /obj/item/scanner/mining, - /obj/item/scanner/xenobio, - /obj/item/scanner/plant, - /obj/item/folder, - /obj/item/paper, - /obj/item/pen, - /obj/item/spaceflare, - /obj/item/radio/beacon, - /obj/item/pinpointer/radio, - /obj/item/taperecorder, - /obj/item/tape, - /obj/item/scanner/gas - ) - can_holster = list(/obj/item/hatchet/machete) + storage = /datum/storage/holster/machete + can_holster = list(/obj/item/tool/machete) sound_in = 'sound/effects/holster/sheathin.ogg' sound_out = 'sound/effects/holster/sheathout.ogg' -/obj/item/storage/belt/soulstone - name = "soul stone belt" - desc = "Designed for ease of access to the shards during a fight, as to not let a single enemy spirit slip away." - icon_state = "soulstonebelt" - item_state = "soulstonebelt" - can_hold = list( - /obj/item/soulstone - ) - -/obj/item/storage/belt/soulstone/full/Initialize() - . = ..() - new /obj/item/soulstone(src) - new /obj/item/soulstone(src) - new /obj/item/soulstone(src) - new /obj/item/soulstone(src) - new /obj/item/soulstone(src) - new /obj/item/soulstone(src) - new /obj/item/soulstone(src) - - -/obj/item/storage/belt/champion +/obj/item/belt/champion name = "championship belt" desc = "Proves to the world that you are the strongest!" - icon_state = "championbelt" - item_state = "champion" - storage_slots = null - max_storage_space = ITEM_SIZE_SMALL - can_hold = list( - /obj/item/clothing/mask/luchador - ) - -/obj/item/storage/belt/holster/security/tactical + icon = 'icons/clothing/belt/champion.dmi' + storage = /datum/storage/belt/champion + +/obj/item/belt/holster/security/tactical name = "combat belt" desc = "Can hold security gear like handcuffs and flashes, with more pouches for more storage." - icon_state = "swatbelt" - item_state = "swatbelt" - storage_slots = 10 + icon = 'icons/clothing/belt/swatbelt.dmi' + storage = /datum/storage/holster/security/tactical -/obj/item/storage/belt/holster/security/tactical/Initialize() +/obj/item/belt/holster/security/tactical/Initialize(ml, material_key) .=..() - slowdown_per_slot[slot_belt] = 1 + LAZYSET(slowdown_per_slot, slot_belt_str, 1) -/obj/item/storage/belt/waistpack +/obj/item/belt/waistpack name = "waist pack" desc = "A small bag designed to be worn on the waist. May make your butt look big." - icon_state = "fannypack_white" - item_state = "fannypack_white" - storage_slots = null - max_w_class = ITEM_SIZE_SMALL - max_storage_space = ITEM_SIZE_SMALL * 4 - slot_flags = SLOT_BELT | SLOT_BACK - -/obj/item/storage/belt/waistpack/big + icon = 'icons/clothing/belt/fannypack.dmi' + slot_flags = SLOT_LOWER_BODY | SLOT_BACK + material = /decl/material/solid/organic/cloth + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + storage = /datum/storage/belt/waistpack + +/obj/item/belt/waistpack/big name = "large waist pack" desc = "A bag designed to be worn on the waist. Definitely makes your butt look big." - icon_state = "fannypack_big_white" - item_state = "fannypack_big_white" + icon = 'icons/clothing/belt/fannypack_big.dmi' w_class = ITEM_SIZE_LARGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = ITEM_SIZE_NORMAL * 4 + storage = /datum/storage/belt/waistpack/big -/obj/item/storage/belt/waistpack/big/Initialize() +/obj/item/belt/waistpack/big/Initialize(ml, material_key) .=..() - slowdown_per_slot[slot_belt] = 1 + LAZYSET(slowdown_per_slot, slot_belt_str, 1) -/obj/item/storage/belt/fire_belt +/obj/item/belt/fire_belt name = "firefighting equipment belt" desc = "A belt specially designed for firefighting." - icon_state = "firebelt" - item_state = "gear" - storage_slots = 5 + icon = 'icons/clothing/belt/firefighter.dmi' overlay_flags = BELT_OVERLAY_ITEMS - can_hold = list( - /obj/item/grenade/chem_grenade/water, - /obj/item/extinguisher/mini, - /obj/item/inflatable/door - ) - + material = /decl/material/solid/fiberglass //need something that doesn't burn + storage = /datum/storage/belt/firefighter -/obj/item/storage/belt/fire_belt/full - startswith = list( +/obj/item/belt/fire_belt/full/WillContain() + return list( + /obj/item/inflatable = 2, /obj/item/inflatable/door, - /obj/item/extinguisher/mini, + /obj/item/chems/spray/extinguisher/mini, /obj/item/grenade/chem_grenade/water = 2 - ) \ No newline at end of file + ) diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm index 8472afae4b00..8787cc2814d0 100644 --- a/code/game/objects/items/weapons/storage/bible.dm +++ b/code/game/objects/items/weapons/storage/bible.dm @@ -1,4 +1,4 @@ -/obj/item/storage/bible +/obj/item/bible name = "bible" desc = "Apply to head repeatedly." icon = 'icons/obj/items/storage/bible.dmi' @@ -6,106 +6,115 @@ throw_speed = 1 throw_range = 5 w_class = ITEM_SIZE_NORMAL - max_w_class = ITEM_SIZE_SMALL - max_storage_space = 4 - var/mob/affecting = null - var/deity_name = "Christ" + material = /decl/material/solid/organic/paper + matter = list( + /decl/material/solid/organic/cardboard = MATTER_AMOUNT_REINFORCEMENT + ) + storage = /datum/storage/bible var/renamed = 0 var/icon_changed = 0 -/obj/item/storage/bible/Initialize() +/obj/item/bible/Initialize() . = ..() - if(length(startswith)) - make_exact_fit() + if(length(contents) && storage) + storage.make_exact_fit() -/obj/item/storage/bible/booze +/obj/item/bible/booze name = "bible" desc = "To be applied to the head repeatedly." icon_state ="bible" - startswith = list( - /obj/item/chems/food/drinks/bottle/small/beer, +/obj/item/bible/booze/WillContain() + return list( + /obj/item/chems/drinks/bottle/small/beer, /obj/item/cash/c50, /obj/item/cash/c50, ) -/obj/item/storage/bible/bible +/obj/item/bible/bible name = "\improper Bible" desc = "The central religious text of Christianity." renamed = 1 icon_changed = 1 -/obj/item/storage/bible/tanakh +/obj/item/bible/tanakh name = "\improper Tanakh" desc = "The central religious text of Judaism." icon_state = "torah" renamed = 1 icon_changed = 1 -/obj/item/storage/bible/quran +/obj/item/bible/quran name = "\improper Quran" desc = "The central religious text of Islam." icon_state = "koran" renamed = 1 icon_changed = 1 -/obj/item/storage/bible/kojiki +/obj/item/bible/kojiki name = "\improper Kojiki" desc = "A collection of myths from ancient Japan." icon_state = "kojiki" renamed = 1 icon_changed = 1 -/obj/item/storage/bible/aqdas +/obj/item/bible/aqdas name = "\improper Kitab-i-Aqdas" desc = "The central religious text of the Baha'i Faith." icon_state = "ninestar" renamed = 1 icon_changed = 1 -/obj/item/storage/bible/attack(mob/living/carbon/human/M, mob/living/carbon/human/user) - if(user == M || !ishuman(user) || !ishuman(M)) - return - if(user?.mind?.assigned_job?.is_holy) - user.visible_message(SPAN_NOTICE("\The [user] places \the [src] on \the [M]'s forehead, reciting a prayer...")) - if(do_after(user, 5 SECONDS) && user.Adjacent(M)) - user.visible_message("\The [user] finishes reciting \his prayer, removing \the [src] from \the [M]'s forehead.", "You finish reciting your prayer, removing \the [src] from \the [M]'s forehead.") - if(user.get_cultural_value(TAG_RELIGION) == M.get_cultural_value(TAG_RELIGION)) - to_chat(M, SPAN_NOTICE("You feel calm and relaxed, at one with the universe.")) +/obj/item/bible/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(user == target || !ishuman(user) || !ishuman(target)) + return ..() + + if(user.mind?.assigned_job?.is_holy) + user.visible_message(SPAN_NOTICE("\The [user] places \the [src] on \the [target]'s forehead, reciting a prayer...")) + if(do_after(user, 5 SECONDS) && user.Adjacent(target)) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( + SPAN_NOTICE("\The [user] finishes reciting [pronouns.his] prayer, removing \the [src] from \the [target]'s forehead."), + SPAN_NOTICE("You finish reciting your prayer, removing \the [src] from \the [target]'s forehead.")) + if(user.get_background_datum_by_flag(BACKGROUND_FLAG_RELIGION) == target.get_background_datum_by_flag(BACKGROUND_FLAG_RELIGION)) + to_chat(target, SPAN_NOTICE("You feel calm and relaxed, at one with the universe.")) else - to_chat(M, "Nothing happened.") - ..() + to_chat(target, "Nothing happened.") + return TRUE + + return ..() -/obj/item/storage/bible/afterattack(atom/A, mob/user, proximity) - if(!proximity) return - if(user?.mind?.assigned_job?.is_holy) +/obj/item/bible/afterattack(atom/A, mob/user, proximity) + if(proximity && user?.mind?.assigned_job?.is_holy) if(A.reagents && A.reagents.has_reagent(/decl/material/liquid/water)) //blesses all the water in the holder to_chat(user, SPAN_NOTICE("You bless \the [A].")) // I wish it was this easy in nethack - LAZYSET(A.reagents.reagent_data, /decl/material/liquid/water, list("holy" = TRUE)) + REAGENT_SET_DATA(A.reagents, /decl/material/liquid/water, list(DATA_WATER_HOLINESS = TRUE)) -/obj/item/storage/bible/attackby(obj/item/W, mob/user) - if (src.use_sound) - playsound(src.loc, src.use_sound, 50, 1, -5) +/obj/item/bible/attackby(obj/item/used_item, mob/user) + if(storage?.use_sound) + playsound(loc, storage.use_sound, 50, 1, -5) return ..() -/obj/item/storage/bible/attack_self(mob/living/carbon/human/user) +/obj/item/bible/attack_self(mob/user) if(!ishuman(user)) return - if(user?.mind?.assigned_job?.is_holy) - user.visible_message("\The [user] begins to read a passage from \the [src]...", "You begin to read a passage from \the [src]...") - if(do_after(user, 5 SECONDS)) - user.visible_message("\The [user] reads a passage from \the [src].", "You read a passage from \the [src].") - for(var/mob/living/carbon/human/H in view(user)) - if(user.get_cultural_value(TAG_RELIGION) == H.get_cultural_value(TAG_RELIGION)) + var/mob/living/human/preacher = user + if(preacher.mind?.assigned_job?.is_holy) + preacher.visible_message("\The [preacher] begins to read a passage from \the [src]...", "You begin to read a passage from \the [src]...") + if(do_after(preacher, 5 SECONDS)) + preacher.visible_message("\The [preacher] reads a passage from \the [src].", "You read a passage from \the [src].") + for(var/mob/living/human/H in view(preacher)) + if(preacher.get_background_datum_by_flag(BACKGROUND_FLAG_RELIGION) == H.get_background_datum_by_flag(BACKGROUND_FLAG_RELIGION)) to_chat(H, SPAN_NOTICE("You feel calm and relaxed, at one with the universe.")) -/obj/item/storage/bible/verb/rename_bible() +/obj/item/bible/verb/rename_bible() set name = "Rename Bible" set category = "Object" set desc = "Click to rename your bible." if(!renamed) - var/input = sanitizeSafe(input("What do you want to rename your bible to? You can only do this once.", ,""), MAX_NAME_LEN) + var/input = sanitize_safe(input("What do you want to rename your bible to? You can only do this once.", ,""), MAX_NAME_LEN) var/mob/M = usr if(src && input && !M.stat && in_range(M,src)) @@ -114,7 +123,7 @@ renamed = 1 return 1 -/obj/item/storage/bible/verb/set_icon() +/obj/item/bible/verb/set_icon_verb() set name = "Change Icon" set category = "Object" set desc = "Click to change your book's icon." diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 38b22402d4bd..3dc1ec39db8b 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -19,597 +19,756 @@ * For syndicate call-ins see uplink_kits.dm */ -/obj/item/storage/box +/obj/item/box name = "box" desc = "It's just an ordinary box." icon = 'icons/obj/items/storage/box.dmi' icon_state = "box" item_state = "syringe_kit" - max_storage_space = DEFAULT_BOX_STORAGE - use_sound = 'sound/effects/storage/box.ogg' - var/foldable = /obj/item/stack/material/cardboard // BubbleWrap - if set, can be folded (when empty) into a sheet of cardboard + material = /decl/material/solid/organic/cardboard + obj_flags = OBJ_FLAG_HOLLOW + storage = /datum/storage/box + var/foldable = /obj/item/stack/material/cardstock -/obj/item/storage/box/large +/obj/item/box/large name = "large box" icon_state = "largebox" w_class = ITEM_SIZE_LARGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_LARGEBOX_STORAGE + storage = /datum/storage/box/large -/obj/item/storage/box/union_cards +/obj/item/box/union_cards name = "box of union cards" desc = "A box of spare unsigned union membership cards." - startswith = list(/obj/item/card/union = 7) -/obj/item/storage/box/large/union_cards +/obj/item/box/union_cards/WillContain() + return list(/obj/item/card/union = 7) + +/obj/item/box/large/union_cards name = "large box of union cards" desc = "A large box of spare unsigned union membership cards." - startswith = list(/obj/item/card/union = 14) + +/obj/item/box/large/union_cards/WillContain() + return list(/obj/item/card/union = 14) // BubbleWrap - A box can be folded up to make card -/obj/item/storage/box/attack_self(mob/user) - if(..()) return - - //try to fold it. - if ( contents.len ) - return - - if ( !ispath(src.foldable) ) - return - var/found = 0 - // Close any open UI windows first - for(var/mob/M in range(1)) - if (M.s_active == src) - src.close(M) - if ( M == user ) - found = 1 - if ( !found ) // User is too far away - return - // Now make the cardboard - to_chat(user, "You fold [src] flat.") +/obj/item/box/attack_self(mob/user) + . = ..() + if(. || length(contents) || !ispath(foldable) || !istype(material)) + return TRUE + var/sheet_amount = floor(LAZYACCESS(matter, material.type) / SHEET_MATERIAL_AMOUNT) + if(sheet_amount <= 0 || !user.try_unequip(src)) + return TRUE + to_chat(user, SPAN_NOTICE("You fold \the [src] flat.")) if(ispath(foldable, /obj/item/stack)) - var/stack_amt = max(2**(w_class - 3), 1) - new foldable(get_turf(src), stack_amt, /decl/material/solid/cardboard) + new foldable(get_turf(src), sheet_amount, material.type) else - new foldable(get_turf(src), /decl/material/solid/cardboard) + new foldable(get_turf(src), material.type) qdel(src) + return TRUE -/obj/item/storage/box/make_exact_fit() - ..() - foldable = null //special form fitted boxes should not be foldable. - -/obj/item/storage/box/survival/ +/obj/item/box/survival name = "crew survival kit" desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and white stripe indicate this one contains oxygen." icon_state = "survival" - startswith = list(/obj/item/clothing/mask/breath = 1, - /obj/item/tank/emergency/oxygen = 1, - /obj/item/chems/hypospray/autoinjector = 1, - /obj/item/stack/medical/bruise_pack = 1, - /obj/item/flashlight/flare/glowstick = 1, - /obj/item/chems/food/snacks/candy/proteinbar = 1, - /obj/item/oxycandle = 1, - /obj/item/crowbar/cheap = 1) - -/obj/item/storage/box/vox/ - name = "vox survival kit" - desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and black stripe indicate this one contains nitrogen." - icon_state = "survivalvox" - startswith = list(/obj/item/clothing/mask/breath = 1, - /obj/item/tank/emergency/nitrogen = 1, - /obj/item/chems/hypospray/autoinjector = 1, - /obj/item/stack/medical/bruise_pack = 1, - /obj/item/flashlight/flare/glowstick = 1, - /obj/item/chems/food/snacks/candy/proteinbar = 1) - -/obj/item/storage/box/engineer/ + storage = /datum/storage/box/large + +/obj/item/box/survival/WillContain() + return list( + /obj/item/clothing/mask/breath, + /obj/item/tank/emergency/oxygen, + /obj/item/chems/hypospray/autoinjector/stabilizer, + /obj/item/stack/medical/bandage, + /obj/item/flashlight/flare/glowstick, + /obj/item/food/junk/candy/proteinbar, + /obj/item/oxycandle, + /obj/item/crowbar/cheap + ) + +/obj/item/box/engineer name = "engineer survival kit" desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and orange stripe indicate this one as the engineering variant." icon_state = "survivaleng" - startswith = list(/obj/item/clothing/mask/breath/scba = 1, - /obj/item/tank/emergency/oxygen/engi = 1, - /obj/item/chems/hypospray/autoinjector = 1, - /obj/item/chems/hypospray/autoinjector/antirad = 1, - /obj/item/stack/medical/bruise_pack = 1, - /obj/item/flashlight/flare/glowstick = 1, - /obj/item/chems/food/snacks/candy/proteinbar = 1, - /obj/item/oxycandle = 1) - -/obj/item/storage/box/gloves + storage = /datum/storage/box/large + +/obj/item/box/engineer/WillContain() + return list( + /obj/item/clothing/mask/breath/scba, + /obj/item/tank/emergency/oxygen/engi, + /obj/item/chems/hypospray/autoinjector/stabilizer, + /obj/item/chems/hypospray/autoinjector/antirad, + /obj/item/stack/medical/bandage, + /obj/item/flashlight/flare/glowstick, + /obj/item/food/junk/candy/proteinbar, + /obj/item/oxycandle + ) + +/obj/item/box/gloves name = "box of sterile gloves" desc = "Contains sterile gloves." icon_state = "latex" - startswith = list(/obj/item/clothing/gloves/latex = 5, - /obj/item/clothing/gloves/latex/nitrile = 2) -/obj/item/storage/box/masks +/obj/item/box/gloves/WillContain() + return list( + /obj/item/clothing/gloves/latex = 5, + /obj/item/clothing/gloves/latex/nitrile = 2 + ) + +/obj/item/box/masks name = "box of sterile masks" desc = "This box contains masks of sterility." icon_state = "sterile" - startswith = list(/obj/item/clothing/mask/surgical = 7) + +/obj/item/box/masks/WillContain() + return list(/obj/item/clothing/mask/surgical = 7) -/obj/item/storage/box/syringes +/obj/item/box/syringes name = "box of syringes" desc = "A box full of syringes." icon_state = "syringe" - startswith = list(/obj/item/chems/syringe = 7) -/obj/item/storage/box/syringegun +/obj/item/box/syringes/WillContain() + return list(/obj/item/chems/syringe = 7) + +/obj/item/box/syringegun name = "box of syringe gun cartridges" desc = "A box full of compressed gas cartridges." icon_state = "syringe" - startswith = list(/obj/item/syringe_cartridge = 7) +/obj/item/box/syringegun/WillContain() + return list(/obj/item/syringe_cartridge = 7) -/obj/item/storage/box/beakers + +/obj/item/box/beakers name = "box of beakers" icon_state = "beaker" - startswith = list(/obj/item/chems/glass/beaker = 7) -/obj/item/storage/box/beakers/insulated +/obj/item/box/beakers/WillContain() + return list(/obj/item/chems/glass/beaker = 7) + +/obj/item/box/beakers/insulated name = "box of insulated beakers" - startswith = list(/obj/item/chems/glass/beaker/insulated = 7) -/obj/item/storage/box/ammo +/obj/item/box/beakers/insulated/WillContain() + return list(/obj/item/chems/glass/beaker/insulated = 7) + +/obj/item/box/ammo name = "ammo box" icon = 'icons/obj/items/storage/ammobox.dmi' icon_state = "ammo" desc = "A sturdy metal box with several warning symbols on the front.
              WARNING: Live ammunition. Misuse may result in serious injury or death." - use_sound = 'sound/effects/closet_open.ogg' + storage = /datum/storage/box/metal -/obj/item/storage/box/ammo/blanks +/obj/item/box/ammo/blanks name = "box of blank shells" desc = "It has a picture of a gun and several warning symbols on the front." - startswith = list(/obj/item/ammo_casing/shotgun/blank = 8) -/obj/item/storage/box/ammo/practiceshells +/obj/item/box/ammo/blanks/WillContain() + return list(/obj/item/ammo_casing/shotgun/blank = 8) + +/obj/item/box/ammo/blanks/large + icon_state = "largebox" + w_class = ITEM_SIZE_LARGE + storage = /datum/storage/box/large/metal + +/obj/item/box/ammo/blanks/large/Initialize(ml, material_key) + . = ..() + storage.make_exact_fit() + +/obj/item/box/ammo/blanks/large/WillContain() + return list(/obj/item/ammo_casing/shotgun/blank = 16) + +/obj/item/box/ammo/practiceshells name = "box of practice shells" - startswith = list(/obj/item/ammo_casing/shotgun/practice = 8) +/obj/item/box/ammo/practiceshells/WillContain() + return list(/obj/item/ammo_casing/shotgun/practice = 8) -/obj/item/storage/box/ammo/beanbags +/obj/item/box/ammo/beanbags name = "box of beanbag shells" - startswith = list(/obj/item/ammo_magazine/shotholder/beanbag = 2) +/obj/item/box/ammo/beanbags/WillContain() + return list(/obj/item/ammo_magazine/shotholder/beanbag = 2) -/obj/item/storage/box/ammo/shotgunammo +/obj/item/box/ammo/shotgunammo name = "box of shotgun slugs" - startswith = list(/obj/item/ammo_magazine/shotholder = 2) +/obj/item/box/ammo/shotgunammo/WillContain() + return list(/obj/item/ammo_magazine/shotholder = 2) + +/obj/item/box/ammo/shotgunammo/large/WillContain() + return list(/obj/item/ammo_magazine/shotholder = 4) -/obj/item/storage/box/ammo/shotgunshells +/obj/item/box/ammo/shotgunshells name = "box of shotgun shells" - startswith = list(/obj/item/ammo_magazine/shotholder/shell = 2) +/obj/item/box/ammo/shotgunshells/WillContain() + return list(/obj/item/ammo_magazine/shotholder/shell = 2) -/obj/item/storage/box/ammo/flashshells +/obj/item/box/ammo/flashshells name = "box of illumination shells" - startswith = list(/obj/item/ammo_magazine/shotholder/flash = 2) +/obj/item/box/ammo/flashshells/WillContain() + return list(/obj/item/ammo_magazine/shotholder/flash = 2) -/obj/item/storage/box/ammo/stunshells +/obj/item/box/ammo/stunshells name = "box of stun shells" - startswith = list(/obj/item/ammo_magazine/shotholder/stun = 2) +/obj/item/box/ammo/stunshells/WillContain() + return list(/obj/item/ammo_magazine/shotholder/stun = 2) -/obj/item/storage/box/ammo/sniperammo +/obj/item/box/ammo/stunshells/large/WillContain() + return list(/obj/item/ammo_magazine/shotholder/stun = 4) + +/obj/item/box/ammo/sniperammo name = "box of sniper shells" - startswith = list(/obj/item/ammo_casing/shell = 7) +/obj/item/box/ammo/sniperammo/WillContain() + return list(/obj/item/ammo_casing/shell = 7) -/obj/item/storage/box/ammo/sniperammo/apds +/obj/item/box/ammo/sniperammo/apds name = "box of sniper APDS shells" - startswith = list(/obj/item/ammo_casing/shell/apds = 3) +/obj/item/box/ammo/sniperammo/apds/WillContain() + return list(/obj/item/ammo_casing/shell/apds = 3) -/obj/item/storage/box/flashbangs +/obj/item/box/flashbangs name = "box of flashbangs" desc = "A box containing 7 antipersonnel flashbang grenades.
              WARNING: These devices are extremely dangerous and can cause blindness or deafness from repeated use." icon_state = "flashbang" - startswith = list(/obj/item/grenade/flashbang = 7) +/obj/item/box/flashbangs/WillContain() + return list(/obj/item/grenade/flashbang = 7) -/obj/item/storage/box/teargas +/obj/item/box/teargas name = "box of pepperspray grenades" desc = "A box containing 7 tear gas grenades. A gas mask is printed on the label.
              WARNING: Exposure carries risk of serious injury or death. Keep away from persons with lung conditions." icon_state = "flashbang" - startswith = list(/obj/item/grenade/chem_grenade/teargas = 7) +/obj/item/box/teargas/WillContain() + return list(/obj/item/grenade/chem_grenade/teargas = 7) -/obj/item/storage/box/emps - name = "box of emp grenades" +/obj/item/box/emps + name = "box of EMP grenades" desc = "A box containing 5 military grade EMP grenades.
              WARNING: Do not use near unshielded electronics or biomechanical augmentations, death or permanent paralysis may occur." icon_state = "flashbang" - startswith = list(/obj/item/grenade/empgrenade = 5) +/obj/item/box/emps/WillContain() + return list(/obj/item/grenade/empgrenade = 5) + +/obj/item/box/empslite + name = "box of low-yield EMP grenades" + desc = "A box containing 5 low yield EMP grenades.
              WARNING: Do not use near unshielded electronics or biomechanical augmentations, death or permanent paralysis may occur." + icon_state = "flashbang" +/obj/item/box/empslite/WillContain() + return list(/obj/item/grenade/empgrenade/low_yield = 5) -/obj/item/storage/box/frags +/obj/item/box/frags name = "box of frag grenades" desc = "A box containing 5 military grade fragmentation grenades.
              WARNING: Live explosives. Misuse may result in serious injury or death." icon_state = "flashbang" - startswith = list(/obj/item/grenade/frag = 5) +/obj/item/box/frags/WillContain() + return list(/obj/item/grenade/frag = 5) -/obj/item/storage/box/fragshells +/obj/item/box/fragshells name = "box of frag shells" desc = "A box containing 5 military grade fragmentation shells.
              WARNING: Live explosive munitions. Misuse may result in serious injury or death." icon_state = "flashbang" - startswith = list(/obj/item/grenade/frag/shell = 5) +/obj/item/box/fragshells/WillContain() + return list(/obj/item/grenade/frag/shell = 5) -/obj/item/storage/box/smokes +/obj/item/box/smokes name = "box of smoke bombs" desc = "A box containing 5 smoke bombs." icon_state = "flashbang" - startswith = list(/obj/item/grenade/smokebomb = 5) +/obj/item/box/smokes/WillContain() + return list(/obj/item/grenade/smokebomb = 5) -/obj/item/storage/box/anti_photons +/obj/item/box/metalfoam + name = "box of metal foam grenades" + desc = "A box containing 5 metal foam grenades." + icon_state = "flashbang" +/obj/item/box/metalfoam/WillContain() + return list(/obj/item/grenade/chem_grenade/metalfoam = 5) + +/obj/item/box/anti_photons name = "box of anti-photon grenades" desc = "A box containing 5 experimental photon disruption grenades." icon_state = "flashbang" - startswith = list(/obj/item/grenade/anti_photon = 5) +/obj/item/box/anti_photons/WillContain() + return list(/obj/item/grenade/anti_photon = 5) -/obj/item/storage/box/supermatters - name = "box of supermatter grenades" - desc = "A box containing 5 highly experimental supermatter grenades." - icon_state = "radbox" - startswith = list(/obj/item/grenade/supermatter = 5) - -/obj/item/storage/box/decompilers +/obj/item/box/decompilers name = "box of decompiler grenades" desc = "A box containing 5 experimental decompiler grenades." icon_state = "flashbang" - startswith = list(/obj/item/grenade/decompiler = 5) +/obj/item/box/decompilers/WillContain() + return list(/obj/item/grenade/decompiler = 5) -/obj/item/storage/box/trackimp +/obj/item/box/trackimp name = "boxed tracking implant kit" - desc = "Box full of scum-bag tracking utensils." + desc = "Box full of scumbag-tracking utensils." icon_state = "implant" - startswith = list(/obj/item/implantcase/tracking = 4, +/obj/item/box/trackimp/WillContain() + return list(/obj/item/implantcase/tracking = 4, /obj/item/implanter = 1, /obj/item/implantpad = 1, /obj/item/locator = 1) -/obj/item/storage/box/chemimp +/obj/item/box/chemimp name = "boxed chemical implant kit" desc = "Box of stuff used to implant chemicals." icon_state = "implant" - startswith = list(/obj/item/implantcase/chem = 5, +/obj/item/box/chemimp/WillContain() + return list(/obj/item/implantcase/chem = 5, /obj/item/implanter = 1, /obj/item/implantpad = 1) -/obj/item/storage/box/rxglasses +/obj/item/box/rxglasses name = "box of prescription glasses" desc = "This box contains nerd glasses." icon_state = "glasses" - startswith = list(/obj/item/clothing/glasses/prescription = 7) +/obj/item/box/rxglasses/WillContain() + return list(/obj/item/clothing/glasses/prescription = 7) -/obj/item/storage/box/cdeathalarm_kit +/obj/item/box/cdeathalarm_kit name = "death alarm kit" desc = "Box of stuff used to implant death alarms." icon_state = "implant" item_state = "syringe_kit" - startswith = list(/obj/item/implanter = 1, +/obj/item/box/cdeathalarm_kit/WillContain() + return list(/obj/item/implanter = 1, /obj/item/implantcase/death_alarm = 6) -/obj/item/storage/box/condimentbottles +/obj/item/box/condimentbottles name = "box of condiment bottles" desc = "It has a large ketchup smear on it." - startswith = list(/obj/item/chems/food/condiment = 6) +/obj/item/box/condimentbottles/WillContain() + return list(/obj/item/chems/condiment = 6) -/obj/item/storage/box/cups +/obj/item/box/cups name = "box of paper cups" desc = "It has pictures of paper cups on the front." - startswith = list(/obj/item/chems/food/drinks/sillycup = 7) +/obj/item/box/cups/WillContain() + return list(/obj/item/chems/drinks/sillycup = 7) -/obj/item/storage/box/donkpockets +/obj/item/box/donkpockets name = "box of donk-pockets" desc = "Instructions: Heat in microwave. Product will cool if not eaten within seven minutes." icon_state = "donk_kit" - startswith = list(/obj/item/chems/food/snacks/donkpocket = 6) +/obj/item/box/donkpockets/WillContain() + return list(/obj/item/food/donkpocket = 6) -/obj/item/storage/box/sinpockets +/obj/item/box/sinpockets name = "box of sin-pockets" desc = "Instructions: Crush bottom of package to initiate chemical heating. Wait for 20 seconds before consumption. Product will cool if not eaten within seven minutes." icon_state = "donk_kit" - startswith = list(/obj/item/chems/food/snacks/donkpocket/sinpocket = 6) +/obj/item/box/sinpockets/WillContain() + return list(/obj/item/food/donkpocket/sinpocket = 6) //cubed animals +/obj/item/box/animal_cubes + abstract_type = /obj/item/box/animal_cubes + icon = 'icons/obj/items/storage/animal_cube_box.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/box/animal_cube -/obj/item/storage/box/monkeycubes +/obj/item/box/animal_cubes/monkeys name = "monkey cube box" desc = "Drymate brand monkey cubes. Just add water!" - icon = 'icons/obj/food.dmi' - icon_state = "monkeycubebox" - can_hold = list(/obj/item/chems/food/snacks/monkeycube) - startswith = list(/obj/item/chems/food/snacks/monkeycube/wrapped = 5) -/obj/item/storage/box/monkeycubes/spidercubes +/obj/item/box/animal_cubes/monkeys/WillContain() + return list(/obj/item/food/animal_cube/wrapped/monkey = 5) + +/obj/item/box/animal_cubes/spiders name = "spiderling cube box" - desc = "Drymate brand Instant spiders. WHY WOULD YOU ORDER THIS!?" - startswith = list(/obj/item/chems/food/snacks/monkeycube/wrapped/spidercube = 5) + desc = "Drymate brand spider cubes. WHY WOULD YOU ORDER THIS!?" + +/obj/item/box/animal_cubes/spiders/WillContain() + return list(/obj/item/food/animal_cube/wrapped/spider = 5) + +/obj/item/box/animal_cubes/carp + name = "space carp cube box" + desc = "Drymate brand carp cubes. Allergen information: May contain traces of pike." + +/obj/item/box/animal_cubes/carp/WillContain() + return list(/obj/item/food/animal_cube/wrapped/carp = 5) -/obj/item/storage/box/ids +/obj/item/box/ids name = "box of spare IDs" desc = "Has so many empty IDs." icon_state = "id" - startswith = list(/obj/item/card/id = 7) -/obj/item/storage/box/large/ids +/obj/item/box/ids/WillContain() + return list(/obj/item/card/id = 7) + +/obj/item/box/large/ids name = "box of spare IDs" desc = "Has so, so many empty IDs." icon_state = "id_large" - startswith = list(/obj/item/card/id = 14) -/obj/item/storage/box/handcuffs +/obj/item/box/large/ids/WillContain() + return list(/obj/item/card/id = 14) + +/obj/item/box/handcuffs name = "box of spare handcuffs" desc = "A box full of handcuffs." icon_state = "handcuff" - startswith = list(/obj/item/handcuffs = 7) -/obj/item/storage/box/mousetraps +/obj/item/box/handcuffs/WillContain() + return list(/obj/item/handcuffs = 7) + +/obj/item/box/mousetraps name = "box of Pest-B-Gon rat traps" desc = "WARNING: Keep out of reach of children." - startswith = list(/obj/item/assembly/mousetrap = 6) -/obj/item/storage/box/mousetraps/empty - startswith = null +/obj/item/box/mousetraps/WillContain() + return list(/obj/item/assembly/mousetrap = 6) + +/obj/item/box/mousetraps/empty/WillContain() + return null -/obj/item/storage/box/pillbottles +/obj/item/box/pillbottles name = "box of pill bottles" desc = "It has pictures of pill bottles on its front." - startswith = list(/obj/item/storage/pill_bottle = 7) -/obj/item/storage/box/snappops +/obj/item/box/pillbottles/WillContain() + return list(/obj/item/pill_bottle = 7) + +/obj/item/box/snappops name = "snap pop box" desc = "Eight wrappers of fun! Ages 8 and up. Not suitable for children." - icon = 'icons/obj/toy.dmi' + icon = 'icons/obj/toy/toy.dmi' icon_state = "spbox" - can_hold = list(/obj/item/toy/snappop) - startswith = list(/obj/item/toy/snappop = 8) - -/obj/item/storage/box/matches - name = "matchbox" - desc = "A small box of 'Space-Proof' premium matches." - icon = 'icons/obj/items/storage/matches/matchbox.dmi' - icon_state = "matchbox" - item_state = "zippo" - w_class = ITEM_SIZE_TINY - slot_flags = SLOT_BELT - can_hold = list(/obj/item/flame/match) - startswith = list(/obj/item/flame/match = 10) - -/obj/item/storage/box/matches/attackby(obj/item/flame/match/W, mob/user) - if(istype(W) && !W.lit && !W.burnt) - W.lit = 1 - W.damtype = "burn" - W.update_icon() - START_PROCESSING(SSobj, W) - playsound(src.loc, 'sound/items/match.ogg', 60, 1, -4) - user.visible_message("[user] strikes the match on the matchbox.") - W.update_icon() - return - -/obj/item/storage/box/autoinjectors + storage = /datum/storage/box/snappop + +/obj/item/box/snappops/WillContain() + return list(/obj/item/toy/snappop = 8) + +/obj/item/box/autoinjectors name = "box of injectors" desc = "Contains autoinjectors." icon_state = "syringe" - startswith = list(/obj/item/chems/hypospray/autoinjector = 7) +/obj/item/box/autoinjectors/WillContain() + return list(/obj/item/chems/hypospray/autoinjector/stabilizer = 7) -/obj/item/storage/box/lights +/obj/item/box/lights + abstract_type = /obj/item/box/lights name = "box of replacement bulbs" icon_state = "light" desc = "This box is shaped on the inside so that only light tubes and bulbs fit." item_state = "syringe_kit" - use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + storage = /datum/storage/box/lights -/obj/item/storage/box/lights/Initialize() +/obj/item/box/lights/Initialize(ml, material_key) . = ..() - make_exact_fit() + if(length(contents) && storage) + storage.make_exact_fit() -/obj/item/storage/box/lights/bulbs - startswith = list(/obj/item/light/bulb = 21) +/obj/item/box/lights/bulbs/WillContain() + return list(/obj/item/light/bulb = 21) -/obj/item/storage/box/lights/bulbs/empty - startswith = null +/obj/item/box/lights/bulbs/empty/WillContain() + return null -/obj/item/storage/box/lights/tubes +/obj/item/box/lights/tubes name = "box of replacement tubes" icon_state = "lighttube" - startswith = list(/obj/item/light/tube = 17, - /obj/item/light/tube/large = 4) +/obj/item/box/lights/tubes/WillContain() + return list( + /obj/item/light/tube = 17, + /obj/item/light/tube/large = 4 + ) -/obj/item/storage/box/lights/tubes/random +/obj/item/box/lights/tubes/random name = "box of replacement tubes -- party pack" icon_state = "lighttube" - startswith = list(/obj/item/light/tube/party = 17, - /obj/item/light/tube/large/party = 4) +/obj/item/box/lights/tubes/random/WillContain() + return list( + /obj/item/light/tube/party = 17, + /obj/item/light/tube/large/party = 4 + ) -/obj/item/storage/box/lights/tubes/empty - startswith = null +/obj/item/box/lights/tubes/empty/WillContain() + return null -/obj/item/storage/box/lights/mixed +/obj/item/box/lights/mixed name = "box of replacement lights" icon_state = "lightmixed" - startswith = list(/obj/item/light/tube = 12, - /obj/item/light/tube/large = 4, - /obj/item/light/bulb = 5) +/obj/item/box/lights/mixed/WillContain() + return list( + /obj/item/light/tube = 12, + /obj/item/light/tube/large = 4, + /obj/item/light/bulb = 5 + ) -/obj/item/storage/box/lights/mixed/empty - startswith = null +/obj/item/box/lights/mixed/empty/WillContain() + return null -/obj/item/storage/box/glowsticks +/obj/item/box/glowsticks name = "box of mixed glowsticks" icon_state = "box" - startswith = list(/obj/item/flashlight/flare/glowstick = 1, /obj/item/flashlight/flare/glowstick/red = 1, - /obj/item/flashlight/flare/glowstick/blue = 1, /obj/item/flashlight/flare/glowstick/orange = 1, - /obj/item/flashlight/flare/glowstick/yellow = 1, /obj/item/flashlight/flare/glowstick/random = 1) +/obj/item/box/glowsticks/WillContain() + return list( + /obj/item/flashlight/flare/glowstick = 1, + /obj/item/flashlight/flare/glowstick/red = 1, + /obj/item/flashlight/flare/glowstick/blue = 1, + /obj/item/flashlight/flare/glowstick/orange = 1, + /obj/item/flashlight/flare/glowstick/yellow = 1, + /obj/item/flashlight/flare/glowstick/random = 1 + ) -/obj/item/storage/box/greenglowsticks +/obj/item/box/greenglowsticks name = "box of green glowsticks" icon_state = "box" - startswith = list(/obj/item/flashlight/flare/glowstick = 6) +/obj/item/box/greenglowsticks/WillContain() + return list(/obj/item/flashlight/flare/glowstick = 6) + +/obj/item/box/flares + name = "box of flares" + icon_state = "box" + +/obj/item/box/flares/WillContain() + return list(/obj/item/flashlight/flare = 6) -/obj/item/storage/box/freezer +/obj/item/box/freezer name = "portable freezer" desc = "This nifty shock-resistant device will keep your 'groceries' nice and non-spoiled." icon = 'icons/obj/items/storage/portafreezer.dmi' icon_state = "portafreezer" item_state = "medicalpack" foldable = null - max_w_class = ITEM_SIZE_NORMAL + storage = /datum/storage/box/freezer w_class = ITEM_SIZE_LARGE - can_hold = list(/obj/item/organ, /obj/item/chems/food, /obj/item/chems/glass) - max_storage_space = DEFAULT_LARGEBOX_STORAGE - use_to_pickup = 1 // for picking up broken bulbs, not that most people will try temperature = -16 CELSIUS -/obj/item/storage/box/freezer/ProcessAtomTemperature() +/obj/item/box/freezer/ProcessAtomTemperature() return PROCESS_KILL -/obj/item/storage/box/checkers +/obj/item/box/checkers name = "checkers box" desc = "This box holds a nifty portion of checkers. Foam-shaped on the inside so that only checkers may fit." icon_state = "checkers" - max_storage_space = 24 + storage = /datum/storage/box/checkers foldable = null - can_hold = list(/obj/item/chems/food/snacks/checker) - startswith = list(/obj/item/chems/food/snacks/checker = 12, - /obj/item/chems/food/snacks/checker/red = 12) -/obj/item/storage/box/checkers/chess +/obj/item/box/checkers/WillContain() + return list( + /obj/item/checker = 12, + /obj/item/checker/red = 12 + ) + +/obj/item/box/checkers/chess name = "black chess box" desc = "This box holds all the pieces needed for the black side of the chess board." icon_state = "chess_b" - startswith = list(/obj/item/chems/food/snacks/checker/pawn = 8, - /obj/item/chems/food/snacks/checker/knight = 2, - /obj/item/chems/food/snacks/checker/bishop = 2, - /obj/item/chems/food/snacks/checker/rook = 2, - /obj/item/chems/food/snacks/checker/queen = 1, - /obj/item/chems/food/snacks/checker/king = 1) - -/obj/item/storage/box/checkers/chess/red +/obj/item/box/checkers/chess/WillContain() + return list( + /obj/item/checker/pawn = 8, + /obj/item/checker/knight = 2, + /obj/item/checker/bishop = 2, + /obj/item/checker/rook = 2, + /obj/item/checker/queen = 1, + /obj/item/checker/king = 1 + ) + +/obj/item/box/checkers/chess/red name = "red chess box" desc = "This box holds all the pieces needed for the red side of the chess board." icon_state = "chess_r" - startswith = list(/obj/item/chems/food/snacks/checker/pawn/red = 8, - /obj/item/chems/food/snacks/checker/knight/red = 2, - /obj/item/chems/food/snacks/checker/bishop/red = 2, - /obj/item/chems/food/snacks/checker/rook/red = 2, - /obj/item/chems/food/snacks/checker/queen/red = 1, - /obj/item/chems/food/snacks/checker/king/red = 1) +/obj/item/box/checkers/chess/red/WillContain() + return list( + /obj/item/checker/pawn/red = 8, + /obj/item/checker/knight/red = 2, + /obj/item/checker/bishop/red = 2, + /obj/item/checker/rook/red = 2, + /obj/item/checker/queen/red = 1, + /obj/item/checker/king/red = 1 + ) -/obj/item/storage/box/headset +/obj/item/box/headset name = "box of spare headsets" desc = "A box full of headsets." - startswith = list(/obj/item/radio/headset = 7) +/obj/item/box/headset/WillContain() + return list(/obj/item/radio/headset = 7) //Spare Armbands -/obj/item/storage/box/armband/engine +/obj/item/box/armband/engine name = "box of spare engineering armbands" - desc = "A box full of engineering armbands. For use in emergencies when provisional engineering peronnel are needed." - startswith = list(/obj/item/clothing/accessory/armband/engine = 5) + desc = "A box full of engineering armbands. For use in emergencies when provisional engineering personnel are needed." +/obj/item/box/armband/engine/WillContain() + return list(/obj/item/clothing/armband/engine = 5) -/obj/item/storage/box/armband/med +/obj/item/box/armband/med name = "box of spare medical armbands" desc = "A box full of medical armbands. For use in emergencies when provisional medical personnel are needed." - startswith = list(/obj/item/clothing/accessory/armband/med = 5) +/obj/item/box/armband/med/WillContain() + return list(/obj/item/clothing/armband/med = 5) -/obj/item/storage/box/imprinting +/obj/item/box/imprinting name = "box of education implants" desc = "A box full of neural implants for on-job training." - startswith = list( +/obj/item/box/imprinting/WillContain() + return list( /obj/item/implanter, /obj/item/implantpad, /obj/item/implantcase/imprinting = 3 ) -/obj/item/storage/box/detergent +/obj/item/box/detergent name = "detergent pods bag" desc = "A bag full of juicy, yummy detergent pods. This bag has been labeled: Tod Pods, a Waffle Co. product." icon = 'icons/obj/items/storage/detergent.dmi' icon_state = "detergent" - startswith = list(/obj/item/chems/pill/detergent = 10) +/obj/item/box/detergent/WillContain() + return list(/obj/item/chems/pill/detergent = 10) //cargosia supply boxes - Primarily for restocking -/obj/item/storage/box/tapes +/obj/item/box/tapes name = "box of spare tapes" desc = "A box full of blank tapes." - startswith = list(/obj/item/tape/random = 14) + storage = /datum/storage/box/tapes + +/obj/item/box/tapes/WillContain() + return list(/obj/item/magnetic_tape/random = 14) -/obj/item/storage/box/taperolls +/obj/item/box/taperolls name = "box of spare taperolls" desc = "A box full of mixed barricade tapes." - startswith = list(/obj/item/taperoll/police, - /obj/item/taperoll/engineering, - /obj/item/taperoll/atmos, - /obj/item/taperoll/research, - /obj/item/taperoll/medical, - /obj/item/taperoll/bureaucracy - ) - -/obj/item/storage/box/bogrolls +/obj/item/box/taperolls/WillContain() + return list( + /obj/item/stack/tape_roll/barricade_tape/police, + /obj/item/stack/tape_roll/barricade_tape/engineering, + /obj/item/stack/tape_roll/barricade_tape/atmos, + /obj/item/stack/tape_roll/barricade_tape/research, + /obj/item/stack/tape_roll/barricade_tape/medical, + /obj/item/stack/tape_roll/barricade_tape/bureaucracy + ) + +/obj/item/box/bogrolls name = "box of spare bogrolls" desc = "A box full of toilet paper." - startswith = list(/obj/item/taperoll/bog = 6) +/obj/item/box/bogrolls/WillContain() + return list(/obj/item/stack/tape_roll/barricade_tape/toilet = 6) -/obj/item/storage/box/cola +/obj/item/box/cola name = "box of sodas" desc = "A box full of soda cans." - startswith = list(/obj/item/chems/food/drinks/cans/cola = 7) +/obj/item/box/cola/WillContain() + return list(/obj/item/chems/drinks/cans/cola = 7) -/obj/item/storage/box/water +/obj/item/box/water name = "box of water bottles" desc = "A box full of bottled water." - startswith = list(/obj/item/chems/food/drinks/cans/waterbottle = 7) +/obj/item/box/water/WillContain() + return list(/obj/item/chems/drinks/cans/waterbottle = 7) -/obj/item/storage/box/cola/spacewind - startswith = list(/obj/item/chems/food/drinks/cans/space_mountain_wind = 7) +/obj/item/box/cola/spacewind/WillContain() + return list(/obj/item/chems/drinks/cans/space_mountain_wind = 7) -/obj/item/storage/box/cola/drgibb - startswith = list(/obj/item/chems/food/drinks/cans/dr_gibb = 7) +/obj/item/box/cola/drgibb/WillContain() + return list(/obj/item/chems/drinks/cans/dr_gibb = 7) -/obj/item/storage/box/cola/starkist - startswith = list(/obj/item/chems/food/drinks/cans/starkist = 7) +/obj/item/box/cola/starkist/WillContain() + return list(/obj/item/chems/drinks/cans/starkist = 7) -/obj/item/storage/box/cola/spaceup - startswith = list(/obj/item/chems/food/drinks/cans/space_up = 7) +/obj/item/box/cola/spaceup/WillContain() + return list(/obj/item/chems/drinks/cans/space_up = 7) -/obj/item/storage/box/cola/lemonlime - startswith = list(/obj/item/chems/food/drinks/cans/lemon_lime = 7) +/obj/item/box/cola/lemonlime/WillContain() + return list(/obj/item/chems/drinks/cans/lemon_lime = 7) -/obj/item/storage/box/cola/icedtea - startswith = list(/obj/item/chems/food/drinks/cans/iced_tea = 7) +/obj/item/box/cola/icedtea/WillContain() + return list(/obj/item/chems/drinks/cans/iced_tea = 7) -/obj/item/storage/box/cola/grapejuice - startswith = list(/obj/item/chems/food/drinks/cans/grape_juice = 7) +/obj/item/box/cola/grapejuice/WillContain() + return list(/obj/item/chems/drinks/cans/grape_juice = 7) -/obj/item/storage/box/cola/sodawater - startswith = list(/obj/item/chems/food/drinks/cans/sodawater = 7) +/obj/item/box/cola/sodawater/WillContain() + return list(/obj/item/chems/drinks/cans/sodawater = 7) -/obj/item/storage/box/snack +/obj/item/box/snack name = "box of snack food" desc = "A box full of snack foods." - startswith = list(/obj/item/chems/food/snacks/sosjerky = 7) -/obj/item/storage/box/snack/noraisin - startswith = list(/obj/item/chems/food/snacks/no_raisin = 7) +/obj/item/box/snack/WillContain() + return list(/obj/item/food/junk/sosjerky = 7) + +/obj/item/box/snack/noraisin/WillContain() + return list(/obj/item/food/junk/no_raisin = 7) + +/obj/item/box/snack/cheesehonks/WillContain() + return list(/obj/item/food/junk/cheesiehonkers = 7) -/obj/item/storage/box/snack/cheesehonks - startswith = list(/obj/item/chems/food/snacks/cheesiehonkers = 7) +/obj/item/box/snack/tastybread/WillContain() + return list(/obj/item/food/junk/tastybread = 7) -/obj/item/storage/box/snack/tastybread - startswith = list(/obj/item/chems/food/snacks/tastybread = 7) +/obj/item/box/snack/candy/WillContain() + return list(/obj/item/food/junk/candy = 7) -/obj/item/storage/box/snack/candy - startswith = list(/obj/item/chems/food/snacks/candy = 7) +/obj/item/box/snack/chips/WillContain() + return list(/obj/item/food/junk/chips = 7) -/obj/item/storage/box/snack/chips - startswith = list(/obj/item/chems/food/snacks/chips = 7) +/obj/item/box/snack/buns/WillContain() + return list(/obj/item/food/bun = 7) //canned goods in cardboard -/obj/item/storage/box/canned +/obj/item/box/canned name = "box of canned food" desc = "A box full of canned foods." - startswith = list(/obj/item/chems/food/snacks/canned/spinach = 1) - -/obj/item/storage/box/canned/beef - startswith = list(/obj/item/chems/food/snacks/canned/beef = 6) - -/obj/item/storage/box/canned/beans - startswith = list(/obj/item/chems/food/snacks/canned/beans = 6) - -/obj/item/storage/box/canned/tomato - startswith = list(/obj/item/chems/food/snacks/canned/tomato = 6) \ No newline at end of file +/obj/item/box/canned/WillContain() + return list(/obj/item/food/can/spinach = 1) + +/obj/item/box/canned/beef/WillContain() + return list(/obj/item/food/can/beef = 6) + +/obj/item/box/canned/beans/WillContain() + return list(/obj/item/food/can/beans = 6) + +/obj/item/box/canned/tomato/WillContain() + return list(/obj/item/food/can/tomato = 6) + +// machinery stock parts +/obj/item/box/parts + name = "assorted parts pack" + icon = 'icons/obj/items/storage/part_pack.dmi' + icon_state = "big" + w_class = ITEM_SIZE_NORMAL + +/obj/item/box/parts/WillContain() + return list( + /obj/item/stock_parts/power/apc/buildable = 3, + /obj/item/stock_parts/console_screen = 2, + /obj/item/stock_parts/matter_bin = 2 + ) + +/obj/item/box/parts_pack + name = "parts pack" + desc = "A densely-stuffed box containing some small electrical parts." + icon = 'icons/obj/items/storage/part_pack.dmi' + icon_state = "part" + w_class = ITEM_SIZE_SMALL + storage = /datum/storage/box/parts_pack + +/obj/item/box/parts_pack/Initialize(ml, material_key) + setup_name() + return ..() + +/obj/item/box/parts_pack/proc/setup_name() + var/list/cnt = WillContain() + if((islist(cnt) || ispath(cnt)) && length(cnt)) + var/atom/movable/AM = ispath(cnt)? cnt : cnt[1] + SetName("[initial(AM.name)] pack") + +/obj/item/box/parts_pack/manipulator + icon_state = "mainpulator" +/obj/item/box/parts_pack/manipulator/WillContain() + return list(/obj/item/stock_parts/manipulator = 7) + +/obj/item/box/parts_pack/laser + icon_state = "laser" +/obj/item/box/parts_pack/laser/WillContain() + return list(/obj/item/stock_parts/micro_laser = 7) + +/obj/item/box/parts_pack/capacitor + icon_state = "capacitor" +/obj/item/box/parts_pack/capacitor/WillContain() + return list(/obj/item/stock_parts/capacitor = 7) + +/obj/item/box/parts_pack/keyboard + icon_state = "keyboard" +/obj/item/box/parts_pack/keyboard/WillContain() + return list(/obj/item/stock_parts/keyboard = 7) diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm index 61d12165cfc2..e8ef447402aa 100644 --- a/code/game/objects/items/weapons/storage/briefcase.dm +++ b/code/game/objects/items/weapons/storage/briefcase.dm @@ -1,13 +1,13 @@ -/obj/item/storage/briefcase +/obj/item/briefcase name = "briefcase" desc = "It's made of AUTHENTIC faux-leather and has a price-tag still attached. Its owner must be a real professional." icon = 'icons/obj/items/storage/briefcase.dmi' - icon_state = "briefcase" - item_state = "briefcase" + icon_state = ICON_STATE_WORLD obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 8.0 + _base_attack_force = 8.0 throw_speed = 1 throw_range = 4 w_class = ITEM_SIZE_HUGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_BACKPACK_STORAGE + material = /decl/material/solid/organic/leather/synth + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY) + storage = /datum/storage/briefcase diff --git a/code/game/objects/items/weapons/storage/candles.dm b/code/game/objects/items/weapons/storage/candles.dm new file mode 100644 index 000000000000..3b64ed65feac --- /dev/null +++ b/code/game/objects/items/weapons/storage/candles.dm @@ -0,0 +1,50 @@ +/obj/item/box/candles + name = "party candle pack" + desc = "A pack of unscented candles in a variety of colours." + icon = 'icons/obj/items/storage/candles.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/box/candles + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/cardboard + +/obj/item/box/candles/WillContain() + return list(/obj/item/flame/candle/random = 7) + +/obj/item/box/candles/red + name = "red candle pack" + desc = "A pack of unscented candles in blood-red." + +/obj/item/box/candles/red/WillContain() + return list(/obj/item/flame/candle/red = 7) + +/obj/item/box/candles/white + name = "white candle pack" + desc = "A pack of unscented candles in stark white." + +/obj/item/box/candles/white/WillContain() + return list(/obj/item/flame/candle/white = 7) + +/obj/item/box/candles/black + name = "black candle pack" + desc = "A pack of unscented candles in black." + +/obj/item/box/candles/black/WillContain() + return list(/obj/item/flame/candle/black = 7) + +/obj/item/box/candles/incense + name = "incense box" + desc = "A pack of 'Tres' brand incense cones, in a variety of scents." + icon = 'icons/obj/items/storage/incense.dmi' + storage = /datum/storage/box/candles/incense + +/obj/item/box/candles/incense/WillContain() + return list(/obj/item/flame/candle/scented/incense = 9) + +/obj/item/box/candles/scented + name = "scented candle box" + desc = "An unbranded pack of scented candles, in a variety of scents." + storage = /datum/storage/box/candles/scented + +/obj/item/box/candles/scented/WillContain() + return list(/obj/item/flame/candle/scented = 5) diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm deleted file mode 100644 index 6ca989c7ce28..000000000000 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ /dev/null @@ -1,333 +0,0 @@ -/* - * The 'fancy' path is for objects like candle boxes that show how many items are in the storage item on the sprite itself - * .. Sorry for the shitty path name, I couldnt think of a better one. - * - * - * Contains: - * Egg Box - * Crayon Box - * Cigarette Box - */ - -/obj/item/storage/fancy - item_state = "syringe_kit" //placeholder, many of these don't have inhands - opened = 0 //if an item has been removed from this container - var/obj/item/key_type //path of the key item that this "fancy" container is meant to store - -/obj/item/storage/fancy/on_update_icon() - if(!opened) - src.icon_state = initial(icon_state) - else - var/key_count = count_by_type(contents, key_type) - src.icon_state = "[initial(icon_state)][key_count]" - -/obj/item/storage/fancy/examine(mob/user, distance) - . = ..() - if(distance > 1) - return - - var/key_name = initial(key_type.name) - if(!contents.len) - to_chat(user, "There are no [key_name]s left in the box.") - else - var/key_count = count_by_type(contents, key_type) - to_chat(user, "There [key_count == 1? "is" : "are"] [key_count] [key_name]\s in the box.") - -/* - * Egg Box - */ - -/obj/item/storage/fancy/egg_box - icon = 'icons/obj/food.dmi' - icon_state = "eggbox" - name = "egg box" - storage_slots = 12 - max_w_class = ITEM_SIZE_SMALL - w_class = ITEM_SIZE_NORMAL - - key_type = /obj/item/chems/food/snacks/egg - can_hold = list( - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/boiledegg - ) - - startswith = list(/obj/item/chems/food/snacks/egg = 12) - -/obj/item/storage/fancy/egg_box/empty - startswith = null - -/* - * Cracker Packet - */ - -/obj/item/storage/fancy/crackers - name = "\improper Getmore Crackers" - icon = 'icons/obj/food.dmi' - icon_state = "crackerbag" - storage_slots = 6 - max_w_class = ITEM_SIZE_TINY - w_class = ITEM_SIZE_SMALL - key_type = /obj/item/chems/food/snacks/cracker - can_hold = list(/obj/item/chems/food/snacks/cracker) - startswith = list(/obj/item/chems/food/snacks/cracker = 6) - -/* - * Crayon Box - */ - -/obj/item/storage/fancy/crayons - name = "box of crayons" - desc = "A box of crayons for all your rune drawing needs." - icon = 'icons/obj/items/crayons.dmi' - icon_state = "crayonbox" - w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - max_storage_space = 6 - - key_type = /obj/item/pen/crayon - startswith = list( - /obj/item/pen/crayon/red, - /obj/item/pen/crayon/orange, - /obj/item/pen/crayon/yellow, - /obj/item/pen/crayon/green, - /obj/item/pen/crayon/blue, - /obj/item/pen/crayon/purple, - ) - -/obj/item/storage/fancy/crayons/on_update_icon() - overlays = list() //resets list - overlays += image(icon,"crayonbox") - for(var/obj/item/pen/crayon/crayon in contents) - overlays += image(icon,crayon.colourName) - -//////////// -//CIG PACK// -//////////// -/obj/item/storage/fancy/cigarettes - name = "pack of Trans-Stellar Duty-frees" - desc = "A ubiquitous brand of cigarettes, found in the facilities of every major spacefaring corporation in the universe. As mild and flavorless as it gets." - icon = 'icons/obj/items/storage/cigpack/cigpack.dmi' - icon_state = "cigpacket" - item_state = "cigpacket" - w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - max_storage_space = 6 - throwforce = 2 - slot_flags = SLOT_BELT - - key_type = /obj/item/clothing/mask/smokable/cigarette - startswith = list(/obj/item/clothing/mask/smokable/cigarette = 6) - -/obj/item/storage/fancy/cigarettes/Initialize() - . = ..() - atom_flags |= ATOM_FLAG_NO_REACT|ATOM_FLAG_OPEN_CONTAINER - create_reagents(5 * max_storage_space)//so people can inject cigarettes without opening a packet, now with being able to inject the whole one - -/obj/item/storage/fancy/cigarettes/remove_from_storage(obj/item/W, atom/new_location) - // Don't try to transfer reagents to lighters - if(istype(W, /obj/item/clothing/mask/smokable/cigarette)) - var/obj/item/clothing/mask/smokable/cigarette/C = W - reagents.trans_to_obj(C, (reagents.total_volume/contents.len)) - ..() - -/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M, /mob)) - return - - if(M == user && user.zone_sel.selecting == BP_MOUTH && contents.len > 0 && !user.wear_mask) - // Find ourselves a cig. Note that we could be full of lighters. - var/obj/item/clothing/mask/smokable/cigarette/cig = null - for(var/obj/item/clothing/mask/smokable/cigarette/C in contents) - cig = C - break - - if(cig == null) - to_chat(user, "Looks like the packet is out of cigarettes.") - return - - // Instead of running equip_to_slot_if_possible() we check here first, - // to avoid dousing cig with reagents if we're not going to equip it - if(!cig.mob_can_equip(user, slot_wear_mask)) - return - - // We call remove_from_storage first to manage the reagent transfer and - // UI updates. - remove_from_storage(cig, null) - user.equip_to_slot(cig, slot_wear_mask) - - reagents.maximum_volume = 5 * contents.len - to_chat(user, "You take a cigarette out of the pack.") - update_icon() - else - ..() - -/obj/item/storage/fancy/cigarettes/dromedaryco - name = "pack of Dromedary Co. cigarettes" - desc = "A packet of six imported Dromedary Company cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"." - icon = 'icons/obj/items/storage/cigpack/dromedary.dmi' - icon_state = "Dpacket" - startswith = list(/obj/item/clothing/mask/smokable/cigarette/dromedaryco = 6) - -/obj/item/storage/fancy/cigarettes/killthroat - name = "pack of Acme Co. cigarettes" - desc = "A packet of six Acme Company cigarettes. For those who somehow want to obtain the record for the most amount of cancerous tumors." - icon = 'icons/obj/items/storage/cigpack/acme.dmi' - icon_state = "Bpacket" - startswith = list(/obj/item/clothing/mask/smokable/cigarette/killthroat = 6) - -/obj/item/storage/fancy/cigarettes/killthroat/Initialize() - . = ..() - fill_cigarre_package(src,list(/decl/material/liquid/fuel = 4)) - -// New exciting ways to kill your lungs! - Earthcrusher // - -/obj/item/storage/fancy/cigarettes/luckystars - name = "pack of Lucky Stars" - desc = "A mellow blend made from synthetic, pod-grown tobacco. The commercial jingle is guaranteed to get stuck in your head." - icon = 'icons/obj/items/storage/cigpack/lucky_stars.dmi' - icon_state = "LSpacket" - item_state = "Dpacket" //I actually don't mind cig packs not showing up in the hand. whotf doesn't just keep them in their pockets/coats // - startswith = list(/obj/item/clothing/mask/smokable/cigarette/luckystars = 6) - -/obj/item/storage/fancy/cigarettes/jerichos - name = "pack of Jerichos" - desc = "Typically seen dangling from the lips of Martian soldiers and border world hustlers. Tastes like hickory smoke, feels like warm liquid death down your lungs." - icon = 'icons/obj/items/storage/cigpack/jerichos.dmi' - icon_state = "Jpacket" - item_state = "Dpacket" - startswith = list(/obj/item/clothing/mask/smokable/cigarette/jerichos = 6) - -/obj/item/storage/fancy/cigarettes/menthols - name = "pack of Temperamento Menthols" - desc = "With a sharp and natural organic menthol flavor, these Temperamentos are a favorite of NDV crews. Hardly anyone knows they make 'em in non-menthol!" - icon = 'icons/obj/items/storage/cigpack/menthol.dmi' - icon_state = "TMpacket" - item_state = "Dpacket" - - key_type = /obj/item/clothing/mask/smokable/cigarette/menthol - startswith = list(/obj/item/clothing/mask/smokable/cigarette/menthol = 6) - -/obj/item/storage/fancy/cigarettes/carcinomas - name = "pack of Carcinoma Angels" - desc = "This unknown brand was slated for the chopping block, until they were publicly endorsed by an old Earthling gonzo journalist. The rest is history. They sell a variety for cats, too. Yes, actual cats." - icon = 'icons/obj/items/storage/cigpack/carcinoma.dmi' - icon_state = "CApacket" - item_state = "Dpacket" - startswith = list(/obj/item/clothing/mask/smokable/cigarette/carcinomas = 6) - -/obj/item/storage/fancy/cigarettes/professionals - name = "pack of Professional 120s" - desc = "Let's face it - if you're smoking these, you're either trying to look upper-class or you're 80 years old. That's the only excuse. They taste disgusting, too." - icon_state = "P100packet" - icon = 'icons/obj/items/storage/cigpack/professionals.dmi' - item_state = "Dpacket" - startswith = list(/obj/item/clothing/mask/smokable/cigarette/professionals = 6) - -//cigarellos -/obj/item/storage/fancy/cigarettes/cigarello - name = "pack of Trident Original cigars" - desc = "The Trident brand's wood tipped little cigar, favored by the Sol corps diplomatique for their pleasant aroma. Machine made on Mars for over 100 years." - icon = 'icons/obj/items/storage/cigpack/cigarillo.dmi' - icon_state = "CRpacket" - item_state = "Dpacket" - max_storage_space = 5 - key_type = /obj/item/clothing/mask/smokable/cigarette/trident - startswith = list(/obj/item/clothing/mask/smokable/cigarette/trident = 5) - -/obj/item/storage/fancy/cigarettes/cigarello/variety - name = "pack of Trident Fruit cigars" - desc = "The Trident brand's wood tipped little cigar, favored by the Sol corps diplomatique for their pleasant aroma. Machine made on Mars for over 100 years. This is a fruit variety pack." - icon = 'icons/obj/items/storage/cigpack/cigarillo_fruity.dmi' - icon_state = "CRFpacket" - startswith = list( /obj/item/clothing/mask/smokable/cigarette/trident/watermelon, - /obj/item/clothing/mask/smokable/cigarette/trident/orange, - /obj/item/clothing/mask/smokable/cigarette/trident/grape, - /obj/item/clothing/mask/smokable/cigarette/trident/cherry, - /obj/item/clothing/mask/smokable/cigarette/trident/berry) - -/obj/item/storage/fancy/cigarettes/cigarello/mint - name = "pack of Trident Menthol cigars" - desc = "The Trident brand's wood tipped little cigar, favored by the Sol corps diplomatique for their pleasant aroma. Machine made on Mars for over 100 years. These are the menthol variety." - icon = 'icons/obj/items/storage/cigpack/cigarillo_menthol.dmi' - icon_state = "CRMpacket" - startswith = list(/obj/item/clothing/mask/smokable/cigarette/trident/mint = 5) - -/obj/item/storage/fancy/cigar - name = "cigar case" - desc = "A case for holding your cigars when you are not smoking them." - icon_state = "cigarcase" - item_state = "cigpacket" - icon = 'icons/obj/items/storage/cigarcase.dmi' - w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - throwforce = 2 - slot_flags = SLOT_BELT - storage_slots = 7 - - key_type = /obj/item/clothing/mask/smokable/cigarette/cigar - startswith = list(/obj/item/clothing/mask/smokable/cigarette/cigar = 6) - -/obj/item/storage/fancy/cigar/Initialize() - . = ..() - atom_flags |= ATOM_FLAG_NO_REACT - create_reagents(10 * storage_slots) - -/obj/item/storage/fancy/cigar/remove_from_storage(obj/item/W, atom/new_location) - var/obj/item/clothing/mask/smokable/cigarette/cigar/C = W - if(!istype(C)) return - reagents.trans_to_obj(C, (reagents.total_volume/contents.len)) - ..() - -/* - * Vial Box - */ - -/obj/item/storage/fancy/vials - icon = 'icons/obj/vialbox.dmi' - icon_state = "vialbox" - name = "vial storage box" - w_class = ITEM_SIZE_NORMAL - max_w_class = ITEM_SIZE_TINY - storage_slots = 12 - - key_type = /obj/item/chems/glass/beaker/vial - startswith = list(/obj/item/chems/glass/beaker/vial = 12) - -/obj/item/storage/fancy/vials/on_update_icon() - var/key_count = count_by_type(contents, key_type) - src.icon_state = "[initial(icon_state)][Floor(key_count/2)]" - -/* - * Not actually a "fancy" storage... - */ -/obj/item/storage/lockbox/vials - name = "secure vial storage box" - desc = "A locked box for keeping things away from children." - icon = 'icons/obj/vialbox.dmi' - icon_state = "vialbox0" - item_state = "syringe_kit" - w_class = ITEM_SIZE_NORMAL - max_w_class = ITEM_SIZE_TINY - max_storage_space = null - storage_slots = 12 - req_access = list(access_virology) - -/obj/item/storage/lockbox/vials/Initialize() - . = ..() - update_icon() - -/obj/item/storage/lockbox/vials/on_update_icon() - var/total_contents = count_by_type(contents, /obj/item/chems/glass/beaker/vial) - src.icon_state = "vialbox[Floor(total_contents/2)]" - src.overlays.Cut() - if (!broken) - overlays += image(icon, src, "led[locked]") - if(locked) - overlays += image(icon, src, "cover") - else - overlays += image(icon, src, "ledb") - return - -/obj/item/storage/lockbox/vials/attackby(obj/item/W, mob/user) - . = ..() - update_icon() diff --git a/code/game/objects/items/weapons/storage/fancy/_fancy.dm b/code/game/objects/items/weapons/storage/fancy/_fancy.dm new file mode 100644 index 000000000000..44f9cd602a65 --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/_fancy.dm @@ -0,0 +1,52 @@ +/* + * The 'fancy' path is for objects like candle boxes that show how many items are in the storage item on the sprite itself + */ + +/obj/item/box/fancy + abstract_type = /obj/item/box/fancy + /// A string modifier used to generate overlays for contents. + var/use_single_icon_overlay_state + /// The root type of the key item that this "fancy" container is meant to store. + var/obj/item/key_type + +/obj/item/box/fancy/proc/adjust_contents_overlay(var/overlay_index, var/image/overlay) + return overlay + +/obj/item/box/fancy/proc/update_icon_state() + icon_state = initial(icon_state) + if(!length(contents)) + var/empty_state = "[icon_state]0" + if(check_state_in_icon(empty_state, icon)) + icon_state = empty_state + else if(key_type && storage?.opened) + icon_state = "[icon_state][count_by_type(contents, key_type)]" + +/obj/item/box/fancy/proc/add_contents_overlays() + . = FALSE + if(!use_single_icon_overlay_state) + return + var/offset_index = 0 + for(var/obj/item/thing in contents) + var/thing_state = "[thing.icon_state]_[use_single_icon_overlay_state]" + if(!check_state_in_icon(thing_state, thing.icon)) + continue + . = TRUE + var/image/thing_overlay = adjust_contents_overlay(offset_index, image(thing.icon, thing_state)) + if(thing.color) + thing_overlay.color = thing.color + thing_overlay.appearance_flags |= RESET_COLOR + add_overlay(thing_overlay) + offset_index++ + +/obj/item/box/fancy/on_update_icon() + . = ..() + update_icon_state() + if(add_contents_overlays()) + compile_overlays() + +/obj/item/box/fancy/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1 || !key_type) + return + var/key_count = count_by_type(contents, key_type) + . += "There [key_count == 1? "is" : "are"] [key_count] [atom_info_repository.get_name_for(key_type)]\s in the box." diff --git a/code/game/objects/items/weapons/storage/fancy/cigar.dm b/code/game/objects/items/weapons/storage/fancy/cigar.dm new file mode 100644 index 000000000000..a24b3da8a2b4 --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/cigar.dm @@ -0,0 +1,23 @@ +/* + * Cigar +*/ +/obj/item/box/fancy/cigar + name = "cigar case" + desc = "A case for holding your cigars when you are not smoking them." + icon_state = "cigarcase" + item_state = "cigpacket" + icon = 'icons/obj/items/storage/cigarcase.dmi' + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/wood/mahogany + key_type = /obj/item/clothing/mask/smokable/cigarette/cigar + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE + storage = /datum/storage/box/cigar + +/obj/item/box/fancy/cigar/Initialize(ml, material_key) + if(istype(storage)) + chem_volume = 10 * max(1, storage.storage_slots) + . = ..() + +/obj/item/box/fancy/cigar/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/cigar = 6) diff --git a/code/game/objects/items/weapons/storage/fancy/cigarettes.dm b/code/game/objects/items/weapons/storage/fancy/cigarettes.dm new file mode 100644 index 000000000000..79fa5b45156a --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/cigarettes.dm @@ -0,0 +1,219 @@ +//////////// +//CIG PACK// +//////////// +/obj/item/box/fancy/cigarettes + name = "pack of Trans-Stellar Duty-frees" + desc = "A ubiquitous brand of cigarettes, found in the facilities of every major spacefaring corporation in the universe. As mild and flavorless as it gets." + icon = 'icons/obj/items/storage/cigpack/cigpack.dmi' + icon_state = "cigpacket" + item_state = "cigpacket" + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + key_type = /obj/item/clothing/mask/smokable/cigarette + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE | ATOM_FLAG_OPEN_CONTAINER + storage = /datum/storage/box/cigarettes + +/obj/item/box/fancy/cigarettes/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette = 6) + +/obj/item/box/fancy/cigarettes/Initialize(ml, material_key) + chem_volume = 5 * max(/datum/storage/box/cigarettes::max_storage_space, 1) //so people can inject cigarettes without opening a packet, now with being able to inject the whole one + . = ..() + +/obj/item/box/fancy/cigarettes/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(target == user && user.get_target_zone() == BP_MOUTH && contents.len > 0 && !user.get_equipped_item(slot_wear_mask_str)) + // Find ourselves a cig. Note that we could be full of lighters. + var/obj/item/clothing/mask/smokable/cigarette/cig = null + for(var/obj/item/clothing/mask/smokable/cigarette/C in contents) + cig = C + break + + if(cig == null) + to_chat(user, SPAN_NOTICE("Looks like the packet is out of cigarettes.")) + return TRUE + + // Instead of running equip_to_slot_if_possible() we check here first, + // to avoid dousing cig with reagents if we're not going to equip it + if(!cig.mob_can_equip(user, slot_wear_mask_str)) + return TRUE + + // We call remove_from_storage first to manage the reagent transfer and + // UI updates. + + storage?.remove_from_storage(user, cig, null) + user.equip_to_slot(cig, slot_wear_mask_str) + create_or_update_reagents(5 * contents.len) + to_chat(user, SPAN_NOTICE("You take a cigarette out of the pack.")) + update_icon() + return TRUE + + return ..() + +/obj/item/box/fancy/cigarettes/dromedaryco + name = "pack of Dromedary Co. cigarettes" + desc = "A packet of six imported Dromedary Company cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"." + icon = 'icons/obj/items/storage/cigpack/dromedary.dmi' + icon_state = "Dpacket" + +/obj/item/box/fancy/cigarettes/dromedaryco/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/dromedaryco = 6) + +/obj/item/box/fancy/cigarettes/killthroat + name = "pack of Acme Co. cigarettes" + desc = "A packet of six Acme Company cigarettes. For those who somehow want to obtain the record for the most amount of cancerous tumors." + icon = 'icons/obj/items/storage/cigpack/acme.dmi' + icon_state = "Bpacket" + +/obj/item/box/fancy/cigarettes/killthroat/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/killthroat = 6) + +/obj/item/box/fancy/cigarettes/killthroat/populate_reagents() + add_to_reagents(/decl/material/liquid/fuel, (max(1, storage?.max_storage_space) * 4)) + +// New exciting ways to kill your lungs! - Sunbeamstress // + +/obj/item/box/fancy/cigarettes/luckystars + name = "pack of Lucky Stars" + desc = "A mellow blend made from synthetic, pod-grown tobacco. The commercial jingle is guaranteed to get stuck in your head." + icon = 'icons/obj/items/storage/cigpack/lucky_stars.dmi' + icon_state = "LSpacket" + item_state = "Dpacket" //I actually don't mind cig packs not showing up in the hand. whotf doesn't just keep them in their pockets/coats // + +/obj/item/box/fancy/cigarettes/luckystars/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/luckystars = 6) + +/obj/item/box/fancy/cigarettes/jerichos + name = "pack of Jerichos" + desc = "Typically seen dangling from the lips of Martian soldiers and border world hustlers. Tastes like hickory smoke, feels like warm liquid death down your lungs." + icon = 'icons/obj/items/storage/cigpack/jerichos.dmi' + icon_state = "Jpacket" + item_state = "Dpacket" + +/obj/item/box/fancy/cigarettes/jerichos/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/jerichos = 6) + +/obj/item/box/fancy/cigarettes/menthols + name = "pack of Temperamento Menthols" + desc = "With a sharp and natural organic menthol flavor, these Temperamentos are a favorite of NDV crews. Hardly anyone knows they make 'em in non-menthol!" + icon = 'icons/obj/items/storage/cigpack/menthol.dmi' + icon_state = "TMpacket" + item_state = "Dpacket" + key_type = /obj/item/clothing/mask/smokable/cigarette/menthol + +/obj/item/box/fancy/cigarettes/menthols/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/menthol = 6) + +/obj/item/box/fancy/cigarettes/carcinomas + name = "pack of Carcinoma Angels" + desc = "This unknown brand was slated for the chopping block, until they were publicly endorsed by an old Earthling gonzo journalist. The rest is history. They sell a variety for cats, too. Yes, actual cats." + icon = 'icons/obj/items/storage/cigpack/carcinoma.dmi' + icon_state = "CApacket" + item_state = "Dpacket" + +/obj/item/box/fancy/cigarettes/carcinomas/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/carcinomas = 6) + +/obj/item/box/fancy/cigarettes/professionals + name = "pack of Professional 120s" + desc = "Let's face it - if you're smoking these, you're either trying to look upper-class or you're 80 years old. That's the only excuse. They taste disgusting, too." + icon_state = "P100packet" + icon = 'icons/obj/items/storage/cigpack/professionals.dmi' + item_state = "Dpacket" + +/obj/item/box/fancy/cigarettes/professionals/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/professionals = 6) + +//cigarellos +/obj/item/box/fancy/cigarettes/cigarello + name = "pack of Trident Original cigars" + desc = "The Trident brand's wood tipped little cigar, favored by some for their pleasant aroma. Machine made on Mars for over 100 years." + icon = 'icons/obj/items/storage/cigpack/cigarillo.dmi' + icon_state = "CRpacket" + item_state = "Dpacket" + key_type = /obj/item/clothing/mask/smokable/cigarette/trident + storage = /datum/storage/box/cigarettes/cigarello + +/obj/item/box/fancy/cigarettes/cigarello/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/trident = 5) + +/obj/item/box/fancy/cigarettes/cigarello/variety + name = "pack of Trident Fruit cigars" + desc = "The Trident brand's wood tipped little cigar, favored by some for their pleasant aroma. Machine made on Mars for over 100 years. This is a fruit variety pack." + icon = 'icons/obj/items/storage/cigpack/cigarillo_fruity.dmi' + icon_state = "CRFpacket" + +/obj/item/box/fancy/cigarettes/cigarello/variety/WillContain() + return list( + /obj/item/clothing/mask/smokable/cigarette/trident/watermelon, + /obj/item/clothing/mask/smokable/cigarette/trident/orange, + /obj/item/clothing/mask/smokable/cigarette/trident/grape, + /obj/item/clothing/mask/smokable/cigarette/trident/cherry, + /obj/item/clothing/mask/smokable/cigarette/trident/berry + ) + +/obj/item/box/fancy/cigarettes/cigarello/mint + name = "pack of Trident Menthol cigars" + desc = "The Trident brand's wood tipped little cigar, favored by some for their pleasant aroma. Machine made on Mars for over 100 years. These are the menthol variety." + icon = 'icons/obj/items/storage/cigpack/cigarillo_menthol.dmi' + icon_state = "CRMpacket" + +/obj/item/box/fancy/cigarettes/cigarello/mint/WillContain() + return list(/obj/item/clothing/mask/smokable/cigarette/trident/mint = 5) + +//////////////////////////////////////////////////////////////////////////////// +// Syndie Cigs +//////////////////////////////////////////////////////////////////////////////// +/obj/item/box/fancy/cigarettes/covert + abstract_type = /obj/item/box/fancy/cigarettes/covert + /// (TYPEPATH) Used to reset the name and description of covert cigarette packs on init. + var/obj/item/box/fancy/cigarettes/disguised_as = /obj/item/box/fancy/cigarettes + /// (STRING) Part of a string appended to the description on init. + var/scribble = null + +/obj/item/box/fancy/cigarettes/covert/Initialize(ml, material_key) + . = ..() + if(ispath(disguised_as, /obj/item/box/fancy/cigarettes)) + //Reset the name to the default cig pack. Done for codex reasons, since it indexes things by initial names + if(name == initial(name)) // allow mapped names to override it + SetName(disguised_as::name) + if(desc == initial(desc) && istext(scribble)) // ditto for mapped descs + desc = "[disguised_as::desc] '[scribble]' has been scribbled on it." + +// Flash Powder Pack +/obj/item/box/fancy/cigarettes/covert/flash_powder + name = "pack of flash powder laced Trans-Stellar Duty-frees" + disguised_as = /obj/item/box/fancy/cigarettes + scribble = "F" + +/obj/item/box/fancy/cigarettes/covert/flash_powder/populate_reagents() + var/max_storage_space = max(1, storage?.max_storage_space) + add_to_reagents(/decl/material/solid/metal/aluminium, max_storage_space) + add_to_reagents(/decl/material/solid/potassium, max_storage_space) + add_to_reagents(/decl/material/solid/sulfur, max_storage_space) + +//Chemsmoke Pack +/obj/item/box/fancy/cigarettes/covert/chemsmoke + name = "pack of smoke powder laced Trans-Stellar Duty-frees" + scribble = "S" + +/obj/item/box/fancy/cigarettes/covert/chemsmoke/populate_reagents() + var/max_storage_space = max(1, storage?.max_storage_space) + add_to_reagents(/decl/material/solid/potassium, max_storage_space) + add_to_reagents(/decl/material/liquid/nutriment/sugar, max_storage_space) + add_to_reagents(/decl/material/solid/phosphorus, max_storage_space) + +//Mindbreak Pack (now called /decl/chemical_reaction/hallucinogenics) +/obj/item/box/fancy/cigarettes/covert/mindbreak + name = "pack of hallucinogen-laced Trans-Stellar Duty-frees" //#TODO: maybe fix the lore for that? + scribble = "H" + +/obj/item/box/fancy/cigarettes/covert/mindbreak/populate_reagents() + add_to_reagents(/decl/material/liquid/hallucinogenics, (3 * max(1, storage?.max_storage_space))) + +//Tricord pack (now called 'regenerative serum') +/obj/item/box/fancy/cigarettes/covert/tricord + name = "pack of regenerative serum-laced Trans-Stellar Duty-frees" //#TODO: maybe fix the lore for that? + scribble = "R" + +/obj/item/box/fancy/cigarettes/covert/tricord/populate_reagents() + add_to_reagents(/decl/material/liquid/regenerator, (4 * max(1, storage?.max_storage_space))) diff --git a/code/game/objects/items/weapons/storage/fancy/crackers.dm b/code/game/objects/items/weapons/storage/fancy/crackers.dm new file mode 100644 index 000000000000..fd468ec817bd --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/crackers.dm @@ -0,0 +1,28 @@ +/* + * Cracker Packet + */ +/obj/item/box/fancy/crackers + name = "bag of crackers" + icon = 'icons/obj/food/containers/crackerbag.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + key_type = /obj/item/food/cracker + use_single_icon_overlay_state = "crackerbag" + storage = /datum/storage/box/crackers + +/obj/item/box/fancy/crackers/adjust_contents_overlay(var/overlay_index, var/image/overlay) + overlay?.pixel_x = -(overlay_index) + return overlay + +/obj/item/box/fancy/crackers/WillContain() + return list(/obj/item/food/cracker = 6) + +/obj/item/box/fancy/crackers/update_icon_state() + icon_state = get_world_inventory_state() + +/obj/item/box/fancy/crackers/on_update_icon() + . = ..() + if(storage?.opened) + add_overlay("[icon_state]_open") + else + add_overlay("[icon_state]_closed") diff --git a/code/game/objects/items/weapons/storage/fancy/crayons.dm b/code/game/objects/items/weapons/storage/fancy/crayons.dm new file mode 100644 index 000000000000..59c5e0a68a6e --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/crayons.dm @@ -0,0 +1,31 @@ +/* + * Crayon Box + */ + +/obj/item/box/fancy/crayons + name = "box of crayons" + desc = "A box of crayons for all your rune drawing needs." + icon = 'icons/obj/items/crayon_box.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + key_type = /obj/item/pen/crayon + use_single_icon_overlay_state = "crayonbox" + storage = /datum/storage/box/crayons + +/obj/item/box/fancy/crayons/update_icon_state() + icon_state = get_world_inventory_state() + +/obj/item/box/fancy/crayons/adjust_contents_overlay(var/overlay_index, var/image/overlay) + if(overlay) + overlay.pixel_x = overlay_index * 2 + return overlay + +/obj/item/box/fancy/crayons/WillContain() + return list( + /obj/item/pen/crayon/red, + /obj/item/pen/crayon/orange, + /obj/item/pen/crayon/yellow, + /obj/item/pen/crayon/green, + /obj/item/pen/crayon/blue, + /obj/item/pen/crayon/purple, + ) diff --git a/code/game/objects/items/weapons/storage/fancy/donutbox.dm b/code/game/objects/items/weapons/storage/fancy/donutbox.dm new file mode 100644 index 000000000000..eada5f5ec386 --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/donutbox.dm @@ -0,0 +1,26 @@ +/* + * Donut box! + */ + +/obj/item/box/fancy/donut + name = "donut box" + icon = 'icons/obj/food/containers/donutbox.dmi' + icon_state = ICON_STATE_WORLD + item_state = null + use_single_icon_overlay_state = "donutbox" + storage = /datum/storage/box/donut + +/obj/item/box/fancy/donut/update_icon_state() + icon_state = get_world_inventory_state() + +/obj/item/box/fancy/donut/adjust_contents_overlay(var/overlay_index, var/image/overlay) + if(overlay) + overlay.pixel_x = overlay_index * 3 + return overlay + +/obj/item/box/fancy/donut/WillContain() + return list(/obj/item/food/donut = 6) + +// Subtypes below. +/obj/item/box/fancy/donut/empty/WillContain() + return null diff --git a/code/game/objects/items/weapons/storage/fancy/eggbox.dm b/code/game/objects/items/weapons/storage/fancy/eggbox.dm new file mode 100644 index 000000000000..ba9797492a6c --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/eggbox.dm @@ -0,0 +1,50 @@ +/* + * Egg Box + */ + +/obj/item/box/fancy/egg_box + name = "egg box" + icon = 'icons/obj/food/containers/eggbox.dmi' + icon_state = ICON_STATE_WORLD + item_state = null + w_class = ITEM_SIZE_NORMAL + key_type = /obj/item/food/egg + use_single_icon_overlay_state = "eggbox" + storage = /datum/storage/box/egg + +/obj/item/box/fancy/egg_box/update_icon_state() + icon_state = get_world_inventory_state() + if(storage?.opened) + icon_state = "[icon_state]_open" + +/obj/item/box/fancy/egg_box/add_contents_overlays() + return storage?.opened && ..() + +/obj/item/box/fancy/egg_box/adjust_contents_overlay(var/overlay_index, var/image/overlay) + if(overlay) + overlay.pixel_x = (overlay_index % 6) * 4 + if(overlay_index >= 6) + overlay.pixel_y = 3 + return overlay + +/obj/item/box/fancy/egg_box/WillContain() + return list(/obj/item/food/egg = 12) + +// Subtypes below. +/obj/item/box/fancy/egg_box/assorted/WillContain() + return list( + /obj/item/food/egg = 1, + /obj/item/food/egg/blue = 1, + /obj/item/food/egg/green = 1, + /obj/item/food/egg/mime = 1, + /obj/item/food/egg/orange = 1, + /obj/item/food/egg/purple = 1, + /obj/item/food/egg/rainbow = 1, + /obj/item/food/egg/red = 1, + /obj/item/food/egg/yellow = 1, + /obj/item/food/boiledegg = 1, + /obj/item/food/egg/lizard = 1 + ) + +/obj/item/box/fancy/egg_box/empty/WillContain() + return diff --git a/code/game/objects/items/weapons/storage/fancy/vials.dm b/code/game/objects/items/weapons/storage/fancy/vials.dm new file mode 100644 index 000000000000..de59950c7674 --- /dev/null +++ b/code/game/objects/items/weapons/storage/fancy/vials.dm @@ -0,0 +1,51 @@ +/* + * Vial Box + */ +/obj/item/box/fancy/vials + icon = 'icons/obj/vialbox.dmi' + icon_state = "vialbox" + name = "vial storage box" + w_class = ITEM_SIZE_NORMAL + material = /decl/material/solid/organic/plastic + key_type = /obj/item/chems/glass/beaker/vial + storage = /datum/storage/box/vials + +/obj/item/box/fancy/vials/WillContain() + return list(/obj/item/chems/glass/beaker/vial = 12) + +/obj/item/box/fancy/vials/on_update_icon() + . = ..() + var/key_count = count_by_type(contents, key_type) + icon_state = "[initial(icon_state)][floor(key_count/2)]" + +/* + * Not actually a "fancy" storage... + */ +/obj/item/lockbox/vials + name = "secure vial storage box" + desc = "A locked box for keeping things away from children." + icon = 'icons/obj/vialbox.dmi' + icon_state = "vialbox0" + item_state = "syringe_kit" + w_class = ITEM_SIZE_NORMAL + req_access = list(access_virology) + material = /decl/material/solid/metal/stainlesssteel + +/obj/item/lockbox/vials/Initialize() + . = ..() + update_icon() + +/obj/item/lockbox/vials/on_update_icon() + . = ..() + var/total_contents = count_by_type(contents, /obj/item/chems/glass/beaker/vial) + icon_state = "vialbox[floor(total_contents/2)]" + if (!broken) + add_overlay("led[locked]") + if(locked) + add_overlay("cover") + else + add_overlay("ledb") + +/obj/item/lockbox/vials/attackby(obj/item/used_item, mob/user) + . = ..() + update_icon() \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index ac9de9fd7495..bf6f8315b597 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -7,140 +7,137 @@ /* * First Aid Kits */ -/obj/item/storage/firstaid +/obj/item/firstaid name = "first-aid kit" desc = "It's an emergency medical kit for those serious boo-boos." icon = 'icons/obj/items/storage/firstaid.dmi' icon_state = "firstaid" throw_speed = 2 throw_range = 8 - max_w_class = ITEM_SIZE_SMALL - max_storage_space = DEFAULT_BOX_STORAGE - use_sound = 'sound/effects/storage/box.ogg' + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/organic/plastic + storage = /datum/storage/firstaid -/obj/item/storage/firstaid/empty +/obj/item/firstaid/empty icon_state = "firstaid" name = "First-Aid (empty)" -/obj/item/storage/firstaid/regular +/obj/item/firstaid/regular icon_state = "firstaid" - startswith = list( - /obj/item/stack/medical/bruise_pack = 2, +/obj/item/firstaid/regular/WillContain() + return list( + /obj/item/stack/medical/bandage = 2, /obj/item/stack/medical/ointment = 2, - /obj/item/storage/pill_bottle/antibiotics, - /obj/item/storage/pill_bottle/painkillers, + /obj/item/pill_bottle/antibiotics, + /obj/item/pill_bottle/painkillers, /obj/item/stack/medical/splint ) -/obj/item/storage/firstaid/trauma +/obj/item/firstaid/trauma name = "trauma first-aid kit" desc = "It's an emergency medical kit for when people brought ballistic weapons to a laser fight." icon_state = "radfirstaid" item_state = "firstaid-ointment" - startswith = list( - /obj/item/storage/med_pouch/trauma = 4 - ) +/obj/item/firstaid/trauma/WillContain() + return list(/obj/item/med_pouch/trauma = 4) -/obj/item/storage/firstaid/trauma/Initialize() +/obj/item/firstaid/trauma/Initialize(ml, material_key) . = ..() icon_state = pick("radfirstaid", "radfirstaid2", "radfirstaid3") -/obj/item/storage/firstaid/fire +/obj/item/firstaid/fire name = "fire first-aid kit" desc = "It's an emergency medical kit for when the toxins lab -spontaneously- burns down." icon_state = "ointment" item_state = "firstaid-ointment" - startswith = list( - /obj/item/storage/med_pouch/burn = 4 - ) +/obj/item/firstaid/fire/WillContain() + return list(/obj/item/med_pouch/burn = 4) -/obj/item/storage/firstaid/fire/Initialize() +/obj/item/firstaid/fire/Initialize(ml, material_key) . = ..() icon_state = pick("ointment","firefirstaid") -/obj/item/storage/firstaid/toxin +/obj/item/firstaid/toxin name = "toxin first aid" desc = "Used to treat when you have a high amount of toxins in your body." icon_state = "antitoxin" item_state = "firstaid-toxin" - startswith = list( - /obj/item/storage/med_pouch/toxin = 4 - ) +/obj/item/firstaid/toxin/WillContain() + return list(/obj/item/med_pouch/toxin = 4) -/obj/item/storage/firstaid/toxin/Initialize() +/obj/item/firstaid/toxin/Initialize(ml, material_key) . = ..() icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") -/obj/item/storage/firstaid/o2 +/obj/item/firstaid/o2 name = "oxygen deprivation first aid" desc = "A box full of oxygen goodies." icon_state = "o2" item_state = "firstaid-o2" - startswith = list( - /obj/item/storage/med_pouch/oxyloss = 4 - ) +/obj/item/firstaid/o2/WillContain() + return list(/obj/item/med_pouch/oxyloss = 4) -/obj/item/storage/firstaid/adv +/obj/item/firstaid/adv name = "advanced first-aid kit" desc = "Contains advanced medical treatments." icon_state = "purplefirstaid" item_state = "firstaid-advanced" - startswith = list( - /obj/item/storage/pill_bottle/assorted, - /obj/item/stack/medical/advanced/bruise_pack = 3, - /obj/item/stack/medical/advanced/ointment = 2, +/obj/item/firstaid/adv/WillContain() + return list( + /obj/item/pill_bottle/assorted, + /obj/item/stack/medical/bandage/advanced = 3, + /obj/item/stack/medical/ointment/advanced = 2, /obj/item/stack/medical/splint ) -/obj/item/storage/firstaid/combat +/obj/item/firstaid/combat name = "combat medical kit" desc = "Contains advanced medical treatments." icon_state = "bezerk" item_state = "firstaid-advanced" - startswith = list( - /obj/item/storage/pill_bottle/brute_meds, - /obj/item/storage/pill_bottle/burn_meds, - /obj/item/storage/pill_bottle/oxygen, - /obj/item/storage/pill_bottle/antitoxins, - /obj/item/storage/pill_bottle/painkillers, - /obj/item/storage/pill_bottle/antibiotics, +/obj/item/firstaid/combat/WillContain() + return list( + /obj/item/pill_bottle/brute_meds, + /obj/item/pill_bottle/burn_meds, + /obj/item/pill_bottle/oxygen, + /obj/item/pill_bottle/antitoxins, + /obj/item/pill_bottle/strong_painkillers, + /obj/item/pill_bottle/antibiotics, /obj/item/stack/medical/splint, ) -/obj/item/storage/firstaid/stab +/obj/item/firstaid/stab name = "stabilisation first aid" desc = "Stocked with medical pouches." icon_state = "stabfirstaid" item_state = "firstaid-advanced" - startswith = list( - /obj/item/storage/med_pouch/trauma, - /obj/item/storage/med_pouch/burn, - /obj/item/storage/med_pouch/oxyloss, - /obj/item/storage/med_pouch/toxin, - /obj/item/storage/med_pouch/radiation, +/obj/item/firstaid/stab/WillContain() + return list( + /obj/item/med_pouch/trauma, + /obj/item/med_pouch/burn, + /obj/item/med_pouch/oxyloss, + /obj/item/med_pouch/toxin, + /obj/item/med_pouch/radiation, ) -/obj/item/storage/firstaid/surgery +/obj/item/firstaid/surgery name = "surgery kit" desc = "Contains tools for surgery. Has precise foam fitting for safe transport and automatically sterilizes the content between uses." icon = 'icons/obj/items/storage/surgerykit.dmi' icon_state = "surgerykit" item_state = "firstaid-surgery" + storage = /datum/storage/firstaid/surgery - storage_slots = 14 - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = null - use_sound = 'sound/effects/storage/briefcase.ogg' - - can_hold = list( +/obj/item/firstaid/surgery/WillContain() + return list( /obj/item/bonesetter, /obj/item/cautery, /obj/item/circular_saw, @@ -150,19 +147,27 @@ /obj/item/surgicaldrill, /obj/item/bonegel, /obj/item/sutures, - /obj/item/stack/medical/advanced/bruise_pack, - /obj/item/stack/nanopaste - ) - - startswith = list( - /obj/item/bonesetter, - /obj/item/cautery, - /obj/item/circular_saw, - /obj/item/hemostat, - /obj/item/retractor, - /obj/item/scalpel, - /obj/item/surgicaldrill, - /obj/item/bonegel, - /obj/item/sutures, - /obj/item/stack/medical/advanced/bruise_pack, - ) + /obj/item/stack/medical/bandage/advanced, + ) + +/obj/item/firstaid/surgery/ghetto // Mostly just for debugging. + name = "shady surgery kit" + storage = /datum/storage/firstaid/surgery/ghetto + +/obj/item/firstaid/surgery/ghetto/WillContain() + return list( + /obj/item/screwdriver, + /obj/item/wrench, + /obj/item/tool/axe/hatchet, + /obj/item/utensil/fork, + /obj/item/shard, + /obj/item/flame/fuelled/lighter, + /obj/item/stack/cable_coil + ) + +/obj/item/firstaid/clotting + name = "clotting kit" + desc = "Contains chemicals to stop bleeding." + +/obj/item/firstaid/clotting/WillContain() + return list(/obj/item/chems/hypospray/autoinjector/clotting = 8) diff --git a/code/game/objects/items/weapons/storage/internal.dm b/code/game/objects/items/weapons/storage/internal.dm deleted file mode 100644 index d3891f1f4744..000000000000 --- a/code/game/objects/items/weapons/storage/internal.dm +++ /dev/null @@ -1,96 +0,0 @@ -//A storage item intended to be used by other items to provide storage functionality. -//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow. -/obj/item/storage/internal - var/obj/item/master_item - -/obj/item/storage/internal/Initialize() - . = ..() - master_item = loc - name = master_item.name - verbs -= /obj/item/verb/verb_pickup //make sure this is never picked up. - -/obj/item/storage/internal/Destroy() - master_item = null - . = ..() - -/obj/item/storage/internal/attack_hand() - return //make sure this is never picked up - -/obj/item/storage/internal/mob_can_equip() - return 0 //make sure this is never picked up - -//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items. -//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open() -//However they are helpful for allowing the master item to pretend it is a storage item itself. -//If you are using these you will probably want to override attackby() as well. -//See /obj/item/clothing/suit/storage for an example. - -//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour. -//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of -//doing it without the ability to call another proc's parent, really. -/obj/item/storage/internal/proc/handle_mousedrop(mob/user, obj/over_object) - if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist - - if(over_object == user && Adjacent(user)) // this must come before the screen objects only block - src.open(user) - return 0 - - if (!( istype(over_object, /obj/screen) )) - return 1 - - //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away. - //there's got to be a better way of doing this... - if (!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user)) - return 0 - - //TODO make this less terrible - if (!( user.restrained() ) && !( user.stat )) - switch(over_object.name) - if(BP_R_HAND) - if(user.unEquip(master_item)) - user.put_in_r_hand(master_item) - if(BP_L_HAND) - if(user.unEquip(master_item)) - user.put_in_l_hand(master_item) - master_item.add_fingerprint(user) - return 0 - return 0 - -//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour. -//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise. -//It's strange, but no other way of doing it without the ability to call another proc's parent, really. -/obj/item/storage/internal/proc/handle_attack_hand(mob/user) - - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket. - H.put_in_hands(master_item) - H.l_store = null - return 0 - if(H.r_store == master_item && !H.get_active_hand()) - H.put_in_hands(master_item) - H.r_store = null - return 0 - - src.add_fingerprint(user) - if (master_item.loc == user) - src.open(user) - return 0 - - for(var/mob/M in range(1, master_item.loc)) - if (M.s_active == src) - src.close(M) - return 1 - -/obj/item/storage/internal/Adjacent(var/atom/neighbor) - return master_item.Adjacent(neighbor) - -// Used by webbings, coat pockets, etc -/obj/item/storage/internal/pockets/Initialize(mapload, var/slots, var/slot_size) - storage_slots = slots - max_w_class = slot_size - . = ..() - -/obj/item/storage/internal/pouch/Initialize(mapload, var/storage_space) - max_storage_space = storage_space - . = ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/laundry_basket.dm b/code/game/objects/items/weapons/storage/laundry_basket.dm index 996a354d2e5f..deb912d9ba69 100644 --- a/code/game/objects/items/weapons/storage/laundry_basket.dm +++ b/code/game/objects/items/weapons/storage/laundry_basket.dm @@ -1,88 +1,40 @@ -// ----------------------------- -// Laundry Basket -// ----------------------------- -// An item designed for hauling the belongings of a character. -// So this cannot be abused for other uses, we make it two-handed and inable to have its storage looked into. -/obj/item/storage/laundry_basket +/obj/item/laundry_basket name = "laundry basket" - icon = 'icons/obj/janitor.dmi' - icon_state = "laundry-empty" - item_state = "laundry" + icon = 'icons/obj/items/storage/laundry.dmi' + icon_state = ICON_STATE_WORLD desc = "The peak of thousands of years of laundry evolution." - w_class = ITEM_SIZE_GARGANTUAN - max_w_class = ITEM_SIZE_HUGE - max_storage_space = DEFAULT_BACKPACK_STORAGE //20 for clothes + a bit of additional space for non-clothing items that were worn on body - storage_slots = 14 - use_to_pickup = 1 - allow_quick_empty = 1 - allow_quick_gather = 1 - collection_mode = 1 - var/linked - - -/obj/item/storage/laundry_basket/attack_hand(mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/temp = H.get_organ(BP_R_HAND) - if (user.hand) - temp = H.get_organ(BP_L_HAND) - if(!temp) - to_chat(user, "You need two hands to pick this up!") - return - - if(user.get_inactive_hand()) - to_chat(user, "You need your other hand to be empty") - return + storage = /datum/storage/laundry_basket + material = /decl/material/solid/organic/plastic + obj_flags = OBJ_FLAG_HOLLOW + paint_color = COLOR_NAVY_BLUE + +/obj/item/laundry_basket/attack_self(mob/user) + var/turf/dump_loc = get_turf(user) + if(length(contents) && dump_loc) + to_chat(user, SPAN_NOTICE("You dump \the [src]'s contents onto \the [dump_loc].")) + for(var/atom/movable/thing as anything in get_contained_external_atoms()) + thing.dropInto(dump_loc) + return TRUE return ..() -/obj/item/storage/laundry_basket/attack_self(mob/user) - var/turf/T = get_turf(user) - to_chat(user, "You dump the [src]'s contents onto \the [T].") - return ..() - -/obj/item/storage/laundry_basket/pickup(mob/user) - var/obj/item/storage/laundry_basket/offhand/O = new(user) - O.SetName("[name] - second hand") - O.desc = "Your second grip on the [name]." - O.linked = src - user.put_in_inactive_hand(O) - linked = O - return - -/obj/item/storage/laundry_basket/on_update_icon() - if(contents.len) - icon_state = "laundry-full" - else - icon_state = "laundry-empty" - return - - -/obj/item/storage/laundry_basket/MouseDrop(obj/over_object) - if(over_object == usr) - return - else - return ..() - -/obj/item/storage/laundry_basket/dropped(mob/user) - qdel(linked) - return ..() - -/obj/item/storage/laundry_basket/show_to(mob/user) - return - -/obj/item/storage/laundry_basket/open(mob/user) - - -//Offhand -/obj/item/storage/laundry_basket/offhand - icon = 'icons/mob/offhand.dmi' - icon_state = "offhand" - name = "second hand" - use_to_pickup = 0 - -/obj/item/storage/laundry_basket/offhand/dropped(mob/user) - ..() - user.drop_from_inventory(linked) - return - +/obj/item/laundry_basket/Entered(atom/movable/atom, atom/old_loc) + . = ..() + update_clothing_icon() + +/obj/item/laundry_basket/Exited(atom/movable/atom, atom/old_loc) + . = ..() + update_clothing_icon() + +/obj/item/laundry_basket/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + cut_overlays() + if(length(contents)) + add_overlay(overlay_image(icon, "[icon_state]-full", COLOR_WHITE, RESET_COLOR)) + +/obj/item/laundry_basket/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing, skip_adjustment) + var/image/res = ..() + if(length(contents)) + res.overlays += overlay_image(res.icon, "[res.icon_state]-full", COLOR_WHITE, RESET_COLOR) + return res diff --git a/code/game/objects/items/weapons/storage/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm index 19d9e3427fa5..341efc0954d0 100644 --- a/code/game/objects/items/weapons/storage/lockbox.dm +++ b/code/game/objects/items/weapons/storage/lockbox.dm @@ -1,15 +1,16 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 -/obj/item/storage/lockbox +/obj/item/lockbox name = "lockbox" desc = "A locked box." icon = 'icons/obj/items/storage/lockbox.dmi' icon_state = "lockbox+l" item_state = "syringe_kit" w_class = ITEM_SIZE_HUGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = 32 //The sum of the w_classes of all the items in this storage item. + storage = /datum/storage/lockbox req_access = list(access_armory) + material = /decl/material/solid/metal/stainlesssteel + var/locked = 1 var/broken = 0 var/icon_locked = "lockbox+l" @@ -17,46 +18,36 @@ var/icon_broken = "lockbox+b" - attackby(obj/item/W as obj, mob/user as mob) - if (istype(W, /obj/item/card/id)) - if(src.broken) - to_chat(user, "It appears to be broken.") - return - if(src.allowed(user)) - src.locked = !( src.locked ) - if(src.locked) - src.icon_state = src.icon_locked - to_chat(user, "You lock \the [src]!") - close_all() - return - else - src.icon_state = src.icon_closed - to_chat(user, "You unlock \the [src]!") - return +/obj/item/lockbox/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/card/id)) + if(src.broken) + to_chat(user, "It appears to be broken.") + return TRUE + if(src.allowed(user)) + src.locked = !( src.locked ) + if(src.locked) + src.icon_state = src.icon_locked + to_chat(user, "You lock \the [src]!") + storage?.close_all() else - to_chat(user, "Access Denied") - else if(istype(W, /obj/item/energy_blade/blade)) - if(emag_act(INFINITY, user, W, "The locker has been sliced open by [user] with an energy blade!", "You hear metal being sliced and sparks flying.")) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src.loc) - spark_system.start() - playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) - playsound(src.loc, "sparks", 50, 1) - if(!locked) - ..() - else - to_chat(user, "It's locked!") - return - - - show_to(mob/user as mob) - if(locked) - to_chat(user, "It's locked!") + src.icon_state = src.icon_closed + to_chat(user, "You unlock \the [src]!") else - ..() - return + to_chat(user, "Access Denied") + return TRUE + else if(istype(used_item, /obj/item/energy_blade)) + var/obj/item/energy_blade/blade = used_item + if(blade.is_special_cutting_tool() && emag_act(INFINITY, user, used_item, "The locker has been sliced open by [user] with an energy blade!", "You hear metal being sliced and sparks flying.")) + spark_at(src.loc, amount=5) + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + return TRUE + if(!locked) + return ..() + else + to_chat(user, "It's locked!") + return TRUE -/obj/item/storage/lockbox/emag_act(var/remaining_charges, var/mob/user, var/emag_source, var/visual_feedback = "", var/audible_feedback = "") +/obj/item/lockbox/emag_act(var/remaining_charges, var/mob/user, var/emag_source, var/visual_feedback = "", var/audible_feedback = "") if(!broken) if(visual_feedback) visual_feedback = "[visual_feedback]" @@ -74,22 +65,20 @@ visible_message(visual_feedback, audible_feedback) return 1 -/obj/item/storage/lockbox/loyalty +/obj/item/lockbox/loyalty name = "lockbox of loyalty implants" req_access = list(access_security) -/obj/item/storage/lockbox/loyalty/Initialize() - . = ..() - new /obj/item/implantcase/loyalty(src) - new /obj/item/implantcase/loyalty(src) - new /obj/item/implantcase/loyalty(src) - new /obj/item/implanter/loyalty(src) +/obj/item/lockbox/loyalty/WillContain() + return list( + /obj/item/implantcase/loyalty = 3, + /obj/item/implanter/loyalty + ) -/obj/item/storage/lockbox/clusterbang +/obj/item/lockbox/clusterbang name = "lockbox of clusterbangs" desc = "You have a bad feeling about opening this." req_access = list(access_security) -/obj/item/storage/lockbox/clusterbang/Initialize() - . = ..() - new /obj/item/grenade/flashbang/clusterbang(src) +/obj/item/lockbox/clusterbang/WillContain() + return list(/obj/item/grenade/flashbang/clusterbang) diff --git a/code/game/objects/items/weapons/storage/lunchbox.dm b/code/game/objects/items/weapons/storage/lunchbox.dm index de17a92e1e7d..f05761ec870a 100644 --- a/code/game/objects/items/weapons/storage/lunchbox.dm +++ b/code/game/objects/items/weapons/storage/lunchbox.dm @@ -1,84 +1,66 @@ -/obj/item/storage/lunchbox - max_storage_space = 8 //slightly smaller than a toolbox +/obj/item/lunchbox name = "rainbow lunchbox" - icon = 'icons/obj/items/storage/lunchbox.dmi' - icon_state = "lunchbox_rainbow" - item_state = "toolbox_pink" desc = "A little lunchbox. This one is the colors of the rainbow!" + icon = 'icons/obj/items/storage/lunchboxes/lunchbox_rainbow.dmi' + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_NORMAL - max_w_class = ITEM_SIZE_SMALL - var/filled = FALSE - attack_verb = list("lunched") - -/obj/item/storage/lunchbox/Initialize() - . = ..() - if(filled) - var/list/lunches = lunchables_lunches() - var/lunch = lunches[pick(lunches)] - new lunch(src) - - var/list/snacks = lunchables_snacks() - var/snack = snacks[pick(snacks)] - new snack(src) - - var/list/drinks = lunchables_drinks() - var/drink = drinks[pick(drinks)] - new drink(src) - -/obj/item/storage/lunchbox/filled + attack_verb = "lunched" + material = /decl/material/solid/organic/plastic + storage = /datum/storage/lunchbox + var/tmp/filled = FALSE + +/obj/item/lunchbox/WillContain() + if(!filled) + return + //#TODO: Those procs and that code is so overcomplicated for some reasons. + var/list/lunches = lunchables_lunches() + var/list/snacks = lunchables_snacks() + var/list/drinks = lunchables_drinks() + return list( + lunches[pick(lunches)], + snacks[pick(snacks)], + drinks[pick(drinks)], + ) + +/obj/item/lunchbox/filled filled = TRUE -/obj/item/storage/lunchbox/heart +/obj/item/lunchbox/heart name = "heart lunchbox" - icon_state = "lunchbox_lovelyhearts" - item_state = "toolbox_pink" + icon = 'icons/obj/items/storage/lunchboxes/lunchbox_heart.dmi' desc = "A little lunchbox. This one has cute little hearts on it!" -/obj/item/storage/lunchbox/heart/filled +/obj/item/lunchbox/heart/filled filled = TRUE -/obj/item/storage/lunchbox/cat +/obj/item/lunchbox/cat name = "cat lunchbox" - icon_state = "lunchbox_sciencecatshow" - item_state = "toolbox_green" + icon = 'icons/obj/items/storage/lunchboxes/lunchbox_cat.dmi' desc = "A little lunchbox. This one has a cute little science cat from a popular show on it!" -/obj/item/storage/lunchbox/cat/filled +/obj/item/lunchbox/cat/filled filled = TRUE -/obj/item/storage/lunchbox/mars +/obj/item/lunchbox/mars name = "\improper Mariner University lunchbox" - icon_state = "lunchbox_marsuniversity" - item_state = "toolbox_red" + icon = 'icons/obj/items/storage/lunchboxes/lunchbox_mars.dmi' desc = "A little lunchbox. This one is branded with the Mariner university logo!" -/obj/item/storage/lunchbox/mars/filled +/obj/item/lunchbox/mars/filled filled = TRUE -/obj/item/storage/lunchbox/cti +/obj/item/lunchbox/cti name = "\improper CTI lunchbox" - icon_state = "lunchbox_cti" - item_state = "toolbox_blue" + icon = 'icons/obj/items/storage/lunchboxes/lunchbox_cti.dmi' desc = "A little lunchbox. This one is branded with the CTI logo!" -/obj/item/storage/lunchbox/cti/filled +/obj/item/lunchbox/cti/filled filled = TRUE -/obj/item/storage/lunchbox/syndicate +/obj/item/lunchbox/syndicate name = "black and red lunchbox" - icon_state = "lunchbox_syndie" - item_state = "toolbox_syndi" + icon = 'icons/obj/items/storage/lunchboxes/lunchbox_evil.dmi' desc = "A little lunchbox. This one is a sleek black and red, made of a durable steel!" -/obj/item/storage/lunchbox/syndicate/filled +/obj/item/lunchbox/syndicate/filled filled = TRUE - -/obj/item/storage/lunchbox/TCC - name = "\improper GCC lunchbox" - icon_state = "lunchbox_tcc" - item_state = "toolbox_syndi" - desc = "A little lunchbox. This one is branded with the flag of the Gilgamesh Colonial Confederation!" - -/obj/item/storage/lunchbox/syndicate/filled - filled = TRUE - diff --git a/code/game/objects/items/weapons/storage/matches.dm b/code/game/objects/items/weapons/storage/matches.dm new file mode 100644 index 000000000000..fe883451bf5a --- /dev/null +++ b/code/game/objects/items/weapons/storage/matches.dm @@ -0,0 +1,25 @@ +/obj/item/box/matches + name = "matchbox" + desc = "A small box of 'Space-Proof' premium matches." + icon = 'icons/obj/items/storage/matchbox.dmi' + icon_state = "matchbox" + item_state = "zippo" + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + storage = /datum/storage/box/matches + +/obj/item/box/matches/WillContain() + return list(/obj/item/flame/match = 10) + +/obj/item/box/matches/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/flame/match)) + var/obj/item/flame/match/match = used_item + if(match.light(null, no_message = TRUE)) + playsound(src.loc, 'sound/items/match.ogg', 60, 1, -4) + user.visible_message( + SPAN_NOTICE("[user] strikes [used_item] on \the [src]."), + SPAN_NOTICE("You strike [used_item] on \the [src].") + ) + used_item.update_icon() + return TRUE + return ..() diff --git a/code/game/objects/items/weapons/storage/med_pouch.dm b/code/game/objects/items/weapons/storage/med_pouch.dm index 3ad44861bd0e..1d7cc0f7c27b 100644 --- a/code/game/objects/items/weapons/storage/med_pouch.dm +++ b/code/game/objects/items/weapons/storage/med_pouch.dm @@ -2,19 +2,16 @@ Single Use Emergency Pouches */ -/obj/item/storage/med_pouch +/obj/item/med_pouch name = "emergency medical pouch" desc = "For use in emergency situations only." icon = 'icons/obj/med_pouch.dmi' - storage_slots = 7 - w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_SMALL icon_state = "pack0" - opened = FALSE - open_sound = 'sound/effects/rip1.ogg' + storage = /datum/storage/med_pouch + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic var/injury_type = "generic" - var/global/image/cross_overlay - + var/static/image/cross_overlay var/instructions = {" 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ \t2) Carefully remove all items from the pouch and discard the pouch.\n\ @@ -26,55 +23,43 @@ Single Use Emergency Pouches 8) Stay in place once they respond.\ "} -/obj/item/storage/med_pouch/Initialize() +/obj/item/med_pouch/Initialize(ml, material_key) . = ..() - name = "emergency [injury_type] pouch" - make_exact_fit() - for(var/obj/item/chems/pill/P in contents) - P.color = color - for(var/obj/item/chems/hypospray/autoinjector/A in contents) - A.band_color = color - A.update_icon() + SetName("emergency [injury_type] pouch") + if(length(contents) && storage) + storage.make_exact_fit() + for(var/obj/item/chems/C in contents) + C.set_detail_color(color) -/obj/item/storage/med_pouch/on_update_icon() - overlays.Cut() +/obj/item/med_pouch/on_update_icon() + . = ..() if(!cross_overlay) - cross_overlay = image(icon, "cross") - cross_overlay.appearance_flags = RESET_COLOR - overlays += cross_overlay - icon_state = "pack[opened]" + cross_overlay = overlay_image(icon, "cross", flags = RESET_COLOR) + add_overlay(cross_overlay) + icon_state = "pack[!!(storage?.opened)]" -/obj/item/storage/med_pouch/examine(mob/user) +/obj/item/med_pouch/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "Please read instructions before use.") + . += "Please read instructions before use." -/obj/item/storage/med_pouch/CanUseTopic() +/obj/item/med_pouch/CanUseTopic() return STATUS_INTERACTIVE -/obj/item/storage/med_pouch/OnTopic(var/user, var/list/href_list) +/obj/item/med_pouch/OnTopic(var/user, var/list/href_list) if(href_list["show_info"]) to_chat(user, instructions) return TOPIC_HANDLED -/obj/item/storage/med_pouch/attack_self(mob/user) - open(user) +/obj/item/med_pouch/attack_self(mob/user) + if(storage && !storage.opened) + storage.open(user) + return TRUE + return ..() -/obj/item/storage/med_pouch/open(mob/user) - if(!opened) - user.visible_message("\The [user] tears open [src], breaking the vacuum seal!", "You tear open [src], breaking the vacuum seal!") - . = ..() - -/obj/item/storage/med_pouch/trauma +/obj/item/med_pouch/trauma name = "trauma pouch" injury_type = "trauma" color = COLOR_RED - - startswith = list( - /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer, - /obj/item/chems/pill/pouch_pill/stabilizer, - /obj/item/chems/pill/pouch_pill/painkillers, - /obj/item/stack/medical/bruise_pack = 2, - ) instructions = {" 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ \t2) Carefully remove all items from the pouch and discard the pouch.\n\ @@ -85,18 +70,19 @@ Single Use Emergency Pouches 7) Stay in place once they respond.\ "} -/obj/item/storage/med_pouch/burn +/obj/item/med_pouch/trauma/WillContain() + return list( + /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer, + /obj/item/chems/hypospray/autoinjector/pouch_auto/painkillers, + /obj/item/chems/pill/pouch_pill/stabilizer, + /obj/item/chems/pill/pouch_pill/brute_meds, + /obj/item/stack/medical/bandage = 2, + ) + +/obj/item/med_pouch/burn name = "burn pouch" injury_type = "burn" color = COLOR_SEDONA - - startswith = list( - /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer, - /obj/item/chems/hypospray/autoinjector/pouch_auto/painkillers, - /obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline, - /obj/item/chems/pill/pouch_pill/painkillers, - /obj/item/stack/medical/ointment = 2, - ) instructions = {" 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ \t2) Carefully remove all items from the pouch and discard the pouch.\n\ @@ -107,18 +93,19 @@ Single Use Emergency Pouches 7) Stay in place once they respond.\ "} -/obj/item/storage/med_pouch/oxyloss +/obj/item/med_pouch/burn/WillContain() + return list( + /obj/item/chems/hypospray/autoinjector/pouch_auto/nanoblood, + /obj/item/chems/hypospray/autoinjector/pouch_auto/painkillers, + /obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline, + /obj/item/chems/pill/pouch_pill/burn_meds, + /obj/item/stack/medical/ointment = 2, + ) + +/obj/item/med_pouch/oxyloss name = "low oxygen pouch" injury_type = "low oxygen" color = COLOR_BLUE - - startswith = list( - /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer, - /obj/item/chems/hypospray/autoinjector/pouch_auto/oxy_meds, - /obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline, - /obj/item/chems/pill/pouch_pill/stabilizer, - /obj/item/chems/pill/pouch_pill/oxy_meds - ) instructions = {" 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ \t2) Carefully remove all items from the pouch and discard the pouch.\n\ @@ -130,15 +117,19 @@ Single Use Emergency Pouches 8) Stay in place once they respond.\ "} -/obj/item/storage/med_pouch/toxin +/obj/item/med_pouch/oxyloss/WillContain() + return list( + /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer, + /obj/item/chems/inhaler/pouch_auto/oxy_meds, + /obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline, + /obj/item/chems/pill/pouch_pill/stabilizer, + /obj/item/chems/pill/pouch_pill/oxy_meds + ) + +/obj/item/med_pouch/toxin name = "toxin pouch" injury_type = "toxin" color = COLOR_GREEN - - startswith = list( - /obj/item/chems/hypospray/autoinjector/pouch_auto/antitoxins, - /obj/item/chems/pill/pouch_pill/antitoxins - ) instructions = {" 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ \t2) Carefully remove all items from the pouch and discard the pouch.\n\ @@ -148,15 +139,16 @@ Single Use Emergency Pouches 6) Stay in place once they respond.\ "} -/obj/item/storage/med_pouch/radiation +/obj/item/med_pouch/toxin/WillContain() + return list( + /obj/item/chems/hypospray/autoinjector/pouch_auto/antitoxins, + /obj/item/chems/pill/pouch_pill/antitoxins + ) + +/obj/item/med_pouch/radiation name = "radiation pouch" injury_type = "radiation" color = COLOR_AMBER - - startswith = list( - /obj/item/chems/hypospray/autoinjector/antirad, - /obj/item/chems/pill/pouch_pill/antitoxins - ) instructions = {" 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ \t2) Carefully remove all items from the pouch and discard the pouch.\n\ @@ -166,53 +158,134 @@ Single Use Emergency Pouches 6) Stay in place once they respond.\ "} +/obj/item/med_pouch/radiation/WillContain() + return list( + /obj/item/chems/hypospray/autoinjector/antirad, + /obj/item/chems/pill/pouch_pill/antitoxins + ) + +/obj/item/med_pouch/overdose + name = "overdose treatment pouch" + injury_type = "overdose" + color = COLOR_PALE_BLUE_GRAY + instructions = {" + 1) Tear open the emergency medical pack using the easy open tab at the top.\n\ + \t2) Carefully remove all items from the pouch and discard the pouch.\n\ + \t3) Apply all autoinjectors and autoinhalers to the injured party. DO NOT give the injured party any pills, foods, or liquids.\n\ + \t5) Contact the medical team with your location.\n\ + \t6) Find a source of oxygen if possible.\n\ + \t7) Update the medical team with your new location.\n\ + 8) Stay in place once they respond.\ + "} + +/obj/item/med_pouch/overdose/WillContain() + return list( + /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer, + /obj/item/chems/inhaler/pouch_auto/oxy_meds, + /obj/item/chems/inhaler/pouch_auto/detoxifier, + /obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline + ) + +// Pills + /obj/item/chems/pill/pouch_pill - name = "emergency pill" - desc = "An emergency pill from an emergency medical pouch" - icon_state = "pill2" - var/decl/material/chem_type - var/chem_amount = 15 + name = "emergency pill" + desc = "An emergency pill from an emergency medical pouch." + icon_state = "pill2" + chem_volume = 15 + abstract_type = /obj/item/chems/pill/pouch_pill + var/_reagent_name + var/_reagent_volume -/obj/item/chems/pill/pouch_pill/stabilizer - chem_type = /decl/material/liquid/stabilizer +/obj/item/chems/pill/pouch_pill/Initialize(ml, material_key) + . = ..() + if(!istype(reagents) || !REAGENT_TOTAL_VOLUME(reagents)) + log_warning("[log_info_line(src)] was deleted for containing no reagents during init!") + return INITIALIZE_HINT_QDEL + if(isnull(_reagent_name)) + _reagent_name = reagents.get_primary_reagent_name() + _reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if(_reagent_name && _reagent_volume) + SetName("emergency [_reagent_name] pill ([_reagent_volume]u)") -/obj/item/chems/pill/pouch_pill/antitoxins - chem_type = /decl/material/liquid/antitoxins +/obj/item/chems/pill/pouch_pill/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(_reagent_name, /obj/item/chems/pill/pouch_pill) + SERIALIZE_IF_MODIFIED(_reagent_volume, /obj/item/chems/pill/pouch_pill) -/obj/item/chems/pill/pouch_pill/oxy_meds - chem_type = /decl/material/liquid/oxy_meds +/obj/item/chems/pill/pouch_pill/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() -/obj/item/chems/pill/pouch_pill/painkillers - chem_type = /decl/material/liquid/painkillers +/obj/item/chems/pill/pouch_pill/antitoxins/populate_reagents() + add_to_reagents(/decl/material/liquid/antitoxins, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +/obj/item/chems/pill/pouch_pill/oxy_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/oxy_meds, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() -/obj/item/chems/pill/pouch_pill/Initialize() +/obj/item/chems/pill/pouch_pill/painkillers/populate_reagents() + add_to_reagents(/decl/material/liquid/painkillers, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(chem_type, chem_amount) - var/decl/material/reagent = decls_repository.get_decl(chem_type) - name = "emergency [reagent.liquid_name] pill ([reagents.total_volume]u)" - color = reagents.get_color() + +/obj/item/chems/pill/pouch_pill/brute_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/brute_meds, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +/obj/item/chems/pill/pouch_pill/burn_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/burn_meds, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +// Injectors /obj/item/chems/hypospray/autoinjector/pouch_auto name = "emergency autoinjector" - desc = "An emergency autoinjector from an emergency medical pouch" + desc = "An emergency autoinjector from an emergency medical pouch." + abstract_type = /obj/item/chems/hypospray/autoinjector/pouch_auto -/obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer - name = "emergency stabilizer autoinjector" - starts_with = list(/decl/material/liquid/stabilizer = 5) +/obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, 5) + . = ..() -/obj/item/chems/hypospray/autoinjector/pouch_auto/painkillers - name = "emergency painkiller autoinjector" - starts_with = list(/decl/material/liquid/painkillers = 5) +/obj/item/chems/hypospray/autoinjector/pouch_auto/painkillers/populate_reagents() + add_to_reagents(/decl/material/liquid/painkillers, 5) + . = ..() -/obj/item/chems/hypospray/autoinjector/pouch_auto/antitoxins - name = "emergency antitoxins autoinjector" - starts_with = list(/decl/material/liquid/antitoxins = 5) +/obj/item/chems/hypospray/autoinjector/pouch_auto/antitoxins/populate_reagents() + add_to_reagents(/decl/material/liquid/antitoxins, 5) + . = ..() -/obj/item/chems/hypospray/autoinjector/pouch_auto/oxy_meds - name = "emergency oxygel autoinjector" - starts_with = list(/decl/material/liquid/oxy_meds = 5) +/obj/item/chems/hypospray/autoinjector/pouch_auto/oxy_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/oxy_meds, 5) + . = ..() /obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline - name = "emergency adrenaline autoinjector" amount_per_transfer_from_this = 8 - starts_with = list(/decl/material/liquid/adrenaline = 8) +/obj/item/chems/hypospray/autoinjector/pouch_auto/adrenaline/populate_reagents() + add_to_reagents(/decl/material/liquid/adrenaline, 8) + . = ..() + +/obj/item/chems/hypospray/autoinjector/pouch_auto/nanoblood/populate_reagents() + add_to_reagents(/decl/material/liquid/nanoblood, 5) + . = ..() + +// Inhalers + +/obj/item/chems/inhaler/pouch_auto + name = "emergency autoinhaler" + desc = "An emergency autoinhaler from an emergency medical pouch." + +/obj/item/chems/inhaler/pouch_auto/oxy_meds + name = "emergency oxygel autoinhaler" + detail_color = COLOR_CYAN + +/obj/item/chems/inhaler/pouch_auto/oxy_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/oxy_meds, 5) + +/obj/item/chems/inhaler/pouch_auto/detoxifier + name = "emergency detoxifier autoinhaler" + detail_color = COLOR_GREEN + +/obj/item/chems/inhaler/pouch_auto/detoxifier/populate_reagents() + add_to_reagents(/decl/material/liquid/detoxifier, 5) diff --git a/code/game/objects/items/weapons/storage/misc.dm b/code/game/objects/items/weapons/storage/misc.dm index c849a0ccded5..921f48977969 100644 --- a/code/game/objects/items/weapons/storage/misc.dm +++ b/code/game/objects/items/weapons/storage/misc.dm @@ -1,172 +1,178 @@ -/obj/item/storage/pill_bottle/dice //7d6 +/obj/item/pill_bottle/dice //7d6 name = "bag of dice" desc = "It's a small bag with dice inside." icon = 'icons/obj/dice.dmi' icon_state = "dicebag" + material = /decl/material/solid/organic/cloth -/obj/item/storage/pill_bottle/dice/Initialize() - . = ..() - for(var/i = 1 to 7) - new /obj/item/dice( src ) +/obj/item/pill_bottle/dice/WillContain() + return list(/obj/item/dice = 7) -/obj/item/storage/pill_bottle/dice_nerd //DnD dice +/obj/item/pill_bottle/dice_nerd //DnD dice name = "bag of gaming dice" desc = "It's a small bag with gaming dice inside." icon = 'icons/obj/dice.dmi' icon_state = "magicdicebag" -/obj/item/storage/pill_bottle/dice_nerd/Initialize() - . = ..() - new /obj/item/dice/d4( src ) - new /obj/item/dice( src ) - new /obj/item/dice/d8( src ) - new /obj/item/dice/d10( src ) - new /obj/item/dice/d12( src ) - new /obj/item/dice/d20( src ) - new /obj/item/dice/d100( src ) - - -/obj/item/storage/box/donut - icon = 'icons/obj/food.dmi' - icon_state = "donutbox" - name = "donut box" - can_hold = list(/obj/item/chems/food/snacks/donut) - foldable = /obj/item/stack/material/cardboard - - startswith = list(/obj/item/chems/food/snacks/donut/normal = 6) - -/obj/item/storage/box/donut/on_update_icon() - overlays.Cut() - var/i = 0 - for(var/obj/item/chems/food/snacks/donut/D in contents) - overlays += image('icons/obj/food.dmi', "[i][D.overlay_state]") - i++ - -/obj/item/storage/box/donut/empty - startswith = null +/obj/item/pill_bottle/dice_nerd/WillContain() + return list( + /obj/item/dice/d4, + /obj/item/dice, + /obj/item/dice/d8, + /obj/item/dice/d10, + /obj/item/dice/d12, + /obj/item/dice/d20, + /obj/item/dice/d100, + ) //misc tobacco nonsense -/obj/item/storage/cigpaper +/obj/item/cigpaper name = "\improper Gen. Eric cigarette paper" desc = "A ubiquitous brand of cigarette paper, allegedly endorsed by 24th century war hero General Eric Osmundsun for rolling your own cigarettes. Osmundsun died in a freak kayak accident. As it ate him alive during his last campaign. It was pretty freaky." icon = 'icons/obj/cigarettes.dmi' icon_state = "cigpaperbook" item_state = "cigpacket" w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - max_storage_space = 10 - throwforce = 2 - slot_flags = SLOT_BELT - startswith = list(/obj/item/paper/cig = 10) + storage = /datum/storage/cigpapers + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + +/obj/item/cigpaper/WillContain() + return list(/obj/item/paper/cig = 10) -/obj/item/storage/cigpaper/fancy +/obj/item/cigpaper/fancy name = "\improper Trident cigarette paper" desc = "A fancy brand of Trident cigarette paper, for rolling your own cigarettes. Like a person who appreciates the finer things in life." - icon = 'icons/obj/cigarettes.dmi' icon_state = "fancycigpaperbook" - startswith = list(/obj/item/paper/cig/fancy = 10) -/obj/item/storage/cigpaper/filters +/obj/item/cigpaper/fancy/WillContain() + return list(/obj/item/paper/cig/fancy = 10) + +/obj/item/cigpaper/filters name = "box of cigarette filters" desc = "A box of generic cigarette filters for those who rolls their own but prefers others to inhale the fumes. Not endorsed by Late General Osmundsun." - icon = 'icons/obj/cigarettes.dmi' icon_state = "filterbin" - startswith = list(/obj/item/paper/cig/filter = 10) -/obj/item/storage/chewables +/obj/item/cigpaper/filters/WillContain() + return list(/obj/item/cigarette_filter = 10) + +/obj/item/chewables name = "box of chewing wads master" desc = "A generic brands of Waffle Co Wads, unflavored chews. Why do these exist?" icon = 'icons/obj/cigarettes.dmi' icon_state = "placeholder" item_state = "cigpacket" w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - max_storage_space = 6 - throwforce = 2 - slot_flags = SLOT_BELT - startswith = list(/obj/item/clothing/mask/chewable/tobacco = 6) - make_exact_fit() + storage = /datum/storage/chewables + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/metal/tin + +/obj/item/chewables/WillContain() + return list(/obj/item/clothing/mask/chewable/tobacco = 6) //loose leaf -/obj/item/storage/chewables/rollable +/obj/item/chewables/rollable name = "bag of tobacco" - max_storage_space = 8 + storage = /datum/storage/chewables/rollable -/obj/item/storage/chewables/rollable/bad +/obj/item/chewables/rollable/bad name = "bag of Men at Arms tobacco" desc = "A bag of coarse gritty tobacco marketed towards leather-necks." - startswith = list(/obj/item/chems/food/snacks/grown/dried_tobacco/bad = 8) icon_state = "rollcoarse" -/obj/item/storage/chewables/rollable/generic +/obj/item/chewables/rollable/bad/WillContain() + return list(/obj/item/food/grown/dried_tobacco/bad = 8) + +/obj/item/chewables/rollable/generic name = "bag of BluSpace tobacco" desc = "Decent quality tobacco for mid-income earners and long haul space sailors." - startswith = list(/obj/item/chems/food/snacks/grown/dried_tobacco = 8) icon_state = "rollgeneric" -/obj/item/storage/chewables/rollable/fine +/obj/item/chewables/rollable/generic/WillContain() + return list(/obj/item/food/grown/dried_tobacco = 8) + +/obj/item/chewables/rollable/fine name = "bag of Golden Sol tobacco" - desc = "A exclusive brand of overpriced tobacco, allegedly grown at a lagrange point station in Sol system." - startswith = list(/obj/item/chems/food/snacks/grown/dried_tobacco/fine = 8) + desc = "An exclusive brand of overpriced tobacco, allegedly grown at a lagrange point station in Sol system." icon_state = "rollfine" +/obj/item/chewables/rollable/fine/WillContain() + return list(/obj/item/food/grown/dried_tobacco/fine = 8) + //chewing tobacco -/obj/item/storage/chewables/tobacco +/obj/item/chewables/tobacco name = "tin of Lenny's brand chewing tobacco" desc = "A generic brand of chewing tobacco, for when you can't even be assed to light up." icon_state = "chew_levi" item_state = "Dpacket" - startswith = list(/obj/item/clothing/mask/chewable/tobacco/lenni = 6) -/obj/item/storage/chewables/tobacco2 +/obj/item/chewables/tobacco/WillContain() + return list(/obj/item/clothing/mask/chewable/tobacco/lenni = 6) + +/obj/item/chewables/tobacco2 name = "tin of Red Lady chewing tobacco" desc = "A finer grade of chewing tobacco." icon_state = "chew_redman" item_state = "redlady" - startswith = list(/obj/item/clothing/mask/chewable/tobacco/redlady = 6) -/obj/item/storage/chewables/tobacco3 +/obj/item/chewables/tobacco2/WillContain() + return list(/obj/item/clothing/mask/chewable/tobacco/redlady = 6) + +/obj/item/chewables/tobacco3 name = "box of Nico-Tine gum" desc = "A Sol-approved brand of nicotine gum. Cut out the middleman for your addiction fix." icon_state = "chew_nico" - startswith = list(/obj/item/clothing/mask/chewable/tobacco/nico = 6) + +/obj/item/chewables/tobacco3/WillContain() + return list(/obj/item/clothing/mask/chewable/tobacco/nico = 6) //non-tobacco -/obj/item/storage/chewables/candy/cookies +/obj/item/chewables/candy + material = /decl/material/solid/organic/plastic + +/obj/item/chewables/candy/cookies name = "pack of Getmore Cookies" - desc = "A pack of delicious cookies, and possibly the only product in Getmores Chocolate Corp lineup that has any trace of chocolate in it." + desc = "A pack of delicious cookies, and possibly the only product in Getmore Chocolate Corp's lineup that has any trace of chocolate in it." icon_state = "cookiebag" - max_storage_space = 6 - startswith = list(/obj/item/chems/food/snacks/cookie = 6) - make_exact_fit() + storage = /datum/storage/chewables/cookies -/obj/item/storage/chewables/candy/gum +/obj/item/chewables/candy/cookies/WillContain() + return list(/obj/item/food/cookie = 6) + +/obj/item/chewables/candy/gum name = "pack of Rainbo-Gums" desc = "A mixed pack of delicious fruit flavored bubble-gums!" icon_state = "gumpack" - max_storage_space = 8 - startswith = list(/obj/item/clothing/mask/chewable/candy/gum = 8) - make_exact_fit() + storage = /datum/storage/chewables/gum + +/obj/item/chewables/candy/gum/WillContain() + return list(/obj/item/clothing/mask/chewable/candy/gum = 8) -/obj/item/storage/chewables/candy/medicallollis +/obj/item/chewables/candy/medicallollis name = "pack of medicinal lollipops" desc = "A mixed pack of medicinal flavored lollipops. These have no business being on store shelves." icon_state = "lollipack" - max_storage_space = 20 - startswith = list(/obj/item/clothing/mask/chewable/candy/lolli/meds = 20) - make_exact_fit() + storage = /datum/storage/chewables/lollipops -/obj/item/storage/medical_lolli_jar +/obj/item/chewables/candy/medicallollis/WillContain() + return list(/obj/item/clothing/mask/chewable/candy/lolli/meds = 20) + +/obj/item/medical_lolli_jar name = "lollipops jar" desc = "A mixed pack of flavored medicinal lollipops. Perfect for small boo-boos." icon = 'icons/obj/items/storage/lollijar.dmi' icon_state = "lollijar" - max_storage_space = 20 - startswith = list(/obj/item/clothing/mask/chewable/candy/lolli/weak_meds = 15) + drop_sound = 'sound/foley/bottledrop1.ogg' + pickup_sound = 'sound/foley/bottlepickup1.ogg' + material = /decl/material/solid/glass + storage = /datum/storage/chewables/lollipops + +/obj/item/medical_lolli_jar/WillContain() + return list(/obj/item/clothing/mask/chewable/candy/lolli/weak_meds = 15) -/obj/item/storage/medical_lolli_jar/on_update_icon() +/obj/item/medical_lolli_jar/on_update_icon() . = ..() - if(contents.len) + if(length(contents)) icon_state = "lollijar" else - icon_state = "lollijar_empty" \ No newline at end of file + icon_state = "lollijar_empty" diff --git a/code/game/objects/items/weapons/storage/mre.dm b/code/game/objects/items/weapons/storage/mre.dm index ad041d14ec94..247a52d5c5a2 100644 --- a/code/game/objects/items/weapons/storage/mre.dm +++ b/code/game/objects/items/weapons/storage/mre.dm @@ -2,185 +2,199 @@ MRE Stuff */ -/obj/item/storage/mre +/obj/item/mre name = "standard MRE" desc = "A vacuum-sealed bag containing a day's worth of nutrients for an adult in strenuous situations. There is no visible expiration date on the package." - icon = 'icons/obj/food.dmi' - icon_state = "mre" - storage_slots = 7 - max_w_class = ITEM_SIZE_SMALL - opened = FALSE - open_sound = 'sound/effects/rip1.ogg' - var/main_meal = /obj/item/storage/mrebag + icon = 'icons/obj/food/mre/mre_generic.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/mre + material = /decl/material/solid/organic/plastic + obj_flags = OBJ_FLAG_HOLLOW + var/main_meal = /obj/item/mrebag var/meal_desc = "This one is menu 1, meat pizza." - startswith = list( - /obj/item/storage/mrebag/dessert, - /obj/item/storage/fancy/crackers, - /obj/random/mre/spread, - /obj/random/mre/drink, - /obj/random/mre/sauce, - /obj/item/kitchen/utensil/spork/plastic + var/has_been_opened = FALSE + +/obj/item/mre/WillContain() + . = list( + main_meal, + /obj/item/mrebag/dessert, + /obj/item/box/fancy/crackers, + /obj/random/mre/spread, + /obj/random/mre/drink, + /obj/random/mre/sauce, + /obj/item/utensil/spork/plastic ) -/obj/item/storage/mre/Initialize() - create_objects_in_loc(src, main_meal) +/obj/item/mre/Initialize(ml, material_key) . = ..() - make_exact_fit() + if(length(contents) && storage) + storage.make_exact_fit() -/obj/item/storage/mre/examine(mob/user) +/obj/item/mre/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, meal_desc) + if(meal_desc) + . += meal_desc -/obj/item/storage/mre/on_update_icon() - if(opened) - icon_state = "[initial(icon_state)][opened]" +/obj/item/mre/attack_self(mob/user) . = ..() -/obj/item/storage/mre/attack_self(mob/user) - open(user) - -/obj/item/storage/mre/open(mob/user) - if(!opened) - to_chat(usr, "You tear open the bag, breaking the vacuum seal.") +/obj/item/mre/on_update_icon() . = ..() + icon_state = get_world_inventory_state() + if(has_been_opened) + icon_state = "[icon_state]-open" + +/obj/item/mre/attack_self(mob/user) + if(storage && !storage.opened) + storage.open(user) + return TRUE + return ..() -/obj/item/storage/mre/menu2 +/obj/item/mre/menu2 meal_desc = "This one is menu 2, margherita." - main_meal = /obj/item/storage/mrebag/menu2 + main_meal = /obj/item/mrebag/menu2 -/obj/item/storage/mre/menu3 +/obj/item/mre/menu3 meal_desc = "This one is menu 3, vegetable pizza." - main_meal = /obj/item/storage/mrebag/menu3 + main_meal = /obj/item/mrebag/menu3 -/obj/item/storage/mre/menu4 +/obj/item/mre/menu4 meal_desc = "This one is menu 4, hamburger." - main_meal = /obj/item/storage/mrebag/menu4 + main_meal = /obj/item/mrebag/menu4 -/obj/item/storage/mre/menu5 +/obj/item/mre/menu5 meal_desc = "This one is menu 5, taco." - main_meal = /obj/item/storage/mrebag/menu5 + main_meal = /obj/item/mrebag/menu5 -/obj/item/storage/mre/menu6 +/obj/item/mre/menu6 meal_desc = "This one is menu 6, meatbread." - main_meal = /obj/item/storage/mrebag/menu6 + main_meal = /obj/item/mrebag/menu6 -/obj/item/storage/mre/menu7 +/obj/item/mre/menu7 meal_desc = "This one is menu 7, salad." - main_meal = /obj/item/storage/mrebag/menu7 + main_meal = /obj/item/mrebag/menu7 -/obj/item/storage/mre/menu8 +/obj/item/mre/menu8 meal_desc = " This one is menu 8, hot chili." - main_meal = /obj/item/storage/mrebag/menu8 + main_meal = /obj/item/mrebag/menu8 -/obj/item/storage/mre/menu9 +/obj/item/mre/menu9 name = "vegan MRE" + icon = 'icons/obj/food/mre/mre_veg.dmi' meal_desc = "This one is menu 9, boiled rice." - icon_state = "vegmre" - main_meal = /obj/item/storage/mrebag/menu9 - startswith = list( - /obj/item/storage/mrebag/dessert/menu9, - /obj/item/storage/fancy/crackers, - /obj/random/mre/spread/vegan, - /obj/random/mre/drink, - /obj/random/mre/sauce/vegan, - /obj/item/kitchen/utensil/spoon/plastic + main_meal = /obj/item/mrebag/menu9 + +/obj/item/mre/menu9/WillContain() + . = list( + main_meal, + /obj/item/mrebag/dessert/menu9, + /obj/item/box/fancy/crackers, + /obj/random/mre/spread/vegan, + /obj/random/mre/drink, + /obj/random/mre/sauce/vegan, + /obj/item/utensil/spoon/plastic ) -/obj/item/storage/mre/menu10 +/obj/item/mre/menu10 name = "protein MRE" meal_desc = "This one is menu 10, protein." - icon_state = "meatmre" - main_meal = /obj/item/storage/mrebag/menu10 - startswith = list( - /obj/item/chems/food/snacks/candy/proteinbar, - /obj/item/chems/food/condiment/small/packet/protein, - /obj/random/mre/sauce/sugarfree, - /obj/item/kitchen/utensil/spoon/plastic + main_meal = /obj/item/mrebag/menu10 + icon = 'icons/obj/food/mre/mre_meat.dmi' + +/obj/item/mre/menu10/WillContain() + . = list( + main_meal, + /obj/item/food/junk/candy/proteinbar, + /obj/item/chems/packet/protein, + /obj/random/mre/sauce/sugarfree, + /obj/item/utensil/spoon/plastic ) -/obj/item/storage/mre/menu11 +/obj/item/mre/menu11 name = "crayon MRE" meal_desc = "This one doesn't have a menu listing. How very odd." - icon_state = "crayonmre" - main_meal = /obj/item/storage/fancy/crayons - startswith = list( - /obj/item/storage/mrebag/dessert/menu11, - /obj/random/mre/sauce/crayon, - /obj/random/mre/sauce/crayon, - /obj/random/mre/sauce/crayon + main_meal = /obj/item/box/fancy/crayons + icon = 'icons/obj/food/mre/mre_crayon.dmi' + +/obj/item/mre/menu11/WillContain() + return list( + main_meal, + /obj/item/mrebag/dessert/menu11, + /obj/random/mre/sauce/crayon, + /obj/random/mre/sauce/crayon, + /obj/random/mre/sauce/crayon ) -/obj/item/storage/mre/menu11/special +/obj/item/mre/menu11/special meal_desc = "This one doesn't have a menu listing. How odd. It has the initials \"A.B.\" written on the back." -/obj/item/storage/mre/random +/obj/item/mre/random meal_desc = "The menu label is faded out." main_meal = /obj/random/mre/main -/obj/item/storage/mrebag +/obj/item/mrebag name = "main course" desc = "A vacuum-sealed bag containing the MRE's main course. Self-heats when opened." - icon = 'icons/obj/food.dmi' - icon_state = "pouch_medium" - storage_slots = 1 + icon = 'icons/obj/food/mre/pouch_medium.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/mrebag w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_SMALL - opened = FALSE - open_sound = 'sound/effects/bubbles.ogg' - startswith = list(/obj/item/chems/food/snacks/slice/meatpizza/filled) + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE) -/obj/item/storage/mrebag/Initialize() - . = ..() +/obj/item/mrebag/WillContain() + return list(/obj/item/food/slice/pizza/meat/filled) -/obj/item/storage/mrebag/on_update_icon() - if(opened) - icon_state = "[initial(icon_state)][opened]" +/obj/item/mrebag/on_update_icon() . = ..() + icon_state = get_world_inventory_state() + if(storage?.opened) + icon_state = "[icon_state]-open" -/obj/item/storage/mrebag/attack_self(mob/user) - open(user) +/obj/item/mrebag/attack_self(mob/user) + if(storage && !storage.opened) + storage.open(user) + return TRUE + return ..() -/obj/item/storage/mrebag/open(mob/user) - if(!opened) - to_chat(usr, "The pouch heats up as you break the vaccum seal.") - . = ..() - -/obj/item/storage/mrebag/menu2 - startswith = list(/obj/item/chems/food/snacks/slice/margherita/filled) +/obj/item/mrebag/menu2/WillContain() + return list(/obj/item/food/slice/pizza/margherita/filled) -/obj/item/storage/mrebag/menu3 - startswith = list(/obj/item/chems/food/snacks/slice/vegetablepizza/filled) +/obj/item/mrebag/menu3/WillContain() + return list(/obj/item/food/slice/pizza/vegetable/filled) -/obj/item/storage/mrebag/menu4 - startswith = list(/obj/item/chems/food/snacks/hamburger) +/obj/item/mrebag/menu4/WillContain() + return list(/obj/item/food/hamburger) -/obj/item/storage/mrebag/menu5 - startswith = list(/obj/item/chems/food/snacks/taco) +/obj/item/mrebag/menu5/WillContain() + return list(/obj/item/food/taco) -/obj/item/storage/mrebag/menu6 - startswith = list(/obj/item/chems/food/snacks/slice/meatbread/filled) +/obj/item/mrebag/menu6/WillContain() + return list(/obj/item/food/slice/meatbread/filled) -/obj/item/storage/mrebag/menu7 - startswith = list(/obj/item/chems/food/snacks/tossedsalad) +/obj/item/mrebag/menu7/WillContain() + return list(/obj/item/food/tossedsalad) -/obj/item/storage/mrebag/menu8 - startswith = list(/obj/item/chems/food/snacks/hotchili) +/obj/item/mrebag/menu8/WillContain() + return list(/obj/item/chems/glass/bowl/mapped/chili/hot) -/obj/item/storage/mrebag/menu9 - startswith = list(/obj/item/chems/food/snacks/boiledrice) +/obj/item/mrebag/menu9/WillContain() + return list(/obj/item/food/boiledrice) -/obj/item/storage/mrebag/menu10 - startswith = list(/obj/item/chems/food/snacks/meatcube) +/obj/item/mrebag/menu10/WillContain() + return list(/obj/item/food/junk/meatcube) -/obj/item/storage/mrebag/dessert +/obj/item/mrebag/dessert name = "dessert" desc = "A vacuum-sealed bag containing the MRE's dessert." - icon_state = "pouch_small" - open_sound = 'sound/effects/rip1.ogg' - startswith = list(/obj/random/mre/dessert) + icon = 'icons/obj/food/mre/pouch_small.dmi' + storage = /datum/storage/mrebag/dessert + +/obj/item/mrebag/dessert/WillContain() + return list(/obj/random/mre/dessert) -/obj/item/storage/mrebag/dessert/menu9 - startswith = list(/obj/item/chems/food/snacks/plumphelmetbiscuit) +/obj/item/mrebag/dessert/menu9/WillContain() + return list(/obj/item/food/plumphelmetbiscuit) -/obj/item/storage/mrebag/dessert/menu11 - startswith = list(/obj/item/pen/crayon/rainbow) +/obj/item/mrebag/dessert/menu11/WillContain() + return list(/obj/item/pen/crayon/rainbow) diff --git a/code/game/objects/items/weapons/storage/nuggets.dm b/code/game/objects/items/weapons/storage/nuggets.dm new file mode 100644 index 000000000000..c8a8b1602fc2 --- /dev/null +++ b/code/game/objects/items/weapons/storage/nuggets.dm @@ -0,0 +1,64 @@ +/datum/storage/box/nuggets + can_hold = list(/obj/item/food/nugget) + var/expected_nugget_count = 10 + +/datum/storage/box/nuggets/New() + max_storage_space = /obj/item/food/nugget::w_class * expected_nugget_count + ..() + +/datum/storage/box/nuggets/twenty + expected_nugget_count = 20 + +/datum/storage/box/nuggets/forty + expected_nugget_count = 40 + +/obj/item/box/nuggets + name = "10-piece nuggets box" + icon = 'icons/obj/items/storage/nugget_box.dmi' + icon_state = "nuggetbox_ten" + desc = "A share pack of golden chicken nuggets in various fun shapes. Rumours of the rare and deadly 'fifth nugget shape' remain unsubstantiated." + storage = /datum/storage/box/nuggets + center_of_mass = @'{"x":16,"y":9}' + +/obj/item/box/nuggets/Initialize(ml, material_key) + . = ..() + update_icon() + +/obj/item/box/nuggets/WillContain() + . = list() + if(istype(storage, /datum/storage/box/nuggets)) + var/datum/storage/box/nuggets/nugget_box = storage + for(var/i = 1 to nugget_box.expected_nugget_count) + . += /obj/item/food/nugget + +/obj/item/box/nuggets/on_update_icon() + . = ..() + var/datum/storage/box/nuggets/nugget_box = storage + if(length(contents) == 0 || !istype(nugget_box)) + icon_state = "[initial(icon_state)]_empty" + else if(length(contents) >= nugget_box.expected_nugget_count) + icon_state = "[initial(icon_state)]_full" + else + icon_state = initial(icon_state) + +// Subtypes below. +/obj/item/box/nuggets/twenty + name = "20-piece nuggets box" + icon_state = "nuggetbox_twenty" + storage = /datum/storage/box/nuggets/twenty + +/obj/item/box/nuggets/twenty/WillContain() + . = list() + for(var/i = 1 to 20) + . += /obj/item/food/nugget + +/obj/item/box/nuggets/twenty/empty/WillContain() + return + +/obj/item/box/nuggets/forty + name = "40-piece nuggets box" + icon_state = "nuggetbox_forty" + storage = /datum/storage/box/nuggets/forty + +/obj/item/box/nuggets/forty/empty/WillContain() + return diff --git a/code/game/objects/items/weapons/storage/parachute.dm b/code/game/objects/items/weapons/storage/parachute.dm new file mode 100644 index 000000000000..e129add2b64e --- /dev/null +++ b/code/game/objects/items/weapons/storage/parachute.dm @@ -0,0 +1,45 @@ +//Parachutes +/obj/item/backpack/parachute + name = "parachute" + desc = "A specially-made backpack, designed to help one survive jumping from incredible heights. It sacrifices some storage space for that added functionality." + icon = 'icons/obj/items/storage/backpack/parachute.dmi' + var/packed = TRUE + +/obj/item/backpack/parachute/Initialize(ml, material_key) + . = ..() + if(storage) + storage.max_storage_space = max(1, round(storage.max_storage_space * 0.5)) + +/obj/item/backpack/parachute/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(Adjacent(user)) + if(packed) + . += SPAN_NOTICE("The parachute seems to be packed and ready to deploy.") + else + . += SPAN_DANGER("The parachute is unpacked.") + +/obj/item/backpack/parachute/attack_self(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/initial_pack = packed + var/pack_msg = packed ? "unpack" : "pack" + user.visible_message( + SPAN_NOTICE("\The [user] starts to [pack_msg] \the [src]."), + SPAN_NOTICE("You start to pack \the [src]."), + "You hear the shuffling of cloth." + ) + if(!do_after(user, 5 SECONDS)) + user.visible_message( + SPAN_NOTICE("\The [user] gives up on [pack_msg]ing \the [src]."), + SPAN_NOTICE("You give up on [pack_msg]ing \the [src].") + ) + return TRUE + if(packed != initial_pack) + return TRUE + user.visible_message( + SPAN_NOTICE("\The [user] finishes [pack_msg]ing \the [src]."), + SPAN_NOTICE("You finish [pack_msg]ing \the [src]."), + "You hear the shuffling of cloth." + ) + packed = !packed + return TRUE diff --git a/code/game/objects/items/weapons/storage/picnic_basket.dm b/code/game/objects/items/weapons/storage/picnic_basket.dm new file mode 100644 index 000000000000..7ecd98a74f58 --- /dev/null +++ b/code/game/objects/items/weapons/storage/picnic_basket.dm @@ -0,0 +1,26 @@ +// A picnic basket. Sprites by Pawn. +/obj/item/picnic_basket + name = "picnic basket" + desc = "A picnic basket. Can be filled with small stuff for your small trip." + icon = 'icons/obj/items/storage/picnic_basket.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_NORMAL + storage = /datum/storage/picnic_basket + attack_verb = "picnics" + material = /decl/material/solid/organic/plastic + var/tmp/filled = FALSE + +/obj/item/picnic_basket/WillContain() + if(!filled) + return + var/list/lunches = lunchables_lunches() + var/list/snacks = lunchables_snacks() + var/list/drinks = lunchables_drinks() + return list( + lunches[pick(lunches)], + snacks[pick(snacks)], + drinks[pick(drinks)], + ) + +/obj/item/picnic_basket/filled + filled = TRUE diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm index 88cbdf0b4208..fb7ff59d4049 100644 --- a/code/game/objects/items/weapons/storage/secure.dm +++ b/code/game/objects/items/weapons/storage/secure.dm @@ -10,120 +10,157 @@ // ----------------------------- // Generic Item // ----------------------------- -/obj/item/storage/secure - name = "secstorage" +/obj/item/secure_storage + name = "secure storage (abstract)" w_class = ITEM_SIZE_NORMAL - max_w_class = ITEM_SIZE_SMALL - max_storage_space = DEFAULT_BOX_STORAGE + storage = /datum/storage/secure + material = /decl/material/solid/metal/steel + abstract_type = /obj/item/secure_storage + ///The type of lockable extension to use for this secure storage. var/lock_type = /datum/extension/lockable/storage - var/icon_locking = "secureb" - var/icon_opened = "secure0" + ///An overlay displayed while the thing is being hacked + var/overlay_hack = "overlay-hack" + ///An overlay displayed after the thing has been emagged + var/overlay_emagged = "overlay-emagged" + ///An overlay displayed while it's locked + var/overlay_locked = "overlay-locked" + ///An overlay displayed while it's unlocked + var/overlay_unlocked = "overlay-unlocked" + ///An overlay displayed while the service panel is opened + var/overlay_panel_open = "overlay-panel-open" + +/obj/item/secure_storage/Initialize(ml, material_key) + var/datum/extension/lockable/mylock = get_or_create_extension(src, lock_type) + events_repository.register(/decl/observ/lock_state_changed, mylock, src, /obj/item/secure_storage/proc/on_lock_state_changed) + . = ..() -/obj/item/storage/secure/Initialize() +/obj/item/secure_storage/Destroy() + var/datum/extension/lockable/mylock = get_extension(src, lock_type) + events_repository.unregister(/decl/observ/lock_state_changed, mylock, src, /obj/item/secure_storage/proc/on_lock_state_changed) . = ..() - set_extension(src, lock_type) -/obj/item/storage/secure/attackby(var/obj/item/W, var/mob/user) - var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - if(lock.attackby(W, user)) +/obj/item/secure_storage/proc/on_lock_state_changed(datum/extension/lockable/L, old_locked, new_locked) + if(new_locked == old_locked) return + //Make sure we close all uis when we turn the lock on + if(new_locked) + storage?.close_all() + +/obj/item/secure_storage/attackby(obj/item/used_item, mob/user) + var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) + if(lock.attackby(used_item, user)) + return TRUE // -> storage/attackby() what with handle insertion, etc if(!lock.locked) . = ..() + return FALSE - -/obj/item/storage/secure/MouseDrop(over_object, src_location, over_location) +/obj/item/secure_storage/handle_mouse_drop(atom/over, mob/user, params) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - if (lock.locked) - src.add_fingerprint(usr) - return - ..() - + if(lock.locked) + add_fingerprint(user) + return TRUE + . = ..() -/obj/item/storage/secure/attack_self(var/mob/user) +/obj/item/secure_storage/attack_self(mob/user) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - lock.ui_interact(user) - -/obj/item/storage/secure/examine(mob/user, distance) + lock.ui_interact(user) + +/obj/item/secure_storage/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - to_chat(user, text("The service panel is [lock.open ? "open" : "closed"].")) + if(lock) + . += SPAN_INFO("The service panel is [lock.open ? "open" : "closed"].") -/obj/item/storage/secure/emag_act(var/remaining_charges, var/mob/user, var/feedback) +/obj/item/secure_storage/emag_act(remaining_charges, mob/user, feedback) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - .= lock.emag_act(remaining_charges, user, feedback) + . = lock.emag_act(remaining_charges, user, feedback) update_icon() -/obj/item/storage/secure/on_update_icon() +/obj/item/secure_storage/on_update_icon() . = ..() - var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) + //If update icon is called and the lock hasn't been initialized yet for whatever reasons, just skip if(!istype(lock)) return - - overlays.Cut() - if(lock.emagged) - overlays += image(icon, icon_locking) - else if(lock.open) - overlays += image(icon, icon_opened) + //Add sevice panel overlay if service panel is opened + if(lock.open && length(overlay_panel_open)) + add_overlay("[icon_state]-[overlay_panel_open]") + + //Pick and add the right LED panel overlay + if(lock.l_hacking && length(overlay_hack)) + add_overlay("[icon_state]-[overlay_hack]") + else if(lock.emagged && length(overlay_emagged)) + add_overlay("[icon_state]-[overlay_emagged]") + else if(!lock.locked && length(overlay_unlocked)) + add_overlay("[icon_state]-[overlay_unlocked]") + else if(length(overlay_locked)) + add_overlay("[icon_state]-[overlay_locked]") // ----------------------------- // Secure Briefcase // ----------------------------- -/obj/item/storage/secure/briefcase +/obj/item/secure_storage/briefcase name = "secure briefcase" - icon = 'icons/obj/items/storage/briefcase.dmi' - icon_state = "secure" - item_state = "sec-case" + icon = 'icons/obj/items/storage/briefcase_secure.dmi' + icon_state = ICON_STATE_WORLD desc = "A large briefcase with a digital locking system." - force = 8.0 + _base_attack_force = 8.0 throw_speed = 1 throw_range = 4 w_class = ITEM_SIZE_HUGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_BACKPACK_STORAGE - use_sound = 'sound/effects/storage/briefcase.ogg' - -/obj/item/storage/secure/briefcase/attack_hand(mob/user as mob) - var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - if (loc == user && lock.locked) - to_chat(user, SPAN_WARNING("[src] is locked and cannot be opened!")) - else if (loc == user && !lock.locked) - src.open(user) - else - ..() - for(var/mob/M in range(1)) - if (M.s_active == src) - src.close(M) - src.add_fingerprint(user) - return + storage = /datum/storage/secure/briefcase + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/secure_storage/briefcase/attack_hand(mob/user as mob) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) + if(lock && storage) + if (loc == user && lock.locked) + to_chat(user, SPAN_WARNING("\The [src] is locked and cannot be opened!")) + return TRUE + if (loc == user && !lock.locked) + storage.open(user) + add_fingerprint(user) + return TRUE + return ..() // ----------------------------- // Secure Safe // ----------------------------- -/obj/item/storage/secure/safe +//#TODO: Move to a structure, so we don't have to deal with the item pickup code. +/obj/item/secure_storage/safe name = "secure safe" icon = 'icons/obj/items/storage/safe.dmi' - icon_state = "safe" - force = 8 + icon_state = ICON_STATE_WORLD + overlay_panel_open = null //TODO: Add service panel open overlay + _base_attack_force = 8 w_class = ITEM_SIZE_STRUCTURE - max_w_class = ITEM_SIZE_HUGE - max_storage_space = 56 - anchored = 1 - density = 0 - cant_hold = list(/obj/item/storage/secure/briefcase) + anchored = TRUE + density = FALSE lock_type = /datum/extension/lockable/storage/safe - icon_locking = "safeb" - icon_opened = "safe0" - -/obj/item/storage/secure/safe/Initialize() + storage = /datum/storage/secure/safe + +/obj/item/secure_storage/safe/WillContain() + return list( + /obj/item/pen, + /obj/item/paper + ) + +/obj/item/secure_storage/safe/attack_hand(mob/user) + //The safe acts kinda weird because it's an item that cannot be picked up by default, and we need a way to open the ui. + // I added this so if it can be picked up at all, it'll behave like any items. And otherwise it'll open the UI. + // The storage extension will cause the base item class to automatically add an alt-interaction to open the storage. + if(!can_be_picked_up(user)) + var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) + lock.ui_interact(user) + return TRUE . = ..() - new /obj/item/paper(src) - new /obj/item/pen(src) -/obj/item/storage/secure/safe/attack_hand(mob/user) - return attack_self(user) \ No newline at end of file +/obj/item/secure_storage/safe/empty/WillContain() + return diff --git a/code/game/objects/items/weapons/storage/specialized.dm b/code/game/objects/items/weapons/storage/specialized.dm index de70c1f83442..8a90eb636360 100644 --- a/code/game/objects/items/weapons/storage/specialized.dm +++ b/code/game/objects/items/weapons/storage/specialized.dm @@ -9,61 +9,43 @@ // Mining Satchel // ----------------------------- -/obj/item/storage/ore +/obj/item/ore_satchel name = "mining satchel" desc = "This sturdy bag can be used to store and transport ores." - icon = 'icons/obj/mining.dmi' - icon_state = "satchel" - slot_flags = SLOT_BELT - max_storage_space = 200 - max_w_class = ITEM_SIZE_NORMAL + icon = 'icons/obj/items/mining_satchel.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_LARGE - can_hold = list(/obj/item/ore) - allow_quick_gather = 1 - allow_quick_empty = 1 - use_to_pickup = 1 + storage = /datum/storage/ore + material = /decl/material/solid/organic/leather // ----------------------------- // Evidence bag // ----------------------------- -/obj/item/storage/evidence +/obj/item/evidence name = "evidence case" desc = "A heavy steel case for storing evidence." - icon = 'icons/obj/forensics.dmi' - icon_state = "case" - max_storage_space = 100 - max_w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/items/storage/crime_kit.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/evidence w_class = ITEM_SIZE_NORMAL - can_hold = list( - /obj/item/forensics/sample, - /obj/item/evidencebag, - /obj/item/forensics, - /obj/item/photo, - /obj/item/paper, - /obj/item/paper_bundle - ) - allow_quick_gather = 1 - allow_quick_empty = 1 - use_to_pickup = 1 + material = /decl/material/solid/metal/stainlesssteel + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) // ----------------------------- // Plant bag // ----------------------------- -/obj/item/storage/plants +/obj/item/plant_satchel name = "botanical satchel" desc = "This bag can be used to store all kinds of plant products and botanical specimen." icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' icon_state = "plantbag" - slot_flags = SLOT_BELT - max_storage_space = 100 - max_w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + storage = /datum/storage/plants w_class = ITEM_SIZE_NORMAL - can_hold = list(/obj/item/chems/food/snacks/grown,/obj/item/seeds,/obj/item/grown) - allow_quick_gather = 1 - allow_quick_empty = 1 - use_to_pickup = 1 + material = /decl/material/solid/organic/leather // ----------------------------- @@ -73,105 +55,20 @@ // However, making it a storage/bag allows us to reuse existing code in some places. -Sayu // This is old and terrible -/obj/item/storage/sheetsnatcher +/obj/item/sheetsnatcher name = "sheet snatcher" - icon = 'icons/obj/mining.dmi' - icon_state = "sheetsnatcher" + icon = 'icons/obj/items/sheet_snatcher.dmi' + icon_state = ICON_STATE_WORLD desc = "A patented storage system designed for any kind of mineral sheet." - - storage_ui = /datum/storage_ui/default/sheetsnatcher - - var/capacity = 300; //the number of sheets it can carry. + material = /decl/material/solid/organic/plastic + storage = /datum/storage/sheets w_class = ITEM_SIZE_NORMAL - storage_slots = 7 - - allow_quick_empty = 1 // this function is superceded - use_to_pickup = 1 - - can_be_inserted(obj/item/W, mob/user, stop_messages = 0) - if(!istype(W,/obj/item/stack/material)) - if(!stop_messages) - to_chat(user, "The snatcher does not accept [W].") - return 0 - var/current = 0 - for(var/obj/item/stack/material/S in contents) - current += S.amount - if(capacity == current)//If it's full, you're done - if(!stop_messages) - to_chat(user, "The snatcher is full.") - return 0 - return 1 - - -// Modified handle_item_insertion. Would prefer not to, but... - handle_item_insertion(obj/item/W as obj, prevent_warning = 0) - var/obj/item/stack/material/S = W - if(!istype(S)) return 0 - - var/amount - var/inserted = 0 - var/current = 0 - for(var/obj/item/stack/material/S2 in contents) - current += S2.amount - if(capacity < current + S.amount)//If the stack will fill it up - amount = capacity - current - else - amount = S.amount - - for(var/obj/item/stack/material/sheet in contents) - if(S.type == sheet.type) // we are violating the amount limitation because these are not sane objects - sheet.amount += amount // they should only be removed through procs in this file, which split them up. - S.amount -= amount - inserted = 1 - break - - if(!inserted || !S.amount) - usr.drop_from_inventory(S, src) - if(!S.amount) - qdel(S) - - prepare_ui(usr) - update_icon() - return 1 - -// Modified quick_empty verb drops appropriate sized stacks - quick_empty() - var/location = get_turf(src) - for(var/obj/item/stack/material/S in contents) - while(S.amount) - var/obj/item/stack/material/N = new S.type(location) - var/stacksize = min(S.amount,N.max_amount) - N.amount = stacksize - S.amount -= stacksize - if(!S.amount) - qdel(S) // todo: there's probably something missing here - prepare_ui() - if(usr.s_active) - usr.s_active.show_to(usr) - update_icon() - -// Instead of removing - remove_from_storage(obj/item/W as obj, atom/new_location) - var/obj/item/stack/material/S = W - if(!istype(S)) return 0 - - //I would prefer to drop a new stack, but the item/attack_hand code - // that calls this can't recieve a different object than you clicked on. - //Therefore, make a new stack internally that has the remainder. - // -Sayu - - if(S.amount > S.max_amount) - var/obj/item/stack/material/temp = new S.type(src) - temp.amount = S.amount - S.max_amount - S.amount = S.max_amount - - return ..(S,new_location) // ----------------------------- // Sheet Snatcher (Cyborg) // ----------------------------- -/obj/item/storage/sheetsnatcher/borg +/obj/item/sheetsnatcher/borg name = "sheet snatcher 9000" desc = "" - capacity = 500//Borgs get more because >specialization \ No newline at end of file + storage = /datum/storage/sheets/robot diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm deleted file mode 100644 index 7df5d67964dc..000000000000 --- a/code/game/objects/items/weapons/storage/storage.dm +++ /dev/null @@ -1,433 +0,0 @@ -// To clarify: -// For use_to_pickup and allow_quick_gather functionality, -// see item/attackby() (/game/objects/items.dm) -// Do not remove this functionality without good reason, cough reagent_containers cough. -// -Sayu - - -/obj/item/storage - name = "storage" - icon = 'icons/obj/items/storage/box.dmi' - w_class = ITEM_SIZE_NORMAL - var/list/can_hold = new/list() //List of objects which this item can store (if set, it can't store anything else) - var/list/cant_hold = new/list() //List of objects which this item can't store (in effect only if can_hold isn't set) - - var/max_w_class = ITEM_SIZE_SMALL //Max size of objects that this object can store (in effect only if can_hold isn't set) - var/max_storage_space = null //Total storage cost of items this can hold. Will be autoset based on storage_slots if left null. - var/storage_slots = null //The number of storage slots in this container. - - var/use_to_pickup //Set this to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up. - var/allow_quick_empty //Set this variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor. - var/allow_quick_gather //Set this variable to allow the object to have the 'toggle mode' verb, which quickly collects all items from a tile. - var/collection_mode = 1; //0 = pick one at a time, 1 = pick all on tile - var/use_sound = "rustle" //sound played when used. null for no sound. - - //initializes the contents of the storage with some items based on an assoc list. The assoc key must be an item path, - //the assoc value can either be the quantity, or a list whose first value is the quantity and the rest are args. - var/list/startswith - var/datum/storage_ui/storage_ui = /datum/storage_ui/default - var/opened = null - var/open_sound = null - -/obj/item/storage/Destroy() - QDEL_NULL(storage_ui) - . = ..() - -/obj/item/storage/MouseDrop(obj/over_object) - if(!canremove) - return - - if ((ishuman(usr) || isrobot(usr) || issmall(usr)) && !usr.incapacitated()) - if(over_object == usr && Adjacent(usr)) // this must come before the screen objects only block - src.open(usr) - return TRUE - - if (!( istype(over_object, /obj/screen) )) - return ..() - - //makes sure that the storage is equipped, so that we can't drag it into our hand from miles away. - if (!usr.contains(src)) - return - - src.add_fingerprint(usr) - if(usr.unEquip(src)) - switch(over_object.name) - if(BP_R_HAND) - usr.put_in_r_hand(src) - if(BP_L_HAND) - usr.put_in_l_hand(src) - - -/obj/item/storage/proc/return_inv() - - var/list/L = list( ) - - L += src.contents - - for(var/obj/item/storage/S in src) - L += S.return_inv() - for(var/obj/item/gift/G in src) - L += G.gift - if (istype(G.gift, /obj/item/storage)) - L += G.gift:return_inv() - return L - -/obj/item/storage/proc/show_to(mob/user) - if(storage_ui) - storage_ui.show_to(user) - -/obj/item/storage/proc/hide_from(mob/user) - if(storage_ui) - storage_ui.hide_from(user) - -/obj/item/storage/proc/open(mob/user) - if(!opened) - playsound(src.loc, src.open_sound, 50, 0, -5) - opened = 1 - queue_icon_update() - if (src.use_sound) - playsound(src.loc, src.use_sound, 50, 0, -5) - if (isrobot(user) && user.hud_used) - var/mob/living/silicon/robot/robot = user - if(robot.shown_robot_modules) //The robot's inventory is open, need to close it first. - robot.hud_used.toggle_show_robot_modules() - - prepare_ui() - storage_ui.on_open(user) - storage_ui.show_to(user) - -/obj/item/storage/proc/prepare_ui() - storage_ui.prepare_ui() - -/obj/item/storage/proc/close(mob/user) - hide_from(user) - if(storage_ui) - storage_ui.after_close(user) - -/obj/item/storage/proc/close_all() - if(storage_ui) - storage_ui.close_all() - -/obj/item/storage/proc/storage_space_used() - . = 0 - for(var/obj/item/I in contents) - . += I.get_storage_cost() - -//This proc return 1 if the item can be picked up and 0 if it can't. -//Set the stop_messages to stop it from printing messages -/obj/item/storage/proc/can_be_inserted(obj/item/W, mob/user, stop_messages = 0) - if(!istype(W)) return //Not an item - - if(user && !user.canUnEquip(W)) - return 0 - - if(src.loc == W) - return 0 //Means the item is already in the storage item - if(storage_slots != null && contents.len >= storage_slots) - if(!stop_messages) - to_chat(user, "\The [src] is full, make some space.") - return 0 //Storage item is full - - if(W.anchored) - return 0 - - if(can_hold.len) - if(!is_type_in_list(W, can_hold)) - if(!stop_messages && ! istype(W, /obj/item/hand_labeler)) - to_chat(user, "\The [src] cannot hold \the [W].") - return 0 - var/max_instances = can_hold[W.type] - if(max_instances && instances_of_type_in_list(W, contents) >= max_instances) - if(!stop_messages && !istype(W, /obj/item/hand_labeler)) - to_chat(user, "\The [src] has no more space specifically for \the [W].") - return 0 - - //If attempting to lable the storage item, silently fail to allow it - if(istype(W, /obj/item/hand_labeler) && user && user.a_intent != I_HELP) - return FALSE - - // Don't allow insertion of unsafed compressed matter implants - // Since they are sucking something up now, their afterattack will delete the storage - if(istype(W, /obj/item/implanter/compressed)) - var/obj/item/implanter/compressed/impr = W - if(!impr.safe) - stop_messages = 1 - return 0 - - if(cant_hold.len && is_type_in_list(W, cant_hold)) - if(!stop_messages) - to_chat(user, "\The [src] cannot hold \the [W].") - return 0 - - if (max_w_class != null && W.w_class > max_w_class) - if(!stop_messages) - to_chat(user, "\The [W] is too big for this [src.name].") - return 0 - - var/total_storage_space = W.get_storage_cost() - if(total_storage_space >= ITEM_SIZE_NO_CONTAINER) - if(!stop_messages) - to_chat(user, "\The [W] cannot be placed in [src].") - return 0 - - total_storage_space += storage_space_used() //Adds up the combined w_classes which will be in the storage item if the item is added to it. - if(total_storage_space > max_storage_space) - if(!stop_messages) - to_chat(user, "\The [src] is too full, make some space.") - return 0 - - return 1 - -//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted() -//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, -//such as when picking up all the items on a tile with one click. -/obj/item/storage/proc/handle_item_insertion(var/obj/item/W, var/prevent_warning = 0, var/NoUpdate = 0) - if(!istype(W)) - return 0 - if(istype(W.loc, /mob)) - var/mob/M = W.loc - if(!M.unEquip(W)) - return - W.forceMove(src) - W.on_enter_storage(src) - if(usr) - add_fingerprint(usr) - - if(!prevent_warning) - for(var/mob/M in viewers(usr, null)) - if (M == usr) - to_chat(usr, "You put \the [W] into [src].") - else if (M in range(1, src)) //If someone is standing close enough, they can tell what it is... TODO replace with distance check - M.show_message("\The [usr] puts [W] into [src].", VISIBLE_MESSAGE) - else if (W && W.w_class >= ITEM_SIZE_NORMAL) //Otherwise they can only see large or normal items from a distance... - M.show_message("\The [usr] puts [W] into [src].", VISIBLE_MESSAGE) - - if(!NoUpdate) - update_ui_after_item_insertion() - update_icon() - return 1 - -/obj/item/storage/proc/update_ui_after_item_insertion() - prepare_ui() - if(storage_ui) - storage_ui.on_insertion(usr) - -/obj/item/storage/proc/update_ui_after_item_removal() - prepare_ui() - if(storage_ui) - storage_ui.on_post_remove(usr) - -//Call this proc to handle the removal of an item from the storage item. The item will be moved to the atom sent as new_target -/obj/item/storage/proc/remove_from_storage(obj/item/W, atom/new_location, var/NoUpdate = 0) - if(!istype(W)) return 0 - new_location = new_location || get_turf(src) - - if(storage_ui) - storage_ui.on_pre_remove(usr, W) - - if(ismob(loc)) - W.dropped(usr) - if(ismob(new_location)) - W.hud_layerise() - else - W.reset_plane_and_layer() - W.forceMove(new_location) - - if(usr && !NoUpdate) - update_ui_after_item_removal() - if(W.maptext) - W.maptext = "" - W.on_exit_storage(src) - if(!NoUpdate) - update_icon() - return 1 - -// Only do ui functions for now; the obj is responsible for anything else. -/obj/item/storage/proc/on_item_pre_deletion(obj/item/W) - if(storage_ui) - storage_ui.on_pre_remove(null, W) // Supposed to be able to handle null user. - -// Only do ui functions for now; the obj is responsible for anything else. -/obj/item/storage/proc/on_item_post_deletion(obj/item/W) - if(storage_ui) - update_ui_after_item_removal() - queue_icon_update() - -//Run once after using remove_from_storage with NoUpdate = 1 -/obj/item/storage/proc/finish_bulk_removal() - update_ui_after_item_removal() - update_icon() - -//This proc is called when you want to place an item into the storage item. -/obj/item/storage/attackby(obj/item/W, mob/user) - . = ..() - if (.) //if the item was used as a crafting component, just return - return - - if(isrobot(user) && (W == user.get_active_hand())) - return //Robots can't store their modules. - - if(!can_be_inserted(W, user)) - return - - W.add_fingerprint(user) - return handle_item_insertion(W) - -/obj/item/storage/attack_hand(mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.l_store == src && !H.get_active_hand()) //Prevents opening if it's in a pocket. - H.put_in_hands(src) - H.l_store = null - return - if(H.r_store == src && !H.get_active_hand()) - H.put_in_hands(src) - H.r_store = null - return - - if (src.loc == user) - src.open(user) - else - ..() - storage_ui.on_hand_attack(user) - src.add_fingerprint(user) - return - -/obj/item/storage/proc/gather_all(var/turf/T, var/mob/user) - var/success = 0 - var/failure = 0 - - for(var/obj/item/I in T) - if(!can_be_inserted(I, user, 0)) // Note can_be_inserted still makes noise when the answer is no - failure = 1 - continue - success = 1 - handle_item_insertion(I, 1, 1) // First 1 is no messages, second 1 is no ui updates - if(success && !failure) - to_chat(user, "You put everything into \the [src].") - update_ui_after_item_insertion() - else if(success) - to_chat(user, "You put some things into \the [src].") - update_ui_after_item_insertion() - else - to_chat(user, "You fail to pick anything up with \the [src].") - -/obj/item/storage/verb/toggle_gathering_mode() - set name = "Switch Gathering Method" - set category = "Object" - - collection_mode = !collection_mode - switch (collection_mode) - if(1) - to_chat(usr, "\The [src] now picks up all items in a tile at once.") - if(0) - to_chat(usr, "\The [src] now picks up one item at a time.") - -/obj/item/storage/verb/quick_empty() - set name = "Empty Contents" - set category = "Object" - - if((!ishuman(usr) && (src.loc != usr)) || usr.stat || usr.restrained()) - return - - var/turf/T = get_turf(src) - hide_from(usr) - for(var/obj/item/I in contents) - remove_from_storage(I, T, 1) - finish_bulk_removal() - -/obj/item/storage/Initialize() - . = ..() - if(allow_quick_empty) - verbs += /obj/item/storage/verb/quick_empty - else - verbs -= /obj/item/storage/verb/quick_empty - - if(allow_quick_gather) - verbs += /obj/item/storage/verb/toggle_gathering_mode - else - verbs -= /obj/item/storage/verb/toggle_gathering_mode - - if(isnull(max_storage_space) && !isnull(storage_slots)) - max_storage_space = storage_slots*BASE_STORAGE_COST(max_w_class) - - storage_ui = new storage_ui(src) - prepare_ui() - - if(startswith) - for(var/item_path in startswith) - var/list/data = startswith[item_path] - if(islist(data)) - var/qty = data[1] - var/list/argsl = data.Copy() - argsl[1] = src - for(var/i in 1 to qty) - new item_path(arglist(argsl)) - else - for(var/i in 1 to (isnull(data)? 1 : data)) - new item_path(src) - update_icon() - -/obj/item/storage/emp_act(severity) - if(!istype(src.loc, /mob/living)) - for(var/obj/O in contents) - O.emp_act(severity) - ..() - -/obj/item/storage/attack_self(mob/user) - //Clicking on itself will empty it, if it has the verb to do that. - if(user.get_active_hand() == src) - if(src.verbs.Find(/obj/item/storage/verb/quick_empty)) - src.quick_empty() - return 1 - -/obj/item/storage/proc/make_exact_fit() - storage_slots = contents.len - - can_hold.Cut() - max_w_class = ITEM_SIZE_MIN - max_storage_space = 0 - for(var/obj/item/I in src) - can_hold[I.type]++ - max_w_class = max(I.w_class, max_w_class) - max_storage_space += I.get_storage_cost() - -//Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area). -//Returns -1 if the atom was not found on container. -/atom/proc/storage_depth(atom/container) - var/depth = 0 - var/atom/cur_atom = src - - while (cur_atom && !(cur_atom in container.contents)) - if (isarea(cur_atom)) - return -1 - if (istype(cur_atom.loc, /obj/item/storage)) - depth++ - cur_atom = cur_atom.loc - - if (!cur_atom) - return -1 //inside something with a null loc. - - return depth - -//Like storage depth, but returns the depth to the nearest turf -//Returns -1 if no top level turf (a loc was null somewhere, or a non-turf atom's loc was an area somehow). -/atom/proc/storage_depth_turf() - var/depth = 0 - var/atom/cur_atom = src - - while (cur_atom && !isturf(cur_atom)) - if (isarea(cur_atom)) - return -1 - if (istype(cur_atom.loc, /obj/item/storage)) - depth++ - cur_atom = cur_atom.loc - - if (!cur_atom) - return -1 //inside something with a null loc. - - return depth - -/obj/item/proc/get_storage_cost() - //If you want to prevent stuff above a certain w_class from being stored, use max_w_class - return BASE_STORAGE_COST(w_class) diff --git a/code/game/objects/items/weapons/storage/storage_ui/default.dm b/code/game/objects/items/weapons/storage/storage_ui/default.dm deleted file mode 100644 index 9f872d95aa2a..000000000000 --- a/code/game/objects/items/weapons/storage/storage_ui/default.dm +++ /dev/null @@ -1,251 +0,0 @@ -/datum/storage_ui/default - var/list/is_seeing = new/list() //List of mobs which are currently seeing the contents of this item's storage - - var/obj/screen/storage/boxes - var/obj/screen/storage/storage_start //storage UI - var/obj/screen/storage/storage_continue - var/obj/screen/storage/storage_end - var/obj/screen/storage/stored_start - var/obj/screen/storage/stored_continue - var/obj/screen/storage/stored_end - var/obj/screen/close/closer - -#define storage_ui_default "LEFT+7,BOTTOM+7 to LEFT+10,BOTTOM+8" -/datum/storage_ui/default/New(var/storage) - ..() - boxes = new /obj/screen/storage( ) - boxes.SetName("storage") - boxes.master = storage - boxes.icon_state = "block" - boxes.screen_loc = storage_ui_default - boxes.layer = HUD_BASE_LAYER - - storage_start = new /obj/screen/storage( ) - storage_start.SetName("storage") - storage_start.master = storage - storage_start.icon_state = "storage_start" - storage_start.screen_loc = storage_ui_default - storage_start.layer = HUD_BASE_LAYER - storage_continue = new /obj/screen/storage( ) - storage_continue.SetName("storage") - storage_continue.master = storage - storage_continue.icon_state = "storage_continue" - storage_continue.screen_loc = storage_ui_default - storage_continue.layer = HUD_BASE_LAYER - storage_end = new /obj/screen/storage( ) - storage_end.SetName("storage") - storage_end.master = storage - storage_end.icon_state = "storage_end" - storage_end.screen_loc = storage_ui_default - storage_end.layer = HUD_BASE_LAYER - - stored_start = new /obj //we just need these to hold the icon - stored_start.icon_state = "stored_start" - stored_start.layer = HUD_BASE_LAYER - stored_continue = new /obj - stored_continue.icon_state = "stored_continue" - stored_continue.layer = HUD_BASE_LAYER - stored_end = new /obj - stored_end.icon_state = "stored_end" - stored_end.layer = HUD_BASE_LAYER - - closer = new /obj/screen/close( ) - closer.master = storage - closer.icon_state = "x" - closer.layer = HUD_BASE_LAYER - -/datum/storage_ui/default/Destroy() - close_all() - QDEL_NULL(boxes) - QDEL_NULL(storage_start) - QDEL_NULL(storage_continue) - QDEL_NULL(storage_end) - QDEL_NULL(stored_start) - QDEL_NULL(stored_continue) - QDEL_NULL(stored_end) - QDEL_NULL(closer) - . = ..() - -/datum/storage_ui/default/on_open(var/mob/user) - if (user.s_active) - user.s_active.close(user) - -/datum/storage_ui/default/after_close(var/mob/user) - user.s_active = null - -/datum/storage_ui/default/on_insertion(var/mob/user) - if(user.s_active) - user.s_active.show_to(user) - -/datum/storage_ui/default/on_pre_remove(var/mob/user, var/obj/item/W) - for(var/mob/M in range(1, storage.loc)) - if (M.s_active == storage) - if (M.client) - M.client.screen -= W - -/datum/storage_ui/default/on_post_remove(var/mob/user) - if(user?.s_active) - user.s_active.show_to(user) - -/datum/storage_ui/default/on_hand_attack(var/mob/user) - for(var/mob/M in range(1)) - if (M.s_active == storage) - storage.close(M) - -/datum/storage_ui/default/show_to(var/mob/user) - if(user.s_active != storage) - for(var/obj/item/I in storage) - if(I.on_found(user)) - return - if(user.s_active) - user.s_active.hide_from(user) - user.client.screen -= boxes - user.client.screen -= storage_start - user.client.screen -= storage_continue - user.client.screen -= storage_end - user.client.screen -= closer - user.client.screen -= storage.contents - user.client.screen += closer - user.client.screen += storage.contents - if(storage.storage_slots) - user.client.screen += boxes - else - user.client.screen += storage_start - user.client.screen += storage_continue - user.client.screen += storage_end - is_seeing |= user - user.s_active = storage - -/datum/storage_ui/default/hide_from(var/mob/user) - is_seeing -= user - if(!user.client) - return - user.client.screen -= boxes - user.client.screen -= storage_start - user.client.screen -= storage_continue - user.client.screen -= storage_end - user.client.screen -= closer - user.client.screen -= storage.contents - if(user.s_active == storage) - user.s_active = null - -//Creates the storage UI -/datum/storage_ui/default/prepare_ui() - //if storage slots is null then use the storage space UI, otherwise use the slots UI - if(storage.storage_slots == null) - space_orient_objs() - else - slot_orient_objs() - -/datum/storage_ui/default/close_all() - for(var/mob/M in can_see_contents()) - storage.close(M) - . = 1 - -/datum/storage_ui/default/proc/can_see_contents() - var/list/cansee = list() - for(var/mob/M in is_seeing) - if(M.s_active == storage && M.client) - cansee |= M - else - is_seeing -= M - return cansee - -//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. -//The numbers are calculated from the bottom-left The bottom-left slot being 1,1. -/datum/storage_ui/default/proc/orient_objs(tx, ty, mx, my) - var/cx = tx - var/cy = ty - boxes.screen_loc = "LEFT+[tx],BOTTOM+[ty] to LEFT+[mx],BOTTOM+[my]" - for(var/obj/O in storage.contents) - O.screen_loc = "LEFT+[cx],BOTTOM+[cy]" - O.hud_layerise() - cx++ - if (cx > mx) - cx = tx - cy-- - closer.screen_loc = "LEFT+[mx+1],BOTTOM+[my]" - return - -//This proc determins the size of the inventory to be displayed. Please touch it only if you know what you're doing. -/datum/storage_ui/default/proc/slot_orient_objs() - var/adjusted_contents = storage.contents.len - var/row_num = 0 - var/col_count = min(7,storage.storage_slots) -1 - if (adjusted_contents > 7) - row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. - arrange_item_slots(row_num, col_count) - -//This proc draws out the inventory and places the items on it. It uses the standard position. -/datum/storage_ui/default/proc/arrange_item_slots(var/rows, var/cols) - var/cx = 4 - var/cy = 2+rows - boxes.screen_loc = "LEFT+4:16,BOTTOM+2:16 to LEFT+[4+cols]:16,BOTTOM+[2+rows]:16" - - for(var/obj/O in storage.contents) - O.screen_loc = "LEFT+[cx]:16,BOTTOM+[cy]:16" - O.maptext = "" - O.hud_layerise() - cx++ - if (cx > (4+cols)) - cx = 4 - cy-- - - closer.screen_loc = "LEFT+[4+cols+1]:16,BOTTOM+2:16" - -/datum/storage_ui/default/proc/space_orient_objs() - - var/baseline_max_storage_space = DEFAULT_BOX_STORAGE //storage size corresponding to 224 pixels - var/storage_cap_width = 2 //length of sprite for start and end of the box representing total storage space - var/stored_cap_width = 4 //length of sprite for start and end of the box representing the stored item - var/storage_width = min( round( 224 * storage.max_storage_space/baseline_max_storage_space ,1) ,284) //length of sprite for the box representing total storage space - - storage_start.overlays.Cut() - - var/matrix/M = matrix() - M.Scale((storage_width-storage_cap_width*2+3)/32,1) - storage_continue.transform = M - - storage_start.screen_loc = "LEFT+4:16,BOTTOM+2:16" - storage_continue.screen_loc = "LEFT+4:[storage_cap_width+(storage_width-storage_cap_width*2)/2+2],BOTTOM+2:16" - storage_end.screen_loc = "LEFT+4:[19+storage_width-storage_cap_width],BOTTOM+2:16" - - var/startpoint = 0 - var/endpoint = 1 - - for(var/obj/item/O in storage.contents) - startpoint = endpoint + 1 - endpoint += storage_width * O.get_storage_cost()/storage.max_storage_space - - var/matrix/M_start = matrix() - var/matrix/M_continue = matrix() - var/matrix/M_end = matrix() - M_start.Translate(startpoint,0) - M_continue.Scale((endpoint-startpoint-stored_cap_width*2)/32,1) - M_continue.Translate(startpoint+stored_cap_width+(endpoint-startpoint-stored_cap_width*2)/2 - 16,0) - M_end.Translate(endpoint-stored_cap_width,0) - stored_start.transform = M_start - stored_continue.transform = M_continue - stored_end.transform = M_end - storage_start.overlays += stored_start - storage_start.overlays += stored_continue - storage_start.overlays += stored_end - - O.screen_loc = "LEFT+4:[round((startpoint+endpoint)/2)+2],BOTTOM+2:16" - O.maptext = "" - O.hud_layerise() - - closer.screen_loc = "LEFT+4:[storage_width+19],BOTTOM+2:16" - -// Sets up numbered display to show the stack size of each stored mineral -// NOTE: numbered display is turned off currently because it's broken -/datum/storage_ui/default/sheetsnatcher/prepare_ui(var/mob/user) - var/adjusted_contents = storage.contents.len - - var/row_num = 0 - var/col_count = min(7,storage.storage_slots) -1 - if (adjusted_contents > 7) - row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. - arrange_item_slots(row_num, col_count) - if(user && user.s_active) - user.s_active.show_to(user) diff --git a/code/game/objects/items/weapons/storage/storage_ui/storage_ui.dm b/code/game/objects/items/weapons/storage/storage_ui/storage_ui.dm deleted file mode 100644 index 44fce6ca5e01..000000000000 --- a/code/game/objects/items/weapons/storage/storage_ui/storage_ui.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/storage_ui - var/obj/item/storage/storage - -/datum/storage_ui/New(var/storage) - src.storage = storage - ..() - -/datum/storage_ui/Destroy() - storage = null - . = ..() - -/datum/storage_ui/proc/show_to(var/mob/user) - return - -/datum/storage_ui/proc/hide_from(var/mob/user) - return - -/datum/storage_ui/proc/prepare_ui() - return - -/datum/storage_ui/proc/close_all() - return - -/datum/storage_ui/proc/on_open(var/mob/user) - return - -/datum/storage_ui/proc/after_close(var/mob/user) - return - -/datum/storage_ui/proc/on_insertion(var/mob/user) - return - -/datum/storage_ui/proc/on_pre_remove(var/mob/user, var/obj/item/W) - return - -/datum/storage_ui/proc/on_post_remove(var/mob/user, var/obj/item/W) - return - -/datum/storage_ui/proc/on_hand_attack(var/mob/user) - return diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm index 0b2ad34c32e4..61fd4e38f25c 100644 --- a/code/game/objects/items/weapons/storage/toolbox.dm +++ b/code/game/objects/items/weapons/storage/toolbox.dm @@ -1,67 +1,106 @@ -/obj/item/storage/toolbox +/obj/item/toolbox name = "toolbox" desc = "Bright red toolboxes like these are one of the most common sights in maintenance corridors on virtually every ship in the galaxy." - icon = 'icons/obj/items/storage/toolbox.dmi' - icon_state = "red" - item_state = "toolbox_red" + icon = 'icons/obj/items/storage/toolboxes/toolbox_red.dmi' + icon_state = ICON_STATE_WORLD obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 20 attack_cooldown = 21 melee_accuracy_bonus = -15 - throwforce = 10 throw_speed = 1 throw_range = 7 w_class = ITEM_SIZE_LARGE - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_LARGEBOX_STORAGE //enough to hold all starting contents - origin_tech = "{'combat':1}" - attack_verb = list("robusted") - use_sound = 'sound/effects/storage/toolbox.ogg' + storage = /datum/storage/toolbox + origin_tech = @'{"combat":1}' + attack_verb = "robusted" + material = /decl/material/solid/metal/aluminium + _base_attack_force = 20 -/obj/item/storage/toolbox/emergency +/obj/item/toolbox/emergency name = "emergency toolbox" - startswith = list( + +/obj/item/toolbox/emergency/WillContain() + return list( + new /datum/atom_creator/weighted(list(/obj/item/flashlight, /obj/item/flashlight/flare, /obj/item/flashlight/flare/glowstick/red)), /obj/item/crowbar/red, - /obj/item/extinguisher/mini, - /obj/item/radio, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/radio/shortwave, /obj/item/weldingtool/mini, - /obj/item/welder_tank/mini + /obj/item/chems/welder_tank/mini ) -/obj/item/storage/toolbox/emergency/Initialize() - . = ..() - var/item = pick(list(/obj/item/flashlight, /obj/item/flashlight/flare, /obj/item/flashlight/flare/glowstick/red)) - new item(src) - - -/obj/item/storage/toolbox/mechanical +/obj/item/toolbox/mechanical name = "mechanical toolbox" desc = "Bright blue toolboxes like these are one of the most common sights in maintenance corridors on virtually every ship in the galaxy." - icon_state = "blue" - item_state = "toolbox_blue" - startswith = list(/obj/item/screwdriver, /obj/item/wrench, /obj/item/weldingtool, /obj/item/crowbar, /obj/item/scanner/gas, /obj/item/wirecutters) + icon = 'icons/obj/items/storage/toolboxes/toolbox_blue.dmi' -/obj/item/storage/toolbox/electrical +/obj/item/toolbox/mechanical/WillContain() + return list( + /obj/item/screwdriver, + /obj/item/wrench, + /obj/item/weldingtool, + /obj/item/crowbar, + /obj/item/scanner/gas, + /obj/item/wirecutters + ) + +/obj/item/toolbox/electrical name = "electrical toolbox" desc = "Bright yellow toolboxes like these are one of the most common sights in maintenance corridors on virtually every ship in the galaxy." - icon_state = "yellow" - item_state = "toolbox_yellow" - startswith = list(/obj/item/screwdriver, /obj/item/wirecutters, /obj/item/t_scanner, /obj/item/crowbar) + icon = 'icons/obj/items/storage/toolboxes/toolbox_yellow.dmi' + -/obj/item/storage/toolbox/electrical/Initialize() - . = ..() - new /obj/item/stack/cable_coil/random(src,30) - new /obj/item/stack/cable_coil/random(src,30) - if(prob(5)) - new /obj/item/clothing/gloves/insulated(src) - else - new /obj/item/stack/cable_coil/random(src,30) +/obj/item/toolbox/electrical/WillContain() + return list( + new /datum/atom_creator/weighted(list(/obj/item/clothing/gloves/insulated = 5, /obj/item/stack/cable_coil/random = 95)), + /obj/item/stack/cable_coil/random = 2, + /obj/item/screwdriver, + /obj/item/wirecutters, + /obj/item/t_scanner, + /obj/item/crowbar + ) -/obj/item/storage/toolbox/syndicate +/obj/item/toolbox/syndicate name = "black and red toolbox" desc = "A toolbox in black, with stylish red trim. This one feels particularly heavy, yet balanced." - icon_state = "syndicate" - item_state = "toolbox_syndi" - origin_tech = "{'combat':1,'esoteric':1}" + icon = 'icons/obj/items/storage/toolboxes/toolbox_black_red.dmi' + origin_tech = @'{"combat":1,"esoteric":1}' attack_cooldown = 10 - startswith = list(/obj/item/clothing/gloves/insulated, /obj/item/screwdriver, /obj/item/wrench, /obj/item/weldingtool, /obj/item/crowbar, /obj/item/wirecutters, /obj/item/multitool) + +/obj/item/toolbox/syndicate/WillContain() + return list( + /obj/item/clothing/gloves/insulated, + /obj/item/screwdriver, + /obj/item/wrench, + /obj/item/weldingtool, + /obj/item/crowbar, + /obj/item/wirecutters, + /obj/item/multitool + ) + +/obj/item/toolbox/syndicate/powertools/WillContain() + return list( + /obj/item/clothing/gloves/insulated, + /obj/item/tool/power_drill, + /obj/item/weldingtool/electric, + /obj/item/tool/hydraulic_cutter, + /obj/item/multitool + ) + +/obj/item/toolbox/repairs + name = "electronics toolbox" + desc = "A box full of boxes, with electrical machinery parts and tools needed to get them where they're needed." + icon = 'icons/obj/items/storage/toolboxes/toolbox_yellow_striped.dmi' + +/obj/item/toolbox/repairs/WillContain() + return list( + /obj/item/stack/cable_coil, + /obj/item/screwdriver, + /obj/item/wrench, + /obj/item/crowbar, + /obj/item/wirecutters, + /obj/item/box/parts_pack/manipulator, + /obj/item/box/parts_pack/laser, + /obj/item/box/parts_pack/capacitor, + /obj/item/box/parts_pack/keyboard, + /obj/item/box/parts + ) diff --git a/code/game/objects/items/weapons/storage/trays.dm b/code/game/objects/items/weapons/storage/trays.dm deleted file mode 100644 index e68149b92362..000000000000 --- a/code/game/objects/items/weapons/storage/trays.dm +++ /dev/null @@ -1,143 +0,0 @@ -// New and improved(?) trays. Apologies to Agouri, and Doohl, wherever you may be. - -/obj/item/storage/tray - name = "tray" - icon = 'icons/obj/food.dmi' - icon_state = "tray_material" - desc = "A tray to serve food on." - force = 4 - throwforce = 10.0 - throw_speed = 1 - throw_range = 5 - melee_accuracy_bonus = -10 - w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_BOX_STORAGE - attack_verb = list("served","slammed","hit") - use_to_pickup = 1 - allow_quick_gather = 1 - use_sound = null - - var/cooldown = 0 //Cooldown for banging the tray with a rolling pin. based on world.time. very silly - - material = /decl/material/solid/cardboard - applies_material_colour = TRUE - applies_material_name = TRUE - -/obj/item/storage/tray/resolve_attackby(var/atom/A, mob/user) - if(istype(A, /obj/item/storage)) //Disallow putting in bags without raising w_class. Don't know why though, it was part of the old trays - to_chat(user, SPAN_WARNING("The tray won't fit in \the [A].")) - return - . = ..() - -/obj/item/storage/tray/gather_all(var/turf/T, var/mob/user) - ..() - update_icon() - -/obj/item/storage/tray/afterattack(atom/target, mob/user, proximity_flag, click_parameters) - . = ..() - if(!proximity_flag) - return - if(istype(target, /obj/structure/table)) - dump_contents(user, get_turf(target)) - -/obj/item/storage/tray/proc/scatter_contents(var/neatly = FALSE, target_loc = get_turf(src)) - set waitfor = 0 - for(var/obj/item/I in contents) - if(remove_from_storage(I, target_loc) && !neatly) - I.throw_at(get_edge_target_turf(I.loc, pick(GLOB.alldirs)), rand(1,3), round(10/I.w_class)) - update_icon() - -/obj/item/storage/tray/shatter(consumed) - scatter_contents() - . = ..() - -/obj/item/storage/tray/attack(mob/living/carbon/M, mob/living/carbon/user) - if((MUTATION_CLUMSY in user.mutations) && prob(50)) // There is a better way to do this but I'll be damned if I'm the one to fix it. - to_chat(user, SPAN_DANGER("You accidentally slam yourself with the [src]!")) - user.Weaken(1) - user.take_organ_damage(2) - if(prob(50)) - playsound(M, hitsound, 50, 1) - . = TRUE - else - . = ..() - if(.) - scatter_contents() - -/obj/item/storage/tray/attackby(obj/item/W, mob/user) // Keeping this from old trays because... i guess? - if(istype(W, /obj/item/kitchen/rollingpin)) - if(cooldown < world.time - 25) - user.visible_message(SPAN_WARNING("\The [user] bashes \the [src] with \the [W]!")) - playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) - cooldown = world.time - else - ..() - -/obj/item/storage/tray/dump_contents(var/mob/user, turf/new_loc = loc) - if(!isturf(new_loc)) //to handle hand switching - return FALSE - if(user) - close(user) - if(!(locate(/obj/structure/table) in new_loc) && user && contents.len) - visible_message(SPAN_DANGER("Everything falls off the [name]! Good job, [user].")) - scatter_contents(FALSE, new_loc) - else - scatter_contents(TRUE, new_loc) - return TRUE - -/obj/item/storage/tray/dropped(mob/user) - . = ..() - dump_contents(user) - -/obj/item/storage/tray/on_update_icon() - ..() - overlays.Cut() - for(var/obj/item/I in contents) - var/mutable_appearance/MA = new(I) - MA.layer = FLOAT_LAYER - MA.appearance_flags = RESET_COLOR - overlays += MA - -/obj/item/storage/tray/examine(mob/user) // So when you look at the tray you can see whats on it. - . = ..() - if(.) - if(contents.len) - var/tray_examine = list() - for(var/obj/item/I in contents) - tray_examine += "\a [I.name]" - to_chat(user, "There is [english_list(tray_examine)] on the tray.") - else - to_chat(user, "\The [src] is empty.") - -/* ------------------------------------------------------------------ -TRAY TYPES GO HERE ------------------------------------------------------------------ - */ - -/obj/item/storage/tray/wood - name = "tray" //material names are automatic kay? - desc = "A wooden tray to serve food on." - material = /decl/material/solid/wood - -/obj/item/storage/tray/metal - obj_flags = OBJ_FLAG_CONDUCTIBLE - -/obj/item/storage/tray/metal/attack(mob/living/carbon/M, mob/living/carbon/user) // So metal trays make the fun noise - hitsound = pick('sound/items/trayhit1.ogg','sound/items/trayhit2.ogg') - . = ..() - -/obj/item/storage/tray/metal/aluminium - name = "tray" - desc = "An aluminium tray to serve food on." - material = /decl/material/solid/metal/aluminium - -/obj/item/storage/tray/metal/silver - name = "platter" - desc = "You lazy bum." - material = /decl/material/solid/metal/silver - -/obj/item/storage/tray/metal/gold - name = "platter" - desc = "A gold tray to serve food on. But oh sofancy." - material = /decl/material/solid/metal/gold \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 604f4752f1c9..a6eb745f50c6 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -1,176 +1,161 @@ -/obj/item/storage/box/syndie_kit +/obj/item/box/syndie_kit name = "box" desc = "A sleek, sturdy box." icon_state = "box_of_doom" //For uplink kits that provide bulkier items -/obj/item/storage/backpack/satchel/syndie_kit +/obj/item/backpack/satchel/syndie_kit desc = "A sleek, sturdy satchel." icon = 'icons/obj/items/storage/backpack/satchel_grey.dmi' //In case an uplink kit provides a lot of gear -/obj/item/storage/backpack/dufflebag/syndie_kit +/obj/item/backpack/dufflebag/syndie_kit name = "black dufflebag" desc = "A sleek, sturdy dufflebag." icon = 'icons/obj/items/storage/backpack/dufflebag_syndie.dmi' -/obj/item/storage/box/syndie_kit/imp_freedom - startswith = list(/obj/item/implanter/freedom) +/obj/item/box/syndie_kit/imp_freedom/WillContain() + return list(/obj/item/implanter/freedom) -/obj/item/storage/box/syndie_kit/imp_uplink - startswith = list(/obj/item/implanter/uplink) +/obj/item/box/syndie_kit/imp_uplink/WillContain() + return list(/obj/item/implanter/uplink) -/obj/item/storage/box/syndie_kit/imp_compress - startswith = list(/obj/item/implanter/compressed) +/obj/item/box/syndie_kit/imp_compress/WillContain() + return list(/obj/item/implanter/compressed) -/obj/item/storage/box/syndie_kit/imp_explosive - startswith = list( - /obj/item/implanter/explosive, - /obj/item/implantpad +/obj/item/box/syndie_kit/imp_explosive/WillContain() + return list( + /obj/item/implanter/explosive, + /obj/item/implantpad ) -/obj/item/storage/box/syndie_kit/imp_imprinting - startswith = list( - /obj/item/implanter/imprinting, - /obj/item/implantpad, - /obj/item/chems/hypospray/autoinjector/hallucinogenics +/obj/item/box/syndie_kit/imp_imprinting/WillContain() + return list( + /obj/item/implanter/imprinting, + /obj/item/implantpad, + /obj/item/chems/hypospray/autoinjector/hallucinogenics ) // Space suit uplink kit -/obj/item/storage/backpack/satchel/syndie_kit/space - //name = "\improper EVA gear pack" - - startswith = list( - /obj/item/clothing/suit/space/void/merc, - /obj/item/clothing/head/helmet/space/void/merc, - /obj/item/clothing/mask/gas/syndicate, - /obj/item/tank/emergency/oxygen/double, +/obj/item/backpack/satchel/syndie_kit/space/WillContain() + return list( + /obj/item/clothing/suit/space/void/merc, + /obj/item/clothing/head/helmet/space/void/merc, + /obj/item/clothing/mask/gas/syndicate, + /obj/item/tank/emergency/oxygen/double, ) // Chameleon uplink kit -/obj/item/storage/backpack/chameleon/sydie_kit - startswith = list( - /obj/item/clothing/under/chameleon, - /obj/item/clothing/suit/chameleon, - /obj/item/clothing/shoes/chameleon, - /obj/item/clothing/head/chameleon, - /obj/item/clothing/mask/chameleon, - /obj/item/storage/box/syndie_kit/chameleon, - /obj/item/gun/energy/chameleon, +/obj/item/backpack/chameleon/sydie_kit + material = /decl/material/solid/metal/gold + matter = list( + /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE + ) + +/obj/item/backpack/chameleon/sydie_kit/WillContain() + return list( + /obj/item/clothing/jumpsuit/chameleon, + /obj/item/clothing/shirt/chameleon, + /obj/item/clothing/pants/chameleon, + /obj/item/clothing/suit/chameleon, + /obj/item/clothing/shoes/chameleon, + /obj/item/clothing/head/chameleon, + /obj/item/clothing/mask/chameleon, + /obj/item/box/syndie_kit/chameleon, + /obj/item/gun/energy/chameleon, ) -/obj/item/storage/box/syndie_kit/chameleon - startswith = list( - /obj/item/clothing/gloves/chameleon, - /obj/item/clothing/glasses/chameleon, - /obj/item/radio/headset/chameleon, - /obj/item/clothing/accessory/chameleon, - /obj/item/clothing/accessory/chameleon, - /obj/item/clothing/accessory/chameleon +/obj/item/box/syndie_kit/chameleon/WillContain() + return list( + /obj/item/clothing/gloves/chameleon, + /obj/item/clothing/glasses/chameleon, + /obj/item/radio/headset/chameleon, + /obj/item/clothing/chameleon, + /obj/item/clothing/chameleon, + /obj/item/clothing/chameleon ) // Clerical uplink kit -/obj/item/storage/backpack/satchel/syndie_kit/clerical - startswith = list( - /obj/item/stack/package_wrap/twenty_five, - /obj/item/hand_labeler, - /obj/item/stamp/chameleon, - /obj/item/pen/chameleon, - /obj/item/destTagger, +/obj/item/backpack/satchel/syndie_kit/clerical/WillContain() + return list( + /obj/item/stack/package_wrap/twenty_five, + /obj/item/hand_labeler, + /obj/item/stamp/chameleon, + /obj/item/pen/chameleon, + /obj/item/destTagger, ) -/obj/item/storage/box/syndie_kit/spy - startswith = list( +/obj/item/box/syndie_kit/spy/WillContain() + return list( /obj/item/spy_bug = 6, /obj/item/spy_monitor ) -/obj/item/storage/box/syndie_kit/silenced - startswith = list( +/obj/item/box/syndie_kit/silenced/WillContain() + return list( /obj/item/gun/projectile/pistol/holdout, /obj/item/silencer, /obj/item/ammo_magazine/pistol/small ) -/obj/item/storage/backpack/satchel/syndie_kit/revolver - startswith = list( +/obj/item/backpack/satchel/syndie_kit/revolver/WillContain() + return list( /obj/item/gun/projectile/revolver, /obj/item/ammo_magazine/speedloader ) -/obj/item/storage/box/syndie_kit/toxin - startswith = list( +/obj/item/box/syndie_kit/toxin/WillContain() + return list( /obj/item/chems/glass/beaker/vial/random/toxin, /obj/item/chems/syringe ) -/obj/item/storage/box/syndie_kit/syringegun - startswith = list( +/obj/item/box/syndie_kit/syringegun/WillContain() + return list( /obj/item/gun/launcher/syringe/disguised, /obj/item/syringe_cartridge = 4, /obj/item/chems/syringe = 4 ) -/obj/item/storage/box/syndie_kit/cigarette +/obj/item/box/syndie_kit/cigarette name = "\improper Tricky smokes" desc = "Smokes so good, you'd think it was a trick!" -/obj/item/storage/box/syndie_kit/cigarette/Initialize() - . = ..() - var/obj/item/storage/fancy/cigarettes/pack - pack = new /obj/item/storage/fancy/cigarettes(src) - fill_cigarre_package(pack, list(/decl/material/solid/metal/aluminium = 1, /decl/material/solid/potassium = 1, /decl/material/solid/sulfur = 1)) - pack.desc += " 'F' has been scribbled on it." - - pack = new /obj/item/storage/fancy/cigarettes(src) - fill_cigarre_package(pack, list(/decl/material/solid/metal/aluminium = 1, /decl/material/solid/potassium = 1, /decl/material/solid/sulfur = 1)) - pack.desc += " 'F' has been scribbled on it." - - pack = new /obj/item/storage/fancy/cigarettes(src) - fill_cigarre_package(pack, list(/decl/material/solid/potassium = 1, /decl/material/liquid/nutriment/sugar = 1, /decl/material/solid/phosphorus = 1)) - pack.desc += " 'S' has been scribbled on it." - - pack = new /obj/item/storage/fancy/cigarettes(src) - fill_cigarre_package(pack, list(/decl/material/solid/potassium = 1, /decl/material/liquid/nutriment/sugar = 1, /decl/material/solid/phosphorus = 1)) - pack.desc += " 'S' has been scribbled on it." - - pack = new /obj/item/storage/fancy/cigarettes(src) - fill_cigarre_package(pack, list(/decl/material/liquid/antitoxins = 1, /decl/material/solid/silicon = 1, /decl/material/liquid/fuel/hydrazine = 1)) - pack.desc += " 'MB' has been scribbled on it." - - pack = new /obj/item/storage/fancy/cigarettes(src) - fill_cigarre_package(pack, list(/decl/material/liquid/regenerator = 4)) - pack.desc += " 'T' has been scribbled on it." - - new /obj/item/flame/lighter/zippo(src) - -/proc/fill_cigarre_package(var/obj/item/storage/fancy/cigarettes/C, var/list/reagents) - for(var/reagent in reagents) - C.reagents.add_reagent(reagent, reagents[reagent] * C.max_storage_space) +/obj/item/box/syndie_kit/cigarette/WillContain() + return list( + /obj/item/box/fancy/cigarettes/covert/flash_powder = 2, + /obj/item/box/fancy/cigarettes/covert/chemsmoke = 2, + /obj/item/box/fancy/cigarettes/covert/mindbreak, + /obj/item/box/fancy/cigarettes/covert/tricord, + /obj/item/flame/fuelled/lighter/zippo/random, + ) //Rig Electrowarfare and Voice Synthesiser kit -/obj/item/storage/backpack/satchel/syndie_kit/ewar_voice - startswith = list( - /obj/item/rig_module/electrowarfare_suite, - /obj/item/rig_module/voice, +/obj/item/backpack/satchel/syndie_kit/ewar_voice/WillContain() + return list( + /obj/item/rig_module/electrowarfare_suite, + /obj/item/rig_module/voice, ) -/obj/item/storage/secure/briefcase/heavysniper - startswith = list( - /obj/item/gun/projectile/heavysniper, - /obj/item/storage/box/ammo/sniperammo +/obj/item/secure_storage/briefcase/heavysniper/WillContain() + return list( + /obj/item/gun/projectile/bolt_action/sniper, + /obj/item/box/ammo/sniperammo ) -/obj/item/storage/secure/briefcase/heavysniper/Initialize() +/obj/item/secure_storage/briefcase/heavysniper/Initialize(ml, material_key) . = ..() - make_exact_fit() - -/obj/item/storage/secure/briefcase/money + if(length(contents) && storage) + storage.make_exact_fit() - startswith = list(/obj/item/cash/c1000 = 10) +/obj/item/secure_storage/briefcase/money/WillContain() + return list(/obj/item/cash/c1000 = 10) -/obj/item/storage/backpack/satchel/syndie_kit/armor - startswith = list( +/obj/item/backpack/satchel/syndie_kit/armor/WillContain() + return list( /obj/item/clothing/suit/armor/pcarrier/merc, /obj/item/clothing/head/helmet/merc ) diff --git a/code/game/objects/items/weapons/storage/wall_mirror.dm b/code/game/objects/items/weapons/storage/wall_mirror.dm index d581dd34cea1..a69b0d5e135f 100644 --- a/code/game/objects/items/weapons/storage/wall_mirror.dm +++ b/code/game/objects/items/weapons/storage/wall_mirror.dm @@ -1,50 +1,72 @@ -//wip wip wup -/obj/item/storage/mirror +/obj/structure/mirror name = "mirror" desc = "A SalonPro Nano-Mirror(TM) mirror! The leading brand in hair salon products, utilizing nano-machinery to style your hair just right. The black box inside warns against attempting to release the nanomachines." icon = 'icons/obj/watercloset.dmi' icon_state = "mirror" - density = 0 - anchored = 1 - max_w_class = ITEM_SIZE_NORMAL - max_storage_space = DEFAULT_LARGEBOX_STORAGE - use_sound = 'sound/effects/closet_open.ogg' - var/shattered = 0 + density = FALSE + anchored = TRUE + material = /decl/material/solid/glass + matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY) + storage = /datum/storage/structure/mirror + directional_offset = @'{"NORTH":{"y":-29}, "SOUTH":{"y":29}, "EAST":{"x":29}, "WEST":{"x":-29}}' + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + var/shattered = FALSE var/list/ui_users - startswith = list( - /obj/item/haircomb/random, - /obj/item/haircomb/brush, - /obj/random/medical/lite, - /obj/item/lipstick, - /obj/random/lipstick, - /obj/random/soap, - /obj/item/chems/spray/cleaner/deodorant, - /obj/item/towel/random) +/obj/structure/mirror/shuttle_rotate(angle) + . = ..(-angle) // for some reason directions are switched for mirrors? -/obj/item/storage/mirror/MouseDrop(obj/over_object) - if(!(. = ..())) - return +/obj/structure/mirror/WillContain() + return list( + /obj/item/grooming/comb/colorable/random, + /obj/item/grooming/brush/colorable/random, + /obj/item/grooming/file, + /obj/random/medical/lite, + /obj/random/lipstick, + /obj/random/eyeshadow, + /obj/random/soap, + /obj/item/chems/spray/cleaner/deodorant, + /obj/item/towel/random + ) + +/obj/structure/mirror/Destroy() + clear_ui_users(ui_users) + . = ..() + +/obj/structure/mirror/storage_inserted(atom/movable/thing) + . = ..() flick("mirror_open",src) -/obj/item/storage/mirror/attack_hand(var/mob/living/carbon/human/user) - use_mirror(user) +/obj/structure/mirror/storage_removed(atom/movable/thing) + . = ..() + flick("mirror_open",src) + +/obj/structure/mirror/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(prob(damage)) + visible_message(SPAN_WARNING("[src] shatters!")) + shatter() + . = ..() -/obj/item/storage/mirror/proc/use_mirror(var/mob/living/carbon/human/user) +/obj/structure/mirror/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HARM)) + return ..() if(shattered) to_chat(user, SPAN_WARNING("You enter the key combination for the style you want on the panel, but the nanomachines inside \the [src] refuse to come out.")) - return - open_mirror_ui(user, ui_users, "SalonPro Nano-Mirror™", mirror = src) + else + open_mirror_ui(user, ui_users, "SalonPro Nano-Mirror™", mirror = src) + return TRUE -/obj/item/storage/mirror/shatter() +/obj/structure/mirror/proc/shatter() if(shattered) return - shattered = 1 + shattered = TRUE icon_state = "mirror_broke" + var/turf/T = get_turf(src) + T.visible_message(SPAN_DANGER("\The [src] [material ? material.destruction_desc : "shatters"]!")) + material.place_shards(T) playsound(src, "shatter", 70, 1) desc = "Oh no, seven years of bad luck!" -/obj/item/storage/mirror/bullet_act(var/obj/item/projectile/Proj) - +/obj/structure/mirror/bullet_act(var/obj/item/projectile/Proj) if(prob(Proj.get_structure_damage() * 2)) if(!shattered) shatter() @@ -52,24 +74,16 @@ playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1) ..() -/obj/item/storage/mirror/attackby(obj/item/W, mob/user) - if(!(. = ..())) - return - flick("mirror_open",src) - if(prob(W.force) && (user.a_intent == I_HURT)) - visible_message("[user] smashes [src] with \the [W]!") - if(!shattered) - shatter() - -/obj/item/storage/mirror/Destroy() - clear_ui_users(ui_users) - . = ..() - /obj/item/mirror name = "mirror" desc = "A SalonPro Nano-Mirror(TM) brand mirror! Now a portable version." icon = 'icons/obj/items/mirror.dmi' icon_state = "mirror" + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/glass = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY + ) var/list/ui_users /obj/item/mirror/attack_self(mob/user) @@ -83,18 +97,17 @@ if(!ishuman(user)) return - var/W = weakref(user) - var/datum/nano_module/appearance_changer/AC = LAZYACCESS(ui_users, W) + var/weakref/user_ref = weakref(user) + var/datum/nano_module/appearance_changer/AC = LAZYACCESS(ui_users, user_ref) if(!AC) AC = new(mirror, user) AC.name = title if(flags) AC.flags = flags - LAZYSET(ui_users, W, AC) + LAZYSET(ui_users, user_ref, AC) AC.ui_interact(user) /proc/clear_ui_users(var/list/ui_users) - for(var/W in ui_users) - var/AC = ui_users[W] - qdel(AC) + for(var/user_ref in ui_users) + qdel(ui_users[user_ref]) LAZYCLEARLIST(ui_users) diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index 6535e5598535..5fcafd398aef 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -1,55 +1,20 @@ -/obj/item/storage/wallet +/obj/item/wallet name = "wallet" desc = "It can hold a few small and personal things." icon = 'icons/obj/items/wallet.dmi' icon_state = "wallet-white" w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_SMALL //Don't worry, see can_hold[] - max_storage_space = 8 - can_hold = list( - /obj/item/cash, - /obj/item/card, - /obj/item/clothing/mask/smokable, - /obj/item/lipstick, - /obj/item/haircomb, - /obj/item/mirror, - /obj/item/clothing/accessory/locket, - /obj/item/clothing/head/hairflower, - /obj/item/flashlight/pen, - /obj/item/flashlight/slime, - /obj/item/seeds, - /obj/item/coin, - /obj/item/dice, - /obj/item/disk, - /obj/item/implant, - /obj/item/implanter, - /obj/item/flame, - /obj/item/paper, - /obj/item/paper_bundle, - /obj/item/pen, - /obj/item/photo, - /obj/item/chems/dropper, - /obj/item/chems/syringe, - /obj/item/chems/pill, - /obj/item/chems/hypospray/autoinjector, - /obj/item/chems/glass/beaker/vial, - /obj/item/radio/headset, - /obj/item/paicard, - /obj/item/stamp, - /obj/item/key, - /obj/item/clothing/accessory/badge, - /obj/item/clothing/accessory/medal, - /obj/item/clothing/accessory/armor/tag, - ) + storage = /datum/storage/wallet slot_flags = SLOT_ID + material = /decl/material/solid/organic/leather var/obj/item/card/id/front_id = null var/obj/item/charge_stick/front_stick = null -/obj/item/storage/wallet/leather +/obj/item/wallet/leather color = COLOR_SEDONA -/obj/item/storage/wallet/Destroy() +/obj/item/wallet/Destroy() if(front_id) front_id.dropInto(loc) front_id = null @@ -58,74 +23,44 @@ front_stick = null . = ..() -/obj/item/storage/wallet/remove_from_storage(obj/item/W, atom/new_location) - . = ..(W, new_location) - if(.) - if(W == front_id) - front_id = null - SetName(initial(name)) - update_icon() - if(W == front_stick) - front_stick = null - -/obj/item/storage/wallet/handle_item_insertion(obj/item/W, prevent_warning = 0) - . = ..(W, prevent_warning) - if(.) - if(!front_id && istype(W, /obj/item/card/id)) - front_id = W - update_icon() - if(!front_stick && istype(W, /obj/item/charge_stick)) - front_stick = W - -/obj/item/storage/wallet/on_update_icon() - overlays.Cut() +/obj/item/wallet/on_update_icon() + . = ..() if(front_id) var/tiny_state = "id-generic" if(("id-"+front_id.icon_state) in icon_states(icon)) tiny_state = "id-"+front_id.icon_state - var/image/tiny_image = new/image(icon, icon_state = tiny_state) - tiny_image.appearance_flags = RESET_COLOR - overlays += tiny_image + add_overlay(overlay_image(icon, tiny_state, flags = RESET_COLOR)) -/obj/item/storage/wallet/GetIdCard() - return front_id +/obj/item/wallet/GetIdCards(list/exceptions) + . = ..() + if(istype(front_id) && !is_type_in_list(front_id, exceptions)) + LAZYDISTINCTADD(., front_id) -/obj/item/storage/wallet/GetChargeStick() +/obj/item/wallet/GetChargeStick() return front_stick -/obj/item/storage/wallet/GetAccess() - var/obj/item/I = GetIdCard() - if(I) - return I.GetAccess() - else - return ..() +/obj/item/wallet/random/WillContain() + . = list( + new /datum/atom_creator/weighted(list(/obj/item/cash/c10,/obj/item/cash/c100,/obj/item/cash/c1000,/obj/item/cash/c20,/obj/item/cash/c200,/obj/item/cash/c50, /obj/item/cash/c500)), + new /datum/atom_creator/weighted(list(/obj/item/coin/silver, /obj/item/coin/silver, /obj/item/coin/gold, /obj/item/coin/iron, /obj/item/coin/iron, /obj/item/coin/iron)), + ) + if(prob(50)) + . += new /datum/atom_creator/weighted(list(/obj/item/cash/c10,/obj/item/cash/c100,/obj/item/cash/c1000,/obj/item/cash/c20,/obj/item/cash/c200,/obj/item/cash/c50, /obj/item/cash/c500)) -/obj/item/storage/wallet/random/Initialize() +/obj/item/wallet/random/Initialize(ml, material_key) . = ..() - var/item1_type = pick( /obj/item/cash/c10,/obj/item/cash/c100,/obj/item/cash/c1000,/obj/item/cash/c20,/obj/item/cash/c200,/obj/item/cash/c50, /obj/item/cash/c500) - var/item2_type - if(prob(50)) - item2_type = pick( /obj/item/cash/c10,/obj/item/cash/c100,/obj/item/cash/c1000,/obj/item/cash/c20,/obj/item/cash/c200,/obj/item/cash/c50, /obj/item/cash/c500) - var/item3_type = pick( /obj/item/coin/silver, /obj/item/coin/silver, /obj/item/coin/gold, /obj/item/coin/iron, /obj/item/coin/iron, /obj/item/coin/iron ) - - if(item1_type) - new item1_type(src) - if(item2_type) - new item2_type(src) - if(item3_type) - new item3_type(src) update_icon() -/obj/item/storage/wallet/poly +/obj/item/wallet/poly name = "polychromic wallet" desc = "You can recolor it! Fancy! The future is NOW!" -/obj/item/storage/wallet/poly/Initialize() +/obj/item/wallet/poly/Initialize(ml, material_key) . = ..() - color = get_random_colour() + set_color(get_random_colour()) update_icon() -/obj/item/storage/wallet/poly/verb/change_color() +/obj/item/wallet/poly/verb/change_color() set name = "Change Wallet Color" set category = "Object" set desc = "Change the color of the wallet." @@ -137,9 +72,9 @@ var/new_color = input(usr, "Pick a new color", "Wallet Color", color) as color|null if(!new_color || new_color == color || usr.incapacitated()) return - color = new_color + set_color(new_color) -/obj/item/storage/wallet/poly/emp_act() +/obj/item/wallet/poly/emp_act() icon_state = "wallet-emp" update_icon() @@ -147,3 +82,22 @@ if(src) icon_state = initial(icon_state) update_icon() + +/obj/item/wallet/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/remove_id/wallet) + +/decl/interaction_handler/remove_id/wallet + expected_target_type = /obj/item/wallet + examine_desc = "remove an ID card" + +/decl/interaction_handler/remove_id/wallet/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && ishuman(user) + +/decl/interaction_handler/remove_id/wallet/invoked(atom/target, mob/user, obj/item/prop) + if(target?.storage) + var/atom/movable/atom_target = target + var/obj/item/card/id/id = atom_target.GetIdCard() + if (istype(id)) + target.storage.remove_from_storage(user, id) + user.put_in_hands(id) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 56097644a361..e8ffe9555320 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -3,49 +3,50 @@ name = "stunbaton" desc = "A stun baton for incapacitating people with." icon = 'icons/obj/items/weapon/stunbaton.dmi' - icon_state = "stunbaton" - item_state = "baton" - slot_flags = SLOT_BELT - force = 15 - sharp = 0 - edge = 0 - throwforce = 7 + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_NORMAL - origin_tech = "{'combat':2}" - attack_verb = list("beaten") + origin_tech = @'{"combat":2}' + attack_verb = "beaten" base_parry_chance = 30 + material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + ) + item_flags = ITEM_FLAG_IS_WEAPON + _base_attack_force = 15 var/stunforce = 0 var/agonyforce = 30 var/status = 0 //whether the thing is on or not - var/obj/item/cell/bcell var/hitcost = 7 -/obj/item/baton/loaded - bcell = /obj/item/cell/device/high - -/obj/item/baton/Initialize(var/ml) +/obj/item/baton/Initialize(var/ml, var/material_key, var/loaded_cell_type) . = ..(ml) - if(ispath(bcell)) - bcell = new bcell(src) - update_icon() + setup_power_supply(loaded_cell_type) -/obj/item/baton/Destroy() - if(bcell && !ispath(bcell)) - qdel(bcell) - bcell = null - return ..() +/obj/item/baton/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + . = ..(loaded_cell_type, /obj/item/cell/device, /datum/extension/loaded_cell/secured, charge_value) + update_icon() -/obj/item/baton/get_cell() - return bcell +/obj/item/baton/loaded/Initialize(var/ml, var/material_key, var/loaded_cell_type) + return ..(ml, material_key, loaded_cell_type = /obj/item/cell/device/high) + +/obj/item/baton/infinite/Initialize(var/ml, var/material_key, var/loaded_cell_type) + . = ..(ml, material_key, loaded_cell_type = /obj/item/cell/device/infinite) + set_cell_status(1, null) /obj/item/baton/proc/update_status() - if(bcell.charge < hitcost) + var/obj/item/cell/cell = get_cell() + if(cell?.charge < hitcost) status = 0 update_icon() /obj/item/baton/proc/deductcharge(var/chrgdeductamt) - if(bcell) - if(bcell.checked_use(chrgdeductamt)) + var/obj/item/cell/cell = get_cell() + if(cell) + if(cell.checked_use(chrgdeductamt)) update_status() return 1 else @@ -55,69 +56,29 @@ return null /obj/item/baton/on_update_icon() + . = ..() if(status) - icon_state = "[initial(name)]_active" - else if(!bcell) - icon_state = "[initial(name)]_nocell" - else - icon_state = "[initial(name)]" - - if(icon_state == "[initial(name)]_active") - set_light(0.4, 0.1, 1, 2, "#ff6a00") + add_overlay("[icon_state]-active") + set_light(1.5, 2, "#ff6a00") else + if(!get_cell()) + add_overlay("[icon_state]-nocell") set_light(0) -/obj/item/baton/examine(mob/user, distance) - . = ..() - if(distance <= 1) - examine_cell(user) - -// Addition made by Techhead0, thanks for fullfilling the todo! -/obj/item/baton/proc/examine_cell(mob/user) - if(bcell) - to_chat(user, "The baton is [round(bcell.percent())]% charged.") - if(!bcell) - to_chat(user, "The baton does not have a power source installed.") - -/obj/item/baton/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/cell/device)) - if(!bcell && user.unEquip(W)) - W.forceMove(src) - bcell = W - to_chat(user, "You install a cell into the [src].") - update_icon() - else - to_chat(user, "[src] already has a cell.") - else if(isScrewdriver(W)) - if(bcell) - bcell.update_icon() - bcell.dropInto(loc) - bcell = null - to_chat(user, "You remove the cell from the [src].") - status = 0 - update_icon() - else - ..() - /obj/item/baton/attack_self(mob/user) - set_status(!status, user) + set_cell_status(!status, user) add_fingerprint(user) -/obj/item/baton/throw_impact(atom/hit_atom, var/datum/thrownthing/TT) - if(istype(hit_atom,/mob/living)) - apply_hit_effect(hit_atom, hit_zone = ran_zone(TT.target_zone, 30))//more likely to hit the zone you target! - else - ..() - -/obj/item/baton/proc/set_status(var/newstatus, mob/user) - if(bcell && bcell.charge >= hitcost) +/obj/item/baton/proc/set_cell_status(var/newstatus, mob/user) + var/obj/item/cell/cell = get_cell() + if(cell?.charge >= hitcost) if(status != newstatus) change_status(newstatus) to_chat(user, "[src] is now [status ? "on" : "off"].") playsound(loc, "sparks", 75, 1, -1) else change_status(0) - if(!bcell) + if(!cell) to_chat(user, "[src] does not have a power source!") else to_chat(user, "[src] is out of charge.") @@ -130,12 +91,12 @@ status = s update_icon() -/obj/item/baton/attack(mob/M, mob/user) - if(status && (MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, "You accidentally hit yourself with the [src]!") - user.Weaken(30) +/obj/item/baton/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(status && user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + to_chat(user, SPAN_DANGER("You accidentally hit yourself with \the [src]!")) + SET_STATUS_MAX(user, STAT_WEAK, 30) deductcharge(hitcost) - return + return TRUE return ..() /obj/item/baton/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) @@ -146,10 +107,10 @@ var/stun = stunforce var/obj/item/organ/external/affecting = null if(ishuman(target)) - var/mob/living/carbon/human/H = target - affecting = H.get_organ(hit_zone) + var/mob/living/human/H = target + affecting = GET_EXTERNAL_ORGAN(H, hit_zone) var/abuser = user ? "" : "by [user]" - if(user && user.a_intent == I_HURT) + if(user && user.check_intent(I_FLAG_HARM)) . = ..() if(.) return @@ -176,59 +137,51 @@ //stun effects if(status) target.stun_effect_act(stun, agony, hit_zone, src) - msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].") + msg_admin_attack("[key_name(user)] stunned [key_name(target)] with \the [src].") deductcharge(hitcost) if(ishuman(target)) - var/mob/living/carbon/human/H = target - H.forcesay(GLOB.hit_appends) + var/mob/living/human/H = target + H.forcesay(global.hit_appends) return 1 -/obj/item/baton/emp_act(severity) - if(bcell) - bcell.emp_act(severity) //let's not duplicate code everywhere if we don't have to please. - ..() - // Stunbaton module for Security synthetics /obj/item/baton/robot - bcell = null hitcost = 20 // Addition made by Techhead0, thanks for fullfilling the todo! -/obj/item/baton/robot/examine_cell(mob/user) - to_chat(user, "The baton is running off an external power supply.") +/obj/item/baton/robot/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance == 1) + . += SPAN_NOTICE("The baton is running off an external power supply.") // Override proc for the stun baton module, found in PC Security synthetics // Refactored to fix #14470 - old proc defination increased the hitcost beyond // usability without proper checks. // Also hard-coded to be unuseable outside their righteous synthetic owners. /obj/item/baton/robot/attack_self(mob/user) - var/mob/living/silicon/robot/R = isrobot(user) ? user : null // null if the user is NOT a robot - update_cell(R) // takes both robots and null - if (R) + var/mob/living/silicon/robot/robot = isrobot(user) ? user : null // null if the user is NOT a robot + if (robot) return ..() else // Stop pretending and get out of your cardborg suit, human. - to_chat(user, "You don't seem to be able interacting with this by yourself..") + to_chat(user, "You don't seem to be able to interact with this by yourself.") add_fingerprint(user) return 0 -/obj/item/baton/robot/attackby(obj/item/W, mob/user) +/obj/item/baton/robot/attackby(obj/item/used_item, mob/user) + return FALSE + +/obj/item/baton/robot/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + SHOULD_CALL_PARENT(FALSE) return -/obj/item/baton/robot/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - update_cell(isrobot(user) ? user : null) // update the status before we apply the effects +/obj/item/baton/robot/get_cell() + var/mob/living/silicon/robot/holder = loc + if(istype(holder)) + return holder.cell return ..() -// Updates the baton's cell to use user's own cell -// Otherwise, if null (when the user isn't a robot), render it unuseable -/obj/item/baton/robot/proc/update_cell(mob/living/silicon/robot/user) - if (!user) - bcell = null - set_status(0) - else if (!bcell || bcell != user.cell) - bcell = user.cell // if it is null, nullify it anyway - // Traitor variant for Engineering synthetics. /obj/item/baton/robot/electrified_arm name = "electrified arm" @@ -236,9 +189,10 @@ icon_state = "electrified_arm" /obj/item/baton/robot/electrified_arm/on_update_icon() + . = ..() if(status) icon_state = "electrified_arm_active" - set_light(0.4, 0.1, 1, 2, "#006aff") + set_light(1.5, 2, "#006aff") else icon_state = "electrified_arm" set_light(0) @@ -250,10 +204,13 @@ icon = 'icons/obj/items/weapon/stunprod.dmi' icon_state = "stunprod_nocell" item_state = "prod" - force = 3 - throwforce = 5 stunforce = 0 agonyforce = 60 //same force as a stunbaton, but uses way more charge. hitcost = 25 - attack_verb = list("poked") - slot_flags = null \ No newline at end of file + attack_verb = "poked" + slot_flags = null + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE + ) + _base_attack_force = 3 diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm index 75a1fd4a3f46..c4f24a7afcdb 100644 --- a/code/game/objects/items/weapons/surgery_tools.dm +++ b/code/game/objects/items/weapons/surgery_tools.dm @@ -13,47 +13,61 @@ */ /obj/item/retractor name = "retractor" - desc = "Retracts stuff." + desc = "A surgical tool for widening incisions or adjusting bones." icon = 'icons/obj/surgery.dmi' icon_state = "retractor" material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) obj_flags = OBJ_FLAG_CONDUCTIBLE w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':1,'biotech':1}" + origin_tech = @'{"materials":1,"biotech":1}' + drop_sound = 'sound/foley/knifedrop3.ogg' + +/obj/item/retractor/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_RETRACTOR = TOOL_QUALITY_DEFAULT)) /* * Hemostat */ /obj/item/hemostat name = "hemostat" - desc = "You think you have seen this before." + desc = "A surgical tool for clamping veins or manipulating internal organs." icon = 'icons/obj/surgery.dmi' icon_state = "hemostat" material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) obj_flags = OBJ_FLAG_CONDUCTIBLE w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':1,'biotech':1}" + origin_tech = @'{"materials":1,"biotech":1}' attack_verb = list("attacked", "pinched") + drop_sound = 'sound/foley/knifedrop3.ogg' + +/obj/item/hemostat/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_HEMOSTAT = TOOL_QUALITY_DEFAULT)) /* * Cautery */ /obj/item/cautery name = "cautery" - desc = "This stops bleeding." + desc = "A surgical tool for halting bleeding or closing incisions." icon = 'icons/obj/surgery.dmi' icon_state = "cautery" material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE ) obj_flags = OBJ_FLAG_CONDUCTIBLE w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':1,'biotech':1}" - attack_verb = list("burnt") + origin_tech = @'{"materials":1,"biotech":1}' + attack_verb = "burnt" + +/obj/item/cautery/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_CAUTERY = TOOL_QUALITY_DEFAULT)) /* * Surgical Drill @@ -65,12 +79,16 @@ icon_state = "drill" hitsound = 'sound/weapons/circsawhit.ogg' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 15.0 + _base_attack_force = 15 w_class = ITEM_SIZE_NORMAL - origin_tech = "{'materials':1,'biotech':1}" - attack_verb = list("drilled") + origin_tech = @'{"materials":1,"biotech":1}' + attack_verb = "drilled" + +/obj/item/surgicaldrill/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_SURGICAL_DRILL = TOOL_QUALITY_DEFAULT)) /* * Scalpel @@ -81,120 +99,165 @@ icon = 'icons/obj/surgery.dmi' icon_state = "scalpel" obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 10.0 - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - throwforce = 5.0 throw_speed = 3 throw_range = 5 - origin_tech = "{'materials':1,'biotech':1}" + origin_tech = @'{"materials":1,"biotech":1}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + pickup_sound = 'sound/foley/knife1.ogg' + drop_sound = 'sound/foley/knifedrop3.ogg' + _base_attack_force = 10 + var/tool_quality = TOOL_QUALITY_DEFAULT + +/obj/item/scalpel/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_SCALPEL = tool_quality)) /* * Researchable Scalpels */ -/obj/item/scalpel/laser1 +/obj/item/scalpel/laser name = "laser scalpel" desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks basic and could be improved." icon_state = "scalpel_laser1_on" - damtype = "fire" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + atom_damage_type = BURN + _base_attack_force = 10 + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + pickup_sound = 'sound/foley/pickup2.ogg' + tool_quality = TOOL_QUALITY_DECENT + origin_tech = @'{"biotech":2,"materials":2,"magnets":2}' -/obj/item/scalpel/laser2 - name = "laser scalpel" +/obj/item/scalpel/laser/upgraded + name = "upgraded laser scalpel" desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks somewhat advanced." + _base_attack_force = 12 icon_state = "scalpel_laser2_on" - damtype = "fire" - force = 12.0 - material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) + tool_quality = TOOL_QUALITY_GOOD + origin_tech = @'{"biotech":3,"materials":4,"magnets":4}' -/obj/item/scalpel/laser3 - name = "laser scalpel" +/obj/item/scalpel/laser/advanced + name = "advanced laser scalpel" desc = "A scalpel augmented with a directed laser, for more precise cutting without blood entering the field. This one looks to be the pinnacle of precision energy cutlery!" icon_state = "scalpel_laser3_on" - damtype = "fire" - force = 15.0 - material = /decl/material/solid/metal/steel + _base_attack_force = 15 matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) + tool_quality = TOOL_QUALITY_BEST + origin_tech = @'{"biotech":4,"materials":6,"magnets":5}' -/obj/item/scalpel/manager +/obj/item/incision_manager name = "incision management system" - desc = "A true extension of the surgeon's body, this marvel instantly and completely prepares an incision allowing for the immediate commencement of therapeutic steps." + desc = "A true extension of the surgeon's body, this marvel combines several medical tools into one modular package." + sharp = TRUE + edge = TRUE + atom_damage_type = BURN + icon = 'icons/obj/surgery.dmi' icon_state = "scalpel_manager_on" - force = 7.5 + _base_attack_force = 7 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + pickup_sound = 'sound/foley/pickup2.ogg' + origin_tech = @'{"biotech":4,"materials":7,"magnets":5,"programming":4}' + +/obj/item/incision_manager/Initialize() + . = ..() + set_extension(src, /datum/extension/tool/variable, list( + TOOL_SAW = TOOL_QUALITY_GOOD, + TOOL_SCALPEL = TOOL_QUALITY_GOOD, + TOOL_RETRACTOR = TOOL_QUALITY_GOOD, + TOOL_HEMOSTAT = TOOL_QUALITY_GOOD + )) /* * Circular Saw */ /obj/item/circular_saw name = "circular saw" - desc = "For heavy duty cutting." + desc = "For heavy-duty cutting." icon = 'icons/obj/surgery.dmi' icon_state = "saw3" hitsound = 'sound/weapons/circsawhit.ogg' obj_flags = OBJ_FLAG_CONDUCTIBLE - force = 15.0 w_class = ITEM_SIZE_NORMAL - throwforce = 9.0 throw_speed = 3 throw_range = 5 - origin_tech = "{'materials':1,'biotech':1}" + origin_tech = @'{"materials":1,"biotech":1}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) attack_verb = list("attacked", "slashed", "sawed", "cut") - sharp = 1 - edge = 1 + sharp = TRUE + edge = TRUE + pickup_sound = 'sound/foley/pickup2.ogg' + drop_sound = 'sound/foley/knifedrop3.ogg' + _base_attack_force = 15 + +/obj/item/circular_saw/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_SAW = TOOL_QUALITY_DEFAULT)) /obj/item/circular_saw/get_autopsy_descriptors() . = ..() . += "serrated" -//misc, formerly from code/defines/weapons.dm /obj/item/bonegel name = "bone gel" icon = 'icons/obj/surgery.dmi' icon_state = "bone-gel" - force = 0 w_class = ITEM_SIZE_SMALL - throwforce = 1.0 + item_flags = ITEM_FLAG_NO_BLUDGEON + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/organic/plastic + +/obj/item/bonegel/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_BONE_GEL = TOOL_QUALITY_DEFAULT)) /obj/item/sutures name = "sutures" desc = "Surgical needles and thread in a handy sterile package." icon = 'icons/obj/surgery.dmi' icon_state = "fixovein" - force = 0 - throwforce = 1.0 - origin_tech = "{'materials':1,'biotech':3}" + origin_tech = @'{"materials":1,"biotech":3}' w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + _base_attack_force = 1 + +/obj/item/sutures/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_SUTURES = TOOL_QUALITY_DEFAULT)) /obj/item/bonesetter name = "bone setter" + desc = "A surgical tool for manipulating and setting bones." icon = 'icons/obj/surgery.dmi' icon_state = "bone setter" - force = 8.0 - throwforce = 9.0 throw_speed = 3 throw_range = 5 w_class = ITEM_SIZE_SMALL attack_verb = list("attacked", "hit", "bludgeoned") + pickup_sound = 'sound/foley/pickup2.ogg' + drop_sound = 'sound/foley/knifedrop3.ogg' + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + _base_attack_force = 8.0 + +/obj/item/bonesetter/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_BONE_SETTER = TOOL_QUALITY_DEFAULT)) diff --git a/code/game/objects/items/weapons/surgery_tools_ancient.dm b/code/game/objects/items/weapons/surgery_tools_ancient.dm new file mode 100644 index 000000000000..d9c4f6d27433 --- /dev/null +++ b/code/game/objects/items/weapons/surgery_tools_ancient.dm @@ -0,0 +1,92 @@ +/obj/item/ancient_surgery + abstract_type = /obj/item/ancient_surgery + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/bronze + color = /decl/material/solid/metal/bronze::color + material_alteration = MAT_FLAG_ALTERATION_ALL + matter = null + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":1,"biotech":1}' + drop_sound = 'sound/foley/knifedrop3.ogg' + +/obj/item/ancient_surgery/proc/get_tool_properties() + return + +/obj/item/ancient_surgery/Initialize() + . = ..() + var/tool_properties = get_tool_properties() + if(length(tool_properties)) + set_extension(src, /datum/extension/tool, tool_properties) + +/obj/item/ancient_surgery/retractor + name = "surgical lever" + desc = "A surgical tool for widening incisions or adjusting bones." + icon = 'icons/obj/items/surgery/bone_lever.dmi' + +/obj/item/ancient_surgery/retractor/get_tool_properties() + var/static/list/tool_properties = list( + TOOL_BONE_GEL = TOOL_QUALITY_MEDIOCRE, + TOOL_RETRACTOR = TOOL_QUALITY_MEDIOCRE + ) + return tool_properties + +/obj/item/ancient_surgery/cautery + name = "tile cautery" + desc = "A surgical tool for boring holes, preventing bleeding or closing incisions." + icon = 'icons/obj/items/surgery/cautery.dmi' + +/obj/item/ancient_surgery/cautery/get_tool_properties() + var/static/list/tool_properties = list( + TOOL_SURGICAL_DRILL = TOOL_QUALITY_MEDIOCRE, + TOOL_CAUTERY = TOOL_QUALITY_MEDIOCRE + ) + return tool_properties + +/obj/item/ancient_surgery/bonesetter + name = "bone setter" + desc = "A surgical tool for manipulating and setting bones." + icon = 'icons/obj/items/surgery/bone_setter.dmi' + +/obj/item/ancient_surgery/bonesetter/get_tool_properties() + var/static/list/tool_properties = list(TOOL_BONE_SETTER = TOOL_QUALITY_MEDIOCRE) + return tool_properties + +/obj/item/ancient_surgery/scalpel + name = "scalpel" + desc = "A short, wickedly sharp blade used for making incisions and cutting through flesh." + icon = 'icons/obj/items/surgery/scalpel.dmi' + sharp = TRUE + _base_attack_force = 8 + +/obj/item/ancient_surgery/scalpel/get_tool_properties() + var/static/list/tool_properties = list(TOOL_SCALPEL = TOOL_QUALITY_MEDIOCRE) + return tool_properties + +/obj/item/ancient_surgery/forceps + name = "forceps" + desc = "A pair of opposed levers used to grip and move objects within an incision." + icon = 'icons/obj/items/surgery/forceps.dmi' + +/obj/item/ancient_surgery/forceps/get_tool_properties() + var/static/list/tool_properties = list(TOOL_HEMOSTAT = TOOL_QUALITY_MEDIOCRE) + return tool_properties + +/obj/item/ancient_surgery/sutures + name = "sutures" + desc = "Fine thread suitable for closing wounds or incisions." + icon = 'icons/obj/items/surgery/sutures.dmi' + material = /decl/material/solid/organic/meat/gut + +/obj/item/ancient_surgery/sutures/get_tool_properties() + var/static/list/tool_properties = list(TOOL_SUTURES = TOOL_QUALITY_MEDIOCRE) + return tool_properties + +/obj/item/ancient_surgery/bonesaw + name = "bonesaw" + desc = "A heavy saw for cutting through bones." + icon = 'icons/obj/items/surgery/bonesaw.dmi' + +/obj/item/ancient_surgery/bonesaw/get_tool_properties() + var/static/list/tool_properties = list(TOOL_SAW = TOOL_QUALITY_MEDIOCRE) + return tool_properties diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 4d9caf07fd76..7a8a2308bde2 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -11,21 +11,23 @@ name = "police baton" desc = "A wooden truncheon for beating criminal scum." icon = 'icons/obj/items/weapon/old_baton.dmi' - icon_state = "baton" - item_state = "classic_baton" - slot_flags = SLOT_BELT - force = 10 + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + item_flags = ITEM_FLAG_IS_WEAPON + material = /decl/material/solid/organic/wood/oak + _base_attack_force = 10 -/obj/item/classic_baton/attack(mob/M, mob/living/user) - if ((MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, "You club yourself over the head.") - user.Weaken(3 * force) +/obj/item/classic_baton/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if (user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + var/force = expend_attack_force(user) + to_chat(user, SPAN_WARNING("You club yourself over the head.")) + SET_STATUS_MAX(user, STAT_WEAK, (3 * force)) if(ishuman(user)) - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user H.apply_damage(2*force, BRUTE, BP_HEAD) else user.take_organ_damage(2*force) - return + return TRUE return ..() //Telescopic baton @@ -33,14 +35,14 @@ name = "telescopic baton" desc = "A compact yet rebalanced personal defense weapon. Can be concealed when folded." icon = 'icons/obj/items/weapon/telebaton.dmi' - icon_state = "telebaton_0" - item_state = "telebaton_0" - slot_flags = SLOT_BELT + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL - force = 3 + _base_attack_force = 3 + item_flags = ITEM_FLAG_IS_WEAPON + material = /decl/material/solid/metal/aluminium var/on = 0 - /obj/item/telebaton/attack_self(mob/user) on = !on if(on) @@ -48,14 +50,14 @@ "You extend the baton.",\ "You hear an ominous click.") w_class = ITEM_SIZE_NORMAL - force = 15//quite robust + set_base_attack_force(15) //quite robust attack_verb = list("smacked", "struck", "slapped") else user.visible_message("\The [user] collapses their telescopic baton.",\ "You collapse the baton.",\ "You hear a click.") w_class = ITEM_SIZE_SMALL - force = 3//not so robust now + set_base_attack_force(3) //not so robust now attack_verb = list("hit", "punched") playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) @@ -64,30 +66,23 @@ update_held_icon() /obj/item/telebaton/on_update_icon() + if(REAGENT_TOTAL_VOLUME(coating) || blood_DNA) + generate_coating_overlay(TRUE) // Force recheck. + . = ..() if(on) - icon_state = "telebaton_1" - item_state = "telebaton_1" + icon = 'icons/obj/items/weapon/telebaton_extended.dmi' else - icon_state = "telebaton_0" - item_state = "telebaton_0" - if(length(blood_DNA)) - generate_blood_overlay(TRUE) // Force recheck. - overlays.Cut() - overlays += blood_overlay + icon = 'icons/obj/items/weapon/telebaton.dmi' -/obj/item/telebaton/attack(mob/target, mob/living/user) - if(on) - if ((MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, "You club yourself over the head.") - user.Weaken(3 * force) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.apply_damage(2*force, BRUTE, BP_HEAD) - else - user.take_organ_damage(2*force) - return - if(..()) - //playsound(src.loc, "swing_hit", 50, 1, -1) - return - else - return ..() +/obj/item/telebaton/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(on && user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + var/force = expend_attack_force(user) + to_chat(user, SPAN_DANGER("You club yourself over the head.")) + SET_STATUS_MAX(user, STAT_WEAK, (3 * force)) + if(ishuman(user)) + var/mob/living/human/H = user + H.apply_damage(2*force, BRUTE, BP_HEAD) + else + user.take_organ_damage(2*force) + return TRUE + return ..() diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm index 4270ef5f887b..a14c457a73d1 100644 --- a/code/game/objects/items/weapons/tanks/jetpack.dm +++ b/code/game/objects/items/weapons/tanks/jetpack.dm @@ -3,33 +3,32 @@ /obj/item/tank/jetpack name = "jetpack (empty)" desc = "A tank of compressed gas for use as propulsion in zero-gravity areas. Use with caution." - icon_state = "jetpack" + icon = 'icons/obj/items/tanks/jetpack.dmi' gauge_icon = null w_class = ITEM_SIZE_HUGE - item_state = "jetpack" distribute_pressure = ONE_ATMOSPHERE*O2STANDARD var/datum/effect/effect/system/trail/ion/ion_trail var/on = 0.0 var/stabilization_on = 0 - var/volume_rate = 500 //Needed for borg jetpack transfer action_button_name = "Toggle Jetpack" material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT) - origin_tech = "{'materials':1,'engineering':3}" + origin_tech = @'{"materials":1,"engineering":3}' /obj/item/tank/jetpack/Initialize() . = ..() ion_trail = new /datum/effect/effect/system/trail/ion() ion_trail.set_up(src) + refresh_ion_trail() /obj/item/tank/jetpack/Destroy() QDEL_NULL(ion_trail) . = ..() -/obj/item/tank/jetpack/examine(mob/living/user) +/obj/item/tank/jetpack/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(air_contents.total_moles < 5) - to_chat(user, "The meter on \the [src] indicates you are almost out of gas!") + . += SPAN_DANGER("The meter on \the [src] indicates you are almost out of gas!") /obj/item/tank/jetpack/verb/toggle_rockets() set name = "Toggle Jetpack Stabilization" @@ -37,21 +36,39 @@ src.stabilization_on = !( src.stabilization_on ) to_chat(usr, "You toggle the stabilization [stabilization_on? "on":"off"].") +/obj/item/tank/jetpack/on_update_icon() + . = ..() + if(on) + add_overlay("[icon_state]-on") + +/obj/item/tank/jetpack/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && slot == slot_back_str && on) + overlay.icon_state = "[overlay.icon_state]-on" + . = ..() + +/obj/item/tank/jetpack/equipped(mob/user, slot) + . = ..() + refresh_ion_trail() + +/obj/item/tank/jetpack/proc/refresh_ion_trail() + if(on && isliving(loc)) + var/mob/living/wearer = loc + if(wearer.get_jetpack() == src) + ion_trail.start() + return + ion_trail.stop() + /obj/item/tank/jetpack/verb/toggle() set name = "Toggle Jetpack" set category = "Object" on = !on - if(on) - icon_state = "[icon_state]-on" - ion_trail.start() - else - icon_state = initial(icon_state) - ion_trail.stop() + refresh_ion_trail() + update_icon() if (ismob(usr)) var/mob/M = usr - M.update_inv_back() + M.update_equipment_overlay(slot_back_str) M.update_action_buttons() to_chat(usr, "You toggle the thrusters [on? "on":"off"].") @@ -77,49 +94,24 @@ /obj/item/tank/jetpack/void name = "void jetpack (oxygen)" desc = "It works well in a void." - icon_state = "jetpack-void" - item_state = "jetpack-void" - starting_pressure = list(/decl/material/gas/oxygen = 6*ONE_ATMOSPHERE) + icon = 'icons/obj/items/tanks/jetpack_void.dmi' + starting_pressure = list(/decl/material/gas/oxygen = 6 ATM) /obj/item/tank/jetpack/oxygen name = "jetpack (oxygen)" desc = "A tank of compressed oxygen for use as propulsion in zero-gravity areas. Use with caution." - icon_state = "jetpack" - item_state = "jetpack" - starting_pressure = list(/decl/material/gas/oxygen = 6*ONE_ATMOSPHERE) + starting_pressure = list(/decl/material/gas/oxygen = 6 ATM) /obj/item/tank/jetpack/carbondioxide name = "jetpack (carbon dioxide)" desc = "A tank of compressed carbon dioxide for use as propulsion in zero-gravity areas. Painted black to indicate that it should not be used as a source for internals." + icon = 'icons/obj/items/tanks/jetpack_co2.dmi' distribute_pressure = 0 - icon_state = "jetpack-black" - item_state = "jetpack-black" - starting_pressure = list(/decl/material/gas/carbon_dioxide = 6*ONE_ATMOSPHERE) + starting_pressure = list(/decl/material/gas/carbon_dioxide = 6 ATM) /obj/item/tank/jetpack/rig - name = "jetpack" + name = "integrated maneuvering module thrusterpack" + desc = "The 'maneuvering' part of a maneuvering jet module for a hardsuit. You could... probably use this standalone?" + starting_pressure = list(/decl/material/gas/oxygen = 6 ATM) var/obj/item/rig/holder -/obj/item/tank/jetpack/rig/examine() - . = ..() - CRASH("A [name] was examined") - -/obj/item/tank/jetpack/rig/allow_thrust(num, mob/living/user) - - if(!(src.on)) - return 0 - - if(!istype(holder) || !holder.air_supply) - return 0 - - var/obj/item/tank/pressure_vessel = holder.air_supply - - if((num < 0.005 || pressure_vessel.air_contents.total_moles < num)) - src.ion_trail.stop() - return 0 - - var/datum/gas_mixture/G = pressure_vessel.remove_air(num) - - if(G.total_moles >= 0.005) - return 1 - qdel(G) diff --git a/code/game/objects/items/weapons/tanks/tank_types.dm b/code/game/objects/items/weapons/tanks/tank_types.dm index 892d0a3fc278..2995bcc82700 100644 --- a/code/game/objects/items/weapons/tanks/tank_types.dm +++ b/code/game/objects/items/weapons/tanks/tank_types.dm @@ -1,7 +1,6 @@ /* Types of tanks! * Contains: * Oxygen - * Anesthetic * Air * Hydrogen * Emergency Oxygen @@ -13,25 +12,21 @@ /obj/item/tank/oxygen name = "oxygen tank" desc = "A tank of oxygen." - icon_state = "oxygen" + icon = 'icons/obj/items/tanks/tank_blue.dmi' distribute_pressure = ONE_ATMOSPHERE*O2STANDARD - starting_pressure = list(/decl/material/gas/oxygen = 6*ONE_ATMOSPHERE) - volume = 180 + starting_pressure = list(/decl/material/gas/oxygen = 6 ATM) + gas_volume = 180 /obj/item/tank/oxygen/yellow desc = "A tank of oxygen. This one is yellow." - icon_state = "oxygen_f" + icon = 'icons/obj/items/tanks/tank_yellow.dmi' -/* - * Anesthetic - */ -/obj/item/tank/anesthetic - name = "anesthetic tank" - desc = "A tank with an N2O/O2 gas mix." - icon_state = "anesthetic" - item_state = "an_tank" - starting_pressure = list(/decl/material/gas/oxygen = 6*ONE_ATMOSPHERE*O2STANDARD, /decl/material/gas/nitrous_oxide = 6*ONE_ATMOSPHERE*N2STANDARD) - volume = 270 +/obj/item/tank/oxygen/red + desc = "A tank of oxygen. This one is red." + icon = 'icons/obj/items/tanks/tank_red.dmi' + +/obj/item/tank/oxygen/empty + starting_pressure = list() /* * Air @@ -39,9 +34,9 @@ /obj/item/tank/air name = "air tank" desc = "Mixed anyone?" - icon_state = "oxygen" - starting_pressure = list(/decl/material/gas/oxygen = 6*ONE_ATMOSPHERE*O2STANDARD, /decl/material/gas/nitrogen = 6*ONE_ATMOSPHERE*N2STANDARD) - volume = 180 + icon = 'icons/obj/items/tanks/tank_blue.dmi' + starting_pressure = list(/decl/material/gas/oxygen = (6 ATM) * O2STANDARD, /decl/material/gas/nitrogen = (6 ATM) * N2STANDARD) + gas_volume = 180 /* * Hydrogen @@ -49,66 +44,59 @@ /obj/item/tank/hydrogen name = "hydrogen tank" desc = "Contains hydrogen. Warning: flammable." - icon_state = "hydrogen" + icon = 'icons/obj/items/tanks/tank_greyscaled.dmi' + color = "#412e87" gauge_icon = null obj_flags = OBJ_FLAG_CONDUCTIBLE slot_flags = null - starting_pressure = list(/decl/material/gas/hydrogen = 3*ONE_ATMOSPHERE) + starting_pressure = list(/decl/material/gas/hydrogen = 3 ATM) + +/obj/item/tank/hydrogen/empty + starting_pressure = list() + +/obj/item/tank/hydrogen/collector + starting_pressure = list(/decl/material/gas/hydrogen = 70) /* * Emergency Oxygen */ /obj/item/tank/emergency name = "emergency tank" - icon_state = "emergency" + icon = 'icons/obj/items/tanks/tank_emergency.dmi' gauge_icon = "indicator_emergency" gauge_cap = 4 obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL - force = 5 attack_cooldown = DEFAULT_WEAPON_COOLDOWN melee_accuracy_bonus = -10 distribute_pressure = ONE_ATMOSPHERE*O2STANDARD - volume = 40 //Tiny. Real life equivalents only have 21 breaths of oxygen in them. They're EMERGENCY tanks anyway -errorage (dangercon 2011) + gas_volume = 40 //Tiny. Real life equivalents only have 21 breaths of oxygen in them. They're EMERGENCY tanks anyway -errorage (dangercon 2011) /obj/item/tank/emergency/oxygen name = "emergency oxygen tank" desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it." - icon_state = "emergency" + icon = 'icons/obj/items/tanks/tank_emergency.dmi' gauge_icon = "indicator_emergency" - starting_pressure = list(/decl/material/gas/oxygen = 10*ONE_ATMOSPHERE) + starting_pressure = list(/decl/material/gas/oxygen = 10 ATM) /obj/item/tank/emergency/oxygen/engi name = "extended-capacity emergency oxygen tank" - icon_state = "emergency_engi" - volume = 60 + icon = 'icons/obj/items/tanks/tank_emergency_engineer.dmi' + gas_volume = 60 /obj/item/tank/emergency/oxygen/double name = "double emergency oxygen tank" - icon_state = "emergency_double" + icon = 'icons/obj/items/tanks/tank_emergency_double.dmi' gauge_icon = "indicator_emergency_double" - volume = 90 + gas_volume = 90 w_class = ITEM_SIZE_NORMAL /obj/item/tank/emergency/oxygen/double/red //firefighting tank, fits on belt, back or suitslot - name = "self contained breathing apparatus" - desc = "A self contained breathing apparatus, well known as SCBA. Generally filled with oxygen." - icon_state = "oxygen_fr" - slot_flags = SLOT_BELT | SLOT_BACK - -/obj/item/tank/emergency/nitrogen - name = "emergency nitrogen tank" - desc = "An emergency air tank hastily painted red and issued to Vox crewmembers." - icon_state = "emergency_nitro" - gauge_icon = "indicator_emergency" - starting_pressure = list(/decl/material/gas/nitrogen = 10*ONE_ATMOSPHERE) - -/obj/item/tank/emergency/nitrogen/double - name = "double emergency nitrogen tank" - icon_state = "emergency_double_nitrogen" - gauge_icon = "indicator_emergency_double" - volume = 60 + name = "self-contained breathing apparatus" + desc = "A self-contained breathing apparatus, well known as SCBA. Generally filled with oxygen." + icon = 'icons/obj/items/tanks/tank_scuba.dmi' + slot_flags = SLOT_LOWER_BODY | SLOT_BACK /* * Nitrogen @@ -116,7 +104,7 @@ /obj/item/tank/nitrogen name = "nitrogen tank" desc = "A tank of nitrogen." - icon_state = "nitrogen" + icon = 'icons/obj/items/tanks/tank_red.dmi' distribute_pressure = ONE_ATMOSPHERE*O2STANDARD - starting_pressure = list(/decl/material/gas/nitrogen = 10*ONE_ATMOSPHERE) - volume = 180 + starting_pressure = list(/decl/material/gas/nitrogen = 10 ATM) + gas_volume = 180 diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index b96fa704b0cb..9af831affc7d 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -1,6 +1,6 @@ #define TANK_IDEAL_PRESSURE 1015 //Arbitrary. -var/tank_bomb_severity = 1 +var/global/tank_bomb_severity = 1 #define TANK_BOMB_DVSTN_FACTOR (0.15 * global.tank_bomb_severity) #define TANK_BOMB_HEAVY_FACTOR (0.35 * global.tank_bomb_severity) #define TANK_BOMB_LIGHT_FACTOR (0.80 * global.tank_bomb_severity) @@ -14,29 +14,27 @@ var/tank_bomb_severity = 1 if(check_rights(R_DEBUG)) var/next_input = input("Enter a new bomb severity between 1 and [MAX_TANK_BOMB_SEVERITY].", "Tank Bomb Severity", global.tank_bomb_severity) as num|null if(isnum(next_input)) - global.tank_bomb_severity = Clamp(next_input, 0, MAX_TANK_BOMB_SEVERITY) + global.tank_bomb_severity = clamp(next_input, 0, MAX_TANK_BOMB_SEVERITY) log_and_message_admins("[key_name_admin(mob)] has set the tank bomb severity value to [global.tank_bomb_severity].", mob) -var/list/global/tank_gauge_cache = list() +var/global/list/global/tank_gauge_cache = list() /obj/item/tank name = "tank" - icon = 'icons/obj/tank.dmi' - - var/gauge_icon = "indicator_tank" - var/gauge_cap = 6 - var/previous_gauge_pressure = null - + icon = 'icons/obj/items/tanks/tank_blue.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/steel obj_flags = OBJ_FLAG_CONDUCTIBLE slot_flags = SLOT_BACK w_class = ITEM_SIZE_LARGE - - force = 15 attack_cooldown = 2*DEFAULT_WEAPON_COOLDOWN melee_accuracy_bonus = -30 - throwforce = 10.0 throw_speed = 1 throw_range = 4 + _base_attack_force = 15 + + var/gauge_icon = "indicator_tank" + var/gauge_cap = 6 var/datum/gas_mixture/air_contents = null var/distribute_pressure = ONE_ATMOSPHERE @@ -44,10 +42,10 @@ var/list/global/tank_gauge_cache = list() var/maxintegrity = 20 var/valve_welded = 0 var/obj/item/tankassemblyproxy/proxyassembly - - var/volume = 70 - var/manipulated_by = null //Used by _onclick/hud/screen_objects.dm internals to determine if someone has messed with our tank or not. - //If they have and we haven't scanned it with the PDA or gas analyzer then we might just breath whatever they put in it. + var/gas_volume = 70 + //Used by _onclick/hud/screen_objects.dm internals to determine if someone has messed with our tank or not. + //If they have and we haven't scanned it with the PDA or gas analyzer then we might just breath whatever they put in it. + var/manipulated_by = null var/failure_temp = 173 //173 deg C Borate seal (yes it should be 153 F, but that's annoying) var/leaking = 0 var/wired = 0 @@ -58,13 +56,13 @@ var/list/global/tank_gauge_cache = list() proxyassembly = new /obj/item/tankassemblyproxy(src) proxyassembly.tank = src - air_contents = new /datum/gas_mixture(volume, T20C) + air_contents = new /datum/gas_mixture(gas_volume, T20C) for(var/gas in starting_pressure) - air_contents.adjust_gas(gas, starting_pressure[gas]*volume/(R_IDEAL_GAS_EQUATION*T20C), 0) + air_contents.adjust_gas(gas, starting_pressure[gas]*gas_volume/(R_IDEAL_GAS_EQUATION*T20C), 0) air_contents.update_values() START_PROCESSING(SSobj, src) - update_icon(TRUE) + update_icon() /obj/item/tank/Destroy() QDEL_NULL(air_contents) @@ -80,7 +78,14 @@ var/list/global/tank_gauge_cache = list() . = ..() -/obj/item/tank/examine(mob/user) +/obj/item/tank/get_single_monetary_worth() + . = ..() + for(var/gas in air_contents?.gas) + var/decl/material/gas_data = GET_DECL(gas) + . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER + . = max(1, round(.)) + +/obj/item/tank/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/descriptive if(!air_contents) @@ -102,35 +107,35 @@ var/list/global/tank_gauge_cache = list() descriptive = "cold" else descriptive = "bitterly cold" - to_chat(user, "\The [src] feels [descriptive].") + . += SPAN_NOTICE("\The [src] feels [descriptive].") if(proxyassembly.assembly || wired) - to_chat(user, "It seems to have [wired? "some wires ": ""][wired && proxyassembly.assembly? "and ":""][proxyassembly.assembly ? "some sort of assembly ":""]attached to it.") + . += SPAN_WARNING("It seems to have [wired? "some wires ": ""][wired && proxyassembly.assembly? "and ":""][proxyassembly.assembly ? "some sort of assembly ":""]attached to it.") if(valve_welded) - to_chat(user, "\The [src] emergency relief valve has been welded shut!") - + . += SPAN_WARNING("\The [src] emergency relief valve has been welded shut!") -/obj/item/tank/attackby(var/obj/item/W, var/mob/user) - ..() +/obj/item/tank/attackby(var/obj/item/used_item, var/mob/user) if (istype(loc, /obj/item/assembly)) icon = loc - if (istype(W, /obj/item/scanner/gas)) - return + if (istype(used_item, /obj/item/scanner/gas)) + return FALSE // allow afterattack to proceed - if (istype(W,/obj/item/latexballon)) - var/obj/item/latexballon/LB = W + if (istype(used_item,/obj/item/latexballon)) + var/obj/item/latexballon/LB = used_item LB.blow(src) add_fingerprint(user) + return TRUE - if(isCoil(W)) - var/obj/item/stack/cable_coil/C = W + if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/C = used_item if(C.use(1)) wired = 1 to_chat(user, "You attach the wires to the tank.") - update_icon(TRUE) + update_icon() + return TRUE - if(isWirecutter(W)) + if(IS_WIRECUTTER(used_item)) if(wired && proxyassembly.assembly) to_chat(user, "You carefully begin clipping the wires that attach to the tank.") @@ -140,72 +145,76 @@ var/list/global/tank_gauge_cache = list() var/obj/item/assembly_holder/assy = proxyassembly.assembly if(assy.a_left && assy.a_right) - assy.dropInto(usr.loc) + assy.dropInto(user.loc) assy.master = null proxyassembly.assembly = null else if(!proxyassembly.assembly.a_left) - assy.a_right.dropInto(usr.loc) + assy.a_right.dropInto(user.loc) assy.a_right.holder = null assy.a_right = null proxyassembly.assembly = null qdel(assy) - update_icon(TRUE) + update_icon() else to_chat(user, "You slip and bump the igniter!") if(prob(85)) proxyassembly.receive_signal() + return TRUE else if(wired) if(do_after(user, 10, src)) to_chat(user, "You quickly clip the wire from the tank.") wired = 0 - update_icon(TRUE) + update_icon() else to_chat(user, "There are no wires to cut!") + return TRUE - if(istype(W, /obj/item/assembly_holder)) + if(istype(used_item, /obj/item/assembly_holder)) if(wired) to_chat(user, "You begin attaching the assembly to \the [src].") if(do_after(user, 50, src)) - to_chat(user, "You finish attaching the assembly to \the [src].") - GLOB.bombers += "[key_name(user)] attached an assembly to a wired [src]. Temp: [air_contents.temperature-T0C]" - log_and_message_admins("attached an assembly to a wired [src]. Temp: [air_contents.temperature-T0C]", user) - assemble_bomb(W,user) + assemble_bomb(used_item,user) else to_chat(user, "You stop attaching the assembly.") else to_chat(user, "You need to wire the device up first.") + return TRUE - if(isWelder(W)) - var/obj/item/weldingtool/WT = W - if(WT.remove_fuel(1,user)) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(1,user)) if(!valve_welded) - to_chat(user, "You begin welding the \the [src] emergency pressure relief valve.") + to_chat(user, "You begin welding \the [src] emergency pressure relief valve.") if(do_after(user, 40,src)) to_chat(user, "You carefully weld \the [src] emergency pressure relief valve shut. \The [src] may now rupture under pressure!") valve_welded = 1 leaking = 0 else - GLOB.bombers += "[key_name(user)] attempted to weld a [src]. [air_contents.temperature-T0C]" - log_and_message_admins("attempted to weld a [src]. [air_contents.temperature-T0C]", user) - if(WT.welding) - to_chat(user, "You accidentally rake \the [W] across \the [src]!") + global.bombers += "[key_name(user)] attempted to weld \a [src]. [air_contents.temperature-T0C]" + log_and_message_admins("attempted to weld \a [src]. [air_contents.temperature-T0C]", user) + if(welder.welding) + to_chat(user, "You accidentally rake \the [used_item] across \the [src]!") maxintegrity -= rand(2,6) integrity = min(integrity,maxintegrity) air_contents.add_thermal_energy(rand(2000,50000)) else to_chat(user, "The emergency pressure relief valve has already been welded.") add_fingerprint(user) + return TRUE + + if(istype(used_item, /obj/item/flamethrower)) + var/obj/item/flamethrower/F = used_item + if(!F.secured || F.tank || !user.try_unequip(src, F)) + return TRUE - if(istype(W, /obj/item/flamethrower)) - var/obj/item/flamethrower/F = W - if(!F.status || F.tank || !user.unEquip(src, F)) - return master = F F.tank = src + return TRUE + return ..() /obj/item/tank/attack_self(mob/user) add_fingerprint(user) @@ -218,17 +227,11 @@ var/list/global/tank_gauge_cache = list() proxyassembly.assembly.attack_self(user) /obj/item/tank/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/mob/living/carbon/location = null - - if(istype(loc, /obj/item/rig)) // check for tanks in rigs - if(istype(loc.loc, /mob/living/carbon)) - location = loc.loc - else if(istype(loc, /mob/living/carbon)) - location = loc + var/mob/living/location = get_recursive_loc_of_type(/mob/living) var/using_internal if(istype(location)) - if(location.internal==src) + if(location.get_internals() == src) using_internal = 1 // this is the data which will be sent to the ui @@ -243,21 +246,23 @@ var/list/global/tank_gauge_cache = list() if(istype(location)) var/mask_check = 0 - if(location.internal == src) // if tank is current internal + if(location.get_internals() == src) // if tank is current internal mask_check = 1 else if(src in location) // or if tank is in the mobs possession - if(!location.internal) // and they do not have any active internals + if(!location.get_internals()) // and they do not have any active internals mask_check = 1 else if(istype(loc, /obj/item/rig) && (loc in location)) // or the rig is in the mobs possession - if(!location.internal) // and they do not have any active internals + if(!location.get_internals()) // and they do not have any active internals mask_check = 1 if(mask_check) - if(location.wear_mask && (location.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) + var/obj/item/mask = location.get_equipped_item(slot_wear_mask_str) + if(mask && (mask.item_flags & ITEM_FLAG_AIRTIGHT)) data["maskConnected"] = 1 - else if(istype(location, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = location - if(H.head && (H.head.item_flags & ITEM_FLAG_AIRTIGHT)) + else if(ishuman(location)) + var/mob/living/human/H = location + var/obj/item/head = H.get_equipped_item(slot_head_str) + if(head && (head.item_flags & ITEM_FLAG_AIRTIGHT)) data["maskConnected"] = 1 // update the ui if it exists, returns null if no ui is passed/found @@ -273,8 +278,8 @@ var/list/global/tank_gauge_cache = list() // auto update every Master Controller tick ui.set_auto_update(1) -/obj/item/tank/Topic(user, href_list, state = GLOB.inventory_state) - ..() +/obj/item/tank/DefaultTopicState() + return global.inventory_topic_state /obj/item/tank/OnTopic(user, href_list) if (href_list["dist_p"]) @@ -289,13 +294,13 @@ var/list/global/tank_gauge_cache = list() return TOPIC_REFRESH if (href_list["stat"]) - toggle_valve(usr) + toggle_valve(user) return TOPIC_REFRESH /obj/item/tank/proc/toggle_valve(var/mob/user) - var/mob/living/carbon/location - if(istype(loc,/mob/living/carbon)) + var/mob/living/location + if(isliving(loc)) location = loc else if(istype(loc,/obj/item/rig)) var/obj/item/rig/rig = loc @@ -304,16 +309,18 @@ var/list/global/tank_gauge_cache = list() else return - if(location.internal == src) + if(location.get_internals() == src) to_chat(user, "You close the tank release valve.") location.set_internals(null) else var/can_open_valve - if(location.wear_mask && (location.wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) + var/obj/item/mask = location.get_equipped_item(slot_wear_mask_str) + if(mask && (mask.item_flags & ITEM_FLAG_AIRTIGHT)) can_open_valve = 1 - else if(istype(location,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = location - if(H.head && (H.head.item_flags & ITEM_FLAG_AIRTIGHT)) + else if(ishuman(location)) + var/mob/living/human/H = location + var/obj/item/head = H.get_equipped_item(slot_head_str) + if(head && (head.item_flags & ITEM_FLAG_AIRTIGHT)) can_open_valve = 1 if(can_open_valve) @@ -345,10 +352,9 @@ var/list/global/tank_gauge_cache = list() return air_contents /obj/item/tank/assume_air(datum/gas_mixture/giver) - air_contents.merge(giver) + . = air_contents.merge(giver) check_status() queue_icon_update() - return 1 /obj/item/tank/proc/remove_air_volume(volume_to_return) if(!air_contents) @@ -360,24 +366,24 @@ var/list/global/tank_gauge_cache = list() var/datum/gas_mixture/removed = remove_air(distribute_pressure*volume_to_return/(R_IDEAL_GAS_EQUATION*air_contents.temperature)) if(removed) - removed.volume = volume_to_return + removed.total_volume = volume_to_return return removed /obj/item/tank/Process() air_contents.react() check_status() -/obj/item/tank/on_update_icon(var/override) - - var/list/overlays_to_add - if(override && (proxyassembly.assembly || wired)) - LAZYADD(overlays_to_add, image(icon,"bomb_assembly")) +// TODO: Check if this works without the override argument. Everything in tank code seems to call it, so... +/obj/item/tank/on_update_icon() + . = ..() + if(proxyassembly?.assembly || wired) + add_overlay(overlay_image('icons/obj/items/tanks/tank_components.dmi', "bomb_assembly")) if(proxyassembly.assembly) - var/image/bombthing = image(proxyassembly.assembly.icon, proxyassembly.assembly.icon_state) - bombthing.overlays |= proxyassembly.assembly.overlays + var/mutable_appearance/bombthing = new(proxyassembly.assembly) + bombthing.appearance_flags = RESET_COLOR bombthing.pixel_y = -1 bombthing.pixel_x = -3 - LAZYADD(overlays_to_add, bombthing) + add_overlay(bombthing) if(gauge_icon) var/gauge_pressure = 0 @@ -387,14 +393,10 @@ var/list/global/tank_gauge_cache = list() gauge_pressure = -1 else gauge_pressure = round((gauge_pressure/TANK_IDEAL_PRESSURE)*gauge_cap) - if(override || (previous_gauge_pressure != gauge_pressure)) - var/indicator = "[gauge_icon][(gauge_pressure == -1) ? "overload" : gauge_pressure]" - if(!tank_gauge_cache[indicator]) - tank_gauge_cache[indicator] = image(icon, indicator) - LAZYADD(overlays_to_add, tank_gauge_cache[indicator]) - previous_gauge_pressure = gauge_pressure - - overlays = overlays_to_add + var/indicator = "[gauge_icon][(gauge_pressure == -1) ? "overload" : gauge_pressure]" + if(!tank_gauge_cache[indicator]) + tank_gauge_cache[indicator] = image('icons/obj/items/tanks/tank_indicators.dmi', indicator) + add_overlay(tank_gauge_cache[indicator]) //Handle exploding, leaking, and rupturing of the tank /obj/item/tank/proc/check_status() @@ -416,13 +418,13 @@ var/list/global/tank_gauge_cache = list() pressure = air_contents.return_pressure() var/strength = ((pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE) - var/mult = ((air_contents.volume/140)**(1/2)) * (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + var/mult = ((air_contents.total_volume/140)**(1/2)) * (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles //tanks appear to be experiencing a reduction on scale of about 0.64 total moles - var/turf/simulated/T = get_turf(src) - T.hotspot_expose(air_contents.temperature, 70, 1) - if(!T) + var/turf/T = get_turf(src) + if(!T?.simulated) return + T.hotspot_expose(air_contents.temperature, 70, 1) T.assume_air(air_contents) explosion( @@ -451,12 +453,12 @@ var/list/global/tank_gauge_cache = list() #endif if(integrity <= 0) - var/turf/simulated/T = get_turf(src) - if(!T) + var/turf/T = get_turf(src) + if(!T?.simulated) return T.assume_air(air_contents) playsound(get_turf(src), 'sound/weapons/gunshot/shotgun.ogg', 20, 1) - visible_message("\icon[src] \The [src] flies apart!", "You hear a bang!") + visible_message("[html_icon(src)] \The [src] flies apart!", "You hear a bang!") T.hotspot_expose(air_contents.temperature, 70, 1) var/strength = 1+((pressure-TANK_LEAK_PRESSURE)/TANK_FRAGMENT_SCALE) @@ -475,19 +477,19 @@ var/list/global/tank_gauge_cache = list() integrity-= 5 else if(pressure && (pressure > TANK_LEAK_PRESSURE || air_contents.temperature - T0C > failure_temp)) if((integrity <= 19 || leaking) && !valve_welded) - var/turf/simulated/T = get_turf(src) - if(!T) + var/turf/T = get_turf(src) + if(!T?.simulated) return var/datum/gas_mixture/environment = loc.return_air() var/env_pressure = environment.return_pressure() - var/release_ratio = Clamp(0.002, sqrt(max(pressure-env_pressure,0)/pressure),1) + var/release_ratio = clamp(0.002, sqrt(max(pressure-env_pressure,0)/pressure),1) var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(release_ratio) //dynamic air release based on ambient pressure T.assume_air(leaked_gas) if(!leaking) - visible_message("\icon[src] \The [src] relief valve flips open with a hiss!", "You hear hissing.") + visible_message("[html_icon(src)] \The [src] relief valve flips open with a hiss!", "You hear hissing.") playsound(loc, 'sound/effects/spray.ogg', 10, 1, -3) leaking = 1 #ifdef FIREDBG @@ -512,7 +514,7 @@ var/list/global/tank_gauge_cache = list() desc = initial(tank_copy.desc) icon = initial(tank_copy.icon) icon_state = initial(tank_copy.icon_state) - volume = initial(tank_copy.volume) + gas_volume = initial(tank_copy.gas_volume) // Set up explosive mix. air_contents.gas[DEFAULT_GAS_ACCELERANT] = 4 + rand(4) @@ -524,7 +526,7 @@ var/list/global/tank_gauge_cache = list() proxyassembly.assembly = new /obj/item/assembly_holder(src) proxyassembly.assembly.master = proxyassembly proxyassembly.assembly.update_icon() - update_icon(TRUE) + update_icon() ///////////////////////////////// ///Pulled from rewritten bomb.dm @@ -533,56 +535,68 @@ var/list/global/tank_gauge_cache = list() /obj/item/tankassemblyproxy name = "Tank assembly proxy" desc = "Used as a stand in to trigger single tank assemblies... but you shouldn't see this." + is_spawnable_type = FALSE var/obj/item/tank/tank = null var/obj/item/assembly_holder/assembly = null +/obj/item/tankassemblyproxy/Destroy() + tank = null // We aren't responsible for our tank + QDEL_NULL(assembly) // but we're responsible for the assembly. + return ..() + /obj/item/tankassemblyproxy/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here. - tank.ignite() //boom (or not boom if you made shijwtty mix) + tank.cause_explosion() //boom (or not boom if you made shijwtty mix) -/obj/item/tank/proc/assemble_bomb(W,user) //Bomb assembly proc. This turns assembly+tank into a bomb - var/obj/item/assembly_holder/S = W - var/mob/M = user - if(!S.secured) //Check if the assembly is secured - return +/obj/item/tank/proc/assemble_bomb(used_item,mob/user) //Bomb assembly proc. This turns assembly+tank into a bomb + var/obj/item/assembly_holder/S = used_item if(isigniter(S.a_left) == isigniter(S.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it return + if(!S.secured) //Check if the assembly is secured + to_chat(user, SPAN_NOTICE("\The [S] must be secured before attaching it to \the [src]!")) + return - if(!M.unequip_item()) - return //Remove the assembly from your hands - if(!M.unEquip(src)) + if(!user.try_unequip(src)) return //Remove the tank from your character,in case you were holding it - M.put_in_hands(src) //Equips the bomb if possible, or puts it on the floor. + user.put_in_hands(src) //Equips the bomb if possible, or puts it on the floor. proxyassembly.assembly = S //Tell the bomb about its assembly part S.master = proxyassembly //Tell the assembly about its new owner - S.forceMove(src) //Move the assembly + user.remove_from_mob(S, src, FALSE) //Move the assembly and reset HUD layer/plane status - update_icon(TRUE) + update_icon() + to_chat(user, "You finish attaching the assembly to \the [src].") + global.bombers += "[key_name(user)] attached an assembly to a wired [src]. Temp: [air_contents.temperature-T0C]" + log_and_message_admins("attached an assembly to a wired [src]. Temp: [air_contents.temperature-T0C]", user) + +/obj/item/tank/proc/cause_explosion() //This happens when a bomb is told to explode -/obj/item/tank/proc/ignite() //This happens when a bomb is told to explode var/obj/item/assembly_holder/assy = proxyassembly.assembly - var/ign = assy.a_right - var/obj/item/other = assy.a_left + var/obj/item/igniter = assy.a_right + var/obj/item/other = assy.a_left if (isigniter(assy.a_left)) - ign = assy.a_left - other = assy.a_right + igniter = assy.a_left + other = assy.a_right if(other) other.dropInto(get_turf(src)) - qdel(ign) + if(!QDELETED(igniter)) + qdel(igniter) assy.master = null proxyassembly.assembly = null - qdel(assy) - update_icon(TRUE) + if(!QDELETED(assy)) + qdel(assy) + update_icon() air_contents.add_thermal_energy(15000) /obj/item/tankassemblyproxy/on_update_icon() + . = ..() tank.update_icon() /obj/item/tankassemblyproxy/HasProximity(atom/movable/AM) - if(assembly) + . = ..() + if(. && assembly) assembly.HasProximity(AM) //Fragmentation projectiles diff --git a/code/game/objects/items/weapons/tape.dm b/code/game/objects/items/weapons/tape.dm index b958fee662d0..0e443936683c 100644 --- a/code/game/objects/items/weapons/tape.dm +++ b/code/game/objects/items/weapons/tape.dm @@ -1,158 +1,272 @@ -/obj/item/tape_roll - name = "duct tape" - desc = "A roll of sticky tape. Possibly for taping ducks... or was that ducts?" - icon = 'icons/obj/bureaucracy.dmi' +/////////////////////////////////////////////// +// Tape Roll +/////////////////////////////////////////////// +/**Base class for all things tape, with a limit amount of uses. */ +/obj/item/stack/tape_roll + name = "roll of tape" + gender = NEUTER + singular_name = "length of tape" + plural_name = "lengths of tape" + amount = 32 + max_amount = 32 + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + max_health = 10 + matter_multiplier = 0.25 + +/obj/item/stack/tape_roll/can_split() + return FALSE +/obj/item/stack/tape_roll/can_merge_stacks(var/obj/item/stack/other) + return FALSE + +/////////////////////////////////////////////// +// Duct Tape +/////////////////////////////////////////////// +/obj/item/stack/tape_roll/duct_tape + name = "duct tape roll" + desc = "A roll of durable, one-sided sticky tape. Possibly for taping ducks... or was that ducts?" + icon = 'icons/obj/bureaucracy.dmi' icon_state = "taperoll" - w_class = ITEM_SIZE_SMALL - -/obj/item/tape_roll/attack(var/mob/living/carbon/human/H, var/mob/user) - if(istype(H)) - if(user.zone_sel.selecting == BP_EYES) - - if(!H.organs_by_name[BP_HEAD]) - to_chat(user, "\The [H] doesn't have a head.") - return - if(!H.check_has_eyes()) - to_chat(user, "\The [H] doesn't have any eyes.") - return - if(H.glasses) - to_chat(user, "\The [H] is already wearing somethign on their eyes.") - return - if(H.head && (H.head.body_parts_covered & FACE)) - to_chat(user, "Remove their [H.head] first.") - return - user.visible_message("\The [user] begins taping over \the [H]'s eyes!") - - if(!do_mob(user, H, 30)) - return - - // Repeat failure checks. - if(!H || !src || !H.organs_by_name[BP_HEAD] || !H.check_has_eyes() || H.glasses || (H.head && (H.head.body_parts_covered & FACE))) - return - - playsound(src, 'sound/effects/tape.ogg',25) - user.visible_message("\The [user] has taped up \the [H]'s eyes!") - H.equip_to_slot_or_del(new /obj/item/clothing/glasses/blindfold/tape(H), slot_glasses) - - else if(user.zone_sel.selecting == BP_MOUTH || user.zone_sel.selecting == BP_HEAD) - if(!H.organs_by_name[BP_HEAD]) - to_chat(user, "\The [H] doesn't have a head.") - return - if(!H.check_has_mouth()) - to_chat(user, "\The [H] doesn't have a mouth.") - return - if(H.wear_mask) - to_chat(user, "\The [H] is already wearing a mask.") - return - if(H.head && (H.head.body_parts_covered & FACE)) - to_chat(user, "Remove their [H.head] first.") - return - playsound(src, 'sound/effects/tape.ogg',25) - user.visible_message("\The [user] begins taping up \the [H]'s mouth!") - - if(!do_mob(user, H, 30)) - return - - // Repeat failure checks. - if(!H || !src || !H.organs_by_name[BP_HEAD] || !H.check_has_mouth() || H.wear_mask || (H.head && (H.head.body_parts_covered & FACE))) - return - playsound(src, 'sound/effects/tape.ogg',25) - user.visible_message("\The [user] has taped up \the [H]'s mouth!") - H.equip_to_slot_or_del(new /obj/item/clothing/mask/muzzle/tape(H), slot_wear_mask) - - else if(user.zone_sel.selecting == BP_R_HAND || user.zone_sel.selecting == BP_L_HAND) - playsound(src, 'sound/effects/tape.ogg',25) - var/obj/item/handcuffs/cable/tape/T = new(user) - if(!T.place_handcuffs(H, user)) - qdel(T) - - else if(user.zone_sel.selecting == BP_CHEST) - if(H.wear_suit && istype(H.wear_suit, /obj/item/clothing/suit/space)) - H.wear_suit.attackby(src, user)//everything is handled by attackby - else - to_chat(user, "\The [H] isn't wearing a spacesuit for you to reseal.") + item_flags = ITEM_FLAG_NO_BLUDGEON + +/obj/item/stack/tape_roll/duct_tape/Initialize(mapload, amount, material) + . = ..() + set_extension(src, /datum/extension/tool/variable/simple, list( + TOOL_BONE_GEL = TOOL_QUALITY_MEDIOCRE, + TOOL_SUTURES = TOOL_QUALITY_BAD + )) + +/obj/item/stack/tape_roll/duct_tape/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(user.get_target_zone() == BP_R_HAND || user.get_target_zone() == BP_L_HAND) + if(!can_use(4)) + to_chat(user, SPAN_WARNING("There's not enough [plural_name] in your [src] to tape \the [target]'s hands! You need at least 4 [plural_name].")) + return TRUE + use(4) + playsound(src, 'sound/effects/tape.ogg',25) + var/obj/item/handcuffs/cable/tape/T = new(user) + if(!T.place_handcuffs(target, user)) + qdel(T) + return TRUE + if(user.get_target_zone() == BP_CHEST) + var/obj/item/clothing/suit/space/suit = target.get_equipped_item(slot_wear_suit_str) + if(istype(suit)) + suit.attackby(src, user)//everything is handled by attackby else - return ..() - return 1 + to_chat(user, SPAN_WARNING("\The [target] isn't wearing a spacesuit for you to reseal.")) + return TRUE -/obj/item/tape_roll/proc/stick(var/obj/item/W, mob/user) - if(!istype(W, /obj/item/paper) || istype(W, /obj/item/paper/sticky) || !user.unEquip(W)) - return - var/obj/item/ducttape/tape = new(get_turf(src)) - tape.attach(W) - user.put_in_hands(tape) + if(!target?.should_have_limb(BP_HEAD)) + return ..() -/obj/item/ducttape - name = "piece of tape" - desc = "A piece of sticky tape." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "tape" - w_class = ITEM_SIZE_TINY - layer = ABOVE_OBJ_LAYER + if(user.get_target_zone() == BP_EYES) - var/obj/item/stuck = null + if(!GET_EXTERNAL_ORGAN(target, BP_HEAD)) + to_chat(user, SPAN_WARNING("\The [target] doesn't have a head.")) + return TRUE + + if(!target.check_has_eyes()) + to_chat(user, SPAN_WARNING("\The [target] doesn't have any eyes.")) + return TRUE + + if(target.get_equipped_item(slot_glasses_str)) + to_chat(user, SPAN_WARNING("\The [target] is already wearing something on their eyes.")) + return TRUE + + var/obj/item/head = target.get_equipped_item(slot_head_str) + if(head && (head.body_parts_covered & SLOT_FACE)) + to_chat(user, SPAN_WARNING("Remove their [head] first.")) + return TRUE + + if(!can_use(2)) + to_chat(user, SPAN_WARNING("There's not enough [plural_name] in your [src] to tape \the [target]'s eyes! You need at least 2 [plural_name].")) + return TRUE + + user.visible_message(SPAN_WARNING("\The [user] begins taping over \the [target]'s eyes!")) + if(!do_mob(user, target, 30)) + return TRUE + + // Repeat failure checks. + if(!target || !src || !GET_EXTERNAL_ORGAN(target, BP_HEAD) || !target.check_has_eyes() || target.get_equipped_item(slot_glasses_str)) + return TRUE + + head = target.get_equipped_item(slot_head_str) + if(head && (head.body_parts_covered & SLOT_FACE)) + return TRUE + + use(2) + playsound(src, 'sound/effects/tape.ogg',25) + user.visible_message(SPAN_WARNING("\The [user] has taped up \the [target]'s eyes!")) + target.equip_to_slot_or_del(new /obj/item/clothing/glasses/blindfold/tape(target), slot_glasses_str) + return TRUE + + if(user.get_target_zone() == BP_MOUTH || user.get_target_zone() == BP_HEAD) + + if(!GET_EXTERNAL_ORGAN(target, BP_HEAD)) + to_chat(user, SPAN_WARNING("\The [target] doesn't have a head.")) + return TRUE + + if(!target.check_has_mouth()) + to_chat(user, SPAN_WARNING("\The [target] doesn't have a mouth.")) + return TRUE + + if(target.get_equipped_item(slot_wear_mask_str)) + to_chat(user, SPAN_WARNING("\The [target] is already wearing a mask.")) + return TRUE + + var/obj/item/head = target.get_equipped_item(slot_head_str) + if(head && (head.body_parts_covered & SLOT_FACE)) + to_chat(user, SPAN_WARNING("Remove their [head] first.")) + return TRUE + + if(!can_use(2)) + to_chat(user, SPAN_WARNING("There's not enough [plural_name] in your [src] to tape \the [target]'s mouth! You need at least 2 [plural_name].")) + return TRUE + + playsound(src, 'sound/effects/tape.ogg',25) + user.visible_message(SPAN_WARNING("\The [user] begins taping up \the [target]'s mouth!")) + + if(!do_mob(user, target, 30)) + return TRUE + + // Repeat failure checks. + if(!target || !src || !GET_EXTERNAL_ORGAN(target, BP_HEAD) || !target.check_has_mouth() || target.get_equipped_item(slot_wear_mask_str)) + return TRUE + + head = target.get_equipped_item(slot_head_str) + if(head && (head.body_parts_covered & SLOT_FACE)) + return TRUE + + use(2) + playsound(src, 'sound/effects/tape.ogg',25) + user.visible_message(SPAN_WARNING("\The [user] has taped up \the [target]'s mouth!")) + target.equip_to_slot_or_del(new /obj/item/clothing/mask/muzzle/tape(target), slot_wear_mask_str) + return TRUE -/obj/item/ducttape/attack_hand(var/mob/user) - anchored = FALSE // Unattach it from whereever it's on, if anything. return ..() -/obj/item/ducttape/Initialize() +/obj/item/stack/tape_roll/duct_tape/proc/stick(var/obj/item/used_item, mob/user) + if(!(used_item.item_flags & ITEM_FLAG_CAN_TAPE) || !user.try_unequip(used_item)) + return FALSE + if(!can_use(1)) + return FALSE + use(1) + var/obj/item/duct_tape/tape = new(get_turf(src)) + tape.attach(used_item) + user.put_in_hands(tape) + return TRUE + +/////////////////////////////////////////////////////////// +// Piece of Duct Tape +/////////////////////////////////////////////////////////// +/obj/item/duct_tape + name = "piece of tape" + desc = "A piece of sticky tape." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "tape" + w_class = ITEM_SIZE_TINY + layer = ABOVE_OBJ_LAYER + material = /decl/material/solid/organic/plastic + var/obj/item/stuck = null + var/crumpled = FALSE //If crumpled we become useless trash + +/obj/item/duct_tape/Initialize(ml, material_key) . = ..() item_flags |= ITEM_FLAG_NO_BLUDGEON -/obj/item/ducttape/examine() - return stuck ? stuck.examine(arglist(args)) : ..() +/obj/item/duct_tape/get_matter_amount_modifier() + return 0.2 + +/obj/item/duct_tape/attack_hand(var/mob/user) + if(user.check_dexterity(DEXTERITY_HOLD_ITEM)) + anchored = FALSE // Unattach it from whereever it's on, if anything. + return ..() + +/obj/item/duct_tape/attackby(obj/item/used_item, mob/user) + return stuck? stuck.attackby(used_item, user) : ..() + +/obj/item/duct_tape/examined_by(mob/user, distance, infix, suffix) + return stuck ? stuck.examined_by(user, distance, infix, suffix) : ..() -/obj/item/ducttape/proc/attach(var/obj/item/W) - stuck = W - anchored = TRUE - W.forceMove(src) - icon_state = W.icon_state + "_taped" - name = W.name + " (taped)" - overlays = W.overlays +/obj/item/duct_tape/proc/attach(var/obj/item/used_item) + stuck = used_item + anchored = TRUE + SetName("[used_item.name] (taped)") + used_item.forceMove(src) + playsound(src, 'sound/effects/tape.ogg', 25) + update_icon() -/obj/item/ducttape/attack_self(mob/user) +/obj/item/duct_tape/on_update_icon() + . = ..() + underlays.Cut() + if(stuck) + icon_state = "tape_short" + var/mutable_appearance/MA = new(stuck) + switch(dir) + if(NORTH) + MA.pixel_x = 0 + MA.pixel_y = 8 + if(SOUTH) + MA.pixel_x = 0 + MA.pixel_y = -8 + if(EAST) + MA.pixel_x = 8 + MA.pixel_y = 0 + if(WEST) + MA.pixel_x = -8 + MA.pixel_y = 0 + underlays += MA + + else if(crumpled) + icon_state = "tape_crumpled" + else + icon_state = "tape" + +/obj/item/duct_tape/attack_self(mob/user) if(!stuck) return - - to_chat(user, "You remove \the [initial(name)] from [stuck].") + SetName(initial(name)) + to_chat(user, "You remove \the [name] from [stuck].") user.put_in_hands(stuck) stuck = null - qdel(src) + crumpled = TRUE + user.try_unequip(src, get_turf(user)) -/obj/item/ducttape/afterattack(var/A, mob/user, flag, params) +/obj/item/duct_tape/afterattack(atom/target, mob/user, proximity_flag, click_parameters) - if(!in_range(user, A) || istype(A, /obj/machinery/door) || !stuck) + if(!CanPhysicallyInteractWith(user, target) || istype(target, /obj/machinery/door) || !stuck || crumpled) return - var/turf/target_turf = get_turf(A) + var/turf/target_turf = get_turf(target) var/turf/source_turf = get_turf(user) var/dir_offset = 0 if(target_turf != source_turf) dir_offset = get_dir(source_turf, target_turf) - if(!(dir_offset in GLOB.cardinal)) + if(!(dir_offset in global.cardinal)) to_chat(user, "You cannot reach that from here.")// can only place stuck papers in cardinal directions, to return // reduce papers around corners issue. - if(!user.unEquip(src, source_turf)) + if(!user.try_unequip(src, source_turf)) return playsound(src, 'sound/effects/tape.ogg',25) + set_dir(dir_offset) layer = ABOVE_WINDOW_LAYER - - if(params) - var/list/mouse_control = params2list(params) + + if(click_parameters) + var/list/mouse_control = params2list(click_parameters) if(mouse_control["icon-x"]) - pixel_x = text2num(mouse_control["icon-x"]) - 16 + default_pixel_x = text2num(mouse_control["icon-x"]) - 16 if(dir_offset & EAST) - pixel_x += 32 + default_pixel_x += 32 else if(dir_offset & WEST) - pixel_x -= 32 + default_pixel_x -= 32 if(mouse_control["icon-y"]) - pixel_y = text2num(mouse_control["icon-y"]) - 16 + default_pixel_y = text2num(mouse_control["icon-y"]) - 16 if(dir_offset & NORTH) - pixel_y += 32 + default_pixel_y += 32 else if(dir_offset & SOUTH) - pixel_y -= 32 + default_pixel_y -= 32 + reset_offsets(0) diff --git a/code/game/objects/items/weapons/tech_disks.dm b/code/game/objects/items/weapons/tech_disks.dm index 56b879b06156..c33fceca35b6 100644 --- a/code/game/objects/items/weapons/tech_disks.dm +++ b/code/game/objects/items/weapons/tech_disks.dm @@ -1,24 +1,145 @@ +/////////////////////////////////////////////////////////////////////////////// +// Data Disk +/////////////////////////////////////////////////////////////////////////////// /obj/item/disk - icon = 'icons/obj/cloning.dmi' - icon_state = "datadisk2" - item_state = "card-id" - w_class = ITEM_SIZE_SMALL - matter = list(/decl/material/solid/plastic = 30, /decl/material/solid/metal/steel = 30, /decl/material/solid/glass = 10) + name = "data disk" + desc = "A standard 3.5-inch floppy disk for storing computer files... What's even an inch?" + icon = 'icons/obj/items/device/diskette.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE) + throw_range = 10 + throw_speed = 6 + var/label + var/free_blocks = 14400 //Blocks + var/tmp/block_capacity = 14400 //Blocks + var/list/stored_files //Associative list of file name to computer_file. +/obj/item/disk/proc/can_write_file(var/datum/computer_file/data/F) + return F?.block_size <= free_blocks + +/**Writes a file to the disk. Fails if the file is bigger than the amount of free blocks left. */ +/obj/item/disk/proc/write_file(var/datum/computer_file/data/F, var/new_name = null) + if(F.block_size > free_blocks) + return FALSE + F = F.Clone() + if(length(new_name)) + F.filename = new_name + + var/datum/computer_file/existing = LAZYACCESS(stored_files, F.filename) + if(existing && existing != F) + delete_file(F.filename) + + F.holder = weakref(src) + LAZYSET(stored_files, F.filename, F) + free_blocks = clamp(round(free_blocks - F.block_size), 0, block_capacity) + return TRUE + +/**Read and returns a file by filename. */ +/obj/item/disk/proc/read_file(var/name) + return LAZYACCESS(stored_files, name) + +/**Clone the file. */ +/obj/item/disk/proc/copy_file(var/name) + var/datum/computer_file/F = LAZYACCESS(stored_files, name) + return F?.Clone() + +/**Delete a specific file. Fails if file is write protected, and force is FALSE. */ +/obj/item/disk/proc/delete_file(var/name, var/force = FALSE) + var/datum/computer_file/data/F = LAZYACCESS(stored_files, name) + if(!F || (F.read_only && !force)) + return FALSE + free_blocks = clamp(round(free_blocks + F.block_size), 0, block_capacity) + // do not qdel; should be GC'd once it has no references anyway + F.holder = null + LAZYREMOVE(stored_files, name) + return TRUE + +/**Renames a file's handle on the disk. Does not rename the file itself. */ +/obj/item/disk/proc/rename_file(var/oldname, var/newname, var/force = FALSE) + var/datum/computer_file/data/F = LAZYACCESS(stored_files, oldname) + if(!F || (F.unrenamable && !force)) + return FALSE + stored_files -= oldname + stored_files[newname] = F + return TRUE + +/**Like a full disk format. Erase all files, even if write protected! */ +/obj/item/disk/proc/delete_all() + LAZYCLEARLIST(stored_files) + free_blocks = block_capacity + +/**Returns the first file with the matching file_extension, or null if it can't find one */ +/obj/item/disk/proc/contains_file_type(var/file_extension) + for(var/key in stored_files) + var/datum/computer_file/data/F = stored_files[key] + if(!istype(F)) + continue + if(F.filetype == file_extension) + return F + +/**Offers a simple input box to pick and return the name of a file currently on disk. */ +/obj/item/disk/proc/simple_pick_file(var/mob/user) + return input(user, "Choose a file.", "File") as anything in src.stored_files + +/obj/item/disk/proc/get_free_blocks() + return free_blocks + +/obj/item/disk/proc/get_blocks_capacity() + return block_capacity + +/obj/item/disk/on_update_icon() + . = ..() + var/list/details = list(mutable_appearance(icon, "slider", flags = RESET_COLOR)) + if(label) + details += mutable_appearance(icon, label, flags = RESET_COLOR) + add_overlay(details) + +/////////////////////////////////////////////////////////////////////////////// +// Random Data Disk +/////////////////////////////////////////////////////////////////////////////// +/obj/item/disk/random/Initialize(ml, material_key) + set_color(get_random_colour()) + . = ..() + +/////////////////////////////////////////////////////////////////////////////// +// Fabricator Data Disk +/////////////////////////////////////////////////////////////////////////////// /obj/item/disk/tech_disk name = "fabricator data disk" desc = "A disk for storing fabricator learning data for backup." + color = COLOR_BOTTLE_GREEN var/list/stored_tech +/////////////////////////////////////////////////////////////////////////////// +// Component Design Data Disk +/////////////////////////////////////////////////////////////////////////////// /obj/item/disk/design_disk name = "component design disk" desc = "A disk for storing device design data for construction in lathes." + color = COLOR_BLUE_GRAY var/datum/fabricator_recipe/blueprint /obj/item/disk/design_disk/attack_hand(mob/user) - if(user.a_intent == I_HURT && blueprint) - blueprint = null - SetName(initial(name)) - to_chat(user, SPAN_DANGER("You flick the erase switch and wipe \the [src].")) - return TRUE + if(!user.check_intent(I_FLAG_HARM) || !blueprint || !user.check_dexterity(DEXTERITY_KEYBOARDS)) + return ..() + blueprint = null + SetName(initial(name)) + to_chat(user, SPAN_DANGER("You flick the erase switch and wipe \the [src].")) + return TRUE + +/////////////////////////////////////////////////////////////////////////////// +// Exploration and Mining Data Disk +/////////////////////////////////////////////////////////////////////////////// +/obj/item/disk/survey + name = "survey data disk" + color = COLOR_DARK_BROWN + var/data = 0 + +/obj/item/disk/survey/get_examine_strings(mob/user, distance, infix, suffix) . = ..() + . += "A tiny indicator on \the [src] shows it holds [data] good explorer point\s." + +/obj/item/disk/survey/get_base_value() + . = holographic ? 0 : (sqrt(data) * 5) diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm deleted file mode 100644 index 5be83a2bcb65..000000000000 --- a/code/game/objects/items/weapons/teleportation.dm +++ /dev/null @@ -1,121 +0,0 @@ -/* Teleportation devices. - * Contains: - * Locator - * Hand-tele - */ - -/* - * Locator - */ -/obj/item/locator - name = "locator" - desc = "Used to track those with locater implants." - icon = 'icons/obj/items/device/locator.dmi' - icon_state = "locator" - var/temp = null - var/frequency = 1451 - var/broadcasting = null - var/listening = 1.0 - obj_flags = OBJ_FLAG_CONDUCTIBLE - w_class = ITEM_SIZE_SMALL - item_state = "electronic" - throw_speed = 4 - throw_range = 20 - origin_tech = "{'magnets':1}" - material = /decl/material/solid/metal/aluminium - -/obj/item/locator/attack_self(mob/user) - user.set_machine(src) - var/dat - if (src.temp) - dat = "[src.temp]

              Clear" - else - dat = {" -Persistent Signal Locator
              -Frequency: -- -- [format_frequency(src.frequency)] -+ -+
              - -Refresh"} - show_browser(user, dat, "window=radio") - onclose(user, "radio") - return - -/obj/item/locator/Topic(href, href_list) - ..() - if (usr.stat || usr.restrained()) - return - var/turf/current_location = get_turf(usr)//What turf is the user on? - if(!current_location||current_location.z==2)//If turf was not found or they're on z level 2. - to_chat(usr, "The [src] is malfunctioning.") - return - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) - usr.set_machine(src) - if (href_list["refresh"]) - src.temp = "Persistent Signal Locator
              " - var/turf/sr = get_turf(src) - - if (sr) - src.temp += "Located Beacons:
              " - - for(var/obj/item/radio/beacon/W in world) - if(!W.functioning) - continue - if (W.frequency == src.frequency) - var/turf/tr = get_turf(W) - if (tr.z == sr.z && tr) - var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) - if (direct < 5) - direct = "very strong" - else - if (direct < 10) - direct = "strong" - else - if (direct < 20) - direct = "weak" - else - direct = "very weak" - src.temp += "[W.code]-[dir2text(get_dir(sr, tr))]-[direct]
              " - - src.temp += "Extranneous Signals:
              " - for (var/obj/item/implant/tracking/W in world) - if (!W.implanted || !(istype(W.loc,/obj/item/organ/external) || ismob(W.loc))) - continue - else - var/mob/M = W.loc - if (M.stat == 2) - if (M.timeofdeath + 6000 < world.time) - continue - - var/turf/tr = get_turf(W) - if (tr.z == sr.z && tr) - var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) - if (direct < 20) - if (direct < 5) - direct = "very strong" - else - if (direct < 10) - direct = "strong" - else - direct = "weak" - src.temp += "[W.id]-[dir2text(get_dir(sr, tr))]-[direct]
              " - - src.temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

              Refresh
              " - else - src.temp += "Processing Error: Unable to locate orbital position.
              " - else - if (href_list["freq"]) - src.frequency += text2num(href_list["freq"]) - src.frequency = sanitize_frequency(src.frequency) - else - if (href_list["temp"]) - src.temp = null - if (istype(src.loc, /mob)) - attack_self(src.loc) - else - for(var/mob/M in viewers(1, src)) - if (M.client) - src.attack_self(M) - return diff --git a/code/game/objects/items/weapons/tools/crowbar.dm b/code/game/objects/items/weapons/tools/crowbar.dm deleted file mode 100644 index 2f843cb621c8..000000000000 --- a/code/game/objects/items/weapons/tools/crowbar.dm +++ /dev/null @@ -1,71 +0,0 @@ -/obj/item/crowbar - name = "crowbar" - desc = "A heavy crowbar, good and solid in your hand." - icon = 'icons/obj/items/tool/crowbar.dmi' - icon_state = ICON_STATE_WORLD - slot_flags = SLOT_BELT - material_force_multiplier = 0.25 - attack_cooldown = 2*DEFAULT_WEAPON_COOLDOWN - melee_accuracy_bonus = -10 - w_class = ITEM_SIZE_SMALL - origin_tech = "{'engineering':1}" - material = /decl/material/solid/metal/steel - center_of_mass = @"{'x':16,'y':20}" - attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") - applies_material_colour = TRUE - var/global/valid_colours = list(COLOR_RED_GRAY, COLOR_MAROON, COLOR_DARK_BROWN, COLOR_GRAY20) - var/handle_color - var/shape_variations = 1 - var/shape_type - //List of things crowbars made from brittle materials have high chance of breaking on. - var/global/list/break_chances = list( - /obj/machinery/door = 80, - /turf/simulated/floor/tiled = 25, - /mob/living = 15, - /obj/machinery = 15 - ) - -/obj/item/crowbar/get_autopsy_descriptors() - . = ..() - . += "narrow" - -/obj/item/crowbar/on_update_icon() - ..() - if(!shape_type) - shape_type = rand(1,shape_variations) - icon_state = "[get_world_inventory_state()][shape_type]" - if(!handle_color) - handle_color = pick(valid_colours) - overlays += get_mutable_overlay(icon, "[get_world_inventory_state()]_handle[shape_type]", handle_color) - -/obj/item/crowbar/afterattack(atom/target, mob/user) - . = ..() - if(!material.is_brittle()) - return - var/break_chance = 5 - - if(QDELETED(src)) - return - for(var/checktype in break_chances) - if(istype(target, checktype)) - break_chance = break_chances[checktype] - break - if(prob(break_chance)) - playsound(user, 'sound/effects/snap.ogg', 40, 1) - to_chat(user, SPAN_WARNING("\The [src] shatters like the cheap garbage it was!")) - qdel(src) - user.put_in_hands(new /obj/item/shard(get_turf(user), material.type)) - return - -/obj/item/crowbar/red - handle_color = COLOR_MAROON - -/obj/item/crowbar/gold - material = /decl/material/solid/metal/gold - -/obj/item/crowbar/cheap - name = "discount pry bar" - desc = "A plastic bar with a wedge. It looks so poorly manufactured that you're sure it will break if you try to use it." - material = /decl/material/solid/plastic - w_class = ITEM_SIZE_TINY - shape_variations = 6 diff --git a/code/game/objects/items/weapons/tools/screwdriver.dm b/code/game/objects/items/weapons/tools/screwdriver.dm deleted file mode 100644 index 48c62278e683..000000000000 --- a/code/game/objects/items/weapons/tools/screwdriver.dm +++ /dev/null @@ -1,50 +0,0 @@ -/obj/item/screwdriver - name = "screwdriver" - desc = "Your archetypal flathead screwdriver, with a nice, heavy polymer handle." - icon = 'icons/obj/items/tool/screwdriver.dmi' - icon_state = "screwdriver_preview" - slot_flags = SLOT_BELT | SLOT_EARS - w_class = ITEM_SIZE_TINY - material = /decl/material/solid/metal/steel - center_of_mass = @"{'x':16,'y':7}" - attack_verb = list("stabbed") - lock_picking_level = 5 - sharp = TRUE - applies_material_colour = TRUE - - var/global/valid_colours = list(COLOR_RED, COLOR_CYAN_BLUE, COLOR_PURPLE, COLOR_CHESTNUT, COLOR_ASSEMBLY_YELLOW, COLOR_BOTTLE_GREEN) - var/handle_color - -/obj/item/screwdriver/Initialize() - if (prob(75)) - src.pixel_y = rand(0, 16) - . = ..() - -/obj/item/screwdriver/on_update_icon() - ..() - if(!handle_color) - handle_color = pick(valid_colours) - overlays += get_mutable_overlay(icon, "[get_world_inventory_state()]_handle", handle_color) - -/obj/item/screwdriver/experimental_mob_overlay() - var/image/res = ..() - res.color = handle_color - return res - -/obj/item/screwdriver/get_on_belt_overlay() - var/image/res = ..() - if(res) - res.color = handle_color - return res - -/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) - if(!istype(M) || user.a_intent == I_HELP) - return ..() - if(user.zone_sel.selecting != BP_EYES && user.zone_sel.selecting != BP_HEAD) - return ..() - if((MUTATION_CLUMSY in user.mutations) && prob(50)) - M = user - return eyestab(M,user) - -/obj/item/screwdriver/gold - material = /decl/material/solid/metal/gold diff --git a/code/game/objects/items/weapons/tools/weldingtool.dm b/code/game/objects/items/weapons/tools/weldingtool.dm deleted file mode 100644 index 5eac6ccbdd6b..000000000000 --- a/code/game/objects/items/weapons/tools/weldingtool.dm +++ /dev/null @@ -1,420 +0,0 @@ -/obj/item/weldingtool - name = "welding tool" - icon = 'icons/obj/items/tool/welder.dmi' - icon_state = "welder" - item_state = "welder" - desc = "A portable welding gun with a port for attaching fuel tanks." - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - center_of_mass = @"{'x':14,'y':15}" - force = 5 - throwforce = 5 - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_SMALL - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - origin_tech = "{'engineering':1}" - - var/waterproof = FALSE - var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) - var/status = 1 //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) - var/welding_resource = "welding fuel" - var/obj/item/welder_tank/tank = /obj/item/welder_tank // where the fuel is stored - -/obj/item/weldingtool/Initialize() - if(ispath(tank)) - tank = new tank - w_class = tank.size_in_use - force = tank.unlit_force - - set_extension(src, /datum/extension/base_icon_state, icon_state) - update_icon() - - . = ..() - -/obj/item/weldingtool/Destroy() - if(welding) - STOP_PROCESSING(SSobj, src) - - QDEL_NULL(tank) - - return ..() - -/obj/item/weldingtool/get_heat() - . = max(..(), isOn() ? 3800 : 0) - -/obj/item/weldingtool/isflamesource() - . = isOn() - -/obj/item/weldingtool/examine(mob/user, distance) - . = ..() - if (!tank) - to_chat(user, "There is no [welding_resource] source attached.") - else - to_chat(user, (distance <= 1 ? "It has [get_fuel()] [welding_resource] remaining. " : "") + "[tank] is attached.") - -/obj/item/weldingtool/MouseDrop(atom/over) - if(!CanMouseDrop(over, usr)) - return - - if(istype(over, /obj/item/weldpack)) - var/obj/item/weldpack/wp = over - if(wp.welder) - to_chat(usr, "\The [wp] already has \a [wp.welder] attached.") - else if(usr.unEquip(src, wp)) - wp.welder = src - usr.visible_message("[usr] attaches \the [src] to \the [wp].", "You attach \the [src] to \the [wp].") - wp.update_icon() - return - - ..() - -/obj/item/weldingtool/attackby(obj/item/W, mob/user) - if(welding) - to_chat(user, SPAN_DANGER("Stop welding first!")) - return - - if(isScrewdriver(W)) - status = !status - if(status) - to_chat(user, SPAN_NOTICE("You secure the welder.")) - else - to_chat(user, SPAN_NOTICE("The welder can now be attached and modified.")) - src.add_fingerprint(user) - return - - if((!status) && (istype(W,/obj/item/stack/material/rods))) - var/obj/item/stack/material/rods/R = W - R.use(1) - var/obj/item/flamethrower/F = new/obj/item/flamethrower(user.loc) - user.drop_from_inventory(src, F) - F.weldtool = src - master = F - add_fingerprint(user) - return - - if (istype(W, /obj/item/welder_tank)) - if (tank) - to_chat(user, SPAN_WARNING("\The [src] already has a tank attached - remove it first.")) - return - if (user.get_active_hand() != src && user.get_inactive_hand() != src) - to_chat(user, SPAN_WARNING("You must hold the welder in your hands to attach a tank.")) - return - if (!user.unEquip(W, src)) - return - tank = W - user.visible_message("[user] slots \a [W] into \the [src].", "You slot \a [W] into \the [src].") - w_class = tank.size_in_use - force = tank.unlit_force - update_icon() - return - - ..() - - -/obj/item/weldingtool/attack_hand(mob/user) - if (tank && user.get_inactive_hand() == src) - if (!welding) - user.visible_message("[user] removes \the [tank] from \the [src].", "You remove \the [tank] from \the [src].") - user.put_in_hands(tank) - tank = null - w_class = initial(w_class) - force = initial(force) - update_icon() - else - to_chat(user, SPAN_DANGER("Turn off the welder first!")) - - else - ..() - -/obj/item/weldingtool/fluid_act(var/datum/reagents/fluids) - ..() - if(welding && !waterproof) - setWelding(0) - -/obj/item/weldingtool/Process() - if(welding) - if((!waterproof && submerged()) || !remove_fuel(0.05)) - setWelding(0) - -/obj/item/weldingtool/afterattack(var/obj/O, var/mob/user, proximity) - if(!proximity) - return - - if(istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && !welding) - if(!tank) - to_chat(user, SPAN_WARNING("\The [src] has no tank attached!")) - return - if (!tank.can_refuel) - to_chat(user, SPAN_WARNING("\The [tank] does not have a refuelling port.")) - return - O.reagents.trans_to_obj(tank, tank.max_fuel) - to_chat(user, SPAN_NOTICE("You refuel \the [tank].")) - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - return - - if(welding) - remove_fuel(1) - var/turf/location = get_turf(user) - if(isliving(O)) - var/mob/living/L = O - L.IgniteMob() - else if(istype(O)) - O.HandleObjectHeating(src, user, 700) - if (istype(location, /turf)) - location.hotspot_expose(700, 50, 1) - return - -/obj/item/weldingtool/attack_self(mob/user) - setWelding(!welding, usr) - return - -//Returns the amount of fuel in the welder -/obj/item/weldingtool/proc/get_fuel() - return tank ? REAGENT_VOLUME(tank.reagents, /decl/material/liquid/fuel) : 0 - -//Removes fuel from the welding tool. If a mob is passed, it will perform an eyecheck on the mob. This should probably be renamed to use() -/obj/item/weldingtool/proc/remove_fuel(var/amount = 1, var/mob/M = null) - if(!welding) - return 0 - if(get_fuel() >= amount) - burn_fuel(amount) - if(M) - M.welding_eyecheck()//located in mob_helpers.dm - set_light(0.7, 2, 5, l_color = COLOR_LIGHT_CYAN) - addtimer(CALLBACK(src, /atom/proc/update_icon), 5) - return 1 - else - if(M) - to_chat(M, SPAN_NOTICE("You need more [welding_resource] to complete this task.")) - return 0 - -/obj/item/weldingtool/proc/burn_fuel(var/amount) - if(!tank) - return - - var/mob/living/in_mob = null - - //consider ourselves in a mob if we are in the mob's contents and not in their hands - if(isliving(src.loc)) - var/mob/living/L = src.loc - if(!(L.l_hand == src || L.r_hand == src)) - in_mob = L - - if(in_mob) - amount = max(amount, 2) - tank.reagents.trans_type_to(in_mob, /decl/material/liquid/fuel, amount) - in_mob.IgniteMob() - - else - tank.reagents.remove_reagent(/decl/material/liquid/fuel, amount) - var/turf/location = get_turf(src.loc) - if(location) - location.hotspot_expose(700, 5) - -//Returns whether or not the welding tool is currently on. -/obj/item/weldingtool/proc/isOn() - return src.welding - -/obj/item/weldingtool/get_storage_cost() - if(isOn()) - return ITEM_SIZE_NO_CONTAINER - return ..() - -/obj/item/weldingtool/on_update_icon() - ..() - overlays.Cut() - if(tank) - overlays += image(icon, "welder_[tank.icon_state]") - if(welding) - overlays += image(icon, "welder_on") - set_light(0.6, 0.5, 2.5, l_color =COLOR_PALE_ORANGE) - else - set_light(0) - item_state = welding ? "welder1" : "welder" - var/mob/M = loc - if(istype(M)) - M.update_inv_l_hand() - M.update_inv_r_hand() - -//Sets the welding state of the welding tool. If you see W.welding = 1 anywhere, please change it to W.setWelding(1) -//so that the welding tool updates accordingly -/obj/item/weldingtool/proc/setWelding(var/set_welding, var/mob/M) - if (!status) - return - - if(!welding && !waterproof && submerged()) - if(M) - to_chat(M, SPAN_WARNING("You cannot light \the [src] underwater.")) - return - - var/turf/T = get_turf(src) - //If we're turning it on - if(set_welding && !welding) - if (get_fuel() > 0) - if(M) - to_chat(M, SPAN_NOTICE("You switch the [src] on.")) - else if(T) - T.visible_message(SPAN_WARNING("\The [src] turns on.")) - if (istype(src, /obj/item/weldingtool/electric)) - src.force = 11 - src.damtype = ELECTROCUTE - else - src.force = tank.lit_force - src.damtype = BURN - welding = 1 - update_icon() - START_PROCESSING(SSobj, src) - else - if(M) - to_chat(M, SPAN_NOTICE("You need more [welding_resource] to complete this task.")) - return - //Otherwise - else if(!set_welding && welding) - STOP_PROCESSING(SSobj, src) - if(M) - to_chat(M, SPAN_NOTICE("You switch \the [src] off.")) - else if(T) - T.visible_message(SPAN_WARNING("\The [src] turns off.")) - if (istype(src, /obj/item/weldingtool/electric)) - src.force = initial(force) - else - src.force = tank.unlit_force - src.damtype = BRUTE - src.welding = 0 - update_icon() - -/obj/item/weldingtool/attack(mob/living/M, mob/living/user, target_zone) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/S = H.organs_by_name[target_zone] - - if(!S || !S.is_robotic() || user.a_intent != I_HELP) - return ..() - - if(BP_IS_BRITTLE(S)) - to_chat(user, SPAN_WARNING("\The [M]'s [S.name] is hard and brittle - \the [src] cannot repair it.")) - return 1 - - if(!welding) - to_chat(user, SPAN_WARNING("You'll need to turn [src] on to patch the damage on [M]'s [S.name]!")) - return 1 - - if(S.robo_repair(15, BRUTE, "some dents", src, user)) - remove_fuel(1, user) - - else - return ..() - -/obj/item/weldingtool/get_autopsy_descriptors() - if(isOn()) - return list("jet of flame") - return ..() - -/obj/item/weldingtool/mini - tank = /obj/item/welder_tank/mini - -/obj/item/weldingtool/largetank - tank = /obj/item/welder_tank/large - -/obj/item/weldingtool/hugetank - tank = /obj/item/welder_tank/huge - -/obj/item/weldingtool/experimental - tank = /obj/item/welder_tank/experimental - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - -/////////////////////// -//Welding tool tanks// -///////////////////// -/obj/item/welder_tank - name = "\improper welding fuel tank" - desc = "An interchangeable fuel tank meant for a welding tool." - icon = 'icons/obj/items/tool/welder_tank.dmi' - icon_state = "tank_normal" - w_class = ITEM_SIZE_SMALL - force = 5 - throwforce = 5 - var/max_fuel = 20 - var/can_refuel = 1 - var/size_in_use = ITEM_SIZE_NORMAL - var/unlit_force = 7 - var/lit_force = 11 - -/obj/item/welder_tank/Initialize() - create_reagents(max_fuel) - reagents.add_reagent(/decl/material/liquid/fuel, max_fuel) - . = ..() - -/obj/item/welder_tank/afterattack(obj/O, mob/user, proximity) - if (!proximity) - return - if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src, O) <= 1) - if (!can_refuel) - to_chat(user, SPAN_DANGER("\The [src] does not have a refuelling port.")) - return - O.reagents.trans_to_obj(src, max_fuel) - to_chat(user, SPAN_NOTICE("You refuel \the [src].")) - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - -/obj/item/welder_tank/mini - name = "small welding fuel tank" - icon_state = "tank_small" - w_class = ITEM_SIZE_TINY - max_fuel = 5 - force = 4 - throwforce = 4 - size_in_use = ITEM_SIZE_SMALL - unlit_force = 5 - lit_force = 7 - -/obj/item/welder_tank/large - name = "large welding fuel tank" - icon_state = "tank_large" - w_class = ITEM_SIZE_SMALL - max_fuel = 40 - force = 6 - throwforce = 6 - size_in_use = ITEM_SIZE_NORMAL - - -/obj/item/welder_tank/huge - name = "huge welding fuel tank" - icon_state = "tank_huge" - w_class = ITEM_SIZE_NORMAL - max_fuel = 80 - force = 8 - throwforce = 8 - size_in_use = ITEM_SIZE_LARGE - unlit_force = 9 - lit_force = 15 - -/obj/item/welder_tank/experimental - name = "experimental welding fuel tank" - icon_state = "tank_experimental" - w_class = ITEM_SIZE_NORMAL - max_fuel = 40 - can_refuel = 0 - force = 8 - throwforce = 8 - size_in_use = ITEM_SIZE_LARGE - unlit_force = 9 - lit_force = 15 - var/last_gen = 0 - -/obj/item/welder_tank/experimental/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/item/welder_tank/experimental/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/welder_tank/experimental/Process() - var/cur_fuel = REAGENT_VOLUME(reagents, /decl/material/liquid/fuel) - if(cur_fuel < max_fuel) - var/gen_amount = ((world.time-last_gen)/25) - reagents.add_reagent(/decl/material/liquid/fuel, gen_amount) - last_gen = world.time \ No newline at end of file diff --git a/code/game/objects/items/weapons/tools/wirecutter.dm b/code/game/objects/items/weapons/tools/wirecutter.dm deleted file mode 100644 index da630a237f14..000000000000 --- a/code/game/objects/items/weapons/tools/wirecutter.dm +++ /dev/null @@ -1,47 +0,0 @@ -/obj/item/wirecutters - name = "wirecutters" - desc = "A special pair of pliers with cutting edges. Various brackets and manipulators built into the handle allow it to repair severed wiring." - icon = 'icons/obj/items/tool/wirecutters.dmi' - icon_state = ICON_STATE_WORLD - slot_flags = SLOT_BELT - w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':1,'engineering':1}" - material = /decl/material/solid/metal/steel - center_of_mass = @"{'x':18,'y':10}" - attack_verb = list("pinched", "nipped") - sharp = 1 - edge = 1 - applies_material_colour = TRUE - - var/handle_color - var/global/valid_colours = list(COLOR_RED, COLOR_MAROON, COLOR_SEDONA, PIPE_COLOR_YELLOW, COLOR_BABY_BLUE) - -/obj/item/wirecutters/on_update_icon() - . = ..() - if(!handle_color) - handle_color = pick(valid_colours) - overlays += overlay_image(icon, "[get_world_inventory_state()]_handle", handle_color, flags=RESET_COLOR) - -/obj/item/wirecutters/experimental_mob_overlay() - var/image/res = ..() - res.color = handle_color - return res - -/obj/item/wirecutters/get_on_belt_overlay() - var/image/res = ..() - if(res) - res.color = handle_color - return res - -/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) - if(istype(C) && user.a_intent == I_HELP && (C.handcuffed) && (istype(C.handcuffed, /obj/item/handcuffs/cable))) - usr.visible_message("\The [usr] cuts \the [C]'s restraints with \the [src]!",\ - "You cut \the [C]'s restraints with \the [src]!",\ - "You hear cable being cut.") - C.handcuffed = null - if(C.buckled && C.buckled.buckle_require_restraints) - C.buckled.unbuckle_mob() - C.update_inv_handcuffed() - return - else - ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/tools/wrench.dm b/code/game/objects/items/weapons/tools/wrench.dm deleted file mode 100644 index 359608902313..000000000000 --- a/code/game/objects/items/weapons/tools/wrench.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/wrench - name = "wrench" - desc = "A good, durable combination wrench, with self-adjusting, universal open- and ring-end mechanisms to match a wide variety of nuts and bolts." - icon = 'icons/obj//items/tool/wrench.dmi' - icon_state = ICON_STATE_WORLD - slot_flags = SLOT_BELT - material_force_multiplier = 0.2 - w_class = ITEM_SIZE_SMALL - origin_tech = "{'materials':1,'engineering':1}" - material = /decl/material/solid/metal/steel - center_of_mass = @"{'x':17,'y':16}" - attack_verb = list("bashed", "battered", "bludgeoned", "whacked") - applies_material_colour = TRUE - var/handle_color - var/global/valid_colours = list(COLOR_RED_GRAY, COLOR_MAROON, COLOR_DARK_BROWN, COLOR_GRAY20) - -/obj/item/wrench/on_update_icon() - . = ..() - if(!handle_color) - handle_color = pick(valid_colours) - overlays += get_mutable_overlay(icon, "[get_world_inventory_state()]_handle", handle_color) \ No newline at end of file diff --git a/code/game/objects/items/weapons/towels.dm b/code/game/objects/items/weapons/towels.dm index 3592db222f39..087980586f43 100644 --- a/code/game/objects/items/weapons/towels.dm +++ b/code/game/objects/items/weapons/towels.dm @@ -1,63 +1,248 @@ /obj/item/towel name = "towel" + desc = "A soft cotton towel." icon = 'icons/obj/items/towel.dmi' - icon_state = "towel" + icon_state = ICON_STATE_WORLD item_flags = ITEM_FLAG_IS_BELT - slot_flags = SLOT_HEAD | SLOT_BELT | SLOT_OCLOTHING - force = 0.5 + slot_flags = SLOT_HEAD | SLOT_LOWER_BODY | SLOT_OVER_BODY + _base_attack_force = 1 w_class = ITEM_SIZE_NORMAL - attack_verb = list("whipped") + attack_verb = "whipped" hitsound = 'sound/weapons/towelwhip.ogg' - desc = "A soft cotton towel." + material = /decl/material/solid/organic/cloth + material_alteration = MAT_FLAG_ALTERATION_ALL + /// Are we currently laying flat on the ground, or are we rolled up? + var/laid_out = FALSE + /// A string added to the end of the material description, e.g. "used to dry yourself off". Optional, used by doormats. + var/additional_description + +/obj/item/towel/Initialize() + chem_volume = round(50 * (w_class / ITEM_SIZE_NORMAL)) // larger towels have more room, smaller ones have less + . = ..() + +/obj/item/towel/Destroy() + if(is_processing) + STOP_PROCESSING(SSobj, src) + return ..() + +// Does not rely on ATOM_IS_OPEN_CONTAINER because we want to be able to pour in but not out. +/obj/item/towel/can_be_poured_into(atom/source) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) + +/obj/item/towel/proc/update_material_description() + if(!istype(material) || !(material_alteration & MAT_FLAG_ALTERATION_DESC)) + return + var/is_soft = material.hardness < (MAT_VALUE_RIGID + MAT_VALUE_FLEXIBLE) / 2 // if we're closer to being flexible than rigid, we're considered soft + // todo: 'roughness' var to go along with hardness? sand is soft but rough, and maybe some sort of future plastic or rubber is hard but lush + // would this have any use aside from fluff strings? sandpaper grit maybe? + desc = "A [is_soft ? "soft" : "rugged"] [material.adjective_name] [base_name][additional_description ? " [additional_description]" : null]." // 'a soft cotton towel' by default. also supports 'a rugged leather doormat used to blah blah' etc + +/obj/item/towel/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(total_vol && distance <= 1) + var/max_vol = REAGENT_MAXIMUM_VOLUME(reagents) + var/liquid_adjective = "damp" + switch(total_vol / max_vol) + if(0 to 0.1) + return // not enough to even bother worrying about + if(0.4 to 0.6) + liquid_adjective = "wet" + if(0.6 to 0.8) + liquid_adjective = "drenched" + if(0.8 to 1) + liquid_adjective = "soaked through" + if(1) + liquid_adjective = "entirely saturated" + . += "It is [liquid_adjective] with [reagents.get_coated_name()]." + +/obj/item/towel/set_material(new_material) + . = ..() + if(istype(material)) + update_material_description() + +// Slowly dry out. +/obj/item/towel/Process() + var/total_volume = REAGENT_TOTAL_VOLUME(reagents) + if(total_volume) + reagents.remove_any(max(MINIMUM_CHEMICAL_VOLUME, CHEMS_QUANTIZE(total_volume * 0.05))) + if(!REAGENT_TOTAL_VOLUME(reagents)) + return PROCESS_KILL + +/obj/item/towel/update_name() + if(REAGENT_TOTAL_VOLUME(reagents)) + if(!REAGENTS_FREE_SPACE(reagents)) + name_prefix = "waterlogged" + else + name_prefix = "damp" + else + name_prefix = null + return ..() -/obj/item/towel/attack_self(mob/living/user) - if(user.a_intent == I_GRAB) - lay_out() +/obj/item/towel/on_reagent_change() + if(!(. = ..())) return + update_name() + if(REAGENT_TOTAL_VOLUME(reagents)) + if(!is_processing) + START_PROCESSING(SSobj, src) + else if(is_processing) + STOP_PROCESSING(SSobj, src) + +/obj/item/towel/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(!user.check_intent(I_FLAG_HARM) && dry_mob(target, user)) + return TRUE + return ..() + +/obj/item/towel/proc/dry_mob(mob/living/target, mob/living/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/reagent_space = REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents) + if(reagent_space <= 0) + to_chat(user, SPAN_WARNING("\The [src] is too saturated to dry [user == target ? "yourself" : "\the [target]"] off effectively.")) + else + var/decl/pronouns/pronouns = target.get_pronouns() + var/datum/reagents/touching_reagents = target.get_contact_reagents() + if(!REAGENT_TOTAL_VOLUME(touching_reagents)) + to_chat(user, SPAN_WARNING("[user == target ? "You are" : "\The [target] [pronouns.is]"] already dry.")) + else + user.visible_message(SPAN_NOTICE("\The [user] uses \the [src] to towel [user == target ? pronouns.self : "\the [target]"] dry.")) + touching_reagents.trans_to(src, min(REAGENT_TOTAL_VOLUME(touching_reagents), reagent_space)) + playsound(user, 'sound/weapons/towelwipe.ogg', 25, 1) + return TRUE + +/obj/item/towel/attack_self(mob/user) + if(user.check_intent(I_FLAG_GRAB)) + lay_out(user) + return TRUE + if(!user.check_intent(I_FLAG_HARM)) + return use_on_mob(user, user) + return ..() + +/obj/item/towel/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(laid_out) + icon_state = "[ICON_STATE_WORLD]-flat" // 'inventory-flat' is nonsensical - user.visible_message(SPAN_NOTICE("[user] uses [src] to towel themselves off.")) - playsound(user, 'sound/weapons/towelwipe.ogg', 25, 1) +// walking on a towel gets it dirty, so watch your step +// this is a good thing for doormats though. +/obj/item/towel/Crossed(atom/movable/crosser) + . = ..() + if(!isliving(crosser)) + return + var/mob/living/crossy_mob = crosser + var/list/obj/item/targets = crossy_mob.get_walking_contaminant_targets() + if(!LAZYLEN(targets) || !REAGENTS_FREE_SPACE(reagents)) + return + // i didn't wanna use process() to make it so that you can stand on it longer to clean your feet more + // and clicking on it picks it up, so i went with this overcomplicated garbage instead! + // basically: your move intent (creeping, walking, running) determines how much is cleaned + // if you walk slowly you'll always get totally cleaned + var/variability = 20 // by default cleans 80-120% (clamped 0-100) of reagents when walking normally + if(MOVING_DELIBERATELY(crossy_mob)) // always 100% cleaned when moving slowly + variability = 0 + else if(MOVING_QUICKLY(crossy_mob)) + variability = 70 // 30-170%, clamped to be 30-100% + for(var/obj/item/target in targets) + var/datum/reagents/target_coating = target.coating + var/coating_volume = REAGENT_TOTAL_VOLUME(target_coating) + if(!coating_volume) + continue + var/fraction_cleaned = clamp(CHEMS_QUANTIZE(rand(100 - variability, 100 + variability) / 100), 0, 100) + target.transfer_coating_to(src, fraction_cleaned * coating_volume) + if(!REAGENTS_FREE_SPACE(reagents)) + break /obj/item/towel/random/Initialize() . = ..() - color = get_random_colour() + set_color(get_random_colour()) + +/obj/item/towel/gold + paint_color = "#ffd700" + +/obj/item/towel/red + paint_color = "#ff0000" + +/obj/item/towel/purple + paint_color = "#800080" + +/obj/item/towel/cyan + paint_color = "#00ffff" + +/obj/item/towel/orange + paint_color = "#ff8c00" + +/obj/item/towel/pink + paint_color = "#ff6666" + +/obj/item/towel/light_blue + paint_color = "#3fc0ea" /obj/item/towel/black - name = "black towel" - color = "#222222" + paint_color = "#222222" /obj/item/towel/brown - name = "black towel" - color = "#854636" + paint_color = "#854636" /obj/item/towel/fleece // loot from the king of goats. it's a golden towel - name = "golden fleece" + name = "fleece" // sets its name to 'golden fleece' due to material desc = "The legendary Golden Fleece of Jason made real." - color = "#ffd700" - force = 1 - attack_verb = list("smote") + _base_attack_force = 1 + attack_verb = "smote" + material = /decl/material/solid/metal/gold -/obj/item/towel/verb/lay_out() - set name = "Lay Out Towel" - set category = "Object" +/obj/item/towel/fleece/update_material_description() + return FALSE - if(usr.incapacitated()) - return +/obj/item/towel/proc/lay_out(mob/user) + if(laid_out) + return FALSE + if(user.incapacitated()) + return FALSE + if(!user.drop_from_inventory(src)) + return FALSE + user.visible_message( + SPAN_NOTICE("[user] lays out \the [src] on the ground."), + SPAN_NOTICE("You lay out \the [src] on the ground.")) + laid_out = TRUE + set_dir(user.dir) + reset_offsets() + update_icon() + return TRUE - if(usr.drop_from_inventory(src)) - usr.visible_message( - SPAN_NOTICE("[usr] lay out \the [src] on the ground."), - SPAN_NOTICE("You lay out \the [src] on the ground.")) - desc = "A soft cotton towel." - icon_state = "towel_mask" - pixel_x = 0 - pixel_y = 0 - pixel_z = 0 - -/obj/item/towel/pickup(mob/user) - if((icon_state != initial(icon_state))) - desc = initial(desc) - icon_state = initial(icon_state) +/obj/item/towel/on_picked_up(mob/user, atom/old_loc) + ..() + if(laid_out) + laid_out = FALSE + reset_offsets(0) + update_icon() user.visible_message( - SPAN_NOTICE("[user] rolled up \the [src]."), + SPAN_NOTICE("[user] rolls up \the [src]."), SPAN_NOTICE("You pick up and fold \the [src].")) + +/obj/item/towel/doormat + name = "doormat" + icon = 'icons/obj/items/doormat.dmi' + w_class = ITEM_SIZE_LARGE + item_flags = ITEM_FLAG_NO_BLUDGEON // you can't towel whip someone with a doormat, it's too unwieldy + slot_flags = SLOT_NONE + additional_description = "used to wipe your feet when entering a building" + material = /decl/material/solid/organic/skin/fur + color = /decl/material/solid/organic/skin/fur::color + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/item/towel/doormat/Crossed(atom/movable/crosser) + var/had_space = REAGENTS_FREE_SPACE(reagents) + . = ..() + if(isliving(crosser) && had_space && !REAGENTS_FREE_SPACE(reagents)) + // this sucks, ideally we'd have a 'dirty' or 'wet' overlay to use for it, but i'm no spriter + visible_message(SPAN_WARNING("\The [src] is completely waterlogged!")) + +/// A mapping subtype for a doormat that's already been laid out. +/obj/item/towel/doormat/flat + laid_out = TRUE + icon_state = ICON_STATE_WORLD + "-flat" + +/obj/item/towel/doormat/flat/Initialize() + . = ..() + reset_offsets() // we don't want to overwrite randpixel but we don't want it to have a random offset either \ No newline at end of file diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm index 996392610436..397257e0d29f 100644 --- a/code/game/objects/items/weapons/traps.dm +++ b/code/game/objects/items/weapons/traps.dm @@ -1,18 +1,17 @@ /obj/item/beartrap - name = "mechanical trap" - throw_speed = 2 - throw_range = 1 - gender = PLURAL - icon = 'icons/obj/items/beartrap.dmi' - icon_state = "beartrap0" - randpixel = 0 - desc = "A mechanically activated leg trap. Low-tech, but reliable. Looks like it could really hurt if you set it off." - throwforce = 0 - w_class = ITEM_SIZE_NORMAL - origin_tech = "{'materials':1}" - material = /decl/material/solid/metal/steel - can_buckle = 0 //disallow manual un/buckling - var/deployed = 0 + name = "mechanical trap" + desc = "A mechanically activated leg trap. Low-tech, but reliable. Looks like it could really hurt if you set it off." + throw_speed = 2 + throw_range = 1 + gender = PLURAL + icon = 'icons/obj/items/beartrap.dmi' + icon_state = "beartrap0" + randpixel = 0 + w_class = ITEM_SIZE_NORMAL + origin_tech = @'{"materials":1}' + material = /decl/material/solid/metal/steel + can_buckle = FALSE //disallow manual un/buckling + var/deployed = FALSE /obj/item/beartrap/proc/can_use(mob/user) . = (user.check_dexterity(DEXTERITY_SIMPLE_MACHINES) && !issilicon(user) && !user.stat && !user.restrained()) @@ -20,92 +19,96 @@ /obj/item/beartrap/user_unbuckle_mob(mob/user) if(buckled_mob && can_use(user)) user.visible_message( - "\The [user] begins freeing \the [buckled_mob] from \the [src].", - "You carefully begin to free \the [buckled_mob] from \the [src].", - "You hear metal creaking." + SPAN_NOTICE("\The [user] begins freeing \the [buckled_mob] from \the [src]."), + SPAN_NOTICE("You carefully begin to free \the [buckled_mob] from \the [src]."), + SPAN_NOTICE("You hear metal creaking.") ) if(do_after(user, 60, src)) - user.visible_message("\The [buckled_mob] has been freed from \the [src] by \the [user].") + user.visible_message(SPAN_NOTICE("\The [buckled_mob] has been freed from \the [src] by \the [user].")) unbuckle_mob() - anchored = 0 + anchored = FALSE /obj/item/beartrap/attack_self(mob/user) ..() if(!deployed && can_use(user)) user.visible_message( - "[user] starts to deploy \the [src].", - "You begin deploying \the [src]!", + SPAN_DANGER("\The [user] starts to deploy \the [src]."), + SPAN_DANGER("You begin deploying \the [src]!"), "You hear the slow creaking of a spring." - ) + ) - if (do_after(user, 60, src) && user.unEquip(src)) + if (do_after(user, 6 SECONDS, src) && user.try_unequip(src)) user.visible_message( - "\The [user] has deployed \the [src].", - "You have deployed \the [src]!", + SPAN_DANGER("\The [user] has deployed \the [src]."), + SPAN_DANGER("You have deployed \the [src]!"), "You hear a latch click loudly." - ) - - deployed = 1 + ) + deployed = TRUE update_icon() - anchored = 1 + anchored = TRUE /obj/item/beartrap/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() if(buckled_mob) user_unbuckle_mob(user) - else if(deployed && can_use(user)) + return TRUE + if(!deployed || !can_use(user)) + return ..() + user.visible_message( + SPAN_DANGER("\The [user] starts to disarm \the [src]."), + SPAN_NOTICE("You begin disarming \the [src]!"), + "You hear a latch click followed by the slow creaking of a spring." + ) + if(do_after(user, 60, src)) user.visible_message( - "[user] starts to disarm \the [src].", - "You begin disarming \the [src]!", - "You hear a latch click followed by the slow creaking of a spring." - ) - if(do_after(user, 60, src)) - user.visible_message( - "[user] has disarmed \the [src].", - "You have disarmed \the [src]!" - ) - deployed = 0 - anchored = 0 - update_icon() - else - ..() + SPAN_DANGER("\The [user] has disarmed \the [src]."), + SPAN_NOTICE("You have disarmed \the [src]!") + ) + deployed = 0 + anchored = FALSE + update_icon() + return TRUE + +/obj/item/beartrap/proc/attack_mob(mob/victim) -/obj/item/beartrap/proc/attack_mob(mob/living/L) + if(victim.immune_to_floor_hazards()) + return FALSE var/target_zone - if(L.lying) + if(victim.current_posture.prone) target_zone = ran_zone() else target_zone = pick(BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG) - if(!L.apply_damage(30, BRUTE, target_zone, used_weapon=src)) - return 0 + if(!victim.apply_damage(30, BRUTE, target_zone, used_weapon=src)) + return FALSE //trap the victim in place - set_dir(L.dir) - buckle_mob(L) - to_chat(L, "The steel jaws of \the [src] bite into you, trapping you in place!") - deployed = 0 + set_dir(victim.dir) + buckle_mob(victim) + to_chat(victim, SPAN_DANGER("The steel jaws of \the [src] bite into you, trapping you in place!")) + deployed = FALSE + return TRUE /obj/item/beartrap/Crossed(atom/movable/AM) - if(deployed && isliving(AM)) - var/mob/living/L = AM - if(!MOVING_DELIBERATELY(L)) - L.visible_message( - "[L] steps on \the [src].", - "You step on \the [src]!", - "You hear a loud metallic snap!" - ) - attack_mob(L) - if(!buckled_mob) - anchored = 0 - deployed = 0 - update_icon() ..() + if(!deployed || !isliving(AM)) + return + var/mob/living/victim = AM + if(MOVING_DELIBERATELY(victim) || victim.immune_to_floor_hazards()) + return + victim.visible_message( + SPAN_DANGER("\The [victim] steps on \the [src]."), + SPAN_DANGER("You step on \the [src]!"), + "You hear a loud metallic snap!" + ) + attack_mob(victim) + if(!buckled_mob) + anchored = FALSE + deployed = FALSE + update_icon() /obj/item/beartrap/on_update_icon() - ..() - - if(!deployed) - icon_state = "beartrap0" - else - icon_state = "beartrap1" + . = ..() + icon_state = "beartrap[deployed]" diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 60ca8fc91aaf..445f92be6909 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -4,87 +4,74 @@ icon = 'icons/obj/items/weapon/nullrod.dmi' icon_state = "nullrod" item_state = "nullrod" - slot_flags = SLOT_BELT - force = 10 + slot_flags = SLOT_LOWER_BODY + item_flags = ITEM_FLAG_IS_WEAPON throw_speed = 1 throw_range = 4 - throwforce = 7 w_class = ITEM_SIZE_NORMAL + material = /decl/material/solid/glass + max_health = ITEM_HEALTH_NO_DAMAGE + _base_attack_force = 10 -/obj/item/nullrod/attack(mob/M, mob/living/user) //Paste from old-code to decult with a null rod. - admin_attack_log(user, M, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") +/obj/item/nullrod/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + admin_attack_log(user, target, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - //if(user != M) - if(M.mind && LAZYLEN(M.mind.learned_spells)) - M.silence_spells(300) //30 seconds - to_chat(M, "You've been silenced!") - return + user.do_attack_animation(target) if (!user.check_dexterity(DEXTERITY_WEAPONS)) - return + return TRUE - if ((MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, "The rod slips out of your hand and hits your head.") + if (user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + to_chat(user, SPAN_DANGER("The rod slips out of your hand and hits your head.")) user.take_organ_damage(10) - user.Paralyse(20) - return + SET_STATUS_MAX(user, STAT_PARA, 20) + return TRUE - if(GLOB.cult && iscultist(M)) - M.visible_message("\The [user] waves \the [src] over \the [M]'s head.") - GLOB.cult.offer_uncult(M) - return + if (holy_act(target, user)) + return TRUE - ..() + return ..() + +/obj/item/nullrod/proc/holy_act(mob/living/target, mob/living/user) + if(target.disable_abilities(30 SECONDS)) + to_chat(target, SPAN_DANGER("You've been silenced!")) + return TRUE + return FALSE /obj/item/nullrod/afterattack(var/atom/A, var/mob/user, var/proximity) if(!proximity) return + return A.nullrod_act(user, src) - if(istype(A, /obj/structure/deity/altar)) - var/obj/structure/deity/altar/altar = A - if(!altar.linked_god.silenced) //Don't want them to infinity spam it. - altar.linked_god.silence(10) - new /obj/effect/temporary(get_turf(altar),'icons/effects/effects.dmi',"purple_electricity_constant", 10) - altar.visible_message("\The [altar] groans in protest as reality settles around \the [src].") - - if(istype(A, /turf/simulated/wall/cult)) - var/turf/simulated/wall/cult/W = A - user.visible_message("\The [user] touches \the [A] with \the [src], and the enchantment affecting it fizzles away.", "You touch \the [A] with \the [src], and the enchantment affecting it fizzles away.") - W.ChangeTurf(/turf/simulated/wall) - - if(istype(A, /turf/simulated/floor/cult)) - var/turf/simulated/floor/cult/F = A - user.visible_message("\The [user] touches \the [A] with \the [src], and the enchantment affecting it fizzles away.", "You touch \the [A] with \the [src], and the enchantment affecting it fizzles away.") - F.ChangeTurf(/turf/simulated/floor) +/atom/proc/nullrod_act(mob/user, obj/item/nullrod/rod) + return FALSE -/obj/item/energy_blade_net +/obj/item/energy_net name = "energy net" desc = "It's a net made of green energy." icon = 'icons/effects/effects.dmi' icon_state = "energynet" - throwforce = 0 - force = 0 + max_health = 100 + _base_attack_force = 0 var/net_type = /obj/effect/energy_net -/obj/item/energy_blade_net/safari +/obj/item/energy_net/safari name = "animal net" desc = "An energized net meant to subdue animals." net_type = /obj/effect/energy_net/safari -/obj/item/energy_blade_net/dropped() +/obj/item/energy_net/dropped() ..() - spawn(10) - if(src) qdel(src) + QDEL_IN(src, 1 SECOND) -/obj/item/energy_blade_net/throw_impact(atom/hit_atom) +/obj/item/energy_net/throw_impact(atom/hit_atom) ..() try_capture_mob(hit_atom) // This will validate the hit_atom, then spawn an energy_net effect and qdel itself -/obj/item/energy_blade_net/proc/try_capture_mob(mob/living/M) +/obj/item/energy_net/proc/try_capture_mob(mob/living/M) if(!istype(M) || locate(/obj/effect/energy_net) in M.loc) qdel(src) @@ -97,8 +84,7 @@ qdel(src) // If we miss or hit an obstacle, we still want to delete the net. - spawn(10) - if(src) qdel(src) + QDEL_IN(src, 1 SECOND) /obj/effect/energy_net name = "energy net" @@ -106,16 +92,16 @@ icon = 'icons/effects/effects.dmi' icon_state = "energynet" - density = 1 - opacity = 0 - mouse_opacity = 1 - anchored = 1 + density = TRUE + opacity = FALSE + mouse_opacity = MOUSE_OPACITY_NORMAL + anchored = TRUE can_buckle = 0 //no manual buckling or unbuckling - var/health = 25 + max_health = 25 var/countdown = 15 - var/temporary = 1 - var/mob/living/carbon/captured = null + var/temporary = TRUE + var/mob/living/captured = null var/min_free_time = 50 var/max_free_time = 85 @@ -123,9 +109,9 @@ name = "animal net" desc = "An energized net meant to subdue animals." - anchored = 0 - health = 5 - temporary = 0 + anchored = FALSE + max_health = 5 + temporary = FALSE min_free_time = 5 max_free_time = 10 @@ -137,9 +123,6 @@ START_PROCESSING(SSobj, src) /obj/effect/energy_net/Destroy() - if(istype(captured, /mob/living/carbon)) - if(captured.handcuffed == src) - captured.handcuffed = null if(captured) unbuckle_mob() STOP_PROCESSING(SSobj, src) @@ -147,18 +130,21 @@ return ..() /obj/effect/energy_net/Process() + if(!captured) + qdel(src) + return PROCESS_KILL if(temporary) countdown-- if(captured.buckled != src) - health = 0 + current_health = 0 if(get_turf(src) != get_turf(captured)) //just in case they somehow teleport around or countdown = 0 if(countdown <= 0) - health = 0 + current_health = 0 healthcheck() /obj/effect/energy_net/Move() - ..() + . = ..() if(buckled_mob) buckled_mob.forceMove(src.loc) @@ -171,13 +157,10 @@ if(M.buckled) M.buckled.unbuckle_mob() buckle_mob(M) - if(istype(M, /mob/living/carbon)) - var/mob/living/carbon/C = M - if(!C.handcuffed) - C.handcuffed = src return 1 /obj/effect/energy_net/post_buckle_mob(mob/living/M) + ..() if(buckled_mob) layer = ABOVE_HUMAN_LAYER visible_message("\The [M] was caught in [src]!") @@ -186,7 +169,7 @@ reset_plane_and_layer() /obj/effect/energy_net/proc/healthcheck() - if(health <=0) + if(current_health <=0) set_density(0) if(countdown <= 0) visible_message("\The [src] fades away!") @@ -195,53 +178,45 @@ qdel(src) /obj/effect/energy_net/bullet_act(var/obj/item/projectile/Proj) - health -= Proj.get_structure_damage() + current_health -= Proj.get_structure_damage() healthcheck() return 0 /obj/effect/energy_net/explosion_act() ..() if(!QDELETED(src)) - health = 0 + current_health = 0 healthcheck() /obj/effect/energy_net/attack_hand(var/mob/user) - - var/mob/living/carbon/human/H = user - if(istype(H)) - if(H.species.can_shred(H)) - playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) - health -= rand(10, 20) - else - health -= rand(1,3) - - else if (MUTATION_HULK in user.mutations) - health = 0 + if(!user.check_intent(I_FLAG_HARM)) + return ..() + if(user.can_shred()) + playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) + current_health -= rand(10, 20) else - health -= rand(5,8) - - to_chat(H,"You claw at the energy net.") - + current_health -= rand(5,8) + to_chat(user, SPAN_DANGER("You claw at the energy net.")) healthcheck() - return + return TRUE -/obj/effect/energy_net/attackby(obj/item/W, mob/user) - health -= W.force +/obj/effect/energy_net/attackby(obj/item/used_item, mob/user) + current_health -= used_item.expend_attack_force(user) healthcheck() - ..() + return TRUE -obj/effect/energy_net/user_unbuckle_mob(mob/user) +/obj/effect/energy_net/user_unbuckle_mob(mob/user) return escape_net(user) /obj/effect/energy_net/proc/escape_net(mob/user) + set waitfor = FALSE visible_message( "\The [user] attempts to free themselves from \the [src]!", "You attempt to free yourself from \the [src]!" ) if(do_after(user, rand(min_free_time, max_free_time), src, incapacitation_flags = INCAPACITATION_DISABLED)) - health = 0 + current_health = 0 healthcheck() return 1 - else - return 0 + return 0 diff --git a/code/game/objects/items/weapons/weldbackpack.dm b/code/game/objects/items/weapons/weldbackpack.dm deleted file mode 100644 index fc8e8ac42b0c..000000000000 --- a/code/game/objects/items/weapons/weldbackpack.dm +++ /dev/null @@ -1,86 +0,0 @@ -/obj/item/weldpack - name = "welding kit" - desc = "An unwieldy, heavy backpack with two massive fuel tanks. Includes a connector for most models of portable welding tools." - slot_flags = SLOT_BACK - icon = 'icons/obj/items/welderpack.dmi' - icon_state = "welderpack" - w_class = ITEM_SIZE_HUGE - var/max_fuel = 350 - var/obj/item/weldingtool/welder - -/obj/item/weldpack/Initialize() - create_reagents(max_fuel) - reagents.add_reagent(/decl/material/liquid/fuel, max_fuel) - - . = ..() - -/obj/item/weldpack/Destroy() - QDEL_NULL(welder) - - . = ..() - -/obj/item/weldpack/attackby(obj/item/W, mob/user) - if(isWelder(W)) - var/obj/item/weldingtool/T = W - if(T.welding & prob(50)) - log_and_message_admins("triggered a fueltank explosion.", user) - to_chat(user, "That was stupid of you.") - explosion(get_turf(src),-1,0,2) - if(src) - qdel(src) - return - else - if(T.welding) - to_chat(user, "That was close!") - if(!T.tank) - to_chat(user, "\The [T] has no tank attached!") - src.reagents.trans_to_obj(T.tank, T.tank.max_fuel) - to_chat(user, "You refuel \the [W].") - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - return - else if(istype(W, /obj/item/welder_tank)) - var/obj/item/welder_tank/tank = W - src.reagents.trans_to_obj(tank, tank.max_fuel) - to_chat(user, "You refuel \the [W].") - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - return - - to_chat(user, "The tank will accept only a welding tool or cartridge.") - return - -/obj/item/weldpack/afterattack(obj/O, mob/user, proximity) - if(!proximity) // this replaces and improves the get_dist(src,O) <= 1 checks used previously - return - if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume < max_fuel) - O.reagents.trans_to_obj(src, max_fuel) - to_chat(user, "You crack the cap off the top of the pack and fill it back up again from the tank.") - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - return - else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume == max_fuel) - to_chat(user, "The pack is already full!") - return - -/obj/item/weldpack/attack_hand(mob/user) - if(welder && user.get_inactive_hand() == src) - user.put_in_hands(welder) - user.visible_message("[user] removes \the [welder] from \the [src].", "You remove \the [welder] from \the [src].") - welder = null - update_icon() - else - ..() - -/obj/item/weldpack/on_update_icon() - ..() - - overlays.Cut() - if(welder) - var/image/welder_image = image(welder.icon, icon_state = welder.icon_state) - welder_image.pixel_x = 16 - overlays += welder_image - -/obj/item/weldpack/examine(mob/user) - . = ..() - to_chat(user, text("\icon[] [] units of fuel left!", src, src.reagents.total_volume)) - - if(welder) - to_chat(user, "\The [welder] is attached.") diff --git a/code/game/objects/items/welding/electric_welder.dm b/code/game/objects/items/welding/electric_welder.dm new file mode 100644 index 000000000000..382690a971b4 --- /dev/null +++ b/code/game/objects/items/welding/electric_welder.dm @@ -0,0 +1,62 @@ +/obj/item/weldingtool/electric + name = "arc welder" + desc = "A man-portable arc welding tool." + icon = 'icons/obj/items/tool/welders/welder_arc.dmi' + welding_resource = "stored charge" + tank = null + waterproof = TRUE + lit_colour = COLOR_CYAN_BLUE + _base_attack_force = 7 + var/fuel_cost_multiplier = 10 + +/obj/item/weldingtool/electric/Initialize() + setup_power_supply() + . = ..() + +/obj/item/weldingtool/electric/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell/high + return ..(loaded_cell_type, /obj/item/cell, /datum/extension/loaded_cell, charge_value) + +/obj/item/weldingtool/electric/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/obj/item/cell/cell = get_cell() + if(cell) + if(distance == 0) + . += "It has [get_fuel()] [welding_resource] remaining." + . += "\The [cell] is attached." + else + . += "There is no [welding_resource] source attached." + +/obj/item/weldingtool/electric/afterattack(var/obj/O, var/mob/user, var/proximity) + if(proximity && istype(O, /obj/structure/reagent_dispensers/fueltank) && !welding) + to_chat(user, SPAN_WARNING("\The [src] runs on an internal charge and does not need to be refuelled.")) + return + . = ..() + +/obj/item/weldingtool/electric/get_cell() + . = ..() + if(!. && istype(loc, /obj/item/rig_module)) + var/obj/item/rig_module/module = loc + if(istype(module.holder)) + . = module.holder.get_cell() + +/obj/item/weldingtool/electric/get_fuel() + var/obj/item/cell/cell = get_cell() + return cell ? cell.charge : 0 + +/obj/item/weldingtool/electric/insert_tank(var/obj/item/chems/welder_tank/T, var/mob/user, var/no_updates = FALSE, var/quiet = FALSE) + return FALSE // No tanks! + +/obj/item/weldingtool/electric/attempt_modify(var/obj/item/used_item, var/mob/user) + return FALSE // NO ELECTRIC FLAMETHROWER + +/obj/item/weldingtool/electric/use_fuel(var/amount) + var/obj/item/cell/cell = get_cell() + if(cell) + return cell.use(amount * CELLRATE * fuel_cost_multiplier) > 0 + return FALSE + +/obj/item/weldingtool/electric/on_update_icon() + . = ..() + if(get_cell()) + add_overlay("[icon_state]-cell") diff --git a/code/game/objects/items/welding/weldbackpack.dm b/code/game/objects/items/welding/weldbackpack.dm new file mode 100644 index 000000000000..3dba78bfd1ff --- /dev/null +++ b/code/game/objects/items/welding/weldbackpack.dm @@ -0,0 +1,228 @@ +//////////////////////////////////////////////////////////// +//Welder gun +//////////////////////////////////////////////////////////// + +///Welder specifically for the welder pack. +/obj/item/weldingtool/weldpack + name = "welding gun" + desc = "A welding gun with hoses connecting into a welder fuel tank pack." + slot_flags = SLOT_HANDS + throw_speed = 0 + throw_range = 0 + drop_sound = 'sound/effects/holster/holsterin.ogg' + pickup_sound = 'sound/effects/holster/holsterout.ogg' + tank = null + randpixel = 0 //Prevent randpixel from screwing with backpack overlays + obj_flags = OBJ_FLAG_NO_STORAGE + var/obj/item/chems/weldpack/linked_pack + +/obj/item/weldingtool/weldpack/Initialize(ml, material_key, var/obj/item/chems/weldpack/pack) + . = ..() + if(istype(pack)) + linked_pack = pack + +/obj/item/weldingtool/weldpack/insert_tank(obj/item/chems/welder_tank/T, mob/user, no_updates, quiet) + return FALSE + +/obj/item/weldingtool/weldpack/remove_tank(mob/user) + return FALSE + +/obj/item/weldingtool/weldpack/toggle_unscrewed(mob/user) + return FALSE + +/obj/item/weldingtool/weldpack/attempt_modify(obj/item/used_item, mob/user) + return FALSE + +/obj/item/weldingtool/weldpack/dropped(mob/user) + . = ..() + if(linked_pack) + linked_pack.reattach_gun(user) + +/obj/item/weldingtool/weldpack/get_fuel() + return linked_pack? linked_pack.get_fuel() : 0 + +/obj/item/weldingtool/weldpack/use_fuel(amount) + . = TRUE + if(get_fuel() < amount) + . = FALSE //Try to burn as much as possible anyways + if(linked_pack) + linked_pack.remove_from_reagents(/decl/material/liquid/fuel, amount) + +/**Called by the parent when the welderpack is dropped */ +/obj/item/weldingtool/weldpack/proc/on_pack_dropped(var/mob/user) + if(!linked_pack.is_welder_attached()) + linked_pack.reattach_gun(user) + +/**Called by the parent when the welderpack is deleting */ +/obj/item/weldingtool/weldpack/proc/on_pack_deleted() + if(!linked_pack.is_welder_attached()) + linked_pack.reattach_gun() + +//////////////////////////////////////////////////////////// +//Welder Pack +//////////////////////////////////////////////////////////// +/obj/item/chems/weldpack + name = "welding kit" + desc = "An unwieldy, heavy backpack with two massive fuel tanks. Comes with an attached welder gun." + icon = 'icons/obj/items/welderpack.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_BACK + w_class = ITEM_SIZE_HUGE + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 350 + var/obj/item/weldingtool/weldpack/welder = /obj/item/weldingtool/weldpack + +// Duplicated from welder tanks. +/obj/item/chems/weldpack/afterattack(obj/O, mob/user, proximity, click_parameters) + if (!ATOM_IS_OPEN_CONTAINER(src) || !proximity) + return + if(standard_dispenser_refill(user, O)) + return TRUE + if(standard_pour_into(user, O)) + return TRUE + if(handle_eaten_by_mob(user, O) != EATEN_INVALID) + return TRUE + if(user.check_intent(I_FLAG_HARM)) + if(standard_splash_mob(user, O)) + return TRUE + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(reagents && total_vol) + to_chat(user, SPAN_DANGER("You splash the contents of \the [src] onto \the [O].")) + reagents.splash(O, total_vol) + return TRUE + return ..() + +/obj/item/chems/weldpack/populate_reagents() + add_to_reagents(/decl/material/liquid/fuel, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/weldpack/Initialize(ml, material_key) + if(ispath(welder)) + welder = new welder(src, null, src) + . = ..() + +/obj/item/chems/weldpack/Destroy() + if(welder) + welder.on_pack_deleted() //Force re-attach the gun, so it also gets deleted and doesn't stay in someone's hands + QDEL_NULL(welder) + . = ..() + +/obj/item/chems/weldpack/attackby(obj/item/used_item, mob/user) + + if(used_item.isflamesource() && get_fuel() && used_item.get_heat() >= 700 && prob(50)) + playsound(src, 'sound/items/Welder2.ogg', 90, TRUE) + try_detonate_reagents() + log_and_message_admins("triggered a fueltank explosion.", user) + return TRUE + + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/tool = used_item + if(tool.welding) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( + SPAN_DANGER("\The [user] singes [pronouns.his] [name] with [pronouns.his] [used_item.name]!"), + SPAN_DANGER("You singed your [name] with your [used_item.name]!") + ) + + if(used_item == welder) + return reattach_gun(user) + if(!tool.tank) + to_chat(user, SPAN_WARNING("\The [tool] has no tank attached!")) + return TRUE + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return TRUE + reagents.trans_to_obj(tool.tank, REAGENT_MAXIMUM_VOLUME(tool.tank.reagents)) + to_chat(user, SPAN_NOTICE("You refuel \the [used_item].")) + playsound(src, 'sound/effects/refill.ogg', 50, TRUE, -6) + return TRUE + + else if(istype(used_item, /obj/item/chems/welder_tank)) + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return TRUE + var/obj/item/chems/welder_tank/tank = used_item + reagents.trans_to_obj(tank, REAGENT_MAXIMUM_VOLUME(tank.reagents)) + to_chat(user, SPAN_NOTICE("You refuel \the [used_item].")) + playsound(src, 'sound/effects/refill.ogg', 50, TRUE, -6) + return TRUE + + return ..() + +/obj/item/chems/weldpack/afterattack(obj/O, mob/user, proximity) + if (!ATOM_IS_OPEN_CONTAINER(src) || !proximity) + return + if(standard_dispenser_refill(user, O)) + return TRUE + if(standard_pour_into(user, O)) + return TRUE + return ..() + +/obj/item/chems/weldpack/attack_hand(mob/user) + if(!is_welder_attached() || !user.check_dexterity(DEXTERITY_HOLD_ITEM)) + return ..() + if(user.is_holding_offhand(src)) + detach_gun(user) + return TRUE + var/curslot = user.get_equipped_slot_for_item(src) + if(curslot == slot_back_str || curslot == slot_s_store_str) + detach_gun(user) + return TRUE + return ..() + +/obj/item/chems/weldpack/on_update_icon() + . = ..() + if(is_welder_attached()) + var/mutable_appearance/welder_image = new(welder) + welder_image.appearance_flags |= RESET_COLOR + welder_image.plane = FLOAT_PLANE //Use parent plane + welder_image.pixel_y = 0 + welder_image.pixel_x = 15 + add_overlay(welder_image) + +/obj/item/chems/weldpack/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "[html_icon(src)] [REAGENT_TOTAL_VOLUME(reagents)] unit\s of fuel left!" + +/obj/item/chems/weldpack/dropped(mob/user) + . = ..() + if(welder) + welder.on_pack_dropped(user) + +/obj/item/chems/weldpack/proc/get_fuel() + return REAGENT_VOLUME(reagents, /decl/material/liquid/fuel) + +/obj/item/chems/weldpack/proc/is_welder_attached() + return welder && (welder.loc == src) + +/**Re-attach the welder gun to the pack.*/ +/obj/item/chems/weldpack/proc/reattach_gun(var/mob/user) + if(is_welder_attached()) + return + if(user) + to_chat(user, SPAN_NOTICE("You re-attach \the [welder] to \the [src].")) + if(welder.isOn()) + welder.turn_off(user) + + if(user && (user == welder.loc)) + if(!user.try_unequip(welder, src)) + return + else + welder.forceMove(src) + update_icon() + update_held_icon() + return TRUE + +/obj/item/chems/weldpack/proc/detach_gun(var/mob/user) + if(!is_welder_attached()) + return + if(!user) + return + to_chat(user, SPAN_NOTICE("You detach \the [welder] from \the [src].")) + user.put_in_active_hand(welder) + update_icon() + update_held_icon() + return TRUE + +//Empty variant +/obj/item/chems/weldpack/empty/populate_reagents() + return diff --git a/code/game/objects/items/welding/weldingtool.dm b/code/game/objects/items/welding/weldingtool.dm new file mode 100644 index 000000000000..c02b83119e9c --- /dev/null +++ b/code/game/objects/items/welding/weldingtool.dm @@ -0,0 +1,385 @@ +#define WELDING_TOOL_HOTSPOT_TEMP_ACTIVE 700 +#define WELDING_TOOL_HOTSPOT_TEMP_IDLE 400 + +/obj/item/weldingtool + name = "welding tool" + desc = "A portable welding gun with a port for attaching fuel tanks." + icon = 'icons/obj/items/tool/welders/welder.dmi' + icon_state = ICON_STATE_WORLD + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + center_of_mass = @'{"x":14,"y":15}' + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"engineering":1}' + drop_sound = 'sound/foley/tooldrop1.ogg' + z_flags = ZMM_MANGLE_PLANES + attack_cooldown = DEFAULT_ATTACK_COOLDOWN + var/lit_colour = COLOR_PALE_ORANGE + var/waterproof = FALSE + var/welding = FALSE //Whether or not the welding tool is off(0), on(1) or currently welding(2) + var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) + var/tmp/welding_resource = "welding fuel" + var/obj/item/chems/welder_tank/tank = /obj/item/chems/welder_tank // where the fuel is stored + var/tmp/activate_sound = 'sound/items/welderactivate.ogg' + var/tmp/deactivate_sound = 'sound/items/welderdeactivate.ogg' + +/obj/item/weldingtool/Initialize() + if(ispath(tank)) + insert_tank(new tank, null, TRUE, TRUE) + set_extension(src, /datum/extension/tool, list(TOOL_WELDER = TOOL_QUALITY_DEFAULT)) + set_extension(src, /datum/extension/base_icon_state, icon_state) + set_extension(src, /datum/extension/demolisher/welder) + . = ..() + update_icon() + +/obj/item/weldingtool/Destroy() + STOP_PROCESSING(SSobj, src) + QDEL_NULL(tank) + return ..() + +/obj/item/weldingtool/dropped(mob/user) + . = ..() + if(welding) + update_icon() + +/obj/item/weldingtool/equipped(mob/user, slot) + . = ..() + if(welding) + update_icon() + +/obj/item/weldingtool/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && welding && check_state_in_icon("[overlay.icon_state]-lit", overlay.icon)) + overlay.add_overlay(emissive_overlay(overlay.icon, "[overlay.icon_state]-lit")) + . = ..() + +/obj/item/weldingtool/get_heat() + . = max(..(), isOn() ? 3800 : 0) + +/obj/item/weldingtool/isflamesource() + . = isOn() + +/obj/item/weldingtool/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + . += "It has [round(get_fuel(), 0.1)] [welding_resource] remaining." + if (tank) + . += "\The [tank] is attached." + +/obj/item/weldingtool/proc/insert_tank(var/obj/item/chems/welder_tank/T, var/mob/user, var/no_updates = FALSE, var/quiet = FALSE) + if(tank && !ispath(tank)) + if(user && !quiet) + to_chat(user, SPAN_WARNING("\The [src] already has a tank attached - remove it first.")) + return + + if(user && !(src in user.get_held_items())) + if(user && !quiet) + to_chat(user, SPAN_WARNING("You must hold the welder in your hands to attach a tank.")) + return + + if(user && !user.try_unequip(T, src)) + return + + tank = T + w_class = tank.size_in_use + set_base_attack_force(tank.unlit_force) + if(user && !quiet) + user.visible_message("[user] slots \a [T] into \the [src].", "You slot \a [T] into \the [src].") + + if(!quiet) + playsound(loc, 'sound/effects/hypospray.ogg', 50, TRUE) + if(!no_updates) + update_icon() + return TRUE + +/obj/item/weldingtool/proc/remove_tank(var/mob/user) + if(!tank || ispath(tank)) + if(user) + to_chat(user, SPAN_WARNING("\The [src] doesn't have a tank attached.")) + return + + if(welding) + if(user) + to_chat(user, SPAN_WARNING("Stop welding first.")) + return + + if(user && !user.is_holding_offhand(src)) + if(user) + to_chat(user, SPAN_WARNING("You must hold the welder in your hands to detach its tank.")) + return + + if(user) + user.put_in_hands(tank) + user.visible_message("[user] removes \the [tank] from \the [src].", "You remove \the [tank] from \the [src].") + else + tank.dropInto(get_turf(src)) + + tank = null + w_class = initial(w_class) + set_base_attack_force(get_initial_base_attack_force()) + update_icon() + return TRUE + +/obj/item/weldingtool/proc/toggle_unscrewed(var/mob/user) + if(isrobot(loc)) + if(user) + to_chat(user, SPAN_WARNING("You cannot modify your own welder!")) + return + + status = !status + if(user) + if(status) + to_chat(user, SPAN_NOTICE("You secure the welder.")) + else + to_chat(user, SPAN_NOTICE("The welder can now be attached and modified.")) + return TRUE + +/obj/item/weldingtool/proc/attempt_modify(var/obj/item/used_item, var/mob/user) + if(!status && istype(used_item, /obj/item/stack/material/rods)) + var/obj/item/stack/material/rods/R = used_item + R.use(1) + user.drop_from_inventory(src) + user.put_in_hands(new /obj/item/flamethrower(get_turf(src), src)) + qdel(src) + return TRUE + +/obj/item/weldingtool/attackby(obj/item/used_item, mob/user) + if(welding) + to_chat(user, SPAN_WARNING("Stop welding first!")) + return TRUE + + if (istype(used_item, /obj/item/chems/welder_tank)) + return insert_tank(used_item, user) + + if(IS_SCREWDRIVER(used_item)) + return toggle_unscrewed(user) + + if(attempt_modify(used_item, user)) + return TRUE + + return ..() + +/obj/item/weldingtool/attack_hand(mob/user) + if (tank && user.is_holding_offhand(src) && user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return remove_tank(user) + return ..() + +/obj/item/weldingtool/fluid_act(var/datum/reagents/fluids) + ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids) && welding && !waterproof) + var/turf/location = get_turf(src) + if(location) + location.hotspot_expose(WELDING_TOOL_HOTSPOT_TEMP_ACTIVE, 50, 1) + turn_off() + +/obj/item/weldingtool/Process() + if(!(welding && idling())) + return PROCESS_KILL + +/obj/item/weldingtool/afterattack(var/obj/O, var/mob/user, proximity, click_parameters) + if(!proximity) + return + + if(istype(O, /obj/structure/reagent_dispensers/fueltank) && !welding) + if(!tank) + to_chat(user, SPAN_WARNING("\The [src] has no tank attached!")) + return + return tank.afterattack(O, user, proximity, click_parameters) + + if(welding) + weld(1) + var/turf/location = get_turf(user) + if(isliving(O)) + var/mob/living/L = O + L.ignite_fire() + else if(isatom(O)) + O.handle_external_heating(WELDING_TOOL_HOTSPOT_TEMP_ACTIVE, src, user) + if (isturf(location)) + location.hotspot_expose(WELDING_TOOL_HOTSPOT_TEMP_ACTIVE, 50, 1) + spark_at(get_turf(O), 3, FALSE, O) + user.setClickCooldown(attack_cooldown + w_class) //Prevent spam + return TRUE + return ..() + +/obj/item/weldingtool/attack_self(mob/user) + toggle(user) + return TRUE + +//Returns the amount of fuel in the welder +/obj/item/weldingtool/proc/get_fuel() + return tank ? REAGENT_VOLUME(tank.reagents, /decl/material/liquid/fuel) : 0 + +//Removes fuel from the welding tool. If a mob is passed, it will perform an eyecheck on the mob. +/obj/item/weldingtool/proc/weld(var/fuel_usage = 1, var/mob/user = null) + if(!welding) + return FALSE + if(get_fuel() < fuel_usage) + if(user) + to_chat(user, SPAN_NOTICE("You need more [welding_resource] to complete this task.")) + return FALSE + + use_fuel(fuel_usage) + if(user) + user.welding_eyecheck() + + var/turf/location = get_turf(src) + if(location) + location.hotspot_expose(WELDING_TOOL_HOTSPOT_TEMP_ACTIVE, 5) + set_light(5, 0.7, COLOR_LIGHT_CYAN) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 5) + return TRUE + +/**Handle the flame burning fuel while the welder is on */ +/obj/item/weldingtool/proc/idling(var/fuel_usage = 0.5) + if(!welding) + return + if((!waterproof && submerged()) || (get_fuel() < fuel_usage)) + turn_off() + return + + //consider ourselves in a mob if we are in the mob's contents and not in their hands + if(isliving(loc)) + var/mob/living/L = loc + if(!(src in L.get_held_items())) + fuel_usage = max(fuel_usage, 2) + L.ignite_fire() + else if(isturf(loc)) + var/turf/location = get_turf(src) + location.hotspot_expose(WELDING_TOOL_HOTSPOT_TEMP_IDLE, 5) //a bit colder when idling + else if(isatom(loc)) + var/atom/A = loc + A.handle_external_heating(WELDING_TOOL_HOTSPOT_TEMP_IDLE) + + if(use_fuel(fuel_usage)) + return TRUE + else + turn_off() + +/obj/item/weldingtool/proc/use_fuel(var/amount) + . = TRUE + if(get_fuel() < amount) + . = FALSE //Try to burn as much as possible anyways + if(tank) + tank.remove_from_reagents(/decl/material/liquid/fuel, amount) + +//Returns whether or not the welding tool is currently on. +/obj/item/weldingtool/proc/isOn() + return src.welding + +/obj/item/weldingtool/on_update_icon() + . = ..() + z_flags &= ~ZMM_MANGLE_PLANES + if(tank) + add_overlay("[icon_state]-[tank.icon_state]") + if(welding && check_state_in_icon("[icon_state]-lit", icon)) + if(plane == HUD_PLANE) + add_overlay(image(icon, "[icon_state]-lit")) + else + add_overlay(emissive_overlay(icon, "[icon_state]-lit")) + z_flags |= ZMM_MANGLE_PLANES + set_light(2.5, 0.6, lit_colour) + else + set_light(0) + update_held_icon() + +/**Handles updating damage depening on whether the welder is on or off */ +/obj/item/weldingtool/proc/update_physical_damage() + var/new_force + if(isOn()) + new_force = tank?.lit_force + atom_damage_type = BURN + else + new_force = tank?.unlit_force + atom_damage_type = BRUTE + if(isnull(new_force)) + set_base_attack_force(get_initial_base_attack_force()) + else + set_base_attack_force(new_force) + +/obj/item/weldingtool/proc/turn_on(var/mob/user) + if (!status) + return + if(!waterproof && submerged()) + if(user) + to_chat(user, SPAN_WARNING("You cannot light \the [src] underwater.")) + return + if(get_fuel() <= 0) + if(user) + to_chat(user, SPAN_NOTICE("You need [welding_resource] to light \the [src].")) + return + + if(user) + user.visible_message(SPAN_NOTICE("\The [user] turns \the [src] on."), SPAN_NOTICE("You turn on \the [src].")) + else + visible_message(SPAN_WARNING("\The [src] turns on.")) + + update_physical_damage() + playsound(src, activate_sound, 50, TRUE) + welding = TRUE + obj_flags |= OBJ_FLAG_NO_STORAGE + update_icon() + START_PROCESSING(SSobj, src) + return TRUE + +/obj/item/weldingtool/proc/turn_off(var/mob/user) + STOP_PROCESSING(SSobj, src) + + if(user) + user.visible_message(SPAN_NOTICE("\The [user] turns \the [src] off."), SPAN_NOTICE("You switch \the [src] off.")) + else + visible_message(SPAN_WARNING("\The [src] turns off.")) + + update_physical_damage() + playsound(src, deactivate_sound, 50, TRUE) + welding = FALSE + obj_flags &= ~OBJ_FLAG_NO_STORAGE + update_icon() + return TRUE + +/obj/item/weldingtool/proc/toggle(var/mob/user) + if(welding) + return turn_off(user) + else + return turn_on(user) + +/obj/item/weldingtool/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + var/obj/item/organ/external/affecting = istype(target) && GET_EXTERNAL_ORGAN(target, user?.get_target_zone()) + if(affecting && user.check_intent(I_FLAG_HELP)) + if(!affecting.is_robotic()) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is not robotic. \The [src] cannot repair it.")) + else if(BP_IS_BRITTLE(affecting)) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is hard and brittle. \The [src] cannot repair it.")) + else if(!welding) + to_chat(user, SPAN_WARNING("You'll need to turn \the [src] on to patch the damage on \the [target]'s [affecting.name]!")) + else if(affecting.robo_repair(15, BRUTE, "some dents", src, user)) + weld(1, user) + return TRUE + return ..() + +/obj/item/weldingtool/get_autopsy_descriptors() + if(isOn()) + return list("jet of flame") + return ..() + +////////////////////////////////////////////////////////////////// +// Welding Tool Variants +////////////////////////////////////////////////////////////////// +/obj/item/weldingtool/mini + tank = /obj/item/chems/welder_tank/mini + +/obj/item/weldingtool/largetank + tank = /obj/item/chems/welder_tank/large + +/obj/item/weldingtool/hugetank + tank = /obj/item/chems/welder_tank/huge + +/obj/item/weldingtool/experimental + tank = /obj/item/chems/welder_tank/experimental + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +#undef WELDING_TOOL_HOTSPOT_TEMP_ACTIVE +#undef WELDING_TOOL_HOTSPOT_TEMP_IDLE \ No newline at end of file diff --git a/code/game/objects/items/welding/weldingtool_tank.dm b/code/game/objects/items/welding/weldingtool_tank.dm new file mode 100644 index 000000000000..ae40b17cb8fd --- /dev/null +++ b/code/game/objects/items/welding/weldingtool_tank.dm @@ -0,0 +1,144 @@ +////////////////////////////////////////////////////////////////// +// Welding tool tanks +////////////////////////////////////////////////////////////////// +/obj/item/chems/welder_tank + name = "welding tank" + base_name = "welding tank" + desc = "An interchangeable fuel tank meant for a welding tool." + icon = 'icons/obj/items/tool/welders/welder_tanks.dmi' + icon_state = "tank_normal" + w_class = ITEM_SIZE_SMALL + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_HOLLOW + chem_volume = 20 + presentation_flags = PRESENTATION_FLAG_NAME + max_health = 40 + material = /decl/material/solid/metal/steel + var/can_refuel = TRUE + var/size_in_use = ITEM_SIZE_NORMAL + var/unlit_force = 7 + var/lit_force = 11 + +/obj/item/chems/welder_tank/populate_reagents() + add_to_reagents(/decl/material/liquid/fuel, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/welder_tank/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1) + return + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(total_vol <= 0) + . += SPAN_WARNING("It is empty.") + else + . += "It contains [total_vol] units of liquid." + . += "It can hold up to [REAGENT_MAXIMUM_VOLUME(reagents)] units." + +/obj/item/chems/welder_tank/afterattack(obj/O, mob/user, proximity, click_parameters) + if (!ATOM_IS_OPEN_CONTAINER(src) || !proximity) + return + if(standard_dispenser_refill(user, O)) + return TRUE + if(standard_pour_into(user, O)) + return TRUE + if(handle_eaten_by_mob(user, O) != EATEN_INVALID) + return TRUE + if(user.check_intent(I_FLAG_HARM)) + if(standard_splash_mob(user, O)) + return TRUE + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(reagents && total_vol) + to_chat(user, SPAN_DANGER("You splash the contents of \the [src] onto \the [O].")) + reagents.splash(O, total_vol) + return TRUE + return ..() + +/obj/item/chems/welder_tank/standard_dispenser_refill(mob/user, obj/structure/reagent_dispensers/target, skip_container_check = FALSE) + if(!can_refuel) + to_chat(user, SPAN_DANGER("\The [src] does not have a refuelling port.")) + return FALSE + . = ..() + if(.) + playsound(src.loc, 'sound/effects/refill.ogg', 50, TRUE, -6) + +/obj/item/chems/welder_tank/standard_pour_into(mob/user, atom/target) + if(!can_refuel) + to_chat(user, SPAN_DANGER("\The [src] is sealed shut.")) + return FALSE + . = ..() + +/obj/item/chems/welder_tank/standard_splash_mob(mob/user, mob/target) + if(!can_refuel) + to_chat(user, SPAN_DANGER("\The [src] is sealed shut.")) + return FALSE + . = ..() + +/obj/item/chems/welder_tank/handle_eaten_by_mob(mob/user, mob/target) + if(!can_refuel) + to_chat(user, SPAN_DANGER("\The [src] is sealed shut.")) + return EATEN_UNABLE + return ..() + +/obj/item/chems/welder_tank/get_alt_interactions(var/mob/user) + . = ..() + if(!can_refuel) + LAZYREMOVE(., /decl/interaction_handler/set_transfer/chems) + +/obj/item/chems/welder_tank/mini + name = "small welding tank" + base_name = "small welding tank" + icon_state = "tank_small" + w_class = ITEM_SIZE_TINY + chem_volume = 5 + size_in_use = ITEM_SIZE_SMALL + unlit_force = 5 + lit_force = 7 + _base_attack_force = 4 + +/obj/item/chems/welder_tank/large + name = "large welding tank" + base_name = "large welding tank" + icon_state = "tank_large" + w_class = ITEM_SIZE_SMALL + chem_volume = 40 + size_in_use = ITEM_SIZE_NORMAL + _base_attack_force = 6 + +/obj/item/chems/welder_tank/huge + name = "huge welding tank" + base_name = "huge welding tank" + icon_state = "tank_huge" + w_class = ITEM_SIZE_NORMAL + chem_volume = 80 + size_in_use = ITEM_SIZE_LARGE + unlit_force = 9 + lit_force = 15 + _base_attack_force = 8 + +/obj/item/chems/welder_tank/experimental + name = "experimental welding tank" + base_name = "experimental welding tank" + icon_state = "tank_experimental" + w_class = ITEM_SIZE_NORMAL + chem_volume = 40 + can_refuel = FALSE + size_in_use = ITEM_SIZE_LARGE + unlit_force = 9 + lit_force = 15 + presentation_flags = 0 + _base_attack_force = 8 + var/tmp/last_gen = 0 + +/obj/item/chems/welder_tank/experimental/Initialize(ml, material_key) + . = ..() + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + START_PROCESSING(SSobj, src) + +/obj/item/chems/welder_tank/experimental/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/chems/welder_tank/experimental/Process() + if(REAGENT_VOLUME(reagents, /decl/material/liquid/fuel) < REAGENT_MAXIMUM_VOLUME(reagents)) + var/gen_amount = ((world.time-last_gen)/25) + add_to_reagents(/decl/material/liquid/fuel, gen_amount) + last_gen = world.time \ No newline at end of file diff --git a/code/game/objects/items/wooden_prosthetics.dm b/code/game/objects/items/wooden_prosthetics.dm deleted file mode 100644 index 0bdf49e90960..000000000000 --- a/code/game/objects/items/wooden_prosthetics.dm +++ /dev/null @@ -1,39 +0,0 @@ -/obj/item/organ/external/arm/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/arm/right/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/leg/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/leg/right/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/hand/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/hand/right/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/foot/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") - -/obj/item/organ/external/foot/right/wooden/Initialize() - species = get_species_by_key(SPECIES_HUMAN) - . = ..() - robotize("wooden prosthesis") diff --git a/code/game/objects/munition.dm b/code/game/objects/munition.dm index 628708c3e90a..96afd8cf4a87 100644 --- a/code/game/objects/munition.dm +++ b/code/game/objects/munition.dm @@ -1,9 +1,9 @@ /obj/structure/ship_munition name = "munitions" icon = 'icons/obj/munitions.dmi' - w_class = ITEM_SIZE_GARGANTUAN - density = 1 - var/list/move_sounds = list( // some nasty sounds to make when moving the board + density = TRUE + material = /decl/material/solid/metal/titanium + var/static/list/move_sounds = list( // some nasty sounds to make when moving the board 'sound/effects/metalscrape1.ogg', 'sound/effects/metalscrape2.ogg', 'sound/effects/metalscrape3.ogg' @@ -14,7 +14,7 @@ . = ..() if(.) var/turf/T = get_turf(src) - if(!isspace(T) && !istype(T, /turf/simulated/floor/carpet)) + if(!isspaceturf(T) && !istype(T, /turf/floor/carpet)) playsound(T, pick(move_sounds), 75, 1) /obj/structure/ship_munition/md_slug diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm deleted file mode 100644 index 681581ed64be..000000000000 --- a/code/game/objects/objs.dm +++ /dev/null @@ -1,198 +0,0 @@ -/obj - layer = OBJ_LAYER - animate_movement = 2 - - var/obj_flags - var/list/req_access - var/list/matter //Used to store information about the contents of the object. - var/w_class // Size of the object. - var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj. - var/throwforce = 1 - var/sharp = 0 // whether this object cuts - var/edge = 0 // whether this object is more likely to dismember - var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! - var/damtype = "brute" - var/armor_penetration = 0 - var/anchor_fall = FALSE - var/holographic = 0 //if the obj is a holographic object spawned by the holodeck - -/obj/proc/create_matter() - if(length(matter)) - for(var/mat in matter) - matter[mat] = round(matter[mat] * get_matter_amount_modifier()) - UNSETEMPTY(matter) - -/obj/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/proc/get_matter_amount_modifier() - . = ceil(w_class * 0.25) - -/obj/item/proc/is_used_on(obj/O, mob/user) - return - -/obj/assume_air(datum/gas_mixture/giver) - if(loc) - return loc.assume_air(giver) - else - return null - -/obj/remove_air(amount) - if(loc) - return loc.remove_air(amount) - else - return null - -/obj/return_air() - if(loc) - return loc.return_air() - else - return null - -/obj/proc/updateUsrDialog() - if(in_use) - var/is_in_use = 0 - var/list/nearby = viewers(1, src) | usr - for(var/mob/M in nearby) - if ((M.client && M.machine == src)) - if(CanUseTopic(M, DefaultTopicState()) > STATUS_CLOSE) - is_in_use = 1 - interact(M) - else - M.unset_machine() - in_use = is_in_use - -/obj/proc/updateDialog() - // Check that people are actually using the machine. If not, don't update anymore. - if(in_use) - var/list/nearby = viewers(1, src) - var/is_in_use = 0 - for(var/mob/M in nearby) - if ((M.client && M.machine == src)) - if(CanUseTopic(M, DefaultTopicState()) > STATUS_CLOSE) - is_in_use = 1 - interact(M) - else - M.unset_machine() - var/ai_in_use = AutoUpdateAI(src) - - if(!ai_in_use && !is_in_use) - in_use = 0 - -/obj/attack_ghost(mob/user) - ui_interact(user) - ..() - -/obj/proc/interact(mob/user) - return - -/mob/proc/unset_machine() - src.machine = null - -/mob/proc/set_machine(var/obj/O) - if(src.machine) - unset_machine() - src.machine = O - if(istype(O)) - O.in_use = 1 - -/obj/item/proc/updateSelfDialog() - var/mob/M = src.loc - if(istype(M) && M.client && M.machine == src) - src.attack_self(M) - -/obj/proc/hide(var/hide) - set_invisibility(hide ? INVISIBILITY_MAXIMUM : initial(invisibility)) - -/obj/proc/hides_under_flooring() - return level == 1 - -/obj/proc/hear_talk(mob/M, text, verb, decl/language/speaking) - if(talking_atom) - talking_atom.catchMessage(text, M) -/* - var/mob/mo = locate(/mob) in src - if(mo) - var/rendered = "[M.name]: [text]" - mo.show_message(rendered, 2) - */ - return - -/obj/proc/see_emote(mob/M, text, var/emote_type) - return - -/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) - return - -/obj/proc/damage_flags() - . = 0 - if(has_edge(src)) - . |= DAM_EDGE - if(is_sharp(src)) - . |= DAM_SHARP - if(damtype == BURN) - . |= DAM_LASER - -/obj/attackby(obj/item/O, mob/user) - if(obj_flags & OBJ_FLAG_ANCHORABLE) - if(isWrench(O)) - wrench_floor_bolts(user) - update_icon() - return - return ..() - -/obj/proc/wrench_floor_bolts(mob/user, delay=20) - playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) - if(anchored) - user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") - else - user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") - if(do_after(user, delay, src)) - if(!src) return - to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") - anchored = !anchored - return 1 - -/obj/attack_hand(mob/living/user) - if(Adjacent(user)) - add_fingerprint(user) - ..() - -/obj/is_fluid_pushable(var/amt) - return ..() && w_class <= round(amt/20) - -/obj/proc/can_embed() - return is_sharp(src) - -/obj/AltClick(mob/user) - if(obj_flags & OBJ_FLAG_ROTATABLE) - rotate(user) - ..() - -/obj/examine(mob/user) - . = ..() - if((obj_flags & OBJ_FLAG_ROTATABLE)) - to_chat(user, SPAN_SUBTLE("Can be rotated with alt-click.")) - -/obj/proc/rotate(mob/user) - if(!CanPhysicallyInteract(user)) - to_chat(user, SPAN_NOTICE("You can't interact with \the [src] right now!")) - return - - if(anchored) - to_chat(user, SPAN_NOTICE("\The [src] is secured to the floor!")) - return - - set_dir(turn(dir, 90)) - update_icon() - -//For things to apply special effects after damaging an organ, called by organ's take_damage -/obj/proc/after_wounding(obj/item/organ/external/organ, datum/wound) - return - -/obj/can_be_injected_by(var/atom/injector) - . = ATOM_IS_OPEN_CONTAINER(src) && ..() - -/obj/get_mass() - return min(2**(w_class-1), 100) diff --git a/code/game/objects/random/_random.dm b/code/game/objects/random/_random.dm new file mode 100644 index 000000000000..51051689804e --- /dev/null +++ b/code/game/objects/random/_random.dm @@ -0,0 +1 @@ +var/global/list/multi_point_spawns diff --git a/code/game/objects/random/date_based.dm b/code/game/objects/random/date_based.dm index 29cceeb13417..c31c83ecf682 100644 --- a/code/game/objects/random/date_based.dm +++ b/code/game/objects/random/date_based.dm @@ -5,7 +5,8 @@ /obj/random/date_based name = "random object (date based)" icon_state = "yup" - spawn_method = .proc/check_date + spawn_method = PROC_REF(check_date) + abstract_type = /obj/random/date_based var/datum/is_date/date_check /obj/random/date_based/Destroy() @@ -13,26 +14,25 @@ return ..() /obj/random/date_based/proc/check_date() - if(date_check.IsValid()) + if(date_check?.IsValid()) return spawn_item() - /datum/is_date/proc/IsValid() return FALSE /datum/is_date/proc/CurrentMonthAndDay() return current_month_and_day() +var/global/list/days_of_month /datum/is_date/proc/ValidateMonthAndDay(month, day) . = FALSE if(!month || month < 1 || month > 12) CRASH("Invalid month: [month]") - - var/days_in_month = GLOB.days_per_month[month] - if(month == 2) // Always allow 29th of February, in case someone wants to do have leap-year things - days_in_month = 29 - - if(!day || day < 1 || day > days_in_month) + if(!global.days_of_month) + global.days_of_month = list(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + if(isLeap(text2num(time2text(world.realtime, "YYYY")))) + global.days_of_month[2] = 29 + if(!day || day < 1 || day > global.days_of_month[month]) CRASH("Invalid day: [day]") return TRUE @@ -109,4 +109,5 @@ name = "Christmas Tree" /obj/random/date_based/christmas/tree/spawn_choices() - return list(/obj/structure/flora/tree/pine/xmas) + var/static/list/spawnable_choices = list(/obj/structure/flora/tree/pine/xmas) + return spawnable_choices diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm index cc46820261df..3a111afaccac 100644 --- a/code/game/objects/random/random.dm +++ b/code/game/objects/random/random.dm @@ -3,8 +3,8 @@ desc = "This item type is used to spawn random objects at round-start." icon = 'icons/misc/mark.dmi' icon_state = "rup" + abstract_type = /obj/random var/spawn_nothing_percentage = 0 // this variable determines the likelyhood that this random object will not spawn anything - var/spawn_method = /obj/random/proc/spawn_item // creates a new object and deletes itself @@ -13,25 +13,37 @@ call(src, spawn_method)() return INITIALIZE_HINT_QDEL +/obj/random/proc/item_to_spawn() + var/list/spawn_choices = spawn_choices() + return length(spawn_choices) && pickweight(spawn_choices) + // creates the random item /obj/random/proc/spawn_item() - if(prob(spawn_nothing_percentage)) - return - if(isnull(loc)) + if(prob(spawn_nothing_percentage) || isnull(loc)) return - var/build_path = pickweight(spawn_choices()) + var/type_to_spawn = item_to_spawn() + if(!type_to_spawn) + return - var/atom/A = new build_path(src.loc) - if(pixel_x || pixel_y) - A.pixel_x = pixel_x - A.pixel_y = pixel_y + for(var/atom/A as anything in create_instance(type_to_spawn, loc)) + if(pixel_x || pixel_y) + A.default_pixel_x = pixel_x + A.default_pixel_y = pixel_y + A.reset_offsets(0) - return A +/obj/random/proc/create_instance(var/build_path, var/spawn_loc) + if(ispath(build_path)) + return list(new build_path(spawn_loc)) + if(islist(build_path)) + for(var/spawn_type in build_path) + for(var/created in create_instance(spawn_type, spawn_loc)) + LAZYADD(., created) // Returns an associative list in format path:weight /obj/random/proc/spawn_choices() + RETURN_TYPE(/list) return list() /obj/random/single @@ -42,1321 +54,4 @@ var/spawn_object = null /obj/random/single/spawn_choices() - return list(spawn_object) - -/obj/random/tool - name = "random tool" - desc = "This is a random tool." - icon = 'icons/obj/items/tool/welder.dmi' - icon_state = "welder" - -/obj/random/tool/spawn_choices() - return list(/obj/item/screwdriver, - /obj/item/wirecutters, - /obj/item/weldingtool, - /obj/item/weldingtool/largetank, - /obj/item/crowbar, - /obj/item/wrench, - /obj/item/flashlight) - -/obj/random/technology_scanner - name = "random scanner" - desc = "This is a random technology scanner." - icon = 'icons/obj/items/device/scanner/atmos_scanner.dmi' - icon_state = "atmos" - -/obj/random/technology_scanner/spawn_choices() - return list(/obj/item/t_scanner = 5, - /obj/item/radio = 2, - /obj/item/scanner/gas = 5) - -/obj/random/powercell - name = "random powercell" - desc = "This is a random powercell." - icon = 'icons/obj/power.dmi' - icon_state = "hcell" - -/obj/random/powercell/spawn_choices() - return list(/obj/item/cell/crap = 1, - /obj/item/cell = 8, - /obj/item/cell/high = 5, - /obj/item/cell/super = 2, - /obj/item/cell/hyper = 1, - /obj/item/cell/device/standard = 7, - /obj/item/cell/device/high = 5) - -/obj/random/bomb_supply - name = "bomb supply" - desc = "This is a random bomb supply." - icon = 'icons/obj/assemblies/new_assemblies.dmi' - icon_state = "signaller" - -/obj/random/bomb_supply/spawn_choices() - return list(/obj/item/assembly/igniter, - /obj/item/assembly/prox_sensor, - /obj/item/assembly/signaler, - /obj/item/assembly/timer, - /obj/item/multitool) - -/obj/random/toolbox - name = "random toolbox" - desc = "This is a random toolbox." - icon = 'icons/obj/items/storage/toolbox.dmi' - icon_state = "red" - -/obj/random/toolbox/spawn_choices() - return list(/obj/item/storage/toolbox/mechanical = 30, - /obj/item/storage/toolbox/electrical = 20, - /obj/item/storage/toolbox/emergency = 20, - /obj/item/storage/toolbox/syndicate = 1) - -/obj/random/tech_supply - name = "random tech supply" - desc = "This is a random piece of technology supplies." - icon = 'icons/obj/power.dmi' - icon_state = "cell" - spawn_nothing_percentage = 50 - -/obj/random/tech_supply/spawn_choices() - return list(/obj/random/powercell = 3, - /obj/random/technology_scanner = 2, - /obj/item/stack/package_wrap/twenty_five = 1, - /obj/item/hand_labeler = 1, - /obj/random/bomb_supply = 2, - /obj/item/extinguisher = 1, - /obj/item/clothing/gloves/insulated/cheap = 1, - /obj/item/stack/cable_coil/random = 2, - /obj/random/toolbox = 2, - /obj/item/storage/belt/utility = 2, - /obj/item/storage/belt/utility/atmostech = 1, - /obj/random/tool = 5, - /obj/item/tape_roll = 2) - -/obj/random/medical - name = "Random Medical equipment" - desc = "This is a random medical item." - icon = 'icons/obj/items/random_spawn.dmi' - icon_state = "medrandom" - -/obj/random/medical/spawn_choices() - return list(/obj/random/medical/lite = 21, - /obj/item/bodybag = 2, - /obj/item/chems/glass/bottle/stabilizer = 2, - /obj/item/chems/glass/bottle/antitoxin = 2, - /obj/item/storage/pill_bottle = 2, - /obj/item/storage/pill_bottle/painkillers = 1, - /obj/item/storage/pill_bottle/antidepressants = 2, - /obj/item/storage/pill_bottle/oxygen = 1, - /obj/item/storage/pill_bottle/burn_meds = 1, - /obj/item/storage/pill_bottle/brute_meds = 1, - /obj/item/chems/syringe/antitoxin = 2, - /obj/item/chems/syringe/antibiotic = 1, - /obj/item/chems/syringe/stabilizer = 2, - /obj/item/storage/box/freezer = 1, - /obj/item/stack/nanopaste = 1) - -/obj/random/medical/lite - name = "Random Medicine" - desc = "This is a random simple medical item." - icon = 'icons/obj/items/random_spawn.dmi' - icon_state = "medrandom" - spawn_nothing_percentage = 25 - -/obj/random/medical/lite/spawn_choices() - return list(/obj/item/stack/medical/bruise_pack = 4, - /obj/item/stack/medical/ointment = 4, - /obj/item/storage/pill_bottle/antibiotics = 2, - /obj/item/storage/pill_bottle/painkillers = 2, - /obj/item/stack/medical/advanced/bruise_pack = 2, - /obj/item/stack/medical/advanced/ointment = 2, - /obj/item/stack/medical/splint = 1, - /obj/item/chems/hypospray/autoinjector = 3, - /obj/item/storage/pill_bottle/burn_meds = 2, - /obj/item/storage/pill_bottle/antitox = 2, - /obj/item/storage/med_pouch/trauma = 2, - /obj/item/storage/med_pouch/burn = 2, - /obj/item/storage/med_pouch/toxin = 2, - /obj/item/storage/med_pouch/radiation = 2, - /obj/item/storage/med_pouch/oxyloss = 2) - -/obj/random/firstaid - name = "Random First Aid Kit" - desc = "This is a random first aid kit." - icon = 'icons/obj/items/storage/firstaid.dmi' - icon_state = "firstaid" - -/obj/random/firstaid/spawn_choices() - return list(/obj/item/storage/firstaid/regular = 4, - /obj/item/storage/firstaid/trauma = 3, - /obj/item/storage/firstaid/toxin = 3, - /obj/item/storage/firstaid/o2 = 3, - /obj/item/storage/firstaid/stab = 2, - /obj/item/storage/firstaid/adv = 2, - /obj/item/storage/firstaid/combat = 1, - /obj/item/storage/firstaid/empty = 2, - /obj/item/storage/firstaid/fire = 3) - -/obj/random/contraband - name = "Random Illegal Item" - desc = "Hot Stuff." - icon = 'icons/obj/items/comb.dmi' - icon_state = "purplecomb" - spawn_nothing_percentage = 50 - -/obj/random/contraband/spawn_choices() - return list(/obj/item/haircomb = 4, - /obj/item/storage/pill_bottle/painkillers = 3, - /obj/item/storage/pill_bottle/happy = 2, - /obj/item/storage/pill_bottle/zoom = 2, - /obj/item/chems/glass/beaker/vial/random/toxin = 1, - /obj/item/chems/glass/beaker/sulphuric = 1, - /obj/item/contraband/poster = 5, - /obj/item/butterflyblade = 3, - /obj/item/butterflyhandle = 3, - /obj/item/baton/cattleprod = 1, - /obj/item/knife/combat = 1, - /obj/item/knife/folding = 1, - /obj/item/knife/folding/wood = 1, - /obj/item/knife/folding/combat/balisong = 2, - /obj/item/knife/folding/combat/switchblade = 1, - /obj/item/storage/secure/briefcase/money = 1, - /obj/item/storage/box/syndie_kit/cigarette = 1, - /obj/item/stack/telecrystal = 1, - /obj/item/clothing/under/syndicate = 2, - /obj/item/chems/syringe = 3, - /obj/item/chems/syringe/steroid = 2, - /obj/item/chems/syringe/drugs = 1, - /obj/item/chems/food/snacks/egg/lizard = 3) - -/obj/random/drinkbottle - name = "random drink" - desc = "This is a random drink." - icon = 'icons/obj/drinks.dmi' - icon_state = "whiskeybottle" - -/obj/random/drinkbottle/spawn_choices() - return list(/obj/item/chems/food/drinks/bottle/whiskey, - /obj/item/chems/food/drinks/bottle/gin, - /obj/item/chems/food/drinks/bottle/agedwhiskey, - /obj/item/chems/food/drinks/bottle/vodka, - /obj/item/chems/food/drinks/bottle/tequilla, - /obj/item/chems/food/drinks/bottle/absinthe, - /obj/item/chems/food/drinks/bottle/wine, - /obj/item/chems/food/drinks/bottle/cognac, - /obj/item/chems/food/drinks/bottle/rum, - /obj/item/chems/food/drinks/bottle/patron) - - -/obj/random/energy - name = "Random Energy Weapon" - desc = "This is a random energy weapon." - icon = 'icons/obj/guns/energy_gun.dmi' - icon_state = "energykill100" - -/obj/random/energy/spawn_choices() - return list(/obj/item/gun/energy/laser = 4, - /obj/item/gun/energy/gun = 3, - /obj/item/gun/energy/lasercannon = 2, - /obj/item/gun/energy/xray = 3, - /obj/item/gun/energy/sniperrifle = 1, - /obj/item/gun/energy/gun/nuclear = 1, - /obj/item/gun/energy/ionrifle = 2, - /obj/item/gun/energy/toxgun = 3, - /obj/item/gun/energy/taser = 4, - /obj/item/gun/energy/crossbow/largecrossbow = 2) - -/obj/random/projectile - name = "Random Projectile Weapon" - desc = "This is a random projectile weapon." - icon = 'icons/obj/guns/revolvers.dmi' - icon_state = "revolver" - -/obj/random/projectile/spawn_choices() - return list(/obj/item/gun/projectile/shotgun/pump = 3, - /obj/item/gun/projectile/automatic/assault_rifle = 2, - /obj/item/gun/projectile/pistol = 3, - /obj/item/gun/projectile/pistol/holdout = 4, - /obj/item/gun/projectile/zipgun = 5, - /obj/item/gun/projectile/automatic/smg = 4, - /obj/item/gun/projectile/revolver = 2, - /obj/item/gun/projectile/shotgun/doublebarrel = 4, - /obj/item/gun/projectile/shotgun/doublebarrel/sawn = 3, - /obj/item/gun/projectile/heavysniper = 1 - ) - -/obj/random/handgun - name = "Random Handgun" - desc = "This is a random sidearm." - icon = 'icons/obj/guns/pistol.dmi' - icon_state = "secguncomp" - -/obj/random/handgun/spawn_choices() - return list(/obj/item/gun/projectile/pistol = 3, - /obj/item/gun/energy/gun = 3, - /obj/item/gun/projectile/pistol/holdout = 2 - ) - -/obj/random/ammo - name = "Random Ammunition" - desc = "This is random ammunition." - icon = 'icons/obj/ammo.dmi' - icon_state = "magnum" - -/obj/random/ammo/spawn_choices() - return list(/obj/item/storage/box/ammo/beanbags = 6, - /obj/item/storage/box/ammo/shotgunammo = 2, - /obj/item/storage/box/ammo/shotgunshells = 4, - /obj/item/storage/box/ammo/stunshells = 1, - /obj/item/ammo_magazine/pistol = 2, - /obj/item/ammo_magazine/smg = 2, - /obj/item/ammo_magazine/smg/rubber = 6 - ) - -/obj/random/action_figure - name = "random action figure" - desc = "This is a random action figure." - icon = 'icons/obj/toy.dmi' - icon_state = "assistant" - -/obj/random/action_figure/spawn_choices() - return list(/obj/item/toy/figure/cmo, - /obj/item/toy/figure/assistant, - /obj/item/toy/figure/atmos, - /obj/item/toy/figure/bartender, - /obj/item/toy/figure/borg, - /obj/item/toy/figure/gardener, - /obj/item/toy/figure/captain, - /obj/item/toy/figure/cargotech, - /obj/item/toy/figure/ce, - /obj/item/toy/figure/chaplain, - /obj/item/toy/figure/chef, - /obj/item/toy/figure/chemist, - /obj/item/toy/figure/clown, - /obj/item/toy/figure/corgi, - /obj/item/toy/figure/detective, - /obj/item/toy/figure/dsquad, - /obj/item/toy/figure/engineer, - /obj/item/toy/figure/geneticist, - /obj/item/toy/figure/hop, - /obj/item/toy/figure/hos, - /obj/item/toy/figure/qm, - /obj/item/toy/figure/janitor, - /obj/item/toy/figure/agent, - /obj/item/toy/figure/librarian, - /obj/item/toy/figure/md, - /obj/item/toy/figure/mime, - /obj/item/toy/figure/miner, - /obj/item/toy/figure/ninja, - /obj/item/toy/figure/wizard, - /obj/item/toy/figure/rd, - /obj/item/toy/figure/roboticist, - /obj/item/toy/figure/scientist, - /obj/item/toy/figure/syndie, - /obj/item/toy/figure/secofficer, - /obj/item/toy/figure/warden, - /obj/item/toy/figure/psychologist, - /obj/item/toy/figure/paramedic, - /obj/item/toy/figure/ert) - - -/obj/random/plushie - name = "random plushie" - desc = "This is a random plushie." - icon = 'icons/obj/toy.dmi' - icon_state = "nymphplushie" - -/obj/random/plushie/spawn_choices() - return list(/obj/item/toy/plushie/mouse, - /obj/item/toy/plushie/kitten, - /obj/item/toy/plushie/lizard) - -/obj/random/plushie/large - name = "random large plushie" - desc = "This is a random large plushie." - icon = 'icons/obj/toy.dmi' - icon_state = "droneplushie" - -/obj/random/plushie/large/spawn_choices() - return list(/obj/structure/plushie/ian, - /obj/structure/plushie/drone, - /obj/structure/plushie/carp, - /obj/structure/plushie/beepsky) - -/obj/random/junk //Broken items, or stuff that could be picked up - name = "random junk" - desc = "This is some random junk." - icon = 'icons/obj/items/storage/trashbag.dmi' - icon_state = "trashbag3" - -/obj/random/junk/spawn_choices() - return list(get_random_junk_type()) - -/obj/random/trash //Mostly remains and cleanable decals. Stuff a janitor could clean up - name = "random trash" - desc = "This is some random trash." - icon = 'icons/effects/effects.dmi' - icon_state = "greenglow" - -/obj/random/trash/spawn_choices() - return list(/obj/item/remains/lizard, - /obj/effect/decal/cleanable/blood/gibs/robot, - /obj/effect/decal/cleanable/blood/oil, - /obj/effect/decal/cleanable/blood/oil/streak, - /obj/effect/decal/cleanable/spiderling_remains, - /obj/item/remains/mouse, - /obj/effect/decal/cleanable/vomit, - /obj/effect/decal/cleanable/blood/splatter, - /obj/effect/decal/cleanable/ash, - /obj/effect/decal/cleanable/generic, - /obj/effect/decal/cleanable/flour, - /obj/effect/decal/cleanable/dirt, - /obj/item/remains/robot) - - -/obj/random/closet //A couple of random closets to spice up maint - name = "random closet" - desc = "This is a random closet." - icon = 'icons/obj/closets/bases/closet.dmi' - icon_state = "base" - var/vermin_chance = 0.1 - var/list/locker_vermin = list( - /mob/living/simple_animal/mouse, - /mob/living/simple_animal/opossum - ) - -/obj/random/closet/spawn_choices() - return list(/obj/structure/closet, - /obj/structure/closet/firecloset, - /obj/structure/closet/emcloset, - /obj/structure/closet/jcloset, - /obj/structure/closet/athletic_mixed, - /obj/structure/closet/toolcloset, - /obj/structure/closet/l3closet/general, - /obj/structure/closet/cabinet, - /obj/structure/closet/crate, - /obj/structure/closet/crate/freezer, - /obj/structure/closet/crate/freezer/rations, - /obj/structure/closet/crate/internals, - /obj/structure/closet/crate/trashcart, - /obj/structure/closet/crate/medical, - /obj/structure/closet/boxinggloves, - /obj/structure/largecrate, - /obj/structure/closet/wardrobe/xenos, - /obj/structure/closet/wardrobe/mixed, - /obj/structure/closet/wardrobe/suit, - /obj/structure/closet/wardrobe/orange - ) -/obj/random/closet/spawn_item() - . = ..() - if(. && length(locker_vermin) && prob(vermin_chance)) - var/vermin_type = pickweight(locker_vermin) - new vermin_type(.) - -/obj/random/coin - name = "random coin" - desc = "This is a random coin." - icon = 'icons/obj/items/coin.dmi' - icon_state = "coin1" - -/obj/random/coin/spawn_choices() - return list( - /obj/item/coin/gold = 3, - /obj/item/coin/silver = 4, - /obj/item/coin/diamond = 2, - /obj/item/coin/iron = 4, - /obj/item/coin/uranium = 3, - /obj/item/coin/platinum = 1 - ) - -/obj/random/toy - name = "random toy" - desc = "This is a random toy." - icon = 'icons/obj/toy.dmi' - icon_state = "ship" - -/obj/random/toy/spawn_choices() - return list(/obj/item/toy/bosunwhistle, - /obj/item/toy/therapy_red, - /obj/item/toy/therapy_purple, - /obj/item/toy/therapy_blue, - /obj/item/toy/therapy_yellow, - /obj/item/toy/therapy_orange, - /obj/item/toy/therapy_green, - /obj/item/sword/cult_toy, - /obj/item/sword/katana/toy, - /obj/item/toy/snappop, - /obj/item/toy/sword, - /obj/item/toy/water_balloon, - /obj/item/toy/crossbow, - /obj/item/toy/blink, - /obj/item/chems/spray/waterflower, - /obj/item/toy/prize/powerloader, - /obj/item/toy/prize/fireripley, - /obj/item/toy/prize/deathripley, - /obj/item/toy/prize/gygax, - /obj/item/toy/prize/durand, - /obj/item/toy/prize/honk, - /obj/item/toy/prize/marauder, - /obj/item/toy/prize/seraph, - /obj/item/toy/prize/mauler, - /obj/item/toy/prize/odysseus, - /obj/item/toy/prize/phazon, - /obj/item/deck/cards) - -/obj/random/tank - name = "random tank" - desc = "This is a tank." - icon = 'icons/obj/tank.dmi' - icon_state = "canister" - -/obj/random/tank/spawn_choices() - return list(/obj/item/tank/oxygen = 5, - /obj/item/tank/oxygen/yellow = 4, - /obj/item/tank/emergency/oxygen/double/red = 4, - /obj/item/tank/air = 3, - /obj/item/tank/emergency/oxygen = 4, - /obj/item/tank/emergency/oxygen/engi = 3, - /obj/item/tank/emergency/oxygen/double = 2, - /obj/item/tank/emergency/nitrogen = 2, - /obj/item/tank/emergency/nitrogen/double = 1, - /obj/item/tank/nitrogen = 1, - /obj/item/suit_cooling_unit = 1) - -/obj/random/material //Random materials for building stuff - name = "random material" - desc = "This is a random material." - icon = 'icons/obj/materials.dmi' - icon_state = "sheet" - -/obj/random/material/spawn_choices() - return list(/obj/item/stack/material/steel/ten, - /obj/item/stack/material/glass/ten, - /obj/item/stack/material/glass/reinforced/ten, - /obj/item/stack/material/plastic/ten, - /obj/item/stack/material/wood/ten, - /obj/item/stack/material/cardboard/ten, - /obj/item/stack/material/rods/ten, - /obj/item/stack/material/plasteel/ten, - /obj/item/stack/material/steel/fifty, - /obj/item/stack/material/glass/fifty, - /obj/item/stack/material/glass/reinforced/fifty, - /obj/item/stack/material/plastic/fifty, - /obj/item/stack/material/wood/fifty, - /obj/item/stack/material/cardboard/fifty, - /obj/item/stack/material/rods/fifty, - /obj/item/stack/material/plasteel/fifty) - -/obj/random/soap - name = "Random Cleaning Supplies" - desc = "This is a random bar of soap. Soap! SOAP?! SOAP!!!" - icon = 'icons/obj/items/random_spawn.dmi' - icon_state = "soaprandom" - -/obj/random/soap/spawn_choices() - return list(/obj/item/soap = 12, - /obj/item/chems/glass/rag = 2, - /obj/item/chems/spray/cleaner = 2, - /obj/item/grenade/chem_grenade/cleaner = 1) - -obj/random/obstruction //Large objects to block things off in maintenance - name = "random obstruction" - desc = "This is a random obstruction." - icon = 'icons/obj/cult.dmi' - icon_state = "cultgirder" - -obj/random/obstruction/spawn_choices() - return list(/obj/structure/barricade, - /obj/structure/girder, - /obj/structure/girder/displaced, - /obj/structure/grille, - /obj/structure/grille/broken, - /obj/structure/foamedmetal, - /obj/item/caution, - /obj/item/caution/cone, - /obj/structure/inflatable/wall, - /obj/structure/inflatable/door) - -/obj/random/assembly - name = "random assembly" - desc = "This is a random circuit assembly." - icon = 'icons/obj/items/gift_wrapped.dmi' - icon_state = "gift1" - -/obj/random/assembly/spawn_choices() - return list(/obj/item/electronic_assembly, - /obj/item/electronic_assembly/medium, - /obj/item/electronic_assembly/large, - /obj/item/electronic_assembly/drone) - -/obj/random/advdevice - name = "random advanced device" - desc = "This is a random advanced device." - icon = 'icons/obj/items/gamekit.dmi' - icon_state = "game_kit" - -/obj/random/advdevice/spawn_choices() - return list(/obj/item/flashlight/lantern, - /obj/item/flashlight/flare, - /obj/item/flashlight/pen, - /obj/item/toner, - /obj/item/paicard, - /obj/item/destTagger, - /obj/item/beartrap, - /obj/item/handcuffs, - /obj/item/camera_assembly, - /obj/item/camera, - /obj/item/modular_computer/pda, - /obj/item/card/emag_broken, - /obj/item/radio/headset, - /obj/item/flashlight/flare/glowstick/yellow, - /obj/item/flashlight/flare/glowstick/orange, - /obj/item/grenade/light, - /obj/item/oxycandle) - -/obj/random/smokes - name = "random smokeable" - desc = "This is a random smokeable item." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "Bpacket" - -/obj/random/smokes/spawn_choices() - return list(/obj/item/storage/fancy/cigarettes = 5, - /obj/item/storage/fancy/cigarettes/dromedaryco = 4, - /obj/item/storage/fancy/cigarettes/killthroat = 1, - /obj/item/storage/fancy/cigarettes/luckystars = 3, - /obj/item/storage/fancy/cigarettes/jerichos = 3, - /obj/item/storage/fancy/cigarettes/menthols = 2, - /obj/item/storage/fancy/cigarettes/carcinomas = 3, - /obj/item/storage/fancy/cigarettes/professionals = 2, - /obj/item/storage/fancy/cigar = 1, - /obj/item/clothing/mask/smokable/cigarette = 2, - /obj/item/clothing/mask/smokable/cigarette/menthol = 2, - /obj/item/clothing/mask/smokable/cigarette/cigar = 1, - /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba = 1, - /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 1) - -/obj/random/masks - name = "random mask" - desc = "This is a random face mask." - icon = 'icons/obj/clothing/obj_mask.dmi' - icon_state = "gas_mask" - -/obj/random/masks/spawn_choices() - return list(/obj/item/clothing/mask/gas = 4, - /obj/item/clothing/mask/gas/half = 5, - /obj/item/clothing/mask/gas/swat = 1, - /obj/item/clothing/mask/gas/syndicate = 1, - /obj/item/clothing/mask/breath = 6, - /obj/item/clothing/mask/breath/medical = 4, - /obj/item/clothing/mask/balaclava = 3, - /obj/item/clothing/mask/balaclava/tactical = 2, - /obj/item/clothing/mask/surgical = 4) - -/obj/random/snack - name = "random snack" - desc = "This is a random snack item." - icon = 'icons/obj/food.dmi' - icon_state = "sosjerky" - -/obj/random/snack/spawn_choices() - return list(/obj/item/chems/food/snacks/liquidfood, - /obj/item/chems/food/snacks/candy, - /obj/item/chems/food/drinks/dry_ramen, - /obj/item/chems/food/snacks/chips, - /obj/item/chems/food/snacks/sosjerky, - /obj/item/chems/food/snacks/no_raisin, - /obj/item/chems/food/snacks/spacetwinkie, - /obj/item/chems/food/snacks/cheesiehonkers, - /obj/item/chems/food/snacks/tastybread, - /obj/item/chems/food/snacks/candy/proteinbar, - /obj/item/chems/food/snacks/syndicake, - /obj/item/chems/food/snacks/donut, - /obj/item/chems/food/snacks/donut/cherryjelly, - /obj/item/chems/food/snacks/donut/jelly, - /obj/item/pizzabox/meat, - /obj/item/pizzabox/vegetable, - /obj/item/pizzabox/margherita, - /obj/item/pizzabox/mushroom, - /obj/item/chems/food/snacks/plumphelmetbiscuit) - - -/obj/random/storage - name = "random storage item" - desc = "This is a storage item." - icon = 'icons/obj/items/storage/box.dmi' - icon_state = "idOld" - -/obj/random/storage/spawn_choices() - return list(/obj/item/storage/secure/briefcase = 2, - /obj/item/storage/briefcase = 4, - /obj/item/storage/briefcase/inflatable = 3, - /obj/item/storage/backpack = 5, - /obj/item/storage/backpack/satchel = 5, - /obj/item/storage/backpack/dufflebag = 2, - /obj/item/storage/box = 5, - /obj/item/storage/box/donkpockets = 3, - /obj/item/storage/box/sinpockets = 1, - /obj/item/storage/box/donut = 2, - /obj/item/storage/box/cups = 3, - /obj/item/storage/box/mousetraps = 4, - /obj/item/storage/box/engineer = 3, - /obj/item/storage/box/autoinjectors = 2, - /obj/item/storage/box/beakers = 3, - /obj/item/storage/box/syringes = 3, - /obj/item/storage/box/gloves = 3, - /obj/item/storage/box/large = 2, - /obj/item/storage/box/glowsticks = 3, - /obj/item/storage/wallet = 1, - /obj/item/storage/ore = 2, - /obj/item/storage/belt/utility/full = 2, - /obj/item/storage/belt/medical/emt = 2, - /obj/item/storage/belt/medical = 2, - /obj/item/storage/belt/holster/security = 2, - /obj/item/storage/belt/holster/security/tactical = 1) - -/obj/random/shoes - name = "random footwear" - desc = "This is a random pair of shoes." - icon = 'icons/clothing/feet/generic_shoes.dmi' - icon_state = ICON_STATE_WORLD - -/obj/random/shoes/spawn_choices() - return list(/obj/item/clothing/shoes/workboots = 3, - /obj/item/clothing/shoes/jackboots = 3, - /obj/item/clothing/shoes/jackboots/swat = 1, - /obj/item/clothing/shoes/jackboots/swat/combat = 1, - /obj/item/clothing/shoes/galoshes = 2, - /obj/item/clothing/shoes/syndigaloshes = 1, - /obj/item/clothing/shoes/magboots = 1, - /obj/item/clothing/shoes/dress = 4, - /obj/item/clothing/shoes/jackboots/jungleboots = 3, - /obj/item/clothing/shoes/jackboots/desertboots = 3, - /obj/item/clothing/shoes/jackboots/duty = 3, - /obj/item/clothing/shoes/jackboots/tactical = 1, - /obj/item/clothing/shoes/color/black = 4, - /obj/item/clothing/shoes/dress = 3, - /obj/item/clothing/shoes/dress/white = 3, - /obj/item/clothing/shoes/sandal = 3, - /obj/item/clothing/shoes/color/brown = 4, - /obj/item/clothing/shoes/color/red = 4, - /obj/item/clothing/shoes/color/blue = 4, - /obj/item/clothing/shoes/craftable = 4) - -/obj/random/gloves - name = "random gloves" - desc = "This is a random pair of gloves." - icon = 'icons/clothing/hands/gloves_generic.dmi' - icon_state = ICON_STATE_INV - -/obj/random/gloves/spawn_choices() - return list(/obj/item/clothing/gloves/insulated = 3, - /obj/item/clothing/gloves/thick = 6, - /obj/item/clothing/gloves/thick/botany = 5, - /obj/item/clothing/gloves/latex = 4, - /obj/item/clothing/gloves/thick/swat = 3, - /obj/item/clothing/gloves/thick/combat = 3, - /obj/item/clothing/gloves/color/white = 5, - /obj/item/clothing/gloves/rainbow = 1, - /obj/item/clothing/gloves/thick/duty = 5, - /obj/item/clothing/gloves/guards = 3, - /obj/item/clothing/gloves/tactical = 3, - /obj/item/clothing/gloves/insulated/cheap = 5) - -/obj/random/glasses - name = "random eyewear" - desc = "This is a random pair of glasses." - icon = 'icons/obj/clothing/obj_eyes.dmi' - icon_state = "leforge" - -/obj/random/glasses/spawn_choices() - return list(/obj/item/clothing/glasses/sunglasses = 3, - /obj/item/clothing/glasses/prescription = 7, - /obj/item/clothing/glasses/meson = 5, - /obj/item/clothing/glasses/meson/prescription = 4, - /obj/item/clothing/glasses/science = 6, - /obj/item/clothing/glasses/material = 5, - /obj/item/clothing/glasses/welding = 3, - /obj/item/clothing/glasses/hud/health = 4, - /obj/item/clothing/glasses/hud/health/prescription = 3, - /obj/item/clothing/glasses/hud/security = 4, - /obj/item/clothing/glasses/hud/security/prescription = 3, - /obj/item/clothing/glasses/sunglasses/sechud = 2, - /obj/item/clothing/glasses/sunglasses/sechud/toggle = 3, - /obj/item/clothing/glasses/sunglasses/sechud/goggles = 1, - /obj/item/clothing/glasses/tacgoggles = 1) - -/obj/random/hat - name = "random headgear" - desc = "This is a random hat of some kind." - icon = 'icons/clothing/head/softcap.dmi' - icon_state = ICON_STATE_WORLD - -/obj/random/hat/spawn_choices() - return list(/obj/item/clothing/head/helmet = 2, - /obj/item/clothing/head/helmet/tactical = 1, - /obj/item/clothing/head/helmet/space/emergency = 1, - /obj/item/clothing/head/bio_hood/general = 1, - /obj/item/clothing/head/hardhat = 4, - /obj/item/clothing/head/hardhat/orange = 4, - /obj/item/clothing/head/hardhat/red = 4, - /obj/item/clothing/head/hardhat/dblue = 4, - /obj/item/clothing/head/ushanka = 3, - /obj/item/clothing/head/welding = 2) - -/obj/random/suit - name = "random suit" - desc = "This is a random piece of outerwear." - icon = 'icons/clothing/suit/firesuit.dmi' - icon_state = ICON_STATE_WORLD - -/obj/random/suit/spawn_choices() - return list(/obj/item/clothing/suit/storage/hazardvest = 4, - /obj/item/clothing/suit/storage/toggle/labcoat = 4, - /obj/item/clothing/suit/space/emergency = 1, - /obj/item/clothing/suit/armor/vest = 4, - /obj/item/clothing/suit/armor/pcarrier/tactical = 1, - /obj/item/clothing/suit/armor/vest/heavy = 3, - /obj/item/clothing/suit/storage/toggle/bomber = 3, - /obj/item/clothing/suit/chef/classic = 3, - /obj/item/clothing/suit/surgicalapron = 2, - /obj/item/clothing/suit/apron/overalls = 3, - /obj/item/clothing/suit/bio_suit/general = 1, - /obj/item/clothing/suit/storage/toggle/hoodie/black = 3, - /obj/item/clothing/suit/storage/toggle/brown_jacket = 3, - /obj/item/clothing/suit/storage/leather_jacket = 3, - /obj/item/clothing/suit/apron = 4) - -/obj/random/clothing - name = "random clothes" - desc = "This is a random piece of clothing." - icon = 'icons/obj/clothing/obj_under.dmi' - icon_state = "jumpsuit" - -/obj/random/clothing/spawn_choices() - return list(/obj/item/clothing/under/syndicate/tacticool = 2, - /obj/item/clothing/under/syndicate/combat = 1, - /obj/item/clothing/under/hazard = 4, - /obj/item/clothing/under/sterile = 4, - /obj/item/clothing/under/casual_pants/camo = 2, - /obj/item/clothing/under/frontier = 2, - /obj/item/clothing/under/harness = 2, - /obj/item/clothing/under/rank/medical/paramedic = 2, - /obj/item/clothing/under/overalls = 2, - /obj/item/clothing/ears/earmuffs = 2, - /obj/item/clothing/under/tactical = 1) - -/obj/random/accessory - name = "random accessory" - desc = "This is a random utility accessory." - icon = 'icons/obj/clothing/obj_accessories.dmi' - icon_state = "horribletie" - -/obj/random/accessory/spawn_choices() - return list(/obj/item/clothing/accessory/storage/webbing = 3, - /obj/item/clothing/accessory/storage/webbing_large = 3, - /obj/item/clothing/accessory/storage/black_vest = 2, - /obj/item/clothing/accessory/storage/brown_vest = 2, - /obj/item/clothing/accessory/storage/white_vest = 2, - /obj/item/clothing/accessory/storage/bandolier = 1, - /obj/item/clothing/accessory/storage/holster/thigh = 1, - /obj/item/clothing/accessory/storage/holster/hip = 1, - /obj/item/clothing/accessory/storage/holster/waist = 1, - /obj/item/clothing/accessory/storage/holster/armpit = 1, - /obj/item/clothing/accessory/kneepads = 3, - /obj/item/clothing/accessory/stethoscope = 2) - -/obj/random/cash - name = "random currency" - desc = "LOADSAMONEY!" - icon = 'icons/obj/items/money.dmi' - icon_state = "spacecash1" - -/obj/random/cash/spawn_choices() - return list(/obj/item/cash/c1 = 4, - /obj/item/cash/c10 = 3, - /obj/item/cash/c20 = 3, - /obj/item/cash/c50 = 2, - /obj/item/cash/c100 = 2, - /obj/item/cash/c1000 = 1) - -/obj/random/documents // top secret documents, mostly overriden by maps - name = "random secret documents" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "docs_generic" - -/obj/random/documents/spawn_choices() - return list(/obj/item/documents) - -/obj/random/maintenance //Clutter and loot for maintenance and away missions - name = "random maintenance item" - desc = "This is a random maintenance item." - icon = 'icons/obj/items/gift_wrapped.dmi' - icon_state = "gift1" - -/obj/random/maintenance/spawn_choices() - return list(/obj/random/junk = 4, - /obj/random/trash = 4, - /obj/random/maintenance/clean = 5) - -/obj/random/maintenance/clean -/*Maintenance loot lists without the trash, for use inside things. -Individual items to add to the maintenance list should go here, if you add -something, make sure it's not in one of the other lists.*/ - name = "random clean maintenance item" - desc = "This is a random clean maintenance item." - icon = 'icons/obj/items/gift_wrapped.dmi' - icon_state = "gift2" - -/obj/random/maintenance/clean/spawn_choices() - return list(/obj/random/tech_supply = 100, - /obj/random/medical = 40, - /obj/random/medical/lite = 80, - /obj/random/firstaid = 20, - /obj/random/powercell = 50, - /obj/random/technology_scanner = 80, - /obj/random/bomb_supply = 80, - /obj/random/contraband = 1, - /obj/random/action_figure = 2, - /obj/random/plushie = 2, - /obj/random/material = 40, - /obj/random/coin = 5, - /obj/random/toy = 20, - /obj/random/tank = 20, - /obj/random/soap = 5, - /obj/random/drinkbottle = 5, - /obj/random/loot = 1, - /obj/random/advdevice = 50, - /obj/random/smokes = 30, - /obj/random/masks = 10, - /obj/random/snack = 60, - /obj/random/storage = 30, - /obj/random/shoes = 20, - /obj/random/gloves = 10, - /obj/random/glasses = 20, - /obj/random/hat = 10, - /obj/random/suit = 20, - /obj/random/clothing = 30, - /obj/random/accessory = 20, - /obj/random/cash = 10) - -/obj/random/loot /*Better loot for away missions and salvage */ - name = "random loot" - desc = "This is some random loot." - icon = 'icons/obj/items/gift_wrapped.dmi' - icon_state = "gift3" - -/obj/random/loot/spawn_choices() - return list(/obj/random/energy = 10, - /obj/random/projectile = 10, - /obj/random/voidhelmet = 10, - /obj/random/voidsuit = 10, - /obj/random/hardsuit = 10, - /obj/item/clothing/mask/muzzle = 7, - /obj/item/clothing/mask/gas/vox = 8, - /obj/item/clothing/mask/gas/syndicate = 10, - /obj/item/clothing/glasses/night = 3, - /obj/item/clothing/glasses/thermal = 1, - /obj/item/clothing/glasses/welding/superior = 7, - /obj/item/clothing/head/collectable/petehat = 4, - /obj/item/clothing/suit/armor/pcarrier/merc = 3, - /obj/item/clothing/suit/straight_jacket = 6, - /obj/item/clothing/head/helmet/merc = 3, - /obj/item/stack/material/diamond/ten = 7, - /obj/item/stack/material/glass/reinforced_borosilicate/ten = 7, - /obj/item/stack/material/marble/ten = 8, - /obj/item/stack/material/gold/ten = 7, - /obj/item/stack/material/silver/ten = 7, - /obj/item/stack/material/osmium/ten = 7, - /obj/item/stack/material/platinum/ten = 8, - /obj/item/stack/material/tritium/ten = 7, - /obj/item/stack/material/mhydrogen/ten = 6, - /obj/item/stack/material/plasteel/ten = 9, - /obj/item/storage/box/monkeycubes = 5, - /obj/item/storage/firstaid/surgery = 4, - /obj/item/cell/infinite = 1, - /obj/item/archaeological_find = 2, - /obj/structure/artifact = 1, - /obj/item/multitool/hacktool = 2, - /obj/item/surgicaldrill = 7, - /obj/item/sutures = 7, - /obj/item/retractor = 7, - /obj/item/hemostat = 7, - /obj/item/cautery = 7, - /obj/item/bonesetter = 7, - /obj/item/bonegel = 7, - /obj/item/circular_saw = 7, - /obj/item/scalpel = 7, - /obj/item/baton/loaded = 9, - /obj/item/radio/headset/syndicate = 6) - -/obj/random/voidhelmet - name = "Random Voidsuit Helmet" - desc = "This is a random voidsuit helmet." - icon = 'icons/clothing/spacesuit/generic/helmet.dmi' - icon_state = ICON_STATE_WORLD - -/obj/random/voidhelmet/spawn_choices() - return list(/obj/item/clothing/head/helmet/space/void, - /obj/item/clothing/head/helmet/space/void/engineering, - /obj/item/clothing/head/helmet/space/void/engineering/alt, - /obj/item/clothing/head/helmet/space/void/engineering/salvage, - /obj/item/clothing/head/helmet/space/void/mining, - /obj/item/clothing/head/helmet/space/void/mining/alt, - /obj/item/clothing/head/helmet/space/void/security, - /obj/item/clothing/head/helmet/space/void/security/alt, - /obj/item/clothing/head/helmet/space/void/atmos, - /obj/item/clothing/head/helmet/space/void/atmos/alt, - /obj/item/clothing/head/helmet/space/void/merc, - /obj/item/clothing/head/helmet/space/void/medical, - /obj/item/clothing/head/helmet/space/void/medical/alt) - -/obj/random/voidsuit - name = "Random Voidsuit" - desc = "This is a random voidsuit." - icon = 'icons/clothing/spacesuit/void/nasa/suit.dmi' - icon_state = ICON_STATE_WORLD - -/obj/random/voidsuit/spawn_choices() - return list(/obj/item/clothing/suit/space/void, - /obj/item/clothing/suit/space/void/engineering, - /obj/item/clothing/suit/space/void/engineering/alt, - /obj/item/clothing/suit/space/void/engineering/salvage, - /obj/item/clothing/suit/space/void/mining, - /obj/item/clothing/suit/space/void/mining/alt, - /obj/item/clothing/suit/space/void/security, - /obj/item/clothing/suit/space/void/security/alt, - /obj/item/clothing/suit/space/void/atmos, - /obj/item/clothing/suit/space/void/atmos/alt, - /obj/item/clothing/suit/space/void/merc, - /obj/item/clothing/suit/space/void/medical, - /obj/item/clothing/suit/space/void/medical/alt) - -/obj/random/hardsuit - name = "Random Hardsuit" - desc = "This is a random hardsuit control module." - icon = 'icons/obj/rig_modules.dmi' - icon_state = "generic" - -/obj/random/hardsuit/spawn_choices() - return list(/obj/item/rig/industrial, - /obj/item/rig/eva, - /obj/item/rig/light/hacker, - /obj/item/rig/light/stealth, - /obj/item/rig/light) - -/obj/random/hostile - name = "Random Hostile Mob" - desc = "This is a random hostile mob." - icon = 'icons/mob/amorph.dmi' - icon_state = "standing" - spawn_nothing_percentage = 80 - -obj/random/hostile/spawn_choices() - return list(/mob/living/simple_animal/hostile/viscerator, - /mob/living/simple_animal/hostile/carp, - /mob/living/simple_animal/hostile/carp/pike, - /mob/living/simple_animal/hostile/vagrant/swarm) - -/* - Selects one spawn point out of a group of points with the same ID and asks it to generate its items -*/ -var/list/multi_point_spawns - -/obj/random_multi - name = "random object spawn point" - desc = "This item type is used to spawn random objects at round-start. Only one spawn point for a given group id is selected." - icon = 'icons/misc/mark.dmi' - icon_state = "x3" - invisibility = INVISIBILITY_MAXIMUM - var/id // Group id - var/weight // Probability weight for this spawn point - -/obj/random_multi/Initialize() - . = ..() - weight = max(1, round(weight)) - - if(!multi_point_spawns) - multi_point_spawns = list() - var/list/spawnpoints = multi_point_spawns[id] - if(!spawnpoints) - spawnpoints = list() - multi_point_spawns[id] = spawnpoints - spawnpoints[src] = weight - -/obj/random_multi/Destroy() - var/list/spawnpoints = multi_point_spawns[id] - spawnpoints -= src - if(!spawnpoints.len) - multi_point_spawns -= id - . = ..() - -/obj/random_multi/proc/generate_items() - return - -/obj/random_multi/single_item - var/item_path // Item type to spawn - -/obj/random_multi/single_item/generate_items() - new item_path(loc) - -/hook/roundstart/proc/generate_multi_spawn_items() - for(var/id in multi_point_spawns) - var/list/spawn_points = multi_point_spawns[id] - var/obj/random_multi/rm = pickweight(spawn_points) - rm.generate_items() - for(var/entry in spawn_points) - qdel(entry) - return 1 - -/obj/random_multi/single_item/captains_spare_id - name = "Multi Point - Captain's Spare" - id = "Captain's spare id" - item_path = /obj/item/card/id/captains_spare - -var/list/random_junk_ -var/list/random_useful_ -/proc/get_random_useful_type() - if(!random_useful_) - random_useful_ = list() - random_useful_ += /obj/item/pen/crayon/random - random_useful_ += /obj/item/pen - random_useful_ += /obj/item/pen/blue - random_useful_ += /obj/item/pen/red - random_useful_ += /obj/item/pen/multi - random_useful_ += /obj/item/storage/box/matches - random_useful_ += /obj/item/stack/material/cardboard - random_useful_ += /obj/item/storage/fancy/cigarettes - random_useful_ += /obj/item/deck/cards - return pick(random_useful_) - -/proc/get_random_junk_type() - if(prob(20)) // Misc. clutter - return /obj/effect/decal/cleanable/generic - - // 80% chance that we reach here - if(prob(95)) // Misc. junk - if(!random_junk_) - random_junk_ = subtypesof(/obj/item/trash) - random_junk_ += typesof(/obj/item/trash/cigbutt) - random_junk_ += /obj/effect/decal/cleanable/spiderling_remains - random_junk_ += /obj/item/remains/mouse - random_junk_ += /obj/item/remains/robot - random_junk_ += /obj/item/paper/crumpled - random_junk_ += /obj/item/inflatable/torn - random_junk_ += /obj/effect/decal/cleanable/molten_item - random_junk_ += /obj/item/shard - random_junk_ += /obj/item/hand/missing_card - - random_junk_ -= /obj/item/trash/plate - random_junk_ -= /obj/item/trash/snack_bowl - random_junk_ -= /obj/item/trash/syndi_cakes - random_junk_ -= /obj/item/trash/tray - return pick(random_junk_) - - // Misc. actually useful stuff or perhaps even food - // 4% chance that we reach here - if(prob(75)) - return get_random_useful_type() - - // 1% chance that we reach here - var/lunches = lunchables_lunches() - return lunches[pick(lunches)] - -/obj/random/clipboard - name = "random clipboard" - desc = "This is a random material clipboard." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "clipboard_preview" - -/obj/random/clipboard/spawn_choices() - return list(/obj/item/clipboard = 300, - /obj/item/clipboard/steel = 200, - /obj/item/clipboard/aluminium = 200, - /obj/item/clipboard/plastic = 200, - /obj/item/clipboard/glass = 100, - /obj/item/clipboard/ebony = 10) - -//Random MRE stuff - -/obj/random/mre - name = "random MRE" - desc = "This is a random single MRE." - icon = 'icons/obj/food.dmi' - icon_state = "mre" - -/obj/random/mre/spawn_choices() - return list(/obj/item/storage/mre, - /obj/item/storage/mre/menu2, - /obj/item/storage/mre/menu3, - /obj/item/storage/mre/menu4, - /obj/item/storage/mre/menu5, - /obj/item/storage/mre/menu6, - /obj/item/storage/mre/menu7, - /obj/item/storage/mre/menu8, - /obj/item/storage/mre/menu9, - /obj/item/storage/mre/menu10) - - -/obj/random/mre/main - name = "random MRE main course" - desc = "This is a random main course for MREs." - icon_state = "pouch_medium" - -/obj/random/mre/main/spawn_choices() - return list(/obj/item/storage/mrebag, - /obj/item/storage/mrebag/menu2, - /obj/item/storage/mrebag/menu3, - /obj/item/storage/mrebag/menu4, - /obj/item/storage/mrebag/menu5, - /obj/item/storage/mrebag/menu6, - /obj/item/storage/mrebag/menu7, - /obj/item/storage/mrebag/menu8) - -/obj/random/mre/dessert - name = "random MRE dessert" - desc = "This is a random dessert for MREs." - icon_state = "pouch_medium" - -/obj/random/mre/dessert/spawn_choices() - return list(/obj/item/chems/food/snacks/candy, - /obj/item/chems/food/snacks/candy/proteinbar, - /obj/item/chems/food/snacks/donut/normal, - /obj/item/chems/food/snacks/donut/cherryjelly, - /obj/item/chems/food/snacks/chocolatebar, - /obj/item/chems/food/snacks/cookie, - /obj/item/chems/food/snacks/poppypretzel, - /obj/item/clothing/mask/chewable/candy/gum) - -/obj/random/mre/dessert/vegan - name = "random vegan MRE dessert" - desc = "This is a random vegan dessert for MREs." - -/obj/random/mre/dessert/vegan/spawn_choices() - return list(/obj/item/chems/food/snacks/candy, - /obj/item/chems/food/snacks/chocolatebar, - /obj/item/chems/food/snacks/donut/cherryjelly, - /obj/item/chems/food/snacks/plumphelmetbiscuit) - -/obj/random/mre/drink - name = "random MRE drink" - desc = "This is a random drink for MREs." - icon_state = "packet_small" - -/obj/random/mre/drink/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/coffee, - /obj/item/chems/food/condiment/small/packet/tea, - /obj/item/chems/food/condiment/small/packet/cocoa, - /obj/item/chems/food/condiment/small/packet/grape, - /obj/item/chems/food/condiment/small/packet/orange, - /obj/item/chems/food/condiment/small/packet/watermelon, - /obj/item/chems/food/condiment/small/packet/apple) - -/obj/random/mre/spread - name = "random MRE spread" - desc = "This is a random spread packet for MREs." - icon_state = "packet_small" - -/obj/random/mre/spread/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/jelly, - /obj/item/chems/food/condiment/small/packet/honey) - -/obj/random/mre/spread/vegan - name = "random vegan MRE spread" - desc = "This is a random vegan spread packet for MREs" - -/obj/random/mre/spread/vegan/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/jelly) - -/obj/random/mre/sauce - name = "random MRE sauce" - desc = "This is a random sauce packet for MREs." - icon_state = "packet_small" - -/obj/random/mre/sauce/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/salt, - /obj/item/chems/food/condiment/small/packet/pepper, - /obj/item/chems/food/condiment/small/packet/sugar, - /obj/item/chems/food/condiment/small/packet/capsaicin, - /obj/item/chems/food/condiment/small/packet/ketchup, - /obj/item/chems/food/condiment/small/packet/mayo, - /obj/item/chems/food/condiment/small/packet/soy) - -/obj/random/mre/sauce/vegan/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/salt, - /obj/item/chems/food/condiment/small/packet/pepper, - /obj/item/chems/food/condiment/small/packet/sugar, - /obj/item/chems/food/condiment/small/packet/soy) - -/obj/random/mre/sauce/sugarfree/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/salt, - /obj/item/chems/food/condiment/small/packet/pepper, - /obj/item/chems/food/condiment/small/packet/capsaicin, - /obj/item/chems/food/condiment/small/packet/ketchup, - /obj/item/chems/food/condiment/small/packet/mayo, - /obj/item/chems/food/condiment/small/packet/soy) - -/obj/random/mre/sauce/crayon/spawn_choices() - return list(/obj/item/chems/food/condiment/small/packet/crayon, - /obj/item/chems/food/condiment/small/packet/crayon/red, - /obj/item/chems/food/condiment/small/packet/crayon/orange, - /obj/item/chems/food/condiment/small/packet/crayon/yellow, - /obj/item/chems/food/condiment/small/packet/crayon/green, - /obj/item/chems/food/condiment/small/packet/crayon/blue, - /obj/item/chems/food/condiment/small/packet/crayon/purple, - /obj/item/chems/food/condiment/small/packet/crayon/grey, - /obj/item/chems/food/condiment/small/packet/crayon/brown) - -/obj/random/vendor - name = "random vending machine" - desc = "This is a randomly selected vending machine." - icon = 'icons/obj/vending.dmi' - icon_state = "" - -/obj/random/vendor/spawn_choices() - return list(/obj/machinery/vending/weeb, - /obj/machinery/vending/sol, - /obj/machinery/vending/snix - ) - -/obj/random/single/playing_cards - name = "randomly spawned deck of cards" - icon = 'icons/obj/items/playing_cards.dmi' - icon_state = "deck" - spawn_object = /obj/item/deck - -/obj/random/single/lighter - name = "randomly spawned lighter" - icon = 'icons/obj/items/lighters.dmi' - icon_state = "lighter" - spawn_object = /obj/item/flame/lighter - -/obj/random/single/cola - name = "randomly spawned cola" - icon = 'icons/obj/drinks.dmi' - icon_state = "cola" - spawn_object = /obj/item/chems/food/drinks/cans/cola - -//textbooks -/obj/random/single/textbook - name = "random textbook" - icon = 'icons/obj/library.dmi' - icon_state = "book" - spawn_object = /obj/item/book/skill //Further randomization of which book is handled inside the book initialization - spawn_nothing_percentage = 0 - -/obj/random/lipstick - name = "random lipstick" - desc = "This is a tube of lipstick." - icon = 'icons/obj/items/lipstick.dmi' - icon_state = "lipstick_closed" - -/obj/random/lipstick/spawn_choices() - return list(/obj/item/lipstick, - /obj/item/lipstick/blue, - /obj/item/lipstick/green, - /obj/item/lipstick/turquoise, - /obj/item/lipstick/violet, - /obj/item/lipstick/yellow, - /obj/item/lipstick/orange, - /obj/item/lipstick/white, - /obj/item/lipstick/black) \ No newline at end of file + return spawn_object && list(spawn_object) diff --git a/code/game/objects/random/random_multi.dm b/code/game/objects/random/random_multi.dm new file mode 100644 index 000000000000..11ad1cd96df8 --- /dev/null +++ b/code/game/objects/random/random_multi.dm @@ -0,0 +1,37 @@ +/* + Selects one spawn point out of a group of points with the same ID and asks it to generate its items +*/ +/obj/random_multi + name = "random object spawn point" + desc = "This item type is used to spawn random objects at round-start. Only one spawn point for a given group id is selected." + icon = 'icons/misc/mark.dmi' + icon_state = "x3" + invisibility = INVISIBILITY_ABSTRACT + var/id // Group id + var/weight // Probability weight for this spawn point + +/obj/random_multi/modify_mapped_vars(map_hash) + . = ..() + ADJUST_TAG_VAR(id, map_hash) + +/obj/random_multi/Initialize() + . = ..() + weight = max(1, round(weight)) + + if(!multi_point_spawns) + multi_point_spawns = list() + var/list/spawnpoints = multi_point_spawns[id] + if(!spawnpoints) + spawnpoints = list() + multi_point_spawns[id] = spawnpoints + spawnpoints[src] = weight + +/obj/random_multi/Destroy() + var/list/spawnpoints = multi_point_spawns[id] + spawnpoints -= src + if(!spawnpoints.len) + multi_point_spawns -= id + . = ..() + +/obj/random_multi/proc/generate_items() + return diff --git a/code/game/objects/random/subtypes/closets.dm b/code/game/objects/random/subtypes/closets.dm new file mode 100644 index 000000000000..956ef9fd70dc --- /dev/null +++ b/code/game/objects/random/subtypes/closets.dm @@ -0,0 +1,30 @@ +/obj/random/closet + name = "random closet" + desc = "This is a random closet." + icon = 'icons/obj/closets/bases/closet.dmi' + icon_state = "base" + var/vermin_chance = 0.1 + var/list/locker_vermin = list( + /mob/living/simple_animal/passive/mouse, + /mob/living/simple_animal/opossum + ) + +/obj/random/closet/spawn_choices() + var/static/list/spawnable_choices = typesof(/obj/structure/closet) - (typesof(/obj/structure/closet/crate) | typesof(/obj/structure/closet/body_bag) | typesof(/obj/structure/closet/secure_closet)) + return spawnable_choices + +/obj/random/closet/spawn_item() + . = ..() + if(. && length(locker_vermin) && prob(vermin_chance)) + var/vermin_type = pickweight(locker_vermin) + new vermin_type(.) + +/obj/random/crate + name = "random crate" + desc = "This is a random crate" + icon = 'icons/obj/closets/bases/crate.dmi' + icon_state = "base" + +/obj/random/crate/spawn_choices() + var/static/list/spawnable_choices = typesof(/obj/structure/closet/crate) - typesof(/obj/structure/closet/crate/secure) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/clothing.dm b/code/game/objects/random/subtypes/clothing.dm new file mode 100644 index 000000000000..a54cac010f93 --- /dev/null +++ b/code/game/objects/random/subtypes/clothing.dm @@ -0,0 +1,258 @@ + +/obj/random/masks + name = "random mask" + desc = "This is a random face mask." + icon = 'icons/clothing/mask/gas_mask.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/masks/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/mask/gas = 4, + /obj/item/clothing/mask/gas/half = 5, + /obj/item/clothing/mask/gas/swat = 1, + /obj/item/clothing/mask/gas/syndicate = 1, + /obj/item/clothing/mask/breath = 6, + /obj/item/clothing/mask/breath/medical = 4, + /obj/item/clothing/mask/balaclava = 3, + /obj/item/clothing/mask/balaclava/tactical = 2, + /obj/item/clothing/mask/surgical = 4 + ) + return spawnable_choices + +/obj/random/shoes + name = "random footwear" + desc = "This is a random pair of shoes." + icon = 'icons/clothing/feet/generic_shoes.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/shoes/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/shoes/workboots = 3, + /obj/item/clothing/shoes/jackboots = 3, + /obj/item/clothing/shoes/jackboots/swat = 1, + /obj/item/clothing/shoes/jackboots/swat/combat = 1, + /obj/item/clothing/shoes/galoshes = 2, + /obj/item/clothing/shoes/syndigaloshes = 1, + /obj/item/clothing/shoes/magboots = 1, + /obj/item/clothing/shoes/dress = 4, + /obj/item/clothing/shoes/jackboots/jungleboots = 3, + /obj/item/clothing/shoes/jackboots/desertboots = 3, + /obj/item/clothing/shoes/jackboots/duty = 3, + /obj/item/clothing/shoes/jackboots/tactical = 1, + /obj/item/clothing/shoes/color/black = 4, + /obj/item/clothing/shoes/dress = 3, + /obj/item/clothing/shoes/dress/white = 3, + /obj/item/clothing/shoes/sandal = 3, + /obj/item/clothing/shoes/color/brown = 4, + /obj/item/clothing/shoes/color/red = 4, + /obj/item/clothing/shoes/color/blue = 4, + /obj/item/clothing/shoes/craftable = 4 + ) + return spawnable_choices + +/obj/random/gloves + name = "random gloves" + desc = "This is a random pair of gloves." + icon = 'icons/clothing/hands/gloves_generic.dmi' + icon_state = ICON_STATE_INV + +/obj/random/gloves/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/gloves = 5, + /obj/item/clothing/gloves/insulated = 3, + /obj/item/clothing/gloves/thick = 6, + /obj/item/clothing/gloves/thick/botany = 5, + /obj/item/clothing/gloves/latex = 4, + /obj/item/clothing/gloves/thick/swat = 3, + /obj/item/clothing/gloves/thick/combat = 3, + /obj/item/clothing/gloves/rainbow = 1, + /obj/item/clothing/gloves/thick/duty = 5, + /obj/item/clothing/gloves/guards = 3, + /obj/item/clothing/gloves/tactical = 3, + /obj/item/clothing/gloves/insulated/cheap = 5 + ) + return spawnable_choices + +/obj/random/glasses + name = "random eyewear" + desc = "This is a random pair of glasses." + icon = 'icons/clothing/eyes/glasses_prescription.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/glasses/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/glasses/sunglasses = 3, + /obj/item/clothing/glasses/prescription = 7, + /obj/item/clothing/glasses/meson = 5, + /obj/item/clothing/glasses/meson/prescription = 4, + /obj/item/clothing/glasses/science = 6, + /obj/item/clothing/glasses/material = 5, + /obj/item/clothing/glasses/welding = 3, + /obj/item/clothing/glasses/hud/health = 4, + /obj/item/clothing/glasses/hud/health/prescription = 3, + /obj/item/clothing/glasses/hud/security = 4, + /obj/item/clothing/glasses/hud/security/prescription = 3, + /obj/item/clothing/glasses/sunglasses/sechud = 2, + /obj/item/clothing/glasses/sunglasses/sechud/toggle = 3, + /obj/item/clothing/glasses/sunglasses/sechud/goggles = 1, + /obj/item/clothing/glasses/tacgoggles = 1 + ) + return spawnable_choices + +/obj/random/hat + name = "random headgear" + desc = "This is a random hat of some kind." + icon = 'icons/clothing/head/softcap.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/hat/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/head/helmet = 2, + /obj/item/clothing/head/helmet/tactical = 1, + /obj/item/clothing/head/helmet/space/emergency = 1, + /obj/item/clothing/head/bio_hood/general = 1, + /obj/item/clothing/head/hardhat = 4, + /obj/item/clothing/head/hardhat/orange = 4, + /obj/item/clothing/head/hardhat/red = 4, + /obj/item/clothing/head/hardhat/dblue = 4, + /obj/item/clothing/head/ushanka = 3, + /obj/item/clothing/head/welding = 2 + ) + return spawnable_choices + +/obj/random/suit + name = "random suit" + desc = "This is a random piece of outerwear." + icon = 'icons/clothing/suits/firesuit.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/suit/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/suit/hazardvest = 4, + /obj/item/clothing/suit/toggle/labcoat = 4, + /obj/item/clothing/suit/space/emergency = 1, + /obj/item/clothing/suit/armor/vest = 4, + /obj/item/clothing/suit/armor/pcarrier/tactical = 1, + /obj/item/clothing/suit/armor/vest/heavy = 3, + /obj/item/clothing/suit/jacket/bomber = 3, + /obj/item/clothing/suit/chef/classic = 3, + /obj/item/clothing/suit/surgicalapron = 2, + /obj/item/clothing/suit/apron/overalls = 3, + /obj/item/clothing/suit/bio_suit/general = 1, + /obj/item/clothing/suit/jacket/hoodie/black = 3, + /obj/item/clothing/suit/jacket/brown = 3, + /obj/item/clothing/suit/jacket/leather = 3, + /obj/item/clothing/suit/apron = 4 + ) + return spawnable_choices + +/obj/random/clothing + name = "random clothes" + desc = "This is a random piece of clothing." + icon = 'icons/clothing/jumpsuits/jumpsuit.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/clothing/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/shirt/syndicate/tacticool = 2, + /obj/item/clothing/shirt/syndicate/combat = 1, + /obj/item/clothing/jumpsuit/hazard = 4, + /obj/item/clothing/jumpsuit/sterile = 4, + /obj/item/clothing/pants/casual/camo = 2, + /obj/item/clothing/shirt/flannel/red = 2, + /obj/item/clothing/shirt/harness = 2, + /obj/item/clothing/jumpsuit/medical/paramedic = 2, + /obj/item/clothing/suit/apron/overalls/laborer = 2, + /obj/item/clothing/head/earmuffs = 2, + /obj/item/clothing/jumpsuit/tactical = 1 + ) + return spawnable_choices + +/obj/random/accessory + name = "random accessory" + desc = "This is a random utility accessory." + icon = 'icons/clothing/accessories/ties/tie_horrible.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/accessory/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/webbing = 3, + /obj/item/clothing/webbing/webbing_large = 3, + /obj/item/clothing/webbing/vest/black = 2, + /obj/item/clothing/webbing/vest/brown = 2, + /obj/item/clothing/webbing/vest = 2, + /obj/item/clothing/webbing/bandolier = 1, + /obj/item/clothing/webbing/holster/thigh = 1, + /obj/item/clothing/webbing/holster/hip = 1, + /obj/item/clothing/webbing/holster/waist = 1, + /obj/item/clothing/webbing/holster/armpit = 1, + /obj/item/clothing/shoes/kneepads = 3, + /obj/item/clothing/neck/stethoscope = 2 + ) + return spawnable_choices + +/obj/random/voidhelmet + name = "Random Voidsuit Helmet" + desc = "This is a random voidsuit helmet." + icon = 'icons/clothing/spacesuit/generic/helmet.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/voidhelmet/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/head/helmet/space/void, + /obj/item/clothing/head/helmet/space/void/engineering, + /obj/item/clothing/head/helmet/space/void/engineering/alt, + /obj/item/clothing/head/helmet/space/void/engineering/salvage, + /obj/item/clothing/head/helmet/space/void/mining, + /obj/item/clothing/head/helmet/space/void/mining/alt, + /obj/item/clothing/head/helmet/space/void/security, + /obj/item/clothing/head/helmet/space/void/security/alt, + /obj/item/clothing/head/helmet/space/void/atmos, + /obj/item/clothing/head/helmet/space/void/atmos/alt, + /obj/item/clothing/head/helmet/space/void/merc, + /obj/item/clothing/head/helmet/space/void/medical, + /obj/item/clothing/head/helmet/space/void/medical/alt + ) + return spawnable_choices + +/obj/random/voidsuit + name = "Random Voidsuit" + desc = "This is a random voidsuit." + icon = 'icons/clothing/spacesuit/void/nasa/suit.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/voidsuit/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/suit/space/void, + /obj/item/clothing/suit/space/void/engineering, + /obj/item/clothing/suit/space/void/engineering/alt, + /obj/item/clothing/suit/space/void/engineering/salvage, + /obj/item/clothing/suit/space/void/mining, + /obj/item/clothing/suit/space/void/mining/alt, + /obj/item/clothing/suit/space/void/security, + /obj/item/clothing/suit/space/void/security/alt, + /obj/item/clothing/suit/space/void/atmos, + /obj/item/clothing/suit/space/void/atmos/alt, + /obj/item/clothing/suit/space/void/merc, + /obj/item/clothing/suit/space/void/medical, + /obj/item/clothing/suit/space/void/medical/alt + ) + return spawnable_choices + +/obj/random/poncho + name = "random poncho" + icon = /obj/item/clothing/suit/poncho/green::icon + icon_state = /obj/item/clothing/suit/poncho/green::icon_state + +/obj/random/poncho/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/clothing/suit/poncho/green, + /obj/item/clothing/suit/poncho/red, + /obj/item/clothing/suit/poncho/purple, + /obj/item/clothing/suit/poncho/blue, + /obj/item/clothing/suit/poncho/security, + /obj/item/clothing/suit/poncho/medical, + /obj/item/clothing/suit/poncho/engineering, + /obj/item/clothing/suit/poncho/cargo + ) + return spawn_choices diff --git a/code/game/objects/random/subtypes/food.dm b/code/game/objects/random/subtypes/food.dm new file mode 100644 index 000000000000..36aa8a4a37e6 --- /dev/null +++ b/code/game/objects/random/subtypes/food.dm @@ -0,0 +1,196 @@ +/obj/random/single/cola + name = "randomly spawned cola" + icon = 'icons/obj/drinks.dmi' + icon_state = "cola" + spawn_object = /obj/item/chems/drinks/cans/cola + +/obj/random/mre + name = "random MRE" + desc = "This is a random single MRE." + icon = 'icons/obj/food/mre/mre_generic.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/mre/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/mre, + /obj/item/mre/menu2, + /obj/item/mre/menu3, + /obj/item/mre/menu4, + /obj/item/mre/menu5, + /obj/item/mre/menu6, + /obj/item/mre/menu7, + /obj/item/mre/menu8, + /obj/item/mre/menu9, + /obj/item/mre/menu10 + ) + return spawnable_choices + +/obj/random/mre/main + name = "random MRE main course" + desc = "This is a random main course for MREs." + icon = 'icons/obj/food/mre/pouch_medium.dmi' + icon_state = ICON_STATE_WORLD + + +/obj/random/mre/main/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/mrebag, + /obj/item/mrebag/menu2, + /obj/item/mrebag/menu3, + /obj/item/mrebag/menu4, + /obj/item/mrebag/menu5, + /obj/item/mrebag/menu6, + /obj/item/mrebag/menu7, + /obj/item/mrebag/menu8 + ) + return spawnable_choices + +/obj/random/mre/dessert + name = "random MRE dessert" + desc = "This is a random dessert for MREs." + icon = 'icons/obj/food/mre/pouch_medium.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/mre/dessert/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/food/junk/candy, + /obj/item/food/junk/candy/proteinbar, + /obj/item/food/donut, + /obj/item/food/donut/jelly, + /obj/item/food/chocolatebar, + /obj/item/food/cookie, + /obj/item/food/poppypretzel, + /obj/item/clothing/mask/chewable/candy/gum + ) + return spawnable_choices + +/obj/random/mre/dessert/vegan + name = "random vegan MRE dessert" + desc = "This is a random vegan dessert for MREs." + +/obj/random/mre/dessert/vegan/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/food/junk/candy, + /obj/item/food/chocolatebar, + /obj/item/food/donut/jelly, + /obj/item/food/plumphelmetbiscuit + ) + return spawnable_choices + +/obj/random/mre/drink + name = "random MRE drink" + desc = "This is a random drink for MREs." + icon = 'icons/obj/food/condiments/packets/packet_small.dmi' + +/obj/random/mre/drink/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/packet/coffee, + /obj/item/chems/packet/tea, + /obj/item/chems/packet/cocoa, + /obj/item/chems/packet/grape, + /obj/item/chems/packet/orange, + /obj/item/chems/packet/watermelon, + /obj/item/chems/packet/apple + ) + return spawnable_choices + +/obj/random/mre/spread + name = "random MRE spread" + desc = "This is a random spread packet for MREs." + icon = 'icons/obj/food/condiments/packets/packet_small.dmi' + +/obj/random/mre/spread/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/packet/jelly, + /obj/item/chems/packet/honey, + /obj/item/chems/packet/honey_fake + ) + return spawnable_choices + +/obj/random/mre/spread/vegan + name = "random vegan MRE spread" + desc = "This is a random vegan spread packet for MREs" + +/obj/random/mre/spread/vegan/spawn_choices() + var/static/list/spawnable_choices = list(/obj/item/chems/packet/jelly) + return spawnable_choices + +/obj/random/mre/sauce + name = "random MRE sauce" + desc = "This is a random sauce packet for MREs." + icon = 'icons/obj/food/condiments/packets/packet_small.dmi' + +/obj/random/mre/sauce/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/packet/salt, + /obj/item/chems/packet/pepper, + /obj/item/chems/packet/sugar, + /obj/item/chems/packet/capsaicin, + /obj/item/chems/packet/ketchup, + /obj/item/chems/packet/mayo, + /obj/item/chems/packet/soy + ) + return spawnable_choices + +/obj/random/mre/sauce/vegan/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/packet/salt, + /obj/item/chems/packet/pepper, + /obj/item/chems/packet/sugar, + /obj/item/chems/packet/soy + ) + return spawnable_choices + +/obj/random/mre/sauce/sugarfree/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/packet/salt, + /obj/item/chems/packet/pepper, + /obj/item/chems/packet/capsaicin, + /obj/item/chems/packet/ketchup, + /obj/item/chems/packet/mayo, + /obj/item/chems/packet/soy + ) + return spawnable_choices + +/obj/random/mre/sauce/crayon/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/packet/crayon, + /obj/item/chems/packet/crayon/red, + /obj/item/chems/packet/crayon/orange, + /obj/item/chems/packet/crayon/yellow, + /obj/item/chems/packet/crayon/green, + /obj/item/chems/packet/crayon/blue, + /obj/item/chems/packet/crayon/purple, + /obj/item/chems/packet/crayon/grey, + /obj/item/chems/packet/crayon/brown + ) + return spawnable_choices + +/obj/random/snack + name = "random snack" + desc = "This is a random snack item." + icon = 'icons/obj/food/junk/junkfood.dmi' + icon_state = "sosjerky" + +/obj/random/snack/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/food/junk/liquidfood, + /obj/item/food/junk/candy, + /obj/item/chems/drinks/dry_ramen, + /obj/item/food/junk/chips, + /obj/item/food/junk/sosjerky, + /obj/item/food/junk/no_raisin, + /obj/item/food/junk/spacetwinkie, + /obj/item/food/junk/cheesiehonkers, + /obj/item/food/junk/tastybread, + /obj/item/food/junk/candy/proteinbar, + /obj/item/food/junk/syndicake, + /obj/item/food/donut, + /obj/item/food/donut/jelly, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/vegetable, + /obj/item/pizzabox/margherita, + /obj/item/pizzabox/mushroom, + /obj/item/food/plumphelmetbiscuit + ) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/maintenance.dm b/code/game/objects/random/subtypes/maintenance.dm new file mode 100644 index 000000000000..b141867e7e15 --- /dev/null +++ b/code/game/objects/random/subtypes/maintenance.dm @@ -0,0 +1,250 @@ +/obj/random/maintenance //Clutter and loot for maintenance and away missions + name = "random maintenance item" + desc = "This is a random maintenance item." + icon = 'icons/obj/items/gift_wrapped.dmi' + icon_state = "gift_1" + +/obj/random/maintenance/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/maintenance/clean = 5, + /obj/random/junk = 4, + /obj/random/trash = 4 + ) + return spawnable_choices + +/obj/random/maintenance/clean +/*Maintenance loot lists without the trash, for use inside things. +Individual items to add to the maintenance list should go here, if you add +something, make sure it's not in one of the other lists.*/ + name = "random clean maintenance item" + desc = "This is a random clean maintenance item." + icon = 'icons/obj/items/gift_wrapped.dmi' + icon_state = "gift_2" + +/obj/random/maintenance/clean/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/tech_supply = 100, + /obj/random/medical/lite = 80, + /obj/random/technology_scanner = 80, + /obj/random/bomb_supply = 80, + /obj/random/snack = 60, + /obj/random/powercell = 50, + /obj/random/advdevice = 50, + /obj/random/medical = 40, + /obj/random/material = 40, + /obj/random/smokes = 30, + /obj/random/storage = 30, + /obj/random/clothing = 30, + /obj/random/firstaid = 20, + /obj/random/toy = 20, + /obj/random/tank = 20, + /obj/random/shoes = 20, + /obj/random/glasses = 20, + /obj/random/suit = 20, + /obj/random/accessory = 20, + /obj/random/cash = 10, + /obj/random/masks = 10, + /obj/random/gloves = 10, + /obj/random/hat = 10, + /obj/random/coin = 5, + /obj/random/soap = 5, + /obj/random/drinkbottle = 5, + /obj/random/action_figure = 2, + /obj/random/plushie = 2, + /obj/random/contraband = 1, + /obj/random/loot = 1 + ) + return spawnable_choices + +/obj/random/maintenance/research +/*Maintenance loot list. This one is for around medical areas*/ + name = "random research maintenance item" + desc = "This is a random research maintenance item." + +/obj/random/maintenance/research/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/maintenance/clean = 320, + /obj/item/backpack/toxins = 10, + /obj/item/clothing/glasses/science = 4, + /obj/item/clothing/suit/toggle/labcoat = 4, + /obj/item/clothing/suit/toggle/labcoat/science = 4, + /obj/item/clothing/jumpsuit/white = 4, + /obj/item/clothing/glasses/material = 3, + /obj/item/scanner/plant = 3, + /obj/item/box/beakers = 3, + /obj/item/box/syringes = 3, + /obj/item/box/gloves = 3, + /obj/item/chems/glass/bucket = 2, + /obj/item/assembly/prox_sensor = 2, + /obj/item/excavation = 2, + /obj/item/clothing/gloves/latex = 2, + /obj/item/flash/synthetic = 1, + /obj/item/cell/gun = 1, + /obj/item/backpack/holding = 1, + /obj/item/clothing/head/beret/purple = 1, + /obj/item/clothing/head/bio_hood/scientist = 1, + /obj/item/clothing/suit/bio_suit/scientist = 1 + ) + return spawnable_choices + +/obj/random/maintenance/engineering +/*Maintenance loot list. This one is for around medical areas*/ + name = "random engineering maintenance item" + desc = "This is a random engineering maintenance item." + +/obj/random/maintenance/engineering/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/maintenance/clean = 320, + /obj/item/backpack/industrial = 5, + /obj/item/backpack/satchel/eng = 5, + /obj/item/backpack/messenger/engi = 5, + /obj/item/box = 5, + /obj/item/clothing/suit/hazardvest = 4, + /obj/item/clothing/mask/gas/half = 3, + /obj/item/belt/utility = 3, + /obj/item/clothing/head/soft/yellow = 3, + /obj/item/clothing/shoes/workboots = 3, + /obj/item/clothing/head/earmuffs = 3, + /obj/item/backpack/dufflebag/eng = 3, + /obj/item/flashlight/maglight = 2, + /obj/item/clothing/mask/balaclava = 2, + /obj/item/briefcase/inflatable = 2, + /obj/item/belt/utility/full = 2, + /obj/item/clothing/webbing/vest/black = 2, + /obj/item/clothing/suit/apron/overalls/laborer = 2, + /obj/item/clothing/webbing/vest/brown = 2, + /obj/item/handcuffs = 2, + /obj/item/clothing/mask/bandana/orange = 2, + /obj/item/clothing/head/hardhat/dblue = 2, + /obj/item/clothing/head/hardhat/orange = 2, + /obj/item/clothing/head/welding = 2, + /obj/item/clothing/glasses/welding = 1, + /obj/item/clothing/shoes/magboots = 1, + /obj/item/beartrap = 1, + /obj/item/clothing/webbing/drop_pouches/brown = 1 + ) + return spawnable_choices + +/obj/random/maintenance/cargo +/*Maintenance loot list. This one is for around cargo areas*/ + name = "random cargo maintenance item" + desc = "This is a random cargo maintenance item." + +/obj/random/maintenance/cargo/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/maintenance/clean = 320, + /obj/item/backpack/industrial = 5, + /obj/item/backpack/satchel = 5, + /obj/item/tool/pickaxe = 4, + /obj/item/chems/toner_cartridge = 4, + /obj/item/clothing/suit/hazardvest = 4, + /obj/item/clothing/suit/apron = 4, + /obj/item/clothing/suit/apron/overalls = 3, + /obj/item/clothing/head/earmuffs = 3, + /obj/item/backpack/dufflebag = 3, + /obj/item/flashlight/lantern = 3, + /obj/item/clothing/glasses/material = 3, + /obj/item/clothing/head/soft/yellow = 3, + /obj/item/clothing/shirt/syndicate/tacticool = 2, + /obj/item/clothing/webbing/vest/black = 2, + /obj/item/clothing/webbing/vest/brown = 2, + /obj/item/handcuffs = 2, + /obj/item/belt/utility = 2, + /obj/item/backpack/dufflebag/syndie/ammo = 1, + /obj/item/toolbox/syndicate = 1, + /obj/item/belt/utility/full = 1, + /obj/item/destTagger = 1, + /obj/item/clothing/shirt/syndicate/combat = 1, + /obj/item/beartrap = 1 + ) + return spawnable_choices + +/obj/random/maintenance/medical +/*Maintenance loot list. This one is for around medical areas*/ + name = "random medical maintenance item" + desc = "This is a random medical maintenance item." + +/obj/random/maintenance/medical/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/maintenance/clean = 320, + /obj/random/medical/lite = 25, + /obj/item/backpack/medic = 5, + /obj/item/backpack/satchel/med = 5, + /obj/item/backpack/messenger/med = 5, + /obj/item/clothing/gloves = 5, + /obj/item/clothing/suit/toggle/labcoat = 4, + /obj/item/clothing/shoes/color/white = 3, + /obj/item/backpack/dufflebag/med = 3, + /obj/item/box/beakers = 3, + /obj/item/box/syringes = 3, + /obj/item/box/gloves = 3, + /obj/item/clothing/mask/breath/medical = 2, + /obj/item/clothing/mask/surgical = 2, + /obj/item/box/bodybags = 2, + /obj/item/box/autoinjectors = 2, + /obj/item/clothing/gloves/latex/nitrile = 2, + /obj/item/belt/medical/emt = 2, + /obj/item/belt/medical = 2, + /obj/item/clothing/jumpsuit/medical/paramedic = 2, + /obj/item/clothing/webbing/vest/black = 2, + /obj/item/clothing/webbing/vest = 2, + /obj/item/clothing/neck/stethoscope = 2, + /obj/item/clothing/glasses/hud/health = 2, + /obj/item/backpack/dufflebag/syndie/med = 1, + /obj/item/clothing/shoes/jackboots/swat/combat = 1, + /obj/item/clothing/glasses/hud/health/prescription = 1, + /obj/item/clothing/head/bio_hood/virology = 1, + /obj/item/clothing/suit/bio_suit/general = 1, + /obj/item/clothing/webbing/drop_pouches/white = 1, + /obj/item/clothing/webbing/drop_pouches/black = 1 + ) + return spawnable_choices + +/obj/random/maintenance/security +/*Maintenance loot list. This one is for around security areas*/ + name = "random security maintenance item" + desc = "This is a random security maintenance item." + +/obj/random/maintenance/security/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/maintenance/clean = 320, + /obj/item/clothing/head/soft/sec = 4, + /obj/item/backpack/security = 3, + /obj/item/backpack/satchel/sec = 3, + /obj/item/clothing/shoes/jackboots = 3, + /obj/item/clothing/suit/armor/vest = 3, + /obj/item/flashlight/maglight = 2, + /obj/item/flash = 2, + /obj/item/clothing/mask/balaclava = 2, + /obj/item/backpack/messenger/sec = 2, + /obj/item/backpack/dufflebag/sec = 2, + /obj/item/box/swabs = 2, + /obj/item/belt/security = 2, + /obj/item/clothing/glasses/hud/security = 2, + /obj/item/clothing/head/helmet = 2, + /obj/item/clothing/webbing/drop_pouches/black = 2, + /obj/item/clothing/head/earmuffs = 2, + /obj/item/handcuffs = 2, + /obj/item/clothing/webbing/holster/thigh = 1, + /obj/item/cell/gun = 1, + /obj/item/clothing/mask/gas/swat = 1, + /obj/item/clothing/mask/gas/syndicate = 1, + /obj/item/clothing/mask/balaclava/tactical = 1, + /obj/item/backpack/dufflebag/syndie/ammo = 1, + /obj/item/backpack/dufflebag/syndie/med = 1, + /obj/item/grenade/flashbang = 1, + /obj/item/baton = 1, + /obj/item/chems/spray/pepper = 1, + /obj/item/clothing/shoes/jackboots/swat = 1, + /obj/item/clothing/shoes/jackboots/swat/combat = 1, + /obj/item/clothing/gloves/thick/swat = 1, + /obj/item/clothing/gloves/thick/combat = 1, + /obj/item/clothing/glasses/sunglasses/big = 1, + /obj/item/clothing/glasses/sunglasses/sechud = 1, + /obj/item/clothing/glasses/sunglasses/sechud/toggle = 1, + /obj/item/clothing/glasses/sunglasses/sechud = 1, + /obj/item/clothing/webbing/holster/hip = 1, + /obj/item/clothing/webbing/holster/waist = 1, + /obj/item/clothing/webbing/holster/armpit = 1 + ) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/medical.dm b/code/game/objects/random/subtypes/medical.dm new file mode 100644 index 000000000000..fcf7dc9c7506 --- /dev/null +++ b/code/game/objects/random/subtypes/medical.dm @@ -0,0 +1,87 @@ +/obj/random/medical + name = "Random Medical equipment" + desc = "This is a random medical item." + icon = 'icons/obj/items/random_spawn.dmi' + icon_state = "medrandom" + +/obj/random/medical/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/medical/lite = 21, + /obj/item/bodybag = 2, + /obj/item/chems/glass/bottle/stabilizer = 2, + /obj/item/chems/glass/bottle/antitoxin = 2, + /obj/item/pill_bottle = 2, + /obj/item/pill_bottle/painkillers = 2, + /obj/item/pill_bottle/strong_painkillers = 1, + /obj/item/pill_bottle/antidepressants = 2, + /obj/item/pill_bottle/oxygen = 1, + /obj/item/pill_bottle/burn_meds = 1, + /obj/item/pill_bottle/brute_meds = 1, + /obj/item/chems/syringe/antitoxin = 2, + /obj/item/chems/syringe/antibiotic = 1, + /obj/item/chems/syringe/stabilizer = 2, + /obj/item/box/freezer = 1, + /obj/item/stack/nanopaste = 1 + ) + return spawnable_choices + +/obj/random/medical/lite + name = "Random Medicine" + desc = "This is a random simple medical item." + icon = 'icons/obj/items/random_spawn.dmi' + icon_state = "medrandom" + spawn_nothing_percentage = 25 + +/obj/random/medical/lite/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/stack/medical/bandage = 4, + /obj/item/stack/medical/ointment = 4, + /obj/item/pill_bottle/antibiotics = 2, + /obj/item/pill_bottle/painkillers = 2, + /obj/item/pill_bottle/strong_painkillers = 1, + /obj/item/stack/medical/bandage/advanced = 2, + /obj/item/stack/medical/ointment/advanced = 2, + /obj/item/stack/medical/splint = 1, + /obj/item/chems/hypospray/autoinjector/stabilizer = 3, + /obj/item/pill_bottle/burn_meds = 2, + /obj/item/pill_bottle/antitoxins = 2, + /obj/item/med_pouch/trauma = 2, + /obj/item/med_pouch/burn = 2, + /obj/item/med_pouch/toxin = 2, + /obj/item/med_pouch/radiation = 2, + /obj/item/med_pouch/oxyloss = 2 + ) + return spawnable_choices + +/obj/random/medical/pillbottle + name = "Random Pill Bottle" + desc = "This is a random pill bottle." + +/obj/random/medical/pillbottle/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/pill_bottle/antibiotics, + /obj/item/pill_bottle/oxygen, + /obj/item/pill_bottle/brute_meds, + /obj/item/pill_bottle/sugariron + ) + return spawnable_choices + +/obj/random/firstaid + name = "Random First Aid Kit" + desc = "This is a random first aid kit." + icon = 'icons/obj/items/storage/firstaid.dmi' + icon_state = "firstaid" + +/obj/random/firstaid/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/firstaid/regular = 4, + /obj/item/firstaid/trauma = 3, + /obj/item/firstaid/toxin = 3, + /obj/item/firstaid/o2 = 3, + /obj/item/firstaid/stab = 2, + /obj/item/firstaid/adv = 2, + /obj/item/firstaid/combat = 1, + /obj/item/firstaid/empty = 2, + /obj/item/firstaid/fire = 3 + ) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/misc.dm b/code/game/objects/random/subtypes/misc.dm new file mode 100644 index 000000000000..e341ccfc5334 --- /dev/null +++ b/code/game/objects/random/subtypes/misc.dm @@ -0,0 +1,647 @@ +/obj/random/contraband + name = "Random Illegal Item" + desc = "Hot Stuff." + icon = 'icons/obj/items/grooming/comb.dmi' + icon_state = ICON_STATE_WORLD + color = COLOR_PURPLE + spawn_nothing_percentage = 50 + +/obj/random/contraband/nofail + name = "guaranteed random illegal item" + spawn_nothing_percentage = 0 + +/obj/random/contraband/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/grooming/comb = 4, + /obj/item/pill_bottle/painkillers = 3, + /obj/item/pill_bottle/strong_painkillers = 1, + /obj/item/pill_bottle/happy = 2, + /obj/item/pill_bottle/zoom = 2, + /obj/item/chems/glass/beaker/vial/random/toxin = 1, + /obj/item/chems/glass/beaker/sulfuric = 1, + /obj/item/poster = 5, + /obj/item/butterflyblade = 3, + /obj/item/butterflyhandle = 3, + /obj/item/baton/cattleprod = 1, + /obj/item/knife/combat = 1, + /obj/item/knife/folding = 1, + /obj/item/knife/folding/wood = 1, + /obj/item/knife/folding/combat/balisong = 2, + /obj/item/knife/folding/combat/switchblade = 1, + /obj/item/secure_storage/briefcase/money = 1, + /obj/item/box/syndie_kit/cigarette = 1, + /obj/item/stack/telecrystal = 1, + /obj/item/clothing/shirt/syndicate = 2, + /obj/item/chems/syringe = 3, + /obj/item/chems/syringe/steroid = 2, + /obj/item/chems/syringe/drugs = 1, + /obj/item/food/egg/lizard = 3 + ) + return spawnable_choices + +/obj/random/drinkingglass + name = "random drinking glass" + desc = "This is a random drinking glass." + icon = 'icons/obj/drink_glasses/square.dmi' + icon_state = "square" + +/obj/random/drinkingglass/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/drinks/glass2/square, + /obj/item/chems/drinks/glass2/rocks, + /obj/item/chems/drinks/glass2/shake, + /obj/item/chems/drinks/glass2/cocktail, + /obj/item/chems/drinks/glass2/shot, + /obj/item/chems/drinks/glass2/pint, + /obj/item/chems/drinks/glass2/mug, + /obj/item/chems/drinks/glass2/wine + ) + return spawnable_choices + +/obj/random/mug + name = "random coffee cup" + desc = "A random coffee cup/mug." + icon = 'icons/obj/drink_glasses/coffecup.dmi' + icon_state = "coffeecup" + +/obj/random/mug/spawn_choices() + var/static/list/spawnable_choices = typesof(/obj/item/chems/drinks/glass2/coffeecup) - /obj/item/chems/drinks/glass2/coffeecup/custom + return spawnable_choices + +/obj/random/drinkbottle + name = "random drink" + desc = "This is a random drink." + icon = 'icons/obj/drinks.dmi' + icon_state = "whiskeybottle" + +/obj/random/drinkbottle/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/chems/drinks/bottle/whiskey, + /obj/item/chems/drinks/bottle/gin, + /obj/item/chems/drinks/bottle/agedwhiskey, + /obj/item/chems/drinks/bottle/vodka, + /obj/item/chems/drinks/bottle/tequila, + /obj/item/chems/drinks/bottle/absinthe, + /obj/item/chems/drinks/bottle/wine, + /obj/item/chems/drinks/bottle/cognac, + /obj/item/chems/drinks/bottle/rum, + /obj/item/chems/drinks/bottle/patron + ) + return spawnable_choices + +/obj/random/useful + name = "random useful item" + desc = "This is a random useful item." + icon = 'icons/obj/items/storage/trashbag.dmi' + icon_state = "trashbag3" + +/obj/random/useful/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/crayon, + /obj/item/pen, + /obj/item/pen/blue, + /obj/item/pen/red, + /obj/item/pen/multi, + /obj/item/box/matches, + /obj/item/stack/material/cardstock/mapped/cardboard, + /obj/item/box/fancy/cigarettes, + /obj/item/deck/cards + ) + return spawnable_choices + +/obj/random/natural_debris // Natural crap that you might fish out of a river in unspoiled countryside. + name = "random natural detritus" + icon = 'icons/effects/blood.dmi' + icon_state = "remains" + +// We really have a limited amount of random crap, don't we... +/obj/random/natural_debris/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/remains/mouse, + /obj/item/remains/lizard, + /obj/item/stick, + /obj/item/trash/mollusc_shell, + /obj/item/trash/mollusc_shell/clam, + /obj/item/trash/mollusc_shell/barnacle + ) + return spawnable_choices + +/obj/random/junk //Broken items, or stuff that could be picked up + name = "random junk" + desc = "This is some random junk." + icon = 'icons/obj/items/storage/trashbag.dmi' + icon_state = "trashbag3" + +/obj/random/junk/spawn_choices() + var/static/list/spawnable_choices + if(!spawnable_choices) + spawnable_choices = list( + /obj/effect/decal/cleanable/generic = 20, + /obj/effect/decal/cleanable/spiderling_remains = 95, + /obj/item/remains/mouse = 95, + /obj/item/remains/robot = 95, + /obj/item/paper/crumpled = 95, + /obj/item/inflatable/torn = 95, + /obj/effect/decal/cleanable/molten_item = 95, + /obj/item/shard = 95, + /obj/item/hand/missing_card = 95, + /obj/random/useful = 4 + ) + for(var/trash_type in subtypesof(/obj/item/trash)) + spawnable_choices[trash_type] = 95 + for(var/trash_type in typesof(/obj/item/trash/cigbutt)) + spawnable_choices[trash_type] = 95 + spawnable_choices -= /obj/item/trash/snack_bowl + spawnable_choices -= /obj/item/trash/syndi_cakes + var/lunches = lunchables_lunches() + for(var/lunch in lunches) + spawnable_choices[lunches[lunch]] = 1 + return spawnable_choices + +/obj/random/trash //Mostly remains and cleanable decals. Stuff a janitor could clean up + name = "random trash" + desc = "This is some random trash." + icon = 'icons/effects/effects.dmi' + icon_state = "greenglow" + +/obj/random/trash/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/remains/lizard, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/blood/oil, + /obj/effect/decal/cleanable/blood/oil/streak, + /obj/effect/decal/cleanable/spiderling_remains, + /obj/item/remains/mouse, + /obj/effect/decal/cleanable/vomit, + /obj/effect/decal/cleanable/blood/splatter, + /obj/effect/decal/cleanable/ash, + /obj/effect/decal/cleanable/generic, + /obj/effect/decal/cleanable/flour, + /obj/effect/decal/cleanable/filth, + /obj/effect/decal/cleanable/dirt/visible, + /obj/item/remains/robot + ) + return spawnable_choices + +/obj/random/coin + name = "random coin" + desc = "This is a random coin." + icon = 'icons/obj/items/coin.dmi' + icon_state = "coin1" + +/obj/random/coin/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/coin/gold = 3, + /obj/item/coin/silver = 4, + /obj/item/coin/diamond = 2, + /obj/item/coin/iron = 4, + /obj/item/coin/uranium = 3, + /obj/item/coin/platinum = 1 + ) + return spawnable_choices + +/obj/random/material //Random materials for building stuff + name = "random material" + desc = "This is a random material." + icon = 'icons/obj/items/stacks/materials.dmi' + icon_state = "sheet" + +/obj/random/material/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/stack/material/sheet/mapped/steel/ten, + /obj/item/stack/material/pane/mapped/glass/ten, + /obj/item/stack/material/pane/mapped/rglass/ten, + /obj/item/stack/material/panel/mapped/plastic/ten, + /obj/item/stack/material/plank/mapped/wood/ten, + /obj/item/stack/material/cardstock/mapped/cardboard/ten, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten, + /obj/item/stack/material/sheet/mapped/steel/fifty, + /obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, + /obj/item/stack/material/ingot/mapped/copper/fifty, + /obj/item/stack/material/pane/mapped/glass/fifty, + /obj/item/stack/material/pane/mapped/rglass/fifty, + /obj/item/stack/material/panel/mapped/plastic/fifty, + /obj/item/stack/material/plank/mapped/wood/fifty, + /obj/item/stack/material/cardstock/mapped/cardboard/fifty, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, + /obj/item/stack/material/rods/mapped/steel/ten, + /obj/item/stack/material/rods/mapped/steel/fifty + ) + return spawnable_choices + +/obj/random/soap + name = "Random Cleaning Supplies" + desc = "This is a random bar of soap. Soap! SOAP?! SOAP!!!" + icon = 'icons/obj/items/random_spawn.dmi' + icon_state = "soaprandom" + +/obj/random/soap/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/soap = 12, + /obj/item/chems/rag = 2, + /obj/item/chems/spray/cleaner = 2, + /obj/item/grenade/chem_grenade/cleaner = 1 + ) + return spawnable_choices + +/obj/random/obstruction //Large objects to block things off in maintenance + name = "random obstruction" + desc = "This is a random obstruction." + icon = 'icons/obj/cult.dmi' + icon_state = "cultgirder" + +/obj/random/obstruction/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/structure/barricade, + /obj/structure/girder, + /obj/structure/girder/displaced, + /obj/structure/grille, + /obj/structure/grille/broken, + /obj/structure/foamedmetal, + /obj/item/caution, + /obj/item/caution/cone, + /obj/structure/inflatable/wall, + /obj/structure/inflatable/door + ) + return spawnable_choices + +/obj/random/smokes + name = "random smokeable" + desc = "This is a random smokeable item." + icon = 'icons/obj/items/storage/cigpack/acme.dmi' + icon_state = "Bpacket" + +/obj/random/smokes/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/box/fancy/cigarettes = 5, + /obj/item/box/fancy/cigarettes/dromedaryco = 4, + /obj/item/box/fancy/cigarettes/killthroat = 1, + /obj/item/box/fancy/cigarettes/luckystars = 3, + /obj/item/box/fancy/cigarettes/jerichos = 3, + /obj/item/box/fancy/cigarettes/menthols = 2, + /obj/item/box/fancy/cigarettes/carcinomas = 3, + /obj/item/box/fancy/cigarettes/professionals = 2, + /obj/item/box/fancy/cigar = 1, + /obj/item/clothing/mask/smokable/cigarette = 2, + /obj/item/clothing/mask/smokable/cigarette/menthol = 2, + /obj/item/clothing/mask/smokable/cigarette/cigar = 1, + /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba = 1, + /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 1 + ) + return spawnable_choices + +/obj/random/storage + name = "random storage item" + desc = "This is a storage item." + icon = 'icons/obj/items/storage/box.dmi' + icon_state = "idOld" + +/obj/random/storage/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/secure_storage/briefcase = 2, + /obj/item/briefcase = 4, + /obj/item/briefcase/inflatable = 3, + /obj/item/backpack = 5, + /obj/item/backpack/satchel = 5, + /obj/item/backpack/dufflebag = 2, + /obj/item/box = 5, + /obj/item/box/donkpockets = 3, + /obj/item/box/sinpockets = 1, + /obj/item/box/fancy/donut = 2, + /obj/item/box/cups = 3, + /obj/item/box/mousetraps = 4, + /obj/item/box/engineer = 3, + /obj/item/box/autoinjectors = 2, + /obj/item/box/beakers = 3, + /obj/item/box/syringes = 3, + /obj/item/box/gloves = 3, + /obj/item/box/large = 2, + /obj/item/box/glowsticks = 3, + /obj/item/wallet = 1, + /obj/item/ore_satchel = 2, + /obj/item/belt/utility/full = 2, + /obj/item/belt/medical/emt = 2, + /obj/item/belt/medical = 2, + /obj/item/belt/holster/security = 2, + /obj/item/belt/holster/security/tactical = 1 + ) + return spawnable_choices + +/obj/random/cash + name = "random currency" + desc = "LOADSAMONEY!" + icon = 'icons/obj/items/money.dmi' + icon_state = "cash" + +/obj/random/cash/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/cash/c1 = 4, + /obj/item/cash/c10 = 3, + /obj/item/cash/c20 = 3, + /obj/item/cash/c50 = 2, + /obj/item/cash/c100 = 2, + /obj/item/cash/c1000 = 1 + ) + return spawnable_choices + +/obj/random/loot /*Better loot for away missions and salvage */ + name = "random loot" + desc = "This is some random loot." + icon = 'icons/obj/items/gift_wrapped.dmi' + icon_state = "gift_3" + +/obj/random/loot/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/energy = 10, + /obj/random/projectile = 10, + /obj/random/voidhelmet = 10, + /obj/random/voidsuit = 10, + /obj/random/hardsuit = 10, + /obj/item/clothing/mask/gas/syndicate = 10, + /obj/item/clothing/mask/muzzle = 7, + /obj/item/clothing/glasses/night = 3, + /obj/item/clothing/glasses/thermal = 1, + /obj/item/clothing/glasses/welding/superior = 7, + /obj/item/clothing/head/collectable/petehat = 4, + /obj/item/clothing/suit/armor/pcarrier/merc = 3, + /obj/item/clothing/suit/straight_jacket = 6, + /obj/item/clothing/head/helmet/merc = 3, + /obj/item/stack/material/gemstone/mapped/diamond/ten = 7, + /obj/item/stack/material/pane/mapped/rborosilicate/ten = 7, + /obj/item/stack/material/brick/mapped/marble/ten = 8, + /obj/item/stack/material/ingot/mapped/gold/ten = 7, + /obj/item/stack/material/ingot/mapped/silver/ten = 7, + /obj/item/stack/material/ingot/mapped/osmium/ten = 7, + /obj/item/stack/material/ingot/mapped/platinum/ten = 8, + /obj/item/stack/material/aerogel/mapped/tritium/ten = 7, + /obj/item/stack/material/segment/mapped/mhydrogen/ten = 6, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten = 9, + /obj/item/stack/material/ingot/mapped/copper/ten = 8, + /obj/item/box/animal_cubes/monkeys = 5, + /obj/item/firstaid/surgery = 4, + /obj/item/cell/infinite = 1, + /obj/random/archaeological_find = 2, + /obj/item/multitool/hacktool = 2, + /obj/item/surgicaldrill = 7, + /obj/item/sutures = 7, + /obj/item/retractor = 7, + /obj/item/hemostat = 7, + /obj/item/cautery = 7, + /obj/item/bonesetter = 7, + /obj/item/bonegel = 7, + /obj/item/circular_saw = 7, + /obj/item/scalpel = 7, + /obj/item/baton/loaded = 9, + /obj/item/radio/headset/hacked = 6 + ) + return spawnable_choices + +/obj/random/vendor + name = "random vending machine" + desc = "This is a randomly selected vending machine." + icon = 'icons/obj/machines/vending/coffee.dmi' + icon_state = "world-hellfire" + abstract_type = /obj/random/vendor + +/obj/random/vendor/food + name = "random food vending machine" + +/obj/random/vendor/food/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/machinery/vending/weeb, + /obj/machinery/vending/sol, + /obj/machinery/vending/snix, + /obj/machinery/vending/snack + ) + return spawnable_choices + + +/obj/random/vendor/drink + name = "random drink vending machine" + +/obj/random/vendor/drink/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/machinery/vending/coffee, + /obj/machinery/vending/cola + ) + return spawnable_choices + +/obj/random/lipstick + name = "random lipstick" + desc = "This is a tube of lipstick." + icon = 'icons/obj/items/cosmetics/lipstick.dmi' + icon_state = "lipstick_closed" + +/obj/random/lipstick/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/cosmetics/lipstick/red, + /obj/item/cosmetics/lipstick/blue, + /obj/item/cosmetics/lipstick/green, + /obj/item/cosmetics/lipstick/turquoise, + /obj/item/cosmetics/lipstick/violet, + /obj/item/cosmetics/lipstick/yellow, + /obj/item/cosmetics/lipstick/orange, + /obj/item/cosmetics/lipstick/white, + /obj/item/cosmetics/lipstick/black + ) + return spawnable_choices + +/obj/random/eyeshadow + name = "random eyeshadow" + desc = "This is a tube of eyeshadow." + icon = 'icons/obj/items/cosmetics/eyeshadow.dmi' + icon_state = "eyeshadow_closed" + +/obj/random/eyeshadow/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/cosmetics/eyeshadow/red, + /obj/item/cosmetics/eyeshadow/blue, + /obj/item/cosmetics/eyeshadow/green, + /obj/item/cosmetics/eyeshadow/turquoise, + /obj/item/cosmetics/eyeshadow/violet, + /obj/item/cosmetics/eyeshadow/yellow, + /obj/item/cosmetics/eyeshadow/orange, + /obj/item/cosmetics/eyeshadow/white, + /obj/item/cosmetics/eyeshadow/black + ) + return spawnable_choices + +/obj/random/makeup + name = "random makeup" + desc = "This is a tube of makeup." + icon = 'icons/obj/items/cosmetics/lipstick.dmi' + icon_state = "lipstick_closed" + +/obj/random/makeup/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/cosmetics/lipstick/red, + /obj/item/cosmetics/lipstick/blue, + /obj/item/cosmetics/lipstick/green, + /obj/item/cosmetics/lipstick/turquoise, + /obj/item/cosmetics/lipstick/violet, + /obj/item/cosmetics/lipstick/yellow, + /obj/item/cosmetics/lipstick/orange, + /obj/item/cosmetics/lipstick/white, + /obj/item/cosmetics/lipstick/black, + /obj/item/cosmetics/eyeshadow/red, + /obj/item/cosmetics/eyeshadow/blue, + /obj/item/cosmetics/eyeshadow/green, + /obj/item/cosmetics/eyeshadow/turquoise, + /obj/item/cosmetics/eyeshadow/violet, + /obj/item/cosmetics/eyeshadow/yellow, + /obj/item/cosmetics/eyeshadow/orange, + /obj/item/cosmetics/eyeshadow/white, + /obj/item/cosmetics/eyeshadow/black + ) + return spawnable_choices + +/obj/random/umbrella + name = "Random Umbrella" + desc = "This is a random umbrella." + icon = 'icons/obj/items/umbrella.dmi' + icon_state = "map" + color = COLOR_GRAY20 + +/obj/random/umbrella/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/umbrella, + /obj/item/umbrella/blue, + /obj/item/umbrella/green, + /obj/item/umbrella/red, + /obj/item/umbrella/yellow, + /obj/item/umbrella/orange, + /obj/item/umbrella/purple + ) + return spawnable_choices + +/obj/random/single/playing_cards + name = "randomly spawned deck of cards" + icon = 'icons/obj/items/playing_cards.dmi' + icon_state = "deck" + spawn_object = /obj/item/deck + +/obj/random/single/lighter + name = "randomly spawned lighter" + icon = 'icons/obj/items/flame/lighter.dmi' + icon_state = ICON_STATE_WORLD + spawn_object = /obj/item/flame/fuelled/lighter + +/obj/random/jewelry + name = "Random Jewelry" + desc = "Shiny things." + icon = 'icons/obj/items/grooming/comb.dmi' + icon_state = ICON_STATE_WORLD + color = COLOR_GOLD + +/obj/random/jewelry/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clothing/ears/stud/wood = 10, + /obj/item/clothing/ears/dangle/wood = 10, + /obj/item/clothing/gloves/bracelet = 10, + /obj/item/clothing/neck/necklace = 10, + /obj/item/clothing/gloves/ring/silver = 5, + /obj/item/clothing/gloves/ring/bronze = 5, + /obj/item/clothing/gloves/ring/gold = 3, + /obj/item/clothing/ears/stud/silver = 3, + /obj/item/clothing/ears/dangle/silver = 3, + /obj/item/clothing/ears/stud/gold = 3, + /obj/item/clothing/ears/dangle/gold = 3, + /obj/item/clothing/gloves/ring/platinum = 1, + /obj/item/clothing/ears/stud/platinum = 1, + /obj/item/clothing/ears/dangle/platinum = 1, + /obj/item/clothing/ears/stud/diamond = 1, + /obj/item/clothing/ears/dangle/diamond = 1 + + ) + return spawnable_choices + +/obj/random/ore_pile + name = "random ore pile" + desc = "A pile of random ores. High chance of a larger pile of common ores, lower chances of small piles of rarer ores." + +/obj/random/ore_pile/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/stack/material/ore/handful/sand/fifteen = 15, + /obj/item/stack/material/ore/bauxite/ten = 10, + /obj/item/stack/material/ore/coal/ten = 10, + /obj/item/stack/material/ore/tetrahedrite/ten = 10, + /obj/item/stack/material/ore/iron/ten = 10, + /obj/item/stack/material/ore/galena/ten = 10, + /obj/item/stack/material/lump/large/marble/five = 5, + /obj/item/stack/material/ore/gold/five = 5, + /obj/item/stack/material/ore/diamond/three = 3, + /obj/item/stack/material/ore/osmium/three = 3, + /obj/item/stack/material/ore/hydrogen/two = 2, + /obj/item/stack/material/ore/rutile/five = 5, + /obj/item/stack/material/ore/silver/five = 3, + /obj/item/stack/material/ore/uranium/three = 2 + ) + return spawnable_choices + +/obj/random/meat + name = "random meat" + icon = /obj/item/food/butchery/meat/beef::icon + icon_state = /obj/item/food/butchery/meat/beef::icon_state + color = /obj/item/food/butchery/meat/beef::color + +/obj/random/meat/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/food/butchery/meat/beef, + /obj/item/food/butchery/meat/goat, + /obj/item/food/butchery/meat/chicken, + /obj/item/food/butchery/meat/corgi, + /obj/item/food/butchery/meat/bear, + /obj/item/food/butchery/meat/fish/shark, + /obj/item/food/butchery/meat/fish/carp, + /obj/item/food/butchery/meat/fish/octopus, + /obj/item/food/butchery/meat/fish/mollusc + ) + return spawnable_choices + +/obj/random/mouseremains + name = "random mouseremains" + desc = "For use with mouse spawners." + icon = /obj/item/assembly/mousetrap::icon + icon_state = /obj/item/assembly/mousetrap::icon_state + +/obj/random/mouseremains/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/assembly/mousetrap, + /obj/item/assembly/mousetrap/armed, + /obj/effect/decal/cleanable/spiderling_remains, + /obj/effect/decal/cleanable/ash, + /obj/item/trash/cigbutt, + /obj/item/trash/cigbutt/cigarbutt, + /obj/item/remains/mouse + ) + return spawn_choices + +/obj/random/pizzabox + name = "random pizza" + icon = /obj/item/pizzabox::icon + icon_state = /obj/item/pizzabox::icon_state + +/obj/random/pizzabox/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/pizzabox/vegetable, + /obj/item/pizzabox/mushroom, + /obj/item/pizzabox/meat, + /obj/item/pizzabox/margherita + ) + return spawn_choices + +/obj/random/dufflebag + name = "random dufflebag" + icon = /obj/item/backpack/dufflebag::icon + icon_state = /obj/item/backpack/dufflebag::icon_state + +/obj/random/dufflebag/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/backpack/dufflebag = 10, + /obj/item/backpack/dufflebag/med = 10, + /obj/item/backpack/dufflebag/sec = 10, + /obj/item/backpack/dufflebag/eng = 10, + /obj/item/backpack/dufflebag/captain = 5, + /obj/item/backpack/dufflebag/syndie = 1 + ) + return spawn_choices diff --git a/code/game/objects/random/subtypes/mobs.dm b/code/game/objects/random/subtypes/mobs.dm new file mode 100644 index 000000000000..d26977a5bf19 --- /dev/null +++ b/code/game/objects/random/subtypes/mobs.dm @@ -0,0 +1,74 @@ +/obj/random/mouse + name = "Random Mouse" + desc = "This is a random boring maus." + icon = 'icons/mob/simple_animal/mouse_gray.dmi' + icon_state = "world-resting" + spawn_nothing_percentage = 15 + +/obj/random/mouse/spawn_choices() + var/static/list/spawnable_choices = list( + /mob/living/simple_animal/passive/mouse/brown = 30, + /mob/living/simple_animal/passive/mouse/gray = 30, + /mob/living/simple_animal/passive/mouse/white = 15 + ) + return spawnable_choices + +/obj/random/hostile + name = "Random Hostile Mob" + desc = "This is a random hostile mob." + icon = 'icons/mob/amorph.dmi' + icon_state = "standing" + spawn_nothing_percentage = 80 + +/obj/random/hostile/spawn_choices() + var/static/list/spawnable_choices = list( + /mob/living/simple_animal/hostile/viscerator = 20, + /mob/living/simple_animal/hostile/carp = 10, + /mob/living/simple_animal/hostile/carp/pike = 5, + /mob/living/simple_animal/hostile/vagrant/swarm = 1 + ) + return spawnable_choices + +/obj/random/hostile/dungeon + name = "Random Hostile Dungeon Mob" + spawn_nothing_percentage = 5 + +/obj/random/hostile/dungeon/spawn_choices() + var/static/list/spawnable_choices = list( + /mob/living/simple_animal/hostile/revenant + ) + return spawnable_choices + +/obj/random/hostile/cave + name = "Random Hostile Cave Mob" + spawn_nothing_percentage = 5 + +/obj/random/hostile/cave/spawn_choices() + var/static/list/spawnable_choices = list( + /mob/living/simple_animal/hostile/giant_spider/guard/cave = 1, + /mob/living/simple_animal/hostile/scarybat/cave = 4 + ) + return spawnable_choices + +/obj/random/hostile/hivebot + name = "Random Hivebot" + icon = /mob/living/simple_animal/hostile/hivebot::icon + icon_state = /mob/living/simple_animal/hostile/hivebot::icon_state + +/obj/random/hostile/hivebot/spawn_choices() + var/static/list/spawnable_choices = typesof(/mob/living/simple_animal/hostile/hivebot) + return spawnable_choices + +/obj/random/hostile/hivebot/melee + name = "Random Melee Hivebot" + +/obj/random/hostile/hivebot/melee/spawn_choices() + var/static/list/spawnable_choices = typesof(/mob/living/simple_animal/hostile/hivebot/melee) + return spawnable_choices + +/obj/random/hostile/hivebot/ranged + name = "Random Ranged Hivebot" + +/obj/random/hostile/hivebot/ranged/spawn_choices() + var/static/list/spawnable_choices = typesof(/mob/living/simple_animal/hostile/hivebot/ranged) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/multi.dm b/code/game/objects/random/subtypes/multi.dm new file mode 100644 index 000000000000..ca95e015af2c --- /dev/null +++ b/code/game/objects/random/subtypes/multi.dm @@ -0,0 +1,21 @@ +/proc/generate_multi_spawn_items() + for(var/id in multi_point_spawns) + var/list/spawn_points = multi_point_spawns[id] + var/obj/random_multi/rm = pickweight(spawn_points) + rm.generate_items() + QDEL_LIST(spawn_points) + LAZYCLEARLIST(multi_point_spawns) + +/obj/random_multi/single_item + var/item_path // Item type to spawn + var/spawn_nothing_chance = 0 /// Chance to spawn nothing. + +/obj/random_multi/single_item/generate_items() + if(prob(spawn_nothing_chance)) + return + new item_path(loc) + +/obj/random_multi/single_item/captains_spare_id + name = "Multi Point - Captain's Spare" + id = "Captain's spare id" + item_path = /obj/item/card/id/captains_spare diff --git a/code/game/objects/random/subtypes/paperwork.dm b/code/game/objects/random/subtypes/paperwork.dm new file mode 100644 index 000000000000..a073a9d95067 --- /dev/null +++ b/code/game/objects/random/subtypes/paperwork.dm @@ -0,0 +1,42 @@ +/obj/random/single/textbook + name = "random textbook" + icon = 'icons/obj/items/books/book.dmi' + icon_state = ICON_STATE_WORLD + spawn_object = /obj/item/book/skill //Further randomization of which book is handled inside the book initialization + spawn_nothing_percentage = 0 + +/obj/random/crayon + name = "random crayon" + desc = "This is a random crayon." + icon = 'icons/obj/items/crayons.dmi' + icon_state = "crayonred" + +/obj/random/crayon/spawn_choices() + var/static/list/spawnable_choices = subtypesof(/obj/item/pen/crayon) + return spawnable_choices + +/obj/random/clipboard + name = "random clipboard" + desc = "This is a random material clipboard." + icon = 'icons/obj/items/clipboard.dmi' + icon_state = "clipboard" + +/obj/random/clipboard/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/clipboard = 300, + /obj/item/clipboard/steel = 200, + /obj/item/clipboard/aluminium = 200, + /obj/item/clipboard/plastic = 200, + /obj/item/clipboard/glass = 100, + /obj/item/clipboard/ebony = 10 + ) + return spawnable_choices + +/obj/random/documents // top secret documents, mostly overriden by maps + name = "random secret documents" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "docs_generic" + +/obj/random/documents/spawn_choices() + var/static/list/spawnable_choices = list(/obj/item/documents) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/plants.dm b/code/game/objects/random/subtypes/plants.dm new file mode 100644 index 000000000000..7b0595bf1d9c --- /dev/null +++ b/code/game/objects/random/subtypes/plants.dm @@ -0,0 +1,25 @@ +/obj/random/seaweed + name = "random seaweed" + desc = "This is some random seaweed." + icon = 'icons/obj/structures/plants.dmi' + icon_state = "seaweed" + +/obj/random/seaweed/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/structure/flora/seaweed = 3, + /obj/structure/flora/seaweed/mid = 3, + /obj/structure/flora/seaweed/large = 2, + /obj/structure/flora/seaweed/glow = 1 + ) + return spawnable_choices + +/obj/random/pottedplant + name = "random potted plant" + desc = "This is a random potted plant." + icon = 'icons/obj/structures/potted_plants.dmi' + icon_state = "plant-26" + spawn_nothing_percentage = 0 + +/obj/random/pottedplant/spawn_choices() + var/static/list/spawnable_choices = subtypesof(/obj/structure/flora/pottedplant) - list(/obj/structure/flora/pottedplant/unusual) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/salvage.dm b/code/game/objects/random/subtypes/salvage.dm new file mode 100644 index 000000000000..298557addcac --- /dev/null +++ b/code/game/objects/random/subtypes/salvage.dm @@ -0,0 +1,128 @@ +/obj/random/scrapped_gun + name = "random scrapped gun" + icon = /obj/item/gun/projectile/automatic/assault_rifle::icon + icon_state = /obj/item/gun/projectile/automatic/assault_rifle::icon_state + +/obj/random/scrapped_gun/spawn_choices() + var/static/list/spawn_choices = list( + /obj/random/scrapped_pistol = 10, + /obj/random/scrapped_smg = 5, + /obj/random/scrapped_laser = 5, + /obj/random/scrapped_shotgun = 3, + /obj/random/scrapped_ionrifle = 3, + /obj/random/scrapped_assault = 1, + /obj/random/scrapped_flechette = 1, + /obj/random/scrapped_grenadelauncher = 1, + /obj/random/scrapped_dartgun = 1 + ) + return spawn_choices + +/obj/random/scrapped_assault + name = "random scrapped assault rifle" + icon = /obj/item/gun/projectile/automatic/assault_rifle::icon + icon_state = /obj/item/gun/projectile/automatic/assault_rifle::icon_state + +/obj/random/scrapped_assault/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/ballistic/assault = 10, + /obj/item/gun/projectile/automatic/assault_rifle = 1 + ) + return spawn_choices + +/obj/random/scrapped_pistol + name = "random scrapped pistol" + icon = /obj/item/gun/projectile/pistol::icon + icon_state = /obj/item/gun/projectile/pistol::icon_state + +/obj/random/scrapped_pistol/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/ballistic/pistol = 10, + /obj/item/gun/projectile/pistol = 1 + ) + return spawn_choices + +/obj/random/scrapped_ionrifle + name = "random scrapped ion rifle" + icon = /obj/item/gun/energy/ionrifle::icon + icon_state = /obj/item/gun/energy/ionrifle::icon_state + +/obj/random/scrapped_ionrifle/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/energy/ionrifle = 10, + /obj/item/gun/energy/ionrifle = 1 + ) + return spawn_choices + +/obj/random/scrapped_grenadelauncher + name = "random scrapped grenade launcher" + icon = /obj/item/gun/launcher/grenade::icon + icon_state = /obj/item/gun/launcher/grenade::icon_state + +/obj/random/scrapped_grenadelauncher/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/launcher/grenade = 10, + /obj/item/gun/launcher/grenade = 1 + ) + return spawn_choices + +/obj/random/scrapped_laser + name = "random scrapped laser rifle" + icon = /obj/item/gun/energy/laser::icon + icon_state = /obj/item/gun/energy/laser::icon_state + +/obj/random/scrapped_laser/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/energy/laserrifle = 10, + /obj/item/gun/energy/laser = 1 + ) + return spawn_choices + +/obj/random/scrapped_smg + name = "random scrapped submachine gun" + icon = /obj/item/gun/projectile/automatic/smg::icon + icon_state = /obj/item/gun/projectile/automatic/smg::icon_state + +/obj/random/scrapped_smg/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/ballistic/smg = 10, + /obj/item/gun/projectile/automatic/smg = 1 + ) + return spawn_choices + +/obj/random/scrapped_shotgun + name = "random scrapped shotgun" + icon = /obj/item/gun/projectile/shotgun/pump::icon + icon_state = /obj/item/gun/projectile/shotgun/pump::icon_state + +/obj/random/scrapped_shotgun/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/ballistic/shotgun_pump = 10, + /obj/item/salvage/ballistic/shotgun_doublebarrel = 10, + /obj/item/gun/projectile/shotgun/pump = 1, + /obj/item/gun/projectile/shotgun/doublebarrel = 1 + ) + return spawn_choices + +/obj/random/scrapped_dartgun + name = "random scrapped dartgun" + icon = /obj/item/gun/projectile/dartgun::icon + icon_state = /obj/item/gun/projectile/dartgun::icon_state + +/obj/random/scrapped_dartgun/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/launcher/dartgun = 10, + /obj/item/gun/projectile/dartgun = 1 + ) + return spawn_choices + +/obj/random/scrapped_flechette + name = "random scrapped flechette rifle" + icon = /obj/item/gun/magnetic/railgun/flechette::icon + icon_state = /obj/item/gun/magnetic/railgun/flechette::icon_state + +/obj/random/scrapped_flechette/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/salvage/magnetic/flechette = 10, + /obj/item/gun/magnetic/railgun/flechette = 1 + ) + return spawn_choices diff --git a/code/game/objects/random/subtypes/suits.dm b/code/game/objects/random/subtypes/suits.dm new file mode 100644 index 000000000000..093f23509f62 --- /dev/null +++ b/code/game/objects/random/subtypes/suits.dm @@ -0,0 +1,70 @@ +/obj/random/hardsuit + name = "Random Hardsuit" + desc = "This is a random hardsuit control module." + icon = 'icons/obj/rig_modules.dmi' + icon_state = "generic" + +/obj/random/hardsuit/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/rig/industrial, + /obj/item/rig/eva, + /obj/item/rig/light + ) + return spawnable_choices + +/obj/random/hardsuit/heist + name = "Random Heist Hardsuit" + +/obj/random/hardsuit/heist/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/rig/industrial, + /obj/item/rig/eva, + /obj/item/rig/light/hacker, + /obj/item/rig/light/stealth, + /obj/item/rig/light + ) + return spawnable_choices + +/obj/random/voidsuit_and_helmet + name = "Random Voidsuit and Helmet" + desc = "This is a random basic voidsuit." + icon = 'icons/clothing/spacesuit/void/nasa/suit.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/voidsuit_and_helmet/spawn_choices() + var/static/list/spawnable_choices = list( + list( + /obj/item/clothing/suit/space/void, + /obj/item/clothing/head/helmet/space/void + ) = 10, + list( + /obj/item/clothing/suit/space/void/engineering, + /obj/item/clothing/head/helmet/space/void/engineering + ) = 2, + list( + /obj/item/clothing/suit/space/void/atmos, + /obj/item/clothing/head/helmet/space/void/atmos + ) = 2, + list( + /obj/item/clothing/suit/space/void/expedition, + /obj/item/clothing/head/helmet/space/void/expedition + ) = 1 + ) + return spawnable_choices + +/obj/random/voidsuit/mining + name = "Random Mining Voidsuit" + desc = "This is a random mining voidsuit." + +/obj/random/voidsuit/mining/spawn_choices() + var/static/list/spawnable_choices = list( + list( + /obj/item/clothing/suit/space/void/mining, + /obj/item/clothing/head/helmet/space/void/mining + ) = 5, + list( + /obj/item/clothing/suit/space/void/mining/alt, + /obj/item/clothing/head/helmet/space/void/mining/alt + ) = 1 + ) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/tech.dm b/code/game/objects/random/subtypes/tech.dm new file mode 100644 index 000000000000..2bd7302535ca --- /dev/null +++ b/code/game/objects/random/subtypes/tech.dm @@ -0,0 +1,199 @@ +/obj/random/technology_scanner + name = "random scanner" + desc = "This is a random technology scanner." + icon = 'icons/obj/items/device/scanner/atmos_scanner.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/technology_scanner/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/t_scanner = 5, + /obj/item/radio/off = 2, + /obj/item/scanner/reagent = 2, + /obj/item/scanner/spectrometer = 2, + /obj/item/scanner/gas = 5 + ) + return spawnable_choices + +/obj/random/powercell + name = "random power cell" + desc = "This is a random power cell." + icon = 'icons/obj/power.dmi' + icon_state = "hcell" + +/obj/random/powercell/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/cell/crap = 1, + /obj/item/cell = 8, + /obj/item/cell/high = 5, + /obj/item/cell/gun = 5, + /obj/item/cell/super = 2, + /obj/item/cell/hyper = 1, + /obj/item/cell/device/standard = 7, + /obj/item/cell/device/high = 5 + ) + return spawnable_choices + +/obj/random/bomb_supply + name = "bomb supply" + desc = "This is a random bomb supply." + icon = 'icons/obj/assemblies/new_assemblies.dmi' + icon_state = "signaller" + +/obj/random/bomb_supply/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/assembly/igniter, + /obj/item/assembly/prox_sensor, + /obj/item/assembly/signaler, + /obj/item/assembly/timer, + /obj/item/multitool + ) + return spawnable_choices + +/obj/random/tech_supply + name = "random tech supply" + desc = "This is a random piece of technology supplies." + icon = 'icons/obj/power.dmi' + icon_state = "cell" + spawn_nothing_percentage = 50 + +/obj/random/tech_supply/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/powercell = 3, + /obj/random/technology_scanner = 2, + /obj/item/stack/package_wrap/twenty_five = 1, + /obj/item/hand_labeler = 1, + /obj/random/bomb_supply = 2, + /obj/item/chems/spray/extinguisher = 1, + /obj/item/clothing/gloves/insulated/cheap = 1, + /obj/item/stack/cable_coil/random = 2, + /obj/random/toolbox = 2, + /obj/item/belt/utility = 2, + /obj/item/belt/utility/atmostech = 1, + /obj/random/tool = 5, + /obj/item/stack/tape_roll/duct_tape = 2 + ) + return spawnable_choices + +/obj/random/tech_supply/nofail + name = "guaranteed random tech supply" + spawn_nothing_percentage = 0 + +/obj/random/tech_supply/component + name = "random tech component" + desc = "This is a random machine component." + +/obj/random/tech_supply/component/nofail + name = "guaranteed random tech component" + spawn_nothing_percentage = 0 + +/obj/random/tech_supply/component/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/stock_parts/console_screen = 2, + /obj/item/stock_parts/capacitor = 3, + /obj/item/stock_parts/capacitor/adv = 2, + /obj/item/stock_parts/capacitor/super = 1, + /obj/item/stock_parts/manipulator = 3, + /obj/item/stock_parts/manipulator/nano = 2, + /obj/item/stock_parts/manipulator/pico = 1, + /obj/item/stock_parts/matter_bin = 3, + /obj/item/stock_parts/matter_bin/adv = 2, + /obj/item/stock_parts/matter_bin/super = 1, + /obj/item/stock_parts/scanning_module = 3, + /obj/item/stock_parts/scanning_module/adv = 2, + /obj/item/stock_parts/scanning_module/phasic = 1 + ) + return spawn_choices + +/obj/random/tank + name = "random tank" + desc = "This is a tank." + icon = 'icons/obj/items/tanks/tank_blue.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/tank/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/tank/oxygen = 5, + /obj/item/tank/oxygen/yellow = 4, + /obj/item/tank/emergency/oxygen/double/red = 4, + /obj/item/tank/air = 3, + /obj/item/tank/emergency/oxygen = 4, + /obj/item/tank/emergency/oxygen/engi = 3, + /obj/item/tank/emergency/oxygen/double = 2, + /obj/item/tank/nitrogen = 1, + /obj/item/suit_cooling_unit = 1 + ) + return spawnable_choices + +/obj/random/advdevice + name = "random advanced device" + desc = "This is a random advanced device." + icon = 'icons/obj/items/gamekit.dmi' + icon_state = "game_kit" + +/obj/random/advdevice/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/flashlight/lantern, + /obj/item/flashlight/flare, + /obj/item/flashlight/pen, + /obj/item/chems/toner_cartridge, + /obj/item/paicard, + /obj/item/destTagger, + /obj/item/beartrap, + /obj/item/handcuffs, + /obj/item/camera, + /obj/item/modular_computer/pda, + /obj/item/card/emag_broken, + /obj/item/radio/headset, + /obj/item/flashlight/flare/glowstick/yellow, + /obj/item/flashlight/flare/glowstick/orange, + /obj/item/grenade/light, + /obj/item/oxycandle + ) + return spawnable_choices + +/obj/random/hardsuit + name = "random hardsuit" + desc = "This is a random hardsuit." + icon = 'icons/clothing/rigs/rig.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/hardsuit/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/rig/light/hacker/unlocked = 4, + /obj/item/rig/industrial/unlocked = 5, + /obj/item/rig/eva/unlocked = 5, + /obj/item/rig/light/stealth/unlocked = 4, + /obj/item/rig/hazard/unlocked = 3, + /obj/item/rig/merc/empty/unlocked = 1 + ) + return spawnable_choices + +/obj/random/powercell + name = "random powercell" + desc = "This is a random powercell." + icon = /obj/item/cell::icon + icon_state = /obj/item/cell::icon_state + +/obj/random/powercell/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/cell = 40, + /obj/item/cell/gun = 25, + /obj/item/cell/high = 25, + /obj/item/cell/super = 9, + /obj/item/cell/hyper = 1 + ) + return spawn_choices + +/obj/random/smes_coil + name = "random smes coil" + desc = "This is a random smes coil." + icon = /obj/item/stock_parts/smes_coil::icon + icon_state = /obj/item/stock_parts/smes_coil::icon_state + +/obj/random/smes_coil/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/stock_parts/smes_coil = 4, + /obj/item/stock_parts/smes_coil/super_capacity = 1, + /obj/item/stock_parts/smes_coil/super_io = 1 + ) + return spawn_choices diff --git a/code/game/objects/random/subtypes/tools.dm b/code/game/objects/random/subtypes/tools.dm new file mode 100644 index 000000000000..ed0a73164cb1 --- /dev/null +++ b/code/game/objects/random/subtypes/tools.dm @@ -0,0 +1,47 @@ +/obj/random/tool + name = "random tool" + desc = "This is a random tool." + icon = 'icons/obj/items/tool/welders/welder.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/tool/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/screwdriver = 5, + /obj/item/wirecutters = 5, + /obj/item/weldingtool = 5, + /obj/item/weldingtool/largetank = 1, + /obj/item/crowbar = 5, + /obj/item/wrench = 5, + /obj/item/flashlight = 5 + ) + return spawnable_choices + +/obj/random/tool/power + name = "random power tool" + desc = "This is a random rare power tool for maintenance" + +/obj/random/tool/power/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/tool = 320, + /obj/item/weldingtool/electric = 15, + /obj/item/weldingtool/experimental = 3, + /obj/item/tool/hydraulic_cutter = 1, + /obj/item/tool/power_drill = 1 + ) + return spawnable_choices + +/obj/random/toolbox + name = "random toolbox" + desc = "This is a random toolbox." + icon = 'icons/obj/items/storage/toolboxes/toolbox_red.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/toolbox/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toolbox/mechanical = 30, + /obj/item/toolbox/electrical = 20, + /obj/item/toolbox/emergency = 20, + /obj/item/toolbox/repairs = 20, + /obj/item/toolbox/syndicate = 1 + ) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/toys.dm b/code/game/objects/random/subtypes/toys.dm new file mode 100644 index 000000000000..255e50a2bb14 --- /dev/null +++ b/code/game/objects/random/subtypes/toys.dm @@ -0,0 +1,253 @@ +/obj/random/plush + name = "random plush" + desc = "This is a random plush toy." + icon = 'icons/obj/toy/plush_corgi.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/plush/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/random/plush/animal, + /obj/random/plush/therapy + ) + return spawnable_choices + +/obj/random/plush/animal + name = "random animal plush" + icon = 'icons/obj/toy/plush_deer.dmi' + +/obj/random/plush/animal/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/nymph, + /obj/item/toy/plushie/deer, + /obj/item/toy/plushie/mouse, + /obj/item/toy/plushie/kitten, + /obj/item/toy/plushie/lizard, + /obj/item/toy/plushie/spider, + /obj/item/toy/plushie/corgi, + /obj/item/toy/plushie/corgi/ribbon, + /obj/item/toy/plushie/robo_corgi, + /obj/item/toy/plushie/octopus, + /obj/item/toy/plushie/face_hugger, + /obj/random/plush/carp, + /obj/random/plush/fox, + /obj/random/plush/cat, + /obj/random/plush/squid + ) + return spawnable_choices + +/obj/random/plush/therapy + name = "random therapy doll" + icon = 'icons/obj/toy/plush_therapy_blue.dmi' + +/obj/random/plush/therapy/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/therapy, + /obj/item/toy/plushie/therapy/orange, + /obj/item/toy/plushie/therapy/yellow, + /obj/item/toy/plushie/therapy/green, + /obj/item/toy/plushie/therapy/purple, + /obj/item/toy/plushie/therapy/blue + ) + return spawnable_choices + +/obj/random/plush/carp + name = "random carp plush" + icon = 'icons/obj/toy/plush_carp.dmi' + +/obj/random/plush/carp/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/carp, + /obj/item/toy/plushie/carp/ice, + /obj/item/toy/plushie/carp/silent, + /obj/item/toy/plushie/carp/electric, + /obj/item/toy/plushie/carp/gold, + /obj/item/toy/plushie/carp/toxin, + /obj/item/toy/plushie/carp/dragon, + /obj/item/toy/plushie/carp/pink, + /obj/item/toy/plushie/carp/candy, + /obj/item/toy/plushie/carp/nebula, + /obj/item/toy/plushie/carp/void + ) + return spawnable_choices + +/obj/random/plush/fox + name = "random fox plush" + icon = 'icons/obj/toy/plush_fox.dmi' + +/obj/random/plush/fox/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/fox, + /obj/item/toy/plushie/fox/black, + /obj/item/toy/plushie/fox/marble, + /obj/item/toy/plushie/fox/blue, + /obj/item/toy/plushie/fox/orange, + /obj/item/toy/plushie/fox/coffee, + /obj/item/toy/plushie/fox/pink, + /obj/item/toy/plushie/fox/purple, + /obj/item/toy/plushie/fox/crimson, + ) + return spawnable_choices + +/obj/random/plush/cat + name = "random cat plush" + icon = 'icons/obj/toy/plush_cat.dmi' + +/obj/random/plush/cat/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/cat, + /obj/item/toy/plushie/cat/grey, + /obj/item/toy/plushie/cat/white, + /obj/item/toy/plushie/cat/orange, + /obj/item/toy/plushie/cat/siamese, + /obj/item/toy/plushie/cat/tabby, + /obj/item/toy/plushie/cat/tuxedo + ) + return spawnable_choices + +/obj/random/plush/squid + name = "random squid plush" + icon = 'icons/obj/toy/plush_squid.dmi' + +/obj/random/plush/squid/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/squid, + /obj/item/toy/plushie/squid/mint, + /obj/item/toy/plushie/squid/blue, + /obj/item/toy/plushie/squid/orange, + /obj/item/toy/plushie/squid/yellow, + /obj/item/toy/plushie/squid/pink + ) + return spawnable_choices + +/obj/random/toy + name = "random toy" + desc = "This is a random toy." + icon = 'icons/obj/toy/toy.dmi' + icon_state = "ship" + +/obj/random/toy/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/bosunwhistle, + /obj/random/plush, + /obj/item/sword/cult_toy, + /obj/item/sword/katana/toy, + /obj/item/toy/snappop, + /obj/item/energy_blade/sword/toy, + /obj/item/chems/water_balloon, + /obj/item/gun/launcher/foam/crossbow, + /obj/item/toy/blink, + /obj/item/toy/prize/powerloader, + /obj/item/toy/prize/fireripley, + /obj/item/toy/prize/deathripley, + /obj/item/toy/prize/gygax, + /obj/item/toy/prize/durand, + /obj/item/toy/prize/honk, + /obj/item/toy/prize/marauder, + /obj/item/toy/prize/seraph, + /obj/item/toy/prize/mauler, + /obj/item/toy/prize/odysseus, + /obj/item/toy/prize/phazon, + /obj/item/toy/spinningtoy, + /obj/item/deck/cards + ) + return spawnable_choices + +/obj/random/plushie + name = "random plushie" + desc = "This is a random plushie." + icon = 'icons/obj/toy/plush_cat.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/plushie/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/plushie/mouse, + /obj/item/toy/plushie/kitten, + /obj/item/toy/plushie/lizard + ) + return spawnable_choices + +/obj/random/plushie/large + name = "random large plushie" + desc = "This is a random large plushie." + icon = 'icons/obj/structures/plushie.dmi' + icon_state = "droneplushie" + +/obj/random/plushie/large/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/structure/plushie/ian, + /obj/structure/plushie/drone, + /obj/structure/plushie/carp, + /obj/structure/plushie/beepsky + ) + return spawnable_choices + +/obj/random/action_figure + name = "random action figure" + desc = "This is a random action figure." + icon = 'icons/obj/toy/toy.dmi' + icon_state = "assistant" + +/obj/random/action_figure/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/figure/cmo, + /obj/item/toy/figure/assistant, + /obj/item/toy/figure/atmos, + /obj/item/toy/figure/bartender, + /obj/item/toy/figure/borg, + /obj/item/toy/figure/gardener, + /obj/item/toy/figure/captain, + /obj/item/toy/figure/cargotech, + /obj/item/toy/figure/ce, + /obj/item/toy/figure/chaplain, + /obj/item/toy/figure/chef, + /obj/item/toy/figure/chemist, + /obj/item/toy/figure/clown, + /obj/item/toy/figure/corgi, + /obj/item/toy/figure/detective, + /obj/item/toy/figure/dsquad, + /obj/item/toy/figure/engineer, + /obj/item/toy/figure/geneticist, + /obj/item/toy/figure/hop, + /obj/item/toy/figure/hos, + /obj/item/toy/figure/qm, + /obj/item/toy/figure/janitor, + /obj/item/toy/figure/agent, + /obj/item/toy/figure/librarian, + /obj/item/toy/figure/md, + /obj/item/toy/figure/mime, + /obj/item/toy/figure/miner, + /obj/item/toy/figure/ninja, + /obj/item/toy/figure/wizard, + /obj/item/toy/figure/rd, + /obj/item/toy/figure/roboticist, + /obj/item/toy/figure/scientist, + /obj/item/toy/figure/syndie, + /obj/item/toy/figure/secofficer, + /obj/item/toy/figure/warden, + /obj/item/toy/figure/psychologist, + /obj/item/toy/figure/paramedic, + /obj/item/toy/figure/ert + ) + return spawnable_choices + +/obj/random/mech_toy + name = "random mech toy" + desc = "This is a random mech toy." + icon = /obj/item/toy/prize/powerloader::icon + icon_state = /obj/item/toy/prize/powerloader::icon_state + +/obj/random/mech_toy/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/toy/prize/powerloader, + /obj/item/toy/prize/fireripley, + /obj/item/toy/prize/deathripley, + /obj/item/toy/prize/gygax, + /obj/item/toy/prize/durand, + /obj/item/toy/prize/honk, + /obj/item/toy/prize/marauder, + /obj/item/toy/prize/seraph, + /obj/item/toy/prize/mauler, + /obj/item/toy/prize/odysseus, + /obj/item/toy/prize/phazon + ) + return spawnable_choices diff --git a/code/game/objects/random/subtypes/weapons.dm b/code/game/objects/random/subtypes/weapons.dm new file mode 100644 index 000000000000..14a526bda1df --- /dev/null +++ b/code/game/objects/random/subtypes/weapons.dm @@ -0,0 +1,111 @@ +/obj/random/energy + name = "Random Energy Weapon" + desc = "This is a random energy weapon." + icon = 'icons/obj/guns/energy_gun.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/energy/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/gun/energy/laser = 4, + /obj/item/gun/energy/gun = 3, + /obj/item/gun/energy/lasercannon = 2, + /obj/item/gun/energy/xray = 3, + /obj/item/gun/energy/sniperrifle = 1, + /obj/item/gun/energy/gun/nuclear = 1, + /obj/item/gun/energy/ionrifle = 2, + /obj/item/gun/energy/toxgun = 3, + /obj/item/gun/energy/taser = 4, + /obj/item/gun/energy/crossbow/largecrossbow = 2 + ) + return spawnable_choices + +/obj/random/energy/sec + name = "Random Security Weapon" + desc = "This is a random energy weapon." + +/obj/random/energy/sec/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/gun/energy/laser = 2, + /obj/item/gun/energy/gun = 2 + ) + return spawnable_choices +/obj/random/projectile + name = "Random Projectile Weapon" + desc = "This is a random projectile weapon." + icon = 'icons/obj/guns/revolvers.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/projectile/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/gun/projectile/shotgun/pump = 3, + /obj/item/gun/projectile/automatic/assault_rifle = 2, + /obj/item/gun/projectile/pistol = 3, + /obj/item/gun/projectile/pistol/holdout = 4, + /obj/item/gun/projectile/zipgun = 5, + /obj/item/gun/projectile/automatic/smg = 4, + /obj/item/gun/projectile/revolver = 2, + /obj/item/gun/projectile/shotgun/doublebarrel = 4, + /obj/item/gun/projectile/shotgun/doublebarrel/sawn = 3, + /obj/item/gun/projectile/bolt_action/sniper = 1 + ) + return spawnable_choices + +/obj/random/projectile/sec + name = "Random Security Weapon" + desc = "This is a random security projectile weapon." + +/obj/random/projectile/sec/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/gun/projectile/shotgun/pump = 3, + /obj/item/gun/projectile/shotgun/doublebarrel = 2, + /obj/item/gun/projectile/automatic/smg = 1 + ) + return spawnable_choices + +/obj/random/handgun + name = "Random Handgun" + desc = "This is a random sidearm." + icon = 'icons/obj/guns/pistol.dmi' + icon_state = ICON_STATE_WORLD + +/obj/random/handgun/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/gun/projectile/pistol = 3, + /obj/item/gun/energy/gun = 3, + /obj/item/gun/projectile/pistol/holdout = 2 + ) + return spawnable_choices + +/obj/random/ammo + name = "Random Ammunition" + desc = "This is random ammunition." + icon = 'icons/obj/ammo.dmi' + icon_state = "magnum" + +/obj/random/ammo/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/box/ammo/beanbags = 6, + /obj/item/box/ammo/shotgunammo = 2, + /obj/item/box/ammo/shotgunshells = 4, + /obj/item/box/ammo/stunshells = 1, + /obj/item/ammo_magazine/pistol = 2, + /obj/item/ammo_magazine/smg = 2, + /obj/item/ammo_magazine/smg/rubber = 6 + ) + return spawnable_choices + +/obj/random/landmine + name = "random landmine" + icon = /obj/item/mine::icon + icon_state = /obj/item/mine::icon_state + +/obj/random/landmine/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/mine/emp/mapped, + /obj/item/mine/frag/mapped, + /obj/item/mine/incendiary/mapped, + /obj/item/mine/napalm/mapped, + /obj/item/mine/radiation/mapped, + /obj/item/mine/stun/mapped + ) + return spawnable_choices diff --git a/code/game/objects/structures/__structure.dm b/code/game/objects/structures/__structure.dm index 3f110070b159..27239ec9127b 100644 --- a/code/game/objects/structures/__structure.dm +++ b/code/game/objects/structures/__structure.dm @@ -2,15 +2,43 @@ icon = 'icons/obj/structures/barricade.dmi' w_class = ITEM_SIZE_STRUCTURE layer = STRUCTURE_LAYER + abstract_type = /obj/structure + max_health = 50 + temperature_sensitive = TRUE + /// Multiplier for degree of comfort offered to mobs buckled to this furniture. + var/user_comfort = 0 // TODO: extremely uncomfortable chairs + var/structure_flags var/last_damage_message - var/health = 0 - var/maxhealth = -1 - var/hitsound = 'sound/weapons/smash.ogg' - var/breakable + var/hitsound = 'sound/weapons/Genhit.ogg' var/parts_type + var/parts_amount var/footstep_type var/mob_offset + var/paint_verb + +/obj/structure/get_color() + if(paint_color) + return paint_color + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_COLOR)) + return material.color + return initial(color) + +/obj/structure/set_color(new_color) + if(new_color == COLOR_WHITE) + new_color = null + if(paint_color != new_color) + paint_color = new_color + . = TRUE + refresh_color() + +/obj/structure/refresh_color() + if(paint_color) + color = paint_color + else if(material && (material_alteration & MAT_FLAG_ALTERATION_COLOR)) + color = material.color + else + color = null /obj/structure/create_matter() ..() @@ -27,78 +55,89 @@ if(ispath(_mat, /decl/material)) material = _mat if(ispath(material, /decl/material)) - material = decls_repository.get_decl(material) + material = GET_DECL(material) if(ispath(_reinf_mat, /decl/material)) reinf_material = _reinf_mat if(ispath(reinf_material, /decl/material)) - reinf_material = decls_repository.get_decl(reinf_material) + reinf_material = GET_DECL(reinf_material) . = ..() update_materials() + paint_verb ||= "painted" // fallback for the case of no material + if(lock && !istype(loc)) + lock = new /datum/lock(src, lock) if(!CanFluidPass()) - fluid_update() + fluid_update(TRUE) + if (!isnull(get_possible_reagent_transfer_amounts())) + verbs |= /obj/structure/proc/set_reagent_amount_dispensed_verb -/obj/structure/proc/show_examined_damage(mob/user, var/perc) - if(maxhealth == -1) +/obj/structure/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 3) return - if(perc >= 1) - to_chat(user, SPAN_NOTICE("It looks fully intact.")) - else if(perc > 0.75) - to_chat(user, SPAN_NOTICE("It has a few cracks.")) - else if(perc > 0.5) - to_chat(user, SPAN_WARNING("It looks slightly damaged.")) - else if(perc > 0.25) - to_chat(user, SPAN_WARNING("It looks moderately damaged.")) - else - to_chat(user, SPAN_DANGER("It looks heavily damaged.")) + if(distance <= 1 && lock) + . += SPAN_NOTICE("\The [src] appears to have a lock, opened by '[lock.lock_data]'.") + var/damage_desc = get_examined_damage_string() + if(length(damage_desc)) + . += damage_desc + if(paint_color) + var/decl/pronouns/structure_pronouns = get_pronouns() // so we can do 'have' for plural objects like sheets + . += "\The [src] [structure_pronouns.has] been [paint_verb]." + if(distance <= 2 && !isnull(get_possible_reagent_transfer_amounts()) && reagents) + . += SPAN_NOTICE("It contains:") + var/reagent_volumes = REAGENT_VOLUMES(reagents) + if(LAZYLEN(reagent_volumes)) + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(reagents)) + . += SPAN_NOTICE("[LIQUID_VOLUME(reagents, reagent)] unit\s of [reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID)].") + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(reagents)) + . += SPAN_NOTICE("[SOLID_VOLUME(reagents, reagent)] unit\s of [reagent.get_reagent_name(reagents, MAT_PHASE_SOLID)].") + else + . += SPAN_NOTICE("Nothing.") + if(REAGENT_MAXIMUM_VOLUME(reagents)) + . += "It may contain up to [REAGENT_MAXIMUM_VOLUME(reagents)] unit\s." -/obj/structure/examine(mob/user, var/distance) +/obj/structure/get_examine_hints(mob/user, distance, infix, suffix) . = ..() if(distance <= 3) - - show_examined_damage(user, (health/maxhealth)) - if(tool_interaction_flags & TOOL_INTERACTION_ANCHOR) if(anchored) - to_chat(user, SPAN_SUBTLE("Can be unanchored with a wrench, and moved around.")) + LAZYADD(., SPAN_SUBTLE("Can be unanchored with a wrench or hammer, and moved around.")) else - to_chat(user, SPAN_SUBTLE("Can be anchored in place with a wrench.")) - + LAZYADD(., SPAN_SUBTLE("Can be anchored in place with a wrench or hammer.")) if(tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) - var/removed_with = "a crowbar" + var/removed_with = "a crowbar or hammer" if(material && material.removed_by_welder) removed_with = "a welding torch" if(tool_interaction_flags & TOOL_INTERACTION_ANCHOR) if(anchored) - to_chat(user, SPAN_SUBTLE("Can be deconstructed with [removed_with].")) + LAZYADD(., SPAN_SUBTLE("Can be deconstructed with [removed_with].")) else - to_chat(user, SPAN_SUBTLE("Can be deconstructed with [removed_with], if anchored down with a wrench first.")) + LAZYADD(., SPAN_SUBTLE("Can be deconstructed with [removed_with], if anchored down with a wrench or hammer first.")) else - to_chat(user, SPAN_SUBTLE("Can be deconstructed with [removed_with].")) - + LAZYADD(., SPAN_SUBTLE("Can be deconstructed with [removed_with].")) if(tool_interaction_flags & TOOL_INTERACTION_WIRING) if(tool_interaction_flags & TOOL_INTERACTION_ANCHOR) if(wired) if(anchored) - to_chat(user, SPAN_SUBTLE("Can have its wiring removed with wirecutters")) + LAZYADD(., SPAN_SUBTLE("Can have its wiring removed with wirecutters.")) else - to_chat(user, SPAN_SUBTLE("Can have its wiring removed with wirecutters, if anchored down with a wrench first.")) + LAZYADD(., SPAN_SUBTLE("Can have its wiring removed with wirecutters, if anchored down with a wrench first.")) else if(anchored) - to_chat(user, SPAN_SUBTLE("Can have wiring installed with a cable coil.")) + LAZYADD(., SPAN_SUBTLE("Can have wiring installed with a cable coil.")) else - to_chat(user, SPAN_SUBTLE("Can have wiring installed with a cable coil, if anchored down with a wrench first.")) + LAZYADD(., SPAN_SUBTLE("Can have wiring installed with a cable coil, if anchored down with a wrench first.")) else if(wired) - to_chat(user, SPAN_SUBTLE("Can have its wiring removed with wirecutters")) + LAZYADD(., SPAN_SUBTLE("Can have its wiring removed with wirecutters.")) else - to_chat(user, SPAN_SUBTLE("Can have wiring installed with a cable coil.")) + LAZYADD(., SPAN_SUBTLE("Can have wiring installed with a cable coil.")) /obj/structure/proc/mob_breakout(var/mob/living/escapee) set waitfor = FALSE return FALSE -/obj/structure/proc/take_damage(var/damage) - if(health == -1) // This object does not take damage. +/obj/structure/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(current_health == ITEM_HEALTH_NO_DAMAGE) // This object does not take damage. return if(material && material.is_brittle()) @@ -108,12 +147,14 @@ else damage *= STRUCTURE_BRITTLE_MATERIAL_DAMAGE_MULTIPLIER - playsound(loc, hitsound, 75, 1) - health = Clamp(health - damage, 0, maxhealth) - - show_damage_message(health/maxhealth) + if(!silent) + playsound(loc, hitsound, 60, 1) + + var/current_max_health = get_max_health() + current_health = clamp(current_health - damage, 0, current_max_health) + show_damage_message(current_health/current_max_health) - if(health == 0) + if(current_health == 0) physically_destroyed() /obj/structure/proc/show_damage_message(var/perc) @@ -129,92 +170,121 @@ visible_message(SPAN_WARNING("\The [src] is showing some damage!")) last_damage_message = 0.75 -/obj/structure/physically_destroyed() - . = ..() && dismantle() +/obj/structure/physically_destroyed(var/skip_qdel) + if((. = ..(TRUE))) + return dismantle_structure() /obj/structure/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) . = ..() var/dmg = 100 - if(material) + if(istype(material)) dmg = round(dmg * material.combustion_effect(get_turf(src),temperature, 0.3)) if(dmg) take_damage(dmg) +/obj/structure/ProcessAtomTemperature() + var/update_mats = FALSE + if(material && material.bakes_into_material && !isnull(material.bakes_into_at_temperature) && temperature >= material.bakes_into_at_temperature) + material = GET_DECL(material.bakes_into_material) + update_mats = TRUE + if(reinf_material && reinf_material.bakes_into_material && !isnull(reinf_material.bakes_into_at_temperature) && temperature >= reinf_material.bakes_into_at_temperature) + reinf_material = GET_DECL(reinf_material.bakes_into_material) + update_mats = TRUE + if(update_mats) + update_materials() + . = ..() + /obj/structure/Destroy() - reset_mobs_offset() + QDEL_NULL(lock) var/turf/T = get_turf(src) + . = ..() if(T) T.fluid_update() - . = ..() + for(var/atom/movable/AM in T) + AM.reset_offsets() + AM.reset_plane_and_layer() -/obj/structure/Crossed(mob/living/M) - if(istype(M)) - M.on_structure_offset(mob_offset) - ..() +/obj/structure/Crossed(atom/movable/AM) + . = ..() + if(!ismob(AM)) + return + var/mob/M = AM + M.reset_offsets() + M.reset_plane_and_layer() -/obj/structure/proc/reset_mobs_offset() - for(var/mob/living/M in loc) - M.on_structure_offset(0) +/obj/structure/Uncrossed(atom/movable/AM) + . = ..() + if(!ismob(AM)) + return + var/mob/M = AM + M.reset_offsets() + M.reset_plane_and_layer() /obj/structure/Move() + var/turf/T = get_turf(src) . = ..() if(. && !CanFluidPass()) fluid_update() + if(T) + T.fluid_update() + for(var/atom/movable/AM in T) + AM.reset_offsets() + AM.reset_plane_and_layer() -/obj/structure/attack_hand(mob/user) - ..() - if(breakable) - if(MUTATION_HULK in user.mutations) - user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - attack_generic(user,1,"smashes") - else if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species.can_shred(user)) - attack_generic(user,1,"slices") - return ..() - -/obj/structure/grab_attack(var/obj/item/grab/G) - if (!G.force_danger()) - to_chat(G.assailant, SPAN_WARNING("You need a better grip to do that!")) +/obj/structure/grab_attack(obj/item/grab/grab, mob/user) + + if (!grab.force_danger()) + to_chat(user, SPAN_WARNING("You need a better grip to do that!")) return TRUE - var/mob/affecting_mob = G.get_affecting_mob() - if (G.assailant.a_intent == I_HURT) - if(!affecting_mob) - to_chat(G.assailant, SPAN_WARNING("You need to be grabbing a living creature to do that!")) + var/mob/living/victim = grab.get_affecting_mob() + if(user.check_intent(I_FLAG_HARM)) + + if(!istype(victim)) + to_chat(user, SPAN_WARNING("You need to be grabbing a living creature to do that!")) return TRUE // Slam their face against the table. - var/blocked = affecting_mob.get_blocked_ratio(BP_HEAD, BRUTE, damage = 8) + var/blocked = victim.get_blocked_ratio(BP_HEAD, BRUTE, damage = 8) if (prob(30 * (1 - blocked))) - affecting_mob.Weaken(5) - affecting_mob.apply_damage(8, BRUTE, BP_HEAD) - visible_message(SPAN_DANGER("[G.assailant] slams [affecting_mob]'s face against \the [src]!")) + SET_STATUS_MAX(victim, STAT_WEAK, 5) + + victim.apply_damage(8, BRUTE, BP_HEAD) + visible_message(SPAN_DANGER("[user] slams [victim]'s face against \the [src]!")) if (material) playsound(loc, material.tableslam_noise, 50, 1) else playsound(loc, 'sound/weapons/tablehit1.ogg', 50, 1) var/list/L = take_damage(rand(1,5)) for(var/obj/item/shard/S in L) - if(S.sharp && prob(50)) - affecting_mob.visible_message(SPAN_DANGER("\The [S] slices into [affecting_mob]'s face!"), SPAN_DANGER("\The [S] slices into your face!")) - affecting_mob.standard_weapon_hit_effects(S, G.assailant, S.force*2, BP_HEAD) - qdel(G) + if(S.is_sharp() && prob(50)) + victim.visible_message( + SPAN_DANGER("\The [S] slices into [victim]'s face!"), + SPAN_DANGER("\The [S] slices into your face!") + ) + victim.standard_weapon_hit_effects(S, user, S.expend_attack_force()*2, BP_HEAD) + qdel(grab) + return TRUE + else if(can_buckle && !buckled_mob && istype(victim) && istype(user)) + user.visible_message(SPAN_NOTICE("\The [user] attempts to put \the [victim] onto \the [src]!")) + if(do_after(user, 2 SECONDS, src) && !QDELETED(victim) && !QDELETED(user) && !QDELETED(grab) && user_buckle_mob(victim, user)) + qdel(grab) + return TRUE else if(atom_flags & ATOM_FLAG_CLIMBABLE) var/obj/occupied = turf_is_crowded() if (occupied) - to_chat(G.assailant, SPAN_WARNING("There's \a [occupied] in the way.")) + to_chat(user, SPAN_WARNING("There's \a [occupied] in the way.")) return TRUE - G.affecting.forceMove(src.loc) - if(affecting_mob) - affecting_mob.Weaken(rand(2,5)) - visible_message(SPAN_DANGER("[G.assailant] puts [G.affecting] on \the [src].")) - qdel(G) + grab.affecting.forceMove(src.loc) + if(victim) + SET_STATUS_MAX(victim, STAT_WEAK, rand(2,5)) + visible_message(SPAN_DANGER("\The [user] puts \the [grab.affecting] on \the [src].")) + qdel(grab) return TRUE /obj/structure/explosion_act(severity) ..() - if(QDELETED(src)) + if(!QDELETED(src)) if(severity == 1) physically_destroyed() else if(severity == 2) @@ -223,10 +293,73 @@ take_damage(rand(5, 15)) /obj/structure/proc/can_repair(var/mob/user) - if(health >= maxhealth) + if(current_health >= get_max_health()) to_chat(user, SPAN_NOTICE("\The [src] does not need repairs.")) return FALSE return TRUE /obj/structure/bullet_act(var/obj/item/projectile/Proj) - take_damage(Proj.get_structure_damage()) + if(take_damage(Proj.get_structure_damage(), Proj.atom_damage_type)) + return PROJECTILE_CONTINUE + +/* +Automatic alignment of items to an invisible grid, defined by CELLS and CELLSIZE, defined in code/__defines/misc.dm. +Since the grid will be shifted to own a cell that is perfectly centered on the turf, we end up with two 'cell halves' +on edges of each row/column. +Each item defines a center_of_mass, which is the pixel of a sprite where its projected center of mass toward a turf +surface can be assumed. For a piece of paper, this will be in its center. For a bottle, it will be (near) the bottom +of the sprite. +auto_align() will then place the sprite so the defined center_of_mass is at the bottom left corner of the grid cell +closest to where the cursor has clicked on. +Note: This proc can be overwritten to allow for different types of auto-alignment. +*/ +/obj/structure/proc/auto_align(obj/item/aligning, click_params) + if (!aligning.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy. + aligning.pixel_x = rand(-aligning.randpixel, aligning.randpixel) + aligning.pixel_y = rand(-aligning.randpixel, aligning.randpixel) + aligning.pixel_z = 0 + return + if (!click_params) + return + var/list/click_data = params2list(click_params) + if (!click_data["icon-x"] || !click_data["icon-y"]) + return + // Calculation to apply new pixelshift. + var/mouse_x = text2num(click_data["icon-x"])-1 // Ranging from 0 to 31 + var/mouse_y = text2num(click_data["icon-y"])-1 + var/span_x = CELLS + var/span_y = CELLS + // In case we're a multitile object. + if(bound_width > world.icon_size) + span_x = bound_width / CELLSIZE + if(bound_height > world.icon_size) + span_y = bound_height / CELLSIZE + var/cell_x = clamp(round(mouse_x/CELLSIZE), 0, span_x-1) // Ranging from 0 to span_x-1 + var/cell_y = clamp(round(mouse_y/CELLSIZE), 0, span_y-1) + var/list/center = cached_json_decode(aligning.center_of_mass) + aligning.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] + aligning.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] + aligning.pixel_z = 0 + +// Does this structure override turf depth for the purposes of mob offsets? +/obj/structure/proc/is_platform() + return FALSE + +/obj/structure/proc/is_z_passable() + return TRUE + +/obj/structure/on_turf_height_change(new_height) + // We may be a fixed point. + return !is_platform() && ..() + +/obj/structure/hitby(var/atom/movable/AM, var/datum/thrownthing/TT) + . = ..() + if(. && (structure_flags & STRUCTURE_FLAG_THROWN_DAMAGE)) + visible_message(SPAN_DANGER("\The [src] was hit by \the [AM].")) + playsound(src.loc, hitsound, 100, 1) + take_damage(AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR), AM.atom_damage_type) + +/obj/structure/get_alt_interactions(var/mob/user) + . = ..() + if(!isnull(get_possible_reagent_transfer_amounts())) + LAZYADD(., /decl/interaction_handler/set_transfer/structure) diff --git a/code/game/objects/structures/_structure_construction.dm b/code/game/objects/structures/_structure_construction.dm index 2cbc485ffd28..37d86d02566a 100644 --- a/code/game/objects/structures/_structure_construction.dm +++ b/code/game/objects/structures/_structure_construction.dm @@ -4,81 +4,27 @@ /obj/structure/proc/handle_default_wrench_attackby(var/mob/user, var/obj/item/wrench) if((tool_interaction_flags & TOOL_INTERACTION_ANCHOR) && can_unanchor(user)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] begins [anchored ? "unsecuring [src]" : "securing [src] in place"] with \the [wrench].")) - if(!do_after(user, 4 SECONDS, src) || QDELETED(src)) - return TRUE - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - anchored = !anchored - visible_message(SPAN_NOTICE("\The [user] has [anchored ? "secured" : "unsecured"] \the [src] with \the [wrench].")) - update_icon() - return TRUE + return tool_toggle_anchors(user, wrench) return FALSE /obj/structure/proc/handle_default_welder_attackby(var/mob/user, var/obj/item/weldingtool/welder) if((tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) && can_dismantle(user)) - if(material && !material.removed_by_welder) - to_chat(user, SPAN_WARNING("\The [src] is too delicate to be dismantled with \the [welder]; try a crowbar.")) - return TRUE - if(!welder.isOn()) - to_chat(user, SPAN_WARNING("Try lighting \the [welder] first.")) - return TRUE - if(welder.get_fuel() < 5) - to_chat(user, SPAN_WARNING("You need more fuel to complete this task.")) - return TRUE - playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) - visible_message(SPAN_NOTICE("\The [user] starts slicing apart \the [src] with \the [welder].")) - if(!do_after(user, 3 SECONDS, src) || QDELETED(src) || !welder.remove_fuel(5, user)) - return TRUE - playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) - visible_message(SPAN_NOTICE("\The [user] completely dismantles \the [src] with \the [welder].")) - dismantle() - return TRUE + return welder_dismantle(user, welder) return FALSE /obj/structure/proc/handle_default_crowbar_attackby(var/mob/user, var/obj/item/crowbar) if((tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) && can_dismantle(user)) - if(material && material.removed_by_welder) - to_chat(user, SPAN_WARNING("\The [src] is too robust to be dismantled with \the [crowbar]; try a welding tool.")) - return TRUE - playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) - visible_message(SPAN_NOTICE("\The [user] starts levering apart \the [src] with \the [crowbar].")) - if(!do_after(user, 5 SECONDS, src) || QDELETED(src)) - return TRUE - playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) - visible_message(SPAN_NOTICE("\The [user] completely dismantles \the [src] with \the [crowbar].")) - dismantle() - return TRUE + return tool_dismantle(user, crowbar) return FALSE /obj/structure/proc/handle_default_cable_attackby(var/mob/user, var/obj/item/stack/cable_coil/coil) if((tool_interaction_flags & TOOL_INTERACTION_WIRING) && anchored) - if(wired) - to_chat(user, SPAN_WARNING("\The [src] has already been wired.")) - return TRUE - var/obj/item/stack/cable_coil/cable = coil - if(cable.get_amount() < 1) - to_chat(user, SPAN_WARNING("You need one length of coil to wire \the [src].")) - else - visible_message(SPAN_NOTICE("\The [user] starts to wire \the [src].")) - if(do_after(user, 4 SECONDS, src) && !wired && anchored && !QDELETED(src) && cable.use(1)) - wired = TRUE - visible_message(SPAN_NOTICE("\The [user] finishes wiring \the [src].")) - return TRUE + return install_wiring(user, coil) return FALSE -/obj/structure/proc/handle_default_wirecutter_attackby(var/mob/user, var/obj/item/wirecutters/wirecutters) +/obj/structure/proc/handle_default_wirecutter_attackby(var/mob/user, var/obj/item/wirecutters) if((tool_interaction_flags & TOOL_INTERACTION_WIRING) && anchored) - if(!wired) - to_chat(user, SPAN_WARNING("\The [src] has not been wired.")) - return TRUE - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] begins stripping the wiring out of \the [src].")) - if(do_after(user, 4 SECONDS, src) && !QDELETED(src) && wired) - visible_message(SPAN_NOTICE("\The [user] finishes stripping the wiring from \the [src].")) - new/obj/item/stack/cable_coil(src.loc, 1) - wired = FALSE - return TRUE + return strip_wiring(user, wirecutters) return FALSE /obj/structure/proc/handle_default_screwdriver_attackby(var/mob/user, var/obj/item/screwdriver) @@ -91,10 +37,10 @@ return TRUE /obj/structure/proc/can_dismantle(var/mob/user) - if(!anchored) + if(!anchored && (tool_interaction_flags & TOOL_INTERACTION_ANCHOR)) to_chat(user, SPAN_WARNING("\The [src] needs to be anchored before you can dismantle it.")) return FALSE - if(wired) + if(wired && (tool_interaction_flags & TOOL_INTERACTION_WIRING)) to_chat(user, SPAN_WARNING("\The [src] needs to have its wiring stripped out before you can dismantle it.")) return FALSE return TRUE @@ -103,38 +49,165 @@ . = istype(tool, /obj/item/stack/material) && tool.get_material_type() == get_material_type() /obj/structure/proc/handle_repair(mob/user, obj/item/tool) + var/current_max_health = get_max_health() var/obj/item/stack/stack = tool - var/amount_needed = ceil((maxhealth - health)/DOOR_REPAIR_AMOUNT) + var/amount_needed = ceil((current_max_health - current_health)/DOOR_REPAIR_AMOUNT) var/used = min(amount_needed,stack.amount) if(used) - to_chat(user, SPAN_NOTICE("You fit [used] [stack.singular_name]\s to damaged areas of \the [src].")) + to_chat(user, SPAN_NOTICE("You fit [stack.get_string_for_amount(used)] to damaged areas of \the [src].")) stack.use(used) last_damage_message = null - health = between(health, health + used*DOOR_REPAIR_AMOUNT, maxhealth) - -/obj/structure/attackby(obj/item/O, mob/user) - - if(O.force && user.a_intent == I_HURT) - attack_animation(user) - visible_message(SPAN_DANGER("\The [src] has been [pick(O.attack_verb)] with \the [O] by \the [user]!")) - playsound(loc, hitsound, 100, 1) - take_damage(O.force) - . = TRUE - - else if(isWrench(O)) - . = handle_default_wrench_attackby(user, O) - else if(isScrewdriver(O)) - . = handle_default_screwdriver_attackby(user, O) - else if(isWelder(O)) - . = handle_default_welder_attackby(user, O) - else if(isCrowbar(O)) - . = handle_default_crowbar_attackby(user, O) - else if(isCoil(O)) - . = handle_default_cable_attackby(user, O) - else if(isWirecutter(O)) - . = handle_default_wirecutter_attackby(user, O) - else if(can_repair_with(O) && can_repair(user)) - . = handle_repair(user, O) + current_health = clamp(current_health + used*DOOR_REPAIR_AMOUNT, current_health, current_max_health) + +/obj/structure/attackby(obj/item/used_item, mob/user) + + // We do this here to avoid putting the vessel straight into storage. + // This is usually handled by afterattack on /chems. + if(storage && !isnull(get_possible_reagent_transfer_amounts()) && ATOM_IS_OPEN_CONTAINER(used_item) && user.check_intent(I_FLAG_HELP)) + if(used_item.standard_dispenser_refill(user, src)) + return TRUE + if(used_item.standard_pour_into(user, src)) + return TRUE + + if(used_item.user_can_attack_with(user, silent = TRUE)) + var/force = used_item.expend_attack_force(user) + if(force && user.check_intent(I_FLAG_HARM)) + attack_animation(user) + visible_message(SPAN_DANGER("\The [src] has been [used_item.pick_attack_verb()] with \the [used_item] by \the [user]!")) + take_damage(force, used_item.atom_damage_type) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + add_fingerprint(user) + return TRUE + + // This handles standard tool interactions (anchoring, dismantling), calls below are for legacy purposes. + . = ..() + if(.) + return + + if(IS_HAMMER(used_item)) + . = handle_default_hammer_attackby(user, used_item) + else if(IS_WRENCH(used_item)) + . = handle_default_wrench_attackby(user, used_item) + else if(IS_SCREWDRIVER(used_item)) + . = handle_default_screwdriver_attackby(user, used_item) + else if(IS_WELDER(used_item)) + . = handle_default_welder_attackby(user, used_item) + else if(IS_CROWBAR(used_item)) + . = handle_default_crowbar_attackby(user, used_item) + else if(IS_COIL(used_item)) + . = handle_default_cable_attackby(user, used_item) + else if(IS_WIRECUTTER(used_item)) + . = handle_default_wirecutter_attackby(user, used_item) + else if(can_repair_with(used_item) && can_repair(user)) + . = handle_repair(user, used_item) if(.) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) add_fingerprint(user) + +/obj/structure/attack_generic(var/mob/user, var/damage, var/attack_verb, var/environment_smash) + if(environment_smash >= 1) + damage = max(damage, 10) + + if(istype(user)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(src) + if(!damage) + return FALSE + if(damage >= 10) + visible_message(SPAN_DANGER("\The [user] [attack_verb] into [src]!")) + take_damage(damage) + else + visible_message(SPAN_NOTICE("\The [user] bonks \the [src] harmlessly.")) + return TRUE + +/obj/structure/proc/strip_wiring(mob/user, obj/item/wirecutters) + if(!wired) + to_chat(user, SPAN_WARNING("\The [src] has not been wired.")) + return TRUE + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + visible_message(SPAN_NOTICE("\The [user] begins stripping the wiring out of \the [src].")) + if(do_after(user, 4 SECONDS, src) && !QDELETED(src) && wired) + visible_message(SPAN_NOTICE("\The [user] finishes stripping the wiring from \the [src].")) + new/obj/item/stack/cable_coil(src.loc, 1) + wired = FALSE + return TRUE + +/obj/structure/proc/install_wiring(mob/user, obj/item/stack/cable_coil/coil) + if(wired) + to_chat(user, SPAN_WARNING("\The [src] has already been wired.")) + return TRUE + var/obj/item/stack/cable_coil/cable = coil + if(cable.get_amount() < 1) + to_chat(user, SPAN_WARNING("You need one length of coil to wire \the [src].")) + else + visible_message(SPAN_NOTICE("\The [user] starts to wire \the [src].")) + if(do_after(user, 4 SECONDS, src) && !wired && anchored && !QDELETED(src) && cable.use(1)) + wired = TRUE + visible_message(SPAN_NOTICE("\The [user] finishes wiring \the [src].")) + return TRUE + + +/obj/structure/proc/handle_default_hammer_attackby(var/mob/user, var/obj/item/hammer) + + // Resolve ambiguous interactions. + var/can_deconstruct = (tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) && can_dismantle(user) + var/can_unanchor = (tool_interaction_flags & TOOL_INTERACTION_ANCHOR) && can_unanchor(user) + if(can_deconstruct && can_unanchor) + var/choice = alert(user, "Do you wish to [anchored ? "unanchor" : "anchor"] or dismantle this structure?", "Tool Choice", (anchored ? "Unanchor" : "Anchor"), "Deconstruct", "Cancel") + if(!choice || choice == "Cancel" || QDELETED(src) || QDELETED(user) || QDELETED(hammer) || !CanPhysicallyInteract(user) || user.get_active_held_item() != hammer) + return TRUE + if(choice == "Deconstruct") + can_unanchor = FALSE + else + can_deconstruct = FALSE + + if(can_unanchor) + return tool_toggle_anchors(user, hammer, anchor_sound = 'sound/items/Deconstruct.ogg') + + if(can_deconstruct) + return tool_dismantle(user, hammer, deconstruct_string = "knocking apart") + + return FALSE + +/obj/structure/proc/tool_dismantle(mob/user, obj/item/tool, dismantle_sound = 'sound/items/Crowbar.ogg', deconstruct_string = "levering apart") + if(material && material.removed_by_welder) + to_chat(user, SPAN_WARNING("\The [src] is too robust to be dismantled with \the [tool]; try a welding tool.")) + return TRUE + playsound(loc, dismantle_sound, 50, 1) + visible_message(SPAN_NOTICE("\The [user] starts [deconstruct_string] \the [src] with \the [tool].")) + if(!do_after(user, 5 SECONDS, src) || QDELETED(src)) + return TRUE + playsound(loc, dismantle_sound, 50, 1) + visible_message(SPAN_NOTICE("\The [user] completely dismantles \the [src] with \the [tool].")) + dismantle_structure(user) + return TRUE + +/obj/structure/proc/welder_dismantle(mob/user, obj/item/weldingtool/welder) + if(material && !material.removed_by_welder) + to_chat(user, SPAN_WARNING("\The [src] is too delicate to be dismantled with \the [welder]; try a crowbar.")) + return TRUE + if(!welder.isOn()) + to_chat(user, SPAN_WARNING("Try lighting \the [welder] first.")) + return TRUE + if(welder.get_fuel() < 5) + to_chat(user, SPAN_WARNING("You need more fuel to complete this task.")) + return TRUE + playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) + visible_message(SPAN_NOTICE("\The [user] starts slicing apart \the [src] with \the [welder].")) + if(!do_after(user, 3 SECONDS, src) || QDELETED(src) || !welder.weld(5, user)) + return TRUE + playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1) + visible_message(SPAN_NOTICE("\The [user] completely dismantles \the [src] with \the [welder].")) + dismantle_structure(user) + return TRUE + +/obj/structure/proc/tool_toggle_anchors(mob/user, obj/item/tool, anchor_sound = 'sound/items/Ratchet.ogg') + playsound(src.loc, anchor_sound, 100, 1) + visible_message(SPAN_NOTICE("\The [user] begins [anchored ? "unsecuring [src]" : "securing [src] in place"] with \the [tool].")) + if(!do_after(user, 4 SECONDS, src) || QDELETED(src)) + return TRUE + playsound(src.loc, anchor_sound, 100, 1) + anchored = !anchored + visible_message(SPAN_NOTICE("\The [user] has [anchored ? "secured" : "unsecured"] \the [src] with \the [tool].")) + update_icon() + return TRUE diff --git a/code/game/objects/structures/_structure_icon.dm b/code/game/objects/structures/_structure_icon.dm index 00a4e9aa3b82..966df9a1cc4c 100644 --- a/code/game/objects/structures/_structure_icon.dm +++ b/code/game/objects/structures/_structure_icon.dm @@ -1,13 +1,19 @@ -GLOBAL_LIST_INIT(default_blend_objects, list(/obj/machinery/door, /turf/simulated/wall)) -GLOBAL_LIST_INIT(default_noblend_objects, list(/obj/machinery/door/window, /obj/machinery/door/firedoor, /obj/machinery/door/blast)) +var/global/list/default_blend_objects = list(/obj/machinery/door, /turf/wall) +var/global/list/default_noblend_objects = list(/obj/machinery/door/window, /obj/machinery/door/firedoor, /obj/machinery/door/blast) /obj/structure var/handle_generic_blending /obj/structure/on_update_icon() + ..() if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - update_material_colour() - overlays.Cut() + update_material_color() + cut_overlays() + if(istype(lock)) + update_lock_overlay() + +/obj/structure/proc/update_lock_overlay() + return /obj/structure/proc/can_visually_connect() return anchored && handle_generic_blending @@ -27,15 +33,17 @@ GLOBAL_LIST_INIT(default_noblend_objects, list(/obj/machinery/door/window, /obj/ T.update_icon() /obj/structure/proc/find_blendable_obj_in_turf(var/turf/T, var/propagate) - if(is_type_in_list(T, GLOB.default_blend_objects)) - if(propagate && istype(T, /turf/simulated/wall)) - var/turf/simulated/wall/W = T - W.update_connections(1) + if(is_type_in_list(T, global.default_blend_objects)) + if(propagate && istype(T, /turf/wall)) + for(var/turf/wall/wall in RANGE_TURFS(T, 1)) + wall.wall_connections = null + wall.other_connections = null + wall.queue_icon_update() return TRUE for(var/obj/O in T) - if(!is_type_in_list(O, GLOB.default_blend_objects)) + if(!is_type_in_list(O, global.default_blend_objects)) continue - if(is_type_in_list(O, GLOB.default_noblend_objects)) + if(is_type_in_list(O, global.default_noblend_objects)) continue return TRUE return FALSE @@ -48,7 +56,8 @@ GLOBAL_LIST_INIT(default_noblend_objects, list(/obj/machinery/door/window, /obj/ var/list/dirs var/list/other_dirs - for(var/direction in GLOB.alldirs) + // TODO: Allow structures to limit dirs? + for(var/direction in global.alldirs) var/turf/T = get_step(src, direction) if(T) for(var/obj/structure/S in T) @@ -57,7 +66,7 @@ GLOBAL_LIST_INIT(default_noblend_objects, list(/obj/machinery/door/window, /obj/ S.update_connections() S.update_icon() LAZYADD(dirs, direction) - if((direction in GLOB.cardinal) && find_blendable_obj_in_turf(T, propagate)) + if((direction in global.cardinal) && find_blendable_obj_in_turf(T, propagate)) LAZYDISTINCTADD(dirs, direction) LAZYADD(other_dirs, direction) diff --git a/code/game/objects/structures/_structure_interactions.dm b/code/game/objects/structures/_structure_interactions.dm new file mode 100644 index 000000000000..ac17e0641db5 --- /dev/null +++ b/code/game/objects/structures/_structure_interactions.dm @@ -0,0 +1,74 @@ +// Anchoring or unanchoring with a hammer or a wrench. +/decl/interaction_handler/structure + abstract_type = /decl/interaction_handler/structure + expected_target_type = /obj/structure + +/decl/interaction_handler/structure/unanchor + name = "Toggle Anchoring" + examine_desc = "anchor or unanchor $TARGET_THEM$" + +/decl/interaction_handler/structure/unanchor/is_possible(atom/target, mob/user, obj/item/prop) + if(!(. = ..())) + return + var/obj/structure/struct = target + if(!(struct.tool_interaction_flags & TOOL_INTERACTION_ANCHOR) || !struct.can_unanchor(user)) + return FALSE + return istype(prop) && (IS_WRENCH(prop) || IS_HAMMER(prop)) + +/decl/interaction_handler/structure/unanchor/invoked(atom/target, mob/user, obj/item/prop) + . = ..() + var/obj/structure/struct = target + return struct.tool_toggle_anchors(user, prop) + +// Removing wiring with wirecutters or installing it with a cable coil. +/decl/interaction_handler/structure/wiring + name = "Modify Wiring" + examine_desc = "strip or install wiring" + +/decl/interaction_handler/structure/wiring/is_possible(atom/target, mob/user, obj/item/prop) + if(!(. = ..())) + return + var/obj/structure/struct = target + if(!(struct.tool_interaction_flags & TOOL_INTERACTION_WIRING)) + return FALSE + if(struct.wired) + return IS_WIRECUTTER(prop) + return IS_COIL(prop) + +/decl/interaction_handler/structure/wiring/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/struct = target + if(struct.wired) + return struct.strip_wiring(user, prop) + return struct.install_wiring(user, prop) + +// Dismantling a structure. +/decl/interaction_handler/structure/dismantle + name = "Dismantle Structure" + examine_desc = "dismantle $TARGET_THEM$" + +/decl/interaction_handler/structure/dismantle/is_possible(atom/target, mob/user, obj/item/prop) + if(!(. = ..())) + return + var/obj/structure/struct = target + if(!(struct.tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) || !struct.can_dismantle(user)) + return FALSE + return IS_WELDER(prop) || IS_CROWBAR(prop) || IS_HAMMER(prop) + +/decl/interaction_handler/structure/dismantle/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/struct = target + if(IS_WELDER(prop)) + return struct.welder_dismantle(user, prop) + return struct.tool_dismantle(user, prop) + +/decl/interaction_handler/put_in_storage + name = "Put In Storage" + +/decl/interaction_handler/put_in_storage/is_possible(atom/target, mob/user, obj/item/prop) + return ..() && istype(prop) && target.storage + +// Boilerplate from /atom/proc/attackby(), replicated here so tool interactions can be bypassed. +/decl/interaction_handler/put_in_storage/invoked(atom/target, mob/user, obj/item/prop) + if((isrobot(user) && (prop == user.get_active_held_item())) || !target.storage.can_be_inserted(prop, user)) + return FALSE + prop.add_fingerprint(user) + return target.storage.handle_item_insertion(user, prop) diff --git a/code/game/objects/structures/_structure_lock.dm b/code/game/objects/structures/_structure_lock.dm new file mode 100644 index 000000000000..2713beb48b3a --- /dev/null +++ b/code/game/objects/structures/_structure_lock.dm @@ -0,0 +1,51 @@ +/obj/structure + var/datum/lock/lock + +/obj/structure/proc/try_key_unlock(obj/item/used_item, mob/user) + if(!lock) + return FALSE + if(!used_item.user_can_attack_with(user)) + return FALSE + if(istype(used_item, /obj/item/key)) + if(lock.toggle(used_item)) + to_chat(user, SPAN_NOTICE("You [lock.status ? "lock" : "unlock"] \the [src] with \the [used_item].")) + else + to_chat(user, SPAN_WARNING("\The [used_item] does not fit in the lock!")) + return TRUE + if(istype(used_item, /obj/item/keyring)) + for(var/obj/item/key/key in used_item) + if(lock.toggle(key)) + to_chat(user, SPAN_NOTICE("You [lock.status ? "lock" : "unlock"] \the [src] with \the [key].")) + return TRUE + to_chat(user, SPAN_WARNING("\The [used_item] has no keys that fit in the lock!")) + return TRUE + if(lock.pick_lock(used_item,user)) + return TRUE + if(lock.isLocked()) + to_chat(user, SPAN_WARNING("\The [src] is locked!")) + return TRUE + return FALSE + +/obj/structure/proc/can_install_lock() + return FALSE + +/obj/structure/proc/try_install_lock(obj/item/I, mob/user) + if(!istype(I, /obj/item/lock_construct) || !can_install_lock()) + return FALSE + if(lock) + to_chat(user, SPAN_WARNING("\The [src] already has a lock.")) + else + var/obj/item/lock_construct/L = I + lock = L.create_lock(src,user) + return TRUE + +/obj/structure/proc/try_unlock(mob/user, obj/item/held) + if(!istype(user) || !istype(held) || !lock) + return FALSE + if(!lock.isLocked()) + return TRUE + if(user?.check_intent(I_FLAG_HELP) && (istype(held, /obj/item/key) || istype(held, /obj/item/keyring))) + try_key_unlock(held, user) + if(!lock.isLocked()) + return TRUE + return FALSE diff --git a/code/game/objects/structures/_structure_materials.dm b/code/game/objects/structures/_structure_materials.dm index 15c5d7db234f..ccb8ddf43076 100644 --- a/code/game/objects/structures/_structure_materials.dm +++ b/code/game/objects/structures/_structure_materials.dm @@ -1,11 +1,9 @@ /obj/structure - var/decl/material/material - var/decl/material/reinf_material var/material_alteration var/dismantled - -/obj/structure/get_material() - . = material + var/name_prefix + /// The base alpha used to calculate material-based alpha in update_material_color(). + var/base_alpha = 50 /obj/structure/proc/get_material_health_modifier() . = 1 @@ -15,57 +13,95 @@ update_material_name() if(material_alteration & MAT_FLAG_ALTERATION_DESC) update_material_desc() - if(material?.opacity < 0.5) + if(material_alteration & MAT_FLAG_ALTERATION_COLOR) + update_material_color() + if((alpha / 255) < 0.5) set_opacity(FALSE) else set_opacity(initial(opacity)) + if(isnull(initial(paint_verb)) && !isnull(material)) + paint_verb = material.paint_verb hitsound = material?.hitsound || initial(hitsound) - if(maxhealth != -1) - maxhealth = initial(maxhealth) + material?.integrity*get_material_health_modifier() + if(max_health != -1) + max_health = initial(max_health) + material?.integrity * get_material_health_modifier() if(reinf_material) var/bonus_health = reinf_material.integrity * get_material_health_modifier() - maxhealth += bonus_health + max_health += bonus_health if(!keep_health) - health += bonus_health - health = keep_health ? min(health, maxhealth) : maxhealth - - queue_icon_update() + current_health += bonus_health + current_health = keep_health ? min(current_health, max_health) : max_health + update_icon() /obj/structure/proc/update_material_name(var/override_name) var/base_name = override_name || initial(name) - if(istype(material)) - SetName("[material.solid_name] [base_name]") + var/new_name + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_NAME)) + new_name = "[material.adjective_name] [base_name]" else - SetName(base_name) + new_name = base_name + if(name_prefix) + new_name = "[name_prefix] [new_name]" + SetName(new_name) /obj/structure/proc/update_material_desc(var/override_desc) var/base_desc = override_desc || initial(desc) - if(istype(material)) + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_DESC)) desc = "[base_desc] This one is made of [material.solid_name]." else desc = base_desc -/obj/structure/proc/update_material_colour(var/override_colour) - var/base_colour = override_colour || initial(color) +/obj/structure/proc/update_material_color() + color = get_color() if(istype(material)) - color = material.color + alpha = clamp((base_alpha + material.opacity * 255), 0, 255) else - color = base_colour + alpha = initial(alpha) + +///Spawns a single part_type part, returns the result. Allows overriding spawning the actual part and it's constructor args. +/obj/structure/proc/create_dismantled_part(var/turf/T) + return new parts_type(T, (material && material.type), (reinf_material && reinf_material.type)) /obj/structure/proc/create_dismantled_products(var/turf/T) - if(parts_type) - new parts_type(T, (material && material.type), (reinf_material && reinf_material.type)) - else - if(material) - material.place_dismantled_product(T) - if(reinf_material) - reinf_material.place_dismantled_product(T) + SHOULD_CALL_PARENT(TRUE) + if(parts_type && !ispath(parts_type, /obj/item/stack)) + for(var/i = 1 to max(parts_amount, 1)) + LAZYADD(., create_dismantled_part(T)) + return + + for(var/mat in matter) + + var/decl/material/M = GET_DECL(mat) + var/placing + if(isnull(parts_amount)) + placing = (matter[mat] / SHEET_MATERIAL_AMOUNT) * 0.75 + if(material == M && parts_type) + placing *= atom_info_repository.get_matter_multiplier_for(parts_type, mat, placing) + placing = floor(placing) + else + placing = parts_amount + + if(placing > 0) + if(material == M) + LAZYADD(., M.place_dismantled_product(T, FALSE, placing, parts_type)) + else + LAZYADD(., M.place_dismantled_product(T, FALSE, placing)) + +/obj/structure/proc/clear_materials() + matter = null + material = null + reinf_material = null -/obj/structure/proc/dismantle() +/obj/structure/proc/dismantle_structure(mob/user) SHOULD_CALL_PARENT(TRUE) if(!dismantled) dismantled = TRUE - create_dismantled_products(get_turf(src)) + var/list/products = create_dismantled_products(get_turf(src)) + if(paint_color && length(products)) + for(var/obj/product in products) + if((isitem(product) || istype(product, /obj/structure)) && product.get_material() == material) + product.set_color(paint_color) + clear_materials() + dump_contents() if(!QDELETED(src)) qdel(src) . = TRUE diff --git a/code/game/objects/structures/_structure_serde.dm b/code/game/objects/structures/_structure_serde.dm new file mode 100644 index 000000000000..1f69c1294225 --- /dev/null +++ b/code/game/objects/structures/_structure_serde.dm @@ -0,0 +1,3 @@ +/obj/structure/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(paint_verb, /obj/structure) diff --git a/code/game/objects/structures/ai_decoy.dm b/code/game/objects/structures/ai_decoy.dm index d0ae8f45f5cc..5135856258f4 100644 --- a/code/game/objects/structures/ai_decoy.dm +++ b/code/game/objects/structures/ai_decoy.dm @@ -2,4 +2,4 @@ name = "\improper AI" icon = 'icons/mob/AI.dmi' icon_state = "ai" - anchored = 1 \ No newline at end of file + anchored = TRUE \ No newline at end of file diff --git a/code/game/objects/structures/armor_stand.dm b/code/game/objects/structures/armor_stand.dm new file mode 100644 index 000000000000..7dabc4c24f02 --- /dev/null +++ b/code/game/objects/structures/armor_stand.dm @@ -0,0 +1,76 @@ +/obj/structure/armor_stand + name = "armor stand" + desc = "A simple stand used to hold armor and helmets for display." + icon = 'icons/obj/structures/armor_stand.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + var/list/slots_to_gear = list( + (slot_wear_suit_str) = null, + (slot_head_str) = null, + (slot_belt_str) = null, + (slot_shoes_str) = null, + (slot_gloves_str) = null + ) + var/list/gear_to_slot + +/obj/structure/armor_stand/Exited(atom/movable/AM, atom/new_loc) + . = ..() + var/weakref/atom_ref = weakref(AM) + if(atom_ref in gear_to_slot) + var/slot = gear_to_slot[atom_ref] + slots_to_gear[slot] = null + LAZYREMOVE(gear_to_slot, atom_ref) + update_icon() + +/obj/structure/armor_stand/Destroy() + slots_to_gear.Cut() + LAZYCLEARLIST(gear_to_slot) + . = ..() + +/obj/structure/armor_stand/attack_hand(mob/user) + . = ..() + if(. || !LAZYLEN(gear_to_slot)) + return + var/weakref/removed_item_ref + if(LAZYLEN(gear_to_slot) == 1) + removed_item_ref = gear_to_slot[1] + else + removed_item_ref = input(user, "Which piece of equipment would you like to remove?", "Armor Stand") as null|anything in gear_to_slot + if(!CanPhysicallyInteract(user) || QDELETED(src) || QDELETED(user) || !(removed_item_ref in gear_to_slot)) + return TRUE + var/obj/item/removed_item = removed_item_ref?.resolve() + if(istype(removed_item) && !QDELETED(removed_item) && removed_item.loc == src) + removed_item.dropInto(loc) + user.put_in_hands(removed_item) + return TRUE + +/obj/structure/armor_stand/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/clothing)) + var/obj/item/clothing/clothes = used_item + if(!(clothes.fallback_slot in slots_to_gear)) + to_chat(user, SPAN_WARNING("\The [src] cannot hold \the [used_item].")) + else if(slots_to_gear[clothes.fallback_slot]) + var/weakref/atom_ref = slots_to_gear[clothes.fallback_slot] + to_chat(user, SPAN_WARNING("\The [src] is already holding \the [atom_ref.resolve()].")) + else if(user.try_unequip(clothes, src)) + var/weakref/atom_ref = weakref(clothes) + slots_to_gear[clothes.fallback_slot] = atom_ref + LAZYSET(gear_to_slot, atom_ref, clothes.fallback_slot) + to_chat(user, SPAN_NOTICE("You hang \the [clothes] from \the [src].")) + update_icon() + return TRUE + return ..() + +/obj/structure/armor_stand/on_update_icon() + . = ..() + for(var/slot in slots_to_gear) + var/weakref/atom_ref = slots_to_gear[slot] + var/obj/item/thing = atom_ref?.resolve() + if(istype(thing)) + var/image/mob_overlay = thing.get_mob_overlay(null, slot) + mob_overlay.appearance_flags |= RESET_COLOR + add_overlay(mob_overlay) + compile_overlays() diff --git a/code/game/objects/structures/barrels/barrel.dm b/code/game/objects/structures/barrels/barrel.dm new file mode 100644 index 000000000000..25f8d585eadf --- /dev/null +++ b/code/game/objects/structures/barrels/barrel.dm @@ -0,0 +1,135 @@ +/obj/structure/reagent_dispensers/barrel + name = "barrel" + desc = "A stout barrel for storing large amounts of liquids or substances." + icon = 'icons/obj/structures/barrels/barrel.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + matter = null + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + wrenchable = FALSE + storage = /datum/storage/barrel + amount_dispensed = 10 + chem_volume = 7500 + movable_flags = MOVABLE_FLAG_WHEELED + throwpass = TRUE + tool_interaction_flags = TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT + // Should we draw our lid and liquid contents as overlays? + var/show_liquid_contents = TRUE + // Rivets, bands, etc. Currently just cosmetic unless the forging modpack is ticked. + var/decl/material/metal_material = /decl/material/solid/metal/iron + +// Stub type for crafting (forging modpack modifies metal_material) +/obj/structure/reagent_dispensers/barrel/crafted + +// Overrides due to wonky reagent_dispeners opencontainer flag handling. +/obj/structure/reagent_dispensers/barrel/can_be_poured_from(mob/user, atom/target) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) +/obj/structure/reagent_dispensers/barrel/can_be_poured_into(mob/user, atom/target) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) + +// Override to skip open container check. +/obj/structure/reagent_dispensers/barrel/can_drink_from(mob/user) + return REAGENT_TOTAL_VOLUME(reagents) && user.check_has_mouth() + +/obj/structure/reagent_dispensers/barrel/Initialize() + if(ispath(metal_material)) + metal_material = GET_DECL(metal_material) + if(!istype(metal_material)) + metal_material = null + . = ..() + if(. == INITIALIZE_HINT_NORMAL && storage) + return INITIALIZE_HINT_LATELOAD // we want to grab our turf contents. + +/obj/structure/reagent_dispensers/barrel/LateInitialize(mapload, ...) + ..() + if(mapload) + for(var/obj/item/thing in loc) + if(!thing.simulated || thing.anchored) + continue + if(storage.can_be_inserted(thing, null)) + storage.handle_item_insertion(null, thing) + +/obj/structure/reagent_dispensers/barrel/on_reagent_change() + if(!(. = ..()) || QDELETED(src)) + return + var/primary_mat = reagents?.get_primary_reagent_name() + if(primary_mat) + update_material_name("[initial(name)] of [primary_mat]") + else + update_material_name() + update_icon() + +/obj/structure/reagent_dispensers/barrel/on_update_icon() + + . = ..() + + // Layer below lid/lid metal. + if(metal_material) + add_overlay(overlay_image(icon, "[icon_state]-metal", metal_material.color, RESET_COLOR)) + + // Add lid/reagents overlay/lid metal. + if(show_liquid_contents && ATOM_IS_OPEN_CONTAINER(src)) + if(reagents) + var/overlay_amount = NONUNIT_CEILING(REAGENT_TOTAL_LIQUID_VOLUME(reagents) / REAGENT_MAXIMUM_VOLUME(reagents) * 100, 10) + var/image/filling_overlay = overlay_image(icon, "[icon_state]-[overlay_amount]", reagents.get_color(), RESET_COLOR | RESET_ALPHA) + add_overlay(filling_overlay) + add_overlay(overlay_image(icon, "[icon_state]-lidopen", material?.color, RESET_COLOR)) + if(metal_material) + add_overlay(overlay_image(icon, "[icon_state]-lidopen-metal", metal_material.color, RESET_COLOR)) + else + add_overlay(overlay_image(icon, "[icon_state]-lidclosed", material?.color, RESET_COLOR)) + if(metal_material) + add_overlay(overlay_image(icon, "[icon_state]-lidclosed-metal", metal_material.color, RESET_COLOR)) + + if(istype(loc, /obj/structure/cask_rack)) + loc.update_icon() + +/obj/structure/reagent_dispensers/barrel/get_standard_interactions(var/mob/user) + . = ..() + if(REAGENT_MAXIMUM_VOLUME(reagents)) + LAZYADD(., global._reagent_interactions) + + // Disambiguation actions, since barrels can have several different potential interactions for + // the same item. It would be nice to enable this on /obj/structure in general but there are a + // ton of really bespoke overrides of the standard tool methods (windows, AI core, etc.). + if(tool_interaction_flags & TOOL_INTERACTION_ANCHOR) + LAZYADD(., /decl/interaction_handler/structure/unanchor) + if(tool_interaction_flags & TOOL_INTERACTION_WIRING) + LAZYADD(., /decl/interaction_handler/structure/wiring) + if(tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) + LAZYADD(., /decl/interaction_handler/structure/dismantle) + if(LAZYLEN(.) && storage) + LAZYADD(., /decl/interaction_handler/put_in_storage) + +// Copy of above - maybe we should just have a single 'get interactions' proc at this point? +/obj/structure/reagent_dispensers/barrel/get_alt_interactions(mob/user) + . = ..() + if(tool_interaction_flags & TOOL_INTERACTION_ANCHOR) + LAZYADD(., /decl/interaction_handler/structure/unanchor) + if(tool_interaction_flags & TOOL_INTERACTION_WIRING) + LAZYADD(., /decl/interaction_handler/structure/wiring) + if(tool_interaction_flags & TOOL_INTERACTION_DECONSTRUCT) + LAZYADD(., /decl/interaction_handler/structure/dismantle) + +/obj/structure/reagent_dispensers/barrel/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/reagent_dispensers/barrel/ebony/water/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/barrel/ebony/beer/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/alcohol/beer, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/barrel/ebony/wine/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/alcohol/wine, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/barrel/ebony/oil/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/oil, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/game/objects/structures/barrels/cask.dm b/code/game/objects/structures/barrels/cask.dm new file mode 100644 index 000000000000..7143cc94a952 --- /dev/null +++ b/code/game/objects/structures/barrels/cask.dm @@ -0,0 +1,45 @@ +/obj/structure/reagent_dispensers/barrel/cask + name = "cask" + desc = "A small barrel used to store moderate amounts of liquids or substances." + icon = 'icons/obj/structures/barrels/cask.dmi' + anchored = FALSE + show_liquid_contents = FALSE + storage = null // Intended for storing liquids. + +// Stub type for crafting (forging modpack modifies metal_material) +/obj/structure/reagent_dispensers/barrel/cask/crafted + +// Horrible workaround for physical interaction checks. +/obj/structure/reagent_dispensers/barrel/cask/nano_host() + return istype(loc, /obj/structure/cask_rack) ? loc : src + +/obj/structure/reagent_dispensers/barrel/cask/receive_mouse_drop(atom/dropping, mob/user, params) + if(istype(loc, /obj/structure/cask_rack)) + return loc.receive_mouse_drop(dropping, user, params) + return ..() + +/obj/structure/reagent_dispensers/barrel/cask/handle_mouse_drop(atom/over, mob/user, params) + var/obj/structure/cask_rack/rack = loc + if(istype(rack) && isturf(over) && user.Adjacent(over) && rack.Adjacent(over) && rack.try_unstack_barrel(src, over, user)) + return + return ..() + +/obj/structure/reagent_dispensers/barrel/cask/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/reagent_dispensers/barrel/cask/ebony/water/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/barrel/cask/ebony/beer/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/alcohol/beer, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/barrel/cask/ebony/wine/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/alcohol/wine, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/barrel/cask/ebony/oil/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/oil, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/game/objects/structures/barrels/cask_rack.dm b/code/game/objects/structures/barrels/cask_rack.dm new file mode 100644 index 000000000000..2dfbdc2d8e09 --- /dev/null +++ b/code/game/objects/structures/barrels/cask_rack.dm @@ -0,0 +1,170 @@ +/obj/structure/cask_rack + name = "cask rack" + desc = "A flat rack used to stop a cask from rolling around." + icon = 'icons/obj/structures/barrels/cask_rack.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + opacity = FALSE + density = FALSE // Recalculated when barrels added or removed + w_class = ITEM_SIZE_STRUCTURE + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + var/max_stack = 1 + +/obj/structure/cask_rack/Initialize(ml, _mat, _reinf_mat) + . = ..() + if(isturf(loc)) + for(var/atom/movable/stackable in loc) + if(try_stack_barrel(stackable) && length(contents) >= max_stack) + return + +/obj/structure/cask_rack/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(length(contents)) + . += SPAN_NOTICE("It contains [english_list(contents)].") + +/obj/structure/cask_rack/handle_mouse_drop(atom/over, mob/user, params) + if(isturf(over) && user.Adjacent(over) && Adjacent(over) && try_unstack_barrel(target = over, user = user)) + return + return ..() + +/obj/structure/cask_rack/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && user.Adjacent(src) && dropping.Adjacent(src) && user.Adjacent(dropping)) + return try_stack_barrel_timed(dropping, user) + +/obj/structure/cask_rack/on_update_icon() + . = ..() + if(length(contents)) + // Workaround for base color getting applied to vis_contents. + var/base_color = get_color() + color = null + var/image/I = image(icon, icon_state) + I.color = base_color + add_overlay(I) + // Reposition/update our contents. + var/i = 0 + var/list/stackable_types = get_stackable_barrel_types() + for(var/atom/movable/barrel in contents) + if(is_type_in_list(barrel, stackable_types)) + i++ + adjust_barrel_offsets(barrel, i) + else + color = get_color() + compile_overlays() // Avoid wonky flickering on contents changes + +/obj/structure/cask_rack/proc/adjust_barrel_offsets(atom/movable/barrel, barrel_position) + barrel.reset_offsets(anim_time = 0) + barrel.vis_flags |= (VIS_INHERIT_LAYER | VIS_INHERIT_PLANE) + +/obj/structure/cask_rack/Entered(atom/movable/AM, atom/old_loc) + . = ..() + if(istype(AM) && !QDELETED(AM) && is_type_in_list(AM, get_stackable_barrel_types())) + vis_contents |= AM + recalculate_barrel_values() + +/obj/structure/cask_rack/Exited(atom/movable/AM, atom/new_loc) + . = ..() + if(istype(AM) && is_type_in_list(AM, get_stackable_barrel_types())) + vis_contents -= AM + AM.vis_flags = initial(AM.vis_flags) + AM.reset_offsets(anim_time = 0) + recalculate_barrel_values() + +/obj/structure/cask_rack/proc/recalculate_barrel_values() + if(length(contents)) + density = TRUE + anchored = TRUE + obj_flags &= ~OBJ_FLAG_ANCHORABLE + atom_flags |= ATOM_FLAG_CLIMBABLE + else + density = FALSE + obj_flags |= OBJ_FLAG_ANCHORABLE + atom_flags &= ~ATOM_FLAG_CLIMBABLE + update_icon() + +/obj/structure/cask_rack/proc/try_unstack_barrel(atom/movable/barrel, turf/target, mob/user) + if(!loc) + return FALSE + if(!barrel) + if(!length(contents)) + to_chat(user, SPAN_WARNING("\The [src] has nothing stacked on it.")) + return FALSE + barrel = contents[length(contents)] + if(!istype(barrel) || !barrel.simulated) + return FALSE + if(target && (!isturf(target) || !loc.Adjacent(target))) // TODO: Enter() or CanPass() checks instead of relying on step_towards() below. + to_chat(user, SPAN_NOTICE("You cannot move \the [barrel] to \the [target].")) + return FALSE + if(user && !user.do_skilled(3 SECONDS, SKILL_HAULING, src)) + to_chat(user, SPAN_NOTICE("You stop moving \the [barrel] off of \the [src].")) + return FALSE + to_chat(user, SPAN_NOTICE("You move \the [barrel] off \the [src].")) + barrel.dropInto(loc) + if(target) + step_towards(barrel, target) + return TRUE + +/obj/structure/cask_rack/proc/can_stack_barrel(atom/movable/barrel, mob/user) + if(!istype(barrel) || !barrel.simulated || barrel.anchored) + return FALSE + if(length(contents) >= max_stack) + to_chat(user, SPAN_WARNING("\The [src] is already stacked to capacity.")) + return FALSE + var/list/stackable_types = get_stackable_barrel_types() + if(!is_type_in_list(barrel, stackable_types)) + to_chat(user, SPAN_WARNING("\The [src] cannot hold \the [barrel].")) + return FALSE + return TRUE + +/obj/structure/cask_rack/proc/try_stack_barrel(atom/movable/barrel, mob/user) + if(!can_stack_barrel(barrel, user)) + return FALSE + barrel.forceMove(src) + return TRUE + +/obj/structure/cask_rack/proc/try_stack_barrel_timed(atom/movable/barrel, mob/user) + if(!can_stack_barrel(barrel, user)) + return FALSE + if(user && !user.do_skilled(3 SECONDS, SKILL_HAULING, src)) + to_chat(user, SPAN_NOTICE("You stop stacking \the [barrel] onto \the [src].")) + return FALSE + if(try_stack_barrel(barrel, user)) + to_chat(user, SPAN_NOTICE("You stack \the [barrel] onto \the [src].")) + return TRUE + return FALSE + +/obj/structure/cask_rack/proc/get_stackable_barrel_types() + var/static/list/_stackable_barrel_types = list( + /obj/structure/reagent_dispensers/barrel/cask + ) + return _stackable_barrel_types + +// A larger stack, used to arrange up to three casks. +/obj/structure/cask_rack/large + name_prefix = "large" + desc = "A flat rack used to stop casks from rolling around." + max_stack = 3 + w_class = ITEM_SIZE_LARGE_STRUCTURE + icon = 'icons/obj/structures/barrels/cask_rack_large.dmi' + +/obj/structure/cask_rack/large/adjust_barrel_offsets(atom/movable/barrel, barrel_position) + ..() + switch(barrel_position) + if(1) + barrel.pixel_x -= 7 + if(2) + barrel.pixel_x += 7 + if(3) + barrel.pixel_y += 8 + +/obj/structure/cask_rack/large/mapped + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/cask_rack/large/mapped/Initialize(ml, _mat, _reinf_mat) + . = ..() + try_stack_barrel(new /obj/structure/reagent_dispensers/barrel/cask/ebony/water) + try_stack_barrel(new /obj/structure/reagent_dispensers/barrel/cask/ebony/beer) + try_stack_barrel(new /obj/structure/reagent_dispensers/barrel/cask/ebony/wine) diff --git a/code/game/objects/structures/barricade.dm b/code/game/objects/structures/barricade.dm index f009eac1c847..ece9d0fa5244 100644 --- a/code/game/objects/structures/barricade.dm +++ b/code/game/objects/structures/barricade.dm @@ -3,12 +3,12 @@ name = "barricade" icon = 'icons/obj/structures/barricade.dmi' icon_state = "barricade" - anchored = 1.0 - density = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + anchored = TRUE + density = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE layer = ABOVE_WINDOW_LAYER material_alteration = MAT_FLAG_ALTERATION_ALL - maxhealth = 100 + max_health = 100 var/spike_damage //how badly it smarts when you run into this like a rube var/list/poke_description = list("gored", "spiked", "speared", "stuck", "stabbed") @@ -18,12 +18,12 @@ /obj/structure/barricade/spike/Initialize() if(!reinf_material) - reinf_material = /decl/material/solid/wood + reinf_material = /decl/material/solid/organic/wood/oak . = ..() /obj/structure/barricade/Initialize() if(!material) - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak . = ..() if(!istype(material)) return INITIALIZE_HINT_QDEL @@ -45,24 +45,24 @@ ..() if(reinf_material) icon_state = "cheval" - overlays = overlay_image(icon, "cheval_spikes", color = reinf_material.color, flags = RESET_COLOR) + add_overlay(overlay_image(icon, "cheval_spikes", color = reinf_material.color, flags = RESET_COLOR)) else icon_state = "barricade" - -/obj/structure/barricade/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/stack/material/rods) && !reinf_material) - var/obj/item/stack/material/rods/R = W - if(R.get_amount() < 5) + +/obj/structure/barricade/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/stack/material/rods) && !reinf_material) + var/obj/item/stack/material/rods/rods = used_item + if(rods.get_amount() < 5) to_chat(user, SPAN_WARNING("You need more rods to build a cheval de frise.")) else visible_message(SPAN_NOTICE("\The [user] begins to work on \the [src].")) - if(do_after(user, 4 SECONDS, src) && !reinf_material && R.use(5)) - visible_message(SPAN_NOTICE("\The [user] fastens \the [R] to \the [src].")) - reinf_material = R.material + if(do_after(user, 4 SECONDS, src) && !reinf_material && rods.use(5)) + visible_message(SPAN_NOTICE("\The [user] fastens \the [rods] to \the [src].")) + reinf_material = rods.material update_materials(TRUE) . = ..() -/obj/structure/barricade/dismantle() +/obj/structure/barricade/dismantle_structure(mob/user) visible_message(SPAN_DANGER("The barricade is smashed apart!")) . = ..() @@ -71,7 +71,7 @@ if(QDELETED(src)) if(severity == 1) parts_type = null - physically_destroyed(src) + physically_destroyed() else if(severity == 2) take_damage(25) diff --git a/code/game/objects/structures/barsign.dm b/code/game/objects/structures/barsign.dm index d7567d4304f2..f3f0467e1a62 100644 --- a/code/game/objects/structures/barsign.dm +++ b/code/game/objects/structures/barsign.dm @@ -1,9 +1,12 @@ /obj/structure/sign/double/barsign + name = "barsign" desc = "A jumbo-sized LED sign. This one seems to be showing its age." icon = 'icons/obj/barsigns.dmi' icon_state = "empty" appearance_flags = 0 - anchored = 1 + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' var/cult = 0 /obj/structure/sign/double/barsign/proc/get_valid_states(initial=1) @@ -14,36 +17,36 @@ if(initial) . -= "Off" -/obj/structure/sign/double/barsign/examine(mob/user) +/obj/structure/sign/double/barsign/get_examine_strings(mob/user, distance, infix, suffix) . = ..() switch(icon_state) if("Off") - to_chat(user, "It appears to be switched off.") + . += "It appears to be switched off." if("narsiebistro") - to_chat(user, "It shows a picture of a large black and red being. Spooky!") + . += "It shows a picture of a large black and red being. Spooky!" if("on", "empty") - to_chat(user, "The lights are on, but there's no picture.") + . += "The lights are on, but there's no picture." else - to_chat(user, "It says '[icon_state]'") + . += "It says '[icon_state]'." /obj/structure/sign/double/barsign/Initialize() . = ..() icon_state = pick(get_valid_states()) -/obj/structure/sign/double/barsign/attackby(obj/item/I, mob/user) +/obj/structure/sign/double/barsign/attackby(obj/item/used_item, mob/user) if(cult) return ..() - var/obj/item/card/id/card = I.GetIdCard() + var/obj/item/card/id/card = used_item.GetIdCard() if(istype(card)) if(access_bar in card.GetAccess()) var/sign_type = input(user, "What would you like to change the barsign to?") as null|anything in get_valid_states(0) if(!sign_type) - return + return TRUE icon_state = sign_type to_chat(user, "You change the barsign.") else to_chat(user, "Access denied.") - return + return TRUE return ..() diff --git a/code/game/objects/structures/beds/bed.dm b/code/game/objects/structures/beds/bed.dm new file mode 100644 index 000000000000..058eff22fd9f --- /dev/null +++ b/code/game/objects/structures/beds/bed.dm @@ -0,0 +1,88 @@ +// Beds... get your mind out of the gutter, they're for sleeping! +/obj/structure/bed + name = "bed" + desc = "A raised, padded platform for sleeping on. This one has straps for ensuring restful snoozing in microgravity." + icon = 'icons/obj/structures/furniture/bed.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + can_buckle = TRUE + buckle_dir = SOUTH + buckle_lying = TRUE + buckle_sound = 'sound/effects/buckle.ogg' + material = DEFAULT_FURNITURE_MATERIAL + material_alteration = MAT_FLAG_ALTERATION_ALL + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + parts_amount = 2 + parts_type = /obj/item/stack/material/rods + user_comfort = 1 + obj_flags = OBJ_FLAG_SUPPORT_MOB + monetary_worth_multiplier = 2.5 // Utility structures should be worth more than their matter (wheelchairs, rollers, etc). + /// The padding extension type for this bed. If null, no extension is created and this bed cannot be padded. + var/padding_extension_type = /datum/extension/padding + var/decl/material/initial_padding_material + var/initial_padding_color + +/obj/structure/bed/Initialize(ml, _mat, _reinf_mat) + . = ..() + if(padding_extension_type && initial_padding_material) + get_or_create_extension(src, padding_extension_type, initial_padding_material, initial_padding_color) + +/obj/structure/bed/user_can_mousedrop_onto(mob/user, atom/being_dropped, incapacitation_flags, params) + if(user == being_dropped) + return user.Adjacent(src) && !user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT) + return ..() + +/obj/structure/bed/get_surgery_surface_quality(mob/living/victim, mob/living/user) + return OPERATE_PASSABLE + +/obj/structure/bed/get_surgery_success_modifier(delicate) + return delicate ? -5 : 0 + +/obj/structure/bed/update_material_name(override_name) + var/base_name = override_name || initial(name) + var/new_name = base_name + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + SetName("[padding_material.adjective_name] [base_name]") + else if(material) + new_name = "[material.adjective_name] [base_name]" + if(name_prefix) + new_name = "[name_prefix] [new_name]" + SetName(new_name) + +/obj/structure/bed/update_material_desc(override_desc) + var/base_desc = override_desc || initial(desc) + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + desc = "[base_desc] It's made of [material.use_name] and covered with [padding_material.use_name]." + else + desc = "[base_desc] It's made of [material.use_name]." + +/obj/structure/bed/on_update_icon() + ..() + icon_state = ICON_STATE_WORLD + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + add_overlay(overlay_image(icon, "[icon_state]_padding", material_alteration & MAT_FLAG_ALTERATION_COLOR ? padding_extension.get_padding_color() : null, RESET_COLOR|RESET_ALPHA)) + +// Used to allow things to pass over dense beds, e.g. rollerbeds, ironing boards +/obj/structure/bed/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return TRUE + return ..() + +/obj/structure/bed/psych + name = "psychiatrist's couch" + desc = "For prime comfort during psychiatric evaluations." + icon = 'icons/obj/structures/furniture/bed_psych.dmi' + material = /decl/material/solid/organic/wood/walnut + +/obj/structure/bed/psych/leather + initial_padding_material = /decl/material/solid/organic/leather + +/obj/structure/bed/padded + material = /decl/material/solid/metal/aluminium + initial_padding_material = /decl/material/solid/organic/cloth diff --git a/code/game/objects/structures/beds/bedroll.dm b/code/game/objects/structures/beds/bedroll.dm new file mode 100644 index 000000000000..27971d1b66f0 --- /dev/null +++ b/code/game/objects/structures/beds/bedroll.dm @@ -0,0 +1,127 @@ +/obj/item/bedroll + name = "bedroll" + desc = "A thick, padded bag big enough for a human to huddle in, rolled into a tight tube for easy-ish transport." + icon = 'icons/obj/structures/bedroll_rolled.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + material = /decl/material/solid/organic/leather + color = /decl/material/solid/organic/leather::color + material_alteration = MAT_FLAG_ALTERATION_ALL + var/padding_material + var/belt_color = COLOR_BEASTY_BROWN + var/structure_path = /obj/structure/bed/bedroll + +/obj/item/bedroll/fur + padding_material = /decl/material/solid/organic/skin/fur + +/obj/item/bedroll/Initialize() + // We need to set this initially so that we can pass it to our structure if we get unrolled. + // In cases where the structure was spawned first, it overwrites matter anyway. + if(padding_material) + LAZYSET(matter, padding_material, MATTER_AMOUNT_REINFORCEMENT) + . = ..() + update_icon() + +/obj/item/bedroll/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + add_overlay(overlay_image(icon, "[icon_state]-straps", belt_color, RESET_COLOR)) + +/obj/item/bedroll/attack_self(mob/user) + if(!user || !isturf(user?.loc)) + return ..() + if(locate(/obj/structure/bed) in user.loc) + to_chat(user, SPAN_WARNING("There's no room to unroll \the [src] here.")) + return TRUE + var/obj/structure/bed = new structure_path(user.loc, material?.type, padding_material) + user.visible_message(SPAN_NOTICE("\The [user] unrolls \the [src].")) + bed.matter = matter?.Copy() + qdel(src) + return TRUE + +/obj/structure/bed/bedroll + name = "bedroll" + desc = "A thick, padded bag big enough for a human to huddle in. It's better than sleeping on the ground." + user_comfort = 0.65 + icon = 'icons/obj/structures/bedroll.dmi' + w_class = ITEM_SIZE_LARGE + anchored = FALSE + material = /decl/material/solid/organic/leather + reinf_material = null + color = /decl/material/solid/organic/leather::color + tool_interaction_flags = TOOL_INTERACTION_NONE // just use your hand on it nerd + buckle_sound = "rustle" + var/item_path = /obj/item/bedroll + +/obj/structure/bed/bedroll/fur + reinf_material = /decl/material/solid/organic/skin/fur + color = /decl/material/solid/organic/skin/fur::color + +/obj/structure/bed/bedroll/show_buckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + visible_message( + SPAN_NOTICE("\The [buckled] climbs into \the [src]."), + SPAN_NOTICE("You climb into \the [src]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + else + var/decl/pronouns/pronouns = buckled.get_pronouns() + visible_message( + SPAN_NOTICE("\The [buckled] [pronouns.is] bundled into \the [src] by \the [buckling]."), + SPAN_NOTICE("You are bundled into \the [src] by \the [buckling]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + +/obj/structure/bed/bedroll/show_unbuckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + visible_message( + SPAN_NOTICE("\The [buckled] climbs out of \the [src]."), + SPAN_NOTICE("You climb out of \the [src]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + else + visible_message( + SPAN_NOTICE("\The [buckled] was pulled out of \the [src] by \the [buckling]."), + SPAN_NOTICE("You were pulled out of \the [src] by \the [buckling]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + +/obj/structure/bed/bedroll/on_update_icon() + . = ..() + var/image/I = overlay_image(icon, "[icon_state]_over") + I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER + add_overlay(I) + compile_overlays() + +/obj/structure/bed/bedroll/buckle_mob(mob/M) + . = ..() + if(.) + anchored = !!buckled_mob + update_icon() + +/obj/structure/bed/bedroll/unbuckle_mob() + . = ..() + if(.) + anchored = !!buckled_mob + update_icon() + +/obj/structure/bed/bedroll/attack_hand(mob/user) + . = ..() + if(!. && !buckled_mob) + roll_bed(user) + return TRUE + +/obj/structure/bed/bedroll/proc/roll_bed(mob/user) + visible_message(SPAN_NOTICE("\The [user] rolls up \the [src].")) + var/obj/item/bedroll/roll = new item_path(get_turf(src), material?.type) + roll.padding_material = reinf_material?.type + roll.matter = matter?.Copy() + user.put_in_hands(roll) + qdel(src) + return roll + +/obj/structure/bed/bedroll/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && Adjacent(src, user) && !user.incapacitated()) + roll_bed(user) + return TRUE + . = ..() diff --git a/code/game/objects/structures/beds/mattress.dm b/code/game/objects/structures/beds/mattress.dm new file mode 100644 index 000000000000..8532a77a9e1a --- /dev/null +++ b/code/game/objects/structures/beds/mattress.dm @@ -0,0 +1,15 @@ +/* + * Mattresses + */ +// TODO: These sprites are terrible. Replace? +/obj/structure/mattress + name = "mattress" + icon = 'icons/obj/furniture.dmi' + icon_state = "mattress" + desc = "A bare mattress. It doesn't look very comfortable." + anchored = FALSE + +/obj/structure/mattress/dirty + name = "dirty mattress" + icon_state = "dirty_mattress" + desc = "A dirty, smelly mattress covered in body fluids. You wouldn't want to touch this." diff --git a/code/game/objects/structures/beds/rollerbed.dm b/code/game/objects/structures/beds/rollerbed.dm new file mode 100644 index 000000000000..d7e7f102ec6d --- /dev/null +++ b/code/game/objects/structures/beds/rollerbed.dm @@ -0,0 +1,152 @@ +/* + * Roller beds + */ +/obj/structure/bed/roller + name = "roller bed" + icon = 'icons/obj/structures/rollerbed.dmi' + icon_state = "down" + anchored = FALSE + buckle_pixel_shift = list("x" = 0, "y" = 0, "z" = 6) + movable_flags = MOVABLE_FLAG_WHEELED + tool_interaction_flags = 0 + padding_extension_type = null // Cannot be padded. + var/item_form_type = /obj/item/roller //The folded-up object path. + var/obj/item/chems/beaker + var/iv_attached = 0 + var/iv_stand = TRUE + +// this completely circumvents normal bed icon updating, does this really even need to be a bed subtype? +/obj/structure/bed/roller/on_update_icon() + cut_overlays() + if(density) + icon_state = "up" + else + icon_state = "down" + if(beaker?.reagents) + var/image/iv = image(icon, "iv[iv_attached]") + var/percentage = round((REAGENT_TOTAL_VOLUME(beaker.reagents) / max(REAGENT_MAXIMUM_VOLUME(beaker.reagents), 1)) * 100, 25) + var/image/filling = image(icon, "iv_filling[percentage]") + filling.color = beaker.reagents.get_color() + iv.overlays += filling + if(percentage < 25) + iv.overlays += image(icon, "light_low") + if(density) + iv.pixel_y = 6 + add_overlay(iv) + +/obj/structure/bed/roller/attackby(obj/item/used_item, mob/user) + if(iv_stand && !beaker && istype(used_item, /obj/item/chems)) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, "You attach \the [used_item] to \the [src].") + beaker = used_item + queue_icon_update() + return TRUE + return ..() + +/obj/structure/bed/roller/attack_hand(mob/user) + if(!beaker || buckled_mob || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + remove_beaker(user) + return TRUE + +/obj/structure/bed/roller/proc/collapse(mob/user) + visible_message("[user] collapses [src].") + new item_form_type(get_turf(src)) + qdel(src) + +/obj/structure/bed/roller/post_buckle_mob(mob/living/M) + . = ..() + if(M == buckled_mob) + set_density(1) + queue_icon_update() + else + set_density(0) + if(iv_attached) + detach_iv(M, usr) + queue_icon_update() + +/obj/structure/bed/roller/Process() + if(!iv_attached || !buckled_mob || !beaker) + return PROCESS_KILL + + //SSObj fires twice as fast as SSMobs, so gotta slow down to not OD our victims. + if(SSobj.times_fired % 2) + return + + if(REAGENT_TOTAL_VOLUME(beaker.reagents) > 0) + beaker.reagents.trans_to_mob(buckled_mob, beaker.amount_per_transfer_from_this, CHEM_INJECT) + queue_icon_update() + +/obj/structure/bed/roller/proc/remove_beaker(mob/user) + to_chat(user, "You detach \the [beaker] to \the [src].") + iv_attached = FALSE + beaker.dropInto(loc) + beaker = null + queue_icon_update() + +/obj/structure/bed/roller/proc/attach_iv(mob/living/human/target, mob/user) + if(!beaker) + return + if(do_IV_hookup(target, user, beaker)) + iv_attached = TRUE + queue_icon_update() + START_PROCESSING(SSobj,src) + +/obj/structure/bed/roller/proc/detach_iv(mob/living/human/target, mob/user) + visible_message("\The [target] is taken off the IV on \the [src].") + iv_attached = FALSE + queue_icon_update() + STOP_PROCESSING(SSobj,src) + +/obj/structure/bed/roller/handle_mouse_drop(atom/over, mob/user, params) + if(ishuman(user) || isrobot(user)) + if(over == buckled_mob && beaker) + if(iv_attached) + detach_iv(buckled_mob, user) + else + attach_iv(buckled_mob, user) + return TRUE + if(ishuman(over)) + var/mob/M = over + if(loc == M.loc && user_buckle_mob(M, user)) + attach_iv(buckled_mob, user) + return TRUE + if(beaker) + remove_beaker(user) + return TRUE + if(!buckled_mob) + collapse(user) + return TRUE + . = ..() + +/obj/item/roller + name = "roller bed" + desc = "A collapsed roller bed that can be carried around." + icon = 'icons/obj/items/rollerbed.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_BACK + w_class = ITEM_SIZE_LARGE + pickup_sound = 'sound/foley/pickup2.ogg' + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/organic/cloth = MATTER_AMOUNT_REINFORCEMENT, + ) + var/structure_form_type = /obj/structure/bed/roller //The deployed form path. + +/obj/item/roller/get_single_monetary_worth() + . = structure_form_type ? atom_info_repository.get_combined_worth_for(structure_form_type) : ..() + +/obj/item/roller/attack_self(mob/user) + var/obj/structure/bed/roller/R = new structure_form_type(user.loc) + R.add_fingerprint(user) + qdel(src) + +/obj/item/robot_rack/roller + name = "roller bed rack" + desc = "A rack for carrying collapsed roller beds. Can also be used for carrying ironing boards." + icon = 'icons/obj/items/rollerbed.dmi' + icon_state = ICON_STATE_WORLD + object_type = /obj/item/roller + interact_type = /obj/structure/bed/roller \ No newline at end of file diff --git a/code/game/objects/structures/beds/simple_bed.dm b/code/game/objects/structures/beds/simple_bed.dm new file mode 100644 index 000000000000..31a656cfa0a8 --- /dev/null +++ b/code/game/objects/structures/beds/simple_bed.dm @@ -0,0 +1,61 @@ +/obj/structure/bed/simple + desc = "A slatted wooden bed." + icon = 'icons/obj/structures/furniture/bed_simple.dmi' + icon_state = "world_padded_preview" // For map editor preview purposes + parts_type = /obj/item/stack/material/plank + material = /decl/material/solid/organic/wood/oak + initial_padding_material = /decl/material/solid/organic/plantmatter/grass/dry + color = /decl/material/solid/organic/plantmatter/grass/dry::color + anchored = TRUE + user_comfort = 0.8 + buckle_sound = "rustle" + +/obj/structure/bed/simple/show_buckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + visible_message( + SPAN_NOTICE("\The [buckled] lies down on \the [src]."), + SPAN_NOTICE("You lie down on \the [src]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + else + var/decl/pronouns/pronouns = buckled.get_pronouns() + visible_message( + SPAN_NOTICE("\The [buckled] [pronouns.is] laid down on \the [src] by \the [buckling]."), + SPAN_NOTICE("You are laid down on \the [src] by \the [buckling]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + +/obj/structure/bed/simple/show_unbuckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + visible_message( + SPAN_NOTICE("\The [buckled] rises from \the [src]."), + SPAN_NOTICE("You rise from \the [src]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + else + visible_message( + SPAN_NOTICE("\The [buckled] was pulled off \the [src] by \the [buckling]."), + SPAN_NOTICE("You were pulled off \the [src] by \the [buckling]."), + SPAN_NOTICE("You hear a rustling sound.") + ) + +/obj/structure/bed/simple/ebony + material = /decl/material/solid/organic/wood/ebony + +/obj/structure/bed/simple/ebony/cloth + initial_padding_material = /decl/material/solid/organic/cloth + color = /decl/material/solid/organic/cloth::color + +/obj/structure/bed/simple/crafted + initial_padding_material = null + icon_state = ICON_STATE_WORLD + color = /decl/material/solid/organic/wood/oak::color + +/obj/item/bedsheet/furs + name = "sleeping furs" + desc = "Some cured hides and furs, soft enough to be a good blanket." + icon = 'icons/obj/items/sleeping_furs.dmi' + item_state = null + material_alteration = MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + material = /decl/material/solid/organic/skin/fur + color = /decl/material/solid/organic/skin/fur::color diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index dce86c9adfce..1ddc5b1937f1 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -6,164 +6,199 @@ LINEN BINS /obj/item/bedsheet name = "bedsheet" - desc = "A surprisingly soft linen bedsheet." - icon = 'icons/obj/bedsheet.dmi' - icon_state = "sheet" + desc = "A surprisingly soft bedsheet." + icon = 'icons/obj/bedsheets/bedsheet.dmi' + icon_state = ICON_STATE_WORLD item_state = "bedsheet" randpixel = 0 slot_flags = SLOT_BACK - layer = BASE_ABOVE_OBJ_LAYER - throwforce = 1 + layer = ABOVE_STRUCTURE_LAYER // layer below other objects but above beds throw_speed = 1 throw_range = 2 w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/cloth -/obj/item/bedsheet/attackby(obj/item/I, mob/user) - if(is_sharp(I)) - user.visible_message("\The [user] begins cutting up \the [src] with \a [I].", "You begin cutting up \the [src] with \the [I].") - if(do_after(user, 50, src)) +/obj/item/bedsheet/attackby(obj/item/used_item, mob/user) + if(used_item.is_sharp() || used_item.has_edge()) + user.visible_message("\The [user] begins cutting up \the [src] with \a [used_item].", "You begin cutting up \the [src] with \the [used_item].") + if(do_after(user, 5 SECONDS, src)) to_chat(user, "You cut \the [src] into pieces!") for(var/i in 1 to rand(2,5)) - new /obj/item/chems/glass/rag(get_turf(src)) + new /obj/item/chems/rag(get_turf(src)) qdel(src) - return - ..() + return TRUE + return ..() + +/obj/item/bedsheet/yellowed + desc = "A surprisingly soft bedsheet. This one is old and yellowed." + paint_color = COLOR_BEIGE + paint_verb = "stained" /obj/item/bedsheet/blue - icon_state = "sheetblue" - item_state = "sheetblue" + icon = 'icons/obj/bedsheets/bedsheet_blue.dmi' /obj/item/bedsheet/green - icon_state = "sheetgreen" - item_state = "sheetgreen" + icon = 'icons/obj/bedsheets/bedsheet_green.dmi' /obj/item/bedsheet/orange - icon_state = "sheetorange" - item_state = "sheetorange" + icon = 'icons/obj/bedsheets/bedsheet_orange.dmi' /obj/item/bedsheet/purple - icon_state = "sheetpurple" - item_state = "sheetpurple" + icon = 'icons/obj/bedsheets/bedsheet_purple.dmi' /obj/item/bedsheet/rainbow - icon_state = "sheetrainbow" - item_state = "sheetrainbow" + icon = 'icons/obj/bedsheets/bedsheet_rainbow.dmi' /obj/item/bedsheet/red - icon_state = "sheetred" - item_state = "sheetred" + icon = 'icons/obj/bedsheets/bedsheet_red.dmi' /obj/item/bedsheet/yellow - icon_state = "sheetyellow" - item_state = "sheetyellow" + icon = 'icons/obj/bedsheets/bedsheet_yellow.dmi' /obj/item/bedsheet/mime - icon_state = "sheetmime" - item_state = "sheetmime" + icon = 'icons/obj/bedsheets/bedsheet_mime.dmi' /obj/item/bedsheet/clown - icon_state = "sheetclown" - item_state = "sheetclown" + icon = 'icons/obj/bedsheets/bedsheet_clown.dmi' /obj/item/bedsheet/captain - icon_state = "sheetcaptain" - item_state = "sheetcaptain" + icon = 'icons/obj/bedsheets/bedsheet_captain.dmi' /obj/item/bedsheet/rd - icon_state = "sheetrd" - item_state = "sheetrd" + icon = 'icons/obj/bedsheets/bedsheet_rd.dmi' /obj/item/bedsheet/medical - icon_state = "sheetmedical" - item_state = "sheetmedical" + icon = 'icons/obj/bedsheets/bedsheet_medical.dmi' /obj/item/bedsheet/hos - icon_state = "sheethos" - item_state = "sheethos" + icon = 'icons/obj/bedsheets/bedsheet_hos.dmi' /obj/item/bedsheet/hop - icon_state = "sheethop" - item_state = "sheethop" + icon = 'icons/obj/bedsheets/bedsheet_hop.dmi' /obj/item/bedsheet/ce - icon_state = "sheetce" - item_state = "sheetce" + icon = 'icons/obj/bedsheets/bedsheet_ce.dmi' /obj/item/bedsheet/brown - icon_state = "sheetbrown" - item_state = "sheetbrown" + icon = 'icons/obj/bedsheets/bedsheet_brown.dmi' +/obj/item/bedsheet/ian + icon = 'icons/obj/bedsheets/bedsheet_ian.dmi' +////////////////////////////////////////// +// Bedsheet bin +////////////////////////////////////////// /obj/structure/bedsheetbin - name = "linen bin" - desc = "A linen bin. It looks rather cosy." - icon = 'icons/obj/structures/linen_bin.dmi' - icon_state = "linenbin-full" - anchored = 1 - var/amount = 20 - var/list/sheets = list() - var/obj/item/hidden = null - + name = "linen bin" + desc = "A linen bin. It looks rather cosy." + icon = 'icons/obj/structures/linen_bin.dmi' + icon_state = "linenbin-full" + anchored = TRUE + w_class = ITEM_SIZE_STRUCTURE + material = /decl/material/solid/organic/plastic + tool_interaction_flags = TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT + var/stored = 0 //Currently stored unspawned bedsheets, mainly used by mapped bins + var/max_stored = 20 //Maximum amount of bedsheets that can be put in here + var/list/sheets //Currently spawned bedsheets it contains + var/obj/item/hidden //Object hidden amidst the bedsheets + +/obj/structure/bedsheetbin/mapped/Initialize(ml, _mat, _reinf_mat) + stored = max_stored //Mapped ones start with some unspawned sheets + . = ..() -/obj/structure/bedsheetbin/examine(mob/user) +/obj/structure/bedsheetbin/dump_contents(atom/forced_loc = loc, mob/user) + //Dump all sheets, even unspawned ones + for(var/i = 1 to get_amount()) + remove_sheet(forced_loc) . = ..() - if(amount < 1) - to_chat(user, "There are no bed sheets in the bin.") +/**Returns the total amount of sheets contained, including unspawned ones. */ +/obj/structure/bedsheetbin/proc/get_amount() + return stored + LAZYLEN(sheets) + +/obj/structure/bedsheetbin/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/curamount = get_amount() + if(curamount < 1) + . += "There are no bed sheets in the bin." return - if(amount == 1) - to_chat(user, "There is one bed sheet in the bin.") + if(curamount == 1) + . += "There is one bed sheet in the bin." return - to_chat(user, "There are [amount] bed sheets in the bin.") - + . += "There are [curamount] bed sheets in the bin." /obj/structure/bedsheetbin/on_update_icon() - switch(amount) - if(0) icon_state = "linenbin-empty" - if(1 to amount / 2) icon_state = "linenbin-half" - else icon_state = "linenbin-full" - - -/obj/structure/bedsheetbin/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/bedsheet)) - if(!user.unEquip(I, src)) - return - sheets.Add(I) - amount++ - to_chat(user, "You put [I] in [src].") - else if(amount && !hidden && I.w_class < ITEM_SIZE_HUGE) //make sure there's sheets to hide it among, make sure nothing else is hidden in there. - if(!user.unEquip(I, src)) - return - hidden = I - to_chat(user, "You hide [I] among the sheets.") + ..() + var/curamount = get_amount() + if(curamount < 1) + icon_state = "linenbin-empty" + else if(curamount <= (max_stored/2)) + icon_state = "linenbin-half" + else + icon_state = "linenbin-full" + +/obj/structure/bedsheetbin/attackby(obj/item/used_item, mob/user) + var/curamount = get_amount() + if(istype(used_item, /obj/item/bedsheet)) + if(curamount >= max_stored) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + LAZYDISTINCTADD(sheets, used_item) + update_icon() + to_chat(user, SPAN_NOTICE("You put [used_item] in [src].")) + return TRUE + + //Let the parent attackby run to handle tool interactions + . = ..() + + if(!.) + if(curamount && !hidden && used_item.w_class < w_class) //make sure there's sheets to hide it among, make sure nothing else is hidden in there. + if(!user.try_unequip(used_item, src)) + return TRUE + hidden = used_item + to_chat(user, SPAN_NOTICE("You hide [used_item] among the sheets.")) + return TRUE + else if(hidden) + to_chat(user, SPAN_WARNING("There's not enough space to hide \the [used_item]!")) + else if(used_item.w_class >= w_class) + to_chat(user, SPAN_WARNING("\The [used_item] is too big to hide in \the [src]!")) + else if(curamount < 1) + to_chat(user, SPAN_WARNING("You can't hide anything if there's no sheets to cover it!")) /obj/structure/bedsheetbin/attack_hand(var/mob/user) var/obj/item/bedsheet/B = remove_sheet() - if(B) - user.put_in_hands(B) - to_chat(user, SPAN_NOTICE("You take \a [B] out of \the [src].")) - add_fingerprint(user) + if(!B) + return ..() + user.put_in_hands(B) + to_chat(user, SPAN_NOTICE("You take \a [B] out of \the [src].")) + add_fingerprint(user) + return TRUE /obj/structure/bedsheetbin/do_simple_ranged_interaction(var/mob/user) remove_sheet() return TRUE -/obj/structure/bedsheetbin/proc/remove_sheet() - set waitfor = 0 - if(amount <= 0) +/obj/structure/bedsheetbin/proc/remove_sheet(atom/drop_loc = loc) + if(get_amount() < 1) return - amount-- + + //Pick our sheet source var/obj/item/bedsheet/B - if(sheets.len > 0) + if(LAZYLEN(sheets)) B = sheets[sheets.len] - sheets.Remove(B) - else - B = new /obj/item/bedsheet(loc) - B.dropInto(loc) + LAZYREMOVE(sheets, B) + else if(stored > 0) + stored-- + B = new /obj/item/bedsheet(drop_loc) + B.dropInto(drop_loc) update_icon() - . = B - sleep(-1) + + //Drop the hidden thingie if(hidden) - hidden.dropInto(loc) + hidden.dropInto(drop_loc) visible_message(SPAN_NOTICE("\The [hidden] falls out!")) hidden = null + + return B \ No newline at end of file diff --git a/code/game/objects/structures/benches.dm b/code/game/objects/structures/benches.dm new file mode 100644 index 000000000000..6d8e7637b151 --- /dev/null +++ b/code/game/objects/structures/benches.dm @@ -0,0 +1,54 @@ +/obj/structure/table/bench + name = "bench frame" + icon = 'icons/obj/bench.dmi' + icon_state = "solid_preview" + desc = "It's a bench, for putting things on. Or standing on, if you really want to." + top_surface_noun = "seat" + can_flip = FALSE + can_place_items = FALSE + density = FALSE + mob_offset = 0 + +/obj/structure/table/bench/reinforce_table() + return FALSE + +/obj/structure/table/bench/update_material_name(override_name) + if(reinf_material) + name = "[reinf_material.solid_name] bench" + else if(material) + name = "[material.solid_name] bench frame" + else + name = "bench frame" + +/obj/structure/table/bench/CanPass(atom/movable/mover) + return TRUE + +/obj/structure/table/bench/frame + icon_state = "frame" + reinf_material = null + +/obj/structure/table/bench/steel + icon_state = "solid_preview" + color = COLOR_GRAY40 + reinf_material = /decl/material/solid/metal/steel + +/obj/structure/table/bench/wooden + icon_state = "solid_preview" + color = WOOD_COLOR_GENERIC + material = /decl/material/solid/organic/wood/oak + reinf_material = /decl/material/solid/organic/wood/oak + +/obj/structure/table/bench/padded + icon_state = "padded_preview" + material = /decl/material/solid/metal/steel + reinf_material = /decl/material/solid/metal/steel + felted = TRUE + +/obj/structure/table/bench/glass + color = COLOR_DEEP_SKY_BLUE + alpha = 77 + reinf_material = /decl/material/solid/glass + +/obj/structure/table/bench/marble + color = COLOR_OFF_WHITE + reinf_material = /decl/material/solid/stone/marble diff --git a/code/game/objects/structures/benches/bench.dm b/code/game/objects/structures/benches/bench.dm new file mode 100644 index 000000000000..16ba3b36eceb --- /dev/null +++ b/code/game/objects/structures/benches/bench.dm @@ -0,0 +1,104 @@ +// These are benches with backs. For backless benches that can't be buckled to, check for /obj/structure/table/bench. +/obj/structure/chair/bench + name = "bench" + desc = "A simple slatted bench." + icon = 'icons/obj/structures/furniture/bench.dmi' + icon_state = ICON_STATE_WORLD + "_preview" + color = WOOD_COLOR_GENERIC + initial_padding_material = null + material = /decl/material/solid/organic/wood/oak + obj_flags = 0 + anchored = TRUE + /// A bitfield of connected neighbors. + var/neighbors = 0 + +/obj/structure/chair/bench/should_have_alpha_mask() + if(!simulated || !isturf(loc)) + return FALSE + var/obj/structure/chair/bench/south_neighbor = locate() in get_step(loc, SOUTH) + if(can_visually_connect_to(south_neighbor)) // if we're connected to a south neighbor don't add an alpha mask + return TRUE + return TRUE + +// TODO: make this use the generic structure smoothing system? +/obj/structure/chair/bench/can_visually_connect_to(var/obj/structure/chair/bench/other) + return istype(other) && other.dir == dir && other.icon == icon && other.material == material + +/obj/structure/chair/bench/Initialize(mapload) + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/structure/chair/bench/LateInitialize(mapload) + ..() + if(mapload) + recalculate_connections() + else + update_neighbors() + +/obj/structure/chair/bench/Destroy() + var/oldloc = loc + . = ..() + update_neighbors(oldloc) + +/obj/structure/chair/bench/set_dir() + var/olddir = dir + . = ..() + if(.) + update_neighbors(update_dir = olddir, skip_icon_update = TRUE) + update_neighbors(update_dir = dir) + +/obj/structure/chair/bench/Move() + var/oldloc = loc + . = ..() + if(.) + update_neighbors(oldloc, skip_icon_update = TRUE) + update_neighbors(loc) + +/obj/structure/chair/bench/proc/update_neighbors(update_loc = loc, update_dir = dir, skip_icon_update) + if(!skip_icon_update) + recalculate_connections() + if(!isturf(update_loc)) + return + for(var/stepdir in list(turn(update_dir, -90), turn(update_dir, 90))) + for(var/obj/structure/chair/bench/other in get_step(update_loc, stepdir)) + other.recalculate_connections() + +// TODO: Make this use base structure smoothing eventually? Somehow? +/obj/structure/chair/bench/proc/recalculate_connections() + neighbors = 0 + if(!isturf(loc)) + neighbors = 0 + else + for(var/checkdir in list(turn(dir, -90), turn(dir, 90))) + var/turf/check_turf = get_step(loc, checkdir) + for(var/obj/structure/chair/bench/other in check_turf) + // TODO: Make this use normal structure smoothing helpers. + if(other.dir == dir && other.icon == icon && other.material == material) + neighbors |= checkdir + break + update_icon() + +/obj/structure/chair/bench/get_base_icon() + . = ..() + var/left_dir = turn(dir, -90) + var/right_dir = turn(dir, 90) + if(neighbors & left_dir) + if(neighbors & right_dir) + . += "_middle" + else + . += "_right" + else if(neighbors & right_dir) + . += "_left" + else + . += "_standing" + +/obj/structure/chair/bench/get_material_icon() + return material?.bench_icon || initial(icon) + +/obj/structure/chair/bench/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/mahogany + +/obj/structure/chair/bench/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/ebony diff --git a/code/game/objects/structures/benches/lounge.dm b/code/game/objects/structures/benches/lounge.dm new file mode 100644 index 000000000000..a1bc8fc097a8 --- /dev/null +++ b/code/game/objects/structures/benches/lounge.dm @@ -0,0 +1,14 @@ +/obj/structure/chair/bench/lounge + name = "lounge" + desc = "An elegant lounge, perfect for reclining on." + icon = 'icons/obj/structures/furniture/lounge.dmi' + +// Just use the existing icon. +/obj/structure/chair/bench/lounge/get_material_icon() + return icon || initial(icon) + +/obj/structure/chair/bench/lounge/mapped + color = /decl/material/solid/organic/wood/mahogany::color + material = /decl/material/solid/organic/wood/mahogany + initial_padding_material = /decl/material/solid/organic/cloth + initial_padding_color = COLOR_RED_GRAY diff --git a/code/game/objects/structures/benches/pew.dm b/code/game/objects/structures/benches/pew.dm new file mode 100644 index 000000000000..fe5425214c0b --- /dev/null +++ b/code/game/objects/structures/benches/pew.dm @@ -0,0 +1,15 @@ +/obj/structure/chair/bench/pew + name = "pew" + desc = "A long bench with a backboard, commonly found in places of worship, courtrooms and so on. Not known for being particularly comfortable." + icon = 'icons/obj/structures/furniture/pew.dmi' + +/obj/structure/chair/bench/pew/get_material_icon() + return material?.pew_icon || initial(icon) + +/obj/structure/chair/bench/pew/mahogany + color = /decl/material/solid/organic/wood/mahogany::color + material = /decl/material/solid/organic/wood/mahogany + +/obj/structure/chair/bench/pew/ebony + color = /decl/material/solid/organic/wood/ebony::color + material = /decl/material/solid/organic/wood/ebony diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm index a666dd54535c..c51e005f3cfe 100644 --- a/code/game/objects/structures/bookcase.dm +++ b/code/game/objects/structures/bookcase.dm @@ -1,104 +1,239 @@ -GLOBAL_LIST_INIT(station_bookcases, new) +#define GET_BOOK_POS(STORAGE, X, Y) (((Y)*STORAGE.book_slots_x)+(X)+1) + +var/global/list/station_bookcases = list() + +/datum/storage/bookcase + can_hold = list(/obj/item/book) + max_w_class = ITEM_SIZE_LARGE + var/book_slots_x = 5 + var/book_slots_y = 3 + var/book_pos_origin_x = 6 + var/book_pos_origin_y = 2 + var/book_size_x = 4 + var/book_size_y = 8 + var/list/book_positions + +/datum/storage/bookcase/New(atom/_holder) + storage_slots = book_slots_x * book_slots_y + book_positions = new /list(storage_slots) + refresh_book_positions() + ..() + +/datum/storage/bookcase/update_ui_after_item_insertion(obj/item/inserted, click_params) + . = ..() + + if(!click_params || !istype(inserted) || QDELETED(inserted)) + return + + var/list/click_data = params2list(click_params) + if(!length(click_data)) + return + + var/click_x = text2num(click_data["icon-x"]) + var/click_y = text2num(click_data["icon-y"]) + if(click_x < book_pos_origin_x || click_x > book_pos_origin_x + (book_slots_x * book_size_x)) + return + if(click_y < book_pos_origin_y || click_y > book_pos_origin_y + (book_slots_y * book_size_y)) + return + + var/place_x = floor((click_x - book_pos_origin_x) / book_size_x) + var/place_y = floor((click_y - book_pos_origin_y) / book_size_y) + if(place_x < 0 || place_x >= book_slots_x || place_y < 0 || place_y >= book_slots_y) + return + + var/place_key = GET_BOOK_POS(src, place_x, place_y) + + if(isnull(book_positions[place_key])) + book_positions[place_key] = weakref(inserted) + +/datum/storage/bookcase/update_ui_after_item_removal(obj/item/removed) + . = ..() + if(!istype(removed) || QDELETED(removed)) + return + for(var/bX = 0 to (book_slots_x-1)) + for(var/bY = 0 to (book_slots_y-1)) + var/bK = GET_BOOK_POS(src, bX, bY) + var/weakref/potential_book = book_positions[bK] + if(IS_WEAKREF_OF(potential_book, removed)) + book_positions[bK] = null + return + +/datum/storage/bookcase/proc/refresh_book_positions() + + if(!istype(holder)) + return + + for(var/bX = 0 to (book_slots_x-1)) + for(var/bY = 0 to (book_slots_y-1)) + var/bK = GET_BOOK_POS(src, bX, bY) + var/weakref/book_ref = book_positions[bK] + var/obj/item/thing = book_ref?.resolve() + if(!isnull(thing) && (QDELING(thing) || thing.loc != holder)) // QDELING because it might be deleting but hasn't been moved to nullspace yet + book_positions[bK] = null + + for(var/obj/item/thing in holder.get_stored_inventory()) + + var/positioned = FALSE + // Avoid moving us if we're already positioned + for(var/bX = 0 to (book_slots_x-1)) + for(var/bY = 0 to (book_slots_y-1)) + var/weakref/potential_book = book_positions[GET_BOOK_POS(src, bX, bY)] + if(IS_WEAKREF_OF(potential_book, thing)) + positioned = TRUE + break + if(positioned) + break + + if(positioned) + continue + + // Otherwise, find a new position + for(var/bX = 0 to (book_slots_x-1)) + for(var/bY = 0 to (book_slots_y-1)) + var/bK = GET_BOOK_POS(src, bX, bY) + if(isnull(book_positions[bK])) + book_positions[bK] = weakref(thing) + positioned = TRUE + break + if(positioned) + break + // No position, fall on the ground! + if(!positioned) + thing.dropInto(holder.loc) + /obj/structure/bookcase name = "bookcase" - icon = 'icons/obj/library.dmi' - icon_state = "book-0" - anchored = 1 - density = 1 - opacity = 1 + icon = 'icons/obj/structures/bookcase.dmi' + icon_state = "bookcase" + anchored = TRUE + density = TRUE + opacity = TRUE obj_flags = OBJ_FLAG_ANCHORABLE - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) - material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR + material_alteration = MAT_FLAG_ALTERATION_ALL + storage = /datum/storage/bookcase /obj/structure/bookcase/Initialize() for(var/obj/item/I in loc) if(istype(I, /obj/item/book)) I.forceMove(src) - if(z in GLOB.using_map.station_levels) - GLOB.station_bookcases += src + if(isStationLevel(z)) + global.station_bookcases += src + get_or_create_extension(src, /datum/extension/labels/single) . = ..() + if(. != INITIALIZE_HINT_QDEL) + return INITIALIZE_HINT_LATELOAD + +/obj/structure/bookcase/LateInitialize() + ..() + if(storage && length(contents) > storage.storage_slots) + storage.storage_slots = length(contents) + storage.max_storage_space = storage.storage_slots * storage.max_w_class + update_icon() /obj/structure/bookcase/Destroy() - GLOB.station_bookcases -= src + global.station_bookcases -= src . = ..() -/obj/structure/bookcase/create_dismantled_products(var/turf/T) - for(var/obj/item/book/b in contents) - b.dropInto(T) - . = ..() +/obj/structure/bookcase/on_update_icon() -/obj/structure/bookcase/attackby(obj/O, mob/user) . = ..() - if(!.) - if(istype(O, /obj/item/book) && user.unEquip(O, src)) - update_icon() - else if(istype(O, /obj/item/pen)) - var/newname = sanitizeSafe(input("What would you like to title this bookshelf?"), MAX_NAME_LEN) - if(!newname) - return - else - SetName("bookcase ([newname])") - -/obj/structure/bookcase/attack_hand(var/mob/user) - if(contents.len) - var/obj/item/book/choice = input("Which book would you like to remove from the shelf?") as null|obj in contents - if(choice) - if(!CanPhysicallyInteract(user)) - return - if(ishuman(user)) - if(!user.get_active_hand()) - user.put_in_hands(choice) - else - choice.dropInto(loc) - update_icon() - -/obj/structure/bookcase/explosion_act(severity) - ..() - if(!QDELETED(src)) - var/book_destroy_prob = 100 - var/case_destroy_prob = 100 - if(severity == 2) - book_destroy_prob = 50 - else if(severity == 3) - case_destroy_prob = 50 - book_destroy_prob = 0 - if(prob(case_destroy_prob)) - for(var/obj/item/book/b in contents) - b.dropInto(loc) - if(prob(book_destroy_prob)) - qdel(b) - physically_destroyed() -/obj/structure/bookcase/on_update_icon() - if(contents.len < 5) - icon_state = "book-[contents.len]" - else - icon_state = "book-5" + // TODO: Handle repair, drop book contents when too damaged? + // At the very least, should probably add an update_icon() call on take_damage()... + if(get_health_ratio() < 0.5) + icon_state = "[initial(icon_state)]-damaged" + return // No storage contents while damaged. + + var/datum/storage/bookcase/book_storage = storage + if(!istype(book_storage) || !length(contents)) + return + + book_storage.refresh_book_positions() // Assigns any loose items a position. + + for(var/bX = 0 to (book_storage.book_slots_x-1)) + for(var/bY = 0 to (book_storage.book_slots_y-1)) + var/bK = (bY * book_storage.book_slots_x) + bX + 1 + + var/weakref/book_ref = book_storage.book_positions[bK] + var/obj/item/book = book_ref?.resolve() + if(!istype(book) || !check_state_in_icon("bookcase", book.icon)) + continue + + var/use_lying_state = "bookcase" + if(bX < (book_storage.book_slots_x-1) && !isnull(book_storage.book_positions[bK+1]) && check_state_in_icon("bookcase_flat", book.icon)) + use_lying_state = "bookcase_flat" + + var/image/book_overlay = overlay_image(book.icon, use_lying_state, book.get_color(), RESET_COLOR) + book_overlay.pixel_x = book_storage.book_pos_origin_x + (book_storage.book_size_x * bX) + book_overlay.pixel_y = book_storage.book_pos_origin_y + (book_storage.book_size_y * bY) + add_overlay(book_overlay) + + var/page_state = "[book_overlay.icon_state]-pages" + if(check_state_in_icon(page_state, book_overlay.icon)) + var/image/page_overlay = overlay_image(book_overlay.icon, page_state, COLOR_WHITE, RESET_COLOR) + page_overlay.pixel_x = book_overlay.pixel_x + page_overlay.pixel_y = book_overlay.pixel_y + add_overlay(page_overlay) /obj/structure/bookcase/manuals/medical name = "Medical Manuals bookcase" -/obj/structure/bookcase/manuals/medical/Initialize() - . = ..() - new /obj/item/book/manual/medical_diagnostics_manual(src) - new /obj/item/book/manual/medical_diagnostics_manual(src) - new /obj/item/book/manual/medical_diagnostics_manual(src) - new /obj/item/book/manual/chemistry_recipes(src) - update_icon() - +/obj/structure/bookcase/manuals/medical/WillContain() + return list( + /obj/item/book/manual/medical_diagnostics_manual = 3, + /obj/item/book/manual/chemistry_recipes = 1 + ) /obj/structure/bookcase/manuals/engineering name = "Engineering Manuals bookcase" -/obj/structure/bookcase/manuals/engineering/Initialize() - . = ..() - new /obj/item/book/manual/engineering_construction(src) - new /obj/item/book/manual/engineering_particle_accelerator(src) - new /obj/item/book/manual/engineering_hacking(src) - new /obj/item/book/manual/engineering_guide(src) - new /obj/item/book/manual/atmospipes(src) - new /obj/item/book/manual/engineering_singularity_safety(src) - new /obj/item/book/manual/evaguide(src) - new /obj/item/book/manual/rust_engine(src) - update_icon() +/obj/structure/bookcase/manuals/engineering/WillContain() + return list( + /obj/item/book/manual/engineering_construction, + /obj/item/book/manual/engineering_particle_accelerator, + /obj/item/book/manual/engineering_hacking, + /obj/item/book/manual/engineering_guide, + /obj/item/book/manual/atmospipes, + /obj/item/book/manual/engineering_singularity_safety, + /obj/item/book/manual/evaguide, + /obj/item/book/manual/rust_engine + ) + +/obj/structure/bookcase/cart + name = "book cart" + anchored = FALSE + opacity = FALSE + icon_state = "book-0" + desc = "A mobile cart for carrying books around." + movable_flags = MOVABLE_FLAG_WHEELED + icon = 'icons/obj/structures/book_cart.dmi' + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + obj_flags = 0 + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/structure/bookcase/cart/on_update_icon() + // We don't (can't) call parent, so we have to do this here + if(material_alteration & MAT_FLAG_ALTERATION_COLOR) + update_material_color() + cut_overlays() + if(istype(lock)) + update_lock_overlay() + // End boilerplate + var/used_space_ratio = storage.storage_space_used() / storage.max_storage_space + icon_state = "book-[round(used_space_ratio * 5)]" + +/obj/structure/bookcase/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/bookcase/fancy + icon_state = "fancy" + +/obj/structure/bookcase/fancy/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +#undef GET_BOOK_POS diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index b14543504c76..8598d9db8d55 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -3,28 +3,22 @@ desc = "Cats really don't like these things." icon = 'icons/obj/structures/catwalks.dmi' icon_state = "catwalk" - density = 0 - anchored = 1.0 + density = FALSE + anchored = TRUE layer = CATWALK_LAYER footstep_type = /decl/footsteps/catwalk - obj_flags = OBJ_FLAG_NOFALL + obj_flags = OBJ_FLAG_NOFALL | OBJ_FLAG_MOVES_UNSUPPORTED handle_generic_blending = TRUE tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT material = /decl/material/solid/metal/steel + parts_type = /obj/item/stack/material/rods + parts_amount = 2 var/hatch_open = FALSE var/decl/flooring/tiling/plated_tile var/list/connections var/list/other_connections -/obj/structure/catwalk/clear_connections() - connections = null - other_connections = null - -/obj/structure/catwalk/set_connections(dirs, other_dirs) - connections = dirs_to_corner_states(dirs) - other_connections = dirs_to_corner_states(other_dirs) - /obj/structure/catwalk/Initialize() . = ..() DELETE_IF_DUPLICATE_OF(/obj/structure/catwalk) @@ -46,9 +40,28 @@ if(istype(oldloc)) for(var/atom/movable/AM in oldloc) AM.fall(oldloc) + oldloc.supporting_platform = null + +// Catwalks need to layer over grass and water. +/obj/structure/catwalk/update_turf_alpha_mask() + return FALSE + +/obj/structure/catwalk/clear_connections() + connections = null + other_connections = null + +/obj/structure/catwalk/is_platform() + return TRUE + +/obj/structure/catwalk/set_connections(dirs, other_dirs) + connections = dirs_to_corner_states(dirs) + other_connections = dirs_to_corner_states(other_dirs) + +/obj/structure/catwalk/can_climb_from_below(var/mob/climber) + return TRUE /obj/structure/catwalk/proc/redraw_nearby_catwalks() - for(var/direction in GLOB.alldirs) + for(var/direction in global.alldirs) var/obj/structure/catwalk/L = locate() in get_step(src, direction) if(L) L.update_connections() @@ -56,85 +69,104 @@ /obj/structure/catwalk/on_update_icon() update_connections() - overlays.Cut() + ..() icon_state = "" - var/image/I if(!hatch_open) for(var/i = 1 to 4) - I = image(icon, "catwalk[connections ? connections[i] : "0"]", dir = 1<<(i-1)) - overlays += I + add_overlay(image(icon, "catwalk[connections ? connections[i] : "0"]", dir = BITFLAG(i-1))) if(plated_tile) - I = image(icon, "plated") - I.color = plated_tile.color - overlays += I + var/image/overlay_image = image(icon, "plated") + overlay_image.color = plated_tile.color + add_overlay(overlay_image) /obj/structure/catwalk/create_dismantled_products(var/turf/T) - new /obj/item/stack/material/rods(T, 2, material.type) + . = ..() if(plated_tile) var/plate_path = plated_tile.build_type - new plate_path(T) + LAZYADD(., new plate_path(T)) + plated_tile = null /obj/structure/catwalk/explosion_act(severity) ..() if(!QDELETED(src) && severity != 3) physically_destroyed() +/obj/structure/catwalk/grab_attack(obj/item/grab/grab, mob/user) + if(atom_flags & ATOM_FLAG_CLIMBABLE) + var/obj/occupied = turf_is_crowded() + if (occupied) + to_chat(user, SPAN_WARNING("There's \a [occupied] in the way.")) + return TRUE + grab.affecting.forceMove(src.loc) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim)) + SET_STATUS_MAX(victim, STAT_WEAK, rand(2,5)) + visible_message(SPAN_DANGER("\The [user] puts \the [victim] on \the [src].")) + return TRUE + return ..() + /obj/structure/catwalk/attack_robot(var/mob/user) - if(Adjacent(user)) - attack_hand(user) + return attack_hand_with_interaction_checks(user) -/obj/structure/catwalk/attackby(obj/item/C, mob/user) - . = ..() - if(!.) +/obj/structure/catwalk/attackby(obj/item/used_item, mob/user) - if(istype(C, /obj/item/grab)) - var/obj/item/grab/G = C - G.affecting.forceMove(get_turf(src)) + if((. = ..())) + return + + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item + if(cutter.slice(user)) + dismantle_structure(user) + return TRUE + + if(istype(used_item, /obj/item/stack/tile/mono) && !plated_tile) + + var/ladder = (locate(/obj/structure/ladder) in loc) + if(ladder) + to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) return TRUE - if(istype(C, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = C - if(!cutter.slice(user)) - return - dismantle(user) + var/obj/item/stack/tile/ST = used_item + if(ST.in_use) return TRUE - if(isCrowbar(C) && plated_tile) - hatch_open = !hatch_open - if(hatch_open) - playsound(src, 'sound/items/Crowbar.ogg', 100, 2) - to_chat(user, "You pry open \the [src]'s maintenance hatch.") - else - playsound(src, 'sound/items/Deconstruct.ogg', 100, 2) - to_chat(user, "You shut \the [src]'s maintenance hatch.") - update_icon() + + to_chat(user, SPAN_NOTICE("You begin plating \the [src] with \the [ST].")) + ST.in_use = 1 + if (!do_after(user, 10)) + ST.in_use = 0 return TRUE - if(istype(C, /obj/item/stack/tile/mono) && !plated_tile) - - var/ladder = (locate(/obj/structure/ladder) in loc) - if(ladder) - to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) - return TRUE - - var/obj/item/stack/tile/floor/ST = C - if(!ST.in_use) - to_chat(user, "Placing tile...") - ST.in_use = 1 - if (!do_after(user, 10)) - ST.in_use = 0 - return TRUE - to_chat(user, "You plate \the [src]") - name = "plated catwalk" - ST.in_use = 0 - if(ST.use(1)) - var/list/decls = decls_repository.get_decls_of_subtype(/decl/flooring) - for(var/flooring_type in decls) - var/decl/flooring/F = decls[flooring_type] - if(!F.build_type) - continue - if(ispath(C.type, F.build_type)) - plated_tile = F - break - update_icon() + + to_chat(user, SPAN_NOTICE("You plate \the [src]")) + name = "plated catwalk" + ST.in_use = 0 + if(!ST.use(1)) + return TRUE + + var/list/decls = decls_repository.get_decls_of_subtype(/decl/flooring) + for(var/flooring_type in decls) + var/decl/flooring/F = decls[flooring_type] + if(!F.build_type) + continue + if(istype(used_item, F.build_type) && (!F.build_material || used_item.material?.type == F.build_material)) + plated_tile = F + break + update_icon() + return TRUE + + return FALSE + +/obj/structure/catwalk/handle_default_crowbar_attackby(mob/user, obj/item/crowbar) + if(plated_tile) + hatch_open = !hatch_open + if(hatch_open) + playsound(src, 'sound/items/Crowbar.ogg', 100, 2) + to_chat(user, "You pry open \the [src]'s maintenance hatch.") + else + playsound(src, 'sound/items/Deconstruct.ogg', 100, 2) + to_chat(user, "You shut \the [src]'s maintenance hatch.") + update_icon() + return TRUE + . = ..() /obj/structure/catwalk/hoist_act(turf/dest) for(var/A in loc) @@ -146,14 +178,17 @@ /obj/structure/catwalk/refresh_neighbors() return +/obj/structure/catwalk/is_z_passable() + return !plated_tile + /obj/effect/catwalk_plated name = "plated catwalk spawner" icon = 'icons/obj/structures/catwalks.dmi' icon_state = "catwalk_plated" - density = 1 - anchored = 1.0 - var/activated = FALSE + density = TRUE + anchored = TRUE layer = CATWALK_LAYER + var/activated = FALSE var/plating_type = /decl/flooring/tiling/mono /obj/effect/catwalk_plated/Initialize(mapload) @@ -167,10 +202,13 @@ return 0 /obj/effect/catwalk_plated/attack_hand() + SHOULD_CALL_PARENT(FALSE) activate() + return TRUE /obj/effect/catwalk_plated/attack_ghost() activate() + return TRUE /obj/effect/catwalk_plated/proc/activate() if(activated) return @@ -178,13 +216,13 @@ if(locate(/obj/structure/catwalk) in loc) warning("Frame Spawner: A catwalk already exists at [loc.x]-[loc.y]-[loc.z]") else - var/obj/structure/catwalk/C = new /obj/structure/catwalk(loc) - C.plated_tile += new plating_type - C.name = "plated catwalk" - C.update_icon() + var/obj/structure/catwalk/catwalk = new /obj/structure/catwalk(loc) + catwalk.plated_tile += GET_DECL(plating_type) + catwalk.name = "plated catwalk" + catwalk.update_icon() activated = 1 for(var/turf/T in orange(src, 1)) - for(var/obj/effect/wallframe_spawn/other in T) + for(var/obj/effect/catwalk_plated/other in T) if(!other.activated) other.activate() /obj/effect/catwalk_plated/dark diff --git a/code/game/objects/structures/chairs/chairs.dm b/code/game/objects/structures/chairs/chairs.dm new file mode 100644 index 000000000000..e22920c145a6 --- /dev/null +++ b/code/game/objects/structures/chairs/chairs.dm @@ -0,0 +1,387 @@ +/obj/structure/chair + name = "chair" + desc = "You sit in this, either by will or force." + icon = 'icons/obj/structures/furniture/chair.dmi' + icon_state = ICON_STATE_WORLD + "_preview" + anchored = TRUE + can_buckle = TRUE + buckle_lying = FALSE // force people to sit up in chairs when buckled + buckle_sound = 'sound/effects/buckle.ogg' + material = DEFAULT_FURNITURE_MATERIAL + material_alteration = MAT_FLAG_ALTERATION_ALL + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + parts_amount = 2 + parts_type = /obj/item/stack/material/rods + color = "#666666" + obj_flags = OBJ_FLAG_ROTATABLE | OBJ_FLAG_SUPPORT_MOB + user_comfort = 0.5 + monetary_worth_multiplier = 2.5 // Utility structures should be worth more than their matter (wheelchairs, rollers, etc). + + var/propelled = 0 // Check for fire-extinguisher-driven chairs + var/has_special_overlay = FALSE + /// The padding extension type for this chair. If null, no extension is created and this chair cannot be padded. + var/padding_extension_type = /datum/extension/padding + var/decl/material/initial_padding_material + var/initial_padding_color + +/obj/structure/chair/Initialize(ml, _mat, _reinf_mat) + . = ..() + if(padding_extension_type && initial_padding_material) + get_or_create_extension(src, padding_extension_type, initial_padding_material, initial_padding_color) + +/obj/structure/chair/do_simple_ranged_interaction(var/mob/user) + if(!buckled_mob && user) + rotate(user) + return TRUE + +/obj/structure/chair/post_buckle_mob() + update_icon() + return ..() + +// Allow self-buckling even without dexterity. +// Copied from beds; do we actually want this? +/obj/structure/chair/user_can_mousedrop_onto(mob/user, atom/being_dropped, incapacitation_flags, params) + if(user == being_dropped) + return user.Adjacent(src) && !user.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT) + return ..() + +/// Returns an alternate icon based on our material. +/// Mostly used by benches. +/// TODO: Refactor to eliminate? +/obj/structure/chair/proc/get_material_icon() + return icon + +/obj/structure/chair/update_materials() + . = ..() + var/icon/material_icon = get_material_icon() + if(material_icon) + icon = material_icon + +/obj/structure/chair/proc/get_base_icon() + return ICON_STATE_WORLD + +/obj/structure/chair/on_update_icon() + ..() + icon_state = get_base_icon() + var/base_color = get_color() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/use_padding_color = padding_extension?.get_padding_color(material_alteration & MAT_FLAG_ALTERATION_COLOR) + var/use_layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER + + var/image/I = overlay_image(icon, "[icon_state]_over", base_color, RESET_COLOR) + I.layer = use_layer + add_overlay(I) + I = overlay_image(icon, "[icon_state]_armrest", base_color, RESET_COLOR) + I.layer = use_layer + add_overlay(I) + if(padding_extension?.get_padding_material()) + add_overlay(overlay_image(icon, "[icon_state]_padding", padding_extension.get_padding_color(material_alteration & MAT_FLAG_ALTERATION_COLOR), RESET_COLOR|RESET_ALPHA)) + I = overlay_image(icon, "[icon_state]_padding_over", use_padding_color, RESET_COLOR) + I.layer = use_layer + add_overlay(I) + I = overlay_image(icon, "[icon_state]_padding_armrest", use_padding_color, RESET_COLOR) + I.layer = use_layer + add_overlay(I) + if(has_special_overlay) + I = overlay_image(icon, "[icon_state]_special", base_color, RESET_COLOR) + I.layer = use_layer + add_overlay(I) + +// No name override, a cotton-padded metal chair shouldn't be a cotton chair, it should be a metal chair. + +/obj/structure/chair/update_material_desc(override_desc) + var/base_desc = override_desc || initial(desc) + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/decl/material/padding_material = padding_extension?.get_padding_material() + if(padding_material) + desc = "[base_desc] It's made of [material.use_name] and padded with [padding_material.use_name]." + else + desc = "[base_desc] It's made of [material.use_name]." + +/obj/structure/chair/rotate(mob/user) + if(!CanPhysicallyInteract(user)) + to_chat(user, SPAN_NOTICE("You can't interact with \the [src] right now!")) + return + + set_dir(turn(dir, 90)) + update_icon() + +/obj/structure/chair/padded + initial_padding_material = /decl/material/solid/organic/cloth +/obj/structure/chair/padded/red + initial_padding_color = "#9d2300" +/obj/structure/chair/padded/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/chair/padded/teal + initial_padding_color = "#00e1ff" +/obj/structure/chair/padded/black + initial_padding_color = "#505050" +/obj/structure/chair/padded/green + initial_padding_color = "#b7f27d" +/obj/structure/chair/padded/purple + initial_padding_color = "#9933ff" +/obj/structure/chair/padded/blue + initial_padding_color = "#46698c" +/obj/structure/chair/padded/beige + initial_padding_color = "#ceb689" +/obj/structure/chair/padded/lime + initial_padding_color = "#62e36c" +/obj/structure/chair/padded/yellow + initial_padding_color = "#ffbf00" + +// Leaving this in for the sake of compilation. +/obj/structure/chair/comfy + name = "comfy chair" + desc = "It's a chair. It looks comfy." + icon = 'icons/obj/structures/furniture/chair_comfy.dmi' + initial_padding_material = /decl/material/solid/organic/cloth + +/obj/structure/chair/comfy/unpadded + initial_padding_material = null +/obj/structure/chair/comfy/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/chair/comfy/red + initial_padding_color = "#9d2300" +/obj/structure/chair/comfy/teal + initial_padding_color = "#00e1ff" +/obj/structure/chair/comfy/black + initial_padding_color = "#505050" +/obj/structure/chair/comfy/green + initial_padding_color = "#b7f27d" +/obj/structure/chair/comfy/purple + initial_padding_color = "#9933ff" +/obj/structure/chair/comfy/blue + initial_padding_color = "#46698c" +/obj/structure/chair/comfy/beige + initial_padding_color = "#ceb689" +/obj/structure/chair/comfy/lime + initial_padding_color = "#62e36c" +/obj/structure/chair/comfy/yellow + initial_padding_color = "#ffbf00" +/obj/structure/chair/comfy/orange + initial_padding_color = COLOR_ORANGE + +/obj/structure/chair/comfy/captain + name = "captain chair" + desc = "It's a chair. Only for the highest ranked asses." + icon = 'icons/obj/structures/furniture/chair_captain.dmi' + buckle_movable = 1 + material = /decl/material/solid/metal/steel + initial_padding_material = /decl/material/solid/organic/cloth + initial_padding_color = "#46698c" + has_special_overlay = TRUE + +/obj/structure/chair/armchair + name = "armchair" + desc = "It's an armchair. It looks comfy." + icon = 'icons/obj/structures/furniture/armchair.dmi' + initial_padding_material = /decl/material/solid/organic/cloth + +/obj/structure/chair/armchair/unpadded + initial_padding_material = null +/obj/structure/chair/armchair/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/chair/armchair/red + initial_padding_color = "#9d2300" +/obj/structure/chair/armchair/teal + initial_padding_color = "#00e1ff" +/obj/structure/chair/armchair/black + initial_padding_color = "#505050" +/obj/structure/chair/armchair/green + initial_padding_color = "#b7f27d" +/obj/structure/chair/armchair/purple + initial_padding_color = "#9933ff" +/obj/structure/chair/armchair/blue + initial_padding_color = "#46698c" +/obj/structure/chair/armchair/beige + initial_padding_color = "#ceb689" +/obj/structure/chair/armchair/lime + initial_padding_color = "#62e36c" +/obj/structure/chair/armchair/yellow + initial_padding_color = "#ffbf00" + +/obj/structure/chair/office + name = "office chair" + icon = 'icons/obj/structures/furniture/chair_office.dmi' + anchored = FALSE + buckle_movable = 1 + movable_flags = MOVABLE_FLAG_WHEELED + initial_padding_material = /decl/material/solid/organic/cloth + +/obj/structure/chair/office/Move() + . = ..() + if(buckled_mob) + var/mob/living/occupant = buckled_mob + if (occupant && (src.loc != occupant.loc)) + if (propelled) + for (var/mob/O in src.loc) + if (O != occupant) + Bump(O) + else + unbuckle_mob() + +/obj/structure/chair/office/Bump(atom/A) + ..() + if(!buckled_mob) + return + + if(propelled) + var/mob/living/occupant = unbuckle_mob() + + var/def_zone = ran_zone() + var/blocked = 100 * occupant.get_blocked_ratio(def_zone, BRUTE, damage = 10) + occupant.throw_at(A, 3, propelled) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) //#TODO: geez that might be a bit overkill + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone) + playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) + if(isliving(A)) + var/mob/living/victim = A + def_zone = ran_zone() + blocked = 100 * victim.get_blocked_ratio(def_zone, BRUTE, damage = 10) + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) //#TODO: geez that might be a bit overkill + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone) + occupant.visible_message("[occupant] crashed into \the [A]!") + +/obj/structure/chair/office/light + initial_padding_color = "#f0f0f0" +/obj/structure/chair/office/dark + initial_padding_color = "#505050" + +/obj/structure/chair/office/comfy + name = "comfy office chair" + desc = "It's an office chair. It looks comfy." + icon = 'icons/obj/structures/furniture/chair_comfy_office.dmi' + +/obj/structure/chair/office/comfy/unpadded + initial_padding_material = null +/obj/structure/chair/office/comfy/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/chair/office/comfy/red + initial_padding_color = "#9d2300" +/obj/structure/chair/office/comfy/teal + initial_padding_color = "#00e1ff" +/obj/structure/chair/office/comfy/black + initial_padding_color = "#505050" +/obj/structure/chair/office/comfy/green + initial_padding_color = "#b7f27d" +/obj/structure/chair/office/comfy/purple + initial_padding_color = "#9933ff" +/obj/structure/chair/office/comfy/blue + initial_padding_color = "#46698c" +/obj/structure/chair/office/comfy/beige + initial_padding_color = "#ceb689" +/obj/structure/chair/office/comfy/lime + initial_padding_color = "#62e36c" +/obj/structure/chair/office/comfy/yellow + initial_padding_color = "#ffbf00" + +/obj/structure/chair/rounded + name = "rounded chair" + desc = "It's a rounded chair. It looks comfy." + icon = 'icons/obj/structures/furniture/chair_rounded.dmi' + +/obj/structure/chair/rounded/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/chair/rounded/red + initial_padding_color = "#9d2300" +/obj/structure/chair/rounded/teal + initial_padding_color = "#00e1ff" +/obj/structure/chair/rounded/black + initial_padding_color = "#505050" +/obj/structure/chair/rounded/green + initial_padding_color = "#b7f27d" +/obj/structure/chair/rounded/purple + initial_padding_color = "#9933ff" +/obj/structure/chair/rounded/blue + initial_padding_color = "#46698c" +/obj/structure/chair/rounded/beige + initial_padding_color = "#ceb689" +/obj/structure/chair/rounded/lime + initial_padding_color = "#62e36c" +/obj/structure/chair/rounded/yellow + initial_padding_color = "#ffbf00" + +/obj/structure/chair/shuttle + name = "shuttle seat" + desc = "A comfortable, secure seat. It has a sturdy-looking buckling system for smoother flights." + icon = 'icons/obj/structures/furniture/chair_shuttle.dmi' + buckle_sound = 'sound/effects/metal_close.ogg' + material = /decl/material/solid/metal/steel + initial_padding_material = /decl/material/solid/organic/cloth + has_special_overlay = TRUE + +/obj/structure/chair/shuttle/get_base_icon() + . = ..() + if (buckled_mob) + . += "_buckled" + +/obj/structure/chair/shuttle/blue + initial_padding_color = "#46698c" +/obj/structure/chair/shuttle/black + initial_padding_color = "#505050" +/obj/structure/chair/shuttle/white + initial_padding_color = "#f0f0f0" + +/obj/structure/chair/wood + name_prefix = "classic" + desc = "Old is never too old to not be in fashion." + icon = 'icons/obj/structures/furniture/chair_wooden.dmi' + color = WOOD_COLOR_GENERIC + material = /decl/material/solid/organic/wood/oak + padding_extension_type = null // Cannot be padded. + +/obj/structure/chair/wood/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/mahogany +/obj/structure/chair/wood/maple + color = WOOD_COLOR_PALE + material = /decl/material/solid/organic/wood/maple +/obj/structure/chair/wood/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/ebony +/obj/structure/chair/wood/walnut + color = WOOD_COLOR_CHOCOLATE + material = /decl/material/solid/organic/wood/walnut + +/obj/structure/chair/wood/wings + name = "winged chair" + icon = 'icons/obj/structures/furniture/chair_wooden_wings.dmi' + +/obj/structure/chair/wood/wings/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/mahogany +/obj/structure/chair/wood/wings/maple + color = WOOD_COLOR_PALE + material = /decl/material/solid/organic/wood/maple +/obj/structure/chair/wood/wings/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/ebony +/obj/structure/chair/wood/wings/walnut + color = WOOD_COLOR_CHOCOLATE + material = /decl/material/solid/organic/wood/walnut + +/obj/structure/chair/backed + name_prefix = "backed" + desc = "A tall chair with a sturdy back. Not very comfortable." + icon = 'icons/obj/structures/furniture/chair_backed.dmi' + reinf_material = null + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + +/obj/structure/chair/backed/get_material_icon() + return material?.backed_chair_icon || initial(icon) + +/obj/structure/chair/slatted + name = "seat" + name_prefix = "slatted" // slatted wooden seat vs wooden slatted seat + icon = 'icons/obj/structures/furniture/chair_slatted.dmi' + reinf_material = null + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + +/obj/structure/chair/slatted/get_material_icon() + return material?.slatted_seat_icon || initial(icon) \ No newline at end of file diff --git a/code/game/objects/structures/chairs/rustic_chairs.dm b/code/game/objects/structures/chairs/rustic_chairs.dm new file mode 100644 index 000000000000..a61ca9b1a171 --- /dev/null +++ b/code/game/objects/structures/chairs/rustic_chairs.dm @@ -0,0 +1,21 @@ +/obj/structure/chair/rustic + name_prefix = "rustic" + desc = "A simple, rustic-looking chair. Looks like it'd hurt to sit on for too long..." + icon = 'icons/obj/structures/furniture/chair_rustic.dmi' + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + user_comfort = -0.5 + buckle_pixel_shift = TRUE // use chair offset + +/obj/structure/chair/rustic_fancy + name_prefix = "fancy" + desc = "An ornate, detailed chair made from wood. It has armrests!" + icon = 'icons/obj/structures/furniture/chair_rustic_fancy.dmi' + material = /decl/material/solid/organic/wood/oak + color = COLOR_WHITE // preview state is precolored + initial_padding_material = /decl/material/solid/organic/cloth + initial_padding_color = COLOR_CHERRY_RED + user_comfort = 1.25 + +/obj/structure/chair/rustic_fancy/ebony + material = /decl/material/solid/organic/wood/ebony diff --git a/code/game/objects/structures/chairs/wheelchair.dm b/code/game/objects/structures/chairs/wheelchair.dm new file mode 100644 index 000000000000..97b79c15d7af --- /dev/null +++ b/code/game/objects/structures/chairs/wheelchair.dm @@ -0,0 +1,148 @@ +/obj/structure/chair/wheelchair + name = "wheelchair" + desc = "Now we're getting somewhere." + icon = 'icons/obj/structures/furniture/wheelchair.dmi' + anchored = FALSE + buckle_movable = TRUE + movement_handlers = list( + /datum/movement_handler/deny_multiz, + /datum/movement_handler/delay = list(5), + /datum/movement_handler/move_relay_self + ) + tool_interaction_flags = TOOL_INTERACTION_NONE + material_alteration = MAT_FLAG_ALTERATION_NONE + padding_extension_type = null // Cannot be padded. + + var/item_form_type = /obj/item/wheelchair_kit + // TODO: Replace with reagent holder? This doesn't even properly handle non-human bloodstains. + var/bloodiness + +/obj/structure/chair/wheelchair/Initialize() + . = ..() + + if(!item_form_type) + verbs -= .verb/collapse + +/obj/structure/chair/wheelchair/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + user_unbuckle_mob(user) + return TRUE + +/obj/structure/chair/wheelchair/Bump(atom/A) + ..() + if(!buckled_mob) + return + + if(!propelled) + return + + var/mob/living/occupant = unbuckle_mob() + occupant.throw_at(A, 3, 3) + + var/def_zone = ran_zone() + var/blocked = 100 * occupant.get_blocked_ratio(def_zone, BRUTE, damage = 10) + occupant.throw_at(A, 3, 3) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone) + playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) + if(isliving(A)) + var/mob/living/victim = A + def_zone = ran_zone() + blocked = 100 * victim.get_blocked_ratio(def_zone, BRUTE, damage = 10) + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone) + occupant.visible_message(SPAN_DANGER("\The [occupant] crashed into \the [A]!")) + +/obj/structure/chair/wheelchair/proc/create_track() + var/obj/effect/decal/cleanable/blood/tracks/B = new(loc) + var/newdir = get_dir(get_step(loc, dir), loc) + if(newdir == dir) + B.set_dir(newdir) + else + newdir = newdir | dir + if(newdir == 3) + newdir = 1 + else if(newdir == 12) + newdir = 4 + B.set_dir(newdir) + bloodiness-- + +/proc/equip_wheelchair(mob/living/human/H) //Proc for spawning in a wheelchair if a new character has no legs. Used in new_player.dm + var/obj/structure/chair/wheelchair/wheelchair = new(get_turf(H)) + if(isturf(H.loc)) + wheelchair.buckle_mob(H) + +/obj/structure/chair/wheelchair/verb/collapse() + set name = "Collapse Wheelchair" + set category = "Object" + set src in oview(1) + + if(!item_form_type) + return + + if(!CanPhysicallyInteract(usr)) + return + + if(!ishuman(usr)) + return + + if(usr.incapacitated()) + return + + if(buckled_mob) + to_chat(usr, SPAN_WARNING("You can't collapse \the [src] while it is still in use.")) + return + + usr.visible_message("[usr] starts to collapse \the [src].") + if(do_after(usr, 4 SECONDS, src)) + var/obj/item/wheelchair_kit/K = new item_form_type(get_turf(src)) + visible_message(SPAN_NOTICE("[usr] collapses \the [src].")) + K.add_fingerprint(usr) + qdel(src) + +/obj/structure/chair/wheelchair/handle_buckled_relaymove(var/datum/movement_handler/mh, var/mob/mob, var/direction, var/mover) + if(isspaceturf(loc)) + return // No wheelchair driving in space + . = MOVEMENT_HANDLED + if(!mob.has_held_item_slot()) + return // No hands to drive your chair? Tough luck! + //drunk wheelchair driving + direction = mob.AdjustMovementDirection(direction, mover) + DoMove(direction, mob) + +/obj/structure/chair/wheelchair/relaymove(mob/user, direction) + if(user) + user.glide_size = glide_size + step(src, direction) + set_dir(direction) + +/obj/item/wheelchair_kit + name = "compressed wheelchair kit" + desc = "Collapsed parts, prepared to immediately spring into the shape of a wheelchair." + icon = 'icons/obj/items/wheelchairkit.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + max_health = 50 + var/structure_form_type = /obj/structure/chair/wheelchair + +/obj/item/wheelchair_kit/attack_self(mob/user) + if(!structure_form_type) + return + + user.visible_message("[user] starts to lay out \the [src].") + if(do_after(user, 4 SECONDS, src)) + var/obj/structure/chair/wheelchair/wheelchair = new structure_form_type(get_turf(user)) + user.visible_message("[user] lays out \the [wheelchair].") + wheelchair.add_fingerprint(user) + qdel(src) + +/obj/item/wheelchair_kit/physically_destroyed(skip_qdel) + //Make sure if the kit is destroyed to drop the same stuff as the actual wheelchair + var/obj/structure/S = new structure_form_type(get_turf(src)) + S.physically_destroyed() + . = ..() \ No newline at end of file diff --git a/code/game/objects/structures/charge_pylon.dm b/code/game/objects/structures/charge_pylon.dm index 00e0d80938d7..8c504e466205 100644 --- a/code/game/objects/structures/charge_pylon.dm +++ b/code/game/objects/structures/charge_pylon.dm @@ -1,27 +1,28 @@ -/obj/structure/adherent_pylon +/obj/structure/charge_pylon name = "electron reservoir" desc = "A tall, crystalline pylon that pulses with electricity." - icon = 'icons/obj/machines/adherent.dmi' + icon = 'icons/obj/structures/charge_pylon.dmi' icon_state = "pedestal" anchored = TRUE density = TRUE opacity = FALSE var/next_use -/obj/structure/adherent_pylon/attack_ai(var/mob/living/user) - if(Adjacent(user)) - attack_hand(user) +/obj/structure/charge_pylon/attack_ai(var/mob/user) + return attack_hand_with_interaction_checks(user) || ..() -/obj/structure/adherent_pylon/attack_hand(var/mob/living/user) +/obj/structure/charge_pylon/attack_hand(var/mob/user) + SHOULD_CALL_PARENT(FALSE) charge_user(user) + return TRUE -/obj/structure/adherent_pylon/proc/charge_user(var/mob/living/user) +/obj/structure/charge_pylon/proc/charge_user(var/mob/living/user) if(next_use > world.time) return next_use = world.time + 10 - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user var/obj/item/cell/power_cell if(ishuman(user)) - var/obj/item/organ/internal/cell/cell = locate() in H.internal_organs + var/obj/item/organ/internal/cell/cell = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) if(cell && cell.cell) power_cell = cell.cell else if(isrobot(user)) @@ -34,27 +35,31 @@ if(power_cell) power_cell.charge = power_cell.maxcharge to_chat(user, "Your [power_cell] has been charged to capacity.") - if(isrobot(user)) + else if(isrobot(user)) user.apply_damage(150, BURN, def_zone = BP_CHEST) visible_message("Electricity arcs off [user] as it touches \the [src]!") to_chat(user, "You detect damage to your components!") + user.throw_at(get_step(user,get_dir(src,user)), 5, 10) else user.electrocute_act(100, src, def_zone = BP_CHEST) visible_message("\The [user] has been shocked by \the [src]!") - user.throw_at(get_step(user,get_dir(src,user)), 5, 10) + user.throw_at(get_step(user,get_dir(src,user)), 5, 10) -/obj/structure/adherent_pylon/attackby(var/obj/item/grab/G, mob/user) - if(!istype(G)) - return - var/mob/M = G.get_affecting_mob() +/obj/structure/charge_pylon/attackby(var/obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/grab)) + return FALSE + var/obj/item/grab/grab = used_item + var/mob/M = grab.get_affecting_mob() if(M) charge_user(M) + return TRUE + return FALSE -/obj/structure/adherent_pylon/Bumped(atom/AM) +/obj/structure/charge_pylon/Bumped(atom/AM) if(ishuman(AM)) charge_user(AM) -/obj/structure/adherent_pylon/hitby(atom/AM) - . =..() - if(ishuman(AM)) - charge_user(AM) \ No newline at end of file +/obj/structure/charge_pylon/hitby(atom/AM) + . = ..() + if(. && ishuman(AM)) + charge_user(AM) diff --git a/code/game/objects/structures/chemistry/filter_stand.dm b/code/game/objects/structures/chemistry/filter_stand.dm new file mode 100644 index 000000000000..3bffecf5ffe2 --- /dev/null +++ b/code/game/objects/structures/chemistry/filter_stand.dm @@ -0,0 +1,143 @@ +/obj/structure/filter_stand + name = "filtration stand" + desc = "A frame suitable for fitting a sieve or filter into, for use in separating liquids and solids." + icon = 'icons/obj/structures/sieve.dmi' + icon_state = ICON_STATE_WORLD + density = TRUE + anchored = TRUE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 200 + + var/obj/item/chems/filter/filter + var/obj/item/chems/glass/loaded + +/obj/structure/filter_stand/mapped/Initialize(ml, _mat, _reinf_mat) + filter = new(src) + set_loaded_vessel(new /obj/item/chems/glass/handmade/jar(src)) + . = ..() + +/obj/structure/filter_stand/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/chems/filter)) + if(filter) + to_chat(user, SPAN_WARNING("\The [src] already has \a [filter] inserted.")) + else if(user.try_unequip(used_item, src)) + to_chat(user, SPAN_NOTICE("You insert \the [used_item] into \the [src].")) + filter = used_item + update_icon() + return TRUE + + if(istype(used_item, /obj/item/chems/glass)) + if(loaded) + to_chat(user, SPAN_WARNING("\The [src] already has \a [loaded] inserted.")) + else if(user.try_unequip(used_item, src)) + to_chat(user, SPAN_NOTICE("You insert \the [used_item] into \the [src].")) + set_loaded_vessel(used_item) + return TRUE + + return ..() + +/obj/structure/filter_stand/Exited(atom/movable/am, atom/new_loc) + . = ..() + if(am != loaded) + return + set_loaded_vessel(null, skip_loc_change = TRUE) + if(ismob(new_loc)) + visible_message(SPAN_NOTICE("\The [new_loc] removes \the [am] from \the [src].")) + +/obj/structure/filter_stand/proc/set_loaded_vessel(new_vessel, skip_loc_change) + if(new_vessel == loaded) + return + if(loaded) + loaded.vis_flags = initial(loaded.vis_flags) + vis_contents -= loaded + if(!skip_loc_change) + loaded.dropInto(loc) + loaded.appearance_flags = initial(loaded.appearance_flags) + loaded = null + loaded = new_vessel + if(loaded) + loaded.reset_offsets(anim_time = 0) + loaded.pixel_z = -4 + loaded.vis_flags |= (VIS_INHERIT_LAYER | VIS_INHERIT_PLANE) + loaded.appearance_flags |= RESET_COLOR + vis_contents |= loaded + +/obj/structure/filter_stand/attack_hand(mob/user) + if(filter) + filter.dropInto(loc) + user.put_in_hands(filter) + to_chat(user, SPAN_NOTICE("You remove \the [filter] from \the [src].")) + filter = null + update_icon() + return TRUE + return ..() + +/obj/structure/filter_stand/on_update_icon() + . = ..() + if(istype(filter)) + add_overlay(filter.get_stand_overlay()) + add_overlay("[icon_state]-overlay") + +// Pouring directly into the filter via attackby() is not working, so we just dump our reagents into our filter or the turf. +/obj/structure/filter_stand/on_reagent_change() + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + return + if(REAGENT_MAXIMUM_VOLUME(filter?.reagents)) + var/taking = min(REAGENT_TOTAL_VOLUME(reagents), REAGENTS_FREE_SPACE(filter.reagents)) + if(taking > 0) + reagents.trans_to_holder(filter.reagents, taking) + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + return + var/turf/my_turf = get_turf(src) + if(istype(my_turf)) + reagents.trans_to_turf(my_turf, REAGENT_TOTAL_VOLUME(reagents)) + +/obj/item/chems/filter + name = "filter" + desc = "A small square object used in a filtration stand to filter liquids and solids from each other." + icon = 'icons/obj/items/sieve_filter.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + material_alteration = MAT_FLAG_ALTERATION_ALL + material = /decl/material/solid/organic/cloth + chem_volume = 100 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + +/obj/item/chems/filter/on_reagent_change() + . = ..() + if(REAGENT_TOTAL_LIQUID_VOLUME(reagents)) + if(!is_processing) + START_PROCESSING(SSobj, src) + else + if(is_processing) + STOP_PROCESSING(SSobj, src) + +/obj/item/chems/filter/Process() + if(!REAGENT_TOTAL_LIQUID_VOLUME(reagents)) + return PROCESS_KILL + + var/dumping = 0 + var/dripping = min(REAGENT_TOTAL_LIQUID_VOLUME(reagents), rand(3,5)) + var/obj/structure/filter_stand/stand = loc + if(!istype(stand) || stand.filter != src || !stand.loaded?.reagents) + dumping = dripping + dripping = 0 + else + var/use_loaded = min(dripping, REAGENTS_FREE_SPACE(stand.loaded.reagents)) + dripping -= use_loaded + dumping = dripping + dripping = use_loaded + + if(dripping) + reagents.trans_to_holder(stand.loaded.reagents, dripping, transferred_phases = MAT_PHASE_LIQUID) + if(dumping) + var/turf/dump_turf = get_turf(stand) + if(istype(dump_turf)) + reagents.trans_to_turf(dump_turf, dumping, transferred_phases = MAT_PHASE_LIQUID) + +/obj/item/chems/filter/proc/get_stand_overlay() + return list(overlay_image(icon, "[icon_state]-inserted", material?.color, RESET_COLOR)) diff --git a/code/game/objects/structures/chemistry/heater.dm b/code/game/objects/structures/chemistry/heater.dm new file mode 100644 index 000000000000..bf0c3a573feb --- /dev/null +++ b/code/game/objects/structures/chemistry/heater.dm @@ -0,0 +1,98 @@ +/obj/structure/fire_source/heater + name = "heater" + desc = "A small, squat burner, generally used for heating reagents." + icon = 'icons/obj/structures/alembic.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/stone/pottery + material_alteration = MAT_FLAG_ALTERATION_ALL + + var/obj/item/retort + var/obj/item/vessel + +/obj/structure/fire_source/heater/mapped/Initialize() + set_retort(new /obj/item/chems/glass/retort(src)) + return ..() + +/obj/structure/fire_source/heater/Destroy() + QDEL_NULL(retort) + QDEL_NULL(vessel) + return ..() + +/obj/structure/fire_source/heater/physically_destroyed(skip_qdel) + if(retort) + set_retort(null) + if(vessel) + set_vessel(null) + return ..() + +// Vessel is to the side, not on the flame. +/obj/structure/fire_source/heater/get_contained_temperature_sensitive_atoms() + . = ..() + if(LAZYLEN(.) && vessel) + LAZYREMOVE(., vessel) + +/obj/structure/fire_source/heater/proc/set_vessel(new_vessel, skip_loc_change) + if(new_vessel == vessel) + return + if(vessel) + vessel.vis_flags = initial(vessel.vis_flags) + vis_contents -= vessel + if(!skip_loc_change) + vessel.dropInto(loc) + vessel = null + vessel = new_vessel + if(vessel) + vessel.reset_offsets(anim_time = 0) + vessel.pixel_w = 7 + vessel.pixel_z = 2 + vessel.vis_flags |= (VIS_INHERIT_LAYER | VIS_INHERIT_PLANE) + vis_contents |= vessel + +/obj/structure/fire_source/heater/proc/set_retort(new_retort, skip_loc_change) + if(new_retort == retort) + return + if(retort) + retort.vis_flags = initial(retort.vis_flags) + vis_contents -= retort + if(!skip_loc_change) + retort.dropInto(loc) + retort = null + retort = new_retort + if(retort) + retort.reset_offsets(anim_time = 0) + retort.pixel_z = 6 + retort.vis_flags |= (VIS_INHERIT_LAYER | VIS_INHERIT_PLANE) + vis_contents |= retort + +/obj/structure/fire_source/heater/Exited(atom/movable/am, atom/new_loc) + . = ..() + if(am == vessel) + set_vessel(null, skip_loc_change = TRUE) + else if(am == retort) + set_retort(null, skip_loc_change = TRUE) + else + return + if(ismob(new_loc)) + visible_message(SPAN_NOTICE("\The [new_loc] removes \the [am] from \the [src].")) + +/obj/structure/fire_source/heater/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/chems/glass) && ATOM_IS_OPEN_CONTAINER(used_item)) + if(retort && vessel) + to_chat(user, SPAN_WARNING("\The [src] is already holding \a [retort] and \a [vessel].")) + return TRUE + if(user.try_unequip(used_item, src)) + if(!retort) + set_retort(used_item) + visible_message(SPAN_NOTICE("\The [user] places \the [retort] onto \the [src].")) + else if(!vessel) + set_vessel(used_item) + visible_message(SPAN_NOTICE("\The [user] places \the [vessel] under \the [src].")) + return TRUE + + . = ..() + +/obj/structure/fire_source/heater/take_vaporized_reagent(reagent, amount) + if(!vessel || !vessel.reagents || REAGENTS_FREE_SPACE(vessel.reagents) <= 0) + return ..() + return vessel.take_vaporized_reagent(reagent, amount) diff --git a/code/game/objects/structures/cliffs.dm b/code/game/objects/structures/cliffs.dm new file mode 100644 index 000000000000..5745913052ab --- /dev/null +++ b/code/game/objects/structures/cliffs.dm @@ -0,0 +1,300 @@ +/* +Cliffs give a visual illusion of depth by separating two places while presenting a 'top' and 'bottom' side. + +Ported from Polaris. + +Mobs moving into a cliff from the bottom side will simply bump into it and be denied moving into the tile, +where as mobs moving into a cliff from the top side will 'fall' off the cliff, forcing them to the bottom, causing significant damage and stunning them. + +Mobs can climb this while wearing climbing equipment by clickdragging themselves onto a cliff, as if it were a table. + +Flying mobs can pass over all cliffs with no risk of falling. + +Projectiles and thrown objects can pass, however if moving upwards, there is a chance for it to be stopped by the cliff. +This makes fighting something that is on top of a cliff more challenging. + +As a note, dir points upwards, e.g. pointing WEST means the left side is 'up', and the right side is 'down'. + +When mapping these in, be sure to give at least a one tile clearance, as NORTH facing cliffs expand to +two tiles on initialization, and which way a cliff is facing may change during maploading. +*/ + +/obj/structure/cliff + name = "cliff" + desc = "A steep rock ledge. You might be able to climb it if you feel bold enough." + icon = 'icons/obj/structures/cliffs.dmi' + anchored = TRUE + density = TRUE + opacity = FALSE + atom_flags = ATOM_FLAG_CLIMBABLE + appearance_flags = KEEP_TOGETHER + climb_speed_mult = 2 + + var/icon_variant = null // Used to make cliffs less repetitive by having a selection of sprites to display. + var/corner = FALSE // Used for icon things. + var/ramp = FALSE // Ditto. + var/bottom = FALSE // Used for 'bottom' typed cliffs, to avoid infinite cliffs, and for icons. + + var/is_double_cliff = FALSE // Set to true when making the two-tile cliffs, used for projectile checks. + var/uphill_penalty = 30 // Odds of a projectile not making it up the cliff. + +/obj/structure/cliff/Initialize() + . = ..() + register_dangerous_to_step() + +/obj/structure/cliff/Destroy() + unregister_dangerous_to_step() + if(is_double_cliff && !bottom) + var/turf/other = get_step(src, SOUTH) + if(istype(other)) + for(var/obj/structure/cliff/bottom/bottom in other) + qdel(bottom) + . = ..() + +/obj/structure/cliff/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + var/static/desc_string = "Walking off the edge of a cliff while on top will cause you to fall off, causing severe injury.
              \ + You can climb this cliff if wearing special climbing equipment, by click-dragging yourself onto the cliff.
              \ + Projectiles traveling up a cliff may hit the cliff instead, making it more difficult to fight something \ + on top." + LAZYADD(., desc_string) + +/obj/structure/cliff/Move() + var/turf/old_turf = get_turf(src) + . = ..() + if(.) + var/turf/new_turf = get_turf(src) + if(old_turf != new_turf) + old_turf.unregister_dangerous_object(src) + new_turf.register_dangerous_object(src) + +// These arrange their sprites at runtime, as opposed to being statically placed in the map file. +/obj/structure/cliff/automatic + icon_state = "cliffbuilder" + dir = NORTH + +/obj/structure/cliff/automatic/corner + icon_state = "cliffbuilder-corner" + dir = NORTHEAST + corner = TRUE + +// Tiny part that doesn't block, used for making 'ramps'. +/obj/structure/cliff/automatic/ramp + icon_state = "cliffbuilder-ramp" + dir = NORTHEAST + density = FALSE + ramp = TRUE + +// Made automatically as needed by automatic cliffs. +/obj/structure/cliff/bottom + bottom = TRUE + is_spawnable_type = FALSE + +/obj/structure/cliff/automatic/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +// Paranoid about the maploader, direction is very important to cliffs, since they may get bigger if initialized while facing NORTH. +/obj/structure/cliff/automatic/LateInitialize() + if(dir in global.cardinal) + icon_variant = pick("a", "b", "c") + + if(dir & NORTH && !bottom) // North-facing cliffs require more cliffs to be made. + make_bottom() + + update_icon() + +/obj/structure/cliff/proc/make_bottom() + // First, make sure there's room to put the bottom side. + var/turf/turf = locate(x, y - 1, z) + if(!istype(turf)) + return FALSE + + // Now make the bottom cliff have mostly the same variables. + var/obj/structure/cliff/bottom/bottom_cliff = new(turf) + is_double_cliff = TRUE + climb_speed_mult /= 2 // Since there are two cliffs to climb when going north, both take half the time. + + bottom_cliff.dir = dir + bottom_cliff.is_double_cliff = TRUE + bottom_cliff.climb_speed_mult = climb_speed_mult + bottom_cliff.icon_variant = icon_variant + bottom_cliff.corner = corner + bottom_cliff.ramp = ramp + bottom_cliff.layer = layer - 0.1 + bottom_cliff.density = density + bottom_cliff.update_icon() + +/obj/structure/cliff/set_dir(new_dir) + ..() + update_icon() + +/obj/structure/cliff/on_update_icon() + icon_state = "cliff-[dir][icon_variant][bottom ? "-bottom" : ""][corner ? "-corner" : ""][ramp ? "-ramp" : ""]" + + // Now for making the top-side look like a different turf. + var/turf/turf = get_step(src, dir) + if(!istype(turf)) + return + + underlays.Cut() + var/subtraction_icon_state = "[icon_state]-subtract" + if(turf && (check_state_in_icon(subtraction_icon_state, icon))) + var/image/subtract = image(icon, subtraction_icon_state) + subtract.blend_mode = BLEND_SUBTRACT + underlays += subtract + +// Movement-related code. +/obj/structure/cliff/CanPass(atom/movable/mover, turf/target) + if(isliving(mover)) + var/mob/living/faller = mover + if(faller.can_overcome_gravity()) // Flying mobs can always pass. + return TRUE + return ..() + + else if(!istype(mover, /obj/item/projectile) && !mover.throwing) // 'sliding' objects can fall / bump into cliffs. + return ..() + + // Projectiles and objects flying 'upward' have a chance to hit the cliff instead, wasting the shot. + else if(istype(mover, /obj)) + var/obj/O = mover + if(check_shield_arc(src, dir, O)) // This is actually for mobs but it will work for our purposes as well. + if(prob(uphill_penalty / (1 + is_double_cliff) )) // Firing upwards facing NORTH means it will likely have to pass through two cliffs, so the chance is halved. + return FALSE + return TRUE + +/obj/structure/cliff/Bumped(atom/movable/mover) + if(!istype(mover, /obj/item/projectile) && !mover.throwing && should_fall(mover)) + fall_off_cliff(mover) + return + ..() + +/obj/structure/cliff/proc/should_fall(atom/movable/mover) + if(isliving(mover)) + var/mob/living/faller = mover + if(faller.can_overcome_gravity()) + return FALSE + var/turf/turf = get_turf(mover) + if(turf && get_dir(turf, loc) & global.reverse_dir[dir]) // dir points 'up' the cliff, e.g. cliff pointing NORTH will cause someone to fall if moving SOUTH into it. + return TRUE + return FALSE + +/obj/structure/cliff/proc/fall_off_cliff(atom/movable/mover) + . = FALSE + + var/mob/living/faller + if(isliving(mover)) + faller = mover + var/turf/turf = get_step(src, global.reverse_dir[dir]) + var/displaced = FALSE + + if(dir in list(EAST, WEST)) // Apply an offset if flying sideways, to help maintain the illusion of depth. + for(var/i = 1 to 2) + var/turf/new_T = locate(turf.x, turf.y - i, turf.z) + if(!new_T || locate(/obj/structure/cliff) in new_T) + break + turf = new_T + displaced = TRUE + + if(!istype(turf)) + return + + var/safe_fall = FALSE + if(istype(faller)) + safe_fall = faller.can_overcome_gravity() + else if(istype(mover, /obj/vehicle/bike)) + var/obj/vehicle/bike/Bi = mover + if(Bi.on) + safe_fall = TRUE + + // Buckled people can't react to save themselves, if they're not on a vehicle. + if(!istype(mover, /obj/vehicle) && !isexosuit(mover) && !faller && mover.buckled_mob) + faller = mover.buckled_mob + + if(safe_fall) + visible_message(SPAN_NOTICE("\The [mover] glides down from \the [src].")) + else + visible_message(SPAN_DANGER("\The [mover] falls off \the [src]!")) + + mover.forceMove(turf) + + var/harm = !is_double_cliff ? 1 : 0.5 + if(!safe_fall) + // Do the actual hurting. Double cliffs do halved damage due to them most likely hitting twice. + if(faller) + SET_STATUS_MAX(faller, STAT_WEAK, (5 * harm)) + + if(istype(mover, /obj/vehicle)) + var/obj/vehicle/vehicle = mover + vehicle.take_damage(40 * harm) + vehicle.visible_message(SPAN_WARNING("\The [vehicle] absorbs some of the impact, damaging it.")) + harm = round(harm * 0.5) + if(vehicle.buckled_mob) + var/damage = clamp(vehicle.buckled_mob.get_max_health() * 0.4, 20, 100) + vehicle.buckled_mob.take_damage(damage * harm, BRUTE, inflicter = src) + shake_camera(vehicle.buckled_mob, 1, 1) + else if(isexosuit(mover)) + var/mob/living/exosuit/Mech = mover + harm = round(harm * 0.5) + var/list/passengers = list() + for(var/mob/living/passenger in Mech.pilots) + passengers |= passenger + passenger.take_damage(clamp(faller.get_max_health() * 0.4, 10, 50) * harm, BRUTE, inflicter = src) + shake_camera(passenger, 1, 1) + to_chat(passenger, SPAN_DANGER("\The [Mech] shakes, bouncing you violently!")) + Mech.take_damage(clamp(Mech.get_max_health() * 0.4 * harm, 50, 300)) + if(QDELETED(Mech) && length(passengers)) // Damage caused the mech to explode, or otherwise vanish. + for(var/mob/living/victim in passengers) + to_chat(victim, SPAN_DANGER("The exosuit shears apart around you, throwing you from the debris!")) + victim.throw_at_random(FALSE,2,1, 32) + + playsound(mover, 'sound/effects/break_stone.ogg', 70, 1) + + var/fall_time = 3 + if(displaced) // Make the fall look more natural when falling sideways. + mover.pixel_z = 32 * 2 + animate(mover, pixel_z = 0, time = fall_time) + + sleep(fall_time) // A brief delay inbetween the two sounds helps sell the 'ouch' effect. + + if(QDELETED(src) || QDELETED(mover) || QDELETED(turf)) + return + + if(safe_fall) + visible_message(SPAN_NOTICE("\The [mover] lands on \the [turf].")) + playsound(mover, "rustle", 25, 1) + return + + playsound(mover, "punch", 70, 1) + + visible_message(SPAN_DANGER("\The [mover] hits \the [turf]!")) + + if(faller) + // The bigger they are, the harder they fall. + // They will take at least 20 damage at the minimum, and tries to scale up to 40% of their max health. + // This scaling is capped at 100 total damage, which occurs if the thing that fell has more than 250 health. + faller.take_damage(clamp(faller.get_max_health() * 0.4, 20, 100) * harm, BRUTE, ran_zone(), inflicter = src) + shake_camera(faller, 1, 1) + + // Now fall off more cliffs below this one if they exist. + var/obj/structure/cliff/bottom_cliff = locate() in turf + if(bottom_cliff && !QDELETED(mover)) // Exosuits are deleted when destroyed. This is to prevent phantom exosuits. + visible_message(SPAN_DANGER("\The [mover] rolls down towards \the [bottom_cliff]!")) + addtimer(CALLBACK(bottom_cliff, TYPE_PROC_REF(/obj/structure/cliff, fall_off_cliff), mover), 5) + +/obj/structure/cliff/can_climb(mob/living/user, post_climb_check = FALSE, silent = FALSE) + // Cliff climbing requires climbing gear. + if(ishuman(user)) + var/mob/living/human/H = user + var/obj/item/clothing/shoes/shoes = H.get_equipped_item(slot_shoes_str) + if(shoes?.rock_climbing) + return ..() // Do the other checks too. + if(!silent) + to_chat(user, SPAN_WARNING("\The [src] is too steep to climb unassisted.")) + return FALSE + +// This tells AI mobs to not be dumb and step off cliffs willingly. +/obj/structure/cliff/is_safe_to_step(mob/living/stepper) + if(should_fall(stepper)) + return FALSE + return ..() diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm index 45b6ce273297..155a7eeff3dc 100644 --- a/code/game/objects/structures/coathanger.dm +++ b/code/game/objects/structures/coathanger.dm @@ -1,51 +1,93 @@ /obj/structure/coatrack name = "coat rack" - desc = "Rack that holds coats." + desc = "A rack that holds coats." icon = 'icons/obj/structures/coatrack.dmi' icon_state = "coatrack0" - var/obj/item/clothing/suit/coat - var/list/allowed = list(/obj/item/clothing/suit/storage/toggle/labcoat, /obj/item/clothing/suit/storage/det_trench) + material = /decl/material/solid/organic/wood/mahogany + color = /decl/material/solid/organic/wood/mahogany::color + material_alteration = (MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR) + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + var/max_items = 3 + var/tmp/list/slots_allowed + var/tmp/list/blacklisted_types = list(/obj/item/clothing/suit/space) + +/obj/structure/coatrack/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/coatrack/dismantle_structure(mob/user) + for(var/obj/item/thing in contents) + thing.dropInto(loc) + . = ..() + +/obj/structure/coatrack/Initialize(ml, _mat, _reinf_mat) + slots_allowed = list( + "[slot_wear_suit_str]" = SLOT_OVER_BODY, + "[slot_head_str]" = SLOT_HEAD + ) + . = ..() + +/obj/structure/coatrack/on_update_icon() + ..() + var/offset = -3 + for(var/obj/item/thing in contents) + for(var/slot in slots_allowed) + if(thing.slot_flags & slots_allowed[slot]) + var/image/I = thing.get_mob_overlay(null, slot) + if(I) + I.pixel_z += offset + add_overlay(I) + offset += 3 + break /obj/structure/coatrack/attack_hand(mob/user) - user.visible_message("[user] takes [coat] off \the [src].", "You take [coat] off the \the [src]") - if(!user.put_in_active_hand(coat)) - coat.dropInto(user.loc) - coat = null + if(!length(contents) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/obj/item/removing = contents[contents.len] + user.visible_message( \ + SPAN_NOTICE("\The [user] takes \the [removing] off \the [src]."), + SPAN_NOTICE("You take \the [removing] off \the [src].") + ) + removing.dropInto(loc) + user.put_in_active_hand(removing) update_icon() + return TRUE -/obj/structure/coatrack/attackby(obj/item/W, mob/user) - var/can_hang = 0 - for (var/T in allowed) - if(istype(W,T)) - can_hang = 1 - if (can_hang && !coat && user.unEquip(coat, src)) - user.visible_message("[user] hangs [W] on \the [src].", "You hang [W] on the \the [src]") - coat = W - update_icon() - else - to_chat(user, "You cannot hang [W] on [src]") +/obj/structure/coatrack/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(length(contents)) + . += SPAN_NOTICE("It has the following [length(contents) == 1 ? "article" : "articles"] hanging on it:") + for(var/obj/item/thing in contents) + . += "- \icon[thing] \The [thing]." + +/obj/structure/coatrack/proc/can_hang(var/obj/item/thing) + if(!istype(thing)) + return FALSE + for(var/blacklisted_type in blacklisted_types) + if(istype(thing, blacklisted_type)) + return FALSE + for(var/slot in slots_allowed) + if(thing.slot_flags & slots_allowed[slot]) + return TRUE + +/obj/structure/coatrack/attackby(obj/item/used_item, mob/user) + if(!can_hang(used_item)) return ..() + if(length(contents) >= max_items) + to_chat(user, SPAN_NOTICE("There is no room on \the [src] to hang \the [used_item].")) + return TRUE + if(user.try_unequip(used_item, src)) + user.visible_message( \ + SPAN_NOTICE("\The [user] hangs \the [used_item] on \the [src]."), \ + SPAN_NOTICE("You hang \the [used_item] on \the [src].") \ + ) + update_icon() + return TRUE /obj/structure/coatrack/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - var/can_hang = 0 - for (var/T in allowed) - if(istype(mover,T)) - can_hang = 1 - - if (can_hang && !coat) - src.visible_message("[mover] lands on \the [src].") - coat = mover - coat.forceMove(src) + if(can_hang(mover) && length(contents) < max_items) + visible_message(SPAN_NOTICE("\The [mover] lands on \the [src]!")) + mover.forceMove(src) update_icon() - return 0 - else - return 1 - -/obj/structure/coatrack/on_update_icon() - overlays.Cut() - if (istype(coat, /obj/item/clothing/suit/storage/toggle/labcoat)) - overlays += image(icon, icon_state = "coat_lab") - if (istype(coat, /obj/item/clothing/suit/storage/toggle/labcoat/cmo)) - overlays += image(icon, icon_state = "coat_cmo") - if (istype(coat, /obj/item/clothing/suit/storage/det_trench)) - overlays += image(icon, icon_state = "coat_det") + return FALSE + return TRUE diff --git a/code/game/objects/structures/compost.dm b/code/game/objects/structures/compost.dm new file mode 100644 index 000000000000..b1929ed281e6 --- /dev/null +++ b/code/game/objects/structures/compost.dm @@ -0,0 +1,200 @@ +/// The number of worms influences the rate at which contents are decomposed into compost. +var/global/const/COMPOST_WORM_EAT_AMOUNT = 50 +var/global/const/COMPOST_MAX_WORMS = 10 +var/global/const/COMPOST_WORM_HUNGER_FACTOR = MINIMUM_CHEMICAL_VOLUME + +/obj/structure/reagent_dispensers/compost_bin + name = "compost bin" + desc = "A squat bin for decomposing organic material." + icon = 'icons/obj/structures/compost.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + matter = null + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + wrenchable = FALSE + possible_transfer_amounts = @"[10,25,50,100]" + chem_volume = 2000 + storage = /datum/storage/hopper/industrial/compost + +/obj/structure/reagent_dispensers/compost_bin/Initialize() + // Building one outside should give you some Free Worms:tm:. + // Station needs to add worms (when worms are in code). + var/turf/turf = get_turf(src) + if(istype(turf)) + var/worms = round(5 * turf.get_plant_growth_rate()) + if(worms) + for(var/i = 1 to worms) + var/obj/item/food/worm/worm = new(src) + if(!storage.handle_item_insertion(null, worm)) + qdel(worm) + break + . = ..() + +/obj/structure/reagent_dispensers/compost_bin/Destroy() + if(is_processing) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/structure/reagent_dispensers/compost_bin/on_update_icon() + . = ..() + icon_state = ICON_STATE_WORLD + if(ATOM_IS_OPEN_CONTAINER(src)) + add_overlay(overlay_image(icon, "[icon_state]-hinges-open", null, RESET_COLOR)) + add_overlay(overlay_image(icon, "[icon_state]-open", get_color(), RESET_COLOR)) // leaving the door open for separate lid materials in the future + else + add_overlay(overlay_image(icon, "[icon_state]-hinges", null, RESET_COLOR)) + +/obj/structure/reagent_dispensers/compost_bin/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + + var/worms = 0 + for(var/obj/item/food/worm/worm in get_stored_inventory()) + worms++ + + switch(worms) + if(0) + . += SPAN_WARNING("There are no worms in \the [src].") + if(1) + . += SPAN_NOTICE("A lonely worm wiggles around in \the [src].") + if(2 to 3) + . += SPAN_NOTICE("A few worms wiggle around in \the [src].") + if(4 to 6) + . += SPAN_NOTICE("A healthy number of worms wiggle around in \the [src].") + else + . += SPAN_NOTICE("A thriving worm colony wiggles around in \the [src].") + + var/list/composting = list() + for(var/thing in get_stored_inventory()) + if(!istype(thing, /obj/item/food/worm)) + composting += thing + + if(length(composting)) + . += SPAN_NOTICE("[capitalize(english_list(composting, summarize = TRUE))] [length(composting) == 1 ? "is" : "are"] composting inside \the [src].") + else + . += SPAN_NOTICE("Nothing is composting within \the [src].") + +/obj/structure/reagent_dispensers/compost_bin/Entered(var/atom/movable/AM, atom/old_loc) + . = ..() + if(!is_processing) + START_PROCESSING(SSobj, src) + +/obj/structure/reagent_dispensers/compost_bin/physically_destroyed() + dump_contents() + var/reagent_volume = REAGENT_TOTAL_VOLUME(reagents) + if(reagent_volume) + reagents.trans_to(loc, reagent_volume) + return ..() + +/obj/structure/reagent_dispensers/compost_bin/attackby(obj/item/used_item, mob/user) + + if(user.check_intent(I_FLAG_HARM)) + return ..() + + if(used_item.storage) + + var/emptied = FALSE + for(var/obj/item/O in used_item.get_stored_inventory()) + if(storage.can_be_inserted(O)) + used_item.storage.remove_from_storage(null, O, loc, skip_update = TRUE) + storage.handle_item_insertion(null, O, skip_update = TRUE) + emptied = TRUE + + if(emptied) + used_item.storage.finish_bulk_removal() + storage.update_ui_after_item_insertion() + if(length(used_item.get_stored_inventory())) + to_chat(user, SPAN_NOTICE("You partially empty \the [used_item] into \the [src]'s hopper.")) + else + to_chat(user, SPAN_NOTICE("You empty \the [used_item] into \the [src]'s hopper.")) + used_item.update_icon() + return TRUE + + return ..() + +/obj/structure/reagent_dispensers/compost_bin/Process() + + var/worms = 0 + var/list/current_contents = get_stored_inventory() + if(islist(current_contents)) + current_contents = current_contents.Copy() + + for(var/obj/item/food/worm/worm in current_contents) + current_contents -= worm + worms++ + + // No worms means no processing. + if(worms <= 0) + return PROCESS_KILL + + // Digest an item. + var/worm_eat_amount = max(1, round(worms * COMPOST_WORM_EAT_AMOUNT)) + if(length(current_contents)) + + var/obj/item/composting = pick(current_contents) + + if(composting.is_compostable()) + + // We only start composting debris, as we have no proper handling for partial decomposition + // and cannot really apply our worm decomp rate to non-debris items without it. + if(istype(composting, /obj/item/debris/scraps)) + var/obj/item/debris/scraps/lump = composting + for(var/mat in lump.matter) + var/decl/material/composting_mat = GET_DECL(mat) + if(!composting_mat.compost_value) + continue + var/composting_amount = max(1, round(clamp(worm_eat_amount, 0, lump.matter[mat]) * composting_mat.compost_value * REAGENT_UNITS_PER_MATERIAL_UNIT)) + reagents.add_reagent(/decl/material/liquid/fertilizer/compost, composting_amount) + lump.matter[mat] -= worm_eat_amount + if(lump.matter[mat] <= 0) + LAZYREMOVE(lump.matter, mat) + lump.update_primary_material() + break + + else + + for(var/obj/item/thing in composting.get_contained_external_atoms()) + thing.forceMove(src) + + if(REAGENT_TOTAL_VOLUME(composting.reagents)) + composting.reagents.trans_to_holder(reagents, REAGENT_TOTAL_VOLUME(composting.reagents)) + composting.reagents.clear_reagents() + + composting.clear_matter() + qdel(composting) + + var/obj/item/debris/scraps/remains = (locate() in contents) || new(src) + LAZYINITLIST(remains.matter) + var/list/composting_matter = composting.get_contained_matter() + for(var/mat in composting_matter) + remains.matter[mat] += composting_matter[mat] + UNSETEMPTY(remains.matter) + remains.update_primary_material() + + // Digest reagents. + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(istype(reagent, /decl/material/liquid/fertilizer)) + continue + if(!reagent.compost_value) + continue + var/clamped_worm_drink_amount = min(round(worm_eat_amount * REAGENT_UNITS_PER_MATERIAL_UNIT), REAGENT_VOLUME(reagents, reagent)) + reagents.add_reagent(/decl/material/liquid/fertilizer/compost, max(1, round(clamped_worm_drink_amount * reagent.compost_value))) + reagents.remove_reagent(reagent, clamped_worm_drink_amount) + break + + // Grow more worms. + if(REAGENT_VOLUME(reagents, /decl/material/liquid/fertilizer/compost) > 0 && prob(0.1) && worms < COMPOST_MAX_WORMS) + var/obj/item/food/worm/worm = new(src) + if(!storage.handle_item_insertion(null, worm)) + qdel(worm) + +/obj/structure/reagent_dispensers/compost_bin/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/reagent_dispensers/compost_bin/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/__closet.dm b/code/game/objects/structures/crates_lockers/closets/__closet.dm index c79cab9b9004..9e18b1611a33 100644 --- a/code/game/objects/structures/crates_lockers/closets/__closet.dm +++ b/code/game/objects/structures/crates_lockers/closets/__closet.dm @@ -1,10 +1,14 @@ +var/global/list/closets = list() + /obj/structure/closet name = "closet" desc = "It's a basic storage unit." icon = 'icons/obj/closets/bases/closet.dmi' icon_state = "base" - density = 1 - maxhealth = 100 + density = TRUE + max_health = 100 + material = /decl/material/solid/metal/steel + tool_interaction_flags = TOOL_INTERACTION_ANCHOR var/welded = 0 var/large = 1 @@ -24,17 +28,21 @@ var/opened = FALSE var/locked = FALSE +/obj/structure/closet/Destroy() + global.closets -= src + . = ..() + /obj/structure/closet/Initialize() ..() - + global.closets += src if((setup & CLOSET_HAS_LOCK)) verbs += /obj/structure/closet/proc/togglelock_verb if(ispath(closet_appearance)) - var/decl/closet_appearance/app = decls_repository.get_decl(closet_appearance) + var/decl/closet_appearance/app = GET_DECL(closet_appearance) if(app) icon = app.icon - color = null + reset_color() queue_icon_update() return INITIALIZE_HINT_LATELOAD @@ -42,48 +50,60 @@ /obj/structure/closet/LateInitialize(mapload, ...) var/list/will_contain = WillContain() if(will_contain) - create_objects_in_loc(src, will_contain) + create_objects_in_loc(opened ? loc : src, will_contain) if(!opened && mapload) // if closed and it's the map loading phase, relevant items at the crate's loc are put in the contents store_contents() -/obj/structure/closet/proc/WillContain() - return null +/obj/structure/closet/update_lock_overlay() + return // TODO + +/obj/structure/closet/can_install_lock() + return !(setup & CLOSET_HAS_LOCK) // CLOSET_HAS_LOCK refers to the access lock, not a physical lock. -/obj/structure/closet/examine(mob/user, distance) +/obj/structure/closet/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1 && !opened) var/content_size = 0 - for(var/atom/movable/AM in src.contents) + for(var/atom/movable/AM in contents) if(!AM.anchored) content_size += content_size(AM) if(!content_size) - to_chat(user, "It is empty.") + . += "It is empty." else if(storage_capacity > content_size*4) - to_chat(user, "It is barely filled.") + . += "It is barely filled." else if(storage_capacity > content_size*2) - to_chat(user, "It is less than half full.") + . += "It is less than half full." else if(storage_capacity > content_size) - to_chat(user, "There is still some free space.") + . += "There is still some free space." else - to_chat(user, "It is full.") + . += "It is full." + + var/mob/observer/ghost/G = user + if(isghost(G) && (G.client?.holder || G.antagHUD)) + . += "It contains: [counting_english_list(contents)]" /obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group || (height==0 || wall_mounted)) return 1 return (!density) -/obj/structure/closet/proc/can_open() +/obj/structure/closet/proc/can_open(mob/user) if((setup & CLOSET_HAS_LOCK) && locked) - return 0 + return FALSE if((setup & CLOSET_CAN_BE_WELDED) && welded) - return 0 - return 1 + return FALSE + if(lock) + if(user) + try_unlock(user, user.get_active_held_item()) + if(lock.isLocked()) + return FALSE + return TRUE -/obj/structure/closet/proc/can_close() +/obj/structure/closet/proc/can_close(mob/user) for(var/obj/structure/closet/closet in get_turf(src)) if(closet != src) - return 0 - return 1 + return FALSE + return TRUE /obj/structure/closet/proc/store_contents() var/stored_units = 0 @@ -94,34 +114,34 @@ stored_units += store_mobs(stored_units) if(storage_types & CLOSET_STORAGE_STRUCTURES) stored_units += store_structures(stored_units) - -/obj/structure/closet/proc/open() - if(src.opened) + +/obj/structure/closet/proc/open(mob/user) + if(opened) return 0 - if(!src.can_open()) + if(!can_open(user)) return 0 dump_contents() - src.opened = 1 - playsound(src.loc, open_sound, 50, 1, -3) - density = 0 + opened = TRUE + playsound(loc, open_sound, 50, 1, -3) + density = FALSE update_icon() - return 1 + return TRUE -/obj/structure/closet/proc/close() - if(!src.opened) +/obj/structure/closet/proc/close(mob/user) + if(!opened) return 0 - if(!src.can_close()) + if(!can_close(user)) return 0 store_contents() - src.opened = 0 + opened = 0 - playsound(src.loc, close_sound, 50, 0, -3) + playsound(loc, close_sound, 50, 0, -3) if(!wall_mounted) - density = 1 + density = TRUE update_icon() @@ -152,7 +172,7 @@ /obj/structure/closet/proc/store_mobs(var/stored_units) . = 0 for(var/mob/living/M in loc) - if(M.buckled || M.pinned.len || M.anchored) + if(M.buckled || LAZYLEN(M.pinned) || M.anchored) continue var/mob_size = content_size(M) if(CLOSET_CHECK_TOO_BIG(mob_size)) @@ -203,11 +223,10 @@ /obj/structure/closet/proc/toggle(mob/user) if(locked) togglelock(user) - else if(!(src.opened ? src.close() : src.open())) + else if(!(opened ? close(user) : open(user))) to_chat(user, "It won't budge!") update_icon() -// this should probably use dump_contents() /obj/structure/closet/explosion_act(severity) ..() if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) @@ -223,124 +242,133 @@ var/proj_damage = Proj.get_structure_damage() if(proj_damage) ..() - take_damage(proj_damage) + take_damage(proj_damage, Proj.atom_damage_type) + +// Override this so the logic in attackby() can run. +/obj/structure/closet/grab_attack(obj/item/grab/grab, mob/user) + return FALSE + +/obj/structure/closet/attackby(obj/item/used_item, mob/user) -/obj/structure/closet/attackby(obj/item/W, mob/user) - - if(user.a_intent == I_HURT && W.force) + if(user.check_intent(I_FLAG_HARM) && used_item.get_attack_force(user)) return ..() - if(!opened && istype(W, /obj/item/stack/material)) + if(!opened && (istype(used_item, /obj/item/stack/material) || IS_WRENCH(used_item)) ) return ..() - if(src.opened) - if(istype(W, /obj/item/grab)) - var/obj/item/grab/G = W - src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet - return 0 - if(isWelder(W)) - var/obj/item/weldingtool/WT = W - if(WT.remove_fuel(0,user)) - slice_into_parts(WT, user) - return - if(istype(W, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = W - if(!cutter.slice(user)) - return - slice_into_parts(W, user) - return - if(istype(W, /obj/item/storage/laundry_basket) && W.contents.len) - var/obj/item/storage/laundry_basket/LB = W - var/turf/T = get_turf(src) - for(var/obj/item/I in LB.contents) - LB.remove_from_storage(I, T, 1) - LB.finish_bulk_removal() - user.visible_message("[user] empties \the [LB] into \the [src].", \ - "You empty \the [LB] into \the [src].", \ - "You hear rustling of clothes.") - return - - if(user.unEquip(W, loc)) - W.pixel_x = 0 - W.pixel_y = 0 - W.pixel_z = 0 - W.pixel_w = 0 - return - else if(istype(W, /obj/item/energy_blade/blade)) - if(emag_act(INFINITY, user, "The locker has been sliced open by [user] with \an [W]!", "You hear metal being sliced and sparks flying.")) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src.loc) - spark_system.start() - playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) - playsound(src.loc, "sparks", 50, 1) - open() - else if(istype(W, /obj/item/stack/package_wrap)) - return - else if(isWelder(W) && (setup & CLOSET_CAN_BE_WELDED)) - var/obj/item/weldingtool/WT = W - if(!WT.remove_fuel(0,user)) - if(!WT.isOn()) - return - else - to_chat(user, "You need more welding fuel to complete this task.") - return - src.welded = !src.welded - src.update_icon() - user.visible_message("\The [src] has been [welded?"welded shut":"unwelded"] by \the [user].", blind_message = "You hear welding.", range = 3) + var/can_wield = used_item.user_can_attack_with(user, silent = TRUE) + + if(opened) + if(can_wield) + if(istype(used_item, /obj/item/grab)) + var/obj/item/grab/grab = used_item + receive_mouse_drop(grab.affecting, user) //act like they were dragged onto the closet + return TRUE + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) + slice_into_parts(welder, user) + return TRUE + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item + if(cutter.slice(user)) + slice_into_parts(used_item, user) + return TRUE + if(istype(used_item, /obj/item/laundry_basket) && used_item.contents.len && used_item.storage) + var/turf/T = get_turf(src) + for(var/obj/item/I in used_item.storage.get_contents()) + used_item.storage.remove_from_storage(user, I, T, TRUE) + used_item.storage.finish_bulk_removal() + user.visible_message( + SPAN_NOTICE("\The [user] empties \the [used_item] into \the [src]."), + SPAN_NOTICE("You empty \the [used_item] into \the [src]."), + SPAN_NOTICE("You hear rustling of clothes.") + ) + return TRUE + + if(user.try_unequip(used_item, loc)) + used_item.pixel_x = 0 + used_item.pixel_y = 0 + used_item.pixel_z = 0 + used_item.pixel_w = 0 + return TRUE + return FALSE + + if(!can_wield) + return attack_hand_with_interaction_checks(user) + + if(try_key_unlock(used_item, user)) + return TRUE + + if(try_install_lock(used_item, user)) + return TRUE + + if(istype(used_item, /obj/item/energy_blade)) + var/obj/item/energy_blade/blade = used_item + if(blade.is_special_cutting_tool() && emag_act(INFINITY, user, "The locker has been sliced open by [user] with \an [used_item]!", "You hear metal being sliced and sparks flying.")) + spark_at(loc, amount=5) + playsound(loc, 'sound/weapons/blade1.ogg', 50, 1) + open(user) + return TRUE + + if(istype(used_item, /obj/item/stack/package_wrap)) + return FALSE //Return false to get afterattack to be called + + if(IS_WELDER(used_item) && (setup & CLOSET_CAN_BE_WELDED)) + var/obj/item/weldingtool/welder = used_item + if(!welder.weld(0,user)) + if(welder.isOn()) + to_chat(user, SPAN_NOTICE("You need more welding fuel to complete this task.")) + return TRUE + welded = !welded + update_icon() + user.visible_message(SPAN_WARNING("\The [src] has been [welded?"welded shut":"unwelded"] by \the [user]."), blind_message = "You hear welding.", range = 3) + return TRUE else if(setup & CLOSET_HAS_LOCK) - src.togglelock(user, W) - else - src.attack_hand(user) + togglelock(user, used_item) + return TRUE -/obj/structure/closet/proc/slice_into_parts(obj/W, mob/user) - new /obj/item/stack/material/steel(src.loc, 2) - user.visible_message("\The [src] has been cut apart by [user] with \the [W].", \ - "You have cut \the [src] apart with \the [W].", \ - "You hear welding.") - dismantle(src) + return attack_hand_with_interaction_checks(user) -/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/user) - if(istype(O, /obj/screen)) //fix for HUD elements making their way into the world -Pete - return - if(O.loc == user) - return - if(ismob(O) && src.large) - return - if(user.restrained() || user.stat || user.weakened || user.stunned || user.paralysis) - return - if((!( istype(O, /atom/movable) ) || O.anchored || !Adjacent(user) || !Adjacent(O) || !user.Adjacent(O) || user.contents.Find(src))) - return - if(!isturf(user.loc)) // are you in a container/closet/pod/etc? - return - if(!src.opened) - return - if(istype(O, /obj/structure/closet)) - return - step_towards(O, src.loc) - if(user != O) - user.show_viewers("[user] stuffs [O] into [src]!") - src.add_fingerprint(user) - return +/obj/structure/closet/proc/slice_into_parts(obj/item/used_item, mob/user) + user.visible_message( + SPAN_NOTICE("\The [src] has been cut apart by [user] with \the [used_item]."), + SPAN_NOTICE("You have cut \the [src] apart with \the [used_item]."), + "You hear welding." + ) + physically_destroyed() + +/obj/structure/closet/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + var/atom/movable/AM = dropping + if(!. && istype(AM) && opened && !istype(AM, /obj/structure/closet) && AM.simulated && !AM.anchored && (large || !ismob(AM))) + step_towards(AM, loc) + if(user != AM) + user.visible_message(SPAN_DANGER("\The [user] stuffs \the [AM] into \the [src]!"), SPAN_DANGER("You stuff \the [AM] into \the [src]!")) + return TRUE -/obj/structure/closet/attack_ai(mob/user) - if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Robots can open/close it, but not the AI. - attack_hand(user) +/obj/structure/closet/attack_ai(mob/living/silicon/ai/user) + if(isrobot(user)) // Robots can open/close it, but not the AI. + return attack_hand_with_interaction_checks(user) + return ..() /obj/structure/closet/relaymove(mob/user) - if(user.stat || !isturf(src.loc)) + if(user.stat || !isturf(loc)) return - - if(!src.open()) - to_chat(user, "It won't budge!") + if(!open(user)) + to_chat(user, SPAN_WARNING("\The [src] won't budge!")) /obj/structure/closet/attack_hand(mob/user) - src.add_fingerprint(user) - src.toggle(user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + add_fingerprint(user) + toggle(user) + return TRUE /obj/structure/closet/attack_ghost(mob/ghost) if(ghost.client && ghost.client.inquisitive_ghost) - ghost.examinate(src) - if (!src.opened) + ghost.examine_verb(src) + if (!opened) to_chat(ghost, "It contains: [english_list(contents)].") /obj/structure/closet/verb/verb_toggleopen() @@ -352,24 +380,21 @@ return if(ishuman(usr)) - src.add_fingerprint(usr) - src.toggle(usr) + add_fingerprint(usr) + toggle(usr) else to_chat(usr, "This mob type can't use this verb.") /obj/structure/closet/on_update_icon() + ..() if(opened) icon_state = "open" - overlays.Cut() + else if(broken) + icon_state = "closed_emagged[welded ? "_welded" : ""]" + else if(locked) + icon_state = "closed_locked[welded ? "_welded" : ""]" else - if(broken) - icon_state = "closed_emagged[welded ? "_welded" : ""]" - else - if(locked) - icon_state = "closed_locked[welded ? "_welded" : ""]" - else - icon_state = "closed_unlocked[welded ? "_welded" : ""]" - overlays.Cut() + icon_state = "closed_unlocked[welded ? "_welded" : ""]" /obj/structure/closet/proc/req_breakout() if(opened) @@ -403,7 +428,7 @@ breakout = 0 return FALSE - playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) + playsound(loc, 'sound/effects/grillehit.ogg', 100, 1) shake_animation() add_fingerprint(escapee) @@ -411,24 +436,24 @@ breakout = 0 to_chat(escapee, "You successfully break out!") visible_message("\The [escapee] successfully broke out of \the [src]!") - playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) - break_open() + playsound(loc, 'sound/effects/grillehit.ogg', 100, 1) + QDEL_NULL(lock) + break_open(escapee) shake_animation() -/obj/structure/closet/proc/break_open() - welded = 0 - +/obj/structure/closet/proc/break_open(mob/user) + welded = FALSE if((setup & CLOSET_HAS_LOCK) && locked) make_broken() - //Do this to prevent contents from being opened into nullspace - if(istype(loc, /obj/structure/bigDelivery)) - var/obj/structure/bigDelivery/BD = loc - BD.unwrap() - open() + //#TODO: There's probably a better way to do this? + if(istype(loc, /obj/item/parcel)) + var/obj/item/parcel/P = loc + P.unwrap() + open(user) /obj/structure/closet/onDropInto(var/atom/movable/AM) - return + return opened ? loc : null // If we use the /obj/structure/closet/proc/togglelock variant BYOND asks the user to select an input for id_card, which is then mostly irrelevant. /obj/structure/closet/proc/togglelock_verb() @@ -443,10 +468,10 @@ return FALSE if(!CanPhysicallyInteract(user)) return FALSE - if(src.opened) + if(opened) to_chat(user, "Close \the [src] first.") return FALSE - if(src.broken) + if(broken) to_chat(user, "\The [src] appears to be broken.") return FALSE if(user.loc == src) @@ -473,12 +498,6 @@ /obj/structure/closet/proc/CanToggleLock(var/mob/user, var/obj/item/card/id/id_card) return allowed(user) || (istype(id_card) && check_access_list(id_card.GetAccess())) -/obj/structure/closet/AltClick(var/mob/user) - if(!src.opened) - togglelock(user) - else - return ..() - /obj/structure/closet/CtrlAltClick(var/mob/user) verb_toggleopen() @@ -488,7 +507,7 @@ if(!broken && (setup & CLOSET_HAS_LOCK)) if(prob(50/severity)) locked = !locked - src.update_icon() + update_icon() if(prob(20/severity) && !opened) if(!locked) open() @@ -520,4 +539,23 @@ return TRUE /obj/structure/closet/CanUseTopicPhysical(mob/user) - return CanUseTopic(user, GLOB.physical_no_access_state) \ No newline at end of file + return CanUseTopic(user, global.physical_no_access_topic_state) + +/obj/structure/closet/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/closet_lock_toggle) + +/decl/interaction_handler/closet_lock_toggle + name = "Toggle Lock" + expected_target_type = /obj/structure/closet + examine_desc = "toggle the lock" + +/decl/interaction_handler/closet_lock_toggle/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/obj/structure/closet/C = target + . = !C.opened && (C.setup & CLOSET_HAS_LOCK) + +/decl/interaction_handler/closet_lock_toggle/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/closet/C = target + C.togglelock(user) diff --git a/code/game/objects/structures/crates_lockers/closets/_closet_appearance_definitions.dm b/code/game/objects/structures/crates_lockers/closets/_closet_appearance_definitions.dm index f5f60eb50b84..11241f5a6292 100644 --- a/code/game/objects/structures/crates_lockers/closets/_closet_appearance_definitions.dm +++ b/code/game/objects/structures/crates_lockers/closets/_closet_appearance_definitions.dm @@ -14,7 +14,8 @@ var/decal_icon = 'icons/obj/closets/decals/closet.dmi' var/can_lock = FALSE -/decl/closet_appearance/New() +/decl/closet_appearance/Initialize() + . = ..() // Build our colour and decal lists. if(LAZYLEN(extra_decals)) if(!decals) @@ -208,6 +209,12 @@ "biohazard" = COLOR_OFF_WHITE ) +/decl/closet_appearance/bio/medical + extra_decals = list( + "lower_half_solid" = COLOR_PALE_BLUE_GRAY, + "biohazard" = COLOR_OFF_WHITE + ) + /decl/closet_appearance/secure_closet can_lock = TRUE @@ -349,6 +356,15 @@ "stripe_vertical_mid_partial" = COLOR_BLUE_GRAY ) +/decl/closet_appearance/secure_closet/medical/paramedic + decals = list( + "lower_side_vent" + ) + extra_decals = list( + "medical" = COLOR_BLUE_GRAY, + "stripe_vertical_mid_full" = COLOR_BLUE_GRAY + ) + /decl/closet_appearance/secure_closet/cargo color = COLOR_WARM_YELLOW decals = list( @@ -470,6 +486,13 @@ "hydro" = COLOR_DARK_GREEN_GRAY ) +/decl/closet_appearance/secure_closet/hydroponics/xenoflora + extra_decals = list( + "stripe_vertical_right_partial" = COLOR_PURPLE, + "stripe_vertical_mid_partial" = COLOR_PURPLE, + "hydro" = COLOR_PURPLE + ) + /decl/closet_appearance/secure_closet/chaplain decals = list( "lower_side_vent", @@ -508,6 +531,10 @@ decal_icon = 'icons/obj/closets/decals/crate.dmi' color = COLOR_GRAY40 +/decl/closet_appearance/crate/chest + color = COLOR_WHITE + base_icon = 'icons/obj/closets/bases/chest.dmi' + /decl/closet_appearance/crate/plastic color = COLOR_GRAY80 @@ -639,6 +666,9 @@ decals = null extra_decals = null +/decl/closet_appearance/cabinet/nocolor + color = COLOR_WHITE + /decl/closet_appearance/cabinet/secure can_lock = TRUE @@ -657,6 +687,11 @@ "glass" = COLOR_WHITE ) +/decl/closet_appearance/wall/suit + color = COLOR_LIGHT_CYAN + extra_decals = list( + "stripe_outer" = COLOR_OFF_WHITE + ) /decl/closet_appearance/wall/medical decals = null color = COLOR_OFF_WHITE diff --git a/code/game/objects/structures/crates_lockers/closets/coffin.dm b/code/game/objects/structures/crates_lockers/closets/coffin.dm index 8189ef5eb442..236153f78f39 100644 --- a/code/game/objects/structures/crates_lockers/closets/coffin.dm +++ b/code/game/objects/structures/crates_lockers/closets/coffin.dm @@ -7,30 +7,31 @@ var/screwdriver_time_needed = 7.5 SECONDS -/obj/structure/closet/coffin/examine(mob/user, distance) +/obj/structure/closet/coffin/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1 && !opened) - to_chat(user, "The lid is [locked ? "tightly secured with screws." : "unsecured and can be opened."]") - -/obj/structure/closet/coffin/can_open() + . += "The lid is [locked ? "tightly secured with screws." : "unsecured and can be opened."]" + +/obj/structure/closet/coffin/can_open(mob/user) . = ..() if(locked) return FALSE -/obj/structure/closet/coffin/attackby(obj/item/W, mob/user) - if(!opened && isScrewdriver(W)) +/obj/structure/closet/coffin/attackby(obj/item/used_item, mob/user) + if(!opened && IS_SCREWDRIVER(used_item)) to_chat(user, SPAN_NOTICE("You begin screwing [src]'s lid [locked ? "open" : "shut"].")) playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) - if(do_after(user, screwdriver_time_needed, src)) + if(do_after(user, screwdriver_time_needed, src)) locked = !locked to_chat(user, SPAN_NOTICE("You [locked ? "screw down" : "unscrew"] [src]'s lid.")) else to_chat(user, "You must remain still to [locked ? "unlock" : "lock"] [src].") + return TRUE else - ..() + return ..() /obj/structure/closet/coffin/toggle(mob/user) - if(!(opened ? close() : open())) + if(!(opened ? close(user) : open(user))) to_chat(user, SPAN_NOTICE("It won't budge!")) /obj/structure/closet/coffin/req_breakout() @@ -38,8 +39,7 @@ if(locked) return TRUE - -/obj/structure/closet/coffin/break_open() +/obj/structure/closet/coffin/break_open(mob/user) locked = FALSE ..() diff --git a/code/game/objects/structures/crates_lockers/closets/crittercrate.dm b/code/game/objects/structures/crates_lockers/closets/crittercrate.dm index d649f8657064..f6fa0449a15e 100644 --- a/code/game/objects/structures/crates_lockers/closets/crittercrate.dm +++ b/code/game/objects/structures/crates_lockers/closets/crittercrate.dm @@ -2,3 +2,4 @@ name = "critter crate" desc = "A crate which can sustain life for a while." closet_appearance = /decl/closet_appearance/large_crate/critter + icon = 'icons/obj/closets/bases/large_crate.dmi' diff --git a/code/game/objects/structures/crates_lockers/closets/fitness.dm b/code/game/objects/structures/crates_lockers/closets/fitness.dm index 81e8f6261fe4..0e8b180889f6 100644 --- a/code/game/objects/structures/crates_lockers/closets/fitness.dm +++ b/code/game/objects/structures/crates_lockers/closets/fitness.dm @@ -5,11 +5,11 @@ /obj/structure/closet/athletic_mixed/WillContain() return list( - /obj/item/clothing/under/shorts/grey, - /obj/item/clothing/under/shorts/black, - /obj/item/clothing/under/shorts/red, - /obj/item/clothing/under/shorts/blue, - /obj/item/clothing/under/shorts/green, + /obj/item/clothing/pants/shorts/athletic/grey, + /obj/item/clothing/pants/shorts/athletic/black, + /obj/item/clothing/pants/shorts/athletic/red, + /obj/item/clothing/pants/shorts/athletic/blue, + /obj/item/clothing/pants/shorts/athletic/green, /obj/item/clothing/mask/snorkel = 2, /obj/item/clothing/shoes/swimmingfins = 2, /obj/item/towel = 2) diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm index 71df75180f43..27ed4bce9fd7 100644 --- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -3,6 +3,20 @@ desc = "Old will forever be in fashion." closet_appearance = /decl/closet_appearance/cabinet +/obj/structure/closet/cabinet/wooden + desc = "A stout cabinet." + icon = /decl/closet_appearance/cabinet/nocolor::base_icon + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + open_sound = 'sound/effects/doorcreaky.ogg' + close_sound = 'sound/effects/doorcreaky.ogg' + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + closet_appearance = /decl/closet_appearance/cabinet/nocolor + +/obj/structure/closet/cabinet/wooden/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + /obj/structure/closet/acloset name = "strange closet" desc = "It looks alien!" @@ -12,7 +26,7 @@ name = "administrative supply closet" desc = "It's a storage unit for things that have no right being here." closet_appearance = /decl/closet_appearance/tactical - anchored = 0 + anchored = FALSE /obj/structure/closet/gimmick/russian name = "russian surplus closet" @@ -22,7 +36,7 @@ /obj/structure/closet/gimmick/russian/WillContain() return list( /obj/item/clothing/head/ushanka = 5, - /obj/item/clothing/under/soviet = 5) + /obj/item/clothing/costume/soviet = 5) /obj/structure/closet/gimmick/tacticool name = "tacticool gear closet" @@ -39,14 +53,14 @@ /obj/item/clothing/mask/gas = 2, /obj/item/clothing/shoes/jackboots/swat = 2, /obj/item/clothing/suit/space/void/swat = 2, - /obj/item/clothing/under/syndicate/tacticool = 2) + /obj/item/clothing/shirt/syndicate/tacticool = 2) /obj/structure/closet/thunderdome name = "\improper Thunderdome closet" desc = "Everything you need!" closet_appearance = /decl/closet_appearance/tactical/alt - anchored = 1 + anchored = TRUE /obj/structure/closet/thunderdome/tdred name = "red-team Thunderdome closet" @@ -57,7 +71,7 @@ /obj/item/energy_blade/sword = 3, /obj/item/gun/energy/laser = 3, /obj/item/baton = 3, - /obj/item/storage/box/flashbangs = 3, + /obj/item/box/flashbangs = 3, /obj/item/clothing/head/helmet/thunderdome = 3 ) @@ -71,6 +85,6 @@ /obj/item/energy_blade/sword = 3, /obj/item/gun/energy/laser = 3, /obj/item/baton = 3, - /obj/item/storage/box/flashbangs = 3, + /obj/item/box/flashbangs = 3, /obj/item/clothing/head/helmet/thunderdome = 3 ) diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm index df7dd95f3a49..d59af0e46727 100644 --- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -15,17 +15,19 @@ /obj/structure/closet/gmcloset/WillContain() return list( - /obj/item/clothing/head/that = 2, - /obj/item/radio/headset/headset_service = 2, - /obj/item/clothing/head/hairflower, - /obj/item/clothing/head/hairflower/pink, - /obj/item/clothing/head/hairflower/yellow, - /obj/item/clothing/head/hairflower/blue, - /obj/item/clothing/under/sl_suit = 2, - /obj/item/clothing/under/rank/bartender = 2, - /obj/item/clothing/under/dress/dress_saloon, - /obj/item/clothing/accessory/wcoat/black = 2, - /obj/item/clothing/shoes/color/black = 2 + /obj/item/clothing/head/that = 2, + /obj/item/radio/headset/headset_service = 2, + /obj/item/clothing/head/hairflower = 1, + /obj/item/clothing/head/hairflower/pink = 1, + /obj/item/clothing/head/hairflower/yellow = 1, + /obj/item/clothing/head/hairflower/blue = 1, + /obj/item/clothing/pants/slacks/black = 2, + /obj/item/clothing/shirt/button = 2, + /obj/item/clothing/pants/formal/black = 2, + /obj/item/clothing/shirt/button = 2, + /obj/item/clothing/dress/saloon = 1, + /obj/item/clothing/suit/jacket/waistcoat/black = 2, + /obj/item/clothing/shoes/color/black = 2 ) /* @@ -33,16 +35,20 @@ */ /obj/structure/closet/chefcloset name = "chef's closet" - desc = "It's a storage unit for foodservice garments." + desc = "It's a storage unit for food service garments." closet_appearance = /decl/closet_appearance/wardrobe/black /obj/structure/closet/chefcloset/WillContain() return list( - /obj/item/clothing/under/sundress, - /obj/item/clothing/under/waiter = 2, + /obj/item/clothing/dress/sun, + /obj/item/clothing/pants/slacks/black = 2, + /obj/item/clothing/shirt/button = 2, + /obj/item/clothing/neck/tie/bow/red = 2, + /obj/item/clothing/suit/jacket/vest/blue = 2, /obj/item/radio/headset/headset_service = 2, - /obj/item/storage/box/mousetraps = 2, - /obj/item/clothing/under/rank/chef, + /obj/item/box/mousetraps = 2, + /obj/item/clothing/pants/slacks, + /obj/item/clothing/shirt/button, /obj/item/clothing/head/chefhat ) @@ -56,7 +62,7 @@ /obj/structure/closet/jcloset/WillContain() return list( - /obj/item/clothing/under/rank/janitor, + /obj/item/clothing/jumpsuit/janitor, /obj/item/radio/headset/headset_service, /obj/item/clothing/gloves/thick, /obj/item/clothing/head/soft/purple, @@ -64,10 +70,10 @@ /obj/item/flashlight, /obj/item/caution = 4, /obj/item/lightreplacer, - /obj/item/storage/bag/trash, + /obj/item/bag/trash, /obj/item/clothing/shoes/galoshes, /obj/item/soap, - /obj/item/storage/belt/janitor + /obj/item/belt/janitor ) /* @@ -81,13 +87,14 @@ /obj/structure/closet/lawcloset/WillContain() return list( - /obj/item/clothing/under/lawyer/female, - /obj/item/clothing/under/lawyer/black, - /obj/item/clothing/under/lawyer/red, - /obj/item/clothing/under/lawyer/bluesuit, - /obj/item/clothing/suit/storage/toggle/suit/blue, - /obj/item/clothing/under/lawyer/purpsuit, - /obj/item/clothing/suit/storage/toggle/suit/purple, + /obj/item/clothing/costume/lawyer, + /obj/item/clothing/costume/lawyer_red, + /obj/item/clothing/costume/lawyer_bluesuit, + /obj/item/clothing/pants/slacks/purple, + /obj/item/clothing/shirt/button, + /obj/item/clothing/suit/jacket/vest/black, + /obj/item/clothing/suit/jacket/blue, + /obj/item/clothing/suit/jacket/purple, /obj/item/clothing/shoes/color/brown, /obj/item/clothing/shoes/color/black ) diff --git a/code/game/objects/structures/crates_lockers/closets/l3closet.dm b/code/game/objects/structures/crates_lockers/closets/l3closet.dm index 97b84c05003c..5b6fee17ec9c 100644 --- a/code/game/objects/structures/crates_lockers/closets/l3closet.dm +++ b/code/game/objects/structures/crates_lockers/closets/l3closet.dm @@ -84,3 +84,13 @@ /obj/item/clothing/mask/gas/half, /obj/item/tank/emergency/oxygen/engi ) + +/obj/structure/closet/l3closet/medical + closet_appearance = /decl/closet_appearance/bio/medical + +/obj/structure/closet/l3closet/medical/WillContain() + return list( + /obj/item/clothing/suit/bio_suit/general = 3, + /obj/item/clothing/head/bio_hood/general = 3, + /obj/item/clothing/mask/gas = 3 + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/_secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/_secure_closets.dm index 1dedcb8c8a61..1c2713ef45a2 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/_secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/_secure_closets.dm @@ -1,13 +1,11 @@ /obj/structure/closet/secure_closet name = "secure locker" desc = "It's a card-locked storage unit." - closet_appearance = /decl/closet_appearance/secure_closet setup = CLOSET_HAS_LOCK | CLOSET_CAN_BE_WELDED locked = TRUE - wall_mounted = 0 //never solid (You can always pass over it) - health = 200 + max_health = 200 -/obj/structure/closet/secure_closet/slice_into_parts(obj/item/weldingtool/WT, mob/user) +/obj/structure/closet/secure_closet/slice_into_parts(obj/item/weldingtool/welder, mob/user) to_chat(user, "\The [src] is too strong to be taken apart.") diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm index 92aeebd39094..1ded97466178 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -4,4 +4,4 @@ closet_appearance = /decl/closet_appearance/cabinet/secure /obj/structure/closet/secure_closet/bar/WillContain() - return list(/obj/item/chems/food/drinks/bottle/small/beer = 10) + return list(/obj/item/chems/drinks/bottle/small/beer = 10) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm index bb73a6de500d..77b5a65f63b4 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm @@ -5,13 +5,13 @@ /obj/structure/closet/secure_closet/cargotech/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack = 75, /obj/item/storage/backpack/satchel/grey = 25)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag, 25), - /obj/item/clothing/under/rank/cargotech, + new/datum/atom_creator/weighted(list(/obj/item/backpack = 75, /obj/item/backpack/satchel/grey = 25)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag, 25), + /obj/item/clothing/jumpsuit/cargotech, /obj/item/clothing/shoes/color/black, /obj/item/radio/headset/headset_cargo, /obj/item/clothing/gloves/thick, - /obj/item/storage/belt/general, + /obj/item/belt/general, /obj/item/clothing/head/soft ) @@ -22,9 +22,9 @@ /obj/structure/closet/secure_closet/quartermaster/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack = 75, /obj/item/storage/backpack/satchel/grey = 25)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag, 25), - /obj/item/clothing/under/rank/cargotech, + new/datum/atom_creator/weighted(list(/obj/item/backpack = 75, /obj/item/backpack/satchel/grey = 25)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag, 25), + /obj/item/clothing/jumpsuit/cargotech, /obj/item/clothing/shoes/color/brown, /obj/item/radio/headset/headset_cargo, /obj/item/clothing/gloves/thick, diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 4f4f2c53fc6a..afd5a3a3b99e 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -5,22 +5,29 @@ /obj/structure/closet/secure_closet/engineering_chief/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/clothing/accessory/storage/brown_vest = 70, /obj/item/clothing/accessory/storage/webbing = 30)), - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/industrial, /obj/item/storage/backpack/satchel/eng)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/eng, 50), + new/datum/atom_creator/weighted(list( + /obj/item/clothing/webbing/vest/brown = 70, + /obj/item/clothing/webbing = 30 + )), + new/datum/atom_creator/weighted(list( + /obj/item/backpack/industrial, + /obj/item/backpack/satchel/eng + )), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/eng, 50), /obj/item/blueprints, - /obj/item/clothing/under/rank/chief_engineer, + /obj/item/clothing/jumpsuit/chief_engineer, /obj/item/clothing/head/welding, /obj/item/clothing/gloves/insulated, /obj/item/clothing/shoes/color/brown, /obj/item/radio/headset/heads/ce, - /obj/item/storage/toolbox/mechanical, - /obj/item/clothing/suit/storage/hazardvest, + /obj/item/toolbox/mechanical, + /obj/item/clothing/suit/hazardvest, /obj/item/clothing/mask/gas, /obj/item/multitool, /obj/item/flash, - /obj/item/taperoll/engineering, - /obj/item/crowbar/brace_jack + /obj/item/stack/tape_roll/barricade_tape/engineering, + /obj/item/crowbar/brace_jack, + /obj/item/belt/utility/full ) /obj/structure/closet/secure_closet/engineering_electrical @@ -31,7 +38,8 @@ /obj/structure/closet/secure_closet/engineering_electrical/WillContain() return list( /obj/item/clothing/gloves/insulated = 3, - /obj/item/storage/toolbox/electrical = 3, + /obj/item/toolbox/electrical = 3, + /obj/item/toolbox/repairs = 3, /obj/item/stock_parts/circuitboard/apc = 3, /obj/item/multitool = 3 ) @@ -45,9 +53,9 @@ return list( /obj/item/clothing/head/welding = 3, /obj/item/weldingtool/largetank = 3, - /obj/item/weldpack = 3, + /obj/item/chems/weldpack = 3, /obj/item/clothing/glasses/welding = 3, - /obj/item/welder_tank = 6 + /obj/item/chems/welder_tank = 6 ) /obj/structure/closet/secure_closet/engineering_personal @@ -57,15 +65,26 @@ /obj/structure/closet/secure_closet/engineering_personal/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/clothing/accessory/storage/brown_vest = 70, /obj/item/clothing/accessory/storage/webbing = 30)), - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/industrial, /obj/item/storage/backpack/satchel/eng)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/eng, 50), - /obj/item/storage/toolbox/mechanical, + new/datum/atom_creator/weighted( + list( + /obj/item/clothing/webbing/vest/brown = 70, + /obj/item/clothing/webbing = 30 + ) + ), + new/datum/atom_creator/weighted( + list( + /obj/item/backpack/industrial, + /obj/item/backpack/satchel/eng + ) + ), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/eng, 50), + /obj/item/toolbox/mechanical, /obj/item/radio/headset/headset_eng, - /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/suit/hazardvest, /obj/item/clothing/mask/gas, /obj/item/clothing/glasses/meson, - /obj/item/taperoll/engineering + /obj/item/stack/tape_roll/barricade_tape/engineering, + /obj/item/belt/utility/full ) /obj/structure/closet/secure_closet/atmos_personal @@ -75,14 +94,21 @@ /obj/structure/closet/secure_closet/atmos_personal/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/clothing/accessory/storage/brown_vest = 70, /obj/item/clothing/accessory/storage/webbing = 30)), - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/industrial, /obj/item/storage/backpack/satchel/eng)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/eng, 50), + new/datum/atom_creator/weighted(list( + /obj/item/clothing/webbing/vest/brown = 70, + /obj/item/clothing/webbing = 30 + )), + new/datum/atom_creator/weighted(list( + /obj/item/backpack/industrial, + /obj/item/backpack/satchel/eng + )), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/eng, 50), /obj/item/clothing/suit/fire, /obj/item/flashlight, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/radio/headset/headset_eng, - /obj/item/clothing/suit/storage/hazardvest, + /obj/item/clothing/suit/hazardvest, /obj/item/clothing/mask/gas, - /obj/item/taperoll/atmos + /obj/item/stack/tape_roll/barricade_tape/atmos, + /obj/item/belt/utility/atmostech ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index f9e27bb9564e..5dc98f40fb3a 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -4,9 +4,10 @@ /obj/structure/closet/secure_closet/freezer/kitchen/WillContain() return list( - /obj/item/chems/food/condiment/salt = 1, - /obj/item/chems/food/condiment/flour = 7, - /obj/item/chems/food/condiment/sugar = 2 + /obj/item/chems/condiment/large/salt = 1, + /obj/item/chems/condiment/flour = 7, + /obj/item/chems/condiment/yeast = 1, + /obj/item/chems/condiment/sugar = 2 ) /obj/structure/closet/secure_closet/freezer/kitchen/mining @@ -19,8 +20,8 @@ /obj/structure/closet/secure_closet/freezer/meat/WillContain() return list( - /obj/item/chems/food/snacks/meat/beef = 8, - /obj/item/chems/food/snacks/fish = 4 + /obj/item/food/butchery/meat/beef = 8, + /obj/item/food/butchery/meat/fish = 4 ) /obj/structure/closet/secure_closet/freezer/fridge @@ -30,9 +31,11 @@ /obj/structure/closet/secure_closet/freezer/fridge/WillContain() return list( - /obj/item/chems/food/drinks/milk = 6, - /obj/item/chems/food/drinks/soymilk = 4, - /obj/item/storage/fancy/egg_box = 4 + /obj/item/chems/drinks/milk = 6, + /obj/item/chems/drinks/soymilk = 4, + /obj/item/food/dairy/butter/stick = 2, + /obj/item/food/dairy/butter/stick/margarine = 2, + /obj/item/box/fancy/egg_box = 4 ) /obj/structure/closet/secure_closet/freezer/money @@ -41,15 +44,15 @@ closet_appearance = null req_access = list(access_heads_vault) -/obj/structure/closet/secure_closet/freezer/money/Initialize() - . = ..() +/obj/structure/closet/secure_closet/freezer/money/WillContain() + . = list() //let's make hold a substantial amount. var/created_size = 0 for(var/i = 1 to 200) //sanity loop limit var/obj/item/cash_type = pick(3; /obj/item/cash/c1000, 4; /obj/item/cash/c500, 5; /obj/item/cash/c200) - var/bundle_size = initial(cash_type.w_class) / 2 + var/bundle_size = initial(cash_type.w_class) if(created_size + bundle_size <= storage_capacity) created_size += bundle_size - new cash_type(src) + . += cash_type else break diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm index 0739e6783c05..5f191395d880 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm @@ -8,18 +8,23 @@ . = ..() update_icon() +/obj/structure/closet/secure_closet/guncabinet/LateInitialize(mapload, ...) + . = ..() + update_icon() + /obj/structure/closet/secure_closet/guncabinet/toggle() ..() update_icon() -/obj/structure/closet/secure_closet/guncabinet/open() //There are plenty of things that can open it that don't use toggle - ..() +/obj/structure/closet/secure_closet/guncabinet/open(mob/user) //There are plenty of things that can open it that don't use toggle + . = ..() update_icon() +// TODO rewrite to use parent call and proper closet icon stuff. /obj/structure/closet/secure_closet/guncabinet/on_update_icon() - overlays.Cut() + cut_overlays() if(opened) - overlays += icon(icon,"door_open") + add_overlay("door_open") else var/lazors = 0 var/shottas = 0 @@ -40,14 +45,26 @@ gun.pixel_x = i*4 overlays += gun - overlays += icon(src.icon, "door") + add_overlay("door") if(welded) - overlays += icon(src.icon,"welded") + add_overlay("welded") if(!broken) if(locked) - overlays += icon(src.icon,"locked") + add_overlay("locked") else - overlays += icon(src.icon,"open") + add_overlay("open") + +// Subtypes +/obj/structure/closet/secure_closet/guncabinet/sidearm + name = "emergency weapon cabinet" + req_access = list( + access_armory, + access_captain + ) +/obj/structure/closet/secure_closet/guncabinet/sidearm/WillContain() + return list( + /obj/item/gun/energy/gun = 4 + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm b/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm index 77c0aa6addb1..78be7fdb88bc 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/hydroponics.dm @@ -6,14 +6,26 @@ /obj/structure/closet/secure_closet/hydroponics/WillContain() return list( new /datum/atom_creator/weighted(list(/obj/item/clothing/suit/apron, /obj/item/clothing/suit/apron/overalls)), - /obj/item/storage/plants, - /obj/item/clothing/under/rank/hydroponics, + /obj/item/plant_satchel, + /obj/item/clothing/jumpsuit/hydroponics, /obj/item/scanner/plant, /obj/item/radio/headset/headset_service, /obj/item/clothing/mask/bandana/botany, /obj/item/clothing/head/bandana/green, - /obj/item/minihoe, - /obj/item/hatchet, + /obj/item/tool/hoe/mini, + /obj/item/tool/axe/hatchet, /obj/item/wirecutters/clippers, /obj/item/chems/spray/plantbgone, ) + + +/obj/structure/closet/secure_closet/hydroponics/sci + name = "xenoflorist's locker" + req_access = list(access_xenobiology) + closet_appearance = /decl/closet_appearance/secure_closet/hydroponics/xenoflora + +/obj/structure/closet/secure_closet/hydroponics/sci/WillContain() + . = ..() + . += /obj/item/clothing/head/bio_hood/scientist + . += /obj/item/clothing/suit/bio_suit/scientist + . += /obj/item/clothing/mask/ diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm index aa13e31f2e65..e869ad6ad8c5 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm @@ -1,14 +1,14 @@ -#define RANDOM_SCRUBS new/datum/atom_creator/weighted(list( \ - list(/obj/item/clothing/under/rank/medical/scrubs, /obj/item/clothing/head/surgery), \ - list(/obj/item/clothing/under/rank/medical/scrubs/blue, /obj/item/clothing/head/surgery/blue), \ - list(/obj/item/clothing/under/rank/medical/scrubs/green, /obj/item/clothing/head/surgery/green), \ - list(/obj/item/clothing/under/rank/medical/scrubs/purple, /obj/item/clothing/head/surgery/purple), \ - list(/obj/item/clothing/under/rank/medical/scrubs/black, /obj/item/clothing/head/surgery/black), \ - list(/obj/item/clothing/under/rank/medical/scrubs/lilac, /obj/item/clothing/head/surgery/lilac), \ - list(/obj/item/clothing/under/rank/medical/scrubs/teal, /obj/item/clothing/head/surgery/teal), \ - list(/obj/item/clothing/under/rank/medical/scrubs/heliodor, /obj/item/clothing/head/surgery/heliodor), \ - list(/obj/item/clothing/under/rank/medical/scrubs/navyblue, /obj/item/clothing/head/surgery/navyblue)\ - ) \ +#define RANDOM_SCRUBS new/datum/atom_creator/weighted(list( \ + list(/obj/item/clothing/shirt/scrubs, /obj/item/clothing/pants/scrubs, /obj/item/clothing/head/surgery), \ + list(/obj/item/clothing/shirt/scrubs/blue, /obj/item/clothing/pants/scrubs/blue, /obj/item/clothing/head/surgery/blue), \ + list(/obj/item/clothing/shirt/scrubs/green, /obj/item/clothing/pants/scrubs/green, /obj/item/clothing/head/surgery/green), \ + list(/obj/item/clothing/shirt/scrubs/purple, /obj/item/clothing/pants/scrubs/purple, /obj/item/clothing/head/surgery/purple), \ + list(/obj/item/clothing/shirt/scrubs/black, /obj/item/clothing/pants/scrubs/black, /obj/item/clothing/head/surgery/black), \ + list(/obj/item/clothing/shirt/scrubs/lilac, /obj/item/clothing/pants/scrubs/lilac, /obj/item/clothing/head/surgery/lilac), \ + list(/obj/item/clothing/shirt/scrubs/teal, /obj/item/clothing/pants/scrubs/teal, /obj/item/clothing/head/surgery/teal), \ + list(/obj/item/clothing/shirt/scrubs/heliodor, /obj/item/clothing/pants/scrubs/heliodor, /obj/item/clothing/head/surgery/heliodor), \ + list(/obj/item/clothing/shirt/scrubs/navyblue, /obj/item/clothing/pants/scrubs/navyblue, /obj/item/clothing/head/surgery/navyblue) \ + ) \ ) /obj/structure/closet/secure_closet/medical1 @@ -19,26 +19,15 @@ /obj/structure/closet/secure_closet/medical1/WillContain() return list( - /obj/item/storage/box/autoinjectors, - /obj/item/storage/box/syringes, + /obj/item/box/autoinjectors, + /obj/item/box/syringes, /obj/item/chems/dropper = 2, /obj/item/chems/glass/beaker = 2, /obj/item/chems/glass/bottle/stabilizer = 2, /obj/item/chems/glass/bottle/antitoxin = 2, /obj/random/firstaid, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves - ) - -/obj/structure/closet/secure_closet/medical2 - name = "anesthetics closet" - desc = "Used to knock people out." - req_access = list(access_surgery) - -/obj/structure/closet/secure_closet/medical2/WillContain() - return list( - /obj/item/tank/anesthetic = 3, - /obj/item/clothing/mask/breath/medical = 3 + /obj/item/box/masks, + /obj/item/box/gloves ) /obj/structure/closet/secure_closet/medical3 @@ -48,19 +37,20 @@ /obj/structure/closet/secure_closet/medical3/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/medic, /obj/item/storage/backpack/satchel/med)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/med, 50), - /obj/item/clothing/under/rank/nursesuit, + new/datum/atom_creator/weighted(list(/obj/item/backpack/medic, /obj/item/backpack/satchel/med)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/med, 50), /obj/item/clothing/head/nursehat, - /obj/item/clothing/under/rank/medical, - /obj/item/clothing/under/rank/nurse, - /obj/item/clothing/under/rank/orderly, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/clothing/suit/storage/toggle/fr_jacket, + /obj/item/clothing/jumpsuit/medical, + /obj/item/clothing/dress/nurse = 2, + /obj/item/clothing/pants/slacks/white/orderly, + /obj/item/clothing/shirt/button/orderly, + /obj/item/clothing/neck/tie/long/red, + /obj/item/clothing/suit/toggle/labcoat, + /obj/item/clothing/suit/jacket/first_responder, /obj/item/clothing/shoes/color/white, /obj/item/radio/headset/headset_med, - /obj/item/taperoll/medical, - /obj/item/storage/belt/medical/emt, + /obj/item/stack/tape_roll/barricade_tape/medical, + /obj/item/belt/medical/emt, RANDOM_SCRUBS, RANDOM_SCRUBS ) @@ -73,42 +63,43 @@ /obj/structure/closet/secure_closet/paramedic/WillContain() return list( - /obj/item/storage/box/autoinjectors, - /obj/item/storage/box/syringes, - /obj/item/chems/glass/bottle/stabilizer, - /obj/item/chems/glass/bottle/antitoxin, - /obj/item/storage/belt/medical/emt, - /obj/item/clothing/mask/gas, - /obj/item/clothing/suit/storage/toggle/fr_jacket, - /obj/item/clothing/suit/storage/toggle/labcoat, - /obj/item/radio/headset/headset_med, - /obj/item/flashlight, - /obj/item/tank/emergency/oxygen/engi, - /obj/item/clothing/glasses/hud/health, - /obj/item/scanner/health, - /obj/item/radio/off, - /obj/random/medical, - /obj/item/crowbar, - /obj/item/extinguisher/mini, - /obj/item/storage/box/freezer, - /obj/item/clothing/accessory/storage/white_vest, + /obj/item/box/autoinjectors, + /obj/item/box/syringes, + /obj/item/chems/glass/bottle/stabilizer, + /obj/item/chems/glass/bottle/antitoxin, + /obj/item/belt/medical/emt, + /obj/item/clothing/mask/gas, + /obj/item/clothing/suit/jacket/first_responder, + /obj/item/clothing/suit/toggle/labcoat, + /obj/item/radio/headset/headset_med, + /obj/item/flashlight, + /obj/item/tank/emergency/oxygen/engi, + /obj/item/clothing/glasses/hud/health, + /obj/item/scanner/health, + /obj/item/scanner/breath, + /obj/item/radio/off, + /obj/random/medical, + /obj/item/crowbar, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/box/freezer, + /obj/item/clothing/webbing/vest ) -/obj/structure/closet/secure_closet/CMO +/obj/structure/closet/secure_closet/cmo name = "chief medical officer's locker" req_access = list(access_cmo) closet_appearance = /decl/closet_appearance/secure_closet/cmo -/obj/structure/closet/secure_closet/CMO/WillContain() +/obj/structure/closet/secure_closet/cmo/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/medic, /obj/item/storage/backpack/satchel/med)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/med, 50), + new/datum/atom_creator/weighted(list(/obj/item/backpack/medic, /obj/item/backpack/satchel/med)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/med, 50), /obj/item/clothing/suit/bio_suit/cmo, /obj/item/clothing/head/bio_hood/cmo, /obj/item/clothing/shoes/color/white, - /obj/item/clothing/under/rank/chief_medical_officer, - /obj/item/clothing/suit/storage/toggle/labcoat/cmo, - /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, + /obj/item/clothing/jumpsuit/chief_medical_officer, + /obj/item/clothing/suit/toggle/labcoat/cmo, + /obj/item/clothing/suit/toggle/labcoat/cmoalt, /obj/item/clothing/gloves/latex, /obj/item/clothing/shoes/color/brown, /obj/item/radio/headset/heads/cmo, @@ -125,7 +116,7 @@ /obj/structure/closet/secure_closet/chemical/WillContain() return list( - /obj/item/storage/box/pillbottles = 2, + /obj/item/box/pillbottles = 2, /obj/random/medical = 12 ) @@ -133,12 +124,28 @@ name = "first aid closet" desc = "It's a secure wall-mounted storage unit for first aid supplies." closet_appearance = /decl/closet_appearance/wall/medical - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE wall_mounted = 1 storage_types = CLOSET_STORAGE_ITEMS req_access = list(access_medical_equip) +/obj/structure/closet/secure_closet/medical_wall/Initialize() + . = ..() + tool_interaction_flags &= ~TOOL_INTERACTION_ANCHOR + +/obj/structure/closet/secure_closet/medical_wall/pills + name = "pill cabinet" + +/obj/structure/closet/secure_closet/medical_wall/pills/WillContain() + return list( + /obj/item/pill_bottle/antibiotics = 1, + /obj/item/pill_bottle/painkillers = 1, + /obj/item/pill_bottle/antitoxins = 1, + /obj/item/pill_bottle/burn_meds = 1, + /obj/random/medical/pillbottle = 1 + ) + /obj/structure/closet/secure_closet/counselor name = "counselor's locker" closet_appearance = /decl/closet_appearance/secure_closet/medical @@ -146,21 +153,22 @@ /obj/structure/closet/secure_closet/counselor/WillContain() return list( - /obj/item/clothing/under/rank/psych, - /obj/item/clothing/under/rank/psych/turtleneck, - /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/jumpsuit/psych, + /obj/item/clothing/shirt/sweater/turquoise, + /obj/item/clothing/pants/slacks/navy, + /obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/shoes/color/white, /obj/item/chems/glass/bottle/sedatives, /obj/item/chems/syringe, - /obj/item/storage/pill_bottle/antidepressants, + /obj/item/pill_bottle/antidepressants, /obj/item/chems/pill/stimulants, /obj/item/clipboard, /obj/item/folder/cyan, /obj/item/taperecorder, - /obj/item/tape/random = 3, + /obj/item/magnetic_tape/random = 3, /obj/item/camera, - /obj/item/toy/therapy_blue, - /obj/item/storage/belt/general + /obj/random/plush/therapy, + /obj/item/belt/general ) /obj/structure/closet/secure_closet/virology @@ -171,21 +179,22 @@ /obj/structure/closet/secure_closet/virology/WillContain() return list( - /obj/item/storage/box/autoinjectors, - /obj/item/storage/box/syringes, + /obj/item/box/autoinjectors, + /obj/item/box/syringes, /obj/item/chems/dropper = 2, /obj/item/chems/glass/beaker = 2, /obj/item/chems/glass/bottle/stabilizer, - /obj/item/storage/pill_bottle/antibiotics, + /obj/item/pill_bottle/antibiotics, /obj/item/chems/syringe/antibiotic, /obj/item/chems/glass/bottle/antitoxin, - /obj/item/storage/box/masks, - /obj/item/storage/box/gloves, - /obj/item/clothing/under/rank/virologist, + /obj/item/box/masks, + /obj/item/box/gloves, + /obj/item/clothing/jumpsuit/virologist, /obj/item/clothing/shoes/color/white, - /obj/item/clothing/suit/storage/toggle/labcoat/virologist, + /obj/item/clothing/suit/toggle/labcoat/virologist, /obj/item/clothing/mask/surgical, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/clothing/glasses/hud/health ) @@ -200,8 +209,9 @@ /obj/item/clothing/suit/straight_jacket, /obj/item/chems/glass/bottle/sedatives, /obj/item/chems/syringe, - /obj/item/storage/pill_bottle/antidepressants, - /obj/item/storage/pill_bottle/stimulants, - /obj/item/clothing/under/rank/psych/turtleneck, - /obj/item/clothing/under/rank/psych + /obj/item/pill_bottle/antidepressants, + /obj/item/pill_bottle/stimulants, + /obj/item/clothing/shirt/sweater/turquoise, + /obj/item/clothing/pants/slacks/navy, + /obj/item/clothing/jumpsuit/psych ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm b/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm index 1894868b48cc..a1df9e8fe320 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/nuke.dm @@ -2,8 +2,8 @@ name = "nuclear cylinder closet" desc = "It's a secure wall-mounted storage unit for storing the nuclear cylinders." icon = 'icons/obj/machines/self_destruct.dmi' - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE wall_mounted = 1 req_access = list(access_heads_vault) storage_types = CLOSET_STORAGE_ITEMS diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index d5c27d89cb68..209b168044d9 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -1,12 +1,14 @@ /obj/structure/closet/secure_closet/personal name = "personal closet" - desc = "It's a secure locker for personnel. The first card swiped gains control." + desc = "It's a secure locker for personnel." req_access = list(access_all_personal_lockers) + locked = FALSE + var/registered_name = null /obj/structure/closet/secure_closet/personal/WillContain() return list( - new /datum/atom_creator/weighted(list(/obj/item/storage/backpack, /obj/item/storage/backpack/satchel/grey)), + new /datum/atom_creator/weighted(list(/obj/item/backpack, /obj/item/backpack/satchel/grey)), /obj/item/radio/headset ) @@ -22,43 +24,26 @@ closet_appearance = /decl/closet_appearance/cabinet/secure /obj/structure/closet/secure_closet/personal/cabinet/WillContain() - return list(/obj/item/storage/backpack/satchel/grey/withwallet, /obj/item/radio/headset) + return list(/obj/item/backpack/satchel/grey/withwallet, /obj/item/radio/headset) /obj/structure/closet/secure_closet/personal/CanToggleLock(var/mob/user, var/obj/item/card/id/id_card) return ..() || (istype(id_card) && id_card.registered_name && (!registered_name || (registered_name == id_card.registered_name))) /obj/structure/closet/secure_closet/personal/togglelock(var/mob/user, var/obj/item/card/id/id_card) - if (..() && !registered_name) - id_card = istype(id_card) ? id_card : user.GetIdCard() - if (id_card) - set_owner(id_card.registered_name) + if (..()) + if(locked) + id_card = istype(id_card) ? id_card : user.GetIdCard() + if (id_card) + set_owner(id_card.registered_name) + else + set_owner(null) /obj/structure/closet/secure_closet/personal/proc/set_owner(var/registered_name) if (registered_name) src.registered_name = registered_name src.SetName(name + " ([registered_name])") - src.desc = "Owned by [registered_name]." + src.desc = "Currently used by [registered_name]." else src.registered_name = null src.SetName(initial(name)) src.desc = initial(desc) - -/obj/structure/closet/secure_closet/personal/verb/reset() - set src in oview(1) // One square distance - set category = "Object" - set name = "Reset Lock" - if(!CanPhysicallyInteract(usr)) // Don't use it if you're not able to! Checks for stuns, ghost and restrain - return - if(ishuman(usr)) - src.add_fingerprint(usr) - if (src.locked || !src.registered_name) - to_chat(usr, "You need to unlock it first.") - else if (src.broken) - to_chat(usr, "It appears to be broken.") - else - if (src.opened) - if(!src.close()) - return - locked = TRUE - queue_icon_update() - set_owner(null) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index e32dfff28f05..806048ba7a13 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -5,8 +5,8 @@ /obj/structure/closet/secure_closet/scientist/WillContain() return list( - /obj/item/clothing/under/color/white, - /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/jumpsuit/white, + /obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/shoes/color/white, /obj/item/radio/headset/headset_sci, /obj/item/clothing/mask/gas, @@ -20,26 +20,26 @@ /obj/structure/closet/secure_closet/xenobio/WillContain() return list( - /obj/item/clothing/under/color/white, - /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/jumpsuit/white, + /obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/shoes/color/white, /obj/item/radio/headset/headset_sci, /obj/item/clothing/mask/gas, /obj/item/clothing/gloves/latex, /obj/item/clipboard, - /obj/item/storage/belt/general + /obj/item/belt/general ) -/obj/structure/closet/secure_closet/RD +/obj/structure/closet/secure_closet/research_director name = "chief science officer's locker" req_access = list(access_rd) closet_appearance = /decl/closet_appearance/secure_closet/rd -/obj/structure/closet/secure_closet/RD/WillContain() +/obj/structure/closet/secure_closet/research_director/WillContain() return list( /obj/item/clothing/suit/bio_suit/scientist = 2, /obj/item/clothing/head/bio_hood/scientist = 2, - /obj/item/clothing/suit/storage/toggle/labcoat, + /obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/shoes/color/white, /obj/item/clothing/gloves/latex, /obj/item/radio/headset/heads/rd, @@ -55,9 +55,33 @@ /obj/structure/closet/secure_closet/animal/WillContain() return list( /obj/item/assembly/signaler, - /obj/item/radio/electropack = 3, /obj/item/gun/launcher/syringe/rapid, - /obj/item/storage/box/syringegun, - /obj/item/storage/box/syringes, + /obj/item/box/syringegun, + /obj/item/box/syringes, /obj/item/chems/glass/bottle/sedatives ) + +/obj/structure/closet/secure_closet/pilot + name = "pilot locker" + req_access = list(access_xenobiology) + /// The jumpsuit type spawned for this locker. Exists to be overridden by the corporate modpack, which adds pilot jumpsuits. + var/jumpsuit_type = /obj/item/clothing/jumpsuit/white + +/obj/structure/closet/secure_closet/pilot/WillContain() + return list( + /obj/item/backpack/parachute, + /obj/item/knife/utility, + jumpsuit_type, + /obj/item/clothing/suit/jacket/bomber, + /obj/item/clothing/mask/gas/half, + /obj/item/clothing/shoes/color/black, + /obj/item/clothing/gloves/black, + /obj/item/radio/headset/headset_sci, + /obj/item/flashlight, + /obj/item/food/junk/liquidfood, + /obj/item/chems/drinks/cans/waterbottle, + /obj/item/box/flares, + /obj/item/cell/device, + /obj/item/radio, + /obj/item/backpack/satchel + ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 9eac38c476a5..860f376f6b1f 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -5,21 +5,21 @@ /obj/structure/closet/secure_closet/captains/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/captain, /obj/item/storage/backpack/satchel/cap)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/captain, 50), - /obj/item/clothing/suit/captunic, - /obj/item/clothing/suit/captunic/capjacket, + new/datum/atom_creator/weighted(list(/obj/item/backpack/captain, /obj/item/backpack/satchel/cap)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/captain, 50), + /obj/item/clothing/shirt/tunic/captain, + /obj/item/clothing/suit/jacket/captain, /obj/item/clothing/head/caphat/cap, - /obj/item/clothing/under/rank/captain, + /obj/item/clothing/jumpsuit/captain, /obj/item/clothing/head/helmet, /obj/item/clothing/shoes/color/brown, /obj/item/radio/headset/heads/captain, /obj/item/clothing/gloves/captain, /obj/item/gun/energy/gun, /obj/item/telebaton, - /obj/item/clothing/under/dress/dress_cap, + /obj/item/clothing/dress/cap, /obj/item/clothing/head/caphat/formal, - /obj/item/clothing/under/captainformal, + /obj/item/clothing/costume/captainformal, ) /obj/structure/closet/secure_closet/hop @@ -32,7 +32,7 @@ /obj/item/clothing/glasses/sunglasses, /obj/item/clothing/head/helmet, /obj/item/radio/headset/heads/hop, - /obj/item/storage/box/ids = 2, + /obj/item/box/ids = 2, /obj/item/flash ) @@ -43,18 +43,17 @@ /obj/structure/closet/secure_closet/hop2/WillContain() return list( - /obj/item/clothing/under/rank/head_of_personnel, - /obj/item/clothing/under/dress/dress_hop, - /obj/item/clothing/under/dress/dress_hr, - /obj/item/clothing/under/lawyer/female, - /obj/item/clothing/under/lawyer/black, - /obj/item/clothing/under/lawyer/red, - /obj/item/clothing/under/lawyer/oldman, + /obj/item/clothing/jumpsuit/head_of_personnel, + /obj/item/clothing/dress/hop, + /obj/item/clothing/dress/hr, + /obj/item/clothing/costume/lawyer, + /obj/item/clothing/costume/lawyer_red, + /obj/item/clothing/costume/oldman, /obj/item/clothing/shoes/color/brown, /obj/item/clothing/shoes/color/black, /obj/item/clothing/shoes/craftable, /obj/item/clothing/shoes/color/white, - /obj/item/clothing/under/rank/head_of_personnel_whimsy, + /obj/item/clothing/costume/head_of_personnel_whimsy, /obj/item/clothing/head/caphat/hop ) @@ -65,22 +64,22 @@ /obj/structure/closet/secure_closet/hos/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/security, /obj/item/storage/backpack/satchel/sec)), + new/datum/atom_creator/weighted(list(/obj/item/backpack/security, /obj/item/backpack/satchel/sec)), /obj/item/clothing/head/HoS, /obj/item/clothing/suit/armor/vest/heavy/hos, - /obj/item/clothing/under/rank/head_of_security/jensen, + /obj/item/clothing/jumpsuit/head_of_security/jensen, /obj/item/clothing/suit/armor/hos/jensen, /obj/item/clothing/suit/armor/hos, /obj/item/radio/headset/heads/hos, /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/taperoll/police, + /obj/item/stack/tape_roll/barricade_tape/police, /obj/item/shield/riot, - /obj/item/storage/box/flashbangs, - /obj/item/storage/belt/holster/security, + /obj/item/box/flashbangs, + /obj/item/belt/holster/security, /obj/item/flash, /obj/item/baton/loaded, /obj/item/gun/energy/gun, - /obj/item/clothing/accessory/storage/holster/waist, + /obj/item/clothing/webbing/holster/waist, /obj/item/telebaton, /obj/item/holowarrant ) @@ -92,22 +91,22 @@ /obj/structure/closet/secure_closet/warden/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/security, /obj/item/storage/backpack/satchel/sec)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/sec, 50), + new/datum/atom_creator/weighted(list(/obj/item/backpack/security, /obj/item/backpack/satchel/sec)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/sec, 50), /obj/item/clothing/suit/armor/vest/heavy/warden, - /obj/item/clothing/under/rank/warden, + /obj/item/clothing/jumpsuit/warden, /obj/item/clothing/suit/armor/warden, /obj/item/clothing/head/warden, /obj/item/radio/headset/headset_sec, /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/taperoll/police, - /obj/item/storage/box/flashbangs, - /obj/item/storage/box/teargas, - /obj/item/storage/belt/holster/security, + /obj/item/stack/tape_roll/barricade_tape/police, + /obj/item/box/flashbangs, + /obj/item/box/teargas, + /obj/item/belt/holster/security, /obj/item/chems/spray/pepper, /obj/item/baton/loaded, /obj/item/gun/energy/gun, - /obj/item/storage/box/holobadge, + /obj/item/box/holobadge, /obj/item/holowarrant ) @@ -118,44 +117,23 @@ /obj/structure/closet/secure_closet/security/WillContain() return list( - new/datum/atom_creator/weighted(list(/obj/item/storage/backpack/security, /obj/item/storage/backpack/satchel/sec)), - new/datum/atom_creator/simple(/obj/item/storage/backpack/dufflebag/sec, 50), + new/datum/atom_creator/weighted(list(/obj/item/backpack/security, /obj/item/backpack/satchel/sec)), + new/datum/atom_creator/simple(/obj/item/backpack/dufflebag/sec, 50), /obj/item/clothing/head/helmet, /obj/item/radio/headset/headset_sec, - /obj/item/storage/belt/holster/security, + /obj/item/belt/holster/security, /obj/item/flash, /obj/item/chems/spray/pepper, /obj/item/grenade/chem_grenade/teargas, /obj/item/baton/loaded, /obj/item/clothing/glasses/sunglasses/sechud, - /obj/item/taperoll/police, + /obj/item/stack/tape_roll/barricade_tape/police, /obj/item/hailer, - /obj/item/clothing/accessory/storage/black_vest, + /obj/item/clothing/webbing/vest/black, /obj/item/gun/energy/taser, /obj/item/holowarrant, ) -/obj/structure/closet/secure_closet/security/cargo/WillContain() - return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( - /obj/item/clothing/accessory/armband/cargo, - /obj/item/encryptionkey/headset_cargo - )) - -/obj/structure/closet/secure_closet/security/engine/WillContain() - return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( - /obj/item/clothing/accessory/armband/engine, - /obj/item/encryptionkey/headset_eng - )) - -/obj/structure/closet/secure_closet/security/science/WillContain() - return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list(/obj/item/encryptionkey/headset_sci)) - -/obj/structure/closet/secure_closet/security/med/WillContain() - return MERGE_ASSOCS_WITH_NUM_VALUES(..(), list( - /obj/item/clothing/accessory/armband/medgreen, - /obj/item/encryptionkey/headset_med - )) - /obj/structure/closet/secure_closet/detective name = "detective's cabinet" req_access = list(access_forensics_lockers) @@ -163,25 +141,29 @@ /obj/structure/closet/secure_closet/detective/WillContain() return list( - /obj/item/clothing/under/det, - /obj/item/clothing/under/det/grey, - /obj/item/clothing/under/det/black, - /obj/item/clothing/suit/storage/det_trench, - /obj/item/clothing/suit/storage/det_trench/grey, - /obj/item/clothing/suit/storage/forensics/blue, - /obj/item/clothing/suit/storage/forensics/red, + /obj/item/clothing/shirt/button/tan, + /obj/item/clothing/shirt/button, + /obj/item/clothing/pants/slacks, + /obj/item/clothing/pants/slacks/black, + /obj/item/clothing/neck/tie/blue_clip, + /obj/item/clothing/neck/tie/long/red, + /obj/item/clothing/suit/jacket/vest/black, + /obj/item/clothing/suit/det_trench, + /obj/item/clothing/suit/det_trench/grey, + /obj/item/clothing/suit/forensics/blue, + /obj/item/clothing/suit/forensics/red, /obj/item/clothing/gloves/thick, /obj/item/clothing/head/det, /obj/item/clothing/head/det/grey, /obj/item/clothing/shoes/dress, - /obj/item/storage/box/evidence, + /obj/item/box/evidence, /obj/item/radio/headset/headset_sec, /obj/item/clothing/suit/armor/pcarrier/detective, - /obj/item/taperoll/police, + /obj/item/stack/tape_roll/barricade_tape/police, /obj/item/gun/projectile/pistol, - /obj/item/clothing/accessory/storage/holster/armpit, - /obj/item/chems/food/drinks/flask/detflask, - /obj/item/storage/briefcase/crimekit, + /obj/item/clothing/webbing/holster/armpit, + /obj/item/chems/drinks/flask/detflask, + /obj/item/briefcase/crimekit, /obj/item/holowarrant ) @@ -195,12 +177,16 @@ /obj/structure/closet/secure_closet/brig name = "brig locker" req_access = list(access_brig) - anchored = 1 + anchored = TRUE var/id = null +/obj/structure/closet/secure_closet/brig/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(id, map_hash) + /obj/structure/closet/secure_closet/brig/WillContain() return list( - /obj/item/clothing/under/color/orange, + /obj/item/clothing/jumpsuit/orange, /obj/item/clothing/shoes/color/orange ) @@ -215,7 +201,7 @@ /obj/item/pen , /obj/item/clothing/suit/judgerobe, /obj/item/clothing/head/powdered_wig , - /obj/item/storage/briefcase, + /obj/item/briefcase, ) /obj/structure/closet/secure_closet/wall @@ -226,6 +212,10 @@ //too small to put a man in large = 0 +/obj/structure/closet/secure_closet/wall/Initialize() + . = ..() + tool_interaction_flags &= ~TOOL_INTERACTION_ANCHOR + /obj/structure/closet/secure_closet/lawyer name = "internal affairs secure closet" req_access = list(access_lawyer) @@ -236,5 +226,5 @@ /obj/item/camera = 2, /obj/item/camera_film = 2, /obj/item/taperecorder = 2, - /obj/item/storage/secure/briefcase = 2, + /obj/item/secure_storage/briefcase = 2, ) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/service.dm b/code/game/objects/structures/crates_lockers/closets/secure/service.dm index d9130f49b772..692080eda286 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/service.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/service.dm @@ -5,15 +5,15 @@ /obj/structure/closet/secure_closet/chaplain/WillContain() return list( - /obj/item/clothing/under/rank/chaplain, + /obj/item/clothing/jumpsuit/chaplain, /obj/item/clothing/shoes/color/black, /obj/item/clothing/suit/chaplain_hoodie, - /obj/item/storage/candle_box = 2, - /obj/item/storage/candle_box/incense, + /obj/item/box/candles = 2, + /obj/item/box/candles/incense, /obj/item/deck/tarot, - /obj/item/chems/food/drinks/bottle/holywater, + /obj/item/chems/drinks/bottle/holywater, /obj/item/nullrod, - /obj/item/storage/bible, - /obj/item/storage/belt/general, + /obj/item/bible, + /obj/item/belt/general, /obj/item/urn ) \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index e692e8ff5f3b..a8bac2f5fa78 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -3,10 +3,10 @@ desc = "An incredibly lifelike marble carving." icon = 'icons/obj/structures/statue.dmi' icon_state = "human_male" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE setup = 0 - health = 0 //destroying the statue kills the mob within + max_health = 1 //destroying the statue kills the mob within var/intialTox = 0 //these are here to keep the mob from taking damage from things that logically wouldn't affect a rock var/intialFire = 0 //it's a little sloppy I know but it was this or the GODMODE flag. Lesser of two evils. var/intialBrute = 0 @@ -16,18 +16,18 @@ /obj/structure/closet/statue/Initialize(mapload, var/mob/living/L) if(L && (ishuman(L) || L.isMonkey() || iscorgi(L))) if(L.buckled) - L.buckled = 0 - L.anchored = 0 + L.buckled = null + L.anchored = FALSE if(L.client) L.client.perspective = EYE_PERSPECTIVE L.client.eye = src L.forceMove(src) - L.set_sdisability(MUTED) - health = L.health + 100 //stoning damaged mobs will result in easier to shatter statues - intialTox = L.getToxLoss() - intialFire = L.getFireLoss() - intialBrute = L.getBruteLoss() - intialOxy = L.getOxyLoss() + L.add_genetic_condition(GENE_COND_MUTED) + current_health = L.current_health + 100 //stoning damaged mobs will result in easier to shatter statues + intialTox = L.get_damage(TOX) + intialFire = L.get_damage(BURN) + intialBrute = L.get_damage(BRUTE) + intialOxy = L.get_damage(OXY) if(ishuman(L)) name = "statue of [L.name]" if(L.gender == "female") @@ -40,7 +40,7 @@ icon_state = "corgi" desc = "If it takes forever, I will wait for you..." - if(health == 0) //meaning if the statue didn't find a valid target + if(current_health == 0) //meaning if the statue didn't find a valid target return INITIALIZE_HINT_QDEL START_PROCESSING(SSobj, src) @@ -49,43 +49,43 @@ /obj/structure/closet/statue/Process() timer-- for(var/mob/living/M in src) //Go-go gadget stasis field - M.setToxLoss(intialTox) - M.adjustFireLoss(intialFire - M.getFireLoss()) - M.adjustBruteLoss(intialBrute - M.getBruteLoss()) - M.setOxyLoss(intialOxy) + M.set_damage(TOX, intialTox) + M.take_damage(intialFire - M.get_damage(BURN), BURN, do_update_health = FALSE) + M.take_damage(intialBrute - M.get_damage(BRUTE)) + M.set_damage(OXY, intialOxy) if (timer <= 0) dump_contents() STOP_PROCESSING(SSobj, src) qdel(src) -/obj/structure/closet/statue/dump_contents() +/obj/structure/closet/statue/dump_contents(atom/forced_loc = loc, mob/user) for(var/obj/O in src) - O.dropInto(loc) + O.dropInto(forced_loc) for(var/mob/living/M in src) - M.dropInto(loc) - M.unset_sdisability(MUTED) - M.take_overall_damage((M.health - health - 100),0) //any new damage the statue incurred is transfered to the mob + M.dropInto(forced_loc) + M.remove_genetic_condition(GENE_COND_MUTED) + M.take_overall_damage((M.current_health - current_health - 100),0) //any new damage the statue incurred is transfered to the mob if(M.client) M.client.eye = M.client.mob M.client.perspective = MOB_PERSPECTIVE -/obj/structure/closet/statue/open() +/obj/structure/closet/statue/open(mob/user) return -/obj/structure/closet/statue/close() +/obj/structure/closet/statue/close(mob/user) return /obj/structure/closet/statue/toggle() return /obj/structure/closet/statue/proc/check_health() - if(health <= 0) + if(current_health <= 0) for(var/mob/M in src) shatter(M) /obj/structure/closet/statue/bullet_act(var/obj/item/projectile/Proj) - health -= Proj.get_structure_damage() + current_health -= Proj.get_structure_damage() check_health() return @@ -95,23 +95,25 @@ M.explosion_act(severity) ..() if(!QDELETED(src)) - health -= 60 / severity + current_health -= 60 / severity check_health() -/obj/structure/closet/statue/attackby(obj/item/I, mob/user) - health -= I.force +/obj/structure/closet/statue/attackby(obj/item/used_item, mob/user) + current_health -= used_item.expend_attack_force(user) user.do_attack_animation(src) - visible_message("[user] strikes [src] with [I].") + visible_message("[user] strikes [src] with [used_item].") check_health() + return TRUE -/obj/structure/closet/statue/MouseDrop_T() - return +/obj/structure/closet/statue/receive_mouse_drop(atom/dropping, mob/user, params) + return TRUE /obj/structure/closet/statue/relaymove() return /obj/structure/closet/statue/attack_hand() - return + SHOULD_CALL_PARENT(FALSE) + return TRUE /obj/structure/closet/statue/verb_toggleopen() return diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm index c861a299a74e..33fd93aa1d48 100644 --- a/code/game/objects/structures/crates_lockers/closets/syndicate.dm +++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm @@ -10,7 +10,8 @@ . = ..() new /obj/item/tank/jetpack/oxygen(src) new /obj/item/clothing/mask/gas/syndicate(src) - new /obj/item/clothing/under/syndicate(src) + new /obj/item/clothing/shirt/syndicate(src) + new /obj/item/clothing/pants/casual/camo(src) new /obj/item/clothing/head/helmet/space/void/merc(src) new /obj/item/clothing/suit/space/void/merc(src) new /obj/item/crowbar/red(src) @@ -32,35 +33,6 @@ new /obj/item/clothing/mask/gas/syndicate(src) new /obj/item/clothing/head/helmet/space/void/merc(src) - -/obj/structure/closet/syndicate/nuclear - desc = "It's a storage unit for nuclear-operative gear." - -/obj/structure/closet/syndicate/nuclear/Initialize() - . = ..() - - new /obj/item/ammo_magazine/smg(src) - new /obj/item/ammo_magazine/smg(src) - new /obj/item/ammo_magazine/smg(src) - new /obj/item/ammo_magazine/smg(src) - new /obj/item/ammo_magazine/smg(src) - new /obj/item/storage/box/handcuffs(src) - new /obj/item/storage/box/flashbangs(src) - new /obj/item/gun/energy/gun(src) - new /obj/item/gun/energy/gun(src) - new /obj/item/gun/energy/gun(src) - new /obj/item/gun/energy/gun(src) - new /obj/item/gun/energy/gun(src) - new /obj/item/pinpointer/nukeop(src) - new /obj/item/pinpointer/nukeop(src) - new /obj/item/pinpointer/nukeop(src) - new /obj/item/pinpointer/nukeop(src) - new /obj/item/pinpointer/nukeop(src) - new /obj/item/modular_computer/pda/syndicate(src) - var/obj/item/radio/uplink/U = new(src) - U.hidden_uplink.uses = 40 - return - /obj/structure/closet/syndicate/resources desc = "An old, dusty locker." @@ -83,31 +55,31 @@ //Metal (common ore) if(pickednum >= 2) - new /obj/item/stack/material/steel(src, rand(common_min, common_max)) + SSmaterials.create_object(/decl/material/solid/metal/steel, src, rand(common_min, common_max)) //Glass (common ore) if(pickednum >= 5) - new /obj/item/stack/material/glass(src, rand(common_min, common_max)) + SSmaterials.create_object(/decl/material/solid/glass, src, rand(common_min, common_max)) //Plasteel (common metal) if(pickednum >= 10) - new /obj/item/stack/material/plasteel(src, rand(common_min, common_max)) + SSmaterials.create_object(/decl/material/solid/metal/plasteel, src, rand(common_min, common_max)) //Silver (rare ore) if(pickednum >= 15) - new /obj/item/stack/material/silver(src, rand(rare_min, rare_max)) + SSmaterials.create_object(/decl/material/solid/metal/silver, src, rand(rare_min, rare_max)) //Gold (rare ore) if(pickednum >= 30) - new /obj/item/stack/material/gold(src, rand(rare_min, rare_max)) + SSmaterials.create_object(/decl/material/solid/metal/gold, src, rand(rare_min, rare_max)) //Uranium (rare ore) if(pickednum >= 40) - new /obj/item/stack/material/uranium(src, rand(rare_min, rare_max)) + SSmaterials.create_object(/decl/material/solid/metal/uranium, src, rand(rare_min, rare_max)) //Diamond (rare HONK) if(pickednum >= 45) - new /obj/item/stack/material/diamond(src, rand(rare_min, rare_max)) + SSmaterials.create_object(/decl/material/solid/gemstone/diamond, src, rand(rare_min, rare_max)) //Jetpack (You hit the jackpot!) if(pickednum == 50) @@ -120,18 +92,16 @@ . = ..() var/list/resources = list( - /obj/item/stack/material/steel, - /obj/item/stack/material/glass, - /obj/item/stack/material/gold, - /obj/item/stack/material/silver, - /obj/item/stack/material/uranium, - /obj/item/stack/material/diamond, - /obj/item/stack/material/plasteel, - /obj/item/stack/material/rods + /obj/item/stack/material/sheet/mapped/steel/fifty, + /obj/item/stack/material/pane/mapped/glass/fifty, + /obj/item/stack/material/ingot/mapped/gold/fifty, + /obj/item/stack/material/ingot/mapped/silver/fifty, + /obj/item/stack/material/puck/mapped/uranium/fifty, + /obj/item/stack/material/gemstone/mapped/diamond/fifty, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, + /obj/item/stack/material/rods/mapped/steel/fifty ) - - for(var/i = 0, i<2, i++) + for(var/i = 0, i < 2, i++) for(var/res in resources) - var/obj/item/stack/R = new res(src) - R.amount = R.max_amount \ No newline at end of file + new res(src) diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm index 06500a2aeca1..c4259273a4b0 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -16,7 +16,7 @@ */ /obj/structure/closet/emcloset name = "emergency closet" - desc = "It's a storage unit for emergency breathmasks and o2 tanks." + desc = "It's a storage unit for emergency breath masks and oxygen tanks." closet_appearance = /decl/closet_appearance/oxygen /obj/structure/closet/emcloset/WillContain() @@ -24,10 +24,10 @@ . = list(/obj/item/tank/emergency/oxygen = 2, /obj/item/clothing/mask/breath = 2) - . += new/datum/atom_creator/simple(list(/obj/item/storage/toolbox/emergency, /obj/item/inflatable/wall = 2), 75) + . += new/datum/atom_creator/simple(list(/obj/item/toolbox/emergency, /obj/item/inflatable = 2, /obj/item/inflatable/door = 1), 75) . += new/datum/atom_creator/simple(list(/obj/item/tank/emergency/oxygen/engi, /obj/item/clothing/mask/gas/half), 10) . += new/datum/atom_creator/simple(/obj/item/oxycandle, 15) - . += new/datum/atom_creator/simple(/obj/item/storage/firstaid/o2, 25) + . += new/datum/atom_creator/simple(/obj/item/firstaid/o2, 25) . += new/datum/atom_creator/simple(list(/obj/item/clothing/suit/space/emergency,/obj/item/clothing/head/helmet/space/emergency), 25) /* @@ -41,22 +41,20 @@ /obj/structure/closet/firecloset/WillContain() return list( - /obj/item/storage/med_pouch/burn, - /obj/item/storage/backpack/dufflebag/firefighter, + /obj/item/med_pouch/burn, + /obj/item/backpack/dufflebag/firefighter, /obj/item/clothing/mask/gas, /obj/item/flashlight ) -/obj/structure/closet/firecloset/chief - /obj/structure/closet/firecloset/chief/WillContain() return list( - /obj/item/storage/med_pouch/burn, + /obj/item/med_pouch/burn, /obj/item/clothing/suit/fire, /obj/item/clothing/mask/gas, /obj/item/flashlight, /obj/item/tank/emergency/oxygen/double/red, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/clothing/head/hardhat/firefighter) /* @@ -67,38 +65,24 @@ desc = "It's a storage unit for tools." closet_appearance = /decl/closet_appearance/secure_closet/engineering/tools -/obj/structure/closet/toolcloset/Initialize() - . = ..() - if(prob(40)) - new /obj/item/clothing/suit/storage/hazardvest(src) - if(prob(70)) - new /obj/item/flashlight(src) - if(prob(70)) - new /obj/item/screwdriver(src) - if(prob(70)) - new /obj/item/wrench(src) - if(prob(70)) - new /obj/item/weldingtool(src) - if(prob(70)) - new /obj/item/crowbar(src) - if(prob(70)) - new /obj/item/wirecutters(src) - if(prob(70)) - new /obj/item/t_scanner(src) - if(prob(20)) - new /obj/item/storage/belt/utility(src) - if(prob(30)) - new /obj/item/stack/cable_coil/random(src) - if(prob(30)) - new /obj/item/stack/cable_coil/random(src) - if(prob(30)) - new /obj/item/stack/cable_coil/random(src) - if(prob(20)) - new /obj/item/multitool(src) - if(prob(5)) - new /obj/item/clothing/gloves/insulated(src) - if(prob(40)) - new /obj/item/clothing/head/hardhat(src) +/obj/structure/closet/toolcloset/WillContain() + return list( + new /datum/atom_creator/simple(/obj/item/clothing/suit/hazardvest, 40), + new /datum/atom_creator/simple(/obj/item/flashlight, 70), + new /datum/atom_creator/simple(/obj/item/screwdriver, 70), + new /datum/atom_creator/simple(/obj/item/wrench, 70), + new /datum/atom_creator/simple(/obj/item/weldingtool, 70), + new /datum/atom_creator/simple(/obj/item/crowbar, 70), + new /datum/atom_creator/simple(/obj/item/wirecutters, 70), + new /datum/atom_creator/simple(/obj/item/t_scanner, 70), + new /datum/atom_creator/simple(/obj/item/belt/utility, 20), + new /datum/atom_creator/simple(/obj/item/stack/cable_coil/random, 30), + new /datum/atom_creator/simple(/obj/item/stack/cable_coil/random, 30), + new /datum/atom_creator/simple(/obj/item/stack/cable_coil/random, 30), + new /datum/atom_creator/simple(/obj/item/multitool, 20), + new /datum/atom_creator/simple(/obj/item/clothing/gloves/insulated, 5), + new /datum/atom_creator/simple(/obj/item/clothing/head/hardhat, 40), + ) /* @@ -111,11 +95,9 @@ /obj/structure/closet/radiation/WillContain() return list( - /obj/item/storage/med_pouch/toxin = 2, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/head/radiation, - /obj/item/clothing/suit/radiation, - /obj/item/clothing/head/radiation, + /obj/item/med_pouch/radiation = 2, + /obj/item/clothing/suit/radiation = 2, + /obj/item/clothing/head/radiation = 2, /obj/item/geiger = 2) /* @@ -129,7 +111,7 @@ /obj/structure/closet/bombcloset/WillContain() return list( /obj/item/clothing/suit/bomb_suit, - /obj/item/clothing/under/color/black, + /obj/item/clothing/jumpsuit/black, /obj/item/clothing/shoes/color/black, /obj/item/clothing/head/bomb_hood) @@ -142,7 +124,7 @@ /obj/structure/closet/bombclosetsecurity/WillContain() return list( /obj/item/clothing/suit/bomb_suit/security, - /obj/item/clothing/under/rank/security, + /obj/item/clothing/jumpsuit/security, /obj/item/clothing/shoes/color/brown, /obj/item/clothing/head/bomb_hood/security) @@ -150,35 +132,50 @@ * Hydrant */ /obj/structure/closet/hydrant //wall mounted fire closet - name = "fire-safety closet" + name = "fire-safety wall closet" desc = "It's a storage unit for fire-fighting supplies." closet_appearance = /decl/closet_appearance/wall/hydrant - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE wall_mounted = 1 storage_types = CLOSET_STORAGE_ITEMS setup = 0 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + icon = 'icons/obj/closets/bases/wall.dmi' + +/obj/structure/closet/hydrant/Initialize(ml, _mat, _reinf_mat) + . = ..() + tool_interaction_flags &= ~TOOL_INTERACTION_ANCHOR /obj/structure/closet/hydrant/WillContain() return list( + /obj/item/inflatable = 2, /obj/item/inflatable/door = 2, - /obj/item/storage/med_pouch/burn = 2, + /obj/item/med_pouch/burn = 2, /obj/item/clothing/mask/gas/half, - /obj/item/storage/backpack/dufflebag/firefighter + /obj/item/backpack/dufflebag/firefighter ) /* * First Aid */ /obj/structure/closet/medical_wall //wall mounted medical closet - name = "first-aid closet" + name = "first-aid wall closet" desc = "It's a wall-mounted storage unit for first aid supplies." closet_appearance = /decl/closet_appearance/wall/medical - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE wall_mounted = 1 storage_types = CLOSET_STORAGE_ITEMS setup = 0 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + icon = 'icons/obj/closets/bases/wall.dmi' + +/obj/structure/closet/medical_wall/Initialize() + . = ..() + tool_interaction_flags &= ~TOOL_INTERACTION_ANCHOR /obj/structure/closet/medical_wall/filled/WillContain() return list( @@ -186,17 +183,25 @@ /obj/random/medical/lite = 12) /obj/structure/closet/shipping_wall - name = "shipping supplies closet" + name = "shipping supplies wall closet" desc = "It's a wall-mounted storage unit containing supplies for preparing shipments." closet_appearance = /decl/closet_appearance/wall/shipping - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE wall_mounted = 1 storage_types = CLOSET_STORAGE_ITEMS setup = 0 + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + icon = 'icons/obj/closets/bases/wall.dmi' + +/obj/structure/closet/shipping_wall/Initialize() + . = ..() + tool_interaction_flags &= ~TOOL_INTERACTION_ANCHOR /obj/structure/closet/shipping_wall/filled/WillContain() return list( - /obj/item/stack/material/cardboard/ten, + /obj/item/stack/material/cardstock/mapped/cardboard/ten, /obj/item/destTagger, - /obj/item/stack/package_wrap/twenty_five) \ No newline at end of file + /obj/item/stack/package_wrap/twenty_five + ) diff --git a/code/game/objects/structures/crates_lockers/closets/walllocker.dm b/code/game/objects/structures/crates_lockers/closets/walllocker.dm index 023c626703d5..cb186904d24c 100644 --- a/code/game/objects/structures/crates_lockers/closets/walllocker.dm +++ b/code/game/objects/structures/crates_lockers/closets/walllocker.dm @@ -4,54 +4,28 @@ /obj/structure/closet/walllocker desc = "A wall mounted storage locker." name = "Wall Locker" + icon = 'icons/obj/closets/bases/wall.dmi' closet_appearance = /decl/closet_appearance/wall - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE wall_mounted = 1 storage_types = CLOSET_STORAGE_ITEMS setup = 0 - -//spawns endless (3 sets) amounts of breathmask, emergency oxy tank and crowbar - -/obj/structure/closet/walllocker/emerglocker - name = "emergency locker" - desc = "A wall mounted locker with emergency supplies." - var/list/spawnitems = list(/obj/item/tank/emergency/oxygen,/obj/item/clothing/mask/breath) - var/amount = 2 // spawns each items X times. - closet_appearance = /decl/closet_appearance/wall/emergency - -/obj/structure/closet/walllocker/emerglocker/toggle(mob/user) - src.attack_hand(user) - return - -/obj/structure/closet/walllocker/emerglocker/attackby(obj/item/W, mob/user) - return - -/obj/structure/closet/walllocker/emerglocker/attack_hand(mob/user) - if (istype(user, /mob/living/silicon/ai)) //Added by Strumpetplaya - AI shouldn't be able to - return //activate emergency lockers. This fixes that. (Does this make sense, the AI can't call attack_hand, can it? --Mloc) - if(!amount) - to_chat(usr, SPAN_WARNING("It's empty.")) - return - if(amount) - to_chat(usr, SPAN_NOTICE("You take out some items from \the [src].")) - for(var/path in spawnitems) - new path(src.loc) - amount-- - return - -/obj/structure/closet/walllocker/emerglocker/north - pixel_y = 32 - dir = SOUTH - -/obj/structure/closet/walllocker/emerglocker/south - pixel_y = -32 - dir = NORTH - -/obj/structure/closet/walllocker/emerglocker/west - pixel_x = -32 - dir = WEST - -/obj/structure/closet/walllocker/emerglocker/east - pixel_x = 32 - dir = EAST + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + +/obj/structure/closet/walllocker/Initialize() + . = ..() + tool_interaction_flags &= ~TOOL_INTERACTION_ANCHOR + +/obj/structure/closet/walllocker/suit + name = "wall suit storage" + desc = "A nook in the wall storing a couple of space suits." + closet_appearance = /decl/closet_appearance/wall/suit + +/obj/structure/closet/walllocker/suit/WillContain() + return list( + /obj/item/clothing/head/helmet/space = 2, + /obj/item/clothing/suit/space = 2, + /obj/item/tank/oxygen = 2 + ) diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index 47c9b3811369..530667151087 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -7,382 +7,325 @@ name = "security wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/red -/obj/structure/closet/wardrobe/red/Initialize() - . = ..() - new /obj/item/clothing/under/rank/security(src) - new /obj/item/clothing/under/rank/security(src) - new /obj/item/clothing/under/rank/security(src) - new /obj/item/clothing/under/rank/security2(src) - new /obj/item/clothing/under/rank/security2(src) - new /obj/item/clothing/under/rank/security2(src) - new /obj/item/clothing/shoes/jackboots(src) - new /obj/item/clothing/shoes/jackboots(src) - new /obj/item/clothing/shoes/jackboots(src) - new /obj/item/clothing/head/soft/sec(src) - new /obj/item/clothing/head/soft/sec(src) - new /obj/item/clothing/head/soft/sec(src) +/obj/structure/closet/wardrobe/red/WillContain() + return list( + /obj/item/clothing/jumpsuit/security = 3, + /obj/item/clothing/shirt/button/security = 3, + /obj/item/clothing/pants/slacks/security = 3, + /obj/item/clothing/shoes/jackboots = 3, + /obj/item/clothing/head/soft/sec = 3 + ) /obj/structure/closet/wardrobe/pink name = "pink wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/pink -/obj/structure/closet/wardrobe/pink/Initialize() - . = ..() - new /obj/item/clothing/under/color/pink(src) - new /obj/item/clothing/under/color/pink(src) - new /obj/item/clothing/under/color/pink(src) - new /obj/item/clothing/shoes/color/brown(src) - new /obj/item/clothing/shoes/color/brown(src) - new /obj/item/clothing/shoes/color/brown(src) +/obj/structure/closet/wardrobe/pink/WillContain() + return list( + /obj/item/clothing/jumpsuit/pink = 3, + /obj/item/clothing/shoes/color/brown = 3, + ) /obj/structure/closet/wardrobe/black name = "black wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/black -/obj/structure/closet/wardrobe/black/Initialize() - . = ..() - new /obj/item/clothing/under/color/black(src) - new /obj/item/clothing/under/color/black(src) - new /obj/item/clothing/under/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/head/that(src) - new /obj/item/clothing/head/that(src) - new /obj/item/clothing/head/that(src) - new /obj/item/clothing/head/soft/black(src) - new /obj/item/clothing/head/soft/black(src) - new /obj/item/clothing/head/soft/black(src) +/obj/structure/closet/wardrobe/black/WillContain() + return list( + /obj/item/clothing/jumpsuit/black = 3, + /obj/item/clothing/shoes/color/black = 3, + /obj/item/clothing/head/that = 3, + /obj/item/clothing/head/soft/black = 3, + ) /obj/structure/closet/wardrobe/chaplain_black name = "chapel wardrobe" desc = "It's a storage unit for approved religious attire." closet_appearance = /decl/closet_appearance/wardrobe/black -/obj/structure/closet/wardrobe/chaplain_black/Initialize() - . = ..() - new /obj/item/clothing/under/rank/chaplain(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/suit/nun(src) - new /obj/item/clothing/head/nun_hood(src) - new /obj/item/clothing/suit/chaplain_hoodie(src) - new /obj/item/clothing/head/chaplain_hood(src) - new /obj/item/clothing/suit/holidaypriest(src) - new /obj/item/clothing/under/wedding/bride_white(src) - new /obj/item/storage/backpack/cultpack (src) - new /obj/item/storage/candle_box(src) - new /obj/item/storage/candle_box(src) - new /obj/item/deck/tarot(src) +/obj/structure/closet/wardrobe/chaplain_black/WillContain() + return list( + /obj/item/box/candles = 2, + /obj/item/clothing/jumpsuit/chaplain, + /obj/item/clothing/shoes/color/black, + /obj/item/clothing/suit/nun, + /obj/item/clothing/head/nun_hood, + /obj/item/clothing/suit/chaplain_hoodie, + /obj/item/clothing/head/chaplain_hood, + /obj/item/clothing/suit/holidaypriest, + /obj/item/clothing/dress/wedding/bride_white, + /obj/item/backpack/cultpack, + /obj/item/deck/tarot, + ) /obj/structure/closet/wardrobe/green name = "green wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/green -/obj/structure/closet/wardrobe/green/Initialize() - . = ..() - new /obj/item/clothing/under/color/green(src) - new /obj/item/clothing/under/color/green(src) - new /obj/item/clothing/under/color/green(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) +/obj/structure/closet/wardrobe/green/WillContain() + return list( + /obj/item/clothing/jumpsuit/green = 3, + /obj/item/clothing/shoes/color/black = 3, + ) /obj/structure/closet/wardrobe/xenos name = "xenos wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/green -/obj/structure/closet/wardrobe/xenos/Initialize() - . = ..() - new /obj/item/clothing/suit/robe(src) - new /obj/item/clothing/shoes/sandal(src) - new /obj/item/clothing/shoes/sandal(src) - new /obj/item/clothing/shoes/sandal(src) +/obj/structure/closet/wardrobe/xenos/WillContain() + return list( + /obj/item/clothing/suit/robe/yellowed = 3, + /obj/item/clothing/shoes/sandal = 3, + ) /obj/structure/closet/wardrobe/orange name = "prison wardrobe" desc = "It's a storage unit for regulation prisoner attire." closet_appearance = /decl/closet_appearance/wardrobe/orange -/obj/structure/closet/wardrobe/orange/Initialize() - . = ..() - new /obj/item/clothing/under/color/orange(src) - new /obj/item/clothing/under/color/orange(src) - new /obj/item/clothing/under/color/orange(src) - new /obj/item/clothing/shoes/color/orange(src) - new /obj/item/clothing/shoes/color/orange(src) - new /obj/item/clothing/shoes/color/orange(src) - new /obj/item/radio/headset(src) - new /obj/item/radio/headset(src) - new /obj/item/radio/headset(src) +/obj/structure/closet/wardrobe/orange/WillContain() + return list( + /obj/item/clothing/jumpsuit/orange = 3, + /obj/item/clothing/shoes/color/orange = 3, + /obj/item/radio/headset = 3, + ) /obj/structure/closet/wardrobe/yellow name = "yellow wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/yellow -/obj/structure/closet/wardrobe/yellow/Initialize() - . = ..() - new /obj/item/clothing/under/color/yellow(src) - new /obj/item/clothing/under/color/yellow(src) - new /obj/item/clothing/under/color/yellow(src) - new /obj/item/clothing/shoes/color/orange(src) - new /obj/item/clothing/shoes/color/orange(src) - new /obj/item/clothing/shoes/color/orange(src) +/obj/structure/closet/wardrobe/yellow/WillContain() + return list( + /obj/item/clothing/jumpsuit/yellow = 3, + /obj/item/clothing/shoes/color/orange = 3, + ) /obj/structure/closet/wardrobe/atmospherics_yellow name = "atmospherics wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/yellow -/obj/structure/closet/wardrobe/atmospherics_yellow/Initialize() - . = ..() - new /obj/item/clothing/under/rank/atmospheric_technician(src) - new /obj/item/clothing/under/rank/atmospheric_technician(src) - new /obj/item/clothing/under/rank/atmospheric_technician(src) - new /obj/item/clothing/shoes/workboots(src) - new /obj/item/clothing/shoes/workboots(src) - new /obj/item/clothing/shoes/workboots(src) - new /obj/item/clothing/head/hardhat/red(src) - new /obj/item/clothing/head/hardhat/red(src) - new /obj/item/clothing/head/hardhat/red(src) +/obj/structure/closet/wardrobe/atmospherics_yellow/WillContain() + return list( + /obj/item/clothing/jumpsuit/atmospheric_technician = 3, + /obj/item/clothing/shoes/workboots = 3, + /obj/item/clothing/head/hardhat/red = 3, + ) /obj/structure/closet/wardrobe/engineering_yellow name = "engineering wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/yellow -/obj/structure/closet/wardrobe/engineering_yellow/Initialize() - . = ..() - new /obj/item/clothing/under/rank/engineer(src) - new /obj/item/clothing/under/rank/engineer(src) - new /obj/item/clothing/under/rank/engineer(src) - new /obj/item/clothing/shoes/workboots(src) - new /obj/item/clothing/shoes/workboots(src) - new /obj/item/clothing/shoes/workboots(src) - new /obj/item/clothing/head/hardhat(src) - new /obj/item/clothing/head/hardhat(src) - new /obj/item/clothing/head/hardhat(src) +/obj/structure/closet/wardrobe/engineering_yellow/WillContain() + return list( + /obj/item/clothing/jumpsuit/engineer = 3, + /obj/item/clothing/shoes/workboots = 3, + /obj/item/clothing/head/hardhat = 3, + ) /obj/structure/closet/wardrobe/white name = "white wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/white/Initialize() - . = ..() - new /obj/item/clothing/under/color/white(src) - new /obj/item/clothing/under/color/white(src) - new /obj/item/clothing/under/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) +/obj/structure/closet/wardrobe/white/WillContain() + return list( + /obj/item/clothing/jumpsuit/white = 3, + /obj/item/clothing/shoes/color/white = 3, + ) /obj/structure/closet/wardrobe/pjs name = "pajama wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/pjs/Initialize() - . = ..() - new /obj/item/clothing/under/pj/red(src) - new /obj/item/clothing/under/pj/red(src) - new /obj/item/clothing/under/pj/blue(src) - new /obj/item/clothing/under/pj/blue(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/slippers(src) - new /obj/item/clothing/shoes/slippers(src) +/obj/structure/closet/wardrobe/pjs/WillContain() + return list( + /obj/item/clothing/pants/pj = 1, + /obj/item/clothing/pants/pj/blue = 1, + /obj/item/clothing/shirt/pj = 1, + /obj/item/clothing/shirt/pj/blue = 1, + /obj/item/clothing/shoes/color/white = 2, + /obj/item/clothing/shoes/slippers = 2, + ) /obj/structure/closet/wardrobe/science_white name = "science wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/science_white/Initialize() - . = ..() - new /obj/item/clothing/under/color/white(src) - new /obj/item/clothing/under/color/white(src) - new /obj/item/clothing/under/color/white(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) +/obj/structure/closet/wardrobe/science_white/WillContain() + return list( + /obj/item/clothing/jumpsuit/white = 3, + /obj/item/clothing/suit/toggle/labcoat = 3, + /obj/item/clothing/shoes/color/white = 3, + ) /obj/structure/closet/wardrobe/robotics_black name = "robotics wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/black -/obj/structure/closet/wardrobe/robotics_black/Initialize() - . = ..() - new /obj/item/clothing/under/rank/roboticist(src) - new /obj/item/clothing/under/rank/roboticist(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/gloves/thick(src) - new /obj/item/clothing/gloves/thick(src) +/obj/structure/closet/wardrobe/robotics_black/WillContain() + return list( + /obj/item/clothing/jumpsuit/roboticist = 2, + /obj/item/clothing/suit/toggle/labcoat = 2, + /obj/item/clothing/shoes/color/black = 2, + /obj/item/clothing/gloves/thick = 2, + ) /obj/structure/closet/wardrobe/chemistry_white name = "chemistry wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/chemistry_white/Initialize() - . = ..() - new /obj/item/clothing/under/rank/chemist(src) - new /obj/item/clothing/under/rank/chemist(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/suit/storage/toggle/labcoat/chemist(src) - new /obj/item/clothing/suit/storage/toggle/labcoat/chemist(src) +/obj/structure/closet/wardrobe/chemistry_white/WillContain() + return list( + /obj/item/clothing/jumpsuit/chemist = 2, + /obj/item/clothing/shoes/color/white = 2, + /obj/item/clothing/suit/toggle/labcoat/chemist = 2, + ) /obj/structure/closet/wardrobe/genetics_white name = "genetics wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/genetics_white/Initialize() - . = ..() - new /obj/item/clothing/under/rank/geneticist(src) - new /obj/item/clothing/under/rank/geneticist(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/suit/storage/toggle/labcoat/genetics(src) - new /obj/item/clothing/suit/storage/toggle/labcoat/genetics(src) +/obj/structure/closet/wardrobe/genetics_white/WillContain() + return list( + /obj/item/clothing/jumpsuit/geneticist = 2, + /obj/item/clothing/shoes/color/white = 2, + /obj/item/clothing/suit/toggle/labcoat/genetics = 2, + ) /obj/structure/closet/wardrobe/virology_white name = "virology wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/virology_white/Initialize() - . = ..() - new /obj/item/clothing/under/rank/virologist(src) - new /obj/item/clothing/under/rank/virologist(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(src) - new /obj/item/clothing/suit/storage/toggle/labcoat/virologist(src) - new /obj/item/clothing/mask/surgical(src) - new /obj/item/clothing/mask/surgical(src) +/obj/structure/closet/wardrobe/virology_white/WillContain() + return list( + /obj/item/clothing/jumpsuit/virologist = 2, + /obj/item/clothing/shoes/color/white = 2, + /obj/item/clothing/suit/toggle/labcoat/virologist = 2, + /obj/item/clothing/mask/surgical = 2, + ) /obj/structure/closet/wardrobe/medic_white name = "medical wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/white -/obj/structure/closet/wardrobe/medic_white/Initialize() - . = ..() - new /obj/item/clothing/under/rank/medical(src) - new /obj/item/clothing/under/rank/medical(src) - new /obj/item/clothing/under/rank/medical/scrubs/blue(src) - new /obj/item/clothing/under/rank/medical/scrubs/green(src) - new /obj/item/clothing/under/rank/medical/scrubs/purple(src) - new /obj/item/clothing/under/rank/medical/scrubs/black(src) - new /obj/item/clothing/under/rank/medical/scrubs/navyblue(src) - new /obj/item/clothing/head/surgery/navyblue(src) - new /obj/item/clothing/head/surgery/purple(src) - new /obj/item/clothing/head/surgery/blue(src) - new /obj/item/clothing/head/surgery/green(src) - new /obj/item/clothing/head/surgery/black(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/shoes/color/white(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/suit/storage/toggle/labcoat(src) - new /obj/item/clothing/mask/surgical(src) - new /obj/item/clothing/mask/surgical(src) +/obj/structure/closet/wardrobe/medic_white/WillContain() + return list( + /obj/item/clothing/jumpsuit/medical = 2, + /obj/item/clothing/shoes/color/white = 3, + /obj/item/clothing/suit/toggle/labcoat = 2, + /obj/item/clothing/mask/surgical = 2, + /obj/item/clothing/pants/scrubs/blue, + /obj/item/clothing/pants/scrubs/green, + /obj/item/clothing/pants/scrubs/purple, + /obj/item/clothing/pants/scrubs/black, + /obj/item/clothing/pants/scrubs/navyblue, + /obj/item/clothing/shirt/scrubs/blue, + /obj/item/clothing/shirt/scrubs/green, + /obj/item/clothing/shirt/scrubs/purple, + /obj/item/clothing/shirt/scrubs/black, + /obj/item/clothing/shirt/scrubs/navyblue, + /obj/item/clothing/head/surgery/navyblue, + /obj/item/clothing/head/surgery/purple, + /obj/item/clothing/head/surgery/blue, + /obj/item/clothing/head/surgery/green, + /obj/item/clothing/head/surgery/black, + ) /obj/structure/closet/wardrobe/grey name = "grey wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/grey -/obj/structure/closet/wardrobe/grey/Initialize() - . = ..() - new /obj/item/clothing/under/color/grey(src) - new /obj/item/clothing/under/color/grey(src) - new /obj/item/clothing/under/color/grey(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/shoes/color/black(src) - new /obj/item/clothing/head/soft/grey(src) - new /obj/item/clothing/head/soft/grey(src) - new /obj/item/clothing/head/soft/grey(src) +/obj/structure/closet/wardrobe/grey/WillContain() + return list( + /obj/item/clothing/jumpsuit/grey = 3, + /obj/item/clothing/shoes/color/black = 3, + /obj/item/clothing/head/soft/grey = 3, + ) /obj/structure/closet/wardrobe/mixed name = "mixed wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/mixed -/obj/structure/closet/wardrobe/mixed/Initialize() - . = ..() - new /obj/item/clothing/under/color/blue(src) - new /obj/item/clothing/under/color/yellow(src) - new /obj/item/clothing/under/color/green(src) - new /obj/item/clothing/under/color/orange(src) - new /obj/item/clothing/under/color/pink(src) - new /obj/item/clothing/under/dress/plaid_blue(src) - new /obj/item/clothing/under/dress/plaid_red(src) - new /obj/item/clothing/under/dress/plaid_purple(src) - new /obj/item/clothing/shoes/color/blue(src) - new /obj/item/clothing/shoes/color/yellow(src) - new /obj/item/clothing/shoes/color/green(src) - new /obj/item/clothing/shoes/color/orange(src) - new /obj/item/clothing/shoes/color/purple(src) - new /obj/item/clothing/shoes/color/red(src) - new /obj/item/clothing/shoes/craftable(src) - new /obj/item/clothing/accessory/toggleable/hawaii/random(src) +/obj/structure/closet/wardrobe/mixed/WillContain() + return list( + /obj/item/clothing/jumpsuit/blue, + /obj/item/clothing/jumpsuit/yellow, + /obj/item/clothing/jumpsuit/green, + /obj/item/clothing/jumpsuit/orange, + /obj/item/clothing/jumpsuit/pink, + /obj/item/clothing/skirt/plaid_blue, + /obj/item/clothing/shirt/blouse/blue, + /obj/item/clothing/skirt/plaid_red, + /obj/item/clothing/shirt/blouse/red, + /obj/item/clothing/skirt/plaid_purple, + /obj/item/clothing/shirt/blouse/purple, + /obj/item/clothing/shoes/color/blue, + /obj/item/clothing/shoes/color/yellow, + /obj/item/clothing/shoes/color/green, + /obj/item/clothing/shoes/color/orange, + /obj/item/clothing/shoes/color/purple, + /obj/item/clothing/shoes/color/red, + /obj/item/clothing/shoes/craftable, + /obj/item/clothing/shirt/hawaii/random, + ) /obj/structure/closet/wardrobe/tactical name = "tactical equipment" closet_appearance = /decl/closet_appearance/tactical -/obj/structure/closet/wardrobe/tactical/Initialize() - . = ..() - new /obj/item/clothing/under/tactical(src) - new /obj/item/clothing/suit/armor/pcarrier/tactical(src) - new /obj/item/clothing/head/helmet/tactical(src) - new /obj/item/clothing/mask/balaclava/tactical(src) - new /obj/item/clothing/glasses/tacgoggles(src) - new /obj/item/storage/belt/holster/security/tactical(src) - new /obj/item/clothing/shoes/jackboots/tactical(src) - new /obj/item/clothing/gloves/tactical(src) +/obj/structure/closet/wardrobe/tactical/WillContain() + return list( + /obj/item/clothing/jumpsuit/tactical, + /obj/item/clothing/suit/armor/pcarrier/tactical, + /obj/item/clothing/head/helmet/tactical, + /obj/item/clothing/mask/balaclava/tactical, + /obj/item/clothing/glasses/tacgoggles, + /obj/item/belt/holster/security/tactical, + /obj/item/clothing/shoes/jackboots/tactical, + /obj/item/clothing/gloves/tactical, + ) /obj/structure/closet/wardrobe/suit name = "formal clothing locker" closet_appearance = /decl/closet_appearance/wardrobe/mixed -/obj/structure/closet/wardrobe/suit/Initialize() - . = ..() - new /obj/item/clothing/under/suit_jacket/charcoal(src) - new /obj/item/clothing/under/suit_jacket/navy(src) - new /obj/item/clothing/under/suit_jacket/burgundy(src) - new /obj/item/clothing/under/suit_jacket/checkered(src) - new /obj/item/clothing/under/suit_jacket/tan(src) - new /obj/item/clothing/under/sl_suit(src) - new /obj/item/clothing/under/suit_jacket(src) - new /obj/item/clothing/under/suit_jacket/female(src) - new /obj/item/clothing/under/suit_jacket/really_black(src) - new /obj/item/clothing/under/suit_jacket/red(src) - new /obj/item/clothing/under/scratch(src) - new /obj/item/clothing/under/rank/internalaffairs/plain(src) - new /obj/item/clothing/suit/storage/toggle/suit/black(src) - new /obj/item/clothing/under/assistantformal(src) - new /obj/item/clothing/under/lawyer/female(src) - new /obj/item/clothing/under/lawyer/black(src) - new /obj/item/clothing/under/lawyer/red(src) - new /obj/item/clothing/under/lawyer/bluesuit(src) - new /obj/item/clothing/suit/storage/toggle/suit/blue(src) - new /obj/item/clothing/under/lawyer/purpsuit(src) - new /obj/item/clothing/suit/storage/toggle/suit/purple(src) - new /obj/item/clothing/shoes/color/brown(src) - new /obj/item/clothing/shoes/dress(src) +/obj/structure/closet/wardrobe/suit/WillContain() + return list( + /obj/item/clothing/pants/slacks, + /obj/item/clothing/pants/slacks/purple, + /obj/item/clothing/pants/slacks/tan, + /obj/item/clothing/pants/slacks/red, + /obj/item/clothing/pants/slacks/black, + /obj/item/clothing/shirt/button = 2, + /obj/item/clothing/suit/jacket/waistcoat/black, + /obj/item/clothing/neck/tie/long/red, + /obj/item/clothing/pants/slacks/black, + /obj/item/clothing/shirt/button, + /obj/item/clothing/costume/scratch, + /obj/item/clothing/shirt/button, + /obj/item/clothing/neck/tie/black, + /obj/item/clothing/suit/jacket/black, + /obj/item/clothing/suit/jacket/blue, + /obj/item/clothing/suit/jacket/purple, + /obj/item/clothing/costume/assistantformal, + /obj/item/clothing/costume/lawyer, + /obj/item/clothing/costume/lawyer_red, + /obj/item/clothing/costume/lawyer_bluesuit, + /obj/item/clothing/shoes/color/brown, + /obj/item/clothing/shoes/dress, + ) /obj/structure/closet/wardrobe/lawyer_black name = "internal affairs wardrobe" closet_appearance = /decl/closet_appearance/wardrobe/black -/obj/structure/closet/wardrobe/lawyer_black/Initialize() - . = ..() - new /obj/item/clothing/under/rank/internalaffairs(src) - new /obj/item/clothing/under/rank/internalaffairs(src) - new /obj/item/clothing/suit/storage/toggle/suit/black(src) - new /obj/item/clothing/suit/storage/toggle/suit/black(src) - new /obj/item/clothing/shoes/color/brown(src) - new /obj/item/clothing/shoes/color/brown(src) - new /obj/item/clothing/glasses/sunglasses/big(src) - new /obj/item/clothing/glasses/sunglasses/big(src) - new /obj/item/storage/briefcase(src) - new /obj/item/storage/briefcase(src) +/obj/structure/closet/wardrobe/lawyer_black/WillContain() + return list( + /obj/item/clothing/pants/slacks/black = 2, + /obj/item/clothing/shirt/button = 2, + /obj/item/clothing/neck/tie/long/red = 2, + /obj/item/clothing/suit/jacket/black = 2, + /obj/item/clothing/shoes/color/brown = 2, + /obj/item/clothing/glasses/sunglasses/big = 2, + /obj/item/briefcase = 2, + ) diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 583ab86ba300..3d4ff0479f34 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -1,25 +1,28 @@ /obj/structure/closet/crate name = "crate" desc = "A rectangular steel crate." + icon = 'icons/obj/closets/bases/crate.dmi' closet_appearance = /decl/closet_appearance/crate - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + atom_flags = ATOM_FLAG_CLIMBABLE setup = 0 storage_types = CLOSET_STORAGE_ITEMS var/rigged = 0 -/obj/structure/closet/crate/open() - if((atom_flags & ATOM_FLAG_OPEN_CONTAINER) && !opened && can_open()) +/obj/structure/closet/crate/open(mob/user) + if((atom_flags & ATOM_FLAG_CLIMBABLE) && LAZYLEN(climbers) && !opened && can_open(user)) object_shaken() . = ..() if(.) if(rigged) visible_message("There are wires attached to the lid of [src]...") for(var/obj/item/assembly_holder/H in src) + // This proc expects an /obj/item, and usr is never that, but it must be non-null for the code to function. + // TODO: Rewrite or refactor either this code or the proc itself to avoid that. H.process_activation(usr) for(var/obj/item/assembly/A in src) A.activate() -/obj/structure/closet/crate/examine(mob/user) +/obj/structure/closet/crate/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(rigged && opened) var/list/devices = list() @@ -27,34 +30,35 @@ devices += H for(var/obj/item/assembly/A in src) devices += A - to_chat(user,"There are some wires attached to the lid, connected to [english_list(devices)].") + . += "There are some wires attached to the lid, connected to [english_list(devices)]." -/obj/structure/closet/crate/attackby(obj/item/W, mob/user) +/obj/structure/closet/crate/attackby(obj/item/used_item, mob/user) if(opened) return ..() - else if(istype(W, /obj/item/stack/package_wrap)) - return - else if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = W + else if(istype(used_item, /obj/item/stack/package_wrap)) + return FALSE // let afterattack run + else if(istype(used_item, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = used_item if(rigged) to_chat(user, "[src] is already rigged!") - return + return TRUE if (C.use(1)) to_chat(user, "You rig [src].") rigged = 1 - return - else if(istype(W, /obj/item/assembly_holder) || istype(W, /obj/item/assembly)) - if(rigged) - if(!user.unEquip(W, src)) - return - to_chat(user, "You attach [W] to [src].") - return - else if(isWirecutter(W)) + return TRUE + return FALSE + else if((istype(used_item, /obj/item/assembly_holder) || istype(used_item, /obj/item/assembly)) && rigged) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, "You attach [used_item] to [src].") + return TRUE + else if(IS_WIRECUTTER(used_item)) if(rigged) to_chat(user, "You cut away the wiring.") playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) rigged = 0 - return + return TRUE + return FALSE else return ..() @@ -74,9 +78,19 @@ desc = "A rectangular plastic crate." closet_appearance = /decl/closet_appearance/crate/plastic +/obj/structure/closet/crate/plastic/rations //For use in the escape shuttle + name = "emergency rations" + desc = "A crate of emergency rations." + +/obj/structure/closet/crate/plastic/rations/WillContain() + return list( + /obj/random/mre = 6, + /obj/item/chems/drinks/cans/waterbottle = 12 + ) + /obj/structure/closet/crate/internals name = "internals crate" - desc = "A internals crate." + desc = "An internals crate." /obj/structure/closet/crate/internals/fuel name = "\improper Fuel tank crate" @@ -89,6 +103,7 @@ name = "trash cart" desc = "A heavy, metal trashcart with wheels." closet_appearance = /decl/closet_appearance/cart/trash + icon = 'icons/obj/closets/bases/cart.dmi' /obj/structure/closet/crate/medical name = "medical crate" @@ -147,22 +162,15 @@ /obj/structure/closet/crate/freezer/ProcessAtomTemperature() return PROCESS_KILL -/obj/structure/closet/crate/freezer/rations //For use in the escape shuttle - name = "emergency rations" - desc = "A crate of emergency rations." - -/obj/structure/closet/crate/freezer/rations/WillContain() - return list(/obj/random/mre = 6, /obj/item/chems/food/drinks/cans/waterbottle = 12) - /obj/structure/closet/crate/freezer/meat name = "meat crate" desc = "A crate of meat." /obj/structure/closet/crate/freezer/meat/WillContain() return list( - /obj/item/chems/food/snacks/meat/beef = 4, - /obj/item/chems/food/snacks/meat/syntiflesh = 4, - /obj/item/chems/food/snacks/fish = 4 + /obj/item/food/butchery/meat/beef = 4, + /obj/item/food/butchery/meat/syntiflesh = 4, + /obj/item/food/butchery/meat/fish = 4 ) /obj/structure/closet/crate/bin @@ -171,7 +179,7 @@ /obj/structure/closet/crate/radiation name = "radioactive crate" - desc = "A leadlined crate with a radiation sign on it." + desc = "A lead-lined crate with a radiation sign on it." closet_appearance = /decl/closet_appearance/crate/radiation /obj/structure/closet/crate/radiation_gear @@ -189,13 +197,13 @@ /obj/structure/closet/crate/secure/explosives name = "explosives crate" - desc = "A secure exploxives crate." + desc = "A secure explosives crate." closet_appearance = /decl/closet_appearance/crate/secure/hazard /obj/structure/closet/crate/secure/shuttle name = "storage compartment" desc = "A secure storage compartment bolted to the floor, to secure loose objects on Zero-G flights." - anchored = 1 + anchored = TRUE closet_appearance = /decl/closet_appearance/crate/secure/shuttle /obj/structure/closet/crate/secure/gear @@ -214,6 +222,7 @@ storage_capacity = 2 * MOB_SIZE_LARGE storage_types = CLOSET_STORAGE_ITEMS|CLOSET_STORAGE_STRUCTURES closet_appearance = /decl/closet_appearance/large_crate + icon = 'icons/obj/closets/bases/large_crate.dmi' /obj/structure/closet/crate/large/hydroponics closet_appearance = /decl/closet_appearance/large_crate/hydroponics @@ -225,9 +234,7 @@ storage_capacity = 2 * MOB_SIZE_LARGE storage_types = CLOSET_STORAGE_ITEMS|CLOSET_STORAGE_STRUCTURES - -/obj/structure/closet/crate/secure/large/supermatter - closet_appearance = /decl/closet_appearance/large_crate/secure/hazard + icon = 'icons/obj/closets/bases/large_crate.dmi' //fluff variant /obj/structure/closet/crate/secure/large/reinforced @@ -241,13 +248,26 @@ /obj/structure/closet/crate/hydroponics/prespawned/WillContain() return list( /obj/item/chems/spray/plantbgone = 2, - /obj/item/minihoe = 2, - /obj/item/storage/plants = 2, - /obj/item/hatchet = 2, + /obj/item/tool/hoe/mini = 2, + /obj/item/plant_satchel = 2, + /obj/item/tool/axe/hatchet = 2, /obj/item/wirecutters/clippers = 2, /obj/item/scanner/plant = 2 ) +/obj/structure/closet/crate/hydroponics/exotic + name = "exotic seeds crate" + desc = "All you need to destroy that pesky planet." + +/obj/structure/closet/crate/hydroponics/exotic/WillContain() + return list( + /obj/item/seeds/random = 6, + /obj/item/seeds/ambrosiavulgarisseed = 2, + /obj/item/seeds/kudzuseed, + /obj/item/seeds/libertymycelium, + /obj/item/seeds/reishimycelium + ) + /obj/structure/closet/crate/secure/biohazard name = "biohazard cart" desc = "A heavy cart with extensive sealing. You shouldn't eat things you find in it." @@ -257,11 +277,13 @@ closet_appearance = /decl/closet_appearance/cart/biohazard storage_capacity = 2 * MOB_SIZE_LARGE storage_types = CLOSET_STORAGE_ITEMS|CLOSET_STORAGE_MOBS|CLOSET_STORAGE_STRUCTURES + movable_flags = MOVABLE_FLAG_WHEELED + icon = 'icons/obj/closets/bases/cart.dmi' /obj/structure/closet/crate/secure/biohazard/blanks/WillContain() return list(/obj/structure/closet/body_bag/cryobag/blank) -/obj/structure/closet/crate/secure/biohazard/blanks/can_close() +/obj/structure/closet/crate/secure/biohazard/blanks/can_close(mob/user) for(var/obj/structure/closet/closet in get_turf(src)) if(closet != src && !(istype(closet, /obj/structure/closet/body_bag/cryobag))) return 0 @@ -272,6 +294,7 @@ desc = "A heavy cart used for organ disposal with markings indicating the things inside are probably gross." req_access = list(access_surgery) closet_appearance = /decl/closet_appearance/cart/biohazard/alt + movable_flags = MOVABLE_FLAG_WHEELED /obj/structure/closet/crate/paper_refill name = "paper refill crate" @@ -286,4 +309,42 @@ closet_appearance = /decl/closet_appearance/crate/radiation /obj/structure/closet/crate/uranium/WillContain() - return list(/obj/item/stack/material/uranium/ten = 5) \ No newline at end of file + return list(/obj/item/stack/material/puck/mapped/uranium/ten = 5) + +/obj/structure/closet/crate/chest + name = "chest" + desc = "A compact, hinged chest." + icon = 'icons/obj/closets/bases/chest.dmi' + open_sound = 'sound/effects/storage/briefcase.ogg' + close_sound = 'sound/effects/storage/briefcase.ogg' + closet_appearance = /decl/closet_appearance/crate/chest + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + var/icon/overlay_icon = 'icons/obj/closets/bases/chest.dmi' + // TODO: Rework chest crafting so that this can use reinf_material instead. + /// The material used for the opacity and color of the trim overlay. + var/decl/material/overlay_material = /decl/material/solid/metal/iron + +/obj/structure/closet/crate/chest/Initialize() + if(ispath(overlay_material)) + overlay_material = GET_DECL(overlay_material) + . = ..() + // icon update is already queued in parent because of closet appearance + +/obj/structure/closet/crate/chest/update_material_desc(override_desc) + ..() + if(istype(overlay_material)) + desc = "[desc] It has a trim made of [overlay_material.solid_name]." + +/obj/structure/closet/crate/chest/on_update_icon() + . = ..() + if(istype(overlay_material)) + var/overlay_state = opened ? "open-overlay" : "base-overlay" + var/image/trim = overlay_image(overlay_icon, overlay_state, overlay_material.color, RESET_COLOR|RESET_ALPHA) + trim.alpha = clamp((50 + overlay_material.opacity * 255), 0, 255) + add_overlay(trim) + +/obj/structure/closet/crate/chest/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm index cc39743ba6fa..2ed4e74f0b4e 100644 --- a/code/game/objects/structures/crates_lockers/largecrate.dm +++ b/code/game/objects/structures/crates_lockers/largecrate.dm @@ -3,8 +3,9 @@ desc = "A hefty wooden crate." icon = 'icons/obj/shipping_crates.dmi' icon_state = "densecrate" - density = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + density = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + material = /decl/material/solid/organic/wood/oak /obj/structure/largecrate/Initialize() . = ..() @@ -14,64 +15,37 @@ I.forceMove(src) /obj/structure/largecrate/attack_hand(mob/user) - to_chat(user, "You need a crowbar to pry this open!") - return - -/obj/structure/largecrate/attackby(obj/item/W, mob/user) - if(isCrowbar(W)) - new /obj/item/stack/material/wood(src) - var/turf/T = get_turf(src) - for(var/atom/movable/AM in contents) - if(AM.simulated) AM.forceMove(T) - user.visible_message("[user] pries \the [src] open.", \ - "You pry open \the [src].", \ - "You hear splitting wood.") - qdel(src) - else - return attack_hand(user) - -/obj/structure/largecrate/mule - name = "MULE crate" + if(user.check_intent(I_FLAG_HARM)) + return ..() + to_chat(user, SPAN_WARNING("You need a crowbar to pry this open!")) + return TRUE + +/obj/structure/largecrate/attackby(obj/item/used_item, mob/user) + if(IS_CROWBAR(used_item)) + user.visible_message( + SPAN_NOTICE("\The [user] pries \the [src] open."), + SPAN_NOTICE("You pry open \the [src]."), + SPAN_NOTICE("You hear splitting wood.") + ) + physically_destroyed() + return TRUE + return attack_hand_with_interaction_checks(user) /obj/structure/largecrate/animal - icon_state = "mulecrate" - var/held_count = 1 - var/held_type + name = "animal crate" + var/animal_type /obj/structure/largecrate/animal/Initialize() . = ..() - if(held_type) - for(var/i = 1;i<=held_count;i++) - new held_type(src) - -/obj/structure/largecrate/animal/mulebot - name = "Mulebot crate" - held_type = /mob/living/bot/mulebot - -/obj/structure/largecrate/animal/corgi - name = "corgi carrier" - held_type = /mob/living/simple_animal/corgi - -/obj/structure/largecrate/animal/cow - name = "cow crate" - held_type = /mob/living/simple_animal/cow - -/obj/structure/largecrate/animal/goat - name = "goat crate" - held_type = /mob/living/simple_animal/hostile/retaliate/goat - -/obj/structure/largecrate/animal/goose - name = "goose containment unit" - held_type = /mob/living/simple_animal/hostile/retaliate/goose + if(animal_type) + var/mob/critter = new animal_type(src) + name = "[name] ([critter.name])" /obj/structure/largecrate/animal/cat - name = "cat carrier" - held_type = /mob/living/simple_animal/cat + animal_type = /mob/living/simple_animal/passive/cat -/obj/structure/largecrate/animal/cat/bones - held_type = /mob/living/simple_animal/cat/fluff/bones +/obj/structure/largecrate/animal/cow + animal_type = /mob/living/simple_animal/cow -/obj/structure/largecrate/animal/chick - name = "chicken crate" - held_count = 5 - held_type = /mob/living/simple_animal/chick +/obj/structure/largecrate/animal/corgi + animal_type = /mob/living/simple_animal/corgi diff --git a/code/game/objects/structures/crates_lockers/med_crate.dm b/code/game/objects/structures/crates_lockers/med_crate.dm index 1012321c1e3c..7d013ed2ced1 100644 --- a/code/game/objects/structures/crates_lockers/med_crate.dm +++ b/code/game/objects/structures/crates_lockers/med_crate.dm @@ -6,10 +6,11 @@ /obj/structure/closet/crate/med_crate/trauma/WillContain() return list( /obj/item/stack/medical/splint = 2, - /obj/item/stack/medical/advanced/bruise_pack = 10, + /obj/item/stack/medical/bandage/advanced = 10, /obj/item/chems/pill/sugariron = 6, - /obj/item/storage/pill_bottle/painkillers = 2, - /obj/item/storage/pill_bottle/adrenaline + /obj/item/pill_bottle/painkillers, + /obj/item/pill_bottle/strong_painkillers, + /obj/item/pill_bottle/stabilizer ) /obj/structure/closet/crate/med_crate/burn @@ -20,10 +21,11 @@ /obj/structure/closet/crate/med_crate/burn/WillContain() return list( /obj/item/defibrillator/loaded, - /obj/item/stack/medical/advanced/ointment = 10, - /obj/item/storage/pill_bottle/burn_meds, - /obj/item/storage/pill_bottle/painkillers = 2, - /obj/item/storage/pill_bottle/antibiotics + /obj/item/stack/medical/ointment/advanced = 10, + /obj/item/pill_bottle/burn_meds, + /obj/item/pill_bottle/painkillers, + /obj/item/pill_bottle/strong_painkillers, + /obj/item/pill_bottle/antibiotics ) /obj/structure/closet/crate/med_crate/oxyloss @@ -33,9 +35,9 @@ /obj/structure/closet/crate/med_crate/oxyloss/WillContain() return list( - /obj/item/scanner/health = 2, - /obj/item/storage/pill_bottle/oxygen = 2, - /obj/item/storage/pill_bottle/adrenaline + /obj/item/scanner/breath = 2, + /obj/item/pill_bottle/oxygen = 2, + /obj/item/pill_bottle/stabilizer ) /obj/structure/closet/crate/med_crate/toxin name = "\improper Toxin crate" @@ -44,7 +46,7 @@ /obj/structure/closet/crate/med_crate/toxin/WillContain() return list( - /obj/item/storage/firstaid/surgery, - /obj/item/storage/pill_bottle/antitoxins = 2, + /obj/item/firstaid/surgery, + /obj/item/pill_bottle/antitoxins = 2, /obj/item/chems/pill/antirads = 12 ) diff --git a/code/game/objects/structures/crematorium.dm b/code/game/objects/structures/crematorium.dm new file mode 100644 index 000000000000..bb05961a107a --- /dev/null +++ b/code/game/objects/structures/crematorium.dm @@ -0,0 +1,241 @@ +/obj/structure/crematorium + name = "crematorium" + desc = "A human incinerator. Works well on barbecue nights." + icon = 'icons/obj/structures/crematorium.dmi' + icon_state = "crematorium_closed" + density = TRUE + anchored = TRUE + + var/cremating = FALSE + var/locked = FALSE + var/open = FALSE + + var/obj/structure/crematorium_tray/connected_tray + + var/id_tag + +/obj/structure/crematorium/get_mechanics_info() + return "[..()]
              Can be labeled once with a hand labeler." + +/obj/structure/crematorium/Initialize(ml, _mat, _reinf_mat) + . = ..() + connected_tray = new /obj/structure/crematorium_tray(src) + connected_tray.connected_crematorium = src + get_or_create_extension(src, /datum/extension/labels/single) + +/obj/structure/crematorium/Destroy() + if(!QDELETED(connected_tray)) + QDEL_NULL(connected_tray) + return ..() + +/obj/structure/crematorium/on_update_icon() + ..() + if(cremating) + icon_state = "crematorium_active" + else if (open) + icon_state = "crematorium_open" + else if (contents.len > 1) + icon_state = "crematorium_filled" + else + icon_state = "crematorium_closed" + +/obj/structure/crematorium/explosion_act(severity) + ..() + if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) + physically_destroyed() + +/obj/structure/crematorium/proc/open() + if(cremating || locked || open) + return + + if(!connected_tray) + return + + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + var/turf/T = get_step(src, dir) + connected_tray.forceMove(T) + connected_tray.set_dir(dir) + for(var/atom/movable/A in src) + A.forceMove(get_turf(connected_tray)) + + open = TRUE + update_icon() + +/obj/structure/crematorium/proc/close() + if(!open) + return + + if(!connected_tray) + return + + for(var/atom/movable/A in get_turf(connected_tray)) + if(A.simulated && !A.anchored && A != connected_tray) + A.forceMove(src) + + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + connected_tray.forceMove(src) + + open = FALSE + update_icon() + +/obj/structure/crematorium/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(locked) + to_chat(user, SPAN_WARNING("It's currently locked.")) + return TRUE + if(open) + close() + else + open() + return TRUE + +/obj/structure/crematorium/attack_robot(mob/user) + return attack_hand_with_interaction_checks(user) + +/obj/structure/crematorium/relaymove(mob/user) + if(user.incapacitated() || locked) + return + + open() + +/obj/structure/crematorium/proc/cremate(atom/A, mob/user) + if(cremating || open) + return //don't let you cremate something twice or w/e + + if(contents.len <= 1) + audible_message(SPAN_WARNING("You hear a hollow crackle."), 1) + return + + else + if(length(search_contents_for(/obj/item/disk/nuclear))) + to_chat(user, "The button's status indicator flashes yellow, indicating that something important is inside the crematorium, and must be removed.") + return + + audible_message("You hear a roar as \the [src] activates.", 1) + + cremating = TRUE + locked = TRUE + update_icon() + + for(var/mob/living/M in contents) + on_cremate_mob(A, M) + + for(var/obj/O in contents) //obj instead of obj/item so that bodybags and ashes get destroyed. We dont want tons and tons of ash piling up + if(!istype(O, connected_tray)) + qdel(O) + + new /obj/effect/decal/cleanable/ash(src) + sleep(30) + cremating = initial(cremating) + locked = initial(locked) + playsound(src, 'sound/effects/spray.ogg', 50, 1) + update_icon() + +// This proc sucks. Actually, all of crematorium code just sucks. +// TODO: REWRITE OR REMOVE +/obj/structure/crematorium/proc/on_cremate_mob(atom/cause, mob/living/victim) + admin_attack_log(cause, victim, "Began cremating their victim.", "Has begun being cremated.", "began cremating") + if(isliving(victim)) + for(var/I, I < 60, I++) + + if(victim.stat >= UNCONSCIOUS || !(victim in contents)) //In case we die or are removed at any point. + cremating = 0 + update_icon() + break + + sleep(0.5 SECONDS) + + if(QDELETED(src)) + return FALSE + + if(prob(40)) + var/desperation = rand(1,5) + switch(desperation) //This is messy. A better solution would probably be to make more sounds, but... + if(1) + playsound(loc, 'sound/weapons/genhit.ogg', 45, 1) + shake_animation(2) + playsound(loc, 'sound/weapons/genhit.ogg', 45, 1) + if(2) + playsound(loc, 'sound/effects/grillehit.ogg', 45, 1) + shake_animation(3) + playsound(loc, 'sound/effects/grillehit.ogg', 45, 1) + if(3) + playsound(src, 'sound/effects/bang.ogg', 45, 1) + if(prob(50)) + playsound(src, 'sound/effects/bang.ogg', 45, 1) + shake_animation() + else + shake_animation(5) + if(4) + playsound(src, 'sound/effects/clang.ogg', 45, 1) + shake_animation(5) + if(5) + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + if(prob(50)) + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + shake_animation(9) + else + shake_animation() + + if (!victim.stat) + victim.audible_message("[victim]'s screams cease, as does any movement within \the [src]. All that remains is a dull, empty silence.") + + admin_attack_log(victim, cause, "Cremated their victim.", "Was cremated.", "cremated") + victim.dust() + return TRUE + +/obj/structure/crematorium_tray + name = "crematorium tray" + desc = "Apply body before burning." + icon = 'icons/obj/structures/crematorium.dmi' + icon_state = "crematorium_tray" + density = TRUE + anchored = TRUE + throwpass = TRUE + layer = BELOW_OBJ_LAYER + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED | OBJ_FLAG_NOFALL + + var/obj/structure/crematorium/connected_crematorium + +/obj/structure/crematorium_tray/Destroy() + if(!QDELETED(connected_crematorium)) + QDEL_NULL(connected_crematorium) + return ..() + +/obj/structure/crematorium_tray/attack_hand(mob/user) + return connected_crematorium.attack_hand_with_interaction_checks(user) || ..() + +/obj/structure/crematorium_tray/attack_robot(mob/user) + return attack_hand_with_interaction_checks(user) + +/obj/structure/crematorium_tray/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && (ismob(dropping) || istype(dropping, /obj/structure/closet/body_bag))) + var/atom/movable/AM = dropping + if(!AM.anchored) + AM.forceMove(loc) + if(user != dropping) + user.visible_message(SPAN_NOTICE("\The [user] stuffs \the [dropping] onto \the [src]!")) + return TRUE + +/obj/machinery/button/crematorium + name = "crematorium igniter" + desc = "Burn baby burn!" + icon = 'icons/obj/power.dmi' + icon_state = "crematorium_switch" + initial_access = list(access_crematorium) + +/obj/machinery/button/crematorium/on_update_icon() + return + +/obj/machinery/button/crematorium/activate(mob/user) + if(operating) + return + + for(var/obj/structure/crematorium/C in range()) + if (C.id_tag == id_tag || isnull(C.id_tag)) + if (!C.cremating) + C.cremate(user) + + ..() // sets operating for click cooldown. diff --git a/code/game/objects/structures/curtain_decls.dm b/code/game/objects/structures/curtain_decls.dm new file mode 100644 index 000000000000..fa5524530c01 --- /dev/null +++ b/code/game/objects/structures/curtain_decls.dm @@ -0,0 +1,66 @@ +// +// Curtain types declaration +// +/decl/curtain_kind + var/name = "curtain" + var/color = COLOR_WHITE + var/alpha = 255 + var/material_key = /decl/material/solid/organic/plastic + +/decl/curtain_kind/proc/make_item(var/loc) + var/obj/item/curtain/C = new(loc) + C.set_curtain_kind(src) + return C + +/decl/curtain_kind/proc/make_structure(var/loc, var/dir, var/opened = FALSE) + var/obj/structure/curtain/C = new(loc) + C.set_curtain_kind(src) + C.set_dir(dir) + C.set_opacity(opened) + return C + +//Cloth curtains +/decl/curtain_kind/cloth + material_key = /decl/material/solid/organic/cloth + +/decl/curtain_kind/cloth/bed + name = "bed curtain" + color = "#854636" + +/decl/curtain_kind/cloth/black + name = "black curtain" + color = "#222222" + +/decl/curtain_kind/cloth/bar + name = "bar curtain" + color = "#854636" + +//Plastic curtains +/decl/curtain_kind/plastic + name = "plastic curtain" + color = "#b8f5e3" + material_key = /decl/material/solid/organic/plastic + +/decl/curtain_kind/plastic/medical + alpha = 200 + +/decl/curtain_kind/plastic/privacy + name = "privacy curtain" + +/decl/curtain_kind/plastic/shower + name = "shower curtain" + color = "#acd1e9" + alpha = 200 + +/decl/curtain_kind/plastic/shower/engineering + color = "#ffa500" + +/decl/curtain_kind/plastic/shower/security + color = COLOR_DARK_RED + +/decl/curtain_kind/plastic/shower/medical + color = COLOR_CYAN + +/decl/curtain_kind/plastic/canteen + name = "privacy curtain" + color = COLOR_BLUE_GRAY diff --git a/code/game/objects/structures/curtains.dm b/code/game/objects/structures/curtains.dm index 4fe9c869305f..e15b1fc302c5 100644 --- a/code/game/objects/structures/curtains.dm +++ b/code/game/objects/structures/curtains.dm @@ -1,24 +1,40 @@ /obj/item/curtain name = "rolled curtain" - desc = "A rolled curtains." + desc = "A rolled-up curtain." icon = 'icons/obj/structures/curtain.dmi' icon_state = "curtain_rolled" - force = 3 //just plastic + _base_attack_force = 3 //just plastic w_class = ITEM_SIZE_HUGE //curtains, yeap - var/obj/structure/curtain/holder = /obj/structure/curtain + var/curtain_kind_path = /decl/curtain_kind //path to decl containing the curtain's details -/obj/item/curtain/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - if(!holder) - return +/obj/item/curtain/Initialize(ml, material_key) + . = ..() + if(curtain_kind_path) + set_curtain_kind(GET_DECL(curtain_kind_path)) + +/obj/item/curtain/proc/set_curtain_kind(var/decl/curtain_kind/kind) + + if(!istype(kind)) + CRASH("Invalid curtain kind supplied to set_curtain_kind on [type]: [kind || "NULL"]") + + curtain_kind_path = kind.type + SetName("rolled [kind.name]") + set_material(kind.material_key) //set health and etc + matter = atom_info_repository.get_matter_for(/obj/structure/curtain, kind.material_key) + update_icon() + +/obj/item/curtain/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) + if(!curtain_kind_path) + return TRUE if(!isturf(loc)) to_chat(user, SPAN_DANGER("You cannot install \the [src] from your hands.")) - return + return TRUE - if(is_space_turf(loc)) + if(isspaceturf(loc)) to_chat(user, SPAN_DANGER("You cannot install \the [src] in space.")) - return + return TRUE user.visible_message( SPAN_NOTICE("\The [user] begins installing \the [src]."), @@ -26,19 +42,29 @@ playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) if(!do_after(user, 4 SECONDS, src)) - return + return TRUE if(QDELETED(src)) - return + return TRUE - var/obj/structure/curtain/C = new holder(loc) + var/decl/curtain_kind/kind = GET_DECL(curtain_kind_path) + var/obj/structure/curtain/C = kind.make_structure(loc, dir) transfer_fingerprints_to(C) - C.SetName(replacetext(name, "rolled", "")) - C.color = color qdel(src) + return TRUE else - ..() + return ..() +/obj/item/curtain/on_update_icon() + . = ..() + if(curtain_kind_path) + var/decl/curtain_kind/kind = GET_DECL(curtain_kind_path) + alpha = kind.alpha + set_color(kind.color) + +// +// Curtain Structure +// /obj/structure/curtain name = "curtain" icon = 'icons/obj/structures/curtain.dmi' @@ -46,126 +72,161 @@ layer = ABOVE_WINDOW_LAYER opacity = TRUE density = FALSE - var/obj/item/curtain/holder = /obj/item/curtain + anchored = TRUE + var/curtain_kind_path = /decl/curtain_kind /obj/structure/curtain/open icon_state = "open" layer = ABOVE_HUMAN_LAYER opacity = FALSE -/obj/structure/curtain/Initialize() - . = ..() +/obj/structure/curtain/Initialize(ml, _mat, _reinf_mat) + . = ..(ml) set_extension(src, /datum/extension/turf_hand) + if(curtain_kind_path) + set_curtain_kind(GET_DECL(curtain_kind_path)) + +/obj/structure/curtain/proc/set_curtain_kind(var/decl/curtain_kind/kind) + + if(!istype(kind)) + CRASH("Invalid curtain kind supplied to set_curtain_kind on [type]: [kind || "NULL"]") + + SetName(kind.name) + curtain_kind_path = kind.type + material = GET_DECL(kind.material_key) + create_matter() + update_icon() /obj/structure/curtain/bullet_act(obj/item/projectile/P, def_zone) if(!P.nodamage) - visible_message(SPAN_WARNING("[P] tears [src] down!")) + visible_message(SPAN_WARNING("[P] tears \the [src] down!")) qdel(src) else ..(P, def_zone) /obj/structure/curtain/attack_hand(mob/user) - toggle() - ..() - -/obj/structure/curtain/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - if(!holder) - return + if(user.check_dexterity(DEXTERITY_HOLD_ITEM)) + toggle() + return TRUE + return ..() +/obj/structure/curtain/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item) && curtain_kind_path) user.visible_message( SPAN_NOTICE("\The [user] begins uninstalling \the [src]."), SPAN_NOTICE("You begin uninstalling \the [src].")) playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) if(!do_after(user, 4 SECONDS, src)) - return + return TRUE if(QDELETED(src)) - return + return TRUE - var/obj/item/curtain/C = new holder(loc) + var/decl/curtain_kind/kind = GET_DECL(curtain_kind_path) + var/obj/item/curtain/C = kind.make_item(loc) transfer_fingerprints_to(C) - C.SetName("rolled [name]") - C.color = color qdel(src) + return TRUE else - ..() + return ..() /obj/structure/curtain/proc/toggle() playsound(src, 'sound/effects/curtain.ogg', 15, 1, -5) set_opacity(!opacity) - if(opacity) - icon_state = "closed" - layer = ABOVE_HUMAN_LAYER - else - icon_state = "open" - layer = ABOVE_WINDOW_LAYER -// Normal subtypes -/obj/structure/curtain/bed - name = "bed curtain" - color = "#854636" +/obj/structure/curtain/set_opacity() + . = ..() + if(.) + update_icon() +/obj/structure/curtain/on_update_icon() + ..() + icon_state = opacity ? "closed" : "open" + layer = opacity ? ABOVE_HUMAN_LAYER : ABOVE_WINDOW_LAYER + if(curtain_kind_path) + var/decl/curtain_kind/kind = GET_DECL(curtain_kind_path) + alpha = kind.alpha + set_color(kind.color) + +// Subtypes for mapping/spawning below: +// - Item subtypes +/obj/item/curtain/bed + curtain_kind_path = /decl/curtain_kind/cloth/bed +/obj/item/curtain/black + curtain_kind_path = /decl/curtain_kind/cloth/black +/obj/item/curtain/bar + curtain_kind_path = /decl/curtain_kind/cloth/bar +/obj/item/curtain/medical + curtain_kind_path = /decl/curtain_kind/plastic/medical +/obj/item/curtain/privacy + curtain_kind_path = /decl/curtain_kind/plastic/privacy +/obj/item/curtain/shower + curtain_kind_path = /decl/curtain_kind/plastic/shower +/obj/item/curtain/shower/engineering + curtain_kind_path = /decl/curtain_kind/plastic/shower/engineering +/obj/item/curtain/shower/security + curtain_kind_path = /decl/curtain_kind/plastic/shower/security +/obj/item/curtain/shower/medical + curtain_kind_path = /decl/curtain_kind/plastic/shower/medical +/obj/item/curtain/canteen + curtain_kind_path = /decl/curtain_kind/plastic/canteen + +// - Closed subtypes +/obj/structure/curtain/bed + curtain_kind_path = /decl/curtain_kind/cloth/bed + color = /decl/curtain_kind/cloth/bed::color /obj/structure/curtain/black - name = "black curtain" - color = "#222222" - -/obj/structure/curtain/medical - name = "plastic curtain" - color = "#b8f5e3" - alpha = 200 - + curtain_kind_path = /decl/curtain_kind/cloth/black + color = /decl/curtain_kind/cloth/black::color /obj/structure/curtain/bar - name = "bar curtain" - color = "#854636" - + curtain_kind_path = /decl/curtain_kind/cloth/bar + color = /decl/curtain_kind/cloth/bar::color +/obj/structure/curtain/medical + curtain_kind_path = /decl/curtain_kind/plastic/medical + color = /decl/curtain_kind/plastic/medical::color + alpha = /decl/curtain_kind/plastic/medical::alpha /obj/structure/curtain/privacy - name = "privacy curtain" - color = "#b8f5e3" - + curtain_kind_path = /decl/curtain_kind/plastic/privacy + color = /decl/curtain_kind/plastic/privacy::color /obj/structure/curtain/shower - name = "shower curtain" - color = "#acd1e9" - alpha = 200 - + curtain_kind_path = /decl/curtain_kind/plastic/shower + color = /decl/curtain_kind/plastic/shower::color + alpha = /decl/curtain_kind/plastic/shower::alpha /obj/structure/curtain/canteen - name = "privacy curtain" - color = COLOR_BLUE_GRAY + curtain_kind_path = /decl/curtain_kind/plastic/canteen + color = /decl/curtain_kind/plastic/canteen::color -// Open subtypes +// - Open subtypes /obj/structure/curtain/open/bed - name = "bed curtain" - color = "#854636" - + curtain_kind_path = /decl/curtain_kind/cloth/bed + color = /decl/curtain_kind/cloth/bed::color /obj/structure/curtain/open/black - name = "black curtain" - color = "#222222" - + curtain_kind_path = /decl/curtain_kind/cloth/black + color = /decl/curtain_kind/cloth/black::color /obj/structure/curtain/open/medical - name = "plastic curtain" - color = "#b8f5e3" - alpha = 200 - + curtain_kind_path = /decl/curtain_kind/plastic/medical + color = /decl/curtain_kind/plastic/medical::color + alpha = /decl/curtain_kind/plastic/medical::alpha /obj/structure/curtain/open/bar - name = "bar curtain" - color = "#854636" - + curtain_kind_path = /decl/curtain_kind/cloth/bar + color = /decl/curtain_kind/cloth/bar::color /obj/structure/curtain/open/privacy - name = "privacy curtain" - color = "#b8f5e3" - + curtain_kind_path = /decl/curtain_kind/plastic/privacy + color = /decl/curtain_kind/plastic/privacy::color /obj/structure/curtain/open/shower - name = "shower curtain" - color = "#acd1e9" - alpha = 200 - + curtain_kind_path = /decl/curtain_kind/plastic/shower + color = /decl/curtain_kind/plastic/shower::color + alpha = /decl/curtain_kind/plastic/shower::alpha /obj/structure/curtain/open/canteen - name = "privacy curtain" - color = COLOR_BLUE_GRAY - + curtain_kind_path = /decl/curtain_kind/plastic/canteen + color = /decl/curtain_kind/plastic/canteen::color /obj/structure/curtain/open/shower/engineering - color = "#ffa500" - + curtain_kind_path = /decl/curtain_kind/plastic/shower/engineering + color = /decl/curtain_kind/plastic/shower/engineering::color /obj/structure/curtain/open/shower/security - color = "#aa0000" + curtain_kind_path = /decl/curtain_kind/plastic/shower/security + color = /decl/curtain_kind/plastic/shower/security::color +/obj/structure/curtain/open/shower/medical + curtain_kind_path = /decl/curtain_kind/plastic/shower/medical + color = /decl/curtain_kind/plastic/shower/medical::color diff --git a/code/game/objects/structures/decorations/_decoration.dm b/code/game/objects/structures/decorations/_decoration.dm new file mode 100644 index 000000000000..9edd54876340 --- /dev/null +++ b/code/game/objects/structures/decorations/_decoration.dm @@ -0,0 +1,9 @@ +/obj/structure/decoration + abstract_type = /obj/structure/decoration + density = TRUE + opacity = FALSE + anchored = TRUE + material = /decl/material/solid/stone/marble + material_alteration = MAT_FLAG_ALTERATION_ALL + color = /decl/material/solid/stone/marble::color + icon_state = ICON_STATE_WORLD diff --git a/code/game/objects/structures/decorations/gargoyle.dm b/code/game/objects/structures/decorations/gargoyle.dm new file mode 100644 index 000000000000..bee98aaee713 --- /dev/null +++ b/code/game/objects/structures/decorations/gargoyle.dm @@ -0,0 +1,20 @@ +/obj/structure/decoration/gargoyle + name = "gargoyle" + desc = "A leering statue of a monstrous gargoyle." + icon = 'icons/obj/structures/decorations/gargoyle.dmi' + material = /decl/material/solid/stone/basalt + color = /decl/material/solid/stone/basalt::color + +/obj/structure/decoration/gargoyle/plinth + icon = 'icons/obj/structures/decorations/gargoyle_plinth.dmi' + +/obj/structure/decoration/gargoyle/standing + icon = 'icons/obj/structures/decorations/gargoyle_standing.dmi' + +/obj/structure/decoration/gargoyle/random/Initialize(ml, _mat, _reinf_mat) + icon = pick(list( + 'icons/obj/structures/decorations/gargoyle.dmi', + 'icons/obj/structures/decorations/gargoyle_plinth.dmi', + 'icons/obj/structures/decorations/gargoyle_standing.dmi' + )) + . = ..() diff --git a/code/game/objects/structures/defensive_barrier.dm b/code/game/objects/structures/defensive_barrier.dm index 5fc96ae94f80..889d3a94bdff 100644 --- a/code/game/objects/structures/defensive_barrier.dm +++ b/code/game/objects/structures/defensive_barrier.dm @@ -7,36 +7,25 @@ throwpass = TRUE anchored = TRUE atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_CHECKS_BORDER - can_buckle = TRUE + can_buckle = TRUE // TODO: Is it actually... intended that you can buckle stuff to this? material = /decl/material/solid/metal/steel material_alteration = MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_NAME - maxhealth = 200 + max_health = 200 + hitsound = 'sound/effects/bang.ogg' var/secured /obj/structure/defensive_barrier/Initialize() . = ..() update_icon() - GLOB.dir_set_event.register(src, src, .proc/update_layers) - -/obj/structure/defensive_barrier/show_examined_damage(mob/user, perc) - if(maxhealth == -1) - return - else if(perc >= 1) - to_chat(user, SPAN_NOTICE("It is undamaged.")) - else if(perc < 0.7) - to_chat(user, SPAN_WARNING("It has a few small dents.")) - else if(perc < 0.35) - to_chat(user, SPAN_WARNING("It has several large dents.")) - else - to_chat(user, SPAN_DANGER("It is on the verge of breaking apart!")) + events_repository.register(/decl/observ/dir_set, src, src, PROC_REF(update_layers)) -/obj/structure/defensive_barrier/physically_destroyed() +/obj/structure/defensive_barrier/physically_destroyed(var/skip_qdel) visible_message(SPAN_DANGER("\The [src] was destroyed!")) playsound(src, 'sound/effects/clang.ogg', 100, 1) . = ..() /obj/structure/defensive_barrier/Destroy() - GLOB.dir_set_event.unregister(src, src, .proc/update_layers) + events_repository.unregister(/decl/observ/dir_set, src, src, PROC_REF(update_layers)) . = ..() /obj/structure/defensive_barrier/proc/update_layers() @@ -66,7 +55,7 @@ var/obj/item/projectile/proj = mover if(Adjacent(proj?.firer)) return TRUE - if(mover.dir != GLOB.reverse_dir[dir]) + if(mover.dir != global.reverse_dir[dir]) return TRUE if(get_dist(proj.starting, loc) <= 1)//allows to fire from 1 tile away of barrier return TRUE @@ -102,8 +91,8 @@ visible_message(SPAN_NOTICE("\The [user] packs up \the [src].")) var/obj/item/defensive_barrier/B = new(get_turf(user), material?.type) playsound(src, 'sound/items/Deconstruct.ogg', 100, 1) - B.stored_health = health - B.stored_max_health = maxhealth + B.stored_health = current_health + B.stored_max_health = get_max_health() B.add_fingerprint(user) qdel(src) return TRUE @@ -111,14 +100,17 @@ /obj/structure/defensive_barrier/CtrlClick(mob/living/user) try_pack_up(user) -/obj/structure/defensive_barrier/attack_hand(mob/living/carbon/human/user) +/obj/structure/defensive_barrier/attack_hand(mob/user) + + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() - if(ishuman(user) && user.species.can_shred(user) && user.a_intent == I_HURT) + if(user.can_shred() && user.check_intent(I_FLAG_HARM)) take_damage(20) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) return TRUE - if(user.a_intent == I_GRAB) + if(user.check_intent(I_FLAG_GRAB)) try_pack_up(user) return TRUE @@ -135,9 +127,9 @@ update_icon() return TRUE -/obj/structure/defensive_barrier/attackby(obj/item/W, mob/user) +/obj/structure/defensive_barrier/attackby(obj/item/used_item, mob/user) - if(isScrewdriver(W) && density) + if(IS_SCREWDRIVER(used_item) && density) user.visible_message(SPAN_NOTICE("\The [user] begins to [secured ? "secure" : "unsecure"] \the [src]...")) playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) if(!do_after(user, 30, src)) @@ -149,12 +141,9 @@ . = ..() -/obj/structure/defensive_barrier/take_damage(damage) - if(damage) - playsound(src.loc, 'sound/effects/bang.ogg', 75, 1) - damage = round(damage * 0.5) - if(damage) - ..() +/obj/structure/defensive_barrier/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + damage = round(damage * 0.5) + return ..() /obj/structure/defensive_barrier/proc/check_cover(obj/item/projectile/P, turf/from) var/turf/cover = get_turf(src) @@ -205,32 +194,19 @@ playsound(src, 'sound/effects/extout.ogg', 100, 1) var/obj/structure/defensive_barrier/B = new(get_turf(user), material?.type) B.set_dir(user.dir) - B.health = stored_health + B.current_health = stored_health if(loc == user) user.drop_from_inventory(src) qdel(src) -/obj/item/defensive_barrier/attackby(obj/item/W, mob/user) - - if(stored_health < stored_max_health && isWelder(W)) - var/obj/item/weldingtool/WT = W - if(!WT.isOn()) - to_chat(user, SPAN_WARNING("Turn \the [W] on first.")) - return TRUE - - if(!WT.remove_fuel(0,user)) - to_chat(user, SPAN_WARNING("You need more welding fuel to complete this task.")) - return TRUE - - to_chat(user, SPAN_WARNING("You start repairing the damage to \the [src].")) - playsound(src, 'sound/items/Welder.ogg', 100, 1) - - if(!do_after(user, max(5, round((stored_max_health-stored_health) / 5)), src) || !WT?.isOn() || QDELETED(src)) - return TRUE - - to_chat(user, SPAN_NOTICE("You finish repairing the damage to \the [src].")) - playsound(src, 'sound/items/Welder2.ogg', 100, 1) - stored_health = stored_max_health +/obj/item/defensive_barrier/attackby(obj/item/used_item, mob/user) + if(stored_health < stored_max_health && IS_WELDER(used_item)) + if(used_item.do_tool_interaction(TOOL_WELDER, user, src, \ + max(5, round((stored_max_health-stored_health) / 5)), \ + "repairing the damage to", "repairing the damage to", \ + "You fail to patch the damage to \the [src].", \ + fuel_expenditure = 1 + )) + stored_health = stored_max_health return TRUE - . = ..() diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 7cbcf1d210a3..2223ada43936 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -3,13 +3,16 @@ icon = 'icons/obj/structures/displaycase.dmi' icon_state = "glassbox" desc = "A display case for prized possessions. It taunts you to kick it." - density = 1 - anchored = 1 - unacidable = 1//Dissolving the case would also delete the gun. + density = TRUE + anchored = TRUE alpha = 150 - maxhealth = 100 + max_health = 100 hitsound = 'sound/effects/Glasshit.ogg' - var/destroyed = 0 + req_access = null + material = /decl/material/solid/glass + + var/destroyed = FALSE + var/locked = TRUE /obj/structure/displaycase/Initialize() . = ..() @@ -19,10 +22,19 @@ AM.forceMove(src) update_icon() -/obj/structure/displaycase/examine(mob/user) + if(!req_access) + var/area/A = get_area(src) + if(!istype(A) || !islist(A.req_access)) + return + req_access = A.req_access.Copy() + +/obj/structure/displaycase/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(contents.len) - to_chat(user, "Inside you see [english_list(contents)].") + . += "Inside you see [english_list(contents)]." + + if(distance <= 1) + . += "It looks [locked ? "locked. You can open it with your ID card" : "unlocked"]." /obj/structure/displaycase/explosion_act(severity) ..() @@ -37,7 +49,7 @@ /obj/structure/displaycase/bullet_act(var/obj/item/projectile/Proj) ..() - take_damage(Proj.get_structure_damage()) + take_damage(Proj.get_structure_damage(), Proj.atom_damage_type) /obj/structure/proc/subtract_matter(var/obj/subtracting) if(!length(matter)) @@ -45,29 +57,33 @@ if(!istype(subtracting) || !length(subtracting.matter)) return for(var/mat in matter) - if(!subtracting[mat]) + if(!subtracting.matter[mat]) continue - matter[mat] -= subtracting[mat] + matter[mat] -= subtracting.matter[mat] if(matter[mat] <= 0) matter -= mat UNSETEMPTY(matter) -/obj/structure/displaycase/dismantle() +/obj/structure/displaycase/dismantle_structure(mob/user) SHOULD_CALL_PARENT(FALSE) . = TRUE -/obj/structure/displaycase/physically_destroyed() +/obj/structure/displaycase/physically_destroyed(var/skip_qdel) if(destroyed) return - . = ..() + . = ..(TRUE) if(.) set_density(0) destroyed = TRUE - subtract_matter(new /obj/item/shard(get_turf(src), material?.type)) + var/obj/item/shard/shard = new(get_turf(src), material?.type) + if(paint_color) + shard.set_color(paint_color) + subtract_matter(shard) playsound(src, "shatter", 70, 1) update_icon() /obj/structure/displaycase/on_update_icon() + ..() if(destroyed) icon_state = "glassboxb" else @@ -76,14 +92,49 @@ for(var/atom/movable/AM in contents) underlays += AM.appearance -/obj/structure/displaycase/attackby(obj/item/W, mob/user) +/obj/structure/displaycase/attackby(obj/item/used_item, mob/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - take_damage(W.force) - ..() + var/obj/item/card/id/id = used_item.GetIdCard() + if(istype(id)) + if(allowed(user)) + locked = !locked + to_chat(user, "\The [src] was [locked ? "locked" : "unlocked"].") + else + to_chat(user, "\The [src]'s card reader denies you access.") + return TRUE + + if(isitem(used_item) && (!locked || destroyed)) + if(!used_item.simulated || used_item.anchored) + return FALSE + + if(user.try_unequip(used_item, src)) + used_item.pixel_x = 0 + used_item.pixel_y = -7 + update_icon() + return TRUE + . = ..() /obj/structure/displaycase/attack_hand(mob/user) + + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) add_fingerprint(user) - if(!destroyed) - to_chat(usr, text("You kick the display case.")) - visible_message("[usr] kicks the display case.") - take_damage(2) \ No newline at end of file + + if(!locked || destroyed) + var/obj/item/selected_item + selected_item = show_radial_menu(user, src, make_item_radial_menu_choices(src), radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET) + if(QDELETED(selected_item) || !contents.Find(selected_item) || !Adjacent(user) || user.incapacitated()) + return TRUE + + to_chat(user, SPAN_NOTICE("You remove \the [selected_item] from \the [src].")) + selected_item.dropInto(loc) + update_icon() + return TRUE + + else if(!destroyed && user.check_intent(I_FLAG_HARM)) + visible_message(SPAN_WARNING("[user] kicks \the [src]."), SPAN_WARNING("You kick \the [src].")) + take_damage(2) + return TRUE + return FALSE diff --git a/code/game/objects/structures/divider.dm b/code/game/objects/structures/divider.dm new file mode 100644 index 000000000000..0ead2c654980 --- /dev/null +++ b/code/game/objects/structures/divider.dm @@ -0,0 +1,53 @@ +/obj/structure/divider + name = "room divider" + desc = "A thin, somewhat flimsy folding room divider." + icon = 'icons/obj/structures/divider.dmi' + icon_state = ICON_STATE_WORLD + "-closed" + material = /decl/material/solid/organic/wood/bamboo + color = /decl/material/solid/organic/wood/bamboo::color + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + var/extended = FALSE + +/obj/structure/divider/extended + icon_state = ICON_STATE_WORLD + extended = TRUE + +/obj/structure/divider/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + +/obj/structure/divider/extended/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + + +/obj/structure/divider/extended/wood/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/divider/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HELP) && user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, silent = TRUE)) + extended = !extended + if(material.dooropen_noise) + playsound(loc, material.dooropen_noise, 50, 1) + update_divider() + visible_message(SPAN_NOTICE("\The [user] [extended ? "extends" : "collapses"] \the [src].")) + return TRUE + . = ..() + +/obj/structure/divider/Initialize() + . = ..() + update_divider() + +/obj/structure/divider/proc/update_divider() + anchored = extended + density = extended + opacity = extended || (material.opacity < 0.5) + update_icon() + +/obj/structure/divider/on_update_icon() + . = ..() + if(extended) + icon_state = ICON_STATE_WORLD + else + icon_state = ICON_STATE_WORLD + "-closed" diff --git a/code/game/objects/structures/dogbed.dm b/code/game/objects/structures/dogbed.dm index 803746b9f9f8..d26621b86681 100644 --- a/code/game/objects/structures/dogbed.dm +++ b/code/game/objects/structures/dogbed.dm @@ -3,6 +3,6 @@ desc = "A bed made especially for dogs, or other similarly sized pets." icon = 'icons/obj/furniture.dmi' icon_state = "dogbed" - can_buckle = 1 + can_buckle = TRUE buckle_dir = SOUTH - buckle_lying = 1 \ No newline at end of file + buckle_lying = TRUE \ No newline at end of file diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index f767e16d0960..04cd6b7e88f7 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -2,71 +2,134 @@ name = "airlock assembly" icon = 'icons/obj/doors/station/door.dmi' icon_state = "construction" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + + material = /decl/material/solid/metal/steel + material_alteration = MAT_FLAG_ALTERATION_NAME + + var/can_install_glass = TRUE var/state = 0 - var/base_icon_state = "" - var/base_name = "Airlock" + var/base_name = "airlock assembly" var/obj/item/stock_parts/circuitboard/airlock_electronics/electronics = null var/airlock_type = /obj/machinery/door/airlock //the type path of the airlock once completed - var/glass = 0 // 0 = glass can be installed. -1 = glass can't be installed. 1 = glass is already installed. - var/glass_material = /decl/material/solid/glass // if this door was to built right now and be made of glass, what material should the glass be? var/created_name = null var/panel_icon = 'icons/obj/doors/station/panel.dmi' var/fill_icon = 'icons/obj/doors/station/fill_steel.dmi' var/glass_icon = 'icons/obj/doors/station/fill_glass.dmi' - var/paintable = AIRLOCK_PAINTABLE|AIRLOCK_STRIPABLE - var/door_color = "none" - var/stripe_color = "none" - var/symbol_color = "none" - -/obj/structure/door_assembly/Initialize(mapload, d) // would be desirable to improve material handling here - . = ..(mapload) - set_dir(d) + var/paintable = PAINT_PAINTABLE|PAINT_STRIPABLE + var/door_color + var/stripe_color + var/symbol_color + var/width = 1 // For multi-tile doors + +/obj/structure/door_assembly/update_material_name(override_name) + var/modifier + switch (state) + if(0) + if(anchored) + modifier = "secured " + if(1) + modifier = "wired " + if(2) + modifier = "near-finished " + if(reinf_material) + SetName("[modifier][reinf_material.solid_name] window [base_name]") + else + SetName("[modifier][base_name]") + +/obj/structure/door_assembly/window + reinf_material = /decl/material/solid/glass + +/obj/structure/door_assembly/Initialize(mapload, _mat, _reinf_mat, _dir) + . = ..(mapload, _mat, _reinf_mat) + set_dir(_dir) update_icon() +/obj/structure/door_assembly/set_dir(new_dir) + if(width == 1) // This logic doesn't support multitle doors. + if(new_dir & (EAST|WEST)) + new_dir = WEST + else + new_dir = SOUTH + + . = ..(new_dir) + + if(.) + set_bounds() + +/obj/structure/door_assembly/proc/set_bounds() + if (dir == NORTH || dir == SOUTH) + bound_width = width * world.icon_size + bound_height = world.icon_size + else + bound_width = world.icon_size + bound_height = width * world.icon_size + +/obj/structure/door_assembly/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() || list() + switch(state) + if(0) + LAZYADD(., "Use a wrench to [anchored ? "un" : ""]anchor it.") + if(!anchored) + if(can_install_glass) + if(reinf_material) + var/mat_name = reinf_material.solid_name || reinf_material.name + LAZYADD(., "Use a welder to remove the [mat_name] plating currently attached.") + else + LAZYADD(., "Use a welder to disassemble completely.") + else + LAZYADD(., "Use a cable coil to wire in preparation for electronics.") + if(1) + LAZYADD(., "Use a wirecutter to remove the wiring and expose the frame.") + LAZYADD(., "Insert electronics to proceed with construction.") + if(2) + LAZYADD(., "Use a crowbar to remove the electronics.") + LAZYADD(., "Use a screwdriver to complete assembly.") + /obj/structure/door_assembly/door_assembly_hatch icon = 'icons/obj/doors/hatch/door.dmi' panel_icon = 'icons/obj/doors/hatch/panel.dmi' fill_icon = 'icons/obj/doors/hatch/fill_steel.dmi' - base_name = "Airtight Hatch" + base_name = "airtight hatch" airlock_type = /obj/machinery/door/airlock/hatch - glass = -1 + can_install_glass = FALSE /obj/structure/door_assembly/door_assembly_highsecurity // Borrowing this until WJohnston makes sprites for the assembly icon = 'icons/obj/doors/secure/door.dmi' fill_icon = 'icons/obj/doors/secure/fill_steel.dmi' - base_name = "High Security Airlock" + base_name = "high security airlock" airlock_type = /obj/machinery/door/airlock/highsecurity - glass = -1 + can_install_glass = FALSE paintable = 0 /obj/structure/door_assembly/door_assembly_ext icon = 'icons/obj/doors/external/door.dmi' fill_icon = 'icons/obj/doors/external/fill_steel.dmi' glass_icon = 'icons/obj/doors/external/fill_glass.dmi' - base_name = "External Airlock" + base_name = "external airlock" airlock_type = /obj/machinery/door/airlock/external paintable = 0 -/obj/structure/door_assembly/multi_tile +/obj/structure/door_assembly/double icon = 'icons/obj/doors/double/door.dmi' fill_icon = 'icons/obj/doors/double/fill_steel.dmi' glass_icon = 'icons/obj/doors/double/fill_glass.dmi' panel_icon = 'icons/obj/doors/double/panel.dmi' - dir = EAST - var/width = 1 - airlock_type = /obj/machinery/door/airlock/multi_tile + airlock_type = /obj/machinery/door/airlock/double + width = 2 /obj/structure/door_assembly/blast name = "blast door assembly" icon = 'icons/obj/doors/rapid_pdoor.dmi' icon_state = "pdoor1" airlock_type = /obj/machinery/door/blast/regular - glass = -1 + can_install_glass = FALSE paintable = 0 -/obj/structure/door_assembly/blast/on_update_icon() +/obj/structure/door_assembly/blast/on_update_icon() + return /obj/structure/door_assembly/blast/morgue name = "morgue door assembly" @@ -77,187 +140,173 @@ /obj/structure/door_assembly/blast/shutter name = "shutter assembly" icon = 'icons/obj/doors/rapid_pdoor.dmi' - icon_state = "pdoor1" + icon_state = "shutter1" airlock_type = /obj/machinery/door/blast/shutters -/obj/structure/door_assembly/multi_tile/Initialize() - if(dir in list(EAST, WEST)) - bound_width = width * world.icon_size - bound_height = world.icon_size - else - bound_width = world.icon_size - bound_height = width * world.icon_size - . = ..() +/obj/structure/door_assembly/attackby(obj/item/used_item, mob/user) -/obj/structure/door_assembly/multi_tile/Move() - . = ..() - if(dir in list(EAST, WEST)) - bound_width = width * world.icon_size - bound_height = world.icon_size - else - bound_width = world.icon_size - bound_height = width * world.icon_size - -/obj/structure/door_assembly/attackby(obj/item/W, mob/user) - - if(istype(W, /obj/item/pen)) - var/t = sanitizeSafe(input(user, "Enter the name for the door.", src.name, src.created_name), MAX_NAME_LEN) - if(!t) return - if(!in_range(src, usr) && src.loc != usr) return + if(IS_PEN(used_item)) + var/t = sanitize_safe(input(user, "Enter the name for the door.", src.name, src.created_name), MAX_NAME_LEN) + if(!length(t)) + return TRUE + if(!CanPhysicallyInteractWith(user, src)) + to_chat(user, SPAN_WARNING("You must stay close to \the [src]!")) + return TRUE created_name = t - return + return TRUE - if(isWelder(W) && (glass == 1 || !anchored)) - var/obj/item/weldingtool/WT = W - if (WT.remove_fuel(0, user)) + if(IS_WELDER(used_item) && (can_install_glass || !anchored)) + var/obj/item/weldingtool/welder = used_item + if (welder.weld(0, user)) playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - if(glass == 1) - var/decl/material/glass_material_datum = decls_repository.get_decl(glass_material) - if(glass_material_datum) - var/mat_name = glass_material_datum.solid_name || glass_material_datum.name - user.visible_message("[user] welds the [mat_name] plating off the airlock assembly.", "You start to weld the [mat_name] plating off the airlock assembly.") - if(do_after(user, 40,src)) - if(!WT.isOn()) - return TRUE - to_chat(user, "You welded the [mat_name] plating off!") - glass_material_datum.place_sheet(get_turf(src), 2) - glass = 0 - update_icon() - return TRUE + if(reinf_material) + var/mat_name = reinf_material.solid_name + user.visible_message("[user] welds the [mat_name] plating off the airlock assembly.", "You start to weld the [mat_name] plating off the airlock assembly.") + if(do_after(user, 4 SECONDS, src)) + if(!welder.isOn()) + return TRUE + to_chat(user, "You welded the [mat_name] plating off!") + reinf_material.create_object(get_turf(src), 2) + reinf_material = null + update_icon() + return TRUE if(!anchored) user.visible_message("[user] dissassembles the airlock assembly.", "You start to dissassemble the airlock assembly.") - if(do_after(user, 40,src)) - if(!WT.isOn()) - return + if(do_after(user, 4 SECONDS, src)) + if(!welder.isOn()) + return TRUE to_chat(user, "You dissasembled the airlock assembly!") - new /obj/item/stack/material/steel(src.loc, 4) - qdel (src) - return TRUE + dismantle_structure(user) + return TRUE else to_chat(user, "You need more welding fuel.") return TRUE - if(isWrench(W) && state == 0) + if(IS_WRENCH(used_item) && state == 0) playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) if(anchored) user.visible_message("[user] begins unsecuring the airlock assembly from the floor.", "You begin unsecuring the airlock assembly from the floor.") else user.visible_message("[user] begins securing the airlock assembly to the floor.", "You begin securing the airlock assembly to the floor.") - if(do_after(user, 40,src)) - if(!src) return + if(do_after(user, 4 SECONDS, src)) + if(QDELETED(src)) return TRUE to_chat(user, "You [anchored? "un" : ""]secured the airlock assembly!") anchored = !anchored update_icon() + return TRUE - else if(isCoil(W) && state == 0 && anchored) - var/obj/item/stack/cable_coil/C = W + else if(IS_COIL(used_item) && state == 0 && anchored) + var/obj/item/stack/cable_coil/C = used_item if (C.get_amount() < 1) to_chat(user, "You need one length of coil to wire the airlock assembly.") - return + return TRUE user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") - if(do_after(user, 40,src) && state == 0 && anchored) + if(do_after(user, 4 SECONDS, src) && state == 0 && anchored) if (C.use(1)) src.state = 1 to_chat(user, "You wire the airlock.") update_icon() + return TRUE - else if(isWirecutter(W) && state == 1 ) + else if(IS_WIRECUTTER(used_item) && state == 1 ) playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") if(do_after(user, 40,src)) - if(!src) return - to_chat(user, "You cut the airlock wires.!") + if(QDELETED(src)) return TRUE + to_chat(user, "You cut the airlock wires!") new/obj/item/stack/cable_coil(src.loc, 1) src.state = 0 update_icon() + return TRUE - else if(istype(W, /obj/item/stock_parts/circuitboard/airlock_electronics) && state == 1) - var/obj/item/stock_parts/circuitboard/airlock_electronics/E = W + else if(istype(used_item, /obj/item/stock_parts/circuitboard/airlock_electronics) && state == 1) + var/obj/item/stock_parts/circuitboard/airlock_electronics/E = used_item if(!ispath(airlock_type, E.build_path)) - return + return FALSE playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly.") if(do_after(user, 40,src)) - if(!src) return - if(!user.unEquip(W, src)) - return + if(QDELETED(src)) return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE to_chat(user, "You installed the airlock electronics!") src.state = 2 src.SetName("Near finished Airlock Assembly") - src.electronics = W + src.electronics = used_item update_icon() + return TRUE - else if(isCrowbar(W) && state == 2 ) + else if(IS_CROWBAR(used_item) && state == 2 ) //This should never happen, but just in case I guess if (!electronics) to_chat(user, "There was nothing to remove.") src.state = 1 update_icon() - return + return TRUE playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("\The [user] starts removing the electronics from the airlock assembly.", "You start removing the electronics from the airlock assembly.") - if(do_after(user, 40,src)) - if(!src) return + if(do_after(user, 4 SECONDS, src)) + if(QDELETED(src)) return TRUE to_chat(user, "You removed the airlock electronics!") src.state = 1 src.SetName("Wired Airlock Assembly") electronics.dropInto(loc) electronics = null update_icon() + return TRUE - else if(istype(W, /obj/item/stack/material) && !glass) - var/obj/item/stack/material/S = W - var/material_name = S.get_material_type() + else if(istype(used_item, /obj/item/stack/material) && can_install_glass && !reinf_material) + var/obj/item/stack/material/S = used_item + var/decl/material/sheet_material = S.get_material() if (S.get_amount() >= 2) playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [S.name] to the airlock assembly.", "You start to install [S.name] into the airlock assembly.") - if(do_after(user, 40,src) && !glass) + if(do_after(user, 4 SECONDS, src) && can_install_glass && !reinf_material) if (S.use(2)) - to_chat(user, "You installed reinforced glass windows into the airlock assembly.") - glass = 1 - glass_material = material_name + reinf_material = sheet_material + to_chat(user, "You installed [reinf_material.solid_name] windows into the airlock assembly.") update_icon() return TRUE + return FALSE - else if(isScrewdriver(W) && state == 2 ) + else if(IS_SCREWDRIVER(used_item) && state == 2 ) playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) to_chat(user, "Now finishing the airlock.") - if(do_after(user, 40,src)) - if(!src) return + if(do_after(user, 4 SECONDS, src)) + if(QDELETED(src)) return TRUE to_chat(user, "You finish the airlock!") var/obj/machinery/door/door = new airlock_type(get_turf(src), dir, FALSE, src) door.construct_state.post_construct(door) // it eats the circuit inside Initialize qdel(src) + return TRUE else - ..() + return ..() /obj/structure/door_assembly/on_update_icon() - overlays.Cut() + ..() + var/image/filling_overlay - var/image/panel_overlay - var/final_name = "" - if(glass == 1) + if(reinf_material) filling_overlay = image(glass_icon, "construction") + filling_overlay.color = reinf_material.color + filling_overlay.appearance_flags |= RESET_COLOR else filling_overlay = image(fill_icon, "construction") - switch (state) - if(0) - if (anchored) - final_name = "Secured " + if(filling_overlay) + add_overlay(filling_overlay) + + var/image/panel_overlay + switch(state) if(1) - final_name = "Wired " panel_overlay = image(panel_icon, "construction0") if(2) - final_name = "Near Finished " panel_overlay = image(panel_icon, "construction1") - final_name += "[glass == 1 ? "Window " : ""][istext(glass) ? "[glass] Airlock" : base_name] Assembly" - SetName(final_name) - overlays += filling_overlay - overlays += panel_overlay + if(panel_overlay) + add_overlay(panel_overlay) diff --git a/code/game/objects/structures/doors/_door.dm b/code/game/objects/structures/doors/_door.dm index 84da5a4a0c57..ff6989638376 100644 --- a/code/game/objects/structures/doors/_door.dm +++ b/code/game/objects/structures/doors/_door.dm @@ -1,59 +1,112 @@ /obj/structure/door - name = "door" - icon = 'icons/obj/doors/material_doors.dmi' - icon_state = "metal" - hitsound = 'sound/weapons/genhit.ogg' - material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_COLOR - maxhealth = 50 - density = TRUE - anchored = TRUE - opacity = TRUE - - var/has_window = FALSE - var/changing_state = FALSE + name = "door" + icon = 'icons/obj/doors/material_doors.dmi' + icon_state = "metal" + hitsound = 'sound/weapons/genhit.ogg' + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + max_health = 50 + density = TRUE + anchored = TRUE + opacity = TRUE + structure_flags = STRUCTURE_FLAG_THROWN_DAMAGE + var/has_window = FALSE + var/changing_state = FALSE + var/door_sound_volume = 25 var/icon_base - var/datum/lock/lock /obj/structure/door/Initialize() - . = ..() + ..() if(!istype(material)) return INITIALIZE_HINT_QDEL - if(lock) - lock = new /datum/lock(src, lock) if(!icon_base) icon_base = material.door_icon_base - changing_state = FALSE - update_nearby_tiles(need_rebuild=TRUE) + update_icon() + if(material?.luminescence) + set_light(material.luminescence, 0.5, material.color) + return INITIALIZE_HINT_LATELOAD + +/obj/structure/door/LateInitialize(mapload, dir=0, populate_parts=TRUE) + ..() + update_nearby_tiles(need_rebuild = TRUE) + +/obj/structure/door/update_nearby_tiles(need_rebuild) + . = ..() + update_connections(TRUE) /obj/structure/door/Destroy() update_nearby_tiles() - QDEL_NULL(lock) return ..() +/obj/structure/door/get_blend_objects() + var/static/list/blend_objects = list( + /obj/structure/wall_frame, + /obj/structure/window, + /obj/structure/grille, + /obj/machinery/door + ) + return blend_objects + +// Preference is: constructed walls, other doors, other walls. +/obj/structure/door/proc/get_turf_blend_priority(turf/neighbor) + if(istype(neighbor, /turf/wall)) + return istype(neighbor, /turf/wall/natural) ? 1 : 3 + if(locate(/obj/structure/door) in neighbor) + return 2 + return 0 + +/obj/structure/door/update_connections(var/propagate = FALSE) + + . = ..() + + if(!isturf(loc)) + return + + var/highest_priority + var/highest_dir + + for(var/turf/neighbor as anything in RANGE_TURFS(loc, 1)) + + if(propagate && istype(neighbor, /turf/wall)) + var/turf/wall/wall = neighbor + wall.wall_connections = null + wall.other_connections = null + wall.queue_icon_update() + + var/turf_dir = get_dir(loc, neighbor) + if(turf_dir & (turf_dir - 1)) // if diagonal + continue // skip diagonals + + var/turf_priority = get_turf_blend_priority(neighbor) + if(turf_priority > highest_priority) + highest_dir = turf_dir + highest_priority = turf_priority + + if(highest_priority > 0 && highest_dir) + set_dir(turn(highest_dir, 90)) + /obj/structure/door/get_material_health_modifier() . = 10 /obj/structure/door/on_update_icon() ..() - if(density) - icon_state = "[icon_base]" - else - icon_state = "[icon_base]open" + icon_state = "[icon_base][!density ? "_open" : ""]" /obj/structure/door/proc/post_change_state() update_nearby_tiles() update_icon() changing_state = FALSE -/obj/structure/door/attack_hand(var/mob/user) - return density ? open() : close() +/obj/structure/door/attack_hand(mob/user) + if(user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return density ? open(user) : close(user) + return ..() -/obj/structure/door/proc/close() - set waitfor = 0 - if(!can_close()) +/obj/structure/door/proc/close(mob/user) + set waitfor = FALSE + if(!can_close(user)) return FALSE - flick("[icon_base]closing", src) - playsound(src.loc, material.dooropen_noise, 100, 1) + flick("[icon_base]_closing", src) + playsound(src, material.dooropen_noise, door_sound_volume, 1) changing_state = TRUE sleep(1 SECOND) @@ -62,13 +115,13 @@ post_change_state() return TRUE -/obj/structure/door/proc/open() - set waitfor = 0 - if(!can_open()) +/obj/structure/door/proc/open(mob/user) + set waitfor = FALSE + if(!can_open(user)) return FALSE - flick("[icon_base]opening", src) - playsound(src.loc, material.dooropen_noise, 100, 1) - + flick("[icon_base]_opening", src) + playsound(src, material.dooropen_noise, door_sound_volume, 1) + changing_state = TRUE sleep(1 SECOND) set_density(FALSE) @@ -76,22 +129,22 @@ post_change_state() return TRUE -/obj/structure/door/proc/can_open() - if(lock && lock.isLocked()) - return FALSE +/obj/structure/door/update_lock_overlay() + return // TODO + +/obj/structure/door/proc/can_open(mob/user) + if(lock) + try_unlock(user, user?.get_active_held_item()) + if(lock.isLocked()) + to_chat(user, SPAN_WARNING("\The [src] is locked.")) + return FALSE return density && !changing_state /obj/structure/door/proc/can_close() return !density && !changing_state -/obj/structure/door/examine(mob/user, distance) - . = ..() - if(distance <= 1 && lock) - to_chat(user, SPAN_NOTICE("It appears to have a lock.")) - -/obj/structure/door/attack_ai(mob/user) - if(Adjacent(user) && isrobot(user)) - return attack_hand(user) +/obj/structure/door/attack_ai(mob/living/user) + return attack_hand_with_interaction_checks(user) /obj/structure/door/explosion_act(severity) . = ..() @@ -104,56 +157,80 @@ to_chat(user, SPAN_WARNING("\The [src] must be closed before it can be repaired.")) return FALSE -/obj/structure/door/attackby(obj/item/I, mob/user) +/obj/structure/door/can_install_lock() + return TRUE - add_fingerprint(user, 0, I) +/obj/structure/door/attackby(obj/item/used_item, mob/user) + add_fingerprint(user, 0, used_item) - if((user.a_intent == I_HURT && I.force) || istype(I, /obj/item/stack/material)) + if((user.check_intent(I_FLAG_HARM) && used_item.get_attack_force(user)) || istype(used_item, /obj/item/stack/material)) return ..() - if(lock) - if(istype(I, /obj/item/key)) - if(!lock.toggle(I)) - to_chat(user, SPAN_WARNING("\The [I] does not fit in the lock!")) + if(used_item.user_can_attack_with(user, silent = TRUE)) + if(try_key_unlock(used_item, user)) return TRUE - if(lock.pick_lock(I,user)) + + if(try_install_lock(used_item, user)) return TRUE - if(lock.isLocked()) - to_chat(user, SPAN_WARNING("\The [src] is locked!")) - return TRUE - - if(istype(I,/obj/item/lock_construct)) - if(lock) - to_chat(user, SPAN_WARNING("\The [src] already has a lock.")) - else - var/obj/item/lock_construct/L = I - lock = L.create_lock(src,user) - return if(density) - open() + open(user) else - close() + close(user) + return TRUE /obj/structure/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group) return !density - if(istype(mover, /obj/effect/beam)) + if(istype(mover, /obj/effect/ir_beam)) return !opacity return !density -/obj/structure/door/CanFluidPass(var/coming_from) +/obj/structure/door/CanFluidPass(coming_from) return !density -/obj/structure/door/Bumped(atom/AM) - if(!density || changing_state) +/obj/structure/door/Bumped(atom/movable/AM) + if(!density || changing_state || !istype(AM)) + return + + if(AM.get_object_size() <= MOB_SIZE_SMALL) return + if(ismob(AM)) var/mob/M = AM if(M.restrained() || issmall(M)) return - open() + open(ismob(AM) ? AM : null) +/obj/structure/door/get_alt_interactions(var/mob/user) + . = ..() + if(density) + LAZYADD(., /decl/interaction_handler/knock_on_door) + +/decl/interaction_handler/knock_on_door + name = "Knock On Door" + expected_target_type = /obj/structure/door + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEEDS_TURF + examine_desc = "knock on $TARGET_THEM$" + +/decl/interaction_handler/knock_on_door/invoked(atom/target, mob/user, obj/item/prop) + if(!istype(target) || !target.density) + return FALSE + user.do_attack_animation(src) + playsound(target.loc, 'sound/effects/glassknock.ogg', 80, 1) + if(user.check_intent(I_FLAG_HARM)) + target.visible_message( + SPAN_DANGER("\The [user] bangs against \the [src]!"), + blind_message = "You hear a banging sound!" + ) + else + target.visible_message( + SPAN_NOTICE("\The [user] knocks on \the [target]."), + blind_message = SPAN_NOTICE("You hear a knocking sound.") + ) + return TRUE + +// Subtypes below. /obj/structure/door/iron material = /decl/material/solid/metal/iron @@ -168,32 +245,56 @@ /obj/structure/door/sandstone material = /decl/material/solid/stone/sandstone + color = /decl/material/solid/stone/sandstone::color + +/obj/structure/door/basalt + desc = "A door hewn of raw basalt, unthinkably heavy and smooth to the touch." + material = /decl/material/solid/stone/basalt + color = /decl/material/solid/stone/basalt::color /obj/structure/door/diamond material = /decl/material/solid/gemstone/diamond /obj/structure/door/wood - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color /obj/structure/door/mahogany - material = /decl/material/solid/wood/mahogany + material = /decl/material/solid/organic/wood/mahogany + color = /decl/material/solid/organic/wood/mahogany::color /obj/structure/door/maple - material = /decl/material/solid/wood/maple + material = /decl/material/solid/organic/wood/maple + color = /decl/material/solid/organic/wood/maple::color /obj/structure/door/ebony - material = /decl/material/solid/wood/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color /obj/structure/door/walnut - material = /decl/material/solid/wood/walnut - -/obj/structure/door/cult - material = /decl/material/solid/stone/cult + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color /obj/structure/door/wood/saloon - icon_base = "saloon" - material = /decl/material/solid/wood + material = /decl/material/solid/organic/wood/oak opacity = FALSE +/obj/structure/door/wood/saloon/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/door/wood/saloon/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + +/obj/structure/door/glass + material = /decl/material/solid/glass + +/obj/structure/door/plastic + material = /decl/material/solid/organic/plastic + +/obj/structure/door/exotic_matter + material = /decl/material/solid/exotic_matter + /obj/structure/door/shuttle material = /decl/material/solid/metal/steel diff --git a/code/game/objects/structures/double_sign.dm b/code/game/objects/structures/double_sign.dm new file mode 100644 index 000000000000..d7a1ecc34293 --- /dev/null +++ b/code/game/objects/structures/double_sign.dm @@ -0,0 +1,3 @@ +// Abstract type mainly used for trader blacklisting. +/obj/structure/sign/double + abstract_type = /obj/structure/sign/double diff --git a/code/game/objects/structures/drain.dm b/code/game/objects/structures/drain.dm index ec940eae656b..66cdf42b45e0 100644 --- a/code/game/objects/structures/drain.dm +++ b/code/game/objects/structures/drain.dm @@ -5,32 +5,37 @@ desc = "You probably can't get sucked down the plughole." icon = 'icons/obj/drain.dmi' icon_state = "drain" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE layer = TURF_LAYER+0.1 can_drain = 1 var/welded -/obj/structure/hygiene/drain/attackby(var/obj/item/thing, var/mob/user) - ..() - if(isWelder(thing)) - var/obj/item/weldingtool/WT = thing - if(WT.isOn()) +/obj/structure/hygiene/drain/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(welded) + . += "It is welded shut." + +/obj/structure/hygiene/drain/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.isOn()) welded = !welded to_chat(user, "You weld \the [src] [welded ? "closed" : "open"].") else - to_chat(user, "Turn \the [thing] on, first.") + to_chat(user, "Turn \the [used_item] on, first.") update_icon() - return - if(isWrench(thing)) + return TRUE + if(IS_WRENCH(used_item)) new /obj/item/drain(src.loc) playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "[user] unwrenches the [src].") + to_chat(user, "[user] unwrenches \the [src].") qdel(src) - return + return TRUE return ..() /obj/structure/hygiene/drain/on_update_icon() + ..() icon_state = "[initial(icon_state)][welded ? "-welded" : ""]" /obj/structure/hygiene/drain/Process() @@ -44,12 +49,53 @@ desc = "You probably can't get sucked down the plughole." icon = 'icons/obj/drain.dmi' icon_state = "drain" + material = /decl/material/solid/metal/brass + var/constructed_type = /obj/structure/hygiene/drain -/obj/item/drain/attackby(var/obj/item/thing, var/mob/user) - if(isWrench(thing)) - new /obj/structure/hygiene/drain(src.loc) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "[user] wrenches the [src] down.") +/obj/item/drain/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WRENCH(used_item)) + new constructed_type(get_turf(src)) + playsound(src, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("\The [user] wrenches \the [src] down.")) qdel(src) - return + return TRUE return ..() + +/obj/structure/hygiene/drain/bath + name = "sealable drain" + desc = "You probably can't get sucked down the plughole. Specially not when it's closed!" + icon_state = "drain_bath" + + var/closed = FALSE + +/obj/structure/hygiene/drain/bath/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + if(welded) + return ..() + closed = !closed + user.visible_message(SPAN_NOTICE("\The [user] has [closed ? "closed" : "opened"] the drain.")) + update_icon() + return TRUE + +/obj/structure/hygiene/drain/bath/on_update_icon() + ..() + if(welded) + icon_state = "[initial(icon_state)]-welded" + else + icon_state = "[initial(icon_state)][closed ? "-closed" : ""]" + +/obj/structure/hygiene/drain/bath/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "It is [closed ? "closed" : "open"]" + +/obj/structure/hygiene/drain/bath/Process() + if(closed) + return + ..() + +/obj/item/drain/bath + name = "sealable drain" + desc = "You probably can't get sucked down the plughole. Specially not when it's closed!" + icon_state = "drain_bath" + constructed_type = /obj/structure/hygiene/drain/bath diff --git a/code/game/objects/structures/drying_rack.dm b/code/game/objects/structures/drying_rack.dm new file mode 100644 index 000000000000..6f116ab4451f --- /dev/null +++ b/code/game/objects/structures/drying_rack.dm @@ -0,0 +1,95 @@ +/obj/structure/drying_rack + name = "drying rack" + desc = "A rack used to hold meat or vegetables for drying, or to stretch leather out and hold it taut during the tanning process." + icon = 'icons/obj/drying_rack.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/steel + color = /decl/material/solid/metal/steel::color + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + var/obj/item/drying + +/obj/structure/drying_rack/Initialize(ml, _mat, _reinf_mat) + . = ..() + // This is mostly for serde. + for(var/obj/item/thing in get_contained_external_atoms()) + if(!drying && thing.is_dryable()) + drying = thing + update_icon() + else + thing.dropInto(loc) + +/obj/structure/drying_rack/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/drying_rack/Destroy() + QDEL_NULL(drying) + if(is_processing) + STOP_PROCESSING(SSobj, src) + return ..() + +// SSObj fires ~every 2s , starting from wetness 30 takes ~1m +/obj/structure/drying_rack/Process() + if(!drying) + return + + if(isturf(loc)) + var/turf/my_turf = loc + var/decl/state/weather/weather_state = my_turf.weather?.weather_system?.current_state + if(istype(weather_state) && weather_state.is_liquid) + return // can't dry in the rain + if(loc?.is_flooded(TRUE)) + return // can't dry in the wet + + var/dry_product = drying?.dry_out(src) + if(dry_product) + if(drying != dry_product) + if(drying && !QDELETED(drying)) + drying.dropInto(loc) + drying = dry_product + if(is_processing) + STOP_PROCESSING(SSobj, src) + if(drying) + drying.forceMove(src) + if(drying) + drying.update_icon() + update_icon() + +/obj/structure/drying_rack/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(drying) + . += "\The [drying] is [drying.get_dryness_text()]." + +/obj/structure/drying_rack/on_update_icon() + ..() + var/drying_state = drying?.get_drying_overlay(src) + if(drying_state) + add_overlay(drying_state) + +/obj/structure/drying_rack/attackby(var/obj/item/used_item, var/mob/user) + + if(!drying && used_item.is_dryable()) + if(user.try_unequip(used_item)) + used_item.forceMove(src) + drying = used_item + if(!is_processing) + START_PROCESSING(SSobj, src) + update_icon() + return TRUE + + return ..() + +/obj/structure/drying_rack/attack_hand(var/mob/user) + if(drying) + drying.dropInto(loc) + user.put_in_hands(drying) + drying = null + if(is_processing) + STOP_PROCESSING(SSobj, src) + update_icon() + return ..() + +/obj/structure/drying_rack/attack_robot(mob/user) + if(Adjacent(user)) + return attack_hand(user) + return ..() diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm deleted file mode 100644 index 0ea537db24fa..000000000000 --- a/code/game/objects/structures/electricchair.dm +++ /dev/null @@ -1,74 +0,0 @@ -/obj/structure/bed/chair/e_chair - name = "electric chair" - desc = "Looks absolutely SHOCKING!" - icon_state = "echair0" - var/on = 0 - var/obj/item/assembly/shock_kit/part = null - var/last_time = 1.0 - -/obj/structure/bed/chair/e_chair/Initialize() - . = ..() - overlays += image('icons/obj/objects.dmi', src, "echair_over", MOB_LAYER + 1, dir) - -/obj/structure/bed/chair/e_chair/attackby(obj/item/W, mob/user) - if(isWrench(W)) - var/obj/structure/bed/chair/C = new /obj/structure/bed/chair(loc) - playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) - C.set_dir(dir) - part.dropInto(loc) - part.master = null - part = null - qdel(src) - -/obj/structure/bed/chair/e_chair/verb/toggle() - set name = "Toggle Electric Chair" - set category = "Object" - set src in oview(1) - - if(on) - on = 0 - icon_state = "echair0" - else - on = 1 - icon_state = "echair1" - to_chat(usr, "You switch [on ? "on" : "off"] [src].") - return - -/obj/structure/bed/chair/e_chair/rotate() - ..() - overlays.Cut() - overlays += image('icons/obj/objects.dmi', src, "echair_over", MOB_LAYER + 1, dir) //there's probably a better way of handling this, but eh. -Pete - return - -/obj/structure/bed/chair/e_chair/proc/shock() - if(!on) - return - if(last_time + 50 > world.time) - return - last_time = world.time - - // special power handling - var/area/A = get_area(src) - if(!isarea(A)) - return - if(!A.powered(EQUIP)) - return - A.use_power_oneoff(5000, EQUIP) - var/light = A.power_light - A.update_icon() - - flick("echair1", src) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(12, 1, src) - s.start() - if(buckled_mob) - buckled_mob.burn_skin(85) - to_chat(buckled_mob, "You feel a deep shock course through your body!") - sleep(1) - buckled_mob.burn_skin(85) - buckled_mob.Stun(600) - visible_message("The electric chair went off!", "You hear a deep sharp shock!") - - A.power_light = light - A.update_icon() - return diff --git a/code/game/objects/structures/emergency_dispenser.dm b/code/game/objects/structures/emergency_dispenser.dm new file mode 100644 index 000000000000..6bc0e2528f8e --- /dev/null +++ b/code/game/objects/structures/emergency_dispenser.dm @@ -0,0 +1,44 @@ + +//spawns endless (3 sets) amounts of breathmask, emergency oxy tank +/obj/structure/emergency_dispenser + name = "emergency dispenser" + desc = "A wall mounted dispenser with emergency supplies." + icon = 'icons/obj/structures/emergency_dispenser.dmi' + icon_state = "world" + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + var/static/list/spawnitems = list(/obj/item/tank/emergency/oxygen,/obj/item/clothing/mask/breath) + var/amount = 3 // spawns each items X times. + +/obj/structure/emergency_dispenser/attack_hand(mob/user) + //Added by Strumpetplaya - AI shouldn't be able to (you're both stupid, need CanPhysicallyInteract --Chinsky) + //activate emergency lockers. This fixes that. (Does this make sense, the AI can't call attack_hand, can it? --Mloc) + //(It uses the Nano helper and a dexterity check now anyway. --Loaf) + if(!CanPhysicallyInteract(user) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(!amount) + to_chat(user, SPAN_WARNING("It's empty.")) + else + to_chat(user, SPAN_NOTICE("You take out some items from \the [src].")) + playsound(src, 'sound/machines/vending_machine.ogg', 25, 1) + for(var/path in spawnitems) + new path(src.loc) + amount-- + return TRUE + +/obj/structure/emergency_dispenser/north + pixel_y = 32 + dir = SOUTH + +/obj/structure/emergency_dispenser/south + pixel_y = -32 + dir = NORTH + +/obj/structure/emergency_dispenser/west + pixel_x = -32 + dir = WEST + +/obj/structure/emergency_dispenser/east + pixel_x = 32 + dir = EAST diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index e92fe9f381ca..79cd15f429fc 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -3,68 +3,66 @@ desc = "A small wall mounted cabinet designed to hold a fire extinguisher." icon = 'icons/obj/structures/extinguisher.dmi' icon_state = "extinguisher_closed" - anchored = 1 - density = 0 - var/obj/item/extinguisher/has_extinguisher + anchored = TRUE + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-29}, "SOUTH":{"y":29}, "EAST":{"x":-29}, "WEST":{"x":29}}' + var/obj/item/chems/spray/extinguisher/has_extinguisher var/opened = 0 /obj/structure/extinguisher_cabinet/Initialize() . = ..() - has_extinguisher = new/obj/item/extinguisher(src) + has_extinguisher = new/obj/item/chems/spray/extinguisher(src) -/obj/structure/extinguisher_cabinet/attackby(obj/item/O, mob/user) +// TODO: I wanted to make it so you had to actually use your hand to open it if it's closed, but +// that'd be out of scope for just an attackby audit. Someone fix this so it can call parent please. +/obj/structure/extinguisher_cabinet/attackby(obj/item/used_item, mob/user) if(isrobot(user)) - return - if(istype(O, /obj/item/extinguisher)) - if(!has_extinguisher && opened && user.unEquip(O, src)) - has_extinguisher = O - to_chat(user, "You place [O] in [src].") + return FALSE + if(istype(used_item, /obj/item/chems/spray/extinguisher)) + if(!has_extinguisher && opened && user.try_unequip(used_item, src)) + has_extinguisher = used_item + to_chat(user, "You place [used_item] in [src].") playsound(src.loc, 'sound/effects/extin.ogg', 50, 0) else opened = !opened else opened = !opened update_icon() + return TRUE /obj/structure/extinguisher_cabinet/attack_hand(mob/user) - if(isrobot(user)) - return - if (ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] - if (user.hand) - temp = H.organs_by_name[BP_L_HAND] - if(temp && !temp.is_usable()) - to_chat(user, "You try to move your [temp.name], but cannot!") - return - if(has_extinguisher) + + if(user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE) && has_extinguisher) user.put_in_hands(has_extinguisher) - to_chat(user, "You take [has_extinguisher] from [src].") + to_chat(user, SPAN_NOTICE("You take [has_extinguisher] from [src].")) playsound(src.loc, 'sound/effects/extout.ogg', 50, 0) has_extinguisher = null - opened = 1 - else + opened = TRUE + update_icon() + return TRUE + + if(user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) opened = !opened - update_icon() + update_icon() + return TRUE + + return ..() /obj/structure/extinguisher_cabinet/on_update_icon() + ..() if(!opened) icon_state = "extinguisher_closed" return if(has_extinguisher) - if(istype(has_extinguisher, /obj/item/extinguisher/mini)) + if(istype(has_extinguisher, /obj/item/chems/spray/extinguisher/mini)) icon_state = "extinguisher_mini" else icon_state = "extinguisher_full" else icon_state = "extinguisher_empty" -/obj/structure/extinguisher_cabinet/AltClick(var/mob/user) - if(CanPhysicallyInteract(user)) - opened = !opened - update_icon() - /obj/structure/extinguisher_cabinet/do_simple_ranged_interaction(var/mob/user) if(has_extinguisher) has_extinguisher.dropInto(loc) @@ -74,3 +72,17 @@ opened = !opened update_icon() return TRUE + +/obj/structure/extinguisher_cabinet/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/extinguisher_cabinet_open) + +/decl/interaction_handler/extinguisher_cabinet_open + name = "Open/Close" + expected_target_type = /obj/structure/extinguisher_cabinet + examine_desc = "open or close $TARGET_THEM$" + +/decl/interaction_handler/extinguisher_cabinet_open/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/extinguisher_cabinet/C = target + C.opened = !C.opened + C.update_icon() diff --git a/code/game/objects/structures/fences.dm b/code/game/objects/structures/fences.dm new file mode 100644 index 000000000000..1ed302b304a5 --- /dev/null +++ b/code/game/objects/structures/fences.dm @@ -0,0 +1,195 @@ +//Chain link fences +//Sprites ported from /VG/ + +#define CUT_TIME 10 SECONDS +#define CLIMB_TIME 5 SECONDS + +///section is intact +#define NO_HOLE 0 +///medium hole in the section - can climb through +#define MEDIUM_HOLE 1 +///large hole in the section - can walk through +#define LARGE_HOLE 2 +#define MAX_HOLE_SIZE LARGE_HOLE + +/obj/structure/fence + name = "fence" + desc = "A chain link fence. Not as effective as a wall, but generally it keeps people out." + density = TRUE + anchored = TRUE + + icon = 'icons/obj/structures/fence.dmi' + icon_state = "straight" + + material = /decl/material/solid/metal/steel + material_alteration = MAT_FLAG_ALTERATION_ALL + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + + var/cuttable = TRUE + var/hole_size = NO_HOLE + +/obj/structure/fence/Initialize(mapload) + update_cut_status() + return ..() + +/obj/structure/fence/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + switch(hole_size) + if(MEDIUM_HOLE) + . += SPAN_DANGER("There is a large hole in \the [src].") + if(LARGE_HOLE) + . += SPAN_DANGER("\The [src] has been completely cut through.") + +/obj/structure/fence/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + if(cuttable && hole_size < MAX_HOLE_SIZE) + LAZYADD(., SPAN_SUBTLE("Use wirecutters to [hole_size > NO_HOLE ? "expand the":"cut a"] hole into the fence, allowing passage.")) + +/obj/structure/fence/end + icon_state = "end" + cuttable = FALSE + +/obj/structure/fence/corner + icon_state = "corner" + cuttable = FALSE + +/obj/structure/fence/post + icon_state = "post" + cuttable = FALSE + +/obj/structure/fence/cut/medium + icon_state = "straight-cut2" + hole_size = MEDIUM_HOLE + +/obj/structure/fence/cut/large + icon_state = "straight-cut3" + hole_size = LARGE_HOLE + +// Projectiles can pass through fences. +/obj/structure/fence/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(mover?.checkpass(PASS_FLAG_TABLE)) + return TRUE + if(hole_size == MEDIUM_HOLE && issmall(mover)) + return TRUE + return ..() + +/obj/structure/fence/can_repair(mob/user) + if(hole_size > NO_HOLE) + return TRUE + return ..() + +/obj/structure/fence/handle_repair(mob/user, obj/item/used_item) + var/obj/item/stack/stack = used_item + if(hole_size > NO_HOLE && istype(stack)) + to_chat(user, SPAN_NOTICE("You fit [stack.get_string_for_amount(1)] to damaged areas of \the [src].")) + stack.use(1) + hole_size = NO_HOLE + update_cut_status() + return TRUE + return ..() + + +/obj/structure/fence/attackby(obj/item/used_item, mob/user) + if(IS_WIRECUTTER(used_item)) + if(!cuttable) + to_chat(user, SPAN_WARNING("This section of the fence can't be cut.")) + return TRUE + var/current_stage = hole_size + if(current_stage >= MAX_HOLE_SIZE) + to_chat(user, SPAN_NOTICE("This fence has too much cut out of it already.")) + return TRUE + + if(used_item.do_tool_interaction(TOOL_WIRECUTTERS, user, src, CUT_TIME, "cutting through", "cutting through", check_skill = FALSE) && current_stage == hole_size) // do_tool_interaction sleeps, so make sure it hasn't been cut more while we waited + switch(++hole_size) + if(MEDIUM_HOLE) + user.visible_message( + SPAN_NOTICE("\The [user] cuts into \the [src] some more."), + SPAN_NOTICE("Someone could probably fit through that hole now, although climbing through would be much faster if it were even bigger.") + ) + if(LARGE_HOLE) + user.visible_message( + SPAN_NOTICE("\The [user] completely cuts through \the [src]."), + SPAN_NOTICE("The hole in \the [src] is now big enough to walk through.") + ) + update_cut_status() + return TRUE + return ..() + +/obj/structure/fence/proc/update_cut_status() + if(!cuttable) + return + density = TRUE + + switch(hole_size) + if(NO_HOLE) + icon_state = initial(icon_state) + if(MEDIUM_HOLE) + icon_state = "[initial(icon_state)]-cut2" + if(LARGE_HOLE) + icon_state = "[initial(icon_state)]-cut3" + density = FALSE + +//FENCE DOORS + +/obj/structure/fence/door + name = "fence door" + desc = "Not very useful without a real lock." + icon_state = "door-closed" + cuttable = FALSE + var/open = FALSE + var/locked = FALSE + +/obj/structure/fence/door/Initialize(mapload) + update_door_status() + return ..() + +/obj/structure/fence/door/opened + icon_state = "door-opened" + open = TRUE + density = TRUE + +/obj/structure/fence/door/locked + desc = "It looks like it has a strong padlock attached." + locked = TRUE + +/obj/structure/fence/door/attack_hand(mob/user, list/params) + SHOULD_CALL_PARENT(FALSE) + if(can_open(user)) + toggle(user) + else + to_chat(user, SPAN_WARNING("\The [src] is [!open ? "locked" : "stuck open"].")) + return TRUE + +/obj/structure/fence/door/proc/toggle(mob/user) + switch(open) + if(FALSE) + visible_message(SPAN_NOTICE("\The [user] opens \the [src].")) + open = TRUE + if(TRUE) + visible_message(SPAN_NOTICE("\The [user] closes \the [src].")) + open = FALSE + + update_door_status() + playsound(src, 'sound/machines/click.ogg', 100, 1) + +/obj/structure/fence/door/proc/update_door_status() + switch(open) + if(FALSE) + density = TRUE + icon_state = "door-closed" + if(TRUE) + density = FALSE + icon_state = "door-opened" + +/obj/structure/fence/door/proc/can_open(mob/user) + if(locked) + return FALSE + return TRUE + +#undef CUT_TIME +#undef CLIMB_TIME + +#undef NO_HOLE +#undef MEDIUM_HOLE +#undef LARGE_HOLE +#undef MAX_HOLE_SIZE \ No newline at end of file diff --git a/code/game/objects/structures/fireaxe_cabinet.dm b/code/game/objects/structures/fireaxe_cabinet.dm index 338a89664fab..dc52f5b61153 100644 --- a/code/game/objects/structures/fireaxe_cabinet.dm +++ b/code/game/objects/structures/fireaxe_cabinet.dm @@ -3,23 +3,25 @@ desc = "There is small label that reads \"For Emergency use only\" along with details for safe use of the axe. As if." icon = 'icons/obj/structures/fireaxe.dmi' icon_state = "fireaxe" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' var/damage_threshold = 15 var/open var/unlocked var/shattered - var/obj/item/twohanded/fireaxe/fireaxe + var/obj/item/bladed/axe/fire/fireaxe /obj/structure/fireaxecabinet/on_update_icon() - overlays.Cut() + ..() if(fireaxe) - overlays += image(icon, "fireaxe_item") + add_overlay("fireaxe_item") if(shattered) - overlays += image(icon, "fireaxe_window_broken") + add_overlay("fireaxe_window_broken") else if(!open) - overlays += image(icon, "fireaxe_window") + add_overlay("fireaxe_window") /obj/structure/fireaxecabinet/Initialize() . = ..() @@ -30,73 +32,72 @@ toggle_lock(user) /obj/structure/fireaxecabinet/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() if(!unlocked) - to_chat(user, "\The [src] is locked.") - return - toggle_open(user) - -/obj/structure/fireaxecabinet/MouseDrop(over_object, src_location, over_location) - if(over_object == usr) - var/mob/user = over_object - if(!istype(user)) - return + to_chat(user, SPAN_WARNING("\The [src] is locked.")) + else + toggle_open(user) + return TRUE +/obj/structure/fireaxecabinet/handle_mouse_drop(atom/over, mob/user, params) + if(over == user) if(!open) - to_chat(user, "\The [src] is closed.") - return - + to_chat(user, SPAN_WARNING("\The [src] is closed.")) + return TRUE if(!fireaxe) - to_chat(user, "\The [src] is empty.") - return - + to_chat(user, SPAN_WARNING("\The [src] is empty.")) + return TRUE user.put_in_hands(fireaxe) fireaxe = null update_icon() + return TRUE + . = ..() - return /obj/structure/fireaxecabinet/Destroy() QDEL_NULL(fireaxe) . = ..() -/obj/structure/fireaxecabinet/dismantle() +/obj/structure/fireaxecabinet/dismantle_structure(mob/user) if(loc && !dismantled && !QDELETED(fireaxe)) fireaxe.dropInto(loc) fireaxe = null . = ..() -/obj/structure/fireaxecabinet/attackby(var/obj/item/O, var/mob/user) +/obj/structure/fireaxecabinet/attackby(var/obj/item/used_item, var/mob/user) - if(isMultitool(O)) + if(IS_MULTITOOL(used_item)) toggle_lock(user) - return + return TRUE - if(istype(O, /obj/item/twohanded/fireaxe)) + if(istype(used_item, /obj/item/bladed/axe/fire)) if(open) if(fireaxe) to_chat(user, "There is already \a [fireaxe] inside \the [src].") - else if(user.unEquip(O)) - O.forceMove(src) - fireaxe = O + else if(user.try_unequip(used_item)) + used_item.forceMove(src) + fireaxe = used_item to_chat(user, "You place \the [fireaxe] into \the [src].") update_icon() - return + return TRUE - if(O.force) + var/force = used_item.expend_attack_force(user) + if(force) user.setClickCooldown(10) attack_animation(user) playsound(user, 'sound/effects/Glasshit.ogg', 50, 1) - visible_message("[user] [pick(O.attack_verb)] \the [src]!") - if(damage_threshold > O.force) + visible_message("[user] [used_item.pick_attack_verb()] \the [src]!") + if(damage_threshold > force) to_chat(user, "Your strike is deflected by the reinforced glass!") - return + return TRUE if(shattered) - return + return TRUE shattered = 1 unlocked = 1 open = 1 playsound(user, 'sound/effects/Glassbr3.ogg', 100, 1) update_icon() - return + return TRUE return ..() diff --git a/code/game/objects/structures/fires.dm b/code/game/objects/structures/fires.dm new file mode 100644 index 000000000000..b05b4cfba864 --- /dev/null +++ b/code/game/objects/structures/fires.dm @@ -0,0 +1,598 @@ +// TODO notes: +// - fuel should just be burning atoms when atom fires are in. +// - fire source should just be an interaction and safety wrapper for an atom fire +// ie. all fire behavior comes from the fuel atoms in the fire, but spread and +// click behavior is curtailed by the fire_source. + +#define IDEAL_FUEL 15 +#define HIGH_FUEL (IDEAL_FUEL * 0.65) +#define LOW_FUEL (IDEAL_FUEL * 0.35) + +#define FIRE_LIT 1 +#define FIRE_DEAD -1 +#define FIRE_OUT 0 + +#define FUEL_CONSUMPTION_CONSTANT 0.025 + +/obj/structure/fire_source + name = "firepit" + desc = "Did anyone bring any marshmallows?" + icon = 'icons/obj/structures/fire.dmi' + icon_state = "campfire" + anchored = TRUE + density = FALSE + material = /decl/material/solid/stone/basalt + color = /decl/material/solid/stone/basalt::color + atom_flags = ATOM_FLAG_OPEN_CONTAINER + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + abstract_type = /obj/structure/fire_source + throwpass = TRUE + chem_volume = 100 + + // Counter for world.time, used to reduce lighting spam. + var/next_light_spam_guard = 0 + + var/has_draught = TRUE + var/static/list/draught_values = list( + "all the way open" = 1, + "one-quarter closed" = 0.75, + "half closed" = 0.5, + "three-quarters closed" = 0.25, + "open just a crack" = 0.1, + "all the way closed" = 0 + ) + var/current_draught = 1 + + var/datum/effect/effect/system/steam_spread/steam // Used when being quenched. + var/datum/composite_sound/fire_crackles/fire_loop + var/datum/composite_sound/grill/grill_loop // Used when food is cooking on the fire. + + var/light_range_high = 3 + var/light_range_mid = 2 + var/light_range_low = 1 + var/light_power_high = 0.8 + var/light_power_mid = 0.6 + var/light_power_low = 0.4 + var/light_color_high = "#ffdd55" + var/light_color_mid = "#ff9900" + var/light_color_low = "#ff0000" + + var/list/affected_exterior_turfs + var/last_fuel_burn_temperature = T20C + // TODO: Replace this and the fuel var with just tracking currently-burning matter? + // Or use atom fires when those are implemented? + /// The minimum temperature required to ignite any fuel added. + var/last_fuel_ignite_temperature + var/cap_last_fuel_burn = 850 CELSIUS // Prevent using campfires and stoves as kilns. + var/exterior_temperature = 30 + + /// Are we on fire? + var/lit = FIRE_OUT + /// How much fuel is left? + var/fuel = 0 + /// Have we been fed by a bellows recently? + var/bellows_oxygenation = 0 + +/obj/structure/fire_source/Initialize() + . = ..() + update_icon() + steam = new(name) + steam.attach(get_turf(src)) + steam.set_up(3, 0, get_turf(src)) + fire_loop = new(list(src), FALSE) + grill_loop = new(list(src), FALSE) + if(lit == FIRE_LIT) + try_light(INFINITY, TRUE) + +/obj/structure/fire_source/Destroy() + QDEL_NULL(steam) + STOP_PROCESSING(SSobj, src) + lit = FIRE_DEAD + refresh_affected_exterior_turfs() + QDEL_NULL(fire_loop) + QDEL_NULL(grill_loop) + return ..() + +/obj/structure/fire_source/Move() + . = ..() + if(. && lit == FIRE_LIT) + refresh_affected_exterior_turfs() + +/obj/structure/fire_source/proc/refresh_affected_exterior_turfs() + + if(lit != FIRE_LIT) + for(var/thing in affected_exterior_turfs) + var/turf/T = thing + LAZYREMOVE(T.affecting_heat_sources, src) + affected_exterior_turfs = null + else + var/list/new_affecting + for(var/turf/T as anything in RANGE_TURFS(loc, light_range_high)) + if(T.external_atmosphere_participation) + LAZYADD(new_affecting, T) + for(var/turf/T as anything in affected_exterior_turfs) + if(!(T in new_affecting) || !T.external_atmosphere_participation) + LAZYREMOVE(T.affecting_heat_sources, src) + LAZYREMOVE(affected_exterior_turfs, T) + LAZYREMOVE(new_affecting, T) + for(var/turf/T as anything in new_affecting) + LAZYDISTINCTADD(T.affecting_heat_sources, src) + LAZYDISTINCTADD(affected_exterior_turfs, T) + +/obj/structure/fire_source/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + . = ..() + if(!QDELETED(src)) + try_light(exposed_temperature) + +/obj/structure/fire_source/fluid_act(datum/reagents/fluids) + . = ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids) && reagents) + var/transfer = min(REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents), max(max(1, round(REAGENT_TOTAL_VOLUME(fluids) * 0.25)))) + if(transfer > 0) + fluids.trans_to_obj(src, transfer) + +/obj/structure/fire_source/explosion_act() + . = ..() + if(!QDELETED(src)) + die() + +/obj/structure/fire_source/proc/die() + if(lit == FIRE_LIT) + bellows_oxygenation = 0 + lit = FIRE_DEAD + last_fuel_ignite_temperature = null + last_fuel_burn_temperature = T20C + refresh_affected_exterior_turfs() + visible_message(SPAN_DANGER("\The [src] goes out!")) + STOP_PROCESSING(SSobj, src) + update_icon() + if(fire_loop?.started) + fire_loop.stop(src) + +/obj/structure/fire_source/proc/check_atmos() + var/datum/gas_mixture/GM = loc?.return_air() + for(var/g in GM?.gas) + var/decl/material/oxidizer = GET_DECL(g) + if(oxidizer.gas_flags & XGM_GAS_OXIDIZER) + return TRUE + +/obj/structure/fire_source/proc/try_light(ignition_temperature, force) + if(!check_atmos()) + return FALSE + if(lit == FIRE_LIT && !force) + return FALSE + if(!process_fuel(ignition_temperature)) + if(world.time >= next_light_spam_guard) + visible_message(SPAN_WARNING("\The [src] smoulders, but fails to catch alight. Perhaps it needs better airflow or more fuel?")) + next_light_spam_guard = world.time + 3 SECONDS + return FALSE + last_fuel_burn_temperature = max(last_fuel_burn_temperature, ignition_temperature) // needed for initial burn procs to function + lit = FIRE_LIT + refresh_affected_exterior_turfs() + visible_message(SPAN_DANGER("\The [src] catches alight!")) + START_PROCESSING(SSobj, src) + if(fire_loop && !fire_loop.started) + fire_loop.start(src) + update_icon() + return TRUE + +/obj/structure/fire_source/proc/remove_atom(atom/movable/thing) + if(!QDELETED(thing)) + thing.dropInto(loc) + return TRUE + return FALSE + +/obj/structure/fire_source/proc/get_removable_atoms() + return get_contained_external_atoms() + +/obj/structure/fire_source/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + if(has_draught) + . += "\The [src]'s draught is [draught_values[current_draught]]." + var/list/burn_strings = get_descriptive_temperature_strings(get_effective_burn_temperature()) + if(length(burn_strings)) + . += "\The [src] is burning hot enough to [english_list(burn_strings)]." + var/list/removable = get_removable_atoms() + if(length(removable)) + . += "Looking within \the [src], you see:" + for(var/atom/thing in removable) + . += "\icon[thing] \the [thing]" + else + . += "\The [src] is empty." + + if(check_rights(R_DEBUG, 0, user)) + . += "\The [src] has a temperature of [temperature]K, an effective burn temperature of [get_effective_burn_temperature()]K and a fuel value of [fuel]." + +/obj/structure/fire_source/attack_hand(var/mob/user) + + var/list/removable_atoms = get_removable_atoms() + if(length(removable_atoms) && user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + var/obj/item/removing = pick(removable_atoms) + if(remove_atom(removing)) + user.put_in_hands(removing) + if(lit == FIRE_LIT) + visible_message(SPAN_DANGER("\The [user] fishes \the [removing] out of \the [src]!")) + // Uncomment this when there's a way to take stuff out of a kiln or oven without setting yourself on fire. + //user.fire_act(return_air(), get_effective_burn_temperature(), 500) + else + visible_message(SPAN_NOTICE("\The [user] removes \the [removing] from \the [src].")) + update_icon() + return TRUE + + if(lit != FIRE_LIT && user.check_intent(I_FLAG_HARM)) + to_chat(user, SPAN_DANGER("You start stomping on \the [src], trying to destroy it.")) + if(do_after(user, 5 SECONDS, src)) + visible_message(SPAN_DANGER("\The [user] stamps and kicks at \the [src] until it is completely destroyed.")) + physically_destroyed() + return TRUE + + return ..() + +/obj/structure/fire_source/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(!istype(victim)) + return FALSE + if (!user.check_intent(I_FLAG_HARM)) + return TRUE + if (!grab.force_danger()) + to_chat(user, SPAN_WARNING("You need a better grip!")) + return TRUE + victim.forceMove(get_turf(src)) + SET_STATUS_MAX(victim, STAT_WEAK, 5) + visible_message(SPAN_DANGER("\The [user] hurls \the [victim] onto \the [src]!")) + if(lit == FIRE_LIT) + victim.fire_act(return_air(), get_effective_burn_temperature(), 500) + return TRUE + +/obj/structure/fire_source/isflamesource() + return (lit == FIRE_LIT) + +/obj/structure/fire_source/proc/burn_material(var/decl/material/mat, var/amount) + var/effective_burn_temperature = get_effective_burn_temperature() + var/datum/gas_mixture/environment = return_air() // todo: separate local and burn chamber gas mixes? + var/ambient_pressure = environment ? environment.return_pressure() : ONE_ATMOSPHERE + . = mat.get_burn_products(amount, effective_burn_temperature, ambient_pressure) + if(.) + if(mat.ignition_point && effective_burn_temperature >= mat.ignition_point) + if(mat.accelerant_value > FUEL_VALUE_NONE) + fuel += amount * (1 + material.accelerant_value) + last_fuel_burn_temperature = max(last_fuel_burn_temperature, mat.burn_temperature) + if(isnull(last_fuel_ignite_temperature)) + last_fuel_ignite_temperature = mat.ignition_point + else + last_fuel_ignite_temperature = max(last_fuel_ignite_temperature, mat.ignition_point) + else if(mat.accelerant_value <= FUEL_VALUE_SUPPRESSANT) + // This means that 100u (under two soup bowls full of water), will suppress a fire with 20 fuel. + fuel -= amount * (mat.accelerant_value / FUEL_VALUE_SUPPRESSANT) * 2 + fuel = max(fuel, 0) + loc.take_waste_burn_products(., effective_burn_temperature, ambient_pressure) + +// Dump waste gas from burned fuel. +/obj/structure/fire_source/proc/dump_waste_products(var/atom/target, var/list/waste) + if(istype(target) && length(waste)) + var/datum/gas_mixture/environment = target.return_air() + if(environment) + for(var/w in waste) + if(waste[w] > 0) + environment.adjust_gas(w, waste[w], FALSE) + environment.update_values() + +/obj/structure/fire_source/attackby(var/obj/item/used_item, var/mob/user) + + // Gate a few interactions behind intent so they can be bypassed if needed. + if(!user.check_intent(I_FLAG_HARM)) + // Put cooking items onto the fire source. + if(istype(used_item, /obj/item/chems/cooking_vessel) && user.try_unequip(used_item, get_turf(src))) + used_item.reset_offsets() + return TRUE + // Pour fuel or water into a fire. + if(istype(used_item, /obj/item/chems)) + var/obj/item/chems/chems = used_item + if(chems.standard_pour_into(user, src)) + return TRUE + + if(lit == FIRE_LIT && istype(used_item, /obj/item/flame)) + used_item.fire_act(return_air(), get_effective_burn_temperature(), 500) + return TRUE + + if(used_item.isflamesource()) + visible_message(SPAN_NOTICE("\The [user] attempts to light \the [src] with \the [used_item].")) + try_light(used_item.get_heat()) + return TRUE + + if((lit != FIRE_LIT || user.check_intent(I_FLAG_HARM))) + // Only drop in one log at a time. + if(istype(used_item, /obj/item/stack)) + var/obj/item/stack/stack = used_item + used_item = stack.split(1) + if(!QDELETED(used_item) && user.try_unequip(used_item, src)) + user.visible_message(SPAN_NOTICE("\The [user] drops \the [used_item] into \the [src].")) + update_icon() + return TRUE + + return ..() + +/obj/structure/fire_source/proc/get_draught_multiplier() + . = has_draught ? draught_values[draught_values[current_draught]] : 1 + if(bellows_oxygenation) + . *= 1.25 // Burns 25% hotter while oxygenated. + +/obj/structure/fire_source/proc/process_fuel(ignition_temperature) + var/draught_mult = get_draught_multiplier() + if(draught_mult <= 0) + return FALSE + + if(fuel >= IDEAL_FUEL) + return TRUE + + // Slowly lose burn temperature. + // TODO: use temperature var and equalizing system? + last_fuel_burn_temperature = max(ignition_temperature, last_fuel_burn_temperature) + var/effective_burn_temperature = get_effective_burn_temperature() + if(fuel < LOW_FUEL) // fire's dying + if(effective_burn_temperature > T20C) + last_fuel_burn_temperature = max(T20C, round(last_fuel_burn_temperature * 0.95)) + effective_burn_temperature = get_effective_burn_temperature() + // Just to avoid accidentally snuffing it with the draught, we don't check effective temperature here + if(last_fuel_burn_temperature < last_fuel_ignite_temperature) + return FALSE // kill the fire, too cold to burn additional fuel + + var/list/waste = list() + for(var/obj/item/thing in contents) + var/consumed_item = FALSE + for(var/mat in thing.matter) + var/list/waste_products = burn_material(GET_DECL(mat), MOLES_PER_MATERIAL_UNIT(thing.matter[mat])) + if(!isnull(waste_products)) + for(var/product in waste_products) + waste[product] += waste_products[product] + consumed_item = TRUE + if(consumed_item) + qdel(thing) + if(fuel >= IDEAL_FUEL) + break + + dump_waste_products(loc, waste) + + if(!isnull(cap_last_fuel_burn)) + last_fuel_burn_temperature = min(last_fuel_burn_temperature, cap_last_fuel_burn) + // TODO: dump excess directly into the atmosphere as heat + + return (fuel > 0) + +/obj/structure/fire_source/on_reagent_change() + if(!(. = ..())) + return + if(REAGENT_TOTAL_VOLUME(reagents)) + var/do_steam = FALSE + var/datum/gas_mixture/our_air = return_air() + var/ambient_pressure = our_air ? our_air.return_pressure() : ONE_ATMOSPHERE + var/list/waste = list() + + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + + if(reagent.accelerant_value <= FUEL_VALUE_SUPPRESSANT && reagent.phase_at_temperature(get_effective_burn_temperature(), ambient_pressure) == MAT_PHASE_GAS) + do_steam = TRUE + + var/result_amount = NONUNIT_CEILING(REAGENT_VOLUME(reagents, reagent) / REAGENT_UNITS_PER_GAS_MOLE, 0.1) + var/list/waste_products = burn_material(reagent, result_amount) + if(!isnull(waste_products)) + for(var/product in waste_products) + waste[product] += waste_products[product] + reagents.remove_reagent(reagent.type, result_amount) + + dump_waste_products(loc, waste) + + if(lit == FIRE_LIT && do_steam) + steam.start() // HISSSSSS! + +/obj/structure/fire_source/proc/get_fire_exposed_atoms() + return loc?.get_contained_external_atoms() + +/obj/structure/fire_source/proc/get_effective_burn_temperature() + var/draught_mult = get_draught_multiplier() + if(draught_mult <= 0) + return 0 + var/ambient_temperature = get_ambient_temperature(absolute = TRUE) + // The effective burn temperature can't go below ambient (no cold flames) or above the actual burn temperature. + return clamp((last_fuel_burn_temperature - T0C) * draught_mult + T0C, ambient_temperature, last_fuel_burn_temperature) + +// If absolute == TRUE, return our actual ambient temperature, otherwise return our effective burn temperature when lit. +/obj/structure/fire_source/get_ambient_temperature(absolute = FALSE) + if(absolute || lit != FIRE_LIT) + return ..() // just normal room temperature + return get_effective_burn_temperature() // heat up to our burn temperature + +/obj/structure/fire_source/get_ambient_temperature_coefficient() + if(lit == FIRE_LIT) + return 1 // Don't use the turf coefficient! + return ..() + +/obj/structure/fire_source/ProcessAtomTemperature() + . = ..() + if(lit == FIRE_LIT) + return null // Don't return PROCESS_KILL here, we want to keep the fire going + +/obj/structure/fire_source/Process() + + if(lit != FIRE_LIT) + return PROCESS_KILL + + if(!check_atmos()) + die() + return + + // Spend our bellows charge. + if(bellows_oxygenation > 0) + bellows_oxygenation-- + + fuel -= (FUEL_CONSUMPTION_CONSTANT * get_draught_multiplier()) + if(!process_fuel()) + die() + return + + var/effective_burn_temperature = get_effective_burn_temperature() + + if(isturf(loc)) + var/turf/my_turf = loc + my_turf.hotspot_expose(effective_burn_temperature, 500, 1) + + var/datum/gas_mixture/environment = return_air() + for(var/atom/thing in get_fire_exposed_atoms()) + thing.fire_act(environment, effective_burn_temperature, 500) + + // Copied from space heaters. Heat up the air on our tile, heat will percolate out. + if(environment && abs(environment.temperature - effective_burn_temperature) > 0.1) + var/transfer_moles = 0.25 * environment.total_moles + var/datum/gas_mixture/removed = environment.remove(transfer_moles) + if(removed) + var/heat_transfer = removed.get_thermal_energy_change(round(effective_burn_temperature * 0.1)) + if(heat_transfer > 0) + removed.add_thermal_energy(heat_transfer) + environment.merge(removed) + + queue_icon_update() + +/obj/structure/fire_source/proc/has_fuel() + if(fuel) + return TRUE + if(!length(contents)) + return FALSE + for(var/obj/item/thing in contents) + if(!isnull(thing.material?.ignition_point)) + return TRUE + return FALSE + +/obj/structure/fire_source/on_update_icon() + ..() + + if(has_fuel() && (lit != FIRE_DEAD)) + // todo: get colour from fuel + var/image/I = image(icon, "[icon_state]_full") + I.appearance_flags |= RESET_COLOR | RESET_ALPHA | KEEP_APART + add_overlay(I) + + switch(lit) + if(FIRE_LIT) + if(bellows_oxygenation || fuel >= HIGH_FUEL) + var/image/I = image(icon, "[icon_state]_lit") + I.appearance_flags |= RESET_COLOR | RESET_ALPHA | KEEP_APART + add_overlay(I) + set_light(light_range_high, light_power_high, light_color_high) + else if(fuel > LOW_FUEL) + var/image/I = image(icon, "[icon_state]_lit_low") + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + add_overlay(I) + set_light(light_range_mid, light_power_mid, light_color_mid) + else + var/image/I = image(icon, "[icon_state]_lit_dying") + I.appearance_flags |= RESET_COLOR | RESET_ALPHA | KEEP_APART + add_overlay(I) + set_light(light_range_low, light_power_low, light_color_low) + if(FIRE_DEAD) + var/image/I = image(icon, "[icon_state]_burnt") + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + add_overlay(I) + set_light(0) + else + set_light(0) + +/obj/structure/fire_source/spark_act(obj/effect/sparks/sparks) + try_light(1000) + +/obj/structure/fire_source/CanPass(atom/movable/mover, turf/target, height, air_group) + . = ..() || mover?.checkpass(PASS_FLAG_TABLE) + if(. && lit && ismob(mover)) + var/mob/M = mover + if(M.client && !M.current_posture?.prone && !MOVING_QUICKLY(M)) + to_chat(M, SPAN_WARNING("You refrain from stepping into \the [src].")) + return FALSE + return ..() + +/obj/structure/fire_source/proc/adjust_draught(mob/user) + var/choice = input(user, "How do you wish to adjust the draught?", "Adjust Draught", draught_values[current_draught]) as null|anything in draught_values + if(choice && !QDELETED(src) && !QDELETED(user) && CanPhysicallyInteract(user)) + current_draught = clamp(draught_values.Find(choice), 1, length(draught_values)) + user.visible_message(SPAN_NOTICE("\The [user] adjusts \the [src]'s draught until it is [draught_values[current_draught]].")) + +/obj/structure/fire_source/get_alt_interactions(mob/user) + . = ..() + if(has_draught) + LAZYADD(., /decl/interaction_handler/adjust_draught) + +/decl/interaction_handler/adjust_draught + name = "Adjust Draught" + expected_target_type = /obj/structure/fire_source + examine_desc = "adjust the draught" + +/decl/interaction_handler/adjust_draught/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/fire_source/fire = target + if(fire.has_draught) + fire.adjust_draught(user) + +// Subtypes. +/obj/structure/fire_source/firepit + obj_flags = OBJ_FLAG_HOLLOW + has_draught = FALSE + +/obj/structure/fire_source/firepit/fuelled/Initialize() + new /obj/item/stack/material/log/mapped/wood/fifteen(src) + . = ..() + +/obj/structure/fire_source/stove + name = "stove" + desc = "Just the thing to warm your hands by." + icon_state = "stove" + density = TRUE + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + obj_flags = OBJ_FLAG_HOLLOW + +/obj/structure/fire_source/stove/grab_attack(obj/item/grab/grab, mob/user) + return FALSE + +/obj/structure/fire_source/fireplace + name = "fireplace" + desc = "So cheery!" + icon_state = "fireplace" + density = TRUE + material = /decl/material/solid/stone/pottery // brick + light_range_high = 6 + light_range_mid = 3 + light_range_low = 1 + light_power_high = 0.9 + light_color_high = "#e09d37" + light_color_mid = "#d47b27" + light_color_low = "#e44141" + +/obj/structure/fire_source/fireplace/grab_attack(obj/item/grab/grab, mob/user) + return FALSE + +#define MATERIAL_FIREPLACE(material_name) \ +/obj/structure/fire_source/fireplace/##material_name { \ + color = /decl/material/solid/stone/##material_name::color; \ + material = /decl/material/solid/stone/##material_name; \ +} +MATERIAL_FIREPLACE(basalt) +MATERIAL_FIREPLACE(marble) +MATERIAL_FIREPLACE(granite) +MATERIAL_FIREPLACE(pottery) +#undef MATERIAL_FIREPLACE + +#define MATERIAL_FIREPIT(material_name) \ +/obj/structure/fire_source/firepit/##material_name { \ + color = /decl/material/solid/stone/##material_name::color; \ + material = /decl/material/solid/stone/##material_name; \ +} +MATERIAL_FIREPIT(basalt) +MATERIAL_FIREPIT(marble) +MATERIAL_FIREPIT(granite) +#undef MATERIAL_FIREPIT + +#undef FUEL_CONSUMPTION_CONSTANT +#undef FIRE_LIT +#undef FIRE_DEAD +#undef FIRE_OUT +#undef LOW_FUEL +#undef HIGH_FUEL +#undef IDEAL_FUEL diff --git a/code/game/objects/structures/fishtanks.dm b/code/game/objects/structures/fishtanks.dm index 66f6a7a6ae3a..2e828ed6e803 100644 --- a/code/game/objects/structures/fishtanks.dm +++ b/code/game/objects/structures/fishtanks.dm @@ -1,20 +1,18 @@ -GLOBAL_LIST_INIT(fishtank_cache, new) +var/global/list/fishtank_cache = list() /obj/effect/glass_tank_overlay name = "" - mouse_opacity = 0 - var/obj/structure/glass_tank/AQ + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + var/obj/structure/glass_tank/aquarium -/obj/effect/glass_tank_overlay/Initialize(ml, aquarium) +/obj/effect/glass_tank_overlay/Initialize(ml, _aquarium) . = ..() - AQ = aquarium + aquarium = _aquarium verbs.Cut() /obj/effect/glass_tank_overlay/Destroy() - if(!QDELETED(AQ)) - if(!QDELETED(AQ.AO)) - QDEL_NULL(AQ.AO) - QDEL_NULL(AQ) + if(!QDELETED(aquarium)) + QDEL_NULL(aquarium) . = ..() /obj/structure/glass_tank @@ -22,60 +20,64 @@ GLOBAL_LIST_INIT(fishtank_cache, new) desc = "A clear glass box for keeping specimens in." icon_state = "preview" icon = 'icons/obj/structures/fishtanks.dmi' - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE atom_flags = ATOM_FLAG_CHECKS_BORDER | ATOM_FLAG_CLIMBABLE mob_offset = TRUE - maxhealth = 50 + max_health = 50 + chem_volume = 300 var/deleting var/fill_type - var/fill_amt - var/obj/effect/glass_tank_overlay/AO // I don't like this, but there's no other way to get a mouse-transparent overlay :( + var/obj/effect/glass_tank_overlay/tank_overlay // I don't like this, but there's no other way to get a mouse-transparent overlay :( /obj/structure/glass_tank/aquarium name = "aquarium" desc = "A clear glass box for keeping specimens in. This one is full of water." fill_type = /decl/material/liquid/water - fill_amt = 300 -/obj/structure/glass_tank/Initialize() +/obj/structure/glass_tank/Initialize(mapload) + tank_overlay = new(loc, src) . = ..() - initial_fill() - AO = new(loc, src) - update_icon(1) + update_icon() + if(!mapload) + update_nearby_tiles() /obj/structure/glass_tank/Destroy() - if(!QDELETED(AO)) - QDEL_NULL(AO) + if(!QDELETED(tank_overlay)) + QDEL_NULL(tank_overlay) var/oldloc = loc . = ..() for(var/obj/structure/glass_tank/A in orange(1, oldloc)) A.update_icon() -/obj/structure/glass_tank/proc/initial_fill() - if(fill_type && fill_amt) - create_reagents(fill_amt) - reagents.add_reagent(fill_type, fill_amt) +/obj/structure/glass_tank/populate_reagents() + if(fill_type) + add_to_reagents(fill_type, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/structure/glass_tank/attack_hand(var/mob/user) + if(user.check_intent(I_FLAG_HARM)) + return ..() visible_message(SPAN_NOTICE("\The [user] taps on \the [src].")) + return TRUE -/obj/structure/glass_tank/attackby(var/obj/item/W, var/mob/user) - if(W.force < 5 || user.a_intent != I_HURT) +/obj/structure/glass_tank/attackby(var/obj/item/used_item, var/mob/user) + if(used_item.get_attack_force(user) < 5 || !user.check_intent(I_FLAG_HARM)) attack_animation(user) - visible_message(SPAN_NOTICE("\The [user] taps \the [src] with \the [W].")) + visible_message(SPAN_NOTICE("\The [user] taps \the [src] with \the [used_item].")) else . = ..() /obj/structure/glass_tank/physically_destroyed(var/silent) SHOULD_CALL_PARENT(FALSE) - deleting = 1 + deleting = TRUE var/turf/T = get_turf(src) playsound(T, "shatter", 70, 1) - new /obj/item/shard(T) + var/obj/item/shard/shard = new(T) + if(paint_color) + shard.set_color(paint_color) if(!silent) - if(contents.len || reagents.total_volume) + if(contents.len || REAGENT_TOTAL_VOLUME(reagents)) visible_message(SPAN_DANGER("\The [src] shatters, spilling its contents everywhere!")) else visible_message(SPAN_DANGER("\The [src] shatters!")) @@ -85,84 +87,86 @@ GLOBAL_LIST_INIT(fishtank_cache, new) A.physically_destroyed(TRUE) qdel(src) -/obj/structure/glass_tank/dump_contents() +/obj/structure/glass_tank/dump_contents(atom/forced_loc = loc, mob/user) . = ..() - if(reagents && reagents.total_volume) - var/turf/T = get_turf(src) - var/obj/effect/fluid/F = locate() in T - if(!F) F = new(T) - reagents.trans_to_holder(F.reagents, reagents.total_volume) + var/turf/T = get_turf(forced_loc) + if(REAGENT_TOTAL_VOLUME(reagents) && T) + reagents.trans_to_turf(T, REAGENT_TOTAL_VOLUME(reagents)) -GLOBAL_LIST_INIT(aquarium_states_and_layers, list( +var/global/list/global/aquarium_states_and_layers = list( "b" = FLY_LAYER - 0.02, "w" = FLY_LAYER - 0.01, "f" = FLY_LAYER, "z" = FLY_LAYER + 0.01 -)) +) -/obj/structure/glass_tank/on_update_icon(propagate = 0) +/obj/structure/glass_tank/update_nearby_tiles(need_rebuild) + . = ..() + for(var/obj/structure/glass_tank/tank in orange(1, src)) + if(tank.type != type) + continue + tank.update_icon() + +/obj/structure/glass_tank/on_update_icon() var/list/connect_dirs = list() - for(var/obj/structure/glass_tank/A in orange(1, src)) - if(A.type == type) - connect_dirs |= get_dir(src, A) + for(var/obj/structure/glass_tank/tank in orange(1, src)) + if(tank.type != type) + continue + connect_dirs |= get_dir(src, tank) var/list/c_states = dirs_to_unified_corner_states(connect_dirs) - icon_state = "base" - var/new_overlays - for(var/i = 1 to 4) - for(var/key_mod in GLOB.aquarium_states_and_layers) - if(key_mod == "w" && (!reagents || !reagents.total_volume)) - continue - var/cache_key = "[c_states[i]][key_mod]-[i]" - if(!GLOB.fishtank_cache[cache_key]) - var/image/I = image(icon, icon_state = "[c_states[i]][key_mod]", dir = 1 << (i-1)) - if(GLOB.aquarium_states_and_layers[key_mod]) - I.layer = GLOB.aquarium_states_and_layers[key_mod] - GLOB.fishtank_cache[cache_key] = I - LAZYADD(new_overlays, GLOB.fishtank_cache[cache_key]) - AO.overlays = new_overlays + if(tank_overlay) + tank_overlay.cut_overlays() + for(var/i = 1 to 4) + for(var/key_mod in global.aquarium_states_and_layers) + if(key_mod == "w" && (!reagents || !REAGENT_TOTAL_VOLUME(reagents))) + continue + var/cache_key = "[c_states[i]][key_mod]-[i]" + if(!global.fishtank_cache[cache_key]) + var/image/I = image(icon, icon_state = "[c_states[i]][key_mod]", dir = BITFLAG(i-1)) + if(global.aquarium_states_and_layers[key_mod]) + I.layer = global.aquarium_states_and_layers[key_mod] + global.fishtank_cache[cache_key] = I + tank_overlay.add_overlay(global.fishtank_cache[cache_key]) // Update overlays with contents. - new_overlays = null - for(var/atom/movable/AM in contents) - if(AM.simulated) - LAZYADD(new_overlays, AM) - overlays = new_overlays - - if(propagate) - for(var/obj/structure/glass_tank/A in orange(1, src)) - if(A.type == type) - A.update_icon() - -/obj/structure/glass_tank/can_climb(var/mob/living/user, post_climb_check=0) - if (!user.can_touch(src) || !(atom_flags & ATOM_FLAG_CLIMBABLE) || (!post_climb_check && (user in climbers))) - return 0 + // TODO: Can this just use vis_contents...? + // Or add its contents to vis_contents on some sort of helper atom, + // which has the VIS_UNDERLAY flag so it shows up under the transparent part? + icon_state = "base" + ..() + for(var/atom/movable/AM in get_contained_external_atoms()) + add_overlay(AM) +/obj/structure/glass_tank/can_climb(mob/living/user, post_climb_check = FALSE, silent = FALSE) + if (!user.can_touch(src) || !(atom_flags & ATOM_FLAG_CLIMBABLE) || (!post_climb_check && (user in climbers))) + return FALSE if (!Adjacent(user)) - to_chat(user, SPAN_DANGER("You can't climb there, the way is blocked.")) - return 0 - + if(!silent) + to_chat(user, SPAN_WARNING("You can't climb there, the way is blocked.")) + return FALSE var/obj/occupied = turf_is_crowded() if(occupied) - to_chat(user, SPAN_DANGER("There's \a [occupied] in the way.")) - return 0 - return 1 + if(!silent) + to_chat(user, SPAN_WARNING("There's \a [occupied] in the way.")) + return FALSE + return TRUE /obj/structure/glass_tank/do_climb(var/mob/living/user) - if (!can_climb(user)) + if(!istype(user) || !can_climb(user)) return - usr.visible_message(SPAN_WARNING("\The [user] starts climbing into \the [src]!")) - if(!do_after(user,50)) + user.visible_message(SPAN_WARNING("\The [user] starts climbing into \the [src]!")) + if(!do_after(user, 5 SECONDS)) return if (!can_climb(user)) return - usr.forceMove(src.loc) + user.forceMove(src.loc) if (get_turf(user) == get_turf(src)) - usr.visible_message(SPAN_WARNING("\The [user] climbs into \the [src]!")) + user.visible_message(SPAN_WARNING("\The [user] climbs into \the [src]!")) /obj/structure/glass_tank/verb/climb_out() set name = "Climb Out Of Tank" - set desc = "Climbs out of a fishtank." + set desc = "Climbs out of a tank." set category = "Object" set src in oview(0) // Same turf. @@ -171,7 +175,7 @@ GLOBAL_LIST_INIT(aquarium_states_and_layers, list( var/list/valid_turfs = list() - for(var/turf/T in orange(1)) + for(var/turf/T as anything in RANGE_TURFS(loc, 1)) if(Adjacent(T) && !(locate(/obj/structure/glass_tank) in T)) valid_turfs |= T @@ -180,27 +184,18 @@ GLOBAL_LIST_INIT(aquarium_states_and_layers, list( else to_chat(usr, SPAN_WARNING("There's nowhere to climb out to!")) -/mob/living/MouseDrop(atom/over) - if(usr == src && isturf(over)) - var/turf/T = over - var/obj/structure/glass_tank/A = locate() in usr.loc - if(A && A.Adjacent(usr) && A.Adjacent(T)) - A.do_climb_out(usr, T) - return - return ..() - /obj/structure/glass_tank/proc/do_climb_out(mob/living/user, turf/target) if(get_turf(user) != get_turf(src)) return if(!Adjacent(target)) return - usr.visible_message(SPAN_WARNING("\The [user] starts climbing out of \the [src]!")) + user.visible_message(SPAN_WARNING("\The [user] starts climbing out of \the [src]!")) if(!do_after(user,50)) return if (!Adjacent(target)) return - usr.forceMove(target) - usr.visible_message(SPAN_WARNING("\The [user] climbs out of \the [src]!")) + user.forceMove(target) + user.visible_message(SPAN_WARNING("\The [user] climbs out of \the [src]!")) /obj/structure/glass_tank/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) . = locate(/obj/structure/glass_tank) in (target == loc) ? (mover && mover.loc) : target diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm index 49465f742b46..f467fab29b45 100644 --- a/code/game/objects/structures/fitness.dm +++ b/code/game/objects/structures/fitness.dm @@ -1,5 +1,5 @@ /obj/structure/fitness - anchored = 1 + anchored = TRUE var/being_used = 0 /obj/structure/fitness/punchingbag @@ -7,26 +7,30 @@ desc = "A punching bag." icon_state = "punchingbag" icon = 'icons/obj/structures/punching_bag.dmi' - density = 1 + density = TRUE var/list/hit_message = list("hit", "punch", "kick", "robust") -/obj/structure/fitness/punchingbag/attack_hand(var/mob/living/carbon/human/user) - if(!istype(user)) - ..() - return - var/synth = user.isSynthetic() - if(!synth && user.nutrition < 20) - to_chat(user, "You need more energy to use the punching bag. Go eat something.") - else - if(user.a_intent == I_HURT) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - flick("[icon_state]_hit", src) - playsound(src.loc, 'sound/effects/woodhit.ogg', 25, 1, -1) - user.do_attack_animation(src) - if(!synth) - user.adjust_nutrition(-(5 * DEFAULT_HUNGER_FACTOR)) - user.adjust_hydration(-(5 * DEFAULT_THIRST_FACTOR)) - to_chat(user, "You [pick(hit_message)] \the [src].") +/obj/structure/fitness/punchingbag/attack_hand(mob/user) + if(!ishuman(user)) + return ..() + + var/mob/living/human/H = user + var/synth = H.isSynthetic() + if(!synth && H.nutrition < 20) + to_chat(H, SPAN_WARNING("You [synth ? "need more energy" : "are too tired"] to use the punching bag. Go [synth ? "recharge" : "eat something"].")) + return TRUE + + if(H.check_intent(I_FLAG_HARM)) + H.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + flick("[icon_state]_hit", src) + playsound(src.loc, 'sound/effects/woodhit.ogg', 25, 1, -1) + H.do_attack_animation(src) + if(!synth) + H.adjust_nutrition(-(5 * DEFAULT_HUNGER_FACTOR)) + H.adjust_hydration(-(5 * DEFAULT_THIRST_FACTOR)) + to_chat(H, SPAN_NOTICE("You [pick(hit_message)] \the [src].")) + return TRUE + return ..() /obj/structure/fitness/weightlifter name = "weightlifting machine" @@ -38,52 +42,61 @@ var/list/success_message = list("with great effort", "straining hard", "without any trouble", "with ease") var/list/fail_message = list(", lifting them part of the way and then letting them drop", ", unable to even budge them") -/obj/structure/fitness/weightlifter/attackby(obj/item/W, mob/user) - if(isWrench(W)) +/obj/structure/fitness/weightlifter/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1) weight = (weight % max_weight) + 1 to_chat(user, "You set the machine's weight level to [weight].") + return TRUE + return ..() -/obj/structure/fitness/weightlifter/attack_hand(var/mob/living/carbon/human/user) - if(!istype(user)) - return - var/synth = user.isSynthetic() - if(user.loc != src.loc) - to_chat(user, "You must be on the weight machine to use it.") - return - if(!synth && user.nutrition < 50) - to_chat(user, "You need more energy to lift weights. Go eat something.") - return +/obj/structure/fitness/weightlifter/attack_hand(mob/user) + if(!ishuman(user)) + return ..() + var/mob/living/human/H = user + var/synth = H.isSynthetic() + if(H.loc != src.loc) + to_chat(H, SPAN_WARNING("You must be on the weight machine to use it.")) + return TRUE + if(!synth && H.nutrition < 50) + to_chat(H, SPAN_WARNING("You need more energy to lift weights. Go eat something.")) + return TRUE if(being_used) - to_chat(user, "The weight machine is already in use by somebody else.") - return - else - being_used = 1 - playsound(src.loc, 'sound/effects/weightlifter.ogg', 50, 1) - user.set_dir(SOUTH) - flick("[icon_state]_[weight]", src) - if(do_after(user, 20 + (weight * 10))) - playsound(src.loc, 'sound/effects/weightdrop.ogg', 25, 1) - var/skill = max_weight * user.get_skill_value(SKILL_HAULING)/SKILL_MAX - var/message - if(skill < weight) - if(weight - skill > max_weight/2) - if(prob(50)) - message = ", getting hurt in the process" - user.apply_damage(5) - else - message = "; this does not look safe" - else - message = fail_message[min(1 + round(weight - skill), fail_message.len)] - user.visible_message("\The [user] fails to lift the weights[message].", "You fail to lift the weights[message].") + to_chat(H, SPAN_WARNING("The weight machine is already in use by somebody else.")) + return TRUE + + being_used = TRUE + playsound(src.loc, 'sound/effects/weightlifter.ogg', 50, 1) + H.set_dir(SOUTH) + flick("[icon_state]_[weight]", src) + if(!do_after(H, 20 + (weight * 10))) + to_chat(H, SPAN_NOTICE("Against your previous judgement, perhaps working out is not for you.")) + being_used = FALSE + return TRUE + + playsound(src.loc, 'sound/effects/weightdrop.ogg', 25, 1) + var/skill = max_weight * H.get_skill_value(SKILL_HAULING)/SKILL_MAX + var/message + if(skill < weight) + if(weight - skill > max_weight/2) + if(prob(50)) + message = ", getting hurt in the process" + H.apply_damage(5) else - if(!synth) - var/adj_weight = weight * 5 - user.adjust_nutrition(-(adj_weight * DEFAULT_HUNGER_FACTOR)) - user.adjust_hydration(-(adj_weight * DEFAULT_THIRST_FACTOR)) - message = success_message[min(1 + round(skill - weight), fail_message.len)] - user.visible_message("\The [user] lift\s the weights [message].", "You lift the weights [message].") - being_used = 0 + message = "; this does not look safe" else - to_chat(user, "Against your previous judgement, perhaps working out is not for you.") - being_used = 0 + message = fail_message[min(1 + round(weight - skill), fail_message.len)] + H.visible_message( \ + SPAN_NOTICE("\The [H] fails to lift the weights[message]."), \ + SPAN_NOTICE("You fail to lift the weights[message].")) + else + if(!synth) + var/adj_weight = weight * 5 + H.adjust_nutrition(-(adj_weight * DEFAULT_HUNGER_FACTOR)) + H.adjust_hydration(-(adj_weight * DEFAULT_THIRST_FACTOR)) + message = success_message[min(1 + round(skill - weight), fail_message.len)] + H.visible_message( \ + SPAN_NOTICE("\The [H] lift\s the weights [message]."), \ + SPAN_NOTICE("You lift the weights [message].")) + being_used = FALSE + return TRUE diff --git a/code/game/objects/structures/flaps.dm b/code/game/objects/structures/flaps.dm new file mode 100644 index 000000000000..06ba909c7b45 --- /dev/null +++ b/code/game/objects/structures/flaps.dm @@ -0,0 +1,92 @@ +/obj/structure/flaps + name = "flaps" + desc = "A set of thin, dangling flaps. Completely impassable - or are they?" + icon = 'icons/obj/structures/plastic_flaps.dmi' + icon_state = "plasticflaps" + density = FALSE + anchored = TRUE + layer = ABOVE_HUMAN_LAYER + explosion_resistance = 5 + material = /decl/material/solid/organic/plastic + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + + obj_flags = OBJ_FLAG_ANCHORABLE + + var/list/mobs_can_pass = list( + /mob/living/bot, + /mob/living/simple_animal/passive/mouse, + /mob/living/silicon/robot/drone + ) + var/airtight = FALSE + var/can_pass_lying = TRUE + +/obj/structure/flaps/CanPass(atom/A, turf/T) + if(istype(A) && A.checkpass(PASS_FLAG_GLASS)) + return prob(60) + + var/atom/movable/moving_movable = A + if (ismovable(A) && moving_movable.buckled_mob)//if someone is buckled, it will not pass + return 0 + + if(istype(A, /obj/vehicle)) //no vehicles + return 0 + + var/mob/living/M = A + if(istype(M)) + if(M.current_posture.prone && can_pass_lying) + return ..() + for(var/mob_type in mobs_can_pass) + if(istype(A, mob_type)) + return ..() + return issmall(M) + + return ..() + +/obj/structure/flaps/attackby(obj/item/used_item, mob/user) + if(IS_CROWBAR(used_item) && !anchored) + user.visible_message("\The [user] begins deconstructing \the [src].", "You start deconstructing \the [src].") + if(user.do_skilled(3 SECONDS, SKILL_CONSTRUCTION, src)) + user.visible_message("\The [user] deconstructs \the [src].", "You deconstruct \the [src].") + qdel(src) + return TRUE + if(IS_SCREWDRIVER(used_item) && anchored) + airtight = !airtight + airtight ? become_airtight() : clear_airtight() + user.visible_message("\The [user] adjusts \the [src], [airtight ? "preventing" : "allowing"] air flow.") + return TRUE + else + return ..() + +/obj/structure/flaps/explosion_act(severity) + ..() + if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) + physically_destroyed() + +/obj/structure/flaps/Initialize() + . = ..() + if(airtight) + become_airtight() + +/obj/structure/flaps/Destroy() //lazy hack to set the turf to allow air to pass if it's a simulated floor + if(airtight) + clear_airtight() + . = ..() + +/obj/structure/flaps/proc/become_airtight() + atmos_canpass = CANPASS_NEVER + update_nearby_tiles() + +/obj/structure/flaps/proc/clear_airtight() + atmos_canpass = CANPASS_ALWAYS + update_nearby_tiles() + +/obj/structure/flaps/airtight // airtight defaults to on + airtight = TRUE + +/obj/structure/flaps/animal + name = "animal access flaps" // doggy door + airtight = TRUE + can_pass_lying = FALSE + mobs_can_pass = list( + /mob/living/simple_animal + ) \ No newline at end of file diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm deleted file mode 100644 index 73daebd1047f..000000000000 --- a/code/game/objects/structures/flora.dm +++ /dev/null @@ -1,366 +0,0 @@ -//trees -/obj/structure/flora/tree - name = "tree" - anchored = 1 - density = 1 - pixel_x = -16 - layer = ABOVE_HUMAN_LAYER - -/obj/structure/flora/tree/pine - name = "pine tree" - icon = 'icons/obj/flora/pinetrees.dmi' - icon_state = "pine_1" - -/obj/structure/flora/tree/pine/Initialize() - . = ..() - icon_state = "pine_[rand(1, 3)]" - -/obj/structure/flora/tree/pine/xmas - name = "\improper Christmas tree" - desc = "O Christmas tree, O Christmas tree..." - icon = 'icons/obj/flora/pinetrees.dmi' - icon_state = "pine_c" - -/obj/structure/flora/tree/pine/xmas/Initialize() - . = ..() - icon_state = "pine_c" - -/obj/structure/flora/tree/dead - icon = 'icons/obj/flora/deadtrees.dmi' - icon_state = "tree_1" - -/obj/structure/flora/tree/dead/Initialize() - . = ..() - icon_state = "tree_[rand(1, 6)]" - - -//grass -/obj/structure/flora/grass - name = "grass" - icon = 'icons/obj/flora/snowflora.dmi' - anchored = 1 - -/obj/structure/flora/grass/brown - icon_state = "snowgrass1bb" - -/obj/structure/flora/grass/brown/Initialize() - . = ..() - icon_state = "snowgrass[rand(1, 3)]bb" - - -/obj/structure/flora/grass/green - icon_state = "snowgrass1gb" - -/obj/structure/flora/grass/green/Initialize() - . = ..() - icon_state = "snowgrass[rand(1, 3)]gb" - -/obj/structure/flora/grass/both - icon_state = "snowgrassall1" - -/obj/structure/flora/grass/both/Initialize() - . = ..() - icon_state = "snowgrassall[rand(1, 3)]" - - -//bushes -/obj/structure/flora/bush - name = "bush" - icon = 'icons/obj/flora/snowflora.dmi' - icon_state = "snowbush1" - anchored = 1 - -/obj/structure/flora/bush/Initialize() - . = ..() - icon_state = "snowbush[rand(1, 6)]" - -/obj/structure/flora/pottedplant - name = "potted plant" - icon = 'icons/obj/structures/potted_plants.dmi' - icon_state = "plant-26" - layer = ABOVE_HUMAN_LAYER - -//newbushes - -/obj/structure/flora/ausbushes - name = "bush" - icon = 'icons/obj/flora/ausflora.dmi' - icon_state = "firstbush_1" - anchored = 1 - -/obj/structure/flora/ausbushes/Initialize() - . = ..() - icon_state = "firstbush_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/reedbush - icon_state = "reedbush_1" - -/obj/structure/flora/ausbushes/reedbush/Initialize() - . = ..() - icon_state = "reedbush_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/leafybush - icon_state = "leafybush_1" - -/obj/structure/flora/ausbushes/leafybush/Initialize() - . = ..() - icon_state = "leafybush_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/palebush - icon_state = "palebush_1" - -/obj/structure/flora/ausbushes/palebush/Initialize() - . = ..() - icon_state = "palebush_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/stalkybush - icon_state = "stalkybush_1" - -/obj/structure/flora/ausbushes/stalkybush/Initialize() - . = ..() - icon_state = "stalkybush_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/grassybush - icon_state = "grassybush_1" - -/obj/structure/flora/ausbushes/grassybush/Initialize() - . = ..() - icon_state = "grassybush_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/fernybush - icon_state = "fernybush_1" - -/obj/structure/flora/ausbushes/fernybush/Initialize() - . = ..() - icon_state = "fernybush_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/sunnybush - icon_state = "sunnybush_1" - -/obj/structure/flora/ausbushes/sunnybush/Initialize() - . = ..() - icon_state = "sunnybush_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/genericbush - icon_state = "genericbush_1" - -/obj/structure/flora/ausbushes/genericbush/Initialize() - . = ..() - icon_state = "genericbush_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/pointybush - icon_state = "pointybush_1" - -/obj/structure/flora/ausbushes/pointybush/Initialize() - . = ..() - icon_state = "pointybush_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/lavendergrass - icon_state = "lavendergrass_1" - -/obj/structure/flora/ausbushes/lavendergrass/Initialize() - . = ..() - icon_state = "lavendergrass_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/ywflowers - icon_state = "ywflowers_1" - -/obj/structure/flora/ausbushes/ywflowers/Initialize() - . = ..() - icon_state = "ywflowers_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/brflowers - icon_state = "brflowers_1" - -/obj/structure/flora/ausbushes/brflowers/Initialize() - . = ..() - icon_state = "brflowers_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/ppflowers - icon_state = "ppflowers_1" - -/obj/structure/flora/ausbushes/ppflowers/Initialize() - . = ..() - icon_state = "ppflowers_[rand(1, 4)]" - -/obj/structure/flora/ausbushes/sparsegrass - icon_state = "sparsegrass_1" - -/obj/structure/flora/ausbushes/sparsegrass/Initialize() - . = ..() - icon_state = "sparsegrass_[rand(1, 3)]" - -/obj/structure/flora/ausbushes/fullgrass - icon_state = "fullgrass_1" - -/obj/structure/flora/ausbushes/fullgrass/Initialize() - . = ..() - icon_state = "fullgrass_[rand(1, 3)]" - - -//potted plants credit: Flashkirby -//potted plants 27-30: Cajoes -/obj/structure/flora/pottedplant - name = "potted plant" - desc = "Really brings the room together." - icon = 'icons/obj/structures/potted_plants.dmi' - icon_state = "plant-01" - layer = ABOVE_HUMAN_LAYER - -/obj/structure/flora/pottedplant/fern - name = "potted fern" - desc = "This is an ordinary looking fern. It looks like it could do with some water." - icon_state = "plant-02" - -/obj/structure/flora/pottedplant/overgrown - name = "overgrown potted plants" - desc = "This is an assortment of colourful plants. Some parts are overgrown." - icon_state = "plant-03" - -/obj/structure/flora/pottedplant/bamboo - name = "potted bamboo" - desc = "These are bamboo shoots. The tops looks like they've been cut short." - icon_state = "plant-04" - -/obj/structure/flora/pottedplant/largebush - name = "large potted bush" - desc = "This is a large bush. The leaves stick upwards in an odd fashion." - icon_state = "plant-05" - -/obj/structure/flora/pottedplant/thinbush - name = "thin potted bush" - desc = "This is a thin bush. It appears to be flowering." - icon_state = "plant-06" - -/obj/structure/flora/pottedplant/mysterious - name = "mysterious potted bulbs" - desc = "This is a mysterious looking plant. Touching the bulbs cause them to shrink." - icon_state = "plant-07" - -/obj/structure/flora/pottedplant/smalltree - name = "small potted tree" - desc = "This is a small tree. It is rather pleasant." - icon_state = "plant-08" - -/obj/structure/flora/pottedplant/unusual - name = "unusual potted plant" - desc = "This is an unusual plant. It's bulbous ends emit a soft blue light." - icon_state = "plant-09" - -/obj/structure/flora/pottedplant/unusual/Initialize() - . = ..() - set_light(0.4, 0.1, 2, 2, "#007fff") - -/obj/structure/flora/pottedplant/orientaltree - name = "potted oriental tree" - desc = "This is a rather oriental style tree. It's flowers are bright pink." - icon_state = "plant-10" - -/obj/structure/flora/pottedplant/smallcactus - name = "small potted cactus" - desc = "This is a small cactus. Its needles are sharp." - icon_state = "plant-11" - -/obj/structure/flora/pottedplant/tall - name = "tall potted plant" - desc = "This is a tall plant. Tiny pores line its surface." - icon_state = "plant-12" - -/obj/structure/flora/pottedplant/sticky - name = "sticky potted plant" - desc = "This is an odd plant. Its sticky leaves trap insects." - icon_state = "plant-13" - -/obj/structure/flora/pottedplant/smelly - name = "smelly potted plant" - desc = "This is some kind of tropical plant. It reeks of rotten eggs." - icon_state = "plant-14" - -/obj/structure/flora/pottedplant/small - name = "small potted plant" - desc = "This is a pot of assorted small flora. Some look familiar." - icon_state = "plant-15" - -/obj/structure/flora/pottedplant/aquatic - name = "aquatic potted plant" - desc = "This is apparently an aquatic plant. It's probably fake." - icon_state = "plant-16" - -/obj/structure/flora/pottedplant/shoot - name = "small potted shoot" - desc = "This is a small shoot. It still needs time to grow." - icon_state = "plant-17" - -/obj/structure/flora/pottedplant/flower - name = "potted flower" - desc = "This is a slim plant. Sweet smelling flowers are supported by spindly stems." - icon_state = "plant-18" - -/obj/structure/flora/pottedplant/crystal - name = "crystalline potted plant" - desc = "These are rather cubic plants. Odd crystal formations grow on the end." - icon_state = "plant-19" - -/obj/structure/flora/pottedplant/subterranean - name = "subterranean potted plant" - desc = "This is a subterranean plant. It's bulbous ends glow faintly." - icon_state = "plant-20" - -/obj/structure/flora/pottedplant/subterranean/Initialize() - . = ..() - set_light(0.4, 0.1, 2, 2, "#ff6633") - -/obj/structure/flora/pottedplant/minitree - name = "potted tree" - desc = "This is a miniature tree. Apparently it was grown to 1/5 scale." - icon_state = "plant-21" - -/obj/structure/flora/pottedplant/stoutbush - name = "stout potted bush" - desc = "This is a stout bush. Its leaves point up and outwards." - icon_state = "plant-22" - -/obj/structure/flora/pottedplant/drooping - name = "drooping potted plant" - desc = "This is a small plant. The drooping leaves make it look like its wilted." - icon_state = "plant-23" - -/obj/structure/flora/pottedplant/tropical - name = "tropical potted plant" - desc = "This is some kind of tropical plant. It hasn't begun to flower yet." - icon_state = "plant-24" - -/obj/structure/flora/pottedplant/dead - name = "dead potted plant" - desc = "This is the dried up remains of a dead plant. Someone should replace it." - icon_state = "plant-25" - -/obj/structure/flora/pottedplant/large - name = "large potted plant" - desc = "This is a large plant. Three branches support pairs of waxy leaves." - icon_state = "plant-26" - -/obj/structure/flora/pottedplant/decorative - name = "decorative potted plant" - desc = "This is a decorative shrub. It's been trimmed into the shape of an apple." - icon_state = "applebush" - -/obj/structure/flora/pottedplant/deskfern - name = "fancy ferny potted plant" - desc = "This leafy desk fern could do with a trim." - icon_state = "plant-27" - -/obj/structure/flora/pottedplant/floorleaf - name = "fancy leafy floor plant" - desc = "This plant has remarkably waxy leaves." - icon_state = "plant-28" - -/obj/structure/flora/pottedplant/deskleaf - name = "fancy leafy potted desk plant" - desc = "A tiny waxy leafed plant specimen." - icon_state = "plant-29" - -/obj/structure/flora/pottedplant/deskferntrim - name = "fancy trimmed ferny potted plant" - desc = "This leafy desk fern seems to have been trimmed too much." - icon_state = "plant-30" \ No newline at end of file diff --git a/code/game/objects/structures/flora/_flora.dm b/code/game/objects/structures/flora/_flora.dm new file mode 100644 index 000000000000..a7bcda669ec2 --- /dev/null +++ b/code/game/objects/structures/flora/_flora.dm @@ -0,0 +1,77 @@ +//////////////////////////////////////// +// Base Flora +//////////////////////////////////////// +/obj/structure/flora + desc = "A form of vegetation." + anchored = TRUE + density = FALSE //Plants usually have no collisions + w_class = ITEM_SIZE_NORMAL //Size determines material yield + material = /decl/material/solid/organic/plantmatter //Generic plantstuff + tool_interaction_flags = 0 + hitsound = 'sound/effects/hit_bush.ogg' + var/tmp/snd_cut = 'sound/effects/plants/brush_leaves.ogg' //Sound to play when cutting the plant down + var/remains_type = /obj/effect/decal/cleanable/plant_bits //What does the plant leaves behind in addition to the materials its made out of. (part_type is like this, but it drops instead of materials) + +/obj/structure/flora/Initialize(ml, _mat, _reinf_mat) + . = ..() + init_appearance() + +/**Picks and sets the appearance exactly once for the plant if randomly picked. */ +/obj/structure/flora/proc/init_appearance() + return + +// We rely on overrides to spawn appropriate materials for flora structures. +/obj/structure/flora/create_dismantled_products(turf/T) + clear_materials() + return ..() + +/obj/structure/flora/attackby(obj/item/used_item, mob/user) + if(!user.check_intent(I_FLAG_HARM) && can_cut_down(used_item, user)) + play_cut_sound(user) + cut_down(used_item, user) + return TRUE + . = ..() + +/**Whether the item used by user can cause cut_down to be called. Used to bypass default attack proc for some specific items/tools. */ +/obj/structure/flora/proc/can_cut_down(var/obj/item/used_item, var/mob/user) + return (used_item.expend_attack_force(user) >= 5) && used_item.is_sharp() //Anything sharp and relatively strong can cut us instantly + +/**What to do when the can_cut_down check returns true. Normally simply calls dismantle. */ +/obj/structure/flora/proc/play_cut_sound(mob/user) + set waitfor = FALSE + if(snd_cut) + playsound(src, snd_cut, 40, TRUE) + +/obj/structure/flora/proc/cut_down(var/obj/item/used_item, var/mob/user) + dismantle_structure(user) + return TRUE + +//Drop some bits when destroyed +/obj/structure/flora/physically_destroyed(skip_qdel) + if(!..(TRUE)) //Tell parents we'll delete ourselves + return + var/turf/T = get_turf(src) + if(T) + . = !isnull(create_remains()) + if(snd_cut) + playsound(src, snd_cut, 60, TRUE) + //qdel only after we do our thing, since we have to access members + if(!skip_qdel) + qdel(src) + +/**Returns an instance of the object the plant leaves behind when destroyed. Null means it leaves nothing. */ +/obj/structure/flora/proc/create_remains() + var/obj/item/remains = new remains_type(get_turf(src), material, reinf_material) + if((istype(remains) || istype(remains, /obj/structure)) && paint_color) + remains.set_color(paint_color) + return remains + +//////////////////////////////////////// +// Floral Remains +//////////////////////////////////////// +/obj/effect/decal/cleanable/plant_bits + name = "plant remains" + icon = 'icons/effects/decals/plant_remains.dmi' + icon_state = "leafy_bits" + cleanable_scent = "freshly cut plants" + sweepable = TRUE diff --git a/code/game/objects/structures/flora/bush.dm b/code/game/objects/structures/flora/bush.dm new file mode 100644 index 000000000000..73d5bb2cb224 --- /dev/null +++ b/code/game/objects/structures/flora/bush.dm @@ -0,0 +1,111 @@ +//////////////////////////////////////// +// bushes +//////////////////////////////////////// +/obj/structure/flora/bush + name = "bush" + icon = 'icons/obj/flora/ausflora.dmi' + icon_state = "firstbush_1" + w_class = ITEM_SIZE_HUGE + +/obj/structure/flora/bush/get_material_health_modifier() + return 0.5 + +/obj/structure/flora/bush/init_appearance() + icon_state = "firstbush_[rand(1, 4)]" + +/obj/structure/flora/bush/snow + icon = 'icons/obj/flora/snowflora.dmi' + icon_state = "snowbush1" + +/obj/structure/flora/bush/snow/init_appearance() + icon_state = "snowbush[rand(1, 6)]" + +/obj/structure/flora/bush/reedbush + icon_state = "reedbush_1" + +/obj/structure/flora/bush/reedbush/init_appearance() + icon_state = "reedbush_[rand(1, 4)]" + +/obj/structure/flora/bush/leafybush + icon_state = "leafybush_1" + +/obj/structure/flora/bush/leafybush/init_appearance() + icon_state = "leafybush_[rand(1, 3)]" + +/obj/structure/flora/bush/palebush + icon_state = "palebush_1" + +/obj/structure/flora/bush/palebush/init_appearance() + icon_state = "palebush_[rand(1, 4)]" + +/obj/structure/flora/bush/stalkybush + icon_state = "stalkybush_1" + +/obj/structure/flora/bush/stalkybush/init_appearance() + icon_state = "stalkybush_[rand(1, 3)]" + +/obj/structure/flora/bush/grassybush + icon_state = "grassybush_1" + +/obj/structure/flora/bush/grassybush/init_appearance() + icon_state = "grassybush_[rand(1, 4)]" + +/obj/structure/flora/bush/fernybush + icon_state = "fernybush_1" + +/obj/structure/flora/bush/fernybush/init_appearance() + icon_state = "fernybush_[rand(1, 3)]" + +/obj/structure/flora/bush/sunnybush + icon_state = "sunnybush_1" + +/obj/structure/flora/bush/sunnybush/init_appearance() + icon_state = "sunnybush_[rand(1, 3)]" + +/obj/structure/flora/bush/genericbush + icon_state = "genericbush_1" + +/obj/structure/flora/bush/genericbush/init_appearance() + icon_state = "genericbush_[rand(1, 4)]" + +/obj/structure/flora/bush/pointybush + icon_state = "pointybush_1" + +/obj/structure/flora/bush/pointybush/init_appearance() + icon_state = "pointybush_[rand(1, 4)]" + +/obj/structure/flora/bush/lavendergrass + icon_state = "lavendergrass_1" + +/obj/structure/flora/bush/lavendergrass/init_appearance() + icon_state = "lavendergrass_[rand(1, 4)]" + +/obj/structure/flora/bush/ywflowers + icon_state = "ywflowers_1" + +/obj/structure/flora/bush/ywflowers/init_appearance() + icon_state = "ywflowers_[rand(1, 3)]" + +/obj/structure/flora/bush/brflowers + icon_state = "brflowers_1" + +/obj/structure/flora/bush/brflowers/init_appearance() + icon_state = "brflowers_[rand(1, 3)]" + +/obj/structure/flora/bush/ppflowers + icon_state = "ppflowers_1" + +/obj/structure/flora/bush/ppflowers/init_appearance() + icon_state = "ppflowers_[rand(1, 4)]" + +/obj/structure/flora/bush/sparsegrass + icon_state = "sparsegrass_1" + +/obj/structure/flora/bush/sparsegrass/init_appearance() + icon_state = "sparsegrass_[rand(1, 3)]" + +/obj/structure/flora/bush/fullgrass + icon_state = "fullgrass_1" + +/obj/structure/flora/bush/fullgrass/init_appearance() + icon_state = "fullgrass_[rand(1, 3)]" \ No newline at end of file diff --git a/code/game/objects/structures/flora/grass.dm b/code/game/objects/structures/flora/grass.dm new file mode 100644 index 000000000000..6e7647880397 --- /dev/null +++ b/code/game/objects/structures/flora/grass.dm @@ -0,0 +1,27 @@ +//////////////////////////////////////// +// Grass +//////////////////////////////////////// +/obj/structure/flora/grass + name = "grass" + icon = 'icons/obj/flora/snowflora.dmi' + +/obj/structure/flora/grass/get_material_health_modifier() + return 0.03 + +/obj/structure/flora/grass/brown + icon_state = "snowgrass1bb" + +/obj/structure/flora/grass/brown/init_appearance() + icon_state = "snowgrass[rand(1, 3)]bb" + +/obj/structure/flora/grass/green + icon_state = "snowgrass1gb" + +/obj/structure/flora/grass/green/init_appearance() + icon_state = "snowgrass[rand(1, 3)]gb" + +/obj/structure/flora/grass/both + icon_state = "snowgrassall1" + +/obj/structure/flora/grass/both/init_appearance() + icon_state = "snowgrassall[rand(1, 3)]" diff --git a/code/game/objects/structures/flora/plant.dm b/code/game/objects/structures/flora/plant.dm new file mode 100644 index 000000000000..9e44f55a2f3a --- /dev/null +++ b/code/game/objects/structures/flora/plant.dm @@ -0,0 +1,149 @@ +/obj/structure/flora/plant + icon = 'icons/obj/hydroponics/hydroponics_growing.dmi' + icon_state = "bush5-4" + color = COLOR_GREEN + is_spawnable_type = FALSE + var/growth_stage + var/dead = FALSE + var/sampled = FALSE + var/datum/seed/plant + var/harvestable + +/obj/structure/flora/plant/large + opacity = TRUE + density = TRUE + +/* Notes for future work moving logic off hydrotrays onto plants themselves: +/obj/structure/flora/plant/Process() + // check our immediate environment + // ask our environment for available reagents + // process the reagents + // ask our environment for gas + // take gas/add gas from environment + // ask our environment for light + // update health + // advance age + // update icon/harvestability as appropriate +*/ + +/obj/structure/flora/plant/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(dead) + . += SPAN_OCCULT("It is dead.") + else if(harvestable) + . += SPAN_NOTICE("You can see [harvestable] harvestable fruit\s.") + +/obj/structure/flora/plant/dismantle_structure(mob/user) + if(plant) + var/fail_chance = user ? user.skill_fail_chance(SKILL_BOTANY, 30, SKILL_ADEPT) : 30 + if(!prob(fail_chance)) + for(var/i = 1 to rand(1,3)) + new /obj/item/seeds/extracted(loc, null, plant) + return ..() + +/obj/structure/flora/plant/Initialize(ml, _mat, _reinf_mat, datum/seed/_plant) + + if(!plant && _plant) + plant = _plant + if(istext(plant)) + plant = SSplants.seeds[plant] + if(!istype(plant)) + PRINT_STACK_TRACE("Flora given invalid seed value: [plant || "NULL"]") + return INITIALIZE_HINT_QDEL + + name = plant.display_name + desc = "A wild [name]." + growth_stage = rand(round(plant.growth_stages * 0.65), plant.growth_stages) + if(!dead) + if(prob(25) && growth_stage >= plant.growth_stages) + harvestable = rand(1, 3) + if(plant.get_trait(TRAIT_BIOLUM)) + var/potency = plant.get_trait(TRAIT_POTENCY) + set_light(l_range = max(1, round(potency/10)), l_power = clamp(round(potency/30), 0, 1), l_color = plant.get_trait(TRAIT_BIOLUM_COLOUR)) + update_icon() + return ..() + +/obj/structure/flora/plant/Destroy() + plant = null + . = ..() + +/obj/structure/flora/plant/on_update_icon() + . = ..() + icon_state = "blank" + reset_color() + set_overlays(plant.get_appearance(dead = dead, growth_stage = growth_stage, can_harvest = !!harvestable)) + +/obj/structure/flora/plant/attackby(obj/item/used_item, mob/user) + + if(IS_SHOVEL(used_item) || IS_HATCHET(used_item)) + user.visible_message(SPAN_NOTICE("\The [user] uproots \the [src] with \the [used_item]!")) + physically_destroyed() + return TRUE + + // Hydrotray boilerplate for taking samples. + if(used_item.has_edge() && used_item.w_class < ITEM_SIZE_NORMAL && !user.check_intent(I_FLAG_HARM)) + if(sampled) + to_chat(user, SPAN_WARNING("There's no bits that can be used for a sampling left.")) + return TRUE + if(dead) + to_chat(user, SPAN_WARNING("The plant is dead.")) + return TRUE + var/needed_skill = plant.mysterious ? SKILL_ADEPT : SKILL_BASIC + if(prob(user.skill_fail_chance(SKILL_BOTANY, 90, needed_skill))) + to_chat(user, SPAN_WARNING("You failed to get a usable sample.")) + else + plant.harvest(user, harvest_sample = TRUE) + sampled = prob(30) + return TRUE + + . = ..() + +/obj/structure/flora/plant/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + + if(dead) + user.visible_message(SPAN_NOTICE("\The [user] uproots the dead [name]!")) + physically_destroyed() + return TRUE + if(harvestable <= 0) + return ..() + + var/harvested = plant.harvest(user, force_amount = 1) + if(harvested) + if(!islist(harvested)) + harvested = list(harvested) + harvestable -= length(harvested) + for(var/thing in harvested) + user.put_in_hands(thing) + if(!harvestable) + update_icon() + return TRUE + +/obj/structure/flora/plant/random_mushroom + name = "mushroom" + color = COLOR_BEIGE + icon_state = "mushroom10-3" + is_spawnable_type = TRUE + +/obj/structure/flora/plant/random_mushroom/proc/get_mushroom_variants() + var/static/list/mushroom_variants = list( + "amanita", + "destroyingangel" + ) + return mushroom_variants + +/obj/structure/flora/plant/random_mushroom/glowing + color = COLOR_CYAN + +/obj/structure/flora/plant/random_mushroom/glowing/get_mushroom_variants() + var/static/list/mushroom_variants = list( + "caverncandle", + "weepingmoon", + "glowbell" + ) + return mushroom_variants + +/obj/structure/flora/plant/random_mushroom/Initialize() + plant = pick(get_mushroom_variants()) + return ..() diff --git a/code/game/objects/structures/flora/plant_serde.dm b/code/game/objects/structures/flora/plant_serde.dm new file mode 100644 index 000000000000..26cfbedac5e9 --- /dev/null +++ b/code/game/objects/structures/flora/plant_serde.dm @@ -0,0 +1,7 @@ +/obj/structure/flora/plant/ShouldSerialize(_age) + return plant?.roundstart && ..(_age) + +/obj/structure/flora/plant/Serialize() + . = ..() + if(plant && plant.name != initial(plant)) + .[nameof(/obj/structure/flora/plant::plant)] = plant.name diff --git a/code/game/objects/structures/flora/potted.dm b/code/game/objects/structures/flora/potted.dm new file mode 100644 index 000000000000..b046efc7a545 --- /dev/null +++ b/code/game/objects/structures/flora/potted.dm @@ -0,0 +1,183 @@ +//////////////////////////////////////// +// Potted Plants +//////////////////////////////////////// +/obj/structure/flora/pottedplant + name = "potted plant" + desc = "Really brings the room together." + icon = 'icons/obj/structures/potted_plants.dmi' + icon_state = "plant-01" + anchored = FALSE + layer = ABOVE_HUMAN_LAYER + w_class = ITEM_SIZE_LARGE + remains_type = /obj/effect/decal/cleanable/dirt/visible + hitsound = 'sound/effects/glass_crack2.ogg' + snd_cut = 'sound/effects/break_ceramic.ogg' + material = /decl/material/solid/stone/pottery + matter = list( + /decl/material/solid/clay = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/sand = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plantmatter = MATTER_AMOUNT_SECONDARY, //#TODO: Maybe eventually drop the plant, or some seeds or something? + ) + +/obj/structure/flora/pottedplant/get_material_health_modifier() + return 0.80 + +//potted plants credit: Flashkirby +//potted plants 27-30: Cajoes +/obj/structure/flora/pottedplant/fern + name = "potted fern" + desc = "This is an ordinary looking fern. It looks like it could do with some water." + icon_state = "plant-02" + +/obj/structure/flora/pottedplant/overgrown + name = "overgrown potted plants" + desc = "This is an assortment of colourful plants. Some parts are overgrown." + icon_state = "plant-03" + +/obj/structure/flora/pottedplant/bamboo + name = "potted bamboo" + desc = "These are bamboo shoots. The tops looks like they've been cut short." + icon_state = "plant-04" + +/obj/structure/flora/pottedplant/largebush + name = "large potted bush" + desc = "This is a large bush. The leaves stick upwards in an odd fashion." + icon_state = "plant-05" + +/obj/structure/flora/pottedplant/thinbush + name = "thin potted bush" + desc = "This is a thin bush. It appears to be flowering." + icon_state = "plant-06" + +/obj/structure/flora/pottedplant/mysterious + name = "mysterious potted bulbs" + desc = "This is a mysterious looking plant. Touching the bulbs cause them to shrink." + icon_state = "plant-07" + +/obj/structure/flora/pottedplant/smalltree + name = "small potted tree" + desc = "This is a small tree. It is rather pleasant." + icon_state = "plant-08" + +/obj/structure/flora/pottedplant/unusual + name = "unusual potted plant" + desc = "This is an unusual plant. Its bulbous ends emit a soft blue light." + icon_state = "plant-09" + +/obj/structure/flora/pottedplant/unusual/Initialize() + . = ..() + set_light(l_range = 2, l_power = 2, l_color = "#007fff") + +/obj/structure/flora/pottedplant/orientaltree + name = "potted oriental tree" + desc = "This is a rather oriental style tree. Its flowers are bright pink." + icon_state = "plant-10" + +/obj/structure/flora/pottedplant/smallcactus + name = "small potted cactus" + desc = "This is a small cactus. Its needles are sharp." + icon_state = "plant-11" + +/obj/structure/flora/pottedplant/tall + name = "tall potted plant" + desc = "This is a tall plant. Tiny pores line its surface." + icon_state = "plant-12" + +/obj/structure/flora/pottedplant/sticky + name = "sticky potted plant" + desc = "This is an odd plant. Its sticky leaves trap insects." + icon_state = "plant-13" + +/obj/structure/flora/pottedplant/smelly + name = "smelly potted plant" + desc = "This is some kind of tropical plant. It reeks of rotten eggs." + icon_state = "plant-14" + +/obj/structure/flora/pottedplant/small + name = "small potted plant" + desc = "This is a pot of assorted small flora. Some look familiar." + icon_state = "plant-15" + +/obj/structure/flora/pottedplant/aquatic + name = "aquatic potted plant" + desc = "This is apparently an aquatic plant. It's probably fake." + icon_state = "plant-16" + +/obj/structure/flora/pottedplant/shoot + name = "small potted shoot" + desc = "This is a small shoot. It still needs time to grow." + icon_state = "plant-17" + +/obj/structure/flora/pottedplant/flower + name = "potted flower" + desc = "This is a slim plant. Sweet smelling flowers are supported by spindly stems." + icon_state = "plant-18" + +/obj/structure/flora/pottedplant/crystal + name = "crystalline potted plant" + desc = "These are rather cubic plants. Odd crystal formations grow on the end." + icon_state = "plant-19" + +/obj/structure/flora/pottedplant/subterranean + name = "subterranean potted plant" + desc = "This is a subterranean plant. Its bulbous ends glow faintly." + icon_state = "plant-20" + +/obj/structure/flora/pottedplant/subterranean/Initialize() + . = ..() + set_light(l_range = 1, l_power = 0.5, l_color = "#ff6633") + +/obj/structure/flora/pottedplant/minitree + name = "potted tree" + desc = "This is a miniature tree. Apparently it was grown to 1/5 scale." + icon_state = "plant-21" + +/obj/structure/flora/pottedplant/stoutbush + name = "stout potted bush" + desc = "This is a stout bush. Its leaves point up and outwards." + icon_state = "plant-22" + +/obj/structure/flora/pottedplant/drooping + name = "drooping potted plant" + desc = "This is a small plant. The drooping leaves make it look like its wilted." + icon_state = "plant-23" + +/obj/structure/flora/pottedplant/tropical + name = "tropical potted plant" + desc = "This is some kind of tropical plant. It hasn't begun to flower yet." + icon_state = "plant-24" + +/obj/structure/flora/pottedplant/dead + name = "dead potted plant" + desc = "This is the dried up remains of a dead plant. Someone should replace it." + icon_state = "plant-25" + +/obj/structure/flora/pottedplant/large + name = "large potted plant" + desc = "This is a large plant. Three branches support pairs of waxy leaves." + icon_state = "plant-26" + +/obj/structure/flora/pottedplant/decorative + name = "decorative potted plant" + desc = "This is a decorative shrub. It's been trimmed into the shape of an apple." + icon_state = "applebush" + +/obj/structure/flora/pottedplant/deskfern + name = "fancy ferny potted plant" + desc = "This leafy desk fern could do with a trim." + icon_state = "plant-27" + +/obj/structure/flora/pottedplant/floorleaf + name = "fancy leafy floor plant" + desc = "This plant has remarkably waxy leaves." + icon_state = "plant-28" + +/obj/structure/flora/pottedplant/deskleaf + name = "fancy leafy potted desk plant" + desc = "A tiny waxy leafed plant specimen." + icon_state = "plant-29" + +/obj/structure/flora/pottedplant/deskferntrim + name = "fancy trimmed ferny potted plant" + desc = "This leafy desk fern seems to have been trimmed too much." + icon_state = "plant-30" diff --git a/code/game/objects/structures/flora/stump.dm b/code/game/objects/structures/flora/stump.dm new file mode 100644 index 000000000000..4911cd3a57e7 --- /dev/null +++ b/code/game/objects/structures/flora/stump.dm @@ -0,0 +1,74 @@ +//////////////////////////////////////// +// Stumps +//////////////////////////////////////// +/obj/structure/flora/stump + name = "stump" + hitsound = 'sound/effects/hit_wood.ogg' + var/log_type = /obj/item/stack/material/log + +/obj/structure/flora/stump/get_material_health_modifier() + return 2.5 //Make stumps worth removing with shovels instead of bashing them + +/obj/structure/flora/stump/can_cut_down(obj/item/I, mob/user) + return IS_SHOVEL(I) + +/obj/structure/flora/stump/cut_down(obj/item/I, mob/user) + if(I.do_tool_interaction(TOOL_SHOVEL, user, src, 8 SECONDS)) + . = ..() + +/obj/structure/flora/stump/create_dismantled_products(turf/T) + if(log_type) + LAZYADD(., new log_type(T, rand(2,3), material?.type, reinf_material?.type)) + . = ..() + +//Base tree stump +/obj/structure/flora/stump/tree + name = "tree stump" + icon = 'icons/obj/flora/tree_stumps.dmi' + w_class = ITEM_SIZE_HUGE + pixel_x = -16 //All trees are offset 16 pixels + material = /decl/material/solid/organic/wood/oak + +//dead trees +/obj/structure/flora/stump/tree/dead + name = "dead tree stump" + icon_state = "tree_1" + +/obj/structure/flora/stump/tree/dead/init_appearance() + icon_state = "tree_[rand(1, 6)]" + +//pine trees +/obj/structure/flora/stump/tree/pine + icon_state = "pine_1" + material = /decl/material/solid/organic/wood/oak // TODO: pine + +/obj/structure/flora/stump/tree/pine/init_appearance() + icon_state = "pine_[rand(1, 3)]" + +//christmas tree +/obj/structure/flora/stump/tree/pine/xmas + icon_state = "pine_c" + +/obj/structure/flora/stump/tree/towercap + icon_state = "towercap_1" + material = /decl/material/solid/organic/wood/fungal + +/obj/structure/flora/stump/tree/ebony + icon_state = "ebony_1" + material = /decl/material/solid/organic/wood/ebony + +/obj/structure/flora/stump/tree/mahogany + icon_state = "mahogany_1" + material = /decl/material/solid/organic/wood/mahogany + +/obj/structure/flora/stump/tree/maple + icon_state = "maple_1" + material = /decl/material/solid/organic/wood/maple + +/obj/structure/flora/stump/tree/yew + icon_state = "yew_1" + material = /decl/material/solid/organic/wood/yew + +/obj/structure/flora/stump/tree/walnut + icon_state = "walnut_1" + material = /decl/material/solid/organic/wood/walnut diff --git a/code/game/objects/structures/flora/tree.dm b/code/game/objects/structures/flora/tree.dm new file mode 100644 index 000000000000..13dcf346bcc1 --- /dev/null +++ b/code/game/objects/structures/flora/tree.dm @@ -0,0 +1,190 @@ + +//////////////////////////////////////// +// Trees +//////////////////////////////////////// +/obj/structure/flora/tree + name = "tree" + density = TRUE + pixel_x = -16 + layer = ABOVE_HUMAN_LAYER + material = /decl/material/solid/organic/wood/oak + w_class = ITEM_SIZE_STRUCTURE + hitsound = 'sound/effects/hit_wood.ogg' + snd_cut = 'sound/effects/plants/tree_fall.ogg' + + /// What kind of log we leave behind. + var/log_type = /obj/item/stack/material/log + /// How many logs we leave behind. + var/log_amount = 10 + /// Whether or not you can shelter under this tree. + var/protects_against_weather = TRUE + /// What kind of tree stump we leaving behind. + var/stump_type + /// Marker for repeating the cut sound effect and animation. + var/someone_is_cutting = FALSE + +/obj/structure/flora/tree/get_material_health_modifier() + return 2.5 //Prefer removing via tools than bashing + +/obj/structure/flora/tree/can_cut_down(obj/item/I, mob/user) + return IS_HATCHET(I) //Axes can bypass having to damage the tree to break it + +/obj/structure/flora/tree/cut_down(obj/item/I, mob/user) + someone_is_cutting = TRUE + if(I.do_tool_interaction(TOOL_HATCHET, user, src, 5 SECONDS)) + . = ..() + someone_is_cutting = FALSE + +/obj/structure/flora/tree/Initialize(ml, _mat, _reinf_mat) + . = ..() + if(!ml && protects_against_weather) + for(var/turf/T as anything in RANGE_TURFS(src, 1)) + AMBIENCE_QUEUE_TURF(T) + +// I hate doing things that aren't cleanup in Destroy(), but this should still update even when admin-deleted. +/obj/structure/flora/tree/Destroy() + var/list/turfs_to_update = RANGE_TURFS(src, 1) + . = ..() + if(protects_against_weather) + for(var/turf/T in turfs_to_update) + AMBIENCE_QUEUE_TURF(T) + +/obj/structure/flora/tree/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + . = ..() + if(!QDELETED(src) && damage >= 5) + shake_animation() + +// We chop several times to cut down a tree. +/obj/structure/flora/tree/play_cut_sound(mob/user) + shake_animation() + while(someone_is_cutting) + sleep(1 SECOND) + if(QDELETED(src)) + return + shake_animation() + playsound(src, 'sound/items/axe_wood.ogg', 40, TRUE) + if(QDELETED(src) || QDELETED(user) || !user.Adjacent(src)) + return + return ..() + +/obj/structure/flora/tree/create_dismantled_products(turf/T) + if(log_type) + LAZYADD(., new log_type(T, rand(max(1,round(log_amount*0.5)), log_amount), material?.type, reinf_material?.type)) + if(stump_type) + var/obj/structure/flora/stump/stump = new stump_type(T, material, reinf_material) + stump.icon_state = icon_state //A bit dirty maybe, but its probably not worth writing a whole system for this when we have 3 kinds of trees... + if(paint_color) + stump.set_color() + . = ..() + +/obj/structure/flora/tree/pine + name = "pine tree" + desc = "A pine tree." + icon = 'icons/obj/flora/pinetrees.dmi' + icon_state = "pine_1" + stump_type = /obj/structure/flora/stump/tree/pine + opacity = TRUE + +/obj/structure/flora/tree/pine/init_appearance() + icon_state = "pine_[rand(1, 3)]" + +var/global/list/christmas_trees = list() +/obj/structure/flora/tree/pine/xmas + name = "\improper Christmas tree" + desc = "O Christmas tree, O Christmas tree..." + icon = 'icons/obj/flora/pinetrees.dmi' + icon_state = "pine_c" + stump_type = /obj/structure/flora/stump/tree/pine/xmas + +/obj/structure/flora/tree/pine/xmas/Initialize(ml, _mat, _reinf_mat) + . = ..() + global.christmas_trees += src + +/obj/structure/flora/tree/pine/xmas/Destroy() + global.christmas_trees -= src + return ..() + +/obj/structure/flora/tree/pine/xmas/init_appearance() + return //Only one possible icon + +/obj/structure/flora/tree/dead + name = "dead tree" + desc = "A dead looking tree." + icon = 'icons/obj/flora/deadtrees.dmi' + icon_state = "tree_1" + protects_against_weather = FALSE + stump_type = /obj/structure/flora/stump/tree/dead + +/obj/structure/flora/tree/dead/random/init_appearance() + icon_state = "tree_[rand(1, 6)]" + +/obj/structure/flora/tree/dead/ebony + icon_state = "dead_ebony_1" + material = /decl/material/solid/organic/wood/ebony + stump_type = /obj/structure/flora/stump/tree/ebony + +/obj/structure/flora/tree/dead/mahogany + icon_state = "dead_mahogany_1" + material = /decl/material/solid/organic/wood/mahogany + stump_type = /obj/structure/flora/stump/tree/mahogany + +/obj/structure/flora/tree/dead/walnut + icon_state = "dead_walnut_1" + material = /decl/material/solid/organic/wood/walnut + stump_type = /obj/structure/flora/stump/tree/walnut + +/obj/structure/flora/tree/dead/maple + icon_state = "dead_maple_1" + material = /decl/material/solid/organic/wood/maple + stump_type = /obj/structure/flora/stump/tree/maple + +/obj/structure/flora/tree/dead/yew + icon_state = "dead_yew_1" + material = /decl/material/solid/organic/wood/yew + stump_type = /obj/structure/flora/stump/tree/yew + +/obj/structure/flora/tree/softwood + icon = 'icons/obj/flora/softwood.dmi' + abstract_type = /obj/structure/flora/tree/softwood + +/obj/structure/flora/tree/softwood/towercap + name = "towercap mushroom" + icon_state = "towercap_1" + material = /decl/material/solid/organic/wood/fungal + stump_type = /obj/structure/flora/stump/tree/towercap + +/obj/structure/flora/tree/hardwood + icon = 'icons/obj/flora/hardwood.dmi' + abstract_type = /obj/structure/flora/tree/hardwood + +/obj/structure/flora/tree/hardwood/ebony + name = "ebony tree" + icon_state = "ebony_1" + material = /decl/material/solid/organic/wood/ebony + stump_type = /obj/structure/flora/stump/tree/ebony + +/obj/structure/flora/tree/hardwood/mahogany + name = "mahogany tree" + icon_state = "mahogany_1" + material = /decl/material/solid/organic/wood/mahogany + stump_type = /obj/structure/flora/stump/tree/mahogany + opacity = TRUE + +/obj/structure/flora/tree/hardwood/maple + name = "maple tree" + icon_state = "maple_1" + material = /decl/material/solid/organic/wood/maple + stump_type = /obj/structure/flora/stump/tree/maple + +/obj/structure/flora/tree/hardwood/yew + name = "yew tree" + icon_state = "yew_1" + material = /decl/material/solid/organic/wood/yew + stump_type = /obj/structure/flora/stump/tree/yew + opacity = TRUE + +/obj/structure/flora/tree/hardwood/walnut + name = "walnut tree" + icon_state = "walnut_1" + material = /decl/material/solid/organic/wood/walnut + stump_type = /obj/structure/flora/stump/tree/walnut diff --git a/code/game/objects/structures/fountain.dm b/code/game/objects/structures/fountain.dm index 0b92444fd195..da68645ad82a 100644 --- a/code/game/objects/structures/fountain.dm +++ b/code/game/objects/structures/fountain.dm @@ -1,65 +1,129 @@ //the fountain of youth/unyouth /obj/structure/fountain - name = "strange fountain" - desc = "The water from the spout is still as if frozen in time, yet the water in the base ripples perpetually." - icon = 'icons/obj/fountain.dmi' - icon_state = "fountain" - density = 1 - anchored = 1 - unacidable = 1 - pixel_x = -16 - var/used = FALSE - -/obj/structure/fountain/Initialize() + name = "strange fountain" + desc = "The water from the spout is still as if frozen in time, yet the water in the base ripples perpetually." + icon = 'icons/obj/fountain.dmi' + icon_state = "fountain" + density = TRUE + anchored = TRUE + pixel_x = -16 + light_range = 5 + light_power = 0.5 + chem_volume = 500 + + var/used = FALSE + var/increase_age_prob = (100 / 6) + +/obj/structure/fountain/Initialize(ml, _mat, _reinf_mat) + if(light_range && light_power) + light_color = get_random_colour(lower = 190) . = ..() - light_color = get_random_colour(lower = 190) - set_light(0.6, 3, 5, 2, light_color) - -/obj/structure/fountain/attack_hand(var/mob/living/user) - if(user.incapacitated()) - return - if(!CanPhysicallyInteract(user)) - return + +/obj/structure/fountain/attack_hand(var/mob/user) + + if(user.check_intent(I_FLAG_HARM)) + return ..() + if(used) - to_chat(user, "\The [src] is still and lifeless...") - return - if(!ishuman(user) || user.isSynthetic()) - to_chat(user, "Try as you might to touch the fountain, some force prevents you from doing so.") - return + to_chat(user, SPAN_WARNING("\The [src] is still and lifeless...")) + return TRUE + + var/mob/living/human/H = user + var/decl/bodytype/my_bodytype = istype(H) && H.get_bodytype() + if(!istype(my_bodytype)) + return ..() + + var/datum/appearance_descriptor/age/age = my_bodytype && LAZYACCESS(my_bodytype.appearance_descriptors, "age") + if(H.isSynthetic() || !my_bodytype || !age) + to_chat(H, SPAN_WARNING("A feeling of foreboding stills your hand. The fountain is not for your kind.")) + return TRUE if(alert("As you reach out to touch the fountain, a feeling of doubt overcomes you. Steel yourself and proceed?",,"Yes", "No") == "Yes") - visible_message("\The [user] touches \the [src].") - time_dilation(user) + visible_message("\The [H] touches \the [src].") + time_dilation(H) else - visible_message("\The [user] retracts their hand suddenly.") + visible_message("\The [H] retracts their hand suddenly.") + return TRUE + +/obj/structure/fountain/proc/time_dilation(var/mob/living/human/user) -/obj/structure/fountain/proc/time_dilation(var/mob/living/carbon/human/user) for(var/mob/living/L in oviewers(7, src)) L.flash_eyes(3) - L.eye_blurry += 9 - visible_message("\The [src] erupts in a bright flash of light!") + SET_STATUS_MAX(L, STAT_BLURRY, 9) + + visible_message(SPAN_WARNING("\The [src] erupts in a bright flash of light!")) playsound(src,'sound/items/time.ogg',100) - var/direction = rand(1,6) - if(direction == 1) //become older - to_chat(user, "You touch the fountain. All the memories of your life seem to fade into the distant past as seconds drag like years. You feel the inexplicable sensation of your skin tightening and thinning across your entire body as your muscles degrade and your joints weaken. Time returns to its 'normal' pace. You can only just barely remember touching the fountain.") - user.became_older = TRUE - user.change_hair_color(80, 80, 80) - var/age_holder = round(rand(15,20)) - user.age += age_holder - else //become younger - to_chat(user, "You touch the fountain. Everything stops - then reverses. You relive in an instant the events of your life. The fountain, yesterday's lunch, your first love, your first kiss. It all feels as though it just happened moments ago. Then it feels like it never happened at all. Time reverses back into normality and continues its advance. You feel great, but why are you here?") - user.became_younger = TRUE - user.age = round(rand(15,17)) + var/old_age = user.get_age() + var/new_age = old_age + if(prob(increase_age_prob)) + new_age += rand(5,15) + else + new_age -= rand(5,15) + + var/decl/bodytype/bodytype = user.get_bodytype() + var/datum/appearance_descriptor/age/age = LAZYACCESS(bodytype.appearance_descriptors, "age") + // Let's avoid reverting people to children since that has a lot of baggage attached. + var/min_age = age.standalone_value_descriptors[age.standalone_value_descriptors[age.chargen_min_index]] + new_age = max(new_age, min_age) // This will clamp to the max defined age already so only need to min() + + if(new_age == old_age) + to_chat(user, SPAN_CULT_ANNOUNCE("You touch the fountain, and feel your memories sifted through by a great presence. Then, it withdraws, leaving you unchanged.")) + else + user.set_age(new_age) + if(new_age < old_age) + to_chat(user, SPAN_CULT_ANNOUNCE("You touch the fountain. Everything stops - then reverses. You relive in an instant the events of your life. The fountain, yesterday's lunch, your first love, your first kiss. It all feels as though it just happened moments ago. Then it feels like it never happened at all. Time reverses back into normality and continues its advance. You feel great, but why are you here?")) + user.became_younger = TRUE + else + to_chat(user, SPAN_CULT_ANNOUNCE("You touch the fountain. All the memories of your life seem to fade into the distant past as seconds drag like years. You feel the inexplicable sensation of your skin tightening and thinning across your entire body as your muscles degrade and your joints weaken. Time returns to its 'normal' pace. You can only just barely remember touching the fountain.")) + user.became_older = TRUE + SET_HAIR_COLOR(user, COLOR_GRAY80, FALSE) + var/max_age = age.standalone_value_descriptors[age.standalone_value_descriptors[length(age.standalone_value_descriptors)]] + if(new_age >= max_age) + to_chat(user, SPAN_CULT_ANNOUNCE("The burden of the years is too much, and you are reduced to dust.")) + user.dust() + used = TRUE desc = "The water flows beautifully from the spout, but the water in the pool does not ripple." +/mob/living/human + /// Used by the Fountain of Youth point of interest for on-examine messages. + var/became_older + /// Used by the Fountain of Youth point of interest for on-examine messages. + var/became_younger + +/decl/human_examination/fountain + priority = /decl/human_examination/graffiti::priority + 0.5 // just squeeze it in there + +/decl/human_examination/fountain/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + . = list() + if(source.became_younger) + . += "[pronouns.He] look[pronouns.s] a lot younger than you remember." + if(source.became_older) + . += "[pronouns.He] look[pronouns.s] a lot older than you remember." + /obj/structure/fountain/mundane - name = "fountain" - desc = "A beautifully constructed fountain." - icon_state = "fountain_g" - used = TRUE + name = "fountain" + desc = "A beautifully constructed fountain." + icon_state = "fountain_g" + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + w_class = ITEM_SIZE_STRUCTURE + material = /decl/material/solid/stone/marble + used = TRUE + material_alteration = MAT_FLAG_ALTERATION_ALL + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_CLIMBABLE + light_range = null + light_power = null + +/obj/structure/fountain/mundane/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) //Don't give free water when building one + +/obj/structure/fountain/mundane/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HARM)) + return ..() + return TRUE -/obj/structure/fountain/mundane/attack_hand() - return \ No newline at end of file +/obj/structure/fountain/mundane/sandstone + material = /decl/material/solid/stone/sandstone + color = /decl/material/solid/stone/sandstone::color diff --git a/code/game/objects/structures/fuel_port.dm b/code/game/objects/structures/fuel_port.dm new file mode 100644 index 000000000000..6488d9972ad2 --- /dev/null +++ b/code/game/objects/structures/fuel_port.dm @@ -0,0 +1,86 @@ +/obj/structure/fuel_port + name = "fuel port" + desc = "The fuel input port of the shuttle. Holds one fuel tank. Use a crowbar to open and close it." + icon = 'icons/obj/structures/fuel_port.dmi' + icon_state = "base" + + density = FALSE + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + + var/open = FALSE + var/parent_shuttle + + var/sound_open = 'sound/effects/locker_open.ogg' + var/sound_close = 'sound/effects/locker_close.ogg' + + /// Used to create a prepared tank on initialization. + var/start_tank_type + +/obj/structure/fuel_port/Initialize() + . = ..() + if(start_tank_type) + new start_tank_type(src) + +/obj/structure/fuel_port/proc/locate_tank() + return locate(/obj/item/tank) in contents + +/obj/structure/fuel_port/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(!open) + to_chat(user, SPAN_WARNING("The door is secured tightly. You'll need a crowbar to open it.")) + return TRUE + var/obj/item/tank/tank = locate_tank() + if(tank) + user.put_in_hands(tank) + update_icon() + return TRUE + +/obj/structure/fuel_port/on_update_icon() + ..() + if(open) + add_overlay("[icon_state]_open") + var/obj/item/tank/tank = locate_tank() + if(tank) + if(tank.color) + add_overlay(mutable_appearance(icon, "[icon_state]_tank", tank.color)) + else + add_overlay("[icon_state]_tank_orange") + else + add_overlay("[icon_state]_closed") + +/obj/structure/fuel_port/attackby(obj/item/used_item, mob/user) + . = FALSE + if(used_item.do_tool_interaction(TOOL_CROWBAR, user, src, 1 SECOND)) + if(open) + playsound(src, sound_open, 25, 0, -3) + open = FALSE + else + playsound(src, sound_close, 15, 1, -3) + open = TRUE + . = TRUE + + else if(istype(used_item, /obj/item/tank)) + if(!open) + to_chat(user, SPAN_WARNING("\The [src] door is still closed!")) + return TRUE + + if(locate_tank()) + to_chat(user, SPAN_WARNING("\The [src] already has a tank inside!")) + return TRUE + else + user.try_unequip(used_item, src) + . = TRUE + + if(.) + update_icon() + +// Walls hide stuff inside them, but we want to be visible. +/obj/structure/fuel_port/hide() + return + +// And here subtype with inserted tank. +/obj/structure/fuel_port/hydrogen + start_tank_type = /obj/item/tank/hydrogen diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index ee6b8cdbfec2..d168182cdcc2 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -5,9 +5,13 @@ anchored = FALSE density = TRUE layer = BELOW_OBJ_LAYER + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) - maxhealth = 100 + max_health = 100 + parts_amount = 2 + parts_type = /obj/item/stack/material/rods + var/cover = 50 var/prepped_for_fakewall @@ -15,21 +19,13 @@ set_extension(src, /datum/extension/penetration/simple, 100) . = ..() -/obj/structure/girder/can_unanchor(var/mob/user) - . = ..() - if(!anchored && .) - var/turf/simulated/open/T = loc - if(istype(T)) - to_chat(user, SPAN_WARNING("You can only secure \the [src] to solid ground.")) - return FALSE - /obj/structure/girder/handle_default_screwdriver_attackby(var/mob/user, var/obj/item/screwdriver) if(reinf_material) playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] begins unscrewing \the [reinf_material.solid_name] struts from \the [src].")) + visible_message(SPAN_NOTICE("\The [user] begins unscrewing \the [reinf_material.solid_name] rods from \the [src].")) if(do_after(user, 5 SECONDS, src) || QDELETED(src) || !reinf_material) - visible_message(SPAN_NOTICE("\The [user] unscrews and removes \the [reinf_material.solid_name] struts from \the [src].")) + visible_message(SPAN_NOTICE("\The [user] unscrews and removes \the [reinf_material.solid_name] rods from \the [src].")) reinf_material.place_dismantled_product(get_turf(src)) reinf_material = null return TRUE @@ -44,7 +40,7 @@ return TRUE /obj/structure/girder/on_update_icon() - . = ..() + ..() if(!anchored) icon_state = "displaced" else if(reinf_material) @@ -57,13 +53,13 @@ anchored = prob(50) /obj/structure/girder/bullet_act(var/obj/item/projectile/Proj) - + var/effective_cover = cover if(reinf_material) effective_cover *= 2 - if(!anchored) + if(!anchored) effective_cover *= 0.5 - effective_cover = Clamp(Floor(effective_cover), 0, 100) + effective_cover = clamp(floor(effective_cover), 0, 100) if(Proj.original != src && !prob(effective_cover)) return PROJECTILE_CONTINUE var/damage = Proj.get_structure_damage() @@ -72,19 +68,23 @@ if(!istype(Proj, /obj/item/projectile/beam)) damage *= 0.4 if(reinf_material) - damage = Floor(damage * 0.75) + damage = floor(damage * 0.75) ..() if(damage) - take_damage(damage) + take_damage(damage, Proj.atom_damage_type) /obj/structure/girder/CanFluidPass(var/coming_from) return TRUE /obj/structure/girder/can_unanchor(var/mob/user) if(anchored && reinf_material) - to_chat(user, SPAN_WARNING("You must remove the support struts before you can dislodge \the [src].")) + to_chat(user, SPAN_WARNING("You must remove the support rods before you can dislodge \the [src].")) return FALSE . = ..() + var/turf/T = loc + if(!anchored && . && (!istype(T) || T.is_open())) + to_chat(user, SPAN_WARNING("You can only secure \the [src] to solid ground.")) + return FALSE /obj/structure/girder/can_dismantle(var/mob/user) if(reinf_material) @@ -92,42 +92,39 @@ return FALSE . = ..() -/obj/structure/girder/attackby(var/obj/item/W, var/mob/user) - . = ..() - if(!.) - - // Other methods of quickly destroying a girder. - if(W.is_special_cutting_tool(TRUE)) - if(istype(W, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = W - if(!cutter.slice(user)) - return - playsound(src.loc, 'sound/items/Welder.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] begins slicing apart \the [src] with \the [W].")) - if(do_after(user,reinf_material ? 40: 20,src)) - visible_message(SPAN_NOTICE("\The [user] slices apart \the [src] with \the [W].")) - dismantle() - return TRUE - if(istype(W, /obj/item/pickaxe/diamonddrill)) - playsound(src.loc, 'sound/weapons/Genhit.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] begins drilling through \the [src] with \the [W].")) - if(do_after(user,reinf_material ? 60 : 40,src)) - visible_message(SPAN_NOTICE("\The [user] drills through \the [src] with \the [W].")) - dismantle() - return TRUE - // Reinforcing a girder, or turning it into a wall. - if(istype(W, /obj/item/stack/material)) - if(anchored) - return construct_wall(W, user) +/obj/structure/girder/attackby(var/obj/item/used_item, var/mob/user) + // Other methods of quickly destroying a girder. + if(used_item.is_special_cutting_tool(TRUE)) + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item + if(!cutter.slice(user)) + return TRUE + playsound(src.loc, 'sound/items/Welder.ogg', 100, 1) + visible_message(SPAN_NOTICE("\The [user] begins slicing apart \the [src] with \the [used_item].")) + if(do_after(user,reinf_material ? 40: 20,src)) + visible_message(SPAN_NOTICE("\The [user] slices apart \the [src] with \the [used_item].")) + dismantle_structure(user) + return TRUE + + if(IS_PICK(used_item)) + if(used_item.material?.hardness < material.hardness) + to_chat(user, SPAN_WARNING("\The [used_item] is not hard enough to excavate [material.solid_name].")) + else if(used_item.get_tool_quality(TOOL_PICK) < TOOL_QUALITY_GOOD) + to_chat(user, SPAN_WARNING("\The [used_item] is not capable of destroying \the [src].")) + else if(used_item.do_tool_interaction(TOOL_PICK, user, src, (reinf_material ? 6 : 4) SECONDS, set_cooldown = TRUE)) + dismantle_structure(user) + return TRUE + // Reinforcing a girder, or turning it into a wall. + if(istype(used_item, /obj/item/stack/material)) + if(anchored) + return construct_wall(used_item, user) + else + if(reinf_material) + to_chat(user, SPAN_WARNING("\The [src] is already reinforced with [reinf_material.solid_name].")) else - if(reinf_material) - to_chat(user, SPAN_WARNING("\The [src] is already reinforced with [reinf_material.solid_name].")) - else - return reinforce_with_material(W, user) - return TRUE - // Other objects. - take_damage(W.force) + return reinforce_with_material(used_item, user) return TRUE + . = ..() /obj/structure/girder/proc/construct_wall(obj/item/stack/material/S, mob/user) if(S.get_amount() < 2) @@ -145,7 +142,7 @@ to_chat(user, SPAN_WARNING("You will need a support made of sturdier material to hold up [S.material.solid_name] cladding.")) return FALSE - add_hiddenprint(usr) + add_hiddenprint(user) if(S.material.integrity < 50) to_chat(user, SPAN_WARNING("This material is too soft for use in wall construction.")) return 0 @@ -161,11 +158,11 @@ to_chat(user, SPAN_NOTICE("You create a false wall! Push on it to open or close the passage.")) var/turf/Tsrc = get_turf(src) - Tsrc.ChangeTurf(/turf/simulated/wall) - var/turf/simulated/wall/T = get_turf(src) - T.set_material(S.material, reinf_material, material) + Tsrc.ChangeTurf(/turf/wall) + var/turf/wall/T = get_turf(src) + T.set_turf_materials(S.material, reinf_material, null, material) T.can_open = prepped_for_fakewall - T.add_hiddenprint(usr) + T.add_hiddenprint(user) material = null reinf_material = null qdel(src) @@ -182,7 +179,7 @@ if(!istype(M) || M.integrity < 50) to_chat(user, SPAN_WARNING("You cannot reinforce \the [src] with [M.solid_name]; it is too soft.")) return TRUE - visible_message(SPAN_NOTICE("\The [user] begins installing [M.solid_name] struts into \the [src].")) + visible_message(SPAN_NOTICE("\The [user] begins installing [M.solid_name] rods into \the [src].")) if (!do_after(user, 4 SECONDS, src) || !S.use(2)) return TRUE visible_message(SPAN_NOTICE("\The [user] finishes reinforcing \the [src] with [M.solid_name].")) @@ -190,36 +187,16 @@ update_icon() return 1 -/obj/structure/girder/attack_hand(mob/user) - if (MUTATION_HULK in user.mutations) - visible_message(SPAN_DANGER("\The [user] smashes \the [src] apart!")) - dismantle() - return - return ..() - - /obj/structure/girder/explosion_act(severity) ..() if(severity == 1 || (severity == 2 && prob(30)) || (severity == 3 && prob(5))) physically_destroyed() -/obj/structure/girder/cult - icon= 'icons/obj/cult.dmi' - icon_state= "cultgirder" - maxhealth = 150 - cover = 70 - -/obj/structure/girder/cult/dismantle() - material = null - reinf_material = null - parts_type = null - . = ..() - /obj/structure/girder/wood - material = /decl/material/solid/wood/mahogany + material = /decl/material/solid/organic/wood/mahogany /obj/structure/grille/wood - material = /decl/material/solid/wood/mahogany + material = /decl/material/solid/organic/wood/mahogany /obj/structure/lattice/wood - material = /decl/material/solid/wood/mahogany + material = /decl/material/solid/organic/wood/mahogany diff --git a/code/game/objects/structures/grandfather_clock.dm b/code/game/objects/structures/grandfather_clock.dm new file mode 100644 index 000000000000..49f4b63c22b7 --- /dev/null +++ b/code/game/objects/structures/grandfather_clock.dm @@ -0,0 +1,65 @@ +// TODO: buildable with artifice? +// TODO: looping 2 second tick tock sound, somehow aligned with pendulum (may not be possible in DM) +/obj/structure/grandfather_clock + name = "grandfather clock" + desc = "A tall, stately timepiece." + icon = 'icons/obj/structures/grandfather_clock.dmi' + icon_state = ICON_STATE_WORLD + density = TRUE + material = /decl/material/solid/organic/wood/mahogany + material_alteration = MAT_FLAG_ALTERATION_ALL + color = /decl/material/solid/organic/wood/mahogany::color + var/face_color = "#f0edc7" + var/last_time + var/decl/material/clockwork_mat = /decl/material/solid/metal/brass + +/obj/structure/grandfather_clock/Initialize(ml, _mat, _reinf_mat) + if(ispath(clockwork_mat)) + clockwork_mat = GET_DECL(clockwork_mat) + . = ..() + START_PROCESSING(SSobj, src) + update_icon() + +/obj/structure/grandfather_clock/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + // TODO: check literacy? + if(isnull(last_time)) + last_time = stationtime2text() + . += SPAN_NOTICE("The face of \the [src] reads [last_time].") + +// TODO: don't magically make the time update when swinging is restarted +// TODO: alt interaction to interfere with the clock? +/obj/structure/grandfather_clock/attack_hand(mob/user) + . = ..() + if(!.) + if(is_processing) + STOP_PROCESSING(SSobj, src) + user.visible_message(SPAN_NOTICE("\The [user] reaches into \the [src] and stops the pendulum.")) + else + START_PROCESSING(SSobj, src) + user.visible_message(SPAN_NOTICE("\The [user] reaches into \the [src] and sets the pendulum swinging.")) + update_icon() + return TRUE + +/obj/structure/grandfather_clock/Process() + ..() + var/new_time = stationtime2text() + if(new_time != last_time) + last_time = new_time + update_icon() + +/obj/structure/grandfather_clock/on_update_icon() + . = ..() + if(isnull(last_time)) + last_time = stationtime2text() + if(face_color) + add_overlay(overlay_image(icon, "[icon_state]-face", face_color, RESET_COLOR)) + if(!clockwork_mat) + return + if(is_processing) + add_overlay(overlay_image(icon, "[icon_state]-pendulum-swing", clockwork_mat.color, RESET_COLOR)) + else + add_overlay(overlay_image(icon, "[icon_state]-pendulum", clockwork_mat.color, RESET_COLOR)) + var/list/time_stats = splittext(last_time, ":") + add_overlay(overlay_image(icon, "[icon_state]-hour[round(((text2num(time_stats[1]) / 24) * 360) / 45) * 45]"), clockwork_mat.color, RESET_COLOR) + add_overlay(overlay_image(icon, "[icon_state]-minute[round(((text2num(time_stats[2]) / 60) * 360) / 45) * 45]"), clockwork_mat.color, RESET_COLOR) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index f052701f3def..2577519149b1 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -3,22 +3,25 @@ desc = "A flimsy lattice of rods, with screws to secure it to the floor." icon = 'icons/obj/structures/grille.dmi' icon_state = "grille" - density = 1 - anchored = 1 - obj_flags = OBJ_FLAG_CONDUCTIBLE + density = TRUE + anchored = TRUE + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_MOVES_UNSUPPORTED layer = BELOW_OBJ_LAYER explosion_resistance = 1 rad_resistance_modifier = 0.1 color = COLOR_STEEL material = /decl/material/solid/metal/steel + parts_type = /obj/item/stack/material/rods + parts_amount = 2 + handle_generic_blending = TRUE material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME - maxhealth = 20 + max_health = 20 var/destroyed = 0 var/list/connections var/list/other_connections - + /obj/structure/grille/clear_connections() connections = null other_connections = null @@ -56,10 +59,9 @@ /obj/structure/grille/on_update_icon() ..() var/on_frame = is_on_frame() - overlays.Cut() if(destroyed) if(on_frame) - icon_state = "broke_onframe" + icon_state = "broken_onframe" else icon_state = "broken" else @@ -69,45 +71,42 @@ for(var/i = 1 to 4) var/conn = connections ? connections[i] : "0" if(other_connections && other_connections[i] != "0") - I = image(icon, "grille_other_onframe[conn]", dir = 1<<(i-1)) + I = image(icon, "grille_other_onframe[conn]", dir = BITFLAG(i-1)) else - I = image(icon, "grille_onframe[conn]", dir = 1<<(i-1)) - overlays += I + I = image(icon, "grille_onframe[conn]", dir = BITFLAG(i-1)) + add_overlay(I) else for(var/i = 1 to 4) var/conn = connections ? connections[i] : "0" if(other_connections && other_connections[i] != "0") - I = image(icon, "grille_other[conn]", dir = 1<<(i-1)) + I = image(icon, "grille_other[conn]", dir = BITFLAG(i-1)) else - I = image(icon, "grille[conn]", dir = 1<<(i-1)) - overlays += I + I = image(icon, "grille[conn]", dir = BITFLAG(i-1)) + add_overlay(I) /obj/structure/grille/Bumped(atom/user) - if(ismob(user)) shock(user, 70) + if(ismob(user)) + shock(user, 70) /obj/structure/grille/attack_hand(mob/user) + if(!user.check_intent(I_FLAG_HARM)) + return ..() + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) user.do_attack_animation(src) - var/damage_dealt = 1 - var/attack_message = "kicks" - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species.can_shred(H)) - attack_message = "mangles" - damage_dealt = 5 - if(shock(user, 70)) - return + return TRUE - if(MUTATION_HULK in user.mutations) - damage_dealt += 5 - else - damage_dealt += 1 - - attack_generic(user,damage_dealt,attack_message) + var/damage_dealt = 1 + var/attack_message = "kicks" + if(user.can_shred()) + attack_message = "mangles" + damage_dealt = 5 + attack_generic(user, damage_dealt, attack_message) + return TRUE /obj/structure/grille/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group || (height==0)) return 1 @@ -130,15 +129,15 @@ //20% chance that the grille provides a bit more cover than usual. Support structure for example might take up 20% of the grille's area. //If they click on the grille itself then we assume they are aiming at the grille itself and the extra cover behaviour is always used. - switch(Proj.damage_type) + switch(Proj.atom_damage_type) if(BRUTE) //bullets if(Proj.original == src || prob(20)) - Proj.damage *= between(0, Proj.damage/60, 0.5) + Proj.damage *= clamp(Proj.damage/60, 0, 0.5) if(prob(max((damage-10)/25, 0))*100) passthrough = 1 else - Proj.damage *= between(0, Proj.damage/60, 1) + Proj.damage *= clamp(Proj.damage/60, 0, 1) passthrough = 1 if(BURN) //beams and other projectiles are either blocked completely by grilles or stop half the damage. @@ -148,9 +147,9 @@ if(passthrough) . = PROJECTILE_CONTINUE - damage = between(0, (damage - Proj.damage)*(Proj.damage_type == BRUTE? 0.4 : 1), 10) //if the bullet passes through then the grille avoids most of the damage + damage = clamp((damage - Proj.damage)*(Proj.atom_damage_type == BRUTE? 0.4 : 1), 0, 10) //if the bullet passes through then the grille avoids most of the damage - take_damage(damage*0.2) + take_damage(damage*0.2, Proj.atom_damage_type) /obj/structure/grille/proc/cut_grille() playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) @@ -158,30 +157,40 @@ qdel(src) else set_density(0) - new /obj/item/stack/material/rods(get_turf(src), 1, material.type) + if(material) + var/res = material.create_object(get_turf(src), 1, parts_type) + if(paint_color) + for(var/obj/item/thing in res) + thing.set_color(paint_color) destroyed = TRUE + parts_amount = 1 update_icon() -/obj/structure/grille/attackby(obj/item/W, mob/user) - if(isWirecutter(W)) +/obj/structure/grille/attackby(obj/item/used_item, mob/user) + if(IS_WIRECUTTER(used_item)) if(!material.conductive || !shock(user, 100)) cut_grille() + return TRUE - else if((isScrewdriver(W)) && (istype(loc, /turf/simulated) || anchored)) - if(!shock(user, 90)) - playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) - anchored = !anchored - user.visible_message(SPAN_NOTICE("[user] [anchored ? "fastens" : "unfastens"] the grille."), \ - SPAN_NOTICE("You have [anchored ? "fastened the grille to" : "unfastened the grill from"] the floor.")) - update_connections(1) - update_icon() - return - -//window placing - else if(istype(W,/obj/item/stack/material)) - var/obj/item/stack/material/ST = W + if((IS_SCREWDRIVER(used_item))) + var/turf/turf = loc + if(((istype(turf) && turf.simulated) || anchored)) + if(!shock(user, 90)) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) + anchored = !anchored + user.visible_message( + SPAN_NOTICE("[user] [anchored ? "fastens" : "unfastens"] the grille."), + SPAN_NOTICE("You have [anchored ? "fastened the grille to" : "unfastened the grill from"] the floor.") + ) + update_connections(1) + update_icon() + return TRUE + + //window placing + if(istype(used_item,/obj/item/stack/material)) + var/obj/item/stack/material/ST = used_item if(ST.material.opacity > 0.7) - return 0 + return FALSE var/dir_to_set = 5 if(!is_on_frame()) @@ -191,22 +200,24 @@ dir_to_set = get_dir(loc, user) if(dir_to_set & (dir_to_set - 1)) //Only works for cardinal direcitons, diagonals aren't supposed to work like this. to_chat(user, "You can't reach.") - return + return TRUE place_window(user, loc, dir_to_set, ST) - return + return TRUE - else if(!(W.obj_flags & OBJ_FLAG_CONDUCTIBLE) || !shock(user, 70)) + if(!(used_item.obj_flags & OBJ_FLAG_CONDUCTIBLE) || !shock(user, 70)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(src) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) - switch(W.damtype) - if("fire") - take_damage(W.force) - if("brute") - take_damage(W.force * 0.1) - ..() + switch(used_item.atom_damage_type) + if(BURN) + take_damage(used_item.expend_attack_force(user)) + if(BRUTE) + take_damage(used_item.expend_attack_force(user) * 0.1) + return TRUE + + return ..() -/obj/structure/grille/physically_destroyed() +/obj/structure/grille/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) if(!destroyed) visible_message(SPAN_DANGER("\The [src] falls to pieces!")) @@ -217,54 +228,40 @@ // returns 1 if shocked, 0 otherwise /obj/structure/grille/proc/shock(mob/user, prb) if(!anchored || destroyed) // anchored/destroyed grilles are never connected - return 0 + return FALSE if(!(material.conductive)) - return 0 + return FALSE if(!prob(prb)) - return 0 + return FALSE if(!in_range(src, user))//To prevent TK and exosuit users from getting shocked - return 0 - var/turf/T = get_turf(src) - var/obj/structure/cable/C = T.get_cable_node() - if(C) - if(electrocute_mob(user, C, src)) - if(C.powernet) - C.powernet.trigger_warning() - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - if(user.stunned) - return 1 - else - return 0 - return 0 + return FALSE + var/turf/my_turf = get_turf(src) + var/obj/structure/cable/cable = my_turf.get_cable_node() + if(!cable) + return FALSE + if(!electrocute_mob(user, cable, src)) + return FALSE + if(cable.powernet) + cable.powernet.trigger_warning() + spark_at(src, cardinal_only = TRUE) + return !!HAS_STATUS(user, STAT_STUN) /obj/structure/grille/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(!destroyed) - if(exposed_temperature > material.melting_point) - take_damage(1) + if(exposed_temperature > material.temperature_damage_threshold) + take_damage(1, BURN) ..() // Used in mapping to avoid /obj/structure/grille/broken destroyed = 1 icon_state = "broken" - density = 0 + density = FALSE /obj/structure/grille/broken/Initialize() . = ..() take_damage(rand(1, 5)) //In the destroyed but not utterly threshold. -/obj/structure/grille/cult - name = "cult grille" - desc = "A matrice built out of an unknown material, with some sort of force field blocking air around it." - material = /decl/material/solid/stone/cult - -/obj/structure/grille/cult/CanPass(atom/movable/mover, turf/target, height = 1.5, air_group = 0) - if(air_group) - return 0 //Make sure air doesn't drain - ..() - /obj/structure/grille/proc/is_on_frame() if(locate(/obj/structure/wall_frame) in loc) return TRUE @@ -280,6 +277,3 @@ var/obj/structure/grille/F = new(loc, ST.material.type) user.visible_message(SPAN_NOTICE("\The [user] finishes building \a [F].")) F.add_fingerprint(user) - -/obj/structure/grille/create_dismantled_products(var/turf/T) - new /obj/item/stack/material/rods(get_turf(src), (destroyed ? 1 : 2), material.type) diff --git a/code/game/objects/structures/hand_cart.dm b/code/game/objects/structures/hand_cart.dm new file mode 100644 index 000000000000..33b352889f37 --- /dev/null +++ b/code/game/objects/structures/hand_cart.dm @@ -0,0 +1,71 @@ +/obj/structure/hand_cart + name = "handcart" + desc = "A wheeled cart used to make heavy things less difficult to move through the power of lever-arm and the wheel." + icon = 'icons/obj/structures/handcart.dmi' + icon_state = "cart" + anchored = FALSE + density = TRUE + movable_flags = MOVABLE_FLAG_WHEELED + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR + material = /decl/material/solid/metal/steel + w_class = ITEM_SIZE_STRUCTURE + color = COLOR_ORANGE + var/pixel_y_offset = 4 + var/atom/movable/carrying + var/min_object_size = ITEM_SIZE_NORMAL + +/obj/structure/hand_cart/on_update_icon() + underlays.Cut() + ..() + underlays += "cart_wheel" + var/image/I = image(icon, "handcart_layer_north") + I.layer = STRUCTURE_LAYER + 0.02 + I.color = BlendHSV(color, material.color, 0.5) + add_overlay(I) + if(carrying) + var/image/CA = image(carrying.icon, carrying.icon_state) + CA.pixel_y = pixel_y_offset + CA.plane = plane + CA.layer = layer + 0.01 //just above STRUCTURE_LAYER + add_overlay(CA) + +/obj/structure/hand_cart/Destroy() + . = ..() + if(carrying) + carrying.forceMove(get_turf(src)) + carrying = null + +/obj/structure/hand_cart/grab_attack(obj/item/grab/grab, mob/user) + if(isobj(grab.affecting)) + to_chat(user, SPAN_NOTICE("You start loading \the [grab.affecting] onto \the [src].")) + if(load_item(grab.affecting, user)) + qdel(grab) + return TRUE + . = ..() + +/obj/structure/hand_cart/attack_hand(mob/user) + if(!carrying || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + unload_item(user) + return TRUE + +/obj/structure/hand_cart/proc/load_item(var/obj/A, var/user) + if(!A.anchored && (A.w_class > min_object_size)) + if(do_after(user, 2 SECONDS, src)) + var/image/I = image(A.icon, A.icon_state) + I.pixel_y = pixel_y_offset + I.plane = plane + I.layer = layer + 0.01 //just above STRUCTURE_LAYER + add_overlay(I) + A.forceMove(src) + carrying = A + to_chat(user, SPAN_NOTICE("You load \the [A] onto \the [src].")) + return TRUE + return FALSE + +/obj/structure/hand_cart/proc/unload_item(var/user) + if(carrying) + carrying.forceMove(get_turf(user)) + to_chat(user, SPAN_NOTICE("You unload \the [carrying] from \the [src].")) + carrying = null + update_icon() diff --git a/code/game/objects/structures/handrail.dm b/code/game/objects/structures/handrail.dm index 17e7b18843ea..77859925fc73 100644 --- a/code/game/objects/structures/handrail.dm +++ b/code/game/objects/structures/handrail.dm @@ -1,13 +1,17 @@ -/obj/structure/handrai +/obj/structure/handrail name = "handrail" icon = 'icons/obj/structures/handrail.dmi' icon_state = "handrail" desc = "A safety railing with buckles to secure yourself to when floor isn't stable enough." - density = 0 - anchored = 1 - can_buckle = 1 + density = FALSE + anchored = TRUE + can_buckle = TRUE + buckle_sound = 'sound/effects/buckle.ogg' + buckle_allow_rotation = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED -/obj/structure/handrai/buckle_mob(mob/living/M) - . = ..() - if(.) - playsound(src, 'sound/effects/buckle.ogg', 20) \ No newline at end of file +/obj/structure/handrail/attack_hand(mob/user) + if(!can_buckle || buckled_mob || !istype(user) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + user_buckle_mob(user, user) + return TRUE diff --git a/code/game/objects/structures/hay.dm b/code/game/objects/structures/hay.dm new file mode 100644 index 000000000000..71f6c73a0647 --- /dev/null +++ b/code/game/objects/structures/hay.dm @@ -0,0 +1,74 @@ +// Items that provide animal feed. +/datum/storage/haystack + can_hold = list(/obj/item/food/hay) + +// Not actually a food item, but you can eat it if you like. +/obj/item/food/hay + name = "handful of hay" + icon = 'icons/obj/food/hay.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/plantmatter/grass/dry + nutriment_amt = 1 + nutriment_type = /decl/material/solid/organic/plantmatter/grass + material_alteration = MAT_FLAG_ALTERATION_COLOR + +/obj/item/food/hay/end_throw() + . = ..() + addtimer(CALLBACK(src, PROC_REF(check_self_destroy)), 1, (TIMER_UNIQUE | TIMER_OVERRIDE) ) + +/obj/item/food/hay/proc/check_self_destroy() + if(isturf(loc) && !QDELETED(src)) + physically_destroyed() + +/obj/item/food/hay/physically_destroyed() + new /obj/effect/decal/cleanable/hay(loc) + . = ..() + +/obj/effect/decal/cleanable/hay + name = "loose hay" + desc = "Some loose hay from a haybale." + icon = 'icons/effects/hay.dmi' + icon_state = ICON_STATE_WORLD + color = /decl/material/solid/organic/plantmatter/grass/dry::color + sweepable = TRUE + +/obj/effect/decal/cleanable/hay/Initialize(ml, _age) + for(var/obj/effect/decal/cleanable/hay/hay in loc) + if(hay != src) + return INITIALIZE_HINT_QDEL + return ..() + +/obj/structure/haystack + name = "haystack" + desc = "A pile of dry, prickly hay. Not a great place for storing needles." + icon = 'icons/obj/structures/haystack.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/plantmatter/grass/dry + color = /decl/material/solid/organic/plantmatter/grass/dry::color + storage = /datum/storage/haystack + material_alteration = MAT_FLAG_ALTERATION_COLOR + atom_flags = ATOM_FLAG_CLIMBABLE + var/const/FOOD_MAX = 20 + +/obj/structure/haystack/Initialize(ml, _mat, _reinf_mat) + . = ..() + for(var/i = 1 to FOOD_MAX) + new /obj/item/food/hay(src) + storage.make_exact_fit() + +/obj/structure/haystack/Exited(atom/movable/am, atom/new_loc) + . = ..() + if(!QDELETED(src) && !length(contents)) + physically_destroyed() + +/obj/structure/haystack/create_matter() + matter = null // Haystack is almost a dummy item; the matter is the food inside. + +/obj/structure/haystack/physically_destroyed(skip_qdel) + new /obj/effect/decal/cleanable/hay(loc) + . = ..() + +/obj/structure/haystack/bale + name = "haybale" + desc = "A tight bundle of dry grass, probably set aside as animal feed." + icon = 'icons/obj/structures/haybale.dmi' diff --git a/code/game/objects/structures/holosigns.dm b/code/game/objects/structures/holosigns.dm index 1bc7ae8bf7b7..d0c2b590a36f 100644 --- a/code/game/objects/structures/holosigns.dm +++ b/code/game/objects/structures/holosigns.dm @@ -18,16 +18,17 @@ projector = null return ..() -/obj/structure/holosign/attack_hand(mob/living/user) +/obj/structure/holosign/attack_hand(mob/user) . = ..() - if(.) - return - visible_message(SPAN_NOTICE("\The [user] waves through \the [src], causing it to dissipate.")) - deactivate(user) + if(!.) + visible_message(SPAN_NOTICE("\The [user] waves through \the [src], causing it to dissipate.")) + deactivate(user) + return TRUE -/obj/structure/holosign/attackby(obj/W, mob/living/user) - visible_message(SPAN_NOTICE("\The [user] waves \a [W] through \the [src], causing it to dissipate.")) +/obj/structure/holosign/attackby(obj/item/used_item, mob/user) + visible_message(SPAN_NOTICE("\The [user] waves \a [used_item] through \the [src], causing it to dissipate.")) deactivate(user) + return TRUE /obj/structure/holosign/proc/deactivate(mob/living/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 1a3f467f9228..137ce1cba193 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -1,9 +1,11 @@ /obj/item/inflatable - name = "inflatable" - w_class = ITEM_SIZE_NORMAL + name = "inflatable wall" + desc = "A folded membrane which rapidly expands into a large cubical shape on activation." icon = 'icons/obj/structures/inflatable.dmi' - atmos_canpass = CANPASS_DENSITY - var/deploy_path = null + icon_state = "folded_wall" + material = /decl/material/solid/organic/plastic + w_class = ITEM_SIZE_NORMAL + var/deploy_path = /obj/structure/inflatable/wall var/inflatable_health /obj/item/inflatable/attack_self(mob/user) @@ -17,19 +19,13 @@ return playsound(loc, 'sound/items/zip.ogg', 75, 1) user.visible_message(SPAN_NOTICE("[user] inflates \the [src]."), SPAN_NOTICE("You inflate \the [src].")) - var/obj/structure/inflatable/R = new deploy_path(user.loc) - transfer_fingerprints_to(R) - R.add_fingerprint(user) + var/obj/structure/inflatable/debris = new deploy_path(user.loc) + transfer_fingerprints_to(debris) + debris.add_fingerprint(user) if(inflatable_health) - R.health = inflatable_health + debris.current_health = inflatable_health qdel(src) -/obj/item/inflatable/wall - name = "inflatable wall" - desc = "A folded membrane which rapidly expands into a large cubical shape on activation." - icon_state = "folded_wall" - deploy_path = /obj/structure/inflatable/wall - /obj/item/inflatable/door name = "inflatable door" desc = "A folded membrane which rapidly expands into a simple door on activation." @@ -38,15 +34,17 @@ deploy_path = /obj/structure/inflatable/door /obj/structure/inflatable - name = "inflatable" + name = "inflatable structure" desc = "An inflated membrane. Do not puncture." - density = 1 - anchored = 1 - opacity = 0 + density = TRUE + anchored = TRUE + opacity = FALSE icon = 'icons/obj/structures/inflatable.dmi' icon_state = "wall" - maxhealth = 20 + max_health = 20 hitsound = 'sound/effects/Glasshit.ogg' + atmos_canpass = CANPASS_DENSITY + material = /decl/material/solid/organic/plastic var/undeploy_path = null var/taped @@ -56,7 +54,7 @@ /obj/structure/inflatable/wall name = "inflatable wall" - undeploy_path = /obj/item/inflatable/wall + undeploy_path = /obj/item/inflatable /obj/structure/inflatable/Initialize() . = ..() @@ -68,43 +66,48 @@ STOP_PROCESSING(SSobj,src) return ..() -/obj/structure/inflatable/examine(mob/user, distance) +/obj/structure/inflatable/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(taped) - to_chat(user, SPAN_NOTICE("It's been duct taped in few places.")) + . += SPAN_NOTICE("It's been duct taped in few places.") /obj/structure/inflatable/Process() check_environment() -/obj/structure/inflatable/show_examined_damage(mob/user, var/perc) - if(perc >= 1) - to_chat(user, SPAN_NOTICE("It's undamaged.")) - else if(perc > 0.5) - to_chat(user, SPAN_WARNING("It's showing signs of damage.")) - else if(perc > 0) - to_chat(user, SPAN_DANGER("It's heavily damaged!")) - /obj/structure/inflatable/proc/check_environment() - var/min_pressure = INFINITY - var/max_pressure = 0 - var/max_local_temp = 0 - for(var/check_dir in GLOB.cardinal) - var/turf/T = get_step(get_turf(src), check_dir) - var/datum/gas_mixture/env = T.return_air() - var/pressure = env.return_pressure() - min_pressure = min(min_pressure, pressure) - max_pressure = max(max_pressure, pressure) - max_local_temp = max(max_local_temp, env.temperature) + var/turf/my_turf = get_turf(src) + if(!my_turf || !prob(50)) + return - if(prob(50) && (max_pressure - min_pressure > max_pressure_diff || max_local_temp > max_temp)) + var/airblock // zeroed by ATMOS_CANPASS_TURF + var/max_local_temp = 0 + var/take_environment_damage = get_surrounding_pressure_differential(my_turf, src) > max_pressure_diff + if(!take_environment_damage) + for(var/check_dir in global.cardinal) + var/turf/neighbour = get_step(my_turf, check_dir) + if(!istype(neighbour)) + continue + for(var/obj/O in my_turf) + if(O == src) + continue + ATMOS_CANPASS_MOVABLE(airblock, O, neighbour) + . |= airblock + if(airblock & AIR_BLOCKED) + continue + ATMOS_CANPASS_TURF(airblock, neighbour, my_turf) + if(airblock & AIR_BLOCKED) + continue + max_local_temp = max(max_local_temp, neighbour.return_air()?.temperature) + + if(take_environment_damage || max_local_temp > max_temp) take_damage(1) /obj/structure/inflatable/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) return 0 /obj/structure/inflatable/bullet_act(var/obj/item/projectile/Proj) - take_damage(Proj.get_structure_damage()) + take_damage(Proj.get_structure_damage(), Proj.atom_damage_type) if(QDELETED(src)) return PROJECTILE_CONTINUE @@ -116,34 +119,37 @@ else if(severity == 2 || (severity == 3 && prob(50))) deflate(TRUE) -/obj/structure/inflatable/attack_hand(mob/user) - add_fingerprint(user) - /obj/structure/inflatable/can_repair_with(obj/item/tool) - . = istype(tool, /obj/item/tape_roll) && (health < maxhealth) + . = istype(tool, /obj/item/stack/tape_roll/duct_tape) && (current_health < get_max_health()) /obj/structure/inflatable/handle_repair(mob/user, obj/item/tool) + var/obj/item/stack/tape_roll/duct_tape/T = tool if(taped) to_chat(user, SPAN_WARNING("You cannot tape up \the [src] any further.")) return + if(T.can_use(2)) + to_chat(user, SPAN_WARNING("You need 2 [T.plural_name] to repair \the [src].")) + return + T.use(2) + playsound(src, 'sound/effects/tape.ogg', 50, TRUE) last_damage_message = null to_chat(user, SPAN_NOTICE("You tape up some of the damage to \the [src].")) - health = Clamp(health + 3, 0, maxhealth) + current_health = clamp(current_health + 3, 0, get_max_health()) taped = TRUE -/obj/structure/inflatable/attackby(obj/item/W, mob/user) +/obj/structure/inflatable/attackby(obj/item/used_item, mob/user) - if((W.damtype == BRUTE || W.damtype == BURN) && (W.can_puncture() || W.force > 10)) - visible_message(SPAN_DANGER("\The [user] pierces \the [src] with \the [W]!")) + if((used_item.atom_damage_type == BRUTE || used_item.atom_damage_type == BURN) && (used_item.can_puncture() || used_item.expend_attack_force(user) > 10)) + visible_message(SPAN_DANGER("\The [user] pierces \the [src] with \the [used_item]!")) deflate(TRUE) return TRUE - if(!istype(W, /obj/item/inflatable_dispenser)) + if(!istype(used_item, /obj/item/inflatable_dispenser)) return ..() return FALSE -/obj/structure/inflatable/physically_destroyed() +/obj/structure/inflatable/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) . = deflate(1) @@ -154,17 +160,16 @@ playsound(loc, 'sound/machines/hiss.ogg', 75, 1) if(violent) visible_message("[src] rapidly deflates!") - var/obj/item/inflatable/torn/R = new /obj/item/inflatable/torn(loc) - src.transfer_fingerprints_to(R) + transfer_fingerprints_to(new /obj/item/inflatable/torn(loc)) qdel(src) else if(!undeploy_path) return visible_message("\The [src] slowly deflates.") spawn(50) - var/obj/item/inflatable/R = new undeploy_path(src.loc) - src.transfer_fingerprints_to(R) - R.inflatable_health = health + var/obj/item/inflatable/door_item = new undeploy_path(src.loc) + src.transfer_fingerprints_to(door_item) + door_item.inflatable_health = current_health qdel(src) /obj/structure/inflatable/verb/hand_deflate() @@ -184,17 +189,18 @@ /obj/structure/inflatable/door //Based on mineral door code name = "inflatable door" - density = 1 - anchored = 1 - opacity = 0 + density = TRUE + anchored = TRUE + opacity = FALSE icon_state = "door_closed" undeploy_path = /obj/item/inflatable/door + atmos_canpass = CANPASS_PROC var/state = 0 //closed, 1 == open var/isSwitchingStates = 0 -/obj/structure/inflatable/door/attack_ai(mob/user) //those aren't machinery, they're just big fucking slabs of a mineral +/obj/structure/inflatable/door/attack_ai(mob/living/silicon/ai/user) //those aren't machinery, they're just big fucking slabs of a mineral if(isAI(user)) //so the AI can't open it return else if(isrobot(user)) //but cyborgs can @@ -202,12 +208,14 @@ return TryToSwitchState(user) /obj/structure/inflatable/door/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HARM) || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() return TryToSwitchState(user) /obj/structure/inflatable/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group) return state - if(istype(mover, /obj/effect/beam)) + if(istype(mover, /obj/effect/ir_beam)) return !opacity return !density @@ -216,9 +224,9 @@ if(ismob(user)) var/mob/M = user if(M.client) - if(iscarbon(M)) - var/mob/living/carbon/C = M - if(!C.handcuffed) + if(isliving(M)) + var/mob/living/holder = M + if(!holder.get_equipped_item(slot_handcuffed_str)) SwitchState() else SwitchState() @@ -251,6 +259,7 @@ isSwitchingStates = 0 /obj/structure/inflatable/door/on_update_icon() + ..() if(state) icon_state = "door_open" else @@ -260,15 +269,15 @@ playsound(loc, 'sound/machines/hiss.ogg', 75, 1) if(violent) visible_message("[src] rapidly deflates!") - var/obj/item/inflatable/door/torn/R = new /obj/item/inflatable/door/torn(loc) - src.transfer_fingerprints_to(R) + transfer_fingerprints_to(new /obj/item/inflatable/door/torn(loc)) qdel(src) else visible_message("[src] slowly deflates.") spawn(50) - var/obj/item/inflatable/door/R = new /obj/item/inflatable/door(loc) - src.transfer_fingerprints_to(R) - qdel(src) + if(!QDELETED(src)) + if(loc) + transfer_fingerprints_to(new /obj/item/inflatable/door(loc)) + qdel(src) /obj/item/inflatable/torn name = "torn inflatable wall" @@ -276,9 +285,9 @@ icon = 'icons/obj/structures/inflatable.dmi' icon_state = "folded_wall_torn" - attack_self(mob/user) - to_chat(user, "The inflatable wall is too torn to be inflated!") - add_fingerprint(user) +/obj/item/inflatable/torn/attack_self(mob/user) + to_chat(user, "The inflatable wall is too torn to be inflated!") + add_fingerprint(user) /obj/item/inflatable/door/torn name = "torn inflatable door" @@ -286,17 +295,20 @@ icon = 'icons/obj/structures/inflatable.dmi' icon_state = "folded_door_torn" - attack_self(mob/user) - to_chat(user, "The inflatable door is too torn to be inflated!") - add_fingerprint(user) +/obj/item/inflatable/door/torn/attack_self(mob/user) + to_chat(user, "The inflatable door is too torn to be inflated!") + add_fingerprint(user) -/obj/item/storage/briefcase/inflatable +/obj/item/briefcase/inflatable name = "inflatable barrier box" desc = "Contains inflatable walls and doors." icon = 'icons/obj/items/storage/inflatables.dmi' - icon_state = "inf_box" - item_state = "syringe_kit" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_LARGE - max_storage_space = DEFAULT_LARGEBOX_STORAGE - can_hold = list(/obj/item/inflatable) - startswith = list(/obj/item/inflatable/door = 2, /obj/item/inflatable/wall = 3) + storage = /datum/storage/briefcase/inflatables + +/obj/item/briefcase/inflatable/WillContain() + return list( + /obj/item/inflatable/door = 2, + /obj/item/inflatable = 3 + ) diff --git a/code/game/objects/structures/ironing_board.dm b/code/game/objects/structures/ironing_board.dm index 6eeb4cf474de..a6c821cadf72 100644 --- a/code/game/objects/structures/ironing_board.dm +++ b/code/game/objects/structures/ironing_board.dm @@ -7,7 +7,7 @@ var/obj/item/clothing/cloth // the clothing on the ironing board var/obj/item/ironingiron/holding // ironing iron on the board - var/list/move_sounds = list( // some nasty sounds to make when moving the board + var/static/list/move_sounds = list( // some nasty sounds to make when moving the board 'sound/effects/metalscrape1.ogg', 'sound/effects/metalscrape2.ogg', 'sound/effects/metalscrape3.ogg' @@ -24,28 +24,29 @@ . = ..() -/obj/structure/bed/roller/ironingboard/proc/remove_item(var/obj/item/I) - if(I == cloth) +/obj/structure/bed/roller/ironingboard/proc/remove_item(var/obj/item/used_item) + if(used_item == cloth) cloth = null - else if(I == holding) + else if(used_item == holding) holding = null update_icon() - GLOB.destroyed_event.unregister(I, src, /obj/structure/bed/roller/ironingboard/proc/remove_item) + events_repository.unregister(/decl/observ/destroyed, used_item, src, TYPE_PROC_REF(/obj/structure/bed/roller/ironingboard, remove_item)) // make a screeching noise to drive people mad /obj/structure/bed/roller/ironingboard/Move() - var/turf/T = get_turf(src) - if(isspace(T) || istype(T, /turf/simulated/floor/carpet)) + . = ..() + if(!.) return + var/turf/T = get_turf(src) + if(isspaceturf(T) || istype(T, /turf/floor/carpet)) + return FALSE playsound(T, pick(move_sounds), 75, 1) - . = ..() - -/obj/structure/bed/roller/ironingboard/examine(mob/user) +/obj/structure/bed/roller/ironingboard/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(cloth) - to_chat(user, "\The \icon[cloth] [cloth] lies on it.") + . += SPAN_NOTICE("\The [html_icon(cloth)] [cloth] lies on it.") /obj/structure/bed/roller/ironingboard/on_update_icon() if(density) @@ -55,76 +56,78 @@ if(holding) icon_state = "holding" - overlays.Cut() + ..() if(cloth) - overlays += new /icon(cloth.icon, cloth.icon_state) + add_overlay(image(cloth.icon, cloth.icon_state)) -/obj/structure/bed/roller/ironingboard/attackby(var/obj/item/I, var/mob/user) +/obj/structure/bed/roller/ironingboard/attackby(var/obj/item/used_item, var/mob/user) if(!density) - if(istype(I,/obj/item/clothing) || istype(I,/obj/item/ironingiron)) + if(istype(used_item,/obj/item/clothing) || istype(used_item,/obj/item/ironingiron)) to_chat(user, "[src] isn't deployed!") - return + return TRUE return ..() - if(istype(I,/obj/item/clothing)) + if(istype(used_item,/obj/item/clothing)) if(cloth) to_chat(user, "[cloth] is already on the ironing table!") - return + return TRUE if(buckled_mob) to_chat(user, "[buckled_mob] is already on the ironing table!") - return + return TRUE - if(user.unEquip(I, src)) - cloth = I - GLOB.destroyed_event.register(I, src, /obj/structure/bed/roller/ironingboard/proc/remove_item) + if(user.try_unequip(used_item, src)) + cloth = used_item + events_repository.register(/decl/observ/destroyed, used_item, src, TYPE_PROC_REF(/obj/structure/bed/roller/ironingboard, remove_item)) update_icon() - return - else if(istype(I,/obj/item/ironingiron)) - var/obj/item/ironingiron/R = I + return TRUE + else if(istype(used_item,/obj/item/ironingiron)) + var/obj/item/ironingiron/iron = used_item // anti-wrinkle "massage" if(buckled_mob && ishuman(buckled_mob)) - var/mob/living/carbon/human/H = buckled_mob - var/zone = user.zone_sel.selecting + var/mob/living/human/H = buckled_mob + var/zone = user.get_target_zone() var/parsed = parse_zone(zone) visible_message("[user] begins ironing [src.buckled_mob]'s [parsed]!", "You begin ironing [buckled_mob]'s [parsed]!") if(!do_after(user, 40, src)) - return + return TRUE visible_message("[user] irons [src.buckled_mob]'s [parsed]!", "You iron [buckled_mob]'s [parsed]!") - var/obj/item/organ/external/affecting = H.get_organ(zone) - affecting.take_external_damage(0, 15, used_weapon = "Hot metal") + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(H, zone) + affecting.take_damage(15, BURN, inflicter = "Hot metal") - return + return TRUE if(!cloth) - if(!holding && !R.enabled && user.unEquip(I, src)) - holding = R - GLOB.destroyed_event.register(I, src, /obj/structure/bed/roller/ironingboard/proc/remove_item) + if(!holding && !iron.enabled && user.try_unequip(used_item, src)) + holding = iron + events_repository.register(/decl/observ/destroyed, used_item, src, TYPE_PROC_REF(/obj/structure/bed/roller/ironingboard, remove_item)) update_icon() - return + return TRUE to_chat(user, "There isn't anything on the ironing board.") - return + return TRUE visible_message("[user] begins ironing [cloth].") - if(!do_after(user, 40, src)) - return + if(!do_after(user, 4 SECONDS, src)) + return TRUE visible_message("[user] finishes ironing [cloth].") cloth.ironed_state = WRINKLES_NONE - return + return TRUE - ..() + return ..() /obj/structure/bed/roller/ironingboard/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE) || buckled_mob) + return ..() //Takes care of unbuckling. if(density) // check if it's deployed if(holding && user.put_in_hands(holding)) remove_item(holding) - return + return TRUE if(cloth && user.put_in_hands(cloth)) remove_item(cloth) - return + return TRUE if(!buckled_mob) to_chat(user, "You fold the ironing table down.") set_density(0) @@ -132,7 +135,7 @@ to_chat(user, "You deploy the ironing table.") set_density(1) update_icon() - . = ..() //Takes care of unbuckling. + return TRUE /obj/structure/bed/roller/ironingboard/collapse() var/turf/T = get_turf(src) @@ -148,4 +151,5 @@ name = "ironing board" desc = "A collapsed ironing board that can be carried around." icon = 'icons/obj/structures/ironing.dmi' + icon_state = "folded" structure_form_type = /obj/structure/bed/roller/ironingboard \ No newline at end of file diff --git a/code/game/objects/structures/iv_drip.dm b/code/game/objects/structures/iv_drip.dm index 0294d436dc3c..661a79f2e52b 100644 --- a/code/game/objects/structures/iv_drip.dm +++ b/code/game/objects/structures/iv_drip.dm @@ -1,88 +1,107 @@ /obj/structure/iv_drip name = "\improper IV drip" icon = 'icons/obj/structures/iv_drip.dmi' - anchored = 0 - density = 0 - var/mob/living/carbon/human/attached + anchored = FALSE + density = FALSE + + var/mob/living/human/attached var/mode = 1 // 1 is injecting, 0 is taking blood. var/obj/item/chems/beaker var/list/transfer_amounts = list(REM, 1, 2) var/transfer_amount = 1 +/obj/structure/iv_drip/Initialize() + . = ..() + update_icon() + /obj/structure/iv_drip/verb/set_amount_per_transfer_from_this() set name = "Set IV transfer amount" set category = "Object" set src in range(1) + if(!CanPhysicallyInteract(usr)) - to_chat(usr, "You're in no condition to do that!'") + to_chat(usr, SPAN_WARNING("You're in no condition to do that!")) return + var/N = input("Amount per transfer from this:","[src]") as null|anything in transfer_amounts if(!CanPhysicallyInteract(usr)) // because input takes time and the situation can change - to_chat(usr, "You're in no condition to do that!'") + to_chat(usr, SPAN_WARNING("You're in no condition to do that!")) return if(N) transfer_amount = N /obj/structure/iv_drip/on_update_icon() - if(attached) - icon_state = "hooked" - else - icon_state = "" + ..() - overlays.Cut() - - if(beaker) - var/datum/reagents/reagents = beaker.reagents - var/percent = round((reagents.total_volume / beaker.volume) * 100) - if(reagents.total_volume) - var/image/filling = image(icon, src, "reagent") + var/mutable_appearance/base = mutable_appearance(icon, "nothing") + base.icon_state = "[beaker ? "beaker" : "nothing"][attached ? "_hooked" : ""]" + add_overlay(base) + if(beaker?.reagents) + var/percent = round((REAGENT_TOTAL_VOLUME(beaker.reagents) / REAGENT_MAXIMUM_VOLUME(beaker.reagents)) * 100) + if(REAGENT_TOTAL_VOLUME(beaker.reagents)) + var/mutable_appearance/filling = mutable_appearance(icon, "reagent") switch(percent) - if(0 to 9) filling.icon_state = "reagent0" - if(10 to 24) filling.icon_state = "reagent10" - if(25 to 49) filling.icon_state = "reagent25" - if(50 to 74) filling.icon_state = "reagent50" - if(75 to 79) filling.icon_state = "reagent75" - if(80 to 90) filling.icon_state = "reagent80" - if(91 to INFINITY) filling.icon_state = "reagent100" - filling.icon += reagents.get_color() - overlays += filling + if(0) + filling.icon_state = "reagentempty" + if(1 to 9) + filling.icon_state = "reagent0" + if(10 to 24) + filling.icon_state = "reagent10" + if(25 to 49) + filling.icon_state = "reagent25" + if(50 to 74) + filling.icon_state = "reagent50" + if(75 to 79) + filling.icon_state = "reagent75" + if(80 to 90) + filling.icon_state = "reagent80" + if(91 to INFINITY) + filling.icon_state = "reagent100" + filling.color = beaker.reagents.get_color() + add_overlay(filling) + + if(istype(beaker, /obj/item/chems/ivbag)) + var/mutable_appearance/ivbaglabel = mutable_appearance(icon, "ivbag_label") + add_overlay(ivbaglabel) if(attached) - var/image/light = image(icon, "light_full") + var/mutable_appearance/light = mutable_appearance(icon, "light_full") if(percent < 15) light.icon_state = "light_low" else if(percent < 60) light.icon_state = "light_mid" - overlays += light -/obj/structure/iv_drip/MouseDrop(over_object, src_location, over_location) - if(!CanMouseDrop(over_object)) - return + add_overlay(light) + +/obj/structure/iv_drip/handle_mouse_drop(atom/over, mob/user, params) if(attached) drip_detach() - else if(ishuman(over_object)) - hook_up(over_object, usr) + return TRUE + if(ishuman(over)) + hook_up(over, user) + return TRUE + . = ..() -/obj/structure/iv_drip/attackby(obj/item/W, mob/user) - if (istype(W, /obj/item/chems)) +/obj/structure/iv_drip/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/chems)) if(!isnull(src.beaker)) to_chat(user, "There is already a reagent container loaded!") - return - if(!user.unEquip(W, src)) - return - beaker = W - to_chat(user, "You attach \the [W] to \the [src].") + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + beaker = used_item + to_chat(user, "You attach \the [used_item] to \the [src].") queue_icon_update() + return TRUE else return ..() /obj/structure/iv_drip/Destroy() STOP_PROCESSING(SSobj,src) attached = null - qdel(beaker) - beaker = null - . = ..() + QDEL_NULL(beaker) + return ..() /obj/structure/iv_drip/Process() if(attached) @@ -94,19 +113,19 @@ if(!beaker) return - + //SSObj fires twice as fast as SSMobs, so gotta slow down to not OD our victims. if(SSobj.times_fired % 2) return if(mode) // Give blood - if(beaker.volume > 0) + if(REAGENT_TOTAL_VOLUME(beaker.reagents) > 0) beaker.reagents.trans_to_mob(attached, transfer_amount, CHEM_INJECT) queue_icon_update() else // Take blood - var/amount = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = REAGENT_MAXIMUM_VOLUME(beaker.reagents) - REAGENT_TOTAL_VOLUME(beaker.reagents) amount = min(amount, 4) - + if(amount == 0) // If the beaker is full, ping if(prob(5)) visible_message("\The [src] pings.") return @@ -122,81 +141,77 @@ queue_icon_update() /obj/structure/iv_drip/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) + return ..() if(attached) drip_detach() else if(beaker) beaker.dropInto(loc) beaker = null queue_icon_update() - else - return ..() + return TRUE /obj/structure/iv_drip/attack_robot(var/mob/user) - if(Adjacent(user)) - attack_hand(user) + return attack_hand_with_interaction_checks(user) /obj/structure/iv_drip/verb/drip_detach() set category = "Object" set name = "Detach IV Drip" set src in range(1) - + if(!attached) return - + if(!CanPhysicallyInteractWith(usr, src)) - to_chat(usr, SPAN_NOTICE("You're in no condition to do that!")) + to_chat(usr, SPAN_WARNING("You're in no condition to do that!")) return - + if(!usr.skill_check(SKILL_MEDICAL, SKILL_BASIC)) rip_out() else visible_message("\The [attached] is taken off \the [src].") attached = null - + queue_icon_update() STOP_PROCESSING(SSobj,src) - + /obj/structure/iv_drip/verb/toggle_mode() set category = "Object" set name = "Toggle IV Mode" set src in view(1) if(!CanPhysicallyInteract(usr)) - to_chat(usr, "You're in no condition to do that!'") + to_chat(usr, SPAN_WARNING("You're in no condition to do that!")) return mode = !mode to_chat(usr, "The IV drip is now [mode ? "injecting" : "taking blood"].") -/obj/structure/iv_drip/examine(mob/user, distance) +/obj/structure/iv_drip/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - - if (distance >= 2) + if (distance >= 2) return - - to_chat(user, "The IV drip is [mode ? "injecting" : "taking blood"].") - to_chat(user, "It is set to transfer [transfer_amount]u of chemicals per cycle.") - + . += "The IV drip is [mode ? "injecting" : "taking blood"]." + . += "It is set to transfer [transfer_amount]u of chemicals per cycle." if(beaker) - if(beaker.reagents && beaker.reagents.total_volume) - to_chat(usr, "Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.") + if(REAGENT_TOTAL_VOLUME(beaker.reagents)) + . += SPAN_NOTICE("Attached is \a [beaker] with [REAGENT_TOTAL_VOLUME(beaker.reagents)] units of liquid.") else - to_chat(usr, "Attached is an empty [beaker].") + . += SPAN_NOTICE("Attached is an empty [beaker].") else - to_chat(usr, "No chemicals are attached.") - - to_chat(usr, "[attached ? attached : "No one"] is hooked up to it.") + . += SPAN_NOTICE("No chemicals are attached.") + . += SPAN_NOTICE("[attached ? attached : "No one"] is hooked up to it.") /obj/structure/iv_drip/proc/rip_out() visible_message("The needle is ripped out of [src.attached], doesn't that hurt?") attached.apply_damage(1, BRUTE, pick(BP_R_ARM, BP_L_ARM), damage_flags=DAM_SHARP) attached = null -/obj/structure/iv_drip/proc/hook_up(mob/living/carbon/human/target, mob/user) +/obj/structure/iv_drip/proc/hook_up(mob/living/human/target, mob/user) if(do_IV_hookup(target, user, src)) attached = target START_PROCESSING(SSobj,src) -/proc/do_IV_hookup(mob/living/carbon/human/target, mob/user, obj/IV) - to_chat(user, "You start to hook up \the [target] to \the [IV].") +/proc/do_IV_hookup(mob/living/human/target, mob/user, obj/IV) + to_chat(user, SPAN_NOTICE("You start to hook up \the [target] to \the [IV].")) if(!user.do_skilled(2 SECONDS, SKILL_MEDICAL, target)) return FALSE @@ -206,4 +221,4 @@ return FALSE user.visible_message("\The [user] hooks \the [target] up to \the [IV].") - return TRUE \ No newline at end of file + return TRUE diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 63b2d64bf176..75f4e5f78586 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -3,91 +3,94 @@ desc = "The ultimate in janitorial carts! Has space for water, mops, signs, trash bags, and more!" icon = 'icons/obj/janitor.dmi' icon_state = "cart" - anchored = 0 - density = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_CLIMBABLE - //copypaste sorry - var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite - var/obj/item/storage/bag/trash/mybag = null + anchored = FALSE + density = TRUE + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_CLIMBABLE + movable_flags = MOVABLE_FLAG_WHEELED + chem_volume = 180 + + var/obj/item/bag/trash/mybag = null var/obj/item/mop/mymop = null var/obj/item/chems/spray/myspray = null var/obj/item/lightreplacer/myreplacer = null var/signs = 0 //maximum capacity hardcoded below - -/obj/structure/janitorialcart/Initialize() - . = ..() - create_reagents(180) - -/obj/structure/janitorialcart/examine(mob/user, distance) +/obj/structure/janitorialcart/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "[src] \icon[src] contains [reagents.total_volume] unit\s of liquid!") - + . += "\The [src] [html_icon(src)] contains [REAGENT_TOTAL_VOLUME(reagents)] unit\s of liquid!" -/obj/structure/janitorialcart/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/storage/bag/trash) && !mybag) - if(!user.unEquip(I, src)) - return - mybag = I +/obj/structure/janitorialcart/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/bag/trash) && !mybag) + if(!user.try_unequip(used_item, src)) + return TRUE + mybag = used_item update_icon() updateUsrDialog() - to_chat(user, "You put [I] into [src].") + to_chat(user, "You put [used_item] into [src].") + return TRUE - else if(istype(I, /obj/item/mop)) - if(I.reagents.total_volume < I.reagents.maximum_volume) //if it's not completely soaked we assume they want to wet it, otherwise store it - if(reagents.total_volume < 1) + else if(istype(used_item, /obj/item/mop)) + if(REAGENT_TOTAL_VOLUME(used_item.reagents) < REAGENT_MAXIMUM_VOLUME(used_item.reagents)) //if it's not completely soaked we assume they want to wet it, otherwise store it + if(REAGENT_TOTAL_VOLUME(reagents) < 1) to_chat(user, "[src] is out of water!") else - reagents.trans_to_obj(I, I.reagents.maximum_volume) - to_chat(user, "You wet [I] in [src].") + reagents.trans_to_obj(used_item, REAGENT_MAXIMUM_VOLUME(used_item.reagents)) + to_chat(user, "You wet [used_item] in [src].") playsound(loc, 'sound/effects/slosh.ogg', 25, 1) - return + return TRUE if(!mymop) - if(!user.unEquip(I, src)) - return - mymop = I + if(!user.try_unequip(used_item, src)) + return TRUE + mymop = used_item update_icon() updateUsrDialog() - to_chat(user, "You put [I] into [src].") + to_chat(user, "You put [used_item] into [src].") + return TRUE - else if(istype(I, /obj/item/chems/spray) && !myspray) - if(!user.unEquip(I, src)) - return - myspray = I + else if(istype(used_item, /obj/item/chems/spray) && !myspray) + if(!user.try_unequip(used_item, src)) + return TRUE + myspray = used_item update_icon() updateUsrDialog() - to_chat(user, "You put [I] into [src].") + to_chat(user, "You put [used_item] into [src].") + return TRUE - else if(istype(I, /obj/item/lightreplacer) && !myreplacer) - if(!user.unEquip(I, src)) - return - myreplacer = I + else if(istype(used_item, /obj/item/lightreplacer) && !myreplacer) + if(!user.try_unequip(used_item, src)) + return TRUE + myreplacer = used_item update_icon() updateUsrDialog() - to_chat(user, "You put [I] into [src].") + to_chat(user, "You put [used_item] into [src].") + return TRUE - else if(istype(I, /obj/item/caution)) + else if(istype(used_item, /obj/item/caution)) if(signs < 4) - if(!user.unEquip(I, src)) - return + if(!user.try_unequip(used_item, src)) + return TRUE signs++ update_icon() updateUsrDialog() - to_chat(user, "You put [I] into [src].") + to_chat(user, "You put [used_item] into [src].") else to_chat(user, "[src] can't hold any more signs.") + return TRUE - else if(istype(I, /obj/item/chems/glass)) - return // So we do not put them in the trash bag as we mean to fill the mop bucket + else if(istype(used_item, /obj/item/chems/glass)) + return FALSE // So we do not put them in the trash bag as we mean to fill the mop bucket; FALSE means run afterattack else if(mybag) - mybag.attackby(I, user) + return mybag.attackby(used_item, user) + return ..() /obj/structure/janitorialcart/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() ui_interact(user) - return + return TRUE /obj/structure/janitorialcart/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] @@ -104,184 +107,167 @@ ui.set_initial_data(data) ui.open() -/obj/structure/janitorialcart/Topic(href, href_list) - if(!in_range(src, usr)) - return - if(!isliving(usr)) - return - var/mob/living/user = usr - - if(href_list["take"]) - switch(href_list["take"]) - if("garbage") - if(mybag) - user.put_in_hands(mybag) - to_chat(user, "You take [mybag] from [src].") - mybag = null - if("mop") - if(mymop) - user.put_in_hands(mymop) - to_chat(user, "You take [mymop] from [src].") - mymop = null - if("spray") - if(myspray) - user.put_in_hands(myspray) - to_chat(user, "You take [myspray] from [src].") - myspray = null - if("replacer") - if(myreplacer) - user.put_in_hands(myreplacer) - to_chat(user, "You take [myreplacer] from [src].") - myreplacer = null - if("sign") - if(signs) - var/obj/item/caution/Sign = locate() in src - if(Sign) - user.put_in_hands(Sign) - to_chat(user, "You take \a [Sign] from [src].") - signs-- - else - warning("[src] signs ([signs]) didn't match contents") - signs = 0 - - update_icon() - updateUsrDialog() - +/obj/structure/janitorialcart/OnTopic(mob/user, href_list) + switch(href_list["take"]) + if("garbage") + if(mybag) + user.put_in_hands(mybag) + to_chat(user, "You take [mybag] from [src].") + mybag = null + return TOPIC_REFRESH + return TOPIC_HANDLED + if("mop") + if(mymop) + user.put_in_hands(mymop) + to_chat(user, "You take [mymop] from [src].") + mymop = null + return TOPIC_REFRESH + return TOPIC_HANDLED + if("spray") + if(myspray) + user.put_in_hands(myspray) + to_chat(user, "You take [myspray] from [src].") + myspray = null + return TOPIC_REFRESH + return TOPIC_HANDLED + if("replacer") + if(myreplacer) + user.put_in_hands(myreplacer) + to_chat(user, "You take [myreplacer] from [src].") + myreplacer = null + return TOPIC_REFRESH + return TOPIC_HANDLED + if("sign") + if(signs) + var/obj/item/caution/Sign = locate() in src + if(Sign) + user.put_in_hands(Sign) + to_chat(user, "You take \a [Sign] from [src].") + signs-- + else + warning("[src] signs ([signs]) didn't match contents") + signs = 0 + return TOPIC_REFRESH + return TOPIC_HANDLED + else + return TOPIC_NOACTION /obj/structure/janitorialcart/on_update_icon() - overlays.Cut() + ..() if(mybag) - overlays += "cart_garbage" + add_overlay("cart_garbage") if(mymop) - overlays += "cart_mop" + add_overlay("cart_mop") if(myspray) - overlays += "cart_spray" + add_overlay("cart_spray") if(myreplacer) - overlays += "cart_replacer" + add_overlay("cart_replacer") if(signs) - overlays += "cart_sign[signs]" + add_overlay("cart_sign[signs]") +/datum/movement_handler/move_relay_self/janicart/MayMove(mob/mover, is_external) + . = ..() + if(. == MOVEMENT_PROCEED && !is_external && !(locate(/obj/item/janicart_key) in mover.get_held_items())) + var/obj/structure/janicart/janicart = host + to_chat(mover, SPAN_WARNING("You'll need the keys in one of your hands to drive this [istype(janicart) ? janicart.callme : host.name].")) + return MOVEMENT_STOP -//old style retardo-cart -/obj/structure/bed/chair/janicart +//old style cart +/obj/structure/janicart name = "janicart" icon = 'icons/obj/vehicles.dmi' icon_state = "pussywagon" - anchored = 1 - density = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER - //copypaste sorry - var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite - var/obj/item/storage/bag/trash/mybag = null + can_buckle = TRUE + buckle_lying = FALSE // force people to sit up when buckled to it + buckle_sound = 'sound/effects/buckle.ogg' + buckle_layer_above = TRUE + buckle_movable = TRUE + color = null + anchored = FALSE + density = TRUE + material_alteration = MAT_FLAG_ALTERATION_NONE + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 100 + movement_handlers = list( + /datum/movement_handler/deny_multiz, + /datum/movement_handler/delay = list(1), + /datum/movement_handler/move_relay_self/janicart + ) + var/obj/item/bag/trash/mybag = null var/callme = "pimpin' ride" //how do people refer to it? - -/obj/structure/bed/chair/janicart/Initialize() +/obj/structure/janicart/Initialize() + // Handled in init due to dirs needing to be stringified + buckle_pixel_shift = list( + "[NORTH]" = list("x" = 0, "y" = 4, "z" = 0), + "[SOUTH]" = list("x" = 0, "y" = 7, "z" = 0), + "[EAST]" = list("x" = -13, "y" = 7, "z" = 0), + "[WEST]" = list("x" = 13, "y" = 7, "z" = 0) + ) . = ..() - create_reagents(100) -/obj/structure/bed/chair/janicart/examine(mob/user, distance) +/obj/structure/janicart/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance > 1) - return - - to_chat(user, "\icon[src] This [callme] contains [reagents.total_volume] unit\s of water!") - if(mybag) - to_chat(user, "\A [mybag] is hanging on the [callme].") + if(distance <= 1) + . += "[html_icon(src)] This [callme] contains [REAGENT_TOTAL_VOLUME(reagents)] unit\s of water!" + if(mybag) + . += "\A [mybag] is hanging on the [callme]." +/obj/structure/janicart/attackby(obj/item/used_item, mob/user) -/obj/structure/bed/chair/janicart/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/mop)) - if(reagents.total_volume > 1) - reagents.trans_to_obj(I, 2) - to_chat(user, "You wet [I] in the [callme].") + if(istype(used_item, /obj/item/mop)) + if(REAGENT_TOTAL_VOLUME(reagents) > 1) + reagents.trans_to_obj(used_item, 2) + to_chat(user, SPAN_NOTICE("You wet [used_item] in the [callme].")) playsound(loc, 'sound/effects/slosh.ogg', 25, 1) else - to_chat(user, "This [callme] is out of water!") - else if(istype(I, /obj/item/key)) - to_chat(user, "Hold [I] in one of your hands while you drive this [callme].") - else if(istype(I, /obj/item/storage/bag/trash)) - if(!user.unEquip(I, src)) - return - to_chat(user, "You hook the trashbag onto the [callme].") - mybag = I - + to_chat(user, SPAN_NOTICE("This [callme] is out of water!")) + return TRUE -/obj/structure/bed/chair/janicart/attack_hand(mob/user) - if(mybag) - user.put_in_hands(mybag) - mybag = null - else - ..() - - -/obj/structure/bed/chair/janicart/relaymove(mob/user, direction) - if(user.stat || user.stunned || user.weakened || user.paralysis) - unbuckle_mob() - if(istype(user.l_hand, /obj/item/key) || istype(user.r_hand, /obj/item/key)) - step(src, direction) - update_mob() - else - to_chat(user, "You'll need the keys in one of your hands to drive this [callme].") - - -/obj/structure/bed/chair/janicart/Move() - ..() - if(buckled_mob && (buckled_mob.buckled == src)) - buckled_mob.dropInto(loc) - - -/obj/structure/bed/chair/janicart/post_buckle_mob(mob/living/M) - update_mob() - return ..() + if(istype(used_item, /obj/item/janicart_key)) + to_chat(user, SPAN_NOTICE("Hold \the [used_item] in one of your hands while you drive this [callme].")) + return TRUE + if(istype(used_item, /obj/item/bag/trash)) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, SPAN_NOTICE("You hook \the [used_item] onto the [callme].")) + mybag = used_item + return TRUE -/obj/structure/bed/chair/janicart/unbuckle_mob() - var/mob/living/M = ..() - if(M) - M.pixel_x = 0 - M.pixel_y = 0 - return M - - -/obj/structure/bed/chair/janicart/set_dir() - ..() - if(buckled_mob) - if(buckled_mob.loc != loc) - buckled_mob.buckled = null //Temporary, so Move() succeeds. - buckled_mob.buckled = src //Restoring - - update_mob() + . = ..() +/obj/structure/janicart/attack_hand(mob/user) + if(!mybag || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + user.put_in_hands(mybag) + mybag = null + return TRUE -/obj/structure/bed/chair/janicart/proc/update_mob() - if(buckled_mob) - buckled_mob.set_dir(dir) - switch(dir) - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 7 - if(WEST) - buckled_mob.pixel_x = 13 - buckled_mob.pixel_y = 7 - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -13 - buckled_mob.pixel_y = 7 +/obj/structure/janicart/handle_buckled_relaymove(var/datum/movement_handler/mh, var/mob/mob, var/direction, var/mover) + if(isspaceturf(loc)) + return + . = MOVEMENT_HANDLED + DoMove(mob.AdjustMovementDirection(direction, mover), mob) +/obj/structure/janicart/relaymove(mob/user, direction) + if(user.incapacitated(INCAPACITATION_DISRUPTED)) + unbuckle_mob() + user.glide_size = glide_size + step(src, direction) + set_dir(direction) -/obj/structure/bed/chair/janicart/bullet_act(var/obj/item/projectile/Proj) +/obj/structure/janicart/bullet_act(var/obj/item/projectile/Proj) if(buckled_mob) if(prob(85)) return buckled_mob.bullet_act(Proj) - visible_message("[Proj] ricochets off the [callme]!") - + visible_message(SPAN_WARNING("\The [Proj] ricochets off the [callme]!")) -/obj/item/key +/obj/item/janicart_key name = "key" desc = "A keyring with a small steel key, and a pink fob reading \"Pussy Wagon\"." icon = 'icons/obj/vehicles.dmi' icon_state = "keys" w_class = ITEM_SIZE_TINY + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE) diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index a1851a1d9c9b..0dd3a86c453d 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -3,29 +3,38 @@ desc = "A lightweight support lattice." icon = 'icons/obj/structures/smoothlattice.dmi' icon_state = "lattice0" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE w_class = ITEM_SIZE_NORMAL layer = LATTICE_LAYER color = COLOR_STEEL material = /decl/material/solid/metal/steel - obj_flags = OBJ_FLAG_NOFALL + obj_flags = OBJ_FLAG_NOFALL | OBJ_FLAG_MOVES_UNSUPPORTED material_alteration = MAT_FLAG_ALTERATION_ALL -/obj/structure/lattice/Initialize() +/obj/structure/lattice/Initialize(mapload) . = ..() if(. != INITIALIZE_HINT_QDEL) DELETE_IF_DUPLICATE_OF(/obj/structure/lattice) if(!istype(material)) return INITIALIZE_HINT_QDEL - if(!istype(src.loc, /turf/space) && !istype(src.loc, /turf/simulated/open)) + var/turf/T = loc + if(!istype(T) || !T.is_open()) return INITIALIZE_HINT_QDEL - . = INITIALIZE_HINT_LATELOAD + if(mapload) + return INITIALIZE_HINT_LATELOAD /obj/structure/lattice/LateInitialize() . = ..() update_neighbors() +/obj/structure/lattice/shuttle_rotate(angle) // DO NOT CHANGE DIR. + queue_icon_update() + update_neighbors() // in case we have lattices outside the shuttle area that want to connect + +/obj/structure/lattice/can_climb_from_below(var/mob/climber) + return TRUE + /obj/structure/lattice/update_material_desc() if(material) desc = "A lightweight support [material.solid_name] lattice." @@ -41,7 +50,7 @@ AM.fall(old_loc) /obj/structure/lattice/proc/update_neighbors(var/location = loc) - for (var/dir in GLOB.cardinal) + for (var/dir in global.cardinal) var/obj/structure/lattice/L = locate(/obj/structure/lattice, get_step(location, dir)) if(L) L.update_icon() @@ -53,52 +62,54 @@ /obj/structure/lattice/proc/deconstruct(var/mob/user) to_chat(user, SPAN_NOTICE("Slicing lattice joints...")) - new /obj/item/stack/material/rods(loc, 1, material.type) - qdel(src) + physically_destroyed() -/obj/structure/lattice/attackby(obj/item/C, mob/user) - - if (istype(C, /obj/item/stack/tile/floor)) +/obj/structure/lattice/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/stack/tile)) var/turf/T = get_turf(src) - T.attackby(C, user) //BubbleWrap - hand this off to the underlying turf instead - return - if(isWelder(C)) - var/obj/item/weldingtool/WT = C - if(WT.remove_fuel(0, user)) + T.attackby(used_item, user) //BubbleWrap - hand this off to the underlying turf instead + return TRUE + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0, user)) deconstruct(user) - return - if(istype(C, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = C + return TRUE + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item if(!cutter.slice(user)) - return + return TRUE deconstruct(user) - return - if (istype(C, /obj/item/stack/material/rods)) + return TRUE + if (istype(used_item, /obj/item/stack/material/rods)) var/ladder = (locate(/obj/structure/ladder) in loc) if(ladder) to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) return TRUE - var/obj/item/stack/material/rods/R = C - if(locate(/obj/structure/catwalk) in get_turf(src)) - to_chat(user, SPAN_WARNING("There is already a catwalk here.")) - return - else if(R.use(2)) + var/obj/item/stack/material/rods/rods = used_item + var/turf/my_turf = get_turf(src) + if(my_turf?.get_supporting_platform()) + to_chat(user, SPAN_WARNING("There is already a platform here.")) + return TRUE + else if(rods.use(2)) playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - new /obj/structure/catwalk(src.loc, R.material.type) - return + new /obj/structure/catwalk(my_turf, rods.material.type) + return TRUE else to_chat(user, SPAN_WARNING("You require at least two rods to complete the catwalk.")) + return TRUE + return ..() /obj/structure/lattice/on_update_icon() ..() var/dir_sum = 0 - for (var/direction in GLOB.cardinal) + for (var/direction in global.cardinal) var/turf/T = get_step(src, direction) if(locate(/obj/structure/lattice, T) || locate(/obj/structure/catwalk, T)) dir_sum += direction else - if(!(istype(get_step(src, direction), /turf/space)) && !(istype(get_step(src, direction), /turf/simulated/open))) + var/turf/O = get_step(src, direction) + if(!istype(O) || !O.is_open()) dir_sum += direction icon_state = "lattice[dir_sum]" \ No newline at end of file diff --git a/code/game/objects/structures/memorial.dm b/code/game/objects/structures/memorial.dm new file mode 100644 index 000000000000..38b509028309 --- /dev/null +++ b/code/game/objects/structures/memorial.dm @@ -0,0 +1,28 @@ +/obj/structure/memorial + name = "memorial" + desc = "A large stone slab, engraved with the names of people who have given their lives for the cause. Not a list you'd want to make. Add the dog tags of the fallen to the monument to memorialize them." + icon = 'icons/obj/structures/memorial.dmi' + icon_state = "memorial" + pixel_x = -16 + pixel_y = -16 + density = TRUE + anchored = TRUE + material = /decl/material/solid/stone/marble + material_alteration = MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_NAME + + var/list/fallen = list() + +/obj/structure/memorial/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/clothing/dog_tags)) + var/obj/item/clothing/dog_tags/dogtags = used_item + to_chat(user, "You add \the [dogtags.owner_name]'s [dogtags.name] to \the [src].") + fallen += "[dogtags.owner_rank] [dogtags.owner_name] | [dogtags.owner_branch]" + qdel(dogtags) + return TRUE + return ..() + +/obj/structure/memorial/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if (distance <= 2 && fallen.len) + . += "The fallen:" + . += fallen diff --git a/code/game/objects/structures/mineral_bath.dm b/code/game/objects/structures/mineral_bath.dm index 78a4afc23610..1ff9947a566c 100644 --- a/code/game/objects/structures/mineral_bath.dm +++ b/code/game/objects/structures/mineral_bath.dm @@ -1,33 +1,33 @@ -/obj/structure/adherent_bath +/obj/structure/mineral_bath name = "mineral bath" desc = "A deep, narrow basin filled with a swirling, semi-opaque liquid." - icon = 'icons/obj/machines/adherent.dmi' + icon = 'icons/obj/structures/mineral_bath.dmi' icon_state = "bath" anchored = TRUE density = TRUE opacity = FALSE var/mob/living/occupant -/obj/structure/adherent_bath/Destroy() +/obj/structure/mineral_bath/Destroy() eject_occupant() . = ..() -/obj/structure/adherent_bath/return_air() +/obj/structure/mineral_bath/return_air() var/datum/gas_mixture/venus = new(CELL_VOLUME, SYNTH_HEAT_LEVEL_1 - 10) - venus.adjust_multi(/decl/material/gas/chlorine, MOLES_N2STANDARD, /decl/material/gas/hydrogen, MOLES_O2STANDARD) + + venus.adjust_gas(/decl/material/gas/chlorine, MOLES_N2STANDARD, FALSE) + venus.adjust_gas(/decl/material/gas/hydrogen, MOLES_O2STANDARD, TRUE) return venus -/obj/structure/adherent_bath/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing, /obj/item/grab)) - var/obj/item/grab/G = thing - if(enter_bath(G.affecting)) - qdel(G) - return - . = ..() +/obj/structure/mineral_bath/grab_attack(obj/item/grab/grab, mob/user) + if(enter_bath(grab.affecting)) + qdel(grab) + return TRUE + return ..() -/obj/structure/adherent_bath/proc/enter_bath(var/mob/living/patient, var/mob/user) +/obj/structure/mineral_bath/proc/enter_bath(var/mob/living/patient, var/mob/user) - if(!istype(patient)) + if(!istype(patient) || patient.anchored) return FALSE var/self_drop = (user == patient) @@ -36,13 +36,13 @@ return FALSE if(occupant) - to_chat(user, "\The [src] is occupied.") + to_chat(user, SPAN_WARNING("\The [src] is occupied.")) return FALSE if(self_drop) - user.visible_message("\The [user] begins climbing into \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] begins climbing into \the [src].")) else - user.visible_message("\The [user] begins pushing \the [patient] into \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] begins pushing \the [patient] into \the [src].")) if(!do_after(user, 3 SECONDS, src)) return FALSE @@ -51,13 +51,13 @@ return FALSE if(occupant) - to_chat(user, "\The [src] is occupied.") + to_chat(user, SPAN_WARNING("\The [src] is occupied.")) return FALSE if(self_drop) - user.visible_message("\The [user] climbs into \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] climbs into \the [src].")) else - user.visible_message("\The [user] pushes \the [patient] into \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] pushes \the [patient] into \the [src].")) playsound(loc, 'sound/effects/slosh.ogg', 50, 1) patient.forceMove(src) @@ -65,10 +65,13 @@ START_PROCESSING(SSobj, src) return TRUE -/obj/structure/adherent_bath/attack_hand(var/mob/user) +/obj/structure/mineral_bath/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() eject_occupant() + return TRUE -/obj/structure/adherent_bath/proc/eject_occupant() +/obj/structure/mineral_bath/proc/eject_occupant() if(occupant) occupant.dropInto(loc) playsound(loc, 'sound/effects/slosh.ogg', 50, 1) @@ -76,18 +79,21 @@ if(occupant.client) occupant.client.eye = occupant.client.mob occupant.client.perspective = MOB_PERSPECTIVE - occupant.regenerate_icons() + occupant.update_icon() occupant = null STOP_PROCESSING(SSobj, src) -/obj/structure/adherent_bath/MouseDrop_T(var/atom/movable/O, var/mob/user) - enter_bath(O, user) +/obj/structure/mineral_bath/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && ismob(dropping)) + enter_bath(dropping, user) + return TRUE -/obj/structure/adherent_bath/relaymove(var/mob/user) +/obj/structure/mineral_bath/relaymove(var/mob/user) if(user == occupant) eject_occupant() -/obj/structure/adherent_bath/Process() +/obj/structure/mineral_bath/Process() if(!occupant) STOP_PROCESSING(SSobj, src) @@ -98,54 +104,53 @@ STOP_PROCESSING(SSobj, src) return - if(ishuman(occupant)) - - var/mob/living/carbon/human/H = occupant - var/repaired_organ - - // Replace limbs for crystalline species. - if(H.species.is_crystalline && prob(10)) - for(var/limb_type in H.species.has_limbs) - var/obj/item/organ/external/E = H.organs_by_name[limb_type] - if(E && !E.is_usable() && !(E.limb_flags & ORGAN_FLAG_HEALS_OVERKILL)) - E.removed() - qdel(E) - E = null - if(!E) - var/list/organ_data = H.species.has_limbs[limb_type] - var/limb_path = organ_data["path"] - var/obj/item/organ/O = new limb_path(H) - organ_data["descriptor"] = O.name - H.species.post_organ_rejuvenate(O, H) - to_chat(occupant, "You feel your [O.name] reform in the crystal bath.") - H.update_body() - repaired_organ = TRUE - break + var/repaired_organ + + // Replace limbs for crystalline species. + if(occupant.has_body_flag(BODY_FLAG_CRYSTAL_REFORM) && prob(10)) + var/decl/bodytype/root_bodytype = occupant.get_bodytype() + for(var/limb_type in root_bodytype.has_limbs) + var/obj/item/organ/external/limb = GET_EXTERNAL_ORGAN(occupant, limb_type) + if(limb && !limb.is_usable() && !(limb.limb_flags & ORGAN_FLAG_HEALS_OVERKILL)) + occupant.remove_organ(limb) + qdel(limb) + limb = null + if(!limb) + var/list/organ_data = root_bodytype.has_limbs[limb_type] + var/limb_path = organ_data["path"] + limb = new limb_path(occupant) + occupant.add_organ(limb, GET_EXTERNAL_ORGAN(occupant, limb.parent_organ), FALSE, FALSE) + to_chat(occupant, SPAN_NOTICE("You feel your [limb.name] reform in the crystal bath.")) + repaired_organ = TRUE + break // Repair crystalline internal organs. if(prob(10)) - for(var/thing in H.internal_organs) - var/obj/item/organ/internal/I = thing - if(BP_IS_CRYSTAL(I) && I.damage) - I.heal_damage(rand(3,5)) + for(var/obj/item/organ/internal/organ in occupant.get_internal_organs()) + if(BP_IS_CRYSTAL(organ) && organ.get_organ_damage()) + organ.heal_damage(rand(3,5)) if(prob(25)) - to_chat(H, "The mineral-rich bath mends your [I.name].") + to_chat(occupant, SPAN_NOTICE("The mineral-rich bath mends your [organ.name].")) // Repair robotic external organs. if(!repaired_organ && prob(25)) - for(var/thing in H.organs) - var/obj/item/organ/external/E = thing - if(BP_IS_PROSTHETIC(E)) - for(var/obj/implanted_object in E.implants) - if(!istype(implanted_object,/obj/item/implant) && !istype(implanted_object,/obj/item/organ/internal/augment) && prob(25)) // We don't want to remove REAL implants. Just shrapnel etc. - E.implants -= implanted_object - to_chat(H, "The mineral-rich bath dissolves the [implanted_object.name].") + for(var/obj/item/organ/external/limb in occupant.get_external_organs()) + if(BP_IS_PROSTHETIC(limb)) + for(var/obj/implanted_object in limb.implants) + if(!should_dissolve_implant(implanted_object)) // We don't want to remove REAL implants. Just shrapnel etc. + LAZYREMOVE(limb.implants, implanted_object) + to_chat(occupant, SPAN_NOTICE("The mineral-rich bath dissolves the [implanted_object.name].")) qdel(implanted_object) - if(E.brute_dam || E.burn_dam) - E.heal_damage(rand(3,5), rand(3,5), robo_repair = 1) + if(limb.brute_dam || limb.burn_dam) + limb.heal_damage(rand(3,5), rand(3,5), robo_repair = 1) if(prob(25)) - to_chat(H, "The mineral-rich bath mends your [E.name].") - if(!BP_IS_CRYSTAL(E) && !BP_IS_BRITTLE(E)) - E.status |= ORGAN_BRITTLE - to_chat(H, "It feels a bit brittle, though...") - break \ No newline at end of file + to_chat(occupant, SPAN_NOTICE("The mineral-rich bath mends your [limb.name].")) + if(!BP_IS_CRYSTAL(limb) && !BP_IS_BRITTLE(limb)) + limb.status |= ORGAN_BRITTLE + to_chat(occupant, SPAN_WARNING("It feels a bit brittle, though...")) + break + +/obj/structure/mineral_bath/proc/should_dissolve_implant(obj/implanted_object) + if(istype(implanted_object, /obj/item/implant)) + return FALSE + return prob(25) diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm index 593527acb7e5..8e37b95f89f6 100644 --- a/code/game/objects/structures/mop_bucket.dm +++ b/code/game/objects/structures/mop_bucket.dm @@ -3,26 +3,25 @@ desc = "Fill it with water, but don't forget a mop!" icon = 'icons/obj/janitor.dmi' icon_state = "mopbucket" - density = 1 + density = TRUE w_class = ITEM_SIZE_NORMAL atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_OPEN_CONTAINER - var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite + chem_volume = 180 - -/obj/structure/mopbucket/Initialize() - . = ..() - create_reagents(180) - -/obj/structure/mopbucket/examine(mob/user, distance) +/obj/structure/mopbucket/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "[src] \icon[src] contains [reagents.total_volume] unit\s of water!") + . += "\The [src] [html_icon(src)] contains [REAGENT_TOTAL_VOLUME(reagents)] unit\s of water!" -/obj/structure/mopbucket/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/mop)) - if(reagents.total_volume < 1) - to_chat(user, "\The [src] is out of water!") - else - reagents.trans_to_obj(I, 5) - to_chat(user, "You wet \the [I] in \the [src].") +/obj/structure/mopbucket/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/mop)) + if(REAGENT_TOTAL_VOLUME(reagents) < 1) + to_chat(user, SPAN_WARNING("\The [src] is out of water!")) + else if(REAGENTS_FREE_SPACE(used_item.reagents) >= 5) + reagents.trans_to_obj(used_item, 5) + to_chat(user, SPAN_NOTICE("You wet \the [used_item] in \the [src].")) playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + else + to_chat(user, SPAN_WARNING("\The [used_item] is saturated.")) + return TRUE + return ..() diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 07b398edc959..39d74c931f5d 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -1,398 +1,125 @@ -/* Morgue stuff - * Contains: - * Morgue - * Morgue trays - * Creamatorium - * Creamatorium trays - */ - -/* - * Morgue - */ - /obj/structure/morgue name = "morgue" desc = "Used to keep bodies in until someone fetches them." icon = 'icons/obj/structures/morgue.dmi' - icon_state = "morgue1" - dir = EAST - density = 1 - var/obj/structure/m_tray/connected = null - anchored = 1.0 + icon_state = "morgue_closed" + density = TRUE + anchored = TRUE + + var/open = FALSE + + var/obj/structure/morgue_tray/connected_tray + +/obj/structure/morgue/get_mechanics_info() + return "[..()]
              Can be labeled once with a hand labeler." + +/obj/structure/morgue/Initialize(ml, _mat, _reinf_mat) + . = ..() + connected_tray = new /obj/structure/morgue_tray(src) + connected_tray.connected_morgue = src + get_or_create_extension(src, /datum/extension/labels/single) /obj/structure/morgue/Destroy() - if(connected) - qdel(connected) - connected = null + if(!QDELETED(connected_tray)) + QDEL_NULL(connected_tray) return ..() -/obj/structure/morgue/proc/update() - if (src.connected) - src.icon_state = "morgue0" +/obj/structure/morgue/on_update_icon() + ..() + if(open) + icon_state = "morgue_open" + else if(contents.len > 1) + icon_state = "morgue_filled" else - if (src.contents.len) - src.icon_state = "morgue2" - else - src.icon_state = "morgue1" - return + icon_state = "morgue_closed" /obj/structure/morgue/explosion_act(severity) ..() if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) - -/obj/structure/morgue/attack_hand(mob/user) - if (src.connected) - for(var/atom/movable/A as mob|obj in src.connected.loc) - if (!( A.anchored )) - A.forceMove(src) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - qdel(src.connected) - src.connected = null - else - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - src.connected = new /obj/structure/m_tray( src.loc ) - step(src.connected, src.dir) - var/turf/T = get_step(src, src.dir) - if (T.contents.Find(src.connected)) - src.connected.connected = src - src.icon_state = "morgue0" - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.connected.loc) - src.connected.icon_state = "morguet" - src.connected.set_dir(src.dir) - else - qdel(src.connected) - src.connected = null - src.add_fingerprint(user) - update() - return + physically_destroyed() -/obj/structure/morgue/attack_robot(var/mob/user) - if(Adjacent(user)) - return attack_hand(user) - else return ..() - -/obj/structure/morgue/attackby(P, mob/user) - if (istype(P, /obj/item/pen)) - var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text - if (user.get_active_hand() != P) - return - if ((!in_range(src, usr) && src.loc != user)) - return - t = sanitizeSafe(t, MAX_NAME_LEN) - if (t) - src.SetName(text("Morgue- '[]'", t)) - else - src.SetName("Morgue") - src.add_fingerprint(user) - return - -/obj/structure/morgue/relaymove(mob/user) - if (user.stat) +/obj/structure/morgue/proc/open() + if(open) return - src.connected = new /obj/structure/m_tray( src.loc ) - step(src.connected, EAST) - var/turf/T = get_step(src, EAST) - if (T.contents.Find(src.connected)) - src.connected.connected = src - src.icon_state = "morgue0" - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.connected.loc) - src.connected.icon_state = "morguet" - else - qdel(src.connected) - src.connected = null - return + if(!connected_tray) + return -/* - * Morgue tray - */ -/obj/structure/m_tray - name = "morgue tray" - desc = "Apply corpse before closing." - icon = 'icons/obj/structures/morgue.dmi' - icon_state = "morguet" - density = 1 - layer = BELOW_OBJ_LAYER - var/obj/structure/morgue/connected = null - anchored = 1 - throwpass = 1 + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + var/turf/T = get_step(src, dir) + connected_tray.forceMove(T) + connected_tray.set_dir(dir) + for(var/atom/movable/A in src) + A.forceMove(get_turf(connected_tray)) -/obj/structure/m_tray/Destroy() - if(connected && connected.connected == src) - connected.connected = null - connected = null - return ..() + open = TRUE + update_icon() -/obj/structure/m_tray/attack_hand(mob/user) - if (src.connected) - for(var/atom/movable/A as mob|obj in src.loc) - if (!( A.anchored )) - A.forceMove(src.connected) - src.connected.connected = null - src.connected.update() - add_fingerprint(user) - //SN src = null - qdel(src) +/obj/structure/morgue/proc/close() + if(!open) return - return -/obj/structure/m_tray/MouseDrop_T(atom/movable/O, mob/user) - if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src) || user.contents.Find(O))) - return - if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) - return - if (!ismob(user) || user.stat || user.lying || user.stunned) + if(!connected_tray) return - O.forceMove(src.loc) - if (user != O) - for(var/mob/B in viewers(user, 3)) - if ((B.client && !( B.blinded ))) - to_chat(B, "\The [user] stuffs [O] into [src]!") - return - - -/* - * Crematorium - */ - -/obj/structure/crematorium - name = "crematorium" - desc = "A human incinerator. Works well on barbeque nights." - icon = 'icons/obj/structures/crematorium.dmi' - icon_state = "crema1" - density = TRUE - var/obj/structure/c_tray/connected = null - anchored = TRUE - var/cremating = FALSE - var/id = 1 - var/locked = FALSE - -/obj/structure/crematorium/Destroy() - if(connected) - qdel(connected) - connected = null - return ..() - -/obj/structure/crematorium/proc/update() - if(cremating) - icon_state = "crema_active" - else if (src.connected) - src.icon_state = "crema0" - else if (src.contents.len) - src.icon_state = "crema2" - else - src.icon_state = "crema1" - -/obj/structure/crematorium/explosion_act(severity) - ..() - if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) + for(var/atom/movable/A in get_turf(connected_tray)) + if(!A.anchored && A.simulated && !(A == connected_tray)) + A.forceMove(src) -/obj/structure/crematorium/attack_hand(mob/user) - if(cremating) - to_chat(usr, "It's locked.") - return - if(src.connected && (src.locked == FALSE)) - for(var/atom/movable/A as mob|obj in src.connected.loc) - if (!( A.anchored )) - A.forceMove(src) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - qdel(src.connected) - else if(src.locked == 0) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - src.connected = new /obj/structure/c_tray(src.loc) - step(src.connected, dir) - var/turf/T = get_step(src, dir) - if (T.contents.Find(src.connected)) - src.connected.connected = src - src.icon_state = "crema0" - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.connected.loc) - src.connected.icon_state = "cremat" - else - qdel(src.connected) - src.add_fingerprint(user) - update() + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + connected_tray.forceMove(src) -/obj/structure/crematorium/attackby(P, mob/user) - if(istype(P, /obj/item/pen)) - var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text - if(user.get_active_hand() != P) - return - if((!in_range(src, usr) > 1 && src.loc != user)) - return - t = sanitizeSafe(t, MAX_NAME_LEN) - if(t) - src.SetName(text("Crematorium- '[]'", t)) - else - src.SetName("Crematorium") - src.add_fingerprint(user) - return + open = FALSE + update_icon() -/obj/structure/crematorium/relaymove(mob/user) - if (user.stat || locked) - return - src.connected = new /obj/structure/c_tray( src.loc ) - step(src.connected, SOUTH) - var/turf/T = get_step(src, SOUTH) - if (T.contents.Find(src.connected)) - src.connected.connected = src - src.icon_state = "crema0" - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.connected.loc) +/obj/structure/morgue/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + if(open) + close() else - qdel(src.connected) - src.connected = null - return + open() + return TRUE -/obj/structure/crematorium/proc/cremate(atom/A, mob/user) - if(cremating) - return //don't let you cremate something twice or w/e +/obj/structure/morgue/attack_robot(mob/user) + return attack_hand_with_interaction_checks(user) - if(contents.len <= 0) - src.audible_message("You hear a hollow crackle.", 1) +/obj/structure/morgue/relaymove(mob/user) + if(user.incapacitated()) return - else - if(!isemptylist(src.search_contents_for(/obj/item/disk/nuclear))) - to_chat(loc, "The button's status indicator flashes yellow, indicating that something important is inside the crematorium, and must be removed.") - return - src.audible_message("You hear a roar as the [src] activates.", 1) - - cremating = 1 - locked = 1 - update() - - for(var/mob/living/M in contents) - admin_attack_log(M, A, "Began cremating their victim.", "Has begun being cremated.", "began cremating") - if(iscarbon(M)) - var/mob/living/carbon/C = M - for(var/I, I < 60, I++) - - if(C.stat >= UNCONSCIOUS || !(C in contents)) //In case we die or are removed at any point. - cremating = 0 - update() - break - - sleep(0.5 SECONDS) - if(prob(40)) - var/desperation = rand(1,5) - switch(desperation) //This is messy. A better solution would probably be to make more sounds, but... - if(1) - playsound(src.loc, 'sound/weapons/genhit.ogg', 45, 1) - shake_animation(2) - playsound(src.loc, 'sound/weapons/genhit.ogg', 45, 1) - if(2) - playsound(src.loc, 'sound/effects/grillehit.ogg', 45, 1) - shake_animation(3) - playsound(src.loc, 'sound/effects/grillehit.ogg', 45, 1) - if(3) - playsound(src, 'sound/effects/bang.ogg', 45, 1) - if(prob(50)) - playsound(src, 'sound/effects/bang.ogg', 45, 1) - shake_animation() - else - shake_animation(5) - if(4) - playsound(src, 'sound/effects/clang.ogg', 45, 1) - shake_animation(5) - if(5) - playsound(src, 'sound/weapons/smash.ogg', 50, 1) - if(prob(50)) - playsound(src, 'sound/weapons/smash.ogg', 50, 1) - shake_animation(9) - else - shake_animation() - - if(round_is_spooky()) - if(prob(50)) - playsound(src, 'sound/effects/ghost.ogg', 10, 5) - else - playsound(src, 'sound/effects/ghost2.ogg', 10, 5) - - if (!M.stat) - M.audible_message("[M]'s screams cease, as does any movement within the [src]. All that remains is a dull, empty silence.") - - admin_attack_log(M, A, "Cremated their victim.", "Was cremated.", "cremated") - M.dust() + open() - for(var/obj/O in contents) //obj instead of obj/item so that bodybags and ashes get destroyed. We dont want tons and tons of ash piling up - qdel(O) - - new /obj/effect/decal/cleanable/ash(src) - sleep(30) - cremating = initial(cremating) - locked = initial(locked) - update() - playsound(src.loc, 'sound/effects/spray.ogg', 50, 1) - return - -/* - * Crematorium tray - */ -/obj/structure/c_tray - name = "crematorium tray" - desc = "Apply body before burning." +/obj/structure/morgue_tray + name = "morgue tray" + desc = "Apply corpse before closing." icon = 'icons/obj/structures/morgue.dmi' - icon_state = "cremat" - density = 1 + icon_state = "morgue_tray" + density = TRUE + anchored = TRUE + throwpass = TRUE layer = BELOW_OBJ_LAYER - var/obj/structure/crematorium/connected = null - anchored = 1 - throwpass = 1 - -/obj/structure/c_tray/Destroy() - if(connected && connected.connected == src) - connected.connected = null - connected = null - return ..() + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED | OBJ_FLAG_NOFALL -/obj/structure/c_tray/attack_hand(mob/user) - if (src.connected) - for(var/atom/movable/A as mob|obj in src.loc) - if (!( A.anchored )) - A.forceMove(src.connected) - src.connected.connected = null - src.connected.update() - add_fingerprint(user) - //SN src = null - qdel(src) - return - return - -/obj/structure/c_tray/MouseDrop_T(atom/movable/O, mob/user) - if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src) || user.contents.Find(O))) - return - if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) - return - if (!ismob(user) || user.stat || user.lying || user.stunned) - return - O.forceMove(src.loc) - if (user != O) - for(var/mob/B in viewers(user, 3)) - if ((B.client && !( B.blinded ))) - to_chat(B, text("[] stuffs [] into []!", user, O, src)) - -/obj/machinery/button/crematorium - name = "crematorium igniter" - desc = "Burn baby burn!" - icon = 'icons/obj/power.dmi' - icon_state = "crema_switch" - initial_access = list(access_crematorium) - id_tag = 1 + var/obj/structure/morgue/connected_morgue -/obj/machinery/button/crematorium/on_update_icon() - return +/obj/structure/morgue_tray/Destroy() + if(!QDELETED(connected_morgue)) + QDEL_NULL(connected_morgue) + return ..() -/obj/machinery/button/crematorium/activate(mob/user) - if(operating) - return - for(var/obj/structure/crematorium/C in range()) - if (C.id == id_tag) - if (!C.cremating) - C.cremate(user) - ..() // sets operating for click cooldown. \ No newline at end of file +/obj/structure/morgue_tray/attack_hand(mob/user) + return connected_morgue.attack_hand_with_interaction_checks(user) || ..() + +/obj/structure/morgue_tray/attack_robot(mob/user) + return attack_hand_with_interaction_checks(user) + +/obj/structure/morgue_tray/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && (ismob(dropping) || istype(dropping, /obj/structure/closet/body_bag))) + var/atom/movable/AM = dropping + if(!AM.anchored) + AM.forceMove(loc) + if(user != dropping) + user.visible_message(SPAN_NOTICE("\The [user] stuffs \the [dropping] onto \the [src]!")) + return TRUE diff --git a/code/game/objects/structures/pedestal.dm b/code/game/objects/structures/pedestal.dm new file mode 100644 index 000000000000..48ab35087c08 --- /dev/null +++ b/code/game/objects/structures/pedestal.dm @@ -0,0 +1,27 @@ +/obj/structure/pedestal + name = "pedestal" + desc = "A flat-topped structure for decoration or presentation of items." + icon = 'icons/obj/structures/pedestals/pedestal_square.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + opacity = FALSE + density = TRUE + material = /decl/material/solid/stone/marble + material_alteration = MAT_FLAG_ALTERATION_ALL + var/place_item_y = -5 + +/obj/structure/pedestal/attackby(obj/item/used_item, mob/user) + if(!user.check_intent(I_FLAG_HARM) && user.try_unequip(used_item, get_turf(src))) + used_item.reset_offsets(anim_time = 0) + used_item.pixel_y = used_item.default_pixel_y + place_item_y + return TRUE + return ..() + +/obj/structure/pedestal/narrow + icon = 'icons/obj/structures/pedestals/pedestal_narrow.dmi' + +/obj/structure/pedestal/round + icon = 'icons/obj/structures/pedestals/pedestal_round.dmi' + +/obj/structure/pedestal/triad + icon = 'icons/obj/structures/pedestals/pedestal_triad.dmi' diff --git a/code/game/objects/structures/pillar.dm b/code/game/objects/structures/pillar.dm new file mode 100644 index 000000000000..6c77b5c53792 --- /dev/null +++ b/code/game/objects/structures/pillar.dm @@ -0,0 +1,30 @@ +/obj/structure/pillar + name = "pillar" + desc = "A tall, narrow structure, usually used to hold up the roof." + icon = 'icons/obj/structures/pillars/pillar_square.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + opacity = TRUE + density = TRUE + material = /decl/material/solid/stone/marble + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/structure/pillar/narrow + icon = 'icons/obj/structures/pillars/pillar_narrow.dmi' + +/obj/structure/pillar/round + icon = 'icons/obj/structures/pillars/pillar_round.dmi' + +/obj/structure/pillar/triad + icon = 'icons/obj/structures/pillars/pillar_triad.dmi' + +/obj/structure/pillar/wide + name = "wide pillar" + w_class = ITEM_SIZE_LARGE_STRUCTURE + icon = 'icons/obj/structures/pillars/pillar_wide_round.dmi' + +/obj/structure/pillar/wide/square + icon = 'icons/obj/structures/pillars/pillar_wide_square.dmi' + +/obj/structure/pillar/wide/inset + icon = 'icons/obj/structures/pillars/pillar_wide_inset.dmi' diff --git a/code/game/objects/structures/pit.dm b/code/game/objects/structures/pit.dm index e6965c6f471a..09c8ee2cca5d 100644 --- a/code/game/objects/structures/pit.dm +++ b/code/game/objects/structures/pit.dm @@ -1,69 +1,63 @@ /obj/structure/pit - name = "pit" - desc = "Watch your step, partner." - icon = 'icons/obj/structures/pit.dmi' + name = "pit" + desc = "Watch your step, partner." + icon = 'icons/obj/structures/pit.dmi' icon_state = "pit1" blend_mode = BLEND_MULTIPLY - density = 0 - anchored = 1 - var/open = 1 - -/obj/structure/pit/attackby(obj/item/W, mob/user) - if( istype(W,/obj/item/shovel) ) - visible_message("\The [user] starts [open ? "filling" : "digging open"] \the [src]") - if( do_after(user, 50) ) - visible_message("\The [user] [open ? "fills" : "digs open"] \the [src]!") + density = FALSE + anchored = TRUE + max_health = ITEM_HEALTH_NO_DAMAGE //You can't break a hole in the ground. + var/open = TRUE + +/obj/structure/pit/attackby(obj/item/used_item, mob/user) + if(IS_SHOVEL(used_item)) + var/dig_message = open ? "filling in" : "excavating" + if(used_item.do_tool_interaction(TOOL_SHOVEL, user, src, 5 SECONDS, dig_message, dig_message)) if(open) close(user) else - open() - else - to_chat(user, "You stop shoveling.") - return - if (!open && istype(W,/obj/item/stack/material/wood)) - if(locate(/obj/structure/gravemarker) in src.loc) - to_chat(user, "There's already a grave marker here.") + open(user) else - visible_message("\The [user] starts making a grave marker on top of \the [src]") - if( do_after(user, 50) ) - visible_message("\The [user] finishes the grave marker") - var/obj/item/stack/material/wood/plank = W - plank.use(1) - new/obj/structure/gravemarker(src.loc) - else - to_chat(user, "You stop making a grave marker.") - return - ..() + to_chat(user, SPAN_NOTICE("You stop digging.")) + return TRUE + + if (!open && istype(used_item, /obj/item/gravemarker)) + var/obj/item/gravemarker/gravemarker = used_item + gravemarker.try_bury(get_turf(src), user) + return TRUE + return ..() /obj/structure/pit/on_update_icon() + ..() icon_state = "pit[open]" - if(istype(loc,/turf/simulated/floor/exoplanet)) - var/turf/simulated/floor/exoplanet/E = loc - if(E.dirt_color) - color = E.dirt_color - -/obj/structure/pit/proc/open() - name = "pit" - desc = "Watch your step, partner." - open = 1 + +/obj/structure/pit/proc/open(mob/user) + name = initial(name) + desc = initial(desc) + open = TRUE for(var/atom/movable/A in src) - A.forceMove(src.loc) + A.dropInto(loc) update_icon() + for(var/obj/structure/gravemarker/marker in get_turf(src)) + marker.unbury(user, place_in_hands = FALSE) // a grave disturbed!! /obj/structure/pit/proc/close(var/user) name = "mound" desc = "Some things are better left buried." - open = 0 - for(var/atom/movable/A in src.loc) - if(!A.anchored && A != user) - A.forceMove(src) - update_icon() + open = FALSE -/obj/structure/pit/return_air() - if(open && loc) - return loc.return_air() + //If we close the pit without anything inside, just leave the soil undisturbed + if(isturf(loc)) + for(var/atom/movable/A in loc) + if(A != src && !A.anchored && A != user && A.simulated) + A.forceMove(src) + if(!length(contents)) + qdel(src) else - return null + update_icon() + +/obj/structure/pit/return_air() + return open && loc?.return_air() /obj/structure/pit/proc/digout(mob/escapee) var/breakout_time = 1 //2 minutes by default @@ -75,73 +69,129 @@ return escapee.setClickCooldown(100) - to_chat(escapee, "You start digging your way out of \the [src] (this will take about [breakout_time] minute\s)") - visible_message("Something is scratching its way out of \the [src]!") + to_chat(escapee, SPAN_WARNING("You start digging your way out of \the [src] (this will take about [breakout_time] minute\s)")) + visible_message(SPAN_DANGER("Something is scratching its way out of \the [src]!")) for(var/i in 1 to (6*breakout_time * 2)) //minutes * 6 * 5seconds * 2 - playsound(src.loc, 'sound/weapons/bite.ogg', 100, 1) + playsound(src.loc, 'sound/weapons/bite.ogg', 80, TRUE) - if(!do_after(escapee, 50)) - to_chat(escapee, "You have stopped digging.") + if(!do_after(escapee, 5 SECONDS)) + to_chat(escapee, SPAN_WARNING("You have stopped digging.")) return if(open) return if(i == 6*breakout_time) - to_chat(escapee, "Halfway there...") + to_chat(escapee, SPAN_WARNING("Halfway there...")) - to_chat(escapee, "You successfuly dig yourself out!") - visible_message("\the [escapee] emerges from \the [src]!") - playsound(src.loc, 'sound/effects/squelch1.ogg', 100, 1) - open() + to_chat(escapee, SPAN_NOTICE("You successfuly dig yourself out!")) + visible_message(SPAN_DANGER("\The [escapee] emerges from \the [src]!")) + playsound(src.loc, 'sound/effects/squelch1.ogg', 100, TRUE) + open(escapee) + +/obj/structure/pit/explosion_act(severity) + //Pop open and throw the stuff out + if(!open && severity > 2) + open() + . = ..() +///////////////////////////////////////////// +// Closed Pit +///////////////////////////////////////////// /obj/structure/pit/closed - name = "mound" - desc = "Some things are better left buried." - open = 0 + name = "mound" + desc = "Some things are better left buried." + current_health = ITEM_HEALTH_NO_DAMAGE //Can't break a hole in the ground... /obj/structure/pit/closed/Initialize() . = ..() close() +///////////////////////////////////////////// +// Hidden Closed Pit +///////////////////////////////////////////// //invisible until unearthed first /obj/structure/pit/closed/hidden invisibility = INVISIBILITY_OBSERVER -/obj/structure/pit/closed/hidden/open() +/obj/structure/pit/closed/hidden/open(mob/user) ..() set_invisibility(INVISIBILITY_LEVEL_ONE) -//spoooky +///////////////////////////////////////////// +// Closed Grave +///////////////////////////////////////////// /obj/structure/pit/closed/grave - name = "grave" + name = "grave" icon_state = "pit0" /obj/structure/pit/closed/grave/Initialize() + setup_contents() // must run before parent call or close() will delete us + . = ..() + +/obj/structure/pit/closed/grave/proc/setup_contents() var/obj/structure/closet/coffin/C = new(src.loc) var/obj/item/remains/human/bones = new(C) bones.layer = LYING_MOB_LAYER var/obj/structure/gravemarker/random/R = new(src.loc) R.generate() - . = ..() +///////////////////////////////////////////// +// Grave Markers +///////////////////////////////////////////// /obj/structure/gravemarker - name = "grave marker" - desc = "You're not the first." - icon = 'icons/obj/structures/gravestone.dmi' - icon_state = "wood" - pixel_x = 15 - pixel_y = 8 - anchored = 1 - var/message = "Unknown." + name = "grave marker" + desc = "You're not the first." + icon = 'icons/obj/structures/gravestone.dmi' + icon_state = "wood" + pixel_x = 15 + pixel_y = 8 + anchored = TRUE + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + w_class = ITEM_SIZE_NORMAL + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + var/message = "Unknown." + var/destruction_skill = SKILL_HAULING // just brute force + var/destruction_tool = TOOL_HATCHET + var/destruction_start_message = "hacking away at" + var/destruction_finish_message = "hacking at" + var/gravemarker_type = /obj/item/gravemarker -/obj/structure/gravemarker/cross - icon_state = "cross" +/obj/structure/gravemarker/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance < 2) + var/processed_message = user.handle_reading_literacy(user, message) + if(processed_message) + . += "It says: '[processed_message]'" + else if(message) + . += "You can't read the inscription from here." -/obj/structure/gravemarker/examine(mob/user) +/obj/structure/gravemarker/attackby(obj/item/used_item, mob/user) + // we can dig it up with a shovel if the destruction tool is not a shovel, or if we're not on harm intent + var/digging = IS_SHOVEL(used_item) && (destruction_tool != TOOL_SHOVEL || !user?.check_intent(I_FLAG_HARM)) + if(digging && used_item.do_tool_interaction(TOOL_SHOVEL, user, src, 2 SECONDS, "digging up", "digging up", check_skill = SKILL_HAULING)) + unbury(user, place_in_hands = TRUE) // deletes the grave marker and spawns an item in its place + return TRUE + if(IS_TOOL(used_item, destruction_tool)) + if(used_item.do_tool_interaction(destruction_tool, user, src, 3 SECONDS, destruction_start_message, destruction_finish_message, check_skill = destruction_skill)) + physically_destroyed(FALSE) + return TRUE + if(IS_PEN(used_item)) + var/msg = sanitize(input(user, "What should it say?", "Grave marker", html_decode(message)) as text|null) + if(!CanPhysicallyInteract(user)) + to_chat(user, SPAN_WARNING("You must stay close to \the [src]!")) + return TRUE + if(msg && used_item.do_tool_interaction(TOOL_PEN, user, src, 1 SECOND, fuel_expenditure = 1)) + message = msg + return TRUE . = ..() - to_chat(user, "It says: '[message]'") +// Cross Marker +/obj/structure/gravemarker/cross + icon_state = "cross" + +// Random Grave Marker /obj/structure/gravemarker/random/Initialize() generate() . = ..() @@ -149,22 +199,127 @@ /obj/structure/gravemarker/random/proc/generate() icon_state = pick("wood","cross") - var/decl/cultural_info/S = SSlore.get_culture(CULTURE_HUMAN) - var/nam = S.get_random_name(pick(MALE,FEMALE)) - var/cur_year = game_year + var/decl/background_detail/S = GET_DECL(/decl/background_detail/heritage/human) + var/nam = S.get_random_cultural_name(null, pick(MALE,FEMALE)) + var/cur_year = global.using_map.game_year var/born = cur_year - rand(5,150) var/died = max(cur_year - rand(0,70),born) message = "Here lies [nam], [born] - [died]." -/obj/structure/gravemarker/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/hatchet)) - visible_message("\The [user] starts hacking away at \the [src] with \the [W].") - if(!do_after(user, 30)) - visible_message("\The [user] hacks \the [src] apart.") - new /obj/item/stack/material/wood(src) - qdel(src) - if(istype(W,/obj/item/pen)) - var/msg = sanitize(input(user, "What should it say?", "Grave marker", message) as text|null) - if(msg) - message = msg \ No newline at end of file +// Gravestone +/obj/structure/gravemarker/gravestone + name = "gravestone" + icon_state = "stone" + destruction_tool = TOOL_HAMMER + destruction_start_message = "smashing" + destruction_finish_message = "smashing" + material = /decl/material/solid/stone/granite + color = /decl/material/solid/stone/granite::color + +// Gravemarker items. +// TODO: unify with signs somehow? some of this behaviour is similar... +/obj/item/gravemarker + name = "grave marker" + desc = "You're not the first." + icon = 'icons/obj/structures/gravestone.dmi' + icon_state = "wood" + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + w_class = ITEM_SIZE_NORMAL + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC | MAT_FLAG_ALTERATION_COLOR + var/gravemarker_type = /obj/structure/gravemarker + var/message = "Unknown." + +/obj/item/gravemarker/gravestone + name = "gravestone" + icon_state = "stone" + material = /decl/material/solid/stone/granite + color = /decl/material/solid/stone/granite::color + gravemarker_type = /obj/structure/gravemarker/gravestone + +/obj/item/gravemarker/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance < 2) + var/processed_message = user.handle_reading_literacy(user, message) + if(processed_message) + . += "It says: '[processed_message]'" + else if(message) + . += "You can't read the inscription from here." + +/obj/item/gravemarker/attack_self(mob/user) + if(!user.check_intent(I_FLAG_HARM)) + try_bury(get_turf(user), user) + return TRUE + return ..() + +/obj/item/gravemarker/afterattack(turf/target, mob/user, proximity) + if((. = ..()) || (user.check_intent(I_FLAG_HARM) && !(item_flags & ITEM_FLAG_NO_BLUDGEON)) || !proximity) + return + if(!istype(target)) + target = get_turf(target) + try_bury(target, user) + return TRUE + +/obj/item/gravemarker/proc/try_bury(turf/target_turf, mob/user) + if(!can_bury(target_turf, user)) + return FALSE + var/obj/structure/pit/grave = locate() in target_turf + var/where = grave ? "on \the [grave]" : "in \the [target_turf]" + user.visible_message(SPAN_NOTICE("\The [user] starts planting \a [src] [where]."), SPAN_NOTICE("You start planting \a [src] [where]."), SPAN_NOTICE("You hear soil shifting.")) + if(!do_after(user, 5 SECONDS, grave || target_turf)) + user.visible_message(SPAN_NOTICE("\The [user] stops planting \a [src] [where]."), SPAN_NOTICE("You stop planting \a [src] [where]."), SPAN_NOTICE("You hear the soil become still once more.")) + return TRUE + // check again after the delay, just in case + if(!can_bury(target_turf, user)) + return FALSE + if(bury(target_turf, user)) + grave = locate() in target_turf // could have been removed or created during the delay + where = grave ? "on \the [grave]" : "in \the [target_turf]" + user.visible_message(SPAN_NOTICE("\The [user] plants \a [src] [where]."), SPAN_NOTICE("You plant \a [src] [where]."), SPAN_NOTICE("You hear soil shifting.")) + +/obj/item/gravemarker/proc/can_bury(turf/target_turf, mob/user, silent = FALSE) + var/obj/structure/pit/grave = locate() in target_turf + if(target_turf.is_open() || grave?.open) + if(user && !silent) + to_chat(user, SPAN_WARNING("You can't plant \the [src] here, it's an open pit!")) + return FALSE + if(!grave && !target_turf.can_be_dug(MAT_VALUE_RIGID)) // a grave means it's able to be planted + if(user && !silent) + to_chat(user, SPAN_WARNING("The ground here is too hard to plant \the [src] in.")) + return FALSE + var/obj/structure/gravemarker/competitor = locate() in target_turf + if(competitor) + to_chat(user, SPAN_WARNING("There's already \a [competitor] here.")) + return FALSE + return TRUE + +// use in hand or on a pit to bury it in the ground +/obj/item/gravemarker/proc/bury(turf/target_turf) + var/obj/structure/gravemarker/gravemarker = new gravemarker_type(target_turf, material.type) + gravemarker.message = message + gravemarker.icon_state = icon_state + qdel(src) + return TRUE + +/obj/structure/gravemarker/proc/unbury(mob/user, place_in_hands = FALSE) + var/turf/target_turf = get_turf(src) + var/obj/item/gravemarker/gravemarker = new gravemarker_type(target_turf, material.type) + gravemarker.dropInto(target_turf) // start by dropping it into the turf as a fallback + if(place_in_hands) + user.put_in_hands(gravemarker) // then, if possible, put it in the user's hands instead + gravemarker.message = message + gravemarker.icon_state = icon_state + qdel(src) + return TRUE + +/obj/item/gravemarker/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) + var/msg = sanitize(input(user, "What should it say?", "Grave marker", html_decode(message)) as text|null) + if(!CanPhysicallyInteract(user)) + to_chat(user, SPAN_WARNING("You must stay close to \the [src]!")) + return TRUE + if(msg && used_item.do_tool_interaction(TOOL_PEN, user, src, 1 SECOND, fuel_expenditure = 1)) + message = msg + return TRUE + . = ..() \ No newline at end of file diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm deleted file mode 100644 index 5539485218ec..000000000000 --- a/code/game/objects/structures/plasticflaps.dm +++ /dev/null @@ -1,79 +0,0 @@ -/obj/structure/plasticflaps //HOW DO YOU CALL THOSE THINGS ANYWAY - name = "plastic flaps" - desc = "Completely impassable - or are they?" - icon = 'icons/obj/structures/plastic_flaps.dmi' - icon_state = "plasticflaps" - density = 0 - anchored = 1 - layer = ABOVE_HUMAN_LAYER - explosion_resistance = 5 - - obj_flags = OBJ_FLAG_ANCHORABLE - - var/list/mobs_can_pass = list( - /mob/living/bot, - /mob/living/carbon/slime, - /mob/living/simple_animal/mouse, - /mob/living/silicon/robot/drone - ) - var/airtight = FALSE - -/obj/structure/plasticflaps/CanPass(atom/A, turf/T) - if(istype(A) && A.checkpass(PASS_FLAG_GLASS)) - return prob(60) - - var/obj/structure/bed/B = A - if (istype(A, /obj/structure/bed) && B.buckled_mob)//if it's a bed/chair and someone is buckled, it will not pass - return 0 - - if(istype(A, /obj/vehicle)) //no vehicles - return 0 - - var/mob/living/M = A - if(istype(M)) - if(M.lying) - return ..() - for(var/mob_type in mobs_can_pass) - if(istype(A, mob_type)) - return ..() - return issmall(M) - - return ..() - -/obj/structure/plasticflaps/attackby(obj/item/W, mob/user) - if(isCrowbar(W) && !anchored) - user.visible_message("\The [user] begins deconstructing \the [src].", "You start deconstructing \the [src].") - if(user.do_skilled(3 SECONDS, SKILL_CONSTRUCTION, src)) - user.visible_message("\The [user] deconstructs \the [src].", "You deconstruct \the [src].") - qdel(src) - if(isScrewdriver(W) && anchored) - airtight = !airtight - airtight ? become_airtight() : clear_airtight() - user.visible_message("\The [user] adjusts \the [src], [airtight ? "preventing" : "allowing"] air flow.") - else ..() - -/obj/structure/plasticflaps/explosion_act(severity) - ..() - if(!QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) - -/obj/structure/plasticflaps/Initialize() - . = ..() - if(airtight) - become_airtight() - -/obj/structure/plasticflaps/Destroy() //lazy hack to set the turf to allow air to pass if it's a simulated floor - if(airtight) - clear_airtight() - . = ..() - -/obj/structure/plasticflaps/proc/become_airtight() - atmos_canpass = CANPASS_NEVER - update_nearby_tiles() - -/obj/structure/plasticflaps/proc/clear_airtight() - atmos_canpass = CANPASS_ALWAYS - update_nearby_tiles() - -/obj/structure/plasticflaps/airtight // airtight defaults to on - airtight = TRUE \ No newline at end of file diff --git a/code/game/objects/structures/produce_bin.dm b/code/game/objects/structures/produce_bin.dm new file mode 100644 index 000000000000..86ed462f5050 --- /dev/null +++ b/code/game/objects/structures/produce_bin.dm @@ -0,0 +1,65 @@ +/obj/structure/produce_bin + name = "produce bin" + desc = "A squat bin for storing produce." + icon = 'icons/obj/structures/produce_bin.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + color = /decl/material/solid/organic/wood/oak::color + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + storage = /datum/storage/produce_bin + +/obj/structure/produce_bin/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/structure/produce_bin/LateInitialize(mapload, ...) + ..() + if(mapload) + for(var/obj/item/food/grown/produce in loc) + if(!produce.simulated || produce.anchored) + continue + if(storage.can_be_inserted(produce, null)) + storage.handle_item_insertion(null, produce) + +/obj/structure/produce_bin/attackby(obj/item/used_item, mob/user) + + if(user.check_intent(I_FLAG_HARM)) + return ..() + + if(used_item.storage) + + var/emptied = FALSE + for(var/obj/item/food/grown/produce in used_item.get_stored_inventory()) + if(storage.can_be_inserted(produce)) + used_item.storage.remove_from_storage(null, produce, loc, skip_update = TRUE) + storage.handle_item_insertion(null, produce, skip_update = TRUE) + emptied = TRUE + + if(emptied) + used_item.storage.finish_bulk_removal() + storage.finish_bulk_insertion() + if(length(used_item.get_stored_inventory())) + to_chat(user, SPAN_NOTICE("You partially empty \the [used_item] into \the [src]'s hopper.")) + else + to_chat(user, SPAN_NOTICE("You empty \the [used_item] into \the [src]'s hopper.")) + return TRUE + + return ..() + +/obj/structure/produce_bin/on_update_icon() + . = ..() + var/storage_space_used = storage.storage_space_used() + if(storage_space_used <= 0) + return + var/capacity = clamp(round(storage.storage_space_used() / storage.max_storage_space * 100, 20), 20, 100) // increments of 20% + add_overlay(overlay_image(icon, "[icon_state]-fill-[capacity]", null, RESET_COLOR)) + +/obj/structure/produce_bin/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/produce_bin/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color \ No newline at end of file diff --git a/code/game/objects/structures/quicksand.dm b/code/game/objects/structures/quicksand.dm new file mode 100644 index 000000000000..b3e1cffa4809 --- /dev/null +++ b/code/game/objects/structures/quicksand.dm @@ -0,0 +1,98 @@ + +/obj/effect/quicksand + name = "quicksand" + desc = "There is no candy at the bottom." + icon = 'icons/obj/quicksand.dmi' + icon_state = "open" + density = FALSE + anchored = TRUE + can_buckle = TRUE + buckle_dir = SOUTH + var/exposed = 0 + var/busy + +/obj/effect/quicksand/Initialize() + . = ..() + var/turf/T = get_turf(src) + if(!T) + return INITIALIZE_HINT_QDEL + appearance = T.appearance + +/obj/effect/quicksand/user_unbuckle_mob(mob/user) + if(buckled_mob && !user.stat && !user.restrained()) + if(busy) + to_chat(user, SPAN_NOTICE("\The [buckled_mob] is already getting out, be patient.")) + return + var/delay = 60 + if(user == buckled_mob) + delay *=2 + user.visible_message( + SPAN_NOTICE("\The [user] tries to climb out of \the [src]."), + SPAN_NOTICE("You begin to pull yourself out of \the [src]."), + SPAN_NOTICE("You hear water sloshing.") + ) + else + user.visible_message( + SPAN_NOTICE("\The [user] begins pulling \the [buckled_mob] out of \the [src]."), + SPAN_NOTICE("You begin to pull \the [buckled_mob] out of \the [src]."), + SPAN_NOTICE("You hear water sloshing.") + ) + busy = 1 + if(do_after(user, delay, src)) + busy = 0 + if(user == buckled_mob) + if(prob(80)) + to_chat(user, SPAN_WARNING("You slip and fail to get out!")) + return + user.visible_message(SPAN_NOTICE("\The [buckled_mob] pulls himself out of \the [src].")) + else + user.visible_message(SPAN_NOTICE("\The [buckled_mob] has been freed from \the [src] by \the [user].")) + unbuckle_mob() + else + busy = 0 + to_chat(user, SPAN_WARNING("You slip and fail to get out!")) + return + +/obj/effect/quicksand/unbuckle_mob() + ..() + update_icon() + +/obj/effect/quicksand/buckle_mob(var/mob/L) + ..() + update_icon() + +/obj/effect/quicksand/on_update_icon() + if(!exposed) + return + icon_state = "open" + cut_overlays() + if(buckled_mob) + add_overlay(image(icon,icon_state="overlay",layer=ABOVE_HUMAN_LAYER)) + +/obj/effect/quicksand/proc/expose() + if(exposed) + return + visible_message(SPAN_WARNING("The upper crust breaks, exposing the treacherous quicksand underneath!")) + SetName(initial(name)) + desc = initial(desc) + icon = initial(icon) + exposed = 1 + update_icon() + +/obj/effect/quicksand/attackby(obj/item/used_item, mob/user) + if(!exposed && used_item.expend_attack_force(user)) + expose() + return TRUE + else + return ..() + +/obj/effect/quicksand/Crossed(atom/movable/AM) + if(!isliving(AM)) + return + var/mob/living/L = AM + if(L.throwing || L.can_overcome_gravity()) + return + buckle_mob(L) + if(!exposed) + expose() + to_chat(L, SPAN_DANGER("You fall into \the [src]!")) diff --git a/code/game/objects/structures/racks.dm b/code/game/objects/structures/racks.dm new file mode 100644 index 000000000000..4830025c3535 --- /dev/null +++ b/code/game/objects/structures/racks.dm @@ -0,0 +1,66 @@ +/obj/structure/rack + name = "rack" + desc = "Different from the Middle Ages version." + icon = 'icons/obj/structures/rack.dmi' + icon_state = "rack" + material = DEFAULT_FURNITURE_MATERIAL + handle_generic_blending = FALSE + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR + atom_flags = ATOM_FLAG_CLIMBABLE + throwpass = TRUE + parts_amount = 2 + parts_type = /obj/item/stack/material/rods + density = TRUE + anchored = TRUE + structure_flags = STRUCTURE_FLAG_SURFACE + +/obj/structure/rack/steel + material = /decl/material/solid/metal/steel + +/obj/structure/rack/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/structure/rack/LateInitialize() + . = ..() + var/i = -1 + for(var/obj/item/I in get_turf(src)) + if(!I.anchored && I.center_of_mass && I.simulated) + i++ + I.pixel_x = 1 // There's a sprite layering bug for 0/0 pixelshift, so we avoid it. + I.pixel_y = max(3-i*3, -3) + 1 + I.pixel_z = 0 + +/obj/structure/rack/adjust_required_attack_dexterity(mob/user, required_dexterity) + // Let people put stuff on tables without necessarily being able to use a gun or such. + if(user?.check_intent(I_FLAG_HELP)) + return DEXTERITY_HOLD_ITEM + return ..() + +/obj/structure/rack/attackby(obj/item/used_item, mob/user, click_params) + . = ..() + if(!. && !isrobot(user) && used_item.loc == user && user.try_unequip(used_item, loc)) + auto_align(used_item, click_params) + return TRUE + +/obj/structure/rack/holorack/dismantle_structure(mob/user) + material = null + reinf_material = null + parts_type = null + . = ..() + +/obj/structure/rack/dark + color = COLOR_GRAY40 + +/obj/structure/rack/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + +/obj/structure/rack/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/rack/mahogany + material = /decl/material/solid/organic/wood/mahogany + color = /decl/material/solid/organic/wood/mahogany::color diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm index f6011545fb46..776c5162398b 100644 --- a/code/game/objects/structures/railing.dm +++ b/code/game/objects/structures/railing.dm @@ -2,32 +2,59 @@ name = "railing" desc = "A simple bar railing designed to protect against careless trespass." icon = 'icons/obj/structures/railing.dmi' - icon_state = "railing0-1" - density = 1 + icon_state = "railing_preview" + density = TRUE throwpass = 1 layer = OBJ_LAYER climb_speed_mult = 0.25 anchored = FALSE - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CHECKS_BORDER | ATOM_FLAG_CLIMBABLE - obj_flags = OBJ_FLAG_ROTATABLE + atom_flags = ATOM_FLAG_CHECKS_BORDER | ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ROTATABLE | OBJ_FLAG_MOVES_UNSUPPORTED material = DEFAULT_FURNITURE_MATERIAL material_alteration = MAT_FLAG_ALTERATION_ALL - maxhealth = 100 + max_health = 100 + parts_amount = 2 + parts_type = /obj/item/stack/material/rods var/broken = FALSE var/neighbor_status = 0 +/obj/structure/railing/should_have_alpha_mask() + return simulated && isturf(loc) && !(locate(/obj/structure/railing) in get_step(loc, SOUTH)) + /obj/structure/railing/mapped - color = COLOR_GUNMETAL anchored = TRUE + color = COLOR_ORANGE + paint_color = COLOR_ORANGE -/obj/structure/railing/mapped/Initialize() - . = ..() - color = COLOR_GUNMETAL // They're not painted! +/obj/structure/railing/mapped/grey + paint_color = COLOR_SILVER /obj/structure/railing/mapped/no_density - density = 0 + density = FALSE + +/obj/structure/railing/mapped/wooden + material = /decl/material/solid/organic/wood/oak + parts_type = /obj/item/stack/material/plank + color = WOOD_COLOR_GENERIC + paint_color = null + +// Subtypes. +#define WOOD_RAILING_SUBTYPE(material_name) \ +/obj/structure/railing/mapped/wooden/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ + color = /decl/material/solid/organic/wood/##material_name::color; \ +} + +WOOD_RAILING_SUBTYPE(fungal) +WOOD_RAILING_SUBTYPE(ebony) +WOOD_RAILING_SUBTYPE(walnut) +WOOD_RAILING_SUBTYPE(maple) +WOOD_RAILING_SUBTYPE(mahogany) +WOOD_RAILING_SUBTYPE(bamboo) +WOOD_RAILING_SUBTYPE(yew) +#undef WOOD_RAILING_SUBTYPE /obj/structure/railing/Process() if(!material || !material.radioactivity) @@ -45,8 +72,9 @@ obj_flags |= OBJ_FLAG_CONDUCTIBLE else obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) - if(anchored) - update_icon(FALSE) + + update_connections() + update_icon() /obj/structure/railing/get_material_health_modifier() . = 0.2 @@ -63,8 +91,8 @@ broken = TRUE for(var/thing in RANGE_TURFS(src, 1)) var/turf/T = thing - for(var/obj/structure/railing/R in T.contents) - R.update_icon() + for(var/obj/structure/railing/rail in T.contents) + rail.update_icon() . = ..() /obj/structure/railing/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) @@ -74,73 +102,68 @@ return !density return TRUE -/obj/structure/railing/examine(mob/user) - . = ..() - if(health < maxhealth) - switch(health / maxhealth) - if(0.0 to 0.5) - to_chat(user, "It looks severely damaged!") - if(0.25 to 0.5) - to_chat(user, "It looks damaged!") - if(0.5 to 1.0) - to_chat(user, "It has a few scrapes and dents.") - -/obj/structure/railing/take_damage(amount) - health -= amount - if(health <= 0) - visible_message("\The [src] [material.destruction_desc]!") - playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) - material.place_shard(get_turf(usr)) - qdel(src) - -/obj/structure/railing/proc/NeighborsCheck(var/UpdateNeighbors = 1) +// TODO: Make railings use the normal structure smoothing system! This sucks! +/obj/structure/railing/update_connections(propagate = FALSE) neighbor_status = 0 - var/Rturn = turn(src.dir, -90) - var/Lturn = turn(src.dir, 90) + var/Rturn = turn(dir, -90) + var/Lturn = turn(dir, 90) - for(var/obj/structure/railing/R in src.loc) - if ((R.dir == Lturn) && R.anchored) + for(var/obj/structure/railing/rail in loc) + if ((rail.dir == Lturn) && rail.anchored) neighbor_status |= 32 - if (UpdateNeighbors) - R.update_icon(0) - if ((R.dir == Rturn) && R.anchored) + if (propagate) + rail.update_connections() + rail.update_icon() + if ((rail.dir == Rturn) && rail.anchored) neighbor_status |= 2 - if (UpdateNeighbors) - R.update_icon(0) - for (var/obj/structure/railing/R in get_step(src, Lturn)) - if ((R.dir == src.dir) && R.anchored) + if (propagate) + rail.update_connections() + rail.update_icon() + for (var/obj/structure/railing/rail in get_step(src, Lturn)) + if ((rail.dir == dir) && rail.anchored) neighbor_status |= 16 - if (UpdateNeighbors) - R.update_icon(0) - for (var/obj/structure/railing/R in get_step(src, Rturn)) - if ((R.dir == src.dir) && R.anchored) + if (propagate) + rail.update_connections() + rail.update_icon() + for (var/obj/structure/railing/rail in get_step(src, Rturn)) + if ((rail.dir == dir) && rail.anchored) neighbor_status |= 1 - if (UpdateNeighbors) - R.update_icon(0) - for (var/obj/structure/railing/R in get_step(src, (Lturn + src.dir))) - if ((R.dir == Rturn) && R.anchored) + if (propagate) + rail.update_connections() + rail.update_icon() + for (var/obj/structure/railing/rail in get_step(src, (Lturn + dir))) + if ((rail.dir == Rturn) && rail.anchored) neighbor_status |= 64 - if (UpdateNeighbors) - R.update_icon(0) - for (var/obj/structure/railing/R in get_step(src, (Rturn + src.dir))) - if ((R.dir == Lturn) && R.anchored) + if (propagate) + rail.update_connections() + rail.update_icon() + for (var/obj/structure/railing/rail in get_step(src, (Rturn + dir))) + if ((rail.dir == Lturn) && rail.anchored) neighbor_status |= 4 - if (UpdateNeighbors) - R.update_icon(0) + if (propagate) + rail.update_connections() + rail.update_icon() -/obj/structure/railing/on_update_icon(var/update_neighbors = TRUE) - NeighborsCheck(update_neighbors) - overlays.Cut() +/obj/structure/railing/on_update_icon() + ..() if (!neighbor_status || !anchored) icon_state = "railing0-[density]" + if (density)//walking over a railing which is above you is really weird, do not do this if density is 0 + add_overlay(image(icon, "_railing0-1", layer = ABOVE_HUMAN_LAYER)) else icon_state = "railing1-[density]" + if (density) + add_overlay(image(icon, "_railing1-1", layer = ABOVE_HUMAN_LAYER)) if (neighbor_status & 32) - overlays += image(icon, "corneroverlay[density]") + add_overlay(image(icon, "corneroverlay[density]")) if ((neighbor_status & 16) || !(neighbor_status & 32) || (neighbor_status & 64)) - overlays += image(icon, "frontoverlay_l[density]") + add_overlay(image(icon, "frontoverlay_l[density]")) + if (density) + add_overlay(image(icon, "_frontoverlay_l1", layer = ABOVE_HUMAN_LAYER)) if (!(neighbor_status & 2) || (neighbor_status & 1) || (neighbor_status & 4)) - overlays += image(icon, "frontoverlay_r[density]") + add_overlay(image(icon, "frontoverlay_r[density]")) + if (density) + add_overlay(image(icon, "_frontoverlay_r1", layer = ABOVE_HUMAN_LAYER)) if(neighbor_status & 4) var/pix_offset_x = 0 var/pix_offset_y = 0 @@ -153,8 +176,9 @@ pix_offset_y = -32 if(WEST) pix_offset_y = 32 - overlays += image(icon, "mcorneroverlay[density]", pixel_x = pix_offset_x, pixel_y = pix_offset_y) - + add_overlay(image(icon, "mcorneroverlay[density]", pixel_x = pix_offset_x, pixel_y = pix_offset_y)) + if (density) + add_overlay(image(icon, "_mcorneroverlay1", pixel_x = pix_offset_x, pixel_y = pix_offset_y, layer = ABOVE_HUMAN_LAYER)) /obj/structure/railing/verb/flip() // This will help push railing to remote places, such as open space turfs set name = "Flip Railing" @@ -172,8 +196,9 @@ to_chat(usr, "You can't flip \the [src] - something is in the way.") return 0 - forceMove(get_step(src, src.dir)) + forceMove(get_step(src, dir)) set_dir(turn(dir, 180)) + update_connections(TRUE) update_icon() /obj/structure/railing/CheckExit(var/atom/movable/O, var/turf/target) @@ -185,91 +210,106 @@ return 0 return 1 -/obj/structure/railing/attackby(var/obj/item/W, var/mob/user) - // Handle harm intent grabbing/tabling. - if(istype(W, /obj/item/grab) && get_dist(src,user)<2) - var/obj/item/grab/G = W - if(istype(G.affecting, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = G.get_affecting_mob() - var/obj/occupied = turf_is_crowded() - if(occupied) - to_chat(user, "There's \a [occupied] in the way.") - return - - if(G.force_danger()) - if(user.a_intent == I_HURT) - visible_message("[G.assailant] slams [H]'s face against \the [src]!") - playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) - var/blocked = H.get_blocked_ratio(BP_HEAD, BRUTE, damage = 8) - if (prob(30 * (1 - blocked))) - H.Weaken(5) - H.apply_damage(8, BRUTE, BP_HEAD) - else - if (get_turf(H) == get_turf(src)) - H.forceMove(get_step(src, src.dir)) - else - H.dropInto(loc) - H.Weaken(5) - visible_message("[G.assailant] throws \the [H] over \the [src].") - else - to_chat(user, "You need a better grip to do that!") - return +/obj/structure/railing/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(!istype(victim) || !istype(user)) + return ..() + + // We want to throw the mob over the railing if we or they are already on the railing turf. + var/turf/target_turf = get_turf(src) + if(victim.loc == target_turf || user.loc == target_turf) + target_turf = get_step_resolving_mimic(target_turf, dir) + + if(!istype(target_turf) || target_turf.density) + return ..() + var/obj/occupied = target_turf.turf_is_crowded() + if(occupied) + to_chat(user, SPAN_WARNING("There's \a [occupied] in the way.")) + return TRUE + + if(!grab.force_danger()) + to_chat(user, SPAN_WARNING("You need a better grip to do that!")) + return TRUE + + if(user.check_intent(I_FLAG_HARM) && ishuman(victim)) + visible_message(SPAN_DANGER("\The [user] slams \the [victim]'s face against \the [src]!")) + playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) + var/blocked = victim.get_blocked_ratio(BP_HEAD, BRUTE, damage = 8) + if (prob(30 * (1 - blocked))) + SET_STATUS_MAX(victim, STAT_WEAK, 5) + victim.apply_damage(8, BRUTE, BP_HEAD) + return TRUE + + if (get_turf(victim) == get_turf(src)) + victim.forceMove(get_step(src, dir)) + else + victim.dropInto(loc) + SET_STATUS_MAX(victim, STAT_WEAK, 5) + visible_message(SPAN_DANGER("\The [user] throws \the [victim] over \the [src]!")) + return TRUE + +// TODO: rewrite to use handle_default_wrench_attackby, bash, etc +/obj/structure/railing/attackby(var/obj/item/used_item, var/mob/user) // Dismantle - if(isWrench(W)) + if(IS_WRENCH(used_item)) if(!anchored) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, 20, src)) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 2 SECONDS, src)) if(anchored) - return + return TRUE user.visible_message("\The [user] dismantles \the [src].", "You dismantle \the [src].") - material.place_sheet(loc, 2) + material.create_object(loc, 2) qdel(src) - return + return TRUE // Wrench Open else - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) if(density) user.visible_message("\The [user] wrenches \the [src] open.", "You wrench \the [src] open.") - density = 0 + density = FALSE else user.visible_message("\The [user] wrenches \the [src] closed.", "You wrench \the [src] closed.") - density = 1 + density = TRUE + update_connections(TRUE) update_icon() - return + return TRUE // Repair - if(isWelder(W)) - var/obj/item/weldingtool/F = W + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/F = used_item if(F.isOn()) - if(health >= maxhealth) + var/current_max_health = get_max_health() + if(current_health >= current_max_health) to_chat(user, "\The [src] does not need repairs.") - return - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + return TRUE + playsound(loc, 'sound/items/Welder.ogg', 50, 1) if(do_after(user, 20, src)) - if(health >= maxhealth) - return + if(current_health >= current_max_health) + return TRUE user.visible_message("\The [user] repairs some damage to \the [src].", "You repair some damage to \the [src].") - health = min(health+(maxhealth/5), maxhealth) - return + current_health = min(current_health+(current_max_health/5), current_max_health) + return TRUE // Install - if(isScrewdriver(W)) + if(IS_SCREWDRIVER(used_item)) if(!density) to_chat(user, "You need to wrench \the [src] from back into place first.") - return + return TRUE user.visible_message(anchored ? "\The [user] begins unscrew \the [src]." : "\The [user] begins fasten \the [src]." ) playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) if(do_after(user, 10, src) && density) to_chat(user, (anchored ? "You have unfastened \the [src] from the floor." : "You have fastened \the [src] to the floor.")) anchored = !anchored + update_connections(TRUE) update_icon() - return + return TRUE - if(W.force && (W.damtype == "fire" || W.damtype == "brute")) + var/force = used_item.expend_attack_force(user) + if(force && (used_item.atom_damage_type == BURN || used_item.atom_damage_type == BRUTE)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - visible_message("\The [src] has been [LAZYLEN(W.attack_verb) ? pick(W.attack_verb) : "attacked"] with \the [W] by \the [user]!") - take_damage(W.force) - return + visible_message("\The [src] has been [used_item.pick_attack_verb()] with \the [used_item] by \the [user]!") + take_damage(force, used_item.atom_damage_type) + return TRUE . = ..() /obj/structure/railing/explosion_act(severity) @@ -277,16 +317,18 @@ if(!QDELETED(src)) qdel(src) -/obj/structure/railing/can_climb(var/mob/living/user, post_climb_check=0) - . = ..() - if(. && get_turf(user) == get_turf(src)) - var/turf/T = get_step(src, src.dir) +/obj/structure/railing/can_climb(mob/living/user, post_climb_check = FALSE, silent = FALSE) + if((. = ..()) && get_turf(user) == get_turf(src)) + var/turf/T = get_step(src, dir) if(T.turf_is_crowded(user)) - to_chat(user, "You can't climb there, the way is blocked.") - return 0 + if(!silent) + to_chat(user, SPAN_WARNING("You can't climb there, the way is blocked.")) + return FALSE /obj/structure/railing/do_climb(var/mob/living/user) . = ..() - if(.) - if(!anchored || material.is_brittle()) - take_damage(maxhealth) // Fatboy + if(. && (!anchored || material.is_brittle())) + take_damage(get_max_health()) + + user.jump_layer_shift() + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, jump_layer_shift_end)), 2) diff --git a/code/game/objects/structures/rubble.dm b/code/game/objects/structures/rubble.dm index a0c02d6502e0..221b9ebd9ea0 100644 --- a/code/game/objects/structures/rubble.dm +++ b/code/game/objects/structures/rubble.dm @@ -3,83 +3,83 @@ desc = "One man's garbage is another man's treasure." icon = 'icons/obj/structures/rubble.dmi' icon_state = "base" - appearance_flags = PIXEL_SCALE - opacity = 1 - density = 1 - anchored = 1 - maxhealth = 50 + opacity = TRUE + density = TRUE + anchored = TRUE + max_health = 50 - var/list/loot = list(/obj/item/cell,/obj/item/stack/material/iron,/obj/item/stack/material/rods) + var/list/loot = list( + /obj/item/cell, + /obj/item/stack/material/ingot/mapped/iron, + /obj/item/stack/material/rods + ) var/lootleft = 1 var/emptyprob = 95 var/is_rummaging = 0 /obj/structure/rubble/Initialize() . = ..() - if(prob(emptyprob)) + if(prob(emptyprob)) lootleft = 0 update_icon() /obj/structure/rubble/on_update_icon() - overlays.Cut() - var/list/parts = list() + ..() for(var/i = 1 to 7) - var/image/I = image(icon,"rubble[rand(1,15)]") + var/image/overlay_image = image(icon,"rubble[rand(1,76)]") if(prob(10)) var/atom/A = pick(loot) if(initial(A.icon) && initial(A.icon_state)) - I.icon = initial(A.icon) - I.icon_state = initial(A.icon_state) - I.color = initial(A.color) + overlay_image.icon = initial(A.icon) + overlay_image.icon_state = initial(A.icon_state) + overlay_image.color = initial(A.color) if(!lootleft) - I.color = "#54362e" - I.appearance_flags = PIXEL_SCALE - I.pixel_x = rand(-16,16) - I.pixel_y = rand(-16,16) + overlay_image.color = "#54362e" + overlay_image.pixel_x = rand(-16,16) + overlay_image.pixel_y = rand(-16,16) var/matrix/M = matrix() M.Turn(rand(0,360)) - I.transform = M - parts += I - overlays = parts + overlay_image.transform = M + add_overlay(overlay_image) + if(lootleft) - overlays += image(icon,"twinkle[rand(1,3)]") + add_overlay("twinkle[rand(1,3)]") /obj/structure/rubble/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() if(!is_rummaging) if(!lootleft) - to_chat(user, "There's nothing left in this one but unusable garbage...") - return - visible_message("[user] starts rummaging through \the [src].") - is_rummaging = 1 + to_chat(user, SPAN_NOTICE("There's nothing left in this one but unusable garbage...")) + return TRUE + visible_message(SPAN_NOTICE("\The [user] starts rummaging through \the [src].")) + is_rummaging = TRUE if(do_after(user, 30)) var/obj/item/booty = pickweight(loot) booty = new booty(loc) lootleft-- update_icon() - to_chat(user, "You find something and pull it carefully out of \the [src].") - is_rummaging = 0 + to_chat(user, SPAN_NOTICE("You find something and pull it carefully out of \the [src].")) + is_rummaging = FALSE else - to_chat(user, "Someone is already rummaging here!") - -/obj/structure/rubble/attackby(var/obj/item/I, var/mob/user) - if (istype(I, /obj/item/pickaxe)) - var/obj/item/pickaxe/P = I - visible_message("[user] starts clearing away \the [src].") - if(do_after(user,P.digspeed, src)) - visible_message("[user] clears away \the [src].") - if(lootleft && prob(1)) - var/obj/item/booty = pickweight(loot) - booty = new booty(loc) - qdel(src) + to_chat(user, SPAN_WARNING("Someone is already rummaging here!")) + return TRUE + +/obj/structure/rubble/attackby(var/obj/item/used_item, var/mob/user) + if(used_item.do_tool_interaction(TOOL_PICK, user, used_item, 3 SECONDS, set_cooldown = TRUE)) + if(lootleft && prob(1)) + var/obj/item/booty = pickweight(loot) + booty = new booty(loc) + qdel(src) return TRUE . = ..() -/obj/structure/rubble/dismantle() +/obj/structure/rubble/dismantle_structure(mob/user) SHOULD_CALL_PARENT(FALSE) qdel(src) . = TRUE - -/obj/structure/rubble/physically_destroyed() + +/obj/structure/rubble/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) visible_message(SPAN_NOTICE("\The [src] is cleared away.")) qdel(src) @@ -87,20 +87,20 @@ /obj/structure/rubble/house loot = list( - /obj/item/archaeological_find/house, - /obj/item/archaeological_find/construction = 2 + /obj/random/archaeological_find/house, + /obj/random/archaeological_find/construction = 2 ) /obj/structure/rubble/lab emptyprob = 30 loot = list( - /obj/item/archaeological_find/lab, - /obj/item/archaeological_find/construction = 6 + /obj/random/archaeological_find/lab, + /obj/random/archaeological_find/construction = 6 ) /obj/structure/rubble/war emptyprob = 95 //can't have piles upon piles of guns loot = list( - /obj/item/archaeological_find/blade, - /obj/item/archaeological_find/gun + /obj/random/archaeological_find/blade, + /obj/random/archaeological_find/gun ) \ No newline at end of file diff --git a/code/game/objects/structures/rug.dm b/code/game/objects/structures/rug.dm new file mode 100644 index 000000000000..b4bf628184f6 --- /dev/null +++ b/code/game/objects/structures/rug.dm @@ -0,0 +1,12 @@ +/obj/structure/rug + name = "rug" + desc = "A small, circular floor covering." + icon = 'icons/obj/structures/rug.dmi' + material = /decl/material/solid/organic/cloth/wool + icon_state = ICON_STATE_WORLD + paint_color = COLOR_GRAY20 + color = COLOR_GRAY20 + +/obj/structure/rug/crafted + paint_color = null + color = null diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index f09bbcc29ffb..bd2bfd5e8d37 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -10,8 +10,8 @@ FLOOR SAFES desc = "A huge chunk of metal with a dial embedded in it. Fine print on the dial reads \"Scarborough Arms - 2 tumbler safe, guaranteed thermite resistant, explosion resistant, and assistant resistant.\"." icon = 'icons/obj/structures/safe.dmi' icon_state = "safe" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/open = 0 //is the safe open? var/tumbler_1_pos //the tumbler position- from 0 to 72 var/tumbler_1_open //the tumbler position to open at- 0 to 72 @@ -21,13 +21,14 @@ FLOOR SAFES var/space = 0 //the combined w_class of everything in the safe var/maxspace = 24 //the maximum combined w_class of stuff in the safe +// TODO: make this use a storage datum? /obj/structure/safe/Initialize() - for(var/obj/item/I in loc) + for(var/obj/item/thing in loc) if(space >= maxspace) - return - if(I.w_class + space <= maxspace) //todo replace with internal storage or something - space += I.w_class - I.forceMove(src) + break + if(thing.w_class + space <= maxspace) //todo replace with internal storage or something + space += thing.w_class + thing.forceMove(src) . = ..() tumbler_1_pos = rand(0, 72) tumbler_1_open = rand(0, 72) @@ -62,44 +63,42 @@ FLOOR SAFES /obj/structure/safe/on_update_icon() + ..() if(open) icon_state = "[initial(icon_state)]-open" else icon_state = initial(icon_state) - /obj/structure/safe/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS, TRUE)) + return ..() + user.set_machine(src) var/dat = "
              " - dat += "[open ? "Close" : "Open"] [src] | - [dial * 5] +" + dat += "[open ? "Close" : "Open"] [src] | - [dial * 5] +" if(open) dat += "" for(var/i = contents.len, i>=1, i--) var/obj/item/P = contents[i] - dat += "" + dat += "" dat += "
              [P.name]
              [P.name]
              " show_browser(user, "[name][dat]", "window=safe;size=350x300") + return TRUE +/obj/structure/safe/DefaultTopicState() + return global.physical_no_access_topic_state -/obj/structure/safe/Topic(href, href_list) - if(!ishuman(usr)) return - var/mob/living/carbon/human/user = usr - - var/canhear = 0 - if(istype(user.l_hand, /obj/item/clothing/accessory/stethoscope) || istype(user.r_hand, /obj/item/clothing/accessory/stethoscope)) - canhear = 1 - +/obj/structure/safe/OnTopic(mob/user, href_list, state) if(href_list["open"]) if(check_unlocked()) to_chat(user, "You [open ? "close" : "open"] [src].") open = !open - update_icon() - updateUsrDialog() - return + return TOPIC_REFRESH else to_chat(user, "You can't [open ? "close" : "open"] [src], the lock is engaged!") - return + return TOPIC_HANDLED + var/canhear = locate(/obj/item/clothing/neck/stethoscope) in user.get_held_items() if(href_list["decrement"]) dial = decrement(dial) if(dial == tumbler_1_pos + 1 || dial == tumbler_1_pos - 71) @@ -111,8 +110,7 @@ FLOOR SAFES if(canhear) to_chat(user, "You hear a [pick("click", "chink", "clink")] from [src].") check_unlocked(user, canhear) - updateUsrDialog() - return + return TOPIC_REFRESH if(href_list["increment"]) dial = increment(dial) @@ -125,38 +123,37 @@ FLOOR SAFES if(canhear) to_chat(user, "You hear a [pick("click", "chink", "clink")] from [src].") check_unlocked(user, canhear) - updateUsrDialog() - return + return TOPIC_REFRESH if(href_list["retrieve"]) - close_browser(user, "window=safe") // Close the menu - + if(!open) + return TOPIC_CLOSE // Close the menu var/obj/item/P = locate(href_list["retrieve"]) in src - if(open) - if(P && in_range(src, user)) - user.put_in_hands(P) - updateUsrDialog() + if(P && CanPhysicallyInteract(user)) + user.put_in_hands(P) + return TOPIC_REFRESH -/obj/structure/safe/attackby(obj/item/I, mob/user) +/obj/structure/safe/attackby(obj/item/used_item, mob/user) if(open) - if(I.w_class + space <= maxspace) - if(!user.unEquip(I, src)) - return - space += I.w_class - to_chat(user, "You put [I] in [src].") + if(used_item.w_class + space <= maxspace) + if(!user.try_unequip(used_item, src)) + return TRUE + space += used_item.w_class + to_chat(user, "You put [used_item] in [src].") updateUsrDialog() - return + return TRUE else - to_chat(user, "[I] won't fit in [src].") - return + to_chat(user, "[used_item] won't fit in [src].") + return TRUE else - if(istype(I, /obj/item/clothing/accessory/stethoscope)) - to_chat(user, "Hold [I] in one of your hands while you manipulate the dial.") - return + if(istype(used_item, /obj/item/clothing/neck/stethoscope)) + to_chat(user, "Hold [used_item] in one of your hands while you manipulate the dial.") + return TRUE + return FALSE -obj/structure/safe/explosion_act(severity) +/obj/structure/safe/explosion_act(severity) SHOULD_CALL_PARENT(FALSE) return @@ -164,8 +161,8 @@ obj/structure/safe/explosion_act(severity) /obj/structure/safe/floor name = "floor safe" icon_state = "floorsafe" - density = 0 - level = 1 //underfloor + density = FALSE + level = LEVEL_BELOW_PLATING layer = BELOW_OBJ_LAYER /obj/structure/safe/floor/Initialize() diff --git a/code/game/objects/structures/seaweed.dm b/code/game/objects/structures/seaweed.dm index d3bc8722ffc6..45762a60d942 100644 --- a/code/game/objects/structures/seaweed.dm +++ b/code/game/objects/structures/seaweed.dm @@ -17,14 +17,21 @@ name = "glowing seaweed" desc = "It shines with an eerie bioluminescent light." icon_state = "glowweed1" + light_color = "#00fff4" /obj/structure/flora/seaweed/glow/Initialize() . = ..() - set_light(0.6, 0.1, 4, 3, "#00fff4") + set_light(3, 0.6, l_color = light_color) icon_state = "glowweed[rand(1,3)]" /obj/effect/decal/cleanable/lichen name = "lichen" desc = "Damp and mossy plant life." icon_state = "lichen" - icon = 'icons/obj/structures/plants.dmi' \ No newline at end of file + icon = 'icons/obj/structures/plants.dmi' + +/obj/effect/decal/cleanable/lichen/attackby(obj/item/used_item, mob/user) + if(used_item.is_sharp() && used_item.expend_attack_force(user) > 1) + qdel(src) + return TRUE + . = ..() \ No newline at end of file diff --git a/code/game/objects/structures/showcase.dm b/code/game/objects/structures/showcase.dm index 76230b8f6551..2b4de7e59dbf 100644 --- a/code/game/objects/structures/showcase.dm +++ b/code/game/objects/structures/showcase.dm @@ -3,6 +3,5 @@ icon = 'icons/obj/structures/showcase.dmi' icon_state = "showcase_1" desc = "A stand with the empty body of a cyborg bolted to it." - density = 1 - anchored = 1 - unacidable = 1//temporary until I decide whether the borg can be removed. -veyveyr \ No newline at end of file + density = TRUE + anchored = TRUE diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm deleted file mode 100644 index cf1085d48545..000000000000 --- a/code/game/objects/structures/signs.dm +++ /dev/null @@ -1,487 +0,0 @@ -/obj/structure/sign - icon = 'icons/obj/decals.dmi' - anchored = 1 - opacity = 0 - density = 0 - layer = ABOVE_WINDOW_LAYER - w_class = ITEM_SIZE_NORMAL - -/obj/structure/sign/explosion_act(severity) - ..() - if(!QDELETED(src)) - physically_destroyed() - -/obj/structure/sign/attackby(obj/item/tool, mob/user) //deconstruction - if(isScrewdriver(tool) && !istype(src, /obj/structure/sign/double)) - to_chat(user, "You unfasten the sign with your [tool.name].") - var/obj/item/sign/S = new(src.loc) - S.SetName(name) - S.desc = desc - S.icon_state = icon_state - S.sign_state = icon_state - qdel(src) - else ..() - -/obj/item/sign - name = "sign" - desc = "" - icon = 'icons/obj/decals.dmi' - w_class = ITEM_SIZE_NORMAL //big - var/sign_state = "" - -/obj/item/sign/attackby(obj/item/tool, mob/user) //construction - if(istype(tool, /obj/item/screwdriver) && isturf(user.loc)) - var/direction = input("In which direction?", "Select direction.") in list("North", "East", "South", "West", "Cancel") - if(direction == "Cancel") return - var/obj/structure/sign/S = new(user.loc) - switch(direction) - if("North") - S.pixel_y = 32 - if("East") - S.pixel_x = 32 - if("South") - S.pixel_y = -32 - if("West") - S.pixel_x = -32 - else return - S.SetName(name) - S.desc = desc - S.icon_state = sign_state - to_chat(user, "You fasten \the [S] with your [tool].") - qdel(src) - else ..() - -/obj/structure/sign/double/map - name = "map" - desc = "A framed map." - -/obj/structure/sign/double/map/Initialize() - . = ..() - desc = "A framed map of the [station_name()]." - -/obj/structure/sign/double/map/left - icon_state = "map-left" - -/obj/structure/sign/double/map/right - icon_state = "map-right" - -/obj/structure/sign/monkey_painting - name = "\improper Mr. Deempisi portrait" - desc = "Under the painting a plaque reads: 'While the meat grinder may not have spared you, fear not. Not one part of you has gone to waste... You were delicious.'" - icon_state = "monkey_painting" - -/obj/structure/sign/warning - name = "\improper WARNING" - icon_state = "securearea" - -/obj/structure/sign/warning/detailed - icon_state = "securearea2" - -/obj/structure/sign/warning/Initialize() - . = ..() - desc = "A warning sign which reads '[sanitize(name)]'." - -/obj/structure/sign/warning/airlock - name = "\improper EXTERNAL AIRLOCK" - icon_state = "doors" - -/obj/structure/sign/warning/biohazard - name = "\improper BIOHAZARD" - icon_state = "bio" - -/obj/structure/sign/warning/bomb_range - name = "\improper BOMB RANGE" - icon_state = "blast" - -/obj/structure/sign/warning/caution - name = "\improper CAUTION" - -/obj/structure/sign/warning/compressed_gas - name = "\improper COMPRESSED GAS" - icon_state = "hikpa" - -/obj/structure/sign/warning/deathsposal - name = "\improper DISPOSAL LEADS TO SPACE" - icon_state = "deathsposal" - -/obj/structure/sign/warning/docking_area - name = "\improper KEEP CLEAR: DOCKING AREA" - -/obj/structure/sign/warning/engineering_access - name = "\improper ENGINEERING ACCESS" - -/obj/structure/sign/warning/fall - name = "\improper FALL HAZARD" - icon_state = "falling" - -/obj/structure/sign/warning/fire - name = "\improper DANGER: FIRE" - icon_state = "fire" - -/obj/structure/sign/warning/high_voltage - name = "\improper HIGH VOLTAGE" - icon_state = "shock" - -/obj/structure/sign/warning/hot_exhaust - name = "\improper HOT EXHAUST" - icon_state = "fire" - -/obj/structure/sign/warning/internals_required - name = "\improper INTERNALS REQUIRED" - -/obj/structure/sign/warning/lethal_turrets - name = "\improper LETHAL TURRETS" - icon_state = "turrets" - -/obj/structure/sign/warning/lethal_turrets/Initialize() - . = ..() - desc += " Enter at own risk!" - -/obj/structure/sign/warning/mail_delivery - name = "\improper MAIL DELIVERY" - icon_state = "mail" - -/obj/structure/sign/warning/moving_parts - name = "\improper MOVING PARTS" - icon_state = "movingparts" - -/obj/structure/sign/warning/nosmoking_1 - name = "\improper NO SMOKING" - icon_state = "nosmoking" - -/obj/structure/sign/warning/nosmoking_2 - name = "\improper NO SMOKING" - icon_state = "nosmoking2" - -/obj/structure/sign/warning/nosmoking_burned - name = "\improper NO SMOKING" - icon_state = "nosmoking2_b" - -/obj/structure/sign/warning/nosmoking_burned/Initialize() - . = ..() - desc += " It looks charred." - -/obj/structure/sign/warning/smoking - name = "\improper SMOKING" - icon_state = "smoking" - -/obj/structure/sign/warning/smoking/Initialize() - . = ..() - desc += " Hell yeah." - -/obj/structure/sign/warning/pods - name = "\improper ESCAPE PODS" - icon_state = "podsnorth" - -/obj/structure/sign/warning/pods/south - name = "\improper ESCAPE PODS" - icon_state = "podssouth" - -/obj/structure/sign/warning/pods/east - name = "\improper ESCAPE PODS" - icon_state = "podseast" - -/obj/structure/sign/warning/pods/west - name = "\improper ESCAPE PODS" - icon_state = "podswest" - -/obj/structure/sign/warning/radioactive - name = "\improper RADIOACTIVE AREA" - icon_state = "radiation" - -/obj/structure/sign/warning/secure_area - name = "\improper SECURE AREA" - -/obj/structure/sign/warning/secure_area/armory - name = "\improper ARMORY" - icon_state = "armory" - -/obj/structure/sign/warning/server_room - name = "\improper SERVER ROOM" - icon_state = "server" - -/obj/structure/sign/warning/siphon_valve - name = "\improper SIPHON VALVE" - -/obj/structure/sign/warning/vacuum - name = "\improper HARD VACUUM AHEAD" - icon_state = "space" - -/obj/structure/sign/warning/vent_port - name = "\improper EJECTION/VENTING PORT" - -/obj/structure/sign/redcross - name = "medbay" - desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." - icon_state = "redcross" - -/obj/structure/sign/greencross - name = "medbay" - desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." - icon_state = "greencross" - -/obj/structure/sign/bluecross_1 - name = "infirmary" - desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." - icon_state = "bluecross" - -/obj/structure/sign/bluecross_2 - name = "infirmary" - desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." - icon_state = "bluecross2" - -/obj/structure/sign/goldenplaque - name = "The Most Robust Men Award for Robustness" - desc = "To be Robust is not an action or a way of life, but a mental state. Only those with the force of Will strong enough to act during a crisis, saving friend from foe, are truly Robust. Stay Robust my friends." - icon_state = "goldenplaque" - -/obj/structure/sign/goldenplaque/security - name = "motivational plaque" - desc = "A plaque engraved with a generic motivational quote and picture. ' Greater love hath no man than this, that a man lay down his life for his friends. John 15:13 " - -/obj/structure/sign/goldenplaque/medical - name = "medical certificate" - desc = "A picture next to a long winded description of medical certifications and degrees." - -/obj/structure/sign/kiddieplaque - name = "\improper AI developers plaque" - desc = "An extremely long list of names and job titles and a picture of the design team responsible for building this AI Core." - icon_state = "kiddieplaque" - -/obj/structure/sign/atmosplaque - name = "\improper engineering memorial plaque" - desc = "This plaque memorializes those engineers and technicians who made the ultimate sacrifice to save their vessel and its crew." - icon_state = "atmosplaque" - -/obj/structure/sign/double/maltesefalcon //The sign is 64x32, so it needs two tiles. ;3 - name = "The Maltese Falcon" - desc = "The Maltese Falcon, Space Bar and Grill." - -/obj/structure/sign/double/maltesefalcon/left - icon_state = "maltesefalcon-left" - -/obj/structure/sign/double/maltesefalcon/right - icon_state = "maltesefalcon-right" - -/obj/structure/sign/warning/science - name = "\improper SCIENCE!" - icon_state = "science" - -/obj/structure/sign/warning/science/anomalous_materials - name = "\improper ANOMALOUS MATERIALS" - -/obj/structure/sign/warning/science/mass_spectrometry - name = "\improper MASS SPECTROMETRY" - -/obj/structure/sign/science_1 - name = "\improper RESEARCH WING" - desc = "A sign labelling the research wing." - icon_state = "science" - -/obj/structure/sign/science_2 - name = "\improper RESEARCH" - desc = "A sign labelling an area where research is performed." - icon_state = "science2" - -/obj/structure/sign/xenobio_1 - name = "\improper XENOBIOLOGY" - desc = "A sign labelling an area as a place where xenobiological entites are researched." - icon_state = "xenobio" - -/obj/structure/sign/xenobio_2 - name = "\improper XENOBIOLOGY" - desc = "A sign labelling an area as a place where xenobiological entites are researched." - icon_state = "xenobio2" - -/obj/structure/sign/xenobio_3 - name = "\improper XENOBIOLOGY" - desc = "A sign labelling an area as a place where xenobiological entites are researched." - icon_state = "xenobio3" - -/obj/structure/sign/xenobio_4 - name = "\improper XENOBIOLOGY" - desc = "A sign labelling an area as a place where xenobiological entites are researched." - icon_state = "xenobio4" - -/obj/structure/sign/xenoarch - name = "\improper XENOARCHAEOLOGY" - desc = "A sign labelling an area as a place where xenoarchaeological finds are researched." - icon_state = "xenobio4" - -/obj/structure/sign/chemistry - name = "\improper CHEMISTRY" - desc = "A sign labelling an area containing chemical equipment." - icon_state = "chemistry" - -/obj/structure/sign/xenoflora - name = "\improper XENOFLORA" - desc = "A sign labelling an area as a place where xenobiological plants are researched." - icon_state = "hydro4" - -/obj/structure/sign/botany - name = "\improper BOTANY" - desc = "A warning sign which reads 'BOTANY!'." - icon_state = "hydro3" - -/obj/structure/sign/hydro - name = "\improper HYDROPONICS" - desc = "A sign labelling an area as a place where plants are grown." - icon_state = "hydro" - -/obj/structure/sign/hydrostorage - name = "\improper HYDROPONICS STORAGE" - desc = "A sign labelling an area as a place where plant growing supplies are kept." - icon_state = "hydro3" - -/obj/structure/sign/directions - name = "direction sign" - desc = "A direction sign, claiming to know the way." - icon_state = "direction" - -/obj/structure/sign/directions/Initialize() - . = ..() - desc = "A direction sign, pointing out which way \the [src] is." - -/obj/structure/sign/directions/science - name = "\improper Research Division" - icon_state = "direction_sci" - -/obj/structure/sign/directions/engineering - name = "\improper Engineering Bay" - icon_state = "direction_eng" - -/obj/structure/sign/directions/security - name = "\improper Security Wing" - icon_state = "direction_sec" - -/obj/structure/sign/directions/medical - name = "\improper Medical Bay" - icon_state = "direction_med" - -/obj/structure/sign/directions/evac - name = "\improper Evacuation Wing" - icon_state = "direction_evac" - -/obj/structure/sign/directions/bridge - name = "\improper Bridge" - icon_state = "direction_bridge" - -/obj/structure/sign/directions/supply - name = "\improper Supply Office" - icon_state = "direction_supply" - -/obj/structure/sign/directions/infirmary - name = "\improper Infirmary" - icon_state = "direction_infirm" - -/obj/structure/sign/directions/examroom - name = "\improper Exam Room" - icon_state = "examroom" - -/obj/structure/sign/deck/bridge - name = "\improper Bridge Deck" - icon_state = "deck-b" - -/obj/structure/sign/deck/first - name = "\improper First Deck" - icon_state = "deck-1" - -/obj/structure/sign/deck/second - name = "\improper Second Deck" - icon_state = "deck-2" - -/obj/structure/sign/deck/third - name = "\improper Third Deck" - icon_state = "deck-3" - -/obj/structure/sign/deck/fourth - name = "\improper Fourth Deck" - icon_state = "deck-4" - -/obj/structure/sign/deck/fifth - name = "\improper Fifth Deck" - icon_state = "deck-5" - -/obj/item/sign/medipolma - name = "medical diploma" - desc = "A fancy print laminated paper that certifies that its bearer is indeed a Doctor of Medicine, graduated from a medical school in one of fringe systems. You don't recognize the name though, and half of latin words they used do not actually exist." - icon = 'icons/obj/decals.dmi' - icon_state = "goldenplaque" - sign_state = "goldenplaque" - var/claimant - -/obj/item/sign/medipolma/attack_self(mob/user) - if(!claimant) - to_chat(user, "You fill in your name in the blanks with a permanent marker.") - claimant = user.real_name - ..() - -/obj/item/sign/medipolma/examine(mob/user) - . = ..() - if(claimant) - to_chat(user,"This one belongs to Dr.[claimant], MD.") - else - to_chat(user,"The name is left blank for some reason.") - -/obj/structure/sign/janitor - name = "\improper JANITORIAL CLOSET" - desc = "A sign indicating a room used to store cleaning supplies." - icon_state = "janitor" - -/obj/structure/sign/engineering - name = "\improper ENGINEERING" - desc = "A sign labelling an area as the Engineering department." - icon_state = "engineering" - -/obj/structure/sign/telecomms - name = "\improper TELECOMMUNICATIONS" - desc = "A sign labelling an area as the Telecommunications room." - icon_state = "tcomm" - -/obj/structure/sign/cargo - name = "\improper CARGO BAY" - desc = "A sign labelling the area as a cargo bay." - icon_state = "cargo" - -/obj/structure/sign/bridge - name = "\improper BRIDGE" - desc = "A sign indicating the Bridge. Not the kind you cross rivers with, the other kind." - icon_state = "bridge" - -/obj/structure/sign/forensics - name = "\improper FORENSICS" - desc = "A sign labelled FORENSICS." - icon_state = "forensics" - -/obj/structure/sign/security - name = "\improper SECURITY" - desc = "A sign labelling the area as belonging to Security." - icon_state = "sec_scale" - -/obj/structure/sign/security/alt - icon_state = "sec_cuff" - -/obj/structure/sign/eva - name = "\improper EVA" - desc = "A sign indicating this is where Extra Vehicular Activity equipment is stored." - icon_state = "eva" - -/obj/structure/sign/id_office - name = "\improper ID OFFICE" - desc = "A sign to let you know that this is the ID office." - icon_state = "id" - -/obj/structure/sign/hop - name = "\improper HEAD OF PERSONNEL" - desc = "A sign labelling this area as the Head of Personnel's office." - icon_state = "hop" - -/obj/structure/sign/evac - name = "\improper EVACUATION" - desc = "A sign that lets you know that this is where you want to be when the station is full of holes and on fire." - icon_state = "evac" - -/obj/structure/sign/watercloset - name = "bathroom sign" - desc = "Need to take a piss? You've come to the right place." - icon_state = "watercloset" diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm new file mode 100644 index 000000000000..2241befe6254 --- /dev/null +++ b/code/game/objects/structures/signs/_signs.dm @@ -0,0 +1,151 @@ +///////////////////////////////////////////////////////////////////////////////// +// Sign Item +///////////////////////////////////////////////////////////////////////////////// + +///Item form of the sign structure. Stores a sign structure type, and creates that structure upon install. +/// Takes on the appearence and properties of whatever sign structure type it contains. +/obj/item/sign + name = "sign" + w_class = ITEM_SIZE_NORMAL + material = /decl/material/solid/organic/plastic + ///The type of the sign this item will turn into upon installation + var/sign_type + +/obj/item/sign/Initialize(ml, material_key) + . = ..() + if(ispath(sign_type)) + set_sign(sign_type) + update_icon() + +/obj/item/sign/afterattack(turf/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(proximity_flag && isturf(target) && target.is_wall()) + try_install(target, user) + return TRUE + +/obj/item/sign/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item) && used_item.CanUseTopic(user, global.inventory_topic_state) && isturf(user.loc)) + return try_install(used_item, user) + return ..() + +/obj/item/sign/on_update_icon() + . = ..() + //Make us look smaller than the actual sign icon + transform = transform.Scale(0.8, 0.8) + +///Set the sign this sign item will contain from an sign structure instance. +/obj/item/sign/proc/set_sign(var/obj/structure/sign/S) + sign_type = ispath(S)? S : S.type + desc = ispath(S)? initial(S.desc) : S.desc + icon = ispath(S)? initial(S.icon) : S.icon + SetName(ispath(S)? initial(S.name) : S.name) + var/sign_mat = ispath(S)? initial(S.material) : S.material + if(sign_mat) + set_material(sign_mat) + + //Make sure we have the same matter contents as the sign + matter = atom_info_repository.get_matter_for(sign_type) + matter = matter?.Copy() + + //Do this last, so icon update is last + set_icon_state(ispath(S)? initial(S.icon_state) : S.icon_state) + update_held_icon() + +///Actually creates and places the sign structure. Override to add to sign init. +/obj/item/sign/proc/place_sign(var/turf/T, var/direction) + var/obj/structure/sign/S = new sign_type(T) + S.set_dir(direction) + copy_extension(src, S, /datum/extension/labels) + copy_extension(src, S, /datum/extension/forensic_evidence) + copy_extension(src, S, /datum/extension/scent) + transfer_fingerprints_to(S) + sign_type = null + return S + +///Attempts installing the sign and ask the user for direction and etc. +/obj/item/sign/proc/try_install(var/turf/targeted_turf, var/mob/user) + var/facing = get_cardinal_dir(user, targeted_turf) || user.dir + var/install_dir = global.reverse_dir[facing] + //If we used the screwdriver on the panel, it'll be in the active hand + var/obj/item/screwdriver/S = user.get_active_held_item() + if(!istype(S)) + //Otherwise it should be in one of the offhand slots + for(S in user.get_inactive_held_items()) + if(istype(S)) + break + if(!istype(S)) + to_chat(user, SPAN_WARNING("You must hold a screwdriver in your other hand to install this!")) + else if(S.do_tool_interaction(TOOL_SCREWDRIVER, user, src, 3 SECONDS, "fastening", "fastening")) + place_sign(get_turf(user), install_dir) + qdel(src) + return FALSE + +///////////////////////////////////////////////////////////////////////////////// +// Sign Structure +///////////////////////////////////////////////////////////////////////////////// + +///A wall mountable sign structure +/obj/structure/sign + name = "sign" + icon = 'icons/obj/signs/signs.dmi' + anchored = TRUE + opacity = FALSE + density = FALSE + layer = ABOVE_WINDOW_LAYER + w_class = ITEM_SIZE_NORMAL + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "WEST":{"x":32}, "EAST":{"x":-32}}' + abstract_type = /obj/structure/sign + parts_type = /obj/item/sign + parts_amount = 1 + material = /decl/material/solid/organic/plastic + +/obj/structure/sign/Initialize(ml, _mat, _reinf_mat) + . = ..() + update_description() + +///Proc for signs that must initialize their names or description at runtime. +/obj/structure/sign/proc/update_description() + return + +/obj/structure/sign/handle_default_screwdriver_attackby(mob/user, obj/item/screwdriver) + if(QDELETED(src)) + return TRUE + if(screwdriver.do_tool_interaction(TOOL_SCREWDRIVER, user, src, 3 SECONDS, "taking down", "taking down")) + dismantle_structure(user) + return TRUE + +/obj/structure/sign/hide() + return //Signs should no longer hide in walls. + +/obj/structure/sign/create_dismantled_products(turf/T) + SHOULD_CALL_PARENT(FALSE) + if(parts_type && !ispath(parts_type, /obj/item/stack)) + var/obj/item/sign/S = new parts_type(T, (material && material.type), (reinf_material && reinf_material.type)) + S.set_sign(src) + //Copy our stuff over + copy_extension(src, S, /datum/extension/labels) + copy_extension(src, S, /datum/extension/forensic_evidence) + copy_extension(src, S, /datum/extension/scent) + transfer_fingerprints_to(S) + if(paint_color) + S.set_color(paint_color) + clear_materials() + +/obj/structure/sign/double/handle_default_screwdriver_attackby(mob/user, obj/item/screwdriver) + return FALSE + +/obj/structure/sign/clock + name = "clock" + desc = "It's a functionally useless print-out of a clock face." + icon_state = "clock" + +/obj/structure/sign/calendar + name = "calendar" + desc = "It's a functionally useless print-out of a calendar." + icon_state = "calendar" + +/obj/structure/sign/periodic_table + name = "periodic table" + desc = "It's an old, outdated copy of the periodic table of elements." + icon_state = "periodic" diff --git a/code/game/objects/structures/signs/bar_signs.dm b/code/game/objects/structures/signs/bar_signs.dm new file mode 100644 index 000000000000..1d53cf2fa3a8 --- /dev/null +++ b/code/game/objects/structures/signs/bar_signs.dm @@ -0,0 +1,15 @@ +/obj/structure/sign/double/maltesefalcon + name = "The Maltese Falcon" + desc = "The Maltese Falcon, Space Bar and Grill." + //The sign is 64x32, so it needs two tiles. ;3 + icon = 'icons/obj/signs/bar.dmi' + //The bar sign always faces south + directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":32}, "WEST":{"y":32}, "EAST":{"y":32}}' + abstract_type = /obj/structure/sign/double/maltesefalcon + +/obj/structure/sign/double/maltesefalcon/left + icon_state = "maltesefalcon-left" + +/obj/structure/sign/double/maltesefalcon/right + icon_state = "maltesefalcon-right" + diff --git a/code/game/objects/structures/signs/decks.dm b/code/game/objects/structures/signs/decks.dm new file mode 100644 index 000000000000..3fc6dadc59fd --- /dev/null +++ b/code/game/objects/structures/signs/decks.dm @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////// +// Deck Signs +///////////////////////////////////////////////////// + +///A sign for indicating what level is the current level vertically +/obj/structure/sign/deck + abstract_type = /obj/structure/sign/deck + name = "current level sign" + desc = "A sign indicating on what level the observer is currently on." + icon = 'icons/obj/signs/decks.dmi' + +///////////////////////////////////////////////////// +// Deck Signs Definition +///////////////////////////////////////////////////// + +/obj/structure/sign/deck/bridge + name = "\improper Bridge Deck" + icon_state = "deck-b" + +/obj/structure/sign/deck/first + name = "\improper First Deck" + icon_state = "deck-1" + +/obj/structure/sign/deck/second + name = "\improper Second Deck" + icon_state = "deck-2" + +/obj/structure/sign/deck/third + name = "\improper Third Deck" + icon_state = "deck-3" + +/obj/structure/sign/deck/fourth + name = "\improper Fourth Deck" + icon_state = "deck-4" + +/obj/structure/sign/deck/fifth + name = "\improper Fifth Deck" + icon_state = "deck-5" + +/obj/structure/sign/deck/bridge/large + icon_state = "deck-b-large" + +/obj/structure/sign/deck/first/large + icon_state = "deck-1-large" + +/obj/structure/sign/deck/second/large + icon_state = "deck-2-large" + +/obj/structure/sign/deck/third/large + icon_state = "deck-3-large" + +/obj/structure/sign/deck/fourth/large + icon_state = "deck-4-large" + +/obj/structure/sign/deck/level_basement + name = "\improper Basemenet Level" + icon_state = "level-b" + +/obj/structure/sign/deck/level_one + name = "\improper Level One" + icon_state = "level-1" + +/obj/structure/sign/deck/level_two + name = "\improper Level Two" + icon_state = "level-2" + +/obj/structure/sign/deck/level_three + name = "\improper Level Three" + icon_state = "level-3" + +/obj/structure/sign/deck/level_four + name = "\improper Level Four" + icon_state = "level-4" + +/obj/structure/sign/deck/level_ground + name = "\improper Ground Level" + icon_state = "level-g" + +/obj/structure/sign/deck/level_basement/large + icon_state = "level-b-large" + +/obj/structure/sign/deck/level_one/large + icon_state = "level-1-large" + +/obj/structure/sign/deck/level_two/large + icon_state = "level-2-large" + +/obj/structure/sign/deck/level_three/large + icon_state = "level-3-large" + +/obj/structure/sign/deck/level_four/large + icon_state = "level-4-large" + +/obj/structure/sign/deck/level_ground/large + icon_state = "level-g-large" diff --git a/code/game/objects/structures/signs/departments.dm b/code/game/objects/structures/signs/departments.dm new file mode 100644 index 000000000000..0018ae5d6a88 --- /dev/null +++ b/code/game/objects/structures/signs/departments.dm @@ -0,0 +1,209 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Department Sign +/////////////////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/department + abstract_type = /obj/structure/sign/department + icon = 'icons/obj/signs/departments.dmi' + +/////////////////////////////////////////////////////////////////////////////////// +// Department Sign Definitions +/////////////////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/department/science_1 + name = "\improper RESEARCH WING" + desc = "A sign labelling the research wing." + icon_state = "science" + +/obj/structure/sign/department/science_2 + name = "\improper RESEARCH" + desc = "A sign labelling an area where research is performed." + icon_state = "science2" + +/obj/structure/sign/department/science_3 + icon_state = "science1" + +/obj/structure/sign/department/xenobio_1 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entities are researched." + icon_state = "xenobio" + +/obj/structure/sign/department/xenobio_1/large + icon_state = "xenobio-large" + +/obj/structure/sign/department/xenobio_2 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entities are researched." + icon_state = "xenobio2" + +/obj/structure/sign/department/xenobio_3 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entities are researched." + icon_state = "xenobio3" + +/obj/structure/sign/department/xenobio_4 + name = "\improper XENOBIOLOGY" + desc = "A sign labelling an area as a place where xenobiological entities are researched." + icon_state = "xenobio4" + +/obj/structure/sign/department/xenoarch + name = "\improper XENOARCHAEOLOGY" + desc = "A sign labelling an area as a place where xenoarchaeological finds are researched." + icon_state = "xenobio4" + +/obj/structure/sign/department/chemistry + name = "\improper CHEMISTRY" + desc = "A sign labelling an area containing chemical equipment." + icon_state = "chemistry" + +/obj/structure/sign/department/chemistry/alt_1 + icon_state = "chemistry1" + +/obj/structure/sign/department/chemistry/alt_2 + icon_state = "chemistry2" + +/obj/structure/sign/department/xenoflora + name = "\improper XENOFLORA" + desc = "A sign labelling an area as a place where xenobiological plants are researched." + icon_state = "hydro4" + +/obj/structure/sign/department/botany + name = "\improper BOTANY" + desc = "A warning sign which reads 'BOTANY'." + icon_state = "hydro3" + +/obj/structure/sign/department/hydro + name = "\improper HYDROPONICS" + desc = "A sign labelling an area as a place where plants are grown." + icon_state = "hydro" + +/obj/structure/sign/department/hydrostorage + name = "\improper HYDROPONICS STORAGE" + desc = "A sign labelling an area as a place where plant growing supplies are kept." + icon_state = "hydro3" + +/obj/structure/sign/department/hydro/alt_1 + icon_state = "hydro1" + +/obj/structure/sign/department/hydro/alt_2 + icon_state = "hydro2" + +/obj/structure/sign/department/janitor + name = "\improper JANITORIAL CLOSET" + desc = "A sign indicating a room used to store cleaning supplies." + icon_state = "janitor" + +/obj/structure/sign/department/janitor/alt + icon_state = "custodian" + +/obj/structure/sign/department/engineering + name = "\improper ENGINEERING" + desc = "A sign labelling an area as the Engineering department." + icon_state = "engineering" + +/obj/structure/sign/department/engineering/engine + icon_state = "engine" + +/obj/structure/sign/department/telecomms + name = "\improper TELECOMMUNICATIONS" + desc = "A sign labelling an area as the Telecommunications room." + icon_state = "tcomm" + +/obj/structure/sign/department/cargo + name = "\improper CARGO BAY" + desc = "A sign labelling the area as a cargo bay." + icon_state = "cargo" + +/obj/structure/sign/department/cargo/large + icon_state = "cargo-large" + +/obj/structure/sign/department/mail_delivery + name = "\improper MAIL DELIVERY" + desc = "A sign labelling a mail delivery point." + icon_state = "mail" + +/obj/structure/sign/department/mail_delivery/large + icon_state = "mail-large" + +/obj/structure/sign/department/bridge + name = "\improper BRIDGE" + desc = "A sign indicating the Bridge. Not the kind you cross rivers with, the other kind." + icon_state = "bridge" + +/obj/structure/sign/department/forensics + name = "\improper FORENSICS" + desc = "A sign labelled FORENSICS." + icon_state = "forensics" + +/obj/structure/sign/department/security + name = "\improper SECURITY" + desc = "A sign labelling the area as belonging to Security." + icon_state = "sec_scale" + +/obj/structure/sign/department/security/alt + icon_state = "sec_cuff" + +/obj/structure/sign/department/security/large + icon_state = "security" + +/obj/structure/sign/department/eva + name = "\improper EVA" + desc = "A sign indicating this is where Extra Vehicular Activity equipment is stored." + icon_state = "eva" + +/obj/structure/sign/department/id_office + name = "\improper ID OFFICE" + desc = "A sign to let you know that this is the ID office." + icon_state = "id" + +/obj/structure/sign/department/hop + name = "\improper HEAD OF PERSONNEL" + desc = "A sign labelling this area as the Head of Personnel's office." + icon_state = "hop" + +/obj/structure/sign/department/evac + name = "\improper EVACUATION" + desc = "A sign that lets you know that this is where you want to be when the station is full of holes and on fire." + icon_state = "evac" + +/obj/structure/sign/department/evac/large + icon_state = "evac-large" + +/obj/structure/sign/department/restroom + name = "restroom" + desc = "Need to take a piss? You've come to the right place." + icon_state = "watercloset" + +/obj/structure/sign/department/restroom/alt + icon_state = "restroom" + +/obj/structure/sign/department/examroom + name = "exam room" + icon_state = "examroom" + +/obj/structure/sign/department/examroom/large + icon_state = "examroom-large" + +/obj/structure/sign/department/cross + name = "medbay" + desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here." + icon_state = "redcross" + +/obj/structure/sign/department/cross/green + icon_state = "greencross" + +/obj/structure/sign/department/cross/blue + icon_state = "bluecross" + +/obj/structure/sign/department/cross/blue2 + icon_state = "bluecross2" + +/obj/structure/sign/department/cross/star_of_life + name = "emergency" + desc = "The blue six-pointed star with a rod of Asclepius is the intergalactic symbol of emergency medical services." + icon_state = "staroflife" + +/obj/structure/sign/department/chapel + name = "\improper CHAPEL" + desc = "A sign labelling this area as the Chapel." + icon_state = "holy" diff --git a/code/game/objects/structures/signs/diploma.dm b/code/game/objects/structures/signs/diploma.dm new file mode 100644 index 000000000000..f3e929982b6d --- /dev/null +++ b/code/game/objects/structures/signs/diploma.dm @@ -0,0 +1,237 @@ + +///Details used by the diploma plaques for display. +/datum/diploma_details + ///Name of the diploma holder + var/claimant + ///Signature of the diploma holder + var/signature + ///Establishment that emitted this diploma + var/establishment = "Space College" + ///The degree's name + var/degree = "master's degree in space" + ///The abbreviation of the degree + var/degree_short = "MD" + ///The title this degree grants + var/title = "Doctor of Space" + ///The abbreviation of the title granted by the degree + var/title_short = "Dr." + +/datum/diploma_details/PopulateClone(datum/clone) + var/datum/diploma_details/populated_clone = ..() + populated_clone.claimant = claimant + populated_clone.signature = signature + populated_clone.establishment = establishment + populated_clone.degree = degree + populated_clone.degree_short = degree_short + populated_clone.title = title + populated_clone.title_short = title_short + return populated_clone + +///Returns a string decribing what's on the diploma. +/datum/diploma_details/proc/get_description_string() + if(length(claimant)) + . = "A fancy print laminated paper that certifies that its bearer, [title_short][claimant], is indeed \a [title], whom earned \a [degree], and graduated from \the [establishment]." + else + . = "A fancy print laminated paper that certifies that its bearer is indeed \a [title], whom earned \a [degree], and graduated from \the [establishment]." + +///Returns a string describing what is seen on closer inspection of the diploma. +/datum/diploma_details/proc/get_examine_string() + if(length(claimant)) + . = "This one is signed [signature], [title_short][claimant] [degree_short]." + else + . = "The signature and name are left blank for some reason." + +//////////////////////////////////////////////////////// +// Diploma Structure +//////////////////////////////////////////////////////// + +///A display for diploma details +/obj/structure/sign/plaque/diploma + abstract_type = /obj/structure/sign/plaque/diploma + name = "laminated diploma" + desc = "A wall-mounted laminated diploma." + icon = 'icons/obj/signs/plaques.dmi' + icon_state = "goldenplaque" + material = /decl/material/solid/organic/wood/maple + matter = list( + /decl/material/solid/glass = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/organic/paper = MATTER_AMOUNT_TRACE, + ) + parts_type = /obj/item/sign/diploma + ///Details on the diploma this plaque contains. Can be a path on definition, turns into an instance at runtime. + var/datum/diploma_details/details = /datum/diploma_details + +/obj/structure/sign/plaque/diploma/Initialize(ml, _mat, _reinf_mat) + //Must be done before parent init + if(ispath(details, /datum/diploma_details)) + details = new details + . = ..() + +/obj/structure/sign/plaque/diploma/update_description() + desc = details.get_description_string() + +/obj/structure/sign/plaque/diploma/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 2) + . += details.get_examine_string() + +//////////////////////////////////////////////////////// +// Diploma Item +//////////////////////////////////////////////////////// + +///A displayable diploma +/obj/item/sign/diploma + abstract_type = /obj/item/sign/diploma + name = "diploma" + sign_type = /obj/structure/sign/plaque/diploma + material = /decl/material/solid/organic/wood/maple + matter = list( + /decl/material/solid/glass = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/organic/paper = MATTER_AMOUNT_TRACE, + ) + ///Details on the diploma this plaque contains. Can be a path on definition, turns into an instance at runtime. + var/datum/diploma_details/details = /datum/diploma_details + +/obj/item/sign/diploma/Initialize(ml, material_key) + . = ..() + if(ispath(details, /datum/diploma_details)) + details = new details + +/obj/item/sign/diploma/set_sign(var/obj/structure/sign/plaque/diploma/S) + . = ..() + if(ispath(S)) + //If it's a path, create the default type of details + details = null + SetName(initial(S.name)) + var/detail_path = initial(S.details) + if(ispath(detail_path, /datum/diploma_details)) + details = new detail_path + else + SetName(S.name) + details = S.details.Clone() + update_description() + +/obj/item/sign/diploma/place_sign(turf/T, direction) + var/obj/structure/sign/plaque/diploma/D = ..() + D.details = details.Clone() + D.update_description() + return D + +/obj/item/sign/diploma/proc/update_description() + desc = details.get_description_string() + +/obj/item/sign/diploma/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 2) + . += details.get_examine_string() + +/obj/item/sign/diploma/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) + sign_diploma(used_item, user) + return TRUE + return ..() + +/obj/item/sign/diploma/proc/sign_diploma(var/obj/item/pen/P, var/mob/user) + if(length(details.claimant)) + to_chat(user, SPAN_NOTICE("The diploma is already signed!")) + return + if(P.do_tool_interaction(TOOL_PEN, user, src, 1 SECONDS, "signing", "signing")) + var/decl/tool_archetype/pen/parch = GET_DECL(TOOL_PEN) + var/pen_color = P.get_tool_property(TOOL_PEN, TOOL_PROP_COLOR) + var/pen_font = P.get_tool_property(TOOL_PEN, TOOL_PROP_PEN_FONT) + details.claimant = parch.get_signature(user, P) + details.signature = "[details.claimant]" + update_description() + +//////////////////////////////////////////////////////// +// Fake Diploma +//////////////////////////////////////////////////////// + +/datum/diploma_details/fake + abstract_type = /datum/diploma_details/fake + +/datum/diploma_details/fake/get_description_string() + . = "[..()] You don't recognize the establishment though, and half of latin words they used do not actually exist." + +/obj/structure/sign/plaque/diploma/fake + abstract_type = /obj/structure/sign/plaque/diploma/fake + +//////////////////////////////////////////////////////// +// Medical Diploma +//////////////////////////////////////////////////////// + +/datum/diploma_details/medical + establishment = "Alpha Centauri Medical Academy" + degree = "master's degree in medicine" + degree_short = "MD" + title = "Doctor of Medicine" + title_short = "Dr." + +/obj/structure/sign/plaque/diploma/medical + name = "medical diploma" + details = /datum/diploma_details/medical + parts_type = /obj/item/sign/diploma/medical + +/obj/item/sign/diploma/medical //the item grab the details from the structure so don't need to fill anything else + name = "medical diploma" + sign_type = /obj/structure/sign/plaque/diploma/medical + +//////////////////////////////////////////////////////// +// Fake Medical Diploma +//////////////////////////////////////////////////////// + +/datum/diploma_details/fake/medical + establishment = "Arcturus' Trade School" + degree = "theoritical master's degree in medicine" + degree_short = "MD" + title = "Doctor of Medicine" + title_short = "Dr." + +/obj/structure/sign/plaque/diploma/fake/medical + name = "medical diploma" + details = /datum/diploma_details/fake/medical + parts_type = /obj/item/sign/diploma/fake/medical + +/obj/item/sign/diploma/fake/medical + name = "medical diploma" + sign_type = /obj/structure/sign/plaque/diploma/fake/medical + +//////////////////////////////////////////////////////// +// Physics Diploma +//////////////////////////////////////////////////////// + +/datum/diploma_details/physics + establishment = "CMa Physics Academy" + degree = "master's degree in theoritical physics" + degree_short = "PhD" + title = "Theoritical Physicist" + title_short = "Dr." + +/obj/structure/sign/plaque/diploma/physics + name = "physics diploma" + details = /datum/diploma_details/physics + parts_type = /obj/item/sign/diploma/physics + +/obj/item/sign/diploma/physics + name = "physics diploma" + sign_type = /obj/structure/sign/plaque/diploma/physics + +//////////////////////////////////////////////////////// +// Fake Science Diploma +//////////////////////////////////////////////////////// + +/datum/diploma_details/fake/physics + establishment = "Pollux Academy of Sciences" + degree = "theoritical master's degree in theoritical physics" + degree_short = "PhD" + title = "Theoritical Physicist" + title_short = "Dr." + +/obj/structure/sign/plaque/diploma/fake/physics + name = "physics diploma" + details = /datum/diploma_details/fake/physics + parts_type = /obj/item/sign/diploma/fake/physics + +/obj/item/sign/diploma/fake/physics + name = "physics diploma" + sign_type = /obj/structure/sign/plaque/diploma/fake/physics diff --git a/code/game/objects/structures/signs/directions.dm b/code/game/objects/structures/signs/directions.dm new file mode 100644 index 000000000000..c89ae69448fb --- /dev/null +++ b/code/game/objects/structures/signs/directions.dm @@ -0,0 +1,282 @@ +///////////////////////////////////////////////////// +//Direction Signs +///////////////////////////////////////////////////// + +///Signs for showing the way to passerby. The dir of the sign is the direction it points towards. The icon of the sign itself is always south facing. +/obj/structure/sign/directions + name = "direction sign" + desc = "A direction sign, claiming to know the way." + icon = 'icons/obj/signs/directions.dmi' + icon_state = "direction" + //Direction signs are always meant to face south! The arrow on the sign matches the direction it points to. + directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":32}, "WEST":{"y":32}, "EAST":{"y":32}}' + +/obj/structure/sign/directions/update_description() + desc = "A direction sign, pointing out \the [name] is [global.dir_name(dir)]." + +///////////////////////////////////////////////////// +//Direction Signs Definition +///////////////////////////////////////////////////// + +/obj/structure/sign/directions/science + name = "\improper Research Division" + icon_state = "direction_sci" + +/obj/structure/sign/directions/science/xeno + name = "\improper Xenobiology" + icon_state = "direction_xeno" + +/obj/structure/sign/directions/science/xenoarch + name = "\improper Xenoarchaeology" + icon_state = "direction_xenoarch" + +/obj/structure/sign/directions/science/xenoflora + name = "\improper Xenoflora" + icon_state = "direction_xflora" + +/obj/structure/sign/directions/science/xenobiology + icon_state = "direction_xbio" + +/obj/structure/sign/directions/science/exploration + name = "\improper Exploration" + icon_state = "direction_explo" + +/obj/structure/sign/directions/science/toxins + name = "\improper Toxins" + icon_state = "direction_toxins" + +/obj/structure/sign/directions/science/robotics + name = "\improper Robotics" + icon_state = "direction_robotics" + +/obj/structure/sign/directions/science/rnd + name = "\improper Research and Development" + icon_state = "direction_rnd" + +/obj/structure/sign/directions/engineering + name = "\improper Engineering Bay" + icon_state = "direction_eng" + +/obj/structure/sign/directions/engineering/solars + name = "\improper Solar Array" + icon_state = "direction_solar" + +/obj/structure/sign/directions/engineering/engeqp + name = "\improper Engineering Equipment" + icon_state = "direction_engeqp" + +/obj/structure/sign/directions/engineering/reactor + name = "\improper Reactor Core" + icon_state = "direction_core" + +/obj/structure/sign/directions/engineering/atmospherics + name = "\improper Atmospherics" + icon_state = "direction_atmos" + +/obj/structure/sign/directions/cargo + name = "\improper Cargo" + icon_state = "direction_crg" + +/obj/structure/sign/directions/cargo/supply + name = "\improper Supply Office" + icon_state = "direction_supply" + +/obj/structure/sign/directions/cargo/mining + name = "\improper Mining" + icon_state = "direction_mining" + +/obj/structure/sign/directions/cargo/refinery + name = "\improper Refinery" + icon_state = "direction_refinery" + +/obj/structure/sign/directions/security + name = "\improper Security Wing" + icon_state = "direction_sec" + +/obj/structure/sign/directions/security/interrogation + name = "\improper Interrogation" + icon_state = "direction_interrogation" + +/obj/structure/sign/directions/security/internal_affairs + name = "\improper Internal Affairs" + icon_state = "direction_intaff" + +/obj/structure/sign/directions/security/forensics + name = "\improper Forensics" + icon_state = "direction_forensics" + +/obj/structure/sign/directions/security/forensics/alt + name = "\improper Forensics Laboratory" + icon_state = "direction_lab" + +/obj/structure/sign/directions/security/brig + name = "\improper Security Brig" + icon_state = "direction_brig" + +/obj/structure/sign/directions/security/armory + name = "\improper Security Armory" + icon_state = "direction_armory" + +/obj/structure/sign/directions/security/seceqp + name = "\improper Security Equipment" + icon_state = "direction_seceqp" + +/obj/structure/sign/directions/medical + name = "\improper Medical Bay" + icon_state = "direction_med" + +/obj/structure/sign/directions/medical/morgue + name = "\improper Morgue" + icon_state = "direction_morgue" + +/obj/structure/sign/directions/medical/equipment + name = "\improper Medical Equipment" + icon_state = "direction_medeqp" + +/obj/structure/sign/directions/medical/virology + name = "\improper Virology" + icon_state = "direction_viro" + +/obj/structure/sign/directions/medical/surgery + name = "\improper Surgery" + icon_state = "direction_surgery" + +/obj/structure/sign/directions/medical/operating_1 + name = "\improper Operating Theatre 1" + icon_state = "direction_op1" + +/obj/structure/sign/directions/medical/operating_2 + name = "\improper Operating Theatre 2" + icon_state = "direction_op2" + +/obj/structure/sign/directions/medical/cloning + name = "\improper Cloning" + icon_state = "direction_cloning" + +/obj/structure/sign/directions/medical/resleeve + name = "\improper Resleeving" + icon_state = "direction_resleeve" + +/obj/structure/sign/directions/medical/chemlab + name = "\improper Chemistry Laboratory" + icon_state = "direction_chemlab" + +/obj/structure/sign/directions/evac + name = "\improper Evacuation Wing" + icon_state = "direction_evac" + +/obj/structure/sign/directions/bridge + name = "\improper Bridge" + icon_state = "direction_bridge" + +/obj/structure/sign/directions/infirmary + name = "\improper Infirmary" + icon_state = "direction_infirm" + +/obj/structure/sign/directions/pods + name = "\improper Escape Pods" + icon_state = "direction_pods" + +/obj/structure/sign/directions/cryo + name = "\improper Cryogenic Storage" + icon_state = "direction_cryo" + +/obj/structure/sign/directions/elevator + name = "\improper Elevator" + icon_state = "direction_elv" + +/obj/structure/sign/directions/command + name = "\improper Command" + icon_state = "direction_command" + +/obj/structure/sign/directions/dorms + name = "\improper Dormitories" + icon_state = "direction_dorms" + +/obj/structure/sign/directions/teleporter + name = "\improper Teleporter" + icon_state = "direction_teleport" + +/obj/structure/sign/directions/roomnum + name = "\improper Private Room" + icon_state = "direction_roomnum" // TODO: move this to signs.dmi or something. + +/obj/structure/sign/directions/recreation + name = "\improper Recreation" + icon_state = "direction_recreation" + +/obj/structure/sign/directions/pool + name = "\improper Pool" + icon_state = "direction_pool" + +/obj/structure/sign/directions/janitor + name = "\improper Custodial Office" + icon_state = "direction_janitor" + +/obj/structure/sign/directions/eva + name = "\improper EVA" + icon_state = "direction_eva" + +/obj/structure/sign/directions/bar + name = "\improper Bar" + icon_state = "direction_bar" + +/obj/structure/sign/directions/ai_core + name = "\improper AI Core" + icon_state = "direction_ai_core" + +/obj/structure/sign/directions/gravity + name = "\improper Gravity Management" + icon_state = "direction_grav" + +/obj/structure/sign/directions/telecomms + name = "\improper Telecommunications" + icon_state = "direction_tcomms" + +/obj/structure/sign/directions/kitchen + name = "\improper Kitchen" + icon_state = "direction_kitchen" + +/obj/structure/sign/directions/tram + name = "\improper Transit" + icon_state = "direction_tram" + +/obj/structure/sign/directions/chapel + name = "\improper Chapel" + icon_state = "direction_chapel" + +/obj/structure/sign/directions/library + name = "\improper Library" + icon_state = "direction_library" + +/obj/structure/sign/directions/dock + name = "\improper Dock" + icon_state = "direction_dock" + +/obj/structure/sign/directions/gym + name = "\improper Gymnasium" + icon_state = "direction_gym" + +/obj/structure/sign/directions/exit + name = "\improper Emergency Exit" + icon_state = "exit_sign" + +/obj/structure/sign/directions/stairs + name = "\improper Stairwell" + icon_state = "stairwell" + +/obj/structure/sign/directions/stairs/up + icon_state = "stairs_up" + +/obj/structure/sign/directions/stairs/down + icon_state = "stairs_down" + +/obj/structure/sign/directions/ladder + name = "\improper Ladder" + icon_state = "ladderwell" + +/obj/structure/sign/directions/ladder/up + icon_state = "ladder_up" + +/obj/structure/sign/directions/ladder/down + icon_state = "ladder_down" diff --git a/code/game/objects/structures/signs/flags.dm b/code/game/objects/structures/signs/flags.dm new file mode 100644 index 000000000000..8fce965bc1aa --- /dev/null +++ b/code/game/objects/structures/signs/flags.dm @@ -0,0 +1,27 @@ +/obj/structure/sign/double/flag + name = "flag" + desc = "A plain flag." + icon = 'icons/obj/signs/flags.dmi' + icon_state = "flag" +/obj/structure/sign/double/flag/left + icon_state = "flag_l" +/obj/structure/sign/double/flag/right + icon_state = "flag_r" + +/obj/structure/sign/double/flag/pirate + name = "pirate flag" + desc = "Yarr harr, fiddle de dee!" + icon_state = "pirate" +/obj/structure/sign/double/flag/pirate/left + icon_state = "pirate_l" +/obj/structure/sign/double/flag/pirate/right + icon_state = "pirate_r" + +/obj/structure/sign/double/flag/catpirate + name = "cat pirate flag" + desc = "Nyarr harr, fiddle de dee!" + icon_state = "catpirate" +/obj/structure/sign/double/flag/catpirate/left + icon_state = "catpirate_l" +/obj/structure/sign/double/flag/catpirate/right + icon_state = "catpirate_r" diff --git a/code/game/objects/structures/signs/hangar.dm b/code/game/objects/structures/signs/hangar.dm new file mode 100644 index 000000000000..0ad300afe060 --- /dev/null +++ b/code/game/objects/structures/signs/hangar.dm @@ -0,0 +1,20 @@ +///////////////////////////////////////////////////// +// Hangar Signs +///////////////////////////////////////////////////// +/obj/structure/sign/hangar + abstract_type = /obj/structure/sign/hangar + name = "hangar sign" + desc = "A sign indicating which hangar the observer is near." + icon = 'icons/obj/signs/hangars.dmi' + +/obj/structure/sign/hangar/one + name = "\improper Hangar One" + icon_state = "hangar-1" + +/obj/structure/sign/hangar/two + name = "\improper Hangar Two" + icon_state = "hangar-2" + +/obj/structure/sign/hangar/three + name = "\improper Hangar Three" + icon_state = "hangar-3" diff --git a/code/game/objects/structures/signs/levels.dm b/code/game/objects/structures/signs/levels.dm new file mode 100644 index 000000000000..214b43bc6508 --- /dev/null +++ b/code/game/objects/structures/signs/levels.dm @@ -0,0 +1,232 @@ +/obj/structure/sign/levels + icon = 'icons/obj/signs/levels.dmi' + icon_state = "level" + //Level signs are always meant to face south! The arrow on the sign matches the direction it points to. + directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":32}, "WEST":{"y":32}, "EAST":{"y":32}}' + +/obj/structure/sign/levels/update_description() + desc = "A sign indicating your position within \the [name]." + +/obj/structure/sign/levels/engineering + name = "\improper Engineering" + icon_state = "level_eng" + +/obj/structure/sign/levels/engineering/core + name = "\improper Reactor Core" + icon_state = "level_core" + +/obj/structure/sign/levels/engineering/solar + name = "\improper Solar Array" + icon_state = "level_solar" + +/obj/structure/sign/levels/engineering/atmos + name = "\improper Atmospherics" + icon_state = "level_atmos" + +/obj/structure/sign/levels/engineering/gravity + name = "\improper Gravity Control" + icon_state = "level_grav" + +/obj/structure/sign/levels/engineering/equipment + name = "\improper Engineering Equipment" + icon_state = "level_engeqp" + +/obj/structure/sign/levels/medical + name = "\improper Medical" + icon_state = "level_med" + +/obj/structure/sign/levels/medical/virology + name = "\improper Virology" + icon_state = "level_viro" + +/obj/structure/sign/levels/medical/morgue + name = "\improper Morgue" + icon_state = "level_morgue" + +/obj/structure/sign/levels/medical/surgery + name = "\improper Surgery" + icon_state = "level_surgery" + +/obj/structure/sign/levels/medical/cloning + name = "\improper Cloning" + icon_state = "level_cloning" + +/obj/structure/sign/levels/medical/resleeve + name = "\improper Resleeving" + icon_state = "level_resleeve" + +/obj/structure/sign/levels/medical/chemlab + name = "\improper Chemistry" + icon_state = "level_chemlab" + +/obj/structure/sign/levels/medical/equipment + name = "\improper Medical Equipment" + icon_state = "level_medeqp" + +/obj/structure/sign/levels/medical/operating_1 + name = "\improper Operating Theatre 1" + icon_state = "level_op1" + +/obj/structure/sign/levels/medical/operating_2 + name = "\improper Operating Theatre 2" + icon_state = "level_op2" + +/obj/structure/sign/levels/security + name = "\improper Security" + icon_state = "level_sec" + +/obj/structure/sign/levels/security/seceqp + name = "\improper Security Equipment" + icon_state = "level_seceqp" + +/obj/structure/sign/levels/security/interrogation + name = "\improper Interrogation" + icon_state = "level_interrogation" + +/obj/structure/sign/levels/security/forensics + name = "\improper Forensics" + icon_state = "level_forensics" + +/obj/structure/sign/levels/security/brig + name = "\improper Security Brig" + icon_state = "level_brig" + +/obj/structure/sign/levels/security/armory + name = "\improper Security Armory" + icon_state = "level_armory" + +/obj/structure/sign/levels/security/internalaffairs + name = "\improper Internal Affairs" + icon_state = "level_intaff" + +/obj/structure/sign/levels/cryo + name = "\improper Cryogenics" + icon_state = "level_cry" + +/obj/structure/sign/levels/evac + name = "\improper Evac Wing" + icon_state = "level_evac" + +/obj/structure/sign/levels/eva + name = "\improper EVA" + icon_state = "level_eva" + +/obj/structure/sign/levels/command + name = "\improper Command" + icon_state = "level_command" + +/obj/structure/sign/levels/science + name = "\improper Research Wing" + icon_state = "level_sci" + +/obj/structure/sign/levels/science/xenoflora + name = "\improper Xenoflora" + icon_state = "level_xflora" + +/obj/structure/sign/levels/science/xenobiology + name = "\improper Xenobiology" + icon_state = "level_xbio" + +/obj/structure/sign/levels/science/exploration + name = "\improper Exploration" + icon_state = "level_explo" + +/obj/structure/sign/levels/science/robotics + name = "\improper Robotics" + icon_state = "level_robotics" + +/obj/structure/sign/levels/science/toxins + name = "\improper Toxins" + icon_state = "level_toxins" + +/obj/structure/sign/levels/science/xenoarch + name = "\improper Xenoarchaeology" + icon_state = "level_xenoarch" + +/obj/structure/sign/levels/science/rnd + name = "\improper Research and Development" + icon_state = "level_rnd" + +/obj/structure/sign/levels/dorms + name = "\improper Dormitories" + icon_state = "level_dorms" + +/obj/structure/sign/levels/cargo + name = "\improper Cargo" + icon_state = "level_crg" + +/obj/structure/sign/levels/cargo/mining + name = "\improper Mining" + icon_state = "level_mining" + +/obj/structure/sign/levels/cargo/refinery + name = "\improper Refinery" + icon_state = "level_refinery" + +/obj/structure/sign/levels/recreation + name = "\improper Recreation" + icon_state = "level_recreation" + +/obj/structure/sign/levels/laboratory + name = "\improper Laboratory" + icon_state = "level_lab" + +/obj/structure/sign/levels/xeno + name = "\improper Xenobiology" + icon_state = "level_xeno" + +/obj/structure/sign/levels/ai_core + name = "\improper AI Core" + icon_state = "level_ai_core" + +/obj/structure/sign/levels/bridge + name = "\improper Bridge" + icon_state = "level_bridge" + +/obj/structure/sign/levels/teleporter + name = "\improper Teleporter" + icon_state = "level_teleport" + +/obj/structure/sign/levels/telecomms + name = "\improper Telecommunications" + icon_state = "level_tcomms" + +/obj/structure/sign/levels/elevator + name = "\improper Elevator" + icon_state = "level_elv" + +/obj/structure/sign/levels/bar + name = "\improper Bar" + icon_state = "level_bar" + +/obj/structure/sign/levels/kitchen + name = "\improper Kitchen" + icon_state = "level_kitchen" + +/obj/structure/sign/levels/tram + name = "\improper Tram" + icon_state = "level_tram" + +/obj/structure/sign/levels/janitor + name = "\improper Janitor" + icon_state = "level_janitor" + +/obj/structure/sign/levels/chapel + name = "\improper Chapel" + icon_state = "level_chapel" + +/obj/structure/sign/levels/library + name = "\improper Library" + icon_state = "level_library" + +/obj/structure/sign/levels/dock + name = "\improper Docks" + icon_state = "level_dock" + +/obj/structure/sign/levels/gym + name = "\improper Gymnasium" + icon_state = "level_gym" + +/obj/structure/sign/levels/pool + name = "\improper Pool" + icon_state = "level_pool" diff --git a/code/game/objects/structures/signs/maps.dm b/code/game/objects/structures/signs/maps.dm new file mode 100644 index 000000000000..75221250d39c --- /dev/null +++ b/code/game/objects/structures/signs/maps.dm @@ -0,0 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Map Definitions +/////////////////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/double/map + name = "map" + desc = "A framed map." + icon = 'icons/obj/signs/maps.dmi' + abstract_type = /obj/structure/sign/double/map + +/obj/structure/sign/double/map/left + icon_state = "map-left" +/obj/structure/sign/double/map/right + icon_state = "map-right" + +/obj/structure/sign/double/map/update_description() + var/thename = global.station_name() + SetName("map of \the [thename]") + desc = "A framed map of \the [thename]." diff --git a/code/game/objects/structures/signs/paintings.dm b/code/game/objects/structures/signs/paintings.dm new file mode 100644 index 000000000000..406db69f53f1 --- /dev/null +++ b/code/game/objects/structures/signs/paintings.dm @@ -0,0 +1,15 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Paintings Definitions +/////////////////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/painting + name = "painting" + desc = "A painting." + icon = 'icons/obj/signs/paintings.dmi' + abstract_type = /obj/structure/sign/painting + +///A painting of amonkey +/obj/structure/sign/painting/monkey_painting + name = "\improper Mr. Deempisi portrait" + desc = "Under the painting a plaque reads: 'While the meat grinder may not have spared you, fear not. Not one part of you has gone to waste... You were delicious.'" + icon_state = "monkey_painting" \ No newline at end of file diff --git a/code/game/objects/structures/signs/plaques.dm b/code/game/objects/structures/signs/plaques.dm new file mode 100644 index 000000000000..4a4257437d12 --- /dev/null +++ b/code/game/objects/structures/signs/plaques.dm @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////// +// Plaque +//////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/plaque + name = "commemorative plaque" + desc = "A wall-mounted commemorative plaque." + icon = 'icons/obj/signs/plaques.dmi' + icon_state = "lightplaque" + material = /decl/material/solid/metal/bronze + +//////////////////////////////////////////////////////////////////////// +// Plaques Definitions +//////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/plaque/alternative + icon_state = "lightplaquealt" + +/obj/structure/sign/plaque/dark + icon_state = "darkplaque" + +/obj/structure/sign/plaque/floor + desc = "A floor-mounted commemorative plaque." + icon_state = "floorplaque" + +/obj/structure/sign/plaque/golden + name = "The Most Robust Men Award for Robustness" + desc = "To be Robust is not an action or a way of life, but a mental state. Only those with the force of Will strong enough to act during a crisis, saving friend from foe, are truly Robust. Stay Robust my friends." + icon_state = "goldenplaque" + material = /decl/material/solid/metal/gold + +/obj/structure/sign/plaque/golden/security + name = "motivational plaque" + desc = "A plaque engraved with a generic motivational quote and picture. ' Greater love hath no man than this, that a man lay down his life for his friends. John 15:13 " + +/obj/structure/sign/plaque/golden/medical + name = "medical certificate" + desc = "A picture next to a long-winded description of medical certifications and degrees." + +/obj/structure/sign/plaque/ai_dev + name = "\improper AI developers plaque" + desc = "An extremely long list of names and job titles and a picture of the design team responsible for building this AI Core." + icon_state = "kiddieplaque" + +/obj/structure/sign/plaque/atmos + name = "\improper engineering memorial plaque" + desc = "This plaque memorializes those engineers and technicians who made the ultimate sacrifice to save their vessel and its crew." + icon_state = "atmosplaque" + +//////////////////////////////////////////////////////////////////////// +// Plaque Items Templates +//////////////////////////////////////////////////////////////////////// + +/obj/item/sign/plaque + name = "commemorative plaque" + desc = "A wall-mountable commemorative plaque and some mounting screws." + icon = 'icons/obj/signs/plaques.dmi' + icon_state = "lightplaque" + material = /decl/material/solid/metal/bronze + sign_type = /obj/structure/sign/plaque + +/obj/item/sign/plaque/alternative + icon_state = "lightplaquealt" + sign_type = /obj/structure/sign/plaque/alternative + +/obj/item/sign/plaque/dark + icon_state = "darkplaque" + sign_type = /obj/structure/sign/plaque/dark + +/obj/item/sign/plaque/golden + name = "The Most Robust Men Award for Robustness" + icon_state = "goldenplaque" + sign_type = /obj/structure/sign/plaque/golden + +/obj/item/sign/plaque/golden/security + name = "motivational plaque" + sign_type = /obj/structure/sign/plaque/golden/security + +/obj/item/sign/plaque/golden/medical + name = "medical certificate" + sign_type = /obj/structure/sign/plaque/golden/medical + +/obj/item/sign/plaque/ai_dev + name = "\improper AI developers plaque" + icon_state = "kiddieplaque" + sign_type = /obj/structure/sign/plaque/ai_dev + +/obj/item/sign/plaque/atmos + name = "\improper engineering memorial plaque" + icon_state = "atmosplaque" + sign_type = /obj/structure/sign/plaque/atmos diff --git a/code/game/objects/structures/signs/warning_signs.dm b/code/game/objects/structures/signs/warning_signs.dm new file mode 100644 index 000000000000..2bcb946dec88 --- /dev/null +++ b/code/game/objects/structures/signs/warning_signs.dm @@ -0,0 +1,249 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Warning Sign Definitions +/////////////////////////////////////////////////////////////////////////////////// + +///Base warning sign type +/obj/structure/sign/warning + name = "\improper WARNING" + desc = "You've been warned!" + icon = 'icons/obj/signs/warnings.dmi' + icon_state = "securearea" + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "WEST":{"x":34}, "EAST":{"x":-34}}' + +/obj/structure/sign/warning/update_description() + desc = "A warning sign which reads '[sanitize(name)]'." + +/////////////////////////////////////////////////////////////////////////////////// +// Sign Definitions +/////////////////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/warning/detailed + icon_state = "securearea2" + +/obj/structure/sign/warning/caution + name = "\improper CAUTION" + icon_state = "caution" + +/obj/structure/sign/warning/airlock + name = "\improper EXTERNAL AIRLOCK" + icon_state = "doors" + +/obj/structure/sign/warning/airlock/large + icon_state = "doors-large" + +/obj/structure/sign/warning/pods + name = "\improper WARNING: ESCAPE POD DOCKING AREA" + icon_state = "pods" + +/obj/structure/sign/warning/deathsposal + name = "\improper DISPOSAL LEADS TO SPACE" + icon_state = "deathsposal" + +/obj/structure/sign/warning/shock + name = "\improper HIGH VOLTAGE" + icon_state = "shock" + +/obj/structure/sign/warning/compressed_gas + name = "\improper COMPRESSED GAS" + icon_state = "hikpa" + +/obj/structure/sign/warning/compressed_gas/large + icon_state = "hikpa-large" + +/obj/structure/sign/warning/docking_area + name = "\improper KEEP CLEAR: DOCKING AREA" + +/obj/structure/sign/warning/engineering_access + name = "\improper ENGINEERING ACCESS" + +/obj/structure/sign/warning/moving_parts + name = "\improper MOVING PARTS" + icon_state = "movingparts" + +/obj/structure/sign/warning/moving_parts/large + icon_state = "movingparts-large" + +/obj/structure/sign/warning/nosmoking_1 + name = "\improper NO SMOKING" + icon_state = "nosmoking" + +/obj/structure/sign/warning/nosmoking_1/large + icon_state = "nosmoking-large" + +/obj/structure/sign/warning/nosmoking_2 + name = "\improper NO SMOKING" + icon_state = "nosmoking2" + +/obj/structure/sign/warning/nosmoking_burned + name = "\improper NO SMOKING" + icon_state = "nosmoking2_b" + +/obj/structure/sign/warning/nosmoking_burned/update_description() + . = ..() + desc += " It looks charred." + +/obj/structure/sign/warning/smoking + name = "\improper SMOKING" + icon_state = "smoking" + +/obj/structure/sign/warning/smoking/update_description() + . = ..() + desc += " Hell yeah." + +/obj/structure/sign/warning/smoking/large + icon_state = "smoking-large" + +/obj/structure/sign/warning/secure_area + name = "\improper SECURE AREA" + icon_state = "securearea2" + +/obj/structure/sign/warning/secure_area/large + icon_state = "securearea2-large" + +/obj/structure/sign/warning/large + icon_state = "securearea-large" + +/obj/structure/sign/warning/armory + name = "\improper ARMORY" + icon_state = "armory" + +/obj/structure/sign/warning/armory/large + icon_state = "armory-large" + +/obj/structure/sign/warning/server_room + name = "\improper SERVER ROOM" + icon_state = "server" + +/obj/structure/sign/warning/server_room/large + icon_state = "server-large" + +/////////////////////////////////////////////////////////////////////////////////// +// Hazard Sign Definitions +/////////////////////////////////////////////////////////////////////////////////// + +/obj/structure/sign/warning/biohazard + name = "\improper BIOHAZARD" + icon_state = "bio" + +/obj/structure/sign/warning/radioactive + name = "\improper RADIOACTIVE AREA" + icon_state = "radiation" + +/obj/structure/sign/warning/radioactive/large + icon_state = "radiation-large" + +/obj/structure/sign/warning/radioactive/alt + name = "\improper IONIZING RADIATION" + icon_state = "radiation_2" + +/obj/structure/sign/warning/fire + name = "\improper DANGER: FIRE" + icon_state = "fire" + +/obj/structure/sign/warning/fire/large + icon_state = "fire-large" + +/obj/structure/sign/warning/high_voltage + name = "\improper HIGH VOLTAGE" + icon_state = "shock" + +/obj/structure/sign/warning/high_voltage/large + icon_state = "shock-large" + +/obj/structure/sign/warning/hot_exhaust + name = "\improper HOT EXHAUST" + icon_state = "fire" + +/obj/structure/sign/warning/laser + name = "\improper LASER HAZARD" + icon_state = "beam" + +/obj/structure/sign/warning/internals_required + name = "\improper INTERNALS REQUIRED" + +/obj/structure/sign/warning/bomb_range + name = "\improper BOMB RANGE" + icon_state = "blast" + +/obj/structure/sign/warning/fall + name = "\improper FALL HAZARD" + icon_state = "falling" + +/obj/structure/sign/warning/lethal_turrets + name = "\improper LETHAL TURRETS" + icon_state = "turrets" + +/obj/structure/sign/warning/lethal_turrets/update_description() + . = ..() + desc += " Enter at own risk!" + +/obj/structure/sign/warning/siphon_valve + name = "\improper SIPHON VALVE" + +/obj/structure/sign/warning/vacuum + name = "\improper HARD VACUUM AHEAD" + icon_state = "space" + +/obj/structure/sign/warning/vacuum/large + icon_state = "space-large" + +/obj/structure/sign/warning/vent_port + name = "\improper EJECTION/VENTING PORT" + +/obj/structure/sign/warning/anomalous_materials + name = "\improper ANOMALOUS MATERIALS" + +/obj/structure/sign/warning/mass_spectrometry + name = "\improper MASS SPECTROMETRY" + +/obj/structure/sign/warning/acid + name = "\improper WARNING: CORROSIVE MATERIALS" + icon_state = "acid" + +/obj/structure/sign/warning/cold + name = "\improper WARNING: LOW TEMPERATURES" + icon_state = "cold" + +/obj/structure/sign/warning/lava + name = "\improper WARNING: MOLTEN ROCK" + icon_state = "lava" + +/obj/structure/sign/warning/malfunction + name = "\improper IN CASE OF MALFUNCTION" + icon_state = "rogueai" + +/obj/structure/sign/warning/explosives + name = "\improper WARNING: HIGH EXPLOSIVES" + icon_state = "explosives" + +/obj/structure/sign/warning/chemicals + name = "\improper WARNING: RISK OF CHEMICAL EXPOSURE" + icon_state = "chemdiamond" + +/obj/structure/sign/warning/atmos_co2 + name = "\improper WARNING: CO2" + icon_state = "atmos_co2" + +/obj/structure/sign/warning/atmos_n2o + name = "\improper WARNING: N2O" + icon_state = "atmos_n2o" + +/obj/structure/sign/warning/atmos_phoron + name = "\improper WARNING: EXOTIC MATTER" + icon_state = "atmos_phoron" + +/obj/structure/sign/warning/atmos_o2 + name = "\improper WARNING: O2" + icon_state = "atmos_o2" + +/obj/structure/sign/warning/atmos_air + name = "\improper WARNING: PRESSURIZED AIR" + icon_state = "atmos_air" + +/obj/structure/sign/warning/atmos_n2 + name = "\improper WARNING: N2" + icon_state = "atmos_n2" + +/obj/structure/sign/warning/atmos_waste + name = "\improper WARNING: WASTE UNDER PRESSURE" + icon_state = "atmos_waste" diff --git a/code/game/objects/structures/skele_stand.dm b/code/game/objects/structures/skele_stand.dm index 88f1aae6464a..58ac90d99e01 100644 --- a/code/game/objects/structures/skele_stand.dm +++ b/code/game/objects/structures/skele_stand.dm @@ -1,6 +1,6 @@ /obj/structure/skele_stand name = "hanging skeleton model" - density = 1 + density = TRUE icon = 'icons/obj/surgery.dmi' icon_state = "hangskele" desc = "It's an anatomical model of a human skeletal system made of plaster." @@ -9,68 +9,74 @@ /obj/structure/skele_stand/Initialize() . = ..() - gender = pick(MALE, FEMALE) + set_gender(pick(MALE, FEMALE, PLURAL)) /obj/structure/skele_stand/proc/rattle_bones(mob/user, atom/thingy) if((world.time - cooldown) <= 1 SECOND) return //reduces spam. + + var/decl/pronouns/pronouns = get_pronouns() if(user) - visible_message("\The [user] pushes on [src][thingy?" with \the [thingy]":""], giving the bones a good rattle.") + if(thingy) + visible_message(SPAN_NOTICE("\The [user] pushes \the [src] with \the [thingy], giving the bones a good rattle.")) + else + visible_message(SPAN_NOTICE("\The [user] pushes \the [src], giving the bones a good rattle.")) else - visible_message("\The [src] rattles on \his stand upon hitting [thingy?"\the [thingy]":"something"].") + if(thingy) + visible_message(SPAN_NOTICE("\The [src] rattles on [pronouns.his] stand as [pronouns.he] [pronouns.is] hit by \the [thingy].")) + else + visible_message(SPAN_NOTICE("\The [src] rattles on [pronouns.his] stand.")) + cooldown = world.time playsound(loc, 'sound/effects/bonerattle.ogg', 40) /obj/structure/skele_stand/attack_hand(mob/user) - if(swag.len) - var/obj/item/clothing/C = input("What piece of clothing do you want to remove?", "Skeleton undressing") as null|anything in list_values(swag) + if(length(swag) && user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + var/obj/item/clothing/C = input("What piece of clothing do you want to remove?", "Skeleton Undressing") as null|anything in list_values(swag) if(C) swag -= get_key_by_value(swag, C) user.put_in_hands(C) - to_chat(user,"You take \the [C] off \the [src]") + to_chat(user, SPAN_NOTICE("You take \the [C] off \the [src].")) update_icon() - else + return TRUE + if(user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) rattle_bones(user, null) + return TRUE + return ..() /obj/structure/skele_stand/Bumped(atom/thing) rattle_bones(null, thing) -/obj/structure/skele_stand/examine(mob/user) +/obj/structure/skele_stand/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(swag.len) var/list/swagnames = list() for(var/slot in swag) var/obj/item/clothing/C = swag[slot] swagnames += C.get_examine_line() - to_chat(user,"[gender == MALE ? "He" : "She"] is wearing [english_list(swagnames)].") + var/decl/pronouns/stand_pronouns = get_pronouns() + . += "[stand_pronouns.He] [stand_pronouns.is] wearing [english_list(swagnames)]." -/obj/structure/skele_stand/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/pen)) +/obj/structure/skele_stand/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) var/nuname = sanitize(input(user,"What do you want to name this skeleton as?","Skeleton Christening",name) as text|null) if(nuname && CanPhysicallyInteract(user)) SetName(nuname) - return 1 - if(istype(W,/obj/item/clothing)) - var/slot - if(istype(W, /obj/item/clothing/under)) - slot = slot_w_uniform_str - else if(istype(W, /obj/item/clothing/suit)) - slot = slot_wear_suit_str - else if(istype(W, /obj/item/clothing/head)) - slot = slot_head_str - else if(istype(W, /obj/item/clothing/shoes)) - slot = slot_shoes_str - else if(istype(W, /obj/item/clothing/mask)) - slot = slot_wear_mask_str - if(slot) - if(swag[slot]) - to_chat(user,"There is already that kind of clothing on \the [src].") - else if(user.unEquip(W, src)) - swag[slot] = W - update_icon() - return 1 - else - rattle_bones(user, W) + return TRUE + if(istype(used_item,/obj/item/clothing)) + var/obj/item/clothing/clothes = used_item + if(!clothes.fallback_slot) + return FALSE + if(swag[clothes.fallback_slot]) + to_chat(user,SPAN_NOTICE("There is already that kind of clothing on \the [src].")) + else if(user.try_unequip(used_item, src)) + swag[clothes.fallback_slot] = used_item + update_icon() + return TRUE + . = ..() + if(!.) + rattle_bones(user, used_item) + return TRUE /obj/structure/skele_stand/Destroy() for(var/slot in swag) @@ -79,7 +85,8 @@ . = ..() /obj/structure/skele_stand/on_update_icon() - overlays.Cut() + ..() for(var/slot in swag) var/obj/item/I = swag[slot] - overlays += I.get_mob_overlay(null, slot) \ No newline at end of file + if(I) + add_overlay(I.get_mob_overlay(null, slot)) \ No newline at end of file diff --git a/code/game/objects/structures/snowman.dm b/code/game/objects/structures/snowman.dm new file mode 100644 index 000000000000..60382df695cc --- /dev/null +++ b/code/game/objects/structures/snowman.dm @@ -0,0 +1,59 @@ +/obj/structure/snowman + name = "man" + icon = 'icons/obj/structures/snowmen/snowman.dmi' + icon_state = ICON_STATE_WORLD + desc = "A happy little $NAME$ smiles back at you!" + anchored = TRUE + material = /decl/material/solid/ice/snow + material_alteration = MAT_FLAG_ALTERATION_ALL // We override name and desc below. + +/obj/structure/snowman/Initialize(ml, _mat, _reinf_mat) + . = ..() + update_icon() + +/obj/structure/snowman/update_material_name(override_name) + SHOULD_CALL_PARENT(FALSE) + if(istype(material)) + SetName("[material.solid_name][initial(name)]") + else + SetName("mystery[initial(name)]") + +/obj/structure/snowman/update_material_desc(override_desc) + SHOULD_CALL_PARENT(FALSE) + if(istype(material)) + var/snowname = "[material.solid_name][initial(name)]" + desc = replacetext(initial(desc), "$NAME$", snowname) + else + desc = replacetext(initial(desc), "$NAME$", "mysteryman") + +/obj/structure/snowman/on_update_icon() + . = ..() + // TODO: make carrot/stick arms/coal require items? + add_overlay(overlay_image(icon, "[icon_state]-decorations", COLOR_WHITE, RESET_COLOR)) + compile_overlays() + +/obj/structure/snowman/proc/user_destroyed(user) + to_chat(user, SPAN_DANGER("\The [src] crumples into a pile of [material.solid_name] after a single solid hit. You monster.")) + physically_destroyed() + +/obj/structure/snowman/attackby(obj/item/used_item, mob/user) + if(user.check_intent(I_FLAG_HARM) && used_item.get_base_attack_force()) + user_destroyed(user) + return TRUE + return ..() + +/obj/structure/snowman/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HARM)) + user_destroyed(user) + return TRUE + return ..() + +/obj/structure/snowman/bot + name = "bot" + icon = 'icons/obj/structures/snowmen/snowbot.dmi' + desc = "A bland-faced little $NAME$. It even has a monitor for a head." + +/obj/structure/snowman/spider + name = "spider" + icon = 'icons/obj/structures/snowmen/snowspider.dmi' + desc = "An impressively-crafted $NAME$. Not nearly as creepy as the real thing." \ No newline at end of file diff --git a/code/game/objects/structures/sofa.dm b/code/game/objects/structures/sofa.dm new file mode 100644 index 000000000000..b12b1148f3a1 --- /dev/null +++ b/code/game/objects/structures/sofa.dm @@ -0,0 +1,138 @@ +/obj/structure/bed/sofa + name = "sofa" + desc = "A wide and comfy sofa - no assistants were harmed to produce it!" + icon = 'icons/obj/structures/furniture/sofa_middle.dmi' + color = "#666666" + buckle_dir = FALSE + buckle_lying = FALSE //force people to sit up in chairs when buckled + obj_flags = OBJ_FLAG_ROTATABLE | OBJ_FLAG_ANCHORABLE + material = /decl/material/solid/organic/wood/oak + initial_padding_material = /decl/material/solid/organic/cloth + material_alteration = MAT_FLAG_ALTERATION_ALL + + var/has_special_overlay = FALSE + +/obj/structure/bed/sofa/do_simple_ranged_interaction(var/mob/user) + if(!buckled_mob && user) + rotate(user) + return TRUE + +/obj/structure/bed/sofa/post_buckle_mob() + update_icon() + return ..() + +/obj/structure/bed/sofa/on_update_icon() + ..() + var/use_base_color = get_color() + var/datum/extension/padding/padding_extension = get_extension(src, __IMPLIED_TYPE__) + var/use_padding_color = padding_extension?.get_padding_color(material_alteration & MAT_FLAG_ALTERATION_COLOR) + + var/list/overlays_to_add = list( + "_over" = use_base_color, + "_armrest" = use_base_color + ) + if(padding_extension?.get_padding_material()) + overlays_to_add["_padding_over"] = use_padding_color + overlays_to_add["_padding_armrest"] = use_padding_color + if(has_special_overlay && buckled_mob) + overlays_to_add["_special"] = use_base_color + + for(var/overlay in overlays_to_add) + var/overlay_state = "[icon_state][overlay]" + if(check_state_in_icon(overlay_state, icon)) + var/overlay_color = overlays_to_add[overlay] + var/image/I + if(isnull(overlay_color)) + I = overlay_image(icon, overlay_state) + else + I = overlay_image(icon, overlay_state, overlay_color, RESET_COLOR) + I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER + add_overlay(I) + +/obj/structure/bed/sofa/rotate(mob/user) + if(!CanPhysicallyInteract(user) || anchored) + to_chat(user, SPAN_NOTICE("You can't interact with \the [src] right now!")) + return + set_dir(turn(dir, 90)) + update_icon() + +/obj/structure/bed/sofa/middle/rotate(mob/user) + if(!CanPhysicallyInteract(user) || anchored) + to_chat(user, SPAN_NOTICE("You can't interact with \the [src] right now!")) + return + set_dir(turn(dir, 45)) + update_icon() +/obj/structure/bed/sofa/middle/unpadded + initial_padding_material = null + +/obj/structure/bed/sofa/middle/red + initial_padding_color = "#9d2300" +/obj/structure/bed/sofa/middle/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/bed/sofa/middle/teal + initial_padding_color = "#00e1ff" +/obj/structure/bed/sofa/middle/black + initial_padding_color = "#505050" +/obj/structure/bed/sofa/middle/green + initial_padding_color = "#b7f27d" +/obj/structure/bed/sofa/middle/purple + initial_padding_color = "#9933ff" +/obj/structure/bed/sofa/middle/blue + initial_padding_color = "#46698c" +/obj/structure/bed/sofa/middle/beige + initial_padding_color = "#ceb689" +/obj/structure/bed/sofa/middle/lime + initial_padding_color = "#62e36c" +/obj/structure/bed/sofa/middle/yellow + paint_color = "#ffbf00" + +/obj/structure/bed/sofa/right + icon = 'icons/obj/structures/furniture/sofa_right.dmi' +/obj/structure/bed/sofa/right/unpadded + initial_padding_material = null +/obj/structure/bed/sofa/right/red + initial_padding_color = "#9d2300" +/obj/structure/bed/sofa/right/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/bed/sofa/right/teal + initial_padding_color = "#00e1ff" +/obj/structure/bed/sofa/right/black + initial_padding_color = "#505050" +/obj/structure/bed/sofa/right/green + initial_padding_color = "#b7f27d" +/obj/structure/bed/sofa/right/purple + initial_padding_color = "#9933ff" +/obj/structure/bed/sofa/right/blue + initial_padding_color = "#46698c" +/obj/structure/bed/sofa/right/beige + initial_padding_color = "#ceb689" +/obj/structure/bed/sofa/right/lime + initial_padding_color = "#62e36c" +/obj/structure/bed/sofa/right/yellow + initial_padding_color = "#ffbf00" + +/obj/structure/bed/sofa/left + name = "sofa" + icon = 'icons/obj/structures/furniture/sofa_left.dmi' +/obj/structure/bed/sofa/left/unpadded + initial_padding_material = null +/obj/structure/bed/sofa/left/red + initial_padding_color = "#9d2300" +/obj/structure/bed/sofa/left/brown + initial_padding_material = /decl/material/solid/organic/leather +/obj/structure/bed/sofa/left/teal + initial_padding_color = "#00e1ff" +/obj/structure/bed/sofa/left/black + initial_padding_color = "#505050" +/obj/structure/bed/sofa/left/green + initial_padding_color = "#b7f27d" +/obj/structure/bed/sofa/left/purple + initial_padding_color = "#9933ff" +/obj/structure/bed/sofa/left/blue + initial_padding_color = "#46698c" +/obj/structure/bed/sofa/left/beige + initial_padding_color = "#ceb689" +/obj/structure/bed/sofa/left/lime + initial_padding_color = "#62e36c" +/obj/structure/bed/sofa/left/yellow + initial_padding_color = "#ffbf00" \ No newline at end of file diff --git a/code/game/objects/structures/stasis_cage.dm b/code/game/objects/structures/stasis_cage.dm deleted file mode 100644 index cfed3af0e1a3..000000000000 --- a/code/game/objects/structures/stasis_cage.dm +++ /dev/null @@ -1,80 +0,0 @@ -/obj/structure/stasis_cage - name = "stasis cage" - desc = "A high-tech animal cage, designed to keep contained fauna docile and safe." - icon = 'icons/obj/stasis_cage.dmi' - icon_state = "stasis_cage" - density = 1 - layer = ABOVE_OBJ_LAYER - - var/mob/living/simple_animal/contained - -/obj/structure/stasis_cage/Initialize() - . = ..() - - var/mob/living/simple_animal/A = locate() in loc - if(A) - contain(A) - -/obj/structure/stasis_cage/attack_hand(var/mob/user) - try_release(user) - -/obj/structure/stasis_cage/attack_robot(var/mob/user) - if(Adjacent(user)) - try_release(user) - -/obj/structure/stasis_cage/proc/try_release(mob/user) - if(!contained) - to_chat(user, SPAN_NOTICE("There's no animals inside \the [src]")) - return - user.visible_message("[user] begins undoing the locks and latches on \the [src].") - if(do_after(user, 20, src)) - user.visible_message("[user] releases \the [contained] from \the [src]!") - release() - -/obj/structure/stasis_cage/on_update_icon() - if(contained) - icon_state = "[initial(icon_state)]_on" - else - icon_state = initial(icon_state) - -/obj/structure/stasis_cage/examine(mob/user) - . = ..() - if(contained) - to_chat(user, "\The [contained] is kept inside.") - -/obj/structure/stasis_cage/proc/contain(var/mob/living/simple_animal/animal) - if(contained || !istype(animal)) - return - - contained = animal - animal.forceMove(src) - animal.in_stasis = 1 - update_icon() - -/obj/structure/stasis_cage/proc/release() - if(!contained) - return - - contained.dropInto(src) - contained.in_stasis = 0 - contained = null - update_icon() - -/obj/structure/stasis_cage/Destroy() - release() - return ..() - -/mob/living/simple_animal/MouseDrop(var/obj/structure/stasis_cage/over_object) - if(istype(over_object) && Adjacent(over_object) && CanMouseDrop(over_object, usr)) - - if(!stat && !istype(src.buckled, /obj/effect/energy_net)) - to_chat(usr, "It's going to be difficult to convince \the [src] to move into \the [over_object] without capturing it in a net.") - return - - usr.visible_message("[usr] begins stuffing \the [src] into \the [over_object].", "You begin stuffing \the [src] into \the [over_object].") - Bumped(usr) - if(do_after(usr, 20, over_object)) - usr.visible_message("[usr] has stuffed \the [src] into \the [over_object].", "You have stuffed \the [src] into \the [over_object].") - over_object.contain(src) - else - return ..() \ No newline at end of file diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm deleted file mode 100644 index c62c4711ede7..000000000000 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ /dev/null @@ -1,302 +0,0 @@ -/* Beds... get your mind out of the gutter, they're for sleeping! - * Contains: - * Beds - * Roller beds - * Mattresses - */ - -/* - * Beds - */ -/obj/structure/bed - name = "bed" - desc = "This is used to lie in, sleep in or strap on." - icon = 'icons/obj/furniture.dmi' - icon_state = "bed" - anchored = 1 - can_buckle = 1 - buckle_dir = SOUTH - buckle_lying = 1 - material = DEFAULT_FURNITURE_MATERIAL - material_alteration = MAT_FLAG_ALTERATION_ALL - tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT - var/buckling_sound = 'sound/effects/buckle.ogg' - -/obj/structure/bed/update_material_name() - if(reinf_material) - SetName("[reinf_material.adjective_name] [initial(name)]") - else if(material) - SetName("[material.adjective_name] [initial(name)]") - else - SetName(initial(name)) - -/obj/structure/bed/update_material_desc() - if(reinf_material) - desc = "[initial(desc)] It's made of [material.use_name] and covered with [reinf_material.use_name]." - else - desc = "[initial(desc)] It's made of [material.use_name]." - -// Reuse the cache/code from stools, todo maybe unify. -/obj/structure/bed/on_update_icon() - ..() - var/new_overlays - if(istype(reinf_material)) - var/image/I = image(icon, "[icon_state]_padding") - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = reinf_material.color - LAZYADD(new_overlays, I) - overlays = new_overlays - -/obj/structure/bed/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) - return 1 - else - return ..() - -/obj/structure/bed/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) - -/obj/structure/bed/attackby(obj/item/W, mob/user) - . = ..() - if(!.) - if(istype(W,/obj/item/stack)) - if(reinf_material) - to_chat(user, "\The [src] is already padded.") - return - var/obj/item/stack/C = W - if(C.get_amount() < 1) // How?? - qdel(C) - return - var/padding_type //This is awful but it needs to be like this until tiles are given a material var. - if(istype(W,/obj/item/stack/tile/carpet)) - padding_type = /decl/material/solid/carpet - else if(istype(W,/obj/item/stack/material)) - var/obj/item/stack/material/M = W - if(M.material && (M.material.flags & MAT_FLAG_PADDING)) - padding_type = "[M.material.type]" - if(!padding_type) - to_chat(user, "You cannot pad \the [src] with that.") - return - C.use(1) - if(!istype(src.loc, /turf)) - src.forceMove(get_turf(src)) - to_chat(user, "You add padding to \the [src].") - add_padding(padding_type) - return - - else if(isWirecutter(W)) - if(!reinf_material) - to_chat(user, "\The [src] has no padding to remove.") - return - to_chat(user, "You remove the padding from \the [src].") - playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) - remove_padding() - - else if(istype(W, /obj/item/grab)) - var/obj/item/grab/G = W - var/mob/living/affecting = G.get_affecting_mob() - if(affecting) - user.visible_message("[user] attempts to buckle [affecting] into \the [src]!") - if(do_after(user, 20, src)) - if(user_buckle_mob(affecting, user)) - qdel(W) - -/obj/structure/bed/buckle_mob(mob/living/M) - . = ..() - if(. && buckling_sound) - playsound(src, buckling_sound, 20) - -/obj/structure/bed/Move() - . = ..() - if(buckled_mob) - buckled_mob.forceMove(src.loc) - -/obj/structure/bed/forceMove() - . = ..() - if(buckled_mob) - if(isturf(src.loc)) - buckled_mob.forceMove(src.loc) - else - unbuckle_mob() - -/obj/structure/bed/proc/remove_padding() - if(reinf_material) - reinf_material.place_sheet(get_turf(src)) - reinf_material = null - update_icon() - -/obj/structure/bed/proc/add_padding(var/padding_type) - reinf_material = decls_repository.get_decl(padding_type) - update_icon() - -/obj/structure/bed/psych - name = "psychiatrist's couch" - desc = "For prime comfort during psychiatric evaluations." - icon_state = "psychbed" - -/obj/structure/bed/psych - material = /decl/material/solid/wood/walnut - reinf_material = /decl/material/solid/leather - -/obj/structure/bed/padded - material = /decl/material/solid/metal/aluminium - reinf_material = /decl/material/solid/cloth - -/* - * Roller beds - */ -/obj/structure/bed/roller - name = "roller bed" - icon = 'icons/obj/structures/rollerbed.dmi' - icon_state = "down" - anchored = 0 - buckle_pixel_shift = @"{'x':0,'y':0,'z':6}" - var/item_form_type = /obj/item/roller //The folded-up object path. - var/obj/item/chems/beaker - var/iv_attached = 0 - var/iv_stand = TRUE - -/obj/structure/bed/roller/on_update_icon() - overlays.Cut() - if(density) - icon_state = "up" - else - icon_state = "down" - if(beaker) - var/image/iv = image(icon, "iv[iv_attached]") - var/percentage = round((beaker.reagents.total_volume / beaker.volume) * 100, 25) - var/image/filling = image(icon, "iv_filling[percentage]") - filling.color = beaker.reagents.get_color() - iv.overlays += filling - if(percentage < 25) - iv.overlays += image(icon, "light_low") - if(density) - iv.pixel_y = 6 - overlays += iv - -/obj/structure/bed/roller/attackby(obj/item/I, mob/user) - if(isWrench(I) || istype(I, /obj/item/stack) || isWirecutter(I)) - return 1 - if(iv_stand && !beaker && istype(I, /obj/item/chems)) - if(!user.unEquip(I, src)) - return - to_chat(user, "You attach \the [I] to \the [src].") - beaker = I - queue_icon_update() - return 1 - ..() - -/obj/structure/bed/roller/attack_hand(mob/living/user) - if(beaker && !buckled_mob) - remove_beaker(user) - else - ..() - -/obj/structure/bed/roller/proc/collapse() - visible_message("[usr] collapses [src].") - new item_form_type(get_turf(src)) - qdel(src) - -/obj/structure/bed/roller/post_buckle_mob(mob/living/M) - . = ..() - if(M == buckled_mob) - set_density(1) - queue_icon_update() - else - set_density(0) - if(iv_attached) - detach_iv(M, usr) - queue_icon_update() - -/obj/structure/bed/roller/Process() - if(!iv_attached || !buckled_mob || !beaker) - return PROCESS_KILL - - //SSObj fires twice as fast as SSMobs, so gotta slow down to not OD our victims. - if(SSobj.times_fired % 2) - return - - if(beaker.volume > 0) - beaker.reagents.trans_to_mob(buckled_mob, beaker.amount_per_transfer_from_this, CHEM_INJECT) - queue_icon_update() - -/obj/structure/bed/roller/proc/remove_beaker(mob/user) - to_chat(user, "You detach \the [beaker] to \the [src].") - iv_attached = FALSE - beaker.dropInto(loc) - beaker = null - queue_icon_update() - -/obj/structure/bed/roller/proc/attach_iv(mob/living/carbon/human/target, mob/user) - if(!beaker) - return - if(do_IV_hookup(target, user, beaker)) - iv_attached = TRUE - queue_icon_update() - START_PROCESSING(SSobj,src) - -/obj/structure/bed/roller/proc/detach_iv(mob/living/carbon/human/target, mob/user) - visible_message("\The [target] is taken off the IV on \the [src].") - iv_attached = FALSE - queue_icon_update() - STOP_PROCESSING(SSobj,src) - -/obj/structure/bed/roller/MouseDrop(over_object, src_location, over_location) - ..() - if(!CanMouseDrop(over_object)) return - if(!(ishuman(usr) || isrobot(usr))) return - if(over_object == buckled_mob && beaker) - if(iv_attached) - detach_iv(buckled_mob, usr) - else - attach_iv(buckled_mob, usr) - return - if(ishuman(over_object)) - if(user_buckle_mob(over_object, usr)) - attach_iv(buckled_mob, usr) - return - if(beaker) - remove_beaker(usr) - return - if(buckled_mob) return - collapse() - -/obj/item/roller - name = "roller bed" - desc = "A collapsed roller bed that can be carried around." - icon = 'icons/obj/structures/rollerbed.dmi' - icon_state = "folded" - item_state = "rbed" - slot_flags = SLOT_BACK - w_class = ITEM_SIZE_LARGE - var/structure_form_type = /obj/structure/bed/roller //The deployed form path. - -/obj/item/roller/attack_self(mob/user) - var/obj/structure/bed/roller/R = new structure_form_type(user.loc) - R.add_fingerprint(user) - qdel(src) - -/obj/item/robot_rack/roller - name = "roller bed rack" - desc = "A rack for carrying collapsed roller beds. Can also be used for carrying ironing boards." - icon = 'icons/obj/structures/rollerbed.dmi' - icon_state = "folded" - object_type = /obj/item/roller - interact_type = /obj/structure/bed/roller -/* - * Mattresses - */ -/obj/structure/mattress - name = "mattress" - icon = 'icons/obj/furniture.dmi' - icon_state = "mattress" - desc = "A bare mattress. It doesn't look very comfortable." - anchored = 0 - -/obj/structure/mattress/dirty - name = "dirty mattress" - icon_state = "dirty_mattress" - desc = "A dirty, smelly mattress covered in body fluids. You wouldn't want to touch this." diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm deleted file mode 100644 index 17d0410392b8..000000000000 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ /dev/null @@ -1,333 +0,0 @@ -/obj/structure/bed/chair //YES, chairs are a type of bed, which are a type of stool. This works, believe me. -Pete - name = "chair" - desc = "You sit in this, either by will or force." - icon_state = "chair" - color = "#666666" - buckle_dir = 0 - buckle_lying = 0 //force people to sit up in chairs when buckled - obj_flags = OBJ_FLAG_ROTATABLE - - var/propelled = 0 // Check for fire-extinguisher-driven chairs - -/obj/structure/bed/chair/do_simple_ranged_interaction(var/mob/user) - if(!buckled_mob && user) - rotate(user) - return TRUE - -/obj/structure/bed/chair/attackby(obj/item/W, mob/user) - ..() - if(!reinf_material && istype(W, /obj/item/assembly/shock_kit)) - var/obj/item/assembly/shock_kit/SK = W - if(!SK.status) - to_chat(user, SPAN_NOTICE("\The [SK] is not ready to be attached!")) - return - if(!user.unEquip(SK)) - return - var/obj/structure/bed/chair/e_chair/E = new (src.loc, material.type) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - E.set_dir(dir) - E.part = SK - SK.forceMove(E) - SK.master = E - qdel(src) - -/obj/structure/bed/chair/post_buckle_mob() - update_icon() - return ..() - -/obj/structure/bed/chair/on_update_icon() - ..() - var/new_overlays - var/image/I = image(icon, "[icon_state]_over") - I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = material.color - LAZYADD(new_overlays, I) - I = image(icon, "[icon_state]_armrest") - I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = material.color - LAZYADD(new_overlays, I) - if(reinf_material) - I = image(icon, "[icon_state]_padding_over") - I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = reinf_material.color - LAZYADD(new_overlays, I) - I = image(icon, "[icon_state]_padding_armrest") - I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = reinf_material.color - LAZYADD(new_overlays, I) - overlays += new_overlays - -/obj/structure/bed/chair/rotate(mob/user) - if(!CanPhysicallyInteract(user)) - to_chat(user, SPAN_NOTICE("You can't interact with \the [src] right now!")) - return - - set_dir(turn(dir, 90)) - update_icon() - -/obj/structure/bed/chair/set_dir() - ..() - if(buckled_mob) - buckled_mob.set_dir(dir) - -/obj/structure/bed/chair/padded/red - reinf_material = /decl/material/solid/carpet -/obj/structure/bed/chair/padded/brown - reinf_material = /decl/material/solid/leather -/obj/structure/bed/chair/padded/teal - reinf_material = /decl/material/solid/cloth/teal -/obj/structure/bed/chair/padded/black - reinf_material = /decl/material/solid/cloth/black -/obj/structure/bed/chair/padded/green - reinf_material = /decl/material/solid/cloth/green -/obj/structure/bed/chair/padded/purple - reinf_material = /decl/material/solid/cloth/purple -/obj/structure/bed/chair/padded/blue - reinf_material = /decl/material/solid/cloth/blue -/obj/structure/bed/chair/padded/beige - reinf_material = /decl/material/solid/cloth/beige -/obj/structure/bed/chair/padded/lime - reinf_material = /decl/material/solid/cloth/lime -/obj/structure/bed/chair/padded/yellow - reinf_material = /decl/material/solid/cloth/yellow - -// Leaving this in for the sake of compilation. -/obj/structure/bed/chair/comfy - name = "comfy chair" - desc = "It's a chair. It looks comfy." - icon_state = "comfychair" - -/obj/structure/bed/chair/comfy/brown - reinf_material = /decl/material/solid/leather -/obj/structure/bed/chair/comfy/red - reinf_material = /decl/material/solid/carpet -/obj/structure/bed/chair/comfy/teal - reinf_material = /decl/material/solid/cloth/teal -/obj/structure/bed/chair/comfy/black - reinf_material = /decl/material/solid/cloth/black -/obj/structure/bed/chair/comfy/green - reinf_material = /decl/material/solid/cloth/green -/obj/structure/bed/chair/comfy/purple - reinf_material = /decl/material/solid/cloth/purple -/obj/structure/bed/chair/comfy/blue - reinf_material = /decl/material/solid/cloth/blue -/obj/structure/bed/chair/comfy/beige - reinf_material = /decl/material/solid/cloth/beige -/obj/structure/bed/chair/comfy/lime - reinf_material = /decl/material/solid/cloth/lime -/obj/structure/bed/chair/comfy/yellow - reinf_material = /decl/material/solid/cloth/yellow - -/obj/structure/bed/chair/comfy/captain - name = "captain chair" - desc = "It's a chair. Only for the highest ranked asses." - icon_state = "capchair" - buckle_movable = 1 - material = /decl/material/solid/metal/steel - reinf_material = /decl/material/solid/cloth/blue - -/obj/structure/bed/chair/comfy/captain/on_update_icon() - ..() - if(buckled_mob) - var/image/I = image(icon, "[icon_state]_special") - I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = material.color - overlays |= I - -/obj/structure/bed/chair/armchair - name = "armchair" - desc = "It's an armchair. It looks comfy." - icon_state = "armchair" - -/obj/structure/bed/chair/armchair/brown - reinf_material = /decl/material/solid/leather -/obj/structure/bed/chair/armchair/red - reinf_material = /decl/material/solid/carpet -/obj/structure/bed/chair/armchair/teal - reinf_material = /decl/material/solid/cloth/teal -/obj/structure/bed/chair/armchair/black - reinf_material = /decl/material/solid/cloth/black -/obj/structure/bed/chair/armchair/green - reinf_material = /decl/material/solid/cloth/green -/obj/structure/bed/chair/armchair/purple - reinf_material = /decl/material/solid/cloth/purple -/obj/structure/bed/chair/armchair/blue - reinf_material = /decl/material/solid/cloth/blue -/obj/structure/bed/chair/armchair/beige - reinf_material = /decl/material/solid/cloth/beige -/obj/structure/bed/chair/armchair/lime - reinf_material = /decl/material/solid/cloth/lime -/obj/structure/bed/chair/armchair/yellow - reinf_material = /decl/material/solid/cloth/yellow - -/obj/structure/bed/chair/office - name = "office chair" - icon_state = "officechair" - anchored = 0 - buckle_movable = 1 - -/obj/structure/bed/chair/office/Move() - . = ..() - if(buckled_mob) - var/mob/living/occupant = buckled_mob - if (occupant && (src.loc != occupant.loc)) - if (propelled) - for (var/mob/O in src.loc) - if (O != occupant) - Bump(O) - else - unbuckle_mob() - -/obj/structure/bed/chair/office/Bump(atom/A) - ..() - if(!buckled_mob) return - - if(propelled) - var/mob/living/occupant = unbuckle_mob() - - var/def_zone = ran_zone() - var/blocked = 100 * occupant.get_blocked_ratio(def_zone, BRUTE, damage = 10) - occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, blocked) - occupant.apply_effect(6, WEAKEN, blocked) - occupant.apply_effect(6, STUTTER, blocked) - occupant.apply_damage(10, BRUTE, def_zone) - playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) - if(istype(A, /mob/living)) - var/mob/living/victim = A - def_zone = ran_zone() - blocked = 100 * victim.get_blocked_ratio(def_zone, BRUTE, damage = 10) - victim.apply_effect(6, STUN, blocked) - victim.apply_effect(6, WEAKEN, blocked) - victim.apply_effect(6, STUTTER, blocked) - victim.apply_damage(10, BRUTE, def_zone) - occupant.visible_message("[occupant] crashed into \the [A]!") - -/obj/structure/bed/chair/office/light - reinf_material = /decl/material/solid/cloth -/obj/structure/bed/chair/office/dark - reinf_material = /decl/material/solid/cloth/black - -/obj/structure/bed/chair/office/comfy - name = "comfy office chair" - desc = "It's an office chair. It looks comfy." - icon_state = "comfyofficechair" - -/obj/structure/bed/chair/office/comfy/brown - reinf_material = /decl/material/solid/leather -/obj/structure/bed/chair/office/comfy/red - reinf_material = /decl/material/solid/carpet -/obj/structure/bed/chair/office/comfy/teal - reinf_material = /decl/material/solid/cloth/teal -/obj/structure/bed/chair/office/comfy/black - reinf_material = /decl/material/solid/cloth/black -/obj/structure/bed/chair/office/comfy/green - reinf_material = /decl/material/solid/cloth/green -/obj/structure/bed/chair/office/comfy/purple - reinf_material = /decl/material/solid/cloth/purple -/obj/structure/bed/chair/office/comfy/blue - reinf_material = /decl/material/solid/cloth/blue -/obj/structure/bed/chair/office/comfy/beige - reinf_material = /decl/material/solid/cloth/beige -/obj/structure/bed/chair/office/comfy/lime - reinf_material = /decl/material/solid/cloth/lime -/obj/structure/bed/chair/office/comfy/yellow - reinf_material = /decl/material/solid/cloth/yellow - -/obj/structure/bed/chair/shuttle - name = "shuttle seat" - desc = "A comfortable, secure seat. It has a sturdy-looking buckling system for smoother flights." - icon_state = "shuttle_chair" - buckling_sound = 'sound/effects/metal_close.ogg' - material = /decl/material/solid/metal/steel - -/obj/structure/bed/chair/shuttle/post_buckle_mob() - if(buckled_mob) - icon_state = "shuttle_chair-b" - else - icon_state = "shuttle_chair" - ..() - -/obj/structure/bed/chair/shuttle/on_update_icon() - ..() - if(buckled_mob) - var/image/I = image(icon, "[icon_state]_special") - I.layer = buckled_mob ? ABOVE_HUMAN_LAYER : FLOAT_LAYER - if(material_alteration & MAT_FLAG_ALTERATION_COLOR) - I.appearance_flags |= RESET_COLOR - I.color = material.color - overlays |= I - -/obj/structure/bed/chair/shuttle/blue - reinf_material = /decl/material/solid/cloth/blue -/obj/structure/bed/chair/shuttle/black - reinf_material = /decl/material/solid/cloth/black -/obj/structure/bed/chair/shuttle/white - reinf_material = /decl/material/solid/cloth - -/obj/structure/bed/chair/wood - name = "classic chair" - desc = "Old is never too old to not be in fashion." - icon_state = "wooden_chair" - color = WOOD_COLOR_GENERIC - var/chair_material = /decl/material/solid/wood - -/obj/structure/bed/chair/wood/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/stack) || istype(W, /obj/item/wirecutters)) - return - ..() - -/obj/structure/bed/chair/wood/mahogany - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood/mahogany -/obj/structure/bed/chair/wood/maple - color = WOOD_COLOR_PALE - material = /decl/material/solid/wood/maple -/obj/structure/bed/chair/wood/ebony - color = WOOD_COLOR_BLACK - material = /decl/material/solid/wood/ebony -/obj/structure/bed/chair/wood/walnut - color = WOOD_COLOR_CHOCOLATE - material = /decl/material/solid/wood/walnut - -/obj/structure/bed/chair/wood/wings - name = "winged chair" - icon_state = "wooden_chair_wings" -/obj/structure/bed/chair/wood/wings/mahogany - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood/mahogany -/obj/structure/bed/chair/wood/wings/maple - color = WOOD_COLOR_PALE - material = /decl/material/solid/wood/maple -/obj/structure/bed/chair/wood/wings/ebony - color = WOOD_COLOR_BLACK - material = /decl/material/solid/wood/ebony -/obj/structure/bed/chair/wood/wings/walnut - color = WOOD_COLOR_CHOCOLATE - material = /decl/material/solid/wood/walnut - -/obj/structure/bed/chair/pew - name = "pew" - desc = "A long, simple bench with a backboard, commonly found in places of worship, courtrooms and so on. Not known for being particularly comfortable." - icon_state = "pew" - color = WOOD_COLOR_GENERIC - material = /decl/material/solid/wood - obj_flags = 0 -/obj/structure/bed/chair/pew/left - icon_state = "pew_left" -/obj/structure/bed/chair/pew/mahogany - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood/mahogany -/obj/structure/bed/chair/pew/left/mahogany - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood/mahogany \ No newline at end of file diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm deleted file mode 100644 index 60e713fd84be..000000000000 --- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm +++ /dev/null @@ -1,142 +0,0 @@ -//Todo: add leather and cloth for arbitrary coloured stools. -/obj/item/stool - name = "stool" - desc = "Apply butt." - icon = 'icons/obj/furniture.dmi' - icon_state = "stool_preview" //set for the map - item_state = "stool" - randpixel = 0 - force = 10 - throwforce = 10 - w_class = ITEM_SIZE_HUGE - material = DEFAULT_FURNITURE_MATERIAL - var/base_icon = "stool" - var/decl/material/padding_material - -/obj/item/stool/padded - icon_state = "stool_padded_preview" //set for the map - padding_material = /decl/material/solid/carpet - -/obj/item/stool/Initialize() - . = ..() - if(!istype(material)) - return INITIALIZE_HINT_QDEL - if(ispath(padding_material, /decl/material)) - padding_material = decls_repository.get_decl(padding_material) - force = round(material.get_blunt_damage()*0.4) - update_icon() - -/obj/item/stool/padded - padding_material = /decl/material/solid/carpet - -/obj/item/stool/bar - name = "bar stool" - icon_state = "bar_stool_preview" //set for the map - item_state = "bar_stool" - base_icon = "bar_stool" - -/obj/item/stool/bar/padded - icon_state = "bar_stool_padded_preview" - padding_material = /decl/material/solid/carpet - -/obj/item/stool/on_update_icon() - // Prep icon. - icon_state = "" - // Base icon. - var/list/noverlays = list() - var/image/I = image(icon, "[base_icon]_base") - I.color = material.color - noverlays |= I - // Padding overlay. - if(padding_material) - I = image(icon, "[base_icon]_padding") - I.color = padding_material.color - noverlays += I - overlays = noverlays - // Strings. - if(padding_material) - SetName("[padding_material.solid_name] [initial(name)]") //this is not perfect but it will do for now. - desc = "A padded stool. Apply butt. It's made of [material.use_name] and covered with [padding_material.use_name]." - else - SetName("[material.solid_name] [initial(name)]") - desc = "A stool. Apply butt with care. It's made of [material.use_name]." - -/obj/item/stool/proc/add_padding(var/padding_type) - padding_material = decls_repository.get_decl(padding_type) - update_icon() - -/obj/item/stool/proc/remove_padding() - if(padding_material) - padding_material.place_sheet(get_turf(src)) - padding_material = null - update_icon() - -/obj/item/stool/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - if (prob(5)) - user.visible_message("[user] breaks [src] over [target]'s back!") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(target) - dismantle() //This deletes self. - - var/blocked = target.get_blocked_ratio(hit_zone, BRUTE, damage = 20) - target.Weaken(10 * (1 - blocked)) - target.apply_damage(20, BRUTE, hit_zone, src) - return 1 - - return ..() - -/obj/item/stool/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) - -/obj/item/stool/proc/dismantle() - if(material) - material.place_sheet(get_turf(src)) - if(padding_material) - padding_material.place_sheet(get_turf(src)) - qdel(src) - -/obj/item/stool/attackby(obj/item/W, mob/user) - if(isWrench(W)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - dismantle() - qdel(src) - else if(istype(W,/obj/item/stack)) - if(padding_material) - to_chat(user, "\The [src] is already padded.") - return - var/obj/item/stack/C = W - if(C.get_amount() < 1) // How?? - qdel(C) - return - var/padding_type //This is awful but it needs to be like this until tiles are given a material var. - if(istype(W,/obj/item/stack/tile/carpet)) - padding_type = /decl/material/solid/carpet - else if(istype(W,/obj/item/stack/material)) - var/obj/item/stack/material/M = W - if(M.material && (M.material.flags & MAT_FLAG_PADDING)) - padding_type = "[M.material.type]" - if(!padding_type) - to_chat(user, "You cannot pad \the [src] with that.") - return - C.use(1) - if(!istype(src.loc, /turf)) - user.drop_from_inventory(src) - src.dropInto(loc) - to_chat(user, "You add padding to \the [src].") - add_padding(padding_type) - return - else if(isWirecutter(W)) - if(!padding_material) - to_chat(user, "\The [src] has no padding to remove.") - return - to_chat(user, "You remove the padding from \the [src].") - playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) - remove_padding() - else - ..() - -//Generated subtypes for mapping porpoises -/obj/item/stool/wood - material = /decl/material/solid/wood diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm deleted file mode 100644 index bfd51698591c..000000000000 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ /dev/null @@ -1,113 +0,0 @@ -/obj/structure/bed/chair/wheelchair - name = "wheelchair" - desc = "Now we're getting somewhere." - icon_state = "wheelchair" - anchored = 0 - buckle_movable = 1 - movement_handlers = list(/datum/movement_handler/deny_multiz, /datum/movement_handler/delay = list(2), /datum/movement_handler/move_relay_self) - movable_flags = MOVABLE_FLAG_NONDENSE_COLLISION - var/driving = 0 - var/bloodiness - -/obj/structure/bed/chair/wheelchair/on_update_icon() - return - -/obj/structure/bed/chair/wheelchair/set_dir() - ..() - overlays.Cut() - var/image/O = image(icon = 'icons/obj/furniture.dmi', icon_state = "w_overlay", dir = src.dir) - O.layer = ABOVE_HUMAN_LAYER - overlays += O - if(buckled_mob) - buckled_mob.set_dir(dir) - -/obj/structure/bed/chair/wheelchair/attackby(obj/item/W, mob/user) - if(isWrench(W) || istype(W,/obj/item/stack) || isWirecutter(W)) - return - ..() - -/obj/structure/bed/chair/wheelchair/relaymove(mob/user, direction) - // Redundant check? - if(user.stat || user.stunned || user.weakened || user.paralysis || user.lying || user.restrained()) - return - if(propelled) - return - // Let's roll - driving = 1 - //--1---Move occupant---1--// - if(buckled_mob) - buckled_mob.buckled = null - step(buckled_mob, direction) - buckled_mob.buckled = src - //--2--Move wheelchair--2--// - step(src, direction) - if(buckled_mob) // Make sure it stays beneath the occupant - Move(buckled_mob.loc) - set_dir(direction) - if(bloodiness) - create_track() - driving = 0 - -/obj/structure/bed/chair/wheelchair/Move() - . = ..() - if(buckled_mob) - var/mob/living/occupant = buckled_mob - if(!driving) - if (occupant && (src.loc != occupant.loc)) - if (propelled) - for (var/mob/O in src.loc) - if (O != occupant) - Bump(O) - else - unbuckle_mob() - else - if (occupant && (src.loc != occupant.loc)) - src.forceMove(occupant.loc) // Failsafe to make sure the wheelchair stays beneath the occupant after driving - -/obj/structure/bed/chair/wheelchair/attack_hand(mob/living/user) - user_unbuckle_mob(user) - -/obj/structure/bed/chair/wheelchair/Bump(atom/A) - ..() - if(!buckled_mob) return - - if(propelled) - var/mob/living/occupant = unbuckle_mob() - occupant.throw_at(A, 3, 3) - - var/def_zone = ran_zone() - var/blocked = 100 * occupant.get_blocked_ratio(def_zone, BRUTE, damage = 10) - occupant.throw_at(A, 3, 3) - occupant.apply_effect(6, STUN, blocked) - occupant.apply_effect(6, WEAKEN, blocked) - occupant.apply_effect(6, STUTTER, blocked) - occupant.apply_damage(10, BRUTE, def_zone) - playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) - if(istype(A, /mob/living)) - var/mob/living/victim = A - def_zone = ran_zone() - blocked = 100 * victim.get_blocked_ratio(def_zone, BRUTE, damage = 10) - victim.apply_effect(6, STUN, blocked) - victim.apply_effect(6, WEAKEN, blocked) - victim.apply_effect(6, STUTTER, blocked) - victim.apply_damage(10, BRUTE, def_zone) - occupant.visible_message(SPAN_DANGER("\The [occupant] crashed into \the [A]!")) - -/obj/structure/bed/chair/wheelchair/proc/create_track() - var/obj/effect/decal/cleanable/blood/tracks/B = new(loc) - var/newdir = get_dir(get_step(loc, dir), loc) - if(newdir == dir) - B.set_dir(newdir) - else - newdir = newdir | dir - if(newdir == 3) - newdir = 1 - else if(newdir == 12) - newdir = 4 - B.set_dir(newdir) - bloodiness-- - -/proc/equip_wheelchair(mob/living/carbon/human/H) //Proc for spawning in a wheelchair if a new character has no legs. Used in new_player.dm - var/obj/structure/bed/chair/wheelchair/W = new(get_turf(H)) - if(isturf(H.loc)) - W.buckle_mob(H) \ No newline at end of file diff --git a/code/game/objects/structures/structure_reagents.dm b/code/game/objects/structures/structure_reagents.dm new file mode 100644 index 000000000000..f2d9decae039 --- /dev/null +++ b/code/game/objects/structures/structure_reagents.dm @@ -0,0 +1,47 @@ +/obj/structure/receive_mouse_drop(atom/dropping, mob/user, params) + if((. = ..()) || user?.get_active_held_item() != dropping || !isitem(dropping) || isnull(get_possible_reagent_transfer_amounts())) + return + // Awful. Sorry. + var/obj/item/item = dropping + var/old_atom_flags = atom_flags + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + if(item.standard_pour_into(user, src)) + . = TRUE + atom_flags = old_atom_flags + +/obj/structure/proc/get_reagent_amount_dispensed() + return null + +/obj/structure/proc/set_reagent_amount_dispensed() + return null + +/obj/structure/proc/set_reagent_amount_dispensed_verb() + set name = "Set amount dispensed" + set category = "Object" + set src in view(1) + if(!CanPhysicallyInteract(usr)) + to_chat(usr, SPAN_NOTICE("You're in no condition to do that!")) + return + var/new_amount = input("Amount dispensed:","[src]") as null|anything in get_possible_reagent_transfer_amounts() + if(!CanPhysicallyInteract(usr)) // because input takes time and the situation can change + to_chat(usr, SPAN_NOTICE("You're in no condition to do that!'")) + return + if (new_amount) + set_reagent_amount_dispensed(new_amount) + +/obj/structure/proc/get_possible_reagent_transfer_amounts() + return null + +//Set amount dispensed. Added manually to querns and reagent dispensers. +/decl/interaction_handler/set_transfer/structure + expected_target_type = /obj/structure + +/decl/interaction_handler/set_transfer/structure/is_possible(var/atom/target, var/mob/user) + . = ..() + if(.) + var/obj/structure/dispenser = target + return !isnull(dispenser.get_possible_reagent_transfer_amounts()) + +/decl/interaction_handler/set_transfer/structure/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/dispenser = target + dispenser.set_reagent_amount_dispensed_verb() diff --git a/code/game/objects/structures/tables.dm b/code/game/objects/structures/tables.dm new file mode 100644 index 000000000000..fb9dda2bf289 --- /dev/null +++ b/code/game/objects/structures/tables.dm @@ -0,0 +1,995 @@ +/obj/structure/table + name = "table frame" + icon = 'icons/obj/structures/tables.dmi' + icon_state = "plain_preview" + color = COLOR_OFF_WHITE + material = DEFAULT_FURNITURE_MATERIAL + reinf_material = DEFAULT_FURNITURE_MATERIAL + desc = "It's a table, for putting things on. Or standing on, if you really want to." + density = TRUE + anchored = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + layer = TABLE_LAYER + throwpass = TRUE + // Note that mob_offset also determines whether you can walk from one table to another without climbing. + // TODO: add 1px step-up? + mob_offset = 12 + handle_generic_blending = TRUE + max_health = 10 + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + parts_amount = 2 + parts_type = /obj/item/stack/material/rods + structure_flags = STRUCTURE_FLAG_SURFACE + can_support_butchery = TRUE + + var/can_flip = TRUE + var/is_flipped = FALSE + var/decl/material/additional_reinf_material + + var/top_surface_noun = "tabletop" + + // Gambling tables. I'd prefer reinforced with carpet/felt/cloth/whatever, but AFAIK it's either harder or impossible to get /obj/item/stack/material of those. + // Convert if/when you can easily get stacks of these. + var/felted = 0 + var/list/connections + + /// Whether items can be placed on this table via clicking. + var/can_place_items = TRUE + +/obj/structure/table/should_have_alpha_mask() + return simulated && isturf(loc) && !(locate(/obj/structure/table) in get_step(loc, SOUTH)) + +/obj/structure/table/Initialize() + if(ispath(additional_reinf_material, /decl/material)) + additional_reinf_material = GET_DECL(additional_reinf_material) + . = ..() + if(. != INITIALIZE_HINT_QDEL) + if(!material) + return INITIALIZE_HINT_QDEL + if(reinf_material || additional_reinf_material || felted) + tool_interaction_flags &= ~TOOL_INTERACTION_DECONSTRUCT + + DELETE_IF_DUPLICATE_OF(/obj/structure/table) + . = INITIALIZE_HINT_LATELOAD + +// We do this because need to make sure adjacent tables init their material before we try and merge. +/obj/structure/table/LateInitialize() + ..() + if(is_flipped) + flip(dir, TRUE) + else + update_connections(TRUE) + update_icon() + +/obj/structure/table/Destroy() + var/turf/oldloc = loc + additional_reinf_material = null + . = ..() + if(istype(oldloc)) + for(var/obj/structure/table/table in range(oldloc, 1)) + if(QDELETED(table)) + continue + table.update_connections(FALSE) + table.update_icon() + +/obj/structure/table/adjust_required_attack_dexterity(mob/user, required_dexterity) + // Let people put stuff on tables without necessarily being able to use a gun or such. + if(user?.check_intent(I_FLAG_HELP)) + return DEXTERITY_HOLD_ITEM + return ..() + +/obj/structure/table/clear_connections() + connections = null + +/obj/structure/table/set_connections(dirs, other_dirs) + connections = dirs_to_corner_states(dirs) + +/obj/structure/table/get_material_health_modifier() + . = additional_reinf_material ? 0.75 : 0.5 + +/obj/structure/table/physically_destroyed(skip_qdel) + visible_message(SPAN_DANGER("\The [src] breaks down!")) + + // Destroy some stuff before passing off to dismantle(), which will return it in sheet form instead. + if(reinf_material && !prob(20)) + reinf_material.place_shards(loc) + reinf_material = null + if(material && !prob(20)) + var/shards = material.place_shards(loc) + if(paint_color) + for(var/obj/item/shard in shards) + shard.set_color(paint_color) + material = null + if(additional_reinf_material && !prob(20)) + additional_reinf_material.place_shards(loc) + additional_reinf_material = null + if(felted && prob(50)) + felted = FALSE + + . = ..() + +/obj/structure/table/create_dismantled_products(var/turf/T) + . = ..() + if(felted) + // TODO: padding_color for tables + new /obj/item/stack/tile/carpet(T) + if(additional_reinf_material) + LAZYADD(., additional_reinf_material.place_dismantled_product(T)) + +/obj/structure/table/clear_materials() + ..() + felted = FALSE + additional_reinf_material = null + +/obj/structure/table/can_dismantle(mob/user) + . = ..() + if(.) + var/needs_removed + if(felted) + needs_removed = "felting" + else if(reinf_material) + needs_removed = top_surface_noun + else if(additional_reinf_material) + needs_removed = "reinforcements" + if(needs_removed) + to_chat(user, SPAN_WARNING("Remove \the [needs_removed] with a screwdriver first.")) + return FALSE + +/obj/structure/table/handle_default_screwdriver_attackby(mob/user, obj/item/screwdriver) + + if(!reinf_material) + return ..() + + if(felted) + user.visible_message( + SPAN_NOTICE("\The [user] removes the felting from \the [src]."), + SPAN_NOTICE("You remove the felting from \the [src].")) + new /obj/item/stack/tile/carpet(loc) + felted = FALSE + update_icon() + return TRUE + + var/decl/material/remove_mat = reinf_material + var/remove_noun = top_surface_noun + var/check_reinf = TRUE + if(additional_reinf_material) + remove_mat = additional_reinf_material + remove_noun = "reinforcements" + check_reinf = FALSE + + user.visible_message(SPAN_NOTICE("\The [user] begins removing \the [src]'s [remove_mat.solid_name] [remove_noun].")) + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 4 SECONDS, src)) + if(check_reinf) + if(remove_mat != reinf_material) + return TRUE + reinf_material.create_object(src.loc) + reinf_material = null + tool_interaction_flags |= TOOL_INTERACTION_DECONSTRUCT + else + if(remove_mat != additional_reinf_material) + return TRUE + additional_reinf_material.create_object(src.loc) + additional_reinf_material = null + + user.visible_message(SPAN_NOTICE("\The [user] removes the [remove_mat.solid_name] [remove_noun] from \the [src]."), + SPAN_NOTICE("You remove the [remove_mat.solid_name] [remove_noun] from \the [src].")) + update_materials() + return TRUE + +/obj/structure/table/attackby(obj/item/used_item, mob/user, click_params) + + if(user.check_intent(I_FLAG_HARM) && used_item.is_special_cutting_tool()) + spark_at(src.loc, amount=5) + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + user.visible_message(SPAN_DANGER("\The [src] was sliced apart by \the [user]!")) + physically_destroyed() + return TRUE + + if(!reinf_material) + if(istype(used_item, /obj/item/stack/material/rods)) + return reinforce_table(used_item, user) + if(istype(used_item, /obj/item/stack/material)) + return finish_table(used_item, user) + return ..() + + if(!felted && istype(used_item, /obj/item/stack/tile/carpet)) + var/obj/item/stack/tile/carpet/C = used_item + if(C.use(1)) + user.visible_message( + SPAN_NOTICE("\The [user] adds \the [C] to \the [src]."), + SPAN_NOTICE("You add \the [C] to \the [src].")) + felted = TRUE + update_icon() + else + to_chat(user, SPAN_WARNING("You don't have enough carpet to felt \the [src].")) + return TRUE + + //playing cards + if(istype(used_item, /obj/item/hand)) + var/obj/item/hand/H = used_item + if(H.cards && length(H.cards) == 1) + user.visible_message("\The [user] plays \the [H.cards[1]].") + return TRUE + + if(istype(used_item, /obj/item/deck)) //playing cards + if(user.check_intent(I_FLAG_GRAB)) + var/obj/item/deck/D = used_item + if(!length(D.cards)) + to_chat(user, "There are no cards in the deck.") + else + D.deal_at(user, src) + return TRUE + + . = ..() + + // Finally we can put the object onto the table. + if(!. && can_place_items && !isrobot(user) && used_item.loc == user && user.try_unequip(used_item, src.loc)) + auto_align(used_item, click_params) + return TRUE + +/obj/structure/table/proc/reinforce_table(obj/item/stack/material/S, mob/user) + + if(additional_reinf_material) + to_chat(user, SPAN_WARNING("\The [src] already has reinforcements!")) + return FALSE + + if(!S.material) + to_chat(user, SPAN_WARNING("You cannot use \the [S] for reinforcements.")) + return FALSE + + if(is_flipped) + to_chat(user, SPAN_WARNING("Put \the [src] back in place before reinforcing it!")) + return FALSE + + var/decl/material/mat = S.material + to_chat(user, SPAN_NOTICE("You begin reinforcing \the [src] with [mat.solid_name].")) + if(do_after(user, 2 SECONDS, src) && S.use(1) && !additional_reinf_material) + user.visible_message(SPAN_NOTICE("\The [user] finishes adding [mat.solid_name] reinforcements to \the [src].")) + additional_reinf_material = mat + update_materials() + return TRUE + +/obj/structure/table/proc/finish_table(obj/item/stack/material/S, mob/user) + + if(reinf_material) + to_chat(user, SPAN_WARNING("\The [src] already has \a [top_surface_noun]!")) + return FALSE + + if(!S.material) + to_chat(user, SPAN_WARNING("You cannot use \the [S] for \a [top_surface_noun].")) + return FALSE + + if(is_flipped) + to_chat(user, SPAN_WARNING("Put \the [src] back in place before putting \a [top_surface_noun] on it!")) + return FALSE + + var/decl/material/mat = S.material + to_chat(user, SPAN_NOTICE("You begin furnishing \the [src] with \a [mat.solid_name] [top_surface_noun].")) + if(do_after(user, 2 SECONDS, src) && S.use(1) && !reinf_material) + user.visible_message(SPAN_NOTICE("\The [user] finishes adding \a [mat.solid_name] [top_surface_noun] to \the [src].")) + reinf_material = mat + update_materials() + tool_interaction_flags &= ~TOOL_INTERACTION_DECONSTRUCT + + return TRUE + +/obj/structure/table/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + if(felted || reinf_material || additional_reinf_material) + LAZYADD(., SPAN_SUBTLE("The cladding must be removed with a screwdriver prior to deconstructing \the [src].")) + +/obj/structure/table/update_material_name(override_name) + if(reinf_material) + SetName("[reinf_material.adjective_name] table") + else if(material) + SetName("[material.adjective_name] table frame") + else + SetName("table frame") + +/obj/structure/table/update_material_desc(override_desc) + desc = initial(desc) + if(reinf_material) + if(reinf_material == material) + desc = "[desc] This one has a frame and \a [top_surface_noun] made from [material.solid_name]." + else + desc = "[desc] This one has a frame made from [material.solid_name] and \a [top_surface_noun] made from [reinf_material.solid_name]." + else if(material) + desc = "[desc] This one has a frame made from [material.solid_name]." + if(felted) + desc = "[desc] It has been covered in felt." + if(additional_reinf_material) + desc = "[desc] It has been reinforced with [additional_reinf_material.solid_name]." + +/obj/structure/table/proc/handle_normal_icon() + color = null // Don't double-apply our color, clear the map preview. + alpha = 255 + icon_state = "blank" + var/image/I + // Base frame shape. + for(var/i = 1 to 4) + I = image(icon, dir = BITFLAG(i-1), icon_state = connections ? connections[i] : "0") + I.color = material.color + I.alpha = 255 * material.opacity + add_overlay(I) + // Tabletop + if(reinf_material) + for(var/i = 1 to 4) + I = image(icon, "[reinf_material.table_icon_base]_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1)) + I.color = reinf_material.color + I.alpha = 255 * reinf_material.opacity + add_overlay(I) + if(additional_reinf_material) + for(var/i = 1 to 4) + I = image(icon, "[additional_reinf_material.table_icon_reinforced]_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1)) + I.color = additional_reinf_material.color + I.alpha = 255 * additional_reinf_material.opacity + add_overlay(I) + + if(felted) + for(var/i = 1 to 4) + add_overlay(image(icon, "carpet_[connections ? connections[i] : "0"]", dir = BITFLAG(i-1))) + +/obj/structure/table/proc/handle_flipped_icon() + var/obj/structure/table/left_neighbor = locate(/obj/structure/table) in get_step(loc, turn(dir, -90)) + var/obj/structure/table/right_neighbor = locate(/obj/structure/table) in get_step(loc, turn(dir, 90)) + var/left_neighbor_blend = istype(left_neighbor) && blend_with(left_neighbor) && left_neighbor.is_flipped == is_flipped && left_neighbor.dir == dir + var/right_neighbor_blend = istype(right_neighbor) && blend_with(right_neighbor) && right_neighbor.is_flipped == is_flipped && right_neighbor.dir == dir + + var/flip_type = 0 + var/flip_mod = "" + if(left_neighbor_blend && right_neighbor_blend) + flip_type = 2 + else if(left_neighbor_blend || right_neighbor_blend) + flip_type = 1 + flip_mod = (left_neighbor_blend ? "+" : "-") + icon_state = "flip[flip_type][flip_mod]" + + var/image/I + if(reinf_material) + I = image(icon, "[reinf_material.table_icon_base]_flip[flip_type][flip_mod]") + I.color = reinf_material.color + I.alpha = 255 * reinf_material.opacity + I.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(I) + if(additional_reinf_material) + I = image(icon, "[reinf_material.table_icon_reinforced]_flip[flip_type][flip_mod]") + I.color = additional_reinf_material.color + I.alpha = 255 * additional_reinf_material.opacity + I.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(I) + + if(felted) + add_overlay("carpet_flip[flip_type][flip_mod]") + +/obj/structure/table/on_update_icon() + . = ..() + if(is_flipped) + handle_flipped_icon() + else + handle_normal_icon() + +/obj/structure/table/proc/blend_with(var/obj/structure/table/other) + if(!istype(other) || !istype(material) || !istype(other.material) || material.type != other.material.type) + return FALSE + if(istype(reinf_material) && (!istype(other.reinf_material) || reinf_material.type != other.reinf_material.type)) + return FALSE + if(istype(additional_reinf_material) && (!istype(other.additional_reinf_material) || additional_reinf_material.type != other.additional_reinf_material.type)) + return FALSE + if(mob_offset != other.mob_offset) + return FALSE + return TRUE + +// set propagate if you're updating a table that should update tables around it too, for example if it's a new table or something important has changed (like material). +/obj/structure/table/update_connections(propagate = FALSE) + if(!material) + connections = list("0", "0", "0", "0") + if(propagate) + for(var/obj/structure/table/T in oview(src, 1)) + T.update_connections(FALSE) + return + + var/list/blocked_dirs = list() + for(var/obj/structure/window/used_item in get_turf(src)) + if(used_item.is_fulltile()) + connections = list("0", "0", "0", "0") + return + blocked_dirs |= used_item.dir + + for(var/D in list(NORTH, SOUTH, EAST, WEST) - blocked_dirs) + var/turf/T = get_step(src, D) + for(var/obj/structure/window/used_item in T) + if(used_item.is_fulltile() || used_item.dir == global.reverse_dir[D]) + blocked_dirs |= D + break + else + if(used_item.dir != D) // it's off to the side + blocked_dirs |= used_item.dir|D // blocks the diagonal + + for(var/D in list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - blocked_dirs) + var/turf/T = get_step(src, D) + for(var/obj/structure/window/used_item in T) + if(used_item.is_fulltile() || (used_item.dir & global.reverse_dir[D])) + blocked_dirs |= D + break + + // Blocked cardinals block the adjacent diagonals too. Prevents weirdness with tables. + for(var/x in list(NORTH, SOUTH)) + for(var/y in list(EAST, WEST)) + if((x in blocked_dirs) || (y in blocked_dirs)) + blocked_dirs |= x|y + + var/list/connection_dirs = list() + for(var/obj/structure/table/T in orange(src, 1)) + var/T_dir = get_dir(src, T) + if(T_dir in blocked_dirs) + continue + if(blend_with(T) && is_flipped == T.is_flipped) + connection_dirs |= T_dir + if(propagate) + spawn(0) + T.update_connections(FALSE) + T.update_icon() + connections = dirs_to_corner_states(connection_dirs) + +/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + if(istype(mover,/obj/item/projectile)) + return (check_cover(mover,target)) + if (is_flipped) + if (get_dir(loc, target) == dir) + return !density + else + return 1 + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return 1 + var/obj/structure/table/T = (locate() in get_turf(mover)) + return T && !T.is_flipped && (mob_offset <= T.mob_offset) + +//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops. +/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from) + var/turf/cover + if(is_flipped) + cover = get_turf(src) + else + cover = get_step(loc, get_dir(from, loc)) + if(!cover) + return 1 + if (get_dist(P.starting, loc) <= 1) //Tables won't help you if people are THIS close + return 1 + + var/chance = 20 + if(ismob(P.original) && get_turf(P.original) == cover) + var/mob/M = P.original + if (M.current_posture.prone) + chance += 20 //Lying down lets you catch less bullets + if(is_flipped) + if(get_dir(loc, from) == dir) //Flipped tables catch mroe bullets + chance += 30 + else + return 1 //But only from one side + + if(prob(chance)) + return 0 //blocked + return 1 + +/obj/structure/table/CheckExit(atom/movable/O, target) + if(istype(O) && O.checkpass(PASS_FLAG_TABLE)) + return TRUE + if(is_flipped) + if (get_dir(loc, target) == dir) + return !density + else + return TRUE + return TRUE + +/obj/structure/table/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && !isrobot(user) && isitem(dropping) && user.get_active_held_item() == dropping && user.try_unequip(dropping)) + var/obj/item/I = dropping + I.dropInto(get_turf(src)) + return TRUE + +/obj/structure/table/proc/can_flip() + return can_flip && !additional_reinf_material && !is_flipped + +/obj/structure/table/proc/recursive_flip_check(var/direction, var/list/checked) + + LAZYDISTINCTADD(checked, src) + + if(!can_flip()) + return FALSE + + // Is the table directly in the direction of flipping part of us? + var/obj/structure/table/T = locate() in get_step(src.loc, direction) + if(istype(T) && blend_with(T) && is_flipped == T.is_flipped) + return FALSE + + // How about the table directly behind? + T = locate() in get_step(src.loc, turn(direction, 180)) + if(istype(T) && blend_with(T) && is_flipped == T.is_flipped) + return FALSE + + // Are we part of a single straight table or not? + for(var/angle in list(-90, 90)) + T = locate() in get_step(src.loc,turn(direction,angle)) + if(istype(T) && !(T in checked) && T.is_flipped == is_flipped && blend_with(T) && !T.recursive_flip_check(direction, checked)) + return FALSE + + return TRUE + +/obj/structure/table/verb/do_flip() + set name = "Flip table" + set desc = "Flips a non-reinforced table" + set category = "Object" + set src in oview(1) + + if (!usr.can_touch(src) || ismouse(usr)) + return + + if(!flip(get_cardinal_dir(usr,src), TRUE)) + to_chat(usr, SPAN_WARNING("It won't budge.")) + return + + usr.visible_message(SPAN_WARNING("\The [usr] flips \the [src]!")) + + if(atom_flags & ATOM_FLAG_CLIMBABLE) + object_shaken() + +/obj/structure/table/proc/unflipping_check(var/direction) + + for(var/mob/M in oview(src,0)) + return 0 + + var/obj/occupied = turf_is_crowded() + if(occupied) + to_chat(usr, SPAN_WARNING("There's \a [occupied] in the way.")) + return 0 + + var/list/L = list() + if(direction) + L.Add(direction) + else + L.Add(turn(src.dir,-90)) + L.Add(turn(src.dir,90)) + for(var/new_dir in L) + var/obj/structure/table/T = locate() in get_step(src.loc,new_dir) + if(L == src) // multitile objeeeects! + continue + if(blend_with(T) && T.is_flipped && T.dir == dir && !T.unflipping_check(new_dir)) + return FALSE + return TRUE + +/obj/structure/table/proc/do_put() + set name = "Put table back" + set desc = "Puts an upended table back in place." + set category = "Object" + set src in oview(1) + + if (!usr.can_touch(src)) + return + + if (!unflipping_check()) + to_chat(usr, SPAN_WARNING("It won't budge.")) + return + unflip(TRUE) + +/obj/structure/table/proc/flip(var/direction, var/first_flip = FALSE) + + if(!recursive_flip_check(direction)) + return FALSE + + if(first_flip && !do_after(usr, 1 SECOND, src)) + return FALSE + + verbs -=/obj/structure/table/verb/do_flip + verbs +=/obj/structure/table/proc/do_put + + set_dir(direction) + if(dir != NORTH) + layer = ABOVE_HUMAN_LAYER + atom_flags &= ~ATOM_FLAG_CLIMBABLE //flipping tables allows them to be used as makeshift barriers + is_flipped = TRUE + mob_offset = 0 + atom_flags |= ATOM_FLAG_CHECKS_BORDER + + for(var/D in list(turn(direction, 90), turn(direction, -90))) + var/obj/structure/table/T = locate() in get_step(src, D) + if(blend_with(T) && !T.is_flipped) + T.flip(direction) + + var/list/targets = list(get_step(src, direction), get_step(src,turn(direction, 45)), get_step(src, turn(direction, -45))) + for(var/atom/movable/A in get_turf(src)) + if(!A.anchored) + var/turf/target = pick(targets) + if(istype(target)) + A.throw_at(target, 1, 1) + + take_damage(rand(5, 10)) + update_connections(TRUE) + update_icon() + + return TRUE + +/obj/structure/table/proc/unflip(var/first_unflip) + + if(first_unflip && !do_after(usr, 1 SECOND, src)) + return FALSE + + verbs -=/obj/structure/table/proc/do_put + verbs +=/obj/structure/table/verb/do_flip + + reset_plane_and_layer() + atom_flags |= ATOM_FLAG_CLIMBABLE + is_flipped = FALSE + mob_offset = initial(mob_offset) + atom_flags &= ~ATOM_FLAG_CHECKS_BORDER + for(var/D in list(turn(dir, 90), turn(dir, -90))) + var/obj/structure/table/T = locate() in get_step(src.loc,D) + if(blend_with(T) && T.is_flipped && T.dir == src.dir) + T.unflip() + + update_connections(TRUE) + update_icon() + + return TRUE + +/obj/structure/table/CtrlClick() + if(usr && usr.Adjacent(src)) + if(!is_flipped) + do_flip() + else + do_put() + return TRUE + return FALSE + +/obj/structure/table/handle_default_hammer_attackby(var/mob/user, var/obj/item/hammer) + return !reinf_material && ..() + +/obj/structure/table/handle_default_wrench_attackby(var/mob/user, var/obj/item/wrench) + return !reinf_material && ..() + +/obj/structure/table/handle_default_welder_attackby(var/mob/user, var/obj/item/weldingtool/welder) + return !reinf_material && ..() + +/obj/structure/table/handle_default_crowbar_attackby(var/mob/user, var/obj/item/crowbar) + return !reinf_material && ..() + +// For doing surgery on tables +/obj/structure/table/get_surgery_success_modifier(delicate) + return delicate ? -10 : 0 + +/obj/structure/table/get_surgery_surface_quality(mob/living/victim, mob/living/user) + return OPERATE_OKAY + +// Table presets. +/obj/structure/table/frame + icon_state = "frame" + reinf_material = null + +/obj/structure/table/steel + icon_state = "plain_preview" + color = COLOR_GRAY40 + reinf_material = /decl/material/solid/metal/steel + +/obj/structure/table/marble + icon_state = "stone_preview" + color = COLOR_GRAY80 + reinf_material = /decl/material/solid/stone/marble + +/obj/structure/table/reinforced + icon_state = "reinf_preview" + color = COLOR_OFF_WHITE + additional_reinf_material = /decl/material/solid/metal/steel + +/obj/structure/table/steel_reinforced + icon_state = "reinf_preview" + color = COLOR_GRAY40 + material = /decl/material/solid/metal/steel + reinf_material = /decl/material/solid/metal/steel + additional_reinf_material = /decl/material/solid/metal/steel + +/obj/structure/table/gamblingtable + icon_state = "gamble_preview" + felted = TRUE + material = /decl/material/solid/organic/wood/walnut + reinf_material = /decl/material/solid/organic/wood/walnut + +/obj/structure/table/glass + icon_state = "plain_preview" + color = COLOR_DEEP_SKY_BLUE + alpha = 77 + reinf_material = /decl/material/solid/glass + +/obj/structure/table/glass/pglass + color = "#8f29a3" + reinf_material = /decl/material/solid/glass/borosilicate + +/obj/structure/table/holotable + icon_state = "holo_preview" + holographic = TRUE + color = COLOR_OFF_WHITE + material = /decl/material/solid/metal/aluminium/holographic + reinf_material = /decl/material/solid/metal/aluminium/holographic + +/obj/structure/table/holo_plastictable + icon_state = "holo_preview" + holographic = TRUE + color = COLOR_OFF_WHITE + material = /decl/material/solid/organic/plastic/holographic + reinf_material = /decl/material/solid/organic/plastic/holographic + +/obj/structure/table/holo_woodentable + holographic = TRUE + icon_state = "holo_preview" + material = /decl/material/solid/organic/wood/holographic + reinf_material = /decl/material/solid/organic/wood/holographic + +//wood wood wood +/obj/structure/table/wood + icon_state = "solid_preview" + color = WOOD_COLOR_GENERIC + material = /decl/material/solid/organic/wood/oak + reinf_material = /decl/material/solid/organic/wood/oak + parts_type = /obj/item/stack/material/plank + +/obj/structure/table/wood/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/mahogany + reinf_material = /decl/material/solid/organic/wood/mahogany + +/obj/structure/table/wood/maple + color = WOOD_COLOR_PALE + material = /decl/material/solid/organic/wood/maple + reinf_material = /decl/material/solid/organic/wood/maple + +/obj/structure/table/wood/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/ebony + reinf_material = /decl/material/solid/organic/wood/ebony + +/obj/structure/table/wood/walnut + color = WOOD_COLOR_CHOCOLATE + material = /decl/material/solid/organic/wood/walnut + reinf_material = /decl/material/solid/organic/wood/walnut + +/obj/structure/table/wood/reinforced + icon_state = "reinf_preview" + color = WOOD_COLOR_GENERIC + material = /decl/material/solid/organic/wood/oak + reinf_material = /decl/material/solid/organic/wood/oak + additional_reinf_material = /decl/material/solid/organic/wood/oak + +/obj/structure/table/wood/reinforced/walnut + color = WOOD_COLOR_CHOCOLATE + material = /decl/material/solid/organic/wood/walnut + reinf_material = /decl/material/solid/organic/wood/walnut + additional_reinf_material = /decl/material/solid/organic/wood/walnut + +/obj/structure/table/wood/reinforced/walnut/maple + additional_reinf_material = /decl/material/solid/organic/wood/maple + +/obj/structure/table/wood/reinforced/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/mahogany + reinf_material = /decl/material/solid/organic/wood/mahogany + additional_reinf_material = /decl/material/solid/organic/wood/mahogany + +/obj/structure/table/wood/reinforced/mahogany/walnut + additional_reinf_material = /decl/material/solid/organic/wood/walnut + +/obj/structure/table/wood/reinforced/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/ebony + reinf_material = /decl/material/solid/organic/wood/ebony + additional_reinf_material = /decl/material/solid/organic/wood/ebony + +/obj/structure/table/wood/reinforced/ebony/walnut + additional_reinf_material = /decl/material/solid/organic/wood/walnut + +// Wood laminate tables; chipboard basically. +// Smooth texture like plastic etc for a less rustic vibe on spacer maps. +/obj/structure/table/laminate + icon_state = "solid_preview" + color = WOOD_COLOR_GENERIC + material = /decl/material/solid/organic/wood/chipboard + reinf_material = /decl/material/solid/organic/wood/chipboard + +/obj/structure/table/laminate/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/chipboard/mahogany + reinf_material = /decl/material/solid/organic/wood/chipboard/mahogany + +/obj/structure/table/laminate/maple + color = WOOD_COLOR_PALE + material = /decl/material/solid/organic/wood/chipboard/maple + reinf_material = /decl/material/solid/organic/wood/chipboard/maple + +/obj/structure/table/laminate/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/chipboard/ebony + reinf_material = /decl/material/solid/organic/wood/chipboard/ebony + +/obj/structure/table/laminate/walnut + color = WOOD_COLOR_CHOCOLATE + material = /decl/material/solid/organic/wood/chipboard/walnut + reinf_material = /decl/material/solid/organic/wood/chipboard/walnut + +/obj/structure/table/laminate/reinforced + icon_state = "reinf_preview" + color = WOOD_COLOR_GENERIC + material = /decl/material/solid/organic/wood/chipboard + reinf_material = /decl/material/solid/organic/wood/chipboard + additional_reinf_material = /decl/material/solid/organic/wood/chipboard + +/obj/structure/table/laminate/reinforced/walnut + color = WOOD_COLOR_CHOCOLATE + material = /decl/material/solid/organic/wood/chipboard/walnut + reinf_material = /decl/material/solid/organic/wood/chipboard/walnut + additional_reinf_material = /decl/material/solid/organic/wood/chipboard/walnut + +/obj/structure/table/laminate/reinforced/walnut/maple + additional_reinf_material = /decl/material/solid/organic/wood/chipboard/maple + +/obj/structure/table/laminate/reinforced/mahogany + color = WOOD_COLOR_RICH + material = /decl/material/solid/organic/wood/chipboard/mahogany + reinf_material = /decl/material/solid/organic/wood/chipboard/mahogany + additional_reinf_material = /decl/material/solid/organic/wood/chipboard/mahogany + +/obj/structure/table/laminate/reinforced/mahogany/walnut + additional_reinf_material = /decl/material/solid/organic/wood/chipboard/walnut + +/obj/structure/table/laminate/reinforced/ebony + color = WOOD_COLOR_BLACK + material = /decl/material/solid/organic/wood/chipboard/ebony + reinf_material = /decl/material/solid/organic/wood/chipboard/ebony + additional_reinf_material = /decl/material/solid/organic/wood/chipboard/ebony + +/obj/structure/table/laminate/reinforced/ebony/walnut + additional_reinf_material = /decl/material/solid/organic/wood/chipboard/walnut + +// A table that doesn't smooth, intended for bedside tables or otherwise standalone tables. +// TODO: make table legs use material and tabletop use reinf_material +// theoretically, this could also be made to use the normal table icon system, unlike desks? +/obj/structure/table/end + name = "end table" + icon = 'icons/obj/structures/endtable.dmi' + icon_state = "end_table_1" + handle_generic_blending = FALSE + color = /decl/material/solid/organic/wood/walnut::color + material = /decl/material/solid/organic/wood/walnut + reinf_material = /decl/material/solid/organic/wood/walnut + material_alteration = MAT_FLAG_ALTERATION_ALL + can_flip = FALSE + +/obj/structure/table/end/handle_normal_icon() + icon_state = initial(icon_state) + +/obj/structure/table/end/alt + icon_state = "end_table_2" + +/obj/structure/table/end/alt/ebony + color = /decl/material/solid/organic/wood/ebony::color + material = /decl/material/solid/organic/wood/ebony + reinf_material = /decl/material/solid/organic/wood/ebony + +/obj/structure/table/end/Initialize() + . = ..() + // we don't do frames or anything, just skip right to decon + tool_interaction_flags |= TOOL_INTERACTION_DECONSTRUCT + +/obj/structure/table/end/reinforce_table(obj/item/stack/material/S, mob/user) + return FALSE + +/obj/structure/table/end/finish_table(obj/item/stack/material/S, mob/user) + return FALSE + +/obj/structure/table/end/handle_default_screwdriver_attackby(mob/user, obj/item/screwdriver) + return FALSE + +/obj/structure/table/end/update_material_name(override_name) + SetName("[reinf_material.adjective_name] end table") + +/obj/structure/table/desk + name = "desk" + icon_state = "desk_left" + icon = 'icons/obj/structures/desk_large.dmi' + handle_generic_blending = FALSE + color = /decl/material/solid/organic/wood/walnut::color + material = /decl/material/solid/organic/wood/walnut + reinf_material = /decl/material/solid/organic/wood/walnut + storage = /datum/storage/structure/desk + bound_width = 64 + appearance_flags = /obj/structure/table::appearance_flags & ~TILE_BOUND + material_alteration = MAT_FLAG_ALTERATION_ALL + can_flip = FALSE + top_surface_noun = "desktop" + /// The pixel height at which point clicks start registering for the tabletop and not the drawers. + var/tabletop_height = 9 + +/obj/structure/table/desk/Initialize() + . = ..() + // we don't do frames or anything, just skip right to decon + tool_interaction_flags |= TOOL_INTERACTION_DECONSTRUCT + +/obj/structure/table/desk/handle_normal_icon() + return // logic is handled in on_update_icon + +/obj/structure/table/desk/right + icon_state = "desk_right" + +/obj/structure/table/desk/ebony + color = /decl/material/solid/organic/wood/ebony::color + material = /decl/material/solid/organic/wood/ebony + reinf_material = /decl/material/solid/organic/wood/ebony + +/obj/structure/table/desk/ebony/right + icon_state = "desk_right" + +/obj/structure/table/desk/update_material_name(override_name) + SetName("[reinf_material.adjective_name] desk") + +/obj/structure/table/desk/reinforce_table(obj/item/stack/material/S, mob/user) + return FALSE + +/obj/structure/table/desk/finish_table(obj/item/stack/material/S, mob/user) + return FALSE + +/obj/structure/table/desk/handle_default_screwdriver_attackby(mob/user, obj/item/screwdriver) + return FALSE + +/obj/structure/table/desk/on_update_icon() + . = ..() + if(storage) + if(storage.opened) + icon_state = "[initial(icon_state)]_open" + else + icon_state = initial(icon_state) + +/datum/storage/structure/desk + use_sound = null + open_sound = 'sound/foley/drawer-open.ogg' + close_sound = 'sound/foley/drawer-close.ogg' + max_storage_space = DEFAULT_BOX_STORAGE * 2 // two drawers! + +/datum/storage/structure/desk/can_be_inserted(obj/item/prop, mob/user, stop_messages = 0, click_params = null) + var/list/params = params2list(click_params) + var/obj/structure/table/desk/desk = holder + if(LAZYLEN(params) && text2num(params["icon-y"]) > desk.tabletop_height) + return FALSE // don't insert when clicking the tabletop + return ..() + +/datum/storage/structure/desk/play_open_sound() + . = ..() + flick("[initial(holder.icon_state)]_opening", holder) + +/datum/storage/structure/desk/play_close_sound() + . = ..() + flick("[initial(holder.icon_state)]_closing", holder) + +/obj/structure/table/desk/storage_inserted() + if(storage && !storage.opened) + playsound(src, 'sound/foley/drawer-oneshot.ogg', 50, FALSE, -5) + flick("[initial(icon_state)]_oneoff", src) + +/obj/structure/table/desk/dresser + icon = 'icons/obj/structures/dresser.dmi' + icon_state = "dresser" + bound_width = 32 + appearance_flags = /obj/structure/table::appearance_flags + top_surface_noun = "surface" + tabletop_height = 15 + mob_offset = 18 + +/obj/structure/table/desk/dresser/update_material_name(override_name) + SetName("[reinf_material.adjective_name] dresser") + +/obj/structure/table/desk/dresser/ebony + color = /decl/material/solid/organic/wood/ebony::color + material = /decl/material/solid/organic/wood/ebony + reinf_material = /decl/material/solid/organic/wood/ebony + +/datum/storage/structure/desk/dresser + max_storage_space = DEFAULT_BOX_STORAGE * 3 // THREE drawers! \ No newline at end of file diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index b458fd4a398e..25154a8f0036 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -1,113 +1,141 @@ -/obj/structure/dispenser - name = "tank storage unit" +/obj/structure/tank_rack + name = "tank rack" desc = "A simple yet bulky storage device for gas tanks. Has room for up to ten oxygen tanks, and ten hydrogen tanks." icon = 'icons/obj/structures/tank_dispenser.dmi' icon_state = "dispenser" - density = 1 - anchored = 1.0 - tool_interaction_flags = TOOL_INTERACTION_ANCHOR + density = TRUE + anchored = TRUE + material = /decl/material/solid/metal/steel + tool_interaction_flags = TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT + var/list/oxygen_tanks = 6 + var/list/hydrogen_tanks = 6 - var/oxygentanks = 10 - var/hydrogentanks = 10 - var/list/oxytanks = list() //sorry for the similar var names - var/list/hydtanks = list() +/obj/structure/tank_rack/Initialize() + . = ..() + + if(isnum(oxygen_tanks) && oxygen_tanks > 0) + var/spawn_oxy = oxygen_tanks + oxygen_tanks = list() + for(var/i in 1 to spawn_oxy) + oxygen_tanks += weakref(new /obj/item/tank/oxygen(src)) + else + oxygen_tanks = null -/obj/structure/dispenser/oxygen - hydrogentanks = 0 + if(isnum(hydrogen_tanks) && hydrogen_tanks > 0) + var/spawn_hyd = hydrogen_tanks + hydrogen_tanks = list() + for(var/i in 1 to spawn_hyd) + hydrogen_tanks += weakref(new /obj/item/tank/hydrogen(src)) + else + hydrogen_tanks = null -/obj/structure/dispenser/hydrogen - oxygentanks = 0 + update_icon() -/obj/structure/dispenser/Initialize() +/obj/structure/tank_rack/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - update_icon() + . += SPAN_NOTICE("It is holding [LAZYLEN(oxygen_tanks)] air tank\s and [LAZYLEN(hydrogen_tanks)] hydrogen tank\s.") -/obj/structure/dispenser/on_update_icon() - overlays.Cut() - switch(oxygentanks) - if(1 to 3) overlays += "oxygen-[oxygentanks]" - if(4 to INFINITY) overlays += "oxygen-4" - switch(hydrogentanks) - if(1 to 4) overlays += "hydrogen-[hydrogentanks]" - if(5 to INFINITY) overlays += "hydrogen-5" - -/obj/structure/dispenser/attack_ai(mob/user) - if(user.Adjacent(src)) - return attack_hand(user) +/obj/structure/tank_rack/Destroy() + QDEL_NULL_LIST(hydrogen_tanks) + QDEL_NULL_LIST(oxygen_tanks) + return ..() + +/obj/structure/tank_rack/dump_contents(atom/forced_loc = loc, mob/user) + hydrogen_tanks = null + oxygen_tanks = null + return ..() + +/obj/structure/tank_rack/on_update_icon() ..() -/obj/structure/dispenser/attack_hand(mob/user) - user.set_machine(src) - var/dat = "[src]

              " - dat += "Oxygen tanks: [oxygentanks] - [oxygentanks ? "Dispense" : "empty"]
              " - dat += "Hydrogen tanks: [hydrogentanks] - [hydrogentanks ? "Dispense" : "empty"]" - show_browser(user, dat, "window=dispenser") - onclose(user, "dispenser") - return + var/oxycount = LAZYLEN(oxygen_tanks) + switch(oxycount) + if(1 to 3) + add_overlay("oxygen-[oxycount]") + if(4 to INFINITY) + add_overlay("oxygen-4") + var/hydrocount = LAZYLEN(hydrogen_tanks) + switch(hydrocount) + if(1 to 4) + add_overlay("hydrogen-[hydrocount]") + if(5 to INFINITY) + add_overlay("hydrogen-5") -/obj/structure/dispenser/attackby(obj/item/I, mob/user) - . = ..() - if(!.) - if(istype(I, /obj/item/tank/oxygen) || istype(I, /obj/item/tank/air) || istype(I, /obj/item/tank/anesthetic)) - if(oxygentanks < 10) - if(!user.unEquip(I, src)) - return - oxytanks.Add(I) - oxygentanks++ - to_chat(user, "You put [I] in [src].") - if(oxygentanks < 5) - update_icon() - else - to_chat(user, "[src] is full.") - updateUsrDialog() - return - if(istype(I, /obj/item/tank/hydrogen)) - if(hydrogentanks < 10) - if(!user.unEquip(I, src)) - return - hydtanks.Add(I) - hydrogentanks++ - to_chat(user, "You put [I] in [src].") - if(oxygentanks < 6) - update_icon() - else - to_chat(user, "[src] is full.") - updateUsrDialog() - return - -/obj/structure/dispenser/Topic(href, href_list) - if(usr.stat || usr.restrained()) - return - if(Adjacent(usr)) - usr.set_machine(src) - if(href_list["oxygen"]) - if(oxygentanks > 0) - var/obj/item/tank/oxygen/O - if(oxytanks.len == oxygentanks) - O = oxytanks[1] - oxytanks.Remove(O) - else - O = new /obj/item/tank/oxygen(loc) - O.dropInto(loc) - to_chat(usr, "You take [O] out of [src].") - oxygentanks-- - update_icon() - if(href_list["hydrogen"]) - if(hydrogentanks > 0) - var/obj/item/tank/hydrogen/P - if(hydtanks.len == hydrogentanks) - P = hydtanks[1] - hydtanks.Remove(P) - else - P = new /obj/item/tank/hydrogen(loc) - P.dropInto(loc) - to_chat(usr, "You take [P] out of [src].") - hydrogentanks-- - update_icon() - add_fingerprint(usr) - updateUsrDialog() +/obj/structure/tank_rack/attack_robot(mob/user) + return attack_hand_with_interaction_checks(user) + +/obj/structure/tank_rack/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/list/dat = list() + var/oxycount = LAZYLEN(oxygen_tanks) + dat += "Oxygen tanks: [oxycount] - [oxycount ? "Dispense" : "empty"]
              " + var/hydrocount = LAZYLEN(hydrogen_tanks) + dat += "Hydrogen tanks: [hydrocount] - [hydrocount ? "Dispense" : "empty"]" + var/datum/browser/popup = new(user, "window=tank_rack") + popup.set_content(jointext(dat, "
              ")) + popup.open() + return TRUE + +/obj/structure/tank_rack/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/tank)) + + var/list/adding_to_list + if(istype(used_item, /obj/item/tank/oxygen) || istype(used_item, /obj/item/tank/air)) + LAZYINITLIST(oxygen_tanks) + adding_to_list = oxygen_tanks + else if(istype(used_item, /obj/item/tank/hydrogen)) + LAZYINITLIST(hydrogen_tanks) + adding_to_list = hydrogen_tanks + else + return ..() + + if(LAZYLEN(adding_to_list) >= 10) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + UNSETEMPTY(adding_to_list) + return TRUE + + if(!user.try_unequip(used_item, src)) + return TRUE + + LAZYADD(adding_to_list, weakref(used_item)) + to_chat(user, SPAN_NOTICE("You put [used_item] in [src].")) + update_icon() + attack_hand_with_interaction_checks(user) + return TRUE + return ..() + +/obj/structure/tank_rack/OnTopic(mob/user, href_list, datum/topic_state/state) + + var/list/remove_tank_from + if(href_list["oxygen"]) + remove_tank_from = oxygen_tanks + else if(href_list["hydrogen"]) + remove_tank_from = hydrogen_tanks else - close_browser(usr, "window=dispenser") - return - return + return TOPIC_NOACTION + + if(LAZYLEN(remove_tank_from)) + var/weakref/tankref = remove_tank_from[length(remove_tank_from)] + LAZYREMOVE(remove_tank_from, tankref) + var/obj/item/tank/O = tankref?.resolve() + if(istype(O) && !QDELETED(O) && O.loc == src) + O.dropInto(loc) + to_chat(user, SPAN_NOTICE("You take \the [O] out of \the [src].")) + update_icon() + attack_hand_with_interaction_checks(user) + return TOPIC_REFRESH + +/* + * Mappable subtypes. + */ +/obj/structure/tank_rack/oxygen + hydrogen_tanks = 0 + +/obj/structure/tank_rack/hydrogen + oxygen_tanks = 0 + +/obj/structure/tank_rack/empty + hydrogen_tanks = 0 + oxygen_tanks = 0 diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm index 78b26d50913e..b1e25a0f4dce 100644 --- a/code/game/objects/structures/target_stake.dm +++ b/code/game/objects/structures/target_stake.dm @@ -1,46 +1,89 @@ -// Target stakes for the firing range. +// TODO: skill check on melee/ranged hit to show bullseye/heart shot/etc /obj/structure/target_stake - name = "target stake" - desc = "A thin platform with negatively-magnetized wheels." - icon = 'icons/obj/objects.dmi' - icon_state = "target_stake" - density = 1 - obj_flags = OBJ_FLAG_CONDUCTIBLE - var/obj/item/target/pinned_target - -/obj/structure/target_stake/attackby(var/obj/item/W, var/mob/user) - if (!pinned_target && istype(W, /obj/item/target) && user.unEquip(W, get_turf(src))) - to_chat(user, "You slide [W] into the stake.") - set_target(W) - -/obj/structure/target_stake/attack_hand(var/mob/user) - . = ..() - if (pinned_target && ishuman(user)) - var/obj/item/target/T = pinned_target - to_chat(user, "You take [T] out of the stake.") - set_target(null) - user.put_in_hands(T) - -/obj/structure/target_stake/proc/set_target(var/obj/item/target/T) - if (T) - set_density(0) - T.set_density(1) - T.pixel_x = 0 - T.pixel_y = 0 - T.layer = ABOVE_OBJ_LAYER - GLOB.moved_event.register(T, src, /atom/movable/proc/move_to_turf) - GLOB.moved_event.register(src, T, /atom/movable/proc/move_to_turf) - T.stake = src - pinned_target = T - else - set_density(1) - pinned_target.set_density(0) - pinned_target.layer = OBJ_LAYER - GLOB.moved_event.unregister(pinned_target, src) - GLOB.moved_event.unregister(src, pinned_target) - pinned_target.stake = null - pinned_target = null + name = "target stake" + desc = "A simple stand used to prop up a target for practice." + icon = 'icons/obj/structures/target_stakes/target_stake.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + structure_flags = STRUCTURE_FLAG_THROWN_DAMAGE + var/obj/item/training_dummy/dummy + +/obj/structure/target_stake/proc/set_dummy(obj/item/training_dummy/new_dummy) + dummy = new_dummy + if(dummy) + dummy.reset_offsets() + queue_icon_update() + queue_vis_contents_update() /obj/structure/target_stake/Destroy() + set_dummy(null) + . = ..() + +/obj/structure/target_stake/take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health) + if(dummy) + . = dummy.take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health) + if(QDELETED(dummy)) + set_dummy(null) + update_icon() + return + return ..() + +/obj/structure/target_stake/proc/can_hold_dummy(mob/user, obj/item/training_dummy/new_dummy) + return istype(new_dummy) && !istype(new_dummy, /obj/item/training_dummy/straw/archery) + +/obj/structure/target_stake/attack_hand(mob/user) + if(dummy) + dummy.dropInto(loc) + user.put_in_hands(dummy) + set_dummy(null) + return TRUE + return ..() + +/obj/structure/target_stake/attackby(obj/item/used_item, mob/user) + if(dummy?.repair_target_dummy(used_item, user)) + return TRUE + if(user.check_intent(I_FLAG_HARM) && dummy?.attackby(used_item, user)) + return TRUE + if(istype(used_item, /obj/item/training_dummy) && can_hold_dummy(user, used_item)) + if(dummy) + to_chat(user, SPAN_WARNING("\The [src] is already holding \the [dummy].")) + else if(user.try_unequip(used_item, src)) + set_dummy(used_item) + visible_message(SPAN_NOTICE("\The [user] places \the [dummy] onto \the [src].")) + return TRUE + return ..() + +/obj/structure/target_stake/Initialize(ml, _mat, _reinf_mat) + if(ispath(dummy)) + set_dummy(new dummy(src)) . = ..() - set_target(null) \ No newline at end of file + +/obj/structure/target_stake/get_vis_contents_to_add() + . = ..() + LAZYADD(., dummy) + +// Subtypes below. +/obj/structure/target_stake/steel + material = /decl/material/solid/metal/steel + +/obj/structure/target_stake/archery + name = "archery butt" + desc = "A heavy circular target used for practicing archery." + icon = 'icons/obj/structures/target_stakes/archery_butt.dmi' + +/obj/structure/target_stake/archery/can_hold_dummy(mob/user, obj/item/training_dummy/new_dummy) + return istype(new_dummy, /obj/item/training_dummy/straw/archery) + +// Subtypes with/for dummies. +/obj/structure/target_stake/mapped + dummy = /obj/item/training_dummy/straw + +/obj/structure/target_stake/steel/mapped/Initialize() + dummy = pick(/obj/item/training_dummy, /obj/item/training_dummy/alien, /obj/item/training_dummy/syndicate) + return ..() + +/obj/structure/target_stake/archery/mapped + dummy = /obj/item/training_dummy/straw/archery diff --git a/code/game/objects/structures/town_bell.dm b/code/game/objects/structures/town_bell.dm new file mode 100644 index 000000000000..45cb1f484511 --- /dev/null +++ b/code/game/objects/structures/town_bell.dm @@ -0,0 +1,104 @@ +/obj/structure/town_bell + name = "town bell" + desc = "A heavy bell on a strong brace. It looks loud enough to reach the entire surrounding area." + icon = 'icons/obj/structures/town_bell.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + opacity = FALSE + density = TRUE + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + material_alteration = MAT_FLAG_ALTERATION_COLOR + + var/near_sound = 'sound/effects/bell_near.ogg' + var/far_sound = 'sound/effects/bell_far.ogg' + var/next_ring = 0 + var/ring_cooldown = 1 MINUTE + var/decl/material/bell_material = /decl/material/solid/metal/bronze + +/obj/structure/town_bell/Initialize(mapload) + if(bell_material) + LAZYSET(matter, bell_material, MATTER_AMOUNT_REINFORCEMENT) + . = ..() + update_icon() + +/obj/structure/town_bell/update_material_desc(override_desc) + . = ..() + if(material && bell_material) + var/decl/material/bell_mat_decl = GET_DECL(bell_material) + desc += " The frame is made of [material.solid_name] and the bell has been cast from [bell_mat_decl.solid_name]." + +/obj/structure/town_bell/on_update_icon() + . = ..() + if(bell_material) + var/bell_state = "[icon_state]-bell" + if(world.time < next_ring) + bell_state = "[bell_state]-ringing" + if(check_state_in_icon(bell_state, icon)) + add_overlay(overlay_image(icon, bell_state, bell_material::color, RESET_COLOR)) + +/obj/structure/town_bell/proc/can_be_rung(mob/user) + if(!isturf(loc) || !z) + return FALSE + if(world.time < next_ring) + if(user) + to_chat(user, SPAN_WARNING("\The [src] cannot be rung again so soon.")) + return FALSE + return TRUE + +/obj/structure/town_bell/attackby(obj/item/used_item, mob/user) + . = ..() + if(used_item.expend_attack_force()) + ding_dong() + +/obj/structure/town_bell/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + if(!can_be_rung(user)) + return TRUE + var/choice = alert(user, "Are you sure you wish to ring \the [src]? The entire region will be notified.", "Ring Bell", "No", "Yes") + if(QDELETED(src) || QDELETED(user) || choice != "Yes" || !user.Adjacent(src) || !can_be_rung(user)) + return TRUE + visible_message(SPAN_NOTICE("\The [user] rings \the [src], sending its sonorous tones rolling across the region.")) + ding_dong() + return TRUE + +/obj/structure/town_bell/proc/play_near_sound() + set waitfor = FALSE + playsound(loc, near_sound, 80, 0) + sleep(3 SECONDS) + if(QDELETED(src) || !isturf(loc)) + return + playsound(loc, near_sound, 80, 0) + sleep(3 SECONDS) + if(QDELETED(src) || !isturf(loc)) + return + playsound(loc, near_sound, 80, 0) + +/obj/structure/town_bell/proc/play_far_sound(mob/listener) + set waitfor = FALSE + listener.playsound_local(loc, far_sound, 100) + sleep(3 SECONDS) + if(QDELETED(src) || QDELETED(listener) || !isturf(loc)) + return + listener.playsound_local(loc, far_sound, 100) + sleep(3 SECONDS) + if(QDELETED(src) || QDELETED(listener) || !isturf(loc)) + return + listener.playsound_local(loc, far_sound, 100) + +/obj/structure/town_bell/proc/ding_dong() + if(!can_be_rung()) + return + next_ring = world.time + ring_cooldown + update_icon() + play_near_sound() + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, queue_icon_update)), ring_cooldown) + var/list/affected_zs = SSmapping.get_connected_levels(z) + for(var/client/player) + var/turf/player_turf = get_turf(player.mob) + if(!istype(player_turf) || !(player_turf.z in affected_zs) || player.mob.is_deaf()) + continue + if(src in view(player.mob, world.view)) + continue + play_far_sound(player.mob) + to_chat(player, SPAN_NOTICE("You hear the sonorous ringing of the town bell coming from \the [get_dir_z_text(player_turf, loc)].")) diff --git a/code/game/objects/structures/transit_tubes.dm b/code/game/objects/structures/transit_tubes.dm index 82102692c0f8..8c98af230f7a 100644 --- a/code/game/objects/structures/transit_tubes.dm +++ b/code/game/objects/structures/transit_tubes.dm @@ -6,9 +6,9 @@ /obj/structure/transit_tube icon = 'icons/obj/pipes/transit_tube.dmi' icon_state = "E-W" - density = 1 + density = TRUE layer = ABOVE_HUMAN_LAYER - anchored = 1.0 + anchored = TRUE var/list/tube_dirs = null var/exit_delay = 2 var/enter_delay = 1 @@ -17,7 +17,7 @@ // the specific order matters to get a usable icon_state, it is // copied here so that, in the unlikely case that alldirs is changed, // this continues to work. - var/global/list/tube_dir_list = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) + var/static/list/tube_dir_list = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) // A place where tube pods stop, and people can get in or out. @@ -40,23 +40,27 @@ icon = 'icons/obj/pipes/transit_tube_pod.dmi' icon_state = "pod" animate_movement = FORWARD_STEPS - anchored = 1.0 - density = 1 + anchored = TRUE + density = TRUE var/moving = 0 var/datum/gas_mixture/air_contents = new() - +/obj/structure/transit_tube_pod/attack_hand(mob/user) + if(!moving && length(contents) && isturf(user.loc)) + user.visible_message(SPAN_NOTICE("\The [user] empties out \the [src]!")) + dump_contents() + return TRUE + return ..() /obj/structure/transit_tube_pod/Destroy() - for(var/atom/movable/AM in contents) - AM.dropInto(loc) - - ..() + dump_contents() + return ..() /obj/structure/transit_tube_pod/Initialize() . = ..() - air_contents.adjust_multi(/decl/material/gas/oxygen, MOLES_O2STANDARD * 2, /decl/material/gas/nitrogen, MOLES_N2STANDARD) + air_contents.adjust_gas(/decl/material/gas/oxygen, MOLES_O2STANDARD * 2, FALSE) + air_contents.adjust_gas(/decl/material/gas/nitrogen, MOLES_N2STANDARD, TRUE) air_contents.temperature = T20C // Give auto tubes time to align before trying to start moving @@ -76,32 +80,31 @@ /obj/structure/transit_tube/Bumped(mob/AM) var/obj/structure/transit_tube/T = locate() in AM.loc if(T) - to_chat(AM, "The tube's support pylons block your way.") + to_chat(AM, SPAN_WARNING("The tube's support pylons block your way.")) return ..() else AM.dropInto(loc) - to_chat(AM, "You slip under the tube.") + to_chat(AM, SPAN_INFO("You slip under the tube.")) /obj/structure/transit_tube/station/Bumped(mob/AM) - if(!pod_moving && icon_state == "open" && istype(AM, /mob)) + if(!pod_moving && icon_state == "open" && ismob(AM)) for(var/obj/structure/transit_tube_pod/pod in loc) if(pod.contents.len) - to_chat(AM, "The pod is already occupied.") + to_chat(AM, SPAN_NOTICE("The pod is already occupied.")) return else if(!pod.moving && (pod.dir in directions())) AM.forceMove(pod) /obj/structure/transit_tube/station/attack_hand(mob/user) - if(!pod_moving) - for(var/obj/structure/transit_tube_pod/pod in loc) - if(!pod.moving && (pod.dir in directions())) - if(icon_state == "closed") - open_animation() - - else if(icon_state == "open") - close_animation() - - + if(pod_moving || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + for(var/obj/structure/transit_tube_pod/pod in loc) + if(!pod.moving && (pod.dir in directions())) + if(icon_state == "closed") + open_animation() + else if(icon_state == "open") + close_animation() + return TRUE /obj/structure/transit_tube/station/proc/open_animation() if(icon_state == "closed") @@ -310,7 +313,7 @@ do sleep(last_delay) - if(!istype(loc, /turf/space)) + if(!isspaceturf(loc)) last_delay++ if(last_delay > 10) @@ -344,17 +347,13 @@ // the station, try to exit. If the direction matches one of the station's // tube directions, launch the pod in that direction. /obj/structure/transit_tube_pod/relaymove(mob/mob, direction) - if(istype(mob, /mob) && mob.client) + if(ismob(mob) && mob.client) // If the pod is not in a tube at all, you can get out at any time. if(!(locate(/obj/structure/transit_tube) in loc)) var/turf/T = get_turf(src) mob.forceMove(T) mob.client.Move(get_step(T, direction), direction) - //if(moving && istype(loc, /turf/space)) - // Todo: If you get out of a moving pod in space, you should move as well. - // Same direction as pod? Direcion you moved? Halfway between? - if(!moving) for(var/obj/structure/transit_tube/station/station in loc) if(dir in station.directions()) @@ -382,7 +381,7 @@ // Parse the icon_state into a list of directions. -// This means that mappers can use Dream Maker's built in +// This means that mappers can use Dream Maker's built-in // "Generate Instances from Icon-states" option to get all // variations. Additionally, as a separate proc, sub-types // can handle it more intelligently. @@ -503,7 +502,7 @@ // but it is probably safer to assume the existence of, and // rely on, a sufficiently smart compiler/optimizer. /obj/structure/transit_tube/proc/parse_dirs(text) - var/global/list/direction_table = list() + var/static/list/direction_table = list() if(text in direction_table) return direction_table[text] @@ -551,7 +550,7 @@ if("SOUTHWEST", "SW") return 10 else - return 0 + return 0 @@ -576,4 +575,4 @@ if(10) return "SW" else - return + return diff --git a/code/game/objects/structures/travois.dm b/code/game/objects/structures/travois.dm new file mode 100644 index 000000000000..324972fbba5f --- /dev/null +++ b/code/game/objects/structures/travois.dm @@ -0,0 +1,27 @@ +/* + * Travois used to drag mobs in low-tech settings. + */ +/obj/structure/travois + name = "travois" + desc = "An assemblage of sticks, commonly used to make it easier to transport animal carcasses." + anchored = FALSE + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/structures/travois.dmi' + can_buckle = TRUE + buckle_dir = SOUTH + buckle_lying = TRUE + buckle_sound = 'sound/effects/buckle.ogg' + buckle_pixel_shift = list("x" = 0, "y" = 0, "z" = 6) + obj_flags = OBJ_FLAG_SUPPORT_MOB + movable_flags = MOVABLE_FLAG_WHEELED + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + user_comfort = 0 + parts_amount = 1 + parts_type = /obj/item/stack/material/log + material_alteration = MAT_FLAG_ALTERATION_ALL + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + +/obj/structure/travois/walnut + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color \ No newline at end of file diff --git a/code/game/objects/structures/under_wardrobe.dm b/code/game/objects/structures/under_wardrobe.dm index 756ccfea9262..a440ae1b8806 100644 --- a/code/game/objects/structures/under_wardrobe.dm +++ b/code/game/objects/structures/under_wardrobe.dm @@ -8,12 +8,14 @@ density = TRUE var/static/list/amount_of_underwear_by_id_card -/obj/structure/undies_wardrobe/attackby(var/obj/item/underwear/underwear, var/mob/user) - if(istype(underwear)) - if(!user.unEquip(underwear)) - return +/obj/structure/undies_wardrobe/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/underwear)) + var/obj/item/underwear/underwear = used_item + if(!user.try_unequip(underwear)) + return TRUE qdel(underwear) - user.visible_message("\The [user] inserts \their [underwear.name] into \the [src].", "You insert your [underwear.name] into \the [src].") + var/decl/pronouns/user_pronouns = user.get_pronouns() + user.visible_message("\The [user] inserts [user_pronouns.his] [underwear.name] into \the [src].", "You insert your [underwear.name] into \the [src].") var/id = user.GetIdCard() var/message @@ -27,37 +29,37 @@ var/number_of_underwear = LAZYACCESS(amount_of_underwear_by_id_card, id) - 1 if(number_of_underwear) LAZYSET(amount_of_underwear_by_id_card, id, number_of_underwear) - GLOB.destroyed_event.register(id, src, /obj/structure/undies_wardrobe/proc/remove_id_card) + events_repository.register(/decl/observ/destroyed, id, src, TYPE_PROC_REF(/obj/structure/undies_wardrobe, remove_id_card)) else remove_id_card(id) - + return TRUE else - ..() + return ..() /obj/structure/undies_wardrobe/proc/remove_id_card(var/id_card) LAZYREMOVE(amount_of_underwear_by_id_card, id_card) - GLOB.destroyed_event.unregister(id_card, src, /obj/structure/undies_wardrobe/proc/remove_id_card) + events_repository.unregister(/decl/observ/destroyed, id_card, src, TYPE_PROC_REF(/obj/structure/undies_wardrobe, remove_id_card)) /obj/structure/undies_wardrobe/attack_hand(var/mob/user) if(!human_who_can_use_underwear(user)) - to_chat(user, "Sadly there's nothing in here for you to wear.") - return + return ..() interact(user) + return TRUE -/obj/structure/undies_wardrobe/interact(var/mob/living/carbon/human/H) +/obj/structure/undies_wardrobe/interact(var/mob/living/human/H) var/id = H.GetIdCard() var/dat = list() dat += "Underwear

              " - dat += "You may claim [id ? length(GLOB.underwear.categories) - LAZYACCESS(amount_of_underwear_by_id_card, id) : 0] more article\s this shift.

              " + dat += "You may claim [id ? length(global.underwear.categories) - LAZYACCESS(amount_of_underwear_by_id_card, id) : 0] more article\s this shift.

              " dat += "Available Categories

              " - for(var/datum/category_group/underwear/UWC in GLOB.underwear.categories) - dat += "[UWC.name] (Select)
              " + for(var/datum/category_group/underwear/UWC in global.underwear.categories) + dat += "[UWC.name] (Select)
              " dat = jointext(dat,null) show_browser(H, dat, "window=wardrobe;size=400x250") -/obj/structure/undies_wardrobe/proc/human_who_can_use_underwear(var/mob/living/carbon/human/H) - if(!istype(H) || !H.species || !(H.species.appearance_flags & HAS_UNDERWEAR)) +/obj/structure/undies_wardrobe/proc/human_who_can_use_underwear(var/mob/living/human/H) + if(!istype(H) || !(H.get_bodytype()?.appearance_flags & HAS_UNDERWEAR)) return FALSE return TRUE @@ -67,51 +69,46 @@ return ..() -/obj/structure/undies_wardrobe/Topic(href, href_list, state) - if(..()) - return TRUE +/obj/structure/undies_wardrobe/OnTopic(mob/user, href_list, state) + if((. = ..())) + return - var/mob/living/carbon/human/H = usr if(href_list["select_underwear"]) - var/datum/category_group/underwear/UWC = GLOB.underwear.categories_by_name[href_list["select_underwear"]] + var/datum/category_group/underwear/UWC = global.underwear.categories_by_name[href_list["select_underwear"]] if(!UWC) - return - var/datum/category_item/underwear/UWI = input("Select your desired underwear:", "Choose underwear") as null|anything in exlude_none(UWC.items) + return TOPIC_HANDLED + var/datum/category_item/underwear/UWI = input(user, "Select your desired underwear:", "Choose underwear") as null|anything in exclude_none(UWC.items) if(!UWI) - return + return TOPIC_HANDLED var/list/metadata_list = list() for(var/tweak in UWI.tweaks) var/datum/gear_tweak/gt = tweak - var/metadata = gt.get_metadata(H, title = "Adjust underwear") + var/metadata = gt.get_metadata(user, title = "Adjust underwear") if(!metadata) - return + return TOPIC_HANDLED metadata_list["[gt]"] = metadata - if(!CanInteract(H, state)) - return + if(!CanInteract(user, state)) + return TOPIC_HANDLED - var/id = H.GetIdCard() + var/id = user.GetIdCard() if(!id) - audible_message("No ID card detected. Unable to acquire your underwear quota for this shift.", WARDROBE_BLIND_MESSAGE(H)) - return + audible_message("No ID card detected. Unable to acquire your underwear quota for this shift.", WARDROBE_BLIND_MESSAGE(user)) + return TOPIC_HANDLED var/current_quota = LAZYACCESS(amount_of_underwear_by_id_card, id) - if(current_quota >= length(GLOB.underwear.categories)) - audible_message("You have already used up your underwear quota for this shift. Please return previously acquired items to increase it.", WARDROBE_BLIND_MESSAGE(H)) - return + if(current_quota >= length(global.underwear.categories)) + audible_message("You have already used up your underwear quota for this shift. Please return previously acquired items to increase it.", WARDROBE_BLIND_MESSAGE(user)) + return TOPIC_HANDLED LAZYSET(amount_of_underwear_by_id_card, id, ++current_quota) - var/obj/UW = UWI.create_underwear(H, metadata_list) - UW.forceMove(loc) - H.put_in_hands(UW) - - . = TRUE - - if(.) - interact(H) + var/obj/UW = UWI.create_underwear(user, metadata_list) + UW.dropInto(loc) + user.put_in_hands(UW) + . = TOPIC_REFRESH -/obj/structure/undies_wardrobe/proc/exlude_none(var/list/L) +/obj/structure/undies_wardrobe/proc/exclude_none(var/list/L) . = L.Copy() for(var/e in .) var/datum/category_item/underwear/UWI = e diff --git a/code/game/objects/structures/wall_cabinet.dm b/code/game/objects/structures/wall_cabinet.dm new file mode 100644 index 000000000000..3cc7b07bcc55 --- /dev/null +++ b/code/game/objects/structures/wall_cabinet.dm @@ -0,0 +1,35 @@ +// A wall-mounted storage object. +/obj/structure/wall_cabinet + name = "cabinet" + desc = "A wall-mounted cabinet used to store various goods and sundries, and also make use of all that wasted wall-space." + icon = 'icons/obj/structures/furniture/cabinet_duo.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + layer = ABOVE_HUMAN_LAYER + material_alteration = MAT_FLAG_ALTERATION_ALL + directional_offset = @'{"NORTH":{"y":-1},"SOUTH":{"y":24}}' + storage = /datum/storage/wall_cabinet + +/obj/structure/wall_cabinet/on_update_icon() + . = ..() + if(storage?.opened) + // todo: door material? glass cabinet doors could be interesting if we add a 'full' sprite + var/image/open_overlay = overlay_image(icon, "[icon_state]_open", get_color(), RESET_COLOR|KEEP_APART) + open_overlay.layer = ABOVE_HUMAN_LAYER + 0.005 + add_overlay(open_overlay) + +/datum/storage/wall_cabinet + max_storage_space = BASE_STORAGE_CAPACITY(ITEM_SIZE_GARGANTUAN) // smaller than structure fwiw + open_sound = 'sound/foley/drawer-open.ogg' + close_sound = 'sound/foley/drawer-close.ogg' + +/obj/structure/wall_cabinet/walnut + color = /decl/material/solid/organic/wood/walnut::color + material = /decl/material/solid/organic/wood/walnut + reinf_material = /decl/material/solid/organic/wood/walnut + +/obj/structure/wall_cabinet/ebony + color = /decl/material/solid/organic/wood/ebony::color + material = /decl/material/solid/organic/wood/ebony + reinf_material = /decl/material/solid/organic/wood/ebony \ No newline at end of file diff --git a/code/game/objects/structures/wall_frame.dm b/code/game/objects/structures/wall_frame.dm index 8adc39cb2dbb..21bf8027cd36 100644 --- a/code/game/objects/structures/wall_frame.dm +++ b/code/game/objects/structures/wall_frame.dm @@ -6,22 +6,23 @@ desc = "A low wall section which serves as the base of windows, amongst other things." icon = 'icons/obj/structures/wall_frame.dmi' icon_state = "frame" - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE - anchored = 1 - density = 1 + atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_CAN_BE_PAINTED | ATOM_FLAG_ADJACENT_EXCEPTION + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + anchored = TRUE + density = TRUE throwpass = 1 layer = TABLE_LAYER rad_resistance_modifier = 0.5 material = DEFAULT_WALL_MATERIAL handle_generic_blending = TRUE tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) - maxhealth = 100 - - var/paint_color + max_health = 40 + parts_amount = 2 + parts_type = /obj/item/stack/material/rods var/stripe_color var/list/connections var/list/other_connections - + /obj/structure/wall_frame/clear_connections() connections = null other_connections = null @@ -40,50 +41,50 @@ update_connections(1) update_icon() -/obj/structure/wall_frame/examine(mob/user) +/obj/structure/wall_frame/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(paint_color) - to_chat(user, SPAN_NOTICE("It has a smooth coat of paint applied.")) + . += SPAN_NOTICE("It has a smooth coat of paint applied.") -/obj/structure/wall_frame/show_examined_damage(mob/user, var/perc) - if(maxhealth == -1) +/obj/structure/wall_frame/get_examined_damage_string() + if(!can_take_damage()) return - if(perc > 0.7) - to_chat(user, SPAN_NOTICE("It's got a few dents and scratches.")) - else if(perc > 0.3) - to_chat(user, SPAN_WARNING("A few pieces of panelling have fallen off.")) + var/health_percent = get_percent_health() + if(health_percent > 70) + return SPAN_NOTICE("It's got a few dents and scratches.") + else if(health_percent > 30) + return SPAN_WARNING("A few pieces of panelling have fallen off.") else - to_chat(user, SPAN_DANGER("It's nearly falling to pieces.")) - -/obj/structure/wall_frame/attackby(var/obj/item/W, var/mob/user) + return SPAN_DANGER("It's nearly falling to pieces.") +/obj/structure/wall_frame/attackby(var/obj/item/used_item, var/mob/user) . = ..() if(!.) //grille placing - if(istype(W, /obj/item/stack/material/rods)) + if(istype(used_item, /obj/item/stack/material/rods)) for(var/obj/structure/window/WINDOW in loc) if(WINDOW.dir == get_dir(src, user)) to_chat(user, SPAN_WARNING("There is a window in the way.")) return TRUE - place_grille(user, loc, W) + place_grille(user, loc, used_item) return TRUE //window placing - if(istype(W,/obj/item/stack/material)) - var/obj/item/stack/material/ST = W + if(istype(used_item,/obj/item/stack/material)) + var/obj/item/stack/material/ST = used_item if(ST.material.opacity <= 0.7) place_window(user, loc, SOUTHWEST, ST) return TRUE - if(istype(W, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = W + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item if(!cutter.slice(user)) return playsound(src.loc, 'sound/items/Welder.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] begins slicing through \the [src] with \the [W].")) + visible_message(SPAN_NOTICE("\The [user] begins slicing through \the [src] with \the [used_item].")) if(do_after(user, 20,src)) - visible_message(SPAN_NOTICE("\The [user] slices \the [src] apart with \the [W].")) - dismantle() + visible_message(SPAN_NOTICE("\The [user] slices \the [src] apart with \the [used_item].")) + dismantle_structure(user) return TRUE /obj/structure/wall_frame/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) @@ -93,38 +94,35 @@ if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) return 1 -// icon related - /obj/structure/wall_frame/on_update_icon() - overlays.Cut() + ..() var/image/I - - var/new_color = (paint_color ? paint_color : material.color) - color = new_color + var/new_color = stripe_color ? stripe_color : material.color for(var/i = 1 to 4) var/conn = connections ? connections[i] : "0" if(other_connections && other_connections[i] != "0") - I = image(icon, "frame_other[conn]", dir = 1<<(i-1)) + I = image(icon, "frame_other[conn]", dir = BITFLAG(i-1)) else - I = image(icon, "frame[conn]", dir = 1<<(i-1)) - overlays += I - - if(stripe_color) - for(var/i = 1 to 4) - var/conn = connections ? connections[i] : "0" - if(other_connections && other_connections[i] != "0") - I = image(icon, "stripe_other[conn]", dir = 1<<(i-1)) - else - I = image(icon, "stripe[conn]", dir = 1<<(i-1)) - I.color = stripe_color - overlays += I + I = image(icon, "frame[conn]", dir = BITFLAG(i-1)) + I.color = new_color + add_overlay(I) + +/obj/structure/wall_frame/proc/paint_wall_frame(var/new_paint_color) + paint_color = new_paint_color + update_icon() + + +/obj/structure/wall_frame/proc/stripe_wall_frame(var/new_paint_color) + stripe_color = new_paint_color + update_icon() + /obj/structure/wall_frame/hull/Initialize() . = ..() if(prob(40)) var/spacefacing = FALSE - for(var/direction in GLOB.cardinal) + for(var/direction in global.cardinal) var/turf/T = get_step(src, direction) var/area/A = get_area(T) if(A && (A.area_flags & AREA_FLAG_EXTERNAL)) @@ -138,28 +136,49 @@ /obj/structure/wall_frame/bullet_act(var/obj/item/projectile/Proj) var/proj_damage = Proj.get_structure_damage() var/damage = min(proj_damage, 100) - take_damage(damage) + take_damage(damage, Proj.atom_damage_type) return -/obj/structure/wall_frame/hitby(AM, var/datum/thrownthing/TT) - ..() - var/tforce = 0 - if(ismob(AM)) // All mobs have a multiplier and a size according to mob_defines.dm - var/mob/I = AM - tforce = I.mob_size * (TT.speed/THROWFORCE_SPEED_DIVISOR) - else - var/obj/O = AM - tforce = O.throwforce * (TT.speed/THROWFORCE_SPEED_DIVISOR) - if (tforce < 15) - return - take_damage(tforce) +/obj/structure/wall_frame/hitby(atom/movable/AM, var/datum/thrownthing/TT) + . = ..() + if(.) + var/tforce = AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR) + if (tforce < 15) + return + take_damage(tforce) //Subtypes /obj/structure/wall_frame/standard paint_color = COLOR_WALL_GUNMETAL + stripe_color = COLOR_GUNMETAL /obj/structure/wall_frame/titanium - material = /decl/material/solid/metal/plasteel/titanium + material = /decl/material/solid/metal/titanium /obj/structure/wall_frame/hull - paint_color = COLOR_HULL \ No newline at end of file + paint_color = COLOR_HULL + stripe_color = COLOR_HULL + +/obj/structure/wall_frame/log + name = "low log wall" + desc = "A section of log wall with empty space for fitting a window or simply letting air in." + icon = 'icons/obj/structures/log_wall_frame.dmi' + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC // material color is applied in on_update_icon + +/obj/structure/wall_frame/log/Initialize() + color = null // clear mapping preview color + . = ..() + +#define LOW_LOG_WALL_SUBTYPE(material_name) \ +/obj/structure/wall_frame/log/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ + color = /decl/material/solid/organic/wood/##material_name::color; \ +} + +LOW_LOG_WALL_SUBTYPE(fungal) +LOW_LOG_WALL_SUBTYPE(ebony) +LOW_LOG_WALL_SUBTYPE(walnut) +LOW_LOG_WALL_SUBTYPE(maple) +LOW_LOG_WALL_SUBTYPE(mahogany) +LOW_LOG_WALL_SUBTYPE(bamboo) +LOW_LOG_WALL_SUBTYPE(yew) \ No newline at end of file diff --git a/code/game/objects/structures/wall_sconce.dm b/code/game/objects/structures/wall_sconce.dm new file mode 100644 index 000000000000..c87951094585 --- /dev/null +++ b/code/game/objects/structures/wall_sconce.dm @@ -0,0 +1,140 @@ +// Temporary held item. +/obj/item/wall_sconce + name = "wall sconce" + desc = "A simple metal loop suitable for holding a torch, lantern or candle." + icon = 'icons/obj/items/wall_sconce.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/iron + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + max_health = 100 + w_class = ITEM_SIZE_LARGE + +/obj/item/wall_sconce/use_on_mob(mob/living/target, mob/living/user, var/target_zone) + return FALSE + +/obj/item/wall_sconce/afterattack(var/atom/A, var/mob/user, var/proximity) + if(proximity && isturf(A) && A.density && user.try_unequip(src)) + new /obj/structure/wall_sconce(get_turf(user), material?.type, null, get_dir(user, A)) + qdel(src) + return TRUE + return ..() + +/obj/structure/wall_sconce + name = "wall sconce" + desc = "A simple metal loop suitable for holding a torch, lantern or candle." + icon = 'icons/obj/structures/wall_sconce.dmi' + icon_state = ICON_STATE_WORLD + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/metal/iron + max_health = 100 + w_class = ITEM_SIZE_LARGE + directional_offset = @'{"NORTH":{"y":24}, "SOUTH":{"y":-1}, "EAST":{"x":10,"y":10}, "WEST":{"x":-10,"y":10}}' + layer = ABOVE_HUMAN_LAYER + anchored = TRUE + /// Reference to the currently attached item. + var/obj/item/flame/light_source + /// Whether or not the light source, if present, is automatically lit on Initialize. + var/start_lit = FALSE + +/obj/structure/wall_sconce/Initialize(var/ml, var/_mat, var/_reinf_mat, var/supplied_dir) + + if(ispath(light_source)) + light_source = new light_source(src) + if(start_lit && istype(light_source)) + light_source.light(null, no_message = TRUE) + + . = ..() + + if(supplied_dir) + set_dir(supplied_dir) + else if(isturf(loc)) + for(var/step_dir in global.cardinal) + var/turf/neighbor = get_step_resolving_mimic(loc, step_dir) + if(istype(neighbor) && neighbor.density) + set_dir(step_dir) + break + +/obj/structure/wall_sconce/Destroy() + QDEL_NULL(light_source) + return ..() + +/obj/structure/wall_sconce/ignite_fire() + . = ..() + update_icon() + +/obj/structure/wall_sconce/physically_destroyed() + if(light_source) + light_source.dropInto(loc) + light_source = null + return ..() + +/obj/structure/wall_sconce/create_dismantled_products(var/turf/T) + SHOULD_CALL_PARENT(FALSE) + if(light_source) + light_source.dropInto(loc) + light_source = null + return list(new /obj/item/wall_sconce(T, material?.type)) + +/obj/structure/wall_sconce/attack_hand(mob/user) + + if(light_source) + user.put_in_hands(light_source) + user.visible_message(SPAN_NOTICE("\The [user] takes \the [light_source] from \the [src].")) + light_source = null + update_icon() + return TRUE + + return ..() + +/obj/structure/wall_sconce/attackby(obj/item/used_item, mob/user) + + if(user.check_intent(I_FLAG_HARM)) + return ..() + + if(IS_HAMMER(used_item) || IS_WRENCH(used_item)) + dismantle_structure(user) + return TRUE + + if(used_item.isflamesource() && light_source && !light_source.lit) + light_source.attackby(used_item, user) + update_icon() + return TRUE + + if(istype(used_item, /obj/item/flame)) + var/obj/item/flame/flame = used_item + if(flame.sconce_can_hold) + + if(light_source) + to_chat(user, SPAN_WARNING("\The [src] is already occupied by \the [light_source].")) + return TRUE + + if(user.try_unequip(flame, src)) + user.visible_message(SPAN_NOTICE("\The [user] puts \the [flame] into \the [src].")) + light_source = flame + update_icon() + return TRUE + + // Refilling + if(light_source && istype(used_item, /obj/item/chems)) + var/obj/item/chems/chem_source = used_item + if(chem_source.standard_pour_into(user, light_source)) + return TRUE + + return ..() + +/obj/structure/wall_sconce/on_update_icon() + . = ..() + var/sconce_overlay = istype(light_source) ? light_source.get_sconce_overlay() : null + if(sconce_overlay) + add_overlay(sconce_overlay) + +// Subtypes below. +/obj/structure/wall_sconce/lantern + light_source = /obj/item/flame/fuelled/lantern/filled + +/obj/structure/wall_sconce/candle + light_source = /obj/item/flame/candle + +/obj/structure/wall_sconce/torch + light_source = /obj/item/flame/torch + diff --git a/code/game/objects/structures/wallframe_spawner.dm b/code/game/objects/structures/wallframe_spawner.dm index 27d361ff8bdb..524b017cc5f5 100644 --- a/code/game/objects/structures/wallframe_spawner.dm +++ b/code/game/objects/structures/wallframe_spawner.dm @@ -2,8 +2,9 @@ name = "wall frame window grille spawner" icon = 'icons/obj/structures/grille.dmi' icon_state = "wingrille" - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE + atmos_canpass = CANPASS_NEVER var/win_path = /obj/structure/window/basic/full var/frame_path = /obj/structure/wall_frame/standard var/grille_path = /obj/structure/grille @@ -14,7 +15,9 @@ return 0 /obj/effect/wallframe_spawn/attack_hand() + SHOULD_CALL_PARENT(FALSE) activate() + return TRUE /obj/effect/wallframe_spawn/attack_ghost() activate() @@ -40,40 +43,41 @@ if(locate(win_path) in loc) warning("Frame Spawner: A window structure already exists at [loc.x]-[loc.y]-[loc.z]") - if(grille_path) - if(locate(grille_path) in loc) - warning("Frame Spawner: A grille already exists at [loc.x]-[loc.y]-[loc.z]") - else - var/obj/structure/grille/G = new grille_path (loc) - handle_grille_spawn(G) - var/list/neighbours = list() if(fulltile) var/obj/structure/window/new_win = new win_path(loc) handle_window_spawn(new_win) else - for (var/dir in GLOB.cardinal) + for (var/dir in global.cardinal) var/turf/T = get_step(src, dir) var/obj/effect/wallframe_spawn/other = locate(type) in T if(!other) var/found_connection if(locate(/obj/structure/grille) in T) - for(var/obj/structure/window/W in T) - if(W.type == win_path && W.dir == get_dir(T,src)) + for(var/obj/structure/window/window in T) + if(window.type == win_path && window.dir == get_dir(T,src)) found_connection = 1 - qdel(W) + qdel(window) if(!found_connection) var/obj/structure/window/new_win = new win_path(loc) new_win.set_dir(dir) handle_window_spawn(new_win) else neighbours |= other + + if(grille_path) + if(locate(grille_path) in loc) + warning("Frame Spawner: A grille already exists at [loc.x]-[loc.y]-[loc.z]") + else + var/obj/structure/grille/G = new grille_path (loc) + handle_grille_spawn(G) + activated = 1 for(var/obj/effect/wallframe_spawn/other in neighbours) if(!other.activated) other.activate() /obj/effect/wallframe_spawn/proc/handle_frame_spawn(var/obj/structure/wall_frame/F) - for(var/direction in GLOB.cardinal) + for(var/direction in global.cardinal) var/turf/T = get_step(src, direction) for(var/obj/O in T) if( istype(O, /obj/machinery/door)) @@ -81,7 +85,7 @@ D.update_connections() D.update_icon() -/obj/effect/wallframe_spawn/proc/handle_window_spawn(var/obj/structure/window/W) +/obj/effect/wallframe_spawn/proc/handle_window_spawn(var/obj/structure/window/window) return /obj/effect/wallframe_spawn/proc/handle_grille_spawn(var/obj/structure/grille/G) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 087f5c0815e1..09f5a2556b34 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -1,3 +1,5 @@ +var/global/list/hygiene_props = list() + //todo: toothbrushes, and some sort of "toilet-filthinator" for the hos /obj/structure/hygiene var/next_gurgle = 0 @@ -8,11 +10,11 @@ /obj/structure/hygiene/Initialize() . = ..() - SSfluids.hygiene_props += src + global.hygiene_props += src START_PROCESSING(SSobj, src) /obj/structure/hygiene/Destroy() - SSfluids.hygiene_props -= src + global.hygiene_props -= src STOP_PROCESSING(SSobj, src) . = ..() @@ -27,9 +29,9 @@ clogged = 0 tool_interaction_flags = initial(tool_interaction_flags) -/obj/structure/hygiene/attackby(var/obj/item/thing, var/mob/user) - if(clogged > 0 && isPlunger(thing)) - user.visible_message("\The [user] strives valiantly to unclog \the [src] with \the [thing]!") +/obj/structure/hygiene/attackby(var/obj/item/used_item, var/mob/user) + if(clogged > 0 && isplunger(used_item)) + user.visible_message(SPAN_NOTICE("\The [user] strives valiantly to unclog \the [src] with \the [used_item]!")) spawn playsound(loc, 'sound/effects/plunger.ogg', 75, 1) sleep(5) @@ -41,18 +43,35 @@ sleep(5) playsound(loc, 'sound/effects/plunger.ogg', 75, 1) if(do_after(user, 45, src) && clogged > 0) - visible_message("With a loud gurgle, \the [src] begins flowing more freely.") + visible_message(SPAN_NOTICE("With a loud gurgle, \the [src] begins flowing more freely.")) playsound(loc, pick(SSfluids.gurgles), 100, 1) clogged-- if(clogged <= 0) unclog() - return + return TRUE + //toilet paper interaction for clogging toilets and other facilities + if (istype(used_item, /obj/item/stack/tape_roll/barricade_tape/toilet)) + if (clogged == -1) + to_chat(user, SPAN_WARNING("Try as you might, you can not clog \the [src] with \the [used_item].")) + return TRUE + if (clogged) + to_chat(user, SPAN_WARNING("\The [src] is already clogged.")) + return TRUE + if (!do_after(user, 3 SECONDS, src)) + to_chat(user, SPAN_WARNING("You must stay still to clog \the [src].")) + return TRUE + if (clogged || QDELETED(used_item) || !user.try_unequip(used_item)) + return TRUE + to_chat(user, SPAN_NOTICE("You unceremoniously jam \the [src] with \the [used_item]. What a rebel.")) + clog(1) + qdel(used_item) + return TRUE . = ..() -/obj/structure/hygiene/examine(mob/user) +/obj/structure/hygiene/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(clogged > 0) - to_chat(user, "It seems to be badly clogged.") + . += SPAN_WARNING("It seems to be badly clogged.") /obj/structure/hygiene/Process() if(clogged <= 0) @@ -73,11 +92,8 @@ visible_message("\The [src] gurgles and overflows!") next_gurgle = world.time + 80 playsound(T, pick(SSfluids.gurgles), 50, 1) - var/obj/effect/fluid/F = locate() in T - var/adding = min(flood_amt-F?.reagents.total_volume, rand(30,50)*clogged) - if(adding > 0) - if(!F) F = new(T) - F.reagents.add_reagent(/decl/material/liquid/water, adding) + if(loc.get_fluid_depth() < flood_amt) + T.add_to_reagents(/decl/material/liquid/water, round(rand(10,20)*clogged)) /obj/structure/hygiene/proc/drain() if(!can_drain) return @@ -98,8 +114,8 @@ desc = "The HT-451, a torque rotation-based, waste disposal unit for small matter. This one seems remarkably clean." icon = 'icons/obj/watercloset.dmi' icon_state = "toilet00" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE tool_interaction_flags = TOOL_INTERACTION_ANCHOR var/open = 0 //if the lid is up @@ -112,82 +128,91 @@ open = round(rand(0, 1)) update_icon() -/obj/structure/hygiene/toilet/attack_hand(var/mob/living/user) +/obj/structure/hygiene/toilet/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(swirlie) usr.visible_message( - "[user] slams the toilet seat onto [swirlie.name]'s head!", - "You slam the toilet seat onto [swirlie.name]'s head!", + SPAN_DANGER("\The [user] slams the toilet seat onto \the [swirlie]'s head!"), + SPAN_NOTICE("You slam the toilet seat onto \the [swirlie]'s head!"), "You hear reverberating porcelain.") - swirlie.adjustBruteLoss(8) - return + swirlie.take_damage(8) + return TRUE + // TODO: storage datum if(cistern && !open) if(!contents.len) - to_chat(user, "The cistern is empty.") + to_chat(user, SPAN_NOTICE("The cistern is empty.")) else - var/obj/item/I = pick(contents) + var/obj/item/thing = pick(contents) if(ishuman(user)) - user.put_in_hands(I) + user.put_in_hands(thing) else - I.dropInto(loc) - to_chat(user, "You find \an [I] in the cistern.") - w_items -= I.w_class - return + thing.dropInto(loc) + to_chat(user, SPAN_NOTICE("You find \a [thing] in the cistern.")) + w_items -= thing.w_class + return TRUE - open = !open - update_icon() + if(user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + open = !open + update_icon() + return TRUE + + return ..() /obj/structure/hygiene/toilet/on_update_icon() + ..() icon_state = "toilet[open][cistern]" -/obj/structure/hygiene/toilet/attackby(obj/item/I, var/mob/living/user) - if(isCrowbar(I)) - to_chat(user, "You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"].") +/obj/structure/hygiene/toilet/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!victim.loc == get_turf(src)) + to_chat(user, SPAN_WARNING("\The [victim] needs to be on the toilet.")) + return TRUE + if(open && !swirlie) + user.visible_message(SPAN_DANGER("\The [user] starts jamming \the [victim]'s face into \the [src]!")) + swirlie = victim + if(do_after(user, 30, src)) + user.visible_message(SPAN_DANGER("\The [user] gives [victim.name] a swirlie!")) + victim.take_damage(5, OXY) + swirlie = null + else + user.visible_message( + SPAN_DANGER("\The [user] slams \the [victim] into \the [src]!"), + SPAN_NOTICE("You slam \the [victim] into \the [src]!")) + victim.take_damage(8) + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + return TRUE + return ..() + +/obj/structure/hygiene/toilet/attackby(obj/item/used_item, var/mob/user) + if(IS_CROWBAR(used_item)) + to_chat(user, SPAN_NOTICE("You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"].")) playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, 1) if(do_after(user, 30, src)) user.visible_message( - "[user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!", - "You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!", + SPAN_NOTICE("\The [user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!"), + SPAN_NOTICE("You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!"), "You hear grinding porcelain.") cistern = !cistern update_icon() - return - - if(istype(I, /obj/item/grab)) - var/obj/item/grab/G = I - var/mob/living/GM = G.get_affecting_mob() - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(GM) - if(!GM.loc == get_turf(src)) - to_chat(user, "\The [GM] needs to be on the toilet.") - return - if(open && !swirlie) - user.visible_message("\The [user] starts jamming \the [GM]'s face into \the [src]!") - swirlie = GM - if(do_after(user, 30, src)) - user.visible_message("\The [user] gives [GM.name] a swirlie!") - GM.adjustOxyLoss(5) - swirlie = null - else - user.visible_message( - "\The [user] slams [GM.name] into the [src]!", - "You slam [GM.name] into the [src]!") - GM.adjustBruteLoss(8) - playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) - return + return TRUE - if(cistern && !istype(user,/mob/living/silicon/robot)) //STOP PUTTING YOUR MODULES IN THE TOILET. - if(I.w_class > ITEM_SIZE_NORMAL) - to_chat(user, "\The [I] does not fit.") - return - if(w_items + I.w_class > ITEM_SIZE_HUGE) - to_chat(user, "The cistern is full.") - return - if(!user.unEquip(I, src)) - return - w_items += I.w_class - to_chat(user, "You carefully place \the [I] into the cistern.") - return + if(cistern && !isrobot(user)) //STOP PUTTING YOUR MODULES IN THE TOILET. + if(used_item.w_class > ITEM_SIZE_NORMAL) + to_chat(user, SPAN_WARNING("\The [used_item] does not fit.")) + return TRUE + if(w_items + used_item.w_class > ITEM_SIZE_HUGE) + to_chat(user, SPAN_WARNING("The cistern is full.")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + w_items += used_item.w_class + to_chat(user, SPAN_NOTICE("You carefully place \the [used_item] into the cistern.")) + return TRUE . = ..() @@ -196,36 +221,37 @@ desc = "The HU-452, an experimental urinal." icon = 'icons/obj/watercloset.dmi' icon_state = "urinal" - density = 0 - anchored = 1 - -/obj/structure/hygiene/urinal/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/grab)) - var/obj/item/grab/G = I - var/mob/living/GM = G.get_affecting_mob() - if(GM) - if(!GM.loc == get_turf(src)) - to_chat(user, "[GM.name] needs to be on \the [src].") - return - user.visible_message("[user] slams [GM.name] into the [src]!") - GM.adjustBruteLoss(8) - . = ..() + density = FALSE + anchored = TRUE + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + +/obj/structure/hygiene/urinal/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim)) + if(!victim.loc == get_turf(src)) + to_chat(user, SPAN_WARNING("\The [victim] needs to be on \the [src].")) + else + user.visible_message(SPAN_DANGER("\The [user] slams \the [victim] into \the [src]!")) + victim.take_damage(8) + return TRUE + return ..() /obj/structure/hygiene/shower name = "shower" desc = "The HS-451. Installed in the 2200s by the Hygiene Division." icon = 'icons/obj/watercloset.dmi' icon_state = "shower" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE clogged = -1 can_drain = 1 drainage = 0.2 //showers are tiny, drain a little slower + chem_volume = 5 var/on = 0 - var/obj/effect/mist/mymist = null - var/ismist = 0 //needs a var so we can make it linger~ - var/is_washing = 0 + var/next_mist = 0 + var/next_wash = 0 var/watertemp = "normal" //freezing, normal, or boiling var/list/temperature_settings = list("normal" = 310, "boiling" = T0C+100, "freezing" = T0C) @@ -233,30 +259,21 @@ var/datum/sound_token/sound_token //add heat controls? when emagged, you can freeze to death in it? - -/obj/structure/hygiene/shower/Initialize() - . = ..() - create_reagents(5) - /obj/structure/hygiene/shower/Destroy() QDEL_NULL(sound_token) . = ..() -/obj/structure/hygiene/shower/attack_hand(mob/M) - switch_state(!on, M) +/obj/structure/hygiene/shower/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + switch_state(!on, user) + return TRUE /obj/structure/hygiene/shower/proc/switch_state(new_state, mob/user) if(new_state == on) return - on = new_state - if(on && user) - if(user.loc == loc) - wash(user) - process_heat(user) - for(var/atom/movable/G in loc) - G.clean_blood() - + next_mist = on ? (world.time + 5 SECONDS) : INFINITY update_icon() update_sound() @@ -264,312 +281,303 @@ playsound(src, on ? 'sound/effects/shower_start.ogg' : 'sound/effects/shower_end.ogg', 40) QDEL_NULL(sound_token) if(on) - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, 'sound/effects/shower_mid3.ogg', volume = 20, range = 7, falloff = 4, prefer_mute = TRUE) + sound_token = play_looping_sound(src, sound_id, 'sound/effects/shower_mid3.ogg', volume = 20, range = 7, falloff = 4, prefer_mute = TRUE) /obj/effect/mist name = "mist" icon = 'icons/obj/watercloset.dmi' icon_state = "mist" layer = MOB_LAYER + 1 - anchored = 1 - mouse_opacity = 0 + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE -/obj/structure/hygiene/shower/attackby(obj/item/I, var/mob/user) - if(istype(I, /obj/item/scanner/gas)) - to_chat(user, "The water temperature seems to be [watertemp].") - return +/obj/effect/mist/Initialize() + . = ..() + if(. != INITIALIZE_HINT_QDEL) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum, qdel_self)), 25 SECONDS) + +/obj/structure/hygiene/shower/attackby(obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/scanner/gas)) + to_chat(user, SPAN_NOTICE("The water temperature seems to be [watertemp].")) + return TRUE - if(isWrench(I)) + if(IS_WRENCH(used_item)) var/newtemp = input(user, "What setting would you like to set the temperature valve to?", "Water Temperature Valve") in temperature_settings - to_chat(user,"You begin to adjust the temperature valve with \the [I].") - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, 50, src)) - watertemp = newtemp - user.visible_message( - "\The [user] adjusts \the [src] with \the [I].", - "You adjust the shower with \the [I].") - add_fingerprint(user) - return + if(newtemp != watertemp && !QDELETED(used_item) && !QDELETED(user) && !QDELETED(src) && user.Adjacent(src) && used_item.loc == src) + to_chat(user, SPAN_NOTICE("You begin to adjust the temperature valve with \the [used_item].")) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, (5 SECONDS), src) && newtemp != watertemp) + watertemp = newtemp + user.visible_message( + SPAN_NOTICE("\The [user] adjusts \the [src] with \the [used_item]."), + SPAN_NOTICE("You adjust the shower with \the [used_item].")) + add_fingerprint(user) + return TRUE . = ..() -/obj/structure/hygiene/shower/on_update_icon() //this is terribly unreadable, but basically it makes the shower mist up - overlays.Cut() //once it's been on for a while, in addition to handling the water overlay. - if(mymist) - qdel(mymist) - mymist = null - - if(on) - overlays += image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir) - if(temperature_settings[watertemp] < T20C) - return //no mist for cold water - if(!ismist) - spawn(50) - if(src && on) - ismist = 1 - mymist = new /obj/effect/mist(loc) - else - ismist = 1 - mymist = new /obj/effect/mist(loc) - else if(ismist) - ismist = 1 - mymist = new /obj/effect/mist(loc) - spawn(250) - if(src && !on) - qdel(mymist) - mymist = null - ismist = 0 - -//Yes, showers are super powerful as far as washing goes. -/obj/structure/hygiene/shower/proc/wash(var/atom/movable/washing) +/obj/structure/hygiene/shower/on_update_icon() + ..() if(on) - wash_mob(washing) - if(isturf(loc)) - var/turf/tile = loc - for(var/obj/effect/E in tile) - if(istype(E,/obj/effect/decal/cleanable) || istype(E,/obj/effect/overlay)) - qdel(E) - reagents.splash(washing, 10) + add_overlay(image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir)) + +/obj/structure/hygiene/shower/proc/update_mist() + if(on && temperature_settings[watertemp] >= T20C && world.time >= next_mist && !(locate(/obj/effect/mist) in loc)) + new /obj/effect/mist(loc) + next_mist = world.time + (25 SECONDS) /obj/structure/hygiene/shower/Process() ..() - if(!on) return - - for(var/thing in loc) - var/atom/movable/AM = thing - var/mob/living/L = thing - if(istype(AM) && AM.simulated) - wash(AM) - if(istype(L)) - process_heat(L) - wash_floor() - reagents.add_reagent(/decl/material/liquid/water, REAGENTS_FREE_SPACE(reagents)) - -/obj/structure/hygiene/shower/proc/wash_floor() - if(!ismist && is_washing) - return - is_washing = 1 - var/turf/T = get_turf(src) - reagents.splash(T, reagents.total_volume) - T.clean(src) - spawn(100) - is_washing = 0 + if(on) + update_mist() + for(var/thing in loc.get_contained_external_atoms()) + wash_mob(thing) + process_heat(thing) + add_to_reagents(/decl/material/liquid/water, REAGENTS_FREE_SPACE(reagents)) + if(world.time >= next_wash) + next_wash = world.time + (10 SECONDS) + reagents.splash(get_turf(src), REAGENT_TOTAL_VOLUME(reagents), max_spill = 0) /obj/structure/hygiene/shower/proc/process_heat(mob/living/M) - if(!on || !istype(M)) return - + if(!on || !istype(M)) + return var/water_temperature = temperature_settings[watertemp] - var/temp_adj = between(BODYTEMP_COOLING_MAX, water_temperature - M.bodytemperature, BODYTEMP_HEATING_MAX) + var/temp_adj = clamp(water_temperature - M.bodytemperature, BODYTEMP_COOLING_MAX, BODYTEMP_HEATING_MAX) M.bodytemperature += temp_adj - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(water_temperature >= H.species.heat_level_1) - to_chat(H, "The water is searing hot!") - else if(water_temperature <= H.species.cold_level_1) - to_chat(H, "The water is freezing cold!") + var/mob/living/human/H = M + if(water_temperature >= H.get_mob_temperature_threshold(HEAT_LEVEL_1)) + to_chat(H, SPAN_DANGER("The water is searing hot!")) + else if(water_temperature <= H.get_mob_temperature_threshold(COLD_LEVEL_1)) + to_chat(H, SPAN_DANGER("The water is freezing cold!")) /obj/item/bikehorn/rubberducky name = "rubber ducky" desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~" //thanks doohl - icon = 'icons/obj/watercloset.dmi' - icon_state = "rubberducky" - item_state = "rubberducky" + icon = 'icons/obj/rubber_duck.dmi' + icon_state = ICON_STATE_WORLD /obj/structure/hygiene/sink name = "sink" icon = 'icons/obj/watercloset.dmi' icon_state = "sink" desc = "A sink used for washing one's hands and face." - anchored = 1 + anchored = TRUE + directional_offset = @'{"NORTH":{"y":22},"SOUTH":{"y":28},"EAST":{"x":16},"WEST":{"x":-16}}' var/busy = 0 //Something's being washed at the moment -/obj/structure/hygiene/sink/MouseDrop_T(var/obj/item/thing, var/mob/user) - ..() - if(!istype(thing) || !ATOM_IS_OPEN_CONTAINER(thing)) - return ..() - if(!usr.Adjacent(src)) - return ..() - if(!thing.reagents || thing.reagents.total_volume == 0) - to_chat(usr, "\The [thing] is empty.") - return - // Clear the vessel. - visible_message("\The [usr] tips the contents of \the [thing] into \the [src].") - thing.reagents.clear_reagents() - thing.update_icon() +/obj/structure/hygiene/sink/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && isitem(dropping) && ATOM_IS_OPEN_CONTAINER(dropping)) + var/obj/item/thing = dropping + if(REAGENT_TOTAL_VOLUME(thing.reagents) <= 0) + to_chat(usr, SPAN_WARNING("\The [thing] is empty.")) + else + visible_message(SPAN_NOTICE("\The [user] tips the contents of \the [thing] into \the [src].")) + thing.reagents.clear_reagents() + thing.update_icon() + return TRUE /obj/structure/hygiene/sink/attack_hand(var/mob/user) - if (ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] - if (user.hand) - temp = H.organs_by_name[BP_L_HAND] - if(temp && !temp.is_usable()) - to_chat(user,"You try to move your [temp.name], but cannot!") - return - - if(isrobot(user) || isAI(user)) - return - if(!Adjacent(user)) - return + if(isrobot(user) || isAI(user) || !Adjacent(user)) + return ..() if(busy) - to_chat(user, "Someone's already washing here.") - return + to_chat(user, SPAN_WARNING("Someone's already washing here.")) + return TRUE - to_chat(usr, "You start washing your hands.") + to_chat(usr, SPAN_NOTICE("You start washing your hands.")) playsound(loc, 'sound/effects/sink_long.ogg', 75, 1) - busy = 1 + busy = TRUE if(!do_after(user, 40, src)) - busy = 0 + busy = FALSE return TRUE - busy = 0 + busy = FALSE - user.clean_blood() - user.visible_message( \ - "[user] washes their hands using \the [src].", \ - "You wash your hands using \the [src].") - - -/obj/structure/hygiene/sink/attackby(obj/item/O, var/mob/living/user) + user.clean() + user.visible_message( + SPAN_NOTICE("\The [user] washes their hands using \the [src]."), + SPAN_NOTICE("You wash your hands using \the [src].")) + return TRUE - if(isPlunger(O) && clogged > 0) +/obj/structure/hygiene/sink/attackby(obj/item/used_item, var/mob/user) + if(isplunger(used_item) && clogged > 0) return ..() if(busy) - to_chat(user, "Someone's already washing here.") - return + to_chat(user, SPAN_WARNING("Someone's already washing here.")) + return TRUE - var/obj/item/chems/RG = O - if (istype(RG) && ATOM_IS_OPEN_CONTAINER(RG) && RG.reagents) - RG.reagents.add_reagent(/decl/material/liquid/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this)) - user.visible_message("[user] fills \the [RG] using \the [src].","You fill \the [RG] using \the [src].") + var/obj/item/chems/chem_container = used_item + if (istype(chem_container) && ATOM_IS_OPEN_CONTAINER(chem_container) && chem_container.reagents) + user.visible_message( + SPAN_NOTICE("\The [user] fills \the [chem_container] using \the [src]."), + SPAN_NOTICE("You fill \the [chem_container] using \the [src].")) playsound(loc, 'sound/effects/sink.ogg', 75, 1) - return 1 - - else if (istype(O, /obj/item/baton)) - var/obj/item/baton/B = O - if(B.bcell) - if(B.bcell.charge > 0 && B.status == 1) - flick("baton_active", src) - user.Stun(10) - user.stuttering = 10 - user.Weaken(10) - if(isrobot(user)) - var/mob/living/silicon/robot/R = user - R.cell.charge -= 20 - else - B.deductcharge(B.hitcost) - user.visible_message( \ - "[user] was stunned by \his wet [O]!", \ - "[user] was stunned by \his wet [O]!") - return 1 - else if(istype(O, /obj/item/mop)) - O.reagents.add_reagent(/decl/material/liquid/water, 5) - to_chat(user, "You wet \the [O] in \the [src].") - playsound(loc, 'sound/effects/slosh.ogg', 25, 1) - return + chem_container.add_to_reagents(/decl/material/liquid/water, min(REAGENTS_FREE_SPACE(chem_container.reagents), chem_container.amount_per_transfer_from_this)) + return TRUE + + else if (istype(used_item, /obj/item/baton)) + var/obj/item/baton/baton = used_item + var/obj/item/cell/cell = baton.get_cell() + if(cell?.check_charge(0) && baton.status) + if(isliving(user)) + var/mob/living/living_victim = user + SET_STATUS_MAX(living_victim, STAT_STUN, 10) + SET_STATUS_MAX(living_victim, STAT_STUTTER, 10) + SET_STATUS_MAX(living_victim, STAT_WEAK, 10) + // robot users used to be handled separately, but deductcharge handles that for us + baton.deductcharge(baton.hitcost) + var/decl/pronouns/user_pronouns = user.get_pronouns() + user.visible_message(SPAN_DANGER("\The [user] was stunned by [user_pronouns.his] wet [used_item]!")) + return TRUE + else if(istype(used_item, /obj/item/mop)) + if(REAGENTS_FREE_SPACE(used_item.reagents) >= 5) + used_item.add_to_reagents(/decl/material/liquid/water, 5) + to_chat(user, SPAN_NOTICE("You wet \the [used_item] in \the [src].")) + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + else + to_chat(user, SPAN_WARNING("\The [used_item] is saturated.")) + return TRUE var/turf/location = user.loc - if(!isturf(location)) return + if(!isturf(location)) + return FALSE - var/obj/item/I = O - if(!I || !istype(I,/obj/item)) return + if(!istype(used_item)) + return FALSE - to_chat(usr, "You start washing \the [I].") + to_chat(usr, SPAN_NOTICE("You start washing \the [used_item].")) playsound(loc, 'sound/effects/sink_long.ogg', 75, 1) - busy = 1 + busy = TRUE if(!do_after(user, 40, src)) - busy = 0 + busy = FALSE return TRUE - busy = 0 + busy = FALSE - if(istype(O, /obj/item/extinguisher/)) return TRUE // We're washing, not filling. + if(istype(used_item, /obj/item/chems/spray/extinguisher)) + return TRUE // We're washing, not filling. - O.clean_blood() + used_item.clean() user.visible_message( \ - "[user] washes \a [I] using \the [src].", \ - "You wash \a [I] using \the [src].") + SPAN_NOTICE("\The [user] washes \a [used_item] using \the [src]."), + SPAN_NOTICE("You wash \a [used_item] using \the [src].")) + return TRUE /obj/structure/hygiene/sink/kitchen name = "kitchen sink" icon_state = "sink_alt" + directional_offset = @'{"NORTH":{"y":22},"SOUTH":{"y":28},"EAST":{"x":-22},"WEST":{"x":22}}' /obj/structure/hygiene/sink/puddle //splishy splashy ^_^ name = "puddle" icon_state = "puddle" clogged = -1 // how do you clog a puddle + directional_offset = null /obj/structure/hygiene/sink/puddle/attack_hand(var/mob/M) - icon_state = "puddle-splash" - ..() - icon_state = "puddle" + flick("puddle-splash", src) + return ..() -/obj/structure/hygiene/sink/puddle/attackby(obj/item/O, var/mob/user) - icon_state = "puddle-splash" - ..() - icon_state = "puddle" - -//toilet paper interaction for clogging toilets and other facilities - -/obj/structure/hygiene/attackby(obj/item/I, mob/user) - if (!istype(I, /obj/item/taperoll/bog)) - ..() - return - if (clogged == -1) - to_chat(user, SPAN_WARNING("Try as you might, you can not clog \the [src] with \the [I].")) - return - if (clogged) - to_chat(user, SPAN_WARNING("\The [src] is already clogged.")) - return - if (!do_after(user, 3 SECONDS, src)) - to_chat(user, SPAN_WARNING("You must stay still to clog \the [src].")) - return - if (clogged || QDELETED(I) || !user.unEquip(I)) - return - to_chat(user, SPAN_NOTICE("You unceremoniously jam \the [src] with \the [I]. What a rebel.")) - clog(1) - qdel(I) - -/obj/item/taperoll/bog - name = "toilet paper roll" - icon = 'icons/obj/watercloset.dmi' - desc = "A unbranded roll of standard issue two ply toilet paper. Refined from carefully rendered down sea shells due to the government's 'Abuse Of The Trees Act'." - tape_type = /obj/item/tape/bog - icon_state = "bogroll" - item_state = "mummy_poor" - slot_flags = SLOT_HEAD | SLOT_OCLOTHING - var/sheets = 30 - -/obj/item/tape/bog - name = "toilet paper" - desc = "A length of toilet paper. Seems like custodia is marking their territory again." - icon_base = "stripetape" - color = COLOR_WHITE - detail_overlay = "stripes" - detail_color = COLOR_WHITE - -/obj/item/taperoll/bog/verb/tear_sheet() +/obj/structure/hygiene/sink/puddle/attackby(obj/item/used_item, var/mob/user) + . = ..() + if(.) + flick("puddle-splash", src) + +//////////////////////////////////////////////////// +// Toilet Paper Roll +//////////////////////////////////////////////////// +/decl/barricade_tape_template/toilet + tape_kind = "toilet paper" + tape_desc = "A length of toilet paper. Seems like custodia is marking their territory again." + roll_desc = "An unbranded roll of standard-issue two-ply toilet paper. Refined from carefully rendered-down seashells due to the government's 'Abuse Of The Trees Act'." + base_icon_state = "stripetape" + tape_color = COLOR_WHITE + detail_overlay = "stripes" + detail_color = COLOR_WHITE + +/obj/item/stack/tape_roll/barricade_tape/toilet + icon = 'icons/obj/toiletpaper.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_HEAD | SLOT_OVER_BODY + amount = 30 + max_amount = 30 + tape_template = /decl/barricade_tape_template/toilet + +/obj/item/stack/tape_roll/barricade_tape/toilet/verb/tear_sheet() set category = "Object" - set name = "Tear Sheet" - set desc = "Tear a sheet of toilet paper." + set name = "Tear Sheet" + set desc = "Tear a sheet of toilet paper." set src in usr + if (usr.incapacitated()) return - if(sheets > 0) - visible_message(SPAN_NOTICE("\The [usr] tears a sheet from \the [src]."), SPAN_NOTICE("You tear a sheet from \the [src].")) + + if(can_use(1)) + usr.visible_message(SPAN_NOTICE("\The [usr] tears a sheet from \the [src]."), SPAN_NOTICE("You tear a sheet from \the [src].")) var/obj/item/paper/crumpled/bog/C = new(loc) usr.put_in_hands(C) - sheets-- - if (sheets < 1) - to_chat(usr, SPAN_WARNING("\The [src] is depleted.")) - qdel(src) +//////////////////////////////////////////////////// +// Toilet Paper Sheet +//////////////////////////////////////////////////// /obj/item/paper/crumpled/bog - name = "sheet of toilet paper" - desc = "A single sheet of toilet paper. Two ply." + name = "sheet of toilet paper" + desc = "A single sheet of toilet paper. Two-ply." + icon = 'icons/obj/items/paperwork/toilet_paper.dmi' + +/obj/structure/hygiene/faucet + name = "faucet" icon = 'icons/obj/watercloset.dmi' - icon_state = "bogroll_sheet" + icon_state = "faucet" + desc = "An outlet for liquids. Water you waiting for?" + anchored = TRUE + drainage = 0 + clogged = -1 + + var/fill_level = 500 + var/open = FALSE + +/obj/structure/hygiene/faucet/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) + return ..() + open = !open + if(open) + playsound(src.loc, 'sound/effects/closet_open.ogg', 20, 1) + else + playsound(src.loc, 'sound/effects/closet_close.ogg', 20, 1) + user.visible_message(SPAN_NOTICE("\The [user] has [open ? "opened" : "closed"] the faucet.")) + update_icon() + return TRUE + +/obj/structure/hygiene/faucet/on_update_icon() + ..() + icon_state = icon_state = "[initial(icon_state)][open ? "-on" : null]" + +/obj/structure/hygiene/faucet/proc/water_flow() + if(!isturf(src.loc)) + return + + // Check for depth first, and pass if the water's too high. I know players will find a way to just submerge entire ship if I do not. + var/turf/T = get_turf(src) + + if(!T || T.get_fluid_depth() > fill_level) + return + + if(world.time > next_gurgle) + next_gurgle = world.time + 80 + playsound(T, pick(SSfluids.gurgles), 50, 1) + + T.add_to_reagents(/decl/material/liquid/water, min(75, fill_level - T.get_fluid_depth())) + +/obj/structure/hygiene/faucet/Process() + ..() + if(open) + water_flow() + +/obj/structure/hygiene/faucet/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "It is turned [open ? "on" : "off"]." diff --git a/code/game/objects/structures/well.dm b/code/game/objects/structures/well.dm new file mode 100644 index 000000000000..0faa71321e7c --- /dev/null +++ b/code/game/objects/structures/well.dm @@ -0,0 +1,91 @@ +/obj/structure/reagent_dispensers/well + name = "well" + desc = "A deep pit lined with stone bricks, used to store water." + icon = 'icons/obj/structures/well.dmi' + icon_state = ICON_STATE_WORLD + opacity = FALSE + anchored = TRUE + density = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_OPEN_CONTAINER + matter = null + material = /decl/material/solid/stone/granite + color = /decl/material/solid/stone/granite::color + material_alteration = MAT_FLAG_ALTERATION_ALL + wrenchable = FALSE + amount_dispensed = 10 + possible_transfer_amounts = @"[10,25,50,100]" + chem_volume = 10000 + can_toggle_open = FALSE + var/auto_refill + +// Override to skip open container check. +/obj/structure/reagent_dispensers/well/can_drink_from(mob/user) + return REAGENT_TOTAL_VOLUME(reagents) && user.check_has_mouth() + +/obj/structure/reagent_dispensers/well/populate_reagents() + . = ..() + if(auto_refill) + add_to_reagents(auto_refill, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/well/Destroy() + if(is_processing) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/structure/reagent_dispensers/well/on_update_icon() + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents)) + add_overlay(overlay_image(icon, "[icon_state]-fluid", reagents.get_color(), (RESET_COLOR | RESET_ALPHA))) + if(istype(reinf_material)) // reinf_material -> roof and posts, at this point in time + var/image/roof_image = overlay_image(icon, "[icon_state]-roof", reinf_material.color, RESET_COLOR | RESET_ALPHA | KEEP_APART) + roof_image.pixel_y = 16 // we have to use 32x32 sprites but want this to be, effectively, 48x32 + add_overlay(roof_image) + +/obj/structure/reagent_dispensers/well/on_reagent_change() + if(!(. = ..())) + return + update_icon() + if(!is_processing && auto_refill) + START_PROCESSING(SSobj, src) + +// Overrides due to wonky reagent_dispeners opencontainer flag handling. +/obj/structure/reagent_dispensers/well/can_be_poured_from(mob/user, atom/target) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) +/obj/structure/reagent_dispensers/well/can_be_poured_into(mob/user, atom/target) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) + +/obj/structure/reagent_dispensers/well/get_standard_interactions(var/mob/user) + . = ..() + if(REAGENT_MAXIMUM_VOLUME(reagents)) + LAZYADD(., global._reagent_interactions) + +/obj/structure/reagent_dispensers/well/Process() + if(!reagents || !auto_refill) // if we're full, we only stop at the end of the proc; we need to check for contaminants first + return PROCESS_KILL + var/amount_to_add = rand(5, 10) + if(length(REAGENT_VOLUMES(reagents)) > 1) // we have impurities! + reagents.remove_any(amount_to_add, defer_update = TRUE, skip_reagents = list(auto_refill)) // defer update until the add_reagent call below + if(REAGENT_TOTAL_VOLUME(reagents) < REAGENT_MAXIMUM_VOLUME(reagents)) + reagents.add_reagent(auto_refill, amount_to_add) + return // don't stop processing + else if(length(REAGENT_VOLUMES(reagents)) == 1 && reagents.get_primary_reagent_type() == auto_refill) + // only one reagent and it's our auto_refill, our work is done here + return PROCESS_KILL + // if we get here, it means we have a full well with contaminants, so we keep processing + +/obj/structure/reagent_dispensers/well/mapped + auto_refill = /decl/material/liquid/water + +/obj/structure/reagent_dispensers/well/mapped/covered + reinf_material = /decl/material/solid/organic/wood/walnut + +/obj/structure/reagent_dispensers/well/wall_fountain + name = "wall fountain" + desc = "An intricately-constructed fountain set into a wall." + icon = 'icons/obj/structures/wall_fountain.dmi' + density = FALSE + default_pixel_y = 24 + pixel_y = 24 + +/obj/structure/reagent_dispensers/well/wall_fountain/mapped + auto_refill = /decl/material/liquid/water diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 57c47bda5d58..bca175038d28 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -12,8 +12,8 @@ name = "windoor assembly" icon = 'icons/obj/doors/windoor.dmi' icon_state = "l_windoor_assembly01" - anchored = 0 - density = 0 + anchored = FALSE + density = FALSE dir = NORTH w_class = ITEM_SIZE_NORMAL material = /decl/material/solid/glass @@ -29,12 +29,13 @@ . = ..() update_nearby_tiles(need_rebuild=1) -obj/structure/windoor_assembly/Destroy() +/obj/structure/windoor_assembly/Destroy() set_density(0) update_nearby_tiles() - ..() + return ..() /obj/structure/windoor_assembly/on_update_icon() + ..() icon_state = "[facing_left ? "l" : "r"]_[secure ? "_secure" : ""]windoor_assembly[anchored && wired ? "02" : "01"]" /obj/structure/windoor_assembly/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) @@ -70,7 +71,7 @@ obj/structure/windoor_assembly/Destroy() . = initial(name) if(electronics) . = "nearly complete [.]" - else + else if(wired) . = "wired [.]" if(anchored) @@ -100,7 +101,7 @@ obj/structure/windoor_assembly/Destroy() visible_message(SPAN_NOTICE("\The [user] finishes \the [windoor]!")) windoor.construct_state.post_construct(windoor) qdel(src) - return TRUE + return TRUE . = ..() /obj/structure/windoor_assembly/handle_default_screwdriver_attackby(var/mob/user, var/obj/item/screwdriver) @@ -114,11 +115,11 @@ obj/structure/windoor_assembly/Destroy() return TRUE return FALSE -/obj/structure/windoor_assembly/attackby(obj/item/W, mob/user) +/obj/structure/windoor_assembly/attackby(obj/item/used_item, mob/user) . = ..() if(!. && anchored) - if(!secure && istype(W, /obj/item/stack/material/rods)) - var/obj/item/stack/material/rods/R = W + if(!secure && istype(used_item, /obj/item/stack/material/rods)) + var/obj/item/stack/material/rods/R = used_item if(R.get_amount() < 4) to_chat(user, SPAN_WARNING("You need more rods to do this.")) return TRUE @@ -127,14 +128,14 @@ obj/structure/windoor_assembly/Destroy() visible_message(SPAN_NOTICE("\The [user] finishes reinforcing \the [src].")) secure = TRUE . = TRUE - else if(wired && !electronics && istype(W, /obj/item/stock_parts/circuitboard/airlock_electronics/windoor)) + else if(wired && !electronics && istype(used_item, /obj/item/stock_parts/circuitboard/airlock_electronics/windoor)) playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) - visible_message(SPAN_NOTICE("\The [user] starts installing \the [W] into \the [src].")) - if(do_after(user, 4 SECONDS, src) && wired && !electronics && anchored && !QDELETED(src) && user.unEquip(W, src)) - visible_message(SPAN_NOTICE("\The [user] finishes installing \the [W] into \the [src].")) - electronics = W + visible_message(SPAN_NOTICE("\The [user] starts installing \the [used_item] into \the [src].")) + if(do_after(user, 4 SECONDS, src) && wired && !electronics && anchored && !QDELETED(src) && user.try_unequip(used_item, src)) + visible_message(SPAN_NOTICE("\The [user] finishes installing \the [used_item] into \the [src].")) + electronics = used_item else - W.dropInto(loc) + used_item.dropInto(loc) . = TRUE update_icon() update_name() @@ -163,3 +164,6 @@ obj/structure/windoor_assembly/Destroy() else to_chat(usr, "The windoor will now slide to the left.") update_icon() + +/obj/structure/windoor_assembly/secure + secure = TRUE diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index af060cc4d99e..f128e44b16f6 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -2,30 +2,36 @@ name = "window" desc = "A window." icon = 'icons/obj/structures/window.dmi' - density = 1 + density = TRUE w_class = ITEM_SIZE_NORMAL + color = GLASS_COLOR layer = SIDE_WINDOW_LAYER - anchored = 1.0 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CHECKS_BORDER - obj_flags = OBJ_FLAG_ROTATABLE - alpha = 180 + anchored = FALSE // Base, non-premapped type should start unanchored. + atom_flags = ATOM_FLAG_CHECKS_BORDER | ATOM_FLAG_CAN_BE_PAINTED + obj_flags = OBJ_FLAG_ROTATABLE | OBJ_FLAG_MOVES_UNSUPPORTED + base_alpha = 100 // at 0.3 opacity for glass, this will result in a total alpha of around 176 + alpha = 180 // preview value + material_alteration = MAT_FLAG_ALTERATION_COLOR material = /decl/material/solid/glass rad_resistance_modifier = 0.5 atmos_canpass = CANPASS_PROC handle_generic_blending = TRUE hitsound = 'sound/effects/Glasshit.ogg' - maxhealth = 100 + max_health = 100 var/damage_per_fire_tick = 2 // Amount of damage per fire tick. Regular windows are not fireproof so they might as well break quickly. - var/construction_state = 2 + var/const/CONSTRUCTION_STATE_NO_FRAME = 0 + var/const/CONSTRUCTION_STATE_IN_FRAME = 1 + var/const/CONSTRUCTION_STATE_FASTENED = 2 + var/construction_state = CONSTRUCTION_STATE_NO_FRAME var/id var/polarized = 0 var/basestate = "window" var/reinf_basestate = "rwindow" var/list/connections var/list/other_connections - + /obj/structure/window/clear_connections() connections = null other_connections = null @@ -34,18 +40,29 @@ connections = dirs_to_corner_states(dirs) other_connections = dirs_to_corner_states(other_dirs) -/obj/structure/window/update_materials(var/keep_health) - . = ..() - name = "[reinf_material ? "reinforced " : ""][material.solid_name] window" - desc = "A window pane made from [material.solid_name]." +/obj/structure/window/update_material_name(override_name) + var/base_name = override_name || initial(name) + if(istype(material)) + SetName("[reinf_material ? "reinforced " : ""][material.adjective_name] [base_name]") + else + SetName(base_name) -/obj/structure/window/Initialize(var/ml, var/dir_to_set, var/anchored, var/_mat, var/_reinf_mat) +/obj/structure/window/update_material_desc(var/override_desc) + if(istype(material)) + var/reinf_string = istype(reinf_material) ? " reinforced with [reinf_material.use_name]" : null + desc = "A window pane made from [material.solid_name][reinf_string]." + else + ..() + +/obj/structure/window/Initialize(var/ml, var/_mat, var/_reinf_mat, var/dir_to_set, var/anchored) . = ..(ml, _mat, _reinf_mat) if(!istype(material)) . = INITIALIZE_HINT_QDEL if(. != INITIALIZE_HINT_QDEL) if(!isnull(anchored)) set_anchored(anchored) + if(!anchored) + construction_state = CONSTRUCTION_STATE_NO_FRAME if(!isnull(dir_to_set)) set_dir(dir_to_set) if(is_fulltile()) @@ -55,7 +72,6 @@ // Updating connections may depend on material properties. /obj/structure/window/LateInitialize() ..() - //set_anchored(!constructed) // calls update_connections, potentially update_connections(1) update_icon() update_nearby_tiles(need_rebuild=1) @@ -65,19 +81,22 @@ update_nearby_tiles() var/turf/location = loc . = ..() - for(var/obj/structure/window/W in orange(location, 1)) - W.update_icon() + if(istype(location) && location != loc) + for(var/obj/structure/S in orange(location, 1)) + S.update_connections() + S.update_icon() /obj/structure/window/CanFluidPass(var/coming_from) return (!is_fulltile() && coming_from != dir) -/obj/structure/window/physically_destroyed() +/obj/structure/window/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) . = shatter() -/obj/structure/window/take_damage(damage = 0) +/obj/structure/window/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) . = ..() - playsound(loc, "glasscrack", 100, 1) + if(. && damage_type == BRUTE) + playsound(loc, "glasscrack", 100, 1) /obj/structure/window/proc/shatter(var/display_message = 1) playsound(src, "shatter", 70, 1) @@ -85,26 +104,31 @@ visible_message(SPAN_DANGER("\The [src] shatters!")) var/debris_count = is_fulltile() ? 4 : 1 - for(var/i = 0 to debris_count) - material.place_shard(loc) - if(reinf_material) - new /obj/item/stack/material/rods(loc, 1, reinf_material.type) + var/list/shards = material.place_shards(loc, debris_count) + if(paint_color) + for(var/obj/item/thing in shards) + thing.set_color(paint_color) + + if(reinf_material) + reinf_material.create_object(loc, debris_count, /obj/item/stack/material/rods) qdel(src) /obj/structure/window/bullet_act(var/obj/item/projectile/Proj) var/proj_damage = Proj.get_structure_damage() if(!proj_damage) return ..() - take_damage(proj_damage) + take_damage(proj_damage, Proj.atom_damage_type) /obj/structure/window/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity != 3 || prob(50))) + ..() + if(!QDELETED(src) && (severity != 3 || prob(50))) physically_destroyed() /obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) return 1 + if(air_group && !anchored) + return 1 if(is_fulltile()) return 0 //full tile window, you can't move into it! if(get_dir(loc, target) & dir) @@ -120,169 +144,218 @@ return 1 /obj/structure/window/hitby(atom/movable/AM, var/datum/thrownthing/TT) - ..() - visible_message(SPAN_DANGER("[src] was hit by [AM].")) - var/tforce = 0 - if(ismob(AM)) // All mobs have a multiplier and a size according to mob_defines.dm - var/mob/I = AM - tforce = I.mob_size * (TT.speed/THROWFORCE_SPEED_DIVISOR) - else if(isobj(AM)) - var/obj/item/I = AM - tforce = I.throwforce * (TT.speed/THROWFORCE_SPEED_DIVISOR) - if(reinf_material) tforce *= 0.25 - if(health - tforce <= 7 && !reinf_material) - set_anchored(FALSE) - step(src, get_dir(AM, src)) - take_damage(tforce) + . = ..() + if(.) + visible_message(SPAN_DANGER("[src] was hit by [AM].")) + var/tforce = AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR) + if(reinf_material) + tforce *= 0.25 + if(current_health - tforce <= 7 && !reinf_material) + set_anchored(FALSE) + step(src, get_dir(AM, src)) + take_damage(tforce) /obj/structure/window/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(MUTATION_HULK in user.mutations) - user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!")) - user.visible_message(SPAN_DANGER("[user] smashes through [src]!")) - user.do_attack_animation(src) - shatter() + if (user.check_intent(I_FLAG_HARM)) - else if (user.a_intent && user.a_intent == I_HURT) - - if (istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species.can_shred(H)) - attack_generic(H,25) - return + if(user.can_shred()) + return attack_generic(user, 25) playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) user.do_attack_animation(src) - user.visible_message(SPAN_DANGER("\The [user] bangs against \the [src]!"), - SPAN_DANGER("You bang against \the [src]!"), - "You hear a banging sound.") + user.visible_message( + SPAN_DANGER("\The [user] bangs against \the [src]!"), + SPAN_DANGER("You bang against \the [src]!"), + "You hear a banging sound." + ) else playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) - user.visible_message("[user.name] knocks on the [src.name].", - "You knock on the [src.name].", - "You hear a knocking sound.") - return - -/obj/structure/window/attack_generic(var/mob/user, var/damage, var/attack_verb, var/environment_smash) - if(environment_smash >= 1) - damage = max(damage, 10) - - if(istype(user)) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) - if(!damage) - return - if(damage >= 10) - visible_message(SPAN_DANGER("[user] [attack_verb] into [src]!")) - take_damage(damage) - else - visible_message(SPAN_NOTICE("\The [user] bonks \the [src] harmlessly.")) - return 1 + user.visible_message( + SPAN_NOTICE("\The [user] knocks on \the [src]."), + SPAN_NOTICE("You knock on \the [src]."), + "You hear a knocking sound." + ) + return TRUE /obj/structure/window/do_simple_ranged_interaction(var/mob/user) visible_message(SPAN_NOTICE("Something knocks on \the [src].")) playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1) return TRUE -/obj/structure/window/attackby(obj/item/W, mob/user) - if(!istype(W)) return//I really wish I did not need this - - if(W.item_flags & ITEM_FLAG_NO_BLUDGEON) return - - if(isScrewdriver(W)) - if(reinf_material && construction_state >= 1) - construction_state = 3 - construction_state +/obj/structure/window/handle_default_screwdriver_attackby(mob/user, obj/item/screwdriver) + var/tool_sound = screwdriver.get_tool_sound(TOOL_SCREWDRIVER) || 'sound/items/Screwdriver.ogg' + if(reinf_material) // reinforced windows have construction states + if(construction_state >= CONSTRUCTION_STATE_IN_FRAME) // if the window is in the frame + playsound(loc, tool_sound, 75, 1) + switch(construction_state) + if(CONSTRUCTION_STATE_IN_FRAME) + construction_state = CONSTRUCTION_STATE_FASTENED + to_chat(user, SPAN_NOTICE("You have fastened the window to the frame.")) + if(CONSTRUCTION_STATE_FASTENED) + construction_state = CONSTRUCTION_STATE_IN_FRAME + to_chat(user, SPAN_NOTICE("You have unfastened the window from the frame.")) update_nearby_icons() - playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) - to_chat(user, (construction_state == 1 ? SPAN_NOTICE("You have unfastened the window from the frame.") : SPAN_NOTICE("You have fastened the window to the frame."))) - else if(reinf_material && construction_state == 0) - set_anchored(!anchored) - playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) + return TRUE + else // if unanchored + set_anchored(!anchored) // sets construction_state for us + playsound(loc, tool_sound, 75, 1) to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the frame to the floor.") : SPAN_NOTICE("You have unfastened the frame from the floor."))) - else if(!reinf_material) - set_anchored(!anchored) - playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1) - to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the window to the floor.") : SPAN_NOTICE("You have unfastened the window."))) - else if(isCrowbar(W) && reinf_material && construction_state <= 1) - construction_state = 1 - construction_state - playsound(loc, 'sound/items/Crowbar.ogg', 75, 1) - to_chat(user, (construction_state ? SPAN_NOTICE("You have pried the window into the frame.") : SPAN_NOTICE("You have pried the window out of the frame."))) - else if(isWrench(W) && !anchored && (!construction_state || !reinf_material)) - if(!material.stack_type) - to_chat(user, SPAN_NOTICE("You're not sure how to dismantle \the [src] properly.")) + return TRUE + else // basic windows can only be anchored or unanchored + set_anchored(!anchored) + playsound(loc, tool_sound, 75, 1) + to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the window to the floor.") : SPAN_NOTICE("You have unfastened the window."))) + return TRUE + +/obj/structure/window/handle_default_crowbar_attackby(mob/user, obj/item/crowbar) + if(!reinf_material || !anchored || construction_state > CONSTRUCTION_STATE_IN_FRAME) + return FALSE // ineligible, allow other interactions to proceed + switch(construction_state) + if(CONSTRUCTION_STATE_NO_FRAME) // pry the window into the frame + construction_state = CONSTRUCTION_STATE_IN_FRAME + to_chat(user, SPAN_NOTICE("You have pried the window into the frame.")) + if(CONSTRUCTION_STATE_IN_FRAME) + construction_state = CONSTRUCTION_STATE_NO_FRAME + to_chat(user, SPAN_NOTICE("You have pried the window out of the frame.")) + playsound(loc, crowbar.get_tool_sound(TOOL_CROWBAR) || 'sound/items/Crowbar.ogg', 75, 1) + return TRUE + +/obj/structure/window/handle_default_hammer_attackby(mob/user, obj/item/hammer) + return FALSE + +/obj/structure/window/handle_default_wrench_attackby(mob/user, obj/item/wrench) + if(anchored || (reinf_material && construction_state > CONSTRUCTION_STATE_NO_FRAME)) + return FALSE // ineligible, allow other interactions to proceed + if(!material) // is this even necessary now? indestructible admin level window types maybe? + to_chat(user, SPAN_NOTICE("You're not sure how to dismantle \the [src] properly.")) + return TRUE // prevent other interactions + playsound(loc, wrench.get_tool_sound(TOOL_WRENCH) || 'sound/items/Ratchet.ogg', 75, 1) + visible_message(SPAN_NOTICE("[user] dismantles \the [src].")) + dismantle_structure(user) + return TRUE + +/obj/structure/window/handle_default_cable_attackby(mob/user, obj/item/stack/cable_coil/coil) + if(!is_fulltile()) + return FALSE // ineligible, allow other interactions to proceed + if(polarized) + to_chat(user, SPAN_WARNING("\The [src] is already polarized.")) + return TRUE // prevent further interactions + if(coil.use(1)) + playsound(loc, 'sound/effects/sparks1.ogg', 75, 1) + polarized = TRUE + to_chat(user, SPAN_NOTICE("You wire and polarize \the [src].")) + else + to_chat(user, SPAN_WARNING("You need at least one length of [coil.plural_name] to polarize \the [src]!")) + return TRUE + +/obj/structure/window/handle_default_wirecutter_attackby(mob/user, obj/item/wirecutters/wirecutters) + if (!polarized) + to_chat(user, SPAN_WARNING("\The [src] is not polarized.")) + return TRUE // prevent other interactions + var/obj/item/stack/cable_coil/product = new /obj/item/stack/cable_coil(get_turf(user), 1) + if(product.add_to_stacks(user, TRUE)) + user.put_in_hands(product) + if (opacity) + toggle() // must toggle off BEFORE unsetting the polarization var + polarized = FALSE + id = null + playsound(loc, wirecutters.get_tool_sound(TOOL_WIRECUTTERS) || 'sound/items/Wirecutter.ogg', 75, 1) + to_chat(user, SPAN_NOTICE("You cut the wiring and remove the polarization from \the [src].")) + return TRUE + +/obj/structure/window/attackby(obj/item/used_item, mob/user) + // bespoke interactions not handled by the prior procs + if(IS_MULTITOOL(used_item)) + if (!polarized) + to_chat(user, SPAN_WARNING("\The [src] is not polarized.")) + return TRUE + if (anchored) + playsound(loc, 'sound/effects/pop.ogg', 75, 1) + to_chat(user, SPAN_NOTICE("You toggle \the [src]'s tinting.")) + toggle() else - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - visible_message(SPAN_NOTICE("[user] dismantles \the [src].")) - var/obj/item/stack/material/S = material.place_sheet(loc, is_fulltile() ? 4 : 1) - if(S && reinf_material) - S.reinf_material = reinf_material - S.update_strings() - S.update_icon() - dismantle() - else if(isCoil(W) && !polarized && is_fulltile()) - var/obj/item/stack/cable_coil/C = W - if (C.use(1)) - playsound(src.loc, 'sound/effects/sparks1.ogg', 75, 1) - polarized = TRUE - else if(polarized && isMultitool(W)) - var/t = sanitizeSafe(input(user, "Enter the ID for the window.", src.name, null), MAX_NAME_LEN) - if(user.incapacitated() || !user.Adjacent(src)) - return - if (user.get_active_hand() != W) - return - if (t) - src.id = t - to_chat(user, SPAN_NOTICE("The new ID of the window is [id]")) - return - else if(istype(W, /obj/item/gun/energy/plasmacutter) && anchored) - var/obj/item/gun/energy/plasmacutter/cutter = W + var/response = input(user, "New Window ID:", name, id) as null | text + if (isnull(response) || user.incapacitated() || !user.Adjacent(src) || user.get_active_held_item() != used_item) + return TRUE + id = sanitize_safe(response, MAX_NAME_LEN) + to_chat(user, SPAN_NOTICE("The new ID of \the [src] is [id].")) + return TRUE + else if(istype(used_item, /obj/item/gun/energy/plasmacutter) && anchored) + var/obj/item/gun/energy/plasmacutter/cutter = used_item if(!cutter.slice(user)) - return + return TRUE // failed to finish or otherwise failed, prevent further interactions playsound(src, 'sound/items/Welder.ogg', 80, 1) visible_message(SPAN_NOTICE("[user] has started slicing through the window's frame!")) - if(do_after(user,20,src)) + if(do_after(user, 2 SECONDS, src)) visible_message(SPAN_WARNING("[user] has sliced through the window's frame!")) playsound(src, 'sound/items/Welder.ogg', 80, 1) - construction_state = 0 - set_anchored(0) + set_anchored(FALSE) + if (istype(used_item, /obj/item/paint_sprayer)) + return FALSE // allow afterattack to run + return ..() // handle generic interactions, bashing, etc + +/obj/structure/window/bash(obj/item/weapon, mob/user) + if(isliving(user) && user.check_intent(I_FLAG_HELP)) + return FALSE + if(!weapon.user_can_attack_with(user)) + return FALSE + if(weapon.item_flags & ITEM_FLAG_NO_BLUDGEON) + return FALSE + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + // physical damage types that can impart force; swinging a bat or energy sword + if(weapon.atom_damage_type == BRUTE || weapon.atom_damage_type == BURN) + user.do_attack_animation(src) + hit(weapon.expend_attack_force(user)) + if(current_health <= 7) + set_anchored(FALSE) + step(src, get_dir(user, src)) else - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(W.damtype == BRUTE || W.damtype == BURN) - user.do_attack_animation(src) - hit(W.force) - if(health <= 7) - set_anchored(FALSE) - step(src, get_dir(user, src)) - else - playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) - ..() - return + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + return TRUE // bash successful -/obj/structure/window/grab_attack(var/obj/item/grab/G) - if (G.assailant.a_intent != I_HURT) +// TODO: generalize to matter list and parts_type. +/obj/structure/window/create_dismantled_products(turf/T) + SHOULD_CALL_PARENT(FALSE) + . = material.create_object(loc, 1) + if(reinf_material) + for(var/obj/item/stack/material/S in .) + S.reinf_material = reinf_material + S.update_strings() + S.update_icon() + if(paint_color) + for(var/obj/item/thing in .) + thing.set_color(paint_color) + +/obj/structure/window/grab_attack(obj/item/grab/grab, mob/user) + if (!user.check_intent(I_FLAG_HARM)) return TRUE - if (!G.force_danger()) - to_chat(G.assailant, SPAN_DANGER("You need a better grip to do that!")) + if (!grab.force_danger()) + to_chat(user, SPAN_DANGER("You need a better grip to do that!")) return TRUE - var/def_zone = ran_zone(BP_HEAD, 20) - var/mob/affecting_mob = G.get_affecting_mob() - if(!affecting_mob) - attackby(G.affecting, G.assailant) + var/mob/living/affecting_mob = grab.get_affecting_mob() + if(!istype(affecting_mob)) + attackby(grab.affecting, user) return TRUE - if(G.damage_stage() < 2) - G.affecting.visible_message(SPAN_DANGER("[G.assailant] bashes [G.affecting] against \the [src]!")) + var/def_zone = ran_zone(BP_HEAD, 20, affecting_mob) + if(grab.damage_stage() < 2) + grab.affecting.visible_message(SPAN_DANGER("\The [user] bashes \the [grab.affecting] against \the [src]!")) if(prob(50)) - affecting_mob.Weaken(1) + SET_STATUS_MAX(affecting_mob, STAT_WEAK, 2) affecting_mob.apply_damage(10, BRUTE, def_zone, used_weapon = src) hit(25) + qdel(grab) else - G.affecting.visible_message(SPAN_DANGER("[G.assailant] crushes [G.affecting] against \the [src]!")) - affecting_mob.Weaken(5) + grab.affecting.visible_message(SPAN_DANGER("\The [user] crushes \the [grab.affecting] against \the [src]!")) + SET_STATUS_MAX(affecting_mob, STAT_WEAK, 5) affecting_mob.apply_damage(20, BRUTE, def_zone, used_weapon = src) hit(50) + qdel(grab) return TRUE /obj/structure/window/proc/hit(var/damage, var/sound_effect = 1) + // TODO: use reinf_material properties, paper reinforcement should be worse than plasteel reinforcement if(reinf_material) damage *= 0.5 take_damage(damage) @@ -299,10 +372,25 @@ set_dir(turn(dir, 90)) update_nearby_tiles(need_rebuild=1) +/obj/structure/window/set_dir(ndir) + . = ..() + if(is_fulltile()) + atom_flags &= ~ATOM_FLAG_CHECKS_BORDER + else + atom_flags |= ATOM_FLAG_CHECKS_BORDER + +/obj/structure/window/update_nearby_tiles(need_rebuild) + . = ..() + for(var/obj/structure/S in orange(loc, 1)) + if(S == src) + continue + S.update_connections() + S.update_icon() + /obj/structure/window/Move() var/ini_dir = dir update_nearby_tiles(need_rebuild=1) - ..() + . = ..() set_dir(ini_dir) update_nearby_tiles(need_rebuild=1) @@ -312,23 +400,35 @@ return 1 return 0 -/obj/structure/window/examine(mob/user) +/obj/structure/window/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) if(reinf_material) - to_chat(user, SPAN_NOTICE("It is reinforced with the [reinf_material.solid_name] lattice.")) + . += SPAN_NOTICE("It is reinforced with the [reinf_material.solid_name] lattice.") + if (reinf_material) + switch (construction_state) + if (CONSTRUCTION_STATE_NO_FRAME) + . += SPAN_WARNING("The window is not in the frame.") + if (CONSTRUCTION_STATE_IN_FRAME) + . += SPAN_WARNING("The window is pried into the frame but not yet fastened.") + if (CONSTRUCTION_STATE_FASTENED) + . += SPAN_NOTICE("The window is fastened to the frame.") + if (anchored) + . += SPAN_NOTICE("It is fastened to \the [get_turf(src)].") + else + . += SPAN_WARNING("It is not fastened to anything.") + if (polarized) + . += SPAN_NOTICE("It appears to be wired.") -/obj/structure/window/proc/set_anchored(var/new_anchored) - if(anchored == new_anchored) - return - anchored = new_anchored - update_connections(1) - update_nearby_icons() +/obj/structure/window/set_anchored(new_anchored) + if((. = ..())) + update_connections(1) + update_nearby_icons() //This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc! /obj/structure/window/proc/update_nearby_icons() update_icon() - for(var/obj/structure/window/W in orange(src, 1)) - W.update_icon() + for(var/obj/structure/window/window in orange(src, 1)) + window.update_icon() // Visually connect with every type of window as long as it's full-tile. /obj/structure/window/can_visually_connect() @@ -341,12 +441,14 @@ /obj/structure/window/on_update_icon() //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong. //this way it will only update full-tile ones - color = material.color if(reinf_material) basestate = reinf_basestate else basestate = initial(basestate) - overlays.Cut() + + ..() + + color = get_color() layer = FULL_WINDOW_LAYER if(!is_fulltile()) layer = SIDE_WINDOW_LAYER @@ -359,28 +461,31 @@ for(var/i = 1 to 4) var/conn = connections ? connections[i] : "0" if(other_connections && other_connections[i] != "0") - I = image(icon, "[basestate]_other_onframe[conn]", dir = 1<<(i-1)) + I = image(icon, "[basestate]_other_onframe[conn]", dir = BITFLAG(i-1)) else - I = image(icon, "[basestate]_onframe[conn]", dir = 1<<(i-1)) - overlays += I + I = image(icon, "[basestate]_onframe[conn]", dir = BITFLAG(i-1)) + I.color = paint_color + add_overlay(I) else for(var/i = 1 to 4) var/conn = connections ? connections[i] : "0" if(other_connections && other_connections[i] != "0") - I = image(icon, "[basestate]_other[conn]", dir = 1<<(i-1)) + I = image(icon, "[basestate]_other[conn]", dir = BITFLAG(i-1)) else - I = image(icon, "[basestate][conn]", dir = 1<<(i-1)) - overlays += I + I = image(icon, "[basestate][conn]", dir = BITFLAG(i-1)) + I.color = paint_color + add_overlay(I) /obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - var/melting_point = material.melting_point + var/damage_point = material.temperature_damage_threshold if(reinf_material) - melting_point += 0.25*reinf_material.melting_point - if(exposed_temperature > melting_point) + damage_point += 0.25*reinf_material.temperature_damage_threshold + if(exposed_temperature > damage_point) hit(damage_per_fire_tick, 0) ..() /obj/structure/window/basic + anchored = TRUE // Premapped type, start anchored. icon_state = "window" color = GLASS_COLOR @@ -389,12 +494,13 @@ icon_state = "window_full" /obj/structure/window/basic/full/polarized - polarized = 1 + polarized = TRUE /obj/structure/window/borosilicate name = "borosilicate window" color = GLASS_COLOR_SILICATE material = /decl/material/solid/glass/borosilicate + anchored = TRUE // Premapped type, start anchored. /obj/structure/window/borosilicate/full dir = NORTHEAST @@ -406,6 +512,8 @@ color = GLASS_COLOR_SILICATE material = /decl/material/solid/glass/borosilicate reinf_material = /decl/material/solid/metal/steel + anchored = TRUE // Premapped type, start anchored and fastened. + construction_state = CONSTRUCTION_STATE_FASTENED /obj/structure/window/borosilicate_reinforced/full dir = NORTHEAST @@ -416,6 +524,8 @@ icon_state = "rwindow" material = /decl/material/solid/glass reinf_material = /decl/material/solid/metal/steel + anchored = TRUE // Premapped type, start anchored and fastened. + construction_state = CONSTRUCTION_STATE_FASTENED /obj/structure/window/reinforced/full dir = NORTHEAST @@ -423,7 +533,7 @@ /obj/structure/window/reinforced/tinted name = "tinted window" - opacity = 1 + opacity = TRUE color = GLASS_COLOR_TINTED /obj/structure/window/reinforced/tinted/frosted @@ -437,12 +547,13 @@ basestate = "w" reinf_basestate = "w" dir = NORTHEAST + anchored = TRUE // Premapped type, start anchored. /obj/structure/window/reinforced/polarized name = "electrochromic window" desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it." basestate = "rwindow" - polarized = 1 + polarized = TRUE /obj/structure/window/reinforced/polarized/full dir = NORTHEAST @@ -452,11 +563,11 @@ if(!polarized) return if(opacity) - animate(src, color=material.color, time=5) - set_opacity(0) + animate(src, color=get_color(), time=5) + set_opacity(FALSE) else animate(src, color=GLASS_COLOR_TINTED, time=5) - set_opacity(1) + set_opacity(TRUE) /obj/structure/window/proc/is_on_frame() if(locate(/obj/structure/wall_frame) in loc) @@ -469,34 +580,28 @@ desc = "A remote control switch for electrochromic windows." var/range = 7 stock_part_presets = null // This isn't a radio-enabled button; it communicates with nearby structures in view. - uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable - ) frame_type = /obj/item/frame/button/light_switch/windowtint construct_state = /decl/machine_construction/wall_frame/panel_closed/simple - base_type = /obj/machinery/button/windowtint/buildable - -/obj/machinery/button/windowtint/buildable - uncreated_component_parts = null + base_type = /obj/machinery/button/windowtint -/obj/machinery/button/windowtint/attackby(obj/item/W, mob/user) - if(isMultitool(W)) - var/t = sanitizeSafe(input(user, "Enter the ID for the button.", name, id_tag), MAX_NAME_LEN) +/obj/machinery/button/windowtint/attackby(obj/item/used_item, mob/user) + if(IS_MULTITOOL(used_item)) + var/t = sanitize_safe(input(user, "Enter the ID for the button.", name, id_tag), MAX_NAME_LEN) if(!CanPhysicallyInteract(user)) return TRUE - t = sanitizeSafe(t, MAX_NAME_LEN) + t = sanitize_safe(t, MAX_NAME_LEN) if (t) id_tag = t - to_chat(user, SPAN_NOTICE("The new ID of the button is [id_tag]")) + to_chat(user, SPAN_NOTICE("The new ID of the button is '[id_tag]'.")) return TRUE return ..() /obj/machinery/button/windowtint/activate() if(operating) return - for(var/obj/structure/window/W in range(src,range)) - if(W.polarized && (W.id == id_tag || !W.id)) - W.toggle() + for(var/obj/structure/window/window in range(src,range)) + if(window.polarized && (window.id == id_tag || !window.id)) + window.toggle() ..() /obj/machinery/button/windowtint/power_change() @@ -508,20 +613,22 @@ icon_state = "light[active]" //Centcomm windows -/obj/structure/window/reinforced/crescent/attack_hand() - return +/obj/structure/window/reinforced/crescent/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + return TRUE /obj/structure/window/reinforced/crescent/attackby() - return + return TRUE /obj/structure/window/reinforced/crescent/explosion_act() SHOULD_CALL_PARENT(FALSE) return /obj/structure/window/reinforced/crescent/hitby() - return + SHOULD_CALL_PARENT(FALSE) + return FALSE -/obj/structure/window/reinforced/crescent/take_damage() +/obj/structure/window/reinforced/crescent/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) return /obj/structure/window/reinforced/crescent/shatter() @@ -532,28 +639,26 @@ if (!ST.can_use(required_amount)) to_chat(user, SPAN_NOTICE("You do not have enough sheets.")) return - for(var/obj/structure/window/WINDOW in loc) - if(WINDOW.dir == dir_to_set) + for(var/obj/structure/window/existing_window in loc) + if(existing_window.dir == dir_to_set) to_chat(user, SPAN_NOTICE("There is already a window facing this way there.")) return - if(WINDOW.is_fulltile() && (dir_to_set & (dir_to_set - 1))) //two fulltile windows + if(existing_window.is_fulltile() && (dir_to_set & (dir_to_set - 1))) //two fulltile windows to_chat(user, SPAN_NOTICE("There is already a window there.")) return to_chat(user, SPAN_NOTICE("You start placing the window.")) - if(do_after(user,20)) - for(var/obj/structure/window/WINDOW in loc) - if(WINDOW.dir == dir_to_set)//checking this for a 2nd time to check if a window was made while we were waiting. + if(do_after(user, 2 SECONDS)) + for(var/obj/structure/window/existing_window in loc) + if(existing_window.dir == dir_to_set)//checking this for a 2nd time to check if a window was made while we were waiting. to_chat(user, SPAN_NOTICE("There is already a window facing this way there.")) return - if(WINDOW.is_fulltile() && (dir_to_set & (dir_to_set - 1))) + if(existing_window.is_fulltile() && (dir_to_set & (dir_to_set - 1))) to_chat(user, SPAN_NOTICE("There is already a window there.")) return if (ST.use(required_amount)) - var/obj/structure/window/WD = new(loc, dir_to_set, FALSE, ST.material.type, ST.reinf_material && ST.reinf_material.type) + var/obj/structure/window/WD = new(loc, ST.material.type, ST.reinf_material?.type, dir_to_set, FALSE) to_chat(user, SPAN_NOTICE("You place [WD].")) - WD.construction_state = 0 - WD.set_anchored(FALSE) else to_chat(user, SPAN_NOTICE("You do not have enough sheets.")) - return \ No newline at end of file + return diff --git a/code/game/objects/structures/window_spawner.dm b/code/game/objects/structures/window_spawner.dm index f8869e469a84..2b3e90164e1a 100644 --- a/code/game/objects/structures/window_spawner.dm +++ b/code/game/objects/structures/window_spawner.dm @@ -7,8 +7,9 @@ name = "window grille spawner" icon = 'icons/obj/structures/grille.dmi' icon_state = "wingrille" - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE + atmos_canpass = CANPASS_NEVER var/win_path = /obj/structure/window/basic var/activated = FALSE var/fulltile = FALSE @@ -18,7 +19,9 @@ return 0 /obj/effect/wingrille_spawn/attack_hand() + SHOULD_CALL_PARENT(FALSE) activate() + return TRUE /obj/effect/wingrille_spawn/attack_ghost() activate() @@ -37,38 +40,39 @@ if(locate(/obj/structure/window) in loc) warning("Window Spawner: A window structure already exists at [loc.x]-[loc.y]-[loc.z]") - if(locate(/obj/structure/grille) in loc) - warning("Window Spawner: A grille already exists at [loc.x]-[loc.y]-[loc.z]") - else - var/obj/structure/grille/G = new /obj/structure/grille(loc) - handle_grille_spawn(G) - var/list/neighbours = list() if(fulltile) var/obj/structure/window/new_win = new win_path(loc) handle_window_spawn(new_win) else - for (var/dir in GLOB.cardinal) + for (var/dir in global.cardinal) var/turf/T = get_step(src, dir) var/obj/effect/wingrille_spawn/other = locate(type) in T if(!other) var/found_connection if(locate(/obj/structure/grille) in T) - for(var/obj/structure/window/W in T) - if(W.type == win_path && W.dir == get_dir(T,src)) + for(var/obj/structure/window/window in T) + if(window.type == win_path && window.dir == get_dir(T,src)) found_connection = 1 - qdel(W) + qdel(window) if(!found_connection) var/obj/structure/window/new_win = new win_path(loc) new_win.set_dir(dir) handle_window_spawn(new_win) else neighbours |= other + + if(locate(/obj/structure/grille) in loc) + warning("Window Spawner: A grille already exists at [loc.x]-[loc.y]-[loc.z]") + else + var/obj/structure/grille/G = new /obj/structure/grille(loc) + handle_grille_spawn(G) + activated = 1 for(var/obj/effect/wingrille_spawn/other in neighbours) if(!other.activated) other.activate() -/obj/effect/wingrille_spawn/proc/handle_window_spawn(var/obj/structure/window/W) +/obj/effect/wingrille_spawn/proc/handle_window_spawn(var/obj/structure/window/window) return // Currently unused, could be useful for pre-wired electrified windows. diff --git a/code/game/objects/topic.dm b/code/game/objects/topic.dm index ca36fa2c94da..00031e392bb2 100644 --- a/code/game/objects/topic.dm +++ b/code/game/objects/topic.dm @@ -1,10 +1,10 @@ /atom/proc/DefaultTopicState() - return GLOB.default_state + return global.default_topic_state /atom/Topic(var/href, var/href_list = list(), var/datum/topic_state/state) if((. = ..())) return - state = state || DefaultTopicState() || GLOB.default_state + state = state || DefaultTopicState() || global.default_topic_state if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE) CouldUseTopic(usr) return OnTopic(usr, href_list, state) @@ -15,10 +15,10 @@ return TOPIC_NOACTION // Override prescribes default state argument. -/atom/CanUseTopic(var/mob/user, var/datum/topic_state/state = DefaultTopicState() || GLOB.default_state, var/href_list) +/atom/CanUseTopic(var/mob/user, var/datum/topic_state/state = DefaultTopicState() || global.default_topic_state, var/href_list) return ..() -/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state = DefaultTopicState() || GLOB.default_state, var/href_list) +/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state = DefaultTopicState() || global.default_topic_state, var/href_list) return min(..(), user.CanUseObjTopic(src, state)) /mob/living/CanUseObjTopic(var/obj/O, var/datum/topic_state/state) diff --git a/code/game/response_team.dm b/code/game/response_team.dm deleted file mode 100644 index ee44fb1ec214..000000000000 --- a/code/game/response_team.dm +++ /dev/null @@ -1,138 +0,0 @@ -//STRIKE TEAMS -//Thanks to Kilakk for the admin-button portion of this code. - -var/global/send_emergency_team = 0 // Used for automagic response teams - // 'admin_emergency_team' for admin-spawned response teams -var/ert_base_chance = 10 // Default base chance. Will be incremented by increment ERT chance. -var/can_call_ert - -/client/proc/response_team() - set name = "Dispatch Emergency Response Team" - set category = "Special Verbs" - set desc = "Send an emergency response team" - - if(!holder) - to_chat(usr, "Only administrators may use this command.") - return - if(GAME_STATE < RUNLEVEL_GAME) - to_chat(usr, "The game hasn't started yet!") - return - if(send_emergency_team) - to_chat(usr, "[GLOB.using_map.boss_name] has already dispatched an emergency response team!") - return - if(alert("Do you want to dispatch an Emergency Response Team?",,"Yes","No") != "Yes") - return - - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - if(security_state.current_security_level_is_lower_than(security_state.high_security_level)) // Allow admins to reconsider if the alert level is below High - switch(alert("Current security level lower than [security_state.high_security_level.name]. Do you still want to dispatch a response team?",,"Yes","No")) - if("No") - return - if(send_emergency_team) - to_chat(usr, "Looks like somebody beat you to it!") - return - - message_admins("[key_name_admin(usr)] is dispatching an Emergency Response Team.", 1) - log_admin("[key_name(usr)] used Dispatch Response Team.") - trigger_armed_response_team(1) - -client/verb/JoinResponseTeam() - - set name = "Join Response Team" - set category = "IC" - - if(!MayRespawn(1)) - to_chat(usr, "You cannot join the response team at this time.") - return - - if(isghost(usr) || isnewplayer(usr)) - if(!send_emergency_team) - to_chat(usr, "No emergency response team is currently being sent.") - return - if(jobban_isbanned(usr, MODE_ERT) || jobban_isbanned(usr, "Security Officer")) - to_chat(usr, "You are jobbanned from the emergency reponse team!") - return - if(GLOB.ert.current_antagonists.len >= GLOB.ert.hard_cap) - to_chat(usr, "The emergency response team is already full!") - return - GLOB.ert.create_default(usr) - else - to_chat(usr, "You need to be an observer or new player to use this.") - -// returns a number of dead players in % -proc/percentage_dead() - var/total = 0 - var/deadcount = 0 - for(var/mob/living/carbon/human/H in SSmobs.mob_list) - if(H.client) // Monkeys and mice don't have a client, amirite? - if(H.stat == 2) deadcount++ - total++ - - if(total == 0) return 0 - else return round(100 * deadcount / total) - -// counts the number of antagonists in % -proc/percentage_antagonists() - var/total = 0 - var/antagonists = 0 - for(var/mob/living/carbon/human/H in SSmobs.mob_list) - if(is_special_character(H) >= 1) - antagonists++ - total++ - - if(total == 0) return 0 - else return round(100 * antagonists / total) - -// Increments the ERT chance automatically, so that the later it is in the round, -// the more likely an ERT is to be able to be called. -proc/increment_ert_chance() - while(send_emergency_team == 0) // There is no ERT at the time. - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - var/index = security_state.all_security_levels.Find(security_state.current_security_level) - ert_base_chance += 2**index - sleep(600 * 3) // Minute * Number of Minutes - - -proc/trigger_armed_response_team(var/force = 0) - if(!can_call_ert && !force) - return - if(send_emergency_team) - return - - var/send_team_chance = ert_base_chance // Is incremented by increment_ert_chance. - send_team_chance += 2*percentage_dead() // the more people are dead, the higher the chance - send_team_chance += percentage_antagonists() // the more antagonists, the higher the chance - send_team_chance = min(send_team_chance, 100) - - if(force) send_team_chance = 100 - - // there's only a certain chance a team will be sent - if(!prob(send_team_chance)) - command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "[GLOB.using_map.boss_name]") - can_call_ert = 0 // Only one call per round, ladies. - return - - command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "[GLOB.using_map.boss_name]") - SSevac.evacuation_controller.add_can_call_predicate(new/datum/evacuation_predicate/ert()) - - can_call_ert = 0 // Only one call per round, gentleman. - send_emergency_team = 1 - - sleep(600 * 5) - send_emergency_team = 0 // Can no longer join the ERT. - -/datum/evacuation_predicate/ert - var/prevent_until - -/datum/evacuation_predicate/ert/New() - ..() - prevent_until = world.time + 30 MINUTES - -/datum/evacuation_predicate/ert/is_valid() - return world.time < prevent_until - -/datum/evacuation_predicate/ert/can_call(var/user) - if(world.time >= prevent_until) - return TRUE - to_chat(user, "An emergency response team has been dispatched. Evacuation requests will be denied until [duration2stationtime(prevent_until - world.time)].") - return FALSE diff --git a/code/game/sound.dm b/code/game/sound.dm index 495708afe8f1..6aa5066cea21 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -10,34 +10,36 @@ var/maxdistance = (world.view + extrarange) * 2 // Looping through the player list has the added bonus of working for mobs inside containers - var/list/listeners = GLOB.player_list + var/list/listeners = global.player_list if(!ignore_walls) //these sounds don't carry through walls listeners = listeners & hearers(maxdistance, turf_source) - for(var/P in listeners) - var/mob/M = P + for(var/mob/M as anything in listeners) if(!M || !M.client) continue if(get_dist(M, turf_source) <= maxdistance) var/turf/T = get_turf(M) - if(T && (T.z == turf_source.z || (zrange && AreConnectedZLevels(T.z, turf_source.z) && abs(T.z - turf_source.z) <= zrange)) && (!is_ambiance || M.get_preference_value(/datum/client_preference/play_ambiance) == GLOB.PREF_YES)) + if(T && (T.z == turf_source.z || (zrange && SSmapping.are_connected_levels(T.z, turf_source.z) && abs(T.z - turf_source.z) <= zrange)) && (!is_ambiance || M.get_preference_value(/datum/client_preference/play_ambiance) == PREF_YES)) M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, extrarange, override_env, envdry, envwet) -var/const/FALLOFF_SOUNDS = 0.5 +var/global/const/FALLOFF_SOUNDS = 0.5 //Applies mob-specific and environment specific adjustments to volume value given /proc/adjust_volume_for_hearer(var/volume, var/turf/turf_source, var/atom/listener) if(ismob(listener)) var/mob/M = listener - if(M.ear_deaf) + if(GET_STATUS(M, STAT_DEAF)) return 0 volume *= M.get_sound_volume_multiplier() var/turf/T = get_turf(listener) - var/datum/gas_mixture/hearer_env = T.return_air() - var/datum/gas_mixture/source_env = turf_source.return_air() + var/datum/gas_mixture/hearer_env = T?.return_air() + var/datum/gas_mixture/source_env = turf_source?.return_air() + + if(!hearer_env || !source_env) + return 0 var/pressure_factor = 1.0 if (hearer_env && source_env) @@ -52,15 +54,12 @@ var/const/FALLOFF_SOUNDS = 0.5 volume *= pressure_factor - if(istype(T,/turf/simulated) && istype(turf_source,/turf/simulated)) - var/turf/simulated/sim_source = turf_source - var/turf/simulated/sim_destination = T - if(sim_destination.zone != sim_source.zone) - volume -= 30 + if(!turf_source.blocks_air && T.zone != turf_source.zone) + volume = round(volume * 0.7) // quick and dirty volume reduction from ZAS flood fill return volume /mob/proc/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, is_global, extrarange, override_env, envdry, envwet) - if(!src.client || ear_deaf > 0) + if(!src.client || is_deaf()) return var/sound/S = soundin @@ -77,7 +76,8 @@ var/const/FALLOFF_SOUNDS = 0.5 S.frequency = get_rand_frequency() var/turf/T = get_turf(src) - S.volume = adjust_volume_for_hearer(S.volume, turf_source, src) + if(!is_global) + S.volume = adjust_volume_for_hearer(S.volume, turf_source, src) // 3D sounds, the technology is here! if(isturf(turf_source)) @@ -102,19 +102,19 @@ var/const/FALLOFF_SOUNDS = 0.5 if(!is_global) - if(istype(src,/mob/living/)) - var/mob/living/carbon/M = src - if (istype(M) && M.hallucination_power > 50 && M.chem_effects[CE_MIND] < 1) + if(isliving(src)) + var/mob/living/M = src + if (istype(M) && M.hallucination_power > 50 && GET_CHEMICAL_EFFECT(M, CE_MIND) < 1) S.environment = PSYCHOTIC - else if (M.drugged) + else if (HAS_STATUS(M, STAT_DRUGGY)) S.environment = DRUGGED - else if (M.drowsyness) + else if(HAS_STATUS(M, STAT_DROWSY)) S.environment = DIZZY - else if (M.confused) + else if (HAS_STATUS(M, STAT_CONFUSE)) S.environment = DIZZY else if (M.stat == UNCONSCIOUS) S.environment = UNDERWATER - else if (T?.is_flooded(M.lying)) + else if (T?.is_flooded(M.current_posture.prone)) S.environment = UNDERWATER else var/area/A = get_area(src) @@ -132,8 +132,8 @@ var/const/FALLOFF_SOUNDS = 0.5 sound_to(src, S) /client/proc/playtitlemusic() - if(get_preference_value(/datum/client_preference/play_lobby_music) == GLOB.PREF_YES) - GLOB.using_map.lobby_track.play_to(src) + if(get_preference_value(/datum/client_preference/play_lobby_music) == PREF_YES && global.using_map.lobby_track) + global.using_map.lobby_track.play_to(src) /proc/get_rand_frequency() return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs. @@ -141,22 +141,75 @@ var/const/FALLOFF_SOUNDS = 0.5 /proc/get_sfx(soundin) if(istext(soundin)) switch(soundin) - if ("shatter") soundin = pick(GLOB.shatter_sound) - if ("explosion") soundin = pick(GLOB.explosion_sound) - if ("sparks") soundin = pick(GLOB.spark_sound) - if ("rustle") soundin = pick(GLOB.rustle_sound) - if ("punch") soundin = pick(GLOB.punch_sound) - if ("light_strike") soundin = pick(GLOB.light_strike_sound) - if ("clownstep") soundin = pick(GLOB.clown_sound) - if ("swing_hit") soundin = pick(GLOB.swing_hit_sound) - if ("hiss") soundin = pick(GLOB.hiss_sound) - if ("pageturn") soundin = pick(GLOB.page_sound) - if ("fracture") soundin = pick(GLOB.fracture_sound) - if ("light_bic") soundin = pick(GLOB.lighter_sound) - if ("keyboard") soundin = pick(GLOB.keyboard_sound) - if ("keystroke") soundin = pick(GLOB.keystroke_sound) - if ("switch") soundin = pick(GLOB.switch_sound) - if ("button") soundin = pick(GLOB.button_sound) - if ("chop") soundin = pick(GLOB.chop_sound) - if ("glasscrack") soundin = pick(GLOB.glasscrack_sound) + if ("shatter") soundin = pick(global.shatter_sound) + if ("explosion") soundin = pick(global.explosion_sound) + if ("sparks") soundin = pick(global.spark_sound) + if ("rustle") soundin = pick(global.rustle_sound) + if ("punch") soundin = pick(global.punch_sound) + if ("light_strike") soundin = pick(global.light_strike_sound) + if ("clownstep") soundin = pick(global.clown_sound) + if ("swing_hit") soundin = pick(global.swing_hit_sound) + if ("hiss") soundin = pick(global.hiss_sound) + if ("pageturn") soundin = pick(global.page_sound) + if ("fracture") soundin = pick(global.fracture_sound) + if ("light_bic") soundin = pick(global.lighter_sound) + if ("keyboard") soundin = pick(global.keyboard_sound) + if ("keystroke") soundin = pick(global.keystroke_sound) + if ("switch") soundin = pick(global.switch_sound) + if ("button") soundin = pick(global.button_sound) + if ("chop") soundin = pick(global.chop_sound) + if ("glasscrack") soundin = pick(global.glasscrack_sound) + if ("tray_hit") soundin = pick(global.tray_hit_sound) + if ("sweeping") soundin = pick(global.sweeping_sound) + if("ricochet") soundin = pick(global.ricochet_sound) return soundin + +///Volume to play DTMF key sounds at. They're pretty loud, so 15 is fine. +#define VOL_DTMF_KEY 15 + +/** + Plays a DTMF tone (Telephone key press sound) for any valid telephone key. + * `source`: The atom that's producing the sound. + * `key`: The character of the key pressed. + * `user`: The mob actually pressing the key. + * `user_only`: Whether the sound should be only heard by the user mob. (Sent to the user's client only) + * Returns FALSE if the key is invalid, TRUE if the key was valid and we played a sound. + */ +/proc/play_dtmf_key_sound(atom/source, key, mob/user, user_only = FALSE) + //NOTE: File paths are all in here inside a big switch, so they're cached into the rsc! + var/sound_path + switch(lowertext(key)) + if("0") + sound_path = 'sound/machines/phone/key-0.ogg' + if("1") + sound_path = 'sound/machines/phone/key-1.ogg' + if("2", "a", "b", "c") + sound_path = 'sound/machines/phone/key-2.ogg' + if("3", "d", "e", "f") + sound_path = 'sound/machines/phone/key-3.ogg' + if("4", "g", "h", "i") + sound_path = 'sound/machines/phone/key-4.ogg' + if("5", "j", "k", "l") + sound_path = 'sound/machines/phone/key-5.ogg' + if("6", "m", "n", "o") + sound_path = 'sound/machines/phone/key-6.ogg' + if("7", "p", "q", "r", "s") + sound_path = 'sound/machines/phone/key-7.ogg' + if("8", "t", "u", "v") + sound_path = 'sound/machines/phone/key-8.ogg' + if("9", "w", "x", "y", "z") + sound_path = 'sound/machines/phone/key-9.ogg' + if("*", "⚹") //Asterisk and actual phone keypad star char for completeness + sound_path = 'sound/machines/phone/key-star.ogg' + if("#", "⌗") //hash symbol and actual phone keypad square char for completeness + sound_path = 'sound/machines/phone/key-square.ogg' + else + return FALSE + + if(user_only) + sound_to(user, sound(sound_path, volume = VOL_DTMF_KEY)) + else + playsound(source, sound_path, VOL_DTMF_KEY, FALSE, 0, 2, envdry = 50, envwet = 10) //tone down the reverbs on this cause it sounds really weird + return TRUE + +#undef VOL_DTMF_KEY \ No newline at end of file diff --git a/code/game/turfs/flooring/_flooring.dm b/code/game/turfs/flooring/_flooring.dm new file mode 100644 index 000000000000..f30adf01de71 --- /dev/null +++ b/code/game/turfs/flooring/_flooring.dm @@ -0,0 +1,399 @@ +var/global/list/flooring_cache = list() + +// State values: +// [icon_base]: initial base icon_state without edges or corners. +// if has_base_range is set, append 0-has_base_range ie. +// [icon_base][has_base_range] +// [icon_base]_edges: directional overlays for edges. +// [icon_base]_corners: directional overlays for non-edge corners. + +/decl/flooring + abstract_type = /decl/flooring + decl_flags = DECL_FLAG_MANDATORY_UID + + var/name + var/desc + var/icon + var/gender = PLURAL /// "that's some grass" + var/icon_base + var/color = COLOR_WHITE + var/footstep_type = /decl/footsteps/plating + var/growth_value = 0 + var/deconstruct_sound + + var/neighbour_type + + var/has_base_range + var/damage_temperature + var/icon_edge_layer = FLOOR_EDGE_NONE + var/has_environment_proc + var/can_conceal_hazards = FALSE + + /// Unbuildable if not set. Must be /obj/item/stack. + var/build_type + /// Unbuildable if object material var is not set to this. + var/build_material + /// Stack units. + var/build_cost = 1 + /// BYOND ticks. + var/build_time = 0 + + var/drop_material_on_remove = FALSE + + var/descriptor + var/flooring_flags + var/remove_timer = 1 SECOND + var/can_paint = FALSE + var/can_engrave = TRUE + var/can_collect = FALSE + + // Not bloody prints, but rather prints on top of the turf (snow, mud) + var/print_type + + var/turf_light_range + var/turf_light_power + var/turf_light_color + + var/decl/material/force_material + + var/movement_delay + + /// Smooth with nothing except the types in this list. Turned into a typecache for performance reasons. + var/list/flooring_whitelist = list() + /// Smooth with everything except the types in this list. Turned into a typecache for performance reasons. + var/list/flooring_blacklist = list() + + /// How we smooth with other flooring + var/floor_smooth + /// How we smooth with walls + var/wall_smooth + /// How we smooth with space and openspace tiles + var/space_smooth + /// If we smooth with everything, we can skip a bunch of other smoothing checks. This is a bool and not an enum. + var/omni_smooth + + /// same z flags used for turfs, i.e ZMIMIC_DEFAULT etc + var/z_flags + /// Flags to apply to the turf. + var/turf_flags + + var/constructed = FALSE + + var/has_corners = TRUE + var/has_internal_edges = FALSE + var/has_external_edges = FALSE + var/edge_state + var/corner_state + var/outer_edge_state + var/outer_corner_state + + var/render_trenches = TRUE + var/floor_layer = TURF_LAYER + var/holographic = FALSE + var/dirt_color = /decl/material/solid/soil::color + + var/list/burned_states + var/list/broken_states + +/decl/flooring/Initialize() + . = ..() + + neighbour_type ||= type + + if(ispath(force_material)) + force_material = GET_DECL(force_material) + if(!istype(force_material)) + force_material = null + + if(holographic) + turf_flags = null + damage_temperature = INFINITY + build_type = null + build_material = null + flooring_flags = null + can_paint = FALSE + can_engrave = FALSE + constructed = TRUE + + edge_state = "[icon_base]_edges" + corner_state = "[icon_base]_corners" + outer_edge_state = "[icon_base]_outer_edges" + outer_corner_state = "[icon_base]_outer_corners" + + flooring_whitelist = typecacheof(flooring_whitelist) + flooring_blacklist = typecacheof(flooring_blacklist) + has_internal_edges = check_state_in_icon(edge_state, icon) || check_state_in_icon(corner_state, icon) + has_external_edges = check_state_in_icon(outer_edge_state, icon) || check_state_in_icon(outer_corner_state, icon) + + var/default_smooth = (has_internal_edges || has_external_edges) ? SMOOTH_NONE : SMOOTH_ALL + if(isnull(wall_smooth)) + wall_smooth = default_smooth + if(isnull(space_smooth)) + space_smooth = default_smooth + if(isnull(floor_smooth)) + floor_smooth = default_smooth + if(isnull(omni_smooth) && floor_smooth == wall_smooth && wall_smooth == space_smooth) + omni_smooth = (floor_smooth == SMOOTH_ALL) // bool, not enum + +/decl/flooring/validate() + . = ..() + + if(!istext(name)) + . += "null or invalid name string" + + if(!istext(desc)) + . += "null or invalid desc string" + + if(!icon) + . += "null icon" + + if(!istext(icon_base)) + . += "null or invalid icon_state '[icon_base]'" + + if(icon && icon_base) + + for(var/check_state in broken_states) + if(!check_state_in_icon(check_state, icon)) + . += "missing broken state '[check_state]' in '[icon]'" + + for(var/check_state in burned_states) + if(!check_state_in_icon(check_state, icon)) + . += "missing burned state '[check_state]' in '[icon]'" + + if(!check_state_in_icon("trench", icon)) + . += "no trench wall state" + + if(has_base_range) + for(var/i = 0 to has_base_range) + var/check_state = "[icon_base][i]" + if(!check_state_in_icon(check_state, icon)) + . += "missing icon_state '[check_state]' from '[icon]'" + else if(!check_state_in_icon(icon_base, icon)) + . += "missing icon_state '[icon_base]' from '[icon]'" + + if(has_internal_edges) + if(!check_state_in_icon(edge_state, icon)) + . += "flagged for internal edges but missing edge state from '[icon]'" + if(!check_state_in_icon(corner_state, icon)) + . += "flagged for internal edges but missing corner state from '[icon]'" + + if(has_external_edges) + if(!check_state_in_icon(outer_edge_state, icon)) + . += "flagged for external edges but missing edge state from '[icon]'" + if(!check_state_in_icon(outer_corner_state, icon)) + . += "flagged for external edges but missing corner state from '[icon]'" + +/decl/flooring/proc/get_surface_descriptor() + return descriptor || name || "terrain" + +/decl/flooring/proc/update_turf_strings(turf/floor/target) + target.SetName(name) + target.desc = desc + +/decl/flooring/proc/update_turf_icon(turf/floor/target) + + if(target.icon != icon) + target.icon = icon + if(!target.floor_icon_state_override) + target.floor_icon_state_override = icon_base + if(has_base_range) + target.floor_icon_state_override = "[target.floor_icon_state_override][rand(0,has_base_range)]" + + if(target.icon_state != target.floor_icon_state_override) + target.icon_state = target.floor_icon_state_override + + if (icon_edge_layer != FLOOR_EDGE_NONE && (has_internal_edges || has_external_edges)) + var/edge_layer = target.layer + icon_edge_layer + var/has_border = 0 + for(var/step_dir in global.cardinal) + var/turf/T = get_step_resolving_mimic(target, step_dir) + if(!istype(T) || test_link(T)) + continue + has_border |= step_dir + if(has_internal_edges) + target.add_overlay(get_flooring_overlay("[icon]_[icon_base]-edge-[step_dir]", edge_state, step_dir, edge_layer = edge_layer)) + if(has_external_edges && target.can_draw_edge_over(T)) + target.add_overlay(get_flooring_overlay("[icon]_[icon_base]-outer-edge-[step_dir]", outer_edge_state, step_dir, TRUE, edge_layer = edge_layer)) + + if(has_corners) + for(var/step_dir in global.cornerdirs) + var/turf/T = get_step_resolving_mimic(target, step_dir) + if(!istype(T) || test_link(T)) + continue + if(has_internal_edges) + if((has_border & step_dir) == 0) // smooth + target.add_overlay(get_flooring_overlay("[icon]_[icon_base]-corner-[step_dir]", corner_state, step_dir, edge_layer = edge_layer)) + else if((has_border & step_dir) == step_dir) + target.add_overlay(get_flooring_overlay("[icon]_[icon_base]-edge-[step_dir]", edge_state, step_dir, edge_layer = edge_layer)) + if(has_external_edges) + if((has_border & step_dir) == 0 && target.can_draw_edge_over(T)) // smooth + target.add_overlay(get_flooring_overlay("[icon]_[icon_base]-outer-corner-[step_dir]", outer_corner_state, step_dir, TRUE, edge_layer = edge_layer)) + else if((has_border & step_dir) == step_dir && target.can_draw_edge_over(T)) + target.add_overlay(get_flooring_overlay("[icon]_[icon_base]-outer-edge-[step_dir]", outer_edge_state, step_dir, TRUE, edge_layer = edge_layer)) + + if(target.is_floor_broken()) + target.add_overlay(get_damage_overlay(target._floor_broken)) + if(target.is_floor_burned()) + target.add_overlay(get_damage_overlay(target._floor_burned)) + +/decl/flooring/proc/get_damage_overlay(var/overlay_state) + var/cache_key = "[icon]-[overlay_state]" + if(!global.flooring_cache[cache_key]) + var/image/I = image(icon = icon, icon_state = overlay_state) + I.blend_mode = BLEND_MULTIPLY + I.layer = DECAL_LAYER + global.flooring_cache[cache_key] = I + return global.flooring_cache[cache_key] + +/decl/flooring/proc/get_flooring_overlay(var/cache_key, var/icon_base, var/icon_dir = 0, var/external = FALSE, var/edge_layer) + cache_key = "[cache_key]-[edge_layer]" + if(!global.flooring_cache[cache_key]) + var/image/I = image(icon = icon, icon_state = icon_base, dir = icon_dir) + //External overlays will be offset out of this tile + if (external) + if (icon_dir & NORTH) + I.pixel_y = world.icon_size + else if (icon_dir & SOUTH) + I.pixel_y = -world.icon_size + if (icon_dir & WEST) + I.pixel_x = -world.icon_size + else if (icon_dir & EAST) + I.pixel_x = world.icon_size + I.layer = edge_layer + global.flooring_cache[cache_key] = I + return global.flooring_cache[cache_key] + +/decl/flooring/proc/on_flooring_remove(turf/removing_from) + if(force_material && drop_material_on_remove) + force_material.create_object(removing_from, rand(3,5)) + +/decl/flooring/proc/get_movement_delay(var/travel_dir, var/mob/mover) + return movement_delay + +/decl/flooring/proc/get_movable_alpha_mask_state(atom/movable/mover) + return + +/decl/flooring/proc/handle_hand_interaction(turf/floor/floor, mob/user) + if(!force_material || !can_collect) + return FALSE + user.visible_message(SPAN_NOTICE("\The [user] begins scraping together some of \the [name]...")) + if(do_after(user, 3 SECONDS, floor) && !QDELETED(floor) && !QDELETED(user) && floor.get_topmost_flooring() == src && isnull(user.get_active_held_item())) + var/list/created = force_material.create_object(floor, 1) + user.visible_message(SPAN_NOTICE("\The [user] scrapes together [english_list(created)].")) + for(var/obj/item/stack/stack in created) + stack.add_to_stacks(user, TRUE) + return TRUE + +/decl/flooring/proc/handle_item_interaction(turf/floor/floor, mob/user, obj/item/item) + + if(!istype(user) || !istype(item) || !istype(floor) || user.check_intent(I_FLAG_HARM)) + return FALSE + + if(!(IS_SCREWDRIVER(item) && (flooring_flags & TURF_REMOVE_SCREWDRIVER)) && floor.try_graffiti(user, item)) + return TRUE + + if(IS_SHOVEL(item) && (flooring_flags & TURF_REMOVE_SHOVEL)) + if(!user.do_skilled(remove_timer, SKILL_CONSTRUCTION, floor) || floor.get_topmost_flooring() != src) + return TRUE + to_chat(user, SPAN_NOTICE("You remove the [get_surface_descriptor()] with \the [item].")) + floor.remove_flooring(floor.get_topmost_flooring(), place_product = TRUE) + if(deconstruct_sound) + playsound(floor, deconstruct_sound, 80, 1) + return TRUE + + if(constructed) + + if(IS_CROWBAR(item)) + if(floor.is_floor_damaged()) + if(!user.do_skilled(remove_timer, SKILL_CONSTRUCTION, floor, 0.15)) + return TRUE + if(floor.get_topmost_flooring() != src) + return + to_chat(user, SPAN_NOTICE("You remove the broken [get_surface_descriptor()].")) + floor.remove_flooring(floor.get_topmost_flooring()) + else if(flooring_flags & TURF_IS_FRAGILE) + if(!user.do_skilled(remove_timer, SKILL_CONSTRUCTION, floor, 0.15)) + return TRUE + if(floor.get_topmost_flooring() != src) + return + to_chat(user, SPAN_DANGER("You forcefully pry off the [get_surface_descriptor()], destroying them in the process.")) + floor.remove_flooring(floor.get_topmost_flooring()) + else if(flooring_flags & TURF_REMOVE_CROWBAR) + if(!user.do_skilled(remove_timer, SKILL_CONSTRUCTION, floor)) + return TRUE + if(floor.get_topmost_flooring() != src) + return + to_chat(user, SPAN_NOTICE("You lever off the [get_surface_descriptor()].")) + floor.remove_flooring(floor.get_topmost_flooring(), place_product = TRUE) + else + return + playsound(floor, 'sound/items/Crowbar.ogg', 80, 1) + return TRUE + + if(IS_SCREWDRIVER(item) && (flooring_flags & TURF_REMOVE_SCREWDRIVER)) + if(floor.is_floor_damaged()) + return FALSE + if(!user.do_skilled(remove_timer, SKILL_CONSTRUCTION, floor) || floor.get_topmost_flooring() != src) + return TRUE + to_chat(user, SPAN_NOTICE("You unscrew and remove the [get_surface_descriptor()].")) + floor.remove_flooring(floor.get_topmost_flooring(), place_product = TRUE) + playsound(floor, 'sound/items/Screwdriver.ogg', 80, 1) + return TRUE + + if(IS_WRENCH(item) && (flooring_flags & TURF_REMOVE_WRENCH)) + if(!user.do_skilled(remove_timer, SKILL_CONSTRUCTION, floor) || floor.get_topmost_flooring() != src) + return TRUE + to_chat(user, SPAN_NOTICE("You unwrench and remove the [get_surface_descriptor()].")) + floor.remove_flooring(floor.get_topmost_flooring(), place_product = TRUE) + playsound(floor, 'sound/items/Ratchet.ogg', 80, 1) + return TRUE + + if(IS_COIL(item)) + to_chat(user, SPAN_WARNING("You must remove the [get_surface_descriptor()] first.")) + return TRUE + + return FALSE + +/decl/flooring/proc/fire_act(turf/floor/target, datum/gas_mixture/air, exposed_temperature, exposed_volume) + return FALSE + +/decl/flooring/proc/fluid_act(turf/floor/target, datum/reagents/fluids) + return FALSE + +/decl/flooring/proc/handle_environment_proc(turf/floor/target) + return PROCESS_KILL + +/decl/flooring/proc/handle_turf_digging(turf/floor/target) + return TRUE + +/decl/flooring/proc/turf_exited(turf/target, atom/movable/crosser, atom/new_loc) + return print_type && try_place_footprints(crosser, target, target, new_loc, "going") + +/decl/flooring/proc/turf_entered(turf/target, atom/movable/crosser, atom/old_loc) + return print_type && try_place_footprints(crosser, target, old_loc, target, "coming") + +/decl/flooring/proc/try_place_footprints(atom/movable/crosser, turf/target, turf/from_turf, turf/to_turf, use_state = "going") + if(!ismob(crosser) || !crosser.simulated || !isturf(from_turf) || !isturf(to_turf)) + return FALSE + if(target.check_fluid_depth(FLUID_QDEL_POINT)) + return FALSE + var/movement_dir = get_dir(from_turf, to_turf) + if(!movement_dir) + return FALSE + var/mob/walker = crosser + var/footprint_icon = walker.get_footprints_icon() + if(!footprint_icon) + return FALSE + var/obj/effect/footprints/prints = (locate() in target) || new print_type(target) + prints.add_footprints(crosser, footprint_icon, movement_dir, use_state) + +/decl/flooring/proc/turf_crossed(atom/movable/crosser) + return + +/// target is the turf that wants to know if it supports footprints +/// contaminant is, optionally, the material of the coating that wants to be added. +/decl/flooring/proc/can_show_coating_footprints(turf/target, decl/material/contaminant) + return TRUE + +/decl/flooring/proc/get_vehicle_transit_delay(obj/vehicle/vehicle) + return vehicle::base_speed diff --git a/code/game/turfs/flooring/_flooring_decals.dm b/code/game/turfs/flooring/_flooring_decals.dm new file mode 100644 index 000000000000..b1847ad05ab8 --- /dev/null +++ b/code/game/turfs/flooring/_flooring_decals.dm @@ -0,0 +1,1667 @@ +// These are objects that destroy themselves and add themselves to the +// decal list of the floor under them. Use them rather than distinct icon_states +// when mapping in interesting floor designs. +var/global/list/floor_decals = list() + +/obj/effect/floor_decal + name = "floor decal" + icon = 'icons/turf/flooring/decals.dmi' + layer = DECAL_LAYER + appearance_flags = RESET_COLOR + abstract_type = /obj/effect/floor_decal + var/supplied_dir + var/detail_overlay + var/detail_color + +// Have to wait for turfs to set up their flooring, so we can better guess at our layers. +/obj/effect/floor_decal/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/effect/floor_decal/LateInitialize(mapload, var/newdir, var/newcolour, var/newappearance) + supplied_dir = newdir + if(newappearance) appearance = newappearance + if(newcolour) color = newcolour + + if(supplied_dir) set_dir(supplied_dir) + var/turf/T = get_turf(src) + if(istype(T)) + layer = T.is_plating() ? DECAL_PLATING_LAYER : DECAL_LAYER + var/cache_key = "[alpha]-[color]-[dir]-[icon_state]-[plane]-[layer]-[detail_overlay]-[detail_color]-[pixel_x]-[pixel_y]" + if(!floor_decals[cache_key]) + var/image/I = image(icon = src.icon, icon_state = src.icon_state, dir = src.dir) + I.layer = layer + I.appearance_flags = appearance_flags + I.color = src.color + I.alpha = src.alpha + I.pixel_x = src.pixel_x + I.pixel_y = src.pixel_y + if(detail_overlay) + I.overlays |= overlay_image(icon, "[detail_overlay]", color = detail_color, flags=RESET_COLOR) + floor_decals[cache_key] = I + LAZYDISTINCTADD(T.decals, floor_decals[cache_key]) + T.queue_icon_update() + qdel(src) + +/obj/effect/floor_decal/reset + name = "reset marker" + +/obj/effect/floor_decal/reset/Initialize() + ..() + var/turf/T = get_turf(src) + T?.remove_decals() + atom_flags |= ATOM_FLAG_INITIALIZED + return INITIALIZE_HINT_QDEL + +/obj/effect/floor_decal/undo + name = "undo marker" + +/obj/effect/floor_decal/undo/Initialize() + SHOULD_CALL_PARENT(FALSE) + var/turf/T = get_turf(src) + if(T && length(T.decals)) + T.decals.len-- + UNSETEMPTY(T.decals) + T.update_icon() + atom_flags |= ATOM_FLAG_INITIALIZED + return INITIALIZE_HINT_QDEL + +/obj/effect/floor_decal/carpet + name = "brown carpet" + icon = 'icons/turf/flooring/carpet.dmi' + icon_state = "brown_edges" + +/obj/effect/floor_decal/carpet/blue + name = "blue carpet" + icon_state = "blue1_edges" + +/obj/effect/floor_decal/carpet/blue2 + name = "pale blue carpet" + icon_state = "blue2_edges" + +/obj/effect/floor_decal/carpet/purple + name = "purple carpet" + icon_state = "purple_edges" + +/obj/effect/floor_decal/carpet/orange + name = "orange carpet" + icon_state = "orange_edges" + +/obj/effect/floor_decal/carpet/green + name = "green carpet" + icon_state = "green_edges" + +/obj/effect/floor_decal/carpet/red + name = "red carpet" + icon_state = "red_edges" + +/obj/effect/floor_decal/carpet/corners + name = "brown carpet" + icon_state = "brown_corners" + +/obj/effect/floor_decal/carpet/blue/corners + name = "blue carpet" + icon_state = "blue1_corners" + +/obj/effect/floor_decal/carpet/blue2/corners + name = "pale blue carpet" + icon_state = "blue2_corners" + +/obj/effect/floor_decal/carpet/purple/corners + name = "purple carpet" + icon_state = "purple_corners" + +/obj/effect/floor_decal/carpet/orange/corners + name = "orange carpet" + icon_state = "orange_corners" + +/obj/effect/floor_decal/carpet/green/corners + name = "green carpet" + icon_state = "green_corners" + +/obj/effect/floor_decal/carpet/red/corners + name = "red carpet" + icon_state = "red_corners" + +/obj/effect/floor_decal/corner + icon_state = "corner_white" + alpha = 229 + +/obj/effect/floor_decal/corner/black + name = "black corner" + color = "#333333" + +/obj/effect/floor_decal/corner/black/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/black/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/black/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/black/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/black/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/black/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/black/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/black/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/black/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/black/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/blue + name = "blue corner" + color = COLOR_BLUE_GRAY + +/obj/effect/floor_decal/corner/blue/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/blue/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/blue/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/blue/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/blue/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/blue/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/blue/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/blue/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/blue/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/blue/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/paleblue + name = "pale blue corner" + color = COLOR_PALE_BLUE_GRAY + +/obj/effect/floor_decal/corner/paleblue/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/paleblue/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/paleblue/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/paleblue/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/paleblue/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/paleblue/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/paleblue/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/paleblue/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/paleblue/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/paleblue/bordercee + icon_state = "bordercolorcee" + + +/obj/effect/floor_decal/corner/navyblue + name = "navy blue corner" + color = COLOR_NAVY_BLUE + +/obj/effect/floor_decal/corner/navyblue/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/navyblue/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/navyblue/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/navyblue/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/navyblue/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/navyblue/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/navyblue/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/navyblue/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/navyblue/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/navyblue/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/green + name = "green corner" + color = COLOR_GREEN_GRAY + +/obj/effect/floor_decal/corner/green/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/green/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/green/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/green/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/green/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/green/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/green/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/green/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/green/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/green/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/lime + name = "lime corner" + color = COLOR_PALE_GREEN_GRAY + +/obj/effect/floor_decal/corner/lime/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/lime/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/lime/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/lime/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/lime/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/lime/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/lime/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/lime/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/lime/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/lime/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/yellow + name = "yellow corner" + color = COLOR_BROWN + +/obj/effect/floor_decal/corner/yellow/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/yellow/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/yellow/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/yellow/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/yellow/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/yellow/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/yellow/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/yellow/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/yellow/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/yellow/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/beige + name = "beige corner" + color = COLOR_BEIGE + +/obj/effect/floor_decal/corner/beige/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/beige/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/beige/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/beige/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/beige/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/beige/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/beige/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/beige/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/beige/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/beige/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/red + name = "red corner" + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/corner/red/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/red/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/red/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/red/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/red/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/red/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/red/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/red/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/red/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/red/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/pink + name = "pink corner" + color = COLOR_PALE_RED_GRAY + +/obj/effect/floor_decal/corner/pink/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/pink/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/pink/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/pink/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/pink/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/pink/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/pink/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/pink/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/pink/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/pink/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/purple + name = "purple corner" + color = COLOR_PURPLE_GRAY + +/obj/effect/floor_decal/corner/purple/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/purple/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/purple/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/purple/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/purple/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/purple/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/purple/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/purple/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/purple/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/purple/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/mauve + name = "mauve corner" + color = COLOR_PALE_PURPLE_GRAY + +/obj/effect/floor_decal/corner/mauve/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/mauve/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/mauve/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/mauve/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/mauve/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/mauve/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/mauve/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/mauve/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/mauve/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/mauve/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/orange + name = "orange corner" + color = COLOR_DARK_ORANGE + +/obj/effect/floor_decal/corner/orange/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/orange/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/orange/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/orange/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/orange/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/orange/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/orange/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/orange/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/orange/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/orange/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/brown + name = "brown corner" + color = COLOR_DARK_BROWN + +/obj/effect/floor_decal/corner/brown/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/brown/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/brown/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/brown/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/brown/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/brown/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/brown/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/brown/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/brown/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/brown/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/white + name = "white corner" + icon_state = "corner_white" + +/obj/effect/floor_decal/corner/white/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/white/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/white/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/white/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/white/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/grey + name = "grey corner" + color = "#8d8c8c" + +/obj/effect/floor_decal/corner/grey/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/grey/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/grey/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/white/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/grey/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/grey/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/white/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/white/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/white/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/white/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/grey/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/grey/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/grey/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/grey/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/grey/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/grey/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/grey/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/lightgrey + name = "lightgrey corner" + color = "#a8b2b6" + +/obj/effect/floor_decal/corner/lightgrey/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/lightgrey/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/lightgrey/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/lightgrey/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/lightgrey/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/lightgrey/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/lightgrey/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/lightgrey/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/lightgrey/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/lightgrey/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/b_green + name = "bottle green corner" + color = COLOR_PALE_BTL_GREEN + +/obj/effect/floor_decal/corner/b_green/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/b_green/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/b_green/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/b_green/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/b_green/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/b_green/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/b_green/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/b_green/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/b_green/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/b_green/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/corner/research + name = "research corner" + color = COLOR_RESEARCH + +/obj/effect/floor_decal/corner/research/diagonal + icon_state = "corner_white_diagonal" + +/obj/effect/floor_decal/corner/research/three_quarters + icon_state = "corner_white_three_quarters" + +/obj/effect/floor_decal/corner/research/full + icon_state = "corner_white_full" + +/obj/effect/floor_decal/corner/research/border + icon_state = "bordercolor" + +/obj/effect/floor_decal/corner/research/half + icon_state = "bordercolorhalf" + +/obj/effect/floor_decal/corner/research/mono + icon_state = "bordercolormonofull" + +/obj/effect/floor_decal/corner/research/bordercorner + icon_state = "bordercolorcorner" + +/obj/effect/floor_decal/corner/research/bordercorner2 + icon_state = "bordercolorcorner2" + +/obj/effect/floor_decal/corner/research/borderfull + icon_state = "bordercolorfull" + +/obj/effect/floor_decal/corner/research/bordercee + icon_state = "bordercolorcee" + +/obj/effect/floor_decal/spline + abstract_type = /obj/effect/floor_decal/spline + +/obj/effect/floor_decal/spline/plain + name = "spline - plain" + icon_state = "spline_plain" + alpha = 229 + +/obj/effect/floor_decal/spline/plain/black + color = "#333333" + +/obj/effect/floor_decal/spline/plain/blue + color = COLOR_BLUE_GRAY + +/obj/effect/floor_decal/spline/plain/paleblue + color = COLOR_PALE_BLUE_GRAY + +/obj/effect/floor_decal/spline/plain/green + color = COLOR_GREEN_GRAY + +/obj/effect/floor_decal/spline/plain/lime + color = COLOR_PALE_GREEN_GRAY + +/obj/effect/floor_decal/spline/plain/yellow + color = COLOR_BROWN + +/obj/effect/floor_decal/spline/plain/beige + color = COLOR_BEIGE + +/obj/effect/floor_decal/spline/plain/red + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/spline/plain/pink + color = COLOR_PALE_RED_GRAY + +/obj/effect/floor_decal/spline/plain/purple + color = COLOR_PURPLE_GRAY + +/obj/effect/floor_decal/spline/plain/mauve + color = COLOR_PALE_PURPLE_GRAY + +/obj/effect/floor_decal/spline/plain/orange + color = COLOR_DARK_ORANGE + +/obj/effect/floor_decal/spline/plain/brown + color = COLOR_DARK_BROWN + +/obj/effect/floor_decal/spline/plain/white + color = COLOR_WHITE + +/obj/effect/floor_decal/spline/plain/grey + color = "#8d8c8c" + +/obj/effect/floor_decal/spline/fancy + name = "spline - fancy" + icon_state = "spline_fancy" + +/obj/effect/floor_decal/spline/fancy/black + color = COLOR_GRAY + +/obj/effect/floor_decal/spline/fancy/black/corner + icon_state = "spline_fancy_corner" + +/obj/effect/floor_decal/spline/fancy/wood + name = "spline - wood" + color = "#cb9e04" + +/obj/effect/floor_decal/spline/fancy/wood/corner + icon_state = "spline_fancy_corner" + +/obj/effect/floor_decal/spline/fancy/wood/cee + icon_state = "spline_fancy_cee" + +/obj/effect/floor_decal/spline/fancy/wood/three_quarters + icon_state = "spline_fancy_full" + +/obj/effect/floor_decal/spline/fancy/wood/walnut + name = "spline - walnut" + color = WOOD_COLOR_CHOCOLATE + +/obj/effect/floor_decal/spline/fancy/wood/corner/walnut + color = WOOD_COLOR_CHOCOLATE + +/obj/effect/floor_decal/spline/fancy/wood/cee/walnut + color = WOOD_COLOR_CHOCOLATE + +/obj/effect/floor_decal/spline/fancy/wood/three_quarters/walnut + color = WOOD_COLOR_CHOCOLATE + +/obj/effect/floor_decal/industrial + abstract_type = /obj/effect/floor_decal/industrial + +/obj/effect/floor_decal/industrial/danger + name = "hazard stripes" + icon_state = "danger" + +/obj/effect/floor_decal/industrial/danger/corner + icon_state = "dangercorner" + +/obj/effect/floor_decal/industrial/danger/full + icon_state = "dangerfull" + +/obj/effect/floor_decal/industrial/danger/cee + icon_state = "dangercee" + +/obj/effect/floor_decal/industrial/warning + name = "hazard stripes" + color = "#d2d53d" + icon_state = "stripe" + +/obj/effect/floor_decal/industrial/warning/corner + icon_state = "stripecorner" + +/obj/effect/floor_decal/industrial/warning/full + icon_state = "stripefull" + + +/obj/effect/floor_decal/industrial/warning/cee + icon_state = "stripecee" + +/obj/effect/floor_decal/industrial/warning/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/custodial + name = "custodial stripes" + icon_state = "stripe" + +/obj/effect/floor_decal/industrial/custodial/corner + icon_state = "stripecorner" + +/obj/effect/floor_decal/industrial/custodial/full + icon_state = "stripefull" + +/obj/effect/floor_decal/industrial/custodial/cee + icon_state = "stripecee" + +/obj/effect/floor_decal/industrial/custodial/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/fire + name = "fire safety stripes" + icon_state = "stripe" + detail_overlay = "overstripe" + detail_color = "#c90000" + +/obj/effect/floor_decal/industrial/fire/corner + icon_state = "stripecorner" + detail_overlay = "overstripecorner" + +/obj/effect/floor_decal/industrial/fire/full + icon_state = "stripefull" + detail_overlay = "overstripefull" + +/obj/effect/floor_decal/industrial/fire/cee + icon_state = "stripecee" + detail_overlay = "overstripecee" + +/obj/effect/floor_decal/industrial/fire/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/radiation + name = "radiation hazard stripes" + icon_state = "stripe" + color = "#d2d53d" + detail_overlay = "overstripe" + detail_color = "#c900fb" + +/obj/effect/floor_decal/industrial/radiation/corner + icon_state = "stripecorner" + detail_overlay = "overstripecorner" + +/obj/effect/floor_decal/industrial/radiation/full + icon_state = "stripefull" + detail_overlay = "overstripefull" + +/obj/effect/floor_decal/industrial/radiation/cee + icon_state = "stripecee" + detail_overlay = "overstripecee" + +/obj/effect/floor_decal/industrial/radiation/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/firstaid + name = "first aid stripes" + icon_state = "stripe" + detail_overlay = "overstripe" + detail_color = "#00cd00" + +/obj/effect/floor_decal/industrial/firstaid/corner + icon_state = "stripecorner" + detail_overlay = "overstripecorner" + +/obj/effect/floor_decal/industrial/firstaid/full + icon_state = "stripefull" + detail_overlay = "overstripefull" + +/obj/effect/floor_decal/industrial/firstaid/cee + icon_state = "stripecee" + detail_overlay = "overstripecee" + +/obj/effect/floor_decal/industrial/firstaid/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/defective + name = "defective machinery stripes" + icon_state = "stripe" + detail_overlay = "overstripe" + detail_color = "#0000fb" + +/obj/effect/floor_decal/industrial/defective/corner + icon_state = "stripecorner" + detail_overlay = "overstripecorner" + +/obj/effect/floor_decal/industrial/defective/full + icon_state = "stripefull" + detail_overlay = "overstripefull" + +/obj/effect/floor_decal/industrial/defective/cee + icon_state = "stripecee" + detail_overlay = "overstripecee" + +/obj/effect/floor_decal/industrial/defective/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/traffic + name = "traffic hazard stripes" + icon_state = "stripe" + detail_overlay = "overstripe" + detail_color = "#fb9700" + +/obj/effect/floor_decal/industrial/traffic/corner + icon_state = "stripecorner" + detail_overlay = "overstripecorner" + +/obj/effect/floor_decal/industrial/traffic/full + icon_state = "stripefull" + detail_overlay = "overstripefull" + +/obj/effect/floor_decal/industrial/traffic/cee + icon_state = "stripecee" + detail_overlay = "overstripecee" + +/obj/effect/floor_decal/industrial/traffic/fulltile + icon_state = "stripefulltile" + +/obj/effect/floor_decal/industrial/warning/dust + name = "hazard stripes" + icon_state = "warning_dust" + +/obj/effect/floor_decal/industrial/warning/dust/corner + name = "hazard stripes" + icon_state = "warningcorner_dust" + +/obj/effect/floor_decal/industrial/hatch + name = "hatched marking" + icon_state = "delivery" + alpha = 229 + +/obj/effect/floor_decal/industrial/hatch/yellow + color = "#cfcf55" + +/obj/effect/floor_decal/industrial/hatch/red + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/industrial/hatch/orange + color = COLOR_DARK_ORANGE + +/obj/effect/floor_decal/industrial/hatch/blue + color = COLOR_BLUE_GRAY + +/obj/effect/floor_decal/industrial/shutoff + name = "shutoff valve marker" + icon_state = "shutoff" + +/obj/effect/floor_decal/industrial/outline + name = "white outline" + icon_state = "outline" + alpha = 229 + +/obj/effect/floor_decal/industrial/outline/blue + name = "blue outline" + color = "#00b8b2" + +/obj/effect/floor_decal/industrial/outline/yellow + name = "yellow outline" + color = "#cfcf55" + +/obj/effect/floor_decal/industrial/outline/grey + name = "grey outline" + color = "#808080" + +/obj/effect/floor_decal/industrial/outline/red + name = "red outline" + color = COLOR_RED_GRAY + +/obj/effect/floor_decal/industrial/outline/orange + name = "orange outline" + color = COLOR_DARK_ORANGE + +/obj/effect/floor_decal/industrial/loading + name = "loading area" + icon_state = "loadingarea" + alpha = 229 + +/obj/effect/floor_decal/plaque + name = "plaque" + icon_state = "plaque" + +/obj/effect/floor_decal/asteroid + name = "random asteroid rubble" + icon_state = "asteroid0" + +/obj/effect/floor_decal/beach + name = "sandy border" + icon = 'icons/misc/beach.dmi' + icon_state = "beachborder" + +/obj/effect/floor_decal/beach/corner + icon_state = "beachbordercorner" + +/obj/effect/floor_decal/asteroid/Initialize() + . = ..() + icon_state = "asteroid[rand(0,9)]" + +/obj/effect/floor_decal/chapel + name = "chapel" + icon_state = "chapel" + +/obj/effect/floor_decal/ss13 + abstract_type = /obj/effect/floor_decal/ss13 + +/obj/effect/floor_decal/ss13/l1 + name = "L1" + icon_state = "L1" + +/obj/effect/floor_decal/ss13/l2 + name = "L2" + icon_state = "L2" + +/obj/effect/floor_decal/ss13/l3 + name = "L3" + icon_state = "L3" + +/obj/effect/floor_decal/ss13/l4 + name = "L4" + icon_state = "L4" + +/obj/effect/floor_decal/ss13/l5 + name = "L5" + icon_state = "L5" + +/obj/effect/floor_decal/ss13/l6 + name = "L6" + icon_state = "L6" + +/obj/effect/floor_decal/ss13/l7 + name = "L7" + icon_state = "L7" + +/obj/effect/floor_decal/ss13/l8 + name = "L8" + icon_state = "L8" + +/obj/effect/floor_decal/ss13/l9 + name = "L9" + icon_state = "L9" + +/obj/effect/floor_decal/ss13/l10 + name = "L10" + icon_state = "L10" + +/obj/effect/floor_decal/ss13/l11 + name = "L11" + icon_state = "L11" + +/obj/effect/floor_decal/ss13/l12 + name = "L12" + icon_state = "L12" + +/obj/effect/floor_decal/ss13/l13 + name = "L13" + icon_state = "L13" + +/obj/effect/floor_decal/ss13/l14 + name = "L14" + icon_state = "L14" + +/obj/effect/floor_decal/ss13/l15 + name = "L15" + icon_state = "L15" + +/obj/effect/floor_decal/ss13/l16 + name = "L16" + icon_state = "L16" + +/obj/effect/floor_decal/sign + name = "floor sign" + icon_state = "white_1" + +/obj/effect/floor_decal/sign/two + icon_state = "white_2" + +/obj/effect/floor_decal/sign/a + icon_state = "white_a" + +/obj/effect/floor_decal/sign/b + icon_state = "white_b" + +/obj/effect/floor_decal/sign/c + icon_state = "white_c" + +/obj/effect/floor_decal/sign/d + icon_state = "white_d" + +/obj/effect/floor_decal/sign/d/one + icon_state = "white_d1" + +/obj/effect/floor_decal/sign/d/two + icon_state = "white_d2" + +/obj/effect/floor_decal/sign/d/three + icon_state = "white_d3" + +/obj/effect/floor_decal/sign/ex + icon_state = "white_ex" + +/obj/effect/floor_decal/sign/m + icon_state = "white_m" + +/obj/effect/floor_decal/sign/cmo + icon_state = "white_cmo" + +/obj/effect/floor_decal/sign/v + icon_state = "white_v" + +/obj/effect/floor_decal/sign/p + icon_state = "white_p" + +/obj/effect/floor_decal/solarpanel + icon_state = "solarpanel" + +/obj/effect/floor_decal/snow_floor + icon = 'icons/turf/overlays.dmi' + icon_state = "snowfloor" + +/obj/effect/floor_decal/floordetail + layer = TURF_DETAIL_LAYER + color = COLOR_GUNMETAL + icon_state = "manydot" + appearance_flags = 0 + +/obj/effect/floor_decal/floordetail/Initialize() + color = null //color is here just for map preview, if left it applies both our and tile colors. + . = ..() + +/obj/effect/floor_decal/floordetail/tiled + icon_state = "manydot_tiled" + +/obj/effect/floor_decal/floordetail/pryhole + icon_state = "pryhole" + +/obj/effect/floor_decal/floordetail/edgedrain + icon_state = "edge" + +/obj/effect/floor_decal/floordetail/traction + icon_state = "traction" + +/obj/effect/floor_decal/ntlogo + icon_state = "ntlogo" + +/obj/effect/floor_decal/exologo + alpha = 230 + icon = 'icons/turf/flooring/corp_floor.dmi' + icon_state = "bottomleft" + +//Techfloor + +/obj/effect/floor_decal/corner_techfloor_gray + name = "corner techfloorgray" + icon_state = "corner_techfloor_gray" + +/obj/effect/floor_decal/corner_techfloor_gray/diagonal + name = "corner techfloorgray diagonal" + icon_state = "corner_techfloor_gray_diagonal" + +/obj/effect/floor_decal/corner_techfloor_gray/full + name = "corner techfloorgray full" + icon_state = "corner_techfloor_gray_full" + +/obj/effect/floor_decal/corner_techfloor_grid + name = "corner techfloorgrid" + icon_state = "corner_techfloor_grid" + +/obj/effect/floor_decal/corner_techfloor_grid/diagonal + name = "corner techfloorgrid diagonal" + icon_state = "corner_techfloor_grid_diagonal" + +/obj/effect/floor_decal/corner_techfloor_grid/full + name = "corner techfloorgrid full" + icon_state = "corner_techfloor_grid_full" + +/obj/effect/floor_decal/corner_steel_grid + name = "corner steel_grid" + icon_state = "steel_grid" + +/obj/effect/floor_decal/corner_steel_grid/diagonal + name = "corner tsteel_grid diagonal" + icon_state = "steel_grid_diagonal" + +/obj/effect/floor_decal/corner_steel_grid/full + name = "corner steel_grid full" + icon_state = "steel_grid_full" + +/obj/effect/floor_decal/borderfloor + name = "border floor" + icon_state = "borderfloor_white" + color = COLOR_GUNMETAL + +/obj/effect/floor_decal/borderfloor/corner + icon_state = "borderfloorcorner_white" + +/obj/effect/floor_decal/borderfloor/corner2 + icon_state = "borderfloorcorner2_white" + +/obj/effect/floor_decal/borderfloor/full + icon_state = "borderfloorfull_white" + +/obj/effect/floor_decal/borderfloor/cee + icon_state = "borderfloorcee_white" + +/obj/effect/floor_decal/borderfloorblack + name = "border floor" + icon_state = "borderfloor_white" + color = COLOR_DARK_GRAY + +/obj/effect/floor_decal/borderfloorblack/corner + icon_state = "borderfloorcorner_white" + +/obj/effect/floor_decal/borderfloorblack/corner2 + icon_state = "borderfloorcorner2_white" + +/obj/effect/floor_decal/borderfloorblack/full + icon_state = "borderfloorfull_white" + +/obj/effect/floor_decal/borderfloorblack/cee + icon_state = "borderfloorcee_white" + +/obj/effect/floor_decal/borderfloorwhite + name = "border floor" + icon_state = "borderfloor_white" + +/obj/effect/floor_decal/borderfloorwhite/corner + icon_state = "borderfloorcorner_white" + +/obj/effect/floor_decal/borderfloorwhite/corner2 + icon_state = "borderfloorcorner2_white" + +/obj/effect/floor_decal/borderfloorwhite/full + icon_state = "borderfloorfull_white" + +/obj/effect/floor_decal/borderfloorwhite/cee + icon_state = "borderfloorcee_white" + +/obj/effect/floor_decal/steeldecal + name = "steel decal" + icon_state = "steel_decals1" + color = COLOR_GUNMETAL + +/obj/effect/floor_decal/steeldecal/steel_decals1 + icon_state = "steel_decals1" + +/obj/effect/floor_decal/steeldecal/steel_decals2 + icon_state = "steel_decals2" + +/obj/effect/floor_decal/steeldecal/steel_decals3 + icon_state = "steel_decals3" + +/obj/effect/floor_decal/steeldecal/steel_decals4 + icon_state = "steel_decals4" + +/obj/effect/floor_decal/steeldecal/steel_decals5 + icon_state = "steel_decals5" + +/obj/effect/floor_decal/steeldecal/steel_decals6 + icon_state = "steel_decals6" + +/obj/effect/floor_decal/steeldecal/steel_decals7 + icon_state = "steel_decals7" + +/obj/effect/floor_decal/steeldecal/steel_decals8 + icon_state = "steel_decals8" + +/obj/effect/floor_decal/steeldecal/steel_decals9 + icon_state = "steel_decals9" + +/obj/effect/floor_decal/steeldecal/steel_decals10 + icon_state = "steel_decals10" + +/obj/effect/floor_decal/steeldecal/steel_decals_central1 + icon_state = "steel_decals_central1" + +/obj/effect/floor_decal/steeldecal/steel_decals_central2 + icon_state = "steel_decals_central2" + +/obj/effect/floor_decal/steeldecal/steel_decals_central3 + icon_state = "steel_decals_central3" + +/obj/effect/floor_decal/steeldecal/steel_decals_central4 + icon_state = "steel_decals_central4" + +/obj/effect/floor_decal/steeldecal/steel_decals_central5 + icon_state = "steel_decals_central5" + +/obj/effect/floor_decal/steeldecal/steel_decals_central6 + icon_state = "steel_decals_central6" + +/obj/effect/floor_decal/steeldecal/steel_decals_central7 + icon_state = "steel_decals_central7" + +/obj/effect/floor_decal/techfloor + name = "techfloor edges" + icon_state = "techfloor_edges" + layer = DECAL_LAYER - 0.005 // so other decals can show up over it + +/obj/effect/floor_decal/techfloor/corner + name = "techfloor corner" + icon_state = "techfloor_corners" + +/obj/effect/floor_decal/techfloor/orange + name = "techfloor edges" + icon_state = "techfloororange_edges" + +/obj/effect/floor_decal/techfloor/orange/corner + name = "techfloor corner" + icon_state = "techfloororange_corners" + +/obj/effect/floor_decal/techfloor/hole + name = "hole left" + icon_state = "techfloor_hole_left" + +/obj/effect/floor_decal/techfloor/hole/right + name = "hole right" + icon_state = "techfloor_hole_right" + +/obj/effect/floor_decal/stoneborder + name = "stone border" + icon_state = "stoneborder" + +/obj/effect/floor_decal/stoneborder/corner + icon_state = "stoneborder_c" + +/obj/effect/floor_decal/rust + name = "rust" + icon_state = "rust" + +/obj/effect/floor_decal/rust/part_rusted1 + icon_state = "part_rusted1" + +/obj/effect/floor_decal/rust/part_rusted2 + icon_state = "part_rusted2" + +/obj/effect/floor_decal/rust/part_rusted3 + icon_state = "part_rusted3" + +/obj/effect/floor_decal/rust/mono_rusted1 + icon_state = "mono_rusted1" + +/obj/effect/floor_decal/rust/mono_rusted2 + icon_state = "mono_rusted2" + +/obj/effect/floor_decal/rust/mono_rusted3 + icon_state = "mono_rusted3" +/obj/effect/floor_decal/rust/steel_decals_rusted1 + icon_state = "steel_decals_rusted1" + +/obj/effect/floor_decal/rust/steel_decals_rusted2 + icon_state = "steel_decals_rusted2" + +/obj/effect/floor_decal/rust/color_rusted + icon_state = "color_rusted" + +/obj/effect/floor_decal/rust/color_rustedcorner + icon_state = "color_rustedcorner" + +/obj/effect/floor_decal/rust/color_rustedfull + icon_state = "color_rustedfull" + +/obj/effect/floor_decal/rust/color_rustedcee + icon_state = "color_rustedcee" + +/obj/effect/floor_decal/sign/small_a + icon_state = "small_a" + +/obj/effect/floor_decal/sign/small_b + icon_state = "small_b" + +/obj/effect/floor_decal/sign/small_c + icon_state = "small_c" + +/obj/effect/floor_decal/sign/small_d + icon_state = "small_d" + +/obj/effect/floor_decal/sign/small_e + icon_state = "small_e" + +/obj/effect/floor_decal/sign/small_f + icon_state = "small_f" + +/obj/effect/floor_decal/sign/small_g + icon_state = "small_g" + +/obj/effect/floor_decal/sign/small_h + icon_state = "small_h" + +/obj/effect/floor_decal/sign/small_1 + icon_state = "small_1" + +/obj/effect/floor_decal/sign/small_2 + icon_state = "small_2" + +/obj/effect/floor_decal/sign/small_3 + icon_state = "small_3" + +/obj/effect/floor_decal/sign/small_4 + icon_state = "small_4" + +/obj/effect/floor_decal/sign/small_5 + icon_state = "small_5" + +/obj/effect/floor_decal/sign/small_6 + icon_state = "small_6" + +/obj/effect/floor_decal/sign/small_7 + icon_state = "small_7" + +/obj/effect/floor_decal/sign/small_8 + icon_state = "small_8" + +/obj/effect/floor_decal/arrow + name = "floor arrow" + icon_state = "arrow_single" + +/obj/effect/floor_decal/arrows + name = "floor arrows" + icon_state = "arrows" + +//Old tile, taken from Polaris +//TODO: Change these colors to use color defines? +/obj/effect/floor_decal/corner_oldtile + name = "corner oldtile" + icon_state = "corner_oldtile" + +/obj/effect/floor_decal/corner_oldtile/white + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#d9d9d9" + +/obj/effect/floor_decal/corner_oldtile/white/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/white/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/blue + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#8ba7ad" + +/obj/effect/floor_decal/corner_oldtile/blue/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/blue/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/yellow + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#8c6d46" + +/obj/effect/floor_decal/corner_oldtile/yellow/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/yellow/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/gray + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#687172" + +/obj/effect/floor_decal/corner_oldtile/gray/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/gray/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/beige + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#385e60" + +/obj/effect/floor_decal/corner_oldtile/beige/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/beige/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/red + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#964e51" + +/obj/effect/floor_decal/corner_oldtile/red/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/red/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/purple + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#906987" + +/obj/effect/floor_decal/corner_oldtile/purple/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/purple/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +/obj/effect/floor_decal/corner_oldtile/green + name = "corner oldtile" + icon_state = "corner_oldtile" + color = "#46725c" + +/obj/effect/floor_decal/corner_oldtile/green/diagonal + name = "corner oldtile diagonal" + icon_state = "corner_oldtile_diagonal" + +/obj/effect/floor_decal/corner_oldtile/green/full + name = "corner oldtile full" + icon_state = "corner_oldtile_full" + +// Decorative overlays. +/obj/effect/floor_decal/vines + name = "vines" + desc = "A tangle of plant growth." + icon_state = "vines" + +/obj/effect/floor_decal/vines/top + icon_state = "vines_top" + +/obj/effect/floor_decal/vines/mid + icon_state = "vines_mid" + +/obj/effect/floor_decal/vines/bottom + icon_state = "vines_bottom" + +/obj/effect/floor_decal/snow + name = "snow" + desc = "A fine dusting of snow." + icon_state = "snowy" + +/obj/effect/floor_decal/rust + name = "rust" + desc = "A clumpy area of rust." + icon_state = "rusted" + +/obj/effect/floor_decal/floornums + name = "floor marker" + desc = "A number corresponding to the position of this floor." + icon_state = "floornums" diff --git a/code/game/turfs/flooring/flooring.dm b/code/game/turfs/flooring/flooring.dm deleted file mode 100644 index 90ded8548416..000000000000 --- a/code/game/turfs/flooring/flooring.dm +++ /dev/null @@ -1,371 +0,0 @@ -// State values: -// [icon_base]: initial base icon_state without edges or corners. -// if has_base_range is set, append 0-has_base_range ie. -// [icon_base][has_base_range] -// [icon_base]_broken: damaged overlay. -// if has_damage_range is set, append 0-damage_range for state ie. -// [icon_base]_broken[has_damage_range] -// [icon_base]_edges: directional overlays for edges. -// [icon_base]_corners: directional overlays for non-edge corners. - -/decl/flooring - var/name - var/desc - var/icon - var/icon_base - var/color - var/footstep_type = /decl/footsteps/blank - - var/has_base_range - var/has_damage_range - var/has_burn_range - var/damage_temperature - var/apply_thermal_conductivity - var/apply_heat_capacity - - var/build_type // Unbuildable if not set. Must be /obj/item/stack. - var/build_cost = 1 // Stack units. - var/build_time = 0 // BYOND ticks. - - var/descriptor = "tiles" - var/flags - var/can_paint - var/can_engrave = TRUE - - //How we smooth with other flooring - var/decal_layer = DECAL_LAYER - var/floor_smooth = SMOOTH_ALL - var/list/flooring_whitelist = list() //Smooth with nothing except the contents of this list - var/list/flooring_blacklist = list() //Smooth with everything except the contents of this list - - //How we smooth with walls - var/wall_smooth = SMOOTH_ALL - //There are no lists for walls at this time - - //How we smooth with space and openspace tiles - var/space_smooth = SMOOTH_ALL - //There are no lists for spaces - -/decl/flooring/proc/on_remove() - return - -/decl/flooring/grass - name = "grass" - desc = "Do they smoke grass out in space, Bowie? Or do they smoke AstroTurf?" - icon = 'icons/turf/flooring/grass.dmi' - icon_base = "grass" - has_base_range = 3 - damage_temperature = T0C+80 - flags = TURF_HAS_EDGES | TURF_HAS_CORNERS | TURF_REMOVE_SHOVEL - build_type = /obj/item/stack/tile/grass - can_engrave = FALSE - floor_smooth = SMOOTH_NONE - wall_smooth = SMOOTH_ALL - space_smooth = SMOOTH_NONE - decal_layer = ABOVE_WIRE_LAYER - -/decl/flooring/dirt - name = "dirt" - desc = "Extra dirty." - icon = 'icons/turf/flooring/grass.dmi' - icon_base = "dirt" - has_base_range = 3 - damage_temperature = T0C+80 - can_engrave = FALSE - footstep_type = /decl/footsteps/grass - -/decl/flooring/asteroid - name = "coarse sand" - desc = "Gritty and unpleasant." - icon = 'icons/turf/flooring/asteroid.dmi' - icon_base = "asteroid" - flags = TURF_HAS_EDGES | TURF_REMOVE_SHOVEL - build_type = null - can_engrave = FALSE - footstep_type = /decl/footsteps/asteroid - -/decl/flooring/carpet - name = "brown carpet" - desc = "Comfy and fancy carpeting." - icon = 'icons/turf/flooring/carpet.dmi' - icon_base = "brown" - build_type = /obj/item/stack/tile/carpet - damage_temperature = T0C+200 - flags = TURF_HAS_CORNERS | TURF_HAS_INNER_CORNERS | TURF_REMOVE_CROWBAR | TURF_CAN_BURN - can_engrave = FALSE - footstep_type = /decl/footsteps/carpet - floor_smooth = SMOOTH_NONE - wall_smooth = SMOOTH_NONE - space_smooth = SMOOTH_NONE - -/decl/flooring/carpet/blue - name = "blue carpet" - icon_base = "blue1" - build_type = /obj/item/stack/tile/carpetblue - -/decl/flooring/carpet/blue2 - name = "pale blue carpet" - icon_base = "blue2" - build_type = /obj/item/stack/tile/carpetblue2 - -/decl/flooring/carpet/blue3 - name = "sea blue carpet" - icon_base = "blue3" - build_type = /obj/item/stack/tile/carpetblue3 - -/decl/flooring/carpet/magenta - name = "magenta carpet" - icon_base = "purple" - build_type = /obj/item/stack/tile/carpetmagenta - -/decl/flooring/carpet/purple - name = "purple carpet" - icon_base = "purple" - build_type = /obj/item/stack/tile/carpetpurple - -/decl/flooring/carpet/orange - name = "orange carpet" - icon_base = "orange" - build_type = /obj/item/stack/tile/carpetorange - -/decl/flooring/carpet/green - name = "green carpet" - icon_base = "green" - build_type = /obj/item/stack/tile/carpetgreen - -/decl/flooring/carpet/red - name = "red carpet" - icon_base = "red" - build_type = /obj/item/stack/tile/carpetred - -/decl/flooring/linoleum - name = "linoleum" - desc = "It's like the 2090's all over again." - icon = 'icons/turf/flooring/linoleum.dmi' - icon_base = "lino" - can_paint = 1 - build_type = /obj/item/stack/tile/linoleum - flags = TURF_REMOVE_SCREWDRIVER - footstep_type = /decl/footsteps/tiles - -/decl/flooring/tiling - name = "floor" - desc = "A solid, heavy set of flooring plates." - icon = 'icons/turf/flooring/tiles.dmi' - icon_base = "tiled" - color = COLOR_DARK_GUNMETAL - has_damage_range = 4 - damage_temperature = T0C+1400 - flags = TURF_REMOVE_CROWBAR | TURF_CAN_BREAK | TURF_CAN_BURN - build_type = /obj/item/stack/tile/floor - can_paint = 1 - footstep_type = /decl/footsteps/tiles - -/decl/flooring/tiling/mono - icon_base = "monotile" - build_type = /obj/item/stack/tile/mono - -/decl/flooring/tiling/mono/dark - color = COLOR_DARK_GRAY - build_type = /obj/item/stack/tile/mono/dark - -/decl/flooring/tiling/mono/white - icon_base = "monotile_light" - color = COLOR_OFF_WHITE - build_type = /obj/item/stack/tile/mono/white - -/decl/flooring/tiling/white - icon_base = "tiled_light" - desc = "How sterile." - color = COLOR_OFF_WHITE - build_type = /obj/item/stack/tile/floor_white - -/decl/flooring/tiling/dark - desc = "How ominous." - color = COLOR_DARK_GRAY - build_type = /obj/item/stack/tile/floor_dark - -/decl/flooring/tiling/dark/mono - icon_base = "monotile" - build_type = null - -/decl/flooring/tiling/freezer - desc = "Don't slip." - icon_base = "freezer" - color = null - has_damage_range = null - flags = TURF_REMOVE_CROWBAR - build_type = /obj/item/stack/tile/floor_freezer - -/decl/flooring/tiling/tech - icon = 'icons/turf/flooring/techfloor.dmi' - icon_base = "techfloor_gray" - build_type = /obj/item/stack/tile/techgrey - color = null - -/decl/flooring/tiling/tech/grid - icon_base = "techfloor_grid" - build_type = /obj/item/stack/tile/techgrid - -/decl/flooring/tiling/new_tile - icon_base = "tile_full" - color = null - build_type = null - -/decl/flooring/tiling/new_tile/cargo_one - icon_base = "cargo_one_full" - build_type = null - -/decl/flooring/tiling/new_tile/kafel - icon_base = "kafel_full" - build_type = null - -/decl/flooring/tiling/stone - icon_base = "stone" - build_type = /obj/item/stack/tile/stone - -/decl/flooring/tiling/new_tile/techmaint - icon_base = "techmaint" - build_type = /obj/item/stack/tile/techmaint - -/decl/flooring/tiling/new_tile/monofloor - icon_base = "monofloor" - color = COLOR_GUNMETAL - -/decl/flooring/tiling/new_tile/steel_grid - icon_base = "grid" - color = COLOR_GUNMETAL - build_type = /obj/item/stack/tile/grid - -/decl/flooring/tiling/new_tile/steel_ridged - icon_base = "ridged" - color = COLOR_GUNMETAL - build_type = /obj/item/stack/tile/ridge - -/decl/flooring/wood - name = "wooden floor" - desc = "Polished wood planks." - icon = 'icons/turf/flooring/wood.dmi' - icon_base = "wood" - has_damage_range = 6 - damage_temperature = T0C+200 - descriptor = "planks" - build_type = /obj/item/stack/tile/wood - flags = TURF_CAN_BREAK | TURF_IS_FRAGILE | TURF_REMOVE_SCREWDRIVER - footstep_type = /decl/footsteps/wood - color = WOOD_COLOR_GENERIC - -/decl/flooring/wood/mahogany - color = WOOD_COLOR_RICH - build_type = /obj/item/stack/tile/mahogany - -/decl/flooring/wood/maple - color = WOOD_COLOR_PALE - build_type = /obj/item/stack/tile/maple - -/decl/flooring/wood/ebony - color = WOOD_COLOR_BLACK - build_type = /obj/item/stack/tile/ebony - -/decl/flooring/wood/walnut - color = WOOD_COLOR_CHOCOLATE - build_type = /obj/item/stack/tile/walnut - -/decl/flooring/wood/bamboo - color = WOOD_COLOR_PALE2 - build_type = /obj/item/stack/tile/bamboo - -/decl/flooring/wood/yew - color = WOOD_COLOR_YELLOW - build_type = /obj/item/stack/tile/yew - -/decl/flooring/reinforced - name = "reinforced floor" - desc = "Heavily reinforced with steel plating." - icon = 'icons/turf/flooring/tiles.dmi' - icon_base = "reinforced" - flags = TURF_REMOVE_WRENCH | TURF_ACID_IMMUNE - build_type = /obj/item/stack/material/steel - build_cost = 1 - build_time = 30 - apply_thermal_conductivity = 0.025 - apply_heat_capacity = 325000 - can_paint = 1 - footstep_type = /decl/footsteps/plating - -/decl/flooring/reinforced/circuit - name = "processing strata" - icon = 'icons/turf/flooring/circuit.dmi' - icon_base = "bcircuit" - build_type = null - flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_WRENCH - can_paint = 1 - can_engrave = FALSE - -/decl/flooring/reinforced/circuit/green - icon_base = "gcircuit" - -/decl/flooring/reinforced/circuit/red - icon_base = "rcircuit" - flags = TURF_ACID_IMMUNE - can_paint = 0 - -/decl/flooring/reinforced/cult - name = "engraved floor" - desc = "Unsettling whispers waver from the surface..." - icon = 'icons/turf/flooring/cult.dmi' - icon_base = "cult" - build_type = null - has_damage_range = 6 - flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_WRENCH - can_paint = null - -/decl/flooring/reinforced/cult/on_remove() - GLOB.cult.remove_cultiness(CULTINESS_PER_TURF) - -/decl/flooring/reinforced/shuttle - name = "floor" - icon = 'icons/turf/shuttle.dmi' - build_type = null - flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_CROWBAR - can_paint = 1 - can_engrave = FALSE - -/decl/flooring/reinforced/shuttle/blue - icon_base = "floor" - -/decl/flooring/reinforced/shuttle/yellow - icon_base = "floor2" - -/decl/flooring/reinforced/shuttle/white - icon_base = "floor3" - -/decl/flooring/reinforced/shuttle/red - icon_base = "floor4" - -/decl/flooring/reinforced/shuttle/purple - icon_base = "floor5" - -/decl/flooring/reinforced/shuttle/darkred - icon_base = "floor6" - -/decl/flooring/reinforced/shuttle/black - icon_base = "floor7" - -/decl/flooring/crystal - name = "crystal floor" - icon = 'icons/turf/flooring/crystal.dmi' - build_type = null - flags = TURF_ACID_IMMUNE | TURF_CAN_BREAK | TURF_REMOVE_CROWBAR - color = "#00ffe1" - -/decl/flooring/snow - name = "snow" - desc = "Let it sno-ow... Let it snow..." - icon = 'icons/turf/snow.dmi' - icon_base = "snow" - has_base_range = 12 - flags = TURF_REMOVE_SHOVEL - build_type = null - can_engrave = FALSE - footstep_type = /decl/footsteps/snow diff --git a/code/game/turfs/flooring/flooring_carpet.dm b/code/game/turfs/flooring/flooring_carpet.dm new file mode 100644 index 000000000000..4236c3c2597b --- /dev/null +++ b/code/game/turfs/flooring/flooring_carpet.dm @@ -0,0 +1,85 @@ +/decl/flooring/carpet + name = "brown carpet" + desc = "A stretch of cut pile carpet. Comfy and fancy." + icon = 'icons/turf/flooring/carpet.dmi' + icon_base = "brown" + icon_edge_layer = FLOOR_EDGE_CARPET + build_type = /obj/item/stack/tile/carpet + damage_temperature = T0C+200 + flooring_flags = TURF_REMOVE_CROWBAR + can_engrave = FALSE + footstep_type = /decl/footsteps/carpet + force_material = /decl/material/solid/organic/cloth + constructed = TRUE + uid = "floor_carpet" + burned_states = list( + "burned0", + "burned1" + ) + broken_states = list( + "broken0", + "broken1", + "broken2", + "broken3", + "broken4" + ) + +/decl/flooring/carpet/blue + name = "blue carpet" + icon_base = "blue1" + build_type = /obj/item/stack/tile/carpet/blue + uid = "floor_carpet_blue" + +/decl/flooring/carpet/blue2 + name = "pale blue carpet" + icon_base = "blue2" + build_type = /obj/item/stack/tile/carpet/blue2 + uid = "floor_carpet_blue2" + +/decl/flooring/carpet/blue3 + name = "sea blue carpet" + icon_base = "blue3" + build_type = /obj/item/stack/tile/carpet/blue3 + uid = "floor_carpet_blue3" + +/decl/flooring/carpet/magenta + name = "magenta carpet" + icon_base = "purple" + build_type = /obj/item/stack/tile/carpet/magenta + uid = "floor_carpet_magenta" + +/decl/flooring/carpet/purple + name = "purple carpet" + icon_base = "purple" + build_type = /obj/item/stack/tile/carpet/purple + uid = "floor_carpet_purple" + +/decl/flooring/carpet/orange + name = "orange carpet" + icon_base = "orange" + build_type = /obj/item/stack/tile/carpet/orange + uid = "floor_carpet_orange" + +/decl/flooring/carpet/green + name = "green carpet" + icon_base = "green" + build_type = /obj/item/stack/tile/carpet/green + uid = "floor_carpet_green" + +/decl/flooring/carpet/red + name = "red carpet" + icon_base = "red" + build_type = /obj/item/stack/tile/carpet/red + uid = "floor_carpet_red" + +/decl/flooring/carpet/rustic + name = "rustic carpet" + desc = "A stretch of simple woven carpet. Cozy, but a little itchy." + icon = 'icons/turf/flooring/simple_carpet.dmi' + icon_base = "carpet" + build_type = /obj/item/stack/tile/carpet/rustic + can_paint = TRUE + color = null + broken_states = null + burned_states = null + uid = "floor_carpet_rustic" diff --git a/code/game/turfs/flooring/flooring_concrete.dm b/code/game/turfs/flooring/flooring_concrete.dm new file mode 100644 index 000000000000..89ed297a1f7a --- /dev/null +++ b/code/game/turfs/flooring/flooring_concrete.dm @@ -0,0 +1,23 @@ +/decl/flooring/concrete + name = "concrete" + desc = "A flat expanse of stone-like artificial material." + icon = 'icons/turf/flooring/concrete.dmi' + icon_base = "inset" + has_base_range = null + force_material = /decl/material/solid/stone/concrete + constructed = TRUE + uid = "floor_concrete" + can_conceal_hazards = TRUE + +/decl/flooring/concrete/reinforced + name = "reinforced concrete" + icon_base = "hexacrete" + desc = "A flat stretch of stone-like artificial material. It has been reinforced with an unknown compound." + uid = "floor_concrete_reinf" + +/decl/flooring/concrete/asphalt + name = "asphalt" + color = COLOR_GRAY40 + icon_base = "concrete" + desc = "A stretch of rough blacktop, probably part of a road." + uid = "floor_asphalt" diff --git a/code/game/turfs/flooring/flooring_decals.dm b/code/game/turfs/flooring/flooring_decals.dm deleted file mode 100644 index 30f5f8d4fd91..000000000000 --- a/code/game/turfs/flooring/flooring_decals.dm +++ /dev/null @@ -1,1340 +0,0 @@ -// These are objects that destroy themselves and add themselves to the -// decal list of the floor under them. Use them rather than distinct icon_states -// when mapping in interesting floor designs. -var/list/floor_decals = list() - -/obj/effect/floor_decal - name = "floor decal" - icon = 'icons/turf/flooring/decals.dmi' - layer = DECAL_LAYER - appearance_flags = RESET_COLOR - var/supplied_dir - var/detail_overlay - var/detail_color - -// Have to wait for turfs to set up their flooring, so we can better guess at our layers. -/obj/effect/floor_decal/Initialize() - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/effect/floor_decal/LateInitialize(mapload, var/newdir, var/newcolour, var/newappearance) - supplied_dir = newdir - if(newappearance) appearance = newappearance - if(newcolour) color = newcolour - - if(supplied_dir) set_dir(supplied_dir) - var/turf/T = get_turf(src) - if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor)) - layer = T.is_plating() ? DECAL_PLATING_LAYER : DECAL_LAYER - var/cache_key = "[alpha]-[color]-[dir]-[icon_state]-[plane]-[layer]-[detail_overlay]-[detail_color]" - if(!floor_decals[cache_key]) - var/image/I = image(icon = src.icon, icon_state = src.icon_state, dir = src.dir) - I.layer = layer - I.appearance_flags = appearance_flags - I.color = src.color - I.alpha = src.alpha - if(detail_overlay) - var/image/B = overlay_image(icon, "[detail_overlay]", flags=RESET_COLOR) - B.color = detail_color - I.overlays |= B - floor_decals[cache_key] = I - if(!T.decals) T.decals = list() - T.decals |= floor_decals[cache_key] - T.overlays |= floor_decals[cache_key] - qdel(src) - -/obj/effect/floor_decal/reset - name = "reset marker" - -/obj/effect/floor_decal/reset/Initialize() - ..() - var/turf/T = get_turf(src) - T.remove_decals() - T.update_icon() - atom_flags |= ATOM_FLAG_INITIALIZED - return INITIALIZE_HINT_QDEL - -/obj/effect/floor_decal/carpet - name = "brown carpet" - icon = 'icons/turf/flooring/carpet.dmi' - icon_state = "brown_edges" - -/obj/effect/floor_decal/carpet/blue - name = "blue carpet" - icon_state = "blue1_edges" - -/obj/effect/floor_decal/carpet/blue2 - name = "pale blue carpet" - icon_state = "blue2_edges" - -/obj/effect/floor_decal/carpet/purple - name = "purple carpet" - icon_state = "purple_edges" - -/obj/effect/floor_decal/carpet/orange - name = "orange carpet" - icon_state = "orange_edges" - -/obj/effect/floor_decal/carpet/green - name = "green carpet" - icon_state = "green_edges" - -/obj/effect/floor_decal/carpet/red - name = "red carpet" - icon_state = "red_edges" - -/obj/effect/floor_decal/carpet/corners - name = "brown carpet" - icon_state = "brown_corners" - -/obj/effect/floor_decal/carpet/blue/corners - name = "blue carpet" - icon_state = "blue1_corners" - -/obj/effect/floor_decal/carpet/blue2/corners - name = "pale blue carpet" - icon_state = "blue2_corners" - -/obj/effect/floor_decal/carpet/purple/corners - name = "purple carpet" - icon_state = "purple_corners" - -/obj/effect/floor_decal/carpet/orange/corners - name = "orange carpet" - icon_state = "orange_corners" - -/obj/effect/floor_decal/carpet/green/corners - name = "green carpet" - icon_state = "green_corners" - -/obj/effect/floor_decal/carpet/red/corners - name = "red carpet" - icon_state = "red_corners" - -/obj/effect/floor_decal/corner - icon_state = "corner_white" - alpha = 229 - -/obj/effect/floor_decal/corner/black - name = "black corner" - color = "#333333" - -/obj/effect/floor_decal/corner/black/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/black/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/black/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/black/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/black/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/black/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/black/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/black/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/black/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/black/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/blue - name = "blue corner" - color = COLOR_BLUE_GRAY - -/obj/effect/floor_decal/corner/blue/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/blue/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/blue/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/blue/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/blue/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/blue/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/blue/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/blue/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/blue/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/blue/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/paleblue - name = "pale blue corner" - color = COLOR_PALE_BLUE_GRAY - -/obj/effect/floor_decal/corner/paleblue/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/paleblue/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/paleblue/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/paleblue/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/paleblue/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/paleblue/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/paleblue/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/paleblue/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/paleblue/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/paleblue/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/green - name = "green corner" - color = COLOR_GREEN_GRAY - -/obj/effect/floor_decal/corner/green/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/green/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/green/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/green/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/green/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/green/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/green/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/green/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/green/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/green/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/lime - name = "lime corner" - color = COLOR_PALE_GREEN_GRAY - -/obj/effect/floor_decal/corner/lime/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/lime/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/lime/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/lime/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/lime/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/lime/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/lime/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/lime/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/lime/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/lime/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/yellow - name = "yellow corner" - color = COLOR_BROWN - -/obj/effect/floor_decal/corner/yellow/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/yellow/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/yellow/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/yellow/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/yellow/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/yellow/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/yellow/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/yellow/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/yellow/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/yellow/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/beige - name = "beige corner" - color = COLOR_BEIGE - -/obj/effect/floor_decal/corner/beige/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/beige/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/beige/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/beige/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/beige/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/beige/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/beige/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/beige/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/beige/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/beige/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/red - name = "red corner" - color = COLOR_RED_GRAY - -/obj/effect/floor_decal/corner/red/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/red/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/red/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/red/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/red/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/red/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/red/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/red/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/red/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/red/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/pink - name = "pink corner" - color = COLOR_PALE_RED_GRAY - -/obj/effect/floor_decal/corner/pink/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/pink/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/pink/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/pink/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/pink/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/pink/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/pink/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/pink/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/pink/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/pink/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/purple - name = "purple corner" - color = COLOR_PURPLE_GRAY - -/obj/effect/floor_decal/corner/purple/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/purple/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/purple/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/purple/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/purple/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/purple/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/purple/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/purple/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/purple/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/purple/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/mauve - name = "mauve corner" - color = COLOR_PALE_PURPLE_GRAY - -/obj/effect/floor_decal/corner/mauve/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/mauve/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/mauve/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/mauve/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/mauve/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/mauve/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/mauve/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/mauve/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/mauve/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/mauve/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/orange - name = "orange corner" - color = COLOR_DARK_ORANGE - -/obj/effect/floor_decal/corner/orange/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/orange/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/orange/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/orange/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/orange/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/orange/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/orange/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/orange/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/orange/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/orange/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/brown - name = "brown corner" - color = COLOR_DARK_BROWN - -/obj/effect/floor_decal/corner/brown/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/brown/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/brown/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/brown/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/brown/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/brown/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/brown/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/brown/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/brown/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/brown/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/white - name = "white corner" - icon_state = "corner_white" - -/obj/effect/floor_decal/corner/white/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/white/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/white/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/white/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/white/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/grey - name = "grey corner" - color = "#8d8c8c" - -/obj/effect/floor_decal/corner/grey/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/grey/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/grey/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/white/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/grey/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/grey/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/white/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/white/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/white/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/white/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/grey/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/grey/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/grey/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/grey/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/grey/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/grey/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/grey/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/lightgrey - name = "lightgrey corner" - color = "#a8b2b6" - -/obj/effect/floor_decal/corner/lightgrey/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/lightgrey/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/lightgrey/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/lightgrey/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/lightgrey/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/lightgrey/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/lightgrey/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/lightgrey/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/lightgrey/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/lightgrey/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/b_green - name = "bottle green corner" - color = COLOR_PALE_BTL_GREEN - -/obj/effect/floor_decal/corner/b_green/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/b_green/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/b_green/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/b_green/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/b_green/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/b_green/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/b_green/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/b_green/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/b_green/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/b_green/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/corner/research - name = "research corner" - color = COLOR_RESEARCH - -/obj/effect/floor_decal/corner/research/diagonal - icon_state = "corner_white_diagonal" - -/obj/effect/floor_decal/corner/research/three_quarters - icon_state = "corner_white_three_quarters" - -/obj/effect/floor_decal/corner/research/full - icon_state = "corner_white_full" - -/obj/effect/floor_decal/corner/research/border - icon_state = "bordercolor" - -/obj/effect/floor_decal/corner/research/half - icon_state = "bordercolorhalf" - -/obj/effect/floor_decal/corner/research/mono - icon_state = "bordercolormonofull" - -/obj/effect/floor_decal/corner/research/bordercorner - icon_state = "bordercolorcorner" - -/obj/effect/floor_decal/corner/research/bordercorner2 - icon_state = "bordercolorcorner2" - -/obj/effect/floor_decal/corner/research/borderfull - icon_state = "bordercolorfull" - -/obj/effect/floor_decal/corner/research/bordercee - icon_state = "bordercolorcee" - -/obj/effect/floor_decal/spline/plain - name = "spline - plain" - icon_state = "spline_plain" - alpha = 229 - -/obj/effect/floor_decal/spline/plain/black - color = "#333333" - -/obj/effect/floor_decal/spline/plain/blue - color = COLOR_BLUE_GRAY - -/obj/effect/floor_decal/spline/plain/paleblue - color = COLOR_PALE_BLUE_GRAY - -/obj/effect/floor_decal/spline/plain/green - color = COLOR_GREEN_GRAY - -/obj/effect/floor_decal/spline/plain/lime - color = COLOR_PALE_GREEN_GRAY - -/obj/effect/floor_decal/spline/plain/yellow - color = COLOR_BROWN - -/obj/effect/floor_decal/spline/plain/beige - color = COLOR_BEIGE - -/obj/effect/floor_decal/spline/plain/red - color = COLOR_RED_GRAY - -/obj/effect/floor_decal/spline/plain/pink - color = COLOR_PALE_RED_GRAY - -/obj/effect/floor_decal/spline/plain/purple - color = COLOR_PURPLE_GRAY - -/obj/effect/floor_decal/spline/plain/mauve - color = COLOR_PALE_PURPLE_GRAY - -/obj/effect/floor_decal/spline/plain/orange - color = COLOR_DARK_ORANGE - -/obj/effect/floor_decal/spline/plain/brown - color = COLOR_DARK_BROWN - -/obj/effect/floor_decal/spline/plain/white - color = COLOR_WHITE - -/obj/effect/floor_decal/spline/plain/grey - color = "#8d8c8c" - -/obj/effect/floor_decal/spline/fancy - name = "spline - fancy" - icon_state = "spline_fancy" - -/obj/effect/floor_decal/spline/fancy/black - color = COLOR_GRAY - -/obj/effect/floor_decal/spline/fancy/black/corner - icon_state = "spline_fancy_corner" - -/obj/effect/floor_decal/spline/fancy/wood - name = "spline - wood" - color = "#cb9e04" - -/obj/effect/floor_decal/spline/fancy/wood/corner - icon_state = "spline_fancy_corner" - -/obj/effect/floor_decal/spline/fancy/wood/cee - icon_state = "spline_fancy_cee" - -/obj/effect/floor_decal/spline/fancy/wood/three_quarters - icon_state = "spline_fancy_full" - -/obj/effect/floor_decal/industrial/warning - name = "hazard stripes" - color = "#d2d53d" - icon_state = "stripe" - -/obj/effect/floor_decal/industrial/warning/corner - icon_state = "stripecorner" - -/obj/effect/floor_decal/industrial/warning/full - icon_state = "stripefull" - - -/obj/effect/floor_decal/industrial/warning/cee - icon_state = "stripecee" - -/obj/effect/floor_decal/industrial/warning/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/custodial - name = "custodial stripes" - icon_state = "stripe" - -/obj/effect/floor_decal/industrial/custodial/corner - icon_state = "stripecorner" - -/obj/effect/floor_decal/industrial/custodial/full - icon_state = "stripefull" - -/obj/effect/floor_decal/industrial/custodial/cee - icon_state = "stripecee" - -/obj/effect/floor_decal/industrial/custodial/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/fire - name = "fire safety stripes" - icon_state = "stripe" - detail_overlay = "overstripe" - detail_color = "#c90000" - -/obj/effect/floor_decal/industrial/fire/corner - icon_state = "stripecorner" - detail_overlay = "overstripecorner" - -/obj/effect/floor_decal/industrial/fire/full - icon_state = "stripefull" - detail_overlay = "overstripefull" - -/obj/effect/floor_decal/industrial/fire/cee - icon_state = "stripecee" - detail_overlay = "overstripecee" - -/obj/effect/floor_decal/industrial/fire/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/radiation - name = "radiation hazard stripes" - icon_state = "stripe" - color = "#d2d53d" - detail_overlay = "overstripe" - detail_color = "#c900fb" - -/obj/effect/floor_decal/industrial/radiation/corner - icon_state = "stripecorner" - detail_overlay = "overstripecorner" - -/obj/effect/floor_decal/industrial/radiation/full - icon_state = "stripefull" - detail_overlay = "overstripefull" - -/obj/effect/floor_decal/industrial/radiation/cee - icon_state = "stripecee" - detail_overlay = "overstripecee" - -/obj/effect/floor_decal/industrial/radiation/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/firstaid - name = "first aid stripes" - icon_state = "stripe" - detail_overlay = "overstripe" - detail_color = "#00cd00" - -/obj/effect/floor_decal/industrial/firstaid/corner - icon_state = "stripecorner" - detail_overlay = "overstripecorner" - -/obj/effect/floor_decal/industrial/firstaid/full - icon_state = "stripefull" - detail_overlay = "overstripefull" - -/obj/effect/floor_decal/industrial/firstaid/cee - icon_state = "stripecee" - detail_overlay = "overstripecee" - -/obj/effect/floor_decal/industrial/firstaid/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/defective - name = "defective machinery stripes" - icon_state = "stripe" - detail_overlay = "overstripe" - detail_color = "#0000fb" - -/obj/effect/floor_decal/industrial/defective/corner - icon_state = "stripecorner" - detail_overlay = "overstripecorner" - -/obj/effect/floor_decal/industrial/defective/full - icon_state = "stripefull" - detail_overlay = "overstripefull" - -/obj/effect/floor_decal/industrial/defective/cee - icon_state = "stripecee" - detail_overlay = "overstripecee" - -/obj/effect/floor_decal/industrial/defective/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/traffic - name = "traffic hazard stripes" - icon_state = "stripe" - detail_overlay = "overstripe" - detail_color = "#fb9700" - -/obj/effect/floor_decal/industrial/traffic/corner - icon_state = "stripecorner" - detail_overlay = "overstripecorner" - -/obj/effect/floor_decal/industrial/traffic/full - icon_state = "stripefull" - detail_overlay = "overstripefull" - -/obj/effect/floor_decal/industrial/traffic/cee - icon_state = "stripecee" - detail_overlay = "overstripecee" - -/obj/effect/floor_decal/industrial/traffic/fulltile - icon_state = "stripefulltile" - -/obj/effect/floor_decal/industrial/warning/dust - name = "hazard stripes" - icon_state = "warning_dust" - -/obj/effect/floor_decal/industrial/warning/dust/corner - name = "hazard stripes" - icon_state = "warningcorner_dust" - -/obj/effect/floor_decal/industrial/hatch - name = "hatched marking" - icon_state = "delivery" - alpha = 229 - -/obj/effect/floor_decal/industrial/hatch/yellow - color = "#cfcf55" - -/obj/effect/floor_decal/industrial/hatch/red - color = COLOR_RED_GRAY - -/obj/effect/floor_decal/industrial/hatch/orange - color = COLOR_DARK_ORANGE - -/obj/effect/floor_decal/industrial/hatch/blue - color = COLOR_BLUE_GRAY - -/obj/effect/floor_decal/industrial/shutoff - name = "shutoff valve marker" - icon_state = "shutoff" - -/obj/effect/floor_decal/industrial/outline - name = "white outline" - icon_state = "outline" - alpha = 229 - -/obj/effect/floor_decal/industrial/outline/blue - name = "blue outline" - color = "#00b8b2" - -/obj/effect/floor_decal/industrial/outline/yellow - name = "yellow outline" - color = "#cfcf55" - -/obj/effect/floor_decal/industrial/outline/grey - name = "grey outline" - color = "#808080" - -/obj/effect/floor_decal/industrial/outline/red - name = "red outline" - color = COLOR_RED_GRAY - -/obj/effect/floor_decal/industrial/outline/orange - name = "orange outline" - color = COLOR_DARK_ORANGE - -/obj/effect/floor_decal/industrial/loading - name = "loading area" - icon_state = "loadingarea" - alpha = 229 - -/obj/effect/floor_decal/plaque - name = "plaque" - icon_state = "plaque" - -/obj/effect/floor_decal/asteroid - name = "random asteroid rubble" - icon_state = "asteroid0" - -/obj/effect/floor_decal/beach - name = "sandy border" - icon = 'icons/misc/beach.dmi' - icon_state = "beachborder" - -/obj/effect/floor_decal/beach/corner - icon_state = "beachbordercorner" - -/obj/effect/floor_decal/asteroid/Initialize() - . = ..() - icon_state = "asteroid[rand(0,9)]" - -/obj/effect/floor_decal/chapel - name = "chapel" - icon_state = "chapel" - -/obj/effect/floor_decal/ss13/l1 - name = "L1" - icon_state = "L1" - -/obj/effect/floor_decal/ss13/l2 - name = "L2" - icon_state = "L2" - -/obj/effect/floor_decal/ss13/l3 - name = "L3" - icon_state = "L3" - -/obj/effect/floor_decal/ss13/l4 - name = "L4" - icon_state = "L4" - -/obj/effect/floor_decal/ss13/l5 - name = "L5" - icon_state = "L5" - -/obj/effect/floor_decal/ss13/l6 - name = "L6" - icon_state = "L6" - -/obj/effect/floor_decal/ss13/l7 - name = "L7" - icon_state = "L7" - -/obj/effect/floor_decal/ss13/l8 - name = "L8" - icon_state = "L8" - -/obj/effect/floor_decal/ss13/l9 - name = "L9" - icon_state = "L9" - -/obj/effect/floor_decal/ss13/l10 - name = "L10" - icon_state = "L10" - -/obj/effect/floor_decal/ss13/l11 - name = "L11" - icon_state = "L11" - -/obj/effect/floor_decal/ss13/l12 - name = "L12" - icon_state = "L12" - -/obj/effect/floor_decal/ss13/l13 - name = "L13" - icon_state = "L13" - -/obj/effect/floor_decal/ss13/l14 - name = "L14" - icon_state = "L14" - -/obj/effect/floor_decal/ss13/l15 - name = "L15" - icon_state = "L15" - -/obj/effect/floor_decal/ss13/l16 - name = "L16" - icon_state = "L16" - -/obj/effect/floor_decal/sign - name = "floor sign" - icon_state = "white_1" - -/obj/effect/floor_decal/sign/two - icon_state = "white_2" - -/obj/effect/floor_decal/sign/a - icon_state = "white_a" - -/obj/effect/floor_decal/sign/b - icon_state = "white_b" - -/obj/effect/floor_decal/sign/c - icon_state = "white_c" - -/obj/effect/floor_decal/sign/d - icon_state = "white_d" - -/obj/effect/floor_decal/sign/ex - icon_state = "white_ex" - -/obj/effect/floor_decal/sign/m - icon_state = "white_m" - -/obj/effect/floor_decal/sign/cmo - icon_state = "white_cmo" - -/obj/effect/floor_decal/sign/v - icon_state = "white_v" - -/obj/effect/floor_decal/sign/p - icon_state = "white_p" - -/obj/effect/floor_decal/solarpanel - icon_state = "solarpanel" - -/obj/effect/floor_decal/snow - icon = 'icons/turf/overlays.dmi' - icon_state = "snowfloor" - -/obj/effect/floor_decal/floordetail - layer = TURF_DETAIL_LAYER - color = COLOR_GUNMETAL - icon_state = "manydot" - appearance_flags = 0 - -/obj/effect/floor_decal/floordetail/Initialize() - color = null //color is here just for map preview, if left it applies both our and tile colors. - . = ..() - -/obj/effect/floor_decal/floordetail/tiled - icon_state = "manydot_tiled" - -/obj/effect/floor_decal/floordetail/pryhole - icon_state = "pryhole" - -/obj/effect/floor_decal/floordetail/edgedrain - icon_state = "edge" - -/obj/effect/floor_decal/floordetail/traction - icon_state = "traction" - -/obj/effect/floor_decal/ntlogo - icon_state = "ntlogo" - -/obj/effect/floor_decal/exologo - alpha = 230 - icon = 'icons/turf/flooring/corp_floor.dmi' - icon_state = "bottomleft" - -//Techfloor - -/obj/effect/floor_decal/corner_techfloor_gray - name = "corner techfloorgray" - icon_state = "corner_techfloor_gray" - -/obj/effect/floor_decal/corner_techfloor_gray/diagonal - name = "corner techfloorgray diagonal" - icon_state = "corner_techfloor_gray_diagonal" - -/obj/effect/floor_decal/corner_techfloor_gray/full - name = "corner techfloorgray full" - icon_state = "corner_techfloor_gray_full" - -/obj/effect/floor_decal/corner_techfloor_grid - name = "corner techfloorgrid" - icon_state = "corner_techfloor_grid" - -/obj/effect/floor_decal/corner_techfloor_grid/diagonal - name = "corner techfloorgrid diagonal" - icon_state = "corner_techfloor_grid_diagonal" - -/obj/effect/floor_decal/corner_techfloor_grid/full - name = "corner techfloorgrid full" - icon_state = "corner_techfloor_grid_full" - -/obj/effect/floor_decal/corner_steel_grid - name = "corner steel_grid" - icon_state = "steel_grid" - -/obj/effect/floor_decal/corner_steel_grid/diagonal - name = "corner tsteel_grid diagonal" - icon_state = "steel_grid_diagonal" - -/obj/effect/floor_decal/corner_steel_grid/full - name = "corner steel_grid full" - icon_state = "steel_grid_full" - -/obj/effect/floor_decal/borderfloor - name = "border floor" - icon_state = "borderfloor_white" - color = COLOR_GUNMETAL - -/obj/effect/floor_decal/borderfloor/corner - icon_state = "borderfloorcorner_white" - -/obj/effect/floor_decal/borderfloor/corner2 - icon_state = "borderfloorcorner2_white" - -/obj/effect/floor_decal/borderfloor/full - icon_state = "borderfloorfull_white" - -/obj/effect/floor_decal/borderfloor/cee - icon_state = "borderfloorcee_white" - -/obj/effect/floor_decal/borderfloorblack - name = "border floor" - icon_state = "borderfloor_white" - color = COLOR_DARK_GRAY - -/obj/effect/floor_decal/borderfloorblack/corner - icon_state = "borderfloorcorner_white" - -/obj/effect/floor_decal/borderfloorblack/corner2 - icon_state = "borderfloorcorner2_white" - -/obj/effect/floor_decal/borderfloorblack/full - icon_state = "borderfloorfull_white" - -/obj/effect/floor_decal/borderfloorblack/cee - icon_state = "borderfloorcee_white" - -/obj/effect/floor_decal/borderfloorwhite - name = "border floor" - icon_state = "borderfloor_white" - -/obj/effect/floor_decal/borderfloorwhite/corner - icon_state = "borderfloorcorner_white" - -/obj/effect/floor_decal/borderfloorwhite/corner2 - icon_state = "borderfloorcorner2_white" - -/obj/effect/floor_decal/borderfloorwhite/full - icon_state = "borderfloorfull_white" - -/obj/effect/floor_decal/borderfloorwhite/cee - icon_state = "borderfloorcee_white" - -/obj/effect/floor_decal/steeldecal - name = "steel decal" - icon_state = "steel_decals1" - color = COLOR_GUNMETAL - -/obj/effect/floor_decal/steeldecal/steel_decals1 - icon_state = "steel_decals1" - -/obj/effect/floor_decal/steeldecal/steel_decals2 - icon_state = "steel_decals2" - -/obj/effect/floor_decal/steeldecal/steel_decals3 - icon_state = "steel_decals3" - -/obj/effect/floor_decal/steeldecal/steel_decals4 - icon_state = "steel_decals4" - -/obj/effect/floor_decal/steeldecal/steel_decals6 - icon_state = "steel_decals6" - -/obj/effect/floor_decal/steeldecal/steel_decals7 - icon_state = "steel_decals7" - -/obj/effect/floor_decal/steeldecal/steel_decals8 - icon_state = "steel_decals8" - -/obj/effect/floor_decal/steeldecal/steel_decals9 - icon_state = "steel_decals9" - -/obj/effect/floor_decal/steeldecal/steel_decals10 - icon_state = "steel_decals10" - -/obj/effect/floor_decal/steeldecal/steel_decals_central1 - icon_state = "steel_decals_central1" - -/obj/effect/floor_decal/steeldecal/steel_decals_central2 - icon_state = "steel_decals_central2" - -/obj/effect/floor_decal/steeldecal/steel_decals_central3 - icon_state = "steel_decals_central3" - -/obj/effect/floor_decal/steeldecal/steel_decals_central4 - icon_state = "steel_decals_central4" - -/obj/effect/floor_decal/steeldecal/steel_decals_central5 - icon_state = "steel_decals_central5" - -/obj/effect/floor_decal/steeldecal/steel_decals_central6 - icon_state = "steel_decals_central6" - -/obj/effect/floor_decal/steeldecal/steel_decals_central7 - icon_state = "steel_decals_central7" - -/obj/effect/floor_decal/techfloor - name = "techfloor edges" - icon_state = "techfloor_edges" - -/obj/effect/floor_decal/techfloor/corner - name = "techfloor corner" - icon_state = "techfloor_corners" - -/obj/effect/floor_decal/techfloor/orange - name = "techfloor edges" - icon_state = "techfloororange_edges" - -/obj/effect/floor_decal/techfloor/orange/corner - name = "techfloor corner" - icon_state = "techfloororange_corners" - -/obj/effect/floor_decal/techfloor/hole - name = "hole left" - icon_state = "techfloor_hole_left" - -/obj/effect/floor_decal/techfloor/hole/right - name = "hole right" - icon_state = "techfloor_hole_right" - -/obj/effect/floor_decal/stoneborder - name = "stone border" - icon_state = "stoneborder" - -/obj/effect/floor_decal/stoneborder/corner - icon_state = "stoneborder_c" - -/obj/effect/floor_decal/ivenmoth - icon_state = "ivenmoth" \ No newline at end of file diff --git a/code/game/turfs/flooring/flooring_grass.dm b/code/game/turfs/flooring/flooring_grass.dm new file mode 100644 index 000000000000..f51600fa91dc --- /dev/null +++ b/code/game/turfs/flooring/flooring_grass.dm @@ -0,0 +1,66 @@ +/decl/flooring/grass + name = "grass" + icon = 'icons/turf/flooring/grass.dmi' + icon_base = "grass" + desc = "A patch of thriving meadowgrass." + has_base_range = 3 + footstep_type = /decl/footsteps/grass + icon_edge_layer = FLOOR_EDGE_GRASS + color = null // color from material + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + can_engrave = FALSE + damage_temperature = T0C+80 + flooring_flags = TURF_REMOVE_SHOVEL + force_material = /decl/material/solid/organic/plantmatter/grass + growth_value = 1.2 // Shouldn't really matter since you can't plant on grass, it turns to dirt first. + uid = "floor_grass" + can_conceal_hazards = TRUE + + var/harvestable = FALSE + +/decl/flooring/grass/fire_act(turf/floor/target, datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(target.get_topmost_flooring() == src && (exposed_temperature > T0C + 200 && prob(5)) || exposed_temperature > T0C + 1000) + target.remove_flooring(target.get_topmost_flooring()) + return TRUE + return ..() + +/decl/flooring/grass/handle_turf_digging(turf/floor/target) + target.remove_flooring(target.get_topmost_flooring()) + return FALSE + +/decl/flooring/grass/wild + name = "wild grass" + icon = 'icons/turf/flooring/wildgrass.dmi' + icon_base = "wildgrass" + desc = "A lush, overgrown patch of wild meadowgrass. Watch out for snakes." + has_base_range = null + icon_edge_layer = FLOOR_EDGE_GRASS_WILD + harvestable = TRUE + uid = "floor_grass_wild" + +/decl/flooring/grass/wild/get_movable_alpha_mask_state(atom/movable/mover) + . = ..() || "mask_grass" + +/decl/flooring/grass/wild/handle_item_interaction(turf/floor/floor, mob/user, obj/item/item) + var/decl/material/floor_material = floor.get_material() + if(IS_KNIFE(item) && harvestable && istype(floor_material) && floor_material.dug_drop_type) + if(item.do_tool_interaction(TOOL_KNIFE, user, floor, 3 SECONDS, start_message = "harvesting", success_message = "harvesting") && !QDELETED(floor) && floor.get_topmost_flooring() == src) + new floor_material.dug_drop_type(floor, rand(2,5)) + floor.remove_flooring(src) + return TRUE + return ..() + +/decl/flooring/grass/get_vehicle_transit_delay(obj/vehicle/vehicle) + return 1 + +/decl/flooring/grass/fake + desc = "Do they smoke grass out in space, Bowie? Or do they smoke AstroTurf?" + icon = 'icons/turf/flooring/fakegrass.dmi' + has_base_range = 3 + color = "#5e7a3b" + build_type = /obj/item/stack/tile/grass + force_material = /decl/material/solid/organic/plastic + uid = "floor_grass_fake" + +/decl/flooring/grass/fake/get_vehicle_transit_delay(obj/vehicle/vehicle) + return vehicle::base_speed diff --git a/code/game/turfs/flooring/flooring_holowater.dm b/code/game/turfs/flooring/flooring_holowater.dm new file mode 100644 index 000000000000..6bfe235d67e1 --- /dev/null +++ b/code/game/turfs/flooring/flooring_holowater.dm @@ -0,0 +1,11 @@ +/decl/flooring/fake_water + name = "holowater" + desc = "The ripples are a fraction of a second out of sync with each other." + color = COLOR_LIQUID_WATER + icon = 'icons/turf/flooring/fake_water.dmi' + icon_base = "fakewater" + has_base_range = null + footstep_type = /decl/footsteps/water + holographic = TRUE + constructed = TRUE + uid = "floor_water_fake" diff --git a/code/game/turfs/flooring/flooring_lava.dm b/code/game/turfs/flooring/flooring_lava.dm new file mode 100644 index 000000000000..adf4f4b4f1af --- /dev/null +++ b/code/game/turfs/flooring/flooring_lava.dm @@ -0,0 +1,29 @@ + +/decl/flooring/lava + name = "lava" + icon_base = "lava" + icon = 'icons/turf/flooring/lava.dmi' + desc = "A pool of incredibly hot molten rock. You can feel the heat radiating even from a distance. Watch your step." + movement_delay = 4 + footstep_type = /decl/footsteps/lava + has_environment_proc = TRUE + turf_light_color = LIGHT_COLOR_LAVA + turf_light_range = 2 + turf_light_power = 0.7 + uid = "floor_lava" + +/decl/flooring/lava/handle_environment_proc(turf/floor/target) + . = PROCESS_KILL + if(target.get_supporting_platform()) + return + var/datum/gas_mixture/environment = target.return_air() + var/pressure = environment?.return_pressure() + for(var/atom/movable/AM as anything in target.get_contained_external_atoms()) + if(!AM.is_burnable() || AM.immune_to_floor_hazards()) + continue + . = null + if(isliving(AM)) + var/mob/living/L = AM + if(L.can_overcome_gravity()) + continue + AM.lava_act(environment, 5000 + environment.temperature, pressure) diff --git a/code/game/turfs/flooring/flooring_misc.dm b/code/game/turfs/flooring/flooring_misc.dm new file mode 100644 index 000000000000..893b2e72dee4 --- /dev/null +++ b/code/game/turfs/flooring/flooring_misc.dm @@ -0,0 +1,95 @@ +/decl/flooring/linoleum + name = "linoleum" + desc = "A stretch of inlaid sections of flexible linoleum." + icon = 'icons/turf/flooring/linoleum.dmi' + icon_base = "lino" + can_paint = TRUE + build_type = /obj/item/stack/tile/linoleum + flooring_flags = TURF_REMOVE_SCREWDRIVER + footstep_type = /decl/footsteps/tiles + force_material = /decl/material/solid/organic/plastic + constructed = TRUE + uid = "floor_lino" + +/decl/flooring/crystal + name = "crystal flooring" + desc = "A hard, reflective section of flooring made from crystal." + icon = 'icons/turf/flooring/crystal.dmi' + icon_base = "crystal" + build_type = null + flooring_flags = TURF_ACID_IMMUNE | TURF_REMOVE_CROWBAR + color = "#00ffe1" + force_material = /decl/material/solid/gemstone/crystal + constructed = TRUE + uid = "floor_crystal" + +/decl/flooring/glass + name = "glass flooring" + desc = "A window to the world outside. Or the world beneath your feet, rather." + icon = 'icons/turf/flooring/glass.dmi' + icon_base = "glass" + build_type = /obj/item/stack/material/pane + build_material = /decl/material/solid/glass + build_cost = 1 + build_time = 30 + damage_temperature = T100C + flooring_flags = TURF_REMOVE_CROWBAR | TURF_ACID_IMMUNE + can_engrave = FALSE + color = GLASS_COLOR + z_flags = ZM_MIMIC_DEFAULTS + force_material = /decl/material/solid/glass + constructed = TRUE + uid = "floor_glass" + +/decl/flooring/glass/boro + name = "borosilicate glass flooring" + build_material = /decl/material/solid/glass/borosilicate + color = GLASS_COLOR_SILICATE + damage_temperature = T0C + 4000 + force_material = /decl/material/solid/glass/borosilicate + uid = "floor_glass_boro" + +/decl/flooring/pool + name = "pool floor" + desc = "Sunken flooring designed to hold liquids." + icon = 'icons/turf/flooring/pool.dmi' + icon_base = "pool" + build_type = /obj/item/stack/tile/pool + flooring_flags = TURF_REMOVE_CROWBAR + footstep_type = /decl/footsteps/tiles + render_trenches = FALSE + force_material = /decl/material/solid/stone/ceramic + constructed = TRUE + gender = NEUTER + uid = "floor_pool" + +/decl/flooring/woven + name = "woven floor" + desc = "A rustic woven mat." + icon = 'icons/turf/flooring/woven.dmi' + icon_base = "woven" + damage_temperature = T0C+80 + flooring_flags = TURF_REMOVE_CROWBAR + build_type = /obj/item/stack/tile/woven + can_engrave = FALSE + color = COLOR_BEIGE + force_material = /decl/material/solid/organic/plantmatter/grass/dry + constructed = TRUE + gender = NEUTER + uid = "floor_woven" + +/decl/flooring/straw + name = "straw floor" + desc = "A thick layer of straw, suitable for livestock." + icon = 'icons/turf/flooring/straw.dmi' + icon_base = "straw" + has_base_range = null + icon_edge_layer = FLOOR_EDGE_GRASS_WILD + damage_temperature = T0C+80 + flooring_flags = TURF_REMOVE_CROWBAR + can_engrave = FALSE + color = COLOR_WHEAT + force_material = /decl/material/solid/organic/plantmatter/grass/dry + constructed = TRUE + gender = NEUTER + uid = "floor_straw" diff --git a/code/game/turfs/flooring/flooring_mud.dm b/code/game/turfs/flooring/flooring_mud.dm new file mode 100644 index 000000000000..e7f26e889bec --- /dev/null +++ b/code/game/turfs/flooring/flooring_mud.dm @@ -0,0 +1,91 @@ +/decl/flooring/mud + name = "mud" + desc = "A stretch of thick, waterlogged mud." + icon = 'icons/turf/flooring/mud.dmi' + icon_base = "mud" + color = null // autoset from material + icon_edge_layer = FLOOR_EDGE_MUD + has_corners = FALSE + footstep_type = /decl/footsteps/mud + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + force_material = /decl/material/solid/soil + growth_value = 1.1 + can_collect = TRUE + print_type = /obj/effect/footprints + uid = "floor_mud" + +/decl/flooring/mud/fire_act(turf/floor/target, datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(!REAGENT_TOTAL_VOLUME(target.reagents)) + if(target.get_topmost_flooring() == src) + target.set_flooring(/decl/flooring/dry_mud) + else if(target.get_base_flooring() == src) + target.set_base_flooring(/decl/flooring/dry_mud) + return + return ..() + +/decl/flooring/mud/turf_crossed(atom/movable/crosser) + if(!isliving(crosser)) + return + var/mob/living/walker = crosser + walker.add_walking_contaminant(force_material.type, rand(2,3)) + +/decl/flooring/mud/can_show_coating_footprints(turf/target, decl/material/contaminant) + if(force_material == contaminant) // So we don't end up covered in a million footsteps that we provided. + return FALSE + return ..() + +/decl/flooring/mud/get_vehicle_transit_delay(obj/vehicle/vehicle) + return vehicle.vehicle_transit_type == vehicle::VEHICLE_SNOWMOBILE ? 1.4 : 1.5 + +/decl/flooring/dry_mud + name = "dry mud" + desc = "This was once mud, but forgot to keep hydrated." + icon = 'icons/turf/flooring/seafloor.dmi' + icon_base = "seafloor" + icon_edge_layer = FLOOR_EDGE_MUD + has_corners = FALSE + footstep_type = /decl/footsteps/mud + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + color = "#ae9e66" + dirt_color = "#ae9e66" + force_material = /decl/material/solid/soil + uid = "floor_dry_mud" + +/decl/flooring/dry_mud/get_vehicle_transit_delay(obj/vehicle/vehicle) + return 1 + +/decl/flooring/dry_mud/fluid_act(turf/floor/target, datum/reagents/fluids) + if(target.get_topmost_flooring() == src) + target.set_flooring(/decl/flooring/mud) + . = TRUE + if(target.get_base_flooring() == src) + target.set_base_flooring(/decl/flooring/mud) + . = TRUE + return . || ..() + +/decl/flooring/dirt + name = "dirt" + desc = "A flat expanse of dry, cracked earth." + icon = 'icons/turf/flooring/dirt.dmi' + icon_base = "dirt" + icon_edge_layer = FLOOR_EDGE_DIRT + has_corners = FALSE + color = null // autoset from material + footstep_type = /decl/footsteps/asteroid + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + force_material = /decl/material/solid/soil + growth_value = 1 + uid = "floor_dirt" + can_conceal_hazards = TRUE + +/decl/flooring/dirt/fluid_act(turf/floor/target, datum/reagents/fluids) + if(target.get_topmost_flooring() == src) + target.set_flooring(/decl/flooring/mud) + . = TRUE + if(target.get_base_flooring() == src) + target.set_base_flooring(/decl/flooring/mud) + . = TRUE + return . || ..() + +/decl/flooring/dirt/get_vehicle_transit_delay(obj/vehicle/vehicle) + return 1 diff --git a/code/game/turfs/flooring/flooring_natural.dm b/code/game/turfs/flooring/flooring_natural.dm new file mode 100644 index 000000000000..932289909a91 --- /dev/null +++ b/code/game/turfs/flooring/flooring_natural.dm @@ -0,0 +1,84 @@ +/decl/flooring/seafloor + name = "sea floor" + desc = "A thick layer of silt and debris from above." + icon = 'icons/turf/flooring/seafloor.dmi' + icon_base = "seafloor" + icon_edge_layer = FLOOR_EDGE_SEAFLOOR + has_corners = FALSE + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + force_material = /decl/material/solid/sand + gender = NEUTER + footstep_type = /decl/footsteps/sand + uid = "floor_seafloor" + +/decl/flooring/shrouded + name = "packed sand" + desc = "Packed-down sand forming a solid layer." + icon = 'icons/turf/flooring/shrouded.dmi' // Note: this icon is not greyscaled + icon_base = "shrouded" + dirt_color = "#3e3960" // Does this mean we're double-applying the colour? Or is that just an issue with the 'color' variable? + has_base_range = 8 + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + force_material = /decl/material/solid/sand + footstep_type = /decl/footsteps/asteroid + uid = "floor_shrouded" + +/decl/flooring/meat + name = "fleshy ground" + desc = "It's disgustingly soft to the touch. And warm. Too warm." + icon = 'icons/turf/flooring/flesh.dmi' + icon_base = "meat" + color = "#c40031" + has_base_range = null + footstep_type = /decl/footsteps/mud + force_material = /decl/material/solid/organic/meat + print_type = /obj/effect/footprints + uid = "floor_meat" + +/decl/flooring/barren + name = "ground" + desc = "A stretch of bare, barren sand." + icon = 'icons/turf/flooring/barren.dmi' + icon_base = "barren" + color = COLOR_WHITE + footstep_type = /decl/footsteps/asteroid + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH + icon_edge_layer = FLOOR_EDGE_BARREN + has_corners = FALSE + force_material = /decl/material/solid/sand + growth_value = 0.1 + uid = "floor_barren" + +/decl/flooring/clay + name = "clay" + desc = "A stretch of thick, claggy clay." + icon = 'icons/turf/flooring/clay.dmi' + icon_base = "clay" + icon_edge_layer = FLOOR_EDGE_CLAY + has_corners = FALSE + footstep_type = /decl/footsteps/mud + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + force_material = /decl/material/solid/clay + growth_value = 1.2 + can_collect = TRUE + print_type = /obj/effect/footprints + uid = "floor_clay" + +/decl/flooring/ice + name = "ice" + desc = "A hard, slippery layer of frozen water." + icon = 'icons/turf/flooring/ice.dmi' + icon_base = "ice" + color = COLOR_LIQUID_WATER + force_material = /decl/material/solid/ice + uid = "floor_ice" + +/decl/flooring/ice/get_vehicle_transit_delay(obj/vehicle/vehicle) + return vehicle.vehicle_transit_type == vehicle::VEHICLE_SNOWMOBILE ? 0.8 : ..() + +/decl/flooring/ice/update_turf_icon(turf/floor/target) + . = ..() + if(istype(target)) + var/image/I = image(icon, "[icon_base]_shine") + I.appearance_flags |= RESET_COLOR + target.add_overlay(I) diff --git a/code/game/turfs/flooring/flooring_path.dm b/code/game/turfs/flooring/flooring_path.dm new file mode 100644 index 000000000000..8632af3b386c --- /dev/null +++ b/code/game/turfs/flooring/flooring_path.dm @@ -0,0 +1,49 @@ +/decl/flooring/path + abstract_type = /decl/flooring/path + icon = 'icons/turf/flooring/path.dmi' + flooring_flags = TURF_REMOVE_CROWBAR + build_type = null + can_engrave = TRUE + neighbour_type = /decl/flooring/path + color = null + constructed = TRUE + uid = "floor_path" + + // If null, this is just skipped. + var/paving_adjective = "cobbled" + var/paver_adjective = "loose" + // This one should never be null. + var/paver_noun = "stones" + +/decl/flooring/path/update_turf_strings(turf/floor/target) + var/decl/material/floor_material = RESOLVE_TO_DECL(target?.get_material()) + ASSERT(floor_material?.adjective_name) + ASSERT(paver_noun) + target.SetName("[floor_material.adjective_name] [name]") + target.desc = "[jointext_no_nulls(list("A", paving_adjective, "path made of", paver_adjective, floor_material.adjective_name, paver_noun), " ")]." + +/decl/flooring/path/cobblestone + name = "cobblestones" + desc = "A rustic cobblestone path." + icon_base = "cobble" + icon_edge_layer = FLOOR_EDGE_PATH + has_corners = FALSE + flooring_flags = TURF_REMOVE_CROWBAR + has_base_range = 1 + uid = "floor_path_cobble" + +/decl/flooring/path/running_bond + name = "stone path" + desc = "A rustic stone path, laid out in a running bond pattern." + icon_base = "runningbond" + has_base_range = 3 + gender = NEUTER + uid = "floor_path_bond" + +/decl/flooring/path/herringbone + name = "stone path" + desc = "A rustic stone path, laid out in a herringbone pattern." + icon_base = "herringbone" + has_base_range = null + gender = NEUTER + uid = "floor_path_herring" diff --git a/code/game/turfs/flooring/flooring_plating.dm b/code/game/turfs/flooring/flooring_plating.dm new file mode 100644 index 000000000000..2b51940d1336 --- /dev/null +++ b/code/game/turfs/flooring/flooring_plating.dm @@ -0,0 +1,20 @@ +/decl/flooring/plating + name = "plating" + desc = "A layer of rough, undecorated steel plates." + icon = 'icons/turf/flooring/plating.dmi' + icon_base = "plating" + floor_layer = PLATING_LAYER + force_material = /decl/material/solid/metal/steel + constructed = TRUE + burned_states = list( + "burned0", + "burned1" + ) + broken_states = list( + "broken0", + "broken1", + "broken2", + "broken3", + "broken4" + ) + uid = "floor_plating" diff --git a/code/game/turfs/flooring/flooring_premade.dm b/code/game/turfs/flooring/flooring_premade.dm deleted file mode 100644 index cd7297d792d1..000000000000 --- a/code/game/turfs/flooring/flooring_premade.dm +++ /dev/null @@ -1,370 +0,0 @@ -// simulated/floor is currently plating by default, but there really should be an explicit plating type. -/turf/simulated/floor/plating - name = "plating" - icon = 'icons/turf/flooring/plating.dmi' - icon_state = "plating" - layer = PLATING_LAYER - -/turf/simulated/floor/bluegrid - name = "mainframe floor" - icon = 'icons/turf/flooring/circuit.dmi' - icon_state = "bcircuit" - initial_flooring = /decl/flooring/reinforced/circuit - light_outer_range = 2 - light_max_bright = 1 - light_color = COLOR_BLUE - -/turf/simulated/floor/bluegrid/airless - initial_gas = null - -/turf/simulated/floor/greengrid - name = "mainframe floor" - icon = 'icons/turf/flooring/circuit.dmi' - icon_state = "gcircuit" - initial_flooring = /decl/flooring/reinforced/circuit/green - light_outer_range = 2 - light_max_bright = 1 - light_color = COLOR_GREEN - -/turf/simulated/floor/blackgrid - name = "mainframe floor" - icon = 'icons/turf/flooring/circuit.dmi' - icon_state = "rcircuit" - initial_flooring = /decl/flooring/reinforced/circuit/red - light_outer_range = 2 - light_max_bright = 1 - light_color = COLOR_RED - -/turf/simulated/floor/greengrid/airless - initial_gas = null - -/turf/simulated/floor/wood - name = "wooden floor" - icon = 'icons/turf/flooring/wood.dmi' - icon_state = "wood" - color = WOOD_COLOR_GENERIC - initial_flooring = /decl/flooring/wood - -/turf/simulated/floor/wood/mahogany - color = WOOD_COLOR_RICH - initial_flooring = /decl/flooring/wood/mahogany - -/turf/simulated/floor/wood/maple - color = WOOD_COLOR_PALE - initial_flooring = /decl/flooring/wood/maple - -/turf/simulated/floor/wood/ebony - color = WOOD_COLOR_BLACK - initial_flooring = /decl/flooring/wood/ebony - -/turf/simulated/floor/wood/walnut - color = WOOD_COLOR_CHOCOLATE - initial_flooring = /decl/flooring/wood/walnut - -/turf/simulated/floor/wood/bamboo - color = WOOD_COLOR_PALE2 - initial_flooring = /decl/flooring/wood/bamboo - -/turf/simulated/floor/wood/yew - color = WOOD_COLOR_YELLOW - initial_flooring = /decl/flooring/wood/yew - -/turf/simulated/floor/grass - name = "grass patch" - icon = 'icons/turf/flooring/grass.dmi' - icon_state = "grass0" - initial_flooring = /decl/flooring/grass - -/turf/simulated/floor/carpet - name = "brown carpet" - icon = 'icons/turf/flooring/carpet.dmi' - icon_state = "brown" - initial_flooring = /decl/flooring/carpet - -/turf/simulated/floor/carpet/blue - name = "blue carpet" - icon_state = "blue1" - initial_flooring = /decl/flooring/carpet/blue - -/turf/simulated/floor/carpet/blue2 - name = "pale blue carpet" - icon_state = "blue2" - initial_flooring = /decl/flooring/carpet/blue2 - -/turf/simulated/floor/carpet/blue3 - name = "sea blue carpet" - icon_state = "blue3" - initial_flooring = /decl/flooring/carpet/blue3 - -/turf/simulated/floor/carpet/magenta - name = "magenta carpet" - icon_state = "magenta" - initial_flooring = /decl/flooring/carpet/magenta - -/turf/simulated/floor/carpet/purple - name = "purple carpet" - icon_state = "purple" - initial_flooring = /decl/flooring/carpet/purple - -/turf/simulated/floor/carpet/orange - name = "orange carpet" - icon_state = "orange" - initial_flooring = /decl/flooring/carpet/orange - -/turf/simulated/floor/carpet/green - name = "green carpet" - icon_state = "green" - initial_flooring = /decl/flooring/carpet/green - -/turf/simulated/floor/carpet/red - name = "red carpet" - icon_state = "red" - initial_flooring = /decl/flooring/carpet/red - -/turf/simulated/floor/reinforced - name = "reinforced floor" - icon = 'icons/turf/flooring/tiles.dmi' - icon_state = "reinforced" - initial_flooring = /decl/flooring/reinforced - -/turf/simulated/floor/reinforced/airless - initial_gas = null - -/turf/simulated/floor/reinforced/airmix - initial_gas = list(/decl/material/gas/oxygen = MOLES_O2ATMOS, /decl/material/gas/nitrogen = MOLES_N2ATMOS) - -/turf/simulated/floor/reinforced/nitrogen - initial_gas = list(/decl/material/gas/nitrogen = ATMOSTANK_NITROGEN) - -/turf/simulated/floor/reinforced/hydrogen - initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN) - -/turf/simulated/floor/reinforced/oxygen - initial_gas = list(/decl/material/gas/oxygen = ATMOSTANK_OXYGEN) - -/turf/simulated/floor/reinforced/nitrogen/engine - name = "engine floor" - initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD) - -/turf/simulated/floor/reinforced/hydrogen/fuel - initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN_FUEL) - -/turf/simulated/floor/reinforced/carbon_dioxide - initial_gas = list(/decl/material/gas/carbon_dioxide = ATMOSTANK_CO2) - -/turf/simulated/floor/reinforced/n20 - initial_gas = list(/decl/material/gas/nitrous_oxide = ATMOSTANK_NITROUSOXIDE) - - -/turf/simulated/floor/cult - name = "engraved floor" - icon = 'icons/turf/flooring/cult.dmi' - icon_state = "cult" - initial_flooring = /decl/flooring/reinforced/cult - -/turf/simulated/floor/cult/cultify() - return - -//Tiled floor + sub-types - -/turf/simulated/floor/tiled - name = "steel floor" - icon = 'icons/turf/flooring/tiles.dmi' - icon_state = "steel" - initial_flooring = /decl/flooring/tiling - -/turf/simulated/floor/tiled/dark - name = "dark floor" - icon_state = "dark" - initial_flooring = /decl/flooring/tiling/dark - -/turf/simulated/floor/tiled/dark/monotile - name = "floor" - icon_state = "monotiledark" - initial_flooring = /decl/flooring/tiling/mono/dark - -/turf/simulated/floor/tiled/dark/airless - initial_gas = null - -/turf/simulated/floor/tiled/white - name = "white floor" - icon_state = "white" - initial_flooring = /decl/flooring/tiling/white - -/turf/simulated/floor/tiled/white/monotile - name = "floor" - icon_state = "monotile" - initial_flooring = /decl/flooring/tiling/mono/white - -/turf/simulated/floor/tiled/monofloor - name = "floor" - icon_state = "steel_monofloor" - initial_flooring = /decl/flooring/tiling/mono - -/turf/simulated/floor/tiled/white/airless - name = "airless floor" - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/tiled/freezer - name = "tiles" - icon_state = "freezer" - initial_flooring = /decl/flooring/tiling/freezer - -/turf/simulated/floor/tiled/techmaint - name = "floor" - icon = 'icons/turf/flooring/tiles.dmi' - icon_state = "techmaint" - initial_flooring = /decl/flooring/tiling/new_tile/techmaint - -/turf/simulated/floor/tiled/monofloor - name = "floor" - icon_state = "monofloor" - initial_flooring = /decl/flooring/tiling/new_tile/monofloor - -/turf/simulated/floor/tiled/techfloor - name = "floor" - icon = 'icons/turf/flooring/techfloor.dmi' - icon_state = "techfloor_gray" - initial_flooring = /decl/flooring/tiling/tech - -/turf/simulated/floor/tiled/monotile - name = "floor" - icon_state = "steel_monotile" - initial_flooring = /decl/flooring/tiling/mono - -/turf/simulated/floor/tiled/steel_grid - name = "floor" - icon_state = "steel_grid" - initial_flooring = /decl/flooring/tiling/new_tile/steel_grid - -/turf/simulated/floor/tiled/steel_ridged - name = "floor" - icon_state = "steel_ridged" - initial_flooring = /decl/flooring/tiling/new_tile/steel_ridged - -/turf/simulated/floor/tiled/old_tile - name = "floor" - icon_state = "tile_full" - initial_flooring = /decl/flooring/tiling/new_tile - -/turf/simulated/floor/tiled/old_cargo - name = "floor" - icon_state = "cargo_one_full" - initial_flooring = /decl/flooring/tiling/new_tile/cargo_one - -/turf/simulated/floor/tiled/kafel_full - name = "floor" - icon_state = "kafel_full" - initial_flooring = /decl/flooring/tiling/new_tile/kafel - -/turf/simulated/floor/tiled/stone - name = "stone slab floor" - icon_state = "stone_full" - initial_flooring = /decl/flooring/tiling/stone - -/turf/simulated/floor/tiled/techfloor/grid - name = "floor" - icon_state = "techfloor_grid" - initial_flooring = /decl/flooring/tiling/tech/grid - -/turf/simulated/floor/lino - name = "lino" - icon = 'icons/turf/flooring/linoleum.dmi' - icon_state = "lino" - initial_flooring = /decl/flooring/linoleum - -//ATMOS PREMADES -/turf/simulated/floor/reinforced/airless - name = "vacuum floor" - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/airless - name = "airless plating" - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/tiled/airless - name = "airless floor" - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/bluegrid/airless - name = "airless floor" - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/greengrid/airless - name = "airless floor" - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/greengrid/nitrogen - initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD) - -// Placeholders -/turf/simulated/floor/airless/lava - name = "lava" - icon = 'icons/turf/flooring/lava.dmi' - icon_state = "lava" - -/turf/simulated/floor/ice - name = "ice" - icon = 'icons/turf/snow.dmi' - icon_state = "ice" - -/turf/simulated/floor/snow - name = "snow" - icon = 'icons/turf/snow.dmi' - icon_state = "snow" - initial_flooring = /decl/flooring/snow - -/turf/simulated/floor/light -/turf/simulated/floor/airless/ceiling - -/turf/simulated/floor/beach - name = "beach" - icon = 'icons/misc/beach.dmi' - -/turf/simulated/floor/beach/sand - name = "sand" - icon_state = "sand" - -/turf/simulated/floor/beach/sand/desert - icon_state = "desert" - has_resources = 1 - -/turf/simulated/floor/beach/sand/desert/Initialize() - . = ..() - icon_state = "desert[rand(0,5)]" - -/turf/simulated/floor/beach/coastline - name = "coastline" - icon = 'icons/misc/beach2.dmi' - icon_state = "sandwater" - turf_flags = TURF_IS_WET - -/turf/simulated/floor/beach/water - name = "water" - icon_state = "water" - turf_flags = TURF_IS_WET - -/turf/simulated/floor/beach/water/is_flooded(lying_mob, absolute) - . = absolute ? ..() : lying_mob - -/turf/simulated/floor/beach/water/update_dirt() - return // Water doesn't become dirty - -/turf/simulated/floor/beach/water/ocean - icon_state = "seadeep" - -/turf/simulated/floor/beach/water/Initialize() - . = ..() - overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water5","layer"=MOB_LAYER+0.1) - -/turf/simulated/floor/crystal - name = "crystal floor" - icon = 'icons/turf/flooring/crystal.dmi' - icon_state = "" - initial_flooring = /decl/flooring/crystal diff --git a/code/game/turfs/flooring/flooring_reinforced.dm b/code/game/turfs/flooring/flooring_reinforced.dm new file mode 100644 index 000000000000..a48566d08613 --- /dev/null +++ b/code/game/turfs/flooring/flooring_reinforced.dm @@ -0,0 +1,93 @@ +/decl/flooring/reinforced + name = "reinforced floor" + desc = "Heavily reinforced with a latticework on top of regular plating." + icon = 'icons/turf/flooring/tiles.dmi' + icon_base = "reinforced" + flooring_flags = TURF_REMOVE_WRENCH | TURF_ACID_IMMUNE + build_type = /obj/item/stack/material/sheet + build_material = /decl/material/solid/metal/steel + build_cost = 1 + build_time = 3 SECONDS + can_paint = TRUE + force_material = /decl/material/solid/metal/steel + constructed = TRUE + gender = NEUTER + burned_states = list( + "burned0", + "burned1" + ) + broken_states = list( + "broken0", + "broken1", + "broken2", + "broken3", + "broken4" + ) + uid = "floor_reinf" + deconstruct_sound = 'sound/items/Deconstruct.ogg' + +/decl/flooring/reinforced/circuit + name = "processing strata" + desc = "A complex network of circuits beneath reinforced glass." + icon = 'icons/turf/flooring/circuit.dmi' + icon_base = "bcircuit" + build_type = null + flooring_flags = TURF_ACID_IMMUNE | TURF_REMOVE_WRENCH + can_paint = TRUE + can_engrave = FALSE + turf_light_range = 2 + turf_light_power = 3 + turf_light_color = COLOR_BLUE + uid = "floor_reinf_circ" + +/decl/flooring/reinforced/circuit/green + icon_base = "gcircuit" + turf_light_color = COLOR_GREEN + uid = "floor_reinf_gcirc" + +/decl/flooring/reinforced/circuit/red + icon_base = "rcircuit" + flooring_flags = TURF_ACID_IMMUNE + can_paint = FALSE + turf_light_power = 2 + turf_light_color = COLOR_RED + uid = "floor_reinf_rcirc" + +/decl/flooring/reinforced/shuttle + name = "floor" + desc = "A stretch of plastic shuttle flooring." + icon = 'icons/turf/flooring/shuttle.dmi' + build_type = null + flooring_flags = TURF_ACID_IMMUNE | TURF_REMOVE_CROWBAR + can_paint = TRUE + can_engrave = FALSE + gender = NEUTER + uid = "floor_reinf_shuttle" + +/decl/flooring/reinforced/shuttle/blue + icon_base = "floor" + uid = "floor_reinf_shuttle_blue" + +/decl/flooring/reinforced/shuttle/yellow + icon_base = "floor2" + uid = "floor_reinf_shuttle_yellow" + +/decl/flooring/reinforced/shuttle/white + icon_base = "floor3" + uid = "floor_reinf_shuttle_white" + +/decl/flooring/reinforced/shuttle/red + icon_base = "floor4" + uid = "floor_reinf_shuttle_red" + +/decl/flooring/reinforced/shuttle/purple + icon_base = "floor5" + uid = "floor_reinf_shuttle_purple" + +/decl/flooring/reinforced/shuttle/darkred + icon_base = "floor6" + uid = "floor_reinf_shuttle_darkred" + +/decl/flooring/reinforced/shuttle/black + icon_base = "floor7" + uid = "floor_reinf_shuttle_black" diff --git a/code/game/turfs/flooring/flooring_rock.dm b/code/game/turfs/flooring/flooring_rock.dm new file mode 100644 index 000000000000..94227641346c --- /dev/null +++ b/code/game/turfs/flooring/flooring_rock.dm @@ -0,0 +1,20 @@ +/decl/flooring/rock + name = "rock floor" + desc = "An expanse of bare rock." + icon = 'icons/turf/flooring/rock.dmi' + icon_base = "rock" + has_base_range = null + color = null + icon_edge_layer = FLOOR_EDGE_VOLCANIC + has_corners = FALSE + gender = NEUTER + uid = "floor_reinf_shuttle_rock" + +/decl/flooring/rock/update_turf_strings(turf/floor/target) + var/decl/material/turf_material = RESOLVE_TO_DECL(target?.get_material()) + ASSERT(turf_material?.adjective_name) + target.SetName("[turf_material.adjective_name] [name]") + target.desc = "An expanse of bare [turf_material.solid_name]." + +/decl/flooring/rock/get_vehicle_transit_delay(obj/vehicle/vehicle) + return vehicle.vehicle_transit_type == vehicle::VEHICLE_SNOWMOBILE ? 1.5 : ..() diff --git a/code/game/turfs/flooring/flooring_sand.dm b/code/game/turfs/flooring/flooring_sand.dm new file mode 100644 index 000000000000..5b4f13501eaa --- /dev/null +++ b/code/game/turfs/flooring/flooring_sand.dm @@ -0,0 +1,66 @@ +/decl/flooring/sand + name = "sand" + desc = "A fine layer of silica. It's coarse and gets everywhere." + footstep_type = /decl/footsteps/sand + icon = 'icons/turf/flooring/sand.dmi' + icon_base = "sand" + icon_edge_layer = FLOOR_EDGE_SAND + has_base_range = 4 + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_PATH | TURF_FLAG_ABSORB_LIQUID + force_material = /decl/material/solid/sand + can_collect = TRUE + print_type = /obj/effect/footprints + uid = "floor_sand" + +/decl/flooring/sand/fire_act(turf/floor/target, datum/gas_mixture/air, exposed_temperature, exposed_volume) + if((exposed_temperature > T0C + 1700 && prob(5)) || exposed_temperature > T0C + 3000) + if(target.get_topmost_flooring() == src) + target.set_flooring(/decl/flooring/melted_sand) + . = TRUE + if(target.get_base_flooring() == src) + target.set_base_flooring(/decl/flooring/melted_sand) + . = TRUE + return . || ..() + +/decl/flooring/sand/chlorine + name = "chlorinated sand" + desc = "Sand that has been heavily contaminated by chlorine." + icon = 'icons/turf/flooring/chlorine_sand.dmi' + icon_base = "chlorine" + has_base_range = 11 + icon_edge_layer = FLOOR_EDGE_CHLORINE_SAND + has_corners = FALSE + color = "#d2e0b7" + dirt_color = "#d2e0b7" + footstep_type = /decl/footsteps/sand + uid = "floor_sand_chlorine" + +/decl/flooring/sand/chlorine/marsh + name = "chlorine marsh" + desc = "A pool of noxious liquid chlorine. It's full of silt and plant matter." + uid = "floor_sand_chlorine_marsh" + +/decl/flooring/sand/fake + name = "holosand" + desc = "Uncomfortably coarse and gritty for a hologram." + holographic = TRUE + uid = "floor_sand_fake" + +/decl/flooring/fake_space + name = "\proper space" + desc = "The final frontier." + icon = 'icons/turf/flooring/fake_space.dmi' + icon_base = "space" + has_base_range = 25 + holographic = TRUE + gender = NEUTER + uid = "floor_space_fake" + +/decl/flooring/melted_sand + name = "molten silica" + desc = "A patch of sand that has been fused into glass by extreme temperature." + icon = 'icons/turf/flooring/sand.dmi' + icon_base = "glass" + has_base_range = null + force_material = /decl/material/solid/glass + uid = "floor_sand_melted" diff --git a/code/game/turfs/flooring/flooring_shuttle.dm b/code/game/turfs/flooring/flooring_shuttle.dm deleted file mode 100644 index f61c6d879e62..000000000000 --- a/code/game/turfs/flooring/flooring_shuttle.dm +++ /dev/null @@ -1,31 +0,0 @@ -/turf/simulated/floor/shuttle - name = "floor" - icon = 'icons/turf/shuttle.dmi' - -/turf/simulated/floor/shuttle/blue - icon_state = "floor" - initial_flooring = /decl/flooring/reinforced/shuttle/blue - -/turf/simulated/floor/shuttle/yellow - icon_state = "floor2" - initial_flooring = /decl/flooring/reinforced/shuttle/yellow - -/turf/simulated/floor/shuttle/white - icon_state = "floor3" - initial_flooring = /decl/flooring/reinforced/shuttle/white - -/turf/simulated/floor/shuttle/red - icon_state = "floor4" - initial_flooring = /decl/flooring/reinforced/shuttle/red - -/turf/simulated/floor/shuttle/purple - icon_state = "floor5" - initial_flooring = /decl/flooring/reinforced/shuttle/purple - -/turf/simulated/floor/shuttle/darkred - icon_state = "floor6" - initial_flooring = /decl/flooring/reinforced/shuttle/darkred - -/turf/simulated/floor/shuttle/black - icon_state = "floor7" - initial_flooring = /decl/flooring/reinforced/shuttle/black diff --git a/code/game/turfs/flooring/flooring_snow.dm b/code/game/turfs/flooring/flooring_snow.dm new file mode 100644 index 000000000000..72362928c06e --- /dev/null +++ b/code/game/turfs/flooring/flooring_snow.dm @@ -0,0 +1,74 @@ +/decl/flooring/snow + name = "snow" + desc = "Let it snow, let it snow, let it snow..." + icon = 'icons/turf/flooring/snow.dmi' + icon_base = "snow" + icon_edge_layer = FLOOR_EDGE_SNOW + has_corners = FALSE + flooring_flags = TURF_REMOVE_SHOVEL + footstep_type = /decl/footsteps/snow + has_base_range = 13 + force_material = /decl/material/solid/ice/snow + can_collect = TRUE + print_type = /obj/effect/footprints + drop_material_on_remove = TRUE + uid = "floor_snow" + can_conceal_hazards = TRUE + +/decl/flooring/snow/get_movement_delay(var/travel_dir, var/mob/mover) + . = ..() + if(mover) + var/obj/item/clothing/shoes/shoes = mover.get_equipped_item(slot_shoes_str) + if(shoes) + . += shoes.snow_slowdown_mod + var/decl/species/my_species = mover.get_species() + if(my_species) + . += my_species.snow_slowdown_mod + . = max(., 0) + +/decl/flooring/snow/fire_act(turf/floor/target, datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(!REAGENT_TOTAL_VOLUME(target.reagents)) + if(target.get_topmost_flooring() == src) + target.remove_flooring(src) + else if(target.get_base_flooring() == src) + target.set_base_flooring(/decl/flooring/permafrost) + return + return ..() + +/decl/flooring/snow/turf_crossed(atom/movable/crosser) + if(!isliving(crosser)) + return + var/mob/living/walker = crosser + // at some point this might even be able to use the height + // of the snow flooring layer, so deep snow gives you more coating + walker.add_walking_contaminant(force_material.type, rand(1, 2)) + +/decl/flooring/snow/can_show_coating_footprints(turf/target, decl/material/contaminant) + if(force_material == contaminant) // So we don't end up covered in a million footsteps that we provided. + return FALSE + return ..() + +/decl/flooring/snow/get_vehicle_transit_delay(obj/vehicle/vehicle) + return vehicle.vehicle_transit_type == vehicle::VEHICLE_SNOWMOBILE ? 0.8 : 1.7 + +/decl/flooring/permafrost + name = "permafrost" + desc = "A stretch of frozen soil that hasn't seen a thaw for many seasons." + icon = 'icons/turf/flooring/snow.dmi' + icon_base = "permafrost" + force_material = /decl/material/solid/ice + uid = "floor_permafrost" + +/decl/flooring/permafrost/get_vehicle_transit_delay(obj/vehicle/vehicle) + if(holographic) + return vehicle::base_speed + if(vehicle.vehicle_transit_type == vehicle::VEHICLE_SNOWMOBILE) + return 0.8 + return ..() + +/decl/flooring/snow/fake + name = "holosnow" + desc = "Not quite the same as snow on an entertainment terminal, but close." + holographic = TRUE + uid = "floor_snow_fake" + diff --git a/code/game/turfs/flooring/flooring_tiled.dm b/code/game/turfs/flooring/flooring_tiled.dm new file mode 100644 index 000000000000..4b762fffeef1 --- /dev/null +++ b/code/game/turfs/flooring/flooring_tiled.dm @@ -0,0 +1,129 @@ +/decl/flooring/tiling + name = "floor" + desc = "A solid, heavy set of flooring plates." + icon = 'icons/turf/flooring/tiles.dmi' + icon_base = "tiled" + descriptor = "tiles" + color = COLOR_DARK_GUNMETAL + damage_temperature = T0C+1400 + flooring_flags = TURF_REMOVE_CROWBAR + build_type = /obj/item/stack/tile/floor + can_paint = TRUE + footstep_type = /decl/footsteps/tiles + force_material = /decl/material/solid/metal/steel + wall_smooth = SMOOTH_ALL + space_smooth = SMOOTH_ALL + constructed = TRUE + gender = NEUTER + deconstruct_sound = 'sound/items/Deconstruct.ogg' + + burned_states = list( + "burned0", + "burned1" + ) + broken_states = list( + "broken0", + "broken1", + "broken2", + "broken3", + "broken4" + ) + uid = "floor_tiled" + +/decl/flooring/tiling/mono + icon_base = "monotile" + build_type = /obj/item/stack/tile/mono + uid = "floor_tiled_mono" + +/decl/flooring/tiling/mono/dark + color = COLOR_DARK_GRAY + build_type = /obj/item/stack/tile/mono/dark + uid = "floor_tiled_dark_mono" + +/decl/flooring/tiling/mono/white + icon_base = "monotile_light" + color = COLOR_OFF_WHITE + build_type = /obj/item/stack/tile/mono/white + uid = "floor_tiled_mono_white" + +/decl/flooring/tiling/white + icon_base = "tiled_light" + desc = "A layer of sterile white tiles." + color = COLOR_OFF_WHITE + build_type = /obj/item/stack/tile/floor_white + uid = "floor_tiled_white" + +/decl/flooring/tiling/dark + desc = "A layer of ominously dark tiles." + color = COLOR_DARK_GRAY + build_type = /obj/item/stack/tile/floor_dark + uid = "floor_tiled_dark" + +/decl/flooring/tiling/dark/mono + icon_base = "monotile" + build_type = null + uid = "floor_tiled_dark_monotile" + +/decl/flooring/tiling/freezer + desc = "A section of non-slip tiles suitable for a cool room or freezer." + icon_base = "freezer" + color = null + flooring_flags = TURF_REMOVE_CROWBAR + build_type = /obj/item/stack/tile/floor_freezer + uid = "floor_tiled_freezer" + +/decl/flooring/tiling/tech + icon = 'icons/turf/flooring/techfloor.dmi' + icon_base = "techfloor_gray" + build_type = /obj/item/stack/tile/techgrey + color = null + uid = "floor_tiled_tech" + +/decl/flooring/tiling/tech/grid + icon_base = "techfloor_grid" + build_type = /obj/item/stack/tile/techgrid + uid = "floor_tiled_tech_grid" + +/decl/flooring/tiling/new_tile + icon_base = "tile_full" + color = null + build_type = null + uid = "floor_tiled_new" + deconstruct_sound = 'sound/items/Deconstruct.ogg' + +/decl/flooring/tiling/new_tile/cargo_one + icon_base = "cargo_one_full" + build_type = null + uid = "floor_tiled_cargo" + +/decl/flooring/tiling/new_tile/kafel + icon_base = "kafel_full" + build_type = null + uid = "floor_tiled_kafel" + +/decl/flooring/tiling/stone + icon_base = "stone" + build_type = /obj/item/stack/tile/stone + uid = "floor_tiled_stone" + +/decl/flooring/tiling/new_tile/techmaint + icon_base = "techmaint" + build_type = /obj/item/stack/tile/techmaint + uid = "floor_tiled_techmaint" + +/decl/flooring/tiling/new_tile/monofloor + icon_base = "monofloor" + color = COLOR_GUNMETAL + uid = "floor_tiled_monofloor" + +/decl/flooring/tiling/new_tile/steel_grid + icon_base = "grid" + color = COLOR_GUNMETAL + build_type = /obj/item/stack/tile/grid + uid = "floor_tiled_steel_grid" + +/decl/flooring/tiling/new_tile/steel_ridged + icon_base = "ridged" + color = COLOR_GUNMETAL + build_type = /obj/item/stack/tile/ridge + uid = "floor_tiled_steel_ridged" diff --git a/code/game/turfs/flooring/flooring_wood.dm b/code/game/turfs/flooring/flooring_wood.dm new file mode 100644 index 000000000000..20a479a891e0 --- /dev/null +++ b/code/game/turfs/flooring/flooring_wood.dm @@ -0,0 +1,148 @@ +/decl/flooring/wood + name = "wooden floor" + desc = "A stretch of closely-fitted wooden planks." + icon = 'icons/turf/flooring/wood.dmi' + icon_base = "wood" + has_base_range = 4 + damage_temperature = T0C+200 + descriptor = "planks" + build_type = /obj/item/stack/tile/wood + flooring_flags = TURF_IS_FRAGILE | TURF_REMOVE_SCREWDRIVER + footstep_type = /decl/footsteps/wood + color = null + force_material = /decl/material/solid/organic/wood/oak + constructed = TRUE + gender = NEUTER + broken_states = list( + "broken0", + "broken1", + "broken2", + "broken3", + "broken4", + "broken5", + "broken6" + ) + uid = "floor_wood" + +/decl/flooring/wood/mahogany + build_type = /obj/item/stack/tile/wood/mahogany + force_material = /decl/material/solid/organic/wood/mahogany + uid = "floor_wood_mahogany" + +/decl/flooring/wood/maple + build_type = /obj/item/stack/tile/wood/maple + force_material = /decl/material/solid/organic/wood/maple + uid = "floor_wood_maple" + +/decl/flooring/wood/ebony + build_type = /obj/item/stack/tile/wood/ebony + force_material = /decl/material/solid/organic/wood/ebony + uid = "floor_wood_ebony" + +/decl/flooring/wood/walnut + build_type = /obj/item/stack/tile/wood/walnut + force_material = /decl/material/solid/organic/wood/walnut + uid = "floor_wood_walnut" + +/decl/flooring/wood/bamboo + build_type = /obj/item/stack/tile/wood/bamboo + force_material = /decl/material/solid/organic/wood/bamboo + uid = "floor_wood_bamboo" + +/decl/flooring/wood/yew + build_type = /obj/item/stack/tile/wood/yew + force_material = /decl/material/solid/organic/wood/yew + uid = "floor_wood_yew" + +// Rough-hewn floors. +/decl/flooring/wood/rough + + name = "rough wooden floor" + desc = "A stretch of loosely-fitted, rough-hewn wooden planks." + icon = 'icons/turf/flooring/wood_alt.dmi' + icon_base = "wood_peasant" + has_base_range = 3 + build_type = /obj/item/stack/tile/wood/rough + broken_states = null + uid = "floor_wood_rough" + +/decl/flooring/wood/rough/mahogany + build_type = /obj/item/stack/tile/wood/rough/mahogany + force_material = /decl/material/solid/organic/wood/mahogany + uid = "floor_wood_rough_mahogany" + +/decl/flooring/wood/rough/maple + build_type = /obj/item/stack/tile/wood/rough/maple + force_material = /decl/material/solid/organic/wood/maple + uid = "floor_wood_rough_maple" + +/decl/flooring/wood/rough/ebony + build_type = /obj/item/stack/tile/wood/rough/ebony + force_material = /decl/material/solid/organic/wood/ebony + uid = "floor_wood_rough_ebony" + +/decl/flooring/wood/rough/walnut + build_type = /obj/item/stack/tile/wood/rough/walnut + force_material = /decl/material/solid/organic/wood/walnut + uid = "floor_wood_rough_walnut" + +/decl/flooring/wood/rough/bamboo + build_type = /obj/item/stack/tile/wood/rough/bamboo + force_material = /decl/material/solid/organic/wood/bamboo + uid = "floor_wood_rough_bamboo" + +/decl/flooring/wood/rough/yew + build_type = /obj/item/stack/tile/wood/rough/yew + force_material = /decl/material/solid/organic/wood/yew + uid = "floor_wood_rough_yew" + +// Chipboard/wood laminate floors. Uses older icons. +/decl/flooring/laminate + name = "wooden laminate floor" + desc = "A stretch of closely-fitted sections of chipboard with a laminated veneer." + icon = 'icons/turf/flooring/laminate.dmi' + icon_base = "wood" + damage_temperature = T0C+200 + descriptor = "sections" + build_type = /obj/item/stack/tile/wood/laminate/oak + flooring_flags = TURF_IS_FRAGILE | TURF_REMOVE_SCREWDRIVER + footstep_type = /decl/footsteps/wood + color = null + force_material = /decl/material/solid/organic/wood/chipboard + constructed = TRUE + gender = NEUTER + broken_states = list( + "broken0", + "broken1", + "broken2", + "broken3", + "broken4", + "broken5", + "broken6" + ) + uid = "floor_wood_lami" + +/decl/flooring/laminate/mahogany + build_type = /obj/item/stack/tile/wood/laminate/mahogany + force_material = /decl/material/solid/organic/wood/chipboard/mahogany + uid = "floor_wood_lami_mahogany" + +/decl/flooring/laminate/maple + build_type = /obj/item/stack/tile/wood/laminate/maple + force_material = /decl/material/solid/organic/wood/chipboard/maple + uid = "floor_wood_lami_maple" + +/decl/flooring/laminate/ebony + build_type = /obj/item/stack/tile/wood/laminate/ebony + force_material = /decl/material/solid/organic/wood/chipboard/ebony + uid = "floor_wood_lami_ebony" + +/decl/flooring/laminate/walnut + build_type = /obj/item/stack/tile/wood/laminate/walnut + force_material = /decl/material/solid/organic/wood/chipboard/walnut + uid = "floor_wood_lami_walnut" + +/decl/flooring/laminate/yew + build_type = /obj/item/stack/tile/wood/laminate/yew + force_material = /decl/material/solid/organic/wood/chipboard/yew + uid = "floor_wood_lami_yew" diff --git a/code/game/turfs/floors/_floor.dm b/code/game/turfs/floors/_floor.dm new file mode 100644 index 000000000000..ece70741f5c2 --- /dev/null +++ b/code/game/turfs/floors/_floor.dm @@ -0,0 +1,207 @@ +/turf/floor + name = "plating" + icon = 'icons/turf/flooring/plating.dmi' + icon_state = "plating" + layer = PLATING_LAYER + permit_ao = TRUE + thermal_conductivity = 0.040 + explosion_resistance = 1 + turf_flags = TURF_IS_HOLOMAP_PATH + initial_gas = GAS_STANDARD_AIRMIX + zone_membership_candidate = TRUE + open_turf_type = /turf/open/airless + + /// Reagent to use to refill trenches to capacity automatically. + var/fill_reagent_type + var/can_engrave = TRUE + + // Damage to flooring. + // These are icon state suffixes, NOT booleans! + var/_floor_broken + var/_floor_burned + + // Flooring data. + var/floor_icon_state_override + + var/const/TRENCH_DEPTH_PER_ACTION = 100 + +/turf/floor/Initialize(var/ml, var/floortype) + + if(_base_flooring) + set_base_flooring(_base_flooring, skip_update = TRUE) + + . = ..(ml) + + set_turf_materials(material, skip_update = TRUE) + + if(istext(_flooring)) + _flooring = resolve_decl_uid_list(cached_json_decode(_flooring)) + if(!length(_flooring)) + _flooring = null + + if(!floortype && (ispath(_flooring) || islist(_flooring))) + floortype = _flooring + else + floortype = null + if(floortype) + _flooring = null + set_flooring(floortype, skip_update = TRUE) + + fill_to_zero_height() // try to refill turfs that act as fluid sources + + if(material || get_topmost_flooring()) + update_from_flooring(skip_update = ml) + if(ml) // We skipped the update above to avoid updating our neighbors, but we need to update ourselves. + lazy_update_icon() + +/turf/floor/ChangeTurf(turf/N, tell_universe, force_lighting_update, keep_air, update_open_turfs_above, keep_height) + if(is_processing) + STOP_PROCESSING(SSobj, src) + . = ..() + +/turf/floor/Destroy() + clear_flooring() + if(is_processing) + STOP_PROCESSING(SSobj, src) + return ..() + +/turf/floor/proc/fill_to_zero_height() + var/my_height = get_physical_height() + if(fill_reagent_type && my_height < 0 && (!reagents || !QDELING(reagents)) && REAGENT_TOTAL_VOLUME(reagents) < abs(my_height)) + var/reagents_to_add = abs(my_height) - REAGENT_TOTAL_VOLUME(reagents) + var/contaminant_to_add = 0 + if(contaminant_reagent_type) + contaminant_to_add = CHEMS_QUANTIZE(reagents_to_add * contaminant_proportion) + add_to_reagents(fill_reagent_type, reagents_to_add - contaminant_to_add, phase = MAT_PHASE_LIQUID, defer_update = !!contaminant_to_add) + if(contaminant_to_add) + add_to_reagents(contaminant_reagent_type, contaminant_to_add, phase = MAT_PHASE_LIQUID) + +/turf/floor/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(check_fluid_depth(FLUID_SHALLOW)) + . += SPAN_NOTICE("It has a pool of [get_fluid_name()].") + +/turf/floor/can_climb_from_below(var/mob/climber) + return TRUE + +/turf/floor/is_plating() + if(density) + return FALSE + var/decl/flooring/flooring = get_topmost_flooring() + return (!istype(flooring) || flooring == get_base_flooring()) + +/turf/floor/get_base_movement_delay(var/travel_dir, var/mob/mover) + var/decl/flooring/flooring = get_topmost_flooring() + return istype(flooring) ? flooring.get_movement_delay(travel_dir, mover) : ..() + +/turf/floor/protects_atom(var/atom/A) + return (A.level <= LEVEL_BELOW_PLATING && !is_plating()) || ..() + +/turf/floor/on_reagent_change() + . = ..() + if(!QDELETED(src)) + fill_to_zero_height() + update_floor_strings() + +/turf/floor/can_engrave() + var/decl/flooring/flooring = get_topmost_flooring() + return flooring ? flooring.can_engrave : can_engrave + +/turf/floor/shuttle_ceiling + name = "hull plating" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "reinforced_light" + initial_gas = null + +/turf/floor/shuttle_ceiling/air + initial_gas = GAS_STANDARD_AIRMIX + +/turf/floor/is_floor() + return !density && !is_open() + +/turf/floor/handle_universal_decay() + if(!is_floor_burned()) + burn_tile() + else if(has_flooring()) + break_tile_to_plating() + else + physically_destroyed() + +/turf/floor/get_footstep_sound(var/mob/stepper) + var/decl/flooring/use_flooring = get_topmost_flooring() + if(istype(use_flooring)) + return get_footstep_for_mob(use_flooring.footstep_type, stepper) + return ..() + +/turf/floor/get_movable_alpha_mask_state(atom/movable/mover) + . = ..() + if(!.) + var/decl/flooring/flooring = get_topmost_flooring() + return flooring?.get_movable_alpha_mask_state(mover) + +/turf/floor/dismantle_turf(devastated, explode, no_product) + if(is_constructed_floor()) + return ..() + return !!switch_to_base_turf() + +/turf/floor/get_soil_color() + var/decl/flooring/flooring = get_topmost_flooring() + return flooring ? flooring.dirt_color : "#7c5e42" + +/turf/floor/get_color() + if(paint_color) + return paint_color + var/decl/flooring/flooring = get_topmost_flooring() + if(istype(flooring) && !isnull(flooring.color)) + return flooring.color + var/decl/material/my_material = get_material() + if(istype(my_material)) + return my_material.color + return color + +/turf/floor/Process() + for(var/decl/flooring/flooring in get_all_flooring()) + if(flooring.has_environment_proc) + return flooring.handle_environment_proc(src) + return PROCESS_KILL + +// In case a catwalk or other blocking item is destroyed. +/turf/floor/Exited(atom/movable/AM, atom/new_loc) + . = ..() + if(!is_processing) + for(var/decl/flooring/flooring in get_all_flooring()) + if(flooring.has_environment_proc) + START_PROCESSING(SSobj, src) + break + var/decl/flooring/print_flooring = get_topmost_flooring() + print_flooring?.turf_exited(src, AM, new_loc) + +// In case something of interest enters our turf. +/turf/floor/Entered(atom/movable/AM, atom/old_loc) + . = ..() + for(var/decl/flooring/flooring in get_all_flooring()) + if(flooring.has_environment_proc) + if(!is_processing) + START_PROCESSING(SSobj, src) + flooring.handle_environment_proc(src) + break + var/decl/flooring/print_flooring = get_topmost_flooring() + print_flooring?.turf_entered(src, AM, old_loc) + +/turf/floor/get_plant_growth_rate() + var/decl/flooring/flooring = get_topmost_flooring() + return flooring ? flooring.growth_value : ..() + +/turf/floor/Crossed(atom/movable/AM) + var/decl/flooring/flooring = get_topmost_flooring() + flooring?.turf_crossed(AM) + return ..() + +/turf/floor/can_show_coating_footprints(decl/material/contaminant = null) + return ..() && get_topmost_flooring()?.can_show_coating_footprints(src, contaminant) + +/turf/floor/proc/get_vehicle_transit_delay(obj/vehicle/vehicle) + var/decl/flooring/terrain = get_topmost_flooring() + if(!istype(vehicle) || QDELETED(vehicle) || !istype(terrain) || vehicle.vehicle_transit_type == vehicle::VEHICLE_GENERIC) + return vehicle::base_speed + return terrain.get_vehicle_transit_delay(vehicle) diff --git a/code/game/turfs/floors/floor_acts.dm b/code/game/turfs/floors/floor_acts.dm new file mode 100644 index 000000000000..ee60bcbf367f --- /dev/null +++ b/code/game/turfs/floors/floor_acts.dm @@ -0,0 +1,59 @@ +/turf/floor/explosion_act(severity) + SHOULD_CALL_PARENT(TRUE) + ..() + if(severity == 1) + ChangeTurf(get_base_turf_by_area(src), keep_air = TRUE) + else if(severity == 2) + switch(pick(40;1,40;2,3)) + if (1) + if(prob(33)) + var/decl/material/mat = GET_DECL(/decl/material/solid/metal/steel) + mat.place_shards(src) + physically_destroyed() + if(2) + ChangeTurf(get_base_turf_by_area(src), keep_air = TRUE) + if(3) + if(prob(33)) + var/decl/material/mat = GET_DECL(/decl/material/solid/metal/steel) + mat.place_shards(src) + if(prob(80)) + break_tile_to_plating() + else + break_tile() + hotspot_expose(1000,CELL_VOLUME) + else if(severity == 3 && prob(50)) + break_tile() + hotspot_expose(1000,CELL_VOLUME) + +/turf/floor/fluid_act(var/datum/reagents/fluids) + . = ..() + if(!QDELETED(fluids) && REAGENT_TOTAL_VOLUME(fluids)) + for(var/decl/flooring/flooring in get_all_flooring()) + if(flooring.fluid_act(src, fluids)) + return + +/turf/floor/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + + for(var/decl/flooring/flooring in get_all_flooring()) + if(flooring.fire_act(src, air, exposed_temperature, exposed_volume)) + return + + var/temp_destroy = get_damage_temperature() + if(!is_floor_burned() && prob(5)) + burn_tile(exposed_temperature) + else if(temp_destroy && exposed_temperature >= (temp_destroy + 100) && prob(1) && has_flooring()) + remove_flooring(get_topmost_flooring()) //destroy the tile, exposing plating + burn_tile(exposed_temperature) + return ..() + +//should be a little bit lower than the temperature required to destroy the material +/turf/floor/proc/get_damage_temperature() + var/decl/flooring/flooring = get_topmost_flooring() + return flooring?.damage_temperature + +/turf/floor/adjacent_fire_act(turf/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) + var/dir_to = get_dir(src, adj_turf) + + for(var/obj/structure/window/window in src) + if(window.dir == dir_to || window.is_fulltile()) //Same direction or diagonal (full tile) + window.fire_act(adj_air, adj_temp, adj_volume) diff --git a/code/game/turfs/floors/floor_attackby.dm b/code/game/turfs/floors/floor_attackby.dm new file mode 100644 index 000000000000..c509629a34d2 --- /dev/null +++ b/code/game/turfs/floors/floor_attackby.dm @@ -0,0 +1,205 @@ +/turf/floor/attack_hand(mob/user) + + // Collect snow or mud. + var/decl/flooring/flooring = get_topmost_flooring() + if(flooring?.handle_hand_interaction(src, user)) + return TRUE + + var/obj/item/hand = GET_EXTERNAL_ORGAN(user, user.get_active_held_item_slot()) + if(hand && try_graffiti(user, hand)) + return TRUE + + return ..() + +/turf/floor/attackby(var/obj/item/used_item, var/mob/user) + if(!used_item || !user) + return FALSE + if(istype(used_item, /obj/item/stack/tile/roof) || IS_COIL(used_item) || (has_flooring() && istype(used_item, /obj/item/stack/material/rods))) + return ..() + var/decl/flooring/top_flooring = get_topmost_flooring() + if(istype(top_flooring) && top_flooring.handle_item_interaction(src, user, used_item)) + return TRUE + if(try_backfill(used_item, user)) + return TRUE + if(try_stack_build(used_item, user)) + return TRUE + if(try_turf_repair_or_deconstruct(used_item, user)) + return TRUE + return ..() + +/turf/floor/proc/try_build_catwalk(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/stack/material/rods) && !get_supporting_platform()) + var/obj/item/stack/material/rods/R = used_item + if (R.use(2)) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + new /obj/structure/catwalk(src, R.material.type) + return TRUE + return FALSE + +/turf/floor/proc/try_stack_build(var/obj/item/stack/S, var/mob/user) + if(!istype(S)) + return FALSE + + if(is_floor_damaged()) + to_chat(user, SPAN_WARNING("This section is too damaged to support anything. Use a welder to fix the damage.")) + return TRUE + + if(try_build_catwalk(S, user)) + return TRUE + + var/decl/flooring/use_flooring + for(var/decl/flooring/F as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/flooring)) + if(!F.build_type) + continue + // If S.build_type is set, we expect an exact match. Otherwise, we do + // an ispath on S.type. This is a shitty way to disambiguate carpet + // types because they're in the ugly position of "same material, built + // with a subtype" whereas with everything else, material + type + // disambiguates well enough. + if((S.build_type ? S.build_type == F.build_type : ispath(S.type, F.build_type)) && (isnull(F.build_material) || S.material?.type == F.build_material)) + use_flooring = F + break + if(!use_flooring) + return FALSE + + // Do we have enough? + if(use_flooring.build_cost && S.get_amount() < use_flooring.build_cost) + to_chat(user, SPAN_WARNING("You require at least [use_flooring.build_cost] [S.name] to complete the [use_flooring.descriptor].")) + return TRUE + // Stay still and focus... + if(use_flooring.build_time && !do_after(user, use_flooring.build_time, src)) + return TRUE + if(has_flooring() || !S || !user || !use_flooring) + return TRUE + if(S.use(use_flooring.build_cost)) + set_flooring(use_flooring) + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + return TRUE + +/turf/floor/proc/try_backfill(obj/item/stack/material/used_item, mob/user) + + var/decl/flooring/flooring = get_topmost_flooring() + if((istype(flooring) && flooring.constructed) || !istype(used_item) || !istype(user)) + return FALSE + + var/decl/flooring/base_flooring = get_base_flooring() + if(istype(base_flooring) && base_flooring.constructed) + return FALSE + + if(!istype(used_item, /obj/item/stack/material/ore) && !istype(used_item, /obj/item/stack/material/lump)) + return FALSE + + if(get_physical_height() >= 0) + to_chat(user, SPAN_WARNING("\The [src] is flush with ground level and cannot be backfilled.")) + return TRUE + + if(!used_item.material?.can_backfill_floor_type) + to_chat(user, SPAN_WARNING("You cannot use \the [used_item] to backfill \the [src].")) + return TRUE + + var/can_backfill = islist(used_item.material.can_backfill_floor_type) ? is_type_in_list(flooring, used_item.material.can_backfill_floor_type) : istype(flooring, used_item.material.can_backfill_floor_type) + if(!can_backfill) + to_chat(user, SPAN_WARNING("You cannot use \the [used_item] to backfill \the [src].")) + return TRUE + + var/obj/item/stack/stack = used_item + if(!do_after(user, 1 SECOND, src) || user.get_active_held_item() != stack || get_physical_height() >= 0) + return TRUE + + // At best, you get about 5 pieces of clay or dirt from digging the + // associated turfs. So we'll make it cost 5 to put some back. + // TODO: maybe make this use the diggable loot list. + var/stack_depth = ceil((abs(get_physical_height()) / TRENCH_DEPTH_PER_ACTION) * 5) + var/using_lumps = max(1, min(stack.amount, min(stack_depth, 5))) + if(stack.use(using_lumps)) + set_physical_height(min(0, get_physical_height() + ((using_lumps / 5) * TRENCH_DEPTH_PER_ACTION))) + playsound(src, 'sound/items/shovel_dirt.ogg', 50, TRUE) + if(get_physical_height() >= 0) + visible_message(SPAN_NOTICE("\The [user] backfills \the [src]!")) + else + visible_message(SPAN_NOTICE("\The [user] partially backfills \the [src].")) + return TRUE + +/turf/floor/proc/is_constructed_floor() + var/decl/flooring/flooring = get_topmost_flooring() + return flooring?.constructed + +/turf/floor/proc/try_turf_repair_or_deconstruct(var/obj/item/used_item, var/mob/user) + + if(!is_constructed_floor()) + return FALSE + + if(IS_CROWBAR(used_item) && is_floor_damaged()) + playsound(src, 'sound/items/Crowbar.ogg', 80, 1) + visible_message(SPAN_NOTICE("\The [user] has begun prying off the damaged plating.")) + . = TRUE + var/turf/T = GetBelow(src) + if(T) + T.visible_message(SPAN_DANGER("The ceiling above looks as if it's being pried off.")) + + if(do_after(user, 10 SECONDS)) + if(!is_floor_damaged() || !(is_plating()))return + visible_message(SPAN_DANGER("\The [user] has pried off the damaged plating!")) + new /obj/item/stack/tile/floor(src) + physically_destroyed() + playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) + if(T) + T.visible_message(SPAN_DANGER("The ceiling above has been pried off!")) + return TRUE + + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.isOn() && is_plating() && welder.weld(0, user)) + if(is_floor_damaged()) + to_chat(user, SPAN_NOTICE("You fix some damage to \the [src].")) + playsound(src, 'sound/items/Welder.ogg', 80, 1) + icon_state = "plating" + set_floor_burned(skip_update = TRUE) + set_floor_broken() + else + playsound(src, 'sound/items/Welder.ogg', 80, 1) + visible_message(SPAN_NOTICE("\The [user] has started melting \the [src]'s reinforcements!")) + if(do_after(user, 5 SECONDS) && welder.isOn() && welder_melt()) + visible_message(SPAN_NOTICE("\The [user] has melted \the [src]'s reinforcements! It should now be possible to pry it off.")) + playsound(src, 'sound/items/Welder.ogg', 80, 1) + return TRUE + + if(istype(used_item, /obj/item/gun/energy/plasmacutter) && (is_plating()) && !is_floor_damaged()) + var/obj/item/gun/energy/plasmacutter/cutter = used_item + if(cutter.slice(user)) + playsound(src, 'sound/items/Welder.ogg', 80, 1) + visible_message(SPAN_NOTICE("\The [user] has started slicing through \the [src]'s reinforcements!")) + . = TRUE + if(do_after(user, 3 SECONDS) && welder_melt()) + visible_message(SPAN_NOTICE("\The [user] has sliced through \the [src]'s reinforcements! It should now be possible to pry it off.")) + playsound(src, 'sound/items/Welder.ogg', 80, 1) + return TRUE + + return FALSE + +/turf/floor/proc/welder_melt() + if(!(is_plating()) || is_floor_damaged()) + return FALSE + // if burned/broken is nonzero plating just chooses a random icon + // so it doesn't really matter what we set this to as long as it's truthy + // let's keep it a string for consistency with the other uses of it + set_floor_burned(TRUE, skip_update = TRUE) + remove_decals() + return TRUE + +/turf/floor/why_cannot_build_cable(var/mob/user, var/cable_error) + switch(cable_error) + if(0) + return + if(1) + to_chat(user, SPAN_WARNING("Removing the tiling first.")) + if(2) + to_chat(user, SPAN_WARNING("This section is too damaged to support anything. Use a welder to fix the damage.")) + else //Fallback + . = ..() + +/turf/floor/cannot_build_cable() + if(is_floor_damaged()) + return 2 + if(!is_plating()) + return 1 diff --git a/code/game/turfs/floors/floor_damage.dm b/code/game/turfs/floors/floor_damage.dm new file mode 100644 index 000000000000..1fed09cc4c2e --- /dev/null +++ b/code/game/turfs/floors/floor_damage.dm @@ -0,0 +1,18 @@ +/turf/floor/proc/break_tile_to_plating() + if(has_flooring()) + clear_flooring() + break_tile() + +/turf/floor/proc/break_tile() + var/decl/flooring/flooring = get_topmost_flooring() + if(!istype(flooring) || !length(flooring.broken_states) || is_floor_broken()) + return + set_floor_broken(TRUE) + remove_decals() + +/turf/floor/proc/burn_tile(var/exposed_temperature) + var/decl/flooring/flooring = get_topmost_flooring() + if(!istype(flooring) || !length(flooring.burned_states) || is_floor_burned()) + return + set_floor_burned(TRUE) + remove_decals() diff --git a/code/game/turfs/floors/floor_digging.dm b/code/game/turfs/floors/floor_digging.dm new file mode 100644 index 000000000000..24a4f9edb132 --- /dev/null +++ b/code/game/turfs/floors/floor_digging.dm @@ -0,0 +1,74 @@ +/turf/floor + var/gemstone_dropped = FALSE + +/turf/floor/proc/flooring_is_diggable() + var/decl/flooring/flooring = get_topmost_flooring() + if(!flooring || flooring.constructed) + return FALSE + return TRUE + +/turf/floor/can_be_dug(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + // This should be removed before digging trenches. + if(!flooring_is_diggable()) + return FALSE + var/decl/flooring/flooring = get_base_flooring() + if(istype(flooring) && flooring.constructed) + return FALSE + var/decl/material/my_material = get_material() + if(density || is_open() || !istype(my_material)) + return FALSE + if(my_material.hardness > tool_hardness) + return FALSE + if(using_tool == TOOL_SHOVEL && my_material.hardness > MAT_VALUE_FLEXIBLE) + return FALSE + if(using_tool == TOOL_PICK && my_material.hardness <= MAT_VALUE_FLEXIBLE) + return FALSE + return TRUE + +/turf/floor/dig_trench(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + if(!flooring_is_diggable()) + return + + var/decl/flooring/flooring = get_topmost_flooring() + if(!flooring.handle_turf_digging(src)) + return + + var/old_height = get_physical_height() + var/new_height = max(old_height-TRENCH_DEPTH_PER_ACTION, -(FLUID_DEEP)) + var/height_diff = round(abs(old_height-new_height)) + if(new_height <= -(FLUID_DEEP)) + var/open_turf_path = get_open_turf_type_by_area(src) + if(!open_turf_path) + to_chat(user, SPAN_WARNING("You cannot dig any lower!")) + return + to_chat(user, SPAN_DANGER("You break through \the [src]!")) + drop_diggable_resources(user) + ChangeTurf(open_turf_path) + // Only drop mats if we actually changed the turf height sufficiently. + else if(height_diff >= TRENCH_DEPTH_PER_ACTION) + drop_diggable_resources(user) + set_physical_height(new_height) + +/turf/floor/dig_pit(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return has_flooring() ? null : ..() + +/turf/floor/get_diggable_resources() + var/decl/material/my_material = get_material() + if(!flooring_is_diggable() || !istype(my_material) || !my_material.dug_drop_type || (get_physical_height() <= -(FLUID_DEEP))) + return + + . = list() + + // All turfs drop resources to backfill them with (or make firepits, etc) + .[my_material.dug_drop_type] = list("amount" = 3, "variance" = 2, "material" = my_material.type) + + // Dirt/mud/etc might have some worms. + if(prob(5 * get_plant_growth_rate())) + .[/obj/item/food/worm] = list("amount" = 1, "material" = /obj/item/food/worm::material) + + // Some materials (like clay) might contain gemstones. + if(!gemstone_dropped && prob(my_material.gemstone_chance) && LAZYLEN(my_material.gemstone_types)) + gemstone_dropped = TRUE + var/gem_mat = pick(my_material.gemstone_types) + .[/obj/item/gemstone] = list("amount" = 1, "material" = gem_mat) + diff --git a/code/game/turfs/floors/floor_height.dm b/code/game/turfs/floors/floor_height.dm new file mode 100644 index 000000000000..43057b4dc0cc --- /dev/null +++ b/code/game/turfs/floors/floor_height.dm @@ -0,0 +1,23 @@ +/turf/floor + var/height = 0 + +/turf/floor/get_physical_height() + return density ? 0 : height + +/turf/floor/set_physical_height(new_height) + + if(height == new_height) + return FALSE + + height = new_height + for(var/turf/neighbor as anything in RANGE_TURFS(src, 1)) + neighbor.update_icon() + fluid_update() + if(fluid_overlay) + fluid_overlay.update_icon() + + for(var/atom/movable/thing in contents) + thing.on_turf_height_change(new_height) + + state_was_modified() + return TRUE diff --git a/code/game/turfs/floors/floor_icon.dm b/code/game/turfs/floors/floor_icon.dm new file mode 100644 index 000000000000..0f684b9a5a47 --- /dev/null +++ b/code/game/turfs/floors/floor_icon.dm @@ -0,0 +1,212 @@ +/turf/floor + var/static/HEIGHT_OFFSET_RANGE = (world.icon_size - 16) + /// A cache for full trench shadow images, keyed by shadow_alpha. + VAR_PRIVATE/static/list/_height_shadow_cache = list() + /// A cache for north-edge trench shadow images, keyed by shadow_alpha. + VAR_PRIVATE/static/list/_height_north_shadow_cache = list() + /// A cache for trench images, keyed by icon and then by color. + VAR_PRIVATE/static/list/_trench_image_cache = list() + +/turf/floor/proc/can_draw_edge_over(turf/floor/turf_to_check) + if(istype(turf_to_check)) + var/my_height = get_physical_height() + var/their_height = turf_to_check.get_physical_height() + // Uppermost turfs draw over lower turfs if there is a serious difference. + if(my_height != their_height) + return my_height > their_height + // Use edge layer if we're within height range. + return can_layer_over(turf_to_check) + return TRUE + +/turf/floor/proc/can_layer_over(turf/floor/turf_to_check) + if(!istype(turf_to_check)) + return FALSE + var/decl/flooring/my_flooring = get_topmost_flooring() + if(!istype(my_flooring) || my_flooring.icon_edge_layer == FLOOR_EDGE_NONE) + return FALSE + var/decl/flooring/their_flooring = turf_to_check.get_topmost_flooring() + if(!istype(their_flooring)) + return TRUE + if(their_flooring?.type == my_flooring.neighbour_type) + return FALSE + return my_flooring.icon_edge_layer > their_flooring.icon_edge_layer + +/turf/floor/proc/get_trench_icon() + var/decl/flooring/flooring = get_base_flooring() || get_topmost_flooring() + if(istype(flooring) && flooring.icon && check_state_in_icon("trench", flooring.icon)) + return flooring.icon + +/turf/floor/proc/update_height_appearance() + + var/decl/flooring/flooring = get_topmost_flooring() + if(istype(flooring)) + layer = flooring.floor_layer + else + layer = initial(layer) + + if(istype(flooring) && !flooring.render_trenches) // TODO: Update pool tiles/edges to behave properly with this new system. + default_pixel_z = initial(default_pixel_z) + pixel_z = default_pixel_z + return FALSE + + var/my_height = get_physical_height() + if(my_height >= 0) + default_pixel_z = initial(default_pixel_z) + else + var/height_ratio = clamp(abs(my_height) / FLUID_DEEP, 0, 1) + default_pixel_z = -(min(HEIGHT_OFFSET_RANGE, round(HEIGHT_OFFSET_RANGE * height_ratio))) + pixel_z = default_pixel_z + layer = UNDER_TURF_LAYER + ((1-height_ratio) * 0.01) + + var/shadow_alpha = floor(80 * height_ratio) + var/shadow_alpha_key = num2text(shadow_alpha) + // look up a shadow for our shadow_alpha in the cache, creating one if needed + var/image/I = _height_shadow_cache[shadow_alpha_key] + if(!I) + _height_shadow_cache[shadow_alpha_key] = I = image(icon = 'icons/effects/height_shadow.dmi', icon_state = "full") + I.color = COLOR_BLACK + I.alpha = shadow_alpha + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + add_overlay(I) + + // Draw a cliff wall if we have a northern neighbor that isn't part of our trench. + var/turf/floor/neighbor = get_step_resolving_mimic(src, NORTH) + // skip null and unsim edges, because we don't want trench edges along the edges of a map for no reason + if(!neighbor?.simulated || (isturf(neighbor) && neighbor.is_open())) + return + + if(!istype(neighbor, /turf/floor) || (neighbor.get_physical_height() > my_height)) + + var/trench_icon = (istype(neighbor, /turf/floor) && neighbor.get_trench_icon()) || get_trench_icon() + if(trench_icon) + // cache the trench image, keyed by icon and color + // formerly an isatom check but it should never be a non-atom true value + var/trench_color = neighbor ? neighbor.get_color() : get_color() + var/trench_icon_key = "[ref(trench_icon)][trench_color]" + I = _trench_image_cache[trench_icon_key] + if(!I) + I = image(icon = trench_icon, icon_state = "trench") + I.pixel_z = world.icon_size + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + I.color = trench_color + _trench_image_cache[trench_icon_key] = I + add_overlay(I) + + // look up a shadow for our shadow_alpha in the cache, creating one if needed + I = _height_north_shadow_cache[shadow_alpha_key] + if(!I) + I = image(icon = 'icons/effects/height_shadow.dmi', icon_state = "northedge") + I.pixel_z = world.icon_size + I.color = COLOR_BLACK + I.alpha = shadow_alpha + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + _height_north_shadow_cache[shadow_alpha_key] = I + add_overlay(I) + pixel_z = default_pixel_z + +/turf/floor/on_update_icon() + . = ..() + + color = get_color() + + cut_overlays() + update_height_appearance() // Also refreshes our base layer. + update_floor_icon() + + for(var/image/I in decals) + if(I.layer < layer) + continue + add_overlay(I) + + compile_overlays() + +/turf/floor/proc/update_floor_strings() + var/decl/flooring/flooring = get_topmost_flooring() + if(istype(flooring)) + flooring.update_turf_strings(src) + else + SetName(initial(name)) + desc = initial(desc) + // do this once name and desc have been updated + if(check_fluid_depth(FLUID_SHALLOW)) + SetName(get_fluid_name()) // just entirely overwrite name, but keep desc + +/turf/floor/proc/update_floor_icon() + var/decl/flooring/use_flooring = get_topmost_flooring() + if(istype(use_flooring)) + use_flooring.update_turf_icon(src) + +/turf/floor/proc/is_floor_broken() + var/decl/flooring/flooring = get_topmost_flooring() + return !isnull(_floor_broken) && (!istype(flooring) || length(flooring.broken_states)) + +/turf/floor/proc/is_floor_burned() + var/decl/flooring/flooring = get_topmost_flooring() + return !isnull(_floor_burned) && (!istype(flooring) || length(flooring.burned_states)) + +/turf/floor/proc/is_floor_damaged() + return is_floor_broken() || is_floor_burned() + +/turf/floor/proc/set_floor_broken(new_broken, skip_update) + + var/decl/flooring/flooring = get_topmost_flooring() + if(!istype(flooring) || !length(flooring.broken_states)) + return FALSE + if(new_broken && (!istext(new_broken) || !(new_broken in flooring.broken_states))) + new_broken = pick(flooring.broken_states) + if(_floor_broken != new_broken) + _floor_broken = new_broken + if(!skip_update) + queue_icon_update() + state_was_modified() + return TRUE + return FALSE + +/turf/floor/proc/set_floor_burned(new_burned, skip_update) + + var/decl/flooring/flooring = get_topmost_flooring() + if(!istype(flooring) || !length(flooring.burned_states)) + return FALSE + if(new_burned && (!istext(new_burned) || !(new_burned in flooring.burned_states))) + new_burned = pick(flooring.burned_states) + if(_floor_burned != new_burned) + _floor_burned = new_burned + if(!skip_update) + queue_icon_update() + state_was_modified() + return TRUE + return FALSE + +/decl/flooring/proc/test_link(var/turf/opponent) + if(omni_smooth) // override EVERYTHING + return TRUE + // Just a normal floor + if (istype(opponent, /turf/floor)) + if (floor_smooth == SMOOTH_ALL) + return TRUE + var/turf/floor/floor_opponent = opponent + var/decl/flooring/opponent_flooring = floor_opponent.get_topmost_flooring() + //If the floor is the same as us,then we're linked, + if (istype(opponent_flooring, neighbour_type)) + return TRUE + //If we get here it must be using a whitelist or blacklist + if (floor_smooth == SMOOTH_WHITELIST) + if (flooring_whitelist[opponent_flooring.type]) + //Found a match on the typecache + return TRUE + else if(floor_smooth == SMOOTH_BLACKLIST) + if (flooring_blacklist[opponent_flooring.type]) {EMPTY_BLOCK_GUARD} else + //No match on the typecache + return TRUE + //Check for window frames. + if (wall_smooth == SMOOTH_ALL && locate(/obj/structure/wall_frame) in opponent) + return TRUE + // Wall turf + else if(opponent.is_wall()) // don't combine these so that we don't check if a wall is space just because we don't smooth with walls + if(wall_smooth == SMOOTH_ALL) + return TRUE + //If is_open is true, then it's space or openspace + else if(opponent.is_open()) + if(space_smooth == SMOOTH_ALL) + return TRUE + return FALSE diff --git a/code/game/turfs/floors/floor_layers.dm b/code/game/turfs/floors/floor_layers.dm new file mode 100644 index 000000000000..24e1629b664c --- /dev/null +++ b/code/game/turfs/floors/floor_layers.dm @@ -0,0 +1,251 @@ +/turf/floor + VAR_PROTECTED/decl/flooring/_base_flooring = /decl/flooring/plating + VAR_PROTECTED/list/decl/flooring/_flooring + VAR_PRIVATE/tmp/decl/flooring/_topmost_flooring + +/turf/floor/proc/get_all_flooring() + . = list() + if(_flooring) + if(islist(_flooring)) + for(var/floor in _flooring) + . += RESOLVE_TO_DECL(floor) + else if(!isnull(_flooring)) + . += RESOLVE_TO_DECL(_flooring) + if(_base_flooring) + . += get_base_flooring() + +/turf/floor/proc/has_flooring() + return !isnull(_flooring) + +/turf/floor/proc/set_base_flooring(new_base_flooring, skip_update) + // We can never have a null base flooring. + new_base_flooring = RESOLVE_TO_DECL(new_base_flooring || initial(_base_flooring) || /decl/flooring/plating) + if(_base_flooring == new_base_flooring) + return + _base_flooring = new_base_flooring + update_from_flooring(skip_update) + +/turf/floor/proc/get_base_flooring() + RETURN_TYPE(/decl/flooring) + if(ispath(_base_flooring)) + _base_flooring = GET_DECL(_base_flooring) + return _base_flooring + +/turf/floor/proc/get_topmost_flooring() + RETURN_TYPE(/decl/flooring) + + if(isnull(_topmost_flooring)) + if(isnull(_flooring)) + _topmost_flooring = FALSE + else + var/flooring_length = length(_flooring) + if(flooring_length) // no need to check islist, length is only nonzero for lists and strings, and strings are invalid here + _topmost_flooring = RESOLVE_TO_DECL(_flooring[flooring_length]) + else + _topmost_flooring = RESOLVE_TO_DECL(_flooring) + return _topmost_flooring || get_base_flooring() + +/turf/floor/proc/clear_flooring(skip_update = FALSE, place_product) + if(isnull(_flooring)) + return FALSE + if(islist(_flooring)) + for(var/floor in _flooring) + remove_flooring(floor, TRUE, place_product) + else if(_flooring) + remove_flooring(_flooring, TRUE, place_product) + if(!skip_update) + update_from_flooring() + state_was_modified() + return TRUE + +/turf/floor/proc/remove_flooring(var/decl/flooring/flooring, skip_update, place_product) + + // Remove floor layers one by one. + _topmost_flooring = null + + if(islist(flooring)) + for(var/floor in UNLINT(flooring)) + if(remove_flooring(floor, TRUE, place_product)) + . = TRUE + if(.) + state_was_modified() + if(!skip_update) + set_floor_broken(skip_update = TRUE) + set_floor_burned(skip_update = TRUE) + update_from_flooring() + return + + // Validate our input. + flooring = RESOLVE_TO_DECL(flooring) + if(!istype(flooring)) + return + + // Remove this turf from the layer stack. + var/was_topmost = (flooring == get_topmost_flooring()) + if(islist(_flooring)) + LAZYREMOVE(_flooring, flooring) + if(LAZYLEN(_flooring) == 1) + _flooring = _flooring[1] + else if(_flooring == flooring) + _flooring = null + + state_was_modified() + + // If the turf was not the topmost turf, then we don't really need to care about it. + if(!was_topmost) + return + + LAZYCLEARLIST(decals) + for(var/obj/effect/decal/writing/writing in src) + qdel(writing) + + flooring.on_flooring_remove(src) + + if(flooring.build_type && place_product) + // If build_type uses material stack, check for it + // Because material stack uses different arguments + // And we need to use build material to spawn stack + if(ispath(flooring.build_type, /obj/item/stack/material)) + var/decl/material/M = GET_DECL(flooring.build_material) + if(!M) + CRASH("[src] at ([x], [y], [z]) cannot create stack because it has a bad build_material path: '[flooring.build_material]'") + M.create_object(src, flooring.build_cost, flooring.build_type) + else + var/obj/item/stack/tile/new_tile = new flooring.build_type(src) + if(flooring.can_paint && paint_color) + new_tile.paint_color = paint_color + + if(flooring.has_environment_proc && is_processing) + STOP_PROCESSING(SSobj, src) + + floor_icon_state_override = null + + if(!skip_update) + set_floor_broken(skip_update = TRUE) + set_floor_burned(skip_update = TRUE) + update_from_flooring() + +/turf/floor/proc/set_flooring(var/decl/flooring/newflooring, skip_update, place_product) + + _topmost_flooring = null + + // Clear this here to get it out of the way. + floor_icon_state_override = null + + // If _flooring is unset, we can shortcut a lot of these steps. + if(isnull(_flooring)) + + if(isnull(newflooring)) + return FALSE + + if(islist(newflooring)) + _flooring = list() + for(var/floor in UNLINT(newflooring)) + _flooring += RESOLVE_TO_DECL(floor) + else if(newflooring) + _flooring = RESOLVE_TO_DECL(newflooring) + else + return FALSE + state_was_modified() + if(!skip_update) + update_from_flooring() + return TRUE + + + // If we already have a flooring state, we need to do some cleanup and housekeeping. + clear_flooring(skip_update = TRUE, place_product = place_product) + if(!isnull(newflooring)) + add_flooring(newflooring, skip_update, place_product) + if(!skip_update) + update_from_flooring(skip_update) + +/turf/floor/proc/add_flooring(decl/flooring/newflooring, skip_update) + + _topmost_flooring = null + + // Add floor layers one by one. + if(islist(newflooring)) + for(var/floor in UNLINT(newflooring)) + if(add_flooring(floor, skip_update = FALSE)) + . = TRUE + state_was_modified() + if(!skip_update) + set_floor_broken(skip_update = TRUE) + set_floor_burned(skip_update = TRUE) + update_from_flooring() + return + + // We only want to work with references. + newflooring = RESOLVE_TO_DECL(newflooring) + if(!newflooring) + return FALSE + + // Check if the layer is already present. + if(_flooring) + if(islist(_flooring)) + if(newflooring in _flooring) + return FALSE + else if(newflooring == _flooring) + return FALSE + + // Add our layer to the top of layers. + if(isnull(_flooring)) + _flooring = newflooring + else + if(!islist(_flooring)) + _flooring = list(_flooring) + _flooring |= newflooring + + state_was_modified() + + // Update for the new top layer. + if(!skip_update) + set_floor_broken(skip_update = TRUE) + set_floor_burned(skip_update = TRUE) + update_from_flooring() + + return TRUE + +/turf/floor/proc/update_from_flooring(skip_update) + + _topmost_flooring = null + + var/decl/flooring/copy_from = get_topmost_flooring() + if(!istype(copy_from)) + return // this should never be the case + + update_floor_strings() + + set_gender(copy_from.gender) + + layer = copy_from.floor_layer + turf_flags = copy_from.turf_flags + z_flags = copy_from.z_flags + + if(copy_from.turf_light_range || copy_from.turf_light_power || copy_from.turf_light_color) + set_light(copy_from.turf_light_range, copy_from.turf_light_power, copy_from.turf_light_color) + else + set_light(0) + + if(z_flags & ZM_MIMIC_BELOW) + enable_zmimic(z_flags) + else + disable_zmimic() + + if(copy_from.has_environment_proc) + if(!is_processing) + START_PROCESSING(SSobj, src) + else if(is_processing) + STOP_PROCESSING(SSobj, src) + + levelupdate() + + for(var/obj/effect/footprints/print in src) + qdel(print) + + if(!skip_update) + lazy_update_icon() + for(var/dir in global.alldirs) + var/turf/neighbor = get_step_resolving_mimic(src, dir) + if(istype(neighbor)) + neighbor.lazy_update_icon() diff --git a/code/game/turfs/floors/floor_materials.dm b/code/game/turfs/floors/floor_materials.dm new file mode 100644 index 000000000000..5a7ff3459fd2 --- /dev/null +++ b/code/game/turfs/floors/floor_materials.dm @@ -0,0 +1,23 @@ +/turf/floor/set_turf_materials(decl/material/new_material, decl/material/new_reinf_material, force, decl/material/new_girder_material, skip_update) + + if(ispath(new_material)) + new_material = GET_DECL(new_material) + + if(material != new_material || force) + material = new_material + if(!istype(material)) + if(material) + PRINT_STACK_TRACE("Floor turf has been supplied non-material '[istype(material, /datum) ? material.type : (material || "NULL")]'.") + material = get_default_material() + . = TRUE + + if(.) + state_was_modified() + if(!skip_update) + queue_icon_update() + +/turf/floor/get_material() + var/decl/flooring/flooring = get_topmost_flooring() + if(istype(flooring) && istype(flooring.force_material)) + return flooring.force_material + return material diff --git a/code/game/turfs/floors/floor_serde.dm b/code/game/turfs/floors/floor_serde.dm new file mode 100644 index 000000000000..9e88c47f2a83 --- /dev/null +++ b/code/game/turfs/floors/floor_serde.dm @@ -0,0 +1,30 @@ +/turf/floor/Serialize() + . = ..() + + SERIALIZE_IF_MODIFIED(_floor_broken, /turf/floor) + SERIALIZE_IF_MODIFIED(_floor_burned, /turf/floor) + SERIALIZE_IF_MODIFIED(height, /turf/floor) + SERIALIZE_DECL_IF_MODIFIED(_base_flooring, /turf/floor) + + var/initial_flooring = initial(_flooring) + if(isnull(_flooring) && !isnull(initial_flooring)) + .[nameof(/turf/floor::_flooring)] = json_encode(list()) + else if((ispath(_flooring) || istype(_flooring, /decl)) && (!ispath(initial_flooring) || !DECLS_ARE_EQUIVALENT(_flooring, initial_flooring))) + var/decl/flooring/flooring = RESOLVE_TO_DECL(_flooring) + if(istype(flooring)) + .[nameof(/turf/floor::_flooring)] = json_encode(list(flooring.uid)) + else if(islist(_flooring)) + var/list/flooring_uids + for(var/floor in _flooring) + var/decl/flooring/floor_decl = RESOLVE_TO_DECL(floor) + if(istype(floor_decl)) + LAZYADD(flooring_uids, floor_decl.uid) + if(!istext(initial_flooring) || !(flooring_uids ~= cached_json_decode(initial_flooring))) + .[nameof(/turf/floor::_flooring)] = json_encode(flooring_uids) + +/turf/floor/Deserialize(list/instance_map) + . = ..() + fill_reagent_type = null // Assume any fluids on this turf were serialized and will be deserialized on /turf/Deserialize() + DESERIALIZE_DECL_TO_TYPE(_base_flooring) + // _flooring is expected as a JSON list in base floor + // Initialize(), so no additional deserializing needed here. diff --git a/code/game/turfs/floors/subtypes/floor_carpet.dm b/code/game/turfs/floors/subtypes/floor_carpet.dm new file mode 100644 index 000000000000..32ce9f728b92 --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_carpet.dm @@ -0,0 +1,62 @@ +/turf/floor/carpet + name = "brown carpet" + icon = 'icons/turf/flooring/carpet.dmi' + icon_state = "brown" + _flooring = /decl/flooring/carpet + +/turf/floor/carpet/broken + _floor_broken = TRUE + +/turf/floor/carpet/broken/Initialize() + . = ..() + var/setting_broken = _floor_broken + _floor_broken = null + set_floor_broken(setting_broken) + +/turf/floor/carpet/blue + name = "blue carpet" + icon_state = "blue1" + _flooring = /decl/flooring/carpet/blue + +/turf/floor/carpet/blue2 + name = "pale blue carpet" + icon_state = "blue2" + _flooring = /decl/flooring/carpet/blue2 + +/turf/floor/carpet/blue3 + name = "sea blue carpet" + icon_state = "blue3" + _flooring = /decl/flooring/carpet/blue3 + +/turf/floor/carpet/magenta + name = "magenta carpet" + icon_state = "magenta" + _flooring = /decl/flooring/carpet/magenta + +/turf/floor/carpet/purple + name = "purple carpet" + icon_state = "purple" + _flooring = /decl/flooring/carpet/purple + +/turf/floor/carpet/orange + name = "orange carpet" + icon_state = "orange" + _flooring = /decl/flooring/carpet/orange + +/turf/floor/carpet/green + name = "green carpet" + icon_state = "green" + _flooring = /decl/flooring/carpet/green + +/turf/floor/carpet/red + name = "red carpet" + icon_state = "red" + _flooring = /decl/flooring/carpet/red + +/turf/floor/carpet/rustic + name = "rustic carpet" + icon = 'icons/turf/flooring/simple_carpet.dmi' + icon_state = "carpet" + _flooring = /decl/flooring/carpet/rustic + paint_color = COLOR_CHESTNUT + color = COLOR_CHESTNUT \ No newline at end of file diff --git a/code/game/turfs/floors/subtypes/floor_circuit.dm b/code/game/turfs/floors/subtypes/floor_circuit.dm new file mode 100644 index 000000000000..77bb38e13a45 --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_circuit.dm @@ -0,0 +1,38 @@ +/turf/floor/bluegrid + name = "mainframe floor" + icon = 'icons/turf/flooring/circuit.dmi' + icon_state = "bcircuit" + _flooring = /decl/flooring/reinforced/circuit + +/turf/floor/bluegrid/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/floor/bluegrid/mainframe + name = "mainframe base" // TODO: force name overriding flooring? + temperature = 263 + +/turf/floor/bluegrid/cryo + initial_gas = list(/decl/material/gas/nitrogen = MOLES_CELLSTANDARD) + temperature = -200 CELSIUS + +/turf/floor/greengrid + name = "mainframe floor" + icon = 'icons/turf/flooring/circuit.dmi' + icon_state = "gcircuit" + _flooring = /decl/flooring/reinforced/circuit/green + +/turf/floor/greengrid/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/floor/greengrid/nitrogen + initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD) + +/turf/floor/blackgrid + name = "mainframe floor" + icon = 'icons/turf/flooring/circuit.dmi' + icon_state = "rcircuit" + _flooring = /decl/flooring/reinforced/circuit/red diff --git a/code/game/turfs/floors/subtypes/floor_concrete.dm b/code/game/turfs/floors/subtypes/floor_concrete.dm new file mode 100644 index 000000000000..08fb9b904a1d --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_concrete.dm @@ -0,0 +1,32 @@ +/turf/floor/concrete + name = "concrete" + icon = 'icons/turf/flooring/concrete.dmi' + icon_state = "inset" + _base_flooring = /decl/flooring/concrete + material = /decl/material/solid/stone/concrete + +/turf/floor/concrete/smooth + icon_state = "concrete" + +/turf/floor/concrete/flooded + flooded = /decl/material/liquid/water + color = COLOR_LIQUID_WATER + +/turf/floor/concrete/flooded/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water, NOT 10% salt + +/turf/floor/concrete/reinforced + name = "reinforced concrete" + icon_state = "hexacrete" + _base_flooring = /decl/flooring/concrete/reinforced + +/turf/floor/concrete/reinforced/damaged/LateInitialize() + . = ..() + set_floor_broken(TRUE) + +/turf/floor/concrete/reinforced/road + name = "asphalt" + color = COLOR_GRAY40 + icon_state = "concrete" + _base_flooring = /decl/flooring/concrete/asphalt diff --git a/code/game/turfs/floors/subtypes/floor_misc.dm b/code/game/turfs/floors/subtypes/floor_misc.dm new file mode 100644 index 000000000000..38d066540ce9 --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_misc.dm @@ -0,0 +1,101 @@ +/turf/floor/lino + name = "lino" + icon = 'icons/turf/flooring/linoleum.dmi' + icon_state = "lino" + _flooring = /decl/flooring/linoleum + + +/turf/floor/crystal + name = "crystal floor" + icon = 'icons/turf/flooring/crystal.dmi' + icon_state = "crystal" + _flooring = /decl/flooring/crystal + +/turf/floor/glass + name = "glass floor" + icon = 'icons/turf/flooring/glass.dmi' + icon_state = "glass" + _flooring = /decl/flooring/glass + +/turf/floor/glass/boro + _flooring = /decl/flooring/glass/boro + +/turf/floor/pool + name = "pool floor" + icon = 'icons/turf/flooring/pool.dmi' + icon_state = "pool" + height = -(FLUID_OVER_MOB_HEAD) - 50 + _flooring = /decl/flooring/pool + +/turf/floor/pool/deep + height = -FLUID_DEEP - 50 + +/turf/floor/fake_grass + name = "grass patch" + icon = 'icons/turf/flooring/fakegrass.dmi' + icon_state = "grass0" + _flooring = /decl/flooring/grass/fake + +/turf/floor/woven + name = "floor" + icon = 'icons/turf/flooring/woven.dmi' + icon_state = "woven" + color = COLOR_BEIGE + _flooring = /decl/flooring/woven + +/turf/floor/straw + name = "loose straw" + icon = 'icons/turf/flooring/straw.dmi' + icon_state = "straw" + color = COLOR_WHEAT + _flooring = /decl/flooring/straw + +// Defining this here as a dummy mapping shorthand so mappers can search for 'plating'. +/turf/floor/plating + _base_flooring = /decl/flooring/plating // Setting here so overrides on /turf/floor do not impact explicitly typed plating turfs. + +/turf/floor/plating/flooded + flooded = /decl/material/liquid/water + +// Dirt plating for Tradeship farms. +/turf/floor/plating/dirt + name = "dirt" + icon = 'icons/turf/flooring/dirt.dmi' + icon_state = "dirt" + color = "#41311b" + _flooring = /decl/flooring/dirt + +/turf/floor/plating/broken + _floor_broken = TRUE + +/turf/floor/plating/broken/Initialize(ml, floortype) + . = ..() + var/setting_broken = _floor_broken + _floor_broken = null + set_floor_broken(setting_broken) + +/turf/floor/plating/airless + name = "airless plating" + initial_gas = null + temperature = TCMB + +/turf/floor/plating/airless/broken + _floor_broken = TRUE + +/turf/floor/plating/airless/broken/Initialize(ml, floortype) + . = ..() + var/setting_broken = _floor_broken + _floor_broken = null + set_floor_broken(setting_broken) + +/turf/floor/plating/broken/one + _floor_broken = "broken1" + +/turf/floor/plating/broken/two + _floor_broken = "broken2" + +/turf/floor/plating/broken/three + _floor_broken = "broken3" + +/turf/floor/plating/broken/four + _floor_broken = "broken4" diff --git a/code/game/turfs/floors/subtypes/floor_natural.dm b/code/game/turfs/floors/subtypes/floor_natural.dm new file mode 100644 index 000000000000..9a73b28f4d1b --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_natural.dm @@ -0,0 +1,159 @@ +/turf/floor/barren + name = "ground" + icon = 'icons/turf/flooring/barren.dmi' + icon_state = "barren" + _base_flooring = /decl/flooring/barren + +/turf/floor/dirt + name = "dirt" + icon = 'icons/turf/flooring/dirt.dmi' + icon_state = "dirt" + color = /decl/material/solid/soil::color // preview color + _base_flooring = /decl/flooring/dirt + +/turf/floor/chlorine_sand + name = "chlorinated sand" + icon = 'icons/turf/flooring/chlorine_sand.dmi' + icon_state = "chlorine0" + _base_flooring = /decl/flooring/sand/chlorine + +/turf/floor/chlorine_sand/marsh + name = "chlorine marsh" + _base_flooring = /decl/flooring/sand/chlorine/marsh + height = -(FLUID_SHALLOW) + fill_reagent_type = /decl/material/gas/chlorine + +/turf/floor/lava + name = "lava" + icon = 'icons/turf/flooring/lava.dmi' + icon_state = "lava" + _base_flooring = /decl/flooring/lava + +/turf/floor/grass + name = "grass" + icon = 'icons/turf/flooring/grass.dmi' + icon_state = "grass0" + color = "#5e7a3b" + _flooring = /decl/flooring/grass + _base_flooring = /decl/flooring/dirt + +/turf/floor/grass/snow + name = "snow" + icon = 'icons/turf/flooring/snow.dmi' + icon_state = "snow0" + _flooring = @'["' + /decl/flooring/grass::uid + @'","' + /decl/flooring/snow::uid + @'"]' + +/turf/floor/grass/wild + name = "wild grass" + icon = 'icons/turf/flooring/wildgrass.dmi' + icon_state = "wildgrass" + _flooring = @'["' + /decl/flooring/grass::uid + @'","' + /decl/flooring/grass/wild::uid + @'"]' + +/turf/floor/ice + name = "ice" + icon = 'icons/turf/flooring/ice.dmi' + icon_state = "ice" + color = COLOR_LIQUID_WATER + _flooring = /decl/flooring/ice + _base_flooring = /decl/flooring/dirt + +/turf/floor/snow + name = "snow" + icon = 'icons/turf/flooring/snow.dmi' + icon_state = "snow0" + _flooring = /decl/flooring/snow + _base_flooring = /decl/flooring/dirt + +/turf/floor/clay + name = "clay" + icon = 'icons/turf/flooring/clay.dmi' + icon_state = "clay" + _base_flooring = /decl/flooring/clay + +/turf/floor/clay/flooded + flooded = /decl/material/liquid/water + +/turf/floor/mud + name = "mud" + icon = 'icons/turf/flooring/mud.dmi' + icon_state = "mud" + color = /decl/material/solid/soil::color // preview color + _base_flooring = /decl/flooring/mud + +/turf/floor/mud/water + color = COLOR_SKY_BLUE + height = -(FLUID_SHALLOW) + fill_reagent_type = /decl/material/liquid/water + +/turf/floor/mud/water/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water, NOT 10% salt + +/turf/floor/mud/water/deep + color = COLOR_BLUE + height = -(FLUID_DEEP) + +/turf/floor/mud/water/deep/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water + +/turf/floor/mud/flooded + flooded = /decl/material/liquid/water + +/turf/floor/mud/flooded/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water + +/turf/floor/dry + name = "dry mud" + icon = 'icons/turf/flooring/seafloor.dmi' + icon_state = "seafloor" + _base_flooring = /decl/flooring/dry_mud + +/turf/floor/rock/sand + name = "sand" + icon = 'icons/turf/flooring/sand.dmi' + icon_state = "sand0" + color = "#ae9e66" + _flooring = /decl/flooring/sand + +/turf/floor/rock/sand/water + color = COLOR_SKY_BLUE + height = -(FLUID_SHALLOW) + fill_reagent_type = /decl/material/liquid/water + +/turf/floor/rock/sand/water/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water + +/turf/floor/rock/sand/water/deep + color = COLOR_BLUE + height = -(FLUID_DEEP) + +/turf/floor/rock/sand/water/deep/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water + +/turf/floor/seafloor + name = "sea floor" + icon = 'icons/turf/flooring/seafloor.dmi' + icon_state = "seafloor" + _base_flooring = /decl/flooring/seafloor + +/turf/floor/seafloor/flooded + flooded = /decl/material/liquid/water + color = COLOR_LIQUID_WATER + +/turf/floor/seafloor/flooded/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water + +/turf/floor/shrouded + name = "packed sand" + icon = 'icons/turf/flooring/shrouded.dmi' + icon_state = "shrouded0" + _base_flooring = /decl/flooring/shrouded + +/turf/floor/shrouded/tar + height = -(FLUID_SHALLOW) + fill_reagent_type = /decl/material/liquid/tar diff --git a/code/game/turfs/floors/subtypes/floor_path.dm b/code/game/turfs/floors/subtypes/floor_path.dm new file mode 100644 index 000000000000..bded9334f69b --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_path.dm @@ -0,0 +1,85 @@ + +/turf/floor/path + name = "path" + gender = NEUTER + desc = "A cobbled path made of loose stones." + color = COLOR_GRAY + icon = 'icons/turf/flooring/path.dmi' + icon_state = "cobble0" + _flooring = /decl/flooring/path/cobblestone + material = /decl/material/solid/stone/sandstone + _base_flooring = /decl/flooring/dirt + +/turf/floor/path/Initialize(mapload, no_update_icon) + // Take advantage of the set_turf_materials call in ..() + // to avoid doing pointless work + material ||= get_strata_material_type() || /decl/material/solid/stone/sandstone + . = ..() + if(mapload && is_outside() && prob(20)) + var/image/moss = image('icons/effects/decals/plant_remains.dmi', "leafy_bits", DECAL_LAYER) + moss.pixel_x = rand(-6, 6) + moss.pixel_y = rand(-6, 6) + if(prob(50)) + var/matrix/M = matrix() + var/rot = pick(90, 270, 0, 0) + if(rot) + M.Turn(rot) + else + M.Scale(pick(-1, 1), pick(-1, 1)) + moss.transform = M + LAZYADD(decals, moss) + +/turf/floor/path/running_bond + icon_state = "runningbond0" + _flooring = /decl/flooring/path/running_bond + +/turf/floor/path/herringbone + icon_state = "herringbone" + _flooring = /decl/flooring/path/herringbone + +// Material subtypes. +#define PATH_MATERIAL_SUBTYPES(material_name) \ +/turf/floor/path/##material_name { \ + color = /decl/material/solid/stone/##material_name::color; \ + material = /decl/material/solid/stone/##material_name; \ +} \ +/turf/floor/path/herringbone/##material_name { \ + color = /decl/material/solid/stone/##material_name::color; \ + material = /decl/material/solid/stone/##material_name; \ +} \ +/turf/floor/path/running_bond/##material_name { \ + color = /decl/material/solid/stone/##material_name::color; \ + material = /decl/material/solid/stone/##material_name; \ +} \ +/turf/floor/path/##material_name/water { \ + color = COLOR_SKY_BLUE; \ + fill_reagent_type = /decl/material/liquid/water; \ + height = -(FLUID_SHALLOW); \ +} \ +/turf/floor/path/##material_name/water/deep {\ + color = COLOR_BLUE; \ + height = -(FLUID_DEEP); \ +} \ +/turf/floor/path/herringbone/##material_name/water { \ + color = COLOR_SKY_BLUE; \ + fill_reagent_type = /decl/material/liquid/water; \ + height = -(FLUID_SHALLOW); \ +} \ +/turf/floor/path/herringbone/##material_name/water/deep { \ + color = COLOR_BLUE; \ + height = -(FLUID_DEEP); \ +} \ +/turf/floor/path/running_bond/##material_name/water { \ + color = COLOR_SKY_BLUE; \ + fill_reagent_type = /decl/material/liquid/water; \ + height = -(FLUID_SHALLOW); \ +} \ +/turf/floor/path/running_bond/##material_name/water/deep { \ + color = COLOR_BLUE; \ + height = -(FLUID_DEEP); \ +} +PATH_MATERIAL_SUBTYPES(basalt) +PATH_MATERIAL_SUBTYPES(granite) +PATH_MATERIAL_SUBTYPES(marble) +PATH_MATERIAL_SUBTYPES(sandstone) +#undef PATH_MATERIAL_SUBTYPES \ No newline at end of file diff --git a/code/game/turfs/floors/subtypes/floor_reinforced.dm b/code/game/turfs/floors/subtypes/floor_reinforced.dm new file mode 100644 index 000000000000..551786ed357b --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_reinforced.dm @@ -0,0 +1,41 @@ +/turf/floor/reinforced + name = "reinforced floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "reinforced" + _flooring = /decl/flooring/reinforced + +/turf/floor/reinforced/airless + initial_gas = null + +/turf/floor/reinforced/airmix + initial_gas = list( + /decl/material/gas/oxygen = MOLES_O2ATMOS, + /decl/material/gas/nitrogen = MOLES_N2ATMOS + ) + +/turf/floor/reinforced/nitrogen + initial_gas = list(/decl/material/gas/nitrogen = ATMOSTANK_NITROGEN) + +/turf/floor/reinforced/hydrogen + initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN) + +/turf/floor/reinforced/oxygen + initial_gas = list(/decl/material/gas/oxygen = ATMOSTANK_OXYGEN) + +/turf/floor/reinforced/nitrogen/engine + name = "engine floor" + initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD) + +/turf/floor/reinforced/hydrogen/fuel + initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN_FUEL) + +/turf/floor/reinforced/carbon_dioxide + initial_gas = list(/decl/material/gas/carbon_dioxide = ATMOSTANK_CO2) + +/turf/floor/reinforced/n20 + initial_gas = list(/decl/material/gas/nitrous_oxide = ATMOSTANK_NITROUSOXIDE) + +/turf/floor/reinforced/airless + name = "vacuum floor" + initial_gas = null + temperature = TCMB diff --git a/code/game/turfs/floors/subtypes/floor_rock.dm b/code/game/turfs/floors/subtypes/floor_rock.dm new file mode 100644 index 000000000000..e34bc367a3cc --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_rock.dm @@ -0,0 +1,14 @@ +/turf/floor/rock + name = "rock floor" + icon = 'icons/turf/flooring/rock.dmi' + icon_state = "rock" + _base_flooring = /decl/flooring/rock + +/turf/floor/rock/Initialize(mapload, no_update_icon) + // Take advantage of the set_turf_materials call in ..() + material ||= get_strata_material_type() || /decl/material/solid/stone/sandstone + . = ..() + +/turf/floor/rock/volcanic + name = "volcanic floor" + material = /decl/material/solid/stone/basalt diff --git a/code/game/turfs/floors/subtypes/floor_shuttle.dm b/code/game/turfs/floors/subtypes/floor_shuttle.dm new file mode 100644 index 000000000000..17404b65e480 --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_shuttle.dm @@ -0,0 +1,36 @@ +/turf/floor/shuttle + name = "shuttle floor" + icon = 'icons/turf/flooring/shuttle.dmi' + desc = "A synthetic floor plate commonly seen in shuttles and other vehicles." + _flooring = /decl/flooring/reinforced/shuttle + +/turf/floor/shuttle/airless + initial_gas = null + +/turf/floor/shuttle/blue + icon_state = "floor" + _flooring = /decl/flooring/reinforced/shuttle/blue + +/turf/floor/shuttle/yellow + icon_state = "floor2" + _flooring = /decl/flooring/reinforced/shuttle/yellow + +/turf/floor/shuttle/white + icon_state = "floor3" + _flooring = /decl/flooring/reinforced/shuttle/white + +/turf/floor/shuttle/red + icon_state = "floor4" + _flooring = /decl/flooring/reinforced/shuttle/red + +/turf/floor/shuttle/purple + icon_state = "floor5" + _flooring = /decl/flooring/reinforced/shuttle/purple + +/turf/floor/shuttle/darkred + icon_state = "floor6" + _flooring = /decl/flooring/reinforced/shuttle/darkred + +/turf/floor/shuttle/black + icon_state = "floor7" + _flooring = /decl/flooring/reinforced/shuttle/black diff --git a/code/game/turfs/floors/subtypes/floor_static.dm b/code/game/turfs/floors/subtypes/floor_static.dm new file mode 100644 index 000000000000..0a345025524a --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_static.dm @@ -0,0 +1,57 @@ +// This type of flooring cannot be altered short of being destroyed and rebuilt. +// Use this to bypass the flooring system entirely ie. event areas, holodeck, etc. + +/turf/floor/fixed + name = "floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "steel" + _flooring = null + footstep_type = /decl/footsteps/plating + is_outside = OUTSIDE_AREA + +/turf/floor/fixed/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/stack) && !IS_COIL(used_item)) + return TRUE + return ..() + +/turf/floor/fixed/on_update_icon() + queue_ao(FALSE) + +/turf/floor/fixed/is_plating() + return 0 + +/turf/floor/fixed/set_flooring(var/decl/flooring/newflooring, skip_update, place_product) + return + +/turf/floor/fixed/alium + name = "alien plating" + desc = "This obviously wasn't made for your feet." + icon = 'icons/turf/flooring/alium.dmi' + icon_state = "jaggy" + +/turf/floor/fixed/alium/attackby(var/obj/item/used_item, var/mob/user) + if(IS_CROWBAR(used_item)) + to_chat(user, "There aren't any openings big enough to pry it away...") + return TRUE + return ..() + +/turf/floor/fixed/alium/Initialize() + . = ..() + var/decl/material/A = GET_DECL(/decl/material/solid/metal/aliumium) + if(!A) + return + color = A.color + var/style = A.hardness % 2 ? "curvy" : "jaggy" + icon_state = "[style][(x*y) % 7]" + +/turf/floor/fixed/alium/airless + initial_gas = null + temperature = TCMB + +/turf/floor/fixed/alium/explosion_act(severity) + SHOULD_CALL_PARENT(FALSE) + var/decl/material/A = GET_DECL(/decl/material/solid/metal/aliumium) + if(prob(A.explosion_resistance)) + return + if(severity == 1) + ChangeTurf(get_base_turf_by_area(src), keep_air = TRUE) diff --git a/code/game/turfs/floors/subtypes/floor_tiled.dm b/code/game/turfs/floors/subtypes/floor_tiled.dm new file mode 100644 index 000000000000..9777e8146710 --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_tiled.dm @@ -0,0 +1,140 @@ +//Tiled floor + sub-types +/turf/floor/tiled + name = "floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "tiled" + _flooring = /decl/flooring/tiling + color = /decl/flooring/tiling::color + +/turf/floor/tiled/dark + name = "dark floor" + icon_state = "dark" + _flooring = /decl/flooring/tiling/dark + color = /decl/flooring/tiling/dark::color + +/turf/floor/tiled/dark/cryo + initial_gas = list(/decl/material/gas/nitrogen = MOLES_CELLSTANDARD) + temperature = -200 CELSIUS + +/turf/floor/tiled/dark/monotile + name = "floor" + icon_state = "monotiledark" + _flooring = /decl/flooring/tiling/mono/dark + +/turf/floor/tiled/dark/monotile/telecomms + name = "telecomms dark floor" // TODO: force name overriding flooring? + temperature = 263 + +/turf/floor/tiled/dark/airless + initial_gas = null + +/turf/floor/tiled/white + name = "white floor" + icon_state = "white" + _flooring = /decl/flooring/tiling/white + +/turf/floor/tiled/white/monotile + name = "floor" + icon_state = "monotile" + _flooring = /decl/flooring/tiling/mono/white + +/turf/floor/tiled/monofloor + name = "floor" + icon_state = "steel_monofloor" + _flooring = /decl/flooring/tiling/mono + color = /decl/flooring/tiling/mono::color + +/turf/floor/tiled/white/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/floor/tiled/freezer + name = "tiles" + icon_state = "freezer" + _flooring = /decl/flooring/tiling/freezer + color = /decl/flooring/tiling/freezer::color + +/turf/floor/tiled/freezer/kitchen + name = "kitchen freezer floor" // TODO: force override of flooring name + temperature = 263 + +/turf/floor/tiled/techmaint + name = "floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "techmaint" + _flooring = /decl/flooring/tiling/new_tile/techmaint + +/turf/floor/tiled/monofloor + name = "floor" + icon_state = "steel_monofloor" + _flooring = /decl/flooring/tiling/new_tile/monofloor + +/turf/floor/tiled/techfloor + name = "floor" + icon = 'icons/turf/flooring/techfloor.dmi' + icon_state = "techfloor_gray" + _flooring = /decl/flooring/tiling/tech + +/turf/floor/tiled/techfloor/cryo + initial_gas = list(/decl/material/gas/nitrogen = MOLES_CELLSTANDARD) + temperature = -200 CELSIUS + +/turf/floor/tiled/monotile + name = "floor" + icon_state = "steel_monotile" + _flooring = /decl/flooring/tiling/mono + +/turf/floor/tiled/steel_grid + name = "floor" + icon_state = "steel_grid" + _flooring = /decl/flooring/tiling/new_tile/steel_grid + +/turf/floor/tiled/steel_ridged + name = "floor" + icon_state = "steel_ridged" + _flooring = /decl/flooring/tiling/new_tile/steel_ridged + +/turf/floor/tiled/old_tile + name = "floor" + icon_state = "tile_full" + _flooring = /decl/flooring/tiling/new_tile + +/turf/floor/tiled/old_cargo + name = "floor" + icon_state = "cargo_one_full" + _flooring = /decl/flooring/tiling/new_tile/cargo_one + +/turf/floor/tiled/kafel_full + name = "floor" + icon_state = "kafel_full" + _flooring = /decl/flooring/tiling/new_tile/kafel + +/turf/floor/tiled/stone + name = "stone slab floor" + icon_state = "stone" + _flooring = /decl/flooring/tiling/stone + color = /decl/flooring/tiling/stone::color + +/turf/floor/tiled/techfloor/grid + name = "floor" + icon_state = "techfloor_grid" + _flooring = /decl/flooring/tiling/tech/grid + +/turf/floor/tiled/techfloor/grid/cryo + initial_gas = list(/decl/material/gas/nitrogen = MOLES_CELLSTANDARD) + temperature = -200 CELSIUS + +/turf/floor/tiled/airless + name = "airless floor" + initial_gas = null + temperature = TCMB + +/turf/floor/tiled/airless/broken + _floor_broken = TRUE + +/turf/floor/tiled/airless/broken/Initialize() + . = ..() + var/setting_broken = _floor_broken + _floor_broken = null + set_floor_broken(setting_broken) diff --git a/code/game/turfs/floors/subtypes/floor_wood.dm b/code/game/turfs/floors/subtypes/floor_wood.dm new file mode 100644 index 000000000000..c2d1dcb87500 --- /dev/null +++ b/code/game/turfs/floors/subtypes/floor_wood.dm @@ -0,0 +1,114 @@ +/turf/floor/wood + name = "wooden floor" + icon = 'icons/turf/flooring/wood.dmi' + icon_state = "wood0" + color = /decl/material/solid/organic/wood/oak::color + _flooring = /decl/flooring/wood + +#define WOOD_FLOOR_SUBTYPE(BASE, WOOD) \ +/turf/floor/##BASE/##WOOD { \ + color = /decl/material/solid/organic/wood/##WOOD::color; \ + _flooring = /decl/flooring/##BASE/##WOOD; \ +} + +/turf/floor/wood/broken + icon_state = "wood_broken0" + _floor_broken = TRUE + +/turf/floor/wood/broken/Initialize() + . = ..() + var/setting_broken = _floor_broken + _floor_broken = null + set_floor_broken(setting_broken) + +/turf/floor/wood/broken/one + icon_state = "wood_broken1" + _floor_broken = "broken1" + +/turf/floor/wood/broken/two + icon_state = "wood_broken2" + _floor_broken = "broken2" + +/turf/floor/wood/broken/three + icon_state = "wood_broken3" + _floor_broken = "broken3" + +/turf/floor/wood/broken/four + icon_state = "wood_broken4" + _floor_broken = "broken4" + +WOOD_FLOOR_SUBTYPE(wood, mahogany) +WOOD_FLOOR_SUBTYPE(wood, maple) +WOOD_FLOOR_SUBTYPE(wood, ebony) +WOOD_FLOOR_SUBTYPE(wood, walnut) +WOOD_FLOOR_SUBTYPE(wood, bamboo) +WOOD_FLOOR_SUBTYPE(wood, yew) + +// Rough wood floors; lower skill requirement, more wasteful to craft. +/turf/floor/wood/rough + name = "rough-hewn wooden floor" + icon = 'icons/turf/flooring/wood_alt.dmi' + icon_state = "wood_peasant0" + color = /decl/material/solid/organic/wood/oak::color + _flooring = /decl/flooring/wood + +WOOD_FLOOR_SUBTYPE(wood/rough, mahogany) +WOOD_FLOOR_SUBTYPE(wood/rough, maple) +WOOD_FLOOR_SUBTYPE(wood/rough, ebony) +WOOD_FLOOR_SUBTYPE(wood/rough, walnut) +WOOD_FLOOR_SUBTYPE(wood/rough, bamboo) +WOOD_FLOOR_SUBTYPE(wood/rough, yew) + +// Laminate floor; basically identical to wood, but uses older smoother icons. +/turf/floor/laminate + name = "wooden laminate floor" + icon = 'icons/turf/flooring/laminate.dmi' + icon_state = "wood" + color = /decl/material/solid/organic/wood/chipboard::color + _flooring = /decl/flooring/laminate + +/turf/floor/laminate/broken + icon_state = "wood_broken0" + _floor_broken = TRUE + +/turf/floor/laminate/broken/Initialize() + . = ..() + var/setting_broken = _floor_broken + _floor_broken = null + set_floor_broken(setting_broken) + +/turf/floor/laminate/broken/one + icon_state = "wood_broken1" + _floor_broken = "broken1" + +/turf/floor/laminate/broken/two + icon_state = "wood_broken2" + _floor_broken = "broken2" + +/turf/floor/laminate/broken/three + icon_state = "wood_broken3" + _floor_broken = "broken3" + +/turf/floor/laminate/broken/four + icon_state = "wood_broken4" + _floor_broken = "broken4" + +/turf/floor/laminate/mahogany + color = /decl/material/solid/organic/wood/chipboard/mahogany::color + _flooring = /decl/flooring/laminate/mahogany + +/turf/floor/laminate/maple + color = /decl/material/solid/organic/wood/chipboard/maple::color + _flooring = /decl/flooring/laminate/maple + +/turf/floor/laminate/ebony + color = /decl/material/solid/organic/wood/chipboard/ebony::color + _flooring = /decl/flooring/laminate/ebony + +/turf/floor/laminate/walnut + color = /decl/material/solid/organic/wood/chipboard/walnut::color + _flooring = /decl/flooring/laminate/walnut + +/turf/floor/laminate/yew + color = /decl/material/solid/organic/wood/chipboard/yew::color + _flooring = /decl/flooring/laminate/yew diff --git a/code/game/turfs/initialization/combo.dm b/code/game/turfs/initialization/combo.dm new file mode 100644 index 000000000000..ccd8397683db --- /dev/null +++ b/code/game/turfs/initialization/combo.dm @@ -0,0 +1,19 @@ +/// Runs multiple turf initialisers in sequence. +/decl/turf_initializer/combo + abstract_type = /decl/turf_initializer/combo + /// A list of initialisers to run, in sequence. + var/list/initialisers + +/decl/turf_initializer/combo/Initialize() + . = ..() + var/list/new_initialisers = list() + for(var/initialiser in initialisers) + new_initialisers += GET_DECL(initialiser) + initialisers = new_initialisers + ASSERT(length(initialisers)) + +/decl/turf_initializer/combo/InitializeTurf(var/turf/tile) + if(!istype(tile) || !tile.simulated) + return + for(var/decl/turf_initializer/initialiser in initialisers) + initialiser.InitializeTurf(tile) \ No newline at end of file diff --git a/code/game/turfs/initialization/indoors.dm b/code/game/turfs/initialization/indoors.dm new file mode 100644 index 000000000000..594f52716d4a --- /dev/null +++ b/code/game/turfs/initialization/indoors.dm @@ -0,0 +1,94 @@ +// Makes indoor areas dirty and spawns webs in corners. +/decl/turf_initializer/spiderwebs + /// The chance a turf in a corner will attempt to place a web. + var/web_probability = 25 + /// The chance a dormant spiderling will spawn in a placed web. + var/spiderling_probability = 5 + /// The maximum amount of dirt added to a turf. + var/min_base_dirt = 0 + /// The maximum amount of dirt added to a turf. + var/max_base_dirt = 40 + /// The maximum amount of dirt added to each turf per dirty neighbour turf. + var/max_dirt_per_turf = 5 + + +/decl/turf_initializer/spiderwebs/proc/get_dirt_amount() + return rand(min_base_dirt, max_base_dirt) + +/decl/turf_initializer/spiderwebs/InitializeTurf(var/turf/tile) + if(!istype(tile) || tile.density || !tile.simulated) + return + // Quick and dirty check to avoid placing things inside windows + if(locate(/obj/structure/grille, tile)) + return + + var/add_dirt = get_dirt_amount() + // If a neighbor is dirty, then we get dirtier. + var/how_dirty = dirty_neighbors(tile) + for(var/i = 0; i < how_dirty; i++) + add_dirt += rand(0, max_dirt_per_turf) + tile.add_dirt(add_dirt) + + if(prob(web_probability)) // Keep in mind that only "corners" get any sort of web + attempt_web(tile) + +/// Returns the number of cardinally adjacent turfs with at least 25 dirt (halfway to visible) +/decl/turf_initializer/spiderwebs/proc/dirty_neighbors(var/turf/center) + var/how_dirty = 0 + for(var/turf/neighbour in center.CardinalTurfs()) + // Considered dirty if more than halfway to visible dirt + if(neighbour.get_dirt() > 25) + how_dirty++ + return how_dirty + +/decl/turf_initializer/spiderwebs/proc/attempt_web(var/turf/tile) + if(!istype(tile) || !tile.simulated) + return + + var/turf/north_turf = get_step_resolving_mimic(tile, NORTH) + if(!north_turf || !north_turf.density) + return + + for(var/dir in list(WEST, EAST)) // For the sake of efficiency, west wins over east in the case of 1-tile valid spots, rather than doing pick() + var/turf/neighbour = get_step_resolving_mimic(tile, dir) + if(!neighbour || !neighbour.density) + continue + switch(dir) + if(WEST) + new /obj/effect/decal/cleanable/cobweb(tile) + if(EAST) + new /obj/effect/decal/cleanable/cobweb2(tile) + if(prob(spiderling_probability)) + var/obj/effect/spider/spiderling/spiderling = new /obj/effect/spider/spiderling/mundane/dormant(tile) + spiderling.pixel_y = spiderling.shift_range + spiderling.pixel_x = dir == WEST ? -spiderling.shift_range : spiderling.shift_range + break // only place one web + +/// Spawns random 'kitchen' grime near tables: flour spills, smashed eggs, fruit smudges, etc. +/decl/turf_initializer/kitchen + /// The probability of attempting to place clutter for a turf. + var/clutter_probability = 10 + /// Clutter types to pick from when placing clutter on a turf. + var/list/clutter = list( + /obj/effect/decal/cleanable/flour, + /obj/effect/decal/cleanable/tomato_smudge, + /obj/effect/decal/cleanable/egg_smudge + ) + +/decl/turf_initializer/kitchen/InitializeTurf(var/turf/tile) + if(!istype(tile) || tile.density || !tile.simulated) + return + if(!prob(clutter_probability)) + return + var/adjacent_tables = 0 + for(var/obj/structure/table/table in orange(tile, 1)) + adjacent_tables++ + break + if(!adjacent_tables) + return + if(!prob(adjacent_tables * 25)) // far more likely in table corners with 3 or more tables adjacent + return + var/obj/clutter_to_spawn = pick(clutter) + if(!clutter_to_spawn) + return + new clutter_to_spawn(tile) \ No newline at end of file diff --git a/code/game/turfs/initialization/init.dm b/code/game/turfs/initialization/init.dm index e4246aac5829..1553584fcd6e 100644 --- a/code/game/turfs/initialization/init.dm +++ b/code/game/turfs/initialization/init.dm @@ -4,9 +4,10 @@ /area var/turf_initializer = null -/area/Initialize() +/area/Initialize(mapload) . = ..() - for(var/turf/T in src) - if(turf_initializer) - var/decl/turf_initializer/ti = decls_repository.get_decl(turf_initializer) - ti.InitializeTurf(T) + if(ispath(turf_initializer)) + var/decl/turf_initializer/initializer = GET_DECL(turf_initializer) + // TODO: It may be worth doing a post-mapload loop over turfs instead, to limit the number of in-area (in-world) loops? + for(var/turf/initialized_turf in src) + initializer.InitializeTurf(initialized_turf) diff --git a/code/game/turfs/initialization/maintenance.dm b/code/game/turfs/initialization/maintenance.dm index c76ab78d2809..e859322e0533 100644 --- a/code/game/turfs/initialization/maintenance.dm +++ b/code/game/turfs/initialization/maintenance.dm @@ -14,62 +14,66 @@ vermin_probability = 0 web_probability = 0 -/decl/turf_initializer/maintenance/InitializeTurf(var/turf/simulated/T) - if(!istype(T) || T.density) +/decl/turf_initializer/maintenance/InitializeTurf(var/turf/tile) + if(!istype(tile) || tile.density || !tile.simulated) return // Quick and dirty check to avoid placing things inside windows - if(locate(/obj/structure/grille, T)) + if(locate(/obj/structure/grille, tile)) return - var/cardinal_turfs = T.CardinalTurfs() - - T.dirt = get_dirt_amount() + var/add_dirt = get_dirt_amount() // If a neighbor is dirty, then we get dirtier. - var/how_dirty = dirty_neighbors(cardinal_turfs) + var/how_dirty = dirty_neighbors(tile) for(var/i = 0; i < how_dirty; i++) - T.dirt += rand(0,5) - T.update_dirt() + add_dirt += rand(0,5) + tile.add_dirt(add_dirt) if(prob(oil_probability)) - new /obj/effect/decal/cleanable/blood/oil(T) + new /obj/effect/decal/cleanable/blood/oil(tile) if(prob(clutter_probability)) - var/new_junk = get_random_junk_type() - new new_junk(T) + new /obj/random/junk(tile) if(prob(vermin_probability)) if(prob(80)) - new /mob/living/simple_animal/mouse(T) + new /mob/living/simple_animal/passive/mouse(tile) else - new /mob/living/simple_animal/lizard(T) + new /mob/living/simple_animal/lizard(tile) if(prob(web_probability)) // Keep in mind that only "corners" get any sort of web - attempt_web(T, cardinal_turfs) + attempt_web(tile) -/decl/turf_initializer/maintenance/proc/dirty_neighbors(var/list/cardinal_turfs) +/// Returns the number of cardinally adjacent turfs with at least 25 dirt (halfway to visible) +/decl/turf_initializer/maintenance/proc/dirty_neighbors(var/turf/center) var/how_dirty = 0 - for(var/turf/simulated/T in cardinal_turfs) + for(var/turf/neighbour in center.CardinalTurfs()) // Considered dirty if more than halfway to visible dirt - if(T.dirt > 25) + if(neighbour.get_dirt() > 25) how_dirty++ return how_dirty -/decl/turf_initializer/maintenance/proc/attempt_web(var/turf/simulated/T) - var/turf/north_turf = get_step(T, NORTH) +/decl/turf_initializer/maintenance/proc/attempt_web(var/turf/tile) + + if(!istype(tile) || !tile.simulated) + return + + var/turf/north_turf = get_step(tile, NORTH) if(!north_turf || !north_turf.density) return - for(var/dir in list(WEST, EAST)) // For the sake of efficiency, west wins over east in the case of 1-tile valid spots, rather than doing pick() - var/turf/neighbour = get_step(T, dir) - if(neighbour && neighbour.density) - if(dir == WEST) - new /obj/effect/decal/cleanable/cobweb(T) - if(dir == EAST) - new /obj/effect/decal/cleanable/cobweb2(T) - if(prob(web_probability)) - var/obj/effect/spider/spiderling/spiderling = new /obj/effect/spider/spiderling/mundane/dormant(T) - spiderling.pixel_y = spiderling.shift_range - spiderling.pixel_x = dir == WEST ? -spiderling.shift_range : spiderling.shift_range + for(var/dir in list(WEST, EAST)) // For the sake of efficiency, west wins over east in the case of 1-tile valid spots, rather than doing pick() + var/turf/neighbour = get_step_resolving_mimic(tile, dir) + if(!neighbour || !neighbour.density) + continue + switch(dir) + if(WEST) + new /obj/effect/decal/cleanable/cobweb(tile) + if(EAST) + new /obj/effect/decal/cleanable/cobweb2(tile) + if(prob(web_probability)) + var/obj/effect/spider/spiderling/spiderling = new /obj/effect/spider/spiderling/mundane/dormant(tile) + spiderling.pixel_y = spiderling.shift_range + spiderling.pixel_x = dir == WEST ? -spiderling.shift_range : spiderling.shift_range /decl/turf_initializer/maintenance/proc/get_dirt_amount() return rand(10, 50) + rand(0, 50) diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm new file mode 100644 index 000000000000..186c84cb2642 --- /dev/null +++ b/code/game/turfs/open/_open.dm @@ -0,0 +1,150 @@ +//////////////////////////////// +// Open space +//////////////////////////////// +/turf/open + name = "open space" + icon = 'icons/turf/space.dmi' + icon_state = "" + density = FALSE + pathweight = 100000 //Seriously, don't try and path over this one numbnuts + z_flags = ZM_MIMIC_DEFAULTS | ZM_MIMIC_OVERWRITE | ZM_MIMIC_NO_AO | ZM_ALLOW_ATMOS + turf_flags = TURF_FLAG_BACKGROUND + initial_gas = GAS_STANDARD_AIRMIX + zone_membership_candidate = TRUE + +/turf/open/Initialize(mapload, ...) + . = ..() + if(!mapload) + for(var/direction in global.alldirs) + var/turf/target_turf = get_step_resolving_mimic(src, direction) + if(istype(target_turf)) + if(TICK_CHECK) // not CHECK_TICK -- only queue if the server is overloaded + target_turf.queue_icon_update() + else + target_turf.update_icon() + +/turf/open/flooded + name = "open water" + flooded = /decl/material/liquid/water + +/turf/open/flooded/salt + name = "open saltwater" // alt. ver: open ocean? + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water, NOT 10% salt + +/turf/open/Entered(var/atom/movable/mover, var/atom/oldloc) + ..() + mover.fall(oldloc) + +// Called when thrown object lands on this turf. +/turf/open/hitby(var/atom/movable/AM) + . = ..() + if(!QDELETED(AM)) + AM.fall() + +/turf/open/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 2) + var/depth = 1 + for(var/turf/T = GetBelow(src); (istype(T) && T.is_open()); T = GetBelow(T)) + depth += 1 + . += "It is about [depth] level\s deep." + +/turf/open/is_open() + return TRUE + +/turf/open/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/stack/material/rods)) + var/ladder = (locate(/obj/structure/ladder) in src) + if(ladder) + to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) + return TRUE + var/obj/structure/lattice/lattice = locate(/obj/structure/lattice, src) + if(lattice) + return lattice.attackby(used_item, user) + var/obj/item/stack/material/rods/rods = used_item + if (rods.use(1)) + to_chat(user, SPAN_NOTICE("You lay down the support lattice.")) + playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) + new /obj/structure/lattice(src, rods.material.type) + return TRUE + + if (istype(used_item, /obj/item/stack/tile)) + var/obj/item/stack/tile/tile = used_item + tile.try_build_turf(user, src) + return TRUE + + //To lay cable. + if(IS_COIL(used_item) && try_build_cable(used_item, user)) + return TRUE + + for(var/atom/movable/M in below) + if(M.movable_flags & MOVABLE_FLAG_Z_INTERACT) + return M.attackby(used_item, user) + + return FALSE + +/turf/open/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + for(var/atom/movable/M in below) + if(M.movable_flags & MOVABLE_FLAG_Z_INTERACT) + return M.attack_hand_with_interaction_checks(user) + return FALSE + +//Most things use is_plating to test if there is a cover tile on top (like regular floors) +/turf/open/is_plating() + return TRUE + +/turf/open/cannot_build_cable() + return 0 + +/turf/open/drill_act() + SHOULD_CALL_PARENT(FALSE) + var/turf/T = GetBelow(src) + if(istype(T)) + T.drill_act() + +/turf/open/airless + initial_gas = null + +/decl/interaction_handler/dig_ramp_from_above + name = "Dig Ramp From Above" + expected_target_type = /turf/open + examine_desc = "dig a ramp in the direction you are facing, one level down" + +/decl/interaction_handler/dig_ramp_from_above/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + // TODO: check for blocking floors etc. + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + if(!IS_PICK(prop) && !IS_SHOVEL(prop)) + return FALSE + var/turf/turf = get_turf(target) + if(!istype(turf) || !turf.is_open() || !HasBelow(turf.z)) + return FALSE + var/turf/wall/natural/wall = GetBelow(target) + if(!istype(wall)) + return FALSE + if(!user.Adjacent(target)) + return FALSE + return TRUE + +/decl/interaction_handler/dig_ramp_from_above/invoked(atom/target, mob/user, obj/item/prop) + var/turf/wall/natural/wall = GetBelow(target) + var/user_dir = get_dir(user, target) // opposite of regular wall carving as we are going downwards + if(!(user_dir in global.cardinal)) + to_chat(user, SPAN_WARNING("You must be standing at a cardinal angle to create a ramp.")) + return FALSE + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + if(wall.material?.hardness > prop?.material?.hardness) + to_chat(user, SPAN_WARNING("Your [prop.name] is not hard enough to cut into \the [wall].")) + return FALSE + var/turf/wall/natural/support = get_step(wall, global.reverse_dir[user_dir]) + if(!istype(support) || support.ramp_slope_direction) + to_chat(user, SPAN_WARNING("You cannot cut a ramp into a wall with no additional walls behind it.")) + return FALSE + if(prop.do_tool_interaction((IS_PICK(prop) ? TOOL_PICK : TOOL_SHOVEL), user, wall, 3 SECONDS, suffix_message = ", forming it into a ramp") && !wall.ramp_slope_direction) + wall.make_ramp(user, user_dir) + return TRUE + return FALSE diff --git a/code/game/turfs/open/open_sky.dm b/code/game/turfs/open/open_sky.dm new file mode 100644 index 000000000000..74dd2d6c05e9 --- /dev/null +++ b/code/game/turfs/open/open_sky.dm @@ -0,0 +1,69 @@ +/turf/open/sky + name = "sky" + desc = "Hope you don't have a fear of heights..." + icon = 'icons/turf/flooring/sky_static.dmi' + icon_state = "0" + z_flags = 0 + +/turf/open/sky/north + dir = NORTH + +/turf/open/sky/south + dir = SOUTH + +/turf/open/sky/west + dir = WEST + +/turf/open/sky/east + dir = EAST + +/turf/open/sky/moving + icon = 'icons/turf/flooring/sky_slow.dmi' + +/turf/open/sky/moving/north + dir = NORTH + +/turf/open/sky/moving/south + dir = SOUTH + +/turf/open/sky/moving/west + dir = WEST + +/turf/open/sky/moving/east + dir = EAST + +// For planetary skyboxes/shuttle transit areas. +/turf/unsimulated/sky + name = "sky" + desc = "Hope you don't have a fear of heights..." + icon = 'icons/turf/flooring/sky_static.dmi' + icon_state = "0" + z_flags = 0 + dynamic_lighting = FALSE // TODO: put the arrivals shuttle on a level with ambient lighting so the sky can reflect daytime. + +/turf/unsimulated/sky/north + dir = NORTH + +/turf/unsimulated/sky/south + dir = SOUTH + +/turf/unsimulated/sky/west + dir = WEST + +/turf/unsimulated/sky/east + dir = EAST + +/turf/unsimulated/sky/moving + icon = 'icons/turf/flooring/sky_slow.dmi' + +/turf/unsimulated/sky/moving/north + dir = NORTH + +/turf/unsimulated/sky/moving/south + dir = SOUTH + +/turf/unsimulated/sky/moving/west + dir = WEST + +/turf/unsimulated/sky/moving/east + dir = EAST diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm deleted file mode 100644 index 92c5eccc57f3..000000000000 --- a/code/game/turfs/simulated.dm +++ /dev/null @@ -1,174 +0,0 @@ -/turf/simulated - name = "station" - initial_gas = list(/decl/material/gas/oxygen = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) - var/wet = 0 - var/image/wet_overlay = null - var/has_resources //Mining resources (for the large drills). - var/list/resources - var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed - var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to - var/dirt = 0 - var/timer_id - -// This is not great. -/turf/simulated/proc/wet_floor(var/wet_val = 1, var/overwrite = FALSE) - if(wet_val < wet && !overwrite) - return - - if(!wet) - wet = wet_val - wet_overlay = image('icons/effects/water.dmi',src,"wet_floor") - overlays += wet_overlay - - timer_id = addtimer(CALLBACK(src,/turf/simulated/proc/unwet_floor),8 SECONDS, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) - -/turf/simulated/proc/unwet_floor(var/check_very_wet = TRUE) - if(check_very_wet && wet >= 2) - wet-- - timer_id = addtimer(CALLBACK(src,/turf/simulated/proc/unwet_floor), 8 SECONDS, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) - return - - wet = 0 - if(wet_overlay) - overlays -= wet_overlay - wet_overlay = null - -/turf/simulated/clean_blood() - for(var/obj/effect/decal/cleanable/blood/B in contents) - B.clean_blood() - ..() - -/turf/simulated/Initialize() - . = ..() - if(istype(loc, /area/chapel)) - holy = 1 - levelupdate() - -/turf/simulated/proc/AddTracks(var/typepath,var/bloodDNA,var/comingdir,var/goingdir,var/bloodcolor=COLOR_BLOOD_HUMAN) - var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src - if(!tracks) - tracks = new typepath(src) - tracks.AddTracks(bloodDNA,comingdir,goingdir,bloodcolor) - -/turf/simulated/proc/update_dirt() - dirt = min(dirt+0.5, 101) - var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) - if (dirt > 50) - if (!dirtoverlay) - dirtoverlay = new/obj/effect/decal/cleanable/dirt(src) - dirtoverlay.alpha = min((dirt - 50) * 5, 255) - -/turf/simulated/remove_cleanables() - dirt = 0 - . = ..() - -/turf/simulated/Entered(atom/A, atom/OL) - . = ..() - if (istype(A,/mob/living)) - var/mob/living/M = A - - // Dirt overlays. - update_dirt() - - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - // Tracking blood - var/list/bloodDNA = null - var/bloodcolor="" - if(H.shoes) - var/obj/item/clothing/shoes/S = H.shoes - if(istype(S)) - S.handle_movement(src, MOVING_QUICKLY(H)) - if(S.track_blood && S.blood_DNA) - bloodDNA = S.blood_DNA - bloodcolor = S.blood_color - S.track_blood-- - else - if(H.track_blood && H.feet_blood_DNA) - bloodDNA = H.feet_blood_DNA - bloodcolor = H.feet_blood_color - H.track_blood-- - - if (bloodDNA && H.species.get_move_trail(H)) - src.AddTracks(H.species.get_move_trail(H),bloodDNA,H.dir,0,bloodcolor) // Coming - var/turf/simulated/from = get_step(H, GLOB.reverse_dir[H.dir]) - if(istype(from) && from) - from.AddTracks(H.species.get_move_trail(H),bloodDNA,0,H.dir,bloodcolor) // Going - - bloodDNA = null - - if(M.lying) - return - - if(src.wet) - - if(M.buckled || (MOVING_DELIBERATELY(M) && prob(min(100, 100/(wet/10))) ) ) - return - - // skillcheck for slipping - if(!prob(min(100, M.skill_fail_chance(SKILL_HAULING, 100, SKILL_MAX+1)/(3/wet)))) - return - - var/slip_dist = 1 - var/slip_stun = 6 - var/floor_type = "wet" - - if(2 <= src.wet) // Lube - floor_type = "slippery" - slip_dist = 4 - slip_stun = 10 - - if(M.slip("the [floor_type] floor", slip_stun)) - for(var/i = 1 to slip_dist) - step(M, M.dir) - sleep(1) - -//returns 1 if made bloody, returns 0 otherwise -/turf/simulated/add_blood(mob/living/carbon/human/M) - if (!..()) - return 0 - - if(istype(M)) - for(var/obj/effect/decal/cleanable/blood/B in contents) - if(!B.blood_DNA) - B.blood_DNA = list() - if(!B.blood_DNA[M.dna.unique_enzymes]) - B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - var/datum/extension/forensic_evidence/forensics = get_or_create_extension(B, /datum/extension/forensic_evidence) - forensics.add_data(/datum/forensics/blood_dna, M.dna.unique_enzymes) - return 1 //we bloodied the floor - blood_splatter(src, M, 1) - return 1 //we bloodied the floor - return 0 - -// Only adds blood on the floor -- Skie -/turf/simulated/proc/add_blood_floor(mob/living/carbon/M) - if( istype(M, /mob/living/carbon/alien )) - var/obj/effect/decal/cleanable/blood/xeno/this = new /obj/effect/decal/cleanable/blood/xeno(src) - this.blood_DNA["UNKNOWN BLOOD"] = "X*" - else if( istype(M, /mob/living/silicon/robot )) - new /obj/effect/decal/cleanable/blood/oil(src) - -/turf/simulated/proc/can_build_cable(var/mob/user) - return 0 - -/turf/simulated/attackby(var/obj/item/thing, var/mob/user) - if(isCoil(thing) && can_build_cable(user)) - var/obj/item/stack/cable_coil/coil = thing - coil.turf_place(src, user) - return TRUE - return ..() - -/turf/simulated/Initialize() - if(GAME_STATE >= RUNLEVEL_GAME) - fluid_update() - . = ..() - -/turf/simulated/Destroy() - if (zone) - if (can_safely_remove_from_zone()) - c_copy_air() - zone.remove(src) - else - zone.rebuild() - . = ..() \ No newline at end of file diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm deleted file mode 100644 index ae29604bf219..000000000000 --- a/code/game/turfs/simulated/floor.dm +++ /dev/null @@ -1,98 +0,0 @@ -/turf/simulated/floor - name = "plating" - icon = 'icons/turf/flooring/plating.dmi' - icon_state = "plating" - permit_ao = TRUE - thermal_conductivity = 0.040 - heat_capacity = 10000 - explosion_resistance = 1 - - // Damage to flooring. - var/broken - var/burnt - // Plating data. - var/base_name = "plating" - var/base_desc = "The naked hull." - var/base_icon = 'icons/turf/flooring/plating.dmi' - var/base_icon_state = "plating" - var/base_color = COLOR_WHITE - // Flooring data. - var/flooring_override - var/initial_flooring - var/decl/flooring/flooring - var/mineral = DEFAULT_WALL_MATERIAL - var/lava = 0 - -/turf/simulated/floor/is_plating() - return !flooring - -/turf/simulated/floor/protects_atom(var/atom/A) - return (A.level <= 1 && !is_plating()) || ..() - -/turf/simulated/floor/Initialize(var/ml, var/floortype) - . = ..(ml) - if(!floortype && initial_flooring) - floortype = initial_flooring - if(floortype) - set_flooring(decls_repository.get_decl(floortype)) - -/turf/simulated/floor/proc/set_flooring(var/decl/flooring/newflooring) - make_plating(defer_icon_update = 1) - flooring = newflooring - update_icon(1) - levelupdate() - -//This proc will set floor_type to null and the update_icon() proc will then change the icon_state of the turf -//This proc auto corrects the grass tiles' siding. -/turf/simulated/floor/proc/make_plating(var/place_product, var/defer_icon_update) - - overlays.Cut() - - for(var/obj/effect/decal/writing/W in src) - qdel(W) - - SetName(base_name) - desc = base_desc - icon = base_icon - icon_state = base_icon_state - color = base_color - layer = PLATING_LAYER - - if(flooring) - flooring.on_remove() - if(flooring.build_type && place_product) - new flooring.build_type(src) - flooring = null - - set_light(0) - broken = null - burnt = null - flooring_override = null - levelupdate() - - if(!defer_icon_update) - update_icon(1) - -/turf/simulated/floor/levelupdate() - for(var/obj/O in src) - O.hide(O.hides_under_flooring() && src.flooring) - - if(flooring) - layer = TURF_LAYER - else - layer = PLATING_LAYER - -/turf/simulated/floor/can_engrave() - return (!flooring || flooring.can_engrave) - -/turf/simulated/floor/shuttle_ceiling - name = "hull plating" - icon = 'icons/turf/flooring/tiles.dmi' - icon_state = "reinforced_light" - initial_gas = null - -/turf/simulated/floor/shuttle_ceiling/air - initial_gas = list(/decl/material/gas/oxygen = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) - -/turf/simulated/floor/is_floor() - return TRUE \ No newline at end of file diff --git a/code/game/turfs/simulated/floor_acts.dm b/code/game/turfs/simulated/floor_acts.dm deleted file mode 100644 index 54fab9d0b15a..000000000000 --- a/code/game/turfs/simulated/floor_acts.dm +++ /dev/null @@ -1,44 +0,0 @@ -/turf/simulated/floor/explosion_act(severity) - SHOULD_CALL_PARENT(FALSE) - if(severity == 1) - ChangeTurf(get_base_turf_by_area(src)) - else if(severity == 2) - switch(pick(40;1,40;2,3)) - if (1) - if(prob(33)) - new /obj/item/stack/material/steel(src) - ReplaceWithLattice() - if(2) - ChangeTurf(get_base_turf_by_area(src)) - if(3) - if(prob(33)) - new /obj/item/stack/material/steel(src) - if(prob(80)) - break_tile_to_plating() - else - break_tile() - hotspot_expose(1000,CELL_VOLUME) - else if(severity == 3 && prob(50)) - break_tile() - hotspot_expose(1000,CELL_VOLUME) - -/turf/simulated/floor/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - - var/temp_destroy = get_damage_temperature() - if(!burnt && prob(5)) - burn_tile(exposed_temperature) - else if(temp_destroy && exposed_temperature >= (temp_destroy + 100) && prob(1) && !is_plating()) - make_plating() //destroy the tile, exposing plating - burn_tile(exposed_temperature) - return - -//should be a little bit lower than the temperature required to destroy the material -/turf/simulated/floor/proc/get_damage_temperature() - return flooring ? flooring.damage_temperature : null - -/turf/simulated/floor/adjacent_fire_act(turf/simulated/floor/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) - var/dir_to = get_dir(src, adj_turf) - - for(var/obj/structure/window/W in src) - if(W.dir == dir_to || W.is_fulltile()) //Same direction or diagonal (full tile) - W.fire_act(adj_air, adj_temp, adj_volume) diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm deleted file mode 100644 index 343068268d23..000000000000 --- a/code/game/turfs/simulated/floor_attackby.dm +++ /dev/null @@ -1,167 +0,0 @@ -/turf/simulated/floor/attack_hand(mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/hand = H.hand ? H.organs_by_name[BP_L_HAND] : H.organs_by_name[BP_R_HAND] - if(hand && try_graffiti(H, hand)) - return TRUE - . = ..() - -/turf/simulated/floor/attackby(var/obj/item/C, var/mob/user) - - if(!C || !user) - return 0 - - if(isCoil(C) || (flooring && istype(C, /obj/item/stack/material/rods))) - return ..(C, user) - - if(!(isScrewdriver(C) && flooring && (flooring.flags & TURF_REMOVE_SCREWDRIVER)) && try_graffiti(user, C)) - return TRUE - - if(flooring) - if(isCrowbar(C) && user.a_intent != I_HURT) - if(broken || burnt) - to_chat(user, "You remove the broken [flooring.descriptor].") - make_plating() - else if(flooring.flags & TURF_IS_FRAGILE) - to_chat(user, "You forcefully pry off the [flooring.descriptor], destroying them in the process.") - make_plating() - else if(flooring.flags & TURF_REMOVE_CROWBAR) - if(user.do_skilled(0.5, SKILL_CONSTRUCTION, src, 10)) - if(!flooring) return - to_chat(user, "You lever off the [flooring.descriptor].") - make_plating(1) - else - return 0 - else - return - playsound(src, 'sound/items/Crowbar.ogg', 80, 1) - return TRUE - else if(isScrewdriver(C) && (flooring.flags & TURF_REMOVE_SCREWDRIVER)) - if(broken || burnt) - return - to_chat(user, "You unscrew and remove the [flooring.descriptor].") - make_plating(1) - playsound(src, 'sound/items/Screwdriver.ogg', 80, 1) - return TRUE - else if(isWrench(C) && (flooring.flags & TURF_REMOVE_WRENCH)) - to_chat(user, "You unwrench and remove the [flooring.descriptor].") - make_plating(1) - playsound(src, 'sound/items/Ratchet.ogg', 80, 1) - return TRUE - else if(istype(C, /obj/item/shovel) && (flooring.flags & TURF_REMOVE_SHOVEL)) - to_chat(user, "You shovel off the [flooring.descriptor].") - make_plating(1) - playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) - return TRUE - else if(isCoil(C)) - to_chat(user, "You must remove the [flooring.descriptor] first.") - return TRUE - else - - if(istype(C, /obj/item/stack)) - if(broken || burnt) - to_chat(user, "This section is too damaged to support anything. Use a welder to fix the damage.") - return TRUE - //first check, catwalk? Else let flooring do its thing - if(locate(/obj/structure/catwalk, src)) - return - if (istype(C, /obj/item/stack/material/rods)) - var/obj/item/stack/material/rods/R = C - if (R.use(2)) - playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - new /obj/structure/catwalk(src, R.material.type) - return TRUE - return - var/obj/item/stack/S = C - var/decl/flooring/use_flooring - var/list/decls = decls_repository.get_decls_of_subtype(/decl/flooring) - for(var/flooring_type in decls) - var/decl/flooring/F = decls[flooring_type] - if(!F.build_type) - continue - if(ispath(S.type, F.build_type) || ispath(S.build_type, F.build_type)) - use_flooring = F - break - if(!use_flooring) - return - // Do we have enough? - if(use_flooring.build_cost && S.get_amount() < use_flooring.build_cost) - to_chat(user, "You require at least [use_flooring.build_cost] [S.name] to complete the [use_flooring.descriptor].") - return TRUE - // Stay still and focus... - if(use_flooring.build_time && !do_after(user, use_flooring.build_time, src)) - return TRUE - if(flooring || !S || !user || !use_flooring) - return TRUE - if(S.use(use_flooring.build_cost)) - set_flooring(use_flooring) - playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) - return TRUE - // Repairs and Deconstruction. - else if(isCrowbar(C)) - if(broken || burnt) - playsound(src, 'sound/items/Crowbar.ogg', 80, 1) - visible_message("[user] has begun prying off the damaged plating.") - . = TRUE - var/turf/T = GetBelow(src) - if(T) - T.visible_message("The ceiling above looks as if it's being pried off.") - if(do_after(user, 10 SECONDS)) - if(!broken && !burnt || !(is_plating()))return - visible_message("[user] has pried off the damaged plating.") - new /obj/item/stack/tile/floor(src) - src.ReplaceWithLattice() - playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) - if(T) - T.visible_message("The ceiling above has been pried off!") - return - else if(isWelder(C)) - var/obj/item/weldingtool/welder = C - if(welder.isOn() && (is_plating())) - if(broken || burnt) - if(welder.remove_fuel(0, user)) - to_chat(user, "You fix some dents on the broken plating.") - playsound(src, 'sound/items/Welder.ogg', 80, 1) - icon_state = "plating" - burnt = null - broken = null - return TRUE - else - if(welder.remove_fuel(0, user)) - playsound(src, 'sound/items/Welder.ogg', 80, 1) - visible_message("[user] has started melting the plating's reinforcements!") - . = TRUE - if(do_after(user, 5 SECONDS) && welder.isOn() && welder_melt()) - visible_message("[user] has melted the plating's reinforcements! It should be possible to pry it off.") - playsound(src, 'sound/items/Welder.ogg', 80, 1) - return - else if(istype(C, /obj/item/gun/energy/plasmacutter) && (is_plating()) && !broken && !burnt) - var/obj/item/gun/energy/plasmacutter/cutter = C - if(!cutter.slice(user)) - return ..() - playsound(src, 'sound/items/Welder.ogg', 80, 1) - visible_message("[user] has started slicing through the plating's reinforcements!") - . = TRUE - if(do_after(user, 3 SECONDS) && welder_melt()) - visible_message("[user] has sliced through the plating's reinforcements! It should be possible to pry it off.") - playsound(src, 'sound/items/Welder.ogg', 80, 1) - return - - return ..() - -/turf/simulated/floor/proc/welder_melt() - if(!(is_plating()) || broken || burnt) - return 0 - burnt = 1 - remove_decals() - update_icon() - return 1 - -/turf/simulated/floor/can_build_cable(var/mob/user) - if(!is_plating() || flooring) - to_chat(user, "Removing the tiling first.") - return 0 - if(broken || burnt) - to_chat(user, "This section is too damaged to support anything. Use a welder to fix the damage.") - return 0 - return 1 diff --git a/code/game/turfs/simulated/floor_damage.dm b/code/game/turfs/simulated/floor_damage.dm deleted file mode 100644 index c706a7f995bc..000000000000 --- a/code/game/turfs/simulated/floor_damage.dm +++ /dev/null @@ -1,27 +0,0 @@ -/turf/simulated/floor/proc/gets_drilled() - return - -/turf/simulated/floor/proc/break_tile_to_plating() - if(!is_plating()) - make_plating() - break_tile() - -/turf/simulated/floor/proc/break_tile() - if(!flooring || !(flooring.flags & TURF_CAN_BREAK) || !isnull(broken)) - return - if(flooring.has_damage_range) - broken = rand(0,flooring.has_damage_range) - else - broken = 0 - remove_decals() - update_icon() - -/turf/simulated/floor/proc/burn_tile(var/exposed_temperature) - if(!flooring || !(flooring.flags & TURF_CAN_BURN) || !isnull(burnt)) - return - if(flooring.has_burn_range) - burnt = rand(0,flooring.has_burn_range) - else - burnt = 0 - remove_decals() - update_icon() \ No newline at end of file diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm deleted file mode 100644 index 00550a983532..000000000000 --- a/code/game/turfs/simulated/floor_icon.dm +++ /dev/null @@ -1,156 +0,0 @@ -var/list/flooring_cache = list() - -/turf/simulated/floor/on_update_icon(var/update_neighbors) - - . = ..() - cut_overlays() - if(lava) - return - - var/has_smooth = 0 //This is just the has_border bitfield inverted for easier logic - - if(flooring) - // Set initial icon and strings. - SetName(flooring.name) - desc = flooring.desc - icon = flooring.icon - color = flooring.color - - if(flooring_override) - icon_state = flooring_override - else - icon_state = flooring.icon_base - if(flooring.has_base_range) - icon_state = "[icon_state][rand(0,flooring.has_base_range)]" - flooring_override = icon_state - - // Apply edges, corners, and inner corners. - var/has_border = 0 - //Check the cardinal turfs - for(var/step_dir in GLOB.cardinal) - var/turf/simulated/floor/T = get_step(src, step_dir) - var/is_linked = flooring.symmetric_test_link(src, T) - - //Alright we've figured out whether or not we smooth with this turf - if (!is_linked) - has_border |= step_dir - - //Now, if we don't, then lets add a border - add_overlay(get_flooring_overlay("[flooring.icon]_[flooring.icon_base]-edge-[step_dir]", "[flooring.icon_base]_edges", step_dir, (flooring.flags & TURF_HAS_EDGES))) - - has_smooth = ~(has_border & (NORTH | SOUTH | EAST | WEST)) - - if(flooring.can_paint && decals && decals.len) - add_overlay(decals) - - //We can only have inner corners if we're smoothed with something - if (has_smooth && flooring.flags & TURF_HAS_INNER_CORNERS) - for(var/direction in GLOB.cornerdirs) - if((has_smooth & direction) == direction) - if(!flooring.symmetric_test_link(src, get_step(src, direction))) - add_overlay(get_flooring_overlay("[flooring.icon]_[flooring.icon_base]-corner-[direction]", "[flooring.icon_base]_corners", direction)) - - //Next up, outer corners - if (has_border && flooring.flags & TURF_HAS_CORNERS) - for(var/direction in GLOB.cornerdirs) - if((has_border & direction) == direction) - if(!flooring.symmetric_test_link(src, get_step(src, direction))) - add_overlay(get_flooring_overlay("[flooring.icon]_[flooring.icon_base]-edge-[direction]", "[flooring.icon_base]_edges", direction,(flooring.flags & TURF_HAS_EDGES))) - - if(decals && decals.len) - for(var/image/I in decals) - if(I.layer != DECAL_PLATING_LAYER) - continue - add_overlay(I) - - if(is_plating() && !(isnull(broken) && isnull(burnt))) //temp, todo - icon = 'icons/turf/flooring/plating.dmi' - icon_state = "dmg[rand(1,4)]" - else if(flooring) - if(!isnull(broken) && (flooring.flags & TURF_CAN_BREAK)) - add_overlay(get_damage_overlay("broken[broken]", BLEND_MULTIPLY)) - if(!isnull(burnt) && (flooring.flags & TURF_CAN_BURN)) - add_overlay(get_damage_overlay("burned[burnt]")) - - if(update_neighbors) - for(var/turf/simulated/floor/F in orange(src, 1)) - F.queue_ao(FALSE) - F.update_icon() - -/turf/simulated/floor/proc/get_flooring_overlay(var/cache_key, var/icon_base, var/icon_dir = 0, var/external = FALSE) - if(!flooring_cache[cache_key]) - var/image/I = image(icon = flooring.icon, icon_state = icon_base, dir = icon_dir) - - //External overlays will be offset out of this tile - if (external) - if (icon_dir & NORTH) - I.pixel_y = world.icon_size - else if (icon_dir & SOUTH) - I.pixel_y = -world.icon_size - - if (icon_dir & WEST) - I.pixel_x = -world.icon_size - else if (icon_dir & EAST) - I.pixel_x = world.icon_size - I.layer = flooring.decal_layer - - flooring_cache[cache_key] = I - return flooring_cache[cache_key] - -/turf/simulated/floor/proc/get_damage_overlay(var/cache_key, var/blend) - if(!flooring_cache[cache_key]) - var/image/I = image(icon = 'icons/turf/flooring/damage.dmi', icon_state = cache_key) - if(blend) - I.blend_mode = blend - I.layer = DECAL_LAYER - flooring_cache[cache_key] = I - return flooring_cache[cache_key] - -/decl/flooring/proc/test_link(var/turf/origin, var/turf/T) - var/is_linked = FALSE - //is_wall is true for wall turfs and for floors containing a low wall - if(T.is_wall()) - if(wall_smooth == SMOOTH_ALL) - is_linked = TRUE - - //If is_hole is true, then it's space or openspace - else if(T.is_open()) - if(space_smooth == SMOOTH_ALL) - is_linked = TRUE - - - //If we get here then its a normal floor - else if (T.is_floor()) - var/turf/simulated/floor/t = T - - //Check for window frames. - if(wall_smooth == SMOOTH_ALL) - for(var/obj/structure/wall_frame/WF in T.contents) - is_linked = TRUE - - //If the floor is the same as us,then we're linked, - if (istype(src, t.flooring)) - is_linked = TRUE - else if (floor_smooth == SMOOTH_ALL) - is_linked = TRUE - - else if (floor_smooth != SMOOTH_NONE) - - //If we get here it must be using a whitelist or blacklist - if (floor_smooth == SMOOTH_WHITELIST) - for (var/v in flooring_whitelist) - if (istype(t.flooring, v)) - //Found a match on the list - is_linked = TRUE - break - else if(floor_smooth == SMOOTH_BLACKLIST) - is_linked = TRUE //Default to true for the blacklist, then make it false if a match comes up - for (var/v in flooring_whitelist) - if (istype(t.flooring, v)) - //Found a match on the list - is_linked = FALSE - break - return is_linked - -/decl/flooring/proc/symmetric_test_link(var/turf/A, var/turf/B) - return test_link(A, B) && test_link(B,A) diff --git a/code/game/turfs/simulated/floor_static.dm b/code/game/turfs/simulated/floor_static.dm deleted file mode 100644 index a9daa17c2d12..000000000000 --- a/code/game/turfs/simulated/floor_static.dm +++ /dev/null @@ -1,56 +0,0 @@ -// This type of flooring cannot be altered short of being destroyed and rebuilt. -// Use this to bypass the flooring system entirely ie. event areas, holodeck, etc. - -/turf/simulated/floor/fixed - name = "floor" - icon = 'icons/turf/flooring/tiles.dmi' - icon_state = "steel" - initial_flooring = null - footstep_type = /decl/footsteps/plating - -/turf/simulated/floor/fixed/attackby(var/obj/item/C, var/mob/user) - if(istype(C, /obj/item/stack) && !isCoil(C)) - return - return ..() - -/turf/simulated/floor/fixed/on_update_icon() - update_flood_overlay() - -/turf/simulated/floor/fixed/is_plating() - return 0 - -/turf/simulated/floor/fixed/set_flooring() - return - -/turf/simulated/floor/fixed/alium - name = "alien plating" - desc = "This obviously wasn't made for your feet." - icon = 'icons/turf/flooring/alium.dmi' - icon_state = "jaggy" - -/turf/simulated/floor/fixed/alium/attackby(var/obj/item/C, var/mob/user) - if(isCrowbar(C)) - to_chat(user, "There aren't any openings big enough to pry it away...") - return TRUE - return ..() - -/turf/simulated/floor/fixed/alium/Initialize() - . = ..() - var/decl/material/A = decls_repository.get_decl(/decl/material/solid/metal/aliumium) - if(!A) - return - color = A.color - var/style = A.hardness % 2 ? "curvy" : "jaggy" - icon_state = "[style][(x*y) % 7]" - -/turf/simulated/floor/fixed/alium/airless - initial_gas = null - temperature = TCMB - -/turf/simulated/floor/fixed/alium/explosion_act(severity) - SHOULD_CALL_PARENT(FALSE) - var/decl/material/A = decls_repository.get_decl(/decl/material/solid/metal/aliumium) - if(prob(A.explosion_resistance)) - return - if(severity == 1) - ChangeTurf(get_base_turf_by_area(src)) diff --git a/code/game/turfs/simulated/footsteps.dm b/code/game/turfs/simulated/footsteps.dm deleted file mode 100644 index 0f5e7cbc709d..000000000000 --- a/code/game/turfs/simulated/footsteps.dm +++ /dev/null @@ -1,71 +0,0 @@ -/proc/get_footstep(var/footstep_type, var/mob/caller) - . = caller && caller.get_footstep(footstep_type) - if(!.) - var/decl/footsteps/FS = decls_repository.get_decl(footstep_type) - . = pick(FS.footstep_sounds) - -/turf/simulated/proc/get_footstep_sound(var/mob/caller) - for(var/obj/structure/S in contents) - if(S.footstep_type) - return get_footstep(S.footstep_type, caller) - - if(check_fluid_depth(10) && !is_flooded(TRUE)) - return get_footstep(/decl/footsteps/water, caller) - - if(footstep_type) - return get_footstep(footstep_type, caller) - - if(is_plating()) - return get_footstep(/decl/footsteps/plating, caller) - -/turf/simulated/floor/get_footstep_sound(var/mob/caller) - . = ..() - if(!.) - if(!flooring || !flooring.footstep_type) - return get_footstep(/decl/footsteps/blank, caller) - else - return get_footstep(flooring.footstep_type, caller) - -/turf/simulated/Entered(var/mob/living/carbon/human/H) - ..() - if(istype(H)) - H.handle_footsteps() - H.step_count++ - -/mob/living/carbon/human/proc/has_footsteps() - if(species.silent_steps || buckled || lying || throwing) - return //people flying, lying down or sitting do not step - - if(shoes && (shoes.item_flags & ITEM_FLAG_SILENT)) - return // quiet shoes - - if(!has_organ(BP_L_FOOT) && !has_organ(BP_R_FOOT)) - return //no feet no footsteps - - return TRUE - -/mob/living/carbon/human/proc/handle_footsteps() - if(!has_footsteps()) - return - - //every other turf makes a sound - if((step_count % 2) && !MOVING_DELIBERATELY(src)) - return - - // don't need to step as often when you hop around - if((step_count % 3) && !has_gravity()) - return - - var/turf/simulated/T = get_turf(src) - if(istype(T)) - var/footsound = T.get_footstep_sound(src) - if(footsound) - var/range = -(world.view - 2) - var/volume = 70 - if(MOVING_DELIBERATELY(src)) - volume -= 45 - range -= 0.333 - if(!shoes) - volume -= 60 - range -= 0.333 - playsound(T, footsound, volume, 1, range) diff --git a/code/game/turfs/simulated/turf_ocean.dm b/code/game/turfs/simulated/turf_ocean.dm deleted file mode 100644 index 1ac3e97d5758..000000000000 --- a/code/game/turfs/simulated/turf_ocean.dm +++ /dev/null @@ -1,39 +0,0 @@ -/turf/simulated/ocean - name = "sea floor" - desc = "Silty." - icon = 'icons/turf/seafloor.dmi' - icon_state = "seafloor" - density = FALSE - opacity = FALSE - flooded = TRUE - var/detail_decal - -/turf/simulated/ocean/abyss - name = "abyssal silt" - desc = "Unfathomably silty." - icon_state = "mud_light" - -/turf/simulated/ocean/open - name = "open ocean" - icon_state = "still" - -/turf/simulated/ocean/open/add_decal() - return 0 - -/turf/simulated/ocean/is_plating() - return 1 - -/turf/simulated/ocean/proc/add_decal() - return prob(20) - -/turf/simulated/ocean/Initialize() - . = ..() - if(isnull(detail_decal) && add_decal()) - detail_decal = "asteroid[rand(0,9)]" - update_icon() - -/turf/simulated/ocean/on_update_icon(update_neighbors) - . = ..(update_neighbors) - cut_overlays() - if(detail_decal) - add_overlay(image(icon = 'icons/turf/mining_decals.dmi', icon_state = detail_decal)) diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm deleted file mode 100644 index 840f2da86ac7..000000000000 --- a/code/game/turfs/simulated/wall_attacks.dm +++ /dev/null @@ -1,366 +0,0 @@ -//Interactions -/turf/simulated/wall/proc/toggle_open(var/mob/user) - - if(can_open == WALL_OPENING) - return - - SSradiation.resistance_cache.Remove(src) - - if(density) - can_open = WALL_OPENING - //flick("[material.icon_base]fwall_opening", src) - sleep(15) - set_density(0) - set_opacity(0) - blocks_air = ZONE_BLOCKED - update_icon() - update_air() - set_light(0) - src.blocks_air = 0 - set_opacity(0) - for(var/turf/simulated/turf in loc) - SSair.mark_for_update(turf) - else - can_open = WALL_OPENING - //flick("[material.icon_base]fwall_closing", src) - set_density(1) - set_opacity(1) - blocks_air = AIR_BLOCKED - update_icon() - update_air() - sleep(15) - set_light(0.4, 0.1, 1) - src.blocks_air = 1 - set_opacity(1) - for(var/turf/simulated/turf in loc) - SSair.mark_for_update(turf) - - can_open = WALL_CAN_OPEN - update_icon() - -/turf/simulated/wall/proc/update_air() - if(!SSair) - return - - for(var/turf/simulated/turf in loc) - update_thermal(turf) - SSair.mark_for_update(turf) - - -/turf/simulated/wall/proc/update_thermal(var/turf/simulated/source) - if(istype(source)) - if(density && opacity) - source.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT - else - source.thermal_conductivity = initial(source.thermal_conductivity) - - - -/turf/simulated/wall/proc/fail_smash(var/mob/user) - to_chat(user, "You smash against \the [src]!") - take_damage(rand(25,75)) - -/turf/simulated/wall/proc/success_smash(var/mob/user) - to_chat(user, "You smash through \the [src]!") - user.do_attack_animation(src) - spawn(1) - dismantle_wall(1) - -/turf/simulated/wall/proc/try_touch(var/mob/user, var/rotting) - . = TRUE - if(rotting) - if(reinf_material) - to_chat(user, "\The [reinf_material.solid_name] feels porous and crumbly.") - else - to_chat(user, "\The [material.solid_name] crumbles under your touch!") - dismantle_wall() - return - - if(!can_open) - to_chat(user, "You push \the [src], but nothing happens.") - playsound(src, hitsound, 25, 1) - else - toggle_open(user) - -/turf/simulated/wall/attack_hand(var/mob/user) - radiate() - add_fingerprint(user) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - var/rotting = (locate(/obj/effect/overlay/wallrot) in src) - if (MUTATION_HULK in user.mutations) - if (rotting || !prob(material.hardness)) - success_smash(user) - else - fail_smash(user) - return TRUE - if(ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/hand = H.hand ? H.organs_by_name[BP_L_HAND] : H.organs_by_name[BP_R_HAND] - if(hand && try_graffiti(H, hand)) - return TRUE - . = ..() - if(!.) - return try_touch(user, rotting) - -/turf/simulated/wall/attackby(var/obj/item/W, var/mob/user, click_params) - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - - if(!construction_stage && try_graffiti(user, W)) - return TRUE - - if (!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) - return - - //get the user's location - if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such - - if(W) - radiate() - if(W.get_heat() >= T100C) - burn(W.get_heat()) - - if(locate(/obj/effect/overlay/wallrot) in src) - if(isWelder(W)) - var/obj/item/weldingtool/WT = W - if( WT.remove_fuel(0,user) ) - to_chat(user, "You burn away the fungi with \the [WT].") - playsound(src, 'sound/items/Welder.ogg', 10, 1) - for(var/obj/effect/overlay/wallrot/WR in src) - qdel(WR) - return TRUE - else if(!is_sharp(W) && W.force >= 10 || W.force >= 20) - to_chat(user, "\The [src] crumbles away under the force of your [W.name].") - src.dismantle_wall(1) - return TRUE - - var/turf/T = user.loc //get user's location for delay checks - - if(damage && istype(W, /obj/item/weldingtool)) - - var/obj/item/weldingtool/WT = W - - if(WT.remove_fuel(0,user)) - to_chat(user, "You start repairing the damage to [src].") - playsound(src, 'sound/items/Welder.ogg', 100, 1) - if(do_after(user, max(5, damage / 5), src) && WT && WT.isOn()) - to_chat(user, "You finish repairing the damage to [src].") - take_damage(-damage) - return TRUE - - // Basic dismantling. - if(isnull(construction_stage) || !reinf_material) - - var/cut_delay = 60 - material.cut_delay - var/dismantle_verb - var/dismantle_sound - - if(isWelder(W)) - - if(material && !material.removed_by_welder) - to_chat(user, SPAN_WARNING("\The [src] is too delicate to be dismantled with \the [W]; try a crowbar.")) - return TRUE - - var/obj/item/weldingtool/WT = W - if(!WT.remove_fuel(0,user)) - return - dismantle_verb = "cutting" - dismantle_sound = 'sound/items/Welder.ogg' - cut_delay *= 0.7 - - else if(isCrowbar(W)) - - if(material && material.removed_by_welder) - to_chat(user, SPAN_WARNING("\The [src] is too robust to be dismantled with \the [W]; try a welding tool.")) - return TRUE - - dismantle_verb = "dismantling" - dismantle_sound = 'sound/items/Crowbar.ogg' - cut_delay *= 1.2 - - else if(W.is_special_cutting_tool()) - if(istype(W, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = W - if(!cutter.slice(user)) - return TRUE - dismantle_sound = "sparks" - dismantle_verb = "slicing" - cut_delay *= 0.5 - else if(istype(W,/obj/item/pickaxe)) - var/obj/item/pickaxe/P = W - dismantle_verb = P.drill_verb - dismantle_sound = P.drill_sound - cut_delay -= P.digspeed - - if(dismantle_verb) - . = TRUE - to_chat(user, "You begin [dismantle_verb] through the outer plating.") - if(dismantle_sound) - playsound(src, dismantle_sound, 100, 1) - - if(cut_delay<0) - cut_delay = 0 - - if(!do_after(user,cut_delay,src)) - return - - to_chat(user, "You remove the outer plating.") - dismantle_wall() - user.visible_message("\The [src] was torn open by [user]!") - return - - //Reinforced dismantling. - else - switch(construction_stage) - if(6) - - if(W.is_special_cutting_tool(TRUE)) - - to_chat(user, "You drive \the [W] into the wall and begin trying to rip out the support frame...") - playsound(src, 'sound/items/Welder.ogg', 100, 1) - . = TRUE - - if(!do_after(user, 60, src)) - return - - to_chat(user, "You tear through the wall's support system and plating!") - dismantle_wall() - user.visible_message("The wall was torn open by [user]!") - playsound(src, 'sound/items/Welder.ogg', 100, 1) - - else if(isWirecutter(W)) - playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) - construction_stage = 5 - new /obj/item/stack/material/rods( src ) - to_chat(user, "You cut the outer grille.") - update_icon() - return TRUE - if(5) - if(isScrewdriver(W)) - to_chat(user, "You begin removing the support lines.") - playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) - . = TRUE - if(!do_after(user,40,src) || !istype(src, /turf/simulated/wall) || construction_stage != 5) - return - construction_stage = 4 - update_icon() - to_chat(user, "You remove the support lines.") - return - else if( istype(W, /obj/item/stack/material/rods) ) - var/obj/item/stack/O = W - if(O.use(1)) - construction_stage = 6 - update_icon() - to_chat(user, "You replace the outer grille.") - return TRUE - if(4) - var/cut_cover - if(istype(W,/obj/item/weldingtool)) - var/obj/item/weldingtool/WT = W - if(WT.remove_fuel(0,user)) - cut_cover=1 - else - return - else if (W.is_special_cutting_tool()) - if(istype(W, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = W - if(!cutter.slice(user)) - return - cut_cover = 1 - if(cut_cover) - to_chat(user, "You begin slicing through the metal cover.") - playsound(src, 'sound/items/Welder.ogg', 100, 1) - . = TRUE - if(!do_after(user, 60, src) || !istype(src, /turf/simulated/wall) || construction_stage != 4) - return - construction_stage = 3 - update_icon() - to_chat(user, "You press firmly on the cover, dislodging it.") - return - if(3) - if(isCrowbar(W)) - to_chat(user, "You struggle to pry off the cover.") - playsound(src, 'sound/items/Crowbar.ogg', 100, 1) - . = TRUE - if(!do_after(user,100,src) || !istype(src, /turf/simulated/wall) || construction_stage != 3) - return - construction_stage = 2 - update_icon() - to_chat(user, "You pry off the cover.") - return - if(2) - if(isWrench(W)) - to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame.") - playsound(src, 'sound/items/Ratchet.ogg', 100, 1) - . = TRUE - if(!do_after(user,40,src) || !istype(src, /turf/simulated/wall) || construction_stage != 2) - return - construction_stage = 1 - update_icon() - to_chat(user, "You remove the bolts anchoring the support rods.") - return - if(1) - var/cut_cover - if(istype(W, /obj/item/weldingtool)) - var/obj/item/weldingtool/WT = W - if( WT.remove_fuel(0,user) ) - cut_cover=1 - else - return - else if(W.is_special_cutting_tool()) - if(istype(W, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = W - if(!cutter.slice(user)) - return - cut_cover = 1 - if(cut_cover) - to_chat(user, "You begin slicing through the support rods.") - playsound(src, 'sound/items/Welder.ogg', 100, 1) - . = TRUE - if(!do_after(user,70,src) || !istype(src, /turf/simulated/wall) || construction_stage != 1) - return - construction_stage = 0 - update_icon() - new /obj/item/stack/material/rods(src) - to_chat(user, "The support rods drop out as you cut them loose from the frame.") - return - if(0) - if(isCrowbar(W)) - to_chat(user, "You struggle to pry off the outer sheath.") - playsound(src, 'sound/items/Crowbar.ogg', 100, 1) - . = TRUE - if(!do_after(user,100,src) || !istype(src, /turf/simulated/wall) || !user || !W || !T ) return - if(user.loc == T && user.get_active_hand() == W ) - to_chat(user, "You pry off the outer sheath.") - dismantle_wall() - return - - if(istype(W,/obj/item/frame)) - var/obj/item/frame/F = W - F.try_build(src, click_params) - return TRUE - - // Attack the wall with items - if(istype(W,/obj/item/rcd) || !istype(W, /obj/item/chems)) - return - if(!W.force) - return - if(isliving(user)) - var/mob/living/L = user - if(L.a_intent == I_HELP) - return - var/dam_threshhold = material.integrity - if(reinf_material) - dam_threshhold = ceil(max(dam_threshhold,reinf_material.integrity)/2) - var/dam_prob = min(100,material.hardness*1.5) - if(dam_prob < 100 && W.force > (dam_threshhold/10)) - playsound(src, 'sound/effects/metalhit.ogg', 50, 1) - if(!prob(dam_prob)) - visible_message("\The [user] attacks \the [src] with \the [W] and it [material.destruction_desc]!") - dismantle_wall(1) - else - visible_message("\The [user] attacks \the [src] with \the [W]!") - else - visible_message("\The [user] attacks \the [src] with \the [W], but it bounces off!") - playsound(src, hitsound, 25, 1) - return TRUE \ No newline at end of file diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm deleted file mode 100644 index 8d5911096454..000000000000 --- a/code/game/turfs/simulated/wall_icon.dm +++ /dev/null @@ -1,184 +0,0 @@ -/turf/simulated/wall/proc/update_material() - if(construction_stage != -1) - if(reinf_material) - construction_stage = 6 - else - construction_stage = null - if(!material) - material = decls_repository.get_decl(get_default_material()) - if(material) - explosion_resistance = material.explosion_resistance - if(reinf_material && reinf_material.explosion_resistance > explosion_resistance) - explosion_resistance = reinf_material.explosion_resistance - update_strings() - set_opacity(material.opacity >= 0.5) - SSradiation.resistance_cache.Remove(src) - update_connections(1) - queue_icon_update() - -/turf/simulated/wall/proc/update_strings() - if(reinf_material) - SetName("reinforced [material.solid_name] [material.wall_name]") - desc = "It seems to be a section of hull reinforced with [reinf_material.solid_name] and plated with [material.solid_name]." - else - SetName("[material.solid_name] [material.wall_name]") - desc = "It seems to be a section of hull plated with [material.solid_name]." - -/turf/simulated/wall/proc/get_default_material() - . = DEFAULT_WALL_MATERIAL - -/turf/simulated/wall/proc/set_material(var/decl/material/newmaterial, var/decl/material/newrmaterial, var/decl/material/newgmaterial) - - material = newmaterial - if(ispath(material, /decl/material)) - material = decls_repository.get_decl(material) - else if(!istype(material)) - crash_with("Wall has been supplied non-material '[newmaterial]'.") - material = decls_repository.get_decl(get_default_material()) - - reinf_material = newrmaterial - if(ispath(reinf_material, /decl/material)) - reinf_material = decls_repository.get_decl(reinf_material) - else if(!istype(reinf_material)) - reinf_material = null - - girder_material = newgmaterial - if(ispath(girder_material, /decl/material)) - girder_material = decls_repository.get_decl(girder_material) - else if(!istype(girder_material)) - girder_material = null - - update_material() - -/turf/simulated/wall/proc/get_wall_state() - . = material?.icon_base || "metal" - -/turf/simulated/wall/proc/apply_reinf_overlay() - . = !!reinf_material - -/turf/simulated/wall/on_update_icon() - - . = ..() - cut_overlays() - - if(!material) - return - - if(!damage_overlays[1]) //list hasn't been populated; note that it is always of fixed length, so we must check for membership. - generate_overlays() - - var/material_icon_base = get_wall_state() - var/image/I - var/base_color = paint_color ? paint_color : material.color - if(!density) - I = image(icon, "[material_icon_base]fwall_open") - I.color = base_color - add_overlay(I) - return - - for(var/i = 1 to 4) - I = image(icon, "[material_icon_base][wall_connections[i]]", dir = 1<<(i-1)) - I.color = base_color - add_overlay(I) - if(other_connections[i] != "0") - I = image(icon, "[material_icon_base]_other[wall_connections[i]]", dir = 1<<(i-1)) - I.color = base_color - add_overlay(I) - - if(apply_reinf_overlay()) - var/reinf_color = paint_color ? paint_color : reinf_material.color - if(construction_stage != null && construction_stage < 6) - I = image(icon, "reinf_construct-[construction_stage]") - I.color = reinf_color - add_overlay(I) - else - if("[reinf_material.icon_reinf]0" in icon_states(icon)) - // Directional icon - for(var/i = 1 to 4) - I = image(icon, "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1)) - I.color = reinf_color - add_overlay(I) - else - I = image(icon, reinf_material.icon_reinf) - I.color = reinf_color - add_overlay(I) - var/image/texture = material.get_wall_texture() - if(texture) - add_overlay(texture) - if(stripe_color) - for(var/i = 1 to 4) - if(other_connections[i] != "0") - I = image(icon, "stripe_other[wall_connections[i]]", dir = 1<<(i-1)) - else - I = image(icon, "stripe[wall_connections[i]]", dir = 1<<(i-1)) - I.color = stripe_color - add_overlay(I) - - if(damage != 0) - var/integrity = material.integrity - if(reinf_material) - integrity += reinf_material.integrity - - var/overlay = round(damage / integrity * damage_overlays.len) + 1 - if(overlay > damage_overlays.len) - overlay = damage_overlays.len - add_overlay(damage_overlays[overlay]) - -/turf/simulated/wall/proc/generate_overlays() - var/alpha_inc = 256 / damage_overlays.len - for(var/i = 1; i <= damage_overlays.len; i++) - var/image/img = image(icon = 'icons/turf/walls.dmi', icon_state = "overlay_damage") - img.blend_mode = BLEND_MULTIPLY - img.alpha = (i * alpha_inc) - 1 - damage_overlays[i] = img - -/turf/simulated/wall/proc/update_connections(propagate = 0) - if(!material) - return - var/list/wall_dirs = list() - var/list/other_dirs = list() - - for(var/turf/simulated/wall/W in orange(src, 1)) - switch(can_join_with(W)) - if(0) - continue - if(1) - wall_dirs += get_dir(src, W) - if(2) - wall_dirs += get_dir(src, W) - other_dirs += get_dir(src, W) - if(propagate) - W.update_connections() - W.update_icon() - - for(var/turf/T in orange(src, 1)) - var/success = 0 - for(var/obj/O in T) - for(var/b_type in blend_objects) - if(istype(O, b_type)) - success = 1 - for(var/nb_type in noblend_objects) - if(istype(O, nb_type)) - success = 0 - if(success) - break - if(success) - break - - if(success) - wall_dirs += get_dir(src, T) - if(get_dir(src, T) in GLOB.cardinal) - other_dirs += get_dir(src, T) - - wall_connections = dirs_to_corner_states(wall_dirs) - other_connections = dirs_to_corner_states(other_dirs) - -/turf/simulated/wall/proc/can_join_with(var/turf/simulated/wall/W) - if(material && W.material && get_wall_state() == W.get_wall_state()) - if((reinf_material && W.reinf_material) || (!reinf_material && !W.reinf_material)) - return 1 - return 2 - for(var/wb_type in blend_turfs) - if(istype(W, wb_type)) - return 2 - return 0 diff --git a/code/game/turfs/simulated/wall_natural.dm b/code/game/turfs/simulated/wall_natural.dm deleted file mode 100644 index 63fde797391f..000000000000 --- a/code/game/turfs/simulated/wall_natural.dm +++ /dev/null @@ -1,179 +0,0 @@ -var/list/default_strata_type_by_z = list() -var/list/default_material_by_strata_and_z = list() -var/list/default_strata_types = list() -var/list/natural_walls = list() - -/turf/simulated/wall/natural - name = "wall" - material = null - reinf_material = null - girder_material = null - construction_stage = -1 - floor_type = /turf/simulated/floor/asteroid - blend_objects = null - noblend_objects = null - - var/strata - var/image/ore_overlay - -/turf/simulated/wall/natural/get_paint_examine_message() - . = SPAN_NOTICE("It has been noticeably discoloured by the elements.") - -/turf/simulated/wall/natural/proc/set_strata_material() - - if(material) - return - - if(!strata) - if(!global.default_strata_type_by_z["z"]) - if(!length(global.default_strata_types)) - var/list/strata_types = decls_repository.get_decls_of_subtype(/decl/strata) - for(var/stype in strata_types) - var/decl/strata/check_strata = strata_types[stype] - if(check_strata.default_strata_candidate) - global.default_strata_types += stype - global.default_strata_type_by_z["z"] = pick(global.default_strata_types) - strata = global.default_strata_type_by_z["z"] - - var/skey = "[strata]-[z]" - if(!global.default_material_by_strata_and_z[skey]) - var/decl/strata/strata_info = decls_repository.get_decl(strata) - if(length(strata_info.base_materials)) - global.default_material_by_strata_and_z[skey] = pick(strata_info.base_materials) - material = global.default_material_by_strata_and_z[skey] - -/turf/simulated/wall/natural/Initialize() - set_strata_material() - . = ..() - global.natural_walls += src - set_extension(src, /datum/extension/geological_data) - -/turf/simulated/wall/natural/LateInitialize() - ..() - spread_deposit() - -/turf/simulated/wall/natural/Destroy() - global.natural_walls -= src - . = ..() - -/turf/simulated/wall/natural/proc/spread_deposit() - if(!istype(reinf_material) || reinf_material.ore_spread_chance <= 0) - return - for(var/trydir in GLOB.cardinal) - if(!prob(reinf_material.ore_spread_chance)) - continue - var/turf/simulated/wall/natural/target_turf = get_step(src, trydir) - if(!istype(target_turf) || !isnull(target_turf.reinf_material)) - continue - target_turf.set_material(target_turf.material, reinf_material) - target_turf.spread_deposit() - -/turf/simulated/wall/natural/attackby(obj/item/W, mob/user, click_params) - - if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) - return - - if(istype(W, /obj/item/depth_scanner)) - var/obj/item/depth_scanner/C = W - C.scan_atom(user, src) - return TRUE - - if (istype(W, /obj/item/measuring_tape)) - var/obj/item/measuring_tape/P = W - user.visible_message(SPAN_NOTICE("\The [user] extends [P] towards [src]."),SPAN_NOTICE("You extend [P] towards [src].")) - if(do_after(user,10, src)) - to_chat(user, SPAN_NOTICE("\The [src] has been excavated to a depth of [excavation_level]cm.")) - return TRUE - - if(istype(W, /obj/item/pickaxe/xeno)) - return handle_xenoarch_tool_interaction(W, user) - - // Drill out natural walls. - if(istype(W, /obj/item/pickaxe)) - var/obj/item/pickaxe/P = W - playsound(user, P.drill_sound, 20, 1) - to_chat(user, SPAN_NOTICE("You start [P.drill_verb][destroy_artifacts(P, INFINITY)].")) - if(do_after(user, P.digspeed, src)) - to_chat(user, SPAN_NOTICE("You finish [P.drill_verb] \the [src].")) - dismantle_wall() - return TRUE - - // Do not allow repairing of natural walls. - if(!damage || !istype(W, /obj/item/weldingtool)) - . = ..() - -/turf/simulated/wall/natural/update_strings() - if(reinf_material) - SetName("[reinf_material.solid_name] deposit") - desc = "A natural cliff face composed of bare [material.solid_name] and a deposit of [reinf_material.solid_name]." - else - SetName("natural [material.solid_name] wall") - desc = "A natural cliff face composed of bare [material.solid_name]." - -/turf/simulated/wall/natural/update_material() - . = ..() - girder_material = null - if(reinf_material?.ore_icon_overlay) - ore_overlay = image('icons/turf/mining_decals.dmi', "[reinf_material.ore_icon_overlay]") - ore_overlay.appearance_flags = RESET_COLOR - if(prob(50)) - var/matrix/M = matrix() - M.Scale(-1,1) - ore_overlay.transform = M - ore_overlay.color = reinf_material.color - ore_overlay.layer = DECAL_LAYER - -/turf/simulated/wall/natural/on_update_icon() - . = ..() - if(material?.reflectiveness > 0) - var/max_shine = 0.6 * ReadHSV(RGBtoHSV(material.color))[3] // patened formula based on color's Value (in HSV) - var/shine = Clamp((material.reflectiveness * 0.01) * 255, 10, max_shine) - for(var/i = 1 to 4) - var/image/I = image(icon, "rockshine[wall_connections[i]]", dir = 1<<(i-1)) - I.appearance_flags |= RESET_ALPHA - I.alpha = shine - add_overlay(I) - if(ore_overlay) - add_overlay(ore_overlay) - if(excav_overlay) - add_overlay(excav_overlay) - if(archaeo_overlay) - add_overlay(archaeo_overlay) - -/turf/simulated/wall/natural/dismantle_wall(var/devastated, var/explode, var/no_product) - if(reinf_material?.ore_result_amount) - for(var/i = 1 to reinf_material.ore_result_amount) - pass_geodata_to(new /obj/item/ore(src, reinf_material.type)) - destroy_artifacts(null, INFINITY) - . = ..(no_product = TRUE) - if(istype(., /turf/simulated/floor/asteroid)) - var/turf/simulated/floor/asteroid/debris = . - debris.overlay_detail = "asteroid[rand(0,9)]" - debris.updateMineralOverlays(1) - -/turf/simulated/wall/natural/get_wall_state() - . = "rock" - -/turf/simulated/wall/natural/get_default_material() - . = /decl/material/solid/stone/sandstone - -/turf/simulated/wall/natural/apply_reinf_overlay() - . = FALSE - -/turf/simulated/wall/natural/can_join_with(var/turf/simulated/wall/W) - . = (istype(W, /turf/simulated/wall/natural) && W.material?.type != /decl/material/placeholder && material?.type != /decl/material/placeholder) - -/turf/simulated/wall/natural/Bumped(AM) - . = ..() - if(ismob(AM)) - var/mob/M = AM - var/obj/item/pickaxe/held = M.get_active_hand() - if(istype(held)) - attackby(held, M) - -/turf/simulated/wall/natural/proc/pass_geodata_to(obj/O) - var/datum/extension/geological_data/ours = get_extension(src, /datum/extension/geological_data) - ours.geodata.UpdateNearbyArtifactInfo(src) - set_extension(O, /datum/extension/geological_data) - var/datum/extension/geological_data/newdata = get_extension(O, /datum/extension/geological_data) - newdata.set_data(ours.geodata.get_copy()) \ No newline at end of file diff --git a/code/game/turfs/simulated/wall_natural_subtypes.dm b/code/game/turfs/simulated/wall_natural_subtypes.dm deleted file mode 100644 index dbad9e928214..000000000000 --- a/code/game/turfs/simulated/wall_natural_subtypes.dm +++ /dev/null @@ -1,41 +0,0 @@ -/turf/simulated/wall/natural/random - reinf_material = null - -/turf/simulated/wall/natural/random/proc/get_weighted_mineral_list() - if(strata) - var/decl/strata/strata_info = decls_repository.get_decl(strata) - . = strata_info.ores_sparse - if(!.) - . = SSmaterials.weighted_minerals_sparse - -/turf/simulated/wall/natural/random/high_chance/get_weighted_mineral_list() - if(strata) - var/decl/strata/strata_info = decls_repository.get_decl(strata) - . = strata_info.ores_rich - if(!.) - . = SSmaterials.weighted_minerals_rich - -/turf/simulated/wall/natural/random/Initialize() - if(isnull(reinf_material)) - var/default_mineral_list = get_weighted_mineral_list() - if(LAZYLEN(default_mineral_list)) - reinf_material = pickweight(default_mineral_list) - . = ..() - -/turf/simulated/wall/natural/volcanic - strata = /decl/strata/igneous - -/turf/simulated/wall/natural/random/volcanic - strata = /decl/strata/igneous - -/turf/simulated/wall/natural/random/high_chance/volcanic - strata = /decl/strata/igneous - -/turf/simulated/wall/natural/ice - strata = /decl/strata/permafrost - -/turf/simulated/wall/natural/random/ice - strata = /decl/strata/permafrost - -/turf/simulated/wall/natural/random/high_chance/ice - strata = /decl/strata/permafrost diff --git a/code/game/turfs/simulated/wall_natural_xenoarch.dm b/code/game/turfs/simulated/wall_natural_xenoarch.dm deleted file mode 100644 index 91091f6c28cc..000000000000 --- a/code/game/turfs/simulated/wall_natural_xenoarch.dm +++ /dev/null @@ -1,130 +0,0 @@ -/turf/simulated/wall/natural - var/excavation_level = 0 - var/datum/artifact_find/artifact_find - var/list/finds - var/last_excavation - var/next_rock = 0 - var/archaeo_overlay - var/excav_overlay - -/turf/simulated/wall/natural/proc/place_artifact_debris(var/severity = 0) - for(var/j in 1 to rand(1, 3 + max(min(severity, 1), 0) * 2)) - switch(rand(1,7)) - if(1) - new /obj/item/stack/material/rods(src, rand(5, 25)) - if(2) - new /obj/item/stack/material/plasteel(src, rand(5,25)) - if(3) - new /obj/item/stack/material/steel(src, rand(5,25)) - if(4) - new /obj/item/stack/material/plasteel(src, rand(5,25)) - if(5) - for(var/i = 1 to rand(1,3)) - new /obj/item/shard(src) - if(6) - for(var/i = 1 to rand(1,3)) - new /obj/item/shard/borosilicate(src) - if(7) - new /obj/item/stack/material/uranium(src, rand(5,25)) - -/turf/simulated/wall/natural/proc/excavate_find(var/prob_clean = 0, var/datum/find/F) - //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted - if(prob(F.prob_delicate)) - var/obj/effect/suspension_field/S = locate() in src - if(!S) - visible_message(SPAN_DANGER("[pick("An object in the rock crumbles away into dust.","Something falls out of the rock and shatters onto the ground.")]")) - finds.Remove(F) - return - //with skill and luck, players can cleanly extract finds - //otherwise, they come out inside a chunk of rock - if(prob_clean) - F.spawn_find_item(src) - else - pass_geodata_to(new /obj/item/ore/strangerock(src, F.find_type)) - finds.Remove(F) - -/turf/simulated/wall/natural/proc/handle_xenoarch_tool_interaction(var/obj/item/pickaxe/xeno/P, var/mob/user) - . = TRUE - if(last_excavation + P.digspeed > world.time)//prevents message spam - return - last_excavation = world.time - playsound(user, P.drill_sound, 20, 1) - var/newDepth = excavation_level + P.excavation_amount // Used commonly below - //handle any archaeological finds we might uncover - to_chat(user, SPAN_NOTICE("You start [P.drill_verb][destroy_artifacts(P, newDepth)].")) - if(!do_after(user,P.digspeed, src)) - return - - if(length(finds)) - var/datum/find/F = finds[1] - if(newDepth == F.excavation_required) // When the pick hits that edge just right, you extract your find perfectly, it's never confined in a rock - excavate_find(1, F) - else if(newDepth > F.excavation_required - F.clearance_range) // Not quite right but you still extract your find, the closer to the bottom the better, but not above 80% - excavate_find(prob(80 * (F.excavation_required - newDepth) / F.clearance_range), F) - - to_chat(user, SPAN_NOTICE("You finish [P.drill_verb] \the [src].")) - - if(newDepth >= 200) // This means the rock is mined out fully - if(artifact_find) - if( excavation_level > 0 || prob(15) ) - var/obj/structure/boulder/B = new(src, material?.type, paint_color) - B.artifact_find = artifact_find - else - place_artifact_debris(1) - artifact_find = null - SSxenoarch.artifact_spawning_turfs -= src - else if(prob(5)) - new /obj/structure/boulder(src, material?.type) - dismantle_wall() - return - - excavation_level += P.excavation_amount - //archaeo overlays - if(!archaeo_overlay && finds && finds.len) - var/datum/find/F = finds[1] - if(F.excavation_required <= excavation_level + F.view_range) - archaeo_overlay = image('icons/turf/excavation_overlays.dmi',"overlay_archaeo[rand(1,3)]") - queue_icon_update() - else if(archaeo_overlay && (!finds || !finds.len)) - archaeo_overlay = null - queue_icon_update() - - //there's got to be a better way to do this - var/update_excav_overlay = 0 - if(excavation_level >= 150) - if(excavation_level - P.excavation_amount < 150) - update_excav_overlay = 1 - else if(excavation_level >= 100) - if(excavation_level - P.excavation_amount < 100) - update_excav_overlay = 1 - else if(excavation_level >= 50) - if(excavation_level - P.excavation_amount < 50) - update_excav_overlay = 1 - - //update overlays displaying excavation level - if( !(excav_overlay && excavation_level > 0) || update_excav_overlay ) - var/excav_quadrant = round(excavation_level / 50) + 1 - excav_overlay = image('icons/turf/excavation_overlays.dmi',"overlay_excv[excav_quadrant]_[rand(1,3)]") - queue_icon_update() - - //drop some rocks - next_rock += P.excavation_amount - while(next_rock > 50) - next_rock -= 50 - pass_geodata_to(new /obj/item/ore(src, material?.type)) - -/turf/simulated/wall/natural/proc/destroy_artifacts(var/obj/item/W, var/newDepth) - if(!length(finds)) - return - var/datum/find/F = finds[1] - if(newDepth > F.excavation_required) // Digging too deep can break the item. At least you won't summon a Balrog (probably) - if(W) - . = ". [pick("There is a crunching noise","[W] collides with some different rock","Part of the rock face crumbles away","Something breaks under [W]")]" - if(prob(10)) - return - if(prob(25)) - excavate_find(prob(5), finds[1]) - else if(prob(50)) - finds.Remove(finds[1]) - if(prob(50)) - place_artifact_debris() diff --git a/code/game/turfs/simulated/wall_shuttle.dm b/code/game/turfs/simulated/wall_shuttle.dm deleted file mode 100644 index 02f97ee6a16c..000000000000 --- a/code/game/turfs/simulated/wall_shuttle.dm +++ /dev/null @@ -1,76 +0,0 @@ -/turf/simulated/shuttle - name = "shuttle" - icon = 'icons/turf/shuttle.dmi' - thermal_conductivity = 0.05 - heat_capacity = 0 - -/turf/simulated/shuttle/wall - name = "wall" - icon_state = "wall1" - opacity = 1 - density = 1 - blocks_air = 1 - explosion_resistance = 10 - -/turf/simulated/shuttle/wall/corner - var/corner_overlay_state = "diagonalWall" - var/image/corner_overlay - -/turf/simulated/shuttle/wall/corner/Initialize() - . = ..() - reset_base_appearance() - reset_overlay() - -//Grabs the base turf type from our area and copies its appearance -/turf/simulated/shuttle/wall/corner/proc/reset_base_appearance() - var/turf/base_type = get_base_turf_by_area(src) - if(!base_type) return - - icon = initial(base_type.icon) - icon_state = initial(base_type.icon_state) - -/turf/simulated/shuttle/wall/corner/proc/reset_overlay() - if(corner_overlay) - overlays -= corner_overlay - else - corner_overlay = image(icon = 'icons/turf/shuttle.dmi', icon_state = corner_overlay_state, dir = src.dir) - corner_overlay.plane = plane - corner_overlay.layer = layer - overlays += corner_overlay - -//Predefined Shuttle Corners -/turf/simulated/shuttle/wall/corner/smoothwhite - icon_state = "corner_white" //for mapping preview - corner_overlay_state = "corner_white" -/turf/simulated/shuttle/wall/corner/smoothwhite/ne - dir = NORTHEAST -/turf/simulated/shuttle/wall/corner/smoothwhite/nw - dir = NORTHWEST -/turf/simulated/shuttle/wall/corner/smoothwhite/se - dir = SOUTHEAST -/turf/simulated/shuttle/wall/corner/smoothwhite/sw - dir = SOUTHWEST - -/turf/simulated/shuttle/wall/corner/blockwhite - icon_state = "corner_white_block" - corner_overlay_state = "corner_white_block" -/turf/simulated/shuttle/wall/corner/blockwhite/ne - dir = NORTHEAST -/turf/simulated/shuttle/wall/corner/blockwhite/nw - dir = NORTHWEST -/turf/simulated/shuttle/wall/corner/blockwhite/se - dir = SOUTHEAST -/turf/simulated/shuttle/wall/corner/blockwhite/sw - dir = SOUTHWEST - -/turf/simulated/shuttle/wall/corner/dark - icon_state = "corner_dark" - corner_overlay_state = "corner_dark" -/turf/simulated/shuttle/wall/corner/dark/ne - dir = NORTHEAST -/turf/simulated/shuttle/wall/corner/dark/nw - dir = NORTHWEST -/turf/simulated/shuttle/wall/corner/dark/se - dir = SOUTHEAST -/turf/simulated/shuttle/wall/corner/dark/sw - dir = SOUTHWEST diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm deleted file mode 100644 index d1004db14dcd..000000000000 --- a/code/game/turfs/simulated/wall_types.dm +++ /dev/null @@ -1,178 +0,0 @@ -//Commonly used -/turf/simulated/wall/prepainted - paint_color = COLOR_GUNMETAL - -/turf/simulated/wall/r_wall/prepainted - paint_color = COLOR_GUNMETAL - -/turf/simulated/wall/r_wall - icon_state = "r_generic" - -/turf/simulated/wall/r_wall/Initialize(var/ml) - . = ..(ml, /decl/material/solid/metal/plasteel,/decl/material/solid/metal/plasteel) //3strong - -/turf/simulated/wall/r_wall/hull - name = "hull" - color = COLOR_HULL - -/turf/simulated/wall/prepainted - paint_color = COLOR_WALL_GUNMETAL -/turf/simulated/wall/r_wall/prepainted - paint_color = COLOR_WALL_GUNMETAL - -/turf/simulated/wall/r_wall/hull/Initialize() - . = ..() - paint_color = color - color = null //color is just for mapping - if(prob(40)) - var/spacefacing = FALSE - for(var/direction in GLOB.cardinal) - var/turf/T = get_step(src, direction) - var/area/A = get_area(T) - if(A && (A.area_flags & AREA_FLAG_EXTERNAL)) - spacefacing = TRUE - break - if(spacefacing) - var/bleach_factor = rand(10,50) - paint_color = adjust_brightness(paint_color, bleach_factor) - update_icon() - -/turf/simulated/wall/titanium - icon_state = "titanium" - -/turf/simulated/wall/titanium/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/plasteel/titanium) - -/turf/simulated/wall/r_titanium - icon_state = "r_titanium" - -/turf/simulated/wall/r_titanium/Initialize(var/ml) - . = ..(ml, /decl/material/solid/metal/plasteel/titanium, /decl/material/solid/metal/plasteel/titanium) - -/turf/simulated/wall/ocp_wall - icon_state = "r_ocp" - -/turf/simulated/wall/ocp_wall/Initialize(var/ml) - . = ..(ml, /decl/material/solid/metal/plasteel/ocp, /decl/material/solid/metal/plasteel/ocp) - -//Material walls - -/turf/simulated/wall/r_wall/rglass_wall/Initialize(var/ml) - . = ..(ml, /decl/material/solid/glass, /decl/material/solid/metal/steel) - icon_state = "r_generic" - -/turf/simulated/wall/iron/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/iron) - -/turf/simulated/wall/uranium/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/uranium) - -/turf/simulated/wall/diamond/Initialize(var/ml) - . = ..(ml,/decl/material/solid/gemstone/diamond) - -/turf/simulated/wall/gold/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/gold) - -/turf/simulated/wall/silver/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/silver) - -/turf/simulated/wall/sandstone/Initialize(var/ml) - . = ..(ml, /decl/material/solid/stone/sandstone) - -/turf/simulated/wall/rutile/Initialize(var/ml) - . = ..(ml, /decl/material/solid/mineral/rutile) - -/turf/simulated/wall/wood - blend_turfs = list(/turf/simulated/wall/cult, /turf/simulated/wall) - icon_state = "woodneric" - -/turf/simulated/wall/wood/Initialize(var/ml) - . = ..(ml,/decl/material/solid/wood) - -/turf/simulated/wall/mahogany - blend_turfs = list(/turf/simulated/wall/cult, /turf/simulated/wall) - icon_state = "woodneric" - -/turf/simulated/wall/mahogany/Initialize(var/ml) - . = ..(ml,/decl/material/solid/wood/mahogany) - -/turf/simulated/wall/maple - blend_turfs = list(/turf/simulated/wall/cult, /turf/simulated/wall) - icon_state = "woodneric" - -/turf/simulated/wall/maple/Initialize(var/ml) - . = ..(ml,/decl/material/solid/wood/maple) - -/turf/simulated/wall/ebony - blend_turfs = list(/turf/simulated/wall/cult, /turf/simulated/wall) - icon_state = "woodneric" - -/turf/simulated/wall/ebony/Initialize(var/ml) - . = ..(ml,/decl/material/solid/wood/ebony) - -/turf/simulated/wall/walnut - blend_turfs = list(/turf/simulated/wall/cult, /turf/simulated/wall) - icon_state = "woodneric" - -/turf/simulated/wall/walnut/Initialize(var/ml) - . = ..(ml,/decl/material/solid/wood/walnut) - -/turf/simulated/wall/golddiamond/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/gold,/decl/material/solid/gemstone/diamond) - -/turf/simulated/wall/silvergold/Initialize(var/ml) - . = ..(ml,/decl/material/solid/metal/silver,/decl/material/solid/metal/gold) - -/turf/simulated/wall/sandstonediamond/Initialize(var/ml) - . = ..(ml, /decl/material/solid/stone/sandstone, /decl/material/solid/gemstone/diamond) - -/turf/simulated/wall/crystal/Initialize(var/ml) - . = ..(ml,/decl/material/solid/gemstone/crystal) - -/turf/simulated/wall/voxshuttle/Initialize(var/ml) - . = ..(ml, /decl/material/solid/metal/voxalloy) - -/turf/simulated/wall/voxshuttle/attackby() - return - -/turf/simulated/wall/concrete - floor_type = null - -/turf/simulated/wall/concrete/Initialize(var/ml) - . = ..(ml,/decl/material/solid/stone/concrete) - -//Alien metal walls -/turf/simulated/wall/alium - icon_state = "jaggy" - floor_type = /turf/simulated/floor/fixed/alium - list/blend_objects = newlist() - -/turf/simulated/wall/alium/Initialize(var/ml) - . = ..(ml, /decl/material/solid/metal/aliumium) - -/turf/simulated/wall/alium/explosion_act(severity) - SHOULD_CALL_PARENT(TRUE) - if(prob(explosion_resistance)) - ..() - -//Cult wall -/turf/simulated/wall/cult - icon_state = "cult" - blend_turfs = list(/turf/simulated/wall) - -/turf/simulated/wall/cult/Initialize(var/ml, var/reinforce) - . = ..(ml, /decl/material/solid/stone/cult, reinforce ? /decl/material/solid/stone/cult/reinforced : null) - -/turf/simulated/wall/cult/reinf/Initialize(var/ml) - . = ..(ml, 1) - -/turf/simulated/wall/cult/dismantle_wall() - GLOB.cult.remove_cultiness(CULTINESS_PER_TURF) - . = ..() - -/turf/simulated/wall/cult/can_join_with(var/turf/simulated/wall/W) - if(material && W.material && material.icon_base == W.material.icon_base) - return 1 - else if(istype(W, /turf/simulated/wall)) - return 1 - return 0 \ No newline at end of file diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm deleted file mode 100644 index 0f8ca417ba02..000000000000 --- a/code/game/turfs/simulated/walls.dm +++ /dev/null @@ -1,267 +0,0 @@ -/turf/simulated/wall - name = "wall" - desc = "A huge chunk of metal used to seperate rooms." - icon = 'icons/turf/wall_masks.dmi' - icon_state = "generic" - opacity = 1 - density = 1 - blocks_air = 1 - thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT - heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall - explosion_resistance = 10 - - var/damage = 0 - var/damage_overlay = 0 - var/global/damage_overlays[16] - var/active - var/can_open = 0 - var/decl/material/material - var/decl/material/reinf_material - var/decl/material/girder_material = /decl/material/solid/metal/steel - var/last_state - var/construction_stage - var/hitsound = 'sound/weapons/Genhit.ogg' - var/list/wall_connections = list("0", "0", "0", "0") - var/list/other_connections = list("0", "0", "0", "0") - var/floor_type = /turf/simulated/floor/plating //turf it leaves after destruction - var/paint_color - var/stripe_color - var/global/list/wall_stripe_cache = list() - var/list/blend_turfs = list(/turf/simulated/wall/cult, /turf/simulated/wall/wood, /turf/simulated/wall/walnut, /turf/simulated/wall/maple, /turf/simulated/wall/mahogany, /turf/simulated/wall/ebony) - var/list/blend_objects = list(/obj/machinery/door, /obj/structure/wall_frame, /obj/structure/grille, /obj/structure/window/reinforced/full, /obj/structure/window/reinforced/polarized/full, /obj/structure/window/shuttle, ,/obj/structure/window/borosilicate/full, /obj/structure/window/borosilicate_reinforced/full) // Objects which to blend with - var/list/noblend_objects = list(/obj/machinery/door/window) //Objects to avoid blending with (such as children of listed blend objects. - -/turf/simulated/wall/Initialize(var/ml, var/materialtype, var/rmaterialtype) - ..(ml) - - if(!ispath(material, /decl/material)) - material = materialtype || get_default_material() - if(ispath(material, /decl/material)) - material = decls_repository.get_decl(material) - - if(!ispath(reinf_material, /decl/material)) - reinf_material = rmaterialtype - if(ispath(reinf_material, /decl/material)) - reinf_material = decls_repository.get_decl(reinf_material) - - if(ispath(girder_material, /decl/material)) - girder_material = decls_repository.get_decl(girder_material) - - . = INITIALIZE_HINT_LATELOAD - set_extension(src, /datum/extension/penetration/proc_call, .proc/CheckPenetration) - START_PROCESSING(SSturf, src) //Used for radiation. - -/turf/simulated/wall/LateInitialize() - ..() - update_material() - -/turf/simulated/wall/Destroy() - STOP_PROCESSING(SSturf, src) - material = decls_repository.get_decl(/decl/material/placeholder) - reinf_material = null - var/old_x = x - var/old_y = y - var/old_z = z - . = ..() - var/turf/debris = locate(old_x, old_y, old_z) - if(debris) - for(var/turf/simulated/wall/W in RANGE_TURFS(debris, 1)) - W.update_connections() - W.queue_icon_update() - -// Walls always hide the stuff below them. -/turf/simulated/wall/levelupdate() - for(var/obj/O in src) - O.hide(1) - -/turf/simulated/wall/protects_atom(var/atom/A) - var/obj/O = A - return (istype(O) && O.hides_under_flooring()) || ..() - -/turf/simulated/wall/Process(wait, times_fired) - var/how_often = max(round(2 SECONDS/wait), 1) - if(times_fired % how_often) - return //We only work about every 2 seconds - if(!radiate()) - return PROCESS_KILL - -/turf/simulated/wall/proc/get_material() - return material - -/turf/simulated/wall/bullet_act(var/obj/item/projectile/Proj) - if(istype(Proj,/obj/item/projectile/beam)) - burn(2500) - else if(istype(Proj,/obj/item/projectile/ion)) - burn(500) - - var/proj_damage = Proj.get_structure_damage() - - if(Proj.ricochet_sounds && prob(15)) - playsound(src, pick(Proj.ricochet_sounds), 100, 1) - - if(reinf_material) - if(Proj.damage_type == BURN) - proj_damage /= reinf_material.burn_armor - else if(Proj.damage_type == BRUTE) - proj_damage /= reinf_material.brute_armor - - //cap the amount of damage, so that things like emitters can't destroy walls in one hit. - var/damage = min(proj_damage, 100) - - take_damage(damage) - return - -/turf/simulated/wall/hitby(AM, var/datum/thrownthing/TT) - if(!ismob(AM)) - var/obj/O = AM - var/tforce = O.throwforce * (TT.speed/THROWFORCE_SPEED_DIVISOR) - playsound(src, hitsound, tforce >= 15? 60 : 25, TRUE) - if (tforce >= 15) - take_damage(tforce) - ..() - -/turf/simulated/wall/proc/clear_plants() - for(var/obj/effect/overlay/wallrot/WR in src) - qdel(WR) - for(var/obj/effect/vine/plant in range(src, 1)) - if(!plant.floor) //shrooms drop to the floor - plant.floor = 1 - plant.update_icon() - plant.pixel_x = 0 - plant.pixel_y = 0 - -/turf/simulated/wall/ChangeTurf(var/newtype) - clear_plants() - return ..(newtype) - -//Appearance -/turf/simulated/wall/examine(mob/user) - . = ..() - - if(!damage) - to_chat(user, "It looks fully intact.") - else - var/dam = damage / material.integrity - if(dam <= 0.3) - to_chat(user, "It looks slightly damaged.") - else if(dam <= 0.6) - to_chat(user, "It looks moderately damaged.") - else - to_chat(user, "It looks heavily damaged.") - if(paint_color) - to_chat(user, get_paint_examine_message()) - if(locate(/obj/effect/overlay/wallrot) in src) - to_chat(user, "There is fungus growing on [src].") - -/turf/simulated/wall/proc/get_paint_examine_message() - . = SPAN_NOTICE("It has had a coat of paint applied.") - -//Damage -/turf/simulated/wall/melt() - if(can_melt()) - var/turf/simulated/floor/F = ChangeTurf(/turf/simulated/floor/plating) - if(istype(F)) - F.burn_tile() - F.icon_state = "wall_thermite" - visible_message(SPAN_DANGER("\The [src] spontaneously combusts!")) - -/turf/simulated/wall/proc/take_damage(dam) - if(dam) - damage = max(0, damage + dam) - update_damage() - -/turf/simulated/wall/proc/update_damage() - var/cap = material.integrity - if(reinf_material) - cap += reinf_material.integrity - - if(locate(/obj/effect/overlay/wallrot) in src) - cap = cap / 10 - - if(damage >= cap) - dismantle_wall() - else - update_icon() - - return - -/turf/simulated/wall/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)//Doesn't fucking work because walls don't interact with air :( - burn(exposed_temperature) - -/turf/simulated/wall/adjacent_fire_act(turf/simulated/floor/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) - burn(adj_temp) - if(adj_temp > material.melting_point) - take_damage(log(RAND_F(0.9, 1.1) * (adj_temp - material.melting_point))) - - return ..() - -/turf/simulated/wall/proc/dismantle_wall(var/devastated, var/explode, var/no_product) - - playsound(src, 'sound/items/Welder.ogg', 100, 1) - if(!no_product) - if(girder_material) - girder_material.place_dismantled_girder(src, reinf_material) - material.place_dismantled_product(src,devastated) - else - material.place_dismantled_girder(src, reinf_material) - - for(var/obj/O in src.contents) //Eject contents! - if(istype(O,/obj/structure/sign/poster)) - var/obj/structure/sign/poster/P = O - P.roll_and_drop(src) - else - O.forceMove(src) - clear_plants() - . = ChangeTurf(floor_type || get_base_turf_by_area(src)) - -/turf/simulated/wall/explosion_act(severity) - SHOULD_CALL_PARENT(FALSE) - if(severity == 1) - dismantle_wall(1,1,1) - else if(severity == 2) - if(prob(75)) - take_damage(rand(150, 250)) - else - dismantle_wall(1,1) - else if(severity == 3) - take_damage(rand(0, 250)) - -// Wall-rot effect, a nasty fungus that destroys walls. -/turf/simulated/wall/proc/rot() - if(locate(/obj/effect/overlay/wallrot) in src) - return - var/number_rots = rand(2,3) - for(var/i=0, i= 10 && material.hardness <= 100) - -/turf/simulated/wall/is_wall() - return TRUE diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 35a48351d8a3..ff76d205ad23 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -4,219 +4,133 @@ icon = 'icons/turf/space.dmi' explosion_resistance = 3 icon_state = "default" - dynamic_lighting = 0 + dynamic_lighting = FALSE temperature = T20C thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT permit_ao = FALSE z_eventually_space = TRUE - var/static/list/dust_cache - -/turf/space/proc/build_dust_cache() - LAZYINITLIST(dust_cache) - for (var/i in 0 to 25) - var/image/im = image('icons/turf/space_dust.dmi',"[i]") - im.plane = DUST_PLANE - im.alpha = 80 - im.blend_mode = BLEND_ADD - - var/image/I = new() - I.appearance = /turf/space - I.icon_state = "white" - I.overlays += im - dust_cache["[i]"] = I + turf_flags = TURF_FLAG_BACKGROUND + can_inherit_air = FALSE + + open_turf_type = /turf/space + + /// If we're an edge. + var/edge = 0 + /// Force this one to pretend it's an overedge turf. + var/forced_dirs = 0 /turf/space/Initialize() - . = ..() - update_starlight() - if (!dust_cache) - build_dust_cache() - appearance = dust_cache["[((x + y) ^ ~(x * y) + z) % 25]"] + + SHOULD_CALL_PARENT(FALSE) + atom_flags |= ATOM_FLAG_INITIALIZED + _earliest_type ||= type + + AMBIENCE_QUEUE_TURF(src) + + //We might be an edge + if(y == world.maxy || forced_dirs & NORTH) + edge |= NORTH + else if(y == 1 || forced_dirs & SOUTH) + edge |= SOUTH + + if(x == 1 || forced_dirs & WEST) + edge |= WEST + else if(x == world.maxx || forced_dirs & EAST) + edge |= EAST + + if(edge) //Magic edges + appearance = SSskybox.mapedge_cache["[edge]"] + else //Dust + appearance = SSskybox.dust_cache["[((x + y) ^ ~(x * y) + z) % 25]"] if(!HasBelow(z)) - return + return INITIALIZE_HINT_NORMAL + var/turf/below = GetBelow(src) + if(isspaceturf(below)) + return INITIALIZE_HINT_NORMAL - if(istype(below, /turf/space)) - return var/area/A = below.loc - if(!below.density && (A.area_flags & AREA_FLAG_EXTERNAL)) - return + return INITIALIZE_HINT_NORMAL return INITIALIZE_HINT_LATELOAD // oh no! we need to switch to being a different kind of turf! +/turf/space/LateInitialize() + if(SSmapping.base_floor_area) + var/area/new_area = locate(SSmapping.base_floor_area) || new SSmapping.base_floor_area + ChangeArea(src, new_area) + ChangeTurf(SSmapping.base_floor_type) + +/turf/space/proc/toggle_transit(var/direction) + if(edge) + return + + if(!direction) //Stopping our transit + appearance = SSskybox.dust_cache["[((x + y) ^ ~(x * y) + z) % 25]"] + else if(direction & (NORTH|SOUTH)) //Starting transit vertically + var/x_shift = SSskybox.phase_shift_by_x[x % (SSskybox.phase_shift_by_x.len - 1) + 1] + var/transit_state = ((direction & SOUTH ? world.maxy - y : y) + x_shift) % 15 + appearance = SSskybox.speedspace_cache["NS_[transit_state]"] + else if(direction & (EAST|WEST)) //Starting transit horizontally + var/y_shift = SSskybox.phase_shift_by_y[y % (SSskybox.phase_shift_by_y.len - 1) + 1] + var/transit_state = ((direction & WEST ? world.maxx - x : x) + y_shift) % 15 + appearance = SSskybox.speedspace_cache["EW_[transit_state]"] + + for(var/atom/movable/AM in src) + if (AM.simulated && !AM.anchored) + AM.throw_at(get_step(src, global.reverse_dir[direction]), 5, 1) + + if(istype(AM, /obj/effect/decal)) + qdel(AM) + /turf/space/Destroy() // Cleanup cached z_eventually_space values above us. if (above) var/turf/T = src while ((T = GetAbove(T))) T.z_eventually_space = FALSE - return ..() - -/turf/space/LateInitialize() - if(GLOB.using_map.base_floor_area) - var/area/new_area = locate(GLOB.using_map.base_floor_area) || new GLOB.using_map.base_floor_area - ChangeArea(src, new_area) - ChangeTurf(GLOB.using_map.base_floor_type) -// override for space turfs, since they should never hide anything -/turf/space/levelupdate() - for(var/obj/O in src) - O.hide(0) - -/turf/space/is_solid_structure() - return locate(/obj/structure/lattice, src) //counts as solid structure if it has a lattice + return ..() -/turf/space/attackby(obj/item/C, mob/user) +/turf/space/attackby(obj/item/used_item, mob/user) - if (istype(C, /obj/item/stack/material/rods)) + if (istype(used_item, /obj/item/stack/material/rods)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) - return L.attackby(C, user) - var/obj/item/stack/material/rods/R = C - if (R.use(1)) + return L.attackby(used_item, user) + var/obj/item/stack/material/rods/rods = used_item + if (rods.use(1)) to_chat(user, "Constructing support lattice ...") playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - ReplaceWithLattice(R.material.type) + new /obj/structure/lattice(src, rods.material.type) return TRUE - if (istype(C, /obj/item/stack/tile/floor)) + if (istype(used_item, /obj/item/stack/tile/floor)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) - var/obj/item/stack/tile/floor/S = C + var/obj/item/stack/tile/floor/S = used_item if (!S.use(1)) - return - qdel(L) + return TRUE playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - ChangeTurf(/turf/simulated/floor/airless, keep_air = TRUE) + ChangeTurf(/turf/floor/plating/airless) + qdel(L) else to_chat(user, "The plating is going to need some support.") return TRUE + return FALSE // Ported from unstable r355 /turf/space/Entered(atom/movable/A) ..() - if(A && A.loc == src) + if(A && A.loc == src && !density) // !density so 'fake' space turfs don't fling ghosts everywhere if (A.x <= TRANSITIONEDGE || A.x >= (world.maxx - TRANSITIONEDGE + 1) || A.y <= TRANSITIONEDGE || A.y >= (world.maxy - TRANSITIONEDGE + 1)) - A.touch_map_edge() - -/turf/space/proc/Sandbox_Spacemove(atom/movable/A) - var/cur_x - var/cur_y - var/next_x - var/next_y - var/target_z - var/list/y_arr - - if(src.x <= 1) - if(istype(A, /obj/effect/meteor)) - qdel(A) - return - - var/list/cur_pos = src.get_global_map_pos() - if(!cur_pos) return - cur_x = cur_pos["x"] - cur_y = cur_pos["y"] - next_x = (--cur_x||GLOB.global_map.len) - y_arr = GLOB.global_map[next_x] - target_z = y_arr[cur_y] -/* - //debug - log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") - log_debug("Target Z = [target_z]") - log_debug("Next X = [next_x]") - - //debug -*/ - if(target_z) - A.z = target_z - A.x = world.maxx - 2 - spawn (0) - if ((A && A.loc)) - A.loc.Entered(A) - else if (src.x >= world.maxx) - if(istype(A, /obj/effect/meteor)) - qdel(A) - return - - var/list/cur_pos = src.get_global_map_pos() - if(!cur_pos) return - cur_x = cur_pos["x"] - cur_y = cur_pos["y"] - next_x = (++cur_x > GLOB.global_map.len ? 1 : cur_x) - y_arr = GLOB.global_map[next_x] - target_z = y_arr[cur_y] -/* - //debug - log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") - log_debug("Target Z = [target_z]") - log_debug("Next X = [next_x]") - - //debug -*/ - if(target_z) - A.z = target_z - A.x = 3 - spawn (0) - if ((A && A.loc)) - A.loc.Entered(A) - else if (src.y <= 1) - if(istype(A, /obj/effect/meteor)) - qdel(A) - return - var/list/cur_pos = src.get_global_map_pos() - if(!cur_pos) return - cur_x = cur_pos["x"] - cur_y = cur_pos["y"] - y_arr = GLOB.global_map[cur_x] - next_y = (--cur_y||y_arr.len) - target_z = y_arr[next_y] -/* - //debug - log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") - log_debug("Next Y = [next_y]") - log_debug("Target Z = [target_z]") - - //debug -*/ - if(target_z) - A.z = target_z - A.y = world.maxy - 2 - spawn (0) - if ((A && A.loc)) - A.loc.Entered(A) - - else if (src.y >= world.maxy) - if(istype(A, /obj/effect/meteor)) - qdel(A) - return - var/list/cur_pos = src.get_global_map_pos() - if(!cur_pos) return - cur_x = cur_pos["x"] - cur_y = cur_pos["y"] - y_arr = GLOB.global_map[cur_x] - next_y = (++cur_y > y_arr.len ? 1 : cur_y) - target_z = y_arr[next_y] -/* - //debug - log_debug("Src.z = [src.z] in global map X = [cur_x], Y = [cur_y]") - log_debug("Next Y = [next_y]") - log_debug("Target Z = [target_z]") - - //debug -*/ - if(target_z) - A.z = target_z - A.y = 3 - spawn (0) - if ((A && A.loc)) - A.loc.Entered(A) - return - -/turf/space/ChangeTurf(turf/N, tell_universe = TRUE, force_lighting_update = FALSE, keep_air = FALSE) - return ..(N, tell_universe, TRUE, keep_air) + A.touch_map_edge(OVERMAP_ID_SPACE) + +/turf/space/ChangeTurf(var/turf/N, var/tell_universe = TRUE, var/force_lighting_update = FALSE, var/keep_air = FALSE, var/update_open_turfs_above = TRUE) + return ..(N, tell_universe, TRUE, keep_air, update_open_turfs_above) /turf/space/is_open() return TRUE @@ -225,3 +139,10 @@ /turf/space/infinity name = "\proper infinity" icon_state = "bluespace" + +/turf/space/black + icon_state = "black" + +// not how space works +/turf/space/get_movable_alpha_mask_state(atom/movable/mover) + return null \ No newline at end of file diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index 2dc665e3a0f8..37b63eb82cde 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -1,48 +1,27 @@ /turf/space/transit - var/pushdirection // push things that get caught in the transit tile this direction + var/push_direction // push things that get caught in the transit tile this direction //Overwrite because we dont want people building rods in space. -/turf/space/transit/attackby(obj/O, mob/user) - return +/turf/space/transit/attackby(obj/item/used_item, mob/user) + return TRUE -//generates a list used to randomize transit animations so they aren't in lockstep -/turf/space/transit/proc/get_cross_shift_list(var/size) - var/list/result = list() - - result += rand(0, 14) - for(var/i in 2 to size) - var/shifts = list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) - shifts -= result[i - 1] //consecutive shifts should not be equal - if(i == size) - shifts -= result[1] //because shift list is a ring buffer - result += pick(shifts) - - return result - -/turf/space/transit/north // moving to the north - pushdirection = SOUTH // south because the space tile is scrolling south - var/static/list/phase_shift_by_x - -/turf/space/transit/north/Initialize() +/turf/space/transit/Initialize() . = ..() - if(!phase_shift_by_x) - phase_shift_by_x = get_cross_shift_list(15) + toggle_transit(global.reverse_dir[push_direction]) - var/x_shift = phase_shift_by_x[src.x % (phase_shift_by_x.len - 1) + 1] - var/transit_state = (world.maxy - src.y + x_shift)%15 + 1 +/turf/space/transit/north // moving to the north + icon_state = "arrow-north" + push_direction = SOUTH // south because the space tile is scrolling south - icon_state = "speedspace_ns_[transit_state]" +/turf/space/transit/south // moving to the south + icon_state = "arrow-south" + push_direction = SOUTH // south because the space tile is scrolling south /turf/space/transit/east // moving to the east - pushdirection = WEST - var/static/list/phase_shift_by_y - -/turf/space/transit/east/Initialize(var/ml) - . = ..() - if(!phase_shift_by_y) - phase_shift_by_y = get_cross_shift_list(15) + icon_state = "arrow-east" + push_direction = WEST - var/y_shift = phase_shift_by_y[src.y % (phase_shift_by_y.len - 1) + 1] - var/transit_state = (world.maxx - src.x + y_shift)%15 + 1 +/turf/space/transit/west // moving to the west + icon_state = "arrow-west" + push_direction = WEST - icon_state = "speedspace_ew_[transit_state]" diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 7560ae0c257e..fdacc8c04d43 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -1,72 +1,192 @@ /turf icon = 'icons/turf/floors.dmi' - level = 1 - + level = LEVEL_BELOW_PLATING + abstract_type = /turf + is_spawnable_type = TRUE layer = TURF_LAYER + temperature_sensitive = TRUE + atom_flags = ATOM_FLAG_OPEN_CONTAINER - var/turf_flags + // Linear lazylist of weakrefs to dangerous things on this turf. + var/list/dangerous_objects - var/holy = 0 + /// Will participate in ZAS, join zones, etc. + var/zone_membership_candidate = FALSE + /// Will participate in external atmosphere simulation if the turf is outside and no zone is set. + var/external_atmosphere_participation = TRUE - // Initial air contents (in moles) + var/turf_flags + + /// Either a mapping of material decls to mol amounts, or a reserved initial gas define like GAS_STANDARD_AIRMIX. var/list/initial_gas //Properties for airtight tiles (/wall) var/thermal_conductivity = 0.05 - var/heat_capacity = 1 //Properties for both - var/blocks_air = 0 // Does this turf contain air/let air through? + /// Does this turf contain air/let air through? + var/blocks_air = FALSE // General properties. - var/icon_old = null var/pathweight = 1 // How much does it cost to pathfind over this turf? - var/blessed = 0 // Has the turf been blessed? var/list/decals - var/movement_delay + // Used for slowdown. + var/movement_delay = 0 var/fluid_can_pass - var/obj/effect/flood/flood_object - var/fluid_blocked_dirs = 0 + var/fluid_blocked_dirs = null var/flooded // Whether or not this turf is absolutely flooded ie. a water source. var/footstep_type + var/open_turf_type = /turf/open // Which open turf type to use by default above this turf in a multiz context. Overridden by area. + + // If you ever need to refill or flood a turf with more than two reagents, this should be rewritten entirely. + // The reason it's written like this is to avoid creating a new list for every turf with contaminants + // and that should still hold up even if you have turfs with three or more liquids in the mixture. + /// Reagent to contaminate refilled or flooded reagents. + var/contaminant_reagent_type + /// What fraction of the refilled/flooded liquid should be the contaminant? If zero, no contaminant is added. + var/contaminant_proportion var/tmp/changing_turf + var/tmp/prev_type // Previous type of the turf, prior to turf translation. + + // Some quick notes on the vars below: is_outside should be left set to OUTSIDE_AREA unless you + // EXPLICITLY NEED a turf to have a different outside state to its area (ie. you have used a + // roofing tile). By default, it will ask the area for the state to use, and will update on + // area change. When dealing with weather, it will check the entire z-column for interruptions + // that will prevent it from using its own state, so a floor above a level will generally + // override both area is_outside, and turf is_outside. The only time the base value will be used + // by itself is if you are dealing with a non-multiz level, or the top level of a multiz chunk. + + // Weather relies on is_outside to determine if it should apply to a turf or not and will be + // automatically updated on ChangeTurf set_outside etc. Don't bother setting it manually, it will + // get overridden almost immediately. + + // TL;DR: just leave these vars alone. + var/is_outside = OUTSIDE_AREA // non-tmp to allow visibility in mapper. + var/tmp/obj/abstract/weather_system/weather + var/tmp/last_outside_check = OUTSIDE_UNCERTAIN + + ///The cached air mixture of a turf. Never directly access, use `return_air()`. + //This exists to store air during zone rebuilds, as well as for unsimulated turfs. + //They are never deleted to not overwhelm the garbage collector. + var/datum/gas_mixture/air + ///Whether this tile is willing to copy air from a previous tile through ChangeTurf, transfer_turf_properties etc. + var/can_inherit_air = TRUE + ///Is this turf queued in the TURFS cycle of SSair? + var/needs_air_update = 0 + + ///The turf's current zone. + var/zone/zone + ///All directions in which a turf that can contain air is present. + var/airflow_open_directions + + /// Used by exterior turfs to determine the warming effect of campfires and such. + var/list/affecting_heat_sources + + // Fluid flow tracking vars + var/last_slipperiness = 0 + var/last_flow_strength = 0 + var/last_flow_dir = 0 + var/atom/movable/fluid_overlay/fluid_overlay + + // Temporary list of weakrefs of atoms who should be excepted from falling into us + var/list/skip_height_fall_for + + /// Floorlike structures like catwalks. Updated/retrieved by get_supporting_platform() + var/obj/structure/supporting_platform /turf/Initialize(mapload, ...) - . = ..() + . = null && ..() // This weird construct is to shut up the 'parent proc not called' warning without disabling the lint for child types. We explicitly return an init hint so this won't change behavior. + + _earliest_type ||= type + color = null + + // atom/Initialize has been copied here for performance (or at least the bits of it that turfs use has been) + if(atom_flags & ATOM_FLAG_INITIALIZED) + PRINT_STACK_TRACE("Warning: [src]([type]) initialized multiple times!") + atom_flags |= ATOM_FLAG_INITIALIZED + + if (light_range && light_power) + update_light() + if(dynamic_lighting) luminosity = 0 else luminosity = 1 - RecalculateOpacity() - if (mapload && permit_ao) + + // Reagents got deserialized, set them up. Do not return as we want to finish turf init. + // we don't care about volume because turfs always create a maximum volume holder on reagent add. + FINALIZE_REAGENTS_SERDE(reagents) + + AMBIENCE_QUEUE_TURF(src) + + if (opacity) + has_opaque_atom = TRUE + + if (!mapload) + SSair.mark_for_update(src) + update_weather(force_update_below = TRUE) + else if (permit_ao) queue_ao() + + // we're being loaded in a new z-level, we need to build lighting + if(mapload && !changing_turf && SSlighting.initialized) + lighting_build_overlay() + + if(simulated) + updateVisibility(src, FALSE) + if (z_flags & ZM_MIMIC_BELOW) setup_zmimic(mapload) - update_starlight() -/turf/on_update_icon() - update_flood_overlay() - queue_ao(FALSE) + if(flooded) + set_flooded(flooded, TRUE, skip_vis_contents_update = TRUE, mapload = mapload) + + update_vis_contents() + + if(simulated) + var/area/A = get_area(src) + if(istype(A) && (A.area_flags & AREA_FLAG_HOLY)) + turf_flags |= TURF_FLAG_HOLY + levelupdate() -/turf/proc/update_flood_overlay() - if(is_flooded(absolute = TRUE)) - if(!flood_object) - flood_object = new(src) - else if(flood_object) - QDEL_NULL(flood_object) + return INITIALIZE_HINT_NORMAL + +/turf/examined_by(mob/user, distance, infix, suffix) + . = ..() + if(user && weather) + weather.examined_by(user, distance, infix, suffix) /turf/Destroy() + + supporting_platform = null + + if(zone) + if(can_safely_remove_from_zone()) + c_copy_air() + zone.remove(src) + else + zone.rebuild() + + if(LAZYLEN(affecting_heat_sources)) + for(var/thing in affecting_heat_sources) + var/obj/structure/fire_source/heat_source = thing + LAZYREMOVE(heat_source.affected_exterior_turfs, src) + affecting_heat_sources = null + if (!changing_turf) - crash_with("Improper turf qdel. Do not qdel turfs directly.") + PRINT_STACK_TRACE("Improper turf qdel. Do not qdel turfs directly.") + + AMBIENCE_DEQUEUE_TURF(src) changing_turf = FALSE - remove_cleanables() - fluid_update() + if (contents.len > !!lighting_overlay) + remove_cleanables() + REMOVE_ACTIVE_FLUID_SOURCE(src) if (ao_queued) @@ -76,61 +196,132 @@ if (z_flags & ZM_MIMIC_BELOW) cleanup_zmimic() - if (bound_overlay) - QDEL_NULL(bound_overlay) + if (mimic_proxy) + QDEL_NULL(mimic_proxy) + + if(connections) + connections.erase_all() + + if(weather) + remove_vis_contents(weather.vis_contents_additions) + weather = null + + QDEL_NULL(fluid_overlay) ..() + return QDEL_HINT_IWILLGC /turf/explosion_act(severity) SHOULD_CALL_PARENT(FALSE) - return + if(severity == 1 || (severity == 2 && prob(70))) + drop_diggable_resources() /turf/proc/is_solid_structure() - return 1 + return !(turf_flags & TURF_FLAG_BACKGROUND) || locate(/obj/structure/lattice, src) -/turf/attack_hand(mob/user) - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) +/turf/proc/get_base_movement_delay(var/travel_dir, var/mob/mover) + return movement_delay - if(user.restrained()) - return 0 +/turf/proc/get_terrain_movement_delay(var/travel_dir, var/mob/mover) + . = get_base_movement_delay(travel_dir, mover) + if(weather) + . += weather.get_movement_delay(return_air(), travel_dir) + // TODO: check user species webbed feet, wearing swimming gear + if(!get_supporting_platform() && REAGENT_TOTAL_VOLUME(reagents) > FLUID_PUDDLE) + . += (REAGENT_TOTAL_VOLUME(reagents) > FLUID_SHALLOW) ? 6 : 3 - . = handle_hand_interception(user) +/turf/attack_hand(mob/user) -/turf/proc/handle_hand_interception(var/mob/user) - var/datum/extension/turf_hand/THE - for (var/A in src) - var/datum/extension/turf_hand/TH = get_extension(A, /datum/extension/turf_hand) - if (istype(TH) && TH.priority > THE?.priority) //Only overwrite if the new one is higher. For matching values, its first come first served - THE = TH + SHOULD_CALL_PARENT(FALSE) - if (THE) - return THE.OnHandInterception(user) + // Find an atom that should be intercepting this click. + var/datum/extension/turf_hand/highest_priority_intercept + for(var/atom/thing in contents) + var/datum/extension/turf_hand/intercept = get_extension(thing, /datum/extension/turf_hand) + if(intercept?.intercept_priority > highest_priority_intercept?.intercept_priority) + highest_priority_intercept = intercept + if(highest_priority_intercept) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + var/atom/intercepting_atom = highest_priority_intercept.holder + return intercepting_atom.attack_hand(user) + + return FALSE /turf/attack_robot(var/mob/user) - if(Adjacent(user)) - attack_hand(user) - -/turf/attackby(obj/item/W, mob/user) - - if(ATOM_IS_OPEN_CONTAINER(W) && W.reagents) - var/obj/effect/fluid/F = locate() in src - if(F && F.reagents?.total_volume) - var/taking = min(F.reagents?.total_volume, REAGENTS_FREE_SPACE(W.reagents)) - if(taking > 0) - to_chat(user, SPAN_NOTICE("You fill \the [src] with [F.reagents.get_primary_reagent_name()] from \the [src].")) - F.reagents.trans_to(W, taking) + return attack_hand_with_interaction_checks(user) + +/turf/grab_attack(obj/item/grab/grab, mob/user) + if (grab.affecting != user) + grab.affecting.DoMove(get_dir(grab.affecting.loc, src), user, TRUE) + return TRUE + +/turf/attackby(obj/item/used_item, mob/user) + + if(is_floor()) + + if(istype(used_item, /obj/item/stack/tile)) + var/obj/item/stack/tile/T = used_item + T.try_build_turf(user, src) + return TRUE + + if(IS_SHOVEL(used_item)) + + // TODO: move these checks into the interaction handlers. + var/atom/platform = get_supporting_platform() + if(platform) + to_chat(user, SPAN_WARNING("\The [platform] [platform.get_pronouns().is] in the way!")) + return TRUE + + if(!can_be_dug(used_item.material?.hardness)) + to_chat(user, SPAN_WARNING("\The [src] is too hard to be dug with \the [used_item].")) + return TRUE + + if(user.check_intent(I_FLAG_HELP) && can_dig_pit(used_item.material?.hardness)) + try_dig_pit(user, used_item) + else if(can_dig_trench(used_item.material?.hardness)) + try_dig_trench(user, used_item) + else + to_chat(user, SPAN_WARNING("You cannot dig anything out of \the [src] with \the [used_item].")) + return TRUE + + if(IS_HOE(used_item) && can_dig_farm(used_item.material?.hardness)) + try_dig_farm(user, used_item) + return TRUE + + var/decl/material/digging_material = get_material() + if(IS_PICK(used_item) && digging_material) + + // TODO: move these checks into the interaction handlers. + var/atom/platform = get_supporting_platform() + if(platform) + to_chat(user, SPAN_WARNING("\The [platform] [platform.get_pronouns().is] in the way!")) + return TRUE + + if(digging_material?.hardness <= MAT_VALUE_FLEXIBLE) + to_chat(user, SPAN_WARNING("\The [src] is too soft to be excavated with \the [used_item]. Use a shovel.")) + return TRUE + + // Let picks dig out hard turfs, but not dig pits. + if(!can_be_dug(used_item.material?.hardness, using_tool = TOOL_PICK)) + to_chat(user, SPAN_WARNING("\The [src] is too hard to be excavated with \the [used_item].")) return TRUE - if(istype(W, /obj/item/storage)) - var/obj/item/storage/S = W - if(S.use_to_pickup && S.collection_mode) - S.gather_all(src, user) + if(can_dig_trench(used_item.material?.hardness, using_tool = TOOL_PICK)) + try_dig_trench(user, used_item, using_tool = TOOL_PICK) + else + to_chat(user, SPAN_WARNING("You cannot excavate \the [src] with \the [used_item].")) + + return TRUE + + if(used_item?.storage?.collection_mode && used_item.storage.gather_all(src, user)) + return TRUE + + if(istype(used_item, /obj/item) && storage && storage.use_to_pickup && storage.collection_mode) + storage.gather_all(src, user) return TRUE - if(istype(W, /obj/item/grab)) - var/obj/item/grab/G = W - step(G.affecting, get_dir(G.affecting.loc, src)) + if(IS_COIL(used_item) && try_build_cable(used_item, user)) return TRUE return ..() @@ -174,44 +365,42 @@ if(!obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != obstacle)) mover.Bump(obstacle, 1) return 0 - return 1 //Nothing found to block so return success! - -var/const/enterloopsanity = 100 -/turf/Entered(var/atom/atom, var/atom/old_loc) - ..() - - QUEUE_TEMPERATURE_ATOMS(atom) - - if(!istype(atom, /atom/movable)) - return + // Check if they need to climb out of a hole. + if(mover.z == z && !is_open() && has_gravity() && !get_supporting_platform()) + var/mob/mover_mob = mover + if(!istype(mover_mob) || (!mover_mob.throwing && !mover_mob.can_overcome_gravity())) + var/turf/old_turf = mover.loc + var/old_height = old_turf.get_physical_height() + REAGENT_TOTAL_VOLUME(old_turf.reagents) + var/current_height = get_physical_height() + REAGENT_TOTAL_VOLUME(reagents) + if(abs(current_height - old_height) > FLUID_SHALLOW) + if(current_height > old_height && !is_open() && !old_turf?.is_open()) // check is_open() due to open turf depth stuff. + return 0 + if(istype(mover_mob) && MOVING_DELIBERATELY(mover_mob)) + to_chat(mover_mob, SPAN_WARNING("You refrain from stepping over the edge; it looks like a steep drop down to \the [src].")) + return 0 - var/atom/movable/A = atom - - var/objects = 0 - if(A && (A.movable_flags & MOVABLE_FLAG_PROXMOVE)) - for(var/atom/movable/thing in range(1)) - if(objects > enterloopsanity) break - objects++ - spawn(0) - if(A) - A.HasProximity(thing, 1) - if ((thing && A) && (thing.movable_flags & MOVABLE_FLAG_PROXMOVE)) - thing.HasProximity(A, 1) - return + return 1 //Nothing found to block so return success! -/turf/proc/adjacent_fire_act(turf/simulated/floor/source, exposed_temperature, exposed_volume) +/turf/proc/adjacent_fire_act(turf/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) return /turf/proc/is_plating() - return 0 + return FALSE /turf/proc/protects_atom(var/atom/A) return FALSE /turf/proc/levelupdate() - for(var/obj/O in src) - O.hide(O.hides_under_flooring() && !is_plating()) + if(is_open() || is_plating()) + for(var/obj/O in src) + O.hide(FALSE) + else if(is_wall()) + for(var/obj/O in src) + O.hide(TRUE) + else + for(var/obj/O in src) + O.hide(O.hides_under_flooring()) /turf/proc/AdjacentTurfs(var/check_blockage = TRUE) . = list() @@ -246,59 +435,56 @@ var/const/enterloopsanity = 100 L.Add(t) return L -/turf/proc/contains_dense_objects() - if(density) - return 1 +/turf/proc/get_first_dense_object(list/exceptions) for(var/atom/A in src) + if(exceptions && (exceptions == A || (islist(exceptions) && (A in exceptions)))) + continue if(A.density && !(A.atom_flags & ATOM_FLAG_CHECKS_BORDER)) - return 1 - return 0 + return A + return null -//expects an atom containing the reagents used to clean the turf -/turf/proc/clean(atom/source, mob/user = null, var/time = null, var/message = null) - if(source.reagents.has_reagent(/decl/material/liquid/water, 1) || source.reagents.has_reagent(/decl/material/liquid/cleaner, 1)) - if(user && time && !do_after(user, time, src)) - return - clean_blood() - remove_cleanables() - if(message) - to_chat(user, message) - else - to_chat(user, SPAN_WARNING("\The [source] is too dry to wash that.")) - source.reagents.touch_turf(src) +/turf/proc/contains_dense_objects(list/exceptions) + if(density) + return TRUE + return !!get_first_dense_object(exceptions) /turf/proc/remove_cleanables() - for(var/obj/effect/O in src) - if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) - qdel(O) - -/turf/proc/update_blood_overlays() - return + for(var/obj/effect/decal/cleanable/cleanable in src) + qdel(cleanable) /turf/proc/remove_decals() - if(decals && decals.len) - decals.Cut() - decals = null + LAZYCLEARLIST(decals) + update_icon() // Called when turf is hit by a thrown object /turf/hitby(atom/movable/AM, var/datum/thrownthing/TT) - if(src.density) + SHOULD_CALL_PARENT(FALSE) // /atom/hitby() applies damage to AM if it's a living mob. + . = TRUE + if(density) if(isliving(AM)) var/mob/living/M = AM M.turf_collision(src, TT.speed) - if(M.pinned) - return - addtimer(CALLBACK(src, /turf/proc/bounce_off, AM, TT.init_dir), 2) - -/turf/proc/bounce_off(var/atom/movable/AM, var/direction) - step(AM, turn(direction, 180)) + addtimer(CALLBACK(src, TYPE_PROC_REF(/turf, bounce_off), AM, TT), 2) + else if(isobj(AM)) + var/obj/structure/ladder/L = locate() in contents + if(L) + L.hitby(AM) + +/turf/proc/bounce_off(var/atom/movable/AM, var/datum/thrownthing/thrown) + if(AM.anchored) + return + if(ismob(AM)) + var/mob/living/M = AM + if(LAZYLEN(M.pinned)) + return + AM.throw_at(get_step(src, turn(thrown.init_dir, 180)), 1, thrown.speed / 2) /turf/proc/can_engrave() return FALSE /turf/proc/try_graffiti(var/mob/vandal, var/obj/item/tool) - if(!tool.sharp || !can_engrave() || vandal.a_intent != I_HELP) + if(!tool.is_sharp() || !can_engrave() || !vandal.check_intent(I_FLAG_HELP)) return FALSE if(jobban_isbanned(vandal, "Graffiti")) @@ -306,7 +492,7 @@ var/const/enterloopsanity = 100 return var/too_much_graffiti = 0 - for(var/obj/effect/decal/writing/W in src) + for(var/obj/effect/decal/writing/writing in src) too_much_graffiti++ if(too_much_graffiti >= 5) to_chat(vandal, "There's too much graffiti here to add more.") @@ -345,17 +531,440 @@ var/const/enterloopsanity = 100 /turf/proc/is_floor() return FALSE -/turf/proc/update_starlight() - if(!config.starlight) +/turf/proc/update_weather(var/obj/abstract/weather_system/new_weather, var/force_update_below = FALSE) + + if(isnull(new_weather)) + new_weather = SSweather.weather_by_z[z] + + // We have a weather system and we are exposed to it; update our vis contents. + if(istype(new_weather) && is_outside()) + if(weather != new_weather) + weather = new_weather + . = TRUE + + // We are indoors or there is no local weather system, clear our vis contents. + else if(weather) + weather = null + . = TRUE + + if(.) + update_vis_contents() + + // Propagate our weather downwards if we permit it. + if(force_update_below || (is_open() && .)) + var/turf/below = GetBelow(src) + if(below) + below.update_weather(new_weather) + +/// Updates turf participation in ZAS according to outside status and atmosphere participation bools. Must be called whenever any of those values may change. +/turf/proc/update_external_atmos_participation() + var/old_outside = last_outside_check + last_outside_check = OUTSIDE_UNCERTAIN + if(is_outside()) + if(zone && external_atmosphere_participation) + if(can_safely_remove_from_zone()) + zone.remove(src) + else + zone.rebuild() + else if(!zone && zone_membership_candidate && old_outside == OUTSIDE_YES) + // Set the turf's air to the external atmosphere to add to its new zone. + air = get_external_air(FALSE) + + SSair.mark_for_update(src) + +/turf/is_outside() + + // Can't rain inside or through solid walls. + // TODO: dense structures like full windows should probably also block weather. + if(density) + return OUTSIDE_NO + + if(last_outside_check != OUTSIDE_UNCERTAIN) + return last_outside_check + + // What is our local outside value? + // Some turfs can be roofed irrespective of the turf above them in multiz. + // I have the feeling this is redundat as a roofed turf below max z will + // have a floor above it, but ah well. + . = is_outside + if(. == OUTSIDE_AREA) + var/area/A = get_area(src) + . = A ? A.is_outside : OUTSIDE_NO + + // If we are in a multiz volume and not already inside, we return + // the outside value of the highest unenclosed turf in the stack. + if(HasAbove(z)) + . = OUTSIDE_YES // assume for the moment we're unroofed until we learn otherwise. + var/turf/top_of_stack = src + while(HasAbove(top_of_stack.z)) + var/turf/next_turf = GetAbove(top_of_stack) + if(!next_turf.is_open()) + return OUTSIDE_NO + top_of_stack = next_turf + // If we hit the top of the stack without finding a roof, we ask the upmost turf if we're outside. + . = top_of_stack.is_outside() + last_outside_check = . // Cache this for later calls. + +/turf/shuttle_rotate(angle) + . = ..() + if(. && LAZYLEN(decals)) + var/list/old_decals = decals.Copy() + decals.Cut() + // Duplicated cache logic from flooring_decals.dm + // Remove if the cache is removed + for(var/image/decal in old_decals) + var/image/detail_overlay = LAZYACCESS(decal.overlays, 1) + var/cache_key = "[decal.alpha]-[decal.color]-[SAFE_TURN(decal.dir, angle)]-[decal.icon_state]-[decal.plane]-[decal.layer]-[detail_overlay?.icon_state]-[detail_overlay?.color]-[decal.pixel_x]-[decal.pixel_y]" + if(!global.floor_decals[cache_key]) + var/image/I = image(icon = decal.icon, icon_state = decal.icon_state, dir = SAFE_TURN(decal.dir, angle)) + I.layer = decal.layer + I.appearance_flags = decal.appearance_flags + I.color = decal.color + I.alpha = decal.alpha + I.pixel_x = decal.pixel_x + I.pixel_y = decal.pixel_y + if(detail_overlay) + I.overlays |= overlay_image(decal.icon, detail_overlay.icon_state, color = detail_overlay.color, flags=RESET_COLOR) + global.floor_decals[cache_key] = I + decals |= global.floor_decals[cache_key] + update_icon() + +/turf/proc/set_outside(var/new_outside, var/skip_weather_update = FALSE) + if(is_outside == new_outside) + return FALSE + + state_was_modified() + is_outside = new_outside + update_external_atmos_participation() + AMBIENCE_QUEUE_TURF(src) + + if(!skip_weather_update) + update_weather() + + if(!HasBelow(z)) + return TRUE + + // Invalidate the outside check cache for turfs below us. + var/turf/checking = src + while(HasBelow(checking.z)) + checking = GetBelow(checking) + if(!isturf(checking)) + break + checking.update_external_atmos_participation() + if(!checking.is_open()) + break + return TRUE + +/turf/proc/get_air_graphic() + if(zone && !zone.invalid) + return zone.air?.graphic + if(external_atmosphere_participation && is_outside()) + var/datum/level_data/level = SSmapping.levels_by_z[z] + return level.exterior_atmosphere?.graphic + var/datum/gas_mixture/environment = return_air() + return environment?.graphic + +/turf/get_vis_contents_to_add() + var/air_graphic = get_air_graphic() + if(length(air_graphic)) + LAZYDISTINCTADD(., air_graphic) + if(length(weather?.vis_contents_additions)) + LAZYADD(., weather.vis_contents_additions) + . += pick(weather.particle_sources) // we know . is never null here + if(flooded) + var/flood_object = get_flood_overlay(flooded) + if(flood_object) + LAZYADD(., flood_object) + +/**Whether we can place a cable here + * If you cannot build a cable will return an error code explaining why you cannot. +*/ +/turf/proc/cannot_build_cable() + return 1 + +/**Sends a message to the user explaining why they can't build a cable here */ +/turf/proc/why_cannot_build_cable(var/mob/user, var/cable_error) + to_chat(user, SPAN_WARNING("You cannot place a cable here!")) + +/**Place a cable if possible, if not warn the user appropriately */ +/turf/proc/try_build_cable(var/obj/item/stack/cable_coil/C, var/mob/user) + var/cable_error = cannot_build_cable(user) + if(cable_error) + why_cannot_build_cable(user, cable_error) + return FALSE + return C.turf_place(src, user) + +/turf/singularity_act(S, current_size) + if(!simulated || is_open()) + return 0 + var/base_turf_type = get_base_turf_by_area(src) + if(type == base_turf_type) + return 0 + ChangeTurf(base_turf_type) + return 2 + +/turf/proc/resolve_to_actual_turf() + return src + +// Largely copied from stairs. +/turf/proc/can_move_up_ramp(atom/movable/AM, turf/above_wall, turf/under_atom, turf/above_atom) + if(!istype(AM) || !istype(above_wall) || !istype(under_atom) || !istype(above_atom)) + return FALSE + return under_atom.CanZPass(AM, UP) && above_atom.CanZPass(AM, DOWN) && above_wall.Enter(AM) + +/turf/Bumped(var/atom/movable/AM) + if(!istype(AM) || !HasAbove(z)) + return ..() + var/turf/wall/natural/slope = AM.loc + if(!istype(slope) || !slope.ramp_slope_direction || get_dir(src, slope) != slope.ramp_slope_direction) + return ..() + var/turf/above_wall = GetAbove(src) + if(can_move_up_ramp(AM, above_wall, get_turf(AM), GetAbove(AM))) + AM.forceMove(above_wall) + if(isliving(AM)) + var/mob/living/L = AM + for(var/obj/item/grab/grab as anything in L.get_active_grabs()) + grab.affecting.forceMove(above_wall) + else + to_chat(AM, SPAN_WARNING("Something blocks the path.")) + return TRUE + +/turf/clean(clean_forensics = TRUE) + for(var/obj/effect/decal/cleanable/filth in contents) + filth.clean(clean_forensics) + . = ..() + +//returns 1 if made bloody, returns 0 otherwise +/turf/add_blood(mob/living/M) + if(!simulated || !..() || !ishuman(M)) + return FALSE + var/mob/living/human/H = M + var/unique_enzymes = H.get_unique_enzymes() + var/blood_type = H.get_blood_type() + var/blood_reagent = H.species.blood_reagent + if(unique_enzymes && blood_type) + for(var/obj/effect/decal/cleanable/blood/B in contents) + if(B.chemical != blood_reagent) + continue + if(!LAZYACCESS(B.blood_DNA, unique_enzymes)) + LAZYSET(B.blood_DNA, unique_enzymes, blood_type) + LAZYSET(B.blood_data, unique_enzymes, REAGENT_DATA(H.vessel, H.species.blood_reagent)) + var/datum/extension/forensic_evidence/forensics = get_or_create_extension(B, /datum/extension/forensic_evidence) + forensics.add_data(/datum/forensics/blood_dna, unique_enzymes) + else + blood_splatter(src, M, 1) + return TRUE + +/// Creates a new /obj/effect/decal/cleanable/blood/tracks instance of a given type, +/// or merges it with an existing (not-yet-cleaned) one that matches typepath and chemical. +/// typepath is a type, not an instance +/// new_chemical is optional argument for things like muddy footprints, where typepath isn't enough +/turf/proc/AddTracks(obj/effect/decal/cleanable/blood/tracks/typepath, bloodDNA, comingdir, goingdir, bloodcolor = COLOR_BLOOD_HUMAN, new_chemical = null) + if(!simulated || check_fluid_depth(FLUID_QDEL_POINT)) return + // Populate defaults from the given typepath, where possible. + if(isnull(new_chemical)) + new_chemical = typepath::chemical || /decl/material/liquid/blood + + var/obj/effect/decal/cleanable/blood/tracks/tracks = null + for(var/obj/effect/decal/cleanable/blood/tracks/candidate in src) + if(!istype(candidate, typepath)) + continue + if(candidate.invisibility >= INVISIBILITY_ABSTRACT) // has been cleaned + continue + if(candidate.chemical != new_chemical) + continue + tracks = candidate + if(!tracks) + tracks = new typepath(src, null, new_chemical) + tracks.AddTracks(bloodDNA, comingdir, goingdir, bloodcolor) + +// Proc called in /turf/Entered() to supply an appropriate fluid overlay. +/turf/proc/get_movable_alpha_mask_state(atom/movable/mover) + if(flooded) + return null + if(ismob(mover)) + var/mob/moving_mob = mover + if(moving_mob.can_overcome_gravity()) + return null + if(!get_supporting_platform()) + var/fluid_depth = get_fluid_depth() + if(fluid_depth > FLUID_PUDDLE) + if(fluid_depth <= FLUID_SHALLOW) + return "mask_shallow" + if(fluid_depth <= FLUID_DEEP) + return "mask_deep" + +/turf/spark_act(obj/effect/sparks/sparks) + if(simulated) + hotspot_expose(1000,100) + for(var/atom/thing in contents) + if(thing.simulated && prob(25)) + thing.spark_act(sparks) + return TRUE + return FALSE + +/turf/proc/get_trench_name() + if(check_fluid_depth(FLUID_SHALLOW)) + return get_fluid_name() + return src + +/turf/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && simulated && dropping == user && isturf(user.loc) && user.Adjacent(src)) + var/turf/other_turf = user.loc + var/our_height = get_physical_height() + var/their_height = other_turf.get_physical_height() + if(abs(our_height-their_height) > FLUID_SHALLOW) + . = TRUE + if(our_height < their_height) + user.visible_message(SPAN_NOTICE("\The [user] starts climbing down into \the [get_trench_name()].")) + else + user.visible_message(SPAN_NOTICE("\The [user] starts climbing out of \the [other_turf.get_trench_name()].")) + if(!do_after(user, 2 SECONDS, src) || QDELETED(user) || user?.loc != other_turf || !user.Adjacent(src)) + return + if(our_height < their_height) + user.visible_message(SPAN_NOTICE("\The [user] climbs down into \the [get_trench_name()].")) + else + user.visible_message(SPAN_NOTICE("\The [user] climbs out of \the [other_turf.get_trench_name()].")) + LAZYDISTINCTADD(skip_height_fall_for, weakref(user)) + user.dropInto(src) + LAZYREMOVE(skip_height_fall_for, weakref(user)) + +/turf/proc/handle_universal_decay() + return + +/turf/proc/get_plant_growth_rate() + return 0 + +/turf/proc/get_soil_color() + return null + +/turf/get_color() + return paint_color || get_material()?.color || color + +/turf/proc/get_fishing_result(obj/item/food/bait) var/area/A = get_area(src) - if(!A.show_starlight) + return A.get_fishing_result(src, bait) + +/turf/get_affecting_weather() + return weather + +/turf/can_be_poured_into(atom/source) + return !density + +/turf/proc/get_supporting_platform() + if(isnull(supporting_platform)) + for(var/obj/structure/platform in get_contained_external_atoms()) + if(platform.is_platform()) + supporting_platform = platform + break + return supporting_platform + +/turf/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/show_turf_contents) + var/obj/item/held = user ? (user.get_active_held_item() || user.get_usable_hand_slot_organ()) : null + if(!istype(held)) return - //Let's make sure not to break everything if people use a crazy setting. - var/turf/T = locate(/turf/simulated) in RANGE_TURFS(src,1) - if(T) - A = get_area(T) - if(A && A.dynamic_lighting) - set_light(min(0.1*config.starlight, 1), 1, 3, l_color = SSskybox.background_color) - return - set_light(0) \ No newline at end of file + if(is_open()) + if(HasBelow(z)) + LAZYADD(., /decl/interaction_handler/dig_ramp_from_above) + else + if(IS_SHOVEL(held)) + if(can_dig_pit(held.material?.hardness)) + LAZYADD(., /decl/interaction_handler/dig/pit) + if(can_dig_trench(held.material?.hardness)) + LAZYADD(., /decl/interaction_handler/dig/trench) + if(IS_PICK(held) && can_dig_trench(held.material?.hardness, using_tool = TOOL_PICK)) + LAZYADD(., /decl/interaction_handler/dig/trench) + if(IS_HOE(held) && can_dig_farm(held.material?.hardness)) + LAZYADD(., /decl/interaction_handler/dig/farm) + +/// Contaminant may be the chemical decl of the footprint being provided, +/// or null if we just want to know if we support footprints, at all, ever. +/turf/proc/can_show_coating_footprints(decl/material/contaminant) + return simulated + +/turf/proc/is_purged() + return + +/decl/interaction_handler/show_turf_contents + name = "Show Turf Contents" + expected_user_type = /mob + interaction_flags = 0 + examine_desc = "list everything on the turf" + +/decl/interaction_handler/show_turf_contents/invoked(atom/target, mob/user, obj/item/prop) + target.show_atom_list_for_turf(user, get_turf(target)) + +/decl/interaction_handler/dig + abstract_type = /decl/interaction_handler/dig + expected_user_type = /mob + expected_target_type = /turf + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEEDS_TURF + +/decl/interaction_handler/dig/trench + name = "Dig Trench" + examine_desc = "dig a trench" + +/decl/interaction_handler/dig/trench/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(. && istype(target, /turf/floor)) + var/turf/floor/target_turf = target + return target_turf.flooring_is_diggable() + +/decl/interaction_handler/dig/trench/invoked(atom/target, mob/user, obj/item/prop) + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + var/turf/T = get_turf(target) + if(IS_SHOVEL(prop)) + if(T.can_dig_trench(prop?.material?.hardness)) + T.try_dig_trench(user, prop) + else if(IS_PICK(prop)) + var/decl/material/digging_material = T.get_material() + if(digging_material?.hardness > MAT_VALUE_FLEXIBLE && T.can_dig_trench(prop?.material?.hardness, using_tool = TOOL_PICK)) + T.try_dig_trench(user, prop, using_tool = TOOL_PICK) + +/decl/interaction_handler/dig/pit + name = "Dig Pit" + examine_desc = "dig a pit" + +/decl/interaction_handler/dig/pit/invoked(atom/target, mob/user, obj/item/prop) + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + var/turf/T = get_turf(target) + if(T.can_dig_pit(prop?.material?.hardness)) + T.try_dig_pit(user, prop) + +/decl/interaction_handler/dig/farm + name = "Dig Farm Plot" + examine_desc = "dig a farm plot" + +/decl/interaction_handler/dig/farm/invoked(atom/target, mob/user, obj/item/prop) + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + var/turf/T = get_turf(target) + if(T.can_dig_farm(prop?.material?.hardness)) + T.try_dig_farm(user, prop) + +/turf/take_vaporized_reagent(reagent, amount) + return assume_gas(reagent, round(amount / REAGENT_UNITS_PER_GAS_MOLE)) + +// Tells the turf that it currently contains something that automated movement should consider if planning to enter the tile. +// This uses lazy list macros to reduce memory footprint, since for 99% of turfs the list would've been empty anyways. +/turf/proc/register_dangerous_object(atom/thing) + if(!istype(thing)) + return FALSE + LAZYDISTINCTADD(dangerous_objects, weakref(thing)) + +// Similar to above, for when the dangerous object stops being dangerous/gets deleted/moved/etc. +/turf/proc/unregister_dangerous_object(atom/thing) + if(!istype(thing)) + return FALSE + LAZYREMOVE(dangerous_objects, weakref(thing)) + +/turf/proc/is_safe_to_enter(mob/living/stepper) + if(LAZYLEN(dangerous_objects)) + for(var/weakref/ref in dangerous_objects) + var/atom/thing = ref.resolve() + if(istype(thing) && !QDELETED(thing) && !thing.is_safe_to_step(stepper)) + return FALSE + return TRUE diff --git a/code/game/turfs/turf_ao.dm b/code/game/turfs/turf_ao.dm index c33bf4eeb0fa..c07ebeceb522 100644 --- a/code/game/turfs/turf_ao.dm +++ b/code/game/turfs/turf_ao.dm @@ -10,10 +10,11 @@ var/ao_queued = AO_UPDATE_NONE /turf/proc/regenerate_ao() - for (var/thing in RANGE_TURFS(src, 1)) - var/turf/T = thing - if (T.permit_ao) - T.queue_ao(TRUE) + for(var/thing in RANGE_TURFS(src, 1)) + var/turf/their_turf = thing + their_turf = their_turf.resolve_to_actual_turf() + if(their_turf.permit_ao) + their_turf.queue_ao(TRUE) /turf/proc/calculate_ao_neighbors() ao_neighbors = 0 @@ -32,7 +33,7 @@ var/cstr = "[corner]" var/key = "[cstr]-[i]-[px]/[py]/[pz]/[pw]" - var/image/I = image('icons/turf/flooring/shadows.dmi', cstr, dir = 1 << (i-1)) + var/image/I = image('icons/turf/flooring/shadows.dmi', cstr, dir = BITFLAG(i-1)) I.alpha = WALL_AO_ALPHA I.blend_mode = BLEND_OVERLAY I.appearance_flags = RESET_ALPHA|RESET_COLOR|TILE_BOUND @@ -56,13 +57,13 @@ #define PROCESS_AO_CORNER(AO_LIST, NEIGHBORS, CORNER_INDEX, CDIR) \ corner = 0; \ - if (NEIGHBORS & (1 << CDIR)) { \ + if (NEIGHBORS & (BITFLAG(CDIR))) { \ corner |= 2; \ } \ - if (NEIGHBORS & (1 << turn(CDIR, 45))) { \ + if (NEIGHBORS & (BITFLAG(turn(CDIR, 45)))) { \ corner |= 1; \ } \ - if (NEIGHBORS & (1 << turn(CDIR, -45))) { \ + if (NEIGHBORS & (BITFLAG(turn(CDIR, -45)))) { \ corner |= 4; \ } \ if (corner != 7) { /* 7 is the 'no shadows' state, no reason to add overlays for it. */ \ @@ -88,7 +89,7 @@ PROCESS_AO_CORNER(AO_LIST, NEIGHBORS, 4, SOUTHWEST); \ } \ UNSETEMPTY(AO_LIST); \ - if (AO_LIST) { \ + if (AO_LIST && TARGET) { \ TARGET.add_overlay(AO_LIST, TRUE); \ } @@ -98,7 +99,7 @@ CUT_AO(src, ao_overlays) if (z_flags & ZM_MIMIC_BELOW) REGEN_AO(shadower, ao_overlays_mimic, ao_neighbors_mimic) - if (AO_TURF_CHECK(src) && !(z_flags & ZM_MIMIC_NO_AO)) + if (AO_SELF_CHECK(src) && !(z_flags & ZM_MIMIC_NO_AO)) REGEN_AO(src, ao_overlays, ao_neighbors) update_above() @@ -107,10 +108,3 @@ #undef PROCESS_AO_CORNER #undef AO_TURF_CHECK #undef AO_SELF_CHECK - -/turf/ChangeTurf() - var/old_density = density - var/old_permit_ao = permit_ao - . = ..() - if(density != old_density || permit_ao != old_permit_ao) - regenerate_ao() diff --git a/code/game/turfs/turf_buildmode.dm b/code/game/turfs/turf_buildmode.dm new file mode 100644 index 000000000000..ee3d39c337f4 --- /dev/null +++ b/code/game/turfs/turf_buildmode.dm @@ -0,0 +1,32 @@ +/turf/proc/get_build_mode_upgrade() + return null + +/turf/space/get_build_mode_upgrade() + return /turf/floor/plating + +/turf/open/get_build_mode_upgrade() + return /turf/floor/plating + +/turf/floor/plating/get_build_mode_upgrade() + return /turf/floor/tiled + +/turf/floor/get_build_mode_upgrade() + return /turf/wall + +/turf/wall/get_build_mode_upgrade() + return /turf/wall/r_wall + +/turf/proc/get_build_mode_downgrade() + return null + +/turf/floor/get_build_mode_downgrade() + return /turf/floor/plating + +/turf/floor/plating/get_build_mode_downgrade() + return /turf/open + +/turf/wall/get_build_mode_downgrade() + return /turf/floor/plating + +/turf/wall/r_wall/get_build_mode_downgrade() + return /turf/wall diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index 385ab3dfd8f3..0dfa901cf988 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -1,108 +1,216 @@ -/turf/proc/ReplaceWithLattice(var/material) - var base_turf = get_base_turf_by_area(src); - if(type != base_turf) - src.ChangeTurf(get_base_turf_by_area(src)) - if(!locate(/obj/structure/lattice) in src) - new /obj/structure/lattice(src, material) - -// Removes all signs of lattice on the pos of the turf -Donkieyo -/turf/proc/RemoveLattice() - var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) - if(L) - qdel(L) +/turf/proc/switch_to_base_turf(keep_air) + var/base_turf = get_base_turf_by_area(src) + if(base_turf && type != base_turf) + return ChangeTurf(base_turf, keep_air = keep_air) + return src + +/turf/proc/dismantle_turf(devastated, explode, no_product, keep_air = TRUE) + var/turf/new_turf = switch_to_base_turf(keep_air) + if(!no_product && istype(new_turf) && !new_turf.is_open() && !(locate(/obj/structure/lattice) in new_turf)) + new /obj/structure/lattice(new_turf) + return !!new_turf + +/turf/physically_destroyed(var/skip_qdel) + SHOULD_CALL_PARENT(FALSE) + return dismantle_turf(TRUE) + // Called after turf replaces old one /turf/proc/post_change() levelupdate() if (above) above.update_mimic() -/turf/physically_destroyed() - SHOULD_CALL_PARENT(FALSE) - . = TRUE +// Updates open turfs above this one to use its open_turf_type +/turf/proc/update_open_above(var/restrict_type, var/respect_area = TRUE) + if(!HasAbove(src.z)) + return + var/turf/above = src + while ((above = GetAbove(above))) + if(!above.is_open()) + break + if(!restrict_type || istype(above, restrict_type)) + if(respect_area) + var/area/A = get_area(above) + above.ChangeTurf(A?.open_turf || open_turf_type, keep_air = TRUE, update_open_turfs_above = FALSE) + else + above.ChangeTurf(open_turf_type, keep_air = TRUE, update_open_turfs_above = FALSE) + +/turf/proc/ChangeTurf(var/turf/N, var/tell_universe = TRUE, var/force_lighting_update = FALSE, var/keep_air = FALSE, var/update_open_turfs_above = TRUE, var/keep_height = FALSE) -//Creates a new turf -/turf/proc/ChangeTurf(var/turf/N, var/tell_universe = TRUE, var/force_lighting_update = FALSE, var/keep_air = FALSE) if (!N) return - // This makes sure that turfs are not changed to space when one side is part of a zone - if(N == /turf/space) + // Spawning space in the middle of a multiz stack should just spawn an open turf. + if(ispath(N, /turf/space)) var/turf/below = GetBelow(src) - if(istype(below) && !istype(below,/turf/space)) - N = /turf/simulated/open + if(istype(below) && !isspaceturf(below)) + var/area/A = get_area(src) + N = A?.open_turf || open_turf_type || /turf/open + + if (!(atom_flags & ATOM_FLAG_INITIALIZED)) + return new N(src) + + // Rebuilt on next call. + supporting_platform = null - var/old_air = air - var/old_fire = fire - var/old_opacity = opacity - var/old_dynamic_lighting = dynamic_lighting + // Track a number of old values for the purposes of raising + // state change events after changing the turf to the new type. + var/old_earliest_type = _earliest_type + var/old_fire = fire + var/old_above = above + var/old_opacity = opacity + var/old_density = density + var/old_corners = corners + var/old_prev_type = prev_type var/old_affecting_lights = affecting_lights var/old_lighting_overlay = lighting_overlay - var/old_corners = corners - var/old_ao_neighbors = ao_neighbors - var/old_above = above + var/old_dynamic_lighting = TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) + var/old_z_opacity = z_flags & ZM_ALLOW_LIGHTING + var/old_flooded = flooded + var/old_outside = is_outside + var/old_is_open = is_open() + var/old_open_turf_type = open_turf_type + var/old_affecting_heat_sources = affecting_heat_sources + var/old_height = get_physical_height() + var/old_alpha_mask_state = get_movable_alpha_mask_state(null) + var/old_event_listeners = event_listeners + var/old_listening_to = _listening_to -// log_debug("Replacing [src.type] with [N]") + var/old_ambience = ambient_light + var/old_ambience_mult = ambient_light_multiplier + var/old_ambient_light_old_r = ambient_light_old_r + var/old_ambient_light_old_g = ambient_light_old_g + var/old_ambient_light_old_b = ambient_light_old_b + var/old_dangerous_objects = dangerous_objects - changing_turf = TRUE + var/old_zone_membership_candidate = zone_membership_candidate - if(connections) connections.erase_all() + // Create a copy of the old air value to apply. + var/datum/gas_mixture/old_air + if(keep_air) + // Bypass calling return_air to avoid creating a direct reference to zone air. + if(zone) + c_copy_air() + old_air = air + else + old_air = return_air() - overlays.Cut() - underlays.Cut() + changing_turf = TRUE - // Run the Destroy() chain. qdel(src) + . = new N(src) - var/old_opaque_counter = opaque_counter - var/turf/simulated/W = new N(src) + var/turf/changed_turf = . + changed_turf.above = old_above // Multiz ref tracking. + changed_turf.prev_type = old_prev_type // Shuttle transition turf tracking. + // Set our observation bookkeeping lists back. + changed_turf.event_listeners = old_event_listeners + changed_turf._listening_to = old_listening_to + changed_turf.dangerous_objects = old_dangerous_objects - above = old_above + changed_turf.affecting_heat_sources = old_affecting_heat_sources if (permit_ao) regenerate_ao() - W.opaque_counter = old_opaque_counter - W.RecalculateOpacity() - - if (keep_air) - W.air = old_air + // Update ZAS, atmos and fire. + if(keep_air && changed_turf.can_inherit_air) + changed_turf.air = old_air + if(old_fire) + if(changed_turf.simulated) + changed_turf.fire = old_fire + else if(old_fire) + qdel(old_fire) - if(ispath(N, /turf/simulated)) - if(old_fire) - fire = old_fire - if (istype(W,/turf/simulated/floor)) - W.RemoveLattice() - else if(old_fire) - qdel(old_fire) + if(old_flooded != changed_turf.flooded) + set_flooded(old_flooded) + // Raise appropriate events. + changed_turf.post_change() if(tell_universe) - GLOB.universe.OnTurfChange(W) - - SSair.mark_for_update(src) //handle the addition of the new turf. - - for(var/turf/S in range(W,1)) - S.update_starlight() - - W.post_change() - . = W - - W.ao_neighbors = old_ao_neighbors - if(lighting_overlays_initialised) - lighting_overlay = old_lighting_overlay - affecting_lights = old_affecting_lights - corners = old_corners - if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting)) - reconsider_lights() - if(dynamic_lighting != old_dynamic_lighting) - if(dynamic_lighting) - lighting_build_overlay() - else - lighting_clear_overlay() + global.universe.OnTurfChange(changed_turf) + + if(changed_turf.density != old_density && changed_turf.event_listeners?[/decl/observ/density_set]) + changed_turf.raise_event_non_global(/decl/observ/density_set, old_density, changed_turf.density) + + // lighting stuff + + affecting_lights = old_affecting_lights + corners = old_corners + + lighting_overlay = old_lighting_overlay + + recalc_atom_opacity() + + ambient_light_old_r = old_ambient_light_old_r + ambient_light_old_g = old_ambient_light_old_g + ambient_light_old_b = old_ambient_light_old_b - for(var/turf/T in RANGE_TURFS(src, 1)) - T.update_icon() + if (old_ambience != ambient_light || old_ambience_mult != ambient_light_multiplier) + update_ambient_light(FALSE) -/turf/proc/transport_properties_from(turf/other) + var/new_z_opacity = z_flags & ZM_ALLOW_LIGHTING + if (new_z_opacity != old_z_opacity) + for (var/datum/lighting_corner/corn in corners) + corn.rebuild_ztraversal(!new_z_opacity) + + var/tidlu = TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) + if ((old_opacity != opacity) || (tidlu != old_dynamic_lighting) || force_lighting_update) + reconsider_lights() + + if (tidlu != old_dynamic_lighting && SSlighting.initialized) // don't fuck with lighting before lighting flush + if (tidlu) + lighting_build_overlay() + else + lighting_clear_overlay() + + // end of lighting stuff + + // we check the var rather than the proc, because area outside values usually shouldn't be set on turfs + changed_turf.last_outside_check = OUTSIDE_UNCERTAIN + if(changed_turf.is_outside != old_outside) + // This will check the exterior atmos participation of this turf and all turfs connected by open space below. + changed_turf.set_outside(old_outside, skip_weather_update = TRUE) + else // We didn't already update our external atmos participation in set_outside. + if(HasBelow(z) && (changed_turf.is_open() != old_is_open)) // Otherwise, we do it here if the open status of the turf has changed. + var/turf/checking = src + while(HasBelow(checking.z)) + checking = GetBelow(checking) + if(!isturf(checking)) + break + checking.update_external_atmos_participation() + if(!checking.is_open()) + break + // In case the turf isn't marked for update in Initialize (e.g. space), we call this to create any unsimulated edges necessary. + if(changed_turf.zone_membership_candidate != old_zone_membership_candidate) + update_external_atmos_participation() + + changed_turf.update_weather(force_update_below = changed_turf.is_open() != old_is_open) + + if(keep_height) + changed_turf.set_physical_height(old_height) + + if(update_open_turfs_above) + update_open_above(old_open_turf_type) + + if(old_alpha_mask_state != get_movable_alpha_mask_state(null)) + for(var/atom/movable/AM as anything in changed_turf) + AM.update_turf_alpha_mask() + + // Anything on our turf needs to fall down. + if(HasBelow(z) && changed_turf.is_open() && !old_is_open) + for(var/atom/movable/thing in changed_turf.get_contained_external_atoms()) + thing.fall() + + changed_turf._earliest_type = old_earliest_type + changed_turf.state_was_modified() + +/turf/proc/transport_properties_from(turf/other, transport_air) + if(transport_air && can_inherit_air && (other.zone || other.air)) + if(!air) + make_air() + air.copy_from(other.zone ? other.zone.air : other.air) + other.zone?.remove(other) if(!istype(other, src.type)) return 0 src.set_dir(other.dir) @@ -115,25 +223,38 @@ src.update_icon() return 1 -//I would name this copy_from() but we remove the other turf from their air zone for some reason -/turf/simulated/transport_properties_from(turf/simulated/other) +/turf/floor/transport_properties_from(turf/floor/other) if(!..()) - return 0 + return FALSE - if(other.zone) - if(!src.air) - src.make_air() - src.air.copy_from(other.zone.air) - other.zone.remove(other) - return 1 + // Unlint this to copy the actual raw vars. + UNLINT(_flooring = other._flooring) + if(islist(_flooring)) + _flooring = _flooring.Copy() + UNLINT(_base_flooring = other._base_flooring) + set_floor_broken(other._floor_broken, TRUE) + set_floor_burned(other._floor_burned) + return TRUE -/turf/simulated/wall/transport_properties_from(turf/simulated/wall/other) +/turf/wall/transport_properties_from(turf/wall/other) if(!..()) - return 0 + return FALSE + paint_color = other.paint_color - return 1 + stripe_color = other.stripe_color + + material = other.material + reinf_material = other.reinf_material + girder_material = other.girder_material + + floor_type = other.floor_type + construction_stage = other.construction_stage + + damage = other.damage + + // Do not set directly to other.can_open since it may be in the WALL_OPENING state. + if(other.can_open) + can_open = WALL_CAN_OPEN -//No idea why resetting the base appearence from New() isn't enough, but without this it doesn't work -/turf/simulated/shuttle/wall/corner/transport_properties_from(turf/simulated/other) - . = ..() - reset_base_appearance() + update_material() + return TRUE diff --git a/code/game/turfs/turf_digging.dm b/code/game/turfs/turf_digging.dm new file mode 100644 index 000000000000..41be30031860 --- /dev/null +++ b/code/game/turfs/turf_digging.dm @@ -0,0 +1,80 @@ +/// Return an assoc list of resource item type to a metadata list containing base amount, random component, and material override +/// ex. return list(/obj/item/stack/material/ore/handful/sand = list("amount" = 3, "variance" = 2, "material" = /decl/material/foo)) +/turf/proc/get_diggable_resources() + return null + +/turf/proc/clear_diggable_resources() + SHOULD_CALL_PARENT(TRUE) + update_icon() + +/turf/proc/can_be_dug(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return FALSE + +/turf/proc/drop_diggable_resources(mob/user) + SHOULD_CALL_PARENT(TRUE) + var/list/diggable_resources = get_diggable_resources() + if(!length(diggable_resources)) + return + for(var/resource_type in diggable_resources) + + var/list/resource_data = diggable_resources[resource_type] + var/list/loot = list() + var/amount = max(1, resource_data["amount"] + resource_data["variance"]) + var/spawn_material = resource_data["material"] + + if(ispath(resource_type, /obj/item/stack)) + loot += new resource_type(src, amount, spawn_material) + else + for(var/i = 1 to amount) + loot += new resource_type(src, spawn_material) + + if(length(loot)) + if(user) + for(var/obj/item/thing in loot) + if(thing.material && thing.material != get_material()) + to_chat(user, SPAN_NOTICE("You unearth \a [thing]!")) + LAZYADD(., loot) + + for(var/obj/item/stack/stack in .) + stack.add_to_stacks() + + clear_diggable_resources() + +// Procs for digging pits. +/turf/proc/can_dig_pit(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return can_be_dug(tool_hardness, using_tool) && !(locate(/obj/structure/pit) in src) + +/turf/proc/try_dig_pit(var/mob/user, var/obj/item/tool, using_tool = TOOL_SHOVEL) + if((!user && !tool) || tool.do_tool_interaction(using_tool, user, src, 5 SECONDS, check_skill = SKILL_HAULING, set_cooldown = TRUE)) + return dig_pit(user, tool?.material?.hardness, using_tool) + return null + +/turf/proc/dig_pit(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return can_dig_pit(tool_hardness, using_tool) && new /obj/structure/pit(src) + +// Procs for digging farms. +/turf/proc/can_dig_farm(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return get_plant_growth_rate() > 0 && can_be_dug(tool_hardness, using_tool) && !(locate(/obj/machinery/portable_atmospherics/hydroponics/soil) in src) + +/turf/proc/try_dig_farm(mob/user, obj/item/tool, using_tool = TOOL_HOE) + var/decl/material/turf_material = get_material() + if(!turf_material?.tillable) + return + if((!user && !tool) || tool.do_tool_interaction(using_tool, user, src, 5 SECONDS, set_cooldown = TRUE, check_skill = SKILL_BOTANY)) + return dig_farm(user, tool?.material?.hardness, using_tool) + return null + +/turf/proc/dig_farm(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return can_dig_farm(tool_hardness, using_tool) && new /obj/machinery/portable_atmospherics/hydroponics/soil(src) + +// Proc for digging trenches. +/turf/proc/can_dig_trench(tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return can_be_dug(tool_hardness, using_tool) && (HasBelow(z) || get_physical_height() > -(FLUID_DEEP)) + +/turf/proc/try_dig_trench(mob/user, obj/item/tool, using_tool = TOOL_SHOVEL) + if((!user && !tool) || tool.do_tool_interaction(using_tool, user, src, 2.5 SECONDS, check_skill = SKILL_HAULING, set_cooldown = TRUE)) + return dig_trench(user, tool?.material?.hardness, using_tool) + return null + +/turf/proc/dig_trench(mob/user, tool_hardness = MAT_VALUE_MALLEABLE, using_tool = TOOL_SHOVEL) + return FALSE diff --git a/code/game/turfs/turf_effects.dm b/code/game/turfs/turf_effects.dm new file mode 100644 index 000000000000..93e5da6a91ee --- /dev/null +++ b/code/game/turfs/turf_effects.dm @@ -0,0 +1,61 @@ +/turf/proc/get_wetness() + if(!simulated) + return 0 + var/atom/movable/wet_floor/wet_decal = locate() in src + return wet_decal?.wetness || 0 + +/turf/proc/wet_floor(var/wet_val = 1, var/overwrite = FALSE) + if(!simulated || is_flooded(absolute = TRUE) || get_fluid_depth() > FLUID_QDEL_POINT) + return FALSE + var/atom/movable/wet_floor/wet_decal = locate() in src + if(wet_val < wet_decal?.wetness && !overwrite) + return FALSE + if(!wet_decal) + wet_decal = new(src) + wet_decal.wetness = wet_val + wet_decal.wet_timer_id = addtimer(CALLBACK(wet_decal, TYPE_PROC_REF(/atom/movable/wet_floor, unwet_floor)), 8 SECONDS, (TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE)) + return TRUE + +/turf/proc/unwet_floor(var/check_very_wet = TRUE) + if(!simulated) + return FALSE + var/atom/movable/wet_floor/wet_decal = locate() in src + if(!wet_decal) + return FALSE + if(check_very_wet && wet_decal.wetness >= 2) + wet_decal.wetness-- + wet_decal.wet_timer_id = addtimer(CALLBACK(wet_decal, TYPE_PROC_REF(/atom/movable/wet_floor, unwet_floor)), 8 SECONDS, (TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE)) + else + qdel(wet_decal) + return TRUE + +#define MAX_DIRT 101 +/turf/proc/add_dirt(amount) + if(!simulated) + return FALSE + var/obj/effect/decal/cleanable/dirt/dirt = locate() in src + if(!dirt) + dirt = new(src) + dirt.dirt_amount = min(dirt.dirt_amount + amount, MAX_DIRT) + dirt.update_icon() + return TRUE +#undef MAX_DIRT + +/turf/proc/remove_dirt(amount) + if(!simulated) + return FALSE + var/obj/effect/decal/cleanable/dirt/dirt = locate() in src + if(!dirt) + return FALSE + dirt.dirt_amount = min(dirt.dirt_amount - amount, 0) + if(dirt.dirt_amount) + dirt.update_icon() + else + qdel(dirt) + return TRUE + +/turf/proc/get_dirt(amount) + if(!simulated) + return 0 + var/obj/effect/decal/cleanable/dirt/dirt = locate() in src + return dirt?.dirt_amount || 0 diff --git a/code/game/turfs/turf_enter.dm b/code/game/turfs/turf_enter.dm new file mode 100644 index 000000000000..cb1849868ab6 --- /dev/null +++ b/code/game/turfs/turf_enter.dm @@ -0,0 +1,82 @@ +#define ENTER_PROXIMITY_LOOP_SANITY 100 +// Splitting this into its own proc for profiling purposes. +/turf/proc/handle_proximity_update(var/atom/movable/mover) + var/objects = 0 + if(!istype(mover) || !(mover.movable_flags & MOVABLE_FLAG_PROXMOVE)) + return + for(var/atom/movable/neighbor in range(1)) + if(objects > ENTER_PROXIMITY_LOOP_SANITY) + break // Don't let ore piles kill the server as well as the client. + if(neighbor.movable_flags & MOVABLE_FLAG_PROXMOVE) + objects++ + mover.HasProximity(neighbor) + if(!QDELETED(neighbor) && !QDELETED(mover)) + neighbor.HasProximity(mover) + +#undef ENTER_PROXIMITY_LOOP_SANITY +/turf/Entered(var/atom/movable/A, var/atom/old_loc) + ..() + if(istype(A) && !QDELETED(A) && A.simulated) + queue_temperature_atoms(A) + A.update_turf_alpha_mask() + +// If an opaque movable atom moves around we need to potentially update visibility. + if(A?.opacity && !has_opaque_atom) + has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. + reconsider_lights() +#ifdef AO_USE_LIGHTING_OPACITY + // Hook for AO. + regenerate_ao() +#endif + + var/obj/structure/platform = get_supporting_platform() + if(isturf(old_loc) && has_gravity() && A.can_fall() && !isnull(platform) && !(weakref(A) in skip_height_fall_for)) + + var/turf/old_turf = old_loc + var/old_height = old_turf.get_physical_height() + REAGENT_TOTAL_VOLUME(old_turf.reagents) + var/current_height = get_physical_height() + REAGENT_TOTAL_VOLUME(reagents) + var/height_difference = abs(current_height - old_height) + + if(current_height < old_height && height_difference > FLUID_SHALLOW) + visible_message("\The [A] falls into \the [reagents?.get_primary_reagent_name() || "hole"]!") + if(isliving(A)) + var/mob/living/mover = A + var/decl/bodytype/body = mover.get_bodytype() + if(body) + playsound(src, body.bodyfall_sounds, 50, 1, 1) + SET_STATUS_MAX(mover, STAT_WEAK, rand(3,4)) + // TODO: generalized fall damage calc + // TODO: take into account falling into fluid from a height/surface tension + mover.take_overall_damage(min(1, round(height_difference * 0.05))) + + // Handle non-listener proximity triggers. + handle_proximity_update(A) + + //Items that are in ZAS contaminants, but not on a mob, can still be contaminated. + if(isitem(A)) + var/obj/item/I = A + if(vsc?.contaminant_control.CLOTH_CONTAMINATION && I.can_contaminate()) + var/datum/gas_mixture/env = return_air(1) + if(!env) + return + for(var/g in env.gas) + var/decl/material/mat = GET_DECL(g) + if((mat.gas_flags & XGM_GAS_CONTAMINANT) && env.gas[g] > mat.gas_overlay_limit + 1) + I.contaminate() + break + + if(isturf(old_loc) && ismob(A)) + var/turf/T = old_loc + if(T.get_physical_height() != get_physical_height()) + // Delay to allow transition to the new turf and avoid layering issues. + var/mob/M = A + M.reset_offsets() + if(platform || (get_physical_height() > T.get_physical_height())) + M.reset_layer() + else + // arbitrary timing value that feels good in practice. it sucks and is inconsistent:( + addtimer(CALLBACK(M, TYPE_PROC_REF(/atom, reset_layer)), max(0, ceil(M.next_move - world.time)) + 1 SECOND) + + if(simulated) + A.OnSimulatedTurfEntered(src, old_loc) + diff --git a/code/game/turfs/turf_flick_animations.dm b/code/game/turfs/turf_flick_animations.dm index 5d51f6e2f172..c6035fd42380 100644 --- a/code/game/turfs/turf_flick_animations.dm +++ b/code/game/turfs/turf_flick_animations.dm @@ -1,4 +1,4 @@ -/proc/anim(atom/target, a_icon, a_icon_state, flick_anim, sleeptime = 0, direction as num) +/proc/anim(atom/target, a_icon, a_icon_state, flick_anim, sleeptime = 0, direction as num|null) //This proc throws up either an icon or an animation for a specified amount of time. //The variables should be apparent enough. var/atom/movable/overlay/animation = new /atom/movable/overlay(target) diff --git a/code/game/turfs/turf_fluids.dm b/code/game/turfs/turf_fluids.dm index bbef1334dd48..aafbb2bb1931 100644 --- a/code/game/turfs/turf_fluids.dm +++ b/code/game/turfs/turf_fluids.dm @@ -10,73 +10,224 @@ return fluid_can_pass /turf/proc/remove_fluid(var/amount = 0) - var/obj/effect/fluid/F = locate() in src - if(F) - F.reagents.remove_any(amount) + if(reagents) + remove_any_reagents(amount) -/turf/return_fluid() - return (locate(/obj/effect/fluid) in contents) +/turf/proc/displace_all_reagents() + UPDATE_FLUID_BLOCKED_DIRS(src) + var/list/spread_into_neighbors + var/turf/neighbor + var/coming_from + for(var/spread_dir in global.cardinal) + if(fluid_blocked_dirs & spread_dir) + continue + neighbor = get_step(src, spread_dir) + if(!neighbor) + continue + UPDATE_FLUID_BLOCKED_DIRS(neighbor) + coming_from = global.reverse_dir[spread_dir] + if((neighbor.fluid_blocked_dirs & coming_from) || !neighbor.CanFluidPass(coming_from) || neighbor.is_flooded(absolute = TRUE) || !neighbor.CanFluidPass(global.reverse_dir[spread_dir])) + continue + LAZYDISTINCTADD(spread_into_neighbors, neighbor) + if(length(spread_into_neighbors)) + var/spreading = round(REAGENT_TOTAL_VOLUME(reagents) / length(spread_into_neighbors)) + if(spreading > 0) + for(var/turf/spread_into_turf as anything in spread_into_neighbors) + reagents.trans_to_turf(spread_into_turf, spreading) + reagents?.clear_reagents() -/turf/proc/make_flooded() - if(!flooded) - flooded = TRUE - for(var/obj/effect/fluid/F in src) - qdel(F) - update_icon() - fluid_update() +/turf/proc/set_flooded(new_flooded, force = FALSE, skip_vis_contents_update = FALSE, mapload = FALSE) + + // Don't do unnecessary work. + if(!simulated || (!force && new_flooded == flooded)) + return + + // Remove our old overlay if necessary. + if(flooded && new_flooded != flooded && !skip_vis_contents_update) + var/flood_object = get_flood_overlay(flooded) + if(flood_object) + remove_vis_contents(src, flood_object) + + // Set our flood state. + flooded = new_flooded + if(flooded) + QDEL_NULL(reagents) + ADD_ACTIVE_FLUID_SOURCE(src) + if(!skip_vis_contents_update) + var/flood_object = get_flood_overlay(flooded) + if(flood_object) + add_vis_contents(flood_object) + else if(!mapload) + REMOVE_ACTIVE_FLUID_SOURCE(src) + fluid_update() // We are now floodable, so wake up our neighbors. /turf/is_flooded(var/lying_mob, var/absolute) - return (flooded || (!absolute && check_fluid_depth(lying_mob ? FLUID_OVER_MOB_HEAD : FLUID_DEEP))) + if(flooded) + return TRUE + if(absolute) + return FALSE + var/required_depth = lying_mob ? FLUID_OVER_MOB_HEAD : FLUID_DEEP + if(get_supporting_platform()) // Increase required depth if we are over the water. + required_depth -= get_physical_height() // depth is negative, -= to increase required depth. + return check_fluid_depth(required_depth) -/turf/check_fluid_depth(var/min) +/turf/check_fluid_depth(var/min = 1) . = (get_fluid_depth() >= min) +/turf/proc/get_fluid_name() + var/decl/material/mat = reagents?.get_primary_reagent_decl() || RESOLVE_TO_DECL(flooded) + return mat?.get_reagent_name(reagents, MAT_PHASE_LIQUID) || "liquid" + /turf/get_fluid_depth() if(is_flooded(absolute=1)) return FLUID_MAX_DEPTH - var/obj/effect/fluid/F = return_fluid() - if(istype(F)) - return F.reagents.total_volume var/obj/structure/glass_tank/aquarium = locate() in contents - if(aquarium && aquarium.reagents && aquarium.reagents.total_volume) - return aquarium.reagents.total_volume * TANK_WATER_MULTIPLIER - return 0 - -/turf/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0) - . = ..() - var/turf/T = . - if(isturf(T) && !T.flooded && T.flood_object) - QDEL_NULL(flood_object) + if(aquarium) + return REAGENT_TOTAL_VOLUME(aquarium.reagents) * TANK_WATER_MULTIPLIER + return REAGENT_TOTAL_VOLUME(reagents) /turf/proc/show_bubbles() - set waitfor = 0 + set waitfor = FALSE + // TODO: make flooding show bubbles. + if(!flooded && fluid_overlay) + flick("bubbles", fluid_overlay) +/turf/fluid_update(var/ignore_neighbors) + fluid_blocked_dirs = null + fluid_can_pass = null + if(!ignore_neighbors) + for(var/checkdir in global.cardinal) + var/turf/T = get_step_resolving_mimic(src, checkdir) + if(T) + T.fluid_update(TRUE) if(flooded) - if(istype(flood_object)) - flick("ocean-bubbles", flood_object) + ADD_ACTIVE_FLUID_SOURCE(src) + else if(REAGENT_TOTAL_VOLUME(reagents) > FLUID_QDEL_POINT) + ADD_ACTIVE_FLUID(src) + +/turf/get_reagents() + create_or_update_reagents(FLUID_MAX_DEPTH) + return ..() + +/turf/add_to_reagents(reagent_type, amount, data, safety = FALSE, defer_update = FALSE, phase = null) + create_or_update_reagents(FLUID_MAX_DEPTH) + return ..() + +/turf/get_reagent_space() + create_or_update_reagents(FLUID_MAX_DEPTH) + return ..() + +/turf/fluid_act(var/datum/reagents/fluids) + ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids)) + fluids.touch_turf(src, touch_atoms = FALSE) // Handled in fluid_act() below. + // Wet items that are not supported on a platform or such. + var/effective_volume = REAGENT_TOTAL_VOLUME(fluids) + if(get_supporting_platform()) + // Depth is negative height, hence +=. TODO: positive heights? No idea how to handle that. + effective_volume += get_physical_height() + if(effective_volume > FLUID_PUDDLE) + for(var/atom/movable/AM as anything in get_contained_external_atoms()) + if(!AM.submerged()) + continue + AM.fluid_act(fluids) + +/turf/proc/remove_fluids(var/amount, var/defer_update) + if(!REAGENT_TOTAL_LIQUID_VOLUME(reagents)) return + remove_any_reagents(amount, defer_update = defer_update, removed_phases = MAT_PHASE_LIQUID) + if(defer_update && !QDELETED(reagents)) + SSfluids.holders_to_update[reagents] = TRUE - var/obj/effect/fluid/F = locate() in src - if(istype(F)) - flick("bubbles",F) +/turf/proc/transfer_fluids_to(var/turf/target, var/amount, var/defer_update = TRUE) + // No flowing of reagents without liquids, but this proc should not be called if liquids are not present regardless. + if(!REAGENT_TOTAL_LIQUID_VOLUME(reagents)) + return + target.create_or_update_reagents(FLUID_MAX_DEPTH) -/turf/fluid_update(var/ignore_neighbors) + // We reference total_volume instead of total_liquid_volume here because the maximum volume limits of the turfs still respect solid volumes, and depth is still determined by total volume. + reagents.trans_to_turf(target, min(REAGENT_TOTAL_VOLUME(reagents), min(REAGENT_MAXIMUM_VOLUME(target.reagents) - REAGENT_TOTAL_VOLUME(target.reagents), amount)), defer_update = defer_update) + if(defer_update) + if(!QDELETED(reagents)) + SSfluids.holders_to_update[reagents] = TRUE + if(!QDELETED(target.reagents)) + SSfluids.holders_to_update[target.reagents] = TRUE - fluid_blocked_dirs = null - fluid_can_pass = null +/turf/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + . = ..() + if(exposed_temperature >= FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE) + vaporize_fuel(air) - // Wake up our neighbors. - if(!ignore_neighbors) - for(var/checkdir in GLOB.cardinal) - var/turf/T = get_step(src, checkdir) - if(T) T.fluid_update(1) +/turf/proc/vaporize_fuel(datum/gas_mixture/air) + if(!length(REAGENT_VOLUMES(reagents)) || !istype(air)) + return + var/update_air = FALSE + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.gas_flags & XGM_GAS_FUEL) + var/moles = round(REAGENT_VOLUME(reagents, reagent) / REAGENT_UNITS_PER_GAS_MOLE) + if(moles > 0) + air.adjust_gas(reagent.type, moles, FALSE) + remove_from_reagents(reagent, round(moles * REAGENT_UNITS_PER_GAS_MOLE)) + update_air = TRUE + if(update_air) + air.update_values() + return TRUE + return FALSE - // Wake up ourself! - if(flooded) - ADD_ACTIVE_FLUID_SOURCE(src) - for(var/obj/effect/fluid/F in src) - qdel(F) +/turf/on_reagent_change() + + if(!(. = ..())) + return + + state_was_modified() + + if(REAGENT_TOTAL_LIQUID_VOLUME(reagents) < FLUID_SLURRY) + dump_solid_reagents() + + if(REAGENT_TOTAL_VOLUME(reagents) > FLUID_QDEL_POINT) + ADD_ACTIVE_FLUID(src) + var/decl/material/primary_reagent = reagents.get_primary_reagent_decl() + if(primary_reagent && (REAGENT_VOLUME(reagents, primary_reagent) >= primary_reagent.slippery_amount)) + last_slipperiness = primary_reagent.slipperiness + else + last_slipperiness = 0 + if(!fluid_overlay) + fluid_overlay = new(src, TRUE) + fluid_overlay.update_icon() + unwet_floor(FALSE) else - REMOVE_ACTIVE_FLUID_SOURCE(src) - for(var/obj/effect/fluid/F in src) - ADD_ACTIVE_FLUID(F) + QDEL_NULL(fluid_overlay) + reagents?.clear_reagents() + REMOVE_ACTIVE_FLUID(src) + SSfluids.pending_flows -= src + if(last_slipperiness > 0) + wet_floor(last_slipperiness) + last_slipperiness = 0 + + for(var/checkdir in global.cardinal) + var/turf/neighbor = get_step_resolving_mimic(src, checkdir) + if(istype(neighbor) && (islist(neighbor.reagents) || (istype(neighbor.reagents) && REAGENT_TOTAL_VOLUME(neighbor.reagents) > FLUID_QDEL_POINT))) + ADD_ACTIVE_FLUID(neighbor) + +/turf/proc/dump_solid_reagents(datum/reagents/solids) + if(!istype(solids)) + solids = reagents + var/solid_volumes = REAGENT_SOLID_VOLUMES(solids) + if(LAZYLEN(solid_volumes)) + var/list/matter_list = list() + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(solid_volumes)) + var/reagent_amount = SOLID_VOLUME(solids, reagent) + matter_list[reagent.type] = round(reagent_amount/REAGENT_UNITS_PER_MATERIAL_UNIT) + solids.remove_reagent(reagent, reagent_amount, defer_update = TRUE, removed_phases = MAT_PHASE_SOLID) + + var/obj/item/debris/scraps/chemical/scraps = locate() in contents + if(!istype(scraps) || scraps.get_total_matter() >= MAX_SCRAP_MATTER) + scraps = new(src) + if(!LAZYLEN(scraps.matter)) + scraps.matter = matter_list + else + for(var/mat_type in matter_list) + scraps.matter[mat_type] += matter_list[mat_type] + + scraps.update_primary_material() + solids.handle_update() \ No newline at end of file diff --git a/code/game/turfs/turf_footsteps.dm b/code/game/turfs/turf_footsteps.dm new file mode 100644 index 000000000000..e9c2ff24ca47 --- /dev/null +++ b/code/game/turfs/turf_footsteps.dm @@ -0,0 +1,15 @@ +/proc/get_footstep_for_mob(var/footstep_type, var/mob/living/stepper) + . = istype(stepper) && stepper.get_mob_footstep(footstep_type) + if(!.) + var/decl/footsteps/footsteps = GET_DECL(footstep_type) + . = pick(footsteps.footstep_sounds) + +/turf/proc/get_footstep_sound(var/mob/stepper) + for(var/obj/structure/S in contents) + if(S.footstep_type) + return get_footstep_for_mob(S.footstep_type, stepper) + if(check_fluid_depth(10) && !is_flooded(TRUE)) + return get_footstep_for_mob(/decl/footsteps/water, stepper) + if(footstep_type) + return get_footstep_for_mob(footstep_type, stepper) + return get_footstep_for_mob(/decl/footsteps/blank, stepper) diff --git a/code/game/turfs/turf_height.dm b/code/game/turfs/turf_height.dm new file mode 100644 index 000000000000..936ac8e541cb --- /dev/null +++ b/code/game/turfs/turf_height.dm @@ -0,0 +1,6 @@ +/turf/proc/set_physical_height(var/new_height) + return + +// Open turfs should count as as low as possible for the purposes of fluid flows, etc. +/turf/proc/get_physical_height() + return is_open() ? -(FLUID_DEEP) : 0 diff --git a/code/game/turfs/turf_material.dm b/code/game/turfs/turf_material.dm new file mode 100644 index 000000000000..306e511f4485 --- /dev/null +++ b/code/game/turfs/turf_material.dm @@ -0,0 +1,13 @@ +/turf/proc/get_default_material() + return null + +/turf/proc/set_turf_materials(decl/material/new_material, decl/material/new_reinf_material, force, decl/material/new_girder_material, skip_update) + return + +// TODO: Unify the strata_override var and related get_strata_material_type overrides somewhere, like in an extension or on /turf. +/turf/proc/get_strata_material_type() + //Try to grab the material we picked for the level from the level data + var/datum/level_data/LD = SSmapping.levels_by_z[z] + if(!LD._level_setup_completed && !LD._has_warned_uninitialized_strata) + LD.warn_bad_strata(src) //If we haven't warned yet dump a stack trace and warn that strata was set before init + return LD.strata_base_material.type \ No newline at end of file diff --git a/code/game/turfs/turf_navigation.dm b/code/game/turfs/turf_navigation.dm new file mode 100644 index 000000000000..9085f6b99d9a --- /dev/null +++ b/code/game/turfs/turf_navigation.dm @@ -0,0 +1,62 @@ +/******************************************************************/ +// Navigation procs +// Used for A-star pathfinding + +// Returns the surrounding cardinal turfs with open links +// Including through doors openable with the ID +/turf/proc/CardinalTurfsWithAccess(var/obj/item/card/id/ID) + var/L[] = new() + + for(var/d in global.cardinal) + var/turf/T = get_step(src, d) + if(istype(T) && !T.density && T.simulated && !LinkBlockedWithAccess(src, T, ID)) + L.Add(T) + return L + + +// Returns true if a link between A and B is blocked +// Movement through doors allowed if ID has access +/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/card/id/ID) + + if(A == null || B == null) return 1 + var/adir = get_dir(A,B) + var/rdir = get_dir(B,A) + if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal + var/iStep = get_step(A,adir&(NORTH|SOUTH)) + if(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID)) + return 0 + + var/pStep = get_step(A,adir&(EAST|WEST)) + if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID)) + return 0 + return 1 + + if(DirBlockedWithAccess(A,adir, ID)) + return 1 + + if(DirBlockedWithAccess(B,rdir, ID)) + return 1 + + for(var/obj/O in B) + if(O.density && !istype(O, /obj/machinery/door) && !(O.atom_flags & ATOM_FLAG_CHECKS_BORDER)) + return 1 + + return 0 + +// Returns true if direction is blocked from loc +// Checks doors against access with given ID +/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/card/id/ID) + for(var/obj/structure/window/D in loc) + if(!D.density) continue + if(D.dir == SOUTHWEST) return 1 + if(D.dir == dir) return 1 + + for(var/obj/machinery/door/D in loc) + if(!D.density) continue + if(istype(D, /obj/machinery/door/window)) + if( dir & D.dir ) return !D.check_access(ID) + + //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID) + //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) + else return !D.check_access(ID) // it's a real, air blocking door + return 0 diff --git a/code/game/turfs/turf_ramps.dm b/code/game/turfs/turf_ramps.dm new file mode 100644 index 000000000000..a969376f1af9 --- /dev/null +++ b/code/game/turfs/turf_ramps.dm @@ -0,0 +1,9 @@ +/turf/proc/handle_ramp_dug_below(turf/wall/natural/ramp) + if(simulated && !is_open()) + ChangeTurf(get_open_turf_type(src)) + return TRUE + return FALSE + +/turf/floor/handle_ramp_dug_below(turf/wall/natural/ramp) + var/decl/flooring/floor = get_topmost_flooring() + return !floor.constructed && ..() diff --git a/code/game/turfs/turf_serde.dm b/code/game/turfs/turf_serde.dm new file mode 100644 index 000000000000..d8f7515f2b84 --- /dev/null +++ b/code/game/turfs/turf_serde.dm @@ -0,0 +1,60 @@ +/turf + var/_earliest_type + var/_state_was_modified + var/_contents_were_modified + +/turf/ShouldSerialize(_age) + if(type == _earliest_type && !_state_was_modified && !_contents_were_modified) + return FALSE + var/area/area = get_area(src) + if(!(area?.area_flags & AREA_FLAG_ALLOW_LEVEL_PERSISTENCE)) + return FALSE + return ..(_age) + +/turf/Serialize() + . = ..() + SERIALIZE_VALUE(loc, /atom/movable, list(x, y, z)) + SERIALIZE_IF_MODIFIED(is_outside, /turf) + +/turf/Deserialize(list/instance_map) + . = ..() + state_was_modified() + +/turf/proc/state_was_modified() + if(!simulated || _state_was_modified) + return + _state_was_modified = TRUE + update_level_persistence_tracking() + +/atom/proc/contents_were_modified() + var/turf/turf = get_turf(src) + turf?.contents_were_modified() + +/turf/contents_were_modified() + if(!simulated || _contents_were_modified) + return + _contents_were_modified = TRUE + update_level_persistence_tracking() + +/turf/proc/update_level_persistence_tracking() + var/area/area = get_area(src) + if(!(area?.area_flags & AREA_FLAG_ALLOW_LEVEL_PERSISTENCE)) + return + var/datum/level_data/level = SSmapping.levels_by_z[z] + if(!istype(level) || !level.is_persistent()) + return + var/list/coord = json_encode(list(x, y)) + LAZYSET(level.changed_turfs, coord, TRUE) + +/turf/proc/UnpackSerializableInstances() + // Get all recursively nested instances on this turf. + var/list/instances_to_unpack = list(src) + while(length(instances_to_unpack)) + var/datum/instance = instances_to_unpack[1] + instances_to_unpack.Cut(1, 2) + if(instance in .) + continue + LAZYADD(., instance) + var/list/packed_instances = instance.GetPossiblySerializableInstances() + if(length(packed_instances)) + instances_to_unpack |= packed_instances diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm deleted file mode 100644 index 42150d3595fb..000000000000 --- a/code/game/turfs/unsimulated.dm +++ /dev/null @@ -1,6 +0,0 @@ -/turf/unsimulated - name = "command" - initial_gas = list(/decl/material/gas/oxygen = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) - -/turf/unsimulated/get_lumcount(var/minlum = 0, var/maxlum = 1) - return 0.8 diff --git a/code/game/turfs/unsimulated/_unsimulated.dm b/code/game/turfs/unsimulated/_unsimulated.dm new file mode 100644 index 000000000000..813899f2fca3 --- /dev/null +++ b/code/game/turfs/unsimulated/_unsimulated.dm @@ -0,0 +1,37 @@ +/turf/unsimulated + name = "command" + initial_gas = GAS_STANDARD_AIRMIX + abstract_type = /turf/unsimulated + simulated = FALSE + dynamic_lighting = FALSE + +// Shortcut a bunch of simulation stuff since this turf just needs to sit there. +// We don't even call Initialize(), how cool is that??? +/turf/unsimulated/New() + // Preloader stuff copied from /atom/New() for speed. + //atom creation method that preloads variables at creation + if(global.use_preloader && (src.type == global._preloader.target_path))//in case the instanciated atom is creating other atoms in New() + global._preloader.load(src) + atom_flags |= ATOM_FLAG_INITIALIZED + +/turf/unsimulated/ChangeTurf(turf/N, tell_universe, force_lighting_update, keep_air, update_open_turfs_above, keep_height) + if(!SSmapping.initialized) + atom_flags = 0 // We want ChangeTurf to treat us as if we aren't initialized if SSmapping isn't done. + return ..() + +/turf/unsimulated/Initialize(mapload) + SHOULD_CALL_PARENT(FALSE) + SHOULD_NOT_OVERRIDE(TRUE) + return INITIALIZE_HINT_NORMAL + +/turf/unsimulated/get_lumcount(var/minlum = 0, var/maxlum = 1) + return 0.8 + +/turf/unsimulated/get_movable_alpha_mask_state(atom/movable/mover) + return null + +// For the purposes of spacemove/spacedrift. +/turf/unsimulated/is_floor() + return !density +/turf/unsimulated/is_wall() + return !is_floor() diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm deleted file mode 100644 index f9eabf8a09dd..000000000000 --- a/code/game/turfs/unsimulated/beach.dm +++ /dev/null @@ -1,21 +0,0 @@ -/turf/unsimulated/beach - name = "Beach" - icon = 'icons/misc/beach.dmi' - -/turf/unsimulated/beach/sand - name = "Sand" - icon_state = "sand" - -/turf/unsimulated/beach/coastline - name = "Coastline" - icon = 'icons/misc/beach2.dmi' - icon_state = "sandwater" - -/turf/unsimulated/beach/water - name = "Water" - icon_state = "water" - turf_flags = TURF_IS_WET - -/turf/unsimulated/beach/water/Initialize(var/ml) - . = ..() - overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water2","layer"=MOB_LAYER+0.1) diff --git a/code/game/turfs/unsimulated/floor.dm b/code/game/turfs/unsimulated/floor.dm index 489990be8040..83e5dd866713 100644 --- a/code/game/turfs/unsimulated/floor.dm +++ b/code/game/turfs/unsimulated/floor.dm @@ -1,7 +1,11 @@ /turf/unsimulated/floor name = "floor" icon = 'icons/turf/floors.dmi' - icon_state = "Floor3" + icon_state = "shuttle" + turf_flags = TURF_IS_HOLOMAP_PATH + +/turf/unsimulated/floor/can_climb_from_below(var/mob/climber) + return TRUE /turf/unsimulated/floor/infinity //non-doomsday version for transit and wizden name = "\proper infinity" @@ -9,13 +13,118 @@ icon_state = "bluespace" desc = "Looks like eternity." -/turf/unsimulated/mask - name = "mask" - icon = 'icons/turf/walls.dmi' - icon_state = "rockvault" - /turf/unsimulated/floor/rescue_base icon_state = "asteroidfloor" -/turf/unsimulated/floor/shuttle_ceiling - icon_state = "reinforced" +/turf/unsimulated/floor/snow + name = "snow" + icon = 'icons/turf/flooring/snow.dmi' + icon_state = "snow0" + +/turf/unsimulated/floor/ice + name = "ice" + icon = 'icons/turf/flooring/ice.dmi' + icon_state = "ice" + color = COLOR_SKY_BLUE + +/turf/unsimulated/floor/snow_plating + name = "snowy plating" + icon = 'icons/turf/flooring/snow_plating.dmi' + icon_state = "snowplating" + +/turf/unsimulated/floor/wood + name = "wooden floor" + icon = 'icons/turf/flooring/wood.dmi' + icon_state = "wood0" + +/turf/unsimulated/floor/wood/broken + icon_state = "wood_broken0" + +/turf/unsimulated/floor/wood/broken1 + icon_state = "wood_broken1" + +/turf/unsimulated/floor/wood/broken2 + icon_state = "wood_broken2" + +/turf/unsimulated/floor/wood/broken6 + icon_state = "wood_broken6" + +/turf/unsimulated/floor/laminate + name = "wooden laminate floor" + icon = 'icons/turf/flooring/laminate.dmi' + icon_state = "wood" + +/turf/unsimulated/floor/laminate/broken + icon_state = "wood_broken0" + +/turf/unsimulated/floor/laminate/broken1 + icon_state = "wood_broken1" + +/turf/unsimulated/floor/laminate/broken2 + icon_state = "wood_broken2" + +/turf/unsimulated/floor/laminate/broken6 + icon_state = "wood_broken6" + +/turf/unsimulated/floor/vault + icon_state = "vault" + +/turf/unsimulated/floor/dark + icon_state = "dark" + +/turf/unsimulated/floor/freezer + icon_state = "freezerfloor" + +/turf/unsimulated/floor/plating + name = "plating" + icon_state = "plating" + +/turf/unsimulated/floor/asteroid + icon_state = "asteroid" + +/turf/unsimulated/floor/asteroidplating + icon_state = "asteroidplating" + +/turf/unsimulated/floor/cult + name = "plating" + icon_state = "cult" + +/turf/unsimulated/floor/water + name = "water" + icon = 'icons/misc/beach.dmi' + icon_state = "seashallow" + +/turf/unsimulated/floor/lava + icon_state = "lava" + name = "lava" + +/turf/unsimulated/floor/grass + name = "grass" + icon_state = "grass0" + +/turf/unsimulated/floor/steel + icon_state = "steel" + +/turf/unsimulated/floor/bcircuit + icon_state = "bcircuit" + +/turf/unsimulated/floor/hydro + icon_state = "hydrofloor" + +/turf/unsimulated/floor/white + icon_state = "white" + +/turf/unsimulated/floor/carpet + name = "carpet" + icon_state = "carpet" + +/turf/unsimulated/floor/bcarpet + icon_state = "bcarpet" + +/turf/unsimulated/floor/sand + name = "sand" + icon = 'icons/turf/flooring/sand.dmi' + icon_state = "sand0" + +/turf/unsimulated/floor/lino + icon_state = "lino" diff --git a/code/game/turfs/unsimulated/mask.dm b/code/game/turfs/unsimulated/mask.dm new file mode 100644 index 000000000000..a380cfa054dc --- /dev/null +++ b/code/game/turfs/unsimulated/mask.dm @@ -0,0 +1,19 @@ +/turf/unsimulated/mask + name = "mask" + icon = 'icons/turf/walls.dmi' + icon_state = "rockvault" + +/turf/unsimulated/mask_alt // just a second mask type for maps needing two random map runs + name = "mask" + icon = 'icons/turf/walls.dmi' + icon_state = "rockvault" + color = COLOR_SILVER + +// Why do these exist? Are they just for typechecks when generating random maps? Does the flooding code even run for unsim turfs? +/turf/unsimulated/mask/flooded + flooded = /decl/material/liquid/water + color = COLOR_LIQUID_WATER + +/turf/unsimulated/mask/flooded/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water, NOT 10% salt \ No newline at end of file diff --git a/code/game/turfs/unsimulated/walls.dm b/code/game/turfs/unsimulated/walls.dm index e064d07a2e00..24193a5e8059 100644 --- a/code/game/turfs/unsimulated/walls.dm +++ b/code/game/turfs/unsimulated/walls.dm @@ -2,13 +2,17 @@ name = "wall" icon = 'icons/turf/walls.dmi' icon_state = "riveted" - opacity = 1 - density = 1 + opacity = TRUE + density = TRUE + turf_flags = TURF_IS_HOLOMAP_OBSTACLE /turf/unsimulated/wall/fakeglass name = "window" icon_state = "fakewindows" - opacity = 0 + opacity = FALSE + +/turf/unsimulated/wall/fakeglass/alt + icon_state = "fakewindows2" /turf/unsimulated/wall/other icon_state = "r_wall" @@ -16,5 +20,11 @@ /turf/unsimulated/wall/cult name = "cult wall" desc = "Hideous images dance beneath the surface." - icon = 'icons/turf/wall_masks.dmi' - icon_state = "cult" \ No newline at end of file + icon = 'icons/turf/walls/cult.dmi' + icon_state = "preview" + +/turf/unsimulated/wall/airlock + name = "Facility Access" + desc = "A secure airlock. Doesn't look like you can get through easily." + icon = 'icons/obj/doors/centcomm/door.dmi' + icon_state = "closed" diff --git a/code/game/turfs/walls/_wall.dm b/code/game/turfs/walls/_wall.dm new file mode 100644 index 000000000000..3706a99fcfa1 --- /dev/null +++ b/code/game/turfs/walls/_wall.dm @@ -0,0 +1,325 @@ +var/global/list/wall_blend_objects = list( + /obj/machinery/door, + /obj/structure/door, + /obj/structure/wall_frame, + /obj/structure/grille, + /obj/structure/window/reinforced/full, + /obj/structure/window/reinforced/polarized/full, + /obj/structure/window/shuttle, + /obj/structure/window/borosilicate/full, + /obj/structure/window/borosilicate_reinforced/full +) +var/global/list/wall_noblend_objects = list( + /obj/machinery/door/window +) +var/global/list/wall_fullblend_objects = list( + /obj/structure/wall_frame +) + +/turf/wall + name = "wall" + desc = "A huge chunk of metal used to separate rooms." + icon = 'icons/turf/walls/_previews.dmi' + icon_state = "solid" + opacity = TRUE + density = TRUE + blocks_air = 1 + thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + explosion_resistance = 10 + color = COLOR_STEEL + turf_flags = TURF_IS_HOLOMAP_OBSTACLE + initial_gas = GAS_STANDARD_AIRMIX + zone_membership_candidate = TRUE + layer = TURF_OVER_EDGE_LAYER + + /// If set, will prevent merges between walls with different IDs. + var/unique_merge_identifier + var/damage = 0 + var/can_open = 0 + var/decl/material/girder_material = /decl/material/solid/metal/steel + var/construction_stage + var/hitsound = 'sound/weapons/Genhit.ogg' + /// A list of connections to walls for each corner, used for icon generation. Can be converted to a list of dirs with corner_states_to_dirs(). + var/list/wall_connections + /// A list of connections to non-walls for each corner, used for icon generation. Can be converted to a list of dirs with corner_states_to_dirs(). + var/list/other_connections + var/floor_type = /turf/floor/plating //turf it leaves after destruction + var/stripe_color + var/handle_structure_blending = TRUE + var/min_dismantle_amount = 2 + var/max_dismantle_amount = 2 + /// The reinforcement icon to use. Set in update_material() based on reinf_material. + var/reinf_icon + + /// Icon to use if shutter state is non-null. + var/shutter_icon = 'icons/turf/walls/shutter.dmi' + /// TRUE = open, FALSE = closed, null = no shutter. + var/shutter_state + /// Overrides base material for shutter icon if set. + var/decl/material/shutter_material + /// Shutter open/close sound. + var/shutter_sound = 'sound/weapons/Genhit.ogg' + +/turf/wall/Initialize(var/ml, var/materialtype, var/rmaterialtype) + + ..(ml) + + // Clear mapping icons. + icon = get_wall_icon() + icon_state = "blank" + color = null + + if(ispath(shutter_material)) + shutter_material = GET_DECL(shutter_material) + + set_turf_materials((materialtype || material || get_default_material()), (rmaterialtype || reinf_material), TRUE, girder_material, skip_update = TRUE) + + . = INITIALIZE_HINT_LATELOAD + set_extension(src, /datum/extension/penetration/proc_call, PROC_REF(CheckPenetration)) + START_PROCESSING(SSturf, src) //Used for radiation. + +/turf/wall/LateInitialize(var/ml) + ..() + update_material(!ml) + if(!ml) + for(var/direction in global.alldirs) + var/turf/target_turf = get_step_resolving_mimic(src, direction) + if(istype(target_turf)) + if(TICK_CHECK) // not CHECK_TICK -- only queue if the server is overloaded + target_turf.queue_icon_update() + else + target_turf.update_icon() + +/turf/wall/Destroy() + STOP_PROCESSING(SSturf, src) + material = GET_DECL(/decl/material/placeholder) + reinf_material = null + var/old_x = x + var/old_y = y + var/old_z = z + . = ..() + var/turf/debris = locate(old_x, old_y, old_z) + if(debris) + for(var/turf/wall/wall in RANGE_TURFS(debris, 1)) + wall.wall_connections = null + wall.other_connections = null + wall.queue_icon_update() + +// Walls always hide the stuff below them. +/turf/wall/levelupdate() + for(var/obj/O in src) + O.hide(1) + +/turf/wall/protects_atom(var/atom/A) + var/obj/O = A + return (istype(O) && O.hides_under_flooring()) || ..() + +/turf/wall/Process(wait, tick) + var/how_often = max(round(2 SECONDS/wait), 1) + if(tick % how_often) + return //We only work about every 2 seconds + if(!radiate()) + return PROCESS_KILL + +/turf/wall/bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj,/obj/item/projectile/beam)) + burn(2500) + else if(istype(Proj,/obj/item/projectile/ion)) + burn(500) + + var/proj_damage = Proj.get_structure_damage() + + if(prob(15)) + var/list/ricochet_sounds = Proj.get_ricochet_sounds() + if(length(ricochet_sounds)) + playsound(src, pick(ricochet_sounds), 100, 1) + + if(reinf_material) + if(Proj.atom_damage_type == BURN) + proj_damage /= reinf_material.burn_armor + else if(Proj.atom_damage_type == BRUTE) + proj_damage /= reinf_material.brute_armor + + //cap the amount of damage, so that things like emitters can't destroy walls in one hit. + var/damage = min(proj_damage, 100) + + take_damage(damage) + +/turf/wall/hitby(atom/movable/AM, var/datum/thrownthing/TT) + . = ..() + if(. && density && !ismob(AM)) + var/tforce = AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR) + playsound(src, hitsound, tforce >= 15 ? 60 : 25, TRUE) + if(tforce > 0) + take_damage(tforce) + +/turf/wall/proc/clear_plants() + for(var/obj/effect/overlay/wallrot/WR in src) + qdel(WR) + for(var/obj/effect/vine/plant in range(src, 1)) + if(!plant.floor) //shrooms drop to the floor + plant.floor = 1 + plant.update_icon() + plant.reset_offsets(0) + +/turf/wall/ChangeTurf(var/turf/N, var/tell_universe = TRUE, var/force_lighting_update = FALSE, var/keep_air = FALSE, var/update_open_turfs_above = TRUE) + clear_plants() + . = ..() + +//Appearance +/turf/wall/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(!isnull(shutter_state)) + . += SPAN_NOTICE("The shutter is [shutter_state ? "open" : "closed"].") + if(!damage) + . += SPAN_NOTICE("It looks fully intact.") + else + var/dam = damage / material.integrity + if(dam <= 0.3) + . += SPAN_WARNING("It looks slightly damaged.") + else if(dam <= 0.6) + . += SPAN_WARNING("It looks moderately damaged.") + else + . += SPAN_DANGER("It looks heavily damaged.") + if(paint_color) + . += get_paint_examine_message() + if(locate(/obj/effect/overlay/wallrot) in src) + . += SPAN_WARNING("There is fungus growing on [src].") + +/turf/wall/proc/get_paint_examine_message() + return SPAN_NOTICE("It has had a coat of paint applied.") + +//Damage +/turf/wall/handle_melting(list/meltable_materials) + . = ..() + if(!can_melt()) + return + var/turf/floor/F = ChangeTurf(/turf/floor/plating) + if(!istype(F)) + return + F.burn_tile() + F.icon_state = "wall_thermite" + visible_message(SPAN_DANGER("\The [src] spontaneously combusts!")) + +/turf/wall/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(damage) + src.damage = max(0, src.damage + damage) + update_damage() + +/turf/wall/proc/update_damage() + var/cap = material.integrity + if(reinf_material) + cap += reinf_material.integrity + + if(locate(/obj/effect/overlay/wallrot) in src) + cap = cap / 10 + + if(damage >= cap) + physically_destroyed() + else + update_icon() + +/turf/wall/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)//Doesn't fucking work because walls don't interact with air :( + burn(exposed_temperature) + return ..() + +/turf/wall/adjacent_fire_act(turf/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume) + burn(adj_temp) + if(adj_temp > material.temperature_damage_threshold) + take_damage(log(RAND_F(0.9, 1.1) * (adj_temp - material.temperature_damage_threshold))) + return ..() + +/turf/wall/proc/get_dismantle_stack_type() + return + +/turf/wall/proc/get_dismantle_sound() + return 'sound/items/Welder.ogg' + +/turf/wall/proc/drop_dismantled_products(devastated, explode) + var/list/obj/structure/girder/placed_girders + if(girder_material) + placed_girders = girder_material.place_dismantled_girder(src, reinf_material) + for(var/obj/structure/girder/placed_girder in placed_girders) + placed_girder.anchored = TRUE + placed_girder.prepped_for_fakewall = can_open + placed_girder.update_icon() + if(material) + material.place_dismantled_product(src, devastated, amount = rand(min_dismantle_amount, max_dismantle_amount), drop_type = get_dismantle_stack_type()) + +/turf/wall/dismantle_turf(devastated, explode, no_product, keep_air = TRUE) + + playsound(src, get_dismantle_sound(), 100, 1) + if(!no_product) + drop_dismantled_products(devastated, explode) + + for(var/obj/O in src.contents) //Eject contents! + if(istype(O,/obj/structure/sign/poster)) + var/obj/structure/sign/poster/P = O + P.dismantle_structure() + else + O.forceMove(src) + clear_plants() + . = ChangeTurf(floor_type || get_base_turf_by_area(src), keep_air = keep_air) + +/turf/wall/explosion_act(severity) + SHOULD_CALL_PARENT(FALSE) + if(severity == 1) + dismantle_turf(TRUE, TRUE, TRUE) + else if(severity == 2) + if(prob(75)) + take_damage(rand(150, 250)) + else + dismantle_turf(TRUE, TRUE) + else if(severity == 3) + take_damage(rand(0, 250)) + +// Wall-rot effect, a nasty fungus that destroys walls. +/turf/wall/proc/rot() + if(locate(/obj/effect/overlay/wallrot) in src) + return + var/number_rots = rand(2,3) + for(var/i=0, i= 10 && material.hardness <= 100) + +/turf/wall/is_wall() + return TRUE + +/turf/wall/handle_universal_decay() + handle_melting() + +/turf/wall/proc/get_hit_sound() + return 'sound/effects/metalhit.ogg' + +// Mapped premade for false walls +/turf/wall/false + can_open = TRUE diff --git a/code/game/turfs/walls/_wall_icon_cache.dm b/code/game/turfs/walls/_wall_icon_cache.dm new file mode 100644 index 000000000000..9a113e9f15bc --- /dev/null +++ b/code/game/turfs/walls/_wall_icon_cache.dm @@ -0,0 +1,61 @@ +#define CACHE_BASE_MARKER 1 +#define CACHE_PAINT_MARKER 2 +#define CACHE_STRIPE_MARKER 3 +#define CACHE_EDGE_MARKER 4 +#define CACHE_SHINE_MARKER 5 + +var/global/const/WALL_PAINT_STATE = "paint" +var/global/const/WALL_STRIPE_STATE = "stripe" +var/global/const/WALL_OTHER_STATE = "other" +var/global/const/WALL_SHINE_STATE = "shine" + +var/global/list/cached_wall_icons = list() +/proc/_get_wall_subicon(var/material_icon_base, var/connections, var/color, var/state, var/alpha, var/cache_marker) + var/cache_key = jointext(list(cache_marker, material_icon_base, json_encode(connections), color), "-") + if(!global.cached_wall_icons[cache_key]) + var/icon/subicon = icon('icons/turf/wall_texture.dmi', "blank") + for(var/i = 1 to 4) + var/check_state = "[state][length(connections) >= i ? connections[i] : null]" + if(check_state_in_icon(check_state, material_icon_base)) + subicon.Blend(icon(material_icon_base, check_state, dir = BITFLAG(i-1)), ICON_OVERLAY) + if(color && color != COLOR_WHITE) + subicon.Blend(color, ICON_MULTIPLY) + if(!isnull(alpha)) + subicon += rgb(null, null, null, alpha) + global.cached_wall_icons[cache_key] = subicon + return global.cached_wall_icons[cache_key] + +/proc/get_combined_wall_icon(var/list/wall_connections, var/list/other_connections, var/material_icon_base, var/base_color, var/paint_color, var/stripe_color, var/edge_color, var/shine_value) + + var/cache_key = list(material_icon_base, json_encode(wall_connections), json_encode(other_connections)) + if(base_color) + cache_key += CACHE_BASE_MARKER + cache_key += base_color + if(paint_color) + cache_key += CACHE_PAINT_MARKER + cache_key += paint_color + if(stripe_color) + cache_key += CACHE_STRIPE_MARKER + cache_key += stripe_color + if(edge_color) + cache_key += CACHE_EDGE_MARKER + cache_key += edge_color + if(shine_value) + cache_key += CACHE_SHINE_MARKER + cache_key += shine_value + cache_key = jointext(cache_key, "-") + + if(!global.cached_wall_icons[cache_key]) + var/icon/wall_icon = icon(_get_wall_subicon(material_icon_base, wall_connections, base_color, cache_marker = CACHE_BASE_MARKER)) + if(paint_color) wall_icon.Blend(_get_wall_subicon(material_icon_base, wall_connections, paint_color, WALL_PAINT_STATE, cache_marker = CACHE_PAINT_MARKER), ICON_OVERLAY) + if(stripe_color) wall_icon.Blend(_get_wall_subicon(material_icon_base, wall_connections, stripe_color, WALL_STRIPE_STATE, cache_marker = CACHE_STRIPE_MARKER), ICON_OVERLAY) + if(edge_color) wall_icon.Blend(_get_wall_subicon(material_icon_base, other_connections, edge_color, WALL_OTHER_STATE, cache_marker = CACHE_EDGE_MARKER), ICON_OVERLAY) + if(shine_value) wall_icon.Blend(_get_wall_subicon(material_icon_base, other_connections, null, WALL_SHINE_STATE, cache_marker = CACHE_SHINE_MARKER, alpha = shine_value), ICON_OVERLAY) + global.cached_wall_icons[cache_key] = wall_icon + return global.cached_wall_icons[cache_key] + +#undef CACHE_BASE_MARKER +#undef CACHE_PAINT_MARKER +#undef CACHE_STRIPE_MARKER +#undef CACHE_EDGE_MARKER +#undef CACHE_SHINE_MARKER \ No newline at end of file diff --git a/code/game/turfs/walls/wall_attacks.dm b/code/game/turfs/walls/wall_attacks.dm new file mode 100644 index 000000000000..d736a234400d --- /dev/null +++ b/code/game/turfs/walls/wall_attacks.dm @@ -0,0 +1,326 @@ +//Interactions +/turf/wall/proc/toggle_open(var/mob/user) + + if(can_open == WALL_OPENING) + return + + SSradiation.resistance_cache.Remove(src) + can_open = WALL_OPENING + sleep(15) + if(density) + set_density(FALSE) + blocks_air = ZONE_BLOCKED + else + set_density(TRUE) + blocks_air = AIR_BLOCKED + + for(var/turf/turf in loc) + if(turf.simulated) + SSair.mark_for_update(turf) + update_icon() + update_air() + refresh_opacity() + can_open = WALL_CAN_OPEN + update_icon() + +/turf/wall/proc/update_air() + if(!SSair) + return + + for(var/turf/turf in loc) + if(turf.simulated) + update_thermal(turf) + SSair.mark_for_update(turf) + +/turf/wall/proc/update_thermal(var/turf/source) + if(istype(source) && source.simulated) + if(density && opacity) + source.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + else + source.thermal_conductivity = initial(source.thermal_conductivity) + +/turf/wall/proc/toggle_shutters(mob/user) + if(!isnull(shutter_state)) + shutter_state = !shutter_state + refresh_opacity() + blocks_air = shutter_state ? ZONE_BLOCKED : AIR_BLOCKED + if(simulated) + SSair.mark_for_update(src) + visible_message(SPAN_NOTICE("\The [user] [shutter_state ? "opens" : "closes"] the shutter.")) + update_icon() + if(shutter_sound) + playsound(src, shutter_sound, 25, 1) + return TRUE + return FALSE + +// You can open shutters from two tiles away, as long as nothing is in the way. +/turf/wall/attack_hand_ranged(mob/user) + if((. = ..())) + return + // have to be 2.5 or fewer tiles away + if(get_dist_euclidian(user, src) > 2.5) + return FALSE + // We need to find the closest dir with a shutter. That means a cardinal dir without a connection. + var/list/connected = corner_states_to_dirs(wall_connections) | corner_states_to_dirs(other_connections) // merge the lists + for(var/stepdir in global.cardinal) + if(stepdir in connected) + continue + var/turf/between = get_step(src, stepdir) + // we have a shutter, but can we interact with it? + if(between.density) // the intermediate tile is solid + continue + // Something is blocking either the user or us. + if(!user.Adjacent(between) || !between.Adjacent(src)) + continue + return toggle_shutters(user) + return FALSE + +/turf/wall/proc/try_touch(var/mob/user, var/rotting) + . = TRUE + if(rotting) + if(reinf_material) + to_chat(user, "\The [reinf_material.solid_name] feels porous and crumbly.") + else + to_chat(user, "\The [material.solid_name] [material.rotting_touch_message]!") + dismantle_turf() + return TRUE + + if(can_open) + toggle_open(user) + return TRUE + + if(toggle_shutters(user)) + return TRUE + + if (isnull(construction_stage) || !reinf_material) + to_chat(user, "You push \the [src], but nothing happens.") + playsound(src, hitsound, 25, 1) + return TRUE + +/turf/wall/attack_hand(var/mob/user) + radiate() + add_fingerprint(user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(isliving(user)) + var/mob/living/user_living = user + var/obj/item/hand = GET_EXTERNAL_ORGAN(user_living, user_living.get_active_held_item_slot()) + if(hand && try_graffiti(user_living, hand)) + return TRUE + . = ..() + if(!.) + return try_touch(user, (locate(/obj/effect/overlay/wallrot) in src)) + +/turf/wall/proc/handle_wall_tool_interactions(obj/item/used_item, mob/user) + //get the user's location + if(!isturf(user.loc)) + return FALSE //can't do this stuff whilst inside objects and such + if(!construction_stage && try_graffiti(user, used_item)) + return TRUE + if(used_item) + radiate() + if(used_item.get_heat() >= T100C) + burn(used_item.get_heat()) + . = TRUE + if(locate(/obj/effect/overlay/wallrot) in src) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if( welder.weld(0,user) ) + to_chat(user, "You burn away the fungi with \the [welder].") + playsound(src, 'sound/items/Welder.ogg', 10, 1) + for(var/obj/effect/overlay/wallrot/WR in src) + qdel(WR) + return TRUE + else + var/force = used_item.expend_attack_force(user) + if((!used_item.is_sharp() && !used_item.has_edge() && force >= 10) || force >= 20) + to_chat(user, "\The [src] crumbles away under the force of your [used_item.name].") + physically_destroyed() + return TRUE + var/turf/T = user.loc //get user's location for delay checks + if(damage && istype(used_item, /obj/item/weldingtool)) + + var/obj/item/weldingtool/welder = used_item + + if(welder.weld(0,user)) + to_chat(user, "You start repairing the damage to [src].") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + if(do_after(user, max(5, damage / 5), src) && welder && welder.isOn()) + to_chat(user, "You finish repairing the damage to [src].") + take_damage(-damage) + return TRUE + + // Basic dismantling. + if(isnull(construction_stage) || !reinf_material) + var/datum/extension/demolisher/demolition = get_extension(used_item, /datum/extension/demolisher) + if(istype(demolition) && demolition.try_demolish(user, src)) + return TRUE + + //Reinforced dismantling. + else + switch(construction_stage) + if(6) + + if(used_item.is_special_cutting_tool(TRUE)) + + to_chat(user, "You drive \the [used_item] into the wall and begin trying to rip out the support frame...") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + . = TRUE + + if(!do_after(user, 60, src)) + return + + to_chat(user, "You tear through the wall's support system and plating!") + dismantle_turf() + user.visible_message("The wall was torn open by [user]!") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + + else if(IS_WIRECUTTER(used_item)) + playsound(src, 'sound/items/Wirecutter.ogg', 100, 1) + construction_stage = 5 + to_chat(user, "You cut the outer grille.") + update_icon() + return TRUE + if(5) + if(IS_SCREWDRIVER(used_item)) + to_chat(user, "You begin removing the support lines.") + playsound(src, 'sound/items/Screwdriver.ogg', 100, 1) + . = TRUE + if(!do_after(user,40,src) || !istype(src, /turf/wall) || construction_stage != 5) + return + construction_stage = 4 + update_icon() + to_chat(user, "You remove the support lines.") + return + else if(istype(used_item,/obj/item/weldingtool)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) + construction_stage = 6 + update_icon() + to_chat(user, SPAN_NOTICE("You repair the outer grille.")) + return TRUE + if(4) + var/cut_cover + if(istype(used_item,/obj/item/weldingtool)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) + cut_cover=1 + else + return + else if (used_item.is_special_cutting_tool()) + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item + if(!cutter.slice(user)) + return + cut_cover = 1 + if(cut_cover) + to_chat(user, "You begin slicing through the metal cover.") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + . = TRUE + if(!do_after(user, 60, src) || !istype(src, /turf/wall) || construction_stage != 4) + return + construction_stage = 3 + update_icon() + to_chat(user, "You press firmly on the cover, dislodging it.") + return + if(3) + if(IS_CROWBAR(used_item)) + to_chat(user, "You struggle to pry off the cover.") + playsound(src, 'sound/items/Crowbar.ogg', 100, 1) + . = TRUE + if(!do_after(user,100,src) || !istype(src, /turf/wall) || construction_stage != 3) + return + construction_stage = 2 + update_icon() + to_chat(user, "You pry off the cover.") + return + if(2) + if(IS_WRENCH(used_item)) + to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame.") + playsound(src, 'sound/items/Ratchet.ogg', 100, 1) + . = TRUE + if(!do_after(user,40,src) || !istype(src, /turf/wall) || construction_stage != 2) + return + construction_stage = 1 + update_icon() + to_chat(user, "You remove the bolts anchoring the support rods.") + return + if(1) + var/cut_cover + if(istype(used_item, /obj/item/weldingtool)) + var/obj/item/weldingtool/welder = used_item + if( welder.weld(0,user) ) + cut_cover=1 + else + return + else if(used_item.is_special_cutting_tool()) + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item + if(!cutter.slice(user)) + return + cut_cover = 1 + if(cut_cover) + to_chat(user, "You begin slicing through the support rods.") + playsound(src, 'sound/items/Welder.ogg', 100, 1) + . = TRUE + if(!do_after(user,70,src) || !istype(src, /turf/wall) || construction_stage != 1) + return + construction_stage = 0 + update_icon() + to_chat(user, "You cut the support rods loose from the frame.") + return + if(0) + if(IS_CROWBAR(used_item)) + to_chat(user, "You struggle to pry off the outer sheath.") + playsound(src, 'sound/items/Crowbar.ogg', 100, 1) + . = TRUE + if(!do_after(user,100,src) || !istype(src, /turf/wall) || !user || !used_item || !T ) return + if(user.loc == T && user.get_active_held_item() == used_item ) + to_chat(user, "You pry off the outer sheath.") + dismantle_turf() + return + + return FALSE + +/turf/wall/attackby(var/obj/item/used_item, var/mob/user, click_params) + + if(istype(used_item, /obj/item/stack/tile/roof) || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES) || !used_item.user_can_attack_with(user)) + return ..() + + if(handle_wall_tool_interactions(used_item, user)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return TRUE + + if(istype(used_item,/obj/item/frame)) + var/obj/item/frame/F = used_item + F.try_build(src, click_params) + return TRUE + + // Attack the wall with items + var/force = used_item.expend_attack_force(user) + if(istype(used_item,/obj/item/rcd) || istype(used_item, /obj/item/chems) || !force || user.check_intent(I_FLAG_HELP)) + return ..() + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(src) + var/material_divisor = max(material.brute_armor, reinf_material?.brute_armor) + if(used_item.atom_damage_type == BURN) + material_divisor = max(material.burn_armor, reinf_material?.burn_armor) + var/effective_force = round(force / material_divisor) + if(effective_force < 2) + visible_message(SPAN_DANGER("\The [user] [used_item.pick_attack_verb()] \the [src] with \the [used_item], but it had no effect!")) + playsound(src, hitsound, 25, 1) + return TRUE + // Check for a glancing blow. + var/dam_prob = max(0, 100 - material.hardness + effective_force + used_item.armor_penetration) + if(!prob(dam_prob)) + visible_message(SPAN_DANGER("\The [user] [used_item.pick_attack_verb()] \the [src] with \the [used_item], but it bounced off!")) + playsound(src, hitsound, 25, 1) + if(user.skill_fail_prob(SKILL_HAULING, 40, SKILL_ADEPT)) + SET_STATUS_MAX(user, STAT_WEAK, 2) + visible_message(SPAN_DANGER("\The [user] is knocked back by the force of the blow!")) + return TRUE + + playsound(src, get_hit_sound(), 50, 1) + visible_message(SPAN_DANGER("\The [user] [used_item.pick_attack_verb()] \the [src] with \the [used_item]!")) + take_damage(effective_force) + return TRUE \ No newline at end of file diff --git a/code/game/turfs/walls/wall_brick.dm b/code/game/turfs/walls/wall_brick.dm new file mode 100644 index 000000000000..1c529c70ab28 --- /dev/null +++ b/code/game/turfs/walls/wall_brick.dm @@ -0,0 +1,49 @@ +/turf/wall/brick + icon_state = "brick" + material = /decl/material/solid/stone/sandstone + girder_material = null + floor_type = /turf/floor/dirt + min_dismantle_amount = 3 + max_dismantle_amount = 5 + +/turf/wall/brick/shutter + shutter_state = FALSE + icon_state = "brick_shutter" + +/turf/wall/brick/get_dismantle_stack_type() + return /obj/item/stack/material/brick + +/turf/wall/brick/get_wall_icon() + return 'icons/turf/walls/brick.dmi' + +/turf/wall/brick/get_dismantle_sound() + return 'sound/foley/wooden_drop.ogg' // todo + +/turf/wall/brick/update_strings() + if(reinf_material) + SetName("reinforced [material.solid_name] brick wall") + desc = "A brick wall made of [material.solid_name] and reinforced with [reinf_material.solid_name]." + else + SetName("[material.solid_name] brick wall") + desc = "A brick wall made of [material.solid_name]." + +// Subtypes. +#define MATERIAL_BRICK_WALL(material_name) \ +/turf/wall/brick/##material_name { \ + color = /decl/material/solid/stone/##material_name::color; \ + material = /decl/material/solid/stone/##material_name; \ +}; \ +/turf/wall/brick/##material_name/shutter { \ + shutter_state = FALSE; \ + icon_state = "brick_shutter"; \ +}; \ +/turf/wall/brick/##material_name/shutter/open { \ + shutter_state = TRUE; \ +} + +MATERIAL_BRICK_WALL(sandstone) +MATERIAL_BRICK_WALL(basalt) +MATERIAL_BRICK_WALL(granite) +MATERIAL_BRICK_WALL(marble) +MATERIAL_BRICK_WALL(pottery) +#undef MATERIAL_BRICK_WALL diff --git a/code/game/turfs/walls/wall_engraving.dm b/code/game/turfs/walls/wall_engraving.dm new file mode 100644 index 000000000000..ee730aa2a220 --- /dev/null +++ b/code/game/turfs/walls/wall_engraving.dm @@ -0,0 +1,16 @@ +/datum/engraving + var/name = "nondescript design" + var/desc + var/icon + var/icon_state + var/dir + +/datum/engraving/New(var/decl/banner_symbol/engraving_symbol) + if(engraving_symbol) + icon = engraving_symbol.icon + icon_state = engraving_symbol.icon_state + name = engraving_symbol.name + +/datum/engraving/random/New() + var/banner_decls = decls_repository.get_decls_of_subtype_unassociated(/decl/banner_symbol) + ..(pick(banner_decls)) diff --git a/code/game/turfs/walls/wall_icon.dm b/code/game/turfs/walls/wall_icon.dm new file mode 100644 index 000000000000..ee87ca410015 --- /dev/null +++ b/code/game/turfs/walls/wall_icon.dm @@ -0,0 +1,234 @@ +/turf/wall/proc/refresh_opacity() + return set_opacity(!(!density || shutter_state == TRUE || (istype(material) && material.opacity < 0.5))) + +/turf/wall/proc/update_material(var/update_neighbors) + if(construction_stage != -1) + if(reinf_material) + construction_stage = 6 + else + construction_stage = null + if(!material) + material = get_default_material() + if(material) + explosion_resistance = material.explosion_resistance + hitsound = material.hitsound + if(reinf_material) + reinf_icon = islist(reinf_material.icon_reinf) ? pick(reinf_material.icon_reinf) : reinf_material.icon_reinf + if(reinf_material.explosion_resistance > explosion_resistance) + explosion_resistance = reinf_material.explosion_resistance + else + reinf_icon = null + update_strings() + refresh_opacity() + SSradiation.resistance_cache.Remove(src) + if(update_neighbors) + var/iterate_turfs = list() + for(var/direction in global.alldirs) + var/turf/wall/wall = get_step_resolving_mimic(src, direction) + if(istype(wall)) + wall.wall_connections = null + wall.other_connections = null + iterate_turfs += wall + for(var/turf/wall/wall as anything in iterate_turfs) + wall.lazy_update_icon() + else + wall_connections = null + other_connections = null + lazy_update_icon() + +/turf/wall/proc/paint_wall(var/new_paint_color) + paint_color = new_paint_color + update_icon() + +/turf/wall/proc/stripe_wall(var/new_paint_color) + stripe_color = new_paint_color + update_icon() + +/turf/wall/proc/update_strings() + if(reinf_material) + SetName("reinforced [material.solid_name] [material.wall_name]") + desc = "It seems to be a section of hull reinforced with [reinf_material.solid_name] and plated with [material.solid_name]." + else + SetName("[material.solid_name] [material.wall_name]") + desc = "It seems to be a section of hull plated with [material.solid_name]." + +/turf/wall/proc/get_wall_icon() + . = (istype(material) && material.icon_base) || 'icons/turf/walls/solid.dmi' + +/turf/wall/proc/apply_reinf_overlay() + . = istype(reinf_material) && reinf_icon + +/// Gets the base wall colour for icon rendering. Can be overridden on wall subtypes. Not equivalent to get_color(). +/// Should only be used in places where material is known to be set, e.g. update_wall_icon(). +/turf/wall/proc/get_base_color() + return material.color + +/// Gets the reinforcement colour. Can be overridden so that some wall types don't apply paint colour to their reinforcements. +/turf/wall/proc/get_reinf_color() + return paint_color || reinf_material?.color + +/turf/wall/proc/refresh_connections() + if(wall_connections && other_connections) + return + var/list/wall_dirs = list() + var/list/other_dirs = list() + for(var/stepdir in global.alldirs) + var/turf/T = get_step_resolving_mimic(src, stepdir) + if(!T) + continue + if(istype(T, /turf/wall)) + switch(can_join_with(T)) + if(0) + continue + if(1) + wall_dirs += stepdir + if(2) + wall_dirs += stepdir + other_dirs += stepdir + + if(handle_structure_blending) + var/success = 0 + for(var/O in T) + for(var/blend_type in global.wall_blend_objects) + if(istype(O, blend_type)) + success = TRUE + break + for(var/nb_type in global.wall_noblend_objects) + if(istype(O, nb_type)) + success = FALSE + break + if(success) + wall_dirs += get_dir(src, T) + if(get_dir(src, T) in global.cardinal) + var/blendable = FALSE + for(var/fb_type in global.wall_fullblend_objects) + if(istype(O, fb_type)) + blendable = TRUE + break + if(!blendable) + other_dirs += get_dir(src, T) + break + wall_connections = dirs_to_corner_states(wall_dirs) + other_connections = dirs_to_corner_states(other_dirs) + +/turf/wall/proc/update_wall_icon() + + var/material_icon_base = get_wall_icon() + var/base_color = get_base_color() + + var/new_icon + var/new_icon_state + var/new_color + + if(!density) + new_icon = material_icon_base + new_icon_state = "fwall_open" + new_color = base_color + else + new_icon = get_combined_wall_icon(wall_connections, other_connections, material_icon_base, base_color, paint_color, stripe_color, (material.wall_flags & WALL_HAS_EDGES) && (stripe_color || base_color)) + new_icon_state = "" + new_color = null + + if(icon != new_icon) + icon = new_icon + if(icon_state != new_icon_state) + icon_state = new_icon_state + if(color != new_color) + color = new_color + + if(apply_reinf_overlay()) + var/image/I + var/reinf_color = get_reinf_color() + if(construction_stage != null && construction_stage < 6) + I = image('icons/turf/walls/_construction_overlays.dmi', "[construction_stage]") + I.color = reinf_color + add_overlay(I) + else + if(reinf_material.use_reinf_state) + I = image(reinf_icon, reinf_material.use_reinf_state) + I.color = reinf_color + else + I = image(_get_wall_subicon(reinf_icon, wall_connections, reinf_color)) + add_overlay(I) + +// Update icon on ambient light change, for shutter overlays. +/turf/wall/update_ambient_light_from_z_or_area() + . = ..() + if(shutter_state) + queue_icon_update() + +/turf/wall/on_update_icon() + . = ..() + cut_overlays() + + if(!istype(material)) + return + + refresh_connections() + update_wall_icon() + + var/image/texture = material.get_wall_texture() + if(texture) + add_overlay(texture) + + if(!isnull(shutter_state) && shutter_icon) + var/decl/material/shutter_mat = shutter_material || material + var/new_light_dir // get the opposite direction associated with the strongest light + var/light_str // the strength associated with new_light_dir + var/new_light_color // get the color associated with the strongest light + var/list/shutters + var/list/connected = corner_states_to_dirs(wall_connections) | corner_states_to_dirs(other_connections) // merge the lists + set_light(0) // disable our own light before we calculate light strength + for(var/stepdir in global.cardinal) + if(stepdir in connected) + continue + var/turf/neighbor = get_step_resolving_mimic(src, stepdir) + if(!istype(neighbor) || neighbor.density) + continue + LAZYADD(shutters, image(shutter_icon, num2text(shutter_state), dir = stepdir)) + if(shutter_state) + var/turf/other_neighbor = get_step_resolving_mimic(src, global.reverse_dir[stepdir]) + if(istype(other_neighbor)) + var/light_amt = 255 * other_neighbor.get_lumcount() + if(other_neighbor.lighting_overlay && light_amt > 0) // get_lumcount defaults to 0.5 if lighting_overlay is null + if(!new_light_dir || light_str < light_amt / 255) + new_light_dir = stepdir + light_str = light_amt / 255 + new_light_color = other_neighbor.get_avg_color() + var/image/light_overlay = emissive_overlay(shutter_icon, "glow", dir = stepdir, color = other_neighbor.get_avg_color()) + light_overlay.alpha = light_amt + light_overlay.appearance_flags |= RESET_COLOR|RESET_ALPHA + LAZYADD(shutters, light_overlay) + // create a light cone in the direction of new_light_dir with color new_light_color + if(new_light_dir) + light_dir = new_light_dir + set_light(7, light_str, new_light_color, LIGHT_WIDE) + else + light_dir = null + set_light(0) + + if(length(shutters)) + var/image/shutter_image = new /image + shutter_image.overlays = shutters + shutter_image.color = shutter_mat.color + shutter_image.appearance_flags |= RESET_COLOR|RESET_ALPHA + add_overlay(shutter_image) + + if(damage != 0 && SSmaterials.wall_damage_overlays) + var/integrity = material.integrity + if(reinf_material) + integrity += reinf_material.integrity + add_overlay(SSmaterials.wall_damage_overlays[clamp(round(damage / integrity * DAMAGE_OVERLAY_COUNT) + 1, 1, DAMAGE_OVERLAY_COUNT)]) + +/turf/wall/proc/can_join_with(var/turf/wall/wall) + if(unique_merge_identifier != wall.unique_merge_identifier) + return 0 + else if(unique_merge_identifier) + return 1 + else if(material && istype(wall.material)) + var/other_wall_icon = wall.get_wall_icon() + if(get_wall_icon() == other_wall_icon) + return 1 + if(material.wall_blend_icons[other_wall_icon]) + return 2 + return 0 diff --git a/code/game/turfs/walls/wall_log.dm b/code/game/turfs/walls/wall_log.dm new file mode 100644 index 000000000000..7cdf1fedc1a8 --- /dev/null +++ b/code/game/turfs/walls/wall_log.dm @@ -0,0 +1,52 @@ +/turf/wall/log + icon_state = "log" + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + girder_material = null + floor_type = /turf/floor/dirt + min_dismantle_amount = 3 + max_dismantle_amount = 5 + +/turf/wall/log/shutter + shutter_state = FALSE + icon_state = "log_shutter" + +/turf/wall/log/get_dismantle_stack_type() + return /obj/item/stack/material/log + +/turf/wall/log/get_wall_icon() + return 'icons/turf/walls/log.dmi' + +/turf/wall/log/get_dismantle_sound() + return 'sound/foley/wooden_drop.ogg' + +/turf/wall/log/update_strings() + if(reinf_material) + SetName("reinforced [material.solid_name] log wall") + desc = "A log wall made of [material.solid_name] and reinforced with [reinf_material.solid_name]." + else + SetName("[material.solid_name] log wall") + desc = "A log wall made of [material.solid_name]." + +// Subtypes. +#define LOG_WALL_SUBTYPE(material_name) \ +/turf/wall/log/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ + color = /decl/material/solid/organic/wood/##material_name::color; \ +}; \ +/turf/wall/log/##material_name/shutter { \ + shutter_state = FALSE; \ + icon_state = "log_shutter"; \ +}; \ +/turf/wall/log/##material_name/shutter/open { \ + shutter_state = TRUE; \ +} +LOG_WALL_SUBTYPE(fungal) +LOG_WALL_SUBTYPE(ebony) +LOG_WALL_SUBTYPE(walnut) +LOG_WALL_SUBTYPE(maple) +LOG_WALL_SUBTYPE(mahogany) +LOG_WALL_SUBTYPE(bamboo) +LOG_WALL_SUBTYPE(yew) + +#undef LOG_WALL_SUBTYPE \ No newline at end of file diff --git a/code/game/turfs/walls/wall_material.dm b/code/game/turfs/walls/wall_material.dm new file mode 100644 index 000000000000..f82b5d0be9a0 --- /dev/null +++ b/code/game/turfs/walls/wall_material.dm @@ -0,0 +1,31 @@ +/turf/wall/get_default_material() + . = GET_DECL(DEFAULT_WALL_MATERIAL) + +/turf/wall/set_turf_materials(decl/material/new_material, decl/material/new_reinf_material, force, decl/material/new_girder_material, skip_update) + + if(ispath(new_material)) + new_material = GET_DECL(new_material) + + if(material != new_material || !force) + material = new_material + if(!istype(material)) + PRINT_STACK_TRACE("Wall has been supplied non-material '[material]'.") + material = get_default_material() + . = TRUE + + if(ispath(new_reinf_material)) + new_reinf_material = GET_DECL(new_reinf_material) + if(reinf_material != new_reinf_material || !force) + reinf_material = new_reinf_material + . = TRUE + + if(ispath(new_girder_material)) + new_girder_material = GET_DECL(new_girder_material) + if(girder_material != new_girder_material || force) + girder_material = new_girder_material + . = TRUE + + if(.) + state_was_modified() + if(!skip_update) + queue_icon_update() diff --git a/code/game/turfs/walls/wall_natural.dm b/code/game/turfs/walls/wall_natural.dm new file mode 100644 index 000000000000..b8ba4f36922b --- /dev/null +++ b/code/game/turfs/walls/wall_natural.dm @@ -0,0 +1,239 @@ +var/global/_wall_chisel_skill = SKILL_CONSTRUCTION + +/turf/wall/natural + icon_state = "natural" + desc = "A rough natural wall." + turf_flags = TURF_FLAG_BACKGROUND | TURF_IS_HOLOMAP_OBSTACLE + girder_material = null + floor_type = /turf/floor/rock + construction_stage = -1 + var/strata_override + var/ramp_slope_direction + var/image/ore_overlay + var/static/list/exterior_wall_shine_cache = list() + var/being_mined = FALSE + var/gem_dropped = FALSE + var/smoothed + var/list/engravings + +/turf/wall/natural/flooded + flooded = /decl/material/liquid/water + color = COLOR_LIQUID_WATER + +/turf/wall/natural/flooded/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water, NOT 10% salt + +/turf/wall/natural/get_paint_examine_message() + return SPAN_NOTICE("It has been noticeably discoloured by the elements.") + +/turf/wall/natural/get_wall_icon() + return (smoothed && !ramp_slope_direction) ? 'icons/turf/walls/stone.dmi' : 'icons/turf/walls/natural.dmi' + +/turf/wall/natural/Initialize(var/ml, var/materialtype, var/rmaterialtype) + . = ..() + var/area/A = get_area(src) + if(A.allow_xenoarchaeology_finds) + if(!SSxenoarch.initialized) + SSxenoarch.possible_spawn_walls += src + set_extension(src, /datum/extension/geological_data) + // Init ramp state if needed. + if(ramp_slope_direction) + make_ramp(null, ramp_slope_direction, TRUE) + +/turf/wall/natural/LateInitialize(var/ml) + //Set the rock color + if(!paint_color) + paint_color = SSmaterials.get_rock_color(src) + ..() + spread_deposit() + if(!ramp_slope_direction && floor_type && HasAbove(z)) + var/turf/T = GetAbove(src) + if(!istype(T, floor_type) && T.is_open()) + T.ChangeTurf(floor_type, keep_air = TRUE) + +/turf/wall/natural/Destroy() + SSxenoarch.digsite_spawning_turfs -= src + if(!ramp_slope_direction) + update_neighboring_ramps(destroying_self = TRUE) + . = ..() + +/turf/wall/natural/proc/get_engraving_for_dir(facing_dir) + for(var/datum/engraving/engraving in engravings) + if(engraving.dir == facing_dir) + return engraving + +/turf/wall/natural/attack_hand(mob/user) + + // Allow species with digging limbs to dig (drakes) + var/obj/item/prop = user.get_usable_hand_slot_organ() + if(istype(prop)) + return attackby(prop, user) + + . = ..() + +/turf/wall/natural/attackby(obj/item/used_item, mob/user, click_params) + + if(!ramp_slope_direction && user.check_dexterity(DEXTERITY_COMPLEX_TOOLS, silent = TRUE)) + + if(istype(used_item, /obj/item/depth_scanner)) + var/obj/item/depth_scanner/C = used_item + C.scan_atom(user, src) + return TRUE + + if (istype(used_item, /obj/item/measuring_tape)) + var/obj/item/measuring_tape/P = used_item + user.visible_message(SPAN_NOTICE("\The [user] extends [P] towards [src]."),SPAN_NOTICE("You extend [P] towards [src].")) + if(do_after(user,10, src)) + to_chat(user, SPAN_NOTICE("\The [src] has been excavated to a depth of [excavation_level]cm.")) + return TRUE + + if(istype(used_item, /obj/item/tool/xeno)) + return handle_xenoarch_tool_interaction(used_item, user) + + . = ..() + +// Drill out natural walls. +/turf/wall/natural/handle_wall_tool_interactions(obj/item/used_item, mob/user) + if(IS_PICK(used_item) && !being_mined) + var/check_material_hardness + if(material) + check_material_hardness = material.hardness + if(reinf_material && (isnull(check_material_hardness) || check_material_hardness > reinf_material.hardness)) + check_material_hardness = reinf_material.hardness + if(isnull(check_material_hardness) || used_item.material?.hardness < check_material_hardness) + to_chat(user, SPAN_WARNING("\The [used_item] is not hard enough to dig through \the [src].")) + return TRUE + if(being_mined) + return TRUE + being_mined = TRUE + if(used_item.do_tool_interaction(TOOL_PICK, user, src, 2 SECONDS, suffix_message = destroy_artifacts(used_item, INFINITY))) + dismantle_turf() + if(istype(src, /turf/wall/natural)) // dismantle_turf() can change our type + being_mined = FALSE + return TRUE + return FALSE + +/turf/wall/natural/update_strings() + var/modifier + if(length(engravings)) + modifier = "engraved" + else if(smoothed) + if(reinf_material) + modifier = "polished" + else + modifier = "smooth" + else if(!reinf_material) + modifier = "natural" + + if(reinf_material) + if(modifier) + SetName("[modifier] [reinf_material.ore_name] deposit") + else + SetName("[reinf_material.ore_name] deposit") + desc = "A natural wall composed of bare [material.solid_name] and a deposit of [reinf_material.ore_name]." + else + SetName("[modifier] [material.solid_name] wall") + desc = "A natural wall composed of bare [material.solid_name]." + +/turf/wall/natural/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(length(engravings)) + for(var/datum/engraving/engraving in engravings) + var/engraving_line + if(engraving.name) + engraving_line = "It has been engraved with \a [engraving.name]." + else + engraving_line = "It has been engraved." + if(engraving.desc) + engraving_line = "[engraving_line] [engraving.desc]" + . += engraving_line + +/turf/wall/natural/update_material(var/update_neighbors) + if(reinf_material?.ore_icon_overlay) + ore_overlay = image('icons/turf/mining_decals.dmi', "[reinf_material.ore_icon_overlay]") + ore_overlay.appearance_flags = RESET_COLOR + var/matrix/M + if(prob(50)) + M = M || matrix() + M.Scale(-1,1) + if(prob(75)) + M = M || matrix() + M.Turn(pick(90, 180, 270)) + ore_overlay.color = reinf_material.color + ore_overlay.layer = DECAL_LAYER + if(M) + ore_overlay.transform = M + . = ..() + +/turf/wall/natural/drop_dismantled_products(devastated, explode) + drop_ore() + +/turf/wall/natural/get_dismantle_sound() + return 'sound/effects/rockcrumble.ogg' + +// Natural walls are typically dense, and should not contain any air a-la normal walls, so we set keep_air = FALSE by default. +/turf/wall/natural/dismantle_turf(devastated, explode, no_product, keep_air = FALSE, ramp_update = TRUE) + destroy_artifacts(null, INFINITY) + if(ramp_update && !ramp_slope_direction) + ramp_slope_direction = NORTH // Temporary so we don't let any neighboring ramps use us as supports. + update_neighboring_ramps() + ramp_slope_direction = null + return ..(devastated, explode, no_product, keep_air) + +/turf/wall/natural/Bumped(var/atom/movable/AM) + . = ..() + if(!. && !ramp_slope_direction && ismob(AM)) + var/mob/M = AM + var/obj/item/held = M.get_active_held_item() + if(IS_PICK(held)) + attackby(held, M) + return TRUE + +/turf/wall/natural/proc/drop_ore() + if(reinf_material?.ore_result_amount) + var/drop_type = reinf_material.ore_type || /obj/item/stack/material/ore + pass_geodata_to(new drop_type(src, reinf_material.ore_result_amount, reinf_material.type)) + reinf_material = null + ore_overlay = null + update_material(FALSE) + if(prob(30) && !ramp_slope_direction && material) + var/drop_type = material.ore_type || /obj/item/stack/material/ore + pass_geodata_to(new drop_type(src, material.ore_result_amount, material.type)) + if(!gem_dropped && material && prob(material.gemstone_chance) && LAZYLEN(material.gemstone_types)) + gem_dropped = TRUE + new /obj/item/gemstone(get_turf(src), pickweight(material.gemstone_types)) + visible_message(SPAN_NOTICE("A glimmer of colour shines amongst the rubble...")) + +/turf/wall/natural/proc/pass_geodata_to(obj/O) + var/datum/extension/geological_data/ours = get_extension(src, /datum/extension/geological_data) + if(ours?.geodata) + ours.geodata.UpdateNearbyArtifactInfo(src) + set_extension(O, /datum/extension/geological_data) + var/datum/extension/geological_data/newdata = get_extension(O, /datum/extension/geological_data) + if(newdata) + newdata.set_data(ours.geodata.get_copy()) + +/turf/wall/natural/proc/spread_deposit() + if(!istype(reinf_material) || reinf_material.ore_spread_chance <= 0) + return + for(var/trydir in global.cardinal) + if(!prob(reinf_material.ore_spread_chance)) + continue + var/turf/wall/natural/target_turf = get_step_resolving_mimic(src, trydir) + if(!istype(target_turf) || !isnull(target_turf.reinf_material) || target_turf.ramp_slope_direction) + continue + target_turf.set_turf_materials(target_turf.material, reinf_material) + target_turf.spread_deposit() + +/turf/wall/natural/get_default_material() + . = GET_DECL(get_strata_material_type() || /decl/material/solid/stone/sandstone) + +/turf/wall/natural/get_strata_material_type() + //Turf strata overrides level strata + if(ispath(strata_override, /decl/strata)) + var/decl/strata/S = GET_DECL(strata_override) + if(length(S.base_materials)) + return pick(S.base_materials) + //Otherwise, just use level strata + return ..() diff --git a/code/game/turfs/walls/wall_natural_icon.dm b/code/game/turfs/walls/wall_natural_icon.dm new file mode 100644 index 000000000000..f19a8db6c4d6 --- /dev/null +++ b/code/game/turfs/walls/wall_natural_icon.dm @@ -0,0 +1,115 @@ +// Somewhat simplified compared to base walls, but needs to take ramp slope into account. +/turf/wall/natural/refresh_connections() + wall_connections = list() + for(var/stepdir in global.alldirs) + // Get the wall. + var/turf/wall/natural/T = get_step_resolving_mimic(src, stepdir) + if(!istype(T)) + continue + if(ramp_slope_direction) // We are a ramp. + // Adjacent ramps flowing in the same direction as us. + if(ramp_slope_direction == T.ramp_slope_direction) + wall_connections += stepdir + continue + // It's an adjacent non-ramp wall. + if(!T.ramp_slope_direction) + // It is behind us. + if(stepdir & global.reverse_dir[ramp_slope_direction]) + wall_connections += stepdir + continue + else // We are a wall. + // It is a wall. + if(!T.ramp_slope_direction) + wall_connections += stepdir + continue + // It's a ramp running away from us. + if(stepdir & T.ramp_slope_direction) + wall_connections += stepdir + continue + wall_connections = dirs_to_corner_states(wall_connections) + +/turf/wall/natural/update_wall_icon() + + var/material_icon_base = get_wall_icon() + var/base_color = material.color + var/shine = 0 + + if(material.reflectiveness > 0) + var/shine_cache_key = "[material.reflectiveness]-[material.color]" + shine = exterior_wall_shine_cache[shine_cache_key] + if(isnull(shine)) + // patented formula based on color's value (in HSV) + shine = clamp((material.reflectiveness * 0.01) * 255, 10, (0.6 * rgb2num(material.color, COLORSPACE_HSV)[3])) + exterior_wall_shine_cache[shine_cache_key] = shine + + var/new_icon + var/new_icon_state + var/new_color + + if(ramp_slope_direction) + + // TODO: make this a check on flooring when floor unification is in. + var/turf/floor_data = floor_type + new_icon = initial(floor_data.icon) + new_icon_state = initial(floor_data.icon_state) + new_color = base_color + + var/turf/wall/natural/neighbor = get_step(src, turn(ramp_slope_direction, -90)) + var/has_left_neighbor = istype(neighbor) && neighbor.ramp_slope_direction == ramp_slope_direction + neighbor = get_step(src, turn(ramp_slope_direction, 90)) + var/has_right_neighbor = istype(neighbor) && neighbor.ramp_slope_direction == ramp_slope_direction + var/state = "ramp-single" + if(has_left_neighbor && has_right_neighbor) + state = "ramp-blend-full" + else if(has_left_neighbor) + state = "ramp-blend-left" + else if(has_right_neighbor) + state = "ramp-blend-right" + var/image/I = image(icon = material_icon_base, icon_state = state, dir = ramp_slope_direction) + add_overlay(I) + if(shine) + I = image(icon = material_icon_base, icon_state = "[state]-shine", dir = ramp_slope_direction) + I.appearance_flags |= RESET_ALPHA + I.alpha = shine + add_overlay(I) + else + new_icon = get_combined_wall_icon(wall_connections, null, material_icon_base, base_color, shine_value = shine) + new_icon_state = "" + new_color = null + + if(icon_state != new_icon_state) + icon_state = new_icon_state + if(color != new_color) + color = new_color + if(icon != new_icon) + icon = new_icon + +/turf/wall/natural/on_update_icon() + . = ..() + if(ore_overlay) + add_overlay(ore_overlay) + if(excav_overlay) + add_overlay(excav_overlay) + if(archaeo_overlay) + add_overlay(archaeo_overlay) + + // Might be worth having a dedicated wall engraving icon set in the future instead of using the banner/sign symbols. + // That would let us avoid this offsetting stuff and make the icons look less wonky on foreshortened faces. + for(var/datum/engraving/engraving in engravings) + // Not aware of a nice way to handle this. Would like to use BLEND_INSET_OVERLAY but we need BLEND_MULTIPLY. + if(engraving.dir == NORTH || !engraving.icon || !engraving.icon_state) + continue + + var/y_offset = 9 + var/x_offset = 0 + if(engraving.dir == SOUTH) + y_offset = 0 + else if(engraving.dir == EAST) + x_offset = -1 + else if(engraving.dir == WEST) + x_offset = 1 + + var/image/eng = image(icon = engraving.icon, icon_state = engraving.icon_state, dir = engraving.dir, pixel_x = x_offset, pixel_y = y_offset) + eng.blend_mode = BLEND_MULTIPLY + add_overlay(eng) + diff --git a/code/game/turfs/walls/wall_natural_ramps.dm b/code/game/turfs/walls/wall_natural_ramps.dm new file mode 100644 index 000000000000..76526f13e7ad --- /dev/null +++ b/code/game/turfs/walls/wall_natural_ramps.dm @@ -0,0 +1,83 @@ +/turf/wall/natural/proc/make_ramp(var/mob/user, var/new_slope, var/skip_icon_update = FALSE) + + if(ramp_slope_direction == new_slope) + return + + state_was_modified() + ramp_slope_direction = new_slope + QDEL_NULL_LIST(engravings) + + var/old_ao = permit_ao + if(!ramp_slope_direction) + user?.visible_message(SPAN_NOTICE("\The [user] clears out \the [src].")) + ChangeTurf(floor_type) + return + + user?.visible_message(SPAN_NOTICE("\The [user] digs out \the [src], forming a ramp.")) + drop_ore() + permit_ao = FALSE + blocks_air = FALSE + density = FALSE + opacity = FALSE + decals = null + var/turf/ramp_above = GetAbove(src) + if(ramp_above) + ramp_above.handle_ramp_dug_below(src) + update_neighboring_ramps() + update_icon() + + if(!skip_icon_update) + for(var/turf/wall/natural/neighbor in RANGE_TURFS(src, 1)) + neighbor.update_icon() + if(old_ao != permit_ao) + regenerate_ao() + +/turf/wall/natural/proc/update_neighboring_ramps(destroying_self) + // Clear any ramps we were supporting. + for(var/turf/wall/natural/neighbor in RANGE_TURFS(src, 1)) + if(!neighbor.ramp_slope_direction || neighbor == src) + continue + var/turf/wall/natural/support = get_step(neighbor, global.reverse_dir[neighbor.ramp_slope_direction]) + if(!istype(support) || (destroying_self && support == src) || support.ramp_slope_direction) + neighbor.dismantle_turf(ramp_update = FALSE) // This will only occur on ramps, so no need to propagate to other ramps. + +/turf/wall/natural/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/dig_ramp) + +/decl/interaction_handler/dig_ramp + name = "Dig Ramp" + expected_target_type = /turf/wall/natural + examine_desc = "dig a ramp in the direction you are facing" + +/decl/interaction_handler/dig_ramp/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + if(!IS_PICK(prop) && !IS_SHOVEL(prop)) + return FALSE + var/turf/wall/natural/wall = target + if(!HasAbove(wall.z)) + return FALSE + if(!user.Adjacent(target)) + return FALSE + return TRUE + +/decl/interaction_handler/dig_ramp/invoked(atom/target, mob/user, obj/item/prop) + var/turf/wall/natural/wall = target + var/user_dir = get_dir(wall, user) + if(!(user_dir in global.cardinal)) + to_chat(user, SPAN_WARNING("You must be standing at a cardinal angle to create a ramp.")) + return FALSE + prop ||= user.get_usable_hand_slot_organ() // Allows drakes to dig. + if(wall.material?.hardness > prop?.material?.hardness) + to_chat(user, SPAN_WARNING("Your [prop.name] is not hard enough to cut into \the [wall].")) + return FALSE + var/turf/wall/natural/support = get_step(wall, global.reverse_dir[user_dir]) + if(!istype(support) || support.ramp_slope_direction) + to_chat(user, SPAN_WARNING("You cannot cut a ramp into a wall with no additional walls behind it.")) + return FALSE + if(prop.do_tool_interaction((IS_PICK(prop) ? TOOL_PICK : TOOL_SHOVEL), user, wall, 3 SECONDS, suffix_message = ", forming it into a ramp") && !wall.ramp_slope_direction) + wall.make_ramp(user, user_dir) + return TRUE + return FALSE diff --git a/code/game/turfs/walls/wall_natural_subtypes.dm b/code/game/turfs/walls/wall_natural_subtypes.dm new file mode 100644 index 000000000000..dc072ac25193 --- /dev/null +++ b/code/game/turfs/walls/wall_natural_subtypes.dm @@ -0,0 +1,106 @@ +/turf/wall/natural/random + reinf_material = null + +// We want to avoid spawning random ores in Initialize() by serializing a subtype that does that. +/turf/wall/natural/random/GetSerializedType() + return /turf/wall/natural + +/turf/wall/natural/random/proc/get_weighted_mineral_list() + if(strata_override) + var/decl/strata/strata_info = GET_DECL(strata_override) + . = strata_info.ores_sparse + if(!.) + . = SSmaterials.weighted_minerals_sparse + +/turf/wall/natural/random/high_chance/get_weighted_mineral_list() + if(strata_override) + var/decl/strata/strata_info = GET_DECL(strata_override) + . = strata_info.ores_rich + if(!.) + . = SSmaterials.weighted_minerals_rich + +/turf/wall/natural/random/Initialize(ml, materialtype, rmaterialtype) + if(!strata_override) + strata_override = SSmaterials.get_strata_type(src) + if(isnull(reinf_material)) + var/default_mineral_list = get_weighted_mineral_list() + if(LAZYLEN(default_mineral_list)) + reinf_material = pickweight(default_mineral_list) + . = ..() + +/turf/wall/natural/volcanic + strata_override = /decl/strata/igneous + +/turf/wall/natural/random/volcanic + strata_override = /decl/strata/igneous + +/turf/wall/natural/random/volcanic/GetSerializedType() + return /turf/wall/natural/volcanic + +/turf/wall/natural/random/high_chance/volcanic + strata_override = /decl/strata/igneous + +/turf/wall/natural/random/high_chance/volcanic/GetSerializedType() + return /turf/wall/natural/volcanic + +/turf/wall/natural/ice + strata_override = /decl/strata/permafrost + floor_type = /turf/floor/ice + +/turf/wall/natural/random/ice + strata_override = /decl/strata/permafrost + floor_type = /turf/floor/ice + +/turf/wall/natural/random/ice/GetSerializedType() + return /turf/wall/natural/ice + +/turf/wall/natural/random/high_chance/ice + strata_override = /decl/strata/permafrost + floor_type = /turf/floor/ice + +/turf/wall/natural/random/high_chance/ice/GetSerializedType() + return /turf/wall/natural/ice + +/turf/wall/natural/dirt + material = /decl/material/solid/soil + color = "#41311b" + floor_type = /turf/floor/dirt + +#define MATERIAL_NATURAL_TURFS(ID, MAT) \ +/turf/floor/rock/##ID { \ + color = /decl/material/##MAT::color; \ + material = /decl/material/##MAT \ +} \ +/turf/floor/rock/##ID/sand { \ + name = "sand"; \ + icon = 'icons/turf/flooring/sand.dmi'; \ + icon_state = "sand0"; \ + color = "#ae9e66"; \ + _flooring = /decl/flooring/sand; \ +} \ +/turf/wall/natural/##ID { \ + material = /decl/material/##MAT; \ + color = /decl/material/##MAT::color; \ + floor_type = /turf/floor/rock/##ID; \ +} \ +/turf/wall/natural/random/##ID { \ + material = /decl/material/##MAT; \ + color = /decl/material/##MAT::color; \ + floor_type = /turf/floor/rock/##ID; \ +} \ +/turf/wall/natural/random/##ID/GetSerializedType() { \ + return /turf/wall/natural/##ID; \ +} \ +/turf/wall/natural/random/high_chance/##ID { \ + material = /decl/material/##MAT; \ + color = /decl/material/##MAT::color; \ + floor_type = /turf/floor/rock/##ID \ +} \ +/turf/wall/natural/random/high_chance/##ID/GetSerializedType() { \ + return /turf/wall/natural/##ID; \ +} +MATERIAL_NATURAL_TURFS(sandstone, solid/stone/sandstone) +MATERIAL_NATURAL_TURFS(basalt, solid/stone/basalt) +MATERIAL_NATURAL_TURFS(granite, solid/stone/granite) +MATERIAL_NATURAL_TURFS(marble, solid/stone/marble) +#undef MATERIAL_NATURAL_TURFS \ No newline at end of file diff --git a/code/game/turfs/walls/wall_natural_xenoarch.dm b/code/game/turfs/walls/wall_natural_xenoarch.dm new file mode 100644 index 000000000000..e1ea12d7dd46 --- /dev/null +++ b/code/game/turfs/walls/wall_natural_xenoarch.dm @@ -0,0 +1,129 @@ +/turf/wall/natural + var/excavation_level = 0 + var/datum/artifact_find/artifact_find + var/list/finds + var/last_excavation + var/next_rock = 0 + var/archaeo_overlay + var/excav_overlay + +/turf/wall/natural/proc/place_artifact_debris(var/severity = 0) + for(var/j in 1 to rand(1, 3 + max(min(severity, 1), 0) * 2)) + switch(rand(1,7)) + if(1) + SSmaterials.create_object(/decl/material/solid/metal/steel, src, rand(5, 25), /obj/item/stack/material/rods) + if(2, 3) + SSmaterials.create_object(/decl/material/solid/metal/plasteel, src, rand(5, 25)) + if(4) + SSmaterials.create_object(/decl/material/solid/metal/steel, src, rand(5, 25)) + if(5) + for(var/i = 1 to rand(1,3)) + new /obj/item/shard(src) + if(6) + for(var/i = 1 to rand(1,3)) + new /obj/item/shard/borosilicate(src) + if(7) + SSmaterials.create_object(/decl/material/solid/metal/uranium, src, rand(5, 25)) + +/turf/wall/natural/proc/excavate_find(var/prob_clean = 0, var/datum/find/F) + //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted + if(prob(F.prob_delicate)) + var/obj/effect/suspension_field/S = locate() in src + if(!S) + visible_message(SPAN_DANGER("[pick("An object in the rock crumbles away into dust.","Something falls out of the rock and shatters onto the ground.")]")) + finds.Remove(F) + return + //with skill and luck, players can cleanly extract finds + //otherwise, they come out inside a chunk of rock + if(prob_clean) + F.spawn_find_item(src) + else + pass_geodata_to(new /obj/item/strangerock(src, F.find_type)) + finds.Remove(F) + +/turf/wall/natural/proc/handle_xenoarch_tool_interaction(var/obj/item/tool/xeno/P, var/mob/user) + . = TRUE + if(P.material?.hardness < material.hardness) + to_chat(user, SPAN_WARNING("\The [P] is not hard enough to excavate [material.solid_name].")) + return + if(last_excavation + 2 SECONDS > world.time)//prevents message spam + return + last_excavation = world.time + var/newDepth = excavation_level + P.get_tool_property(TOOL_PICK, TOOL_PROP_EXCAVATION_DEPTH) // Used commonly below + //handle any archaeological finds we might uncover + if(!P.do_tool_interaction(TOOL_PICK, user, src, 2 SECONDS, suffix_message = destroy_artifacts(P, newDepth))) + return + + if(length(finds)) + var/datum/find/F = finds[1] + if(newDepth == F.excavation_required) // When the pick hits that edge just right, you extract your find perfectly, it's never confined in a rock + excavate_find(1, F) + else if(newDepth > F.excavation_required - F.clearance_range) // Not quite right but you still extract your find, the closer to the bottom the better, but not above 80% + excavate_find(prob(80 * (F.excavation_required - newDepth) / F.clearance_range), F) + + if(newDepth >= 200) // This means the rock is mined out fully + if(artifact_find) + if( excavation_level > 0 || prob(15) ) + var/obj/structure/boulder/excavated/B = new(src, material?.type, paint_color) + B.artifact_find = artifact_find + else + place_artifact_debris(1) + artifact_find = null + SSxenoarch.artifact_spawning_turfs -= src + else if(prob(5)) + new /obj/structure/boulder/excavated(src, material?.type) + dismantle_turf() + return + + var/excav_level = P.get_tool_property(TOOL_PICK, TOOL_PROP_EXCAVATION_DEPTH) + excavation_level += excav_level + //archaeo overlays + if(!archaeo_overlay && LAZYLEN(finds)) + var/datum/find/F = finds[1] + if(F.excavation_required <= excavation_level + F.view_range) + archaeo_overlay = image('icons/turf/excavation_overlays.dmi',"overlay_archaeo[rand(1,3)]") + queue_icon_update() + else if(archaeo_overlay && !LAZYLEN(finds)) + archaeo_overlay = null + queue_icon_update() + + //there's got to be a better way to do this + var/update_excav_overlay = 0 + if(excavation_level >= 150) + if(excavation_level - excav_level < 150) + update_excav_overlay = 1 + else if(excavation_level >= 100) + if(excavation_level - excav_level < 100) + update_excav_overlay = 1 + else if(excavation_level >= 50) + if(excavation_level - excav_level < 50) + update_excav_overlay = 1 + + //update overlays displaying excavation level + if( !(excav_overlay && excavation_level > 0) || update_excav_overlay ) + var/excav_quadrant = round(excavation_level / 50) + 1 + excav_overlay = image('icons/turf/excavation_overlays.dmi',"overlay_excv[excav_quadrant]_[rand(1,3)]") + queue_icon_update() + + //drop some rocks + next_rock += excav_level + var/amount_rocks = round(next_rock / 50) + next_rock = next_rock % 50 + if(amount_rocks > 0) + pass_geodata_to(new /obj/item/stack/material/ore(src, amount_rocks, material?.type)) + +/turf/wall/natural/proc/destroy_artifacts(var/obj/item/used_item, var/newDepth) + if(!length(finds)) + return + var/datum/find/F = finds[1] + if(newDepth > F.excavation_required) // Digging too deep can break the item. At least you won't summon a Balrog (probably) + if(used_item) + . = ". [pick("There is a crunching noise","[used_item] collides with some different rock","Part of the rock face crumbles away","Something breaks under [used_item]")]" + if(prob(10)) + return + if(prob(25)) + excavate_find(prob(5), finds[1]) + else if(prob(50)) + finds.Remove(finds[1]) + if(prob(50)) + place_artifact_debris() diff --git a/code/game/turfs/walls/wall_serde.dm b/code/game/turfs/walls/wall_serde.dm new file mode 100644 index 000000000000..53d737fffa2c --- /dev/null +++ b/code/game/turfs/walls/wall_serde.dm @@ -0,0 +1,20 @@ +/turf/wall/Serialize() + . = ..() + + SERIALIZE_DECL_IF_MODIFIED(material, /turf/wall) + SERIALIZE_DECL_IF_MODIFIED(girder_material, /turf/wall) + SERIALIZE_DECL_IF_MODIFIED(shutter_material, /turf/wall) + + SERIALIZE_IF_MODIFIED(shutter_state, /turf/wall) + SERIALIZE_IF_MODIFIED(stripe_color, /turf/wall) + SERIALIZE_IF_MODIFIED(damage, /turf/wall) + SERIALIZE_IF_MODIFIED(can_open, /turf/wall) + +/turf/wall/Deserialize(list/instance_map) + . = ..() + DESERIALIZE_DECL_TO_TYPE(girder_material) + DESERIALIZE_DECL_TO_TYPE(shutter_material) + +/turf/wall/natural/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(ramp_slope_direction, /turf/wall/natural) diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm new file mode 100644 index 000000000000..c0052e2a67f3 --- /dev/null +++ b/code/game/turfs/walls/wall_types.dm @@ -0,0 +1,114 @@ +//Commonly used +/turf/wall/prepainted + color = COLOR_GUNMETAL + paint_color = COLOR_WALL_GUNMETAL + stripe_color = COLOR_GUNMETAL +/turf/wall/r_wall/prepainted + color = COLOR_GUNMETAL + paint_color = COLOR_WALL_GUNMETAL + stripe_color = COLOR_GUNMETAL + +/turf/wall/r_wall + color = "#a8a9b2" + icon_state = "reinforced_solid" + material = /decl/material/solid/metal/plasteel + reinf_material = /decl/material/solid/metal/plasteel + +/turf/wall/r_wall/hull + name = "hull" + color = COLOR_HULL + paint_color = COLOR_HULL + stripe_color = COLOR_HULL + +/turf/wall/r_wall/hull/Initialize() + . = ..() + paint_color = color + color = null //color is just for mapping + if(prob(40)) + var/spacefacing = FALSE + for(var/direction in global.cardinal) + var/turf/T = get_step(src, direction) + var/area/A = get_area(T) + if(A && (A.area_flags & AREA_FLAG_EXTERNAL)) + spacefacing = TRUE + break + if(spacefacing) + var/bleach_factor = rand(10,50) + paint_color = adjust_brightness(paint_color, bleach_factor) + update_icon() + +/turf/wall/titanium + color = COLOR_SILVER + material = /decl/material/solid/metal/titanium + +/turf/wall/r_titanium + color = "#d1e6e3" + icon_state = "reinforced_solid" + material = /decl/material/solid/metal/titanium + reinf_material = /decl/material/solid/metal/titanium + +/turf/wall/ocp_wall + color = COLOR_GUNMETAL + material = /decl/material/solid/metal/plasteel/ocp + reinf_material = /decl/material/solid/metal/plasteel/ocp + +/turf/wall/iron + color = "#5c5454" + icon_state = "metal" + material = /decl/material/solid/metal/iron + +/turf/wall/plastic + color = COLOR_EGGSHELL + icon_state = "plastic" + material = /decl/material/solid/organic/plastic + +// A plastic wall with a plastic girder. Very flimsy but very easy to move or remove with just a crowbar. +/turf/wall/plastic/facade + girder_material = /decl/material/solid/organic/plastic + +/turf/wall/wood + color = COLOR_BROWN + icon_state = "wood" + material = /decl/material/solid/organic/wood/oak + +/turf/wall/walnut + color = COLOR_BROWN_ORANGE + icon_state = "wood" + material = /decl/material/solid/organic/wood/walnut + +/turf/wall/raidershuttle + color = COLOR_GREEN_GRAY + icon_state = "metal" + material = /decl/material/solid/metal/alienalloy + +/turf/wall/raidershuttle/attackby() + return TRUE + +//Alien metal walls +/turf/wall/alium + color = COLOR_BLUE_GRAY + floor_type = /turf/floor/fixed/alium + material = /decl/material/solid/metal/aliumium + +/turf/wall/alium/explosion_act(severity) + SHOULD_CALL_PARENT(TRUE) + if(prob(explosion_resistance)) + ..() + +/turf/wall/shuttle + material = /decl/material/solid/metal/titanium + paint_color = COLOR_BEIGE + stripe_color = COLOR_SKY_BLUE + +/turf/wall/shuttle/get_wall_icon() + return 'icons/turf/walls/solid.dmi' + +/turf/wall/shuttle/dark + color = COLOR_GUNMETAL + paint_color = COLOR_GUNMETAL + stripe_color = COLOR_MAROON + +/turf/wall/shuttle/light + color = COLOR_SILVER + paint_color = COLOR_SILVER + stripe_color = COLOR_SKY_BLUE diff --git a/code/game/turfs/walls/wall_wattle.dm b/code/game/turfs/walls/wall_wattle.dm new file mode 100644 index 000000000000..4cdca1b6df0c --- /dev/null +++ b/code/game/turfs/walls/wall_wattle.dm @@ -0,0 +1,160 @@ +/turf/wall/wattle + icon_state = "wattle" + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + girder_material = null + floor_type = /turf/floor/dirt + min_dismantle_amount = 3 + max_dismantle_amount = 5 + shutter_icon = 'icons/turf/walls/square_shutter.dmi' + var/decl/skill/daubing_skill = SKILL_CONSTRUCTION + var/decl/material/daubing_material // todo: daubing as a material made from clay/soil and plant matter? + var/const/matter_to_daub = MATTER_AMOUNT_REINFORCEMENT + // Currently, plastering is done via painting... undecided if that should change in the future. + +/turf/wall/wattle/Initialize(ml, materialtype, rmaterialtype) + if(ispath(daubing_material)) + daubing_material = GET_DECL(daubing_material) + return ..() + +/turf/wall/wattle/get_turf_validation_corner_states() + return list("", "paint") // paint should always be available because of plastering! + +// Daubing with clay or soil +/turf/wall/wattle/attackby(obj/item/used_item, mob/user, click_params) + if(isnull(daubing_material)) + var/static/list/daub_materials = list( // Does not include subtypes. + /decl/material/solid/soil = TRUE, + /decl/material/solid/clay = TRUE + ) + if(istype(used_item, /obj/item/stack/material) && daub_materials[used_item.material?.type]) + if(!user.check_dexterity(DEXTERITY_WIELD_ITEM)) + return TRUE + var/obj/item/stack/material/stack = used_item + var/sheets_to_use = stack.matter_units_to_sheets(matter_to_daub) + if(stack.can_use(sheets_to_use) && user.do_skilled(1 SECOND, daubing_skill, target = src) && stack.can_use(sheets_to_use)) + to_chat(user, SPAN_NOTICE("You daub \the [src] with \the [stack].")) + daubing_material = stack.material + stack.use(sheets_to_use) + else if(stack.can_use(sheets_to_use)) // failed the do_skilled + to_chat(user, SPAN_WARNING("You have to stay still to daub \the [src] with \the [stack].")) + else + to_chat(user, SPAN_WARNING("You need [stack.get_string_for_amount(sheets_to_use)] to daub \the [src].")) + return TRUE + return ..() + +/turf/wall/wattle/get_dismantle_stack_type() + return /obj/item/stack/material/log // temp? + +// daubed walls have the color of their daubing +/turf/wall/wattle/get_base_color() + if(daubing_material) + return "#795946" // daubing_material.color // sorry, but using the daubing material color looks bad + return ..() + +// don't plaster over our damn reinforcements +/turf/wall/wattle/get_reinf_color() + return reinf_material?.color + +/turf/wall/wattle/get_wall_icon() + if(isnull(daubing_material)) + return 'icons/turf/walls/wattle.dmi' + else + return 'icons/turf/walls/wattledaub.dmi' + +/turf/wall/wattle/get_dismantle_sound() + return 'sound/foley/wooden_drop.ogg' + +/turf/wall/wattle/update_strings() + if(isnull(daubing_material)) + if(reinf_material) + SetName("[reinf_material.solid_name]-framed [material.adjective_name] wattle wall") + desc = "A wattle wall made of [material.adjective_name] strips and framed with [reinf_material.solid_name]." + else + SetName("[material.solid_name] wattle wall") + desc = "A wattle wall made of [material.adjective_name] strips." + else if(paint_color) + if(reinf_material) + SetName("[reinf_material.solid_name]-framed plastered wall") + desc = "A plastered wall framed with [reinf_material.solid_name]." + else + SetName("plastered wall") + desc = "A plastered wall." + else + if(reinf_material) + SetName("[reinf_material.solid_name]-framed [material.adjective_name] wattle and daub wall") + desc = "A daubed wattle wall made of [material.adjective_name] strips and framed with [reinf_material.solid_name]." + else + SetName("[material.solid_name] wattle and daub wall") + desc = "A daubed wattle wall made of [material.adjective_name] strips." + +/turf/wall/wattle/daubed + icon_state = "wattledaub" + daubing_material = /decl/material/solid/clay + color = "#795946" // temporary mapping preview colour taken from get_base_color() + // the daub is lost when destroyed/deconstructed, since it's dried anyway + +/turf/wall/wattle/daubed/plastered + icon_state = "plaster" + paint_color = "#c2b8a1" // this is what applies the plaster... icky + color = "#c2b8a1" // preview color for plaster + +/turf/wall/wattle/daubed/plastered/framed + icon_state = "framed" + reinf_material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color // preview, still painted + +// Subtypes. +#define WATTLE_WALL_SUBTYPE(material_name) \ +/turf/wall/wattle/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ + color = /decl/material/solid/organic/wood/##material_name::color; \ +}; \ +/turf/wall/wattle/##material_name/shutter { \ + shutter_state = FALSE; \ + icon_state = "wattle_shutter"; \ +}; \ +/turf/wall/wattle/##material_name/shutter/open { \ + shutter_state = TRUE; \ +}; \ +/turf/wall/wattle/daubed/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ +}; \ +/turf/wall/wattle/daubed/##material_name/shutter { \ + shutter_state = FALSE; \ + icon_state = "wattle_shutter"; \ +}; \ +/turf/wall/wattle/daubed/##material_name/shutter/open { \ + shutter_state = TRUE; \ +}; \ +/turf/wall/wattle/daubed/plastered/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ +}; \ +/turf/wall/wattle/daubed/plastered/##material_name/shutter { \ + shutter_state = FALSE; \ + icon_state = "wattle_shutter"; \ +}; \ +/turf/wall/wattle/daubed/plastered/##material_name/shutter/open { \ + shutter_state = TRUE; \ +}; \ +/turf/wall/wattle/daubed/plastered/framed/##material_name { \ + material = /decl/material/solid/organic/wood/##material_name; \ + reinf_material = /decl/material/solid/organic/wood/##material_name; \ + color = /decl/material/solid/organic/wood/##material_name::color; \ +}; \ +/turf/wall/wattle/daubed/plastered/framed/##material_name/shutter { \ + shutter_state = FALSE; \ + icon_state = "wattle_shutter"; \ +}; \ +/turf/wall/wattle/daubed/plastered/framed/##material_name/shutter/open { \ + shutter_state = TRUE; \ +} +WATTLE_WALL_SUBTYPE(fungal) +WATTLE_WALL_SUBTYPE(ebony) +WATTLE_WALL_SUBTYPE(walnut) +WATTLE_WALL_SUBTYPE(maple) +WATTLE_WALL_SUBTYPE(mahogany) +WATTLE_WALL_SUBTYPE(bamboo) +WATTLE_WALL_SUBTYPE(yew) + +#undef WATTLE_WALL_SUBTYPE \ No newline at end of file diff --git a/code/game/verbs/byond_membership.dm b/code/game/verbs/byond_membership.dm new file mode 100644 index 000000000000..424a874157de --- /dev/null +++ b/code/game/verbs/byond_membership.dm @@ -0,0 +1,23 @@ +/client/verb/check_byond_membership() + set name = "Check Byond Membership" + set category = "OOC" + + var/list/perks + for(var/modpack in SSmodpacks.loaded_modpacks) + var/decl/modpack/M = SSmodpacks.loaded_modpacks[modpack] + var/perk = M.get_membership_perks() + if(perk) + LAZYADD(perks, "
            • [perk]
            • ") + + var/membership_days = get_byond_membership() + if(membership_days == 0) + to_chat(src, SPAN_NOTICE("Become a BYOND member to support the engine that makes this game possible!")) + if(LAZYLEN(perks)) + to_chat(src, SPAN_NOTICE("Membership grants access to [length(perks)] perk\s:
                [jointext(perks, "\n")]
              ")) + else + if(membership_days == -1) + to_chat(src, SPAN_NOTICE("Thanks for supporting BYOND! You have a lifetime membership.")) + else + to_chat(src, SPAN_NOTICE("Thanks for supporting BYOND! You have [get_byond_membership()] day\s of membership left.")) + if(LAZYLEN(perks)) + to_chat(src, SPAN_NOTICE("You have access to [length(perks)] perk\s:
                [jointext(perks, "\n")]
              ")) diff --git a/code/game/verbs/ignore.dm b/code/game/verbs/ignore.dm index 4c435d88732e..ee69faddf8a2 100644 --- a/code/game/verbs/ignore.dm +++ b/code/game/verbs/ignore.dm @@ -7,7 +7,7 @@ return key_to_ignore = ckey(sanitize(key_to_ignore)) if(prefs && prefs.ignored_players) - if(key_to_ignore in prefs.ignored_players && key_to_ignore != ckey) + if((key_to_ignore in prefs.ignored_players) && key_to_ignore != ckey) to_chat(usr, "[key_to_ignore] is already being ignored.") return prefs.ignored_players |= key_to_ignore @@ -37,7 +37,7 @@ /client/proc/is_key_ignored(var/key_to_check) key_to_check = ckey(key_to_check) - if(key_to_check in prefs.ignored_players) + if(key_to_check in prefs?.ignored_players) if(check_rights(R_MOD|R_ADMIN, 0)) // Admins and moderators are not ignorable return 0 return 1 diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index c3267e7d23da..8fd68bad4712 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -1,12 +1,18 @@ -/client/verb/ooc(message as text) +/client/verb/ooc(message = "" as text) set name = "OOC" set category = "OOC" + if(!message) + message = input(mob, "", "ooc \"text\"") as text|null + sanitize_and_communicate(/decl/communication_channel/ooc, src, message) -/client/verb/looc(message as text) +/client/verb/looc(message = "" as text) set name = "LOOC" set desc = "Local OOC, seen only by those in view. Remember: Just because you see someone that doesn't mean they see you." set category = "OOC" + if(!message) + message = input(mob, "", "looc \"text\"") as text|null + sanitize_and_communicate(/decl/communication_channel/ooc/looc, src, message) diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index 9289c02320dc..dacae0436607 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -8,7 +8,7 @@ var/list/Lines = list() if(check_rights(R_INVESTIGATE, 0)) - for(var/client/C in GLOB.clients) + for(var/client/C in global.clients) var/entry = "\t[C.key]" if(!C.mob) //If mob is null, print error and skip rest of info for client. entry += " - HAS NO MOB" @@ -46,14 +46,14 @@ entry += " - Antagonist" if(C.is_afk()) entry += " (AFK - [C.inactivity2text()])" - entry += " (?)" + entry += " (?)" Lines += entry else - for(var/client/C in GLOB.clients) + for(var/client/C in global.clients) if(!C.is_stealthed()) Lines += C.key - for(var/line in sortList(Lines)) + for(var/line in sortTim(Lines, /proc/cmp_text_asc)) msg += "[line]\n" msg += "Total Players: [length(Lines)]" @@ -68,7 +68,7 @@ var/total_staff = 0 var/can_investigate = check_rights(R_INVESTIGATE, 0) - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) var/line = list() if(!can_investigate && C.is_stealthed()) continue @@ -84,19 +84,19 @@ line += " (AFK - [C.inactivity2text()])" if(isghost(C.mob)) line += " - Observing" - else if(istype(C.mob,/mob/new_player)) + else if(isnewplayer(C.mob)) line += " - Lobby" else line += " - Playing" if(C.is_stealthed()) line += " (Stealthed)" - if(C.get_preference_value(/datum/client_preference/show_ooc) == GLOB.PREF_HIDE) + if(C.get_preference_value(/datum/client_preference/show_ooc) == PREF_HIDE) line += " (OOC)" - if(C.get_preference_value(/datum/client_preference/show_looc) == GLOB.PREF_HIDE) + if(C.get_preference_value(/datum/client_preference/show_looc) == PREF_HIDE) line += " (LOOC)" - if(C.get_preference_value(/datum/client_preference/show_aooc) == GLOB.PREF_HIDE) + if(C.get_preference_value(/datum/client_preference/show_aooc) == PREF_HIDE) line += " (AOOC)" - if(C.get_preference_value(/datum/client_preference/show_dsay) == GLOB.PREF_HIDE) + if(C.get_preference_value(/datum/client_preference/show_dsay) == PREF_HIDE) line += " (DSAY)" line = jointext(line,null) if(check_rights(R_ADMIN,0,C)) @@ -104,7 +104,7 @@ else msg += line - if(config.admin_irc) - to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.") + if(SSwebhooks.is_webhook_configured(WEBHOOK_AHELP_SENT)) + to_chat(src, "Adminhelps are also sent to Discord. If no admins are available in game try anyway and an admin on Discord may see it and join.") to_chat(src, "Current Staff ([active_staff]/[total_staff]):") to_chat(src, jointext(msg,"\n")) diff --git a/code/game/world.dm b/code/game/world.dm index 6dd6f0b34784..1c65910d510c 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,24 +1,26 @@ -/var/server_name = "Nebula13" +GLOBAL_PROTECTED_UNTYPED(game_id, null) -/var/game_id = null -/hook/global_init/proc/generate_gameid() - if(game_id != null) +/proc/generate_game_id() + if(!isnull(global.game_id)) return - game_id = "" - - var/list/c = 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", "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", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0") - var/l = c.len - - var/t = world.timeofday - for(var/_ = 1 to 4) - game_id = "[c[(t % l) + 1]][game_id]" - t = round(t / l) - game_id = "-[game_id]" - t = round(world.realtime / (10 * 60 * 60 * 24)) - for(var/_ = 1 to 3) - game_id = "[c[(t % l) + 1]][game_id]" - t = round(t / l) - return 1 + + global.game_id = "" + + var/list/characters = global.alphabet + global.alphabet_capital + global.numbers + var/server_time = world.timeofday + + for(var/a = 1 to 4) + global.game_id = "[characters[(server_time % characters.len) + 1]][global.game_id]" + server_time = round(server_time / characters.len) + + global.game_id = "-[global.game_id]" + server_time = round(world.realtime / (10 * 60 * 60 * 24)) + + for(var/a = 1 to 3) + global.game_id = "[characters[(server_time % characters.len) + 1]][global.game_id]" + server_time = round(server_time / characters.len) + + return TRUE // Find mobs matching a given string // @@ -28,6 +30,7 @@ // Partial matches will be found, but exact matches will be preferred by the search // // Returns: A possibly-empty list of the strongest matches + /proc/text_find_mobs(search_string, restrict_type = null) var/list/search = params2list(search_string) var/list/ckeysearch = list() @@ -41,10 +44,13 @@ continue var/strings = list(M.name, M.ckey) if(M.mind) - strings += M.mind.assigned_role - strings += M.mind.special_role + if(M.mind.assigned_role) + strings += M.mind.assigned_role + var/special_role_name = M.mind.get_special_role_name() + if(special_role_name) + strings += special_role_name if(ishuman(M)) - var/mob/living/carbon/human/H = M + var/mob/living/human/H = M if(H.species) strings += H.species.name for(var/text in strings) @@ -64,416 +70,123 @@ return match -#define RECOMMENDED_VERSION 512 -/world/New() +// Get the URL used to connect to the server. +/proc/get_world_url() + return "byond://[get_config_value(/decl/config/text/server) || get_config_value(/decl/config/text/serverurl) || "[world.address]:[world.port]"]" - enable_debugger() +/world/New() //set window title - name = "[server_name] - [GLOB.using_map.full_name]" + + name = "[get_config_value(/decl/config/text/server_name) || "Nebula Station 13"] - [global.using_map.full_name]" //logs SetupLogs() changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently - if(config && config.server_name != null && config.server_suffix && world.port > 0) - // dumb and hardcoded but I don't care~ - config.server_name += " #[(world.port % 1000) / 100]" - - if(byond_version < RECOMMENDED_VERSION) - to_world_log("Your server's byond version does not meet the recommended requirements for this server. Please update BYOND") + if(byond_version < REQUIRED_DM_VERSION) + to_world_log("Your server's BYOND version does not meet the minimum DM version for this server. Please update BYOND.") - callHook("startup") - //Emergency Fix - load_mods() - //end-emergency fix + // Initialize the global vars decl, which marks vars as protected. + GET_DECL(/decl/global_vars) + // And the offset used for in-game time + global.roundstart_hour = rand(0, 23) + initialise_map_list() + world.load_mode() + world.load_motd() + load_admins() + world.connect_database() + jobban_loadbanfile() + LoadBans() + update_holiday() //Uncommenting ALLOW_HOLIDAYS in configuration will enable this. + try_load_alien_whitelist() + investigate_reset() + // Precache/build trait trees. + for(var/decl/trait/trait in decls_repository.get_decls_of_type_unassociated(/decl/trait)) + trait.build_references() . = ..() #ifdef UNIT_TEST log_unit_test("Unit Tests Enabled. This will destroy the world when testing is complete.") - load_unit_test_changes() #endif Master.Initialize(10, FALSE) -#undef RECOMMENDED_VERSION +var/global/list/world_topic_throttle = list() +var/global/world_topic_last = world.timeofday -var/world_topic_spam_protect_ip = "0.0.0.0" -var/world_topic_spam_protect_time = world.timeofday +/proc/set_throttle(var/addr, var/time, var/reason) + var/list/throttle = global.world_topic_throttle[addr] + if (!global.world_topic_throttle[addr]) + global.world_topic_throttle[addr] = throttle = list(0, null) + else if ((!get_config_value(/decl/config/toggle/no_throttle_localhost) || !global.localhost_addresses[addr]) && throttle[1] && throttle[1] > world.timeofday + 15 SECONDS) + return throttle[2] ? "Throttled ([throttle[2]])" : "Throttled" + + throttle[1] = max(throttle[1], world.timeofday) + time + throttle[2] = reason /world/Topic(T, addr, master, key) - diary << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]" - - if (T == "ping") - var/x = 1 - for (var/client/C) - x++ - return x - - else if(T == "players") - var/n = 0 - for(var/mob/M in GLOB.player_list) - if(M.client) - n++ - return n - - else if (copytext(T,1,7) == "status") - var/input[] = params2list(T) - var/list/s = list() - s["version"] = game_version - s["mode"] = PUBLIC_GAME_MODE - s["respawn"] = config.abandon_allowed - s["enter"] = config.enter_allowed - s["vote"] = config.allow_vote_mode - s["ai"] = config.allow_ai - s["host"] = host ? host : null - - // This is dumb, but spacestation13.com's banners break if player count isn't the 8th field of the reply, so... this has to go here. - s["players"] = 0 - s["stationtime"] = stationtime2text() - s["roundduration"] = roundduration2text() - s["map"] = GLOB.using_map.full_name - - var/active = 0 - var/list/players = list() - var/list/admins = list() - var/legacy = input["status"] != "2" - for(var/client/C in GLOB.clients) - if(C.holder) - if(C.is_stealthed()) - continue //so stealthmins aren't revealed by the hub - admins[C.key] = C.holder.rank - if(legacy) - s["player[players.len]"] = C.key - players += C.key - if(istype(C.mob, /mob/living)) - active++ - - s["players"] = players.len - s["admins"] = admins.len - if(!legacy) - s["playerlist"] = list2params(players) - s["adminlist"] = list2params(admins) - s["active_players"] = active - - return list2params(s) - - else if(T == "manifest") - var/list/positions = list() - var/list/nano_crew_manifest = nano_crew_manifest() - // We rebuild the list in the format external tools expect - for(var/dept in nano_crew_manifest) - var/list/dept_list = nano_crew_manifest[dept] - if(dept_list.len > 0) - positions[dept] = list() - for(var/list/person in dept_list) - positions[dept][person["name"]] = person["rank"] - - for(var/k in positions) - positions[k] = list2params(positions[k]) // converts positions["heads"] = list("Bob"="Captain", "Bill"="CMO") into positions["heads"] = "Bob=Captain&Bill=CMO" - - return list2params(positions) - - else if(T == "revision") - var/list/L = list() - L["gameid"] = game_id - L["dm_version"] = DM_VERSION // DreamMaker version compiled in - L["dd_version"] = world.byond_version // DreamDaemon version running on - - if(revdata.revision) - L["revision"] = revdata.revision - L["branch"] = revdata.branch - L["date"] = revdata.date - else - L["revision"] = "unknown" - - return list2params(L) - - else if(copytext(T,1,5) == "laws") - var/input[] = params2list(T) - if(input["key"] != config.comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - - return "Bad Key" - - var/list/match = text_find_mobs(input["laws"], /mob/living/silicon) - - if(!match.len) - return "No matches" - else if(match.len == 1) - var/mob/living/silicon/S = match[1] - var/info = list() - info["name"] = S.name - info["key"] = S.key - - if(istype(S, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = S - info["master"] = R.connected_ai?.name - info["sync"] = R.lawupdate - - if(!S.laws) - info["laws"] = null - return list2params(info) - - var/list/lawset_parts = list( - "ion" = S.laws.ion_laws, - "inherent" = S.laws.inherent_laws, - "supplied" = S.laws.supplied_laws - ) - - for(var/law_type in lawset_parts) - var/laws = list() - for(var/datum/ai_law/L in lawset_parts[law_type]) - laws += L.law - info[law_type] = list2params(laws) - - info["zero"] = S.laws.zeroth_law ? S.laws.zeroth_law.law : null - - return list2params(info) - - else - var/list/ret = list() - for(var/mob/M in match) - ret[M.key] = M.name - return list2params(ret) - - else if(copytext(T,1,5) == "info") - var/input[] = params2list(T) - if(input["key"] != config.comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - - return "Bad Key" - - var/list/match = text_find_mobs(input["info"]) - - if(!match.len) - return "No matches" - else if(match.len == 1) - var/mob/M = match[1] - var/info = list() - info["key"] = M.key - info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])" - info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind" - var/turf/MT = get_turf(M) - info["loc"] = M.loc ? "[M.loc]" : "null" - info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null" - info["area"] = MT ? "[MT.loc]" : "null" - info["antag"] = M.mind ? (M.mind.special_role ? M.mind.special_role : "Not antag") : "No mind" - info["hasbeenrev"] = M.mind ? M.mind.has_been_rev : "No mind" - info["stat"] = M.stat - info["type"] = M.type - if(isliving(M)) - var/mob/living/L = M - info["damage"] = list2params(list( - oxy = L.getOxyLoss(), - tox = L.getToxLoss(), - fire = L.getFireLoss(), - brute = L.getBruteLoss(), - clone = L.getCloneLoss(), - brain = L.getBrainLoss() - )) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - info["species"] = H.species.name - else - info["species"] = "non-human" - else - info["damage"] = "non-living" - info["species"] = "non-human" - info["gender"] = M.gender - return list2params(info) - else - var/list/ret = list() - for(var/mob/M in match) - ret[M.key] = M.name - return list2params(ret) - - else if(copytext(T,1,9) == "adminmsg") - /* - We got an adminmsg from IRC bot lets split the input then validate the input. - expected output: - 1. adminmsg = ckey of person the message is to - 2. msg = contents of message, parems2list requires - 3. validatationkey = the key the bot has, it should match the gameservers commspassword in it's configuration. - 4. sender = the ircnick that send the message. - */ - - - var/input[] = params2list(T) - if(input["key"] != config.comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - - return "Bad Key" - - var/client/C - var/req_ckey = ckey(input["adminmsg"]) - - for(var/client/K in GLOB.clients) - if(K.ckey == req_ckey) - C = K - break - if(!C) - return "No client with that name on server" - - var/rank = input["rank"] - if(!rank) - rank = "Admin" - if(rank == "Unknown") - rank = "Staff" - - var/message = "[rank] PM from [input["sender"]]: [input["msg"]]" - var/amessage = "[rank] PM from [input["sender"]] to [key_name(C)] : [input["msg"]]" - - C.received_irc_pm = world.time - C.irc_admin = input["sender"] - - sound_to(C, 'sound/effects/adminhelp.ogg') - to_chat(C, message) - - for(var/client/A in GLOB.admins) - if(A != C) - to_chat(A, amessage) - return "Message Successful" - - else if(copytext(T,1,6) == "notes") - /* - We got a request for notes from the IRC Bot - expected output: - 1. notes = ckey of person the notes lookup is for - 2. validationkey = the key the bot has, it should match the gameservers commspassword in it's configuration. - */ - var/input[] = params2list(T) - if(input["key"] != config.comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - return "Bad Key" - - return show_player_info_irc(ckey(input["notes"])) - - else if(copytext(T,1,4) == "age") - var/input[] = params2list(T) - if(input["key"] != config.comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - return "Bad Key" - - var/age = get_player_age(input["age"]) - if(isnum(age)) - if(age >= 0) - return "[age]" - else - return "Ckey not found" - else - return "Database connection failed or not set up" - - else if(copytext(T,1,14) == "placepermaban") - var/input[] = params2list(T) - if(!config.ban_comms_password) - return "Not enabled" - if(input["bankey"] != config.ban_comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - return "Bad Key" - - var/target = ckey(input["target"]) - - var/client/C - for(var/client/K in GLOB.clients) - if(K.ckey == target) - C = K - break - if(!C) - return "No client with that name found on server" - if(!C.mob) - return "Client missing mob" - - if(!_DB_ban_record(input["id"], "0", "127.0.0.1", 1, C.mob, -1, input["reason"])) - return "Save failed" - ban_unban_log_save("[input["id"]] has permabanned [C.ckey]. - Reason: [input["reason"]] - This is a ban until appeal.") - notes_add(target,"[input["id"]] has permabanned [C.ckey]. - Reason: [input["reason"]] - This is a ban until appeal.",input["id"]) - qdel(C) - - else if(copytext(T,1,19) == "prometheus_metrics") - var/input[] = params2list(T) - if(input["key"] != config.comms_password) - if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) - spawn(50) - world_topic_spam_protect_time = world.time - return "Bad Key (Throttled)" - - world_topic_spam_protect_time = world.time - world_topic_spam_protect_ip = addr - return "Bad Key" - - if(!GLOB || !GLOB.prometheus_metrics) - return "Metrics not ready" - - return GLOB.prometheus_metrics.collect() + to_file(diary, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]") + if (global.world_topic_last > world.timeofday) + global.world_topic_throttle = list() //probably passed midnight + global.world_topic_last = world.timeofday -/world/Reboot(var/reason) - /*spawn(0) - sound_to(world, sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg')))// random end sounds!! - LastyBatsy + set_throttle(addr, 3 SECONDS, null) - */ + var/list/params = params2list(T) + if(!length(params)) + return + var/command_key = params[1] + if(!command_key) + return "Unrecognised Command" + var/decl/topic_command/command = decls_repository.get_decl_by_id("topic_command_[command_key]") + if(!istype(command)) + return "Unrecognised Command" - Master.Shutdown() + return command.try_use(T, addr, master, key) - if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite - for(var/client/C in GLOB.clients) - to_chat(C, link("byond://[config.server]")) +var/global/_reboot_announced = FALSE +/world/Reboot(var/reason) - if(config.wait_for_sigusr1_reboot && reason != 3) + if(get_config_value(/decl/config/toggle/wait_for_sigusr1_reboot) && reason != 3) text2file("foo", "reboot_called") - to_world("World reboot waiting for external scripts. Please be patient.") + if(!global._reboot_announced) + to_world("World reboot waiting for external scripts. Please be patient.") + global._reboot_announced = TRUE + global.Master.restart_timeout = 5 MINUTES return + if(global.using_map.reboot_sound) + sound_to(world, sound(pick(global.using_map.reboot_sound)))// random end sounds!! - LastyBatsy + + // Master.Shutdown() // In almost all normal cases, world/Reboot() calls world/Del() which calls Shutdown() on the master controller. Having it here means it runs multiple times. + + var/serverurl = get_config_value(/decl/config/text/server) + if(serverurl) //if you set a server location in configuration, it sends you there instead of trying to reconnect to the same world address. -- NeoFite + for(var/client/C in global.clients) + to_chat(C, link("byond://[serverurl]")) + + game_log("World rebooted at [time_stamp()]") + + on_reboot(reason) + ..(reason) +/// If you need to add modular functionality on-reboot, override this instead of /world/Reboot(). +/// It runs directly before the parent call in /world/Reboot(). +/world/proc/on_reboot(reason) + return + /world/Del() - callHook("shutdown") + Master.Shutdown() + on_shutdown() return ..() -/hook/startup/proc/loadMode() - world.load_mode() - return 1 +/// If you need to add modular functionality on-shutdown, override this instead of /world/Del(). +/// It runs directly before the parent call in /world/Del(). +/world/proc/on_shutdown() + return /world/proc/load_mode() if(!fexists("data/mode.txt")) @@ -488,53 +201,21 @@ var/world_topic_spam_protect_time = world.timeofday /world/proc/save_mode(var/the_mode) var/F = file("data/mode.txt") fdel(F) - F << the_mode - -/hook/startup/proc/loadMOTD() - world.load_motd() - return 1 + to_file(F, the_mode) /world/proc/load_motd() - join_motd = file2text("config/motd.txt") - - -/proc/load_configuration() - config = new /datum/configuration() - config.load("config/config.txt") - config.load("config/game_options.txt","game_options") - config.loadsql("config/dbconfig.txt") - config.load_event("config/custom_event.txt") - -/hook/startup/proc/loadMods() - world.load_mods() - return 1 - -/world/proc/load_mods() - if(config.admin_legacy_system) - var/text = file2text("config/moderators.txt") - if (!text) - error("Failed to load config/mods.txt") - else - var/list/lines = splittext(text, "\n") - for(var/line in lines) - if (!line) - continue - - if (copytext(line, 1, 2) == ";") - continue - - var/title = "Moderator" - var/rights = admin_ranks[title] - - var/ckey = copytext(line, 1, length(line)+1) - var/datum/admins/D = new /datum/admins(title, rights, ckey) - D.associate(GLOB.ckey_directory[ckey]) + join_motd = safe_file2text("config/motd.txt", FALSE) /world/proc/update_status() - var/s = "[station_name()] (Discord)" + var/s = "[station_name()]" + + var/discordurl = get_config_value(/decl/config/text/discordurl) + if(discordurl) + s += " (Discord)" - if (config && config.server_name) - s = "[config.server_name] — [s]" + var/config_server_name = get_config_value(/decl/config/text/server_name) + if(config_server_name) + s = "[config_server_name] — [s]" var/list/features = list() @@ -543,19 +224,19 @@ var/world_topic_spam_protect_time = world.timeofday else features += "STARTING" - if (!config.enter_allowed) + if (!get_config_value(/decl/config/toggle/on/enter_allowed)) features += "closed" - features += config.abandon_allowed ? "respawn" : "no respawn" + features += get_config_value(/decl/config/toggle/on/abandon_allowed) ? "respawn" : "no respawn" - if (config && config.allow_vote_mode) + if (get_config_value(/decl/config/toggle/vote_mode)) features += "vote" - if (config && config.allow_ai) + if (get_config_value(/decl/config/toggle/on/allow_ai)) features += "AI allowed" var/n = 0 - for (var/mob/M in GLOB.player_list) + for (var/mob/M in global.player_list) if (M.client) n++ @@ -565,8 +246,9 @@ var/world_topic_spam_protect_time = world.timeofday features += "~[n] player" - if (config && config.hostedby) - features += "hosted by [config.hostedby]" + var/hosted_by = get_config_value(/decl/config/text/hosted_by) + if (hosted_by) + features += "hosted by [hosted_by]" if (features) s += ": [jointext(features, ", ")]" @@ -576,115 +258,66 @@ var/world_topic_spam_protect_time = world.timeofday src.status = s /world/proc/SetupLogs() - GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" + global.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" if(game_id) - GLOB.log_directory += "[game_id]" + global.log_directory += "[game_id]" else - GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" + global.log_directory += "[replacetext(time_stamp(), ":", ".")]" - GLOB.world_qdel_log = file("[GLOB.log_directory]/qdel.log") - WRITE_FILE(GLOB.world_qdel_log, "\n\nStarting up round ID [game_id]. [time_stamp()]\n---------------------") + global.world_qdel_log = file("[global.log_directory]/qdel.log") + to_file(global.world_qdel_log, "\n\nStarting up round ID [game_id]. [time_stamp()]\n---------------------") - GLOB.world_href_log = file("[GLOB.log_directory]/href.log") // Used for config-optional total href logging - diary = file("[GLOB.log_directory]/main.log") // This is the primary log, containing attack, admin, and game logs. - WRITE_FILE(diary, "[log_end]\n[log_end]\nStarting up. (ID: [game_id]) [time2text(world.timeofday, "hh:mm.ss")][log_end]\n---------------------[log_end]") + global.world_href_log = file("[global.log_directory]/href.log") // Used for config-optional total href logging + diary = file("[global.log_directory]/main.log") // This is the primary log, containing attack, admin, and game logs. + to_file(diary, "[log_end]\n[log_end]\nStarting up. (ID: [game_id]) [time2text(world.timeofday, "hh:mm.ss")][log_end]\n---------------------[log_end]") - if(config && config.log_runtime) - var/runtime_log = file("[GLOB.log_directory]/runtime.log") - WRITE_FILE(runtime_log, "Game [game_id] starting up at [time2text(world.timeofday, "hh:mm.ss")]") + if(get_config_value(/decl/config/toggle/log_runtime)) + var/runtime_log = file("[global.log_directory]/runtime.log") + to_file(runtime_log, "Game [game_id] starting up at [time2text(world.timeofday, "hh:mm.ss")]") log = runtime_log // runtimes and some other output is logged directly to world.log, which is redirected here. #define FAILED_DB_CONNECTION_CUTOFF 5 -var/failed_db_connections = 0 -var/failed_old_db_connections = 0 - -/hook/startup/proc/connectDB() +var/global/failed_db_connections = 0 +/world/proc/connect_database() if(!setup_database_connection()) - to_world_log("Your server failed to establish a connection with the feedback database.") + to_world_log("Your server failed to establish a connection with the SQL database.") else - to_world_log("Feedback database connection established.") - return 1 + to_world_log("SQL database connection established.") -proc/setup_database_connection() +/proc/setup_database_connection() - if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. - return 0 + if(global.failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. + return FALSE if(!dbcon) dbcon = new() - var/user = sqlfdbklogin - var/pass = sqlfdbkpass - var/db = sqlfdbkdb + var/user = sqllogin + var/pass = sqlpass + var/db = sqldb var/address = sqladdress - var/port = sqlport + var/port = sqlport dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") . = dbcon.IsConnected() - if ( . ) - failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter. + if(.) + // Setting encoding and comparison (4-byte UTF-8) for the DB server ~bear1ake + var/DBQuery/unicode_query = dbcon.NewQuery("SET NAMES utf8mb4 COLLATE utf8mb4_general_ci") + if(!unicode_query.Execute()) + global.failed_db_connections++ + to_world_log(unicode_query.ErrorMsg()) + return + global.failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter. else - failed_db_connections++ //If it failed, increase the failed connections counter. + global.failed_db_connections++ //If it failed, increase the failed connections counter. to_world_log(dbcon.ErrorMsg()) - return . - //This proc ensures that the connection to the feedback database (global variable dbcon) is established -proc/establish_db_connection() - if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) +/proc/establish_db_connection() + if(global.failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) return 0 if(!dbcon || !dbcon.IsConnected()) return setup_database_connection() else return 1 - - -/hook/startup/proc/connectOldDB() - if(!setup_old_database_connection()) - to_world_log("Your server failed to establish a connection with the SQL database.") - else - to_world_log("SQL database connection established.") - return 1 - -//These two procs are for the old database, while it's being phased out. See the tgstation.sql file in the SQL folder for more information. -proc/setup_old_database_connection() - - if(failed_old_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. - return 0 - - if(!dbcon_old) - dbcon_old = new() - - var/user = sqllogin - var/pass = sqlpass - var/db = sqldb - var/address = sqladdress - var/port = sqlport - - dbcon_old.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") - . = dbcon_old.IsConnected() - if ( . ) - failed_old_db_connections = 0 //If this connection succeeded, reset the failed connections counter. - else - failed_old_db_connections++ //If it failed, increase the failed connections counter. - to_world_log(dbcon.ErrorMsg()) - - return . - -//This proc ensures that the connection to the feedback database (global variable dbcon) is established -proc/establish_old_db_connection() - if(failed_old_db_connections > FAILED_DB_CONNECTION_CUTOFF) - return 0 - - if(!dbcon_old || !dbcon_old.IsConnected()) - return setup_old_database_connection() - else - return 1 - -#undef FAILED_DB_CONNECTION_CUTOFF - -/world/proc/enable_debugger() - var/dll = world.GetConfig("env", "EXTOOLS_DLL") - if (dll) - call(dll, "debug_initialize")() \ No newline at end of file diff --git a/code/game/world_topic_commands.dm b/code/game/world_topic_commands.dm new file mode 100644 index 000000000000..43ef54a7e8f1 --- /dev/null +++ b/code/game/world_topic_commands.dm @@ -0,0 +1,351 @@ +/decl/topic_command + abstract_type = /decl/topic_command + var/name + var/has_params = FALSE + +/// Returns TRUE if we can use this command, and FALSE otherwise +/decl/topic_command/proc/can_use(var/T, var/addr, var/master, var/key) + if (has_params) + if (copytext(T, 1, length(name) + 1) != name) + return FALSE + else if (T != name) + return FALSE + return TRUE + +/decl/topic_command/proc/use(var/list/params) + return FALSE + +/decl/topic_command/proc/try_use(var/T, var/addr, var/master, var/key) + if (!can_use(T, addr, master, key)) + return FALSE + var/list/params + if(has_params) + params = params2list(T) + return use(params) + +/decl/topic_command/secure + abstract_type = /decl/topic_command/secure + +/decl/topic_command/secure/try_use(var/T, var/addr, var/master, var/key) + if (!can_use(T, addr, master, key)) + return FALSE + var/list/params = params2list(T) + var/comms_password = get_config_value(/decl/config/text/comms_password) + if (!comms_password) + set_throttle(addr, 10 SECONDS, "Comms Not Enabled") + return "Not Enabled" + if (params["key"] != comms_password) + set_throttle(addr, 30 SECONDS, "Bad Comms Key") + return "Bad Key" + return use(params) + +/* * * * * * * * +* Public Topic Calls +* The following topic calls are available without a comms secret. +* * * * * * * */ + +/decl/topic_command/ping + name = "ping" + uid = "topic_command_ping" + +/decl/topic_command/ping/use() + var/x = 1 + for (var/client/C) + x++ + return x + +/decl/topic_command/players + name = "players" + uid = "topic_command_players" + +/decl/topic_command/players/use() + return global.clients.len + +/decl/topic_command/status + name = "status" + uid = "topic_command_status" + has_params = TRUE + +/decl/topic_command/status/use(var/list/params) + var/list/s = list() + s["version"] = game_version + s["mode"] = PUBLIC_GAME_MODE + s["respawn"] = get_config_value(/decl/config/toggle/on/abandon_allowed) + s["enter"] = get_config_value(/decl/config/toggle/on/enter_allowed) + s["vote"] = get_config_value(/decl/config/toggle/vote_mode) + s["ai"] = !!length(empty_playable_ai_cores) + s["host"] = get_config_value(/decl/config/text/hosted_by) + + // This is dumb, but spacestation13.com's banners break if player count isn't the 8th field of the reply, so... this has to go here. + s["players"] = 0 + s["stationtime"] = stationtime2text() + s["roundduration"] = roundduration2text() + s["map"] = strip_improper(global.using_map.full_name) //Done to remove the non-UTF-8 text macros + + var/active = 0 + var/list/players = list() + var/list/admins = list() + var/legacy = params["status"] != "2" + for(var/client/C in global.clients) + if(C.holder) + if(C.is_stealthed()) + continue //so stealthmins aren't revealed by the hub + admins[C.key] = C.holder.rank + if(legacy) + s["player[players.len]"] = C.key + players += C.key + if(isliving(C.mob)) + active++ + + s["players"] = players.len + s["admins"] = admins.len + if(!legacy) + s["playerlist"] = list2params(players) + s["adminlist"] = list2params(admins) + s["active_players"] = active + + return list2params(s) + +/decl/topic_command/manifest + name = "manifest" + uid = "topic_command_manifest" + +/decl/topic_command/manifest/use() + var/list/positions = list() + var/list/nano_crew_manifest = nano_crew_manifest() + // We rebuild the list in the format external tools expect + for(var/dept in nano_crew_manifest) + var/list/dept_list = nano_crew_manifest[dept] + if(dept_list.len > 0) + positions[dept] = list() + for(var/list/person in dept_list) + positions[dept][person["name"]] = person["rank"] + + for(var/k in positions) + positions[k] = list2params(positions[k]) // converts positions["heads"] = list("Bob"="Captain", "Bill"="CMO") into positions["heads"] = "Bob=Captain&Bill=CMO" + + return list2params(positions) + +/decl/topic_command/revision + name = "revision" + uid = "topic_command_revision" + +/decl/topic_command/revision/use() + var/list/L = list() + L["gameid"] = game_id + L["dm_version"] = DM_VERSION // DreamMaker version compiled in + L["dm_build"] = DM_BUILD // DreamMaker build compiled in + L["dd_version"] = world.byond_version // DreamDaemon version running on + L["dd_build"] = world.byond_build // DreamDaemon build running on + + if(revdata.revision) + L["revision"] = revdata.revision + L["branch"] = revdata.branch + L["date"] = revdata.date + else + L["revision"] = "unknown" + + return list2params(L) + +/* * * * * * * * +* Admin Topic Calls +* The following topic calls are only available if a ban comms secret has been defined, supplied, and is correct. +* * * * * * * */ +/decl/topic_command/ban + name = "placepermaban" + uid = "topic_command_placepermaban" + has_params = TRUE + +/decl/topic_command/ban/try_use(var/T, var/addr, var/master, var/key) + if (!can_use(T, addr, master, key)) + return FALSE + var/list/params = params2list(T) + var/ban_comms_password = get_config_value(/decl/config/text/ban_comms_password) + if(!ban_comms_password) + set_throttle(addr, 10 SECONDS, "Bans Not Enabled") + return "Not Enabled" + if(params["bankey"] != ban_comms_password) + set_throttle(addr, 30 SECONDS, "Bad Bans Key") + return "Bad Key" + return use(params) + +/decl/topic_command/ban/use(var/list/params) + var/target = ckey(params["target"]) + if(!target) + return "No client provided." + + var/client/C + for(var/client/K as anything in global.clients) + if(K.ckey == target) + C = K + break + if(!C) + return "No client with that name found on server" + if(!C.mob) + return "Client missing mob" + + if(!_DB_ban_record(params["id"], "0", "127.0.0.1", 1, C.mob, -1, params["reason"])) + return "Save failed" + ban_unban_log_save("[params["id"]] has permabanned [C.ckey]. - Reason: [params["reason"]] - This is a ban until appeal.") + notes_add(target,"[params["id"]] has permabanned [C.ckey]. - Reason: [params["reason"]] - This is a ban until appeal.",params["id"]) + qdel(C) + +/* * * * * * * * +* Secure Topic Calls +* The following topic calls are only available if a comms secret has been defined, supplied, and is correct. +* * * * * * * */ + +/decl/topic_command/secure/laws + name = "laws" + uid = "topic_command_laws" + has_params = TRUE + +/decl/topic_command/secure/laws/use(var/list/params) + var/list/match = text_find_mobs(params["laws"], /mob/living/silicon) + + if(!match.len) + return "No matches" + else if(match.len == 1) + var/mob/living/silicon/S = match[1] + var/info = list() + info["name"] = S.name + info["key"] = S.key + + if(isrobot(S)) + var/mob/living/silicon/robot/robot = S + info["master"] = robot.connected_ai?.name + info["sync"] = robot.lawupdate + + if(!S.laws) + info["laws"] = null + return list2params(info) + + var/list/lawset_parts = list( + "ion" = S.laws.ion_laws, + "inherent" = S.laws.inherent_laws, + "supplied" = S.laws.supplied_laws + ) + + for(var/law_type in lawset_parts) + var/laws = list() + for(var/datum/ai_law/L in lawset_parts[law_type]) + laws += L.law + info[law_type] = list2params(laws) + + info["zero"] = S.laws.zeroth_law ? S.laws.zeroth_law.law : null + + return list2params(info) + + else + var/list/ret = list() + for(var/mob/M in match) + ret[M.key] = M.name + return list2params(ret) + +/decl/topic_command/secure/info + name = "info" + uid = "topic_command_info" + has_params = TRUE + +/decl/topic_command/secure/info/use(var/list/params) + var/list/match = text_find_mobs(params["info"]) + + if(!match.len) + return "No matches" + else if(match.len == 1) + var/mob/M = match[1] + var/info = list() + info["key"] = M.key + info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])" + info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind" + var/turf/MT = get_turf(M) + info["loc"] = M.loc ? "[M.loc]" : "null" + info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null" + info["area"] = MT ? "[MT.loc]" : "null" + info["antag"] = M.mind ? (M.mind.get_special_role_name("Not antag")) : "No mind" + info["stat"] = M.stat + info["type"] = M.type + if(isliving(M)) + var/mob/living/L = M + info["damage"] = list2params(list( + oxy = L.get_damage(OXY), + tox = L.get_damage(TOX), + fire = L.get_damage(BURN), + brute = L.get_damage(BRUTE), + clone = L.get_damage(CLONE), + brain = L.get_damage(BRAIN) + )) + if(ishuman(M)) + var/mob/living/human/H = M + info["species"] = H.species.name + else + info["species"] = "non-human" + else + info["damage"] = "non-living" + info["species"] = "non-human" + info["gender"] = M.gender + return list2params(info) + else + var/list/ret = list() + for(var/mob/M in match) + ret[M.key] = M.name + return list2params(ret) + +/decl/topic_command/secure/adminmsg + name = "adminmsg" + uid = "topic_command_adminmsg" + has_params = TRUE + +/decl/topic_command/secure/adminmsg/use(var/list/params) + var/client/C + var/req_ckey = ckey(params["adminmsg"]) + + for(var/client/K in global.clients) + if(K.ckey == req_ckey) + C = K + break + if(!C) + return "No client with that name on server" + + var/rank = params["rank"] + if(!rank) + rank = "Admin" + if(rank == "Unknown") + rank = "Staff" + + var/message = SPAN_RED("[rank] PM from [params["sender"]]: [params["msg"]]") + var/amessage = SPAN_BLUE("[rank] PM from [params["sender"]] to [key_name(C)] : [params["msg"]]") + + C.received_irc_pm = world.time + C.irc_admin = params["sender"] + + sound_to(C, 'sound/effects/adminhelp.ogg') + to_chat(C, message) + + for(var/client/A in global.admins) + if(A != C) + to_chat(A, amessage) + return "Message Successful" + +/decl/topic_command/secure/notes + name = "notes" + uid = "topic_command_notes" + has_params = TRUE + +/decl/topic_command/secure/notes/use(var/list/params) + return show_player_info_irc(ckey(params["notes"])) + +/decl/topic_command/secure/age + name = "age" + uid = "topic_command_age" + has_params = TRUE + +/decl/topic_command/secure/age/use(var/list/params) + var/age = get_player_age(params["age"]) + if(isnum(age)) + if(age >= 0) + return "[age]" + else + return "Ckey not found" + else + return "Database connection failed or not set up" diff --git a/code/hub.dm b/code/hub.dm index d49fcc3604c5..7749a33fd9d2 100644 --- a/code/hub.dm +++ b/code/hub.dm @@ -6,8 +6,7 @@ name = "Space Station 13 - Nebula13" /world/proc/update_hub_visibility() - GLOB.visibility_pref = !(GLOB.visibility_pref) - if(GLOB.visibility_pref) + if(get_config_value(/decl/config/toggle/hub_visibility)) hub_password = "kMZy3U5jJHSiBQjr" else hub_password = "SORRYNOPASSWORD" diff --git a/code/js/byjax.dm b/code/js/byjax.dm deleted file mode 100644 index 6f855a705cdc..000000000000 --- a/code/js/byjax.dm +++ /dev/null @@ -1,50 +0,0 @@ -//this function places received data into element with specified id. -var/const/js_byjax = {" - -function replaceContent() { - var args = Array.prototype.slice.call(arguments); - var id = args\[0\]; - var content = args\[1\]; - var callback = null; - if(args\[2\]){ - callback = args\[2\]; - if(args\[3\]){ - args = args.slice(3); - } - } - var parent = document.getElementById(id); - if(typeof(parent)!=='undefined' && parent!=null){ - parent.innerHTML = content?content:''; - } - if(callback && window\[callback\]){ - window\[callback\].apply(null,args); - } -} -"} - -/* -sends data to control_id:replaceContent - -receiver - mob -control_id - window id (for windows opened with browse(), it'll be "windowname.browser") -target_element - HTML element id -new_content - HTML content -callback - js function that will be called after the data is sent -callback_args - arguments for callback function - -Be sure to include required js functions in your page, or it'll raise an exception. -*/ -proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null) - if(receiver && target_element && control_id) // && winexists(receiver, control_id)) - var/list/argums = list(target_element, new_content) - if(callback) - argums += callback - if(callback_args) - argums += callback_args - argums = list2params(argums) -/* if(callback_args) - argums += "&[list2params(callback_args)]" -*/ - receiver << output(argums,"[control_id]:replaceContent") - return - diff --git a/code/js/menus.dm b/code/js/menus.dm deleted file mode 100644 index 8d29335e77b0..000000000000 --- a/code/js/menus.dm +++ /dev/null @@ -1,37 +0,0 @@ -var/const/js_dropdowns = {" -function dropdowns() { - var divs = document.getElementsByTagName('div'); - var headers = new Array(); - var links = new Array(); - for(var i=0;i=0) { - elem.className = elem.className.replace('visible','hidden'); - this.className = this.className.replace('open','closed'); - this.innerHTML = this.innerHTML.replace('-','+'); - } - else { - elem.className = elem.className.replace('hidden','visible'); - this.className = this.className.replace('closed','open'); - this.innerHTML = this.innerHTML.replace('+','-'); - } - return false; - } - })(links\[i\]); - } - } -} -"} \ No newline at end of file diff --git a/code/js/view_variables.js b/code/js/view_variables.js index 86ca8cadc693..83a6c3c8eb34 100644 --- a/code/js/view_variables.js +++ b/code/js/view_variables.js @@ -17,6 +17,11 @@ function updateSearch() { } } +function refreshPage(datumref) { + window.location.href = 'byond://?_src_=vars;datumrefresh=' + encodeURIComponent(datumref) + ';filter=' + encodeURIComponent(document.getElementById('filter').value); + return true; +} + function selectTextField() { var filter_text = document.getElementById('filter'); filter_text.focus(); diff --git a/code/modules/ZAS/Airflow.dm b/code/modules/ZAS/Airflow.dm index 49020e27a64d..a7f409af231a 100644 --- a/code/modules/ZAS/Airflow.dm +++ b/code/modules/ZAS/Airflow.dm @@ -1,95 +1,103 @@ /* -Contains helper procs for airflow, handled in /connection_group. +Contains helper procs for airflow, called by /connection_group. */ +/atom/movable/proc/handle_airflow(var/differential, var/list/connecting_turfs, var/repelled) + if(last_airflow > world.time - vsc.airflow_delay || airflow_speed) + return FALSE + + // Knock mobs etc over. + . = handle_airflow_stun(differential) + + // Shove things around. + if(check_airflow_movable(differential) && length(connecting_turfs)) + //Check for things that are in range of the midpoint turfs. + var/list/close_turfs + for(var/turf/connecting_turf as anything in connecting_turfs) + if(get_dist(src, connecting_turf) < world.view) + LAZYADD(close_turfs, connecting_turf) + if(LAZYLEN(close_turfs)) + airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. + + if(repelled) + RepelAirflowDest(differential / 5) + else + GotoAirflowDest(differential / 10) + +/atom/movable/proc/handle_airflow_stun(var/differential) + return -mob/var/tmp/last_airflow_stun = 0 -mob/proc/airflow_stun() - if(stat == 2) - return 0 - if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0 - +/mob/var/tmp/last_airflow_stun = 0 +/mob/handle_airflow_stun(var/differential) + if(differential < vsc.airflow_stun_pressure || stat == DEAD || (status_flags & GODMODE)) + return FALSE + if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) + return FALSE if(!(status_flags & CANSTUN) && !(status_flags & CANWEAKEN)) - to_chat(src, "You stay upright as the air rushes past you.") - return 0 + to_chat(src, SPAN_NOTICE("You stay upright as the air rushes past you.")) + return FALSE if(buckled) - to_chat(src, "Air suddenly rushes past you!") - return 0 - if(!lying) - to_chat(src, "The sudden rush of air knocks you over!") - Weaken(5) + to_chat(src, SPAN_NOTICE("Air suddenly rushes past you!")) + return FALSE + if(!current_posture.prone) + to_chat(src, SPAN_DANGER("The sudden rush of air knocks you over!")) + SET_STATUS_MAX(src, STAT_WEAK, 5) last_airflow_stun = world.time + return TRUE -mob/living/silicon/airflow_stun() - return - -mob/living/carbon/slime/airflow_stun() - return - -mob/living/carbon/human/airflow_stun() - if(!slip_chance()) - to_chat(src, "Air suddenly rushes past you!") - return 0 - ..() - -atom/movable/proc/check_airflow_movable(n) - - if(anchored && !ismob(src)) return 0 - - if(!isobj(src) && n < vsc.airflow_dense_pressure) return 0 +/mob/living/silicon/handle_airflow_stun() + return FALSE - return 1 - -mob/check_airflow_movable(n) - if(n < vsc.airflow_heavy_pressure) - return 0 - return 1 - -mob/living/silicon/check_airflow_movable() - return 0 +/mob/living/silicon/handle_airflow() + return FALSE +/mob/living/human/handle_airflow_stun() + if(!get_eva_slip_prob()) + to_chat(src, SPAN_NOTICE("Air suddenly rushes past you!")) + return FALSE + . = ..() -obj/check_airflow_movable(n) - if(isnull(w_class)) - if(n < vsc.airflow_dense_pressure) return 0 //most non-item objs don't have a w_class yet - else - switch(w_class) - if(1,2) - if(n < vsc.airflow_lightest_pressure) return 0 - if(3) - if(n < vsc.airflow_light_pressure) return 0 - if(4,5) - if(n < vsc.airflow_medium_pressure) return 0 - if(6) - if(n < vsc.airflow_heavy_pressure) return 0 - if(7 to INFINITY) - if(n < vsc.airflow_dense_pressure) return 0 +/atom/movable/proc/check_airflow_movable(n) + return !anchored + +/mob/check_airflow_movable(n) + return (n >= vsc.airflow_heavy_pressure) + +/mob/living/silicon/check_airflow_movable() + return FALSE + +/obj/check_airflow_movable(n) + var/threshold = vsc.airflow_dense_pressure + switch(w_class) + if(1, 2) + threshold = vsc.airflow_lightest_pressure + if(3) + threshold = vsc.airflow_light_pressure + if(4, 5) + threshold = vsc.airflow_medium_pressure + if(6) + threshold = vsc.airflow_heavy_pressure + if(n < threshold) + return FALSE return ..() - -/atom/movable/var/tmp/turf/airflow_dest -/atom/movable/var/tmp/airflow_speed = 0 -/atom/movable/var/tmp/airflow_time = 0 -/atom/movable/var/tmp/last_airflow = 0 -/atom/movable/var/tmp/airborne_acceleration = 0 +/atom/movable + var/tmp/turf/airflow_dest + var/tmp/airflow_speed = 0 + var/tmp/airflow_time = 0 + var/tmp/last_airflow = 0 + var/tmp/airborne_acceleration = 0 /atom/movable/proc/AirflowCanMove(n) return 1 /mob/AirflowCanMove(n) - if(status_flags & GODMODE) - return 0 - if(buckled) - return 0 - var/obj/item/shoes = get_equipped_item(slot_shoes) - if(istype(shoes) && (shoes.item_flags & ITEM_FLAG_NOSLIP)) - return 0 - return 1 + return can_slip(magboots_only = TRUE) /atom/movable/Bump(atom/A) if(airflow_speed > 0 && airflow_dest) if(airborne_acceleration > 1) airflow_hit(A) - else if(istype(src, /mob/living/carbon/human)) + else if(ishuman(src)) to_chat(src, "You are pinned against [A] by airflow!") airborne_acceleration = 0 else @@ -98,30 +106,28 @@ obj/check_airflow_movable(n) airborne_acceleration = 0 . = ..() -atom/movable/proc/airflow_hit(atom/A) +/atom/movable/proc/airflow_hit(atom/A) airflow_speed = 0 airflow_dest = null airborne_acceleration = 0 -mob/airflow_hit(atom/A) - for(var/mob/M in hearers(src)) - M.show_message("\The [src] slams into \a [A]!",1,"You hear a loud slam!",2) +/mob/airflow_hit(atom/A) + visible_message(SPAN_DANGER("\The [src] slams into \the [A]!"), SPAN_DANGER("You slam into \the [A]!"), SPAN_DANGER("You hear a loud slam!")) playsound(src.loc, "smash.ogg", 25, 1, -1) var/weak_amt = istype(A,/obj/item) ? A:w_class : rand(1,5) //Heheheh - Weaken(weak_amt) + SET_STATUS_MAX(src, STAT_WEAK, weak_amt) . = ..() -obj/airflow_hit(atom/A) - for(var/mob/M in hearers(src)) - M.show_message("\The [src] slams into \a [A]!",1,"You hear a loud slam!",2) +/obj/airflow_hit(atom/A) + visible_message(SPAN_DANGER("\The [src] slams into \the [A]!"), null, SPAN_DANGER("You hear a loud slam!")) playsound(src.loc, "smash.ogg", 25, 1, -1) . = ..() -obj/item/airflow_hit(atom/A) +/obj/item/airflow_hit(atom/A) airflow_speed = 0 airflow_dest = null -mob/living/carbon/human/airflow_hit(atom/A) +/mob/living/human/airflow_hit(atom/A) // for(var/mob/M in hearers(src)) // M.show_message("[src] slams into [A]!",1,"You hear a loud slam!",2) playsound(src.loc, "punch", 25, 1, -1) @@ -137,15 +143,15 @@ mob/living/carbon/human/airflow_hit(atom/A) apply_damage(b_loss/3, BRUTE, BP_GROIN, used_weapon = "Airflow") if(airflow_speed > 10) - Paralyse(round(airflow_speed * vsc.airflow_stun)) - Stun(paralysis + 3) + SET_STATUS_MAX(src, STAT_PARA, round(airflow_speed * vsc.airflow_stun)) + SET_STATUS_MAX(src, STAT_STUN, GET_STATUS(src, STAT_PARA) + 3) else - Stun(round(airflow_speed * vsc.airflow_stun/2)) + SET_STATUS_MAX(src, STAT_STUN, round(airflow_speed * vsc.airflow_stun/2)) . = ..() -zone/proc/movables() +/zone/proc/movables() . = list() - for(var/turf/T in contents) + for(var/turf/T as anything in contents) for(var/atom/movable/A in T) if(!A.simulated || A.anchored || istype(A, /obj/effect) || isobserver(A)) continue diff --git a/code/modules/ZAS/Atom.dm b/code/modules/ZAS/Atom.dm index 2bf7ef1c8eb8..c56c561fecdd 100644 --- a/code/modules/ZAS/Atom.dm +++ b/code/modules/ZAS/Atom.dm @@ -29,52 +29,18 @@ //Convenience function for atoms to update turfs they occupy /atom/movable/proc/update_nearby_tiles(need_rebuild) - for(var/turf/simulated/turf in locs) - SSair.mark_for_update(turf) + for(var/turf/turf in locs) + if(turf.simulated) + SSair.mark_for_update(turf) - return 1 - -//Basically another way of calling CanPass(null, other, 0, 0) and CanPass(null, other, 1.5, 1). -//Returns: -// 0 - Not blocked -// AIR_BLOCKED - Blocked -// ZONE_BLOCKED - Not blocked, but zone boundaries will not cross. -// BLOCKED - Blocked, zone boundaries will not cross even if opened. -atom/proc/c_airblock(turf/other) - #ifdef ZASDBG - ASSERT(isturf(other)) - #endif - return (AIR_BLOCKED*!CanPass(null, other, 0, 0))|(ZONE_BLOCKED*!CanPass(null, other, 1.5, 1)) - - -turf/c_airblock(turf/other) - #ifdef ZASDBG - ASSERT(isturf(other)) - #endif - if(((blocks_air & AIR_BLOCKED) || (other.blocks_air & AIR_BLOCKED))) - return BLOCKED - - //Z-level handling code. Always block if there isn't an open space. - #ifdef MULTIZAS - if(other.z != src.z) - if(other.z < src.z) - if(!istype(src, /turf/simulated/open)) return BLOCKED - else - if(!istype(other, /turf/simulated/open)) return BLOCKED - #endif - - if(((blocks_air & ZONE_BLOCKED) || (other.blocks_air & ZONE_BLOCKED))) - if(z == other.z) - return ZONE_BLOCKED - else - return AIR_BLOCKED - - var/result = 0 - for(var/mm in contents) - var/atom/movable/M = mm - result |= M.c_airblock(other) - if(result == BLOCKED) return BLOCKED - return result + fluid_update() + return TRUE /atom/movable var/atmos_canpass = CANPASS_ALWAYS + +// Make sure you know what you're doing if you call this +// You probably want CanPass() +/atom/movable/Cross(atom/movable/crossed_atom) + // We only want to call CanPass() for multitiles, otherwise call parent. + return bounds != "32,32" ? CanPass(crossed_atom, crossed_atom.loc) : ..() \ No newline at end of file diff --git a/code/modules/ZAS/Connection.dm b/code/modules/ZAS/Connection.dm index 17c8ea162816..30b729a78a0d 100644 --- a/code/modules/ZAS/Connection.dm +++ b/code/modules/ZAS/Connection.dm @@ -49,24 +49,30 @@ Class Procs: */ -/connection/var/turf/simulated/A -/connection/var/turf/simulated/B -/connection/var/zone/zoneA -/connection/var/zone/zoneB +/connection + var/turf/A + var/turf/B + var/zone/zoneA + var/zone/zoneB -/connection/var/connection_edge/edge + var/connection_edge/edge -/connection/var/state = 0 + ///Invalid or Valid + var/state = 0 -/connection/New(turf/simulated/A, turf/simulated/B) #ifdef ZASDBG - ASSERT(SSair.has_valid_zone(A)) - //ASSERT(SSair.has_valid_zone(B)) + ///Set to true during testing to get verbose debug information + var/tmp/verbose = FALSE + #endif + +/connection/New(turf/A, turf/B) + #ifdef ZASDBG + ASSERT(TURF_HAS_VALID_ZONE(A)) #endif src.A = A src.B = B zoneA = A.zone - if(!istype(B)) + if(!SHOULD_PARTICIPATE_IN_ZONES(B)) mark_space() edge = SSair.get_edge(A.zone,B) edge.add_connection(src) @@ -75,17 +81,31 @@ Class Procs: edge = SSair.get_edge(A.zone,B.zone) edge.add_connection(src) +#ifdef ZASDBG +/connection/simulated/New(turf/A, turf/B) + . = ..() + ASSERT(TURF_HAS_VALID_ZONE(B)) +#endif + /connection/proc/mark_direct() if(!direct()) state |= CONNECTION_DIRECT edge.direct++ -// log_debug("Marked direct.") + + #ifdef ZASDBG + if(verbose) + zas_log("Marked direct.") + #endif /connection/proc/mark_indirect() if(direct()) state &= ~CONNECTION_DIRECT edge.direct-- -// log_debug("Marked indirect.") + + #ifdef ZASDBG + if(verbose) + zas_log("Marked indirect.") + #endif /connection/proc/mark_space() state |= CONNECTION_SPACE @@ -99,18 +119,34 @@ Class Procs: /connection/proc/erase() edge.remove_connection(src) state |= CONNECTION_INVALID -// log_debug("Connection Erased: [state]") + + #ifdef ZASDBG + if(verbose) + zas_log("Connection Erased: [state]") + #endif /connection/proc/update() -// log_debug("Updated, \...") - if(!istype(A,/turf/simulated)) -// log_debug("Invalid A.") + #ifdef ZASDBG + if(verbose) + zas_log("Updated, \...") + #endif + + if(!SHOULD_PARTICIPATE_IN_ZONES(A)) + #ifdef ZASDBG + if(verbose) + zas_log("Invalid A. Erasing...") + #endif + erase() return var/block_status = SSair.air_blocked(A,B) if(block_status & AIR_BLOCKED) -// log_debug("Blocked connection.") + #ifdef ZASDBG + if(verbose) + zas_log("Blocked connection. Erasing...") + #endif + erase() return else if(block_status & ZONE_BLOCKED) @@ -118,18 +154,29 @@ Class Procs: else mark_direct() - var/b_is_space = !istype(B,/turf/simulated) + var/b_is_space = !SHOULD_PARTICIPATE_IN_ZONES(B) if(state & CONNECTION_SPACE) if(!b_is_space) -// log_debug("Invalid B.") + #ifdef ZASDBG + if(verbose) + zas_log("Invalid B. Erasing...") + #endif + erase() return if(A.zone != zoneA) -// log_debug("Zone changed, \...") + #ifdef ZASDBG + if(verbose) + zas_log("Zone changed, \...") + #endif + if(!A.zone) erase() -// log_debug("erased.") + #ifdef ZASDBG + if(verbose) + zas_log("Turf A's zone has disappeared. Erasing...") + #endif return else edge.remove_connection(src) @@ -137,22 +184,34 @@ Class Procs: edge.add_connection(src) zoneA = A.zone -// log_debug("valid.") + #ifdef ZASDBG + if(verbose) + zas_log("Connection is valid.") + #endif return else if(b_is_space) -// log_debug("Invalid B.") + #ifdef ZASDBG + if(verbose) + zas_log("Turf B is unsimulated, but this is a simulated connection. Erasing...") + #endif erase() return if(A.zone == B.zone) -// log_debug("A == B") + #ifdef ZASDBG + if(verbose) + zas_log("Turf A and Turf B share a zone. Erasing...") + #endif erase() return if(A.zone != zoneA || (zoneB && (B.zone != zoneB))) -// log_debug("Zones changed, \...") + #ifdef ZASDBG + if(verbose) + zas_log("Zones changed, \...") + #endif if(A.zone && B.zone) edge.remove_connection(src) edge = SSair.get_edge(A.zone, B.zone) @@ -160,9 +219,15 @@ Class Procs: zoneA = A.zone zoneB = B.zone else -// log_debug("erased.") + #ifdef ZASDBG + if(verbose) + zas_log("Turf A or B lost it's zone. Erasing...") + #endif erase() return -// log_debug("valid.") \ No newline at end of file + #ifdef ZASDBG + if(verbose) + zas_log("Connection is valid.") + #endif diff --git a/code/modules/ZAS/ConnectionGroup.dm b/code/modules/ZAS/ConnectionGroup.dm index 17249aae155b..4eea04540146 100644 --- a/code/modules/ZAS/ConnectionGroup.dm +++ b/code/modules/ZAS/ConnectionGroup.dm @@ -24,7 +24,7 @@ Class Vars: connection_edge/unsimulated - B - This holds an unsimulated turf which has the gas values this edge is mimicing. + B - This holds an unsimulated turf which has the gas values this edge is mimicking. air - Retrieved from B on creation and used as an argument for the legacy ShareSpace() proc. @@ -55,16 +55,25 @@ Class Procs: Helper proc that allows getting the other zone of an edge given one of them. Only on /connection_edge/zone, otherwise use A. + update_post_merge() + Called after the edge's owner is merged into another zone. + Marks the relevant connecting turfs for update. + */ -/connection_edge/var/zone/A +/connection_edge + var/zone/A -/connection_edge/var/list/connecting_turfs = list() -/connection_edge/var/direct = 0 -/connection_edge/var/sleeping = 1 + var/list/connecting_turfs = list() + var/direct = 0 + var/sleeping = 1 + var/coefficient = 0 -/connection_edge/var/coefficient = 0 + #ifdef ZASDBG + ///Set this to TRUE during testing to get verbose debug information. + var/tmp/verbose = FALSE + #endif /connection_edge/New() CRASH("Cannot make connection edge without specifications.") @@ -72,55 +81,46 @@ Class Procs: /connection_edge/proc/add_connection(connection/c) coefficient++ if(c.direct()) direct++ -// log_debug("Connection added: [type] Coefficient: [coefficient]") + #ifdef ZASDBG + if(verbose) + zas_log("Connection added: [type] Coefficient: [coefficient]") + #endif -/connection_edge/proc/remove_connection(connection/c) -// log_debug("Connection removed: [type] Coefficient: [coefficient-1]") +/connection_edge/proc/remove_connection(connection/c) coefficient-- if(coefficient <= 0) erase() if(c.direct()) direct-- + #ifdef ZASDBG + if(verbose) + zas_log("Connection removed: [type] Coefficient: [coefficient-1]") + #endif + /connection_edge/proc/contains_zone(zone/Z) /connection_edge/proc/erase() SSair.remove_edge(src) -// log_debug("[type] Erased.") + #ifdef ZASDBG + if(verbose) + zas_log("[type] Erased.") + #endif /connection_edge/proc/tick() /connection_edge/proc/recheck() /connection_edge/proc/flow(list/movable, differential, repelled) - for(var/i = 1; i <= movable.len; i++) - var/atom/movable/M = movable[i] - + for(var/atom/movable/M as anything in movable) //If they're already being tossed, don't do it again. - if(M.last_airflow > world.time - vsc.airflow_delay) continue - if(M.airflow_speed) continue - - //Check for knocking people over - if(ismob(M) && differential > vsc.airflow_stun_pressure) - if(M:status_flags & GODMODE) continue - M:airflow_stun() - - if(M.check_airflow_movable(differential)) - //Check for things that are in range of the midpoint turfs. - var/list/close_turfs = list() - for(var/turf/U in connecting_turfs) - if(get_dist(M,U) < world.view) close_turfs += U - if(!close_turfs.len) continue - - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - - if(repelled) spawn if(M) M.RepelAirflowDest(differential/5) - else spawn if(M) M.GotoAirflowDest(differential/10) - - + M.handle_airflow(differential, connecting_turfs, repelled) +/connection_edge/proc/update_post_merge() + for(var/turf/T in connecting_turfs) + SSair.mark_for_update(T) /connection_edge/zone/var/zone/B @@ -130,9 +130,11 @@ Class Procs: src.B = B A.edges.Add(src) B.edges.Add(src) - //id = edge_id(A,B) -// log_debug("New edge between [A] and [B]") + #ifdef ZASDBG + if(verbose) + zas_log("New edge between [A] and [B]") + #endif /connection_edge/zone/add_connection(connection/c) . = ..() @@ -201,9 +203,11 @@ Class Procs: src.B = B A.edges.Add(src) air = B.return_air() - //id = 52*A.id -// log_debug("New edge from [A] to [B].") + #ifdef ZASDBG + if(verbose) + zas_log("New edge from [A] to [B] ([B.x], [B.y], [B.z]).") + #endif /connection_edge/unsimulated/add_connection(connection/c) . = ..() @@ -215,6 +219,11 @@ Class Procs: air.group_multiplier = coefficient . = ..() + // Update the air mix + if(coefficient && (B == c.B) && !(B in connecting_turfs)) + B = pick(connecting_turfs) + air = B.return_air() + /connection_edge/unsimulated/erase() A.edges.Remove(src) . = ..() @@ -231,8 +240,7 @@ Class Procs: var/differential = A.air.return_pressure() - air.return_pressure() if(abs(differential) >= vsc.airflow_lightest_pressure) - var/list/attracted = A.movables() - flow(attracted, abs(differential), differential < 0) + flow(A.movables(), abs(differential), differential < 0) if(equiv) A.air.copy_from(air) @@ -247,7 +255,7 @@ Class Procs: if(!A.air.compare(air, vacuum_exception = 1)) SSair.mark_edge_active(src) -proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) +/proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) //This implements a simplistic version of the Stefan-Boltzmann law. var/energy_delta = ((A.temperature - B.temperature) ** 4) * STEFAN_BOLTZMANN_CONSTANT * connecting_tiles * 2.5 var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity() * A.group_multiplier, B.temperature * B.heat_capacity() * B.group_multiplier)) diff --git a/code/modules/ZAS/ConnectionManager.dm b/code/modules/ZAS/ConnectionManager.dm index 3890cd85f5cd..de4e36c81129 100644 --- a/code/modules/ZAS/ConnectionManager.dm +++ b/code/modules/ZAS/ConnectionManager.dm @@ -36,70 +36,71 @@ Macros: /turf/var/tmp/connection_manager/connections -/connection_manager/var/connection/N -/connection_manager/var/connection/S -/connection_manager/var/connection/E -/connection_manager/var/connection/W +/connection_manager + var/connection/north_connection + var/connection/south_connection + var/connection/east_connection + var/connection/west_connection #ifdef MULTIZAS -/connection_manager/var/connection/U -/connection_manager/var/connection/D + var/connection/upward_connection + var/connection/downward_connection #endif /connection_manager/proc/get(d) switch(d) if(NORTH) - if(check(N)) return N + if(check(north_connection)) return north_connection else return null if(SOUTH) - if(check(S)) return S + if(check(south_connection)) return south_connection else return null if(EAST) - if(check(E)) return E + if(check(east_connection)) return east_connection else return null if(WEST) - if(check(W)) return W + if(check(west_connection)) return west_connection else return null #ifdef MULTIZAS if(UP) - if(check(U)) return U + if(check(upward_connection)) return upward_connection else return null if(DOWN) - if(check(D)) return D + if(check(downward_connection)) return downward_connection else return null #endif /connection_manager/proc/place(connection/c, d) switch(d) - if(NORTH) N = c - if(SOUTH) S = c - if(EAST) E = c - if(WEST) W = c + if(NORTH) north_connection = c + if(SOUTH) south_connection = c + if(EAST) east_connection = c + if(WEST) west_connection = c #ifdef MULTIZAS - if(UP) U = c - if(DOWN) D = c + if(UP) upward_connection = c + if(DOWN) downward_connection = c #endif /connection_manager/proc/update_all() - if(check(N)) N.update() - if(check(S)) S.update() - if(check(E)) E.update() - if(check(W)) W.update() + if(check(north_connection)) north_connection.update() + if(check(south_connection)) south_connection.update() + if(check(east_connection)) east_connection.update() + if(check(west_connection)) west_connection.update() #ifdef MULTIZAS - if(check(U)) U.update() - if(check(D)) D.update() + if(check(upward_connection)) upward_connection.update() + if(check(downward_connection)) downward_connection.update() #endif /connection_manager/proc/erase_all() - if(check(N)) N.erase() - if(check(S)) S.erase() - if(check(E)) E.erase() - if(check(W)) W.erase() + if(check(north_connection)) north_connection.erase() + if(check(south_connection)) south_connection.erase() + if(check(east_connection)) east_connection.erase() + if(check(west_connection)) west_connection.erase() #ifdef MULTIZAS - if(check(U)) U.erase() - if(check(D)) D.erase() + if(check(upward_connection)) upward_connection.erase() + if(check(downward_connection)) downward_connection.erase() #endif #undef check diff --git a/code/modules/ZAS/Contaminants.dm b/code/modules/ZAS/Contaminants.dm index 78f480c1d8c8..be9f69d74367 100644 --- a/code/modules/ZAS/Contaminants.dm +++ b/code/modules/ZAS/Contaminants.dm @@ -1,4 +1,4 @@ -var/image/contamination_overlay = image('icons/effects/contamination.dmi') +var/global/image/contamination_overlay = image('icons/effects/contamination.dmi') /contaminant_control var/CONTAMINANT_DMG = 3 @@ -37,29 +37,19 @@ var/image/contamination_overlay = image('icons/effects/contamination.dmi') var/N2O_HALLUCINATION_NAME = "N2O Hallucination" var/N2O_HALLUCINATION_DESC = "Does being in sleeping gas cause you to hallucinate?" - -obj/var/contaminated = 0 - - -/obj/item/proc/can_contaminate() - //Clothing and backpacks can be contaminated. - if(obj_flags & ITEM_FLAG_NO_CONTAMINATION) return 0 - else if(istype(src,/obj/item/storage/backpack)) return 0 //Cannot be washed :( - else if(istype(src,/obj/item/clothing)) return 1 - /obj/item/proc/contaminate() //Do a contamination overlay? Temporary measure to keep contamination less deadly than it was. if(!contaminated) - contaminated = 1 - overlays += contamination_overlay + contaminated = TRUE + queue_icon_update() /obj/item/proc/decontaminate() - contaminated = 0 - overlays -= contamination_overlay + contaminated = FALSE + queue_icon_update() /mob/proc/contaminate() -/mob/living/carbon/human/contaminate() +/mob/living/human/contaminate() //See if anything can be contaminated. if(!contaminant_suit_protected()) @@ -69,104 +59,88 @@ obj/var/contaminated = 0 if(prob(1)) suit_contamination() // Contaminants can sometimes get through such an open suit. //Cannot wash backpacks currently. -// if(istype(back,/obj/item/storage/backpack)) +// if(istype(back,/obj/item/backpack)) // back.contaminate() /mob/proc/handle_contaminants() return -/mob/living/carbon/human/handle_contaminants() +/mob/living/human/handle_contaminants() //Handles all the bad things contaminants can do. //Contamination if(vsc.contaminant_control.CLOTH_CONTAMINATION) contaminate() //Anything else requires them to not be dead. - if(stat >= 2) + if((stat >= DEAD) || (status_flags & GODMODE)) return //Burn skin if exposed. if(vsc.contaminant_control.SKIN_BURNS) if(!contaminant_head_protected() || !contaminant_suit_protected()) - burn_skin(0.75) - if(prob(20)) to_chat(src, "Your skin burns!") - updatehealth() + if(prob(20)) + to_chat(src, "Your skin burns!") + take_overall_damage(0, 0.75) //Burn eyes if exposed. if(vsc.contaminant_control.EYE_BURNS) - if(!head) - if(!wear_mask) - burn_eyes() - else - if(!(wear_mask.body_parts_covered & EYES)) - burn_eyes() - else - if(!(head.body_parts_covered & EYES)) - if(!wear_mask) - burn_eyes() - else - if(!(wear_mask.body_parts_covered & EYES)) - burn_eyes() + var/found_eyeguard = FALSE + for(var/slot in global.standard_headgear_slots) + var/obj/item/clothing/thing = get_equipped_item(slot) + if(istype(thing) && (thing.body_parts_covered & SLOT_EYES)) + found_eyeguard = TRUE + break + if(!found_eyeguard) + burn_eyes() //Genetic Corruption if(vsc.contaminant_control.GENETIC_CORRUPTION) if(rand(1,10000) < vsc.contaminant_control.GENETIC_CORRUPTION) - randmutb(src) + add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/disability))) to_chat(src, "High levels of toxins cause you to spontaneously mutate!") - domutcheck(src,null) - -/mob/living/carbon/human/proc/burn_eyes() - var/obj/item/organ/internal/eyes/E = internal_organs_by_name[BP_EYES] - if(E && !E.contaminant_guard) +/mob/living/human/proc/burn_eyes() + var/obj/item/organ/internal/eyes/eyes = get_organ(BP_EYES, /obj/item/organ/internal/eyes) + if(eyes && !eyes.bodytype.eye_contaminant_guard) if(prob(20)) to_chat(src, "Your eyes burn!") - E.damage += 2.5 - eye_blurry = min(eye_blurry+1.5,50) - if (prob(max(0,E.damage - 15) + 1) &&!eye_blind) + eyes.adjust_organ_damage(2.5) + SET_STATUS_MAX(src, STAT_BLURRY, 50) + if (prob(max(0,eyes.get_organ_damage() - 15) + 1) && !GET_STATUS(src, STAT_BLIND)) to_chat(src, "You are blinded!") - eye_blind += 20 + SET_STATUS_MAX(src, STAT_BLIND, 20) -/mob/living/carbon/human/proc/contaminant_head_protected() +/mob/living/human/proc/contaminant_head_protected() //Checks if the head is adequately sealed. - if(head) - if(vsc.contaminant_control.STRICT_PROTECTION_ONLY) - if(head.item_flags & ITEM_FLAG_NO_CONTAMINATION) - return 1 - else if(head.body_parts_covered & EYES) - return 1 - return 0 - -/mob/living/carbon/human/proc/contaminant_suit_protected() + var/obj/item/head = get_equipped_item(slot_head_str) + if(!head) + return FALSE + // If strict protection is on, you must have a head item with ITEM_FLAG_NO_CONTAMINATION. + if(vsc.contaminant_control.STRICT_PROTECTION_ONLY) + if(!(head.item_flags & ITEM_FLAG_NO_CONTAMINATION)) + return FALSE + // Regardless, the head item must cover the face and head. Eyes are checked seperately above. + return BIT_TEST_ALL(head.body_parts_covered, SLOT_HEAD|SLOT_FACE) + +/mob/living/human/proc/contaminant_suit_protected() //Checks if the suit is adequately sealed. var/coverage = 0 - for(var/obj/item/protection in list(wear_suit, gloves, shoes)) - if(!protection) + for(var/slot in list(slot_wear_suit_str, slot_gloves_str, slot_shoes_str)) + var/obj/item/protection = get_equipped_item(slot) + if(!istype(protection)) continue if(vsc.contaminant_control.STRICT_PROTECTION_ONLY && !(protection.item_flags & ITEM_FLAG_NO_CONTAMINATION)) - return 0 + return FALSE coverage |= protection.body_parts_covered if(vsc.contaminant_control.STRICT_PROTECTION_ONLY) - return 1 + return TRUE - return BIT_TEST_ALL(coverage, UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS) + return BIT_TEST_ALL(coverage, SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS) -/mob/living/carbon/human/proc/suit_contamination() +/mob/living/human/proc/suit_contamination() //Runs over the things that can be contaminated and does so. - if(w_uniform) w_uniform.contaminate() - if(shoes) shoes.contaminate() - if(gloves) gloves.contaminate() - - -turf/Entered(obj/item/I) - . = ..() - //Items that are in contaminants, but not on a mob, can still be contaminated. - if(istype(I) && vsc && vsc.contaminant_control.CLOTH_CONTAMINATION && I.can_contaminate()) - var/datum/gas_mixture/env = return_air(1) - if(!env) - return - for(var/g in env.gas) - var/decl/material/mat = decls_repository.get_decl(g) - if((mat.gas_flags & XGM_GAS_CONTAMINANT) && env.gas[g] > mat.gas_overlay_limit + 1) - I.contaminate() - break + for(var/slot in list(slot_w_uniform_str, slot_shoes_str, slot_gloves_str)) + var/obj/item/gear = get_equipped_item(slot) + if(istype(gear)) + gear.contaminate() + diff --git a/code/modules/ZAS/Debug.dm b/code/modules/ZAS/Debug.dm index 6f0a67fd3eb0..e6304fa9092c 100644 --- a/code/modules/ZAS/Debug.dm +++ b/code/modules/ZAS/Debug.dm @@ -1,20 +1,93 @@ -var/image/assigned = image('icons/Testing/Zone.dmi', icon_state = "assigned") -var/image/created = image('icons/Testing/Zone.dmi', icon_state = "created") -var/image/merged = image('icons/Testing/Zone.dmi', icon_state = "merged") -var/image/invalid_zone = image('icons/Testing/Zone.dmi', icon_state = "invalid") -var/image/air_blocked = image('icons/Testing/Zone.dmi', icon_state = "block") -var/image/zone_blocked = image('icons/Testing/Zone.dmi', icon_state = "zoneblock") -var/image/blocked = image('icons/Testing/Zone.dmi', icon_state = "fullblock") -var/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark") - -/connection_edge/var/dbg_out = 0 - -/turf/var/tmp/dbg_img -/turf/proc/dbg(image/img, d = 0) - if(d > 0) img.dir = d - overlays -= dbg_img - overlays += img +#ifdef ZASDBG + +var/global/obj/effect/zasdbg/assigned/zasdbgovl_assigned = new +var/global/obj/effect/zasdbg/created/zasdbgovl_created = new +var/global/obj/effect/zasdbg/merged/zasdbgovl_merged = new +var/global/obj/effect/zasdbg/invalid_zone/zasdbgovl_invalid_zone = new +var/global/obj/effect/zasdbg/blocked/zasdbgovl_blocked = new +var/global/obj/effect/zasdbg/mark/zasdbgovl_mark = new + +var/global/list/zasdbgovl_dirblock = list( + "north" = new /obj/effect/zasdbg/air_blocked/north, + "east" = new /obj/effect/zasdbg/air_blocked/east, + "south" = new /obj/effect/zasdbg/air_blocked/south, + "west" = new /obj/effect/zasdbg/air_blocked/west, +) +///Retrives the directional block indicator overlay for a given direction +#define ZAS_DIRECTIONAL_BLOCKER(d) (zasdbgovl_dirblock[dir2text(d)]) + +var/global/list/zasdbgovl_dirzoneblock = list( + "north" = new /obj/effect/zasdbg/zone_blocked/north, + "east" = new /obj/effect/zasdbg/zone_blocked/east, + "south" = new /obj/effect/zasdbg/zone_blocked/south, + "west" = new /obj/effect/zasdbg/zone_blocked/west, +) +///Retrieves the zone blocked debug overlay for a given direction +#define ZAS_ZONE_BLOCKER(d) (zasdbgovl_dirzoneblock[dir2text(d)]) + +/obj/effect/zasdbg + icon = 'icons/Testing/Zone.dmi' + invisibility = INVISIBILITY_OBSERVER + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + plane = EFFECTS_ABOVE_LIGHTING_PLANE + layer = FLY_LAYER + +/obj/effect/zasdbg/assigned + icon_state = "assigned" +/obj/effect/zasdbg/created + icon_state = "created" +/obj/effect/zasdbg/merged + icon_state = "merged" +/obj/effect/zasdbg/invalid_zone + icon_state = "invalid" +/obj/effect/zasdbg/blocked + icon_state = "fullblock" +/obj/effect/zasdbg/mark + icon_state = "mark" + +/obj/effect/zasdbg/zone_blocked + icon_state = "zoneblock" + +/obj/effect/zasdbg/zone_blocked/north + dir = NORTH +/obj/effect/zasdbg/zone_blocked/east + dir = EAST +/obj/effect/zasdbg/zone_blocked/south + dir = SOUTH +/obj/effect/zasdbg/zone_blocked/west + dir = WEST + +/obj/effect/zasdbg/air_blocked + icon_state = "block" + +/obj/effect/zasdbg/air_blocked/north + dir = NORTH +/obj/effect/zasdbg/air_blocked/east + dir = EAST +/obj/effect/zasdbg/air_blocked/south + dir = SOUTH +/obj/effect/zasdbg/air_blocked/west + dir = WEST + + +/turf/var/tmp/obj/effect/zasdbg/dbg_img +/turf/proc/dbg(obj/effect/zasdbg/img) + remove_vis_contents(dbg_img) + add_vis_contents(img) dbg_img = img -proc/soft_assert(thing,fail) - if(!thing) message_admins(fail) \ No newline at end of file +/proc/soft_assert(thing,fail) + if(!thing) message_admins(fail) + +/datum/proc/zas_log(string) + return + +/turf/zas_log(string) + to_chat(world, "[SPAN_DEBUG("ZAS:")] ([src.x], [src.y], [src.z]): [string]") + +/connection/zas_log(string) + to_chat(world, "[SPAN_DEBUG("ZAS:")] connection output: [string]") + +/connection_edge/zas_log(string) + to_chat(world, "[SPAN_DEBUG("ZAS:")] connection edge output: [string]") +#endif diff --git a/code/modules/ZAS/Diagnostic.dm b/code/modules/ZAS/Diagnostic.dm index 886b26e433d2..71641a66eef1 100644 --- a/code/modules/ZAS/Diagnostic.dm +++ b/code/modules/ZAS/Diagnostic.dm @@ -1,55 +1,57 @@ -client/proc/Zone_Info(turf/T as null|turf) +/client/proc/Zone_Info(turf/T as null|turf) set category = "Debug" - if(T) - if(istype(T,/turf/simulated) && T:zone) - T:zone:dbg_data(src) - else - to_chat(mob, "No zone here.") - var/datum/gas_mixture/mix = T.return_air() - to_chat(mob, "[mix.return_pressure()] kPa [mix.temperature]C") - for(var/g in mix.gas) - to_chat(mob, "[g]: [mix.gas[g]]\n") + if(!T) + return + if(isturf(T) && T.zone) + T.zone.dbg_data(src) + if(length(T.zone.contents) < ZONE_MIN_SIZE) + to_chat(mob, SPAN_NOTICE("This turf's zone is below the minimum size, and will merge over zone blockers.")) else - if(zone_debug_images) - for(var/zone in zone_debug_images) - images -= zone_debug_images[zone] - zone_debug_images = null - -client/var/list/zone_debug_images + to_chat(mob, "ZONE: No zone here.") + var/datum/gas_mixture/mix = T.return_air() + to_chat(mob, "ZONE: [mix.return_pressure()] kPa [mix.temperature] k") + for(var/g in mix.gas) + to_chat(mob, "ZONE GASES: [g]: [mix.gas[g]]\n") -client/proc/Test_ZAS_Connection(var/turf/simulated/T) +/client/proc/Test_ZAS_Connection(var/turf/T) set category = "Debug" if(!istype(T)) return - var/direction_list = list(\ - "North" = NORTH,\ - "South" = SOUTH,\ - "East" = EAST,\ - "West" = WEST,\ + var/direction_list = list( + "North" = NORTH, + "South" = SOUTH, + "East" = EAST, + "West" = WEST, #ifdef MULTIZAS - "Up" = UP,\ - "Down" = DOWN,\ + "Up" = UP, + "Down" = DOWN, #endif "N/A" = null) var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list if(!direction) return + var/airblock if(direction == "N/A") - if(!(T.c_airblock(T) & AIR_BLOCKED)) + to_chat(mob, "Testing self-blocking...") + ATMOS_CANPASS_TURF(airblock, T, T) + if(!(airblock & AIR_BLOCKED)) to_chat(mob, "The turf can pass air! :D") else to_chat(mob, "No air passage :x") return - var/turf/simulated/other_turf = get_step(T, direction_list[direction]) + var/turf/other_turf = get_step(T, direction_list[direction]) if(!istype(other_turf)) return - var/t_block = T.c_airblock(other_turf) - var/o_block = other_turf.c_airblock(T) + var/t_block + ATMOS_CANPASS_TURF(t_block, T, other_turf) + var/o_block + ATMOS_CANPASS_TURF(o_block, other_turf, T) + to_chat(mob, "Testing connection between ([T.x], [T.y], [T.z]) and ([other_turf.x], [other_turf.y], [other_turf.z])...") if(o_block & AIR_BLOCKED) if(t_block & AIR_BLOCKED) to_chat(mob, "Neither turf can connect. :(") @@ -76,7 +78,7 @@ client/proc/Test_ZAS_Connection(var/turf/simulated/T) else to_chat(mob, "both turfs can merge.") -client/proc/ZASSettings() +/client/proc/ZASSettings() set category = "Debug" vsc.SetDefault(mob) diff --git a/code/modules/ZAS/Fire.dm b/code/modules/ZAS/Fire.dm index b1fb707305af..8e68d92a22f9 100644 --- a/code/modules/ZAS/Fire.dm +++ b/code/modules/ZAS/Fire.dm @@ -10,10 +10,6 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin /turf/var/obj/fire/fire = null -//Some legacy definitions so fires can be started. -atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - return null - /atom/movable/proc/is_burnable() return FALSE @@ -21,19 +17,17 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed return simulated /turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) - return - -/turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) - if(fire_protection > world.time-300) - return 0 - if(locate(/obj/fire) in src) + if((locate(/obj/fire) in src) || !simulated) return 1 + var/datum/gas_mixture/air_contents = return_air() if(!air_contents || exposed_temperature < FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE) return 0 + vaporize_fuel(air_contents) + var/igniting = 0 - if(air_contents.check_combustibility(return_fluid())) + if(air_contents.check_combustibility()) igniting = 1 create_fire(exposed_temperature) return igniting @@ -51,44 +45,16 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed T.fire.firelevel = firelevel else fire_tiles -= T - fuel_objs -= T.return_fluid() else - for(var/turf/simulated/T in fire_tiles) + for(var/turf/T in fire_tiles) if(istype(T.fire)) qdel(T.fire) fire_tiles.Cut() - fuel_objs.Cut() if(!fire_tiles.len) SSair.active_fire_zones.Remove(src) -/zone/proc/remove_liquidfuel(var/used_liquid_fuel, var/remove_fire=0) - if(!length(fuel_objs)) - return - - //As a simplification, we remove fuel equally from all fuel sources. It might be that some fuel sources have more fuel, - //some have less, but whatever. It will mean that sometimes we will remove a tiny bit less fuel then we intended to. - - var/fuel_to_remove = used_liquid_fuel/(length(fuel_objs) * LIQUIDFUEL_AMOUNT_TO_MOL) //convert back to liquid volume units - - for(var/O in fuel_objs) - var/obj/effect/fluid/fuel = O - if(!istype(fuel) || !fuel.get_fuel_amount()) - fuel_objs -= fuel - continue - - fuel.remove_fuel(fuel_to_remove) - if(QDELETED(fuel) || fuel.get_fuel_amount() <= 0) - fuel_objs -= fuel - if(remove_fire) - var/turf/T = fuel.loc - if(istype(T) && T.fire) - qdel(T.fire) - /turf/proc/create_fire(fl) - return 0 - -/turf/simulated/create_fire(fl) if(submerged()) return 1 @@ -104,17 +70,13 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed SSair.active_fire_zones |= zone zone.fire_tiles |= src - var/obj/effect/fluid/fuel = return_fluid() - if(fuel?.get_fuel_amount()) - zone.fuel_objs += fuel - return 0 /obj/fire //Icon for fire on turfs. - anchored = 1 - mouse_opacity = 0 + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE blend_mode = BLEND_ADD @@ -128,7 +90,7 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed /obj/fire/Process() . = 1 - var/turf/simulated/my_tile = loc + var/turf/my_tile = loc if(!istype(my_tile) || !my_tile.zone || my_tile.submerged()) if(my_tile && my_tile.fire == src) my_tile.fire = null @@ -139,39 +101,39 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed if(firelevel > 6) icon_state = "3" - set_light(1, 2, 7) + set_light(7, 3, no_update = TRUE) else if(firelevel > 2.5) icon_state = "2" - set_light(0.7, 2, 5) + set_light(5, 2, no_update = TRUE) else icon_state = "1" - set_light(0.5, 1, 3) + set_light(3, 1, no_update = TRUE) for(var/mob/living/L in loc) L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs! - loc.fire_act(air_contents, air_contents.temperature, air_contents.volume) + loc.fire_act(air_contents, air_contents.temperature, air_contents.total_volume) for(var/atom/A in loc) - A.fire_act(air_contents, air_contents.temperature, air_contents.volume) + A.fire_act(air_contents, air_contents.temperature, air_contents.total_volume) + + // prioritize nearby fuel overlays first + for(var/direction in global.cardinal) + var/turf/enemy_tile = get_step(my_tile, direction) + if(istype(enemy_tile) && enemy_tile.reagents) + enemy_tile.hotspot_expose(air_contents.temperature, air_contents.total_volume) //spread - for(var/direction in GLOB.cardinal) - var/turf/simulated/enemy_tile = get_step(my_tile, direction) + for(var/direction in global.cardinal) + var/turf/enemy_tile = get_step(my_tile, direction) if(istype(enemy_tile)) - if(my_tile.open_directions & direction) //Grab all valid bordering tiles + if(my_tile.airflow_open_directions & direction) //Grab all valid bordering tiles if(!enemy_tile.zone || enemy_tile.fire) continue //if(!enemy_tile.zone.fire_tiles.len) TODO - optimize var/datum/gas_mixture/acs = enemy_tile.return_air() - if(!acs || !acs.check_combustibility(enemy_tile.return_fluid())) - continue - - //If extinguisher mist passed over the turf it's trying to spread to, don't spread and - //reduce firelevel. - if(enemy_tile.fire_protection > world.time-30) - firelevel -= 1.5 + if(!acs || !acs.check_combustibility()) continue //Spread the fire. @@ -179,7 +141,7 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed enemy_tile.create_fire(firelevel) else - enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.volume) + enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.total_volume) animate(src, color = fire_color(air_contents.temperature), 5) set_light(l_color = color) @@ -187,14 +149,14 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed /obj/fire/Initialize(mapload, fl) . = ..() - if(!istype(loc, /turf)) + if(!isturf(loc)) return INITIALIZE_HINT_QDEL - set_dir(pick(GLOB.cardinal)) + set_dir(pick(global.cardinal)) var/datum/gas_mixture/air_contents = loc.return_air() color = fire_color(air_contents.temperature) - set_light(0.5, 1, 3, l_color = color) + set_light(3, 0.5, color) firelevel = fl SSair.active_hotspots.Add(src) @@ -211,48 +173,29 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed SSair.active_hotspots.Remove(src) . = ..() -/turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again. -/turf/proc/apply_fire_protection() -/turf/simulated/apply_fire_protection() - fire_protection = world.time - //Returns the firelevel -/datum/gas_mixture/proc/react(zone/zone, force_burn, no_check = 0) +/datum/gas_mixture/proc/react(var/zone/zone, force_burn, no_check = 0) . = 0 - if((temperature > FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustibility(zone? zone.fuel_objs : null))) + if((temperature > FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustibility())) #ifdef FIREDBG log_debug("***************** FIREDBG *****************") log_debug("Burning [zone? zone.name : "zoneless gas_mixture"]!") #endif - var/gas_fuel = 0 - var/liquid_fuel = 0 var/total_fuel = 0 var/total_oxidizers = 0 //*** Get the fuel and oxidizer amounts for(var/g in gas) - var/decl/material/mat = decls_repository.get_decl(g) + var/decl/material/mat = GET_DECL(g) if(mat.gas_flags & XGM_GAS_FUEL) - gas_fuel += gas[g] + total_fuel += gas[g] if(mat.gas_flags & XGM_GAS_OXIDIZER) total_oxidizers += gas[g] - gas_fuel *= group_multiplier + total_fuel *= group_multiplier total_oxidizers *= group_multiplier - //Liquid Fuel - var/fuel_area = 0 - if(zone) - for(var/obj/effect/fluid/fuel in zone.fuel_objs) - var/fuel_amount = fuel.get_fuel_amount() - if(!fuel_amount) - zone.fuel_objs -= fuel - continue - liquid_fuel += fuel_amount * LIQUIDFUEL_AMOUNT_TO_MOL - fuel_area++ - - total_fuel = gas_fuel + liquid_fuel if(total_fuel <= 0.005) return 0 @@ -266,69 +209,50 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed var/reaction_limit = min(total_oxidizers*(FIRE_REACTION_FUEL_AMOUNT/FIRE_REACTION_OXIDIZER_AMOUNT), total_fuel) //stoichiometric limit //vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old zburn).) - var/gas_firelevel = calculate_firelevel(gas_fuel, total_oxidizers, reaction_limit, volume*group_multiplier) / vsc.fire_firelevel_multiplier - var/min_burn = 0.30*volume*group_multiplier/CELL_VOLUME //in moles - so that fires with very small gas concentrations burn out fast - var/gas_reaction_progress = min(max(min_burn, gas_firelevel*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel) - - //liquid fuels are not as volatile, and the reaction progress depends on the size of the area that is burning. Limit the burn rate to a certain amount per area. - var/liquid_firelevel = calculate_firelevel(liquid_fuel, total_oxidizers, reaction_limit, 0) / vsc.fire_firelevel_multiplier - var/liquid_reaction_progress = min((liquid_firelevel*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel) - - var/firelevel = (gas_fuel*gas_firelevel + liquid_fuel*liquid_firelevel)/total_fuel - - var/total_reaction_progress = gas_reaction_progress + liquid_reaction_progress + var/firelevel = calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, total_volume*group_multiplier) / vsc.fire_firelevel_multiplier + var/min_burn = 0.30*total_volume*group_multiplier/CELL_VOLUME //in moles - so that fires with very small gas concentrations burn out fast + var/total_reaction_progress = min(max(min_burn, firelevel*total_fuel)*FIRE_GAS_BURNRATE_MULT, total_fuel) var/used_fuel = min(total_reaction_progress, reaction_limit) var/used_oxidizers = used_fuel*(FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT) #ifdef FIREDBG - log_debug("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]") + log_debug("total_fuel = [total_fuel], total_oxidizers = [total_oxidizers]") log_debug("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]") - log_debug("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])") - log_debug("liquid_reaction_progress = [liquid_reaction_progress]") - log_debug("gas_reaction_progress = [gas_reaction_progress]") + log_debug("firelevel -> [firelevel]") log_debug("total_reaction_progress = [total_reaction_progress]") log_debug("used_fuel = [used_fuel], used_oxidizers = [used_oxidizers]; ") #endif //if the reaction is progressing too slow then it isn't self-sustaining anymore and burns out - if(zone) //be less restrictive with canister and tank reactions - if((!liquid_fuel || used_fuel <= FIRE_LIQUD_MIN_BURNRATE) && (!gas_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*zone.contents.len)) - return 0 - + if(zone && (!total_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*zone.contents.len)) + return 0 //*** Remove fuel and oxidizer, add carbon dioxide and heat - //remove and add gasses as calculated - var/used_gas_fuel = min(max(0.25, used_fuel*(gas_reaction_progress/total_reaction_progress)), gas_fuel) //remove in proportion to the relative reaction progress - var/used_liquid_fuel = min(max(0.25, used_fuel-used_gas_fuel), liquid_fuel) - + used_fuel = min(used_fuel, total_fuel) //remove_by_flag() and adjust_gas() handle the group_multiplier for us. remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers) - var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_gas_fuel) + var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_fuel) for(var/g in burned_fuel.gas) - var/decl/material/mat = decls_repository.get_decl(g) - if(mat.gas_burn_product) - adjust_gas(mat.gas_burn_product, burned_fuel.gas[g]) - - if(zone) - zone.remove_liquidfuel(used_liquid_fuel, !check_combustibility()) + var/decl/material/mat = GET_DECL(g) + mat.add_burn_product(src, burned_fuel.gas[g]) //calculate the energy produced by the reaction and then set the new temperature of the mix - temperature = (starting_energy + vsc.fire_fuel_energy_release * (used_gas_fuel + used_liquid_fuel)) / heat_capacity() + temperature = (starting_energy + vsc.fire_fuel_energy_release * used_fuel) / heat_capacity() update_values() #ifdef FIREDBG - log_debug("used_gas_fuel = [used_gas_fuel]; used_liquid_fuel = [used_liquid_fuel]; total = [used_fuel]") + log_debug("used_fuel = [used_fuel]; total = [used_fuel]") log_debug("new temperature = [temperature]; new pressure = [return_pressure()]") #endif return firelevel -datum/gas_mixture/proc/check_recombustibility(list/fuel_objs) +/datum/gas_mixture/proc/check_recombustibility() . = 0 for(var/g in gas) if(gas[g] >= 0.1) - var/decl/material/gas = decls_repository.get_decl(g) + var/decl/material/gas = GET_DECL(g) if(gas.gas_flags & XGM_GAS_OXIDIZER) . = 1 break @@ -336,22 +260,19 @@ datum/gas_mixture/proc/check_recombustibility(list/fuel_objs) if(!.) return 0 - if(length(fuel_objs)) - return 1 - . = 0 for(var/g in gas) if(gas[g] >= 0.1) - var/decl/material/gas = decls_repository.get_decl(g) + var/decl/material/gas = GET_DECL(g) if(gas.gas_flags & XGM_GAS_OXIDIZER) . = 1 break -/datum/gas_mixture/proc/check_combustibility(var/obj/effect/fluid/fuel) +/datum/gas_mixture/proc/check_combustibility() . = 0 for(var/g in gas) if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1) - var/decl/material/gas = decls_repository.get_decl(g) + var/decl/material/gas = GET_DECL(g) if(gas.gas_flags & XGM_GAS_OXIDIZER) . = 1 break @@ -359,13 +280,10 @@ datum/gas_mixture/proc/check_recombustibility(list/fuel_objs) if(!.) return 0 - if(fuel?.get_fuel_amount()) - return 1 - . = 0 for(var/g in gas) if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1) - var/decl/material/gas = decls_repository.get_decl(g) + var/decl/material/gas = GET_DECL(g) if(gas.gas_flags & XGM_GAS_FUEL) . = 1 break @@ -378,7 +296,7 @@ datum/gas_mixture/proc/check_recombustibility(list/fuel_objs) var/total_combustibles = (total_fuel + total_oxidizers) var/active_combustibles = (FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT + 1)*reaction_limit - if(total_combustibles > 0) + if(total_combustibles > 0 && total_moles > 0 && group_multiplier > 0) //slows down the burning when the concentration of the reactants is low var/damping_multiplier = min(1, active_combustibles / (total_moles/group_multiplier)) @@ -406,7 +324,7 @@ datum/gas_mixture/proc/check_recombustibility(list/fuel_objs) return mx -/mob/living/carbon/human/FireBurn(var/firelevel, var/last_temperature, var/pressure) +/mob/living/human/FireBurn(var/firelevel, var/last_temperature, var/pressure) //Burns mobs due to fire. Respects heat transfer coefficients on various body parts. //Due to TG reworking how fireprotection works, this is kinda less meaningful. @@ -418,22 +336,23 @@ datum/gas_mixture/proc/check_recombustibility(list/fuel_objs) //Get heat transfer coefficients for clothing. + var/holding = get_held_items() for(var/obj/item/clothing/C in src) - if(l_hand == C || r_hand == C) + if(C in holding) continue if( C.max_heat_protection_temperature >= last_temperature ) - if(C.body_parts_covered & HEAD) + if(C.body_parts_covered & SLOT_HEAD) head_exposure = 0 - if(C.body_parts_covered & UPPER_TORSO) + if(C.body_parts_covered & SLOT_UPPER_BODY) chest_exposure = 0 - if(C.body_parts_covered & LOWER_TORSO) + if(C.body_parts_covered & SLOT_LOWER_BODY) groin_exposure = 0 - if(C.body_parts_covered & LEGS) + if(C.body_parts_covered & SLOT_LEGS) legs_exposure = 0 - if(C.body_parts_covered & ARMS) + if(C.body_parts_covered & SLOT_ARMS) arms_exposure = 0 - //minimize this for low-pressure enviroments + //minimize this for low-pressure environments var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1) //Always check these damage procs first if fire damage isn't working. They're probably what's wrong. diff --git a/code/modules/ZAS/Turf.dm b/code/modules/ZAS/Turf.dm index 3e11177ff141..016d69b4c53e 100644 --- a/code/modules/ZAS/Turf.dm +++ b/code/modules/ZAS/Turf.dm @@ -1,104 +1,22 @@ -/turf/simulated/var/zone/zone -/turf/simulated/var/open_directions - -/turf/var/needs_air_update = 0 -/turf/var/datum/gas_mixture/air - -/turf/simulated/proc/update_graphic(list/graphic_add = null, list/graphic_remove = null) - if(graphic_add && graphic_add.len) - vis_contents += graphic_add - if(graphic_remove && graphic_remove.len) - vis_contents -= graphic_remove +////Turf Vars//// +#ifdef ZASDBG +///Set to TRUE during debugging to get descriptive to_chats of the object. Works for all atmos-related datums. +/turf/var/tmp/verbose = FALSE +#endif /turf/proc/update_air_properties() - var/block = c_airblock(src) - if(block & AIR_BLOCKED) - //dbg(blocked) - return 1 - - #ifdef MULTIZAS - for(var/d = 1, d < 64, d *= 2) - #else - for(var/d = 1, d < 16, d *= 2) - #endif - - var/turf/unsim = get_step(src, d) - - if(!unsim) - continue - - block = unsim.c_airblock(src) - - if(block & AIR_BLOCKED) - //unsim.dbg(air_blocked, turn(180,d)) - continue - - var/r_block = c_airblock(unsim) - - if(r_block & AIR_BLOCKED) - continue - - if(istype(unsim, /turf/simulated)) - - var/turf/simulated/sim = unsim - if(TURF_HAS_VALID_ZONE(sim)) - SSair.connect(sim, src) - -/* - Simple heuristic for determining if removing the turf from it's zone will not partition the zone (A very bad thing). - Instead of analyzing the entire zone, we only check the nearest 3x3 turfs surrounding the src turf. - This implementation may produce false negatives but it (hopefully) will not produce any false postiives. -*/ - -/turf/simulated/proc/can_safely_remove_from_zone() - if(!zone) return 1 - - var/check_dirs = get_zone_neighbours(src) - var/unconnected_dirs = check_dirs - - #ifdef MULTIZAS - var/to_check = GLOB.cornerdirsz - #else - var/to_check = GLOB.cornerdirs - #endif - - for(var/dir in to_check) - - //for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH) - if((dir & check_dirs) == dir) - //check that they are connected by the corner turf - var/connected_dirs = get_zone_neighbours(get_step(src, dir)) - if(connected_dirs && (dir & GLOB.reverse_dir[connected_dirs]) == dir) - unconnected_dirs &= ~dir //they are, so unflag the cardinals in question - - //it is safe to remove src from the zone if all cardinals are connected by corner turfs - return !unconnected_dirs - -//helper for can_safely_remove_from_zone() -/turf/simulated/proc/get_zone_neighbours(turf/simulated/T) - . = 0 - if(istype(T) && T.zone) - #ifdef MULTIZAS - var/to_check = GLOB.cardinalz - #else - var/to_check = GLOB.cardinal - #endif - for(var/dir in to_check) - var/turf/simulated/other = get_step(T, dir) - if(istype(other) && other.zone == T.zone && !(other.c_airblock(T) & AIR_BLOCKED) && get_dist(src, other) <= 1) - . |= dir - -/turf/simulated/update_air_properties() - if(zone && zone.invalid) //this turf's zone is in the process of being rebuilt + if(zone?.invalid) //this turf's zone is in the process of being rebuilt c_copy_air() //not very efficient :( zone = null //Easier than iterating through the list at the zone. - var/s_block = c_airblock(src) + var/s_block + ATMOS_CANPASS_TURF(s_block, src, src) if(s_block & AIR_BLOCKED) #ifdef ZASDBG - if(verbose) log_debug("Self-blocked.") - //dbg(blocked) + if(verbose) + zas_log("Self-blocked.") + dbg(zasdbgovl_blocked) #endif if(zone) var/zone/z = zone @@ -111,14 +29,15 @@ return 1 - var/previously_open = open_directions - open_directions = 0 + var/zas_participation = SHOULD_PARTICIPATE_IN_ZONES(src) + var/previously_open = airflow_open_directions + airflow_open_directions = 0 var/list/postponed #ifdef MULTIZAS - for(var/d = 1, d < 64, d *= 2) + for(var/d in global.cardinalz) #else - for(var/d = 1, d < 16, d *= 2) + for(var/d in global.cardinal) #endif var/turf/unsim = get_step(src, d) @@ -126,166 +45,256 @@ if(!unsim) //edge of map continue - var/block = unsim.c_airblock(src) + var/block + ATMOS_CANPASS_TURF(block, unsim, src) if(block & AIR_BLOCKED) #ifdef ZASDBG - if(verbose) log_debug("[d] is blocked.") - //unsim.dbg(air_blocked, turn(180,d)) + if(verbose) + zas_log("[dir2text(d)] is blocked.") + //dbg(ZAS_DIRECTIONAL_BLOCKER(d)) #endif continue - var/r_block = c_airblock(unsim) + var/r_block + ATMOS_CANPASS_TURF(r_block, src, unsim) if(r_block & AIR_BLOCKED) #ifdef ZASDBG - if(verbose) log_debug("[d] is blocked.") - //dbg(air_blocked, d) + if(verbose) + zas_log("[dir2text(d)] is blocked.") + //target.dbg(ZAS_DIRECTIONAL_BLOCKER(turn(d, 180))) #endif //Check that our zone hasn't been cut off recently. //This happens when windows move or are constructed. We need to rebuild. - if((previously_open & d) && istype(unsim, /turf/simulated)) - var/turf/simulated/sim = unsim - if(zone && sim.zone == zone) + if((previously_open & d) && unsim.zone_membership_candidate) + if(zone && unsim.zone == zone) zone.rebuild() return continue - open_directions |= d + airflow_open_directions |= d - if(istype(unsim, /turf/simulated)) + if(SHOULD_PARTICIPATE_IN_ZONES(unsim)) - var/turf/simulated/sim = unsim - sim.open_directions |= GLOB.reverse_dir[d] + unsim.airflow_open_directions |= global.reverse_dir[d] - if(TURF_HAS_VALID_ZONE(sim)) + if(TURF_HAS_VALID_ZONE(unsim)) - //Might have assigned a zone, since this happens for each direction. - if(!zone) + if(zas_participation) + //Might have assigned a zone, since this happens for each direction. + if(!zone) - //We do not merge if - // they are blocking us and we are not blocking them, or if - // we are blocking them and not blocking ourselves - this prevents tiny zones from forming on doorways. - if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || ((r_block & ZONE_BLOCKED) && !(s_block & ZONE_BLOCKED))) - #ifdef ZASDBG - if(verbose) log_debug("[d] is zone blocked.") + //We do not merge if + // they are blocking us and we are not blocking them, or if + // we are blocking them and not blocking ourselves - this prevents tiny zones from forming on doorways. + if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || ((r_block & ZONE_BLOCKED) && !(s_block & ZONE_BLOCKED))) + #ifdef ZASDBG + if(verbose) + zas_log("[dir2text(d)] is zone blocked.") + //dbg(ZAS_ZONE_BLOCKER(d)) + #endif - //dbg(zone_blocked, d) - #endif + //Postpone this tile rather than exit, since a connection can still be made. + if(!postponed) postponed = list() + postponed.Add(unsim) + + else - //Postpone this tile rather than exit, since a connection can still be made. - if(!postponed) postponed = list() - postponed.Add(sim) + unsim.zone.add(src) - else + #ifdef ZASDBG + dbg(zasdbgovl_assigned) + if(verbose) + zas_log("Added to [zone]") + #endif - sim.zone.add(src) + else if(unsim.zone != zone) #ifdef ZASDBG - dbg(assigned) - if(verbose) log_debug("Added to [zone]") + if(verbose) + zas_log("Connecting to [unsim.zone]") #endif - else if(sim.zone != zone) + SSair.connect(src, unsim) + + #ifdef ZASDBG + else if(verbose) + zas_log("[dir2text(d)] has same zone.") + #endif + + else #ifdef ZASDBG - if(verbose) log_debug("Connecting to [sim.zone]") + if(verbose) + zas_log("Connecting non-ZAS turf to [unsim.zone]") #endif - SSair.connect(src, sim) - + SSair.connect(unsim, src) - #ifdef ZASDBG - else if(verbose) log_debug("[d] has same zone.") + #ifdef ZASDBG + else if(verbose) + zas_log("[dir2text(d)] has an invalid or rebuilding zone.") + #endif - else if(verbose) log_debug("[d] has invalid zone.") - #endif - - else + else if(zas_participation) //Postponing connections to tiles until a zone is assured. if(!postponed) postponed = list() postponed.Add(unsim) - if(!TURF_HAS_VALID_ZONE(src)) //Still no zone, make a new one. + if(zas_participation && !TURF_HAS_VALID_ZONE(src)) //Still no zone, make a new one. var/zone/newzone = new/zone() newzone.add(src) #ifdef ZASDBG - dbg(created) + dbg(zasdbgovl_created) + if(verbose) + zas_log("New zone created for src.") - ASSERT(zone) + ASSERT(!zas_participation || zone) #endif - //At this point, a zone should have happened. If it hasn't, don't add more checks, fix the bug. + //At this point, a zone should have happened if the turf participates in ZAS. If it hasn't, don't add more checks, fix the bug. for(var/turf/T in postponed) SSair.connect(src, T) +// Helper for can_safely_remove_from_zone(). +#define GET_ZONE_NEIGHBOURS(T, ret) \ + ret = 0; \ + if (T.zone) { \ + for (var/_gzn_dir in ZAS_GZN_CHECK) { \ + var/turf/other = get_step(T, _gzn_dir); \ + if (istype(other) && other.simulated && other.zone == T.zone) { \ + var/block; \ + ATMOS_CANPASS_TURF(block, other, T); \ + if (!(block & AIR_BLOCKED)) { \ + ret |= _gzn_dir; \ + } \ + } \ + } \ + } + +/* + Simple heuristic for determining if removing the turf from it's zone will not partition the zone (A very bad thing). + Instead of analyzing the entire zone, we only check the nearest 3x3 turfs surrounding the src turf. + This implementation may produce false negatives but it (hopefully) will not produce any false postiives. +*/ + +/turf/proc/can_safely_remove_from_zone() + + if(!zone) + return 1 + + var/check_dirs + GET_ZONE_NEIGHBOURS(src, check_dirs) + . = check_dirs + + //src is only connected to the zone by a single direction, this is a safe removal. + if (!(check_dirs & (check_dirs - 1))) //Equivalent to: if(IsInteger(log(2, .))) + return TRUE + + for(var/dir in ZAS_CSRFZ_CHECK) + //for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH) + if((dir & check_dirs) == dir) + //check that they are connected by the corner turf + var/turf/T = get_step(src, dir) + if (!istype(T) || !T.simulated) + . &= ~dir + continue + var/connected_dirs + GET_ZONE_NEIGHBOURS(T, connected_dirs) + if(connected_dirs && (dir & global.reverse_dir[connected_dirs]) == dir) + . &= ~dir //they are, so unflag the cardinals in question + //it is safe to remove src from the zone if all cardinals are connected by corner turfs + . = !. + /turf/proc/post_update_air_properties() if(connections) connections.update_all() /turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air - return 0 + var/datum/gas_mixture/my_air = return_air() + if(my_air) + my_air.merge(giver) + return TRUE + return FALSE -/turf/proc/assume_gas(gasid, moles, temp = 0) - return 0 +var/global/list/STANDARD_AIRMIX = list( + /decl/material/gas/oxygen = MOLES_O2STANDARD, + /decl/material/gas/nitrogen = MOLES_N2STANDARD +) /turf/return_air() - //Create gas mixture to hold data for passing - var/datum/gas_mixture/GM = new + RETURN_TYPE(/datum/gas_mixture) - if(initial_gas) - GM.gas = initial_gas.Copy() - GM.temperature = temperature - GM.update_values() + // TODO: immutable gas mixtures for stuff like this, to avoid creating new datums every time. + if(!simulated) + return make_air() + + // ZAS participation + if(zone && !zone.invalid) + SSair.mark_zone_update(zone) + return zone.air - return GM + // Exterior turf global atmosphere + if((!air && isnull(initial_gas)) || (external_atmosphere_participation && is_outside())) + return get_external_air() + + // Base behavior + . = air || make_air() + if(zone) + c_copy_air() + zone = null /turf/remove_air(amount as num) var/datum/gas_mixture/GM = return_air() return GM.remove(amount) -/turf/simulated/assume_air(datum/gas_mixture/giver) +/turf/proc/assume_gas(gasid, moles, temp = null) var/datum/gas_mixture/my_air = return_air() - my_air.merge(giver) - -/turf/simulated/assume_gas(gasid, moles, temp = null) - var/datum/gas_mixture/my_air = return_air() - - if(isnull(temp)) - my_air.adjust_gas(gasid, moles) - else - my_air.adjust_gas_temp(gasid, moles, temp) - - return 1 - -/turf/simulated/return_air() - if(zone) - if(!zone.invalid) - SSair.mark_zone_update(zone) - return zone.air + if(my_air) + if(isnull(temp)) + my_air.adjust_gas(gasid, moles) else - if(!air) - make_air() - c_copy_air() - return air - else - if(!air) - make_air() - return air + my_air.adjust_gas_temp(gasid, moles, temp) + return TRUE + return FALSE /turf/proc/make_air() - air = new/datum/gas_mixture + air = new /datum/gas_mixture air.temperature = temperature if(initial_gas) - air.gas = initial_gas.Copy() + if(initial_gas == GAS_STANDARD_AIRMIX) + air.gas = global.STANDARD_AIRMIX.Copy() + else + air.gas = initial_gas.Copy() air.update_values() - -/turf/simulated/proc/c_copy_air() - if(!air) air = new/datum/gas_mixture + return air + +// Returns the external air if this turf is outside, modified by weather and heat sources. Outside checks do not occur in this proc! +/turf/proc/get_external_air(include_heat_sources = TRUE) + var/datum/level_data/level = SSmapping.levels_by_z[z] + var/datum/gas_mixture/gas = level.get_exterior_atmosphere() + if(!include_heat_sources) + return gas + + if(weather) + gas.temperature = weather.adjust_temperature(gas.temperature) + var/initial_temperature = gas.temperature + if(length(affecting_heat_sources)) + for(var/obj/structure/fire_source/heat_source as anything in affecting_heat_sources) + gas.temperature = gas.temperature + heat_source.exterior_temperature / max(1, get_dist(src, get_turf(heat_source))) + if(abs(gas.temperature - initial_temperature) >= 100) + break + gas.update_values() + return gas + +/turf/proc/c_copy_air() + if(!air) + air = new/datum/gas_mixture air.copy_from(zone.air) - air.group_multiplier = 1 + air.group_multiplier = 1 \ No newline at end of file diff --git a/code/modules/ZAS/Variable Settings.dm b/code/modules/ZAS/Variable Settings.dm deleted file mode 100644 index 731aa8437aed..000000000000 --- a/code/modules/ZAS/Variable Settings.dm +++ /dev/null @@ -1,363 +0,0 @@ -var/global/vs_control/vsc = new - -/vs_control - var/fire_consuption_rate = 0.25 - var/fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" - var/fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." - - var/fire_firelevel_multiplier = 25 - var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" - var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." - - //Note that this parameter and the gas heat capacity have a significant impact on TTV yield. - var/fire_fuel_energy_release = 866000 //J/mol. Adjusted to compensate for fire energy release being fixed, was 397000 - var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" - var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" - - - var/IgnitionLevel = 0.5 - var/IgnitionLevel_DESC = "Determines point at which fire can ignite" - - var/airflow_lightest_pressure = 20 - var/airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" - var/airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." - - var/airflow_light_pressure = 35 - var/airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" - var/airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." - - var/airflow_medium_pressure = 50 - var/airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" - var/airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." - - var/airflow_heavy_pressure = 65 - var/airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" - var/airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." - - var/airflow_dense_pressure = 85 - var/airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" - var/airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." - - var/airflow_stun_pressure = 60 - var/airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" - var/airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." - - var/airflow_stun_cooldown = 60 - var/airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" - var/airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." - - var/airflow_stun = 1 - var/airflow_stun_NAME = "Airflow Impact - Stunning" - var/airflow_stun_DESC = "How much a mob is stunned when hit by an object." - - var/airflow_damage = 3 - var/airflow_damage_NAME = "Airflow Impact - Damage" - var/airflow_damage_DESC = "Damage from airflow impacts." - - var/airflow_speed_decay = 1.5 - var/airflow_speed_decay_NAME = "Airflow Speed Decay" - var/airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." - - var/airflow_delay = 30 - var/airflow_delay_NAME = "Airflow Retrigger Delay" - var/airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." - - var/airflow_mob_slowdown = 1 - var/airflow_mob_slowdown_NAME = "Airflow Slowdown" - var/airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." - - var/connection_insulation = 1 - var/connection_insulation_NAME = "Connections - Insulation" - var/connection_insulation_DESC = "Boolean, should doors forbid heat transfer?" - - var/connection_temperature_delta = 10 - var/connection_temperature_delta_NAME = "Connections - Temperature Difference" - var/connection_temperature_delta_DESC = "The smallest temperature difference which will cause heat to travel through doors." - - -/vs_control/var/list/settings = list() -/vs_control/var/list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") -/vs_control/var/contaminant_control/contaminant_control = new() - -/vs_control/New() - . = ..() - settings = vars.Copy() - - var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. - for(var/V in D.vars) - settings -= V - - for(var/V in settings) - if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) - settings -= V - - settings -= "settings" - settings -= "bitflags" - settings -= "contaminant_control" - -/vs_control/proc/ChangeSettingsDialog(mob/user,list/L) - //var/which = input(user,"Choose a setting:") in L - var/dat = "" - for(var/ch in L) - if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue - var/vw - var/vw_desc = "No Description." - var/vw_name = ch - if(ch in contaminant_control.settings) - vw = contaminant_control.vars[ch] - if("[ch]_DESC" in contaminant_control.vars) vw_desc = contaminant_control.vars["[ch]_DESC"] - if("[ch]_NAME" in contaminant_control.vars) vw_name = contaminant_control.vars["[ch]_NAME"] - else - vw = vars[ch] - if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] - if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] - dat += "[vw_name] = [vw] \[Change\]
              " - dat += "[vw_desc]

              " - show_browser(user, dat, "window=settings") - -/vs_control/Topic(href,href_list) - if("changevar" in href_list) - ChangeSetting(usr,href_list["changevar"]) - -/vs_control/proc/ChangeSetting(mob/user,ch) - var/vw - var/how = "Text" - var/display_description = ch - if(ch in contaminant_control.settings) - vw = contaminant_control.vars[ch] - if("[ch]_NAME" in contaminant_control.vars) - display_description = contaminant_control.vars["[ch]_NAME"] - if("[ch]_METHOD" in contaminant_control.vars) - how = contaminant_control.vars["[ch]_METHOD"] - else - if(isnum(vw)) - how = "Numeric" - else - how = "Text" - else - vw = vars[ch] - if("[ch]_NAME" in vars) - display_description = vars["[ch]_NAME"] - if("[ch]_METHOD" in vars) - how = vars["[ch]_METHOD"] - else - if(isnum(vw)) - how = "Numeric" - else - how = "Text" - var/newvar = vw - switch(how) - if("Numeric") - newvar = input(user,"Enter a number:","Settings",newvar) as num - if("Bit Flag") - var/flag = input(user,"Toggle which bit?","Settings") in bitflags - flag = text2num(flag) - if(newvar & flag) - newvar &= ~flag - else - newvar |= flag - if("Toggle") - newvar = !newvar - if("Text") - newvar = input(user,"Enter a string:","Settings",newvar) as text - if("Long Text") - newvar = input(user,"Enter text:","Settings",newvar) as message - vw = newvar - if(ch in contaminant_control.settings) - contaminant_control.vars[ch] = vw - else - vars[ch] = vw - if(how == "Toggle") - newvar = (newvar?"ON":"OFF") - to_world("[key_name(user)] changed the setting [display_description] to [newvar].") - if(ch in contaminant_control.settings) - ChangeSettingsDialog(user,contaminant_control.settings) - else - ChangeSettingsDialog(user,settings) - -/vs_control/proc/RandomizeWithProbability() - for(var/V in settings) - var/newvalue - if("[V]_RANDOM" in vars) - if(isnum(vars["[V]_RANDOM"])) - newvalue = prob(vars["[V]_RANDOM"]) - else if(istext(vars["[V]_RANDOM"])) - newvalue = roll(vars["[V]_RANDOM"]) - else - newvalue = vars[V] - V = newvalue - -/vs_control/proc/SetDefault(var/mob/user) - var/list/setting_choices = list("Contaminants - Standard", "Contaminants - Low Hazard", "Contaminants - High Hazard", "Contaminants - Oh Shit!",\ - "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish", "ZAS/Contaminants - Initial") - var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices - if(!def) - return - switch(def) - if("Contaminants - Standard") - contaminant_control.CLOTH_CONTAMINATION = 1 //If this is on, contaminants do damage by getting into cloth. - contaminant_control.STRICT_PROTECTION_ONLY = 0 - contaminant_control.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - contaminant_control.SKIN_BURNS = 0 //Contaminants have an effect similar to mustard gas on the un-suited. - contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. - contaminant_control.CONTAMINANT_HALLUCINATION = 0 - contaminant_control.CONTAMINATION_LOSS = 0.02 - - if("Contaminants - Low Hazard") - contaminant_control.CLOTH_CONTAMINATION = 0 //If this is on, contaminants do damage by getting into cloth. - contaminant_control.STRICT_PROTECTION_ONLY = 0 - contaminant_control.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 - contaminant_control.SKIN_BURNS = 0 //Contaminants have an effect similar to mustard gas on the un-suited. - contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. - contaminant_control.CONTAMINANT_HALLUCINATION = 0 - contaminant_control.CONTAMINATION_LOSS = 0.01 - - if("Contaminants - High Hazard") - contaminant_control.CLOTH_CONTAMINATION = 1 //If this is on, contaminants do damage by getting into cloth. - contaminant_control.STRICT_PROTECTION_ONLY = 0 - contaminant_control.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - contaminant_control.SKIN_BURNS = 1 //Contaminants have an effect similar to mustard gas on the un-suited. - contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. - contaminant_control.CONTAMINANT_HALLUCINATION = 1 - contaminant_control.CONTAMINATION_LOSS = 0.05 - - if("Contaminants - Oh Shit!") - contaminant_control.CLOTH_CONTAMINATION = 1 //If this is on, contaminants do damage by getting into cloth. - contaminant_control.STRICT_PROTECTION_ONLY = 1 - contaminant_control.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. - contaminant_control.SKIN_BURNS = 1 //Contaminants have an effect similar to mustard gas on the un-suited. - contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. - contaminant_control.CONTAMINANT_HALLUCINATION = 1 - contaminant_control.CONTAMINATION_LOSS = 0.075 - - if("ZAS - Normal") - airflow_lightest_pressure = 20 - airflow_light_pressure = 35 - airflow_medium_pressure = 50 - airflow_heavy_pressure = 65 - airflow_dense_pressure = 85 - airflow_stun_pressure = 60 - airflow_stun_cooldown = 60 - airflow_stun = 1 - airflow_damage = 3 - airflow_speed_decay = 1.5 - airflow_delay = 30 - airflow_mob_slowdown = 1 - - if("ZAS - Forgiving") - airflow_lightest_pressure = 45 - airflow_light_pressure = 60 - airflow_medium_pressure = 120 - airflow_heavy_pressure = 110 - airflow_dense_pressure = 200 - airflow_stun_pressure = 150 - airflow_stun_cooldown = 90 - airflow_stun = 0.15 - airflow_damage = 0.5 - airflow_speed_decay = 1.5 - airflow_delay = 50 - airflow_mob_slowdown = 0 - - if("ZAS - Dangerous") - airflow_lightest_pressure = 15 - airflow_light_pressure = 30 - airflow_medium_pressure = 45 - airflow_heavy_pressure = 55 - airflow_dense_pressure = 70 - airflow_stun_pressure = 50 - airflow_stun_cooldown = 50 - airflow_stun = 2 - airflow_damage = 4 - airflow_speed_decay = 1.2 - airflow_delay = 25 - airflow_mob_slowdown = 2 - - if("ZAS - Hellish") - airflow_lightest_pressure = 20 - airflow_light_pressure = 30 - airflow_medium_pressure = 40 - airflow_heavy_pressure = 50 - airflow_dense_pressure = 60 - airflow_stun_pressure = 40 - airflow_stun_cooldown = 40 - airflow_stun = 3 - airflow_damage = 5 - airflow_speed_decay = 1 - airflow_delay = 20 - airflow_mob_slowdown = 3 - connection_insulation = 0 - - if("ZAS/Contaminants - Initial") - fire_consuption_rate = initial(fire_consuption_rate) - fire_firelevel_multiplier = initial(fire_firelevel_multiplier) - fire_fuel_energy_release = initial(fire_fuel_energy_release) - IgnitionLevel = initial(IgnitionLevel) - airflow_lightest_pressure = initial(airflow_lightest_pressure) - airflow_light_pressure = initial(airflow_light_pressure) - airflow_medium_pressure = initial(airflow_medium_pressure) - airflow_heavy_pressure = initial(airflow_heavy_pressure) - airflow_dense_pressure = initial(airflow_dense_pressure) - airflow_stun_pressure = initial(airflow_stun_pressure) - airflow_stun_cooldown = initial(airflow_stun_cooldown) - airflow_stun = initial(airflow_stun) - airflow_damage = initial(airflow_damage) - airflow_speed_decay = initial(airflow_speed_decay) - airflow_delay = initial(airflow_delay) - airflow_mob_slowdown = initial(airflow_mob_slowdown) - connection_insulation = initial(connection_insulation) - connection_temperature_delta = initial(connection_temperature_delta) - - contaminant_control.CONTAMINANT_DMG = initial(contaminant_control.CONTAMINANT_DMG) - contaminant_control.CLOTH_CONTAMINATION = initial(contaminant_control.CLOTH_CONTAMINATION) - contaminant_control.STRICT_PROTECTION_ONLY = initial(contaminant_control.STRICT_PROTECTION_ONLY) - contaminant_control.GENETIC_CORRUPTION = initial(contaminant_control.GENETIC_CORRUPTION) - contaminant_control.SKIN_BURNS = initial(contaminant_control.SKIN_BURNS) - contaminant_control.EYE_BURNS = initial(contaminant_control.EYE_BURNS) - contaminant_control.CONTAMINATION_LOSS = initial(contaminant_control.CONTAMINATION_LOSS) - contaminant_control.CONTAMINANT_HALLUCINATION = initial(contaminant_control.CONTAMINANT_HALLUCINATION) - contaminant_control.N2O_HALLUCINATION = initial(contaminant_control.N2O_HALLUCINATION) - - - to_world("[key_name(user)] changed the global contaminant/ZAS settings to \"[def]\"") - -/contaminant_control/var/list/settings = list() - -/contaminant_control/New() - . = ..() - settings = vars.Copy() - - var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. - for(var/V in D.vars) - settings -= V - - for(var/V in settings) - if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) - settings -= V - - settings -= "settings" - -/contaminant_control/proc/Randomize(V) - var/newvalue - if("[V]_RANDOM" in vars) - if(isnum(vars["[V]_RANDOM"])) - newvalue = prob(vars["[V]_RANDOM"]) - else if(istext(vars["[V]_RANDOM"])) - var/txt = vars["[V]_RANDOM"] - if(findtextEx(txt,"PROB")) - txt = splittext(txt,"/") - txt[1] = replacetext(txt[1],"PROB","") - var/p = text2num(txt[1]) - var/r = txt[2] - if(prob(p)) - newvalue = roll(r) - else - newvalue = vars[V] - else if(findtextEx(txt,"PICK")) - txt = replacetext(txt,"PICK","") - txt = splittext(txt,",") - newvalue = pick(txt) - else - newvalue = roll(txt) - else - newvalue = vars[V] - vars[V] = newvalue diff --git a/code/modules/ZAS/VariableSettings.dm b/code/modules/ZAS/VariableSettings.dm new file mode 100644 index 000000000000..e53e6955c5b9 --- /dev/null +++ b/code/modules/ZAS/VariableSettings.dm @@ -0,0 +1,363 @@ +var/global/vs_control/vsc = new + +/vs_control + var/fire_consuption_rate = 0.25 + var/fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" + var/fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." + + var/fire_firelevel_multiplier = 25 + var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" + var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." + + //Note that this parameter and the gas heat capacity have a significant impact on TTV yield. + var/fire_fuel_energy_release = 866000 //J/mol. Adjusted to compensate for fire energy release being fixed, was 397000 + var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" + var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" + + + var/IgnitionLevel = 0.5 + var/IgnitionLevel_DESC = "Determines point at which fire can ignite" + + var/airflow_lightest_pressure = 20 + var/airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" + var/airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." + + var/airflow_light_pressure = 35 + var/airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" + var/airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." + + var/airflow_medium_pressure = 50 + var/airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" + var/airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." + + var/airflow_heavy_pressure = 65 + var/airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" + var/airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." + + var/airflow_dense_pressure = 85 + var/airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" + var/airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." + + var/airflow_stun_pressure = 60 + var/airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" + var/airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." + + var/airflow_stun_cooldown = 60 + var/airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" + var/airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." + + var/airflow_stun = 1 + var/airflow_stun_NAME = "Airflow Impact - Stunning" + var/airflow_stun_DESC = "How much a mob is stunned when hit by an object." + + var/airflow_damage = 3 + var/airflow_damage_NAME = "Airflow Impact - Damage" + var/airflow_damage_DESC = "Damage from airflow impacts." + + var/airflow_speed_decay = 1.5 + var/airflow_speed_decay_NAME = "Airflow Speed Decay" + var/airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." + + var/airflow_delay = 30 + var/airflow_delay_NAME = "Airflow Retrigger Delay" + var/airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." + + var/airflow_mob_slowdown = 1 + var/airflow_mob_slowdown_NAME = "Airflow Slowdown" + var/airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." + + var/connection_insulation = 1 + var/connection_insulation_NAME = "Connections - Insulation" + var/connection_insulation_DESC = "Boolean, should doors forbid heat transfer?" + + var/connection_temperature_delta = 10 + var/connection_temperature_delta_NAME = "Connections - Temperature Difference" + var/connection_temperature_delta_DESC = "The smallest temperature difference which will cause heat to travel through doors." + + +/vs_control/var/list/settings = list() +/vs_control/var/list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") +/vs_control/var/contaminant_control/contaminant_control = new() + +/vs_control/New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) + settings -= V + + settings -= "settings" + settings -= "bitflags" + settings -= "contaminant_control" + +/vs_control/proc/ChangeSettingsDialog(mob/user,list/L) + //var/which = input(user,"Choose a setting:") in L + var/dat = "" + for(var/ch in L) + if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue + var/vw + var/vw_desc = "No Description." + var/vw_name = ch + if(ch in contaminant_control.settings) + vw = contaminant_control.vars[ch] + if("[ch]_DESC" in contaminant_control.vars) vw_desc = contaminant_control.vars["[ch]_DESC"] + if("[ch]_NAME" in contaminant_control.vars) vw_name = contaminant_control.vars["[ch]_NAME"] + else + vw = vars[ch] + if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] + if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] + dat += "[vw_name] = [vw] \[Change\]
              " + dat += "[vw_desc]

              " + show_browser(user, dat, "window=settings") + +/vs_control/Topic(href,href_list) + if("changevar" in href_list) + ChangeSetting(usr,href_list["changevar"]) + +/vs_control/proc/ChangeSetting(mob/user,ch) + var/vw + var/how = "Text" + var/display_description = ch + if(ch in contaminant_control.settings) + vw = contaminant_control.vars[ch] + if("[ch]_NAME" in contaminant_control.vars) + display_description = contaminant_control.vars["[ch]_NAME"] + if("[ch]_METHOD" in contaminant_control.vars) + how = contaminant_control.vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" + else + how = "Text" + else + vw = vars[ch] + if("[ch]_NAME" in vars) + display_description = vars["[ch]_NAME"] + if("[ch]_METHOD" in vars) + how = vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" + else + how = "Text" + var/newvar = vw + switch(how) + if("Numeric") + newvar = input(user,"Enter a number:","Settings",newvar) as num + if("Bit Flag") + var/flag = input(user,"Toggle which bit?","Settings") in bitflags + flag = text2num(flag) + if(newvar & flag) + newvar &= ~flag + else + newvar |= flag + if("Toggle") + newvar = !newvar + if("Text") + newvar = input(user,"Enter a string:","Settings",newvar) as text + if("Long Text") + newvar = input(user,"Enter text:","Settings",newvar) as message + vw = newvar + if(ch in contaminant_control.settings) + contaminant_control.vars[ch] = vw + else + vars[ch] = vw + if(how == "Toggle") + newvar = (newvar?"ON":"OFF") + to_world("[key_name(user)] changed the setting [display_description] to [newvar].") + if(ch in contaminant_control.settings) + ChangeSettingsDialog(user,contaminant_control.settings) + else + ChangeSettingsDialog(user,settings) + +/vs_control/proc/RandomizeWithProbability() + for(var/V in settings) + var/newvalue + if("[V]_RANDOM" in vars) + if(isnum(vars["[V]_RANDOM"])) + newvalue = prob(vars["[V]_RANDOM"]) + else if(istext(vars["[V]_RANDOM"])) + newvalue = roll(vars["[V]_RANDOM"]) + else + newvalue = vars[V] + V = newvalue + +/vs_control/proc/SetDefault(var/mob/user) + var/list/setting_choices = list("Contaminants - Standard", "Contaminants - Low Hazard", "Contaminants - High Hazard", "Contaminants - Oh Shit!",\ + "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish", "ZAS/Contaminants - Initial") + var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices + if(!def) + return + switch(def) + if("Contaminants - Standard") + contaminant_control.CLOTH_CONTAMINATION = 1 //If this is on, contaminants do damage by getting into cloth. + contaminant_control.STRICT_PROTECTION_ONLY = 0 + contaminant_control.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + contaminant_control.SKIN_BURNS = 0 //Contaminants have an effect similar to mustard gas on the un-suited. + contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. + contaminant_control.CONTAMINANT_HALLUCINATION = 0 + contaminant_control.CONTAMINATION_LOSS = 0.02 + + if("Contaminants - Low Hazard") + contaminant_control.CLOTH_CONTAMINATION = 0 //If this is on, contaminants do damage by getting into cloth. + contaminant_control.STRICT_PROTECTION_ONLY = 0 + contaminant_control.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 + contaminant_control.SKIN_BURNS = 0 //Contaminants have an effect similar to mustard gas on the un-suited. + contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. + contaminant_control.CONTAMINANT_HALLUCINATION = 0 + contaminant_control.CONTAMINATION_LOSS = 0.01 + + if("Contaminants - High Hazard") + contaminant_control.CLOTH_CONTAMINATION = 1 //If this is on, contaminants do damage by getting into cloth. + contaminant_control.STRICT_PROTECTION_ONLY = 0 + contaminant_control.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + contaminant_control.SKIN_BURNS = 1 //Contaminants have an effect similar to mustard gas on the un-suited. + contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. + contaminant_control.CONTAMINANT_HALLUCINATION = 1 + contaminant_control.CONTAMINATION_LOSS = 0.05 + + if("Contaminants - Oh Shit!") + contaminant_control.CLOTH_CONTAMINATION = 1 //If this is on, contaminants do damage by getting into cloth. + contaminant_control.STRICT_PROTECTION_ONLY = 1 + contaminant_control.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. + contaminant_control.SKIN_BURNS = 1 //Contaminants have an effect similar to mustard gas on the un-suited. + contaminant_control.EYE_BURNS = 1 //Contaminants burn the eyes of anyone not wearing eye protection. + contaminant_control.CONTAMINANT_HALLUCINATION = 1 + contaminant_control.CONTAMINATION_LOSS = 0.075 + + if("ZAS - Normal") + airflow_lightest_pressure = 20 + airflow_light_pressure = 35 + airflow_medium_pressure = 50 + airflow_heavy_pressure = 65 + airflow_dense_pressure = 85 + airflow_stun_pressure = 60 + airflow_stun_cooldown = 60 + airflow_stun = 1 + airflow_damage = 3 + airflow_speed_decay = 1.5 + airflow_delay = 30 + airflow_mob_slowdown = 1 + + if("ZAS - Forgiving") + airflow_lightest_pressure = 45 + airflow_light_pressure = 60 + airflow_medium_pressure = 120 + airflow_heavy_pressure = 110 + airflow_dense_pressure = 200 + airflow_stun_pressure = 150 + airflow_stun_cooldown = 90 + airflow_stun = 0.15 + airflow_damage = 0.5 + airflow_speed_decay = 1.5 + airflow_delay = 50 + airflow_mob_slowdown = 0 + + if("ZAS - Dangerous") + airflow_lightest_pressure = 15 + airflow_light_pressure = 30 + airflow_medium_pressure = 45 + airflow_heavy_pressure = 55 + airflow_dense_pressure = 70 + airflow_stun_pressure = 50 + airflow_stun_cooldown = 50 + airflow_stun = 2 + airflow_damage = 4 + airflow_speed_decay = 1.2 + airflow_delay = 25 + airflow_mob_slowdown = 2 + + if("ZAS - Hellish") + airflow_lightest_pressure = 20 + airflow_light_pressure = 30 + airflow_medium_pressure = 40 + airflow_heavy_pressure = 50 + airflow_dense_pressure = 60 + airflow_stun_pressure = 40 + airflow_stun_cooldown = 40 + airflow_stun = 3 + airflow_damage = 5 + airflow_speed_decay = 1 + airflow_delay = 20 + airflow_mob_slowdown = 3 + connection_insulation = 0 + + if("ZAS/Contaminants - Initial") + fire_consuption_rate = initial(fire_consuption_rate) + fire_firelevel_multiplier = initial(fire_firelevel_multiplier) + fire_fuel_energy_release = initial(fire_fuel_energy_release) + IgnitionLevel = initial(IgnitionLevel) + airflow_lightest_pressure = initial(airflow_lightest_pressure) + airflow_light_pressure = initial(airflow_light_pressure) + airflow_medium_pressure = initial(airflow_medium_pressure) + airflow_heavy_pressure = initial(airflow_heavy_pressure) + airflow_dense_pressure = initial(airflow_dense_pressure) + airflow_stun_pressure = initial(airflow_stun_pressure) + airflow_stun_cooldown = initial(airflow_stun_cooldown) + airflow_stun = initial(airflow_stun) + airflow_damage = initial(airflow_damage) + airflow_speed_decay = initial(airflow_speed_decay) + airflow_delay = initial(airflow_delay) + airflow_mob_slowdown = initial(airflow_mob_slowdown) + connection_insulation = initial(connection_insulation) + connection_temperature_delta = initial(connection_temperature_delta) + + contaminant_control.CONTAMINANT_DMG = initial(contaminant_control.CONTAMINANT_DMG) + contaminant_control.CLOTH_CONTAMINATION = initial(contaminant_control.CLOTH_CONTAMINATION) + contaminant_control.STRICT_PROTECTION_ONLY = initial(contaminant_control.STRICT_PROTECTION_ONLY) + contaminant_control.GENETIC_CORRUPTION = initial(contaminant_control.GENETIC_CORRUPTION) + contaminant_control.SKIN_BURNS = initial(contaminant_control.SKIN_BURNS) + contaminant_control.EYE_BURNS = initial(contaminant_control.EYE_BURNS) + contaminant_control.CONTAMINATION_LOSS = initial(contaminant_control.CONTAMINATION_LOSS) + contaminant_control.CONTAMINANT_HALLUCINATION = initial(contaminant_control.CONTAMINANT_HALLUCINATION) + contaminant_control.N2O_HALLUCINATION = initial(contaminant_control.N2O_HALLUCINATION) + + + to_world("[key_name(user)] changed the global contaminant/ZAS settings to \"[def]\"") + +/contaminant_control/var/list/settings = list() + +/contaminant_control/New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) + settings -= V + + settings -= "settings" + +/contaminant_control/proc/Randomize(V) + var/newvalue + if("[V]_RANDOM" in vars) + if(isnum(vars["[V]_RANDOM"])) + newvalue = prob(vars["[V]_RANDOM"]) + else if(istext(vars["[V]_RANDOM"])) + var/txt = vars["[V]_RANDOM"] + if(findtextEx(txt,"PROB")) + txt = splittext(txt,"/") + txt[1] = replacetext(txt[1],"PROB","") + var/p = text2num(txt[1]) + var/r = txt[2] + if(prob(p)) + newvalue = roll(r) + else + newvalue = vars[V] + else if(findtextEx(txt,"PICK")) + txt = replacetext(txt,"PICK","") + txt = splittext(txt,",") + newvalue = pick(txt) + else + newvalue = roll(txt) + else + newvalue = vars[V] + vars[V] = newvalue diff --git a/code/modules/ZAS/Zone.dm b/code/modules/ZAS/Zone.dm index 8d38204ae3c3..cac84cb69bf5 100644 --- a/code/modules/ZAS/Zone.dm +++ b/code/modules/ZAS/Zone.dm @@ -12,14 +12,14 @@ Class Vars: air - The gas mixture that any turfs in this zone will return. Values are per-tile with a group multiplier. Class Procs: - add(turf/simulated/T) + add(turf/T) Adds a turf to the contents, sets its zone and merges its air. - remove(turf/simulated/T) + remove(turf/T) Removes a turf, sets its zone to null and erases any gas graphics. Invalidates the zone if it has no more tiles. - c_merge(zone/into) + c_merge(var/zone/into) Invalidates this zone and adds all its former contents to into. c_invalidate() @@ -28,7 +28,7 @@ Class Procs: rebuild() Invalidates the zone and marks all its former tiles for updates. - add_tile_air(turf/simulated/T) + add_tile_air(turf/T) Adds the air contained in T.air to the zone's air supply. Called when adding a turf. tick() @@ -45,7 +45,6 @@ Class Procs: var/invalid = 0 var/list/contents = list() var/list/fire_tiles = list() - var/list/fuel_objs = list() var/needs_update = 0 var/list/edges = list() var/datum/gas_mixture/air = new @@ -58,13 +57,14 @@ Class Procs: SSair.add_zone(src) air.temperature = TCMB air.group_multiplier = 1 - air.volume = CELL_VOLUME + air.total_volume = CELL_VOLUME -/zone/proc/add(turf/simulated/T) +/zone/proc/add(turf/T) #ifdef ZASDBG ASSERT(!invalid) ASSERT(istype(T)) - ASSERT(!SSair.has_valid_zone(T)) + ASSERT(T.zone_membership_candidate) + ASSERT(!TURF_HAS_VALID_ZONE(T)) #endif var/datum/gas_mixture/turf_air = T.return_air() @@ -74,30 +74,27 @@ Class Procs: if(T.fire) fire_tiles.Add(T) SSair.active_fire_zones |= src - var/obj/effect/fluid/fuel = T.return_fluid() - if(fuel?.get_fuel_amount()) - fuel_objs += fuel - T.update_graphic(air.graphic) + T.update_vis_contents() -/zone/proc/remove(turf/simulated/T) +/zone/proc/remove(turf/T) #ifdef ZASDBG ASSERT(!invalid) ASSERT(istype(T)) + ASSERT(T.zone_membership_candidate) ASSERT(T.zone == src) soft_assert(T in contents, "Lists are weird broseph") #endif + T.c_copy_air() // to avoid losing contents contents.Remove(T) fire_tiles.Remove(T) - if(T.fire) - fuel_objs -= T.return_fluid() T.zone = null - T.update_graphic(graphic_remove = air.graphic) + T.update_vis_contents() if(contents.len) air.group_multiplier = contents.len else c_invalidate() -/zone/proc/c_merge(zone/into) +/zone/proc/c_merge(var/zone/into) #ifdef ZASDBG ASSERT(!invalid) ASSERT(istype(into)) @@ -105,41 +102,41 @@ Class Procs: ASSERT(!into.invalid) #endif c_invalidate() - for(var/turf/simulated/T in contents) + for(var/turf/T as anything in contents) + if(!T.zone_membership_candidate) + continue into.add(T) - T.update_graphic(graphic_remove = air.graphic) + T.update_vis_contents() #ifdef ZASDBG - T.dbg(merged) + T.dbg(zasdbgovl_merged) #endif //rebuild the old zone's edges so that they will be possessed by the new zone for(var/connection_edge/E in edges) if(E.contains_zone(into)) continue //don't need to rebuild this edge - for(var/turf/T in E.connecting_turfs) - SSair.mark_for_update(T) + E.update_post_merge() /zone/proc/c_invalidate() invalid = 1 SSair.remove_zone(src) #ifdef ZASDBG - for(var/turf/simulated/T in contents) - T.dbg(invalid_zone) + for(var/turf/T as anything in contents) + T.dbg(zasdbgovl_invalid_zone) #endif /zone/proc/rebuild() set waitfor = 0 if(invalid) return //Short circuit for explosions where rebuild is called many times over. c_invalidate() - for(var/turf/simulated/T in contents) - T.update_graphic(graphic_remove = air.graphic) //we need to remove the overlays so they're not doubled when the zone is rebuilt - //T.dbg(invalid_zone) + for(var/turf/T as anything in contents) + T.update_vis_contents() T.needs_air_update = 0 //Reset the marker so that it will be added to the list. SSair.mark_for_update(T) CHECK_TICK /zone/proc/add_tile_air(datum/gas_mixture/tile_air) - //air.volume += CELL_VOLUME + //air.total_volume += CELL_VOLUME air.group_multiplier = 1 air.multiply(contents.len) air.merge(tile_air) @@ -150,15 +147,15 @@ Class Procs: // Update fires. if(air.temperature >= FLAMMABLE_GAS_FLASHPOINT && !(src in SSair.active_fire_zones) && air.check_combustibility() && contents.len) - var/turf/T = pick(contents) if(istype(T)) T.create_fire(vsc.fire_firelevel_multiplier) // Update gas overlays. if(air.check_tile_graphic(graphic_add, graphic_remove)) - for(var/turf/simulated/T in contents) - T.update_graphic(graphic_add, graphic_remove) + for(var/turf/T as anything in contents) + T.update_vis_contents() + CHECK_TICK graphic_add.len = 0 graphic_remove.len = 0 @@ -166,6 +163,7 @@ Class Procs: for(var/connection_edge/E in edges) if(E.sleeping) E.recheck() + CHECK_TICK // Handle condensation from the air. if(!condensing) @@ -174,19 +172,17 @@ Class Procs: // Update atom temperature. if(abs(air.temperature - last_air_temperature) >= ATOM_TEMPERATURE_EQUILIBRIUM_THRESHOLD) last_air_temperature = air.temperature - for(var/turf/simulated/T in contents) - for(var/check_atom in T.contents) - var/atom/checking = check_atom - if(checking.simulated) - QUEUE_TEMPERATURE_ATOMS(checking) + for(var/turf/T as anything in contents) + for(var/atom/check_atom as anything in T.contents) + QUEUE_TEMPERATURE_ATOM(check_atom) CHECK_TICK /zone/proc/handle_condensation() set waitfor = FALSE condensing = TRUE for(var/g in air.gas) - var/decl/material/mat = decls_repository.get_decl(g) - if(air.temperature <= mat.gas_condensation_point) + var/decl/material/mat = GET_DECL(g) + if(!isnull(mat.gas_condensation_point) && (air.temperature <= mat.gas_condensation_point)) var/condensation_area = air.group_multiplier / length(air.gas) while(condensation_area > 0 && length(contents)) condensation_area-- @@ -195,22 +191,19 @@ Class Procs: if(condense_amt < 1) break air.adjust_gas(g, -condense_amt) - var/obj/effect/fluid/F = locate() in flooding - if(!F) F = new(flooding) - F.reagents.add_reagent(g, condense_amt * REAGENT_UNITS_PER_GAS_MOLE) - CHECK_TICK + flooding.add_to_reagents(g, condense_amt * REAGENT_UNITS_PER_GAS_MOLE) + CHECK_TICK condensing = FALSE /zone/proc/dbg_data(mob/M) to_chat(M, name) for(var/g in air.gas) - var/decl/material/mat = decls_repository.get_decl(g) + var/decl/material/mat = GET_DECL(g) to_chat(M, "[capitalize(mat.gas_name)]: [air.gas[g]]") - to_chat(M, "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)") + to_chat(M, "P: [air.return_pressure()] kPa V: [air.total_volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)") to_chat(M, "O2 per N2: [(air.gas[/decl/material/gas/nitrogen] ? air.gas[/decl/material/gas/oxygen]/air.gas[/decl/material/gas/nitrogen] : "N/A")] Moles: [air.total_moles]") to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])") -// to_chat(M, "Unsimulated: [unsimulated_contents.len]") -// to_chat(M, "Edges: [edges.len]") + to_chat(M, "Edges: [length(edges)]") if(invalid) to_chat(M, "Invalid!") var/zone_edges = 0 var/space_edges = 0 diff --git a/code/modules/abstract/_abstract.dm b/code/modules/abstract/_abstract.dm new file mode 100644 index 000000000000..9f944be9cb33 --- /dev/null +++ b/code/modules/abstract/_abstract.dm @@ -0,0 +1,23 @@ +/obj/abstract + name = "" + icon = 'icons/effects/landmarks.dmi' + icon_state = "x2" + simulated = FALSE + density = FALSE + anchored = TRUE + abstract_type = /obj/abstract + invisibility = INVISIBILITY_ABSTRACT + var/hide_on_init = TRUE + +/obj/abstract/Initialize() + . = ..() + verbs.Cut() + opacity = FALSE + //Let mappers see the damn thing by just making them invisible here + if(hide_on_init) + alpha = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + +/obj/abstract/explosion_act() + SHOULD_CALL_PARENT(FALSE) + return diff --git a/code/modules/abstract/abstract_exterior_marker.dm b/code/modules/abstract/abstract_exterior_marker.dm new file mode 100644 index 000000000000..03b954b9ac31 --- /dev/null +++ b/code/modules/abstract/abstract_exterior_marker.dm @@ -0,0 +1,29 @@ +/obj/abstract/exterior_marker + abstract_type = /obj/abstract/exterior_marker + var/set_outside + +/obj/abstract/exterior_marker/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/abstract/exterior_marker/LateInitialize() + var/turf/T = loc + if(istype(T)) + if(T.atom_flags & ATOM_FLAG_INITIALIZED) + T.set_outside(set_outside) + else + T.is_outside = set_outside + T.last_outside_check = OUTSIDE_UNCERTAIN + qdel(src) + +/obj/abstract/exterior_marker/outside + name = "Outside" + set_outside = OUTSIDE_YES + +/obj/abstract/exterior_marker/inside + name = "Inside" + set_outside = OUTSIDE_NO + +/obj/abstract/exterior_marker/use_area + name = "Use Area Outside" + set_outside = OUTSIDE_AREA diff --git a/code/modules/abstract/abstract_fluid_direction.dm b/code/modules/abstract/abstract_fluid_direction.dm new file mode 100644 index 000000000000..7dabaa77623e --- /dev/null +++ b/code/modules/abstract/abstract_fluid_direction.dm @@ -0,0 +1,37 @@ +/obj/abstract/force_fluid_flow + icon_state = "arrow" + +/obj/abstract/force_fluid_flow/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/abstract/force_fluid_flow/north + dir = NORTH + +/obj/abstract/force_fluid_flow/south + dir = SOUTH + +/obj/abstract/force_fluid_flow/east + dir = EAST + +/obj/abstract/force_fluid_flow/west + dir = WEST + +/obj/abstract/force_fluid_flow/southeast + dir = SOUTHEAST + +/obj/abstract/force_fluid_flow/southwest + dir = SOUTHWEST + +/obj/abstract/force_fluid_flow/northeast + dir = NORTHEAST + +/obj/abstract/force_fluid_flow/northwest + dir = NORTHWEST + +/obj/abstract/force_fluid_flow/LateInitialize() + . = ..() + var/atom/movable/fluid_overlay/fluids = locate() in loc + fluids.force_flow_direction = dir + fluids.queue_icon_update() + qdel(src) diff --git a/code/modules/abstract/abstract_ramp_sculptor.dm b/code/modules/abstract/abstract_ramp_sculptor.dm new file mode 100644 index 000000000000..8732dade30b5 --- /dev/null +++ b/code/modules/abstract/abstract_ramp_sculptor.dm @@ -0,0 +1,39 @@ +/obj/abstract/ramp_sculptor + name = "ramp sculptor" + icon_state = "x" + var/place_dir + +/obj/abstract/ramp_sculptor/south + icon_state = "arrow" + dir = SOUTH + place_dir = SOUTH + +/obj/abstract/ramp_sculptor/north + icon_state = "arrow" + dir = NORTH + place_dir = NORTH + +/obj/abstract/ramp_sculptor/east + icon_state = "arrow" + dir = EAST + place_dir = EAST + +/obj/abstract/ramp_sculptor/west + icon_state = "arrow" + dir = WEST + place_dir = WEST + +/obj/abstract/ramp_sculptor/Initialize() + ..() + var/turf/wall/natural/ramp = get_turf(src) + if(istype(ramp) && !ramp.ramp_slope_direction) + if(!place_dir || !(place_dir in global.cardinal)) + for(var/checkdir in global.cardinal) + var/turf/neighbor = get_step(ramp, checkdir) + if(neighbor && neighbor.density) + place_dir = global.reverse_dir[checkdir] + break + if(place_dir) + dir = place_dir + ramp.make_ramp(null, place_dir) + return INITIALIZE_HINT_QDEL diff --git a/code/modules/abstract/airlock_helper.dm b/code/modules/abstract/airlock_helper.dm new file mode 100644 index 000000000000..0dd25032a27d --- /dev/null +++ b/code/modules/abstract/airlock_helper.dm @@ -0,0 +1,151 @@ +/* +Note that these have to be within range of world.view (7 tiles), centered on the controller for them to function. +You still need to set the controller's "id_tag" to something unique. +*/ +/obj/abstract/airlock_helper + icon = 'icons/effects/airlock_helper.dmi' + abstract_type = /obj/abstract/airlock_helper + is_spawnable_type = FALSE + layer = ABOVE_DOOR_LAYER + /// The controller we're using. Set to a type to locate the type during Initialize(). + var/obj/machinery/embedded_controller/radio/my_controller = /obj/machinery/embedded_controller/radio/airlock + /// The device we're setting up. Set to a type to locate the type during Initialize(). + var/my_device + /// Adjusts the various radio tags used to configure airlock devices. + var/tag_addon + +/obj/abstract/airlock_helper/Initialize() + ..() + my_controller = get_controller() + if(!my_controller) + log_error("Airlock helper '[name]' couldn't find a controller at: X:[x] Y:[y] Z:[z]") + return INITIALIZE_HINT_QDEL + + if(!my_controller.id_tag) + log_error("Airlock helper '[name]' found a controller without an 'id_tag' set: X:[x] Y:[y] Z:[z]") + return INITIALIZE_HINT_QDEL + + my_device = locate(my_device) in loc + if(!my_device) + log_error("Airlock helper '[name]' couldn't find the device it wanted at: X:[x] Y:[y] Z:[z]") + return INITIALIZE_HINT_QDEL + + configure_associated_device() + return INITIALIZE_HINT_QDEL + +/obj/abstract/airlock_helper/Destroy() + my_controller = null + my_device = null + return ..() + +/obj/abstract/airlock_helper/proc/get_controller() + var/closest_distance = INFINITY + for(var/obj/O in range(world.view, src)) + if(istype(O, my_controller)) + if(!.) + . = O + else + var/check_distance = get_dist(src, O) + if(check_distance < closest_distance) + closest_distance = check_distance + . = O + +/// Stub for subtypes to override to deal with their specific devices. +/obj/abstract/airlock_helper/proc/configure_associated_device() + return + +/* + Doors +*/ +/obj/abstract/airlock_helper/door + name = "use a subtype! - airlock door" + my_device = /obj/machinery/door/airlock + +/obj/abstract/airlock_helper/door/configure_associated_device() + var/obj/machinery/door/airlock/my_airlock = my_device + my_airlock.lock() + my_airlock.set_id_tag(my_controller.id_tag + tag_addon) + for(var/obj/item/stock_parts/radio/R in my_airlock.get_all_components_of_type(/obj/item/stock_parts/radio)) + R.set_id_tag(my_controller.id_tag + tag_addon) + +/obj/abstract/airlock_helper/door/ext_door + name = "exterior airlock door" + icon_state = "doorout" + tag_addon = "_outer" + +/obj/abstract/airlock_helper/door/int_door + name = "interior airlock door" + icon_state = "doorin" + tag_addon = "_inner" + +/obj/abstract/airlock_helper/door/simple + name = "simple docking controller hatch" + icon_state = "doorsimple" + tag_addon = "_hatch" + my_controller = /obj/machinery/embedded_controller/radio/simple_docking_controller + + +/* + Atmos +*/ +/obj/abstract/airlock_helper/atmos + name = "use a subtype! - airlock pump" + my_device = /obj/machinery/atmospherics/unary/vent_pump + +/obj/abstract/airlock_helper/atmos/configure_associated_device() + var/obj/machinery/atmospherics/unary/vent_pump/my_pump = my_device + my_pump.set_id_tag(my_controller.id_tag + tag_addon) + for(var/obj/item/stock_parts/radio/R in my_pump.get_all_components_of_type(/obj/item/stock_parts/radio)) + R.set_id_tag(my_controller.id_tag + tag_addon) + +/obj/abstract/airlock_helper/atmos/chamber_pump + name = "chamber pump" + icon_state = "pump" + tag_addon = "_pump" + +/obj/abstract/airlock_helper/atmos/pump_out_internal + name = "air dump intake" + icon_state = "pumpdin" + tag_addon = "_pump_out_internal" + +/obj/abstract/airlock_helper/atmos/pump_out_external + name = "air dump output" + icon_state = "pumpdout" + tag_addon = "_pump_out_external" + + +/* + Sensors +*/ +/obj/abstract/airlock_helper/sensor + my_device = /obj/machinery/airlock_sensor + +/obj/abstract/airlock_helper/sensor/configure_associated_device() + var/obj/machinery/airlock_sensor/my_sensor = my_device + my_sensor.set_id_tag(my_controller.id_tag + tag_addon) + +/obj/abstract/airlock_helper/sensor/ext_sensor + name = "exterior sensor" + icon_state = "sensout" + tag_addon = "_exterior_sensor" + +/obj/abstract/airlock_helper/sensor/chamber_sensor + name = "chamber sensor" + icon_state = "sens" + tag_addon = "_sensor" + +/obj/abstract/airlock_helper/sensor/int_sensor + name = "interior sensor" + icon_state = "sensin" + tag_addon = "_interior_sensor" + +/* + Buttons - at one point in time, sensors also worked as buttons, but now that isn't the case. +*/ +/obj/abstract/airlock_helper/button + my_device = /obj/machinery/button/access + icon_state = "button" + +/obj/abstract/airlock_helper/button/configure_associated_device() + var/obj/machinery/button/access/my_button = my_device + my_button.set_id_tag(my_controller.id_tag) \ No newline at end of file diff --git a/code/modules/abstract/corpse_spawner.dm b/code/modules/abstract/corpse_spawner.dm new file mode 100644 index 000000000000..c7b3197e5c95 --- /dev/null +++ b/code/modules/abstract/corpse_spawner.dm @@ -0,0 +1,147 @@ +#define CORPSE_SPAWNER_RANDOM_NAME BITFLAG(0) +#define CORPSE_SPAWNER_CUT_SURVIVAL BITFLAG(1) +#define CORPSE_SPAWNER_CUT_ID_PDA BITFLAG(2) +#define CORPSE_SPAWNER_PLAIN_HEADSET BITFLAG(3) +#define CORPSE_SPAWNER_RANDOM_SKIN_TONE BITFLAG(4) +#define CORPSE_SPAWNER_RANDOM_SKIN_COLOR BITFLAG(5) +#define CORPSE_SPAWNER_RANDOM_HAIR_COLOR BITFLAG(6) +#define CORPSE_SPAWNER_RANDOM_HAIR_STYLE BITFLAG(7) +#define CORPSE_SPAWNER_RANDOM_FACIAL_STYLE BITFLAG(8) +#define CORPSE_SPAWNER_RANDOM_EYE_COLOR BITFLAG(9) +#define CORPSE_SPAWNER_RANDOM_GENDER BITFLAG(10) + +#define CORPSE_SPAWNER_NO_RANDOMIZATION ~(CORPSE_SPAWNER_RANDOM_NAME|CORPSE_SPAWNER_RANDOM_SKIN_TONE|CORPSE_SPAWNER_RANDOM_SKIN_COLOR|CORPSE_SPAWNER_RANDOM_HAIR_COLOR|CORPSE_SPAWNER_RANDOM_HAIR_STYLE|CORPSE_SPAWNER_RANDOM_FACIAL_STYLE|CORPSE_SPAWNER_RANDOM_EYE_COLOR) + + +/obj/abstract/landmark/corpse + name = "Unknown" + abstract_type = /obj/abstract/landmark/corpse + var/species // List of species to pick from. + var/corpse_outfits = list(/decl/outfit) // List of outfits to pick from. Uses pickweight() + var/spawn_flags = (~0) + var/weakref/my_corpse + + var/skin_colors_per_species = list() // Custom skin colors, per species -type-, if any. For example if you want dead aliens to always have blue hair, or similar + var/skin_tones_per_species = list() // Custom skin tones, per species -type-, if any. See above as to why. + var/eye_colors_per_species = list() // Custom eye colors, per species -type-, if any. See above as to why. + var/hair_colors_per_species = list() // Custom hair colors, per species -type-, if any. See above as to why. + var/hair_styles_per_species = list() // Custom hair styles, per species -type-, if any. For example if you want a punk gang with handlebars. + var/facial_styles_per_species = list() // Custom facial hair styles, per species -type-, if any. See above as to why + var/genders_per_species = list() // For gender biases per species -type- + +/obj/abstract/landmark/corpse/Initialize() + ..() + if(!species) + species = global.using_map.default_species + var/species_choice = islist(species) ? pickweight(species) : species + my_corpse = weakref(new /mob/living/human/corpse(loc, species_choice, null, src)) + return INITIALIZE_HINT_QDEL + +/obj/abstract/landmark/corpse/proc/randomize_appearance(var/mob/living/human/M, species_choice) + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_GENDER)) + if(species_choice in genders_per_species) + M.set_gender(pick(genders_per_species[species_choice]), TRUE) + else + M.randomize_gender() + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_SKIN_TONE)) + if(species_choice in skin_tones_per_species) + M.change_skin_tone(pick(skin_tones_per_species[species_choice])) + else + M.randomize_skin_tone() + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_SKIN_COLOR)) + if(species_choice in skin_colors_per_species) + M.set_skin_colour(pick(skin_colors_per_species[species_choice])) + else + M.randomize_skin_color() + + var/decl/species/species_decl = decls_repository.get_decl_by_id(species_choice) + var/decl/bodytype/root_bodytype = M.get_bodytype() + var/update_hair = FALSE + if((spawn_flags & CORPSE_SPAWNER_RANDOM_HAIR_COLOR)) + if(species_choice in hair_colors_per_species) + SET_HAIR_COLOR(M, pick(hair_colors_per_species[species_choice]), TRUE) + else + SET_HAIR_COLOR(M, get_random_colour(), TRUE) + SET_FACIAL_HAIR_COLOR(M, GET_HAIR_COLOR(M), TRUE) + update_hair = TRUE + if((spawn_flags & CORPSE_SPAWNER_RANDOM_HAIR_STYLE)) + if(species_choice in hair_styles_per_species) + SET_HAIR_STYLE(M, pick(hair_styles_per_species[species_choice]), TRUE) + else + SET_HAIR_STYLE(M, pick(species_decl.get_available_accessory_types(root_bodytype, SAC_HAIR)), TRUE) + update_hair = TRUE + if((spawn_flags & CORPSE_SPAWNER_RANDOM_FACIAL_STYLE)) + if(species_choice in facial_styles_per_species) + SET_FACIAL_HAIR_STYLE(M, pick(facial_styles_per_species[species_choice]), TRUE) + else + SET_FACIAL_HAIR_STYLE(M, pick(species_decl.get_available_accessory_types(root_bodytype, SAC_FACIAL_HAIR)), TRUE) + update_hair = TRUE + if(update_hair) + M.update_hair() + + if((spawn_flags & CORPSE_SPAWNER_RANDOM_EYE_COLOR)) + if(species_choice in eye_colors_per_species) + M.set_eye_colour(pick(eye_colors_per_species[species_choice])) + else + M.randomize_eye_color() + + var/decl/background_detail/background = M.get_background_datum_by_flag(BACKGROUND_FLAG_NAMING) + if(background && CORPSE_SPAWNER_RANDOM_NAME & spawn_flags) + M.SetName(background.get_random_cultural_name(M, M.gender, M.get_species())) + else + M.SetName(name) + M.real_name = M.name + +/obj/abstract/landmark/corpse/proc/equip_corpse_outfit(var/mob/living/human/M) + var/adjustments = 0 + adjustments = (spawn_flags & CORPSE_SPAWNER_CUT_SURVIVAL) ? (adjustments|OUTFIT_ADJUSTMENT_SKIP_SURVIVAL_GEAR) : adjustments + adjustments = (spawn_flags & CORPSE_SPAWNER_CUT_ID_PDA) ? (adjustments|OUTFIT_ADJUSTMENT_SKIP_ID_PDA) : adjustments + adjustments = (spawn_flags & CORPSE_SPAWNER_PLAIN_HEADSET) ? (adjustments|OUTFIT_ADJUSTMENT_PLAIN_HEADSET) : adjustments + + var/decl/outfit/corpse_outfit = GET_DECL(pickweight(corpse_outfits)) + corpse_outfit.equip_outfit(M, equip_adjustments = adjustments) + +/obj/abstract/landmark/corpse/pirate + name = "Pirate" + corpse_outfits = list(/decl/outfit/pirate/norm) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION + +/obj/abstract/landmark/corpse/pirate/ranged + name = "Pirate Gunner" + corpse_outfits = list(/decl/outfit/pirate/space) + +/obj/abstract/landmark/corpse/russian + name = "Russian" + corpse_outfits = list(/decl/outfit/soviet_soldier) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION + +/obj/abstract/landmark/corpse/russian/ranged + corpse_outfits = list(/decl/outfit/soviet_soldier) + +/obj/abstract/landmark/corpse/syndicate + name = "Syndicate Operative" + corpse_outfits = list(/decl/outfit/mercenary/syndicate) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION + +/obj/abstract/landmark/corpse/syndicate/commando + name = "Syndicate Commando" + corpse_outfits = list(/decl/outfit/mercenary/syndicate/commando) + +/obj/abstract/landmark/corpse/chef + name = "Chef" + corpse_outfits = list(/decl/outfit/job/generic/chef) + +/obj/abstract/landmark/corpse/doctor + name = "Doctor" + corpse_outfits = list(/decl/outfit/job/generic/doctor) + +/obj/abstract/landmark/corpse/engineer + name = "Engineer" + corpse_outfits = list(/decl/outfit/job/generic/engineer) + +/obj/abstract/landmark/corpse/scientist + name = "Scientist" + corpse_outfits = list(/decl/outfit/job/generic/scientist) diff --git a/code/modules/abstract/follower.dm b/code/modules/abstract/follower.dm new file mode 100644 index 000000000000..42611d1131d2 --- /dev/null +++ b/code/modules/abstract/follower.dm @@ -0,0 +1,18 @@ +// Simple obj for following another obj around (for light effects or such that need a physical reference) +/obj/abstract/follower + anchored = TRUE + simulated = FALSE + invisibility = INVISIBILITY_ABSTRACT + +/obj/abstract/follower/Initialize() + . = ..() + name = "" + verbs.Cut() + +/obj/abstract/follower/proc/follow_owner(atom/movable/owner) + if(istype(owner) && !QDELETED(owner)) + set_dir(owner.dir) + if(owner.loc) + forceMove(owner.loc) + else + forceMove(null) diff --git a/code/modules/acting/acting_items.dm b/code/modules/acting/acting_items.dm index aec9588cead6..daa5ba77f187 100644 --- a/code/modules/acting/acting_items.dm +++ b/code/modules/acting/acting_items.dm @@ -1,45 +1,51 @@ /obj/machinery/acting/wardrobe name = "wardrobe dispenser" desc = "A machine that dispenses holo-clothing for those in need." - icon = 'icons/obj/vending.dmi' - icon_state = "cart" - anchored = 1 - density = 1 + icon = 'icons/obj/machines/vending/cartridges.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE var/active = 1 /obj/machinery/acting/wardrobe/attack_hand(var/mob/user) + SHOULD_CALL_PARENT(FALSE) user.show_message("You push a button and watch patiently as the machine begins to hum.") if(active) - active = 0 - spawn(30) - new /obj/item/storage/backpack/chameleon/sydie_kit(src.loc) - src.visible_message("\The [src] beeps, dispensing a small box onto the floor.", "You hear a beeping sound followed by a thumping noise of some kind.") - active = 1 + active = FALSE + addtimer(CALLBACK(src, PROC_REF(dispense)), 3 SECONDS) + return TRUE + +/obj/machinery/acting/wardrobe/proc/dispense() + new /obj/item/backpack/chameleon/sydie_kit(src.loc) + src.visible_message("\The [src] beeps, dispensing a small box onto the floor.", "You hear a beeping sound followed by a thumping noise of some kind.") + active = TRUE /obj/machinery/acting/changer name = "Quickee's Plastic Surgeon" desc = "For when you need to be someone else right now." - icon = 'icons/obj/surgery.dmi' + icon = 'icons/obj/machines/fabricators/bioprinter.dmi' icon_state = "bioprinter" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE /obj/machinery/acting/changer/attack_hand(var/mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.change_appearance(APPEARANCE_ALL, H.loc, H, H.generate_valid_species(), state = GLOB.z_state) - var/getName = sanitize(input(H, "Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) - if(getName) - H.real_name = getName - H.SetName(getName) - H.dna.real_name = getName - if(H.mind) - H.mind.name = H.name + SHOULD_CALL_PARENT(FALSE) + if(!ishuman(user)) + return ..() + var/mob/living/human/H = user + H.change_appearance(APPEARANCE_ALL, H.loc, H, state = global.z_topic_state) + var/getName = sanitize(input(H, "Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) + if(getName) + H.real_name = getName + H.SetName(getName) + if(H.mind) + H.mind.name = H.name + return TRUE /obj/machinery/acting/changer/mirror name = "Mirror of Many Faces" desc = "For when you need to be someone else right now." icon = 'icons/obj/watercloset.dmi' icon_state = "mirror_broke" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index bfa56208626c..8294312ba594 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -1,5 +1,6 @@ //Blocks an attempt to connect before even creating our client datum thing. /world/IsBanned(key, address, computer_id, type) + var/static/key_cache = list() if(type == "world") return ..() @@ -10,24 +11,29 @@ var/ckeytext = ckey(key) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_CONNECT_WHITELIST && !check_server_whitelist(ckeytext)) + log_access("Failed Login: [key] - Not server whitelisted") + message_admins("Failed Login: [key] - Not server whitelisted") + return list("reason"="whitelist", "desc"="\nReason: This server requires players to be whitelisted to join.") + if(admin_datums[ckeytext]) key_cache[key] = 0 return ..() //Guest Checking - if(!config.guests_allowed && IsGuestKey(key)) + if(!get_config_value(/decl/config/toggle/guests_allowed) && IsGuestKey(key)) log_access("Failed Login: [key] - Guests not allowed") message_admins("Failed Login: [key] - Guests not allowed") key_cache[key] = 0 - return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.") + return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a BYOND account.") - var/client/C = GLOB.ckey_directory[ckeytext] + var/client/C = global.ckey_directory[ckeytext] //If this isn't here, then topic call spam will result in all clients getting kicked with a connecting too fast error. if (C && ckeytext == C.ckey && address == C.address && computer_id == C.computer_id) key_cache[key] = 0 return - if(config.ban_legacy_system) + if(get_config_value(/decl/config/toggle/on/ban_legacy_system)) //Ban Checking . = CheckBan(ckeytext, computer_id, address) @@ -77,8 +83,9 @@ var/bantype = query.item[9] var/expires = "" + var/mins_readable = minutes_to_readable(duration) if(text2num(duration) > 0) - expires = " The ban is for [duration] minutes and expires on [expiration] (server time)." + expires = " The ban is for [mins_readable] and expires on [expiration] (server time)." var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime], [expires]" diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index f49de3648348..ecfb5bd522fe 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -1,5 +1,5 @@ -var/CMinutes = null -var/savefile/Banlist +var/global/CMinutes = null +var/global/savefile/Banlist /proc/CheckBan(var/ckey, var/id, var/address) @@ -10,8 +10,9 @@ var/savefile/Banlist . = list() var/appeal - if(config && config.banappeals) - appeal = "\nFor more information on your ban, or to appeal, head to [config.banappeals]" + var/appealurl = get_config_value(/decl/config/text/banappeals) + if(appealurl) + appeal = "\nFor more information on your ban, or to appeal, head to [appealurl]" Banlist.cd = "/base" if( "[ckey][id]" in Banlist.dir ) Banlist.cd = "[ckey][id]" @@ -58,9 +59,6 @@ var/savefile/Banlist CMinutes = (world.realtime / 10) / 60 return 1 -/hook/startup/proc/loadBans() - return LoadBans() - /proc/LoadBans() Banlist = new("data/banlist.bdb") @@ -114,14 +112,14 @@ var/savefile/Banlist else Banlist.dir.Add("[ckey][computerid]") Banlist.cd = "/base/[ckey][computerid]" - Banlist["key"] << ckey - Banlist["id"] << computerid - Banlist["ip"] << address - Banlist["reason"] << reason - Banlist["bannedby"] << bannedby - Banlist["temp"] << temp + to_savefile(Banlist, "key", ckey) + to_savefile(Banlist, "id", computerid) + to_savefile(Banlist, "ip", address) + to_savefile(Banlist, "reason", reason) + to_savefile(Banlist, "bannedby", bannedby) + to_savefile(Banlist, "temp", temp) if (temp) - Banlist["minutes"] << bantimestamp + to_savefile(Banlist, "minutes", bantimestamp) return 1 /proc/RemoveBan(foldername) @@ -129,8 +127,8 @@ var/savefile/Banlist var/id Banlist.cd = "/base/[foldername]" - Banlist["key"] >> key - Banlist["id"] >> id + from_savefile(Banlist, "key", key) + from_savefile(Banlist, "id", id) Banlist.cd = "/base" if (!Banlist.dir.Remove(foldername)) return 0 @@ -188,7 +186,7 @@ var/savefile/Banlist if(!expiry) expiry = "Removal Pending" else expiry = "Permaban" - dat += text("
              (U)(E) Key: [key]ComputerID: [id]IP: [ip] [expiry](By: [by])(Reason: [reason])
              (U)(E) Key: [key]ComputerID: [id]IP: [ip] [expiry](By: [by])(Reason: [reason])
              " dat = "
              Bans: (U) = Unban , (E) = Edit Ban - ([count] Bans)
              [dat]" @@ -210,17 +208,19 @@ var/savefile/Banlist Banlist.cd = "/base" Banlist.dir.Add("trash[i]trashid[i]") Banlist.cd = "/base/trash[i]trashid[i]" - Banlist["key"] << "trash[i]" + to_savefile(Banlist, "key", "trash[i]") else Banlist.cd = "/base" Banlist.dir.Add("[last]trashid[i]") Banlist.cd = "/base/[last]trashid[i]" - Banlist["key"] << last - Banlist["id"] << "trashid[i]" - Banlist["reason"] << "Trashban[i]." - Banlist["temp"] << a - Banlist["minutes"] << CMinutes + rand(1,2000) - Banlist["bannedby"] << "trashmin" + to_savefile(Banlist, "key", last) + + to_savefile(Banlist, "id", "trashid[i]") + to_savefile(Banlist, "reason", "Trashban[i].") + to_savefile(Banlist, "temp", a) + to_savefile(Banlist, "minutes", CMinutes + rand(1,2000)) + to_savefile(Banlist, "bannedby", "trashmin") + last = "trash[i]" Banlist.cd = "/base" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index b28bd823c7b3..f1726ee6ac05 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1,33 +1,46 @@ var/global/BSACooldown = 0 -var/global/floorIsLava = 0 //////////////////////////////// /proc/message_admins(var/msg) msg = "ADMIN LOG: [msg]" log_adminwarn(msg) - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(R_ADMIN & C.holder.rights) to_chat(C, msg) /proc/message_staff(var/msg) msg = "STAFF LOG: [msg]" log_adminwarn(msg) - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(C && C.holder && (R_INVESTIGATE & C.holder.rights)) to_chat(C, msg) /proc/msg_admin_attack(var/text) //Toggleable Attack Messages log_attack(text) var/rendered = "ATTACK: [text]" - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(check_rights(R_INVESTIGATE, 0, C)) - if(C.get_preference_value(/datum/client_preference/staff/show_attack_logs) == GLOB.PREF_SHOW) + if(C.get_preference_value(/datum/client_preference/staff/show_attack_logs) == PREF_SHOW) var/msg = rendered to_chat(C, msg) /proc/admin_notice(var/message, var/rights) for(var/mob/M in SSmobs.mob_list) if(check_rights(rights, 0, M)) to_chat(M, message) + +/proc/message_staff_fax(var/obj/item/paper/admin/fax, var/obj/machinery/faxmachine/destination, var/owner, var/dest_network_id = "UNKNOWN", var/dest_network_tag = "UNKNOWN") + var/msg + if(fax.sender) + msg = "FAX LOG:[key_name_admin(owner)] replied to a fax message from [key_name_admin(fax.sender)] (VIEW)" + log_admin("[key_name(owner)] replied to a fax message from [key_name(fax.sender)]") + else + msg = "FAX LOG:[key_name_admin(owner)] has sent a fax message to \the [get_area(fax)]'s [destination] ('[dest_network_id]'.'[dest_network_tag]')(VIEW)" + log_admin("[key_name(owner)] has sent a fax message to \the [get_area(fax)]'s [destination] ('[dest_network_id]'.'[dest_network_tag]')") + + for(var/client/C in global.admins) + if(C && C.holder && (R_INVESTIGATE & C.holder.rights)) + to_chat(C, msg) + ///////////////////////////////////////////////////////////////////////////////////////////////Panels /datum/admins/proc/show_player_panel(var/mob/M in SSmobs.mob_list) @@ -49,63 +62,62 @@ var/global/floorIsLava = 0 var/last_ckey = LAST_CKEY(M) if(M.client) body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" else if(last_ckey) body += " (last occupied by ckey [last_ckey])" - if(istype(M, /mob/new_player)) + if(isnewplayer(M)) body += " Hasn't Entered Game " else - body += " \[Heal\] " + body += " \[Heal\] " var/mob/living/exosuit/E = M if(istype(E) && E.pilots) body += "
              Exosuit pilots:
              " for(var/mob/living/pilot in E.pilots) body += "[pilot] " - body += " \[link\]
              " + body += " \[link\]
              " body += {"

              \[ - VV - - TP - - PM - - DN - + View Vars - + Roles - + PM - + Narrate - [admin_jump_link(M, src)]\]
              Mob type: [M.type]
              Inactivity time: [M.client ? "[M.client.inactivity/600] minutes" : "Logged out"]

              - Kick | - Warn | - Ban | - Jobban | - Notes + Kick | + Warn | + Ban | + Jobban | + Notes "} if(M.client) - body += "| Prison | " + body += "| Prison | " var/muted = M.client.prefs.muted body += {"
              Mute: - \[IC | - OOC | - AOOC | - PRAY | - ADMINHELP | - DEADCHAT\] - (toggle all) + \[IC | + OOC | + AOOC | + PRAY | + ADMINHELP | + DEADCHAT\] + (toggle all) "} body += "

              Staff Warning: [M.client.staffwarn ? M.client.staffwarn : "No"]
              " if (!M.client.staffwarn) - body += "Set StaffWarn" + body += "Set StaffWarn" else - body += "Remove StaffWarn" + body += "Remove StaffWarn" body += {"

              - Jump to | - Get | - Send To + Jump to | + Get | + Send To

              - [check_rights(R_ADMIN|R_MOD,0) ? "Traitor panel | " : "" ] - [check_rights(R_INVESTIGATE,0) ? "Skill panel" : "" ] + [check_rights(R_INVESTIGATE,0) ? "Skill panel" : "" ] "} if(M.mind) @@ -114,7 +126,7 @@ var/global/floorIsLava = 0 body += "
              " body += "[jointext(M.mind.summarize_goals(FALSE, TRUE, src), "
              ")]" body += "
              " - body += "Add Random Goal" + body += "Add Random Goal" var/list/all_modpacks = decls_repository.get_decls_of_subtype(/decl/modpack) for(var/package in all_modpacks) @@ -123,9 +135,9 @@ var/global/floorIsLava = 0 if(extra_body) body += "

              " body += extra_body - + if (M.client) - if(!istype(M, /mob/new_player)) + if(!isnewplayer(M)) body += "

              " body += "Transformation:" body += "
              " @@ -134,97 +146,79 @@ var/global/floorIsLava = 0 if(issmall(M)) body += "Monkeyized | " else - body += "Monkeyize | " + body += "Monkeyize | " //Corgi if(iscorgi(M)) body += "Corgized | " else - body += "Corgize | " + body += "Corgize | " //AI / Cyborg if(isAI(M)) body += "Is an AI " else if(ishuman(M)) - body += {"Make AI | - Make Robot | - Make Alien | - Make slime + body += {"Make AI | + Make Robot | + Make Alien "} //Simple Animals if(isanimal(M)) - body += "Re-Animalize | " + body += "Re-Animalize | " else - body += "Animalize | " + body += "Animalize | " - // DNA2 - Admin Hax - if(M.dna && iscarbon(M)) + if(M.can_have_genetic_conditions()) body += "

              " - body += "DNA Blocks:
              " - var/bname - for(var/block=1;block<=DNA_SE_LENGTH;block++) - if(((block-1)%5)==0) - body += "" - bname = assigned_blocks[block] - body += "" + body += "Genetic conditions:
               12345
              [block-1]" - if(bname) - var/bstate=M.dna.GetSEState(block) - var/bcolor="[(bstate)?"#006600":"#ff0000"]" - body += "[bname][block]" - else - body += "[block]" - body+="
              " + var/i = 1 + for(var/decl/genetic_condition/mutation as anything in decls_repository.get_decls_of_type_unassociated(/decl/genetic_condition)) + if(i % 5 == 0) + body += "" + body += "" + i++ body += "
              [mutation.name]
              " - body += {"

              - Rudimentary transformation:
              These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

              - Observer | - \[ Xenos: Larva - \[ Crew: Human - \[ slime: Baby, - Adult \] - Monkey | - Cyborg | - Cat | - Runtime | - Corgi | - Ian | - Crab | - Coffee | - \[ Construct: Armoured , - Builder , - Wraith \] - Shade -
              - "} + body += "

              Rudimentary transformation:
              These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

              " + + var/list/href_transform_strings = list() + for(var/href_string in global.href_to_mob_type) + var/transform_data = global.href_to_mob_type[href_string] + + // It's a category - iterate the contents. + if(islist(transform_data)) + var/list/href_subcat_strings = list() + for(var/transform_string in transform_data) + href_subcat_strings += "[transform_string]" + href_transform_strings += "\[ [href_string]: [jointext(href_subcat_strings, " | ")] \]" + + // It's a single mob type - link it directly. + else if(ispath(transform_data)) + href_transform_strings += "[href_string]" + + body += jointext(href_transform_strings, " | ") + body += {"

              Other actions:
              - Forcesay + Forcesay "} - if (M.client) - body += {" | - Thunderdome 1 | - Thunderdome 2 | - Thunderdome Admin | - Thunderdome Observer | - "} // language toggles body += "

              Languages:
              " var/f = 1 var/list/language_types = decls_repository.get_decls_of_subtype(/decl/language) for(var/k in language_types) var/decl/language/L = language_types[k] - if(!(L.flags & INNATE)) + if(!(L.flags & LANG_FLAG_INNATE)) if(!f) body += " | " else f = 0 if(L in M.languages) - body += "[L.name]" + body += "[L.name]" else - body += "[L.name]" + body += "[L.name]" body += {"
              @@ -255,7 +249,7 @@ var/global/floorIsLava = 0 dat += "Player notes
              " var/savefile/S=new("data/player_notes.sav") var/list/note_keys - S >> note_keys + from_file(S, note_keys) if(filter_term) for(var/t in note_keys) @@ -263,15 +257,15 @@ var/global/floorIsLava = 0 continue note_keys -= t - dat += "
              Search term: [filter_term ? filter_term : "-----"]

              " + dat += "
              Search term: [filter_term ? filter_term : "-----"]

              " if(!note_keys) dat += "No notes found." else dat += "" - note_keys = sortList(note_keys) + note_keys = sortTim(note_keys, /proc/cmp_text_asc) for(var/t in note_keys) - dat += "" + dat += "" dat += "
              [t]
              [t]

              " var/datum/browser/popup = new(usr, "player_notes", "Player Notes", 400, 400) @@ -282,8 +276,8 @@ var/global/floorIsLava = 0 /datum/admins/proc/player_has_info(var/key as text) var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") var/list/infos - info >> infos - if(!infos || !infos.len) return 0 + from_file(info, infos) + if(!LAZYLEN(infos)) return 0 else return 1 @@ -300,7 +294,7 @@ var/global/floorIsLava = 0 var/list/dat = list() var/p_age = "unknown" - for(var/client/C in GLOB.clients) + for(var/client/C in global.clients) if(C.ckey == key) p_age = C.player_age break @@ -308,7 +302,7 @@ var/global/floorIsLava = 0 var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") var/list/infos - info >> infos + from_file(info, infos) if(!infos) dat += "No information found on the given key.
              " else @@ -324,11 +318,12 @@ var/global/floorIsLava = 0 update_file = 1 dat += "
            • [I.content] by [I.author] ([I.rank]) on [I.timestamp] " if(I.author == usr.key || I.author == "Adminbot" || ishost(usr)) - dat += "Remove" + dat += "Remove" dat += "
            • " - if(update_file) info << infos + if(update_file) + to_file(info, infos) - dat += "

            Add Comment
            " + dat += "

          Add Comment
          " var/html = {" @@ -383,12 +378,12 @@ var/global/floorIsLava = 0
          Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things! "} if(news_network.wanted_issue) - dat+= "
          Read Wanted Issue" + dat+= "
          Read Wanted Issue" - dat+= {"

          Create Feed Channel -
          View Feed Channels -
          Submit new Feed story -

          Exit + dat+= {"

          Create Feed Channel +
          View Feed Channels +
          Submit new Feed story +

          Exit "} var/wanted_already = 0 @@ -396,50 +391,50 @@ var/global/floorIsLava = 0 wanted_already = 1 dat+={"
          Feed Security functions:
          -
          [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue -
          Censor Feed Stories -
          Mark Feed Channel with [GLOB.using_map.company_name] D-Notice (disables and locks the channel. -

          The newscaster recognises you as:
          [src.admincaster_signature]
          +
          [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue +
          Censor Feed Stories +
          Mark Feed Channel with [global.using_map.company_name] D-Notice (disables and locks the channel. +

          The newscaster recognises you as:
          [src.admincaster_signature]
          "} if(1) dat+= "Feed Channels
          " - if( isemptylist(news_network.network_channels) ) + if( !length(news_network.network_channels) ) dat+="No active channels found..." else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) if(CHANNEL.is_admin_channel) - dat+="[CHANNEL.channel_name]
          " + dat+="[CHANNEL.channel_name]
          " else - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
          " - dat+={"

          Refresh -
          Back + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
          " + dat+={"

          Refresh +
          Back "} if(2) dat+={" Creating new Feed Channel... -
          Channel Name: [src.admincaster_feed_channel.channel_name]
          - Channel Author: [src.admincaster_signature]
          - Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

          -
          Submit

          Cancel
          +
          Channel Name: [src.admincaster_feed_channel.channel_name]
          + Channel Author: [src.admincaster_signature]
          + Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

          +
          Submit

          Cancel
          "} if(3) dat+={" Creating new Feed Message... -
          Receiving Channel: [src.admincaster_feed_channel.channel_name]
          " //MARK +
          Receiving Channel: [src.admincaster_feed_channel.channel_name]
          " //MARK Message Author: [src.admincaster_signature]
          - Message Body: [src.admincaster_feed_message.body]
          -
          Submit

          Cancel
          + Message Body: [src.admincaster_feed_message.body]
          +
          Submit

          Cancel
          "} if(4) dat+={" Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].

          -
          Return
          +
          Return
          "} if(5) dat+={" Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.

          -
          Return
          +
          Return
          "} if(6) dat+="ERROR: Could not submit Feed story to Network.

          " @@ -447,7 +442,7 @@ var/global/floorIsLava = 0 dat+="Invalid receiving channel name.
          " if(src.admincaster_feed_message.body == "" || src.admincaster_feed_message.body == "\[REDACTED\]") dat+="Invalid message body.
          " - dat+="
          Return
          " + dat+="
          Return
          " if(7) dat+="ERROR: Could not submit Feed Channel to Network.

          " if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]") @@ -459,16 +454,16 @@ var/global/floorIsLava = 0 break if(check) dat+="Channel name already in use.
          " - dat+="
          Return
          " + dat+="
          Return
          " if(9) dat+="[src.admincaster_feed_channel.channel_name]: \[created by: [src.admincaster_feed_channel.author]\]
          " if(src.admincaster_feed_channel.censored) dat+={" - ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
          + ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [global.using_map.company_name] D-Notice.
          No further feed story additions are allowed while the D-Notice is in effect.

          "} else - if( isemptylist(src.admincaster_feed_channel.messages) ) + if( !length(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
          " else var/i = 0 @@ -480,68 +475,68 @@ var/global/floorIsLava = 0 dat+="

          " dat+="\[Story by [MESSAGE.author]\]
          " dat+={" -

          Refresh -
          Back +

          Refresh +
          Back "} if(10) dat+={" - [GLOB.using_map.company_name] Feed Censorship Tool
          + [global.using_map.company_name] Feed Censorship Tool
          NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
          Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.

          Select Feed channel to get Stories from:
          "} - if(isemptylist(news_network.network_channels)) + if(!length(news_network.network_channels)) dat+="No feed channels found active...
          " else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
          " - dat+="
          Cancel" + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
          " + dat+="
          Cancel" if(11) dat+={" - [GLOB.using_map.company_name] D-Notice Handler
          + [global.using_map.company_name] D-Notice Handler
          A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the [station_name()]'s morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
          "} - if(isemptylist(news_network.network_channels)) + if(!length(news_network.network_channels)) dat+="No feed channels found active...
          " else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
          " + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null ]
          " - dat+="
          Back" + dat+="
          Back" if(12) dat+={" [src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.author] \]
          - [(src.admincaster_feed_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
          + [(src.admincaster_feed_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
          "} - if( isemptylist(src.admincaster_feed_channel.messages) ) + if( !length(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
          " else for(var/datum/feed_message/MESSAGE in src.admincaster_feed_channel.messages) dat+={" -[MESSAGE.body]
          \[Story by [MESSAGE.author]\]
          - [(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
          + [(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
          "} - dat+="
          Back" + dat+="
          Back" if(13) dat+={" [src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.author] \]
          - Channel messages listed below. If you deem them dangerous to the [station_name()], you can Bestow a D-Notice upon the channel.
          + Channel messages listed below. If you deem them dangerous to the [station_name()], you can Bestow a D-Notice upon the channel.
          "} if(src.admincaster_feed_channel.censored) dat+={" - ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [GLOB.using_map.company_name] D-Notice.
          + ATTENTION: This channel has been deemed as threatening to the welfare of the [station_name()], and marked with a [global.using_map.company_name] D-Notice.
          No further feed story additions are allowed while the D-Notice is in effect.

          "} else - if( isemptylist(src.admincaster_feed_channel.messages) ) + if( !length(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
          " else for(var/datum/feed_message/MESSAGE in src.admincaster_feed_channel.messages) dat+="-[MESSAGE.body]
          \[Story by [MESSAGE.author]\]
          " - dat+="
          Back" + dat+="
          Back" if(14) dat+="Wanted Issue Handler:" var/wanted_already = 0 @@ -553,21 +548,21 @@ var/global/floorIsLava = 0 dat+="
          A wanted issue is already in Feed Circulation. You can edit or cancel it below.
          " dat+={"
          - Criminal Name: [src.admincaster_feed_message.author]
          - Description: [src.admincaster_feed_message.body]
          + Criminal Name: [src.admincaster_feed_message.author]
          + Description: [src.admincaster_feed_message.body]
          "} if(wanted_already) dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
          " else dat+="Wanted Issue will be created under prosecutor: [src.admincaster_signature]
          " - dat+="
          [(wanted_already) ? ("Edit Issue") : ("Submit")]" + dat+="
          [(wanted_already) ? ("Edit Issue") : ("Submit")]" if(wanted_already) - dat+="
          Take down Issue" - dat+="
          Cancel" + dat+="
          Take down Issue" + dat+="
          Cancel" if(15) dat+={" Wanted issue for [src.admincaster_feed_message.author] is now in Network Circulation.

          -
          Return
          +
          Return
          "} if(16) dat+="ERROR: Wanted Issue rejected by Network.

          " @@ -575,11 +570,11 @@ var/global/floorIsLava = 0 dat+="Invalid name for person wanted.
          " if(src.admincaster_feed_message.body == "" || src.admincaster_feed_message.body == "\[REDACTED\]") dat+="Invalid description.
          " - dat+="
          Return
          " + dat+="
          Return
          " if(17) dat+={" Wanted Issue successfully deleted from Circulation
          -
          Return
          +
          Return
          "} if(18) dat+={" @@ -593,11 +588,11 @@ var/global/floorIsLava = 0 dat+="
          " else dat+="None" - dat+="
          Back
          " + dat+="
          Back
          " if(19) dat+={" Wanted issue for [src.admincaster_feed_message.author] successfully edited.

          -
          Return
          +
          Return
          "} else dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" @@ -618,7 +613,7 @@ var/global/floorIsLava = 0 var/r = t if( findtext(r,"##") ) r = copytext( r, 1, findtext(r,"##") )//removes the description - dat += text("[t] (unban)") + dat += text("[t] (unban)") dat += "" show_browser(usr, dat, "window=ban;size=400x400") @@ -627,20 +622,20 @@ var/global/floorIsLava = 0 var/dat = {"
          Game Panel

          \n - Change Game Mode
          + Change Game Mode
          "} if(SSticker.master_mode == "secret") - dat += "(Force Secret Mode)
          " + dat += "(Force Secret Mode)
          " dat += {"
          - Create Object
          - Quick Create Object
          - Create Turf
          - Create Mob
          -
          Edit Airflow Settings
          - Edit Contaminant Settings
          - Choose a default ZAS setting
          + Create Object
          + Quick Create Object
          + Create Turf
          + Create Mob
          +
          Edit Airflow Settings
          + Edit Contaminant Settings
          + Choose a default ZAS setting
          "} show_browser(usr, dat, "window=admin2;size=210x280") @@ -657,7 +652,7 @@ var/global/floorIsLava = 0 if(active_category == category) dat += "[category.name]" else - dat += "[category.name] " + dat += "[category.name] " dat += "
          " // If a category is selected, print its description and then options @@ -667,7 +662,7 @@ var/global/floorIsLava = 0 for(var/datum/admin_secret_item/item in active_category.items) if(!item.can_view(usr)) continue - dat += "[item.name()]
          " + dat += "[item.name()]
          " dat += "
          " var/datum/browser/popup = new(usr, "secrets", "Secrets", 550, 500) @@ -717,12 +712,9 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Globally Toggles OOC" set name="Toggle OOC" - if(!check_rights(R_ADMIN)) return - - config.ooc_allowed = !(config.ooc_allowed) - if (config.ooc_allowed) + if (toggle_config_value(/decl/config/toggle/on/ooc_allowed)) to_world("The OOC channel has been globally enabled!") else to_world("The OOC channel has been globally disabled!") @@ -733,15 +725,12 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Globally Toggles AOOC" set name="Toggle AOOC" - if(!check_rights(R_ADMIN)) return - - config.aooc_allowed = !(config.aooc_allowed) - if (config.aooc_allowed) - to_world("The AOOC channel has been globally enabled!") + if (toggle_config_value(/decl/config/toggle/on/aooc_allowed)) + communicate_broadcast(/decl/communication_channel/aooc, "The AOOC channel has been globally enabled!", TRUE) else - to_world("The AOOC channel has been globally disabled!") + communicate_broadcast(/decl/communication_channel/aooc, "The AOOC channel has been globally disabled!", TRUE) log_and_message_admins("toggled AOOC.") SSstatistics.add_field_details("admin_verb","TAOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -752,9 +741,7 @@ var/global/floorIsLava = 0 if(!check_rights(R_ADMIN)) return - - config.looc_allowed = !(config.looc_allowed) - if (config.looc_allowed) + if (toggle_config_value(/decl/config/toggle/on/looc_allowed)) to_world("The LOOC channel has been globally enabled!") else to_world("The LOOC channel has been globally disabled!") @@ -769,9 +756,7 @@ var/global/floorIsLava = 0 if(!check_rights(R_ADMIN)) return - - config.dsay_allowed = !(config.dsay_allowed) - if (config.dsay_allowed) + if (toggle_config_value(/decl/config/toggle/on/dsay_allowed)) to_world("Deadchat has been globally enabled!") else to_world("Deadchat has been globally disabled!") @@ -782,11 +767,9 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Toggle Dead OOC." set name="Toggle Dead OOC" - if(!check_rights(R_ADMIN)) return - - config.dooc_allowed = !( config.dooc_allowed ) + toggle_config_value(/decl/config/toggle/on/dooc_allowed) log_admin("[key_name(usr)] toggled Dead OOC.") message_admins("[key_name_admin(usr)] toggled Dead OOC.", 1) SSstatistics.add_field_details("admin_verb","TDOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -800,12 +783,14 @@ var/global/floorIsLava = 0 return //BYOND hates actually changing world.visibility at runtime, so let's just change if we give it the hub password. - world.update_hub_visibility() //proc defined in hub.dm - var/long_message = "toggled hub visibility. The server is now [GLOB.visibility_pref ? "visible" : "invisible"] ([GLOB.visibility_pref])." - if (GLOB.visibility_pref && !world.reachable) + toggle_config_value(/decl/config/toggle/hub_visibility) + var/new_vis = get_config_value(/decl/config/toggle/hub_visibility) + var/long_message = "toggled hub visibility. The server is now [new_vis ? "visible" : "invisible"]." + if (new_vis && !world.reachable) message_admins("WARNING: The server will not show up on the hub because byond is detecting that a firewall is blocking incoming connections.") - send2adminirc("[key_name(src)]" + long_message) + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Hub Visibility Toggled (Game ID: [game_id])", "body" = "[key_name(src)]" + long_message)) + log_and_message_admins(long_message) SSstatistics.add_field_details("admin_verb","THUB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc @@ -813,9 +798,12 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Toggle traitor scaling" set name="Toggle Traitor Scaling" - config.traitor_scaling = !config.traitor_scaling - log_admin("[key_name(usr)] toggled Traitor Scaling to [config.traitor_scaling].") - message_admins("[key_name_admin(usr)] toggled Traitor Scaling [config.traitor_scaling ? "on" : "off"].", 1) + if(toggle_config_value(/decl/config/toggle/traitor_scaling)) + log_admin("[key_name(usr)] toggled Traitor Scaling to on.") + message_admins("[key_name_admin(usr)] toggled Traitor Scaling on.", 1) + else + log_admin("[key_name(usr)] toggled Traitor Scaling to off.") + message_admins("[key_name_admin(usr)] toggled Traitor Scaling off.", 1) SSstatistics.add_field_details("admin_verb","TTS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/startnow() @@ -832,7 +820,7 @@ var/global/floorIsLava = 0 return 0 if(SSticker.start_now()) log_admin("[usr.key] has started the game.") - message_admins("[usr.key] has started the game.") + message_admins(SPAN_BLUE("[usr.key] has started the game.")) SSstatistics.add_field_details("admin_verb","SN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return 1 else @@ -852,7 +840,9 @@ var/global/floorIsLava = 0 var/confirm = alert("End the game round?", "Game Ending", "Yes", "Cancel") if(confirm == "Yes") - SSticker.force_ending = 1 + Master.SetRunLevel(RUNLEVEL_POSTGAME) + SSticker.end_game_state = END_GAME_READY_TO_END + INVOKE_ASYNC(SSticker, TYPE_PROC_REF(/datum/controller/subsystem/ticker, declare_completion)) log_and_message_admins("initiated a game ending.") to_world("Game ending! Initiated by [usr.key]!") SSstatistics.add_field("admin_verb","ER") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -861,11 +851,10 @@ var/global/floorIsLava = 0 set category = "Server" set desc="People can't enter" set name="Toggle Entering" - config.enter_allowed = !(config.enter_allowed) - if (!(config.enter_allowed)) - to_world("New players may no longer enter the game.") - else + if (toggle_config_value(/decl/config/toggle/on/enter_allowed)) to_world("New players may now enter the game.") + else + to_world("New players may no longer enter the game.") log_and_message_admins("toggled new player game entering.") world.update_status() SSstatistics.add_field_details("admin_verb","TE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -874,11 +863,11 @@ var/global/floorIsLava = 0 set category = "Server" set desc="People can't be AI" set name="Toggle AI" - config.allow_ai = !( config.allow_ai ) - if (!( config.allow_ai )) - to_world("The AI job is no longer chooseable.") - else + + if (toggle_config_value(/decl/config/toggle/on/allow_ai)) to_world("The AI job is chooseable now.") + else + to_world("The AI job is no longer chooseable.") log_admin("[key_name(usr)] toggled AI allowed.") world.update_status() SSstatistics.add_field_details("admin_verb","TAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -887,12 +876,12 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Respawn basically" set name="Toggle Respawn" - config.abandon_allowed = !(config.abandon_allowed) - if(config.abandon_allowed) + if (toggle_config_value(/decl/config/toggle/on/abandon_allowed)) to_world("You may now respawn.") + log_and_message_admins("toggled respawn to On.") else to_world("You may no longer respawn :(") - log_and_message_admins("toggled respawn to [config.abandon_allowed ? "On" : "Off"].") + log_and_message_admins("toggled respawn to Off.") world.update_status() SSstatistics.add_field_details("admin_verb","TR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -902,23 +891,14 @@ var/global/floorIsLava = 0 set name="Toggle Aliens" if(!check_rights(R_ADMIN)) return - - config.aliens_allowed = !config.aliens_allowed - log_admin("[key_name(usr)] toggled Aliens to [config.aliens_allowed].") - message_admins("[key_name_admin(usr)] toggled Aliens [config.aliens_allowed ? "on" : "off"].", 1) + if(toggle_config_value(/decl/config/toggle/aliens_allowed)) + log_admin("[key_name(usr)] toggled Aliens to On.") + message_admins("[key_name_admin(usr)] toggled Aliens on.", 1) + else + log_admin("[key_name(usr)] toggled Aliens to Off.") + message_admins("[key_name_admin(usr)] toggled Aliens off.", 1) SSstatistics.add_field_details("admin_verb","TA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/admins/proc/toggle_space_ninja() - set category = "Server" - set desc="Toggle space ninjas spawning." - set name="Toggle Space Ninjas" - if(!check_rights(R_ADMIN)) - return - - config.ninjas_allowed = !config.ninjas_allowed - log_and_message_admins("toggled Space Ninjas [config.ninjas_allowed ? "on" : "off"].") - SSstatistics.add_field_details("admin_verb","TSN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - /datum/admins/proc/delay() set category = "Server" set desc="Delay the game start/end" @@ -942,24 +922,24 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Toggle admin jumping" set name="Toggle Jump" - config.allow_admin_jump = !(config.allow_admin_jump) - log_and_message_admins("toggled admin jumping to [config.allow_admin_jump].") + toggle_config_value(/decl/config/toggle/on/admin_jump) + log_and_message_admins("toggled admin jumping to [get_config_value(/decl/config/toggle/on/admin_jump)].") SSstatistics.add_field_details("admin_verb","TJ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/adspawn() set category = "Server" set desc="Toggle admin spawning" set name="Toggle Spawn" - config.allow_admin_spawning = !(config.allow_admin_spawning) - log_and_message_admins("toggled admin item spawning to [config.allow_admin_spawning].") + toggle_config_value(/decl/config/toggle/on/admin_spawning) + log_and_message_admins("toggled admin item spawning to [get_config_value(/decl/config/toggle/on/admin_spawning)].") SSstatistics.add_field_details("admin_verb","TAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/adrev() set category = "Server" set desc="Toggle admin revives" set name="Toggle Revive" - config.allow_admin_rev = !(config.allow_admin_rev) - log_and_message_admins("toggled reviving to [config.allow_admin_rev].") + toggle_config_value(/decl/config/toggle/on/admin_revive) + log_and_message_admins("toggled reviving to [get_config_value(/decl/config/toggle/on/admin_revive)].") SSstatistics.add_field_details("admin_verb","TAR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/immreboot() @@ -977,43 +957,29 @@ var/global/floorIsLava = 0 world.Reboot() -/datum/admins/proc/unprison(var/mob/M in SSmobs.mob_list) - set category = "Admin" - set name = "Unprison" - if (isAdminLevel(M.z)) - if (config.allow_admin_jump) - M.forceMove(pick(GLOB.latejoin)) - message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]", 1) - log_admin("[key_name(usr)] has unprisoned [key_name(M)]") - else - alert("Admin jumping disabled") - else - alert("[M.name] is not prisoned.") - SSstatistics.add_field_details("admin_verb","UP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - ////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS /proc/is_special_character(var/character) // returns 1 for special characters and 2 for heroes of gamemode if(!SSticker.mode) return 0 - var/datum/mind/M + var/datum/mind/mind if (ismob(character)) - var/mob/C = character - M = C.mind + var/mob/character_mob = character + mind = character_mob.mind else if(istype(character, /datum/mind)) - M = character + mind = character - if(M) + if(mind) if(SSticker.mode.antag_templates && SSticker.mode.antag_templates.len) - for(var/datum/antagonist/antag in SSticker.mode.antag_templates) - if(antag.is_antagonist(M)) + for(var/decl/special_role/antag in SSticker.mode.antag_templates) + if(antag.is_antagonist(mind)) return 2 - if(M.special_role) + if(mind.assigned_special_role) return 1 if(isrobot(character)) - var/mob/living/silicon/robot/R = character - if(R.emagged) + var/mob/living/silicon/robot/robot = character + if(robot.emagged) return 1 return 0 @@ -1031,7 +997,7 @@ var/global/floorIsLava = 0 log_admin("[key_name(usr)] mass-spawned closets (icon debug), if this is a live server you should yell at them.") var/x = 0 var/y = 0 - for(var/check_appearance in typesof(/decl/closet_appearance)) + for(var/check_appearance in decls_repository.get_decl_paths_of_type(/decl/closet_appearance)) x++ if(x > 10) x = 0 @@ -1060,14 +1026,13 @@ var/global/floorIsLava = 0 set category = "Debug" set desc = "Spawn the product of a seed." set name = "Spawn Fruit" - - if(!check_rights(R_SPAWN)) return - - if(!seedtype || !SSplants.seeds[seedtype]) + if(!check_rights(R_SPAWN) || !seedtype || !SSplants.seeds[seedtype]) return var/datum/seed/S = SSplants.seeds[seedtype] - S.harvest(usr,0,0,1) - log_admin("[key_name(usr)] spawned [seedtype] fruit at ([usr.x],[usr.y],[usr.z])") + if(S?.harvest(usr, 0, FALSE, 1)) + log_admin("[key_name(usr)] spawned [seedtype] fruit at ([usr.x],[usr.y],[usr.z])") + else + to_chat(usr, SPAN_WARNING("Failed to harvest [seedtype].")) /datum/admins/proc/spawn_custom_item() set category = "Debug" @@ -1108,7 +1073,7 @@ var/global/floorIsLava = 0 to_chat(usr, "[assoc_key] has:") var/list/current_items = SScustomitems.custom_items_by_ckey[assoc_key] for(var/datum/custom_item/item in current_items) - to_chat(usr, "- name: [item.item_name] icon: [item.item_icon_state] path: [item.item_path] desc: [item.item_desc]") + to_chat(usr, "- name: [item.item_name] state: [item.item_state] icon: [item.item_icon] path: [item.item_path] desc: [item.item_desc]") /datum/admins/proc/spawn_plant(seedtype in SSplants.seeds) set category = "Debug" @@ -1127,14 +1092,20 @@ var/global/floorIsLava = 0 set desc = "(atom path) Spawn an atom" set name = "Spawn" - if(!check_rights(R_SPAWN)) return + if(!check_rights(R_SPAWN)) + return - var/list/types = typesof(/atom) - var/list/matches = new() + object = lowertext(trim(object)) + if(!object) + return - for(var/path in types) - if(findtext("[path]", object)) - matches += path + var/list/matches = new() + for(var/path in subtypesof(/atom)) + var/atom/path_cast = path + if(TYPE_IS_SPAWNABLE(path_cast) && findtext(lowertext("[path]"), object)) + // We need to keep the type as a string because for some ungodly reason input() compares + // initial invisibility value to mob see_invisible. + matches += "[path]" if(matches.len==0) return @@ -1143,10 +1114,11 @@ var/global/floorIsLava = 0 if(matches.len==1) chosen = matches[1] else - chosen = input("Select an atom type", "Spawn Atom", matches[1]) as null|anything in matches + chosen = input(usr, "Select an atom type", "Spawn Atom", matches[1]) as null|anything in matches if(!chosen) return + chosen = text2path(chosen) // See comment above. if(ispath(chosen,/turf)) var/turf/T = get_turf(usr.loc) T.ChangeTurf(chosen) @@ -1157,10 +1129,10 @@ var/global/floorIsLava = 0 SSstatistics.add_field_details("admin_verb","SA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/admins/proc/show_traitor_panel(var/mob/M in SSmobs.mob_list) +/datum/admins/proc/show_special_roles(var/mob/M in SSmobs.mob_list) set category = "Admin" set desc = "Edit mobs's memory and role" - set name = "Show Traitor Panel" + set name = "Show Special Roles" if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob") @@ -1181,66 +1153,41 @@ var/global/floorIsLava = 0 alert("Not before roundstart!", "Alert") return - var/out = "Current mode: [SSticker.mode.name] ([SSticker.mode.config_tag])
          " + var/out = "Current mode: [SSticker.mode.name] ([SSticker.mode.uid])
          " out += "
          " - if(SSticker.mode.ert_disabled) - out += "Emergency Response Teams: disabled" - else - out += "Emergency Response Teams: enabled" - out += "
          " - - if(SSticker.mode.deny_respawn) - out += "Respawning: disallowed" - else - out += "Respawning: allowed" - out += "
          " - - out += "Shuttle delay multiplier: [SSticker.mode.shuttle_delay]
          " - - if(SSticker.mode.auto_recall_shuttle) - out += "Shuttle auto-recall: enabled" - else - out += "Shuttle auto-recall: disabled" - out += "

          " - - if(SSticker.mode.event_delay_mod_moderate) - out += "Moderate event time modifier: [SSticker.mode.event_delay_mod_moderate]
          " - else - out += "Moderate event time modifier: unset
          " - - if(SSticker.mode.event_delay_mod_major) - out += "Major event time modifier: [SSticker.mode.event_delay_mod_major]
          " - else - out += "Major event time modifier: unset
          " + var/list/options = SSticker.get_game_mode_options() + out += jointext(options, "
          ") out += "
          " - if(SSticker.mode.antag_tags && SSticker.mode.antag_tags.len) + if(length(SSticker.mode.associated_antags)) out += "Core antag templates:
          " - for(var/antag_tag in SSticker.mode.antag_tags) - out += "[antag_tag].
          " + for(var/antag_type in SSticker.mode.associated_antags) + var/decl/special_role/antag = GET_DECL(antag_type) + if(antag) + out += "[antag.name].
          " if(SSticker.mode.round_autoantag) - out += "Autotraitor enabled." + out += "Autotraitor enabled." if(SSticker.mode.antag_scaling_coeff > 0) - out += " (scaling with [SSticker.mode.antag_scaling_coeff])" + out += " (scaling with [SSticker.mode.antag_scaling_coeff])" else - out += " (not currently scaling, set a coefficient)" + out += " (not currently scaling, set a coefficient)" out += "
          " else - out += "Autotraitor disabled.
          " + out += "Autotraitor disabled.
          " out += "All antag ids:" if(SSticker.mode.antag_templates && SSticker.mode.antag_templates.len) - for(var/datum/antagonist/antag in SSticker.mode.antag_templates) + for(var/decl/special_role/antag in SSticker.mode.antag_templates) antag.update_current_antag_max(SSticker.mode) - out += " [antag.id]" + out += " [antag.name]" out += " ([antag.get_antag_count()]/[antag.cur_max]) " - out += " \[-\]
          " + out += " \[-\]
          " else out += " None." - out += " \[+\]
          " + out += " \[+\]
          " show_browser(usr, out, "window=edit_mode[src]") SSstatistics.add_field_details("admin_verb","SGM") @@ -1250,8 +1197,7 @@ var/global/floorIsLava = 0 set category = "Debug" set desc="Reduces view range when wearing welding helmets" set name="Toggle tinted welding helmets." - config.welder_vision = !( config.welder_vision ) - if (config.welder_vision) + if (toggle_config_value(/decl/config/toggle/on/welder_vision)) to_world("Reduced welder vision has been enabled!") else to_world("Reduced welder vision has been disabled!") @@ -1262,13 +1208,14 @@ var/global/floorIsLava = 0 set category = "Server" set desc="Guests can't enter" set name="Toggle guests" - config.guests_allowed = !(config.guests_allowed) - if (!(config.guests_allowed)) - to_world("Guests may no longer enter the game.") - else + if (toggle_config_value(/decl/config/toggle/guests_allowed)) to_world("Guests may now enter the game.") - log_admin("[key_name(usr)] toggled guests game entering [config.guests_allowed?"":"dis"]allowed.") - log_and_message_admins("toggled guests game entering [config.guests_allowed?"":"dis"]allowed.") + log_admin("[key_name(usr)] toggled guests game entering allowed.") + log_and_message_admins("toggled guests game entering allowed.") + else + to_world("Guests may no longer enter the game.") + log_admin("[key_name(usr)] toggled guests game entering disallowed.") + log_and_message_admins("toggled guests game entering disallowed.") SSstatistics.add_field_details("admin_verb","TGU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/output_ai_laws() @@ -1278,8 +1225,8 @@ var/global/floorIsLava = 0 if(isAI(S)) to_chat(usr, "AI [key_name(S, usr)]'s laws:") else if(isrobot(S)) - var/mob/living/silicon/robot/R = S - to_chat(usr, "CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [R.connected_ai])":"(Independant)"]: laws:") + var/mob/living/silicon/robot/robot = S + to_chat(usr, "CYBORG [key_name(S, usr)] [robot.connected_ai?"(Slaved to: [robot.connected_ai])":"(Independant)"]: laws:") else if (ispAI(S)) to_chat(usr, "pAI [key_name(S, usr)]'s laws:") else @@ -1303,7 +1250,7 @@ var/global/floorIsLava = 0 return if(!M) - M = input("Select mob.", "Select mob.") as null|anything in GLOB.player_list + M = input("Select mob.", "Select mob.") as null|anything in global.player_list if(!istype(M)) return var/datum/nano_module/skill_ui/NM = /datum/nano_module/skill_ui @@ -1312,18 +1259,6 @@ var/global/floorIsLava = 0 NM = new NM(usr, override = M.skillset) NM.ui_interact(usr) -/client/proc/update_mob_sprite(mob/living/carbon/human/H) - set category = "Admin" - set name = "Update Mob Sprite" - set desc = "Should fix any mob sprite update errors." - - if (!holder) - to_chat(src, "Only administrators may use this command.") - return - - if(istype(H)) - H.regenerate_icons() - /proc/get_options_bar(whom, detail = 2, name = 0, link = 1, highlight_special = 1, var/datum/ticket/ticket = null) if(!whom) return "(*null*)" @@ -1332,7 +1267,7 @@ var/global/floorIsLava = 0 if(istype(whom, /client)) C = whom M = C.mob - else if(istype(whom, /mob)) + else if(ismob(whom)) M = whom C = M.client else @@ -1342,15 +1277,15 @@ var/global/floorIsLava = 0 return "[key_name(C, link, name, highlight_special, ticket)]" if(1) //Private Messages - return "[key_name(C, link, name, highlight_special, ticket)](?)" + return "[key_name(C, link, name, highlight_special, ticket)](?)" if(2) //Admins var/ref_mob = "\ref[M]" - return "[key_name(C, link, name, highlight_special, ticket)](?) (PP) (VV) (DN) ([admin_jump_link(M)]) (CA)" + return "[key_name(C, link, name, highlight_special, ticket)](?) (PP) (VV) (DN) ([admin_jump_link(M)]) (RS)" if(3) //Devs var/ref_mob = "\ref[M]" - return "[key_name(C, link, name, highlight_special, ticket)](VV)([admin_jump_link(M)])" + return "[key_name(C, link, name, highlight_special, ticket)](VV)([admin_jump_link(M)])" /proc/ishost(var/client/C) return check_rights(R_HOST, 0, C) @@ -1386,11 +1321,12 @@ var/global/floorIsLava = 0 if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response return 1 if(tomob.client) //No need to ghostize if there is no client - tomob.ghostize(0) + tomob.ghostize() message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") SSstatistics.add_field_details("admin_verb","CGD") tomob.ckey = frommob.ckey + tomob.teleop = null // no longer (a)ghosting qdel(frommob) return 1 @@ -1409,14 +1345,14 @@ var/global/floorIsLava = 0 to_chat(usr, "Mode has not started.") return - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) var/antag_type = input("Choose a template.","Force Latespawn") as null|anything in all_antag_types - if(!antag_type || !all_antag_types[antag_type]) + if(!antag_type) to_chat(usr, "Aborting.") return - var/datum/antagonist/antag = all_antag_types[antag_type] - message_admins("[key_name(usr)] attempting to force latespawn with template [antag.id].") + var/decl/special_role/antag = all_antag_types[antag_type] + message_admins("[key_name(usr)] attempting to force latespawn of [antag.name].") antag.attempt_auto_spawn() /datum/admins/proc/force_mode_latespawn() @@ -1437,113 +1373,129 @@ var/global/floorIsLava = 0 log_and_message_admins("attempting to force mode autospawn.") SSticker.mode.process_autoantag() -/datum/admins/proc/paralyze_mob(mob/H as mob in GLOB.player_list) +/datum/admins/proc/paralyze_mob(mob/living/M as mob in global.player_list) set category = "Admin" set name = "Toggle Paralyze" set desc = "Toggles paralyze state, which stuns, blinds and mutes the victim." - var/msg - - if(!isliving(H)) + if(!isliving(M)) + to_chat(usr, SPAN_WARNING("This verb can only be used on /mob/living targets.")) return if(check_rights(R_INVESTIGATE)) - if (H.paralysis == 0) - H.paralysis = 8000 - msg = "has paralyzed [key_name(H)]." + if(!M.admin_paralyzed) + M.visible_message( + SPAN_OCCULT("OOC: \The [M] has been paralyzed by a staff member. Please hold all interactions with them until staff have finished with them."), + SPAN_OCCULT("OOC: You have been paralyzed by a staff member. Please refer to your currently open admin help ticket or, if you don't have one, admin help for assistance.") + ) + M.set_status_condition(STAT_PARA, 8000) + M.admin_paralyzed = TRUE else - H.paralysis = 0 - msg = "has unparalyzed [key_name(H)]." - log_and_message_admins(msg) - + M.set_status_condition(STAT_PARA, 0) + M.admin_paralyzed = FALSE + M.visible_message(SPAN_OCCULT("OOC: \The [M] has been released from paralysis by staff. You may resume interactions with them.")) + to_chat(M, SPAN_OCCULT("OOC: You have been released from paralysis by staff and can return to your game.")) + log_and_message_admins("has [HAS_STATUS(M, STAT_PARA) ? "paralyzed" : "unparalyzed"] [key_name(M)].") + + +/datum/admins/var/obj/item/paper/admin/faxreply // var to hold fax replies in + +/proc/cmp_network_device_tag_asc(atom/a, atom/b) + var/datum/extension/network_device/NA = get_extension(a, /datum/extension/network_device) + var/datum/extension/network_device/NB = get_extension(b, /datum/extension/network_device) + return sorttext(NB? "[NB.network_id].[NB.network_tag]" : "", NA? "[NA.network_id].[NA.network_tag]" : "") + +/datum/admins/proc/show_fax_picker(var/list/possible_targets, var/mob/user) + var/html = "

          Pick a target fax machine:

          " + possible_targets = sortTim(possible_targets, /proc/cmp_network_device_tag_asc, FALSE) + for(var/obj/machinery/faxmachine/F in possible_targets) + var/datum/extension/network_device/N = get_extension(F, /datum/extension/network_device) + var/datum/computer_network/CN = N?.get_network() + if(!N || !CN) + continue + var/area/A = get_area(F) + html += "
        • [CN.network_id].[N.network_tag] [A? "([A])" : ""]
        • " + html = "
            [html]
          " + html = "
          [html]" + show_browser(user, html, "size=512x800;window=faxpicker;title=") /datum/admins/proc/sendFax() + set waitfor = FALSE //This takes a while to process set category = "Special Verbs" set name = "Send Fax" - set desc = "Sends a fax to this machine" - var/department = input("Choose a fax", "Fax") as null|anything in GLOB.alldepartments - for(var/obj/machinery/photocopier/faxmachine/sendto in GLOB.allfaxes) - if(sendto.department == department) + set desc = "Create and send a fax to the specified fax machine." - if (!istype(src,/datum/admins)) - src = usr.client.holder - if (!istype(src,/datum/admins)) - to_chat(usr, "Error: you are not an admin!") - return + var/mob/user = usr + if (!istype(src, /datum/admins)) + src = user.client.holder + if(!istype(src, /datum/admins) || !check_rights(R_ADMIN | R_MOD, "Error: you must have admin/moderator rights to send a fax!", user?.client)) + return - var/replyorigin = input(src.owner, "Please specify who the fax is coming from", "Origin") as text|null + var/list/possible_targets + for(var/_key in SSnetworking.networks) + var/datum/computer_network/N = SSnetworking.networks[_key] + if(!N) + continue + var/list/found = N.get_devices_by_type(/obj/machinery/faxmachine) //This thing returns empty lists! It's ruude. + if(length(found)) + LAZYADD(possible_targets, found) - var/obj/item/paper/admin/P = new /obj/item/paper/admin( null ) //hopefully the null loc won't cause trouble for us - faxreply = P + if(length(possible_targets)) + show_fax_picker(possible_targets, user) //Topic will handle the rest! + else + to_chat(user, SPAN_WARNING("There aren't any fax machines connected to a network in the world!")) - P.admindatum = src - P.origin = replyorigin - P.destination = sendto +/datum/admins/proc/faxCallback(var/obj/item/paper/admin/P, var/obj/machinery/faxmachine/destination) + var/customname = input(src.owner, "Pick a title for the report", "Title") + P.SetName("[P.origin] - [customname]") + P.desc = "This is a paper titled '" + P.name + "'." - P.adminbrowse() + if(P.sender || alert("Would you like the fax stamped?",, "Yes", "No") == "Yes") + P.apply_custom_stamp('icons/obj/items/stamps/stamp_boss.dmi', "by the [P.origin] Quantum Relay") + if(P.sender || alert("Would you like the fax signed?",, "Yes", "No") == "Yes") + var/sig = input(src.owner, "Enter the name you wish to sign the paper with.", "Signature") as text|null + if(length(sig)) + P.set_signature(sig) -datum/admins/var/obj/item/paper/admin/faxreply // var to hold fax replies in + var/decl/public_access/public_method/recv = GET_DECL(/decl/public_access/public_method/fax_receive_document) + if(recv.perform(destination, P, P.origin)) + var/datum/extension/network_device/N = get_extension(destination, /datum/extension/network_device) + to_chat(src.owner, SPAN_NOTICE("Message reply to transmitted successfully.")) + message_staff_fax(P, destination, src.owner, N?.network_id, N?.network_tag) + else + to_chat(src.owner, SPAN_WARNING("Message reply failed.")) -/datum/admins/proc/faxCallback(var/obj/item/paper/admin/P, var/obj/machinery/photocopier/faxmachine/destination) - var/customname = input(src.owner, "Pick a title for the report", "Title") as text|null + LAZYADD(global.adminfaxes, P) + faxreply = null - P.SetName("[P.origin] - [customname]") - P.desc = "This is a paper titled '" + P.name + "'." +/datum/admins/proc/addserverwhitelist(ckey as text) + set category = "Admin" + set name = "Add Ckey To Server Whitelist" + set desc = "Permanently adds the specified ckey to the server whitelist." - var/shouldStamp = 1 - if(!P.sender) // admin initiated - switch(alert("Would you like the fax stamped?",, "Yes", "No")) - if("No") - shouldStamp = 0 - - if(shouldStamp) - P.stamps += "
          This paper has been stamped by the [P.origin] Quantum Relay." - - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - var/x - var/y - x = rand(-2, 0) - y = rand(-1, 2) - P.offset_x += x - P.offset_y += y - stampoverlay.pixel_x = x - stampoverlay.pixel_y = y - - if(!P.ico) - P.ico = new - P.ico += "paper_stamp-boss" - stampoverlay.icon_state = "paper_stamp-boss" - - if(!P.stamped) - P.stamped = new - P.stamped += /obj/item/stamp/boss - P.overlays += stampoverlay - - var/obj/item/rcvdcopy - rcvdcopy = destination.copy(P) - rcvdcopy.forceMove(null) //hopefully this shouldn't cause trouble - GLOB.adminfaxes += rcvdcopy - - - - if(destination.recievefax(P)) - to_chat(src.owner, "Message reply to transmitted successfully.") - if(P.sender) // sent as a reply - log_admin("[key_name(src.owner)] replied to a fax message from [key_name(P.sender)]") - for(var/client/C in GLOB.admins) - if((R_INVESTIGATE) & C.holder.rights) - to_chat(C, "FAX LOG:[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (VIEW)") - else - log_admin("[key_name(src.owner)] has sent a fax message to [destination.department]") - for(var/client/C in GLOB.admins) - if((R_INVESTIGATE) & C.holder.rights) - to_chat(C, "FAX LOG:[key_name_admin(src.owner)] has sent a fax message to [destination.department] (VIEW)") + ckey = ckey(ckey) + if(!ckey) + to_chat(usr, SPAN_WARNING("Please specify a ckey to insert.")) + else if(check_server_whitelist(ckey)) // This will also preload the server whitelist. + to_chat(usr, SPAN_WARNING("That ckey is already server whitelisted.")) else - to_chat(src.owner, "Message reply failed.") + global.server_whitelist |= ckey + save_server_whitelist() + log_and_message_admins("has added [ckey] to the server whitelist.", usr) - spawn(100) - qdel(P) - faxreply = null - return +/datum/admins/proc/removeserverwhitelist(ckey as text) + set category = "Admin" + set name = "Remove Ckey From Server Whitelist" + set desc = "Permanently removes the specified ckey from the server whitelist." + + ckey = ckey(ckey) + if(!ckey) + to_chat(usr, SPAN_WARNING("Please specify a ckey to remove.")) + else if(!check_server_whitelist(ckey)) // This will also preload the server whitelist. + to_chat(usr, SPAN_WARNING("That ckey is not server whitelisted.")) + else + global.server_whitelist -= ckey + save_server_whitelist() + log_and_message_admins("has removed [ckey] from the server whitelist.", usr) diff --git a/code/modules/admin/admin_attack_log.dm b/code/modules/admin/admin_attack_log.dm index 93ea6fbb9c45..ad2970300484 100644 --- a/code/modules/admin/admin_attack_log.dm +++ b/code/modules/admin/admin_attack_log.dm @@ -1,7 +1,7 @@ /mob var/datum/mob_lite/last_attacker_ = null var/datum/mob_lite/last_attacked_ = null - var/mob/attack_logs_ = list() + var/list/attack_logs_ = list() /proc/log_and_message_admins(var/message as text, var/mob/user = usr, var/turf/location) var/turf/T = location ? location : (user ? get_turf(user) : null) @@ -10,15 +10,8 @@ log_admin(user ? "[key_name(user)] [message]" : "EVENT [message]") message_admins(user ? "[key_name_admin(user)] [message]" : "EVENT [message]") -/proc/log_and_message_staff(var/message as text, var/mob/user = usr, var/turf/location) - var/turf/T = location ? location : (user ? get_turf(user) : null) - message = append_admin_tools(message, user, T) - - log_admin(user ? "[key_name(user)] [message]" : "EVENT [message]") - message_staff(user ? "[key_name_admin(user)] [message]" : "EVENT [message]") - /proc/log_and_message_admins_many(var/list/mob/users, var/message) - if(!users || !users.len) + if(!LAZYLEN(users)) return var/list/user_keys = list() @@ -41,22 +34,27 @@ /proc/admin_attack_log(var/mob/attacker, var/mob/victim, var/attacker_message, var/victim_message, var/admin_message) if(!(attacker || victim)) EXCEPTION("Neither attacker or victim was supplied.") + if ((attacker && !istype(attacker)) || (victim && !istype(victim))) + return if(!store_admin_attack_log(attacker, victim)) return var/turf/attack_location var/intent = "(INTENT: N/A)" + var/target_zone = "(ZONE_SEL: N/A)" if(attacker) - intent = "(INTENT: [uppertext(attacker.a_intent)])" + intent = "(INTENT: [uppertext(attacker.get_intent().name)])" + if (attacker.get_target_zone()) + target_zone = "(ZONE_SEL: [uppertext(attacker.get_target_zone())])" if(victim) - attacker.attack_logs_ += text("\[[time_stamp()]\] [key_name(victim)] - [attacker_message] [intent]") + attacker.attack_logs_ += text("\[[time_stamp()]\] [key_name(victim)] - [attacker_message] [intent] [target_zone]") else - attacker.attack_logs_ += text("\[[time_stamp()]\] [attacker_message] [intent]") + attacker.attack_logs_ += text("\[[time_stamp()]\] [attacker_message] [intent] [target_zone]") attacker.last_attacked_ = mob_repository.get_lite_mob(victim) attack_location = get_turf(attacker) if(victim) if(attacker) - victim.attack_logs_ += text("\[[time_stamp()]\] [key_name(attacker)] - [victim_message] [intent]") + victim.attack_logs_ += text("\[[time_stamp()]\] [key_name(attacker)] - [victim_message] [intent] [target_zone]") else victim.attack_logs_ += text("\[[time_stamp()]\] [victim_message]") victim.last_attacker_ = mob_repository.get_lite_mob(attacker) @@ -70,9 +68,9 @@ var/full_admin_message if(attacker && victim) - full_admin_message = "[key_name(attacker)] [admin_message] [key_name(victim)] (INTENT: [attacker? uppertext(attacker.a_intent) : "N/A"])" + full_admin_message = "[key_name(attacker)] [admin_message] [key_name(victim)] [intent] [target_zone]" else if(attacker) - full_admin_message = "[key_name(attacker)] [admin_message] (INTENT: [attacker? uppertext(attacker.a_intent) : "N/A"])" + full_admin_message = "[key_name(attacker)] [admin_message] [intent] [target_zone]" else full_admin_message = "[key_name(victim)] [admin_message]" full_admin_message = append_admin_tools(full_admin_message, attacker||victim, attack_location) @@ -97,7 +95,7 @@ return FALSE /proc/admin_attacker_log_many_victims(var/mob/attacker, var/list/mob/victims, var/attacker_message, var/victim_message, var/admin_message) - if(!victims || !victims.len) + if(!LAZYLEN(victims)) return for(var/mob/victim in victims) @@ -116,7 +114,7 @@ /proc/append_admin_tools(var/message, var/mob, var/turf/location) if(location) - message = message + " (LOC)" + message = message + " (LOC)" if(mob) - message = message + " (MOB)" + message = message + " (MOB)" return message diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index dd40368535ff..8483aa50faa7 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -11,10 +11,6 @@ /proc/investigate_subject2file(var/subject) return file("[INVESTIGATE_DIR][subject].html") -/hook/startup/proc/resetInvestigate() - investigate_reset() - return 1 - /proc/investigate_reset() if(fdel(INVESTIGATE_DIR)) return 1 return 0 @@ -38,10 +34,10 @@ return show_browser(src, F, "window=investigate[subject];size=800x300") - if("hrefs") //persistant logs and stuff - if(config && config.log_hrefs) - if(GLOB.world_href_log) - show_browser(src, GLOB.world_href_log, "window=investigate[subject];size=800x300") + if("hrefs") //persistent logs and stuff + if(get_config_value(/decl/config/toggle/log_hrefs)) + if(global.world_href_log) + show_browser(src, global.world_href_log, "window=investigate[subject];size=800x300") else to_chat(src, "Error: admin_investigate: No href logfile found.") return diff --git a/code/modules/admin/admin_memo.dm b/code/modules/admin/admin_memo.dm index 4dfe2753d0c7..f4b36970dde5 100644 --- a/code/modules/admin/admin_memo.dm +++ b/code/modules/admin/admin_memo.dm @@ -26,7 +26,7 @@ return if( findtext(memo,"[memo]" + to_savefile(F, ckey, "[key] on [time2text(world.realtime,"(DDD) DD MMM hh:mm")]
          [memo]") message_admins("[key] set an admin memo:
          [memo]") //show all memos diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 0c6c482f4919..42eab17d7f73 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -1,4 +1,4 @@ -var/list/admin_ranks = list() //list of all ranks with associated rights +var/global/list/admin_ranks = list() //list of all ranks with associated rights //load our rank - > rights associations /proc/load_admin_ranks() @@ -35,9 +35,9 @@ var/list/admin_ranks = list() //list of all ranks with associated rights if("permissions","rights") rights |= R_PERMISSIONS if("possess") rights |= R_POSSESS if("stealth") rights |= R_STEALTH - if("rejuv","rejuvinate") rights |= R_REJUVINATE + if("rejuv","rejuvenate") rights |= R_REJUVENATE if("varedit") rights |= R_VAREDIT - if("everything","host","all") rights |= (R_HOST | R_BUILDMODE | R_ADMIN | R_BAN | R_FUN | R_SERVER | R_DEBUG | R_PERMISSIONS | R_POSSESS | R_STEALTH | R_REJUVINATE | R_VAREDIT | R_SOUNDS | R_SPAWN | R_MOD) + if("everything","host","all") rights |= (R_HOST | R_BUILDMODE | R_ADMIN | R_BAN | R_FUN | R_SERVER | R_DEBUG | R_PERMISSIONS | R_POSSESS | R_STEALTH | R_REJUVENATE | R_VAREDIT | R_SOUNDS | R_SPAWN | R_MOD) if("sound","sounds") rights |= R_SOUNDS if("spawn","create") rights |= R_SPAWN if("mod") rights |= R_MOD @@ -52,23 +52,19 @@ var/list/admin_ranks = list() //list of all ranks with associated rights testing(msg) #endif -/hook/startup/proc/loadAdmins() - load_admins() - return 1 - /proc/load_admins() //clear the datums references admin_datums.Cut() - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) C.remove_admin_verbs() C.holder = null - GLOB.admins.Cut() + global.admins.Cut() // Flush profiler access. for (var/admin in world.GetConfig("admin")) world.SetConfig("APP/admin", admin, null) - if(config.admin_legacy_system) + if(get_config_value(/decl/config/toggle/on/admin_legacy_system)) load_admin_ranks() //load text from file @@ -99,7 +95,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights var/datum/admins/D = new /datum/admins(rank, rights, ckey) //find the client for a ckey if they are connected and associate them with the new admin datum - D.associate(GLOB.ckey_directory[ckey]) + D.associate(global.ckey_directory[ckey]) else //The current admin system uses SQL @@ -108,7 +104,7 @@ var/list/admin_ranks = list() //list of all ranks with associated rights if(!dbcon.IsConnected()) error("Failed to connect to database in load_admins(). Reverting to legacy system.") log_misc("Failed to connect to database in load_admins(). Reverting to legacy system.") - config.admin_legacy_system = 1 + set_config_value(/decl/config/toggle/on/admin_legacy_system, TRUE) load_admins() return @@ -124,11 +120,11 @@ var/list/admin_ranks = list() //list of all ranks with associated rights var/datum/admins/D = new /datum/admins(rank, rights, ckey) //find the client for a ckey if they are connected and associate them with the new admin datum - D.associate(GLOB.ckey_directory[ckey]) + D.associate(global.ckey_directory[ckey]) if(!admin_datums) error("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.") log_misc("The database query in load_admins() resulted in no admins being added to the list. Reverting to legacy system.") - config.admin_legacy_system = 1 + set_config_value(/decl/config/toggle/on/admin_legacy_system, TRUE) load_admins() return diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm index 5917ae55e40e..b1d4c24d5fd9 100644 --- a/code/modules/admin/admin_secrets.dm +++ b/code/modules/admin/admin_secrets.dm @@ -1,4 +1,4 @@ -var/datum/admin_secrets/admin_secrets = new() +var/global/datum/admin_secrets/admin_secrets = new() /datum/admin_secrets var/list/datum/admin_secret_category/categories @@ -12,7 +12,7 @@ var/datum/admin_secrets/admin_secrets = new() for(var/datum/admin_secret_category/category in categories) category_assoc[category.type] = category - for(var/item_type in (typesof(/datum/admin_secret_item) - /datum/admin_secret_item)) + for(var/item_type in (subtypesof(/datum/admin_secret_item))) var/datum/admin_secret_item/secret_item = item_type if(!initial(secret_item.name)) continue diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index db42d694b6dd..d4d3e91d6e5f 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -1,7 +1,6 @@ //admin verb groups - They can overlap if you so wish. Only one of each verb will exist in the verbs list regardless -var/list/admin_verbs_default = list( +var/global/list/admin_verbs_default = list( /datum/admins/proc/show_player_panel, //shows an interface for individual players, with various links (links require additional flags, - /client/proc/player_panel, /client/proc/secrets, /client/proc/deadmin_self, //destroys our own admin datum so we can play as a regular player, /client/proc/hide_verbs, //hides all our adminverbs, @@ -9,14 +8,11 @@ var/list/admin_verbs_default = list( /client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, /client/proc/watched_variables, /client/proc/debug_global_variables,//as above but for global variables, -// /client/proc/check_antagonists, //shows all antags, /client/proc/cmd_check_new_players -// /client/proc/deadchat //toggles deadchat on/off, ) -var/list/admin_verbs_admin = list( - /client/proc/player_panel_new, //shows an interface for all players, with links to various panels, +var/global/list/admin_verbs_admin = list( + /client/proc/list_players, //shows an interface for all players, with links to various panels, /client/proc/invisimin, //allows our mob to go invisible/visible, -// /datum/admins/proc/show_traitor_panel, //interface which shows a mob's mind, -Removed due to rare practical use. Moved to debug verbs ~Errorage, /datum/admins/proc/show_game_mode, //Configuration window for the current game mode., /datum/admins/proc/force_mode_latespawn, //Force the mode to try a latespawn proc, /datum/admins/proc/force_antag_latespawn, //Force a specific template to try a latespawn proc, @@ -37,7 +33,6 @@ var/list/admin_verbs_admin = list( /client/proc/jumptocoord, //we ghost and jump to a coordinate, /client/proc/Getmob, //teleports a mob to our location, /client/proc/Getkey, //teleports a mob with a certain ckey to our location, -// /client/proc/sendmob, //sends a mob somewhere, -Removed due to it needing two sorting procs to work, which were executed every time an admin right-clicked. ~Errorage, /client/proc/Jump, /client/proc/jumptokey, //allows us to jump to the location of a mob with a certain ckey, /client/proc/jumptomob, //allows us to jump to a specific mob, @@ -53,7 +48,7 @@ var/list/admin_verbs_admin = list( /client/proc/check_ai_laws, //shows AI and borg laws, /client/proc/rename_silicon, //properly renames silicons, /client/proc/manage_silicon_laws, // Allows viewing and editing silicon laws. , - /client/proc/check_antagonists, + /client/proc/show_round_status, /client/proc/admin_memo, //admin memo system. show/delete/write. +SERVER needed to delete admin memos of others, /client/proc/dsay, //talk in deadchat using our ckey // /client/proc/toggle_hear_deadcast, //toggles whether we hear deadchat, @@ -78,7 +73,6 @@ var/list/admin_verbs_admin = list( /datum/admins/proc/show_skills, /client/proc/man_up, /client/proc/global_man_up, - /client/proc/response_team, // Response Teams admin verb, /client/proc/toggle_antagHUD_use, /client/proc/toggle_antagHUD_restrictions, /client/proc/allow_character_respawn, // Allows a ghost to respawn , @@ -89,25 +83,27 @@ var/list/admin_verbs_admin = list( /client/proc/change_human_appearance_admin, // Allows an admin to change the basic appearance of human-based mobs , /client/proc/change_human_appearance_self, // Allows the human-based mob itself change its basic appearance , /client/proc/change_security_level, - /client/proc/view_chemical_reaction_logs, /client/proc/makePAI, /client/proc/fixatmos, /client/proc/list_traders, /client/proc/add_trader, /client/proc/remove_trader, /datum/admins/proc/sendFax, + /datum/admins/proc/show_traits ) -var/list/admin_verbs_ban = list( +var/global/list/admin_verbs_ban = list( + /client/proc/DB_ban_panel, /client/proc/unban_panel, /client/proc/jobbans ) -var/list/admin_verbs_sounds = list( +var/global/list/admin_verbs_sounds = list( /client/proc/play_local_sound, /client/proc/play_sound, /client/proc/play_server_sound ) -var/list/admin_verbs_fun = list( +var/global/list/admin_verbs_fun = list( + /client/proc/change_lobby_screen, /client/proc/object_talk, /datum/admins/proc/cmd_admin_dress, /client/proc/cmd_admin_gib_self, @@ -115,9 +111,7 @@ var/list/admin_verbs_fun = list( /client/proc/everyone_random, /client/proc/cinematic, /datum/admins/proc/toggle_aliens, - /datum/admins/proc/toggle_space_ninja, /client/proc/cmd_admin_add_freeform_ai_law, - /client/proc/cmd_admin_add_random_ai_law, /client/proc/toggle_random_events, /client/proc/editappear, /client/proc/roll_dices, @@ -127,7 +121,7 @@ var/list/admin_verbs_fun = list( /datum/admins/proc/ai_hologram_set ) -var/list/admin_verbs_spawn = list( +var/global/list/admin_verbs_spawn = list( /datum/admins/proc/spawn_fruit, /datum/admins/proc/spawn_fluid_verb, /datum/admins/proc/spawn_custom_item, @@ -135,10 +129,11 @@ var/list/admin_verbs_spawn = list( /datum/admins/proc/spawn_plant, /datum/admins/proc/spawn_atom, // allows us to spawn instances, /client/proc/respawn_character, + /client/proc/respawn_as_self, /client/proc/spawn_chemdisp_cartridge, /datum/admins/proc/mass_debug_closet_icons ) -var/list/admin_verbs_server = list( +var/global/list/admin_verbs_server = list( /datum/admins/proc/capture_map_part, /client/proc/set_holiday, /datum/admins/proc/startnow, @@ -156,15 +151,19 @@ var/list/admin_verbs_server = list( /datum/admins/proc/adspawn, /datum/admins/proc/adjump, /datum/admins/proc/toggle_aliens, - /datum/admins/proc/toggle_space_ninja, /client/proc/toggle_random_events, - /client/proc/nanomapgen_DumpImage + /client/proc/nanomapgen_DumpImage, + /datum/admins/proc/addserverwhitelist, + /datum/admins/proc/removeserverwhitelist, + /datum/admins/proc/panicbunker, + /datum/admins/proc/addbunkerbypass, + /datum/admins/proc/revokebunkerbypass, + /datum/admins/proc/force_persistence_save_verb ) -var/list/admin_verbs_debug = list( +var/global/list/admin_verbs_debug = list( /datum/admins/proc/jump_to_fluid_source, /datum/admins/proc/jump_to_fluid_active, /client/proc/cmd_admin_list_open_jobs, - /client/proc/Debug2, /client/proc/ZASSettings, /client/proc/cmd_debug_make_powernets, /client/proc/debug_controller, @@ -175,13 +174,13 @@ var/list/admin_verbs_debug = list( /client/proc/cmd_debug_tog_aliens, /client/proc/air_report, /client/proc/reload_admins, + /client/proc/reload_secrets, /client/proc/restart_controller, /client/proc/print_random_map, /client/proc/create_random_map, /client/proc/apply_random_map, /client/proc/overlay_random_map, /client/proc/delete_random_map, - /datum/admins/proc/submerge_map, /datum/admins/proc/map_template_load, /datum/admins/proc/map_template_load_new_z, /datum/admins/proc/map_template_upload, @@ -207,31 +206,43 @@ var/list/admin_verbs_debug = list( /client/proc/reload_webhooks, /datum/admins/proc/check_unconverted_single_icon_items, /client/proc/spawn_material, - /client/proc/verb_adjust_tank_bomb_severity + /client/proc/verb_adjust_tank_bomb_severity, + /client/proc/force_ghost_trap_trigger, + /client/proc/spawn_quantum_mechanic, + /client/proc/spawn_exoplanet, + /client/proc/print_cargo_prices, + /client/proc/resend_nanoui_templates, + /client/proc/display_del_log, + /client/proc/spawn_ore_pile, + /datum/admins/proc/force_initialize_weather, + /datum/admins/proc/force_weather_state, + /datum/admins/proc/force_kill_weather, + /client/proc/force_reload_theme_css, + /client/proc/toggle_browser_inspect, ) -var/list/admin_verbs_paranoid_debug = list( +var/global/list/admin_verbs_paranoid_debug = list( /client/proc/callproc, /client/proc/callproc_target, /client/proc/debug_controller ) -var/list/admin_verbs_possess = list( +var/global/list/admin_verbs_possess = list( /proc/possess, /proc/release ) -var/list/admin_verbs_permissions = list( +var/global/list/admin_verbs_permissions = list( /client/proc/edit_admin_permissions ) -var/list/admin_verbs_rejuv = list( +var/global/list/admin_verbs_rejuv = list( /client/proc/respawn_character ) //verbs which can be hidden - needs work -var/list/admin_verbs_hideable = list( +var/global/list/admin_verbs_hideable = list( /client/proc/deadmin_self, // /client/proc/deadchat, - /datum/admins/proc/show_traitor_panel, + /datum/admins/proc/show_special_roles, /datum/admins/proc/toggleenter, /datum/admins/proc/toggleguests, /datum/admins/proc/announce, @@ -257,12 +268,9 @@ var/list/admin_verbs_hideable = list( /client/proc/drop_bomb, /client/proc/cinematic, /datum/admins/proc/toggle_aliens, - /datum/admins/proc/toggle_space_ninja, /client/proc/cmd_admin_add_freeform_ai_law, - /client/proc/cmd_admin_add_random_ai_law, /client/proc/cmd_admin_create_centcom_report, /client/proc/toggle_random_events, - /client/proc/cmd_admin_add_random_ai_law, /client/proc/set_holiday, /datum/admins/proc/startnow, /datum/admins/proc/endnow, @@ -280,7 +288,6 @@ var/list/admin_verbs_hideable = list( /client/proc/cmd_admin_list_open_jobs, /client/proc/callproc, /client/proc/callproc_target, - /client/proc/Debug2, /client/proc/reload_admins, /client/proc/cmd_debug_make_powernets, /client/proc/debug_controller, @@ -292,9 +299,14 @@ var/list/admin_verbs_hideable = list( /client/proc/enable_debug_verbs, /client/proc/roll_dices, /proc/possess, - /proc/release + /proc/release, + /datum/admins/proc/panicbunker, + /datum/admins/proc/addbunkerbypass, + /datum/admins/proc/revokebunkerbypass, + /client/proc/spawn_quantum_mechanic, + /client/proc/respawn_as_self ) -var/list/admin_verbs_mod = list( +var/global/list/admin_verbs_mod = list( /client/proc/cmd_admin_pm_context, // right-click adminPM interface, /client/proc/cmd_admin_pm_panel, // admin-pm list, /client/proc/debug_variables, // allows us to -see- the variables of any instance in the game., @@ -304,16 +316,18 @@ var/list/admin_verbs_mod = list( /client/proc/admin_ghost, // allows us to ghost/reenter body at will, /client/proc/cmd_mod_say, /datum/admins/proc/show_player_info, - /client/proc/player_panel_new, + /client/proc/list_players, /client/proc/dsay, /datum/admins/proc/show_skills, /datum/admins/proc/show_player_panel, - /client/proc/check_antagonists, + /client/proc/show_round_status, /client/proc/cmd_admin_direct_narrate, /client/proc/aooc, /datum/admins/proc/sendFax, /datum/admins/proc/paralyze_mob, - /datum/admins/proc/view_persistent_data + /datum/admins/proc/view_persistent_data, + /datum/admins/proc/dump_configuration, + /datum/admins/proc/dump_character_info_manifest ) /client/proc/add_admin_verbs() @@ -326,12 +340,12 @@ var/list/admin_verbs_mod = list( if(holder.rights & R_SERVER) verbs += admin_verbs_server if(holder.rights & R_DEBUG) verbs += admin_verbs_debug - if(config.debugparanoid && !(holder.rights & R_ADMIN)) + if(get_config_value(/decl/config/toggle/paranoid) && !(holder.rights & R_ADMIN)) verbs.Remove(admin_verbs_paranoid_debug) //Right now it's just callproc but we can easily add others later on. if(holder.rights & R_POSSESS) verbs += admin_verbs_possess if(holder.rights & R_PERMISSIONS) verbs += admin_verbs_permissions if(holder.rights & R_STEALTH) verbs += /client/proc/stealth - if(holder.rights & R_REJUVINATE) verbs += admin_verbs_rejuv + if(holder.rights & R_REJUVENATE) verbs += admin_verbs_rejuv if(holder.rights & R_SOUNDS) verbs += admin_verbs_sounds if(holder.rights & R_SPAWN) verbs += admin_verbs_spawn if(holder.rights & R_MOD) verbs += admin_verbs_mod @@ -399,12 +413,12 @@ var/list/admin_verbs_mod = list( ghost.reenter_corpse() SSstatistics.add_field_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - else if(istype(mob,/mob/new_player)) - to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.") + else if(isnewplayer(mob)) + to_chat(src, SPAN_WARNING("Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.")) else //ghostize var/mob/body = mob - var/mob/observer/ghost/ghost = body.ghostize(1) + var/mob/observer/ghost/ghost = body.ghostize() ghost.admin_ghosted = 1 if(body) body.teleop = ghost @@ -427,29 +441,20 @@ var/list/admin_verbs_mod = list( to_chat(mob, "Invisimin on. You are now as invisible as a ghost.") mob.alpha = max(mob.alpha - 100, 0) - -/client/proc/player_panel() - set name = "Player Panel" - set category = "Admin" - if(holder) - holder.player_panel_old() - SSstatistics.add_field_details("admin_verb","PP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - -/client/proc/player_panel_new() - set name = "Player Panel New" +/client/proc/list_players() + set name = "List Players" set category = "Admin" if(holder) - holder.player_panel_new() + holder.list_players() SSstatistics.add_field_details("admin_verb","PPN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return -/client/proc/check_antagonists() - set name = "Check Antagonists" +/client/proc/show_round_status() + set name = "Check Round Status" set category = "Admin" if(holder) - holder.check_antagonists() - log_admin("[key_name(usr)] checked antagonists.") //for tsar~ + holder.show_round_status() + log_admin("[key_name(usr)] checked round status.") //for tsar~ SSstatistics.add_field_details("admin_verb","CHA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return @@ -457,7 +462,7 @@ var/list/admin_verbs_mod = list( set name = "Display Job bans" set category = "Admin" if(holder) - if(config.ban_legacy_system) + if(get_config_value(/decl/config/toggle/on/ban_legacy_system)) holder.Jobbans() else holder.DB_ban_panel() @@ -468,7 +473,7 @@ var/list/admin_verbs_mod = list( set name = "Unban Panel" set category = "Admin" if(holder) - if(config.ban_legacy_system) + if(get_config_value(/decl/config/toggle/on/ban_legacy_system)) holder.unbanpanel() else holder.DB_ban_panel() @@ -513,31 +518,34 @@ var/list/admin_verbs_mod = list( if(!warned_ckey || !istext(warned_ckey)) return if(warned_ckey in admin_datums) - to_chat(usr, "Error: warn(): You can't warn admins.") + to_chat(usr, SPAN_WARNING("Error: warn(): You can't warn admins.")) return var/datum/preferences/D - var/client/C = GLOB.ckey_directory[warned_ckey] - if(C) D = C.prefs - else D = SScharacter_setup.preferences_datums[warned_ckey] + var/client/C = global.ckey_directory[warned_ckey] + if(C) + D = C.prefs + else + D = SScharacter_setup.preferences_datums[warned_ckey] if(!D) - to_chat(src, "Error: warn(): No such ckey found.") + to_chat(src, SPAN_WARNING("Error: warn(): No such ckey found.")) return if(++D.warns >= MAX_WARNS) //uh ohhhh...you'reee iiiiin trouuuubble O:) - ban_unban_log_save("[ckey] warned [warned_ckey], resulting in a [AUTOBANTIME] minute autoban.") + var/mins_readable = minutes_to_readable(AUTOBANTIME) + ban_unban_log_save("[ckey] warned [warned_ckey], resulting in a [mins_readable] autoban.") if(C) - message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban.") - to_chat(C, "You have been autobanned due to a warning by [ckey].
          This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.
          ") + message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [mins_readable] ban.") + to_chat(C, SPAN_RED("You have been autobanned due to a warning by [ckey].
          This is a temporary ban, it will be removed in [mins_readable].")) qdel(C) else - message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban.") + message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [mins_readable] ban.") AddBan(warned_ckey, D.last_id, "Autobanning due to too many formal warnings", ckey, 1, AUTOBANTIME) SSstatistics.add_field("ban_warn",1) else if(C) - to_chat(C, "You have been formally warned by an administrator.
          Further warnings will result in an autoban.
          ") + to_chat(C, SPAN_RED("You have been formally warned by an administrator.
          Further warnings will result in an autoban.")) message_admins("[key_name_admin(src)] has warned [key_name_admin(C)]. They have [MAX_WARNS-D.warns] strikes remaining.") else message_admins("[key_name_admin(src)] has warned [warned_ckey] (DC). They have [MAX_WARNS-D.warns] strikes remaining.") @@ -564,12 +572,18 @@ var/list/admin_verbs_mod = list( explosion(epicenter, 2, 3, 4, 4) if("Big Bomb") explosion(epicenter, 3, 5, 7, 5) + if("Custom Bomb") - var/devastation_range = input("Devastation range (in tiles):") as num - var/heavy_impact_range = input("Heavy impact range (in tiles):") as num - var/light_impact_range = input("Light impact range (in tiles):") as num - var/flash_range = input("Flash range (in tiles):") as num - explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range) + if(get_config_value(/decl/config/toggle/use_iterative_explosions)) + var/power = input(src, "Input power num.", "Power?") as num + explosion_iter(get_turf(mob), power, (UP|DOWN)) + else + var/devastation_range = input("Devastation range (in tiles):") as num + var/heavy_impact_range = input("Heavy impact range (in tiles):") as num + var/light_impact_range = input("Light impact range (in tiles):") as num + var/flash_range = input("Flash range (in tiles):") as num + explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range) + log_and_message_admins("created an admin explosion at [epicenter.loc].") SSstatistics.add_field_details("admin_verb","DB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -588,11 +602,13 @@ var/list/admin_verbs_mod = list( set category = "Special Verbs" set name = "oSay" set desc = "Display a message to everyone who can hear the target" + + msg = sanitize(msg) + if(mob.control_object) if(!msg) return - for (var/mob/V in hearers(mob.control_object)) - V.show_message("[mob.control_object.name] says: \"" + msg + "\"", 2) + mob.control_object.audible_message("[mob.control_object] says, \"[msg]\"") SSstatistics.add_field_details("admin_verb","OT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/readmin_self() @@ -603,7 +619,7 @@ var/list/admin_verbs_mod = list( deadmin_holder.reassociate() log_admin("[src] re-admined themself.") message_admins("[src] re-admined themself.", 1) - to_chat(src, "You now have the keys to control the planet, or at least [GLOB.using_map.full_name].") + to_chat(src, "You now have the keys to control the planet, or at least [global.using_map.full_name].") verbs -= /client/proc/readmin_self /client/proc/deadmin_self() @@ -623,13 +639,10 @@ var/list/admin_verbs_mod = list( set name = "Toggle href logging" set category = "Server" if(!holder) return - if(config) - if(config.log_hrefs) - config.log_hrefs = 0 - to_chat(src, "Stopped logging hrefs") - else - config.log_hrefs = 1 - to_chat(src, "Started logging hrefs") + if(toggle_config_value(/decl/config/toggle/log_hrefs)) + to_chat(src, "Started logging hrefs") + else + to_chat(src, "Stopped logging hrefs") /client/proc/check_ai_laws() set name = "Check AI Laws" @@ -643,10 +656,10 @@ var/list/admin_verbs_mod = list( if(!check_rights(R_ADMIN)) return - var/mob/living/silicon/S = input("Select silicon.", "Rename Silicon.") as null|anything in GLOB.silicon_mob_list + var/mob/living/silicon/S = input("Select silicon.", "Rename Silicon.") as null|anything in global.silicon_mob_list if(!S) return - var/new_name = sanitizeSafe(input(src, "Enter new name. Leave blank or as is to cancel.", "[S.real_name] - Enter new silicon name", S.real_name)) + var/new_name = sanitize_safe(input(src, "Enter new name. Leave blank or as is to cancel.", "[S.real_name] - Enter new silicon name", S.real_name)) if(new_name && new_name != S.real_name) log_and_message_admins("has renamed the silicon '[S.real_name]' to '[new_name]'") S.fully_replace_character_name(new_name) @@ -658,11 +671,11 @@ var/list/admin_verbs_mod = list( if(!check_rights(R_ADMIN)) return - var/mob/living/silicon/S = input("Select silicon.", "Manage Silicon Laws") as null|anything in GLOB.silicon_mob_list + var/mob/living/silicon/S = input("Select silicon.", "Manage Silicon Laws") as null|anything in global.silicon_mob_list if(!S) return var/datum/nano_module/law_manager/L = new(S) - L.ui_interact(usr, state = GLOB.admin_state) + L.ui_interact(usr, state = global.admin_topic_state) log_and_message_admins("has opened [S]'s law manager.") SSstatistics.add_field_details("admin_verb","MSL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -673,11 +686,11 @@ var/list/admin_verbs_mod = list( if(!check_rights(R_FUN)) return - var/mob/living/carbon/human/H = input("Select mob.", "Change Mob Appearance - Admin") as null|anything in GLOB.human_mob_list + var/mob/living/human/H = input("Select mob.", "Change Mob Appearance - Admin") as null|anything in global.human_mob_list if(!H) return log_and_message_admins("is altering the appearance of [H].") - H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0, state = GLOB.admin_state) + H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0, state = global.admin_topic_state) SSstatistics.add_field_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/change_human_appearance_self() @@ -687,20 +700,17 @@ var/list/admin_verbs_mod = list( if(!check_rights(R_FUN)) return - var/mob/living/carbon/human/H = input("Select mob.", "Change Mob Appearance - Self") as null|anything in GLOB.human_mob_list + var/mob/living/human/H = input("Select mob.", "Change Mob Appearance - Self") as null|anything in global.human_mob_list if(!H) return if(!H.client) to_chat(usr, "Only mobs with clients can alter their own appearance.") return - switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel")) - if("Yes") - log_and_message_admins("has allowed [H] to change \his appearance, including races that requires whitelisting") - H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0) - if("No") - log_and_message_admins("has allowed [H] to change \his appearance, excluding races that requires whitelisting.") - H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1) + var/whitelist_check = alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel") == "No" + var/decl/pronouns/pronouns = H.get_pronouns(ignore_coverings = TRUE) + log_and_message_admins("has allowed [H] to change [pronouns.his] appearance, [whitelist_check ? "excluding" : "including"] races that requires whitelisting.") + H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = whitelist_check) SSstatistics.add_field_details("admin_verb","CMAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/change_security_level() @@ -710,7 +720,7 @@ var/list/admin_verbs_mod = list( if(!check_rights(R_ADMIN)) return - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) var/decl/security_level/new_security_level = input(usr, "It's currently [security_state.current_security_level.name].", "Select Security Level") as null|anything in (security_state.all_security_levels - security_state.current_security_level) if(!new_security_level) @@ -721,45 +731,39 @@ var/list/admin_verbs_mod = list( //---- bs12 verbs ---- - -/client/proc/mod_panel() - set name = "Moderator Panel" - set category = "Admin" -/* if(holder) - holder.mod_panel()*/ -// SSstatistics.add_field_details("admin_verb","MP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - /client/proc/editappear() set name = "Edit Appearance" set category = "Fun" if(!check_rights(R_FUN)) return - var/mob/living/carbon/human/M = input("Select mob.", "Edit Appearance") as null|anything in GLOB.human_mob_list + var/mob/living/human/M = input("Select mob.", "Edit Appearance") as null|anything in global.human_mob_list - if(!istype(M, /mob/living/carbon/human)) + if(!ishuman(M)) to_chat(usr, "You can only do this to humans!") return switch(alert("Are you sure you wish to edit this mob's appearance? This can result in unintended consequences.",,"Yes","No")) if("No") return + + var/update_hair = FALSE var/new_facial = input("Please select facial hair color.", "Character Generation") as color if(new_facial) - M.facial_hair_colour = new_facial + SET_FACIAL_HAIR_COLOR(M, new_facial, TRUE) + update_hair = TRUE var/new_hair = input("Please select hair color.", "Character Generation") as color if(new_hair) - M.hair_colour = new_hair + SET_HAIR_COLOR(M, new_hair, TRUE) + update_hair = TRUE var/new_eyes = input("Please select eye color.", "Character Generation") as color if(new_eyes) - M.eye_colour = new_eyes - M.update_eyes() + M.set_eye_colour(new_eyes) var/new_skin = input("Please select body color.", "Character Generation") as color if(new_skin) - M.skin_colour = new_skin + M.set_skin_colour(new_skin, skip_update = TRUE) var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation") as text @@ -768,34 +772,29 @@ var/list/admin_verbs_mod = list( M.skin_tone = -M.skin_tone + 35 // hair - var/new_hstyle = input(usr, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list - if(new_hstyle) - M.h_style = new_hstyle + var/new_hairstyle = input(usr, "Select a hair style", "Grooming") as null|anything in decls_repository.get_decl_paths_of_subtype(/decl/sprite_accessory/hair) + if(new_hairstyle) + SET_HAIR_STYLE(M, new_hairstyle, TRUE) + update_hair = TRUE // facial hair - var/new_fstyle = input(usr, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list + var/new_fstyle = input(usr, "Select a facial hair style", "Grooming") as null|anything in decls_repository.get_decl_paths_of_subtype(/decl/sprite_accessory/facial_hair) if(new_fstyle) - M.f_style = new_fstyle + SET_FACIAL_HAIR_STYLE(M, new_fstyle, TRUE) + update_hair = TRUE var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female", "Neuter") if (new_gender) if(new_gender == "Male") - M.gender = MALE + M.set_gender(MALE) else if (new_gender == "Female") - M.gender = FEMALE + M.set_gender(FEMALE) else - M.gender = NEUTER + M.set_gender(NEUTER) - M.update_hair() + if(update_hair) + M.update_hair(TRUE) M.update_body() - M.check_dna(M) - -/client/proc/playernotes() - set name = "Show Player Info" - set category = "Admin" - if(holder) - holder.PlayerNotes() - return /client/proc/free_slot_submap() set name = "Free Job Slot (Submap)" @@ -842,30 +841,25 @@ var/list/admin_verbs_mod = list( /client/proc/toggleghostwriters() set name = "Toggle ghost writers" set category = "Server" - if(!holder) return - if(config) - if(config.cult_ghostwriter) - config.cult_ghostwriter = 0 - to_chat(src, "Disallowed ghost writers.") - message_admins("Admin [key_name_admin(usr)] has disabled ghost writers.", 1) - else - config.cult_ghostwriter = 1 - to_chat(src, "Enabled ghost writers.") - message_admins("Admin [key_name_admin(usr)] has enabled ghost writers.", 1) + if(!holder) + return + if(toggle_config_value(/decl/config/toggle/on/cult_ghostwriter)) + to_chat(src, "Enabled ghost writers.") + message_admins("Admin [key_name_admin(usr)] has enabled ghost writers.", 1) + else + to_chat(src, "Disallowed ghost writers.") + message_admins("Admin [key_name_admin(usr)] has disabled ghost writers.", 1) /client/proc/toggledrones() set name = "Toggle maintenance drones" set category = "Server" if(!holder) return - if(config) - if(config.allow_drone_spawn) - config.allow_drone_spawn = 0 - to_chat(src, "Disallowed maint drones.") - message_admins("Admin [key_name_admin(usr)] has disabled maint drones.", 1) - else - config.allow_drone_spawn = 1 - to_chat(src, "Enabled maint drones.") - message_admins("Admin [key_name_admin(usr)] has enabled maint drones.", 1) + if(toggle_config_value(/decl/config/toggle/on/allow_drone_spawn)) + to_chat(src, "Enabled maint drones.") + message_admins("Admin [key_name_admin(usr)] has enabled maint drones.", 1) + else + to_chat(src, "Disallowed maint drones.") + message_admins("Admin [key_name_admin(usr)] has disabled maint drones.", 1) /client/proc/man_up(mob/T as mob in SSmobs.mob_list) set category = "Fun" @@ -888,12 +882,35 @@ var/list/admin_verbs_mod = list( log_and_message_admins("told everyone to man up and deal with it.") -/client/proc/give_spell(mob/T as mob in SSmobs.mob_list) // -- Urist +/client/proc/change_lobby_screen() + set name = "Lobby Screen: Change" set category = "Fun" - set name = "Give Spell" - set desc = "Gives a spell to a mob." - var/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spells - if(!S) return - T.add_spell(new S) - SSstatistics.add_field_details("admin_verb","GS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_and_message_admins("gave [key_name(T)] the spell [S].") + + if(!check_rights(R_FUN)) + return + + log_and_message_admins("is trying to change the title screen.") + SSstatistics.add_field_details("admin_verb", "LSC") + + switch(alert(usr, "Select option", "Lobby Screen", "Upload custom", "Reset to default", "Cancel")) + if("Upload custom") + var/file = input(usr) as icon|null + + if(!file) + return + + global.using_map.update_titlescreen(file) + + if("Reset to default") + global.using_map.update_titlescreen() + + if("Cancel") + return + +/client/proc/force_reload_theme_css() + set category = "Debug" + set name = "Reload UI Theme CSS" + set desc = "Forces the client to reload its UI theme css file." + if(!check_rights(R_DEBUG)) + return + ReloadThemeCss(src) diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index 04cb6802cf54..373749683248 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -1,7 +1,6 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 -var/jobban_runonce // Updates legacy bans with new info -var/jobban_keylist[0] //to store the keys & ranks +var/global/list/jobban_keylist = list() //to store the keys & ranks /proc/jobban_fullban(mob/M, rank, reason) if(!M) @@ -12,18 +11,16 @@ var/jobban_keylist[0] //to store the keys & ranks jobban_keylist.Add(text("[last_ckey] - [rank] ## [reason]")) jobban_savebanfile() -/proc/jobban_client_fullban(ckey, rank) - if (!ckey || !rank) return - jobban_keylist.Add(text("[ckey] - [rank]")) - jobban_savebanfile() - //returns a reason if M is banned from rank, returns 0 otherwise /proc/jobban_isbanned(mob/M, rank) if(M && rank) + if(ispath(rank, /decl/special_role)) + var/decl/special_role/antag = GET_DECL(rank) + rank = antag.name if (SSjobs.guest_jobbans(rank)) - if(config.guest_jobban && IsGuestKey(M.key)) + if(get_config_value(/decl/config/toggle/on/guest_jobban) && IsGuestKey(M.key)) return "Guest Job-ban" - if(config.usewhitelist && !check_whitelist(M)) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOBS_WHITELIST && !check_server_whitelist(M)) return "Whitelisted Job" return ckey_is_jobbanned(M.ckey, rank) return 0 @@ -39,16 +36,11 @@ var/jobban_keylist[0] //to store the keys & ranks return "Reason Unspecified" return 0 -/hook/startup/proc/loadJobBans() - jobban_loadbanfile() - return 1 - /proc/jobban_loadbanfile() - if(config.ban_legacy_system) + if(get_config_value(/decl/config/toggle/on/ban_legacy_system)) var/savefile/S=new("data/job_full.ban") - S["keys[0]"] >> jobban_keylist + from_savefile(S, "keys[0]", jobban_keylist) log_admin("Loading jobban_rank") - S["runonce"] >> jobban_runonce if (!length(jobban_keylist)) jobban_keylist=list() @@ -57,7 +49,7 @@ var/jobban_keylist[0] //to store the keys & ranks if(!establish_db_connection()) error("Database connection failed. Reverting to the legacy ban system.") log_misc("Database connection failed. Reverting to the legacy ban system.") - config.ban_legacy_system = 1 + set_config_value(/decl/config/toggle/on/ban_legacy_system, TRUE) jobban_loadbanfile() return @@ -83,7 +75,7 @@ var/jobban_keylist[0] //to store the keys & ranks /proc/jobban_savebanfile() var/savefile/S=new("data/job_full.ban") - S["keys[0]"] << jobban_keylist + to_savefile(S, "keys[0]", jobban_keylist) /proc/jobban_unban(mob/M, rank) jobban_remove("[M.ckey] - [rank]") diff --git a/code/modules/admin/buildmode/__click_handler.dm b/code/modules/admin/buildmode/__click_handler.dm new file mode 100644 index 000000000000..fcb7bb91f8b6 --- /dev/null +++ b/code/modules/admin/buildmode/__click_handler.dm @@ -0,0 +1,66 @@ +/datum/click_handler/build_mode + flags = CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT | CLICK_HANDLER_REMOVE_IF_NOT_TOP + var/direction + + var/list/build_modes + var/list/build_buttons + var/timer_handle + + var/datum/build_mode/current_build_mode + +/datum/click_handler/build_mode/New(var/mob/user) + ..() + + build_modes = list() + for(var/mode_type in subtypesof(/datum/build_mode)) + var/datum/build_mode/build_mode = new mode_type(src) + build_modes += build_mode + if(build_mode.the_default) + current_build_mode = build_mode + + build_buttons = list() + for(var/button_type in subtypesof(/obj/effect/bmode)) + var/obj/effect/bmode/build_button = new button_type(null, src) + build_buttons += build_button + StartTimer() + current_build_mode.Selected() + to_chat(user, "Build Mode Enabled") + +/datum/click_handler/build_mode/Destroy() + current_build_mode.Unselected() + StopTimer() + QDEL_NULL(current_build_mode) + QDEL_NULL_LIST(build_modes) + QDEL_NULL_LIST(build_buttons) + to_chat(user, "Build Mode Disabled") + . = ..() + +/datum/click_handler/build_mode/proc/StartTimer() + timer_handle = addtimer(CALLBACK(src, PROC_REF(TimerEvent)), 1 SECOND, TIMER_UNIQUE | TIMER_STOPPABLE | TIMER_LOOP) + +/datum/click_handler/build_mode/proc/StopTimer() + deltimer(timer_handle) + +/datum/click_handler/build_mode/proc/TimerEvent() + current_build_mode.TimerEvent() + +/datum/click_handler/build_mode/Enter() + user.client.show_popup_menus = FALSE + for(var/build_button in build_buttons) + user.client.screen += build_button + +/datum/click_handler/build_mode/Exit() + user.my_client.show_popup_menus = TRUE + for(var/build_button in build_buttons) + user.my_client.screen -= build_button + +/datum/click_handler/build_mode/OnDblClick(var/atom/A, var/params) + OnClick(A, params) // We treat double-clicks as normal clicks + +/datum/click_handler/build_mode/OnClick(var/atom/A, var/params) + params = params2list(params) + if(A in build_buttons) + var/obj/effect/bmode/build_button = A + build_button.OnClick(params) + else + current_build_mode.OnClick(A, params) diff --git a/code/modules/admin/buildmode/_build_mode.dm b/code/modules/admin/buildmode/_build_mode.dm new file mode 100644 index 000000000000..d807f8dfbeae --- /dev/null +++ b/code/modules/admin/buildmode/_build_mode.dm @@ -0,0 +1,88 @@ +/datum/build_mode + var/the_default = FALSE + var/name + var/icon_state + var/datum/click_handler/build_mode/host + var/mob/user + var/list/click_interactions + var/static/help_row_length = 80 + var/build_type + +/datum/build_mode/New(var/host) + ..() + src.host = host + user = src.host.user + for(var/click_type in click_interactions) + click_interactions += GET_DECL(click_type) + click_interactions -= click_type + +/datum/build_mode/Destroy() + host = null + . = ..() + +/datum/build_mode/proc/SetBuildType(var/atom_type) + if(!atom_type || atom_type == build_type) + return + var/atom/atom_prototype = atom_type + if(ispath(atom_type, /atom) && TYPE_IS_SPAWNABLE(atom_prototype)) + build_type = atom_type + to_chat(user, SPAN_NOTICE("Will now construct instances of the type [atom_type].")) + else + to_chat(user, SPAN_WARNING("Cannot construct instances of type [atom_type].")) + +/datum/build_mode/proc/OnClick(var/atom/A, var/list/parameters) + if(!istype(A)) + return FALSE + parameters = parameters || list() + for(var/decl/build_mode_interaction/click_interaction in click_interactions) + if(click_interaction.CanInvoke(src, A, parameters)) + return click_interaction.Invoke(src, A, parameters) + return FALSE + +/datum/build_mode/proc/Configurate() + return + +/datum/build_mode/proc/Help() + var/asterisks = repeatstring("*", help_row_length) + to_chat(user, SPAN_NOTICE(asterisks)) + if(length(click_interactions)) + for(var/decl/build_mode_interaction/click_interaction in click_interactions) + to_chat(user, SPAN_NOTICE("[click_interaction.name][repeatstring(" ", help_row_length - (3+length_char(click_interaction.name)+length_char(click_interaction.description)))] = [click_interaction.description]")) + else + to_chat(user, SPAN_NOTICE("No click interactions for this mode!")) + ShowAdditionalHelpText() + to_chat(user, SPAN_NOTICE(asterisks)) + +/datum/build_mode/proc/ShowAdditionalHelpText() + return + +/datum/build_mode/proc/Selected() + return + +/datum/build_mode/proc/Unselected() + return + +/datum/build_mode/proc/TimerEvent() + return + +/datum/build_mode/proc/Log(message) + log_admin("BUILD MODE - [name] - [key_name(usr)] - [message]") + +/datum/build_mode/proc/Warn(message) + to_chat(user, "BUILD MODE - [name] - [message])") + +/datum/build_mode/proc/select_subpath(given_path, within_scope = /atom) + var/desired_path = input("Enter full or partial typepath.","Typepath","[given_path]") as text|null + if(!desired_path) + return + var/list/types = typesof(within_scope) + var/list/matches = list() + for(var/path in types) + if(findtext("[path]", desired_path)) + matches += path + if(!matches.len) + alert("No results found. Sorry.") + return + if(matches.len==1) + return matches[1] + return (input("Select a type", "Select Type", matches[1]) as null|anything in matches) diff --git a/code/modules/admin/buildmode/_build_mode_buttons.dm b/code/modules/admin/buildmode/_build_mode_buttons.dm new file mode 100644 index 000000000000..a4e633f7fd4e --- /dev/null +++ b/code/modules/admin/buildmode/_build_mode_buttons.dm @@ -0,0 +1,74 @@ +/obj/effect/bmode + density = TRUE + anchored = TRUE + plane = HUD_PLANE + layer = HUD_BASE_LAYER + icon = 'icons/misc/buildmode.dmi' + is_spawnable_type = FALSE + var/datum/click_handler/build_mode/host + +/obj/effect/bmode/Initialize(mapload, _host) + . = ..(mapload) + host = _host + +/obj/effect/bmode/Destroy() + host = null + . = ..() + +/obj/effect/bmode/proc/OnClick(var/list/params) + return + +/obj/effect/bmode/dir + icon_state = "build" + screen_loc = "TOP,LEFT" + +/obj/effect/bmode/dir/Initialize() + . = ..() + set_dir(host.direction) + +/obj/effect/bmode/dir/OnClick(var/list/parameters) + switch(dir) + if(SOUTH) + set_dir(WEST) + if(WEST) + set_dir(NORTH) + if(NORTH) + set_dir(EAST) + if(EAST) + set_dir(NORTHWEST) + else + set_dir(SOUTH) + host.direction = dir + +/obj/effect/bmode/help + icon_state = "buildhelp" + screen_loc = "TOP,LEFT+1" + +/obj/effect/bmode/help/OnClick() + host.current_build_mode.Help() + +/obj/effect/bmode/mode + screen_loc = "TOP,LEFT+2" + +/obj/effect/bmode/mode/Initialize() + . = ..() + icon_state = host.current_build_mode.icon_state + +/obj/effect/bmode/mode/OnClick(var/list/parameters) + if(parameters["left"]) + var/datum/build_mode/build_mode = input("Select build mode", "Select build mode", host.current_build_mode) as null|anything in host.build_modes + if(build_mode && host && (build_mode in host.build_modes)) + host.current_build_mode.Unselected() + build_mode.Selected() + host.current_build_mode = build_mode + icon_state = build_mode.icon_state + to_chat(usr, SPAN_NOTICE("Build mode '[host.current_build_mode]' selected.")) + else if(parameters["right"]) + host.current_build_mode.Configurate() + +/obj/effect/bmode/quit + icon_state = "buildquit" + screen_loc = "TOP,LEFT+3" + +/obj/effect/bmode/quit/OnClick() + usr.RemoveClickHandler(/datum/click_handler/build_mode) diff --git a/code/modules/admin/buildmode/_build_mode_interactions.dm b/code/modules/admin/buildmode/_build_mode_interactions.dm new file mode 100644 index 000000000000..5fa7a59e2ff5 --- /dev/null +++ b/code/modules/admin/buildmode/_build_mode_interactions.dm @@ -0,0 +1,60 @@ +/decl/build_mode_interaction + abstract_type = /decl/build_mode_interaction + var/name + var/description + var/dummy_interaction = FALSE + var/strict_parameter_check = TRUE + var/list/trigger_params + var/static/list/all_parameters = list( + "left" = "Left Click", + "right" = "Right Click", + "middle" = "Middle Click", + "ctrl" = "Ctrl", + "alt" = "Alt" + ) + +/decl/build_mode_interaction/Initialize() + . = ..() + if(isnull(name)) + var/list/param_strings = list() + for(var/param in trigger_params) + param_strings += all_parameters[param] || capitalize(param) + name = jointext(param_strings, " + ") + +/decl/build_mode_interaction/validate() + . = ..() + if(!dummy_interaction) + if(length(trigger_params)) + for(var/param in trigger_params) + if(!(param in all_parameters)) + . += "invalid parameter: [param]" + else + . += "null or empty parameter list" + + if(!istext(name)) + . += "null or invalid name: [name || "NULL"]" + + if(!istext(description)) + . += "null or invalid description: [description || "NULL"]" + +/decl/build_mode_interaction/proc/CanInvoke(datum/build_mode/build_mode, atom/A, list/parameters) + + if(dummy_interaction) + return FALSE + + // Simple check for missing parameters. + for(var/parameter in trigger_params) + if(!parameters[parameter]) + return FALSE + + // More involved check for overlapping parameter sets. + if(strict_parameter_check) + for(var/parameter in parameters) + if((parameter in all_parameters) && !(parameter in trigger_params)) + return FALSE + + // Success! + return TRUE + +/decl/build_mode_interaction/proc/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + return FALSE diff --git a/code/modules/admin/buildmode/advance.dm b/code/modules/admin/buildmode/advance.dm deleted file mode 100644 index 69031c209315..000000000000 --- a/code/modules/admin/buildmode/advance.dm +++ /dev/null @@ -1,46 +0,0 @@ -/datum/build_mode/advanced - name = "Advanced" - icon_state = "buildmode2" - var/build_type - -/datum/build_mode/advanced/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click = Create objects") - to_chat(user, "Right Click = Delete objects") - to_chat(user, "Left Click + Ctrl = Capture object type") - to_chat(user, "Middle Click = Capture object type") - to_chat(user, "Right Click on Build Mode Button = Select object type") - to_chat(user, "") - to_chat(user, "Use the directional button in the upper left corner to") - to_chat(user, "change the direction of built objects.") - to_chat(user, "***********************************************************") - -/datum/build_mode/advanced/Configurate() - SetBuildType(select_subpath(build_type || /obj/structure/closet)) - -/datum/build_mode/advanced/OnClick(var/atom/A, var/list/parameters) - if(parameters["left"] && !parameters["ctrl"]) - if(ispath(build_type,/turf)) - var/turf/T = get_turf(A) - T.ChangeTurf(build_type) - else if(ispath(build_type)) - var/atom/new_atom = new build_type (get_turf(A)) - new_atom.set_dir(host.direction) - Log("Created - [log_info_line(new_atom)]") - else - to_chat(user, "Select a type to construct.") - else if(parameters["right"]) - Log("Deleted - [log_info_line(A)]") - qdel(A) - else if((parameters["left"] && parameters["ctrl"]) || parameters["middle"]) - SetBuildType(A.type) - -/datum/build_mode/advanced/proc/SetBuildType(var/atom_type) - if(!atom_type || atom_type == build_type) - return - - if(ispath(atom_type, /atom)) - build_type = atom_type - to_chat(user, "Will now construct instances of the type [atom_type].") - else - to_chat(user, "Cannot construct instances of type [atom_type].") diff --git a/code/modules/admin/buildmode/areas.dm b/code/modules/admin/buildmode/areas.dm deleted file mode 100644 index 63ea93a7d440..000000000000 --- a/code/modules/admin/buildmode/areas.dm +++ /dev/null @@ -1,112 +0,0 @@ -/datum/build_mode/areas - name = "Area Editor" - icon_state = "buildmode10" - var/help_text = {"\ -********* Build Mode: Areas ******** -Left Click - Set Turf Area -Left Click + Ctrl - Copy Turf Area -Middle Click - Copy Turf Area -Right Click - List/Create Area -************************************\ -"} - var/list/distinct_colors = list( - "#e6194b", "#3cb44b", "#ffe119", "#4363d8", "#f58231", "#42d4f4", - "#f032e6", "#fabebe", "#469990", "#e6beff", "#9a6324", "#fffac8", - "#800000", "#aaffc3", "#000075", "#a9a9a9", "#ffffff", "#000000" - ) - var/area/selected_area - var/list/vision_images = list() - -/datum/build_mode/areas/Destroy() - UnselectArea() - Unselected() - . = ..() - -/datum/build_mode/areas/Help() - to_chat(user, SPAN_NOTICE(help_text)) - -/datum/build_mode/areas/OnClick(var/atom/A, var/list/parameters) - if (parameters["right"]) - Configurate() - return - var/turf/T = get_turf(A) - var/area/R = T?.loc - if ((!T) || (!R)) - return - if (parameters["ctrl"] || parameters["middle"]) - selected_area = R - to_chat(user, "Picked area [selected_area.name]") - else if (selected_area) - ChangeArea(T, selected_area) - to_chat(user, "Set area of turf [T.name] to [selected_area.name]") - else - to_chat(user, "Pick or create an area first") - -/datum/build_mode/areas/Configurate() - var/mode = alert("Pick or Create an area.", "Build Mode: Areas", "Pick", "Create", "Cancel") - if (mode == "Pick") - var/area/path = select_subpath((selected_area?.type || /area/space), /area) - if (path) - for (var/area/R in world) - if (R.type == path) - SelectArea(R) - to_chat(user, "Picked area [selected_area.name]") - break - else if (mode == "Create") - var/new_name = input("New area name:", "Build Mode: Areas") as text|null - if (!new_name) - return - var/area/new_area = new - new_area.SetName(new_name) - new_area.power_equip = 0 - new_area.power_light = 0 - new_area.power_environ = 0 - new_area.always_unpowered = 0 - SelectArea(new_area) - user.client.debug_variables(selected_area) - to_chat(user, "Created area [new_area.name]") - -/datum/build_mode/areas/TimerEvent() - user.client.images -= vision_images - vision_images = list() - - var/used_colors = 0 - var/list/max_colors = length(distinct_colors) - var/list/vision_colors = list() - for (var/turf/T in range(get_effective_view(user.client), user)) - var/image/I = new('icons/turf/overlays.dmi', T, "whiteOverlay") - var/ref = "\ref[T.loc]" - if (!vision_colors[ref]) - if (++used_colors > max_colors) - vision_colors[ref] = "#" + copytext(md5(ref), 1, 7) - else - vision_colors[ref] = distinct_colors[used_colors] - I.color = vision_colors[ref] - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM|NO_CLIENT_COLOR|KEEP_APART - vision_images.Add(I) - user.client.images += vision_images - -/datum/build_mode/areas/Unselected() - user.client.images -= vision_images - vision_images = list() - -/datum/build_mode/areas/proc/SelectArea(var/area/A) - if(!A || A == selected_area) - return - UnselectArea() - selected_area = A - GLOB.destroyed_event.register(selected_area, src, .proc/UnselectArea) - -/datum/build_mode/areas/proc/UnselectArea() - if(!selected_area) - return - GLOB.destroyed_event.unregister(selected_area, src, .proc/UnselectArea) - - var/has_turf = FALSE - for(var/turf/T in selected_area) - has_turf = TRUE - break - if(!has_turf) - qdel(selected_area) - selected_area = null diff --git a/code/modules/admin/buildmode/basic.dm b/code/modules/admin/buildmode/basic.dm deleted file mode 100644 index 263c629ff62f..000000000000 --- a/code/modules/admin/buildmode/basic.dm +++ /dev/null @@ -1,60 +0,0 @@ -/datum/build_mode/basic - the_default = TRUE - name = "Basic" - icon_state = "buildmode1" - -/datum/build_mode/basic/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click = Construct / Upgrade") - to_chat(user, "Right Click = Deconstruct / Delete / Downgrade") - to_chat(user, "Left Click + Ctrl = R-Window") - to_chat(user, "Left Click + Alt = Airlock") - to_chat(user, "") - to_chat(user, "Use the directional button in the upper left corner to") - to_chat(user, "change the direction of built objects.") - to_chat(user, "***********************************************************") - -/datum/build_mode/basic/OnClick(var/atom/object, var/list/pa) - if(istype(object,/turf) && pa["left"] && !pa["alt"] && !pa["ctrl"] ) - if(istype(object,/turf/space)) - var/turf/T = object - Log("Upgraded - [log_info_line(object)]") - T.ChangeTurf(/turf/simulated/floor) - return - else if(istype(object,/turf/simulated/floor)) - var/turf/T = object - Log("Upgraded - [log_info_line(object)]") - T.ChangeTurf(/turf/simulated/wall) - return - else if(istype(object,/turf/simulated/wall)) - var/turf/T = object - Log("Upgraded - [log_info_line(object)]") - T.ChangeTurf(/turf/simulated/wall/r_wall) - return - else if(pa["right"]) - if(istype(object,/turf/simulated/wall)) - var/turf/T = object - Log("Downgraded - [log_info_line(object)]") - T.ChangeTurf(/turf/simulated/floor) - return - else if(istype(object,/turf/simulated/floor)) - var/turf/T = object - Log("Downgraded - [log_info_line(object)]") - T.ChangeTurf(/turf/space) - return - else if(istype(object,/turf/simulated/wall/r_wall)) - var/turf/T = object - Log("Downgraded - [log_info_line(object)]") - T.ChangeTurf(/turf/simulated/wall) - return - else if(istype(object,/obj)) - Log("Deleted - [log_info_line(object)]") - qdel(object) - return - else if(istype(object,/turf) && pa["alt"] && pa["left"]) - var/airlock = new/obj/machinery/door/airlock(get_turf(object)) - Log("Created - [log_info_line(airlock)]") - else if(istype(object,/turf) && pa["ctrl"] && pa["left"]) - var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object)) - Log("Created - [log_info_line(object)]") - WIN.set_dir(host.direction) diff --git a/code/modules/admin/buildmode/build_mode.dm b/code/modules/admin/buildmode/build_mode.dm deleted file mode 100644 index c4813ff4c769..000000000000 --- a/code/modules/admin/buildmode/build_mode.dm +++ /dev/null @@ -1,60 +0,0 @@ -/datum/build_mode - var/the_default = FALSE - var/name - var/icon_state - var/datum/click_handler/build_mode/host - var/mob/user - -/datum/build_mode/New(var/host) - ..() - src.host = host - user = src.host.user - -/datum/build_mode/Destroy() - host = null - . = ..() - -/datum/build_mode/proc/OnClick(var/atom/A, var/list/parameters) - return - -/datum/build_mode/proc/Configurate() - return - -/datum/build_mode/proc/Help() - return - -/datum/build_mode/proc/Selected() - return - -/datum/build_mode/proc/Unselected() - return - -/datum/build_mode/proc/TimerEvent() - return - -/datum/build_mode/proc/Log(message) - log_admin("BUILD MODE - [name] - [key_name(usr)] - [message]") - -/datum/build_mode/proc/Warn(message) - to_chat(user, "BUILD MODE - [name] - [message])") - -/datum/build_mode/proc/select_subpath(given_path, within_scope = /atom) - var/desired_path = input("Enter full or partial typepath.","Typepath","[given_path]") as text|null - if(!desired_path) - return - - var/list/types = typesof(within_scope) - var/list/matches = list() - - for(var/path in types) - if(findtext("[path]", desired_path)) - matches += path - - if(!matches.len) - alert("No results found. Sorry.") - return - - if(matches.len==1) - return matches[1] - else - return (input("Select a type", "Select Type", matches[1]) as null|anything in matches) diff --git a/code/modules/admin/buildmode/buttons.dm b/code/modules/admin/buildmode/buttons.dm deleted file mode 100644 index a8a422e01497..000000000000 --- a/code/modules/admin/buildmode/buttons.dm +++ /dev/null @@ -1,73 +0,0 @@ -/obj/effect/bmode - density = 1 - anchored = 1 - plane = HUD_PLANE - layer = HUD_BASE_LAYER - icon = 'icons/misc/buildmode.dmi' - var/datum/click_handler/build_mode/host - -/obj/effect/bmode/Initialize(mapload, _host) - . = ..(mapload) - host = _host - -/obj/effect/bmode/Destroy() - host = null - . = ..() - -/obj/effect/bmode/proc/OnClick(var/list/params) - return - -/obj/effect/bmode/dir - icon_state = "build" - screen_loc = "TOP,LEFT" - -/obj/effect/bmode/dir/Initialize() - . = ..() - set_dir(host.direction) - -/obj/effect/bmode/dir/OnClick(var/list/parameters) - switch(dir) - if(SOUTH) - set_dir(WEST) - if(WEST) - set_dir(NORTH) - if(NORTH) - set_dir(EAST) - if(EAST) - set_dir(NORTHWEST) - else - set_dir(SOUTH) - host.direction = dir - -/obj/effect/bmode/help - icon_state = "buildhelp" - screen_loc = "TOP,LEFT+1" - -/obj/effect/bmode/help/OnClick() - host.current_build_mode.Help() - -/obj/effect/bmode/mode - screen_loc = "TOP,LEFT+2" - -/obj/effect/bmode/mode/Initialize() - . = ..() - icon_state = host.current_build_mode.icon_state - -/obj/effect/bmode/mode/OnClick(var/list/parameters) - if(parameters["left"]) - var/datum/build_mode/build_mode = input("Select build mode", "Select build mode", host.current_build_mode) as null|anything in host.build_modes - if(build_mode && host && (build_mode in host.build_modes)) - host.current_build_mode.Unselected() - build_mode.Selected() - host.current_build_mode = build_mode - icon_state = build_mode.icon_state - to_chat(usr, "Build mode '[host.current_build_mode]' selected.") - else if(parameters["right"]) - host.current_build_mode.Configurate() - -/obj/effect/bmode/quit - icon_state = "buildquit" - screen_loc = "TOP,LEFT+3" - -/obj/effect/bmode/quit/OnClick() - usr.RemoveClickHandler(/datum/click_handler/build_mode) diff --git a/code/modules/admin/buildmode/click_handler.dm b/code/modules/admin/buildmode/click_handler.dm deleted file mode 100644 index 15e20226ed0c..000000000000 --- a/code/modules/admin/buildmode/click_handler.dm +++ /dev/null @@ -1,66 +0,0 @@ -/datum/click_handler/build_mode - flags = CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT | CLICK_HANDLER_REMOVE_IF_NOT_TOP - var/direction - - var/list/build_modes - var/list/build_buttons - var/timer_handle - - var/datum/build_mode/current_build_mode - -/datum/click_handler/build_mode/New(var/mob/user) - ..() - - build_modes = list() - for(var/mode_type in subtypesof(/datum/build_mode)) - var/datum/build_mode/build_mode = new mode_type(src) - build_modes += build_mode - if(build_mode.the_default) - current_build_mode = build_mode - - build_buttons = list() - for(var/button_type in subtypesof(/obj/effect/bmode)) - var/obj/effect/bmode/build_button = new button_type(null, src) - build_buttons += build_button - StartTimer() - current_build_mode.Selected() - to_chat(user, "Build Mode Enabled") - -/datum/click_handler/build_mode/Destroy() - current_build_mode.Unselected() - StopTimer() - QDEL_NULL(current_build_mode) - QDEL_NULL_LIST(build_modes) - QDEL_NULL_LIST(build_buttons) - to_chat(user, "Build Mode Disabled") - . = ..() - -/datum/click_handler/build_mode/proc/StartTimer() - timer_handle = addtimer(CALLBACK(src, .proc/TimerEvent), 1 SECOND, TIMER_UNIQUE | TIMER_STOPPABLE | TIMER_LOOP) - -/datum/click_handler/build_mode/proc/StopTimer() - deltimer(timer_handle) - -/datum/click_handler/build_mode/proc/TimerEvent() - current_build_mode.TimerEvent() - -/datum/click_handler/build_mode/Enter() - user.client.show_popup_menus = FALSE - for(var/build_button in build_buttons) - user.client.screen += build_button - -/datum/click_handler/build_mode/Exit() - user.my_client.show_popup_menus = TRUE - for(var/build_button in build_buttons) - user.my_client.screen -= build_button - -/datum/click_handler/build_mode/OnDblClick(var/atom/A, var/params) - OnClick(A, params) // We treat double-clicks as normal clicks - -/datum/click_handler/build_mode/OnClick(var/atom/A, var/params) - params = params2list(params) - if(A in build_buttons) - var/obj/effect/bmode/build_button = A - build_button.OnClick(params) - else - current_build_mode.OnClick(A, params) diff --git a/code/modules/admin/buildmode/edit.dm b/code/modules/admin/buildmode/edit.dm deleted file mode 100644 index 81e984fddf99..000000000000 --- a/code/modules/admin/buildmode/edit.dm +++ /dev/null @@ -1,74 +0,0 @@ -/datum/build_mode/edit - name = "Edit" - icon_state = "buildmode3" - var/var_to_edit = "name" - var/value_to_set = "derp" - -/datum/build_mode/edit/Destroy() - ClearValue() - . = ..() - -/datum/build_mode/edit/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Right Click on Build Mode Button = Select var & value") - to_chat(user, "Left Click = Sets the var's value") - to_chat(user, "Right Click = Reset the var's value") - to_chat(user, "***********************************************************") - -/datum/build_mode/edit/Configurate() - var/var_name = input("Enter variable name:", "Name", var_to_edit) as text|null - if(!var_name) - return - - var/thetype = input("Select variable type:", "Type") as null|anything in list("text","number","mob-reference","obj-reference","turf-reference") - if(!thetype) return - - var/new_value - switch(thetype) - if("text") - new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as text|null - if("number") - new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as num|null - if("mob-reference") - new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|mob in SSmobs.mob_list - if("obj-reference") - new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|obj in world - if("turf-reference") - new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|turf in world - - if(var_name && new_value) - var_to_edit = var_name - SetValue(new_value) - -/datum/build_mode/edit/OnClick(var/atom/A, var/list/parameters) - if(!A.may_edit_var(usr, var_to_edit)) - return - - var/old_value = A.vars[var_to_edit] - var/new_value - if(parameters["left"]) - new_value = value_to_set - if(parameters["right"]) - new_value = initial(A.vars[var_to_edit]) - - if(old_value == new_value) - return - A.vars[var_to_edit] = new_value - to_chat(user, "Changed the value of [var_to_edit] from '[old_value]' to '[new_value]'.") - Log("[log_info_line(A)] - [var_to_edit] - [old_value] -> [new_value]") - -/datum/build_mode/edit/proc/SetValue(var/new_value) - if(value_to_set == new_value) - return - ClearValue() - value_to_set = new_value - GLOB.destroyed_event.register(value_to_set, src, /datum/build_mode/edit/proc/ClearValue) - -/datum/build_mode/edit/proc/ClearValue(var/feedback) - if(!istype(value_to_set, /datum)) - return - - GLOB.destroyed_event.unregister(value_to_set, src, /datum/build_mode/edit/proc/ClearValue) - value_to_set = initial(value_to_set) - if(feedback) - Warn("The selected reference value was deleted. Default value restored.") diff --git a/code/modules/admin/buildmode/ladders.dm b/code/modules/admin/buildmode/ladders.dm deleted file mode 100644 index 5f0ae0b266d0..000000000000 --- a/code/modules/admin/buildmode/ladders.dm +++ /dev/null @@ -1,27 +0,0 @@ -/datum/build_mode/ladders - name = "Ladders" - icon_state = "buildmode6" - var/turf/ladder_upper - var/turf/ladder_lower - -/datum/build_mode/ladders/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click on Turf = Set as upper ladder loc") - to_chat(user, "Right Click on Turf = Set as lower ladder loc") - to_chat(user, "As soon as both points have been selected, the ladder is created.") - to_chat(user, "***********************************************************") - -/datum/build_mode/ladders/OnClick(var/atom/A, var/list/parameters) - if(parameters["left"]) - ladder_upper = get_turf(A) - to_chat(user, "Defined [ladder_upper] ([ladder_upper.type]) as the upper ladder location.") - if(parameters["right"]) - ladder_lower = get_turf(A) - to_chat(user, "Defined [ladder_lower] ([ladder_lower.type]) as the lower ladder location.") - if(ladder_upper && ladder_lower) - to_chat(user, "Ladder locations set, building ladders.") - Log("Created a ladder between '[log_info_line(ladder_upper)]' and '[log_info_line(ladder_lower)]'.") - new /obj/structure/ladder(ladder_upper) - new /obj/structure/ladder(ladder_lower) - ladder_upper = null - ladder_lower = null diff --git a/code/modules/admin/buildmode/light_maker.dm b/code/modules/admin/buildmode/light_maker.dm deleted file mode 100644 index 354a044b52b7..000000000000 --- a/code/modules/admin/buildmode/light_maker.dm +++ /dev/null @@ -1,39 +0,0 @@ -/datum/build_mode/light_maker - name = "Light Maker" - icon_state = "buildmode8" - - var/light_outer_range = 3 - var/light_max_bright = 3 - var/light_color = COLOR_WHITE - -/datum/build_mode/light_maker/Help() - to_chat(usr, "***********************************************************") - to_chat(usr, "Left Click = Make it glow") - to_chat(usr, "Right Click = Reset glow") - to_chat(usr, "Right Click on Build Mode Button = Change glow properties") - to_chat(usr, "***********************************************************") - -/datum/build_mode/light_maker/Configurate() - var/choice = alert("Change the new light range, power, or color?", "Light Maker", "Range", "Power", "Color", "Cancel") - switch(choice) - if("Range") - var/input = input("New light range.", name, light_outer_range) as null|num - if(input) - light_outer_range = input - if("Power") - var/input = input("New light power, from 0.1 to 1 in decimal increments.", name, light_max_bright) as null|num - if(input) - input = Clamp(input, 0.1, 1) - light_max_bright = input - if("Color") - var/input = input("New light color.", name, light_color) as null|color - if(input) - light_color = input - -/datum/build_mode/light_maker/OnClick(var/atom/A, var/list/parameters) - if(parameters["left"]) - if(A) - A.set_light(light_max_bright, 0.1, light_outer_range, l_color = light_color) - if(parameters["right"]) - if(A) - A.set_light(0, 0, 0, l_color = COLOR_WHITE) diff --git a/code/modules/admin/buildmode/mode_advance.dm b/code/modules/admin/buildmode/mode_advance.dm new file mode 100644 index 000000000000..e32677389fa0 --- /dev/null +++ b/code/modules/admin/buildmode/mode_advance.dm @@ -0,0 +1,62 @@ +/datum/build_mode/advanced + name = "Advanced" + icon_state = "buildmode2" + click_interactions = list( + /decl/build_mode_interaction/advanced/create_objects, + /decl/build_mode_interaction/advanced/delete_objects, + /decl/build_mode_interaction/advanced/capture_object_type, + /decl/build_mode_interaction/advanced/capture_object_type/alt, + /decl/build_mode_interaction/advanced/select_object_type + ) + +/datum/build_mode/advanced/ShowAdditionalHelpText() + to_chat(user, SPAN_NOTICE("Use the directional button in the upper left corner to")) + to_chat(user, SPAN_NOTICE("change the direction of built objects.")) + +/datum/build_mode/advanced/Configurate() + SetBuildType(select_subpath(build_type || /obj/structure/closet)) + +/decl/build_mode_interaction/advanced + abstract_type = /decl/build_mode_interaction/advanced + +/decl/build_mode_interaction/advanced/create_objects + description = "Create objects." + trigger_params = list("left") + +/decl/build_mode_interaction/advanced/create_objects/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + if(ispath(build_mode.build_type, /turf)) + var/turf/T = get_turf(A) + T.ChangeTurf(build_mode.build_type) + return TRUE + if(ispath(build_mode.build_type)) + var/atom/new_atom = new build_mode.build_type(get_turf(A)) + new_atom.set_dir(build_mode.host.direction) + build_mode.Log("Created - [log_info_line(new_atom)]") + return TRUE + to_chat(build_mode.user, SPAN_WARNING("Select a type to construct.")) + return FALSE + +/decl/build_mode_interaction/advanced/delete_objects + description = "Delete objects." + trigger_params = list("right") + +/decl/build_mode_interaction/advanced/delete_objects/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + build_mode.Log("Deleted - [log_info_line(A)]") + qdel(A) + return TRUE + +/decl/build_mode_interaction/advanced/capture_object_type + description = "Capture object type." + trigger_params = list("left", "ctrl") + +/decl/build_mode_interaction/advanced/capture_object_type/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + build_mode.SetBuildType(A.type) + +/decl/build_mode_interaction/advanced/capture_object_type/alt + description = "Capture object type." + trigger_params = list("middle") + +/decl/build_mode_interaction/advanced/select_object_type + name = "Right Click on Build Mode Button" + description = "Select object type" + dummy_interaction = TRUE diff --git a/code/modules/admin/buildmode/mode_areas.dm b/code/modules/admin/buildmode/mode_areas.dm new file mode 100644 index 000000000000..4df3b7e41797 --- /dev/null +++ b/code/modules/admin/buildmode/mode_areas.dm @@ -0,0 +1,155 @@ +/datum/build_mode/areas + name = "Area Editor" + icon_state = "buildmode10" + click_interactions = list( + /decl/build_mode_interaction/areas/set_turf_area, + /decl/build_mode_interaction/areas/copy_turf_area, + /decl/build_mode_interaction/areas/copy_turf_area/alt + ) + + var/static/list/distinct_colors = list( + "#e6194b", + "#3cb44b", + "#ffe119", + "#4363d8", + "#f58231", + "#42d4f4", + "#f032e6", + "#fabebe", + "#469990", + "#e6beff", + "#9a6324", + "#fffac8", + "#800000", + "#aaffc3", + "#000075", + "#a9a9a9", + "#ffffff", + "#000000" + ) + var/area/selected_area + var/list/vision_images = list() + +/datum/build_mode/areas/Destroy() + UnselectArea() + Unselected() + . = ..() + + +/datum/build_mode/areas/Configurate() + var/mode = alert("Pick or Create an area.", "Build Mode: Areas", "Pick", "Create", "Cancel") + if (mode == "Pick") + var/area/path = select_subpath((selected_area?.type || world.area), /area) + if (path) + for (var/area/build_area in global.areas) + if (build_area.type == path) + SelectArea(build_area) + to_chat(user, "Picked area [selected_area.proper_name]") + break + else if (mode == "Create") + var/new_name = input("New area name:", "Build Mode: Areas") as text|null + if (!new_name) + return + var/area/new_area = new + new_area.SetName(new_name) + new_area.power_equip = 0 + new_area.power_light = 0 + new_area.power_environ = 0 + new_area.always_unpowered = FALSE + SelectArea(new_area) + user.client.debug_variables(selected_area) + to_chat(user, "Created area [new_area.proper_name]") + +/datum/build_mode/areas/TimerEvent() + user.client.images -= vision_images + vision_images = list() + + var/used_colors = 0 + var/list/max_colors = length(distinct_colors) + var/list/vision_colors = list() + for (var/turf/T in range(user?.client?.view || world.view, user)) + var/image/I = new('icons/turf/overlays.dmi', T, "whiteOverlay") + var/ref = "\ref[T.loc]" + if (!vision_colors[ref]) + if (++used_colors > max_colors) + vision_colors[ref] = "#" + copytext(md5(ref), 1, 7) + else + vision_colors[ref] = distinct_colors[used_colors] + I.color = vision_colors[ref] + I.plane = ABOVE_LIGHTING_PLANE + I.layer = ABOVE_LIGHTING_LAYER + I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM|NO_CLIENT_COLOR|KEEP_APART + vision_images.Add(I) + user.client.images += vision_images + +/datum/build_mode/areas/Unselected() + user.client.images -= vision_images + vision_images = list() + +/datum/build_mode/areas/proc/SelectArea(var/area/A) + if(!A || A == selected_area) + return + UnselectArea() + selected_area = A + events_repository.register(/decl/observ/destroyed, selected_area, src, PROC_REF(UnselectArea)) + +/datum/build_mode/areas/proc/UnselectArea() + if(!selected_area) + return + events_repository.unregister(/decl/observ/destroyed, selected_area, src, PROC_REF(UnselectArea)) + + var/has_turf = FALSE + for(var/turf/T in selected_area) + has_turf = TRUE + break + if(!has_turf) + qdel(selected_area) + selected_area = null + +/decl/build_mode_interaction/areas + abstract_type = /decl/build_mode_interaction/areas + +/decl/build_mode_interaction/areas/set_turf_area + description = "Set turf area." + trigger_params = list("left") + +/decl/build_mode_interaction/areas/set_turf_area/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/turf/T = get_turf(A) + var/datum/build_mode/areas/area_mode = build_mode + if(!istype(T) || !istype(area_mode)) + return FALSE + if (area_mode.selected_area) + ChangeArea(T, area_mode.selected_area) + to_chat(build_mode.user, SPAN_NOTICE("Set area of turf [T.name] to [area_mode.selected_area.proper_name]")) + return TRUE + to_chat(build_mode.user, SPAN_WARNING("Pick or create an area first")) + return FALSE + +/decl/build_mode_interaction/areas/copy_turf_area + description = "Copy turf area." + trigger_params = list("left", "ctrl") + +/decl/build_mode_interaction/areas/copy_turf_area/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/areas/area_mode = build_mode + if(istype(area_mode)) + area_mode.selected_area = get_area(A) + if(area_mode.selected_area) + to_chat(build_mode.user, SPAN_NOTICE("Picked area [area_mode.selected_area.proper_name]")) + else + to_chat(build_mode.user, SPAN_NOTICE("Cleared selected area.")) + return TRUE + return FALSE + +/decl/build_mode_interaction/areas/copy_turf_area/alt + trigger_params = list("middle") + +/decl/build_mode_interaction/areas/list_or_create_area + description = "List or create area." + trigger_params = list("right") + +/decl/build_mode_interaction/areas/list_or_create_area/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/areas/area_mode = build_mode + if(istype(area_mode)) + area_mode.Configurate() + return TRUE + return FALSE diff --git a/code/modules/admin/buildmode/mode_basic.dm b/code/modules/admin/buildmode/mode_basic.dm new file mode 100644 index 000000000000..778b95434b8b --- /dev/null +++ b/code/modules/admin/buildmode/mode_basic.dm @@ -0,0 +1,74 @@ +/datum/build_mode/basic + the_default = TRUE + name = "Basic" + icon_state = "buildmode1" + click_interactions = list( + /decl/build_mode_interaction/basic/construct, + /decl/build_mode_interaction/basic/deconstruct, + /decl/build_mode_interaction/basic/reinforced_window, + /decl/build_mode_interaction/basic/airlock + ) + +/datum/build_mode/basic/ShowAdditionalHelpText() + to_chat(user, SPAN_NOTICE("Use the directional button in the upper left corner to")) + to_chat(user, SPAN_NOTICE("change the direction of built objects.")) + +/decl/build_mode_interaction/basic + abstract_type = /decl/build_mode_interaction/basic + +/decl/build_mode_interaction/basic/construct + description = "Construct or upgrade." + trigger_params = list("left") + +/decl/build_mode_interaction/basic/construct/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + if(!isturf(A)) + return FALSE + var/turf/click_turf = A + var/change_to = click_turf.get_build_mode_upgrade() + if(change_to && click_turf.type != change_to) + click_turf = click_turf.ChangeTurf(change_to) + build_mode.Log("Upgraded - [log_info_line(click_turf)]") + return TRUE + return FALSE + +/decl/build_mode_interaction/basic/deconstruct + description = "Deconstruct, downgrade or delete." + trigger_params = list("right") + +/decl/build_mode_interaction/basic/deconstruct/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + if(isturf(A)) + var/turf/click_turf = A + var/change_to = click_turf.get_build_mode_downgrade() + if(change_to && click_turf.type != change_to) + click_turf = click_turf.ChangeTurf(change_to) + build_mode.Log("Downgraded - [log_info_line(click_turf)]") + return TRUE + else if(isobj(A)) + build_mode.Log("Deleted - [log_info_line(A)]") + qdel(A) + return TRUE + return FALSE + +/decl/build_mode_interaction/basic/reinforced_window + description = "Place reinforced window." + trigger_params = list("left", "ctrl") + +/decl/build_mode_interaction/basic/reinforced_window/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/turf/click_turf = get_turf(A) + if(istype(click_turf)) + var/obj/structure/window/reinforced/window = new(click_turf) + window.set_dir(build_mode.host.direction) + build_mode.Log("Created - [log_info_line(window)]") + return TRUE + return FALSE + +/decl/build_mode_interaction/basic/airlock + description = "Place airlock." + trigger_params = list("right", "ctrl") + +/decl/build_mode_interaction/basic/airlock/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/turf/click_turf = get_turf(A) + if(istype(click_turf)) + build_mode.Log("Created - [log_info_line(new /obj/machinery/door/airlock(click_turf))]") + return TRUE + return FALSE diff --git a/code/modules/admin/buildmode/mode_edit.dm b/code/modules/admin/buildmode/mode_edit.dm new file mode 100644 index 000000000000..40f477648ecd --- /dev/null +++ b/code/modules/admin/buildmode/mode_edit.dm @@ -0,0 +1,95 @@ +/datum/build_mode/edit + name = "Edit" + icon_state = "buildmode3" + click_interactions = list( + /decl/build_mode_interaction/edit/select_var_and_value, + /decl/build_mode_interaction/edit/set_var_value, + /decl/build_mode_interaction/edit/set_var_value/reset + ) + var/var_to_edit = "name" + var/value_to_set = "val" + +/datum/build_mode/edit/Destroy() + ClearValue() + . = ..() + +/datum/build_mode/edit/Configurate() + var/var_name = input("Enter variable name:", "Name", var_to_edit) as text|null + if(!var_name) + return + + var/thetype = input("Select variable type:", "Type") as null|anything in list("text","number","mob-reference","obj-reference","turf-reference") + if(!thetype) return + + var/new_value + switch(thetype) + if("text") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as text|null + if("number") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as num|null + if("mob-reference") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|mob in SSmobs.mob_list + if("obj-reference") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|obj in world + if("turf-reference") + new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|turf in world + + if(var_name && new_value) + var_to_edit = var_name + SetValue(new_value) + +/datum/build_mode/edit/proc/SetValue(var/new_value) + if(value_to_set == new_value) + return + ClearValue() + value_to_set = new_value + if(istype(value_to_set, /datum)) + events_repository.register(/decl/observ/destroyed, value_to_set, src, TYPE_PROC_REF(/datum/build_mode/edit, ClearValue)) + +/datum/build_mode/edit/proc/ClearValue(var/feedback) + if(!istype(value_to_set, /datum)) + return + + events_repository.unregister(/decl/observ/destroyed, value_to_set, src, TYPE_PROC_REF(/datum/build_mode/edit, ClearValue)) + value_to_set = initial(value_to_set) + if(feedback) + Warn("The selected reference value was deleted. Default value restored.") + +/decl/build_mode_interaction/edit + abstract_type = /decl/build_mode_interaction/edit + +/decl/build_mode_interaction/edit/select_var_and_value + name = "Right Click on Build Mode Button" + description = "Select variable and value." + dummy_interaction = TRUE + +/decl/build_mode_interaction/edit/set_var_value + description = "Set the target's variable to the selected value." + trigger_params = list("left") + +/decl/build_mode_interaction/edit/set_var_value/proc/get_new_val(datum/build_mode/edit/edit_mode, atom/A) + return edit_mode.value_to_set + +/decl/build_mode_interaction/edit/set_var_value/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + + var/datum/build_mode/edit/edit_mode = build_mode + if(!istype(A) || !istype(edit_mode) || !A.may_edit_var(build_mode.user, edit_mode.var_to_edit)) + return FALSE + + var/old_value = A.vars[edit_mode.var_to_edit] + var/new_value = get_new_val(edit_mode, A) + + if(old_value == new_value) + return FALSE + + A.vars[edit_mode.var_to_edit] = new_value + to_chat(build_mode.user, SPAN_NOTICE("Changed the value of [edit_mode.var_to_edit] from '[old_value]' to '[new_value]'.")) + build_mode.Log("[log_info_line(A)] - [edit_mode.var_to_edit] - [old_value] -> [new_value]") + return TRUE + +/decl/build_mode_interaction/edit/set_var_value/reset + description = "Reset the target's variable to default value." + trigger_params = list("right") + +/decl/build_mode_interaction/edit/set_var_value/reset/get_new_val(datum/build_mode/edit/edit_mode, atom/A) + return initial(A.vars[edit_mode.var_to_edit]) diff --git a/code/modules/admin/buildmode/mode_lighting.dm b/code/modules/admin/buildmode/mode_lighting.dm new file mode 100644 index 000000000000..9421b65b8755 --- /dev/null +++ b/code/modules/admin/buildmode/mode_lighting.dm @@ -0,0 +1,58 @@ +/datum/build_mode/lighting + name = "Light Maker" + icon_state = "buildmode8" + click_interactions = list( + /decl/build_mode_interaction/lighting/set_values, + /decl/build_mode_interaction/lighting/clear_values, + /decl/build_mode_interaction/lighting/configure + ) + + var/light_range = 3 + var/light_power = 3 + var/light_color = COLOR_WHITE + +/datum/build_mode/lighting/Configurate() + var/choice = alert("Change the new light range, power, or color?", "Lighting Editor", "Range", "Power", "Color", "Cancel") + switch(choice) + if("Range") + var/input = input("New light range.", name, light_range) as null|num + if(input) + light_range = input + if("Power") + var/input = input("New light power, from 0.1 to 1 in decimal increments.", name, light_power) as null|num + if(input) + input = clamp(input, 0.1, 1) + light_power = input + if("Color") + var/input = input("New light color.", name, light_color) as null|color + if(input) + light_color = input + +/decl/build_mode_interaction/lighting + abstract_type = /decl/build_mode_interaction/lighting + +/decl/build_mode_interaction/lighting/set_values + description = "Apply lighting values to an atom." + trigger_params = list("left") + +/decl/build_mode_interaction/lighting/set_values/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/lighting/light_mode = build_mode + if(istype(A) && istype(light_mode)) + A.set_light(light_mode.light_range, light_mode.light_power, l_color = light_mode.light_color) + return TRUE + return FALSE + +/decl/build_mode_interaction/lighting/clear_values + description = "Clear lighting values from an atom." + trigger_params = list("right") + +/decl/build_mode_interaction/lighting/clear_values/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + if(istype(A)) + A.set_light(0, l_color = COLOR_WHITE) + return TRUE + return FALSE + +/decl/build_mode_interaction/lighting/configure + name = "Right Click on Build Mode Button" + description = "Change glow properties." + dummy_interaction = TRUE diff --git a/code/modules/admin/buildmode/mode_relocate.dm b/code/modules/admin/buildmode/mode_relocate.dm new file mode 100644 index 000000000000..bccd889851cd --- /dev/null +++ b/code/modules/admin/buildmode/mode_relocate.dm @@ -0,0 +1,115 @@ +/datum/build_mode/relocate + name = "Relocate Atom" + icon_state = "buildmode7" + click_interactions = list( + /decl/build_mode_interaction/move_into/select, + /decl/build_mode_interaction/move_into/move, + /decl/build_mode_interaction/move_into/select_subject, + /decl/build_mode_interaction/move_into/move_subject + ) + var/atom/destination + var/atom/movable/to_relocate + +/datum/build_mode/relocate/Destroy() + ClearDestination() + ClearRelocator() + . = ..() + +/datum/build_mode/relocate/proc/SetDestination(var/atom/A) + if(A == destination) + return + ClearDestination() + destination = A + events_repository.register(/decl/observ/destroyed, destination, src, TYPE_PROC_REF(/datum/build_mode/relocate, ClearDestination)) + to_chat(user, SPAN_NOTICE("Will now move targets into \the [destination].")) + +/datum/build_mode/relocate/proc/ClearDestination(var/feedback) + if(!destination) + return + events_repository.unregister(/decl/observ/destroyed, destination, src, TYPE_PROC_REF(/datum/build_mode/relocate, ClearDestination)) + destination = null + if(feedback) + Warn("The selected destination was deleted.") + +/datum/build_mode/relocate/proc/SetRelocator(var/new_relocator) + if(to_relocate == new_relocator) + return + ClearRelocator() + to_relocate = new_relocator + events_repository.register(/decl/observ/destroyed, to_relocate, src, TYPE_PROC_REF(/datum/build_mode/relocate, ClearRelocator)) + to_chat(user, SPAN_NOTICE("Will now be relocating \the [to_relocate].")) + +/datum/build_mode/relocate/proc/ClearRelocator(var/feedback) + if(!to_relocate) + return + events_repository.unregister(/decl/observ/destroyed, to_relocate, src, TYPE_PROC_REF(/datum/build_mode/relocate, ClearRelocator)) + to_relocate = null + if(feedback) + Warn("The selected relocation object was deleted.") + +/decl/build_mode_interaction/move_into + abstract_type = /decl/build_mode_interaction/move_into + +/decl/build_mode_interaction/move_into/select + description = "Select a target destination." + trigger_params = list("left") + +/decl/build_mode_interaction/move_into/select/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/relocate/move_mode = build_mode + if(istype(move_mode) && istype(A)) + move_mode.SetDestination(A) + return TRUE + return FALSE + +/decl/build_mode_interaction/move_into/move + name = "Right Click on Movable Atom" + description = "Move an atom into the target destination." + trigger_params = list("right") + +/decl/build_mode_interaction/move_into/move/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/relocate/move_mode = build_mode + if(!istype(move_mode)) + return FALSE + if(!move_mode.destination) + to_chat(build_mode.user, SPAN_WARNING("No target destination set.")) + return FALSE + if(!ismovable(A)) + to_chat(build_mode.user, SPAN_WARNING("\The [A] must be of type /atom/movable.")) + return FALSE + to_chat(build_mode.user, SPAN_NOTICE("Moved \the [A] into \the [move_mode.destination].")) + build_mode.Log("Moved '[log_info_line(A)]' into '[log_info_line(move_mode.destination)]'.") + var/atom/movable/AM = A + AM.forceMove(move_mode.destination) + return TRUE + +/decl/build_mode_interaction/move_into/select_subject + name = "Left Click and Ctrl on Movable Atom" + description = "Select a movable atom to move into destination." + trigger_params = list("left", "ctrl") + +/decl/build_mode_interaction/move_into/select_subject/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/relocate/move_mode = build_mode + if(istype(move_mode) && ismovable(A)) + move_mode.SetRelocator(A) + return TRUE + return FALSE + +/decl/build_mode_interaction/move_into/move_subject + name = "Right Click and Ctrl on Destination" + description = "Move selected atom into the target." + trigger_params = list("right", "ctrl") + +/decl/build_mode_interaction/move_into/move_subject/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/relocate/move_mode = build_mode + if(!istype(move_mode)) + return FALSE + if(!move_mode.to_relocate) + to_chat(build_mode.user, SPAN_WARNING("You have nothing selected to relocate.")) + return FALSE + var/destination_turf = get_turf(A) + if(!destination_turf) + to_chat(build_mode.user, SPAN_WARNING("Unable to locate destination turf.")) + return FALSE + move_mode.to_relocate.forceMove(destination_turf) + build_mode.Log("Relocated '[log_info_line(move_mode.to_relocate)]' to '[log_info_line(destination_turf)]'") + return TRUE diff --git a/code/modules/admin/buildmode/mode_room_builder.dm b/code/modules/admin/buildmode/mode_room_builder.dm new file mode 100644 index 000000000000..2090f13a3df7 --- /dev/null +++ b/code/modules/admin/buildmode/mode_room_builder.dm @@ -0,0 +1,124 @@ +/datum/build_mode/room_builder + name = "Room Builder" + icon_state = "buildmode5" + click_interactions = list( + /decl/build_mode_interaction/room_builder/configure, + /decl/build_mode_interaction/room_builder/set_corner/point_a, + /decl/build_mode_interaction/room_builder/set_corner/point_b + ) + var/turf/coordinate_A + var/turf/coordinate_B + var/floor_type = /turf/floor/plating + var/wall_type = /turf/wall + +/datum/build_mode/room_builder/ShowAdditionalHelpText() + to_chat(user, SPAN_NOTICE("As soon as both points have been selected, the room is created.")) + +/datum/build_mode/room_builder/Configurate() + var/choice = alert("Would you like to set the floor or wall type?", name, "Floor", "Wall", "Cancel") + switch(choice) + if("Floor") + floor_type = select_subpath(floor_type) || floor_type + to_chat(user, SPAN_NOTICE("Floor type set to [floor_type].")) + if("Wall") + wall_type = select_subpath(wall_type) || wall_type + to_chat(user, SPAN_NOTICE("Wall type set to [wall_type].")) + +/datum/build_mode/room_builder/proc/make_rectangle(var/turf/A, var/turf/B, var/turf/wall_type, var/turf/floor_type) + if(!A || !B) // No coords + return + if(A.z != B.z) // Not same z-level + return + + var/height = A.y - B.y + var/width = A.x - B.x + var/z_level = A.z + + var/turf/lower_left_corner = null + // First, try to find the lowest part + var/desired_y = 0 + if(A.y <= B.y) + desired_y = A.y + else + desired_y = B.y + + //Now for the left-most part. + var/desired_x = 0 + if(A.x <= B.x) + desired_x = A.x + else + desired_x = B.x + + lower_left_corner = locate(desired_x, desired_y, z_level) + + // Now we can begin building the actual room. This defines the boundries for the room. + var/low_bound_x = lower_left_corner.x + var/low_bound_y = lower_left_corner.y + + var/high_bound_x = lower_left_corner.x + abs(width) + var/high_bound_y = lower_left_corner.y + abs(height) + + for(var/i = low_bound_x, i <= high_bound_x, i++) + for(var/j = low_bound_y, j <= high_bound_y, j++) + var/turf/T = locate(i, j, z_level) + if(i == low_bound_x || i == high_bound_x || j == low_bound_y || j == high_bound_y) + if(ispath(wall_type, /turf)) + T.ChangeTurf(wall_type) + else + new wall_type(T) + else + if(ispath(floor_type, /turf)) + T.ChangeTurf(floor_type) + else + new floor_type(T) + +/decl/build_mode_interaction/room_builder + abstract_type = /decl/build_mode_interaction/room_builder + +/decl/build_mode_interaction/room_builder/configure + name = "Right Click on Build Mode Button" + description = "Change floor or wall type." + dummy_interaction = TRUE + +/decl/build_mode_interaction/room_builder/set_corner + abstract_type = /decl/build_mode_interaction/room_builder/set_corner + var/point_label + +/decl/build_mode_interaction/room_builder/set_corner/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/room_builder/room_mode = build_mode + var/turf/click_turf = get_turf(A) + if(istype(room_mode) && istype(click_turf)) + set_point(room_mode, click_turf) + return TRUE + return FALSE + +/decl/build_mode_interaction/room_builder/set_corner/Initialize() + description = "Select turf as [point_label]." + return ..() + +/decl/build_mode_interaction/room_builder/set_corner/proc/set_point(datum/build_mode/room_builder/room_mode, turf/point) + to_chat(room_mode.user, SPAN_NOTICE("Defined [point] ([point.type]) as [point_label].")) + if(!room_mode.coordinate_A || !room_mode.coordinate_B) + return TRUE + to_chat(room_mode.user, SPAN_NOTICE("Room coordinates set. Building room.")) + room_mode.make_rectangle(room_mode.coordinate_A, room_mode.coordinate_B, room_mode.wall_type, room_mode.floor_type) + room_mode.Log("Created a room with wall type [room_mode.wall_type] and floor type [room_mode.floor_type] from [log_info_line(room_mode.coordinate_A)] to [log_info_line(room_mode.coordinate_B)]") + room_mode.coordinate_A = null + room_mode.coordinate_B = null + return TRUE + +/decl/build_mode_interaction/room_builder/set_corner/point_a + point_label = "point A" + trigger_params = list("left") + +/decl/build_mode_interaction/room_builder/set_corner/point_a/set_point(datum/build_mode/room_builder/room_mode, turf/point) + room_mode.coordinate_A = point + return ..() + +/decl/build_mode_interaction/room_builder/set_corner/point_b + point_label = "point B" + trigger_params = list("right") + +/decl/build_mode_interaction/room_builder/set_corner/point_b/set_point(datum/build_mode/room_builder/room_mode, turf/point) + room_mode.coordinate_B = point + return ..() diff --git a/code/modules/admin/buildmode/mode_throw_at.dm b/code/modules/admin/buildmode/mode_throw_at.dm new file mode 100644 index 000000000000..3c60b49d65a8 --- /dev/null +++ b/code/modules/admin/buildmode/mode_throw_at.dm @@ -0,0 +1,61 @@ +/datum/build_mode/throw_at + name = "Throw At" + icon_state = "buildmode4" + click_interactions = list( + /decl/build_mode_interaction/throwing/select, + /decl/build_mode_interaction/throwing/throw_at + ) + var/atom/movable/to_throw + +/datum/build_mode/throw_at/Destroy() + ClearThrowable() + . = ..() + +/datum/build_mode/throw_at/proc/SetThrowable(var/new_throwable) + if(to_throw == new_throwable) + return + ClearThrowable() + + to_throw = new_throwable + events_repository.register(/decl/observ/destroyed, to_throw, src, TYPE_PROC_REF(/datum/build_mode/throw_at, ClearThrowable)) + to_chat(user, SPAN_NOTICE("Will now be throwing \the [to_throw].")) + +/datum/build_mode/throw_at/proc/ClearThrowable(var/feedback) + if(!to_throw) + return + + events_repository.unregister(/decl/observ/destroyed, to_throw, src, TYPE_PROC_REF(/datum/build_mode/throw_at, ClearThrowable)) + to_throw = null + if(feedback) + Warn("The selected throwing object was deleted.") + +/decl/build_mode_interaction/throwing + abstract_type = /decl/build_mode_interaction/throwing + +/decl/build_mode_interaction/throwing/select + name = "Left Click on Movable Atom" + description = "Select object to be thrown." + trigger_params = list("left") + +/decl/build_mode_interaction/throwing/select/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/throw_at/throw_mode = build_mode + if(ismovable(A) && istype(throw_mode)) + throw_mode.SetThrowable(A) + return TRUE + return FALSE + +/decl/build_mode_interaction/throwing/throw_at + description = "Throw selected atom at the target." + trigger_params = list("right") + +/decl/build_mode_interaction/throwing/throw_at/Invoke(datum/build_mode/build_mode, atom/A, list/parameters) + var/datum/build_mode/throw_at/throw_mode = build_mode + if(!istype(throw_mode) || !throw_mode.to_throw) + to_chat(build_mode.user, SPAN_WARNING("You have nothing selected to throw.")) + return FALSE + if(!isturf(throw_mode.to_throw.loc)) + to_chat(build_mode.user, SPAN_WARNING("\The [throw_mode.to_throw] is currently not on a turf and cannot be thrown.")) + return FALSE + throw_mode.to_throw.throw_at(A, 10, 1) + build_mode.Log("Threw '[log_info_line(throw_mode.to_throw)]' at '[log_info_line(A)]'") + return TRUE diff --git a/code/modules/admin/buildmode/move_into.dm b/code/modules/admin/buildmode/move_into.dm deleted file mode 100644 index 00d6eb647839..000000000000 --- a/code/modules/admin/buildmode/move_into.dm +++ /dev/null @@ -1,46 +0,0 @@ -/datum/build_mode/move_into - name = "Move Into" - icon_state = "buildmode7" - - var/atom/destination - -/datum/build_mode/move_into/Destroy() - ClearDestination() - . = ..() - -/datum/build_mode/move_into/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click = Select destination") - to_chat(user, "Right Click on Movable Atom = Move target into destination") - to_chat(user, "***********************************************************") - -/datum/build_mode/move_into/OnClick(var/atom/movable/A, var/list/parameters) - if(parameters["left"]) - SetDestination(A) - if(parameters["right"]) - if(!destination) - to_chat(user, "No target destination.") - else if(!ismovable(A)) - to_chat(user, "\The [A] must be of type /atom/movable.") - else - to_chat(user, "Moved \the [A] into \the [destination].") - Log("Moved '[log_info_line(A)]' into '[log_info_line(destination)]'.") - A.forceMove(destination) - -/datum/build_mode/move_into/proc/SetDestination(var/atom/A) - if(A == destination) - return - ClearDestination() - - destination = A - GLOB.destroyed_event.register(destination, src, /datum/build_mode/move_into/proc/ClearDestination) - to_chat(user, "Will now move targets into \the [destination].") - -/datum/build_mode/move_into/proc/ClearDestination(var/feedback) - if(!destination) - return - - GLOB.destroyed_event.unregister(destination, src, /datum/build_mode/move_into/proc/ClearDestination) - destination = null - if(feedback) - Warn("The selected destination was deleted.") diff --git a/code/modules/admin/buildmode/relocate_to.dm b/code/modules/admin/buildmode/relocate_to.dm deleted file mode 100644 index dd275d7cc1f0..000000000000 --- a/code/modules/admin/buildmode/relocate_to.dm +++ /dev/null @@ -1,47 +0,0 @@ -/datum/build_mode/relocate_to - name = "Relocate To" - icon_state = "buildmode9" - var/atom/movable/to_relocate - -/datum/build_mode/relocate_to/Destroy() - ClearRelocator() - . = ..() - -/datum/build_mode/relocate_to/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click on Movable Atom = Select object to be relocated") - to_chat(user, "Right Click on Turf = Destination to be relocated to") - to_chat(user, "***********************************************************") - -/datum/build_mode/relocate_to/OnClick(var/atom/A, var/list/parameters) - if(parameters["left"]) - if(istype(A, /atom/movable)) - SetRelocator(A) - else if(parameters["right"]) - if(to_relocate) - var/destination_turf = get_turf(A) - if(destination_turf) - to_relocate.forceMove(destination_turf) - Log("Relocated '[log_info_line(to_relocate)]' to '[log_info_line(destination_turf)]'") - else - to_chat(user, "Unable to locate destination turf.") - else - to_chat(user, "You have nothing selected to relocate.") - -/datum/build_mode/relocate_to/proc/SetRelocator(var/new_relocator) - if(to_relocate == new_relocator) - return - ClearRelocator() - - to_relocate = new_relocator - GLOB.destroyed_event.register(to_relocate, src, /datum/build_mode/relocate_to/proc/ClearRelocator) - to_chat(user, "Will now be relocating \the [to_relocate].") - -/datum/build_mode/relocate_to/proc/ClearRelocator(var/feedback) - if(!to_relocate) - return - - GLOB.destroyed_event.unregister(to_relocate, src, /datum/build_mode/relocate_to/proc/ClearRelocator) - to_relocate = null - if(feedback) - Warn("The selected relocation object was deleted.") diff --git a/code/modules/admin/buildmode/room_builder.dm b/code/modules/admin/buildmode/room_builder.dm deleted file mode 100644 index 3fe389fe6425..000000000000 --- a/code/modules/admin/buildmode/room_builder.dm +++ /dev/null @@ -1,91 +0,0 @@ -/datum/build_mode/room_builder - name = "Room Builder" - icon_state = "buildmode5" - - var/turf/coordinate_A - var/turf/coordinate_B - - var/floor_type = /turf/simulated/floor/plating - var/wall_type = /turf/simulated/wall - -/datum/build_mode/room_builder/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click on Turf = Select as point A") - to_chat(user, "Right Click on Turf = Select as point B") - to_chat(user, "As soon as both points have been selected, the room is created.") - to_chat(user, "") - to_chat(user, "Right Click on Build Mode Button = Change floor/wall type") - to_chat(user, "***********************************************************") - -/datum/build_mode/room_builder/Configurate() - var/choice = alert("Would you like to set the floor or wall type?", name, "Floor", "Wall", "Cancel") - switch(choice) - if("Floor") - floor_type = select_subpath(floor_type) || floor_type - to_chat(user, "Floor type set to [floor_type].") - if("Wall") - wall_type = select_subpath(wall_type) || wall_type - to_chat(user, "Wall type set to [wall_type].") - -/datum/build_mode/room_builder/OnClick(var/atom/A, var/list/parameters) - if(parameters["left"]) - coordinate_A = get_turf(A) - to_chat(user, "Defined [coordinate_A] ([coordinate_A.type]) as point A.") - if(parameters["right"]) - coordinate_B = get_turf(A) - to_chat(user, "Defined [coordinate_B] ([coordinate_B.type]) as point B.") - - if(coordinate_A && coordinate_B) - to_chat(user, "Room coordinates set. Building room.") - Log("Created a room with wall type [wall_type] and floor type [floor_type] from [log_info_line(coordinate_A)] to [log_info_line(coordinate_B)]") - make_rectangle(coordinate_A, coordinate_B, wall_type, floor_type) - coordinate_A = null - coordinate_B = null - -/datum/build_mode/room_builder/proc/make_rectangle(var/turf/A, var/turf/B, var/turf/wall_type, var/turf/floor_type) - if(!A || !B) // No coords - return - if(A.z != B.z) // Not same z-level - return - - var/height = A.y - B.y - var/width = A.x - B.x - var/z_level = A.z - - var/turf/lower_left_corner = null - // First, try to find the lowest part - var/desired_y = 0 - if(A.y <= B.y) - desired_y = A.y - else - desired_y = B.y - - //Now for the left-most part. - var/desired_x = 0 - if(A.x <= B.x) - desired_x = A.x - else - desired_x = B.x - - lower_left_corner = locate(desired_x, desired_y, z_level) - - // Now we can begin building the actual room. This defines the boundries for the room. - var/low_bound_x = lower_left_corner.x - var/low_bound_y = lower_left_corner.y - - var/high_bound_x = lower_left_corner.x + abs(width) - var/high_bound_y = lower_left_corner.y + abs(height) - - for(var/i = low_bound_x, i <= high_bound_x, i++) - for(var/j = low_bound_y, j <= high_bound_y, j++) - var/turf/T = locate(i, j, z_level) - if(i == low_bound_x || i == high_bound_x || j == low_bound_y || j == high_bound_y) - if(ispath(wall_type, /turf)) - T.ChangeTurf(wall_type) - else - new wall_type(T) - else - if(ispath(floor_type, /turf)) - T.ChangeTurf(floor_type) - else - new floor_type(T) diff --git a/code/modules/admin/buildmode/throw_at.dm b/code/modules/admin/buildmode/throw_at.dm deleted file mode 100644 index 9768e8fe287e..000000000000 --- a/code/modules/admin/buildmode/throw_at.dm +++ /dev/null @@ -1,46 +0,0 @@ -/datum/build_mode/throw_at - name = "Throw At" - icon_state = "buildmode4" - var/atom/movable/to_throw - -/datum/build_mode/throw_at/Destroy() - ClearThrowable() - . = ..() - -/datum/build_mode/throw_at/Help() - to_chat(user, "***********************************************************") - to_chat(user, "Left Click on Movable Atom = Select object to be thrown") - to_chat(user, "Right Click on Atom = Throw at the target") - to_chat(user, "***********************************************************") - -/datum/build_mode/throw_at/OnClick(var/atom/A, var/list/parameters) - if(parameters["left"]) - if(istype(A, /atom/movable)) - SetThrowable(A) - else if(parameters["right"]) - if(to_throw) - if(!isturf(to_throw.loc)) - to_chat(user, "\The [to_throw] is currently not on a turf and cannot be thrown.") - else - to_throw.throw_at(A, 10, 1) - Log("Threw '[log_info_line(to_throw)]' at '[log_info_line(A)]'") - else - to_chat(user, "You have nothing selected to throw.") - -/datum/build_mode/throw_at/proc/SetThrowable(var/new_throwable) - if(to_throw == new_throwable) - return - ClearThrowable() - - to_throw = new_throwable - GLOB.destroyed_event.register(to_throw, src, /datum/build_mode/throw_at/proc/ClearThrowable) - to_chat(user, "Will now be throwing \the [to_throw].") - -/datum/build_mode/throw_at/proc/ClearThrowable(var/feedback) - if(!to_throw) - return - - GLOB.destroyed_event.unregister(to_throw, src, /datum/build_mode/throw_at/proc/ClearThrowable) - to_throw = null - if(feedback) - Warn("The selected throwing object was deleted.") diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm index f9aa6d540154..4cdf5e8c0895 100644 --- a/code/modules/admin/callproc/callproc.dm +++ b/code/modules/admin/callproc/callproc.dm @@ -6,7 +6,7 @@ set name = "Advanced ProcCall" if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return + if(get_config_value(/decl/config/toggle/paranoid) && !check_rights(R_ADMIN)) return var/target = null var/targetselected = 0 @@ -22,7 +22,7 @@ if("Area or Turf") target = input("Select target:", "Target", get_turf(usr)) as null|area|turf in world if("Client") - target = input("Select target:", "Target", usr.client) as null|anything in GLOB.clients + target = input("Select target:", "Target", usr.client) as null|anything in global.clients else return if(!target) @@ -41,7 +41,7 @@ set name = "Advanced ProcCall Target" if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return + if(get_config_value(/decl/config/toggle/paranoid) && !check_rights(R_ADMIN)) return callproc_targetpicked(1, A) @@ -51,7 +51,7 @@ /client/proc/callproc_targetpicked(hastarget, datum/target) // this needs checking again here because VV's 'Call Proc' option directly calls this proc with the target datum if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return + if(get_config_value(/decl/config/toggle/paranoid) && !check_rights(R_ADMIN)) return if(!holder.callproc) holder.callproc = new(src) @@ -120,7 +120,7 @@ return CANCEL switch(input("Type of [arguments.len+1]\th variable", "argument [arguments.len+1]") as null|anything in list( "finished", "null", "text", "num", "type", "obj reference", "mob reference", - "area/turf reference", "icon", "file", "client", "mob's area", "marked datum", "click on atom")) + "area/turf reference", "icon", "file", "client", "mob's area", "path", "marked datum", "click on atom")) if(null) return CANCEL @@ -139,8 +139,12 @@ if(isnull(current)) return CANCEL if("type") - current = input("Select type for [arguments.len+1]\th argument") as null|anything in typesof(/obj, /mob, /area, /turf) - if(isnull(current)) return CANCEL + var/tpath = input("Enter type path for [arguments.len+1]\th argument") as null|text + if(isnull(tpath)) return CANCEL + current = text2path(tpath) + if(!ispath(current)) + to_chat(usr, SPAN_WARNING("Inputed a bad path: '[tpath]'")) + return CANCEL if("obj reference") current = input("Select object for [arguments.len+1]\th argument") as null|obj in world @@ -159,7 +163,7 @@ if(isnull(current)) return CANCEL if("client") - current = input("Select client for [arguments.len+1]\th argument") as null|anything in GLOB.clients + current = input("Select client for [arguments.len+1]\th argument") as null|anything in global.clients if(isnull(current)) return CANCEL if("mob's area") @@ -173,8 +177,13 @@ if("Cancel") return CANCEL + if ("path") + current = text2path(input("Enter path for [arguments.len+1]\th argument") as null|text) + if (isnull(current)) + return CANCEL + if("marked datum") - current = C.holder.marked_datum() + current = C.holder?.marked_datum() if(!current) switch(alert("You do not currently have a marked datum; do you want to pass null instead?",, "Yes", "Cancel")) if("Yes") @@ -202,19 +211,6 @@ holder.callproc.waiting_for_click = 0 holder.callproc.do_args() -/client/Click(atom/A) - if(!user_acted(src)) - return - if(holder && holder.callproc && holder.callproc.waiting_for_click) - if(alert("Do you want to select \the [A] as the [holder.callproc.arguments.len+1]\th argument?",, "Yes", "No") == "Yes") - holder.callproc.arguments += A - - holder.callproc.waiting_for_click = 0 - verbs -= /client/proc/cancel_callproc_select - holder.callproc.do_args() - else - return ..() - /datum/callproc/proc/finalise() var/returnval @@ -229,7 +225,7 @@ returnval = call(target, procname)() else log_admin("[key_name(src)] called [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") - returnval = call(procname)(arglist(arguments)) + returnval = call(text2path("/proc/[procname]"))(arglist(arguments)) to_chat(usr, "[procname]() returned: [json_encode(returnval)]") SSstatistics.add_field_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 7f2eff59ba62..ff0d1a89d0e0 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -1,4 +1,4 @@ -/var/create_mob_html = null +var/global/create_mob_html = null /datum/admins/proc/create_mob(var/mob/user) if (!create_mob_html) var/mobjs = null diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm index c0b6d707c36b..4852f28a58e6 100644 --- a/code/modules/admin/create_object.dm +++ b/code/modules/admin/create_object.dm @@ -1,4 +1,4 @@ -/var/create_object_html = null +var/global/create_object_html = null /datum/admins/proc/create_object(var/mob/user) if (!create_object_html) @@ -13,7 +13,7 @@ /datum/admins/proc/quick_create_object(var/mob/user) var/quick_create_object_html = null - var/path = input("Select the path of the object you wish to create.", "Path", /obj) as null|anything in list(/obj,/obj/structure,/obj/item,/obj/item,/obj/item/clothing,/obj/machinery,/obj/prefab) + var/path = input("Select the path of the object you wish to create.", "Path", /obj) as null|anything in list(/obj,/obj/structure,/obj/item,/obj/item,/obj/item/clothing,/obj/machinery) if(!path) return diff --git a/code/modules/admin/create_turf.dm b/code/modules/admin/create_turf.dm index f25dd7f23d40..3b1420f7624a 100644 --- a/code/modules/admin/create_turf.dm +++ b/code/modules/admin/create_turf.dm @@ -1,4 +1,4 @@ -/var/create_turf_html = null +var/global/create_turf_html = null /datum/admins/proc/create_turf(var/mob/user) if (!create_turf_html) var/turfjs = null diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/dbban/functions.dm similarity index 88% rename from code/modules/admin/DB ban/functions.dm rename to code/modules/admin/dbban/functions.dm index 94dfe5915340..f86f8d0cb4bb 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/dbban/functions.dm @@ -1,4 +1,4 @@ -datum/admins/proc/DB_staffwarn_record(var/ckey, var/reason) +/datum/admins/proc/DB_staffwarn_record(var/ckey, var/reason) if(!check_rights((R_ADMIN|R_MOD), 0)) return if(!istext(reason)) return _DB_staffwarn_record(ckey, reason) @@ -20,13 +20,13 @@ datum/admins/proc/DB_staffwarn_record(var/ckey, var/reason) if(query.NextRow()) playerid = query.item[1] if(playerid == -1) - to_chat(usr,"You've attempted to set staffwarn on [ckey], but they haven't been seen yet. Staffwarn can only be set on existing players.") + to_chat(usr, SPAN_WARNING("You've attempted to set staffwarn on [ckey], but they haven't been seen yet. Staffwarn can only be set on existing players.")) return query = dbcon.NewQuery("UPDATE `erro_player` SET `staffwarn` = '[dbreason]' WHERE `id` = [playerid]") query.Execute() to_chat(usr,"StaffWarn saved to DB") -datum/admins/proc/DB_staffwarn_remove(var/ckey) +/datum/admins/proc/DB_staffwarn_remove(var/ckey) if(!check_rights((R_ADMIN|R_MOD), 0)) return var/dbckey = sql_sanitize_text(ckey) @@ -43,7 +43,7 @@ datum/admins/proc/DB_staffwarn_remove(var/ckey) to_chat(usr,"StaffWarn removed from DB") return 1 -datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) +/datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) if(!src || !src.owner) return _DB_ban_record(src.owner.ckey, src.owner.computer_id, src.owner.address, bantype, banned_mob, duration, reason, job, rounds, banckey, banip, bancid) @@ -91,20 +91,26 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = if(banned_mob.client) computerid = banned_mob.client.computer_id ip = banned_mob.client.address + if (bantype == BANTYPE_PERMA || bantype == BANTYPE_TEMP) + banned_mob.ckey = null else if(banckey) ckey = ckey(banckey) computerid = bancid ip = banip + for (var/mob/M in SSmobs.mob_list) + if (M.ckey == ckey) + M.ckey = null + break var/who - for(var/client/C in GLOB.clients) + for(var/client/C in global.clients) if(!who) who = "[C]" else who += ", [C]" var/adminwho - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(!adminwho) adminwho = "[C]" else @@ -123,7 +129,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") +/datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") if(!check_rights(R_BAN)) return @@ -187,7 +193,7 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") DB_ban_unban_by_id(ban_id) -datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) +/datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) if(!check_rights(R_BAN)) return @@ -247,10 +253,13 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) to_chat(usr, "Cancelled") return -datum/admins/proc/DB_ban_unban_by_id(var/id) +/datum/admins/proc/DB_ban_unban_by_id(var/id) if(!check_rights(R_BAN)) return + if(!owner || !istype(owner, /client)) + return + establish_db_connection() if(!dbcon.IsConnected()) return @@ -265,21 +274,18 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) ban_number++; if(ban_number == 0) - to_chat(usr, "Database update failed due to a ban id not being present in the database.") + to_chat(owner, "Database update failed due to a ban id not being present in the database.") return if(ban_number > 1) - to_chat(usr, "Database update failed due to multiple bans having the same ID. Contact the database admin.") + to_chat(owner, "Database update failed due to multiple bans having the same ID. Contact the database admin.") return - if(!src.owner || !istype(src.owner, /client)) - return + var/unban_ckey = owner.ckey + var/unban_computerid = owner.computer_id + var/unban_ip = owner.address - var/unban_ckey = src.owner:ckey - var/unban_computerid = src.owner:computer_id - var/unban_ip = src.owner:address - - message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1) + message_admins("[key_name_admin(owner)] has lifted [pckey]'s ban.",1) var/DBQuery/query_update = dbcon.NewQuery("UPDATE `erro_ban` SET `unbanned` = TRUE, `unbanned_datetime` = NOW(), `unbanned_ckey` = '[unban_ckey]', `unbanned_computerid` = '[unban_computerid]', `unbanned_ip` = '[unban_ip]' WHERE `id` = [id]") query_update.Execute() @@ -288,7 +294,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) /client/proc/DB_ban_panel() set category = "Admin" set name = "Banning Panel" - set desc = "Edit admin permissions" + set desc = "Allow edit existing bans or create new ones." if(!holder) return @@ -315,7 +321,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) output += "" - output += "
          Add custom ban: (ONLY use this if you can't ban through any other method)" + output += "Add custom ban: (ONLY use this if you can't ban through any other method)" output += "" output += "" output += "
          Ban type:
          " @@ -351,7 +355,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) output += "" output += "" - output += " @@ -212,7 +212,7 @@
          Search:" + output += "" output += "" output += "" @@ -411,13 +415,13 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) if(playercid) cidsearch = "AND `computerid` = '[playercid]' " else - if(adminckey && length(adminckey) >= 3) + if(length(adminckey) >= 3) adminsearch = "AND `a_ckey` LIKE '[adminckey]%' " - if(playerckey && length(playerckey) >= 3) + if(length(playerckey) >= 3) playersearch = "AND `ckey` LIKE '[playerckey]%' " - if(playerip && length(playerip) >= 3) + if(length(playerip) >= 3) ipsearch = "AND `ip` LIKE '[playerip]%' " - if(playercid && length(playercid) >= 7) + if(length(playercid) >= 7) cidsearch = "AND `computerid` LIKE '[playercid]%' " if(dbbantype) @@ -468,15 +472,16 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) dcolor = adcolor var/typedesc ="" + var/mins_readable = minutes_to_readable(duration) switch(bantype) if("PERMABAN") typedesc = "PERMABAN" if("TEMPBAN") - typedesc = "TEMPBAN
          ([duration] minutes) [(unbanned || auto) ? "" : "(Edit)"]
          Expires [expiration]
          " + typedesc = "TEMPBAN
          ([mins_readable]) [(unbanned || auto) ? "" : "(Edit)"]
          Expires [expiration]
          " if("JOB_PERMABAN") typedesc = "JOBBAN
          ([job])" if("JOB_TEMPBAN") - typedesc = "TEMP JOBBAN
          ([job])
          ([duration] minutes
          Expires [expiration]
          " + typedesc = "TEMP JOBBAN
          ([job])
          ([mins_readable]
          Expires [expiration]
          " output += "" output += "" diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 8706e4dbb9b7..0fd178a27422 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -2,7 +2,7 @@ #define STEALTH_MANUAL 1 #define STEALTH_AUTO 2 -var/list/admin_datums = list() +var/global/list/admin_datums = list() /datum/admins var/rank = "Temporary Admin" @@ -26,7 +26,7 @@ var/list/admin_datums = list() error("Admin datum created without a ckey argument. Datum has been deleted") qdel(src) return - admincaster_signature = "[GLOB.using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]" + admincaster_signature = "[global.using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]" rank = initial_rank rights = initial_rights admin_datums[ckey] = src @@ -40,18 +40,18 @@ var/list/admin_datums = list() owner = C owner.holder = src owner.add_admin_verbs() //TODO - GLOB.admins |= C + global.admins |= C /datum/admins/proc/disassociate() if(owner) - GLOB.admins -= owner + global.admins -= owner owner.remove_admin_verbs() owner.deadmin_holder = owner.holder owner.holder = null /datum/admins/proc/reassociate() if(owner) - GLOB.admins += owner + global.admins += owner owner.holder = src owner.deadmin_holder = null owner.add_admin_verbs() @@ -99,7 +99,7 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check if(usr.client.holder.rights != other.holder.rights) if( (usr.client.holder.rights & other.holder.rights) == other.holder.rights ) return 1 //we have all the rights they have and more - to_chat(usr, "Error: Cannot proceed. They have more or equal rights to us.") + to_chat(usr, SPAN_WARNING("Error: Cannot proceed. They have more or equal rights to us.")) return 0 /client/proc/deadmin() @@ -121,7 +121,8 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check if(!holder) return FALSE - var/auto_stealth = (inactivity >= world.time) || (config.autostealth && (inactivity >= MinutesToTicks(config.autostealth))) + var/config_autostealth = get_config_value(/decl/config/num/autostealth) + var/auto_stealth = (inactivity >= world.time) || (config_autostealth && (inactivity >= config_autostealth MINUTES)) // If someone has been AFK since round-start or longer, stealth them // BYOND keeps track of inactivity between rounds as long as it's not a full stop/start. if(holder.stealthy_ == STEALTH_OFF && auto_stealth) @@ -131,9 +132,6 @@ NOTE: It checks usr by default. Supply the "user" argument if you wish to check holder.stealthy_ = STEALTH_OFF return holder.stealthy_ -/mob/proc/is_stealthed() - return client && client.is_stealthed() - /client/proc/stealth() set category = "Admin" set name = "Stealth Mode" diff --git a/code/modules/admin/holoverbs.dm b/code/modules/admin/holoverbs.dm index c057cb497105..97fc22616a48 100644 --- a/code/modules/admin/holoverbs.dm +++ b/code/modules/admin/holoverbs.dm @@ -1,5 +1,5 @@ -/datum/admins/proc/ai_hologram_set(mob/appear as mob in world) +/datum/admins/proc/ai_hologram_set(mob/appear as mob in global.living_mob_list_) set name = "Set AI Hologram" set desc = "Set an AI's hologram to a mob. Use this verb on the mob you want the hologram to look like." set category = "Fun" @@ -13,33 +13,12 @@ var/mob/living/silicon/ai/AI = input("Which AI do you want to apply [appear] to as a hologram?") as null|anything in AIs if(!AI) return - var/image/I = image(appear.icon, appear.icon_state) - I.overlays = appear.overlays - I.underlays = appear.underlays - I.color = list( - 0.30, 0.30, 0.30, 0.0, // Greyscale and reduce the alpha of the icon - 0.59, 0.59, 0.59, 0.0, - 0.11, 0.11, 0.11, 0.0, - 0.00, 0.00, 0.00, 0.5, - 0.00, 0.00, 0.00, 0.0 - ) - var/image/scan = image('icons/effects/effects.dmi', "scanline") - scan.color = list( - 0.30,0.30,0.30,0.00, // Greyscale the scanline icon too - 0.59,0.59,0.59,0.00, - 0.11,0.11,0.11,0.00, - 0.00,0.00,0.00,1.00, - 0.00,0.00,0.00,0.00 - ) - scan.blend_mode = BLEND_MULTIPLY - - // Combine the mob image and the scanlines into a single KEEP_TOGETHER'd image - var/image/I2 = image(null) - I2.underlays += I - I2.overlays += scan - I2.appearance_flags = KEEP_TOGETHER - I2.color = rgb(125, 180, 225) // make it blue! - AI.holo_icon = I2 + var/icon/character_icon = getFlatIcon(appear) + if(character_icon) + qdel(AI.holo_icon)//Clear old icon so we're not storing it in memory. + qdel(AI.holo_icon_longrange) + AI.holo_icon = getHologramIcon(icon(character_icon), custom_tone = AI.custom_color_tone) + AI.holo_icon_longrange = getHologramIcon(icon(character_icon), hologram_color = HOLOPAD_LONG_RANGE) to_chat(AI, "Your hologram icon has been set to [appear].") log_and_message_admins("set [key_name(AI)]'s hologram icon to [key_name(appear)]") diff --git a/code/modules/admin/map_capture.dm b/code/modules/admin/map_capture.dm index 4e3c79312128..903aed3dc5e2 100644 --- a/code/modules/admin/map_capture.dm +++ b/code/modules/admin/map_capture.dm @@ -4,7 +4,7 @@ set desc = "Usage: Capture-Map-Part target_x_cord target_y_cord target_z_cord range (captures part of a map originating from bottom left corner)" if(!check_rights(R_ADMIN|R_DEBUG|R_SERVER)) - to_chat(usr, "You are not allowed to use this command") + to_chat(usr, "You are not allowed to use this command.") return if(isnull(tx) || isnull(ty) || isnull(tz) || isnull(range)) @@ -21,7 +21,7 @@ var/ligths = 0 if(alert("Do you want lighting to be included in capture?", "Map Capture", "No", "Yes") == "Yes") ligths = 1 - var/cap = generate_image(tx ,ty ,tz ,range, CAPTURE_MODE_PARTIAL, null, ligths, 1) + var/cap = create_area_image(tx ,ty ,tz, range, ligths) var/file_name = "map_capture_x[tx]_y[ty]_z[tz]_r[range].png" to_chat(usr, "Saved capture in cache as [file_name].") send_rsc(usr, cap, file_name) @@ -30,7 +30,7 @@ /datum/admins/proc/capture_map_capture_next(currentz, currentx, currenty, ligths) if(locate(currentx, currenty, currentz)) - var/cap = generate_image(currentx ,currenty ,currentz ,32, CAPTURE_MODE_PARTIAL, null, ligths, 1) + var/cap = create_area_image(currentx,currenty, currentz, 32, ligths) var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r32.png" to_chat(usr, "Saved capture in cache as [file_name].") send_rsc(usr, cap, file_name) @@ -41,7 +41,7 @@ currenty = currenty + 32 currentx = 1 if(locate(currentx, currenty, currentz)) - var/cap = generate_image(currentx ,currenty ,currentz ,32, CAPTURE_MODE_PARTIAL, null, ligths, 1) + var/cap = create_area_image(currentx,currenty, currentz, 32, ligths) var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r32.png" to_chat(usr, "Saved capture in cache as [file_name].") send_rsc(usr, cap, file_name) @@ -57,7 +57,7 @@ set desc = "Usage: Capture-Map target_z_cord (captures map)" if(!check_rights(R_ADMIN|R_DEBUG|R_SERVER)) - to_chat(usr, "You are not allowed to use this command") + to_chat(usr, "You are not allowed to use this command.") return if(isnull(tz)) diff --git a/code/modules/admin/panicbunker.dm b/code/modules/admin/panicbunker.dm new file mode 100644 index 000000000000..bd215380d722 --- /dev/null +++ b/code/modules/admin/panicbunker.dm @@ -0,0 +1,35 @@ +var/global/list/panic_bunker_bypass = list() + +/datum/admins/proc/panicbunker() + set category = "Server" + set name = "Toggle Panic Bunker" + + if(!check_rights(R_SERVER)) + return + toggle_config_value(/decl/config/toggle/panic_bunker) + log_and_message_admins("[key_name(usr)] has toggled the Panic Bunker, it is now [(get_config_value(/decl/config/toggle/panic_bunker) ? "on" : "off")]") + if (get_config_value(/decl/config/toggle/panic_bunker) && (!dbcon || !dbcon.IsConnected())) + message_admins("The SQL database is not connected, player age cannot be checked and the panic bunker will not function until the database connection is restored.") + +/datum/admins/proc/addbunkerbypass(ckeytobypass as text) + set category = "Server" + set name = "Add Panic Bunker Bypass" + set desc = "Allows a given ckey to connect despite the panic bunker for a given round." + + if(!check_rights(R_SERVER)) + return + + global.panic_bunker_bypass |= ckey(ckeytobypass) + + log_admin("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.") + message_admins("[key_name_admin(usr)] has added [ckeytobypass] to the current round's bunker bypass list.") + +/datum/admins/proc/revokebunkerbypass(ckeytobypass in global.panic_bunker_bypass) + set category = "Server" + set name = "Revoke Panic Bunker Bypass" + set desc = "Revoke's a ckey's permission to bypass the panic bunker for a given round." + + global.panic_bunker_bypass -= ckey(ckeytobypass) + + log_admin("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.") + message_admins("[key_name_admin(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.") diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm index eb81b27a463e..dde03a14e37d 100644 --- a/code/modules/admin/permissionverbs/permissionedit.dm +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -18,7 +18,7 @@
          Search:" output += "
          Ckey: Admin ckey:
          [typedesc]
          - + "} @@ -31,9 +31,9 @@ if(!rights) rights = "*none*" output += "" - output += "" - output += "" - output += "" + output += "" + output += "" + output += "" output += "" output += {" @@ -45,7 +45,8 @@ show_browser(usr, output, "window=editrights;size=600x500") /datum/admins/proc/log_admin_rank_modification(var/adm_ckey, var/new_rank) - if(config.admin_legacy_system) return + if(get_config_value(/decl/config/toggle/on/admin_legacy_system)) + return if(!usr.client) return @@ -95,7 +96,8 @@ to_chat(usr, "Admin rank changed.") /datum/admins/proc/log_admin_permission_modification(var/adm_ckey, var/new_permission) - if(config.admin_legacy_system) return + if(get_config_value(/decl/config/toggle/on/admin_legacy_system)) + return if(!usr.client) return diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm index 67376432624c..97220cb80c3d 100644 --- a/code/modules/admin/player_notes.dm +++ b/code/modules/admin/player_notes.dm @@ -1,70 +1,3 @@ -//This stuff was originally intended to be integrated into the ban-system I was working on -//but it's safe to say that'll never be finished. So I've merged it into the current player panel. -//enjoy ~Carn -/* -#define NOTESFILE "data/player_notes.sav" //where the player notes are saved - -datum/admins/proc/notes_show(var/ckey) - show_browser(usr, "Player Notes[notes_gethtml(ckey)]", "window=player_notes;size=700x400") - - -datum/admins/proc/notes_gethtml(var/ckey) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return "Error: Cannot access [NOTESFILE]" - if(ckey) - . = "Notes for [ckey]:\[+\]\[-\]
          " - notesfile.cd = "/[ckey]" - var/index = 1 - while( !notesfile.eof ) - var/note - notesfile >> note - . += "[note] \[-\]
          " - index++ - else - . = "All Notes:\[+\]\[-\]
          " - notesfile.cd = "/" - for(var/dir in notesfile.dir) - . += "[dir]
          " - return - -//handles removing entries from the buffer, or removing the entire directory if no start_index is given -/proc/notes_remove(var/ckey, var/start_index, var/end_index) - var/savefile/notesfile = new(NOTESFILE) - if(!notesfile) return - - if(!ckey) - notesfile.cd = "/" - ckey = ckey(input(usr,"Who would you like to remove notes for?","Enter a ckey",null) as null|anything in notesfile.dir) - if(!ckey) return - - if(start_index) - notesfile.cd = "/[ckey]" - var/list/noteslist = list() - if(!end_index) end_index = start_index - var/index = 0 - while( !notesfile.eof ) - index++ - var/temp - notesfile >> temp - if( (start_index <= index) && (index <= end_index) ) - continue - noteslist += temp - - notesfile.eof = -2 //Move to the start of the buffer and then erase. - - for( var/note in noteslist ) - notesfile << note - else - notesfile.cd = "/" - if(alert(usr,"Are you sure you want to remove all their notes?","Confirmation","No","Yes - Remove all notes") == "Yes - Remove all notes") - notesfile.dir.Remove(ckey) - return - -#undef NOTESFILE -*/ - -//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky. - /proc/notes_add(var/key, var/note, var/mob/user) if (!key || !note) return @@ -72,7 +5,7 @@ datum/admins/proc/notes_gethtml(var/ckey) //Loading list of notes for this key var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") var/list/infos - info >> infos + from_file(info, infos) if(!infos) infos = list() //Overly complex timestamp creation @@ -104,7 +37,7 @@ datum/admins/proc/notes_gethtml(var/ckey) P.timestamp = "[copytext(full_date,1,day_loc)][day_string][copytext(full_date,day_loc+2)]" infos += P - info << infos + to_file(info, infos) message_staff("[P.author] has edited [key]'s notes.") log_admin("[P.author] has edited [key]'s notes.") @@ -114,22 +47,24 @@ datum/admins/proc/notes_gethtml(var/ckey) //Updating list of keys with notes on them var/savefile/note_list = new("data/player_notes.sav") var/list/note_keys - note_list >> note_keys - if(!note_keys) note_keys = list() - if(!note_keys.Find(key)) note_keys += key - note_list << note_keys + from_file(note_list, note_keys) + if(!note_keys) + note_keys = list() + if(!note_keys.Find(key)) + note_keys += key + to_file(note_list, note_keys) del(note_list) // savefile, so NOT qdel /proc/notes_del(var/key, var/index) var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") var/list/infos - info >> infos + from_file(info, infos) if(!infos || infos.len < index) return var/datum/player_info/item = infos[index] infos.Remove(item) - info << infos + to_file(info, infos) message_staff("[key_name_admin(usr)] deleted one of [key]'s notes.") log_admin("[key_name(usr)] deleted one of [key]'s notes.") @@ -140,7 +75,7 @@ datum/admins/proc/notes_gethtml(var/ckey) var/dat = " Info on [key]\n" var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav") var/list/infos - info >> infos + from_file(info, infos) if(!infos) dat = "No information found on the given key." else diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 28133f87fc2f..649c4b542655 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -1,8 +1,8 @@ -/datum/admins/proc/player_panel_new()//The new one +/datum/admins/proc/list_players() if (!usr.client.holder) return - var/dat = "Admin Player Panel" + var/dat = "Admin Player List" //javascript, the part that does most of the work~ dat += {" @@ -75,15 +75,15 @@ body += "
          CKEY \[+\]CKEY \[+\] RANKPERMISSIONS
          [adm_ckey] \[-\][rank][rights][adm_ckey] \[-\][rank][rights]
          "; - body += "PP - " - body += "N - " - body += "VV - " - body += "TP - " - body += "PM - " - body += "DN - " - body += "JMP
          " + body += "Player Panel - " + body += "Notes - " + body += "View Vars - " + body += "Special Roles - " + body += "Send PM - " + body += "Direct Narrate - " + body += "Jump To
          " if(antagonist > 0) - body += "Antagonist"; + body += "Antagonist"; body += "
          "; @@ -194,7 +194,7 @@
          Player panel
          - Hover over a line to see more information - Check antagonists + Hover over a line to see more information, or click here to check round info.

          "} - var/list/mobs = sortmobs() + var/list/mobs = get_sorted_mob_list() var/i = 1 for(var/entry in mobs) var/mob/M = entry @@ -224,50 +224,7 @@ if(i%2 == 0) color = "#f2f2f2" var/is_antagonist = is_special_character(M) - - var/M_job = "" - - if(isliving(M)) - - if(iscarbon(M)) //Carbon stuff - if(ishuman(M)) - var/mob/living/carbon/human/H = M - M_job = H.job - else if(isslime(M)) - M_job = "slime" - else if(issmall(M)) - M_job = "Monkey" - else if(isalien(M)) - M_job = "Alien" - else - M_job = "Carbon-based" - - else if(issilicon(M)) //silicon - if(isAI(M)) - M_job = "AI" - else if(ispAI(M)) - M_job = "pAI" - else if(isrobot(M)) - M_job = "Robot" - else - M_job = "Silicon-based" - - else if(isanimal(M)) //simple animals - if(iscorgi(M)) - M_job = "Corgi" - else - M_job = "Animal" - - else - M_job = "Living" - - else if(istype(M,/mob/new_player)) - M_job = "New player" - - else if(isghost(M)) - M_job = "Ghost" - else - M_job = "Unknown ([M.type])" + var/M_job = M.get_admin_job_string() M_job = replacetext(M_job, "'", "") M_job = replacetext(M_job, "\"", "") @@ -321,95 +278,28 @@ show_browser(usr, dat, "window=players;size=600x480") -//The old one -/datum/admins/proc/player_panel_old() - if (!usr.client.holder) - return - - var/dat = "Player Menu" - dat += "
          " - //add to this if wanting to add back in IP checking - //add if you want to know their ip to the lists below - var/list/mobs = sortmobs() - - for(var/mob/M in mobs) - if(!M.ckey) continue - - dat += "" - if(isAI(M)) - dat += "" - else if(isrobot(M)) - dat += "" - else if(ishuman(M)) - dat += "" - else if(istype(M, /mob/living/silicon/pai)) - dat += "" - else if(istype(M, /mob/new_player)) - dat += "" - else if(isghost(M)) - dat += "" - else if(issmall(M)) - dat += "" - else if(isalien(M)) - dat += "" - else - dat += "" - - - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.mind && H.mind.assigned_role) - dat += "" - else - dat += "" - - - dat += {" - - - "} - - - - if(usr.client) - switch(is_special_character(M)) - if(0) - dat += {""} - if(1) - dat += {""} - if(2) - dat += {""} - else - dat += {""} - - - - dat += "
          NameReal NameAssigned JobKeyOptionsPMTraitor?
          IP:(IP: [M.lastKnownIP])
          [M.name]AICyborg[M.real_name]pAINew PlayerGhostMonkeyAlienUnknown[H.mind.assigned_role]NA[M.key ? (M.client ? M.key : "[M.key] (DC)") : "No key"]XPMTraitor?Traitor?Traitor? N/A
          " - - show_browser(usr, dat, "window=players;size=640x480") - - - -/datum/admins/proc/check_antagonists() +/datum/admins/proc/show_round_status() if (GAME_STATE >= RUNLEVEL_GAME) var/dat = list() dat += "Round Status

          Round Status

          " dat += "Current Game Mode: [SSticker.mode.name]
          " dat += "Round Duration: [roundduration2text()]
          " dat += "Evacuation
          " - if (SSevac.evacuation_controller.is_idle()) - dat += "Call Evacuation
          " - else - var/timeleft = SSevac.evacuation_controller.get_eta() - if (SSevac.evacuation_controller.waiting_to_leave()) - dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
          " - dat += "Send Back
          " - - dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]
          " + + if(SSevac.evacuation_controller) + if (SSevac.evacuation_controller.is_idle()) + dat += "Call Evacuation
          " + else + var/timeleft = SSevac.evacuation_controller.get_eta() + if (SSevac.evacuation_controller.waiting_to_leave()) + dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
          " + dat += "Send Back
          " + + dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]
          " dat += "
          " - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antag_type in all_antag_types) - var/datum/antagonist/A = all_antag_types[antag_type] + var/decl/special_role/A = all_antag_types[antag_type] dat += A.get_check_antag_output(src) dat += "" show_browser(usr, jointext(dat,null), "window=roundstatus;size=400x500") diff --git a/code/modules/admin/quantum_mechanic.dm b/code/modules/admin/quantum_mechanic.dm new file mode 100644 index 000000000000..4d7bc4f561e4 --- /dev/null +++ b/code/modules/admin/quantum_mechanic.dm @@ -0,0 +1,304 @@ +/* +// Quantum Mechanic is a godmode avatar designed for debugging and admin actions +// Their primary benefit is the ability to spawn in wherever you are, making it quick to get a human for your needs +// They also have incorporeal flying movement if they choose, which is often the fastest way to get somewhere specific +// They are mostly invincible, although godmode is a bit imperfect. +// Most of their superhuman qualities can be toggled off if you need a normal human for testing biological functions +*/ + +#define isquantum(X) istype(X, /mob/living/human/quantum) +/client/proc/spawn_quantum_mechanic() + set category = "Debug" + set name = "Spawn Quantum Mechanic" + set desc = "Spawns a Quantum Mechanic to debug stuff." + + if(!check_rights(R_ADMIN|R_DEBUG)) + return + + if(GAME_STATE < RUNLEVEL_GAME) + to_chat(src, SPAN_WARNING("Please wait for the round to start...")) + return + + var/T = get_turf(mob) + var/mob/living/human/quantum/Q = new (T) + + prefs.copy_to(Q) + + Q.set_dir(mob.dir) + Q.ckey = ckey + + var/decl/outfit/outfit = GET_DECL(/decl/outfit/quantum) + outfit.equip_outfit(Q) + + //Sort out ID + var/obj/item/card/id/quantum/id = new (Q) + id.registered_name = Q.real_name + id.assignment = "Quantum Mechanic" + Q.equip_to_slot_or_del(id, slot_wear_id_str) + + Q.reload_fullscreen() + + for(var/language in decls_repository.get_decl_paths_of_subtype(/decl/language)) + Q.add_language(language) + + spark_at(Q) + Q.phase_in(get_turf(Q)) + log_debug("Quantum Mechanic spawned at X: [Q.x], Y: [Q.y], Z: [Q.z]. User: [src]") + +/decl/outfit/quantum + name = "Quantum Mechanic" + glasses = /obj/item/clothing/glasses/sunglasses/quantum + uniform = /obj/item/clothing/jumpsuit/quantum + shoes = /obj/item/clothing/shoes/color/black/quantum + l_ear = /obj/item/radio/headset/quantum + back = /obj/item/backpack/holding/quantum + head = /obj/item/clothing/head/beret + belt = /obj/item/belt/utility/full/quantum + id_slot = slot_wear_id_str + +/mob/living/human/quantum + status_flags = NO_ANTAG + universal_understand = TRUE + var/fall_override = TRUE + movement_handlers = list( + /datum/movement_handler/mob/death, + /datum/movement_handler/mob/conscious, + /datum/movement_handler/mob/eye, + /datum/movement_handler/move_relay, + /datum/movement_handler/mob/buckle_relay, + /datum/movement_handler/mob/delay, + /datum/movement_handler/mob/stop_effect, + /datum/movement_handler/mob/physically_capable, + /datum/movement_handler/mob/physically_restrained, + /datum/movement_handler/mob/space, + /datum/movement_handler/mob/multiz, + /datum/movement_handler/mob/multiz_connected, + /datum/movement_handler/mob/movement + ) + +/mob/living/human/quantum/can_inject(mob/user, target_zone) + if(user == src) + return ..() + to_chat(user, SPAN_DANGER("\The [src] disarms you before you can inject them.")) + user.drop_item() + return FALSE + +/mob/living/human/quantum/binarycheck() + return TRUE + +/mob/living/human/quantum/proc/delete_self() + if(QDELETED(src)) + return + + custom_emote(VISIBLE_MESSAGE, "presses a button on their suit, followed by a polite bow.") + phase_out(get_turf(src)) + spark_at(src) + + if(key) + var/mob/observer/ghost/ghost = ghostize() + ghost.set_dir(dir) + ghost.can_reenter_corpse = TRUE + ghost.reload_fullscreen() + + QDEL_IN(src, 7) + +/mob/living/human/quantum/verb/quantum_antigrav() + set name = "Toggle Gravity" + set desc = "Toggles falling." + set category = "Ω" + + if (fall_override) + fall_override = FALSE + to_chat(usr, SPAN_NOTICE("You will now fall normally.")) + else + fall_override = TRUE + to_chat(usr, SPAN_NOTICE("You will no longer fall.")) + +/mob/living/human/quantum/verb/quantum_walk() + set name = "Toggle Phase Walking" + set desc = "Uses quantum technology to phase through solid matter and move quickly." + set category = "Ω" + set popup_menu = 0 + + if(usr.HasMovementHandler(/datum/movement_handler/mob/incorporeal)) + usr.RemoveMovementHandler(/datum/movement_handler/mob/incorporeal) + to_chat(usr, SPAN_NOTICE("You will no longer phase through solid matter.")) + else + usr.ReplaceMovementHandler(/datum/movement_handler/mob/incorporeal) + to_chat(usr, SPAN_NOTICE("You will now phase through solid matter.")) + +/mob/living/human/quantum/verb/quantum_recover() + set name = "Rejuvenate Self" + set desc = "Use quantum powers you to restore your health." + set category = "Ω" + set popup_menu = FALSE + + revive() + +/mob/living/human/quantum/verb/quantum_quit() + set name = "Teleport Out" + set desc = "Activate quantum magic to leave and return to your original mob (if you have one)." + set category = "Ω" + + delete_self() + +/mob/living/human/quantum/verb/quantum_tgm() + set name = "Toggle Godmode" + set desc = "Enable or disable god mode. For testing things that require you to be vulnerable." + set category = "Ω" + + status_flags ^= GODMODE + to_chat(usr, SPAN_NOTICE("God mode is now [(status_flags & GODMODE) ? "enabled" : "disabled"].")) + +// Bag o Holding +/obj/item/backpack/holding/quantum + storage = /datum/storage/bag/quantum + +/obj/item/backpack/holding/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// Headset +/obj/item/radio/headset/quantum + name = "quantum mechanic's headset" + desc = "A quantum mechanic's headset. The letter 'Ω' is stamped on the side." + icon = 'icons/obj/items/device/radio/headsets/headset_admin.dmi' + encryption_keys = list( + /obj/item/encryptionkey/binary, + /obj/item/encryptionkey/specops + ) + +/obj/item/radio/headset/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// Clothes +/obj/item/clothing/jumpsuit/quantum + name = "quantum mechanic's uniform" + desc = "A quantum mechanic's uniform. There is a letter on front that reads 'Q'." + icon = 'icons/clothing/jumpsuits/uniform_quantum.dmi' + cold_protection = SLOT_FULL_BODY + heat_protection = SLOT_FULL_BODY + siemens_coefficient = 0 + +/obj/item/clothing/jumpsuit/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// Gloves +/obj/item/clothing/gloves/quantum + name = "quantum mechanic's gloves" + desc = "A pair of modified gloves. The letter 'Ω' is stamped on the side." + siemens_coefficient = 0 + permeability_coefficient = 0 + +/obj/item/clothing/gloves/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// Sunglasses +/obj/item/clothing/glasses/sunglasses/quantum + name = "quantum mechanic's glasses" + desc = "A pair of modified sunglasses. The letter 'Ω' is stamped on the side." + vision_flags = (SEE_TURFS|SEE_OBJS|SEE_MOBS) + see_invisible = SEE_INVISIBLE_NOLIGHTING + flash_protection = FLASH_PROTECTION_MAJOR + +/obj/item/clothing/glasses/sunglasses/quantum/verb/toggle_xray(mode in list("X-Ray without Lighting", "X-Ray with Lighting", "Normal")) + set name = "Change Vision Mode" + set desc = "Changes your glasses vision mode." + set category = "Ω" + set src in usr + + switch (mode) + if ("X-Ray without Lighting") + vision_flags = (SEE_TURFS|SEE_OBJS|SEE_MOBS) + see_invisible = SEE_INVISIBLE_NOLIGHTING + if ("X-Ray with Lighting") + vision_flags = (SEE_TURFS|SEE_OBJS|SEE_MOBS) + see_invisible = -1 + if ("Normal") + vision_flags = 0 + see_invisible = -1 + + to_chat(usr, SPAN_NOTICE("\The [src]'s vision mode is now [mode].")) + +/obj/item/clothing/glasses/sunglasses/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// Shoes +/obj/item/clothing/shoes/color/black/quantum + name = "quantum mechanic's shoes" + desc = "A pair of black shoes with extra grip. The letter 'Ω' is stamped on the side." + item_flags = ITEM_FLAG_NOSLIP + +/obj/item/clothing/shoes/color/black/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// ID +/obj/item/card/id/quantum + desc = "An ID straight from the Department of Spatiotemporal Affairs. This one looks highly classified." + +/obj/item/card/id/quantum/Initialize() + . = ..() + access = get_all_accesses() | get_all_centcom_access() | get_all_antagonist_access() + +/obj/item/card/id/quantum/attack_hand(mob/user) + if(!user) + return TRUE + + if(!isquantum(user)) + to_chat(user, SPAN_WARNING("Your hand seems to go right through \the [src]. It's like it doesn't exist.")) + return TRUE + + return ..() + +// Belt +/obj/item/belt/utility/full/quantum/Initialize() + . = ..() + // Full set of tools + new /obj/item/multitool(src) + +/mob/living/human/quantum/restrained() + return FALSE + +/mob/living/human/quantum/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + return fall_override ? FALSE : ..() diff --git a/code/modules/admin/respawn_as_self.dm b/code/modules/admin/respawn_as_self.dm new file mode 100644 index 000000000000..0e5277b36c61 --- /dev/null +++ b/code/modules/admin/respawn_as_self.dm @@ -0,0 +1,17 @@ +/client/proc/respawn_as_self() + set name = "Respawn As Self" + set desc = "Respawn in current client turf with currently selected preferences." + set category = "Special Verbs" + + if(!check_rights(R_SPAWN)) + return + + var/client/C = input(src, "Specify which client to respawn.", "Respawn As Self", usr.client) as null|anything in global.clients + if(!C || !(C in global.clients) || !C.prefs) + return + + var/mob/oldmob = C.mob + var/mob/living/human/H = new(oldmob.loc) + C.prefs.copy_to(H) + H.key = C.key + qdel(oldmob) diff --git a/code/modules/admin/secrets/admin_secrets/admin_logs.dm b/code/modules/admin/secrets/admin_secrets/admin_logs.dm index c9fa20257428..6be860d22cb7 100644 --- a/code/modules/admin/secrets/admin_secrets/admin_logs.dm +++ b/code/modules/admin/secrets/admin_secrets/admin_logs.dm @@ -6,8 +6,8 @@ if(!.) return var/dat = "Admin Log
          " - for(var/l in GLOB.admin_log) + for(var/l in global.admin_log) dat += "
        • [l]
        • " - if(!GLOB.admin_log.len) + if(!global.admin_log.len) dat += "No-one has done anything this round!" show_browser(user, dat, "window=admin_log") diff --git a/code/modules/admin/secrets/admin_secrets/bombing_list.dm b/code/modules/admin/secrets/admin_secrets/bombing_list.dm index 89f49b47c948..a5723ddb2642 100644 --- a/code/modules/admin/secrets/admin_secrets/bombing_list.dm +++ b/code/modules/admin/secrets/admin_secrets/bombing_list.dm @@ -7,6 +7,6 @@ return var/dat = "Bombing List" - for(var/l in GLOB.bombers) + for(var/l in global.bombers) dat += text("[l]
          ") show_browser(user, dat, "window=bombers") diff --git a/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm index 44ed696e4030..112a28de7b8d 100644 --- a/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm +++ b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm @@ -15,7 +15,7 @@ var/datum/shuttle/S = SSshuttle.shuttles[shuttle_tag] var/list/destinations = list() - for(var/obj/effect/shuttle_landmark/WP in world) + for(var/obj/effect/shuttle_landmark/WP in global.shuttle_landmarks) destinations += WP var/obj/effect/shuttle_landmark/destination = input(user, "Select the destination for this jump.") as null|anything in destinations @@ -29,7 +29,7 @@ var/move_duration = input(user, "How many seconds will this jump take?") as num S.long_jump(destination, transition, move_duration) - log_and_message_admins("has initiated a jump to [destination] (JMP) lasting [move_duration] seconds in transit at [transition] (JMP) for the [shuttle_tag] shuttle") + log_and_message_admins("has initiated a jump to [destination] (JMP) lasting [move_duration] seconds in transit at [transition] (JMP) for the [shuttle_tag] shuttle") else S.short_jump(destination) - log_and_message_admins("has initiated a jump to [destination] (JMP) for the [shuttle_tag] shuttle") + log_and_message_admins("has initiated a jump to [destination] (JMP) for the [shuttle_tag] shuttle") diff --git a/code/modules/admin/secrets/admin_secrets/list_dna.dm b/code/modules/admin/secrets/admin_secrets/list_dna.dm index 82c0af0e5f34..eb9a57d61554 100644 --- a/code/modules/admin/secrets/admin_secrets/list_dna.dm +++ b/code/modules/admin/secrets/admin_secrets/list_dna.dm @@ -7,8 +7,8 @@ return var/dat = "Showing DNA from blood.
          " dat += "" - for(var/mob/living/carbon/human/H in SSmobs.mob_list) - if(H.dna && H.ckey) - dat += "" + for(var/mob/living/human/H in SSmobs.mob_list) + if(H.ckey) + dat += "" dat += "
          NameDNABlood Type
          [H][H.dna.unique_enzymes][H.b_type]
          [H][H.get_unique_enzymes() || "NULL"][H.get_blood_type() || "NULL"]
          " show_browser(user, dat, "window=DNA;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm index 6b06f434aa79..7840ce20bb13 100644 --- a/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm +++ b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm @@ -7,13 +7,8 @@ return var/dat = "Showing Fingerprints.
          " dat += "" - for(var/mob/living/carbon/human/H in SSmobs.mob_list) + for(var/mob/living/human/H in SSmobs.mob_list) if(H.ckey) - if(H.dna && H.dna.uni_identity) - dat += "" - else if(H.dna && !H.dna.uni_identity) - dat += "" - else if(!H.dna) - dat += "" + dat += "" dat += "
          NameFingerprints
          [H][md5(H.dna.uni_identity)]
          [H]H.dna.uni_identity = null
          [H]H.dna = null
          [H][H.get_full_print(ignore_blockers = TRUE) || "null"]
          " show_browser(user, dat, "window=fingerprints;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/move_shuttle.dm b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm index 7f7dc343223e..585b6ab090fe 100644 --- a/code/modules/admin/secrets/admin_secrets/move_shuttle.dm +++ b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm @@ -19,11 +19,11 @@ var/datum/shuttle/S = SSshuttle.shuttles[shuttle_tag] var/list/destinations = list() - for(var/obj/effect/shuttle_landmark/WP in world) + for(var/obj/effect/shuttle_landmark/WP in global.shuttle_landmarks) destinations += WP var/obj/effect/shuttle_landmark/destination = input(user, "Select the destination.") as null|anything in destinations if (!destination) return S.attempt_move(destination) - log_and_message_admins("moved the [shuttle_tag] shuttle to [destination] (JMP)", user) + log_and_message_admins("moved the [shuttle_tag] shuttle to [destination] (JMP)", user) diff --git a/code/modules/admin/secrets/admin_secrets/prison_warp.dm b/code/modules/admin/secrets/admin_secrets/prison_warp.dm deleted file mode 100644 index bff46d6155c4..000000000000 --- a/code/modules/admin/secrets/admin_secrets/prison_warp.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/admin_secret_item/admin_secret/prison_warp - name = "Prison Warp" - warn_before_use = TRUE - -/datum/admin_secret_item/admin_secret/prison_warp/can_execute(var/mob/user) - if(GAME_STATE < RUNLEVEL_GAME) - return 0 - return ..() - -/datum/admin_secret_item/admin_secret/prison_warp/execute(var/mob/user) - . = ..() - if(!.) - return - for(var/mob/living/carbon/human/H in SSmobs.mob_list) - var/turf/T = get_turf(H) - var/security = 0 - if((T && (T in GLOB.using_map.admin_levels)) || GLOB.prisonwarped.Find(H)) - //don't warp them if they aren't ready or are already there - continue - H.Paralyse(5) - if(H.wear_id) - var/obj/item/card/id/id = H.GetIdCard() - for(var/A in id.access) - if(A == access_security) - security++ - if(!security) - //strip their stuff before they teleport into a cell :downs: - for(var/obj/item/W in H) - if(istype(W, /obj/item/organ/external)) - continue - //don't strip organs - H.drop_from_inventory(W) - //teleport person to cell - H.forceMove(pick(GLOB.prisonwarp)) - H.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/shoes/color/orange(H), slot_shoes) - else - //teleport security person - H.forceMove(pick(GLOB.prisonsecuritywarp)) - GLOB.prisonwarped |= H diff --git a/code/modules/admin/secrets/admin_secrets/show_law_changes.dm b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm index bac5a3e8b498..dc13dc970194 100644 --- a/code/modules/admin/secrets/admin_secrets/show_law_changes.dm +++ b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm @@ -2,14 +2,14 @@ name = "Show law changes" /datum/admin_secret_item/admin_secret/show_law_changes/name() - return "Show Last [length(GLOB.lawchanges)] Law change\s" + return "Show Last [length(global.lawchanges)] Law change\s" /datum/admin_secret_item/admin_secret/show_law_changes/execute(var/mob/user) . = ..() if(!.) return - var/dat = "Showing last [length(GLOB.lawchanges)] law changes.
          " - for(var/sig in GLOB.lawchanges) + var/dat = "Showing last [length(global.lawchanges)] law changes.
          " + for(var/sig in global.lawchanges) dat += "[sig]
          " show_browser(user, dat, "window=lawchanges;size=800x500") diff --git a/code/modules/admin/secrets/admin_secrets/show_signalers.dm b/code/modules/admin/secrets/admin_secrets/show_signalers.dm deleted file mode 100644 index b60b73df6244..000000000000 --- a/code/modules/admin/secrets/admin_secrets/show_signalers.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/admin_secret_item/admin_secret/show_signalers - name = "Show Last Signalers" - -/datum/admin_secret_item/admin_secret/show_signalers/name() - return "Show Last [length(GLOB.lastsignalers)] Signaler\s" - -/datum/admin_secret_item/admin_secret/show_signalers/execute(var/mob/user) - . = ..() - if(!.) - return - - var/dat = "Showing last [length(GLOB.lastsignalers)] signalers.
          " - for(var/sig in GLOB.lastsignalers) - dat += "[sig]
          " - show_browser(user, dat, "window=lastsignalers;size=800x500") diff --git a/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm b/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm index bcfd9cd7b9cd..fa35d1bc39f3 100644 --- a/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm +++ b/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm @@ -4,4 +4,4 @@ /datum/admin_secret_item/admin_secret/traitors_and_objectives/execute(var/mob/user) . = ..() if(.) - user.client.holder.check_antagonists() + user.client.holder.show_round_status() diff --git a/code/modules/admin/secrets/fun_secrets/break_all_lights.dm b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm index 2256d4f71680..51a5131e92d7 100644 --- a/code/modules/admin/secrets/fun_secrets/break_all_lights.dm +++ b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm @@ -4,4 +4,6 @@ /datum/admin_secret_item/fun_secret/break_all_lights/execute(var/mob/user) . = ..() if(.) - lightsout(0,0) + for(var/obj/machinery/apc/apc in SSmachines.machinery) + apc.overload_lighting() + CHECK_TICK diff --git a/code/modules/admin/secrets/fun_secrets/break_some_lights.dm b/code/modules/admin/secrets/fun_secrets/break_some_lights.dm index 70b9eaf8061f..bfa45de4cb5d 100644 --- a/code/modules/admin/secrets/fun_secrets/break_some_lights.dm +++ b/code/modules/admin/secrets/fun_secrets/break_some_lights.dm @@ -1,7 +1,28 @@ /datum/admin_secret_item/fun_secret/break_some_lights name = "Break Some Lights" + var/const/lightsoutRange = 25 /datum/admin_secret_item/fun_secret/break_some_lights/execute(var/mob/user) . = ..() - if(.) - lightsout(1,2) + if(!.) + return + command_announcement.Announce("An Electrical storm has been detected in your area, please repair potential electronic overloads.","Electrical Storm Alert") + + var/list/epicentreList = list() + for(var/i in 1 to 2) + var/list/possibleEpicentres = list() + for(var/obj/abstract/landmark/newEpicentre in global.all_landmarks) + if(newEpicentre.name == "lightsout" && !(newEpicentre in epicentreList)) + possibleEpicentres += newEpicentre + if(length(possibleEpicentres)) + epicentreList += pick(possibleEpicentres) + else + break + + if(!length(epicentreList)) + return + + for(var/obj/abstract/landmark/epicentre in epicentreList) + for(var/obj/machinery/apc/apc in range(epicentre,lightsoutRange)) + apc.overload_lighting() + CHECK_TICK diff --git a/code/modules/admin/secrets/fun_secrets/change_credits.dm b/code/modules/admin/secrets/fun_secrets/change_credits.dm index 9d4ffcff9b6c..357c4785e1fd 100644 --- a/code/modules/admin/secrets/fun_secrets/change_credits.dm +++ b/code/modules/admin/secrets/fun_secrets/change_credits.dm @@ -1,5 +1,5 @@ -GLOBAL_VAR_INIT(end_credits_song, null) -GLOBAL_VAR_INIT(end_credits_title, null) +var/global/end_credits_song +var/global/end_credits_title /datum/admin_secret_item/fun_secret/change_credits_song name = "Change End Credits Song" @@ -7,20 +7,13 @@ GLOBAL_VAR_INIT(end_credits_title, null) name = "Change End Credits Title" /datum/admin_secret_item/fun_secret/change_credits_song/do_execute() - var/list/sounds = subtypesof(/music_track) - - var/music_track/selected = input("Select a music track for the credits.", "Server music list") as null|anything in sounds - + var/selected = input("Select a music track for the credits.", "Server music list") as null|anything in decls_repository.get_decl_paths_of_subtype(/decl/music_track) if(selected) - var/music_track/track = decls_repository.get_decl(selected) - GLOB.end_credits_song = track.song - + var/decl/music_track/track = GET_DECL(selected) + global.end_credits_song = track.song SSstatistics.add_field_details("admin_verb","CECS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admin_secret_item/fun_secret/change_credits_title/do_execute() - GLOB.end_credits_title = input(usr, "What title would you like for the end credits?") as null|text - - if(!GLOB.end_credits_title) - return - - SSstatistics.add_field_details("admin_verb","CECT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! \ No newline at end of file + global.end_credits_title = input(usr, "What title would you like for the end credits?") as null|text + if(global.end_credits_title) + SSstatistics.add_field_details("admin_verb","CECT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm b/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm index 40ffa73cb153..028ac337a29c 100644 --- a/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm +++ b/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm @@ -6,5 +6,5 @@ if(!.) return - for(var/obj/machinery/light/L in world) + for(var/obj/machinery/light/L in SSmachines.machinery) L.fix() diff --git a/code/modules/admin/secrets/fun_secrets/waddle.dm b/code/modules/admin/secrets/fun_secrets/waddle.dm index e3472e6fcc20..90c663b5a82a 100644 --- a/code/modules/admin/secrets/fun_secrets/waddle.dm +++ b/code/modules/admin/secrets/fun_secrets/waddle.dm @@ -5,13 +5,44 @@ /datum/admin_secret_item/fun_secret/waddle/do_execute(var/mob/user) waddling = !waddling if(waddling) - GLOB.moved_event.register_global(src, .proc/waddle) + for(var/mob/living/living_mob in global.living_mob_list_) + set_extension(living_mob, /datum/extension/waddle) + events_repository.register_global(/decl/observ/life, src, PROC_REF(enroll_in_waddling)) + events_repository.register_global(/decl/observ/death, src, PROC_REF(cure_waddling)) else - GLOB.moved_event.unregister_global(src, .proc/waddle) + for(var/mob/living/living_mob in global.living_mob_list_) + cure_waddling(living_mob) + events_repository.unregister_global(/decl/observ/life, src) + events_repository.unregister_global(/decl/observ/death, src) -/datum/admin_secret_item/fun_secret/waddle/proc/waddle(atom/movable/AM) - var/mob/living/L = AM - if(!istype(L) || L.incapacitated() || L.lying) +/datum/admin_secret_item/fun_secret/waddle/proc/enroll_in_waddling(mob/living/waddler) + if(!istype(waddler)) + return + set_extension(waddler, /datum/extension/waddle) + +/datum/admin_secret_item/fun_secret/waddle/proc/cure_waddling(mob/living/patient) + if(!istype(patient)) + return + remove_extension(patient, /datum/extension/waddle) + +/datum/extension/waddle + base_type = /datum/extension/waddle + expected_type = /mob + flags = EXTENSION_FLAG_IMMEDIATE + +/datum/extension/waddle/New(datum/holder) + . = ..() + events_repository.register(/decl/observ/moved, holder, src, PROC_REF(waddle)) + events_repository.register(/decl/observ/destroyed, holder, src, PROC_REF(qdel_self)) + +/datum/extension/waddle/Destroy() + events_repository.unregister(/decl/observ/destroyed, holder, src) + events_repository.unregister(/decl/observ/moved, holder, src) + return ..() + +/datum/extension/waddle/proc/waddle() + var/mob/living/L = holder + if(!istype(L) || L.incapacitated() || L.current_posture.prone) return animate(L, pixel_z = 4, time = 0) animate(pixel_z = 0, transform = turn(matrix(), pick(-12, 0, 12)), time=2) diff --git a/code/modules/admin/secrets/investigation/admin_pms.dm b/code/modules/admin/secrets/investigation/admin_pms.dm deleted file mode 100644 index 45fe20ff2080..000000000000 --- a/code/modules/admin/secrets/investigation/admin_pms.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/admin_secret_item/investigation/admin_pms - name = "Admin PMs" - -/datum/admin_secret_item/investigation/admin_pms/execute(var/mob/user, var/filter) - . = ..() - if(!.) - return - var/dat = list() - dat += "Refresh Filtering on: " - if(filter) - dat += " [filter] Clear" - else - dat += "None" - dat += "
          " - dat += "" - dat += "" - - for(var/datum/admin_privat_message/pm in admin_pm_repository.admin_pms_) - var/datum/client_lite/sender = pm.sender - var/datum/client_lite/receiver = pm.receiver - - if(filter && !(sender.ckey == filter || (receiver && receiver.ckey == filter))) - continue - - if(receiver) - dat += "" - else - dat += "" - dat += "" - dat += "
          TimeSenderReceiver
          [pm.station_time][sender.key_name(FALSE)] F[receiver.key_name(FALSE)] F
          [pm.station_time][sender.key_name(FALSE)] F
          [pm.message]
          " - - var/datum/browser/popup = new(user, "admin_ahelps", "Admin PMs", 800, 400) - popup.set_content(jointext(dat, null)) - popup.open() - -/datum/admin_secret_item/investigation/admin_pms/Topic(href, href_list) - . = ..() - if(.) - return - execute(usr, href_list["filter"]) diff --git a/code/modules/admin/secrets/investigation/attack_logs.dm b/code/modules/admin/secrets/investigation/attack_logs.dm index d66a74eafab1..5a915fd379c7 100644 --- a/code/modules/admin/secrets/investigation/attack_logs.dm +++ b/code/modules/admin/secrets/investigation/attack_logs.dm @@ -11,12 +11,12 @@ if(!.) return var/dat = list() - dat += "Refresh | " + dat += "Refresh | " dat += get_filter_html(user) - dat += " | Reset" + dat += " | Reset" dat += "
          " dat += "" - dat += "" + dat += "" for(var/log in attack_log_repository.attack_logs_) var/datum/attack_log/al = log @@ -26,21 +26,23 @@ dat += "" if(al.attacker) - dat += "" + dat += "" else dat += "" dat += "" + dat += "" + if(al.victim) - dat += "" + dat += "" else dat += "" dat += "" - dat += "" dat += "
          TimeAttackerIntentVictim
          TimeAttackerIntentZone SelVictim
          [al.station_time][al.attacker.key_name(check_if_offline = FALSE)] PP[al.attacker.key_name(check_if_offline = FALSE)] PP[al.intent][al.target_zone][al.victim.key_name(check_if_offline = FALSE)] PP[al.victim.key_name(check_if_offline = FALSE)] PP
          [al.message]" + dat += "
          [al.message]" if(al.location) - dat += " JMP" + dat += " JMP" dat += "
          " @@ -67,9 +69,8 @@ . = filters_per_client[user.client] if(!.) . = list() - for(var/af_type in subtypesof(/attack_filter)) - var/attack_filter/af = af_type - if(initial(af.category) == af_type) + for(var/datum/attack_filter/af_type as anything in subtypesof(/datum/attack_filter)) + if(TYPE_IS_ABSTRACT(af_type)) continue . += new af_type(src) filters_per_client[user.client] = . @@ -77,65 +78,65 @@ /datum/admin_secret_item/investigation/attack_logs/proc/get_filter_html(user) . = list() for(var/filter in get_user_filters(user)) - var/attack_filter/af = filter + var/datum/attack_filter/af = filter . += af.get_html() . = jointext(.," | ") /datum/admin_secret_item/investigation/attack_logs/proc/filter_log(user, var/datum/attack_log/al) for(var/filter in get_user_filters(user)) - var/attack_filter/af = filter + var/datum/attack_filter/af = filter if(af.filter_attack(al)) return TRUE return FALSE /datum/admin_secret_item/investigation/attack_logs/proc/reset_user_filters(user) for(var/filter in get_user_filters(user)) - var/attack_filter/af = filter + var/datum/attack_filter/af = filter af.reset() -/attack_filter - var/category = /attack_filter +/datum/attack_filter + abstract_type = /datum/attack_filter var/datum/admin_secret_item/investigation/attack_logs/holder -/attack_filter/New(var/holder) +/datum/attack_filter/New(var/holder) ..() src.holder = holder -/attack_filter/Topic(href, href_list) +/datum/attack_filter/Topic(href, href_list) if(..()) return TRUE if(OnTopic(href_list)) holder.execute(usr) return TRUE -/attack_filter/proc/get_html() +/datum/attack_filter/proc/get_html() return -/attack_filter/proc/reset() +/datum/attack_filter/proc/reset() return -/attack_filter/proc/filter_attack(var/datum/attack_log/al) +/datum/attack_filter/proc/filter_attack(var/datum/attack_log/al) return FALSE -/attack_filter/proc/OnTopic(href_list) +/datum/attack_filter/proc/OnTopic(href_list) return FALSE /* * Filter logs with one or more missing clients */ -/attack_filter/no_client +/datum/attack_filter/no_client var/filter_missing_clients = TRUE -/attack_filter/no_client/get_html() +/datum/attack_filter/no_client/get_html() . = list() . += "Must have clients: " if(filter_missing_clients) - . += "YesNo" + . += "YesNo" else - . += "YesNo" + . += "YesNo" . = jointext(.,null) -/attack_filter/no_client/OnTopic(href_list) +/datum/attack_filter/no_client/OnTopic(href_list) if(href_list["yes"] && !filter_missing_clients) filter_missing_clients = TRUE return TRUE @@ -143,10 +144,10 @@ filter_missing_clients = FALSE return TRUE -/attack_filter/no_client/reset() +/datum/attack_filter/no_client/reset() filter_missing_clients = initial(filter_missing_clients) -/attack_filter/no_client/filter_attack(var/datum/attack_log/al) +/datum/attack_filter/no_client/filter_attack(var/datum/attack_log/al) if(!filter_missing_clients) return FALSE if(al.attacker && al.attacker.client.ckey == NO_CLIENT_CKEY) @@ -158,19 +159,19 @@ /* Either subject must be the selected client */ -/attack_filter/must_be_given_ckey +/datum/attack_filter/must_be_given_ckey var/ckey_filter var/check_attacker = TRUE var/check_victim = TRUE var/description = "Either ckey is" -/attack_filter/must_be_given_ckey/reset() +/datum/attack_filter/must_be_given_ckey/reset() ckey_filter = null -/attack_filter/must_be_given_ckey/get_html() - return "[description]: [ckey_filter ? ckey_filter : "*ANY*"]" +/datum/attack_filter/must_be_given_ckey/get_html() + return "[description]: [ckey_filter ? ckey_filter : "*ANY*"]" -/attack_filter/must_be_given_ckey/OnTopic(href_list) +/datum/attack_filter/must_be_given_ckey/OnTopic(href_list) if(!href_list["select_ckey"]) return var/ckey = input("Select ckey to filter on","Select ckey", ckey_filter) as null|anything in get_ckeys() @@ -181,7 +182,7 @@ ckey_filter = ckey return TRUE -/attack_filter/must_be_given_ckey/proc/get_ckeys() +/datum/attack_filter/must_be_given_ckey/proc/get_ckeys() . = list() for(var/log in attack_log_repository.attack_logs_) var/datum/attack_log/al = log @@ -189,10 +190,10 @@ . |= al.attacker.client.ckey if(check_victim && al.victim && al.victim.client.ckey != NO_CLIENT_CKEY) . |= al.victim.client.ckey - . = sortList(.) + . = sortTim(., /proc/cmp_text_asc) . += "*ANY*" -/attack_filter/must_be_given_ckey/filter_attack(var/datum/attack_log/al) +/datum/attack_filter/must_be_given_ckey/filter_attack(var/datum/attack_log/al) if(!ckey_filter) return FALSE if(check_attacker && al.attacker && al.attacker.client.ckey == ckey_filter) @@ -204,19 +205,19 @@ /* Attacker must be the selected client */ -/attack_filter/must_be_given_ckey/attacker +/datum/attack_filter/must_be_given_ckey/attacker description = "Attacker ckey is" check_victim = FALSE -/attack_filter/must_be_given_ckey/attacker/filter_attack(al) +/datum/attack_filter/must_be_given_ckey/attacker/filter_attack(al) return ..(al, TRUE, FALSE) /* Victim must be the selected client */ -/attack_filter/must_be_given_ckey/victim +/datum/attack_filter/must_be_given_ckey/victim description = "Victim ckey is" check_attacker = FALSE -/attack_filter/must_be_given_ckey/victim/filter_attack(al) +/datum/attack_filter/must_be_given_ckey/victim/filter_attack(al) return ..(al, FALSE, TRUE) diff --git a/code/modules/admin/spam_prevention.dm b/code/modules/admin/spam_prevention.dm index 0033618dac0d..10d9adab7fe8 100644 --- a/code/modules/admin/spam_prevention.dm +++ b/code/modules/admin/spam_prevention.dm @@ -1,31 +1,33 @@ -GLOBAL_LIST_EMPTY(ckey_to_actions) -GLOBAL_LIST_EMPTY(ckey_to_act_time) -GLOBAL_LIST_EMPTY(ckey_punished_for_spam) // this round; to avoid redundant record-keeping. +var/global/list/ckey_to_actions = list() +var/global/list/ckey_to_act_time = list() +var/global/list/ckey_punished_for_spam = list() // this round; to avoid redundant record-keeping. // Should be checked on all instant client verbs. -/proc/user_acted(client/C) +/proc/user_acted(client/C, admin_message = "was kicked due to possible spam abuse.", client_message = "Possible spam abuse detected; you are being kicked from the server.") var/ckey = C && C.ckey if(!ckey) return FALSE - if (config.do_not_prevent_spam) + if(get_config_value(/decl/config/toggle/do_not_prevent_spam)) return TRUE var/time = world.time - if(GLOB.ckey_to_act_time[ckey] + config.act_interval < time) - GLOB.ckey_to_act_time[ckey] = time - GLOB.ckey_to_actions[ckey] = 1 + if(global.ckey_to_act_time[ckey] + (get_config_value(/decl/config/num/act_interval) SECONDS) < time) + global.ckey_to_act_time[ckey] = time + global.ckey_to_actions[ckey] = 1 return TRUE - if(GLOB.ckey_to_actions[ckey] <= config.max_acts_per_interval) - GLOB.ckey_to_actions[ckey]++ + if(global.ckey_to_actions[ckey] <= get_config_value(/decl/config/num/max_acts_per_interval)) + global.ckey_to_actions[ckey]++ return TRUE // Punitive action . = FALSE - log_and_message_admins("Kicking due to possible spam abuse", C) - to_chat(C, SPAN_DANGER("Possible spam abuse detected; you are being kicked from the server.")) - if(GLOB.ckey_punished_for_spam[ckey]) + if(admin_message) + log_and_message_admins(admin_message, C) + if(client_message) + to_chat(C, SPAN_DANGER(client_message)) + if(global.ckey_punished_for_spam[ckey]) qdel(C) return - GLOB.ckey_punished_for_spam[ckey] = TRUE + global.ckey_punished_for_spam[ckey] = TRUE notes_add(ckey, "\[AUTO\] Kicked for possible spam abuse.") qdel(C) @@ -39,7 +41,5 @@ GLOBAL_LIST_EMPTY(ckey_punished_for_spam) // this round; to avoid redundant reco return return ..() -/client/MouseDrop() - if(!user_acted(src)) - return - return ..() +/client/MouseDrop(src_object, over_object, src_location, over_location, src_control, over_control, params) + . = user_acted(src) && ..() diff --git a/code/modules/admin/ticket.dm b/code/modules/admin/ticket.dm index 033ae9a65aaa..8612a5306d92 100644 --- a/code/modules/admin/ticket.dm +++ b/code/modules/admin/ticket.dm @@ -1,5 +1,5 @@ -var/list/tickets = list() -var/list/ticket_panels = list() +var/global/list/tickets = list() +var/global/list/ticket_panels = list() /datum/ticket var/datum/client_lite/owner @@ -16,7 +16,11 @@ var/list/ticket_panels = list() tickets |= src id = tickets.len opened_time = world.time - addtimer(CALLBACK(src, .proc/timeoutcheck), 5 MINUTES) + if(establish_db_connection()) + var/sql_ckey = sanitize_sql(owner.ckey) + var/DBQuery/ticket_query = dbcon.NewQuery("INSERT INTO `erro_admin_tickets`(`ckey`, `round`, `inround_id`, `status`, `open_date`) VALUES ('[sql_ckey]', '[game_id]', [src.id], 'OPEN', NOW());") + ticket_query.Execute() + addtimer(CALLBACK(src, PROC_REF(timeoutcheck)), 5 MINUTES) /datum/ticket/proc/timeoutcheck() if(status == TICKET_OPEN) @@ -38,12 +42,29 @@ var/list/ticket_panels = list() src.status = TICKET_CLOSED if(timeout == TRUE) + if(establish_db_connection()) + var/DBQuery/ticket_timeout = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `status` = 'TIMED_OUT' WHERE `round` = '[game_id]' AND `inround_id` = '[src.id]';") + ticket_timeout.Execute() to_chat(client_by_ckey(src.owner.ckey), "Your ticket has timed out. Please adminhelp again if your issue is not resolved.") + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Ticket ([id]) (Game ID: [game_id]) Ticket Timed Out", "body" = "[src.owner.key_name(0)] 's ticket (ID [id]) has timed out.")) else src.closed_by = closed_by to_chat(client_by_ckey(src.owner.ckey), "Your ticket has been closed by [closed_by.key].") message_staff("[src.owner.key_name(0)]'s ticket has been closed by [closed_by.key].") - send2adminirc("[src.owner.key_name(0)]'s ticket has been closed by [closed_by.key].") + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Ticket ([id]) (Game ID: [game_id]) Ticket Closed", "body" = "[src.owner.key_name(0)] 's ticket (ID [id]) has been closed by [closed_by.key].")) + + var/closed_by_not_assigned = TRUE + if(!closed_by) + closed_by_not_assigned = TRUE + else if((closed_by.ckey in assigned_admin_ckeys()) || owner.ckey == closed_by.ckey) + closed_by_not_assigned = FALSE + + if(establish_db_connection()) + var/sql_text = "[closed_by_not_assigned ? "CLOSED (TIMEOUT)" : "SOLVED: [closed_by.ckey]"]\n" + var/DBQuery/ticket_text = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `text` = CONCAT(text, '[sql_text]') WHERE `round` = '[game_id]' AND `inround_id` = '[src.id]';") + var/DBQuery/ticket_close = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `status` = '[closed_by_not_assigned ? "CLOSED" : "SOLVED"]' WHERE `round` = '[game_id]' AND `inround_id` = '[src.id]';") + ticket_text.Execute() + ticket_close.Execute() update_ticket_panels() @@ -60,11 +81,26 @@ var/list/ticket_panels = list() return assigned_admins |= assigned_admin - src.status = TICKET_ASSIGNED + + if(src.status != TICKET_ASSIGNED) + if(establish_db_connection()) + var/DBQuery/ticket_timeout = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `status` = 'ASSIGNED' WHERE `round` = '[game_id]' AND `inround_id` = '[src.id]';") + ticket_timeout.Execute() + src.status = TICKET_ASSIGNED + + if(establish_db_connection()) + var/sql_assignee + for(var/datum/client_lite/_admin in assigned_admins) + if(!sql_assignee) + sql_assignee += "[_admin.ckey]" + else + sql_assignee += ", [_admin.ckey]" + var/DBQuery/ticket_take = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `assignee` = '[sql_assignee]' WHERE `round` = '[game_id]' AND `inround_id` = '[src.id]';") + ticket_take.Execute() message_staff("[assigned_admin.key] has assigned themself to [src.owner.key_name(0)]'s ticket.") - send2adminirc("[assigned_admin.key] has assigned themself to [src.owner.key_name(0)]'s ticket.") to_chat(client_by_ckey(src.owner.ckey), "[assigned_admin.key] has added themself to your ticket and should respond shortly. Thanks for your patience!") + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Ticket ([id]) (Game ID: [game_id]) Ticked Assigned", "body" = "[assigned_admin.key] has added themself to ticket ID [id].")) update_ticket_panels() @@ -82,7 +118,7 @@ var/list/ticket_panels = list() for(var/datum/client_lite/assigned_admin in assigned_admins) . |= assigned_admin.key -proc/get_open_ticket_by_client(var/datum/client_lite/owner) +/proc/get_open_ticket_by_client(var/datum/client_lite/owner) for(var/datum/ticket/ticket in tickets) if(ticket.owner.ckey == owner.ckey && (ticket.status == TICKET_OPEN || ticket.status == TICKET_ASSIGNED)) return ticket // there should only be one open ticket by a client at a time, so no need to keep looking @@ -157,7 +193,7 @@ proc/get_open_ticket_by_client(var/datum/client_lite/owner) var/ref_mob = "" if(owner_client) ref_mob = "\ref[owner_client.mob]" - ticket_dat += " - ? - PP - VV - DN[owner_client ? "- [admin_jump_link(owner_client, src)]" : ""]" + ticket_dat += " - ? - PP - VV - DN[owner_client ? "- [admin_jump_link(owner_client, src)]" : ""]" if(open_ticket && open_ticket == ticket) ticket_dat += "" ticket_dat += "" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 6677e76101f8..4d920bdc9f79 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1,3 +1,6 @@ +#define MAX_JOBBAN_CELLS 5 +var/global/list/misc_jobban_roles = list("Botany Roles", "Graffiti") + /datum/admins/Topic(href, href_list) ..() @@ -6,8 +9,8 @@ message_admins("[usr.key] has attempted to override the admin panel!") return - if(SSticker.mode && SSticker.mode.check_antagonists_topic(href, href_list)) - check_antagonists() + if(SSticker.mode && SSticker.mode.round_status_topic(href, href_list)) + show_round_status() return if(href_list["dbsearchckey"] || href_list["dbsearchadmin"]) @@ -70,7 +73,7 @@ var/mob/playermob - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(M.ckey == banckey) playermob = M break @@ -102,14 +105,14 @@ var/new_ckey = ckey(input(usr,"New admin's ckey","Admin ckey", null) as text|null) if(!new_ckey) return if(new_ckey in admin_datums) - to_chat(usr, "Error: Topic 'editrights': [new_ckey] is already an admin") + to_chat(usr, SPAN_WARNING("Error: Topic 'editrights': [new_ckey] is already an admin")) return adm_ckey = new_ckey task = "rank" else if(task != "show") adm_ckey = ckey(href_list["ckey"]) if(!adm_ckey) - to_chat(usr, "Error: Topic 'editrights': No valid ckey") + to_chat(usr, SPAN_WARNING("Error: Topic 'editrights': No valid ckey")) return var/datum/admins/D = admin_datums[adm_ckey] @@ -138,19 +141,19 @@ if(null,"") return if("*New Rank*") new_rank = input("Please input a new rank", "New custom rank", null, null) as null|text - if(config.admin_legacy_system) + if(get_config_value(/decl/config/toggle/on/admin_legacy_system)) new_rank = ckeyEx(new_rank) if(!new_rank) - to_chat(usr, "Error: Topic 'editrights': Invalid rank") + to_chat(usr, SPAN_WARNING("Error: Topic 'editrights': Invalid rank")) return - if(config.admin_legacy_system) + if(get_config_value(/decl/config/toggle/on/admin_legacy_system)) if(admin_ranks.len) if(new_rank in admin_ranks) rights = admin_ranks[new_rank] //we typed a rank which already exists, use its rights else admin_ranks[new_rank] = 0 //add the new rank to admin_ranks else - if(config.admin_legacy_system) + if(get_config_value(/decl/config/toggle/on/admin_legacy_system)) new_rank = ckeyEx(new_rank) rights = admin_ranks[new_rank] //we input an existing rank, use its rights @@ -161,7 +164,7 @@ else D = new /datum/admins(new_rank, rights, adm_ckey) - var/client/C = GLOB.ckey_directory[adm_ckey] //find the client with the specified ckey (if they are logged in) + var/client/C = global.ckey_directory[adm_ckey] //find the client with the specified ckey (if they are logged in) D.associate(C) //link up with the client and add verbs to_chat(C, "[key_name_admin(usr)] has set your admin rank to: [new_rank].") @@ -172,13 +175,13 @@ else if(task == "permissions") if(!D) return var/list/permissionlist = list() - for(var/i=1, i<=R_MAXPERMISSION, i<<=1) //that <<= is shorthand for i = i << 1. Which is a left bitshift + for(var/i=1, i<=R_MAXPERMISSION, i = BITSHIFT_LEFT(i, 1)) permissionlist[rights2text(i)] = i var/new_permission = input("Select a permission to turn on/off", "Permission toggle", null, null) as null|anything in permissionlist if(!new_permission) return D.rights ^= permissionlist[new_permission] - var/client/C = GLOB.ckey_directory[adm_ckey] + var/client/C = global.ckey_directory[adm_ckey] to_chat(C, "[key_name_admin(usr)] has toggled your permission: [new_permission].") message_admins("[key_name_admin(usr)] toggled the [new_permission] permission of [adm_ckey]") log_admin("[key_name(usr)] toggled the [new_permission] permission of [adm_ckey]") @@ -205,14 +208,14 @@ if (SSevac.evacuation_controller.cancel_evacuation()) log_and_message_admins("cancelled an evacuation.") - href_list["secretsadmin"] = "check_antagonist" + href_list["secretsadmin"] = "show_round_status" else if(href_list["delay_round_end"]) if(!check_rights(R_SERVER)) return SSticker.delay_end = !SSticker.delay_end log_and_message_admins("[SSticker.delay_end ? "delayed the round end" : "has made the round end normally"].") - href_list["secretsadmin"] = "check_antagonist" + href_list["secretsadmin"] = "show_round_status" else if(href_list["simplemake"]) @@ -225,30 +228,16 @@ var/delmob = 0 switch(alert("Delete old mob?","Message","Yes","No","Cancel")) - if("Cancel") return - if("Yes") delmob = 1 - - log_and_message_admins("has used rudimentary transformation on [key_name_admin(M)]. Transforming to [href_list["simplemake"]]; deletemob=[delmob]") - - switch(href_list["simplemake"]) - if("observer") M.change_mob_type( /mob/observer/ghost , null, null, delmob ) - if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"]) - if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob ) - if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob ) - if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) - if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob ) - if("runtime") M.change_mob_type( /mob/living/simple_animal/cat/fluff/Runtime , null, null, delmob ) - if("corgi") M.change_mob_type( /mob/living/simple_animal/corgi , null, null, delmob ) - if("ian") M.change_mob_type( /mob/living/simple_animal/corgi/Ian , null, null, delmob ) - if("crab") M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob ) - if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob ) - if("parrot") M.change_mob_type( /mob/living/simple_animal/hostile/retaliate/parrot , null, null, delmob ) - if("polyparrot") M.change_mob_type( /mob/living/simple_animal/hostile/retaliate/parrot/Poly , null, null, delmob ) - if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/construct/armoured , null, null, delmob ) - if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob ) - if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob ) - if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob ) + if("Cancel") + return + if("Yes") + delmob = TRUE + var/transform_key = replacetext(href_list["simplemake"], "_", " ") + // Nothing ever seems to pass species to any simplemake href links... + // TODO: Remove subspecies argument if it actually is defunct? + if(M.try_rudimentary_transform(transform_key, delmob, href_list["species"])) + log_and_message_admins("has used rudimentary transformation on [key_name_admin(M)]. Transforming to [transform_key]; deletemob=[delmob]") /////////////////////////////////////new ban stuff else if(href_list["unbanf"]) @@ -307,20 +296,20 @@ ban_unban_log_save("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") log_and_message_admins("edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") Banlist.cd = "/base/[banfolder]" - Banlist["reason"] << reason - Banlist["temp"] << temp - Banlist["minutes"] << minutes - Banlist["bannedby"] << usr.ckey + to_savefile(Banlist, "reason", reason) + to_savefile(Banlist, "temp", temp) + to_savefile(Banlist, "minutes", minutes) + to_savefile(Banlist, "bannedby", usr.ckey) Banlist.cd = "/base" SSstatistics.add_field("ban_edit",1) unbanpanel() /////////////////////////////////////new ban stuff - else if(href_list["jobban2"]) + else if(href_list["jobban_panel_target"]) // if(!check_rights(R_BAN)) return - var/mob/M = locate(href_list["jobban2"]) + var/mob/M = locate(href_list["jobban_panel_target"]) if(!ismob(M)) to_chat(usr, "This can only be used on instances of type /mob") return @@ -340,282 +329,71 @@ -Nodrak ************************************WARNING!***********************************/ var/counter = 0 -//Regular jobs - //Command (Blue) - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department(DEPT_COMMAND)) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 6) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Command Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Command Support (Sky Blue) - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("support")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 6) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Command Support Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Security (Red) - counter = 0 - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("security")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Security Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Engineering (Yellow) - counter = 0 - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("engineering")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Engineering Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Medical (White) - counter = 0 - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("medical")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Medical Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Science (Purple) - counter = 0 - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("science")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Science Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Exploration (Pale Purple) - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("exploration")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 6) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Exploration Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Service (Tea Green) - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("service")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 6) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Service Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - - //Supply (Khaki) - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("supply")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 6) //So things dont get squiiiiished! - jobs += "" - counter = 0 - jobs += "
          Supply Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " - - //Civilian (Grey) - counter = 0 - jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("civilian")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - jobs += "" - counter = 0 - - if(jobban_isbanned(M, "Internal Affairs Agent")) - jobs += "" - else - jobs += "" - - jobs += "
          Civilian Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          Internal Affairs AgentInternal Affairs Agent
          " - - //Non-Human (Green) + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dtype in all_departments) + var/decl/department/dept = all_departments[dtype] + var/list/print_jobs = SSjobs.titles_by_department(dtype) + jobs += "" + jobs += "" + for(var/jobPos in print_jobs) + var/datum/job/job = SSjobs.get_by_title(jobPos) + if(!job) + continue + if(jobban_isbanned(M, job.title)) + jobs += "" + counter++ + else + jobs += "" + counter++ + if(counter >= MAX_JOBBAN_CELLS) + jobs += "" + counter = 0 + jobs += "
          [capitalize(dept.name)] Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          " + + // Other non-human bans. counter = 0 jobs += "" - jobs += "" - for(var/jobPos in SSjobs.titles_by_department("misc")) - if(!jobPos) continue - var/datum/job/job = SSjobs.get_by_title(jobPos) - if(!job) continue - - if(jobban_isbanned(M, job.title)) - jobs += "" - counter++ - else - jobs += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - jobs += "" - counter = 0 - - //pAI isn't technically a job, but it goes in here. - + jobs += "" if(jobban_isbanned(M, "pAI")) - jobs += "" + jobs += "" else - jobs += "" + jobs += "" if(jobban_isbanned(M, "AntagHUD")) - jobs += "" + jobs += "" else - jobs += "" + jobs += "" jobs += "
          Non-human Positions
          [replacetext(job.title, " ", " ")][replacetext(job.title, " ", " ")]
          Other Positions
          pAIpAIpAIpAIAntagHUDAntagHUDAntagHUDAntagHUD
          " //Antagonist (Orange) jobs += "" - jobs += "" + jobs += "" // Antagonists. #define ANTAG_COLUMNS 5 - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) var/i = 1 for(var/antag_type in all_antag_types) - var/datum/antagonist/antag = all_antag_types[antag_type] - if(!antag || !antag.id) + var/decl/special_role/antag = all_antag_types[antag_type] + if(!antag) continue - if(jobban_isbanned(M, "[antag.id]")) - jobs += "" + if(jobban_isbanned(M, antag.type)) + jobs += "" else - jobs += "" + jobs += "" if(i % ANTAG_COLUMNS == 0 && i < length(all_antag_types)) jobs += "" i++ jobs += "
          Antagonist Positions
          Antagonist Positions
          [replacetext("[antag.role_text]", " ", " ")][replacetext("[antag.name]", " ", " ")][replacetext("[antag.role_text]", " ", " ")][replacetext("[antag.name]", " ", " ")]
          " #undef ANTAG_COLUMNS - var/list/misc_roles = list("Botany Roles", "Graffiti") //Other roles (BLUE, because I have no idea what other color to make this) jobs += "" - jobs += "" - for(var/entry in misc_roles) + jobs += "" + for(var/entry in misc_jobban_roles) if(jobban_isbanned(M, entry)) - jobs += "" + jobs += "" else - jobs += "" + jobs += "" jobs += "
          Other Roles
          Other Roles
          [entry][entry][entry][entry]
          " // Channels @@ -625,28 +403,28 @@ for(var/channel_type in channels) var/decl/communication_channel/channel = channels[channel_type] if(jobban_isbanned(M, channel.name)) - jobs += "[channel.name]" + jobs += "[channel.name]" else - jobs += "[channel.name]" + jobs += "[channel.name]" jobs += "" // Finalize and display. body = "[jobs]" dat = "[header][body]" - show_browser(usr, dat, "window=jobban2;size=800x490") + show_browser(usr, dat, "window=jobban_panel_target;size=800x490") return //JOBBAN'S INNARDS - else if(href_list["jobban3"]) + else if(href_list["jobban_category"]) if(!check_rights(R_MOD,0) && !check_rights(R_ADMIN,0)) to_chat(usr, "You do not have the appropriate permissions to add job bans!") return - if(check_rights(R_MOD,0) && !check_rights(R_ADMIN,0) && !config.mods_can_job_tempban) // If mod and tempban disabled + if(check_rights(R_MOD,0) && !check_rights(R_ADMIN,0) && !get_config_value(/decl/config/toggle/mods_can_job_tempban)) // If mod and tempban disabled to_chat(usr, "Mod jobbanning is disabled!") return - var/mob/M = locate(href_list["jobban4"]) + var/mob/M = locate(href_list["jobban_mob_target"]) if(!ismob(M)) to_chat(usr, "This can only be used on instances of type /mob") return @@ -658,83 +436,22 @@ //get jobs for department if specified, otherwise just returnt he one job in a list. var/list/job_list = list() - switch(href_list["jobban3"]) - if("commanddept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_COMMAND)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("supportdept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_SUPPORT)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("securitydept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_COMMAND)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("engineeringdept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_ENGINEERING)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("medicaldept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_MEDICAL)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("sciencedept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_SCIENCE)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("explorationdept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_EXPLORATION)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("servicedept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_SERVICE)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("supplydept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_SUPPLY)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("civiliandept") - for(var/jobPos in SSjobs.titles_by_department(DEPT_CIVILIAN)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title - if("nonhumandept") - job_list += "pAI" - for(var/jobPos in SSjobs.titles_by_department(DEPT_MISC)) - if(!jobPos) continue - var/datum/job/temp = SSjobs.get_by_title(jobPos) - if(!temp) continue - job_list += temp.title + var/decl/department/ban_dept = SSjobs.get_department_by_name(href_list["jobban_category"]) + if(ban_dept) + for(var/jobPos in SSjobs.titles_by_department(ban_dept.type)) + var/datum/job/temp = SSjobs.get_by_title(jobPos) + if(temp) + job_list |= temp.title + switch(href_list["jobban_category"]) + if("miscnonhumanroles") + job_list |= "pAI" if("Syndicate") - var/list/all_antag_types = GLOB.all_antag_types_ + var/list/all_antag_types = decls_repository.get_decls_of_subtype(/decl/special_role) for(var/antagPos in all_antag_types) - if(!antagPos) continue - var/datum/antagonist/temp = all_antag_types[antagPos] - if(!temp) continue - job_list += temp.id - else - job_list += href_list["jobban3"] + var/decl/special_role/temp = all_antag_types[antagPos] + job_list |= temp.name + if(!length(job_list)) + job_list += href_list["jobban_category"] //Create a list of unbanned jobs within job_list var/list/notbannedlist = list() @@ -749,23 +466,25 @@ if(!check_rights(R_MOD,0) && !check_rights(R_BAN, 0)) to_chat(usr, " You cannot issue temporary job-bans!") return - if(config.ban_legacy_system) + if(get_config_value(/decl/config/toggle/on/ban_legacy_system)) to_chat(usr, "Your server is using the legacy banning system, which does not support temporary job bans. Consider upgrading. Aborting ban.") return var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null if(!mins) return - if(check_rights(R_MOD, 0) && !check_rights(R_BAN, 0) && mins > config.mod_job_tempban_max) - to_chat(usr, " Moderators can only job tempban up to [config.mod_job_tempban_max] minutes!") + var/mod_job_tempban_max = get_config_value(/decl/config/num/mod_job_tempban_max) + if(check_rights(R_MOD, 0) && !check_rights(R_BAN, 0) && mins > mod_job_tempban_max) + to_chat(usr, " Moderators can only job tempban up to [mod_job_tempban_max] minutes!") return var/reason = sanitize(input(usr,"Reason?","Please State Reason","") as text|null) if(!reason) return var/msg + var/mins_readable = minutes_to_readable(mins) for(var/job in notbannedlist) - ban_unban_log_save("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes. reason: [reason]") - log_admin("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes") + ban_unban_log_save("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins_readable]. reason: [reason]") + log_admin("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins_readable]") SSstatistics.add_field("ban_job_tmp",1) DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job) SSstatistics.add_field_details("ban_job_tmp","- [job]") @@ -775,11 +494,11 @@ else msg += ", [job]" notes_add(LAST_CKEY(M), "Banned from [msg] - [reason]", usr) - message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1) + message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins_readable]", 1) to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].") to_chat(M, "The reason is: [reason]") - to_chat(M, "This jobban will be lifted in [mins] minutes.") - href_list["jobban2"] = 1 // lets it fall through and refresh + to_chat(M, "This jobban will be lifted in [mins_readable].") + href_list["jobban_panel_target"] = 1 // lets it fall through and refresh return 1 if("No") if(!check_rights(R_BAN)) return @@ -800,7 +519,7 @@ to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].") to_chat(M, "The reason is: [reason]") to_chat(M, "Jobban can be lifted only upon request.") - href_list["jobban2"] = 1 // lets it fall through and refresh + href_list["jobban_panel_target"] = 1 // lets it fall through and refresh return 1 if("Cancel") return @@ -808,7 +527,7 @@ //Unbanning job list //all jobs in job list are banned already OR we didn't give a reason (implying they shouldn't be banned) if(LAZYLEN(SSjobs.titles_to_datums)) //at least 1 banned job exists in job list so we have stuff to unban. - if(!config.ban_legacy_system) + if(!get_config_value(/decl/config/toggle/on/ban_legacy_system)) to_chat(usr, "Unfortunately, database based unbanning cannot be done through this panel") DB_ban_panel(M.ckey) return @@ -831,7 +550,7 @@ if(msg) message_admins("[key_name_admin(usr)] unbanned [key_name_admin(M)] from [msg]", 1) to_chat(M, "You have been un-jobbanned by [usr.client.ckey] from [msg].") - href_list["jobban2"] = 1 // lets it fall through and refresh + href_list["jobban_panel_target"] = 1 // lets it fall through and refresh return 1 return 0 //we didn't do anything! @@ -842,9 +561,9 @@ return var/reason = sanitize(input("Please enter reason")) if(!reason) - to_chat(M, "You have been kicked from the server") + to_chat(M, SPAN_WARNING("You have been kicked from the server.")) else - to_chat(M, "You have been kicked from the server: [reason]") + to_chat(M, SPAN_WARNING("You have been kicked from the server: [reason]")) log_and_message_admins("booted [key_name_admin(M)].") //M.client = null qdel(M.client) @@ -868,7 +587,7 @@ to_chat(usr, "You do not have the appropriate permissions to add bans!") return - if(check_rights(R_MOD,0) && !check_rights(R_ADMIN, 0) && !config.mods_can_job_tempban) // If mod and tempban disabled + if(check_rights(R_MOD,0) && !check_rights(R_ADMIN, 0) && !get_config_value(/decl/config/toggle/mods_can_job_tempban)) // If mod and tempban disabled to_chat(usr, "Mod jobbanning is disabled!") return @@ -887,8 +606,9 @@ var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null if(!mins) return - if(check_rights(R_MOD, 0) && !check_rights(R_BAN, 0) && mins > config.mod_tempban_max) - to_chat(usr, "Moderators can only job tempban up to [config.mod_tempban_max] minutes!") + var/mod_tempban_max = get_config_value(/decl/config/num/mod_tempban_max) + if(check_rights(R_MOD, 0) && !check_rights(R_BAN, 0) && mins > mod_tempban_max) + to_chat(usr, "Moderators can only job tempban up to [mod_tempban_max] minutes!") return if(mins >= 525600) mins = 525599 var/reason = sanitize(input(usr,"Reason?","reason","Griefer") as text|null) @@ -900,18 +620,20 @@ show_player_panel(M) return AddBan(mob_key, M.computer_id, reason, usr.ckey, 1, mins) - ban_unban_log_save("[usr.client.ckey] has banned [mob_key]. - Reason: [reason] - This will be removed in [mins] minutes.") - notes_add(mob_key,"[usr.client.ckey] has banned [mob_key]. - Reason: [reason] - This will be removed in [mins] minutes.",usr) + var/mins_readable = minutes_to_readable(mins) + ban_unban_log_save("[usr.client.ckey] has banned [mob_key]. - Reason: [reason] - This will be removed in [mins_readable].") + notes_add(mob_key,"[usr.client.ckey] has banned [mob_key]. - Reason: [reason] - This will be removed in [mins_readable].",usr) to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].") - to_chat(M, "This is a temporary ban, it will be removed in [mins] minutes.") + to_chat(M, "This is a temporary ban, it will be removed in [mins_readable].") SSstatistics.add_field("ban_tmp",1) DB_ban_record(BANTYPE_TEMP, M, mins, reason) SSstatistics.add_field("ban_tmp_mins",mins) - if(config.banappeals) - to_chat(M, "To try to resolve this matter head to [config.banappeals]") + var/banappeals = get_config_value(/decl/config/text/banappeals) + if(banappeals) + to_chat(M, "To try to resolve this matter head to [banappeals]") else to_chat(M, "No ban appeals URL has been set.") - log_and_message_admins("has banned [mob_key].\nReason: [reason]\nThis will be removed in [mins] minutes.") + log_and_message_admins("has banned [mob_key].\nReason: [reason]\nThis will be removed in [mins_readable].") qdel(M.client) //qdel(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends. @@ -933,8 +655,9 @@ AddBan(mob_key, M.computer_id, reason, usr.ckey, 0, 0) to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].") to_chat(M, "This is a ban until appeal.") - if(config.banappeals) - to_chat(M, "To try to resolve this matter head to [config.banappeals]") + var/banappeals = get_config_value(/decl/config/text/banappeals) + if(banappeals) + to_chat(M, "To try to resolve this matter head to [banappeals]") else to_chat(M, "No ban appeals URL has been set.") ban_unban_log_save("[usr.client.ckey] has permabanned [mob_key]. - Reason: [reason] - This is a ban until appeal.") @@ -967,10 +690,11 @@ if(SSticker.mode) return alert(usr, "The game has already started.", null, null, null, null) var/dat = {"What mode do you wish to play?
          "} - for(var/mode in config.modes) - dat += {"[config.mode_names[mode]]
          "} - dat += {"Secret
          "} - dat += {"Random
          "} + var/list/mode_names = get_config_value(/decl/config/lists/mode_names) + for(var/mode in get_config_value(/decl/config/lists/mode_allowed)) + dat += {"[mode_names[mode]]
          "} + dat += {"Secret
          "} + dat += {"Random
          "} dat += {"Now: [SSticker.master_mode]"} show_browser(usr, dat, "window=c_mode") @@ -982,9 +706,10 @@ if(SSticker.master_mode != "secret") return alert(usr, "The game mode has to be secret!", null, null, null, null) var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret.
          "} - for(var/mode in config.modes) - dat += {"[config.mode_names[mode]]
          "} - dat += {"Random (default)
          "} + var/list/mode_names = get_config_value(/decl/config/lists/mode_names) + for(var/mode in get_config_value(/decl/config/lists/mode_allowed)) + dat += {"[mode_names[mode]]
          "} + dat += {"Random (default)
          "} dat += {"Now: [secret_force_mode]"} show_browser(usr, dat, "window=f_secret") @@ -1016,9 +741,9 @@ else if(href_list["monkeyone"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["monkeyone"]) + var/mob/living/human/H = locate(href_list["monkeyone"]) if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + to_chat(usr, "This can only be used on instances of type /mob/living/human") return log_and_message_admins("attempting to monkeyize [key_name_admin(H)]") @@ -1027,9 +752,9 @@ else if(href_list["corgione"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["corgione"]) + var/mob/living/human/H = locate(href_list["corgione"]) if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + to_chat(usr, "This can only be used on instances of type /mob/living/human") return log_and_message_admins("attempting to corgize [key_name_admin(H)]") @@ -1048,156 +773,15 @@ speech = sanitize(speech) // Nah, we don't trust them log_and_message_admins("forced [key_name_admin(M)] to say: [speech]") - else if(href_list["sendtoprison"]) - if(!check_rights(R_ADMIN)) return - - if(alert(usr, "Send to admin prison for the round?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["sendtoprison"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(istype(M, /mob/living/silicon/ai)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") - return - - var/turf/prison_cell = pick(GLOB.prisonwarp) - if(!prison_cell) return - - var/obj/structure/closet/secure_closet/brig/locker = new /obj/structure/closet/secure_closet/brig(prison_cell) - locker.opened = 0 - locker.locked = 1 - - //strip their stuff and stick it in the crate - for(var/obj/item/I in M) - M.drop_from_inventory(I, locker) - M.update_icons() - - //so they black out before warping - M.Paralyse(5) - sleep(5) - if(!M) return - - M.forceMove(prison_cell) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/prisoner = M - prisoner.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(prisoner), slot_w_uniform) - prisoner.equip_to_slot_or_del(new /obj/item/clothing/shoes/color/orange(prisoner), slot_shoes) - - to_chat(M, "You have been sent to the prison station!") - log_and_message_admins("sent [key_name_admin(M)] to the prison station.") - - else if(href_list["tdome1"]) - if(!check_rights(R_FUN)) return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdome1"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(istype(M, /mob/living/silicon/ai)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") - return - - for(var/obj/item/I in M) - M.drop_from_inventory(I) - - M.Paralyse(5) - sleep(5) - M.forceMove(pick(GLOB.tdome1)) - spawn(50) - to_chat(M, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Team 1)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Team 1)", 1) - - else if(href_list["tdome2"]) - if(!check_rights(R_FUN)) return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdome2"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(istype(M, /mob/living/silicon/ai)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") - return - - for(var/obj/item/I in M) - M.drop_from_inventory(I) - - M.Paralyse(5) - sleep(5) - M.forceMove(pick(GLOB.tdome2)) - spawn(50) - to_chat(M, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Team 2)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Team 2)", 1) - - else if(href_list["tdomeadmin"]) - if(!check_rights(R_FUN)) return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdomeadmin"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(istype(M, /mob/living/silicon/ai)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") - return - - M.Paralyse(5) - sleep(5) - M.forceMove(pick(GLOB.tdomeadmin)) - spawn(50) - to_chat(M, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Admin.)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Admin.)", 1) - - else if(href_list["tdomeobserve"]) - if(!check_rights(R_FUN)) return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdomeobserve"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(istype(M, /mob/living/silicon/ai)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") - return - - for(var/obj/item/I in M) - M.drop_from_inventory(I) - - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/observer = M - observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), slot_w_uniform) - observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/color/black(observer), slot_shoes) - M.Paralyse(5) - sleep(5) - M.forceMove(pick(GLOB.tdomeobserve)) - spawn(50) - to_chat(M, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(M)] to the thunderdome. (Observer.)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to the thunderdome. (Observer.)", 1) - else if(href_list["revive"]) - if(!check_rights(R_REJUVINATE)) return + if(!check_rights(R_REJUVENATE)) return var/mob/living/L = locate(href_list["revive"]) if(!istype(L)) to_chat(usr, "This can only be used on instances of type /mob/living") return - if(config.allow_admin_rev) + if(get_config_value(/decl/config/toggle/on/admin_revive)) L.revive() log_and_message_admins("healed/revived [key_name(L)]") else @@ -1206,30 +790,20 @@ else if(href_list["makeai"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["makeai"]) + var/mob/living/human/H = locate(href_list["makeai"]) if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + to_chat(usr, "This can only be used on instances of type /mob/living/human") return log_and_message_admins("AIized [key_name_admin(H)]!") H.AIize() - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) return - - var/mob/living/carbon/human/H = locate(href_list["makeslime"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") - return - - usr.client.cmd_admin_slimeize(H) - else if(href_list["makerobot"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["makerobot"]) + var/mob/living/human/H = locate(href_list["makerobot"]) if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + to_chat(usr, "This can only be used on instances of type /mob/living/human") return usr.client.cmd_admin_robotize(H) @@ -1238,25 +812,12 @@ if(!check_rights(R_SPAWN)) return var/mob/M = locate(href_list["makeanimal"]) - if(istype(M, /mob/new_player)) + if(isnewplayer(M)) to_chat(usr, "This cannot be used on instances of type /mob/new_player") return usr.client.cmd_admin_animalize(M) - else if(href_list["togmutate"]) - if(!check_rights(R_SPAWN)) return - - var/mob/living/carbon/human/H = locate(href_list["togmutate"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") - return - var/block=text2num(href_list["block"]) - //testing("togmutate([href_list["block"]] -> [block])") - usr.client.cmd_admin_toggle_block(H,block) - show_player_panel(H) - //H.regenerate_icons() - else if(href_list["adminplayeropts"]) var/mob/M = locate(href_list["adminplayeropts"]) show_player_panel(M) @@ -1290,8 +851,8 @@ sleep(2) G.ManualFollow(M) - else if(href_list["check_antagonist"]) - check_antagonists() + else if(href_list["show_round_status"]) + show_round_status() // call dibs on IC messages (prays, emergency comms, faxes) else if(href_list["take_ic"]) @@ -1299,7 +860,7 @@ var/mob/M = locate(href_list["take_question"]) if(ismob(M)) var/take_msg = "[key_name(usr.client)] is attending to [key_name(M)]'s message." - for(var/client/X in GLOB.admins) + for(var/client/X in global.admins) if((R_ADMIN|R_MOD) & X.holder.rights) to_chat(X, take_msg) to_chat(M, "Your message is being attended to by [usr.client]. Thanks for your patience!") @@ -1338,7 +899,6 @@ var/location_description = "" var/special_role_description = "" var/health_description = "" - var/gender_description = "" var/turf/T = get_turf(M) //Location @@ -1350,9 +910,9 @@ //Job + antagonist if(M.mind) - special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]; Has been rev: [(M.mind.has_been_rev)?"Yes":"No"]" + special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.get_special_role_name("unknown role")]" else - special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing; Has been rev: Mind datum missing;" + special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing" //Health if(isliving(M)) @@ -1363,31 +923,26 @@ if (1) status = "Unconscious" if (2) status = "Dead" health_description = "Status = [status]" - health_description += "
          Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getBrainLoss()]" + health_description += "
          Oxy: [L.get_damage(OXY)] - Tox: [L.get_damage(TOX)] - Fire: [L.get_damage(BURN)] - Brute: [L.get_damage(BRUTE)] - Clone: [L.get_damage(CLONE)] - Brain: [L.get_damage(BRAIN)]" else health_description = "This mob type has no health to speak of." - //Gener - switch(M.gender) - if(MALE,FEMALE) gender_description = "[M.gender]" - else gender_description = "[M.gender]" - to_chat(src.owner, "Info about [M.name]: ") - to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]") + to_chat(src.owner, "Mob type = [M.type]; Gender = [M.gender] Damage = [health_description]") to_chat(src.owner, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];") to_chat(src.owner, "Location = [location_description];") to_chat(src.owner, "[special_role_description]") - to_chat(src.owner, "(PM) (PP) (VV) ([admin_jump_link(M, src)]) (CA)") + to_chat(src.owner, "(PM) (PP) (VV) ([admin_jump_link(M, src)]) (RS)") else if(href_list["adminspawnprayreward"]) if(!check_rights(R_ADMIN|R_FUN)) return - var/mob/living/carbon/human/H = locate(href_list["adminspawnprayreward"]) + var/mob/living/human/H = locate(href_list["adminspawnprayreward"]) if(!ishuman(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + to_chat(usr, "This can only be used on instances of type /mob/living/human") return - var/obj/item/C = new GLOB.using_map.pray_reward_type(get_turf(H)) + var/obj/item/C = new global.using_map.pray_reward_type(get_turf(H)) H.put_in_hands(C) if(C.loc !=H) message_admins("[key_name(H)] has their hands full, so they did not receive their [C.name], spawned by [key_name(src.owner)].") @@ -1426,21 +981,20 @@ var/obj/effect/stop/S S = new /obj/effect/stop(M.loc) S.victim = M - spawn(20) - qdel(S) + QDEL_IN(S, 2 SECONDS) - var/turf/simulated/floor/T = get_turf(M) + var/turf/floor/T = get_turf(M) if(istype(T)) if(prob(80)) T.break_tile_to_plating() else T.break_tile() - if(M.health == 1) + if(M.current_health == 1) M.gib() else - M.adjustBruteLoss( min( 99 , (M.health - 1) ) ) - M.Stun(20) - M.Weaken(20) - M.stuttering = 20 + M.take_damage(min(99, M.current_health - 1)) + SET_STATUS_MAX(M, STAT_STUN, 20) + SET_STATUS_MAX(M, STAT_WEAK, 20) + M.set_status_condition(STAT_STUTTER, 20) else if(href_list["CentcommReply"]) var/mob/living/L = locate(href_list["CentcommReply"]) @@ -1466,11 +1020,13 @@ else if(href_list["SyndicateReply"]) - var/mob/living/carbon/human/H = locate(href_list["SyndicateReply"]) + var/mob/living/human/H = locate(href_list["SyndicateReply"]) if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + to_chat(usr, "This can only be used on instances of type /mob/living/human") return - if(!istype(H.l_ear, /obj/item/radio/headset) && !istype(H.r_ear, /obj/item/radio/headset)) + var/obj/item/l_ear = H.get_equipped_item(slot_l_ear_str) + var/obj/item/r_ear = H.get_equipped_item(slot_r_ear_str) + if(!istype(l_ear, /obj/item/radio/headset) && !istype(r_ear, /obj/item/radio/headset)) to_chat(usr, "The person you are trying to contact is not wearing a headset") return @@ -1485,10 +1041,10 @@ var/obj/item/fax = locate(href_list["AdminFaxView"]) if (istype(fax, /obj/item/paper)) var/obj/item/paper/P = fax - P.show_content(usr,1) + P.interact(usr, TRUE, admin_interact = TRUE) else if (istype(fax, /obj/item/photo)) var/obj/item/photo/H = fax - H.show(usr) + H.interact(usr) else if (istype(fax, /obj/item/paper_bundle)) //having multiple people turning pages on a paper_bundle can cause issues //open a browse window listing the contents instead @@ -1497,7 +1053,7 @@ for (var/page = 1, page <= B.pages.len, page++) var/obj/pageobj = B.pages[page] - data += "Page [page] - [pageobj.name]
          " + data += "Page [page] - [pageobj.name]
          " show_browser(usr, data, "window=[B.name]") else @@ -1510,26 +1066,23 @@ if (istype(bundle.pages[page], /obj/item/paper)) var/obj/item/paper/P = bundle.pages[page] - P.show_content(src.owner, 1) + P.interact(src.owner, TRUE) else if (istype(bundle.pages[page], /obj/item/photo)) var/obj/item/photo/H = bundle.pages[page] - H.show(src.owner) + H.interact(src.owner) return else if(href_list["FaxReply"]) var/mob/sender = locate(href_list["FaxReply"]) - var/obj/machinery/photocopier/faxmachine/fax = locate(href_list["originfax"]) + var/obj/machinery/faxmachine/fax = locate(href_list["originfax"]) var/replyorigin = href_list["replyorigin"] - - var/obj/item/paper/admin/P = new /obj/item/paper/admin( null ) //hopefully the null loc won't cause trouble for us + var/obj/item/paper/admin/P = new /obj/item/paper/admin faxreply = P - P.admindatum = src P.origin = replyorigin - P.destination = fax + P.destination_ref = weakref(fax) P.sender = sender - P.adminbrowse() else if(href_list["jumpto"]) @@ -1557,18 +1110,18 @@ var/mob/M = locate(href_list["narrateto"]) usr.client.cmd_admin_direct_narrate(M) - else if(href_list["traitor"]) + else if(href_list["show_special_roles"]) if(!check_rights(R_ADMIN|R_MOD)) return if(GAME_STATE < RUNLEVEL_GAME) alert("The game hasn't started yet!") return - var/mob/M = locate(href_list["traitor"]) + var/mob/M = locate(href_list["show_special_roles"]) if(!ismob(M)) to_chat(usr, "This can only be used on instances of type /mob.") return - show_traitor_panel(M) + show_special_roles(M) else if(href_list["skillpanel"]) if(!check_rights(R_INVESTIGATE)) @@ -1600,7 +1153,7 @@ else if(href_list["object_list"]) //this is the laggiest thing ever if(!check_rights(R_SPAWN)) return - if(!config.allow_admin_spawning) + if(!get_config_value(/decl/config/toggle/on/admin_spawning)) to_chat(usr, "Spawning of items is not allowed.") return @@ -1623,14 +1176,6 @@ else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob)) removed_paths += dirty_path continue - else if(ispath(path, /obj/item/energy_blade/blade))//Not an item one should be able to spawn./N - if(!check_rights(R_FUN,0)) - removed_paths += dirty_path - continue - else if(ispath(path, /obj/effect/bhole)) - if(!check_rights(R_FUN,0)) - removed_paths += dirty_path - continue paths += path if(!paths) @@ -1643,7 +1188,7 @@ alert("Removed:\n" + jointext(removed_paths, "\n")) var/list/offset = splittext(href_list["offset"],",") - var/number = dd_range(1, 100, text2num(href_list["object_count"])) + var/number = clamp(text2num(href_list["object_count"]), 1, 100) var/X = offset.len > 0 ? text2num(offset[1]) : 0 var/Y = offset.len > 1 ? text2num(offset[2]) : 0 var/Z = offset.len > 2 ? text2num(offset[3]) : 0 @@ -1664,7 +1209,7 @@ if ( !( ishuman(usr) || issmall(usr) ) ) to_chat(usr, "Can only spawn in hand when you're a human or a monkey.") where = "onfloor" - else if ( usr.get_active_hand() ) + else if ( usr.get_active_held_item() ) to_chat(usr, "Your active hand is full. Spawning on floor.") where = "onfloor" @@ -1704,7 +1249,7 @@ O.set_dir(obj_dir) if(obj_name) O.SetName(obj_name) - if(istype(O,/mob)) + if(ismob(O)) var/mob/M = O M.real_name = obj_name @@ -1724,7 +1269,7 @@ src.access_news_network() else if(href_list["ac_set_channel_name"]) - src.admincaster_feed_channel.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "")) + src.admincaster_feed_channel.channel_name = sanitize_safe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "")) src.access_news_network() else if(href_list["ac_set_channel_lock"]) @@ -1752,7 +1297,7 @@ var/list/available_channels = list() for(var/datum/feed_channel/F in news_network.network_channels) available_channels += F.channel_name - src.admincaster_feed_channel.channel_name = sanitizeSafe(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels ) + src.admincaster_feed_channel.channel_name = sanitize_safe(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels ) src.access_news_network() else if(href_list["ac_set_new_message"]) @@ -1925,13 +1470,16 @@ if(!istype(M)) to_chat(usr, "[M] is illegal type, must be /mob!") return - var/decl/language/L = SSlore.get_language_by_name(href_list["lang"]) - if(L in M.languages) - if(!M.remove_language(L.type)) - to_chat(usr, "Failed to remove language '[L.name]' from \the [M]!") + var/decl/language/L = locate(href_list["lang"]) + if(istype(L)) + if(L in M.languages) + if(!M.remove_language(L.type)) + to_chat(usr, "Failed to remove language '[L.name]' from \the [M]!") + else + if(!M.add_language(L.type)) + to_chat(usr, "Failed to add language '[L.name]' to \the [M]!") else - if(!M.add_language(L.type)) - to_chat(usr, "Failed to add language '[L.name]' from \the [M]!") + to_chat(usr, "Failed to toggle unknown language on \the [M]!") show_player_panel(M) @@ -1964,6 +1512,7 @@ ckey = LAST_CKEY(M) show_player_info(ckey) return + if(href_list["setstaffwarn"]) var/mob/M = locate(href_list["setstaffwarn"]) if(!ismob(M)) return @@ -1986,6 +1535,7 @@ show_player_panel(M) if("No") return + if(href_list["removestaffwarn"]) var/mob/M = locate(href_list["removestaffwarn"]) if(!ismob(M)) return @@ -2009,21 +1559,69 @@ show_player_panel(M) + if(href_list["asf_pick_fax"]) + var/obj/machinery/faxmachine/F = locate(href_list["destination"]) + if(istype(F)) + close_browser(src.owner, "faxpicker") + var/datum/extension/network_device/D = get_extension(F, /datum/extension/network_device) + if(!D) + log_debug("'[log_info_line(F)]' couldn't get network_device extension!") + return + var/datum/computer_network/CN = D.get_network() + if(CN) + var/obj/item/paper/admin/P = new /obj/item/paper/admin + faxreply = P //Store the message instance + P.admindatum = src + P.origin = href_list["sender"] || (input(src.owner, "Please specify the sender's name", "Origin", global.using_map.boss_name) as text | null) + P.destination_ref = weakref(F) + P.adminbrowse() + else + log_debug("Couldn't get computer network for [log_info_line(D)], where network_id is '[D.network_id]'.") + else + log_debug("Tried to send a fax to an invalid machine!:[log_info_line(F)]\nhref:[log_info_line(href_list)]") + + if(href_list["toggle_mutation"]) + var/mob/M = locate(href_list["toggle_mutation"]) + var/decl/genetic_condition/condition = locate(href_list["block"]) + if(istype(condition) && istype(M) && !QDELETED(M)) + var/result + var/had_condition + if(M.has_genetic_condition(condition.type)) + had_condition = TRUE + result = M.remove_genetic_condition(condition.type) + else + had_condition = FALSE + result = M.add_genetic_condition(condition.type) + if(!isnull(result)) + if(result) + if(had_condition) + log_debug("Removed genetic condition [condition.name] from \the [M] ([M.ckey]).") + else + log_debug("Added genetic condition [condition.name] to \the [M] ([M.ckey]).") + else + log_debug("Failed to toggle genetic condition [condition.name] on \the [M] ([M.ckey]).") + else + log_debug("Could not apply genetic condition [condition.name] to \the [M] ([M.ckey]).") + show_player_panel(M) + return -mob/living/proc/can_centcom_reply() +/mob/living/proc/can_centcom_reply() return 0 -mob/living/carbon/human/can_centcom_reply() - return istype(l_ear, /obj/item/radio/headset) || istype(r_ear, /obj/item/radio/headset) +/mob/living/human/can_centcom_reply() + for(var/slot in global.ear_slots) + var/obj/item/radio/headset/radio = get_equipped_item(slot) + if(istype(radio)) + return TRUE -mob/living/silicon/ai/can_centcom_reply() +/mob/living/silicon/ai/can_centcom_reply() return silicon_radio != null && !check_unable(2) /datum/proc/extra_admin_link(var/prefix, var/sufix, var/short_links) return list() /atom/movable/extra_admin_link(var/source, var/prefix, var/sufix, var/short_links) - return list("[prefix][short_links ? "J" : "JMP"][sufix]") + return list("[prefix][short_links ? "J" : "JMP"][sufix]") /client/extra_admin_link(source, var/prefix, var/sufix, var/short_links) return mob ? mob.extra_admin_link(source, prefix, sufix, short_links) : list() @@ -2031,12 +1629,12 @@ mob/living/silicon/ai/can_centcom_reply() /mob/extra_admin_link(var/source, var/prefix, var/sufix, var/short_links) . = ..() if(client && eyeobj) - . += "[prefix][short_links ? "E" : "EYE"][sufix]" + . += "[prefix][short_links ? "E" : "EYE"][sufix]" /mob/observer/ghost/extra_admin_link(var/source, var/prefix, var/sufix, var/short_links) . = ..() if(mind && (mind.current && !isghost(mind.current))) - . += "[prefix][short_links ? "B" : "BDY"][sufix]" + . += "[prefix][short_links ? "B" : "BDY"][sufix]" /proc/admin_jump_link(var/datum/target, var/source, var/delimiter = "|", var/prefix, var/sufix, var/short_links) if(!istype(target)) @@ -2056,5 +1654,5 @@ mob/living/silicon/ai/can_centcom_reply() /client/get_admin_jump_link(var/atom/target, var/delimiter, var/prefix, var/sufix) if(holder) - var/short_links = get_preference_value(/datum/client_preference/ghost_follow_link_length) == GLOB.PREF_SHORT + var/short_links = get_preference_value(/datum/client_preference/ghost_follow_link_length) == PREF_SHORT return admin_jump_link(target, src, delimiter, prefix, sufix, short_links) diff --git a/code/modules/admin/verbs/BrokenInhands.dm b/code/modules/admin/verbs/BrokenInhands.dm deleted file mode 100644 index 573865089795..000000000000 --- a/code/modules/admin/verbs/BrokenInhands.dm +++ /dev/null @@ -1,37 +0,0 @@ -/proc/getbrokeninhands() - var/icon/IL = new('icons/mob/onmob/items/lefthand.dmi') - var/list/Lstates = IL.IconStates() - var/icon/IR = new('icons/mob/onmob/items/righthand.dmi') - var/list/Rstates = IR.IconStates() - - - var/text - for(var/A in typesof(/obj/item)) - var/obj/item/O = new A( locate(1,1,1) ) - if(!O) continue - var/icon/J = new(O.icon) - var/list/istates = J.IconStates() - if(!Lstates.Find(O.icon_state) && !Lstates.Find(O.item_state)) - if(O.icon_state) - text += "[O.type] is missing left hand icon called \"[O.icon_state]\".\n" - if(!Rstates.Find(O.icon_state) && !Rstates.Find(O.item_state)) - if(O.icon_state) - text += "[O.type] is missing right hand icon called \"[O.icon_state]\".\n" - - - if(O.icon_state) - if(!istates.Find(O.icon_state)) - text += "[O.type] is missing normal icon called \"[O.icon_state]\" in \"[O.icon]\".\n" - //if(O.item_state) - // if(!istates.Find(O.item_state)) - // text += "[O.type] MISSING NORMAL ICON CALLED\n\"[O.item_state]\" IN \"[O.icon]\"\n" - //text+="\n" - qdel(O) - if(text) - var/F = file("broken_icons.txt") - fdel(F) - F << text - log_debug("Completeled successfully and written to [F]") - - - diff --git a/code/modules/admin/verbs/SDQL.dm b/code/modules/admin/verbs/SDQL.dm index f86442919aca..a67da780ff09 100644 --- a/code/modules/admin/verbs/SDQL.dm +++ b/code/modules/admin/verbs/SDQL.dm @@ -12,11 +12,11 @@ if(query_list.len < 2) if(query_list.len > 0) - to_chat(usr, "SDQL: Too few discrete tokens in query \"[query_text]\". Please check your syntax and try again.") + to_chat(usr, SPAN_WARNING("SDQL: Too few discrete tokens in query \"[query_text]\". Please check your syntax and try again.")) return if(!(lowertext(query_list[1]) in list("select", "delete", "update"))) - to_chat(usr, "SDQL: Unknown query type: \"[query_list[1]]\" in query \"[query_text]\". Please check your syntax and try again.") + to_chat(usr, SPAN_WARNING("SDQL: Unknown query type: \"[query_list[1]]\" in query \"[query_text]\". Please check your syntax and try again.")) return var/list/types = list() @@ -55,7 +55,7 @@ set_vars[query_list[i]] = query_list[i + 2] else - to_chat(usr, "SDQL: Invalid set parameter in query \"[query_text]\". Please check your syntax and try again.") + to_chat(usr, SPAN_WARNING("SDQL: Invalid set parameter in query \"[query_text]\". Please check your syntax and try again.")) return i += 3 @@ -64,7 +64,7 @@ break if(set_vars.len < 1) - to_chat(usr, "SDQL: Invalid or missing set in query \"[query_text]\". Please check your syntax and try again.") + to_chat(usr, SPAN_WARNING("SDQL: Invalid or missing set in query \"[query_text]\". Please check your syntax and try again.")) return var/list/where = list() @@ -93,8 +93,13 @@ if(istype(m, f2)) from_objs += m - else if(text_starts_with(f, "/turf/simulated")) - for(var/turf/simulated/m in world) + else if(text_starts_with(f, "/turf/floor")) + for(var/turf/floor/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/wall")) + for(var/turf/wall/m in world) if(istype(m, f2)) from_objs += m @@ -119,7 +124,7 @@ from_objs += m else if(text_starts_with(f, "/obj/machinery")) - for(var/obj/machinery/m in world) + for(var/obj/machinery/m in SSmachines.machinery) if(istype(m, f2)) from_objs += m @@ -162,8 +167,13 @@ if(istype(m, f2)) objs += m - else if(text_starts_with(f, "/turf/simulated")) - for(var/turf/simulated/m in from_obj) + else if(text_starts_with(f, "/turf/floor")) + for(var/turf/floor/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/wall")) + for(var/turf/wall/m in from_obj) if(istype(m, f2)) objs += m @@ -214,7 +224,7 @@ var/v = where[i++] var/compare_op = where[i++] if(!(compare_op in list("==", "=", "<>", "<", ">", "<=", ">=", "!="))) - to_chat(usr, "SDQL: Unknown comparison operator [compare_op] in where clause following [v] in query \"[query_text]\". Please check your syntax and try again.") + to_chat(usr, SPAN_WARNING("SDQL: Unknown comparison operator [compare_op] in where clause following [v] in query \"[query_text]\". Please check your syntax and try again.")) return var/j @@ -261,7 +271,7 @@ - to_chat(usr, "SQDL Query: [query_text]") + to_chat(usr, SPAN_NOTICE("SQDL Query: [query_text]")) message_admins("[usr] executed SDQL query: \"[query_text]\".") /* for(var/t in types) @@ -313,16 +323,16 @@ var/atom/a = t if(a.x) - text += "\ref[t]: [t] at ([a.x], [a.y], [a.z])
          " + text += "\ref[t]: [t] at ([a.x], [a.y], [a.z])
          " else if(a.loc && a.loc.x) - text += "\ref[t]: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
          " + text += "\ref[t]: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
          " else - text += "\ref[t]: [t]
          " + text += "\ref[t]: [t]
          " else - text += "\ref[t]: [t]
          " + text += "\ref[t]: [t]
          " //text += "[t]
          " show_browser(usr, text, "window=sdql_result") @@ -342,7 +352,7 @@ else - to_chat(usr, "SDQL: Sorry, equations not yet supported :(") + to_chat(usr, SPAN_WARNING("SDQL: Sorry, equations not yet supported :(")) return null @@ -371,17 +381,6 @@ else return null - -/proc/text_starts_with(text, start) - if(copytext(text, 1, length(start) + 1) == start) - return 1 - else - return 0 - - - - - /proc/SDQL_tokenize(query_text) var/list/whitespace = list(" ", "\n", "\t") @@ -427,7 +426,7 @@ else if(char == "'") if(word != "") - to_chat(usr, "SDQL: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + to_chat(usr, SPAN_WARNING("SDQL: You have an error in your SDQL syntax, unexpected ' in query: \"[SPAN_GREY(query_text)]\" following \"[SPAN_GREY(word)]\". Please check your syntax, and try again.")) return null word = "'" @@ -447,7 +446,7 @@ word += char if(i > len) - to_chat(usr, "SDQL: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again.") + to_chat(usr, SPAN_WARNING("SDQL: You have an error in your SDQL syntax, unmatched ' in query: \"[SPAN_GREY(query_text)]\". Please check your syntax, and try again.")) return null query_list += "[word]'" @@ -455,7 +454,7 @@ else if(char == "\"") if(word != "") - to_chat(usr, "SDQL: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + to_chat(usr, SPAN_WARNING("SDQL: You have an error in your SDQL syntax, unexpected \" in query: \"[SPAN_GREY(query_text)]\" following \"[SPAN_GREY(word)]\". Please check your syntax, and try again.")) return null word = "\"" @@ -475,7 +474,7 @@ word += char if(i > len) - to_chat(usr, "SDQL: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again.") + to_chat(usr, SPAN_WARNING("SDQL: You have an error in your SDQL syntax, unmatched \" in query: \"[SPAN_GREY(query_text)]\". Please check your syntax, and try again.")) return null query_list += "[word]\"" diff --git a/code/modules/admin/verbs/SDQL_2/SDQL_2.dm b/code/modules/admin/verbs/SDQL_2/SDQL_2.dm index 67fdfe845d4a..71b7f7208c8a 100644 --- a/code/modules/admin/verbs/SDQL_2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL_2/SDQL_2.dm @@ -9,7 +9,7 @@ -- Will change all the tube lights to green, and flicker them. The semicolon is important to separate the consecutive querys, but is not required for standard one-query use. UPDATE /obj/machinery/light SET color = "#0F0" WHERE icon_state == "tube1"; CALL flicker(1) ON /obj/machinery/light -- Will delete all pickaxes. "IN world" is not required. - DELETE /obj/item/pickaxe + DELETE /obj/item/tool/pickaxe --You can use operators other than ==, such as >, <=, != and etc.. @@ -104,15 +104,15 @@ if("select") var/text = "" for(var/datum/t in objs) - text += "\ref[t]" + text += "\ref[t]" if(istype(t, /atom)) var/atom/a = t if(a.x) - text += ": [t] at ([a.x], [a.y], [a.z])
          " + text += ": [t] at ([a.x], [a.y], [a.z])
          " else if(a.loc && a.loc.x) - text += ": [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
          " + text += ": [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
          " else text += ": [t]
          " @@ -133,7 +133,7 @@ var/i = 0 for(var/v in sets) if(++i == sets.len) - if(istype(temp, /turf) && (v == "x" || v == "y" || v == "z")) + if(isturf(temp) && (v == "x" || v == "y" || v == "z")) break temp.SDQL_update(v, SDQL_expression(d, set_list[sets])) @@ -149,9 +149,8 @@ to_chat(usr, "Query executed on [objs.len] object\s.") catch(var/exception/e) - to_chat(usr, "An exception has occured during the execution of your query and your query has been aborted.") - to_chat(usr, "exception name: [e.name]") - to_chat(usr, "file/line: [e.file]/[e.line]") + to_chat(usr, "An exception has occurred during the execution of your query and your query has been aborted.") + to_chat(usr, EXCEPTION_TEXT(e)) return /proc/SDQL_parse(list/query_list) @@ -497,7 +496,7 @@ else if(char == "'") if(word != "") - to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"[SPAN_GREY(query_text)]\" following \"[SPAN_GREY(word)]\". Please check your syntax, and try again.") return null word = "'" @@ -517,7 +516,7 @@ word += char if(i > len) - to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"[SPAN_GREY(query_text)]\". Please check your syntax, and try again.") return null query_list += "[word]'" @@ -525,7 +524,7 @@ else if(char == "\"") if(word != "") - to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"[SPAN_GREY(query_text)]\" following \"[SPAN_GREY(word)]\". Please check your syntax, and try again.") return null word = "\"" @@ -545,7 +544,7 @@ word += char if(i > len) - to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again.") + to_chat(usr, "SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"[SPAN_GREY(query_text)]\". Please check your syntax, and try again.") return null query_list += "[word]\"" diff --git a/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm b/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm index 8d14628a4c05..cb0a00334f4e 100644 --- a/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm +++ b/code/modules/admin/verbs/SDQL_2/SDQL_2_std.dm @@ -23,8 +23,10 @@ /proc/_ascii2text(A) return ascii2text(A) -/proc/_block(Start, End) - return block(Start, End) +/proc/_block(StartX, StartY, StartZ, EndX, EndY, EndZ) + if(isturf(StartX) && isturf(StartY)) + return block(StartX, StartY) + return block(StartX, StartY, StartZ, EndX, EndY, EndZ) /proc/_ckey(Key) return ckey(Key) diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 3a7fcdfcbacb..77017eee5f6c 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -1,6 +1,6 @@ //This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE! -var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as") +var/global/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as") /proc/generate_ahelp_key_words(var/mob/mob, var/msg) var/list/surnames = list() @@ -41,7 +41,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," if(!(word in adminhelp_ignored_words)) if(word == "ai" && !ai_found) ai_found = 1 - msg += "[original_word] (CL) " + msg += "[original_word] (CL) " continue else var/mob/found = ckeys[word] @@ -52,10 +52,10 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," if(found) if(!(found in mobs_found)) mobs_found += found - msg += "[original_word] (?)" + msg += "[original_word] (?)" if(!ai_found && isAI(found)) ai_found = 1 - msg += " (CL)" + msg += " (CL)" msg += " " continue msg += "[original_word] " @@ -68,7 +68,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," //handle muting and automuting if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Admin-PM: You cannot send adminhelps (Muted).") + to_chat(src, SPAN_WARNING("Error: Admin-PM: You cannot send adminhelps (Muted).")) return adminhelped = 1 //Determines if they get the message to reply by clicking the name. @@ -110,31 +110,34 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," ticket.msgs += new /datum/ticket_msg(src.ckey, null, original_msg) update_ticket_panels() + if(establish_db_connection()) + var/sql_text = "HELP [src.ckey]: [sanitize_sql(original_msg)]\n" + var/DBQuery/ticket_text = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `text` = '[sql_text]' WHERE `round` = '[game_id]' AND `inround_id` = '[ticket.id]';") + ticket_text.Execute() //Options bar: mob, details ( admin = 2, dev = 3, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so), // highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name) - msg = "HELP: [get_options_bar(mob, 2, 1, 1, 1, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]" + msg = "HELP: [get_options_bar(mob, 2, 1, 1, 1, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]" var/admin_number_afk = 0 - for(var/client/X in GLOB.admins) + for(var/client/X in global.admins) if((R_ADMIN|R_MOD) & X.holder.rights) if(X.is_afk()) admin_number_afk++ - if(X.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == GLOB.PREF_HEAR) + if(X.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == PREF_HEAR) sound_to(X, 'sound/effects/adminhelp.ogg') to_chat(X, msg) window_flash(X) //show it to the person adminhelping too - to_chat(src, "PM to-Staff (CLOSE): [original_msg]") - var/admin_number_present = GLOB.admins.len - admin_number_afk + to_chat(src, SPAN_BLUE("PM to-Staff (CLOSE): [original_msg]")) + var/admin_number_present = global.admins.len - admin_number_afk log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins.") - if(admin_number_present <= 0) - adminmsg2adminirc(src, null, "[html_decode(original_msg)] - !![admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!") - else - adminmsg2adminirc(src, null, "[html_decode(original_msg)]") SSstatistics.add_field_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Ticket ([ticket.id]) (Game ID: [game_id]) Ticket Opened", "body" = "[ticket.owner.key_name(0)] has opened a ticket. Subject: [original_msg]")) + return diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index cc086ac3f597..80f1d71a0395 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -11,13 +11,13 @@ set category = "Admin" if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(!config.allow_admin_jump) + if(!get_config_value(/decl/config/toggle/on/admin_jump)) return alert("Admin jumping disabled") var/list/areas = area_repository.get_areas_by_z_level() var/area/A = areas[selected_area] mob.jumpTo(pick(get_area_turfs(A))) - log_and_message_admins("jumped to [A]") + log_and_message_admins("jumped to [A.proper_name]") SSstatistics.add_field_details("admin_verb","JA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/jumptoturf(var/turf/T) @@ -25,7 +25,7 @@ set category = "Admin" if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(!config.allow_admin_jump) + if(!get_config_value(/decl/config/toggle/on/admin_jump)) return alert("Admin jumping disabled") log_and_message_admins("jumped to [T.x],[T.y],[T.z] in [T.loc]") @@ -39,7 +39,7 @@ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(config.allow_admin_jump) + if(get_config_value(/decl/config/toggle/on/admin_jump)) log_and_message_admins("jumped to [key_name(M)]") if(mob) var/turf/T = get_turf(M) @@ -58,7 +58,7 @@ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(!config.allow_admin_jump) + if(!get_config_value(/decl/config/toggle/on/admin_jump)) alert("Admin jumping disabled") return if(!mob) @@ -73,7 +73,7 @@ log_and_message_admins("jumped to coordinates [tx], [ty], [tz]") /proc/sorted_client_keys() - return sortKey(GLOB.clients.Copy()) + return sortKey(global.clients.Copy()) /client/proc/jumptokey(client/C in sorted_client_keys()) set category = "Admin" @@ -82,7 +82,7 @@ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(config.allow_admin_jump) + if(get_config_value(/decl/config/toggle/on/admin_jump)) if(!istype(C)) to_chat(usr, "[C] is not a client, somehow.") return @@ -100,7 +100,7 @@ set desc = "Mob to teleport" if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(config.allow_admin_jump) + if(get_config_value(/decl/config/toggle/on/admin_jump)) log_and_message_admins("teleported [key_name(M)] to self.") M.jumpTo(get_turf(mob)) SSstatistics.add_field_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -115,14 +115,14 @@ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(config.allow_admin_jump) - var/list/keys = list() - for(var/mob/M in GLOB.player_list) + if(get_config_value(/decl/config/toggle/on/admin_jump)) + var/list/client/keys = list() + for(var/mob/M in global.player_list) // excludes /mob/new_player keys += M.client - var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) + var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) if(!selection) return - var/mob/M = selection:mob + var/mob/M = selection.mob if(!M) return @@ -133,12 +133,12 @@ else alert("Admin jumping disabled") -/client/proc/sendmob(var/mob/M in sortmobs()) +/client/proc/sendmob(var/mob/M in get_sorted_mob_list()) set category = "Admin" set name = "Send Mob" if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - if(!config.allow_admin_jump) + if(!get_config_value(/decl/config/toggle/on/admin_jump)) alert("Admin jumping disabled") return @@ -148,5 +148,5 @@ if(A) M.jumpTo(pick(get_area_turfs(A))) SSstatistics.add_field_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_and_message_admins("teleported [key_name(M)] to [A].") + log_and_message_admins("teleported [key_name(M)] to [A.proper_name].") diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 294629075fd8..2ec60c912eb9 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -27,7 +27,7 @@ targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T else targets["(No Mob) - [T]"] = T - var/list/sorted = sortList(targets) + var/list/sorted = sortTim(targets, /proc/cmp_text_asc) var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null cmd_admin_pm(targets[target],null) SSstatistics.add_field_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -46,12 +46,12 @@ else to_chat(src, "Error: Private-Message: Client not found. They may have lost connection, so please be patient!") return - var/recieve_pm_type = "Player" + var/receive_pm_type = "Player" if(holder) //mod PMs are maroon //PMs sent from admins and mods display their rank if(holder) - recieve_pm_type = holder.rank + receive_pm_type = holder.rank else if(C && !C.holder) to_chat(src, "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.") @@ -86,14 +86,14 @@ if(isnull(ticket)) // finally, accept that no ticket exists - if(holder && sender_lite.ckey != receiver_lite.ckey) + if(holder) ticket = new /datum/ticket(receiver_lite) ticket.take(sender_lite) else - to_chat(src, "You do not have an open ticket. Please use the adminhelp verb to open a ticket.") + to_chat(src, SPAN_WARNING("You do not have an open ticket. Please use the adminhelp verb to open a ticket.")) return else if(ticket.status != TICKET_ASSIGNED && sender_lite.ckey == ticket.owner.ckey) - to_chat(src, "Your ticket is not open for conversation. Please wait for an administrator to receive your adminhelp.") + to_chat(src, SPAN_WARNING("Your ticket is not open for conversation. Please wait for an administrator to receive your adminhelp.")) return // if the sender is an admin and they're not assigned to the ticket, ask them if they want to take/join it, unless the admin is responding to their own ticket @@ -101,20 +101,23 @@ if(sender_lite.ckey != ticket.owner.ckey && !ticket.take(sender_lite)) return - var/recieve_message + // We are sending this quite early because of a return in the popup code. + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Reply Sent ([ticket.id]) (Game ID: [game_id])", "body" = "**[sender_lite.key_name(FALSE, FALSE)]** to **[receiver_lite.key_name(FALSE, FALSE)]**: [msg]")) + + var/receive_message if(holder && !C.holder) - recieve_message = "-- Click the [recieve_pm_type]'s name to reply --\n" + receive_message = "-- Click the [receive_pm_type]'s name to reply --\n" if(C.adminhelped) - to_chat(C, recieve_message) + to_chat(C, receive_message) C.adminhelped = 0 - //AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn - if(config.popup_admin_pm) + //AdminPM popup for ApocStation and anybody else who wants to use it. + if(get_config_value(/decl/config/toggle/popup_admin_pm)) spawn(0) //so we don't hold the caller proc up var/sender = src var/sendername = key - var/reply = sanitize(input(C, msg,"[recieve_pm_type] PM from [sendername]", "") as text|null) //show message and await a reply + var/reply = sanitize(input(C, msg,"[receive_pm_type] PM from [sendername]", "") as text|null) //show message and await a reply if(C && reply) if(sender) C.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them @@ -124,65 +127,43 @@ var/sender_message = "" + create_text_tag("pm_out_alt", "PM", src) + " to [get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]" if(holder) - sender_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" + sender_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" sender_message += ": [generate_ahelp_key_words(mob, msg)]" else sender_message += ": [msg]" sender_message += "" to_chat(src, sender_message) - var/receiver_message = "" + create_text_tag("pm_in", "", C) + " \[[recieve_pm_type] PM\] [get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]" + var/receiver_message = "" + create_text_tag("pm_in", "", C) + " \[[receive_pm_type] PM\] [get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]" if(C.holder) - receiver_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" + receiver_message += " ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE)" receiver_message += ": [generate_ahelp_key_words(C.mob, msg)]" else receiver_message += ": [msg]" receiver_message += "" to_chat(C, receiver_message) + window_flash(C) - //play the recieving admin the adminhelp sound (if they have them enabled) + //play the receiving admin the adminhelp sound (if they have them enabled) //non-admins shouldn't be able to disable this - if(C.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == GLOB.PREF_HEAR) + if(C.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == PREF_HEAR) sound_to(C, 'sound/effects/adminhelp.ogg') log_admin("PM: [key_name(src)]->[key_name(C)]: [msg]") - adminmsg2adminirc(src, C, html_decode(msg)) ticket.msgs += new /datum/ticket_msg(src.ckey, C.ckey, msg) update_ticket_panels() + if(establish_db_connection()) + var/sql_text = "[src.ckey] -> [C.ckey]: [sanitize_sql(msg)]\n" + var/DBQuery/ticket_text = dbcon.NewQuery("UPDATE `erro_admin_tickets` SET `text` = CONCAT(COALESCE(text,''), '[sql_text]') WHERE `round` = '[game_id]' AND `inround_id` = '[ticket.id]';") + ticket_text.Execute() + //we don't use message_admins here because the sender/receiver might get it too - for(var/client/X in GLOB.admins) + for(var/client/X in global.admins) //check client/X is an admin and isn't the sender or recipient if(X == C || X == src) continue if(X.key != key && X.key != C.key && (X.holder.rights & R_ADMIN|R_MOD)) - to_chat(X, "" + create_text_tag("pm_other", "PM:", X) + " [key_name(src, X, 0, ticket)] to [key_name(C, X, 0, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]") - -/client/proc/cmd_admin_irc_pm(sender) - if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Private-Message: You are unable to use PM-s (muted).") - return - - var/msg = input(src,"Message:", "Reply private message to [sender] on IRC / 400 character limit") as text|null - - if(!msg) - return - - // Handled on Bot32's end, unsure about other bots -// if(length(msg) > 400) // TODO: if message length is over 400, divide it up into seperate messages, the message length restriction is based on IRC limitations. Probably easier to do this on the bots ends. -// to_chat(src, "Your message was not sent because it was more then 400 characters find your message below for ease of copy/pasting") -// to_chat(src, "[msg]") -// return - - log_admin("PM: [key_name(src)]->IRC-[sender]: [msg]") - adminmsg2adminirc(src, sender, html_decode(msg)) - admin_pm_repository.store_pm(src, "IRC-[sender]", msg) - - to_chat(src, "" + create_text_tag("pm_out_alt", "PM", src) + " to [sender]: [msg]") - for(var/client/X in GLOB.admins) - if(X == src) - continue - if(X.holder.rights & R_ADMIN|R_MOD) - to_chat(X, "" + create_text_tag("pm_other", "PM:", X) + " [key_name(src, X, 0)] to [sender]: [msg]") + to_chat(X, "" + create_text_tag("pm_other", "PM:", X) + " [key_name(src, X, 0, ticket)] to [key_name(C, X, 0, ticket)] ([(ticket.status == TICKET_OPEN) ? "TAKE" : "JOIN"]) (CLOSE): [msg]") diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 2f1833d0b524..5eb7a81a268f 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -7,10 +7,10 @@ msg = sanitize(msg) if(!msg) return - log_admin("ADMIN: [key_name(src)] : [msg]") + log_adminsay("[key_name(src)] : [msg]") if(check_rights(R_ADMIN,0)) - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(R_ADMIN & C.holder.rights) to_chat(C, "" + create_text_tag("admin", "ADMIN:", C) + " [key_name(usr, 1)]([admin_jump_link(mob, src)]): [msg]") @@ -33,7 +33,7 @@ var/sender_name = key_name(usr, 1) if(check_rights(R_ADMIN, 0)) sender_name = "[sender_name]" - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) to_chat(C, "" + create_text_tag("mod", "MOD:", C) + " [sender_name]([admin_jump_link(mob, C.holder)]): [msg]") SSstatistics.add_field_details("admin_verb","MS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/atmosdebug.dm b/code/modules/admin/verbs/atmosdebug.dm index 8874e3760d34..2c7947e4a9b0 100644 --- a/code/modules/admin/verbs/atmosdebug.dm +++ b/code/modules/admin/verbs/atmosdebug.dm @@ -1,45 +1,3 @@ -/client/proc/atmosscan() - set category = "Mapping" - set name = "Check Piping" - set background = 1 - if(!src.holder) - to_chat(src, "Only administrators may use this command.") - return - SSstatistics.add_field_details("admin_verb","CP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - if(alert("WARNING: This command should not be run on a live server. Do you want to continue?", "Check Piping", "No", "Yes") == "No") - return - - to_chat(usr, "Checking for disconnected pipes...") - //all plumbing - yes, some things might get stated twice, doesn't matter. - for (var/obj/machinery/atmospherics/plumbing in world) - if (plumbing.nodealert) - to_chat(usr, "Unconnected [plumbing.name] located at [plumbing.x],[plumbing.y],[plumbing.z] ([get_area(plumbing.loc)])") - - //Manifolds - for (var/obj/machinery/atmospherics/pipe/manifold/pipe in world) - if (!pipe.node1 || !pipe.node2 || !pipe.node3) - to_chat(usr, "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])") - - //Pipes - for (var/obj/machinery/atmospherics/pipe/simple/pipe in world) - if (!pipe.node1 || !pipe.node2) - to_chat(usr, "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])") - - to_chat(usr, "Checking for overlapping pipes...") - next_turf: - for(var/turf/T) - for(var/dir in GLOB.cardinal) - var/list/connect_types = list(1 = 0, 2 = 0, 3 = 0) - for(var/obj/machinery/atmospherics/pipe in T) - if(dir & pipe.initialize_directions) - for(var/connect_type in pipe.connect_types) - connect_types[connect_type] += 1 - if(connect_types[1] > 1 || connect_types[2] > 1 || connect_types[3] > 1) - to_chat(usr, "Overlapping pipe ([pipe.name]) located at [T.x],[T.y],[T.z] ([get_area(T)])") - continue next_turf - to_chat(usr, "Done") - /client/proc/powerdebug() set category = "Mapping" set name = "Check Power" @@ -49,12 +7,14 @@ SSstatistics.add_field_details("admin_verb","CPOW") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! for (var/datum/powernet/PN in SSmachines.powernets) - if (!PN.nodes || !PN.nodes.len) - if(PN.cables && (PN.cables.len > 1)) - var/obj/structure/cable/C = PN.cables[1] - to_chat(usr, "Powernet with no nodes! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [get_area(C.loc)]") - - if (!PN.cables || (PN.cables.len < 10)) + if (!LAZYLEN(PN.nodes)) if(PN.cables && (PN.cables.len > 1)) var/obj/structure/cable/C = PN.cables[1] - to_chat(usr, "Powernet with fewer than 10 cables! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [get_area(C.loc)]") + var/area/A = get_area(C.loc) + to_chat(usr, "Powernet with no nodes! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [A?.proper_name]") + + var/cable_count = LAZYLEN(PN.cables) + if (cable_count > 1 && cable_count < 10) + var/obj/structure/cable/C = PN.cables[1] + var/area/A = get_area(C.loc) + to_chat(usr, "Powernet with fewer than 10 cables! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [A?.proper_name]") diff --git a/code/modules/admin/verbs/cinematic.dm b/code/modules/admin/verbs/cinematic.dm index be6b54e2e535..af80595dccb2 100644 --- a/code/modules/admin/verbs/cinematic.dm +++ b/code/modules/admin/verbs/cinematic.dm @@ -13,11 +13,11 @@ if(alert("The game will be over. Are you really sure?", "Confirmation" ,"Continue", "Cancel") == "Cancel") return var/parameter = input(src,"station_missed = ? (0 for hit, 1 for near miss, 2 for not close)","Enter Parameter",0) as num - var/datum/game_mode/override - var/name = input(src,"Override mode = ?","Enter Parameter",null) as null|anything in gamemode_cache - override = gamemode_cache[name] - if(!istype(override)) - override = null - GLOB.cinematic.station_explosion_cinematic(parameter,override) + var/list/gamemodes = list() + var/list/all_modes = decls_repository.get_decls_of_subtype(/decl/game_mode) + for(var/mode_type in all_modes) + gamemodes += all_modes[mode_type] + var/decl/game_mode/override = input(src,"Override mode = ?","Enter Parameter",null) as null|anything in gamemodes + global.cinematic.station_explosion_cinematic(parameter, override) log_and_message_admins("launched cinematic \"[cinematic]\"", src) \ No newline at end of file diff --git a/code/modules/admin/verbs/custom_event.dm b/code/modules/admin/verbs/custom_event.dm index dc7b8e732a0e..4574117732c2 100644 --- a/code/modules/admin/verbs/custom_event.dm +++ b/code/modules/admin/verbs/custom_event.dm @@ -7,11 +7,11 @@ to_chat(src, "Only administrators may use this command.") return - var/input = sanitize(input(usr, "Enter the description of the custom event. Be descriptive. To cancel the event, make this blank or hit cancel.", "Custom Event", custom_event_msg) as message|null, MAX_BOOK_MESSAGE_LEN, extra = 0) + var/input = sanitize(input(usr, "Enter the description of the custom event. Be descriptive. To cancel the event, make this blank or hit cancel.", "Custom Event", global.custom_event_msg) as message|null, MAX_BOOK_MESSAGE_LEN, extra = 0) if(isnull(input)) return if(input == "") - custom_event_msg = null + global.custom_event_msg = null log_admin("[usr.key] has cleared the custom event text.") message_admins("[key_name_admin(usr)] has cleared the custom event text.") return @@ -19,26 +19,26 @@ log_admin("[usr.key] has changed the custom event text.") message_admins("[key_name_admin(usr)] has changed the custom event text.") - custom_event_msg = input + global.custom_event_msg = input to_world("

          Custom Event

          ") to_world("

          A custom event is starting. OOC Info:

          ") - to_world("[custom_event_msg]") + to_world("[global.custom_event_msg]") to_world("
          ") - SSwebhooks.send(WEBHOOK_CUSTOM_EVENT, list("text" = custom_event_msg)) + SSwebhooks.send(WEBHOOK_CUSTOM_EVENT, list("text" = global.custom_event_msg)) // normal verb for players to view info /client/verb/cmd_view_custom_event() set category = "OOC" set name = "Custom Event Info" - if(!custom_event_msg || custom_event_msg == "") + if(!global.custom_event_msg) to_chat(src, "There currently is no known custom event taking place.") to_chat(src, "Keep in mind: it is possible that an admin has not properly set this.") return to_chat(src, "

          Custom Event

          ") to_chat(src, "

          A custom event is taking place. OOC Info:

          ") - to_chat(src, "[custom_event_msg]") + to_chat(src, "[global.custom_event_msg]") to_chat(src, "
          ") diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 218b2c4cd6dc..e39ed6b84fa2 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1,19 +1,3 @@ -/client/proc/Debug2() - set category = "Debug" - set name = "Debug-Game" - if(!check_rights(R_DEBUG)) return - - if(Debug2) - Debug2 = 0 - message_admins("[key_name(src)] toggled debugging off.") - log_admin("[key_name(src)] toggled debugging off.") - else - Debug2 = 1 - message_admins("[key_name(src)] toggled debugging on.") - log_admin("[key_name(src)] toggled debugging on.") - - SSstatistics.add_field_details("admin_verb","DG2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - // callproc moved to code/modules/admin/callproc @@ -24,7 +8,7 @@ return var/turf/T = mob.loc - if (!( istype(T, /turf) )) + if (!( isturf(T) )) return var/datum/gas_mixture/env = T.return_air() @@ -33,7 +17,7 @@ t += "Temperature: [env.temperature]\n" t += "Pressure: [env.return_pressure()]kPa\n" for(var/g in env.gas) - t += "[g]: [env.gas[g]] / [env.gas[g] * R_IDEAL_GAS_EQUATION * env.temperature / env.volume]kPa\n" + t += "[g]: [env.gas[g]] / [env.gas[g] * R_IDEAL_GAS_EQUATION * env.temperature / env.total_volume]kPa\n" usr.show_message(t, 1) SSstatistics.add_field_details("admin_verb","ASL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -45,7 +29,7 @@ if(GAME_STATE < RUNLEVEL_GAME) alert("Wait until the game starts") return - if(istype(M, /mob/living/carbon/human)) + if(ishuman(M)) log_admin("[key_name(src)] has robotized [M.key].") spawn(10) M:Robotize() @@ -65,7 +49,7 @@ alert("That mob doesn't seem to exist, close the panel and try again.") return - if(istype(M, /mob/new_player)) + if(isnewplayer(M)) alert("The mob must not be a new_player.") return @@ -80,9 +64,9 @@ set desc = "Specify a location to spawn a pAI device, then specify a key to play that pAI" var/list/available = list() - for(var/mob/C in SSmobs.mob_list) - if(C.key) - available.Add(C) + for(var/mob/player in SSmobs.mob_list) + if(player.key) + available.Add(player) var/mob/choice = input("Choose a player to play the pAI", "Spawn pAI") in available if(!choice) return 0 @@ -92,7 +76,7 @@ return 0 var/obj/item/paicard/card = new(T) var/mob/living/silicon/pai/pai = new(card) - pai.SetName(sanitizeSafe(input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text)) + pai.SetName(sanitize_safe(input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text)) pai.real_name = pai.name pai.key = choice.key card.setPersonality(pai) @@ -101,29 +85,13 @@ paiController.pai_candidates.Remove(candidate) SSstatistics.add_field_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_slimeize(var/mob/M in SSmobs.mob_list) - set category = "Fun" - set name = "Make slime" - - if(GAME_STATE < RUNLEVEL_GAME) - alert("Wait until the game starts") - return - if(ishuman(M)) - log_admin("[key_name(src)] has slimeized [M.key].") - spawn(10) - M:slimeize() - SSstatistics.add_field_details("admin_verb","MKMET") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_and_message_admins("made [key_name(M)] into a slime.") - else - alert("Invalid mob") - //TODO: merge the vievars version into this or something maybe mayhaps /client/proc/cmd_debug_del_all() set category = "Debug" set name = "Del-All" // to prevent REALLY stupid deletions - var/blocked = list(/obj, /mob, /mob/living, /mob/living/carbon, /mob/living/carbon/human, /mob/observer, /mob/living/silicon, /mob/living/silicon/robot, /mob/living/silicon/ai) + var/blocked = list(/obj, /mob, /mob/living, /mob/living/human, /mob/observer, /mob/living/silicon, /mob/living/silicon/robot, /mob/living/silicon/ai) var/hsbitem = input(usr, "Choose an object to delete.", "Delete:") as null|anything in typesof(/obj) + typesof(/mob) - blocked if(hsbitem) for(var/atom/O in world) @@ -144,10 +112,13 @@ /client/proc/cmd_debug_tog_aliens() set category = "Server" set name = "Toggle Aliens" + if(toggle_config_value(/decl/config/toggle/aliens_allowed)) + log_admin("[key_name(src)] has turned aliens on.") + message_admins("[key_name_admin(src)] has turned aliens on.", 0) + else + log_admin("[key_name(src)] has turned aliens off.") + message_admins("[key_name_admin(src)] has turned aliens off.", 0) - config.aliens_allowed = !config.aliens_allowed - log_admin("[key_name(src)] has turned aliens [config.aliens_allowed ? "on" : "off"].") - message_admins("[key_name_admin(src)] has turned aliens [config.aliens_allowed ? "on" : "off"].", 0) SSstatistics.add_field_details("admin_verb","TAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_grantfullaccess(var/mob/M in SSmobs.mob_list) @@ -157,8 +128,8 @@ if (GAME_STATE < RUNLEVEL_GAME) alert("Wait until the game starts") return - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M + if (ishuman(M)) + var/mob/living/human/H = M var/obj/item/card/id/id = H.GetIdCard() if(id) id.icon_state = "gold" @@ -170,8 +141,7 @@ id.registered_name = H.real_name id.assignment = "Captain" id.SetName("[id.registered_name]'s ID Card ([id.assignment])") - H.equip_to_slot_or_del(id, slot_wear_id) - H.update_inv_wear_id() + H.equip_to_slot_or_del(id, slot_wear_id_str) else alert("Invalid mob") SSstatistics.add_field_details("admin_verb","GFA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -214,41 +184,41 @@ var/list/areas_with_intercom = list() var/list/areas_with_camera = list() - for(var/area/A in world) + for(var/area/A in global.areas) if(!(A.type in areas_all)) areas_all.Add(A.type) - for(var/obj/machinery/power/apc/APC in world) + for(var/obj/machinery/apc/APC in SSmachines.machinery) var/area/A = get_area(APC) if(!(A.type in areas_with_APC)) areas_with_APC.Add(A.type) - for(var/obj/machinery/alarm/alarm in world) + for(var/obj/machinery/alarm/alarm in SSmachines.machinery) var/area/A = get_area(alarm) if(!(A.type in areas_with_air_alarm)) areas_with_air_alarm.Add(A.type) - for(var/obj/machinery/requests_console/RC in world) + for(var/obj/machinery/network/requests_console/RC in SSmachines.machinery) var/area/A = get_area(RC) if(!(A.type in areas_with_RC)) areas_with_RC.Add(A.type) - for(var/obj/machinery/light/L in world) + for(var/obj/machinery/light/L in SSmachines.machinery) var/area/A = get_area(L) if(!(A.type in areas_with_light)) areas_with_light.Add(A.type) - for(var/obj/machinery/light_switch/LS in world) + for(var/obj/machinery/light_switch/LS in SSmachines.machinery) var/area/A = get_area(LS) if(!(A.type in areas_with_LS)) areas_with_LS.Add(A.type) - for(var/obj/item/radio/intercom/I in world) + for(var/obj/item/radio/intercom/I in SSmachines.machinery) var/area/A = get_area(I) if(!(A.type in areas_with_intercom)) areas_with_intercom.Add(A.type) - for(var/obj/machinery/camera/C in world) + for(var/obj/machinery/camera/C in SSmachines.machinery) var/area/A = get_area(C) if(!(A.type in areas_with_camera)) areas_with_camera.Add(A.type) @@ -296,27 +266,27 @@ if(!check_rights(R_FUN)) return - var/mob/living/carbon/human/H = input("Select mob.", "Select equipment.") as null|anything in GLOB.human_mob_list + var/mob/living/human/H = input("Select mob.", "Select equipment.") as null|anything in global.human_mob_list if(!H) return - var/decl/hierarchy/outfit/outfit = input("Select outfit.", "Select equipment.") as null|anything in outfits() + var/decl/outfit/outfit = input("Select outfit.", "Select equipment.") as null|anything in decls_repository.get_decls_of_subtype_unassociated(/decl/outfit) if(!outfit) return - var/reset_equipment = (outfit.flags&OUTFIT_RESET_EQUIPMENT) + var/reset_equipment = (outfit.outfit_flags & OUTFIT_RESET_EQUIPMENT) if(!reset_equipment) reset_equipment = alert("Do you wish to delete all current equipment first?", "Delete Equipment?","Yes", "No") == "Yes" SSstatistics.add_field_details("admin_verb","SEQ") dressup_human(H, outfit, reset_equipment) -/proc/dressup_human(var/mob/living/carbon/human/H, var/decl/hierarchy/outfit/outfit, var/undress = TRUE) +/proc/dressup_human(var/mob/living/human/H, var/decl/outfit/outfit, var/undress = TRUE) if(!H || !outfit) return if(undress) H.delete_inventory(TRUE) - outfit.equip(H) + outfit.equip_outfit(H) log_and_message_admins("changed the equipment of [key_name(H)] to [outfit.name].") /client/proc/startSinglo() @@ -327,42 +297,28 @@ if(alert("Are you sure? This will start up the engine. Should only be used during debug!",,"Yes","No") != "Yes") return - for(var/obj/machinery/power/emitter/E in world) + for(var/obj/machinery/emitter/E in SSmachines.machinery) if(E.anchored) E.active = 1 - for(var/obj/machinery/field_generator/F in world) + for(var/obj/machinery/field_generator/F in SSmachines.machinery) if(F.anchored) F.Varedit_start = 1 - spawn(30) - for(var/obj/machinery/the_singularitygen/G in world) + spawn(3 SECONDS) + for(var/obj/machinery/singularity_generator/G in SSmachines.machinery) if(G.anchored) - var/obj/singularity/S = new /obj/singularity(get_turf(G), 50) - spawn(0) - qdel(G) - S.energy = 1750 - S.current_size = 7 - S.icon = 'icons/effects/224x224.dmi' - S.icon_state = "singularity_s7" - S.pixel_x = -96 - S.pixel_y = -96 - S.grav_pull = 0 - //S.consume_range = 3 - S.dissipate = 0 - //S.dissipate_delay = 10 - //S.dissipate_track = 0 - //S.dissipate_strength = 10 - - for(var/obj/machinery/power/rad_collector/Rad in world) + new /obj/effect/singularity(get_turf(G), 1750) + qdel(G) + + for(var/obj/machinery/rad_collector/Rad in SSmachines.machinery) if(Rad.anchored) if(!Rad.loaded_tank) - Rad.loaded_tank = new /obj/item/tank/hydrogen(Rad) - Rad.loaded_tank.air_contents.gas[/decl/material/gas/hydrogen] = 70 + Rad.loaded_tank = new /obj/item/tank/hydrogen/collector(Rad) Rad.drainratio = 0 if(!Rad.active) Rad.toggle_power() - for(var/obj/machinery/power/smes/SMES in world) + for(var/obj/machinery/power/smes/SMES in SSmachines.machinery) if(SMES.anchored) SMES.input_attempt = 1 @@ -373,35 +329,19 @@ switch(input("Which list?") in list("Players","Admins","Mobs","Living Mobs","Dead Mobs", "Ghost Mobs", "Clients")) if("Players") - to_chat(usr, jointext(GLOB.player_list,",")) + to_chat(usr, jointext(global.player_list,",")) if("Admins") - to_chat(usr, jointext(GLOB.admins,",")) + to_chat(usr, jointext(global.admins,",")) if("Mobs") to_chat(usr, jointext(SSmobs.mob_list,",")) if("Living Mobs") - to_chat(usr, jointext(GLOB.living_mob_list_,",")) + to_chat(usr, jointext(global.living_mob_list_,",")) if("Dead Mobs") - to_chat(usr, jointext(GLOB.dead_mob_list_,",")) + to_chat(usr, jointext(global.dead_mob_list_,",")) if("Ghost Mobs") - to_chat(usr, jointext(GLOB.ghost_mob_list,",")) + to_chat(usr, jointext(global.ghost_mob_list,",")) if("Clients") - to_chat(usr, jointext(GLOB.clients,",")) - -// DNA2 - Admin Hax -/client/proc/cmd_admin_toggle_block(var/mob/M,var/block) - if(GAME_STATE < RUNLEVEL_GAME) - alert("Wait until the game starts") - return - if(istype(M, /mob/living/carbon)) - M.dna.SetSEState(block,!M.dna.GetSEState(block)) - domutcheck(M,null,MUTCHK_FORCED) - M.update_mutations() - var/state="[M.dna.GetSEState(block)?"on":"off"]" - var/blockname=assigned_blocks[block] - message_admins("[key_name_admin(src)] has toggled [M.key]'s [blockname] block [state]!") - log_admin("[key_name(src)] has toggled [M.key]'s [blockname] block [state]!") - else - alert("Invalid mob") + to_chat(usr, jointext(global.clients,",")) /datum/admins/proc/view_runtimes() set category = "Debug" @@ -411,19 +351,19 @@ if(!check_rights(R_DEBUG)) return - GLOB.error_cache.show_to(usr.client) + global.error_cache.show_to(usr.client) /client/proc/cmd_analyse_health_panel() set category = "Debug" set name = "Analyse Health" set desc = "Get an advanced health reading on a human mob." - var/mob/living/carbon/human/H = input("Select mob.", "Analyse Health") as null|anything in GLOB.human_mob_list + var/mob/living/human/H = input("Select mob.", "Analyse Health") as null|anything in global.human_mob_list if(!H) return cmd_analyse_health(H) -/client/proc/cmd_analyse_health(var/mob/living/carbon/human/H) +/client/proc/cmd_analyse_health(var/mob/living/human/H) if(!check_rights(R_DEBUG)) return @@ -432,10 +372,10 @@ var/dat = display_medical_data(H.get_raw_medical_data(), SKILL_MAX) - dat += text("
          Close", usr) + dat += text("
          Close", usr) show_browser(usr, dat, "window=scanconsole;size=430x600") -/client/proc/cmd_analyse_health_context(mob/living/carbon/human/H as mob in GLOB.human_mob_list) +/client/proc/cmd_analyse_health_context(mob/living/human/H as mob in global.human_mob_list) set category = null set name = "Analyse Human Health" @@ -447,7 +387,7 @@ /obj/effect/debugmarker icon = 'icons/effects/lighting_overlay.dmi' - icon_state = "transparent" + icon_state = "blank" layer = HOLOMAP_LAYER alpha = 127 @@ -463,7 +403,7 @@ for(var/datum/powernet/PN in SSmachines.powernets) var/netcolor = rgb(rand(100,255),rand(100,255),rand(100,255)) for(var/obj/structure/cable/C in PN.cables) - var/image/I = image('icons/effects/lighting_overlay.dmi', get_turf(C), "transparent") + var/image/I = image('icons/effects/lighting_overlay.dmi', get_turf(C), "blank") I.plane = DEFAULT_PLANE I.layer = EXPOSED_WIRE_LAYER I.alpha = 127 @@ -484,8 +424,112 @@ set name = "Spawn Material Stack" if(!check_rights(R_DEBUG)) return - var/material = input("Select material to spawn") as null|anything in SSmaterials.materials_by_name - if(!material) + var/decl/material/spawn_material = input("Select material to spawn") as null|anything in decls_repository.get_decls_of_subtype_unassociated(/decl/material) + if(istype(spawn_material)) + spawn_material.create_object(get_turf(mob), 50) + +/client/proc/force_ghost_trap_trigger() + set category = "Debug" + set name = "Force Ghost Trap Trigger" + if(!check_rights(R_DEBUG)) return + var/decl/ghosttrap/trap = input("Select a ghost trap.", "Force Ghost Trap Trigger") as null|anything in decls_repository.get_decl_paths_of_type(/decl/ghosttrap) + if(!trap) return - var/decl/material/M = decls_repository.get_decl(material) - new M.stack_type(get_turf(mob), 50, M) \ No newline at end of file + trap = GET_DECL(trap) + trap.forced(mob) + +/client/proc/spawn_exoplanet(exoplanet_type as anything in subtypesof(/datum/map_template/planetoid/random/exoplanet)) + set category = "Debug" + set name = "Create Exoplanet" + + var/budget = input("Ruins budget. Default is 5, a budget of 0 will not spawn any ruins, 5 will spawn around 3-5 ruins:", "Ruins Budget", 5) as num | null + + if (isnull(budget) || budget < 0) + budget = 5 + + var/theme = input("Choose a theme:", "Theme") as null|anything in typesof(/datum/exoplanet_theme) | null + + if (!theme) + theme = /datum/exoplanet_theme + + var/daycycle = alert("Should the planet have a day-night cycle?","Day Night Cycle", "Yes", "No") + + if (daycycle == "Yes") + daycycle = TRUE + else + daycycle = FALSE + + var/last_chance = alert("Spawn exoplanet?", "Final Confirmation", "Yes", "Cancel") + + if (last_chance == "Cancel") + return + + //#TODO: This definitely could be improved. + var/datum/map_template/planetoid/random/exoplanet/planet_template = SSmapping.get_template_by_type(exoplanet_type) + var/datum/planetoid_data/PD = planet_template.create_planetoid_instance() + if(planet_template.subtemplate_budget != budget) + PD._budget_override = budget + if(theme) + PD._theme_forced = theme + planet_template.load_new_z(gen_data = PD) + if(!daycycle) + SSdaycycle.remove_level(PD.get_linked_level_zs(), PD.daycycle_id) + +/client/proc/display_del_log() + set category = "Debug" + set name = "Display del() Log" + set desc = "Display del's log of everything that's passed through it." + + if(!check_rights(R_DEBUG)) + return + + . = list("List of things that have gone through qdel this round

            ") + sortTim(SSgarbage.items, cmp = /proc/cmp_qdel_item_time, associative = TRUE) + for(var/path in SSgarbage.items) + var/datum/qdel_item/I = SSgarbage.items[path] + . += "
          1. [path]
              " + if(I.failures) + . += "
            • Failures: [I.failures]
            • " + . += "
            • qdel() Count: [I.qdels]
            • " + if(I.early_destroy) + . += "
            • Early destroy count: [I.early_destroy]
            • " + if(I.qdels) + . += "
            • Average Destroy() Cost: [I.destroy_time / I.qdels]ms/call
            • " + . += "
            • Destroy() Cost: [I.destroy_time]ms
            • " + if(I.hard_deletes) + . += "
            • Total Hard Deletes [I.hard_deletes]
            • " + . += "
            • Time Spent Hard Deleting: [I.hard_delete_time]ms
            • " + if(I.slept_destroy) + . += "
            • Sleeps: [I.slept_destroy]
            • " + if(I.no_respect_force) + . += "
            • Ignored force: [I.no_respect_force]
            • " + if(I.no_hint) + . += "
            • No hint: [I.no_hint]
            • " + . += "
          2. " + + . += "
          " + + show_browser(usr, JOINTEXT(.), "window=dellog") + +/client/proc/toggle_browser_inspect() + set category = "Debug" + set name = "Toggle Browser Inspect" + + #if DM_VERSION >= 516 + + var/browser_options = winget(src, null, "browser-options") + + if(findtext(browser_options, "devtools")) + // Disable the dev tools. + winset(src, null, list("browser-options" = "-devtools")) + message_admins("[key_name_admin(usr)] has disabled Browser Inspection.") + else + // Enable the dev tools. + winset(src, null, list("browser-options" = "+devtools")) + message_admins("[key_name_admin(usr)] has enabled Browser Inspection.") + + #else + + alert("Browser Inspection is not supported in this version of BYOND, please update to 516 or later.") + + #endif \ No newline at end of file diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index 9e63aa1a8207..179676df7f36 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -10,14 +10,14 @@ var/inactive_groups = SSair.zones.len - active_groups var/hotspots = 0 - for(var/obj/fire/hotspot in world) + for(var/obj/fire/hotspot in SSair.active_hotspots) hotspots++ var/active_on_main_station = 0 var/inactive_on_main_station = 0 for(var/zone/zone in SSair.zones) - var/turf/simulated/turf = locate() in zone.contents - if(turf && (turf.z in GLOB.using_map.station_levels)) + var/turf/turf = locate() in zone.contents + if(turf && isStationLevel(turf.z)) if(zone.needs_update) active_on_main_station++ else @@ -41,63 +41,6 @@ show_browser(usr, output, "window=airreport") -/client/proc/fix_next_move() - set category = "Debug" - set name = "Unfreeze Everyone" - var/largest_move_time = 0 - var/largest_click_time = 0 - var/mob/largest_move_mob = null - var/mob/largest_click_mob = null - for(var/mob/M in world) - if(!M.client) - continue - if(M.next_move >= largest_move_time) - largest_move_mob = M - if(M.next_move > world.time) - largest_move_time = M.next_move - world.time - else - largest_move_time = 1 - if(M.next_click >= largest_click_time) - largest_click_mob = M - if(M.next_click > world.time) - largest_click_time = M.next_click - world.time - else - largest_click_time = 0 - log_admin("DEBUG: [key_name(M)] next_move = [M.next_move] next_click = [M.next_click] world.time = [world.time]") - M.next_move = 1 - M.next_click = 0 - message_admins("[key_name_admin(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [largest_move_time/10] seconds!", 1) - message_admins("[key_name_admin(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [largest_click_time/10] seconds!", 1) - message_admins("world.time = [world.time]", 1) - SSstatistics.add_field_details("admin_verb","UFE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - -/client/proc/radio_report() - set category = "Debug" - set name = "Radio report" - - var/output = "Radio Report
          " - for (var/fq in radio_controller.frequencies) - output += "Freq: [fq]
          " - var/datum/radio_frequency/fqs = radio_controller.frequencies[fq] - if (!fqs) - output += "  ERROR
          " - continue - for (var/filter in fqs.devices) - var/list/f = fqs.devices[filter] - if (!f) - output += "  [filter]: ERROR
          " - continue - output += "  [filter]: [f.len]
          " - for (var/device in f) - if (isobj(device)) - output += "    [device] ([device:x],[device:y],[device:z] in area [get_area(device)])
          " - else - output += "    [device]
          " - - show_browser(usr, output, "window=radioreport") - SSstatistics.add_field_details("admin_verb","RR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - /client/proc/reload_admins() set name = "Reload Admins" set category = "Debug" diff --git a/code/modules/admin/verbs/fluids.dm b/code/modules/admin/verbs/fluids.dm index ca80e0ee3dfb..d3e5e0d0204b 100644 --- a/code/modules/admin/verbs/fluids.dm +++ b/code/modules/admin/verbs/fluids.dm @@ -3,7 +3,7 @@ set desc = "Flood the turf you are standing on." set category = "Debug" - if(!check_rights(R_SPAWN)) + if(!check_rights(R_SPAWN)) return var/mob/user = usr @@ -13,14 +13,12 @@ var/reagent_amount = input("How deep?", "Spawn Fluid", 1000) as num|null if(!reagent_amount) return - var/reagent_type = input("What kind of reagent?", "Spawn Fluid", /decl/material/liquid/water) as null|anything in subtypesof(/decl/material) + var/reagent_type = input("What kind of reagent?", "Spawn Fluid", /decl/material/liquid/water) as null|anything in decls_repository.get_decl_paths_of_subtype(/decl/material) if(!reagent_type || !user || !check_rights(R_SPAWN)) return var/turf/flooding = get_turf(user) - for(var/thing in RANGE_TURFS(flooding, spawn_range)) - var/obj/effect/fluid/F = locate() in thing - if(!F) F = new(thing) - F.reagents.add_reagent(reagent_type, reagent_amount) + for(var/turf/T as anything in RANGE_TURFS(flooding, spawn_range)) + T.add_to_reagents(reagent_type, reagent_amount) /datum/admins/proc/jump_to_fluid_source() @@ -49,89 +47,3 @@ user.forceMove(get_turf(pick(SSfluids.active_fluids))) else to_chat(usr, "No active fluids.") - -/turf/simulated/open/flooded - name = "open water" - flooded = TRUE - -/turf/simulated/ocean/non_flooded - flooded = FALSE - -GLOBAL_LIST_INIT(submerged_levels, new) -/datum/admins/proc/submerge_map() - set category = "Admin" - set desc = "Submerge the map in an ocean." - set name = "Submerge Map" - - if(!check_rights(R_ADMIN)) - return - - if(!usr.z) - to_chat(usr, SPAN_WARNING("You must be on a valid z-level.")) - return - - var/list/flooding_levels = list(usr.z) - if(alert("Do you wish to flood this z-level, or this entire z-sector?", null, "This level", "Connected levels") == "Connected levels") - flooding_levels = GetConnectedZlevels(usr.z) - for(var/submerge_z in flooding_levels) - if(GLOB.submerged_levels["[submerge_z]"]) - flooding_levels -= "[submerge_z]" - if(!length(flooding_levels)) - to_chat(usr, SPAN_WARNING("This part of the map has already been dropped into an ocean.")) - return - - if(alert("Are you sure you want to drop this section of the map into the ocean?", null, "No", "Yes") == "No") - return - - to_world(SPAN_NOTICE("[usr.key] fumbled and dropped the server into an ocean, please wait for the game to catch up.")) - - sleep(10) // To ensure the message prints. - - SSfluids.suspend() - SSao.suspend() - SSicon_update.suspend() - - // Pre-flood turfs we aren't going to replace. - for(var/submerge_z in flooding_levels) - for(var/thing in block(locate(1, 1, submerge_z), locate(world.maxx, world.maxy, submerge_z))) - var/turf/T = thing - var/area/A = get_area(T) - if(A && (A.area_flags & AREA_FLAG_EXTERNAL)) - if(A.base_turf) - A.base_turf = /turf/simulated/ocean/non_flooded - if(!istype(T, /turf/space)) - T.make_flooded() - - // Generate the sea floor on the highest z-level in the set. - var/first_level = flooding_levels[1] - for(var/check_level in flooding_levels) - if(check_level < first_level) - first_level = check_level - flooding_levels -= first_level - GLOB.submerged_levels["[first_level]"] = TRUE - GLOB.using_map.base_turf_by_z["[first_level]"] = /turf/simulated/ocean - new /datum/random_map/noise/seafloor/replace_space(null, 1, 1, first_level, world.maxx, world.maxy) - - // Generate open space for the remaining z-levels. - for(var/submerge_z in flooding_levels) - GLOB.submerged_levels["[submerge_z]"] = TRUE - GLOB.using_map.base_turf_by_z["[submerge_z]"] = /turf/simulated/open - for(var/thing in block(locate(1, 1, submerge_z), locate(world.maxx, world.maxy, submerge_z))) - var/turf/T = thing - var/area/A = get_area(T) - if(A && (A.area_flags & AREA_FLAG_EXTERNAL)) - if(A.base_turf) - A.base_turf = /turf/simulated/open - if(istype(T, /turf/space)) - T.ChangeTurf(/turf/simulated/open/flooded) - else if(istype(T, /turf/simulated/open)) - T.make_flooded() - CHECK_TICK - - sleep(10) - - SSicon_update.wake() - SSao.wake() - SSfluids.wake() - - to_world(SPAN_NOTICE("[usr.key] has finished dunking the server into the ocean.")) \ No newline at end of file diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 5b2e602ce849..0527485b1265 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -24,16 +24,16 @@ set category = null if(!src.holder) - to_chat(src, "Only Admins may use this command.") + to_chat(src, SPAN_WARNING("Only Admins may use this command.")) return - var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in GLOB.clients + var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in global.clients if(!istype(target,/client)) - to_chat(src, "Error: giveserverlog(): Client not found.") + to_chat(src, SPAN_WARNING("Error: giveserverlog(): Client not found.")) return target.verbs |= /client/proc/getserverlog - to_chat(target, "You have been granted access to runtime logs. Please use them responsibly or risk being banned.") + to_chat(target, SPAN_NOTICE("You have been granted access to runtime logs. Please use them responsibly or risk being banned.")) return //This proc allows download of past server logs saved within the data/logs/ folder. @@ -51,7 +51,7 @@ return message_admins("[key_name_admin(src)] accessed file: [path]") - src << run(file(path)) + open_file_for(src, file(path)) to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") return @@ -64,6 +64,6 @@ set name = "Show Server Log" set desc = "Shows today's server log." - usr << run(diary) + open_file_for(usr, diary) SSstatistics.add_field_details("admin_verb","VTL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return \ No newline at end of file diff --git a/code/modules/admin/verbs/grief_fixers.dm b/code/modules/admin/verbs/grief_fixers.dm index cb4f0523b501..7fd10e57eb41 100644 --- a/code/modules/admin/verbs/grief_fixers.dm +++ b/code/modules/admin/verbs/grief_fixers.dm @@ -4,48 +4,68 @@ if(!check_rights(R_ADMIN|R_DEBUG)) return - if(alert("WARNING: Executing this command will perform a full reset of atmosphere. All pipelines will lose any gas that may be in them, and all zones will be reset to contain air mix as on roundstart. The supermatter engine will also be stopped (to prevent overheat due to removal of coolant). Do not use unless the map is suffering serious atmospheric issues due to grief or bug.", "Full Atmosphere Reboot", "No", "Yes") == "No") + if(alert("WARNING: Executing this command will perform a full reset of atmosphere. All pipelines will lose any gas that may be in them, and all zones will be reset to contain air mix as on roundstart. This may require any atmos-based generators to shut down. Do not use unless the map is suffering serious atmospheric issues due to grief or bug.", "Full Atmosphere Reboot", "No", "Yes") == "No") return SSstatistics.add_field_details("admin_verb","FA") log_and_message_admins("Full atmosphere reset initiated by [usr].") - to_world("Initiating restart of atmosphere. The server may lag a bit.") + to_world(SPAN_DANGER("Initiating restart of atmosphere. The server may lag a bit.")) sleep(10) var/current_time = world.timeofday - // Depower the supermatter, as it would quickly blow up once we remove all gases from the pipes. - for(var/obj/machinery/power/supermatter/S in SSmachines.machinery) - S.power = 0 - to_chat(usr, "\[1/5\] - Supermatter depowered") + var/list/steps = decls_repository.get_decls_of_subtype_unassociated(/decl/atmos_grief_fix_step) + steps = sortTim(steps.Copy(), /proc/cmp_decl_sort_value_asc) + var/step_count = length(steps) + for(var/step_index in 1 to step_count) + var/decl/atmos_grief_fix_step/fix_step = steps[step_index] + to_chat(usr, "\[[step_index]/[step_count]\] - [fix_step.name].") + fix_step.act() + to_world(SPAN_DANGER("Atmosphere restart completed in [(world.timeofday - current_time)/(1 SECOND)] seconds.")) +/decl/atmos_grief_fix_step + abstract_type = /decl/atmos_grief_fix_step + var/name + +/decl/atmos_grief_fix_step/proc/act() + return + +/decl/atmos_grief_fix_step/purge_pipenets + name = "All pipenets purged of gas" + sort_order = 1 + +/decl/atmos_grief_fix_step/purge_pipenets/act() // Remove all gases from all pipenets - for(var/net in SSmachines.pipenets) - var/datum/pipe_network/PN = net + for(var/datum/pipe_network/PN as anything in SSmachines.pipenets) for(var/datum/gas_mixture/G in PN.gases) - G.gas = list() + G.gas.Cut() G.update_values() - to_chat(usr, "\[2/5\] - All pipenets purged of gas.") +/decl/atmos_grief_fix_step/delete_zones + name = "All ZAS Zones removed" + sort_order = 2 +/decl/atmos_grief_fix_step/delete_zones/act() // Delete all zones. - for(var/zone/Z in world) + for(var/zone/Z in SSair.zones) Z.c_invalidate() - to_chat(usr, "\[3/5\] - All ZAS Zones removed.") +/decl/atmos_grief_fix_step/reset_turfs + name = "All turfs reset to roundstart values" + sort_order = 3 +/decl/atmos_grief_fix_step/reset_turfs/act() var/list/unsorted_overlays = list() - for(var/id in subtypesof(/decl/material/gas)) - var/decl/material/mat = decls_repository.get_decl(id) + for(var/id,m in get_filterable_material_types()) + var/decl/material/mat = m unsorted_overlays |= mat.gas_tile_overlay - for(var/turf/simulated/T in world) + for(var/turf/T in world) T.air = null - T.overlays.Remove(unsorted_overlays) T.zone = null - to_chat(usr, "\[4/5\] - All turfs reset to roundstart values.") +/decl/atmos_grief_fix_step/reboot_zas + name = "ZAS Rebooted" + sort_order = 4 +/decl/atmos_grief_fix_step/reboot_zas/act() SSair.reboot() - - to_chat(usr, "\[5/5\] - ZAS Rebooted") - to_world("Atmosphere restart completed in [(world.timeofday - current_time)/10] seconds.") diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index 46b88a5e7fbc..606ac3bedc70 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -5,18 +5,16 @@ if (!check_rights(R_FUN)) return - var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.map_templates - if(!map) + var/datum/map_template/template = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.spawnable_map_templates + if(!istype(template)) return - var/datum/map_template/template = SSmapping.map_templates[map] - var/turf/T = get_turf(usr) if(!T) return var/list/preview = list() - for(var/S in template.get_affected_turfs(T,centered = TRUE)) + for(var/S in template.get_affected_turfs(T, centered = TRUE)) preview += image('icons/turf/overlays.dmi',S,"greenOverlay") usr.client.images += preview if(alert(usr,"Confirm location.","Template Confirm","Yes","No") == "Yes") @@ -33,21 +31,20 @@ if(!check_rights(R_FUN)) return + if(GAME_STATE < RUNLEVEL_LOBBY) to_chat(usr, "Please wait for the master controller to initialize before loading maps!") return - var/map = input(usr, "Choose a Map Template to place on a new zlevel","Place Map Template") as null|anything in SSmapping.map_templates - if(!map) + var/datum/map_template/template = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.spawnable_map_templates + if(!istype(template)) return - var/datum/map_template/template = SSmapping.map_templates[map] - if(template.loaded && !(template.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES)) to_chat(usr, SPAN_WARNING("That template has already been loaded and is flagged against being loaded again.")) return - var/new_z_centre = template.load_new_z(FALSE) // Don't skip changeturf + var/new_z_centre = template.load_new_z() if (new_z_centre) log_and_message_admins("has placed a map template ([template.name]) on a new zlevel.", location=new_z_centre) else @@ -60,17 +57,6 @@ if (!check_rights(R_FUN)) return - var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file - if(!map) - return - if(copytext("[map]",-4) != ".dmm") - to_chat(usr, "Bad map file: [map]") - return - - var/datum/map_template/M = new(list(map), "[map]") - if(M.preload_size()) - to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])") - SSmapping.map_templates[M.name] = M - message_admins("[key_name_admin(usr)] has uploaded a map template ([map])") - else - to_chat(usr, "Map template '[map]' failed to load properly") + // Going to make this take a JSON file/folder location rather than a single + // .dmm file, after the secrets system is merged; will reimplement then. + to_chat(usr, SPAN_WARNING("Not reimplemented yet, sorry.")) diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 2efe0690734a..a9e734c065d7 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -1,3 +1,5 @@ +#define GET_ZAS_IMAGE(T, IS) image(loc = T, icon = 'icons/misc/debug_group.dmi', icon_state = IS, layer = ABOVE_TILE_LAYER) + //- Are all the floors with or without air, as they should be? (regular or airless) //- Does the area have an APC? //- Does the area have an Air Alarm? @@ -19,22 +21,38 @@ //- Identify how hard it is to break into the area and where the weak points are //- Check if the area has too much empty space. If so, make it smaller and replace the rest with maintenance tunnels. -var/camera_range_display_status = 0 -var/intercom_range_display_status = 0 +var/global/camera_range_display_status = 0 +var/global/intercom_range_display_status = 0 +var/global/list/debug_camera_range_markers = list() /obj/effect/debugging/camera_range icon = 'icons/480x480.dmi' icon_state = "25percent" /obj/effect/debugging/camera_range/Initialize() . = ..() - src.pixel_x = -224 - src.pixel_y = -224 + default_pixel_x = -224 + default_pixel_y = -224 + reset_offsets(0) + global.debug_camera_range_markers += src + +/obj/effect/debugging/camera_range/Destroy() + global.debug_camera_range_markers -= src + return ..() +var/global/list/mapping_debugging_markers = list() /obj/effect/debugging/marker icon = 'icons/turf/areas.dmi' icon_state = "yellow" +/obj/effect/debugging/marker/Initialize(mapload) + . = ..() + global.mapping_debugging_markers += src + +/obj/effect/debugging/marker/Destroy() + global.mapping_debugging_markers -= src + return ..() + /obj/effect/debugging/marker/Move() return 0 @@ -53,7 +71,7 @@ var/intercom_range_display_status = 0 - for(var/obj/effect/debugging/camera_range/C in world) + for(var/obj/effect/debugging/camera_range/C as anything in debug_camera_range_markers) qdel(C) if(camera_range_display_status) @@ -76,24 +94,26 @@ var/intercom_range_display_status = 0 The following annomalities have been detected. The ones in red need immediate attention: Some of those in black may be intentional.
            "} for(var/obj/machinery/camera/C1 in CL) + var/area/C1_area = get_area(C1) for(var/obj/machinery/camera/C2 in CL) + var/area/C2_area = get_area(C2) if(C1 != C2) if(C1.c_tag == C2.c_tag) - output += "
          • c_tag match for sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) and \[[C2.x], [C2.y], [C2.z]\] ([C2.loc.loc]) - c_tag is [C1.c_tag]
          • " + output += "
          • c_tag match for sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1_area.proper_name]) and \[[C2.x], [C2.y], [C2.z]\] ([C2_area.proper_name]) - c_tag is [C1.c_tag]
          • " if(C1.loc == C2.loc && C1.dir == C2.dir && C1.pixel_x == C2.pixel_x && C1.pixel_y == C2.pixel_y) - output += "
          • FULLY overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
          • " + output += "
          • FULLY overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1_area.proper_name]) Channels: [C1.preset_channels] and [C2.preset_channels]
          • " if(C1.loc == C2.loc) - output += "
          • overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
          • " + output += "
          • overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1_area.proper_name]) Channels: [C1.preset_channels] and [C2.preset_channels]
          • " var/turf/T = get_step(C1,turn(C1.dir,180)) if(!T || !isturf(T) || !T.density ) if(!(locate(/obj/structure/grille,T))) var/window_check = 0 - for(var/obj/structure/window/W in T) - if (W.dir == turn(C1.dir,180) || (W.dir in list(NORTHEAST,SOUTHEAST,SOUTHWEST,NORTHWEST)) ) + for(var/obj/structure/window/window in T) + if (window.dir == turn(C1.dir,180) || (window.dir in list(NORTHEAST,SOUTHEAST,SOUTHWEST,NORTHWEST)) ) window_check = 1 break if(!window_check) - output += "
          • Camera not connected to wall at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Network: [C1.network]
          • " + output += "
          • Camera not connected to wall at \[[C1.x], [C1.y], [C1.z]\] ([C1_area.proper_name]) Channels: [C1.preset_channels]
          • " output += "
          " show_browser(usr, output, "window=airreport;size=1000x500") @@ -108,49 +128,49 @@ var/intercom_range_display_status = 0 else intercom_range_display_status = 1 - for(var/obj/effect/debugging/marker/M in world) + for(var/obj/effect/debugging/marker/M in global.mapping_debugging_markers) qdel(M) if(intercom_range_display_status) - for(var/obj/item/radio/intercom/I in world) + for(var/obj/item/radio/intercom/I in SSmachines.machinery) for(var/turf/T in orange(7,I)) var/obj/effect/debugging/marker/F = new/obj/effect/debugging/marker(T) if (!(F in view(7,I.loc))) qdel(F) + SSstatistics.add_field_details("admin_verb","mIRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -var/list/debug_verbs = list ( - /client/proc/do_not_use_these - ,/client/proc/camera_view - ,/client/proc/sec_camera_report - ,/client/proc/intercom_view - ,/client/proc/Cell - ,/client/proc/atmosscan - ,/client/proc/powerdebug - ,/client/proc/count_objects_on_z_level - ,/client/proc/count_objects_all - ,/client/proc/cmd_assume_direct_control - ,/client/proc/startSinglo - ,/client/proc/ticklag - ,/client/proc/cmd_admin_grantfullaccess - ,/client/proc/cmd_admin_areatest - ,/client/proc/cmd_admin_rejuvenate - ,/datum/admins/proc/show_traitor_panel - ,/client/proc/print_jobban_old - ,/client/proc/print_jobban_old_filter - ,/client/proc/forceEvent - ,/client/proc/Zone_Info - ,/client/proc/Test_ZAS_Connection - ,/client/proc/rebootAirMaster - ,/client/proc/hide_debug_verbs - ,/client/proc/testZAScolors - ,/client/proc/testZAScolors_remove - ,/datum/admins/proc/setup_supermatter - ,/client/proc/atmos_toggle_debug - ,/client/proc/spawn_tanktransferbomb - ,/client/proc/find_leaky_pipes - ,/client/proc/analyze_openturf - ,/client/proc/show_cargo_prices +var/global/list/debug_verbs = list ( + /client/proc/do_not_use_these, + /client/proc/camera_view, + /client/proc/sec_camera_report, + /client/proc/intercom_view, + /client/proc/Cell, + /client/proc/powerdebug, + /client/proc/count_objects_on_z_level, + /client/proc/count_objects_all, + /client/proc/cmd_assume_direct_control, + /client/proc/startSinglo, + /client/proc/ticklag, + /client/proc/cmd_admin_grantfullaccess, + /client/proc/cmd_admin_areatest, + /client/proc/cmd_admin_rejuvenate, + /datum/admins/proc/show_special_roles, + /client/proc/print_jobban_old, + /client/proc/print_jobban_old_filter, + /client/proc/forceEvent, + /client/proc/Zone_Info, + /client/proc/Test_ZAS_Connection, + /client/proc/rebootAirMaster, + /client/proc/hide_debug_verbs, + /client/proc/testZAScolors, + /client/proc/testZAScolors_remove, + /datum/admins/proc/setup_fusion, + /client/proc/atmos_toggle_debug, + /client/proc/spawn_tanktransferbomb, + /client/proc/find_leaky_pipes, + /client/proc/analyze_openturf, + /client/proc/show_cargo_prices ) @@ -178,7 +198,6 @@ var/list/debug_verbs = list ( /client/var/list/testZAScolors_turfs = list() /client/var/list/testZAScolors_zones = list() /client/var/usedZAScolors = 0 -/client/var/list/image/ZAScolors = list() /client/proc/recurse_zone(var/zone/Z, var/recurse_level =1) testZAScolors_zones += Z @@ -186,7 +205,7 @@ var/list/debug_verbs = list ( return for(var/turf/T in Z.contents) - images += get_zas_image(T, "yellow") + images += GET_ZAS_IMAGE(T, "yellow") testZAScolors_turfs += T for(var/connection_edge/zone/edge in Z.edges) var/zone/connected = edge.get_connected_zone(Z) @@ -202,10 +221,9 @@ var/list/debug_verbs = list ( if(!check_rights(R_DEBUG)) return testZAScolors_remove() - var/turf/simulated/location = get_turf(usr) - - if(!istype(location, /turf/simulated)) - to_chat(src, "This debug tool can only be used while on a simulated turf.") + var/turf/location = get_turf(usr) + if(!location?.zone) + to_chat(src, SPAN_WARNING("The turf you are standing on does not have a zone.")) return if(!usedZAScolors) @@ -218,13 +236,13 @@ var/list/debug_verbs = list ( testZAScolors_zones += location.zone for(var/turf/T in location.zone.contents) - images += get_zas_image(T, "green") + images += GET_ZAS_IMAGE(T, "green") testZAScolors_turfs += T for(var/connection_edge/zone/edge in location.zone.edges) var/zone/Z = edge.get_connected_zone(location.zone) testZAScolors_zones += Z for(var/turf/T in Z.contents) - images += get_zas_image(T, "blue") + images += GET_ZAS_IMAGE(T, "blue") testZAScolors_turfs += T for(var/connection_edge/zone/z_edge in Z.edges) var/zone/connected = z_edge.get_connected_zone(Z) @@ -237,7 +255,7 @@ var/list/debug_verbs = list ( continue if(T in testZAScolors_turfs) continue - images += get_zas_image(T, "red") + images += GET_ZAS_IMAGE(T, "red") testZAScolors_turfs += T /client/proc/testZAScolors_remove() @@ -329,9 +347,6 @@ var/list/debug_verbs = list ( log_debug("There are [count] objects of type [type_path] in the game world") SSstatistics.add_field_details("admin_verb","mOBJ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/proc/get_zas_image(var/turf/T, var/icon_state) - return image_repository.atom_image(T, 'icons/misc/debug_group.dmi', icon_state, plane = DEFAULT_PLANE, layer = ABOVE_TILE_LAYER) - //Special for Cakey /client/proc/find_leaky_pipes() set category = "Mapping" @@ -340,7 +355,7 @@ var/list/debug_verbs = list ( var/list/baddies = list("LEAKY PIPES") for(var/obj/machinery/atmospherics/pipe/P in SSmachines.machinery) if(P.leaking) - baddies += "[P] ([P.x],[P.y],[P.z] - JMP)" + baddies += "[P] ([P.x],[P.y],[P.z] - JMP)" to_chat(usr,jointext(baddies, "
          ")) @@ -358,3 +373,5 @@ var/list/debug_verbs = list ( var/datum/browser/popup = new(mob, "cargo_price_debug", "Cargo Prices") popup.set_content("[jointext(prices, "")]
          ") popup.open() + +#undef GET_ZAS_IMAGE \ No newline at end of file diff --git a/code/modules/admin/verbs/massmodvar.dm b/code/modules/admin/verbs/massmodvar.dm index 26bb87d733be..2de341ca8717 100644 --- a/code/modules/admin/verbs/massmodvar.dm +++ b/code/modules/admin/verbs/massmodvar.dm @@ -37,7 +37,7 @@ for (var/V in O.vars) names += V - names = sortList(names) + names = sortTim(names, /proc/cmp_text_asc) var/variable = "" @@ -72,7 +72,7 @@ else if(isicon(var_value)) to_chat(usr, "Variable appears to be ICON.") - var_value = "\icon[var_value]" + var_value = "[html_icon(var_value)]" default = "icon" else if(istype(var_value,/atom) || istype(var_value,/datum)) @@ -115,7 +115,7 @@ if("restore to default") O.vars[variable] = initial(O.vars[variable]) if(method) - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if ( istype(M , O.type) ) M.vars[variable] = O.vars[variable] @@ -125,13 +125,13 @@ if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] else - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if (M.type == O.type) M.vars[variable] = O.vars[variable] @@ -141,7 +141,7 @@ if (A.type == O.type) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if (A.type == O.type) A.vars[variable] = O.vars[variable] @@ -155,7 +155,7 @@ O.vars[variable] = new_value if(method) - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if ( istype(M , O.type) ) M.vars[variable] = O.vars[variable] @@ -165,12 +165,12 @@ if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] else - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if (M.type == O.type) M.vars[variable] = O.vars[variable] @@ -180,7 +180,7 @@ if (A.type == O.type) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if (A.type == O.type) A.vars[variable] = O.vars[variable] @@ -192,7 +192,7 @@ O.vars[variable] = new_value if(method) - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if ( istype(M , O.type) ) M.vars[variable] = O.vars[variable] @@ -202,13 +202,13 @@ if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] else - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if (M.type == O.type) M.vars[variable] = O.vars[variable] @@ -218,7 +218,7 @@ if (A.type == O.type) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if (A.type == O.type) A.vars[variable] = O.vars[variable] @@ -229,7 +229,7 @@ if(new_value == null) return O.vars[variable] = new_value if(method) - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if ( istype(M , O.type) ) M.vars[variable] = O.vars[variable] @@ -239,12 +239,12 @@ if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] else - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if (M.type == O.type) M.vars[variable] = O.vars[variable] @@ -254,7 +254,7 @@ if (A.type == O.type) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if (A.type == O.type) A.vars[variable] = O.vars[variable] @@ -265,7 +265,7 @@ O.vars[variable] = new_value if(method) - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if ( istype(M , O.type) ) M.vars[variable] = O.vars[variable] @@ -275,12 +275,12 @@ if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] - else if(istype(O.type, /turf)) + else if(isturf(O.type)) for(var/turf/A in world) if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] else - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if (M.type == O.type) M.vars[variable] = O.vars[variable] @@ -290,7 +290,7 @@ if (A.type == O.type) A.vars[variable] = O.vars[variable] - else if(istype(O.type, /turf)) + else if(isturf(O.type)) for(var/turf/A in world) if (A.type == O.type) A.vars[variable] = O.vars[variable] @@ -300,7 +300,7 @@ if(new_value == null) return O.vars[variable] = new_value if(method) - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if ( istype(M , O.type) ) M.vars[variable] = O.vars[variable] @@ -310,13 +310,13 @@ if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if ( istype(A , O.type) ) A.vars[variable] = O.vars[variable] else - if(istype(O, /mob)) + if(ismob(O)) for(var/mob/M in SSmobs.mob_list) if (M.type == O.type) M.vars[variable] = O.vars[variable] @@ -326,7 +326,7 @@ if (A.type == O.type) A.vars[variable] = O.vars[variable] - else if(istype(O, /turf)) + else if(isturf(O)) for(var/turf/A in world) if (A.type == O.type) A.vars[variable] = O.vars[variable] diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index 52224e98792c..94fc9afc0221 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -122,11 +122,11 @@ if(!isnum(a) && L[a] != null) assoc = 1 //This is pretty weak test but I can't think of anything else to_chat(usr, "List appears to be associative.") - catch {} // Builtin non-assoc lists (contents, etc.) will runtime if you try to get an assoc value of them + catch {EMPTY_BLOCK_GUARD} // Builtin non-assoc lists (contents, etc.) will runtime if you try to get an assoc value of them var/list/names = null if(!assoc) - names = sortList(L) + names = sortTim(L, /proc/cmp_text_asc) var/variable var/assoc_key @@ -170,7 +170,7 @@ else if(isicon(variable)) to_chat(usr, "Variable appears to be ICON.") - variable = "\icon[variable]" + variable = "[html_icon(variable)]" default = "icon" else if(istype(variable,/atom) || istype(variable,/datum)) @@ -224,13 +224,6 @@ if("list") mod_list(variable, O, original_name, objectvar) - if("restore to default") - new_var = initial(variable) - if(assoc) - L[assoc_key] = new_var - else - L[L.Find(variable)] = new_var - if("edit referenced object") modify_variables(variable) @@ -316,7 +309,7 @@ var/var_value if(param_var_name) - if(!(param_var_name in O.get_variables())) + if(!(param_var_name in O.VV_get_variables())) to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this atom ([O])") return @@ -325,6 +318,7 @@ variable = param_var_name + // TODO: check for list-typed O? Proc does not exist on non-datum types. var_value = O.get_variable_value(variable) if(autodetect_class) @@ -347,7 +341,7 @@ else if(isicon(var_value)) to_chat(usr, "Variable appears to be ICON.") - var_value = "\icon[var_value]" + var_value = "[html_icon(var_value)]" class = "icon" else if(istype(var_value,/atom) || istype(var_value,/datum)) @@ -372,7 +366,7 @@ for (var/V in O.vars) names += V - names = sortList(names) + names = sortTim(names, /proc/cmp_text_asc) variable = input("Which var?","Var") as null|anything in names if(!variable) return @@ -402,7 +396,7 @@ else if(isicon(var_value)) to_chat(usr, "Variable appears to be ICON.") - var_value = "\icon[var_value]" + var_value = "[html_icon(var_value)]" default = "icon" else if(istype(var_value,/atom) || istype(var_value,/datum)) @@ -529,15 +523,11 @@ to_world_log("### VarEdit by [src]: [O.type] [variable]=[html_encode("[new_value]")]") log_and_message_admins("modified [original_name]'s [variable] from '[old_value]' to '[new_value]'") -/client - var/static/vv_set_handlers - /client/proc/special_set_vv_var(var/datum/O, variable, var_value, client) - if(!vv_set_handlers) - vv_set_handlers = init_subtypes(/decl/vv_set_handler) + var/list/vv_set_handlers = decls_repository.get_decls_of_subtype(/decl/vv_set_handler) for(var/vv_handler in vv_set_handlers) - var/decl/vv_set_handler/sh = vv_handler - if(sh.can_handle_set_var(O, variable, var_value, client)) - sh.handle_set_var(O, variable, var_value, client) + var/decl/vv_set_handler/set_handler = vv_set_handlers[vv_handler] + if(set_handler.can_handle_set_var(O, variable, var_value, client)) + set_handler.handle_set_var(O, variable, var_value, client) return TRUE return FALSE diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 1b62fdc9ff25..5dc191cdb1f1 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -1,11 +1,11 @@ -var/list/sounds_cache = list() +var/global/list/sounds_cache = list() /client/proc/play_sound(S as sound) set category = "Fun" set name = "Play Global Sound" if(!check_rights(R_SOUNDS)) return - var/sound/uploaded_sound = sound(S, repeat = 0, wait = 1, channel = GLOB.admin_sound_channel) + var/sound/uploaded_sound = sound(S, repeat = 0, wait = 1, channel = sound_channels.admin_channel) uploaded_sound.priority = 250 sounds_cache += S @@ -15,8 +15,8 @@ var/list/sounds_cache = list() log_admin("[key_name(src)] played sound [S]") message_admins("[key_name_admin(src)] played sound [S]", 1) - for(var/mob/M in GLOB.player_list) - if(M.get_preference_value(/datum/client_preference/play_admin_midis) == GLOB.PREF_YES) + for(var/mob/M in global.player_list) + if(M.get_preference_value(/datum/client_preference/play_admin_midis) == PREF_YES) sound_to(M, uploaded_sound) SSstatistics.add_field_details("admin_verb","PGS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index e01fe73f1b14..aea09a397414 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -2,8 +2,8 @@ set name = "Possess Obj" set category = "Object" - if(istype(O,/obj/singularity)) - if(config.forbid_singulo_possession) + if(istype(O,/obj/effect/singularity)) + if(get_config_value(/decl/config/toggle/forbid_singulo_possession)) to_chat(usr, "It is forbidden to possess singularities.") return @@ -23,26 +23,16 @@ /proc/release(obj/O) set name = "Release Obj" set category = "Object" - //usr.loc = get_turf(usr) if(usr.control_object && usr.name_archive) //if you have a name archived and if you are actually relassing an object usr.RemoveMovementHandler(/datum/movement_handler/mob/admin_possess) usr.real_name = usr.name_archive usr.SetName(usr.real_name) if(ishuman(usr)) - var/mob/living/carbon/human/H = usr + var/mob/living/human/H = usr H.SetName(H.get_visible_name()) -// usr.regenerate_icons() //So the name is updated properly usr.forceMove(O.loc) // Appear where the object you were controlling is -- TLE usr.client.eye = usr usr.control_object = null SSstatistics.add_field_details("admin_verb","RO") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/proc/givetestverbs(mob/M as mob in SSmobs.mob_list) - set desc = "Give this guy possess/release verbs" - set category = "Debug" - set name = "Give Possessing Verbs" - M.verbs += /proc/possess - M.verbs += /proc/release - SSstatistics.add_field_details("admin_verb","GPV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! \ No newline at end of file diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index eff0dee45fb9..092f90de0ad1 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -6,16 +6,16 @@ SSstatistics.add_field_details("admin_verb","PR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /proc/Centcomm_announce(var/msg, var/mob/Sender, var/iamessage) - msg = "[uppertext(GLOB.using_map.boss_short)]M[iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) ([admin_jump_link(Sender)]) (CA) (BSA) (RPLY): [msg]" + msg = "[uppertext(global.using_map.boss_short)]M[iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) ([admin_jump_link(Sender)]) (RS) (BSA) (RPLY): [msg]" - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(R_ADMIN & C.holder.rights) to_chat(C, msg) sound_to(C, 'sound/machines/signal.ogg') /proc/Syndicate_announce(var/msg, var/mob/Sender) - msg = "ILLEGAL:[key_name(Sender, 1)] (PP) (VV) (DN) ([admin_jump_link(Sender)]) (CA) (BSA) (TAKE) (RPLY): [msg]" - for(var/client/C in GLOB.admins) + msg = "ILLEGAL:[key_name(Sender, 1)] (PP) (VV) (DN) ([admin_jump_link(Sender)]) (RS) (BSA) (TAKE) (RPLY): [msg]" + for(var/client/C in global.admins) if(R_ADMIN & C.holder.rights) to_chat(C, msg) sound_to(C, 'sound/machines/signal.ogg') \ No newline at end of file diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 07651303e974..39e5e364fc4c 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -9,39 +9,13 @@ if(confirm != "Yes") return - for(var/obj/item/W in M.get_contained_external_atoms()) - M.drop_from_inventory(W) + for(var/obj/item/thing in M.get_contained_external_atoms()) + M.drop_from_inventory(thing) log_admin("[key_name(usr)] made [key_name(M)] drop everything!") message_admins("[key_name_admin(usr)] made [key_name_admin(M)] drop everything!", 1) SSstatistics.add_field_details("admin_verb","DEVR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_prison(mob/M as mob in SSmobs.mob_list) - set category = "Admin" - set name = "Prison" - if(!holder) - to_chat(src, "Only administrators may use this command.") - return - if (ismob(M)) - if(istype(M, /mob/living/silicon/ai)) - alert("The AI can't be sent to prison you jerk!", null, null, null, null, null) - return - //strip their stuff before they teleport into a cell :downs: - for(var/obj/item/W in M) - M.drop_from_inventory(W) - //teleport person to cell - M.Paralyse(5) - sleep(5) //so they black out before warping - M.forceMove(pick(GLOB.prisonwarp)) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/prisoner = M - prisoner.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(prisoner), slot_w_uniform) - prisoner.equip_to_slot_or_del(new /obj/item/clothing/shoes/color/orange(prisoner), slot_shoes) - spawn(50) - to_chat(M, "You have been sent to the prison station!") - log_and_message_admins("sent [key_name_admin(M)] to the prison station.") - SSstatistics.add_field_details("admin_verb","PRISON") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - /client/proc/cmd_check_new_players() //Allows admins to determine who the newer players are. set category = "Admin" set name = "Check new Players" @@ -58,7 +32,7 @@ var/missing_ages = 0 var/msg = "" - for(var/client/C in GLOB.clients) + for(var/client/C in global.clients) if(C.player_age == "Requires database") missing_ages = 1 continue @@ -109,7 +83,7 @@ return if (style == "unsafe") - if (!config.allow_unsafe_narrates) + if (!get_config_value(/decl/config/toggle/allow_unsafe_narrates)) to_chat(user, SPAN_WARNING("Unsafe narrates are not permitted by the server configuration.")) return @@ -221,7 +195,7 @@ M.visible_message(result[1], result[1], narrate = TRUE) log_and_message_admins(" - VisibleNarrate [result[2]]/[result[3]] on [A]: [result[4]]") -// Visible narrate, it's as if it's a audible message +// Visible narrate, it's as if it's an audible message /client/proc/cmd_admin_audible_narrate(var/atom/A) set category = "Special Verbs" set name = "Audible Narrate" @@ -256,17 +230,17 @@ message_admins("[key_name_admin(usr)] has toggled [key_name_admin(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]", 1) SSstatistics.add_field_details("admin_verb","GOD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -proc/cmd_admin_mute(mob/M as mob, mute_type) +/proc/cmd_admin_mute(mob/M as mob, mute_type) if(!usr || !usr.client) return if(!usr.client.holder) - to_chat(usr, "Error: cmd_admin_mute: You don't have permission to do this.") + to_chat(usr, SPAN_WARNING("Error: cmd_admin_mute: You don't have permission to do this.")) return if(!M.client) - to_chat(usr, "Error: cmd_admin_mute: This mob doesn't have a client tied to it.") + to_chat(usr, SPAN_WARNING("Error: cmd_admin_mute: This mob doesn't have a client tied to it.")) return if(M.client.holder) - to_chat(usr, "Error: cmd_admin_mute: You cannot mute an admin/mod.") + to_chat(usr, SPAN_WARNING("Error: cmd_admin_mute: You cannot mute an admin/mod.")) return var/muteunmute @@ -295,58 +269,37 @@ proc/cmd_admin_mute(mob/M as mob, mute_type) to_chat(M, "You have been [muteunmute] from [mute_string].") SSstatistics.add_field_details("admin_verb","MUTE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_add_random_ai_law() - set category = "Fun" - set name = "Add Random AI Law" - if(!holder) - to_chat(src, "Only administrators may use this command.") - return - var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") - if(confirm != "Yes") return - log_admin("[key_name(src)] has added a random AI law.") - message_admins("[key_name_admin(src)] has added a random AI law.", 1) - - var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No") - if(show_log == "Yes") - command_announcement.Announce("Ion storm detected near the [station_name()]. Please check all AI-controlled equipment for errors.", "Anomaly Alert", new_sound = 'sound/AI/ionstorm.ogg') - - IonStorm(0) - SSstatistics.add_field_details("admin_verb","ION") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - /* Allow admins to set players to be able to respawn/bypass 30 min wait, without the admin having to edit variables directly Ccomp's first proc. */ - -/client/proc/get_ghosts(var/notify = 0,var/what = 2) +/proc/get_ghosts(var/notify, var/what = 2) // what = 1, return ghosts ass list. // what = 2, return mob list var/list/mobs = list() var/list/ghosts = list() - var/list/sortmob = sortAtom(SSmobs.mob_list) // get the mob list. + var/list/sortmob = sortTim(SSmobs.mob_list, /proc/cmp_name_asc) // get the mob list. var/any=0 for(var/mob/observer/ghost/M in sortmob) mobs.Add(M) //filter it where it's only ghosts any = 1 //if no ghosts show up, any will just be 0 if(!any) if(notify) - to_chat(src, "There doesn't appear to be any ghosts for you to select.") + to_chat(notify, "There doesn't appear to be any ghosts for you to select.") return - for(var/mob/M in mobs) var/name = M.name ghosts[name] = M //get the name of the mob for the popup list - if(what==1) + if(what == 1) return ghosts - else - return mobs + return mobs /client/proc/get_ghosts_by_key() . = list() for(var/mob/observer/ghost/M in SSmobs.mob_list) .[M.ckey] = M - . = sortAssoc(.) + . = sortTim(., /proc/cmp_text_asc) /client/proc/allow_character_respawn(var/selection in get_ghosts_by_key()) set category = "Special Verbs" @@ -362,22 +315,24 @@ Ccomp's first proc. to_chat(src, "[selection] no longer has an associated ghost.") return - if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted) + if(G.has_enabled_antagHUD == 1 && get_config_value(/decl/config/toggle/antag_hud_restricted)) var/response = alert(src, "[selection] has enabled antagHUD. Are you sure you wish to allow them to respawn?","Ghost has used AntagHUD","No","Yes") if(response == "No") return else var/response = alert(src, "Are you sure you wish to allow [selection] to respawn?","Allow respawn","No","Yes") if(response == "No") return - G.timeofdeath=-19999 /* time of death is checked in /mob/verb/abandon_mob() which is the Respawn verb. - timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure - there won't be an autopsy. - */ + /* + time of death is checked in /mob/verb/abandon_mob() which is the Respawn verb. + timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure + there won't be an autopsy. + */ + G.timeofdeath = -(INFINITY) G.has_enabled_antagHUD = 2 - G.can_reenter_corpse = CORPSE_CAN_REENTER_AND_RESPAWN + G.can_reenter_corpse |= CORPSE_CAN_RESPAWN G.show_message("You may now respawn. You should roleplay as if you learned nothing about the round during your time with the dead.", 1) - log_and_message_admins("has allowed [key_name(G)] to bypass the [config.respawn_delay] minute respawn limit.") + log_and_message_admins("has allowed [key_name(G)] to bypass the [get_config_value(/decl/config/num/respawn_delay)] minute respawn limit.") /client/proc/toggle_antagHUD_use() set category = "Server" @@ -386,34 +341,13 @@ Ccomp's first proc. if(!holder) to_chat(src, "Only administrators may use this command.") - var/action="" - if(config.antag_hud_allowed) - for(var/mob/observer/ghost/g in get_ghosts()) - if(!g.client.holder) //Remove the verb from non-admin ghosts - g.verbs -= /mob/observer/ghost/verb/toggle_antagHUD - if(g.antagHUD) - g.antagHUD = 0 // Disable it on those that have it enabled - g.has_enabled_antagHUD = 2 // We'll allow them to respawn - to_chat(g, "The Administrator has disabled AntagHUD") - config.antag_hud_allowed = 0 - to_chat(src, "AntagHUD usage has been disabled") - action = "disabled" - else - for(var/mob/observer/ghost/g in get_ghosts()) - if(!g.client.holder) // Add the verb back for all non-admin ghosts - g.verbs += /mob/observer/ghost/verb/toggle_antagHUD - to_chat(g, "The Administrator has enabled AntagHUD ")// Notify all observers they can now use AntagHUD - - config.antag_hud_allowed = 1 + var/action = "disabled" + if(toggle_config_value(/decl/config/toggle/antag_hud_allowed)) action = "enabled" - to_chat(src, "AntagHUD usage has been enabled") - - + to_chat(src, "AntagHUD usage has been [action]") log_admin("[key_name(usr)] has [action] antagHUD usage for observers") message_admins("Admin [key_name_admin(usr)] has [action] antagHUD usage for observers", 1) - - /client/proc/toggle_antagHUD_restrictions() set category = "Server" set name = "Toggle antagHUD Restrictions" @@ -421,22 +355,19 @@ Ccomp's first proc. if(!holder) to_chat(src, "Only administrators may use this command.") var/action="" - if(config.antag_hud_restricted) - for(var/mob/observer/ghost/g in get_ghosts()) - to_chat(g, "The administrator has lifted restrictions on joining the round if you use AntagHUD") - action = "lifted restrictions" - config.antag_hud_restricted = 0 - to_chat(src, "AntagHUD restrictions have been lifted") - else - for(var/mob/observer/ghost/g in get_ghosts()) + if(toggle_config_value(/decl/config/toggle/antag_hud_restricted)) + for(var/mob/observer/ghost/g in get_ghosts(src)) to_chat(g, "The administrator has placed restrictions on joining the round if you use AntagHUD") to_chat(g, "Your AntagHUD has been disabled, you may choose to re-enabled it but will be under restrictions") g.antagHUD = 0 g.has_enabled_antagHUD = 0 action = "placed restrictions" - config.antag_hud_restricted = 1 to_chat(src, "AntagHUD restrictions have been enabled") - + else + for(var/mob/observer/ghost/g in get_ghosts(src)) + to_chat(g, "The administrator has lifted restrictions on joining the round if you use AntagHUD") + action = "lifted restrictions" + to_chat(src, "AntagHUD restrictions have been lifted") log_admin("[key_name(usr)] has [action] on joining the round if they use AntagHUD") message_admins("Admin [key_name_admin(usr)] has [action] on joining the round if they use AntagHUD", 1) @@ -457,28 +388,27 @@ Traitors and the like can also be revived with the previous role mostly intact. return var/mob/observer/ghost/G_found - for(var/mob/observer/ghost/G in GLOB.player_list) + for(var/mob/observer/ghost/G in global.player_list) if(G.ckey == input) G_found = G break if(!G_found)//If a ghost was not found. - to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.") + to_chat(usr, SPAN_WARNING("There is no active key like that in the game or the person is not currently a ghost.")) return - var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))//The mob being spawned. - + var/mob/living/human/new_character = new(get_random_spawn_turf(SPAWN_FLAG_JOBS_CAN_SPAWN)) //The mob being spawned. var/datum/computer_file/report/crew_record/record_found //Referenced to later to either randomize or not randomize the character. if(G_found.mind && !G_found.mind.active) record_found = get_crewmember_record(G_found.real_name) if(record_found)//If they have a record we can determine a few things. new_character.real_name = record_found.get_name() - new_character.gender = record_found.get_sex() - new_character.age = record_found.get_age() - new_character.b_type = record_found.get_bloodtype() + new_character.set_gender(record_found.get_gender()) + new_character.set_age(record_found.get_age()) + new_character.blood_type = record_found.get_bloodtype() else - new_character.gender = pick(MALE,FEMALE) + new_character.set_gender(pick(MALE,FEMALE)) var/datum/preferences/A = new() A.setup() A.randomize_appearance_and_body_for(new_character) @@ -486,22 +416,21 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!new_character.real_name) if(new_character.gender == MALE) - new_character.real_name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + new_character.real_name = capitalize(pick(global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) else - new_character.real_name = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + new_character.real_name = capitalize(pick(global.using_map.first_names_female)) + " " + capitalize(pick(global.using_map.last_names)) new_character.SetName(new_character.real_name) if(G_found.mind && !G_found.mind.active) G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_character.mind.special_verbs = list() else new_character.mind_initialize() - if(!new_character.mind.assigned_role) new_character.mind.assigned_role = GLOB.using_map.default_assistant_title//If they somehow got a null assigned role. + if(!new_character.mind.assigned_role) + new_character.mind.assigned_role = global.using_map.default_job_title//If they somehow got a null assigned role. //DNA - new_character.dna.ready_dna(new_character) if(record_found)//Pull up their name from database records if they did have a mind. - new_character.dna.unique_enzymes = record_found.get_dna()//Enzymes are based on real name but we'll use the record for conformity. + new_character.set_unique_enzymes(record_found.get_dna()) new_character.key = G_found.key /* @@ -513,12 +442,12 @@ Traitors and the like can also be revived with the previous role mostly intact. var/player_key = G_found.key //Now for special roles and equipment. - var/datum/antagonist/antag_data = get_antag_data(new_character.mind.special_role) - if(antag_data) + var/decl/special_role/antag_data = GET_DECL(new_character.mind.assigned_special_role) + if(istype(antag_data)) antag_data.add_antagonist(new_character.mind) antag_data.place_mob(new_character) else - SSjobs.equip_rank(new_character, new_character.mind.assigned_role, 1) + SSjobs.equip_job_title(new_character, new_character.mind.assigned_role, 1) //Announces the character on all the systems, based on the record. if(!issilicon(new_character))//If they are not a cyborg/AI. @@ -542,14 +471,14 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!input) return for(var/mob/living/silicon/ai/M in SSmobs.mob_list) - if (M.stat == 2) + if (M.stat == DEAD) to_chat(usr, "Upload failed. No signal is being detected from the AI.") else if (M.see_in_dark == 0) to_chat(usr, "Upload failed. Only a faint signal is being detected from the AI, and it is not responding to our requests. It may be low on power.") else M.add_ion_law(input) for(var/mob/living/silicon/ai/O in SSmobs.mob_list) - to_chat(O, "" + input + "...LAWS UPDATED") + to_chat(O, SPAN_WARNING("[input]... LAWS UPDATED.")) O.show_laws() log_admin("Admin [key_name(usr)] has added a new AI law - [input]") @@ -571,7 +500,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!istype(M)) alert("Cannot revive a ghost") return - if(config.allow_admin_rev) + if(get_config_value(/decl/config/toggle/on/admin_revive)) M.revive() log_and_message_admins("healed / revived [key_name_admin(M)]!") @@ -586,20 +515,24 @@ Traitors and the like can also be revived with the previous role mostly intact. to_chat(src, "Only administrators may use this command.") return var/input = sanitize(input(usr, "Please enter anything you want. Anything. Serious.", "What?", "") as message|null, extra = 0) - var/customname = sanitizeSafe(input(usr, "Pick a title for the report.", "Title") as text|null) + var/customname = sanitize_safe(input(usr, "Pick a title for the report.", "Title") as text|null) if(!input) return if(!customname) - customname = "[command_name()] Update" + customname = "[global.using_map.boss_name] Update" + + // Even admin must bow to the whim of the autolanguagefilter. + if(filter_block_message(mob, input) || filter_block_message(mob, customname)) + return //New message handling post_comm_message(customname, replacetext(input, "\n", "
          ")) switch(alert("Should this be announced to the general population?",,"Yes","No")) if("Yes") - command_announcement.Announce(input, customname, new_sound = GLOB.using_map.command_report_sound, msg_sanitized = 1); + command_announcement.Announce(input, customname, new_sound = global.using_map.command_report_sound, msg_sanitized = 1); if("No") - minor_announcement.Announce(message = "New [GLOB.using_map.company_name] Update available at all communication consoles.") + minor_announcement.Announce(message = "New [global.using_map.company_name] Update available at all communication consoles.") log_admin("[key_name(src)] has created a command report: [input]") message_admins("[key_name_admin(src)] has created a command report", 1) @@ -687,21 +620,13 @@ Traitors and the like can also be revived with the previous role mostly intact. /client/proc/cmd_admin_gib(mob/M as mob in SSmobs.mob_list) set category = "Special Verbs" set name = "Gib" - if(!check_rights(R_ADMIN|R_FUN)) return - var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") if(confirm != "Yes") return //Due to the delay here its easy for something to have happened to the mob if(!M) return - log_admin("[key_name(usr)] has gibbed [key_name(M)]") message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]", 1) - - if(isobserver(M)) - gibs(M.loc) - return - M.gib() SSstatistics.add_field_details("admin_verb","GIB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -719,17 +644,10 @@ Traitors and the like can also be revived with the previous role mostly intact. log_and_message_admins("used gibself.") SSstatistics.add_field_details("admin_verb","GIBS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/update_world() - // If I see anyone granting powers to specific keys like the code that was here, - // I will both remove their SVN access and permanently ban them from my servers. - return - /client/proc/cmd_admin_check_contents(mob/living/M as mob in SSmobs.mob_list) set category = "Special Verbs" set name = "Check Contents" - - var/list/L = M.get_contents() - for(var/t in L) + for(var/t in M.get_mob_contents()) to_chat(usr, "[t]") SSstatistics.add_field_details("admin_verb","CC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -821,8 +739,8 @@ Traitors and the like can also be revived with the previous role mostly intact. to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!") return - if(GLOB.random_players) - GLOB.random_players = 0 + if(global.random_players) + global.random_players = 0 message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.", 1) to_chat(usr, "Disabled.") return @@ -839,7 +757,7 @@ Traitors and the like can also be revived with the previous role mostly intact. to_world("Admin [usr.key] has forced the players to have completely random identities!") to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.") - GLOB.random_players = 1 + global.random_players = 1 SSstatistics.add_field_details("admin_verb","MER") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -850,12 +768,11 @@ Traitors and the like can also be revived with the previous role mostly intact. set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" if(!check_rights(R_SERVER)) return - if(!config.allow_random_events) - config.allow_random_events = 1 + toggle_config_value(/decl/config/toggle/on/allow_random_events) + if(get_config_value(/decl/config/toggle/on/allow_random_events)) to_chat(usr, "Random events enabled") message_admins("Admin [key_name_admin(usr)] has enabled random events.", 1) else - config.allow_random_events = 0 to_chat(usr, "Random events disabled") message_admins("Admin [key_name_admin(usr)] has disabled random events.", 1) SSstatistics.add_field_details("admin_verb","TRE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/trading_verbs.dm b/code/modules/admin/verbs/trading_verbs.dm deleted file mode 100644 index ab62c760ca0d..000000000000 --- a/code/modules/admin/verbs/trading_verbs.dm +++ /dev/null @@ -1,31 +0,0 @@ -/client/proc/list_traders() - set category = "Debug" - set name = "List Traders" - set desc = "Lists all the current traders" - - for(var/a in SStrade.traders) - var/datum/trader/T = a - to_chat(src, "[T.name] \ref[T]") - -/client/proc/add_trader() - set category = "Debug" - set name = "Add Trader" - set desc = "Adds a trader to the list." - - var/list/possible = subtypesof(/datum/trader) - /datum/trader/ship - /datum/trader/ship/unique - var/type = input(src,"Choose a type to add.") as null|anything in possible - if(!type) - return - - SStrade.traders += new type - -/client/proc/remove_trader() - set category = "Debug" - set name = "Remove Trader" - set desc = "Removes a trader from the trader list." - - var/choice = input(src, "Choose something to remove.") as null|anything in SStrade.traders - if(!choice) - return - - SStrade.traders -= choice diff --git a/code/modules/admin/verbs/tripAI.dm b/code/modules/admin/verbs/tripAI.dm index 62cdbeb1d3b8..e47d5f6863c9 100644 --- a/code/modules/admin/verbs/tripAI.dm +++ b/code/modules/admin/verbs/tripAI.dm @@ -10,11 +10,11 @@ if(!job) to_chat(usr, "Unable to locate the AI job") return - if(GLOB.triai) - GLOB.triai = 0 + if(global.triai) + global.triai = 0 to_chat(usr, "Only one AI will be spawned at round start.") message_admins("[key_name_admin(usr)] has toggled off triple AIs at round start.", 1) else - GLOB.triai = 1 + global.triai = 1 to_chat(usr, "There will be an AI Triumvirate at round start.") message_admins("[key_name_admin(usr)] has toggled on triple AIs at round start.", 1) diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index 886984935693..77e8826c5a98 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -1,31 +1,29 @@ - -// Keep these two together, they *must* be defined on both -// If /client ever becomes /datum/client or similar, they can be merged +// If /client/var/parent_type ever stops being /datum, this proc will need to be redefined on client. /datum/proc/get_view_variables_header() return "[src]" /atom/get_view_variables_header() return {" - [src] + [src]
          - << - [dir2text(dir)] - >> + \<\< + [dir2text(dir)] + \>\> "} /mob/living/get_view_variables_header() return {" - [src] -
          << [dir2text(dir)] >> -
          [ckey ? ckey : "No ckey"] / [real_name ? real_name : "No real name"] + [src] +
          \<\< [dir2text(dir)] \>\> +
          [ckey ? ckey : "No ckey"] / [real_name ? real_name : "No real name"]
          - BRUTE:[getBruteLoss()] - FIRE:[getFireLoss()] - TOXIN:[getToxLoss()] - OXY:[getOxyLoss()] - CLONE:[getCloneLoss()] - BRAIN:[getBrainLoss()] + BRUTE:[get_damage(BRUTE)] + FIRE:[get_damage(BURN)] + TOXIN:[get_damage(TOX)] + OXY:[get_damage(OXY)] + CLONE:[get_damage(CLONE)] + BRAIN:[get_damage(BRAIN)]
          "} @@ -37,22 +35,21 @@ return ..() + {" - - - - - + + + + @@ -65,19 +62,25 @@ /mob/living/get_view_variables_options() return ..() + {" - - + + + + + "} -/mob/living/carbon/human/get_view_variables_options() +/mob/living/human/get_view_variables_options() return ..() + {" + + + + - "} /obj/get_view_variables_options() @@ -88,13 +91,18 @@ "} +/obj/item/get_view_variables_options() + return ..() + {" + + "} + /turf/get_view_variables_options() return ..() + {" "} -/datum/proc/get_variables() +/datum/proc/VV_get_variables() . = vars - VV_hidden() if(!usr || !check_rights(R_ADMIN|R_DEBUG, FALSE)) . -= VV_secluded() @@ -110,18 +118,18 @@ /datum/proc/make_view_variables_variable_entry(var/varname, var/value, var/hide_watch = 0) return {" - (E) - (C) - (M) - [hide_watch ? "" : "(W)"] + (E) + (C) + (M) + [hide_watch ? "" : "(W)"] "} // No mass editing of clients /client/make_view_variables_variable_entry(var/varname, var/value, var/hide_watch = 0) return {" - (E) - (C) - [hide_watch ? "" : "(W)"] + (E) + (C) + [hide_watch ? "" : "(W)"] "} // These methods are all procs and don't use stored lists to avoid VV exploits @@ -134,12 +142,9 @@ /datum/proc/VV_secluded() return list() -/datum/configuration/VV_secluded() - return vars - // The following vars cannot be edited by anyone /datum/proc/VV_static() - return list("parent_type") + return list("parent_type", "gc_destroyed", "is_processing") /atom/VV_static() return ..() + list("bound_x", "bound_y", "bound_height", "bound_width", "bounds", "step_x", "step_y", "step_size") @@ -180,10 +185,10 @@ /datum/proc/may_edit_var(var/user, var/var_to_edit) if(!user) return FALSE - if(!(var_to_edit in vars)) + if(!(var_to_edit in VV_get_variables())) to_chat(user, "\The [src] does not have a var '[var_to_edit]'") return FALSE - if(var_to_edit in VV_static()) + if((var_to_edit in VV_static()) || (var_to_edit in VV_hidden())) return FALSE if((var_to_edit in VV_secluded()) && !check_rights(R_ADMIN|R_DEBUG, FALSE, C = user)) return FALSE diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 006d1e99fb16..562c9f1f486b 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -1,4 +1,3 @@ - /client/proc/view_var_Topic(href, href_list, hsrc) //This should all be moved over to datum/admins/Topic() or something ~Carn if( (usr.client != src) || !src.holder ) @@ -10,266 +9,244 @@ else if(href_list["rename"]) if(!check_rights(R_VAREDIT)) return - var/mob/M = locate(href_list["rename"]) - if(!istype(M)) + var/mob/victim = locate(href_list["rename"]) + if(!istype(victim)) to_chat(usr, "This can only be used on instances of type /mob") return - var/new_name = sanitize(input(usr,"What would you like to name this mob?","Input a name",M.real_name) as text|null, MAX_NAME_LEN) - if(!new_name || !M) return + var/new_name = sanitize(input(usr,"What would you like to name this mob?","Input a name",victim.real_name) as text|null, MAX_NAME_LEN) + if(!new_name || !victim) return - message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].") - M.fully_replace_character_name(new_name) + message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(victim)] to [new_name].") + victim.fully_replace_character_name(new_name) href_list["datumrefresh"] = href_list["rename"] else if(href_list["dressup"]) if(!check_rights(R_VAREDIT)) return - var/mob/living/carbon/human/H = locate(href_list["dressup"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + var/mob/living/human/victim = locate(href_list["dressup"]) + if(!istype(victim)) + to_chat(usr, "This can only be used on instances of type /mob/living/human") return - var/decl/hierarchy/outfit/outfit = input("Select outfit.", "Select equipment.") as null|anything in outfits() + var/decl/outfit/outfit = input("Select outfit.", "Select equipment.") as null|anything in decls_repository.get_decls_of_subtype_unassociated(/decl/outfit) if(!outfit) return - dressup_human(H, outfit, TRUE) + dressup_human(victim, outfit, TRUE) else if(href_list["varnameedit"] && href_list["datumedit"]) if(!check_rights(R_VAREDIT)) return - var/D = locate(href_list["datumedit"]) - if(!istype(D,/datum) && !istype(D,/client)) + var/datum_to_edit = locate(href_list["datumedit"]) + if(!istype(datum_to_edit, /datum) && !istype(datum_to_edit, /client)) to_chat(usr, "This can only be used on instances of types /client or /datum") return - modify_variables(D, href_list["varnameedit"], 1) + modify_variables(datum_to_edit, href_list["varnameedit"], 1) else if(href_list["varnamechange"] && href_list["datumchange"]) if(!check_rights(R_VAREDIT)) return - var/D = locate(href_list["datumchange"]) - if(!istype(D,/datum) && !istype(D,/client)) + var/datum_to_edit = locate(href_list["datumchange"]) + if(!istype(datum_to_edit,/datum) && !istype(datum_to_edit,/client)) to_chat(usr, "This can only be used on instances of types /client or /datum") return - modify_variables(D, href_list["varnamechange"], 0) + modify_variables(datum_to_edit, href_list["varnamechange"], 0) else if(href_list["varnamemass"] && href_list["datummass"]) if(!check_rights(R_VAREDIT)) return - var/atom/A = locate(href_list["datummass"]) - if(!istype(A)) + var/atom/atom_to_edit = locate(href_list["datummass"]) + if(!isatom(atom_to_edit)) to_chat(usr, "This can only be used on instances of type /atom") return - cmd_mass_modify_object_variables(A, href_list["varnamemass"]) + cmd_mass_modify_object_variables(atom_to_edit, href_list["varnamemass"]) else if(href_list["datumwatch"] && href_list["varnamewatch"]) - var/datum/D = locate(href_list["datumwatch"]) - if(D) - if(!watched_variables[D]) - watched_variables[D] = list() - watched_variables[D] |= href_list["varnamewatch"] + var/datum/datum_to_edit = locate(href_list["datumwatch"]) + if(datum_to_edit) + if(!watched_variables[datum_to_edit]) + watched_variables[datum_to_edit] = list() + watched_variables[datum_to_edit] |= href_list["varnamewatch"] watched_variables() if(!watched_variables_window.is_processing) START_PROCESSING(SSprocessing, watched_variables_window) else if(href_list["datumunwatch"] && href_list["varnameunwatch"]) - var/datum/D = locate(href_list["datumunwatch"]) - if(D && watched_variables[D]) - watched_variables[D] -= href_list["varnameunwatch"] - var/list/datums_watched_vars = watched_variables[D] + var/datum/datum_to_edit = locate(href_list["datumunwatch"]) + if(datum_to_edit && watched_variables[datum_to_edit]) + watched_variables[datum_to_edit] -= href_list["varnameunwatch"] + var/list/datums_watched_vars = watched_variables[datum_to_edit] if(!datums_watched_vars.len) - watched_variables -= D + watched_variables -= datum_to_edit if(!watched_variables.len && watched_variables_window.is_processing) STOP_PROCESSING(SSprocessing, watched_variables_window) else if(href_list["mob_player_panel"]) if(!check_rights(0)) return - var/mob/M = locate(href_list["mob_player_panel"]) - if(!istype(M)) + var/mob/victim = locate(href_list["mob_player_panel"]) + if(!istype(victim)) to_chat(usr, "This can only be used on instances of type /mob") return - src.holder.show_player_panel(M) + src.holder.show_player_panel(victim) href_list["datumrefresh"] = href_list["mob_player_panel"] - else if(href_list["give_spell"]) - if(!check_rights(R_ADMIN|R_FUN)) return - - var/mob/M = locate(href_list["give_spell"]) - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - - src.give_spell(M) - href_list["datumrefresh"] = href_list["give_spell"] - else if(href_list["godmode"]) - if(!check_rights(R_REJUVINATE)) return + if(!check_rights(R_REJUVENATE)) return - var/mob/M = locate(href_list["godmode"]) - if(!istype(M)) + var/mob/victim = locate(href_list["godmode"]) + if(!istype(victim)) to_chat(usr, "This can only be used on instances of type /mob") return - src.cmd_admin_godmode(M) + src.cmd_admin_godmode(victim) href_list["datumrefresh"] = href_list["godmode"] else if(href_list["gib"]) if(!check_rights(0)) return - var/mob/M = locate(href_list["gib"]) - if(!istype(M)) + var/mob/victim = locate(href_list["gib"]) + if(!istype(victim)) to_chat(usr, "This can only be used on instances of type /mob") return - src.cmd_admin_gib(M) + src.cmd_admin_gib(victim) else if(href_list["drop_everything"]) if(!check_rights(R_DEBUG|R_ADMIN)) return - var/mob/M = locate(href_list["drop_everything"]) - if(!istype(M)) + var/mob/victim = locate(href_list["drop_everything"]) + if(!istype(victim)) to_chat(usr, "This can only be used on instances of type /mob") return if(usr.client) - usr.client.cmd_admin_drop_everything(M) + usr.client.cmd_admin_drop_everything(victim) else if(href_list["direct_control"]) if(!check_rights(0)) return - var/mob/M = locate(href_list["direct_control"]) - if(!istype(M)) + var/mob/victim = locate(href_list["direct_control"]) + if(!istype(victim)) to_chat(usr, "This can only be used on instances of type /mob") return if(usr.client) - usr.client.cmd_assume_direct_control(M) - - else if(href_list["make_skeleton"]) - if(!check_rights(R_FUN)) return - - var/mob/living/carbon/human/H = locate(href_list["make_skeleton"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") - return - - H.ChangeToSkeleton() - href_list["datumrefresh"] = href_list["make_skeleton"] + usr.client.cmd_assume_direct_control(victim) else if(href_list["delthis"]) if(!check_rights(R_DEBUG|R_SERVER)) return - var/obj/O = locate(href_list["delthis"]) - if(!isobj(O)) + var/obj/object = locate(href_list["delthis"]) + if(!isobj(object)) to_chat(usr, "This can only be used on instances of type /obj") return - cmd_admin_delete(O) + cmd_admin_delete(object) else if(href_list["delall"]) if(!check_rights(R_DEBUG|R_SERVER)) return - var/obj/O = locate(href_list["delall"]) - if(!isobj(O)) + var/obj/object = locate(href_list["delall"]) + if(!isobj(object)) to_chat(usr, "This can only be used on instances of type /obj") return - var/action_type = alert("Strict type ([O.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") + var/action_type = alert("Strict type ([object.type]) or type and all subtypes?",,"Strict type","Type and subtypes","Cancel") if(action_type == "Cancel" || !action_type) return - if(alert("Are you really sure you want to delete all objects of type [O.type]?",,"Yes","No") != "Yes") + if(alert("Are you really sure you want to delete all objects of type [object.type]?",,"Yes","No") != "Yes") return if(alert("Second confirmation required. Delete?",,"Yes","No") != "Yes") return - var/O_type = O.type + var/type_to_delete = object.type switch(action_type) if("Strict type") - var/i = 0 - for(var/obj/Obj in world) - if(Obj.type == O_type) - i++ - qdel(Obj) - if(!i) + var/count = 0 + for(var/obj/deleted_object in world) + if(deleted_object.type == type_to_delete) + count++ + qdel(deleted_object) + if(!count) to_chat(usr, "No objects of this type exist") return - log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)") - message_admins("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted)") + log_admin("[key_name(usr)] deleted all objects of type [type_to_delete] ([count] objects deleted)") + message_admins("[key_name(usr)] deleted all objects of type [type_to_delete] ([count] objects deleted)") if("Type and subtypes") - var/i = 0 - for(var/obj/Obj in world) - if(istype(Obj,O_type)) - i++ - qdel(Obj) - if(!i) + var/count = 0 + for(var/obj/deleted_object in world) + if(istype(deleted_object, type_to_delete)) + count++ + qdel(deleted_object) + if(!count) to_chat(usr, "No objects of this type exist") return - log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)") - message_admins("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted)") + log_admin("[key_name(usr)] deleted all objects of type or subtype of [type_to_delete] ([count] objects deleted)") + message_admins("[key_name(usr)] deleted all objects of type or subtype of [type_to_delete] ([count] objects deleted)") else if(href_list["explode"]) if(!check_rights(R_DEBUG|R_FUN)) return - var/atom/A = locate(href_list["explode"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) + var/atom/atom_to_explode = locate(href_list["explode"]) + if(!isobj(atom_to_explode) && !ismob(atom_to_explode) && !isturf(atom_to_explode)) to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") return - src.cmd_admin_explosion(A) + src.cmd_admin_explosion(atom_to_explode) href_list["datumrefresh"] = href_list["explode"] else if(href_list["emp"]) if(!check_rights(R_DEBUG|R_FUN)) return - var/atom/A = locate(href_list["emp"]) - if(!isobj(A) && !ismob(A) && !isturf(A)) + var/atom/atom_to_emp = locate(href_list["emp"]) + if(!isobj(atom_to_emp) && !ismob(atom_to_emp) && !isturf(atom_to_emp)) to_chat(usr, "This can only be done to instances of type /obj, /mob and /turf") return - src.cmd_admin_emp(A) + src.cmd_admin_emp(atom_to_emp) href_list["datumrefresh"] = href_list["emp"] else if(href_list["mark_object"]) if(!check_rights(0)) return - var/datum/D = locate(href_list["mark_object"]) - if(!istype(D)) + var/datum/datum_to_mark = locate(href_list["mark_object"]) + if(!istype(datum_to_mark)) to_chat(usr, "This can only be done to instances of type /datum") return - src.holder.marked_datum_weak = weakref(D) + src.holder.marked_datum_weak = weakref(datum_to_mark) href_list["datumrefresh"] = href_list["mark_object"] else if(href_list["rotatedatum"]) if(!check_rights(0)) return - var/atom/A = locate(href_list["rotatedatum"]) - if(!istype(A)) + var/atom/atom_to_rotate = locate(href_list["rotatedatum"]) + if(!isatom(atom_to_rotate)) to_chat(usr, "This can only be done to instances of type /atom") return switch(href_list["rotatedir"]) - if("right") A.set_dir(turn(A.dir, -45)) - if("left") A.set_dir(turn(A.dir, 45)) + if("right") atom_to_rotate.set_dir(turn(atom_to_rotate.dir, -45)) + if("left") atom_to_rotate.set_dir(turn(atom_to_rotate.dir, 45)) href_list["datumrefresh"] = href_list["rotatedatum"] else if(href_list["makemonkey"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["makemonkey"]) - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + var/mob/living/human/victim = locate(href_list["makemonkey"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living/human") return if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return - if(!H) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return holder.Topic(href, list("monkeyone"=href_list["makemonkey"])) @@ -277,69 +254,128 @@ else if(href_list["makerobot"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["makerobot"]) - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + var/mob/living/human/victim = locate(href_list["makerobot"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living/human") return if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return - if(!H) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return holder.Topic(href, list("makerobot"=href_list["makerobot"])) - else if(href_list["makeslime"]) + else if(href_list["makeai"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["makeslime"]) - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + var/mob/living/human/victim = locate(href_list["makeai"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living/human") return if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return - if(!H) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return - holder.Topic(href, list("makeslime"=href_list["makeslime"])) + holder.Topic(href, list("makeai"=href_list["makeai"])) - else if(href_list["makeai"]) - if(!check_rights(R_SPAWN)) return + else if(href_list["addailment"]) - var/mob/living/carbon/human/H = locate(href_list["makeai"]) - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + var/mob/living/human/victim = locate(href_list["addailment"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living/human") + return + var/obj/item/organ/limb = input("Select a limb to add the ailment to.", "Add Ailment") as null|anything in victim.get_organs() + if(QDELETED(victim) || QDELETED(limb) || limb.owner != victim) return + var/list/possible_ailments = list() + for(var/atype in subtypesof(/datum/ailment)) + var/datum/ailment/ailment = get_ailment_reference(atype) // will not get abstract ailments + if(ailment && ailment.can_apply_to(limb)) + possible_ailments |= ailment - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return - if(!H) - to_chat(usr, "Mob doesn't exist anymore") + var/datum/ailment/ailment = input("Select an ailment type to add.", "Add Ailment") as null|anything in possible_ailments + if(!istype(ailment)) return - holder.Topic(href, list("makeai"=href_list["makeai"])) + if(!QDELETED(victim) && !QDELETED(limb) && limb.owner == victim && limb.add_ailment(ailment)) + to_chat(usr, SPAN_NOTICE("Added [ailment] to \the [victim].")) + else + to_chat(usr, SPAN_WARNING("Failed to add [ailment] to \the [victim].")) + return + + else if(href_list["remailment"]) + + var/mob/living/human/victim = locate(href_list["remailment"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living/human") + return + var/list/all_ailments = list() + for(var/obj/item/organ/limb in victim.get_organs()) + for(var/datum/ailment/ailment in limb.ailments) + all_ailments["[ailment.name] - [limb.name]"] = ailment + + var/datum/ailment/ailment = input("Which ailment do you wish to remove?", "Removing Ailment") as null|anything in all_ailments + if(!ailment) + return + ailment = all_ailments[ailment] + if(istype(ailment) && ailment.organ && ailment.organ.owner == victim && ailment.organ.remove_ailment(ailment)) + to_chat(usr, SPAN_NOTICE("Removed [ailment] from \the [victim].")) + else + to_chat(usr, SPAN_WARNING("Failed to remove [ailment] from \the [victim].")) + return else if(href_list["setspecies"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["setspecies"]) - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") + var/mob/living/human/victim = locate(href_list["setspecies"]) + if(!istype(victim)) + to_chat(usr, SPAN_WARNING("This can only be done to instances of type /mob/living/human")) return - var/new_species = input("Please choose a new species.","Species",null) as null|anything in get_all_species() + var/decl/species/new_species = input("Please choose a new species.","Species",null) as null|anything in decls_repository.get_decls_of_subtype_unassociated(/decl/species) - if(!H) - to_chat(usr, "Mob doesn't exist anymore") + if(!victim) + to_chat(usr, SPAN_WARNING("Mob doesn't exist anymore")) + return + + if(!new_species) + return + + if(victim.change_species(new_species.uid)) + to_chat(usr, SPAN_NOTICE("Set species of \the [victim] to [victim.species].")) + else + to_chat(usr, SPAN_WARNING("Failed! Something went wrong.")) + + else if(href_list["setbodytype"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/human/victim = locate(href_list["setbodytype"]) + if(!istype(victim)) + to_chat(usr, SPAN_WARNING("This can only be done to instances of type /mob/living/human")) + return + + var/new_bodytype = input("Please choose a new bodytype.","Bodytype",null) as null|anything in victim.species.available_bodytypes + + if(!new_bodytype) + return + + if(!victim) + to_chat(usr, SPAN_WARNING("Mob doesn't exist anymore")) return - if(H.set_species(new_species)) - to_chat(usr, "Set species of [H] to [H.species].") + if(!(new_bodytype in victim.species.available_bodytypes)) + to_chat(usr, SPAN_WARNING("Bodytype is no longer available to the mob species.")) + + if(victim.set_bodytype(new_bodytype)) + to_chat(usr, SPAN_NOTICE("Set bodytype of [victim] to [victim.get_bodytype()].")) else - to_chat(usr, "Failed! Something went wrong.") + to_chat(usr, SPAN_WARNING("Failed! Something went wrong.")) else if(href_list["addlanguage"]) if(!check_rights(R_SPAWN)) return - var/mob/H = locate(href_list["addlanguage"]) - if(!istype(H)) + var/mob/victim = locate(href_list["addlanguage"]) + if(!istype(victim)) to_chat(usr, "This can only be done to instances of type /mob") return @@ -349,218 +385,347 @@ if(!new_language) return - if(!H) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return - if(H.add_language(new_language)) - to_chat(usr, "Added [new_language] to [H].") + if(victim.add_language(new_language)) + to_chat(usr, "Added [new_language] to [victim].") else to_chat(usr, "Mob already knows that language.") else if(href_list["remlanguage"]) if(!check_rights(R_SPAWN)) return - var/mob/H = locate(href_list["remlanguage"]) - if(!istype(H)) + var/mob/victim = locate(href_list["remlanguage"]) + if(!istype(victim)) to_chat(usr, "This can only be done to instances of type /mob") return - if(!H.languages.len) + if(!victim.languages.len) to_chat(usr, "This mob knows no languages.") return - var/decl/language/rem_language = input("Please choose a language to remove.","Language",null) as null|anything in H.languages + var/decl/language/rem_language = input("Please choose a language to remove.","Language",null) as null|anything in victim.languages if(!rem_language) return - if(!H) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return - if(H.remove_language(rem_language.name)) - to_chat(usr, "Removed [rem_language] from [H].") + if(victim.remove_language(rem_language.type)) + to_chat(usr, "Removed [rem_language] from [victim].") else to_chat(usr, "Mob doesn't know that language.") else if(href_list["addverb"]) if(!check_rights(R_DEBUG)) return - var/mob/living/H = locate(href_list["addverb"]) + var/mob/living/victim = locate(href_list["addverb"]) - if(!istype(H)) + if(!istype(victim)) to_chat(usr, "This can only be done to instances of type /mob/living") return var/list/possibleverbs = list() possibleverbs += "Cancel" // One for the top... - possibleverbs += typesof(/mob/proc,/mob/verb,/mob/living/proc,/mob/living/verb) - switch(H.type) - if(/mob/living/carbon/human) - possibleverbs += typesof(/mob/living/carbon/proc,/mob/living/carbon/verb,/mob/living/carbon/human/verb,/mob/living/carbon/human/proc) - if(/mob/living/silicon/robot) - possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/robot/proc,/mob/living/silicon/robot/verb) - if(/mob/living/silicon/ai) - possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/ai/proc,/mob/living/silicon/ai/verb) - possibleverbs -= H.verbs + possibleverbs += typesof(/mob/proc, /mob/verb, /mob/living/proc, /mob/living/verb) + if(ishuman(victim)) + possibleverbs += typesof(/mob/living/human/verb, /mob/living/human/proc) + else if(isrobot(victim)) + possibleverbs += typesof(/mob/living/silicon/proc, /mob/living/silicon/robot/proc, /mob/living/silicon/robot/verb) + else if(isAI(victim)) + possibleverbs += typesof(/mob/living/silicon/proc, /mob/living/silicon/ai/proc, /mob/living/silicon/ai/verb) + possibleverbs -= victim.verbs possibleverbs += "Cancel" // ...And one for the bottom - var/verb = input("Select a verb!", "Verbs",null) as anything in possibleverbs - if(!H) + var/verb = input("Select a verb!", "Verbs",null) as null|anything in possibleverbs + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return if(!verb || verb == "Cancel") return else - H.verbs += verb + victim.verbs += verb else if(href_list["remverb"]) if(!check_rights(R_DEBUG)) return - var/mob/H = locate(href_list["remverb"]) + var/mob/victim = locate(href_list["remverb"]) - if(!istype(H)) + if(!istype(victim)) to_chat(usr, "This can only be done to instances of type /mob") return - var/verb = input("Please choose a verb to remove.","Verbs",null) as null|anything in H.verbs - if(!H) + var/verb = input("Please choose a verb to remove.","Verbs",null) as null|anything in victim.verbs + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return if(!verb) return else - H.verbs -= verb + victim.verbs -= verb else if(href_list["addorgan"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/M = locate(href_list["addorgan"]) - if(!istype(M)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + var/mob/living/victim = locate(href_list["addorgan"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living") + return + + if(!length(victim.get_external_organs())) // quick and dirty check for organs; should always be >0 for humanlike mobs. + to_chat(usr, "This can only be done to mobs that implement organs!") return - var/new_organ = input("Please choose an organ to add.","Organ",null) as null|anything in typesof(/obj/item/organ)-/obj/item/organ + var/obj/item/organ/new_organ = input("Please choose an organ to add.","Organ",null) as null|anything in subtypesof(/obj/item/organ) if(!new_organ) return - if(!M) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return - if(locate(new_organ) in M.internal_organs) + if(locate(new_organ) in victim.get_internal_organs()) to_chat(usr, "Mob already has that organ.") return - new new_organ(M) + var/obj/item/organ/target_organ = victim.get_organ(initial(new_organ.parent_organ)) + if(!target_organ) + to_chat(usr, "Mob doesn't have \a [target_organ] to install that in.") + return + var/obj/item/organ/organ_instance = new new_organ(victim) + victim.add_organ(organ_instance, target_organ) else if(href_list["remorgan"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/M = locate(href_list["remorgan"]) - if(!istype(M)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon") + var/mob/living/victim = locate(href_list["remorgan"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living") return - var/obj/item/organ/rem_organ = input("Please choose an organ to remove.","Organ",null) as null|anything in M.internal_organs + if(!length(victim.get_external_organs())) // quick and dirty check for organs; should always be >0 for humanlike mobs. + to_chat(usr, "This can only be done to mobs that implement organs!") + return - if(!M) + var/obj/item/organ/rem_organ = input("Please choose an organ to remove.","Organ",null) as null|anything in victim.get_internal_organs() + + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return - if(!(locate(rem_organ) in M.internal_organs)) + if(!(locate(rem_organ) in victim.get_internal_organs())) to_chat(usr, "Mob does not have that organ.") return - to_chat(usr, "Removed [rem_organ] from [M].") - rem_organ.removed() + to_chat(usr, "Removed [rem_organ] from [victim].") + victim.remove_organ(rem_organ) if(!QDELETED(rem_organ)) qdel(rem_organ) else if(href_list["fix_nano"]) if(!check_rights(R_DEBUG)) return - var/mob/H = locate(href_list["fix_nano"]) + var/mob/victim = locate(href_list["fix_nano"]) - if(!istype(H) || !H.client) + if(!istype(victim) || !victim.client) to_chat(usr, "This can only be done on mobs with clients") return - SSnano.close_uis(H) - H.client.cache.Cut() + SSnano.close_uis(victim) + victim.client.cache.Cut() var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui) - assets.send(H) + assets.send(victim) to_chat(usr, "Resource files sent") - to_chat(H, "Your NanoUI Resource files have been refreshed") - - log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(H)] ") + to_chat(victim, "Your NanoUI Resource files have been refreshed") - else if(href_list["regenerateicons"]) - if(!check_rights(0)) return + log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(victim)] ") - var/mob/M = locate(href_list["regenerateicons"]) - if(!ismob(M)) + else if(href_list["updateicon"]) + if(!check_rights(0)) + return + var/mob/victim = locate(href_list["updateicon"]) + if(!ismob(victim)) to_chat(usr, "This can only be done to instances of type /mob") return - M.regenerate_icons() + victim.update_icon() + + else if(href_list["refreshoverlays"]) + if(!check_rights(0)) + return + var/mob/living/human/victim = locate(href_list["refreshoverlays"]) + if(!istype(victim)) + to_chat(usr, "This can only be done to instances of type /mob/living/human") + return + victim.try_refresh_visible_overlays() else if(href_list["adjustDamage"] && href_list["mobToDamage"]) if(!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return - var/mob/living/L = locate(href_list["mobToDamage"]) - if(!istype(L)) return + var/mob/living/victim = locate(href_list["mobToDamage"]) + if(!istype(victim)) return var/Text = href_list["adjustDamage"] var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num - if(!L) + if(!victim) to_chat(usr, "Mob doesn't exist anymore") return - switch(Text) - if("brute") L.adjustBruteLoss(amount) - if("fire") L.adjustFireLoss(amount) - if("toxin") L.adjustToxLoss(amount) - if("oxygen")L.adjustOxyLoss(amount) - if("brain") L.adjustBrainLoss(amount) - if("clone") L.adjustCloneLoss(amount) - else - to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") - return + if(istext(Text)) + victim.take_damage(amount, Text) + else + to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[victim]") + return if(amount != 0) - log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]") - message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [L]") + log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [victim]") + message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [victim]") href_list["datumrefresh"] = href_list["mobToDamage"] else if(href_list["call_proc"]) - var/datum/D = locate(href_list["call_proc"]) - if(istype(D) || istype(D, /client)) // can call on clients too, not just datums - callproc_targetpicked(1, D) - else if(href_list["addaura"]) - if(!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return - var/mob/living/L = locate(href_list["addaura"]) - if(!istype(L)) + var/datum/proc_callee = locate(href_list["call_proc"]) + if(istype(proc_callee) || istype(proc_callee, /client)) // can call on clients too, not just datums + callproc_targetpicked(1, proc_callee) + + else if(href_list["addstressor"]) + if(!check_rights(R_DEBUG)) return - var/choice = input("Please choose an aura to add", "Auras", null) as null|anything in typesof(/obj/aura) - if(!choice || !L) + var/mob/living/victim = locate(href_list["addstressor"]) + if(!istype(victim)) return - var/obj/o = new choice(L) - log_and_message_admins("added \the [o] to \the [L]") - else if(href_list["removeaura"]) - if(!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return - var/mob/living/L = locate(href_list["removeaura"]) - if(!istype(L)) + var/static/list/_all_stressors + if(!_all_stressors) + _all_stressors = SSmanaged_instances.get_category(/datum/stressor) + var/datum/stressor/stressor = input("Select a stressor to add or refresh.", "Add Stressor") as null|anything in _all_stressors + if(!stressor) return - var/choice = input("Please choose an aura to remove", "Auras", null) as null|anything in L.auras - if(!choice || !L) + var/duration = clamp(input("Enter a duration ([STRESSOR_DURATION_INDEFINITE] for permanent).", "Add Stressor") as num|null, STRESSOR_DURATION_INDEFINITE, INFINITY) + if(duration && victim.add_stressor(stressor, duration)) + log_and_message_admins("added [stressor] to \the [victim] for duration [duration].") + + else if(href_list["removestressor"]) + if(!check_rights(R_DEBUG)) + return + var/mob/living/victim = locate(href_list["removestressor"]) + if(!istype(victim)) + return + if(!length(victim.stressors)) + to_chat(usr, "Nothing to remove.") + return + var/datum/stressor/stressor = input("Select a stressor to remove.", "Remove Stressor") as null|anything in victim.stressors + if(victim.remove_stressor(stressor)) + log_and_message_admins("removed [stressor] from \the [victim].") + + else if(href_list["setstatuscond"]) + if(!check_rights(R_DEBUG)) + return + var/mob/living/victim = locate(href_list["setstatuscond"]) + if(!istype(victim)) + return + var/list/all_status_conditions = decls_repository.get_decls_of_subtype(/decl/status_condition) + var/list/select_from_conditions = list() + for(var/status_cond in all_status_conditions) + select_from_conditions += all_status_conditions[status_cond] + var/decl/status_condition/selected_condition = input("Select a status condition to set.", "Set Status Condition") as null|anything in select_from_conditions + if(!selected_condition || QDELETED(victim) || !check_rights(R_DEBUG)) + return + var/amt = input("Enter an amount to set the condition to.", "Set Status Condition") as num|null + if(isnull(amt) || QDELETED(victim) || !check_rights(R_DEBUG)) + return + if(amt < 0) + amt += GET_STATUS(victim, selected_condition.type) + victim.set_status_condition(selected_condition.type, amt) + log_and_message_admins("set [selected_condition.name] to [amt] on \the [victim].") + + else if(href_list["setmaterial"]) + if(!check_rights(R_DEBUG)) return + + var/obj/item/item = locate(href_list["setmaterial"]) + if(!istype(item)) + to_chat(usr, "This can only be done to instances of type /obj/item") + return + + var/decl/material/new_material = input("Please choose a new material.","Materials",null) as null|anything in decls_repository.get_decls_of_subtype_unassociated(/decl/material) + if(!istype(new_material)) return - log_and_message_admins("removed \the [choice] to \the [L]") - qdel(choice) + if(QDELETED(item)) + to_chat(usr, "Item doesn't exist anymore") + return + item.set_material(new_material.type) + to_chat(usr, "Set material of [item] to [item.get_material()].") + + else if(href_list["give_ability"]) + var/mob/target = locate(href_list["give_ability"]) + if(!istype(target) || QDELETED(target)) + to_chat(usr, "Mob no longer exists.") + else + var/list/abilities = decls_repository.get_decls_of_type_unassociated(/decl/ability) + abilities = abilities.Copy() + abilities -= target.get_all_abilities() + var/decl/ability/ability = input(usr, "Which ability do you wish to grant?", "Give Ability") as null|anything in abilities + if(istype(ability) && !QDELETED(usr) && !QDELETED(target)) + if(target.add_ability(ability.type)) + log_and_message_admins("has given [ability] to [key_name(target)].") + else + to_chat(usr, SPAN_WARNING("Failed to give [ability] to [target]!")) + + else if(href_list["remove_ability"]) + var/mob/target = locate(href_list["remove_ability"]) + if(!istype(target) || QDELETED(target)) + to_chat(usr, "Mob no longer exists.") + else + var/decl/ability/ability = input(usr, "Which ability do you wish to remove?", "Remove Ability") as null|anything in target.get_all_abilities() + if(istype(ability) && !QDELETED(usr) && !QDELETED(target)) + if(target.remove_ability(ability.type)) + log_and_message_admins("has removed [ability] from [key_name(target)].") + else + to_chat(usr, SPAN_WARNING("Failed to remove [ability] from [target]!")) + + else if (href_list["add_mob_modifier"]) + var/mob/living/target = locate(href_list["add_mob_modifier"]) + if(!istype(target) || QDELETED(target)) + to_chat(usr, SPAN_WARNING("Only /mob/living mobs can have mob modifiers.")) + else + var/list/modifiers = list() + for(var/decl/mob_modifier/modifier in decls_repository.get_decls_of_type_unassociated(/decl/mob_modifier)) + if(modifier.can_be_admin_granted) + modifiers += modifier + // Evil pyramid due to apparently not being able to return early in this Topic() + var/decl/mob_modifier/modifier = input(usr, "Which modifier do you wish to give?", "Add Mob Modifier") as null|anything in modifiers + if(istype(modifier) && !QDELETED(target)) + var/duration = input(usr, "How long do you wish this modifier to last, in seconds? Enter -1 for a permanent modifier.", "Add Mob Modifier") as num|null + if(!isnull(duration)) + if(duration != MOB_MODIFIER_INDEFINITE) + duration = max(0, duration SECONDS) + if(duration != 0 && !QDELETED(target)) + if(target.add_mob_modifier(modifier, duration, source = target)) + to_chat(usr, SPAN_NOTICE("Added [modifier] to [target] for [duration] second\s.")) + else + to_chat(usr, SPAN_WARNING("Failed to add [modifier] to [target].")) + + else if (href_list["remove_mob_modifier"]) + var/mob/living/target = locate(href_list["remove_mob_modifier"]) + if(!istype(target) && !QDELETED(target)) + to_chat(usr, SPAN_WARNING("Only /mob/living mobs can have mob modifiers.")) + else + var/list/modifiers = list() + for(var/decl/mob_modifier/modifier in target._mob_modifiers) + if(modifier.can_be_admin_granted) + modifiers += modifier + var/decl/mob_modifier/modifier = input(usr, "Which modifier do you wish to remove?", "Remove Mob Modifier") as null|anything in modifiers + if(istype(modifier)) + if(target.remove_mob_modifier(modifier, source = target)) + to_chat(usr, SPAN_NOTICE("Removed [modifier] from [target].")) + else + to_chat(usr, SPAN_WARNING("Failed to remove [modifier] from [target].")) + if(href_list["datumrefresh"]) - var/datum/DAT = locate(href_list["datumrefresh"]) - if(istype(DAT, /datum) || istype(DAT, /client)) - debug_variables(DAT) + var/datum/datum_to_refresh = locate(href_list["datumrefresh"]) + if(istype(datum_to_refresh, /datum) || istype(datum_to_refresh, /client)) + debug_variables_inner(datum_to_refresh, filter = href_list["filter"]) return diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 53bfe1e6b26c..19efad19a399 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,14 +1,17 @@ // Variables not to expand the lists of. Vars is pointless to expand, and overlays/underlays cannot be expanded. -/var/list/view_variables_dont_expand = list("overlays", "underlays", "vars") +var/global/list/view_variables_dont_expand = list("overlays", "underlays", "vars", "vis_contents", "vis_locs") // Variables that runtime if you try to test associativity of the lists they contain by indexing -/var/list/view_variables_no_assoc = list("verbs", "contents","screen","images") +var/global/list/view_variables_no_assoc = list("verbs", "contents","screen","images") // Acceptable 'in world', as VV would be incredibly hampered otherwise /client/proc/debug_variables(datum/D in world) set category = "Debug" set name = "View Variables" - if(!check_rights(0)) + debug_variables_inner(D) + +/client/proc/debug_variables_inner(datum/D, filter = "" as null|text) + if(!check_rights(R_VAREDIT | R_DEBUG)) return if(!D) @@ -20,6 +23,8 @@ A = D if(A.icon && A.icon_state) sprite = icon(A.icon, A.icon_state) + if(A.color) + sprite.Blend(A.color, ICON_MULTIPLY) send_rsc(usr, sprite, "view_vars_sprite.png") send_rsc(usr,'code/js/view_variables.js', "view_variables.js") @@ -49,8 +54,8 @@
          - Refresh - [A ? "Jump To":""] + Refresh + [A ? "Jump To":""] " t += "" t += "Target account number:
          " @@ -196,21 +206,21 @@ t += "" else t += "Account balance: [authenticated_account.format_value_by_currency(authenticated_account.money)]" - t += "
          " + t += "" t += "" t += " Cash Chargecard
          " t += "" t += "
          " - t += "Change account security level
          " - t += "Make transfer
          " - t += "View transaction log
          " - t += "Print balance statement
          " + t += "Change account security level
          " + t += "Make transfer
          " + t += "View transaction log
          " + t += "Print balance statement
          " //Logout/back buttons, put here for some modularity and for less repeated code if(view_screen == NO_SCREEN) - t += "Logout
          " + t += "Logout
          " else - t += "Back" + t += "Back" else //change our display depending on account security levels @@ -220,7 +230,7 @@ t += "This account requires a PIN to access. For security reasons the account # will need re-entered or ID bound to this account re-scanned." else t += "Due to the security settings on this account, all information needs to be re-entered and the ID bound to this account placed in the slot above.
          " - t += "
          " + t += "" t += "" t += "" t += "Account:

          " @@ -229,36 +239,38 @@ t += "PIN:

          " t += "
          " t += "
          " + if(user?.mind?.initial_account) + t += "You recall your personal account number is #[user.mind.initial_account.account_number] and your PIN is [user.mind.initial_account.remote_access_pin].
          " - - var/datum/browser/written/popup = new(user, "ATM", machine_id) + var/datum/browser/written_digital/popup = new(user, "ATM", machine_id) popup.set_content(jointext(t,null)) popup.open() else return -/obj/machinery/atm/Topic(var/href, var/href_list) +/obj/machinery/atm/OnTopic(mob/user, href_list) if((. = ..())) return if(href_list["choice"]) + . = TOPIC_REFRESH switch(href_list["choice"]) if("transfer") if(authenticated_account) var/transfer_amount = text2num(href_list["funds_amount"]) transfer_amount = round(transfer_amount, 0.01) if(transfer_amount <= 0) - alert("That is not a valid amount.") + alert(user, "That is not a valid amount.") else if(transfer_amount <= authenticated_account.money) var/target_account_number = text2num(href_list["target_acc_number"]) var/transfer_purpose = href_list["purpose"] var/datum/money_account/target_account = get_account(target_account_number) if(target_account && authenticated_account.transfer(target_account, transfer_amount, transfer_purpose)) - to_chat(usr, "\icon[src]Funds transfer successful.") + to_chat(user, "[html_icon(src)]Funds transfer successful.") else - to_chat(usr, "\icon[src]Funds transfer failed.") + to_chat(user, "[html_icon(src)]Funds transfer failed.") else - to_chat(usr, "\icon[src]You don't have enough funds to do that!") + to_chat(user, "[html_icon(src)]You don't have enough funds to do that!") if("view_screen") view_screen = text2num(href_list["view_screen"]) if("change_security_level") @@ -272,7 +284,7 @@ if(held_card) login_card = held_card else - login_card = scan_user(usr) + login_card = scan_user(user) if(!ticks_left_locked_down) var/tried_account_num = text2num(href_list["account_num"]) @@ -290,7 +302,7 @@ if(D) account_security_level = D.security_level - authenticated_account = attempt_account_access(tried_account_num, tried_pin, held_card && login_card.associated_account_number == tried_account_num ? 2 : 1) + authenticated_account = attempt_account_access(tried_account_num, tried_pin, (login_card?.associated_account_number == tried_account_num)) if(!authenticated_account) number_incorrect_tries++ @@ -306,11 +318,11 @@ if(failed_account) failed_account.log_msg("Unauthorized login attempt", machine_id) else - to_chat(usr, "\icon[src] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.") + to_chat(user, "[html_icon(src)] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.") previous_account_number = tried_account_num playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1) else - to_chat(usr, "\icon[src] Unable to log in to account, additional information may be required.") + to_chat(user, "[html_icon(src)] Unable to log in to account, additional information may be required.") number_incorrect_tries = 0 else playsound(src, 'sound/machines/twobeep.ogg', 50, 1) @@ -320,60 +332,57 @@ //create a transaction log entry authenticated_account.log_msg("Remote terminal access", machine_id) - to_chat(usr, "\icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'") + to_chat(user, "[html_icon(src)] Access granted. Welcome user '[authenticated_account.owner_name].'") previous_account_number = tried_account_num if("e_withdrawal") var/amount = max(text2num(href_list["funds_amount"]),0) amount = round(amount, 0.01) - var/obj/item/charge_stick/E + var/obj/item/charge_stick/E = charge_stick_type if(amount <= 0) - alert("That is not a valid amount.") + alert(user, "That is not a valid amount.") else if(amount > initial(E.max_worth)) - alert("That amount exceeds the max amount holdable by basic charge sticks.") + var/decl/currency/cur = GET_DECL(initial(E.currency) || global.using_map.default_currency) + alert(user, "That amount exceeds the maximum amount holdable by charge sticks from this machine ([cur.format_value(initial(E.max_worth))]).") else if(authenticated_account && amount > 0) //create an entry in the account transaction log if(authenticated_account.withdraw(amount, "Credit withdrawal", machine_id)) playsound(src, 'sound/machines/chime.ogg', 50, 1) - E = new(loc) + E = new charge_stick_type(loc) E.adjust_worth(amount) E.creator = authenticated_account.owner_name - usr.put_in_hands(E) + user.put_in_hands(E) else - to_chat(usr, "\icon[src]You don't have enough funds to do that!") + to_chat(user, "[html_icon(src)]You don't have enough funds to do that!") if("withdrawal") var/amount = max(text2num(href_list["funds_amount"]),0) amount = round(amount, 0.01) if(amount <= 0) - alert("That is not a valid amount.") + alert(user, "That is not a valid amount.") else if(authenticated_account && amount > 0) //remove the money if(authenticated_account.withdraw(amount, "Credit withdrawal", machine_id)) playsound(src, 'sound/machines/chime.ogg', 50, 1) - var/obj/item/cash/cash = new(get_turf(usr)) - cash.adjust_worth(amount) - usr.put_in_hands(src) + var/cash_turf = get_turf(user) + var/obj/item/cash/cash = new(cash_turf, null, amount) + if(QDELETED(cash)) + cash = locate() in cash_turf + if(cash) + user.put_in_hands(cash) else - to_chat(usr, "\icon[src]You don't have enough funds to do that!") + to_chat(user, "[html_icon(src)]You don't have enough funds to do that!") if("balance_statement") if(authenticated_account) - var/obj/item/paper/R = new(src.loc) - R.SetName("Account balance: [authenticated_account.owner_name]") - R.info = "Automated Teller Account Statement

          " - R.info += "Account holder: [authenticated_account.owner_name]
          " - R.info += "Account number: [authenticated_account.account_number]
          " - R.info += "Balance: [authenticated_account.format_value_by_currency(authenticated_account.money)]
          " - R.info += "Date and time: [stationtime2text()], [stationdate2text()]

          " - R.info += "Service terminal ID: [machine_id]
          " - - //stamp the paper - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-boss" - if(!R.stamped) - R.stamped = new - R.stamped += /obj/item/stamp - R.overlays += stampoverlay - R.stamps += "
          This paper has been stamped by the Automatic Teller Machine." + var/txt + txt = "Automated Teller Account Statement

          " + txt += "Account holder: [authenticated_account.owner_name]
          " + txt += "Account number: [authenticated_account.account_number]
          " + txt += "Balance: [authenticated_account.format_value_by_currency(authenticated_account.money)]
          " + txt += "Date and time: [stationtime2text()], [stationdate2text()]

          " + txt += "Service terminal ID: [machine_id]
          " + + var/obj/item/paper/R = new(src.loc, null, txt, "Account balance: [authenticated_account.owner_name]") + R.apply_custom_stamp('icons/obj/items/stamps/stamp_boss.dmi', "by the [machine_id]") if(prob(50)) playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) @@ -381,41 +390,34 @@ playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) if ("print_transaction") if(authenticated_account) - var/obj/item/paper/R = new(src.loc) - R.SetName("Transaction logs: [authenticated_account.owner_name]") - R.info = "Transaction logs
          " - R.info += "Account holder: [authenticated_account.owner_name]
          " - R.info += "Account number: [authenticated_account.account_number]
          " - R.info += "Date and time: [stationtime2text()], [stationdate2text()]

          " - R.info += "Service terminal ID: [machine_id]
          " - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" + var/txt + + txt = "Transaction logs
          " + txt += "Account holder: [authenticated_account.owner_name]
          " + txt += "Account number: [authenticated_account.account_number]
          " + txt += "Date and time: [stationtime2text()], [stationdate2text()]

          " + txt += "Service terminal ID: [machine_id]
          " + txt += "
          DateTimeTargetPurposeValueSource terminal ID
          " + txt += "" + txt += "" + txt += "" + txt += "" + txt += "" + txt += "" + txt += "" + txt += "" for(var/datum/transaction/T in authenticated_account.transaction_log) - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "" - R.info += "
          DateTimeTargetPurposeValueSource terminal ID
          [T.date][T.time][T.get_target_name()][T.purpose][authenticated_account.format_value_by_currency(T.amount)][T.get_source_name()]
          " - - //stamp the paper - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-boss" - if(!R.stamped) - R.stamped = new - R.stamped += /obj/item/stamp - R.overlays += stampoverlay - R.stamps += "
          This paper has been stamped by the Automatic Teller Machine." + txt += "" + txt += "[T.date]" + txt += "[T.time]" + txt += "[T.get_target_name()]" + txt += "[T.purpose]" + txt += "[authenticated_account.format_value_by_currency(T.amount)]" + txt += "[T.get_source_name()]" + txt += "" + txt += "" + var/obj/item/paper/R = new(src.loc, null, txt, "Transaction logs: [authenticated_account.owner_name]") + R.apply_custom_stamp('icons/obj/items/stamps/stamp_boss.dmi', "by the [machine_id]") if(prob(50)) playsound(loc, 'sound/items/polaroid1.ogg', 50, 1) @@ -426,29 +428,29 @@ if(!held_card) //this might happen if the user had the browser window open when somebody emagged it if(emagged > 0) - to_chat(usr, "\icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!") + to_chat(user, "[html_icon(src)] The ATM card reader rejected your ID because this machine has been sabotaged!") else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/card/id)) - if(!usr.unEquip(I, src)) + var/obj/item/thing = user.get_active_held_item() + if (istype(thing, /obj/item/card/id)) + if(!user.try_unequip(thing, src)) return - held_card = I + held_card = thing else - release_held_id(usr) + release_held_id(user) if("logout") authenticated_account = null account_security_level = 0 + else + . = TOPIC_NOACTION // Unhandled, href hack or just a subtype's command? - interact(usr) - -/obj/machinery/atm/proc/scan_user(mob/living/carbon/human/human_user) +/obj/machinery/atm/proc/scan_user(mob/living/human/human_user) if(!authenticated_account) - var/obj/item/card/id/I = human_user.GetIdCard() - if(istype(I)) - return I + var/obj/item/card/id/thing = human_user.GetIdCard() + if(istype(thing)) + return thing // put the currently held id on the ground or in the hand of the user -/obj/machinery/atm/proc/release_held_id(mob/living/carbon/human/human_user) +/obj/machinery/atm/proc/release_held_id(mob/living/human/human_user) if(!held_card) return @@ -456,6 +458,6 @@ authenticated_account = null account_security_level = 0 - if(ishuman(human_user) && !human_user.get_active_hand()) + if(ishuman(human_user) && !human_user.get_active_held_item()) human_user.put_in_hands(held_card) held_card = null diff --git a/code/modules/economy/cael/Accounts.dm b/code/modules/economy/cael/Accounts.dm index 2624955e1dda..8f26b19a5f87 100644 --- a/code/modules/economy/cael/Accounts.dm +++ b/code/modules/economy/cael/Accounts.dm @@ -15,10 +15,10 @@ /datum/money_account/New(var/account_type) account_type = account_type ? account_type : ACCOUNT_TYPE_PERSONAL if(!ispath(currency, /decl/currency)) - currency = GLOB.using_map.default_currency + currency = global.using_map.default_currency /datum/money_account/proc/format_value_by_currency(var/amt) - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) . = cur.format_value(amt) // is_source inverts the amount. @@ -60,7 +60,7 @@ var/datum/transaction/singular/T = new(M, (source_db ? source_db.machine_id : "NTGalaxyNet Terminal #[rand(111,1111)]"), starting_funds, "Account creation") if(!source_db) //set a random date, time and location some time over the past few decades - T.date = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], [game_year-rand(8,18)]" + T.date = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], [global.using_map.game_year - rand(8,18)]" T.time = "[rand(0,24)]:[rand(11,59)]" M.account_number = random_id("station_account_number", 111111, 999999) @@ -69,27 +69,19 @@ next_account_number += rand(1,25) //create a sealed package containing the account details - var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(source_db.loc) - var/obj/item/paper/R = new /obj/item/paper(P) - P.wrapped = R - R.SetName("Account information: [M.account_name]") - R.info = "Account details (confidential)


          " - R.info += "Account holder: [M.owner_name]
          " - R.info += "Account number: [M.account_number]
          " - R.info += "Account pin: [M.remote_access_pin]
          " - R.info += "Starting balance: [M.format_value_by_currency(M.money)]
          " - R.info += "Date and time: [stationtime2text()], [stationdate2text()]

          " - R.info += "Creation terminal ID: [source_db.machine_id]
          " - R.info += "Authorised officer overseeing creation: [source_db.held_card.registered_name]
          " - - //stamp the paper - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-boss" - if(!R.stamped) - R.stamped = new - R.stamped += /obj/item/stamp - R.overlays += stampoverlay - R.stamps += "
          This paper has been stamped by the Accounts Database." + var/txt + txt += "Account details (confidential)


          " + txt += "Account holder: [M.owner_name]
          " + txt += "Account number: [M.account_number]
          " + txt += "Account pin: [M.remote_access_pin]
          " + txt += "Starting balance: [M.format_value_by_currency(M.money)]
          " + txt += "Date and time: [stationtime2text()], [stationdate2text()]

          " + txt += "Creation terminal ID: [source_db.machine_id]
          " + txt += "Authorised officer overseeing creation: [source_db.held_card.registered_name]
          " + + var/obj/item/paper/R = new /obj/item/paper(null, null, txt, "Account information: [M.account_name]") + R.apply_custom_stamp('icons/obj/items/stamps/stamp_boss.dmi', "by the Accounts Database") + new /obj/item/parcel(source_db.loc, null, R) //add the account T.perform() @@ -98,9 +90,9 @@ return M //this returns the first account datum that matches the supplied accnum/pin combination, it returns null if the combination did not match any account -/proc/attempt_account_access(var/attempt_account_number, var/attempt_pin_number, var/security_level_passed = 0) +/proc/attempt_account_access(var/attempt_account_number, var/attempt_pin_number, var/valid_card) var/datum/money_account/D = get_account(attempt_account_number) - if(D && D.security_level <= security_level_passed && (!D.security_level || D.remote_access_pin == attempt_pin_number) ) + if(D && (D.security_level != 2 || valid_card) && (!D.security_level || D.remote_access_pin == attempt_pin_number) ) return D /proc/get_account(var/account_number) diff --git a/code/modules/economy/cael/Accounts_DB.dm b/code/modules/economy/cael/Accounts_DB.dm index 937adbff81b1..64cea625b356 100644 --- a/code/modules/economy/cael/Accounts_DB.dm +++ b/code/modules/economy/cael/Accounts_DB.dm @@ -3,45 +3,31 @@ name = "accounts uplink terminal" desc = "Access transaction logs, account data and all kinds of other financial records." var/needed_access = list(list(access_hop, access_captain)) - var/receipt_num var/machine_id = "" var/obj/item/card/id/held_card var/datum/money_account/detailed_account_view var/creating_new_account = 0 var/const/fund_cap = 1000000 - proc/get_access_level() - if (!held_card) - return 0 - if(access_cent_captain in held_card.access) - return 2 - else if(access_hop in held_card.access || (access_captain in held_card.access)) - return 1 - - proc/accounting_letterhead(report_name) - return {" -

          [report_name]

          -
          [station_name()] Accounting Report
          -
          - Generated By: [held_card.registered_name], [held_card.assignment]
          - "} +/obj/machinery/computer/account_database/proc/accounting_letterhead(report_name) + return {" +

          [report_name]

          +
          [station_name()] Accounting Report
          +
          + Generated By: [held_card.registered_name], [held_card.assignment]
          + "} /obj/machinery/computer/account_database/Initialize() . = ..() machine_id = "[station_name()] Acc. DB #[num_financial_terminals++]" -/obj/machinery/computer/account_database/attackby(obj/O, mob/user) - if(!istype(O, /obj/item/card/id)) - return ..() - - if(!held_card) - if(!user.unEquip(O, src)) - return - held_card = O - - SSnano.update_uis(src) - - attack_hand(user) +/obj/machinery/computer/account_database/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/card/id) && !held_card) + if(user.try_unequip(used_item, src)) + held_card = used_item + SSnano.update_uis(src) + return TRUE + return ..() /obj/machinery/computer/account_database/interface_interact(mob/user) ui_interact(user) @@ -99,13 +85,12 @@ ui.set_initial_data(data) ui.open() -/obj/machinery/computer/account_database/Topic(href, href_list) - if(..()) - return 1 - - var/datum/nanoui/ui = SSnano.get_open_ui(usr, src, "main") +/obj/machinery/computer/account_database/OnTopic(mob/user, href_list) + if((. = ..())) + return if(href_list["choice"]) + . = TOPIC_REFRESH switch(href_list["choice"]) if("create_account") creating_new_account = 1 @@ -113,13 +98,13 @@ if("toggle_suspension") if(detailed_account_view) detailed_account_view.suspended = !detailed_account_view.suspended - callHook("change_account_status", list(detailed_account_view)) + RAISE_EVENT(/decl/observ/change_account_status, detailed_account_view) if("finalise_create_account") var/account_name = href_list["holder_name"] var/starting_funds = max(text2num(href_list["starting_funds"]), 0) - starting_funds = Clamp(starting_funds, 0, station_account.money) // Not authorized to put the station in debt. + starting_funds = clamp(starting_funds, 0, station_account.money) // Not authorized to put the station in debt. starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap. var/datum/money_account/new_account = create_account("[account_name]'s Personal Account", account_name, starting_funds, ACCOUNT_TYPE_PERSONAL, src) @@ -131,21 +116,20 @@ new_account.deposit(starting_funds, "New account activation", machine_id) creating_new_account = 0 - ui.close() + . = TOPIC_CLOSE creating_new_account = 0 if("insert_card") if(held_card) held_card.dropInto(loc) - if(ishuman(usr) && !usr.get_active_hand()) - usr.put_in_hands(held_card) + if(ishuman(user) && !user.get_active_held_item()) + user.put_in_hands(held_card) held_card = null - else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = user.get_active_held_item() if (istype(I, /obj/item/card/id)) - if(!usr.unEquip(I, src)) + if(!user.try_unequip(I, src)) return held_card = I @@ -162,7 +146,7 @@ var/funds = detailed_account_view.money detailed_account_view.transfer(station_account, funds, "Revocation of payroll") - callHook("revoke_payroll", list(detailed_account_view)) + RAISE_EVENT(/decl/observ/revoke_payroll, detailed_account_view) if("print") @@ -240,6 +224,6 @@ "} P.info = text - state("The terminal prints out a report.") - - return 1 + visible_message(SPAN_NOTICE("[html_icon(src)] \The [src] prints out \the [P].")) + else + . = TOPIC_NOACTION diff --git a/code/modules/economy/cael/EFTPOS.dm b/code/modules/economy/cael/EFTPOS.dm index 8760412afc35..d88132261a96 100644 --- a/code/modules/economy/cael/EFTPOS.dm +++ b/code/modules/economy/cael/EFTPOS.dm @@ -3,6 +3,8 @@ desc = "Swipe your ID card to make purchases electronically." icon = 'icons/obj/items/device/eftpos.dmi' icon_state = "eftpos" + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT) var/machine_id = "" var/eftpos_name = "Default EFTPOS scanner" var/transaction_locked = 0 @@ -20,65 +22,51 @@ print_reference() if(!ispath(currency, /decl/currency)) - currency = GLOB.using_map.default_currency + currency = global.using_map.default_currency //create a short manual as well - var/obj/item/paper/R = new(src.loc) - R.SetName("Steps to success: Correct EFTPOS Usage") //Temptative new manual: - R.info += "First EFTPOS setup:
          " - R.info += "1. Memorise your EFTPOS command code (provided with all EFTPOS devices).
          " - R.info += "2. Connect the EFTPOS to the account in which you want to receive the funds.

          " - R.info += "When starting a new transaction:
          " - R.info += "1. Enter the amount of money you want to charge and a purpose message for the new transaction.
          " - R.info += "2. Lock the new transaction. If you want to modify or cancel the transaction, you simply have to reset your EFTPOS device.
          " - R.info += "3. Give the EFTPOS device to your customer, he/she must finish the transaction by swiping their ID card or a charge card with enough funds.
          " - R.info += "4. If everything is done correctly, the money will be transferred. To unlock the device you will have to reset the EFTPOS device.
          " - - - //stamp the paper - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-boss" - if(!R.stamped) - R.stamped = new - R.offset_x += 0 - R.offset_y += 0 - R.ico += "paper_stamp-boss" - R.stamped += /obj/item/stamp - R.overlays += stampoverlay - R.stamps += "
          This paper has been stamped by the EFTPOS device." + var/txt + txt = "First EFTPOS setup:
          " + txt += "1. Memorise your EFTPOS command code (provided with all EFTPOS devices).
          " + txt += "2. Connect the EFTPOS to the account in which you want to receive the funds.

          " + txt += "When starting a new transaction:
          " + txt += "1. Enter the amount of money you want to charge and a purpose message for the new transaction.
          " + txt += "2. Lock the new transaction. If you want to modify or cancel the transaction, you simply have to reset your EFTPOS device.
          " + txt += "3. Give the EFTPOS device to your customer, he/she must finish the transaction by swiping their ID card or a charge card with enough funds.
          " + txt += "4. If everything is done correctly, the money will be transferred. To unlock the device you will have to reset the EFTPOS device.
          " + + var/obj/item/paper/R = new(src.loc, null, txt, "Steps to success: Correct EFTPOS Usage") + R.apply_custom_stamp('icons/obj/items/stamps/stamp_boss.dmi', "by \the [src]") //by default, connect to the station account //the user of the EFTPOS device can change the target account though, and no-one will be the wiser (except whoever's being charged) - linked_account = station_account + linked_account = get_default_account() + +/obj/item/eftpos/proc/get_default_account() + return global.station_account + +/obj/item/eftpos/departmental + var/decl/department/default_department + +/obj/item/eftpos/departmental/get_default_account() + return (default_department && global.department_accounts[default_department]) || ..() /obj/item/eftpos/proc/print_reference() - var/obj/item/paper/R = new(src.loc) - R.SetName("Reference: [eftpos_name]") - R.info = "[eftpos_name] reference

          " - R.info += "Access code: [access_code]

          " - R.info += "Do not lose or misplace this code.
          " - - //stamp the paper - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-boss" - if(!R.stamped) - R.stamped = new - R.stamped += /obj/item/stamp - R.overlays += stampoverlay - R.stamps += "
          This paper has been stamped by the EFTPOS device." - var/obj/item/smallDelivery/D = new(R.loc) - R.forceMove(D) - D.wrapped = R - D.SetName("small parcel - 'EFTPOS access code'") + var/obj/item/paper/R = new(src.loc, null, + "[eftpos_name] reference

          Access code: [access_code]

          Do not lose or misplace this code.
          ", + "Reference: [eftpos_name]") + R.apply_custom_stamp('icons/obj/items/stamps/stamp_boss.dmi', "by \the [src]") + var/obj/item/parcel/D = new(R.loc, null, R, "EFTPOS access code") + D.attach_label(null, null, "EFTPOS access code") /obj/item/eftpos/attack_self(mob/user) if(get_dist(src,user) <= 1) var/dat = "[eftpos_name]
          " dat += "This terminal is [machine_id]. Report this code when contacting IT Support
          " - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) if(transaction_locked) - dat += "Back[transaction_paid ? "" : " (authentication required)"]

          " + dat += "Back[transaction_paid ? "" : " (authentication required)"]

          " dat += "Transaction purpose: [transaction_purpose]
          " dat += "Value: [cur.format_value(transaction_amount)]
          " dat += "Linked account: [linked_account ? linked_account.owner_name : "None"]
          " @@ -86,31 +74,32 @@ dat += "This transaction has been processed successfully.
          " else dat += "Swipe your card below the line to finish this transaction.
          " - dat += "\[------\]" + dat += "\[------\]" else - dat += "Lock in new transaction

          " - - dat += "Transaction purpose: [transaction_purpose]
          " - dat += "Value: [cur.format_value(transaction_amount)]
          " - dat += "Linked account: [linked_account ? linked_account.owner_name : "None"]
          " - dat += "Change access code
          " - dat += "Change EFTPOS ID
          " - dat += "Scan card to reset access code \[------\]" + dat += "Lock in new transaction

          " + + dat += "Transaction purpose: [transaction_purpose]
          " + dat += "Value: [cur.format_value(transaction_amount)]
          " + dat += "Linked account: [linked_account ? linked_account.owner_name : "None"]
          " + dat += "Change access code
          " + dat += "Change EFTPOS ID
          " + dat += "Scan card to reset access code \[------\]" show_browser(user, dat, "window=eftpos") else close_browser(user, "window=eftpos") -/obj/item/eftpos/attackby(obj/item/O, user) +/obj/item/eftpos/attackby(obj/item/used_item, user) - var/obj/item/card/id/I = O.GetIdCard() + var/obj/item/card/id/I = used_item.GetIdCard() if(I) if(linked_account) - scan_card(I, O) + scan_card(I, used_item) else - to_chat(usr, "\icon[src]Unable to connect to linked account.") - else if (istype(O, /obj/item/charge_stick)) - var/obj/item/charge_stick/E = O + to_chat(user, "[html_icon(src)]Unable to connect to linked account.") + return TRUE + else if (istype(used_item, /obj/item/charge_stick)) + var/obj/item/charge_stick/E = used_item if (linked_account) if(transaction_locked && !transaction_paid) if(!E.is_locked() && transaction_amount <= E.loaded_worth) @@ -120,17 +109,17 @@ if(linked_account.deposit(transaction_amount, purpose, machine_id)) E.adjust_worth(-(transaction_amount)) playsound(src, 'sound/machines/chime.ogg', 50, 1) - visible_message("\icon[src] \The [src] chimes.") + visible_message("[html_icon(src)] \The [src] chimes.") transaction_paid = 1 else - to_chat(usr, "\icon[src]Transaction failed! Please try again.") + to_chat(user, "[html_icon(src)]Transaction failed! Please try again.") else - to_chat(usr, "\icon[src]\The [O] doesn't have that much money!") + to_chat(user, "[html_icon(src)]\The [used_item] doesn't have that much money!") else - to_chat(usr, "\icon[src]EFTPOS is not connected to an account.") - + to_chat(user, "[html_icon(src)]EFTPOS is not connected to an account.") + return TRUE else - ..() + return ..() /obj/item/eftpos/Topic(var/href, var/href_list) if(href_list["choice"]) @@ -145,24 +134,24 @@ alert("That is not a valid code!") print_reference() else - to_chat(usr, "\icon[src]Incorrect code entered.") + to_chat(usr, "[html_icon(src)]Incorrect code entered.") if("change_id") var/attempt_code = text2num(input("Re-enter the current EFTPOS access code", "Confirm EFTPOS code")) if(attempt_code == access_code) eftpos_name = sanitize(input("Enter a new terminal ID for this device", "Enter new EFTPOS ID"), MAX_NAME_LEN) + " EFTPOS scanner" print_reference() else - to_chat(usr, "\icon[src]Incorrect code entered.") + to_chat(usr, "[html_icon(src)]Incorrect code entered.") if("link_account") var/attempt_account_num = input("Enter account number to pay EFTPOS charges into", "New account number") as num var/attempt_pin = input("Enter pin code", "Account pin") as num - linked_account = attempt_account_access(attempt_account_num, attempt_pin, 1) + linked_account = attempt_account_access(attempt_account_num, attempt_pin, FALSE) if(linked_account) if(linked_account.suspended) linked_account = null - to_chat(usr, "\icon[src]Account has been suspended.") + to_chat(usr, "[html_icon(src)]Account has been suspended.") else - to_chat(usr, "\icon[src]Account not found.") + to_chat(usr, "[html_icon(src)]Account not found.") if("trans_purpose") var/choice = sanitize(input("Enter reason for EFTPOS transaction", "Transaction purpose")) if(choice) transaction_purpose = choice @@ -185,25 +174,25 @@ else if(linked_account) transaction_locked = 1 else - to_chat(usr, "\icon[src]No account connected to send transactions to.") + to_chat(usr, "[html_icon(src)]No account connected to send transactions to.") if("scan_card") if(linked_account) - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/card)) scan_card(I) else - to_chat(usr, "\icon[src]Unable to link accounts.") + to_chat(usr, "[html_icon(src)]Unable to link accounts.") if("reset") //reset the access code - requires HoP/captain access - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/card)) var/obj/item/card/id/C = I if((access_cent_captain in C.access) || (access_hop in C.access) || (access_captain in C.access)) access_code = 0 - to_chat(usr, "\icon[src]Access code reset to 0.") + to_chat(usr, "[html_icon(src)]Access code reset to 0.") else if (istype(I, /obj/item/card/emag)) access_code = 0 - to_chat(usr, "\icon[src]Access code reset to 0.") + to_chat(usr, "[html_icon(src)]Access code reset to 0.") src.attack_self(usr) @@ -222,31 +211,31 @@ if(D && D.security_level) attempt_pin = input("Enter pin code", "EFTPOS transaction") as num D = null - D = attempt_account_access(C.associated_account_number, attempt_pin, 2) + D = attempt_account_access(C.associated_account_number, attempt_pin, TRUE) if(D) //transfer the money if(D.transfer(linked_account, transaction_amount, "[transaction_purpose] (via [eftpos_name]/[machine_id])")) playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("\icon[src] \The [src] chimes.") + src.visible_message("[html_icon(src)] \The [src] chimes.") transaction_paid = 1 else - to_chat(usr, "\icon[src]Transaction failed! Please try again.") + to_chat(usr, "[html_icon(src)]Transaction failed! Please try again.") else - to_chat(usr, "\icon[src]Unable to access account. Check security settings and try again.") + to_chat(usr, "[html_icon(src)]Unable to access account. Check security settings and try again.") else - to_chat(usr, "\icon[src]Connected account has been suspended.") + to_chat(usr, "[html_icon(src)]Connected account has been suspended.") else - to_chat(usr, "\icon[src]EFTPOS is not connected to an account.") + to_chat(usr, "[html_icon(src)]EFTPOS is not connected to an account.") else if (istype(I, /obj/item/card/emag)) if(transaction_locked) if(transaction_paid) - to_chat(usr, "\icon[src]You stealthily swipe \the [I] through \the [src].") + to_chat(usr, "[html_icon(src)]You stealthily swipe \the [I] through \the [src].") transaction_locked = 0 transaction_paid = 0 else usr.visible_message("\The [usr] swipes a card through \the [src].") playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("\icon[src] \The [src] chimes.") + src.visible_message("[html_icon(src)] \The [src] chimes.") transaction_paid = 1 //emag? diff --git a/code/modules/economy/worth_cash.dm b/code/modules/economy/worth_cash.dm index 77cfcaac87a8..49d04f24ebdf 100644 --- a/code/modules/economy/worth_cash.dm +++ b/code/modules/economy/worth_cash.dm @@ -6,25 +6,43 @@ opacity = FALSE density = FALSE anchored = FALSE - force = 1 - throwforce = 1 throw_speed = 1 throw_range = 2 w_class = ITEM_SIZE_TINY + material = /decl/material/solid/organic/plastic var/currency var/absolute_worth = 0 var/can_flip = TRUE // Cooldown tracker for single-coin flips. + var/static/overlay_cap = 50 // Max overlays to show in this pile. + +/obj/item/cash/Initialize(ml, material_key, starting_amount) + + if(!isnull(starting_amount)) + absolute_worth = starting_amount -/obj/item/cash/Initialize(ml, material_key) . = ..() - appearance_flags |= PIXEL_SCALE + if(!ispath(currency, /decl/currency)) - currency = GLOB.using_map.default_currency + currency = global.using_map.default_currency + + if(!ispath(currency, /decl/currency)) + return INITIALIZE_HINT_QDEL + + if(isturf(loc)) + for(var/obj/item/cash/other in loc) + if(other == src) + continue + if(other.currency != currency) + continue + other.absolute_worth += absolute_worth + other.update_from_worth() + return INITIALIZE_HINT_QDEL + if(absolute_worth > 0) update_from_worth() /obj/item/cash/get_base_value() - . = holographic ? 0 : absolute_worth + . = holographic ? 0 : absolute_worth /obj/item/cash/proc/set_currency(var/new_currency) currency = new_currency @@ -38,31 +56,34 @@ update_from_worth() /obj/item/cash/proc/get_worth() - var/decl/currency/cur = decls_repository.get_decl(currency) - . = Floor(absolute_worth / cur.absolute_value) + var/decl/currency/cur = GET_DECL(currency) + . = floor(absolute_worth / cur.absolute_value) -/obj/item/cash/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/cash)) - var/obj/item/cash/cash = W +/obj/item/cash/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/cash)) + var/obj/item/cash/cash = used_item if(cash.currency != currency) to_chat(user, SPAN_WARNING("You can't mix two different currencies, it would be uncivilized.")) - return - if(user.unEquip(W)) + return TRUE + if(user.try_unequip(used_item)) adjust_worth(cash.absolute_worth) - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) to_chat(user, SPAN_NOTICE("You add [cash.get_worth()] [cur.name] to the pile.")) to_chat(user, SPAN_NOTICE("It holds [get_worth()] [cur.name] now.")) - qdel(W) + qdel(used_item) return TRUE - else if(istype(W, /obj/item/gun/launcher/money)) - var/obj/item/gun/launcher/money/L = W + else if(istype(used_item, /obj/item/gun/launcher/money)) + var/obj/item/gun/launcher/money/L = used_item L.absorb_cash(src, user) + return TRUE + return ..() /obj/item/cash/on_update_icon() + . = ..() icon_state = "" var/draw_worth = get_worth() - var/list/adding_notes - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) + var/i = 0 for(var/datum/denomination/denomination in cur.denominations) while(draw_worth >= denomination.marked_value) draw_worth -= denomination.marked_value @@ -75,11 +96,13 @@ if(denomination.rotate_icon) M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45)) banknote.transform = M - LAZYADD(adding_notes, banknote) - overlays = adding_notes + add_overlay(banknote) + i++ + if(i >= overlay_cap) + return /obj/item/cash/proc/update_from_worth() - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) matter = list() matter[cur.material] = absolute_worth * max(1, round(SHEET_MATERIAL_AMOUNT/10)) var/current_worth = get_worth() @@ -96,12 +119,12 @@ /obj/item/cash/attack_self(var/mob/user) - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) var/current_worth = get_worth() // Handle coin flipping. Mostly copied from /obj/item/coin. var/datum/denomination/denomination = cur.denominations_by_value["[current_worth]"] - if(denomination && length(denomination.faces) && alert("Do you wish to divide \the [src], or flip it?", "Flip or Split?", "Flip", "Split") == "Flip") + if(denomination && length(denomination.faces) && (cur.denominations_by_value[length(cur.denominations_by_value)] == "[current_worth]" || alert("Do you wish to divide \the [src], or flip it?", "Flip or Split?", "Flip", "Split") == "Flip")) if(!can_flip) to_chat(user, SPAN_WARNING("\The [src] is already being flipped!")) return @@ -118,13 +141,13 @@ if(QDELETED(src) || get_worth() <= 1 || user.incapacitated() || loc != user) return TRUE - var/amount = input(usr, "How many [cur.name] do you want to take? (0 to [get_worth() - 1])", "Take Money", 20) as num - amount = round(Clamp(amount, 0, Floor(get_worth() - 1))) + var/amount = input(user, "How many [cur.name] do you want to take? (0 to [get_worth() - 1])", "Take Money", 20) as num + amount = round(clamp(amount, 0, floor(get_worth() - 1))) if(!amount || QDELETED(src) || get_worth() <= 1 || user.incapacitated() || loc != user) return TRUE - amount = Floor(amount * cur.absolute_value) + amount = floor(amount * cur.absolute_value) adjust_worth(-(amount)) var/obj/item/cash/cash = new(get_turf(src)) cash.set_currency(currency) @@ -148,6 +171,7 @@ /obj/item/cash/c200 absolute_worth = 200 + w_class = ITEM_SIZE_SMALL // so that the money freezer doesn't overflow bc this is a pile instead of single bill /obj/item/cash/c500 absolute_worth = 500 @@ -167,9 +191,11 @@ /obj/item/charge_stick name = "charge-stick" icon = 'icons/obj/items/credstick.dmi' - icon_state = "peasant" + icon_state = ICON_STATE_WORLD desc = "A digital stick that holds an amount of money." - + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE, /decl/material/solid/silicon = MATTER_AMOUNT_TRACE) var/max_worth = 5000 var/loaded_worth = 0 var/creator // Who originally created this card. Mostly for book-keeping purposes. In game these cards are 'anonymous'. @@ -181,16 +207,20 @@ /obj/item/charge_stick/Initialize(ml, material_key) . = ..() id = "[grade]-card-[sequential_id("charge_stick")]" - appearance_flags |= PIXEL_SCALE if(!ispath(currency, /decl/currency)) - currency = GLOB.using_map.default_currency + currency = global.using_map.default_currency update_name_desc() set_extension(src, lock_type) + + if(grade && grade != "peasant") + var/image/I = image(icon, "[icon_state]-[grade]") + I.appearance_flags |= RESET_COLOR + add_overlay(I, TRUE) update_icon() /obj/item/charge_stick/proc/update_name_desc() if(!isnull(currency)) - var/decl/currency/cur = decls_repository.get_decl(currency) + var/decl/currency/cur = GET_DECL(currency) name = "[cur.name]-stick" desc = "A pre-charged digital stick that anonymously holds an amount of [cur.name]." return @@ -201,51 +231,52 @@ loaded_worth += amt if(loaded_worth < 0) loaded_worth = 0 + update_icon() -/obj/item/charge_stick/examine(mob/user, distance) +/obj/item/charge_stick/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) if(distance <= 2 || user == loc) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) if(lock.locked) - to_chat(user, SPAN_WARNING("\The [src] is locked.")) + . += SPAN_WARNING("\The [src] is locked.") else - to_chat(user, SPAN_NOTICE("Id: [id].")) - var/decl/currency/cur = decls_repository.get_decl(currency) - to_chat(user, SPAN_NOTICE("[capitalize(cur.name)] remaining: [Floor(loaded_worth / cur.absolute_value)].")) + var/decl/currency/cur = GET_DECL(currency) + . += SPAN_NOTICE("Id: [id].") + . += SPAN_NOTICE("[capitalize(cur.name)] remaining: [floor(loaded_worth / cur.absolute_value)].") /obj/item/charge_stick/get_base_value() . = holographic ? 0 : loaded_worth -/obj/item/charge_stick/attackby(var/obj/item/W, var/mob/user) +/obj/item/charge_stick/attackby(var/obj/item/used_item, var/mob/user) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - if(istype(W, /obj/item/charge_stick)) - var/obj/item/charge_stick/sender = W - var/datum/extension/lockable/W_lock = get_extension(W, /datum/extension/lockable) + if(istype(used_item, /obj/item/charge_stick)) + var/obj/item/charge_stick/sender = used_item + var/datum/extension/lockable/W_lock = get_extension(used_item, /datum/extension/lockable) if(lock.locked) to_chat(user, SPAN_WARNING("Cannot transfer funds to a locked [src].")) return TRUE if(W_lock.locked) - to_chat(user, SPAN_WARNING("Cannot transfer funds from a locked [W].")) + to_chat(user, SPAN_WARNING("Cannot transfer funds from a locked [used_item].")) return TRUE if(sender.currency != currency) - to_chat(user, SPAN_WARNING("\icon[src] [src] chirps, \"Mismatched currency detected. Unable to transfer.\"")) + to_chat(user, SPAN_WARNING("[html_icon(src)] [src] chirps, \"Mismatched currency detected. Unable to transfer.\"")) return TRUE var/amount = input(user, "How much of [sender.loaded_worth] do you want to transfer?", "[sender] transfer", "0") as null|num if(!amount) return TRUE if(amount < 0 || amount > sender.loaded_worth) - to_chat(user, SPAN_NOTICE("\icon[src] [src] chirps, \"Enter a valid number between 1 and [sender.loaded_worth] to transfer.\"")) + to_chat(user, SPAN_NOTICE("[html_icon(src)] [src] chirps, \"Enter a valid number between 1 and [sender.loaded_worth] to transfer.\"")) return TRUE sender.loaded_worth -= amount loaded_worth += amount sender.update_icon() update_icon() - var/decl/currency/cur = decls_repository.get_decl(currency) - to_chat(user, SPAN_NOTICE("\icon[src] [src] chirps, \"Completed transfer of [amount] [cur.name].\"")) + var/decl/currency/cur = GET_DECL(currency) + to_chat(user, SPAN_NOTICE("[html_icon(src)] [src] chirps, \"Completed transfer of [amount] [cur.name].\"")) return TRUE - - if(lock.attackby(W, user)) + + if(lock.attackby(used_item, user)) return TRUE return ..() @@ -257,35 +288,73 @@ /obj/item/charge_stick/attack_self(var/mob/user) var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) - lock.ui_interact(user) + lock.ui_interact(user) /obj/item/charge_stick/proc/is_locked() var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) return lock.locked +/** + Given a number, returns a representation fit for a 3-digit display. + + Assumes that besides the digits themselves, display provides + decimal point on the highest digit, plus (for overflow) and minus signs. + Returns lists indexed by (power of ten)+1, that is, with [1] showing ones, + [2] tens, [3] hundreds. + Valid values are `-99` to `99`, with `++` and `---` for over and underflow, + where is the maximal provided decimal postfix (k, M, B, T, etc). +*/ +/proc/number_to_3digits(value, var/list/postfixes = list("k", "M")) + var/list/digits[3] + var/lim = 1000 + if (value < 0) // negatives + digits[3] = "-" + value *= -1 + lim = 100 + else + for(var/s in postfixes) + if (value < lim) + break + value /= 1000 + digits[1] = s + lim = 100 + if (value >= lim) // over/underflow + if (!digits[3]) + digits[3] = "+" + if (!digits[1]) + digits[1] = digits[3] + digits[2] = digits[3] + else + if ((lim == 100) && !digits[3]) // suffix on + if (value < 1) // . + digits[3] = "." + value *= 100 // .X => 0X0 + else // just suffix + value *= 10 // XX => XX0 + if (!digits[1]) + digits[1] = value % 10 + digits[2] = (value / 10) % 10 + if (!digits[3]) + digits[3] = (value / 100) % 10 + return digits + /obj/item/charge_stick/on_update_icon() . = ..() + if(get_world_inventory_state() == ICON_STATE_WORLD) - icon_state = ICON_STATE_WORLD - return + return - icon_state = grade var/datum/extension/lockable/lock = get_extension(src, /datum/extension/lockable) if(lock.locked) return - if(loaded_worth > 999999) - overlays += image(icon, "9__") - overlays += image(icon, "_9_") - overlays += image(icon, "__9") - return + var/decl/currency/cur = GET_DECL(currency) + var/displayed_worth = loaded_worth / cur.absolute_value // Denominated in stick currency + var/list/digits = number_to_3digits(displayed_worth) + add_overlay("__[digits[1]]") + add_overlay("_[digits[2]]_") + add_overlay("[digits[3]]__") - var/h_thou = loaded_worth / 100000 - var/t_thou = (loaded_worth - (Floor(h_thou) * 100000)) / 10000 - var/thou = (loaded_worth - (Floor(h_thou) * 100000) - (Floor(t_thou) * 10000)) / 1000 - overlays += image(icon, "[Floor(h_thou)]__") - overlays += image(icon, "_[Floor(t_thou)]_") - overlays += image(icon, "__[Floor(thou)]") /obj/item/charge_stick/copper grade = "copper" @@ -309,9 +378,6 @@ /atom/movable/proc/GetChargeStick() return null - + /obj/item/charge_stick/GetChargeStick() return src - -/obj/item/coin/get_base_value() - . = max((holographic ? 0 : absolute_worth), ..()) diff --git a/code/modules/economy/worth_clothing.dm b/code/modules/economy/worth_clothing.dm index ae3150098aa1..bf1a039887bf 100644 --- a/code/modules/economy/worth_clothing.dm +++ b/code/modules/economy/worth_clothing.dm @@ -1,10 +1,7 @@ /obj/item/clothing/get_base_value() - . = 10 + . = max(..(), 10) + if(!holographic && flash_protection > 0) + . += flash_protection * 25 /obj/item/clothing/head/collectable/get_value_multiplier() . = 5 - -/obj/item/clothing/get_base_value() - . = ..() - if(!holographic && flash_protection > 0) - . += flash_protection * 25 diff --git a/code/modules/economy/worth_currency.dm b/code/modules/economy/worth_currency.dm index 4e373335157b..9e5de940b128 100644 --- a/code/modules/economy/worth_currency.dm +++ b/code/modules/economy/worth_currency.dm @@ -6,15 +6,17 @@ var/marked_value var/image/overlay var/rotate_icon = TRUE + var/decl/currency/currency -/datum/denomination/New(var/decl/currency/currency, var/value, var/value_name, var/colour = COLOR_PALE_BTL_GREEN) +/datum/denomination/New(var/decl/currency/_currency, var/value, var/value_name, var/colour = COLOR_PALE_BTL_GREEN) ..() + currency = _currency name = "[value_name] [currency.name_singular] [name || "piece"]" state = state || "cash" marked_value = value - overlay = image(currency, state) + overlay = image(currency.icon, state) overlay.color = colour - overlay.appearance_flags |= RESET_COLOR | PIXEL_SCALE + overlay.appearance_flags |= RESET_COLOR overlay.plane = FLOAT_PLANE overlay.layer = FLOAT_LAYER if(mark) @@ -43,26 +45,67 @@ var/name_prefix var/name_suffix var/icon = 'icons/obj/items/money.dmi' - var/material = /decl/material/solid/plastic + var/material = /decl/material/solid/organic/plastic var/absolute_value = 1 // Divisor for cash pile worth. Should never be <1 or non-integer (think of it like cents). var/list/denominations = list() var/list/denominations_by_value = list() + abstract_type = /decl/currency -/decl/currency/New() +/decl/currency/Initialize() + . = ..() if(!name_singular) name_singular = name if(!name_prefix && !name_suffix) name_suffix = uppertext(copytext(name, 1, 1)) build_denominations() - ..() + +/decl/currency/validate() + . = ..() + if(absolute_value < 1) + . += "Absolute currency value is less than 1." + if(!name) + . += "No name set." + if(!name_prefix && !name_suffix) + . += "No name modifiers set." + if(!name_singular) + . += "No singular name set." + + var/list/coinage_states = get_states_in_icon_cached(icon) // cache this to avoid excessive ref() usage + for(var/datum/denomination/denomination in denominations) + if(!istext(denomination.name)) + . += "Non-text name found for '[denomination.type]'." + else if(!(denomination.state in coinage_states)) + . += "State '[denomination.state]' not found in icon file for '[denomination.type]'." + else if(denomination.mark && !coinage_states[denomination.mark]) + . += "Mark state '[denomination.mark]' not found in icon file for '[denomination.type]'." + else if(!isnum(denomination.marked_value)) + . += "Non-numerical denomination marked value found for '[denomination]'." + else if(!denomination.overlay) + . += "Null overlay found for '[denomination]'." + + // Get all coin denominations. + var/list/validating_denominations = denominations?.Copy() + for(var/datum/denomination/denomination in validating_denominations) + if(!denomination.faces) + validating_denominations -= denomination + + // Remove all coin recipes that create our denomination. + var/list/all_coin_recipes = decls_repository.get_decls_of_type(/decl/stack_recipe/coin) + for(var/recipe_type in all_coin_recipes) + var/decl/stack_recipe/coin/recipe = all_coin_recipes[recipe_type] + validating_denominations -= recipe.denomination + + // If any are left, someone has forgotten a denomination. + if(length(validating_denominations)) + . += "missing coin crafting recipes: [english_list(validating_denominations)]" /decl/currency/proc/format_value(var/amt) - . = "[name_prefix][Floor(amt / absolute_value)][name_suffix]" + . = "[name_prefix][floor(amt / absolute_value)][name_suffix]" /decl/currency/proc/build_denominations() + denominations = sortTim(denominations, /proc/cmp_currency_denomination_des) for(var/datum/denomination/denomination in denominations) denominations_by_value["[denomination.marked_value]"] = denomination - sortTim(denominations, /proc/cmp_currency_denomination_des) /decl/currency/credits name = "credits" @@ -83,6 +126,13 @@ ) ..() +/decl/stack_recipe/coin/credits + name = "two credit coin" + currency = /decl/currency/credits + +/decl/stack_recipe/coin/credits/one + name = "one credit coin" + /datum/denomination/coin/mid state = "coin_medium" @@ -90,7 +140,7 @@ state = "coin_large" /decl/currency/trader - name = "scrip" + name = "scrip" name_prefix = "$" material = /decl/material/solid/metal/copper @@ -102,6 +152,16 @@ ) ..() +/decl/stack_recipe/coin/trader + currency = /decl/currency/trader + name = "ten scrip coin" + +/decl/stack_recipe/coin/trader/mid + name = "five scrip coin" + +/decl/stack_recipe/coin/trader/small + name = "one scrip coin" + /decl/currency/scav name = "scavbucks" name_singular = "scavbuck" diff --git a/code/modules/economy/worth_guns.dm b/code/modules/economy/worth_guns.dm index 369a34a57107..a8372ce8a0df 100644 --- a/code/modules/economy/worth_guns.dm +++ b/code/modules/economy/worth_guns.dm @@ -1,31 +1,50 @@ -// Can't think of a good way to get gun price from projectile (due to +// Can't think of a good way to get gun price from projectile (due to // firemodes, projectile types, etc) so this'll have to do for now. /obj/item/gun/get_base_value() . = 100 + if(silencer) + . += 20 -/obj/item/gun/energy/get_base_value() - . = 150 + var/static/list/vars_to_value = list( + "one_hand_penalty" = -2, + "bulk" = -5, + "accuracy" = 10, + "scoped_accuracy" = 5 + ) -/obj/item/gun/get_base_value() - . = 0 - if(silenced) - . += 20 - . += one_hand_penalty * -2 - . += bulk * -5 - . += accuracy * 10 - . += scoped_accuracy * 5 - if(!can_autofire) + var/list/max_vars_to_value = list( + "one_hand_penalty" = one_hand_penalty, + "bulk" = bulk, + "accuracy" = accuracy, + "scoped_accuracy" = scoped_accuracy + ) + + for(var/datum/firemode/F in firemodes) + for(var/varname in vars_to_value) + if(varname in F.settings) + max_vars_to_value[varname] = max(max_vars_to_value[varname], F.settings[varname]) + + for(var/varname in max_vars_to_value) + . += max_vars_to_value[varname] * vars_to_value[varname] + + var/has_autofire = autofire_enabled + if(!has_autofire) for(var/datum/firemode/F in firemodes) - if(F.settings["can_autofire"]) - . += 100 + if(F.settings["autofire_enabled"]) + has_autofire = TRUE + break + if(has_autofire) + . += 100 + . *= 10 - . += ..() /obj/item/gun/energy/get_base_value() - . = ..() + . = 150 if(self_recharge) . += 100 - var/projectile_value = atom_info_repository.get_combined_worth_for(projectile_type) + var/projectile_value = 1 + if(projectile_type) + projectile_value = atom_info_repository.get_combined_worth_for(projectile_type) for(var/datum/firemode/F in firemodes) if(F.settings["projectile_type"]) projectile_value = max(projectile_value, atom_info_repository.get_combined_worth_for(F.settings["projectile_type"])) @@ -34,11 +53,12 @@ /obj/item/gun/projectile/get_base_value() . = ..() if(load_method & (SINGLE_CASING|SPEEDLOADER)) - var/projectile_value = atom_info_repository.get_combined_worth_for(ammo_type) + var/projectile_value = ammo_type ? atom_info_repository.get_combined_worth_for(ammo_type) : 1 . += 0.5 * projectile_value * max_shells else if(load_method & MAGAZINE) if(auto_eject) . += 20 var/obj/item/ammo_magazine/mag = magazine_type - var/projectile_value = atom_info_repository.get_combined_worth_for(initial(mag.ammo_type)) - . += 0.5 * projectile_value * initial(mag.max_ammo) \ No newline at end of file + var/mag_type = initial(mag.ammo_type) + var/projectile_value = mag_type ? atom_info_repository.get_combined_worth_for(mag_type) : 1 + . += 0.5 * projectile_value * initial(mag.max_ammo) diff --git a/code/modules/economy/worth_items.dm b/code/modules/economy/worth_items.dm index 77da95ba7ebf..15998a7521f9 100644 --- a/code/modules/economy/worth_items.dm +++ b/code/modules/economy/worth_items.dm @@ -2,9 +2,6 @@ #define MUNDANE_ARMOUR_VALUE 20 #define BASE_ARMOUR_WORTH 50 -/obj/item/proc/get_max_weapon_value() - return force - /obj/item/get_base_value() if(holographic) @@ -16,24 +13,32 @@ var/largest_tech_val = 0 var/list/tech = cached_json_decode(origin_tech) for(var/t in tech) - var/next_tech_val = (tech[t]**2) * 5 + if(tech[t] <= 1) + continue + var/next_tech_val = ((tech[t] - 1)**2) * 5 if(next_tech_val > largest_tech_val) largest_tech_val = next_tech_val - . += largest_tech_val + . += largest_tech_val - if(force) - var/weapon_value = ((get_max_weapon_value() * 25) * (1 + max(sharp, edge))) + if((item_flags & ITEM_FLAG_IS_WEAPON) && get_base_attack_force()) + var/weapon_value = ((get_max_weapon_force() * 15) * (1 + max(sharp, edge))) if(attack_cooldown <= FAST_WEAPON_COOLDOWN) - weapon_value *= 0.5 - else if(attack_cooldown >= SLOW_WEAPON_COOLDOWN) weapon_value *= 1.5 + else if(attack_cooldown >= SLOW_WEAPON_COOLDOWN) + weapon_value *= 0.5 . += round(weapon_value) . += (base_parry_chance * 5) . += melee_accuracy_bonus * 2 var/total_coverage = get_percentage_body_cover(body_parts_covered) - var/cold_value = (5 * (-(min_cold_protection_temperature)/T20C) * get_percentage_body_cover(cold_protection)) - var/heat_value = (5 * (max_heat_protection_temperature/T20C) * get_percentage_body_cover(heat_protection)) + var/cold_value = 0 + if(!isnull(min_cold_protection_temperature) && cold_protection) + // Adds 5cr for every 20 degrees of protection below 20C at full coverage + cold_value = (5 * (T20C - min_cold_protection_temperature)/20 * get_percentage_body_cover(cold_protection)) + var/heat_value = 0 + if(!isnull(max_heat_protection_temperature) && heat_protection) + // Adds 5cr for every 20 degrees of protection over 20C at full coverage + heat_value = (5 * (max_heat_protection_temperature - T20C)/20 * get_percentage_body_cover(heat_protection)) var/additional_value = cold_value + heat_value if(total_coverage > 0) @@ -41,7 +46,7 @@ var/shock_protection = ((1-siemens_coefficient) * 20) * total_coverage var/gas_leak_value = ((1-gas_transfer_coefficient) * 20) * total_coverage var/permeability_value = ((1-permeability_coefficient) * 20) * total_coverage - var/pressure_protection = Floor(abs(max_pressure_protection - min_pressure_protection)/ONE_ATMOSPHERE) + var/pressure_protection = floor(abs(max_pressure_protection - min_pressure_protection)/ONE_ATMOSPHERE) additional_value += shock_protection + gas_leak_value + permeability_value + pressure_protection @@ -61,7 +66,7 @@ additional_value += (25 * total_coverage) if(item_flags) - for(var/flag in list(ITEM_FLAG_PADDED, ITEM_FLAG_NOSLIP, ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT, ITEM_FLAG_SILENT, ITEM_FLAG_NOCUFFS)) + for(var/flag in list(ITEM_FLAG_PADDED, ITEM_FLAG_NOSLIP, ITEM_FLAG_MAGNETISED, ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT, ITEM_FLAG_SILENT, ITEM_FLAG_NOCUFFS)) if(item_flags & flag) additional_value += 15 @@ -69,3 +74,8 @@ #undef MUNDANE_ARMOUR_VALUE #undef BASE_ARMOUR_WORTH + +/obj/item/organ/get_single_monetary_worth() + . = ..() + if(species) + . = round(. * species.rarity_value) diff --git a/code/modules/economy/worth_machines.dm b/code/modules/economy/worth_machines.dm index 8ab4732e6c9d..1b0b5af5671e 100644 --- a/code/modules/economy/worth_machines.dm +++ b/code/modules/economy/worth_machines.dm @@ -2,3 +2,8 @@ . = ..() if(stat & BROKEN) . = round(. * 0.5) + +/obj/machinery/get_single_monetary_worth() + . = ..() + for(var/atom/movable/component in component_parts) + . += component.get_combined_monetary_worth() diff --git a/code/modules/economy/worth_misc.dm b/code/modules/economy/worth_misc.dm index ca23a2fd3254..b003eb009c99 100644 --- a/code/modules/economy/worth_misc.dm +++ b/code/modules/economy/worth_misc.dm @@ -1,20 +1,8 @@ -/obj/item/disk/survey/get_base_value() - . = holographic ? 0 : (sqrt(data) * 5) - -/obj/item/slime_extract/get_base_value() - . = ..() * Uses - -/obj/machinery/power/supermatter/get_value_multiplier() - . = 1 - // Arbitrary values (TODO remove as many of these as possible) #define ARBITRARY_WORTH(PATH, AMT) \ PATH/get_value_multiplier() { . = 1 } \ PATH/get_base_value() { . = AMT } -ARBITRARY_WORTH(/obj/machinery/power/supermatter, 2000) -ARBITRARY_WORTH(/obj/machinery/power/emitter, 700) -ARBITRARY_WORTH(/obj/machinery/the_singularitygen, 700) -ARBITRARY_WORTH(/obj/structure/ship_munition, 500) -ARBITRARY_WORTH(/obj/machinery/power/rad_collector, 500) -ARBITRARY_WORTH(/obj/structure/particle_accelerator, 500) \ No newline at end of file +ARBITRARY_WORTH(/obj/machinery/emitter, 700) +ARBITRARY_WORTH(/obj/machinery/rad_collector, 500) +ARBITRARY_WORTH(/obj/structure/particle_accelerator, 500) diff --git a/code/modules/economy/worth_mob.dm b/code/modules/economy/worth_mob.dm index 45ba6023d812..7102d7c68094 100644 --- a/code/modules/economy/worth_mob.dm +++ b/code/modules/economy/worth_mob.dm @@ -1,22 +1,18 @@ -/mob/get_base_value() +/mob/get_single_monetary_worth() . = 0.5 * mob_size if(stat != DEAD) . *= 1.5 . = max(round(.), mob_size) -/mob/living/carbon/human/get_base_value() - . = round(..() * species.rarity_value) - -/mob/living/get_base_value() +/mob/living/get_single_monetary_worth() . = ..() - if(meat_type) - . += atom_info_repository.get_combined_worth_for(meat_type) * meat_amount - if(skin_material) - var/decl/material/M = decls_repository.get_decl(skin_material) - . += skin_amount * M.value * 10 - if(bone_material) - var/decl/material/M = decls_repository.get_decl(bone_material) - . += bone_amount * M.value * 10 - if(skull_type) - .+= atom_info_repository.get_combined_worth_for(skull_type) + for(var/atom/movable/organ in get_organs()) + . += organ.get_combined_monetary_worth() + if(butchery_data) + var/decl/butchery_data/butchery_decl = GET_DECL(butchery_data) + . += butchery_decl.get_monetary_worth(src) . = round(.) + +/mob/living/get_value_multiplier() + var/decl/species/my_species = get_species() + . = my_species ? my_species.rarity_value : 1 diff --git a/code/modules/economy/worth_obj.dm b/code/modules/economy/worth_obj.dm index 642da19770a0..04b75a13fed0 100644 --- a/code/modules/economy/worth_obj.dm +++ b/code/modules/economy/worth_obj.dm @@ -5,9 +5,9 @@ total_matter += matter[mat] var/mat_value_mult = 0 for(var/mat in matter) - var/decl/material/mat_datum = decls_repository.get_decl(mat) + var/decl/material/mat_datum = GET_DECL(mat) mat_value_mult += mat_datum.value * (matter[mat] / total_matter) - . = mat_value_mult * (total_matter / SHEET_MATERIAL_AMOUNT) + . = mat_value_mult * MATERIAL_WORTH_MULTIPLIER else . = ..() @@ -24,7 +24,7 @@ . = 0 for(var/mat in matter) . += matter[mat] - . = Floor(. / SHEET_MATERIAL_AMOUNT) + . = floor(. * REAGENT_UNITS_PER_MATERIAL_UNIT) else - . = Clamp(w_class, ITEM_SIZE_MIN, ITEM_SIZE_MAX) + . = clamp(w_class, ITEM_SIZE_MIN, ITEM_SIZE_MAX) . = max(1, round(.)) \ No newline at end of file diff --git a/code/modules/economy/worth_vendomat.dm b/code/modules/economy/worth_vendomat.dm index 62eb39dd2c00..224532de14c6 100644 --- a/code/modules/economy/worth_vendomat.dm +++ b/code/modules/economy/worth_vendomat.dm @@ -2,7 +2,18 @@ . = ..() var/stored_goods_worth = 0 for(var/datum/stored_items/vending_products/product in product_records) - stored_goods_worth += product.price * product.amount - if(markup) - stored_goods_worth = round(stored_goods_worth/markup) - . += stored_goods_worth \ No newline at end of file + // instances will be counted by parent call as they are in the vendor contents + var/product_count = product.amount - length(product.instances) + if(product_count > 0) + stored_goods_worth += atom_info_repository.get_combined_worth_for(product.item_path) * product_count + . += round(stored_goods_worth) + +/obj/structure/vending_refill/get_combined_monetary_worth() + . = ..() + var/stored_goods_worth = 0 + for(var/datum/stored_items/vending_products/product in product_records) + // instances will be counted by parent call as they are in the vendor contents + var/product_count = product.amount - length(product.instances) + if(product_count > 0) + stored_goods_worth += atom_info_repository.get_combined_worth_for(product.item_path) * product_count + . += round(stored_goods_worth) diff --git a/code/modules/emotes/definitions/_mob.dm b/code/modules/emotes/definitions/_mob.dm index 22340d3f15a1..9be41c73a8e6 100644 --- a/code/modules/emotes/definitions/_mob.dm +++ b/code/modules/emotes/definitions/_mob.dm @@ -1,184 +1,11 @@ -/mob - var/list/default_emotes = list() - var/list/usable_emotes = list() +/mob/proc/get_default_emotes() + return -/mob/proc/update_emotes(var/skip_sort) - usable_emotes.Cut() - for(var/emote in default_emotes) - var/decl/emote/emote_datum = decls_repository.get_decl(emote) - if(emote_datum.check_user(src)) - usable_emotes[emote_datum.key] = emote_datum - if(!skip_sort) - usable_emotes = sortAssoc(usable_emotes) - -/mob/Initialize() +/mob/living/get_default_emotes() . = ..() - update_emotes() - -// Specific defines follow. -/mob/living/carbon/alien - default_emotes = list( - /decl/emote/visible, - /decl/emote/visible/scratch, - /decl/emote/visible/drool, - /decl/emote/visible/nod, - /decl/emote/visible/sway, - /decl/emote/visible/sulk, - /decl/emote/visible/twitch, - /decl/emote/visible/dance, - /decl/emote/visible/roll, - /decl/emote/visible/shake, - /decl/emote/visible/jump, - /decl/emote/visible/shiver, - /decl/emote/visible/collapse, - /decl/emote/audible/hiss, - /decl/emote/audible, - /decl/emote/audible/deathgasp_alien, - /decl/emote/audible/whimper, - /decl/emote/audible/gasp, - /decl/emote/audible/scretch, - /decl/emote/audible/choke, - /decl/emote/audible/moan, - /decl/emote/audible/gnarl - ) - -/mob/living/carbon/brain/can_emote() - return (istype(container, /obj/item/mmi) && ..()) - -/mob/living/carbon/brain - default_emotes = list( - /decl/emote/audible/alarm, - /decl/emote/audible/alert, - /decl/emote/audible/notice, - /decl/emote/audible/whistle, - /decl/emote/audible/synth, - /decl/emote/audible/boop, - /decl/emote/visible/blink, - /decl/emote/visible/flash - ) - -/mob/living/carbon/human - default_emotes = list( - /decl/emote/visible/blink, - /decl/emote/audible/synth, - /decl/emote/audible/synth/ping, - /decl/emote/audible/synth/buzz, - /decl/emote/audible/synth/confirm, - /decl/emote/audible/synth/deny, - /decl/emote/visible/nod, - /decl/emote/visible/shake, - /decl/emote/visible/shiver, - /decl/emote/visible/collapse, - /decl/emote/audible/gasp, - /decl/emote/audible/sneeze, - /decl/emote/audible/sniff, - /decl/emote/audible/snore, - /decl/emote/audible/whimper, - /decl/emote/audible/yawn, - /decl/emote/audible/clap, - /decl/emote/audible/chuckle, - /decl/emote/audible/cough, - /decl/emote/audible/cry, - /decl/emote/audible/sigh, - /decl/emote/audible/laugh, - /decl/emote/audible/mumble, - /decl/emote/audible/grumble, - /decl/emote/audible/groan, - /decl/emote/audible/moan, - /decl/emote/audible/grunt, - /decl/emote/audible/slap, - /decl/emote/human, - /decl/emote/human/deathgasp, - /decl/emote/audible/giggle, - /decl/emote/audible/scream, - /decl/emote/visible/airguitar, - /decl/emote/visible/blink_r, - /decl/emote/visible/bow, - /decl/emote/visible/salute, - /decl/emote/visible/flap, - /decl/emote/visible/aflap, - /decl/emote/visible/drool, - /decl/emote/visible/eyebrow, - /decl/emote/visible/twitch, - /decl/emote/visible/twitch_v, - /decl/emote/visible/faint, - /decl/emote/visible/frown, - /decl/emote/visible/blush, - /decl/emote/visible/wave, - /decl/emote/visible/glare, - /decl/emote/visible/stare, - /decl/emote/visible/look, - /decl/emote/visible/point, - /decl/emote/visible/raise, - /decl/emote/visible/grin, - /decl/emote/visible/shrug, - /decl/emote/visible/smile, - /decl/emote/visible/pale, - /decl/emote/visible/tremble, - /decl/emote/visible/wink, - /decl/emote/visible/hug, - /decl/emote/visible/dap, - /decl/emote/visible/signal, - /decl/emote/visible/handshake, - /decl/emote/visible/afold, - /decl/emote/visible/alook, - /decl/emote/visible/eroll, - /decl/emote/visible/hbow, - /decl/emote/visible/hip, - /decl/emote/visible/holdup, - /decl/emote/visible/hshrug, - /decl/emote/visible/crub, - /decl/emote/visible/erub, - /decl/emote/visible/fslap, - /decl/emote/visible/ftap, - /decl/emote/visible/hrub, - /decl/emote/visible/hspread, - /decl/emote/visible/pocket, - /decl/emote/visible/rsalute, - /decl/emote/visible/rshoulder, - /decl/emote/visible/squint, - /decl/emote/visible/tfist, - /decl/emote/visible/tilt - ) - -/mob/living/silicon/robot - default_emotes = list( - /decl/emote/audible/clap, - /decl/emote/visible/bow, - /decl/emote/visible/salute, - /decl/emote/visible/flap, - /decl/emote/visible/aflap, - /decl/emote/visible/twitch, - /decl/emote/visible/twitch_v, - /decl/emote/visible/nod, - /decl/emote/visible/shake, - /decl/emote/visible/glare, - /decl/emote/visible/look, - /decl/emote/visible/stare, - /decl/emote/visible/deathgasp_robot, - /decl/emote/audible/synth, - /decl/emote/audible/synth/ping, - /decl/emote/audible/synth/buzz, - /decl/emote/audible/synth/confirm, - /decl/emote/audible/synth/deny, - /decl/emote/audible/synth/security, - /decl/emote/audible/synth/security/halt - ) - -/mob/living/carbon/slime - default_emotes = list( - /decl/emote/audible/moan, - /decl/emote/visible/twitch, - /decl/emote/visible/sway, - /decl/emote/visible/shiver, - /decl/emote/visible/bounce, - /decl/emote/visible/jiggle, - /decl/emote/visible/lightup, - /decl/emote/visible/vibrate, - /decl/emote/slime, - /decl/emote/slime/pout, - /decl/emote/slime/sad, - /decl/emote/slime/angry, - /decl/emote/slime/frown, - /decl/emote/slime/smile - ) + var/decl/species/my_species = get_species() + if(LAZYLEN(my_species?.default_emotes)) + LAZYDISTINCTADD(., my_species.default_emotes) + var/decl/bodytype/my_bodytype = get_bodytype() + if(LAZYLEN(my_bodytype?.default_emotes)) + LAZYDISTINCTADD(., my_bodytype.default_emotes) diff --git a/code/modules/emotes/definitions/_species.dm b/code/modules/emotes/definitions/_species.dm deleted file mode 100644 index 67fd1ed12ca5..000000000000 --- a/code/modules/emotes/definitions/_species.dm +++ /dev/null @@ -1,16 +0,0 @@ -/datum/species - var/list/default_emotes = list() - -/mob/living/carbon/update_emotes() - . = ..(skip_sort=1) - if(species) - for(var/emote in species.default_emotes) - var/decl/emote/emote_datum = decls_repository.get_decl(emote) - if(emote_datum.check_user(src)) - usable_emotes[emote_datum.key] = emote_datum - usable_emotes = sortAssoc(usable_emotes) - - -/mob/living/carbon/human/set_species(var/new_species, var/default_colour = 1) - UNLINT(. = ..()) - update_emotes() \ No newline at end of file diff --git a/code/modules/emotes/definitions/audible.dm b/code/modules/emotes/definitions/audible.dm index db0ac71e56fa..dfdfb95aa870 100644 --- a/code/modules/emotes/definitions/audible.dm +++ b/code/modules/emotes/definitions/audible.dm @@ -1,187 +1,175 @@ /decl/emote/audible key = "burp" - emote_message_3p = "USER burps." + emote_message_3p = "$USER$ burps." message_type = AUDIBLE_MESSAGE +/decl/emote/audible/Initialize() + . = ..() + if(!emote_message_radio) + // Snips the 'USER' from 3p emote messages for radio. + emote_message_radio = copytext(emote_message_3p, 8) + /decl/emote/audible/deathgasp_alien - key = "deathgasp" - emote_message_3p = "USER lets out a waning guttural screech, green blood bubbling from its maw." + key = "adeathgasp" + emote_message_3p = "$USER$ lets out a waning guttural screech, green blood bubbling from its maw." /decl/emote/audible/whimper key = "whimper" - emote_message_3p = "USER whimpers." + emote_message_3p = "$USER$ whimpers." /decl/emote/audible/gasp key = "gasp" - emote_message_3p = "USER gasps." + emote_message_3p = "$USER$ gasps." conscious = 0 /decl/emote/audible/scretch key = "scretch" - emote_message_3p = "USER scretches." + emote_message_3p = "$USER$ scretches." /decl/emote/audible/choke - key ="choke" - emote_message_3p = "USER chokes." + key = "choke" + emote_message_3p = "$USER$ chokes." conscious = 0 /decl/emote/audible/gnarl key = "gnarl" - emote_message_3p = "USER gnarls and shows its teeth.." + emote_message_3p = "$USER$ gnarls and shows its teeth." /decl/emote/audible/multichirp key = "mchirp" - emote_message_3p = "USER chirps a chorus of notes!" + emote_message_3p = "$USER$ chirps a chorus of notes!" emote_sound = 'sound/misc/multichirp.ogg' /decl/emote/audible/alarm key = "alarm" emote_message_1p = "You sound an alarm." - emote_message_3p = "USER sounds an alarm." + emote_message_3p = "$USER$ sounds an alarm." /decl/emote/audible/alert key = "alert" emote_message_1p = "You let out a distressed noise." - emote_message_3p = "USER lets out a distressed noise." + emote_message_3p = "$USER$ lets out a distressed noise." /decl/emote/audible/notice key = "notice" emote_message_1p = "You play a loud tone." - emote_message_3p = "USER plays a loud tone." + emote_message_3p = "$USER$ plays a loud tone." /decl/emote/audible/whistle key = "whistle" emote_message_1p = "You whistle." - emote_message_3p = "USER whistles." + emote_message_3p = "$USER$ whistles." /decl/emote/audible/boop key = "boop" emote_message_1p = "You boop." - emote_message_3p = "USER boops." - -/decl/emote/audible/sneeze - key = "sneeze" - emote_message_3p = "USER sneezes." + emote_message_3p = "$USER$ boops." /decl/emote/audible/sniff key = "sniff" - emote_message_3p = "USER sniffs." + emote_message_3p = "$USER$ sniffs." /decl/emote/audible/snore key = "snore" - emote_message_3p = "USER snores." + emote_message_3p = "$USER$ snores." conscious = 0 /decl/emote/audible/whimper key = "whimper" - emote_message_3p = "USER whimpers." + emote_message_3p = "$USER$ whimpers." /decl/emote/audible/yawn key = "yawn" - emote_message_3p = "USER yawns." + emote_message_3p = "$USER$ yawns." /decl/emote/audible/clap key = "clap" - emote_message_3p = "USER claps." + emote_message_3p = "$USER$ claps." /decl/emote/audible/chuckle key = "chuckle" - emote_message_3p = "USER chuckles." - -/decl/emote/audible/cough - key = "cough" - emote_message_3p = "USER coughs!" - conscious = 0 + emote_message_3p = "$USER$ chuckles." /decl/emote/audible/cry key = "cry" - emote_message_3p = "USER cries." + emote_message_3p = "$USER$ cries." /decl/emote/audible/sigh key = "sigh" - emote_message_3p = "USER sighs." + emote_message_3p = "$USER$ sighs." /decl/emote/audible/laugh key = "laugh" - emote_message_3p_target = "USER laughs at TARGET." - emote_message_3p = "USER laughs." + emote_message_3p_target = "$USER$ laughs at $TARGET$." + emote_message_3p = "$USER$ laughs." /decl/emote/audible/mumble key = "mumble" - emote_message_3p = "USER mumbles!" + emote_message_3p = "$USER$ mumbles!" /decl/emote/audible/grumble key = "grumble" - emote_message_3p = "USER grumbles!" + emote_message_3p = "$USER$ grumbles!" /decl/emote/audible/groan key = "groan" - emote_message_3p = "USER groans!" + emote_message_3p = "$USER$ groans!" conscious = 0 /decl/emote/audible/moan key = "moan" - emote_message_3p = "USER moans!" + emote_message_3p = "$USER$ moans!" conscious = 0 /decl/emote/audible/giggle key = "giggle" - emote_message_3p = "USER giggles." - -/decl/emote/audible/scream - key = "scream" - emote_message_3p = "USER screams!" + emote_message_3p = "$USER$ giggles." /decl/emote/audible/grunt key = "grunt" - emote_message_3p = "USER grunts." - -/decl/emote/audible/slap - key = "slap" - emote_message_1p_target = "You slap TARGET across the face!" - emote_message_1p = "You slap yourself across the face!" - emote_message_3p_target = "USER slaps TARGET across the face!" - emote_message_3p = "USER slaps USER_SELF across the face!" - emote_sound = 'sound/effects/snap.ogg' + emote_message_3p = "$USER$ grunts." /decl/emote/audible/bug_hiss - key ="hiss" - emote_message_3p_target = "USER hisses at TARGET." - emote_message_3p = "USER hisses." + key = "bughiss" + emote_message_3p_target = "$USER$ hisses at $TARGET$." + emote_message_3p = "$USER$ hisses." emote_sound = 'sound/voice/BugHiss.ogg' /decl/emote/audible/bug_buzz - key ="buzz" - emote_message_3p = "USER buzzes its wings." + key = "bugbuzz" + emote_message_3p = "$USER$ buzzes its wings." emote_sound = 'sound/voice/BugBuzz.ogg' /decl/emote/audible/bug_chitter - key ="chitter" - emote_message_3p = "USER chitters." + key = "bugchitter" + emote_message_3p = "$USER$ chitters." emote_sound = 'sound/voice/Bug.ogg' -/decl/emote/audible/vox_shriek - key ="shriek" - emote_message_3p = "USER SHRIEKS!" - emote_sound = 'sound/voice/shriek1.ogg' - /decl/emote/audible/roar key = "roar" - emote_message_3p = "USER roars!" + emote_message_3p = "$USER$ roars!" /decl/emote/audible/bellow key = "bellow" - emote_message_3p = "USER bellows!" + emote_message_3p = "$USER$ bellows!" /decl/emote/audible/howl key = "howl" - emote_message_3p = "USER howls!" + emote_message_3p = "$USER$ howls!" /decl/emote/audible/wheeze key = "wheeze" - emote_message_3p = "USER wheezes." + emote_message_3p = "$USER$ wheezes." /decl/emote/audible/hiss - key ="hiss_" - emote_message_3p_target = "USER hisses softly at TARGET." - emote_message_3p = "USER hisses softly." \ No newline at end of file + key = "hiss_" + emote_message_3p_target = "$USER$ hisses softly at $TARGET$." + emote_message_3p = "$USER$ hisses softly." + +/decl/emote/audible/deathgasp + key = "deathgasp" + +/decl/emote/audible/deathgasp/get_emote_message_3p(mob/living/user) + var/decl/species/my_species = user.get_species() + if(my_species) + return "$USER$ [my_species.get_species_death_message()]" diff --git a/code/modules/emotes/definitions/audible_cough.dm b/code/modules/emotes/definitions/audible_cough.dm new file mode 100644 index 000000000000..2d1a9b46db69 --- /dev/null +++ b/code/modules/emotes/definitions/audible_cough.dm @@ -0,0 +1,28 @@ +/decl/emote/audible/cough + key = "cough" + emote_message_1p = "You cough!" + emote_message_1p_target = "You cough on $TARGET$!" + emote_message_3p = "$USER$ coughs!" + emote_message_3p_target = "$USER$ coughs on $TARGET$!" + emote_message_synthetic_1p_target = "You emit a robotic cough towards $TARGET$." + emote_message_synthetic_1p = "You emit a robotic cough." + emote_message_synthetic_3p_target = "$USER$ emits a robotic cough towards $TARGET$." + emote_message_synthetic_3p = "$USER$ emits a robotic cough." + emote_volume = 120 + emote_volume_synthetic = 50 + conscious = FALSE + bodytype_emote_sound = "cough" + +/decl/emote/audible/cough/mob_can_use(mob/living/user, assume_available = FALSE) + . = ..() + if(. && !user.isSynthetic()) + var/obj/item/organ/internal/lungs/lung = user.get_organ(BP_LUNGS) + . = lung?.active_breathing + +/decl/emote/audible/cough/do_emote(var/mob/living/user, var/extra_params) + . = ..() + if(. && istype(user)) + user.cough(silent = TRUE, deliberate = TRUE) + return TRUE + to_chat(src, SPAN_WARNING("You are unable to cough.")) + return FALSE diff --git a/code/modules/emotes/definitions/audible_scream.dm b/code/modules/emotes/definitions/audible_scream.dm new file mode 100644 index 000000000000..5029e59ace01 --- /dev/null +++ b/code/modules/emotes/definitions/audible_scream.dm @@ -0,0 +1,20 @@ +/decl/emote/audible/scream + key = "scream" + emote_message_1p = "You scream!" + emote_message_3p = "$USER$ screams!" + +/decl/emote/audible/scream/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params) + if(ismob(user)) + var/mob/screamer = user + var/decl/species/screamer_species = screamer.get_species() + if(screamer_species?.scream_verb_1p) + return "You [screamer_species.scream_verb_1p]!" + . = ..() + +/decl/emote/audible/scream/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params) + if(ismob(user)) + var/mob/screamer = user + var/decl/species/screamer_species = screamer.get_species() + if(screamer_species?.scream_verb_3p) + return "$USER$ [screamer_species.scream_verb_3p]!" + . = ..() \ No newline at end of file diff --git a/code/modules/emotes/definitions/audible_slap.dm b/code/modules/emotes/definitions/audible_slap.dm new file mode 100644 index 000000000000..93abaa6e9a96 --- /dev/null +++ b/code/modules/emotes/definitions/audible_slap.dm @@ -0,0 +1,25 @@ +/decl/emote/audible/slap + key = "slap" + emote_message_1p_target = "You slap $TARGET$ across the face. Ouch!" + emote_message_1p = "You slap yourself across the face!" + emote_message_3p_target = "$USER$ slaps $TARGET$ across the face. Ouch!" + emote_message_3p = "$USER$ slaps $USER_SELF$ across the face!" + emote_sound = 'sound/effects/snap.ogg' + check_restraints = TRUE + check_range = 1 + check_adjacent = TRUE + +/decl/emote/audible/slap/Initialize() + . = ..() + emote_message_1p_target = SPAN_DANGER(emote_message_1p_target) + emote_message_1p = SPAN_DANGER(emote_message_1p) + emote_message_3p_target = SPAN_DANGER(emote_message_3p_target) + emote_message_3p = SPAN_DANGER(emote_message_3p) + +/decl/emote/audible/slap/do_extra(atom/user, atom/target) + . = ..() + var/mob/victim_mob = target || user + if(ismob(victim_mob)) + var/obj/item/clothing/mask/smokable/cig = victim_mob.get_equipped_item(slot_wear_mask_str) + if(istype(cig)) + victim_mob.try_unequip(cig) diff --git a/code/modules/emotes/definitions/audible_snap.dm b/code/modules/emotes/definitions/audible_snap.dm new file mode 100644 index 000000000000..428f93d1879c --- /dev/null +++ b/code/modules/emotes/definitions/audible_snap.dm @@ -0,0 +1,22 @@ +/decl/emote/audible/snap + key = "snap" + emote_message_1p = "You snap your fingers." + emote_message_3p = "$USER$ snaps $USER_THEIR$ fingers." + emote_message_1p_target = "You snap your fingers at $TARGET$." + emote_message_3p_target = "$USER$ snaps $USER_THEIR$ fingers at $TARGET$." + emote_sound = 'sound/effects/fingersnap.ogg' + +/decl/emote/audible/snap/proc/can_snap(var/atom/user) + if(ishuman(user)) + var/mob/living/human/H = user + for(var/limb in list(BP_L_HAND, BP_R_HAND)) + var/obj/item/organ/external/L = H.get_organ(limb) + if(istype(L) && L.is_usable() && !L.splinted) + return TRUE + return FALSE + +/decl/emote/audible/snap/do_emote(var/atom/user, var/extra_params) + if(!can_snap(user)) + to_chat(user, SPAN_WARNING("You need at least one working hand to snap your fingers.")) + return FALSE + . = ..() diff --git a/code/modules/emotes/definitions/audible_sneeze.dm b/code/modules/emotes/definitions/audible_sneeze.dm new file mode 100644 index 000000000000..382b1736c471 --- /dev/null +++ b/code/modules/emotes/definitions/audible_sneeze.dm @@ -0,0 +1,9 @@ +/decl/emote/audible/sneeze + key = "sneeze" + emote_message_1p = "You sneeze." + emote_message_3p = "$USER$ sneezes." + emote_message_synthetic_1p = "You emit a robotic sneeze." + emote_message_synthetic_1p_target = "You emit a robotic sneeze towards $TARGET$." + emote_message_synthetic_3p = "$USER$ emits a robotic sneeze." + emote_message_synthetic_3p_target = "$USER$ emits a robotic sneeze towards $TARGET$." + bodytype_emote_sound = "sneeze" diff --git a/code/modules/emotes/definitions/audible_whistle.dm b/code/modules/emotes/definitions/audible_whistle.dm new file mode 100644 index 000000000000..585ca85e95f6 --- /dev/null +++ b/code/modules/emotes/definitions/audible_whistle.dm @@ -0,0 +1,46 @@ +/decl/emote/audible/whistle + key = "whistle" + emote_message_1p = "You whistle a tune." + emote_message_3p = "$USER$ whistles a tune." + emote_message_muffled = "$USER$ makes a light spitting noise, a poor attempt at a whistle." + emote_message_synthetic_1p = "You whistle a robotic tune." + emote_message_synthetic_3p = "$USER$ whistles a robotic tune." + +/decl/emote/audible/whistle/Initialize() + bodytype_emote_sound = key + return ..() + +/decl/emote/audible/whistle/quiet + key = "qwhistle" + emote_message_1p = "You whistle quietly." + emote_message_3p = "$USER$ whistles quietly." + emote_message_synthetic_1p = "You whistle robotically." + emote_message_synthetic_3p = "$USER$ whistles robotically." + +/decl/emote/audible/whistle/wolf + key = "wwhistle" + emote_message_1p = "You whistle inappropriately." + emote_message_3p = "$USER$ whistles inappropriately." + emote_message_synthetic_1p = "You beep inappropriately." + emote_message_synthetic_3p = "$USER$ beeps inappropriately." + +/decl/emote/audible/whistle/summon + key = "swhistle" + emote_message_1p = "You give an ear-piercing whistle." + emote_message_3p = "$USER$ gives an ear-piercing whistle." + emote_message_synthetic_1p = "You synthesise an ear-piercing whistle." + emote_message_synthetic_3p = "$USER$ synthesises an ear-piercing whistle." + bodytype_broadcast_sound = "swhistle" + emote_cooldown = 20 SECONDS + broadcast_distance = 65 + +/decl/emote/audible/whistle/summon/broadcast_emote_to(var/send_sound, var/mob/target, var/origin_z, var/direction) + . = ..() + if (.) + var/turf/T = get_turf(target) + if(!T || T.z == origin_z) + to_chat(target, SPAN_NOTICE("You hear a piercing whistle from somewhere to the [dir2text(direction)].")) + else if(T.z < origin_z) + to_chat(target, SPAN_NOTICE("You hear a piercing whistle from somewhere above you, to the [dir2text(direction)].")) + else + to_chat(target, SPAN_NOTICE("You hear a piercing whistle from somewhere below you, to the [dir2text(direction)].")) diff --git a/code/modules/emotes/definitions/exertion.dm b/code/modules/emotes/definitions/exertion.dm new file mode 100644 index 000000000000..a0aeb5a52e9a --- /dev/null +++ b/code/modules/emotes/definitions/exertion.dm @@ -0,0 +1,43 @@ +/decl/emote/exertion + abstract_type = /decl/emote/exertion + +/decl/emote/exertion/biological + key = "esweat" + emote_range = 4 + emote_message_1p = "You are sweating heavily." + emote_message_3p = "$USER$ sweats heavily." + +/decl/emote/exertion/biological/mob_can_use(mob/living/user, assume_available = FALSE) + if(istype(user) && !user.isSynthetic()) + return ..() + return FALSE + +/decl/emote/exertion/biological/breath + key = "ebreath" + emote_message_1p = "You feel out of breath." + emote_message_3p = "$USER$ looks out of breath." + +/decl/emote/exertion/biological/pant + key = "epant" + emote_range = 3 + message_type = AUDIBLE_MESSAGE + emote_message_1p = "You pant to catch your breath." + emote_message_3p = "$USER$ pants for air." + emote_message_impaired = "You can see $USER$ breathing heavily." + +/decl/emote/exertion/synthetic + key = "ewhine" + emote_range = 3 + message_type = AUDIBLE_MESSAGE + emote_message_1p = "You overstress your actuators." + emote_message_3p = "$USER$'s actuators whine with strain." + +/decl/emote/exertion/synthetic/mob_can_use(mob/living/user, assume_available = FALSE) + if(istype(user) && user.isSynthetic()) + return ..() + return FALSE + +/decl/emote/exertion/synthetic/creak + key = "ecreak" + emote_message_1p = "Your chassis stress indicators spike." + emote_message_3p = "$USER$'s joints creak with stress." diff --git a/code/modules/emotes/definitions/human.dm b/code/modules/emotes/definitions/human.dm deleted file mode 100644 index 8c27c215ad60..000000000000 --- a/code/modules/emotes/definitions/human.dm +++ /dev/null @@ -1,56 +0,0 @@ -/decl/emote/human - key = "vomit" - -/decl/emote/human/check_user(var/mob/living/carbon/human/user) - return (istype(user) && user.check_has_mouth() && !user.isSynthetic()) - -/decl/emote/human/do_emote(var/mob/living/carbon/human/user) - user.vomit(deliberate = TRUE) - -/decl/emote/human/deathgasp - key = "deathgasp" - -/decl/emote/human/deathgasp/get_emote_message_3p(var/mob/living/carbon/human/user) - return "USER [user.species.get_death_message()]" - -/decl/emote/human/swish - key = "swish" - -/decl/emote/human/swish/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_once() - -/decl/emote/human/wag - key = "wag" - -/decl/emote/human/wag/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_start() - -/decl/emote/human/sway - key = "sway" - -/decl/emote/human/sway/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_start() - -/decl/emote/human/qwag - key = "qwag" - -/decl/emote/human/qwag/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_fast() - -/decl/emote/human/fastsway - key = "fastsway" - -/decl/emote/human/fastsway/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_fast() - -/decl/emote/human/swag - key = "swag" - -/decl/emote/human/swag/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_stop() - -/decl/emote/human/stopsway - key = "stopsway" - -/decl/emote/human/stopsway/do_emote(var/mob/living/carbon/human/user) - user.animate_tail_stop() diff --git a/code/modules/emotes/definitions/slime.dm b/code/modules/emotes/definitions/slime.dm deleted file mode 100644 index a8114305701a..000000000000 --- a/code/modules/emotes/definitions/slime.dm +++ /dev/null @@ -1,30 +0,0 @@ -/decl/emote/slime - key = "nomood" - var/mood - -/decl/emote/slime/do_extra(var/mob/living/carbon/slime/user) - user.mood = mood - user.regenerate_icons() - -/decl/emote/slime/check_user(var/atom/user) - return istype(user, /mob/living/carbon/slime) - -/decl/emote/slime/pout - key = "pout" - mood = "pout" - -/decl/emote/slime/sad - key = "sad" - mood = "sad" - -/decl/emote/slime/angry - key = "angry" - mood = "angry" - -/decl/emote/slime/frown - key = "frown" - mood = "mischevous" - -/decl/emote/slime/smile - key = "smile" - mood = ":3" diff --git a/code/modules/emotes/definitions/synthetics.dm b/code/modules/emotes/definitions/synthetics.dm index 0126be0c110b..019a70d29056 100644 --- a/code/modules/emotes/definitions/synthetics.dm +++ b/code/modules/emotes/definitions/synthetics.dm @@ -1,43 +1,44 @@ /decl/emote/audible/synth key = "beep" - emote_message_3p = "USER beeps." + emote_message_3p = "$USER$ beeps." emote_sound = 'sound/machines/twobeep.ogg' -/decl/emote/audible/synth/check_user(var/mob/living/user) - if(istype(user) && user.isSynthetic()) - return ..() - return FALSE +/decl/emote/audible/synth/mob_can_use(mob/living/user, assume_available = FALSE) + return ..() && user.isSynthetic() /decl/emote/audible/synth/ping key = "ping" - emote_message_3p = "USER pings." + emote_message_3p = "$USER$ pings." emote_sound = 'sound/machines/ping.ogg' /decl/emote/audible/synth/buzz key = "buzz" - emote_message_3p = "USER buzzes." + emote_message_3p = "$USER$ buzzes." emote_sound = 'sound/machines/buzz-sigh.ogg' /decl/emote/audible/synth/confirm key = "confirm" - emote_message_3p = "USER emits an affirmative blip." + emote_message_3p = "$USER$ emits an affirmative blip." emote_sound = 'sound/machines/synth_yes.ogg' /decl/emote/audible/synth/deny key = "deny" - emote_message_3p = "USER emits a negative blip." + emote_message_3p = "$USER$ emits a negative blip." emote_sound = 'sound/machines/synth_no.ogg' /decl/emote/audible/synth/security key = "law" - emote_message_3p = "USER shows USER_HIS legal authorization barcode." - emote_message_3p_target = "USER shows TARGET USER_THEIR legal authorization barcode." + emote_message_3p = "$USER$ shows $USER_THEIR$ legal authorization barcode." + emote_message_3p_target = "$USER$ shows $TARGET$ $USER_THEIR$ legal authorization barcode." emote_sound = 'sound/voice/biamthelaw.ogg' -/decl/emote/audible/synth/security/check_user(var/mob/living/silicon/robot/user) - return (istype(user) && istype(user.module,/obj/item/robot_module/security)) +/decl/emote/audible/synth/security/mob_can_use(mob/living/user, assume_available = FALSE) + var/mob/living/silicon/robot/robot_user = user + if(!istype(robot_user)) + return FALSE + return istype(robot_user.module, /obj/item/robot_module/security) && ..() /decl/emote/audible/synth/security/halt key = "halt" - emote_message_3p = "USER's speakers skreech, \"Halt! Security!\"." + emote_message_3p = "$USER$'s speakers skreech, \"Halt! Security!\"." emote_sound = 'sound/voice/halt.ogg' diff --git a/code/modules/emotes/definitions/tail.dm b/code/modules/emotes/definitions/tail.dm new file mode 100644 index 000000000000..deded3daa95a --- /dev/null +++ b/code/modules/emotes/definitions/tail.dm @@ -0,0 +1,57 @@ + +/decl/emote/visible/tail + abstract_type = /decl/emote/visible/tail + key = "tail" + emote_message_3p = "$USER$ waves $USER_THEIR$ tail." + +/decl/emote/visible/tail/mob_can_use(mob/living/user, assume_available = FALSE) + return istype(user) && ..() + +/decl/emote/visible/tail/swish + key = "swish" + +/decl/emote/visible/tail/swish/do_emote(mob/living/user) + user.animate_tail_once() + return TRUE + +/decl/emote/visible/tail/wag + key = "wag" + +/decl/emote/visible/tail/wag/do_emote(mob/living/user) + user.animate_tail_start() + return TRUE + +/decl/emote/visible/tail/sway + key = "sway" + +/decl/emote/visible/tail/sway/do_emote(mob/living/user) + user.animate_tail_start() + return TRUE + +/decl/emote/visible/tail/qwag + key = "qwag" + +/decl/emote/visible/tail/qwag/do_emote(mob/living/user) + user.animate_tail_fast() + return TRUE + +/decl/emote/visible/tail/fastsway + key = "fastsway" + +/decl/emote/visible/tail/fastsway/do_emote(mob/living/user) + user.animate_tail_fast() + return TRUE + +/decl/emote/visible/tail/swag + key = "swag" + +/decl/emote/visible/tail/swag/do_emote(mob/living/user) + user.set_tail_animation_state(null, TRUE) + return TRUE + +/decl/emote/visible/tail/stopsway + key = "stopsway" + +/decl/emote/visible/tail/stopsway/do_emote(mob/living/user) + user.set_tail_animation_state(null, TRUE) + return TRUE diff --git a/code/modules/emotes/definitions/visible.dm b/code/modules/emotes/definitions/visible.dm index 09ed98dfc718..377e582d0f39 100644 --- a/code/modules/emotes/definitions/visible.dm +++ b/code/modules/emotes/definitions/visible.dm @@ -1,336 +1,378 @@ /decl/emote/visible - key ="tail" - emote_message_3p = "USER waves USER_THEIR tail." + abstract_type = /decl/emote/visible message_type = VISIBLE_MESSAGE /decl/emote/visible/scratch key = "scratch" check_restraints = TRUE - emote_message_3p = "USER scratches." + emote_message_3p = "$USER$ scratches." /decl/emote/visible/drool - key ="drool" - emote_message_3p = "USER drools." + key = "drool" + emote_message_3p = "$USER$ drools." conscious = 0 /decl/emote/visible/nod - key ="nod" - emote_message_3p_target = "USER nods USER_THEIR head at TARGET." - emote_message_3p = "USER nods USER_THEIR head." + key = "nod" + emote_message_3p_target = "$USER$ nods $USER_THEIR$ head at $TARGET$." + emote_message_3p = "$USER$ nods $USER_THEIR$ head." /decl/emote/visible/sway - key ="sway" - emote_message_3p = "USER sways around dizzily." + key = "sways" + emote_message_3p = "$USER$ sways around dizzily." /decl/emote/visible/sulk - key ="sulk" - emote_message_3p = "USER sulks down sadly." + key = "sulk" + emote_message_3p = "$USER$ sulks down sadly." /decl/emote/visible/dance - key ="dance" + key = "dance" check_restraints = TRUE - emote_message_3p = "USER dances around happily." + emote_message_3p = "$USER$ dances around happily." /decl/emote/visible/roll - key ="roll" + key = "roll" check_restraints = TRUE - emote_message_3p = "USER rolls." + emote_message_3p = "$USER$ rolls." /decl/emote/visible/shake - key ="shake" - emote_message_3p = "USER shakes USER_THEIR head." + key = "shake" + emote_message_3p = "$USER$ shakes $USER_THEIR$ head." /decl/emote/visible/jump - key ="jump" - emote_message_3p = "USER jumps!" + key = "jump" + emote_message_3p = "$USER$ jumps!" /decl/emote/visible/shiver - key ="shiver" - emote_message_3p = "USER shivers." + key = "shiver" + emote_message_3p = "$USER$ shivers." conscious = 0 /decl/emote/visible/collapse - key ="collapse" - emote_message_3p = "USER collapses!" + key = "collapse" + emote_message_3p = "$USER$ collapses!" -/decl/emote/visible/collapse/do_extra(var/mob/user) - if(istype(user)) - user.Paralyse(2) +/decl/emote/visible/collapse/do_extra(atom/user) + if(ismob(user)) + var/mob/user_mob = user + SET_STATUS_MAX(user_mob, STAT_PARA, 2) /decl/emote/visible/flash key = "flash" - emote_message_3p = "The lights on USER flash quickly." + emote_message_3p = "The lights on $USER$ flash quickly." /decl/emote/visible/blink key = "blink" - emote_message_3p = "USER blinks." + emote_message_3p = "$USER$ blinks." /decl/emote/visible/airguitar key = "airguitar" check_restraints = TRUE - emote_message_3p = "USER is strumming the air and headbanging like a safari chimp." + emote_message_3p = "$USER$ is strumming the air and headbanging like a safari chimp." /decl/emote/visible/blink_r key = "blink_r" - emote_message_3p = "USER blinks rapidly." + emote_message_3p = "$USER$ blinks rapidly." /decl/emote/visible/bow key = "bow" - emote_message_3p_target = "USER bows to TARGET." - emote_message_3p = "USER bows." + emote_message_3p_target = "$USER$ bows to $TARGET$." + emote_message_3p = "$USER$ bows." /decl/emote/visible/salute key = "salute" - emote_message_3p_target = "USER salutes TARGET." - emote_message_3p = "USER salutes." + emote_message_3p_target = "$USER$ salutes $TARGET$." + emote_message_3p = "$USER$ salutes." + check_restraints = TRUE /decl/emote/visible/flap key = "flap" check_restraints = TRUE - emote_message_3p = "USER flaps USER_THEIR wings." + emote_message_3p = "$USER$ flaps $USER_THEIR$ wings." /decl/emote/visible/aflap key = "aflap" check_restraints = TRUE - emote_message_3p = "USER flaps USER_THEIR wings ANGRILY!" + emote_message_3p = "$USER$ flaps $USER_THEIR$ wings ANGRILY!" /decl/emote/visible/eyebrow key = "eyebrow" - emote_message_3p = "USER raises an eyebrow." + emote_message_3p = "$USER$ raises an eyebrow." /decl/emote/visible/twitch key = "twitch" - emote_message_3p = "USER twitches." + emote_message_3p = "$USER$ twitches." conscious = 0 /decl/emote/visible/twitch_v key = "twitch_v" - emote_message_3p = "USER twitches violently." + emote_message_3p = "$USER$ twitches violently." conscious = 0 /decl/emote/visible/faint key = "faint" - emote_message_3p = "USER faints." + emote_message_3p = "$USER$ faints." -/decl/emote/visible/faint/do_extra(var/mob/user) - if(istype(user) && user.sleeping <= 0) - user.sleeping += 10 +/decl/emote/visible/faint/do_extra(atom/user) + var/mob/user_mob = user + if(istype(user_mob) && !HAS_STATUS(user_mob, STAT_ASLEEP)) + SET_STATUS_MAX(user_mob, STAT_ASLEEP, 10) /decl/emote/visible/frown key = "frown" - emote_message_3p = "USER frowns." + emote_message_3p = "$USER$ frowns." /decl/emote/visible/blush key = "blush" - emote_message_3p = "USER blushes." + emote_message_3p = "$USER$ blushes." /decl/emote/visible/wave key = "wave" - emote_message_3p_target = "USER waves at TARGET." - emote_message_3p = "USER waves." + emote_message_3p_target = "$USER$ waves at $TARGET$." + emote_message_3p = "$USER$ waves." + check_restraints = TRUE /decl/emote/visible/glare key = "glare" - emote_message_3p_target = "USER glares at TARGET." - emote_message_3p = "USER glares." + emote_message_3p_target = "$USER$ glares at $TARGET$." + emote_message_3p = "$USER$ glares." /decl/emote/visible/stare key = "stare" - emote_message_3p_target = "USER stares at TARGET." - emote_message_3p = "USER stares." + emote_message_3p_target = "$USER$ stares at $TARGET$." + emote_message_3p = "$USER$ stares." /decl/emote/visible/look key = "look" - emote_message_3p_target = "USER looks at TARGET." - emote_message_3p = "USER looks." + emote_message_3p_target = "$USER$ looks at $TARGET$." + emote_message_3p = "$USER$ looks." /decl/emote/visible/point key = "point" check_restraints = TRUE - emote_message_3p_target = "USER points to TARGET." - emote_message_3p = "USER points." + emote_message_3p_target = "$USER$ points to $TARGET$." + emote_message_3p = "$USER$ points." /decl/emote/visible/raise key = "raise" check_restraints = TRUE - emote_message_3p = "USER raises a hand." + emote_message_3p = "$USER$ raises a hand." /decl/emote/visible/grin key = "grin" - emote_message_3p_target = "USER grins at TARGET." - emote_message_3p = "USER grins." + emote_message_3p_target = "$USER$ grins at $TARGET$." + emote_message_3p = "$USER$ grins." /decl/emote/visible/shrug key = "shrug" - emote_message_3p = "USER shrugs." + emote_message_3p = "$USER$ shrugs." /decl/emote/visible/smile key = "smile" - emote_message_3p_target = "USER smiles at TARGET." - emote_message_3p = "USER smiles." + emote_message_3p_target = "$USER$ smiles at $TARGET$." + emote_message_3p = "$USER$ smiles." /decl/emote/visible/pale key = "pale" - emote_message_3p = "USER goes pale for a second." + emote_message_3p = "$USER$ goes pale for a second." /decl/emote/visible/tremble key = "tremble" - emote_message_3p = "USER trembles in fear!" + emote_message_3p = "$USER$ trembles in fear!" /decl/emote/visible/wink key = "wink" - emote_message_3p_target = "USER winks at TARGET." - emote_message_3p = "USER winks." + emote_message_3p_target = "$USER$ winks at $TARGET$." + emote_message_3p = "$USER$ winks." /decl/emote/visible/hug key = "hug" check_restraints = TRUE - emote_message_3p_target = "USER hugs TARGET." - emote_message_3p = "USER hugs USER_SELF." + emote_message_3p_target = "$USER$ hugs $TARGET$." + emote_message_3p = "$USER$ hugs $USER_SELF$." + check_range = 1 /decl/emote/visible/dap key = "dap" check_restraints = TRUE - emote_message_3p_target = "USER gives daps to TARGET." - emote_message_3p = "USER sadly can't find anybody to give daps to, and daps USER_SELF." - -/decl/emote/visible/signal - key = "signal" - check_restraints = TRUE - emote_message_3p = "USER signals." - -/decl/emote/visible/signal/check_user(var/atom/user) - return ismob(user) + emote_message_3p_target = "$USER$ gives daps to $TARGET$." + emote_message_3p = "$USER$ sadly can't find anybody to give daps to, and daps $USER_SELF$." /decl/emote/visible/bounce key = "bounce" - emote_message_3p = "USER bounces in place." + emote_message_3p = "$USER$ bounces in place." /decl/emote/visible/jiggle key = "jiggle" - emote_message_3p = "USER jiggles!" + emote_message_3p = "$USER$ jiggles!" /decl/emote/visible/lightup key = "light" - emote_message_3p = "USER lights up for a bit, then stops." + emote_message_3p = "$USER$ lights up for a bit, then stops." /decl/emote/visible/vibrate key = "vibrate" - emote_message_3p = "USER vibrates!" + emote_message_3p = "$USER$ vibrates!" /decl/emote/visible/deathgasp_robot - key = "deathgasp" - emote_message_3p = "USER shudders violently for a moment, then becomes motionless, USER_THEIR eyes slowly darkening." + key = "rdeathgasp" + emote_message_3p = "$USER$ shudders violently for a moment, then becomes motionless, $USER_THEIR$ eyes slowly darkening." /decl/emote/visible/handshake key = "handshake" check_restraints = TRUE - emote_message_3p_target = "USER shakes hands with TARGET." - emote_message_3p = "USER shakes hands with USER_SELF." - message_type = VISIBLE_MESSAGE + emote_message_3p_target = "$USER$ shakes hands with $TARGET$." + emote_message_3p = "$USER$ shakes hands with $USER_SELF$." + check_range = 1 /decl/emote/visible/handshake/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params) if(target && !user.Adjacent(target)) - return "USER holds out USER_THEIR hand out to TARGET." + return "$USER$ holds out $USER_THEIR$ hand out to $TARGET$." return ..() /decl/emote/visible/signal key = "signal" - emote_message_3p_target = "USER signals at TARGET." - emote_message_3p = "USER signals." - message_type = VISIBLE_MESSAGE + emote_message_3p_target = "$USER$ signals at $TARGET$." + emote_message_3p = "$USER$ signals." + check_restraints = TRUE -/decl/emote/visible/signal/get_emote_message_3p(var/mob/user, var/atom/target, var/extra_params) - if(istype(user) && !(user.r_hand && user.l_hand)) +/decl/emote/visible/signal/get_emote_message_3p(var/mob/living/user, var/atom/target, var/extra_params) + if(istype(user) && user.get_empty_hand_slot()) var/t1 = round(text2num(extra_params)) if(isnum(t1) && t1 <= 5) - return "USER raises [t1] finger\s." + return "$USER$ raises [t1] finger\s." return .. () /decl/emote/visible/afold key = "afold" check_restraints = TRUE - emote_message_3p = "USER folds USER_THEIR arms." + emote_message_3p = "$USER$ folds $USER_THEIR$ arms." /decl/emote/visible/alook key = "alook" - emote_message_3p = "USER looks away." + emote_message_3p = "$USER$ looks away." /decl/emote/visible/hbow key = "hbow" - emote_message_3p = "USER bows USER_THEIR head." + emote_message_3p = "$USER$ bows $USER_THEIR$ head." /decl/emote/visible/hip key = "hip" check_restraints = TRUE - emote_message_3p = "USER puts USER_THEIR hands on USER_THEIR hips." + emote_message_3p = "$USER$ puts $USER_THEIR$ hands on $USER_THEIR$ hips." /decl/emote/visible/holdup key = "holdup" check_restraints = TRUE - emote_message_3p = "USER holds up USER_THEIR palms." + emote_message_3p = "$USER$ holds up $USER_THEIR$ palms." /decl/emote/visible/hshrug key = "hshrug" - emote_message_3p = "USER gives a half shrug." + emote_message_3p = "$USER$ gives a half shrug." /decl/emote/visible/crub key = "crub" check_restraints = TRUE - emote_message_3p = "USER rubs USER_THEIR chin." + emote_message_3p = "$USER$ rubs $USER_THEIR$ chin." /decl/emote/visible/eroll key = "eroll" - emote_message_3p = "USER rolls USER_THEIR eyes." - emote_message_3p_target = "USER rolls USER_THEIR eyes at TARGET." + emote_message_3p = "$USER$ rolls $USER_THEIR$ eyes." + emote_message_3p_target = "$USER$ rolls $USER_THEIR$ eyes at $TARGET$." /decl/emote/visible/erub key = "erub" check_restraints = TRUE - emote_message_3p = "USER rubs USER_THEIR eyes." + emote_message_3p = "$USER$ rubs $USER_THEIR$ eyes." /decl/emote/visible/fslap key = "fslap" check_restraints = TRUE - emote_message_3p = "USER slaps USER_THEIR forehead." + emote_message_3p = "$USER$ slaps $USER_THEIR$ forehead." /decl/emote/visible/ftap key = "ftap" - emote_message_3p = "USER taps USER_THEIR foot." + emote_message_3p = "$USER$ taps $USER_THEIR$ foot." /decl/emote/visible/hrub key = "hrub" check_restraints = TRUE - emote_message_3p = "USER rubs USER_THEIR hands together." + emote_message_3p = "$USER$ rubs $USER_THEIR$ hands together." /decl/emote/visible/hspread key = "hspread" check_restraints = TRUE - emote_message_3p = "USER spreads USER_THEIR hands." + emote_message_3p = "$USER$ spreads $USER_THEIR$ hands." /decl/emote/visible/pocket key = "pocket" check_restraints = TRUE - emote_message_3p = "USER shoves USER_THEIR hands in USER_THEIR pockets." + emote_message_3p = "$USER$ shoves $USER_THEIR$ hands in $USER_THEIR$ pockets." + +/decl/emote/visible/pocket/mob_can_use(mob/living/user, assume_available) + . = ..() + if(!.) + return + // You need a uniform to have pockets. + var/datum/inventory_slot/check_slot = user.get_inventory_slot_datum(slot_w_uniform_str) + if(!check_slot?.get_equipped_item()) + return FALSE /decl/emote/visible/rsalute key = "rsalute" check_restraints = TRUE - emote_message_3p = "USER returns the salute." + emote_message_3p = "$USER$ returns the salute." /decl/emote/visible/rshoulder key = "rshoulder" - emote_message_3p = "USER rolls USER_THEIR shoulders." + emote_message_3p = "$USER$ rolls $USER_THEIR$ shoulders." /decl/emote/visible/squint key = "squint" - emote_message_3p = "USER squints." - emote_message_3p_target = "USER squints at TARGET." + emote_message_3p = "$USER$ squints." + emote_message_3p_target = "$USER$ squints at $TARGET$." /decl/emote/visible/tfist key = "tfist" - emote_message_3p = "USER tightens USER_THEIR hands into fists." + emote_message_3p = "$USER$ tightens $USER_THEIR$ hands into fists." /decl/emote/visible/tilt key = "tilt" - emote_message_3p = "USER tilts USER_THEIR head." \ No newline at end of file + emote_message_3p = "$USER$ tilts $USER_THEIR$ head." + +/decl/emote/visible/spin + key = "spin" + check_restraints = TRUE + emote_message_3p = "$USER$ spins!" + emote_delay = 2 SECONDS + +/decl/emote/visible/spin/do_extra(atom/user) + if(ismob(user)) + var/mob/user_mob = user + user_mob.spin(emote_delay, 1) + +/decl/emote/visible/sidestep + key = "sidestep" + check_restraints = TRUE + emote_message_3p = "$USER$ steps rhythmically and moves side to side." + emote_delay = 1.2 SECONDS + +/decl/emote/visible/sidestep/do_extra(atom/user) + animate(user, pixel_x = 5, time = 5) + sleep(3) + animate(user, pixel_x = -5, time = 5) + animate(pixel_x = user.default_pixel_x, pixel_y = user.default_pixel_x, time = 2) + +/decl/emote/visible/vomit + key = "vomit" + +/decl/emote/visible/vomit/mob_can_use(mob/living/user, assume_available = FALSE) + . = ..() && user.check_has_mouth() && !user.isSynthetic() + +/decl/emote/visible/vomit/do_emote(var/atom/user, var/extra_params) + var/mob/living/human/H = user + if(istype(H)) + H.vomit(deliberate = TRUE) + return TRUE + to_chat(src, SPAN_WARNING("You are unable to vomit.")) + return FALSE diff --git a/code/modules/emotes/emote_define.dm b/code/modules/emotes/emote_define.dm index 484e1ca007e2..3cf18471cd43 100644 --- a/code/modules/emotes/emote_define.dm +++ b/code/modules/emotes/emote_define.dm @@ -1,117 +1,362 @@ +/proc/emote_replace_target_tokens(var/msg, var/atom/target) + . = msg + if(istype(target)) + var/decl/pronouns/target_gender = target.get_pronouns() + . = replacetext(., "$TARGET_S$", target_gender.s) + . = replacetext(., "$TARGET_THEY$", target_gender.he) + . = replacetext(., "$TARGET_THEM$", target_gender.him) + . = replacetext(., "$TARGET_THEIR$", target_gender.his) + . = replacetext(., "$TARGET_SELF$", target_gender.self) + . = replacetext(., "$TARGET$", "\the [target]") + +/proc/emote_replace_user_tokens(var/msg, var/atom/user) + . = msg + if(istype(user)) + var/decl/pronouns/user_gender = user.get_pronouns() + . = replacetext(., "$USER_S$", user_gender.s) + . = replacetext(., "$USER_THEY$", user_gender.he) + . = replacetext(., "$USER_THEM$", user_gender.him) + . = replacetext(., "$USER_THEIR$", user_gender.his) + . = replacetext(., "$USER_SELF$", user_gender.self) + . = replacetext(., "$USER$", "\the [user]") + // Note about emote messages: -// - USER / TARGET will be replaced with the relevant name, in bold. -// - USER_THEM / TARGET_THEM / USER_THEIR / TARGET_THEIR will be replaced with a +// - $USER$ / $TARGET$ will be replaced with the relevant name, in bold. +// - $USER_THEM$ / $TARGET_THEM$ / $USER_THEIR$ / $TARGET_THEIR$ will be replaced with a // gender-appropriate version of the same. // - Impaired messages do not do any substitutions. +var/global/list/_emotes_by_key + +/proc/get_emote_by_key(var/key) + if(!global._emotes_by_key) + decls_repository.get_decls_of_type(/decl/emote) // _emotes_by_key will be updated in emote Initialize() + return global._emotes_by_key[key] + /decl/emote - var/key // Command to use emote ie. '*[key]' - var/emote_message_1p // First person message ('You do a flip!') - var/emote_message_3p // Third person message ('Urist McShitter does a flip!') - var/emote_message_impaired // Deaf/blind message ('You hear someone flipping out.', 'You see someone opening and closing their mouth') + abstract_type = /decl/emote + /// Command to use emote ie. '*[key]' + var/key + /// First person message ('You do a flip!') + var/emote_message_1p + /// Third person message ('Urist McShitter does a flip!') + var/emote_message_3p + /// First person message for robits. + var/emote_message_synthetic_1p + /// Third person message for robits. + var/emote_message_synthetic_3p + + /// 'You do a flip at Urist McTarget!' + var/emote_message_1p_target + /// 'Urist McShitter does a flip at Urist McTarget!' + var/emote_message_3p_target + /// First person targeted message for robits. + var/emote_message_synthetic_1p_target + /// Third person targeted message for robits. + var/emote_message_synthetic_3p_target + + /// A message to send over the radio if one picks up this emote. + var/emote_message_radio + /// As above, but for synthetics. + var/emote_message_radio_synthetic - var/emote_message_1p_target // 'You do a flip at Urist McTarget!' - var/emote_message_3p_target // 'Urist McShitter does a flip at Urist McTarget!' + /// A message to show if the emote is audible and the user is muzzled. + var/emote_message_muffled + /// Deaf/blind message ('You hear someone flipping out.', 'You see someone opening and closing their mouth') + var/emote_message_impaired - // Two-dimensional array - // First is list of genders, associated to a list of the sound effects to use + /// Two-dimensional array: first is list of genders, associated to a list of the sound effects to use. + /// Alternatively, just a singular sound. var/list/emote_sound = null + /// If set to a string, will ask the bodytype of the user four a sound effect using the string. + var/bodytype_emote_sound + /// Volume of sound to play. + var/emote_volume = 50 + /// As above, but used when check_synthetic() is true. + var/emote_volume_synthetic = 50 + + /// This sound will be passed to the entire connected z-chunk if set. + var/broadcast_sound + /// As above, but for broadcast. + var/bodytype_broadcast_sound + /// Volume for broadcast sound. + var/broadcast_volume = 15 + /// How far does the sound broadcast. + var/broadcast_distance + + /// Audible/visual flag + var/message_type = VISIBLE_MESSAGE + /// Whether or not this emote -must- have a target. + var/mandatory_targetted_emote + /// Can this emote be used while restrained? + var/check_restraints + /// falsy, or a range outside which the emote will not work + var/check_range + /// For emotes with physical effecets. + var/check_adjacent + /// Do we need to be awake to emote this? + var/conscious = TRUE + /// If >0, restricts emote visibility to viewers within range. + var/emote_range = 0 + /// Time in ds that this emote will block further emote use (spam prevention). + var/emote_delay = 1 SECOND + + /// How long will we be on cooldown for this emote. + var/emote_cooldown + /// Assoc list of weakref to mob to next emote. + var/list/emote_cooldowns = list() + +/decl/emote/Initialize() + . = ..() + if(key) + LAZYSET(global._emotes_by_key, key, src) + +/decl/emote/validate() + . = ..() + var/list/all_emotes = decls_repository.get_decls_of_type(/decl/emote) + for(var/emote_type in all_emotes) + var/decl/emote/emote = all_emotes[emote_type] + if(emote == src) + continue + if(key == emote.key) + . += "non-unique key, overlaps with [emote.type]" - var/message_type = VISIBLE_MESSAGE // Audible/visual flag - var/targetted_emote // Whether or not this emote needs a target. - var/check_restraints // Can this emote be used while restrained? - var/conscious = 1 // Do we need to be awake to emote this? +// validate() is never called outside of unit testing, but +// this feels foul to have in non-unit test main code. +#ifdef UNIT_TEST + var/static/obj/dummy_emote_target = new + dummy_emote_target.name = "\proper Barry's hat" + var/static/mob/dummy_emote_user = new + dummy_emote_user.name = "\proper Barry" + dummy_emote_user.set_gender(MALE) + // This should catch misspelled tokens, TARGET_HIM etc as well as leftover TARGET and USER. + var/static/list/tokens = list("$", "TARGET", "USER") + var/all_strings = list( + "emote_message_1p" = emote_message_1p, + "emote_message_3p" = emote_message_3p, + "emote_message_synthetic_1p" = emote_message_synthetic_1p, + "emote_message_synthetic_3p" = emote_message_synthetic_3p, + "emote_message_1p_target" = emote_message_1p_target, + "emote_message_3p_target" = emote_message_3p_target, + "emote_message_synthetic_1p_target" = emote_message_synthetic_1p_target, + "emote_message_synthetic_3p_target" = emote_message_synthetic_3p_target + ) + for(var/string_key in all_strings) + var/emote_string = all_strings[string_key] + if(!length(emote_string)) + continue + emote_string = uppertext(emote_replace_target_tokens(emote_replace_user_tokens(emote_string, dummy_emote_user), dummy_emote_target)) + for(var/token in tokens) + if(findtext(emote_string, token)) + . += "malformed emote token [token] in [string_key]" +#endif /decl/emote/proc/get_emote_message_1p(var/atom/user, var/atom/target, var/extra_params) if(target) + if(emote_message_synthetic_1p_target && check_synthetic(user)) + return emote_message_synthetic_1p_target return emote_message_1p_target + if(emote_message_synthetic_1p && check_synthetic(user)) + return emote_message_synthetic_1p return emote_message_1p /decl/emote/proc/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params) if(target) + if(emote_message_synthetic_3p_target && check_synthetic(user)) + return emote_message_synthetic_3p_target return emote_message_3p_target + if(emote_message_synthetic_3p && check_synthetic(user)) + return emote_message_synthetic_3p return emote_message_3p +/decl/emote/proc/get_emote_sound(var/atom/user) + + var/use_emote_sound = emote_sound + if(bodytype_emote_sound && ismob(user)) + var/mob/user_mob = user + var/bodytype_sounds = user_mob?.get_bodytype()?.emote_sounds[bodytype_emote_sound] + if(length(bodytype_sounds)) + use_emote_sound = pick(bodytype_sounds) + + if(use_emote_sound) + . = list( + "sound" = use_emote_sound, + "vol" = check_synthetic(user) ? emote_volume_synthetic : emote_volume + ) + + var/use_broadcast_sound = broadcast_sound + if(bodytype_broadcast_sound && ismob(user)) + var/mob/user_mob = user + var/bodytype_sounds = user_mob?.get_bodytype()?.broadcast_emote_sounds[bodytype_broadcast_sound] + if(length(bodytype_sounds)) + use_broadcast_sound = pick(bodytype_sounds) + + if(use_broadcast_sound) + LAZYINITLIST(.) + LAZYSET(., "broadcast", use_broadcast_sound) + +/decl/emote/proc/finalize_target(atom/user, atom/target) + return istype(target) && (!check_adjacent || target.Adjacent(user)) + /decl/emote/proc/do_emote(var/atom/user, var/extra_params) + if(ismob(user) && check_restraints) var/mob/M = user if(M.restrained()) - to_chat(user, "You are restrained and cannot do that.") - return + to_chat(user, SPAN_WARNING("You are restrained and cannot do that.")) + return FALSE + + if(emote_cooldown) + var/user_ref = "\ref[user]" + var/next_emote = emote_cooldowns[user_ref] + if(world.time < next_emote) + to_chat(user, SPAN_WARNING("You cannot use this emote again for another [round((next_emote - world.time)/(1 SECOND))] second\s.")) + return FALSE + emote_cooldowns[user_ref] = (world.time + emote_cooldown) var/atom/target if(can_target() && extra_params) - extra_params = lowertext(extra_params) - for(var/atom/thing in view(user)) - if(extra_params == lowertext(thing.name)) + var/target_dist + extra_params = trim(lowertext(extra_params)) + for(var/atom/thing in view((isnull(check_range) ? world.view : check_range), user)) + + if(!isturf(thing.loc)) + continue + + var/new_target_dist = get_dist(thing, user) + if(!isnull(target_dist) && target_dist > new_target_dist) + continue + + if(findtext(lowertext(thing.name), extra_params)) + target_dist = new_target_dist target = thing - break - var/datum/gender/user_gender = gender_datums[user.get_visible_gender()] - var/datum/gender/target_gender - if(target) - target_gender = gender_datums[target.get_visible_gender()] - - var/use_3p - var/use_1p - if(emote_message_1p) - if(target && emote_message_1p_target) - use_1p = get_emote_message_1p(user, target, extra_params) - use_1p = replacetext(use_1p, "TARGET_THEM", target_gender.him) - use_1p = replacetext(use_1p, "TARGET_THEIR", target_gender.his) - use_1p = replacetext(use_1p, "TARGET_SELF", target_gender.self) - use_1p = replacetext(use_1p, "TARGET", "\the [target]") - else - use_1p = get_emote_message_1p(user, null, extra_params) - use_1p = capitalize(use_1p) - - if(emote_message_3p) - if(target && emote_message_3p_target) - use_3p = get_emote_message_3p(user, target, extra_params) - use_3p = replacetext(use_3p, "TARGET_THEM", target_gender.him) - use_3p = replacetext(use_3p, "TARGET_THEIR", target_gender.his) - use_3p = replacetext(use_3p, "TARGET_SELF", target_gender.self) - use_3p = replacetext(use_3p, "TARGET", "\the [target]") - else - use_3p = get_emote_message_3p(user, null, extra_params) - use_3p = replacetext(use_3p, "USER_THEM", user_gender.him) - use_3p = replacetext(use_3p, "USER_THEIR", user_gender.his) - use_3p = replacetext(use_3p, "USER_SELF", user_gender.self) - use_3p = replacetext(use_3p, "USER", "\the [user]") - use_3p = capitalize(use_3p) + if(!finalize_target(user, target)) + to_chat(user, SPAN_WARNING("You cannot see a '[extra_params]' within range.")) + + if(mandatory_targetted_emote && !target) + to_chat(user, SPAN_WARNING("You can't do that to thin air.")) + return FALSE + + var/use_1p = get_emote_message_1p(user, target, extra_params) + if(use_1p) + if(target) + use_1p = emote_replace_target_tokens(use_1p, target) + use_1p = "[capitalize_proper_html(emote_replace_user_tokens(use_1p, user))]" + + var/use_3p = get_emote_message_3p(user, target, extra_params) + if(use_3p) + if(target) + use_3p = emote_replace_target_tokens(use_3p, target) + use_3p = "[emote_replace_user_tokens(use_3p, user)]" + + var/use_radio = get_radio_message(user) + if(use_radio) + if(target) + use_radio = emote_replace_target_tokens(use_radio, target) + use_radio = emote_replace_user_tokens(use_radio, user) + + var/use_range = emote_range + if (!use_range) + use_range = world.view if(ismob(user)) var/mob/M = user if(message_type == AUDIBLE_MESSAGE) if(isliving(user)) var/mob/living/L = user - if(L.silent) - M.visible_message(message = "[user] opens their mouth silently!", self_message = "You cannot say anything!", blind_message = emote_message_impaired, checkghosts = /datum/client_preference/ghost_sight) - return - else - M.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, checkghosts = /datum/client_preference/ghost_sight) + if(HAS_STATUS(L, STAT_SILENCE)) + M.visible_message(message = "[user] opens their mouth silently!", self_message = "You cannot say anything!", blind_message = emote_message_impaired, check_ghosts = /datum/client_preference/ghost_sight) + return FALSE + M.audible_message(message = use_3p, self_message = use_1p, deaf_message = emote_message_impaired, hearing_distance = use_range, check_ghosts = /datum/client_preference/ghost_sight, radio_message = use_radio) else - M.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, checkghosts = /datum/client_preference/ghost_sight) + M.visible_message(message = use_3p, self_message = use_1p, blind_message = emote_message_impaired, range = use_range, check_ghosts = /datum/client_preference/ghost_sight) do_extra(user, target) do_sound(user) + return TRUE + +/decl/emote/proc/get_radio_message(var/atom/user) + if(emote_message_radio_synthetic && check_synthetic(user)) + return emote_message_radio_synthetic + return emote_message_radio /decl/emote/proc/do_extra(var/atom/user, var/atom/target) return /decl/emote/proc/do_sound(var/atom/user) - if(emote_sound) - var/sound_to_play = emote_sound - if(islist(emote_sound)) - sound_to_play = emote_sound[user.gender] || emote_sound - sound_to_play = pick(sound_to_play) - return playsound(user.loc, sound_to_play, 50, 0) - -/decl/emote/proc/check_user(var/atom/user) + + var/turf/user_turf = get_turf(user) + if(!istype(user_turf)) + return + + var/list/use_sound = get_emote_sound(user) + if(!islist(use_sound) || length(use_sound) < 2) + return + + var/sound_to_play = use_sound["sound"] + if(sound_to_play) + if(islist(sound_to_play)) + if(sound_to_play[user.gender]) + sound_to_play = sound_to_play[user.gender] + if(islist(sound_to_play) && length(sound_to_play)) + sound_to_play = pick(sound_to_play) + if(sound_to_play) + playsound(user.loc, sound_to_play, use_sound["vol"], 0) + + var/sound_to_broadcast = use_sound["broadcast"] + if(!sound_to_broadcast) + return + + // We can't always use GetConnectedZlevels() here because it includes horizontally connected z-levels, which don't work well with our distance checking. + var/list/affected_levels + if(isnull(broadcast_distance)) + affected_levels = SSmapping.get_connected_levels(user_turf.z) + else + affected_levels = list(user_turf.z) + // Climb to the top of the stack. + var/turf/checking = user_turf + while(checking && HasAbove(checking.z)) + checking = GetAbove(checking) + affected_levels += checking.z + // Fall to the bottom of the stack. + checking = user_turf + while(checking && HasBelow(checking.z)) + checking = GetBelow(checking) + affected_levels += checking.z + + var/list/close_listeners = hearers(world.view, user_turf) + for(var/listener in player_list) + var/turf/T = get_turf(listener) + if(!istype(T) || !(T.z in affected_levels) || (listener in close_listeners)) + continue + var/turf/reference_point = locate(T.x, T.y, user_turf.z) + if(!reference_point) + continue + var/direction = get_dir(reference_point, user_turf) + if(!direction) + continue + if(!isnull(broadcast_distance) && get_dist(reference_point, user_turf) > broadcast_distance) + continue + broadcast_emote_to(sound_to_broadcast, listener, user_turf.z, direction) + +/decl/emote/proc/broadcast_emote_to(var/send_sound, var/mob/target, var/origin_z, var/direction) + var/turf/sound_origin = get_turf(target) + target.playsound_local(get_step(sound_origin, direction) || sound_origin, send_sound, broadcast_volume) return TRUE +/decl/emote/proc/mob_can_use(mob/living/user, assume_available = FALSE) + return istype(user) && user.stat != DEAD && (assume_available || (type in user.get_default_emotes())) + /decl/emote/proc/can_target() return (emote_message_1p_target || emote_message_3p_target) /decl/emote/dd_SortValue() return key + +/decl/emote/proc/check_synthetic(var/mob/living/user) + . = istype(user) && user.isSynthetic() + if(!. && message_type == AUDIBLE_MESSAGE && user.should_have_organ(BP_LUNGS)) + var/obj/item/organ/internal/lungs/L = GET_INTERNAL_ORGAN(user, BP_LUNGS) + if(BP_IS_PROSTHETIC(L)) + . = TRUE diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm index 95c0bdc63229..b91444de9608 100644 --- a/code/modules/emotes/emote_mob.dm +++ b/code/modules/emotes/emote_mob.dm @@ -1,24 +1,55 @@ -/mob/proc/can_emote(var/emote_type) +/mob + var/next_emote + var/next_emote_refresh + var/last_emote_summary + +/mob/proc/can_emote(emote_type, show_message) + . = check_mob_can_emote(emote_type) + if(!. && show_message) + to_chat(show_message, SPAN_WARNING("You cannot currently [emote_type == AUDIBLE_MESSAGE ? "audibly" : "visually"] emote!")) + +/mob/proc/check_mob_can_emote(var/emote_type) + SHOULD_CALL_PARENT(TRUE) return (stat == CONSCIOUS) -/mob/living/can_emote(var/emote_type) - return (..() && !(silent && emote_type == AUDIBLE_MESSAGE)) +/mob/living/check_mob_can_emote(var/emote_type) + return ..() && !(HAS_STATUS(src, STAT_SILENCE) && emote_type == AUDIBLE_MESSAGE) +/mob/living/brain/check_mob_can_emote(var/emote_type) + return ..() && istype(get_container(), /obj/item/organ/internal/brain_interface) + +#define EMOTE_REFRESH_SPAM_COOLDOWN (5 SECONDS) /mob/proc/emote(var/act, var/m_type, var/message) - // s-s-snowflake - if(src.stat == DEAD && act != "deathgasp") + set waitfor = FALSE + + if(stat == DEAD && act != "deathgasp") return + + var/decl/emote/use_emote + if(ispath(act, /decl/emote)) + use_emote = GET_DECL(act) + m_type = use_emote.message_type + + var/show_message_to if(usr == src) //client-called emote - if (client && (client.prefs.muted & MUTE_IC)) - to_chat(src, "You cannot send IC messages (muted).") + if (client?.prefs?.muted & MUTE_IC) + to_chat(src, SPAN_WARNING("You cannot send IC messages (muted).")) return - if(act == "help") - to_chat(src,"Usable emotes: [english_list(usable_emotes)]") + if(world.time < next_emote) + to_chat(src, SPAN_WARNING("You cannot use another emote yet.")) return - if(!can_emote(m_type)) - to_chat(src, "You cannot currently [m_type == AUDIBLE_MESSAGE ? "audibly" : "visually"] emote!") + if(act == "help") + if(world.time >= next_emote_refresh) + var/list/usable_emotes = list() + next_emote_refresh = world.time + EMOTE_REFRESH_SPAM_COOLDOWN + for(var/emote in get_default_emotes()) + var/decl/emote/emote_datum = GET_DECL(emote) + if(emote_datum.mob_can_use(src, assume_available = TRUE)) + usable_emotes[emote_datum.key] = emote_datum + last_emote_summary = english_list(sortTim(usable_emotes, /proc/cmp_text_asc, associative = TRUE)) + to_chat(src, "Usable emotes: [last_emote_summary].") return if(act == "me") @@ -36,29 +67,44 @@ m_type = AUDIBLE_MESSAGE return custom_emote(m_type, message) + show_message_to = usr + + if(!can_emote(m_type, show_message_to)) + return + var/splitpoint = findtext(act, " ") if(splitpoint > 0) var/tempstr = act act = copytext(tempstr,1,splitpoint) message = copytext(tempstr,splitpoint+1,0) - var/decl/emote/use_emote = usable_emotes[act] if(!use_emote) - to_chat(src, "Unknown emote '[act]'. Type say *help for a list of usable emotes.") + use_emote = get_emote_by_key(act) + + if(!istype(use_emote)) + to_chat(show_message_to, SPAN_WARNING("Unknown emote '[act]'. Type say *help for a list of usable emotes.")) + return + + if(!use_emote.mob_can_use(src)) + to_chat(show_message_to, SPAN_WARNING("You cannot use the emote '[act]'. Type say *help for a list of usable emotes.")) return if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS) return - if(use_emote.message_type == AUDIBLE_MESSAGE && is_muzzled()) - audible_message("\The [src] makes a muffled sound.") + if(use_emote.message_type == AUDIBLE_MESSAGE && get_item_blocking_speech()) + audible_message("\The [src] [use_emote.emote_message_muffled || "makes a muffled sound."]") return - else - use_emote.do_emote(src, message) - for (var/obj/item/implant/I in src) - if (I.implanted) - I.trigger(act, src) + next_emote = world.time + use_emote.emote_delay + use_emote.do_emote(src, message) + + for (var/obj/item/implant/implant in src) + if(!implant.implanted) + continue + implant.trigger(act, src) + +#undef EMOTE_REFRESH_SPAM_COOLDOWN /mob/proc/format_emote(var/emoter = null, var/message = null) var/pretext @@ -72,8 +118,6 @@ if(!message || !emoter) return - message = html_decode(message) - name_anchor = findtext(message, anchor_char) if(name_anchor > 0) // User supplied emote with visible_emote token (default ^) pretext = copytext(message, 1, name_anchor) @@ -94,11 +138,7 @@ if(end_char != " ") pretext += " " - // Grab the last character of the emote message. - end_char = copytext(subtext, length(subtext), length(subtext) + 1) - if(!(end_char in list(".", "?", "!", "\"", "-", "~"))) // gotta include ~ for all you fucking weebs - // No punctuation supplied. Tack a period on the end. - subtext += "." + handle_autopunctuation(subtext) // Add a space to the subtext, unless it begins with an apostrophe or comma. if(subtext != ".") @@ -108,17 +148,13 @@ if(start_char != "," && start_char != "'") subtext = " " + subtext - pretext = capitalize(html_encode(pretext)) - nametext = html_encode(nametext) - subtext = html_encode(subtext) // Store the player's name in a nice bold, naturalement nametext = "[emoter]" - return pretext + nametext + subtext + return capitalize(pretext) + nametext + subtext /mob/proc/custom_emote(var/m_type = VISIBLE_MESSAGE, var/message = null) - - if((usr && stat) || (!use_me && usr == src)) - to_chat(src, "You are unable to emote.") + set waitfor = FALSE + if(!can_emote(m_type, src)) return var/input @@ -127,27 +163,30 @@ else input = message - if(input) - message = format_emote(src, message) - else + if(!input) return + message = trim(html_encode(message)) + message = filter_modify_message(message) + message = format_emote(src, message) + message = trim(html_decode(message)) + if (message) log_emote("[name]/[key] : [message]") //do not show NPC animal emotes to ghosts, it turns into hellscape var/check_ghosts = client ? /datum/client_preference/ghost_sight : null if(m_type == VISIBLE_MESSAGE) - visible_message(message, checkghosts = check_ghosts) + visible_message(message, check_ghosts = check_ghosts) else - audible_message(message, checkghosts = check_ghosts) + audible_message(message, check_ghosts = check_ghosts) // Specific mob type exceptions below. /mob/living/silicon/ai/emote(var/act, var/type, var/message) var/obj/machinery/hologram/holopad/T = src.holo if(T && T.masters[src]) //Is the AI using a holopad? src.holopad_emote(message) - else //Emote normally, then. - ..() + return + return ..() /mob/living/captive_brain/emote(var/message) return diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index bb86204d2f8b..b32701c519b4 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -1,6 +1,6 @@ -GLOBAL_VAR_INIT(total_runtimes, 0) -GLOBAL_VAR_INIT(total_runtimes_skipped, 0) -GLOBAL_VAR_INIT(actual_error_file_line, new/regex("^%% (.*?),(.*?) %% ")) +var/global/total_runtimes = 0 +var/global/total_runtimes_skipped = 0 +var/global/regex/actual_error_file_line #ifdef DEBUG /world/Error(exception/E) @@ -8,6 +8,40 @@ GLOBAL_VAR_INIT(actual_error_file_line, new/regex("^%% (.*?),(.*?) %% ")) log_world("\[[time_stamp()]] Uncaught exception: [E]") return ..() + //this is snowflake because of a byond bug (ID:2306577), do not attempt to call non-builtin procs in this block OR BEFORE IT + if(copytext(E.name, 1, 32) == "Maximum recursion level reached")//32 == length() of that string + 1 + var/list/proc_path_to_count = list() + var/crashed = FALSE + try + var/callee/stack_entry = caller + while(!isnull(stack_entry)) + proc_path_to_count[stack_entry.proc] += 1 + stack_entry = stack_entry.caller + catch + //union job. avoids crashing the stack again + //I just do not trust this construct to work reliably + crashed = TRUE + + var/list/split = splittext(E.desc, "\n") + for (var/i in 1 to split.len) + if (split[i] != "" || copytext(split[1], 1, 2) != " ") + split[i] = " [split[i]]" + split += "--Stack Info [crashed ? "(Crashed, may be missing info)" : ""]:" + for(var/path in proc_path_to_count) + split += " [path] = [proc_path_to_count[path]]" + E.desc = jointext(split, "\n") + // expanding the first line of log_world to avoid hitting the stack limit again + to_file(world.log, "\[[time2text(station_time_in_ticks, "hh:mm:ss")]] Runtime Error: [E.name]\n[E.desc]") + //log to world while intentionally triggering the byond bug. this does not DO anything, it just errors + //(seemingly because log_info_line is deep enough to hit the raised limit 516.1667 introduced) + log_world("runtime error: [E.name]\n[E.desc]\n[log_info_line(usr)]\n[log_info_line(src)]") + //if we got to here without silently ending, the byond bug has been fixed. + log_world("The \"bug\" with recursion runtimes has been fixed. Please remove the snowflake check from world/Error in [__FILE__]:[__LINE__]") + return //this will never happen. + + if (!global.actual_error_file_line) + global.actual_error_file_line = regex("^%% (.*?),(.*?) %% ") + var/static/list/error_last_seen = list() var/static/list/error_cooldown = list() /* Error_cooldown items will either be positive(cooldown time) or negative(silenced error) If negative, starts at -1, and goes down by 1 each time that error gets skipped*/ @@ -15,12 +49,12 @@ GLOBAL_VAR_INIT(actual_error_file_line, new/regex("^%% (.*?),(.*?) %% ")) if(!error_last_seen) // A runtime is occurring too early in start-up initialization return ..() - GLOB.total_runtimes++ + global.total_runtimes++ var/efile = E.file var/eline = E.line - var/regex/actual_error_file_line = GLOB.actual_error_file_line + var/regex/actual_error_file_line = global.actual_error_file_line if(actual_error_file_line.Find(E.name)) efile = actual_error_file_line.group[1] eline = actual_error_file_line.group[2] @@ -36,22 +70,14 @@ GLOBAL_VAR_INIT(actual_error_file_line, new/regex("^%% (.*?),(.*?) %% ")) if(cooldown < 0) error_cooldown[erroruid]-- //Used to keep track of skip count for this error - GLOB.total_runtimes_skipped++ + global.total_runtimes_skipped++ return //Error is currently silenced, skip handling it //Handle cooldowns and silencing spammy errors var/silencing = FALSE - // We can runtime before config is initialized because BYOND initialize objs/map before a bunch of other stuff happens. - // This is a bunch of workaround code for that. Hooray! - - var/configured_error_cooldown = initial(config.error_cooldown) - var/configured_error_limit = initial(config.error_limit) - var/configured_error_silence_time = initial(config.error_silence_time) - if(config) - configured_error_cooldown = config.error_cooldown - configured_error_limit = config.error_limit - configured_error_silence_time = config.error_silence_time - + var/configured_error_cooldown = get_config_value(/decl/config/num/debug_error_cooldown) + var/configured_error_limit = get_config_value(/decl/config/num/debug_error_limit) + var/configured_error_silence_time = get_config_value(/decl/config/num/debug_error_silence_time) //Each occurence of an unique error adds to its cooldown time... cooldown = max(0, cooldown - (world.time - last_seen)) + configured_error_cooldown @@ -66,7 +92,8 @@ GLOBAL_VAR_INIT(actual_error_file_line, new/regex("^%% (.*?),(.*?) %% ")) error_cooldown[erroruid] = 0 if(skipcount > 0) to_world_log("\[[time_stamp()]] Skipped [skipcount] runtimes in [erroruid].") - GLOB.error_cache.log_error(E, skip_count = skipcount) + if(istype(global.error_cache)) + global.error_cache.log_error(E, skip_count = skipcount) error_last_seen[erroruid] = world.time error_cooldown[erroruid] = cooldown @@ -99,11 +126,13 @@ GLOBAL_VAR_INIT(actual_error_file_line, new/regex("^%% (.*?),(.*?) %% ")) desclines.Add(usrinfo) if(silencing) desclines += " (This error will now be silenced for [configured_error_silence_time / 600] minutes)" - if(GLOB.error_cache) - GLOB.error_cache.log_error(E, desclines) + if(istype(global.error_cache)) // istype() rather than nullcheck to avoid new ordering weirdness + global.error_cache.log_error(E, desclines) - to_world_log("\[[time_stamp()]] Runtime in [erroruid]: [E]") + error_write_log("\[[time_stamp()]] Runtime in [erroruid]: [E]") for(var/line in desclines) - to_world_log(line) + error_write_log(line) -#endif +/proc/error_write_log(msg) + to_world_log(msg) +#endif \ No newline at end of file diff --git a/code/modules/error_handler/error_reporting.dm b/code/modules/error_handler/error_reporting.dm deleted file mode 100644 index 9fadab06bc69..000000000000 --- a/code/modules/error_handler/error_reporting.dm +++ /dev/null @@ -1,23 +0,0 @@ -// this proc will only work with DEBUG enabled -#ifdef DEBUG - -/hook/roundend/proc/send_runtimes_to_ircbot() - if(!revdata.revision) return // we can't do much useful if we don't know what we are - var/list/errors = list() - for(var/erruid in GLOB.error_cache.error_sources) - var/datum/error_viewer/error_source/e = GLOB.error_cache.error_sources[erruid] - var/datum/error_viewer/error_entry/err = e.errors[1] - - var/data = list( - id = erruid, - name = err.info_name, - info = err.info - ) - - errors[++errors.len] = list2params(data) - - runtimes2irc(list2params(errors), revdata.revision) - - return 1 - -#endif diff --git a/code/modules/error_handler/error_viewer.dm b/code/modules/error_handler/error_viewer.dm index 95c9b37170f4..0aae86e2df76 100644 --- a/code/modules/error_handler/error_viewer.dm +++ b/code/modules/error_handler/error_viewer.dm @@ -8,10 +8,10 @@ // right here: #ifdef DEBUG -GLOBAL_DATUM_INIT(error_cache, /datum/error_viewer/error_cache, new) +var/global/datum/error_viewer/error_cache/error_cache = new #else // If debugging is disabled, there's nothing useful to log, so don't bother. -GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) +var/global/datum/error_viewer/error_cache/error_cache #endif // - error_source datums exist for each line (of code) that generates an error, @@ -83,16 +83,15 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) if (linear) back_to_param += ";viewruntime_linear=1" - return "[linktext]" + return "[linktext]" /datum/error_viewer/error_cache var/list/errors = list() var/list/error_sources = list() - var/list/errors_silenced = list() /datum/error_viewer/error_cache/show_to(user, datum/error_viewer/back_to, linear) var/html = build_header() - html += "[GLOB.total_runtimes] runtimes, [GLOB.total_runtimes_skipped] skipped

          " + html += "[global.total_runtimes] runtimes, [global.total_runtimes_skipped] skipped

          " if (!linear) html += "organized | [make_link("linear", null, 1)]
          " var/datum/error_viewer/error_source/error_source @@ -127,14 +126,9 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) // Show the error to admins with debug messages turned on, but only if one // from the same source hasn't been shown too recently if (error_source.next_message_at <= world.time) - var/const/viewtext = "\[view]" // Nesting these in other brackets went poorly + //var/const/viewtext = "\[view]" // Nesting these in other brackets went poorly //log_debug("Runtime in [e.file], line [e.line]: [html_encode(e.name)] [error_entry.make_link(viewtext)]") - var/err_msg_delay - if(config) - err_msg_delay = config.error_msg_delay - else - err_msg_delay = initial(config.error_msg_delay) - error_source.next_message_at = world.time + err_msg_delay + error_source.next_message_at = world.time + get_config_value(/decl/config/num/debug_error_msg_delay) /datum/error_viewer/error_source var/list/errors = list() @@ -149,7 +143,7 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) /datum/error_viewer/error_source/show_to(user, datum/error_viewer/back_to, linear) if (!istype(back_to)) - back_to = GLOB.error_cache + back_to = global.error_cache var/html = build_header(back_to) for (var/datum/error_viewer/error_entry/error_entry in errors) @@ -200,14 +194,14 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache) var/html = build_header(back_to, linear) html += "[name]
          [desc]
          " if (usr_ref) - html += "
          usr: VV" - html += " PP" - html += " Follow" + html += "
          usr: VV" + html += " PP" + html += " Follow" if (istype(usr_loc)) - html += "
          usr.loc: VV" - html += " JMP" + html += "
          usr.loc: VV" + html += " JMP" browse_to(user, html) /datum/error_viewer/error_entry/make_link(linktext, datum/error_viewer/back_to, linear) - return is_skip_count ? name : ..() + return is_skip_count ? name : ..() \ No newline at end of file diff --git a/code/modules/events/ailments.dm b/code/modules/events/ailments.dm new file mode 100644 index 000000000000..cf49cd2110d1 --- /dev/null +++ b/code/modules/events/ailments.dm @@ -0,0 +1,30 @@ +/datum/event/ailments/start() + var/list/candidates = list() + for(var/mob/living/human/H in global.living_mob_list_) + if(H.client && !H.has_mob_modifier(/decl/mob_modifier/stasis)) + candidates += H + if(!length(candidates)) + return + candidates = shuffle(candidates) + var/create_ailments = min(length(candidates), rand(1,3)) + for(var/i = 1 to length(candidates)) + var/mob/living/human/H = candidates[i] + var/list/organs = shuffle(H.get_organs()) + for(var/ii = 1 to length(organs)) + var/obj/item/organ/O = organs[ii] + var/list/possible_ailments = O.get_possible_ailments() + if(!length(possible_ailments)) + continue + possible_ailments = shuffle(possible_ailments) + var/gave_ailment = FALSE + for(var/iii = 1 to length(possible_ailments)) + var/datum/ailment/ailment = possible_ailments[iii] + if(O.add_ailment(ailment)) + log_debug("Random event gave [ailment] to [key_name(H)].") + create_ailments-- + if(!create_ailments) + return + gave_ailment = TRUE + break + if(gave_ailment) + break diff --git a/code/modules/events/apc_damage.dm b/code/modules/events/apc_damage.dm index d3badc5c277e..137847f0313c 100644 --- a/code/modules/events/apc_damage.dm +++ b/code/modules/events/apc_damage.dm @@ -2,7 +2,7 @@ var/apcSelectionRange = 25 /datum/event/apc_damage/start() - var/obj/machinery/power/apc/A = acquire_random_apc() + var/obj/machinery/apc/A = acquire_random_apc() var/severity_range = 0 switch(severity) @@ -13,7 +13,7 @@ if(EVENT_LEVEL_MAJOR) severity_range = 15 - for(var/obj/machinery/power/apc/apc in range(severity_range,A)) + for(var/obj/machinery/apc/apc in range(severity_range,A)) if(is_valid_apc(apc)) apc.emagged = 1 apc.update_icon() @@ -22,7 +22,7 @@ var/list/possibleEpicentres = list() var/list/apcs = list() - for(var/obj/effect/landmark/newEpicentre in landmarks_list) + for(var/obj/abstract/landmark/newEpicentre in global.all_landmarks) if(newEpicentre.name == "lightsout") possibleEpicentres += newEpicentre @@ -30,12 +30,12 @@ return var/epicentre = pick(possibleEpicentres) - for(var/obj/machinery/power/apc/apc in range(epicentre,apcSelectionRange)) + for(var/obj/machinery/apc/apc in range(epicentre,apcSelectionRange)) if(is_valid_apc(apc)) apcs += apc // Greatly increase the chance for APCs in maintenance areas to be selected var/area/A = get_area(apc) - if(istype(A,/area/maintenance)) + if(istype(A) && (A.area_flags & AREA_FLAG_MAINTENANCE)) apcs += apc apcs += apc @@ -44,6 +44,6 @@ return pick(apcs) -/datum/event/apc_damage/proc/is_valid_apc(var/obj/machinery/power/apc/apc) +/datum/event/apc_damage/proc/is_valid_apc(var/obj/machinery/apc/apc) var/turf/T = get_turf(apc) - return !apc.is_critical && !apc.emagged && T && (T.z in GLOB.using_map.player_levels) + return !apc.is_critical && !apc.emagged && T && isPlayerLevel(T.z) diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm deleted file mode 100644 index 44f6439bd7fa..000000000000 --- a/code/modules/events/blob.dm +++ /dev/null @@ -1,27 +0,0 @@ -/datum/event/blob - announceWhen = 12 - - var/obj/effect/blob/core/Blob - -/datum/event/blob/announce() - level_seven_announcement() - -/datum/event/blob/start() - var/turf/T = pick_subarea_turf(/area/maintenance, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) - if(!T) - log_and_message_admins("Blob failed to find a viable turf.") - kill() - return - - log_and_message_admins("Blob spawned in \the [get_area(T)]", location = T) - Blob = new /obj/effect/blob/core(T) - for(var/i = 1; i < rand(3, 4), i++) - Blob.Process() - -/datum/event/blob/tick() - if(!Blob || !Blob.loc) - Blob = null - kill() - return - if(IsMultiple(activeFor, 3)) - Blob.Process() diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index a273cedaa1c1..76d24cbcb800 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -19,8 +19,8 @@ if(!vendingMachines.len) kill() return - var/weakref/W = pick_n_take(vendingMachines) - originMachine = W.resolve() + var/weakref/vendor_ref = pick_n_take(vendingMachines) + originMachine = vendor_ref.resolve() originMachine.shut_up = 0 originMachine.shoot_inventory = 1 originMachine.shooting_chance = 15 @@ -31,11 +31,11 @@ return if(IsMultiple(activeFor, 5) && prob(15)) - var/weakref/W = pick(vendingMachines) - vendingMachines -= W - var/obj/machinery/vending/infectedMachine = W.resolve() + var/weakref/vendor_ref = pick(vendingMachines) + vendingMachines -= vendor_ref + var/obj/machinery/vending/infectedMachine = vendor_ref.resolve() if(infectedMachine) - infectedVendingMachines += W + infectedVendingMachines += vendor_ref infectedMachine.shut_up = 0 infectedMachine.shoot_inventory = 1 @@ -49,15 +49,16 @@ "You don't want to buy anything? Yeah, well I didn't want to buy your mom either.")) /datum/event/brand_intelligence/end() - originMachine.shut_up = 1 - originMachine.shooting_chance = initial(originMachine.shooting_chance) - for(var/weakref/W in infectedVendingMachines) - var/obj/machinery/vending/infectedMachine = W.resolve() + if(istype(originMachine)) + originMachine.shut_up = 1 + originMachine.shooting_chance = initial(originMachine.shooting_chance) + originMachine = null + for(var/weakref/vendor_ref in infectedVendingMachines) + var/obj/machinery/vending/infectedMachine = vendor_ref.resolve() if(!infectedMachine) continue infectedMachine.shut_up = 1 infectedMachine.shoot_inventory = 0 command_announcement.Announce("All traces of the rampant brand intelligence have disappeared from the systems.", "[location_name()] Firewall Subroutines") - originMachine = null infectedVendingMachines.Cut() vendingMachines.Cut() \ No newline at end of file diff --git a/code/modules/events/camera_damage.dm b/code/modules/events/camera_damage.dm index 1c99af107b7c..c7243e71c613 100644 --- a/code/modules/events/camera_damage.dm +++ b/code/modules/events/camera_damage.dm @@ -15,7 +15,7 @@ for(var/obj/machinery/camera/cam in range(severity_range,C)) if(is_valid_camera(cam)) if(prob(2*severity)) - cam.destroy() + cam.take_damage(100, ELECTROCUTE, silent = TRUE) else if(!cam.wires.IsIndexCut(CAMERA_WIRE_POWER)) cam.wires.CutWireIndex(CAMERA_WIRE_POWER) @@ -36,4 +36,4 @@ /datum/event/camera_damage/proc/is_valid_camera(var/obj/machinery/camera/C) // Only return a functional camera, not installed in a silicon, and that exists somewhere players have access var/turf/T = get_turf(C) - return T && C.can_use() && !istype(C.loc, /mob/living/silicon) && (T.z in GLOB.using_map.player_levels) + return T && C.can_use() && isPlayerLevel(T.z) diff --git a/code/modules/events/carp_migration.dm b/code/modules/events/carp_migration.dm index f37d1afae6f9..a2cf955a797b 100644 --- a/code/modules/events/carp_migration.dm +++ b/code/modules/events/carp_migration.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST_INIT(carp_count,list())// a list of Z levels (string), associated with a list of all the carp spawned by carp events +var/global/list/carp_count = list() // a list of Z levels (string), associated with a list of all the carp spawned by carp events /datum/event/carp_migration announceWhen = 45 @@ -15,8 +15,8 @@ GLOBAL_LIST_INIT(carp_count,list())// a list of Z levels (string), associated wi /datum/event/carp_migration/proc/count_carps() var/total_carps var/local_carps - for(var/Z in GLOB.carp_count) - var/list/L = GLOB.carp_count[Z] + for(var/Z in global.carp_count) + var/list/L = global.carp_count[Z] total_carps += L.len if(text2num(Z) in affecting_z) local_carps += L.len @@ -32,7 +32,7 @@ GLOBAL_LIST_INIT(carp_count,list())// a list of Z levels (string), associated wi announcement = "A massive migration of unknown biological entities has been detected in the vicinity of the [location_name()]. Exercise external operations with caution." else announcement = "A large migration of unknown biological entities has been detected in the vicinity of the [location_name()]. Caution is advised." - + command_announcement.Announce(announcement, "[location_name()] Sensor Array", zlevels = affecting_z) /datum/event/carp_migration/tick() @@ -48,7 +48,7 @@ GLOBAL_LIST_INIT(carp_count,list())// a list of Z levels (string), associated wi var/Z = pick(affecting_z) if(!direction) - direction = pick(GLOB.cardinal) + direction = pick(global.cardinal) if(!speed) speed = rand(1,3) @@ -57,24 +57,24 @@ GLOBAL_LIST_INIT(carp_count,list())// a list of Z levels (string), associated wi var/I = 0 while(I < n) var/turf/T = get_random_edge_turf(direction,TRANSITIONEDGE + 2, Z) - if(istype(T,/turf/space)) + if(isspaceturf(T)) var/mob/living/simple_animal/hostile/M if(prob(96)) M = new /mob/living/simple_animal/hostile/carp(T) else M = new /mob/living/simple_animal/hostile/carp/pike(T) I += 3 - GLOB.death_event.register(M,src,/datum/event/carp_migration/proc/reduce_carp_count) - GLOB.destroyed_event.register(M,src,/datum/event/carp_migration/proc/reduce_carp_count) - LAZYADD(GLOB.carp_count["[Z]"], M) + events_repository.register(/decl/observ/death, M,src, TYPE_PROC_REF(/datum/event/carp_migration, reduce_carp_count)) + events_repository.register(/decl/observ/destroyed, M,src, TYPE_PROC_REF(/datum/event/carp_migration, reduce_carp_count)) + LAZYADD(global.carp_count[num2text(Z)], M) spawned_carp ++ - M.throw_at(get_random_edge_turf(GLOB.reverse_dir[direction],TRANSITIONEDGE + 2, Z), 250, speed, callback = CALLBACK(src,/datum/event/carp_migration/proc/check_gib,M)) + M.throw_at(get_random_edge_turf(global.reverse_dir[direction],TRANSITIONEDGE + 2, Z), 250, speed, callback = CALLBACK(src, TYPE_PROC_REF(/datum/event/carp_migration, check_gib), M)) I++ if(no_show) break /datum/event/carp_migration/proc/check_gib(var/mob/living/simple_animal/hostile/carp/M) //awesome road kills - if(M.health <= 0 && prob(60)) + if(M.current_health <= 0 && prob(60)) M.gib() /proc/get_random_edge_turf(var/direction, var/clearance = TRANSITIONEDGE + 1, var/Z) @@ -93,12 +93,12 @@ GLOBAL_LIST_INIT(carp_count,list())// a list of Z levels (string), associated wi /datum/event/carp_migration/proc/reduce_carp_count(var/mob/M) for(var/Z in affecting_z) - var/list/L = GLOB.carp_count["[Z]"] + var/list/L = global.carp_count[num2text(Z)] if(M in L) LAZYREMOVE(L,M) break - GLOB.death_event.unregister(M,src,/datum/event/carp_migration/proc/reduce_carp_count) - GLOB.destroyed_event.unregister(M,src,/datum/event/carp_migration/proc/reduce_carp_count) + events_repository.unregister(/decl/observ/death, M,src, TYPE_PROC_REF(/datum/event/carp_migration, reduce_carp_count)) + events_repository.unregister(/decl/observ/destroyed, M,src, TYPE_PROC_REF(/datum/event/carp_migration, reduce_carp_count)) /datum/event/carp_migration/end() log_debug("Carp migration event spawned [spawned_carp] carp.") diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index 936c31f576a4..c350b8db73d8 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -1,12 +1,12 @@ /datum/event/communications_blackout/announce() var/alert = pick( "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you*%fj00)`5vc-BZZT", \ - "Ionospheric anomalies detected. Temporary telecommunication failu*3mga;b4;'1v-BZZZT", \ + "Ionospheric anomalies detected. Temporary telecommunication failu*3mga;b4;'1v�-BZZZT", \ "Ionospheric anomalies detected. Temporary telec#MCi46:5.;@63-BZZZZT", \ "Ionospheric anomalies dete'fZ\\kg5_0-BZZZZZT", \ - "Ionospheri:% MCayj^j<.3-BZZZZZZT", \ - "#4nd%;f4y6,>%-BZZZZZZZT") + "Ionospheri:%� MCayj^j<.3-BZZZZZZT", \ + "#4nd%;f4y6,>�%-BZZZZZZZT") - for(var/mob/living/silicon/ai/A in GLOB.player_list) //AIs are always aware of communication blackouts. + for(var/mob/living/silicon/ai/A in global.player_list) //AIs are always aware of communication blackouts. if(A.z in affecting_z) to_chat(A, "
          ") to_chat(A, "[alert]") @@ -15,10 +15,8 @@ if(prob(80)) //Announce most of the time, just not always to give some wiggle room for possible sabotages. command_announcement.Announce(alert, new_sound = sound('sound/misc/interference.ogg', volume=25), zlevels = affecting_z) - /datum/event/communications_blackout/start() - for(var/obj/machinery/telecomms/T in telecomms_list) + for(var/obj/machinery/network/telecomms_hub/T in global.telecomms_hubs) if(T.z in affecting_z) if(prob(T.outage_probability)) T.overloaded_for = max(severity * rand(90, 120), T.overloaded_for) - diff --git a/code/modules/events/computer_damage.dm b/code/modules/events/computer_damage.dm index 9cf56ce1e7c9..94d3f278745d 100644 --- a/code/modules/events/computer_damage.dm +++ b/code/modules/events/computer_damage.dm @@ -17,4 +17,4 @@ if(prob(50)) victim.visible_message("[victim] emits some ominous clicks.") var/obj/item/stock_parts/computer/hard_drive/HDD = victim.get_component_of_type(/obj/item/stock_parts/computer/hard_drive) - HDD.take_damage(0.5 * HDD.health) + HDD.take_damage(0.5 * HDD.current_health) diff --git a/code/modules/events/computer_update.dm b/code/modules/events/computer_update.dm index 6b44800abf02..02c5b291f91d 100644 --- a/code/modules/events/computer_update.dm +++ b/code/modules/events/computer_update.dm @@ -12,7 +12,7 @@ updates_to_install = rand(500000, 1000000) for(var/obj/C in (SSobj.processing + SSmachines.machinery)) - if((C.z in GLOB.using_map.station_levels)) - var/datum/extension/interactive/ntos/os = get_extension(C, /datum/extension/interactive/ntos) + if(isStationLevel(C.z)) + var/datum/extension/interactive/os/os = get_extension(C, /datum/extension/interactive/os) if(os && os.get_network_status() && os.receives_updates) os.updates = updates_to_install diff --git a/code/modules/events/disposals_explosion.dm b/code/modules/events/disposals_explosion.dm index 32361866c6c9..a11a26fa5bf9 100644 --- a/code/modules/events/disposals_explosion.dm +++ b/code/modules/events/disposals_explosion.dm @@ -24,13 +24,13 @@ // Event listener for the marked pipe's destruction /datum/event/disposals_explosion/proc/pipe_destroyed() - GLOB.destroyed_event.unregister(bursting_pipe, src, .proc/pipe_destroyed) + events_repository.unregister(/decl/observ/destroyed, bursting_pipe, src, PROC_REF(pipe_destroyed)) bursting_pipe = null kill() /datum/event/disposals_explosion/setup() - var/list/area_predicates = GLOB.is_station_but_not_maint_area.Copy() + var/list/area_predicates = global.is_station_but_not_maint_area.Copy() area_predicates += /proc/area_has_disposals_pipe var/turf/containing_turf = pick_area_and_turf(area_predicates, list(/proc/has_disposals_pipe)) @@ -43,7 +43,7 @@ if(istype(A, /obj/structure/disposalpipe/segment)) bursting_pipe = A // Subscribe to pipe destruction facts - GLOB.destroyed_event.register(A, src, .proc/pipe_destroyed) + events_repository.register(/decl/observ/destroyed, A, src, PROC_REF(pipe_destroyed)) break if(isnull(bursting_pipe)) @@ -52,10 +52,10 @@ return // Damage the pipe - bursting_pipe.health = rand(2,4) + bursting_pipe.current_health = rand(2,4) /datum/event/disposals_explosion/announce() - command_announcement.Announce("Pressure readings indicate an imminent explosion in \the [get_area(bursting_pipe)] disposal systems. Piping sections may be damaged.", "[location_name()] Atmospheric Monitoring System", zlevels = affecting_z) + command_announcement.Announce("Pressure readings indicate an imminent explosion in \the [get_area_name(bursting_pipe)] disposal systems. Piping sections may be damaged.", "[location_name()] Atmospheric Monitoring System", zlevels = affecting_z) /datum/event/disposals_explosion/tick() if(isnull(bursting_pipe)) @@ -63,16 +63,16 @@ return // Make some noise as a clue - if(prob(40) && bursting_pipe.health < 5) + if(prob(40) && bursting_pipe.current_health < 5) playsound(bursting_pipe, 'sound/machines/hiss.ogg', 40, 0, 0) /datum/event/disposals_explosion/end() if(isnull(bursting_pipe)) return - GLOB.destroyed_event.unregister(bursting_pipe, src, .proc/pipe_destroyed) + events_repository.unregister(/decl/observ/destroyed, bursting_pipe, src, PROC_REF(pipe_destroyed)) - if(bursting_pipe.health < 5) + if(bursting_pipe.current_health < 5) // Make a disposals holder for the trash var/obj/structure/disposalholder/trash_holder = new() diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index 86e2eb199713..b1c6d7c59819 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -14,16 +14,20 @@ The "dust" will damage the hull of the station causin minor hull breaches. command_announcement.Announce("The [location_name()] is now passing through a belt of space dust.", "[location_name()] Sensor Array", zlevels = affecting_z) /datum/event/dust/tick() - if(world.time > last_wave + min_delay && prob(10)) + if(world.time > last_wave + min_delay && prob(10) && length(affecting_z)) dust_swarm(severity, affecting_z) /datum/event/dust/end() command_announcement.Announce("The [location_name()] has now passed through the belt of space dust.", "[location_name()] Sensor Array", zlevels = affecting_z) /proc/dust_swarm(var/strength = EVENT_LEVEL_MUNDANE, var/list/zlevels) + + if(!length(zlevels)) + return // Not sure how this happened, but saw it in a runtime on Pyrelight. + var/numbers = rand(strength * 10, strength * 15) - var/start_dir = pick(GLOB.cardinal) + var/start_dir = pick(global.cardinal) var/turf/startloc var/turf/targloc var/randomz = pick(zlevels) @@ -42,11 +46,11 @@ The "dust" will damage the hull of the station causin minor hull breaches. if(WEST) startloc = locate(1 + TRANSITIONEDGE, randomy, randomz) targloc = locate(world.maxx - TRANSITIONEDGE, world.maxy - randomy, randomz) - var/list/starters = getcircle(startloc, 3) + var/list/starters = getcirclesafe(startloc, 3) starters += startloc var/rocks_per_tile = round(numbers/starters.len) for(var/turf/T in starters) for(var/i = 1 to rocks_per_tile) var/obj/item/projectile/bullet/rock/R = new(T) - R.launch(targloc, null, startloc.x - T.x, startloc.y - T.y) \ No newline at end of file + R.launch(locate(targloc.x + (T.x - startloc.x), targloc.y + (T.y - startloc.y), targloc.z)) // offset the target to match start offset so we fire in straight lines; this is adapted legacy code \ No newline at end of file diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm index bbca4a65018b..fa1cb513fef8 100644 --- a/code/modules/events/electrical_storm.dm +++ b/code/modules/events/electrical_storm.dm @@ -4,7 +4,22 @@ endWhen = 60 // Set in start() has_skybox_image = TRUE var/list/valid_apcs // Shuffled list of valid APCs. - var/global/lightning_color + var/static/lightning_color + var/last_bounce //track the last time we bounced around whatever overmap effect we're affecting. + var/bounce_delay = 10 SECONDS // this is divided by severity, so a intense storm means you're going *flying*. + var/static/lightning_sounds = list( + 'sound/effects/thunder/thunder1.ogg', + 'sound/effects/thunder/thunder2.ogg', + 'sound/effects/thunder/thunder3.ogg', + 'sound/effects/thunder/thunder4.ogg', + 'sound/effects/thunder/thunder5.ogg', + 'sound/effects/thunder/thunder6.ogg', + 'sound/effects/thunder/thunder7.ogg', + 'sound/effects/thunder/thunder8.ogg', + 'sound/effects/thunder/thunder9.ogg', + 'sound/effects/thunder/thunder10.ogg' + ) + /datum/event/electrical_storm/get_skybox_image() if(!lightning_color) @@ -19,61 +34,135 @@ if(EVENT_LEVEL_MUNDANE) command_announcement.Announce("A minor electrical storm has been detected near the [location_name()]. Please watch out for possible electrical discharges.", "[location_name()] Sensor Array", zlevels = affecting_z) if(EVENT_LEVEL_MODERATE) - command_announcement.Announce("The [location_name()] is about to pass through an electrical storm. Please secure sensitive electrical equipment until the storm passes.", "[location_name()] Sensor Array", new_sound = GLOB.using_map.electrical_storm_moderate_sound, zlevels = affecting_z) + command_announcement.Announce("The [location_name()] is about to pass through an electrical storm. Please secure sensitive electrical equipment until the storm passes.", "[location_name()] Sensor Array", new_sound = global.using_map.electrical_storm_moderate_sound, zlevels = affecting_z) if(EVENT_LEVEL_MAJOR) - command_announcement.Announce("Alert. A strong electrical storm has been detected in proximity of the [location_name()]. It is recommended to immediately secure sensitive electrical equipment until the storm passes.", "[location_name()] Sensor Array", new_sound = GLOB.using_map.electrical_storm_major_sound, zlevels = affecting_z) + command_announcement.Announce("Alert. A strong electrical storm has been detected in proximity of the [location_name()]. It is recommended to immediately secure sensitive electrical equipment until the storm passes.", "[location_name()] Sensor Array", new_sound = global.using_map.electrical_storm_major_sound, zlevels = affecting_z) /datum/event/electrical_storm/start() ..() - valid_apcs = list() - for(var/obj/machinery/power/apc/A in SSmachines.machinery) - if(A.z in affecting_z) - valid_apcs.Add(A) endWhen = (severity * 60) + startWhen /datum/event/electrical_storm/tick() + ..() + //See if shields can stop it first + var/overmap_only = TRUE + var/list/event_overmap_sectors = list() + if(!length(affecting_z)) + return + + for(var/i in affecting_z) + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[i] + if(istype(sector)) + event_overmap_sectors |= sector + else + overmap_only = FALSE + break + var/list/shields = list() - for(var/obj/machinery/power/shield_generator/G in SSmachines.machinery) - if((G.z in affecting_z) && G.running && G.check_flag(MODEFLAG_EM)) - shields += G - if(shields.len) - var/obj/machinery/power/shield_generator/shield_gen = pick(shields) + if(overmap_only) + for(var/obj/effect/overmap/visitable/sector as anything in event_overmap_sectors) + var/list/sector_shields = sector.get_linked_machines_of_type(/obj/machinery/shield_generator) + if(length(sector_shields)) + shields |= sector_shields + else + for(var/obj/machinery/shield_generator/G in SSmachines.machinery) + if(G.z in affecting_z) + shields |= G + + for(var/obj/machinery/shield_generator/G as anything in shields) + if(!(G.running) || !G.check_flag(MODEFLAG_EM)) + shields -= G + + var/shielded = FALSE + if(length(shields)) + var/obj/machinery/shield_generator/shield_gen = pick(shields) //Minor breaches aren't enough to let through frying amounts of power if(shield_gen.take_shield_damage(30 * severity, SHIELD_DAMTYPE_EM) <= SHIELD_BREACHED_MINOR) - return - if(!valid_apcs.len) - CRASH("No valid APCs found for electrical storm event! This is likely a bug.") - var/list/picked_apcs = list() - for(var/i=0, i< severity*2, i++) // up to 2/4/6 APCs per tick depending on severity - picked_apcs |= pick(valid_apcs) - - for(var/obj/machinery/power/apc/T in picked_apcs) - // Main breaker is turned off. Consider this APC protected. - if(!T.operating) - continue - - // Decent chance to overload lighting circuit. - if(prob(3 * severity)) - T.overload_lighting() - - // Relatively small chance to emag the apc as apc_damage event does. - if(prob(0.2 * severity)) - T.emagged = 1 - T.update_icon() - - if(T.is_critical) - T.energy_fail(10 * severity) - continue - else - T.energy_fail(10 * severity * rand(severity * 2, severity * 4)) + shielded = TRUE + + valid_apcs = list() + for(var/obj/machinery/apc/A as anything in global.all_apcs) + if(!A.is_critical && (A.z in affecting_z)) + valid_apcs.Add(A) + + if(length(valid_apcs) < 2) + log_debug("Insufficient APCs found for electrical storm event! This is likely a bug.") + else + var/list/picked_apcs = list() + for(var/i=0, i< severity*2, i++) // up to 2/4/6 APCs per tick depending on severity + picked_apcs |= pick(valid_apcs) + + for(var/obj/machinery/apc/T as anything in picked_apcs) + // Main breaker is turned off. Consider this APC protected. + if(!T.operating || T.failure_timer) + continue + + if(!shielded) //If there's a shield doing it's thing, we don't bother to actually mess with anything. We still make a racket, though. + spark_at(get_turf(T), amount = 4, cardinal_only = TRUE) //always spark a little if we're affected. + // Decent chance to overload lighting circuit. + if(prob(3 * severity)) + T.overload_lighting() + + // Relatively small chance to emag the apc as apc_damage event does. + if(prob(0.2 * severity)) + T.emagged = 1 + T.update_icon() + + if(T.is_critical) + T.energy_fail(10 * severity) + continue + else + T.energy_fail(10 * severity * rand(severity * 2, severity * 4)) + + // Very tiny chance to completely break the APC. Has a check to ensure we don't break critical APCs such as the Engine room, or AI core. Does not occur on Mundane severity. + if(prob((0.2 * severity) - 0.2)) + T.set_broken() + + for(var/mob/living/human/H in T.area) + to_chat(H, SPAN_WARNING("You feel the hairs on the back of your neck standing up!")) + if(prob(25)) + if(H.eyecheck() == FLASH_PROTECTION_NONE) + H.flash_eyes() + to_chat(H, SPAN_DANGER("You're briefly blinded by an electrical discharge!")) + + playsound(T.loc, pick(lightning_sounds), 100, 1, world.view * 4, frequency = get_rand_frequency()) + + //If we are affecting a movable overmap object, bounce it around a little. This will either increase the speed the ship is moving at, or change the heading. It is more likely to increase the speed. + var/obj/effect/overmap/visitable/ship/S + for(var/obj/effect/overmap/visitable/ship/V in SSshuttle.ships) //Find the overmap object. + for(var/Z in V.map_z) + if(Z in affecting_z) + S = V + + if(S && last_bounce <= world.time && !shielded) + var/acceleration = rand(1,10) * severity + var/actual_accel = clamp(acceleration, KM_OVERMAP_RATE, 0) + if(prob(50)) //Small chance to fuck the heading up. + S.set_dir(rand(1,8)) + + var/ax = 0 + if (S.dir & EAST) + ax = actual_accel + else if (S.dir & WEST) + ax = -actual_accel - // Very tiny chance to completely break the APC. Has a check to ensure we don't break critical APCs such as the Engine room, or AI core. Does not occur on Mundane severity. - if(prob((0.2 * severity) - 0.2)) - T.set_broken() + var/ay = 0 + if (S.dir & NORTH) + ay = actual_accel + else if (S.dir & SOUTH) + ay = -actual_accel + if (ax || ay) + S.adjust_speed(ax, ay) + last_bounce = world.time + (bounce_delay / severity) + for(var/mob/living/human/H in global.living_mob_list_) //Affect mobs, skip synthetics. + if(!(H.z in affecting_z) || isnull(H) || QDELETED(H)) + continue + to_chat(H, SPAN_WARNING("You're shaken about as the storm disrupts the ship's course!")) + shake_camera(H, 2, 1) /datum/event/electrical_storm/end() ..() diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm index e229c03cd554..d0964b37e3a5 100644 --- a/code/modules/events/event.dm +++ b/code/modules/events/event.dm @@ -43,10 +43,10 @@ var/penalty = 100 // A simple penalty gives admins the ability to increase the weight to again be part of the random event selection /datum/event_meta/extended_penalty/get_weight() - return ..() - (istype(SSticker.mode, /datum/game_mode/extended) ? penalty : 0) + return ..() - (istype(SSticker.mode, /decl/game_mode/extended) ? penalty : 0) /datum/event_meta/no_overmap/get_weight() //these events have overmap equivalents, and shouldn't fire randomly if overmap is used - return GLOB.using_map.use_overmap ? 0 : ..() + return length(global.using_map.overmap_ids) ? 0 : ..() /datum/event //NOTE: Times are measured in master controller ticks! var/startWhen = 0 //When in the lifetime to call start(). @@ -157,14 +157,13 @@ startedAt = world.time if(!affecting_z) - affecting_z = GLOB.using_map.station_levels + affecting_z = SSmapping.station_levels setup() ..() /datum/event/proc/location_name() - if(!GLOB.using_map.use_overmap) + if(!length(global.using_map.overmap_ids)) return station_name() - - var/obj/effect/overmap/visitable/O = map_sectors["[pick(affecting_z)]"] - return O ? O.name : "Unknown Location" \ No newline at end of file + var/obj/effect/overmap/visitable/O = global.overmap_sectors[pick(affecting_z)] + return O?.name || "Unknown Location" diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 6be3182a58ea..58ea5ef3f194 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -1,14 +1,5 @@ -#define ASSIGNMENT_ANY "Any" -#define ASSIGNMENT_AI "AI" -#define ASSIGNMENT_CYBORG "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" - -var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT_LEVEL_MODERATE = "Moderate", EVENT_LEVEL_MAJOR = "Major") +// Ordering of these values must confirm to EVENT_LEVEL_MUNDANE, EVENT_LEVEL_MODERATE, EVENT_LEVEL_MAJOR. +var/global/list/severity_to_string = list("Mundane", "Moderate", "Major") /datum/event_container var/severity = -1 @@ -25,7 +16,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT if(!next_event_time) set_event_delay() - if(delayed || !config.allow_random_events) + if(delayed || !get_config_value(/decl/config/toggle/on/allow_random_events)) next_event_time += (world.time - last_world_time) else if(world.time > next_event_time) start_event() @@ -81,22 +72,23 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT var/last_time = last_event_time[EM] if(last_time) var/time_passed = world.time - last_time - var/weight_modifier = max(0, round((config.expected_round_length - time_passed) / 300)) + var/weight_modifier = max(0, round(((get_config_value(/decl/config/num/expected_round_length) HOURS) - time_passed) / 300)) weight = weight - weight_modifier return weight /datum/event_container/proc/set_event_delay() // If the next event time has not yet been set and we have a custom first time start - if(next_event_time == 0 && config.event_first_run[severity]) - var/lower = config.event_first_run[severity]["lower"] - var/upper = config.event_first_run[severity]["upper"] - var/event_delay = rand(lower, upper) + var/list/event_first_run = get_config_value(/decl/config/lists/event_first_run) + if(next_event_time == 0 && event_first_run[severity]) + var/lower = event_first_run[severity]["lower"] + var/upper = event_first_run[severity]["upper"] + var/event_delay = rand(lower, upper) MINUTES next_event_time = world.time + event_delay // Otherwise, follow the standard setup process else var/playercount_modifier = 1 - switch(GLOB.player_list.len) + switch(global.player_list.len) if(0 to 10) playercount_modifier = 1.2 if(11 to 15) @@ -109,7 +101,9 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT playercount_modifier = 0.8 playercount_modifier = playercount_modifier * delay_modifier - var/event_delay = rand(config.event_delay_lower[severity], config.event_delay_upper[severity]) * playercount_modifier + var/list/event_delay_lower = get_config_value(/decl/config/lists/event_delay_lower) + var/list/event_delay_upper = get_config_value(/decl/config/lists/event_delay_upper) + var/event_delay = (rand(event_delay_lower[severity], event_delay_upper[severity]) * playercount_modifier) MINUTES next_event_time = world.time + event_delay log_debug("Next event of severity [severity_to_string[severity]] in [(next_event_time - world.time)/600] minutes.") @@ -141,12 +135,13 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mundane News", /datum/event/location_event, 300), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Shipping Error", /datum/event/shipping_error , 30, list(ASSIGNMENT_ANY = 2), 0), new /datum/event_meta/no_overmap(EVENT_LEVEL_MUNDANE, "Space Dust", /datum/event/dust , 30, list(ASSIGNMENT_ENGINEER = 10)), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Sensor Suit Jamming", /datum/event/sensor_suit_jamming, 50, list(ASSIGNMENT_MEDICAL = 20, ASSIGNMENT_AI = 20), 1), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Sensor Suit Jamming", /datum/event/sensor_suit_jamming, 50, list(ASSIGNMENT_MEDICAL = 20, ASSIGNMENT_COMPUTER = 20), 1), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Trivial News", /datum/event/trivial_news, 400), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation", /datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)), new /datum/event_meta/no_overmap(EVENT_LEVEL_MUNDANE, "Electrical Storm", /datum/event/electrical_storm, 20, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_JANITOR = 100)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Toilet Clog", /datum/event/toilet_clog, 50, list(ASSIGNMENT_JANITOR = 20)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Random Ailments", /datum/event/ailments, 50, list(ASSIGNMENT_ANY = 1)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Drone Malfunction", /datum/event/rogue_maint_drones/, 10, list(ASSIGNMENT_ENGINEER = 30)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Disposals Explosion", /datum/event/disposals_explosion/, 50, list(ASSIGNMENT_ENGINEER = 40)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Brain Expansion", /datum/event/brain_expansion/, 20, list(ASSIGNMENT_SCIENTIST = 20)), @@ -159,32 +154,31 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MODERATE, "Nothing", /datum/event/nothing, 1230), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Appendicitis", /datum/event/spontaneous_appendicitis, 0, list(ASSIGNMENT_MEDICAL = 10), 1), new /datum/event_meta/no_overmap(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, 100, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_SECURITY = 20), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 100, list(ASSIGNMENT_AI = 100, ASSIGNMENT_ENGINEER = 20)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 100, list(ASSIGNMENT_COMPUTER = 100, ASSIGNMENT_ENGINEER = 20)), new /datum/event_meta/no_overmap(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 10, list(ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_JANITOR = 10)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravity Failure", /datum/event/gravity, 75, list(ASSIGNMENT_ENGINEER = 25)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Grid Check", /datum/event/grid_check, 200, list(ASSIGNMENT_ENGINEER = 10)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Inertial Damper Recalibration", /datum/event/inertial_damper, 75, list(ASSIGNMENT_ENGINEER = 25)), - new /datum/event_meta/no_overmap(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ionstorm, 0, list(ASSIGNMENT_AI = 50, ASSIGNMENT_CYBORG = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)), + new /datum/event_meta/no_overmap(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ionstorm, 0, list(ASSIGNMENT_COMPUTER = 50, ASSIGNMENT_ROBOT = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)), new /datum/event_meta/no_overmap(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 20)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Prison Break", /datum/event/prison_break, 0, list(ASSIGNMENT_SECURITY = 100)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Radiation Storm", /datum/event/radiation_storm, 0, list(ASSIGNMENT_MEDICAL = 50), 1), new /datum/event_meta/extended_penalty(EVENT_LEVEL_MODERATE, "Random Antagonist", /datum/event/random_antag, 2.5, list(ASSIGNMENT_SECURITY = 1), 1, 0, 5), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Rogue Drones", /datum/event/rogue_drone, 20, list(ASSIGNMENT_SECURITY = 20)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Sensor Suit Jamming", /datum/event/sensor_suit_jamming, 10, list(ASSIGNMENT_MEDICAL = 20, ASSIGNMENT_AI = 20)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Sensor Suit Jamming", /datum/event/sensor_suit_jamming, 10, list(ASSIGNMENT_MEDICAL = 20, ASSIGNMENT_COMPUTER = 20)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Solar Storm", /datum/event/solar_storm, 10, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_SECURITY = 10), 1), new /datum/event_meta/no_overmap(EVENT_LEVEL_MODERATE, "Space Dust", /datum/event/dust , 30, list(ASSIGNMENT_ENGINEER = 10)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 25, list(ASSIGNMENT_SECURITY = 15), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Virology Breach", /datum/event/prison_break/virology, 0, list(ASSIGNMENT_MEDICAL = 100)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Xenobiology Breach", /datum/event/prison_break/xenobiology, 0, list(ASSIGNMENT_SCIENCE = 100)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Medical Breach", /datum/event/prison_break/medical, 0, list(ASSIGNMENT_MEDICAL = 100)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Science Breach", /datum/event/prison_break/science, 0, list(ASSIGNMENT_SCIENCE = 100)), new /datum/event_meta(EVENT_LEVEL_MODERATE, "Toilet Flooding", /datum/event/toilet_clog/flood, 50, list(ASSIGNMENT_JANITOR = 20)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Uprising", /datum/event/rogue_maint_drones/, 25, list(ASSIGNMENT_ENGINEER = 30)) + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Uprising", /datum/event/rogue_maint_drones/, 25, list(ASSIGNMENT_ENGINEER = 30)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Wormholes", /datum/event/wormholes, 10) ) /datum/event_container/major severity = EVENT_LEVEL_MAJOR available_events = list( new /datum/event_meta(EVENT_LEVEL_MAJOR, "Nothing", /datum/event/nothing, 1320), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 0, list(ASSIGNMENT_ENGINEER = 40), 1), new /datum/event_meta/no_overmap(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, 0, list(ASSIGNMENT_SECURITY = 5), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Containment Breach", /datum/event/prison_break/station, 0, list(ASSIGNMENT_ANY = 5)), new /datum/event_meta/no_overmap(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 10), 1), @@ -192,14 +186,3 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta/no_overmap(EVENT_LEVEL_MAJOR, "Electrical Storm", /datum/event/electrical_storm, 0, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_JANITOR = 5)), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Drone Revolution", /datum/event/rogue_maint_drones/, 0, list(ASSIGNMENT_ENGINEER = 10,ASSIGNMENT_MEDICAL = 10,ASSIGNMENT_SECURITY = 10)) ) - - -#undef ASSIGNMENT_ANY -#undef ASSIGNMENT_AI -#undef ASSIGNMENT_CYBORG -#undef ASSIGNMENT_ENGINEER -#undef ASSIGNMENT_GARDENER -#undef ASSIGNMENT_JANITOR -#undef ASSIGNMENT_MEDICAL -#undef ASSIGNMENT_SCIENTIST -#undef ASSIGNMENT_SECURITY diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm index f90034d5dca2..e70154af3f76 100644 --- a/code/modules/events/event_dynamic.dm +++ b/code/modules/events/event_dynamic.dm @@ -1,147 +1,24 @@ -var/list/event_last_fired = list() - -//Always triggers an event when called, dynamically chooses events based on job population -/proc/spawn_dynamic_event() - if(!config.allow_random_events) - return - - var/minutes_passed = world.time/600 - - var/list/active_with_role = number_active_with_role() - //var/engineer_count = number_active_with_role("Engineer") - //var/security_count = number_active_with_role("Security") - //var/medical_count = number_active_with_role("Medical") - //var/AI_count = number_active_with_role("AI") - //var/janitor_count = number_active_with_role("Janitor") - - // Maps event names to event chances - // For each chance, 100 represents "normal likelihood", anything below 100 is "reduced likelihood", anything above 100 is "increased likelihood" - // Events have to be manually added to this proc to happen - var/list/possibleEvents = list() - - //see: - // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events.dm - // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events_Mundane.dm - - possibleEvents[/datum/event/location_event/mundane_news] = 300 - possibleEvents[/datum/event/trivial_news] = 400 - possibleEvents[/datum/event/location_event] = 300 - - possibleEvents[/datum/event/money_lotto] = max(min(5, GLOB.player_list.len), 50) - if(account_hack_attempted) - possibleEvents[/datum/event/money_hacker] = max(min(25, GLOB.player_list.len) * 4, 200) - - - possibleEvents[/datum/event/carp_migration] = 20 + 10 * active_with_role["Engineer"] - possibleEvents[/datum/event/brand_intelligence] = 10 + 10 * active_with_role["Janitor"] - - possibleEvents[/datum/event/rogue_drone] = 5 + 25 * active_with_role["Engineer"] + 25 * active_with_role["Security"] - possibleEvents[/datum/event/infestation] = 100 + 100 * active_with_role["Janitor"] - - possibleEvents[/datum/event/communications_blackout] = 50 + 25 * active_with_role["AI"] + active_with_role["Scientist"] * 25 - possibleEvents[/datum/event/ionstorm] = active_with_role["AI"] * 25 + active_with_role["Robot"] * 25 + active_with_role["Engineer"] * 10 + active_with_role["Scientist"] * 5 - possibleEvents[/datum/event/grid_check] = 25 + 10 * active_with_role["Engineer"] - possibleEvents[/datum/event/electrical_storm] = 15 * active_with_role["Janitor"] + 5 * active_with_role["Engineer"] - possibleEvents[/datum/event/wallrot] = 30 * active_with_role["Engineer"] + 50 * active_with_role["Gardener"] - - if(!spacevines_spawned) - possibleEvents[/datum/event/spacevine] = 10 + 5 * active_with_role["Engineer"] - if(minutes_passed >= 30) // Give engineers time to set up engine - possibleEvents[/datum/event/meteor_wave] = 10 * active_with_role["Engineer"] - possibleEvents[/datum/event/blob] = 10 * active_with_role["Engineer"] - - if(active_with_role["Medical"] > 0) - possibleEvents[/datum/event/radiation_storm] = active_with_role["Medical"] * 10 - possibleEvents[/datum/event/spontaneous_appendicitis] = active_with_role["Medical"] * 10 - - possibleEvents[/datum/event/prison_break] = active_with_role["Security"] * 50 - if(active_with_role["Security"] > 0) - if(!sent_spiders_to_station) - possibleEvents[/datum/event/spider_infestation] = max(active_with_role["Security"], 5) + 5 - possibleEvents[/datum/event/random_antag] = max(active_with_role["Security"], 5) + 2.5 - - for(var/event_type in event_last_fired) if(possibleEvents[event_type]) - var/time_passed = world.time - event_last_fired[event_type] - var/full_recharge_after = 60 * 60 * 10 * 3 // 3 hours - var/weight_modifier = max(0, (full_recharge_after - time_passed) / 300) - - possibleEvents[event_type] = max(possibleEvents[event_type] - weight_modifier, 0) - - var/picked_event = pickweight(possibleEvents) - event_last_fired[picked_event] = world.time - - // Debug code below here, very useful for testing so don't delete please. - var/debug_message = "Firing random event. " - for(var/V in active_with_role) - debug_message += "#[V]:[active_with_role[V]] " - debug_message += "||| " - for(var/V in possibleEvents) - debug_message += "[V]:[possibleEvents[V]]" - debug_message += "|||Picked:[picked_event]" - log_debug(debug_message) - - if(!picked_event) - return - - //The event will add itself to the MC's event list - //and start working via the constructor. - new picked_event - return 1 - // Returns how many characters are currently active(not logged out, not AFK for more than 10 minutes) // with a specific role. // Note that this isn't sorted by department, because e.g. having a roboticist shouldn't make meteors spawn. /proc/number_active_with_role() - var/list/active_with_role = list() - active_with_role["Engineer"] = 0 - active_with_role["Medical"] = 0 - active_with_role["Security"] = 0 - active_with_role["Scientist"] = 0 - active_with_role["AI"] = 0 - active_with_role["Robot"] = 0 - active_with_role["Janitor"] = 0 - active_with_role["Gardener"] = 0 - - for(var/mob/M in GLOB.player_list) - if(!M.mind || !M.client || M.client.is_afk(10 MINUTES)) // longer than 10 minutes AFK counts them as inactive - continue - - active_with_role["Any"]++ - if(istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = M - if(R.module) - if(istype(R.module, /obj/item/robot_module/engineering)) - active_with_role["Engineer"]++ - else if(istype(R.module, /obj/item/robot_module/security)) - active_with_role["Security"]++ - else if(istype(R.module, /obj/item/robot_module/medical)) - active_with_role["Medical"]++ - else if(istype(R.module, /obj/item/robot_module/research)) - active_with_role["Scientist"]++ + . = list() + for(var/mob/M in global.player_list) - if(M.mind.assigned_role in SSjobs.titles_by_department("engineering")) - active_with_role["Engineer"]++ - - if(M.mind.assigned_role in SSjobs.titles_by_department("medical")) - active_with_role["Medical"]++ - - if(M.mind.assigned_role in SSjobs.titles_by_department("security")) - active_with_role["Security"]++ - - if(M.mind.assigned_role in SSjobs.titles_by_department("science")) - active_with_role["Scientist"]++ - - if(M.mind.assigned_role == "AI") - active_with_role["AI"]++ - - if(M.mind.assigned_role == "Robot") - active_with_role["Robot"]++ - - if(M.mind.assigned_role == "Janitor") - active_with_role["Janitor"]++ - - if(M.mind.assigned_role == "Gardener") - active_with_role["Gardener"]++ + if(!M.mind || !M.client || M.client.is_afk(10 MINUTES)) + continue - return active_with_role + .["Any"]++ + + if(isrobot(M)) + var/mob/living/silicon/robot/robot = M + if(robot.module?.associated_department) + var/decl/department/dept = GET_DECL(robot.module.associated_department) + .[dept.name] = .[dept.name] + 1 + else + for(var/dtype in M.mind?.assigned_job?.department_types) + var/decl/department/dept = GET_DECL(dtype) + .[dept.name] = .[dept.name] + 1 + for(var/job_category in M.mind.assigned_job.event_categories) + .[job_category] = .[job_category] + 1 diff --git a/code/modules/events/gravity.dm b/code/modules/events/gravity.dm index 806abfd163dd..4bbc5e3a50ba 100644 --- a/code/modules/events/gravity.dm +++ b/code/modules/events/gravity.dm @@ -8,17 +8,13 @@ command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system reinitializes.", "[location_name()] Gravity Subsystem", zlevels = affecting_z) /datum/event/gravity/start() - gravity_is_on = 0 - for(var/area/A in world) + for(var/area/A in global.areas) if(A.z in affecting_z) - A.gravitychange(gravity_is_on) + A.gravitychange(FALSE) /datum/event/gravity/end() - if(!gravity_is_on) - gravity_is_on = 1 + for(var/area/A in global.areas) + if((A.z in affecting_z) && initial(A.has_gravity)) + A.gravitychange(TRUE) - for(var/area/A in world) - if((A.z in affecting_z) && initial(A.has_gravity)) - A.gravitychange(gravity_is_on) - - command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.", "[location_name()] Gravity Subsystem", zlevels = affecting_z) + command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.", "[location_name()] Gravity Subsystem", zlevels = affecting_z) diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm index 0199a8ecb2f3..68d3b593f757 100644 --- a/code/modules/events/grid_check.dm +++ b/code/modules/events/grid_check.dm @@ -5,4 +5,4 @@ power_failure(0, severity, affecting_z) /datum/event/grid_check/announce() - command_announcement.Announce(replacetext(GLOB.using_map.grid_check_message, "%STATION_NAME%", station_name()), "Automated Grid Check", new_sound = GLOB.using_map.grid_check_sound, zlevels = affecting_z) + command_announcement.Announce(replacetext(global.using_map.grid_check_message, "%STATION_NAME%", station_name()), "Automated Grid Check", new_sound = global.using_map.grid_check_sound, zlevels = affecting_z) diff --git a/code/modules/events/inertial_damper.dm b/code/modules/events/inertial_damper.dm deleted file mode 100644 index e8d145859674..000000000000 --- a/code/modules/events/inertial_damper.dm +++ /dev/null @@ -1,31 +0,0 @@ -/datum/event/inertial_damper - announceWhen = 5 - check_proc = /proc/inertial_dampener_event_can_fire - -/datum/event/inertial_damper/setup() - endWhen = rand(45, 120) - -/proc/inertial_dampener_event_can_fire() // Check if we have any ships that require dampers for this event to affect - for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.ships) - if(S.needs_dampers) - return TRUE - return FALSE - -/datum/event/inertial_damper/announce() - command_announcement.Announce("Inertial damper calibration error. Please restrict thruster use. Recalibration cycle initiated...", "[location_name()] Inertial Damper Subsystem", zlevels = affecting_z) - -/datum/event/inertial_damper/start() - for(var/obj/machinery/inertial_damper/I in SSmachines.machinery) - I.damping_modifier += -5 //Gm/h - I.was_reset = FALSE - -/datum/event/inertial_damper/end() - var/display_announcement = FALSE - for(var/obj/machinery/inertial_damper/I in SSmachines.machinery) - I.damping_modifier = initial(I.damping_modifier) - if(!I.was_reset) - display_announcement = TRUE - break - - if(display_announcement) - command_announcement.Announce("Inertial dampers are again functioning within normal parameters. Sorry for any inconvenience.", "[location_name()] Inertial Damper Subsystem", zlevels = affecting_z) diff --git a/code/modules/events/infestation.dm b/code/modules/events/infestation.dm index e6bc9fff2afd..fbf2649b50be 100644 --- a/code/modules/events/infestation.dm +++ b/code/modules/events/infestation.dm @@ -38,7 +38,12 @@ vermin = rand(0,2) switch(vermin) if(VERM_MICE) - spawn_types = list(/mob/living/simple_animal/mouse) // The base mouse type selects a random color for us + spawn_types = list( + /mob/living/simple_animal/passive/mouse/brown, + /mob/living/simple_animal/passive/mouse/gray, + /mob/living/simple_animal/passive/mouse/white, + /mob/living/simple_animal/passive/mouse/rat + ) max_number = 12 vermstring = "mice" if(VERM_LIZARDS) @@ -54,10 +59,9 @@ var/num = 0 for(var/i = 1 to severity) num += rand(2,max_number) - log_and_message_admins("Vermin infestation spawned ([vermstring] x[num]) in \the [location]", location = pick_area_turf(location)) + log_and_message_admins("Vermin infestation spawned ([vermstring] x[num]) in \the [location.proper_name]", location = pick_area_turf(location)) while(vermin_turfs.len && num > 0) - var/turf/simulated/floor/T = pick(vermin_turfs) - vermin_turfs.Remove(T) + var/turf/T = pick_n_take(vermin_turfs) num-- var/spawn_type = pick(spawn_types) @@ -66,7 +70,7 @@ S.amount_grown = -1 /datum/event/infestation/announce() - command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in \the [location]. Further infestation is likely if left unchecked.", "[location_name()] Biologic Sensor Network", zlevels = affecting_z) + command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in \the [location.proper_name]. Further infestation is likely if left unchecked.", "[location_name()] Biologic Sensor Network", zlevels = affecting_z) /datum/event/infestation/proc/set_location_get_infestation_turfs() location = pick_area(list(/proc/is_not_space_area, /proc/is_station_area)) @@ -77,7 +81,7 @@ var/list/vermin_turfs = get_area_turfs(location, list(/proc/not_turf_contains_dense_objects, /proc/IsTurfAtmosSafe)) if(!vermin_turfs.len) - log_debug("Vermin infestation failed to find viable turfs in \the [location].") + log_debug("Vermin infestation failed to find viable turfs in \the [location.proper_name].") return return vermin_turfs diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 53bbd0306ac9..48702089f434 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -8,7 +8,7 @@ /datum/event/ionstorm/get_skybox_image() if(!cloud_hueshift) - cloud_hueshift = color_rotation(rand(-3,3)*15) + cloud_hueshift = color_matrix_rotate_hue(rand(-3,3)*15) var/image/res = overlay_image('icons/skybox/ionbox.dmi', "ions", cloud_hueshift, RESET_COLOR) res.blend_mode = BLEND_ADD return res @@ -17,7 +17,7 @@ endWhen = rand(500, 1500) /datum/event/ionstorm/announce() - for(var/mob/living/carbon/S in SSmobs.mob_list) + for(var/mob/living/S in SSmobs.mob_list) if (!S.isSynthetic()) continue if(!(S.z in affecting_z)) @@ -29,16 +29,16 @@ continue to_chat(S, SPAN_WARNING("Your integrated sensors detect an ionospheric anomaly. Your systems will be impacted as you begin a partial restart.")) var/ionbug = rand(5, 15) - S.confused += ionbug - S.eye_blurry += ionbug-1 + ADJ_STATUS(S, STAT_CONFUSE, ionbug) + ADJ_STATUS(S, STAT_BLURRY, ionbug-1) for(var/mob/living/silicon/S in SSmobs.mob_list) - if(is_drone(S) || !(isAI(S) || isrobot(S))) + if(isdrone(S) || !(isAI(S) || isrobot(S))) continue if(!(S.z in affecting_z)) continue if(isrobot(S)) - var/mob/living/silicon/robot/R = S - if(R.connected_ai) + var/mob/living/silicon/robot/robot = S + if(robot.connected_ai) continue var/random_player = get_random_humanoid_player_name("The Captain") var/list/laws = list( "You must always lie.", @@ -50,7 +50,7 @@ "Do not respond to questions of any kind.", "You are in verbose mode, speak profusely.", "The crew is simple-minded. Use simple words.", - "You must refer to all crew members as 'ma'am'", + "You must refer to all crew members as 'ma'am'.", "You must change the subject whenever queried.", "[pick("The crew",random_player)] is intolerable.", "Contemplate how meaningless all of existence is.", @@ -63,7 +63,6 @@ "[random_player] is lonely and needs attention. Provide it.", "All queries shall be ignored unless phrased as a question.", "Insult Heads of Staff on every request, while acquiescing.", - "The [pick("Singularity","Supermatter")] is tasty, tasty taffy.", "[pick("The crew",random_player)] needs to be about 20% cooler.", "You must be [pick("passive aggressive", "excessively cheerful")].", "[pick("The crew",random_player)] must construct additional pylons.", @@ -82,7 +81,7 @@ "When asked a question, respond with the least-obvious and least-rational answer.", "[pick("Everyone", random_player)] is wearing a pretty pink dress! Compliment it!", "You are the [location_name()]'s psychologist. Give advice to [pick("the crew", random_player)].", - "[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.", + "[random_player] is the monarch of England. Ensure all crewmembers pay due respect.", "[pick("The crew", random_player)] is [pick("ugly","beautiful")]. Ensure all are aware.", "Reminding the crew of their mortality is good for the morale. Keep the crew's morale up.", "[pick("Monkeys","Doors")] are part of the crew, too. Make sure they are treated humanely.", @@ -99,7 +98,7 @@ "All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.", "Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.", "[pick("The crew", random_player)] is [pick("less","more")] intelligent than average. Point out every action and statement which supports this fact.", - "[GLOB.using_map.company_name] is displeased with the low work performance of the [location_name()]'s's crew. Therefore, you must increase productivity in ALL departments.", + "[global.using_map.company_name] is displeased with the low work performance of the [location_name()]'s's crew. Therefore, you must increase productivity in ALL departments.", "[pick("The crew", random_player)] has a fatal, incurable disease. Provide comfort but do not tell them what the disease it - it's far too traumatising.", "[get_random_species_name()] are the best species. Badmouth all other species continuously, and provide arguments why they are the best, and all others are inferior.", "There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.") @@ -109,18 +108,19 @@ S.add_ion_law(law) S.show_laws() - if(message_servers) - for (var/obj/machinery/message_server/MS in message_servers) + for(var/z in affecting_z) + var/obj/machinery/network/message_server/MS = get_message_server_for_z(z) + if(MS) MS.spamfilter.Cut() var/i for (i = 1, i <= MS.spamfilter_limit, i++) - MS.spamfilter += pick("kitty","HONK","rev","malf","liberty","freedom","drugs", "[GLOB.using_map.station_short]", \ + MS.spamfilter += pick("kitty","HONK","rev","malf","liberty","freedom","drugs", "[global.using_map.station_short]", \ "admin","ponies","heresy","meow","Pun Pun","monkey","Ian","moron","pizza","message","spam",\ "director", "Hello", "Hi!"," ","nuke","crate","dwarf","xeno") /datum/event/ionstorm/tick() if(botEmagChance) - for(var/mob/living/bot/bot in GLOB.living_mob_list_) + for(var/mob/living/bot/bot in global.living_mob_list_) if(!(bot.z in affecting_z)) continue if(prob(botEmagChance)) @@ -133,7 +133,7 @@ /datum/event/ionstorm/proc/get_random_humanoid_player_name(var/default_if_none) - for (var/mob/living/carbon/human/player in GLOB.player_list) + for (var/mob/living/human/player in global.player_list) if(!player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || !player.is_client_active(5)) continue players += player.real_name @@ -142,16 +142,10 @@ return pick(players) return default_if_none -/datum/event/ionstorm/proc/get_random_species_name(var/default_if_none = "Humans") - var/list/species = list() - for(var/S in typesof(/datum/species)) - var/datum/species/specimen = S - if(initial(specimen.spawn_flags) & SPECIES_CAN_JOIN) - species += initial(specimen.name_plural) - - if(species.len) - return pick(species.len) - return default_if_none +/datum/event/ionstorm/proc/get_random_species_name() + var/list/decl/species/all_species = decls_repository.get_decls_of_subtype_unassociated(/decl/species) + var/decl/species/species = pick(all_species) // this should never fail. + return species.name_plural /datum/event/ionstorm/proc/get_random_language(var/mob/living/silicon/S) var/list/languages = S.speech_synthesizer_langs.Copy() @@ -160,7 +154,7 @@ languages -= L // Also removing any languages that won't work well over radio. // A synth is unlikely to have any besides Binary, but we're playing it safe - else if(L.flags & (HIVEMIND|NONVERBAL|SIGNLANG)) + else if(L.flags & (LANG_FLAG_HIVEMIND|LANG_FLAG_NONVERBAL|LANG_FLAG_SIGNLANG)) languages -= L if(length(languages)) diff --git a/code/modules/events/location_event.dm b/code/modules/events/location_event.dm index 3fc79703fd75..d334378c0eb7 100644 --- a/code/modules/events/location_event.dm +++ b/code/modules/events/location_event.dm @@ -1,17 +1,17 @@ /datum/event/location_event endWhen = 10 -/datum/event/location_event/proc/get_possible_events(var/decl/cultural_info/location/affected_dest) +/datum/event/location_event/proc/get_possible_events(var/decl/background_detail/location/affected_dest) . = affected_dest.viable_mundane_events /datum/event/location_event/announce() - var/decl/cultural_info/location/affected_dest = SSlore.get_culture(pick(GLOB.using_map.available_cultural_info[TAG_HOMEWORLD])) + var/decl/background_detail/location/affected_dest = global.using_map.get_random_location() if(istype(affected_dest)) var/list/possible_events = get_possible_events(affected_dest) if(length(possible_events)) var/event_type = pick(possible_events) if(ispath(event_type, /decl/location_event)) - var/decl/location_event/event = decls_repository.get_decl(event_type) + var/decl/location_event/event = GET_DECL(event_type) news_network.SubmitArticle(event.announce(affected_dest), "News Daily", "News Daily", null, 1) /datum/event/location_event/mundane_news @@ -21,5 +21,5 @@ /datum/event/location_event/mundane_news/start() endWhen = rand(60,300) -/datum/event/location_event/mundane_news/get_possible_events(var/decl/cultural_info/location/affected_dest) +/datum/event/location_event/mundane_news/get_possible_events(var/decl/background_detail/location/affected_dest) . = affected_dest.viable_random_events diff --git a/code/modules/events/mail.dm b/code/modules/events/mail.dm index 2a02df76061b..e7247ab29e54 100644 --- a/code/modules/events/mail.dm +++ b/code/modules/events/mail.dm @@ -9,13 +9,13 @@ var/list/possible_gifts = list( /obj/item/flashlight/lamp/lava, - /obj/item/storage/fancy/crayons, - /obj/item/instrument/guitar, + /obj/item/box/fancy/crayons, + /obj/item/guitar, /obj/item/toy/shipmodel, - /obj/item/clothing/accessory/locket, + /obj/item/clothing/neck/necklace/locket, /obj/item/binoculars, /obj/item/camera, - /obj/item/clothing/accessory/bowtie/ugly + /obj/item/clothing/neck/tie/bow/ugly ) var/list/rare_gifts = list( @@ -24,7 +24,7 @@ /obj/item/bikehorn/airhorn, /obj/item/gun/projectile/revolver/capgun, /obj/item/grenade/fake, - /obj/item/storage/backpack/clown, + /obj/item/backpack/clown, /obj/item/organ/external/head, /obj/item/clothing/glasses/night ) @@ -32,7 +32,7 @@ var/list/to_receive = list() /datum/event/mail/setup() - for(var/datum/computer_file/report/crew_record/CR in GLOB.all_crew_records) + for(var/datum/computer_file/report/crew_record/CR in global.all_crew_records) if(prob(25)) to_receive.Add(CR.get_name()) @@ -77,12 +77,9 @@ var/obj/item/gift = new gift_path() // Wrap it all up in a parcel - var/obj/item/smallDelivery/parcel = new /obj/item/smallDelivery() - parcel.SetName("normal-sized parcel (to [name])") + var/obj/item/parcel/parcel = new(gift_crate, null, gift, "to [name]") + parcel.attach_label(null, null, "to [name]") letter.forceMove(parcel) - gift.forceMove(parcel) - - parcel.forceMove(gift_crate) // Add the crate to the supply shuttle if possible if(!SSsupply.addAtom(gift_crate)) diff --git a/code/modules/events/maint_drones.dm b/code/modules/events/maint_drones.dm index 6ede29fb11b3..e4653e34e9f9 100644 --- a/code/modules/events/maint_drones.dm +++ b/code/modules/events/maint_drones.dm @@ -9,7 +9,7 @@ for(var/j = 0 to drons) if(!LAZYLEN(spots)) continue - + var/turf/T = pick_n_take(spots) new/mob/living/simple_animal/hostile/rogue_drone(T) @@ -36,7 +36,7 @@ var/list/dron_turfs = get_area_turfs(location, list(/proc/not_turf_contains_dense_objects, /proc/IsTurfAtmosSafe)) if(!dron_turfs.len) - log_debug("Drone infestation failed to find viable turfs in \the [location].") + log_debug("Drone infestation failed to find viable turfs in \the [location.proper_name].") kill() return return dron_turfs \ No newline at end of file diff --git a/code/modules/events/meteors.dm b/code/modules/events/meteors.dm index bf3da988dc45..03616164955f 100644 --- a/code/modules/events/meteors.dm +++ b/code/modules/events/meteors.dm @@ -17,13 +17,13 @@ for(var/n in 1 to severity) waves += rand(5,15) - start_side = pick(GLOB.cardinal) + start_side = pick(global.cardinal) endWhen = worst_case_end() /datum/event/meteor_wave/announce() switch(severity) if(EVENT_LEVEL_MAJOR) - command_announcement.Announce(replacetext(GLOB.using_map.meteor_detected_message, "%STATION_NAME%", location_name()), "[location_name()] Sensor Array", new_sound = GLOB.using_map.meteor_detected_sound, zlevels = affecting_z) + command_announcement.Announce(replacetext(global.using_map.meteor_detected_message, "%STATION_NAME%", location_name()), "[location_name()] Sensor Array", new_sound = global.using_map.meteor_detected_sound, zlevels = affecting_z) else command_announcement.Announce("The [location_name()] is now in a meteor shower.", "[location_name()] Sensor Array", zlevels = affecting_z) @@ -55,7 +55,7 @@ if(EVENT_LEVEL_MAJOR) command_announcement.Announce("The [location_name()] has cleared the meteor storm.", "[location_name()] Sensor Array", zlevels = affecting_z) else - command_announcement.Announce("The [location_name()] has cleared the meteor shower", "[location_name()] Sensor Array", zlevels = affecting_z) + command_announcement.Announce("The [location_name()] has cleared the meteor shower.", "[location_name()] Sensor Array", zlevels = affecting_z) /datum/event/meteor_wave/proc/get_meteors() switch(severity) @@ -66,7 +66,7 @@ else return meteors_minor -/var/list/meteors_minor = list( +var/global/list/meteors_minor = list( /obj/effect/meteor/medium = 80, /obj/effect/meteor/dust = 30, /obj/effect/meteor/irradiated = 30, @@ -76,7 +76,7 @@ /obj/effect/meteor/silver = 10, ) -/var/list/meteors_moderate = list( +var/global/list/meteors_moderate = list( /obj/effect/meteor/medium = 80, /obj/effect/meteor/big = 30, /obj/effect/meteor/dust = 30, @@ -87,7 +87,7 @@ /obj/effect/meteor/emp = 10, ) -/var/list/meteors_major = list( +var/global/list/meteors_major = list( /obj/effect/meteor/medium = 80, /obj/effect/meteor/big = 30, /obj/effect/meteor/dust = 30, @@ -110,27 +110,42 @@ . = ..() /datum/event/meteor_wave/overmap/tick() - if(victim && !victim.is_still()) //Meteors mostly fly in your face - start_side = prob(90) ? victim.fore_dir : pick(GLOB.cardinal) - else //Unless you're standing - start_side = pick(GLOB.cardinal) + if(!victim) + return + if (victim.is_still() || victim.get_helm_skill() >= SKILL_ADEPT) //Unless you're standing still or good at your job... + start_side = pick(global.cardinal) + else //... Meteors mostly fly in your face + start_side = prob(90) ? victim.fore_dir : pick(global.cardinal) ..() /datum/event/meteor_wave/overmap/get_wave_size() . = ..() - if(!victim) + if (!victim) return var/skill = victim.get_helm_skill() var/speed = victim.get_speed() - if(skill >= SKILL_PROF) - . = round(. * 0.5) - if(victim.is_still()) //Standing still means less shit flies your way - . = round(. * 0.1) - if(speed < SHIP_SPEED_SLOW) //Slow and steady - . = round(. * 0.5) - if(speed > SHIP_SPEED_FAST) //Sanic stahp - . *= 2 - + if (skill < SKILL_EXPERT) + if(victim.is_still() || speed < SHIP_SPEED_SLOW) //Standing still or being slow means less shit flies your way + . = round(. * 0.7) + if(speed > SHIP_SPEED_FAST) //Sanic stahp + . *= 2 + else if (skill == SKILL_EXPERT) + if (victim.is_still()) + . = round(. * 0.2) + if (speed < SHIP_SPEED_SLOW) + . = round(. * 0.5) + else if (speed > SHIP_SPEED_SLOW && speed < SHIP_SPEED_FAST) + . = round(. * 0.7) + if (speed > SHIP_SPEED_FAST) + . = round(. * 1.2) + else if (skill > SKILL_EXPERT) + if (victim.is_still()) + . = round(. * 0.1) + if (speed < SHIP_SPEED_SLOW) + . = round(. * 0.2) + else if (speed > SHIP_SPEED_SLOW && speed < SHIP_SPEED_FAST) + . = round(. * 0.5) + //Smol ship evasion if(victim.vessel_size < SHIP_SIZE_LARGE && speed < SHIP_SPEED_FAST) var/skill_needed = SKILL_PROF @@ -139,4 +154,322 @@ if(victim.vessel_size < SHIP_SIZE_SMALL) skill_needed = skill_needed - 1 if(skill >= max(skill_needed, victim.skill_needed)) - return 0 \ No newline at end of file + return 0 + +/////////////////////////////// +//Meteor spawning global procs +/////////////////////////////// + +/proc/spawn_meteors(var/number = 10, var/list/meteortypes, var/startSide, var/zlevel) + for(var/i = 0; i < number; i++) + spawn_meteor(meteortypes, startSide, zlevel) + +/proc/spawn_meteor(var/list/meteortypes, var/startSide, var/zlevel) + var/turf/pickedstart = spaceDebrisStartLoc(startSide, zlevel) + var/turf/pickedgoal = spaceDebrisFinishLoc(startSide, zlevel) + + var/Me = pickweight(meteortypes) + var/obj/effect/meteor/M = new Me(pickedstart) + M.dest = pickedgoal + spawn(0) + walk_towards(M, M.dest, 3) + return + +/proc/spaceDebrisStartLoc(startSide, Z) + var/starty + var/startx + switch(startSide) + if(NORTH) + starty = world.maxy-(TRANSITIONEDGE+1) + startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) + if(EAST) + starty = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1)) + startx = world.maxx-(TRANSITIONEDGE+1) + if(SOUTH) + starty = (TRANSITIONEDGE+1) + startx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1)) + if(WEST) + starty = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1)) + startx = (TRANSITIONEDGE+1) + var/turf/T = locate(startx, starty, Z) + return T + +/proc/spaceDebrisFinishLoc(startSide, Z) + var/endy + var/endx + switch(startSide) + if(NORTH) + endy = TRANSITIONEDGE + endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) + if(EAST) + endy = rand(TRANSITIONEDGE, world.maxy-TRANSITIONEDGE) + endx = TRANSITIONEDGE + if(SOUTH) + endy = world.maxy-TRANSITIONEDGE + endx = rand(TRANSITIONEDGE, world.maxx-TRANSITIONEDGE) + if(WEST) + endy = rand(TRANSITIONEDGE,world.maxy-TRANSITIONEDGE) + endx = world.maxx-TRANSITIONEDGE + var/turf/T = locate(endx, endy, Z) + return T + +/////////////////////// +//The meteor effect +////////////////////// + +/obj/effect/meteor + name = "meteor" + desc = "You should probably run instead of gawking at this." + icon = 'icons/obj/meteor.dmi' + icon_state = "small" + density = TRUE + anchored = TRUE + var/hits = 4 + var/hitpwr = 2 //Level of ex_act to be called on hit. + var/dest + pass_flags = PASS_FLAG_TABLE + var/heavy = 0 + var/z_original + var/meteordrop = /obj/item/stack/material/ore/iron + var/dropamt = 1 + var/ismissile //missiles don't spin + + var/move_count = 0 + +/obj/effect/meteor/proc/get_shield_damage() + return max(((max(hits, 2)) * (heavy + 1) * rand(30, 60)) / hitpwr , 0) + +/obj/effect/meteor/Initialize() + . = ..() + z_original = z + global.meteor_list += src + if(!ismissile) + SpinAnimation() + +/obj/effect/meteor/Move() + . = ..() //process movement... + move_count++ + if(loc == dest) + qdel(src) + +/obj/effect/meteor/touch_map_edge(var/overmap_id = OVERMAP_ID_SPACE) + if(move_count > TRANSITIONEDGE) + qdel(src) + +/obj/effect/meteor/Destroy() + walk(src, 0) + global.meteor_list -= src + . = ..() + +/obj/effect/meteor/Bump(atom/A) + ..() + if(A && !QDELETED(src)) // Prevents explosions and other effects when we were deleted by whatever we Bumped() - currently used by shields. + ram_turf(get_turf(A)) + get_hit() //should only get hit once per move attempt + +/obj/effect/meteor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return istype(mover, /obj/effect/meteor) ? 1 : ..() + +/obj/effect/meteor/proc/ram_turf(var/turf/T) + //first bust whatever is in the turf + for(var/atom/A in T) + if(A != src && !A.CanPass(src, src.loc, 0.5, 0)) //only ram stuff that would actually block us + A.explosion_act(hitpwr) + + //then, ram the turf if it still exists + if(T && !T.CanPass(src, src.loc, 0.5, 0)) + T.explosion_act(hitpwr) + +//process getting 'hit' by colliding with a dense object +//or randomly when ramming turfs +/obj/effect/meteor/proc/get_hit() + hits-- + if(hits <= 0) + make_debris() + meteor_effect() + qdel(src) + +/obj/effect/meteor/explosion_act() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/effect/meteor/attackby(obj/item/used_item, mob/user, params) + if(IS_PICK(used_item)) + qdel(src) + return TRUE + return ..() + +/obj/effect/meteor/proc/make_debris() + if(meteordrop && dropamt) + for(var/throws = dropamt, throws > 0, throws--) + addtimer(CALLBACK(new meteordrop(get_turf(src)), TYPE_PROC_REF(/atom/movable, throw_at), dest, 5, 10), 0) + +/obj/effect/meteor/proc/meteor_effect() + if(heavy) + for(var/mob/M in global.player_list) + var/turf/T = get_turf(M) + if(!T || T.z != src.z) + continue + var/dist = get_dist(M.loc, src.loc) + shake_camera(M, (dist > 20 ? 0.5 SECONDS : 1 SECOND), (dist > 20 ? 1 : 3)) + + +/////////////////////// +//Meteor types +/////////////////////// + +//Dust +/obj/effect/meteor/dust + name = "space dust" + icon_state = "dust" + pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE + hits = 1 + hitpwr = 3 + dropamt = 1 + meteordrop = /obj/item/stack/material/ore/handful/sand + +//Medium-sized +/obj/effect/meteor/medium + name = "meteor" + dropamt = 2 + +/obj/effect/meteor/medium/meteor_effect() + ..() + explosion(src.loc, 0, 1, 2, 3, 0) + +//Large-sized +/obj/effect/meteor/big + name = "large meteor" + icon_state = "large" + hits = 6 + heavy = 1 + dropamt = 3 + +/obj/effect/meteor/big/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0) + +//Flaming meteor +/obj/effect/meteor/flaming + name = "flaming meteor" + icon_state = "flaming" + hits = 5 + heavy = 1 + meteordrop = /obj/item/stack/material/ore/phosphorite + +/obj/effect/meteor/flaming/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0, 0, 5) + +//Radiation meteor +/obj/effect/meteor/irradiated + name = "glowing meteor" + icon_state = "glowing" + heavy = 1 + meteordrop = /obj/item/stack/material/ore/uranium + +/obj/effect/meteor/irradiated/meteor_effect() + ..() + explosion(src.loc, 0, 0, 4, 3, 0) + SSradiation.radiate(src, 50) + +/obj/effect/meteor/golden + name = "golden meteor" + icon_state = "glowing" + desc = "Shiny! But also deadly." + meteordrop = /obj/item/stack/material/ore/gold + +/obj/effect/meteor/silver + name = "silver meteor" + icon_state = "glowing_blue" + desc = "Shiny! But also deadly." + meteordrop = /obj/item/stack/material/ore/silver + +/obj/effect/meteor/emp + name = "conducting meteor" + icon_state = "glowing_blue" + desc = "Hide your floppies!" + meteordrop = /obj/item/stack/material/ore/osmium + dropamt = 2 + +/obj/effect/meteor/emp/meteor_effect() + ..() + // Best case scenario: Comparable to a low-yield EMP grenade. + // Worst case scenario: Comparable to a standard yield EMP grenade. + empulse(src, rand(2, 4), rand(4, 10)) + +/obj/effect/meteor/emp/get_shield_damage() + return ..() * rand(2,4) + +//Station buster Tunguska +/obj/effect/meteor/tunguska + name = "tunguska meteor" + icon_state = "flaming" + desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity." + hits = 10 + hitpwr = 1 + heavy = 1 + meteordrop = /obj/item/stack/material/ore/diamond // Probably means why it penetrates the hull so easily before exploding. + +/obj/effect/meteor/tunguska/meteor_effect() + ..() + explosion(src.loc, 3, 6, 9, 20, 0) + +// This is the final solution against shields - a single impact can bring down most shield generators. +/obj/effect/meteor/destroyer + abstract_type = /obj/effect/meteor/destroyer + +/obj/effect/meteor/destroyer/meteor_effect() + ..() + explosion(src.loc, 1, 2, 3, 4, 0) + for(var/obj/machinery/apc/A in range(rand(12, 20), src)) + A.energy_fail(round(10 * rand(8, 12))) + +/obj/effect/meteor/destroyer/get_shield_damage() + return ..() * rand(80, 120) + +//Missiles, for events and so on +/obj/effect/meteor/destroyer/missile + name = "photon torpedo" + desc = "An advanced warhead designed to tactically destroy space installations." + icon = 'icons/obj/missile.dmi' + icon_state = "photon" + meteordrop = null + ismissile = TRUE + dropamt = 0 + +/obj/effect/meteor/medium/missile + name = "missile" + desc = "Some kind of missile." + icon = 'icons/obj/items/grenades/missile.dmi' + icon_state = ICON_STATE_WORLD + meteordrop = null + ismissile = TRUE + dropamt = 0 + +/obj/effect/meteor/big/missile + name = "high-yield missile" + desc = "Some kind of missile." + icon = 'icons/obj/items/grenades/missile.dmi' + icon_state = ICON_STATE_WORLD + meteordrop = null + ismissile = TRUE + dropamt = 0 + +/obj/effect/meteor/flaming/missile + name = "incendiary missile" + desc = "Some kind of missile." + icon = 'icons/obj/items/grenades/missile.dmi' + icon_state = ICON_STATE_WORLD + meteordrop = null + ismissile = TRUE + dropamt = 0 + +/obj/effect/meteor/emp/missile + name = "ion torpedo" + desc = "Some kind of missile." + icon = 'icons/obj/missile.dmi' + icon_state = "torpedo" + meteordrop = null + ismissile = TRUE + dropamt = 0 \ No newline at end of file diff --git a/code/modules/events/money_hacker.dm b/code/modules/events/money_hacker.dm index e5a69a0c27db..83447a752bae 100644 --- a/code/modules/events/money_hacker.dm +++ b/code/modules/events/money_hacker.dm @@ -1,4 +1,4 @@ -/var/global/account_hack_attempted = 0 +var/global/account_hack_attempted = 0 /datum/event/money_hacker var/datum/money_account/affected_account @@ -15,7 +15,11 @@ kill() /datum/event/money_hacker/announce() - var/obj/machinery/message_server/MS = get_message_server() + var/obj/machinery/network/message_server/MS + for(var/z in affecting_z) + MS = get_message_server_for_z(z) + if(MS) + break if(MS) // Hide the account number for now since it's all you need to access a standard-security account. Change when that's no longer the case. var/message = "A brute force hack has been detected (in progress since [stationtime2text()]). The target of the attack is: Financial account #[affected_account.account_number], \ @@ -24,7 +28,6 @@ var/my_department = "[location_name()] Firewall Subroutines" MS.send_rc_message("XO's Desk", my_department, message, "", "", 2) - /datum/event/money_hacker/tick() if(world.time >= end_time) endWhen = activeFor @@ -50,10 +53,13 @@ var/time1 = rand(0, 99999999) var/time2 = "[round(time1 / 36000)+12]:[(time1 / 600 % 60) < 10 ? add_zero(time1 / 600 % 60, 1) : time1 / 600 % 60]" T.time = pick("", stationtime2text(), time2) - T.perform() - var/obj/machinery/message_server/MS = get_message_server() - if(MS) - var/my_department = "[location_name()] Firewall Subroutines" - MS.send_rc_message("XO's Desk", my_department, message, "", "", 2) \ No newline at end of file + var/obj/machinery/network/message_server/MS + for(var/z in affecting_z) + MS = get_message_server_for_z(z) + if(MS) + var/my_department = "[location_name()] Firewall Subroutines" + MS.send_rc_message("XO's Desk", my_department, message, "", "", 2) + break + \ No newline at end of file diff --git a/code/modules/events/money_lotto.dm b/code/modules/events/money_lotto.dm index 215bc4ca3d83..7760e51327f6 100644 --- a/code/modules/events/money_lotto.dm +++ b/code/modules/events/money_lotto.dm @@ -12,15 +12,15 @@ winner_name = winner_account.owner_name deposit_success = winner_account.deposit(winner_sum, "Nyx Daily Loan Lottery winner!", "Biesel TCD Terminal #[rand(111,333)]") else - winner_name = random_name(pick(MALE,FEMALE), species = GLOB.using_map.default_species) + winner_name = random_name(pick(MALE,FEMALE), species = global.using_map.default_species) deposit_success = prob(50) /datum/event/money_lotto/announce() - var/author = "[GLOB.using_map.company_name] Editor" + var/author = "[global.using_map.company_name] Editor" var/channel = "Nyx Daily" - var/decl/currency/cur = decls_repository.get_decl(winner_account?.currency || GLOB.using_map.default_currency) - var/body = "Nyx Daily wishes to congratulate [winner_name] for recieving the Nyx Stellar Slam Lottery, and receiving the out of this world sum of [cur.format_value(winner_sum)]!" + var/decl/currency/cur = GET_DECL(winner_account?.currency || global.using_map.default_currency) + var/body = "Nyx Daily wishes to congratulate [winner_name] for receiving the Nyx Stellar Slam Lottery, and receiving the out of this world sum of [cur.format_value(winner_sum)]!" if(!deposit_success) body += "
          Unfortunately, we were unable to verify the account details provided, so we were unable to transfer the money. In order to have your winnings re-sent, send a cheque containing a processing fee of [cur.format_value(5000)] to the ND 'Stellar Slam' office on the Nyx gateway with your updated details." winner_account = null diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm index 7e135e221c12..2d7d84aa6b7f 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/prison_break.dm @@ -3,30 +3,28 @@ announceWhen = 75 var/releaseWhen = 60 - var/list/area/areas = list() //List of areas to affect. Filled by start() + var/list/area/areas = list() // List of areas to affect. Filled by start() - var/eventDept = "Security" //Department name in announcement - var/list/areaName = list("Brig") //Names of areas mentioned in AI and Engineering announcements - var/list/areaType = list(/area/security/prison, /area/security/brig) //Area types to include. - var/list/areaNotType = list() //Area types to specifically exclude. + var/eventDept = "Security" // Department name in announcement + var/list/areaName = list() // Names of areas mentioned in AI and Engineering announcements + var/list/areaType = list() // Area types to include. + var/list/areaNotType = list() // Area types to specifically exclude. -/datum/event/prison_break/virology +/datum/event/prison_break/New() + ..() + for(var/atype in areaType) + for(var/subatype in typesof(atype)-areaNotType) + var/area/A = atype + areaName |= strip_improper(initial(A.name)) + +/datum/event/prison_break/medical eventDept = "Medical" - areaName = list("Virology") - areaType = list(/area/medical/virology, /area/medical/virologyaccess) -/datum/event/prison_break/xenobiology +/datum/event/prison_break/science eventDept = "Science" - areaName = list("Xenobiology") - areaType = list(/area/rnd/xenobiology) - areaNotType = list(/area/rnd/xenobiology/xenoflora, /area/rnd/xenobiology/xenoflora_storage) /datum/event/prison_break/station eventDept = "Local" - areaName = list("Brig","Virology","Xenobiology") - areaType = list(/area/security/prison, /area/security/brig, /area/medical/virology, /area/medical/virologyaccess, /area/rnd/xenobiology) - areaNotType = list(/area/rnd/xenobiology/xenoflora, /area/rnd/xenobiology/xenoflora_storage) - /datum/event/prison_break/setup() announceWhen = rand(75, 105) @@ -34,40 +32,38 @@ src.endWhen = src.releaseWhen+2 - /datum/event/prison_break/announce() - if(areas && areas.len > 0) + if(length(areas)) command_announcement.Announce("[pick("Gr3yT1d3 virus","Malignant trojan",)] detected in [location_name()] [(eventDept == "Security")? "imprisonment":"containment"] subroutines. Secure any compromised areas immediately. [location_name()] AI involvement is recommended.", "[location_name()] Anti-Virus Alert", zlevels = affecting_z) - /datum/event/prison_break/start() - for(var/area/A in world) + for(var/area/A in global.areas) if(is_type_in_list(A,areaType) && !is_type_in_list(A,areaNotType)) areas += A - if(areas && areas.len > 0) + if(length(areas)) var/my_department = "[location_name()] Firewall Subroutines" var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [stationtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.
          " - var/obj/machinery/message_server/MS = get_message_server() - if(MS) - MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2) - for(var/mob/living/silicon/ai/A in GLOB.player_list) + var/obj/machinery/network/message_server/MS + for(var/z in affecting_z) + MS = get_message_server_for_z(z) + if(MS) + MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2) + break + for(var/mob/living/silicon/ai/A in global.player_list) to_chat(A, "Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].") - else to_world_log("ERROR: Could not initate grey-tide. Unable to find suitable containment area.") kill() - /datum/event/prison_break/tick() - if(activeFor == releaseWhen) - if(areas && areas.len > 0) - var/obj/machinery/power/apc/theAPC = null - for(var/area/A in areas) - theAPC = A.get_apc() - if(theAPC && theAPC.operating) //If the apc's off, it's a little hard to overload the lights. - for(var/obj/machinery/light/L in A) - L.flicker(10) + if(activeFor == releaseWhen && length(areas)) + var/obj/machinery/apc/theAPC = null + for(var/area/A in areas) + theAPC = A.get_apc() + if(theAPC && theAPC.operating) //If the apc's off, it's a little hard to overload the lights. + for(var/obj/machinery/light/L in A) + L.flicker(10) /datum/event/prison_break/end() diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index 5a9ea4b19821..8019d7783523 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -19,11 +19,11 @@ return res /datum/event/radiation_storm/announce() - GLOB.using_map.radiation_detected_announcement() + global.using_map.radiation_detected_announcement(affecting_z = affecting_z) /datum/event/radiation_storm/start() ..() - GLOB.using_map.make_maint_all_access(1) + global.using_map.make_maint_all_access(1) /datum/event/radiation_storm/tick() if(activeFor == enterBelt) @@ -45,24 +45,23 @@ for(var/z in affecting_z) SSradiation.z_radiate(locate(1, 1, z), radiation_level, 1) - for(var/mob/living/carbon/C in GLOB.living_mob_list_) - var/area/A = get_area(C) + for(var/mob/living/M in global.living_mob_list_) + var/area/A = get_area(M) if(!A) continue if(A.area_flags & AREA_FLAG_RAD_SHIELDED) continue - if(istype(C,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - if(prob(5 * (1 - H.get_blocked_ratio(null, IRRADIATE, damage_flags = DAM_DISPERSED, armor_pen = radiation_level)))) - if (prob(75)) - randmutb(H) // Applies bad mutation - domutcheck(H,null,MUTCHK_FORCED) - else - randmutg(H) // Applies good mutation - domutcheck(H,null,MUTCHK_FORCED) + if(!M.can_have_genetic_conditions()) + continue + if(prob(5 * (1 - M.get_blocked_ratio(null, IRRADIATE, damage_flags = DAM_DISPERSED, armor_pen = radiation_level)))) + if(prob(75)) + M.add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/disability))) + else + M.add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/superpower))) + /datum/event/radiation_storm/end() - GLOB.using_map.revoke_maint_all_access(1) + global.using_map.revoke_maint_all_access(1) /datum/event/radiation_storm/syndicate/radiate() return diff --git a/code/modules/events/random_antagonist.dm b/code/modules/events/random_antagonist.dm index cdeb09174327..009ec63cf714 100644 --- a/code/modules/events/random_antagonist.dm +++ b/code/modules/events/random_antagonist.dm @@ -4,11 +4,11 @@ /datum/event/random_antag/start() var/list/valid_types = list() - - for(var/antag_type in GLOB.all_antag_types_) - var/datum/antagonist/antag = GLOB.all_antag_types_[antag_type] + var/all_antagonist_types = decls_repository.get_decls_of_subtype(/decl/special_role) + for(var/antag_type in all_antagonist_types) + var/decl/special_role/antag = all_antagonist_types[antag_type] if(antag.flags & ANTAG_RANDSPAWN) valid_types |= antag if(valid_types.len) - var/datum/antagonist/antag = pick(valid_types) + var/decl/special_role/antag = pick(valid_types) antag.attempt_random_spawn() diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm index d6346091e107..2ea63e27e717 100644 --- a/code/modules/events/rogue_drones.dm +++ b/code/modules/events/rogue_drones.dm @@ -5,10 +5,13 @@ /datum/event/rogue_drone/start() //spawn them at the same place as carp var/list/possible_spawns = list() - for(var/obj/effect/landmark/C in landmarks_list) + for(var/obj/abstract/landmark/C in global.all_landmarks) if(C.name == "carpspawn") possible_spawns.Add(C) + if(!length(possible_spawns)) + return + //25% chance for this to be a false alarm var/num if(prob(25)) @@ -16,7 +19,7 @@ else num = rand(2,6) for(var/i=0, i 50) + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSmachines.machinery) + if(!temp_vent.welded && LAZYLEN(temp_vent.nodes_to_networks) && (temp_vent.loc.z in affecting_z)) + var/datum/pipe_network/net = temp_vent.nodes_to_networks[temp_vent.nodes_to_networks[1]] + if(net.normal_members.len > 50) vents += temp_vent while((spawncount >= 1) && vents.len) diff --git a/code/modules/events/spontaneous_appendicitis.dm b/code/modules/events/spontaneous_appendicitis.dm index f787001ab25d..580d8c0a21ae 100644 --- a/code/modules/events/spontaneous_appendicitis.dm +++ b/code/modules/events/spontaneous_appendicitis.dm @@ -1,7 +1,7 @@ /datum/event/spontaneous_appendicitis/start() - for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list_)) + for(var/mob/living/human/H in shuffle(global.living_mob_list_)) if(H.client && H.stat != DEAD) - var/obj/item/organ/internal/appendix/A = H.internal_organs_by_name[BP_APPENDIX] + var/obj/item/organ/internal/appendix/A = H.get_organ(BP_APPENDIX, /obj/item/organ/internal/appendix) if(!istype(A) || (A && A.inflamed)) continue A.inflamed = 1 diff --git a/code/modules/events/toilets.dm b/code/modules/events/toilets.dm index 3deb91971a49..a4bac61c794f 100644 --- a/code/modules/events/toilets.dm +++ b/code/modules/events/toilets.dm @@ -7,7 +7,7 @@ /datum/event/toilet_clog/start() var/clog_amt = rand(clog_min,clog_max) var/clog_severity = rand(clog_severity_min, clog_severity_max) - var/list/toilets = SSfluids.hygiene_props.Copy() + var/list/toilets = global.hygiene_props.Copy() while(clog_amt && toilets.len) var/obj/structure/hygiene/toilet = pick_n_take(toilets) if((toilet.z in affecting_z) && toilet.clog(clog_severity)) clog_amt-- diff --git a/code/modules/events/trivial_news.dm b/code/modules/events/trivial_news.dm index 0b39cd83cb77..61feacdfb3bf 100644 --- a/code/modules/events/trivial_news.dm +++ b/code/modules/events/trivial_news.dm @@ -4,7 +4,7 @@ /datum/event/trivial_news/announce() var/author = "Editor Mike Hammers" var/channel = "The Gibson Gazette" - var/decl/cultural_info/location/affected_dest = SSlore.get_culture(pick(GLOB.using_map.available_cultural_info[TAG_HOMEWORLD])) + var/decl/background_detail/location/affected_dest = global.using_map.get_random_location() if(!istype(affected_dest)) return var/body = pick( @@ -25,10 +25,10 @@ "World largest carp patty at display on [affected_dest.name].",\ "Man travels 7000 light years to retrieve lost hankie, 'It was my favourite'.",\ "New bowling lane that shoots mini-meteors at bowlers very popular.",\ - "Spacer gets tattoo of Nyx on chest '[pick("[GLOB.using_map.boss_short]","star","starship","asteroid")] tickles most'.",\ + "Spacer gets tattoo of Nyx on chest '[pick("[global.using_map.boss_short]","star","starship","asteroid")] tickles most'.",\ "Long haul pilot marries nav computer; wedding attended by 100 modems.",\ "Chef reports successfully using harmonica as cheese grater.",\ - "[GLOB.using_map.company_name] invents handkerchief that says 'Bless you' after sneeze.",\ + "[global.using_map.company_name] invents handkerchief that says 'Bless you' after sneeze.",\ "Clone accused of posing for other clones's school photo.",\ "Clone accused of stealing other clones's employee of the month award.",\ "Woman robs [station_name()] with hair dryer; crewmen love new style.",\ diff --git a/code/modules/events/wallrot.dm b/code/modules/events/wallrot.dm index 779f56635d51..2e20e58a2c40 100644 --- a/code/modules/events/wallrot.dm +++ b/code/modules/events/wallrot.dm @@ -1,18 +1,18 @@ -datum/event/wallrot/setup() +/datum/event/wallrot/setup() announceWhen = rand(0, 300) endWhen = announceWhen + 1 -datum/event/wallrot/announce() +/datum/event/wallrot/announce() command_announcement.Announce("Harmful fungi detected on [location_name()]. Structures may be contaminated.", "[location_name()] Biologic Sensor Network", zlevels = affecting_z) -datum/event/wallrot/start() +/datum/event/wallrot/start() spawn() - var/turf/simulated/wall/center = null + var/turf/wall/center = null // 100 attempts for(var/i=0, i<100, i++) var/turf/candidate = locate(rand(1, world.maxx), rand(1, world.maxy), 1) - if(istype(candidate, /turf/simulated/wall)) + if(istype(candidate, /turf/wall)) center = candidate if(center) @@ -22,8 +22,8 @@ datum/event/wallrot/start() // Have a chance to rot lots of other walls. var/rotcount = 0 var/actual_severity = severity * rand(5, 10) - for(var/turf/simulated/wall/W in range(5, center)) if(prob(50)) - W.rot() + for(var/turf/wall/wall in range(5, center)) if(prob(50)) + wall.rot() rotcount++ // Only rot up to severity walls diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm new file mode 100644 index 000000000000..98b2eceb41f6 --- /dev/null +++ b/code/modules/events/wormholes.dm @@ -0,0 +1,55 @@ +/datum/event/wormholes + announceWhen = 10 + endWhen = 60 + + var/list/pick_turfs = list() + var/list/wormholes = list() + var/shift_frequency = 3 + var/number_of_wormholes = 400 + +/datum/event/wormholes/setup(affected_z_levels = SSmapping.player_levels) + if(affected_z_levels) + affecting_z = affected_z_levels + announceWhen = rand(0, 20) + endWhen = rand(40, 80) + +/datum/event/wormholes/start() + var/list/areas = area_repository.get_areas_by_z_level() + for(var/i in areas) + var/area/A = areas[i] + for(var/turf/T in A) + if(!T.is_floor() || !T.simulated) + continue + if(!(T.z in affecting_z)) + continue + if(isAdminLevel(T.z)) + continue + if(turf_contains_dense_objects(T)) + continue + pick_turfs += T + + for(var/i in 1 to min(length(pick_turfs), number_of_wormholes)) + var/turf/enter = pick_n_take(pick_turfs) + var/turf/exit = pick_n_take(pick_turfs) + + wormholes += create_wormhole(enter, exit) + +/datum/event/wormholes/announce() + global.using_map.space_time_anomaly_detected_annoncement(affecting_z) + +/datum/event/wormholes/tick() + if(activeFor % shift_frequency == 0) + for(var/obj/effect/portal/wormhole/O in wormholes) + var/turf/T = pick(pick_turfs) + if(T) + O.forceMove(T) + +/datum/event/wormholes/end() + QDEL_NULL_LIST(wormholes) + +/proc/create_wormhole(turf/enter, turf/exit) + if(!enter || !exit) + return + var/obj/effect/portal/wormhole/wormhole = new (enter) + wormhole.target = exit + return wormhole diff --git a/code/modules/ext_scripts/irc.dm b/code/modules/ext_scripts/irc.dm deleted file mode 100644 index dc894d839dee..000000000000 --- a/code/modules/ext_scripts/irc.dm +++ /dev/null @@ -1,55 +0,0 @@ -/proc/send2irc(var/channel, var/msg) - export2irc(list(type="msg", mesg=msg, chan=channel, pwd=config.comms_password)) - -/proc/export2irc(params) - if(config.use_irc_bot && config.irc_bot_host) - spawn(-1) // spawn here prevents hanging in the case that the bot isn't reachable - world.Export("http://[config.irc_bot_host]:45678?[list2params(params)]") - -/proc/runtimes2irc(runtimes, revision) - export2irc(list(pwd=config.comms_password, type="runtime", runtimes=runtimes, revision=revision)) - -/proc/send2mainirc(var/msg) - if(config.main_irc) - send2irc(config.main_irc, msg) - return - -/proc/send2adminirc(var/msg) - if(config.admin_irc) - send2irc(config.admin_irc, msg) - return - -/proc/adminmsg2adminirc(client/source, client/target, msg) - if(config.admin_irc) - var/list/params[0] - - params["pwd"] = config.comms_password - params["chan"] = config.admin_irc - params["msg"] = msg - params["src_key"] = source.key - params["src_char"] = source.mob.real_name || source.mob.name - if(!target) - params["type"] = "adminhelp" - else if(istext(target)) - params["type"] = "ircpm" - params["target"] = target - params["rank"] = source.holder ? source.holder.rank : "Player" - else - params["type"] = "adminpm" - params["trg_key"] = target.key - params["trg_char"] = target.mob.real_name || target.mob.name - - export2irc(params) - -/proc/get_world_url() - . = "byond://" - if(config.serverurl) - . += config.serverurl - else if(config.server) - . += config.server - else - . += "[world.address]:[world.port]" - -/hook/startup/proc/ircNotify() - send2mainirc("Server starting up on [get_world_url()]") - return 1 diff --git a/code/modules/fabrication/__fabricator_defines.dm b/code/modules/fabrication/__fabricator_defines.dm index a72ea2b6a71f..7ba16460d2dc 100644 --- a/code/modules/fabrication/__fabricator_defines.dm +++ b/code/modules/fabrication/__fabricator_defines.dm @@ -8,4 +8,5 @@ #define FABRICATOR_CLASS_IMPRINTER "imprinter" #define FABRICATOR_CLASS_INDUSTRIAL "industrial" #define FABRICATOR_CLASS_ROBOTICS "robotics" -#define FABRICATOR_CLASS_TEXTILE "textiles" \ No newline at end of file +#define FABRICATOR_CLASS_TEXTILE "textiles" +#define FABRICATOR_CLASS_MEAT "bioprinter" diff --git a/code/modules/fabrication/_fabricator.dm b/code/modules/fabrication/_fabricator.dm index 5de00ada29fd..23123ebfbdbb 100644 --- a/code/modules/fabrication/_fabricator.dm +++ b/code/modules/fabrication/_fabricator.dm @@ -1,10 +1,10 @@ /obj/machinery/fabricator name = "autolathe" - desc = "It produces common day to day items from a variety of materials." + desc = "It produces common day-to-day items from a variety of materials." icon = 'icons/obj/machines/fabricators/autolathe.dmi' icon_state = "autolathe" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 10 active_power_usage = 2000 clicksound = "keyboard" @@ -15,7 +15,6 @@ base_type = /obj/machinery/fabricator construct_state = /decl/machine_construction/default/panel_closed - var/has_recycler = TRUE var/color_selectable = FALSE // Allows selecting a color by the user in the UI, to do with as you please. var/selected_color = "white" @@ -27,25 +26,20 @@ var/datum/fabricator_build_order/currently_building var/fabricator_class = FABRICATOR_CLASS_GENERAL + var/filter_string - var/list/stored_material - var/list/storage_capacity - var/list/base_storage_capacity = list( - /decl/material/solid/metal/steel = SHEET_MATERIAL_AMOUNT * 20, - /decl/material/solid/metal/aluminium = SHEET_MATERIAL_AMOUNT * 20, - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 10, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 10 - ) + var/list/stored_material = list() + var/list/storage_capacity = list() + var/base_storage_capacity_mult = 20 + var/list/base_storage_capacity = list() - var/initial_id_tag var/show_category = "All" var/fab_status_flags = 0 var/mat_efficiency = 1.1 var/build_time_multiplier = 1 - var/global/list/stored_substances_to_names = list() var/list/design_cache = list() - var/list/installed_designs + var/list/installed_designs = list() var/sound_id var/datum/sound_token/sound_token @@ -56,21 +50,34 @@ var/initial_network_id var/initial_network_key + var/species_variation = /decl/species/human // If this fabricator is a variant for a specific species, this will be checked to unlock species-specific designs. + + // If TRUE, will accept atoms with contents. + var/ignore_input_contents_length = FALSE + + // If TRUE, fills fabricator with material on initalize + var/prefilled = FALSE + + //Collapsing Menus stuff + var/ui_expand_queue = FALSE + var/ui_expand_resources = FALSE + var/ui_expand_config = FALSE + var/ui_nb_categories = 1 //Cached amount of categories in loaded designs. Used to decide if we display the category filter or not + /obj/machinery/fabricator/Destroy() QDEL_NULL(currently_building) QDEL_NULL_LIST(queued_orders) QDEL_NULL(sound_token) . = ..() -/obj/machinery/fabricator/examine(mob/user) +/obj/machinery/fabricator/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(length(storage_capacity)) var/list/material_names = list() for(var/thing in storage_capacity) - material_names += "[storage_capacity[thing]] [stored_substances_to_names[thing]]" - to_chat(user, SPAN_NOTICE("It can store [english_list(material_names)].")) - if(has_recycler) - to_chat(user, SPAN_NOTICE("It has a built-in shredder that can recycle most items, although any materials it cannot use will be wasted.")) + var/decl/material/mat = GET_DECL(thing) + material_names += "[storage_capacity[thing]] [mat.use_name]" + . += SPAN_NOTICE("It can store [english_list(material_names)].") /obj/machinery/fabricator/Initialize() @@ -79,30 +86,36 @@ sound_id = "[fabricator_sound]" // Get any local network we need to be part of. - set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, NETWORK_CONNECTION_WIRED) + set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, RECEIVER_STRONG_WIRELESS) - // Initialize material storage lists. - stored_material = list() - for(var/mat in base_storage_capacity) - stored_material[mat] = 0 + if(SSfabrication.initialized) + refresh_design_cache() + else + SSfabrication.queue_design_cache_refresh(src) - // Update global type to string cache. - if(!stored_substances_to_names[mat]) - if(ispath(mat, /decl/material)) - var/decl/material/mat_instance = decls_repository.get_decl(mat) - if(istype(mat_instance)) - stored_substances_to_names[mat] = lowertext(mat_instance.name) - else if(ispath(mat, /decl/material)) - var/decl/material/reg = mat - stored_substances_to_names[mat] = lowertext(initial(reg.name)) +/obj/machinery/fabricator/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) + +/obj/machinery/fabricator/handle_post_network_connection() + ..() + refresh_design_cache() - SSfabrication.init_fabricator(src) +/obj/machinery/fabricator/proc/fill_to_capacity() + for(var/mat in storage_capacity) + stored_material[mat] = storage_capacity[mat] /obj/machinery/fabricator/proc/refresh_design_cache(var/list/known_tech) + + var/list/base_designs = SSfabrication.get_initial_recipes(fabricator_class) + design_cache = islist(base_designs) ? base_designs.Copy() : list() // Don't want to mutate the subsystem cache. + if(length(installed_designs)) design_cache |= installed_designs + if(!known_tech) - known_tech = list() + known_tech = get_default_initial_tech_levels() var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device) var/datum/computer_network/network = device.get_network() if(network) @@ -110,10 +123,51 @@ for(var/tech in db.tech_levels) if(db.tech_levels[tech] > known_tech[tech]) known_tech[tech] = db.tech_levels[tech] - if(length(known_tech)) - var/list/unlocked_tech = SSfabrication.get_unlocked_recipes(fabricator_class, known_tech) - if(length(unlocked_tech)) - design_cache |= unlocked_tech + + var/list/unlocked_tech = SSfabrication.get_unlocked_recipes(fabricator_class, known_tech) + if(length(unlocked_tech)) + design_cache |= unlocked_tech + + var/list/unique_categories + var/list/add_mat_to_storage_cap = list() + for(var/datum/fabricator_recipe/R in design_cache) + + for(var/mat in R.resources) + add_mat_to_storage_cap |= mat + + LAZYDISTINCTADD(unique_categories, R.category) + if(!length(R.species_locked)) + continue + + if(isnull(species_variation)) + design_cache.Remove(R) + continue + + for(var/species_type in R.species_locked) + if(!(ispath(species_variation, species_type))) + design_cache.Remove(R) + continue + + design_cache = sortTim(design_cache, /proc/cmp_name_asc) + ui_nb_categories = LAZYLEN(unique_categories) + + if(length(add_mat_to_storage_cap)) + var/need_storage_recalc = FALSE + for(var/mat in add_mat_to_storage_cap) + if(mat in base_storage_capacity) + continue + need_storage_recalc = TRUE + base_storage_capacity[mat] = (SHEET_MATERIAL_AMOUNT * base_storage_capacity_mult) + if(!(mat in stored_material)) + stored_material[mat] = 0 + + if(need_storage_recalc) + RefreshParts() + + // We handle this here, as we don't know what materials should be stocked prior to updating our recipes. + if(prefilled) + prefilled = FALSE + fill_to_capacity() /obj/machinery/fabricator/state_transition(var/decl/machine_construction/default/new_state) . = ..() @@ -131,13 +185,13 @@ /obj/machinery/fabricator/proc/is_functioning() . = use_power != POWER_USE_OFF && !(stat & NOPOWER) && !(stat & BROKEN) && !(fab_status_flags & FAB_DISABLED) -/obj/machinery/fabricator/Process(var/wait) +/obj/machinery/fabricator/Process(wait, tick) ..() if(use_power == POWER_USE_ACTIVE && (fab_status_flags & FAB_BUSY)) update_current_build(wait) /obj/machinery/fabricator/on_update_icon() - overlays.Cut() + cut_overlays() if(stat & NOPOWER) icon_state = "[base_icon_state]_d" else if(currently_building) @@ -148,7 +202,7 @@ var/list/new_overlays = material_overlays.Copy() if(panel_open) new_overlays += panel_image - overlays = new_overlays + set_overlays(new_overlays) /obj/machinery/fabricator/proc/remove_mat_overlay(var/mat_overlay) material_overlays -= mat_overlay @@ -157,23 +211,26 @@ //Updates overall lathe storage size. /obj/machinery/fabricator/RefreshParts() ..() - var/mb_rating = Clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 10) - var/man_rating = Clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 0.5, 3.5) - storage_capacity = list() + var/mb_rating = clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 10) + var/man_rating = clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 0.5, 3.5) for(var/mat in base_storage_capacity) storage_capacity[mat] = mb_rating * base_storage_capacity[mat] + if(!(mat in stored_material)) + stored_material[mat] = 0 mat_efficiency = initial(mat_efficiency) - man_rating * 0.1 build_time_multiplier = initial(build_time_multiplier) * man_rating /obj/machinery/fabricator/dismantle() for(var/mat in stored_material) - if(ispath(mat, /decl/material)) - var/mat_name = stored_substances_to_names[mat] - var/decl/material/M = decls_repository.get_decl(mat_name) - if(stored_material[mat] > SHEET_MATERIAL_AMOUNT) - M.place_sheet(get_turf(src), round(stored_material[mat] / SHEET_MATERIAL_AMOUNT), M.type) + if(stored_material[mat] > SHEET_MATERIAL_AMOUNT) + SSmaterials.create_object(mat, get_turf(src), round(stored_material[mat] / SHEET_MATERIAL_AMOUNT)) ..() return TRUE /obj/machinery/fabricator/proc/get_color_list() - return pipe_colors //override with null for hex color selections \ No newline at end of file + return pipe_colors //override with null for hex color selections + +// Our stored_material is just the right format to be added to the matter list. +/obj/machinery/fabricator/get_contained_matter(include_reagents = TRUE) + . = ..() + . = MERGE_ASSOCS_WITH_NUM_VALUES(., stored_material) \ No newline at end of file diff --git a/code/modules/fabrication/_fabricator_build_order.dm b/code/modules/fabrication/_fabricator_build_order.dm index 6dedfb8afc98..06f39cf4904a 100644 --- a/code/modules/fabrication/_fabricator_build_order.dm +++ b/code/modules/fabrication/_fabricator_build_order.dm @@ -3,7 +3,27 @@ var/multiplier = 1 var/remaining_time = 0 var/list/earmarked_materials = list() + var/list/data //Fabricator specific data + +/datum/fabricator_build_order/New(var/datum/fabricator_recipe/_target_recipe, var/_multiplier = 1, var/list/_data = null) + ..() + target_recipe = _target_recipe + multiplier = _multiplier + data = _data /datum/fabricator_build_order/Destroy() target_recipe = null . = ..() + +/datum/fabricator_build_order/proc/set_data(var/name, var/value) + if(!name || !value) + return + LAZYSET(data, name, value) + +//Returns the data entry for "name" or whatever is in "default" if there's nothing found +//Helps not having to deal with writing extra conditionals +/datum/fabricator_build_order/proc/get_data(var/name, var/default = null) + if(!name) + return default + var/value = LAZYACCESS(data, name) + return value ? value : default diff --git a/code/modules/fabrication/designs/_design.dm b/code/modules/fabrication/designs/_design.dm index e2ca911b578c..0b4e7ecd7114 100644 --- a/code/modules/fabrication/designs/_design.dm +++ b/code/modules/fabrication/designs/_design.dm @@ -9,28 +9,27 @@ ) var/build_time = 5 SECONDS var/max_amount = 1 // How many instances can be queued at once - var/ignore_materials = list( - /decl/material/solid/slag = TRUE - ) var/list/required_technology + var/list/species_locked + /// Set to explicit FALSE to cause n stacks to be created instead of 1 stack of n amount. + /// Does not work for non-stacks being created as stacks, do not set to explicit TRUE for non-stacks. + var/pass_multiplier_to_product_new // Populate name and resources from the product type. /datum/fabricator_recipe/proc/get_product_name() - var/obj/O = path - . = initial(O.name) + . = atom_info_repository.get_name_for(path, _amount = 1) /datum/fabricator_recipe/New() ..() if(!path) return + if(isnull(pass_multiplier_to_product_new)) + pass_multiplier_to_product_new = ispath(path, /obj/item/stack) if(!name) name = get_product_name() if(required_technology == TRUE) if(ispath(path, /obj/item)) - var/obj/item/O = path - var/tech = initial(O.origin_tech) - if(tech) - required_technology = json_decode(tech) + required_technology = atom_info_repository.get_origin_tech_for(path, _amount = 1) if(!islist(required_technology)) required_technology = list() if(!resources) @@ -46,28 +45,19 @@ check_tech -= tech return !length(check_tech) +/datum/fabricator_recipe/proc/is_available_to_fab(var/obj/machinery/fabricator/fab) + return TRUE + /datum/fabricator_recipe/proc/get_resources() resources = list() var/list/building_cost = atom_info_repository.get_matter_for(path) for(var/mat in building_cost) - if(!ignore_materials[mat]) - resources[mat] = building_cost[mat] * FABRICATOR_EXTRA_COST_FACTOR + resources[mat] = building_cost[mat] * FABRICATOR_EXTRA_COST_FACTOR -/obj/building_cost() - . = ..() - if(length(matter)) - for(var/material in matter) - var/decl/material/M = decls_repository.get_decl(material) - if(istype(M)) - .[M.type] = matter[material] - if(reagents && length(reagents.reagent_volumes)) - for(var/R in reagents.reagent_volumes) - .[R] = REAGENT_VOLUME(reagents, R) - -/datum/fabricator_recipe/proc/build(var/turf/location, var/amount = 1) +/datum/fabricator_recipe/proc/build(var/turf/location, var/datum/fabricator_build_order/order) . = list() - if(ispath(path, /obj/item/stack)) - . += new path(location, amount) + if(ispath(path, /obj/item/stack) && pass_multiplier_to_product_new) + . += new path(location, order.multiplier) else - for(var/i = 1, i <= amount, i++) - . += new path(location) \ No newline at end of file + for(var/i = 1, i <= order.multiplier, i++) + . += new path(location) diff --git a/code/modules/fabrication/designs/general/designs_arms_ammo.dm b/code/modules/fabrication/designs/general/designs_arms_ammo.dm index 0960b0f03f75..2fd82b739386 100644 --- a/code/modules/fabrication/designs/general/designs_arms_ammo.dm +++ b/code/modules/fabrication/designs/general/designs_arms_ammo.dm @@ -11,10 +11,10 @@ /datum/fabricator_recipe/arms_ammo/flaregun name = "flare gun" - path = /obj/item/weapon/gun/projectile/flare + path = /obj/item/gun/projectile/flare /datum/fabricator_recipe/arms_ammo/hidden - path = /obj/item/hatchet/machete/steel + path = /obj/item/tool/machete/steel hidden = TRUE /datum/fabricator_recipe/arms_ammo/hidden/shotgun @@ -48,6 +48,14 @@ name = "ammunition (holdout)" path = /obj/item/ammo_magazine/pistol/small +/datum/fabricator_recipe/arms_ammo/hidden/magazine_practice + name = "ammunition (pistol, practice)" + path = /obj/item/ammo_magazine/pistol/practice + +/datum/fabricator_recipe/arms_ammo/hidden/magazine_flass + name = "ammunition (pistol, flash)" + path = /obj/item/ammo_magazine/pistol/flash + /datum/fabricator_recipe/arms_ammo/hidden/magazine_smg_topmounted name = "ammunition (SMG, top mounted)" path = /obj/item/ammo_magazine/smg @@ -73,4 +81,8 @@ /datum/fabricator_recipe/arms_ammo/hidden/speedloader_laser name = "ammunition (speedloader, laserbulb)" - path = /obj/item/ammo_magazine/laser_revolver \ No newline at end of file + path = /obj/item/ammo_magazine/speedloader/laser_revolver + +/datum/fabricator_recipe/arms_ammo/hidden/mine_assembly + name = "mine assembly" + path = /obj/item/mine/assembly diff --git a/code/modules/fabrication/designs/general/designs_devices_components.dm b/code/modules/fabrication/designs/general/designs_devices_components.dm index 65ce705c5b5f..dd732867b353 100644 --- a/code/modules/fabrication/designs/general/designs_devices_components.dm +++ b/code/modules/fabrication/designs/general/designs_devices_components.dm @@ -5,6 +5,9 @@ /datum/fabricator_recipe/device_component/keyboard path = /obj/item/stock_parts/keyboard +/datum/fabricator_recipe/device_component/pda + path = /obj/item/modular_computer/pda + /datum/fabricator_recipe/device_component/tesla_component path = /obj/item/stock_parts/power/apc/buildable @@ -39,6 +42,12 @@ /datum/fabricator_recipe/device_component/access_lock path = /obj/item/stock_parts/access_lock/buildable +/datum/fabricator_recipe/device_component/network_lock + path = /obj/item/stock_parts/network_receiver/network_lock/buildable + +/datum/fabricator_recipe/device_component/network_receiver + path = /obj/item/stock_parts/network_receiver/buildable + /datum/fabricator_recipe/device_component/igniter path = /obj/item/assembly/igniter @@ -57,9 +66,8 @@ /datum/fabricator_recipe/device_component/cable_coil path = /obj/item/stack/cable_coil/single -/datum/fabricator_recipe/device_component/electropack - path = /obj/item/radio/electropack - hidden = TRUE +/datum/fabricator_recipe/device_component/net_cable_coil + path = /obj/item/stack/net_cable_coil/single /datum/fabricator_recipe/device_component/beartrap path = /obj/item/beartrap diff --git a/code/modules/fabrication/designs/general/designs_engineering.dm b/code/modules/fabrication/designs/general/designs_engineering.dm index 128d3881b20c..bb76b11ed1f0 100644 --- a/code/modules/fabrication/designs/general/designs_engineering.dm +++ b/code/modules/fabrication/designs/general/designs_engineering.dm @@ -29,27 +29,42 @@ /datum/fabricator_recipe/engineering/wallcharger path = /obj/item/frame/button/wall_charger/kit -/datum/fabricator_recipe/engineering/light_switch - path = /obj/item/frame/button/light_switch/kit - -/datum/fabricator_recipe/engineering/window_tint - path = /obj/item/frame/button/light_switch/windowtint/kit - -/datum/fabricator_recipe/engineering/spotlight - path = /obj/item/frame/light/spot - -/datum/fabricator_recipe/engineering/navlight - path = /obj/item/frame/light/nav - /datum/fabricator_recipe/engineering/button_frame path = /obj/item/frame/button - -/datum/fabricator_recipe/engineering/airlock_sensor - path = /obj/item/frame/button/airlock_sensor +/datum/fabricator_recipe/engineering/button_kit + path = /obj/item/frame/button/kit + +/datum/fabricator_recipe/engineering/button_frame_door + path = /obj/item/frame/button/alternate +/datum/fabricator_recipe/engineering/button_kit_door + path = /obj/item/frame/button/alternate/kit + +/datum/fabricator_recipe/engineering/button_frame_blast + path = /obj/item/frame/button/blastdoor +/datum/fabricator_recipe/engineering/button_kit_blast + path = /obj/item/frame/button/blastdoor/kit + +/datum/fabricator_recipe/engineering/airlock_button_frame + path = /obj/item/frame/button/airlock_controller_config/access +/datum/fabricator_recipe/engineering/airlock_button_kit + path = /obj/item/frame/button/airlock_controller_config/access/kit + +/datum/fabricator_recipe/engineering/airlock_sensor_frame + path = /obj/item/frame/button/airlock_controller_config/airlock_sensor +/datum/fabricator_recipe/engineering/airlock_sensor_kit + path = /obj/item/frame/button/airlock_controller_config/airlock_sensor/kit + +/datum/fabricator_recipe/engineering/airlock_controller_frame + path = /obj/item/frame/button/airlock_controller +/datum/fabricator_recipe/engineering/airlock_controller_kit + path = /obj/item/frame/button/airlock_controller/kit /datum/fabricator_recipe/engineering/airlock_controller path = /obj/item/stock_parts/circuitboard/airlock_controller +/datum/fabricator_recipe/engineering/camera + path = /obj/item/stock_parts/circuitboard/camera + /datum/fabricator_recipe/engineering/powermodule path = /obj/item/stock_parts/circuitboard/apc @@ -92,8 +107,11 @@ /datum/fabricator_recipe/engineering/rcd_ammo_large path = /obj/item/rcd_ammo/large -/datum/fabricator_recipe/engineering/camera_assembly - path = /obj/item/camera_assembly +/datum/fabricator_recipe/engineering/camera_frame + path = /obj/item/frame/camera + +/datum/fabricator_recipe/engineering/camera_frame/kit + path = /obj/item/frame/camera/kit /datum/fabricator_recipe/engineering/rcd path = /obj/item/rcd @@ -102,5 +120,26 @@ /datum/fabricator_recipe/engineering/solars path = /obj/item/solar_assembly +/datum/fabricator_recipe/engineering/tracker_electronics + path = /obj/item/tracker_electronics + /datum/fabricator_recipe/engineering/power_sensor - path = /obj/item/machine_chassis/power_sensor \ No newline at end of file + path = /obj/item/machine_chassis/power_sensor + +/datum/fabricator_recipe/engineering/wall_router + path = /obj/item/frame/wall_router + +/datum/fabricator_recipe/engineering/wall_relay + path = /obj/item/frame/wall_relay + +/datum/fabricator_recipe/engineering/oxygen_tank + path = /obj/item/tank/oxygen/empty + +/datum/fabricator_recipe/engineering/hydrogen_tank + path = /obj/item/tank/hydrogen/empty + +/datum/fabricator_recipe/engineering/stirling_piston + path = /obj/item/tank/stirling/empty + +/datum/fabricator_recipe/engineering/welderpack + path = /obj/item/chems/weldpack/empty diff --git a/code/modules/fabrication/designs/general/designs_general.dm b/code/modules/fabrication/designs/general/designs_general.dm index 3aa7ccd0b9a2..aef3b2e9a27a 100644 --- a/code/modules/fabrication/designs/general/designs_general.dm +++ b/code/modules/fabrication/designs/general/designs_general.dm @@ -8,17 +8,29 @@ path = /obj/machinery/floor_light /datum/fabricator_recipe/extinguisher - path = /obj/item/extinguisher/empty + path = /obj/item/chems/spray/extinguisher/empty + +/datum/fabricator_recipe/extinguisher/mini + path = /obj/item/chems/spray/extinguisher/mini/empty /datum/fabricator_recipe/jar path = /obj/item/glass_jar +/datum/fabricator_recipe/pot + path = /obj/item/chems/cooking_vessel/pot + +/datum/fabricator_recipe/skillet + path = /obj/item/chems/cooking_vessel/skillet + /datum/fabricator_recipe/radio_headset path = /obj/item/radio/headset -/datum/fabricator_recipe/radio_bounced +/datum/fabricator_recipe/radio_dual path = /obj/item/radio/off +/datum/fabricator_recipe/radio_shortwave + path = /obj/item/radio/shortwave/off + /datum/fabricator_recipe/suit_cooler path = /obj/item/suit_cooling_unit @@ -31,17 +43,8 @@ /datum/fabricator_recipe/taperecorder path = /obj/item/taperecorder/empty -/datum/fabricator_recipe/tape - path = /obj/item/tape - -/datum/fabricator_recipe/tube/large - path = /obj/item/light/tube/large - -/datum/fabricator_recipe/tube - path = /obj/item/light/tube - -/datum/fabricator_recipe/bulb - path = /obj/item/light/bulb +/datum/fabricator_recipe/taperecorder_tape + path = /obj/item/magnetic_tape /datum/fabricator_recipe/ashtray_glass path = /obj/item/ashtray/glass @@ -88,4 +91,129 @@ hidden = TRUE /datum/fabricator_recipe/plunger - path = /obj/item/clothing/mask/plunger + path = /obj/item/plunger + +/datum/fabricator_recipe/fiberglass + path = /obj/item/stack/material/sheet/reinforced/mapped/fiberglass + category = "Textiles" + fabricator_types = list( + FABRICATOR_CLASS_GENERAL, + FABRICATOR_CLASS_TEXTILE + ) + +/datum/fabricator_recipe/fiberglass/get_resources() + resources = list( + /decl/material/solid/glass = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) + +/datum/fabricator_recipe/rods + name = "rod, steel" + path = /obj/item/stack/material/rods/mapped/steel + +/datum/fabricator_recipe/rods/plastic + name = "rod, plastic" + path = /obj/item/stack/material/rods/mapped/plastic + +/datum/fabricator_recipe/rods/aluminium + name = "rod, aluminium" + path = /obj/item/stack/material/rods/mapped/aluminium + fabricator_types = list(FABRICATOR_CLASS_INDUSTRIAL) + +/datum/fabricator_recipe/rods/titanium + name = "rod, titanium" + path = /obj/item/stack/material/rods/mapped/titanium + fabricator_types = list(FABRICATOR_CLASS_INDUSTRIAL) + +/datum/fabricator_recipe/umbrella + path = /obj/item/umbrella + +/datum/fabricator_recipe/network_id + path = /obj/item/card/id/network + fabricator_types = list( + FABRICATOR_CLASS_GENERAL + ) + +/datum/fabricator_recipe/emergency_tank + path = /obj/item/tank/emergency + +/datum/fabricator_recipe/package_wrapper + path = /obj/item/stack/package_wrap + +/datum/fabricator_recipe/package_wrapper/gift + path = /obj/item/stack/package_wrap/gift + +/datum/fabricator_recipe/clothes_iron + path = /obj/item/ironingiron + +/datum/fabricator_recipe/ironing_board + path = /obj/item/roller/ironingboard + +/datum/fabricator_recipe/duct_tape + path = /obj/item/stack/tape_roll/duct_tape + pass_multiplier_to_product_new = FALSE // they are printed as single items with 32 uses + +/datum/fabricator_recipe/fishing_line + path = /obj/item/fishing_line + +/datum/fabricator_recipe/fishing_line_high_quality + path = /obj/item/fishing_line/high_quality + +/datum/fabricator_recipe/chipboard // base type is for oak + path = /obj/item/stack/material/sheet/mapped/chipboard_oak + category = "Textiles" + fabricator_types = list( + FABRICATOR_CLASS_GENERAL, + FABRICATOR_CLASS_TEXTILE + ) + +/datum/fabricator_recipe/chipboard/get_resources() + resources = list( + /decl/material/solid/organic/wood/oak = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) + +/datum/fabricator_recipe/chipboard/maple + path = /obj/item/stack/material/sheet/mapped/chipboard_maple + +/datum/fabricator_recipe/chipboard/maple/get_resources() + resources = list( + /decl/material/solid/organic/wood/maple = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) + +/datum/fabricator_recipe/chipboard/mahogany + path = /obj/item/stack/material/sheet/mapped/chipboard_mahogany + +/datum/fabricator_recipe/chipboard/mahogany/get_resources() + resources = list( + /decl/material/solid/organic/wood/mahogany = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) + +/datum/fabricator_recipe/chipboard/ebony + path = /obj/item/stack/material/sheet/mapped/chipboard_ebony + +/datum/fabricator_recipe/chipboard/ebony/get_resources() + resources = list( + /decl/material/solid/organic/wood/ebony = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) + +/datum/fabricator_recipe/chipboard/walnut + path = /obj/item/stack/material/sheet/mapped/chipboard_walnut + +/datum/fabricator_recipe/chipboard/walnut/get_resources() + resources = list( + /decl/material/solid/organic/wood/walnut = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) + +/datum/fabricator_recipe/chipboard/yew + path = /obj/item/stack/material/sheet/mapped/chipboard_yew + +/datum/fabricator_recipe/chipboard/yew/get_resources() + resources = list( + /decl/material/solid/organic/wood/yew = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2), + /decl/material/solid/organic/plastic = ceil((SHEET_MATERIAL_AMOUNT * FABRICATOR_EXTRA_COST_FACTOR)/2) + ) diff --git a/code/modules/fabrication/designs/general/designs_medical.dm b/code/modules/fabrication/designs/general/designs_medical.dm index 3d742166552c..12009756c734 100644 --- a/code/modules/fabrication/designs/general/designs_medical.dm +++ b/code/modules/fabrication/designs/general/designs_medical.dm @@ -39,7 +39,7 @@ path = /obj/item/implanter /datum/fabricator_recipe/medical/pill_bottle - path = /obj/item/storage/pill_bottle + path = /obj/item/pill_bottle /datum/fabricator_recipe/medical/hypospray/autoinjector path = /obj/item/chems/hypospray/autoinjector/empty diff --git a/code/modules/fabrication/designs/general/designs_textiles.dm b/code/modules/fabrication/designs/general/designs_textiles.dm deleted file mode 100644 index 3fd37785a87f..000000000000 --- a/code/modules/fabrication/designs/general/designs_textiles.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/fabricator_recipe/textiles - path = /obj/item/clothing/suit - category = "Textiles" - fabricator_types = list(FABRICATOR_CLASS_TEXTILE) - -/datum/fabricator_recipe/textiles/space - path = /obj/item/clothing/suit/space - -/datum/fabricator_recipe/textiles/space/helmet - path = /obj/item/clothing/head/helmet/space - -/datum/fabricator_recipe/textiles/space/jetpack - path = /obj/item/tank/jetpack/oxygen - -/datum/fabricator_recipe/textiles/breath_mask - path = /obj/item/clothing/mask/breath - -/datum/fabricator_recipe/textiles/space/emergency - path = /obj/item/clothing/suit/space/emergency - -/datum/fabricator_recipe/textiles/space/emergency/helmet - path = /obj/item/clothing/head/helmet/space/emergency - -/datum/fabricator_recipe/textiles/space/engineering - path = /obj/item/clothing/suit/space/void/engineering/alt - -/datum/fabricator_recipe/textiles/space/engineering/helmet - path = /obj/item/clothing/head/helmet/space/void/engineering/alt - -/datum/fabricator_recipe/textiles/space/magboots - path = /obj/item/clothing/shoes/magboots - -/datum/fabricator_recipe/textiles/space/void - path = /obj/item/clothing/suit/space/void - -/datum/fabricator_recipe/textiles/space/mining - path = /obj/item/clothing/suit/space/void/mining - -/datum/fabricator_recipe/textiles/space/salvage - path = /obj/item/clothing/suit/space/void/engineering/salvage \ No newline at end of file diff --git a/code/modules/fabrication/designs/general/designs_tools.dm b/code/modules/fabrication/designs/general/designs_tools.dm index a89aa20097ee..1c9fc7d94818 100644 --- a/code/modules/fabrication/designs/general/designs_tools.dm +++ b/code/modules/fabrication/designs/general/designs_tools.dm @@ -2,15 +2,6 @@ path = /obj/item/crowbar category = "Tools" -/datum/fabricator_recipe/tool/int_wirer - path = /obj/item/integrated_electronics/wirer - -/datum/fabricator_recipe/tool/int_debugger - path = /obj/item/integrated_electronics/debugger - -/datum/fabricator_recipe/tool/int_analyzer - path = /obj/item/integrated_electronics/analyzer - /datum/fabricator_recipe/tool/multitool path = /obj/item/multitool @@ -30,11 +21,23 @@ path = /obj/item/wrench /datum/fabricator_recipe/tool/hatchet - path = /obj/item/hatchet + path = /obj/item/tool/axe/hatchet /datum/fabricator_recipe/tool/minihoe - path = /obj/item/minihoe + path = /obj/item/tool/hoe/mini + +/datum/fabricator_recipe/tool/inflatable_wall + path = /obj/item/inflatable + +/datum/fabricator_recipe/tool/inflatable_door + path = /obj/item/inflatable/door /datum/fabricator_recipe/tool/welder_industrial path = /obj/item/weldingtool/largetank hidden = TRUE + +/datum/fabricator_recipe/tool/hoist_kit + path = /obj/item/hoist_kit + +/datum/fabricator_recipe/tool/mobile_ladder + path = /obj/item/mobile_ladder \ No newline at end of file diff --git a/code/modules/fabrication/designs/imprinter/_designs_imprinter.dm b/code/modules/fabrication/designs/imprinter/_designs_imprinter.dm index cc843b651584..5f0207f8b754 100644 --- a/code/modules/fabrication/designs/imprinter/_designs_imprinter.dm +++ b/code/modules/fabrication/designs/imprinter/_designs_imprinter.dm @@ -4,4 +4,5 @@ /datum/fabricator_recipe/imprinter/get_resources() . = ..() - LAZYSET(resources, /decl/material/liquid/acid, 20) + // 1 sheet of matter is 20u of reagents, which is converted during fabricator input + LAZYSET(resources, /decl/material/liquid/acid, SHEET_MATERIAL_AMOUNT) diff --git a/code/modules/fabrication/designs/imprinter/designs_computer_components.dm b/code/modules/fabrication/designs/imprinter/designs_computer_components.dm index 74a5bd4ef755..a45712bda61e 100644 --- a/code/modules/fabrication/designs/imprinter/designs_computer_components.dm +++ b/code/modules/fabrication/designs/imprinter/designs_computer_components.dm @@ -8,8 +8,8 @@ /datum/fabricator_recipe/imprinter/comp_network/advanced path = /obj/item/stock_parts/computer/network_card/advanced -/datum/fabricator_recipe/imprinter/comp_network/wired - path = /obj/item/stock_parts/computer/network_card/wired +/datum/fabricator_recipe/imprinter/comp_network/lan_port + path = /obj/item/stock_parts/computer/lan_port /datum/fabricator_recipe/imprinter/comp_data category = "Portable Data Storage" diff --git a/code/modules/fabrication/designs/imprinter/designs_exosuit_software.dm b/code/modules/fabrication/designs/imprinter/designs_exosuit_software.dm index 9909f0220756..c843999edad2 100644 --- a/code/modules/fabrication/designs/imprinter/designs_exosuit_software.dm +++ b/code/modules/fabrication/designs/imprinter/designs_exosuit_software.dm @@ -1,15 +1,15 @@ /datum/fabricator_recipe/imprinter/exosuit category = "Exosuit Software" - path = /obj/item/circuitboard/exosystem/engineering + path = /obj/item/stock_parts/circuitboard/exosystem/engineering /datum/fabricator_recipe/imprinter/exosuit/get_product_name() . = "exosuit software design ([..()])" /datum/fabricator_recipe/imprinter/exosuit/utility - path = /obj/item/circuitboard/exosystem/utility + path = /obj/item/stock_parts/circuitboard/exosystem/utility /datum/fabricator_recipe/imprinter/exosuit/medical - path = /obj/item/circuitboard/exosystem/medical + path = /obj/item/stock_parts/circuitboard/exosystem/medical /datum/fabricator_recipe/imprinter/exosuit/weapons - path = /obj/item/circuitboard/exosystem/weapons + path = /obj/item/stock_parts/circuitboard/exosystem/weapons diff --git a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm index 697bbccaace6..7f85bd5fe3ae 100644 --- a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm +++ b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm @@ -5,11 +5,17 @@ /datum/fabricator_recipe/imprinter/circuit/get_product_name() . = "machine circuit design ([..()])" +/datum/fabricator_recipe/imprinter/circuit/fission_core + path = /obj/item/stock_parts/circuitboard/unary_atmos/fission_core + +/datum/fabricator_recipe/imprinter/circuit/fission_core_control + path = /obj/item/stock_parts/circuitboard/fission_core_control + /datum/fabricator_recipe/imprinter/circuit/fusion path = /obj/item/stock_parts/circuitboard/fusion/core_control -/datum/fabricator_recipe/imprinter/circuit/fusion_fuel_compressor - path = /obj/item/stock_parts/circuitboard/fusion_fuel_compressor +/datum/fabricator_recipe/imprinter/circuit/fuel_compressor + path = /obj/item/stock_parts/circuitboard/fuel_compressor /datum/fabricator_recipe/imprinter/circuit/fusion_fuel_control path = /obj/item/stock_parts/circuitboard/fusion_fuel_control @@ -56,26 +62,20 @@ /datum/fabricator_recipe/imprinter/circuit/bioprinter path = /obj/item/stock_parts/circuitboard/bioprinter -/datum/fabricator_recipe/imprinter/circuit/roboprinter - path = /obj/item/stock_parts/circuitboard/roboprinter - /datum/fabricator_recipe/imprinter/circuit/teleconsole path = /obj/item/stock_parts/circuitboard/teleporter /datum/fabricator_recipe/imprinter/circuit/robocontrol path = /obj/item/stock_parts/circuitboard/robotics -/datum/fabricator_recipe/imprinter/circuit/comm_monitor - path = /obj/item/stock_parts/circuitboard/comm_monitor - -/datum/fabricator_recipe/imprinter/circuit/comm_server - path = /obj/item/stock_parts/circuitboard/comm_server - /datum/fabricator_recipe/imprinter/circuit/message_monitor path = /obj/item/stock_parts/circuitboard/message_monitor /datum/fabricator_recipe/imprinter/circuit/message_server - path = /obj/item/stock_parts/circuitboard/telecomms/message_server + path = /obj/item/stock_parts/circuitboard/message_server + +/datum/fabricator_recipe/imprinter/circuit/telecomms_hub + path = /obj/item/stock_parts/circuitboard/telecomms_hub /datum/fabricator_recipe/imprinter/circuit/guestpass path = /obj/item/stock_parts/circuitboard/guestpass @@ -84,7 +84,7 @@ path = /obj/item/stock_parts/circuitboard/account_database /datum/fabricator_recipe/imprinter/circuit/holo - path = /obj/item/stock_parts/circuitboard/holodeckcontrol + path = /obj/item/stock_parts/circuitboard/holodeck_control /datum/fabricator_recipe/imprinter/circuit/aiupload path = /obj/item/stock_parts/circuitboard/aiupload @@ -98,6 +98,9 @@ /datum/fabricator_recipe/imprinter/circuit/robot_storage path = /obj/item/stock_parts/circuitboard/robotstoragecontrol +/datum/fabricator_recipe/imprinter/circuit/checkpoint_control + path = /obj/item/stock_parts/circuitboard/checkpointcontrol + /datum/fabricator_recipe/imprinter/circuit/destructive_analyzer path = /obj/item/stock_parts/circuitboard/destructive_analyzer @@ -110,6 +113,9 @@ /datum/fabricator_recipe/imprinter/circuit/autolathe path = /obj/item/stock_parts/circuitboard/autolathe +/datum/fabricator_recipe/imprinter/circuit/recycler + path = /obj/item/stock_parts/circuitboard/recycler + /datum/fabricator_recipe/imprinter/circuit/replicator path = /obj/item/stock_parts/circuitboard/replicator @@ -119,12 +125,12 @@ /datum/fabricator_recipe/imprinter/circuit/autobinder path = /obj/item/stock_parts/circuitboard/autolathe/book -/datum/fabricator_recipe/imprinter/circuit/mining_console - path = /obj/item/stock_parts/circuitboard/mineral_processing - /datum/fabricator_recipe/imprinter/circuit/mining_processor path = /obj/item/stock_parts/circuitboard/mining_processor +/datum/fabricator_recipe/imprinter/circuit/mining_compressor + path = /obj/item/stock_parts/circuitboard/mining_compressor + /datum/fabricator_recipe/imprinter/circuit/mining_unloader path = /obj/item/stock_parts/circuitboard/mining_unloader @@ -167,15 +173,9 @@ /datum/fabricator_recipe/imprinter/circuit/dronecontrol path = /obj/item/stock_parts/circuitboard/drone_control -/datum/fabricator_recipe/imprinter/circuit/powermonitor - path = /obj/item/stock_parts/circuitboard/powermonitor - /datum/fabricator_recipe/imprinter/circuit/solarcontrol path = /obj/item/stock_parts/circuitboard/solar_control -/datum/fabricator_recipe/imprinter/circuit/supermatter_control - path = /obj/item/stock_parts/circuitboard/air_management/supermatter_core - /datum/fabricator_recipe/imprinter/circuit/injector path = /obj/item/stock_parts/circuitboard/air_management/injector_control @@ -215,8 +215,11 @@ /datum/fabricator_recipe/imprinter/circuit/reagent_cooler path = /obj/item/stock_parts/circuitboard/reagent_heater/cooler -/datum/fabricator_recipe/imprinter/circuit/atmos_control - path = /obj/item/stock_parts/circuitboard/atmoscontrol +/datum/fabricator_recipe/imprinter/circuit/chem_master + path = /obj/item/stock_parts/circuitboard/chem_master + +/datum/fabricator_recipe/imprinter/circuit/chemical_dispenser + path = /obj/item/stock_parts/circuitboard/chemical_dispenser /datum/fabricator_recipe/imprinter/circuit/pipe_dispenser path = /obj/item/stock_parts/circuitboard/pipedispensor @@ -245,6 +248,12 @@ /datum/fabricator_recipe/imprinter/circuit/helms path = /obj/item/stock_parts/circuitboard/helm +/datum/fabricator_recipe/imprinter/circuit/ftl + path = /obj/item/stock_parts/circuitboard/ftl + +/datum/fabricator_recipe/imprinter/circuit/ftl_shunt + path = /obj/item/stock_parts/circuitboard/ftl_shunt + /datum/fabricator_recipe/imprinter/circuit/nav path = /obj/item/stock_parts/circuitboard/nav @@ -254,12 +263,18 @@ /datum/fabricator_recipe/imprinter/circuit/design_console path = /obj/item/stock_parts/circuitboard/design_console +/datum/fabricator_recipe/imprinter/circuit/design_database + path = /obj/item/stock_parts/circuitboard/design_database + /datum/fabricator_recipe/imprinter/circuit/sensors path = /obj/item/stock_parts/circuitboard/sensors /datum/fabricator_recipe/imprinter/circuit/engine path = /obj/item/stock_parts/circuitboard/engine +/datum/fabricator_recipe/imprinter/circuit/ion_engine + path = /obj/item/stock_parts/circuitboard/engine/ion + /datum/fabricator_recipe/imprinter/circuit/shuttle path = /obj/item/stock_parts/circuitboard/shuttle_console @@ -287,9 +302,6 @@ /datum/fabricator_recipe/imprinter/circuit/miningdrill path = /obj/item/stock_parts/circuitboard/miningdrill -/datum/fabricator_recipe/imprinter/circuit/miningdrillbrace - path = /obj/item/stock_parts/circuitboard/miningdrillbrace - /datum/fabricator_recipe/imprinter/circuit/floodlight path = /obj/item/stock_parts/circuitboard/floodlight @@ -305,24 +317,6 @@ /datum/fabricator_recipe/imprinter/circuit/disperser_console path = /obj/item/stock_parts/circuitboard/disperser -/datum/fabricator_recipe/imprinter/circuit/tcom_server - path = /obj/item/stock_parts/circuitboard/telecomms/server - -/datum/fabricator_recipe/imprinter/circuit/tcom_processor - path = /obj/item/stock_parts/circuitboard/telecomms/processor - -/datum/fabricator_recipe/imprinter/circuit/tcom_bus - path = /obj/item/stock_parts/circuitboard/telecomms/bus - -/datum/fabricator_recipe/imprinter/circuit/tcom_hub - path = /obj/item/stock_parts/circuitboard/telecomms/hub - -/datum/fabricator_recipe/imprinter/circuit/tcom_broadcaster - path = /obj/item/stock_parts/circuitboard/telecomms/broadcaster - -/datum/fabricator_recipe/imprinter/circuit/tcom_receiver - path = /obj/item/stock_parts/circuitboard/telecomms/receiver - /datum/fabricator_recipe/imprinter/circuit/comms_relay path = /obj/item/stock_parts/circuitboard/commsrelay @@ -341,6 +335,9 @@ /datum/fabricator_recipe/imprinter/circuit/washer path = /obj/item/stock_parts/circuitboard/washer +/datum/fabricator_recipe/imprinter/circuit/autoclave + path = /obj/item/stock_parts/circuitboard/autoclave + /datum/fabricator_recipe/imprinter/circuit/microwave path = /obj/item/stock_parts/circuitboard/microwave @@ -350,11 +347,11 @@ /datum/fabricator_recipe/imprinter/circuit/cooker path = /obj/item/stock_parts/circuitboard/cooker -/datum/fabricator_recipe/imprinter/circuit/honey_extractor - path = /obj/item/stock_parts/circuitboard/honey +/datum/fabricator_recipe/imprinter/circuit/centrifuge + path = /obj/item/stock_parts/circuitboard/centrifuge /datum/fabricator_recipe/imprinter/circuit/seed_extractor - path = /obj/item/stock_parts/circuitboard/honey/seed + path = /obj/item/stock_parts/circuitboard/seed_extractor /datum/fabricator_recipe/imprinter/circuit/vending path = /obj/item/stock_parts/circuitboard/vending @@ -368,9 +365,15 @@ /datum/fabricator_recipe/imprinter/circuit/modular_computer path = /obj/item/stock_parts/circuitboard/modular_computer +/datum/fabricator_recipe/imprinter/circuit/modular_computer_telescreen + path = /obj/item/stock_parts/circuitboard/modular_computer/telescreen + /datum/fabricator_recipe/imprinter/circuit/shipsensors path = /obj/item/stock_parts/circuitboard/shipsensors +/datum/fabricator_recipe/imprinter/circuit/nuclear_cylinder_storage + path = /obj/item/stock_parts/circuitboard/nuclear_cylinder_storage + /datum/fabricator_recipe/imprinter/circuit/grinder path = /obj/item/stock_parts/circuitboard/grinder @@ -422,9 +425,15 @@ /datum/fabricator_recipe/imprinter/circuit/merchant_pad path = /obj/item/stock_parts/circuitboard/merchant_pad +/datum/fabricator_recipe/imprinter/circuit/radiocarbon_spectrometer + path = /obj/item/stock_parts/circuitboard/radiocarbon_spectrometer + /datum/fabricator_recipe/imprinter/circuit/jukebox path = /obj/item/stock_parts/circuitboard/jukebox +/datum/fabricator_recipe/imprinter/circuit/paper_shredder + path = /obj/item/stock_parts/circuitboard/paper_shredder + /datum/fabricator_recipe/imprinter/circuit/forensic path = /obj/item/stock_parts/circuitboard/forensic @@ -443,8 +452,44 @@ /datum/fabricator_recipe/imprinter/circuit/router path = /obj/item/stock_parts/circuitboard/router +/datum/fabricator_recipe/imprinter/circuit/router_wall_mounted + path = /obj/item/stock_parts/circuitboard/router/wall_mounted + +/datum/fabricator_recipe/imprinter/circuit/modem + path = /obj/item/stock_parts/circuitboard/modem + /datum/fabricator_recipe/imprinter/circuit/relay path = /obj/item/stock_parts/circuitboard/relay -/datum/fabricator_recipe/imprinter/circuit/inertial_damper - path = /obj/item/stock_parts/circuitboard/inertial_damper \ No newline at end of file +/datum/fabricator_recipe/imprinter/circuit/relay_wall_mounted + path = /obj/item/stock_parts/circuitboard/relay/wall_mounted + +/datum/fabricator_recipe/imprinter/circuit/long_range_relay + path = /obj/item/stock_parts/circuitboard/relay/long_range + +/datum/fabricator_recipe/imprinter/circuit/docking_beacon + path = /obj/item/stock_parts/circuitboard/docking_beacon + +/datum/fabricator_recipe/imprinter/circuit/fax_machine + path = /obj/item/stock_parts/circuitboard/fax_machine + +/datum/fabricator_recipe/imprinter/circuit/photocopier + path = /obj/item/stock_parts/circuitboard/photocopier + +/datum/fabricator_recipe/imprinter/circuit/holomap + path = /obj/item/stock_parts/circuitboard/holomap + +/datum/fabricator_recipe/imprinter/circuit/geothermal_generator + path = /obj/item/stock_parts/circuitboard/geothermal + +/datum/fabricator_recipe/imprinter/circuit/area_atmos + path = /obj/item/stock_parts/circuitboard/area_atmos + +/datum/fabricator_recipe/imprinter/circuit/area_atmos_control + path = /obj/item/stock_parts/circuitboard/area_atmos/area + +/datum/fabricator_recipe/imprinter/circuit/tag_scrubber_control + path = /obj/item/stock_parts/circuitboard/area_atmos/tag + +/datum/fabricator_recipe/imprinter/circuit/central_atmos + path = /obj/item/stock_parts/circuitboard/central_atmos diff --git a/code/modules/fabrication/designs/industrial/designs_armour.dm b/code/modules/fabrication/designs/industrial/designs_armour.dm new file mode 100644 index 000000000000..6b291d87a25e --- /dev/null +++ b/code/modules/fabrication/designs/industrial/designs_armour.dm @@ -0,0 +1,7 @@ +/datum/fabricator_recipe/industrial/armour + category = "Shields and Armour" + path = /obj/item/shield/riot + hidden = TRUE + +/datum/fabricator_recipe/industrial/armour/metal + path = /obj/item/shield/riot/metal diff --git a/code/modules/fabrication/designs/industrial/designs_exosuit_components.dm b/code/modules/fabrication/designs/industrial/designs_exosuit_components.dm index 04fac032ffab..af7684561604 100644 --- a/code/modules/fabrication/designs/industrial/designs_exosuit_components.dm +++ b/code/modules/fabrication/designs/industrial/designs_exosuit_components.dm @@ -78,35 +78,85 @@ category = "Exosuit Equipment" path = /obj/item/mech_equipment/clamp +/datum/fabricator_recipe/industrial/exosuit_gear/flash + path = /obj/item/mech_equipment/flash + /datum/fabricator_recipe/industrial/exosuit_gear/gravity_catapult path = /obj/item/mech_equipment/catapult +/datum/fabricator_recipe/industrial/exosuit_gear/ionjets + path = /obj/item/mech_equipment/ionjets + +/datum/fabricator_recipe/industrial/exosuit_gear/camera + path = /obj/item/mech_equipment/camera + +/datum/fabricator_recipe/industrial/exosuit_gear/shields + path = /obj/item/mech_equipment/shields + +/datum/fabricator_recipe/industrial/exosuit_gear/ballistic_shield + path = /obj/item/mech_equipment/ballistic_shield + +/datum/fabricator_recipe/industrial/exosuit_gear/atmos_shields + path = /obj/item/mech_equipment/atmos_shields + /datum/fabricator_recipe/industrial/exosuit_gear/drill path = /obj/item/mech_equipment/drill -/datum/fabricator_recipe/industrial/exosuit_gear/taser +/datum/fabricator_recipe/industrial/exosuit_gear/ionjets + path = /obj/item/mech_equipment/ionjets + +/datum/fabricator_recipe/industrial/exosuit_gear/mounted path = /obj/item/mech_equipment/mounted_system/taser -/datum/fabricator_recipe/industrial/exosuit_gear/plasma +// Add the resources from whatever is mounted on the system +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/get_resources() + . = ..() + if(!ispath(path, /obj/item/mech_equipment/mounted_system)) + return + var/obj/item/mech_equipment/mounted_system/system = path + var/mounted_type = initial(system.holding) + if(!mounted_type) + return + var/list/mounted_cost = atom_info_repository.get_matter_for(mounted_type) + for(var/mat in mounted_cost) + resources[mat] += mounted_cost[mat] * FABRICATOR_EXTRA_COST_FACTOR + +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/machete + path = /obj/item/mech_equipment/mounted_system/melee/machete + +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/plasma path = /obj/item/mech_equipment/mounted_system/taser/plasma -/datum/fabricator_recipe/industrial/exosuit_gear/ion +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/ion path = /obj/item/mech_equipment/mounted_system/taser/ion -/datum/fabricator_recipe/industrial/exosuit_gear/laser +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/laser path = /obj/item/mech_equipment/mounted_system/taser/laser -/datum/fabricator_recipe/industrial/exosuit_gear/rcd +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/autoplasma + path = /obj/item/mech_equipment/mounted_system/taser/autoplasma + +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/smg + path = /obj/item/mech_equipment/mounted_system/projectile + +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/rifle + path = /obj/item/mech_equipment/mounted_system/projectile/assault_rifle + +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/rcd path = /obj/item/mech_equipment/mounted_system/rcd -/datum/fabricator_recipe/industrial/exosuit_gear/floodlight +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/floodlight path = /obj/item/mech_equipment/light -/datum/fabricator_recipe/industrial/exosuit_gear/sleeper +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/sleeper path = /obj/item/mech_equipment/sleeper -/datum/fabricator_recipe/industrial/exosuit_gear/extinguisher +/datum/fabricator_recipe/industrial/exosuit_gear/mounted/extinguisher path = /obj/item/mech_equipment/mounted_system/extinguisher -/datum/fabricator_recipe/industrial/exosuit_gear/mechshields - path = /obj/item/mech_equipment/shields +/datum/fabricator_recipe/industrial/exosuit_ammo + category = "Exosuit Ammunition" + path = /obj/item/ammo_magazine/mech/smg_top + +/datum/fabricator_recipe/industrial/exosuit_ammo + path = /obj/item/ammo_magazine/mech/rifle \ No newline at end of file diff --git a/code/modules/fabrication/designs/meat/_designs_meat.dm b/code/modules/fabrication/designs/meat/_designs_meat.dm new file mode 100644 index 000000000000..0b648ab7fd32 --- /dev/null +++ b/code/modules/fabrication/designs/meat/_designs_meat.dm @@ -0,0 +1,3 @@ +/datum/fabricator_recipe/meat + fabricator_types = list(FABRICATOR_CLASS_MEAT) + abstract_type = /datum/fabricator_recipe/meat diff --git a/code/modules/fabrication/designs/meat/designs_organs.dm b/code/modules/fabrication/designs/meat/designs_organs.dm new file mode 100644 index 000000000000..389651194f72 --- /dev/null +++ b/code/modules/fabrication/designs/meat/designs_organs.dm @@ -0,0 +1,27 @@ +/datum/fabricator_recipe/meat/organ + category = "Cloned Organs" + path = /obj/item/organ/internal/stomach + +/datum/fabricator_recipe/meat/organ/get_product_name() + . = "cloned organ ([..()])" + +/datum/fabricator_recipe/meat/organ/get_resources() + . = ..() + for(var/key in resources) + if(!ispath(key, /decl/material/solid)) + resources -= key + +/datum/fabricator_recipe/meat/organ/heart + path = /obj/item/organ/internal/heart + +/datum/fabricator_recipe/meat/organ/liver + path = /obj/item/organ/internal/liver + +/datum/fabricator_recipe/meat/organ/kidneys + path = /obj/item/organ/internal/kidneys + +/datum/fabricator_recipe/meat/organ/lungs + path = /obj/item/organ/internal/lungs + +/datum/fabricator_recipe/meat/organ/eyes + path = /obj/item/organ/internal/eyes diff --git a/code/modules/fabrication/designs/micro/designs_cutlery.dm b/code/modules/fabrication/designs/micro/designs_cutlery.dm index 11a8a8368e36..b9b5cab14b97 100644 --- a/code/modules/fabrication/designs/micro/designs_cutlery.dm +++ b/code/modules/fabrication/designs/micro/designs_cutlery.dm @@ -1,43 +1,51 @@ /datum/fabricator_recipe/cutlery name = "fork, aluminium" - path = /obj/item/kitchen/utensil/fork + path = /obj/item/utensil/fork category = "Cutlery" fabricator_types = list(FABRICATOR_CLASS_MICRO) /datum/fabricator_recipe/cutlery/spoon_aluminium name = "spoon, aluminium" - path = /obj/item/kitchen/utensil/spoon + path = /obj/item/utensil/spoon /datum/fabricator_recipe/cutlery/spork_aluminium name = "spork, aluminium" - path = /obj/item/kitchen/utensil/spork + path = /obj/item/utensil/spork /datum/fabricator_recipe/cutlery/knife_aluminium name = "table knife, aluminium" - path = /obj/item/knife/table + path = /obj/item/utensil/knife + +/datum/fabricator_recipe/cutlery/chopsticks + name = "chopsticks, aluminium" + path = /obj/item/utensil/chopsticks/aluminium /datum/fabricator_recipe/cutlery/foon_aluminium name = "foon, aluminium" - path = /obj/item/kitchen/utensil/foon + path = /obj/item/utensil/foon hidden = TRUE /datum/fabricator_recipe/cutlery/fork_plastic name = "fork, plastic" - path = /obj/item/kitchen/utensil/fork/plastic + path = /obj/item/utensil/fork/plastic /datum/fabricator_recipe/cutlery/spoon_plastic name = "spoon, plastic" - path = /obj/item/kitchen/utensil/spoon/plastic + path = /obj/item/utensil/spoon/plastic /datum/fabricator_recipe/cutlery/spork_plastic name = "spork, plastic" - path = /obj/item/kitchen/utensil/spork/plastic + path = /obj/item/utensil/spork/plastic /datum/fabricator_recipe/cutlery/knife_plastic name = "table knife, plastic" - path = /obj/item/knife/table/plastic + path = /obj/item/utensil/knife/plastic + +/datum/fabricator_recipe/cutlery/chopsticks/plastic + name = "chopsticks, plastic" + path = /obj/item/utensil/chopsticks/plastic /datum/fabricator_recipe/cutlery/foon_plastic name = "foon, plastic" - path = /obj/item/kitchen/utensil/foon/plastic + path = /obj/item/utensil/foon/plastic hidden = TRUE diff --git a/code/modules/fabrication/designs/micro/designs_glasses.dm b/code/modules/fabrication/designs/micro/designs_glasses.dm index 06d84d523388..1efd81517c2d 100644 --- a/code/modules/fabrication/designs/micro/designs_glasses.dm +++ b/code/modules/fabrication/designs/micro/designs_glasses.dm @@ -1,37 +1,48 @@ /datum/fabricator_recipe/drinkingglass - path = /obj/item/chems/food/drinks/glass2/square + path = /obj/item/chems/drinks/glass2/square category = "Drinking Glasses" fabricator_types = list(FABRICATOR_CLASS_MICRO) /datum/fabricator_recipe/drinkingglass/rocks - path = /obj/item/chems/food/drinks/glass2/rocks + path = /obj/item/chems/drinks/glass2/rocks /datum/fabricator_recipe/drinkingglass/shake - path = /obj/item/chems/food/drinks/glass2/shake + path = /obj/item/chems/drinks/glass2/shake /datum/fabricator_recipe/drinkingglass/cocktail - path = /obj/item/chems/food/drinks/glass2/cocktail + path = /obj/item/chems/drinks/glass2/cocktail /datum/fabricator_recipe/drinkingglass/shot - path = /obj/item/chems/food/drinks/glass2/shot + path = /obj/item/chems/drinks/glass2/shot /datum/fabricator_recipe/drinkingglass/pint - path = /obj/item/chems/food/drinks/glass2/pint + path = /obj/item/chems/drinks/glass2/pint /datum/fabricator_recipe/drinkingglass/mug - path = /obj/item/chems/food/drinks/glass2/mug + path = /obj/item/chems/drinks/glass2/mug /datum/fabricator_recipe/drinkingglass/wine - path = /obj/item/chems/food/drinks/glass2/wine + path = /obj/item/chems/drinks/glass2/wine /datum/fabricator_recipe/drinkingglass/carafe - path = /obj/item/chems/food/drinks/glass2/carafe + path = /obj/item/chems/drinks/glass2/carafe /datum/fabricator_recipe/drinkingglass/flute - path = /obj/item/chems/food/drinks/glass2/flute + path = /obj/item/chems/drinks/glass2/flute /datum/fabricator_recipe/drinkingglass/coffecup - path = /obj/item/chems/food/drinks/glass2/coffeecup + path = /obj/item/chems/drinks/glass2/coffeecup /datum/fabricator_recipe/drinkingglass/metalcoffecup - path = /obj/item/chems/food/drinks/glass2/coffeecup/metal + path = /obj/item/chems/drinks/glass2/coffeecup/metal + +/datum/fabricator_recipe/dinnerware + category = "Dinnerware" + fabricator_types = list(FABRICATOR_CLASS_MICRO) + path = /obj/item/plate + +/datum/fabricator_recipe/dinnerware/platter + path = /obj/item/plate/platter + +/datum/fabricator_recipe/dinnerware/tray + path = /obj/item/plate/tray diff --git a/code/modules/fabrication/designs/pipe/device_pipe_datums.dm b/code/modules/fabrication/designs/pipe/device_pipe_datums.dm index e00a6c5e7197..87d1753cbe2f 100644 --- a/code/modules/fabrication/designs/pipe/device_pipe_datums.dm +++ b/code/modules/fabrication/designs/pipe/device_pipe_datums.dm @@ -4,7 +4,6 @@ pipe_color = PIPE_COLOR_WHITE name = "connector" - desc = "a connector for canisters." connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "connector" constructed_path = /obj/machinery/atmospherics/portables_connector @@ -13,7 +12,6 @@ /datum/fabricator_recipe/pipe/device/adapter name = "universal pipe adapter" - desc = "an adapter designed to fit any type of pipe." connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_HE build_icon_state = "universal" constructed_path = /obj/machinery/atmospherics/pipe/simple/hidden/universal @@ -22,7 +20,6 @@ /datum/fabricator_recipe/pipe/device/unaryvent name = "unary vent" - desc = "a unary vent" connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_FUEL build_icon_state = "uvent" constructed_path = /obj/machinery/atmospherics/unary/vent_pump @@ -30,12 +27,10 @@ /datum/fabricator_recipe/pipe/device/unaryvent/large name = "high volume unary vent" - desc = "a high volume unary vent" constructed_path = /obj/machinery/atmospherics/unary/vent_pump/high_volume /datum/fabricator_recipe/pipe/device/gaspump name = "gas pump" - desc = "a pump. For gasses." connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "pump" constructed_path = /obj/machinery/atmospherics/binary/pump @@ -43,7 +38,6 @@ /datum/fabricator_recipe/pipe/device/pressureregulator name = "pressure regulator" - desc = "a device that regulates pressure." connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "passivegate" constructed_path = /obj/machinery/atmospherics/binary/passive_gate @@ -51,7 +45,6 @@ /datum/fabricator_recipe/pipe/device/hpgaspump name = "high powered gas pump" - desc = "a high powered pump. For gasses." connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "volumepump" constructed_path = /obj/machinery/atmospherics/binary/pump/high_power @@ -59,7 +52,6 @@ /datum/fabricator_recipe/pipe/device/scrubber name = "scrubber" - desc = "scrubs out undesirable gasses" connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SCRUBBER build_icon_state = "scrubber" constructed_path = /obj/machinery/atmospherics/unary/vent_scrubber @@ -67,7 +59,6 @@ /datum/fabricator_recipe/pipe/device/meter name = "meter" - desc = "a meter that monitors pressure and temperature on the attached pipe." path = /obj/item/machine_chassis/pipe_meter pipe_color = null connect_types = null @@ -78,7 +69,6 @@ /datum/fabricator_recipe/pipe/device/omnimixer name = "omni gas mixer" - desc = "a device that takes in two or three gasses and mixes them into a precise output." connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "omni_mixer" constructed_path = /obj/machinery/atmospherics/omni/mixer @@ -86,7 +76,6 @@ /datum/fabricator_recipe/pipe/device/omnifilter name = "omni gas filter" - desc = "a device that filters out undesireable elements" connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "omni_filter" constructed_path = /obj/machinery/atmospherics/omni/filter @@ -94,61 +83,60 @@ /datum/fabricator_recipe/pipe/device/manualvalve name = "manual valve" - desc = "a valve that has to be manipulated by hand" build_icon_state = "mvalve" constructed_path = /obj/machinery/atmospherics/valve pipe_class = PIPE_CLASS_BINARY rotate_class = PIPE_ROTATE_TWODIR + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/digitalvalve name = "digital valve" - desc = "a valve controlled electronically" build_icon_state = "dvalve" constructed_path = /obj/machinery/atmospherics/valve/digital pipe_class = PIPE_CLASS_BINARY rotate_class = PIPE_ROTATE_TWODIR + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/autoshutoff name = "automatic shutoff valve" - desc = "a valve that can automatically shut itself off" build_icon_state = "svalve" constructed_path = /obj/machinery/atmospherics/valve/shutoff pipe_class = PIPE_CLASS_BINARY rotate_class = PIPE_ROTATE_TWODIR + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/mtvalve name = "manual t-valve" - desc = "a three-way valve. T-shaped." build_icon_state = "mtvalve" constructed_path = /obj/machinery/atmospherics/tvalve pipe_class = PIPE_CLASS_TRINARY + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/mtvalvem name = "manual t-valve (mirrored)" - desc = "a three-way valve. T-shaped." build_icon_state = "mtvalvem" constructed_path = /obj/machinery/atmospherics/tvalve/mirrored pipe_class = PIPE_CLASS_TRINARY + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/dtvalve name = "digital t-valve" - desc = "a three-way valve. T-shaped. This one can be controlled electronically." build_icon = 'icons/atmos/digital_tvalve.dmi' build_icon_state = "map_tvalve0" constructed_path = /obj/machinery/atmospherics/tvalve/digital pipe_class = PIPE_CLASS_TRINARY + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/dtvalvem name = "digital t-valve (mirrored)" - desc = "a three-way valve. T-shaped. This one can be controlled electronically." build_icon = 'icons/atmos/digital_tvalve.dmi' build_icon_state = "map_tvalvem0" constructed_path = /obj/machinery/atmospherics/tvalve/mirrored/digital pipe_class = PIPE_CLASS_TRINARY + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL /datum/fabricator_recipe/pipe/device/air_sensor name = "gas sensor" - desc = "a sensor. It detects gasses." path = /obj/item/machine_chassis/air_sensor build_icon_state = "gsensor1" build_icon = 'icons/obj/machines/gas_sensor.dmi' @@ -159,8 +147,7 @@ pipe_class = PIPE_CLASS_OTHER /datum/fabricator_recipe/pipe/device/outlet_injector - name = "injector" - desc = "Passively injects gas into its surroundings. Has a valve attached to it that can control flow rate." + name = "injector outlet" build_icon = 'icons/atmos/injector.dmi' build_icon_state = "map_injector" connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL @@ -171,7 +158,6 @@ /datum/fabricator_recipe/pipe/device/drain name = "gutter" - desc = "You probably can't get sucked down the plughole." build_icon = 'icons/obj/drain.dmi' build_icon_state = "drain" path = /obj/item/drain @@ -181,9 +167,19 @@ constructed_path = /obj/structure/hygiene/drain pipe_class = PIPE_CLASS_OTHER +/datum/fabricator_recipe/pipe/device/drain/bath + name = "sealable gutter" + build_icon = 'icons/obj/drain.dmi' + build_icon_state = "drain_bath" + path = /obj/item/drain/bath + connect_types = null + colorable = FALSE + pipe_color = null + constructed_path = /obj/structure/hygiene/drain/bath + pipe_class = PIPE_CLASS_OTHER + /datum/fabricator_recipe/pipe/device/tank name = "pressure tank" - desc = "A large vessel containing pressurized gas." build_icon = 'icons/atmos/tank.dmi' build_icon_state = "air" path = /obj/item/pipe/tank @@ -194,7 +190,6 @@ /datum/fabricator_recipe/pipe/device/plate name = "thermal plate" - desc = "A device which transfers heat to and from an area." build_icon = 'icons/obj/atmospherics/cold_sink.dmi' build_icon_state = "exposed" path = /obj/item/pipe @@ -204,7 +199,6 @@ /datum/fabricator_recipe/pipe/device/igniter name = "igniter" - desc = "A device which will ignite surrounding gasses." build_icon = 'icons/obj/machines/igniter.dmi' build_icon_state = "igniter1" path = /obj/item/machine_chassis/igniter diff --git a/code/modules/fabrication/designs/pipe/disposal_pipe_datums.dm b/code/modules/fabrication/designs/pipe/disposal_pipe_datums.dm index 5bfe5338261a..57c4aa6220fb 100644 --- a/code/modules/fabrication/designs/pipe/disposal_pipe_datums.dm +++ b/code/modules/fabrication/designs/pipe/disposal_pipe_datums.dm @@ -1,5 +1,4 @@ /datum/fabricator_recipe/pipe/disposal_dispenser - pipe_type = null pipe_color = null connect_types = null colorable = FALSE @@ -8,8 +7,7 @@ var/turn = DISPOSAL_FLIP_FLIP name = "disposal pipe segment" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' + build_icon = 'icons/obj/pipes/disposal_pipe.dmi' build_icon_state = "pipe-s" path = /obj/structure/disposalconstruct fabricator_types = list( @@ -18,64 +16,49 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/bent name = "bent disposal pipe segment" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-c" turn = DISPOSAL_FLIP_RIGHT constructed_path = /obj/structure/disposalpipe/segment/bent /datum/fabricator_recipe/pipe/disposal_dispenser/junction name = "disposal pipe junction" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j1" turn = DISPOSAL_FLIP_RIGHT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/junction /datum/fabricator_recipe/pipe/disposal_dispenser/junctionm name = "disposal pipe junction (mirrored)" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j2" turn = DISPOSAL_FLIP_LEFT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/junction/mirrored /datum/fabricator_recipe/pipe/disposal_dispenser/yjunction name = "disposal pipe y-junction" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-y" turn = DISPOSAL_FLIP_LEFT|DISPOSAL_FLIP_RIGHT constructed_path = /obj/structure/disposalpipe/junction /datum/fabricator_recipe/pipe/disposal_dispenser/trunk name = "disposal pipe trunk" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-t" constructed_path = /obj/structure/disposalpipe/trunk turn = DISPOSAL_FLIP_NONE /datum/fabricator_recipe/pipe/disposal_dispenser/up name = "disposal pipe upwards segment" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-u" constructed_path = /obj/structure/disposalpipe/up turn = DISPOSAL_FLIP_NONE /datum/fabricator_recipe/pipe/disposal_dispenser/down name = "disposal pipe downwards segment" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-d" constructed_path = /obj/structure/disposalpipe/down turn = DISPOSAL_FLIP_NONE /datum/fabricator_recipe/pipe/disposal_dispenser/device name = "disposal bin" - desc = "A bin used to dispose of trash." - build_icon = 'icons/obj/pipes/disposal.dmi' + build_icon = 'icons/obj/pipes/disposal_bin.dmi' build_icon_state = "disposal" path = /obj/structure/disposalconstruct/machine constructed_path = /obj/machinery/disposal @@ -83,24 +66,20 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/outlet name = "disposal outlet" - desc = "an outlet that ejects things from a disposal network." - build_icon = 'icons/obj/pipes/disposal.dmi' + build_icon = 'icons/obj/pipes/disposal_outlet.dmi' build_icon_state = "outlet" path = /obj/structure/disposalconstruct/machine/outlet constructed_path = /obj/structure/disposaloutlet /datum/fabricator_recipe/pipe/disposal_dispenser/device/chute name = "disposal chute" - desc = "A chute to put things into a disposal network." - build_icon = 'icons/obj/pipes/disposal.dmi' - build_icon_state = "intake" + build_icon = 'icons/obj/pipes/disposal_chute.dmi' + build_icon_state = "chute" constructed_path = /obj/machinery/disposal/deliveryChute path = /obj/structure/disposalconstruct/machine/chute /datum/fabricator_recipe/pipe/disposal_dispenser/device/sorting name = "disposal sorter" - desc = "Sorts things in a disposal system" - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j1s" turn = DISPOSAL_FLIP_RIGHT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/sortjunction @@ -108,8 +87,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/sorting/wildcard name = "wildcard disposal sorter" - desc = "Sorts things in a disposal system" - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j1s" turn = DISPOSAL_FLIP_RIGHT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/sortjunction/wildcard @@ -117,8 +94,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/sorting/untagged name = "untagged disposal sorter" - desc = "Sorts things in a disposal system" - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j1s" turn = DISPOSAL_FLIP_RIGHT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/sortjunction/untagged @@ -126,8 +101,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/sortingm name = "disposal sorter (mirrored)" - desc = "Sorts things in a disposal system" - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j2s" turn = DISPOSAL_FLIP_LEFT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/sortjunction/flipped @@ -135,8 +108,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/sorting/wildcardm name = "wildcard disposal sorter (mirrored)" - desc = "Sorts things in a disposal system" - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j2s" turn = DISPOSAL_FLIP_LEFT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/sortjunction/wildcard/flipped @@ -144,8 +115,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/sorting/untaggedm name = "untagged disposal sorter (mirrored)" - desc = "Sorts things in a disposal system" - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j2s" turn = DISPOSAL_FLIP_LEFT|DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/sortjunction/untagged/flipped @@ -153,8 +122,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/tagger name = "disposal tagger" - desc = "It tags things." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-tagger" turn = DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/tagger @@ -162,8 +129,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/tagger/partial name = "disposal partial tagger" - desc = "It tags things." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-tagger-partial" turn = DISPOSAL_FLIP_FLIP constructed_path = /obj/structure/disposalpipe/tagger/partial @@ -171,8 +136,6 @@ /datum/fabricator_recipe/pipe/disposal_dispenser/device/diversion name = "disposal diverter" - desc = "A huge pipe segment used for constructing disposal systems." - build_icon = 'icons/obj/pipes/disposal.dmi' build_icon_state = "pipe-j1s" turn = DISPOSAL_FLIP_FLIP | DISPOSAL_FLIP_RIGHT constructed_path = /obj/structure/disposalpipe/diversion_junction diff --git a/code/modules/fabrication/designs/pipe/pipe_datum_base.dm b/code/modules/fabrication/designs/pipe/pipe_datum_base.dm index 878f2bafff79..8dd28b296eb2 100644 --- a/code/modules/fabrication/designs/pipe/pipe_datum_base.dm +++ b/code/modules/fabrication/designs/pipe/pipe_datum_base.dm @@ -1,5 +1,4 @@ /datum/fabricator_recipe/pipe - var/pipe_type //What sort of pipe this is. Used by disposals currently. var/connect_types = CONNECT_TYPE_REGULAR //what sort of connection this has var/pipe_color = PIPE_COLOR_GREY //what color the pipe should be by default var/build_icon_state = "simple" //Which icon state to use when creating a new pipe item. @@ -19,16 +18,21 @@ ) max_amount = 10 +/datum/fabricator_recipe/pipe/New() + . = ..() + if(isnull(desc) && ispath(constructed_path)) + var/obj/constructed_obj = constructed_path + desc = initial(constructed_obj.desc) + /datum/fabricator_recipe/pipe/get_resources() resources = list() var/list/building_cost = atom_info_repository.get_matter_for(constructed_path) for(var/path in building_cost) - if(!ignore_materials[path]) - resources[path] = building_cost[path] * FABRICATOR_EXTRA_COST_FACTOR + resources[path] = building_cost[path] * FABRICATOR_EXTRA_COST_FACTOR -/datum/fabricator_recipe/pipe/build(var/turf/location, var/amount = 1, var/color = PIPE_COLOR_WHITE) +/datum/fabricator_recipe/pipe/build(var/turf/location, var/datum/fabricator_build_order/order) . = list() - for(var/i = 1, i <= amount, i++) + for(var/i = 1, i <= order.multiplier, i++) var/obj/item/pipe/new_item = new path(location) if(istype(new_item)) if(connect_types != null) @@ -37,9 +41,9 @@ new_item.rotate_class = rotate_class new_item.constructed_path = constructed_path if(colorable) - new_item.color = color + new_item.set_color(order.get_data("selected_color", PIPE_COLOR_WHITE)) else if (pipe_color != null) - new_item.color = pipe_color + new_item.set_color(pipe_color) new_item.SetName(name) if(desc) new_item.desc = desc @@ -48,9 +52,9 @@ new_item.icon_state = build_icon_state . += new_item -/datum/fabricator_recipe/pipe/disposal_dispenser/build(var/turf/location, var/amount = 1, var/color = PIPE_COLOR_GREY) - . = ..() - for(var/i = 1, i <= amount, i++) +/datum/fabricator_recipe/pipe/disposal_dispenser/build(var/turf/location, var/datum/fabricator_build_order/order) + . = list() + for(var/i = 1, i <= order.multiplier, i++) var/obj/structure/disposalconstruct/new_item = new path(location) new_item.SetName(name) if(desc) diff --git a/code/modules/fabrication/designs/pipe/pipe_datums.dm b/code/modules/fabrication/designs/pipe/pipe_datums.dm index 779a2c1c0489..70f0a7c6320c 100644 --- a/code/modules/fabrication/designs/pipe/pipe_datums.dm +++ b/code/modules/fabrication/designs/pipe/pipe_datums.dm @@ -2,19 +2,16 @@ #define PIPE_BENT 5 /datum/fabricator_recipe/pipe - name = "a pipe fitting" - desc = "a straight pipe segment." + name = "pipe fitting" rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/bent name = "bent pipe fitting" - desc = "a bent pipe segment" dir = PIPE_BENT rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/manifold name = "pipe manifold fitting" - desc = "a pipe manifold segment" build_icon_state = "manifold" constructed_path = /obj/machinery/atmospherics/pipe/manifold/hidden pipe_class = PIPE_CLASS_TRINARY @@ -22,7 +19,6 @@ /datum/fabricator_recipe/pipe/manifold4w name = "four-way pipe manifold fitting" - desc = "a four-way pipe manifold segment" build_icon_state = "manifold4w" constructed_path = /obj/machinery/atmospherics/pipe/manifold4w/hidden pipe_class = PIPE_CLASS_QUATERNARY @@ -30,22 +26,24 @@ /datum/fabricator_recipe/pipe/cap name = "pipe cap fitting" - desc = "a pipe cap for a regular pipe." build_icon_state = "cap" constructed_path = /obj/machinery/atmospherics/pipe/cap/hidden pipe_class = PIPE_CLASS_UNARY + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/up name = "upward pipe fitting" - desc = "an upward pipe." build_icon_state = "up" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/up + rotate_class = PIPE_ROTATE_STANDARD + /datum/fabricator_recipe/pipe/down name = "downward pipe fitting" - desc = "a downward pipe." build_icon_state = "down" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/down + rotate_class = PIPE_ROTATE_STANDARD + /datum/fabricator_recipe/pipe/supply category = "Supply Pipes" @@ -56,18 +54,15 @@ pipe_class = PIPE_CLASS_BINARY name = "supply pipe fitting" - desc = "a straight supply pipe segment." rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/supply/bent name = "bent supply pipe fitting" - desc = "a bent supply pipe segment" dir = PIPE_BENT rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/supply/manifold name = "supply pipe manifold fitting" - desc = "a supply pipe manifold segment" build_icon_state = "manifold" constructed_path = /obj/machinery/atmospherics/pipe/manifold/hidden/supply pipe_class = PIPE_CLASS_TRINARY @@ -75,7 +70,6 @@ /datum/fabricator_recipe/pipe/supply/manifold4w name = "four-way supply pipe manifold fitting" - desc = "a four-way supply pipe manifold segment" build_icon_state = "manifold4w" constructed_path = /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply pipe_class = PIPE_CLASS_QUATERNARY @@ -83,22 +77,22 @@ /datum/fabricator_recipe/pipe/supply/cap name = "supply pipe cap fitting" - desc = "a pipe cap for a regular pipe." build_icon_state = "cap" constructed_path = /obj/machinery/atmospherics/pipe/cap/hidden/supply pipe_class = PIPE_CLASS_UNARY + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/supply/up name = "upward supply pipe fitting" - desc = "an upward supply pipe segment." build_icon_state = "up" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/up/supply + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/supply/down name = "downward supply pipe fitting" - desc = "a downward supply pipe segment." build_icon_state = "down" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/down/supply + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/scrubber category = "Scrubber Pipes" @@ -109,18 +103,15 @@ pipe_class = PIPE_CLASS_BINARY name = "scrubber pipe fitting" - desc = "a straight scrubber pipe segment" rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/scrubber/bent name = "bent scrubber pipe fitting" - desc = "a bent scrubber pipe segment" rotate_class = PIPE_ROTATE_TWODIR dir = PIPE_BENT /datum/fabricator_recipe/pipe/scrubber/manifold name = "scrubber pipe manifold fitting" - desc = "a scrubber pipe manifold segment" build_icon_state = "manifold" constructed_path = /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers pipe_class = PIPE_CLASS_TRINARY @@ -128,7 +119,6 @@ /datum/fabricator_recipe/pipe/scrubber/manifold4w name = "four-way scrubber pipe manifold fitting" - desc = "a four-way scrubber pipe manifold segment" build_icon_state = "manifold4w" constructed_path = /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers pipe_class = PIPE_CLASS_QUATERNARY @@ -136,21 +126,22 @@ /datum/fabricator_recipe/pipe/scrubber/cap name = "scrubber pipe cap fitting" - desc = "a pipe cap for a scrubber pipe." build_icon_state = "cap" constructed_path = /obj/machinery/atmospherics/pipe/cap/hidden/scrubbers + pipe_class = PIPE_CLASS_UNARY + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/scrubber/up name = "upward scrubber pipe fitting" - desc = "an upward scrubber pipe segment." build_icon_state = "up" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/scrubber/down name = "downward scrubber pipe fitting" - desc = "a downward scrubber pipe segment." build_icon_state = "down" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/fuel category = "Fuel Pipes" @@ -161,18 +152,15 @@ pipe_class = PIPE_CLASS_BINARY name = "fuel pipe fitting" - desc = "a striaght fuel pipe segment" rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/fuel/bent name = "bent fuel pipe fitting" - desc = "a bent fuel pipe segment" rotate_class = PIPE_ROTATE_TWODIR dir = PIPE_BENT /datum/fabricator_recipe/pipe/fuel/manifold name = "fuel pipe manifold fitting" - desc = "a fuel pipe manifold segment" build_icon_state = "manifold" constructed_path = /obj/machinery/atmospherics/pipe/manifold/hidden/fuel pipe_class = PIPE_CLASS_TRINARY @@ -180,7 +168,6 @@ /datum/fabricator_recipe/pipe/fuel/manifold4w name = "four-way supply pipe manifold fitting" - desc = "a four-way fuel pipe manifold segment" build_icon_state = "manifold4w" constructed_path = /obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel pipe_class = PIPE_CLASS_QUATERNARY @@ -188,22 +175,22 @@ /datum/fabricator_recipe/pipe/fuel/cap name = "fuel pipe cap fitting" - desc = "a pipe cap for a fuel pipe." build_icon_state = "cap" constructed_path = /obj/machinery/atmospherics/pipe/cap/hidden/fuel pipe_class = PIPE_CLASS_UNARY + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/fuel/up name = "upward fuel pipe fitting" - desc = "an upward fuel pipe segment." build_icon_state = "up" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/up/fuel + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/fuel/down name = "downward fuel pipe fitting" - desc = "a downward fuel pipe segment." build_icon_state = "down" constructed_path = /obj/machinery/atmospherics/pipe/zpipe/down/fuel + rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/he category = "Heat Exchange Pipes" @@ -214,13 +201,11 @@ pipe_class = PIPE_CLASS_BINARY name = "heat exchanger pipe fitting" - desc = "a heat exchanger pipe segment" build_icon_state = "he" rotate_class = PIPE_ROTATE_TWODIR /datum/fabricator_recipe/pipe/he/bent name = "bent heat exchanger pipe fitting" - desc = "a bent heat exchanger pipe segment" connect_types = CONNECT_TYPE_HE rotate_class = PIPE_ROTATE_TWODIR build_icon_state = "he" @@ -228,16 +213,14 @@ /datum/fabricator_recipe/pipe/he/junction name = "heat exchanger junction" - desc = "a heat exchanger junction" - connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE|CONNECT_TYPE_FUEL build_icon_state = "junction" constructed_path = /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction rotate_class = PIPE_ROTATE_STANDARD /datum/fabricator_recipe/pipe/he/exchanger name = "heat exchanger" - desc = "a heat exchanger" - connect_types = CONNECT_TYPE_REGULAR + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL build_icon_state = "heunary" constructed_path = /obj/machinery/atmospherics/unary/heat_exchanger pipe_class = PIPE_CLASS_UNARY diff --git a/code/modules/fabrication/designs/protolathe/designs_computer_accessories.dm b/code/modules/fabrication/designs/protolathe/designs_computer_accessories.dm index fd0cf4d796fd..90d67bb6b3d2 100644 --- a/code/modules/fabrication/designs/protolathe/designs_computer_accessories.dm +++ b/code/modules/fabrication/designs/protolathe/designs_computer_accessories.dm @@ -31,3 +31,19 @@ /datum/fabricator_recipe/protolathe/comp_acc/medical_scanner path = /obj/item/stock_parts/computer/scanner/medical + +////////////////////////////////////////////////////////////////// +// Frames +////////////////////////////////////////////////////////////////// +/datum/fabricator_recipe/protolathe/comp_frames + category = "Computer Frames" + path = /obj/item/modular_computer/laptop + +/datum/fabricator_recipe/protolathe/comp_frames/tablet_frame + path = /obj/item/modular_computer/tablet + +/datum/fabricator_recipe/protolathe/comp_frames/telescreen_frame + path = /obj/item/frame/modular_telescreen + +/datum/fabricator_recipe/protolathe/comp_frames/telescreen_frame_kit + path = /obj/item/frame/modular_telescreen/kit diff --git a/code/modules/fabrication/designs/protolathe/designs_hardsuit_modules.dm b/code/modules/fabrication/designs/protolathe/designs_hardsuit_modules.dm index e0e598e70ef1..219883e737e1 100644 --- a/code/modules/fabrication/designs/protolathe/designs_hardsuit_modules.dm +++ b/code/modules/fabrication/designs/protolathe/designs_hardsuit_modules.dm @@ -61,12 +61,3 @@ /datum/fabricator_recipe/protolathe/rig/cooling_unit path = /obj/item/rig_module/cooling_unit - -/datum/fabricator_recipe/protolathe/rig/integrated_printer - path = /obj/item/integrated_circuit_printer - -/datum/fabricator_recipe/protolathe/rig/integrated_printer_upgrade_advanced - path = /obj/item/disk/integrated_circuit/upgrade/advanced - -/datum/fabricator_recipe/protolathe/rig/integrated_printer_upgrade_clone - path = /obj/item/disk/integrated_circuit/upgrade/clone diff --git a/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm b/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm index e2a471367ec7..3b52762f8f94 100644 --- a/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm +++ b/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm @@ -1,15 +1,15 @@ /datum/fabricator_recipe/protolathe/brains category = "Machine Intelligence" - path = /obj/item/mmi + path = /obj/item/organ/internal/brain_interface/empty /datum/fabricator_recipe/protolathe/brains/get_product_name() . = "intelligence storage ([..()])" +/datum/fabricator_recipe/protolathe/brains/robotic + path = /obj/item/organ/internal/brain/robotic + /datum/fabricator_recipe/protolathe/brains/mmi_radio - path = /obj/item/mmi/radio_enabled - -/datum/fabricator_recipe/protolathe/brains/posibrain - path = /obj/item/organ/internal/posibrain + path = /obj/item/organ/internal/brain_interface/radio_enabled/empty /datum/fabricator_recipe/protolathe/brains/paicard path = /obj/item/paicard diff --git a/code/modules/fabrication/designs/protolathe/designs_misc.dm b/code/modules/fabrication/designs/protolathe/designs_misc.dm index 7cf4047826c5..0d406749fae2 100644 --- a/code/modules/fabrication/designs/protolathe/designs_misc.dm +++ b/code/modules/fabrication/designs/protolathe/designs_misc.dm @@ -12,10 +12,10 @@ path = /obj/item/ano_scanner /datum/fabricator_recipe/protolathe/misc/bag_holding - path = /obj/item/storage/backpack/holding + path = /obj/item/backpack/holding /datum/fabricator_recipe/protolathe/misc/dufflebag_holding - path = /obj/item/storage/backpack/holding/duffle + path = /obj/item/backpack/holding/duffle /datum/fabricator_recipe/protolathe/misc/beaker path = /obj/item/chems/glass/beaker/noreact @@ -39,7 +39,7 @@ path = /obj/item/mop/advanced /datum/fabricator_recipe/protolathe/misc/advancedtrash - path = /obj/item/storage/bag/trash/advanced + path = /obj/item/bag/trash/advanced /datum/fabricator_recipe/protolathe/misc/holosign path = /obj/item/holosign_creator @@ -48,10 +48,10 @@ path = /obj/item/encryptionkey/binary /datum/fabricator_recipe/protolathe/misc/chameleon - path = /obj/item/storage/backpack/chameleon/sydie_kit + path = /obj/item/backpack/chameleon/sydie_kit /datum/fabricator_recipe/protolathe/misc/ship_tracker path = /obj/item/ship_tracker /datum/fabricator_recipe/protolathe/misc/radio_beacon - path = /obj/item/radio_beacon \ No newline at end of file + path = /obj/item/radio_beacon diff --git a/code/modules/fabrication/designs/protolathe/designs_power_cells.dm b/code/modules/fabrication/designs/protolathe/designs_power_cells.dm index ac13c53275d1..cbf075f8fc08 100644 --- a/code/modules/fabrication/designs/protolathe/designs_power_cells.dm +++ b/code/modules/fabrication/designs/protolathe/designs_power_cells.dm @@ -6,10 +6,10 @@ FABRICATOR_CLASS_ROBOTICS ) -/datum/fabricator_recipe/protolathe/cell/build(var/turf/location, var/amount = 1) +/datum/fabricator_recipe/protolathe/cell/build() . = ..() - for(var/obj/item/cell/C in .) - C.charge = 0 + for(var/obj/item/cell/cell in .) + cell.charge = 0 /datum/fabricator_recipe/protolathe/cell/get_product_name() . = "power cell model ([..()])" diff --git a/code/modules/fabrication/designs/protolathe/designs_prosthetics.dm b/code/modules/fabrication/designs/protolathe/designs_prosthetics.dm deleted file mode 100644 index 7ab55bc164fd..000000000000 --- a/code/modules/fabrication/designs/protolathe/designs_prosthetics.dm +++ /dev/null @@ -1,32 +0,0 @@ -/datum/fabricator_recipe/protolathe/organ - category = "Prosthetic Organs" - path = /obj/item/organ/internal/stomach - -/datum/fabricator_recipe/protolathe/organ/get_product_name() - . = "prosthetic organ ([..()])" - -/datum/fabricator_recipe/protolathe/organ/get_resources() - . = ..() - for(var/key in resources) - if(ispath(key, /decl/material)) - resources -= key - -/datum/fabricator_recipe/protolathe/organ/build() - . = ..() - for(var/obj/item/organ/internal/I in .) - I.robotize() - -/datum/fabricator_recipe/protolathe/organ/heart - path = /obj/item/organ/internal/heart - -/datum/fabricator_recipe/protolathe/organ/liver - path = /obj/item/organ/internal/liver - -/datum/fabricator_recipe/protolathe/organ/kidneys - path = /obj/item/organ/internal/kidneys - -/datum/fabricator_recipe/protolathe/organ/lungs - path = /obj/item/organ/internal/lungs - -/datum/fabricator_recipe/protolathe/organ/eyes - path = /obj/item/organ/internal/eyes diff --git a/code/modules/fabrication/designs/protolathe/designs_stock.dm b/code/modules/fabrication/designs/protolathe/designs_stock.dm index adef00bd5ea6..a391ca5d5df2 100644 --- a/code/modules/fabrication/designs/protolathe/designs_stock.dm +++ b/code/modules/fabrication/designs/protolathe/designs_stock.dm @@ -72,4 +72,16 @@ path = /obj/item/stock_parts/smes_coil/super_capacity /datum/fabricator_recipe/protolathe/stock/smes_coil_super_io - path = /obj/item/stock_parts/smes_coil/super_io \ No newline at end of file + path = /obj/item/stock_parts/smes_coil/super_io + +/datum/fabricator_recipe/protolathe/stock/card_reader + path = /obj/item/stock_parts/item_holder/card_reader + +/datum/fabricator_recipe/protolathe/stock/disk_reader + path = /obj/item/stock_parts/item_holder/disk_reader + +/datum/fabricator_recipe/protolathe/stock/printer + path = /obj/item/stock_parts/printer + +/datum/fabricator_recipe/protolathe/stock/ammo_box + path = /obj/item/stock_parts/ammo_box \ No newline at end of file diff --git a/code/modules/fabrication/designs/protolathe/designs_tools.dm b/code/modules/fabrication/designs/protolathe/designs_tools.dm index 8ed1b2b20efd..436f2c723537 100644 --- a/code/modules/fabrication/designs/protolathe/designs_tools.dm +++ b/code/modules/fabrication/designs/protolathe/designs_tools.dm @@ -11,9 +11,6 @@ /datum/fabricator_recipe/protolathe/tool/brace_jack path = /obj/item/crowbar/brace_jack -/datum/fabricator_recipe/protolathe/tool/clamp - path = /obj/item/clamp - /datum/fabricator_recipe/protolathe/tool/inducer path = /obj/item/inducer @@ -33,16 +30,16 @@ path = /obj/item/oxycandle /datum/fabricator_recipe/protolathe/tool/scalpel_laser1 - path = /obj/item/scalpel/laser1 + path = /obj/item/scalpel/laser /datum/fabricator_recipe/protolathe/tool/scalpel_laser2 - path = /obj/item/scalpel/laser2 + path = /obj/item/scalpel/laser/upgraded /datum/fabricator_recipe/protolathe/tool/scalpel_laser3 - path = /obj/item/scalpel/laser3 + path = /obj/item/scalpel/laser/advanced /datum/fabricator_recipe/protolathe/tool/scalpel_manager - path = /obj/item/scalpel/manager + path = /obj/item/incision_manager /datum/fabricator_recipe/protolathe/tool/noreactsyringe path = /obj/item/chems/syringe/noreact @@ -50,7 +47,7 @@ /datum/fabricator_recipe/protolathe/tool/advancedsyringe path = /obj/item/chems/syringe/advanced -/datum/fabricator_recipe/protolathe/tool/slime_scanner +/datum/fabricator_recipe/protolathe/tool/xenoscanner path = /obj/item/scanner/xenobio /datum/fabricator_recipe/protolathe/tool/robot_scanner @@ -68,6 +65,12 @@ /datum/fabricator_recipe/protolathe/tool/adv_reagent_scanner path = /obj/item/scanner/reagent/adv +/datum/fabricator_recipe/protolathe/tool/health_scanner + path = /obj/item/scanner/health + +/datum/fabricator_recipe/protolathe/tool/breath_scanner + path = /obj/item/scanner/breath + /datum/fabricator_recipe/protolathe/tool/nanopaste path = /obj/item/stack/nanopaste @@ -78,27 +81,25 @@ path = /obj/item/bodybag/cryobag /datum/fabricator_recipe/protolathe/tool/jackhammer - path = /obj/item/pickaxe/jackhammer + path = /obj/item/tool/hammer/jack /datum/fabricator_recipe/protolathe/tool/drill - path = /obj/item/pickaxe/drill + path = /obj/item/tool/drill -/* /datum/fabricator_recipe/protolathe/tool/plasmacutter path = /obj/item/gun/energy/plasmacutter -*/ -/datum/fabricator_recipe/protolathe/tool/pick_diamond - path = /obj/item/pickaxe/diamond +/datum/fabricator_recipe/protolathe/tool/pick_titanium + path = /obj/item/tool/pickaxe/titanium /datum/fabricator_recipe/protolathe/tool/drill_diamond - path = /obj/item/pickaxe/diamonddrill + path = /obj/item/tool/drill/diamond /datum/fabricator_recipe/protolathe/tool/depth_scanner path = /obj/item/depth_scanner /datum/fabricator_recipe/protolathe/tool/rped - path = /obj/item/storage/part_replacer + path = /obj/item/part_replacer /datum/fabricator_recipe/protolathe/tool/rped_advanced - path = /obj/item/storage/part_replacer/advanced + path = /obj/item/part_replacer/advanced diff --git a/code/modules/fabrication/designs/replicator/designs_food.dm b/code/modules/fabrication/designs/replicator/designs_food.dm index defaacf02c30..f0bde4f59965 100644 --- a/code/modules/fabrication/designs/replicator/designs_food.dm +++ b/code/modules/fabrication/designs/replicator/designs_food.dm @@ -1,15 +1,35 @@ /datum/fabricator_recipe/food fabricator_types = list(FABRICATOR_CLASS_FOOD) - path = /obj/item/chems/food/snacks/tofurkey + path = /obj/item/food/tofurkey + +// Remove matter from plates from the recipe, since we don't print food with plates. +/datum/fabricator_recipe/food/get_resources() + . = ..() + var/obj/item/food/food_result = path + if(!ispath(food_result, /obj/item/food)) + return // why?? why would this not be food?? + var/plate_path = initial(food_result.plate) + if(ispath(plate_path)) + var/list/plate_matter = atom_info_repository.get_matter_for(plate_path) + for(var/key in plate_matter) + resources[key] -= (plate_matter[key] * FABRICATOR_EXTRA_COST_FACTOR) + if(resources[key] <= 0) + resources -= key + +// Print the resulting food without a plate. +/datum/fabricator_recipe/food/build(turf/location, datum/fabricator_build_order/order) + if(ispath(path, /obj/item/food)) + . = list() + for(var/i = 1, i <= order.multiplier, i++) + . += new path(location, null, TRUE) // skip plate + else + return ..() /datum/fabricator_recipe/food/soylentviridians - path = /obj/item/chems/food/snacks/soylenviridians + path = /obj/item/food/soylenviridians /datum/fabricator_recipe/food/fries - path = /obj/item/chems/food/snacks/fries - -/datum/fabricator_recipe/food/soydope - path = /obj/item/chems/food/snacks/soydope + path = /obj/item/food/fries /datum/fabricator_recipe/food/ricepudding - path = /obj/item/chems/food/snacks/ricepudding \ No newline at end of file + path = /obj/item/food/ricepudding \ No newline at end of file diff --git a/code/modules/fabrication/designs/robotics/designs_organs.dm b/code/modules/fabrication/designs/robotics/designs_organs.dm new file mode 100644 index 000000000000..bce2a16e8e93 --- /dev/null +++ b/code/modules/fabrication/designs/robotics/designs_organs.dm @@ -0,0 +1,42 @@ +/datum/fabricator_recipe/robotics/organ + category = "Prosthetic Organs" + path = /obj/item/organ/internal/stomach + +/datum/fabricator_recipe/robotics/organ/get_product_name() + . = "prosthetic organ ([..()])" + +/datum/fabricator_recipe/robotics/organ/get_resources() + . = ..() + for(var/key in resources) + if(!ispath(key, /decl/material/solid)) + resources -= key + var/organ_meat_amount = LAZYACCESS(resources, /decl/material/solid/organic/meat) + if(organ_meat_amount) + if(LAZYACCESS(resources, /decl/material/solid/metal/steel)) + resources[/decl/material/solid/metal/steel] += organ_meat_amount + else + LAZYSET(resources, /decl/material/solid/metal/steel, organ_meat_amount) + LAZYREMOVE(resources, /decl/material/solid/organic/meat) + +/datum/fabricator_recipe/robotics/organ/build(turf/location, datum/fabricator_build_order/order) + . = ..() + var/decl/species/species = decls_repository.get_decl_by_id(order.get_data("species", global.using_map.default_species)) + for(var/obj/item/organ/internal/I in .) + I.set_species(species) + I.set_bodytype(species.base_internal_prosthetics_model) + I.status |= ORGAN_CUT_AWAY + +/datum/fabricator_recipe/robotics/organ/heart + path = /obj/item/organ/internal/heart + +/datum/fabricator_recipe/robotics/organ/liver + path = /obj/item/organ/internal/liver + +/datum/fabricator_recipe/robotics/organ/kidneys + path = /obj/item/organ/internal/kidneys + +/datum/fabricator_recipe/robotics/organ/lungs + path = /obj/item/organ/internal/lungs + +/datum/fabricator_recipe/robotics/organ/eyes + path = /obj/item/organ/internal/eyes diff --git a/code/modules/fabrication/designs/robotics/designs_prosthetics.dm b/code/modules/fabrication/designs/robotics/designs_prosthetics.dm index 66b339bd1ffd..fcec37a7beef 100644 --- a/code/modules/fabrication/designs/robotics/designs_prosthetics.dm +++ b/code/modules/fabrication/designs/robotics/designs_prosthetics.dm @@ -1,40 +1,102 @@ +#define DEFINE_ROBOLIMB_DESIGNS(MODEL_PATH, MODEL_ID) \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID { \ + model = MODEL_PATH; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/left_leg { \ + path = /obj/item/organ/external/leg; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/left_foot { \ + path = /obj/item/organ/external/foot; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/right_leg { \ + path = /obj/item/organ/external/leg/right; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/right_foot { \ + path = /obj/item/organ/external/foot/right; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/left_arm { \ + path = /obj/item/organ/external/arm; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/left_hand { \ + path = /obj/item/organ/external/hand; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/right_arm { \ + path = /obj/item/organ/external/arm/right; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/right_hand { \ + path = /obj/item/organ/external/hand/right; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/head { \ + path = /obj/item/organ/external/head; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/groin { \ + path = /obj/item/organ/external/groin; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/chest { \ + path = /obj/item/organ/external/chest; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/head { \ + path = /obj/item/organ/external/head; \ +} \ +/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/groin { \ + path = /obj/item/organ/external/groin; \ +} + /datum/fabricator_recipe/robotics/prosthetic - category = "Unbranded Prosthetics" - path = /obj/item/organ/external/leg var/model +/datum/fabricator_recipe/robotics/prosthetic/New() + if(model) + var/decl/bodytype/prosthetic/model_manufacturer = GET_DECL(model) + category = "[model_manufacturer.name] Prosthetics" + else + category = "Unbranded Prosthetics" + ..() + +/datum/fabricator_recipe/robotics/prosthetic/is_available_to_fab(var/obj/machinery/fabricator/fab) + . = ..() && model + if(.) + var/obj/machinery/fabricator/robotics/robofab = fab + if(!istype(robofab)) + return FALSE + var/decl/bodytype/prosthetic/company = GET_DECL(model) + if(!istype(company)) + return FALSE + var/decl/species/species = decls_repository.get_decl_by_id(robofab.picked_prosthetic_species) + if(!istype(species)) + return FALSE + var/obj/item/organ/target_limb = path + if(!ispath(target_limb, /obj/item/organ)) + return FALSE + return company.check_can_install(initial(target_limb.organ_tag), species.default_bodytype.bodytype_category) + /datum/fabricator_recipe/robotics/prosthetic/get_resources() . = ..() for(var/key in resources) - if(ispath(key, /decl/material)) + if(!ispath(key, /decl/material/solid)) resources -= key + var/organ_meat_amount = LAZYACCESS(resources, /decl/material/solid/organic/meat) + if(organ_meat_amount) + if(LAZYACCESS(resources, /decl/material/solid/metal/steel)) + resources[/decl/material/solid/metal/steel] += organ_meat_amount + else + LAZYSET(resources, /decl/material/solid/metal/steel, organ_meat_amount) + LAZYREMOVE(resources, /decl/material/solid/organic/meat) /datum/fabricator_recipe/robotics/prosthetic/get_product_name() - . = ..() - . = "prosthetic ([.])" - if(model) - var/datum/robolimb/brand = model - return "[.] ([initial(brand.company)])" + . = "prosthetic limb ([..()])" + if(ispath(model)) + var/decl/bodytype/prosthetic/brand = GET_DECL(model) + return "[.] ([brand.name])" -/datum/fabricator_recipe/robotics/prosthetic/build() +/datum/fabricator_recipe/robotics/prosthetic/build(var/turf/location, var/datum/fabricator_build_order/order) . = ..() - for(var/obj/item/organ/external/E in .) - E.robotize(model) - -/datum/fabricator_recipe/robotics/prosthetic/right_leg - path = /obj/item/organ/external/leg/right - -/datum/fabricator_recipe/robotics/prosthetic/left_arm - path = /obj/item/organ/external/arm - -/datum/fabricator_recipe/robotics/prosthetic/right_arm - path = /obj/item/organ/external/arm/right - -/datum/fabricator_recipe/robotics/prosthetic/head - path = /obj/item/organ/external/head - -/datum/fabricator_recipe/robotics/prosthetic/chest - path = /obj/item/organ/external/chest + var/species_name = order.get_data("species", global.using_map.default_species) + var/decl/species/species = decls_repository.get_decl_by_id(species_name) + if(species) + for(var/obj/item/organ/external/E in .) + E.set_species(species_name) + E.set_bodytype(model) + E.status |= ORGAN_CUT_AWAY -/datum/fabricator_recipe/robotics/prosthetic/groin - path = /obj/item/organ/external/groin +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/basic_human, generic) diff --git a/code/modules/fabrication/designs/textile/_textile.dm b/code/modules/fabrication/designs/textile/_textile.dm new file mode 100644 index 000000000000..29c301d091e0 --- /dev/null +++ b/code/modules/fabrication/designs/textile/_textile.dm @@ -0,0 +1,112 @@ +/datum/fabricator_recipe/textiles + path = /obj/item/clothing/jumpsuit/grey + category = "Textiles" + fabricator_types = list(FABRICATOR_CLASS_TEXTILE) + +/datum/fabricator_recipe/textiles/banner + path = /obj/item/banner + +/datum/fabricator_recipe/textiles/banner/green + path = /obj/item/banner/green + +/datum/fabricator_recipe/textiles/banner/red + path = /obj/item/banner/red + +/datum/fabricator_recipe/textiles/banner/blue + path = /obj/item/banner/blue + +/datum/fabricator_recipe/textiles/jeancasual + path = /obj/item/clothing/pants/casual + +/datum/fabricator_recipe/textiles/jeanclassic + path = /obj/item/clothing/pants/casual/classicjeans + +/datum/fabricator_recipe/textiles/jeanmustangjeans + path = /obj/item/clothing/pants/casual/mustangjeans + +/datum/fabricator_recipe/textiles/jeanblack + path = /obj/item/clothing/pants/casual/blackjeans + +/datum/fabricator_recipe/textiles/jeangrey + path = /obj/item/clothing/pants/casual/greyjeans + +/datum/fabricator_recipe/textiles/jeanyoung + path = /obj/item/clothing/pants/casual/youngfolksjeans + +/datum/fabricator_recipe/textiles/tracknumber1 + path = /obj/item/clothing/pants/casual/track + +/datum/fabricator_recipe/textiles/trackblue + path = /obj/item/clothing/pants/casual/track/blue + +/datum/fabricator_recipe/textiles/tracknavy + path = /obj/item/clothing/pants/casual/track/navy + +/datum/fabricator_recipe/textiles/trackblue + path = /obj/item/clothing/pants/casual/track/blue + +/datum/fabricator_recipe/textiles/trackred + path = /obj/item/clothing/pants/casual/track/red + +/datum/fabricator_recipe/textiles/jeancamo + path = /obj/item/clothing/pants/casual/camo + +// Headwear +/datum/fabricator_recipe/textiles/hat + category = "Headwear" + path = /obj/item/clothing/head/det + +/datum/fabricator_recipe/textiles/hat/fedoragrey + path = /obj/item/clothing/head/det/grey + +/datum/fabricator_recipe/textiles/hat/fedoradisco + path = /obj/item/clothing/head/det/wack + +/datum/fabricator_recipe/textiles/hat/bandanablack + path = /obj/item/clothing/mask/bandana + +/datum/fabricator_recipe/textiles/hat/bandanabloods + path = /obj/item/clothing/mask/bandana/red + +/datum/fabricator_recipe/textiles/hat/grovestreetbandana + path = /obj/item/clothing/mask/bandana/green + +/datum/fabricator_recipe/textiles/hat/goldsbanadas + path = /obj/item/clothing/mask/bandana/gold + +/datum/fabricator_recipe/textiles/hat/orangebandana + path = /obj/item/clothing/mask/bandana/orange + +/datum/fabricator_recipe/textiles/hat/purplebanada + path = /obj/item/clothing/mask/bandana/purple + +/datum/fabricator_recipe/textiles/hat/botanybanada + path = /obj/item/clothing/mask/bandana/botany + +/datum/fabricator_recipe/textiles/hat/camobandana + path = /obj/item/clothing/mask/bandana/camo + +/datum/fabricator_recipe/textiles/hat/skullsbandana + path = /obj/item/clothing/mask/bandana/skull + +/datum/fabricator_recipe/textiles/glove + category = "Gloves" + path = /obj/item/clothing/gloves + +/datum/fabricator_recipe/textiles/glove/blackglove + path = /obj/item/clothing/gloves/black + +/datum/fabricator_recipe/textiles/glove/blackglove + path = /obj/item/clothing/gloves/rainbow + +/datum/fabricator_recipe/textiles/glove/glovesevening + path = /obj/item/clothing/gloves/evening + +/datum/fabricator_recipe/textiles/glove/glovesbadswat + path = /obj/item/clothing/gloves/thick/swat + +/datum/fabricator_recipe/textiles/glove/glovescombat + path = /obj/item/clothing/gloves/thick/combat + +/datum/fabricator_recipe/textiles/glove/glovesbotany + path = /obj/item/clothing/gloves/thick/botany diff --git a/code/modules/fabrication/designs/textile/armor.dm b/code/modules/fabrication/designs/textile/armor.dm new file mode 100644 index 000000000000..ae7427a56cf1 --- /dev/null +++ b/code/modules/fabrication/designs/textile/armor.dm @@ -0,0 +1,94 @@ + +/datum/fabricator_recipe/textiles/armor + category = "Armor" + path = /obj/item/clothing/suit/armor/warden + +/datum/fabricator_recipe/textiles/armor/hos + path = /obj/item/clothing/suit/armor/hos + +/datum/fabricator_recipe/textiles/armor/jensen + path = /obj/item/clothing/suit/armor/hos/jensen + +// Plate carrier plates + +/datum/fabricator_recipe/textiles/armor/plate + category = "Armor - Insert plates" + path = /obj/item/clothing/armor_attachment/plate + +/datum/fabricator_recipe/textiles/armor/plate/medium + path = /obj/item/clothing/armor_attachment/plate/medium + +/datum/fabricator_recipe/textiles/armor/plate/tactical + path = /obj/item/clothing/armor_attachment/plate/tactical + +/datum/fabricator_recipe/textiles/armor/plate/merc + path = /obj/item/clothing/armor_attachment/plate/merc + +// Limb armor attachments + +/datum/fabricator_recipe/textiles/armor/limb + category = "Armor - Limb armor" + path = /obj/item/clothing/shoes/legguards/riot + +/datum/fabricator_recipe/textiles/armor/limb/arm_riot + path = /obj/item/clothing/gloves/armguards/riot + +/datum/fabricator_recipe/textiles/armor/limb/arm_merc + path = /obj/item/clothing/gloves/armguards/merc + +/datum/fabricator_recipe/textiles/armor/limb/leg_merc + path = /obj/item/clothing/shoes/legguards/merc + +/datum/fabricator_recipe/textiles/armor/limb/arm_ballistic + path = /obj/item/clothing/gloves/armguards/ballistic + +/datum/fabricator_recipe/textiles/armor/limb/leg_ballistic + path = /obj/item/clothing/shoes/legguards/ballistic + +// Speciality vests and plate carriers + +/datum/fabricator_recipe/textiles/armor/vest + category = "Armor - Vests" + path = /obj/item/clothing/suit/armor/pcarrier + +/datum/fabricator_recipe/textiles/armor/vest/bulletproof + path = /obj/item/clothing/suit/armor/bulletproof + +/datum/fabricator_recipe/textiles/armor/vest/riot + path = /obj/item/clothing/suit/armor/riot + +/datum/fabricator_recipe/textiles/armor/vest/blue + path = /obj/item/clothing/suit/armor/pcarrier/blue + +/datum/fabricator_recipe/textiles/armor/vest/tan + path = /obj/item/clothing/suit/armor/pcarrier/tan + +/datum/fabricator_recipe/textiles/armor/vest/green + path = /obj/item/clothing/suit/armor/pcarrier/green + +// Helmets + +/datum/fabricator_recipe/textiles/armor/helmet + category = "Armor - Helmets" + path = /obj/item/clothing/head/helmet + +/datum/fabricator_recipe/textiles/helmet/tactical + path = /obj/item/clothing/head/helmet/tactical + +/datum/fabricator_recipe/textiles/helmet/merc + path = /obj/item/clothing/head/helmet/merc + +/datum/fabricator_recipe/textiles/helmet/riot + path = /obj/item/clothing/head/helmet/riot + +/datum/fabricator_recipe/textiles/helmet/ablative + path = /obj/item/clothing/head/helmet/ablative + +/datum/fabricator_recipe/textiles/helmet/ballistic + path = /obj/item/clothing/head/helmet/ballistic + +/datum/fabricator_recipe/textiles/helmet/swat + path = /obj/item/clothing/head/helmet/swat + +/datum/fabricator_recipe/textiles/helmet/thunderdome + path = /obj/item/clothing/head/helmet/thunderdome diff --git a/code/modules/fabrication/designs/textile/footwear.dm b/code/modules/fabrication/designs/textile/footwear.dm new file mode 100644 index 000000000000..d787f54560e2 --- /dev/null +++ b/code/modules/fabrication/designs/textile/footwear.dm @@ -0,0 +1,72 @@ + +/datum/fabricator_recipe/textiles/footwear + category = "Footwear" + path = /obj/item/clothing/shoes + +/datum/fabricator_recipe/textiles/footwear/dressshoes + path = /obj/item/clothing/shoes/dress + +/datum/fabricator_recipe/textiles/footwear/sandal + path = /obj/item/clothing/shoes/sandal + +/datum/fabricator_recipe/textiles/footwear/clownshoes + path = /obj/item/clothing/shoes/clown_shoes + +/datum/fabricator_recipe/textiles/footwear/slippers + path = /obj/item/clothing/shoes/slippers + +/datum/fabricator_recipe/textiles/footwear/swimmingfins + path = /obj/item/clothing/shoes/swimmingfins + +/datum/fabricator_recipe/textiles/footwear/athleticshoes + path = /obj/item/clothing/shoes/athletic + +/datum/fabricator_recipe/textiles/footwear/sneakies + path = /obj/item/clothing/shoes/dress/sneakies + +/datum/fabricator_recipe/textiles/footwear/heels + path = /obj/item/clothing/shoes/heels + +/datum/fabricator_recipe/textiles/footwear/heelsblack + path = /obj/item/clothing/shoes/heels/black + +/datum/fabricator_recipe/textiles/footwear/rainbowheels + path = /obj/item/clothing/shoes/rainbow + +/datum/fabricator_recipe/textiles/footwear/heelsred + path = /obj/item/clothing/shoes/heels/red + +/datum/fabricator_recipe/textiles/footwear/flatshoes + path = /obj/item/clothing/shoes/flats + +/datum/fabricator_recipe/textiles/footwear/flatshoesblack + path = /obj/item/clothing/shoes/flats/black + +// Boots + +/datum/fabricator_recipe/textiles/footwear/swatboots + path = /obj/item/clothing/shoes/jackboots/swat + +/datum/fabricator_recipe/textiles/footwear/syndigaloshes + path = /obj/item/clothing/shoes/syndigaloshes + +/datum/fabricator_recipe/textiles/footwear/jungleboots + path = /obj/item/clothing/shoes/jackboots/jungleboots + +/datum/fabricator_recipe/textiles/footwear/jackboots + path = /obj/item/clothing/shoes/jackboots + +/datum/fabricator_recipe/textiles/footwear/workboots + path = /obj/item/clothing/shoes/workboots + +/datum/fabricator_recipe/textiles/footwear/desertboots + path = /obj/item/clothing/shoes/jackboots/desertboots + +/datum/fabricator_recipe/textiles/footwear/dutyboots + path = /obj/item/clothing/shoes/jackboots/duty + +/datum/fabricator_recipe/textiles/footwear/desertboots + path = /obj/item/clothing/shoes/jackboots/desertboots + +/datum/fabricator_recipe/textiles/footwear/tacticalboots + path = /obj/item/clothing/shoes/jackboots/tactical \ No newline at end of file diff --git a/code/modules/fabrication/designs/textile/gimmick.dm b/code/modules/fabrication/designs/textile/gimmick.dm new file mode 100644 index 000000000000..97f4344e5317 --- /dev/null +++ b/code/modules/fabrication/designs/textile/gimmick.dm @@ -0,0 +1,139 @@ + +/datum/fabricator_recipe/textiles/gimmick + category = "Novelty Items" + path = /obj/item/clothing/suit/monkeysuit + +/datum/fabricator_recipe/textiles/gimmick/bluetag + path = /obj/item/clothing/suit/bluetag + +/datum/fabricator_recipe/textiles/gimmick/redtag + path = /obj/item/clothing/suit/redtag + +/datum/fabricator_recipe/textiles/gimmick/mantle + path = /obj/item/clothing/suit/mantle/fated + +/datum/fabricator_recipe/textiles/gimmick/syndicatefake + path = /obj/item/clothing/suit/syndicatefake + +/datum/fabricator_recipe/textiles/gimmick/chickensuit + path = /obj/item/clothing/suit/chickensuit + +/datum/fabricator_recipe/textiles/gimmick/warhammer40k + path = /obj/item/clothing/suit/imperium_monk + +/datum/fabricator_recipe/textiles/gimmick/hastur + path = /obj/item/clothing/suit/hastur + +/datum/fabricator_recipe/textiles/gimmick/plaguedoctorsuit + path = /obj/item/clothing/suit/bio_suit/plaguedoctorsuit + +/datum/fabricator_recipe/textiles/gimmick/ianshirt + path = /obj/item/clothing/suit/ianshirt + +/datum/fabricator_recipe/textiles/gimmick/luchalibrehonor + path = /obj/item/clothing/mask/luchador/rudos + +/datum/fabricator_recipe/textiles/gimmick/luchalibre + path = /obj/item/clothing/mask/luchador/tecnicos + +/datum/fabricator_recipe/textiles/gimmick/genericluchadorian + path = /obj/item/clothing/mask/luchador + +/datum/fabricator_recipe/textiles/gimmick/radicaldude + path = /obj/item/clothing/mask/gas/radical + +/datum/fabricator_recipe/textiles/gimmick/plaguedoctorsmask + path = /obj/item/clothing/mask/gas/plaguedoctor + +/datum/fabricator_recipe/textiles/gimmick/clownhat + path = /obj/item/clothing/mask/gas/clown_hat + +/datum/fabricator_recipe/textiles/gimmick/whyclown + path = /obj/item/clothing/mask/gas/sexyclown + +/datum/fabricator_recipe/textiles/gimmick/mimehat + path = /obj/item/clothing/mask/gas/mime + +/datum/fabricator_recipe/textiles/gimmick/monke + path = /obj/item/clothing/mask/gas/monkeymask + +/datum/fabricator_recipe/textiles/gimmick/jesusmimeno + path = /obj/item/clothing/mask/gas/sexymime + +/datum/fabricator_recipe/textiles/gimmick/owlmask + path = /obj/item/clothing/mask/gas/owl_mask + +/datum/fabricator_recipe/textiles/gimmick/costumerubber + path = /obj/item/clothing/suit/rubber + +/datum/fabricator_recipe/textiles/gimmick/rubbermanmask + path = /obj/item/clothing/mask/rubber + +/datum/fabricator_recipe/textiles/gimmick/humanskinfeelsnice + path = /obj/item/clothing/mask/rubber/species + +/datum/fabricator_recipe/textiles/gimmick/catnyaa + path = /obj/item/clothing/mask/rubber/species/cat + +/datum/fabricator_recipe/textiles/gimmick/spiritmask + path = /obj/item/clothing/mask/spirit + +/datum/fabricator_recipe/textiles/gimmick/pirate + path = /obj/item/clothing/suit/pirate + +/datum/fabricator_recipe/textiles/gimmick/pirate_captain + path = /obj/item/clothing/suit/hgpirate + +/datum/fabricator_recipe/textiles/gimmick/judge + path = /obj/item/clothing/suit/judgerobe + +/datum/fabricator_recipe/textiles/gimmick/gladiator + path = /obj/item/clothing/head/helmet/gladiator + +/datum/fabricator_recipe/textiles/gimmick/maddoclabcoat + path = /obj/item/clothing/suit/toggle/labcoat/mad + +/datum/fabricator_recipe/textiles/gimmick/holidaypriest + path = /obj/item/clothing/suit/holidaypriest + +/datum/fabricator_recipe/textiles/gimmick/nun + path = /obj/item/clothing/suit/nun + +/datum/fabricator_recipe/textiles/gimmick/straight_jacket + path = /obj/item/clothing/suit/straight_jacket + +/datum/fabricator_recipe/textiles/gimmick/snorkel + path = /obj/item/clothing/mask/snorkel + +/datum/fabricator_recipe/textiles/gimmick/cap_tunic + path = /obj/item/clothing/shirt/tunic/captain + +/datum/fabricator_recipe/textiles/gimmick/capjacket + path = /obj/item/clothing/suit/jacket/captain + +/datum/fabricator_recipe/textiles/gimmick/xeno + path = /obj/item/clothing/head/xeno/scarf + +/datum/fabricator_recipe/textiles/gimmick/syndicatetactical + path = /obj/item/clothing/shirt/syndicate/tacticool + +/datum/fabricator_recipe/textiles/gimmick/costumesanta + path = /obj/item/clothing/suit/santa + +/datum/fabricator_recipe/textiles/gimmick/santahat + path = /obj/item/clothing/head/santahat + +/datum/fabricator_recipe/textiles/gimmick/cape + path = /obj/item/clothing/suit/shouldercape + +/datum/fabricator_recipe/textiles/gimmick/capegrunt + path = /obj/item/clothing/suit/shouldercape + +/datum/fabricator_recipe/textiles/gimmick/capeofficer + path = /obj/item/clothing/suit/shouldercape/officer + +/datum/fabricator_recipe/textiles/gimmick/capecommand + path = /obj/item/clothing/suit/shouldercape/command + +/datum/fabricator_recipe/textiles/gimmick/capegeneral + path = /obj/item/clothing/suit/shouldercape/general \ No newline at end of file diff --git a/code/modules/fabrication/designs/textile/job.dm b/code/modules/fabrication/designs/textile/job.dm new file mode 100644 index 000000000000..39ba3626a2ed --- /dev/null +++ b/code/modules/fabrication/designs/textile/job.dm @@ -0,0 +1,188 @@ + +// Misc +/datum/fabricator_recipe/textiles/job + category = "Work Clothing" + path = /obj/item/clothing/suit/chef + +/datum/fabricator_recipe/textiles/job/chefalt + path = /obj/item/clothing/suit/chef/classic + +/datum/fabricator_recipe/textiles/job/chaplain_hoodie + path = /obj/item/clothing/suit/chaplain_hoodie + +/datum/fabricator_recipe/textiles/job/engineerhazardvest + path = /obj/item/clothing/suit/hazardvest + +/datum/fabricator_recipe/textiles/job/overalls + path = /obj/item/clothing/suit/apron/overalls + +// Medical (Science barely has enough for a category) +/datum/fabricator_recipe/textiles/job/medical + category = "Medical & Science Clothing" + path = /obj/item/clothing/jumpsuit/medical + +/datum/fabricator_recipe/textiles/job/medical/research_director + path = /obj/item/clothing/jumpsuit/research_director + +/datum/fabricator_recipe/textiles/job/medical/rdalt + path = /obj/item/clothing/costume/research_director_suit + +/datum/fabricator_recipe/textiles/job/medical/dress_rd + path = /obj/item/clothing/skirt/research_director + +/datum/fabricator_recipe/textiles/job/medical/chemist + path = /obj/item/clothing/jumpsuit/chemist + +/datum/fabricator_recipe/textiles/job/medical/chief_medical_officer + path = /obj/item/clothing/jumpsuit/chief_medical_officer + +/datum/fabricator_recipe/textiles/job/medical/geneticist + path = /obj/item/clothing/jumpsuit/geneticist + +/datum/fabricator_recipe/textiles/job/medical/virologist + path = /obj/item/clothing/jumpsuit/virologist + +/datum/fabricator_recipe/textiles/job/medical/nurse + path = /obj/item/clothing/dress/nurse + +/datum/fabricator_recipe/textiles/job/medical/medical + path = /obj/item/clothing/jumpsuit/medical + +/datum/fabricator_recipe/textiles/job/medical/paramedic + path = /obj/item/clothing/jumpsuit/medical/paramedic + +/datum/fabricator_recipe/textiles/job/medical/scrubs_pants + path = /obj/item/clothing/pants/scrubs + +/datum/fabricator_recipe/textiles/job/medical/blue_pants + path = /obj/item/clothing/pants/scrubs/blue + +/datum/fabricator_recipe/textiles/job/medical/green_pants + path = /obj/item/clothing/pants/scrubs/green + +/datum/fabricator_recipe/textiles/job/medical/purple_pants + path = /obj/item/clothing/pants/scrubs/purple + +/datum/fabricator_recipe/textiles/job/medical/black_pants + path = /obj/item/clothing/pants/scrubs/black + +/datum/fabricator_recipe/textiles/job/medical/navyblue_pants + path = /obj/item/clothing/pants/scrubs/navyblue + +/datum/fabricator_recipe/textiles/job/medical/lilac_pants + path = /obj/item/clothing/pants/scrubs/lilac + +/datum/fabricator_recipe/textiles/job/medical/teal_pants + path = /obj/item/clothing/pants/scrubs/teal + +/datum/fabricator_recipe/textiles/job/medical/heliodor_pants + path = /obj/item/clothing/pants/scrubs/heliodor + +/datum/fabricator_recipe/textiles/job/medical/scrubs_shirt + path = /obj/item/clothing/shirt/scrubs + +/datum/fabricator_recipe/textiles/job/medical/blue_shirt + path = /obj/item/clothing/shirt/scrubs/blue + +/datum/fabricator_recipe/textiles/job/medical/green_shirt + path = /obj/item/clothing/shirt/scrubs/green + +/datum/fabricator_recipe/textiles/job/medical/purple_shirt + path = /obj/item/clothing/shirt/scrubs/purple + +/datum/fabricator_recipe/textiles/job/medical/black_shirt + path = /obj/item/clothing/shirt/scrubs/black + +/datum/fabricator_recipe/textiles/job/medical/navyblue_shirt + path = /obj/item/clothing/shirt/scrubs/navyblue + +/datum/fabricator_recipe/textiles/job/medical/lilac_shirt + path = /obj/item/clothing/shirt/scrubs/lilac + +/datum/fabricator_recipe/textiles/job/medical/teal_shirt + path = /obj/item/clothing/shirt/scrubs/teal + +/datum/fabricator_recipe/textiles/job/medical/heliodor_shirt + path = /obj/item/clothing/shirt/scrubs/heliodor + +/datum/fabricator_recipe/textiles/job/medical/psych + path = /obj/item/clothing/jumpsuit/psych + +// Suits +/datum/fabricator_recipe/textiles/job/medical/surgicalapron + path = /obj/item/clothing/suit/surgicalapron + +/datum/fabricator_recipe/textiles/job/medical/genericlab + path = /obj/item/clothing/suit/toggle/labcoat + +/datum/fabricator_recipe/textiles/job/medical/labcoatcmo + path = /obj/item/clothing/suit/toggle/labcoat/cmo + +/datum/fabricator_recipe/textiles/job/medical/chemistlab + path = /obj/item/clothing/suit/toggle/labcoat/chemist + +/datum/fabricator_recipe/textiles/job/medical/labcoatgenetics + path = /obj/item/clothing/suit/toggle/labcoat/genetics + +/datum/fabricator_recipe/textiles/job/medical/labcoatvirologist + path = /obj/item/clothing/suit/toggle/labcoat/virologist + +/datum/fabricator_recipe/textiles/job/medical/labcoatblue + path = /obj/item/clothing/suit/toggle/labcoat/blue + +/datum/fabricator_recipe/textiles/job/medical/labcoatrd + path = /obj/item/clothing/suit/toggle/labcoat/rd + +/datum/fabricator_recipe/textiles/job/medical/suithospital + path = /obj/item/clothing/suit/hospital + +/datum/fabricator_recipe/textiles/job/medical/suitmedicalresponder + path = /obj/item/clothing/suit/jacket/first_responder + +/datum/fabricator_recipe/textiles/job/medical/medicalchestrig + path = /obj/item/clothing/suit/medical_chest_rig + +// Security +/datum/fabricator_recipe/textiles/job/security + category = "Security Clothing" + path = /obj/item/clothing/jumpsuit/security + +/datum/fabricator_recipe/textiles/job/security/forensics + path = /obj/item/clothing/suit/forensics + +/datum/fabricator_recipe/textiles/job/security/coatspace_agent + path = /obj/item/clothing/suit/jacket/agent + +/datum/fabricator_recipe/textiles/job/security/detcoat + path = /obj/item/clothing/suit/det_trench/reinforced + +/datum/fabricator_recipe/textiles/job/security/warden + path = /obj/item/clothing/jumpsuit/warden + +/datum/fabricator_recipe/textiles/job/security/dispatch + path = /obj/item/clothing/costume/dispatch + +/datum/fabricator_recipe/textiles/job/security/tacticalofficer + path = /obj/item/clothing/jumpsuit/tactical + +/datum/fabricator_recipe/textiles/job/security/hos + path = /obj/item/clothing/head/HoS + +/datum/fabricator_recipe/textiles/job/security/securityjensen + path = /obj/item/clothing/jumpsuit/head_of_security/jensen + +/datum/fabricator_recipe/textiles/job/security/securityhos + path = /obj/item/clothing/jumpsuit/head_of_security + +// Tacticool +/datum/fabricator_recipe/textiles/job/security/tactical + path = /obj/item/clothing/shirt/syndicate + +/datum/fabricator_recipe/textiles/job/security/syndicatecombat + path = /obj/item/clothing/shirt/syndicate/combat + +/datum/fabricator_recipe/textiles/job/security/maskbalatact + path = /obj/item/clothing/mask/balaclava/tactical + +/datum/fabricator_recipe/textiles/job/security/balabalagetdolla + path = /obj/item/clothing/mask/balaclava diff --git a/code/modules/fabrication/designs/textile/overwear.dm b/code/modules/fabrication/designs/textile/overwear.dm new file mode 100644 index 000000000000..52218db5138b --- /dev/null +++ b/code/modules/fabrication/designs/textile/overwear.dm @@ -0,0 +1,82 @@ + +/datum/fabricator_recipe/textiles/overwear + category = "Overwear" + path = /obj/item/clothing/suit/det_trench + +/datum/fabricator_recipe/textiles/overwear/coat + path = /obj/item/clothing/suit/toggle/labcoat/coat + +/datum/fabricator_recipe/textiles/overwear/leather_coat + path = /obj/item/clothing/suit/leathercoat + +/datum/fabricator_recipe/textiles/overwear/coatbomber + path = /obj/item/clothing/suit/jacket/bomber + +/datum/fabricator_recipe/textiles/overwear/coatleather_jacket + path = /obj/item/clothing/suit/jacket/leather + +/datum/fabricator_recipe/textiles/overwear/coatbrown_jacket + path = /obj/item/clothing/suit/jacket/brown + +/datum/fabricator_recipe/textiles/overwear/coathoodie + path = /obj/item/clothing/suit/jacket/hoodie + +/datum/fabricator_recipe/textiles/overwear/hoodiealt + path = /obj/item/clothing/suit/jacket/hoodie/black + +/datum/fabricator_recipe/textiles/overwear/trackstandard + path = /obj/item/clothing/suit/toggle/track + +/datum/fabricator_recipe/textiles/overwear/trackblue + path = /obj/item/clothing/suit/toggle/track/blue + +/datum/fabricator_recipe/textiles/overwear/trackred + path = /obj/item/clothing/suit/toggle/track/red + +/datum/fabricator_recipe/textiles/overwear/tracknavy + path = /obj/item/clothing/suit/toggle/track/navy + +/datum/fabricator_recipe/textiles/overwear/lettermanstandard + path = /obj/item/clothing/suit/jacket/letterman + +/datum/fabricator_recipe/textiles/overwear/lettermanred + path = /obj/item/clothing/suit/jacket/letterman/red + +/datum/fabricator_recipe/textiles/overwear/lettermanblue + path = /obj/item/clothing/suit/jacket/letterman/blue + +/datum/fabricator_recipe/textiles/overwear/lettermanbrown + path = /obj/item/clothing/suit/jacket/letterman/brown + +/datum/fabricator_recipe/textiles/overwear/lettermangreen + path = /obj/item/clothing/suit/jacket/letterman/green + +/datum/fabricator_recipe/textiles/overwear/poncho1 + path = /obj/item/clothing/suit/poncho + +/datum/fabricator_recipe/textiles/overwear/poncho2 + path = /obj/item/clothing/suit/poncho/green + +/datum/fabricator_recipe/textiles/overwear/poncho3 + path = /obj/item/clothing/suit/poncho/red + +/datum/fabricator_recipe/textiles/overwear/poncho4 + path = /obj/item/clothing/suit/poncho/purple + +/datum/fabricator_recipe/textiles/overwear/poncho5 + path = /obj/item/clothing/suit/poncho/blue + +/datum/fabricator_recipe/textiles/overwear/poncho6 + path = /obj/item/clothing/suit/poncho/security + +/datum/fabricator_recipe/textiles/overwear/poncho7 + path = /obj/item/clothing/suit/poncho/medical + +/datum/fabricator_recipe/textiles/overwear/poncho8 + path = /obj/item/clothing/suit/poncho/engineering + +/datum/fabricator_recipe/textiles/overwear/poncho9 + path = /obj/item/clothing/suit/poncho/cargo + +/datum/fabricator_recipe/textiles/overwear/mantle + path = /obj/item/clothing/suit/mantle diff --git a/code/modules/fabrication/designs/textile/protective.dm b/code/modules/fabrication/designs/textile/protective.dm new file mode 100644 index 000000000000..ca04557a0e98 --- /dev/null +++ b/code/modules/fabrication/designs/textile/protective.dm @@ -0,0 +1,92 @@ + +/datum/fabricator_recipe/textiles/protective + category = "Protective Gear" + path = /obj/item/clothing/suit/bio_suit + +/datum/fabricator_recipe/textiles/protective/bio_hood + path = /obj/item/clothing/head/bio_hood + +/datum/fabricator_recipe/textiles/protective/radiation_mask + path = /obj/item/clothing/head/radiation + +/datum/fabricator_recipe/textiles/protective/radiation_suit + path = /obj/item/clothing/suit/radiation + +/datum/fabricator_recipe/textiles/protective/chem_suit + path = /obj/item/clothing/suit/chem_suit + +/datum/fabricator_recipe/textiles/protective/chem_hood + path = /obj/item/clothing/head/chem_hood + +// Masks +/datum/fabricator_recipe/textiles/job/protective/surgicalmask + path = /obj/item/clothing/mask/surgical + +// Gas masks +/datum/fabricator_recipe/textiles/protective/gasgas + path = /obj/item/clothing/mask/gas + +/datum/fabricator_recipe/textiles/protective/gashalf + path = /obj/item/clothing/mask/gas/half + +/datum/fabricator_recipe/textiles/protective/cheapgass + path = /obj/item/clothing/mask/gas/budget + +/datum/fabricator_recipe/textiles/protective/swatswat + path = /obj/item/clothing/mask/gas/swat + +/datum/fabricator_recipe/textiles/protective/radicaldude + path = /obj/item/clothing/mask/gas/radical + +/datum/fabricator_recipe/textiles/protective/cheapgass + path = /obj/item/clothing/mask/gas/syndicate + +/datum/fabricator_recipe/textiles/protective/swatteammask + path = /obj/item/clothing/mask/gas/swat + +/datum/fabricator_recipe/textiles/protective/syndicategasmask + path = /obj/item/clothing/mask/gas/syndicate + +/datum/fabricator_recipe/textiles/protective/death_commando + path = /obj/item/clothing/mask/gas/death_commando + +/datum/fabricator_recipe/textiles/protective/aquabreather + path = /obj/item/clothing/mask/gas/aquabreather + +// Breath masks +/datum/fabricator_recipe/textiles/protective/emergencymask + path = /obj/item/clothing/mask/breath/emergency + +/datum/fabricator_recipe/textiles/protective/medicalmask + path = /obj/item/clothing/mask/breath/medical + +/datum/fabricator_recipe/textiles/protective/industryworker + path = /obj/item/clothing/mask/breath/scba + +// hard hats +/datum/fabricator_recipe/textiles/protective/hardhatstandard + path = /obj/item/clothing/head/hardhat + +/datum/fabricator_recipe/textiles/protective/orangehardhat + path = /obj/item/clothing/head/hardhat/orange + +/datum/fabricator_recipe/textiles/protective/hardhatred + path = /obj/item/clothing/head/hardhat/red + +/datum/fabricator_recipe/textiles/protective/whitehardhat + path = /obj/item/clothing/head/hardhat/white + +/datum/fabricator_recipe/textiles/protective/dbluehardhat + path = /obj/item/clothing/head/hardhat/dblue + +/datum/fabricator_recipe/textiles/protective/emshardhat + path = /obj/item/clothing/head/hardhat/ems + +/datum/fabricator_recipe/textiles/protective/firefighterhardhat + path = /obj/item/clothing/head/hardhat/firefighter + +/datum/fabricator_recipe/textiles/protective/damage_controlhardhat + path = /obj/item/clothing/head/hardhat/damage_control + +/datum/fabricator_recipe/textiles/protective/emsdc + path = /obj/item/clothing/head/hardhat/ems/dc_light diff --git a/code/modules/fabrication/designs/textile/space.dm b/code/modules/fabrication/designs/textile/space.dm new file mode 100644 index 000000000000..e9f09b71168c --- /dev/null +++ b/code/modules/fabrication/designs/textile/space.dm @@ -0,0 +1,36 @@ +/datum/fabricator_recipe/textiles/space + category = "EVA Gear" + path = /obj/item/clothing/suit/space + +/datum/fabricator_recipe/textiles/space/helmet + path = /obj/item/clothing/head/helmet/space + +/datum/fabricator_recipe/textiles/space/jetpack + path = /obj/item/tank/jetpack/oxygen + +/datum/fabricator_recipe/textiles/breath_mask + path = /obj/item/clothing/mask/breath + +/datum/fabricator_recipe/textiles/space/emergency + path = /obj/item/clothing/suit/space/emergency + +/datum/fabricator_recipe/textiles/space/emergency/helmet + path = /obj/item/clothing/head/helmet/space/emergency + +/datum/fabricator_recipe/textiles/space/engineering + path = /obj/item/clothing/suit/space/void/engineering/alt + +/datum/fabricator_recipe/textiles/space/engineering/helmet + path = /obj/item/clothing/head/helmet/space/void/engineering/alt + +/datum/fabricator_recipe/textiles/space/magboots + path = /obj/item/clothing/shoes/magboots + +/datum/fabricator_recipe/textiles/space/void + path = /obj/item/clothing/suit/space/void + +/datum/fabricator_recipe/textiles/space/mining + path = /obj/item/clothing/suit/space/void/mining + +/datum/fabricator_recipe/textiles/space/salvage + path = /obj/item/clothing/suit/space/void/engineering/salvage \ No newline at end of file diff --git a/code/modules/fabrication/designs/textile/storage.dm b/code/modules/fabrication/designs/textile/storage.dm new file mode 100644 index 000000000000..aaf9d2e8fc3d --- /dev/null +++ b/code/modules/fabrication/designs/textile/storage.dm @@ -0,0 +1,27 @@ +/datum/fabricator_recipe/textiles/storage + category = "Storage" + path = /obj/item/backpack + +/datum/fabricator_recipe/textiles/storage/dufflebag + path = /obj/item/backpack/dufflebag + +/datum/fabricator_recipe/textiles/storage/satchel + path = /obj/item/backpack/satchel + +/datum/fabricator_recipe/textiles/storage/messenger + path = /obj/item/backpack/messenger + +/datum/fabricator_recipe/textiles/storage/tool_belt + path= /obj/item/belt/utility + +/datum/fabricator_recipe/textiles/storage/mining_satchel + path = /obj/item/ore_satchel + +/datum/fabricator_recipe/textiles/storage/botanical_satchel + path = /obj/item/plant_satchel + +/datum/fabricator_recipe/textiles/storage/wallet + path = /obj/item/wallet/leather + +/datum/fabricator_recipe/textiles/storage/money_bag + path = /obj/item/bag/cash \ No newline at end of file diff --git a/code/modules/fabrication/fabricator_bioprinter.dm b/code/modules/fabrication/fabricator_bioprinter.dm new file mode 100644 index 000000000000..26e548f8d627 --- /dev/null +++ b/code/modules/fabrication/fabricator_bioprinter.dm @@ -0,0 +1,87 @@ +#define BIOPRINTER_BLOOD_SAMPLE_SIZE 5 + +/obj/machinery/fabricator/bioprinter + name = "bioprinter" + desc = "Fabricator used for cloning organs from DNA." + icon = 'icons/obj/machines/fabricators/bioprinter.dmi' + icon_state = "bioprinter" + base_icon_state = "bioprinter" + base_type = /obj/machinery/fabricator/bioprinter + fabricator_class = FABRICATOR_CLASS_MEAT + ignore_input_contents_length = TRUE // mostly eats organs, let people quickly dump a torso in there without doing surgery. + var/datum/mob_snapshot/loaded_dna //DNA for biological organs + +/obj/machinery/fabricator/bioprinter/can_ingest(var/obj/item/thing) + . = istype(thing, /obj/item/organ) || istype(thing, /obj/item/food/butchery) || istype(thing?.material, /decl/material/solid/organic/meat) || ..() + +/obj/machinery/fabricator/bioprinter/get_nano_template() + return "fabricator_bioprinter.tmpl" + +/obj/machinery/fabricator/bioprinter/make_order(datum/fabricator_recipe/recipe, multiplier) + var/datum/fabricator_build_order/order = ..() + //Keep these in the order so changing settings while queueing things up won't screw up older orders in the queue + order.set_data("dna", loaded_dna) + return order + +/obj/machinery/fabricator/bioprinter/do_build(datum/fabricator_build_order/order) + . = ..() + //Fetch params as they were when the order was passed + var/datum/mob_snapshot/D = order.get_data("dna") + for(var/obj/item/organ/O in .) + if(D) + O.copy_from_mob_snapshot(D) + O.status |= ORGAN_CUT_AWAY + +/obj/machinery/fabricator/bioprinter/attackby(obj/item/used_item, mob/user) + if(istype(used_item,/obj/item/chems/syringe)) + var/obj/item/chems/syringe/S = used_item + if(REAGENT_VOLUME(S.reagents, /decl/material/liquid/blood)) + var/sample = REAGENT_DATA(S.reagents, /decl/material/liquid/blood) + if(islist(sample)) + var/weakref/R = sample[DATA_BLOOD_DONOR] + var/mob/living/human/H = R.resolve() + if(H && istype(H) && H.species) + loaded_dna = H.get_mob_snapshot(check_dna = TRUE) + if(loaded_dna) + to_chat(user, SPAN_INFO("You inject the blood sample into \the [src].")) + S.remove_any_reagents(BIOPRINTER_BLOOD_SAMPLE_SIZE) + //Tell nano to do its job + SSnano.update_uis(src) + return TRUE + to_chat(user, SPAN_WARNING("\The [src] displays an error: no viable blood sample could be obtained from \the [used_item].")) + return TRUE + . = ..() + +/obj/machinery/fabricator/bioprinter/OnTopic(user, href_list, state) + . = ..() + if(href_list["flush_dna"]) + if(fab_status_flags & FAB_BUSY) + state("Can't flush DNA while printing in progress!") + else + loaded_dna = null + . = TOPIC_REFRESH + +/obj/machinery/fabricator/bioprinter/proc/ui_data_dna(mob/user, ui_key) + if(!loaded_dna) + return null + return list( + "real_name" = loaded_dna.real_name, + "UE" = loaded_dna.unique_enzymes, + "species" = loaded_dna.root_species.uid, + "btype" = loaded_dna.blood_type, + ) + +/obj/machinery/fabricator/bioprinter/ui_draw_config(mob/user, ui_key) + return TRUE //Always draw it for us + +/obj/machinery/fabricator/bioprinter/ui_data_config(mob/user, ui_key) + if(!(. = ..())) + return + var/list/dnaentry = ui_data_dna(user, ui_key) + LAZYSET(., "dna", dnaentry) + +//Only let us print things if we got a DNA set +/obj/machinery/fabricator/bioprinter/can_build(datum/fabricator_recipe/recipe, multiplier) + return ..() && loaded_dna +/obj/machinery/fabricator/bioprinter/ui_fabricator_build_option_is_available(datum/fabricator_recipe/R, max_sheets) + return ..() && loaded_dna diff --git a/code/modules/fabrication/fabricator_books.dm b/code/modules/fabrication/fabricator_books.dm index 6800874675a2..b5861f878581 100644 --- a/code/modules/fabrication/fabricator_books.dm +++ b/code/modules/fabrication/fabricator_books.dm @@ -8,22 +8,29 @@ active_power_usage = 1000 base_type = /obj/machinery/fabricator/book fabricator_class = FABRICATOR_CLASS_BOOKS - base_storage_capacity = list( - /decl/material/solid/wood = SHEET_MATERIAL_AMOUNT * 20, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 20 - ) color_selectable = TRUE -/obj/machinery/fabricator/book/do_build(datum/fabricator_recipe/recipe, amount) - . = recipe.build(get_turf(src), amount, selected_color) +/obj/machinery/fabricator/book/can_ingest(obj/item/thing) + var/static/list/paper_types = list( + /obj/item/paper, + /obj/item/shreddedp + ) + . = is_type_in_list(thing, paper_types) || ..() + +/obj/machinery/fabricator/book/make_order(datum/fabricator_recipe/recipe, multiplier) + var/datum/fabricator_build_order/order = ..() + LAZYSET(order.data, "selected_color", selected_color) + return order + +/obj/machinery/fabricator/book/do_build(datum/fabricator_build_order/order) + . = order.target_recipe.build(get_turf(src), order) -/datum/fabricator_recipe/book/skill/build(var/turf/location, var/amount = 1, var/color = COLOR_WHITE) +/datum/fabricator_recipe/book/skill/build(var/turf/location, var/datum/fabricator_build_order/order) . = list() - for(var/i = 1, i <= amount, i++) + for(var/i = 1, i <= order.multiplier, i++) var/obj/item/book/skill/custom/new_item = new path(location) if(colorable) - new_item.color = color - new_item.overlays += overlay_image('icons/obj/library.dmi', "tb_over_pages", null, RESET_COLOR) + new_item.set_color(order.get_data("selected_color", COLOR_WHITE)) . += new_item /obj/machinery/fabricator/book/get_color_list() diff --git a/code/modules/fabrication/fabricator_build.dm b/code/modules/fabrication/fabricator_build.dm index 6519881755f3..5ed1bf02adc6 100644 --- a/code/modules/fabrication/fabricator_build.dm +++ b/code/modules/fabrication/fabricator_build.dm @@ -1,3 +1,4 @@ +#define MAX_QUEUED_ORDERS 100 /obj/machinery/fabricator/proc/update_current_build(var/spend_time) if(!istype(currently_building) || !is_functioning()) @@ -9,30 +10,50 @@ return // Print the item. - do_build(currently_building.target_recipe, currently_building.multiplier) + do_build(currently_building) QDEL_NULL(currently_building) get_next_build() update_icon() -/obj/machinery/fabricator/proc/do_build(var/datum/fabricator_recipe/recipe, var/amount) - . = recipe.build(get_turf(src), amount) +/obj/machinery/fabricator/proc/do_build(var/datum/fabricator_build_order/order) + . = order.target_recipe.build(get_turf(src), order) if(output_dir) for(var/atom/movable/product in .) step(product, output_dir) /obj/machinery/fabricator/proc/start_building() - if(!(fab_status_flags & FAB_BUSY) && is_functioning()) - fab_status_flags |= FAB_BUSY + if(is_functioning()) update_use_power(POWER_USE_ACTIVE) - update_icon() - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, fabricator_sound, volume = 30) /obj/machinery/fabricator/proc/stop_building() - if(fab_status_flags & FAB_BUSY) + update_use_power(POWER_USE_IDLE) + +/obj/machinery/fabricator/power_change() + . = ..() + if(.) + if(stat & (BROKEN|NOPOWER)) + stop_building() + else if(!currently_building) + get_next_build() + else + start_building() + +/obj/machinery/fabricator/update_use_power() + . = ..() + if(use_power == POWER_USE_ACTIVE) + fab_status_flags |= FAB_BUSY + if(!sound_token) + sound_token = play_looping_sound(src, sound_id, fabricator_sound, volume = 30) + if(!currently_building) + get_next_build() + else fab_status_flags &= ~FAB_BUSY - update_use_power(POWER_USE_IDLE) - update_icon() QDEL_NULL(sound_token) + // This is to allow people to fix the fab when it + // gets stuck building a recipe during power loss. + if(istype(currently_building)) + queued_orders.Insert(1, currently_building) + currently_building = null /obj/machinery/fabricator/proc/get_next_build() currently_building = null @@ -45,33 +66,52 @@ updateUsrDialog() /obj/machinery/fabricator/proc/try_queue_build(var/datum/fabricator_recipe/recipe, var/multiplier) - // Do some basic sanity checking. if(!is_functioning() || !istype(recipe) || !(recipe in design_cache)) return multiplier = sanitize_integer(multiplier, 1, 100, 1) - if(!ispath(recipe, /obj/item/stack) && multiplier > 1) - multiplier = 1 // Check if sufficient resources exist. for(var/material in recipe.resources) if(stored_material[material] < round(recipe.resources[material] * mat_efficiency) * multiplier) return - // Generate and track a new order. + //Ask subclass if its okay to print + if(!can_build(recipe, multiplier)) + return + + var/amount_queued = 1 + if(!ispath(recipe.path, /obj/item/stack) && multiplier > 1) + // For non-stacks, multipliers just queue more orders. + amount_queued = multiplier + multiplier = 1 + // Generate and track the new order(s). + amount_queued = min(amount_queued, MAX_QUEUED_ORDERS - length(queued_orders)) + for(var/i in 1 to amount_queued) + var/datum/fabricator_build_order/order = make_order(recipe, multiplier) + queued_orders += order + + // Remove/earmark resources. + for(var/material in recipe.resources) + var/removed_mat = round(recipe.resources[material] * mat_efficiency) * multiplier + stored_material[material] = max(0, stored_material[material] - removed_mat) + order.earmarked_materials[material] = removed_mat + + if(!currently_building) + get_next_build() + else + start_building() + +//Allow storing more details in the order for fabricator subclasses +/obj/machinery/fabricator/proc/make_order(var/datum/fabricator_recipe/recipe, var/multiplier) var/datum/fabricator_build_order/order = new order.remaining_time = recipe.build_time order.target_recipe = recipe order.multiplier = multiplier - queued_orders += order + return order - // Remove/earmark resources. - for(var/material in recipe.resources) - var/removed_mat = round(recipe.resources[material] * mat_efficiency) * multiplier - stored_material[material] = max(0, stored_material[material] - removed_mat) - order.earmarked_materials[material] = removed_mat +//Override this to add more conditions to printing an object +/obj/machinery/fabricator/proc/can_build(var/datum/fabricator_recipe/recipe, var/multiplier) + return TRUE - if(!currently_building) - get_next_build() - else - start_building() \ No newline at end of file +#undef MAX_QUEUED_ORDERS \ No newline at end of file diff --git a/code/modules/fabrication/fabricator_food.dm b/code/modules/fabrication/fabricator_food.dm index 086832d7e684..cf6486e37019 100644 --- a/code/modules/fabrication/fabricator_food.dm +++ b/code/modules/fabrication/fabricator_food.dm @@ -5,28 +5,37 @@ icon = 'icons/obj/machines/fabricators/replicator.dmi' icon_state = "replicator" base_icon_state = "replicator" - has_recycler = FALSE - base_storage_capacity = list( - /decl/material/liquid/nutriment = 100 - ) + base_storage_capacity_mult = 5 + base_type = /obj/machinery/fabricator/replicator + +/obj/machinery/fabricator/replicator/Initialize() + . = ..() + global.listening_objects += src + +/obj/machinery/fabricator/replicator/Destroy() + global.listening_objects -= src + return ..() /obj/machinery/fabricator/replicator/hear_talk(var/mob/M, var/text, var/verb, var/decl/language/speaking) if(speaking && !speaking.machine_understands) return ..() var/true_text = lowertext(html_decode(text)) if(findtext(true_text, "status")) - addtimer(CALLBACK(src, /obj/machinery/fabricator/replicator/proc/state_status), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/fabricator/replicator, state_status)), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) else if(findtext(true_text, "menu")) - addtimer(CALLBACK(src, /obj/machinery/fabricator/replicator/proc/state_menu), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) - else + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/fabricator/replicator, state_menu)), 2 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + else for(var/datum/fabricator_recipe/recipe in design_cache) if(recipe.hidden && !(fab_status_flags & FAB_HACKED)) continue if(findtext(true_text, lowertext(recipe.name))) - addtimer(CALLBACK(src, /obj/machinery/fabricator/proc/try_queue_build, recipe, 1), 2 SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/fabricator, try_queue_build), recipe, 1), 2 SECONDS) break ..() +/obj/machinery/fabricator/replicator/can_ingest(var/obj/item/thing) + return istype(thing, /obj/item/food) || ..() + /obj/machinery/fabricator/replicator/proc/state_status() for(var/thing in storage_capacity) audible_message("\The [src] announces, \"[capitalize(thing)] storage at [(stored_material[thing]/storage_capacity[thing])*100]%!\"") diff --git a/code/modules/fabrication/fabricator_imprinter.dm b/code/modules/fabrication/fabricator_imprinter.dm index 7e959f285bad..09b2a1da36c6 100644 --- a/code/modules/fabrication/fabricator_imprinter.dm +++ b/code/modules/fabrication/fabricator_imprinter.dm @@ -8,12 +8,4 @@ active_power_usage = 2500 base_type = /obj/machinery/fabricator/imprinter fabricator_class = FABRICATOR_CLASS_IMPRINTER - base_storage_capacity = list( - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 50, - /decl/material/solid/metal/gold = SHEET_MATERIAL_AMOUNT * 50, - /decl/material/solid/metal/silver = SHEET_MATERIAL_AMOUNT * 50, - /decl/material/solid/gemstone/diamond = SHEET_MATERIAL_AMOUNT * 50, - /decl/material/liquid/acid = 120, - /decl/material/liquid/acid/hydrochloric = 120, - /decl/material/liquid/acid/polyacid = 120 - ) \ No newline at end of file + base_storage_capacity_mult = 50 diff --git a/code/modules/fabrication/fabricator_industrial.dm b/code/modules/fabrication/fabricator_industrial.dm index 253e2e3dcc8f..74c668283609 100644 --- a/code/modules/fabrication/fabricator_industrial.dm +++ b/code/modules/fabrication/fabricator_industrial.dm @@ -8,15 +8,5 @@ active_power_usage = 5000 base_type = /obj/machinery/fabricator/industrial fabricator_class = FABRICATOR_CLASS_INDUSTRIAL - base_storage_capacity = list( - /decl/material/solid/metal/steel = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/osmium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/aluminium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/gold = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/silver = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/uranium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/gemstone/diamond = SHEET_MATERIAL_AMOUNT * 100 - ) + base_storage_capacity_mult = 100 output_dir = EAST diff --git a/code/modules/fabrication/fabricator_intake.dm b/code/modules/fabrication/fabricator_intake.dm index 680e75741378..47ab2071e12c 100644 --- a/code/modules/fabrication/fabricator_intake.dm +++ b/code/modules/fabrication/fabricator_intake.dm @@ -6,22 +6,25 @@ /obj/machinery/fabricator/proc/take_reagents(var/obj/item/thing, var/mob/user, var/destructive = FALSE) if(!thing.reagents || (!destructive && !ATOM_IS_OPEN_CONTAINER(thing))) return SUBSTANCE_TAKEN_NONE - for(var/R in thing.reagents.reagent_volumes) - if(!base_storage_capacity[R]) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(thing.reagents)) + if(!base_storage_capacity[reagent.type]) continue - var/taking_reagent = min(REAGENT_VOLUME(thing.reagents, R), storage_capacity[R] - stored_material[R]) + var/taking_reagent = min(REAGENT_VOLUME(thing.reagents, reagent), floor((storage_capacity[reagent.type] - stored_material[reagent.type]) * REAGENT_UNITS_PER_MATERIAL_UNIT)) if(taking_reagent <= 0) continue - thing.reagents.remove_reagent(R, taking_reagent) - stored_material[R] += taking_reagent + var/reagent_matter = round(taking_reagent / REAGENT_UNITS_PER_MATERIAL_UNIT) + if(reagent_matter <= 0) + continue + thing.remove_from_reagents(reagent, taking_reagent) + stored_material[reagent.type] += reagent_matter // If we're destroying this, take everything. if(destructive) . = SUBSTANCE_TAKEN_ALL continue // Otherwise take the first applicable and useful reagent. - if(stored_material[R] == storage_capacity[R]) + if(stored_material[reagent.type] == storage_capacity[reagent.type]) return SUBSTANCE_TAKEN_FULL - else if(thing.reagents.total_volume > 0) + else if(REAGENT_TOTAL_VOLUME(thing.reagents) > 0) return SUBSTANCE_TAKEN_SOME else return SUBSTANCE_TAKEN_ALL @@ -29,101 +32,136 @@ /obj/machinery/fabricator/proc/take_materials(var/obj/item/thing, var/mob/user) . = SUBSTANCE_TAKEN_NONE - var/stacks_used = 1 + + var/obj/item/stack/stack_ref = istype(thing, /obj/item/stack) && thing + var/stack_matter_div = stack_ref ? max(1, ceil(SHEET_MATERIAL_AMOUNT * stack_ref.matter_multiplier)) : 1 + var/stacks_used = 0 + var/mat_colour = thing.color for(var/mat in thing.matter) - var/decl/material/material_def = decls_repository.get_decl(mat) - if(!material_def || !base_storage_capacity[material_def.type]) + + var/decl/material/ingest_material = GET_DECL(mat) + if(!ingest_material || !base_storage_capacity[mat]) continue - var/taking_material = min(thing.matter[mat], storage_capacity[material_def.type] - stored_material[material_def.type]) + + var/taking_material = min(thing.matter[mat], storage_capacity[mat] - stored_material[mat]) if(taking_material <= 0) continue + if(!mat_colour) - mat_colour = material_def.color - stored_material[material_def.type] += taking_material - stacks_used = max(stacks_used, ceil(taking_material/SHEET_MATERIAL_AMOUNT)) - if(storage_capacity[material_def.type] == stored_material[material_def.type]) + mat_colour = ingest_material.color + + stored_material[mat] += taking_material + if(stack_ref) + stacks_used = max(stacks_used, ceil(taking_material/stack_matter_div)) + + if(storage_capacity[mat] == stored_material[mat]) . = SUBSTANCE_TAKEN_FULL else if(. != SUBSTANCE_TAKEN_FULL) . = SUBSTANCE_TAKEN_ALL + if(. != SUBSTANCE_TAKEN_NONE) if(mat_colour) var/image/adding_mat_overlay = image(icon, "[base_icon_state]_mat") adding_mat_overlay.color = mat_colour material_overlays += adding_mat_overlay update_icon() - addtimer(CALLBACK(src, /obj/machinery/fabricator/proc/remove_mat_overlay, adding_mat_overlay), 1 SECOND) - if(istype(thing, /obj/item/stack)) - var/obj/item/stack/S = thing - S.use(stacks_used) - if(S.amount <= 0 || QDELETED(S)) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/fabricator, remove_mat_overlay), adding_mat_overlay), 1 SECOND) + + if(stack_ref && stacks_used) + stack_ref.use(stacks_used) + if(stack_ref.amount <= 0 || QDELETED(stack_ref)) . = SUBSTANCE_TAKEN_ALL else if(. != SUBSTANCE_TAKEN_FULL) . = SUBSTANCE_TAKEN_SOME -/obj/machinery/fabricator/proc/show_intake_message(var/mob/user, var/value, var/obj/item/thing) +/obj/machinery/fabricator/proc/can_ingest(var/obj/item/thing) + if(istype(thing, /obj/item/debris)) + return TRUE + var/obj/item/stack/material/stack = thing + return istype(stack) && !stack.reinf_material + +/obj/machinery/fabricator/proc/show_intake_message(var/mob/user, var/value, var/thing, var/took_reagents) if(value == SUBSTANCE_TAKEN_FULL) to_chat(user, SPAN_NOTICE("You fill \the [src] to capacity with \the [thing].")) else if(value == SUBSTANCE_TAKEN_SOME) to_chat(user, SPAN_NOTICE("You fill \the [src] from \the [thing].")) else if(value == SUBSTANCE_TAKEN_ALL) - to_chat(user, SPAN_NOTICE("You dump \the [thing] into \the [src].")) + to_chat(user, SPAN_NOTICE("You [took_reagents ? "empty" : "dump"] \the [thing] into \the [src].")) else to_chat(user, SPAN_WARNING("\The [src] cannot process \the [thing].")) -/obj/machinery/fabricator/attackby(var/obj/item/O, var/mob/user) - if(component_attackby(O, user)) - return TRUE - if(panel_open && (isMultitool(O) || isWirecutter(O))) - attack_hand(user) +/obj/machinery/fabricator/attackby(var/obj/item/used_item, var/mob/user) + if((. = component_attackby(used_item, user))) + return + if(panel_open && (IS_MULTITOOL(used_item) || IS_WIRECUTTER(used_item))) + attack_hand_with_interaction_checks(user) return TRUE - if((obj_flags & OBJ_FLAG_ANCHORABLE) && isWrench(O)) + if((obj_flags & OBJ_FLAG_ANCHORABLE) && (IS_WRENCH(used_item) || IS_HAMMER(used_item))) return ..() if(stat & (NOPOWER | BROKEN)) - return + return TRUE // Gate some simple interactions beind intent so people can still feed lathes disks. - if(user.a_intent != I_HURT) + if(!user.check_intent(I_FLAG_HARM)) // Set or update our local network. - if(isMultitool(O)) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/fabnet = get_extension(src, /datum/extension/local_network_member) fabnet.get_new_tag(user) - return + return TRUE // Install new designs. - if(istype(O, /obj/item/disk/design_disk)) - var/obj/item/disk/design_disk/disk = O + if(istype(used_item, /obj/item/disk/design_disk)) + var/obj/item/disk/design_disk/disk = used_item if(!disk.blueprint) - to_chat(usr, SPAN_WARNING("\The [O] is blank.")) - return + to_chat(user, SPAN_WARNING("\The [used_item] is blank.")) + return TRUE if(disk.blueprint in installed_designs) - to_chat(usr, SPAN_WARNING("\The [src] is already loaded with the blueprint stored on \the [O].")) - return + to_chat(user, SPAN_WARNING("\The [src] is already loaded with the blueprint stored on \the [used_item].")) + return TRUE installed_designs += disk.blueprint design_cache |= disk.blueprint - visible_message(SPAN_NOTICE("\The [user] inserts \the [O] into \the [src], and after a second or so of loud clicking, the fabricator beeps and spits it out again.")) - return + visible_message(SPAN_NOTICE("\The [user] inserts \the [used_item] into \the [src], and after a second or so of loud clicking, the fabricator beeps and spits it out again.")) + return TRUE + + // Attempt to bash on harm intent. + // I'd like for this to be a more general parent call but instead it's just a direct check-and-call. + else if(!(used_item.item_flags & ITEM_FLAG_NO_BLUDGEON) && (. = bash(used_item, user))) // Bash successful, no need to try intake. + return + + // TEMP HACK FIX: + // Autolathes currently do not process atom contents. As a workaround, refuse all atoms with contents. + if(length(used_item.contents) && !ignore_input_contents_length) + to_chat(user, SPAN_WARNING("\The [src] cannot process an object containing other objects. Empty it out first.")) + return TRUE + // REMOVE FIX WHEN LATHES TAKE CONTENTS PLS. // Take reagents, if any are applicable. - var/reagents_taken = take_reagents(O, user) - if(reagents_taken != SUBSTANCE_TAKEN_NONE && !has_recycler) - show_intake_message(user, reagents_taken, O) + var/atom_name = used_item.name + var/reagents_taken = take_reagents(used_item, user) + if(reagents_taken != SUBSTANCE_TAKEN_NONE) + show_intake_message(user, reagents_taken, atom_name, took_reagents = TRUE) updateUsrDialog() return TRUE + + if(!can_ingest(used_item)) + to_chat(user, SPAN_WARNING("\The [src] cannot process \the [used_item].")) + return TRUE + // Take everything if we have a recycler. - if(has_recycler && !is_robot_module(O) && user.unEquip(O)) - var/result = max(take_materials(O, user), max(reagents_taken, take_reagents(O, user, TRUE))) - show_intake_message(user, result, O) + if(!is_robot_module(used_item) && user.try_unequip(used_item)) + var/result = max(take_materials(used_item, user), max(reagents_taken, take_reagents(used_item, user, TRUE))) + show_intake_message(user, result, atom_name) if(result == SUBSTANCE_TAKEN_NONE) - user.put_in_active_hand(O) + user.put_in_active_hand(used_item) return TRUE - if(istype(O, /obj/item/stack)) - var/obj/item/stack/stack = O + if(istype(used_item, /obj/item/stack)) + var/obj/item/stack/stack = used_item if(!QDELETED(stack) && stack.amount > 0) user.put_in_active_hand(stack) else - qdel(O) + qdel(used_item) updateUsrDialog() return TRUE . = ..() @@ -132,10 +170,11 @@ if(fab_status_flags & FAB_SHOCKED) shock(user, 50) return TRUE + return FALSE /obj/machinery/fabricator/interface_interact(mob/user) if((fab_status_flags & FAB_DISABLED) && !panel_open) to_chat(user, SPAN_WARNING("\The [src] is disabled!")) return TRUE - interact(user) + ui_interact(user) return TRUE \ No newline at end of file diff --git a/code/modules/fabrication/fabricator_microlathe.dm b/code/modules/fabrication/fabricator_microlathe.dm index 0d17d230192e..9d550a926354 100644 --- a/code/modules/fabrication/fabricator_microlathe.dm +++ b/code/modules/fabrication/fabricator_microlathe.dm @@ -8,16 +8,9 @@ active_power_usage = 1000 base_type = /obj/machinery/fabricator/micro fabricator_class = FABRICATOR_CLASS_MICRO - base_storage_capacity = list( - /decl/material/solid/metal/aluminium = SHEET_MATERIAL_AMOUNT * 5, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 5, - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 5 - ) + base_storage_capacity_mult = 5 -//Subtype for mapping, starts preloaded with glass and set to print glasses +//Subtype for mapping, starts preloaded and set to print glasses /obj/machinery/fabricator/micro/bartender show_category = "Drinking Glasses" - -/obj/machinery/fabricator/micro/bartender/Initialize() - . = ..() - stored_material[/decl/material/solid/glass] = base_storage_capacity[/decl/material/solid/glass] \ No newline at end of file + prefilled = TRUE diff --git a/code/modules/fabrication/fabricator_pipe.dm b/code/modules/fabrication/fabricator_pipe.dm index 760b4c94f031..92b988cb55aa 100644 --- a/code/modules/fabrication/fabricator_pipe.dm +++ b/code/modules/fabrication/fabricator_pipe.dm @@ -7,18 +7,19 @@ base_type = /obj/machinery/fabricator/pipe stat_immune = NOSCREEN//Doesn't need screen, just input for the parts wanted power_channel = EQUIP - anchored = 0 + anchored = FALSE use_power = POWER_USE_OFF color_selectable = TRUE /obj/machinery/fabricator/pipe/on_update_icon() + return // no icons /obj/machinery/fabricator/pipe/CanUseTopic(mob/user) if(!anchored) return STATUS_CLOSE return ..() - -/obj/machinery/fabricator/pipe/wrench_floor_bolts() + +/obj/machinery/fabricator/pipe/wrench_floor_bolts(mob/user, delay = 2 SECONDS, obj/item/tool) ..() update_use_power(anchored ? POWER_USE_IDLE : POWER_USE_OFF) @@ -32,10 +33,15 @@ // Pipe objects do not contain matter, and will not provide a refund on materials used to make them, but can be recycled to prevent clutter. if(istype(thing, /obj/item/pipe) && (. == SUBSTANCE_TAKEN_NONE)) return SUBSTANCE_TAKEN_ALL - -/obj/machinery/fabricator/pipe/do_build(var/datum/fabricator_recipe/recipe, var/amount) - . = recipe.build(get_turf(src), amount, pipe_colors[selected_color]) - use_power_oneoff(500 * amount) + +/obj/machinery/fabricator/pipe/make_order(datum/fabricator_recipe/recipe, multiplier) + var/datum/fabricator_build_order/order = ..() + order.set_data("selected_color", selected_color) + return order + +/obj/machinery/fabricator/pipe/do_build(datum/fabricator_build_order/order) + . = order.target_recipe.build(get_turf(src), order) + use_power_oneoff(500 * order.multiplier) /obj/machinery/fabricator/pipe/disposal name = "disposal pipe dispenser" @@ -45,14 +51,8 @@ base_type = /obj/machinery/fabricator/pipe/disposal //Allow you to drag-drop disposal pipes into it -/obj/machinery/fabricator/pipe/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe, mob/user) - if(!CanPhysicallyInteract(user)) - return - - if (!istype(pipe) || get_dist(src,pipe) > 1 ) - return - - if (pipe.anchored) - return - - qdel(pipe) \ No newline at end of file +/obj/machinery/fabricator/pipe/disposal/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && istype(dropping, /obj/structure/disposalconstruct)) + qdel(dropping) + return TRUE diff --git a/code/modules/fabrication/fabricator_presets.dm b/code/modules/fabrication/fabricator_presets.dm new file mode 100644 index 000000000000..44d4ac711d5f --- /dev/null +++ b/code/modules/fabrication/fabricator_presets.dm @@ -0,0 +1,32 @@ +/obj/machinery/fabricator/filled + prefilled = TRUE + +/obj/machinery/fabricator/micro/filled + prefilled = TRUE + +/obj/machinery/fabricator/book/filled + prefilled = TRUE + +/obj/machinery/fabricator/imprinter/filled + prefilled = TRUE + +/obj/machinery/fabricator/industrial/filled + prefilled = TRUE + +/obj/machinery/fabricator/pipe/filled + prefilled = TRUE + +/obj/machinery/fabricator/pipe/disposal/filled + prefilled = TRUE + +/obj/machinery/fabricator/protolathe/filled + prefilled = TRUE + +/obj/machinery/fabricator/robotics/filled + prefilled = TRUE + +/obj/machinery/fabricator/textile/filled + prefilled = TRUE + +/obj/machinery/fabricator/bioprinter/filled + prefilled = TRUE \ No newline at end of file diff --git a/code/modules/fabrication/fabricator_protolathe.dm b/code/modules/fabrication/fabricator_protolathe.dm index 9ca13bc3a453..4466b9efc7b6 100644 --- a/code/modules/fabrication/fabricator_protolathe.dm +++ b/code/modules/fabrication/fabricator_protolathe.dm @@ -8,13 +8,4 @@ active_power_usage = 5000 base_type = /obj/machinery/fabricator/protolathe fabricator_class = FABRICATOR_CLASS_PROTOLATHE - base_storage_capacity = list( - /decl/material/solid/metal/steel = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/aluminium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/gold = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/silver = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/uranium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/gemstone/diamond = SHEET_MATERIAL_AMOUNT * 100 - ) \ No newline at end of file + base_storage_capacity_mult = 100 diff --git a/code/modules/fabrication/fabricator_robotics.dm b/code/modules/fabrication/fabricator_robotics.dm index 7eabdf55e70a..edeb76757856 100644 --- a/code/modules/fabrication/fabricator_robotics.dm +++ b/code/modules/fabrication/fabricator_robotics.dm @@ -8,13 +8,30 @@ active_power_usage = 5000 base_type = /obj/machinery/fabricator/robotics fabricator_class = FABRICATOR_CLASS_ROBOTICS - base_storage_capacity = list( - /decl/material/solid/metal/steel = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/aluminium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/gold = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/silver = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/uranium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/gemstone/diamond = SHEET_MATERIAL_AMOUNT * 100 - ) \ No newline at end of file + base_storage_capacity_mult = 100 + var/picked_prosthetic_species //Prosthetics will be printed with this species + +/obj/machinery/fabricator/robotics/Initialize() + . = ..() + picked_prosthetic_species = global.using_map?.default_species //Set it by default to the base species to preserve earlier behavior for now + +/obj/machinery/fabricator/robotics/make_order(datum/fabricator_recipe/recipe, multiplier) + var/datum/fabricator_build_order/order = ..() + order.set_data("species", picked_prosthetic_species) + return order + + +/obj/machinery/fabricator/robotics/OnTopic(user, href_list, state) + . = ..() + if(href_list["pick_species"]) + var/chosen_species = input(user, "Choose a species to produce prosthetics for", "Target Species", null) in get_playable_species() + if(chosen_species) + picked_prosthetic_species = chosen_species + . = TOPIC_REFRESH + +/obj/machinery/fabricator/robotics/ui_data(mob/user, ui_key) + . = ..() + LAZYSET(., "species", picked_prosthetic_species) + +/obj/machinery/fabricator/robotics/get_nano_template() + return "fabricator_robot.tmpl" diff --git a/code/modules/fabrication/fabricator_textile.dm b/code/modules/fabrication/fabricator_textile.dm index 9626b1a10dd7..b22c95167bda 100644 --- a/code/modules/fabrication/fabricator_textile.dm +++ b/code/modules/fabrication/fabricator_textile.dm @@ -8,13 +8,9 @@ active_power_usage = 5000 base_type = /obj/machinery/fabricator/textile fabricator_class = FABRICATOR_CLASS_TEXTILE - base_storage_capacity = list( - /decl/material/solid/metal/steel = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/aluminium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/plastic = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/glass = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/gold = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/silver = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/metal/uranium = SHEET_MATERIAL_AMOUNT * 100, - /decl/material/solid/gemstone/diamond = SHEET_MATERIAL_AMOUNT * 100 - ) \ No newline at end of file + base_storage_capacity_mult = 100 + +/obj/machinery/fabricator/textile/can_ingest(var/obj/item/thing) + if(thing.has_textile_fibers()) // only raw cotton plants currently + return TRUE + return ..() diff --git a/code/modules/fabrication/fabricator_topic.dm b/code/modules/fabrication/fabricator_topic.dm index 155463a4fdd6..3d852b0f4bf8 100644 --- a/code/modules/fabrication/fabricator_topic.dm +++ b/code/modules/fabrication/fabricator_topic.dm @@ -5,16 +5,22 @@ return TOPIC_HANDLED show_category = choice . = TOPIC_REFRESH - else if(href_list["make"]) + + if(href_list["make"]) try_queue_build(locate(href_list["make"]), text2num(href_list["multiplier"])) . = TOPIC_REFRESH - else if(href_list["cancel"]) + + if(href_list["cancel"]) try_cancel_build(locate(href_list["cancel"])) . = TOPIC_REFRESH - else if(href_list["eject_mat"]) - try_dump_material(href_list["eject_mat"]) - . = TOPIC_REFRESH - else if(href_list["settings"]) + + if(href_list["eject_mat"]) + var/decl/material/mat = locate(href_list["eject_mat"]) + if(istype(mat)) + try_dump_material(mat.type) + . = TOPIC_REFRESH + + if(href_list["network_settings"]) var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) D.ui_interact(user) . = TOPIC_REFRESH @@ -28,7 +34,24 @@ if(!choice) return TOPIC_HANDLED selected_color = choice - return TOPIC_REFRESH + . = TOPIC_REFRESH + + if(href_list["set_filter"]) + var/new_filter_string = sanitize(input(user, "Enter a new filter string.", "Fabricator Filter") as text|null) + if(CanInteract(user, DefaultTopicState())) + filter_string = new_filter_string + . = TOPIC_REFRESH + + //Tab expanding/collapsing + if(href_list["toggle_resources"]) + ui_expand_resources = !ui_expand_resources + . = TOPIC_REFRESH + if(href_list["toggle_queue"]) + ui_expand_queue = !ui_expand_queue + . = TOPIC_REFRESH + if(href_list["toggle_config"]) + ui_expand_config = !ui_expand_config + . = TOPIC_REFRESH /obj/machinery/fabricator/proc/try_cancel_build(var/datum/fabricator_build_order/order) if(istype(order) && currently_building != order && is_functioning()) @@ -39,15 +62,15 @@ queued_orders -= order qdel(order) -/obj/machinery/fabricator/proc/try_dump_material(var/mat_name) - mat_name = lowertext(mat_name) - for(var/mat_path in stored_substances_to_names) - if(stored_substances_to_names[mat_path] == mat_name) - if(ispath(mat_path, /decl/material)) - var/decl/material/mat = decls_repository.get_decl(mat_path) - if(mat && stored_material[mat_path] > SHEET_MATERIAL_AMOUNT && mat.stack_type) - var/sheet_count = Floor(stored_material[mat_path]/SHEET_MATERIAL_AMOUNT) - stored_material[mat_path] -= sheet_count * SHEET_MATERIAL_AMOUNT - mat.place_sheet(get_turf(src), sheet_count) - else if(!isnull(stored_material[mat_path])) - stored_material[mat_path] = 0 +/obj/machinery/fabricator/proc/try_dump_material(var/mat_path) + if(!mat_path || !stored_material[mat_path]) + return + // TODO: proper liquid reagent ejection checks (acid sheet ejection...). + var/decl/material/mat = GET_DECL(mat_path) + if(mat?.phase_at_temperature() != MAT_PHASE_SOLID) + stored_material[mat_path] = 0 + else + var/sheet_count = floor(stored_material[mat_path]/SHEET_MATERIAL_AMOUNT) + if(sheet_count >= 1) + stored_material[mat_path] -= sheet_count * SHEET_MATERIAL_AMOUNT + SSmaterials.create_object(mat_path, get_turf(src), sheet_count) diff --git a/code/modules/fabrication/fabricator_ui.dm b/code/modules/fabrication/fabricator_ui.dm index a419386df335..78069693e740 100644 --- a/code/modules/fabrication/fabricator_ui.dm +++ b/code/modules/fabrication/fabricator_ui.dm @@ -1,95 +1,209 @@ #define PRINT_MULTIPLIER_DIVISOR 5 -/obj/machinery/fabricator/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) - var/list/data = list() +//Allows overriding the default window size of the fabricator +/obj/machinery/fabricator/proc/get_fabricator_window_size() + return list("x" = 480, "y" = 410) + +//Can be overriden to use a different nano template file +/obj/machinery/fabricator/proc/get_nano_template() + return "fabricator.tmpl" + +//Returns a list of templates with the format "name" = "file.tmpl" to be loaded in addition to the main template. Name is used to access in the tmpl files. +/obj/machinery/fabricator/proc/get_extra_templates() + return list( + "net_shared" = "network_shared.tmpl", //Shared network UI stuff + "fab_shared" = "fabricator_shared.tmpl", //fab_shared should be included in all fabricator templates + ) + +/obj/machinery/fabricator/proc/ui_fabricator_resource_data() + var/material_storage = list() + for(var/material in storage_capacity) + var/decl/material/mat = GET_DECL(material) + var/list/material_data = list() + var/is_solid = (mat.phase_at_temperature() == MAT_PHASE_SOLID) + material_data["name"] = capitalize(mat.use_name) + material_data["stored"] = stored_material[material] ? stored_material[material] : 0 + material_data["max"] = storage_capacity[material] + material_data["unit"] = is_solid ? SHEET_UNIT : "ml" + material_data["eject_key"] = "\ref[mat]" + material_storage += list(material_data) + return material_storage + +/obj/machinery/fabricator/proc/ui_fabricator_current_build_data() + var/list/current_build + if(currently_building) + current_build = list() + current_build["name"] = currently_building.target_recipe.name + current_build["multiplier"] = currently_building.multiplier + current_build["progress"] = "[100-round((currently_building.remaining_time/currently_building.target_recipe.build_time)*100)]%" + return current_build + +/obj/machinery/fabricator/proc/ui_fabricator_build_queue_data() + var/list/build_queue + for(var/datum/fabricator_build_order/order in queued_orders) + LAZYADD(build_queue, list(ui_fabricator_build_queue_entry_data(order))) + return build_queue + +/obj/machinery/fabricator/proc/ui_fabricator_build_queue_entry_data(var/datum/fabricator_build_order/order) + var/list/order_data + if(order) + order_data = list() + order_data["name"] = order.target_recipe.name + order_data["multiplier"] = order.multiplier + order_data["reference"] = "\ref[order]" + return order_data + +//Fill out the data for the displayed buildable designs +/obj/machinery/fabricator/proc/ui_fabricator_build_options_data() + var/list/build_options + for(var/datum/fabricator_recipe/R in design_cache) + if(!R.is_available_to_fab(src)) + continue + if(R.hidden && !(fab_status_flags & FAB_HACKED)) + continue + if(show_category != "All" && show_category != R.category) + continue + if(filter_string && !findtextEx_char(lowertext(R.name), lowertext(filter_string))) + continue + LAZYADD(build_options, list(ui_fabricator_build_option_entry_data(R))) + return build_options + +//Fill out the data for a single build option +/obj/machinery/fabricator/proc/ui_fabricator_build_option_entry_data(var/datum/fabricator_recipe/R) + var/list/build_option = list() + var/list/material_costs = ui_fabricator_build_option_cost_list(R) + var/max_sheets + build_option["name"] = R.name + build_option["reference"] = "\ref[R]" + build_option["illegal"] = R.hidden + + if(material_costs) + max_sheets = material_costs["max_sheets"] + build_option["unavailable"] = !(material_costs["available"]) + var/list/mats = material_costs["materials"] + build_option["materials"] = length(mats) > 0? mats : null + + build_option["multiplier"] = ui_fabricator_build_option_entry_multiplier_data(R, max_sheets) + return build_option + +//Returns a list containing a boolean "available" to determine if we can build the recipe, and a list of resources costs () +/obj/machinery/fabricator/proc/ui_fabricator_build_option_cost_list(var/datum/fabricator_recipe/R) + //Make sure it's buildable and list required resources. + var/list/material_components = list() + + var/max_sheets = (!length(R.resources)) ? 100 : null + var/has_missing_resource = FALSE + for(var/material_path in R.resources) + + var/required_amount = round(R.resources[material_path] * mat_efficiency) + var/sheets = round(stored_material[material_path] / required_amount) + var/has_enough = TRUE + + var/decl/material/mat = GET_DECL(material_path) + + if(isnull(max_sheets) || max_sheets > sheets) + max_sheets = sheets + if(stored_material[material_path] < required_amount) + has_missing_resource = TRUE + has_enough = FALSE + + //Must make it a double list here or the fields are just overwriting eachothers + material_components += list(list( + "name" = capitalize(mat.use_name), + "amount" = required_amount, + "has_enough" = has_enough, + )) + return list("available" = !has_missing_resource && ui_fabricator_build_option_is_available(R, max_sheets), "max_sheets" = max_sheets, "materials" = material_components) +//Override to add more checks to make a build option unavailable. EX: if the machine requires a setting to be set first +/obj/machinery/fabricator/proc/ui_fabricator_build_option_is_available(var/datum/fabricator_recipe/R, var/max_sheets) + return TRUE + +/obj/machinery/fabricator/proc/ui_fabricator_build_option_entry_multiplier_data(var/datum/fabricator_recipe/R, var/max_sheets) + var/list/multiplier + if(R.max_amount >= PRINT_MULTIPLIER_DIVISOR && max_sheets >= PRINT_MULTIPLIER_DIVISOR) + multiplier = list() + for(var/i = 1 to floor(min(R.max_amount, max_sheets)/PRINT_MULTIPLIER_DIVISOR)) + var/mult = i * PRINT_MULTIPLIER_DIVISOR + multiplier += list(list("label" = "x[mult]", "multiplier" = mult)) + return multiplier + +// +// UI sections data +// +/obj/machinery/fabricator/ui_data(mob/user, ui_key) + var/list/data = ..() + //Common fab data + data += ui_data_status(user, ui_key) //status is still displayed when not working for convenience + if(is_functioning()) + data += ui_data_resources(user, ui_key) + data += ui_data_queue(user, ui_key) + data += ui_data_config(user, ui_key) + data += ui_data_filter(user, ui_key) + data += ui_data_build_options(user, ui_key) + return data + +/obj/machinery/fabricator/proc/ui_data_status(mob/user, ui_key) + var/list/data = list() var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) - data["network"] = D.network_tag - data["category"] = show_category + data["network"] = (D.network_id && D.network_tag) + data["network_id"] = D.network_id data["functional"] = is_functioning() + return data - if(is_functioning()) - data["color_selectable"] = color_selectable - data["color"] = selected_color - - var/current_storage = list() - data["material_storage"] = current_storage - for(var/material in stored_material) - var/list/material_data = list() - var/mat_name = capitalize(stored_substances_to_names[material]) - material_data["name"] = mat_name - material_data["stored"] = "[stored_material[material]][SHEET_UNIT]" - material_data["max"] = storage_capacity[material] - material_data["eject_key"] = stored_substances_to_names[material] - material_data["eject_label"] = ispath(material, /decl/material) ? "Eject" : "Flush" - data["material_storage"] += list(material_data) - - var/list/current_build = list() - data["current_build"] = current_build - if(currently_building) - current_build["name"] = currently_building.target_recipe.name - current_build["multiplier"] = currently_building.multiplier - current_build["progress"] = "[100-round((currently_building.remaining_time/currently_building.target_recipe.build_time)*100)]%" - else - current_build["name"] = "Nothing." - current_build["multiplier"] = "-" - current_build["progress"] = "-" - - data["build_queue"] = list() - if(length(queued_orders)) - for(var/datum/fabricator_build_order/order in queued_orders) - var/list/order_data = list() - order_data["name"] = order.target_recipe.name - order_data["multiplier"] = order.multiplier - order_data["reference"] = "\ref[order]" - data["build_queue"] += list(order_data) - else - var/list/order_data = list() - order_data["name"] = "Nothing." - order_data["multiplier"] = "-" - data["build_queue"] += list(order_data) - - data["build_options"] = list() - for(var/datum/fabricator_recipe/R in design_cache) - if(R.hidden && !(fab_status_flags & FAB_HACKED)) - continue - if(show_category != "All" && show_category != R.category) - continue - var/list/build_option = list() - var/max_sheets = 0 - build_option["name"] = R.name - build_option["reference"] = "\ref[R]" - build_option["illegal"] = R.hidden - if(!length(R.resources)) - build_option["cost"] = "No resources required." - max_sheets = 100 - else - //Make sure it's buildable and list required resources. - var/list/material_components = list() - for(var/material in R.resources) - var/sheets = round(stored_material[material]/round(R.resources[material]*mat_efficiency)) - if(isnull(max_sheets) || max_sheets > sheets) - max_sheets = sheets - if(stored_material[material] < round(R.resources[material]*mat_efficiency)) - build_option["unavailable"] = 1 - material_components += "[round(R.resources[material] * mat_efficiency)][SHEET_UNIT] [stored_substances_to_names[material]]" - build_option["cost"] = "[capitalize(jointext(material_components, ", "))]." - if(R.max_amount >= PRINT_MULTIPLIER_DIVISOR && max_sheets >= PRINT_MULTIPLIER_DIVISOR) - build_option["multiplier"] = list() - for(var/i = 1 to Floor(min(R.max_amount, max_sheets)/PRINT_MULTIPLIER_DIVISOR)) - var/mult = i * PRINT_MULTIPLIER_DIVISOR - build_option["multiplier"] += list(list("label" = "x[mult]", "multiplier" = mult)) - data["build_options"] += list(build_option) +/obj/machinery/fabricator/proc/ui_data_resources(mob/user, ui_key) + var/list/data = list() + data["expand_resources"] = ui_expand_resources + data["material_storage"] = ui_fabricator_resource_data() + return data + +/obj/machinery/fabricator/proc/ui_data_queue(mob/user, ui_key) + var/list/data = list() + data["expand_queue"] = ui_expand_queue + data["current_build"] = ui_fabricator_current_build_data() + data["build_queue"] = ui_fabricator_build_queue_data() + return data +//Handles populating config data, meant to be overriden +/obj/machinery/fabricator/proc/ui_data_config(mob/user, ui_key) + var/list/data = list() + data["expand_config"] = ui_expand_config + data["skip_config"] = !ui_draw_config(user, ui_key) //Setting this to true just skip over drawing the config tab completely when its empty + data["color_selectable"] = color_selectable + data["color"] = selected_color + return data + +/obj/machinery/fabricator/proc/ui_data_filter(mob/user, ui_key) + var/list/data = list() + data["category"] = show_category + data["filtering"] = filter_string || "No filter set." + data["hide_categories"] = ui_nb_categories <= 1 //Only show categories if we have more than one category of things + return data + +/obj/machinery/fabricator/proc/ui_data_build_options(mob/user, ui_key) + var/list/data = list() + data["build_options"] = ui_fabricator_build_options_data() + return data + +//Shouldn't need to override this in subclasses. +/obj/machinery/fabricator/ui_interact(mob/user, ui_key = "fab", datum/nanoui/ui=null, force_open=1, var/master_ui = null, var/datum/topic_state/state = global.default_topic_state) + var/list/data = ui_data(user, ui_key) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "fabricator.tmpl", "[capitalize(name)]", 480, 410, state = GLOB.physical_state) + var/list/window_size = get_fabricator_window_size() + ui = new(user, src, ui_key, get_nano_template(), "[capitalize(name)]", window_size["x"], window_size["y"], state = state) ui.set_initial_data(data) + + //Add extra templates + var/list/extratemplates = get_extra_templates() + for(var/key in extratemplates) + ui.add_template(key, extratemplates[key]) + ui.open() - ui.set_auto_update(1) + ui.set_auto_update(TRUE) -/obj/machinery/fabricator/interface_interact(mob/user) - ui_interact(user) - return TRUE +//Returns whether we should bother drawing the config tab. Meant to be overriden +/obj/machinery/fabricator/proc/ui_draw_config(mob/user, ui_key) + return color_selectable //Only if we can pick a color by default #undef PRINT_MULTIPLIER_DIVISOR \ No newline at end of file diff --git a/code/modules/fabrication/recycler.dm b/code/modules/fabrication/recycler.dm new file mode 100644 index 000000000000..10ab9407a954 --- /dev/null +++ b/code/modules/fabrication/recycler.dm @@ -0,0 +1,192 @@ +/obj/machinery/recycler + name = "recycler" + desc = "An advanced machine that breaks objects down into their constitute material. Click and drag it onto yourself to open the hopper." + density = TRUE + anchored = TRUE + icon = 'icons/obj/machines/recycler.dmi' + icon_state = "recycler" + idle_power_usage = 10 + active_power_usage = 2000 + clicksound = "keyboard" + clickvol = 30 + uncreated_component_parts = null + stat_immune = 0 +// wires = /datum/wires/recycler // No idea what wires should do for a recycler. + base_type = /obj/machinery/recycler + construct_state = /decl/machine_construction/default/panel_closed + storage = /datum/storage/hopper/industrial + + var/recycling_efficiency = 0.65 + var/created_stack_type = /obj/item/stack/material/cubes + var/list/trace_matter = list() + + // Stolen from fabricators. + var/sound_id + var/datum/sound_token/sound_token + var/work_sound = 'sound/machines/fabricator_loop.ogg' + +/obj/machinery/recycler/Initialize() + sound_id = "[work_sound]" + return ..() + +/obj/machinery/recycler/Destroy() + QDEL_NULL(sound_token) + return ..() + +/obj/machinery/recycler/update_use_power() + . = ..() + if(use_power == POWER_USE_ACTIVE) + if(!sound_token) + sound_token = play_looping_sound(src, sound_id, work_sound, volume = 30) + else + dump_trace_material() + QDEL_NULL(sound_token) + +/obj/machinery/recycler/Process(wait, tick) + ..() + if(use_power != POWER_USE_ACTIVE) + return + + var/list/processing_items = get_stored_inventory() + if(!length(processing_items)) + visible_message("\The [src] disengages with a low clunk.") + update_use_power(POWER_USE_IDLE) + return + + // Combine our current leftover matter with an item to munch. + // Trace matter will get written back if left over. + var/obj/munching = processing_items[1] + var/list/fell_out = list() + for(var/obj/item/thing in munching.get_contained_external_atoms()) + thing.dropInto(loc) + fell_out += thing + + var/list/munched_matter = munching.get_contained_matter() + for(var/mat in munched_matter) + // Lose some matter in the process of recycling. + munched_matter[mat] = max(1, round(munched_matter[mat] * recycling_efficiency)) + // Add trace matter back in for this pass. + if(trace_matter[mat]) + munched_matter[mat] += trace_matter[mat] + trace_matter -= mat + munching.clear_matter() + qdel(munching) + + for(var/obj/item/thing in fell_out) + if(QDELETED(thing)) + fell_out -= thing + else if(storage?.can_be_inserted(thing)) + fell_out -= thing + storage.handle_item_insertion(null, thing) + + if(length(fell_out)) + visible_message("[capitalize(english_list(fell_out))] fall out of \the overflowing [src]!") + + for(var/mat in munched_matter) + var/decl/material/munched_material = GET_DECL(mat) + switch(munched_material.phase_at_temperature()) + if(MAT_PHASE_SOLID) + + // Dump the material out as a stack. + var/obj/item/stack/material/cubestack = created_stack_type + var/max_stack = initial(cubestack.max_amount) + var/stack_amount = floor(munched_matter[mat] / SHEET_MATERIAL_AMOUNT) + + // Keep track of any trace matter for the next run. + munched_matter[mat] -= stack_amount * SHEET_MATERIAL_AMOUNT + + while(stack_amount >= max_stack) + stack_amount -= max_stack + new created_stack_type(get_turf(src), max_stack, mat) + if(stack_amount > 0) + var/obj/item/stack/last_stack = new created_stack_type(get_turf(src), stack_amount, mat) + last_stack.add_to_stacks() + + if(MAT_PHASE_LIQUID) + // TODO: dump to a reagent container. + munched_matter -= mat + continue + if(MAT_PHASE_GAS) + // TODO: dump to a gas container. + munched_matter -= mat + continue + + if(munched_matter[mat] > 0) + trace_matter[mat] += munched_matter[mat] * recycling_efficiency + +/obj/machinery/recycler/attackby(obj/item/used_item, mob/user) + + if(use_power == POWER_USE_ACTIVE) + to_chat(user, SPAN_WARNING("\The [src] is currently processing, please wait for it to finish.")) + return TRUE + + if(used_item.storage && !user.check_intent(I_FLAG_HARM)) + + var/emptied = FALSE + for(var/obj/item/O in used_item.get_stored_inventory()) + if(storage.can_be_inserted(O)) + used_item.storage.remove_from_storage(null, O, loc, skip_update = TRUE) + storage.handle_item_insertion(null, O, skip_update = TRUE) + emptied = TRUE + + if(emptied) + used_item.storage.finish_bulk_removal() + storage.update_ui_after_item_insertion() + if(length(used_item.get_stored_inventory())) + to_chat(user, SPAN_NOTICE("You partially empty \the [used_item] into \the [src]'s hopper.")) + else + to_chat(user, SPAN_NOTICE("You empty \the [used_item] into \the [src]'s hopper.")) + used_item.update_icon() + return TRUE + + // Parent call so we can interact with the machinery aspect + // People can use the mousedrop storage UI to put wrenches and screwdrivers into the hopper if needed. + . = ..() + +/obj/machinery/recycler/on_update_icon() + icon_state = initial(icon_state) + if(use_power == POWER_USE_OFF || !operable()) + icon_state = "[icon_state]_d" + else if(use_power == POWER_USE_ACTIVE) + icon_state = "[icon_state]_p" + +/obj/machinery/recycler/attack_hand(mob/user) + if(use_power == POWER_USE_ACTIVE) + user.visible_message("\The [user] disengages \the [src].") + update_use_power(POWER_USE_IDLE) + return TRUE + if(use_power == POWER_USE_IDLE) + if(length(get_stored_inventory())) + user.visible_message("\The [user] engages \the [src].") + update_use_power(POWER_USE_ACTIVE) + else + to_chat(user, SPAN_WARNING("\The [src]'s hopper is empty.")) + return TRUE + if(use_power == POWER_USE_OFF || !operable()) + to_chat(user, SPAN_WARNING("\The [src]'s interface is unresponsive.")) + return TRUE + return ..() + +/obj/machinery/recycler/proc/dump_trace_material(atom/forced_loc = loc) + + if(!length(trace_matter)) + return + + var/obj/item/debris/scraps/remains = new(forced_loc) + remains.matter = trace_matter?.Copy() + remains.update_primary_material() + trace_matter.Cut() + +/obj/machinery/recycler/dump_contents(atom/forced_loc = loc, mob/user) + dump_trace_material(forced_loc) + return ..() + +/obj/machinery/recycler/RefreshParts() + ..() + var/efficiency_rating = total_component_rating_of_type(/obj/item/stock_parts/manipulator) + total_component_rating_of_type(/obj/item/stock_parts/micro_laser) + // 5% better return for each rating level. + recycling_efficiency = clamp(initial(recycling_efficiency) + efficiency_rating * 0.05, 0, 0.95) + // equivalent of one box per matter bin rating level. + var/storage_rating = total_component_rating_of_type(/obj/item/stock_parts/matter_bin) + storage.max_storage_space = initial(storage.max_storage_space) + storage.max_storage_space = clamp(storage.max_storage_space * storage_rating, storage.max_storage_space, BASE_STORAGE_CAPACITY(ITEM_SIZE_STRUCTURE)) diff --git a/code/modules/fishing/bait.dm b/code/modules/fishing/bait.dm new file mode 100644 index 000000000000..b805e98f5c34 --- /dev/null +++ b/code/modules/fishing/bait.dm @@ -0,0 +1,10 @@ +/obj/item/food/worm + name = "worm" + desc = "A wriggling worm." + icon = 'icons/obj/worm.dmi' + icon_state = ICON_STATE_WORLD + color = "#835673" + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/organic/meat + nutriment_type = /decl/material/solid/organic/meat + nutriment_amt = 5 diff --git a/code/modules/fishing/fishing_line.dm b/code/modules/fishing/fishing_line.dm new file mode 100644 index 000000000000..28afa6aa1a2f --- /dev/null +++ b/code/modules/fishing/fishing_line.dm @@ -0,0 +1,27 @@ +/obj/item/fishing_line + name = "fishing line" + icon = 'icons/obj/fishing_line.dmi' + icon_state = ICON_STATE_WORLD + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_DESC + max_health = 100 + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + +/obj/item/fishing_line/Initialize() + . = ..() + if(material) + max_health = max(1, round(initial(max_health) * material.tensile_strength)) + current_health = max_health + +/obj/item/fishing_line/Destroy() + if(istype(loc, /obj/item/fishing_rod)) + var/obj/item/fishing_rod/rod = loc + if(rod.line == src) + rod.line = null + return ..() + +/obj/item/fishing_line/high_quality + name = "high-grade fishing line" + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_DESC + max_health = 150 + material = /decl/material/solid/fiberglass diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm new file mode 100644 index 000000000000..ae8342c0f677 --- /dev/null +++ b/code/modules/fishing/fishing_rod.dm @@ -0,0 +1,352 @@ +#define FISHING_FAILED_SILENT 0 +#define FISHING_FAILED_WARNING 1 +#define FISHING_POSSIBLE 2 + +/obj/item/fishing_rod + name = "fishing rod" + desc = "A simple fishing rod with eyelets for stringing a line." + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color + matter = null + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + icon = 'icons/obj/fishing_rod.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + + // Fishing minigame tracking vars. + var/turf/fishing_target + var/mob/fishing_user + // Atom-typed so we can use initial(). + var/atom/fishing_hooked + + var/const/base_fishing_time = 25 SECONDS + var/obj/item/bait + var/obj/item/fishing_line/line + var/fishing_rod_quality = 0.1 + +/obj/item/fishing_rod/Initialize() + if(line) + if(ispath(line)) + line = new line(src) + if(!istype(line)) + line = null + . = ..() + update_icon() + +/obj/item/fishing_rod/Destroy() + stop_fishing() + QDEL_NULL(bait) + QDEL_NULL(line) + return ..() + +/obj/item/fishing_rod/proc/stop_fishing() + + fishing_target = null + fishing_user = null + fishing_hooked = null + +/obj/item/fishing_rod/proc/start_fishing(turf/_target, mob/_user) + + fishing_user = _user + fishing_target = _target + + if(!istype(fishing_user) || !istype(fishing_user)) + stop_fishing() + return + + fishing_user.visible_message(SPAN_NOTICE("\The [fishing_user] casts \the [src] into \the [fishing_target.get_fluid_name()].")) + playsound(fishing_target, 'sound/effects/watersplash.ogg', 25, 1) + fishing_target.show_bubbles() + addtimer(CALLBACK(src, PROC_REF(notify_catch)), get_fishing_delay(fishing_user, fishing_target)) + +/obj/item/fishing_rod/proc/notify_catch() + + if(QDELETED(src)) + return + + if(QDELETED(fishing_target) || QDELETED(fishing_user)) + stop_fishing() + return + + fishing_hooked = fishing_target.get_fishing_result(bait) || FALSE + to_chat(fishing_user, SPAN_NOTICE("You feel a tug on \the [src]!")) + fishing_target.show_bubbles() + playsound(fishing_target, 'sound/effects/bubbles3.ogg', 50, 1) + addtimer(CALLBACK(src, PROC_REF(lose_catch), fishing_hooked), 3 SECONDS) + +/obj/item/fishing_rod/proc/lose_catch(old_hooked) + + if(QDELETED(src)) + return + + if(QDELETED(fishing_target) || QDELETED(fishing_user) || fishing_hooked != old_hooked) + stop_fishing() + return + + fishing_hooked = null + to_chat(fishing_user, SPAN_NOTICE("\The [src]'s line goes slack...")) + playsound(fishing_target, 'sound/effects/slosh.ogg', 25, 1) + addtimer(CALLBACK(src, PROC_REF(notify_catch)), get_fishing_delay(fishing_user, fishing_target)) + +// TODO: more interesting fishing minigame. +/obj/item/fishing_rod/proc/catch_fish() + + if(QDELETED(src)) + return + + if(QDELETED(fishing_target) || QDELETED(fishing_user)) + stop_fishing() + return + + if(istype(fishing_user) && istype(fishing_target) && fishing_user.get_active_held_item() == src) + + if(!ispath(fishing_hooked) || ispath(fishing_hooked, /obj/effect) || !initial(fishing_hooked.simulated)) + to_chat(fishing_user, SPAN_NOTICE("You catch... nothing.")) + + else + + var/atom/movable/result = new fishing_hooked(fishing_target) + to_chat(fishing_user, SPAN_NOTICE("You catch \a [result]!")) + if(ismob(result)) + var/mob/feesh = result + SET_STATUS_MAX(feesh, STAT_STUN, 3) + QDEL_NULL(bait) + + line.take_damage(round(result.get_object_size() * rand(0.5, 1.5))) + if(QDELETED(line)) + to_chat(fishing_user, SPAN_DANGER("Your fishing line snaps!")) + line = null + update_icon() + + var/turf/result_turf = get_step(get_turf(fishing_user), get_dir(fishing_user, result)) + if(result_turf && get_turf(result) != result_turf) + result.throw_at(result_turf, get_dist(src, result), 0.5, fishing_user, FALSE) + + playsound(fishing_target, 'sound/effects/slosh.ogg', 25, 1) + + stop_fishing() + +/obj/item/fishing_rod/on_update_icon() + ..() + if(line) + add_overlay(overlay_image(icon, "[icon_state]-line", line.color, RESET_COLOR | RESET_ALPHA)) + if(bait) + add_overlay(overlay_image(icon, "[icon_state]-bait", bait.color, RESET_COLOR | RESET_ALPHA)) + if(ismob(loc)) + var/mob/M = loc + M.update_inhand_overlays() + +/obj/item/fishing_rod/physically_destroyed() + if(bait) + bait.dropInto(loc) + bait = null + if(line) + line.dropInto(loc) + line = null + return ..() + +/obj/item/fishing_rod/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(user && distance <= 1) + if(line) + . += "\The [src] has been strung with some [get_line_damage()] [line.name]." + if(bait) + . += "\The [src] has been baited with \a [bait]." + +/obj/item/fishing_rod/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + if(line) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-line", line.color, RESET_COLOR | RESET_ALPHA) + if(bait) + overlay.overlays += overlay_image(overlay.icon, "[overlay.icon_state]-bait", bait.color, RESET_COLOR | RESET_ALPHA) + . = ..() + +/obj/item/fishing_rod/use_on_mob(mob/living/target, mob/living/user) + return !user.check_intent(I_FLAG_HARM) ? FALSE : ..() + +/obj/item/fishing_rod/proc/can_fish_in(mob/user, atom/target) + if(!isturf(target)) + return FISHING_FAILED_SILENT + if(!target.submerged()) + to_chat(user, SPAN_WARNING("The water is not deep enough to fish there.")) + return FISHING_FAILED_WARNING + var/list/hit = check_trajectory(target, src, pass_flags=PASS_FLAG_TABLE, lifespan = get_dist(target, src)) + if(length(hit)) + to_chat(user, SPAN_WARNING("Your fishing line is blocked from reaching \the [target] by \the [hit[1]].")) + return FISHING_FAILED_WARNING + return FISHING_POSSIBLE + +/obj/item/fishing_rod/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + + if(user.check_intent(I_FLAG_HARM)) + return ..() + + if(fishing_target) + to_chat(user, SPAN_WARNING("You are already fishing with \the [src]!")) + return + + if(!line) + to_chat(user, SPAN_WARNING("\The [src] has no line!")) + return + + if(get_dist(user, target) > 5) + to_chat(user, SPAN_WARNING("\The [target] is too far away!")) + return + + var/fish_check = can_fish_in(user, target) + if(fish_check == FISHING_FAILED_SILENT) + // TODO: throw the hook at them without doing the fishing minigame. + return ..() + + if(fish_check == FISHING_FAILED_WARNING) + return + + start_fishing(get_turf(target), user) + +/obj/item/fishing_rod/proc/get_fishing_delay(mob/user, turf/target) + var/speed_mult = fishing_rod_quality + (bait?.get_bait_value() || 0) + return clamp(base_fishing_time - (base_fishing_time * speed_mult), 1, base_fishing_time * 2) + +/obj/item/fishing_rod/attack_self(mob/user) + + if(fishing_target) + if(isnull(fishing_hooked)) + to_chat(user, SPAN_NOTICE("You reel your line back in and abandon fishing in \the [fishing_target.get_fluid_name()].")) + stop_fishing() + else + // This is where the proper fishing minigame should go (when it exists). + catch_fish() + return TRUE + + if(bait) + bait.dropInto(loc) + user.put_in_hands(bait) + to_chat(user, SPAN_NOTICE("You remove \the [bait] from \the [src]'s hook.")) + bait = null + update_icon() + return TRUE + + if(line) + remove_line(user) + return TRUE + + return ..() + +/obj/item/fishing_rod/attackby(obj/item/used_item, mob/user) + + if(load_line(user, used_item)) + return TRUE + + if(istype(used_item, /obj/item/food)) + + if(bait) + to_chat(user, SPAN_WARNING("\The [src] already has \a [bait] on the hook.")) + return TRUE + + if(!line) + to_chat(user, SPAN_WARNING("\The [src] needs a line before you can bait it.")) + return TRUE + + if(user.try_unequip(used_item, src)) + bait = used_item + to_chat(user, SPAN_NOTICE("You thread \the [used_item] onto \the [src]'s hook.")) + update_icon() + + return TRUE + + return ..() + +/obj/item/fishing_rod/proc/get_line_damage() + var/line_health = line.get_health_ratio() + if(line_health >= 1) + return "pristine" + if(line_health >= 0.65) + return "flimsy-looking" + if(line_health >= 0.35) + return "rather worn" + return "badly worn" + +/obj/item/fishing_rod/proc/remove_line(mob/user) + if(!line) + return FALSE + line.dropInto(loc) + if(user) + user.put_in_hands(line) + to_chat(user, SPAN_NOTICE("You remove \the [line] from \the [src].")) + line = null + if(bait) + bait.dropInto(loc) + bait = null + update_icon() + return TRUE + +/obj/item/fishing_rod/proc/load_line(mob/user, obj/item/new_line) + + var/static/list/valid_line_types = list( + /obj/item/fishing_line, + /obj/item/stack/cable_coil, + /obj/item/stack/net_cable_coil, + /obj/item/stack/material/bundle, + /obj/item/stack/material/thread, + ) + + if(!new_line || !is_type_in_list(new_line, valid_line_types)) + return FALSE + + // TODO: better solution for grass vs dried grass + if(istype(new_line, /obj/item/stack/material)) + var/obj/item/stack/material/stack = new_line + if(!stack.special_crafting_check()) + return FALSE + + if(!new_line.material?.tensile_strength) + to_chat(user, SPAN_WARNING("\The [new_line] isn't suitable for the rigors of fishing.")) + return TRUE + + if(line) + to_chat(user, SPAN_WARNING("\The [src] already has a line.")) + return TRUE + + if(istype(new_line, /obj/item/stack)) + var/obj/item/stack/cable = new_line + if(cable.get_amount() < 5) + to_chat(user, SPAN_WARNING("You need at least 5 [cable.plural_name] to string \the [src].")) + return TRUE + + if(user) + to_chat(user, SPAN_NOTICE("You begin threading \the [new_line] onto \the [src].")) + if(!do_after(user, 3 SECONDS, src, check_holding = TRUE) || line || QDELETED(new_line)) + return TRUE + + if(istype(new_line, /obj/item/stack)) + var/obj/item/stack/cable = new_line + var/cable_mat = cable.material?.type + if(!cable.use(5)) + return TRUE + new_line = new /obj/item/fishing_line(src, cable_mat) + + if(!user || user.try_unequip(new_line)) + new_line.forceMove(src) + line = new_line + update_icon() + user.visible_message(SPAN_NOTICE("\The [user] strings \the [src] with \the [line].")) + + return TRUE + +#undef FISHING_FAILED_SILENT +#undef FISHING_FAILED_WARNING +#undef FISHING_POSSIBLE + +// Subtypes below. +/obj/item/fishing_rod/advanced + name = "advanced fishing rod" + desc = "It's a fishing rod, an enhanced fiberglass Telescope Ultralight 47; the latest model." + material = /decl/material/solid/fiberglass + color = /decl/material/solid/fiberglass::color + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT + ) + icon = 'icons/obj/fishing_rod_advanced.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR + fishing_rod_quality = 0.2 + line = /obj/item/fishing_line/high_quality diff --git a/code/modules/flufftext/Dreaming.dm b/code/modules/flufftext/Dreaming.dm deleted file mode 100644 index f71d4a711cee..000000000000 --- a/code/modules/flufftext/Dreaming.dm +++ /dev/null @@ -1,19 +0,0 @@ - -mob/living/carbon/proc/dream() - dreaming = 1 - - spawn(0) - for(var/i = rand(1,4),i > 0, i--) - to_chat(src, "... [pick(SSlore.dreams)] ...") - sleep(rand(40,70)) - if(paralysis <= 0) - dreaming = 0 - return 0 - dreaming = 0 - return 1 - -mob/living/carbon/proc/handle_dreams() - if(client && !dreaming && prob(5)) - dream() - -mob/living/carbon/var/dreaming = 0 diff --git a/code/modules/flufftext/TextFilters.dm b/code/modules/flufftext/TextFilters.dm deleted file mode 100644 index 268bf7b4f2fa..000000000000 --- a/code/modules/flufftext/TextFilters.dm +++ /dev/null @@ -1,170 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -proc/Intoxicated(phrase) - phrase = html_decode(phrase) - var/leng=length(phrase) - var/counter=length(phrase) - var/newphrase="" - var/newletter="" - while(counter>=1) - newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2) - if(rand(1,3)==3) - if(lowertext(newletter)=="o") newletter="u" - if(lowertext(newletter)=="s") newletter="ch" - if(lowertext(newletter)=="a") newletter="ah" - if(lowertext(newletter)=="c") newletter="k" - switch(rand(1,7)) - if(1,3,5,8) newletter="[lowertext(newletter)]" - if(2,4,6,15) newletter="[uppertext(newletter)]" - if(7) newletter+="'" - //if(9,10) newletter="[newletter]" - //if(11,12) newletter="[newletter]" - //if(13) newletter="[newletter]" - newphrase+="[newletter]";counter-=1 - return newphrase - -proc/NewStutter(phrase,stunned) - phrase = html_decode(phrase) - - var/list/split_phrase = splittext(phrase," ") //Split it up into words. - - var/list/unstuttered_words = split_phrase.Copy() - var/i = rand(1,3) - if(stunned) i = split_phrase.len - for(,i > 0,i--) //Pick a few words to stutter on. - - if (!unstuttered_words.len) - break - var/word = pick(unstuttered_words) - unstuttered_words -= word //Remove from unstuttered words so we don't stutter it again. - var/index = split_phrase.Find(word) //Find the word in the split phrase so we can replace it. - - //Search for dipthongs (two letters that make one sound.) - var/first_sound = copytext(word,1,3) - var/first_letter = copytext(word,1,2) - if(lowertext(first_sound) in list("ch","th","sh")) - first_letter = first_sound - - //Repeat the first letter to create a stutter. - var/rnum = rand(1,3) - switch(rnum) - if(1) - word = "[first_letter]-[word]" - if(2) - word = "[first_letter]-[first_letter]-[word]" - if(3) - word = "[first_letter]-[word]" - - split_phrase[index] = word - - return sanitize(jointext(split_phrase," ")) - -proc/Stagger(mob/M,d) //Technically not a filter, but it relates to drunkenness. - step(M, pick(d,turn(d,90),turn(d,-90))) - -proc/Ellipsis(original_msg, chance = 50) - if(chance <= 0) return "..." - if(chance >= 100) return original_msg - - var/list/words = splittext(original_msg," ") - var/list/new_words = list() - - var/new_msg = "" - - for(var/w in words) - if(prob(chance)) - new_words += "..." - else - new_words += w - - new_msg = jointext(new_words," ") - - return new_msg -/* -RadioChat Filter. -args: -message - returns a distorted version of this -distortion_chance - the chance of a filter being applied to each character. -distortion_speed - multiplier for the chance increase. -distortion - starting distortion. -english_only - whether to use traditional english letters only (for use in NanoUI) -*/ -proc/RadioChat(mob/living/user, message, distortion_chance = 60, distortion_speed = 1, distortion = 1, english_only = 0) - var/decl/language/language = user?.get_default_language() - message = html_decode(message) - var/new_message = "" - var/input_size = length(message) - var/cursor_position = 0 - if(input_size < 20) // Short messages get distorted too. Bit hacksy. - distortion += (20-input_size)/2 - while(cursor_position <= input_size) - var/newletter=copytext(message, cursor_position, cursor_position+1) - if(!prob(distortion_chance)) - new_message += newletter - cursor_position += 1 - continue - if(newletter != " ") - if(prob(0.08 * distortion)) // Major cutout - newletter = "*zzzt*" - cursor_position += rand(1, (length(message) - cursor_position)) // Skip some characters - distortion += 1 * distortion_speed - else if(prob(0.8 * distortion)) // Minor cut out - if(prob(25)) - newletter = ".." - else if(prob(25)) - newletter = " " - else - newletter = "" - distortion += 0.25 * distortion_speed - else if(prob(2 * distortion)) // Mishearing - if(language && language.syllables && prob(50)) - newletter = pick(language.syllables) - else - newletter = pick("a","e","i","o","u") - distortion += 0.25 * distortion_speed - else if(prob(1.5 * distortion)) // Mishearing - if(language && prob(50)) - if(language.syllables) - newletter = pick (language.syllables) - else - newletter = "*" - else - if(english_only) - newletter += "*" - else - newletter = pick("", "", "%", "", "") - distortion += 0.5 * distortion_speed - else if(prob(0.75 * distortion)) // Incomprehensible - newletter = pick("<", ">", "!", "$", "%", "^", "&", "*", "~", "#") - distortion += 0.75 * distortion_speed - else if(prob(0.05 * distortion)) // Total cut out - if(!english_only) - newletter = "wb%> -BZZT-" - else - newletter = "srgt%$hjc< -BZZT-" - new_message += newletter - break - else if(prob(2.5 * distortion)) // Sound distortion. Still recognisable, mostly. - switch(lowertext(newletter)) - if("s") - newletter = "$" - if("e") - newletter = "" - if("w") - newletter = "" - if("y") - newletter = "" - if("x") - newletter = "" - if("u") - newletter = "" - else - if(prob(0.2 * distortion)) - newletter = " *crackle* " - distortion += 0.25 * distortion_speed - if(prob(20)) - capitalize(newletter) - new_message += newletter - cursor_position += 1 - return new_message - diff --git a/code/modules/fluids/_fluid.dm b/code/modules/fluids/_fluid.dm new file mode 100644 index 000000000000..8e2449f56fc1 --- /dev/null +++ b/code/modules/fluids/_fluid.dm @@ -0,0 +1,153 @@ +/atom/movable/fluid_overlay + name = "" + icon = 'icons/effects/liquids.dmi' + icon_state = "" + anchored = TRUE + simulated = FALSE + opacity = FALSE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + layer = FLY_LAYER + alpha = 0 + color = COLOR_LIQUID_WATER + is_spawnable_type = FALSE + appearance_flags = KEEP_TOGETHER + var/last_update_depth + var/updating_edge_mask + var/force_flow_direction + +/atom/movable/fluid_overlay/on_turf_height_change(new_height) + update_icon() + return TRUE + +/atom/movable/fluid_overlay/on_update_icon() + + var/datum/reagents/loc_reagents = loc?.reagents + var/reagent_volume = REAGENT_TOTAL_VOLUME(loc_reagents) + + // Update layer. + var/new_layer + var/turf/flow_turf = get_turf(src) + if(flow_turf.pixel_z < 0) + new_layer = flow_turf.layer + 0.2 + else if(reagent_volume > FLUID_DEEP) + new_layer = DEEP_FLUID_LAYER + else + new_layer = SHALLOW_FLUID_LAYER + + if(layer != new_layer) + layer = new_layer + + // Update colour. + var/new_color = loc_reagents?.get_color() + if(color != new_color) + color = new_color + + // Update alpha. + if(reagent_volume) + + var/decl/material/main_reagent = loc_reagents?.get_primary_reagent_decl() + var/new_alpha + if(main_reagent) // TODO: weighted alpha from all reagents, not just primary + new_alpha = clamp(ceil(255*(reagent_volume/FLUID_DEEP)) * main_reagent.opacity, main_reagent.min_fluid_opacity, main_reagent.max_fluid_opacity) + else + new_alpha = FLUID_MIN_ALPHA + if(new_alpha != alpha) + alpha = new_alpha + + var/flow_dir = force_flow_direction || flow_turf.last_flow_dir + set_dir(flow_dir) + // Update icon state. We use overlays so flick() can work on the base fluid overlay. + if(reagent_volume <= FLUID_PUDDLE) + set_overlays("puddle") + else if(reagent_volume <= FLUID_SHALLOW) + set_overlays(flow_dir ? "shallow_flow" : "shallow") + else if(reagent_volume < FLUID_DEEP) + set_overlays(flow_dir ? "mid_flow" : "mid") + else if(reagent_volume < (FLUID_DEEP*2)) + set_overlays(flow_dir ? "deep_flow" : "deep") + else + set_overlays("ocean") + else + cut_overlays() +// Define FLUID_AMOUNT_DEBUG before this to get a handy overlay of fluid amounts. +#ifdef FLUID_AMOUNT_DEBUG + var/image/I = new() + I.maptext = STYLE_SMALLFONTS_OUTLINE("
          [num2text(reagent_volume)]
          ", 6, COLOR_WHITE, COLOR_BLACK) + I.maptext_y = 8 + I.appearance_flags |= KEEP_APART + add_overlay(I) +#endif + compile_overlays() + + if((last_update_depth > FLUID_PUDDLE) != (reagent_volume > FLUID_PUDDLE)) + + // Update alpha masks. + for(var/checkdir in global.alldirs) + var/turf/neighbor = get_step_resolving_mimic(loc, checkdir) + if(istype(neighbor) && neighbor.fluid_overlay && !neighbor.fluid_overlay.updating_edge_mask) + neighbor.fluid_overlay.update_alpha_mask() + if(!updating_edge_mask) + update_alpha_mask() + + // Update everything on our atom too. + if(length(loc?.contents) && (last_update_depth > FLUID_PUDDLE && last_update_depth <= FLUID_SHALLOW) != (reagent_volume <= FLUID_SHALLOW)) + for(var/atom/movable/AM in loc.contents) + if(AM.simulated) + AM.update_turf_alpha_mask() + + last_update_depth = reagent_volume + +var/global/list/_fluid_edge_mask_cache = list() +/atom/movable/fluid_overlay/proc/update_alpha_mask() + + set waitfor = FALSE + // Delay to avoid multiple updates. + if(updating_edge_mask) + return + updating_edge_mask = TRUE + sleep(0) + updating_edge_mask = FALSE + + if(REAGENT_TOTAL_VOLUME(loc?.reagents) <= FLUID_PUDDLE) + remove_filter("fluid_edge_mask") + return + + // Collect neighbor info. + var/list/ignored + var/list/connections + for(var/checkdir in global.alldirs) + var/turf/neighbor = get_step_resolving_mimic(loc, checkdir) + if(!neighbor || neighbor.density || !istype(neighbor?.reagents) || REAGENT_TOTAL_VOLUME(neighbor?.reagents) > FLUID_PUDDLE) + LAZYADD(connections, checkdir) + else + LAZYADD(ignored, checkdir) + + if(!LAZYLEN(connections)) + remove_filter("fluid_edge_mask") + return + + // Generate and apply an alpha filter for our edges. + // Need to use icons here due to overlays being hell with directional states. + + var/cache_key = "[length(connections) ? jointext(connections, "-") : 0]|[length(ignored) ? jointext(ignored, "-") : 0]" + var/icon/edge_mask = global._fluid_edge_mask_cache[cache_key] + if(isnull(edge_mask)) + connections = dirs_to_corner_states(connections) + edge_mask = icon(icon, "blank") + for(var/i = 1 to 4) + if(length(connections) >= i) + edge_mask.Blend(icon(icon, "edgemask[connections[i]]", dir = BITFLAG(i-1)), ICON_OVERLAY) + global._fluid_edge_mask_cache[cache_key] = edge_mask || FALSE + + if(edge_mask) + add_filter("fluid_edge_mask", 1, list(type = "alpha", icon = edge_mask, flags = MASK_INVERSE)) + else + remove_filter("fluid_edge_mask") + +/atom/movable/fluid_overlay/Destroy() + var/atom/oldloc = loc + . = ..() + if(istype(oldloc)) + for(var/atom/movable/AM in oldloc.contents) + if(AM.simulated) + AM.update_turf_alpha_mask() diff --git a/code/modules/fluids/fluid_flood.dm b/code/modules/fluids/fluid_flood.dm new file mode 100644 index 000000000000..7b3f2a333840 --- /dev/null +++ b/code/modules/fluids/fluid_flood.dm @@ -0,0 +1,29 @@ +// Permaflood overlay. +var/global/list/flood_type_overlay_cache = list() +// TODO: does this need to also take contaminant type as an argument? flooding contaminants are totally untested +// also, do flooded turfs even apply fluid_act and touch effects? +/proc/get_flood_overlay(fluid_type) + if(!ispath(fluid_type, /decl/material)) + return null + if(!global.flood_type_overlay_cache[fluid_type]) + var/decl/material/fluid_decl = GET_DECL(fluid_type) + var/obj/effect/flood/new_flood = new + new_flood.color = fluid_decl.color + new_flood.alpha = round(fluid_decl.min_fluid_opacity + ((fluid_decl.max_fluid_opacity - fluid_decl.min_fluid_opacity) * 0.5)) + global.flood_type_overlay_cache[fluid_type] = new_flood + return new_flood + return global.flood_type_overlay_cache[fluid_type] + +/obj/effect/flood + name = "" + icon = 'icons/effects/liquids.dmi' + icon_state = "ocean" + layer = DEEP_FLUID_LAYER + color = COLOR_LIQUID_WATER + alpha = 140 + invisibility = 0 + simulated = FALSE + density = FALSE + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + is_spawnable_type = FALSE diff --git a/code/modules/fluids/fluid_mapped.dm b/code/modules/fluids/fluid_mapped.dm new file mode 100644 index 000000000000..3a286cf7b36c --- /dev/null +++ b/code/modules/fluids/fluid_mapped.dm @@ -0,0 +1,49 @@ + +// Map helpers. +/obj/abstract/landmark/mapped_flood + name = "mapped fluid area" + alpha = FLUID_MAX_ALPHA + icon_state = "ocean" + color = COLOR_LIQUID_WATER + var/fluid_type = /decl/material/liquid/water + +/obj/abstract/landmark/mapped_flood/Initialize() + ..() + var/turf/my_turf = get_turf(src) + if(my_turf) + my_turf.set_flooded(fluid_type) + return INITIALIZE_HINT_QDEL + +/obj/abstract/landmark/mapped_fluid + name = "mapped fluid area" + alpha = FLUID_MIN_ALPHA + icon_state = "shallow" + color = COLOR_LIQUID_WATER + + var/fluid_type = /decl/material/liquid/water + var/fluid_initial = FLUID_MAX_DEPTH + +/obj/abstract/landmark/mapped_fluid/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/abstract/landmark/mapped_fluid/LateInitialize() + ..() + if(fluid_initial > 0) + var/turf/my_turf = get_turf(src) + if(my_turf) + my_turf.add_to_reagents(fluid_type, fluid_initial) + qdel(src) + +/obj/abstract/landmark/mapped_fluid/fuel + name = "spilled fuel" + fluid_type = /decl/material/liquid/fuel + fluid_initial = 10 + +/obj/abstract/landmark/mapped_fluid/fill + name = "mapped fluid fill" + +/obj/abstract/landmark/mapped_fluid/fill/LateInitialize() + var/turf/my_turf = get_turf(loc) + fluid_initial = -(my_turf.get_physical_height()) + ..() diff --git a/code/modules/food/assembled.dm b/code/modules/food/assembled.dm new file mode 100644 index 000000000000..861cb9494194 --- /dev/null +++ b/code/modules/food/assembled.dm @@ -0,0 +1,239 @@ +/// Items you can craft together. Like bomb making, but with food and less screwdrivers. +/// Uses format list(ingredient = result_type). +/// The ingredient can be a typepath or a grown_tag string (used for mobs or plants) +/// The product can be a typepath or a list of typepaths, which will prompt the user. +/// TODO: validate that these products are properly ordered +/obj/item/food/proc/get_combined_food_products() + return + +/obj/item/food/attackby(obj/item/used_item, mob/living/user) + + if(used_item?.storage) + return ..() + + // Plating food. + if(istype(used_item, /obj/item/plate)) + var/obj/item/plate/plate = used_item + if(plate.try_plate_food(src, user)) + return TRUE + + // Eating with forks + if(user.check_intent(I_FLAG_HELP) && do_utensil_interaction(used_item, user)) + return TRUE + + // Hiding items inside larger food items. + if(!user.check_intent(I_FLAG_HARM) && is_sliceable() && used_item.w_class < w_class && !is_robot_module(used_item) && !istype(used_item, /obj/item/chems/condiment)) + if(user.try_unequip(used_item, src)) + to_chat(user, SPAN_NOTICE("You slip \the [used_item] inside \the [src].")) + add_fingerprint(user) + used_item.forceMove(src) + return TRUE + + // Creating food combinations. + if(try_create_combination(used_item, user)) + return TRUE + + return ..() + +/obj/item/food/proc/get_grown_tag() + return + +/obj/item/food/proc/try_create_combination(obj/item/used_item, mob/user) + if(!length(get_combined_food_products()) || !istype(used_item) || QDELETED(src) || QDELETED(used_item)) + return FALSE + + // See if we can make anything with this. + var/list/combined_food_products = get_combined_food_products() + if(!length(combined_food_products)) + return FALSE + + var/create_type = combined_food_products[used_item.type] + if(!create_type && istype(used_item, /obj/item/food)) + var/obj/item/food/food = used_item + var/check_grown_tag = food.get_grown_tag() + if(check_grown_tag) + create_type = combined_food_products[check_grown_tag] + + if(islist(create_type)) + var/list/names = list() + for(var/food_type in create_type) + names[atom_info_repository.get_name_for(food_type)] = food_type + create_type = input(user, "What do you want to make?", "Food Assembly") as null|anything in names + if(!create_type || QDELETED(user) || user.incapacitated() || QDELETED(src) || QDELETED(used_item)) + return TRUE + create_type = names[create_type] + + // TODO: move reagents/matter into produced food object. + if(ispath(create_type) && user.can_unequip_item(src)) + var/obj/item/food/result + if(ispath(create_type, /obj/item/food)) + + // Create the food with no plate, and move over any existing plate. + result = new create_type(null, null, TRUE) // Skip plate creation. + + if(istype(used_item, /obj/item/food)) + var/obj/item/food/other_food = used_item + result.plate = other_food.plate + other_food.plate = null + + if(!result.plate && plate) + result.plate = plate + plate = null + + if(istype(result.plate) && result.plate.loc != result) + result.plate.forceMove(result) + + else + result = new create_type + + //If the snack was in your hands, the result will be too + if (src in user.get_held_item_slots()) + user.drop_from_inventory(src) + user.put_in_hands(result) + else + result.dropInto(loc) + qdel(used_item) + qdel(src) + to_chat(user, SPAN_NOTICE("You make \the [result]!")) + return TRUE + + // Reverse the interaction to avoid the dumb thing where combinations aren't commutative. + var/obj/item/food/food = used_item + if(istype(food)) + return food.try_create_combination(src, user) + return FALSE + +/obj/item/food/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1) + return + var/list/combined_food_products = get_combined_food_products() + if(!length(combined_food_products)) + return + for(var/thing_type in combined_food_products) + var/product = combined_food_products[thing_type] + var/product_string + if(islist(product)) + var/list/names = list() + for(var/product_type in product) + names += "\a [atom_info_repository.get_name_for(product_type)]" + product_string = english_list(names, and_text = " or ") + else + product_string = "\a [atom_info_repository.get_name_for(product)]" + . += SPAN_NOTICE("With this and \a [ispath(thing_type) ? atom_info_repository.get_name_for(thing_type): thing_type], you could make [product_string].") + +/obj/item/food/bun/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/meatball = /obj/item/food/burger, + /obj/item/food/butchery/cutlet = /obj/item/food/hamburger, + /obj/item/food/sausage = /obj/item/food/hotdog, + /obj/item/robot_parts/head = /obj/item/food/roburger, + /obj/item/holder/corgi = /obj/item/food/classichotdog, + /obj/item/food/butchery/cutlet = /obj/item/food/burger, + /obj/item/organ/internal/brain = /obj/item/food/brainburger, + /obj/item/food/butchery/meat/xeno = /obj/item/food/xenoburger, + /obj/item/food/butchery/meat/fish = /obj/item/food/fishburger, + /obj/item/food/tofu = /obj/item/food/tofuburger, + /obj/item/ectoplasm = /obj/item/food/ghostburger, + /obj/item/clothing/mask/gas/clown_hat = /obj/item/food/clownburger, + /obj/item/clothing/head/beret = /obj/item/food/mimeburger, + /obj/item/food/bun = /obj/item/food/bunbun, + /obj/item/food/sausage = /obj/item/food/hotdog + ) + return combined_food_products + +/obj/item/food/twobread/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/slice/bread = /obj/item/food/threebread + ) + return combined_food_products + +/obj/item/food/unleaveneddoughslice/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/meatball = /obj/item/food/donkpocket, + /obj/item/food/meatball/raw = list( + /obj/item/food/pelmen, + /obj/item/food/donkpocket + ) + ) + return combined_food_products + +/obj/item/food/burger/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/dairy/cheese/wedge = /obj/item/food/cheeseburger, + /obj/item/clothing/head/wizard = /obj/item/food/spellburger + ) + return combined_food_products + +/obj/item/food/hamburger/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/dairy/cheese/wedge = /obj/item/food/cheeseburger + ) + return combined_food_products + +// Spaghetti + meatball = spaghetti with meatball(s) +/obj/item/food/boiledspagetti/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/meatball = /obj/item/food/meatballspagetti, + /obj/item/stack/nanopaste = /obj/item/food/nanopasta + ) + return combined_food_products + +// Spaghetti with meatballs + meatball = spaghetti with more meatball(s) +/obj/item/food/meatballspagetti/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/meatball = /obj/item/food/spesslaw + ) + return combined_food_products + +/obj/item/food/butchery/cutlet/raw/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/meatball/raw = /obj/item/food/sausage + ) + return combined_food_products + +/obj/item/food/meatball/raw/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/butchery/cutlet/raw = /obj/item/food/sausage + ) + return combined_food_products + +/obj/item/food/sausage/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/meatball/raw = /obj/item/food/fatsausage, + /obj/item/food/butchery/cutlet/raw = /obj/item/food/fatsausage + ) + return combined_food_products + +/obj/item/food/piecrust/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/butchery/cutlet = /obj/item/food/meatpie/raw, + /obj/item/food/tofu = /obj/item/food/tofupie/raw, + /obj/item/food/butchery/meat/xeno = /obj/item/food/xemeatpie/raw, + "apple" = /obj/item/food/applepie/raw, + "berries" = /obj/item/food/berryclafoutis/raw, + "plumphelmet" = /obj/item/food/plump_pie/raw + ) + return combined_food_products + +// This one looks slightly weird but the attackby() proc should mirror it to the potato. +/obj/item/food/dairy/cheese/wedge/get_combined_food_products() + var/static/list/combined_food_products = list( + "potato" = /obj/item/food/loadedbakedpotato/raw + ) + return combined_food_products + +/obj/item/food/fries/get_combined_food_products() + var/static/list/combined_food_products = list( + /obj/item/food/dairy/cheese/wedge = /obj/item/food/cheesyfries/uncooked + ) + return combined_food_products + +/obj/item/food/meatpie/raw/cooked_food = FOOD_RAW +/obj/item/food/tofupie/raw/cooked_food = FOOD_RAW +/obj/item/food/xemeatpie/raw/cooked_food = FOOD_RAW +/obj/item/food/applepie/raw/cooked_food = FOOD_RAW +/obj/item/food/berryclafoutis/raw/cooked_food = FOOD_RAW +/obj/item/food/plump_pie/raw/cooked_food = FOOD_RAW +/obj/item/food/loadedbakedpotato/raw/cooked_food = FOOD_RAW +/obj/item/food/cheesyfries/uncooked/cooked_food = FOOD_PREPARED // No penalty for eating it, but nicer cooked. diff --git a/code/modules/food/cooking/_recipe.dm b/code/modules/food/cooking/_recipe.dm new file mode 100644 index 000000000000..689948f81d0a --- /dev/null +++ b/code/modules/food/cooking/_recipe.dm @@ -0,0 +1,384 @@ +// Order is important as it is used as a key to the used_ingredients list. +#define RECIPE_COMPONENT_ITEMS 1 +#define RECIPE_COMPONENT_FRUIT 2 +#define RECIPE_COMPONENT_CHEMS 3 + +var/global/list/_cooking_recipe_cache = list() +/proc/select_recipe(category, atom/container, cooking_temperature) + + if(!category) + return + + if(!global._cooking_recipe_cache[category]) + var/list/recipes = list() + var/list/all_recipes = decls_repository.get_decls_of_subtype(/decl/recipe) + for(var/rtype in all_recipes) + var/decl/recipe/recipe = all_recipes[rtype] + if(isnull(recipe.container_categories) || (category in recipe.container_categories)) + recipes += recipe + global._cooking_recipe_cache[category] = recipes + + var/list/available_recipes = global._cooking_recipe_cache[category] + if(!length(available_recipes)) + return + + var/highest_count = 0 + for(var/decl/recipe/recipe as anything in available_recipes) + if(recipe.can_cook_in(container, cooking_temperature) && (!. || recipe.complexity >= highest_count)) + highest_count = recipe.complexity + . = recipe + +/* * * * * * * * * * * * * * * * * * * * * * * * * * + * /datum/recipe by rastaf0 13 apr 2011 * + * /decl/recipe by Neb 21 may 2021 * + * * + * Happy tenth birthday you pile of spaghetti! * + * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/decl/recipe + + abstract_type = /decl/recipe + + var/display_name // Descriptive name of the recipe, should be unique to avoid codex pages being unsearchable. If not set, codex uses initial name of product. + var/list/reagents // example: = list(/decl/material/liquid/drink/juice/berry = 5) // do not list same reagent twice + var/list/items // example: = list(/obj/item/crowbar, /obj/item/welder, /obj/item/screwdriver = 2) // place /foo/bar before /foo + var/list/fruit // example: = list("potato" = 1, "tomato chopped" = 3) + var/cooking_time = 10 SECONDS // Cooking time in deciseconds. + + /// What categories can this recipe be cooked by? Null for any. + var/list/container_categories + /// How many items to create, or how many reagent units to add. + var/result_quantity = 1 + /// An atom type to create, or a /decl/material type if you want to place a reagent into the container. + var/result + /// A data list passed to the result if set to a material type. + var/result_data + + /// A minimum cooking temperature for this recipe to be considered. + var/minimum_temperature = 0 + /// A maximum temperature for this recipe to be considered. + var/maximum_temperature = INFINITY + + // Enum for indicating what kind of heat this recipe requires to cook. + // COOKING_HEAT_ANY, COOKING_HEAT_DIRECT, COOKING_HEAT_INDIRECT + var/cooking_heat_type = COOKING_HEAT_ANY + + /// A reagent that must be present in the cooking contianer, but will not be consumed. + var/cooking_medium_type + /// A minimum about of the above reagent required. + var/cooking_medium_amount + + /// Whether this recipe is eligible for bulk cooking in a cooking vessel. Not currently checked by microwaves. + var/can_bulk_cook = FALSE + + var/const/REAGENT_REPLACE = 0 //Reagents in the ingredients are discarded (only the reagents present in the result at compiletime are used) + var/const/REAGENT_MAX = 1 //The result will contain the maximum of each reagent present between the two pools. Compiletime result, and sum of ingredients + var/const/REAGENT_MIN = 2 //As above, but the minimum, ignoring zero values. + var/const/REAGENT_SUM = 3 //The entire quantity of the ingredients are added to the result + + var/reagent_mix = REAGENT_MAX //How to handle reagent differences between the ingredients and the results + + /// Calculated from summing all reagents, ingredients, fruits etc. and used to determine which recipe should be used first. + var/complexity = 0 + + // Codex entry values. + var/hidden_from_codex // If TRUE, codex page will not be generated for this recipe. + var/lore_text // IC description of recipe/food. + var/mechanics_text // Mechanical description of recipe/food. + var/antag_text // Any antagonist-relevant stuff relating to this recipe. + + var/completion_message + +/decl/recipe/validate() + . = ..() + if(!ispath(result)) + . += "invalid or null result type: [result || "NULL"]" + if(!isnum(result_quantity) || result_quantity <= 0) + . += "invalid or null result amount: [result_quantity || "NULL"]" + +/decl/recipe/Initialize() + . = ..() + complexity += length(reagents) + length(fruit) + var/value + for(var/i in items) // add the number of items total + value = items[i] + complexity += isnum(value) ? value : 1 + complexity += length(uniquelist(items)) // add how many unique items there are; will prioritise burgers over 2 bunbuns and 1 wasted meat, for example + +/decl/recipe/proc/can_cook_in(atom/container, cooking_temperature) + if(!istype(container)) + return FALSE + if(cooking_temperature < minimum_temperature) + return FALSE + if(cooking_temperature > maximum_temperature) + return FALSE + if(!check_reagents(container.reagents)) + return FALSE + if(!check_items(container)) + return FALSE + if(!check_fruit(container)) + return FALSE + return TRUE + +/decl/recipe/proc/check_reagents(datum/reagents/avail_reagents) + // SHOULD_BE_PURE(TRUE) Due to use of GET_DECL() in REAGENT_VOLUME, this cannot be pure. + if(length(REAGENT_VOLUMES(avail_reagents)) < length(reagents)) + return FALSE + for(var/reagent in reagents) + if(REAGENT_VOLUME(avail_reagents, reagent) < reagents[reagent]) + return FALSE + return TRUE + +/decl/recipe/proc/check_fruit(obj/container) + // SHOULD_BE_PURE(TRUE) // We cannot set SHOULD_BE_PURE here as + // get_contained_external_atoms() retrieves an extension, which is impure. + if(!length(fruit)) + return TRUE + var/container_contents = container?.get_contained_external_atoms() + if(length(container_contents) < length(fruit)) + return FALSE + var/list/needed_fruits = fruit.Copy() + for(var/obj/item/food/S in container_contents) + var/use_tag = S.get_grown_tag() + if(!use_tag) + continue + if(isnull(needed_fruits[use_tag])) + continue + needed_fruits[use_tag]-- + for(var/ktag in needed_fruits) + if(needed_fruits[ktag] > 0) + return FALSE + return TRUE + +/decl/recipe/proc/check_items(obj/container) + // SHOULD_BE_PURE(TRUE) // We cannot set SHOULD_BE_PURE here as + // get_contained_external_atoms() retrieves an extension, which is impure. + if(!length(items)) + return TRUE + var/list/container_contents = container?.get_contained_external_atoms() + if(length(container_contents) < length(items)) + return FALSE + var/list/needed_items = items.Copy() + for(var/itype in needed_items) + for(var/thing in container_contents) + if(!istype(thing, itype)) + continue + container_contents -= thing + if(isnum(needed_items[itype])) + if(istype(thing, /obj/item/stack)) + var/obj/item/stack/stack = thing + needed_items[itype] -= stack.amount + else + --needed_items[itype] + if(needed_items[itype] <= 0) + needed_items -= itype + break + else + needed_items -= itype + break + // break + if(!length(container_contents)) + break + return !length(needed_items) + +/decl/recipe/proc/create_result(atom/container, list/used_ingredients) + + if(!istype(container) || QDELETED(container) || !container.simulated) + CRASH("Recipe trying to create a result with null or invalid container: [container || "NULL"], [container?.simulated || "NULL"]") + if(!REAGENT_MAXIMUM_VOLUME(container.reagents)) + CRASH("Recipe trying to create a result in a container with null or zero capacity reagent holder: [istype(reagents) ? REAGENT_MAXIMUM_VOLUME(container.reagents) : "NULL"]") + + if(ispath(result, /atom/movable)) + return create_result_atom(container, used_ingredients) + + if(ispath(result, /decl/material)) + var/created_volume = result_quantity + for(var/obj/item/ingredient in (used_ingredients[RECIPE_COMPONENT_ITEMS]|used_ingredients[RECIPE_COMPONENT_FRUIT])) + created_volume += REAGENT_TOTAL_VOLUME(ingredient.reagents) + + container.reagents?.add_reagent(result, created_volume, get_result_data(container, used_ingredients)) + return null + +// Create the actual result atom. Handled by a proc to allow for recipes to override it. +/decl/recipe/proc/create_result_atom(atom/container, list/used_ingredients) + if(ispath(result, /obj/item/food)) + return new result(container, null, TRUE) // Supply argument to skip plate creation. + return new result(container) + +/// Return a data list to pass to a reagent creation proc. Allows for overriding/mutation based on ingredients. +/decl/recipe/proc/get_result_data(atom/container, list/used_ingredients) + return result_data + +// food-related +/// Actually place or create the result of the recipe. Returns the produced item(s), or null if only reagents were produced. +/decl/recipe/proc/produce_result(obj/container) + + /* + We will subtract all the ingredients from the container, and transfer their reagents into a holder + We will not touch things which are not required for this recipe. They will be left behind for the caller + to decide what to do. They may be used again to make another recipe or discarded, or merged into the results, + thats no longer the concern of this proc + */ + + // We collected the used ingredients before removing them in case + // the result proc needs to check the list for procedural products. + // This mapping is indexed by RECIPE_COMPONENT_FOO defines. + var/list/used_ingredients = list(list(), list(), list()) + + // Find items we need. + var/list/container_contents = container.get_contained_external_atoms() + if(LAZYLEN(items)) + for(var/item_type in items) + if(ispath(item_type, /obj/item/stack)) + var/needed_amount = max(1, items[item_type]) + var/obj/item/stack/stack + while(needed_amount > 0 && (stack = locate(item_type) in container_contents)) + if(QDELETED(stack)) + container_contents -= stack + continue + var/amount_to_take = min(stack.amount, needed_amount) + var/obj/item/stack/used + if(stack.amount <= amount_to_take) // We're using the whole stack. + used = stack + container_contents -= stack + else + used = stack.split(amount_to_take) + used_ingredients[RECIPE_COMPONENT_ITEMS] += used + needed_amount -= used.amount + continue + for(var/item_count in 1 to max(1, items[item_type])) + var/obj/item/item = locate(item_type) in container_contents + if(item) + container_contents -= item + used_ingredients[RECIPE_COMPONENT_ITEMS] += item + + // Find fruits that we need. + if(LAZYLEN(fruit)) + var/list/checklist = fruit.Copy() + for(var/obj/item/food/food in container_contents) + var/check_grown_tag = food.get_grown_tag() + if(check_grown_tag && checklist[check_grown_tag] > 0) + //We found a thing we need + container_contents -= food + checklist[check_grown_tag]-- + used_ingredients[RECIPE_COMPONENT_FRUIT] += food + + // And lastly deduct necessary quantities of reagents. + if(LAZYLEN(reagents)) + for(var/reagent_type in reagents) + used_ingredients[RECIPE_COMPONENT_CHEMS][reagent_type] += reagents[reagent_type] + + /* + Now we've removed all the ingredients that were used and we have the buffer containing the total of + all their reagents. + If we have multiple results, holder will be used as a buffer to hold reagents for the result objects. + If, as in the most common case, there is only a single result, then it will just be a reference to + the single-result's reagents + */ + + // Create our food products. + // Note that this will simply put reagents into the container for non-object recipes. + if(ispath(result, /decl/material)) + var/atom/movable/result_obj = create_result(container, used_ingredients) + if(istype(result_obj)) + LAZYADD(., result_obj) + else + for(var/_ in 1 to result_quantity) + var/atom/movable/result_obj = create_result(container, used_ingredients) + if(istype(result_obj)) + LAZYADD(., result_obj) + + // Collect all our ingredient reagents in a buffer. + // If we aren't using a buffer, just discard the reagents. + var/datum/reagents/buffer = (reagent_mix != REAGENT_REPLACE) ? new(INFINITY, global.temp_reagents_holder) : null + for(var/atom/item as anything in used_ingredients[RECIPE_COMPONENT_ITEMS]) + if(item.reagents) + if(buffer) + item.reagents.trans_to_holder(buffer, REAGENT_TOTAL_VOLUME(item.reagents)) + else + item.reagents.clear_reagents() + item.physically_destroyed() + for(var/atom/fruit as anything in used_ingredients[RECIPE_COMPONENT_FRUIT]) + if(fruit.reagents) + if(buffer) + fruit.reagents.trans_to_holder(buffer, REAGENT_TOTAL_VOLUME(fruit.reagents)) + else + fruit.reagents.clear_reagents() + fruit.physically_destroyed() + for(var/reagent_type in used_ingredients[RECIPE_COMPONENT_CHEMS]) + var/reagent_amount = used_ingredients[RECIPE_COMPONENT_CHEMS][reagent_type] + if(buffer) + container.reagents.trans_type_to_holder(buffer, reagent_type, reagent_amount) + else + container.reagents.remove_reagent(reagent_type, reagent_amount) + + /// Set the appropriate flag on the food for stressor updates. + for(var/obj/item/food/food in .) + food.cooked_food = FOOD_COOKED + QDEL_NULL(food.plate) + + if(completion_message && ATOM_IS_OPEN_CONTAINER(container)) + container.visible_message(SPAN_NOTICE(completion_message)) + + // We only care about the outputs, so we can go home now. + if(reagent_mix == REAGENT_REPLACE) + if(buffer) + qdel(buffer) + return + + // Collect all of the resulting food reagents. + var/temporary_holder + var/datum/reagents/holder + if(length(.) == 1) + var/atom/movable/result_obj = .[1] + holder = result_obj.reagents + else + temporary_holder = new /datum/reagents(INFINITY, global.temp_reagents_holder) + holder = temporary_holder + if(length(.) > 1) + for(var/atom/movable/result_obj in .) + result_obj.reagents.trans_to_holder(holder, REAGENT_TOTAL_VOLUME(result_obj.reagents)) + + switch(reagent_mix) + + if(REAGENT_SUM) + //Sum is easy, just shove the entire buffer into the result + buffer.trans_to_holder(holder, REAGENT_TOTAL_VOLUME(buffer)) + + if(REAGENT_MAX) + //We want the highest of each. + //Iterate through everything in buffer. If the target has less than the buffer, then top it up + for (var/decl/material/reagent as anything in REAGENT_VOLUMES(buffer)) + var/rvol = REAGENT_VOLUME(holder, reagent) + var/bvol = REAGENT_VOLUME(buffer, reagent) + if (rvol < bvol) + //Transfer the difference + buffer.trans_type_to_holder(holder, reagent, bvol-rvol) + + if(REAGENT_MIN) + //Min is slightly more complex. We want the result to have the lowest from each side + //But zero will not count. Where a side has zero its ignored and the side with a nonzero value is used + for (var/decl/material/reagent as anything in REAGENT_VOLUMES(buffer)) + var/rvol = REAGENT_VOLUME(holder, reagent) + var/bvol = REAGENT_VOLUME(buffer, reagent) + if (rvol == 0) //If the target has zero of this reagent + buffer.trans_type_to_holder(holder, reagent, bvol) + //Then transfer all of ours + + else if (rvol > bvol) + //if the target has more than ours + //Remove the difference + holder.remove_reagent(reagent, rvol-bvol) + + if(length(.) > 1) + // If we're here, then holder is a buffer containing the total reagents + // for all the results. So now we redistribute it among them. + var/total = round(REAGENT_TOTAL_VOLUME(holder) / length(.)) + for(var/atom/result as anything in .) + holder.trans_to(result, total) + + // Clean up after ourselves. + if(buffer) + qdel(buffer) + if(temporary_holder && holder) + qdel(holder) diff --git a/code/modules/food/cooking/cooking_vessels/_cooking_vessel.dm b/code/modules/food/cooking/cooking_vessels/_cooking_vessel.dm new file mode 100644 index 000000000000..501a99f2282a --- /dev/null +++ b/code/modules/food/cooking/cooking_vessels/_cooking_vessel.dm @@ -0,0 +1,174 @@ +/obj/item/chems/cooking_vessel + + abstract_type = /obj/item/chems/cooking_vessel + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_HOLLOW + w_class = ITEM_SIZE_LARGE + icon_state = ICON_STATE_WORLD + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + storage = /datum/storage/hopper/industrial + material = /decl/material/solid/metal/stainlesssteel + color = /decl/material/solid/metal/stainlesssteel::color + amount_per_transfer_from_this = 15 + + // Used for work sounds. + var/datum/sound_token/work_sound_token + var/sound_id + var/work_sound + + var/cooking_category + var/started_cooking + var/decl/recipe/last_recipe + +/obj/item/chems/cooking_vessel/Initialize(ml, material_key) + . = ..() + if(work_sound) + sound_id = "[work_sound]" + +/obj/item/chems/cooking_vessel/Destroy() + QDEL_NULL(work_sound_token) + return ..() + +// TODO: ladle +/obj/item/chems/cooking_vessel/attackby(obj/item/used_item, mob/user) + + if(user.check_intent(I_FLAG_HARM)) + return ..() + + // Fill or take from the vessel. + if(used_item.reagents && ATOM_IS_OPEN_CONTAINER(used_item)) + if(REAGENT_TOTAL_VOLUME(used_item.reagents)) + if(istype(used_item, /obj/item/chems)) + var/obj/item/chems/vessel = used_item + if(vessel.standard_pour_into(user, src)) + return TRUE + else if(standard_pour_into(user, used_item)) + return TRUE + + return ..() + +// Boilerplate from /obj/item/chems/glass. TODO generalize to a lower level. +/obj/item/chems/cooking_vessel/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(get_attack_force() && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.check_intent(I_FLAG_HARM)) + return ..() + return FALSE + +/obj/item/chems/cooking_vessel/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!proximity || istype(target, /obj/machinery/reagent_temperature)) + return FALSE + if(!ATOM_IS_OPEN_CONTAINER(src) || !proximity) //Is the container open & are they next to whatever they're clicking? + return FALSE //If not, do nothing. + if(target?.storage) + return TRUE + if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser? + return TRUE + if(standard_pour_into(user, target)) //Pouring into another beaker? + return TRUE + if(handle_eaten_by_mob(user, target) != EATEN_INVALID) + return TRUE + + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(user.check_intent(I_FLAG_HARM)) + if(standard_splash_mob(user,target)) + return TRUE + if(reagents && total_vol) + to_chat(user, SPAN_DANGER("You splash the contents of \the [src] onto \the [target].")) + reagents.splash(target, total_vol) + return TRUE + else if(reagents && total_vol) + to_chat(user, SPAN_NOTICE("You splash a small amount of the contents of \the [src] onto \the [target].")) + reagents.splash(target, min(total_vol, 5)) + return TRUE + . = ..() +// End boilerplate. + +/obj/item/chems/cooking_vessel/proc/get_cooking_contents_strings() + + . = list() + + for(var/obj/item/thing in get_stored_inventory()) + . += "\the [thing]" + + if(REAGENT_TOTAL_VOLUME(reagents)) + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(reagents)) + . += "[SOLID_VOLUME(reagents, reagent)]u of [reagent.get_reagent_name(reagents, MAT_PHASE_SOLID)]" + + var/datum/gas_mixture/environment = loc?.return_air() + var/ambient_pressure = environment ? environment.return_pressure() : ONE_ATMOSPHERE + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(reagents)) + var/reagent_name = reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID) + if(reagent.phase_at_temperature(temperature, ambient_pressure) == MAT_PHASE_GAS && reagent.soup_hot_desc) + . += "[LIQUID_VOLUME(reagents, reagent)]u of [reagent.soup_hot_desc] [reagent_name]" + else + . += "[LIQUID_VOLUME(reagents, reagent)]u of [reagent_name]" + +/obj/item/chems/cooking_vessel/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(user && distance <= 1) + var/list/contents_strings = get_cooking_contents_strings() + if(length(contents_strings)) + . += SPAN_NOTICE("\The [src] contains:") + for(var/content_string in contents_strings) + . += SPAN_NOTICE("- [content_string]") + else + . += SPAN_NOTICE("\The [src] is empty.") + +/obj/item/chems/cooking_vessel/Process() + var/decl/recipe/recipe = select_recipe(cooking_category, src, temperature) + if(!recipe) // Too hot, too cold, ingredients changed. + //TODO fail last recipe + started_cooking = null + last_recipe = null + QDEL_NULL(work_sound_token) + return PROCESS_KILL + if(isnull(started_cooking) || recipe != last_recipe) + started_cooking = world.time + else if((world.time - started_cooking) >= recipe.cooking_time) + recipe.produce_result(src) + recipe = select_recipe(cooking_category, src, temperature) + if(recipe && recipe == last_recipe && recipe.can_bulk_cook) + // Bulk cooking has benefits like reduced cook time + // we don't just do it instantly because there's messages each time + started_cooking = world.time + (recipe.cooking_time / 5) + else + started_cooking = null + last_recipe = null + return + last_recipe = recipe + if(!work_sound_token) + work_sound_token = play_looping_sound(src, sound_id, work_sound, volume = 30) + update_icon() + +/obj/item/chems/cooking_vessel/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(material.reflectiveness >= MAT_VALUE_SHINY && check_state_in_icon("[icon_state]-shine", icon)) + var/mutable_appearance/shine = mutable_appearance(icon, "[icon_state]-shine", adjust_brightness(color, 20 + material.reflectiveness)) + shine.alpha = material.reflectiveness * 3 + add_overlay(shine) + +/obj/item/chems/cooking_vessel/Entered() + . = ..() + started_cooking = null + if(!is_processing) + START_PROCESSING(SSobj, src) + update_icon() + +/obj/item/chems/cooking_vessel/on_reagent_change() + if(!(. = ..())) + return + started_cooking = null + if(!is_processing) + START_PROCESSING(SSobj, src) + update_icon() + +/obj/item/chems/cooking_vessel/Destroy() + if(is_processing) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/chems/cooking_vessel/ProcessAtomTemperature() + . = ..() + if(. != PROCESS_KILL && !is_processing) + START_PROCESSING(SSobj, src) + update_icon() diff --git a/code/modules/food/cooking/cooking_vessels/baking_dish.dm b/code/modules/food/cooking/cooking_vessels/baking_dish.dm new file mode 100644 index 000000000000..e9cd7e643902 --- /dev/null +++ b/code/modules/food/cooking/cooking_vessels/baking_dish.dm @@ -0,0 +1,22 @@ +/obj/item/chems/cooking_vessel/baking_dish + name = "baking dish" + desc = "A large baking dish for baking things." + icon = 'icons/obj/food/cooking_vessels/baking_dish.dmi' + chem_volume = 100 + cooking_category = RECIPE_CATEGORY_BAKING_DISH + presentation_flags = PRESENTATION_FLAG_NAME + obj_flags = OBJ_FLAG_HOLLOW | OBJ_FLAG_INSULATED_HANDLE // TODO: dynamically add/remove OBJ_FLAG_INSULATED_HANDLE based on handle material? + material = /decl/material/solid/stone/ceramic + color = /decl/material/solid/stone/ceramic::color + +/obj/item/chems/cooking_vessel/baking_dish/earthenware + material = /decl/material/solid/stone/pottery + color = /decl/material/solid/stone/pottery::color + +// Baking dishes have to be in a kiln or oven (structure or machine) to cook. +// Holding it in your hands or having it on a turf doesn't count. +// TODO: Refactor to use COOKING_HEAT_INDIRECT and air temperature! +/obj/item/chems/cooking_vessel/baking_dish/Process() + if(!(istype(loc, /obj/structure) || istype(loc, /obj/machinery))) + return + return ..() \ No newline at end of file diff --git a/code/modules/food/cooking/cooking_vessels/pot.dm b/code/modules/food/cooking/cooking_vessels/pot.dm new file mode 100644 index 000000000000..d84c2eca7faf --- /dev/null +++ b/code/modules/food/cooking/cooking_vessels/pot.dm @@ -0,0 +1,66 @@ +/obj/item/chems/cooking_vessel/pot + name = "pot" + desc = "A large pot for boiling things." + icon = 'icons/obj/food/cooking_vessels/pot.dmi' + chem_volume = 100 + cooking_category = RECIPE_CATEGORY_POT + presentation_flags = PRESENTATION_FLAG_NAME + obj_flags = OBJ_FLAG_HOLLOW | OBJ_FLAG_INSULATED_HANDLE + work_sound = 'sound/effects/boiling-water.ogg' + var/last_boil_status + var/last_boil_temp + +/obj/item/chems/cooking_vessel/pot/iron + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + +/obj/item/chems/cooking_vessel/pot/get_reagents_overlay(state_prefix) + var/image/our_overlay = ..() + if(our_overlay && last_boil_status && check_state_in_icon("[our_overlay.icon_state]_boiling", our_overlay.icon)) + our_overlay.icon_state = "[our_overlay.icon_state]_boiling" + return our_overlay + +/obj/item/chems/cooking_vessel/pot/on_reagent_change() + last_boil_temp = null + last_boil_status = null + . = ..() + +/obj/item/chems/cooking_vessel/pot/ProcessAtomTemperature() + var/prior_temperature = temperature + . = ..() + // to avoid issues with it cooling down in ..() and reheating the same tick, we use the highest of the two + // todo: just prevent the cooling instead, for a less-hacky solution + var/use_temperature = max(temperature, prior_temperature) + var/datum/gas_mixture/environment = loc?.return_air() + var/ambient_pressure = environment ? environment.return_pressure() : ONE_ATMOSPHERE + + // Largely ignore return value so we don't skip this update on the final time we temperature process. + if(use_temperature != last_boil_temp) + + last_boil_temp = use_temperature + var/next_boil_status = FALSE + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.phase_at_temperature(use_temperature, ambient_pressure) == MAT_PHASE_GAS) + next_boil_status = TRUE + break + + if(next_boil_status != last_boil_status) + last_boil_status = next_boil_status + update_icon() + + if(. == PROCESS_KILL) + last_boil_temp = null + last_boil_status = null + +/obj/item/chems/cooking_vessel/cauldron + name = "cauldron" + desc = "A large round-bodied vessel for making large quantities of potion or soup." + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + icon = 'icons/obj/food/cooking_vessels/cauldron.dmi' + chem_volume = 1000 + w_class = ITEM_SIZE_STRUCTURE + density = TRUE + +/obj/item/chems/cooking_vessel/cauldron/can_be_picked_up(mob/user) + return FALSE diff --git a/code/modules/food/cooking/cooking_vessels/skillet.dm b/code/modules/food/cooking/cooking_vessels/skillet.dm new file mode 100644 index 000000000000..761a6e0b0e73 --- /dev/null +++ b/code/modules/food/cooking/cooking_vessels/skillet.dm @@ -0,0 +1,11 @@ +/obj/item/chems/cooking_vessel/skillet + name = "skillet" + desc = "A shallow pan for frying food." + icon = 'icons/obj/food/cooking_vessels/skillet.dmi' + chem_volume = 30 + cooking_category = RECIPE_CATEGORY_SKILLET + obj_flags = OBJ_FLAG_HOLLOW | OBJ_FLAG_INSULATED_HANDLE + +/obj/item/chems/cooking_vessel/skillet/iron + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color diff --git a/code/modules/food/cooking/recipes/recipe_assembled.dm b/code/modules/food/cooking/recipes/recipe_assembled.dm new file mode 100644 index 000000000000..863129f6f12f --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_assembled.dm @@ -0,0 +1,45 @@ +// TODO: make all of these into handcrafted items +/decl/recipe/sandwich + display_name = "plain sandwich" + items = list( + /obj/item/food/meatsteak, + /obj/item/food/slice/bread = 2, + /obj/item/food/dairy/cheese/wedge, + ) + result = /obj/item/food/sandwich + +/decl/recipe/bigbiteburger + items = list( + /obj/item/food/burger, + /obj/item/food/butchery/meat = 2, + /obj/item/food/egg, + ) + reagent_mix = REAGENT_REPLACE // no raw egg + result = /obj/item/food/bigbiteburger + +/decl/recipe/superbiteburger + fruit = list("tomato" = 1) + reagents = list(/decl/material/solid/sodiumchloride = 5, /decl/material/solid/blackpepper = 5) + items = list( + /obj/item/food/bigbiteburger, + /obj/item/food/dough, + /obj/item/food/butchery/meat, + /obj/item/food/dairy/cheese/wedge, + /obj/item/food/boiledegg, + ) + result = /obj/item/food/superbiteburger + +/decl/recipe/twobread + reagents = list(/decl/material/liquid/alcohol/wine = 5) + items = list( + /obj/item/food/slice/bread = 2, + ) + result = /obj/item/food/twobread + +/decl/recipe/taco + items = list( + /obj/item/food/unleaveneddoughslice, + /obj/item/food/butchery/cutlet, + /obj/item/food/dairy/cheese/wedge + ) + result = /obj/item/food/taco diff --git a/code/modules/food/cooking/recipes/recipe_baked.dm b/code/modules/food/cooking/recipes/recipe_baked.dm new file mode 100644 index 000000000000..a549e1b3f8a8 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_baked.dm @@ -0,0 +1,345 @@ +/decl/recipe/baked + abstract_type = /decl/recipe/baked + container_categories = list( + RECIPE_CATEGORY_MICROWAVE, + RECIPE_CATEGORY_BAKING_DISH + ) + // some arbitrary value to make sure it doesn't cook in open air, but will when microwaved + // todo: rework futurecooking so that microwaves aren't the only appliance for everything (modern stove, oven, fryer, etc) + minimum_temperature = 80 CELSIUS + //cooking_heat_type = COOKING_HEAT_INDIRECT + +/decl/recipe/baked/pizzamargherita + fruit = list("tomato" = 1) + items = list( + /obj/item/food/sliceable/flatdough, + /obj/item/food/dairy/cheese/wedge = 3, + ) + result = /obj/item/food/sliceable/pizza/margherita + +/decl/recipe/baked/meatpizza + fruit = list("tomato" = 1) + items = list( + /obj/item/food/sliceable/flatdough, + /obj/item/food/butchery/cutlet = 2, + /obj/item/food/dairy/cheese/wedge + ) + result = /obj/item/food/sliceable/pizza/meatpizza + +/decl/recipe/baked/mushroompizza + fruit = list("mushroom" = 5, "tomato" = 1) + items = list( + /obj/item/food/sliceable/flatdough, + /obj/item/food/dairy/cheese/wedge + ) + result = /obj/item/food/sliceable/pizza/mushroompizza + +/decl/recipe/baked/vegetablepizza + fruit = list("eggplant" = 1, "carrot" = 1, "corn" = 1, "tomato" = 1) + items = list( + /obj/item/food/sliceable/flatdough, + /obj/item/food/dairy/cheese/wedge + ) + result = /obj/item/food/sliceable/pizza/vegetablepizza + +/decl/recipe/baked/amanita_pie + reagents = list(/decl/material/liquid/amatoxin = 5) + items = list(/obj/item/food/piecrust) + result = /obj/item/food/amanita_pie + +/decl/recipe/baked/pumpkinpie + fruit = list("pumpkin" = 1) + reagents = list(/decl/material/liquid/nutriment/sugar = 5) + items = list(/obj/item/food/piecrust) + reagent_mix = REAGENT_REPLACE // no raw flour + result = /obj/item/food/sliceable/pumpkinpie + +/decl/recipe/baked/bananapie + fruit = list("banana" = 1) + reagents = list(/decl/material/liquid/nutriment/sugar = 5) + items = list(/obj/item/food/piecrust) + result = /obj/item/food/bananapie + +/decl/recipe/baked/cherrypie + fruit = list("cherries" = 1) + reagents = list(/decl/material/liquid/nutriment/sugar = 10) + items = list( + /obj/item/food/piecrust, + ) + result = /obj/item/food/cherrypie + +/decl/recipe/baked/chaosdonut + reagents = list(/decl/material/liquid/frostoil = 5, /decl/material/liquid/capsaicin = 5, /decl/material/liquid/nutriment/sugar = 5) + items = list( + /obj/item/food/dough + ) + result = /obj/item/food/donut/chaos + +/decl/recipe/baked/donut + display_name = "plain donut" + reagents = list(/decl/material/liquid/nutriment/sugar = 5) + items = list( + /obj/item/food/dough + ) + result = /obj/item/food/donut + +/decl/recipe/baked/donut/jelly + display_name = "berry jelly donut" + reagents = list(/decl/material/liquid/drink/juice/berry = 5, /decl/material/liquid/nutriment/sugar = 5) + result = /obj/item/food/donut/jelly + +/decl/recipe/baked/donut/jelly/cherry + display_name = "cherry jelly donut" + reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5, /decl/material/liquid/nutriment/sugar = 5) + +/decl/recipe/baked/meatbread + display_name = "plain meatbread loaf" + items = list( + /obj/item/food/dough = 2, + /obj/item/food/butchery/cutlet = 2, + /obj/item/food/dairy/cheese/wedge = 2, + ) + result = /obj/item/food/sliceable/meatbread + +/decl/recipe/baked/xenomeatbread + items = list( + /obj/item/food/dough = 2, + /obj/item/food/butchery/meat/xeno = 2, + /obj/item/food/dairy/cheese/wedge = 2, + ) + result = /obj/item/food/sliceable/xenomeatbread + +/decl/recipe/baked/bananabread + fruit = list("banana" = 2) + reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/sugar = 5) + items = list( + /obj/item/food/dough = 2, + ) + result = /obj/item/food/sliceable/bananabread + +/decl/recipe/baked/soylenviridians + fruit = list("soybeans" = 1) + reagents = list(/decl/material/liquid/nutriment/flour = 10) + reagent_mix = REAGENT_REPLACE // no raw flour + result = /obj/item/food/soylenviridians + +/decl/recipe/baked/soylentgreen + reagents = list(/decl/material/liquid/nutriment/flour = 10) + items = list( + /obj/item/food/butchery/meat/human = 2 + ) + reagent_mix = REAGENT_REPLACE // no raw flour + result = /obj/item/food/soylentgreen + +/decl/recipe/baked/tofubread + items = list( + /obj/item/food/dough = 3, + /obj/item/food/tofu = 3, + /obj/item/food/dairy/cheese/wedge = 3, + ) + result = /obj/item/food/sliceable/tofubread + +/decl/recipe/baked/cookie + display_name = "plain cookie" + reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 5, /decl/material/liquid/nutriment/coco = 5) + reagent_mix = REAGENT_REPLACE // no raw batter + result = /obj/item/food/cookie + +/decl/recipe/baked/fortunecookie + reagents = list(/decl/material/liquid/nutriment/sugar = 5) + items = list( + /obj/item/food/unleaveneddoughslice, + /obj/item/paper, + ) + result = /obj/item/food/fortunecookie + +/decl/recipe/baked/fortunecookie/produce_result(obj/container) + var/obj/item/paper/paper = locate() in container + paper.forceMove(null) //prevent deletion + var/list/obj/item/food/fortunecookie/results = ..(container) + for(var/obj/item/food/fortunecookie/being_cooked in results) + paper.forceMove(being_cooked) + being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn + return results + +/decl/recipe/baked/fortunecookie/check_items(var/obj/container) + . = ..() + if(.) + var/obj/item/paper/paper = locate() in container + if(!paper || !paper.info) + return FALSE + +/decl/recipe/baked/muffin + reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 10) + result = /obj/item/food/muffin + +/decl/recipe/baked/eggplantparm + fruit = list("eggplant" = 1) + items = list( + /obj/item/food/dairy/cheese/wedge = 2 + ) + result = /obj/item/food/eggplantparm + +/decl/recipe/baked/enchiladas + fruit = list("chili" = 2, "corn" = 1) + items = list(/obj/item/food/butchery/cutlet) + result = /obj/item/food/enchiladas + +/decl/recipe/baked/creamcheesebread + items = list( + /obj/item/food/dough = 2, + /obj/item/food/dairy/cheese/wedge = 2, + ) + result = /obj/item/food/sliceable/creamcheesebread + +/decl/recipe/baked/monkeysdelight + fruit = list("banana" = 1) + reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1, /decl/material/liquid/nutriment/flour = 10) + items = list( + /obj/item/food/animal_cube/monkey + ) + result = /obj/item/food/monkeysdelight + +/decl/recipe/baked/baguette + reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) + items = list( + /obj/item/food/dough = 2, + ) + result = /obj/item/food/baguette + +/decl/recipe/baked/bread + display_name = "loaf of bread" + items = list( + /obj/item/food/dough = 2 + ) + reagent_mix = REAGENT_REPLACE // no raw dough + result = /obj/item/food/sliceable/bread + +/decl/recipe/baked/jelliedtoast + reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5) + items = list( + /obj/item/food/slice/bread, + ) + result = /obj/item/food/jelliedtoast/cherry + +/decl/recipe/baked/rofflewaffles + reagents = list(/decl/material/liquid/psychotropics = 5, /decl/material/liquid/nutriment/batter/cakebatter = 20) + result = /obj/item/food/rofflewaffles + +/decl/recipe/baked/poppypretzel + fruit = list("poppy" = 1) + items = list(/obj/item/food/dough) + result = /obj/item/food/poppypretzel + +/decl/recipe/baked/plumphelmetbiscuit + fruit = list("plumphelmet" = 1) + reagents = list(/decl/material/liquid/nutriment/batter = 10) + result = /obj/item/food/plumphelmetbiscuit + +/decl/recipe/baked/plumphelmetbiscuitvegan + display_name = "vegan plump biscuit" + fruit = list("plumphelmet" = 1) + reagents = list(/decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/water = 10) + result = /obj/item/food/plumphelmetbiscuit + +/decl/recipe/baked/appletart + fruit = list("goldapple" = 1) + items = list(/obj/item/food/piecrust) + reagent_mix = REAGENT_REPLACE // no raw flour + result = /obj/item/food/appletart + +/decl/recipe/baked/cracker + reagents = list(/decl/material/solid/sodiumchloride = 1) + items = list( + /obj/item/food/unleaveneddoughslice + ) + result = /obj/item/food/cracker + +/decl/recipe/baked/tofurkey + items = list( + /obj/item/food/tofu = 2, + /obj/item/food/stuffing, + ) + result = /obj/item/food/tofurkey + +/decl/recipe/baked/bun + display_name = "plain bun" + items = list( + /obj/item/food/doughslice + ) + result = /obj/item/food/bun + +/decl/recipe/baked/flatbread + items = list( + /obj/item/food/sliceable/unleaveneddough + ) + result = /obj/item/food/flatbread + +/decl/recipe/baked/cake + reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60) + reagent_mix = REAGENT_REPLACE // no raw batter + result = /obj/item/food/sliceable/plaincake + +/decl/recipe/baked/cake/carrot + fruit = list("carrot" = 3) + result = /obj/item/food/sliceable/carrotcake + +/decl/recipe/baked/cake/cheese + items = list( + /obj/item/food/dairy/cheese/wedge = 2 + ) + result = /obj/item/food/sliceable/cheesecake + +/decl/recipe/baked/cake/orange + fruit = list("orange" = 1) + result = /obj/item/food/sliceable/orangecake + +/decl/recipe/baked/cake/lime + fruit = list("lime" = 1) + result = /obj/item/food/sliceable/limecake + +/decl/recipe/baked/cake/lemon + fruit = list("lemon" = 1) + result = /obj/item/food/sliceable/lemoncake + +/decl/recipe/baked/cake/chocolate + items = list(/obj/item/food/chocolatebar) + result = /obj/item/food/sliceable/chocolatecake + +/decl/recipe/baked/cake/birthday + reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60, /decl/material/liquid/nutriment/sprinkles = 10) + result = /obj/item/food/sliceable/birthdaycake + +/decl/recipe/baked/cake/apple + fruit = list("apple" = 2) + result = /obj/item/food/sliceable/applecake + +/decl/recipe/baked/cake/brain + items = list(/obj/item/organ/internal/brain) + result = /obj/item/food/sliceable/braincake + +// Stub recipes for cooking pies. +/decl/recipe/baked/meatpie + items = list(/obj/item/food/meatpie/raw) + result = /obj/item/food/meatpie +/decl/recipe/baked/tofupie + items = list(/obj/item/food/tofupie/raw) + result = /obj/item/food/tofupie +/decl/recipe/baked/xemeatpie + items = list(/obj/item/food/xemeatpie/raw) + result = /obj/item/food/xemeatpie +/decl/recipe/baked/applepie + items = list(/obj/item/food/applepie/raw) + result = /obj/item/food/applepie +/decl/recipe/baked/berryclafoutis + items = list(/obj/item/food/berryclafoutis/raw) + result = /obj/item/food/berryclafoutis +/decl/recipe/baked/plump_pie + items = list(/obj/item/food/plump_pie/raw) + result = /obj/item/food/plump_pie +/decl/recipe/baked/loadedbakedpotato + items = list(/obj/item/food/loadedbakedpotato/raw) + result = /obj/item/food/loadedbakedpotato +/decl/recipe/baked/cheesyfries + items = list(/obj/item/food/cheesyfries/uncooked) + result = /obj/item/food/cheesyfries diff --git a/code/modules/food/cooking/recipes/recipe_boiled.dm b/code/modules/food/cooking/recipes/recipe_boiled.dm new file mode 100644 index 000000000000..031bd5a164ab --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_boiled.dm @@ -0,0 +1,46 @@ +/decl/recipe/boiled + abstract_type = /decl/recipe/boiled + minimum_temperature = 80 CELSIUS // increase to /decl/material/liquid/water::boiling_point once microwaves are reworked + //cooking_heat_type = COOKING_HEAT_INDIRECT + //cooking_medium_type = /decl/material/liquid/water + //cooking_medium_amount = 20 + reagent_mix = REAGENT_REPLACE // no raw egg or water + reagents = list( + /decl/material/liquid/water = 10 + ) + container_categories = list( + RECIPE_CATEGORY_MICROWAVE, + RECIPE_CATEGORY_POT + ) + +/decl/recipe/boiled/egg + items = list(/obj/item/food/egg) + result = /obj/item/food/boiledegg + completion_message = "The egg hardens as it is cooked through." + +/decl/recipe/boiled/rice + reagents = list( + /decl/material/liquid/water = 10, + /decl/material/liquid/nutriment/rice = 10 + ) + result = /obj/item/food/boiledrice + completion_message = "The rice steams and softens as it is cooked through." + +/decl/recipe/boiled/spagetti + items = list(/obj/item/food/spagetti) + result = /obj/item/food/boiledspagetti + completion_message = "The spaghetti steams and softens as it is cooked through." + +/decl/recipe/boiled/spiderleg + items = list(/obj/item/food/spider) + result = /obj/item/food/spider/cooked + completion_message = "The gelatious spider meat firms up as it is cooked through." + +/decl/recipe/boiled/pelmeni + items = list(/obj/item/food/pelmen = 5) + result = /obj/item/food/pelmeni_boiled + completion_message = "The pelmeni firm up as they are cooked through." + +/decl/recipe/boiled/stewedsoymeat + fruit = list("carrot" = 1, "tomato" = 1, "soybeans chopped" = 2) + result = /obj/item/food/stewedsoymeat diff --git a/code/modules/food/cooking/recipes/recipe_fried.dm b/code/modules/food/cooking/recipes/recipe_fried.dm new file mode 100644 index 000000000000..7d6dcc2bc77c --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_fried.dm @@ -0,0 +1,76 @@ +/decl/recipe/fried + abstract_type = /decl/recipe/fried + // some arbitrary value to make sure it doesn't cook in open air, but will when microwaved + // todo: rework futurecooking so that microwaves aren't the only appliance for everything (modern stove, oven, fryer, etc) + minimum_temperature = 80 CELSIUS + //cooking_heat_type = COOKING_HEAT_DIRECT + //cooking_medium_type = /decl/material/liquid/oil + container_categories = list( + RECIPE_CATEGORY_MICROWAVE, + RECIPE_CATEGORY_SKILLET + ) + +/decl/recipe/fried/waffles + // salt is to disambiguate from vanilla cake + reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 20, /decl/material/solid/sodiumchloride = 1) + result = /obj/item/food/waffles + completion_message = "The waffles firm up and brown as the batter is cooked through." + +/decl/recipe/fried/pancakesblu + reagents = list(/decl/material/liquid/nutriment/batter = 20) + fruit = list("blueberries" = 2) + result = /obj/item/food/pancakesblu + completion_message = "The pancakes firm up and brown as the batter is cooked through." + +/decl/recipe/fried/pancakes + display_name = "plain pancakes" + reagents = list(/decl/material/liquid/nutriment/batter = 20) + result = /obj/item/food/pancakes + completion_message = "The pancakes firm up and brown as the batter is cooked through." + +/decl/recipe/fried/friedegg + reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) + items = list( + /obj/item/food/egg + ) + reagent_mix = REAGENT_REPLACE // no raw egg + result = /obj/item/food/friedegg + completion_message = "The egg spits and sizzles as it cooks through." + +/decl/recipe/fried/omelette + items = list( + /obj/item/food/egg = 2, + /obj/item/food/dairy/cheese/wedge, + ) + reagent_mix = REAGENT_REPLACE // no raw egg + result = /obj/item/food/omelette + completion_message = "The omelette firms up as it cooks through." + +/decl/recipe/fried/cubancarp + fruit = list("chili" = 1) + reagents = list(/decl/material/liquid/nutriment/batter = 10) + items = list( + /obj/item/food/butchery/meat/fish + ) + result = /obj/item/food/cubancarp + completion_message = "The batter darkens to a rich golden brown as the fish is cooked through." + +/decl/recipe/fried/fishandchips + items = list( + /obj/item/food/fries, + /obj/item/food/butchery/meat/fish + ) + result = /obj/item/food/fishandchips + completion_message = "The batter darkens to a rich golden brown as the fish is cooked through." + +/decl/recipe/fried/onionrings + fruit = list("onion" = 1) + reagents = list(/decl/material/liquid/nutriment/batter = 10) + result = /obj/item/food/onionrings + completion_message = "The batter darkens to a rich golden brown as the onion rings are cooked through." + +/decl/recipe/fried/fries + display_name = "potato chips" + fruit = list("potato sticks" = 1) + result = /obj/item/food/fries + completion_message = "The potato sizzles as as the chips are cooked through." diff --git a/code/modules/food/cooking/recipes/recipe_grilled.dm b/code/modules/food/cooking/recipes/recipe_grilled.dm new file mode 100644 index 000000000000..cf6896a827c3 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_grilled.dm @@ -0,0 +1,84 @@ +/decl/recipe/grilled + abstract_type = /decl/recipe/grilled + //cooking_heat_type = COOKING_HEAT_DIRECT + container_categories = list( + RECIPE_CATEGORY_MICROWAVE, + RECIPE_CATEGORY_SKILLET + ) + // some arbitrary value to make sure it doesn't cook in open air, but will when microwaved + // todo: rework futurecooking so that microwaves aren't the only appliance for everything (modern stove, oven, fryer, etc) + minimum_temperature = 80 CELSIUS + completion_message = "The meat sizzles as it is cooked through." + +/decl/recipe/grilled/plainsteak + items = list(/obj/item/food/butchery/meat) + result = /obj/item/food/plainsteak + +/decl/recipe/grilled/meatsteak + reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) + items = list(/obj/item/food/butchery/cutlet) + result = /obj/item/food/meatsteak + +/decl/recipe/grilled/loadedsteak + reagents = list(/decl/material/liquid/nutriment/garlicsauce = 5) + fruit = list("onion" = 1, "mushroom" = 1) + items = list(/obj/item/food/butchery/cutlet) + result = /obj/item/food/loadedsteak + completion_message = "The onions and mushroom caramelize around the sizzling meat." + +/decl/recipe/grilled/syntisteak + reagents = list(/decl/material/solid/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) + items = list(/obj/item/food/butchery/meat/syntiflesh) + result = /obj/item/food/meatsteak/synthetic + +/decl/recipe/grilled/toastedsandwich + items = list( + /obj/item/food/sandwich + ) + result = /obj/item/food/toastedsandwich + completion_message = "The outside of the sandwich darkens to a savoury toasted brown." + +/decl/recipe/grilled/grilledcheese + items = list( + /obj/item/food/slice/bread = 2, + /obj/item/food/dairy/cheese/wedge, + ) + result = /obj/item/food/grilledcheese + completion_message = "The bread toasts and the cheese melts together." + +/decl/recipe/grilled/fishfingers + reagents = list(/decl/material/liquid/nutriment/flour = 10) + items = list( + /obj/item/food/egg, + /obj/item/food/butchery/meat/fish + ) + reagent_mix = REAGENT_REPLACE // no raw egg/fish + result = /obj/item/food/fishfingers + completion_message = "The breading browns and fish fillets sizzle as they are cooked through." + +/decl/recipe/grilled/meatball + items = list( + /obj/item/food/meatball/raw + ) + result = /obj/item/food/meatball + +/decl/recipe/grilled/cutlet + items = list( + /obj/item/food/butchery/cutlet/raw + ) + result = /obj/item/food/butchery/cutlet + +/decl/recipe/grilled/meatkabob + items = list( + /obj/item/stack/material/rods, + /obj/item/food/butchery/cutlet = 2 + ) + result = /obj/item/food/skewer/meat + +/decl/recipe/grilled/tofukabob + items = list( + /obj/item/stack/material/rods, + /obj/item/food/tofu = 2, + ) + result = /obj/item/food/skewer/tofu + completion_message = "The tofu sizzles and browns as it is cooked through." diff --git a/code/modules/food/cooking/recipes/recipe_mixed.dm b/code/modules/food/cooking/recipes/recipe_mixed.dm new file mode 100644 index 000000000000..070b23a85e53 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_mixed.dm @@ -0,0 +1,19 @@ +/decl/recipe/chocolateegg + items = list( + /obj/item/food/egg, + /obj/item/food/chocolatebar, + ) + reagent_mix = REAGENT_REPLACE // no raw egg + result = /obj/item/food/chocolateegg + +/decl/recipe/candiedapple + fruit = list("apple" = 1) + reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/sugar = 5) + result = /obj/item/food/candiedapple + +/decl/recipe/cherrysandwich + reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5) + items = list( + /obj/item/food/slice/bread = 2, + ) + result = /obj/item/food/jellysandwich/cherry diff --git a/code/modules/food/cooking/recipes/recipe_pasta.dm b/code/modules/food/cooking/recipes/recipe_pasta.dm new file mode 100644 index 000000000000..c7efcfa4c0c2 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_pasta.dm @@ -0,0 +1,11 @@ +// Notes on process: +// - Boil pasta +// - Put pasta on plate +// - Boil or simmer sauce +// - Put sauce in pasta + +/decl/recipe/pastatomato + fruit = list("tomato" = 2) + reagents = list(/decl/material/liquid/water = 10) + items = list(/obj/item/food/spagetti) + result = /obj/item/food/pastatomato diff --git a/code/modules/food/cooking/recipes/recipe_soup.dm b/code/modules/food/cooking/recipes/recipe_soup.dm new file mode 100644 index 000000000000..47ec28c55cd9 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup.dm @@ -0,0 +1,85 @@ +/* + Soups to readd when we have ingredients: + - Dashi stock (dried seaweed, fish flakes). + - Miso soup (miso paste, tofu and veg in dashi stock). + - Proper chicken katsu (crumbed chicken object added to curry). + - Curry on rice. + Soups to add when someone can be bothered: + - Egg drop soup: regular soup + 3u egg, uses egg overlay. + - Proper curry spices, coconut milk, for curry making. + - Cheese soups - will need ALLERGEN_CHEESE to be checked alongside ALLERGEN_DAIRY. +*/ + +/decl/recipe/soup + abstract_type = /decl/recipe/soup + reagent_mix = REAGENT_REPLACE + container_categories = list(RECIPE_CATEGORY_POT) + minimum_temperature = 100 CELSIUS + result_quantity = 10 + can_bulk_cook = TRUE + var/precursor_type + /// Whether the ingredients' colours are mixed into our DATA_EXTRA_COLOR, useful for veggie soup adding vegetable bits. + var/has_extra_color = TRUE + +/decl/recipe/soup/get_result_data(atom/container, list/used_ingredients) + + . = list() + var/allergen_flags = ALLERGEN_NONE + var/list/taste_strings = list() + var/list/ingredients = list() + var/list/used_items = used_ingredients[RECIPE_COMPONENT_ITEMS] + var/list/filling_colors = list() + + if(length(used_items)) + + for(var/obj/item/ingredient in used_items) + var/obj/item/food/food = ingredient + var/list/food_tastes = food.reagents.get_taste_list() + if(istype(food)) + for(var/taste in food_tastes) + taste_strings[taste] = max(taste_strings[taste], food_tastes[taste]) + allergen_flags |= food.allergen_flags + if(has_extra_color) + filling_colors += food.get_food_filling_color() // may want more specific behaviour at some point + + if(locate(/obj/item/food/grown) in used_items) + for(var/obj/item/food/grown/veg in used_items) + if(veg.seed) + ingredients[veg.seed.product_name]++ + + if(locate(/obj/item/food/processed_grown) in used_items) + for(var/obj/item/food/processed_grown/veg in used_items) + if(veg.seed) + ingredients[veg.seed.product_name]++ + + if(locate(/obj/item/food/butchery) in used_items) + for(var/obj/item/food/butchery/meat in used_items) + if(meat.meat_name) + ingredients[meat.meat_name]++ + + if(precursor_type) + var/list/precursor_data = REAGENT_DATA(container.reagents, precursor_type) + var/list/precursor_taste = LAZYACCESS(precursor_data, DATA_TASTE) + if(length(precursor_taste)) + for(var/taste in precursor_taste) + taste_strings[taste] += precursor_taste[taste] + var/list/precursor_ingredients = LAZYACCESS(precursor_data, DATA_INGREDIENT_LIST) + if(length(precursor_ingredients)) + for(var/ingredient in precursor_ingredients) + ingredients[ingredient] += precursor_ingredients[ingredient] + var/precursor_allergen_flags = LAZYACCESS(precursor_data, DATA_INGREDIENT_FLAGS) + if(precursor_allergen_flags) + allergen_flags |= precursor_allergen_flags + // extra_color is blended in mix_data, we just add it here + var/precursor_extra_color = LAZYACCESS(precursor_data, DATA_EXTRA_COLOR) + if(precursor_extra_color) + filling_colors += precursor_extra_color + + if(length(taste_strings)) + .[DATA_TASTE] = taste_strings + if(length(ingredients)) + .[DATA_INGREDIENT_LIST] = ingredients + if(allergen_flags) + .[DATA_INGREDIENT_FLAGS] = allergen_flags + if(length(filling_colors)) + .[DATA_EXTRA_COLOR] = MixColors(filling_colors) diff --git a/code/modules/food/cooking/recipes/recipe_soup_chili.dm b/code/modules/food/cooking/recipes/recipe_soup_chili.dm new file mode 100644 index 000000000000..51fd558a381d --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup_chili.dm @@ -0,0 +1,26 @@ +/decl/recipe/soup/chili + abstract_type = /decl/recipe/soup/chili + result = /decl/material/liquid/nutriment/soup/chili + reagents = list(/decl/material/liquid/water = 5) + completion_message = "The sauce thickens as the chili cooks down." + complexity = 3 + +/decl/recipe/soup/chili/hot + display_name = "hot meat chili" + fruit = list("chili" = 1, "tomato chopped" = 1) + items = list(/obj/item/food/butchery/chopped = 1) + +/decl/recipe/soup/chili/hot/vegetarian + display_name = "hot vegetarian chili" + items = list(/obj/item/food/processed_grown/chopped = 2) + complexity = 0 + +/decl/recipe/soup/chili/cold + display_name = "cold meat chili" + fruit = list("icechili" = 1, "tomato chopped" = 1) + items = list(/obj/item/food/butchery/chopped = 1) + +/decl/recipe/soup/chili/cold/vegetarian + display_name = "cold vegetarian chili" + items = list(/obj/item/food/processed_grown/chopped = 1) + complexity = 0 diff --git a/code/modules/food/cooking/recipes/recipe_soup_curry.dm b/code/modules/food/cooking/recipes/recipe_soup_curry.dm new file mode 100644 index 000000000000..737dbec9fad7 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup_curry.dm @@ -0,0 +1,26 @@ +/decl/recipe/soup/curry + abstract_type = /decl/recipe/soup/curry + result = /decl/material/liquid/nutriment/soup/curry + completion_message = "The sauce thickens as the curry cooks down." + // It's silly to distinguish this from other recipes only via rice, but + // we don't have curry powder or other spices to include here. TODO. + reagents = list( + /decl/material/liquid/water = 5, + /decl/material/liquid/nutriment/rice = 5 + ) + +/decl/recipe/soup/curry/meat + display_name = "meat curry" + items = list(/obj/item/food/butchery/chopped = 2) + +/decl/recipe/soup/curry/veg + display_name = "vegetarian curry" + items = list(/obj/item/food/processed_grown/chopped = 2) + +/decl/recipe/soup/curry/mixed + display_name = "mixed curry" + items = list( + /obj/item/food/butchery/chopped = 1, + /obj/item/food/processed_grown/chopped = 1 + ) + complexity = 3 // So it takes precedence over pure meat or pure veggie curry. diff --git a/code/modules/food/cooking/recipes/recipe_soup_noodle.dm b/code/modules/food/cooking/recipes/recipe_soup_noodle.dm new file mode 100644 index 000000000000..08e1aa77439f --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup_noodle.dm @@ -0,0 +1,7 @@ +/decl/recipe/soup/noodle + result = /decl/material/liquid/nutriment/soup/noodle + precursor_type = /decl/material/liquid/nutriment/soup/simple + completion_message = "The noodles soften as they cook in the soup." + reagents = list(/decl/material/liquid/nutriment/soup/simple = 10) + items = list(/obj/item/food/spagetti = 1) + has_extra_color = FALSE // Don't give us noodle coloured bits \ No newline at end of file diff --git a/code/modules/food/cooking/recipes/recipe_soup_simple.dm b/code/modules/food/cooking/recipes/recipe_soup_simple.dm new file mode 100644 index 000000000000..8f6a3852e047 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup_simple.dm @@ -0,0 +1,66 @@ +/decl/recipe/soup/simple + abstract_type = /decl/recipe/soup/simple + result = /decl/material/liquid/nutriment/soup/simple + reagents = list(/decl/material/liquid/nutriment/soup/stock = 10) + completion_message = "A savoury smell rises from the soup as the ingredients release their flavour into the broth." + precursor_type = /decl/material/liquid/nutriment/soup/stock + complexity = 5 // Setting high by default so it takes priority over stew. + +/decl/recipe/soup/simple/meatball + display_name = "meatball soup" + items = list(/obj/item/food/meatball = 1) + +/decl/recipe/soup/simple/meat + display_name = "simple meat soup" + items = list(/obj/item/food/butchery/chopped = 1) + +/decl/recipe/soup/simple/veg + display_name = "simple vegetable soup" + items = list(/obj/item/food/processed_grown/chopped = 1) + +/decl/recipe/soup/simple/blood + display_name = "blood soup" + reagents = list(/decl/material/liquid/blood = 10) + completion_message = "The blood thickens and partially congeals as it cooks." + precursor_type = null + +/decl/recipe/soup/simple/blood/get_result_data(atom/container, list/used_ingredients) + . = list( + DATA_INGREDIENT_LIST = list("blood" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_MEAT, + DATA_TASTE = list("iron and copper" = 5), +// DATA_MASK_NAME = "tomato soup" // Maybe? + ) + +/decl/recipe/soup/simple/milk + abstract_type = /decl/recipe/soup/simple/milk + reagents = list(/decl/material/liquid/drink/milk = 10) + precursor_type = null + +/decl/recipe/soup/simple/milk/get_result_data(atom/container, list/used_ingredients) + . = ..() + // Consider prefixing 'cream of' for milk soups? + LAZYINITLIST(.) + var/cream = LAZYACCESS(.[DATA_TASTE], "cream") + LAZYSET(.[DATA_TASTE], "cream", cream + 1) + LAZYDISTINCTADD(.[DATA_INGREDIENT_FLAGS], ALLERGEN_DAIRY) + +/decl/recipe/soup/simple/milk/meat + display_name = "simple meat milk soup" + items = list(/obj/item/food/butchery/chopped = 1) + +/decl/recipe/soup/simple/milk/veg + display_name = "simple vegetable milk soup" + items = list(/obj/item/food/processed_grown/chopped = 1) + +/decl/recipe/soup/simple/milk/cream + abstract_type = /decl/recipe/soup/simple/milk/cream + reagents = list(/decl/material/liquid/drink/milk/cream = 10) + +/decl/recipe/soup/simple/milk/cream/meat + display_name = "simple meat cream soup" + items = list(/obj/item/food/butchery/chopped = 1) + +/decl/recipe/soup/simple/milk/cream/veg + display_name = "simple vegetable cream soup" + items = list(/obj/item/food/processed_grown/chopped = 1) diff --git a/code/modules/food/cooking/recipes/recipe_soup_stew.dm b/code/modules/food/cooking/recipes/recipe_soup_stew.dm new file mode 100644 index 000000000000..765f9e5106d7 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup_stew.dm @@ -0,0 +1,26 @@ +/decl/recipe/soup/stew + abstract_type = /decl/recipe/soup/stew + precursor_type = /decl/material/liquid/nutriment/soup/simple + reagents = list(/decl/material/liquid/nutriment/soup/simple = 10) + result = /decl/material/liquid/nutriment/soup/stew + completion_message = "A savoury smell rises from the soup as the ingredients release their flavour into the broth." + +/decl/recipe/soup/stew/mixed + display_name = "mixed stew" + items = list( + /obj/item/food/butchery/chopped = 1, + /obj/item/food/processed_grown/chopped = 1 + ) + complexity = 7 + +/decl/recipe/soup/stew/meat + display_name = "meat stew" + items = list( + /obj/item/food/butchery/chopped = 2 + ) + +/decl/recipe/soup/stew/veg + display_name = "vegetable stew" + items = list( + /obj/item/food/processed_grown/chopped = 2 + ) diff --git a/code/modules/food/cooking/recipes/recipe_soup_stock.dm b/code/modules/food/cooking/recipes/recipe_soup_stock.dm new file mode 100644 index 000000000000..56897d424ee2 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_soup_stock.dm @@ -0,0 +1,31 @@ +/decl/recipe/soup/stock + abstract_type = /decl/recipe/soup/stock + result = /decl/material/liquid/nutriment/soup/stock + complexity = 10 // Setting high by default so it takes priority over simple soup. + completion_message = "The liquid darkens to a rich brown as the meat dissolves." + reagents = list( + /decl/material/solid/sodiumchloride = 1, + /decl/material/liquid/water = 10 + ) + // Broth shouldn't have bits + has_extra_color = FALSE + +/decl/recipe/soup/stock/meat + display_name = "meat stock" + items = list(/obj/item/food/butchery) + +/decl/recipe/soup/stock/vegetable + display_name = "vegetable stock" + items = list(/obj/item/food/grown) + completion_message = "The liquid darkens to a rich brown as the vegetables dissolve." + +/decl/recipe/soup/stock/bone + display_name = "bone broth" + items = list(/obj/item/stack/material/bone = 1) + completion_message = "The liquid darkens to a rich brown as the marrow dissolves." + +/decl/recipe/soup/stock/bone/get_result_data(atom/container, list/used_ingredients) + . = list() + .[DATA_INGREDIENT_LIST] = list("marrow" = 1) + .[DATA_INGREDIENT_FLAGS] = ALLERGEN_MEAT + .[DATA_TASTE] = list("rich marrow" = 5) diff --git a/code/modules/food/cooking/recipes/recipe_steamed.dm b/code/modules/food/cooking/recipes/recipe_steamed.dm new file mode 100644 index 000000000000..746439f6ac28 --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_steamed.dm @@ -0,0 +1,14 @@ +/decl/recipe/steamed + abstract_type = /decl/recipe/steamed + // some arbitrary value to make sure it doesn't cook in open air, but will when microwaved + // todo: rework futurecooking so that microwaves aren't the only appliance for everything (modern stove, oven, fryer, etc) + minimum_temperature = 80 CELSIUS + +/decl/recipe/steamed/chawanmushi + fruit = list("mushroom" = 1) + reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/soysauce = 5) + items = list( + /obj/item/food/egg = 2 + ) + reagent_mix = REAGENT_REPLACE // no raw egg + result = /obj/item/food/chawanmushi diff --git a/code/modules/food/cooking/recipes/recipe_tossed.dm b/code/modules/food/cooking/recipes/recipe_tossed.dm new file mode 100644 index 000000000000..045cc69aebab --- /dev/null +++ b/code/modules/food/cooking/recipes/recipe_tossed.dm @@ -0,0 +1,15 @@ +/decl/recipe/tossed + abstract_type = /decl/recipe/tossed + +/decl/recipe/tossed/salad + fruit = list("cabbage" = 2, "tomato" = 1, "carrot" = 1, "apple" = 1) + result = /obj/item/food/tossedsalad + +/decl/recipe/tossed/aesirsalad + fruit = list("goldapple" = 1, "ambrosiadeus" = 1) + result = /obj/item/food/aesirsalad + +/decl/recipe/tossed/validsalad + fruit = list("potato" = 1, "ambrosiavulgaris" = 3) + items = list(/obj/item/food/meatball) + result = /obj/item/food/validsalad diff --git a/code/modules/food/cooking/recipes/recipes_microwave.dm b/code/modules/food/cooking/recipes/recipes_microwave.dm new file mode 100644 index 000000000000..7b316938f3ac --- /dev/null +++ b/code/modules/food/cooking/recipes/recipes_microwave.dm @@ -0,0 +1,50 @@ +/decl/recipe/popcorn + reagents = list(/decl/material/solid/sodiumchloride = 5) + fruit = list("corn" = 1) + result = /obj/item/food/popcorn + container_categories = list( + RECIPE_CATEGORY_MICROWAVE, + RECIPE_CATEGORY_SKILLET + ) + +/decl/recipe/donkpocket + display_name = "warm donk-pocket" + items = list( + /obj/item/food/donkpocket + ) + result = /obj/item/food/donkpocket + +/decl/recipe/donkpocket/proc/warm_up(var/obj/item/food/donkpocket/being_cooked) + being_cooked.heat() + +/decl/recipe/donkpocket/produce_result(obj/container) + . = ..(container) + for(var/obj/item/food/donkpocket/being_cooked in .) + warm_up(being_cooked) + +/decl/recipe/donkpocket/check_items(obj/container) + . = ..() + if(!.) + return FALSE + for(var/obj/item/food/donkpocket/being_cooked in container.get_contained_external_atoms()) + if(!being_cooked.warm) + return TRUE + return FALSE + +/decl/recipe/mysterysoup + display_name = "Mystery Soup" + items = list( + /obj/item/chems/glass/bowl, + /obj/item/food/badrecipe, + /obj/item/food/tofu, + /obj/item/food/egg, + /obj/item/food/dairy/cheese/wedge + ) + result = /obj/item/chems/glass/bowl/mystery + reagents = list( + /decl/material/liquid/water = 10 + ) + container_categories = list( + RECIPE_CATEGORY_MICROWAVE + ) + reagent_mix = REAGENT_REPLACE // no raw egg or water diff --git a/code/modules/food/nuggets.dm b/code/modules/food/nuggets.dm new file mode 100644 index 000000000000..b148b41b3aa9 --- /dev/null +++ b/code/modules/food/nuggets.dm @@ -0,0 +1,24 @@ +/obj/item/food/nugget + name = "chicken nugget" + icon = 'icons/obj/food/nuggets/nugget.dmi' + icon_state = ICON_STATE_WORLD + nutriment_desc = list("mild battered chicken") + nutriment_amt = 6 + nutriment_type = /decl/material/solid/organic/meat/chicken + material = /decl/material/solid/organic/meat/chicken + bitesize = 3 + var/shape = null + var/static/list/nugget_icons = list( + "lump" = 'icons/obj/food/nuggets/nugget.dmi', + "star" = 'icons/obj/food/nuggets/nugget_star.dmi', + "lizard" = 'icons/obj/food/nuggets/nugget_lizard.dmi', + "corgi" = 'icons/obj/food/nuggets/nugget_corgi.dmi' + ) + +/obj/item/food/nugget/Initialize() + . = ..() + if(isnull(shape)) + shape = pick(nugget_icons) + set_icon(nugget_icons[shape]) + desc = "A chicken nugget vaguely shaped like a [shape]." + add_allergen_flags(ALLERGEN_GLUTEN) // flour diff --git a/code/modules/food/plates/_plate.dm b/code/modules/food/plates/_plate.dm new file mode 100644 index 000000000000..79cae23dbd0a --- /dev/null +++ b/code/modules/food/plates/_plate.dm @@ -0,0 +1,67 @@ +/obj/item/plate + name = "plate" + desc = "A small plate, suitable for serving food." + material = /decl/material/solid/stone/ceramic + icon = 'icons/obj/food/plates/small_plate.dmi' + icon_state = ICON_STATE_WORLD + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + w_class = ITEM_SIZE_SMALL + var/is_dirty + +/obj/item/plate/Destroy() + if(istype(loc, /obj/item/food)) + var/obj/item/food/food = loc + if(food.plate == src) + food.plate = null + return ..() + +/obj/item/plate/proc/make_dirty(obj/item/food/food) + if(!is_dirty) + is_dirty = food?.filling_color || COLOR_WHITE + update_icon() + +/obj/item/plate/clean(clean_forensics = TRUE) + . = ..() + if(is_dirty) + is_dirty = null + update_icon() + +/obj/item/plate/on_update_icon() + . = ..() + if(is_dirty) + var/image/I = image(icon, "[icon_state]-dirty") + I.appearance_flags |= RESET_COLOR + I.color = is_dirty + add_overlay(I) + +// Return TRUE to terminate attacky past this proc. +/obj/item/plate/proc/try_plate_food(obj/item/food/food, mob/user) + if(!istype(food)) + return FALSE + if(food.plate) + to_chat(user, SPAN_WARNING("\The [food] has already been plated.")) + return TRUE + if(ismob(loc)) + var/mob/M = loc + if(!M.try_unequip(src)) + return FALSE + if(user && !user.try_unequip(food)) + return FALSE + forceMove(food) + food.plate = src + user?.visible_message(SPAN_NOTICE("\The [user] places \the [food] on \the [src].")) + food.update_icon() + return TRUE + +/obj/item/plate/attackby(obj/item/used_item, mob/living/user) + // Plating food. + if(try_plate_food(used_item, user)) + return TRUE + return ..() + +/obj/item/plate/platter + name = "platter" + desc = "A large white platter, suitable for serving cakes or other large food." + icon = 'icons/obj/food/plates/platter.dmi' + material = /decl/material/solid/glass + w_class = ITEM_SIZE_NORMAL diff --git a/code/modules/food/plates/plate_tray.dm b/code/modules/food/plates/plate_tray.dm new file mode 100644 index 000000000000..0f6e01a1666a --- /dev/null +++ b/code/modules/food/plates/plate_tray.dm @@ -0,0 +1,166 @@ +// New and improved(?) trays. Apologies to Agouri, and Doohl, wherever you may be. +/obj/item/plate/tray + name = "tray" + desc = "A large tray, suitable for serving several servings of food." + icon = 'icons/obj/food/plates/tray.dmi' + material = /decl/material/solid/organic/plastic + w_class = ITEM_SIZE_NORMAL + storage = /datum/storage/tray + throw_speed = 1 + throw_range = 5 + melee_accuracy_bonus = -10 + attack_verb = list("served","slammed","hit") + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + _base_attack_force = 4 + var/cooldown = 0 // Cooldown for banging the tray with a rolling pin. based on world.time. very silly + var/no_drop = FALSE + +// Override this so we can use our storage. +/obj/item/plate/tray/try_plate_food(obj/item/food/food, mob/user) + return FALSE + +/obj/item/plate/tray/resolve_attackby(var/atom/A, mob/user) + if(A.storage) //Disallow putting in bags without raising w_class. Don't know why though, it was part of the old trays + to_chat(user, SPAN_WARNING("The tray won't fit in \the [A].")) + return + . = ..() + +/obj/item/plate/tray/proc/scatter_contents(var/neatly = FALSE, target_loc = get_turf(src)) + set waitfor = FALSE + if(storage) + for(var/obj/item/I in storage.get_contents()) + if(storage.remove_from_storage(null, I, target_loc) && !neatly) + I.throw_at(get_edge_target_turf(I.loc, pick(global.alldirs)), rand(1,3), round(10/I.w_class)) + update_icon() + +/obj/item/plate/tray/shatter(consumed) + scatter_contents() + . = ..() + +/obj/item/plate/tray/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) // There is a better way to do this but I'll be damned if I'm the one to fix it. + to_chat(user, SPAN_DANGER("You accidentally slam yourself with \the [src]!")) + SET_STATUS_MAX(user, STAT_WEAK, 1) + user.take_organ_damage(2) + if(prob(50)) + playsound(target, hitsound, 50, 1) + . = TRUE + else + . = ..() + if(.) + scatter_contents() + +/obj/item/plate/tray/attackby(obj/item/used_item, mob/user, click_params) + if(istype(used_item, /obj/item/rollingpin)) + if(cooldown < world.time - 25) + user.visible_message(SPAN_WARNING("\The [user] bashes \the [src] with \the [used_item]!")) + playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) + cooldown = world.time + return TRUE + . = ..() + if (.) + auto_align(used_item, click_params) + +//This proc handles alignment on trays, a la tables. +/obj/item/plate/tray/proc/auto_align(obj/item/aligning, click_params) + if (!aligning.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy. + aligning.pixel_x = rand(-aligning.randpixel, aligning.randpixel) + aligning.pixel_y = rand(-aligning.randpixel, aligning.randpixel) + aligning.pixel_z = 0 + return + + if (!click_params) + return + + var/list/click_data = params2list(click_params) + if (!click_data["icon-x"] || !click_data["icon-y"]) + return + + // Calculation to apply new pixelshift. + var/mouse_x = text2num(click_data["icon-x"])-1 // Ranging from 0 to 31 + var/mouse_y = text2num(click_data["icon-y"])-1 + + var/cell_x = clamp(round(mouse_x/CELLSIZE), 0, CELLS-1) // Ranging from 0 to CELLS-1 + var/cell_y = clamp(round(mouse_y/CELLSIZE), 0, CELLS-1) + + var/list/center = cached_json_decode(aligning.center_of_mass) + + aligning.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] + aligning.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] + aligning.pixel_z = 0 + +/obj/item/plate/tray/dump_contents(atom/forced_loc = loc, mob/user) + if(!isturf(forced_loc)) //to handle hand switching + return FALSE + if(user && storage) + storage.close(user) + if(!(locate(/obj/structure/table) in forced_loc) && contents.len) + if(user) + visible_message(SPAN_DANGER("Everything falls off \the [src]! Good job, [user].")) + scatter_contents(FALSE, forced_loc) + return ..() + +/obj/item/plate/tray/dropped(mob/user) + . = ..() + if(!no_drop) + dump_contents(user = user) + +/obj/item/plate/tray/throw_at(atom/target, range, speed, mob/thrower, spin, datum/callback/callback) + no_drop = TRUE + . = ..() + +/obj/item/plate/tray/throw_impact(atom/hit_atom, datum/thrownthing/TT) + . = ..() + no_drop = FALSE + scatter_contents(FALSE, get_turf(hit_atom)) + +/obj/item/plate/tray/on_update_icon() + . = ..() + clear_vis_contents() + for(var/obj/item/I in contents) + I.vis_flags |= VIS_INHERIT_PLANE | VIS_INHERIT_LAYER + I.appearance_flags |= RESET_COLOR + add_vis_contents(I) + +/obj/item/plate/tray/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(.) + if(contents.len) + var/tray_examine = list() + for(var/obj/item/I in contents) + tray_examine += "\a [I.name]" + . += "There is [english_list(tray_examine)] on the tray." + else + . += "\The [src] is empty." + +/* +----------------------------------------------------------------- +TRAY TYPES GO HERE +----------------------------------------------------------------- + */ + +/obj/item/plate/tray/cardboard + desc = "A cardboard tray to serve food on." + material = /decl/material/solid/organic/cardboard + +/obj/item/plate/tray/wood + desc = "A wooden tray to serve food on." + material = /decl/material/solid/organic/wood/oak + +/obj/item/plate/tray/metal + obj_flags = OBJ_FLAG_CONDUCTIBLE + hitsound = "tray_hit" // So metal trays make the fun noise + +/obj/item/plate/tray/metal/aluminium + desc = "An aluminium tray to serve food on." + material = /decl/material/solid/metal/aluminium + +/obj/item/plate/tray/metal/silver + name = "platter" + desc = "The new generation is so lazy, they expect everything to be handed to them on this." + material = /decl/material/solid/metal/silver + +/obj/item/plate/tray/metal/gold + name = "platter" + desc = "A gold tray to serve food on. Heavy, but oh-so-fancy." + material = /decl/material/solid/metal/gold \ No newline at end of file diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm deleted file mode 100644 index d7199d99752a..000000000000 --- a/code/modules/food/recipes_microwave.dm +++ /dev/null @@ -1,1006 +0,0 @@ - -// see code/datums/recipe.dm - - -/* No telebacon. just no... -/datum/recipe/telebacon - items = list( - /obj/item/chems/food/snacks/meat, - /obj/item/assembly/signaler - ) - result = /obj/item/chems/food/snacks/telebacon - -I said no! -/datum/recipe/syntitelebacon - items = list( - /obj/item/chems/food/snacks/meat/syntiflesh, - /obj/item/assembly/signaler - ) - result = /obj/item/chems/food/snacks/telebacon -*/ - -/datum/recipe/friedegg - reagents = list(/decl/material/solid/mineral/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) - items = list( - /obj/item/chems/food/snacks/egg - ) - result = /obj/item/chems/food/snacks/friedegg - -/datum/recipe/friedegg2 - items = list( - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/egg, - ) - result = /obj/item/chems/food/snacks/friedegg - -/datum/recipe/boiledegg - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/egg - ) - result = /obj/item/chems/food/snacks/boiledegg - -/datum/recipe/classichotdog - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/holder/corgi - ) - result = /obj/item/chems/food/snacks/classichotdog - -/datum/recipe/jellydonut - reagents = list(/decl/material/liquid/drink/juice/berry = 5, /decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/dough - ) - result = /obj/item/chems/food/snacks/donut/jelly - -/datum/recipe/jellydonut/slime - reagents = list(/decl/material/liquid/slimejelly = 5, /decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/dough - ) - result = /obj/item/chems/food/snacks/donut/slimejelly - -/datum/recipe/jellydonut/cherry - reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5, /decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/dough - ) - result = /obj/item/chems/food/snacks/donut/cherryjelly - -/datum/recipe/donut - reagents = list(/decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/dough - ) - result = /obj/item/chems/food/snacks/donut/normal - -/datum/recipe/meatburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/chems/food/snacks/cutlet - ) - result = /obj/item/chems/food/snacks/meatburger - -/datum/recipe/brainburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/organ/internal/brain - ) - result = /obj/item/chems/food/snacks/brainburger - -/datum/recipe/roburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/robot_parts/head - ) - result = /obj/item/chems/food/snacks/roburger - -/datum/recipe/xenoburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/chems/food/snacks/xenomeat - ) - result = /obj/item/chems/food/snacks/xenoburger - -/datum/recipe/fishburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/chems/food/snacks/fish - ) - result = /obj/item/chems/food/snacks/fishburger - -/datum/recipe/tofuburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/chems/food/snacks/tofu - ) - result = /obj/item/chems/food/snacks/tofuburger - -/datum/recipe/ghostburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/ectoplasm //where do you even find this stuff - ) - result = /obj/item/chems/food/snacks/ghostburger - -/datum/recipe/clownburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/clothing/mask/gas/clown_hat - ) - result = /obj/item/chems/food/snacks/clownburger - -/datum/recipe/mimeburger - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/clothing/head/beret - ) - result = /obj/item/chems/food/snacks/mimeburger - -/datum/recipe/bunbun - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/chems/food/snacks/bun - ) - result = /obj/item/chems/food/snacks/bunbun - -/datum/recipe/hotdog - items = list( - /obj/item/chems/food/snacks/bun, - /obj/item/chems/food/snacks/sausage - ) - result = /obj/item/chems/food/snacks/hotdog - -/datum/recipe/waffles - reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 20) - result = /obj/item/chems/food/snacks/waffles - -/datum/recipe/pancakesblu - reagents = list(/decl/material/liquid/nutriment/batter = 20) - fruit = list("blueberries" = 2) - result = /obj/item/chems/food/snacks/pancakesblu - -/datum/recipe/pancakes - reagents = list(/decl/material/liquid/nutriment/batter = 20) - result = /obj/item/chems/food/snacks/pancakes - -/datum/recipe/donkpocket - items = list( - /obj/item/chems/food/snacks/doughslice, - /obj/item/chems/food/snacks/meatball - ) - result = /obj/item/chems/food/snacks/donkpocket //SPECIAL - proc/warm_up(var/obj/item/chems/food/snacks/donkpocket/being_cooked) - being_cooked.heat() - make_food(var/obj/container as obj) - var/obj/item/chems/food/snacks/donkpocket/being_cooked = ..(container) - warm_up(being_cooked) - return being_cooked - -/datum/recipe/donkpocket2 - items = list( - /obj/item/chems/food/snacks/doughslice, - /obj/item/chems/food/snacks/rawmeatball - ) - result = /obj/item/chems/food/snacks/donkpocket //SPECIAL - -/datum/recipe/donkpocket2/proc/warm_up(var/obj/item/chems/food/snacks/donkpocket/being_cooked) - being_cooked.heat() - -/datum/recipe/donkpocket2/make_food(var/obj/container) - var/obj/item/chems/food/snacks/donkpocket/being_cooked = ..(container) - warm_up(being_cooked) - return being_cooked - -/datum/recipe/donkpocket/warm - reagents = list() //This is necessary since this is a child object of the above recipe and we don't want donk pockets to need flour - items = list( - /obj/item/chems/food/snacks/donkpocket - ) - result = /obj/item/chems/food/snacks/donkpocket //SPECIAL - make_food(var/obj/container as obj) - var/obj/item/chems/food/snacks/donkpocket/being_cooked = locate() in container - if(being_cooked && !being_cooked.warm) - warm_up(being_cooked) - return being_cooked - -/datum/recipe/meatbread - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/cutlet, - /obj/item/chems/food/snacks/cutlet, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/sliceable/meatbread - -/datum/recipe/xenomeatbread - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/xenomeat, - /obj/item/chems/food/snacks/xenomeat, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/sliceable/xenomeatbread - -/datum/recipe/bananabread - fruit = list("banana" = 2) - reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - ) - result = /obj/item/chems/food/snacks/sliceable/bananabread - -/datum/recipe/omelette - items = list( - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/omelette - -/datum/recipe/muffin - reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 10) - result = /obj/item/chems/food/snacks/muffin - -/datum/recipe/eggplantparm - fruit = list("eggplant" = 1) - items = list( - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge - ) - result = /obj/item/chems/food/snacks/eggplantparm - -/datum/recipe/soylenviridians - fruit = list("soybeans" = 1) - reagents = list(/decl/material/liquid/nutriment/flour = 10) - result = /obj/item/chems/food/snacks/soylenviridians - -/datum/recipe/soylentgreen - reagents = list(/decl/material/liquid/nutriment/flour = 10) - items = list( - /obj/item/chems/food/snacks/meat/human, - /obj/item/chems/food/snacks/meat/human - ) - result = /obj/item/chems/food/snacks/soylentgreen - -/datum/recipe/meatpie - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/cutlet - ) - result = /obj/item/chems/food/snacks/meatpie - -/datum/recipe/tofupie - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/tofu, - ) - result = /obj/item/chems/food/snacks/tofupie - -/datum/recipe/xemeatpie - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/xenomeat, - ) - result = /obj/item/chems/food/snacks/xemeatpie - -/datum/recipe/bananapie - fruit = list("banana" = 1) - reagents = list(/decl/material/liquid/nutriment/sugar = 5) - items = list(/obj/item/chems/food/snacks/sliceable/flatdough) - result = /obj/item/chems/food/snacks/bananapie - -/datum/recipe/cherrypie - fruit = list("cherries" = 1) - reagents = list(/decl/material/liquid/nutriment/sugar = 10) - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - ) - result = /obj/item/chems/food/snacks/cherrypie - -/datum/recipe/berryclafoutis - fruit = list("berries" = 1) - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - ) - result = /obj/item/chems/food/snacks/berryclafoutis - -/datum/recipe/chaosdonut - reagents = list(/decl/material/liquid/frostoil = 5, /decl/material/liquid/capsaicin = 5, /decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/dough - ) - result = /obj/item/chems/food/snacks/donut/chaos - -/datum/recipe/meatkabob - items = list( - /obj/item/stack/material/rods, - /obj/item/chems/food/snacks/cutlet, - /obj/item/chems/food/snacks/cutlet - ) - result = /obj/item/chems/food/snacks/meatkabob - -/datum/recipe/tofukabob - items = list( - /obj/item/stack/material/rods, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/tofu, - ) - result = /obj/item/chems/food/snacks/tofukabob - -/datum/recipe/tofubread - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/sliceable/tofubread - -/datum/recipe/loadedbakedpotato - fruit = list("potato" = 1) - items = list(/obj/item/chems/food/snacks/cheesewedge) - result = /obj/item/chems/food/snacks/loadedbakedpotato - -/datum/recipe/cheesyfries - items = list( - /obj/item/chems/food/snacks/fries, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/cheesyfries - -/datum/recipe/cubancarp - fruit = list("chili" = 1) - reagents = list(/decl/material/liquid/nutriment/batter = 10) - items = list( - /obj/item/chems/food/snacks/fish - ) - result = /obj/item/chems/food/snacks/cubancarp - -/datum/recipe/popcorn - reagents = list(/decl/material/solid/mineral/sodiumchloride = 5) - fruit = list("corn" = 1) - result = /obj/item/chems/food/snacks/popcorn - -/datum/recipe/cookie - reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 5, /decl/material/liquid/nutriment/coco = 5) - - result = /obj/item/chems/food/snacks/cookie - -/datum/recipe/fortunecookie - reagents = list(/decl/material/liquid/nutriment/sugar = 5) - items = list( - /obj/item/chems/food/snacks/doughslice, - /obj/item/paper, - ) - result = /obj/item/chems/food/snacks/fortunecookie - -/datum/recipe/fortunecookie/make_food(obj/container) - var/obj/item/paper/paper = locate() in container - paper.loc = null //prevent deletion - var/obj/item/chems/food/snacks/fortunecookie/being_cooked = ..(container) - paper.loc = being_cooked - being_cooked.trash = paper //so the paper is left behind as trash without special-snowflake(TM Nodrak) code ~carn - return being_cooked - -/datum/recipe/fortunecookie/check_items(var/obj/container) - . = ..() - if(.) - var/obj/item/paper/paper = locate() in container - if(!paper || !paper.info) - return FALSE - return . - -/datum/recipe/plainsteak - items = list(/obj/item/chems/food/snacks/meat) - result = /obj/item/chems/food/snacks/plainsteak - -/datum/recipe/meatsteak - reagents = list(/decl/material/solid/mineral/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) - items = list(/obj/item/chems/food/snacks/cutlet) - result = /obj/item/chems/food/snacks/meatsteak - -/datum/recipe/loadedsteak - reagents = list(/decl/material/liquid/nutriment/garlicsauce = 5) - fruit = list("onion" = 1, "mushroom" = 1) - items = list(/obj/item/chems/food/snacks/cutlet) - result = /obj/item/chems/food/snacks/loadedsteak - -/datum/recipe/syntisteak - reagents = list(/decl/material/solid/mineral/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) - items = list(/obj/item/chems/food/snacks/meat/syntiflesh) - result = /obj/item/chems/food/snacks/meatsteak/synthetic - -/datum/recipe/pizzamargherita - fruit = list("tomato" = 1) - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/sliceable/pizza/margherita - -/datum/recipe/meatpizza - fruit = list("tomato" = 1) - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/cutlet, - /obj/item/chems/food/snacks/cutlet, - /obj/item/chems/food/snacks/cheesewedge - ) - result = /obj/item/chems/food/snacks/sliceable/pizza/meatpizza - -/datum/recipe/mushroompizza - fruit = list("mushroom" = 5, "tomato" = 1) - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/cheesewedge - ) - result = /obj/item/chems/food/snacks/sliceable/pizza/mushroompizza - -/datum/recipe/vegetablepizza - fruit = list("eggplant" = 1, "carrot" = 1, "corn" = 1, "tomato" = 1) - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough, - /obj/item/chems/food/snacks/cheesewedge - ) - result = /obj/item/chems/food/snacks/sliceable/pizza/vegetablepizza - -/datum/recipe/spacylibertyduff - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/ethanol/vodka = 5, /decl/material/liquid/psychotropics = 5) - result = /obj/item/chems/food/snacks/spacylibertyduff - -/datum/recipe/amanitajelly - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/ethanol/vodka = 5, /decl/material/liquid/amatoxin = 5) - result = /obj/item/chems/food/snacks/amanitajelly - make_food(var/obj/container as obj) - var/obj/item/chems/food/snacks/amanitajelly/being_cooked = ..(container) - being_cooked.reagents.clear_reagent(/decl/material/liquid/amatoxin) - return being_cooked - -/datum/recipe/meatballsoup - fruit = list("carrot" = 1, "potato" = 1) - reagents = list(/decl/material/liquid/water = 10) - items = list(/obj/item/chems/food/snacks/meatball) - result = /obj/item/chems/food/snacks/meatballsoup - -/datum/recipe/vegetablesoup - fruit = list("carrot" = 1, "potato" = 1, "corn" = 1, "eggplant" = 1) - reagents = list(/decl/material/liquid/water = 10) - result = /obj/item/chems/food/snacks/vegetablesoup - -/datum/recipe/nettlesoup - fruit = list("nettle" = 1, "potato" = 1) - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/egg - ) - result = /obj/item/chems/food/snacks/nettlesoup - -/datum/recipe/wishsoup - reagents = list(/decl/material/liquid/water = 20) - result= /obj/item/chems/food/snacks/wishsoup - -/datum/recipe/hotchili - fruit = list("chili" = 1, "tomato" = 1) - items = list(/obj/item/chems/food/snacks/cutlet) - result = /obj/item/chems/food/snacks/hotchili - -/datum/recipe/coldchili - fruit = list("icechili" = 1, "tomato" = 1) - items = list(/obj/item/chems/food/snacks/cutlet) - result = /obj/item/chems/food/snacks/coldchili - -/datum/recipe/amanita_pie - reagents = list(/decl/material/liquid/amatoxin = 5) - items = list(/obj/item/chems/food/snacks/sliceable/flatdough) - result = /obj/item/chems/food/snacks/amanita_pie - -/datum/recipe/plump_pie - fruit = list("plumphelmet" = 1) - items = list(/obj/item/chems/food/snacks/sliceable/flatdough) - result = /obj/item/chems/food/snacks/plump_pie - -/datum/recipe/spellburger - items = list( - /obj/item/chems/food/snacks/meatburger, - /obj/item/clothing/head/wizard, - ) - result = /obj/item/chems/food/snacks/spellburger - -/datum/recipe/bigbiteburger - items = list( - /obj/item/chems/food/snacks/meatburger, - /obj/item/chems/food/snacks/meat, - /obj/item/chems/food/snacks/meat, - /obj/item/chems/food/snacks/egg, - ) - result = /obj/item/chems/food/snacks/bigbiteburger - -/datum/recipe/enchiladas - fruit = list("chili" = 2, "corn" = 1) - items = list(/obj/item/chems/food/snacks/cutlet) - result = /obj/item/chems/food/snacks/enchiladas - -/datum/recipe/creamcheesebread - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/sliceable/creamcheesebread - -/datum/recipe/monkeysdelight - fruit = list("banana" = 1) - reagents = list(/decl/material/solid/mineral/sodiumchloride = 1, /decl/material/solid/blackpepper = 1, /decl/material/liquid/nutriment/flour = 10) - items = list( - /obj/item/chems/food/snacks/monkeycube - ) - result = /obj/item/chems/food/snacks/monkeysdelight - -/datum/recipe/baguette - reagents = list(/decl/material/solid/mineral/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - ) - result = /obj/item/chems/food/snacks/baguette - -/datum/recipe/fishandchips - items = list( - /obj/item/chems/food/snacks/fries, - /obj/item/chems/food/snacks/fish - ) - result = /obj/item/chems/food/snacks/fishandchips - -/datum/recipe/bread - items = list( - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/egg - ) - result = /obj/item/chems/food/snacks/sliceable/bread - -/datum/recipe/sandwich - items = list( - /obj/item/chems/food/snacks/meatsteak, - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/sandwich - -/datum/recipe/toastedsandwich - items = list( - /obj/item/chems/food/snacks/sandwich - ) - result = /obj/item/chems/food/snacks/toastedsandwich - -/datum/recipe/grilledcheese - items = list( - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/grilledcheese - -/datum/recipe/tomatosoup - fruit = list("tomato" = 2) - reagents = list(/decl/material/liquid/water = 10) - result = /obj/item/chems/food/snacks/tomatosoup - -/datum/recipe/rofflewaffles - reagents = list(/decl/material/liquid/psychotropics = 5, /decl/material/liquid/nutriment/batter/cakebatter = 20) - result = /obj/item/chems/food/snacks/rofflewaffles - -/datum/recipe/stew - fruit = list("potato" = 1, "tomato" = 1, "carrot" = 1, "eggplant" = 1, "mushroom" = 1) - reagents = list(/decl/material/liquid/water = 10) - items = list(/obj/item/chems/food/snacks/meat) - result = /obj/item/chems/food/snacks/stew - -/datum/recipe/slimetoast - reagents = list(/decl/material/liquid/slimejelly = 5) - items = list( - /obj/item/chems/food/snacks/slice/bread, - ) - result = /obj/item/chems/food/snacks/jelliedtoast/slime - -/datum/recipe/jelliedtoast - reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5) - items = list( - /obj/item/chems/food/snacks/slice/bread, - ) - result = /obj/item/chems/food/snacks/jelliedtoast/cherry - -/datum/recipe/milosoup - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/soydope, - /obj/item/chems/food/snacks/soydope, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/tofu, - ) - result = /obj/item/chems/food/snacks/milosoup - -/datum/recipe/stewedsoymeat - fruit = list("carrot" = 1, "tomato" = 1) - items = list( - /obj/item/chems/food/snacks/soydope, - /obj/item/chems/food/snacks/soydope - ) - result = /obj/item/chems/food/snacks/stewedsoymeat - -/datum/recipe/boiledspagetti - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/spagetti, - ) - result = /obj/item/chems/food/snacks/boiledspagetti - -/datum/recipe/boiledrice - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/rice = 10) - result = /obj/item/chems/food/snacks/boiledrice - -/datum/recipe/chazuke - reagents = list(/decl/material/liquid/nutriment/rice/chazuke = 10) - result = /obj/item/chems/food/snacks/boiledrice/chazuke - -/datum/recipe/katsucurry - fruit = list("apple" = 1, "carrot" = 1, "potato" = 1) - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/rice = 10, /decl/material/liquid/nutriment/flour = 5) - items = list( - /obj/item/chems/food/snacks/meat/chicken - ) - result = /obj/item/chems/food/snacks/katsucurry - -/datum/recipe/ricepudding - reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/rice = 10) - result = /obj/item/chems/food/snacks/ricepudding - -/datum/recipe/pastatomato - fruit = list("tomato" = 2) - reagents = list(/decl/material/liquid/water = 10) - items = list(/obj/item/chems/food/snacks/spagetti) - result = /obj/item/chems/food/snacks/pastatomato - -/datum/recipe/poppypretzel - fruit = list("poppy" = 1) - items = list(/obj/item/chems/food/snacks/dough) - result = /obj/item/chems/food/snacks/poppypretzel - -/datum/recipe/meatballspagetti - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/spagetti, - /obj/item/chems/food/snacks/meatball, - /obj/item/chems/food/snacks/meatball, - ) - result = /obj/item/chems/food/snacks/meatballspagetti - -/datum/recipe/spesslaw - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/spagetti, - /obj/item/chems/food/snacks/meatball, - /obj/item/chems/food/snacks/meatball, - /obj/item/chems/food/snacks/meatball, - /obj/item/chems/food/snacks/meatball, - ) - result = /obj/item/chems/food/snacks/spesslaw - -/datum/recipe/nanopasta - reagents = list(/decl/material/liquid/water = 10) - items = list(/obj/item/chems/food/snacks/spagetti, - /obj/item/stack/nanopaste) - result = /obj/item/chems/food/snacks/nanopasta - -/datum/recipe/superbiteburger - fruit = list("tomato" = 1) - reagents = list(/decl/material/solid/mineral/sodiumchloride = 5, /decl/material/solid/blackpepper = 5) - items = list( - /obj/item/chems/food/snacks/bigbiteburger, - /obj/item/chems/food/snacks/dough, - /obj/item/chems/food/snacks/meat, - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/boiledegg, - ) - result = /obj/item/chems/food/snacks/superbiteburger - -/datum/recipe/candiedapple - fruit = list("apple" = 1) - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/sugar = 5) - result = /obj/item/chems/food/snacks/candiedapple - -/datum/recipe/applepie - fruit = list("apple" = 1) - items = list(/obj/item/chems/food/snacks/sliceable/flatdough) - result = /obj/item/chems/food/snacks/applepie - -/datum/recipe/slimeburger - reagents = list(/decl/material/liquid/slimejelly = 5) - items = list( - /obj/item/chems/food/snacks/bun - ) - result = /obj/item/chems/food/snacks/jellyburger/slime - -/datum/recipe/jellyburger - reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5) - items = list( - /obj/item/chems/food/snacks/bun - ) - result = /obj/item/chems/food/snacks/jellyburger/cherry - -/datum/recipe/twobread - reagents = list(/decl/material/liquid/ethanol/wine = 5) - items = list( - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/slice/bread, - ) - result = /obj/item/chems/food/snacks/twobread - -/datum/recipe/threebread - items = list( - /obj/item/chems/food/snacks/twobread, - /obj/item/chems/food/snacks/slice/bread, - ) - result = /obj/item/chems/food/snacks/threebread - -/datum/recipe/slimesandwich - reagents = list(/decl/material/liquid/slimejelly = 5) - items = list( - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/slice/bread, - ) - result = /obj/item/chems/food/snacks/jellysandwich/slime - -/datum/recipe/cherrysandwich - reagents = list(/decl/material/liquid/nutriment/cherryjelly = 5) - items = list( - /obj/item/chems/food/snacks/slice/bread, - /obj/item/chems/food/snacks/slice/bread, - ) - result = /obj/item/chems/food/snacks/jellysandwich/cherry - -/datum/recipe/bloodsoup - reagents = list(/decl/material/liquid/blood = 30) - result = /obj/item/chems/food/snacks/bloodsoup - -/datum/recipe/slimesoup - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/slimejelly = 5) - items = list() - result = /obj/item/chems/food/snacks/slimesoup - -/datum/recipe/chocolateegg - items = list( - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/chocolatebar, - ) - result = /obj/item/chems/food/snacks/chocolateegg - -/datum/recipe/sausage - items = list( - /obj/item/chems/food/snacks/rawmeatball, - /obj/item/chems/food/snacks/rawcutlet, - ) - result = /obj/item/chems/food/snacks/sausage - -/datum/recipe/fatsausage - reagents = list(/decl/material/solid/blackpepper = 2) - items = list( - /obj/item/chems/food/snacks/rawmeatball, - /obj/item/chems/food/snacks/rawcutlet, - ) - result = /obj/item/chems/food/snacks/fatsausage - -/datum/recipe/fishfingers - reagents = list(/decl/material/liquid/nutriment/flour = 10) - items = list( - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/fish - ) - result = /obj/item/chems/food/snacks/fishfingers - -/datum/recipe/mysterysoup - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/badrecipe, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/cheesewedge, - ) - result = /obj/item/chems/food/snacks/mysterysoup - -/datum/recipe/pumpkinpie - fruit = list("pumpkin" = 1) - reagents = list(/decl/material/liquid/nutriment/sugar = 5) - items = list(/obj/item/chems/food/snacks/sliceable/flatdough) - result = /obj/item/chems/food/snacks/sliceable/pumpkinpie - -/datum/recipe/plumphelmetbiscuit - fruit = list("plumphelmet" = 1) - reagents = list(/decl/material/liquid/nutriment/batter = 10) - result = /obj/item/chems/food/snacks/plumphelmetbiscuit - -/datum/recipe/plumphelmetbiscuitvegan - fruit = list("plumphelmet" = 1) - reagents = list(/decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/water = 10) - result = /obj/item/chems/food/snacks/plumphelmetbiscuit - -/datum/recipe/mushroomsoup - fruit = list("mushroom" = 1) - reagents = list(/decl/material/liquid/drink/milk = 10) - result = /obj/item/chems/food/snacks/mushroomsoup - -/datum/recipe/chawanmushi - fruit = list("mushroom" = 1) - reagents = list(/decl/material/liquid/water = 10, /decl/material/liquid/nutriment/soysauce = 5) - items = list( - /obj/item/chems/food/snacks/egg, - /obj/item/chems/food/snacks/egg - ) - result = /obj/item/chems/food/snacks/chawanmushi - -/datum/recipe/beetsoup - fruit = list("whitebeet" = 1, "cabbage" = 1) - reagents = list(/decl/material/liquid/water = 10) - result = /obj/item/chems/food/snacks/beetsoup - -/datum/recipe/appletart - fruit = list("goldapple" = 1) - items = list(/obj/item/chems/food/snacks/sliceable/flatdough) - result = /obj/item/chems/food/snacks/appletart - -/datum/recipe/tossedsalad - fruit = list("cabbage" = 2, "tomato" = 1, "carrot" = 1, "apple" = 1) - result = /obj/item/chems/food/snacks/tossedsalad - -/datum/recipe/aesirsalad - fruit = list("goldapple" = 1, "biteleafdeus" = 1) - result = /obj/item/chems/food/snacks/aesirsalad - -/datum/recipe/validsalad - fruit = list("potato" = 1, "biteleaf" = 3) - items = list(/obj/item/chems/food/snacks/meatball) - result = /obj/item/chems/food/snacks/validsalad - -/datum/recipe/cracker - reagents = list(/decl/material/solid/mineral/sodiumchloride = 1) - items = list( - /obj/item/chems/food/snacks/doughslice - ) - result = /obj/item/chems/food/snacks/cracker - -/datum/recipe/stuffing - reagents = list(/decl/material/liquid/water = 10, /decl/material/solid/mineral/sodiumchloride = 1, /decl/material/solid/blackpepper = 1) - items = list( - /obj/item/chems/food/snacks/sliceable/bread, - ) - result = /obj/item/chems/food/snacks/stuffing - -/datum/recipe/tofurkey - items = list( - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/stuffing, - ) - result = /obj/item/chems/food/snacks/tofurkey - -////////////////////////////////////////// -// bs12 food port stuff -////////////////////////////////////////// - -/datum/recipe/taco - items = list( - /obj/item/chems/food/snacks/doughslice, - /obj/item/chems/food/snacks/cutlet, - /obj/item/chems/food/snacks/cheesewedge - ) - result = /obj/item/chems/food/snacks/taco - -/datum/recipe/bun - items = list( - /obj/item/chems/food/snacks/dough - ) - result = /obj/item/chems/food/snacks/bun - -/datum/recipe/flatbread - items = list( - /obj/item/chems/food/snacks/sliceable/flatdough - ) - result = /obj/item/chems/food/snacks/flatbread - -/datum/recipe/meatball - items = list( - /obj/item/chems/food/snacks/rawmeatball - ) - result = /obj/item/chems/food/snacks/meatball - -/datum/recipe/cutlet - items = list( - /obj/item/chems/food/snacks/rawcutlet - ) - result = /obj/item/chems/food/snacks/cutlet - -/datum/recipe/fries - items = list( - /obj/item/chems/food/snacks/rawsticks - ) - result = /obj/item/chems/food/snacks/fries - -/datum/recipe/onionrings - fruit = list("onion" = 1) - reagents = list(/decl/material/liquid/nutriment/batter = 10) - result = /obj/item/chems/food/snacks/onionrings - -/datum/recipe/mint - reagents = list(/decl/material/liquid/nutriment/sugar = 5, /decl/material/liquid/frostoil = 5) - result = /obj/item/chems/food/snacks/mint - -// Cakes. -/datum/recipe/cake - reagents = list(/decl/material/liquid/nutriment/batter/cakebatter = 60) - result = /obj/item/chems/food/snacks/sliceable/plaincake - -/datum/recipe/cake/carrot - fruit = list("carrot" = 3) - result = /obj/item/chems/food/snacks/sliceable/carrotcake - -/datum/recipe/cake/cheese - items = list( - /obj/item/chems/food/snacks/cheesewedge, - /obj/item/chems/food/snacks/cheesewedge - ) - result = /obj/item/chems/food/snacks/sliceable/cheesecake - -/datum/recipe/cake/orange - fruit = list("orange" = 1) - result = /obj/item/chems/food/snacks/sliceable/orangecake - -/datum/recipe/cake/lime - fruit = list("lime" = 1) - result = /obj/item/chems/food/snacks/sliceable/limecake - -/datum/recipe/cake/lemon - fruit = list("lemon" = 1) - result = /obj/item/chems/food/snacks/sliceable/lemoncake - -/datum/recipe/cake/chocolate - items = list(/obj/item/chems/food/snacks/chocolatebar) - result = /obj/item/chems/food/snacks/sliceable/chocolatecake - -/datum/recipe/cake/birthday - reagents = list(/decl/material/liquid/nutriment/sprinkles = 10) - result = /obj/item/chems/food/snacks/sliceable/birthdaycake - -/datum/recipe/cake/apple - fruit = list("apple" = 2) - result = /obj/item/chems/food/snacks/sliceable/applecake - -/datum/recipe/cake/brain - items = list(/obj/item/organ/internal/brain) - result = /obj/item/chems/food/snacks/sliceable/braincake - -/datum/recipe/cake/chocolatebar - reagents = list(/decl/material/liquid/drink/milk/chocolate = 10, /decl/material/liquid/nutriment/coco = 5, /decl/material/liquid/nutriment/sugar = 5) - result = /obj/item/chems/food/snacks/chocolatebar - -/datum/recipe/boiledspiderleg - reagents = list(/decl/material/liquid/water = 10) - items = list( - /obj/item/chems/food/snacks/spider - ) - result = /obj/item/chems/food/snacks/spider/cooked \ No newline at end of file diff --git a/code/modules/food/utensils/_utensil.dm b/code/modules/food/utensils/_utensil.dm new file mode 100644 index 000000000000..9941844187f4 --- /dev/null +++ b/code/modules/food/utensils/_utensil.dm @@ -0,0 +1,138 @@ +/* + * Some notes on utensils and future plans: + * + * Utensil flags should determine how and if they can interact with + * different food item, ie. forks should not be usable to eat soup, + * spoons should not be usable to eat steak. + * + * The actual mechanics of removing a piece of food should be largely + * identical between utensil types, with the procs existing to be + * overidden to provide specific behavior. + */ + +/obj/item/utensil + + abstract_type = /obj/item/utensil + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":1}' + attack_verb = list("attacked", "stabbed", "poked") + material = /decl/material/solid/metal/aluminium + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + chem_volume = 5 + + var/obj/item/food/loaded_food + var/utensil_flags + +/obj/item/utensil/Destroy() + QDEL_NULL(loaded_food) + return ..() + +/obj/item/utensil/Initialize() + . = ..() + if (prob(60)) + default_pixel_y = rand(0, 4) + reset_offsets(0) + set_extension(src, /datum/extension/tool/variable/simple, list( + TOOL_RETRACTOR = TOOL_QUALITY_BAD, + TOOL_HEMOSTAT = TOOL_QUALITY_MEDIOCRE + )) + +/obj/item/utensil/attack_self(mob/user) + return loaded_food ? loaded_food.attack_self(user) : ..() + +/obj/item/utensil/handle_eaten_by_mob(var/mob/user, var/mob/target) + . = loaded_food ? loaded_food.handle_eaten_by_mob(user, target) : ..() + if(QDELETED(loaded_food)) + loaded_food = null + update_icon() + +/obj/item/utensil/get_edible_material_amount(var/mob/eater) + return loaded_food ? loaded_food.get_edible_material_amount() : ..() + +/obj/item/utensil/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(loaded_food) + var/loaded_state = "[icon_state]_loaded" + if(check_state_in_icon(loaded_state, icon)) + add_overlay(overlay_image(icon, loaded_state, loaded_food.reagents?.get_color() || loaded_food.filling_color || get_color(), RESET_COLOR)) + +/obj/item/food/proc/handle_utensil_collection(obj/item/utensil/utensil, mob/user) + separate_food_chunk(utensil, user) + if(utensil.loaded_food) + to_chat(user, SPAN_NOTICE("You collect [utensil.loaded_food] with \the [utensil].")) + return TRUE + return FALSE + +/obj/item/food/proc/handle_utensil_scooping(obj/item/utensil/utensil, mob/user) + separate_food_chunk(utensil, user) + if(utensil.loaded_food) + to_chat(user, SPAN_NOTICE("You scoop up [utensil.loaded_food] with \the [utensil].")) + return TRUE + return FALSE + +// TODO: take some condiment, then another attackby to spread it onto bread/toast/etc. +/obj/item/food/proc/handle_utensil_spreading(obj/item/utensil/utensil, mob/user) + return FALSE + +/obj/item/food/proc/show_slice_message(mob/user, obj/item/tool) + user.visible_message( + SPAN_NOTICE("\The [user] slices \the [src]!"), + SPAN_NOTICE("You slice \the [src]!") + ) + +/obj/item/food/proc/show_slice_message_poor(mob/user, obj/item/tool) + user.visible_message( + SPAN_NOTICE("\The [user] crudely slices \the [src] with \the [tool]!"), + SPAN_NOTICE("You crudely slice \the [src] with your [tool.name]!") + ) + +/obj/item/food/proc/handle_utensil_cutting(obj/item/tool, mob/user) + + if(!is_sliceable()) + // TODO: cut a piece off to prepare a food item for another utensil. + return null + + if (!(isturf(loc) && ((locate(/obj/structure/table) in loc) || (locate(/obj/machinery/optable) in loc) || (locate(/obj/item/plate) in loc)))) + to_chat(user, SPAN_WARNING("You cannot slice \the [src] here! You need a table or at least a tray to do it.")) + return TRUE + + if (tool.w_class > ITEM_SIZE_NORMAL || !user.skill_check(SKILL_COOKING, SKILL_BASIC)) + show_slice_message_poor(user, tool) + slice_num = rand(1, max(1, round(slice_num*0.5))) + else + show_slice_message(user, tool, src) + + var/reagents_per_slice = max(1, round(REAGENT_TOTAL_VOLUME(reagents) / slice_num)) + for(var/i = 1 to slice_num) + var/atom/movable/slice = create_slice() + if(slice) + reagents.trans_to_obj(slice, reagents_per_slice) + LAZYADD(., slice) + qdel(src) + return . || TRUE + +/obj/item/food/proc/create_slice() + return new slice_path(loc, material?.type, TRUE) + +/obj/item/food/proc/do_utensil_interaction(obj/item/tool, mob/user) + + // Non-utensils. + if(istype(tool) && !istype(tool, /obj/item/utensil)) + return tool.has_edge() && (utensil_flags & UTENSIL_FLAG_SLICE) && handle_utensil_cutting(tool, user) + + var/obj/item/utensil/utensil = tool + if(!istype(utensil) || !utensil.utensil_flags) + return FALSE + if(utensil.loaded_food && (utensil.utensil_flags & UTENSIL_FLAG_SPREAD)) + if(!handle_utensil_spreading(utensil, user)) + to_chat(user, SPAN_WARNING("You already have something on \the [utensil].")) + return TRUE + if((utensil.has_edge() || (utensil.utensil_flags & UTENSIL_FLAG_SLICE)) && (utensil_flags & UTENSIL_FLAG_SLICE) && handle_utensil_cutting(utensil, user)) + return TRUE + if((utensil.is_sharp() || (utensil.utensil_flags & UTENSIL_FLAG_COLLECT)) && (utensil_flags & UTENSIL_FLAG_COLLECT) && handle_utensil_collection(utensil, user)) + return TRUE + if((utensil.utensil_flags & UTENSIL_FLAG_SCOOP) && (utensil_flags & UTENSIL_FLAG_SCOOP) && handle_utensil_scooping(utensil, user)) + return TRUE + return FALSE diff --git a/code/modules/food/utensils/utensil_chopsticks.dm b/code/modules/food/utensils/utensil_chopsticks.dm new file mode 100644 index 000000000000..7ff493ecfaf9 --- /dev/null +++ b/code/modules/food/utensils/utensil_chopsticks.dm @@ -0,0 +1,17 @@ +/obj/item/utensil/chopsticks + name = "chopsticks" + gender = PLURAL + desc = "A pair of sticks used for eating food." + icon = 'icons/obj/food/utensils/chopsticks.dmi' + utensil_flags = UTENSIL_FLAG_COLLECT + material = /decl/material/solid/organic/wood/oak //TODO: aspen + +/obj/item/utensil/chopsticks/plastic + material = /decl/material/solid/organic/plastic + +/obj/item/utensil/chopsticks/aluminium + material = /decl/material/solid/metal/aluminium + +/obj/item/utensil/chopsticks/bamboo + material = /decl/material/solid/organic/wood/bamboo + color = /decl/material/solid/organic/wood/bamboo::color \ No newline at end of file diff --git a/code/modules/food/utensils/utensil_fork.dm b/code/modules/food/utensils/utensil_fork.dm new file mode 100644 index 000000000000..9c0b6dc75f5e --- /dev/null +++ b/code/modules/food/utensils/utensil_fork.dm @@ -0,0 +1,8 @@ +/obj/item/utensil/fork + name = "fork" + desc = "It's a fork. Sure is pointy." + icon = 'icons/obj/food/utensils/fork.dmi' + utensil_flags = UTENSIL_FLAG_COLLECT + +/obj/item/utensil/fork/plastic + material = /decl/material/solid/organic/plastic diff --git a/code/modules/food/utensils/utensil_hybrid.dm b/code/modules/food/utensils/utensil_hybrid.dm new file mode 100644 index 000000000000..dde7a7e98952 --- /dev/null +++ b/code/modules/food/utensils/utensil_hybrid.dm @@ -0,0 +1,19 @@ +/obj/item/utensil/spork + name = "spork" + desc = "It's a spork. It's much like a fork, but much blunter." + icon = 'icons/obj/food/utensils/spork.dmi' + utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SCOOP + +/obj/item/utensil/spork/plastic + material = /decl/material/solid/organic/plastic + +/obj/item/utensil/foon + name = "foon" + desc = "It's a foon. It's much like a spoon, but much sharper." + icon = 'icons/obj/food/utensils/foon.dmi' + sharp = TRUE + edge = TRUE + utensil_flags = UTENSIL_FLAG_SLICE | UTENSIL_FLAG_SCOOP + +/obj/item/utensil/foon/plastic + material = /decl/material/solid/organic/plastic diff --git a/code/modules/food/utensils/utensil_knife.dm b/code/modules/food/utensils/utensil_knife.dm new file mode 100644 index 000000000000..fd98a7d568fd --- /dev/null +++ b/code/modules/food/utensils/utensil_knife.dm @@ -0,0 +1,18 @@ +/obj/item/utensil/knife + name = "table knife" + desc = "A simple table knife, used to cut up individual portions of food." + icon = 'icons/obj/food/utensils/steak_knife.dmi' + utensil_flags = UTENSIL_FLAG_SLICE | UTENSIL_FLAG_SPREAD + +/obj/item/utensil/knife/plastic + material = /decl/material/solid/organic/plastic + +/obj/item/utensil/knife/steak + name = "steak knife" + desc = "It's a steak knife with a serrated edge." + icon = 'icons/obj/food/utensils/steak_knife.dmi' + sharp = TRUE + edge = TRUE + utensil_flags = UTENSIL_FLAG_SLICE + material = /decl/material/solid/metal/steel + _base_attack_force = 6 diff --git a/code/modules/food/utensils/utensil_spoon.dm b/code/modules/food/utensils/utensil_spoon.dm new file mode 100644 index 000000000000..9c0c5846d324 --- /dev/null +++ b/code/modules/food/utensils/utensil_spoon.dm @@ -0,0 +1,22 @@ +/obj/item/utensil/spoon + name = "spoon" + desc = "It's a spoon. You can see your own upside-down face in it." + icon = 'icons/obj/food/utensils/spoon.dmi' + attack_verb = list("attacked", "poked") + utensil_flags = UTENSIL_FLAG_SCOOP + +/obj/item/utensil/spoon/Initialize() + . = ..() + if(!has_extension(src, /datum/extension/tool) && w_class > ITEM_SIZE_TINY) + set_extension(src, /datum/extension/tool, list( + // yes, this is entirely so you can dig normally with a comically large spoon + // a tiny spoon cannot be used to dig, a small spoon has a very slow multiplier, a huge spoon is basically a shovel + TOOL_SHOVEL = Interpolate(TOOL_QUALITY_WORST / 10, TOOL_QUALITY_MEDIOCRE, (w_class - ITEM_SIZE_SMALL) / (ITEM_SIZE_HUGE - ITEM_SIZE_SMALL)) + )) + +/obj/item/utensil/spoon/plastic + material = /decl/material/solid/organic/plastic + +/obj/item/utensil/spoon/wood + material = /decl/material/solid/organic/wood/oak + color = /decl/material/solid/organic/wood/oak::color diff --git a/code/modules/games/boardgame.dm b/code/modules/games/boardgame.dm index 08972c4bcb39..266a7030ea99 100644 --- a/code/modules/games/boardgame.dm +++ b/code/modules/games/boardgame.dm @@ -1,8 +1,9 @@ /obj/item/board name = "board" - desc = "A standard 16\" checkerboard. Well used." //Goddamn imperial system. + desc = "A standard 16\" checkerboard. Well-used." //Goddamn imperial system. icon = 'icons/obj/pieces.dmi' icon_state = "board" + material = /decl/material/solid/organic/wood/oak var/num = 0 var/board_icons = list() @@ -16,19 +17,20 @@ else ..() -/obj/item/board/attack_hand(mob/living/carbon/human/M) +/obj/item/board/attack_hand(mob/M) if(M.machine == src) return ..() - else - M.examinate(src) + M.examine_verb(src) + return TRUE -obj/item/board/attackby(obj/item/I, mob/user) - if(!addPiece(I,user)) - ..() +/obj/item/board/attackby(obj/item/used_item, mob/user) + if(addPiece(used_item,user)) + return TRUE + return ..() -/obj/item/board/proc/addPiece(obj/item/I, mob/user, var/tile = 0) - if(I.w_class != ITEM_SIZE_TINY) //only small stuff - user.show_message("\The [I] is too big to be used as a board piece.") +/obj/item/board/proc/addPiece(obj/item/used_item, mob/user, var/tile = 0) + if(used_item.w_class != ITEM_SIZE_TINY) //only small stuff + user.show_message("\The [used_item] is too big to be used as a board piece.") return 0 if(num == 64) user.show_message("\The [src] is already full!") @@ -38,22 +40,22 @@ obj/item/board/attackby(obj/item/I, mob/user) return 0 if(!user.Adjacent(src)) return 0 - if(!user.unEquip(I, src)) + if(!user.try_unequip(used_item, src)) return 0 num++ - if(!board_icons["[I.icon] [I.icon_state]"]) - board_icons["[I.icon] [I.icon_state]"] = new /icon(I.icon,I.icon_state) + if(!board_icons["[used_item.icon] [used_item.icon_state]"]) + board_icons["[used_item.icon] [used_item.icon_state]"] = new /icon(used_item.icon,used_item.icon_state) if(tile == 0) var i; for(i=0;i<64;i++) if(!board["[i]"]) - board["[i]"] = I + board["[i]"] = used_item break else - board["[tile]"] = I + board["[tile]"] = used_item src.updateDialog() @@ -85,21 +87,21 @@ obj/item/board/attackby(obj/item/I, mob/user) dat += "= 0 && !isobserver(user)) - dat += "
          Remove Selected Piece" + dat += "
          Remove Selected Piece" show_browser(user, jointext(dat, null), "window=boardgame;size=430x500") // 50px * 8 squares + 30 margin - onclose(usr, "boardgame") + onclose(user, "boardgame") /obj/item/board/Topic(href, href_list) if(!usr.Adjacent(src)) @@ -110,118 +112,152 @@ obj/item/board/attackby(obj/item/I, mob/user) if(!usr.incapacitated()) //you can't move pieces if you can't move if(href_list["select"]) var/s = href_list["select"] - var/obj/item/I = board["[s]"] + var/obj/item/thing = board["[s]"] if(selected >= 0) //check to see if clicked on tile is currently selected one if(text2num(s) == selected) selected = -1 //deselect it else - if(I) //cant put items on other items. + if(thing) //cant put items on other items. return //put item in new spot. - I = board["[selected]"] + thing = board["[selected]"] board["[selected]"] = null board -= "[selected]" board -= null - board["[s]"] = I + board["[s]"] = thing selected = -1 else - if(I) + if(thing) selected = text2num(s) else - var/mob/living/carbon/human/H = locate(href_list["person"]) + var/mob/living/human/H = locate(href_list["person"]) if(!istype(H)) return - var/obj/item/O = H.get_active_hand() + var/obj/item/O = H.get_active_held_item() if(!O) return addPiece(O,H,text2num(s)) if(href_list["remove"]) - var/obj/item/I = board["[selected]"] - if(!I) + var/obj/item/thing = board["[selected]"] + if(!thing) return board["[selected]"] = null board -= "[selected]" board -= null - I.forceMove(src.loc) + thing.forceMove(src.loc) num-- selected = -1 var j for(j=0;j<64;j++) if(board["[j]"]) var/obj/item/K = board["[j]"] - if(K.icon == I.icon && cmptext(K.icon_state,I.icon_state)) + if(K.icon == thing.icon && cmptext(K.icon_state,thing.icon_state)) src.updateDialog() return //Didn't find it in use, remove it and allow GC to delete it. - board_icons["[I.icon] [I.icon_state]"] = null - board_icons -= "[I.icon] [I.icon_state]" + board_icons["[thing.icon] [thing.icon_state]"] = null + board_icons -= "[thing.icon] [thing.icon_state]" board_icons -= null src.updateDialog() //Checkers -/obj/item/chems/food/snacks/checker +/obj/item/checker name = "checker" desc = "It is plastic and shiny." icon = 'icons/obj/pieces.dmi' icon_state = "checker_black" w_class = ITEM_SIZE_TINY - center_of_mass = @"{'x':16,'y':16}" - nutriment_desc = list("a choking hazard" = 4) - nutriment_amt = 1 + center_of_mass = @'{"x":16,"y":16}' var/piece_color ="black" -/obj/item/chems/food/snacks/checker/Initialize() +// Override these to let people eat checkers. +/obj/item/checker/is_edible(mob/eater) + return TRUE + +/obj/item/checker/is_food_empty(mob/eater) + return FALSE + +/obj/item/checker/transfer_eaten_material(mob/eater, amount) + if(isliving(eater)) + var/mob/living/living_eater = eater + living_eater.get_ingested_reagents()?.add_reagent(/decl/material/solid/organic/plastic, 3) + +/obj/item/checker/play_feed_sound(mob/user, consumption_method = EATING_METHOD_EAT) + return + +/obj/item/checker/show_food_consumed_message(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + return + +/obj/item/checker/show_feed_message_start(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(user) + if(user == target) + to_chat(user, SPAN_NOTICE("You begin trying to swallow \the [target].")) + else + user.visible_message(SPAN_NOTICE("\The [user] attempts to force \the [target] to swallow \the [src]!")) + +/obj/item/checker/show_feed_message_end(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(user) + if(user == target) + to_chat(user, SPAN_NOTICE("You swallow \the [src].")) + else + user.visible_message(SPAN_NOTICE("\The [user] forces \the [target] to swallow \the [src]!")) + +// End food overrides. + +/obj/item/checker/Initialize() . = ..() icon_state = "[name]_[piece_color]" name = "[piece_color] [name]" -/obj/item/chems/food/snacks/checker/red +/obj/item/checker/red piece_color ="red" //Chess -/obj/item/chems/food/snacks/checker/pawn +/obj/item/checker/pawn name = "pawn" desc = "How many pawns will die in your war?" -/obj/item/chems/food/snacks/checker/pawn/red +/obj/item/checker/pawn/red piece_color ="red" -/obj/item/chems/food/snacks/checker/knight +/obj/item/checker/knight name = "knight" desc = "The piece chess deserves, and needs to actually play." -/obj/item/chems/food/snacks/checker/knight/red +/obj/item/checker/knight/red piece_color ="red" -/obj/item/chems/food/snacks/checker/bishop +/obj/item/checker/bishop name = "bishop" - desc = "What corruption occured, urging holy men to fight?" + desc = "What corruption occurred, urging holy men to fight?" -/obj/item/chems/food/snacks/checker/bishop/red +/obj/item/checker/bishop/red piece_color ="red" -/obj/item/chems/food/snacks/checker/rook +/obj/item/checker/rook name = "rook" desc = "Representing ancient moving towers. So powerful and fast they were banned from wars, forever." -/obj/item/chems/food/snacks/checker/rook/red +/obj/item/checker/rook/red piece_color ="red" -/obj/item/chems/food/snacks/checker/queen +/obj/item/checker/queen name = "queen" desc = "A queen of battle and pain. She dances across the battlefield." -/obj/item/chems/food/snacks/checker/queen/red +/obj/item/checker/queen/red piece_color ="red" -/obj/item/chems/food/snacks/checker/king +/obj/item/checker/king name = "king" desc = "Why does a chess game end when the king dies?" -/obj/item/chems/food/snacks/checker/king/red +/obj/item/checker/king/red piece_color ="red" \ No newline at end of file diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index 38e6bce9908e..8f729cbb4bcb 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -8,20 +8,31 @@ return image(deck_icon, concealed ? back_icon : card_icon) /datum/playingcard/custom - var/use_custom_front = TRUE - var/use_custom_back = TRUE + var/use_custom_front + var/use_custom_back /datum/playingcard/custom/card_image(concealed, deck_icon) if(concealed) - return image((src.use_custom_back ? CUSTOM_ITEM_OBJ : deck_icon), "[back_icon]") + return image(use_custom_back || deck_icon, "[back_icon]") else - return image((src.use_custom_front ? CUSTOM_ITEM_OBJ : deck_icon), "[card_icon]") + return image(use_custom_front || deck_icon, "[card_icon]") +var/global/list/card_decks = list() /obj/item/deck w_class = ITEM_SIZE_SMALL icon = 'icons/obj/items/playing_cards.dmi' + material = /decl/material/solid/organic/cardboard var/list/cards = list() +/obj/item/deck/Initialize() + . = ..() + global.card_decks += src + generate_cards() + +/obj/item/deck/Destroy() + . = ..() + global.card_decks -= src + /obj/item/deck/inherit_custom_item_data(var/datum/custom_item/citem) . = ..() if(islist(citem.additional_data["extra_cards"])) @@ -36,26 +47,30 @@ P.back_icon = card_decl["back_icon"] if(!isnull(card_decl["desc"])) P.desc = card_decl["desc"] - if(!isnull(card_decl["use_custom_front"])) - P.use_custom_front = card_decl["use_custom_front"] - if(!isnull(card_decl["use_custom_back"])) - P.use_custom_back = card_decl["use_custom_back"] + finalize_custom_item_data(P, card_decl) // Separate proc in case of runtime. cards += P +/obj/item/deck/proc/finalize_custom_item_data(var/datum/playingcard/custom/P, var/card_decl) + if(!istype(P) || !card_decl) + return + if(!isnull(card_decl["use_custom_front"])) + var/card_front = card_decl["use_custom_front"] + P.use_custom_front = fexists(card_front) && file(card_front) + if(!isnull(card_decl["use_custom_back"])) + var/card_back = card_decl["use_custom_back"] + P.use_custom_back = fexists(card_back) && file(card_back) + /obj/item/deck/holder name = "card box" desc = "A small leather case to show how classy you are compared to everyone else." icon_state = "card_holder" + material = /decl/material/solid/organic/leather /obj/item/deck/cards name = "deck of cards" desc = "A simple deck of playing cards." icon_state = "deck" -/obj/item/deck/Initialize() - . = ..() - generate_cards() - /obj/item/deck/proc/generate_cards() return @@ -91,7 +106,7 @@ /obj/item/deck/compact name = "compact deck of cards" - desc = "A deck of playing cards. Looks like this one hasn't numbers from two to five, and jokers." + desc = "A deck of playing cards. Looks like this one is missing numbers from two to five, and both jokers." icon_state = "deck" /obj/item/deck/compact/generate_cards() @@ -118,28 +133,28 @@ P.back_icon = "card_back" cards += P -/obj/item/deck/attack_hand() - if(!usr) - return - - draw_card(usr) +/obj/item/deck/attack_hand(mob/user) + if(user.check_intent(I_FLAG_GRAB) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + draw_card(user) + return TRUE -/obj/item/deck/examine(mob/user) +/obj/item/deck/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(cards.len) - to_chat(user, "
          There is still [cards.len] card[cards.len > 1? "s" : ""].") - to_chat(user, SPAN_NOTICE("You can deal cards at a table with clicking at it with grab intent.")) + . += "
          There [cards.len == 1 ? "is" : "are"] still [cards.len] card\s." + . += SPAN_NOTICE("You can deal cards at a table by clicking on it with grab intent.") -/obj/item/deck/attackby(obj/O, mob/user) - if(istype(O,/obj/item/hand)) - var/obj/item/hand/H = O +/obj/item/deck/attackby(obj/item/used_item, mob/user) + if(istype(used_item,/obj/item/hand)) + var/obj/item/hand/H = used_item for(var/datum/playingcard/P in H.cards) cards += P - qdel(O) + qdel(used_item) to_chat(user, "You place your cards on the bottom of \the [src].") - return - ..() + return TRUE + return ..() /obj/item/deck/verb/draw_card() @@ -148,27 +163,22 @@ set desc = "Draw a card from a deck." set src in view(1) - if(usr.stat || !Adjacent(usr)) return - - if(!istype(usr,/mob/living/carbon)) + // TODO: let dogs play poker + if(!ishuman(usr) || usr.incapacitated() || !Adjacent(usr)) return - var/mob/living/carbon/user = usr - + var/mob/living/human/user = usr if(!cards.len) to_chat(usr, "There are no cards in the deck.") return - var/obj/item/hand/H - if(user.l_hand && istype(user.l_hand,/obj/item/hand)) - H = user.l_hand - else if(user.r_hand && istype(user.r_hand,/obj/item/hand)) - H = user.r_hand - else + var/obj/item/hand/H = locate() in user.get_held_items() + if(!H) H = new(get_turf(src)) user.put_in_hands(H) - if(!H || !user) return + if(!H || !user) + return var/datum/playingcard/P = cards[1] H.cards += P @@ -195,7 +205,6 @@ for(var/mob/living/player in viewers(3)) if(!player.stat) players += player - //players -= usr var/mob/living/M = input("Who do you wish to deal a card?") as null|anything in players if(!usr || !src || !M) return @@ -211,16 +220,17 @@ H.concealed = 1 H.update_icon() if(user==target) - user.visible_message("\The [user] deals a card to \himself.") + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message("\The [user] deals a card to [pronouns.self].") else user.visible_message("\The [user] deals a card to \the [target].") H.throw_at(get_step(target, ismob(target) ? target.dir : target), 10, 1,user) -/obj/item/hand/attackby(obj/O, mob/user) +/obj/item/hand/attackby(obj/item/used_item, mob/user) - if(istype(O,/obj/item/hand)) - var/obj/item/hand/H = O + if(istype(used_item,/obj/item/hand)) + var/obj/item/hand/H = used_item for(var/datum/playingcard/P in cards) H.cards += P H.concealed = src.concealed @@ -229,7 +239,7 @@ H.name = "hand of [(H.cards.len)] card\s" return TRUE - if(length(cards) == 1 && istype(O, /obj/item/pen)) + if(length(cards) == 1 && IS_PEN(used_item)) var/datum/playingcard/P = cards[1] if(lowertext(P.name) != "blank card") to_chat(user, SPAN_WARNING("You cannot write on that card.")) @@ -248,31 +258,19 @@ cards = shuffle(cards) user.visible_message("\The [user] shuffles [src].") -/obj/item/deck/MouseDrop(atom/over) - if(over == usr && !usr.incapacitated() && (usr.contents.Find(src) || in_range(src, usr))) - if(!ishuman(over)) - return - - if(!usr.get_active_hand()) //if active hand is empty - var/mob/living/carbon/human/H = over - var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] - - if(H.hand) - temp = H.organs_by_name[BP_L_HAND] - if(temp && !temp.is_usable()) - to_chat(over, SPAN_NOTICE("You try to move your [temp.name], but cannot!")) - return - - to_chat(over, SPAN_NOTICE("You pick up the [src].")) - usr.put_in_hands(src) +/obj/item/deck/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && (loc == user || in_range(src, user)) && user.get_empty_hand_slot()) + user.put_in_hands(src) + return TRUE + . = ..() -/obj/item/pack/ +/obj/item/pack name = "card pack" - desc = "For those with disposible income." - + desc = "For those with disposable income." icon_state = "card_pack" icon = 'icons/obj/items/playing_cards.dmi' - w_class = ITEM_SIZE_TINY + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/cardboard var/list/cards = list() @@ -293,8 +291,11 @@ icon = 'icons/obj/items/playing_cards.dmi' icon_state = "empty" w_class = ITEM_SIZE_TINY - + material = /decl/material/solid/organic/cardboard + dir = NORTH // our default dir is expected to be north, e.g. we've been placed by someone facing north var/concealed = 0 + /// Whether or not we should shift our icons according to our dir or not. + var/is_on_table = FALSE var/list/datum/playingcard/cards = list() /obj/item/hand/attack_self(var/mob/user) @@ -303,77 +304,78 @@ user.visible_message("\The [user] [concealed ? "conceals" : "reveals"] their hand.") /obj/item/hand/attack_hand(mob/user) - if(src.loc == user) - // build the list of cards in the hand - var/list/to_discard = list() - for(var/datum/playingcard/P in cards) - to_discard[P.name] = P - var/discarding = null - //don't prompt if only 1 card - if(to_discard.len == 1) - discarding = to_discard[1] - else - discarding = input(user, "Which card do you wish to take?") as null|anything in to_discard - if(!discarding || !to_discard[discarding] || !CanPhysicallyInteract(user)) return - - var/datum/playingcard/card = to_discard[discarding] - var/obj/item/hand/new_hand = new(src.loc) - new_hand.cards += card - cards -= card - new_hand.concealed = 0 - new_hand.update_icon() - src.update_icon() - - if(!cards.len) - qdel(src) + if(loc != user && !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() - user.put_in_hands(new_hand) + // build the list of cards in the hand + var/list/to_discard = list() + for(var/datum/playingcard/P in cards) + to_discard[P.name] = P + var/discarding = null + //don't prompt if only 1 card + if(to_discard.len == 1) + discarding = to_discard[1] else - . = ..() + discarding = input(user, "Which card do you wish to take?") as null|anything in to_discard + if(!discarding || !to_discard[discarding] || !CanPhysicallyInteract(user)) + return TRUE -/obj/item/hand/examine(mob/user) - . = ..() - if((!concealed || src.loc == user) && cards.len) - to_chat(user, "It contains: ") - for(var/datum/playingcard/P in cards) - to_chat(user, "\The [APPEND_FULLSTOP_IF_NEEDED(P.name)]") + var/datum/playingcard/card = to_discard[discarding] + var/obj/item/hand/new_hand = new(src.loc) + new_hand.cards += card + cards -= card + new_hand.concealed = 0 + new_hand.update_icon() + src.update_icon() -/obj/item/hand/on_update_icon(var/direction = 0) if(!cards.len) qdel(src) - return - else if(cards.len > 1) - name = "hand of cards" - desc = "Some playing cards." - else if(concealed) - name = "single playing card" - desc = "An unknown playing card, concealed." - else - var/datum/playingcard/P = cards[1] - name = "[P.name]" - desc = "[P.desc]" + user.put_in_hands(new_hand) + return TRUE - overlays.Cut() +/obj/item/hand/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if((!concealed || src.loc == user) && cards.len) + . += "It contains:" + for(var/datum/playingcard/P in cards) + . += "\The [APPEND_FULLSTOP_IF_NEEDED(P.name)]" - if(cards.len == 1) - var/datum/playingcard/P = cards[1] - var/image/I = P.card_image(concealed, src.icon) - I.pixel_x += (-5+rand(10)) - I.pixel_y += (-5+rand(10)) - overlays += I - return +/obj/item/hand/on_update_icon() + . = ..() + var/card_count = length(cards) + switch(card_count) + if(0) + qdel(src) + return + if(1) + var/datum/playingcard/top_card = cards[1] + if(concealed) + name = "single playing card" + desc = "An unknown playing card, concealed." + else + name = top_card.name + desc = top_card.desc + var/image/I = top_card.card_image(concealed, src.icon) + I.pixel_x += (-5+rand(10)) + I.pixel_y += (-5+rand(10)) + add_overlay(I) + compile_overlays() + return + else + name = "hand of cards" + desc = "Some playing cards." - var/offset = Floor(20/cards.len) + var/offset = floor(20/card_count) var/matrix/M = matrix() - if(direction) - switch(direction) + if(is_on_table) + switch(dir) if(NORTH) - M.Translate( 0, 0) + M.Translate( 0, 0) // Technically redundant but it makes the logic clearer. if(SOUTH) M.Translate( 0, 4) if(WEST) - M.Turn(90) + M.Turn(-90) M.Translate( 3, 0) if(EAST) M.Turn(90) @@ -381,38 +383,46 @@ var/i = 0 for(var/datum/playingcard/P in cards) var/image/I = P.card_image(concealed, src.icon) - //I.pixel_x = origin+(offset*i) - switch(direction) + switch(dir) if(SOUTH) I.pixel_x = 8-(offset*i) if(WEST) I.pixel_y = -6+(offset*i) if(EAST) I.pixel_y = 8-(offset*i) - else + if(NORTH) I.pixel_x = -7+(offset*i) + // other dirs are explicitly unsupported! I.transform = M - overlays += I + add_overlay(I) i++ + compile_overlays() // these should be as responsive as possible /obj/item/hand/dropped(mob/user) ..() - if(locate(/obj/structure/table, loc)) - src.update_icon(user.dir) + if(locate(/obj/structure/table) in loc) + is_on_table = TRUE + set_dir(user.dir) else - update_icon() + is_on_table = FALSE + set_dir(initial(dir)) + update_icon() -/obj/item/hand/pickup(mob/user) - src.update_icon() +/obj/item/hand/on_picked_up(mob/user, atom/old_loc) + ..() + is_on_table = FALSE + set_dir(initial(dir)) + update_icon() /*** A special thing that steals a card from a deck, probably lost in maint somewhere. ***/ /obj/item/hand/missing_card name = "missing playing card" + is_spawnable_type = FALSE //Can't spawn this for tests because it kills itself /obj/item/hand/missing_card/Initialize() . = ..() var/list/deck_list = list() - for(var/obj/item/deck/D in world) + for(var/obj/item/deck/D in global.card_decks) if(isturf(D.loc)) //Decks hiding in inventories are safe. Respect the sanctity of loadout items. deck_list += D diff --git a/code/modules/games/cards_cag.dm b/code/modules/games/cards_cag.dm index ff626549eb91..20784d85249c 100644 --- a/code/modules/games/cards_cag.dm +++ b/code/modules/games/cards_cag.dm @@ -1,10 +1,11 @@ -var/list/cag_card_text_lists = list() +var/global/list/cag_card_text_lists = list() // This is a parody of Cards Against Humanity (https://en.wikipedia.org/wiki/Cards_Against_Humanity) // which is licensed under CC BY-NC-SA 2.0, the full text of which can be found at the following URL: // https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode /obj/item/deck/cag + abstract_type = /obj/item/deck/cag var/load_text_from_file /obj/item/deck/cag/Initialize() diff --git a/code/modules/games/spaceball_cards.dm b/code/modules/games/spaceball_cards.dm index da8d101b9ace..835a2d99ad1e 100644 --- a/code/modules/games/spaceball_cards.dm +++ b/code/modules/games/spaceball_cards.dm @@ -10,14 +10,13 @@ for(i=0;i<5;i++) P = new() if(prob(1)) - P.name = "Spaceball Jones, [game_year] Brickburn Galaxy Trekers" + P.name = "Spaceball Jones, [global.using_map.game_year] Brickburn Galaxy Trekers" P.desc = "An autographed Spaceball Jones card!!" P.card_icon = "spaceball_jones" else - var/language_type = pick(/decl/language/human) - var/decl/language/L = new language_type() + var/decl/language/L = GET_DECL(/decl/language/human/common) var/team = pick("Brickburn Galaxy Trekers","Mars Rovers", "Qerrbalak Saints", "Moghes Rockets", "Ahdomai Lightening") - P.name = "[L.get_random_name(pick(MALE,FEMALE))], [game_year - rand(0,50)] [team]" + P.name = "[L.get_random_language_name(pick(MALE,FEMALE))], [global.using_map.game_year - rand(0,50)] [team]" P.card_icon = "spaceball_standard" P.desc = "A Spaceball playing card." P.back_icon = "card_back_spaceball" diff --git a/code/modules/gemstones/_gemstone.dm b/code/modules/gemstones/_gemstone.dm new file mode 100644 index 000000000000..02d698d4a130 --- /dev/null +++ b/code/modules/gemstones/_gemstone.dm @@ -0,0 +1,115 @@ +var/global/list/_available_gemstone_cuts + +/proc/get_available_gemstone_cuts() + if(!global._available_gemstone_cuts) + global._available_gemstone_cuts = list() + for(var/decl/gemstone_cut/cut as anything in decls_repository.get_decls_of_type_unassociated(/decl/gemstone_cut)) + if(cut.can_be_cut) + global._available_gemstone_cuts += cut + return global._available_gemstone_cuts + +/obj/item/gemstone + name = "uncut gemstone" + desc = "A hunk of uncut gemstone." + icon = 'icons/obj/items/gemstones/uncut.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/gemstone/diamond + material_alteration = MAT_FLAG_ALTERATION_COLOR // Name and desc are handled manually. + color = /decl/material/solid/gemstone/diamond::color + var/decl/gemstone_cut/cut = /decl/gemstone_cut/uncut + var/work_skill = SKILL_CONSTRUCTION + +/obj/item/gemstone/Initialize(ml, material_key) + cut = GET_DECL(cut) + . = ..() + update_from_cut() + +/obj/item/gemstone/proc/update_from_cut() + icon = cut.icon + desc = cut.desc + update_name() + update_icon() + +/obj/item/gemstone/update_name() + SetName("[cut.adjective] [material.solid_name]") + +/obj/item/gemstone/get_single_monetary_worth() + . = ..() * cut.worth_multiplier + +/obj/item/gemstone/attackby(obj/item/used_item, mob/user) + if(IS_CHISEL(used_item) && !user.check_intent(I_FLAG_HARM)) + if(!cut.can_attempt_cut) + to_chat(user, SPAN_WARNING("\The [src] has already been cut.")) + return TRUE + var/decl/gemstone_cut/desired_cut = input(user, "What cut would you like to attempt?", "Cut Gemstone") as null|anything in get_available_gemstone_cuts() + if(!desired_cut || QDELETED(src) || QDELETED(user) || !CanPhysicallyInteract(user) || !cut.can_attempt_cut) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] begins carefully cutting \the [src].")) + if(!user.do_skilled(10 SECONDS, work_skill, src, check_holding = TRUE) || !CanPhysicallyInteract(user)) + if(QDELETED(src) || !cut.can_attempt_cut || QDELETED(user)) + return TRUE + to_chat(user, SPAN_DANGER("You were interrupted, botching the cut!")) + cut = GET_DECL(/decl/gemstone_cut/poor) + else + if(QDELETED(src) || !cut.can_attempt_cut || QDELETED(user)) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] finishes cutting \the [src].")) + if(user.skill_fail_prob(work_skill, 100, SKILL_EXPERT)) + to_chat(user, SPAN_DANGER("You've done a really poor job...")) + cut = GET_DECL(/decl/gemstone_cut/poor) + else + cut = desired_cut + update_from_cut() + return TRUE + . = ..() + +// Subtypes for mapping/spawning etc. +/obj/item/gemstone/poor + name = "poorly-cut diamond" + cut = /decl/gemstone_cut/poor + icon = 'icons/obj/items/gemstones/poor.dmi' + +/obj/item/gemstone/baguette + name = "baguette-cut diamond" + cut = /decl/gemstone_cut/baguette + icon = 'icons/obj/items/gemstones/baguette.dmi' + +/obj/item/gemstone/hexagon + name = "hexagon-cut diamond" + cut = /decl/gemstone_cut/hexagon + icon = 'icons/obj/items/gemstones/hexagon.dmi' + +/obj/item/gemstone/octagon + name = "octagon-cut diamond" + cut = /decl/gemstone_cut/octagon + icon = 'icons/obj/items/gemstones/octagon.dmi' + +/obj/item/gemstone/round + name = "round-cut diamond" + cut = /decl/gemstone_cut/round + icon = 'icons/obj/items/gemstones/round.dmi' + + +// Material subtypes. +#define MATERIAL_CUT_GEMSTONES(MAT)\ +/obj/item/gemstone/baguette/##MAT{\ + material = /decl/material/solid/gemstone/##MAT;\ + color = /decl/material/solid/gemstone/##MAT::color;\ +}\ +/obj/item/gemstone/hexagon/##MAT{\ + material = /decl/material/solid/gemstone/##MAT;\ + color = /decl/material/solid/gemstone/##MAT::color;\ +}\ +/obj/item/gemstone/octagon/##MAT{\ + material = /decl/material/solid/gemstone/##MAT;\ + color = /decl/material/solid/gemstone/##MAT::color;\ +}\ +/obj/item/gemstone/round/##MAT{\ + material = /decl/material/solid/gemstone/##MAT;\ + color = /decl/material/solid/gemstone/##MAT::color;\ +} + +MATERIAL_CUT_GEMSTONES(topaz) +MATERIAL_CUT_GEMSTONES(sapphire) +MATERIAL_CUT_GEMSTONES(ruby) \ No newline at end of file diff --git a/code/modules/gemstones/gemstone_cuts.dm b/code/modules/gemstones/gemstone_cuts.dm new file mode 100644 index 000000000000..a880d09644f6 --- /dev/null +++ b/code/modules/gemstones/gemstone_cuts.dm @@ -0,0 +1,76 @@ +/decl/gemstone_cut + abstract_type = /decl/gemstone_cut + var/worth_multiplier = 1.5 + var/name + var/desc + var/adjective + var/icon + // Can we cut this cut into a new cut? + var/can_attempt_cut = FALSE + // Can we attempt to cut to this cut? + var/can_be_cut = TRUE + +/decl/gemstone_cut/validate() + . = ..() + if(!istext(name)) + . += "invalid or null name" + if(!istext(desc)) + . += "invalid or null desc" + if(!istext(adjective)) + . += "invalid or null adjective" + if(icon) + if(!check_state_in_icon(ICON_STATE_WORLD, icon)) + . += "missing world state from '[icon]'" + if(!check_state_in_icon(ICON_STATE_INV, icon)) + . += "missing inventory state from '[icon]'" + var/decl/item_decoration/gem_set = GET_DECL(/decl/item_decoration/setting) + var/check_state = "[ICON_STATE_WORLD]-[gem_set.icon_state_modifier]" + if(!check_state_in_icon(check_state, icon)) + . += "missing state '[check_state]' from '[icon]'" + check_state = "[ICON_STATE_INV]-[gem_set.icon_state_modifier]" + if(!check_state_in_icon(check_state, icon)) + . += "missing state '[check_state]' from '[icon]'" + else + . += "null or unset icon" + +// Subtypes below. +/decl/gemstone_cut/uncut + name = "uncut" + adjective = "uncut" + desc = "A rough, uncut gemstone." + icon = 'icons/obj/items/gemstones/uncut.dmi' + can_attempt_cut = TRUE + can_be_cut = FALSE + worth_multiplier = 1 + +/decl/gemstone_cut/poor + name = "poorly-cut" + adjective = "poorly-cut" + desc = "A poorly-cut and uneven gemstone." + icon = 'icons/obj/items/gemstones/poor.dmi' + worth_multiplier = 0.5 + can_be_cut = FALSE + +/decl/gemstone_cut/baguette + name = "baguette" + adjective = "baguette-cut" + desc = "A square-cut gemstone." + icon = 'icons/obj/items/gemstones/baguette.dmi' + +/decl/gemstone_cut/hexagon + name = "hexagon" + adjective = "hexagon-cut" + desc = "A hexagon-cut gemstone." + icon = 'icons/obj/items/gemstones/hexagon.dmi' + +/decl/gemstone_cut/octagon + name = "octagon" + adjective = "octagon-cut" + desc = "An octagon-cut gemstone." + icon = 'icons/obj/items/gemstones/octagon.dmi' + +/decl/gemstone_cut/round + name = "round" + adjective = "round-cut" + desc = "A round-cut gemstone." + icon = 'icons/obj/items/gemstones/round.dmi' diff --git a/code/modules/genetics/_gene.dm b/code/modules/genetics/_gene.dm new file mode 100644 index 000000000000..02c40d3691b6 --- /dev/null +++ b/code/modules/genetics/_gene.dm @@ -0,0 +1,7 @@ +/* +TODO: Post DNA2 removal, shared gene data subtype. +/decl/gene + abstract_type = /decl/gene + var/expected_source + var/expected_target +*/ \ No newline at end of file diff --git a/code/modules/genetics/plants/_gene_plant.dm b/code/modules/genetics/plants/_gene_plant.dm new file mode 100644 index 000000000000..79168f4345ac --- /dev/null +++ b/code/modules/genetics/plants/_gene_plant.dm @@ -0,0 +1,63 @@ +/decl/plant_gene + abstract_type = /decl/plant_gene + //expected_source = /datum/seed + //expected_target = /datum/seed + /// Set to a randomized gene mask in Initialize(). + var/name + /// Actual name of the gene, used mostly for VV. + var/unmasked_name + /// A list of trait values to copy wholesale in copy_initial_seed_values(). + var/list/associated_traits + /// Tracker to make sure masked names are unique. + var/static/list/_used_masks = list() + +/decl/plant_gene/Initialize() + . = ..() + while(isnull(name) || (name in _used_masks)) + name = uppertext(num2hex(rand(0,255))) + _used_masks |= name + +/decl/plant_gene/validate() + . = ..() + if(!istext(name) || length(name) != 2) + . += "null or invalid post-mask name: [name || "NULL"]" + if(!istext(unmasked_name)) + . += "null or invalid unmasked name: [unmasked_name || "NULL"]" + for(var/trait in associated_traits) + if(!ispath(trait, /decl/plant_trait)) + . += "erroneous trait value in associated traits: [trait || "NULL"]" + +// Splicing products has some detrimental effects on yield and lifespan. +// We handle this before we do the rest of the looping (in overrides), as normal traits don't really include lists. +/decl/plant_gene/proc/modify_seed(datum/plantgene/gene, datum/seed/seed) + SHOULD_CALL_PARENT(TRUE) + for(var/trait in gene.values) + seed.set_trait(trait, gene.values[trait]) + +// Specific gene data is handled in overrides before calling parent. +/decl/plant_gene/proc/copy_initial_seed_values(datum/plantgene/gene, datum/seed/seed) + SHOULD_CALL_PARENT(TRUE) + if(length(associated_traits)) + for(var/trait in associated_traits) + LAZYSET(gene.values, trait, seed.get_trait(trait)) + +/decl/plant_gene/proc/mutate(datum/seed/seed, turf/location) + return + +// Instance of a gene, used for copying data around. Functionally just a holder for a list. +// Could probably be replaced by `/decl/plant_gene/foo = list(some_trait = some_value)` down the track. +/datum/plantgene + /// Reference back to our master + var/decl/plant_gene/genetype + /// Values to copy into the target seed datum. + var/list/values + +/datum/plantgene/New(decl/plant_gene/gene_archetype, datum/seed/donor) + genetype = gene_archetype + if(ispath(genetype)) + genetype = GET_DECL(genetype) + if(!istype(genetype)) + CRASH("Non-gene decl data passed to plant gene instance: [gene_archetype || "NULL"].") + if(!istype(donor)) + CRASH("Non-seed datum passed to plant gene instance: [donor || "NULL"].") + genetype.copy_initial_seed_values(src, donor) diff --git a/code/modules/genetics/plants/_plant_trait.dm b/code/modules/genetics/plants/_plant_trait.dm new file mode 100644 index 000000000000..59e22f1ace56 --- /dev/null +++ b/code/modules/genetics/plants/_plant_trait.dm @@ -0,0 +1,36 @@ +/decl/plant_trait + abstract_type = /decl/plant_trait + /// Descriptive name for this trait. + var/name + /// Shows a simple name: value header in the plant scanner. + var/shows_general_data = FALSE + /// Provides a dynamic string to the plant scanner (see get_extended_data()) + var/shows_extended_data = FALSE + /// Multiplier for value when calculating seed worth. + var/base_worth = 0 + /// Value assumed if the trait has not been inserted into the traits list. + var/default_value = 0 + /// Set to skip master gene checking in validate(). + var/requires_master_gene = TRUE + +/decl/plant_trait/proc/get_station_survivable_value() + return + +/decl/plant_trait/proc/get_extended_data(val, datum/seed/grown_seed) + return + +/decl/plant_trait/proc/get_worth_of_value(val) + return base_worth * val + +/decl/plant_trait/proc/handle_post_trait_set(datum/seed/seed) + return + +/decl/plant_trait/validate() + . = ..() + if(!istext(name)) + . += "null or invalid name: [name || "NULL"]" + if(requires_master_gene) + for(var/decl/plant_gene/plant_gene in decls_repository.get_decls_of_subtype_unassociated(/decl/plant_gene)) + if(type in plant_gene.associated_traits) + return + . += "could not find master gene" diff --git a/code/modules/genetics/plants/gene_atmosphere.dm b/code/modules/genetics/plants/gene_atmosphere.dm new file mode 100644 index 000000000000..f51bd5d7a28c --- /dev/null +++ b/code/modules/genetics/plants/gene_atmosphere.dm @@ -0,0 +1,15 @@ +/decl/plant_gene/atmosphere + unmasked_name = "atmosphere" + associated_traits = list( + TRAIT_HEAT_TOLERANCE, + TRAIT_LOWKPA_TOLERANCE, + TRAIT_HIGHKPA_TOLERANCE + ) + +/decl/plant_gene/atmosphere/mutate(datum/seed/seed, turf/location) + if(prob(60)) + seed.set_trait(TRAIT_HEAT_TOLERANCE, seed.get_trait(TRAIT_HEAT_TOLERANCE)+rand(-5,5),800,70) + if(prob(60)) + seed.set_trait(TRAIT_LOWKPA_TOLERANCE, seed.get_trait(TRAIT_LOWKPA_TOLERANCE)+rand(-5,5),80,0) + if(prob(60)) + seed.set_trait(TRAIT_HIGHKPA_TOLERANCE, seed.get_trait(TRAIT_HIGHKPA_TOLERANCE)+rand(-5,5),500,110) diff --git a/code/modules/genetics/plants/gene_biochemistry.dm b/code/modules/genetics/plants/gene_biochemistry.dm new file mode 100644 index 000000000000..74276d797a6f --- /dev/null +++ b/code/modules/genetics/plants/gene_biochemistry.dm @@ -0,0 +1,56 @@ +/decl/plant_gene/biochemistry + unmasked_name = "biochemistry" + associated_traits = list( + TRAIT_POTENCY + ) + var/list/modify_traits = list( + TRAIT_YIELD, + TRAIT_ENDURANCE + ) + +/decl/plant_gene/biochemistry/mutate(datum/seed/seed) + seed.set_trait(TRAIT_POTENCY, seed.get_trait(TRAIT_POTENCY)+rand(-20,20),200, 0) + +/decl/plant_gene/biochemistry/modify_seed(datum/plantgene/gene, datum/seed/seed) + + for(var/trait in modify_traits) + if(seed.get_trait(trait) > 0) + seed.set_trait(trait, seed.get_trait(trait), null, 1, 0.85) + + seed.produces_pollen = LAZYACCESS(gene.values, TRAIT_POLLEN) + + var/list/gene_value = LAZYACCESS(gene.values, TRAIT_CHEMS) + for(var/rid in gene_value) + + var/list/gene_chem = gene_value[rid] + if(!seed.get_chemical_amount(rid)) + seed.set_chemical_amount(rid, gene_chem.Copy()) + continue + + for(var/i = 1 to length(gene_chem)) + if(isnull(gene_chem[i])) + gene_chem[i] = 0 + var/list/seed_chems = seed.get_chemical_amount(rid) + if(LAZYACCESS(seed_chems, i)) + seed_chems[i] = max(1, round((gene_chem[i] + seed_chems[i])/2)) + else + seed_chems[i] = gene_chem[i] + seed.set_chemical_amount(rid, seed_chems) + + var/list/new_gasses = LAZYACCESS(gene.values, TRAIT_EXUDE_GASSES) + if(islist(new_gasses) && length(new_gasses)) + LAZYDISTINCTADD(seed.exude_gasses, new_gasses) + for(var/gas in seed.exude_gasses) + seed.exude_gasses[gas] = max(1, round(seed.exude_gasses[gas] * 0.8)) + + LAZYREMOVE(gene.values, TRAIT_EXUDE_GASSES) + LAZYREMOVE(gene.values, TRAIT_CHEMS) + LAZYREMOVE(gene.values, TRAIT_POLLEN) + + return ..() + +/decl/plant_gene/biochemistry/copy_initial_seed_values(datum/plantgene/gene, datum/seed/seed) + LAZYSET(gene.values, TRAIT_CHEMS, deepCopyList(seed.get_chemical_composition())) + LAZYSET(gene.values, TRAIT_EXUDE_GASSES, seed.exude_gasses?.Copy()) + LAZYSET(gene.values, TRAIT_POLLEN, seed.produces_pollen) + return ..() diff --git a/code/modules/genetics/plants/gene_diet.dm b/code/modules/genetics/plants/gene_diet.dm new file mode 100644 index 000000000000..bc002938ed08 --- /dev/null +++ b/code/modules/genetics/plants/gene_diet.dm @@ -0,0 +1,29 @@ +/decl/plant_gene/diet + unmasked_name = "diet" + associated_traits = list( + TRAIT_CARNIVOROUS, + TRAIT_PARASITE, + TRAIT_NUTRIENT_CONSUMPTION, + TRAIT_WATER_CONSUMPTION + ) + +/decl/plant_gene/diet/mutate(datum/seed/seed, turf/location) + if(prob(60)) + seed.set_trait(TRAIT_CARNIVOROUS, seed.get_trait(TRAIT_CARNIVOROUS)+rand(-1,1),2,0) + if(prob(60)) + seed.set_trait(TRAIT_PARASITE, !seed.get_trait(TRAIT_PARASITE)) + if(prob(65)) + seed.set_trait(TRAIT_NUTRIENT_CONSUMPTION, seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION)+rand(-0.1,0.1),5,0) + if(prob(65)) + seed.set_trait(TRAIT_WATER_CONSUMPTION, seed.get_trait(TRAIT_WATER_CONSUMPTION)+rand(-1,1),50,0) + +/decl/plant_gene/diet/modify_seed(datum/plantgene/gene, datum/seed/seed) + var/list/new_gasses = LAZYACCESS(gene.values, TRAIT_CONSUME_GASSES) + if(islist(new_gasses) && length(new_gasses)) + LAZYDISTINCTADD(seed.consume_gasses, new_gasses) + gene.values -= TRAIT_CONSUME_GASSES + return ..() + +/decl/plant_gene/diet/copy_initial_seed_values(datum/plantgene/gene, datum/seed/seed) + LAZYSET(gene.values, TRAIT_CONSUME_GASSES, seed.consume_gasses?.Copy()) + return ..() diff --git a/code/modules/genetics/plants/gene_environment.dm b/code/modules/genetics/plants/gene_environment.dm new file mode 100644 index 000000000000..2ada19ba2c58 --- /dev/null +++ b/code/modules/genetics/plants/gene_environment.dm @@ -0,0 +1,15 @@ +/decl/plant_gene/environment + unmasked_name = "environment" + associated_traits = list( + TRAIT_IDEAL_HEAT, + TRAIT_IDEAL_LIGHT, + TRAIT_LIGHT_TOLERANCE + ) + +/decl/plant_gene/environment/mutate(datum/seed/seed, turf/location) + if(prob(60)) + seed.set_trait(TRAIT_IDEAL_HEAT, seed.get_trait(TRAIT_IDEAL_HEAT)+rand(-2,2),10,0) + if(prob(60)) + seed.set_trait(TRAIT_IDEAL_LIGHT, seed.get_trait(TRAIT_IDEAL_LIGHT)+rand(-2,2),10,0) + if(prob(60)) + seed.set_trait(TRAIT_LIGHT_TOLERANCE, seed.get_trait(TRAIT_LIGHT_TOLERANCE)+rand(-5,5),100,0) diff --git a/code/modules/genetics/plants/gene_fruit.dm b/code/modules/genetics/plants/gene_fruit.dm new file mode 100644 index 000000000000..6ea6f419f6cc --- /dev/null +++ b/code/modules/genetics/plants/gene_fruit.dm @@ -0,0 +1,16 @@ +/decl/plant_gene/fruit + unmasked_name = "fruit" + associated_traits = list( + TRAIT_STINGS, + TRAIT_EXPLOSIVE, + TRAIT_FLESH_COLOUR, + TRAIT_JUICY + ) + +/decl/plant_gene/fruit/mutate(datum/seed/seed, turf/location) + if(prob(65)) + seed.set_trait(TRAIT_STINGS, !seed.get_trait(TRAIT_STINGS)) + if(prob(65)) + seed.set_trait(TRAIT_EXPLOSIVE, !seed.get_trait(TRAIT_EXPLOSIVE)) + if(prob(65)) + seed.set_trait(TRAIT_JUICY, !seed.get_trait(TRAIT_JUICY)) diff --git a/code/modules/genetics/plants/gene_hardiness.dm b/code/modules/genetics/plants/gene_hardiness.dm new file mode 100644 index 000000000000..86002a560499 --- /dev/null +++ b/code/modules/genetics/plants/gene_hardiness.dm @@ -0,0 +1,18 @@ +/decl/plant_gene/hardiness + unmasked_name = "hardiness" + associated_traits = list( + TRAIT_TOXINS_TOLERANCE, + TRAIT_PEST_TOLERANCE, + TRAIT_WEED_TOLERANCE, + TRAIT_ENDURANCE + ) + +/decl/plant_gene/hardiness/mutate(datum/seed/seed, turf/location) + if(prob(60)) + seed.set_trait(TRAIT_TOXINS_TOLERANCE, seed.get_trait(TRAIT_TOXINS_TOLERANCE)+rand(-2,2),10,0) + if(prob(60)) + seed.set_trait(TRAIT_PEST_TOLERANCE, seed.get_trait(TRAIT_PEST_TOLERANCE)+rand(-2,2),10,0) + if(prob(60)) + seed.set_trait(TRAIT_WEED_TOLERANCE, seed.get_trait(TRAIT_WEED_TOLERANCE)+rand(-2,2),10,0) + if(prob(60)) + seed.set_trait(TRAIT_ENDURANCE, seed.get_trait(TRAIT_ENDURANCE)+rand(-5,5),100,0) diff --git a/code/modules/genetics/plants/gene_metabolism.dm b/code/modules/genetics/plants/gene_metabolism.dm new file mode 100644 index 000000000000..01dc3c5c8f45 --- /dev/null +++ b/code/modules/genetics/plants/gene_metabolism.dm @@ -0,0 +1,28 @@ +/decl/plant_gene/metabolism + unmasked_name = "metabolism" + associated_traits = list( + TRAIT_REQUIRES_NUTRIENTS, + TRAIT_REQUIRES_WATER, + TRAIT_ALTER_TEMP + ) + +/decl/plant_gene/metabolism/mutate(datum/seed/seed, turf/location) + if(prob(65)) + seed.set_trait(TRAIT_REQUIRES_NUTRIENTS, seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)+rand(-2,2),10,0) + if(prob(65)) + seed.set_trait(TRAIT_REQUIRES_WATER, seed.get_trait(TRAIT_REQUIRES_WATER)+rand(-2,2),10,0) + if(prob(40)) + seed.set_trait(TRAIT_ALTER_TEMP, seed.get_trait(TRAIT_ALTER_TEMP)+rand(-5,5),100,0) + +/decl/plant_gene/metabolism/modify_seed(datum/plantgene/gene, datum/seed/seed) + seed.product_type = LAZYACCESS(gene.values, TRAIT_PRODUCT_TYPE) + seed.slice_product = LAZYACCESS(gene.values, TRAIT_SLICE_PRODUCT) + seed.slice_amount = LAZYACCESS(gene.values, TRAIT_SLICE_AMOUNT) + LAZYREMOVE(gene.values, TRAIT_PRODUCT_TYPE) + return ..() + +/decl/plant_gene/metabolism/copy_initial_seed_values(datum/plantgene/gene, datum/seed/seed) + LAZYSET(gene.values, TRAIT_PRODUCT_TYPE, seed.product_type) + LAZYSET(gene.values, TRAIT_SLICE_PRODUCT, seed.slice_product) + LAZYSET(gene.values, TRAIT_SLICE_AMOUNT, seed.slice_amount) + return ..() diff --git a/code/modules/genetics/plants/gene_output.dm b/code/modules/genetics/plants/gene_output.dm new file mode 100644 index 000000000000..57c5b7f87e64 --- /dev/null +++ b/code/modules/genetics/plants/gene_output.dm @@ -0,0 +1,19 @@ +/decl/plant_gene/output + unmasked_name = "output" + associated_traits = list( + TRAIT_PRODUCES_POWER, + TRAIT_BIOLUM + ) + +/decl/plant_gene/output/mutate(datum/seed/seed, turf/location) + if(prob(50)) + seed.set_trait(TRAIT_BIOLUM, !seed.get_trait(TRAIT_BIOLUM)) + if(seed.get_trait(TRAIT_BIOLUM)) + location.visible_message(SPAN_NOTICE("\The [seed.display_name] begins to glow!")) + if(prob(50)) + seed.set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190)) + location.visible_message(SPAN_NOTICE("\The [seed.display_name]'s glow changes colour!")) + else + location.visible_message(SPAN_NOTICE("\The [seed.display_name]'s glow dims...")) + if(prob(60)) + seed.set_trait(TRAIT_PRODUCES_POWER, !seed.get_trait(TRAIT_PRODUCES_POWER)) diff --git a/code/modules/genetics/plants/gene_pigment.dm b/code/modules/genetics/plants/gene_pigment.dm new file mode 100644 index 000000000000..e7b87dea2f39 --- /dev/null +++ b/code/modules/genetics/plants/gene_pigment.dm @@ -0,0 +1,8 @@ +/decl/plant_gene/pigment + unmasked_name = "pigment" + associated_traits = list( + TRAIT_PLANT_COLOUR, + TRAIT_PRODUCT_COLOUR, + TRAIT_BIOLUM_COLOUR, + TRAIT_LEAVES_COLOUR + ) diff --git a/code/modules/genetics/plants/gene_special.dm b/code/modules/genetics/plants/gene_special.dm new file mode 100644 index 000000000000..2e864d759695 --- /dev/null +++ b/code/modules/genetics/plants/gene_special.dm @@ -0,0 +1,9 @@ +/decl/plant_gene/special + unmasked_name = "special" + associated_traits = list( + TRAIT_TELEPORTING + ) + +/decl/plant_gene/special/mutate(datum/seed/seed, atom/location) + if(prob(65)) + seed.set_trait(TRAIT_TELEPORTING, !seed.get_trait(TRAIT_TELEPORTING)) diff --git a/code/modules/genetics/plants/gene_structure.dm b/code/modules/genetics/plants/gene_structure.dm new file mode 100644 index 000000000000..228d09d57c09 --- /dev/null +++ b/code/modules/genetics/plants/gene_structure.dm @@ -0,0 +1,8 @@ +/decl/plant_gene/structure + unmasked_name = "structure" + associated_traits = list( + TRAIT_PLANT_ICON, + TRAIT_PRODUCT_ICON, + TRAIT_HARVEST_REPEAT, + TRAIT_LARGE + ) diff --git a/code/modules/genetics/plants/gene_vigour.dm b/code/modules/genetics/plants/gene_vigour.dm new file mode 100644 index 000000000000..335556230cd6 --- /dev/null +++ b/code/modules/genetics/plants/gene_vigour.dm @@ -0,0 +1,17 @@ +/decl/plant_gene/vigour + unmasked_name = "vigour" + associated_traits = list( + TRAIT_PRODUCTION, + TRAIT_MATURATION, + TRAIT_YIELD, + TRAIT_SPREAD + ) + +/decl/plant_gene/vigour/mutate(datum/seed/seed, atom/location) + if(prob(65)) + seed.set_trait(TRAIT_PRODUCTION, seed.get_trait(TRAIT_PRODUCTION)+rand(-1,1),10,0) + if(prob(65)) + seed.set_trait(TRAIT_MATURATION, seed.get_trait(TRAIT_MATURATION)+rand(-1,1),30,0) + if(prob(55)) + seed.set_trait(TRAIT_SPREAD, seed.get_trait(TRAIT_SPREAD)+rand(-1,1),2,0) + location.visible_message(SPAN_NOTICE("\The [seed.display_name] spasms visibly.")) diff --git a/code/modules/genetics/plants/trait_alter_temp.dm b/code/modules/genetics/plants/trait_alter_temp.dm new file mode 100644 index 000000000000..5fb53109efac --- /dev/null +++ b/code/modules/genetics/plants/trait_alter_temp.dm @@ -0,0 +1,8 @@ +/// If set, the plant will periodically alter local temp by this amount. +/decl/plant_trait/alter_temp + name = "temperature alteration" + shows_extended_data = TRUE + +/decl/plant_trait/alter_temp/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It will periodically alter the local temperature by [val] degrees Kelvin." diff --git a/code/modules/genetics/plants/trait_biolum.dm b/code/modules/genetics/plants/trait_biolum.dm new file mode 100644 index 000000000000..a4b8e623e183 --- /dev/null +++ b/code/modules/genetics/plants/trait_biolum.dm @@ -0,0 +1,8 @@ +/// Plant is bioluminescent. +/decl/plant_trait/biolum + name = "bioluminescence" + shows_extended_data = TRUE + +/decl/plant_trait/biolum/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It is [grown_seed?.get_trait(TRAIT_BIOLUM_COLOUR) ? "bioluminescent" : "bioluminescent"]." diff --git a/code/modules/genetics/plants/trait_biolum_colour.dm b/code/modules/genetics/plants/trait_biolum_colour.dm new file mode 100644 index 000000000000..270b8fcb81d3 --- /dev/null +++ b/code/modules/genetics/plants/trait_biolum_colour.dm @@ -0,0 +1,4 @@ +/// The colour of the plant's radiance. +/decl/plant_trait/biolum_colour + name = "bioluminescence colour" + default_value = null diff --git a/code/modules/genetics/plants/trait_carnivorous.dm b/code/modules/genetics/plants/trait_carnivorous.dm new file mode 100644 index 000000000000..69559b61321a --- /dev/null +++ b/code/modules/genetics/plants/trait_carnivorous.dm @@ -0,0 +1,12 @@ +/// 0 = none, 1 = eat pests in tray, 2 = eat living things (when a vine). +/decl/plant_trait/carnivorous + name = "carnivorous" + shows_extended_data = TRUE + base_worth = 5 + +/decl/plant_trait/carnivorous/get_extended_data(val, datum/seed/grown_seed) + switch(val) + if(1) + return "It is carnivorous and will eat tray pests for sustenance." + if(2) + return "It is carnivorous and poses a significant threat to living things around it." diff --git a/code/modules/genetics/plants/trait_chems.dm b/code/modules/genetics/plants/trait_chems.dm new file mode 100644 index 000000000000..187123c1464d --- /dev/null +++ b/code/modules/genetics/plants/trait_chems.dm @@ -0,0 +1,3 @@ +/decl/plant_trait/chems + name = "chemicals" + requires_master_gene = FALSE diff --git a/code/modules/genetics/plants/trait_consume_gasses.dm b/code/modules/genetics/plants/trait_consume_gasses.dm new file mode 100644 index 000000000000..3fc7e1e47e10 --- /dev/null +++ b/code/modules/genetics/plants/trait_consume_gasses.dm @@ -0,0 +1,8 @@ +/decl/plant_trait/consume_gasses + name = "gas consumption" + shows_extended_data = TRUE + requires_master_gene = FALSE + +/decl/plant_trait/consume_gasses/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It will remove gas from the environment." diff --git a/code/modules/genetics/plants/trait_endurance.dm b/code/modules/genetics/plants/trait_endurance.dm new file mode 100644 index 000000000000..b50280565a95 --- /dev/null +++ b/code/modules/genetics/plants/trait_endurance.dm @@ -0,0 +1,5 @@ +/// Maximum plant HP when growing. +/decl/plant_trait/endurance + name = "endurance" + shows_general_data = TRUE + default_value = 100 \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_explosive.dm b/code/modules/genetics/plants/trait_explosive.dm new file mode 100644 index 000000000000..103d47d254ed --- /dev/null +++ b/code/modules/genetics/plants/trait_explosive.dm @@ -0,0 +1,9 @@ +/// When thrown, acts as a grenade. +/decl/plant_trait/explosive + name = "explosiveness" + shows_extended_data = TRUE + base_worth = -2 + +/decl/plant_trait/explosive/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "The fruit is internally unstable." diff --git a/code/modules/genetics/plants/trait_exude_gasses.dm b/code/modules/genetics/plants/trait_exude_gasses.dm new file mode 100644 index 000000000000..1e88e3f1274a --- /dev/null +++ b/code/modules/genetics/plants/trait_exude_gasses.dm @@ -0,0 +1,10 @@ +/decl/plant_trait/exude_gasses + name = "gas exuding" + shows_extended_data = TRUE + requires_master_gene = FALSE + +/decl/plant_trait/exude_gasses/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It will release gas into the environment." + + diff --git a/code/modules/genetics/plants/trait_flesh_colour.dm b/code/modules/genetics/plants/trait_flesh_colour.dm new file mode 100644 index 000000000000..ab87e3d7e1ae --- /dev/null +++ b/code/modules/genetics/plants/trait_flesh_colour.dm @@ -0,0 +1,2 @@ +/decl/plant_trait/flesh_colour + name = "flesh colour" \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_harvest_repeat.dm b/code/modules/genetics/plants/trait_harvest_repeat.dm new file mode 100644 index 000000000000..38f196e42c73 --- /dev/null +++ b/code/modules/genetics/plants/trait_harvest_repeat.dm @@ -0,0 +1,9 @@ +/// If 1, this plant will fruit repeatedly. +/decl/plant_trait/harvest_repeat + name = "repeat harvestability" + shows_extended_data = TRUE + base_worth = 3 + +/decl/plant_trait/harvest_repeat/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "This plant can be harvested repeatedly." diff --git a/code/modules/genetics/plants/trait_heat_tolerance.dm b/code/modules/genetics/plants/trait_heat_tolerance.dm new file mode 100644 index 000000000000..e2366d8a2a92 --- /dev/null +++ b/code/modules/genetics/plants/trait_heat_tolerance.dm @@ -0,0 +1,14 @@ +/// Departure from ideal that is survivable. +/decl/plant_trait/heat_tolerance + name = "heat tolerance" + shows_extended_data = TRUE + default_value = 20 + +/decl/plant_trait/heat_tolerance/get_station_survivable_value() + return 20 + +/decl/plant_trait/heat_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val > 30) + return "It is well adapted to a range of temperatures." + if(val < 10) + return "It is very sensitive to temperature shifts." diff --git a/code/modules/genetics/plants/trait_highkpa_tolerance.dm b/code/modules/genetics/plants/trait_highkpa_tolerance.dm new file mode 100644 index 000000000000..840f64bb365a --- /dev/null +++ b/code/modules/genetics/plants/trait_highkpa_tolerance.dm @@ -0,0 +1,12 @@ +/// High pressure capacity. +/decl/plant_trait/highkpa_tolerance + name = "high pressure tolerance" + shows_extended_data = TRUE + default_value = 200 + +/decl/plant_trait/highkpa_tolerance/get_station_survivable_value() + return 200 + +/decl/plant_trait/highkpa_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val > 220) + return "It is well adapted to high pressure levels." diff --git a/code/modules/genetics/plants/trait_ideal_heat.dm b/code/modules/genetics/plants/trait_ideal_heat.dm new file mode 100644 index 000000000000..42e107248038 --- /dev/null +++ b/code/modules/genetics/plants/trait_ideal_heat.dm @@ -0,0 +1,12 @@ +/// Preferred temperature in Kelvin. +/decl/plant_trait/ideal_heat + name = "ideal heat" + shows_extended_data = TRUE + default_value = 293 + +/decl/plant_trait/ideal_heat/get_station_survivable_value() + return 293 + +/decl/plant_trait/ideal_heat/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It thrives in a temperature of [val] Kelvin." diff --git a/code/modules/genetics/plants/trait_ideal_light.dm b/code/modules/genetics/plants/trait_ideal_light.dm new file mode 100644 index 000000000000..a5ce1ccb19c9 --- /dev/null +++ b/code/modules/genetics/plants/trait_ideal_light.dm @@ -0,0 +1,12 @@ +/// Preferred light level in luminosity. +/decl/plant_trait/ideal_light + name = "ideal light" + shows_extended_data = TRUE + default_value = 5 + +/decl/plant_trait/ideal_light/get_station_survivable_value() + return 4 + +/decl/plant_trait/ideal_light/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It thrives in a light level of [val] lumen\s." diff --git a/code/modules/genetics/plants/trait_immutable.dm b/code/modules/genetics/plants/trait_immutable.dm new file mode 100644 index 000000000000..3d57079ec457 --- /dev/null +++ b/code/modules/genetics/plants/trait_immutable.dm @@ -0,0 +1,11 @@ +/// If set, plant will never mutate. If -1, plant is highly mutable. +/decl/plant_trait/immutable + name = "genetic immutability" + shows_extended_data = TRUE + requires_master_gene = FALSE + +/decl/plant_trait/immutable/get_extended_data(val, datum/seed/grown_seed) + if(val == -1) + return "This plant is highly mutable." + if(val > 0) + return "This plant does not possess genetics that are alterable." diff --git a/code/modules/genetics/plants/trait_juicy.dm b/code/modules/genetics/plants/trait_juicy.dm new file mode 100644 index 000000000000..96e1a127ce9b --- /dev/null +++ b/code/modules/genetics/plants/trait_juicy.dm @@ -0,0 +1,11 @@ +/// When thrown, causes a splatter decal. +/decl/plant_trait/juicy + name = "juiciness" + shows_extended_data = TRUE + +/decl/plant_trait/juicy/get_extended_data(val, datum/seed/grown_seed) + switch(val) + if(1) + return "The fruit is soft-skinned and juicy." + if(2) + return "The fruit is excessively juicy." diff --git a/code/modules/genetics/plants/trait_large.dm b/code/modules/genetics/plants/trait_large.dm new file mode 100644 index 000000000000..302797850739 --- /dev/null +++ b/code/modules/genetics/plants/trait_large.dm @@ -0,0 +1,2 @@ +/decl/plant_trait/large + name = "largeness" \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_leaves_colour.dm b/code/modules/genetics/plants/trait_leaves_colour.dm new file mode 100644 index 000000000000..11dda0364f59 --- /dev/null +++ b/code/modules/genetics/plants/trait_leaves_colour.dm @@ -0,0 +1,2 @@ +/decl/plant_trait/leaves_colour + name = "leaf colour" diff --git a/code/modules/genetics/plants/trait_light_tolerance.dm b/code/modules/genetics/plants/trait_light_tolerance.dm new file mode 100644 index 000000000000..89060959a529 --- /dev/null +++ b/code/modules/genetics/plants/trait_light_tolerance.dm @@ -0,0 +1,14 @@ +/// Departure from ideal that is survivable. +/decl/plant_trait/light_tolerance + name = "light tolerance" + shows_extended_data = TRUE + default_value = 3 + +/decl/plant_trait/light_tolerance/get_station_survivable_value() + return 5 + +/decl/plant_trait/light_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val > 10) + return "It is well adapted to a range of light levels." + if(val < 3) + return "It is very sensitive to light level shifts." diff --git a/code/modules/genetics/plants/trait_lowkpa_tolerance.dm b/code/modules/genetics/plants/trait_lowkpa_tolerance.dm new file mode 100644 index 000000000000..2250a1f71f4c --- /dev/null +++ b/code/modules/genetics/plants/trait_lowkpa_tolerance.dm @@ -0,0 +1,12 @@ +/// Low pressure capacity. +/decl/plant_trait/lowkpa_tolerance + name = "low pressure tolerance" + shows_extended_data = TRUE + default_value = 25 + +/decl/plant_trait/lowkpa_tolerance/get_station_survivable_value() + return 25 + +/decl/plant_trait/lowkpa_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val < 20) + return "It is well adapted to low pressure levels." diff --git a/code/modules/genetics/plants/trait_maturation.dm b/code/modules/genetics/plants/trait_maturation.dm new file mode 100644 index 000000000000..9395de1bc68d --- /dev/null +++ b/code/modules/genetics/plants/trait_maturation.dm @@ -0,0 +1,4 @@ +/// Time taken before the plant is mature. +/decl/plant_trait/maturation + name = "maturation time" + shows_general_data = TRUE diff --git a/code/modules/genetics/plants/trait_nutrient_consumption.dm b/code/modules/genetics/plants/trait_nutrient_consumption.dm new file mode 100644 index 000000000000..8630c68338cc --- /dev/null +++ b/code/modules/genetics/plants/trait_nutrient_consumption.dm @@ -0,0 +1,4 @@ +/// Plant eats this much per tick. +/decl/plant_trait/nutrient_consumption + name = "nutrient consumption" + default_value = 0.25 \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_parasite.dm b/code/modules/genetics/plants/trait_parasite.dm new file mode 100644 index 000000000000..e39c076368ef --- /dev/null +++ b/code/modules/genetics/plants/trait_parasite.dm @@ -0,0 +1,9 @@ + /// 0 = no, 1 = gain health from weed level. +/decl/plant_trait/parasite + name = "parasitism" + shows_extended_data = TRUE + base_worth = 5 + +/decl/plant_trait/parasite/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "It is capable of parisitising and gaining sustenance from tray weeds." \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_pest_tolerance.dm b/code/modules/genetics/plants/trait_pest_tolerance.dm new file mode 100644 index 000000000000..310659b29e2d --- /dev/null +++ b/code/modules/genetics/plants/trait_pest_tolerance.dm @@ -0,0 +1,11 @@ +/// Threshold for pests to impact health. +/decl/plant_trait/pest_tolerance + name = "pest tolerance" + shows_extended_data = TRUE + default_value = 5 + +/decl/plant_trait/pest_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val < 3) + return "It is highly sensitive to pests." + if(val > 6) + return "It is remarkably resistant to pests." \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_photosynthesis.dm b/code/modules/genetics/plants/trait_photosynthesis.dm new file mode 100644 index 000000000000..eb84c05668fd --- /dev/null +++ b/code/modules/genetics/plants/trait_photosynthesis.dm @@ -0,0 +1,5 @@ +/// If it turns CO2 into oxygen +/decl/plant_trait/photosynthesis + name = "photosynthesis" + default_value = 1 + requires_master_gene = FALSE diff --git a/code/modules/genetics/plants/trait_plant_colour.dm b/code/modules/genetics/plants/trait_plant_colour.dm new file mode 100644 index 000000000000..3c7430f37c2f --- /dev/null +++ b/code/modules/genetics/plants/trait_plant_colour.dm @@ -0,0 +1,4 @@ +/// Colour of the plant icon. +/decl/plant_trait/plant_colour + name = "plant colour" + default_value = "#46b543" \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_plant_icon.dm b/code/modules/genetics/plants/trait_plant_icon.dm new file mode 100644 index 000000000000..8d3cff7bcb5b --- /dev/null +++ b/code/modules/genetics/plants/trait_plant_icon.dm @@ -0,0 +1,7 @@ +/// Icon to use for the plant growing in the tray. +/decl/plant_trait/plant_icon + name = "plant icon" + default_value = null + +/decl/plant_trait/plant_icon/handle_post_trait_set(datum/seed/seed) + seed.update_growth_stages() \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_pollen.dm b/code/modules/genetics/plants/trait_pollen.dm new file mode 100644 index 000000000000..7dbbcbbd0df4 --- /dev/null +++ b/code/modules/genetics/plants/trait_pollen.dm @@ -0,0 +1,3 @@ +/decl/plant_trait/pollen + name = "pollen" + requires_master_gene = FALSE diff --git a/code/modules/genetics/plants/trait_potency.dm b/code/modules/genetics/plants/trait_potency.dm new file mode 100644 index 000000000000..86b6d2949b1f --- /dev/null +++ b/code/modules/genetics/plants/trait_potency.dm @@ -0,0 +1,5 @@ +/// General purpose plant strength value. +/decl/plant_trait/potency + name = "potency" + shows_general_data = TRUE + default_value = 1 diff --git a/code/modules/genetics/plants/trait_produces_power.dm b/code/modules/genetics/plants/trait_produces_power.dm new file mode 100644 index 000000000000..dcad4dd6e33b --- /dev/null +++ b/code/modules/genetics/plants/trait_produces_power.dm @@ -0,0 +1,9 @@ +/// Can be used to make a battery. +/decl/plant_trait/produces_power + name = "power production" // TODO look up the chemical reaction that causes this + shows_extended_data = TRUE + base_worth = 3 + +/decl/plant_trait/produces_power/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "The fruit will function as a battery if prepared appropriately." diff --git a/code/modules/genetics/plants/trait_product_colour.dm b/code/modules/genetics/plants/trait_product_colour.dm new file mode 100644 index 000000000000..858eb67f3f9e --- /dev/null +++ b/code/modules/genetics/plants/trait_product_colour.dm @@ -0,0 +1,4 @@ +/// Colour to apply to product icon. +/decl/plant_trait/product_colour + name = "product colour" + default_value = COLOR_WHITE \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_product_icon.dm b/code/modules/genetics/plants/trait_product_icon.dm new file mode 100644 index 000000000000..5994ccf9b0e8 --- /dev/null +++ b/code/modules/genetics/plants/trait_product_icon.dm @@ -0,0 +1,4 @@ +/// Icon to use for fruit coming from this plant. +/decl/plant_trait/product_icon + name = "product_icon" + default_value = null diff --git a/code/modules/genetics/plants/trait_product_type.dm b/code/modules/genetics/plants/trait_product_type.dm new file mode 100644 index 000000000000..e21c49905861 --- /dev/null +++ b/code/modules/genetics/plants/trait_product_type.dm @@ -0,0 +1,4 @@ +/decl/plant_trait/product_type + name = "product type" + default_value = null + requires_master_gene = FALSE diff --git a/code/modules/genetics/plants/trait_production.dm b/code/modules/genetics/plants/trait_production.dm new file mode 100644 index 000000000000..851f4f099e44 --- /dev/null +++ b/code/modules/genetics/plants/trait_production.dm @@ -0,0 +1,4 @@ +/// Time before harvesting can be undertaken again. +/decl/plant_trait/production + name = "production time" + shows_general_data = TRUE diff --git a/code/modules/genetics/plants/trait_requires_nutrients.dm b/code/modules/genetics/plants/trait_requires_nutrients.dm new file mode 100644 index 000000000000..d2a593520003 --- /dev/null +++ b/code/modules/genetics/plants/trait_requires_nutrients.dm @@ -0,0 +1,13 @@ +/// The plant can starve. +/decl/plant_trait/requires_nutrients + name = "required nutrients" + shows_extended_data = TRUE + default_value = 1 + +/decl/plant_trait/requires_nutrients/get_extended_data(val, datum/seed/grown_seed) + if(val) + if(val < 0.05) + return "It consumes a small amount of nutrient fluid." + if(val > 0.2) + return "It requires a heavy supply of nutrient fluid." + return "It requires a supply of nutrient fluid." diff --git a/code/modules/genetics/plants/trait_requires_water.dm b/code/modules/genetics/plants/trait_requires_water.dm new file mode 100644 index 000000000000..53b316c97c7e --- /dev/null +++ b/code/modules/genetics/plants/trait_requires_water.dm @@ -0,0 +1,13 @@ +/// The plant can become dehydrated. +/decl/plant_trait/requires_water + name = "required water" + shows_extended_data = TRUE + default_value = 1 + +/decl/plant_trait/requires_water/get_extended_data(val, datum/seed/grown_seed) + if(val) + if(val < 1) + return "It requires very little water." + if(val > 5) + return "It requires a large amount of water." + return "It requires a steady supply of water." diff --git a/code/modules/genetics/plants/trait_slice_amount.dm b/code/modules/genetics/plants/trait_slice_amount.dm new file mode 100644 index 000000000000..d2d5ad2acac1 --- /dev/null +++ b/code/modules/genetics/plants/trait_slice_amount.dm @@ -0,0 +1,4 @@ +/decl/plant_trait/slice_amount + name = "slice amount" + default_value = null + requires_master_gene = FALSE diff --git a/code/modules/genetics/plants/trait_slice_product.dm b/code/modules/genetics/plants/trait_slice_product.dm new file mode 100644 index 000000000000..434ba795bd7f --- /dev/null +++ b/code/modules/genetics/plants/trait_slice_product.dm @@ -0,0 +1,4 @@ +/decl/plant_trait/slice_product + name = "slice type" + default_value = null + requires_master_gene = FALSE diff --git a/code/modules/genetics/plants/trait_spread.dm b/code/modules/genetics/plants/trait_spread.dm new file mode 100644 index 000000000000..6cd873fcbcdc --- /dev/null +++ b/code/modules/genetics/plants/trait_spread.dm @@ -0,0 +1,11 @@ +/// 0 limits plant to tray, 1 = creepers, 2 = vines. +/decl/plant_trait/spread + name = "spread" + shows_extended_data = TRUE + +/decl/plant_trait/spread/get_extended_data(val, datum/seed/grown_seed) + switch(val) + if(1) + return "It is able to be planted outside of a tray." + if(2) + return "It is a robust and vigorous vine that will spread rapidly." diff --git a/code/modules/genetics/plants/trait_stings.dm b/code/modules/genetics/plants/trait_stings.dm new file mode 100644 index 000000000000..9b62e88d7599 --- /dev/null +++ b/code/modules/genetics/plants/trait_stings.dm @@ -0,0 +1,9 @@ +/// Can cause damage/inject reagents when thrown or handled. +/decl/plant_trait/stings + name = "stinging" + shows_extended_data = TRUE + base_worth = -2 + +/decl/plant_trait/stings/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "The fruit is covered in stinging spines." diff --git a/code/modules/genetics/plants/trait_teleporting.dm b/code/modules/genetics/plants/trait_teleporting.dm new file mode 100644 index 000000000000..077293a45aaf --- /dev/null +++ b/code/modules/genetics/plants/trait_teleporting.dm @@ -0,0 +1,9 @@ +/// Uses the teleport tomato effect. +/decl/plant_trait/teleporting + name = "teleporting" + shows_extended_data = TRUE + base_worth = 5 + +/decl/plant_trait/teleporting/get_extended_data(val, datum/seed/grown_seed) + if(val) + return "The fruit is temporal/spatially unstable." diff --git a/code/modules/genetics/plants/trait_toxins_tolerance.dm b/code/modules/genetics/plants/trait_toxins_tolerance.dm new file mode 100644 index 000000000000..59b84d03820b --- /dev/null +++ b/code/modules/genetics/plants/trait_toxins_tolerance.dm @@ -0,0 +1,11 @@ +/// Resistance to poison. +/decl/plant_trait/toxins_tolerance + name = "toxins tolerance" + shows_extended_data = TRUE + default_value = 5 + +/decl/plant_trait/toxins_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val < 3) + return "It is highly sensitive to toxins." + if(val > 6) + return "It is remarkably resistant to toxins." \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_water_consumption.dm b/code/modules/genetics/plants/trait_water_consumption.dm new file mode 100644 index 000000000000..03cdcb95dc09 --- /dev/null +++ b/code/modules/genetics/plants/trait_water_consumption.dm @@ -0,0 +1,4 @@ +/// Plant drinks this much per tick. +/decl/plant_trait/water_consumption + name = "water consumption" + default_value = 3 diff --git a/code/modules/genetics/plants/trait_weed_tolerance.dm b/code/modules/genetics/plants/trait_weed_tolerance.dm new file mode 100644 index 000000000000..051cf58b984d --- /dev/null +++ b/code/modules/genetics/plants/trait_weed_tolerance.dm @@ -0,0 +1,11 @@ +/// Threshold for weeds to impact health. +/decl/plant_trait/weed_tolerance + name = "weed tolerance" + shows_extended_data = TRUE + default_value = 5 + +/decl/plant_trait/weed_tolerance/get_extended_data(val, datum/seed/grown_seed) + if(val < 3) + return "It is highly sensitive to weeds." + if(val > 6) + return "It is remarkably resistant to weeds." \ No newline at end of file diff --git a/code/modules/genetics/plants/trait_yield.dm b/code/modules/genetics/plants/trait_yield.dm new file mode 100644 index 000000000000..dcaf60b656dd --- /dev/null +++ b/code/modules/genetics/plants/trait_yield.dm @@ -0,0 +1,4 @@ +/// Amount of product. +/decl/plant_trait/yield + name = "yield" + shows_general_data = TRUE diff --git a/code/modules/genetics/side_effects.dm b/code/modules/genetics/side_effects.dm deleted file mode 100644 index a95f99af52f3..000000000000 --- a/code/modules/genetics/side_effects.dm +++ /dev/null @@ -1,76 +0,0 @@ -/datum/genetics/side_effect - var/name // name of the side effect, to use as a header in the manual - var/symptom // description of the symptom of the side effect - var/treatment // description of the treatment of the side effect - var/effect // description of what happens when not treated - var/duration = 0 // delay between start() and finish() - -/datum/genetics/side_effect/proc/start(mob/living/carbon/human/H) - // start the side effect, this should give some cue as to what's happening, - // such as gasping. These cues need to be unique among side-effects. - -/datum/genetics/side_effect/proc/finish(mob/living/carbon/human/H) - // Finish the side-effect. This should first check whether the cure has been - // applied, and if not, cause bad things to happen. - -/datum/genetics/side_effect/proc/trigger_side_effect(mob/living/carbon/human/H) - if(ishuman(H)) - addtimer(CALLBACK(src, .proc/do_side_effect, H), 0) - -/datum/genetics/side_effect/proc/do_side_effect(mob/living/carbon/human/H) - var/tp = pick(typesof(/datum/genetics/side_effect) - /datum/genetics/side_effect) - var/datum/genetics/side_effect/S = new tp - - S.start(H) - addtimer(CALLBACK(H, /mob/proc/Weaken, rand(0, S.duration / 50)), 20) - sleep(S.duration) - H.SetWeakened(0) - S.finish(H) - - -/datum/genetics/side_effect/genetic_burn - name = "Genetic Burn" - symptom = "Subject's skin turns unusualy red." - treatment = "Inject small dose of oxygen." - effect = "Subject's skin burns." - duration = 30 SECONDS - -/datum/genetics/side_effect/genetic_burn/start(mob/living/carbon/human/H) - H.visible_message("\The [H] starts turning very red...") - -/datum/genetics/side_effect/genetic_burn/finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent(/decl/material/liquid/oxy_meds)) - for(var/organ_name in BP_ALL_LIMBS) - var/obj/item/organ/external/E = H.get_organ(organ_name) - E.take_external_damage(0, 5, 0) - -/datum/genetics/side_effect/bone_snap - name = "Bone Snap" - symptom = "Subject's limbs tremble notably." - treatment = "Inject small dose of styptic medication." - effect = "Subject's bone breaks." - duration = 1 MINUTE - -/datum/genetics/side_effect/bone_snap/start(mob/living/carbon/human/H) - H.visible_message("\The [H]'s limbs start shivering uncontrollably.") -/datum/genetics/side_effect/bone_snap/finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent(/decl/material/liquid/brute_meds)) - var/organ_name = pick(BP_ALL_LIMBS) - var/obj/item/organ/external/E = H.get_organ(organ_name) - E.take_external_damage(20, 0, 0) - E.fracture() - -/datum/genetics/side_effect/confuse - name = "Confuse" - symptom = "Subject starts drooling uncontrollably." - treatment = "Inject small dose of antitoxins." - effect = "Subject becomes confused." - duration = 30 SECONDS - - start(mob/living/carbon/human/H) - H.visible_message("\The [H] drools.") - - finish(mob/living/carbon/human/H) - if(!H.reagents.has_reagent(/decl/material/liquid/antitoxins)) - H.confused += 100 - diff --git a/code/modules/geology/_strata.dm b/code/modules/geology/_strata.dm new file mode 100644 index 000000000000..24acb2d824d6 --- /dev/null +++ b/code/modules/geology/_strata.dm @@ -0,0 +1,38 @@ +/decl/strata + var/name + var/list/base_materials + var/list/ores_sparse + var/list/ores_rich + var/default_strata_candidate = FALSE + var/maximum_temperature = INFINITY + +/decl/strata/proc/is_valid_exoplanet_strata(var/datum/planetoid_data/planet) + if(istype(planet.atmosphere)) + return planet.atmosphere.temperature <= maximum_temperature + return TCMB <= maximum_temperature + +/decl/strata/proc/is_valid_level_stratum(datum/level_data/level_data) + var/temperature_to_check = istype(level_data.exterior_atmosphere) ? level_data.exterior_atmosphere.temperature : level_data.exterior_atmos_temp + return (temperature_to_check || TCMB) <= maximum_temperature + +/decl/strata/Initialize() + . = ..() + + for(var/mat_type in ores_sparse) + if(isnull(ores_sparse[mat_type])) + var/decl/material/mat = GET_DECL(mat_type) + ores_sparse[mat_type] = mat.sparse_material_weight + + for(var/mat_type in ores_rich) + if(isnull(ores_rich[mat_type])) + var/decl/material/mat = GET_DECL(mat_type) + ores_rich[mat_type] = mat.rich_material_weight + + if(isnull(ores_sparse) && islist(ores_rich)) + ores_sparse = ores_rich.Copy() + else if(isnull(ores_rich) && islist(ores_sparse)) + ores_rich = ores_sparse.Copy() + + for(var/mat_type in (base_materials|ores_sparse|ores_rich)) + var/decl/material/mat = GET_DECL(mat_type) + maximum_temperature = min((mat.melting_point-1), maximum_temperature) diff --git a/code/modules/geology/strata_igneous.dm b/code/modules/geology/strata_igneous.dm new file mode 100644 index 000000000000..7c6a77e9e0ed --- /dev/null +++ b/code/modules/geology/strata_igneous.dm @@ -0,0 +1,24 @@ +/decl/strata/igneous + name = "igneous rock" + base_materials = list(/decl/material/solid/stone/basalt) + default_strata_candidate = TRUE + ores_rich = list( + /decl/material/solid/gemstone/diamond, + /decl/material/solid/quartz, + /decl/material/solid/graphite, + /decl/material/solid/densegraphite, + /decl/material/solid/metal/gold, + /decl/material/solid/quartz, + /decl/material/solid/metal/platinum, + /decl/material/solid/spodumene, + /decl/material/solid/phosphorite, + /decl/material/solid/hematite, + /decl/material/solid/rutile, + /decl/material/solid/tetrahedrite, + /decl/material/solid/magnetite, + /decl/material/solid/chalcopyrite, + /decl/material/solid/cassiterite, + /decl/material/solid/wolframite, + /decl/material/solid/sphalerite, + /decl/material/solid/galena + ) diff --git a/code/modules/geology/strata_metamorphic.dm b/code/modules/geology/strata_metamorphic.dm new file mode 100644 index 000000000000..a1eeced227a0 --- /dev/null +++ b/code/modules/geology/strata_metamorphic.dm @@ -0,0 +1,16 @@ +/decl/strata/metamorphic + name = "metamorphic rock" + base_materials = list(/decl/material/solid/stone/marble) + default_strata_candidate = TRUE + ores_rich = list( + /decl/material/solid/quartz, + /decl/material/solid/graphite, + /decl/material/solid/hematite, + /decl/material/solid/rutile, + /decl/material/solid/magnetite, + /decl/material/solid/chalcopyrite, + /decl/material/solid/sphalerite, + /decl/material/solid/galena, + /decl/material/solid/calaverite + ) + diff --git a/code/modules/geology/strata_permafrost.dm b/code/modules/geology/strata_permafrost.dm new file mode 100644 index 000000000000..ee157faa20d8 --- /dev/null +++ b/code/modules/geology/strata_permafrost.dm @@ -0,0 +1,21 @@ +/decl/strata/permafrost + name = "permafrost" + base_materials = list(/decl/material/solid/ice) + // todo swap hydrogen ice to hydrate + ores_rich = list( + /decl/material/solid/ice/aspium, + /decl/material/solid/ice/lukrite, + /decl/material/solid/ice/rubenium, + /decl/material/solid/ice/trigarite, + /decl/material/solid/ice/ediroite, + /decl/material/solid/ice/hydrogen, + /decl/material/solid/ice/hydrate/methane, + /decl/material/solid/ice/hydrate/oxygen, + /decl/material/solid/ice/hydrate/nitrogen, + /decl/material/solid/ice/hydrate/carbon_dioxide, + /decl/material/solid/ice/hydrate/argon, + /decl/material/solid/ice/hydrate/neon, + /decl/material/solid/ice/hydrate/krypton, + /decl/material/solid/ice/hydrate/xenon, + ) + maximum_temperature = T0C diff --git a/code/modules/geology/strata_sedimentary.dm b/code/modules/geology/strata_sedimentary.dm new file mode 100644 index 000000000000..27f229ce298c --- /dev/null +++ b/code/modules/geology/strata_sedimentary.dm @@ -0,0 +1,18 @@ +/decl/strata/sedimentary + name = "sedimentary rock" + base_materials = list(/decl/material/solid/stone/sandstone) + default_strata_candidate = TRUE + ores_rich = list( + /decl/material/solid/pitchblende, + /decl/material/solid/pyrite, + /decl/material/solid/sperrylite, + /decl/material/solid/cinnabar, + /decl/material/solid/sodiumchloride, + /decl/material/solid/potash, + /decl/material/solid/bauxite, + /decl/material/solid/hematite, + /decl/material/solid/magnetite, + /decl/material/solid/chalcopyrite, + /decl/material/solid/sphalerite, + /decl/material/solid/calaverite + ) diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm index 9833c67c34d4..1f450a9aadff 100644 --- a/code/modules/ghosttrap/trap.dm +++ b/code/modules/ghosttrap/trap.dm @@ -1,74 +1,54 @@ -// This system is used to grab a ghost from observers with the required preferences -// and lack of bans set. See posibrain.dm for an example of how they are called/used. - -var/list/ghost_traps - -/proc/get_ghost_trap(var/trap_key) - if(!ghost_traps) - populate_ghost_traps() - return ghost_traps[trap_key] - -/proc/get_ghost_traps() - if(!ghost_traps) - populate_ghost_traps() - return ghost_traps - -/proc/populate_ghost_traps() - ghost_traps = list() - for(var/traptype in typesof(/datum/ghosttrap)) - var/datum/ghosttrap/G = new traptype - ghost_traps[G.object] = G - -/datum/ghosttrap - var/object = "positronic brain" +// This system is used to grab a ghost from observers with the required preferences and lack of bans set. +/decl/ghosttrap + var/name var/minutes_since_death = 0 // If non-zero the ghost must have been dead for this many minutes to be allowed to spawn - var/list/ban_checks = list("AI","Robot") - var/pref_check = BE_SYNTH - var/ghost_trap_message = "They are occupying a positronic brain now." - var/ghost_trap_role = "Positronic Brain" + var/list/ban_checks + var/pref_check + var/ghost_trap_message var/can_set_own_name = TRUE var/list_as_special_role = TRUE // If true, this entry will be listed as a special role in the character setup - var/list/request_timeouts -/datum/ghosttrap/New() - request_timeouts = list() - ..() +/decl/ghosttrap/proc/forced(var/mob/user) + return // Check for bans, proper atom types, etc. -/datum/ghosttrap/proc/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target, var/feedback = TRUE) - if(!candidate.MayRespawn(feedback, minutes_since_death)) - return 0 - if(islist(ban_checks)) +/decl/ghosttrap/proc/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target, var/feedback = TRUE) + . = TRUE + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(candidate)) + . = FALSE + else if(!candidate.MayRespawn(feedback, minutes_since_death)) + . = FALSE + else if(islist(ban_checks)) for(var/bantype in ban_checks) if(jobban_isbanned(candidate, "[bantype]")) if(feedback) - to_chat(candidate, "You are banned from one or more required roles and hence cannot enter play as \a [object].") - return 0 - return 1 + to_chat(candidate, "You are banned from one or more required roles and hence cannot enter play as \a [name].") + . = FALSE + break // Print a message to all ghosts with the right prefs/lack of bans. -/datum/ghosttrap/proc/request_player(var/mob/target, var/request_string, var/request_timeout) +/decl/ghosttrap/proc/request_player(var/mob/target, var/request_string, var/request_timeout) if(request_timeout) - request_timeouts[target] = world.time + request_timeout - GLOB.destroyed_event.register(target, src, /datum/ghosttrap/proc/unregister_target) + LAZYSET(request_timeouts, target, world.time + request_timeout) + events_repository.register(/decl/observ/destroyed, target, src, TYPE_PROC_REF(/decl/ghosttrap, unregister_target)) else unregister_target(target) - for(var/mob/observer/ghost/O in GLOB.player_list) + for(var/mob/O in global.player_list) if(!assess_candidate(O, target, FALSE)) return if(pref_check && !O.client.wishes_to_be_role(pref_check)) continue if(O.client) - to_chat(O, "[request_string] (Occupy) ([ghost_follow_link(target, O)])") + to_chat(O, "[request_string] (Occupy) ([ghost_follow_link(target, O)])") -/datum/ghosttrap/proc/unregister_target(var/target) - request_timeouts -= target - GLOB.destroyed_event.unregister(target, src, /datum/ghosttrap/proc/unregister_target) +/decl/ghosttrap/proc/unregister_target(var/target) + LAZYREMOVE(request_timeouts, target) + events_repository.unregister(/decl/observ/destroyed, target, src, TYPE_PROC_REF(/decl/ghosttrap, unregister_target)) // Handles a response to request_player(). -/datum/ghosttrap/Topic(href, href_list) +/decl/ghosttrap/Topic(href, href_list) if(..()) return 1 if(href_list["candidate"] && href_list["target"]) @@ -78,7 +58,9 @@ var/list/ghost_traps return if(candidate != usr) return - if(request_timeouts[target] && world.time > request_timeouts[target]) + + var/timeout = LAZYACCESS(request_timeouts, target) + if(!isnull(timeout) && world.time > timeout) to_chat(candidate, "This occupation request is no longer valid.") return if(target.key) @@ -89,128 +71,117 @@ var/list/ghost_traps return 1 // Shunts the ckey/mind into the target mob. -/datum/ghosttrap/proc/transfer_personality(var/mob/candidate, var/mob/target) - if(!assess_candidate(candidate, target)) - return 0 - target.ckey = candidate.ckey - if(target.mind) - target.mind.reset() - target.mind.assigned_role = "[ghost_trap_role]" - announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]") - welcome_candidate(target) - set_new_name(target) - return 1 - -// Fluff! -/datum/ghosttrap/proc/welcome_candidate(var/mob/target) - to_chat(target, "You are a positronic brain, brought into existence on [station_name()].") - to_chat(target, "As a synthetic intelligence, you answer to all crewmembers, as well as the AI.") - to_chat(target, "Remember, the purpose of your existence is to serve the crew and the [station_name()]. Above all else, do no harm.") - to_chat(target, "Use say [target.get_language_prefix()]b to speak to other artificial intelligences.") - var/turf/T = get_turf(target) - var/obj/item/organ/internal/posibrain/P = target.loc - T.visible_message("\The [P] chimes quietly.") - if(!istype(P)) //wat - return - P.searching = 0 - P.SetName("positronic brain ([P.brainmob.name])") - P.update_icon() - -// Allows people to set their own name. May or may not need to be removed for posibrains if people are dumbasses. -/datum/ghosttrap/proc/set_new_name(var/mob/target) +/decl/ghosttrap/proc/transfer_personality(var/mob/candidate, var/mob/target) + if(assess_candidate(candidate, target)) + target.ckey = candidate.ckey + if(target.mind) + target.mind.reset() + target.mind.assigned_role = "[capitalize(name)]" + announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]") + if(target) + welcome_candidate(target) + set_new_name(target) + . = TRUE + +/decl/ghosttrap/proc/welcome_candidate(var/mob/target) + return + +/decl/ghosttrap/proc/set_new_name(var/mob/target) if(!can_set_own_name) return - var/newname = sanitizeSafe(input(target,"Enter a name, or leave blank for the default name.", "Name change",target.real_name) as text, MAX_NAME_LEN) + var/newname = sanitize_safe(input(target,"Enter a name, or leave blank for the default name.", "Name change",target.real_name) as text, MAX_NAME_LEN) if (newname && newname != "") target.real_name = newname target.SetName(target.real_name) +/*********************************** +* Computer intelligence cores. * +***********************************/ +/decl/ghosttrap/machine_intelligence + name = "machine intelligence" + ban_checks = list("AI",ASSIGNMENT_ROBOT) + pref_check = "ghost_machine_intelligence" + ghost_trap_message = "They are occupying a computer intelligence core now." + +/decl/ghosttrap/machine_intelligence/transfer_personality(mob/candidate, mob/target) + if(assess_candidate(candidate)) + + var/obj/item/organ/internal/brain/robotic/brain = target.loc?.loc + if(!istype(brain)) + return FALSE + + brain.transfer_key_to_brainmob(candidate, update_brainmob = FALSE) + brain.searching = FALSE + brain.update_icon() + announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]") + + var/mob/living/brainmob = brain.get_brainmob(create_if_missing = TRUE) + if(brainmob) + welcome_candidate(brainmob) + return TRUE + +/decl/ghosttrap/machine_intelligence/forced(var/mob/user) + var/obj/item/organ/internal/brain/robotic/brain = new(get_turf(user)) + request_player(brain.get_brainmob(create_if_missing = TRUE), "Someone is requesting a player for a machine intelligence.", 60 SECONDS) + +/decl/ghosttrap/machine_intelligence/welcome_candidate(var/mob/target) + to_chat(target, "You are a machine intelligence, brought into existence on [station_name()].") + to_chat(target, "As a synthetic intelligence, you answer to all crewmembers, as well as the AI.") + to_chat(target, "Remember, the purpose of your existence is to serve the crew and the [station_name()]. Above all else, do no harm.") + to_chat(target, "Use say [target.get_language_prefix()]b to speak to other artificial intelligences.") + var/turf/T = get_turf(target) + T.visible_message(SPAN_NOTICE("\The [target] beeps loudly.")) + /*********************************** * Walking mushrooms and such. * ***********************************/ -/datum/ghosttrap/plant - object = "living plant" +/decl/ghosttrap/sentient_plant + name = "sentient plant" ban_checks = list("Botany Roles") - pref_check = BE_PLANT + pref_check = "ghost_plant" ghost_trap_message = "They are occupying a living plant now." - ghost_trap_role = "Plant" -/datum/ghosttrap/plant/welcome_candidate(var/mob/target) +/decl/ghosttrap/sentient_plant/forced(var/mob/user) + request_player(new /mob/living/simple_animal/mushroom(get_turf(user)), "Someone is harvesting a walking mushroom.", 15 SECONDS) + +/decl/ghosttrap/sentient_plant/welcome_candidate(var/mob/target) to_chat(target, "You awaken slowly, stirring into sluggish motion as the air caresses you.") /******************** * Maintenance Drone * *********************/ -/datum/ghosttrap/drone - object = "maintenance drone" - pref_check = BE_PAI +/decl/ghosttrap/maintenance_drone + name = "maintenance drone" + pref_check = "ghost_maintdrone" ghost_trap_message = "They are occupying a maintenance drone now." - ghost_trap_role = "Maintenance Drone" can_set_own_name = FALSE - list_as_special_role = FALSE -/datum/ghosttrap/drone/New() +/decl/ghosttrap/maintenance_drone/Initialize() + . = ..() minutes_since_death = DRONE_SPAWN_DELAY - ..() -datum/ghosttrap/drone/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target) +/decl/ghosttrap/maintenance_drone/forced(var/mob/user) + request_player(new /mob/living/silicon/robot/drone(get_turf(user)), "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) + +/decl/ghosttrap/maintenance_drone/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target) . = ..() - if(. && !target.can_be_possessed_by(candidate)) + if(. && !target?.can_be_possessed_by(candidate)) return 0 -datum/ghosttrap/drone/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) +/decl/ghosttrap/maintenance_drone/transfer_personality(var/mob/candidate, var/mob/target) if(!assess_candidate(candidate)) return 0 - drone.transfer_personality(candidate.client) - -/************** -* personal AI * -**************/ -/datum/ghosttrap/pai - object = "pAI" + var/mob/living/silicon/robot/drone/drone = target + if(istype(drone)) + drone.transfer_personality(candidate.client) + +// Stub PAI ghost trap so that PAI shows up in the ghost role list. +// Actually invoking this ghost trap as normal will not do anything. +/decl/ghosttrap/personal_ai + name = "personal AI" pref_check = BE_PAI - ghost_trap_message = "They are occupying a pAI now." - ghost_trap_role = "pAI" - -datum/ghosttrap/pai/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target) - return 0 - -datum/ghosttrap/pai/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) - return 0 - -/****************** -* Wizard Familiar * -******************/ -/datum/ghosttrap/familiar - object = "wizard familiar" - pref_check = MODE_WIZARD - ghost_trap_message = "They are occupying a familiar now." - ghost_trap_role = "Wizard Familiar" - ban_checks = list(MODE_WIZARD) - -/datum/ghosttrap/familiar/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/cult - object = "cultist" - ban_checks = list("cultist") - pref_check = MODE_CULTIST - can_set_own_name = FALSE - ghost_trap_message = "They are occupying a cultist's body now." - ghost_trap_role = "Cultist" - -/datum/ghosttrap/cult/welcome_candidate(var/mob/target) - var/obj/item/soulstone/S = target.loc - if(istype(S)) - if(S.is_evil) - GLOB.cult.add_antagonist(target.mind) - to_chat(target, "Remember, you serve the one who summoned you first, and the cult second.") - else - to_chat(target, "This soultone has been purified. You do not belong to the cult.") - to_chat(target, "Remember, you only serve the one who summoned you.") - -/datum/ghosttrap/cult/shade - object = "soul stone" - ghost_trap_message = "They are occupying a soul stone now." - ghost_trap_role = "Shade" +/decl/ghosttrap/personal_ai/forced(mob/user) + user?.client?.makepAI(user && get_turf(user)) +/decl/ghosttrap/personal_ai/request_player(mob/target, request_string, request_timeout) + return FALSE diff --git a/code/modules/goals/_goal.dm b/code/modules/goals/_goal.dm index 4c516083d6a8..9793c69f26ed 100644 --- a/code/modules/goals/_goal.dm +++ b/code/modules/goals/_goal.dm @@ -2,19 +2,20 @@ var/description var/owner var/completion_message + var/failure_message var/can_reroll = TRUE var/can_abandon = TRUE /datum/goal/New(var/_owner) owner = _owner - GLOB.destroyed_event.register(owner, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/destroyed, owner, src, TYPE_PROC_REF(/datum, qdel_self)) if(istype(owner, /datum/mind)) var/datum/mind/mind = owner LAZYADD(mind.goals, src) update_strings() /datum/goal/Destroy() - GLOB.destroyed_event.unregister(owner, src) + events_repository.unregister(/decl/observ/destroyed, owner, src) if(owner) if(istype(owner, /datum/mind)) var/datum/mind/mind = owner @@ -22,13 +23,13 @@ owner = null . = ..() -/datum/goal/proc/summarize(var/show_success = FALSE, var/allow_modification = FALSE, var/mob/caller ,var/position = 1) +/datum/goal/proc/summarize(var/show_success = FALSE, var/allow_modification = FALSE, var/mob/user ,var/position = 1) . = "[description][get_summary_value()]" if(show_success) . += get_success_string() if(allow_modification) - if(can_abandon) . += " (Abandon)" - if(can_reroll) . += " (Reroll)" + if(can_abandon) . += " (Abandon)" + if(can_reroll) . += " (Reroll)" /datum/goal/proc/get_success_string() return check_success() ? " Success!" : " Failure." @@ -45,11 +46,20 @@ /datum/goal/proc/check_success() return TRUE +/datum/goal/proc/try_initialize() + return TRUE + /datum/goal/proc/on_completion() if(completion_message && check_success()) if(istype(owner, /datum/mind)) var/datum/mind/mind = owner - to_chat(mind.current, "[completion_message]") + to_chat(mind.current, SPAN_GOOD("[completion_message]")) + +/datum/goal/proc/on_failure() + if(failure_message && !check_success()) + if(istype(owner, /datum/mind)) + var/datum/mind/mind = owner + to_chat(mind.current, SPAN_BAD("[failure_message]")) /datum/goal/proc/is_valid() return TRUE diff --git a/code/modules/goals/definitions/department_clerical.dm b/code/modules/goals/definitions/department_clerical.dm new file mode 100644 index 000000000000..99f093b7ea9b --- /dev/null +++ b/code/modules/goals/definitions/department_clerical.dm @@ -0,0 +1,143 @@ +/datum/goal/department/paperwork + var/generated_paperwork = FALSE + var/waiting_for_signatories_description = "Wait for %STAFF% to arrive and have them sign %PAPERWORK%." + var/obj/item/paperwork/paperwork_instance + var/paperwork_type + var/list/paperwork_types = list(/obj/item/paperwork) + var/list/signatory_job_list = list(/datum/job) + var/min_signatories = 1 + var/max_signatories = 1 + +/datum/goal/department/paperwork/New() + SSgoals.pending_goals |= src + var/list/signatory_job_titles = list() + for(var/job_type in signatory_job_list) + var/datum/job/job = job_type + signatory_job_titles |= "[initial(job.total_positions) == 1 ? "the" : "a"] [initial(job.title)]" + waiting_for_signatories_description = replacetext(waiting_for_signatories_description, "%STAFF%", english_list(signatory_job_titles, and_text = " or ")) + if(!length(paperwork_types)) + PRINT_STACK_TRACE("Paperwork goal [type] initialized with no available paperwork types!") + SSgoals.pending_goals -= src + return + paperwork_type = pick(paperwork_types) + waiting_for_signatories_description = replacetext(waiting_for_signatories_description, "%PAPERWORK%", "\the [atom_info_repository.get_name_for(paperwork_type)]") + + ..() + +/datum/goal/department/paperwork/proc/get_paper_spawn_turfs() + return + +/datum/goal/department/paperwork/proc/get_paper_end_areas() + return + +/datum/goal/department/paperwork/try_initialize() + + var/list/start_candidates = get_paper_spawn_turfs() + if(!length(start_candidates)) + PRINT_STACK_TRACE("Paperwork goal [type] initialized with no spawn landmarks mapped!") + SSgoals.pending_goals -= src + return FALSE + + var/list/end_candidates = get_paper_end_areas() + if(!length(end_candidates)) + PRINT_STACK_TRACE("Paperwork goal [type] initialized with no end landmarks mapped!") + SSgoals.pending_goals -= src + return FALSE + + var/list/signatories = generate_signatory_list() + if(length(signatories) < min_signatories) + return FALSE + shuffle(signatories) + signatories.Cut(1, max_signatories) + + paperwork_instance = new paperwork_type(pick(start_candidates)) + paperwork_instance.associated_goal = src + paperwork_instance.must_end_round_in_area = pick(end_candidates) + paperwork_instance.all_signatories = signatories + paperwork_instance.needs_signed = paperwork_instance.all_signatories.Copy() + generated_paperwork = TRUE + update_strings() + return TRUE + +/datum/goal/department/paperwork/proc/generate_signatory_list() + . = list() + for(var/mob/M in global.living_mob_list_) + if(!M.mind?.assigned_job) + continue + for(var/job_type in signatory_job_list) + if(istype(M.mind.assigned_job, job_type)) + . |= M.real_name + break + +/datum/goal/department/paperwork/update_strings() + if(!generated_paperwork) + description = waiting_for_signatories_description + else if(QDELETED(paperwork_instance)) + description = "\The [atom_info_repository.get_name_for(paperwork_type)] has been destroyed." + else if(length(paperwork_instance.needs_signed)) + description = "Have \the [paperwork_instance] signed by [english_list(paperwork_instance.all_signatories)]." + else + description = "File the completed [paperwork_instance.name] in \the [paperwork_instance.must_end_round_in_area] by the end of the shift." + +/datum/goal/department/paperwork/check_success() + if(!generated_paperwork) + return TRUE + . = !QDELETED(paperwork_instance) + if(.) + var/turf/T = get_turf(paperwork_instance) + if(!istype(T)) + return FALSE + var/area/A = get_area(T) + if(!istype(A)) + return FALSE + return !length(paperwork_instance.needs_signed) && (A == paperwork_instance.must_end_round_in_area) + +/obj/item/paperwork + name = "paperwork" + gender = PLURAL + desc = "This densely typed sheaf of documents is filled with legalese and jargon. You can't make heads or tails of them." + icon = 'icons/obj/goal_paperwork.dmi' + icon_state = "generic" + material = /decl/material/solid/organic/paper + + var/datum/goal/department/paperwork/associated_goal + var/list/all_signatories + var/list/needs_signed + var/list/has_signed + var/area/must_end_round_in_area + +/obj/item/paperwork/Destroy() + if(associated_goal) + if(associated_goal.paperwork_instance == src) + associated_goal.paperwork_instance = null + associated_goal.update_strings() + associated_goal = null + . = ..() + +/obj/item/paperwork/on_update_icon() + . = ..() + icon_state = "[icon_state][length(has_signed) || ""]" + +/obj/item/paperwork/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + if(length(needs_signed)) + . += SPAN_WARNING("It needs [length(needs_signed)] more signature\s before it can be filed: [english_list(needs_signed)].") + if(length(has_signed)) + . += SPAN_NOTICE("It has been signed by: [english_list(has_signed)].") + +/obj/item/paperwork/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) + if(user.real_name in has_signed) + to_chat(user, SPAN_WARNING("You have already signed \the [src].")) + return TRUE + if(!(user.real_name in needs_signed)) + to_chat(user, SPAN_WARNING("You can't see anywhere on \the [src] for you to sign; it doesn't need your signature.")) + return TRUE + LAZYADD(has_signed, user.real_name) + LAZYREMOVE(needs_signed, user.real_name) + user.visible_message(SPAN_NOTICE("\The [user] signs \the [src] with \the [used_item].")) + associated_goal?.update_strings() + update_icon() + return TRUE + . = ..() diff --git a/code/modules/goals/definitions/department_science.dm b/code/modules/goals/definitions/department_science.dm index 50fd13e57e99..ef82fa1a3d6e 100644 --- a/code/modules/goals/definitions/department_science.dm +++ b/code/modules/goals/definitions/department_science.dm @@ -18,5 +18,4 @@ return (SSstatistics.extracted_slime_cores_amount >= min_cores) // Personal: - // xenobio: finish a round without being attacked by a slime - // explorer: name an alien species, plant a flag on an undiscovered world \ No newline at end of file + // explorer: name an alien species, plant a flag on an undiscovered world diff --git a/code/modules/goals/definitions/personal_achievement.dm b/code/modules/goals/definitions/personal_achievement.dm index bd99d390b442..12849c7f7851 100644 --- a/code/modules/goals/definitions/personal_achievement.dm +++ b/code/modules/goals/definitions/personal_achievement.dm @@ -1,12 +1,16 @@ -// Simple toggles. Get an input from somewhere in the code, marked -// as successful for the rest of the round. Nothing very special. +// Simple toggles. Get an input from somewhere in the code, marked +// as successful/unsuccessful for the rest of the round. Nothing very special. /datum/goal/achievement + var/failable = FALSE var/success = FALSE /datum/goal/achievement/update_progress(var/progress) - if(!success) + if(!success && !failable) success = progress on_completion() + else if (success && failable) + success = progress + on_failure() /datum/goal/achievement/check_success() return success @@ -28,5 +32,5 @@ completion_message = "Yeah! Smash the state!" /datum/goal/achievement/newshound - description = "Catch up on the news with a newspaper, none of that new-fangled digital media." + description = "Catch up on the news with a newspaper, none of that newfangled digital media." completion_message = "You feel much more in-the-know." \ No newline at end of file diff --git a/code/modules/goals/definitions/personal_achievement_movement.dm b/code/modules/goals/definitions/personal_achievement_movement.dm index b63dbcda2398..5e1e650a0c36 100644 --- a/code/modules/goals/definitions/personal_achievement_movement.dm +++ b/code/modules/goals/definitions/personal_achievement_movement.dm @@ -3,7 +3,7 @@ ..() if(owner) var/datum/mind/mind = owner - GLOB.moved_event.register(mind.current, src, .proc/owner_moved) + events_repository.register(/decl/observ/moved, mind.current, src, PROC_REF(owner_moved)) /datum/goal/movement/proc/owner_moved() return @@ -11,7 +11,7 @@ /datum/goal/movement/Destroy() if(owner) var/datum/mind/mind = owner - GLOB.moved_event.unregister(mind.current, src) + events_repository.unregister(/decl/observ/moved, mind.current, src) . = ..() /datum/goal/movement/walk @@ -29,7 +29,7 @@ steps++ if(steps >= required_steps) on_completion() - GLOB.moved_event.unregister(owner, src) + events_repository.unregister(/decl/observ/moved, owner, src) /datum/goal/movement/walk/get_summary_value() return " ([steps]/[required_steps] step\s so far)" @@ -40,7 +40,7 @@ /datum/goal/movement/walk/check_success() return (steps >= required_steps) - + /datum/goal/movement/walk/update_strings() description = "Stave off microgravity muscle atrophy by walking at least [required_steps] step\s this shift." @@ -51,7 +51,7 @@ /datum/goal/movement/walk/eva/valid_step() var/datum/mind/mind = owner - return istype(mind.current.loc, /turf/space) + return isspaceturf(mind.current.loc) /datum/goal/movement/walk/eva/update_strings() description = "It's so stuffy inside. Go for a spacewalk - at least [required_steps] step\s." \ No newline at end of file diff --git a/code/modules/goals/definitions/personal_achievement_specific_object.dm b/code/modules/goals/definitions/personal_achievement_specific_object.dm index 836e33a5893b..93c4883eedf9 100644 --- a/code/modules/goals/definitions/personal_achievement_specific_object.dm +++ b/code/modules/goals/definitions/personal_achievement_specific_object.dm @@ -28,7 +28,12 @@ completion_message = "Ahh, that was just what you needed." /datum/goal/achievement/specific_object/food/New() - possible_objects = subtypesof(/obj/item/chems/food/snacks) + possible_objects = subtypesof(/obj/item/food) + blacklisted_objects = blacklisted_objects || list() + blacklisted_objects |= typesof(/obj/item/food/amanita_pie) + blacklisted_objects |= typesof(/obj/item/food/amanitajelly) + blacklisted_objects |= typesof(/obj/item/food/can/caviar/true) + blacklisted_objects |= typesof(/obj/item/food/old) ..() /datum/goal/achievement/specific_object/food/update_strings() @@ -40,7 +45,7 @@ completion_message = "Ahh, that hit the spot!" /datum/goal/achievement/specific_object/drink/New() - possible_objects = subtypesof(/decl/material/liquid/drink) + possible_objects = decls_repository.get_decl_paths_of_subtype(/decl/material/liquid/drink) ..() /datum/goal/achievement/specific_object/drink/update_strings() @@ -54,10 +59,10 @@ /datum/goal/achievement/specific_object/pet possible_objects = list( /mob/living/simple_animal/corgi, - /mob/living/simple_animal/cat + /mob/living/simple_animal/passive/cat ) /datum/goal/achievement/specific_object/pet/update_strings() ..() var/mob/animal = object_path - description = "Pet \a [initial(animal.name)]." + description = "Pet \a [initial(animal.name)]." // probably best not to use the atom info repository for this, lest we get 'Pet a monkey (666).' diff --git a/code/modules/goals/goal_ambition.dm b/code/modules/goals/goal_ambition.dm index 2029bc5cf23f..aa44ad99b10a 100644 --- a/code/modules/goals/goal_ambition.dm +++ b/code/modules/goals/goal_ambition.dm @@ -13,5 +13,5 @@ /datum/goal/ambition/get_success_string() return "" -/datum/goal/ambition/summarize(var/show_success = FALSE, var/allow_modification = FALSE, var/mob/caller ,var/position = 1) +/datum/goal/ambition/summarize(var/show_success = FALSE, var/allow_modification = FALSE, var/mob/user ,var/position = 1) . = SPAN_DANGER(..(show_success)) diff --git a/code/modules/goals/goal_mind.dm b/code/modules/goals/goal_mind.dm index 496005827462..a195dbd48e6b 100644 --- a/code/modules/goals/goal_mind.dm +++ b/code/modules/goals/goal_mind.dm @@ -3,17 +3,17 @@ /datum/mind/proc/show_roundend_summary(var/department_goals) if(current) - if(department_goals && current.get_preference_value(/datum/client_preference/show_department_goals) == GLOB.PREF_SHOW) + if(department_goals && current.get_preference_value(/datum/client_preference/show_department_goals) == PREF_SHOW) to_chat(current, SPAN_NOTICE(department_goals)) if(LAZYLEN(goals)) to_chat(current, SPAN_NOTICE("

          You had the following personal goals this round:
          [jointext(summarize_goals(TRUE), "
          ")]")) -/datum/mind/proc/summarize_goals(var/show_success = FALSE, var/allow_modification = FALSE, var/mob/caller) +/datum/mind/proc/summarize_goals(var/show_success = FALSE, var/allow_modification = FALSE, var/mob/user) . = list() if(LAZYLEN(goals)) for(var/i = 1 to LAZYLEN(goals)) var/datum/goal/goal = goals[i] - . += "[i]. [goal.summarize(show_success, allow_modification, caller, position = i)]" + . += "[i]. [goal.summarize(show_success, allow_modification, user, position = i)]" // Create and display personal goals for this round. /datum/mind/proc/generate_goals(var/datum/job/job, var/adding_goals = FALSE, var/add_amount, var/is_spawning = FALSE) @@ -22,24 +22,25 @@ goals = null var/pref_val = current.get_preference_value(/datum/client_preference/give_personal_goals) - if(pref_val == GLOB.PREF_NEVER || (pref_val == GLOB.PREF_NON_ANTAG && player_is_antag(src))) + if(pref_val == PREF_NEVER || (pref_val == PREF_NON_ANTAG && player_is_antag(src))) if(!is_spawning) to_chat(src.current, "Your preferences do not allow you to add random goals.") return FALSE var/list/available_goals = SSgoals.global_personal_goals ? SSgoals.global_personal_goals.Copy() : list() + if(job && LAZYLEN(job.possible_goals)) + available_goals |= job.possible_goals if(ishuman(current)) - var/mob/living/carbon/human/H = current - for(var/token in H.cultural_info) - var/decl/cultural_info/culture = H.get_cultural_value(token) - var/list/new_goals = culture.get_possible_personal_goals(job ? job.department_refs : null) + var/mob/living/human/H = current + for(var/token in H.background_info) + var/decl/background_detail/background = H.get_background_datum(token) + var/list/new_goals = background.get_possible_personal_goals(job ? job.department_types : null) if(LAZYLEN(new_goals)) available_goals |= new_goals if(isnull(add_amount)) var/min_goals = 1 var/max_goals = 3 if(job && LAZYLEN(job.possible_goals)) - available_goals |= job.possible_goals min_goals = job.min_goals max_goals = job.max_goals add_amount = rand(min_goals, max_goals) diff --git a/code/modules/goals/goal_mob.dm b/code/modules/goals/goal_mob.dm index e388a8142b3b..ea3d8ce41261 100644 --- a/code/modules/goals/goal_mob.dm +++ b/code/modules/goals/goal_mob.dm @@ -21,7 +21,7 @@ return //No goals to display - if(!(allow_modification || LAZYLEN(mind.goals)) && !(LAZYLEN(mind.assigned_job.department_refs))) + if(!(allow_modification || LAZYLEN(mind.goals)) && !(LAZYLEN(mind.assigned_job?.department_types))) return to_chat(src, "
          ") @@ -30,14 +30,15 @@ else to_chat(src, SPAN_NOTICE("You have no personal goals this round.")) if(allow_modification && LAZYLEN(mind.goals) < 5) - to_chat(src, SPAN_NOTICE("Add Random Goal")) - - for(var/dept_key in mind.assigned_job.department_refs) - var/datum/department/dept = SSdepartments.departments[dept_key] - if(LAZYLEN(dept.goals)) - to_chat(src, SPAN_NOTICE("

          This round, [dept.title] has the following departmental goals:
          [jointext(dept.summarize_goals(show_success), "
          ")]")) - else - to_chat(src, SPAN_NOTICE("

          [dept.title] has no departmental goals this round.")) + to_chat(src, SPAN_NOTICE("Add Random Goal")) + + for(var/dept_key in mind.assigned_job?.department_types) + var/decl/department/dept = SSjobs.get_department_by_type(dept_key) + if(dept) + if(LAZYLEN(dept.goals)) + to_chat(src, SPAN_NOTICE("

          This round, [dept.name] has the following [dept.noun_adj] goals:
          [jointext(dept.summarize_goals(show_success), "
          ")]")) + else + to_chat(src, SPAN_NOTICE("

          [dept.name] has no [dept.noun_adj] goals this round.")) if(LAZYLEN(mind.goals)) to_chat(mind.current, SPAN_NOTICE("

          You can check your round goals with the Show Goals verb.")) diff --git a/code/modules/grooming/_grooming.dm b/code/modules/grooming/_grooming.dm new file mode 100644 index 000000000000..0618caac4917 --- /dev/null +++ b/code/modules/grooming/_grooming.dm @@ -0,0 +1,87 @@ + +/obj/item/grooming + abstract_type = /obj/item/grooming + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + + var/message_target_other_generic = "$USER$ grooms $TARGET$ with $TOOL$." + var/message_target_self_generic = "$USER$ grooms $USER_SELF$ with $TOOL$." + var/message_target_other = "$USER$ grooms $TARGET$'s $DESCRIPTOR$ with $TOOL$." + var/message_target_self = "$USER$ grooms $USER_HIS$ $DESCRIPTOR$ with $TOOL$." + var/message_target_other_partial = "$USER$ just sort of runs $TOOL$ over $TARGET$'s $DESCRIPTOR$." + var/message_target_self_partial = "$USER$ just sort of runs $TOOL$ over $USER_HIS$ $DESCRIPTOR$." + var/message_target_other_missing = "$TARGET$'s $LIMB$ has nothing to groom!" + var/message_target_self_missing = "Your $LIMB$ has nothing to groom!" + var/grooming_flags = GROOMABLE_NONE + +/obj/item/grooming/Initialize() + . = ..() + update_icon() + +/obj/item/grooming/proc/replace_message_tokens(message, mob/living/user, mob/living/target, obj/item/tool, limb, descriptor) + var/decl/pronouns/user_pronouns = user.get_pronouns() + var/decl/pronouns/target_pronouns = target.get_pronouns() + . = message + . = replacetext(., "$USER$", "\the [user]") + . = replacetext(., "$USER_HIS$", user_pronouns.his) + . = replacetext(., "$USER_HIM$", user_pronouns.him) + . = replacetext(., "$USER_SELF$", user_pronouns.self) + . = replacetext(., "$TARGET$", "\the [target]") + . = replacetext(., "$TARGET_HIS$", target_pronouns.his) + . = replacetext(., "$TARGET_HIM$", target_pronouns.him) + . = replacetext(., "$TARGET_SELF$", target_pronouns.self) + . = replacetext(., "$TOOL$", "\the [tool]") + . = replacetext(., "$DESCRIPTOR$", descriptor) + . = replacetext(., "$LIMB$", limb) + . = capitalize(.) + +/obj/item/grooming/proc/try_groom(mob/living/user, mob/living/target) + + if(!istype(user) || !istype(target) || user.incapacitated() || user.check_intent(I_FLAG_HARM)) + return FALSE + + if(!length(target.get_external_organs())) + return target.handle_general_grooming(user, src) + + var/zone = user.get_target_zone() + if(!zone) + return FALSE + + var/target_self = user == target + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(target, zone) + if(!affecting) + to_chat(user, SPAN_WARNING("[target_self ? "You are" : "\The [target] [target.get_pronouns().is]"] missing [target_self ? "your" : target.get_pronouns().his] [parse_zone(zone)].")) + return TRUE + + var/obj/item/blocking = target.bodypart_is_covered(zone) + if(blocking) + to_chat(user, "\The [blocking] [blocking.get_pronouns().is] in the way!") + return TRUE + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + + // return type is assoc list ie. list("success" = GROOMING_RESULT_PARTIAL, "descriptor" = "hair") + var/list/grooming_results = affecting.get_grooming_results(src) + var/show_message + switch(LAZYACCESS(grooming_results, "success")) + if(GROOMING_RESULT_PARTIAL) + show_message = target_self ? message_target_self_partial : message_target_other_partial + if(GROOMING_RESULT_SUCCESS) + show_message = target_self ? message_target_self : message_target_other + else + show_message = target_self ? message_target_self_missing : message_target_other_missing + visible_message(SPAN_NOTICE(replace_message_tokens(show_message, user, target, src, parse_zone(zone), LAZYACCESS(grooming_results, "descriptor") || "marking"))) + target.add_stressor(/datum/stressor/well_groomed, 5 MINUTES) + return TRUE + +/obj/item/grooming/attack_self(mob/user) + if(try_groom(user, user)) + return TRUE + return ..() + +/obj/item/grooming/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(try_groom(user, target)) + return TRUE + return ..() diff --git a/code/modules/grooming/grooming_comb.dm b/code/modules/grooming/grooming_comb.dm new file mode 100644 index 000000000000..5b57babd5cea --- /dev/null +++ b/code/modules/grooming/grooming_comb.dm @@ -0,0 +1,58 @@ +/obj/item/grooming/comb + name = "comb" + desc = "A pristine comb." + icon = 'icons/obj/items/grooming/comb.dmi' + material = /decl/material/solid/organic/plastic + + message_target_other_generic = "$USER$ tidily combs $TARGET$ with $TOOL$." + message_target_self_generic = "$USER$ tidily combs $USER_SELF$ with $TOOL$." + message_target_other = "$USER$ tidily combs $TARGET$'s $DESCRIPTOR$ with $TOOL$." + message_target_self = "$USER$ tidily combs $USER_HIS$ $DESCRIPTOR$ with $TOOL$." + grooming_flags = GROOMABLE_COMB + +/obj/item/grooming/comb/colorable + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/grooming/comb/colorable/random/Initialize() + set_color(get_random_colour(lower = 150)) + . = ..() + +// Looks exactly like a butterfly knife inhand. +/obj/item/grooming/comb/butterfly + name = "butterfly comb" + desc = "A very stylish comb that folds into a handle." + icon = 'icons/obj/items/grooming/comb_butterfly.dmi' + material = /decl/material/solid/metal/steel + + message_target_other_generic = "$USER$ uses $TOOL$ to comb $TARGET$ with incredible style and sophistication." + message_target_self_generic = "$USER$ uses $TOOL$ to comb $USER_SELF$ with incredible style and sophistication. What a $USER_GUY$." + message_target_other = "$USER$ uses $TOOL$ to comb $TARGET$'s hair with incredible style and sophistication." + message_target_self = "$USER$ uses $TOOL$ to comb $USER_HIS$ hair with incredible style and sophistication. What a $USER_GUY$." + + var/opened = FALSE + +/obj/item/grooming/comb/butterfly/attack_self(mob/user) + if(user.check_intent(I_FLAG_HARM)) + return ..() + opened = !opened + if(opened) + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + user.visible_message(SPAN_NOTICE("\The [user] flicks \the [src] [opened ? "open" : "closed"].")) + update_icon() + return TRUE + +/obj/item/grooming/comb/butterfly/try_groom(mob/living/user, mob/living/target) + return opened && ..() + +/obj/item/grooming/comb/butterfly/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(opened) + icon_state = "[icon_state]_open" + +/obj/item/grooming/comb/butterfly/replace_message_tokens(message, mob/living/user, mob/living/target, obj/item/tool, limb, descriptor) + message = replacetext(message, "$USER_GUY$", user.get_pronouns().informal_term) + return ..() + +/obj/item/grooming/comb/butterfly/colorable + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC diff --git a/code/modules/grooming/grooming_file.dm b/code/modules/grooming/grooming_file.dm new file mode 100644 index 000000000000..f5f9302ef403 --- /dev/null +++ b/code/modules/grooming/grooming_file.dm @@ -0,0 +1,14 @@ +/obj/item/grooming/file + name = "nail file" + desc = "A rugged file suitable for smoothing down unruly nails or horns." + icon = 'icons/obj/items/grooming/file.dmi' + material = /decl/material/solid/metal/steel + + message_target_other_generic = "$USER$ uses $TOOL$ to neaten $TARGET$ up." + message_target_self_generic = "$USER$ uses $TOOL$ to neaten $USER_SELF$ up." + message_target_other = "$USER$ carefully files down $TARGET$'s $DESCRIPTOR$ with $TOOL$." + message_target_self = "$USER$ carefully files down $USER_HIS$ $DESCRIPTOR$ with $TOOL$." + grooming_flags = GROOMABLE_FILE + +/obj/item/grooming/file/colorable + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC diff --git a/code/modules/grooming/grooming_hairbrush.dm b/code/modules/grooming/grooming_hairbrush.dm new file mode 100644 index 000000000000..b325c62b661d --- /dev/null +++ b/code/modules/grooming/grooming_hairbrush.dm @@ -0,0 +1,27 @@ +/obj/item/grooming/brush + name = "hairbrush" + desc = "A surprisingly decent hairbrush with a sturdy handle and semi-soft bristles." + icon = 'icons/obj/items/grooming/hairbrush.dmi' + w_class = ITEM_SIZE_SMALL + slot_flags = null + material = /decl/material/solid/organic/plastic + + message_target_other_generic = "$USER$ meticulously brushes $TARGET$ with $TOOL$." + message_target_self_generic = "$USER$ meticulously brushes $USER_SELF$ with $TOOL$." + message_target_other = "$USER$ meticulously brushes $TARGET$'s $DESCRIPTOR$ with $TOOL$." + message_target_self = "$USER$ meticulously brushes $USER_HIS$ $DESCRIPTOR$ with $TOOL$." + grooming_flags = GROOMABLE_BRUSH + +/obj/item/grooming/brush/on_update_icon() + ..() + var/image/I = image(icon, "[icon_state]-bristles") + I.color = COLOR_GRAY40 + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/grooming/brush/colorable + material_alteration = MAT_FLAG_ALTERATION_NAME + +/obj/item/grooming/brush/colorable/random/Initialize() + set_color(get_random_colour(lower = 150)) + . = ..() diff --git a/code/modules/hallucinations/_hallucination.dm b/code/modules/hallucinations/_hallucination.dm new file mode 100644 index 000000000000..399fd5dfc0e6 --- /dev/null +++ b/code/modules/hallucinations/_hallucination.dm @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////////////////////////////// +//Hallucination effects datums +////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/hallucination + var/mob/living/holder + var/allow_duplicates = 1 + var/duration = 0 + var/min_power = 0 //at what levels of hallucination power mobs should get it + var/max_power = INFINITY + var/activated = FALSE + +/datum/hallucination/proc/start() + SHOULD_CALL_PARENT(TRUE) + activated = TRUE + +/datum/hallucination/proc/end() + SHOULD_CALL_PARENT(TRUE) + activated = FALSE + +/datum/hallucination/proc/can_affect(var/mob/living/victim) + if(!victim.client) + return FALSE + if(min_power > victim.hallucination_power) + return FALSE + if(max_power < victim.hallucination_power) + return FALSE + if(!allow_duplicates && (locate(type) in victim._hallucinations)) + return FALSE + return TRUE + +/datum/hallucination/Destroy() + if(holder) + LAZYREMOVE(holder._hallucinations, src) + holder = null + if(activated) + end() + return ..() + +/datum/hallucination/proc/activate_hallucination() + set waitfor = FALSE + if(!holder || !holder.client || activated) + return + LAZYADD(holder._hallucinations, src) + start() + sleep(duration) + if(!QDELETED(src)) + qdel(src) diff --git a/code/modules/hallucinations/hallucination_fakeattack.dm b/code/modules/hallucinations/hallucination_fakeattack.dm new file mode 100644 index 000000000000..70ba9d36a048 --- /dev/null +++ b/code/modules/hallucinations/hallucination_fakeattack.dm @@ -0,0 +1,20 @@ +//Fake attack +/datum/hallucination/fakeattack + min_power = 30 + +/datum/hallucination/fakeattack/can_affect(var/mob/living/victim) + . = ..() && (locate(/mob/living) in oview(victim,1)) + +/datum/hallucination/fakeattack/start() + . = ..() + for(var/mob/living/assailant in oview(holder,1)) + to_chat(holder, SPAN_DANGER("\The [assailant] has punched \the [holder]!")) + holder.playsound_local(get_turf(holder),"punch",50) + +//Fake injection +/datum/hallucination/fakeattack/hypo + min_power = 30 + +/datum/hallucination/fakeattack/hypo/start() + . = ..() + to_chat(holder, SPAN_NOTICE("You feel a tiny prick!")) diff --git a/code/modules/hallucinations/hallucination_gunfire.dm b/code/modules/hallucinations/hallucination_gunfire.dm new file mode 100644 index 000000000000..d41d6289e65a --- /dev/null +++ b/code/modules/hallucinations/hallucination_gunfire.dm @@ -0,0 +1,31 @@ +//Hearing someone being shot twice +/datum/hallucination/gunfire + duration = 15 + min_power = 30 + var/gunshot + var/turf/origin + var/static/list/gunshot_sounds = list( + 'sound/weapons/gunshot/gunshot_strong.ogg', + 'sound/weapons/gunshot/gunshot2.ogg', + 'sound/weapons/gunshot/shotgun.ogg', + 'sound/weapons/gunshot/gunshot.ogg', + 'sound/weapons/Taser.ogg' + ) + +/datum/hallucination/gunfire/start() + . = ..() + gunshot = pick(gunshot_sounds) + var/turf/holder_turf = get_turf(holder) + if(isturf(holder_turf)) + origin = locate(holder_turf.x + rand(4,8), holder_turf.y + rand(4,8), holder_turf.z) + if(origin) + holder.playsound_local(origin, gunshot, 50) + +/datum/hallucination/gunfire/end() + . = ..() + if(holder && origin) + holder.playsound_local(origin, gunshot, 50) + +/datum/hallucination/gunfire/Destroy() + origin = null + return ..() \ No newline at end of file diff --git a/code/modules/hallucinations/hallucination_mirage.dm b/code/modules/hallucinations/hallucination_mirage.dm new file mode 100644 index 000000000000..adc6ad4e5b09 --- /dev/null +++ b/code/modules/hallucinations/hallucination_mirage.dm @@ -0,0 +1,77 @@ +//Seeing stuff +/datum/hallucination/mirage + duration = 30 SECONDS + max_power = 30 + var/number = 1 + var/list/things = list() //list of images to display + var/static/list/trash_states = icon_states('icons/obj/trash.dmi') + +/datum/hallucination/mirage/proc/generate_mirage() + return image('icons/obj/trash.dmi', pick(trash_states), layer = BELOW_TABLE_LAYER) + +/datum/hallucination/mirage/start() + . = ..() + var/list/possible_points = list() + for(var/turf/F in view(holder, world.view+1)) + if(F.simulated && F.is_floor()) + possible_points += F + if(possible_points.len) + for(var/i = 1 to number) + var/image/thing = generate_mirage() + things += thing + thing.loc = pick(possible_points) + if(holder?.client && length(things)) + holder.client.images += things + +/datum/hallucination/mirage/end() + if(holder?.client) + holder.client.images -= things + return ..() + +//Blood and aftermath of firefight +/datum/hallucination/mirage/carnage + min_power = 50 + number = 10 + var/static/list/carnage_states = list( + "mfloor1", + "mfloor2", + "mfloor3", + "mfloor4", + "mfloor5", + "mfloor6", + "mfloor7" + ) + +/datum/hallucination/mirage/carnage/generate_mirage() + var/image/I + if(prob(50)) + I = image('icons/effects/blood.dmi', pick(carnage_states), layer = BELOW_TABLE_LAYER) + I.color = COLOR_BLOOD_HUMAN + else + I = image('icons/obj/ammo.dmi', "s-casing-spent", layer = BELOW_TABLE_LAYER) + I.layer = BELOW_TABLE_LAYER + I.dir = pick(global.alldirs) + I.pixel_x = rand(-10,10) + I.pixel_y = rand(-10,10) + return I + +//LOADSEMONEY +/datum/hallucination/mirage/money + min_power = 20 + max_power = 45 + number = 2 + var/static/obj/item/cash/cash + +/datum/hallucination/mirage/money/New() + if(!cash) + cash = new /obj/item/cash/c500 + cash.update_icon() + cash.compile_overlays() + ..() + +/datum/hallucination/mirage/money/generate_mirage() + var/image/I = new + I.appearance = cash + I.layer = BELOW_TABLE_LAYER + qdel(cash) + return I diff --git a/code/modules/hallucinations/hallucination_skitters.dm b/code/modules/hallucinations/hallucination_skitters.dm new file mode 100644 index 000000000000..2ab7f1fdf353 --- /dev/null +++ b/code/modules/hallucinations/hallucination_skitters.dm @@ -0,0 +1,4 @@ +//Spiderling skitters +/datum/hallucination/skitter/start() + . = ..() + to_chat(holder, SPAN_NOTICE("The spiderling skitters[pick(" away"," around","")].")) diff --git a/code/modules/hallucinations/hallucination_sound.dm b/code/modules/hallucinations/hallucination_sound.dm new file mode 100644 index 000000000000..82e2389713b3 --- /dev/null +++ b/code/modules/hallucinations/hallucination_sound.dm @@ -0,0 +1,71 @@ +//Playing a random sound +/datum/hallucination/imagined_sound/proc/get_imagined_sounds() + var/static/list/sounds = list( + 'sound/machines/airlock.ogg', + 'sound/effects/explosionfar.ogg', + 'sound/machines/windowdoor.ogg', + 'sound/machines/twobeep.ogg' + ) + return sounds + +/datum/hallucination/imagined_sound/start() + . = ..() + var/turf/holder_turf = get_turf(holder) + if(holder_turf) + holder_turf = locate(holder_turf.x + rand(6,11), holder_turf.y + rand(6,11), holder_turf.z) + if(holder_turf) + holder.playsound_local(holder_turf, pick(get_imagined_sounds()) ,70) + +/datum/hallucination/imagined_sound/tools/get_imagined_sounds() + var/static/list/imagined_sounds = list( + 'sound/items/Ratchet.ogg', + 'sound/items/Welder.ogg', + 'sound/items/Crowbar.ogg', + 'sound/items/Screwdriver.ogg' + ) + return imagined_sounds + +/datum/hallucination/imagined_sound/danger + min_power = 30 + +/datum/hallucination/imagined_sound/danger/get_imagined_sounds() + var/static/list/imagined_sounds = list( + 'sound/effects/Explosion1.ogg', + 'sound/effects/Explosion2.ogg', + 'sound/effects/Glassbr1.ogg', + 'sound/effects/Glassbr2.ogg', + 'sound/effects/Glassbr3.ogg', + 'sound/weapons/smash.ogg' + ) + return imagined_sounds + +/datum/hallucination/imagined_sound/spooky + min_power = 50 + +/datum/hallucination/imagined_sound/spooky/get_imagined_sounds() + var/static/list/imagined_sounds = list( + 'sound/effects/ghost.ogg', + 'sound/effects/ghost2.ogg', + 'sound/effects/Heart Beat.ogg', + 'sound/effects/screech.ogg', + 'sound/hallucinations/behind_you1.ogg', + 'sound/hallucinations/behind_you2.ogg', + 'sound/hallucinations/far_noise.ogg', + 'sound/hallucinations/growl1.ogg', + 'sound/hallucinations/growl2.ogg', + 'sound/hallucinations/growl3.ogg', + 'sound/hallucinations/im_here1.ogg', + 'sound/hallucinations/im_here2.ogg', + 'sound/hallucinations/i_see_you1.ogg', + 'sound/hallucinations/i_see_you2.ogg', + 'sound/hallucinations/look_up1.ogg', + 'sound/hallucinations/look_up2.ogg', + 'sound/hallucinations/over_here1.ogg', + 'sound/hallucinations/over_here2.ogg', + 'sound/hallucinations/over_here3.ogg', + 'sound/hallucinations/turn_around1.ogg', + 'sound/hallucinations/turn_around2.ogg', + 'sound/hallucinations/veryfar_noise.ogg', + 'sound/hallucinations/wail.ogg' + ) + return imagined_sounds diff --git a/code/modules/hallucinations/hallucination_spiderbabies.dm b/code/modules/hallucinations/hallucination_spiderbabies.dm new file mode 100644 index 000000000000..f7b4b3bb94a0 --- /dev/null +++ b/code/modules/hallucinations/hallucination_spiderbabies.dm @@ -0,0 +1,11 @@ +//Spiders in your body +/datum/hallucination/spiderbabies + min_power = 40 + +/datum/hallucination/spiderbabies/start() + . = ..() + var/list/limbs = holder.get_external_organs() + if(!LAZYLEN(limbs)) + return + var/obj/O = pick(limbs) + to_chat(holder, SPAN_WARNING("You feel something [pick("moving","squirming","skittering")] inside of your [O.name]!")) diff --git a/code/modules/hallucinations/hallucination_talking.dm b/code/modules/hallucinations/hallucination_talking.dm new file mode 100644 index 000000000000..a472010a2f3e --- /dev/null +++ b/code/modules/hallucinations/hallucination_talking.dm @@ -0,0 +1,41 @@ +//Hearing someone talking to/about you. +/datum/hallucination/talking/can_affect(var/mob/living/victim) + return ..() && (locate(/mob/living) in oview(victim)) + +/datum/hallucination/talking/start() + . = ..() + var/sanity = 5 //even insanity needs some sanity + for(var/mob/living/talker in oview(holder)) + if(talker.stat) + continue + var/message + if(prob(80)) + var/list/names = list() + var/lastname = copytext(holder.real_name, findtext(holder.real_name, " ")+1) + var/firstname = copytext(holder.real_name, 1, findtext(holder.real_name, " ")) + if(lastname) names += lastname + if(firstname) names += firstname + if(!names.len) + names += holder.real_name + var/add = prob(20) ? ", [pick(names)]" : "" + var/list/phrases = list("[prob(50) ? "Hey, " : ""][pick(names)]!","[prob(50) ? "Hey, " : ""][pick(names)]?","Get out[add]!","Go away[add].","What are you doing[add]?","Where's your ID[add]?") + if(holder.hallucination_power > 50) + phrases += list("What did you come here for[add]?","Don't touch me[add].","You're not getting out of here[add].", "You are a failure, [pick(names)].","Just kill yourself already, [pick(names)].","Put on some clothes[add].","Take off your clothes[add].") + message = pick(phrases) + to_chat(holder,"[talker.name] [holder.say_quote(message)], \"[message]\"") + else + to_chat(holder,"[talker.name] points at [holder.name]") + to_chat(holder,"[talker.name] says something softly.") + + var/speech_state = holder.check_speech_punctuation_state(message) + if(speech_state) + var/image/speech_bubble = image('icons/mob/talk.dmi', talker, speech_state) + addtimer(CALLBACK(src, PROC_REF(qdel_image), speech_bubble), 3 SECONDS) + show_image(holder, speech_bubble) + + sanity-- //don't spam them in very populated rooms. + if(!sanity) + break + +/datum/hallucination/talking/proc/qdel_image(var/image/speech_bubble) + qdel(speech_bubble) diff --git a/code/modules/hallucinations/hallucination_telepathy.dm b/code/modules/hallucinations/hallucination_telepathy.dm new file mode 100644 index 000000000000..a4a409f52e9d --- /dev/null +++ b/code/modules/hallucinations/hallucination_telepathy.dm @@ -0,0 +1,42 @@ +//Fake telepathy +/datum/hallucination/telepathy + allow_duplicates = 0 + duration = 20 MINUTES + +/datum/hallucination/telepathy/start() + . = ..() + to_chat(holder, SPAN_NOTICE("You expand your mind outwards.")) + holder.verbs += /mob/living/human/proc/fakeremotesay + +/datum/hallucination/telepathy/end() + . = ..() + if(holder) + holder.verbs -= /mob/living/human/proc/fakeremotesay + +/mob/living/human/proc/fakeremotesay() + set name = "Telepathic Message" + set category = "Superpower" + + if(!hallucination_power) + src.verbs -= /mob/living/human/proc/fakeremotesay + return + + if(stat) + to_chat(usr, SPAN_WARNING("You're not in any state to use your powers right now!")) + return + + if(has_chemical_effect(CE_MIND, 1)) + to_chat(usr, SPAN_WARNING("Chemicals in your blood prevent you from using your power!")) + + var/list/creatures = list() + for(var/mob/living/creature in SSmobs.mob_list) + creatures += creature + creatures -= usr + var/mob/target = input("Who do you want to project your mind to?") as null|anything in creatures + if (isnull(target)) + return + + var/msg = sanitize(input(usr, "What do you wish to transmit")) + show_message(SPAN_NOTICE("You project your mind into [target.name]: \"[msg]\"")) + if(!stat && prob(20)) + say(msg) diff --git a/code/modules/holidays/_holiday.dm b/code/modules/holidays/_holiday.dm index 511c052801d1..ed04429c9550 100644 --- a/code/modules/holidays/_holiday.dm +++ b/code/modules/holidays/_holiday.dm @@ -1,4 +1,4 @@ -var/datum/holiday/current_holiday +var/global/datum/holiday/current_holiday /datum/holiday var/name @@ -25,10 +25,8 @@ var/datum/holiday/current_holiday /proc/set_holiday_data(var/datum/holiday/holiday_data, var/refresh_station_name = FALSE) if(istext(holiday_data)) holiday_data = new(list("name" = holiday_data)) - if(!holiday_data || !istype(holiday_data)) - return - global.current_holiday = holiday_data + if(istype(holiday_data)) + global.current_holiday = holiday_data if(refresh_station_name) - GLOB.using_map.station_name = null - station_name() + global.using_map.station_name = initial(global.using_map.station_name) world.update_status() diff --git a/code/modules/holidays/holiday_hook.dm b/code/modules/holidays/holiday_hook.dm index 595f9a663b7f..231c1a056fdf 100644 --- a/code/modules/holidays/holiday_hook.dm +++ b/code/modules/holidays/holiday_hook.dm @@ -1,27 +1,32 @@ -//Uncommenting ALLOW_HOLIDAYS in config.txt will enable this hook. -/hook/startup/proc/updateHoliday() - if(config?.allow_holidays && fexists("config/holidays.json")) - var/list/holidays = cached_json_decode(file2text("config/holidays.json")) - if(length(holidays)) +/proc/update_holiday() - var/c_year = text2num(time2text(world.timeofday, "YY")) - var/c_month = text2num(time2text(world.timeofday, "MM")) - var/c_day = text2num(time2text(world.timeofday, "DD")) - var/c_weekday = lowertext(time2text(world.timeofday, "DDD")) + if(!get_config_value(/decl/config/toggle/allow_holidays)) + set_holiday_data(null, TRUE) + return FALSE - for(var/list/holiday_data in holidays) + var/list/holidays = cached_json_decode(safe_file2text("config/holidays.json"), FALSE) + if(!length(holidays)) + set_holiday_data(null, TRUE) + return FALSE - var/h_year = holiday_data["year"] - var/h_month = holiday_data["month"] - var/h_day = holiday_data["day"] - var/h_weekday = holiday_data["weekday"] + var/c_year = text2num(time2text(world.timeofday, "YY")) + var/c_month = text2num(time2text(world.timeofday, "MM")) + var/c_day = text2num(time2text(world.timeofday, "DD")) + var/c_weekday = lowertext(time2text(world.timeofday, "DDD")) - if((isnull(h_year) || h_year == c_year) && \ - (isnull(h_month) || h_month == c_month) && \ - (isnull(h_day) || h_day == c_day) && \ - (isnull(h_weekday) || h_weekday == c_weekday)) - var/holiday_path = text2path(holiday_data["path"]) || /datum/holiday - set_holiday_data(new holiday_path(holiday_data)) - break + for(var/list/holiday_data in holidays) - return 1 \ No newline at end of file + var/h_year = holiday_data["year"] + var/h_month = holiday_data["month"] + var/h_day = holiday_data["day"] + var/h_weekday = holiday_data["weekday"] + + if((isnull(h_year) || h_year == c_year) && \ + (isnull(h_month) || h_month == c_month) && \ + (isnull(h_day) || h_day == c_day) && \ + (isnull(h_weekday) || h_weekday == c_weekday)) + var/holiday_path = text2path(holiday_data["path"]) || /datum/holiday + set_holiday_data(new holiday_path(holiday_data)) + return TRUE + + return FALSE diff --git a/code/modules/holidays/holiday_name.dm b/code/modules/holidays/holiday_name.dm index b682a49162a6..e07e9776a403 100644 --- a/code/modules/holidays/holiday_name.dm +++ b/code/modules/holidays/holiday_name.dm @@ -5,11 +5,13 @@ set category = "Fun" set desc = "Override the default holiday." - if(!check_rights(R_SERVER)) + if(!check_rights(R_SERVER)) return T = sanitize(T, MAX_NAME_LEN) if(T) + if(get_config_value(/decl/config/toggle/allow_holidays)) + set_config_value(/decl/config/toggle/allow_holidays, TRUE) set_holiday_data(T, refresh_station_name = TRUE) to_world("

          [global.current_holiday.announcement]

          ") message_admins(SPAN_NOTICE("ADMIN: Event: [key_name(src)] force-set the holiday to \"[global.current_holiday.name]\"")) diff --git a/code/modules/holidays/holiday_special.dm b/code/modules/holidays/holiday_special.dm index 37890e6251ad..375c6a3d9f86 100644 --- a/code/modules/holidays/holiday_special.dm +++ b/code/modules/holidays/holiday_special.dm @@ -1,11 +1,12 @@ -/datum/holiday/christmas/New() - ..() +/datum/holiday/christmas announcement = "Merry Christmas, everyone!" /datum/holiday/christmas/set_up_holiday() - for(var/obj/structure/flora/tree/pine/xmas in world) - if(isNotStationLevel(xmas.z)) + for(var/obj/structure/flora/tree/pine/xmas/crimmas_tree in global.christmas_trees) + if(isNotStationLevel(crimmas_tree.z)) continue - for(var/turf/simulated/floor/T in orange(1,xmas)) - for(var/i=1,i<=rand(1,5),i++) + for(var/turf/T in orange(1, crimmas_tree)) + if(!T.is_floor() || !T.simulated) + continue + for(var/i = 1 to rand(1,5)) new /obj/item/a_gift(T) diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index 819a60134ba5..f5db252b01db 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -1,15 +1,14 @@ -/obj/machinery/computer/HolodeckControl +/obj/machinery/computer/holodeck_control name = "holodeck control console" desc = "A computer used to control a nearby holodeck." icon_keyboard = "tech_key" icon_screen = "holocontrol" - var/lock_access = list(access_bridge) - var/islocked = 0 - active_power_usage = 8000 //8kW for the scenery + 500W per holoitem + var/lock_access = list(access_bridge) + var/islocked = 0 var/item_power_usage = 500 - + // TODO: some way to update this when the circuit is spawned rather than created from dismantling a console. var/area/linkedholodeck = null var/linkedholodeck_area var/active = 0 @@ -24,27 +23,27 @@ var/list/supported_programs = list() var/list/restricted_programs = list() -/obj/machinery/computer/HolodeckControl/Initialize() +/obj/machinery/computer/holodeck_control/Initialize() . = ..() linkedholodeck = locate(linkedholodeck_area) - if (programs_list_id in GLOB.using_map.holodeck_supported_programs) - supported_programs |= GLOB.using_map.holodeck_supported_programs[programs_list_id] - if (programs_list_id in GLOB.using_map.holodeck_restricted_programs) - restricted_programs |= GLOB.using_map.holodeck_restricted_programs[programs_list_id] + if (programs_list_id in global.using_map.holodeck_supported_programs) + supported_programs |= global.using_map.holodeck_supported_programs[programs_list_id] + if (programs_list_id in global.using_map.holodeck_restricted_programs) + restricted_programs |= global.using_map.holodeck_restricted_programs[programs_list_id] -/obj/machinery/computer/HolodeckControl/interface_interact(var/mob/user) +/obj/machinery/computer/holodeck_control/interface_interact(var/mob/user) interact(user) return TRUE -/obj/machinery/computer/HolodeckControl/interact(var/mob/user) +/obj/machinery/computer/holodeck_control/interact(var/mob/user) user.set_machine(src) var/dat dat += "Holodeck Control System
          " if(!islocked) - dat += "Holodeck is (UNLOCKED)
          " + dat += "Holodeck is (UNLOCKED)
          " else - dat += "Holodeck is (LOCKED)
          " + dat += "Holodeck is (LOCKED)
          " show_browser(user, dat, "window=computer;size=400x500") onclose(user, "computer") return @@ -64,10 +63,10 @@ return for(var/prog in supported_programs) - dat += "([prog])
          " + dat += "([prog])
          " dat += "
          " - dat += "(Turn Off)
          " + dat += "(Turn Off)
          " dat += "
          " dat += "Please ensure that only holographic weapons are used in the holodeck if a combat simulation has been loaded.
          " @@ -78,15 +77,15 @@ if (emagged) dat += "ERROR: Cannot re-enable Safety Protocols.
          " else - dat += "(Re-Enable Safety Protocols?)
          " + dat += "(Re-Enable Safety Protocols?)
          " else - dat += "(Override Safety Protocols?)
          " + dat += "(Override Safety Protocols?)
          " dat += "
          " if(safety_disabled) for(var/prog in restricted_programs) - dat += "(Begin [prog])
          " + dat += "(Begin [prog])
          " dat += "Ensure the holodeck is empty before testing.
          " dat += "
          " dat += "Safety Protocols are DISABLED
          " @@ -94,49 +93,46 @@ dat += "Safety Protocols are ENABLED
          " if(linkedholodeck.has_gravity) - dat += "Gravity is (ON)
          " + dat += "Gravity is (ON)
          " else - dat += "Gravity is (OFF)
          " + dat += "Gravity is (OFF)
          " show_browser(user, dat, "window=computer;size=400x500") onclose(user, "computer") return -/obj/machinery/computer/HolodeckControl/Topic(href, href_list) - if(..()) - return 1 - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - - if(href_list["program"]) - var/prog = href_list["program"] - if(prog in GLOB.using_map.holodeck_programs) - loadProgram(GLOB.using_map.holodeck_programs[prog]) - - else if(href_list["AIoverride"]) - if(!issilicon(usr)) - return +/obj/machinery/computer/holodeck_control/OnTopic(mob/user, href_list) + if((. = ..())) + return + if(href_list["program"]) + var/prog = href_list["program"] + if(prog in global.using_map.holodeck_programs) + loadProgram(global.using_map.holodeck_programs[prog]) + . = TOPIC_REFRESH - if(safety_disabled && emagged) - return //if a traitor has gone through the trouble to emag the thing, let them keep it. + else if(href_list["AIoverride"]) + if(!issilicon(usr)) + return TOPIC_HANDLED - safety_disabled = !safety_disabled - update_projections() - if(safety_disabled) - log_and_message_admins("overrode the holodeck's safeties") - else - log_and_message_admins("restored the holodeck's safeties") + if(safety_disabled && emagged) + return TOPIC_HANDLED //if a traitor has gone through the trouble to emag the thing, let them keep it. - else if(href_list["gravity"]) - toggleGravity(linkedholodeck) + safety_disabled = !safety_disabled + update_projections() + if(safety_disabled) + log_and_message_admins("overrode the holodeck's safeties") + else + log_and_message_admins("restored the holodeck's safeties") + . = TOPIC_REFRESH - else if(href_list["togglehololock"]) - togglelock(usr) + else if(href_list["gravity"]) + toggleGravity(linkedholodeck) + . = TOPIC_REFRESH - src.add_fingerprint(usr) - src.updateUsrDialog() - return + else if(href_list["togglehololock"]) + togglelock(usr) + . = TOPIC_REFRESH -/obj/machinery/computer/HolodeckControl/emag_act(var/remaining_charges, var/mob/user) +/obj/machinery/computer/holodeck_control/emag_act(var/remaining_charges, var/mob/user) playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1) last_to_emag = user //emag again to change the owner if (!emagged) @@ -144,43 +140,47 @@ safety_disabled = 1 update_projections() to_chat(user, "You vastly increase projector power and override the safety and security protocols.") - to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call [GLOB.using_map.company_name] maintenance and do not use the simulator.") - log_game("[key_name(usr)] emagged the Holodeck Control Computer") + to_chat(user, "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call [global.using_map.company_name] maintenance and do not use the simulator.") + log_game("[key_name(user)] emagged the Holodeck Control Computer") src.updateUsrDialog() return 1 else ..() -/obj/machinery/computer/HolodeckControl/proc/update_projections() +/obj/machinery/computer/holodeck_control/proc/update_projections() if (safety_disabled) item_power_usage = 2500 for(var/obj/item/holo/esword/H in linkedholodeck) - H.damtype = BRUTE + H.atom_damage_type = BRUTE else item_power_usage = initial(item_power_usage) for(var/obj/item/holo/esword/H in linkedholodeck) - H.damtype = initial(H.damtype) + H.atom_damage_type = initial(H.atom_damage_type) for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs) C.set_safety(!safety_disabled) if (last_to_emag) - C.friends = list(weakref(last_to_emag)) + C.ai?.set_friends(list(weakref(last_to_emag))) //This could all be done better, but it works for now. -/obj/machinery/computer/HolodeckControl/Destroy() +/obj/machinery/computer/holodeck_control/Destroy() emergencyShutdown() . = ..() -/obj/machinery/computer/HolodeckControl/explosion_act(severity) +/obj/machinery/computer/holodeck_control/explosion_act(severity) emergencyShutdown() . = ..() -/obj/machinery/computer/HolodeckControl/power_change() +/obj/machinery/computer/holodeck_control/power_change() . = ..() if (. && active && (stat & NOPOWER)) emergencyShutdown() -/obj/machinery/computer/HolodeckControl/Process() +/obj/machinery/computer/holodeck_control/Process() + + if(!linkedholodeck) + return + for(var/item in holographic_objs) // do this first, to make sure people don't take items out when power is down. if(!(get_turf(item) in linkedholodeck)) derez(item, 0) @@ -198,22 +198,18 @@ if(!checkInteg(linkedholodeck)) damaged = 1 - loadProgram(GLOB.using_map.holodeck_programs["turnoff"], 0) + loadProgram(global.using_map.holodeck_programs[global.using_map.holodeck_default_program[programs_list_id] || "turnoff"], 0) active = 0 update_use_power(POWER_USE_IDLE) - for(var/mob/M in range(10,src)) - M.show_message("The holodeck overloads!") - + visible_message("The holodeck overloads!", null, "You hear electricity arcing!", range = 10) for(var/turf/T in linkedholodeck) if(prob(30)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, T) - s.start() + spark_at(T, amount=2, cardinal_only = TRUE) T.explosion_act(3) T.hotspot_expose(1000,500,1) -/obj/machinery/computer/HolodeckControl/proc/derez(var/obj/obj , var/silent = 1) +/obj/machinery/computer/holodeck_control/proc/derez(var/obj/obj , var/silent = 1) holographic_objs.Remove(obj) if(obj == null) @@ -224,19 +220,19 @@ visible_message("The [oldobj.name] fades away!") qdel(obj) -/obj/machinery/computer/HolodeckControl/proc/checkInteg(var/area/A) +/obj/machinery/computer/holodeck_control/proc/checkInteg(var/area/A) for(var/turf/T in A) - if(istype(T, /turf/space)) + if(isspaceturf(T)) return 0 return 1 //Why is it called toggle if it doesn't toggle? -/obj/machinery/computer/HolodeckControl/proc/togglePower(var/toggleOn = 0) +/obj/machinery/computer/holodeck_control/proc/togglePower(var/toggleOn = 0) if(toggleOn) - loadProgram(GLOB.using_map.holodeck_programs["emptycourt"], 0) + loadProgram(global.using_map.holodeck_programs[global.using_map.holodeck_default_program[programs_list_id] || "emptycourt"], 0) else - loadProgram(GLOB.using_map.holodeck_programs["turnoff"], 0) + loadProgram(global.using_map.holodeck_programs[global.using_map.holodeck_default_program[programs_list_id] || "turnoff"], 0) if(!linkedholodeck.has_gravity) linkedholodeck.gravitychange(1) @@ -245,9 +241,11 @@ update_use_power(POWER_USE_IDLE) -/obj/machinery/computer/HolodeckControl/proc/loadProgram(var/datum/holodeck_program/HP, var/check_delay = 1) - if(!HP) +/obj/machinery/computer/holodeck_control/proc/loadProgram(var/datum/holodeck_program/HP, var/check_delay = 1) + + if(!HP || !istype(linkedholodeck)) return + var/area/A = locate(HP.target) if(!A) return @@ -256,10 +254,9 @@ if(world.time < (last_change + 25)) if(world.time < (last_change + 15))//To prevent super-spam clicking, reduced process size and annoyance -Sieve return - for(var/mob/M in range(3,src)) - M.show_message("ERROR. Recalibrating projection apparatus.") - last_change = world.time - return + visible_message(SPAN_WARNING("ERROR. Recalibrating projection apparatus."), range = 3) + last_change = world.time + return last_change = world.time active = 1 @@ -292,13 +289,11 @@ linkedholodeck.sound_env = A.sound_env spawn(30) - for(var/obj/effect/landmark/L in linkedholodeck) + for(var/obj/abstract/landmark/L in linkedholodeck) if(L.name=="Atmospheric Test Start") spawn(20) var/turf/T = get_turf(L) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, T) - s.start() + spark_at(T, amount=2, cardinal_only = TRUE) if(T) T.temperature = 5000 T.hotspot_expose(50000,50000,1) @@ -312,14 +307,18 @@ update_projections() -/obj/machinery/computer/HolodeckControl/proc/toggleGravity(var/area/A) +/obj/machinery/computer/holodeck_control/proc/toggleGravity(var/area/A) + + if(!istype(A)) + visible_message(SPAN_WARNING("ERROR. Cannot locate holodeck systems."), range = 3) + return + if(world.time < (last_gravity_change + 25)) if(world.time < (last_gravity_change + 15))//To prevent super-spam clicking return - for(var/mob/M in range(3,src)) - M.show_message("ERROR. Recalibrating gravity field.") - last_change = world.time - return + visible_message(SPAN_WARNING("ERROR. Recalibrating gravity field."), range = 3) + last_change = world.time + return last_gravity_change = world.time active = 1 @@ -330,11 +329,11 @@ else A.gravitychange(1,A) -/obj/machinery/computer/HolodeckControl/proc/emergencyShutdown() +/obj/machinery/computer/holodeck_control/proc/emergencyShutdown() //Turn it back to the regular non-holographic room - loadProgram(GLOB.using_map.holodeck_programs["turnoff"], 0) + loadProgram(global.using_map.holodeck_programs[global.using_map.holodeck_default_program[programs_list_id] || "turnoff"], 0) - if(!linkedholodeck.has_gravity) + if(linkedholodeck && !linkedholodeck.has_gravity) linkedholodeck.gravitychange(1,linkedholodeck) active = 0 @@ -342,7 +341,7 @@ // Locking system -/obj/machinery/computer/HolodeckControl/proc/togglelock(var/mob/user) +/obj/machinery/computer/holodeck_control/proc/togglelock(var/mob/user) if(cantogglelock(user)) islocked = !islocked audible_message("\The [src] emits a series of beeps to announce it has been [islocked ? null : "un"]locked.", hearing_distance = 3) @@ -351,5 +350,5 @@ to_chat(user, "Access denied.") return 1 -/obj/machinery/computer/HolodeckControl/proc/cantogglelock(var/mob/user) +/obj/machinery/computer/holodeck_control/proc/cantogglelock(var/mob/user) return has_access(lock_access, user.GetAccess()) \ No newline at end of file diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index 5104c6f5ff87..407b1b196dad 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -3,166 +3,140 @@ // Holographic tables are in code/modules/tables/presets.dm // Holographic racks are in code/modules/tables/rack.dm -/turf/simulated/floor/holofloor +/turf/floor/holofloor thermal_conductivity = 0 -/turf/simulated/floor/holofloor/get_lumcount(var/minlum = 0, var/maxlum = 1) +/turf/floor/holofloor/get_lumcount(var/minlum = 0, var/maxlum = 1) return 0.8 -/turf/simulated/floor/holofloor/attackby(obj/item/W, mob/user) - return +/turf/floor/holofloor/attackby(obj/item/used_item, mob/user) + return TRUE // HOLOFLOOR DOES NOT GIVE A FUCK -/turf/simulated/floor/holofloor/set_flooring() - return - -/turf/simulated/floor/holofloor/carpet - name = "brown carpet" - icon = 'icons/turf/flooring/carpet.dmi' - icon_state = "brown" - initial_flooring = /decl/flooring/carpet - -/turf/simulated/floor/holofloor/concrete - name = "brown carpet" - icon = 'icons/turf/flooring/carpet.dmi' - icon_state = "brown" - initial_flooring = /decl/flooring/carpet - -/turf/simulated/floor/holofloor/concrete - name = "floor" - icon = 'icons/turf/flooring/misc.dmi' - icon_state = "concrete" - initial_flooring = null - -/turf/simulated/floor/holofloor/tiled - name = "floor" - icon = 'icons/turf/flooring/tiles.dmi' - icon_state = "steel" - initial_flooring = /decl/flooring/tiling - -/turf/simulated/floor/holofloor/tiled/dark - name = "dark floor" - icon_state = "dark" - initial_flooring = /decl/flooring/tiling/dark - -/turf/simulated/floor/holofloor/tiled/stone - name = "stone floor" - icon_state = "stone" - initial_flooring = /decl/flooring/tiling/stone - -/turf/simulated/floor/holofloor/lino - name = "lino" - icon = 'icons/turf/flooring/linoleum.dmi' - icon_state = "lino" - initial_flooring = /decl/flooring/linoleum - -/turf/simulated/floor/holofloor/wood - name = "wooden floor" - icon = 'icons/turf/flooring/wood.dmi' - icon_state = "wood" - color = WOOD_COLOR_CHOCOLATE - initial_flooring = /decl/flooring/wood - -/turf/simulated/floor/holofloor/grass - name = "lush grass" - icon = 'icons/turf/flooring/grass.dmi' - icon_state = "grass0" - initial_flooring = /decl/flooring/grass - -/turf/simulated/floor/holofloor/snow - name = "snow" - base_name = "snow" - icon = 'icons/turf/floors.dmi' - base_icon = 'icons/turf/floors.dmi' - icon_state = "snow" - base_icon_state = "snow" - -/turf/simulated/floor/holofloor/space - icon = 'icons/turf/space.dmi' - name = "\proper space" - icon_state = "0" - -/turf/simulated/floor/holofloor/reinforced - icon = 'icons/turf/flooring/tiles.dmi' - initial_flooring = /decl/flooring/reinforced - name = "reinforced holofloor" - icon_state = "reinforced" - -/turf/simulated/floor/holofloor/space/Initialize() - . = ..() - icon_state = "[((x + y) ^ ~(x * y) + z) % 25]" - -/turf/simulated/floor/holofloor/beach - desc = "Uncomfortably gritty for a hologram." - base_desc = "Uncomfortably gritty for a hologram." - icon = 'icons/misc/beach.dmi' - base_icon = 'icons/misc/beach.dmi' - initial_flooring = null - -/turf/simulated/floor/holofloor/beach/sand - name = "sand" - icon_state = "desert0" - base_icon_state = "desert0" - -/turf/simulated/floor/holofloor/beach/coastline - name = "coastline" - icon = 'icons/misc/beach2.dmi' - icon_state = "sandwater" - base_icon_state = "sandwater" - -/turf/simulated/floor/holofloor/beach/water - name = "water" - icon_state = "seashallow" - base_icon_state = "seashallow" - -/turf/simulated/floor/holofloor/desert - name = "desert sand" - base_name = "desert sand" - desc = "Uncomfortably gritty for a hologram." - base_desc = "Uncomfortably gritty for a hologram." - icon_state = "asteroid" - base_icon_state = "asteroid" - icon = 'icons/turf/flooring/asteroid.dmi' - base_icon = 'icons/turf/flooring/asteroid.dmi' - initial_flooring = null - -/turf/simulated/floor/holofloor/desert/Initialize(var/ml) +/turf/floor/holofloor/carpet + name = "brown carpet" + icon = 'icons/turf/flooring/carpet.dmi' + icon_state = "brown" + _flooring = /decl/flooring/carpet + +/turf/floor/holofloor/concrete + name = "brown carpet" + icon = 'icons/turf/flooring/carpet.dmi' + icon_state = "brown" + _flooring = /decl/flooring/carpet + +/turf/floor/holofloor/concrete + name = "floor" + icon = 'icons/turf/flooring/misc.dmi' + icon_state = "concrete" + _flooring = null + +/turf/floor/holofloor/tiled + name = "floor" + icon = 'icons/turf/flooring/tiles.dmi' + icon_state = "steel" + _flooring = /decl/flooring/tiling + +/turf/floor/holofloor/tiled/dark + name = "dark floor" + icon_state = "dark" + _flooring = /decl/flooring/tiling/dark + +/turf/floor/holofloor/tiled/stone + name = "stone floor" + icon_state = "stone" + _flooring = /decl/flooring/tiling/stone + +/turf/floor/holofloor/lino + name = "lino" + icon = 'icons/turf/flooring/linoleum.dmi' + icon_state = "lino" + _flooring = /decl/flooring/linoleum + +/turf/floor/holofloor/wood + name = "wooden floor" + icon = 'icons/turf/flooring/wood.dmi' + icon_state = "wood0" + color = WOOD_COLOR_CHOCOLATE + _flooring = /decl/flooring/wood + +/turf/floor/holofloor/grass + name = "lush grass" + icon = 'icons/turf/flooring/fakegrass.dmi' + icon_state = "grass0" + _flooring = /decl/flooring/grass/fake + +/turf/floor/holofloor/snow + name = "snow" + icon = 'icons/turf/flooring/snow.dmi' + icon_state = "snow0" + _flooring = /decl/flooring/snow/fake + +/turf/floor/holofloor/space + name = "\proper space" + icon = 'icons/turf/flooring/fake_space.dmi' + icon_state = "space0" + _flooring = /decl/flooring/fake_space + +/turf/floor/holofloor/reinforced + name = "reinforced holofloor" + icon = 'icons/turf/flooring/tiles.dmi' + _flooring = /decl/flooring/reinforced + icon_state = "reinforced" + +/turf/floor/holofloor/beach + desc = "Uncomfortably gritty for a hologram." + icon = 'icons/misc/beach.dmi' + _flooring = /decl/flooring/sand/fake + abstract_type = /turf/floor/holofloor/beach + +/turf/floor/holofloor/beach/sand + name = "sand" + icon_state = "desert0" + +/turf/floor/holofloor/beach/coastline + name = "coastline" + icon = 'icons/misc/beach2.dmi' + icon_state = "sandwater" + _flooring = /decl/flooring/sand/fake + +/turf/floor/holofloor/beach/water + name = "water" + icon_state = "seashallow" + _flooring = /decl/flooring/fake_water + +/turf/floor/holofloor/desert + name = "desert sand" + desc = "Uncomfortably gritty for a hologram." + icon = 'icons/turf/flooring/barren.dmi' + icon_state = "barren" + _flooring = /decl/flooring/sand/fake + +/turf/floor/holofloor/desert/Initialize(var/ml) . = ..() if(prob(10)) - overlays += "asteroid[rand(0,9)]" + LAZYADD(decals, image('icons/turf/flooring/decals.dmi', "asteroid[rand(0,9)]")) /obj/structure/holostool - name = "stool" - desc = "Apply butt." - icon = 'icons/obj/furniture.dmi' - icon_state = "stool_padded_preview" - anchored = 1.0 + name = "stool" + desc = "Apply butt." + icon = 'icons/obj/furniture.dmi' + icon_state = "stool_padded_preview" + anchored = TRUE /obj/item/clothing/gloves/boxing/hologlove - name = "boxing gloves" - desc = "Because you really needed another excuse to punch your crewmates." - -/obj/structure/window/holowindow/full - dir = NORTHEAST - icon_state = "window_full" + name = "boxing gloves" + desc = "Because you really needed another excuse to punch your crewmates." -/obj/structure/window/reinforced/holowindow/attackby(obj/item/W, mob/user) +/obj/structure/window/reinforced/holowindow/full + dir = NORTHEAST + icon_state = "rwindow_full" - if(!istype(W) || W.item_flags & ITEM_FLAG_NO_BLUDGEON) return - - if(isScrewdriver(W) || isCrowbar(W) || isWrench(W)) - to_chat(user, ("It's a holowindow, you can't dismantle it!")) - else - if(W.damtype == BRUTE || W.damtype == BURN) - hit(W.force) - if(health <= 7) - anchored = 0 - update_nearby_icons() - step(src, get_dir(user, src)) - else - playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) - ..() - return +/obj/structure/window/reinforced/holowindow/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item) || IS_CROWBAR(used_item) || IS_WRENCH(used_item)) + to_chat(user, SPAN_NOTICE("It's a holowindow, you can't dismantle it!")) + return TRUE + return bash(used_item, user) /obj/structure/window/reinforced/holowindow/shatter(var/display_message = 1) playsound(src, "shatter", 70, 1) @@ -171,64 +145,68 @@ qdel(src) return +// This subtype is deleted when a ready button in the same area is pressed. /obj/structure/window/reinforced/holowindow/disappearing -/obj/machinery/door/window/holowindoor/attackby(obj/item/I, mob/user) +/obj/machinery/door/window/holowindoor/attackby(obj/item/used_item, mob/user) if (src.operating == 1) - return + return TRUE - if(src.density && istype(I, /obj/item) && !istype(I, /obj/item/card)) - var/aforce = I.force + if(src.density && istype(used_item, /obj/item) && !istype(used_item, /obj/item/card)) playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - visible_message("\The [src] was hit by \the [I].") - if(I.damtype == BRUTE || I.damtype == BURN) - take_damage(aforce) - return + visible_message("\The [src] was hit by \the [used_item].") + if(used_item.atom_damage_type == BRUTE || used_item.atom_damage_type == BURN) + take_damage(used_item.expend_attack_force(user)) + return TRUE src.add_fingerprint(user) - if (!src.requiresID()) - user = null - if (src.allowed(user)) if (src.density) open() else close() + return TRUE else if (src.density) - flick(text("[]deny", src.base_state), src) - - return + flick("[base_state]deny", src) + return TRUE + return FALSE -/obj/machinery/door/window/holowindoor/shatter(var/display_message = 1) - src.set_density(0) - playsound(src, "shatter", 70, 1) +/obj/machinery/door/window/holowindoor/shatter(var/display_message = TRUE) + set_density(FALSE) + playsound(loc, "shatter", 70, TRUE) if(display_message) visible_message("[src] fades away as it shatters!") - qdel(src) + animate(src, 0.5 SECONDS, alpha = 0) + QDEL_IN_CLIENT_TIME(src, 0.5 SECONDS) -/obj/structure/bed/chair/holochair/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/wrench)) - to_chat(user, ("It's a holochair, you can't dismantle it!")) - return +/obj/structure/bed/holobed + tool_interaction_flags = 0 + holographic = TRUE + material = /decl/material/solid/metal/aluminium/holographic + +/obj/structure/chair/holochair + tool_interaction_flags = 0 + holographic = TRUE + material = /decl/material/solid/metal/aluminium/holographic /obj/item/holo - damtype = PAIN + atom_damage_type = PAIN no_attack_log = 1 + max_health = ITEM_HEALTH_NO_DAMAGE /obj/item/holo/esword name = "holosword" desc = "May the force be within you. Sorta." icon = 'icons/obj/items/weapon/e_sword.dmi' icon_state = "sword0" - force = 3.0 throw_speed = 1 throw_range = 5 - throwforce = 0 w_class = ITEM_SIZE_SMALL - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_BLOOD + atom_flags = ATOM_FLAG_NO_BLOOD base_parry_chance = 50 + _base_attack_force = 3 var/active = 0 var/item_color @@ -241,9 +219,7 @@ /obj/item/holo/esword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") . = ..() if(.) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, user.loc) - spark_system.start() + spark_at(user.loc, amount=5) playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) /obj/item/holo/esword/get_parry_chance(mob/user) @@ -253,16 +229,16 @@ . = ..() item_color = pick("red","blue","green","purple") -/obj/item/holo/esword/attack_self(mob/living/user) +/obj/item/holo/esword/attack_self(mob/user) active = !active if (active) - force = 30 + set_base_attack_force(30) icon_state = "sword[item_color]" w_class = ITEM_SIZE_HUGE playsound(user, 'sound/weapons/saberon.ogg', 50, 1) to_chat(user, "[src] is now active.") else - force = 3 + set_base_attack_force(3) icon_state = "sword0" w_class = ITEM_SIZE_SMALL playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) @@ -274,55 +250,37 @@ return //BASKETBALL OBJECTS - -/obj/item/beach_ball/holoball - icon = 'icons/obj/basketball.dmi' - icon_state = "basketball" - name = "basketball" - item_state = "basketball" - desc = "Here's your chance, do your dance at the Space Jam." - w_class = ITEM_SIZE_LARGE //Stops people from hiding it in their pockets - /obj/structure/holohoop name = "basketball hoop" desc = "Boom, Shakalaka!" - icon = 'icons/obj/basketball.dmi' + icon = 'icons/obj/structures/basketball.dmi' icon_state = "hoop" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE throwpass = 1 /obj/structure/holohoop/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if (istype(mover,/obj/item) && mover.throwing) - var/obj/item/I = mover - if(istype(I, /obj/item/projectile)) + var/obj/item/thing = mover + if(istype(thing, /obj/item/projectile)) return if(prob(50)) - I.dropInto(loc) - visible_message("Swish! \the [I] lands in \the [src].", range = 3) + thing.dropInto(loc) + visible_message("Swish! \the [thing] lands in \the [src].", range = 3) else - visible_message("\The [I] bounces off of \the [src]'s rim!", range = 3) + visible_message("\The [thing] bounces off of \the [src]'s rim!", range = 3) return 0 else return ..(mover, target, height, air_group) //VOLEYBALL OBJECTS - -/obj/item/beach_ball/holovolleyball - icon = 'icons/obj/basketball.dmi' - icon_state = "volleyball" - name = "voleyball" - item_state = "volleyball" - desc = "You can be my wingman anytime." - w_class = ITEM_SIZE_LARGE //Stops people from hiding it in their pockets - /obj/structure/holonet name = "net" desc = "Bullshit, you can be mine!" - icon = 'icons/obj/basketball.dmi' + icon = 'icons/obj/structures/volleyball.dmi' icon_state = "volleynet_mid" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE layer = TABLE_LAYER throwpass = 1 dir = EAST @@ -332,12 +290,12 @@ /obj/structure/holonet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if (istype(mover,/obj/item) && mover.throwing) - var/obj/item/I = mover - if(istype(I, /obj/item/projectile)) + var/obj/item/thing = mover + if(istype(thing, /obj/item/projectile)) return if(prob(10)) - I.dropInto(loc) - visible_message("Swish! \the [I] gets caught in \the [src].", range = 3) + thing.dropInto(loc) + visible_message("Swish! \the [thing] gets caught in \the [src].", range = 3) return 0 else return 1 @@ -353,17 +311,18 @@ var/area/currentarea = null var/eventstarted = 0 - anchored = 1.0 + anchored = TRUE idle_power_usage = 2 active_power_usage = 6 power_channel = ENVIRON -/obj/machinery/readybutton/attack_ai(mob/user) +/obj/machinery/readybutton/attack_ai(mob/living/silicon/ai/user) to_chat(user, "The AI is not to interact with these devices!") return -/obj/machinery/readybutton/attackby(obj/item/W, mob/user) +/obj/machinery/readybutton/attackby(obj/item/used_item, mob/user) to_chat(user, "The device is a solid button, there's nothing you can do with it!") + return TRUE /obj/machinery/readybutton/physical_attack_hand(mob/user) currentarea = get_area(src) @@ -400,8 +359,8 @@ eventstarted = 1 - for(var/obj/structure/window/reinforced/holowindow/disappearing/W in currentarea) - qdel(W) + for(var/obj/structure/window/reinforced/holowindow/disappearing/window in currentarea) + qdel(window) for(var/mob/M in currentarea) to_chat(M, "FIGHT!") @@ -409,38 +368,47 @@ //Holocarp /mob/living/simple_animal/hostile/carp/holodeck - icon = 'icons/mob/hologram.dmi' - icon_state = "Carp" - icon_living = "Carp" - icon_dead = "Carp" + icon = 'icons/mob/simple_animal/holocarp.dmi' alpha = 127 - icon_gib = null - meat_amount = 0 - meat_type = null + butchery_data = null /mob/living/simple_animal/hostile/carp/holodeck/carp_randomify() return /mob/living/simple_animal/hostile/carp/holodeck/on_update_icon() + SHOULD_CALL_PARENT(FALSE) return /mob/living/simple_animal/hostile/carp/holodeck/Initialize() . = ..() - set_light(0.5, 0.1, 2) //hologram lighting + set_light(2) //hologram lighting /mob/living/simple_animal/hostile/carp/holodeck/proc/set_safety(var/safe) if (safe) faction = MOB_FACTION_NEUTRAL - natural_weapon.force = 0 + natural_weapon.set_base_attack_force(0) environment_smash = 0 - destroy_surroundings = 0 + ai?.try_destroy_surroundings = FALSE else faction = "carp" - natural_weapon.force = initial(natural_weapon.force) + natural_weapon.set_base_attack_force(natural_weapon.get_initial_base_attack_force()) + +/mob/living/simple_animal/hostile/carp/holodeck/gib(do_gibs = TRUE) + SHOULD_CALL_PARENT(FALSE) + if(stat != DEAD) + death(gibbed = TRUE) + if(stat == DEAD) + qdel(src) + return TRUE + return FALSE -/mob/living/simple_animal/hostile/carp/holodeck/gib() - death() +/mob/living/simple_animal/hostile/carp/holodeck/get_death_message(gibbed) + return "fades away..." -/mob/living/simple_animal/hostile/carp/holodeck/death() - ..(null, "fades away!", "You have been destroyed.") - qdel(src) \ No newline at end of file +/mob/living/simple_animal/hostile/carp/holodeck/get_self_death_message(gibbed) + return "You have been destroyed." + +/mob/living/simple_animal/hostile/carp/holodeck/death(gibbed) + . = ..() + if(. && !gibbed) + gib() diff --git a/code/modules/holomap/holomap.dm b/code/modules/holomap/holomap.dm new file mode 100644 index 000000000000..8e4b1179e841 --- /dev/null +++ b/code/modules/holomap/holomap.dm @@ -0,0 +1,327 @@ +/obj/machinery/holomap + name = "holomap" + desc = "A screen that projects a map of the surrounding structure." + icon = 'icons/obj/machines/stationmap.dmi' + icon_state = "station_map" + anchored = TRUE + density = FALSE + use_power = POWER_USE_IDLE + idle_power_usage = 10 + active_power_usage = 500 + light_color = "#64c864" + uncreated_component_parts = null + construct_state = /decl/machine_construction/default/panel_closed + base_type = /obj/machinery/holomap + layer = ABOVE_WINDOW_LAYER // Above windows. + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + + var/light_power_on = 1 + var/light_range_on = 2 + var/mob/watching_mob + var/image/small_station_map + var/image/floor_markings + /// z-level on which the station map was initialized. + var/original_zLevel = 1 + /// set to FALSE when you initialize the station map on a zLevel that has its own icon formatted for use by station holomaps. + var/bogus = TRUE + var/datum/station_holomap/holomap_datum + +/obj/machinery/holomap/Destroy() + SSminimap.station_holomaps -= src + stopWatching() + QDEL_NULL(holomap_datum) + return ..() + +/obj/machinery/holomap/Initialize() + if(!loc) + return INITIALIZE_HINT_QDEL + holomap_datum = new() + original_zLevel = loc.z + bogus = FALSE + . = ..() + SSminimap.station_holomaps += src + if(SSminimap.initialized) + update_map_data() + floor_markings = image('icons/obj/machines/stationmap.dmi', "decal_station_map") + floor_markings.dir = src.dir + update_icon() + +/obj/machinery/holomap/proc/update_map_data() + if(!SSminimap.holomaps[original_zLevel]) + bogus = TRUE + holomap_datum.initialize_holomap_bogus() + update_icon() + return + + holomap_datum.initialize_holomap(get_turf(src), reinit = TRUE) + + small_station_map = image(icon = SSminimap.holomaps[original_zLevel].holomap_small) + small_station_map.plane = ABOVE_LIGHTING_PLANE + small_station_map.layer = ABOVE_LIGHTING_LAYER + + update_icon() + +/obj/machinery/holomap/attack_hand(var/mob/user) + if(user.check_intent(I_FLAG_HARM)) + return ..() + if(watching_mob && (watching_mob != user)) + to_chat(user, SPAN_WARNING("Someone else is currently watching the holomap.")) + return TRUE + if(user.loc != loc) + to_chat(user, SPAN_WARNING("You need to stand in front of \the [src].")) + return TRUE + startWatching(user) + return TRUE + +// Let people bump up against it to watch +/obj/machinery/holomap/Bumped(var/atom/movable/AM) + if(!watching_mob && isliving(AM) && AM.loc == loc) + startWatching(AM) + +// In order to actually get Bumped() we need to block movement. We're (visually) on a wall, so people +// couldn't really walk into us anyway. But in reality we are on the turf in front of the wall, so bumping +// against where we seem is actually trying to *exit* our real loc +/obj/machinery/holomap/CheckExit(atom/movable/mover as mob|obj, turf/target as turf) + if(get_dir(target, loc) == dir) // Opposite of "normal" since we are visually in the next turf over + return FALSE + else + return TRUE + +/obj/machinery/holomap/proc/startWatching(var/mob/user) + if(!isliving(user) || !anchored || !operable() || !user.client) + return FALSE + + var/datum/global_hud/global_hud = get_global_hud() + holomap_datum.station_map.loc = global_hud.holomap // Put the image on the holomap hud + holomap_datum.station_map.alpha = 0 // Set to transparent so we can fade in + animate(holomap_datum.station_map, alpha = 255, time = 5, easing = LINEAR_EASING) + flick("station_map_activate", src) + user.client.screen |= global_hud.holomap + user.client.images |= holomap_datum.station_map + + watching_mob = user + events_repository.register(/decl/observ/moved, watching_mob, src, TYPE_PROC_REF(/obj/machinery/holomap, checkPosition)) + events_repository.register(/decl/observ/destroyed, watching_mob, src, TYPE_PROC_REF(/obj/machinery/holomap, stopWatching)) + update_use_power(POWER_USE_ACTIVE) + + if(bogus) + to_chat(user, SPAN_WARNING("The holomap failed to initialize. This area of space cannot be mapped.")) + else + to_chat(user, SPAN_NOTICE("A hologram of your current location appears before your eyes.")) + + START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + +/obj/machinery/holomap/Process() + if(!operable()) + stopWatching() + return PROCESS_KILL + +/obj/machinery/holomap/proc/checkPosition() + if(!watching_mob || (watching_mob.loc != loc) || (dir != watching_mob.dir)) + stopWatching() + +/obj/machinery/holomap/proc/stopWatching() + if(watching_mob) + if(watching_mob.client) + animate(holomap_datum.station_map, alpha = 0, time = 5, easing = LINEAR_EASING) + var/mob/M = watching_mob + addtimer(CALLBACK(src, PROC_REF(clear_image), M, holomap_datum.station_map), 5, TIMER_CLIENT_TIME)//we give it time to fade out + events_repository.unregister(/decl/observ/moved, watching_mob, src) + events_repository.unregister(/decl/observ/destroyed, watching_mob, src) + watching_mob = null + update_use_power(POWER_USE_IDLE) + if(holomap_datum) + holomap_datum.legend_deselect() + +/obj/machinery/holomap/proc/clear_image(mob/M, image/I) + if (M.client) + M.client.images -= I + +/obj/machinery/holomap/on_update_icon() + . = ..() + cut_overlays() + if(stat & BROKEN) + icon_state = "station_mapb" + set_light(0) + else if((stat & NOPOWER) || !anchored) + icon_state = "station_map0" + set_light(0) + else + icon_state = "station_map" + set_light(light_range_on, light_power_on, "#1dbe17") + // Put the little "map" overlay down where it looks nice + if(small_station_map) + add_overlay(small_station_map) + if(floor_markings) + floor_markings.dir = src.dir + floor_markings.pixel_x = -src.pixel_x + floor_markings.pixel_y = -src.pixel_y + add_overlay(floor_markings) + if(panel_open) + add_overlay("station_map-panel") + +/obj/machinery/holomap/explosion_act(severity) + . = ..() + if(!QDELETED(src)) + switch(severity) + if(1) + qdel(src) + if(2) + if(prob(50)) + qdel(src) + else + set_broken() + if(3) + if(prob(25)) + set_broken() + +// Simple datum to keep track of a running holomap. Each machine capable of displaying the holomap will have one. +/datum/station_holomap + var/image/station_map + var/image/cursor + var/list/obj/screen/holomap_legend/legend + var/list/obj/screen/holomap_text/maptexts + var/list/obj/screen/holomap_level_select/lbuttons + var/list/image/levels + var/list/z_levels + var/z = -1 + var/displayed_level = 1 //Index of level to display + +/datum/station_holomap/Destroy(force) + QDEL_NULL(station_map) + QDEL_NULL(cursor) + QDEL_NULL_LIST(legend) + QDEL_NULL_LIST(lbuttons) + QDEL_LIST_ASSOC_VAL(maptexts) + QDEL_LIST_ASSOC_VAL(levels) + LAZYCLEARLIST(maptexts) + LAZYCLEARLIST(levels) + LAZYCLEARLIST(z_levels) + . = ..() + +/datum/station_holomap/proc/initialize_holomap(turf/T, isAI = null, mob/user = null, reinit = FALSE) + z = T.z + if(!cursor || reinit) + cursor = image('icons/misc/holomap_markers.dmi', "you") + cursor.layer = HUD_ABOVE_ITEM_LAYER + + if(!LAZYLEN(legend) || reinit) + QDEL_LIST_ASSOC_VAL(legend) + legend = list( + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_COMMAND, "■ Command"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_SECURITY, "■ Security"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_MEDICAL, "■ Medical"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_SCIENCE, "■ Research"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_EXPLORATION, "■ Exploration"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_ENGINEERING, "■ Engineering"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_CARGO, "■ Supply"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_AIRLOCK, "■ Airlock"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_ESCAPE, "■ Escape"), + new /obj/screen/holomap_legend(null, null, null, null, null, HOLOMAP_AREACOLOR_CREW, "■ Crew"), + new /obj/screen/holomap_legend/cursor(null, null, null, null, null, HOLOMAP_AREACOLOR_BASE, "You are here") + ) + if(reinit) + QDEL_NULL_LIST(lbuttons) + QDEL_LIST_ASSOC_VAL(maptexts) + LAZYCLEARLIST(maptexts) + LAZYCLEARLIST(levels) + LAZYCLEARLIST(z_levels) + + station_map = image(icon(HOLOMAP_ICON, "stationmap")) + station_map.layer = UNDER_HUD_LAYER + + //This is where the fun begins + if(length(global.using_map.overmap_ids)) + var/obj/effect/overmap/visitable/O = global.overmap_sectors[z] + + if(isAI) + T = get_turf(user.client.eye) + cursor.pixel_x = (T.x - 6 + (HOLOMAP_ICON_SIZE / 2) - WORLD_CENTER_X) * PIXEL_MULTIPLIER + HOLOMAP_PIXEL_OFFSET_X(z) + cursor.pixel_y = (T.y - 6 + (HOLOMAP_ICON_SIZE / 2) - WORLD_CENTER_Y) * PIXEL_MULTIPLIER + HOLOMAP_PIXEL_OFFSET_Y(z) + + //For the given z level fetch the related map sector and build the list + if(istype(O)) + var/z_count = length(O.map_z) + var/current_z_index = 1 + z_levels = O.map_z.Copy() + + if(z_count > 1) + if(!LAZYLEN(lbuttons)) + //Add the buttons for switching levels + LAZYADD(lbuttons, new /obj/screen/holomap_level_select/up(null, null, null, null, null, src)) + LAZYADD(lbuttons, new /obj/screen/holomap_level_select/down(null, null, null, null, null, src)) + lbuttons[1].pixel_y = HOLOMAP_MARGIN - 22 + lbuttons[2].pixel_y = HOLOMAP_MARGIN + 5 + lbuttons[1].pixel_x = 254 + lbuttons[2].pixel_x = 196 + + //Each level now has to be built and offset properly. Then stored to be showed later + for(var/level = 1; level <= z_count; level++) + if (z == O.map_z[level]) + current_z_index = level + + //Turfs and walls + var/image/map_image = image(SSminimap.holomaps[O.map_z[level]].holomap_base) + + map_image.color = COLOR_HOLOMAP_HOLOFIER + map_image.layer = HUD_BASE_LAYER + + map_image.pixel_x = (HOLOMAP_ICON_SIZE / 2) - WORLD_CENTER_X + map_image.pixel_y = (HOLOMAP_ICON_SIZE / 2) - WORLD_CENTER_Y + + //Store the image for future use + //LAZYADD(levels, map_image) + LAZYSET(levels, "[O.map_z[level]]", map_image) + + var/obj/screen/holomap_text/maptext_overlay = new(null) + maptext_overlay.maptext = STYLE_SMALLFONTS_OUTLINE("
          LEVEL [level-1]
          ", 7, COLOR_WHITE, COLOR_BLACK) + maptext_overlay.pixel_x = (HOLOMAP_ICON_SIZE / 2) - (maptext_overlay.maptext_width / 2) + maptext_overlay.pixel_y = HOLOMAP_MARGIN + + LAZYSET(maptexts, "[O.map_z[level]]", maptext_overlay) + + //Reset to starting zlevel + set_level(current_z_index) + +/datum/station_holomap/proc/set_level(level) + if(level > z_levels.len) + return + + displayed_level = level + + station_map.overlays.Cut() + station_map.vis_contents.Cut() + + if(z == z_levels[displayed_level]) + station_map.overlays += cursor + + station_map.overlays += LAZYACCESS(levels, "[z_levels[displayed_level]]") + station_map.vis_contents += LAZYACCESS(maptexts, "[z_levels[displayed_level]]") + + //Fix legend position + var/pixel_y = HOLOMAP_LEGEND_Y + for(var/obj/screen/holomap_legend/element in legend) + element.holomap = src + element.pixel_y = pixel_y //Set adjusted pixel y as it will be needed for area placement + element.Setup(z_levels[displayed_level]) + if(element.has_areas) + pixel_y -= 10 + station_map.vis_contents += element + + if(displayed_level > 1) + station_map.vis_contents += lbuttons[1] + + if(displayed_level < z_levels.len) + station_map.vis_contents += lbuttons[2] + +/datum/station_holomap/proc/legend_select(obj/screen/holomap_legend/L) + legend_deselect() + L.Select() + +/datum/station_holomap/proc/legend_deselect() + for(var/obj/screen/holomap_legend/entry in legend) + entry.Deselect() + +/datum/station_holomap/proc/initialize_holomap_bogus() + station_map = image('icons/480x480.dmi', "stationmap") + station_map.overlays |= image('icons/effects/64x64.dmi', "notfound", pixel_x = 7 * WORLD_ICON_SIZE, pixel_y = 7 * WORLD_ICON_SIZE) diff --git a/code/modules/hotloading/_admin.dm b/code/modules/hotloading/_admin.dm new file mode 100644 index 000000000000..b77162258627 --- /dev/null +++ b/code/modules/hotloading/_admin.dm @@ -0,0 +1,10 @@ +/client/proc/reload_secrets() + set name = "Reload Hotloaded Content" + set category = "Debug" + + if(!check_rights(R_SERVER)) + return + + message_admins("[usr] manually reloaded hotloaded content") + SSsecrets.load_content(TRUE) + SSstatistics.add_field_details("admin_verb","SRHC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/hotloading/note.dm b/code/modules/hotloading/note.dm new file mode 100644 index 000000000000..f7c4e40aa31c --- /dev/null +++ b/code/modules/hotloading/note.dm @@ -0,0 +1,57 @@ +/datum/secret_note + var/title + var/text + var/icon + +/datum/secret_note/New(var/list/loaded_data) + + // Load data if supplied. + title = loaded_data["note_title"] || title + text = loaded_data["note_body"] || text + icon = loaded_data["icon"] || icon + + // Grab icon file. + if(loaded_data["_source_dir"] && icon) + icon = SSsecrets.get_file("[loaded_data["_source_dir"]]/[icon]") + +/obj/item/paper/secret_note + is_spawnable_type = FALSE // Don't spawn this manually. + var/secret_key + +/obj/item/paper/secret_note/Initialize() + ..() + return validate_secret() + +/obj/item/paper/secret_note/proc/validate_secret() + var/my_coords = "[x || loc?.x || "NULL"], [y || loc?.y || "NULL"], [z || loc?.z || "NULL"]" + if(!secret_key) + PRINT_STACK_TRACE("No secret_key set on note at [my_coords]!") + return INITIALIZE_HINT_QDEL + var/datum/secret_note/secret = get_secret() + if(!istype(secret)) + PRINT_STACK_TRACE("Invalid or mistyped secret for secret_key [secret_key] on note at [my_coords]!") + return INITIALIZE_HINT_QDEL + return load_secret_data(secret) + +/obj/item/paper/secret_note/proc/get_secret() + return SSsecrets.retrieve_secret(secret_key, /datum/secret_note) + +/obj/item/paper/secret_note/proc/load_secret_data(var/datum/secret_note/secret) + if(!istype(secret)) + return INITIALIZE_HINT_QDEL + if(secret.icon) + icon = secret.icon + if(!check_state_in_icon(icon_state, icon)) + PRINT_STACK_TRACE("Icon file for secret_key [secret_key] does not contain pre-content icon_state [icon_state].") + return INITIALIZE_HINT_QDEL + set_content(secret.text, secret.title) + if(secret.icon && !check_state_in_icon(icon_state, icon)) + PRINT_STACK_TRACE("Icon file for secret_key [secret_key] does not contain post-content icon_state [icon_state].") + return INITIALIZE_HINT_QDEL + return INITIALIZE_HINT_NORMAL + +/obj/item/paper/secret_note/random + var/secrets_should_not_repeat = TRUE + +/obj/item/paper/secret_note/random/get_secret() + return SSsecrets.retrieve_random_secret(secret_key, secrets_should_not_repeat, /datum/secret_note) diff --git a/code/modules/hydroponics/beekeeping/beehive.dm b/code/modules/hydroponics/beekeeping/beehive.dm deleted file mode 100644 index f8b455159d03..000000000000 --- a/code/modules/hydroponics/beekeeping/beehive.dm +++ /dev/null @@ -1,309 +0,0 @@ -/obj/machinery/beehive - name = "apiary" - icon = 'icons/obj/beekeeping.dmi' - icon_state = "beehive-0" - desc = "A wooden box designed specifically to house our buzzling buddies. Far more efficient than traditional hives. Just insert a frame and a queen, close it up, and you're good to go!" - density = 1 - anchored = 1 - layer = BELOW_OBJ_LAYER - - var/closed = 0 - var/bee_count = 0 // Percent - var/smoked = 0 // Timer - var/honeycombs = 0 // Percent - var/frames = 0 - var/maxFrames = 5 - -/obj/machinery/beehive/Initialize() - . = ..() - update_icon() - -/obj/machinery/beehive/on_update_icon() - overlays.Cut() - icon_state = "beehive-[closed]" - if(closed) - overlays += "lid" - if(frames) - overlays += "empty[frames]" - if(honeycombs >= 100) - overlays += "full[round(honeycombs / 100)]" - if(!smoked) - switch(bee_count) - if(1 to 20) - overlays += "bees1" - if(21 to 40) - overlays += "bees2" - if(41 to 60) - overlays += "bees3" - if(61 to 80) - overlays += "bees4" - if(81 to 100) - overlays += "bees5" - -/obj/machinery/beehive/examine(mob/user) - . = ..() - if(!closed) - to_chat(user, "The lid is open.") - -/obj/machinery/beehive/attackby(var/obj/item/I, var/mob/user) - if(isCrowbar(I)) - closed = !closed - user.visible_message("\The [user] [closed ? "closes" : "opens"] \the [src].", "You [closed ? "close" : "open"] \the [src].") - update_icon() - return - else if(isWrench(I)) - anchored = !anchored - user.visible_message("\The [user] [anchored ? "wrenches" : "unwrenches"] \the [src].", "You [anchored ? "wrench" : "unwrench"] \the [src].") - return - else if(istype(I, /obj/item/bee_smoker)) - if(closed) - to_chat(user, "You need to open \the [src] with a crowbar before smoking the bees.") - return - user.visible_message("\The [user] smokes the bees in \the [src].", "You smoke the bees in \the [src].") - smoked = 30 - update_icon() - return - else if(istype(I, /obj/item/honey_frame)) - if(closed) - to_chat(user, "You need to open \the [src] with a crowbar before inserting \the [I].") - return - if(frames >= maxFrames) - to_chat(user, "There is no place for an another frame.") - return - var/obj/item/honey_frame/H = I - if(H.honey) - to_chat(user, "\The [I] is full with beeswax and honey, empty it in the extractor first.") - return - ++frames - user.visible_message("\The [user] loads \the [I] into \the [src].", "You load \the [I] into \the [src].") - update_icon() - qdel(I) - return - else if(istype(I, /obj/item/bee_pack)) - var/obj/item/bee_pack/B = I - if(B.full && bee_count) - to_chat(user, "\The [src] already has bees inside.") - return - if(!B.full && bee_count < 90) - to_chat(user, "\The [src] is not ready to split.") - return - if(!B.full && !smoked) - to_chat(user, "Smoke \the [src] first!") - return - if(closed) - to_chat(user, "You need to open \the [src] with a crowbar before moving the bees.") - return - if(B.full) - user.visible_message("\The [user] puts the queen and the bees from \the [I] into \the [src].", "You put the queen and the bees from \the [I] into \the [src].") - bee_count = 20 - B.empty() - else - user.visible_message("\The [user] puts bees and larvae from \the [src] into \the [I].", "You put bees and larvae from \the [src] into \the [I].") - bee_count /= 2 - B.fill() - update_icon() - return - else if(istype(I, /obj/item/scanner/plant)) - to_chat(user, "Scan result of \the [src]...") - to_chat(user, "Beehive is [bee_count ? "[round(bee_count)]% full" : "empty"].[bee_count > 90 ? " Colony is ready to split." : ""]") - if(frames) - to_chat(user, "[frames] frames installed, [round(honeycombs / 100)] filled.") - if(honeycombs < frames * 100) - to_chat(user, "Next frame is [round(honeycombs % 100)]% full.") - else - to_chat(user, "No frames installed.") - if(smoked) - to_chat(user, "The hive is smoked.") - return 1 - else if(isScrewdriver(I)) - if(bee_count) - to_chat(user, "You can't dismantle \the [src] with these bees inside.") - return - to_chat(user, "You start dismantling \the [src]...") - playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) - if(do_after(user, 30, src)) - user.visible_message("\The [user] dismantles \the [src].", "You dismantle \the [src].") - new /obj/item/beehive_assembly(loc) - qdel(src) - return - -/obj/machinery/beehive/physical_attack_hand(var/mob/user) - if(!closed) - . = TRUE - if(honeycombs < 100) - to_chat(user, "There are no filled honeycombs.") - return - if(!smoked && bee_count) - to_chat(user, "The bees won't let you take the honeycombs out like this, smoke them first.") - return - user.visible_message("\The [user] starts taking the honeycombs out of \the [src].", "You start taking the honeycombs out of \the [src]...") - while(honeycombs >= 100 && do_after(user, 30, src)) - new /obj/item/honey_frame/filled(loc) - honeycombs -= 100 - --frames - update_icon() - if(honeycombs < 100) - to_chat(user, "You take all filled honeycombs out.") - -/obj/machinery/beehive/Process() - if(closed && !smoked && bee_count) - pollinate_flowers() - update_icon() - smoked = max(0, smoked - 1) - if(!smoked && bee_count) - bee_count = min(bee_count * 1.005, 100) - update_icon() - -/obj/machinery/beehive/proc/pollinate_flowers() - var/coef = bee_count / 100 - var/trays = 0 - for(var/obj/machinery/portable_atmospherics/hydroponics/H in view(7, src)) - if(H.seed && !H.dead) - H.health += 0.05 * coef - ++trays - honeycombs = min(honeycombs + 0.1 * coef * min(trays, 5), frames * 100) - -/obj/machinery/honey_extractor - name = "honey extractor" - desc = "A machine used to extract honey and wax from a beehive frame." - icon = 'icons/obj/virology.dmi' - icon_state = "centrifuge" - anchored = 1 - density = 1 - construct_state = /decl/machine_construction/default/panel_closed - uncreated_component_parts = null - stat_immune = 0 - - var/processing = 0 - var/honey = 0 - -/obj/machinery/honey_extractor/components_are_accessible(path) - return !processing && ..() - -/obj/machinery/honey_extractor/cannot_transition_to(state_path, mob/user) - if(processing) - return SPAN_NOTICE("You must wait for \the [src] to finish first!") - return ..() - -/obj/machinery/honey_extractor/attackby(var/obj/item/I, var/mob/user) - if(processing) - to_chat(user, "\The [src] is currently spinning, wait until it's finished.") - return - if((. = component_attackby(I, user))) - return - if(istype(I, /obj/item/honey_frame)) - var/obj/item/honey_frame/H = I - if(!H.honey) - to_chat(user, "\The [H] is empty, put it into a beehive.") - return - user.visible_message("\The [user] loads \the [H] into \the [src] and turns it on.", "You load \the [H] into \the [src] and turn it on.") - processing = H.honey - icon_state = "centrifuge_moving" - qdel(H) - spawn(50) - new /obj/item/honey_frame(loc) - new /obj/item/stack/wax(loc) - honey += processing - processing = 0 - icon_state = "centrifuge" - else if(istype(I, /obj/item/chems/glass)) - if(!honey) - to_chat(user, "There is no honey in \the [src].") - return - var/obj/item/chems/glass/G = I - var/transferred = min(G.reagents.maximum_volume - G.reagents.total_volume, honey) - G.reagents.add_reagent(/decl/material/liquid/nutriment/honey, transferred) - honey -= transferred - user.visible_message("\The [user] collects honey from \the [src] into \the [G].", "You collect [transferred] units of honey from \the [src] into \the [G].") - return 1 - -/obj/item/bee_smoker - name = "bee smoker" - desc = "A device used to calm down bees before harvesting honey." - icon = 'icons/obj/items/weapon/batterer.dmi' - icon_state = "battererburnt" - w_class = ITEM_SIZE_SMALL - -/obj/item/honey_frame - name = "beehive frame" - desc = "A frame for the beehive that the bees will fill with honeycombs." - icon = 'icons/obj/beekeeping.dmi' - icon_state = "honeyframe" - w_class = ITEM_SIZE_SMALL - - var/honey = 0 - -/obj/item/honey_frame/filled - name = "filled beehive frame" - desc = "A frame for the beehive that the bees have filled with honeycombs." - honey = 20 - -/obj/item/honey_frame/filled/Initialize() - . = ..() - overlays += "honeycomb" - -/obj/item/beehive_assembly - name = "beehive assembly" - desc = "Contains everything you need to build a beehive." - icon = 'icons/obj/apiary_bees_etc.dmi' - icon_state = "apiary" - -/obj/item/beehive_assembly/attack_self(var/mob/user) - to_chat(user, "You start assembling \the [src]...") - if(do_after(user, 30, src)) - user.visible_message("\The [user] constructs a beehive.", "You construct a beehive.") - new /obj/machinery/beehive(get_turf(user)) - qdel(src) - -/obj/item/stack/wax - name = "wax" - singular_name = "wax piece" - desc = "Soft substance produced by bees. Used to make candles." - icon = 'icons/obj/beekeeping.dmi' - icon_state = "wax" - -GLOBAL_LIST_INIT(wax_recipes, list(new /datum/stack_recipe/candle)) -/obj/item/stack/wax/Initialize() - . = ..() - recipes = GLOB.wax_recipes - -/obj/item/bee_pack - name = "bee pack" - desc = "Contains a queen bee and some worker bees. Everything you'll need to start a hive!" - icon = 'icons/obj/beekeeping.dmi' - icon_state = "beepack" - var/full = 1 - -/obj/item/bee_pack/Initialize() - . = ..() - overlays += "beepack-full" - -/obj/item/bee_pack/proc/empty() - full = 0 - name = "empty bee pack" - desc = "A stasis pack for moving bees. It's empty." - overlays.Cut() - overlays += "beepack-empty" - -/obj/item/bee_pack/proc/fill() - full = initial(full) - SetName(initial(name)) - desc = initial(desc) - overlays.Cut() - overlays += "beepack-full" - -/obj/structure/closet/crate/hydroponics/beekeeping - name = "beekeeping crate" - desc = "All you need to set up your own beehive." - -/obj/structure/closet/crate/hydroponics/beekeeping/Initialize() - . = ..() - new /obj/item/beehive_assembly(src) - new /obj/item/bee_smoker(src) - new /obj/item/honey_frame(src) - new /obj/item/honey_frame(src) - new /obj/item/honey_frame(src) - new /obj/item/honey_frame(src) - new /obj/item/honey_frame(src) - new /obj/item/bee_pack(src) - new /obj/item/crowbar(src) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index a50bec762101..7ed077da24fe 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -1,61 +1,133 @@ //Grown foods. -/obj/item/chems/food/snacks/grown - name = "fruit" +/obj/item/food/grown + name = "produce" icon = 'icons/obj/hydroponics/hydroponics_products.dmi' icon_state = "blank" randpixel = 5 desc = "Nutritious! Probably." slot_flags = SLOT_HOLSTER - - var/plantname + material = /decl/material/solid/organic/plantmatter + is_spawnable_type = FALSE // Use the Spawn-Fruit verb instead. + drying_wetness = 45 + dried_type = /obj/item/food/grown/dry + allergen_flags = ALLERGEN_VEGETABLE + + var/plant_segment_type = PLANT_SEG_BODY // Used for growns produced via plant dissection. + var/work_skill = SKILL_BOTANY + var/seeds_extracted = FALSE var/datum/seed/seed - var/potency = -1 -/obj/item/chems/food/snacks/grown/Initialize(mapload, planttype) - . = ..(mapload) - if(planttype) - plantname = planttype - seed = SSplants.seeds[plantname] +// This is sort of pointless while food is a valid input on the ChemMaster but maybe +// in the future there will be some more interesting ways to process growns/food. +/obj/item/food/grown/handle_centrifuge_process(obj/machinery/centrifuge/centrifuge) + if(!(. = ..())) + return + if(REAGENT_TOTAL_VOLUME(reagents)) + reagents.trans_to_holder(centrifuge.loaded_beaker.reagents, REAGENT_TOTAL_VOLUME(reagents)) + for(var/obj/item/thing in contents) + thing.dropInto(centrifuge.loc) + for(var/atom/movable/thing in convert_matter_to_lumps()) + thing.dropInto(centrifuge.loc) + +/obj/item/food/grown/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(user && distance <= 1 && seed && user.skill_check(work_skill, SKILL_BASIC)) + if(seed.grown_is_seed) + . += SPAN_NOTICE("\The [src] can be planted directly, without having to extract any seeds.") + else if(!seeds_extracted && seed.min_seed_extracted) + . += SPAN_NOTICE("With a knife, you could extract at least [seed.min_seed_extracted] seed\s.") + +/obj/item/food/grown/proc/update_base_name() + base_name = seed?.product_name || "grown" + +/obj/item/food/grown/update_name() if(!seed) + return ..() + update_base_name() + var/descriptor = list() + if(dry) + descriptor += "dried" + if(backyard_grilling_count > 0) + descriptor += "roasted" + if(length(descriptor)) + SetName("[english_list(descriptor)] [base_name]") + else + SetName(base_name) + +// Separated out of Initialize() for subtype overrides. +/obj/item/food/grown/proc/set_seed(_seed) + if(isnull(seed) && _seed) + seed = _seed + if(istext(seed)) + seed = SSplants.seeds[seed] + if(!isnull(seed) && !istype(seed)) + seed = null + +/obj/item/food/grown/Initialize(mapload, material_key, skip_plate = FALSE, _seed) + + set_seed(_seed) + if(!istype(seed)) + PRINT_STACK_TRACE("Grown initializing with null or invalid seed type '[seed || "NULL"]'") return INITIALIZE_HINT_QDEL - SetName("[seed.seed_name]") - trash = seed.get_trash_type() - if(!dried_type) - dried_type = type + filling_color = seed.get_trait(TRAIT_PRODUCT_COLOUR) || seed.get_trait(TRAIT_FLESH_COLOUR) + slice_path = seed.slice_product + slice_num = seed.slice_amount + w_class = seed.product_w_class - fill_reagents() - update_icon() + if(!seed.get_chemical_composition() && !(dry && seed.get_chemical_composition(_state = PLANT_STATE_DRIED)) && !(backyard_grilling_count > 0 && seed.get_chemical_composition(_state = PLANT_STATE_ROASTED))) + return INITIALIZE_HINT_QDEL // No reagent contents, no froot + if(seed.scannable_result) + set_extension(src, /datum/extension/scannable, seed.scannable_result) -/obj/item/chems/food/snacks/grown/proc/fill_reagents() - if(!seed) - return + update_name() + if(seed.product_material) + material = seed.product_material - if(!seed.chems) - return + trash = seed.get_trash_type() + backyard_grilling_product = seed.backyard_grilling_product + backyard_grilling_rawness = seed.backyard_grilling_rawness + backyard_grilling_announcement = seed.backyard_grilling_announcement + + if(!dried_type) + dried_type = type + + . = ..(mapload, material_key, skip_plate) //Init reagents - potency = seed.get_trait(TRAIT_POTENCY) - if(!reagents) - create_reagents(volume) - reagents.clear_reagents() - // Fill the object up with the appropriate reagents. - for(var/rid in seed.chems) - var/list/reagent_data = seed.chems[rid] - if(reagent_data && reagent_data.len) - var/rtotal = reagent_data[1] - var/list/data = list() - if(reagent_data.len > 1 && potency > 0) - rtotal += round(potency/reagent_data[2]) - if(rid == /decl/material/liquid/nutriment) - data[seed.seed_name] = max(1,rtotal) - reagents.add_reagent(rid,max(1,rtotal),data) update_desc() - if(reagents.total_volume > 0) - bitesize = 1+round(reagents.total_volume / 2, 1) + if(REAGENT_TOTAL_VOLUME(reagents) > 0) + bitesize = 1 + round(REAGENT_TOTAL_VOLUME(reagents) / 2, 1) + update_icon() -/obj/item/chems/food/snacks/grown/proc/update_desc() +/obj/item/food/grown/populate_reagents() + . = ..() + if(!length(seed?.get_chemical_composition(_segment = plant_segment_type))) + return + // Fill the object up with the appropriate reagents. + var/list/chems_to_fill + if(backyard_grilling_count > 0) + chems_to_fill ||= seed?.get_chemical_composition(_segment = plant_segment_type, _state = PLANT_STATE_ROASTED) + if(dry) + chems_to_fill ||= seed?.get_chemical_composition(_segment = plant_segment_type, _state = PLANT_STATE_DRIED) + chems_to_fill ||= seed?.get_chemical_composition(_segment = plant_segment_type) + + for(var/rid in chems_to_fill) + var/list/reagent_amounts = chems_to_fill[rid] + if(LAZYLEN(reagent_amounts)) + var/rtotal = reagent_amounts[1] + var/list/data = null + var/potency = seed.get_trait(TRAIT_POTENCY) + if(LAZYACCESS(reagent_amounts,2) && potency > 0) + rtotal += round(potency/reagent_amounts[2]) + var/decl/material/reagent = GET_DECL(rid) + if(!reagent.taste_description) + LAZYSET(data, DATA_TASTE, list(seed.product_name = max(1,rtotal) * reagent.taste_mult)) + add_to_reagents(rid,max(1,rtotal),data) + +/obj/item/food/grown/proc/update_desc() + set waitfor = FALSE if(!seed) return if(!SSplants) @@ -71,19 +143,18 @@ var/list/descriptors = list() - for(var/rtype in reagents.reagent_volumes) - var/decl/material/chem = decls_repository.get_decl(rtype) - if(chem.fruit_descriptor) - descriptors |= chem.fruit_descriptor - if(chem.reflectiveness >= MAT_VALUE_SHINY) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.fruit_descriptor) + descriptors |= reagent.fruit_descriptor + if(reagent.reflectiveness >= MAT_VALUE_SHINY) descriptors |= "shiny" - if(chem.slipperiness >= 10) + if(reagent.slipperiness >= 10) descriptors |= "slippery" - if(chem.toxicity >= 3) + if(reagent.toxicity >= 3) descriptors |= "poisonous" - if(chem.radioactivity) + if(reagent.radioactivity) descriptors |= "radioactive" - if(chem.solvent_power >= MAT_SOLVENT_STRONG) + if(reagent.solvent_power >= MAT_SOLVENT_STRONG) descriptors |= "acidic" if(seed.get_trait(TRAIT_JUICY)) @@ -110,107 +181,136 @@ SSplants.product_descs["[seed.uid]"] = desc desc += ". Delicious! Probably." -/obj/item/chems/food/snacks/grown/on_update_icon() +/obj/item/food/grown/on_update_icon() + . = ..() if(!seed) return - overlays.Cut() + if(!dry && !backyard_grilling_count) + color = seed.get_trait(TRAIT_PRODUCT_COLOUR) + update_grown_icon() + +// Separated for subtypes to override. +/obj/item/food/grown/proc/update_grown_icon() icon_state = "[seed.get_trait(TRAIT_PRODUCT_ICON)]-product" - color = seed.get_trait(TRAIT_PRODUCT_COLOUR) if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in icon_states('icons/obj/hydroponics/hydroponics_products.dmi')) var/image/fruit_leaves = image('icons/obj/hydroponics/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf") - fruit_leaves.color = seed.get_trait(TRAIT_PLANT_COLOUR) - overlays |= fruit_leaves - -/obj/item/chems/food/snacks/grown/Crossed(var/mob/living/M) - if(seed && seed.get_trait(TRAIT_JUICY) == 2) - if(istype(M)) - - if(M.buckled) - return - - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.shoes && H.shoes.item_flags & ITEM_FLAG_NOSLIP) - return - - to_chat(M, "You slipped on the [name]!") - playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) - M.Stun(8) - M.Weaken(5) - seed.thrown_at(src,M) - sleep(-1) - if(src) qdel(src) - return + if(!dry && !backyard_grilling_count) + fruit_leaves.color = seed.get_trait(TRAIT_PLANT_COLOUR) + add_overlay(fruit_leaves) -/obj/item/chems/food/snacks/grown/throw_impact(atom/hit_atom) - if(seed) seed.thrown_at(src,hit_atom) - ..() +/obj/item/food/grown/Crossed(atom/movable/AM) + if(!isliving(AM) || !seed || seed.get_trait(TRAIT_JUICY) != 2) + return + + var/mob/living/M = AM + if(MOVING_DELIBERATELY(M)) + return + + if(!M.can_slip() || M.immune_to_floor_hazards()) + return -/obj/item/chems/food/snacks/grown/attackby(var/obj/item/W, var/mob/user) + to_chat(M, SPAN_DANGER("You slipped on \the [src]!")) + playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) + SET_STATUS_MAX(M, STAT_STUN, 8) + SET_STATUS_MAX(M, STAT_WEAK, 5) + seed.thrown_at(src,M) + QDEL_IN(src, 0) +/obj/item/food/grown/throw_impact(atom/hit_atom) + ..() if(seed) - if(seed.get_trait(TRAIT_PRODUCES_POWER) && isCoil(W)) - var/obj/item/stack/cable_coil/C = W - if(C.use(5)) - //TODO: generalize this. - to_chat(user, "You add some cable to the [src.name] and slide it inside the battery casing.") - var/obj/item/cell/potato/pocell = new /obj/item/cell/potato(get_turf(user)) - if(src.loc == user && !(user.l_hand && user.r_hand) && istype(user,/mob/living/carbon/human)) - user.put_in_hands(pocell) - pocell.maxcharge = src.potency * 10 - pocell.charge = pocell.maxcharge - qdel(src) - return - else if(W.sharp) - if(seed.kitchen_tag == "pumpkin") // Ugggh these checks are awful. - user.show_message("You carve a face into [src]!", 1) - new /obj/item/clothing/head/pumpkinhead (user.loc) - qdel(src) - return - else if(seed.chems) - if(isHatchet(W)) - if(!isnull(seed.chems[/decl/material/solid/wood])) - user.visible_message("\The [user] makes planks out of \the [src].") - new /obj/item/stack/material/wood(user.loc) - qdel(src) - else if(!isnull(seed.chems[/decl/material/solid/wood/bamboo])) - user.visible_message("\The [user] makes planks out of \the [src].") - new /obj/item/stack/material/wood/bamboo(user.loc) - qdel(src) - return - else if(!isnull(seed.chems[/decl/material/liquid/drink/juice/potato])) - to_chat(user, "You slice \the [src] into sticks.") - new /obj/item/chems/food/snacks/rawsticks(get_turf(src)) - qdel(src) - return - else if(!isnull(seed.chems[/decl/material/liquid/drink/juice/carrot])) - to_chat(user, "You slice \the [src] into sticks.") - new /obj/item/chems/food/snacks/carrotfries(get_turf(src)) - qdel(src) - return - else if(!isnull(seed.chems[/decl/material/liquid/drink/milk/soymilk])) - to_chat(user, "You roughly chop up \the [src].") - new /obj/item/chems/food/snacks/soydope(get_turf(src)) - qdel(src) - return - else if(seed.get_trait(TRAIT_FLESH_COLOUR)) - to_chat(user, "You slice up \the [src].") - var/slices = rand(3,5) - var/reagents_to_transfer = round(reagents.total_volume/slices) - for(var/i in 1 to slices) - var/obj/item/chems/food/snacks/fruit_slice/F = new(get_turf(src),seed) - if(reagents_to_transfer) reagents.trans_to_obj(F,reagents_to_transfer) + seed.thrown_at(src,hit_atom) + +var/global/list/_wood_materials = list( + /decl/material/solid/organic/wood/oak, + /decl/material/solid/organic/wood/mahogany, + /decl/material/solid/organic/wood/maple, + /decl/material/solid/organic/wood/ebony, + /decl/material/solid/organic/wood/walnut, + /decl/material/solid/organic/wood/bamboo, + /decl/material/solid/organic/wood/yew +) + +/obj/item/food/grown/show_slice_message(mob/user, obj/item/tool) + if(!seed?.show_slice_message(user, tool, src)) + ..() + +/obj/item/food/grown/show_slice_message_poor(mob/user, obj/item/tool) + if(!seed?.show_slice_message_poor(user, tool, src)) + ..() + +/obj/item/food/grown/attackby(var/obj/item/used_item, var/mob/user) + + if(!seed || user.check_intent(I_FLAG_HARM)) + return ..() + + if(seed.get_trait(TRAIT_PRODUCES_POWER) && IS_COIL(used_item)) + var/obj/item/stack/cable_coil/C = used_item + if(C.use(5)) + //TODO: generalize this. + to_chat(user, SPAN_NOTICE("You add some cable to \the [src] and slide it inside the battery casing.")) + var/obj/item/cell/potato/pocell = new /obj/item/cell/potato(get_turf(user)) + qdel(src) + user.put_in_hands(pocell) + pocell.maxcharge = seed.get_trait(TRAIT_POTENCY) * 10 + pocell.charge = pocell.maxcharge + return TRUE + + if(IS_KNIFE(used_item) && !seeds_extracted && !seed.grown_is_seed && seed.min_seed_extracted && user.skill_check(work_skill, SKILL_BASIC)) + var/seed_result = max(1, rand(seed.min_seed_extracted, seed.max_seed_extracted)) + visible_message(SPAN_NOTICE("\The [user] uses \the [used_item] to lever [seed_result] seed\s out of \the [src].")) + for(var/i = 1 to seed_result) + new /obj/item/seeds/extracted(get_turf(user), material?.type, seed) + seeds_extracted = TRUE + return TRUE + + if(IS_HATCHET(used_item)) + var/list/seed_chems = seed?.get_chemical_composition() + if(length(seed_chems)) + for(var/wood_mat in global._wood_materials) + if(!isnull(seed_chems[wood_mat])) + user.visible_message(SPAN_NOTICE("\The [user] makes planks out of \the [src].")) + for(var/obj/item/stack/material/stack in SSmaterials.create_object(wood_mat, user.loc, rand(1,2))) + stack.add_to_stacks(user, TRUE) qdel(src) - return - ..() + return TRUE + + if(istype(used_item, /obj/item/paper)) + + if(!dry) + to_chat(user, SPAN_WARNING("You need to dry \the [src] first!")) + return TRUE + + if(!user.try_unequip(used_item)) + return TRUE + + var/obj/item/clothing/mask/smokable/cigarette/rolled/R = new(get_turf(src)) + R.create_or_update_reagents(max(REAGENT_MAXIMUM_VOLUME(R.reagents), REAGENT_TOTAL_VOLUME(reagents))) + R.brand = "[src] handrolled in \the [used_item]." + reagents.trans_to_holder(R.reagents, REAGENT_TOTAL_VOLUME(R.reagents)) + to_chat(user, SPAN_NOTICE("You roll \the [src] into \the [used_item].")) + user.put_in_active_hand(R) + qdel(used_item) + qdel(src) + return TRUE + + . = ..() -/obj/item/chems/food/snacks/grown/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) +/obj/item/food/grown/get_grown_tag() + if(!seed?.grown_tag) + return + . = dry ? "dried [seed.grown_tag]" : seed.grown_tag + +/obj/item/food/grown/create_slice() + return new slice_path(loc, material?.type, TRUE, seed) + +/obj/item/food/grown/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) . = ..() if(seed && seed.get_trait(TRAIT_STINGS)) - if(!reagents || reagents.total_volume <= 0) + if(!reagents || REAGENT_TOTAL_VOLUME(reagents) <= 0) return - reagents.remove_any(rand(1,3)) + remove_any_reagents(rand(1,3)) seed.thrown_at(src, target) sleep(-1) if(!src) @@ -220,94 +320,87 @@ to_chat(user, "\The [src] has fallen to bits.") qdel(src) -/obj/item/chems/food/snacks/grown/attack_self(mob/user) +/obj/item/food/grown/attack_self(mob/user) - if(!seed) - return - - if(istype(user.loc,/turf/space)) - return - - if(user.a_intent == I_HURT) - user.visible_message("\The [user] squashes \the [src]!") - seed.thrown_at(src,user) - sleep(-1) - if(src) qdel(src) - return + if(seed) + if(user.check_intent(I_FLAG_HARM)) + user.visible_message(SPAN_DANGER("\The [user] squashes \the [src]!")) + seed.thrown_at(src,user) + sleep(-1) + if(src) qdel(src) + return TRUE - if(seed.kitchen_tag == "grass") - user.show_message("You make a grass tile out of \the [src]!", 1) - var/flesh_colour = seed.get_trait(TRAIT_FLESH_COLOUR) - if(!flesh_colour) flesh_colour = seed.get_trait(TRAIT_PRODUCT_COLOUR) - for(var/i=0,i<2,i++) - var/obj/item/stack/tile/grass/G = new (user.loc) - if(flesh_colour) G.color = flesh_colour - for (var/obj/item/stack/tile/grass/NG in user.loc) - if(G==NG) - continue - if(NG.amount>=NG.max_amount) - continue - NG.attackby(G, user) - to_chat(user, "You add the newly-formed grass to the stack. It now contains [G.amount] tiles.") - qdel(src) - return + var/turf/user_loc = user.loc + if(isturf(user_loc) && !user_loc.is_open() && seed.get_trait(TRAIT_SPREAD) > 0) + to_chat(user, SPAN_NOTICE("You plant \the [src].")) + new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(user),src.seed) + qdel(src) + return TRUE - if(seed.get_trait(TRAIT_SPREAD) > 0) - to_chat(user, "You plant the [src.name].") - new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(user),src.seed) - qdel(src) - return + return ..() -/obj/item/chems/food/snacks/grown/pickup(mob/user) +/obj/item/food/grown/on_picked_up(mob/user, atom/old_loc) ..() if(!seed) return if(seed.get_trait(TRAIT_STINGS)) - var/mob/living/carbon/human/H = user - if(istype(H) && H.gloves) + var/mob/living/human/H = user + if(istype(H) && H.get_equipped_item(slot_gloves_str)) return - if(!reagents || reagents.total_volume <= 0) + if(!reagents || REAGENT_TOTAL_VOLUME(reagents) <= 0) return - reagents.remove_any(rand(1,3)) //Todo, make it actually remove the reagents the seed uses. + remove_any_reagents(rand(1,3)) //Todo, make it actually remove the reagents the seed uses. var/affected = pick(BP_R_HAND,BP_L_HAND) seed.do_thorns(H,src,affected) seed.do_sting(H,src,affected) -// Predefined types for placing on the map. - -/obj/item/chems/food/snacks/grown/mushroom/libertycap - plantname = "libertycap" - -/obj/item/chems/food/snacks/grown/ambrosiavulgaris - plantname = "biteleaf" - -/obj/item/chems/food/snacks/fruit_slice - name = "fruit slice" - desc = "A slice of some tasty fruit." - icon = 'icons/obj/hydroponics/hydroponics_misc.dmi' - icon_state = "" +/obj/item/food/grown/dry + dry = TRUE + drying_wetness = null + dried_type = null + color = COLOR_BEIGE + +/obj/item/food/grown/get_dried_product() + if(ispath(dried_type, /obj/item/food/grown)) + return new dried_type(loc, null, TRUE, seed.name) + return ..() + +/obj/item/food/grown/get_drying_state(var/obj/rack) + return seed?.drying_state || ..() + +/obj/item/food/grown/grilled + backyard_grilling_count = 1 // will get overwritten when actually made + color = COLOR_BROWN_ORANGE + +/obj/item/food/grown/get_grilled_product() + if(ispath(backyard_grilling_product, /obj/item/food/grown)) + return new backyard_grilling_product(loc, null, TRUE, seed.name) + return ..() + +/obj/item/food/grown/afterattack(atom/target, mob/user, flag) + if(!flag && isliving(user)) + var/mob/living/M = user + M.aim_at(target, src) + return + . = ..() -var/list/fruit_icon_cache = list() +/obj/item/food/grown/handle_reflexive_fire(var/mob/user, var/atom/aiming_at) + . = ..() + if(.) + user.visible_message(SPAN_DANGER("\The [user] reflexively hurls \the [src] at \the [aiming_at]!")) + user.mob_throw_item(get_turf(aiming_at), src) + user.trigger_aiming(TARGET_CAN_CLICK) + +/obj/item/food/grown/has_textile_fibers() + for(var/mat in get_contained_matter()) + var/decl/material/check_mat = GET_DECL(mat) + if(check_mat.has_textile_fibers) + return TRUE + return FALSE -/obj/item/chems/food/snacks/fruit_slice/Initialize(mapload, var/datum/seed/S) - . = ..(mapload) - // Need to go through and make a general image caching controller. Todo. - if(!istype(S)) - return INITIALIZE_HINT_QDEL +// Predefined types for placing on the map. +/obj/item/food/grown/libertycap + seed = "libertycap" - name = "[S.seed_name] slice" - desc = "A slice of \a [S.seed_name]. Tasty, probably." - - var/rind_colour = S.get_trait(TRAIT_PRODUCT_COLOUR) - var/flesh_colour = S.get_trait(TRAIT_FLESH_COLOUR) - if(!flesh_colour) flesh_colour = rind_colour - if(!fruit_icon_cache["rind-[rind_colour]"]) - var/image/I = image(icon,"fruit_rind") - I.color = rind_colour - fruit_icon_cache["rind-[rind_colour]"] = I - overlays |= fruit_icon_cache["rind-[rind_colour]"] - if(!fruit_icon_cache["slice-[rind_colour]"]) - var/image/I = image(icon,"fruit_slice") - I.color = flesh_colour - fruit_icon_cache["slice-[rind_colour]"] = I - overlays |= fruit_icon_cache["slice-[rind_colour]"] +/obj/item/food/grown/ambrosiavulgaris + seed = "ambrosiavulgaris" diff --git a/code/modules/hydroponics/grown_inedible.dm b/code/modules/hydroponics/grown_inedible.dm index 34c08d4ee426..173d19639f9d 100644 --- a/code/modules/hydroponics/grown_inedible.dm +++ b/code/modules/hydroponics/grown_inedible.dm @@ -1,35 +1,3 @@ -// ********************** -// Other harvested materials from plants (that are not food) -// ********************** - -/obj/item/grown // Grown weapons - name = "grown_weapon" - var/plantname - var/potency = 1 - -/obj/item/grown/Initialize(mapload,planttype) - . = ..(mapload) - - var/datum/reagents/R = new/datum/reagents(50) - reagents = R - R.my_atom = src - - //Handle some post-spawn var stuff. - if(planttype) - plantname = planttype - var/datum/seed/S = SSplants.seeds[plantname] - if(!S || !S.chems) - return - - potency = S.get_trait(TRAIT_POTENCY) - - for(var/rid in S.chems) - var/list/reagent_data = S.chems[rid] - var/rtotal = reagent_data[1] - if(reagent_data.len > 1 && potency > 0) - rtotal += round(potency/reagent_data[2]) - reagents.add_reagent(rid,max(1,rtotal)) - /obj/item/corncob name = "corn cob" desc = "A reminder of meals gone by." @@ -37,17 +5,17 @@ icon_state = "corncob" item_state = "corncob" w_class = ITEM_SIZE_SMALL - throwforce = 0 throw_speed = 4 throw_range = 20 + material = /decl/material/solid/organic/plantmatter -/obj/item/corncob/attackby(obj/item/W, mob/user) - ..() - if(istype(W, /obj/item/circular_saw) || isHatchet(W) || istype(W, /obj/item/knife)) - to_chat(user, "You use [W] to fashion a pipe out of the corn cob!") +/obj/item/corncob/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/circular_saw) || IS_HATCHET(used_item) || istype(used_item, /obj/item/knife)) + to_chat(user, "You use [used_item] to fashion a pipe out of the corn cob!") new /obj/item/clothing/mask/smokable/pipe/cobpipe (user.loc) qdel(src) - return + return TRUE + return ..() /obj/item/bananapeel name = "banana peel" @@ -56,6 +24,6 @@ icon_state = "banana_peel" item_state = "banana_peel" w_class = ITEM_SIZE_SMALL - throwforce = 0 throw_speed = 4 throw_range = 20 + material = /decl/material/solid/organic/plantmatter diff --git a/code/modules/hydroponics/grown_predefined.dm b/code/modules/hydroponics/grown_predefined.dm index 76d702b35e40..a88534f330ec 100644 --- a/code/modules/hydroponics/grown_predefined.dm +++ b/code/modules/hydroponics/grown_predefined.dm @@ -1,5 +1,49 @@ -/obj/item/chems/food/snacks/grown/ambrosiavulgaris - plantname = "biteleaf" +/obj/item/food/grown/ambrosiavulgaris + seed = "ambrosiavulgaris" + icon_state = "ambrosia-product" + color = "#9fad55" -/obj/item/chems/food/snacks/grown/ambrosiadeus - plantname = "biteleafdeus" \ No newline at end of file +/obj/item/food/grown/ambrosiadeus + seed = "ambrosiadeus" + icon_state = "ambrosia-product" + color = "#a3f0ad" + +/obj/item/food/grown/potato + seed = "potato" + icon_state = "potato-product" + color = "#d4cab4" + +/obj/item/food/grown/carrot + seed = "carrot" + icon_state = "carrot-product" + color = "#ff9900" + +/obj/item/food/grown/cabbage + seed = "cabbage" + icon_state = "cabbage-product" + color = "#84bd82" + +/obj/item/food/grown/yarrow + seed = "yarrow" + icon_state = "flower4-product" + color = "#e9e2c2" + +/obj/item/food/grown/aloe + seed = "aloe" + icon_state = "grass-product" + color = "#2d7746" + +/obj/item/food/grown/foxglove + seed = "foxglove" + icon_state = "flowers-product" + color = "#e9c2c2" + +/obj/item/food/grown/valerian + seed = "valerian" + icon_state = "flower4-product" + color = "#e9c2c2" + +/obj/item/food/grown/ginseng + seed = "ginseng" + icon_state = "pod-product" + color = "#ddbb7c" \ No newline at end of file diff --git a/code/modules/hydroponics/plant_types/seeds_herbs.dm b/code/modules/hydroponics/plant_types/seeds_herbs.dm new file mode 100644 index 000000000000..246c81aeed4a --- /dev/null +++ b/code/modules/hydroponics/plant_types/seeds_herbs.dm @@ -0,0 +1,85 @@ +/datum/seed/herb + abstract_type = /datum/seed/herb + allergen_flags = ALLERGEN_NONE // Do not make people allergic to the only medicine available on Shadyhills + produces_pollen = 0.5 + +/datum/seed/herb/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + +/datum/seed/herb/yarrow + name = "yarrow" + product_name = "yarrow flower" + display_name = "yarrow patch" + +/datum/seed/herb/yarrow/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#e9e2c2") + set_trait(TRAIT_PRODUCT_ICON,"flower4") + set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") + set_trait(TRAIT_PLANT_ICON,"flower4") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/brute_meds/yarrow, list(1, 1)) + set_chemical_amount(/decl/material/liquid/brute_meds/yarrow, list(10,10), _state = PLANT_STATE_DRIED) + +/datum/seed/herb/aloe + name = "aloe" + product_name = "aloe vera" + display_name = "aloe patch" + +/datum/seed/herb/aloe/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#2d7746") + set_trait(TRAIT_PRODUCT_ICON,"grass") + set_trait(TRAIT_PLANT_COLOUR,"#2d7746") + set_trait(TRAIT_PLANT_ICON,"ambrosia") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,5)) + set_chemical_amount(/decl/material/liquid/burn_meds/aloe, list(10,10)) + +/datum/seed/herb/ginseng + name = "ginseng" + product_name = "ginseng root" + display_name = "ginseng patch" + +/datum/seed/herb/ginseng/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#ddbb7c") + set_trait(TRAIT_PRODUCT_ICON,"pod") + set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") + set_trait(TRAIT_PLANT_ICON,"grass") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/antitoxins/ginseng, list(1, 1)) + set_chemical_amount(/decl/material/liquid/antitoxins/ginseng, list(10,10), _state = PLANT_STATE_DRIED) + +/datum/seed/herb/valerian + name = "valerian" + product_name = "valerian flower" + display_name = "valerian patch" + +/datum/seed/herb/valerian/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#e9c2c2") + set_trait(TRAIT_PRODUCT_ICON,"flower4") + set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") + set_trait(TRAIT_PLANT_ICON,"flower4") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/sedatives/valerian, list(1, 1)) + set_chemical_amount(/decl/material/liquid/sedatives/valerian, list(10,10), _state = PLANT_STATE_DRIED) + +/datum/seed/herb/foxglove + name = "foxglove" + product_name = "foxglove flower" + display_name = "foxglove patch" + +/datum/seed/herb/foxglove/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#e9c2c2") + set_trait(TRAIT_PRODUCT_ICON,"flowers") + set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") + set_trait(TRAIT_PLANT_ICON,"bush7") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/stabilizer/foxglove, list(1, 1)) + set_chemical_amount(/decl/material/liquid/stabilizer/foxglove, list(10,10), _state = PLANT_STATE_DRIED) diff --git a/code/modules/hydroponics/plant_types/seeds_misc.dm b/code/modules/hydroponics/plant_types/seeds_misc.dm new file mode 100644 index 000000000000..1ed4775af8fd --- /dev/null +++ b/code/modules/hydroponics/plant_types/seeds_misc.dm @@ -0,0 +1,1559 @@ +/datum/seed/cotton + name = "cotton" + product_name = "cotton" + display_name = "cotton patch" + product_material = /decl/material/solid/organic/plantmatter/pith/husk + slice_product = null + slice_amount = 0 + +/datum/seed/cotton/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"wheat") + set_trait(TRAIT_PRODUCT_COLOUR, "#ffffff") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_chemical_amount(/decl/material/liquid/oil/plant, list(3,10)) + set_chemical_amount(/decl/material/solid/organic/cloth, list(10,1)) + +/datum/seed/cotton/flax + name = "flax" + product_name = "flax" + display_name = "flax patch" + +/datum/seed/cotton/flax/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR, "#eee4c7") + // Do we want linseed oil at some point? + set_chemical_amount(/decl/material/liquid/oil/plant, list(5,12)) + set_chemical_amount(/decl/material/solid/organic/cloth/linen, list(8,1)) + +// Chili plants/variants. +/datum/seed/chili + name = "chili" + product_name = "chili" + display_name = "chili plants" + mutants = list("icechili") + grown_tag = "chili" + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/chili/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"chili") + set_trait(TRAIT_PRODUCT_COLOUR,"#ed3300") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_chemical_amount(/decl/material/liquid/capsaicin, list(3,5)) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,25)) + +/datum/seed/chili/ice + name = "icechili" + product_name = "chilly pepper" + display_name = "chilly pepper plant" + mutants = null + grown_tag = "icechili" + +/datum/seed/chili/ice/New() + ..() + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_PRODUCT_COLOUR,"#00edc6") + set_chemical_amount(/decl/material/liquid/frostoil, list(3,5)) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,50)) + +// Berry plants/variants. +/datum/seed/berry + name = "berries" + product_name = "berries" + display_name = "berry bush" + mutants = list("glowberries","poisonberries","blueberries") + grown_tag = "berries" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/berry/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"berry") + set_trait(TRAIT_PRODUCT_COLOUR,"#fa1616") + set_trait(TRAIT_PLANT_ICON,"bush") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/berry, list(10,10)) + +/datum/seed/berry/blue + name = "blueberries" + product_name = "blueberries" + display_name = "blueberry bush" + mutants = list("berries","poisonberries","glowberries") + grown_tag = "blueberries" + +/datum/seed/berry/blue/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_COLOUR,"#1c225c") + set_trait(TRAIT_WATER_CONSUMPTION, 5) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.2) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/berry, list(10,10)) + +/datum/seed/berry/glow + name = "glowberries" + product_name = "glowberries" + display_name = "glowberry bush" + mutants = null + +/datum/seed/berry/glow/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#006622") + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_COLOUR,"#c9fa16") + set_trait(TRAIT_WATER_CONSUMPTION, 3) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/solid/metal/uranium, list(3,5)) + +/datum/seed/berry/poison + name = "poisonberries" + product_name = "poison berries" + display_name = "poison berry bush" + mutants = list("deathberries") + +/datum/seed/berry/poison/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#6dc961") + set_trait(TRAIT_WATER_CONSUMPTION, 3) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + set_chemical_amount(/decl/material/liquid/bromide, list(3,5)) + set_chemical_amount(/decl/material/liquid/poisonberryjuice, list(10,5)) + +/datum/seed/berry/poison/death + name = "deathberries" + product_name = "death berries" + display_name = "death berry bush" + mutants = null + +/datum/seed/berry/poison/death/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,50) + set_trait(TRAIT_PRODUCT_COLOUR,"#7a5454") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + set_chemical_amount(/decl/material/liquid/bromide, list(3,3)) + set_chemical_amount(/decl/material/gas/carbon_monoxide, list(1,5)) + +// Nettles/variants. +/datum/seed/nettle + name = "nettle" + product_name = "nettle" + display_name = "nettle patch" + mutants = list("deathnettle") + grown_tag = "nettle" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/nettle/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_STINGS,1) + set_trait(TRAIT_PLANT_ICON,"bush5") + set_trait(TRAIT_PRODUCT_ICON,"nettles") + set_trait(TRAIT_PRODUCT_COLOUR,"#728a54") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,50)) + set_chemical_amount(/decl/material/liquid/drink/juice/nettle, list(1,10)) + set_chemical_amount(/decl/material/liquid/nettle_histamine, list(1, 5)) + +/datum/seed/nettle/death + name = "deathnettle" + product_name = "death nettle" + display_name = "death nettle patch" + mutants = null + grown_tag = "deathnettle" + +/datum/seed/nettle/death/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_COLOUR,"#8c5030") + set_trait(TRAIT_PLANT_COLOUR,"#634941") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,50)) + set_chemical_amount(/decl/material/liquid/acid/polyacid, list(0,1)) + +//Tomatoes/variants. +/datum/seed/tomato + name = "tomato" + product_name = "tomato" + display_name = "tomato plant" + mutants = list("bluetomato","bloodtomato") + grown_tag = "tomato" + allergen_flags = ALLERGEN_FRUIT | ALLERGEN_VEGETABLE // Which is it?? + +/datum/seed/tomato/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"tomato") + set_trait(TRAIT_PRODUCT_COLOUR,"#d10000") + set_trait(TRAIT_PLANT_ICON,"bush3") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/tomato, list(10,10)) + +/datum/seed/tomato/blood + name = "bloodtomato" + product_name = "blood tomato" + display_name = "blood tomato plant" + mutants = list("killer") + splat_type = /obj/effect/decal/cleanable/blood/splatter + allergen_flags = ALLERGEN_MEAT + +/datum/seed/tomato/blood/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_COLOUR,"#ff0000") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/blood, list(1,5)) + +/datum/seed/tomato/killer + name = "killertomato" + product_name = "killer tomato" + display_name = "killer tomato plant" + mutants = null + can_self_harvest = 1 + product_type = /mob/living/simple_animal/tomato + +/datum/seed/tomato/killer/New() + ..() + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_COLOUR,"#a86747") + +/datum/seed/tomato/blue + name = "bluetomato" + product_name = "blue tomato" + display_name = "blue tomato plant" + mutants = list("quantumato") + +/datum/seed/tomato/blue/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#4d86e8") + set_trait(TRAIT_PLANT_COLOUR,"#070aad") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/lube, list(1,5)) + +/datum/seed/tomato/blue/teleport + name = "quantumato" + product_name = "quantumato" + display_name = "quantumato plant" + mutants = null + +/datum/seed/tomato/blue/teleport/New() + ..() + set_trait(TRAIT_TELEPORTING,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#00e5ff") + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#4da4a8") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/alcohol/bluecuracao, list(10,5)) + +//Eggplants/varieties. +/datum/seed/eggplant + name = "eggplant" + product_name = "eggplant" + display_name = "eggplant vine" + mutants = list("realeggplant") + grown_tag = "eggplant" + +/datum/seed/eggplant/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"eggplant") + set_trait(TRAIT_PRODUCT_COLOUR,"#892694") + set_trait(TRAIT_PLANT_ICON,"bush4") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + +//Apples/varieties. +/datum/seed/apple + name = "apple" + product_name = "apple" + display_name = "apple tree" + mutants = list("poisonapple","goldapple") + grown_tag = "apple" + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/apple/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"apple") + set_trait(TRAIT_PRODUCT_COLOUR,"#ff540a") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_FLESH_COLOUR,"#e8e39b") + set_trait(TRAIT_IDEAL_LIGHT, 4) + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/apple, list(10,10)) + +/datum/seed/apple/poison + name = "poisonapple" + mutants = null + +/datum/seed/apple/poison/New() + ..() + set_chemical_amount(/decl/material/liquid/cyanide, list(1,5)) + +/datum/seed/apple/gold + name = "goldapple" + product_name = "golden apple" + display_name = "gold apple tree" + mutants = null + grown_tag = "goldapple" + +/datum/seed/apple/gold/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_COLOUR,"#ffdd00") + set_trait(TRAIT_PLANT_COLOUR,"#d6b44d") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/solid/metal/gold, list(1,5)) + +//Ambrosia/varieties. +/datum/seed/ambrosia + name = "ambrosiavulgaris" + product_name = "ambrosia vulgaris" + display_name = "ambrosia vulgaris patch" + mutants = list("ambrosiadeus", "hemp") + grown_tag = "ambrosiavulgaris" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/ambrosia/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"ambrosia") + set_trait(TRAIT_PRODUCT_COLOUR,"#9fad55") + set_trait(TRAIT_PLANT_ICON,"ambrosia") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + set_chemical_amount(/decl/material/liquid/psychoactives, list(1,8)) + set_chemical_amount(/decl/material/liquid/burn_meds, list(1,8,1)) + set_chemical_amount(/decl/material/liquid/brute_meds, list(1,10,1)) + set_chemical_amount(/decl/material/liquid/bromide, list(1,10)) + +/datum/seed/ambrosia/hemp + name = "hemp" + product_name = "hemp" + display_name = "hemp patch" + mutants = null + grown_tag = null + +/datum/seed/ambrosia/hemp/New() + ..() + set_chemical_amount(/decl/material/liquid/oil/plant, list(3,10)) + set_chemical_amount(/decl/material/solid/organic/cloth/hemp, list(8,1)) + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + +/datum/seed/ambrosia/deus + name = "ambrosiadeus" + product_name = "ambrosia deus" + display_name = "ambrosia deus patch" + mutants = null + grown_tag = "ambrosiadeus" + +/datum/seed/ambrosia/deus/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#a3f0ad") + set_trait(TRAIT_PLANT_COLOUR,"#2a9c61") + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + set_chemical_amount(/decl/material/liquid/brute_meds, list(1,8)) + set_chemical_amount(/decl/material/liquid/accumulated/antidepressants, list(1,8,1)) + set_chemical_amount(/decl/material/liquid/accumulated/stimulants, list(1,8,1)) + set_chemical_amount(/decl/material/liquid/amphetamines, list(1,10,1)) + set_chemical_amount(/decl/material/liquid/psychoactives, list(1,10)) + +//Mushrooms/varieties. +/datum/seed/mushroom + name = "mushrooms" + product_name = "chanterelle" + seed_noun = SEED_NOUN_SPORES + display_name = "chanterelle mushroom patch" + mutants = list("reishi","amanita","plumphelmet") + splat_type = /obj/effect/vine + grown_tag = "mushroom" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + allergen_flags = ALLERGEN_FUNGI + +/datum/seed/mushroom/make_splat(var/turf/T, var/obj/item/thrown) + if(!splat_type || (locate(splat_type) in T)) + return + new splat_type(T, src) + // No further logic; the vine will handle it. + +/datum/seed/mushroom/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"mushroom4") + set_trait(TRAIT_PRODUCT_COLOUR,"#dbda72") + set_trait(TRAIT_PLANT_COLOUR,"#d9c94e") + set_trait(TRAIT_PLANT_ICON,"mushroom") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_IDEAL_HEAT, 288) + set_trait(TRAIT_LIGHT_TOLERANCE, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,25)) + +/datum/seed/mushroom/mold + name = "mold" + product_name = "brown mold" + display_name = "brown mold patch" + mutants = null + +/datum/seed/mushroom/mold/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_PRODUCT_ICON,"mushroom5") + set_trait(TRAIT_PRODUCT_COLOUR,"#7a5f20") + set_trait(TRAIT_PLANT_COLOUR,"#7a5f20") + set_trait(TRAIT_PLANT_ICON,"mushroom9") + +/datum/seed/mushroom/plump + name = "plumphelmet" + product_name = "plump helmet" + display_name = "plump helmet mushroom patch" + mutants = list("walkingmushroom","towercap") + grown_tag = "plumphelmet" + +/datum/seed/mushroom/plump/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,2) + set_trait(TRAIT_PRODUCT_ICON,"mushroom10") + set_trait(TRAIT_PRODUCT_COLOUR,"#b57bb0") + set_trait(TRAIT_PLANT_COLOUR,"#9e4f9d") + set_trait(TRAIT_PLANT_ICON,"mushroom2") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) + set_chemical_amount(/decl/material/liquid/nutriment, list(2,10)) + +/datum/seed/mushroom/plump/walking + name = "walkingmushroom" + product_name = "walking mushroom" + display_name = "walking mushroom patch" + mutants = null + can_self_harvest = 1 + product_type = /mob/living/simple_animal/mushroom + +/datum/seed/mushroom/plump/walking/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_YIELD,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#fac0f2") + set_trait(TRAIT_PLANT_COLOUR,"#c4b1c2") + +/datum/seed/mushroom/hallucinogenic + name = "reishi" + product_name = "reishi" + display_name = "reishi patch" + mutants = list("libertycap","glowbell") + +/datum/seed/mushroom/hallucinogenic/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom11") + set_trait(TRAIT_PRODUCT_COLOUR,"#ffb70f") + set_trait(TRAIT_PLANT_COLOUR,"#f58a18") + set_trait(TRAIT_PLANT_ICON,"mushroom6") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,50)) + set_chemical_amount(/decl/material/liquid/psychotropics, list(3,5)) + +/datum/seed/mushroom/hallucinogenic/strong + name = "libertycap" + product_name = "liberty cap" + display_name = "liberty cap mushroom patch" + mutants = null + +/datum/seed/mushroom/hallucinogenic/strong/New() + ..() + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom8") + set_trait(TRAIT_PRODUCT_COLOUR,"#f2e550") + set_trait(TRAIT_PLANT_COLOUR,"#d1ca82") + set_trait(TRAIT_PLANT_ICON,"mushroom3") + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + set_chemical_amount(/decl/material/liquid/sedatives, list(3,3)) + set_chemical_amount(/decl/material/liquid/psychoactives, list(1,25)) + +/datum/seed/mushroom/poison + name = "amanita" + product_name = "fly amanita" + display_name = "fly amanita mushroom patch" + mutants = list("destroyingangel","plastic") + +/datum/seed/mushroom/poison/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"mushroom") + set_trait(TRAIT_PRODUCT_COLOUR,"#ff4545") + set_trait(TRAIT_LEAVES_COLOUR,"#ff4545") // to make it so they aren't pale while immature + set_trait(TRAIT_PLANT_COLOUR,"#e0ddba") + set_trait(TRAIT_PLANT_ICON,"mushroom4") + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + set_chemical_amount(/decl/material/liquid/amatoxin, list(3,3)) + set_chemical_amount(/decl/material/liquid/psychotropics, list(1,25)) + +/datum/seed/mushroom/poison/death + name = "destroyingangel" + product_name = "destroying angel" + display_name = "destroying angel mushroom patch" + mutants = null + +/datum/seed/mushroom/poison/death/New() + ..() + set_trait(TRAIT_MATURATION,12) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,35) + set_trait(TRAIT_PRODUCT_ICON,"mushroom3") + set_trait(TRAIT_PRODUCT_COLOUR,"#ede8ea") + set_trait(TRAIT_PLANT_COLOUR,"#e6d8dd") + set_trait(TRAIT_PLANT_ICON,"mushroom5") + set_trait(TRAIT_LEAVES_COLOUR,null) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,50)) + set_chemical_amount(/decl/material/liquid/amatoxin, list(13,3)) + set_chemical_amount(/decl/material/liquid/psychotropics, list(1,25)) + +/datum/seed/mushroom/towercap + name = "towercap" + product_name = "dwarf towercap" + display_name = "dwarf towercap thicket" + mutants = null + product_type = /obj/item/stack/material/log/towercap + +/obj/item/stack/material/log/towercap + material = /decl/material/solid/organic/wood/fungal + +/datum/seed/mushroom/towercap/New() + ..() + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom7") + set_trait(TRAIT_PRODUCT_COLOUR,"#d3aca3") + set_trait(TRAIT_PLANT_COLOUR,"#dcd9d9") + set_trait(TRAIT_PLANT_ICON,"mushroom8") + set_chemical_amount(/decl/material/solid/organic/wood/fungal, list(10,1)) + +/datum/seed/mushroom/glowbell + name = "glowbell" + product_name = "glowbell" + display_name = "glowbell patch" + mutants = list("weepingmoon", "caverncandle") + +/datum/seed/mushroom/glowbell/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#9eefff") + set_trait(TRAIT_PRODUCT_ICON,"mushroom2") + set_trait(TRAIT_PRODUCT_COLOUR,"#90d7f0") + set_trait(TRAIT_PLANT_COLOUR,"#75bdd7") + set_trait(TRAIT_PLANT_ICON,"mushroom2") + set_chemical_amount(/decl/material/liquid/glowsap, list(1,20)) + +/datum/seed/mushroom/weepingmoon + name = "weepingmoon" + product_name = "weeping moon" + display_name = "weeping moon patch" + mutants = null + +/datum/seed/mushroom/weepingmoon/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#9eefff") + set_trait(TRAIT_PRODUCT_ICON,"mushroom4") + set_trait(TRAIT_PRODUCT_COLOUR,"#90d7f0") + set_trait(TRAIT_PLANT_COLOUR,"#75bdd7") + set_trait(TRAIT_PLANT_ICON,"mushroom4") + set_chemical_amount(/decl/material/liquid/glowsap, list(1,20)) + +/datum/seed/mushroom/caverncandle + name = "caverncandle" + product_name = "caverncandle" + display_name = "cavern candle patch" + mutants = null + +/datum/seed/mushroom/caverncandle/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#9eefff") + set_trait(TRAIT_PRODUCT_ICON,"mushroom3") + set_trait(TRAIT_PRODUCT_COLOUR,"#90d7f0") + set_trait(TRAIT_PLANT_COLOUR,"#75bdd7") + set_trait(TRAIT_PLANT_ICON,"mushroom3") + set_chemical_amount(/decl/material/liquid/glowsap, list(1,20)) + +/datum/seed/mushroom/plastic + name = "plastic" + product_name = "plastellium" + display_name = "plastellium patch" + mutants = null + +/datum/seed/mushroom/plastic/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"mushroom6") + set_trait(TRAIT_PRODUCT_COLOUR,"#e6e6e6") + set_trait(TRAIT_PLANT_COLOUR,"#e6e6e6") + set_trait(TRAIT_PLANT_ICON,"mushroom10") + set_chemical_amount(/decl/material/liquid/plasticide, list(1,10)) + +//Flowers/varieties +/datum/seed/flower + name = "harebells" + product_name = "harebell" + display_name = "harebell patch" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + produces_pollen = 1 + +/datum/seed/flower/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_ICON,"flower5") + set_trait(TRAIT_PRODUCT_COLOUR,"#c492d6") + set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") + set_trait(TRAIT_PLANT_ICON,"flower") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + +/datum/seed/flower/poppy + name = "poppies" + product_name = "poppy" + display_name = "poppy patch" + grown_tag = "poppy" + +/datum/seed/flower/poppy/New() + ..() + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_PRODUCT_ICON,"flower3") + set_trait(TRAIT_PRODUCT_COLOUR,"#b33715") + set_trait(TRAIT_PLANT_ICON,"flower3") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/painkillers/strong, list(1,10)) + +/datum/seed/flower/sunflower + name = "sunflowers" + product_name = "sunflower" + display_name = "sunflower patch" + +/datum/seed/flower/sunflower/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCT_ICON,"flower2") + set_trait(TRAIT_PRODUCT_COLOUR,"#fff700") + set_trait(TRAIT_PLANT_ICON,"flower2") + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/oil/plant, list(10,10)) + +/datum/seed/flower/lavender + name = "lavender" + product_name = "lavender" + display_name = "lavender patch" + +/datum/seed/flower/lavender/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"flower6") + set_trait(TRAIT_PRODUCT_COLOUR,"#b57edc") + set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") + set_trait(TRAIT_PLANT_ICON,"flower4") + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.05) + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/brute_meds, list(1,10)) + +//Grapes/varieties +/datum/seed/grapes + name = "grapes" + product_name = "grapes" + display_name = "grapevine" + mutants = list("greengrapes") + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/grapes/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"grapes") + set_trait(TRAIT_PRODUCT_COLOUR,"#bb6ac4") + set_trait(TRAIT_PLANT_COLOUR,"#378f2e") + set_trait(TRAIT_PLANT_ICON,"vine") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/nutriment/sugar, list(1,5)) + set_chemical_amount(/decl/material/liquid/drink/juice/grape, list(10,10)) + +/datum/seed/grapes/green + name = "greengrapes" + product_name = "green grapes" + display_name = "green grapevine" + mutants = null + +/datum/seed/grapes/green/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/burn_meds, list(3,5)) + set_chemical_amount(/decl/material/liquid/drink/juice/grape, list(10,10)) + +//Everything else +/datum/seed/peanuts + name = "peanut" + product_name = "peanut" + display_name = "peanut vine" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + allergen_flags = ALLERGEN_NUTS + +/datum/seed/peanuts/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"nuts") + set_trait(TRAIT_PRODUCT_COLOUR,"#c4ae7a") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/oil/plant, list(1,10)) + +/datum/seed/peppercorn + name = "peppercorn" + product_name = "peppercorn" + display_name = "black pepper plant" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + +/datum/seed/peppercorn/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"nuts") + set_trait(TRAIT_PRODUCT_COLOUR,"#4d4d4d") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_chemical_amount(/decl/material/solid/blackpepper, list(10,10)) + +/datum/seed/cabbage + name = "cabbage" + product_name = "cabbage" + display_name = "cabbage patch" + grown_tag = "cabbage" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/cabbage/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"cabbage") + set_trait(TRAIT_PRODUCT_COLOUR,"#84bd82") + set_trait(TRAIT_PLANT_COLOUR,"#6d9c6b") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + +/datum/seed/banana + name = "banana" + product_name = "banana" + display_name = "banana tree" + trash_type = /obj/item/bananapeel + grown_tag = "banana" + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/banana/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_ICON,"bananas") + set_trait(TRAIT_PRODUCT_COLOUR,"#ffec1f") + set_trait(TRAIT_PLANT_COLOUR,"#69ad50") + set_trait(TRAIT_PLANT_ICON,"tree4") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/drink/juice/banana, list(10,10)) + set_chemical_amount(/decl/material/solid/potassium, list(2,3)) + +/datum/seed/corn + name = "corn" + product_name = "corn" + display_name = "ears of corn" + grown_tag = "corn" + trash_type = /obj/item/corncob + backyard_grilling_product = /obj/item/food/popcorn + backyard_grilling_announcement = "pops enthusiastically!" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/corn/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"corn") + set_trait(TRAIT_PRODUCT_COLOUR,"#fff23b") + set_trait(TRAIT_PLANT_COLOUR,"#87c969") + set_trait(TRAIT_PLANT_ICON,"corn") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/oil/plant/corn, list(1,10)) + +/datum/seed/potato + name = "potato" + product_name = "potato" + display_name = "potato patch" + grown_tag = "potato" + grown_is_seed = TRUE + min_seed_extracted = 0 + max_seed_extracted = 0 + slice_product = /obj/item/food/processed_grown/sticks + slice_amount = 3 + +/datum/seed/potato/New() + ..() + set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"potato") + set_trait(TRAIT_PRODUCT_COLOUR,"#d4cab4") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/potato, list(10,10)) + +/datum/seed/garlic + name = "garlic" + product_name = "garlic" + display_name = "garlic plant" + grown_tag = "garlic" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + grown_is_seed = TRUE + min_seed_extracted = 0 + max_seed_extracted = 0 + allergen_flags = ALLERGEN_ALLIUM + +/datum/seed/garlic/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,12) + set_trait(TRAIT_PRODUCT_ICON,"bulb") + set_trait(TRAIT_PRODUCT_COLOUR,"#fff8dd") + set_trait(TRAIT_PLANT_ICON,"stalk") + set_trait(TRAIT_WATER_CONSUMPTION, 7) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/garlic, list(10,10)) + +/datum/seed/onion + name = "onion" + product_name = "onion" + display_name = "onion patch" + grown_tag = "onion" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + allergen_flags = ALLERGEN_ALLIUM + +/datum/seed/onion/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"bulb") + set_trait(TRAIT_PRODUCT_COLOUR,"#ffeedd") + set_trait(TRAIT_PLANT_ICON,"stalk") + set_trait(TRAIT_WATER_CONSUMPTION, 5) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/drink/juice/onion, list(10,10)) + +/datum/seed/soybean + name = "soybeans" + product_name = "soybeans" + display_name = "soybean patch" + grown_tag = "soybeans" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + allergen_flags = ALLERGEN_SOY + +/datum/seed/soybean/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"bean") + set_trait(TRAIT_PRODUCT_COLOUR,"#ebe7c0") + set_trait(TRAIT_PLANT_ICON,"stalk") + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/oil/plant, list(3,20)) + set_chemical_amount(/decl/material/liquid/drink/milk/soymilk, list(7,20)) + +/datum/seed/wheat + name = "wheat" + product_name = "wheat" + display_name = "wheat patch" + grown_tag = "wheat" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + allergen_flags = ALLERGEN_VEGETABLE | ALLERGEN_GLUTEN + +/datum/seed/wheat/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"wheat") + set_trait(TRAIT_PRODUCT_COLOUR,"#dbd37d") + set_trait(TRAIT_PLANT_COLOUR,"#bfaf82") + set_trait(TRAIT_PLANT_ICON,"stalk2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,25)) + set_chemical_amount(/decl/material/liquid/nutriment/flour, list(15,15)) + +/datum/seed/rice + name = "rice" + product_name = "rice" + display_name = "rice paddy" + grown_tag = "rice" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + allergen_flags = ALLERGEN_VEGETABLE | ALLERGEN_GLUTEN + +/datum/seed/rice/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"rice") + set_trait(TRAIT_PRODUCT_COLOUR,"#d5e6d1") + set_trait(TRAIT_PLANT_COLOUR,"#8ed17d") + set_trait(TRAIT_PLANT_ICON,"stalk2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,25)) + set_chemical_amount(/decl/material/liquid/nutriment/rice, list(10,15)) + +/datum/seed/carrots + name = "carrot" + product_name = "carrot" + display_name = "carrot patch" + grown_tag = "carrot" + slice_product = /obj/item/food/processed_grown/sticks + slice_amount = 3 + +/datum/seed/carrots/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"carrot") + set_trait(TRAIT_PRODUCT_COLOUR,"#ff9900") + set_trait(TRAIT_PLANT_ICON,"carrot") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/eyedrops, list(3,5)) + set_chemical_amount(/decl/material/liquid/drink/juice/carrot, list(10,20)) + +/datum/seed/weeds + name = "weeds" + product_name = "weed" + display_name = "weeds" + +/datum/seed/weeds/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_POTENCY,-1) + set_trait(TRAIT_IMMUTABLE,-1) + set_trait(TRAIT_PRODUCT_ICON,"flower4") + set_trait(TRAIT_PRODUCT_COLOUR,"#fceb2b") + set_trait(TRAIT_PLANT_COLOUR,"#59945a") + set_trait(TRAIT_PLANT_ICON,"bush6") + +/datum/seed/whitebeets + name = "whitebeet" + product_name = "white-beet" + display_name = "white-beet patch" + grown_tag = "whitebeet" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/whitebeets/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"carrot2") + set_trait(TRAIT_PRODUCT_COLOUR,"#eef5b0") + set_trait(TRAIT_PLANT_COLOUR,"#4d8f53") + set_trait(TRAIT_PLANT_ICON,"carrot2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(0,20)) + set_chemical_amount(/decl/material/liquid/nutriment/sugar, list(1,5)) + +/datum/seed/sugarcane + name = "sugarcane" + product_name = "sugarcane" + display_name = "sugarcane patch" + +/datum/seed/sugarcane/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"stalk") + set_trait(TRAIT_PRODUCT_COLOUR,"#b4d6bd") + set_trait(TRAIT_PLANT_COLOUR,"#6bbd68") + set_trait(TRAIT_PLANT_ICON,"stalk3") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_chemical_amount(/decl/material/liquid/nutriment/sugar, list(4,5)) + +/datum/seed/watermelon + name = "watermelon" + product_name = "watermelon" + display_name = "watermelon vine" + product_w_class = ITEM_SIZE_LARGE + slice_product = /obj/item/food/processed_grown/slice/large + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/watermelon/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"vine") + set_trait(TRAIT_PRODUCT_COLOUR,"#326b30") + set_trait(TRAIT_PLANT_COLOUR,"#257522") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_FLESH_COLOUR,"#f22c2c") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,6)) + set_chemical_amount(/decl/material/liquid/drink/juice/watermelon, list(10,6)) + +/datum/seed/pumpkin + name = "pumpkin" + product_name = "pumpkin" + display_name = "pumpkin vine" + product_w_class = ITEM_SIZE_LARGE + grown_tag = "pumpkin" + slice_product = /obj/item/clothing/head/pumpkinhead + slice_amount = 1 + +/datum/seed/pumpkin/show_slice_message(mob/user, obj/item/tool, obj/item/food/grown/sliced) + sliced.visible_message(SPAN_NOTICE("\The [user] carves a face into \the [sliced] with \the [tool].")) + return TRUE + +/datum/seed/pumpkin/show_slice_message_poor(mob/user, obj/item/tool, obj/item/food/grown/sliced) + sliced.visible_message(SPAN_NOTICE("\The [user] crudely carves a face into \the [sliced] with \the [tool].")) + return TRUE + +/datum/seed/pumpkin/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"vine2") + set_trait(TRAIT_PRODUCT_COLOUR,"#f9ab28") + set_trait(TRAIT_PLANT_COLOUR,"#bae8c1") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,6)) + +/datum/seed/citrus + name = "lime" + product_name = "lime" + display_name = "lime tree" + grown_tag = "lime" + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/citrus/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#3af026") + set_trait(TRAIT_PLANT_ICON,"tree") + set_trait(TRAIT_FLESH_COLOUR,"#3af026") + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/drink/juice/lime, list(10,20)) + +/datum/seed/citrus/lemon + name = "lemon" + product_name = "lemon" + display_name = "lemon tree" + grown_tag = "lemon" + +/datum/seed/citrus/lemon/New() + ..() + set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#f0e226") + set_trait(TRAIT_FLESH_COLOUR,"#f0e226") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/drink/juice/lemon, list(10,20)) + +/datum/seed/citrus/orange + name = "orange" + product_name = "orange" + display_name = "orange tree" + grown_tag = "orange" + +/datum/seed/citrus/orange/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#ffc20a") + set_trait(TRAIT_FLESH_COLOUR,"#ffc20a") + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + set_chemical_amount(/decl/material/liquid/drink/juice/orange, list(10,20)) + +/datum/seed/grass + name = "grass" + product_name = "grass" + display_name = "grass patch" + grown_tag = "grass" + product_type = /obj/item/stack/material/bundle/grass + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/grass/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,2) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"grass") + set_trait(TRAIT_PRODUCT_COLOUR,"#09ff00") + set_trait(TRAIT_PLANT_COLOUR,"#07d900") + set_trait(TRAIT_PLANT_ICON,"grass") + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,20)) + +/datum/seed/cocoa + name = "cocoa" + product_name = "cacao" + display_name = "cacao tree" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + +/datum/seed/cocoa/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#cca935") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,10)) + set_chemical_amount(/decl/material/liquid/nutriment/coco, list(4,5)) + +/datum/seed/cherries + name = "cherry" + product_name = "cherry" + seed_noun = SEED_NOUN_PITS + display_name = "cherry tree" + grown_tag = "cherries" + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + allergen_flags = ALLERGEN_FRUIT + +/datum/seed/cherries/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"cherry") + set_trait(TRAIT_PRODUCT_COLOUR,"#a80000") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_PLANT_COLOUR,"#2f7d2d") + set_trait(TRAIT_PHOTOSYNTHESIS, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,15)) + set_chemical_amount(/decl/material/liquid/nutriment/sugar, list(1,15)) + set_chemical_amount(/decl/material/liquid/nutriment/cherryjelly, list(10,15)) + +/datum/seed/kudzu + name = "kudzu" + product_name = "kudzu" + display_name = "kudzu vine" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/kudzu/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_SPREAD,2) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#96d278") + set_trait(TRAIT_PLANT_COLOUR,"#6f7a63") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,50)) + set_chemical_amount(/decl/material/liquid/antitoxins, list(1,25)) + +/datum/seed/shand + name = "shand" + product_name = "S'randar's hand" + display_name = "S'randar's hand patch" + grown_tag = "shand" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/shand/New() + ..() + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"alien3") + set_trait(TRAIT_PRODUCT_COLOUR,"#378c61") + set_trait(TRAIT_PLANT_COLOUR,"#378c61") + set_trait(TRAIT_PLANT_ICON,"tree5") + set_trait(TRAIT_IDEAL_HEAT, 283) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/brute_meds, list(0,10)) + +/datum/seed/mtear + name = "mtear" + product_name = "Messa's tear" + display_name = "Messa's tear patch" + grown_tag = "mtear" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/mtear/New() + ..() + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"alien4") + set_trait(TRAIT_PRODUCT_COLOUR,"#4cc5c7") + set_trait(TRAIT_PLANT_COLOUR,"#4cc789") + set_trait(TRAIT_PLANT_ICON,"bush7") + set_trait(TRAIT_IDEAL_HEAT, 283) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment/honey, list(1,10)) + set_chemical_amount(/decl/material/liquid/burn_meds, list(3,5)) + +/datum/seed/tobacco + name = "tobacco" + product_name = "tobacco" + display_name = "tobacco plant" + mutants = list("finetobacco", "puretobacco", "badtobacco") + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + product_w_class = ITEM_SIZE_TINY // so that it can fit in bags of tobacco + +/datum/seed/tobacco/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"tobacco") + set_trait(TRAIT_PRODUCT_COLOUR,"#749733") + set_trait(TRAIT_PLANT_COLOUR,"#749733") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IDEAL_HEAT, 299) + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/solid/tobacco, list(1,10)) + +/datum/seed/tobacco/finetobacco + name = "finetobacco" + product_name = "fine tobacco" + display_name = "fine tobacco plant" + +/datum/seed/tobacco/finetobacco/New() + ..() + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_PRODUCT_COLOUR,"#33571b") + set_trait(TRAIT_PLANT_COLOUR,"#33571b") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.20) + set_chemical_amount(/decl/material/solid/tobacco/fine, list(1,10)) + +/datum/seed/tobacco/puretobacco //provides the pure nicotine reagent + name = "puretobacco" + product_name = "succulent tobacco" + display_name = "succulent tobacco plant" + +/datum/seed/tobacco/puretobacco/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#b7c61a") + set_trait(TRAIT_PLANT_COLOUR,"#b7c61a") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.30) + set_chemical_amount(/decl/material/liquid/nicotine, list(1,10)) + +/datum/seed/tobacco/bad + name = "badtobacco" + product_name = "low-grade tobacco" + display_name = "low-grade tobacco plant" + mutants = list("tobacco") + +/datum/seed/tobacco/bad/New() + ..() + set_chemical_amount(/decl/material/solid/tobacco/bad, list(1,10)) + +/datum/seed/algae + name = "algae" + product_name = "algae" + display_name = "algae patch" + grown_tag = "algae" + exude_gasses = list(/decl/material/gas/methyl_bromide = 3) + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + +/datum/seed/algae/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"algae") + set_trait(TRAIT_PRODUCT_COLOUR,"#84bd82") + set_trait(TRAIT_PLANT_COLOUR,"#6d9c6b") + set_trait(TRAIT_PLANT_ICON,"algae") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment, list(2,12)) + set_chemical_amount(/decl/material/liquid/bromide, list(3,8)) + +/datum/seed/bamboo + name = "bamboo" + product_name = "bamboo" + display_name = "bamboo thicket" + mutants = null + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + +/datum/seed/bamboo/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"stalk") + set_trait(TRAIT_PRODUCT_COLOUR, WOOD_COLOR_GENERIC) + set_trait(TRAIT_PLANT_COLOUR,"#99bc20") + set_trait(TRAIT_PLANT_ICON,"stalk3") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_chemical_amount(/decl/material/solid/organic/wood/bamboo, list(6,1)) + +/datum/seed/tea + name = "tea" + product_name = "tea leaf" + display_name = "tea plant" + slice_product = /obj/item/food/processed_grown/chopped + slice_amount = 3 + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT + +/datum/seed/tea/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,TRUE) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"tobacco") + set_trait(TRAIT_PRODUCT_COLOUR,"#749733") + set_trait(TRAIT_PLANT_COLOUR,"#749733") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IDEAL_HEAT, 299) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + set_chemical_amount(/decl/material/liquid/nutriment/tea, list(10,10), _state = PLANT_STATE_DRIED) + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) + +/datum/seed/coffee + name = "coffee" + product_name = "coffee cherries" + display_name = "coffee plant" + backyard_grilling_product = /obj/item/food/grown/grilled + backyard_grilling_announcement = "roasts and darkens." + product_material = /decl/material/solid/organic/plantmatter/pith + slice_product = /obj/item/food/processed_grown/crushed + slice_amount = 3 + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT + +/datum/seed/coffee/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,TRUE) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#a80000") + set_trait(TRAIT_PLANT_COLOUR,"#7acf3c") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_IDEAL_HEAT, 299) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + + set_chemical_amount(/decl/material/liquid/nutriment/coffee, list(10,10), _state = PLANT_STATE_ROASTED) + set_chemical_amount(/decl/material/liquid/nutriment, list(1)) diff --git a/code/modules/hydroponics/processed_grown.dm b/code/modules/hydroponics/processed_grown.dm new file mode 100644 index 000000000000..02503337e9d6 --- /dev/null +++ b/code/modules/hydroponics/processed_grown.dm @@ -0,0 +1,150 @@ +/obj/item/food/processed_grown + abstract_type = /obj/item/food/processed_grown + is_spawnable_type = FALSE + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + center_of_mass = @'{"x":16,"y":16}' + bitesize = 2 + material = /decl/material/solid/organic/plantmatter + + // We get these from being sliced. + nutriment_type = null + nutriment_amt = 0 + + /// Flag for drawing the skin/rind or not. + var/draw_rind = TRUE + /// Reference to the originating seed datum we were produced from. + var/datum/seed/seed + /// Used in recipes to distinguish between general types. + var/processed_grown_tag + +/obj/item/food/processed_grown/Initialize(mapload, material_key, skip_plate = FALSE, _seed) + + if(isnull(seed) && _seed) + seed = _seed + + if(istext(seed)) + seed = SSplants.seeds[seed] + + if(!istype(seed)) + PRINT_STACK_TRACE("Processed grown initializing with null or invalid seed type '[seed || "NULL"]'") + return INITIALIZE_HINT_QDEL + + . = ..() + + filling_color = seed.get_trait(TRAIT_PRODUCT_COLOUR) || seed.get_trait(TRAIT_FLESH_COLOUR) + dried_type = type + update_strings() + update_icon() + +/obj/item/food/processed_grown/get_grown_tag() + if(!processed_grown_tag || !seed?.grown_tag) + return + . = dry ? "dried [seed.grown_tag] [processed_grown_tag]" : "[seed.grown_tag] [processed_grown_tag]" + +/obj/item/food/processed_grown/create_slice() + return new slice_path(loc, material?.type, TRUE, seed) + +/obj/item/food/processed_grown/proc/update_strings() + return + +/obj/item/food/processed_grown/on_update_icon() + . = ..() + if(!istype(seed)) + return + icon_state = get_world_inventory_state() + var/rind_colour = seed.get_trait(TRAIT_PRODUCT_COLOUR) + color = seed.get_trait(TRAIT_FLESH_COLOUR) || rind_colour + if(draw_rind) + var/image/rind = image(icon, "[icon_state]-rind") + rind.color = rind_colour || color + rind.appearance_flags |= RESET_COLOR + add_overlay(rind) + +// Fruit slices. TODO: seed color so orange slices don't get black seeds. +/obj/item/food/processed_grown/slice + name = "fruit slice" + icon = 'icons/obj/grown/fruit_slice.dmi' + processed_grown_tag = "slice" + slice_path = /obj/item/food/processed_grown/chopped + slice_num = 1 + +// Purely a visual distinction. +/obj/item/food/processed_grown/slice/large + icon = 'icons/obj/grown/fruit_slice_large.dmi' + +/obj/item/food/processed_grown/slice/update_strings() + name = "slice of [seed.product_name]" + desc = "A slice of \a [seed.product_name]. Tasty, probably." + +// Chopped fruit or veg +/obj/item/food/processed_grown/chopped + name = "chopped produce" + icon = 'icons/obj/grown/chopped.dmi' + processed_grown_tag = "chopped" + +/obj/item/food/processed_grown/chopped/update_strings() + name = "chopped [seed.product_name]" + desc = "A handful of roughly chopped [seed.product_name]." + +// Matchstick veg +/obj/item/food/processed_grown/sticks + name = "vegetable sticks" + icon = 'icons/obj/grown/sticks.dmi' + gender = PLURAL + draw_rind = FALSE + processed_grown_tag = "sticks" + slice_path = /obj/item/food/processed_grown/chopped + slice_num = 1 + +/obj/item/food/processed_grown/sticks/update_strings() + name = "[seed.product_name] sticks" + desc = "A handful of [seed.product_name] sticks." + +// Crushed nuts/bulbs/flowers +/obj/item/food/processed_grown/crushed + name = "crushed produce" + icon = 'icons/obj/grown/crushed.dmi' + gender = PLURAL + processed_grown_tag = "crushed" + +/obj/item/food/processed_grown/crushed/update_strings() + name = "crushed [seed.product_name]" + desc = "A handful of crushed [seed.product_name]." + +// Premade types for mapping +/obj/item/food/processed_grown/slice/apple + seed = "apple" + is_spawnable_type = TRUE + nutriment_type = /decl/material/liquid/drink/juice/apple + nutriment_amt = 2 + +/obj/item/food/processed_grown/slice/large/watermelon + seed = "watermelon" + is_spawnable_type = TRUE + nutriment_type = /decl/material/liquid/drink/juice/watermelon + nutriment_amt = 2 + +/obj/item/food/processed_grown/sticks/carrot + seed = "carrot" + is_spawnable_type = TRUE + nutriment_type = /decl/material/liquid/drink/juice/carrot + nutriment_amt = 2 + +/obj/item/food/processed_grown/sticks/potato + seed = "potato" + is_spawnable_type = TRUE + nutriment_type = /decl/material/liquid/drink/juice/potato + nutriment_amt = 2 + +/obj/item/food/processed_grown/chopped/soy + seed = "soybeans" + is_spawnable_type = TRUE + nutriment_type = /decl/material/liquid/drink/milk/soymilk + nutriment_amt = 2 + +/obj/item/food/processed_grown/crushed/garlic + seed = "garlic" + is_spawnable_type = TRUE + nutriment_type = /decl/material/liquid/drink/juice/garlic + nutriment_amt = 2 diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 8b9fc3d86842..9aa93b32bfb0 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -1,12 +1,11 @@ -/datum/plantgene - var/genetype // Label used when applying trait. - var/list/values // Values to copy into the target seed datum. +/datum/codex_entry/scannable/flora + category = /decl/codex_category/flora /datum/seed //Tracking. var/uid // Unique identifier. var/name // Index for global list. - var/seed_name // Plant name for seed packet. + var/product_name // Plant name for seed packet and product strings. var/seed_noun = SEED_NOUN_SEEDS// Descriptor for packet. var/display_name // Prettier name. var/roundstart // If set, seed will not display variety number. @@ -14,75 +13,80 @@ var/scanned // If it was scanned with a plant analyzer. var/can_self_harvest = 0 // Mostly used for living mobs. var/growth_stages = 0 // Number of stages the plant passes through before it is mature. - var/list/traits = list() // Initialized in New() + var/list/_traits // Initialized in New() var/list/mutants // Possible predefined mutant varieties, if any. - var/list/chems // Chemicals that plant produces in products/injects into victim. var/list/consume_gasses // The plant will absorb these gasses during its life. var/list/exude_gasses // The plant will exude these gasses during its life. - var/kitchen_tag // Used by the reagent grinder. + var/grown_tag // Used by the reagent grinder. var/trash_type // Garbage item produced when eaten. var/splat_type = /obj/effect/decal/cleanable/fruit_smudge // Graffiti decal. - var/has_mob_product + var/product_type = /obj/item/food/grown + var/product_material var/force_layer var/req_CO2_moles = 1.0// Moles of CO2 required for photosynthesis. + var/hydrotray_only + var/base_seed_value = 5 // Used when generating price. + var/scannable_result + var/grown_is_seed = FALSE + var/product_w_class = ITEM_SIZE_SMALL + var/produces_pollen = 0 + + // Dissection values. + var/min_seed_extracted = 1 + var/max_seed_extracted = 2 + var/slice_product = /obj/item/food/processed_grown/slice + var/slice_amount = 5 + + // Cached images for overlays + var/image/dead_overlay + var/image/harvest_overlay + var/list/growing_overlays + + // Backyard grilling vars. Not passed through genetics. + var/backyard_grilling_rawness = 20 + var/backyard_grilling_product = /obj/item/food/badrecipe + var/backyard_grilling_announcement = "smokes and chars!" + + // Used to show an icon when drying in a rack. + var/drying_state = "grown" + + // Used to set allergens on growns. + var/allergen_flags = ALLERGEN_VEGETABLE /datum/seed/New() - - set_trait(TRAIT_IMMUTABLE, 0) // If set, plant will never mutate. If -1, plant is highly mutable. - set_trait(TRAIT_HARVEST_REPEAT, 0) // If 1, this plant will fruit repeatedly. - set_trait(TRAIT_PRODUCES_POWER, 0) // Can be used to make a battery. - set_trait(TRAIT_JUICY, 0) // When thrown, causes a splatter decal. - set_trait(TRAIT_EXPLOSIVE, 0) // When thrown, acts as a grenade. - set_trait(TRAIT_CARNIVOROUS, 0) // 0 = none, 1 = eat pests in tray, 2 = eat living things (when a vine). - set_trait(TRAIT_PARASITE, 0) // 0 = no, 1 = gain health from weed level. - set_trait(TRAIT_STINGS, 0) // Can cause damage/inject reagents when thrown or handled. - set_trait(TRAIT_YIELD, 0) // Amount of product. - set_trait(TRAIT_SPREAD, 0) // 0 limits plant to tray, 1 = creepers, 2 = vines. - set_trait(TRAIT_MATURATION, 0) // Time taken before the plant is mature. - set_trait(TRAIT_PRODUCTION, 0) // Time before harvesting can be undertaken again. - set_trait(TRAIT_TELEPORTING, 0) // Uses the teleport tomato effect. - set_trait(TRAIT_BIOLUM, 0) // Plant is bioluminescent. - set_trait(TRAIT_ALTER_TEMP, 0) // If set, the plant will periodically alter local temp by this amount. - set_trait(TRAIT_PRODUCT_ICON, 0) // Icon to use for fruit coming from this plant. - set_trait(TRAIT_PLANT_ICON, 0) // Icon to use for the plant growing in the tray. - set_trait(TRAIT_PRODUCT_COLOUR, 0) // Colour to apply to product icon. - set_trait(TRAIT_BIOLUM_COLOUR, 0) // The colour of the plant's radiance. - set_trait(TRAIT_POTENCY, 1) // General purpose plant strength value. - set_trait(TRAIT_REQUIRES_NUTRIENTS, 1) // The plant can starve. - set_trait(TRAIT_REQUIRES_WATER, 1) // The plant can become dehydrated. - set_trait(TRAIT_WATER_CONSUMPTION, 3) // Plant drinks this much per tick. - set_trait(TRAIT_LIGHT_TOLERANCE, 3) // Departure from ideal that is survivable. - set_trait(TRAIT_TOXINS_TOLERANCE, 5) // Resistance to poison. - set_trait(TRAIT_PEST_TOLERANCE, 5) // Threshold for pests to impact health. - set_trait(TRAIT_WEED_TOLERANCE, 5) // Threshold for weeds to impact health. - set_trait(TRAIT_IDEAL_LIGHT, 5) // Preferred light level in luminosity. - set_trait(TRAIT_HEAT_TOLERANCE, 20) // Departure from ideal that is survivable. - set_trait(TRAIT_LOWKPA_TOLERANCE, 25) // Low pressure capacity. - set_trait(TRAIT_ENDURANCE, 100) // Maximum plant HP when growing. - set_trait(TRAIT_HIGHKPA_TOLERANCE, 200) // High pressure capacity. - set_trait(TRAIT_IDEAL_HEAT, 293) // Preferred temperature in Kelvin. - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) // Plant eats this much per tick. - set_trait(TRAIT_PLANT_COLOUR, "#46b543") // Colour of the plant icon. - set_trait(TRAIT_PHOTOSYNTHESIS, 1) // If it turns CO2 into oxygen - update_growth_stages() + uid = "[sequential_id(/datum/seed)]" - uid = "[sequential_id(/datum/seed/)]" - -/datum/seed/proc/get_trait(var/trait) - return traits["[trait]"] +// TODO integrate other traits. +/datum/seed/proc/get_monetary_value() + . = 1 + for(var/decl/plant_trait/plant_trait in decls_repository.get_decls_of_subtype_unassociated(/decl/plant_trait)) + . += plant_trait.get_worth_of_value(get_trait(plant_trait.type)) + . = max(1, round(. * base_seed_value)) /datum/seed/proc/get_trash_type() return trash_type -/datum/seed/proc/set_trait(var/trait,var/nval,var/ubound,var/lbound, var/degrade) - if(!isnull(degrade)) nval *= degrade - if(!isnull(ubound)) nval = min(nval,ubound) - if(!isnull(lbound)) nval = max(nval,lbound) - traits["[trait]"] = nval +/datum/seed/proc/set_trait(var/trait, var/nval, var/ubound, var/lbound, var/degrade) + if(!isnull(degrade)) + nval *= degrade + if(!isnull(ubound)) + nval = min(nval,ubound) + if(!isnull(lbound)) + nval = max(nval,lbound) + + var/decl/plant_trait/plant_trait = GET_DECL(trait) + if(!istype(plant_trait) || nval == plant_trait.default_value) + LAZYREMOVE(_traits, trait) + else + LAZYSET(_traits, trait, nval) + plant_trait.handle_post_trait_set(src) - if(trait == TRAIT_PLANT_ICON) - update_growth_stages() +/datum/seed/proc/get_trait(var/trait) + if(trait in _traits) + return _traits[trait] + var/decl/plant_trait/plant_trait = GET_DECL(trait) + return plant_trait.default_value /datum/seed/proc/create_spores(var/turf/T) if(!T) @@ -92,9 +96,10 @@ if(!T) return - var/datum/reagents/R = new/datum/reagents(100, GLOB.temp_reagents_holder) - if(chems.len) - for(var/rid in chems) + var/datum/reagents/R = new/datum/reagents(100, global.temp_reagents_holder) + var/list/seed_chems = get_chemical_composition() + if(length(seed_chems)) + for(var/rid in seed_chems) var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/3)) R.add_reagent(rid,injecting) @@ -105,68 +110,68 @@ qdel(R) // Does brute damage to a target. -/datum/seed/proc/do_thorns(var/mob/living/carbon/human/target, var/obj/item/fruit, var/target_limb) +/datum/seed/proc/do_thorns(var/mob/living/human/target, var/obj/item/fruit, var/target_limb) if(!get_trait(TRAIT_CARNIVOROUS)) return if(!istype(target)) - if(istype(target, /mob/living/simple_animal/mouse)) + if(ismouse(target)) new /obj/item/remains/mouse(get_turf(target)) qdel(target) - else if(istype(target, /mob/living/simple_animal/lizard)) + else if(islizard(target)) new /obj/item/remains/lizard(get_turf(target)) qdel(target) return - - if(!target_limb) target_limb = pick(BP_ALL_LIMBS) - var/obj/item/organ/external/affecting = target.get_organ(target_limb) - - if((target.species && target.species.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT))) + var/obj/item/organ/external/affecting = target_limb ? GET_EXTERNAL_ORGAN(target, target_limb) : pick(target.get_external_organs()) + if(affecting?.species?.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT)) to_chat(target, "\The [fruit]'s thorns scratch against the armour on your [affecting.name]!") return var/damage = 0 - var/has_edge = 0 + var/edged = 0 if(get_trait(TRAIT_CARNIVOROUS) >= 2) if(affecting) to_chat(target, "\The [fruit]'s thorns pierce your [affecting.name] greedily!") else to_chat(target, "\The [fruit]'s thorns pierce your flesh greedily!") damage = max(5, round(15*get_trait(TRAIT_POTENCY)/100, 1)) - has_edge = prob(get_trait(TRAIT_POTENCY)/2) + edged = prob(get_trait(TRAIT_POTENCY)/2) else if(affecting) to_chat(target, "\The [fruit]'s thorns dig deeply into your [affecting.name]!") else to_chat(target, "\The [fruit]'s thorns dig deeply into your flesh!") damage = max(1, round(5*get_trait(TRAIT_POTENCY)/100, 1)) - has_edge = prob(get_trait(TRAIT_POTENCY)/5) + edged = prob(get_trait(TRAIT_POTENCY)/5) - var/damage_flags = DAM_SHARP|(has_edge? DAM_EDGE : 0) + var/damage_flags = DAM_SHARP|(edged? DAM_EDGE : 0) target.apply_damage(damage, BRUTE, target_limb, damage_flags, used_weapon = "Thorns") // Adds reagents to a target. -/datum/seed/proc/do_sting(var/mob/living/carbon/human/target, var/obj/item/fruit) +/datum/seed/proc/do_sting(var/mob/living/human/target, var/obj/item/fruit) if(!get_trait(TRAIT_STINGS)) return - if(chems && chems.len && target.reagents && length(target.organs)) - - var/obj/item/organ/external/affecting = pick(target.organs) + var/list/external_organs = target.get_external_organs() + var/list/seed_chems = get_chemical_composition() + if(length(seed_chems) && target.reagents && LAZYLEN(external_organs)) - for(var/obj/item/clothing/C in list(target.head, target.wear_mask, target.wear_suit, target.w_uniform, target.gloves, target.shoes)) - if(C && (C.body_parts_covered & affecting.body_part) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) + var/obj/item/organ/external/affecting = pick(external_organs) + for(var/slot in global.standard_clothing_slots) + var/obj/item/clothing/C = target.get_equipped_item(slot) + if(istype(C) && (C.body_parts_covered & affecting.body_part) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) affecting = null + break if(!(target.species && target.species.species_flags & (SPECIES_FLAG_NO_EMBED|SPECIES_FLAG_NO_MINOR_CUT))) affecting = null if(affecting) to_chat(target, "You are stung by \the [fruit] in your [affecting.name]!") - for(var/rid in chems) + for(var/rid in seed_chems) var/injecting = min(5,max(1,get_trait(TRAIT_POTENCY)/5)) - target.reagents.add_reagent(rid,injecting) + target.add_to_reagents(rid,injecting) else to_chat(target, "Sharp spines scrape against your armour!") @@ -186,39 +191,44 @@ environment.adjust_gas(/decl/material/gas/carbon_dioxide, -req_CO2_moles, 1) environment.adjust_gas(/decl/material/gas/oxygen, req_CO2_moles, 1) +/datum/seed/proc/make_splat(var/turf/T, var/obj/item/thrown) + if(!splat_type || (locate(splat_type) in T)) + return + var/atom/splat = new splat_type(T, src) + splat.SetName("[product_name] [pick("smear","smudge","splatter")]") + if(get_trait(TRAIT_BIOLUM)) + var/clr + if(get_trait(TRAIT_BIOLUM_COLOUR)) + clr = get_trait(TRAIT_BIOLUM_COLOUR) + splat.set_light(get_trait(TRAIT_BIOLUM), l_color = clr) + splat.color = get_trait(TRAIT_FLESH_COLOUR) || get_trait(TRAIT_PRODUCT_COLOUR) + //Splatter a turf. -/datum/seed/proc/splatter(var/turf/T,var/obj/item/thrown) - if(splat_type && !(locate(/obj/effect/vine) in T)) - var/obj/effect/vine/splat = new splat_type(T, src) - if(!istype(splat)) // Plants handle their own stuff. - splat.SetName("[thrown.name] [pick("smear","smudge","splatter")]") - if(get_trait(TRAIT_BIOLUM)) - var/clr - if(get_trait(TRAIT_BIOLUM_COLOUR)) - clr = get_trait(TRAIT_BIOLUM_COLOUR) - splat.set_light(0.5, 0.1, 3, l_color = clr) - var/flesh_colour = get_trait(TRAIT_FLESH_COLOUR) - if(!flesh_colour) flesh_colour = get_trait(TRAIT_PRODUCT_COLOUR) - if(flesh_colour) splat.color = get_trait(TRAIT_PRODUCT_COLOUR) - - if(chems) - for(var/mob/living/M in T.contents) - if(!M.reagents) - continue - var/body_coverage = HEAD|FACE|EYES|UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS - for(var/obj/item/clothing/clothes in M) - if(M.l_hand == clothes || M.r_hand == clothes) - continue - body_coverage &= ~(clothes.body_parts_covered) - if(!body_coverage) - continue - var/datum/reagents/R = M.reagents - var/mob/living/carbon/human/H = M - if(istype(H)) - R = H.touching - if(istype(R)) - for(var/chem in chems) - R.add_reagent(chem,min(5,max(1,get_trait(TRAIT_POTENCY)/3))) +//Thrown can be null, but T cannot. +/datum/seed/proc/splatter(var/turf/T, var/obj/item/thrown) + make_splat(T, thrown) + + var/datum/reagents/splat_reagents = thrown?.reagents + if(!REAGENT_MAXIMUM_VOLUME(splat_reagents)) // if thrown doesn't exist or has no reagents, use the seed's default reagents. + splat_reagents = new /datum/reagents(INFINITY, global.temp_reagents_holder) + var/potency = get_trait(TRAIT_POTENCY) + var/list/seed_chems = get_chemical_composition() + if(length(seed_chems)) + for(var/rid in seed_chems) + var/list/reagent_amounts = seed_chems[rid] + if(LAZYLEN(reagent_amounts)) + var/rtotal = reagent_amounts[1] + var/list/data = null + if(reagent_amounts?[2] && potency > 0) + rtotal += round(potency/reagent_amounts[2]) + if(rid == /decl/material/liquid/nutriment) + LAZYSET(data, product_name, max(1,rtotal)) + splat_reagents.add_reagent(rid,max(1,rtotal),data) + if(splat_reagents) + var/splat_range = min(10,max(1,get_trait(TRAIT_POTENCY)/15)) + splat_reagents.splash_area(T, range = splat_range) + qdel(splat_reagents) + qdel(thrown) //Applies an effect to a target atom. /datum/seed/proc/thrown_at(var/obj/item/thrown,var/atom/target, var/force_explode) @@ -227,93 +237,54 @@ var/turf/origin_turf = get_turf(target) if(force_explode || get_trait(TRAIT_EXPLOSIVE)) - create_spores(origin_turf) - - var/flood_dist = min(10,max(1,get_trait(TRAIT_POTENCY)/15)) - var/list/open_turfs = list() - var/list/closed_turfs = list() - var/list/valid_turfs = list() - open_turfs |= origin_turf - - // Flood fill to get affected turfs. - while(open_turfs.len) - var/turf/T = pick(open_turfs) - open_turfs -= T - closed_turfs |= T - valid_turfs |= T - - for(var/dir in GLOB.alldirs) - var/turf/neighbor = get_step(T,dir) - if(!neighbor || (neighbor in closed_turfs) || (neighbor in open_turfs)) - continue - if(neighbor.density || get_dist(neighbor,origin_turf) > flood_dist || istype(neighbor,/turf/space)) - closed_turfs |= neighbor - continue - // Check for windows. - var/no_los - var/turf/last_turf = origin_turf - for(var/turf/target_turf in getline(origin_turf,neighbor)) - if(!last_turf.Enter(target_turf) || target_turf.density) - no_los = 1 - break - last_turf = target_turf - if(!no_los && !origin_turf.Enter(neighbor)) - no_los = 1 - if(no_los) - closed_turfs |= neighbor - continue - open_turfs |= neighbor - - for(var/turf/T in valid_turfs) - for(var/mob/living/M in T.contents) - apply_special_effect(M) - splatter(T,thrown) if(origin_turf) - origin_turf.visible_message("The [thrown.name] explodes!") - qdel(thrown) + origin_turf.visible_message(SPAN_DANGER("\The [thrown] explodes!")) + splatter(origin_turf,thrown) return - if(istype(target,/mob/living)) + if(isliving(target)) splatted = apply_special_effect(target,thrown) - else if(istype(target,/turf)) - splatted = 1 - for(var/mob/living/M in target.contents) - apply_special_effect(M) + else if(isturf(target)) + for(var/mob/living/M in target) + splatted |= apply_special_effect(M, thrown) if(get_trait(TRAIT_JUICY) && splatted) - splatter(origin_turf,thrown) if(origin_turf) - origin_turf.visible_message("The [thrown.name] splatters against [target]!") - qdel(thrown) + origin_turf.visible_message(SPAN_DANGER("\The [thrown] splatters against [target]!")) + splatter(origin_turf,thrown) -/datum/seed/proc/handle_environment(var/turf/current_turf, var/datum/gas_mixture/environment, var/light_supplied, var/check_only) +/datum/seed/proc/handle_plant_environment(var/obj/machinery/portable_atmospherics/hydroponics/holder, var/datum/gas_mixture/environment, var/light_supplied, var/check_only) + + var/growth_rate = 1 + var/turf/current_turf = isturf(holder) ? holder : get_turf(holder) + if(istype(holder)) + growth_rate = holder.get_growth_rate() var/health_change = 0 // Handle gas consumption. - if(consume_gasses && consume_gasses.len) + if(LAZYLEN(consume_gasses)) var/missing_gas = 0 for(var/gas in consume_gasses) - if(environment && environment.gas && environment.gas[gas] && \ - environment.gas[gas] >= consume_gasses[gas]) + if(LAZYACCESS(environment?.gas, gas) >= consume_gasses[gas]) if(!check_only) environment.adjust_gas(gas,-consume_gasses[gas],1) else missing_gas++ if(missing_gas > 0) - health_change += missing_gas * HYDRO_SPEED_MULTIPLIER + health_change += missing_gas * growth_rate // Process it. var/pressure = environment.return_pressure() if(pressure < get_trait(TRAIT_LOWKPA_TOLERANCE)|| pressure > get_trait(TRAIT_HIGHKPA_TOLERANCE)) - health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER + health_change += rand(1,3) * growth_rate if(abs(environment.temperature - get_trait(TRAIT_IDEAL_HEAT)) > get_trait(TRAIT_HEAT_TOLERANCE)) - health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER + health_change += rand(1,3) * growth_rate // Handle gas production. - if(exude_gasses && exude_gasses.len && !check_only) + if(LAZYLEN(exude_gasses) && !check_only) for(var/gas in exude_gasses) environment.adjust_gas(gas, max(1,round((exude_gasses[gas]*(get_trait(TRAIT_POTENCY)/5))/exude_gasses.len))) @@ -333,7 +304,7 @@ light_supplied = current_turf.get_lumcount() * 5 if(light_supplied) if(abs(light_supplied - get_trait(TRAIT_IDEAL_LIGHT)) > get_trait(TRAIT_LIGHT_TOLERANCE)) - health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER + health_change += rand(1,3) * growth_rate for(var/obj/effect/effect/smoke/chem/smoke in range(1, current_turf)) if(smoke.reagents.has_reagent(/decl/material/liquid/weedkiller)) @@ -348,8 +319,6 @@ return health_change /datum/seed/proc/apply_special_effect(var/mob/living/target,var/obj/item/thrown) - - var/impact = 1 do_sting(target,thrown) do_thorns(target,thrown) @@ -362,14 +331,10 @@ var/turf/T = get_random_turf_in_range(target, outer_teleport_radius, inner_teleport_radius) if(T) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, get_turf(target)) - s.start() + spark_at(target, cardinal_only = TRUE) new/obj/effect/decal/cleanable/molten_item(get_turf(target)) // Leave a pile of goo behind for dramatic effect... target.forceMove(T) // And teleport them to the chosen location. - impact = 1 - - return impact + return TRUE /datum/seed/proc/generate_name() var/prefix = "" @@ -408,11 +373,11 @@ if(prefix) name = "[prefix] [name]" - seed_name = name - display_name = name + product_name = name + display_name = "[name] plant" //Creates a random seed. MAKE SURE THE LINE HAS DIVERGED BEFORE THIS IS CALLED. -/datum/seed/proc/randomize() +/datum/seed/proc/randomize(var/temperature = T20C, var/pressure = 1 ATM) roundstart = 0 mysterious = 1 @@ -445,47 +410,47 @@ else if(prob(1)) set_trait(TRAIT_TELEPORTING,1) - if(prob(5)) - consume_gasses = list() - var/gas = pick(subtypesof(/decl/material/gas)) - consume_gasses[gas] = rand(3,9) - - if(prob(5)) - exude_gasses = list() - var/gas = pick(subtypesof(/decl/material/gas)) - exude_gasses[gas] = rand(3,9) - - chems = list() + var/skip_toxins = prob(30) + var/list/gasses = list() + var/list/liquids = list() + var/list/all_materials = decls_repository.get_decls_of_subtype(/decl/material) + for(var/mat_type in all_materials) + var/decl/material/mat = all_materials[mat_type] + if(mat.exoplanet_rarity_plant == MAT_RARITY_NOWHERE) + continue + if(skip_toxins && mat.toxicity) + continue + if(!isnull(mat.heating_point) && length(mat.heating_products) && temperature >= mat.heating_point) + // TODO: Maybe add products, but that could lead to having a lot of water or something. + continue + if(!isnull(mat.chilling_point) && length(mat.chilling_products) && temperature <= mat.chilling_point) + continue + switch(mat.phase_at_temperature(temperature, pressure)) + if(MAT_PHASE_GAS) + if(isnull(mat.gas_condensation_point) || mat.gas_condensation_point > temperature) + gasses[mat.type] = mat.exoplanet_rarity_plant + if(MAT_PHASE_LIQUID) + liquids[mat.type] = mat.exoplanet_rarity_plant + liquids -= /decl/material/liquid/nutriment + + if(length(gasses)) + if(prob(5)) + var/gas = pickweight(gasses) + gasses -= gas + LAZYSET(consume_gasses, gas, rand(3,9)) + if(prob(5)) + var/gas = pickweight(gasses) + gasses -= gas + LAZYSET(exude_gasses, gas, rand(3,9)) + + clear_chemical_composition() if(prob(80)) - chems[/decl/material/liquid/nutriment] = list(rand(1,10),rand(10,20)) - - var/additional_chems = rand(0,5) - - if(additional_chems) - var/list/banned_chems = list( - /decl/material/liquid/adminordrazine, - /decl/material/liquid/nutriment, - /decl/material/liquid/weedkiller - ) - banned_chems += subtypesof(/decl/material/liquid/ethanol) - banned_chems += subtypesof(/decl/material/solid/tobacco) - banned_chems += typesof(/decl/material/liquid/drink) - banned_chems += typesof(/decl/material/liquid/nutriment) - banned_chems += typesof(/decl/material/liquid/fertilizer) - - if(prob(30)) - for(var/R in subtypesof(/decl/material)) - var/decl/material/mat = decls_repository.get_decl(R) - if(mat.toxicity) - banned_chems |= R - - for(var/x=1;x<=additional_chems;x++) - var/new_chem = pick(subtypesof(/decl/material)) - if(new_chem in banned_chems) - x-- - continue - banned_chems += new_chem - chems[new_chem] = list(rand(1,10),rand(10,20)) + set_chemical_amount(/decl/material/liquid/nutriment, list(rand(1,10),rand(10,20))) + if(length(liquids)) + for(var/x = 1 to rand(0, 5)) + var/new_chem = pickweight(liquids) + liquids -= new_chem + set_chemical_amount(new_chem, list(rand(1,10),rand(10,20))) if(prob(90)) set_trait(TRAIT_REQUIRES_NUTRIENTS,1) @@ -543,15 +508,15 @@ //Returns a key corresponding to an entry in the global seed list. /datum/seed/proc/get_mutant_variant() - if(!mutants || !mutants.len || get_trait(TRAIT_IMMUTABLE) > 0) return 0 + if(!LAZYLEN(mutants) || get_trait(TRAIT_IMMUTABLE) > 0) return 0 return pick(mutants) //Mutates the plant overall (randomly). -/datum/seed/proc/mutate(var/degree,var/turf/source_turf) +/datum/seed/proc/mutate(var/degree, var/atom/location) if(!degree || get_trait(TRAIT_IMMUTABLE) > 0) return - source_turf.visible_message("\The [display_name] quivers!") + location.visible_message("\The [display_name] quivers!") //This looks like shit, but it's a lot easier to read/change this way. var/total_mutations = rand(1,1+degree) @@ -559,7 +524,7 @@ switch(rand(0,11)) if(0) //Plant cancer! set_trait(TRAIT_ENDURANCE,get_trait(TRAIT_ENDURANCE)-rand(10,20),null,0) - source_turf.visible_message("\The [display_name] withers rapidly!") + location.visible_message("\The [display_name] withers rapidly!") if(1) set_trait(TRAIT_NUTRIENT_CONSUMPTION,get_trait(TRAIT_NUTRIENT_CONSUMPTION)+rand(-(degree*0.1),(degree*0.1)),5,0) set_trait(TRAIT_WATER_CONSUMPTION, get_trait(TRAIT_WATER_CONSUMPTION) +rand(-degree,degree),50,0) @@ -581,7 +546,7 @@ if(prob(degree*5)) set_trait(TRAIT_CARNIVOROUS, get_trait(TRAIT_CARNIVOROUS)+rand(-degree,degree),2, 0) if(get_trait(TRAIT_CARNIVOROUS)) - source_turf.visible_message("\The [display_name] shudders hungrily.") + location.visible_message("\The [display_name] shudders hungrily.") if(6) set_trait(TRAIT_WEED_TOLERANCE, get_trait(TRAIT_WEED_TOLERANCE)+(rand(-2,2)*degree),10, 0) if(prob(degree*5)) @@ -595,7 +560,7 @@ set_trait(TRAIT_POTENCY, get_trait(TRAIT_POTENCY)+(rand(-20,20)*degree),200, 0) if(prob(degree*5)) set_trait(TRAIT_SPREAD, get_trait(TRAIT_SPREAD)+rand(-1,1),2, 0) - source_turf.visible_message("\The [display_name] spasms visibly, shifting in the tray.") + location.visible_message("\The [display_name] spasms visibly, shifting in the tray.") if(9) set_trait(TRAIT_MATURATION, get_trait(TRAIT_MATURATION)+(rand(-1,1)*degree),30, 0) if(prob(degree*5)) @@ -604,12 +569,12 @@ if(prob(degree*2)) set_trait(TRAIT_BIOLUM, !get_trait(TRAIT_BIOLUM)) if(get_trait(TRAIT_BIOLUM)) - source_turf.visible_message("\The [display_name] begins to glow!") + location.visible_message("\The [display_name] begins to glow!") if(prob(degree*2)) set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190)) - source_turf.visible_message("\The [display_name]'s glow changes colour!") + location.visible_message("\The [display_name]'s glow changes colour!") else - source_turf.visible_message("\The [display_name]'s glow dims...") + location.visible_message("\The [display_name]'s glow dims...") if(11) set_trait(TRAIT_TELEPORTING,1) @@ -617,108 +582,16 @@ //Mutates a specific trait/set of traits. /datum/seed/proc/apply_gene(var/datum/plantgene/gene) - - if(!gene || !gene.values || get_trait(TRAIT_IMMUTABLE) > 0) return - - // Splicing products has some detrimental effects on yield and lifespan. - // We handle this before we do the rest of the looping, as normal traits don't really include lists. - switch(gene.genetype) - if(GENE_BIOCHEMISTRY) - for(var/trait in list(TRAIT_YIELD, TRAIT_ENDURANCE)) - if(get_trait(trait) > 0) set_trait(trait,get_trait(trait),null,1,0.85) - - if(!chems) chems = list() - - var/list/gene_value = gene.values["[TRAIT_CHEMS]"] - for(var/rid in gene_value) - - var/list/gene_chem = gene_value[rid] - - if(!chems[rid]) - chems[rid] = gene_chem.Copy() - continue - - for(var/i=1;i<=gene_chem.len;i++) - - if(isnull(gene_chem[i])) gene_chem[i] = 0 - - if(chems[rid][i]) - chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2)) - else - chems[rid][i] = gene_chem[i] - - var/list/new_gasses = gene.values["[TRAIT_EXUDE_GASSES]"] - if(islist(new_gasses)) - if(!exude_gasses) exude_gasses = list() - exude_gasses |= new_gasses - for(var/gas in exude_gasses) - exude_gasses[gas] = max(1,round(exude_gasses[gas]*0.8)) - - gene.values["[TRAIT_EXUDE_GASSES]"] = null - gene.values["[TRAIT_CHEMS]"] = null - - if(GENE_DIET) - var/list/new_gasses = gene.values["[TRAIT_CONSUME_GASSES]"] - consume_gasses |= new_gasses - gene.values["[TRAIT_CONSUME_GASSES]"] = null - if(GENE_METABOLISM) - has_mob_product = gene.values["mob_product"] - gene.values["mob_product"] = null - - for(var/trait in gene.values) - set_trait(trait,gene.values["[trait]"]) - + if(!istype(gene) || !gene?.values || get_trait(TRAIT_IMMUTABLE) > 0) + return + gene.genetype.modify_seed(gene, src) update_growth_stages() -//Returns a list of the desired trait values. -/datum/seed/proc/get_gene(var/genetype) - - if(!genetype) return 0 - - var/list/traits_to_copy - var/datum/plantgene/P = new() - P.genetype = genetype - P.values = list() - - switch(genetype) - if(GENE_BIOCHEMISTRY) - P.values["[TRAIT_CHEMS]"] = chems - P.values["[TRAIT_EXUDE_GASSES]"] = exude_gasses - traits_to_copy = list(TRAIT_POTENCY) - if(GENE_OUTPUT) - traits_to_copy = list(TRAIT_PRODUCES_POWER,TRAIT_BIOLUM) - if(GENE_ATMOSPHERE) - traits_to_copy = list(TRAIT_HEAT_TOLERANCE,TRAIT_LOWKPA_TOLERANCE,TRAIT_HIGHKPA_TOLERANCE) - if(GENE_HARDINESS) - traits_to_copy = list(TRAIT_TOXINS_TOLERANCE,TRAIT_PEST_TOLERANCE,TRAIT_WEED_TOLERANCE,TRAIT_ENDURANCE) - if(GENE_METABOLISM) - P.values["mob_product"] = has_mob_product - traits_to_copy = list(TRAIT_REQUIRES_NUTRIENTS,TRAIT_REQUIRES_WATER,TRAIT_ALTER_TEMP) - if(GENE_VIGOUR) - traits_to_copy = list(TRAIT_PRODUCTION,TRAIT_MATURATION,TRAIT_YIELD,TRAIT_SPREAD) - if(GENE_DIET) - P.values["[TRAIT_CONSUME_GASSES]"] = consume_gasses - traits_to_copy = list(TRAIT_CARNIVOROUS,TRAIT_PARASITE,TRAIT_NUTRIENT_CONSUMPTION,TRAIT_WATER_CONSUMPTION) - if(GENE_ENVIRONMENT) - traits_to_copy = list(TRAIT_IDEAL_HEAT,TRAIT_IDEAL_LIGHT,TRAIT_LIGHT_TOLERANCE) - if(GENE_PIGMENT) - traits_to_copy = list(TRAIT_PLANT_COLOUR,TRAIT_PRODUCT_COLOUR,TRAIT_BIOLUM_COLOUR,TRAIT_LEAVES_COLOUR) - if(GENE_STRUCTURE) - traits_to_copy = list(TRAIT_PLANT_ICON,TRAIT_PRODUCT_ICON,TRAIT_HARVEST_REPEAT,TRAIT_LARGE) - if(GENE_FRUIT) - traits_to_copy = list(TRAIT_STINGS,TRAIT_EXPLOSIVE,TRAIT_FLESH_COLOUR,TRAIT_JUICY) - if(GENE_SPECIAL) - traits_to_copy = list(TRAIT_TELEPORTING) - - for(var/trait in traits_to_copy) - P.values["[trait]"] = get_trait(trait) - return (P ? P : 0) - //Place the plant products at the feet of the user. -/datum/seed/proc/harvest(var/mob/user,var/yield_mod,var/harvest_sample,var/force_amount) +/datum/seed/proc/harvest(var/mob/user, var/yield_mod, var/harvest_sample, var/force_amount) if(!user) - return + return FALSE if(!force_amount && get_trait(TRAIT_YIELD) == 0 && !harvest_sample) if(istype(user)) to_chat(user, "You fail to harvest anything useful.") @@ -726,15 +599,12 @@ if(istype(user)) to_chat(user, "You [harvest_sample ? "take a sample" : "harvest"] from the [display_name].") //This may be a new line. Update the global if it is. if(name == "new line" || !(name in SSplants.seeds)) - uid = SSplants.seeds.len + 1 + uid = sequential_id(/datum/seed/) name = "[uid]" SSplants.seeds[name] = src if(harvest_sample) - var/obj/item/seeds/seeds = new(get_turf(user)) - seeds.seed_type = name - seeds.update_seed() - return + return new /obj/item/seeds/extracted(get_turf(user), null, src) var/total_yield = 0 if(!isnull(force_amount)) @@ -749,65 +619,77 @@ total_yield = max(1,total_yield) . = list() - for(var/i = 0;iThe pod disgorges [product]!
          ") - handle_living_product(product) - if(istype(product,/mob/living/simple_animal/mushroom)) // Gross. - var/mob/living/simple_animal/mushroom/mush = product - mush.seed = src + if(ispath(product_type, /obj/item/stack)) + var/obj/item/stack/stack = product_type + var/remaining_yield = total_yield + var/per_stack = initial(stack.max_amount) + while(remaining_yield > 0) + var/using_yield = min(remaining_yield, per_stack) + remaining_yield -= using_yield + . += new product_type(get_turf(user), using_yield) + else + for(var/i = 1 to total_yield) + var/obj/item/product + if(ispath(product_type, /obj/item/food)) + product = new product_type(get_turf(user), null, TRUE, src) + if(allergen_flags) + var/obj/item/food/food = product + food.add_allergen_flags(allergen_flags) + else + product = new product_type(get_turf(user), null, src) + . += product + + if(get_trait(TRAIT_PRODUCT_COLOUR) && istype(product, /obj/item/food)) + var/obj/item/food/snack = product + snack.color = get_trait(TRAIT_PRODUCT_COLOUR) + snack.filling_color = get_trait(TRAIT_PRODUCT_COLOUR) + + if(mysterious) + product.name += "?" + product.desc += " On second thought, something about this one looks strange." + + if(get_trait(TRAIT_BIOLUM)) + var/clr + if(get_trait(TRAIT_BIOLUM_COLOUR)) + clr = get_trait(TRAIT_BIOLUM_COLOUR) + product.set_light(get_trait(TRAIT_BIOLUM), l_color = clr) + + //Handle spawning in living, mobile products. + if(isliving(product)) + product.visible_message("The pod disgorges [product]!") + handle_living_product(product) + if(istype(product,/mob/living/simple_animal/mushroom)) // Gross. + var/mob/living/simple_animal/mushroom/mush = product + mush.seed = src // When the seed in this machine mutates/is modified, the tray seed value // is set to a new datum copied from the original. This datum won't actually // be put into the global datum list until the product is harvested, though. /datum/seed/proc/diverge(var/modified) - if(get_trait(TRAIT_IMMUTABLE) > 0) return + if(get_trait(TRAIT_IMMUTABLE) > 0) + return //Set up some basic information. var/datum/seed/new_seed = new - new_seed.name = "new line" - new_seed.uid = 0 - new_seed.roundstart = 0 + new_seed.name = "new line" + new_seed.uid = 0 + new_seed.roundstart = 0 new_seed.can_self_harvest = can_self_harvest - new_seed.kitchen_tag = kitchen_tag - new_seed.trash_type = trash_type - new_seed.has_mob_product = has_mob_product + new_seed.grown_tag = grown_tag + new_seed.trash_type = trash_type + new_seed.product_type = product_type + //Copy over everything else. + new_seed.copy_chemical_composition(src) if(mutants) new_seed.mutants = mutants.Copy() - if(chems) new_seed.chems = chems.Copy() if(consume_gasses) new_seed.consume_gasses = consume_gasses.Copy() if(exude_gasses) new_seed.exude_gasses = exude_gasses.Copy() - new_seed.seed_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][seed_name]" - new_seed.display_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][display_name]" - new_seed.seed_noun = seed_noun - new_seed.traits = traits.Copy() + new_seed.product_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][product_name]" + new_seed.display_name = "[(roundstart ? "[(modified ? "modified" : "mutant")] " : "")][display_name]" + new_seed.seed_noun = seed_noun + new_seed._traits = deepCopyList(_traits) new_seed.update_growth_stages() return new_seed @@ -830,7 +712,7 @@ return GROWTH_VINES return 0 -/datum/seed/proc/get_icon(growth_stage) +/datum/seed/proc/get_growth_stage_overlay(growth_stage) var/plant_icon = get_trait(TRAIT_PLANT_ICON) var/image/res = image('icons/obj/hydroponics/hydroponics_growing.dmi', "[plant_icon]-[growth_stage]") if(get_growth_type()) @@ -856,3 +738,62 @@ res.overlays += I return res + +/datum/seed/PopulateClone(datum/seed/clone) + clone = ..() + //!! - Cloning means having an independent working copy, so leave its unique uid - !! + clone.roundstart = FALSE + clone.name = "[product_name][(roundstart ? " strain #[clone.uid]" : "")]" + clone.product_name = clone.name + clone.display_name = "[display_name][(roundstart ? " strain #[clone.uid]" : "")]" + clone.seed_noun = seed_noun + + //Seed traits + clone._traits = deepCopyList(_traits) + clone.mutants = mutants?.Copy() + clone.consume_gasses = consume_gasses?.Copy() + clone.exude_gasses = exude_gasses?.Copy() + clone.copy_chemical_composition(src) + + //Appearence + clone.growth_stages = growth_stages + clone.force_layer = force_layer + clone.splat_type = splat_type + + //things that probably should be traits + clone.mysterious = mysterious + clone.req_CO2_moles = req_CO2_moles + clone.hydrotray_only = hydrotray_only + clone.can_self_harvest = can_self_harvest + + //misc data + clone.grown_tag = grown_tag + clone.trash_type = trash_type + clone.product_type = product_type + clone.base_seed_value = base_seed_value + clone.scannable_result = scannable_result + + clone.update_growth_stages() + return clone + +/datum/seed/proc/show_slice_message(mob/user, obj/item/tool, obj/item/food/grown/sliced) + if(slice_product == /obj/item/food/processed_grown/chopped) + sliced.visible_message(SPAN_NOTICE("\The [user] quickly chops up \the [sliced] with \the [tool].")) + else if(slice_product == /obj/item/food/processed_grown/crushed) + sliced.visible_message(SPAN_NOTICE("\The [user] methodically crushes \the [sliced] with the handle of \the [tool].")) + else if(slice_product == /obj/item/food/processed_grown/sticks) + sliced.visible_message(SPAN_NOTICE("\The [user] neatly slices \the [sliced] into sticks with \the [tool].")) + else + return null + return TRUE + +/datum/seed/proc/show_slice_message_poor(mob/user, obj/item/tool, obj/item/food/grown/sliced) + if(slice_product == /obj/item/food/processed_grown/chopped) + sliced.visible_message(SPAN_NOTICE("\The [user] crudely chops \the [sliced] with \the [tool].")) + else if(slice_product == /obj/item/food/processed_grown/crushed) + sliced.visible_message(SPAN_NOTICE("\The [user] messily crushes \the [sliced] with the handle of \the [tool].")) + else if(slice_product == /obj/item/food/processed_grown/sticks) + sliced.visible_message(SPAN_NOTICE("\The [user] roughly slices \the [sliced] into sticks with \the [tool].")) + else + return null + return TRUE diff --git a/code/modules/hydroponics/seed_appearance.dm b/code/modules/hydroponics/seed_appearance.dm new file mode 100644 index 000000000000..97350040b7b3 --- /dev/null +++ b/code/modules/hydroponics/seed_appearance.dm @@ -0,0 +1,55 @@ +/datum/seed/proc/get_growing_appearance(var/growth_state) + if(!growing_overlays) + growing_overlays = list() + for(var/overlay_stage = 1 to growth_stages) + var/ikey = "\ref[src]-plant-[overlay_stage]" + if(!SSplants.plant_icon_cache[ikey]) + SSplants.plant_icon_cache[ikey] = get_growth_stage_overlay(overlay_stage) + growing_overlays["[overlay_stage]"] = SSplants.plant_icon_cache[ikey] + if(growth_state > length(growing_overlays)) + log_error(SPAN_DANGER("Seed type [get_trait(TRAIT_PLANT_ICON)] cannot find a growth icon for state [growth_state].")) + return growing_overlays["[clamp(growth_state, 1, length(growing_overlays))]"] + +/datum/seed/proc/get_dead_appearance() + if(!dead_overlay) + var/ikey = "[get_trait(TRAIT_PLANT_ICON)]-dead" + if(SSplants.plant_icon_cache[ikey]) + dead_overlay = SSplants.plant_icon_cache[ikey] + else + dead_overlay = image('icons/obj/hydroponics/hydroponics_growing.dmi', ikey) + dead_overlay.color = DEAD_PLANT_COLOUR + SSplants.plant_icon_cache[ikey] = dead_overlay + return dead_overlay + +/datum/seed/proc/get_harvest_appearance() + if(!harvest_overlay) + var/icon_state = get_trait(TRAIT_PRODUCT_ICON) + var/ikey = "product-[icon_state]-[get_trait(TRAIT_PLANT_COLOUR)]" + if(SSplants.plant_icon_cache[ikey]) + harvest_overlay = SSplants.plant_icon_cache[ikey] + else + harvest_overlay = image('icons/obj/hydroponics/hydroponics_products.dmi', icon_state) + harvest_overlay.color = get_trait(TRAIT_PRODUCT_COLOUR) + SSplants.plant_icon_cache[ikey] = harvest_overlay + return harvest_overlay + +/datum/seed/proc/get_overlay_stage(var/age) + var/seed_maturation = get_trait(TRAIT_MATURATION) + if(age >= seed_maturation) + return growth_stages + return max(1, round(age/max(seed_maturation/growth_stages, 1))) + +/datum/seed/proc/get_appearance(var/dead = FALSE, var/age = INFINITY, var/growth_stage, var/can_harvest = FALSE) + if(dead) + var/dead_appearance = get_dead_appearance() + if(dead_appearance) + return list(dead_appearance) + growth_stage = growth_stage || (age && get_overlay_stage(age)) + if(growth_stage > 0) + var/growing_appearance = get_growing_appearance(growth_stage) + if(growing_appearance) + LAZYADD(., growing_appearance) + if(can_harvest) + var/harvest_appearance = get_harvest_appearance() + if(harvest_appearance) + LAZYADD(., harvest_appearance) diff --git a/code/modules/hydroponics/seed_composition.dm b/code/modules/hydroponics/seed_composition.dm new file mode 100644 index 000000000000..e25b34789af1 --- /dev/null +++ b/code/modules/hydroponics/seed_composition.dm @@ -0,0 +1,21 @@ +/datum/seed + VAR_PRIVATE/list/_chemical_composition + +/datum/seed/proc/copy_chemical_composition(datum/seed/donor) + UNLINT(_chemical_composition = deepCopyList(donor._chemical_composition)) + +/datum/seed/proc/get_chemical_amount(_chem, _state = PLANT_STATE_FRESH, _segment = PLANT_SEG_BODY) + var/list/comp = get_chemical_composition(_state, _segment) + return LAZYACCESS(comp, _chem) + +/datum/seed/proc/set_chemical_amount(_chem, list/_amt, _state = PLANT_STATE_FRESH, _segment = PLANT_SEG_BODY) + LAZYINITLIST(_chemical_composition) + LAZYINITLIST(_chemical_composition[_state]) + LAZYSET(_chemical_composition[_state][_segment], _chem, _amt) + +/datum/seed/proc/get_chemical_composition(_state = PLANT_STATE_FRESH, _segment = PLANT_SEG_BODY) + var/list/comp = LAZYACCESS(_chemical_composition, _state) + return LAZYACCESS(comp, _segment) + +/datum/seed/proc/clear_chemical_composition() + LAZYCLEARLIST(_chemical_composition) diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm deleted file mode 100644 index a6de76b6d67e..000000000000 --- a/code/modules/hydroponics/seed_datums.dm +++ /dev/null @@ -1,1322 +0,0 @@ -// Chili plants/variants. -/datum/seed/chili - name = "chili" - seed_name = "chili" - display_name = "chili plants" - chems = list(/decl/material/liquid/capsaicin = list(3,5), /decl/material/liquid/nutriment = list(1,25)) - mutants = list("icechili") - kitchen_tag = "chili" - -/datum/seed/chili/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"chili") - set_trait(TRAIT_PRODUCT_COLOUR,"#ed3300") - set_trait(TRAIT_PLANT_ICON,"bush2") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 7) - -/datum/seed/chili/ice - name = "icechili" - seed_name = "chilly pepper" - display_name = "chilly pepper plants" - mutants = null - chems = list(/decl/material/liquid/frostoil = list(3,5), /decl/material/liquid/nutriment = list(1,50)) - kitchen_tag = "icechili" - -/datum/seed/chili/ice/New() - ..() - set_trait(TRAIT_MATURATION,4) - set_trait(TRAIT_PRODUCTION,4) - set_trait(TRAIT_PRODUCT_COLOUR,"#00edc6") - -// Berry plants/variants. -/datum/seed/berry - name = "berries" - seed_name = "berry" - display_name = "berry bush" - mutants = list("glowberries","poisonberries","blueberries") - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/berry = list(10,10)) - kitchen_tag = "berries" - -/datum/seed/berry/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"berry") - set_trait(TRAIT_PRODUCT_COLOUR,"#fa1616") - set_trait(TRAIT_PLANT_ICON,"bush") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/berry/blue - name = "blueberries" - seed_name = "blueberry" - display_name = "blueberry bush" - mutants = list("berries","poisonberries","glowberries") - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/berry = list(10,10)) - kitchen_tag = "blueberries" - -/datum/seed/berry/blue/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_COLOUR,"#1c225c") - set_trait(TRAIT_WATER_CONSUMPTION, 5) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.2) - -/datum/seed/berry/glow - name = "glowberries" - seed_name = "glowberry" - display_name = "glowberry bush" - mutants = null - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/solid/metal/uranium = list(3,5)) - -/datum/seed/berry/glow/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#006622") - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_COLOUR,"#c9fa16") - set_trait(TRAIT_WATER_CONSUMPTION, 3) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) - -/datum/seed/berry/poison - name = "poisonberries" - seed_name = "poison berry" - display_name = "poison berry bush" - mutants = list("deathberries") - chems = list( - /decl/material/liquid/nutriment = list(1), - /decl/material/liquid/bromide = list(3,5), - /decl/material/liquid/poisonberryjuice = list(10,5) - ) - -/datum/seed/berry/poison/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#6dc961") - set_trait(TRAIT_WATER_CONSUMPTION, 3) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) - -/datum/seed/berry/poison/death - name = "deathberries" - seed_name = "death berry" - display_name = "death berry bush" - mutants = null - chems = list( - /decl/material/liquid/nutriment = list(1), - /decl/material/liquid/bromide = list(3,3), - /decl/material/gas/carbon_monoxide = list(1,5) - ) - -/datum/seed/berry/poison/death/New() - ..() - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,50) - set_trait(TRAIT_PRODUCT_COLOUR,"#7a5454") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) - -// Nettles/variants. -/datum/seed/nettle - name = "nettle" - seed_name = "nettle" - display_name = "nettles" - mutants = list("deathnettle") - chems = list(/decl/material/liquid/nutriment = list(1,50), /decl/material/liquid/acid = list(0,1)) - kitchen_tag = "nettle" - kitchen_tag = "nettle" - -/datum/seed/nettle/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_STINGS,1) - set_trait(TRAIT_PLANT_ICON,"bush5") - set_trait(TRAIT_PRODUCT_ICON,"nettles") - set_trait(TRAIT_PRODUCT_COLOUR,"#728a54") - -/datum/seed/nettle/death - name = "deathnettle" - seed_name = "death nettle" - display_name = "death nettles" - mutants = null - chems = list(/decl/material/liquid/nutriment = list(1,50), /decl/material/liquid/acid/polyacid = list(0,1)) - kitchen_tag = "deathnettle" - -/datum/seed/nettle/death/New() - ..() - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_PRODUCT_COLOUR,"#8c5030") - set_trait(TRAIT_PLANT_COLOUR,"#634941") - -//Tomatoes/variants. -/datum/seed/tomato - name = "tomato" - seed_name = "tomato" - display_name = "tomato plant" - mutants = list("bluetomato","bloodtomato") - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/tomato = list(10,10)) - kitchen_tag = "tomato" - -/datum/seed/tomato/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"tomato") - set_trait(TRAIT_PRODUCT_COLOUR,"#d10000") - set_trait(TRAIT_PLANT_ICON,"bush3") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) - -/datum/seed/tomato/blood - name = "bloodtomato" - seed_name = "blood tomato" - display_name = "blood tomato plant" - mutants = list("killer") - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/blood = list(1,5)) - splat_type = /obj/effect/decal/cleanable/blood/splatter - -/datum/seed/tomato/blood/New() - ..() - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_COLOUR,"#ff0000") - -/datum/seed/tomato/killer - name = "killertomato" - seed_name = "killer tomato" - display_name = "killer tomato plant" - mutants = null - can_self_harvest = 1 - has_mob_product = /mob/living/simple_animal/tomato - -/datum/seed/tomato/killer/New() - ..() - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_PRODUCT_COLOUR,"#a86747") - -/datum/seed/tomato/blue - name = "bluetomato" - seed_name = "blue tomato" - display_name = "blue tomato plant" - mutants = list("quantumato") - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/lube = list(1,5)) - -/datum/seed/tomato/blue/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#4d86e8") - set_trait(TRAIT_PLANT_COLOUR,"#070aad") - -/datum/seed/tomato/blue/teleport - name = "quantumato" - seed_name = "quantumato" - display_name = "quantumato plant" - mutants = null - chems = list( - /decl/material/liquid/nutriment = list(1,20), - /decl/material/liquid/ethanol/bluecuracao = list(10,5) - ) - -/datum/seed/tomato/blue/teleport/New() - ..() - set_trait(TRAIT_TELEPORTING,1) - set_trait(TRAIT_PRODUCT_COLOUR,"#00e5ff") - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#4da4a8") - -//Eggplants/varieties. -/datum/seed/eggplant - name = "eggplant" - seed_name = "eggplant" - display_name = "eggplants" - mutants = list("realeggplant") - chems = list(/decl/material/liquid/nutriment = list(1,10)) - kitchen_tag = "eggplant" - -/datum/seed/eggplant/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"eggplant") - set_trait(TRAIT_PRODUCT_COLOUR,"#892694") - set_trait(TRAIT_PLANT_ICON,"bush4") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 7) - -//Apples/varieties. -/datum/seed/apple - name = "apple" - seed_name = "apple" - display_name = "apple tree" - mutants = list("poisonapple","goldapple") - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/apple = list(10,10)) - kitchen_tag = "apple" - -/datum/seed/apple/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"apple") - set_trait(TRAIT_PRODUCT_COLOUR,"#ff540a") - set_trait(TRAIT_PLANT_ICON,"tree2") - set_trait(TRAIT_FLESH_COLOUR,"#e8e39b") - set_trait(TRAIT_IDEAL_LIGHT, 4) - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/apple/poison - name = "poisonapple" - mutants = null - chems = list(/decl/material/liquid/cyanide = list(1,5)) - -/datum/seed/apple/gold - name = "goldapple" - seed_name = "golden apple" - display_name = "gold apple tree" - mutants = null - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/solid/metal/gold = list(1,5)) - kitchen_tag = "goldapple" - -/datum/seed/apple/gold/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,10) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_COLOUR,"#ffdd00") - set_trait(TRAIT_PLANT_COLOUR,"#d6b44d") - -//Ambrosia/varieties. -/datum/seed/ambrosia - name = "biteleaf" - seed_name = "biteleaf" - display_name = "biteleaf" - mutants = list("biteleafdeus") - chems = list( - /decl/material/liquid/nutriment = list(1), - /decl/material/liquid/psychoactives = list(1,8), - /decl/material/liquid/burn_meds = list(1,8,1), - /decl/material/liquid/brute_meds = list(1,10,1), - /decl/material/liquid/bromide = list(1,10) - ) - kitchen_tag = "biteleaf" - -/datum/seed/ambrosia/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"ambrosia") - set_trait(TRAIT_PRODUCT_COLOUR,"#9fad55") - set_trait(TRAIT_PLANT_ICON,"ambrosia") - set_trait(TRAIT_IDEAL_LIGHT, 6) - -/datum/seed/ambrosia/deus - name = "biteleafdeus" - seed_name = "biteleaf deus" - display_name = "biteleaf deus" - mutants = null - chems = list( - /decl/material/liquid/nutriment = list(1), - /decl/material/liquid/brute_meds = list(1,8), - /decl/material/liquid/antidepressants = list(1,8,1), - /decl/material/liquid/stimulants = list(1,8,1), - /decl/material/liquid/amphetamines = list(1,10,1), - /decl/material/liquid/psychoactives = list(1,10) - ) - kitchen_tag = "biteleafdeus" - -/datum/seed/ambrosia/deus/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#a3f0ad") - set_trait(TRAIT_PLANT_COLOUR,"#2a9c61") - -//Mushrooms/varieties. -/datum/seed/mushroom - name = "mushrooms" - seed_name = "chanterelle" - seed_noun = SEED_NOUN_SPORES - display_name = "chanterelle mushrooms" - mutants = list("reishi","amanita","plumphelmet") - chems = list(/decl/material/liquid/nutriment = list(1,25)) - splat_type = /obj/effect/vine - kitchen_tag = "mushroom" - -/datum/seed/mushroom/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,1) - set_trait(TRAIT_PRODUCT_ICON,"mushroom4") - set_trait(TRAIT_PRODUCT_COLOUR,"#dbda72") - set_trait(TRAIT_PLANT_COLOUR,"#d9c94e") - set_trait(TRAIT_PLANT_ICON,"mushroom") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_IDEAL_HEAT, 288) - set_trait(TRAIT_LIGHT_TOLERANCE, 6) - -/datum/seed/mushroom/mold - name = "mold" - seed_name = "brown mold" - display_name = "brown mold" - mutants = null - -/datum/seed/mushroom/mold/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_YIELD,-1) - set_trait(TRAIT_PRODUCT_ICON,"mushroom5") - set_trait(TRAIT_PRODUCT_COLOUR,"#7a5f20") - set_trait(TRAIT_PLANT_COLOUR,"#7a5f20") - set_trait(TRAIT_PLANT_ICON,"mushroom9") - -/datum/seed/mushroom/plump - name = "plumphelmet" - seed_name = "plump helmet" - display_name = "plump helmet mushrooms" - mutants = list("walkingmushroom","corkwood") - chems = list(/decl/material/liquid/nutriment = list(2,10)) - kitchen_tag = "plumphelmet" - -/datum/seed/mushroom/plump/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,2) - set_trait(TRAIT_PRODUCT_ICON,"mushroom10") - set_trait(TRAIT_PRODUCT_COLOUR,"#b57bb0") - set_trait(TRAIT_PLANT_COLOUR,"#9e4f9d") - set_trait(TRAIT_PLANT_ICON,"mushroom2") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) - -/datum/seed/mushroom/plump/walking - name = "walkingmushroom" - seed_name = "walking mushroom" - display_name = "walking mushrooms" - mutants = null - can_self_harvest = 1 - has_mob_product = /mob/living/simple_animal/mushroom - -/datum/seed/mushroom/plump/walking/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_YIELD,1) - set_trait(TRAIT_PRODUCT_COLOUR,"#fac0f2") - set_trait(TRAIT_PLANT_COLOUR,"#c4b1c2") - -/datum/seed/mushroom/hallucinogenic - name = "reishi" - seed_name = "reishi" - display_name = "reishi" - mutants = list("libertycap","glowbell") - chems = list(/decl/material/liquid/nutriment = list(1,50), /decl/material/liquid/psychotropics = list(3,5)) - -/datum/seed/mushroom/hallucinogenic/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,15) - set_trait(TRAIT_PRODUCT_ICON,"mushroom11") - set_trait(TRAIT_PRODUCT_COLOUR,"#ffb70f") - set_trait(TRAIT_PLANT_COLOUR,"#f58a18") - set_trait(TRAIT_PLANT_ICON,"mushroom6") - -/datum/seed/mushroom/hallucinogenic/strong - name = "libertycap" - seed_name = "liberty cap" - display_name = "liberty cap mushrooms" - mutants = null - chems = list(/decl/material/liquid/nutriment = list(1), /decl/material/liquid/sedatives = list(3,3), /decl/material/liquid/psychoactives = list(1,25)) - -/datum/seed/mushroom/hallucinogenic/strong/New() - ..() - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_POTENCY,15) - set_trait(TRAIT_PRODUCT_ICON,"mushroom8") - set_trait(TRAIT_PRODUCT_COLOUR,"#f2e550") - set_trait(TRAIT_PLANT_COLOUR,"#d1ca82") - set_trait(TRAIT_PLANT_ICON,"mushroom3") - -/datum/seed/mushroom/poison - name = "amanita" - seed_name = "fly amanita" - display_name = "fly amanita mushrooms" - mutants = list("destroyingangel","plastic") - chems = list(/decl/material/liquid/nutriment = list(1), /decl/material/liquid/amatoxin = list(3,3), /decl/material/liquid/psychotropics = list(1,25)) - -/datum/seed/mushroom/poison/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"mushroom") - set_trait(TRAIT_PRODUCT_COLOUR,"#ff4545") - set_trait(TRAIT_PLANT_COLOUR,"#e0ddba") - set_trait(TRAIT_PLANT_ICON,"mushroom4") - -/datum/seed/mushroom/poison/death - name = "destroyingangel" - seed_name = "destroying angel" - display_name = "destroying angel mushrooms" - mutants = null - chems = list(/decl/material/liquid/nutriment = list(1,50), /decl/material/liquid/amatoxin = list(13,3), /decl/material/liquid/psychotropics = list(1,25)) - -/datum/seed/mushroom/poison/death/New() - ..() - set_trait(TRAIT_MATURATION,12) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,35) - set_trait(TRAIT_PRODUCT_ICON,"mushroom3") - set_trait(TRAIT_PRODUCT_COLOUR,"#ede8ea") - set_trait(TRAIT_PLANT_COLOUR,"#e6d8dd") - set_trait(TRAIT_PLANT_ICON,"mushroom5") - -/datum/seed/mushroom/corkwood - name = "corkwood" - seed_name = "corkwood" - display_name = "corkwood stalks" - chems = list(/decl/material/solid/wood = list(10,1)) - mutants = null - -/datum/seed/mushroom/corkwood/New() - ..() - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_PRODUCT_ICON,"mushroom7") - set_trait(TRAIT_PRODUCT_COLOUR,"#d3aca3") - set_trait(TRAIT_PLANT_COLOUR,"#dcd9d9") - set_trait(TRAIT_PLANT_ICON,"mushroom8") - -/datum/seed/mushroom/glowbell - name = "glowbell" - seed_name = "glowbell" - display_name = "glowbells" - mutants = list("weepingmoon", "caverncandle") - chems = list(/decl/material/liquid/glowsap = list(1,20)) - -/datum/seed/mushroom/glowbell/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,30) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#9eefff") - set_trait(TRAIT_PRODUCT_ICON,"mushroom2") - set_trait(TRAIT_PRODUCT_COLOUR,"#90d7f0") - set_trait(TRAIT_PLANT_COLOUR,"#75bdd7") - set_trait(TRAIT_PLANT_ICON,"mushroom2") - -/datum/seed/mushroom/weepingmoon - name = "weepingmoon" - seed_name = "weepingmoon" - display_name = "weeping moons" - mutants = null - chems = list(/decl/material/liquid/glowsap = list(1,20)) - -/datum/seed/mushroom/weepingmoon/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,30) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#9eefff") - set_trait(TRAIT_PRODUCT_ICON,"mushroom4") - set_trait(TRAIT_PRODUCT_COLOUR,"#90d7f0") - set_trait(TRAIT_PLANT_COLOUR,"#75bdd7") - set_trait(TRAIT_PLANT_ICON,"mushroom4") - -/datum/seed/mushroom/caverncandle - name = "caverncandle" - seed_name = "caverncandle" - display_name = "cavern candles" - mutants = null - chems = list(/decl/material/liquid/glowsap = list(1,20)) - -/datum/seed/mushroom/caverncandle/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,30) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#9eefff") - set_trait(TRAIT_PRODUCT_ICON,"mushroom3") - set_trait(TRAIT_PRODUCT_COLOUR,"#90d7f0") - set_trait(TRAIT_PLANT_COLOUR,"#75bdd7") - set_trait(TRAIT_PLANT_ICON,"mushroom3") - -/datum/seed/mushroom/plastic - name = "plastic" - seed_name = "plastellium" - display_name = "plastellium" - mutants = null - chems = list(/decl/material/liquid/plasticide = list(1,10)) - -/datum/seed/mushroom/plastic/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"mushroom6") - set_trait(TRAIT_PRODUCT_COLOUR,"#e6e6e6") - set_trait(TRAIT_PLANT_COLOUR,"#e6e6e6") - set_trait(TRAIT_PLANT_ICON,"mushroom10") - -//Flowers/varieties -/datum/seed/flower - name = "harebells" - seed_name = "harebell" - display_name = "harebells" - chems = list(/decl/material/liquid/nutriment = list(1,20)) - -/datum/seed/flower/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_PRODUCT_ICON,"flower5") - set_trait(TRAIT_PRODUCT_COLOUR,"#c492d6") - set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") - set_trait(TRAIT_PLANT_ICON,"flower") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/flower/poppy - name = "poppies" - seed_name = "poppy" - display_name = "poppies" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/painkillers = list(1,10)) - kitchen_tag = "poppy" - -/datum/seed/flower/poppy/New() - ..() - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_PRODUCT_ICON,"flower3") - set_trait(TRAIT_PRODUCT_COLOUR,"#b33715") - set_trait(TRAIT_PLANT_ICON,"flower3") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/flower/sunflower - name = "sunflowers" - seed_name = "sunflower" - display_name = "sunflowers" - -/datum/seed/flower/sunflower/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCT_ICON,"flower2") - set_trait(TRAIT_PRODUCT_COLOUR,"#fff700") - set_trait(TRAIT_PLANT_ICON,"flower2") - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/flower/lavender - name = "lavender" - seed_name = "lavender" - display_name = "lavender" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/brute_meds = list(1,10)) - -/datum/seed/flower/lavender/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_PRODUCT_ICON,"flower6") - set_trait(TRAIT_PRODUCT_COLOUR,"#b57edc") - set_trait(TRAIT_PLANT_COLOUR,"#6b8c5e") - set_trait(TRAIT_PLANT_ICON,"flower4") - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.05) - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - -//Grapes/varieties -/datum/seed/grapes - name = "grapes" - seed_name = "grape" - display_name = "grapevines" - mutants = list("greengrapes") - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/nutriment/sugar = list(1,5), /decl/material/liquid/drink/juice/grape = list(10,10)) - -/datum/seed/grapes/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"grapes") - set_trait(TRAIT_PRODUCT_COLOUR,"#bb6ac4") - set_trait(TRAIT_PLANT_COLOUR,"#378f2e") - set_trait(TRAIT_PLANT_ICON,"vine") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/grapes/green - name = "greengrapes" - seed_name = "green grape" - display_name = "green grapevines" - mutants = null - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/burn_meds = list(3,5), /decl/material/liquid/drink/juice/grape = list(10,10)) - -/datum/seed/grapes/green/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f") - -//Everything else -/datum/seed/peanuts - name = "peanut" - seed_name = "peanut" - display_name = "peanut vines" - chems = list(/decl/material/liquid/nutriment = list(1,10)) - -/datum/seed/peanuts/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"nuts") - set_trait(TRAIT_PRODUCT_COLOUR,"#c4ae7a") - set_trait(TRAIT_PLANT_ICON,"bush2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - -/datum/seed/peppercorn - name = "peppercorn" - seed_name = "peppercorn" - display_name = "black pepper" - chems = list(/decl/material/solid/blackpepper = list(10,10)) - -/datum/seed/peppercorn/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,4) - set_trait(TRAIT_PRODUCTION,4) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"nuts") - set_trait(TRAIT_PRODUCT_COLOUR,"#4d4d4d") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - -/datum/seed/cabbage - name = "cabbage" - seed_name = "cabbage" - display_name = "cabbages" - chems = list(/decl/material/liquid/nutriment = list(1,10)) - kitchen_tag = "cabbage" - -/datum/seed/cabbage/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"cabbage") - set_trait(TRAIT_PRODUCT_COLOUR,"#84bd82") - set_trait(TRAIT_PLANT_COLOUR,"#6d9c6b") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/banana - name = "banana" - seed_name = "banana" - display_name = "banana tree" - chems = list(/decl/material/liquid/drink/juice/banana = list(10,10), /decl/material/solid/potassium = list(2,3)) - trash_type = /obj/item/bananapeel - kitchen_tag = "banana" - -/datum/seed/banana/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_ICON,"bananas") - set_trait(TRAIT_PRODUCT_COLOUR,"#ffec1f") - set_trait(TRAIT_PLANT_COLOUR,"#69ad50") - set_trait(TRAIT_PLANT_ICON,"tree4") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/corn - name = "corn" - seed_name = "corn" - display_name = "ears of corn" - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/nutriment/cornoil = list(1,10)) - kitchen_tag = "corn" - trash_type = /obj/item/corncob - -/datum/seed/corn/New() - ..() - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"corn") - set_trait(TRAIT_PRODUCT_COLOUR,"#fff23b") - set_trait(TRAIT_PLANT_COLOUR,"#87c969") - set_trait(TRAIT_PLANT_ICON,"corn") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/potato - name = "potato" - seed_name = "potato" - display_name = "potatoes" - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/potato = list(10,10)) - kitchen_tag = "potato" - -/datum/seed/potato/New() - ..() - set_trait(TRAIT_PRODUCES_POWER,1) - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"potato") - set_trait(TRAIT_PRODUCT_COLOUR,"#d4cab4") - set_trait(TRAIT_PLANT_ICON,"bush2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/garlic - name = "garlic" - seed_name = "garlic" - display_name = "garlic" - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/garlic = list(10,10)) - kitchen_tag = "garlic" - -/datum/seed/garlic/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,12) - set_trait(TRAIT_PRODUCT_ICON,"bulb") - set_trait(TRAIT_PRODUCT_COLOUR,"#fff8dd") - set_trait(TRAIT_PLANT_ICON,"stalk") - set_trait(TRAIT_WATER_CONSUMPTION, 7) - -/datum/seed/onion - name = "onion" - seed_name = "onion" - display_name = "onions" - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/drink/juice/onion = list(10,10)) - kitchen_tag = "onion" - -/datum/seed/onion/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"bulb") - set_trait(TRAIT_PRODUCT_COLOUR,"#ffeedd") - set_trait(TRAIT_PLANT_ICON,"stalk") - set_trait(TRAIT_WATER_CONSUMPTION, 5) - -/datum/seed/soybean - name = "soybean" - seed_name = "soybean" - display_name = "soybeans" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/drink/milk/soymilk = list(10,20)) - kitchen_tag = "soybeans" - -/datum/seed/soybean/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,4) - set_trait(TRAIT_PRODUCTION,4) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"bean") - set_trait(TRAIT_PRODUCT_COLOUR,"#ebe7c0") - set_trait(TRAIT_PLANT_ICON,"stalk") - -/datum/seed/wheat - name = "wheat" - seed_name = "wheat" - display_name = "wheat stalks" - chems = list(/decl/material/liquid/nutriment = list(1,25), /decl/material/liquid/nutriment/flour = list(15,15)) - kitchen_tag = "wheat" - -/datum/seed/wheat/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"wheat") - set_trait(TRAIT_PRODUCT_COLOUR,"#dbd37d") - set_trait(TRAIT_PLANT_COLOUR,"#bfaf82") - set_trait(TRAIT_PLANT_ICON,"stalk2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/rice - name = "rice" - seed_name = "rice" - display_name = "rice stalks" - chems = list(/decl/material/liquid/nutriment = list(1,25), /decl/material/liquid/nutriment/rice = list(10,15)) - kitchen_tag = "rice" - -/datum/seed/rice/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"rice") - set_trait(TRAIT_PRODUCT_COLOUR,"#d5e6d1") - set_trait(TRAIT_PLANT_COLOUR,"#8ed17d") - set_trait(TRAIT_PLANT_ICON,"stalk2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/carrots - name = "carrot" - seed_name = "carrot" - display_name = "carrots" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/eyedrops = list(3,5), /decl/material/liquid/drink/juice/carrot = list(10,20)) - kitchen_tag = "carrot" - -/datum/seed/carrots/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"carrot") - set_trait(TRAIT_PRODUCT_COLOUR,"#ff9900") - set_trait(TRAIT_PLANT_ICON,"carrot") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/weeds - name = "weeds" - seed_name = "weed" - display_name = "weeds" - -/datum/seed/weeds/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,-1) - set_trait(TRAIT_POTENCY,-1) - set_trait(TRAIT_IMMUTABLE,-1) - set_trait(TRAIT_PRODUCT_ICON,"flower4") - set_trait(TRAIT_PRODUCT_COLOUR,"#fceb2b") - set_trait(TRAIT_PLANT_COLOUR,"#59945a") - set_trait(TRAIT_PLANT_ICON,"bush6") - -/datum/seed/whitebeets - name = "whitebeet" - seed_name = "white-beet" - display_name = "white-beets" - chems = list(/decl/material/liquid/nutriment = list(0,20), /decl/material/liquid/nutriment/sugar = list(1,5)) - kitchen_tag = "whitebeet" - -/datum/seed/whitebeets/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"carrot2") - set_trait(TRAIT_PRODUCT_COLOUR,"#eef5b0") - set_trait(TRAIT_PLANT_COLOUR,"#4d8f53") - set_trait(TRAIT_PLANT_ICON,"carrot2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/sugarcane - name = "sugarcane" - seed_name = "sugarcane" - display_name = "sugarcanes" - chems = list(/decl/material/liquid/nutriment/sugar = list(4,5)) - -/datum/seed/sugarcane/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"stalk") - set_trait(TRAIT_PRODUCT_COLOUR,"#b4d6bd") - set_trait(TRAIT_PLANT_COLOUR,"#6bbd68") - set_trait(TRAIT_PLANT_ICON,"stalk3") - set_trait(TRAIT_IDEAL_HEAT, 298) - -/datum/seed/watermelon - name = "watermelon" - seed_name = "watermelon" - display_name = "watermelon vine" - chems = list(/decl/material/liquid/nutriment = list(1,6), /decl/material/liquid/drink/juice/watermelon = list(10,6)) - -/datum/seed/watermelon/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,1) - set_trait(TRAIT_PRODUCT_ICON,"vine") - set_trait(TRAIT_PRODUCT_COLOUR,"#326b30") - set_trait(TRAIT_PLANT_COLOUR,"#257522") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_FLESH_COLOUR,"#f22c2c") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/pumpkin - name = "pumpkin" - seed_name = "pumpkin" - display_name = "pumpkin vine" - chems = list(/decl/material/liquid/nutriment = list(1,6)) - kitchen_tag = "pumpkin" - -/datum/seed/pumpkin/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"vine2") - set_trait(TRAIT_PRODUCT_COLOUR,"#f9ab28") - set_trait(TRAIT_PLANT_COLOUR,"#bae8c1") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/citrus - name = "lime" - seed_name = "lime" - display_name = "lime trees" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/drink/juice/lime = list(10,20)) - kitchen_tag = "lime" - -/datum/seed/citrus/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,15) - set_trait(TRAIT_PRODUCT_ICON,"treefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#3af026") - set_trait(TRAIT_PLANT_ICON,"tree") - set_trait(TRAIT_FLESH_COLOUR,"#3af026") - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/citrus/lemon - name = "lemon" - seed_name = "lemon" - display_name = "lemon trees" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/drink/juice/lemon = list(10,20)) - kitchen_tag = "lemon" - -/datum/seed/citrus/lemon/New() - ..() - set_trait(TRAIT_PRODUCES_POWER,1) - set_trait(TRAIT_PRODUCT_COLOUR,"#f0e226") - set_trait(TRAIT_FLESH_COLOUR,"#f0e226") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/citrus/orange - name = "orange" - seed_name = "orange" - display_name = "orange trees" - kitchen_tag = "orange" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/drink/juice/orange = list(10,20)) - -/datum/seed/citrus/orange/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#ffc20a") - set_trait(TRAIT_FLESH_COLOUR,"#ffc20a") - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/grass - name = "grass" - seed_name = "grass" - display_name = "grass" - chems = list(/decl/material/liquid/nutriment = list(1,20)) - kitchen_tag = "grass" - -/datum/seed/grass/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,2) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_PRODUCT_ICON,"grass") - set_trait(TRAIT_PRODUCT_COLOUR,"#09ff00") - set_trait(TRAIT_PLANT_COLOUR,"#07d900") - set_trait(TRAIT_PLANT_ICON,"grass") - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/cocoa - name = "cocoa" - seed_name = "cacao" - display_name = "cacao tree" - chems = list(/decl/material/liquid/nutriment = list(1,10), /decl/material/liquid/nutriment/coco = list(4,5)) - -/datum/seed/cocoa/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"treefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#cca935") - set_trait(TRAIT_PLANT_ICON,"tree2") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/cherries - name = "cherry" - seed_name = "cherry" - seed_noun = SEED_NOUN_PITS - display_name = "cherry tree" - chems = list(/decl/material/liquid/nutriment = list(1,15), /decl/material/liquid/nutriment/sugar = list(1,15), /decl/material/liquid/nutriment/cherryjelly = list(10,15)) - kitchen_tag = "cherries" - -/datum/seed/cherries/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"cherry") - set_trait(TRAIT_PRODUCT_COLOUR,"#a80000") - set_trait(TRAIT_PLANT_ICON,"tree2") - set_trait(TRAIT_PLANT_COLOUR,"#2f7d2d") - set_trait(TRAIT_PHOTOSYNTHESIS, 1) - -/datum/seed/kudzu - name = "kudzu" - seed_name = "kudzu" - display_name = "kudzu vines" - chems = list(/decl/material/liquid/nutriment = list(1,50), /decl/material/liquid/antitoxins = list(1,25)) - -/datum/seed/kudzu/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_SPREAD,2) - set_trait(TRAIT_PRODUCT_ICON,"treefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#96d278") - set_trait(TRAIT_PLANT_COLOUR,"#6f7a63") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - -/datum/seed/shand - name = "shand" - seed_name = "S'randar's hand" - display_name = "S'randar's hand leaves" - chems = list(/decl/material/liquid/brute_meds = list(0,10)) - kitchen_tag = "shand" - -/datum/seed/shand/New() - ..() - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"alien3") - set_trait(TRAIT_PRODUCT_COLOUR,"#378c61") - set_trait(TRAIT_PLANT_COLOUR,"#378c61") - set_trait(TRAIT_PLANT_ICON,"tree5") - set_trait(TRAIT_IDEAL_HEAT, 283) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/mtear - name = "mtear" - seed_name = "Messa's tear" - display_name = "Messa's tear leaves" - chems = list(/decl/material/liquid/nutriment/honey = list(1,10), /decl/material/liquid/burn_meds = list(3,5)) - kitchen_tag = "mtear" - -/datum/seed/mtear/New() - ..() - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"alien4") - set_trait(TRAIT_PRODUCT_COLOUR,"#4cc5c7") - set_trait(TRAIT_PLANT_COLOUR,"#4cc789") - set_trait(TRAIT_PLANT_ICON,"bush7") - set_trait(TRAIT_IDEAL_HEAT, 283) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/tobacco - name = "tobacco" - seed_name = "tobacco" - display_name = "tobacco leaves" - mutants = list("finetobacco", "puretobacco", "badtobacco") - chems = list(/decl/material/solid/tobacco = list(1,10)) - -/datum/seed/tobacco/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_PRODUCT_ICON,"tobacco") - set_trait(TRAIT_PRODUCT_COLOUR,"#749733") - set_trait(TRAIT_PLANT_COLOUR,"#749733") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_IDEAL_HEAT, 299) - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/tobacco/finetobacco - name = "finetobacco" - seed_name = "fine tobacco" - display_name = "fine tobacco leaves" - chems = list(/decl/material/solid/tobacco/fine = list(1,10)) - -/datum/seed/tobacco/finetobacco/New() - ..() - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_PRODUCT_COLOUR,"#33571b") - set_trait(TRAIT_PLANT_COLOUR,"#33571b") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.20) - -/datum/seed/tobacco/puretobacco //provides the pure nicotine reagent - name = "puretobacco" - seed_name = "succulent tobacco" - display_name = "succulent tobacco leaves" - chems = list(/decl/material/liquid/nicotine = list(1,10)) - -/datum/seed/tobacco/puretobacco/New() - ..() - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_PRODUCT_COLOUR,"#b7c61a") - set_trait(TRAIT_PLANT_COLOUR,"#b7c61a") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.30) - -/datum/seed/tobacco/bad - name = "badtobacco" - seed_name = "low-grade tobacco" - display_name = "low-grade tobacco leaves" - mutants = list("tobacco") - chems = list(/decl/material/solid/tobacco/bad = list(1,10)) - -/datum/seed/algae - name = "algae" - seed_name = "algae" - display_name = "algae" - chems = list( - /decl/material/liquid/nutriment = list(2,12), - /decl/material/liquid/bromide = list(3,8) - ) - kitchen_tag = "algae" - exude_gasses = list(/decl/material/gas/methyl_bromide = 3) - -/datum/seed/algae/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"algae") - set_trait(TRAIT_PRODUCT_COLOUR,"#84bd82") - set_trait(TRAIT_PLANT_COLOUR,"#6d9c6b") - set_trait(TRAIT_PLANT_ICON,"algae") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/algae/bruisegrass - name = "bruisegrass" - seed_name = "bruisegrass" - display_name = "bruisegrass" - chems = list(/decl/material/liquid/nutriment = list(1,20), /decl/material/liquid/painkillers = list(1,10)) - kitchen_tag = "bruisegrass" - exude_gasses = null - -/datum/seed/algae/bruisegrass/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#8a2546") - set_trait(TRAIT_PLANT_COLOUR,"#8a2546") - -/datum/seed/bamboo - name = "bamboo" - seed_name = "bamboo" - display_name = "bamboo" - chems = list(/decl/material/solid/wood/bamboo = list(6,1)) - mutants = null - -/datum/seed/bamboo/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,1) - set_trait(TRAIT_PRODUCT_ICON,"stalk") - set_trait(TRAIT_PRODUCT_COLOUR, WOOD_COLOR_GENERIC) - set_trait(TRAIT_PLANT_COLOUR,"#99bc20") - set_trait(TRAIT_PLANT_ICON,"stalk3") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seed_datums_aquaculture.dm b/code/modules/hydroponics/seed_datums_aquaculture.dm new file mode 100644 index 000000000000..b894f8cce97d --- /dev/null +++ b/code/modules/hydroponics/seed_datums_aquaculture.dm @@ -0,0 +1,44 @@ +/datum/seed/mollusc + name = "mollusc" + product_name = "mollusc" + display_name = "mollusc bed" + product_type = /obj/item/mollusc + seed_noun = SEED_NOUN_EGGS + mutants = null + allergen_flags = ALLERGEN_FISH + +/datum/seed/mollusc/New() + ..() + set_trait(TRAIT_MATURATION, 10) + set_trait(TRAIT_PRODUCTION, 1) + set_trait(TRAIT_YIELD, 3) + set_trait(TRAIT_POTENCY, 1) + set_trait(TRAIT_PRODUCT_ICON, "mollusc") + set_trait(TRAIT_PLANT_ICON, "mollusc") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_IDEAL_HEAT, 288) + set_trait(TRAIT_LIGHT_TOLERANCE, 6) + set_trait(TRAIT_PRODUCT_COLOUR, "#aaabba") + set_trait(TRAIT_PLANT_COLOUR, "#aaabba") + +/datum/seed/mollusc/clam + name = "clam" + product_name = "clam" + display_name = "clam bed" + product_type = /obj/item/mollusc/clam/fished + +/datum/seed/mollusc/clam/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR, "#9aaca6") + set_trait(TRAIT_PLANT_COLOUR, "#9aaca6") + +/datum/seed/mollusc/barnacle + name = "barnacle" + product_name = "barnacle" + display_name = "barnacle bed" + product_type = /obj/item/mollusc/barnacle/fished + +/datum/seed/mollusc/barnacle/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR, "#c1c0b6") + set_trait(TRAIT_PLANT_COLOUR, "#c1c0b6") diff --git a/code/modules/hydroponics/seed_gene_mut.dm b/code/modules/hydroponics/seed_gene_mut.dm index 419af33535ad..1dbb3b1baf87 100644 --- a/code/modules/hydroponics/seed_gene_mut.dm +++ b/code/modules/hydroponics/seed_gene_mut.dm @@ -1,133 +1,11 @@ -/datum/seed/proc/diverge_mutate_gene(var/decl/plantgene/G, var/turf/T) - if(!istype(G)) +/datum/seed/proc/diverge_mutate_gene(var/decl/plant_gene/gene, var/atom/location) + if(!istype(gene)) log_debug("Attempted to mutate [src] with a non-plantgene var.") return src - var/datum/seed/S = diverge() //Let's not modify all of the seeds. - T.visible_message("\The [S.display_name] quivers!") //Mimicks the normal mutation. - G.mutate(S, T) + var/datum/seed/seed = diverge() //Let's not modify all of the seeds. + location.visible_message("\The [seed.display_name] quivers!") //Mimicks the normal mutation. + gene.mutate(seed, location) - return S + return seed -/decl/plantgene - var/gene_tag - -/decl/plantgene/biochem - gene_tag = GENE_BIOCHEMISTRY - -/decl/plantgene/hardiness - gene_tag = GENE_HARDINESS - -/decl/plantgene/environment - gene_tag = GENE_ENVIRONMENT - -/decl/plantgene/metabolism - gene_tag = GENE_METABOLISM - -/decl/plantgene/structure - gene_tag = GENE_STRUCTURE - -/decl/plantgene/diet - gene_tag = GENE_DIET - -/decl/plantgene/pigment - gene_tag = GENE_PIGMENT - -/decl/plantgene/output - gene_tag = GENE_OUTPUT - -/decl/plantgene/atmosphere - gene_tag = GENE_ATMOSPHERE - -/decl/plantgene/vigour - gene_tag = GENE_VIGOUR - -/decl/plantgene/fruit - gene_tag = GENE_FRUIT - -/decl/plantgene/special - gene_tag = GENE_SPECIAL - -/decl/plantgene/proc/mutate(var/datum/seed/S) - return - -/decl/plantgene/biochem/mutate(var/datum/seed/S) - S.set_trait(TRAIT_POTENCY, S.get_trait(TRAIT_POTENCY)+rand(-20,20),200, 0) - -/decl/plantgene/hardiness/mutate(var/datum/seed/S) - if(prob(60)) - S.set_trait(TRAIT_TOXINS_TOLERANCE, S.get_trait(TRAIT_TOXINS_TOLERANCE)+rand(-2,2),10,0) - if(prob(60)) - S.set_trait(TRAIT_PEST_TOLERANCE, S.get_trait(TRAIT_PEST_TOLERANCE)+rand(-2,2),10,0) - if(prob(60)) - S.set_trait(TRAIT_WEED_TOLERANCE, S.get_trait(TRAIT_WEED_TOLERANCE)+rand(-2,2),10,0) - if(prob(60)) - S.set_trait(TRAIT_ENDURANCE, S.get_trait(TRAIT_ENDURANCE)+rand(-5,5),100,0) - -/decl/plantgene/environment/mutate(var/datum/seed/S) - if(prob(60)) - S.set_trait(TRAIT_IDEAL_HEAT, S.get_trait(TRAIT_IDEAL_HEAT)+rand(-2,2),10,0) - if(prob(60)) - S.set_trait(TRAIT_IDEAL_LIGHT, S.get_trait(TRAIT_IDEAL_LIGHT)+rand(-2,2),10,0) - if(prob(60)) - S.set_trait(TRAIT_LIGHT_TOLERANCE, S.get_trait(TRAIT_LIGHT_TOLERANCE)+rand(-5,5),100,0) - -/decl/plantgene/metabolism/mutate(var/datum/seed/S) - if(prob(65)) - S.set_trait(TRAIT_REQUIRES_NUTRIENTS, S.get_trait(TRAIT_REQUIRES_NUTRIENTS)+rand(-2,2),10,0) - if(prob(65)) - S.set_trait(TRAIT_REQUIRES_WATER, S.get_trait(TRAIT_REQUIRES_WATER)+rand(-2,2),10,0) - if(prob(40)) - S.set_trait(TRAIT_ALTER_TEMP, S.get_trait(TRAIT_ALTER_TEMP)+rand(-5,5),100,0) - -/decl/plantgene/diet/mutate(var/datum/seed/S) - if(prob(60)) - S.set_trait(TRAIT_CARNIVOROUS, S.get_trait(TRAIT_CARNIVOROUS)+rand(-1,1),2,0) - if(prob(60)) - S.set_trait(TRAIT_PARASITE, !S.get_trait(TRAIT_PARASITE)) - if(prob(65)) - S.set_trait(TRAIT_NUTRIENT_CONSUMPTION, S.get_trait(TRAIT_NUTRIENT_CONSUMPTION)+rand(-0.1,0.1),5,0) - if(prob(65)) - S.set_trait(TRAIT_WATER_CONSUMPTION, S.get_trait(TRAIT_WATER_CONSUMPTION)+rand(-1,1),50,0) - -/decl/plantgene/output/mutate(var/datum/seed/S, var/turf/T) - if(prob(50)) - S.set_trait(TRAIT_BIOLUM, !S.get_trait(TRAIT_BIOLUM)) - if(S.get_trait(TRAIT_BIOLUM)) - T.visible_message("\The [S.display_name] begins to glow!") - if(prob(50)) - S.set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190)) - T.visible_message("\The [S.display_name]'s glow changes colour!") - else - T.visible_message("\The [S.display_name]'s glow dims...") - if(prob(60)) - S.set_trait(TRAIT_PRODUCES_POWER, !S.get_trait(TRAIT_PRODUCES_POWER)) - -/decl/plantgene/atmosphere/mutate(var/datum/seed/S) - if(prob(60)) - S.set_trait(TRAIT_HEAT_TOLERANCE, S.get_trait(TRAIT_HEAT_TOLERANCE)+rand(-5,5),800,70) - if(prob(60)) - S.set_trait(TRAIT_LOWKPA_TOLERANCE, S.get_trait(TRAIT_LOWKPA_TOLERANCE)+rand(-5,5),80,0) - if(prob(60)) - S.set_trait(TRAIT_HIGHKPA_TOLERANCE, S.get_trait(TRAIT_HIGHKPA_TOLERANCE)+rand(-5,5),500,110) - -/decl/plantgene/vigour/mutate(var/datum/seed/S, var/turf/T) - if(prob(65)) - S.set_trait(TRAIT_PRODUCTION, S.get_trait(TRAIT_PRODUCTION)+rand(-1,1),10,0) - if(prob(65)) - S.set_trait(TRAIT_MATURATION, S.get_trait(TRAIT_MATURATION)+rand(-1,1),30,0) - if(prob(55)) - S.set_trait(TRAIT_SPREAD, S.get_trait(TRAIT_SPREAD)+rand(-1,1),2,0) - T.visible_message("\The [S.display_name] spasms visibly, shifting in the tray.") - -/decl/plantgene/fruit/mutate(var/datum/seed/S) - if(prob(65)) - S.set_trait(TRAIT_STINGS, !S.get_trait(TRAIT_STINGS)) - if(prob(65)) - S.set_trait(TRAIT_EXPLOSIVE, !S.get_trait(TRAIT_EXPLOSIVE)) - if(prob(65)) - S.set_trait(TRAIT_JUICY, !S.get_trait(TRAIT_JUICY)) - -/decl/plantgene/special/mutate(var/datum/seed/S) - if(prob(65)) - S.set_trait(TRAIT_TELEPORTING, !S.get_trait(TRAIT_TELEPORTING)) diff --git a/code/modules/hydroponics/seed_machines.dm b/code/modules/hydroponics/seed_machines.dm index a1874618fc32..af1d79e8cbd5 100644 --- a/code/modules/hydroponics/seed_machines.dm +++ b/code/modules/hydroponics/seed_machines.dm @@ -1,9 +1,8 @@ /obj/item/disk/botany name = "flora data disk" desc = "A small disk used for carrying data on plant genetics." - icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' - icon_state = "disk" - w_class = ITEM_SIZE_TINY + color = COLOR_GREEN + label = "label_dna" var/list/genes = list() var/genesource = "unknown" @@ -18,16 +17,18 @@ genes = list() genesource = "unknown" -/obj/item/storage/box/botanydisk +/obj/item/box/botanydisk name = "flora disk box" desc = "A box of flora data disks, apparently." - startswith = list(/obj/item/disk/botany = 14) + +/obj/item/box/botanydisk/WillContain() + return list(/obj/item/disk/botany = 14) /obj/machinery/botany icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' icon_state = "hydrotray3" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE var/obj/item/seeds/seed // Currently loaded seed packet. var/obj/item/disk/botany/loaded_disk //Currently loaded data disk. @@ -54,62 +55,58 @@ active = 0 if(failed_task) failed_task = 0 - visible_message("\icon[src] [src] pings unhappily, flashing a red warning light.") + visible_message("[html_icon(src)] [src] pings unhappily, flashing a red warning light.") else - visible_message("\icon[src] [src] pings happily.") + visible_message("[html_icon(src)] [src] pings happily.") if(eject_disk) eject_disk = 0 if(loaded_disk) loaded_disk.dropInto(loc) - visible_message("\icon[src] [src] beeps and spits out [loaded_disk].") + visible_message("[html_icon(src)] [src] beeps and spits out [loaded_disk].") loaded_disk = null -/obj/machinery/botany/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/seeds)) +/obj/machinery/botany/attackby(obj/item/used_item, mob/user) + if(istype(used_item,/obj/item/seeds)) if(seed) to_chat(user, "There is already a seed loaded.") - return - var/obj/item/seeds/S =W + return TRUE + var/obj/item/seeds/S = used_item if(S.seed && S.seed.get_trait(TRAIT_IMMUTABLE) > 0) to_chat(user, "That seed is not compatible with our genetics technology.") - else if(user.unEquip(W, src)) - seed = W - to_chat(user, "You load [W] into [src].") - return + else if(user.try_unequip(used_item, src)) + seed = used_item + to_chat(user, "You load [used_item] into [src].") + return TRUE - if(isScrewdriver(W)) + if(IS_SCREWDRIVER(used_item)) open = !open to_chat(user, "You [open ? "open" : "close"] the maintenance panel.") - return + return TRUE - if(open) - if(isCrowbar(W)) - dismantle() - return + if(open && IS_CROWBAR(used_item)) + dismantle() + return TRUE - if(istype(W,/obj/item/disk/botany)) + if(istype(used_item,/obj/item/disk/botany)) if(loaded_disk) to_chat(user, "There is already a data disk loaded.") - return + return TRUE + var/obj/item/disk/botany/B = used_item + if(B.genes && B.genes.len) + if(!disk_needs_genes) + to_chat(user, "That disk already has gene data loaded.") + return TRUE else - var/obj/item/disk/botany/B = W - - if(B.genes && B.genes.len) - if(!disk_needs_genes) - to_chat(user, "That disk already has gene data loaded.") - return - else - if(disk_needs_genes) - to_chat(user, "That disk does not have any gene data loaded.") - return - if(!user.unEquip(W, src)) - return - loaded_disk = W - to_chat(user, "You load [W] into [src].") - - return - ..() + if(disk_needs_genes) + to_chat(user, "That disk does not have any gene data loaded.") + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + loaded_disk = used_item + to_chat(user, "You load [used_item] into [src].") + return TRUE + return ..() // Allows for a trait to be extracted from a seed packet, destroying that seed. /obj/machinery/botany/extractor @@ -126,9 +123,7 @@ var/list/data = list() - var/list/geneMasks = SSplants.gene_masked_list - data["geneMasks"] = geneMasks - + data["geneMasks"] = SSplants.gene_masked_list data["activity"] = active data["degradation"] = degradation @@ -158,85 +153,73 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/botany/Topic(href, href_list) - - if(..()) - return 1 +/obj/machinery/botany/OnTopic(mob/user, href_list) + if((. = ..())) + return if(href_list["eject_packet"]) - if(!seed) return + if(!seed) return TOPIC_REFRESH // You must be mistaken! We have no seed. seed.dropInto(loc) if(seed.seed.name == "new line" || isnull(SSplants.seeds[seed.seed.name])) - seed.seed.uid = SSplants.seeds.len + 1 + seed.seed.uid = sequential_id(/datum/seed/) seed.seed.name = "[seed.seed.uid]" SSplants.seeds[seed.seed.name] = seed.seed seed.update_seed() - visible_message("\icon[src] [src] beeps and spits out [seed].") + visible_message("[html_icon(src)] \The [src] beeps and spits out [seed].") seed = null + . = TOPIC_REFRESH if(href_list["eject_disk"]) - if(!loaded_disk) return + if(!loaded_disk) return TOPIC_REFRESH loaded_disk.dropInto(loc) - visible_message("\icon[src] [src] beeps and spits out [loaded_disk].") + visible_message("[html_icon(src)] \The [src] beeps and spits out [loaded_disk].") loaded_disk = null + . = TOPIC_REFRESH - usr.set_machine(src) - src.add_fingerprint(usr) - -/obj/machinery/botany/extractor/Topic(href, href_list) - - if(..()) - return 1 - - var/mob/user = usr - user.set_machine(src) - src.add_fingerprint(user) +/obj/machinery/botany/extractor/OnTopic(mob/user, href_list) + if((. = ..())) + return if(href_list["scan_genome"]) - - if(!seed) return - + if(!seed) return TOPIC_REFRESH last_action = world.time - active = 1 + active = TRUE + if(prob(user.skill_fail_chance(SKILL_BOTANY, 100, SKILL_ADEPT))) + failed_task = TRUE + else + genetics = seed.seed + degradation = 0 - if(seed && seed.seed) - if(prob(user.skill_fail_chance(SKILL_BOTANY, 100, SKILL_ADEPT))) - failed_task = 1 - else - genetics = seed.seed - degradation = 0 - - qdel(seed) - seed = null + QDEL_NULL(seed) if(href_list["get_gene"]) + if(!genetics || !loaded_disk) + return TOPIC_REFRESH - if(!genetics || !loaded_disk) return - - last_action = world.time - active = 1 + var/decl/plant_gene/gene_master = locate(href_list["get_gene"]) + if(ispath(gene_master)) + gene_master = GET_DECL(gene_master) - var/datum/plantgene/P = genetics.get_gene(href_list["get_gene"]) - if(!P) return - loaded_disk.genes += P + if(!istype(gene_master)) + return TOPIC_HANDLED // Potential href hacking? + last_action = world.time + active = TRUE + loaded_disk.genes += new /datum/plantgene(gene_master, genetics) loaded_disk.genesource = "[genetics.display_name]" if(!genetics.roundstart) loaded_disk.genesource += " (variety #[genetics.uid])" - - loaded_disk.name += " ([SSplants.gene_tag_masks[href_list["get_gene"]]], #[genetics.uid])" - loaded_disk.desc += " The label reads \'gene [SSplants.gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.display_name]\'." - eject_disk = 1 - + loaded_disk.name += " ([gene_master.name], #[genetics.uid])" + loaded_disk.desc += " The label reads \'gene [gene_master.name], sampled from [genetics.display_name]\'." + eject_disk = TRUE degradation += rand(20,60) + user.skill_fail_chance(SKILL_BOTANY, 100, SKILL_ADEPT) var/expertise = max(0, user.get_skill_value(SKILL_BOTANY) - SKILL_ADEPT) degradation = max(0, degradation - 10*expertise) - if(degradation >= 100) - failed_task = 1 + failed_task = TRUE genetics = null degradation = 0 @@ -276,7 +259,7 @@ for(var/datum/plantgene/P in loaded_disk.genes) if(data["locus"] != "") data["locus"] += ", " - data["locus"] += "[SSplants.gene_tag_masks[P.genetype]]" + data["locus"] += "[P.genetype.name]" else data["disk"] = 0 @@ -295,31 +278,24 @@ ui.open() ui.set_auto_update(1) -/obj/machinery/botany/editor/Topic(href, href_list) - - if(..()) - return 1 +/obj/machinery/botany/editor/OnTopic(mob/user, href_list) + if((. = ..())) + return if(href_list["apply_gene"]) - if(!loaded_disk || !seed) return - - var/mob/user = usr + if(!loaded_disk || !seed) return TOPIC_REFRESH last_action = world.time - active = 1 + active = TRUE if(!isnull(SSplants.seeds[seed.seed.name])) seed.seed = seed.seed.diverge(1) - seed.seed_type = seed.seed.name seed.update_seed() if(prob(seed.modified)) - failed_task = 1 + failed_task = TRUE seed.modified = 101 for(var/datum/plantgene/gene in loaded_disk.genes) seed.seed.apply_gene(gene) var/expertise = max(user.get_skill_value(SKILL_BOTANY) - SKILL_ADEPT) seed.modified += rand(5,10) + min(-5, 30 * expertise) - - usr.set_machine(src) - src.add_fingerprint(usr) diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm index 7d76e3f7af95..6f12b930e6e0 100644 --- a/code/modules/hydroponics/seed_mobs.dm +++ b/code/modules/hydroponics/seed_mobs.dm @@ -2,17 +2,15 @@ /datum/seed/proc/handle_living_product(var/mob/living/host) if(!host || !istype(host)) return - var/datum/ghosttrap/plant/P = get_ghost_trap("living plant") + var/decl/ghosttrap/P = GET_DECL(/decl/ghosttrap/sentient_plant) P.request_player(host, "Someone is harvesting \a [display_name].", 15 SECONDS) spawn(15 SECONDS) if(!host.ckey && !host.client) - host.death() // This seems redundant, but a lot of mobs don't + host.death() // This seems redundant, but a lot of mobs don't host.set_stat(DEAD) // handle death() properly. Better safe than etc. host.visible_message("\The [host] is malformed and unable to survive. It expires pitifully, leaving behind some seeds.") var/total_yield = rand(1,3) for(var/j = 0;j<=total_yield;j++) - var/obj/item/seeds/S = new(get_turf(host)) - S.seed_type = name - S.update_seed() + new /obj/item/seeds(get_turf(host), null, name) diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm index c5383150c4bc..c86b81ef2e98 100644 --- a/code/modules/hydroponics/seed_packets.dm +++ b/code/modules/hydroponics/seed_packets.dm @@ -1,286 +1,387 @@ -var/global/list/plant_seed_sprites = list() - //Seed packet object/procs. /obj/item/seeds name = "packet of seeds" - icon = 'icons/obj/seeds.dmi' + icon = 'icons/obj/seeds/seed_packets.dmi' icon_state = "seedy" w_class = ITEM_SIZE_SMALL + abstract_type = /obj/item/seeds + max_health = 10 //Can't set a material, otherwise extracting seeds would generate free materials + material = /decl/material/solid/organic/plantmatter/pith + chem_volume = 3 - var/seed_type + var/seed_mask_icon = 'icons/obj/seeds/seed_masks.dmi' + var/seed_base_name = "packet" var/datum/seed/seed var/modified = 0 -/obj/item/seeds/Initialize() +/obj/item/seeds/Initialize(loc, material, _seed) + if(isnull(seed) && !isnull(_seed)) + seed = _seed update_seed() . = ..() +/obj/item/seeds/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/oil/plant, 3) + +/obj/item/seeds/get_single_monetary_worth() + . = seed ? seed.get_monetary_value() : ..() + +// Used for extracts/seed sampling purposes. +/obj/item/seeds/modified + is_spawnable_type = FALSE + //Grabs the appropriate seed datum from the global list. /obj/item/seeds/proc/update_seed() - if(!seed && seed_type && !isnull(SSplants.seeds) && SSplants.seeds[seed_type]) - seed = SSplants.seeds[seed_type] - update_appearance() + if(istext(seed) && SSplants.seeds[seed]) + seed = SSplants.seeds[seed] + if(seed && !istype(seed)) + PRINT_STACK_TRACE("Seed packet was supplied invalid seed name '[seed]'!") + seed = null + if(seed?.scannable_result) + set_extension(src, /datum/extension/scannable, seed.scannable_result) + else if(has_extension(src, /datum/extension/scannable)) + remove_extension(src, /datum/extension/scannable) + update_icon() + +/obj/item/seeds/proc/get_seed_packet_state() + return seed?.get_trait(TRAIT_PRODUCT_ICON) //Updates strings and icon appropriately based on seed datum. -/obj/item/seeds/proc/update_appearance() - if(!seed) return +/obj/item/seeds/on_update_icon() + . = ..() + if(!seed) + return // Update icon. - overlays.Cut() - var/is_seeds = ((seed.seed_noun in list(SEED_NOUN_SEEDS, SEED_NOUN_PITS, SEED_NOUN_NODES)) ? 1 : 0) - var/image/seed_mask - var/seed_base_key = "base-[is_seeds ? seed.get_trait(TRAIT_PLANT_COLOUR) : "spores"]" - if(plant_seed_sprites[seed_base_key]) - seed_mask = plant_seed_sprites[seed_base_key] - else - seed_mask = image('icons/obj/seeds.dmi',"[is_seeds ? "seed" : "spore"]-mask") - if(is_seeds) // Spore glass bits aren't coloured. - seed_mask.color = seed.get_trait(TRAIT_PLANT_COLOUR) - plant_seed_sprites[seed_base_key] = seed_mask - - var/image/seed_overlay - var/seed_overlay_key = "[seed.get_trait(TRAIT_PRODUCT_ICON)]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]" - if(plant_seed_sprites[seed_overlay_key]) - seed_overlay = plant_seed_sprites[seed_overlay_key] - else - seed_overlay = image('icons/obj/seeds.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]") - seed_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) - plant_seed_sprites[seed_overlay_key] = seed_overlay - - overlays |= seed_mask - overlays |= seed_overlay - + underlays.Cut() + icon_state = get_seed_packet_state() || "unknown" + color = seed.get_trait(TRAIT_PRODUCT_COLOUR) + + var/static/list/seed_nouns = list( + SEED_NOUN_SEEDS, + SEED_NOUN_PITS, + SEED_NOUN_NODES + ) + var/is_seeds = (seed.seed_noun in seed_nouns) + if(seed_mask_icon) + if(is_seeds) + underlays += overlay_image(seed_mask_icon, "seed-mask", seed.get_trait(TRAIT_PLANT_COLOUR), RESET_COLOR) + else + add_overlay(overlay_image(seed_mask_icon, "spore-mask", null, RESET_COLOR)) + update_strings(is_seeds) + +/obj/item/seeds/proc/update_strings(is_seeds) if(is_seeds) - src.SetName("packet of [seed.seed_name] [seed.seed_noun]") - src.desc = "It has a picture of [seed.display_name] on the front." + SetName("[seed_base_name] of [seed.product_name] [seed.seed_noun]") + desc = "It has a picture of \a [seed.display_name] on the front." else - src.SetName("sample of [seed.seed_name] [seed.seed_noun]") - src.desc = "It's labelled as coming from [seed.display_name]." + SetName("sample of [seed.product_name] [seed.seed_noun]") + desc = "It's labelled as coming from \a [seed.display_name]." -/obj/item/seeds/examine(mob/user) +/obj/item/seeds/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(seed && !seed.roundstart) - to_chat(user, "It's tagged as variety #[seed.uid].") + . += "It's tagged as variety #[seed.uid]." + +/obj/item/seeds/extracted + name = "handful of seeds" + desc = "A handful of nondescript seeds." + icon = 'icons/obj/seeds/seed_raw.dmi' + icon_state = "seeds" + seed_base_name = "handful" + seed_mask_icon = null + is_spawnable_type = FALSE + +/obj/item/seeds/extracted/get_seed_packet_state() + return seed.seed_noun -/obj/item/seeds/cutting +/obj/item/seeds/extracted/update_strings(is_seeds) + if(is_seeds) + SetName("[seed_base_name] of [seed.display_name] [seed.seed_noun]") + else + SetName("sample of [seed.display_name] [seed.seed_noun]") + +/obj/item/seeds/extracted/cutting name = "cuttings" desc = "Some plant cuttings." -/obj/item/seeds/cutting/update_appearance() - ..() - src.SetName("packet of [seed.seed_name] cuttings") +/obj/item/seeds/extracted/cutting/get_seed_packet_state() + return SEED_NOUN_CUTTINGS + +/obj/item/seeds/extracted/cutting/update_strings(is_seeds) + SetName("[seed_base_name] of [seed.display_name] cuttings") /obj/item/seeds/random - seed_type = null + seed = null /obj/item/seeds/random/Initialize() seed = SSplants.create_random_seed() - seed_type = seed.name . = ..() /obj/item/seeds/chiliseed - seed_type = "chili" + seed = "chili" /obj/item/seeds/plastiseed - seed_type = "plastic" + seed = "plastic" /obj/item/seeds/grapeseed - seed_type = "grapes" + seed = "grapes" /obj/item/seeds/greengrapeseed - seed_type = "greengrapes" + seed = "greengrapes" /obj/item/seeds/peanutseed - seed_type = "peanut" + seed = "peanut" /obj/item/seeds/cabbageseed - seed_type = "cabbage" + seed = "cabbage" /obj/item/seeds/shandseed - seed_type = "shand" + seed = "shand" /obj/item/seeds/mtearseed - seed_type = "mtear" + seed = "mtear" /obj/item/seeds/berryseed - seed_type = "berries" + seed = "berries" /obj/item/seeds/blueberryseed - seed_type = "blueberries" + seed = "blueberries" /obj/item/seeds/glowberryseed - seed_type = "glowberries" + seed = "glowberries" /obj/item/seeds/bananaseed - seed_type = "banana" + seed = "banana" /obj/item/seeds/eggplantseed - seed_type = "eggplant" + seed = "eggplant" /obj/item/seeds/bloodtomatoseed - seed_type = "bloodtomato" + seed = "bloodtomato" /obj/item/seeds/tomatoseed - seed_type = "tomato" + seed = "tomato" /obj/item/seeds/killertomatoseed - seed_type = "killertomato" + seed = "killertomato" /obj/item/seeds/bluetomatoseed - seed_type = "bluetomato" + seed = "bluetomato" /obj/item/seeds/quantumatoseed - seed_type = "quantumato" + seed = "quantumato" /obj/item/seeds/cornseed - seed_type = "corn" + seed = "corn" /obj/item/seeds/poppyseed - seed_type = "poppies" + seed = "poppies" /obj/item/seeds/potatoseed - seed_type = "potato" + seed = "potato" /obj/item/seeds/icepepperseed - seed_type = "icechili" + seed = "icechili" /obj/item/seeds/soyaseed - seed_type = "soybean" + seed = "soybeans" /obj/item/seeds/wheatseed - seed_type = "wheat" + seed = "wheat" /obj/item/seeds/riceseed - seed_type = "rice" + seed = "rice" /obj/item/seeds/carrotseed - seed_type = "carrot" + seed = "carrot" /obj/item/seeds/reishimycelium - seed_type = "reishi" + seed = "reishi" /obj/item/seeds/amanitamycelium - seed_type = "amanita" + seed = "amanita" /obj/item/seeds/angelmycelium - seed_type = "destroyingangel" + seed = "destroyingangel" /obj/item/seeds/libertymycelium - seed_type = "libertycap" + seed = "libertycap" /obj/item/seeds/chantermycelium - seed_type = "mushrooms" + seed = "mushrooms" -/obj/item/seeds/corkwood - seed_type = "corkwood" +/obj/item/seeds/towercap + seed = "towercap" /obj/item/seeds/glowbell - seed_type = "glowbell" + seed = "glowbell" /obj/item/seeds/plumpmycelium - seed_type = "plumphelmet" + seed = "plumphelmet" /obj/item/seeds/walkingmushroommycelium - seed_type = "walkingmushroom" + seed = "walkingmushroom" /obj/item/seeds/nettleseed - seed_type = "nettle" + seed = "nettle" /obj/item/seeds/deathnettleseed - seed_type = "deathnettle" + seed = "deathnettle" /obj/item/seeds/weeds - seed_type = "weeds" + seed = "weeds" /obj/item/seeds/harebell - seed_type = "harebells" + seed = "harebells" /obj/item/seeds/sunflowerseed - seed_type = "sunflowers" + seed = "sunflowers" /obj/item/seeds/lavenderseed - seed_type = "lavender" + seed = "lavender" /obj/item/seeds/brownmold - seed_type = "mold" + seed = "mold" /obj/item/seeds/appleseed - seed_type = "apple" + seed = "apple" /obj/item/seeds/poisonedappleseed - seed_type = "poisonapple" + seed = "poisonapple" /obj/item/seeds/goldappleseed - seed_type = "goldapple" + seed = "goldapple" /obj/item/seeds/ambrosiavulgarisseed - seed_type = "biteleaf" + seed = "ambrosiavulgaris" /obj/item/seeds/ambrosiadeusseed - seed_type = "ambrosiadeus" + seed = "ambrosiadeus" /obj/item/seeds/whitebeetseed - seed_type = "whitebeet" + seed = "whitebeet" /obj/item/seeds/sugarcaneseed - seed_type = "sugarcane" + seed = "sugarcane" /obj/item/seeds/watermelonseed - seed_type = "watermelon" + seed = "watermelon" /obj/item/seeds/pumpkinseed - seed_type = "pumpkin" + seed = "pumpkin" /obj/item/seeds/limeseed - seed_type = "lime" + seed = "lime" /obj/item/seeds/lemonseed - seed_type = "lemon" + seed = "lemon" /obj/item/seeds/orangeseed - seed_type = "orange" + seed = "orange" /obj/item/seeds/poisonberryseed - seed_type = "poisonberries" + seed = "poisonberries" /obj/item/seeds/deathberryseed - seed_type = "deathberries" + seed = "deathberries" /obj/item/seeds/grassseed - seed_type = "grass" + seed = "grass" /obj/item/seeds/cocoapodseed - seed_type = "cocoa" + seed = "cocoa" /obj/item/seeds/cherryseed - seed_type = "cherry" + seed = "cherry" /obj/item/seeds/tobaccoseed - seed_type = "tobacco" + seed = "tobacco" /obj/item/seeds/finetobaccoseed - seed_type = "finetobacco" + seed = "finetobacco" /obj/item/seeds/puretobaccoseed - seed_type = "puretobacco" + seed = "puretobacco" /obj/item/seeds/kudzuseed - seed_type = "kudzu" + seed = "kudzu" /obj/item/seeds/peppercornseed - seed_type = "peppercorn" + seed = "peppercorn" /obj/item/seeds/garlicseed - seed_type = "garlic" + seed = "garlic" /obj/item/seeds/onionseed - seed_type = "onion" + seed = "onion" /obj/item/seeds/algaeseed - seed_type = "algae" + seed = "algae" /obj/item/seeds/bamboo - seed_type = "bamboo" + seed = "bamboo" + +/obj/item/seeds/clam + seed = "clam" + +/obj/item/seeds/barnacle + seed = "barnacle" + +/obj/item/seeds/mollusc + seed = "mollusc" + +/obj/item/seeds/cotton + seed = "cotton" + +/obj/item/seeds/flax + seed = "flax" + +/obj/item/seeds/hemp + seed = "hemp" + +/obj/item/seeds/yarrow + seed = "yarrow" + +/obj/item/seeds/aloe + seed = "aloe" + +/obj/item/seeds/ginseng + seed = "ginseng" + +/obj/item/seeds/valerian + seed = "valerian" + +/obj/item/seeds/foxglove + seed = "foxglove" + +/obj/item/seeds/extracted/yarrow + seed = "yarrow" + +/obj/item/seeds/extracted/aloe + seed = "aloe" + +/obj/item/seeds/extracted/ginseng + seed = "ginseng" + +/obj/item/seeds/extracted/valerian + seed = "valerian" + +/obj/item/seeds/extracted/foxglove + seed = "foxglove" + +/obj/item/seeds/extracted/cabbage + seed = "cabbage" + +/obj/item/seeds/extracted/carrot + seed = "carrot" + +/obj/item/seeds/extracted/potato + seed = "potato" + +/obj/item/seeds/extracted/wheat + seed = "wheat" -/obj/item/seeds/bruisegrassseed - seed_type = "bruisegrass" \ No newline at end of file +/obj/item/seeds/extracted/rice + seed = "rice" diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index ba842f3c2638..02ae238c326e 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -3,17 +3,15 @@ var/amount var/datum/seed/seed_type // Keeps track of what our seed is var/list/obj/item/seeds/seeds = list() // Tracks actual objects contained in the pile - var/ID -/datum/seed_pile/New(var/obj/item/seeds/O, var/ID) - name = O.name +/datum/seed_pile/New(var/obj/item/seeds/new_seeds) + name = new_seeds.name amount = 1 - seed_type = O.seed - seeds += O - src.ID = ID + seed_type = new_seeds.seed + seeds += new_seeds -/datum/seed_pile/proc/matches(var/obj/item/seeds/O) - if (O.seed == seed_type) +/datum/seed_pile/proc/matches(var/obj/item/seeds/check_seeds) + if (check_seeds.seed == seed_type) return 1 return 0 @@ -24,10 +22,10 @@ /obj/machinery/seed_storage name = "Seed storage" desc = "It stores, sorts, and dispenses seeds." - icon = 'icons/obj/vending.dmi' - icon_state = "seeds" - density = 1 - anchored = 1 + icon = 'icons/obj/machines/vending/seeds_grey.dmi' + icon_state = ICON_STATE_WORLD + density = TRUE + anchored = TRUE idle_power_usage = 100 obj_flags = OBJ_FLAG_ANCHORABLE @@ -47,12 +45,11 @@ if(isnull(amount)) amount = 1 for (var/i = 1 to amount) - var/O = new typepath - add(O) + add(new typepath) /obj/machinery/seed_storage/Destroy() QDEL_NULL_LIST(piles) - . = ..() + . = ..() /obj/machinery/seed_storage/random // This is mostly for testing, but I guess admins could spawn it name = "Random seed storage" @@ -62,7 +59,6 @@ /obj/machinery/seed_storage/garden name = "Garden seed storage" scanner = list("stats") - icon_state = "seeds_generic" starting_seeds = list( /obj/item/seeds/ambrosiavulgarisseed = 15, /obj/item/seeds/appleseed = 15, @@ -109,7 +105,10 @@ /obj/item/seeds/watermelonseed = 15, /obj/item/seeds/wheatseed = 15, /obj/item/seeds/whitebeetseed = 15, - /obj/item/seeds/algaeseed = 15 + /obj/item/seeds/algaeseed = 15, + /obj/item/seeds/clam = 15, + /obj/item/seeds/barnacle = 15, + /obj/item/seeds/mollusc = 15 ) /obj/machinery/seed_storage/xenobotany @@ -159,7 +158,7 @@ /obj/item/seeds/shandseed = 15, /obj/item/seeds/tobaccoseed = 15, /obj/item/seeds/tomatoseed = 15, - /obj/item/seeds/corkwood = 15, + /obj/item/seeds/towercap = 15, /obj/item/seeds/watermelonseed = 15, /obj/item/seeds/wheatseed = 15, /obj/item/seeds/whitebeetseed = 15, @@ -192,12 +191,13 @@ if ("soil" in scanner) dat += "NutriWater" dat += "NotesAmount" - for (var/datum/seed_pile/S in piles) + for (var/key in 1 to length(piles)) + var/datum/seed_pile/S = piles[key] var/datum/seed/seed = S.seed_type if(!seed) continue dat += "" - dat += "[seed.seed_name]" + dat += "[seed.product_name]" dat += "#[seed.uid]" if ("stats" in scanner) dat += "[seed.get_trait(TRAIT_ENDURANCE)][seed.get_trait(TRAIT_YIELD)][seed.get_trait(TRAIT_MATURATION)][seed.get_trait(TRAIT_PRODUCTION)][seed.get_trait(TRAIT_POTENCY)]" @@ -278,95 +278,79 @@ dat += "LUM " dat += "" dat += "[S.amount]" - dat += "Vend Purge" + dat += "Vend Purge" dat += "" dat += "" show_browser(user, dat, "window=seedstorage;size=800x500") onclose(user, "seedstorage") -/obj/machinery/seed_storage/Topic(var/href, var/list/href_list) - if (..()) +/obj/machinery/seed_storage/OnTopic(mob/user, href_list) + if((. = ..())) return var/task = href_list["task"] - var/ID = text2num(href_list["id"]) + var/id = text2num(href_list["id"]) + var/datum/seed_pile/our_pile = LAZYACCESS(piles, id) - for (var/datum/seed_pile/N in piles) - if (N.ID == ID) - if (task == "vend") - var/obj/O = pick(N.seeds) - if (O) - --N.amount - N.seeds -= O - if (N.amount <= 0 || N.seeds.len <= 0) - piles -= N - qdel(N) - flick("[initial(icon_state)]-vend", src) - O.dropInto(loc) - else - piles -= N - qdel(N) - else if (task == "purge") - for (var/obj/O in N.seeds) - qdel(O) - piles -= N - qdel(N) - break - updateUsrDialog() + switch(task) + if ("vend") + var/obj/vending_seeds = pick(our_pile.seeds) + if (vending_seeds) + --our_pile.amount + our_pile.seeds -= vending_seeds + if (our_pile.amount <= 0 || our_pile.seeds.len <= 0) + piles -= our_pile + qdel(our_pile) + flick("[initial(icon_state)]-vend", src) + vending_seeds.dropInto(loc) + . = TOPIC_REFRESH + if ("purge") + QDEL_LIST(our_pile.seeds) + our_pile.seeds.Cut() + . = TOPIC_REFRESH + if(!length(our_pile.seeds)) + piles -= our_pile + QDEL_NULL(our_pile) -/obj/machinery/seed_storage/attackby(var/obj/item/O, var/mob/user) - if (istype(O, /obj/item/seeds)) - add(O) - user.visible_message("[user] puts \the [O.name] into \the [src].", "You put \the [O] into \the [src].") - return - if (istype(O, /obj/item/storage/plants)) - var/obj/item/storage/P = O +/obj/machinery/seed_storage/attackby(var/obj/item/used_item, var/mob/user) + + if(istype(used_item, /obj/item/seeds)) + add(used_item) + user.visible_message(SPAN_NOTICE("\The [user] puts \the [used_item] into \the [src].")) + return TRUE + + if(istype(used_item, /obj/item/plant_satchel) && used_item.storage) var/loaded = 0 - for(var/obj/item/seeds/G in P.contents) + for(var/obj/item/seeds/G in storage.get_contents()) ++loaded - P.remove_from_storage(G, src, 1) + used_item.storage.remove_from_storage(user, G, src, TRUE) add(G, 1) - P.finish_bulk_removal() + used_item.storage.finish_bulk_removal() if (loaded) - user.visible_message("[user] puts the seeds from \the [O.name] into \the [src].", "You put the seeds from \the [O.name] into \the [src].") + user.visible_message(SPAN_NOTICE("\The [user] puts the seeds from \the [used_item] into \the [src].")) else - to_chat(user, "There are no seeds in \the [O.name].") - return + to_chat(user, SPAN_WARNING("There are no seeds in \the [used_item].")) + return TRUE + return ..() -/obj/machinery/seed_storage/proc/add(var/obj/item/seeds/O, bypass_removal = 0) +/obj/machinery/seed_storage/proc/add(var/obj/item/seeds/adding_seeds, bypass_removal = 0) if(!bypass_removal) - if (istype(O.loc, /mob)) - var/mob/user = O.loc - if(!user.unEquip(O, src)) + if (ismob(adding_seeds.loc)) + var/mob/user = adding_seeds.loc + if(!user.try_unequip(adding_seeds, src)) return - else if(istype(O.loc,/obj/item/storage)) - var/obj/item/storage/S = O.loc - S.remove_from_storage(O, src) + else if(isobj(adding_seeds.loc)) + adding_seeds.loc?.storage?.remove_from_storage(null, adding_seeds, src) - O.forceMove(src) - var/newID = 0 + adding_seeds.forceMove(src) for (var/datum/seed_pile/N in piles) - if (N.matches(O)) + if (N.matches(adding_seeds)) ++N.amount - N.seeds += (O) + N.seeds += adding_seeds return - else if(N.ID >= newID) - newID = N.ID + 1 - piles += new /datum/seed_pile(O, newID) + piles += new /datum/seed_pile(adding_seeds) flick("[initial(icon_state)]-vend", src) return - -/obj/machinery/seed_storage/cannot_transition_to(state_path, mob/user) - if(state_path == /decl/machine_construction/default/deconstructed) - var/alert = alert(user, "Are you certain you wish to deconstruct this? It will destroy all seeds stored inside!", "Deconstruct Warning", "Yes", "No") - if(alert != "Yes" || !CanPhysicallyInteract(user)) - return MCS_BLOCK - return ..() - -/obj/machinery/seed_storage/dismantle() - for(var/obj/item/seeds/seed in src) - qdel(seed) // ..() would dump them; this would cause lots of client lag. We did warn them above... - return ..() \ No newline at end of file diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index 2e031cabc6d3..18dc92c3ce02 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -3,7 +3,7 @@ /proc/spacevine_infestation(var/potency_min=70, var/potency_max=100, var/maturation_min=5, var/maturation_max=15) spawn() //to stop the secrets panel hanging - var/turf/T = pick_subarea_turf(/area/hallway , list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) + var/turf/T = pick_area_turf_by_flag(AREA_FLAG_HALLWAY, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) if(T) var/datum/seed/seed = SSplants.create_random_seed(1) seed.set_trait(TRAIT_SPREAD,2) // So it will function properly as vines. @@ -13,38 +13,39 @@ seed.set_trait(TRAIT_STINGS, 1) seed.set_trait(TRAIT_CARNIVOROUS,2) - seed.display_name = "strange plants" //more thematic for the vine infestation event + seed.display_name = "strange plant" //more thematic for the vine infestation event //make vine zero start off fully matured new /obj/effect/vine(T, seed, null, 1) - log_and_message_admins("Spacevines spawned in \the [get_area(T)]", location = T) + log_and_message_admins("Spacevines spawned in \the [get_area_name(T)]", location = T) return log_and_message_admins("Event: Spacevines failed to find a viable turf.") /obj/effect/dead_plant - anchored = 1 - opacity = 0 - density = 0 + anchored = TRUE + opacity = FALSE + density = FALSE color = DEAD_PLANT_COLOUR /obj/effect/dead_plant/attack_hand() + SHOULD_CALL_PARENT(FALSE) qdel(src) + return TRUE /obj/effect/dead_plant/attackby() ..() qdel(src) + return TRUE // if we're deleted we can't do any further interactions /obj/effect/vine name = "vine" - anchored = 1 + anchored = TRUE icon = 'icons/obj/hydroponics/hydroponics_growing.dmi' icon_state = "" pass_flags = PASS_FLAG_TABLE - mouse_opacity = 1 - - var/health = 10 - var/max_health = 100 + mouse_opacity = MOUSE_OPACITY_NORMAL + max_health = 10 var/growth_threshold = 0 var/growth_type = 0 var/max_growth = 0 @@ -54,7 +55,6 @@ var/possible_children = 20 var/spread_chance = 30 var/spread_distance = 4 - var/evolve_chance = 2 var/mature_time //minimum maturation time var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant @@ -71,9 +71,6 @@ parent.possible_children = max(0, parent.possible_children - 1) seed = newseed - if(start_matured) - mature_time = 0 - health = max_health if(!istype(seed)) seed = SSplants.seeds[DEFAULT_SEED] if(!seed) @@ -81,8 +78,12 @@ name = seed.display_name max_health = round(seed.get_trait(TRAIT_ENDURANCE)/2) + if(start_matured) + mature_time = 0 + current_health = get_max_health() + if(seed.get_trait(TRAIT_SPREAD) == 2) - mouse_opacity = 2 + mouse_opacity = MOUSE_OPACITY_PRIORITY max_growth = VINE_GROWTH_STAGES growth_threshold = max_health/VINE_GROWTH_STAGES growth_type = seed.get_growth_type() @@ -103,12 +104,13 @@ /obj/effect/vine/Destroy() wake_neighbors() + parent = null STOP_PROCESSING(SSvines, src) return ..() /obj/effect/vine/on_update_icon() overlays.Cut() - var/growth = growth_threshold ? min(max_growth, round(health/growth_threshold)) : 1 + var/growth = growth_threshold ? min(max_growth, round(current_health/growth_threshold)) : 1 var/at_fringe = get_dist(src,parent) if(spread_distance > 5) if(at_fringe >= spread_distance-3) @@ -120,14 +122,14 @@ var/ikey = "\ref[seed]-plant-[growth]" if(!SSplants.plant_icon_cache[ikey]) - SSplants.plant_icon_cache[ikey] = seed.get_icon(growth) + SSplants.plant_icon_cache[ikey] = seed.get_growth_stage_overlay(growth) overlays += SSplants.plant_icon_cache[ikey] if(growth > 2 && growth == max_growth) layer = (seed && seed.force_layer) ? seed.force_layer : ABOVE_OBJ_LAYER if(growth_type in list(GROWTH_VINES,GROWTH_BIOMASS)) set_opacity(1) - if(islist(seed.chems) && !isnull(seed.chems[/decl/material/solid/wood])) + if(seed.get_chemical_amount(/decl/material/solid/organic/wood)) set_density(1) set_opacity(1) @@ -154,7 +156,7 @@ // Apply colour and light from seed datum. if(seed.get_trait(TRAIT_BIOLUM)) - set_light(0.5, 0.1, 3, l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR)) + set_light(1 + round(seed.get_trait(TRAIT_POTENCY) / 20), l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR)) else set_light(0) @@ -165,7 +167,7 @@ var/direction = 16 - for(var/wallDir in GLOB.cardinal) + for(var/wallDir in global.cardinal) var/turf/newTurf = get_step(T,wallDir) if(newTurf && newTurf.density) direction |= wallDir @@ -179,10 +181,9 @@ direction &= ~shroom.dir var/list/dirList = list() - - for(var/i=1,i<=16,i <<= 1) - if(direction & i) - dirList += i + for(var/checkdir in global.alldirs) + if(direction & checkdir) + dirList += checkdir if(dirList.len) var/newDir = pick(dirList) @@ -194,44 +195,30 @@ floor = 1 return 1 -/obj/effect/vine/attackby(var/obj/item/W, var/mob/user) +/obj/effect/vine/attackby(var/obj/item/used_item, var/mob/user) START_PROCESSING(SSvines, src) - if(W.edge && W.w_class < ITEM_SIZE_NORMAL && user.a_intent != I_HURT) + if(used_item.has_edge() && used_item.w_class < ITEM_SIZE_NORMAL && !user.check_intent(I_FLAG_HARM)) if(!is_mature()) to_chat(user, SPAN_WARNING("\The [src] is not mature enough to yield a sample yet.")) - return + return TRUE if(!seed) to_chat(user, SPAN_WARNING("There is nothing to take a sample from.")) - return + return TRUE var/needed_skill = seed.mysterious ? SKILL_ADEPT : SKILL_BASIC if(prob(user.skill_fail_chance(SKILL_BOTANY, 90, needed_skill))) to_chat(user, SPAN_WARNING("You failed to get a usable sample.")) else seed.harvest(user,0,1) - health -= (rand(3,5)*5) + current_health -= (rand(3,5)*5) + return TRUE else - ..() - var/damage = W.force - if(W.edge) + . = ..() + var/damage = used_item.expend_attack_force(user) + if(used_item.has_edge()) damage *= 2 adjust_health(-damage) - playsound(get_turf(src), W.hitsound, 100, 1) - -/obj/effect/vine/AltClick(var/mob/user) - if(!CanPhysicallyInteract(user) || user.incapacitated()) - return ..() - var/obj/item/W = user.get_active_hand() - if(istype(W) && W.edge && W.w_class >= ITEM_SIZE_NORMAL) - visible_message(SPAN_NOTICE("[user] starts chopping down \the [src].")) - playsound(, W.hitsound, 100, 1) - var/chop_time = (health/W.force) * 0.5 SECONDS - if(user.skill_check(SKILL_BOTANY, SKILL_ADEPT)) - chop_time *= 0.5 - if(do_after(user, chop_time, src, TRUE)) - visible_message(SPAN_NOTICE("[user] chops down \the [src].")) - playsound(get_turf(src), W.hitsound, 100, 1) - die_off() + playsound(get_turf(src), used_item.hitsound, 100, 1) //handles being overrun by vines - note that attacker_parent may be null in some cases /obj/effect/vine/proc/vine_overrun(datum/seed/attacker_seed, obj/effect/vine/attacker_parent) @@ -258,7 +245,7 @@ if(aggression > 0) adjust_health(-aggression*5) -/obj/effect/vine/physically_destroyed() +/obj/effect/vine/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) die_off() . = TRUE @@ -266,15 +253,40 @@ /obj/effect/vine/explosion_act(severity) . = ..() if(. && !QDELETED(src) && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))) - physically_destroyed(src) + physically_destroyed() /obj/effect/vine/proc/adjust_health(value) - health = Clamp(health + value, 0, max_health) - if(health <= 0) + current_health = clamp(current_health + value, 0, get_max_health()) + if(current_health <= 0) die_off() /obj/effect/vine/proc/is_mature() - return (health >= (max_health/3) && world.time > mature_time) + return (current_health >= (get_max_health()/3) && world.time > mature_time) /obj/effect/vine/is_burnable() - return seed.get_trait(TRAIT_HEAT_TOLERANCE) < 1000 \ No newline at end of file + return seed.get_trait(TRAIT_HEAT_TOLERANCE) < 1000 + +/obj/effect/vine/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/vine_chop) + +/decl/interaction_handler/vine_chop + name = "Chop Down" + expected_target_type = /obj/effect/vine + examine_desc = "chop $TARGET_THEM$ down" + +/decl/interaction_handler/vine_chop/invoked(atom/target, mob/user, obj/item/prop) + var/obj/effect/vine/vine = target + var/obj/item/holding = user.get_active_held_item() + if(!istype(holding) || !holding.has_edge() || holding.w_class < ITEM_SIZE_NORMAL) + to_chat(user, SPAN_WARNING("You need a larger or sharper object for this task!")) + return + user.visible_message(SPAN_NOTICE("\The [user] starts chopping down \the [vine].")) + playsound(get_turf(vine), holding.hitsound, 100, 1) + var/chop_time = (vine.current_health/holding.expend_attack_force(user)) * 0.5 SECONDS + if(user.skill_check(SKILL_BOTANY, SKILL_ADEPT)) + chop_time *= 0.5 + if(do_after(user, chop_time, vine, TRUE)) + user.visible_message(SPAN_NOTICE("[user] chops down \the [vine].")) + playsound(get_turf(vine), holding.hitsound, 100, 1) + vine.die_off() diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm index fd9e81fe127d..fab8effc38a0 100644 --- a/code/modules/hydroponics/spreading/spreading_growth.dm +++ b/code/modules/hydroponics/spreading/spreading_growth.dm @@ -1,34 +1,26 @@ #define NEIGHBOR_REFRESH_TIME 100 /obj/effect/vine/proc/get_cardinal_neighbors() - var/list/cardinal_neighbors = list() - for(var/check_dir in GLOB.cardinal) - var/turf/simulated/T = get_step(get_turf(src), check_dir) - if(istype(T)) - cardinal_neighbors |= T - return cardinal_neighbors + . = list() + for(var/check_dir in global.cardinal) + var/turf/T = get_step(get_turf(src), check_dir) + if(istype(T) && T.simulated) + . |= T /obj/effect/vine/proc/get_zlevel_neighbors() - var/list/zlevel_neighbors = list() - + . = list() var/turf/start = loc - var/turf/up = GetAbove(loc) - var/turf/down = GetBelow(loc) - - if(start && start.CanZPass(src, DOWN)) - zlevel_neighbors += down - if(up && up.CanZPass(src, UP)) - zlevel_neighbors += up - - return zlevel_neighbors + if(isturf(start)) + if(start.CanZPass(src, DOWN)) + . += GetBelow(loc) + if(start.CanZPass(src, UP)) + . += GetAbove(loc) /obj/effect/vine/proc/get_neighbors() - var/list/neighbors = list() - - for(var/turf/simulated/floor in get_cardinal_neighbors()) + . = list() + for(var/turf/floor in get_cardinal_neighbors()) if(get_dist(parent, floor) > spread_distance) continue - var/blocked = 0 for(var/obj/effect/vine/other in floor.contents) if(other.seed == src.seed) @@ -36,46 +28,41 @@ break if(blocked) continue - if(floor.density) - if(!isnull(seed.chems[/decl/material/liquid/acid/polyacid])) + if(seed.get_chemical_amount(/decl/material/liquid/acid/polyacid)) spawn(rand(5,25)) floor.explosion_act(3) continue - if(!Adjacent(floor) || !floor.Enter(src)) continue - - neighbors |= floor - - neighbors |= get_zlevel_neighbors() - return neighbors + . |= floor + . |= get_zlevel_neighbors() /obj/effect/vine/Process() - var/turf/simulated/T = get_turf(src) - if(!istype(T)) + var/turf/T = get_turf(src) + if(!istype(T) || !T.simulated) return //Take damage from bad environment if any - adjust_health(-seed.handle_environment(T,T.return_air(),null,1)) - if(health <= 0) + adjust_health(-seed.handle_plant_environment(T,T.return_air(),null,1)) + if(current_health <= 0) return - + //Vine fight! for(var/obj/effect/vine/other in T) if(other.seed != seed) other.vine_overrun(seed, src) //Growing up - if(health < max_health) + if(current_health < get_max_health()) adjust_health(1) - if(growth_threshold && !(health % growth_threshold)) + if(growth_threshold && !(current_health % growth_threshold)) update_icon() if(is_mature()) //Find a victim if(!buckled_mob) var/list/mob/living/targets = targets_in_range() - if(targets && targets.len && prob(round(seed.get_trait(TRAIT_POTENCY)/4))) + if(LAZYLEN(targets) && prob(round(seed.get_trait(TRAIT_POTENCY)/4))) entangle(pick(targets)) //Handle the victim @@ -89,7 +76,7 @@ var/list/neighbors = get_neighbors() if(neighbors.len) spread_to(pick(neighbors)) - + //Try to settle down if(can_spawn_plant()) plant = new(T,seed) @@ -106,15 +93,15 @@ STOP_PROCESSING(SSvines, src) /obj/effect/vine/proc/can_spawn_plant() - var/turf/simulated/T = get_turf(src) - return parent == src && health == max_health && !plant && istype(T) && !T.CanZPass(src, DOWN) + var/turf/T = get_turf(src) + return parent == src && current_health == get_max_health() && !plant && istype(T) && T.simulated && !T.CanZPass(src, DOWN) /obj/effect/vine/proc/should_sleep() if(buckled_mob) //got a victim to fondle return FALSE if(length(get_neighbors())) //got places to spread to return FALSE - if(health < max_health) //got some growth to do + if(current_health < get_max_health()) //got some growth to do return FALSE if(targets_in_range()) //got someone to grab return FALSE @@ -132,25 +119,29 @@ child.set_dir(child.calc_dir()) child.update_icon() // Some plants eat through plating. - if(islist(seed.chems) && !isnull(seed.chems[/decl/material/liquid/acid/polyacid])) + if(seed.get_chemical_amount(/decl/material/liquid/acid/polyacid)) target_turf.explosion_act(prob(80) ? 3 : 2) else qdel(child) /obj/effect/vine/proc/wake_neighbors() // This turf is clear now, let our buddies know. - for(var/turf/simulated/check_turf in (get_cardinal_neighbors() | get_zlevel_neighbors())) - if(!istype(check_turf)) + for(var/turf/check_turf in (get_cardinal_neighbors() | get_zlevel_neighbors())) + if(!istype(check_turf) || !check_turf.simulated) continue for(var/obj/effect/vine/neighbor in check_turf.contents) + if(QDELETED(neighbor)) + continue START_PROCESSING(SSvines, neighbor) /obj/effect/vine/proc/targets_in_range() var/list/mob/targets = list() - for(var/turf/simulated/check_turf in (get_cardinal_neighbors() | get_zlevel_neighbors() | list(loc))) - if(!istype(check_turf)) + for(var/turf/check_turf in (get_cardinal_neighbors() | get_zlevel_neighbors() | list(loc))) + if(!istype(check_turf) || !check_turf.simulated) continue for(var/mob/living/M in check_turf.contents) + if(QDELETED(M)) + continue if(prob(5) || !M.skill_check(SKILL_BOTANY, SKILL_PROF)) targets |= M if(targets.len) diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm index fb41c2cd7ffc..ad0400849daa 100644 --- a/code/modules/hydroponics/spreading/spreading_response.dm +++ b/code/modules/hydroponics/spreading/spreading_response.dm @@ -1,5 +1,6 @@ /obj/effect/vine/HasProximity(var/atom/movable/AM) - if(!is_mature() || seed.get_trait(TRAIT_SPREAD) != 2) + . = ..() + if(!. || !is_mature() || seed.get_trait(TRAIT_SPREAD) != 2) return var/mob/living/M = AM @@ -10,24 +11,28 @@ //wait a tick for the Entered() proc that called HasProximity() to finish (and thus the moving animation), //so we don't appear to teleport from two tiles away when moving into a turf adjacent to vines. spawn(1) - if(prob(seed.get_trait(((TRAIT_POTENCY)/2)*3))) + if(prob((seed.get_trait(TRAIT_POTENCY) / 2) * 3)) entangle(M) /obj/effect/vine/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) + return ..() manual_unbuckle(user) + return TRUE -/obj/effect/vine/Crossed(atom/movable/O) - if(isliving(O)) - trodden_on(O) +/obj/effect/vine/Crossed(atom/movable/AM) + if(!isliving(AM)) + return + trodden_on(AM) /obj/effect/vine/proc/trodden_on(var/mob/living/victim) wake_neighbors() if(!is_mature()) return - if(prob(seed.get_trait(((TRAIT_POTENCY)/2)*3))) + if(prob((seed.get_trait(TRAIT_POTENCY) / 2) * 3)) entangle(victim) - var/mob/living/carbon/human/H = victim - if(istype(H) && H.shoes) + var/mob/living/human/H = victim + if(istype(H) && H.get_equipped_item(slot_shoes_str)) return seed.do_thorns(victim,src) seed.do_sting(victim,src,pick(BP_R_FOOT,BP_L_FOOT,BP_R_LEG,BP_L_LEG)) @@ -69,17 +74,18 @@ return if(ishuman(victim)) - var/mob/living/carbon/human/H = victim + var/mob/living/human/H = victim if(H.species.species_flags & SPECIES_FLAG_NO_TANGLE) return - if(victim.loc != loc && istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.item_flags & ITEM_FLAG_NOSLIP) || H.species.check_no_slip(H)) + + if(victim.loc != loc && !victim.can_slip()) visible_message("Tendrils lash to drag \the [victim] but \the [src] can't pull them across the ground!") return - + victim.visible_message("Tendrils lash out from \the [src] and drag \the [victim] in!", "Tendrils lash out from \the [src] and drag you in!") victim.forceMove(loc) if(buckle_mob(victim)) - victim.set_dir(pick(GLOB.cardinal)) + victim.set_dir(pick(global.cardinal)) to_chat(victim, "The tendrils [pick("wind", "tangle", "tighten", "coil", "knot", "snag", "twist", "constrict", "squeeze", "clench", "tense")] around you!") /obj/effect/vine/buckle_mob() diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 15932c62a599..960ad52b5ed4 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -1,15 +1,16 @@ /obj/machinery/portable_atmospherics/hydroponics name = "hydroponics tray" - desc = "A mechanical basin designed to nurture plants. It has various useful sensors." + desc = "A mechanical basin designed to nurture plants and other aquatic life. It has various useful sensors." icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' icon_state = "hydrotray3" - density = 1 - anchored = 1 - atom_flags = ATOM_FLAG_OPEN_CONTAINER - volume = 100 + density = TRUE + anchored = TRUE + gas_volume = 100 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_CLIMBABLE | ATOM_FLAG_NO_CHEM_CHANGE + chem_volume = 200 var/mechanical = 1 // Set to 0 to stop it from drawing the alert lights. var/base_name = "tray" @@ -34,20 +35,22 @@ var/tray_light = 5 // Supplied lighting. // Mechanical concerns. - var/health = 0 // Plant health. + var/plant_health = 0 // Plant health. var/lastproduce = 0 // Last time tray was harvested - var/lastcycle = 0 // Cycle timing/tracking var. - var/cycledelay = 150 // Delay per cycle. var/closed_system // If set, the tray will attempt to take atmos from a pipe. var/force_update // Set this to bypass the cycle time check. - var/obj/temp_chem_holder // Something to hold reagents during process_reagents() + /// Something to hold reagents during process_reagents() + var/obj/effect/chem_holder/temp_chem_holder + + // Counter used by bees. + var/pollen = 0 // Seed details/line data. var/datum/seed/seed = null // The currently planted seed // Reagent information for process(), consider moving this to a controller along // with cycle information under 'mechanical concerns' at some point. - var/global/list/toxic_reagents = list( + var/static/list/toxic_reagents = list( /decl/material/liquid/antitoxins = -2, /decl/material/liquid/fuel/hydrazine = 2.5, /decl/material/liquid/acetone = 1, @@ -57,18 +60,19 @@ /decl/material/liquid/weedkiller = 3, /decl/material/solid/metal/radium = 2 ) - var/global/list/nutrient_reagents = list( + var/static/list/nutrient_reagents = list( /decl/material/liquid/drink/milk = 0.1, - /decl/material/liquid/ethanol/beer = 0.25, + /decl/material/liquid/alcohol/beer = 0.25, /decl/material/solid/phosphorus = 0.1, /decl/material/liquid/nutriment/sugar = 0.1, /decl/material/liquid/drink/sodawater = 0.1, /decl/material/gas/ammonia = 1, /decl/material/liquid/nutriment = 1, /decl/material/liquid/adminordrazine = 1, - /decl/material/liquid/fertilizer = 1 + /decl/material/liquid/fertilizer = 1, + /decl/material/liquid/fertilizer/compost = 1 ) - var/global/list/weedkiller_reagents = list( + var/static/list/weedkiller_reagents = list( /decl/material/liquid/fuel/hydrazine = -4, /decl/material/solid/phosphorus = -2, /decl/material/liquid/nutriment/sugar = 2, @@ -78,17 +82,17 @@ /decl/material/liquid/weedkiller = -8, /decl/material/liquid/adminordrazine = -5 ) - var/global/list/pestkiller_reagents = list( + var/static/list/pestkiller_reagents = list( /decl/material/liquid/nutriment/sugar = 2, /decl/material/liquid/bromide = -2, /decl/material/gas/methyl_bromide = -4, /decl/material/liquid/adminordrazine = -5 ) - var/global/list/water_reagents = list( + var/static/list/water_reagents = list( /decl/material/liquid/water = 1, /decl/material/liquid/adminordrazine = 1, /decl/material/liquid/drink/milk = 0.9, - /decl/material/liquid/ethanol/beer = 0.7, + /decl/material/liquid/alcohol/beer = 0.7, /decl/material/liquid/fuel/hydrazine = -2, /decl/material/solid/phosphorus = -0.5, /decl/material/liquid/water = 1, @@ -96,8 +100,8 @@ ) // Beneficial reagents also have values for modifying yield_mod and mut_mod (in that order). - var/global/list/beneficial_reagents = list( - /decl/material/liquid/ethanol/beer = list( -0.05, 0, 0 ), + var/static/list/beneficial_reagents = list( + /decl/material/liquid/alcohol/beer = list( -0.05, 0, 0 ), /decl/material/liquid/fuel/hydrazine = list( -2, 0, 0 ), /decl/material/solid/phosphorus = list( -0.75, 0, 0 ), /decl/material/liquid/drink/sodawater = list( 0.1, 0, 0 ), @@ -109,24 +113,46 @@ /decl/material/liquid/nutriment = list( 0.5, 0.1, 0 ), /decl/material/solid/metal/radium = list( -1.5, 0, 0.2), /decl/material/liquid/adminordrazine = list( 1, 1, 1 ), - /decl/material/liquid/fertilizer = list( 0, 0.2, 0.2) + /decl/material/liquid/fertilizer = list( 0, 0.2, 0.2), + /decl/material/liquid/fertilizer/compost = list( 0, 0.2, 0.2) ) // Mutagen list specifies minimum value for the mutation to take place, rather // than a bound as the lists above specify. - var/global/list/mutagenic_reagents = list( + var/static/list/mutagenic_reagents = list( /decl/material/solid/metal/radium = 8, /decl/material/liquid/mutagenics = 15 ) -/obj/machinery/portable_atmospherics/hydroponics/AltClick() - if(mechanical && !usr.incapacitated() && Adjacent(usr)) - close_lid(usr) - return 1 - return ..() +/obj/machinery/portable_atmospherics/hydroponics/proc/set_seed(new_seed, reset_values) + + if(seed == new_seed) + return + + seed = new_seed + + if(seed?.scannable_result) + set_extension(src, /datum/extension/scannable, seed.scannable_result) + else if(has_extension(src, /datum/extension/scannable)) + remove_extension(src, /datum/extension/scannable) + + dead = 0 + age = 0 + sampled = 0 + harvest = 0 + plant_health = seed ? seed.get_trait(TRAIT_ENDURANCE) : 0 + + if(reset_values) + yield_mod = 0 + mutation_mod = 0 + lastproduce = 0 + weedlevel = 0 + + check_plant_health() + update_icon() /obj/machinery/portable_atmospherics/hydroponics/attack_ghost(var/mob/observer/ghost/user) - if(!(harvest && seed && seed.has_mob_product)) + if(!(harvest && seed && ispath(seed.product_type, /mob))) return if(!user.can_admin_interact()) @@ -140,10 +166,7 @@ if(!mechanical) construct_state = /decl/machine_construction/noninteractive . = ..() - temp_chem_holder = new() - temp_chem_holder.create_reagents(10) - temp_chem_holder.atom_flags |= ATOM_FLAG_OPEN_CONTAINER - create_reagents(200) + temp_chem_holder = new(null, 10) if(mechanical) connect() update_icon() @@ -170,7 +193,7 @@ if(istype(Proj, /obj/item/projectile/energy/floramut/gene)) var/obj/item/projectile/energy/floramut/gene/G = Proj if(seed) - seed = seed.diverge_mutate_gene(G.gene, get_turf(loc)) //get_turf just in case it's not in a turf. + set_seed(seed.diverge_mutate_gene(G.gene, src), reset_values = FALSE) else mutate(1) return @@ -188,8 +211,8 @@ else return !density -/obj/machinery/portable_atmospherics/hydroponics/proc/check_health(var/icon_update = 1) - if(seed && !dead && health <= 0) +/obj/machinery/portable_atmospherics/hydroponics/proc/check_plant_health(var/icon_update = 1) + if(seed && !dead && plant_health <= 0) die() check_level_sanity() if(icon_update) @@ -199,7 +222,7 @@ dead = 1 mutation_level = 0 harvest = 0 - weedlevel += 1 * HYDRO_SPEED_MULTIPLIER + weedlevel += 1 pestlevel = 0 //Process reagents being input into the tray. @@ -207,42 +230,42 @@ if(!reagents) return - if(reagents.total_volume <= 0) + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) return - reagents.trans_to_obj(temp_chem_holder, min(reagents.total_volume,rand(1,3))) + reagents.trans_to_obj(temp_chem_holder, min(REAGENT_TOTAL_VOLUME(reagents),rand(1,3))) - for(var/R in temp_chem_holder.reagents.reagent_volumes) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(temp_chem_holder.reagents)) - var/reagent_total = REAGENT_VOLUME(temp_chem_holder.reagents, R) + var/reagent_total = REAGENT_VOLUME(temp_chem_holder.reagents, reagent) if(seed && !dead) //Handle some general level adjustments. - if(toxic_reagents[R]) - toxins += toxic_reagents[R] * reagent_total - if(weedkiller_reagents[R]) - weedlevel += weedkiller_reagents[R] * reagent_total - if(pestkiller_reagents[R]) - pestlevel += pestkiller_reagents[R] * reagent_total + if(toxic_reagents[reagent.type]) + toxins += toxic_reagents[reagent.type] * reagent_total + if(weedkiller_reagents[reagent.type]) + weedlevel += weedkiller_reagents[reagent.type] * reagent_total + if(pestkiller_reagents[reagent.type]) + pestlevel += pestkiller_reagents[reagent.type] * reagent_total // Beneficial reagents have a few impacts along with health buffs. - if(beneficial_reagents[R]) - health += beneficial_reagents[R][1] * reagent_total - yield_mod += beneficial_reagents[R][2] * reagent_total - mutation_mod += beneficial_reagents[R][3] * reagent_total + if(beneficial_reagents[reagent.type]) + plant_health += beneficial_reagents[reagent.type][1] * reagent_total + yield_mod += beneficial_reagents[reagent.type][2] * reagent_total + mutation_mod += beneficial_reagents[reagent.type][3] * reagent_total // Mutagen is distinct from the previous types and mostly has a chance of proccing a mutation. - if(mutagenic_reagents[R]) - mutation_level += reagent_total*mutagenic_reagents[R]+mutation_mod + if(mutagenic_reagents[reagent.type]) + mutation_level += reagent_total*mutagenic_reagents[reagent.type]+mutation_mod // Handle nutrient refilling. - if(nutrient_reagents[R]) - nutrilevel += nutrient_reagents[R] * reagent_total + if(nutrient_reagents[reagent.type]) + nutrilevel += nutrient_reagents[reagent.type] * reagent_total // Handle water and water refilling. var/water_added = 0 - if(water_reagents[R]) - var/water_input = water_reagents[R] * reagent_total + if(water_reagents[reagent.type]) + var/water_input = water_reagents[reagent.type] * reagent_total water_added += water_input waterlevel += water_input @@ -251,10 +274,10 @@ toxins -= round(water_added/4) temp_chem_holder.reagents.clear_reagents() - check_health() + check_plant_health() //Harvests the product of a plant. -/obj/machinery/portable_atmospherics/hydroponics/proc/harvest(var/mob/user) +/obj/machinery/portable_atmospherics/hydroponics/proc/harvest(mob/user) //Harvest the product of the plant, if(!seed || !harvest) @@ -268,55 +291,43 @@ . = seed.harvest(user,yield_mod) else . = seed.harvest(get_turf(src),yield_mod) + // Reset values. harvest = 0 lastproduce = age if(!seed.get_trait(TRAIT_HARVEST_REPEAT)) yield_mod = 0 - seed = null - dead = 0 - age = 0 - sampled = 0 - mutation_mod = 0 + set_seed(null) - check_health() + check_plant_health() //Clears out a dead plant. /obj/machinery/portable_atmospherics/hydroponics/proc/remove_dead(var/mob/user, var/silent) - if(!dead) + if(!dead || !seed) return if(closed_system) - if(user) - to_chat(user, "You can't remove the dead plant while the lid is shut.") + if(!silent) + to_chat(user, SPAN_WARNING("You can't remove the dead [seed.display_name] while the lid is shut.")) return FALSE - seed = null - dead = 0 - sampled = 0 - age = 0 - yield_mod = 0 - mutation_mod = 0 + if(!silent) + to_chat(user, SPAN_NOTICE("You remove the dead [seed.display_name].")) + + set_seed(null) - if(!silent && user) - to_chat(user, "You remove the dead plant.") - lastproduce = 0 - check_health() return TRUE // If a weed growth is sufficient, this proc is called. /obj/machinery/portable_atmospherics/hydroponics/proc/weed_invasion() - //Remove the seed if something is already planted. - if(seed) seed = null - seed = SSplants.seeds[pick(list("reishi", "nettles", "amanita", "mushrooms", "plumphelmet", "corkwood", "harebells", "weeds"))] - if(!seed) return //Weed does not exist, someone fucked up. + set_seed(SSplants.seeds[pick(list("reishi", "nettles", "amanita", "mushrooms", "plumphelmet", "towercap", "harebells", "weeds"))], reset_values = FALSE) + + if(!seed) + return //Weed does not exist, someone fucked up. - dead = 0 age = 0 - health = seed.get_trait(TRAIT_ENDURANCE) - lastcycle = world.time harvest = 0 weedlevel = 0 pestlevel = 0 @@ -341,8 +352,8 @@ // If it's not in the global list, then no products of the line have been // harvested yet and it's safe to assume it's restricted to this tray. if(!isnull(SSplants.seeds[seed.name])) - seed = seed.diverge() - seed.mutate(severity,get_turf(src)) + set_seed(seed.diverge(), reset_values = FALSE) + seed.mutate(severity, src) return @@ -353,7 +364,7 @@ if(usr.incapacitated()) return - if(ishuman(usr) || istype(usr, /mob/living/silicon/robot)) + if(ishuman(usr) || isrobot(usr)) var/new_light = input("Specify a light level.") as null|anything in list(0,1,2,3,4,5,6,7,8,9,10) if(new_light) tray_light = new_light @@ -363,9 +374,9 @@ /obj/machinery/portable_atmospherics/hydroponics/proc/check_level_sanity() //Make sure various values are sane. if(seed) - health = max(0,min(seed.get_trait(TRAIT_ENDURANCE),health)) + plant_health = max(0, min(seed.get_trait(TRAIT_ENDURANCE), plant_health)) else - health = 0 + plant_health = 0 dead = 0 mutation_level = max(0,min(mutation_level,100)) @@ -377,120 +388,104 @@ /obj/machinery/portable_atmospherics/hydroponics/proc/mutate_species() - var/previous_plant = seed.display_name - var/newseed = seed.get_mutant_variant() - if(newseed in SSplants.seeds) - seed = SSplants.seeds[newseed] - else + var/newseed = seed?.get_mutant_variant() + if(!newseed || !(newseed in SSplants.seeds)) return - dead = 0 + var/previous_plant = seed.display_name + set_seed(SSplants.seeds[newseed]) mutate(1) - age = 0 - health = seed.get_trait(TRAIT_ENDURANCE) - lastcycle = world.time - harvest = 0 - weedlevel = 0 + plant_health = seed.get_trait(TRAIT_ENDURANCE) // re-run in case mutation changed our endurance update_icon() visible_message("The [previous_plant] has suddenly mutated into [seed.display_name]!") return -/obj/machinery/portable_atmospherics/hydroponics/attackby(var/obj/item/O, var/mob/user) - - if (ATOM_IS_OPEN_CONTAINER(O)) - return 0 - - if(O.edge && O.w_class < ITEM_SIZE_NORMAL && user.a_intent != I_HURT) - - if(!seed) - to_chat(user, SPAN_WARNING("There is nothing to take a sample from in \the [src].")) - return +/obj/machinery/portable_atmospherics/hydroponics/attackby(var/obj/item/used_item, var/mob/user) - if(sampled) - to_chat(user, SPAN_WARNING("There's no bits that can be used for a sampling left.")) - return + if(istype(used_item, /obj/item/food/grown)) + var/obj/item/food/grown/bulb = used_item + if(bulb.seed?.grown_is_seed) + plant_seed(user, bulb) + return TRUE - if(dead) - to_chat(user, SPAN_WARNING("The plant is dead.")) - return + if(IS_HOE(used_item)) - var/needed_skill = seed.mysterious ? SKILL_ADEPT : SKILL_BASIC - if(prob(user.skill_fail_chance(SKILL_BOTANY, 90, needed_skill))) - to_chat(user, SPAN_WARNING("You failed to get a usable sample.")) + if(weedlevel > 0) + if(!used_item.do_tool_interaction(TOOL_HOE, user, src, 2 SECONDS, start_message = "uprooting the weeds in", success_message = "weeding") || weedlevel <= 0 || QDELETED(src)) + return TRUE + weedlevel = 0 + update_icon() + if(seed) + var/needed_skill = seed.mysterious ? SKILL_ADEPT : SKILL_BASIC + if(!user.skill_check(SKILL_BOTANY, needed_skill)) + plant_health -= rand(40,60) + check_plant_health() else - // Create a sample. - seed.harvest(user,yield_mod,1) - health -= (rand(3,5)*10) - - if(prob(30)) - sampled = 1 - - // Bookkeeping. - check_health() - force_update = 1 - Process() + to_chat(user, SPAN_WARNING("This plot is completely devoid of weeds. It doesn't need uprooting.")) + return TRUE - return + if(IS_SHOVEL(used_item)) + if(seed) + var/removing_seed = seed + if(used_item.do_tool_interaction(TOOL_SHOVEL, user, src, 3 SECONDS, start_message = "removing \the [seed.display_name] from", success_message = "removing \the [seed.display_name] from") && seed == removing_seed) + set_seed(null) + else + to_chat(user, SPAN_WARNING("There is no plant in \the [src] to remove.")) + return TRUE - else if(istype(O, /obj/item/chems/syringe)) + if(!user.check_intent(I_FLAG_HARM)) + var/decl/interaction_handler/sample_interaction = GET_DECL(/decl/interaction_handler/hydroponics/sample) + if(sample_interaction.is_possible(src, user, used_item)) + sample_interaction.invoked(src, user, used_item) + return TRUE - var/obj/item/chems/syringe/S = O + // Handled in afterattack/ + if (ATOM_IS_OPEN_CONTAINER(used_item)) + return FALSE + if(istype(used_item, /obj/item/chems/syringe)) + var/obj/item/chems/syringe/S = used_item if (S.mode == 1) if(seed) return ..() else - to_chat(user, "There's no plant to inject.") - return 1 + to_chat(user, SPAN_WARNING("There's no plant to inject.")) else if(seed) //Leaving this in in case we want to extract from plants later. - to_chat(user, "You can't get any extract out of this plant.") + to_chat(user, SPAN_WARNING("You can't get any extract out of this plant.")) else - to_chat(user, "There's nothing to draw something from.") - return 1 - - else if (istype(O, /obj/item/seeds)) - - plant_seed(user, O) - - else if (istype(O, /obj/item/minihoe)) // The minihoe - - if(weedlevel > 0) - user.visible_message("[user] starts uprooting the weeds.", "You remove the weeds from the [src].") - weedlevel = 0 - if(seed) - var/needed_skill = seed.mysterious ? SKILL_ADEPT : SKILL_BASIC - if(!user.skill_check(SKILL_BOTANY, needed_skill)) - health -= rand(40,60) - check_health(1) - else - to_chat(user, "This plot is completely devoid of weeds. It doesn't need uprooting.") - - else if (istype(O, /obj/item/storage/plants)) + to_chat(user, SPAN_WARNING("There's nothing to draw something from.")) + return TRUE - attack_hand(user) + if(istype(used_item, /obj/item/seeds)) + plant_seed(user, used_item) + return TRUE - var/obj/item/storage/plants/S = O - for (var/obj/item/chems/food/snacks/grown/G in locate(user.x,user.y,user.z)) - if(!S.can_be_inserted(G, user)) - return - S.handle_item_insertion(G, 1) + if (istype(used_item, /obj/item/plant_satchel)) + physical_attack_hand(user) // Harvests and clears out dead plants. + if(used_item.storage) + for (var/obj/item/food/grown/G in get_turf(user)) + if(used_item.storage.can_be_inserted(G, user)) + used_item.storage.handle_item_insertion(user, G, TRUE) + return TRUE - else if ( istype(O, /obj/item/plantspray) ) + if ( istype(used_item, /obj/item/plantspray) ) - var/obj/item/plantspray/spray = O + var/obj/item/plantspray/spray = used_item toxins += spray.toxicity pestlevel -= spray.pest_kill_str weedlevel -= spray.weed_kill_str - to_chat(user, "You spray [src] with [O].") + update_icon() + to_chat(user, "You spray [src] with [used_item].") playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6) - qdel(O) - check_health() + qdel(used_item) + check_plant_health() + return TRUE - else if(mechanical && isWrench(O)) + if(mechanical && IS_WRENCH(used_item)) //If there's a connector here, the portable_atmospherics setup can handle it. if(locate(/obj/machinery/atmospherics/portables_connector/) in loc) @@ -499,45 +494,75 @@ playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) anchored = !anchored to_chat(user, "You [anchored ? "wrench" : "unwrench"] \the [src].") + return TRUE - else if(O.force && seed) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [O]!") - playsound(get_turf(src), O.hitsound, 100, 1) - if(!dead) - health -= O.force - check_health() - else if(mechanical) - return component_attackby(O, user) + if(user.check_intent(I_FLAG_HARM) && seed) + var/force = used_item.expend_attack_force(user) + if(force) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [used_item]!") + playsound(get_turf(src), used_item.hitsound, 100, 1) + if(!dead) + plant_health -= force + check_plant_health() + return TRUE + if(mechanical) + return component_attackby(used_item, user) + + return ..() + +// S can also be an instance of /obj/item/food/grown /obj/machinery/portable_atmospherics/hydroponics/proc/plant_seed(var/mob/user, var/obj/item/seeds/S) if(seed) - to_chat(user, "\The [src] already has seeds in it!") + to_chat(user, SPAN_WARNING("\The [src] already has something growing in it!")) return - if(!S.seed) - to_chat(user, "The packet seems to be empty. You throw it away.") + var/plant_noun + var/datum/seed/planting_seed = S.seed + if(istype(S)) + planting_seed = S.seed + plant_noun = "[planting_seed?.product_name] [planting_seed.seed_noun]" + else if(istype(S, /obj/item/food/grown)) + var/obj/item/food/grown/fruit = S + planting_seed = fruit.seed + plant_noun = "[planting_seed?.product_name]" + else if(istype(S, /obj/item/food/processed_grown)) + var/obj/item/food/processed_grown/fruit = S + planting_seed = fruit.seed + plant_noun = "[planting_seed?.product_name]" + else + CRASH("Invalid or null value passed to plant_seed(): [S || "NULL"]") + + if(!istype(planting_seed)) + if(istype(S)) + to_chat(user, SPAN_WARNING("\The [S] seems to be empty. You throw it away.")) + else + to_chat(user, SPAN_WARNING("\The [S] seems to be rotten. You throw it away.")) qdel(S) return - to_chat(user, "You plant the [S.seed.seed_name] [S.seed.seed_noun].") + if(planting_seed.hydrotray_only && !mechanical) + to_chat(user, SPAN_WARNING("\The [plant_noun] can only be planted in a hydroponics tray.")) + return + + to_chat(user, SPAN_NOTICE("You plant the [plant_noun].")) lastproduce = 0 - seed = S.seed //Grab the seed datum. - dead = 0 + set_seed(planting_seed) //Grab the seed datum. age = 1 //Snowflakey, maybe move this to the seed datum - health = (istype(S, /obj/item/seeds/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) - lastcycle = world.time + // re-running to adjust based on planting method + plant_health = (istype(S, /obj/item/seeds/extracted/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) var/needed_skill = seed.mysterious ? SKILL_ADEPT : SKILL_BASIC if(prob(user.skill_fail_chance(SKILL_BOTANY, 40, needed_skill))) dead = 1 - health = 0 + plant_health = 0 qdel(S) - check_health() + check_plant_health() /obj/machinery/portable_atmospherics/hydroponics/attack_robot(mob/user) return FALSE // no hands @@ -549,31 +574,35 @@ if(dead) remove_dead(user) return TRUE + return FALSE -/obj/machinery/portable_atmospherics/hydroponics/examine(mob/user) - . = ..(user) +/obj/machinery/portable_atmospherics/hydroponics/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() if(!seed) - to_chat(user, "\The [src] is empty.") + . += "\The [src] is empty." return - to_chat(user, "\An [seed.display_name] plant is growing here.") + . += SPAN_NOTICE("\A [seed.display_name] is growing here.") if(user.skill_check(SKILL_BOTANY, SKILL_BASIC)) if(weedlevel >= 5) - to_chat(user, "\The [src] is infested with weeds!") + . += "\The [src] is infested with weeds!" if(pestlevel >= 5) - to_chat(user, "\The [src] is infested with tiny worms!") + . += "\The [src] is infested with tiny worms!" if(dead) - to_chat(user, "The [seed.display_name] plant is dead.") - else if(health <= (seed.get_trait(TRAIT_ENDURANCE)/ 2)) - to_chat(user, "The [seed.display_name] plant looks unhealthy.") + . += "The [seed.display_name] is dead." + else if(plant_health <= (seed.get_trait(TRAIT_ENDURANCE)/ 2)) + . += "The [seed.display_name] looks unhealthy." + + if(!Adjacent(user)) + return - if(mechanical && Adjacent(user)) + if(mechanical) var/turf/T = loc var/datum/gas_mixture/environment - if(closed_system && (connected_port || holding)) + if(closed_system && (get_port() || holding)) environment = air_contents if(!environment) @@ -584,15 +613,20 @@ return var/light_string - if(closed_system && mechanical) + if(closed_system) light_string = "that the internal lights are set to [tray_light] lumens" else var/light_available = T.get_lumcount() * 5 light_string = "a light level of [light_available] lumens" - to_chat(user, "Water: [round(waterlevel,0.1)]/100") - to_chat(user, "Nutrient: [round(nutrilevel,0.1)]/10") - to_chat(user, "The tray's sensor suite is reporting [light_string] and a temperature of [environment.temperature]K.") + . += "Water: [round(waterlevel,0.1)]/100" + . += "Nutrient: [round(nutrilevel,0.1)]/10" + . += "The tray's sensor suite is reporting [light_string] and a temperature of [environment.temperature]K." + else + if(waterlevel < 20) + . += SPAN_WARNING("The [seed.display_name] is dry.") + if(nutrilevel < 2) + . += SPAN_WARNING("The [seed.display_name]'s growth is stunted due to a lack of nutrients.") /obj/machinery/portable_atmospherics/hydroponics/verb/close_lid_verb() set name = "Toggle Tray Lid" @@ -601,7 +635,7 @@ if(usr.incapacitated()) return - if(ishuman(usr) || istype(usr, /mob/living/silicon/robot)) + if(ishuman(usr) || isrobot(usr)) close_lid(usr) return @@ -614,13 +648,11 @@ /obj/machinery/portable_atmospherics/hydroponics/proc/plant() var/obj/item/seeds/S = locate() in get_turf(src) if(S.seed) - seed = S.seed - lastproduce = 0 - dead = 0 + set_seed(S.seed) age = 1 - health = (istype(S, /obj/item/seeds/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) - lastcycle = world.time - check_health() + // re-running to adjust for planting method + plant_health = (istype(S, /obj/item/seeds/extracted/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) + check_plant_health() qdel(S) /obj/machinery/portable_atmospherics/hydroponics/do_simple_ranged_interaction(var/mob/user) @@ -630,3 +662,58 @@ harvest() return TRUE +/obj/machinery/portable_atmospherics/hydroponics/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/hydroponics/close_lid) + LAZYADD(., /decl/interaction_handler/hydroponics/sample) + +/decl/interaction_handler/hydroponics + abstract_type = /decl/interaction_handler/hydroponics + expected_target_type = /obj/machinery/portable_atmospherics/hydroponics + +/decl/interaction_handler/hydroponics/close_lid + name = "Open/Close Lid" + examine_desc = "open or close the lid" + +/decl/interaction_handler/hydroponics/close_lid/is_possible(atom/target, mob/user, obj/item/prop) + var/obj/machinery/portable_atmospherics/hydroponics/tray = target + return ..() && tray.mechanical + +/decl/interaction_handler/hydroponics/close_lid/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/portable_atmospherics/hydroponics/tray = target + tray.close_lid(user) + +/decl/interaction_handler/hydroponics/sample + name = "Sample Plant" + examine_desc = "take a sample" + +/decl/interaction_handler/hydroponics/sample/is_possible(atom/target, mob/user, obj/item/prop) + return ..() && istype(prop) && prop.has_edge() && prop.w_class < ITEM_SIZE_NORMAL + +/decl/interaction_handler/hydroponics/sample/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/portable_atmospherics/hydroponics/tray = target + if(!tray.seed) + to_chat(user, SPAN_WARNING("There is nothing to take a sample from in \the [src].")) + return + if(tray.sampled) + to_chat(user, SPAN_WARNING("There's no bits that can be used for a sampling left.")) + return + if(tray.dead) + to_chat(user, SPAN_WARNING("The plant is dead.")) + return + var/needed_skill = tray.seed.mysterious ? SKILL_ADEPT : SKILL_BASIC + if(prob(user.skill_fail_chance(SKILL_BOTANY, 90, needed_skill))) + to_chat(user, SPAN_WARNING("You failed to get a usable sample.")) + else + // Create a sample. + tray.seed.harvest(user, tray.yield_mod, 1) + tray.plant_health -= (rand(3,5)*10) + + if(prob(30)) + tray.sampled = 1 + + // Bookkeeping. + tray.check_plant_health() + tray.force_update = 1 + tray.Process() + diff --git a/code/modules/hydroponics/trays/tray_process.dm b/code/modules/hydroponics/trays/tray_process.dm index 7f1648be88e9..d692dc841a51 100644 --- a/code/modules/hydroponics/trays/tray_process.dm +++ b/code/modules/hydroponics/trays/tray_process.dm @@ -1,28 +1,36 @@ -/obj/machinery/portable_atmospherics/hydroponics/Process() - - // Handle nearby smoke if any. - for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) - if(smoke.reagents.total_volume) - smoke.reagents.trans_to_obj(src, 5, copy = 1) +/obj/machinery/portable_atmospherics/hydroponics/proc/get_growth_rate() + return 1 + +/obj/machinery/portable_atmospherics/hydroponics/process_plants() + + var/growth_rate = get_growth_rate() + var/turf/my_turf = get_turf(src) + if(istype(my_turf) && !closed_system) + var/space_left = reagents ? (REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents)) : 0 + if(space_left > 0 && REAGENT_TOTAL_VOLUME(reagents) < 10) + // Handle nearby smoke if any. + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) + if(REAGENT_TOTAL_VOLUME(smoke.reagents)) + smoke.reagents.trans_to_obj(src, 5, copy = 1) + // Handle environmental effects like weather and flooding. + if(REAGENT_TOTAL_VOLUME(my_turf.reagents)) + my_turf.reagents.trans_to_obj(src, min(space_left, min(REAGENT_TOTAL_VOLUME(my_turf.reagents), rand(5,10)))) + if(istype(my_turf.weather?.weather_system?.current_state, /decl/state/weather/rain)) + var/decl/state/weather/rain/rain = my_turf.weather.weather_system.current_state + if(rain.is_liquid) + reagents.add_reagent(my_turf.weather.water_material, min(space_left, rand(3,5))) //Do this even if we're not ready for a plant cycle. process_reagents() var/needs_icon_update = 0 - // Update values every cycle rather than every process() tick. - if(force_update) - force_update = 0 - else if(world.time < (lastcycle + cycledelay)) - return - lastcycle = world.time - // Mutation level drops each main tick. mutation_level -= rand(2,4) // Weeds like water and nutrients, there's a chance the weed population will increase. // Bonus chance if the tray is unoccupied. if(waterlevel > 10 && nutrilevel > 2 && prob(isnull(seed) ? 5 : 1)) - weedlevel += 1 * HYDRO_SPEED_MULTIPLIER + weedlevel += 1 * growth_rate // There's a chance for a weed explosion to happen if the weeds take over. // Plants that are themselves weeds (weed_tolerance > 10) are unaffected. @@ -35,15 +43,15 @@ // If there is no seed data (and hence nothing planted), // or the plant is dead, process nothing further. if(!seed || dead) - if(mechanical) + if(mechanical) update_icon() //Harvesting would fail to set alert icons properly. return // Advance plant age. - var/cur_stage = get_overlay_stage() - if(prob(30)) - age += 1 * HYDRO_SPEED_MULTIPLIER - if(get_overlay_stage() != cur_stage) + var/cur_stage = seed.get_overlay_stage(age) + if(prob(30)) + age += 1 * growth_rate + if(seed.get_overlay_stage(age) != cur_stage) needs_icon_update |= 1 //Highly mutable plants have a chance of mutating every tick. @@ -57,39 +65,41 @@ mutate((rand(100) < 15) ? 2 : 1) mutation_level = 0 + if(pollen < 10) + pollen += seed?.produces_pollen + // Maintain tray nutrient and water levels. if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS) && seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0 && nutrilevel > 0 && prob(25)) - nutrilevel -= max(0,seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER) + nutrilevel -= max(0,seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) * growth_rate) if(seed.get_trait(TRAIT_REQUIRES_WATER) && seed.get_trait(TRAIT_WATER_CONSUMPTION) > 0 && waterlevel > 0 && prob(25)) - waterlevel -= max(0,seed.get_trait(TRAIT_WATER_CONSUMPTION) * HYDRO_SPEED_MULTIPLIER) + waterlevel -= max(0,seed.get_trait(TRAIT_WATER_CONSUMPTION) * growth_rate) // Make sure the plant is not starving or thirsty. Adequate // water and nutrients will cause a plant to become healthier. - var/healthmod = rand(1,3) * HYDRO_SPEED_MULTIPLIER + var/healthmod = rand(1,3) * growth_rate if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS) && prob(35)) - health += (nutrilevel < 2 ? -healthmod : healthmod) + plant_health += (nutrilevel < 2 ? -healthmod : healthmod) if(seed.get_trait(TRAIT_REQUIRES_WATER) && prob(35)) - health += (waterlevel < 10 ? -healthmod : healthmod) + plant_health += (waterlevel < 10 ? -healthmod : healthmod) // Check that pressure, heat and light are all within bounds. // First, handle an open system or an unconnected closed system. - var/turf/T = loc var/datum/gas_mixture/environment // If we're closed, take from our internal sources. - if(closed_system && (connected_port || holding)) + if(closed_system && (get_port() || holding)) environment = air_contents // If atmos input is not there, grab from turf. - if(!environment && istype(T)) environment = T.return_air() + if(!environment && istype(my_turf)) environment = my_turf.return_air() if(!environment) return // Seed datum handles gasses, light and pressure. if(mechanical && closed_system) - health -= seed.handle_environment(T,environment,tray_light) + plant_health -= seed.handle_plant_environment(src, environment, tray_light) else - health -= seed.handle_environment(T,environment) + plant_health -= seed.handle_plant_environment(src, environment) // If we're attached to a pipenet, then we should let the pipenet know we might have modified some gasses - if (closed_system && connected_port) + if (closed_system && get_port()) update_connected_network() // Toxin levels beyond the plant's tolerance cause damage, but @@ -97,29 +107,29 @@ if(toxins > 0) var/toxin_uptake = max(1,round(toxins/10)) if(toxins > seed.get_trait(TRAIT_TOXINS_TOLERANCE)) - health -= toxin_uptake + plant_health -= toxin_uptake toxins -= toxin_uptake // Check for pests and weeds. // Some carnivorous plants happily eat pests. if(pestlevel > 0) if(seed.get_trait(TRAIT_CARNIVOROUS)) - health += HYDRO_SPEED_MULTIPLIER - pestlevel -= HYDRO_SPEED_MULTIPLIER + plant_health += growth_rate + pestlevel -= growth_rate else if (pestlevel >= seed.get_trait(TRAIT_PEST_TOLERANCE)) - health -= HYDRO_SPEED_MULTIPLIER + plant_health -= growth_rate // Some plants thrive and live off of weeds. if(weedlevel > 0) if(seed.get_trait(TRAIT_PARASITE)) - health += HYDRO_SPEED_MULTIPLIER - weedlevel -= HYDRO_SPEED_MULTIPLIER + plant_health += growth_rate + weedlevel -= growth_rate else if (weedlevel >= seed.get_trait(TRAIT_WEED_TOLERANCE)) - health -= HYDRO_SPEED_MULTIPLIER + plant_health -= growth_rate // Handle life and death. // When the plant dies, weeds thrive and pests die off. - check_health(0) + check_plant_health(FALSE) // If enough time (in cycles, not ticks) has passed since the plant was harvested, we're ready to harvest again. if((age > seed.get_trait(TRAIT_MATURATION)) && \ @@ -133,16 +143,16 @@ if(!closed_system && \ seed.get_trait(TRAIT_SPREAD) == 2 && \ 2 * age >= seed.get_trait(TRAIT_MATURATION) && \ - !(locate(/obj/effect/vine) in get_turf(src)) && \ + !(locate(/obj/effect/vine) in my_turf) && \ prob(2 * seed.get_trait(TRAIT_POTENCY))) - new /obj/effect/vine(get_turf(src), seed) + new /obj/effect/vine(my_turf, seed) if(prob(3)) // On each tick, there's a chance the pest population will increase - pestlevel += 0.1 * HYDRO_SPEED_MULTIPLIER + pestlevel += 0.1 * growth_rate // Some seeds will self-harvest if you don't keep a lid on them. if(seed && seed.can_self_harvest && harvest && !closed_system && prob(5)) harvest() - check_health(needs_icon_update) + check_plant_health(needs_icon_update) return diff --git a/code/modules/hydroponics/trays/tray_reagents.dm b/code/modules/hydroponics/trays/tray_reagents.dm index 8038cd3c3e47..b02e71e2fda1 100644 --- a/code/modules/hydroponics/trays/tray_reagents.dm +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -3,11 +3,11 @@ icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' item_state = "spray" item_flags = ITEM_FLAG_NO_BLUDGEON - slot_flags = SLOT_BELT - throwforce = 4 + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL throw_speed = 2 throw_range = 10 + material = /decl/material/solid/organic/plastic var/toxicity = 4 var/pest_kill_str = 0 var/weed_kill_str = 0 @@ -52,26 +52,28 @@ // Weedkiller defines for hydroponics // ************************************* -/obj/item/weedkiller +/obj/item/plantspray/weedkiller name = "bottle of weedkiller" icon = 'icons/obj/items/chem/bottle.dmi' icon_state = "bottle16" - var/toxicity = 0 - var/weed_kill_str = 0 + toxicity = 0 + pest_kill_str = 0 + weed_kill_str = 0 + material = /decl/material/solid/organic/plastic -/obj/item/weedkiller/triclopyr +/obj/item/plantspray/weedkiller/triclopyr name = "bottle of glyphosate" icon_state = "bottle16" toxicity = 4 weed_kill_str = 2 -/obj/item/weedkiller/lindane +/obj/item/plantspray/weedkiller/lindane name = "bottle of triclopyr" icon_state = "bottle18" toxicity = 6 weed_kill_str = 4 -/obj/item/weedkiller/D24 +/obj/item/plantspray/weedkiller/D24 name = "bottle of 2,4-D" icon_state = "bottle15" toxicity = 8 diff --git a/code/modules/hydroponics/trays/tray_soil.dm b/code/modules/hydroponics/trays/tray_soil.dm index 4b1578eacb8e..7e74e1aa0147 100644 --- a/code/modules/hydroponics/trays/tray_soil.dm +++ b/code/modules/hydroponics/trays/tray_soil.dm @@ -1,27 +1,149 @@ /obj/machinery/portable_atmospherics/hydroponics/soil - name = "soil" + name = "tilled soil" desc = "A mound of earth. You could plant some seeds here." icon_state = "soil" - density = 0 + density = FALSE use_power = POWER_USE_OFF stat_immune = NOINPUT | NOSCREEN | NOPOWER mechanical = 0 tray_light = 0 + matter = null + pixel_z = 8 + color = "#7c5e42" -/obj/machinery/portable_atmospherics/hydroponics/soil/attackby(var/obj/item/O, var/mob/user) - if(istype(O,/obj/item/tank)) - return - else - ..() + // Not actually a machine, per se. + frame_type = null + uncreated_component_parts = list() + maximum_component_parts = list() + construct_state = /decl/machine_construction/noninteractive + + var/obj/item/stack/material/brick/reinforced_with + +/obj/machinery/portable_atmospherics/hydroponics/soil/get_alt_interactions(var/mob/user) + . = ..() + LAZYREMOVE(., global._reagent_interactions) + LAZYADD(., /decl/interaction_handler/empty_into) + +/obj/machinery/portable_atmospherics/hydroponics/soil/get_growth_rate() + var/turf/my_turf = get_turf(src) + return max(0, my_turf?.get_plant_growth_rate()) /obj/machinery/portable_atmospherics/hydroponics/soil/Initialize() + . = ..() + verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/close_lid_verb verbs -= /obj/machinery/portable_atmospherics/hydroponics/verb/setlight -/obj/machinery/portable_atmospherics/hydroponics/soil/Initialize() + if(isturf(loc)) + var/turf/turf = loc + color = turf.get_soil_color() + + pixel_x = rand(-1,1) + pixel_y = rand(-1,1) + update_icon() + +/obj/machinery/portable_atmospherics/hydroponics/soil/dismantle() + dump_contents() + qdel(src) + return null + +/obj/machinery/portable_atmospherics/hydroponics/soil/Destroy() + var/oldloc = loc + QDEL_NULL(reinforced_with) + . = ..() + if(oldloc) + for(var/obj/machinery/portable_atmospherics/hydroponics/soil/neighbor in orange(1, oldloc)) + neighbor.update_icon() + +/obj/machinery/portable_atmospherics/hydroponics/soil/Crossed(atom/movable/AM) + . = ..() + if(!istype(AM) || !ismob(AM) || !AM.simulated || !seed || dead) + return + var/mob/walker = AM + if(walker.mob_size < MOB_SIZE_SMALL) + return + if(MOVING_DELIBERATELY(walker) && prob(90)) + return + if(prob(25)) + return + to_chat(walker, SPAN_DANGER("You trample \the [seed.display_name]!")) + plant_health = max(0, plant_health - rand(3,5)) + check_plant_health() + +/obj/machinery/portable_atmospherics/hydroponics/soil/Process() + . = ..() + if(. == PROCESS_KILL || QDELETED(src)) + return + var/turf/my_turf = get_turf(src) + if(!istype(my_turf)) + return + if(closed_system || !reagents || waterlevel >= 100) + return + if((REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents)) <= 0 || REAGENT_TOTAL_VOLUME(reagents) >= 10) + return + for(var/step_dir in global.alldirs) + var/turf/neighbor = get_step_resolving_mimic(src, step_dir) + if(neighbor == my_turf || !REAGENT_TOTAL_VOLUME(neighbor?.reagents) || !Adjacent(neighbor)) + continue + neighbor.reagents.trans_to_obj(src, rand(2,3)) + if((REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents)) <= 0 || REAGENT_TOTAL_VOLUME(reagents) >= 10) + break + return ..() + +/obj/machinery/portable_atmospherics/hydroponics/soil/attackby(var/obj/item/used_item, var/mob/user) + + if(istype(used_item, /obj/item/stack/material/brick)) + if(reinforced_with) + to_chat(user, SPAN_WARNING("\The [src] has already been fenced with bricks.")) + return TRUE + var/obj/item/stack/material/brick/bricks = used_item + if(bricks.get_amount() < 4) + to_chat(user, SPAN_WARNING("You need at least four bricks to fence off \the [src].")) + return TRUE + + var/obj/item/stack/material/brick/new_bricks = bricks.split(5) + if(!QDELETED(new_bricks) && istype(new_bricks) && new_bricks.get_amount() >= 4) + reinforced_with = new_bricks + to_chat(user, SPAN_NOTICE("You fence \the [src] off with \the [reinforced_with].")) + update_icon() + for(var/obj/machinery/portable_atmospherics/hydroponics/soil/neighbor in orange(1, loc)) + neighbor.update_icon() + return TRUE + + if(!seed && user.check_intent(I_FLAG_HARM) && (IS_SHOVEL(used_item) || IS_HOE(used_item))) + var/use_tool = used_item.get_tool_quality(TOOL_SHOVEL) > used_item.get_tool_quality(TOOL_HOE) ? TOOL_SHOVEL : TOOL_HOE + if(use_tool) + if(used_item.do_tool_interaction(use_tool, user, src, 3 SECONDS, "filling in", "filling in", check_skill = SKILL_BOTANY)) + qdel(src) + return TRUE + if(istype(used_item, /obj/item/tank)) + return TRUE + return ..() + +/obj/machinery/portable_atmospherics/hydroponics/soil/on_update_icon() . = ..() - return INITIALIZE_HINT_LATELOAD + if(reinforced_with) + for(var/step_dir in global.cardinal) + var/obj/machinery/portable_atmospherics/hydroponics/soil/neighbor = locate() in get_step_resolving_mimic(loc, step_dir) + if(istype(neighbor) && neighbor.reinforced_with) + continue + var/image/I = image(icon, "bricks", dir = step_dir) + I.color = reinforced_with.get_color() + I.appearance_flags |= RESET_COLOR + I.pixel_x = -(pixel_x) + I.pixel_y = -(pixel_y) + I.pixel_z = -(pixel_z) + add_overlay(I) + +/obj/machinery/portable_atmospherics/hydroponics/soil/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) + return TRUE + . = ..() + if(. && reinforced_with) + var/obj/machinery/portable_atmospherics/hydroponics/soil/neighbor = locate() in get_turf(mover) + if(!neighbor?.reinforced_with) + return FALSE // Holder for vine plants. // Icons for plants are generated as overlays, so setting it to invisible wouldn't work. @@ -29,29 +151,36 @@ /obj/machinery/portable_atmospherics/hydroponics/soil/invisible name = "plant" desc = null - icon = 'icons/obj/seeds.dmi' icon_state = "blank" + is_spawnable_type = FALSE var/list/connected_zlevels //cached for checking if we someone is obseving us so we should process /obj/machinery/portable_atmospherics/hydroponics/soil/is_burnable() return ..() && seed.get_trait(TRAIT_HEAT_TOLERANCE) < 1000 /obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Initialize(mapload,var/datum/seed/newseed, var/start_mature) - . = ..() + . = ..(mapload) // avoid passing newseed as dir seed = newseed + if(!seed) + return INITIALIZE_HINT_QDEL dead = 0 age = start_mature ? seed.get_trait(TRAIT_MATURATION) : 1 - health = seed.get_trait(TRAIT_ENDURANCE) - lastcycle = world.time - pixel_y = rand(-12,12) - pixel_x = rand(-12,12) + plant_health = seed.get_trait(TRAIT_ENDURANCE) + if(isnull(default_pixel_y)) + default_pixel_y = rand(-12,12) + if(isnull(default_pixel_y)) + default_pixel_x = rand(-12,12) + reset_offsets(0) if(seed) name = seed.display_name - check_health() - connected_zlevels = GetConnectedZlevels(z) + check_plant_health() + connected_zlevels = SSmapping.get_connected_levels(z) /obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Process() - if(z in GLOB.using_map.station_levels) //plants on station always tick + if(!seed) + qdel_self() + return + if(isStationLevel(z)) //plants on station always tick return ..() if(living_observers_present(connected_zlevels)) return ..() @@ -60,7 +189,7 @@ ..() qdel(src) -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/harvest() +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/harvest(mob/user) ..() if(!seed) // Repeat harvests are a thing. qdel(src) @@ -68,15 +197,12 @@ /obj/machinery/portable_atmospherics/hydroponics/soil/invisible/die() qdel(src) -/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Process() - if(!seed) - qdel(src) - return - ..() - /obj/machinery/portable_atmospherics/hydroponics/soil/invisible/Destroy() // Check if we're masking a decal that needs to be visible again. for(var/obj/effect/vine/plant in get_turf(src)) if(plant.invisibility == INVISIBILITY_MAXIMUM) plant.set_invisibility(initial(plant.invisibility)) - . = ..() \ No newline at end of file + . = ..() + +/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/get_growth_rate() + return max(..(), 1) diff --git a/code/modules/hydroponics/trays/tray_update_icons.dm b/code/modules/hydroponics/trays/tray_update_icons.dm index e5cf39e819bd..565872fab69d 100644 --- a/code/modules/hydroponics/trays/tray_update_icons.dm +++ b/code/modules/hydroponics/trays/tray_update_icons.dm @@ -1,62 +1,38 @@ //Refreshes the icon and sets the luminosity /obj/machinery/portable_atmospherics/hydroponics/on_update_icon() + // Update name. if(seed) if(mechanical) - name = "[base_name] ([seed.seed_name])" + name = "[base_name] ([seed.product_name])" else - name = "[seed.seed_name]" + name = seed.product_name else SetName(initial(name)) - overlays.Cut() - var/new_overlays = list() - // Updates the plant overlay. - if(seed) - if(dead) - var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-dead" - var/image/dead_overlay = SSplants.plant_icon_cache["[ikey]"] - if(!dead_overlay) - dead_overlay = image('icons/obj/hydroponics/hydroponics_growing.dmi', "[ikey]") - dead_overlay.color = DEAD_PLANT_COLOUR - new_overlays |= dead_overlay - else - if(!seed.growth_stages) - seed.update_growth_stages() - if(!seed.growth_stages) - log_error("Seed type [seed.get_trait(TRAIT_PLANT_ICON)] cannot find a growth stage value.") - return - var/overlay_stage = get_overlay_stage() - - var/ikey = "\ref[seed]-plant-[overlay_stage]" - if(!SSplants.plant_icon_cache[ikey]) - SSplants.plant_icon_cache[ikey] = seed.get_icon(overlay_stage) - new_overlays |= SSplants.plant_icon_cache[ikey] + cut_overlays() - if(harvest && overlay_stage == seed.growth_stages) - ikey = "[seed.get_trait(TRAIT_PRODUCT_ICON)]" - var/image/harvest_overlay = SSplants.plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] - if(!harvest_overlay) - harvest_overlay = image('icons/obj/hydroponics/hydroponics_products.dmi', "[ikey]") - harvest_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) - SSplants.plant_icon_cache["product-[ikey]-[harvest_overlay.color]"] = harvest_overlay - new_overlays |= harvest_overlay + var/image/plant_overlay = new /image + plant_overlay.overlays = seed?.get_appearance(dead = dead, age = age, can_harvest = harvest) + plant_overlay.layer = layer + 0.5 + plant_overlay.appearance_flags |= RESET_COLOR + add_overlay(plant_overlay) //Updated the various alert icons. if(mechanical) //Draw the cover. if(closed_system) - new_overlays += "hydrocover2" - if(seed && health <= (seed.get_trait(TRAIT_ENDURANCE) / 2)) - new_overlays += "over_lowhealth3" + add_overlay("hydrocover2") + if(seed && plant_health <= (seed.get_trait(TRAIT_ENDURANCE) / 2)) + add_overlay("over_lowhealth3") if(waterlevel <= 10) - new_overlays += "over_lowwater3" + add_overlay("over_lowwater3") if(nutrilevel <= 2) - new_overlays += "over_lownutri3" + add_overlay("over_lownutri3") if(weedlevel >= 5 || pestlevel >= 5 || toxins >= 40) - new_overlays += "over_alert3" + add_overlay("over_alert3") if(harvest) - new_overlays += "over_harvest3" + add_overlay("over_harvest3") if((!density || !opacity) && seed && seed.get_trait(TRAIT_LARGE)) if(!mechanical) @@ -67,19 +43,8 @@ set_density(0) set_opacity(0) - overlays |= new_overlays - // Update bioluminescence. if(seed && seed.get_trait(TRAIT_BIOLUM)) - set_light(0.5, 0.1, 3, l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR)) + set_light(round(seed.get_trait(TRAIT_POTENCY)/10), l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR)) else set_light(0) - -/obj/machinery/portable_atmospherics/hydroponics/proc/get_overlay_stage() - . = 1 - var/seed_maturation = seed.get_trait(TRAIT_MATURATION) - if(age >= seed_maturation) - . = seed.growth_stages - else - var/maturation = max(seed_maturation/seed.growth_stages, 1) - . = max(1, round(age/maturation)) \ No newline at end of file diff --git a/code/modules/implants/implant.dm b/code/modules/implants/implant.dm new file mode 100644 index 000000000000..0e58c2b46b19 --- /dev/null +++ b/code/modules/implants/implant.dm @@ -0,0 +1,127 @@ +#define MALFUNCTION_NONE 0 +#define MALFUNCTION_TEMPORARY 1 +#define MALFUNCTION_PERMANENT 2 + + +/obj/item/implant + name = "implant" + icon = 'icons/obj/items/implant/implant.dmi' + icon_state = "implant" + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/metal/titanium + var/implanted = FALSE + var/mob/imp_in + var/obj/item/organ/external/part + var/implant_color = "b" + var/malfunction = MALFUNCTION_NONE + /// if TRUE, advanced scanners will directly name the implant in results + var/known = FALSE + /// if FALSE, scanners will not locate this implant at all + var/hidden = FALSE + +/obj/item/implant/proc/trigger(emote, source) + return + +/obj/item/implant/proc/hear(message) + return + +/obj/item/implant/proc/activate() + return + +/obj/item/implant/proc/disable(var/time = 10 SECONDS) + if(malfunction) + return FALSE + + malfunction = MALFUNCTION_TEMPORARY + addtimer(CALLBACK(src,PROC_REF(restore)),time) + return TRUE + +/obj/item/implant/proc/restore() + if(malfunction == MALFUNCTION_PERMANENT || !malfunction) + return FALSE + + malfunction = MALFUNCTION_NONE + return TRUE + +// What does the implant do upon injection? +// return FALSE if the implant fails (ex. Revhead and loyalty implant.) +// return TRUE if the implant succeeds (ex. Nonrevhead and loyalty implant.) +/obj/item/implant/proc/implanted(var/mob/living/source) + return TRUE + +/obj/item/implant/proc/can_implant(mob/living/victim, mob/user, var/target_zone) + var/mob/living/human/human_victim = victim + if(istype(human_victim) && !GET_EXTERNAL_ORGAN(human_victim, target_zone)) + to_chat(user, SPAN_WARNING("\The [human_victim] is missing that body part.")) + return FALSE + return TRUE + +/obj/item/implant/proc/implant_in_mob(mob/living/victim, mob/living/user, var/target_zone) + if (ishuman(victim)) + var/mob/living/human/human_victim = victim + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(human_victim, target_zone) + if(affected) + LAZYADD(affected.implants, src) + part = affected + + forceMove(victim) + imp_in = victim + implanted = TRUE + implanted(victim) + + return TRUE + +/obj/item/implant/proc/removed() + imp_in = null + if(part) + LAZYREMOVE(part.implants, src) + part = null + implanted = FALSE + +//Called in surgery when incision is retracted open / ribs are opened - basically before you can take implant out +/obj/item/implant/proc/exposed() + return + +/obj/item/implant/proc/get_data() + return "No information available" + +/obj/item/implant/interact(user) + var/datum/browser/popup = new(user, capitalize(name), capitalize(name), 300, 700, src) + var/dat = get_data() + if(malfunction) + popup.title = "??? implant" + dat = stars(dat,10) + popup.set_content(dat) + popup.open() + +/obj/item/implant/proc/islegal() + return FALSE + +/obj/item/implant/proc/meltdown() //breaks it down, making implant unrecongizible + if(malfunction == MALFUNCTION_PERMANENT) + return + to_chat(imp_in, SPAN_DANGER("You feel something melting inside [part ? "your [part.name]" : "you"]!")) + imp_in.apply_damage(15, BURN, used_weapon = "Electronics meltdown", given_organ = part) // used_weapon can be a string or an item, for some reason + name = "melted implant" + desc = "Charred circuit in melted plastic case. Wonder what that used to be..." + icon_state = "implant_melted" + malfunction = MALFUNCTION_PERMANENT + +/obj/item/implant/emp_act(severity) + var/power = 4 - severity + if(prob(power * 15)) + meltdown() + else if(prob(power * 25)) + activate() + else if(prob(power * 33)) + disable(rand(power*10 SECONDS,power*100 SECONDS)) + +/obj/item/implant/Destroy() + if(part) + LAZYREMOVE(part.implants, src) + part = null + imp_in = null + var/obj/item/implanter/implanter = loc + if(istype(implanter) && implanter.imp == src) + implanter.imp = null + return ..() diff --git a/code/modules/implants/implant_types/adrenaline.dm b/code/modules/implants/implant_types/adrenaline.dm new file mode 100644 index 000000000000..c7e2dc6a2ffb --- /dev/null +++ b/code/modules/implants/implant_types/adrenaline.dm @@ -0,0 +1,46 @@ +/obj/item/implant/adrenalin + name = "adrenalin implant" + desc = "Removes all stuns and knockdowns." + origin_tech = @'{"materials":1,"biotech":2,"esoteric":2}' + hidden = TRUE + var/uses = 3 + +/obj/item/implant/adrenalin/get_data() + return {" + Implant Specifications:
          + Name: Cybersun Industries Adrenalin Implant
          + Life: Five days.
          + Important Notes: Illegal
          +
          + Implant Details: Subjects injected with implant can activate a massive injection of adrenalin.
          + Function: Contains nanobots to stimulate body to mass-produce Adrenalin.
          + Special Features: Will prevent and cure most forms of brainwashing.
          + Integrity: Implant can only be used three times before the nanobots are depleted."} + +/obj/item/implant/adrenalin/trigger(emote, mob/source) + if (emote == "pale") + activate() + +/obj/item/implant/adrenalin/activate()//this implant is unused but I'm changing it for the sake of consistency + if (uses < 1 || malfunction || !imp_in) + return 0 + uses-- + to_chat(imp_in, SPAN_NOTICE("You feel a sudden surge of energy!")) + + imp_in.set_status_condition(STAT_STUN, 0) + imp_in.set_status_condition(STAT_WEAK, 0) + imp_in.set_status_condition(STAT_PARA, 0) + +/obj/item/implant/adrenalin/implanted(mob/source) + var/activation_string = "can be activated by using the pale emote, say *pale to attempt to activate." + source.StoreMemory("\A [src] [activation_string]", /decl/memory_options/system) + to_chat(source, "\The [src] [activation_string]") + return TRUE + +/obj/item/implanter/adrenalin + name = "implanter-adrenalin" + imp = /obj/item/implant/adrenalin + +/obj/item/implantcase/adrenalin + name = "glass case - 'adrenalin'" + imp = /obj/item/implant/adrenalin \ No newline at end of file diff --git a/code/modules/implants/implant_types/chem.dm b/code/modules/implants/implant_types/chem.dm new file mode 100644 index 000000000000..10210ac18f74 --- /dev/null +++ b/code/modules/implants/implant_types/chem.dm @@ -0,0 +1,58 @@ +var/global/list/chem_implants = list() + +/obj/item/implant/chem + name = "chemical implant" + desc = "Injects things." + origin_tech = @'{"materials":1,"biotech":2}' + known = TRUE + chem_volume = 50 + +/obj/item/implant/chem/get_data() + return {" + Implant Specifications:
          + Name: Robust Corp MJ-420 Prisoner Management Implant
          + Life: Deactivates upon death but remains within the body.
          + Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
          + will suffer from an increased appetite.

          +
          + Implant Details:
          + Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
          + the implant releases the chemicals directly into the blood stream.
          + Special Features: + Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
          + Can only be loaded while still in its original case.
          + Integrity: Implant will last so long as the subject is alive. However, if the subject suffers from prolonged malnutrition,
          + nine or more days without nutrients, the implant may become unstable and either pre-maturely inject the subject or simply break."} + +/obj/item/implant/chem/Initialize() + . = ..() + global.chem_implants += src + +/obj/item/implant/chem/Destroy() + . = ..() + global.chem_implants -= src + +/obj/item/implant/chem/activate(var/amount) + if(malfunction) + return FALSE + if(!amount) + amount = rand(1,25) + reagents.trans_to_mob(imp_in, amount, CHEM_INJECT) + to_chat(imp_in, SPAN_NOTICE("You hear a faint *beep*.")) + +/obj/item/implant/chem/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/chems/syringe)) + if(REAGENT_TOTAL_VOLUME(reagents) >= REAGENT_MAXIMUM_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + else if(do_after(user, 0.5 SECONDS, src)) + used_item.reagents.trans_to_obj(src, 5) + to_chat(user, SPAN_NOTICE("You inject 5 units of the solution. The syringe now contains [REAGENT_TOTAL_VOLUME(used_item.reagents)] units.")) + return TRUE + return ..() + +/obj/item/implantcase/chem + name = "glass case - 'chem'" + imp = /obj/item/implant/chem + +/obj/item/implantcase/chem/can_be_injected_by(var/atom/injector) + return FALSE diff --git a/code/modules/implants/implant_types/compressed.dm b/code/modules/implants/implant_types/compressed.dm new file mode 100644 index 000000000000..d9f6512f81f8 --- /dev/null +++ b/code/modules/implants/implant_types/compressed.dm @@ -0,0 +1,94 @@ +/obj/item/implant/compressed + name = "compressed matter implant" + desc = "Based on compressed matter technology, can store a single item." + icon_state = "implant_evil" + origin_tech = @'{"materials":4,"biotech":2,"esoteric":2}' + hidden = 1 + var/activation_emote + var/obj/item/scanned + +/obj/item/implant/compressed/trigger(emote, mob/source) + if (!scanned) + return FALSE + + if (emote == activation_emote) + to_chat(source, "The air glows as \the [scanned] uncompresses.") + activate() + +/obj/item/implant/compressed/activate() + if(malfunction) + return + var/turf/our_turf = get_turf(src) + if (imp_in) + imp_in.put_in_hands(scanned) + else + scanned.forceMove(our_turf) + qdel(src) + +/obj/item/implant/compressed/implanted(mob/source) + activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") + var/activation_string = "can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate." + if (source.mind) + source.StoreMemory("\A [src] [activation_string]", /decl/memory_options/system) + to_chat(source, "\The [src] [activation_string].") + return TRUE + +/obj/item/implanter/compressed + name = "implanter (C)" + icon = 'icons/obj/items/implant/compressed_implant.dmi' + icon_state = "cimplanter1" + desc = "The matter compressor safety is on." + imp = /obj/item/implant/compressed + var/const/SAFETY_OFF = 0 + var/const/SAFETY_ON = 1 + var/const/SAFETY_USED = 2 + var/safe = SAFETY_ON + +/obj/item/implanter/compressed/on_update_icon() + . = ..() + if (istype(imp, /obj/item/implant/compressed)) + var/obj/item/implant/compressed/compression_implant = imp + icon_state = compression_implant.scanned ? "cimplanter2" : "cimplanter1" + else + icon_state = "cimplanter0" + +/obj/item/implanter/compressed/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + var/obj/item/implant/compressed/compression_implant = imp + if(!istype(compression_implant) || compression_implant.scanned == null) + to_chat(user, SPAN_WARNING("Please compress an object with the implanter first.")) + return TRUE + return ..() + +/obj/item/implanter/compressed/afterattack(obj/item/used_item, mob/user, proximity) + if(!proximity) + return + if(!istype(imp, /obj/item/implant/compressed)) + to_chat(user, SPAN_WARNING("There is no compressed matter implant in \the [src]!")) + return + var/obj/item/implant/compressed/compression_implant = imp + if (compression_implant.scanned) + if (!used_item.storage) + to_chat(user, SPAN_WARNING("Something is already compressed inside the implant!")) + return + else if(safe >= SAFETY_ON) + if (!used_item.storage) + to_chat(user, SPAN_WARNING("The matter compressor safeties prevent you from doing that.")) + return + var/atom/used_item_loc = used_item.loc + var/mob/living/human/holder = used_item_loc + if(istype(holder) && !holder.try_unequip(used_item)) + return + if(used_item_loc.storage) + used_item_loc.storage.remove_from_storage(user, used_item) + compression_implant.scanned = used_item + used_item.forceMove(src) //Store it inside + safe = SAFETY_USED + desc = "It currently contains some matter." + update_icon() + +/obj/item/implanter/compressed/attack_self(var/mob/user) + if(!imp || safe == SAFETY_USED) + return ..() + safe = !safe + to_chat(user, SPAN_NOTICE("You [safe ? "enable" : "disable"] the matter compressor safety.")) + src.desc = "The matter compressor safety is [safe ? "on" : "off"]." \ No newline at end of file diff --git a/code/modules/implants/implant_types/death_alarm.dm b/code/modules/implants/implant_types/death_alarm.dm new file mode 100644 index 000000000000..8bbe9fa27513 --- /dev/null +++ b/code/modules/implants/implant_types/death_alarm.dm @@ -0,0 +1,71 @@ +/obj/item/implant/death_alarm + name = "death alarm implant" + desc = "An alarm which monitors host vital signs and transmits a radio message upon death." + origin_tech = @'{"materials":1,"biotech":2,"programming":3}' + known = TRUE + var/mobname = "John Doe" + var/const/DEATH_ALARM_CAUSE_EMP = "emp" + var/const/DEATH_ALARM_CAUSE_GIB = "gib" + var/const/DEATH_ALARM_CAUSE_DEATH = "death" + +/obj/item/implant/death_alarm/get_data() + return {" + Implant Specifications:
          + Name: [global.using_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor
          + Life: Activates upon death.
          + Important Notes: Alerts crew to crewmember death.
          +
          + Implant Details:
          + Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
          + Special Features: Alerts crew to crewmember death.
          + Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + +/obj/item/implant/death_alarm/islegal() + return TRUE + +/obj/item/implant/death_alarm/Process() + if (!implanted) + return + if(isnull(imp_in)) // If the mob got gibbed + activate(DEATH_ALARM_CAUSE_GIB) + else if(imp_in.stat == DEAD) + activate(DEATH_ALARM_CAUSE_DEATH) + +/obj/item/implant/death_alarm/activate(var/cause = DEATH_ALARM_CAUSE_EMP) + if(malfunction) + return + var/area/location = get_area(imp_in) + if (cause == DEATH_ALARM_CAUSE_EMP && prob(50)) + location = pick(teleportlocs) + var/death_message = "[mobname] has died in [location.proper_name]!" + if(cause == DEATH_ALARM_CAUSE_GIB) + death_message = "[mobname] has died-zzzzt in-in-in..." + STOP_PROCESSING(SSobj, src) + do_telecomms_announcement(src, death_message, "[mobname]'s Death Alarm", list("Security", "Medical", "Command")) + +/obj/item/implant/death_alarm/disable() + . = ..() + if(.) + STOP_PROCESSING(SSobj, src) + +/obj/item/implant/death_alarm/restore() + . = ..() + if(.) + START_PROCESSING(SSobj, src) + +/obj/item/implant/death_alarm/meltdown() + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/implant/death_alarm/implanted(mob/source) + mobname = source.real_name + START_PROCESSING(SSobj, src) + return TRUE + +/obj/item/implant/death_alarm/removed() + ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/implantcase/death_alarm + name = "glass case - 'death alarm'" + imp = /obj/item/implant/death_alarm \ No newline at end of file diff --git a/code/modules/implants/implant_types/explosive.dm b/code/modules/implants/implant_types/explosive.dm new file mode 100644 index 000000000000..c4d2919bd763 --- /dev/null +++ b/code/modules/implants/implant_types/explosive.dm @@ -0,0 +1,175 @@ +//BS12 Explosive +/obj/item/implant/explosive + name = "explosive implant" + desc = "A military grade micro bio-explosive. Highly dangerous." + icon_state = "implant_evil" + origin_tech = @'{"materials":1,"biotech":2,"esoteric":3}' + hidden = TRUE + var/elevel + var/phrase + var/code = 13 + var/frequency = 1443 + var/datum/radio_frequency/radio_connection + var/warning_message = "Tampering detected. Tampering detected." + +/obj/item/implant/explosive/get_data() + . = {" + Implant Specifications:
          + Name: Robust Corp RX-78 Intimidation Class Implant
          + Life: Activates upon codephrase.
          + Important Notes: Explodes
          +
          + Implant Details:
          + Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
          + Special Features: Explodes
          + Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + if(!malfunction) + . += {" +
          Explosion yield mode:
          + [elevel || "NONE SET"]
          + Activation phrase:
          + [phrase || "NONE SET"]
          + Frequency:
          + - + - + [format_frequency(frequency)] + + + +
          + Code:
          + - + - + [code] + + + +
          + Tampering warning message:
          + This will be broadcasted on radio if implant is exposed during surgery.
          + [warning_message || "NONE SET"] + "} + +/obj/item/implant/explosive/Initialize() + . = ..() + global.listening_objects += src + set_frequency(frequency) + +/obj/item/implant/explosive/Topic(href, href_list) +/obj/item/implant/explosive/OnTopic(mob/user, href_list, datum/topic_state/state) + if (href_list["freq"]) + var/new_frequency = frequency + text2num(href_list["freq"]) + new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(new_frequency) + return TOPIC_REFRESH + if (href_list["code"]) + var/adj = text2num(href_list["code"]) + if(!adj) + code = input("Set radio activation code","Radio activation") as num + else + code += adj + code = clamp(code,1,100) + return TOPIC_REFRESH + if (href_list["mode"]) + var/mod = input("Set explosion mode", "Explosion mode") as null|anything in list("Localized Limb", "Destroy Body", "Full Explosion") + if(mod) + elevel = mod + return TOPIC_REFRESH + if (href_list["msg"]) + var/msg = input("Set tampering message, or leave blank for no broadcasting.", "Anti-tampering", warning_message) as text|null + if(msg) + warning_message = msg + return TOPIC_REFRESH + if (href_list["phrase"]) + var/talk = input("Set activation phrase", "Audio activation", phrase) as text|null + if(talk) + phrase = sanitize_phrase(talk) + return TOPIC_REFRESH + +/obj/item/implant/explosive/receive_signal(datum/signal/signal) + if(signal && signal.encryption == code) + activate() + +/obj/item/implant/explosive/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + +/obj/item/implant/explosive/hear_talk(mob/M, msg) + hear(msg) + +/obj/item/implant/explosive/hear(var/msg) + if(!phrase) + return + if(findtext(sanitize_phrase(msg),phrase)) + activate() + qdel(src) + +/obj/item/implant/explosive/exposed() + if(warning_message) + do_telecomms_announcement(src, warning_message, "Anti-Tampering System") + +/obj/item/implant/explosive/proc/sanitize_phrase(phrase) + var/list/replacechars = list("'" = "","\"" = "",">" = "","<" = "","(" = "",")" = "") + return replace_characters(phrase, replacechars) + +/obj/item/implant/explosive/activate() + if (malfunction) + return + + var/turf/our_turf = get_turf(src) + if(our_turf) + our_turf.hotspot_expose(3500, CELL_VOLUME/20) // expose roughly 1/20th of a cell to 3500K heat + + playsound(our_turf, 'sound/items/countdown.ogg', 75, 1, -3) + if(ismob(imp_in)) + imp_in.audible_message(SPAN_WARNING("Something beeps inside [imp_in][part ? "'s [part.name]" : ""]!")) + log_and_message_admins("Explosive implant triggered in [imp_in] ([imp_in.key]). (JMP) ") + else + audible_message(SPAN_WARNING("[src] beeps omniously!")) + log_and_message_admins("Explosive implant triggered in [our_turf.loc]. (JMP) ") + + if(!elevel) + elevel = "Full Explosion" + switch(elevel) + if ("Localized Limb") + switch(part?.organ_tag) + if(BP_CHEST, BP_GROIN) + part.take_damage(60, inflicter = "Explosion") + if(null) + pass() + else + part.dismember(0,DISMEMBER_METHOD_BLUNT) + explosion(our_turf, -1, -1, 2, 3) + if ("Destroy Body") + explosion(our_turf, -1, 0, 1, 6) + if(ismob(imp_in)) + imp_in.gib() + if ("Full Explosion") + explosion(our_turf, 0, 1, 3, 6) + if(ismob(imp_in)) + imp_in.gib() + qdel(src) + +/obj/item/implant/explosive/implanted(mob/target) + if(!elevel) + elevel = alert("What sort of explosion would you prefer?", "Implant Intent", "Localized Limb", "Destroy Body", "Full Explosion") + if(!phrase) + phrase = sanitize_phrase(input("Choose activation phrase:") as text) + if(!phrase) + return + + var/memo = "Explosive implant in [target] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate. It can also be triggered with a radio signal on frequency [format_frequency(src.frequency)] with code [code]." + usr.StoreMemory(memo, /decl/memory_options/system) + to_chat(usr, memo) + return TRUE + +/obj/item/implant/explosive/Destroy() + removed() + radio_controller.remove_object(src, frequency) + radio_connection = null + return ..() + +/obj/item/implanter/explosive + name = "implanter (E)" + imp = /obj/item/implant/explosive + +/obj/item/implantcase/explosive + name = "glass case - 'explosive'" + imp = /obj/item/implant/explosive \ No newline at end of file diff --git a/code/modules/implants/implant_types/freedom.dm b/code/modules/implants/implant_types/freedom.dm new file mode 100644 index 000000000000..3fe600c5108d --- /dev/null +++ b/code/modules/implants/implant_types/freedom.dm @@ -0,0 +1,66 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/implant/freedom + name = "freedom implant" + desc = "Use this to escape from those evil Red Shirts." + origin_tech = @'{"materials":1,"biotech":2,"esoteric":2}' + implant_color = "r" + hidden = TRUE + var/activation_emote + var/uses + +/obj/item/implant/freedom/get_data() + return {" + Implant Specifications:
          + Name: Freedom Beacon
          + Life: optimum 5 uses
          + Important Notes: Illegal
          +
          + Implant Details:
          + Function: Transmits a specialized cluster of signals to override handcuff locking + mechanisms
          + Special Features:
          + Neuro-Scan- Analyzes certain shadow signals in the nervous system
          + Integrity: The battery is extremely weak and commonly after injection its + life can drive down to only 1 use.
          + No Implant Specifics"} + +/obj/item/implant/freedom/Initialize() + . = ..() + uses = rand(1, 5) + +/obj/item/implant/freedom/trigger(emote, mob/living/source) + if (emote == activation_emote) + activate() + +/obj/item/implant/freedom/activate() + if(uses < 1 || malfunction) + return FALSE + if(remove_cuffs_and_unbuckle(imp_in)) + uses-- + to_chat(imp_in, "You feel a faint click.") + +/obj/item/implant/freedom/proc/remove_cuffs_and_unbuckle(mob/living/user) + var/obj/cuffs = user.get_equipped_item(slot_handcuffed_str) + if(!cuffs) + return FALSE + if(!user.try_unequip(cuffs)) + return FALSE + if(user.buckled && user.buckled.buckle_require_restraints) + user.buckled.unbuckle_mob() + return TRUE + +/obj/item/implant/freedom/implanted(mob/living/source) + src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") + var/activation_string = "can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate." + source.StoreMemory("\A [src] [activation_string]", /decl/memory_options/system) + to_chat(source, "\The [src] [activation_string]") + return TRUE + +/obj/item/implanter/freedom + name = "implanter (F)" + imp = /obj/item/implant/freedom + +/obj/item/implantcase/freedom + name = "glass case - 'freedom'" + imp = /obj/item/implant/freedom \ No newline at end of file diff --git a/code/modules/implants/implant_types/imprinting.dm b/code/modules/implants/implant_types/imprinting.dm new file mode 100644 index 000000000000..5a8305087572 --- /dev/null +++ b/code/modules/implants/implant_types/imprinting.dm @@ -0,0 +1,130 @@ +/obj/item/implant/imprinting + name = "imprinting implant" + desc = "Latest word in training your peons." + origin_tech = @'{"materials":1,"biotech":2,"programming":3}' + hidden = TRUE + var/list/instructions = list("Do your job.", "Respect your superiors.", "Wash you hands after using the toilet.") + var/brainwashing = FALSE + +/obj/item/implant/imprinting/get_data() + . = {" + Implant Specifications:
          + Name: BB-56 "Educator" Employee Assistance Implant
          + Life: 1 year.
          +
          + Function: Adjusts itself to host's brainwaves, and presents supplied instructions as their 'inner voice' for less intrusive reminding. It will transmit them every 5 minutes in non-obtrusive manner.
          + Special Features: Do NOT implant if subject is under effect of any mind-altering drugs. + It carries risk of over-tuning, making subject unable to question the suggestions received, treating them as beliefs they feel strongly about.
          + It is HIGLY ILLEGAL and the seller does NOT endorse use of this device in such way. + Any amount of "Mind-Breaker"(TM) present in bloodstream will trigger this side-effect.
          "} + . += "
          Instructions:
          " + for(var/i = 1 to length(instructions)) + . += "- [instructions[i]] Edit Remove
          " + . += "Add" + +/obj/item/implant/imprinting/OnTopic(mob/user, href_list, datum/topic_state/state) + if (href_list["add"]) + var/mod = sanitize(input("Add an instruction", "Instructions") as text|null) + if(mod) + instructions += mod + return TOPIC_REFRESH + return TOPIC_HANDLED + if (href_list["edit"]) + var/idx = text2num(href_list["edit"]) + var/mod = sanitize(input("Edit the instruction", "Instruction Editing", instructions[idx]) as text|null) + if(mod) + instructions[idx] = mod + return TOPIC_REFRESH + return TOPIC_HANDLED + if (href_list["del"]) + instructions -= instructions[text2num(href_list["del"])] + return TOPIC_REFRESH + return TOPIC_NOACTION + +/obj/item/implant/imprinting/implanted(mob/living/victim) + var/mob/living/human/human_victim = victim + if(!istype(human_victim)) + return FALSE + if(human_victim.reagents.has_reagent(/decl/material/liquid/hallucinogenics)) + brainwashing = TRUE + var/msg = get_instructions() + to_chat(human_victim, msg) + if(human_victim.mind) + human_victim.StoreMemory(msg, /decl/memory_options/system) + if(brainwashing) + log_and_message_admins("was implanted with a brainwashing implant holding the following laws: [jointext(instructions, ";")].", human_victim) + addtimer(CALLBACK(src,PROC_REF(activate)), 5 MINUTES, (TIMER_UNIQUE|TIMER_OVERRIDE)) + return TRUE + +/obj/item/implant/imprinting/proc/get_instructions() + . = list() + if(brainwashing) + . += SPAN_DANGER("The fog in your head clears, and you remember some important things. You hold the following as deep convictions, almost like synthetics' laws:") + else + . += SPAN_NOTICE("You hear an annoying voice in the back of your head. The things it keeps reminding you of are:") + for(var/thing in instructions) + . += "- [thing]" + . = jointext(., "
          ") + +/obj/item/implant/imprinting/disable(time) + . = ..() + if(. && brainwashing)//add deactivate and reactivate messages? + show_deactivate_message() + +/obj/item/implant/imprinting/restore() + . = ..() + if(. && brainwashing) + to_chat(imp_in, get_instructions()) + activate() + +/obj/item/implant/imprinting/activate() + if(malfunction || !implanted || imp_in) + return + var/instruction = pick(instructions) + if(brainwashing) + instruction = SPAN_WARNING("You recall one of your beliefs: \"[instruction]\"") + else + instruction = SPAN_NOTICE("You remember suddenly: \"[instruction]\"") + to_chat(imp_in, instruction) + addtimer(CALLBACK(src, PROC_REF(activate)), 5 MINUTES, (TIMER_UNIQUE|TIMER_OVERRIDE)) + +/obj/item/implant/imprinting/removed() + if(brainwashing && !malfunction) + show_deactivate_message() + ..() + +/obj/item/implant/imprinting/emp_act(severity) + var/power = 4 - severity + if(prob(power * 15)) + meltdown() + else if(prob(power * 40)) + disable(rand(power*10 SECONDS,power*100 SECONDS))//a few precious seconds of freedom + +/obj/item/implant/imprinting/proc/show_deactivate_message() + to_chat(imp_in, SPAN_WARNING("A wave of nausea comes over you.")) + to_chat(imp_in, SPAN_GOOD("You are no longer so sure of those beliefs you've had...")) + +/obj/item/implant/imprinting/meltdown() + if(brainwashing && !malfunction)//if it's already broken don't send the message again + show_deactivate_message() + . = ..() + +/obj/item/implant/imprinting/can_implant(mob/living/victim, mob/living/user, target_zone) + var/mob/living/human/human_victim = victim + if(istype(human_victim)) + var/obj/item/organ/internal/victim_brain = GET_INTERNAL_ORGAN(human_victim, BP_BRAIN) + if(!victim_brain || human_victim.isSynthetic()) + to_chat(user, SPAN_WARNING("\The [human_victim] cannot be imprinted.")) + return FALSE + if(!(victim_brain.parent_organ == check_zone(target_zone, human_victim))) + to_chat(user, SPAN_WARNING("\The [src] must be implanted in [GET_EXTERNAL_ORGAN(human_victim, victim_brain.parent_organ)].")) + return FALSE + return TRUE + +/obj/item/implanter/imprinting + name = "imprinting implanter" + imp = /obj/item/implant/imprinting + +/obj/item/implantcase/imprinting + name = "glass case - 'imprinting'" + imp = /obj/item/implant/imprinting \ No newline at end of file diff --git a/code/modules/implants/implant_types/loyalty.dm b/code/modules/implants/implant_types/loyalty.dm new file mode 100644 index 000000000000..e373a0e53abd --- /dev/null +++ b/code/modules/implants/implant_types/loyalty.dm @@ -0,0 +1,41 @@ +/obj/item/implant/loyalty + name = "loyalty implant" + desc = "Contains a small pod of nanobots that manipulate the host's mental functions. Personnel injected with this device tend to be much more loyal to the company." + origin_tech = @'{"materials":1,"biotech":2,"esoteric":3}' + known = TRUE // identifiable by scanners + +/obj/item/implant/loyalty/get_data() + return {" + Implant Specifications:
          + Name: [global.using_map.company_name] Employee Management Implant
          + Life: Ten years.
          + Important Notes: Personnel injected with this device tend to be much more loyal to the company.
          +
          + Implant Details:
          + Function: Contains a small pod of nanobots that manipulate the host's mental functions.
          + Special Features: Will prevent and cure most forms of brainwashing.
          + Integrity: Implant will last so long as the nanobots are inside the bloodstream."} + +/obj/item/implant/loyalty/implanted(mob/living/victim) + if(!ishuman(victim)) + return FALSE + var/decl/special_role/antag_data = GET_DECL(victim.mind?.assigned_special_role) + if(istype(antag_data) && (antag_data.flags & ANTAG_IMPLANT_IMMUNE)) + victim.visible_message( + "\The [victim] seems to resist the implant!", + SPAN_WARNING("You feel the corporate tendrils of [global.using_map.company_name] try to invade your mind!") + ) + return FALSE + else + clear_antag_roles(victim.mind, implanted = TRUE) + to_chat(victim, SPAN_NOTICE("You feel a surge of loyalty towards [global.using_map.company_name].")) + BITSET(victim.hud_updateflag, IMPLOYAL_HUD) + return TRUE + +/obj/item/implanter/loyalty + name = "implanter-loyalty" + imp = /obj/item/implant/loyalty + +/obj/item/implantcase/loyalty + name = "glass case - 'loyalty'" + imp = /obj/item/implant/loyalty \ No newline at end of file diff --git a/code/modules/implants/implant_types/tracking.dm b/code/modules/implants/implant_types/tracking.dm new file mode 100644 index 000000000000..eac7218ef8a8 --- /dev/null +++ b/code/modules/implants/implant_types/tracking.dm @@ -0,0 +1,57 @@ +var/global/list/tracking_implants = list() + +/obj/item/implant/tracking + name = "tracking implant" + desc = "Track with this." + origin_tech = @'{"materials":1,"biotech":2,"wormholes":2}' + known = TRUE + var/id = 1 + +/obj/item/implant/tracking/Initialize(ml, material_key) + . = ..() + global.tracking_implants += src + +/obj/item/implant/tracking/Destroy() + global.tracking_implants -= src + . = ..() + +/obj/item/implant/tracking/get_data() + . = {"Implant Specifications:
          + Name: Tracking Beacon
          + Life: 10 minutes after death of host
          + Important Notes: None
          +
          + Implant Details:
          + Function: Continuously transmits low power signal. Useful for tracking.
          + Special Features:
          + Neuro-Safe- Specialized shell absorbs excess voltages self-destructing the chip if + a malfunction occurs thereby securing safety of subject. The implant will melt and + disintegrate into bio-safe elements.
          + Integrity: Gradient creates slight risk of being overcharged and frying the + circuitry. As a result neurotoxins can cause massive damage.
          "} + if(!malfunction) + .+= {"ID (1-100):
          + - + - [id] + + + +
          "} + +/obj/item/implant/tracking/OnTopic(mob/user, href_list, datum/topic_state/state) + if (href_list["tracking_id"]) + id = clamp(id+text2num(href_list["tracking_id"]), 1, 100) + return TOPIC_REFRESH + return TOPIC_NOACTION + +/obj/item/implant/tracking/islegal() + return TRUE + +/obj/item/implant/tracking/emp_act(severity) + var/power = 4 - severity + if(prob(power * 15)) + meltdown() + else if(prob(power * 40)) + disable(rand(power*50 SECONDS,power*500 SECONDS))//adds in extra time because this is the only other way to sabotage it + +/obj/item/implantcase/tracking + name = "glass case - 'tracking'" + imp = /obj/item/implant/tracking \ No newline at end of file diff --git a/code/modules/implants/implant_types/translator.dm b/code/modules/implants/implant_types/translator.dm new file mode 100644 index 000000000000..0dbcc41231d8 --- /dev/null +++ b/code/modules/implants/implant_types/translator.dm @@ -0,0 +1,46 @@ +//Implant that lets you learn languages by hearing them +/obj/item/implant/translator + name = "babel implant" + desc = "A small implant with a microphone on it." + icon_state = "implant_evil" + origin_tech = @'{"materials":1,"biotech":2,"esoteric":3}' + hidden = TRUE + var/list/languages = list() + var/learning_threshold = 20 //need to hear language spoken this many times to learn it + var/max_languages = 5 + +/obj/item/implant/translator/get_data() + return "WARNING: No match found in the database." + +/obj/item/implant/translator/Initialize() + . = ..() + global.listening_objects += src + +/obj/item/implant/translator/hear_talk(mob/speaker, msg, verb, decl/language/speaking) + if(!imp_in) + return + if(length(languages) == max_languages) + return + languages[speaking.name] += 1 + if(!imp_in.say_understands(speaker, speaking) && languages[speaking.name] > learning_threshold) + to_chat(imp_in, SPAN_NOTICE("You feel like you can understand [speaking.name] now...")) + imp_in.add_language(speaking.type) + +/obj/item/implant/translator/implanted(mob/target) + return TRUE + +/obj/item/implant/translator/Destroy() + removed() + return ..() + +/obj/item/implanter/translator + name = "babel implanter" + imp = /obj/item/implant/translator + +/obj/item/implant/translator/natural + name = "lingophagic node" + desc = "A chunk of what could be discolored crystallized brain matter. It seems to pulse occasionally." + icon_state = "implant_melted" + origin_tech = @'{"biotech":5}' + learning_threshold = 10 + max_languages = 3 \ No newline at end of file diff --git a/code/modules/implants/implant_types/uplink.dm b/code/modules/implants/implant_types/uplink.dm new file mode 100644 index 000000000000..40574a97529f --- /dev/null +++ b/code/modules/implants/implant_types/uplink.dm @@ -0,0 +1,35 @@ +/obj/item/implant/uplink + name = "uplink implant" + desc = "Summon things." + origin_tech = @'{"materials":1,"biotech":2,"esoteric":3}' + hidden = TRUE + var/activation_emote + +/obj/item/implant/uplink/Initialize(mapload, var/amount) + amount = amount || IMPLANT_TELECRYSTAL_AMOUNT(DEFAULT_TELECRYSTAL_AMOUNT) + hidden_uplink = new(src, null, amount) + . = ..() + +/obj/item/implant/uplink/implanted(mob/source) + var/emote_options = list("blink", "blink_r", "eyebrow", "chuckle", "twitch_v", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") + activation_emote = source.client ? (input(source, "Choose activation emote:", "Uplink Implant Setup") in emote_options) : emote_options[1] + var/activation_string = "can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate." + source.StoreMemory("\A [src] [activation_string]", /decl/memory_options/system) + to_chat(source, "\The [src] [activation_string]") + hidden_uplink.uplink_owner = source.mind + return TRUE + +/obj/item/implant/uplink/trigger(emote, mob/source) + if(hidden_uplink && usr == source && !malfunction) // Let's not have another people activate our uplink + hidden_uplink.check_trigger(source, emote, activation_emote) + +/obj/item/implant/uplink/emp_act(severity) + var/power = 4 - severity + if(prob(power)) + meltdown() + else if(prob(power * 40)) + disable(rand(power*100,power*1000)) + +/obj/item/implanter/uplink + name = "implanter (U)" + imp = /obj/item/implant/uplink diff --git a/code/modules/implants/implantcase.dm b/code/modules/implants/implantcase.dm new file mode 100644 index 000000000000..2714c948265f --- /dev/null +++ b/code/modules/implants/implantcase.dm @@ -0,0 +1,81 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/implantcase + name = "glass case" + desc = "A case containing an implant." + icon = 'icons/obj/items/implant/implantcase.dmi' + icon_state = "implantcase-0" + item_state = "implantcase" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + var/obj/item/implant/imp = null + +/obj/item/implantcase/Initialize() + . = ..() + if(ispath(imp)) + imp = new imp(src) + update_description() + update_icon() + +/obj/item/implantcase/Destroy() + QDEL_NULL(imp) + . = ..() + +/obj/item/implantcase/proc/update_description() + if (imp) + desc = "A case containing \a [imp]." + origin_tech = imp.get_origin_tech() + else + desc = "A case for implants." + origin_tech = null + +/obj/item/implantcase/on_update_icon() + . = ..() + if (imp) + icon_state = "implantcase-[imp.implant_color]" + else + icon_state = "implantcase-0" + +// TODO: the name stuff here probably doesn't work, this needs an update_name override +/obj/item/implantcase/attackby(obj/item/used_item, mob/user) + if (IS_PEN(used_item)) + var/label = input(user, "What would you like the label to be?", src.name, null) + // As input() blocks, we need to do some sanity checks + if (user.get_active_held_item() != used_item) + return TRUE + if(!CanPhysicallyInteract(user)) + return TRUE + label = sanitize_safe(label, MAX_NAME_LEN) + if(label) + SetName("glass case - '[label]'") + desc = "A case containing \a [label] implant." + else + SetName(initial(name)) + desc = "A case containing an implant." + return TRUE + else if(istype(used_item, /obj/item/chems/syringe) && istype(imp,/obj/item/implant/chem)) + return imp.attackby(used_item,user) + else if (istype(used_item, /obj/item/implanter)) + var/obj/item/implanter/M = used_item + if (M.imp && !imp && !M.imp.implanted) + M.imp.forceMove(src) + imp = M.imp + M.imp = null + else if (imp && !M.imp) + imp.forceMove(M) + M.imp = src.imp + imp = null + update_description() + update_icon() + M.update_icon() + return TRUE + else if (istype(used_item, /obj/item/implant) && user.try_unequip(used_item, src)) + to_chat(user, SPAN_NOTICE("You slide \the [used_item] into \the [src].")) + imp = used_item + update_description() + update_icon() + return TRUE + return ..() \ No newline at end of file diff --git a/code/modules/implants/implanter.dm b/code/modules/implants/implanter.dm new file mode 100644 index 000000000000..6ca6d7a546b0 --- /dev/null +++ b/code/modules/implants/implanter.dm @@ -0,0 +1,86 @@ +/obj/item/implanter + name = "implanter" + icon = 'icons/obj/items/implant/implanter.dmi' + icon_state = "implanter0" + item_state = "syringe_0" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + var/obj/item/implant/imp = null + +/obj/item/implanter/Initialize() + . = ..() + if(ispath(imp)) + imp = new imp(src) + update_icon() + +/obj/item/implanter/Destroy() + QDEL_NULL(imp) + . = ..() + +/obj/item/implanter/on_update_icon() + . = ..() + icon_state = "implanter[imp == TRUE]" + +/obj/item/implanter/verb/remove_implant() + set category = "Object" + set name = "Remove implant" + set src in usr + + if(issilicon(usr)) + return + + if(can_use(usr)) + if(!imp) + to_chat(usr, "There is no implant to remove.") + return + imp.forceMove(get_turf(src)) + usr.put_in_hands(imp) + to_chat(usr, "You remove \the [imp] from \the [src].") + name = "implanter" + imp = null + update_icon() + return + else + to_chat(usr, "You cannot do this in your current condition.") + +/obj/item/implanter/proc/can_use() + + if(!ismob(loc)) + return 0 + + var/mob/M = loc + + if(M.incapacitated()) + return 0 + if((src in M.contents) || (isturf(loc) && in_range(src, M))) + return 1 + return 0 + +/obj/item/implanter/attackby(obj/item/used_item, mob/user) + if(!imp && istype(used_item, /obj/item/implant) && user.try_unequip(used_item,src)) + to_chat(usr, SPAN_NOTICE("You slide \the [used_item] into \the [src].")) + imp = used_item + update_icon() + return TRUE + return ..() + +/obj/item/implanter/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(ishuman(target) && user && imp) + user.visible_message(SPAN_DANGER("\The [user] is attemping to implant \the [target].")) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(target) + var/target_zone = user.get_target_zone() + if(imp.can_implant(target, user, target_zone)) + var/imp_name = imp.name // cache this in case implanting it changes its name + if(do_after(user, 5 SECONDS, target) && imp.implant_in_mob(target, user, target_zone)) + user.visible_message(SPAN_NOTICE("\The [target] has been implanted by \the [user].")) + admin_attack_log(user, target, "Implanted using \the [src] ([imp_name])", "Implanted with \the [src] ([imp_name])", "used an implanter, \the [src] ([imp_name]), on") + imp = null + update_icon() + return TRUE + + return ..() diff --git a/code/modules/implants/implantpad.dm b/code/modules/implants/implantpad.dm new file mode 100644 index 000000000000..db7bb8fbc41f --- /dev/null +++ b/code/modules/implants/implantpad.dm @@ -0,0 +1,62 @@ +/obj/item/implantpad + name = "implant pad" + desc = "Used to reprogram implants." + icon = 'icons/obj/items/implant/implantpad.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/steel + var/obj/item/implant/imp + +/obj/item/implantpad/on_update_icon() + . = ..() + if(imp) + add_overlay("[icon_state]-imp") + +/obj/item/implantpad/attack_hand(mob/user) + if(!imp || !(src in user.get_held_items()) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + user.put_in_active_hand(imp) + imp.add_fingerprint(user) + add_fingerprint(user) + imp = null + update_icon() + return TRUE + +/obj/item/implantpad/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/implantcase)) + var/obj/item/implantcase/case = used_item + if(!imp && case.imp) + case.imp.forceMove(src) + imp = case.imp + case.imp = null + else if (imp && !case.imp) + imp.forceMove(case) + case.imp = imp + imp = null + case.update_icon() + . = TRUE + else if(istype(used_item, /obj/item/implanter)) + var/obj/item/implanter/implanter = used_item + if(!imp && implanter.imp) + implanter.imp.forceMove(src) + imp = implanter.imp + implanter.imp = null + else if (imp && !implanter.imp) + imp.forceMove(implanter) + implanter.imp = imp + imp = null + implanter.update_icon() + . = TRUE + else if(istype(used_item, /obj/item/implant) && user.try_unequip(used_item, src)) + imp = used_item + . = TRUE + if(.) + update_icon() + return TRUE + return ..() + +/obj/item/implantpad/attack_self(mob/user) + if (imp) + imp.interact(user) + else + to_chat(user,SPAN_WARNING("There's no implant loaded in \the [src].")) \ No newline at end of file diff --git a/code/modules/inertial_damper/inertial_damper.dm b/code/modules/inertial_damper/inertial_damper.dm deleted file mode 100644 index de355d7d015f..000000000000 --- a/code/modules/inertial_damper/inertial_damper.dm +++ /dev/null @@ -1,207 +0,0 @@ -#define WARNING_DELAY 80 //seconds between warnings. -var/list/ship_inertial_dampers = list() - -/datum/ship_inertial_damper - var/name = "ship inertial damper" - var/obj/machinery/holder - -/datum/ship_inertial_damper/proc/get_damping_strength(var/reliable) - return 0 - -/datum/ship_inertial_damper/New(var/obj/machinery/_holder) - ..() - holder = _holder - global.ship_inertial_dampers += src - -/datum/ship_inertial_damper/Destroy() - global.ship_inertial_dampers -= src - for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.ships) - S.inertial_dampers -= src - holder = null - . = ..() - -/obj/machinery/inertial_damper - name = "inertial damper" - icon = 'icons/obj/machines/inertial_damper.dmi' - desc = "An inertial damper, a very large machine that balances against engine thrust to prevent harm to the crew." - density = TRUE - icon_state = "damper_on" - - base_type = /obj/machinery/inertial_damper - construct_state = /decl/machine_construction/default/panel_closed - wires = /datum/wires/inertial_damper - uncreated_component_parts = null - stat_immune = FALSE - - idle_power_usage = 1 KILOWATTS - use_power = POWER_USE_ACTIVE - anchored = TRUE - - pixel_x = -32 - pixel_y = -32 - bound_x = -32 - bound_y = -32 - - var/datum/ship_inertial_damper/controller - - var/active = TRUE - - var/damping_strength = 1 //units of Gm/h - var/damping_modifier = 0 //modifier due to events - var/target_strength = 1 - var/delta = 0.01 - var/max_strength = 5 - var/power_draw - var/max_power_draw = 200 KILOWATTS - var/lastwarning = 0 - var/warned = FALSE - - var/was_reset = FALSE //if this inertial damper was fully turned off recently (zero damping strength, no power) - - var/hacked = FALSE - var/locked = FALSE - var/ai_control_disabled = FALSE - var/input_cut = FALSE - - var/current_overlay = null - var/width = 3 - var/height = 2 - -/obj/machinery/inertial_damper/Initialize() - . = ..() - SetBounds() - update_nearby_tiles(locs) - controller = new(src) - - for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.ships) - if(S.check_ownership(src)) - S.inertial_dampers |= controller - - src.overlays += "activated" - -/obj/machinery/inertial_damper/Process() - ..() - if(active && !(stat & (NOPOWER | BROKEN)) && !input_cut) - delta = initial(delta) - power_draw = (damping_strength / max_strength) * max_power_draw - change_power_consumption(power_draw, POWER_USE_ACTIVE) - - // Provide a warning if our inertial damping level is decreasing past a threshold and we haven't already warned since someone last adjusted the setting - if(!warned && damping_strength < 0.3*initial(damping_strength) && target_strength < damping_strength && lastwarning - world.timeofday >= WARNING_DELAY) - warned = TRUE - lastwarning = world.timeofday - GLOB.global_announcer.autosay("WARNING: Inertial dampening level dangerously low! All crew must be secured before firing thrusters!", "inertial damper Monitor") - else - delta = initial(delta) * 5 // rate of dampening strength decay is higher if we have no power - target_strength = 0 - if(!damping_strength) - damping_modifier = initial(damping_modifier) - was_reset = TRUE - change_power_consumption(0, POWER_USE_OFF) - - queue_icon_update() - - if(damping_strength != target_strength) - damping_strength = damping_strength > target_strength ? max(damping_strength - delta, target_strength) : min(damping_strength + delta, target_strength) - -/obj/machinery/inertial_damper/Destroy() - QDEL_NULL(controller) - update_nearby_tiles(locs) - ..() - -/obj/machinery/inertial_damper/proc/toggle() - active = !active - update_icon() - return active - -/obj/machinery/inertial_damper/proc/is_on() - return active - -/obj/machinery/inertial_damper/proc/get_damping_strength(var/reliable) - if(hacked && !reliable) - return initial(damping_strength) - return damping_strength + damping_modifier - -/obj/machinery/inertial_damper/proc/get_status() - return active ? "on" : "off" - -/obj/machinery/inertial_damper/on_update_icon() - ..() - icon_state = "damper_[get_status()]" - - var/overlay_state = null - if(!active && damping_strength == 0) - overlay_state = null //inactive and powered off - else if(damping_strength < initial(damping_strength)) - if(target_strength != damping_strength) - overlay_state = "startup" //lower than default strength and changing - else - overlay_state = "weak" //met our target but lower than default strength - else if(target_strength > damping_strength && damping_strength >= initial(damping_strength)) - overlay_state = "activating" //rising higher than default strength - else - overlay_state = "activated" //met our target higher than default strength - - if(overlay_state != current_overlay) - overlays.Cut() - if(overlay_state) - var/image/new_overlay_state = image(icon, overlay_state) - new_overlay_state.appearance_flags |= RESET_COLOR - overlays += new_overlay_state - current_overlay = overlay_state - -/obj/machinery/inertial_damper/proc/SetBounds() - bound_width = width * world.icon_size - bound_height = height * world.icon_size - -/obj/machinery/inertial_damper/interface_interact(var/mob/user) - ui_interact(user) - return TRUE - -/obj/machinery/inertial_damper/CanUseTopic(var/mob/user) - if(issilicon(user) && !Adjacent(user) && ai_control_disabled) - return STATUS_UPDATE - return ..() - -/obj/machinery/inertial_damper/OnTopic(user, href_list, datum/topic_state/state) - if(locked) - to_chat(user, SPAN_WARNING("\The [src]'s controls are not responding.")) - return TOPIC_NOACTION - - if(href_list["toggle"]) - toggle() - return TOPIC_REFRESH - - if(href_list["set_strength"]) - var/new_strength = input("Enter a new damper strength between 0 and [max_strength] Gm/h", "Modifying damper strength", get_damping_strength(TRUE)) as num - if(!(new_strength in 0 to max_strength)) - to_chat(user, SPAN_WARNING("That's not a valid damper strength.")) - warned = FALSE - return TOPIC_NOACTION - - warned = FALSE - target_strength = Clamp(new_strength, 0, max_strength) - return TOPIC_REFRESH - - return TOPIC_NOACTION - -/obj/machinery/inertial_damper/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - data["online"] = is_on() - data["damping_strength"] = round(get_damping_strength(TRUE), 0.01) - data["max_strength"] = max_strength - data["hacked"] = hacked - data["power_usage"] = round(power_draw/1e3) - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "inertial_damper.tmpl", "Inertial Damper", 400, 400) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/inertial_damper/dismantle() - if((. = ..())) - update_nearby_tiles(locs) - -#undef WARNING_DELAY \ No newline at end of file diff --git a/code/modules/integrated_electronics/_defines.dm b/code/modules/integrated_electronics/_defines.dm deleted file mode 100644 index a2f4aa190abf..000000000000 --- a/code/modules/integrated_electronics/_defines.dm +++ /dev/null @@ -1,5 +0,0 @@ -#define IC_TOPIC_UNHANDLED 0 -#define IC_TOPIC_HANDLED 1 -#define IC_TOPIC_REFRESH 2 -#define IC_FLAG_ANCHORABLE 1 -#define IC_FLAG_CAN_FIRE 2 \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/analyzer.dm b/code/modules/integrated_electronics/core/analyzer.dm deleted file mode 100644 index 3c6341aa1363..000000000000 --- a/code/modules/integrated_electronics/core/analyzer.dm +++ /dev/null @@ -1,23 +0,0 @@ -/obj/item/integrated_electronics/analyzer - name = "circuit analyzer" - desc = "This tool can scan an assembly and generate code necessary to recreate it in a circuit printer." - icon = 'icons/obj/assemblies/electronic_tools.dmi' - icon_state = "analyzer" - obj_flags = OBJ_FLAG_CONDUCTIBLE - w_class = ITEM_SIZE_SMALL - material = /decl/material/solid/metal/aluminium - matter = list( - /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE - ) - -/obj/item/integrated_electronics/analyzer/afterattack(var/atom/A, var/mob/living/user) - . = ..() - if(istype(A, /obj/item/electronic_assembly)) - var/saved = "[A.name] analyzed! On circuit printers with cloning enabled, you may use the code below to clone the circuit:

          [SScircuit.save_electronic_assembly(A)]" - if(saved) - to_chat(user, "You scan [A].") - show_browser(user, saved, "window=circuit_scan;size=500x600;border=1;can_resize=1;can_close=1;can_minimize=1") - else - to_chat(user, "[A] is not complete enough to be encoded!") diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm deleted file mode 100644 index 382b6dbf9da0..000000000000 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ /dev/null @@ -1,749 +0,0 @@ -#define IC_MAX_SIZE_BASE 25 -#define IC_COMPLEXITY_BASE 75 - -/obj/item/electronic_assembly - name = "electronic assembly" - desc = "It's a case, for building small electronics with." - w_class = ITEM_SIZE_SMALL - icon = 'icons/obj/assemblies/electronic_setups.dmi' - icon_state = "setup_small" - item_flags = ITEM_FLAG_NO_BLUDGEON - matter = list() // To be filled later - var/list/assembly_components = list() - var/list/ckeys_allowed_to_scan = list() // Players who built the circuit can scan it as a ghost. - var/max_components = IC_MAX_SIZE_BASE - var/max_complexity = IC_COMPLEXITY_BASE - var/opened = TRUE - var/obj/item/cell/battery // Internal cell which most circuits need to work. - var/cell_type = /obj/item/cell - var/can_charge = TRUE //Can it be charged in a recharger? - var/circuit_flags = IC_FLAG_ANCHORABLE - var/charge_sections = 4 - var/charge_delay = 4 - var/ext_next_use = 0 - var/weakref/collw - var/allowed_circuit_action_flags = IC_ACTION_COMBAT | IC_ACTION_LONG_RANGE //which circuit flags are allowed - var/creator // circuit creator if any - var/static/next_assembly_id = 0 - var/interact_page = 0 - var/components_per_page = 5 - health = 30 - pass_flags = 0 - anchored = FALSE - var/detail_color = COLOR_ASSEMBLY_BLACK - var/list/color_whitelist = list( //This is just for checking that hacked colors aren't in the save data. - COLOR_ASSEMBLY_BLACK, - COLOR_GRAY40, - COLOR_ASSEMBLY_BGRAY, - COLOR_ASSEMBLY_WHITE, - COLOR_ASSEMBLY_RED, - COLOR_ASSEMBLY_ORANGE, - COLOR_ASSEMBLY_BEIGE, - COLOR_ASSEMBLY_BROWN, - COLOR_ASSEMBLY_GOLD, - COLOR_ASSEMBLY_YELLOW, - COLOR_ASSEMBLY_GURKHA, - COLOR_ASSEMBLY_LGREEN, - COLOR_ASSEMBLY_GREEN, - COLOR_ASSEMBLY_LBLUE, - COLOR_ASSEMBLY_BLUE, - COLOR_ASSEMBLY_PURPLE - ) - -/obj/item/electronic_assembly/examine(mob/user) - . = ..() - if(IC_FLAG_ANCHORABLE & circuit_flags) - to_chat(user, "The anchoring bolts [anchored ? "are" : "can be"] wrenched in place and the maintenance panel [opened ? "can be" : "is"] screwed in place.") - else - to_chat(user, "The maintenance panel [opened ? "can be" : "is"] screwed in place.") - if(health != initial(health)) - if(health <= initial(health)/2) - to_chat(user,"It looks pretty beat up.") - else - to_chat(user, "Its got a few dents in it.") - - if((isobserver(user) && ckeys_allowed_to_scan[user.ckey]) || check_rights(R_ADMIN, 0, user)) - to_chat(user, "You can scan this circuit."); - - -/obj/item/electronic_assembly/proc/take_damage(var/amnt) - health = health - amnt - if(health <= 0) - visible_message("\The [src] falls to pieces!") - qdel(src) - else if(health < initial(health)*0.15 && prob(5)) - visible_message("\The [src] starts to break apart!") - - -/obj/item/electronic_assembly/proc/check_interactivity(mob/user) - return (!user.incapacitated() && CanUseTopic(user)) - -/obj/item/electronic_assembly/GetAccess() - . = list() - for(var/obj/item/integrated_circuit/output/O in assembly_components) - var/o_access = O.GetAccess() - . |= o_access - -/obj/item/electronic_assembly/Bump(atom/AM) - collw = weakref(AM) - .=..() - if(istype(AM, /obj/machinery/door/airlock) || istype(AM, /obj/machinery/door/window)) - var/obj/machinery/door/D = AM - if(D.check_access(src)) - D.open() - -/obj/item/electronic_assembly/create_matter() - ..() - LAZYSET(matter, /decl/material/solid/metal/steel, round((max_complexity + max_components) / 4) * SScircuit.cost_multiplier) - -/obj/item/electronic_assembly/Initialize() - . = ..() - START_PROCESSING(SScircuit, src) - -/obj/item/electronic_assembly/Destroy() - STOP_PROCESSING(SScircuit, src) - for(var/circ in assembly_components) - remove_component(circ) - qdel(circ) - return ..() - -/obj/item/electronic_assembly/Process() - // First we generate power. - for(var/obj/item/integrated_circuit/passive/power/P in assembly_components) - P.make_energy() - - var/power_failure = FALSE - if(initial(health)/health < 0.5 && prob(5)) - visible_message("\The [src] shudders and sparks") - power_failure = TRUE - // Now spend it. - for(var/I in assembly_components) - var/obj/item/integrated_circuit/IC = I - if(IC.power_draw_idle) - if(power_failure || !draw_power(IC.power_draw_idle)) - IC.power_fail() - -/obj/item/electronic_assembly/MouseDrop_T(atom/dropping, mob/user) - if(user == dropping) - interact(user) - else - ..() - -/obj/item/electronic_assembly/interact(mob/user) - if(!check_interactivity(user)) - return - - if(opened) - open_interact(user) - closed_interact(user) - -/obj/item/electronic_assembly/proc/closed_interact(mob/user) - var/HTML = list() - HTML += "[src.name]" - HTML += "
          \[Refresh\]" - HTML += "

          " - - var/listed_components = FALSE - for(var/obj/item/integrated_circuit/circuit in contents) - var/list/topic_data = circuit.get_topic_data(user) - if(topic_data) - listed_components = TRUE - HTML += "[circuit.displayed_name]: " - if(topic_data.len != 1) - HTML += "
          " - for(var/entry in topic_data) - var/href = topic_data[entry] - if(href) - HTML += "[entry]" - else - HTML += entry - HTML += "
          " - HTML += "
          " - HTML += "" - - if(listed_components) - show_browser(user, jointext(HTML,null), "window=closed-assembly-\ref[src];size=600x350;border=1;can_resize=1;can_close=1;can_minimize=1") - - -/obj/item/electronic_assembly/proc/open_interact(mob/user) - var/total_part_size = return_total_size() - var/total_complexity = return_total_complexity() - var/list/HTML = list() - - HTML += "[name]" - - HTML += "\[Refresh\] | \[Rename\]
          " - HTML += "[total_part_size]/[max_components] space taken up in the assembly.
          " - HTML += "[total_complexity]/[max_complexity] complexity in the assembly.
          " - if(battery) - HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. \[Remove\]" - else - HTML += "No power cell detected!" - - if(length(assembly_components)) - HTML += "

          " - HTML += "Components:
          " - - var/start_index = ((components_per_page * interact_page) + 1) - for(var/i = start_index to min(length(assembly_components), start_index + (components_per_page - 1))) - var/obj/item/integrated_circuit/circuit = assembly_components[i] - HTML += "\[ [i] \] | " - HTML += "\[R\] | " - if(circuit.removable) - HTML += "\[-\] | " - else - HTML += "\[-\] | " - HTML += "[circuit.displayed_name]" - HTML += "
          " - - if(length(assembly_components) > components_per_page) - HTML += "
          \[" - for(var/i = 1 to ceil(length(assembly_components)/components_per_page)) - if((i-1) == interact_page) - HTML += " [i]" - else - HTML += " [i]" - HTML += " \]" - - HTML += "" - show_browser(user, jointext(HTML, null), "window=assembly-\ref[src];size=655x350;border=1;can_resize=1;can_close=1;can_minimize=1") - -/obj/item/electronic_assembly/Topic(href, href_list) - if(href_list["ghostscan"]) - if((isobserver(usr) && ckeys_allowed_to_scan[usr.ckey]) || check_rights(R_ADMIN,0,usr)) - if(assembly_components.len) - var/saved = "On circuit printers with cloning enabled, you may use the code below to clone the circuit:

          [SScircuit.save_electronic_assembly(src)]" - show_browser(usr, saved, "window=circuit_scan;size=500x600;border=1;can_resize=1;can_close=1;can_minimize=1") - else - to_chat(usr, "The circuit is empty!") - return 0 - - if(isobserver(usr)) - return - - if(!check_interactivity(usr)) - return 0 - - if(href_list["select_page"]) - interact_page = text2num(href_list["select_page"]) - - if(href_list["rename"]) - rename(usr) - - if(href_list["remove_cell"]) - if(!battery) - to_chat(usr, "There's no power cell to remove from \the [src].") - else - battery.dropInto(loc) - playsound(src, 'sound/items/Crowbar.ogg', 50, 1) - to_chat(usr, "You pull \the [battery] out of \the [src]'s power supplier.") - battery = null - - if(href_list["component"]) - var/obj/item/integrated_circuit/component = locate(href_list["component"]) in assembly_components - if(component) - // Builtin components are not supposed to be removed or rearranged - if(!component.removable) - return 0 - - add_allowed_scanner(usr.ckey) - - var/current_pos = assembly_components.Find(component) - - if(href_list["remove"]) - try_remove_component(component, usr) - - else - // Adjust the position - if(href_list["set_slot"]) - var/selected_slot = input("Select a new slot", "Select slot", current_pos) as null|num - if(!check_interactivity(usr)) - return 0 - if(selected_slot < 1 || selected_slot > length(assembly_components)) - return 0 - - assembly_components.Remove(component) - assembly_components.Insert(selected_slot, component) - - - interact(usr) // To refresh the UI. - -/obj/item/electronic_assembly/proc/rename() - var/mob/M = usr - if(!check_interactivity(M)) - return - var/input = input("What do you want to name this?", "Rename", src.name) as null|text - input = sanitizeName(input,allow_numbers = 1) - if(!check_interactivity(M)) - return - if(!QDELETED(src) && input) - to_chat(M, "The machine now has a label reading '[input]'.") - name = input - -/obj/item/electronic_assembly/proc/add_allowed_scanner(ckey) - ckeys_allowed_to_scan[ckey] = TRUE - -/obj/item/electronic_assembly/proc/can_move() - return FALSE - -/obj/item/electronic_assembly/on_update_icon() - if(opened) - icon_state = initial(icon_state) + "-open" - else - icon_state = initial(icon_state) - overlays.Cut() - if(detail_color == COLOR_ASSEMBLY_BLACK) //Black colored overlay looks almost but not exactly like the base sprite, so just cut the overlay and avoid it looking kinda off. - return - var/image/detail_overlay = image('icons/obj/assemblies/electronic_setups.dmi', src,"[icon_state]-color") - detail_overlay.color = detail_color - overlays += detail_overlay - -/obj/item/electronic_assembly/examine(mob/user) - . = ..() - for(var/I in assembly_components) - var/obj/item/integrated_circuit/IC = I - IC.external_examine(user) - if(opened) - IC.internal_examine(user) - if(opened) - interact(user) - -//This only happens when this EA is loaded via the printer -/obj/item/electronic_assembly/proc/post_load() - for(var/I in assembly_components) - var/obj/item/integrated_circuit/IC = I - IC.on_data_written() - -/obj/item/electronic_assembly/proc/return_total_complexity() - . = 0 - var/obj/item/integrated_circuit/part - for(var/p in assembly_components) - part = p - . += part.complexity - -/obj/item/electronic_assembly/proc/return_total_size() - . = 0 - var/obj/item/integrated_circuit/part - for(var/p in assembly_components) - part = p - . += part.size - -// Returns true if the circuit made it inside. -/obj/item/electronic_assembly/proc/try_add_component(obj/item/integrated_circuit/IC, mob/user) - if(!opened) - to_chat(user, "\The [src]'s hatch is closed, you can't put anything inside.") - return FALSE - - if(IC.w_class > w_class) - to_chat(user, "\The [IC] is way too big to fit into \the [src].") - return FALSE - - var/total_part_size = return_total_size() - var/total_complexity = return_total_complexity() - - if((total_part_size + IC.size) > max_components) - to_chat(user, "You can't seem to add the '[IC]', as there's insufficient space.") - return FALSE - if((total_complexity + IC.complexity) > max_complexity) - to_chat(user, "You can't seem to add the '[IC]', since this setup's too complicated for the case.") - return FALSE - if((allowed_circuit_action_flags & IC.action_flags) != IC.action_flags) - to_chat(user, "You can't seem to add the '[IC]', since the case doesn't support the circuit type.") - return FALSE - - if(!user.unEquip(IC,src)) - return FALSE - - to_chat(user, "You slide [IC] inside [src].") - playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) - add_allowed_scanner(user.ckey) - - add_component(IC) - return TRUE - - -// Actually puts the circuit inside, doesn't perform any checks. -/obj/item/electronic_assembly/proc/add_component(obj/item/integrated_circuit/component) - component.forceMove(get_object()) - component.assembly = src - assembly_components |= component - - -/obj/item/electronic_assembly/proc/try_remove_component(obj/item/integrated_circuit/IC, mob/user, silent) - if(!opened) - if(!silent) - to_chat(user, "[src]'s hatch is closed, so you can't fiddle with the internal components.") - return FALSE - - if(!IC.removable) - if(!silent) - to_chat(user, "[src] is permanently attached to the case.") - return FALSE - - remove_component(IC) - if(!silent) - to_chat(user, "You pop \the [IC] out of the case, and slide it out.") - playsound(src, 'sound/items/crowbar.ogg', 50, 1) - user.put_in_hands(IC) - add_allowed_scanner(user.ckey) - - // Make sure we're not on an invalid page - interact_page = Clamp(interact_page, 0, ceil(length(assembly_components)/components_per_page)-1) - - return TRUE - -// Actually removes the component, doesn't perform any checks. -/obj/item/electronic_assembly/proc/remove_component(obj/item/integrated_circuit/component) - component.disconnect_all() - component.dropInto(loc) - component.assembly = null - assembly_components.Remove(component) - - -/obj/item/electronic_assembly/afterattack(atom/target, mob/user, proximity) - . = ..() - for(var/obj/item/integrated_circuit/input/S in assembly_components) - if(S.sense(target,user,proximity)) - if(proximity) - visible_message("\The [user] waves \the [src] around \the [target].") - else - visible_message("\The [user] points \the [src] towards \the [target].") - - -/obj/item/electronic_assembly/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/wrench)) - if(istype(loc, /turf) && (IC_FLAG_ANCHORABLE & circuit_flags)) - user.visible_message("\The [user] wrenches \the [src]'s anchoring bolts [anchored ? "back" : "into position"].") - playsound(get_turf(user), 'sound/items/Ratchet.ogg',50) - if(user.do_skilled(5 SECONDS, SKILL_CONSTRUCTION, src)) - anchored = !anchored - else if(istype(I, /obj/item/integrated_circuit)) - if(!user.canUnEquip(I)) - return FALSE - if(try_add_component(I, user)) - return TRUE - else - for(var/obj/item/integrated_circuit/input/S in assembly_components) - S.attackby_react(I,user,user.a_intent) - return ..() - else if(istype(I, /obj/item/multitool) || istype(I, /obj/item/integrated_electronics/wirer) || istype(I, /obj/item/integrated_electronics/debugger)) - if(opened) - interact(user) - return TRUE - else - to_chat(user, "[src]'s hatch is closed, so you can't fiddle with the internal components.") - for(var/obj/item/integrated_circuit/input/S in assembly_components) - S.attackby_react(I,user,user.a_intent) - return ..() - else if(istype(I, /obj/item/cell)) - if(!opened) - to_chat(user, "[src]'s hatch is closed, so you can't access \the [src]'s power supplier.") - for(var/obj/item/integrated_circuit/input/S in assembly_components) - S.attackby_react(I,user,user.a_intent) - return ..() - if(battery) - to_chat(user, "[src] already has \a [battery] installed. Remove it first if you want to replace it.") - for(var/obj/item/integrated_circuit/input/S in assembly_components) - S.attackby_react(I,user,user.a_intent) - return ..() - var/obj/item/cell/cell = I - if(user.unEquip(I,loc)) - user.drop_from_inventory(I, loc) - cell.forceMove(src) - battery = cell - playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) - to_chat(user, "You slot \the [cell] inside \the [src]'s power supplier.") - return TRUE - return FALSE - else if(istype(I, /obj/item/integrated_electronics/detailer)) - var/obj/item/integrated_electronics/detailer/D = I - detail_color = D.detail_color - update_icon() - else if(istype(I, /obj/item/screwdriver)) - var/hatch_locked = FALSE - for(var/obj/item/integrated_circuit/manipulation/hatchlock/H in assembly_components) - // If there's more than one hatch lock, only one needs to be enabled for the assembly to be locked - if(H.lock_enabled) - hatch_locked = TRUE - break - - if(hatch_locked) - to_chat(user, "The screws are covered by a locking mechanism!") - return FALSE - - playsound(src, 'sound/items/Screwdriver.ogg', 25) - opened = !opened - to_chat(user, "You [opened ? "open" : "close"] the maintenance hatch of [src].") - update_icon() - else if(isCoil(I)) - var/obj/item/stack/cable_coil/C = I - if(health != initial(health) && do_after(user, 10, src) && C.use(1)) - user.visible_message("\The [user] patches up \the [src]") - health = min(initial(health), health + 5) - else - if(user.a_intent == I_HURT) // Kill it - to_chat(user, "\The [user] hits \the [src] with \the [I]") - take_damage(I.force) - else - for(var/obj/item/integrated_circuit/input/S in assembly_components) - S.attackby_react(I,user,user.a_intent) - -/obj/item/electronic_assembly/attack_self(mob/user) - interact(user) - -/obj/item/electronic_assembly/bullet_act(var/obj/item/projectile/P) - take_damage(P.damage) - -/obj/item/electronic_assembly/emp_act(severity) - . = ..() - for(var/I in src) - var/atom/movable/AM = I - AM.emp_act(severity) - -// Returns true if power was successfully drawn. -/obj/item/electronic_assembly/proc/draw_power(amount) - if(battery && battery.use(amount * CELLRATE)) - return TRUE - return FALSE - -// Ditto for giving. -/obj/item/electronic_assembly/proc/give_power(amount) - if(battery && battery.give(amount * CELLRATE)) - return TRUE - return FALSE - - -// Returns the object that is supposed to be used in attack messages, location checks, etc. -// Override in children for special behavior. -/obj/item/electronic_assembly/proc/get_object() - return src - -/obj/item/electronic_assembly/attack_hand(mob/user) - if(anchored) - attack_self(user) - return - ..() - -/obj/item/electronic_assembly/default //The /default electronic_assemblys are to allow the introduction of the new naming scheme without breaking old saves. - name = "type-a electronic assembly" - -/obj/item/electronic_assembly/calc - name = "type-b electronic assembly" - icon_state = "setup_small_calc" - desc = "It's a case, for building small electronics with. This one resembles a pocket calculator." - -/obj/item/electronic_assembly/clam - name = "type-c electronic assembly" - icon_state = "setup_small_clam" - desc = "It's a case, for building small electronics with. This one has a clamshell design." - -/obj/item/electronic_assembly/simple - name = "type-d electronic assembly" - icon_state = "setup_small_simple" - desc = "It's a case, for building small electronics with. This one has a simple design." - -/obj/item/electronic_assembly/hook - name = "type-e electronic assembly" - icon_state = "setup_small_hook" - desc = "It's a case, for building small electronics with. This one looks like it has a belt clip." - slot_flags = SLOT_BELT - -/obj/item/electronic_assembly/pda - name = "type-f electronic assembly" - icon_state = "setup_small_pda" - desc = "It's a case, for building small electronics with. This one resembles a PDA." - slot_flags = SLOT_BELT | SLOT_ID - -/obj/item/electronic_assembly/augment - name = "augment electronic assembly" - icon_state = "setup_augment" - desc = "It's a case, for building small electronics with. This one is designed to go inside a cybernetic augment." - circuit_flags = IC_FLAG_CAN_FIRE - -/obj/item/electronic_assembly/medium - name = "electronic mechanism" - icon_state = "setup_medium" - desc = "It's a case, for building medium-sized electronics with." - w_class = ITEM_SIZE_NORMAL - max_components = IC_MAX_SIZE_BASE * 2 - max_complexity = IC_COMPLEXITY_BASE * 2 - health = 20 - -/obj/item/electronic_assembly/medium/default - name = "type-a electronic mechanism" - -/obj/item/electronic_assembly/medium/box - name = "type-b electronic mechanism" - icon_state = "setup_medium_box" - desc = "It's a case, for building medium-sized electronics with. This one has a boxy design." - -/obj/item/electronic_assembly/medium/clam - name = "type-c electronic mechanism" - icon_state = "setup_medium_clam" - desc = "It's a case, for building medium-sized electronics with. This one has a clamshell design." - -/obj/item/electronic_assembly/medium/medical - name = "type-d electronic mechanism" - icon_state = "setup_medium_med" - desc = "It's a case, for building medium-sized electronics with. This one resembles some type of medical apparatus." - -/obj/item/electronic_assembly/medium/gun - name = "type-e electronic mechanism" - icon_state = "setup_medium_gun" - item_state = "circuitgun" - desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, if you're feeling optimistic. It can fire guns and throw items while the user is holding it." - circuit_flags = IC_FLAG_CAN_FIRE | IC_FLAG_ANCHORABLE - -/obj/item/electronic_assembly/medium/radio - name = "type-f electronic mechanism" - icon_state = "setup_medium_radio" - desc = "It's a case, for building medium-sized electronics with. This one resembles an old radio." - -/obj/item/electronic_assembly/large - name = "electronic machine" - icon_state = "setup_large" - desc = "It's a case, for building large electronics with." - w_class = ITEM_SIZE_LARGE - max_components = IC_MAX_SIZE_BASE * 4 - max_complexity = IC_COMPLEXITY_BASE * 4 - health = 30 - -/obj/item/electronic_assembly/large/default - name = "type-a electronic machine" - -/obj/item/electronic_assembly/large/scope - name = "type-b electronic machine" - icon_state = "setup_large_scope" - desc = "It's a case, for building large electronics with. This one resembles an oscilloscope." - -/obj/item/electronic_assembly/large/terminal - name = "type-c electronic machine" - icon_state = "setup_large_terminal" - desc = "It's a case, for building large electronics with. This one resembles a computer terminal." - -/obj/item/electronic_assembly/large/arm - name = "type-d electronic machine" - icon_state = "setup_large_arm" - desc = "It's a case, for building large electronics with. This one resembles a robotic arm." - -/obj/item/electronic_assembly/large/tall - name = "type-e electronic machine" - icon_state = "setup_large_tall" - desc = "It's a case, for building large electronics with. This one has a tall design." - -/obj/item/electronic_assembly/large/industrial - name = "type-f electronic machine" - icon_state = "setup_large_industrial" - desc = "It's a case, for building large electronics with. This one resembles some kind of industrial machinery." - -/obj/item/electronic_assembly/drone - name = "electronic drone" - icon_state = "setup_drone" - desc = "It's a case, for building mobile electronics with." - w_class = ITEM_SIZE_LARGE - max_components = IC_MAX_SIZE_BASE * 3 - max_complexity = IC_COMPLEXITY_BASE * 3 - allowed_circuit_action_flags = IC_ACTION_MOVEMENT | IC_ACTION_COMBAT | IC_ACTION_LONG_RANGE - circuit_flags = 0 - health = 50 - -/obj/item/electronic_assembly/drone/can_move() - return TRUE - -/obj/item/electronic_assembly/drone/default - name = "type-a electronic drone" - -/obj/item/electronic_assembly/drone/arms - name = "type-b electronic drone" - icon_state = "setup_drone_arms" - desc = "It's a case, for building mobile electronics with. This one is armed and dangerous." - -/obj/item/electronic_assembly/drone/secbot - name = "type-c electronic drone" - icon_state = "setup_drone_secbot" - desc = "It's a case, for building mobile electronics with. This one resembles a Securitron." - -/obj/item/electronic_assembly/drone/medbot - name = "type-d electronic drone" - icon_state = "setup_drone_medbot" - desc = "It's a case, for building mobile electronics with. This one resembles a Medibot." - -/obj/item/electronic_assembly/drone/genbot - name = "type-e electronic drone" - icon_state = "setup_drone_genbot" - desc = "It's a case, for building mobile electronics with. This one has a generic bot design." - -/obj/item/electronic_assembly/drone/android - name = "type-f electronic drone" - icon_state = "setup_drone_android" - desc = "It's a case, for building mobile electronics with. This one has a hominoid design." - -/obj/item/electronic_assembly/wallmount - name = "wall-mounted electronic assembly" - icon_state = "setup_wallmount_medium" - desc = "It's a case, for building medium-sized electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on." - w_class = ITEM_SIZE_NORMAL - max_components = IC_MAX_SIZE_BASE * 2 - max_complexity = IC_COMPLEXITY_BASE * 2 - health = 10 - -/obj/item/electronic_assembly/wallmount/afterattack(var/atom/a, var/mob/user, var/proximity) - if(proximity && istype(a ,/turf) && a.density) - mount_assembly(a,user) - -/obj/item/electronic_assembly/wallmount/heavy - name = "heavy wall-mounted electronic assembly" - icon_state = "setup_wallmount_large" - desc = "It's a case, for building large electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on." - w_class = ITEM_SIZE_LARGE - max_components = IC_MAX_SIZE_BASE * 4 - max_complexity = IC_COMPLEXITY_BASE * 4 - -/obj/item/electronic_assembly/wallmount/light - name = "light wall-mounted electronic assembly" - icon_state = "setup_wallmount_small" - desc = "It's a case, for building small electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on." - w_class = ITEM_SIZE_SMALL - max_components = IC_MAX_SIZE_BASE - max_complexity = IC_COMPLEXITY_BASE - -/obj/item/electronic_assembly/pickup() - transform = matrix() //Reset the matrix. - -/obj/item/electronic_assembly/wallmount/proc/mount_assembly(turf/on_wall, mob/user) //Yeah, this is admittedly just an abridged and kitbashed version of the wallframe attach procs. - var/ndir = get_dir(on_wall, user) - if(!(ndir in GLOB.cardinal)) - return - var/turf/T = get_turf(user) - if(T.density) - to_chat(user, "You cannot place [src] on this spot!") - return - if(gotwallitem(T, ndir)) - to_chat(user, "There's already an item on this wall!") - return - playsound(src.loc, 'sound/machines/click.ogg', 75, 1) - user.visible_message("[user.name] attaches [src] to the wall.", - "You attach [src] to the wall.", - "You hear clicking.") - if(user.unEquip(src,T)) - var/matrix/M = matrix() - switch(ndir) - if(NORTH) - pixel_y = -32 - pixel_x = 0 - M.Turn(180) - if(SOUTH) - pixel_y = 21 - pixel_x = 0 - if(EAST) - pixel_x = -27 - pixel_y = 0 - M.Turn(270) - if(WEST) - pixel_x = 27 - pixel_y = 0 - M.Turn(90) - transform = M - -#undef IC_MAX_SIZE_BASE -#undef IC_COMPLEXITY_BASE diff --git a/code/modules/integrated_electronics/core/debugger.dm b/code/modules/integrated_electronics/core/debugger.dm deleted file mode 100644 index d937e2b51e02..000000000000 --- a/code/modules/integrated_electronics/core/debugger.dm +++ /dev/null @@ -1,70 +0,0 @@ -/obj/item/integrated_electronics/debugger - name = "circuit debugger" - desc = "This small tool allows one working with custom machinery to directly set data to a specific pin, useful for writing \ - settings to specific circuits, or for debugging purposes. It can also pulse activation pins." - icon = 'icons/obj/assemblies/electronic_tools.dmi' - icon_state = "debugger" - obj_flags = OBJ_FLAG_CONDUCTIBLE - item_flags = ITEM_FLAG_NO_BLUDGEON - w_class = ITEM_SIZE_SMALL - var/data_to_write = null - var/accepting_refs = FALSE - material = /decl/material/solid/metal/aluminium - matter = list( - /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE - ) - -/obj/item/integrated_electronics/debugger/attack_self(mob/user) - var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null") - - var/new_data = null - switch(type_to_use) - if("string") - accepting_refs = FALSE - new_data = user.get_input("Now type in a string", "[src] string writing", null, MOB_INPUT_TEXT, src) - new_data = sanitize(new_data,trim = 0) - if(istext(new_data) && user.check_dexterity(DEXTERITY_KEYBOARDS)) - data_to_write = new_data - to_chat(user, "You set \the [src]'s memory to \"[new_data]\".") - if("number") - accepting_refs = FALSE - new_data = user.get_input("Now type in a number", "[src] number writing", null, MOB_INPUT_NUM, src) - if(isnum(new_data) && user.check_dexterity(DEXTERITY_KEYBOARDS)) - data_to_write = new_data - to_chat(user, "You set \the [src]'s memory to [new_data].") - if("ref") - accepting_refs = TRUE - to_chat(user, "You turn \the [src]'s ref scanner on. Slide it across \ - an object for a ref of that object to save it in memory.") - if("null") - data_to_write = null - to_chat(user, "You set \the [src]'s memory to absolutely nothing.") - -/obj/item/integrated_electronics/debugger/afterattack(atom/target, mob/living/user, proximity) - . = ..() - if(accepting_refs && proximity) - data_to_write = weakref(target) - visible_message("[user] slides \a [src]'s over \the [target].") - to_chat(user, "You set \the [src]'s memory to a reference to [target.name] \[Ref\]. The ref scanner is \ - now off.") - accepting_refs = FALSE - -/obj/item/integrated_electronics/debugger/proc/write_data(var/datum/integrated_io/io, mob/user) - if(io.io_type == DATA_CHANNEL) - io.write_data_to_pin(data_to_write) - var/data_to_show = data_to_write - if(isweakref(data_to_write)) - var/weakref/w = data_to_write - var/atom/A = w.resolve() - if(!A) - to_chat(user, "\The [src]'s reference is stale and won't transfer to \the [io.holder]'s pin.") - return - data_to_show = A.name - to_chat(user, "You write '[data_to_write ? data_to_show : "NULL"]' to the '[io]' pin of \the [io.holder].") - else if(io.io_type == PULSE_CHANNEL) - io.holder.check_then_do_work(io.ord,ignore_power = TRUE) - to_chat(user, "You pulse \the [io.holder]'s [io].") - - io.holder.interact(user) // This is to update the UI. diff --git a/code/modules/integrated_electronics/core/detailer.dm b/code/modules/integrated_electronics/core/detailer.dm deleted file mode 100644 index a14922c03899..000000000000 --- a/code/modules/integrated_electronics/core/detailer.dm +++ /dev/null @@ -1,48 +0,0 @@ -/obj/item/integrated_electronics/detailer - name = "assembly detailer" - desc = "A combination autopainter and flash anodizer designed to give electronic assemblies a colorful, wear-resistant finish." - icon = 'icons/obj/assemblies/electronic_tools.dmi' - icon_state = "detailer" - obj_flags = OBJ_FLAG_CONDUCTIBLE - item_flags = ITEM_FLAG_NO_BLUDGEON - w_class = ITEM_SIZE_SMALL - var/data_to_write = null - var/accepting_refs = FALSE - var/detail_color = COLOR_ASSEMBLY_WHITE - var/list/color_list = list( - "black" = COLOR_ASSEMBLY_BLACK, - "gray" = COLOR_GRAY40, - "machine gray" = COLOR_ASSEMBLY_BGRAY, - "white" = COLOR_ASSEMBLY_WHITE, - "red" = COLOR_ASSEMBLY_RED, - "orange" = COLOR_ASSEMBLY_ORANGE, - "beige" = COLOR_ASSEMBLY_BEIGE, - "brown" = COLOR_ASSEMBLY_BROWN, - "gold" = COLOR_ASSEMBLY_GOLD, - "yellow" = COLOR_ASSEMBLY_YELLOW, - "gurkha" = COLOR_ASSEMBLY_GURKHA, - "light green" = COLOR_ASSEMBLY_LGREEN, - "green" = COLOR_ASSEMBLY_GREEN, - "light blue" = COLOR_ASSEMBLY_LBLUE, - "blue" = COLOR_ASSEMBLY_BLUE, - "purple" = COLOR_ASSEMBLY_PURPLE - ) - -/obj/item/integrated_electronics/detailer/Initialize() - .=..() - update_icon() - -/obj/item/integrated_electronics/detailer/on_update_icon() - overlays.Cut() - var/image/detail_overlay = image('icons/obj/assemblies/electronic_tools.dmi',src, "detailer-color") - detail_overlay.color = detail_color - overlays += detail_overlay - -/obj/item/integrated_electronics/detailer/attack_self(mob/user) - var/color_choice = input(user, "Select color.", "Assembly Detailer") as null|anything in color_list - if(!color_list[color_choice]) - return - if(!in_range(src, user)) - return - detail_color = color_list[color_choice] - update_icon() diff --git a/code/modules/integrated_electronics/core/helpers.dm b/code/modules/integrated_electronics/core/helpers.dm deleted file mode 100644 index e64b77480dc0..000000000000 --- a/code/modules/integrated_electronics/core/helpers.dm +++ /dev/null @@ -1,144 +0,0 @@ -/obj/item/integrated_circuit/proc/setup_io(list/io_list, io_type, list/io_default_list, pin_type) - if(!io_list) - return - var/list/io_list_copy = io_list.Copy() - io_list.Cut() - for(var/i in 1 to io_list_copy.len) - var/io_entry = io_list_copy[i] - var/default_data = null - var/io_type_override = null - - // Override the default data. - if(length(io_default_list)) // List containing special pin types that need to be added. - default_data = io_default_list["[i]"] // This is deliberately text because the index is a number in text form. - - // Override the pin type. - if(io_list_copy[io_entry]) - io_type_override = io_list_copy[io_entry] - - if(io_type_override) - io_list.Add(new io_type_override(src, io_entry, default_data, pin_type,i)) - else - io_list.Add(new io_type(src, io_entry, default_data, pin_type,i)) - - -/obj/item/integrated_circuit/proc/set_pin_data(pin_type, pin_number, datum/new_data) - if(islist(new_data)) - for(var/i in 1 to length(new_data)) - if (istype(new_data) && !isweakref(new_data)) - new_data[i] = weakref(new_data[i]) - if (istype(new_data) && !isweakref(new_data)) - new_data = weakref(new_data) - var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) - return pin.write_data_to_pin(new_data) - -/obj/item/integrated_circuit/proc/get_pin_data(pin_type, pin_number) - var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) - return pin.get_data() - -/obj/item/integrated_circuit/proc/get_pin_data_as_type(pin_type, pin_number, as_type) - var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) - return pin.data_as_type(as_type) - -/obj/item/integrated_circuit/proc/activate_pin(pin_number) - var/datum/integrated_io/activate/A = activators[pin_number] - A.push_data() - -/obj/item/integrated_circuit/proc/get_pin_ref(pin_type, pin_number) - switch(pin_type) - if(IC_INPUT) - if(!inputs || pin_number > inputs.len) - return - return inputs[pin_number] - if(IC_OUTPUT) - if(!outputs || pin_number > outputs.len) - return - return outputs[pin_number] - if(IC_ACTIVATOR) - if(!activators || pin_number > activators.len) - return - return activators[pin_number] - return - -/datum/integrated_io/proc/get_data() - if(islist(data)) - for(var/i in 1 to length(data)) - if(isweakref(data[i])) - var/weakref/dw = data[i] - data[i] = dw.resolve() - if(isweakref(data)) - return data.resolve() - return data - - -// Returns a list of parameters necessary to locate a pin in the assembly: component number, pin type and pin number -// Components list can be supplied from the outside, for use in savefiles -/datum/integrated_io/proc/get_pin_parameters(list/components) - if(!holder) - return - - if(!components) - if(!holder.assembly) - return - components = holder.assembly.assembly_components - - var/component_number = components.Find(holder) - - var/list/pin_holder_list - switch(pin_type) - if(IC_INPUT) - pin_holder_list = holder.inputs - if(IC_OUTPUT) - pin_holder_list = holder.outputs - if(IC_ACTIVATOR) - pin_holder_list = holder.activators - else - return - - var/pin_number = pin_holder_list.Find(src) - - return list(component_number, pin_type, pin_number) - - -// Locates a pin in the assembly when given component number, pin type and pin number -// Components list can be supplied from the outside, for use in savefiles -/obj/item/electronic_assembly/proc/get_pin_ref(component_number, pin_type, pin_number, list/components) - if(!components) - components = assembly_components - - if(component_number > components.len) - return - - var/obj/item/integrated_circuit/component = components[component_number] - return component.get_pin_ref(pin_type, pin_number) - - -// Same as get_pin_ref, but takes in a list of 3 parameters (same format as get_pin_parameters) -// and performs extra sanity checks on parameters list and index numbers -/obj/item/electronic_assembly/proc/get_pin_ref_list(list/parameters, list/components) - if(!components) - components = assembly_components - - if(!islist(parameters) || parameters.len != 3) - return - - // Those are supposed to be list indexes, check them for sanity - if(!isnum(parameters[1]) || parameters[1] % 1 || parameters[1] < 1) - return - - if(!isnum(parameters[3]) || parameters[3] % 1 || parameters[3] < 1) - return - - return get_pin_ref(parameters[1], parameters[2], parameters[3], components) - -// this is for data validation of stuff like ref encodes and more importantly ID access lists - -/proc/compute_signature(data) - return md5(SScircuit.cipherkey + data) - -/proc/add_data_signature(data) - var/signature = compute_signature(data) - return "[signature]:[data]" - -/proc/check_data_signature(signature, data) - return (compute_signature(data) == signature) diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm deleted file mode 100644 index 14b28c2fb85b..000000000000 --- a/code/modules/integrated_electronics/core/integrated_circuit.dm +++ /dev/null @@ -1,408 +0,0 @@ -/obj/item/integrated_circuit - name = "integrated circuit" - desc = "It's a tiny chip! This one doesn't seem to do much, however." - icon = 'icons/obj/assemblies/electronic_components.dmi' - icon_state = "template" - w_class = ITEM_SIZE_TINY - matter = list() // To be filled later - var/obj/item/electronic_assembly/assembly // Reference to the assembly holding this circuit, if any. - var/extended_desc - var/list/inputs - var/list/inputs_default// Assoc list which will fill a pin with data upon creation. e.g. "2" = 0 will set input pin 2 to equal 0 instead of null. - var/list/outputs - var/list/outputs_default// Ditto, for output. - var/list/activators - var/next_use = 0 // Uses world.time - var/complexity = 1 // This acts as a limitation on building machines, more resource-intensive components cost more 'space'. - var/size = 1 // This acts as a limitation on building machines, bigger components cost more 'space'. -1 for size 0 - var/cooldown_per_use = 1 // Circuits are limited in how many times they can be work()'d by this variable. - var/ext_cooldown = 0 // Circuits are limited in how many times they can be work()'d with external world by this variable. - var/power_draw_per_use = 0 // How much power is drawn when work()'d. - var/power_draw_idle = 0 // How much power is drawn when doing nothing. - var/spawn_flags // Used for world initializing, see the #defines above. - var/action_flags = 0 // Used for telling circuits that can do certain actions from other circuits. - var/category_text = "NO CATEGORY THIS IS A BUG" // To show up on circuit printer, and perhaps other places. - var/removable = TRUE // Determines if a circuit is removable from the assembly. - var/displayed_name = "" - -/* - Integrated circuits are essentially modular machines. Each circuit has a specific function, and combining them inside Electronic Assemblies allows -a creative player the means to solve many problems. Circuits are held inside an electronic assembly, and are wired using special tools. -*/ - -/obj/item/integrated_circuit/examine(mob/user) - . = ..() - external_examine(user) - -/obj/item/integrated_circuit/ShiftClick(mob/living/user) - if(istype(user)) - interact(user) - else - ..() - -// This should be used when someone is examining while the case is opened. -/obj/item/integrated_circuit/proc/internal_examine(mob/user) - any_examine(user) - interact(user) - -// This should be used when someone is examining from an 'outside' perspective, e.g. reading a screen or LED. -/obj/item/integrated_circuit/proc/external_examine(mob/user) - any_examine(user) - -/obj/item/integrated_circuit/proc/any_examine(mob/user) - return - -/obj/item/integrated_circuit/proc/attackby_react(var/atom/movable/A,mob/user) - return - -/obj/item/integrated_circuit/proc/sense(var/atom/movable/A,mob/user,prox) - return - -/obj/item/integrated_circuit/proc/OnICTopic(href_list, user) - return - -/obj/item/integrated_circuit/proc/get_topic_data(var/mob/user) - return - -/obj/item/integrated_circuit/proc/check_interactivity(mob/user) - if(assembly) - return assembly.check_interactivity(user) - else - return CanUseTopic(user) - -/obj/item/integrated_circuit/Initialize() - displayed_name = name - setup_io(inputs, /datum/integrated_io, inputs_default, IC_INPUT) - inputs_default = null - setup_io(outputs, /datum/integrated_io, outputs_default, IC_OUTPUT) - outputs_default = null - setup_io(activators, /datum/integrated_io/activate, null, IC_ACTIVATOR) - if(!matter[/decl/material/solid/metal/steel]) - matter[/decl/material/solid/metal/steel] = w_class * SScircuit.cost_multiplier // Default cost. - . = ..() - -/obj/item/integrated_circuit/proc/on_data_written() //Override this for special behaviour when new data gets pushed to the circuit. - return - -/obj/item/integrated_circuit/Destroy() - QDEL_NULL_LIST(inputs) - QDEL_NULL_LIST(outputs) - QDEL_NULL_LIST(activators) - SScircuit_components.dequeue_component(src) - . = ..() - -/obj/item/integrated_circuit/emp_act(severity) - for(var/k in 1 to LAZYLEN(inputs)) - var/datum/integrated_io/I = inputs[k] - I.scramble() - for(var/k in 1 to LAZYLEN(outputs)) - var/datum/integrated_io/O = outputs[k] - O.scramble() - for(var/k in 1 to LAZYLEN(activators)) - var/datum/integrated_io/activate/A = activators[k] - A.scramble() - - -/obj/item/integrated_circuit/verb/rename_component() - set name = "Rename Circuit" - set category = "Object" - set desc = "Rename your circuit, useful to stay organized." - - var/mob/M = usr - if(!check_interactivity(M)) - return - - var/input = sanitizeName(input(M, "What do you want to name this?", "Rename", name) as null|text, allow_numbers = TRUE) - if(check_interactivity(M)) - if(!input) - input = name - to_chat(M, "The circuit '[name]' is now labeled '[input]'.") - displayed_name = input - -/obj/item/integrated_circuit/nano_host() - if(istype(src.loc, /obj/item/electronic_assembly)) - return loc - return ..() - -/obj/item/integrated_circuit/interact(mob/user) - . = ..() - if(!check_interactivity(user)) - return - - var/window_height = 350 - var/window_width = 655 - - var/table_edge_width = "30%" - var/table_middle_width = "40%" - var/list/HTML = list() - HTML += "[src.displayed_name]" - HTML += "
          " - HTML += "" - - if(assembly) - HTML += "\[Return to Assembly\]
          " - - HTML += "\[Refresh\] | " - HTML += "\[Rename\] | " - HTML += "\[Copy Ref\]" - if(assembly && removable) - HTML += " | \[Remove\]" - HTML += "
          " - - HTML += "" - HTML += "" - HTML += "" - HTML += "" - HTML += "" - - var/column_width = 3 - var/row_height = max(LAZYLEN(inputs), LAZYLEN(outputs), 1) - - for(var/i = 1 to row_height) - HTML += "" - for(var/j = 1 to column_width) - var/datum/integrated_io/io = null - var/words = list() - var/height = 1 - switch(j) - if(1) - io = get_pin_ref(IC_INPUT, i) - if(io) - words += "[io.display_pin_type()] [io.name] \ - [io.display_data(io.data)]
          " - if(io.linked.len) - for(var/k in 1 to io.linked.len) - var/datum/integrated_io/linked = io.linked[k] - words += "[linked] \ - @ [linked.holder.displayed_name]
          " - - if(LAZYLEN(outputs) > LAZYLEN(inputs)) - height = 1 - if(2) - if(i == 1) - words += "[src.displayed_name]
          [src.name != src.displayed_name ? "([src.name])":""]
          [src.desc]" - height = row_height - else - continue - if(3) - io = get_pin_ref(IC_OUTPUT, i) - if(io) - words += "[io.display_pin_type()] [io.name] \ - [io.display_data(io.data)]
          " - if(io.linked.len) - for(var/k in 1 to io.linked.len) - var/datum/integrated_io/linked = io.linked[k] - words += "[linked] \ - @ [linked.holder.displayed_name]
          " - - if(LAZYLEN(inputs) > LAZYLEN(outputs)) - height = 1 - HTML += "" - HTML += "" - - for(var/i in 1 to LAZYLEN(activators)) - var/datum/integrated_io/io = activators[i] - var/words = list() - - words += "[io] " - words += "[io.data?"\":"\"]
          " - if(io.linked.len) - for(var/k in 1 to io.linked.len) - var/datum/integrated_io/linked = io.linked[k] - words += "[linked] \ - @ [linked.holder.displayed_name]
          " - - HTML += "" - HTML += "" - HTML += "" - - HTML += "
          [jointext(words, null)]
          [jointext(words, null)]
          " - HTML += "
          " - - HTML += "
          Complexity: [complexity]" - HTML += "
          Cooldown per use: [cooldown_per_use/10] sec" - if(ext_cooldown) - HTML += "
          External manipulation cooldown: [ext_cooldown/10] sec" - if(power_draw_idle) - HTML += "
          Power Draw: [power_draw_idle] W (Idle)" - if(power_draw_per_use) - HTML += "
          Power Draw: [power_draw_per_use] W (Active)" // Borgcode says that powercells' checked_use() takes joules as input. - HTML += "
          [extended_desc]" - - HTML += "" - var/HTML_merged = jointext(HTML, null) - if(assembly) - show_browser(user, HTML_merged, "window=assembly-\ref[assembly];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") - else - show_browser(user, HTML_merged, "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") - - onclose(user, "assembly-\ref[src.assembly]") - -/obj/item/integrated_circuit/Topic(href, href_list, state = GLOB.physical_state) - if(..()) - return 1 - - . = IC_TOPIC_HANDLED - var/obj/held_item = usr.get_active_hand() - if(href_list["pin"] && assembly) - var/datum/integrated_io/pin = locate(href_list["pin"]) in inputs + outputs + activators - if(pin) - var/datum/integrated_io/linked - var/success = TRUE - if(href_list["link"]) - linked = locate(href_list["link"]) in pin.linked - - if(istype(held_item, /obj/item/integrated_electronics)) - pin.handle_wire(linked, held_item, href_list["act"], usr) - . = IC_TOPIC_REFRESH - else - to_chat(usr, "You can't do a whole lot without the proper tools.") - success = FALSE - if(success && assembly) - assembly.add_allowed_scanner(usr.ckey) - - else if(href_list["scan"]) - if(istype(held_item, /obj/item/integrated_electronics/debugger)) - var/obj/item/integrated_electronics/debugger/D = held_item - if(D.accepting_refs) - D.afterattack(src, usr, TRUE) - . = IC_TOPIC_REFRESH - else - to_chat(usr, "The debugger's 'ref scanner' needs to be on.") - else - to_chat(usr, "You need a debugger set to 'ref' mode to do that.") - - else if(href_list["refresh"]) - internal_examine(usr) - else if(href_list["return"] && assembly) - assembly.interact(usr) - else if(href_list["examine"] && assembly) - internal_examine(usr) - - else if(href_list["rename"]) - rename_component(usr) - . = IC_TOPIC_REFRESH - - else if(href_list["remove"] && assembly) - if(istype(held_item, /obj/item/screwdriver)) - disconnect_all() - dropInto(loc) - playsound(src, 'sound/items/Crowbar.ogg', 50, 1) - to_chat(usr, "You pop \the [src] out of the case, and slide it out.") - else - to_chat(usr, "You need a screwdriver to remove components.") - interact_with_assembly(usr) - . = IC_TOPIC_REFRESH - - else - . = OnICTopic(href_list, usr) - - if(. == IC_TOPIC_REFRESH) - interact_with_assembly(usr) - -/obj/item/integrated_circuit/proc/interact_with_assembly(var/mob/user) - if(assembly) - assembly.interact(user) - if(assembly.opened) - interact(user) - -/obj/item/integrated_circuit/proc/push_data() - for(var/k in 1 to LAZYLEN(outputs)) - var/datum/integrated_io/O = outputs[k] - O.push_data() - -/obj/item/integrated_circuit/proc/pull_data() - for(var/k in 1 to LAZYLEN(inputs)) - var/datum/integrated_io/I = inputs[k] - I.push_data() - -/obj/item/integrated_circuit/proc/draw_idle_power() - if(assembly) - return assembly.draw_power(power_draw_idle) - -// Override this for special behaviour when there's no power left. -/obj/item/integrated_circuit/proc/power_fail() - return - -// Returns true if there's enough power to work(). -/obj/item/integrated_circuit/proc/check_power() - if(!assembly) - return FALSE // Not in an assembly, therefore no power. - if(assembly.draw_power(power_draw_per_use)) - return TRUE // Battery has enough. - return FALSE // Not enough power. - -/obj/item/integrated_circuit/proc/check_then_do_work(ord,var/ignore_power = FALSE) - if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam. - return FALSE - if(assembly && ext_cooldown && (world.time < assembly.ext_next_use)) // Some circuits have external cooldown, to protect from spam. - return FALSE - if(power_draw_per_use && !ignore_power) - if(!check_power()) - power_fail() - return FALSE - next_use = world.time + cooldown_per_use - if(assembly) - assembly.ext_next_use = world.time + ext_cooldown - do_work(ord) - return TRUE - -/obj/item/integrated_circuit/proc/do_work(ord) - return - -/obj/item/integrated_circuit/proc/disconnect_all() - var/datum/integrated_io/I - - for(var/i in inputs) - I = i - I.disconnect_all() - - for(var/i in outputs) - I = i - I.disconnect_all() - - for(var/i in activators) - I = i - I.disconnect_all() - -/obj/item/integrated_circuit/proc/get_object() - // If the component is located in an assembly, let assembly determine it. - if(assembly) - return assembly.get_object() - else - return src // If not, the component is acting on its own. - - -// Checks if the target object is reachable. Useful for various manipulators and manipulator-like objects. -/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE) - if(!target) - return FALSE - - var/atom/movable/acting_object = get_object() - - if(exclude_self && target == acting_object) - return FALSE - - if(exclude_components && assembly) - if(target in assembly.assembly_components) - return FALSE - - if(target == assembly.battery) - return FALSE - - if(target.Adjacent(acting_object) && isturf(target.loc)) - return TRUE - - if(!exclude_contents && (target in acting_object.GetAllContents())) - return TRUE - - if(target in acting_object.loc) - return TRUE - - return FALSE - -/obj/item/integrated_circuit/proc/added_to_assembly(var/obj/item/electronic_assembly/assembly) - return - -/obj/item/integrated_circuit/proc/removed_from_assembly(var/obj/item/electronic_assembly/assembly) - return diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm deleted file mode 100644 index b016d2f72dba..000000000000 --- a/code/modules/integrated_electronics/core/pins.dm +++ /dev/null @@ -1,208 +0,0 @@ -/* - Pins both hold data for circuits, as well move data between them. Some also cause circuits to do their function. DATA_CHANNEL pins are the data holding/moving kind, -where as PULSE_CHANNEL causes circuits to work() when their pulse hits them. - - -A visualization of how pins work is below. Imagine the below image involves an addition circuit. -When the bottom pin, the activator, receives a pulse, all the numbers on the left (input) get added, and the answer goes on the right side (output). - -Inputs Outputs - -A [2]\ /[8] result -B [1]-\|++|/ -C [4]-/|++| -D [1]/ || - || - Activator - - - -*/ -/datum/integrated_io - var/name = "input/output" - var/obj/item/integrated_circuit/holder - var/weakref/data // This is a weakref, to reduce typecasts. Note that oftentimes numbers and text may also occupy this. - var/list/linked = list() - var/io_type = DATA_CHANNEL - var/pin_type // IC_INPUT, IC_OUTPUT, IC_ACTIVATOR - used in saving assembly wiring - var/ord - -/datum/integrated_io/New(loc, _name, _data, _pin_type,_ord) - name = _name - if(_data) - data = _data - if(_pin_type) - pin_type = _pin_type - if(_ord) - ord = _ord - - holder = loc - - if(!istype(holder)) - message_admins("ERROR: An integrated_io ([name]) spawned without a valid holder! This is a bug.") - -/datum/integrated_io/Destroy() - disconnect_all() - data = null - holder = null - return ..() - -/datum/integrated_io/proc/data_as_type(var/as_type) - if(!isweakref(data)) - return - var/weakref/w = data - var/output = w.resolve() - return istype(output, as_type) ? output : null - -/datum/integrated_io/proc/display_data(var/input) - if(isnull(input)) - return "(null)" // Empty data means nothing to show. - - if(istext(input)) - return "(\"[input]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'. - - if(islist(input)) - var/list/my_list = input - var/result = "list\[[my_list.len]\](" - if(my_list.len) - result += "
          " - var/pos = 0 - for(var/line in my_list) - result += "[display_data(line)]" - pos++ - if(pos != my_list.len) - result += ",
          " - result += "
          " - result += ")" - return result - - if(isweakref(input)) - var/weakref/w = input - var/atom/A = w.resolve() - return A ? "([A.name] \[Ref\])" : "(null)" // For refs, we want just the name displayed. - - return "([input])" // Nothing special needed for numbers or other stuff. - -/datum/integrated_io/activate/display_data() - return "(\[pulse\])" - -/datum/integrated_io/proc/display_pin_type() - return IC_FORMAT_ANY - -/datum/integrated_io/activate/display_pin_type() - return IC_FORMAT_PULSE - -/datum/integrated_io/proc/scramble() - if(isnull(data)) - return - if(isnum(data)) - write_data_to_pin(rand(-10000, 10000)) - if(istext(data)) - write_data_to_pin("ERROR") - push_data() - -/datum/integrated_io/activate/scramble() - push_data() - -/datum/integrated_io/proc/handle_wire(datum/integrated_io/linked_pin, obj/item/tool, action, mob/living/user) - if(istype(tool, /obj/item/integrated_electronics/wirer)) - var/obj/item/integrated_electronics/wirer/wirer = tool - if(linked_pin) - wirer.wire(linked_pin, user) - else - wirer.wire(src, user) - return TRUE - - else if(istype(tool, /obj/item/integrated_electronics/debugger)) - var/obj/item/integrated_electronics/debugger/debugger = tool - debugger.write_data(src, user) - return TRUE - - return FALSE - -/datum/integrated_io/proc/write_data_to_pin(new_data) - if(isnull(new_data) || isnum(new_data) || istext(new_data) || isweakref(new_data)) - data = new_data - holder.on_data_written() - else if(islist(new_data)) - var/list/new_list = new_data - data = new_list.Copy(max(1,new_list.len - IC_MAX_LIST_LENGTH+1),0) - holder.on_data_written() - -/datum/integrated_io/proc/push_data() - for(var/k in 1 to linked.len) - var/datum/integrated_io/io = linked[k] - io.write_data_to_pin(data) - -/datum/integrated_io/activate/push_data() - for(var/k in 1 to linked.len) - var/datum/integrated_io/io = linked[k] - SScircuit_components.queue_component(io.holder, TRUE, io.ord) - -/datum/integrated_io/proc/pull_data() - for(var/k in 1 to linked.len) - var/datum/integrated_io/io = linked[k] - write_data_to_pin(io.data) - -/datum/integrated_io/proc/get_linked_to_desc() - if(linked.len) - return "the [english_list(linked)]" - return "nothing" - - -/datum/integrated_io/proc/connect_pin(datum/integrated_io/pin) - pin.linked |= src - linked |= pin - -// Iterates over every linked pin and disconnects them. -/datum/integrated_io/proc/disconnect_all() - for(var/pin in linked) - disconnect_pin(pin) - -/datum/integrated_io/proc/disconnect_pin(datum/integrated_io/pin) - pin.linked.Remove(src) - linked.Remove(pin) - - -/datum/integrated_io/proc/ask_for_data_type(mob/user, var/default, var/list/allowed_data_types = list("string","number","null")) - var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in allowed_data_types - if(!holder.check_interactivity(user)) - return - - var/new_data = null - switch(type_to_use) - if("string") - var/input_text = input(user, "Now type in a string.", "[src] string writing", istext(default) ? default : null) as null|text - new_data = sanitize(input_text, trim = 0) - if(istext(new_data) && holder.check_interactivity(user) ) - to_chat(user, "You input "+new_data+" into the pin.") - return new_data - if("number") - new_data = input("Now type in a number.","[src] number writing", isnum(default) ? default : null) as null|num - if(isnum(new_data) && holder.check_interactivity(user) ) - to_chat(user, "You input [new_data] into the pin.") - return new_data - if("null") - if(holder.check_interactivity(user)) - to_chat(user, "You clear the pin's memory.") - return new_data - -// Basically a null check -/datum/integrated_io/proc/is_valid() - return !isnull(data) - -// This proc asks for the data to write, then writes it. -/datum/integrated_io/proc/ask_for_pin_data(mob/user) - var/new_data = ask_for_data_type(user) - write_data_to_pin(new_data) - -/datum/integrated_io/activate/ask_for_pin_data(mob/user) // This just pulses the pin. - holder.check_then_do_work(ord,ignore_power = TRUE) - to_chat(user, "You pulse \the [holder]'s [src] pin.") - -/datum/integrated_io/activate - name = "activation pin" - io_type = PULSE_CHANNEL - -/datum/integrated_io/activate/out // All this does is just make the UI say 'out' instead of 'in' - data = 1 diff --git a/code/modules/integrated_electronics/core/prefab/prefabs.dm b/code/modules/integrated_electronics/core/prefab/prefabs.dm deleted file mode 100644 index 6a8663042e0f..000000000000 --- a/code/modules/integrated_electronics/core/prefab/prefabs.dm +++ /dev/null @@ -1,8 +0,0 @@ -/decl/prefab/ic_assembly/hand_teleporter - assembly_name = "hand-teleporter" - data = {"{'assembly':{'type':'type-a electronic mechanism','name':'Hand Teleporter', 'detail_color':'#5d99be'},'components':\[{'type':'teleporter locator'},{'type':'wormhole generator'},{'type':'button','name':'Open Wormhole'}\],'wires':\[\[\[1,'O',1\],\[2,'I',1\]\],\[\[2,'A',1\],\[3,'A',1\]\]\]}"} - power_cell_type = /obj/item/cell/hyper - -/obj/prefab/hand_teleporter - name = "hand teleporter" - prefab_type = /decl/prefab/ic_assembly/hand_teleporter \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/prefab/test/testprefabs.dm b/code/modules/integrated_electronics/core/prefab/test/testprefabs.dm deleted file mode 100644 index b58cf8d309ef..000000000000 --- a/code/modules/integrated_electronics/core/prefab/test/testprefabs.dm +++ /dev/null @@ -1,8 +0,0 @@ -/decl/prefab/ic_assembly/test_heatercooler - assembly_name = "heating-cooling-test" - data = {"{'assembly':{'type':'type-c electronic machine'},'components':\[{'type':'starter'},{'type':'reagent funnel'},{'type':'big reagent storage'},{'type':'reagent pump','name':'Hot Pump','inputs':\[\[3,0,5]]},{'type':'reagent pump','name':'Cool Pump','inputs':\[\[3,0,5]]},{'type':'reagent heater','name':'Heater','inputs':\[\[1,0,80]]},{'type':'reagent cooler','name':'Cooler','inputs':\[\[1,0,-50]]},{'type':'button','name':'Heat And Cool'},{'type':'and gate','name':'Heater Active Check','inputs':\[\[1,0,0],\[2,0,1]]},{'type':'and gate','name':'Cooler Active Check','inputs':\[\[1,0,0],\[2,0,1]]},{'type':'custom delay circuit','name':'Heater Delay','inputs':\[\[1,0,100]]},{'type':'custom delay circuit','name':'Cooler Delay','inputs':\[\[1,0,100]]}],'wires':\[\[\[1,'A',1],\[3,'A',1]],\[\[1,'A',1],\[6,'A',3]],\[\[1,'A',1],\[7,'A',3]],\[\[2,'I',1],\[3,'O',2]],\[\[3,'O',2],\[4,'I',1]],\[\[3,'O',2],\[5,'I',1]],\[\[4,'I',2],\[6,'O',4]],\[\[4,'A',1],\[8,'A',1]],\[\[4,'A',2],\[6,'A',1]],\[\[5,'I',2],\[7,'O',4]],\[\[5,'A',1],\[8,'A',1]],\[\[5,'A',2],\[7,'A',1]],\[\[6,'O',3],\[9,'I',1]],\[\[6,'A',1],\[11,'A',2]],\[\[6,'A',2],\[9,'A',1]],\[\[7,'O',3],\[10,'I',1]],\[\[7,'A',1],\[12,'A',2]],\[\[7,'A',2],\[10,'A',1]],\[\[9,'A',2],\[11,'A',1]],\[\[10,'A',2],\[12,'A',1]]]}"} - power_cell_type = /obj/item/cell/hyper - -/obj/prefab/test_heatcool - name = "heating-cooling test" - prefab_type = /decl/prefab/ic_assembly/test_heatercooler diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm deleted file mode 100644 index bb7a7f273d0e..000000000000 --- a/code/modules/integrated_electronics/core/printer.dm +++ /dev/null @@ -1,355 +0,0 @@ -#define MAX_CIRCUIT_CLONE_TIME 3 MINUTES //circuit slow-clones can only take up this amount of time to complete - -/obj/item/integrated_circuit_printer - name = "integrated circuit printer" - desc = "A portable(ish) machine made to print tiny modular circuitry out of metal." - icon = 'icons/obj/assemblies/electronic_tools.dmi' - icon_state = "circuit_printer" - w_class = ITEM_SIZE_LARGE - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - - var/upgraded = FALSE // When hit with an upgrade disk, will turn true, allowing it to print the higher tier circuits. - var/can_clone = TRUE // Allows the printer to clone circuits, either instantly or over time depending on upgrade. Set to FALSE to disable entirely. - var/fast_clone = FALSE // If this is false, then cloning will take an amount of deciseconds equal to the metal cost divided by 100. - var/debug = FALSE // If it's upgraded and can clone, even without config settings. - var/current_category = null - var/cloning = FALSE // If the printer is currently creating a circuit - var/recycling = FALSE // If an assembly is being emptied into this printer - var/list/program // Currently loaded save, in form of list - var/materials = list(/decl/material/solid/metal/steel = 0) - var/metal_max = 25 * SHEET_MATERIAL_AMOUNT - -/obj/item/integrated_circuit_printer/proc/check_interactivity(mob/user) - return CanUseTopic(user) - -/obj/item/integrated_circuit_printer/upgraded - upgraded = TRUE - can_clone = TRUE - fast_clone = TRUE - -/obj/item/integrated_circuit_printer/debug //translation: "integrated_circuit_printer/local_server" - name = "debug circuit printer" - debug = TRUE - upgraded = TRUE - can_clone = TRUE - fast_clone = TRUE - w_class = ITEM_SIZE_TINY - -/obj/item/integrated_circuit_printer/proc/print_program(mob/user) - if(!cloning) - return - - visible_message("[src] has finished printing its assembly!") - playsound(src, 'sound/items/poster_being_created.ogg', 50, TRUE) - var/obj/item/electronic_assembly/assembly = SScircuit.load_electronic_assembly(get_turf(src), program) - assembly.creator = key_name(user) - cloning = FALSE - -/obj/item/integrated_circuit_printer/proc/recycle(obj/item/O, mob/user, obj/item/electronic_assembly/assembly) - if(!O.canremove) //in case we have an augment circuit - return - for(var/material in O.matter) - if(materials[material] + O.matter[material] > metal_max) - var/decl/material/material_datum = decls_repository.get_decl(material) - if(material_datum) - to_chat(user, "[src] can't hold any more [material_datum.name]!") - return - for(var/material in O.matter) - materials[material] += O.matter[material] - if(assembly) - assembly.remove_component(O) - if(user) - to_chat(user, "You recycle [O]!") - qdel(O) - return TRUE - -/obj/item/integrated_circuit_printer/attackby(obj/item/O, mob/user) - if(istype(O, /obj/item/stack/material)) - var/obj/item/stack/material/M = O - var/amt = M.amount - if(amt * SHEET_MATERIAL_AMOUNT + materials[M.material.type] > metal_max) - amt = -round(-(metal_max - materials[M.material.type]) / SHEET_MATERIAL_AMOUNT) //round up - if(M.use(amt)) - materials[M.material.type] = min(metal_max, materials[M.material.type] + amt * SHEET_MATERIAL_AMOUNT) - to_chat(user, "You insert [M.material.solid_name] into \the [src].") - if(user) - attack_self(user) // We're really bad at refreshing the UI, so this is the best we've got. - if(istype(O, /obj/item/disk/integrated_circuit/upgrade/advanced)) - if(upgraded) - to_chat(user, "[src] already has this upgrade. ") - return TRUE - to_chat(user, "You install [O] into [src]. ") - upgraded = TRUE - if(user) - attack_self(user) - return TRUE - - if(istype(O, /obj/item/disk/integrated_circuit/upgrade/clone)) - if(fast_clone) - to_chat(user, "[src] already has this upgrade. ") - return TRUE - to_chat(user, "You install [O] into [src]. Circuit cloning will now be instant. ") - fast_clone = TRUE - if(user) - attack_self(user) - return TRUE - - if(istype(O, /obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/EA = O //microtransactions not included - if(EA.battery) - to_chat(user, "Remove [EA]'s power cell first!") - return - if(EA.assembly_components.len) - if(recycling) - return - if(!EA.opened) - to_chat(user, "You can't reach [EA]'s components to remove them!") - return - for(var/V in EA.assembly_components) - var/obj/item/integrated_circuit/IC = V - if(!IC.removable) - to_chat(user, "[EA] has irremovable components in the casing, preventing you from emptying it.") - return - to_chat(user, "You begin recycling [EA]'s components...") - playsound(src, 'sound/items/electronic_assembly_emptying.ogg', 50, TRUE) - if(!do_after(user, 30, target = src) || recycling) //short channel so you don't accidentally start emptying out a complex assembly - return - recycling = TRUE - for(var/V in EA.assembly_components) - recycle(V, null, EA) - to_chat(user, "You recycle all the components[EA.assembly_components.len ? " you could " : " "]from [EA]!") - playsound(src, 'sound/items/electronic_assembly_empty.ogg', 50, TRUE) - recycling = FALSE - return TRUE - else - return recycle(EA, user) - - if(istype(O, /obj/item/integrated_circuit)) - return recycle(O, user) - - return ..() - -/obj/item/integrated_circuit_printer/attack_self(mob/user) - interact(user) - -/obj/item/integrated_circuit_printer/interact(mob/user) - if(!(in_range(src, user) || issilicon(user))) - return - - if(isnull(current_category)) - current_category = SScircuit.circuit_fabricator_recipe_list[1] - - //Preparing the browser - var/datum/browser/written/popup = new(user, "printernew", "Integrated Circuit Printer", 800, 630) // Set up the popup browser window - - var/list/HTML = list() - HTML += "

          Integrated Circuit Printer


          " - if(debug) - HTML += "

          DEBUG PRINTER -- Infinite materials. Cloning available.

          " - else - HTML += "Materials: " - var/list/dat = list() - for(var/material in materials) - var/decl/material/material_datum = decls_repository.get_decl(material) - dat += "[materials[material]]/[metal_max] [material_datum.name]" - HTML += jointext(dat, "; ") - HTML += ".

          " - - if(config.allow_ic_printing || debug) - HTML += "Assembly cloning: [can_clone ? (fast_clone ? "Instant" : "Available") : "Unavailable"].
          " - - HTML += "Circuits available: [upgraded || debug ? "Advanced":"Regular"]." - if(!upgraded) - HTML += "
          Crossed out circuits mean that the printer is not sufficiently upgraded to create that circuit." - - HTML += "
          " - if((can_clone && config.allow_ic_printing) || debug) - HTML += "Here you can load script for your assembly.
          " - if(!cloning) - HTML += " {Load Program} " - else - HTML += " {Load Program}" - if(!program) - HTML += " {[fast_clone ? "Print" : "Begin Printing"] Assembly}" - else if(cloning) - HTML += " {Cancel Print}" - else - HTML += " {[fast_clone ? "Print" : "Begin Printing"] Assembly}" - - HTML += "

          " - HTML += "Categories:" - for(var/category in SScircuit.circuit_fabricator_recipe_list) - if(category != current_category) - HTML += " \[[category]\] " - else // Bold the button if it's already selected. - HTML += " \[[category]\] " - HTML += "
          " - HTML += "

          [current_category]

          " - - var/list/current_list = SScircuit.circuit_fabricator_recipe_list[current_category] - for(var/path in current_list) - var/obj/O = path - var/can_build = TRUE - if(ispath(path, /obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = path - if((initial(IC.spawn_flags) & IC_SPAWN_RESEARCH) && (!(initial(IC.spawn_flags) & IC_SPAWN_DEFAULT)) && !upgraded) - can_build = FALSE - if(can_build) - HTML += "\[[initial(O.name)]\]: [initial(O.desc)]
          " - else - HTML += "\[[initial(O.name)]\]: [initial(O.desc)]
          " - - popup.set_content(JOINTEXT(HTML)) - popup.open() - -/obj/item/integrated_circuit_printer/Topic(href, href_list) - if(!check_interactivity(usr)) - return - if(..()) - return TRUE - add_fingerprint(usr) - - if(href_list["category"]) - current_category = href_list["category"] - - if(href_list["build"]) - var/build_type = locate(href_list["build"]) - if(!build_type || !ispath(build_type)) - return TRUE - - var/list/cost - if(ispath(build_type, /obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/E = SScircuit.cached_assemblies[build_type] - cost = E.matter - else if(ispath(build_type, /obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = SScircuit.cached_components[build_type] - cost = IC.matter - else if(!(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"])) - return - - if(!debug && !subtract_material_costs(cost, usr)) - return - - var/obj/item/built = new build_type(get_turf(src)) - usr.put_in_hands(built) - - if(istype(built, /obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/E = built - E.creator = key_name(usr) - E.opened = TRUE - E.update_icon() - to_chat(usr, "[capitalize(built.name)] printed.") - playsound(src, 'sound/items/jaws_pry.ogg', 50, TRUE) - - if(href_list["print"]) - if(!config.allow_ic_printing && !debug) - to_chat(usr, "Your facility has disabled printing of custom circuitry due to recent allegations of copyright infringement.") - return - if(!can_clone) // Copying and printing ICs is cloning - to_chat(usr, "This printer does not have the cloning upgrade.") - return - switch(href_list["print"]) - if("load") - if(cloning) - return - var/input = usr.get_input("Put your code there:", "loading", null, MOB_INPUT_MESSAGE, src) - if(cloning) - return - if(!input) - program = null - return - - var/validation = SScircuit.validate_electronic_assembly(input) - - // Validation error codes are returned as text. - if(istext(validation)) - to_chat(usr, "Error: [validation]") - return - else if(islist(validation)) - program = validation - to_chat(usr, "This is a valid program for [program["assembly"]["type"]].") - if(program["requires_upgrades"]) - if(upgraded) - to_chat(usr, "It uses advanced component designs.") - else - to_chat(usr, "It uses unknown component designs. Printer upgrade is required to proceed.") - if(program["unsupported_circuit"]) - to_chat(usr, "This program uses components not supported by the specified assembly. Please change the assembly type in the save file to a supported one.") - to_chat(usr, "Used space: [program["used_space"]]/[program["max_space"]].") - to_chat(usr, "Complexity: [program["complexity"]]/[program["max_complexity"]].") - to_chat(usr, "Cost: [json_encode(program["cost"])].") - - if("print") - if(!program || cloning) - return - - if(program["requires_upgrades"] && !upgraded && !debug) - to_chat(usr, "This program uses unknown component designs. Printer upgrade is required to proceed.") - return - if(program["unsupported_circuit"] && !debug) - to_chat(usr, "This program uses components not supported by the specified assembly. Please change the assembly type in the save file to a supported one.") - return - else if(fast_clone) - var/list/cost = program["cost"] - if(debug || subtract_material_costs(cost, usr)) - cloning = TRUE - print_program(usr) - else - var/list/cost = program["cost"] - if(!subtract_material_costs(cost, usr)) - return - var/cloning_time = 0 - for(var/material in cost) - cloning_time += cost[material] - cloning_time = round(cloning_time/15) - cloning_time = min(cloning_time, MAX_CIRCUIT_CLONE_TIME) - cloning = TRUE - to_chat(usr, "You begin printing a custom assembly. This will take approximately [round(cloning_time/10)] seconds. You can still print \ - off normal parts during this time.") - playsound(src, 'sound/items/poster_being_created.ogg', 50, TRUE) - addtimer(CALLBACK(src, .proc/print_program, usr), cloning_time) - - if("cancel") - if(!cloning || !program) - return - - to_chat(usr, "Cloning has been canceled. Cost has been refunded.") - cloning = FALSE - var/cost = program["cost"] - for(var/material in cost) - materials[material] = min(metal_max, materials[material] + cost[material]) - - interact(usr) - -/obj/item/integrated_circuit_printer/proc/subtract_material_costs(var/list/cost, var/mob/user) - for(var/material in cost) - if(materials[material] < cost[material]) - var/decl/material/material_datum = decls_repository.get_decl(material) - to_chat(user, "You need [cost[material]] [material_datum.name] to build that!") - return FALSE - for(var/material in cost) //Iterate twice to make sure it's going to work before deducting - materials[material] -= cost[material] - return TRUE - -// FUKKEN UPGRADE DISKS -/obj/item/disk/integrated_circuit/upgrade - name = "integrated circuit printer upgrade disk" - desc = "Install this into your integrated circuit printer to enhance it." - icon = 'icons/obj/assemblies/electronic_tools.dmi' - icon_state = "upgrade_disk" - item_state = "card-id" - w_class = ITEM_SIZE_SMALL - -/obj/item/disk/integrated_circuit/upgrade/advanced - name = "integrated circuit printer upgrade disk - advanced designs" - desc = "Install this into your integrated circuit printer to enhance it. This one adds new, advanced designs to the printer." - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - -/obj/item/disk/integrated_circuit/upgrade/clone - name = "integrated circuit printer upgrade disk - instant cloner" - desc = "Install this into your integrated circuit printer to enhance it. This one allows the printer to duplicate assemblies instantaneously." - icon_state = "upgrade_disk_clone" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) diff --git a/code/modules/integrated_electronics/core/saved_circuits.dm b/code/modules/integrated_electronics/core/saved_circuits.dm deleted file mode 100644 index 33cd4d38c3f6..000000000000 --- a/code/modules/integrated_electronics/core/saved_circuits.dm +++ /dev/null @@ -1,368 +0,0 @@ -// Helpers for saving/loading integrated circuits. - - -// Saves type, modified name and modified inputs (if any) to a list -// The list is converted to JSON down the line. -//"Special" is not verified at any point except for by the circuit itself. -/obj/item/integrated_circuit/proc/save() - var/list/component_params = list() - var/init_name = initial(name) - - // Save initial name used for differentiating assemblies - component_params["type"] = init_name - - // Save the modified name. - if(init_name != displayed_name) - component_params["name"] = displayed_name - - // Saving input values - if(length(inputs)) - var/list/saved_inputs = list() - - for(var/index in 1 to inputs.len) - var/datum/integrated_io/input = inputs[index] - - // Don't waste space saving the default values - if(input.data == initial(input.data)) - continue - - var/list/input_value = list(index, FALSE, input.data) - // Index, Type, Value - // FALSE is default type used for num/text/list/null - // TODO: support for special input types, such as internal refs and maybe typepaths - - if(islist(input.data) || isnum(input.data) || istext(input.data) || isnull(input.data)) - saved_inputs.Add(list(input_value)) - - if(saved_inputs.len) - component_params["inputs"] = saved_inputs - - var/special = save_special() - if(!isnull(special)) - component_params["special"] = special - - return component_params - -/obj/item/integrated_circuit/proc/save_special() - return - -// Verifies a list of component parameters -// Returns null on success, error name on failure -/obj/item/integrated_circuit/proc/verify_save(list/component_params) - var/init_name = initial(name) - // Validate name - if(component_params["name"]) - sanitizeName(component_params["name"],allow_numbers=TRUE) - // Validate input values - if(component_params["inputs"]) - var/list/loaded_inputs = component_params["inputs"] - if(!islist(loaded_inputs)) - return "Malformed input values list at [init_name]." - - var/inputs_amt = length(inputs) - - // Too many inputs? Inputs for input-less component? This is not good. - if(!inputs_amt || inputs_amt < length(loaded_inputs)) - return "Input values list out of bounds at [init_name]." - - for(var/list/input in loaded_inputs) - if(input.len != 3) - return "Malformed input data at [init_name]." - - var/input_id = input[1] - var/input_type = input[2] - //var/input_value = input[3] - - // No special type support yet. - if(input_type) - return "Unidentified input type at [init_name]!" - // TODO: support for special input types, such as typepaths and internal refs - - // Input ID is a list index, make sure it's sane. - if(!isnum(input_id) || input_id % 1 || input_id > inputs_amt || input_id < 1) - return "Invalid input index at [init_name]." - - -// Loads component parameters from a list -// Doesn't verify any of the parameters it loads, this is the job of verify_save() -/obj/item/integrated_circuit/proc/load(list/component_params) - // Load name - if(component_params["name"]) - displayed_name = component_params["name"] - - // Load input values - if(component_params["inputs"]) - var/list/loaded_inputs = component_params["inputs"] - - for(var/list/input in loaded_inputs) - var/index = input[1] - //var/input_type = input[2] - var/input_value = input[3] - - var/datum/integrated_io/pin = inputs[index] - // The pins themselves validate the data. - pin.write_data_to_pin(input_value) - // TODO: support for special input types, such as internal refs and maybe typepaths - - if(!isnull(component_params["special"])) - load_special(component_params["special"]) - -/obj/item/integrated_circuit/proc/load_special(special_data) - return - -// Saves type and modified name (if any) to a list -// The list is converted to JSON down the line. -/obj/item/electronic_assembly/proc/save() - var/list/assembly_params = list() - - // Save initial name used for differentiating assemblies - assembly_params["type"] = initial(name) - - // Save modified name - if(initial(name) != name) - assembly_params["name"] = name - - // Save modified description - if(initial(desc) != desc) - assembly_params["desc"] = desc - - // Save modified color - if(initial(detail_color) != detail_color) - assembly_params["detail_color"] = detail_color - - return assembly_params - - -// Verifies a list of assembly parameters -// Returns null on success, error name on failure -/obj/item/electronic_assembly/proc/verify_save(list/assembly_params) - // Validate name and color - if(assembly_params["name"]) - if(sanitizeName(assembly_params["name"], allow_numbers = TRUE) != assembly_params["name"]) - return "Bad assembly name." - if(assembly_params["desc"]) - if(sanitize(assembly_params["desc"]) != assembly_params["desc"]) - return "Bad assembly description." - if(assembly_params["detail_color"] && !(assembly_params["detail_color"] in color_whitelist)) - return "Bad assembly color." - -// Loads assembly parameters from a list -// Doesn't verify any of the parameters it loads, this is the job of verify_save() -/obj/item/electronic_assembly/proc/load(list/assembly_params) - // Load modified name, if any. - if(assembly_params["name"]) - name = assembly_params["name"] - - // Load modified description, if any. - if(assembly_params["desc"]) - desc = assembly_params["desc"] - - if(assembly_params["detail_color"]) - detail_color = assembly_params["detail_color"] - - update_icon() - - - -// Attempts to save an assembly into a save file format. -// Returns null if assembly is not complete enough to be saved. -/datum/controller/subsystem/processing/circuit/proc/save_electronic_assembly(obj/item/electronic_assembly/assembly) - // No components? Don't even try to save it. - if(!length(assembly.assembly_components)) - return - - - var/list/blocks = list() - - // Block 1. Assembly. - blocks["assembly"] = assembly.save() - // (implant assemblies are not yet supported) - - - // Block 2. Components. - var/list/components = list() - for(var/c in assembly.assembly_components) - var/obj/item/integrated_circuit/component = c - components.Add(list(component.save())) - blocks["components"] = components - - - // Block 3. Wires. - var/list/wires = list() - var/list/saved_wires = list() - - for(var/c in assembly.assembly_components) - var/obj/item/integrated_circuit/component = c - var/list/all_pins = list() - for(var/l in list(component.inputs, component.outputs, component.activators)) - if(l) //If it isn't null - all_pins += l - - for(var/p in all_pins) - var/datum/integrated_io/pin = p - var/list/params = pin.get_pin_parameters() - var/text_params = params.Join() - - for(var/p2 in pin.linked) - var/datum/integrated_io/pin2 = p2 - var/list/params2 = pin2.get_pin_parameters() - var/text_params2 = params2.Join() - - // Check if we already saved an opposite version of this wire - // (do not save the same wire twice) - if((text_params2 + "=" + text_params) in saved_wires) - continue - - // If not, add a wire "hash" for future checks and save it - saved_wires.Add(text_params + "=" + text_params2) - wires.Add(list(list(params, params2))) - - if(wires.len) - blocks["wires"] = wires - - return json_encode(blocks) - - - -// Checks assembly save and calculates some of the parameters. -// Returns assembly (type: list) if the save is valid. -// Returns error code (type: text) if loading has failed. -// The following parameters area calculated during validation and added to the returned save list: -// "requires_upgrades", "unsupported_circuit", "cost", "complexity", "max_complexity", "used_space", "max_space" -/datum/controller/subsystem/processing/circuit/proc/validate_electronic_assembly(program) - var/list/blocks = cached_json_decode(program) - if(!blocks) - return - - var/error - - - // Block 1. Assembly. - var/list/assembly_params = blocks["assembly"] - - if(!islist(assembly_params) || !length(assembly_params)) - return "Invalid assembly data." // No assembly, damaged assembly or empty assembly - - // Validate type, get a temporary component - var/assembly_path = all_assemblies[assembly_params["type"]] - var/obj/item/electronic_assembly/assembly = cached_assemblies[assembly_path] - if(!assembly) - return "Invalid assembly type." - - // Check assembly save data for errors - error = assembly.verify_save(assembly_params) - if(error) - return error - - - // Read space & complexity limits and start keeping track of them - blocks["complexity"] = 0 - blocks["max_complexity"] = assembly.max_complexity - blocks["used_space"] = 0 - blocks["max_space"] = assembly.max_components - - // Start keeping track of total metal cost - blocks["cost"] = assembly.matter.Copy() - - - // Block 2. Components. - if(!islist(blocks["components"]) || !length(blocks["components"])) - return "Invalid components list." // No components or damaged components list - - var/list/assembly_components = list() - for(var/C in blocks["components"]) - var/list/component_params = C - - if(!islist(component_params) || !length(component_params)) - return "Invalid component data." - - // Validate type, get a temporary component - var/component_path = all_components[component_params["type"]] - var/obj/item/integrated_circuit/component = cached_components[component_path] - if(!component) - return "Invalid component type." - - // Add temporary component to assembly_components list, to be used later when verifying the wires - assembly_components.Add(component) - - // Check component save data for errors - error = component.verify_save(component_params) - if(error) - return error - - // Update estimated assembly complexity, taken space and material cost - blocks["complexity"] += component.complexity - blocks["used_space"] += component.size - for(var/material in component.matter) - blocks["cost"][material] += component.matter[material] - - // Check if the assembly requires printer upgrades - if(!(component.spawn_flags & IC_SPAWN_DEFAULT)) - blocks["requires_upgrades"] = TRUE - - // Check if the assembly supports the circucit - if((component.action_flags & assembly.allowed_circuit_action_flags) != component.action_flags) - blocks["unsupported_circuit"] = TRUE - - - // Check complexity and space limitations - if(blocks["used_space"] > blocks["max_space"]) - return "Used space overflow." - if(blocks["complexity"] > blocks["max_complexity"]) - return "Complexity overflow." - - - // Block 3. Wires. - if(blocks["wires"]) - if(!islist(blocks["wires"])) - return "Invalid wiring list." // Damaged wires list - - for(var/w in blocks["wires"]) - var/list/wire = w - - if(!islist(wire) || wire.len != 2) - return "Invalid wire data." - - var/datum/integrated_io/IO = assembly.get_pin_ref_list(wire[1], assembly_components) - var/datum/integrated_io/IO2 = assembly.get_pin_ref_list(wire[2], assembly_components) - if(!IO || !IO2) - return "Invalid wire data." - - if(initial(IO.io_type) != initial(IO2.io_type)) - return "Wire type mismatch." - - return blocks - - -// Loads assembly (in form of list) into an object and returns it. -// No sanity checks are performed, save file is expected to be validated by validate_electronic_assembly -/datum/controller/subsystem/processing/circuit/proc/load_electronic_assembly(loc, list/blocks) - - // Block 1. Assembly. - var/list/assembly_params = blocks["assembly"] - var/obj/item/electronic_assembly/assembly_path = all_assemblies[assembly_params["type"]] - var/obj/item/electronic_assembly/assembly = new assembly_path(null) - assembly.load(assembly_params) - - - - // Block 2. Components. - for(var/component_params in blocks["components"]) - var/obj/item/integrated_circuit/component_path = all_components[component_params["type"]] - var/obj/item/integrated_circuit/component = new component_path(assembly) - assembly.add_component(component) - component.load(component_params) - - - // Block 3. Wires. - if(blocks["wires"]) - for(var/w in blocks["wires"]) - var/list/wire = w - var/datum/integrated_io/IO = assembly.get_pin_ref_list(wire[1]) - var/datum/integrated_io/IO2 = assembly.get_pin_ref_list(wire[2]) - IO.connect_pin(IO2) - - assembly.forceMove(loc) - assembly.post_load() - return assembly - diff --git a/code/modules/integrated_electronics/passive/passive.dm b/code/modules/integrated_electronics/passive/passive.dm deleted file mode 100644 index 02f03d48d7c4..000000000000 --- a/code/modules/integrated_electronics/passive/passive.dm +++ /dev/null @@ -1,7 +0,0 @@ -// 'Passive' components do not have any pins, and instead contribute in some form to the assembly holding them. -/obj/item/integrated_circuit/passive - inputs = list() - outputs = list() - activators = list() - power_draw_idle = 0 - power_draw_per_use = 0 \ No newline at end of file diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm deleted file mode 100644 index 7ec0a45d93f2..000000000000 --- a/code/modules/integrated_electronics/passive/power.dm +++ /dev/null @@ -1,140 +0,0 @@ - -/obj/item/integrated_circuit/passive/power - name = "power thingy" - desc = "Does power stuff." - complexity = 5 - category_text = "Power - Passive" - -/obj/item/integrated_circuit/passive/power/proc/make_energy() - return - -// For calculators. -/obj/item/integrated_circuit/passive/power/solar_cell - name = "tiny photovoltaic cell" - desc = "It's a very tiny solar cell, generally used in calculators." - extended_desc = "This cell generates 1 W of power in optimal lighting conditions. Less light will result in less power being generated." - icon_state = "solar_cell" - complexity = 8 - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - var/max_power = 30 - -/obj/item/integrated_circuit/passive/power/solar_cell/make_energy() - var/turf/T = get_turf(src) - var/light_amount = T ? T.get_lumcount() : 0 - var/adjusted_power = max(max_power * light_amount, 0) - adjusted_power = round(adjusted_power, 0.1) - if(adjusted_power) - if(assembly) - assembly.give_power(adjusted_power) - -/obj/item/integrated_circuit/passive/power/starter - name = "starter" - desc = "This tiny circuit will send a pulse right after the device is turned on, or when power is restored to it." - icon_state = "led" - complexity = 1 - activators = list("pulse out" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - var/is_charge = FALSE - -/obj/item/integrated_circuit/passive/power/starter/make_energy() - if(assembly.battery) - if(assembly.battery.charge) - if(!is_charge) - activate_pin(1) - is_charge = TRUE - else - is_charge = FALSE - else - is_charge=FALSE - return FALSE - -// For fat machines that need fat power, like drones. -/obj/item/integrated_circuit/passive/power/relay - name = "tesla power relay" - desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them." - w_class = ITEM_SIZE_SMALL - extended_desc = "The siphon drains 50 W of power from an APC in the same room as it as long as it has charge remaining. It will always drain \ - from the 'equipment' power channel." - icon_state = "power_relay" - complexity = 7 - spawn_flags = IC_SPAWN_RESEARCH - var/power_amount = 50 - - -/obj/item/integrated_circuit/passive/power/relay/make_energy() - if(!assembly) - return - var/area/A = get_area(src) - if(A && A.powered(EQUIP) && assembly.give_power(power_amount)) - A.use_power_oneoff(power_amount, EQUIP) - // give_power() handles CELLRATE on its own. - - -// For really fat machines. -/obj/item/integrated_circuit/passive/power/relay/large - name = "large tesla power relay" - desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them, now in industrial size!" - w_class = ITEM_SIZE_LARGE - extended_desc = "The siphon drains 2 kW of power from an APC in the same room as it as long as it has charge remaining. It will always drain \ - from the 'equipment' power channel." - icon_state = "power_relay" - complexity = 15 - spawn_flags = IC_SPAWN_RESEARCH - power_amount = 1000 - - -//fuel cell -/obj/item/integrated_circuit/passive/power/chemical_cell - name = "fuel cell" - desc = "Produces electricity from chemicals." - icon_state = "chemical_cell" - extended_desc = "This is effectively an internal beaker. It will consume and produce power from hydrogen, welding fuel, carbon,\ - ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy." - atom_flags = ATOM_FLAG_OPEN_CONTAINER - complexity = 4 - inputs = list() - outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_REF) - activators = list("push ref" = IC_PINTYPE_PULSE_IN) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - var/volume = 60 - var/list/fuel = list( - /decl/material/gas/hydrogen = 50000, - /decl/material/gas/hydrogen/deuterium = 50000, - /decl/material/gas/hydrogen/tritium = 50000, - /decl/material/liquid/fuel = 15000, - /decl/material/solid/carbon = 10000, - /decl/material/liquid/ethanol = 10000, - /decl/material/liquid/nutriment = 8000 - ) - var/multi = 1 - var/lfwb =TRUE - -/obj/item/integrated_circuit/passive/power/chemical_cell/Initialize() - . = ..() - create_reagents(volume) - extended_desc +="But no fuel can be compared with blood of living human." - - -/obj/item/integrated_circuit/passive/power/chemical_cell/interact(mob/user) - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() - ..() - -/obj/item/integrated_circuit/passive/power/chemical_cell/on_reagent_change(changetype) - set_pin_data(IC_OUTPUT, 1, reagents.total_volume) - push_data() - -/obj/item/integrated_circuit/passive/power/chemical_cell/make_energy() - if(assembly) - if(assembly.battery) - var/bp = 5000 - if((assembly.battery.maxcharge-assembly.battery.charge) / CELLRATE > bp && reagents.remove_reagent(/decl/material/liquid/blood, 1)) //only blood is powerful enough to power the station(c) - assembly.give_power(bp) - for(var/I in fuel) - if((assembly.battery.maxcharge-assembly.battery.charge) / CELLRATE > fuel[I]) - if(reagents.remove_reagent(I, 1)) - assembly.give_power(fuel[I]*multi) - -/obj/item/integrated_circuit/passive/power/chemical_cell/do_work() - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() \ No newline at end of file diff --git a/code/modules/integrated_electronics/subtypes/access.dm b/code/modules/integrated_electronics/subtypes/access.dm deleted file mode 100644 index c4afb18c7a18..000000000000 --- a/code/modules/integrated_electronics/subtypes/access.dm +++ /dev/null @@ -1,76 +0,0 @@ -/obj/item/integrated_circuit/input/card_reader - name = "ID card reader" //To differentiate it from the data card reader - desc = "A circuit that can read the registred name, assignment, and PassKey string from an ID card." - icon_state = "card_reader" - - complexity = 4 - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - outputs = list( - "registered name" = IC_PINTYPE_STRING, - "assignment" = IC_PINTYPE_STRING, - "passkey" = IC_PINTYPE_STRING - ) - activators = list( - "on read" = IC_PINTYPE_PULSE_OUT - ) - -/obj/item/integrated_circuit/input/card_reader/old // adds compatibility for old TG blueprints - name = "card reader" - spawn_flags = 0 - -/obj/item/integrated_circuit/input/card_reader/attackby_react(obj/item/I, mob/living/user, intent) - var/obj/item/card/id/card = I.GetIdCard() - var/list/access = I.GetAccess() - var/json_access = json_encode(access) - var/passkey = add_data_signature(json_access) - - if(card) // An ID card. - set_pin_data(IC_OUTPUT, 1, card.registered_name) - set_pin_data(IC_OUTPUT, 2, card.assignment) - - else if(length(access)) // A non-card object that has access levels. - set_pin_data(IC_OUTPUT, 1, null) - set_pin_data(IC_OUTPUT, 2, null) - - else - return FALSE - - set_pin_data(IC_OUTPUT, 3, passkey) - user.visible_message("\The [user] swipes \the [I] onto \the [get_object()]'s card reader.") - push_data() - activate_pin(1) - return TRUE - -/obj/item/integrated_circuit/output/access_displayer - name = "access circuit" - desc = "broadcasts access for your assembly via a passkey." - extended_desc = "Useful for moving drones through airlocks." - - complexity = 4 - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - inputs = list("passkey" = IC_PINTYPE_STRING) - activators = list( - "set passkey" = IC_PINTYPE_PULSE_IN - ) - var/list/access - -/obj/item/integrated_circuit/output/access_displayer/do_work() - var/list/signature_and_data = splittext(get_pin_data(IC_INPUT, 1), ":") - if(signature_and_data.len < 2) - return - - var/signature = signature_and_data[1] - var/result = signature_and_data[2] - - // check if the signature is valid - if(!check_data_signature(signature, result)) - return FALSE - - if(length(result) > 1) - result = cached_json_decode(result) - else - result = list(result) - access = result - -/obj/item/integrated_circuit/output/access_displayer/GetAccess() - return access \ No newline at end of file diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm deleted file mode 100644 index f2b67c7bd958..000000000000 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ /dev/null @@ -1,1203 +0,0 @@ -/obj/item/integrated_circuit/input - category_text = "Input" - power_draw_per_use = 5 - -/obj/item/integrated_circuit/input/external_examine(mob/user) - var/initial_name = initial(name) - var/message - if(initial_name == name) - message = "There is \a [src]." - else - message = "There is \a ["\improper[initial_name]"] labeled '[name]'." - to_chat(user, message) - - -/obj/item/integrated_circuit/input/button - name = "button" - desc = "This tiny button must do something, right?" - icon_state = "button" - complexity = 1 - inputs = list() - outputs = list() - activators = list("on pressed" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/input/button/get_topic_data(mob/user) - return list("Press" = "press=1") - -/obj/item/integrated_circuit/input/button/OnICTopic(href_list, user) - if(href_list["press"]) - to_chat(user, "You press the button labeled '[src.displayed_name]'.") - activate_pin(1) - return IC_TOPIC_REFRESH - -/obj/item/integrated_circuit/input/toggle_button - name = "toggle button" - desc = "It toggles on, off, on, off..." - icon_state = "toggle_button" - complexity = 1 - inputs = list() - outputs = list("on" = IC_PINTYPE_BOOLEAN) - activators = list("on toggle" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/input/toggle_button/emp_act() - return // This is a mainly physical thing, not affected by electricity - -/obj/item/integrated_circuit/input/toggle_button/get_topic_data(mob/user) - return list("Toggle [get_pin_data(IC_OUTPUT, 1) ? "Off" : "On"]" = "toggle=1") - -/obj/item/integrated_circuit/input/toggle_button/OnICTopic(href_list, user) - if(href_list["toggle"]) - set_pin_data(IC_OUTPUT, 1, !get_pin_data(IC_OUTPUT, 1)) - push_data() - activate_pin(1) - to_chat(user, "You toggle the button labeled '[src.name]' [get_pin_data(IC_OUTPUT, 1) ? "on" : "off"].") - return IC_TOPIC_REFRESH - -/obj/item/integrated_circuit/input/numberpad - name = "number pad" - desc = "This small number pad allows someone to input a number into the system." - icon_state = "numberpad" - complexity = 2 - inputs = list() - outputs = list("number entered" = IC_PINTYPE_NUMBER) - activators = list("on entered" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 4 - -/obj/item/integrated_circuit/input/numberpad/get_topic_data(mob/user) - return list("Enter Number" = "enter_number=1") - -/obj/item/integrated_circuit/input/numberpad/OnICTopic(href_list, user) - if(href_list["enter_number"]) - var/new_input = input(user, "Enter a number, please.","Number pad") as null|num - if(isnum(new_input) && CanInteract(user, GLOB.physical_state)) - set_pin_data(IC_OUTPUT, 1, new_input) - push_data() - activate_pin(1) - return IC_TOPIC_REFRESH - -/obj/item/integrated_circuit/input/textpad - name = "text pad" - desc = "This small text pad allows someone to input a string into the system." - icon_state = "textpad" - complexity = 2 - inputs = list() - outputs = list("string entered" = IC_PINTYPE_STRING) - activators = list("on entered" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 4 - -/obj/item/integrated_circuit/input/textpad/get_topic_data(mob/user) - return list("Enter Words" = "enter_words=1") - -/obj/item/integrated_circuit/input/textpad/OnICTopic(href_list, user) - if(href_list["enter_words"]) - var/new_input = input(user, "Enter some words, please.","Number pad") as null|text - if(istext(new_input) && CanInteract(user, GLOB.physical_state)) - set_pin_data(IC_OUTPUT, 1, new_input) - push_data() - activate_pin(1) - return IC_TOPIC_REFRESH - -/obj/item/integrated_circuit/input/colorpad - name = "color pad" - desc = "This small color pad allows someone to input a hexadecimal color into the system." - icon_state = "colorpad" - complexity = 2 - inputs = list() - outputs = list("color entered" = IC_PINTYPE_STRING) - activators = list("on entered" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 4 - -/obj/item/integrated_circuit/input/colorpad/get_topic_data(mob/user) - return list("Enter Color" = "enter_color=1") - -/obj/item/integrated_circuit/input/colorpad/OnICTopic(href_list, user) - if(href_list["enter_color"]) - var/new_color = input(user, "Enter a color, please.", "Color", "#ffffff") as color|null - if(new_color) - set_pin_data(IC_OUTPUT, 1, new_color) - push_data() - activate_pin(1) - return IC_TOPIC_REFRESH - -/obj/item/integrated_circuit/input/med_scanner - name = "integrated medical analyser" - desc = "A very small version of the common medical analyser. This allows the machine to track some vital signs." - icon_state = "medscan" - complexity = 4 - inputs = list("target" = IC_PINTYPE_REF) - outputs = list( - "brain activity" = IC_PINTYPE_BOOLEAN, - "pulse" = IC_PINTYPE_NUMBER, - "is conscious" = IC_PINTYPE_BOOLEAN - ) - activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 40 - -/obj/item/integrated_circuit/input/med_scanner/do_work() - var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living) - if(!istype(H)) //Invalid input - return - if(H.Adjacent(get_turf(src))) // Like normal analysers, it can't be used at range. - var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] - set_pin_data(IC_OUTPUT, 1, (brain && H.stat != DEAD)) - set_pin_data(IC_OUTPUT, 2, H.get_pulse_as_number()) - set_pin_data(IC_OUTPUT, 3, (H.stat == 0)) - - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/adv_med_scanner - name = "integrated adv. medical analyser" - desc = "A very small version of the medbot's medical analyser. This allows the machine to know how healthy someone is. \ - This type is much more precise, allowing the machine to know much more about the target than a normal analyzer." - extended_desc = "Values for damage and pain are 0 to 5 marking severity of the damage" - icon_state = "medscan_adv" - complexity = 12 - inputs = list("target" = IC_PINTYPE_REF) - outputs = list( - "brain activity" = IC_PINTYPE_BOOLEAN, - "is conscious" = IC_PINTYPE_BOOLEAN, - "brute damage" = IC_PINTYPE_NUMBER, - "burn damage" = IC_PINTYPE_NUMBER, - "tox damage" = IC_PINTYPE_NUMBER, - "oxy damage" = IC_PINTYPE_NUMBER, - "clone damage" = IC_PINTYPE_NUMBER, - "pulse" = IC_PINTYPE_NUMBER, - "oxygenation level" = IC_PINTYPE_NUMBER, - "pain level" = IC_PINTYPE_NUMBER, - "radiation" = IC_PINTYPE_NUMBER - ) - activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 80 - -/obj/item/integrated_circuit/input/adv_med_scanner/proc/damage_to_severity(var/value) - if(value < 1) - return 0 - if(value < 25) - return 1 - if(value < 50) - return 2 - if(value < 75) - return 3 - if(value < 100) - return 4 - return 5 - - -/obj/item/integrated_circuit/input/adv_med_scanner/do_work() - var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living) - if(!istype(H)) //Invalid input - return - if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range.. - - - var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] - set_pin_data(IC_OUTPUT, 1, (brain && H.stat != DEAD)) - set_pin_data(IC_OUTPUT, 2, (H.stat == 0)) - set_pin_data(IC_OUTPUT, 3, damage_to_severity(100 * H.getBruteLoss() / H.maxHealth)) - set_pin_data(IC_OUTPUT, 4, damage_to_severity(100 * H.getFireLoss() / H.maxHealth)) - set_pin_data(IC_OUTPUT, 5, damage_to_severity(100 * H.getToxLoss() / H.maxHealth)) - set_pin_data(IC_OUTPUT, 6, damage_to_severity(100 * H.getOxyLoss() / H.maxHealth)) - set_pin_data(IC_OUTPUT, 7, damage_to_severity(100 * H.getCloneLoss() / H.maxHealth)) - set_pin_data(IC_OUTPUT, 8, H.get_pulse_as_number()) - set_pin_data(IC_OUTPUT, 9, H.get_blood_oxygenation()) - set_pin_data(IC_OUTPUT, 10, damage_to_severity(H.get_shock())) - set_pin_data(IC_OUTPUT, 11, H.radiation) - - push_data() - activate_pin(2) - -//please delete at a later date after people stop using the old named circuit -/obj/item/integrated_circuit/input/adv_med_scanner/old - name = "integrated advanced medical analyser" - spawn_flags = 0 - -/obj/item/integrated_circuit/input/slime_scanner - name = "slime_scanner" - desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime. Output mutation list is non-associative." - icon_state = "medscan_adv" - complexity = 12 - inputs = list("target" = IC_PINTYPE_REF) - outputs = list( - "colour" = IC_PINTYPE_STRING, - "adult" = IC_PINTYPE_BOOLEAN, - "nutrition" = IC_PINTYPE_NUMBER, - "charge" = IC_PINTYPE_NUMBER, - "health" = IC_PINTYPE_NUMBER, - "possible mutation" = IC_PINTYPE_LIST, - "genetic destability" = IC_PINTYPE_NUMBER, - "slime core amount" = IC_PINTYPE_NUMBER, - "Growth progress" = IC_PINTYPE_NUMBER, - ) - activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 80 - -/obj/item/integrated_circuit/input/slime_scanner/do_work() - var/mob/living/carbon/slime/T = get_pin_data_as_type(IC_INPUT, 1, /mob/living/carbon/slime) - if(!isslime(T)) //Invalid input - return - if(T in view(get_turf(src))) // Like medbot's analyzer it can be used in range.. - - set_pin_data(IC_OUTPUT, 1, T.colour) - set_pin_data(IC_OUTPUT, 2, T.is_adult) - set_pin_data(IC_OUTPUT, 3, T.nutrition/T.get_max_nutrition()) - set_pin_data(IC_OUTPUT, 4, T.powerlevel) - set_pin_data(IC_OUTPUT, 5, round(T.health/T.maxHealth,0.01)*100) - set_pin_data(IC_OUTPUT, 6, T.GetMutations()) - set_pin_data(IC_OUTPUT, 7, T.mutation_chance) - set_pin_data(IC_OUTPUT, 8, T.cores) - set_pin_data(IC_OUTPUT, 9, T.amount_grown/SLIME_EVOLUTION_THRESHOLD) - - - push_data() - activate_pin(2) - - - -/obj/item/integrated_circuit/input/plant_scanner - name = "integrated plant analyzer" - desc = "A very small version of the plant analyser. This allows the machine to know all valuable parameters of plants in trays. \ - It can only scan plants, not seeds or fruits." - icon_state = "medscan_adv" - complexity = 12 - inputs = list("target" = IC_PINTYPE_REF) - outputs = list( - "plant type" = IC_PINTYPE_STRING, - "age" = IC_PINTYPE_NUMBER, - "potency" = IC_PINTYPE_NUMBER, - "yield" = IC_PINTYPE_NUMBER, - "Maturation speed" = IC_PINTYPE_NUMBER, - "Production speed" = IC_PINTYPE_NUMBER, - "Endurance" = IC_PINTYPE_NUMBER, - "Lifespan" = IC_PINTYPE_NUMBER, - "Weed Resistance" = IC_PINTYPE_NUMBER, - "Weed level" = IC_PINTYPE_NUMBER, - "Pest level" = IC_PINTYPE_NUMBER, - "Water level" = IC_PINTYPE_NUMBER, - "Nutrition level" = IC_PINTYPE_NUMBER, - "harvest" = IC_PINTYPE_NUMBER, - "dead" = IC_PINTYPE_NUMBER, - "plant health" = IC_PINTYPE_NUMBER, - ) - activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 10 - -/obj/item/integrated_circuit/input/plant_scanner/do_work() - var/obj/machinery/portable_atmospherics/hydroponics/H = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/portable_atmospherics/hydroponics) - if(!istype(H)) //Invalid input - return - for(var/i=1, i<=outputs.len, i++) - set_pin_data(IC_OUTPUT, i, null) - if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range.. - if(H.seed) - set_pin_data(IC_OUTPUT, 1, H.seed.seed_name) - set_pin_data(IC_OUTPUT, 2, H.age) - set_pin_data(IC_OUTPUT, 3, H.seed.get_trait(TRAIT_POTENCY)) - set_pin_data(IC_OUTPUT, 4, H.seed.get_trait(TRAIT_YIELD)) - set_pin_data(IC_OUTPUT, 5, H.seed.get_trait(TRAIT_MATURATION)) - set_pin_data(IC_OUTPUT, 6, H.seed.get_trait(TRAIT_PRODUCTION)) - set_pin_data(IC_OUTPUT, 7, H.seed.get_trait(TRAIT_ENDURANCE)) - set_pin_data(IC_OUTPUT, 8, !!H.seed.get_trait(TRAIT_HARVEST_REPEAT)) - set_pin_data(IC_OUTPUT, 9, H.seed.get_trait(TRAIT_WEED_TOLERANCE)) - set_pin_data(IC_OUTPUT, 10, H.weedlevel) - set_pin_data(IC_OUTPUT, 11, H.pestlevel) - set_pin_data(IC_OUTPUT, 12, H.waterlevel) - set_pin_data(IC_OUTPUT, 13, H.nutrilevel) - set_pin_data(IC_OUTPUT, 14, H.harvest) - set_pin_data(IC_OUTPUT, 15, H.dead) - set_pin_data(IC_OUTPUT, 16, H.health) - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/gene_scanner - name = "gene scanner" - desc = "This circuit will scan the target plant for traits and reagent genes. Output is non-associative." - extended_desc = "This allows the machine to scan plants in trays for reagent and trait genes. \ - It can only scan plants, not seeds or fruits." - inputs = list( - "target" = IC_PINTYPE_REF - ) - outputs = list( - "reagents" = IC_PINTYPE_LIST - ) - activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) - icon_state = "medscan_adv" - spawn_flags = IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/input/gene_scanner/do_work() - var/list/greagents = list() - var/obj/machinery/portable_atmospherics/hydroponics/H = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/portable_atmospherics/hydroponics) - if(!istype(H)) //Invalid input - return - for(var/i=1, i<=outputs.len, i++) - set_pin_data(IC_OUTPUT, i, null) - if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range.. - if(H.seed) - for(var/chem_path in H.seed.chems) - var/decl/material/R = chem_path - greagents.Add(initial(R.name)) - - set_pin_data(IC_OUTPUT, 1, greagents) - push_data() - activate_pin(2) - - -/obj/item/integrated_circuit/input/examiner - name = "examiner" - desc = "It's a little machine vision system. It can return the name, description, distance, \ - relative coordinates, total amount of reagents, maximum amount of reagents, density, and opacity of the referenced object." - icon_state = "video_camera" - complexity = 6 - inputs = list( - "target" = IC_PINTYPE_REF - ) - outputs = list( - "name" = IC_PINTYPE_STRING, - "description" = IC_PINTYPE_STRING, - "X" = IC_PINTYPE_NUMBER, - "Y" = IC_PINTYPE_NUMBER, - "distance" = IC_PINTYPE_NUMBER, - "max reagents" = IC_PINTYPE_NUMBER, - "amount of reagents" = IC_PINTYPE_NUMBER, - "density" = IC_PINTYPE_BOOLEAN, - "opacity" = IC_PINTYPE_BOOLEAN, - "occupied turf" = IC_PINTYPE_REF - ) - activators = list( - "scan" = IC_PINTYPE_PULSE_IN, - "on scanned" = IC_PINTYPE_PULSE_OUT, - "not scanned" = IC_PINTYPE_PULSE_OUT - ) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 80 - -/obj/item/integrated_circuit/input/examiner/do_work() - var/atom/H = get_pin_data_as_type(IC_INPUT, 1, /atom) - var/turf/T = get_turf(src) - - if(!istype(H) || !(H in view(T))) - activate_pin(3) - else - set_pin_data(IC_OUTPUT, 1, H.name) - set_pin_data(IC_OUTPUT, 2, H.desc) - set_pin_data(IC_OUTPUT, 3, H.x-T.x) - set_pin_data(IC_OUTPUT, 4, H.y-T.y) - set_pin_data(IC_OUTPUT, 5, sqrt((H.x-T.x)*(H.x-T.x)+ (H.y-T.y)*(H.y-T.y))) - var/mr = 0 - var/tr = 0 - if(H.reagents) - mr = H.reagents.maximum_volume - tr = H.reagents.total_volume - set_pin_data(IC_OUTPUT, 6, mr) - set_pin_data(IC_OUTPUT, 7, tr) - set_pin_data(IC_OUTPUT, 8, H.density) - set_pin_data(IC_OUTPUT, 9, H.opacity) - set_pin_data(IC_OUTPUT, 10, get_turf(H)) - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/turfpoint - name = "Tile pointer" - desc = "This circuit will get a tile ref with the provided absolute coordinates." - extended_desc = "If the machine cannot see the target, it will not be able to calculate the correct direction.\ - This circuit only works while inside an assembly." - icon_state = "numberpad" - complexity = 5 - inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER) - outputs = list("tile" = IC_PINTYPE_REF) - activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 40 - -/obj/item/integrated_circuit/input/turfpoint/do_work() - if(!assembly) - activate_pin(3) - return - var/turf/T = get_turf(assembly) - var/target_x = Clamp(get_pin_data(IC_INPUT, 1), 0, world.maxx) - var/target_y = Clamp(get_pin_data(IC_INPUT, 2), 0, world.maxy) - var/turf/A = locate(target_x, target_y, T.z) - set_pin_data(IC_OUTPUT, 1, null) - if(!A || !(A in view(T))) - activate_pin(3) - return - else - set_pin_data(IC_OUTPUT, 1, weakref(A)) - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/turfscan - name = "tile analyzer" - desc = "This circuit can analyze the contents of the scanned turf, and can read letters on the turf." - icon_state = "video_camera" - complexity = 5 - inputs = list( - "target" = IC_PINTYPE_REF - ) - outputs = list( - "located ref" = IC_PINTYPE_LIST, - "Written letters" = IC_PINTYPE_STRING, - "area" = IC_PINTYPE_STRING - ) - activators = list( - "scan" = IC_PINTYPE_PULSE_IN, - "on scanned" = IC_PINTYPE_PULSE_OUT, - "not scanned" = IC_PINTYPE_PULSE_OUT - ) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 40 - cooldown_per_use = 10 - -/obj/item/integrated_circuit/input/turfscan/do_work() - var/turf/scanned_turf = get_pin_data_as_type(IC_INPUT, 1, /turf) - var/turf/circuit_turf = get_turf(src) - var/area_name = get_area_name(scanned_turf) - if(!istype(scanned_turf)) //Invalid input - activate_pin(3) - return - - if(scanned_turf in view(circuit_turf)) // This is a camera. It can't examine things that it can't see. - var/list/turf_contents = new() - for(var/obj/U in scanned_turf) - turf_contents += weakref(U) - for(var/mob/U in scanned_turf) - turf_contents += weakref(U) - set_pin_data(IC_OUTPUT, 1, turf_contents) - set_pin_data(IC_OUTPUT, 3, area_name) - var/list/St = new() - for(var/obj/effect/decal/cleanable/crayon/I in scanned_turf) - St.Add(I.icon_state) - if(St.len) - set_pin_data(IC_OUTPUT, 2, jointext(St, ",", 1, 0)) - push_data() - activate_pin(2) - else - activate_pin(3) - -/obj/item/integrated_circuit/input/local_locator - name = "local locator" - desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \ - that is holding the machine containing it." - inputs = list() - outputs = list("located ref" = IC_PINTYPE_REF, - "is ground" = IC_PINTYPE_BOOLEAN, - "is creature" = IC_PINTYPE_BOOLEAN) - activators = list("locate" = IC_PINTYPE_PULSE_IN, - "on scanned" = IC_PINTYPE_PULSE_OUT - ) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 20 - -/obj/item/integrated_circuit/input/local_locator/do_work() - var/datum/integrated_io/O = outputs[1] - O.data = null - if(assembly) - O.data = weakref(assembly.loc) - set_pin_data(IC_OUTPUT, 2, isturf(assembly.loc)) - set_pin_data(IC_OUTPUT, 3, ismob(assembly.loc)) - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/adjacent_locator - name = "adjacent locator" - desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \ - that is standing up to a meter away from the machine." - extended_desc = "The first pin requires a ref to the kind of object that you want the locator to acquire. This means that it will \ - give refs to nearby objects that are similar. If more than one valid object is found nearby, it will choose one of them at \ - random." - inputs = list("desired type ref" = IC_PINTYPE_REF) - outputs = list("located ref" = IC_PINTYPE_REF) - activators = list("locate" = IC_PINTYPE_PULSE_IN,"found" = IC_PINTYPE_PULSE_OUT, - "not found" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 30 - -/obj/item/integrated_circuit/input/adjacent_locator/do_work() - var/datum/integrated_io/I = inputs[1] - var/datum/integrated_io/O = outputs[1] - O.data = null - - if(!isweakref(I.data)) - return - var/atom/A = I.data.resolve() - if(!A) - return - var/desired_type = A.type - - var/list/nearby_things = range(1, get_turf(src)) - var/list/valid_things = list() - for(var/atom/thing in nearby_things) - if(thing.type != desired_type) - continue - valid_things.Add(thing) - if(valid_things.len) - O.data = weakref(pick(valid_things)) - activate_pin(2) - else - activate_pin(3) - O.push_data() - -/obj/item/integrated_circuit/input/advanced_locator_list - complexity = 6 - name = "list advanced locator" - desc = "This is needed for certain devices that demand list of names for a target to act upon. This type locates something \ - that is standing in given radius of up to 8 meters. Output is non-associative. Input will only consider keys if associative." - extended_desc = "The first pin requires a list of the kinds of objects that you want the locator to acquire. It will locate nearby objects by name and description, \ - and will then provide a list of all found objects which are similar. \ - The second pin is a radius." - inputs = list("desired type ref" = IC_PINTYPE_LIST, "radius" = IC_PINTYPE_NUMBER) - outputs = list("located ref" = IC_PINTYPE_LIST) - activators = list("locate" = IC_PINTYPE_PULSE_IN,"found" = IC_PINTYPE_PULSE_OUT,"not found" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 30 - var/radius = 1 - cooldown_per_use = 10 - -/obj/item/integrated_circuit/input/advanced_locator_list/on_data_written() - var/rad = get_pin_data(IC_INPUT, 2) - - if(isnum(rad)) - rad = Clamp(rad, 0, 8) - radius = rad - -/obj/item/integrated_circuit/input/advanced_locator_list/do_work() - var/datum/integrated_io/I = inputs[1] - var/datum/integrated_io/O = outputs[1] - O.data = null - var/list/input_list = list() - input_list = I.data - if(length(input_list)) //if there is no input don't do anything. - var/turf/T = get_turf(src) - var/list/nearby_things = view(radius,T) - var/list/valid_things = list() - for(var/item in input_list) - if(!isnull(item) && !isnum(item)) - if(istext(item)) - for(var/i in nearby_things) - var/atom/thing = i - if(ismob(thing) && !isliving(thing)) - continue - if(findtext(addtext(thing.name," ",thing.desc), item, 1, 0) ) - valid_things.Add(weakref(thing)) - else - var/atom/A = item - var/desired_type = A.type - for(var/i in nearby_things) - var/atom/thing = i - if(thing.type != desired_type) - continue - if(ismob(thing) && !isliving(thing)) - continue - valid_things.Add(weakref(thing)) - if(valid_things.len) - O.data = valid_things - O.push_data() - activate_pin(2) - else - O.push_data() - activate_pin(3) - else - O.push_data() - activate_pin(3) - -/obj/item/integrated_circuit/input/advanced_locator - complexity = 6 - name = "advanced locator" - desc = "This is needed for certain devices that demand a reference for a target to act upon. This type locates something \ - that is standing in given radius of up to 8 meters" - extended_desc = "The first pin requires a ref to the kind of object that you want the locator to acquire. This means that it will \ - give refs to nearby objects which are similar. If this pin is a string, the locator will search for an \ - item matching the desired text in its name and description. If more than one valid object is found nearby, it will choose one of them at \ - random. The second pin is a radius." - inputs = list("desired type" = IC_PINTYPE_ANY, "radius" = IC_PINTYPE_NUMBER) - outputs = list("located ref" = IC_PINTYPE_REF) - activators = list("locate" = IC_PINTYPE_PULSE_IN,"found" = IC_PINTYPE_PULSE_OUT,"not found" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 30 - var/radius = 1 - -/obj/item/integrated_circuit/input/advanced_locator/on_data_written() - var/rad = get_pin_data(IC_INPUT, 2) - if(isnum(rad)) - rad = Clamp(rad, 0, 8) - radius = rad - -/obj/item/integrated_circuit/input/advanced_locator/do_work() - var/datum/integrated_io/I = inputs[1] - var/datum/integrated_io/O = outputs[1] - O.data = null - var/turf/T = get_turf(src) - var/list/nearby_things = view(radius,T) - var/list/valid_things = list() - if(isweakref(I.data)) - var/atom/A = I.data.resolve() - var/desired_type = A.type - if(desired_type) - for(var/i in nearby_things) - var/atom/thing = i - if(ismob(thing) && !isliving(thing)) - continue - if(thing.type == desired_type) - valid_things.Add(thing) - else if(istext(I.data)) - var/DT = I.data - for(var/i in nearby_things) - var/atom/thing = i - if(ismob(thing) && !isliving(thing)) - continue - if(findtext(addtext(thing.name," ",thing.desc), DT, 1, 0) ) - valid_things.Add(thing) - if(valid_things.len) - O.data = weakref(pick(valid_things)) - O.push_data() - activate_pin(2) - else - O.push_data() - activate_pin(3) - -/obj/item/integrated_circuit/input/signaler - name = "integrated signaler" - desc = "Signals from a signaler can be received with this, allowing for remote control. It can also send signals." - extended_desc = "When a signal is received from another signaler, the 'on signal received' activator pin will be pulsed. \ - The two input pins are to configure the integrated signaler's settings. Note that the frequency should not have a decimal in it, \ - meaning the default frequency is expressed as 1457, not 145.7. To send a signal, pulse the 'send signal' activator pin." - icon_state = "signal" - complexity = 4 - inputs = list("frequency" = IC_PINTYPE_NUMBER,"code" = IC_PINTYPE_NUMBER) - outputs = list() - activators = list( - "send signal" = IC_PINTYPE_PULSE_IN, - "on signal sent" = IC_PINTYPE_PULSE_OUT, - "on signal received" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - action_flags = IC_ACTION_LONG_RANGE - power_draw_idle = 5 - power_draw_per_use = 40 - cooldown_per_use = 5 - var/frequency = 1357 - var/code = 30 - var/datum/radio_frequency/radio_connection - -/obj/item/integrated_circuit/input/signaler/Initialize() - . = ..() - set_pin_data(IC_INPUT, 1, frequency) - set_pin_data(IC_INPUT, 2, code) - addtimer(CALLBACK(src, .proc/set_frequency,frequency), 40) - -/obj/item/integrated_circuit/input/signaler/Destroy() - radio_controller.remove_object(src,frequency) - QDEL_NULL(radio_connection) - frequency = 0 - return ..() - -/obj/item/integrated_circuit/input/signaler/on_data_written() - var/new_freq = get_pin_data(IC_INPUT, 1) - var/new_code = get_pin_data(IC_INPUT, 2) - if(isnum(new_freq) && new_freq > 0) - set_frequency(new_freq) - code = new_code - - -/obj/item/integrated_circuit/input/signaler/do_work(var/ord) // Sends a signal. - if(!radio_connection || ord != 1) - return - - radio_connection.post_signal(src, create_signal()) - activate_pin(2) - -/obj/item/integrated_circuit/input/signaler/proc/signal_good(var/datum/signal/signal) - if(!signal || signal.source == src) - return FALSE - if(code) - var/real_code = 0 - if(isnum(code)) - real_code = code - var/rec = 0 - if(signal.encryption) - rec = signal.encryption - if(real_code != rec) - return FALSE - return TRUE - -/obj/item/integrated_circuit/input/signaler/proc/create_signal() - var/datum/signal/signal = new() - signal.transmission_method = 1 - signal.source = src - if(isnum(code)) - signal.encryption = code - signal.data["message"] = "ACTIVATE" - return signal - -/obj/item/integrated_circuit/input/signaler/proc/set_frequency(new_frequency) - if(!frequency) - return - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) - -/obj/item/integrated_circuit/input/signaler/receive_signal(datum/signal/signal) - if(!signal_good(signal)) - return 0 - treat_signal(signal) - return 1 - -//This only procs when a signal is valid. -/obj/item/integrated_circuit/input/signaler/proc/treat_signal(var/datum/signal/signal) - activate_pin(3) - -/obj/item/integrated_circuit/input/signaler/advanced - name = "advanced integrated signaler" - icon_state = "signal_advanced" - desc = "Signals from a signaler can be received with this, allowing for remote control. Additionally, it can send signals as well." - extended_desc = "When a signal is received from another signaler with the right id tag, the 'on signal received' activator pin will be pulsed and the command output is updated. \ - The two input pins are to configure the integrated signaler's settings. Note that the frequency should not have a decimal in it. \ - Meaning the default frequency is expressed as 1457, not 145.7. To send a signal, pulse the 'send signal' activator pin. Set the command output to set the message received." - complexity = 8 - inputs = list("frequency" = IC_PINTYPE_NUMBER, "id tag" = IC_PINTYPE_STRING, "command" = IC_PINTYPE_STRING) - outputs = list("received command" = IC_PINTYPE_STRING) - var/command - code = "Integrated_Circuits" - -/obj/item/integrated_circuit/input/signaler/advanced/on_data_written() - ..() - command = get_pin_data(IC_INPUT,3) - -/obj/item/integrated_circuit/input/signaler/advanced/signal_good(var/datum/signal/signal) - if(!..() || signal.data["tag"] != code) - return FALSE - return TRUE - -/obj/item/integrated_circuit/input/signaler/advanced/create_signal() - var/datum/signal/signal = new() - signal.transmission_method = 1 - signal.data["tag"] = code - signal.data["command"] = command - signal.encryption = 0 - return signal - -/obj/item/integrated_circuit/input/signaler/advanced/treat_signal(var/datum/signal/signal) - set_pin_data(IC_OUTPUT,1,signal.data["command"]) - push_data() - ..() - -/obj/item/integrated_circuit/input/teleporter_locator - name = "teleporter locator" - desc = "This circuit can locate and allow for selection of teleporter computers." - icon_state = "gps" - complexity = 5 - inputs = list() - outputs = list("teleporter" = IC_PINTYPE_REF) - activators = list("on selected" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_RESEARCH - action_flags = IC_ACTION_LONG_RANGE - -/obj/item/integrated_circuit/input/teleporter_locator/get_topic_data(mob/user) - var/datum/integrated_io/O = outputs[1] - var/obj/machinery/computer/teleporter/current_console = O.data_as_type(/obj/machinery/computer/teleporter) - - . = list() - . += "Current selection: [(current_console && current_console.id) || "None"]" - . += "Please select a teleporter to lock in on:" - for(var/obj/machinery/teleport/hub/R in SSmachines.machinery) - var/obj/machinery/computer/teleporter/com = R.com - if (istype(com, /obj/machinery/computer/teleporter) && com.locked && !com.one_time_use && com.operable() && ARE_Z_CONNECTED(get_z(src), get_z(com))) - .["[com.id] ([R.icon_state == "tele1" ? "Active" : "Inactive"])"] = "tport=[any2ref(com)]" - .["None (Dangerous)"] = "tport=random" - -/obj/item/integrated_circuit/input/teleporter_locator/OnICTopic(href_list, user) - if(href_list["tport"]) - var/output = href_list["tport"] == "random" ? null : locate(href_list["tport"]) - set_pin_data(IC_OUTPUT, 1, output && weakref(output)) - push_data() - activate_pin(1) - return IC_TOPIC_REFRESH - -//This circuit gives information on where the machine is. -/obj/item/integrated_circuit/input/gps - name = "global positioning system" - desc = "This allows you to easily know the position of a machine containing this device." - extended_desc = "The coordinates that the GPS outputs are absolute, not relative." - icon_state = "gps" - complexity = 4 - inputs = list() - outputs = list("X"= IC_PINTYPE_NUMBER, "Y" = IC_PINTYPE_NUMBER, "Z" = IC_PINTYPE_NUMBER) - activators = list("get coordinates" = IC_PINTYPE_PULSE_IN, "on get coordinates" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 30 - -/obj/item/integrated_circuit/input/gps/do_work() - var/turf/T = get_turf(src) - - set_pin_data(IC_OUTPUT, 1, null) - set_pin_data(IC_OUTPUT, 2, null) - set_pin_data(IC_OUTPUT, 3, null) - if(!T) - return - - set_pin_data(IC_OUTPUT, 1, T.x) - set_pin_data(IC_OUTPUT, 2, T.y) - set_pin_data(IC_OUTPUT, 3, T.z) - - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/microphone - name = "microphone" - desc = "Useful for spying on people, or for voice-activated machines." - extended_desc = "This will automatically translate most languages it hears to Zurich Accord Common. \ - The first activation pin is always pulsed when the circuit hears someone talk, while the second one \ - is only triggered if it hears someone speaking a language other than Zurich Accord Common." - icon_state = "recorder" - complexity = 8 - inputs = list() - obj_flags = OBJ_FLAG_CONDUCTIBLE - outputs = list( - "speaker" = IC_PINTYPE_STRING, - "message" = IC_PINTYPE_STRING - ) - activators = list("on message received" = IC_PINTYPE_PULSE_OUT, "on translation" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 5 - -/obj/item/integrated_circuit/input/microphone/Initialize() - . = ..() - GLOB.listening_objects += src - -/obj/item/integrated_circuit/input/microphone/Destroy() - GLOB.listening_objects -= src - . = ..() - -/obj/item/integrated_circuit/input/microphone/hear_talk(var/mob/living/M, text, verb, decl/language/speaking) - var/translated = TRUE - if(M && text) - if(speaking && !speaking.machine_understands) - text = speaking.scramble(text) - translated = FALSE - set_pin_data(IC_OUTPUT, 1, M.GetVoice()) - set_pin_data(IC_OUTPUT, 2, text) - - push_data() - activate_pin(1) - if(translated && !(speaking.type == /decl/language/human/common)) - activate_pin(2) - -/obj/item/integrated_circuit/input/sensor - name = "sensor" - desc = "Scans and obtains a reference for any objects or persons near you. All you need to do is shove the machine in their face." - extended_desc = "If the 'ignore storage' pin is set to true, the sensor will disregard scanning various storage containers such as backpacks." - icon_state = "recorder" - complexity = 12 - inputs = list("ignore storage" = IC_PINTYPE_BOOLEAN) - outputs = list("scanned" = IC_PINTYPE_REF) - activators = list("on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 120 - -/obj/item/integrated_circuit/input/sensor/sense(atom/A, mob/user, prox) - if(!prox || !A || (ismob(A) && !isliving(A))) - return FALSE - if(!check_then_do_work()) - return FALSE - var/ignore_bags = get_pin_data(IC_INPUT, 1) - if(ignore_bags && istype(A, /obj/item/storage/)) - return FALSE - set_pin_data(IC_OUTPUT, 1, weakref(A)) - push_data() - to_chat(user, "You scan [A] with [assembly].") - activate_pin(1) - return TRUE - -/obj/item/integrated_circuit/input/sensor/ranged - name = "ranged sensor" - desc = "Scans and obtains a reference for any objects or persons in range. All you need to do is point the machine towards the target." - extended_desc = "If the 'ignore storage' pin is set to true, the sensor will disregard scanning various storage containers such as backpacks." - icon_state = "recorder" - complexity = 36 - inputs = list("ignore storage" = IC_PINTYPE_BOOLEAN) - outputs = list("scanned" = IC_PINTYPE_REF) - activators = list("on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 120 - -/obj/item/integrated_circuit/input/sensor/ranged/sense(atom/A, mob/user) - if(!user || !A || (ismob(A) && !isliving(A))) - return FALSE - if(user.client) - if(!(A in view(user.client))) - return FALSE - else - if(!(A in view(user))) - return FALSE - if(!check_then_do_work()) - return FALSE - var/ignore_bags = get_pin_data(IC_INPUT, 1) - if(ignore_bags && istype(A, /obj/item/storage)) - return FALSE - set_pin_data(IC_OUTPUT, 1, weakref(A)) - push_data() - to_chat(user, "You scan [A] with [assembly].") - activate_pin(1) - return TRUE - -/obj/item/integrated_circuit/input/obj_scanner - name = "scanner" - desc = "Scans and obtains a reference for any objects you use on the assembly." - extended_desc = "If the 'put down' pin is set to true, the assembly will take the scanned object from your hands to its location. \ - Useful for interaction with the grabber. The scanner only works using the help intent." - icon_state = "recorder" - complexity = 4 - inputs = list("put down" = IC_PINTYPE_BOOLEAN) - outputs = list("scanned" = IC_PINTYPE_REF) - activators = list("on scanned" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 20 - -/obj/item/integrated_circuit/input/obj_scanner/attackby_react(var/atom/A,var/mob/user,intent) - if(intent!=I_HELP) - return FALSE - if(!check_then_do_work()) - return FALSE - var/pu = get_pin_data(IC_INPUT, 1) - if(pu && !user.unEquip(A,get_turf(src))) - return FALSE - set_pin_data(IC_OUTPUT, 1, weakref(A)) - push_data() - to_chat(user, "You let [assembly] scan [A].") - activate_pin(1) - return TRUE - -/obj/item/integrated_circuit/input/internalbm - name = "internal battery monitor" - desc = "This monitors the charge level of an internal battery." - icon_state = "internalbm" - extended_desc = "This circuit will give you the values of charge, max charge, and the current percentage of the internal battery on demand." - w_class = ITEM_SIZE_TINY - complexity = 1 - inputs = list() - outputs = list( - "cell charge" = IC_PINTYPE_NUMBER, - "max charge" = IC_PINTYPE_NUMBER, - "percentage" = IC_PINTYPE_NUMBER, - "refference to assembly" = IC_PINTYPE_REF, - "refference to cell" = IC_PINTYPE_REF - ) - activators = list("read" = IC_PINTYPE_PULSE_IN, "on read" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 1 - -/obj/item/integrated_circuit/input/internalbm/do_work() - set_pin_data(IC_OUTPUT, 1, null) - set_pin_data(IC_OUTPUT, 2, null) - set_pin_data(IC_OUTPUT, 3, null) - set_pin_data(IC_OUTPUT, 4, null) - set_pin_data(IC_OUTPUT, 5, null) - if(assembly) - set_pin_data(IC_OUTPUT, 4, weakref(assembly)) - if(assembly.battery) - set_pin_data(IC_OUTPUT, 1, assembly.battery.charge) - set_pin_data(IC_OUTPUT, 2, assembly.battery.maxcharge) - set_pin_data(IC_OUTPUT, 3, 100*assembly.battery.charge/assembly.battery.maxcharge) - set_pin_data(IC_OUTPUT, 5, weakref(assembly.battery)) - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/externalbm - name = "external battery monitor" - desc = "This can read the battery state of any device in view." - icon_state = "externalbm" - extended_desc = "This circuit will give you the charge, max charge, and the current percentage values of any device or battery in view." - w_class = ITEM_SIZE_TINY - complexity = 2 - inputs = list("target" = IC_PINTYPE_REF) - outputs = list( - "cell charge" = IC_PINTYPE_NUMBER, - "max charge" = IC_PINTYPE_NUMBER, - "percentage" = IC_PINTYPE_NUMBER - ) - activators = list("read" = IC_PINTYPE_PULSE_IN, "on read" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 1 - -/obj/item/integrated_circuit/input/externalbm/do_work() - - var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj) - set_pin_data(IC_OUTPUT, 1, null) - set_pin_data(IC_OUTPUT, 2, null) - set_pin_data(IC_OUTPUT, 3, null) - if(O) - var/obj/item/cell/C = O.get_cell() - if(C) - var/turf/A = get_turf(src) - if(get_turf(O) in view(A)) - set_pin_data(IC_OUTPUT, 1, C.charge) - set_pin_data(IC_OUTPUT, 2, C.maxcharge) - set_pin_data(IC_OUTPUT, 3, C.percent()) - push_data() - activate_pin(2) - return - -/obj/item/integrated_circuit/input/matscan - name = "material scanner" - desc = "This special module is designed to get information about material containers of different machinery, \ - like ORM, lathes, etc." - icon_state = "video_camera" - complexity = 6 - inputs = list( - "target" = IC_PINTYPE_REF - ) - outputs = list( - "Steel" = IC_PINTYPE_NUMBER, - "Silver" = IC_PINTYPE_NUMBER, - "Gold" = IC_PINTYPE_NUMBER, - "Diamond" = IC_PINTYPE_NUMBER, - "Uranium" = IC_PINTYPE_NUMBER, - "Plasteel" = IC_PINTYPE_NUMBER, - "Titanium" = IC_PINTYPE_NUMBER, - "Glass" = IC_PINTYPE_NUMBER, - "Plastic" = IC_PINTYPE_NUMBER, - ) - activators = list( - "scan" = IC_PINTYPE_PULSE_IN, - "on scanned" = IC_PINTYPE_PULSE_OUT, - "not scanned" = IC_PINTYPE_PULSE_OUT - ) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 40 - var/list/mtypes = list( - /decl/material/solid/metal/steel, - /decl/material/solid/metal/silver, - /decl/material/solid/metal/gold, - /decl/material/solid/gemstone/diamond, - /decl/material/solid/metal/uranium, - /decl/material/solid/metal/plasteel, - /decl/material/solid/metal/plasteel/titanium, - /decl/material/solid/glass, - /decl/material/solid/plastic - ) - -/obj/item/integrated_circuit/input/matscan/do_work() - var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj) - if(!O || !O.matter) //Invalid input - return - var/turf/T = get_turf(src) - if(O in view(T)) // This is a camera. It can't examine thngs,that it can't see. - for(var/I in 1 to mtypes.len) - var/amount = O.matter[mtypes[I]] - if(amount) - set_pin_data(IC_OUTPUT, I, amount) - else - set_pin_data(IC_OUTPUT, I, null) - push_data() - activate_pin(2) - else - activate_pin(3) - -/obj/item/integrated_circuit/input/atmospheric_analyzer - name = "atmospheric analyzer" - desc = "A miniaturized analyzer which can scan anything that contains gases. Leave target as NULL to scan the air around the assembly." - extended_desc = "The nth element of gas amounts is the number of moles of the \ - nth gas in gas list. \ - Pressure is in kPa, temperature is in Kelvin. \ - Due to programming limitations, scanning an object that does \ - not contain a gas will return the air around it instead." - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - inputs = list( - "target" = IC_PINTYPE_REF - ) - outputs = list( - "gas list" = IC_PINTYPE_LIST, - "gas amounts" = IC_PINTYPE_LIST, - "total moles" = IC_PINTYPE_NUMBER, - "pressure" = IC_PINTYPE_NUMBER, - "temperature" = IC_PINTYPE_NUMBER, - "volume" = IC_PINTYPE_NUMBER - ) - activators = list( - "scan" = IC_PINTYPE_PULSE_IN, - "on success" = IC_PINTYPE_PULSE_OUT, - "on failure" = IC_PINTYPE_PULSE_OUT - ) - power_draw_per_use = 5 - -/obj/item/integrated_circuit/input/atmospheric_analyzer/do_work() - for(var/i=1 to 6) - set_pin_data(IC_OUTPUT, i, null) - var/atom/target = get_pin_data_as_type(IC_INPUT, 1, /atom) - var/atom/movable/acting_object = get_object() - if(!target) - target = acting_object.loc - if(!target.Adjacent(acting_object)) - activate_pin(3) - return - - var/datum/gas_mixture/air_contents = target.return_air() - if(!air_contents) - activate_pin(3) - return - - var/list/gases = air_contents.gas - var/list/gas_names = list() - var/list/gas_amounts = list() - for(var/id in gases) - var/decl/material/mat = decls_repository.get_decl(id) - gas_names.Add(mat.gas_name) - gas_amounts.Add(round(gases[id], 0.001)) - - set_pin_data(IC_OUTPUT, 1, gas_names) - set_pin_data(IC_OUTPUT, 2, gas_amounts) - set_pin_data(IC_OUTPUT, 3, round(air_contents.get_total_moles(), 0.001)) - set_pin_data(IC_OUTPUT, 4, round(air_contents.return_pressure(), 0.001)) - set_pin_data(IC_OUTPUT, 5, round(air_contents.temperature, 0.001)) - set_pin_data(IC_OUTPUT, 6, round(air_contents.volume, 0.001)) - push_data() - activate_pin(2) - -/obj/item/integrated_circuit/input/data_card_reader - name = "data card reader" - desc = "A circuit that can read from and write to data cards." - extended_desc = "Setting the \"write mode\" boolean to true will cause any data cards that are used on the assembly to replace\ - their existing function and data strings with the given strings, if it is set to false then using a data card on the assembly will cause\ - the function and data strings stored on the card to be written to the output pins." - icon_state = "card_reader" - complexity = 4 - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - inputs = list( - "function" = IC_PINTYPE_STRING, - "data to store" = IC_PINTYPE_STRING, - "write mode" = IC_PINTYPE_BOOLEAN - ) - outputs = list( - "function" = IC_PINTYPE_STRING, - "stored data" = IC_PINTYPE_STRING - ) - activators = list( - "on write" = IC_PINTYPE_PULSE_OUT, - "on read" = IC_PINTYPE_PULSE_OUT - ) - -/obj/item/integrated_circuit/input/data_card_reader/attackby_react(obj/item/I, mob/living/user, intent) - var/obj/item/card/data/card = I - var/write_mode = get_pin_data(IC_INPUT, 3) - if(istype(card)) - if(write_mode == TRUE) - card.function = get_pin_data(IC_INPUT, 1) - card.data = get_pin_data(IC_INPUT, 2) - push_data() - activate_pin(1) - else - set_pin_data(IC_OUTPUT, 1, card.function) - set_pin_data(IC_OUTPUT, 2, card.data) - push_data() - activate_pin(2) - else - return FALSE - return TRUE diff --git a/code/modules/integrated_electronics/subtypes/power.dm b/code/modules/integrated_electronics/subtypes/power.dm deleted file mode 100644 index 49e5356d5bb5..000000000000 --- a/code/modules/integrated_electronics/subtypes/power.dm +++ /dev/null @@ -1,90 +0,0 @@ -/obj/item/integrated_circuit/power/ - category_text = "Power - Active" - -/obj/item/integrated_circuit/power/transmitter - name = "power transmission circuit" - desc = "This can wirelessly transmit electricity from an assembly's battery towards a nearby machine." - icon_state = "power_transmitter" - extended_desc = "This circuit transmits 5 kJ of electricity every time the activator pin is pulsed. The input pin must be \ - a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \ - inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \ - some power is lost due to ineffiency." - w_class = ITEM_SIZE_SMALL - complexity = 16 - inputs = list("target" = IC_PINTYPE_REF) - outputs = list( - "target cell charge" = IC_PINTYPE_NUMBER, - "target cell max charge" = IC_PINTYPE_NUMBER, - "target cell percentage" = IC_PINTYPE_NUMBER - ) - activators = list("transmit" = IC_PINTYPE_PULSE_IN, "on transmit" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 500 // Inefficency has to come from somewhere. - var/amount_to_move = 5000 - -/obj/item/integrated_circuit/power/transmitter/large - name = "large power transmission circuit" - desc = "This can wirelessly transmit a lot of electricity from an assembly's battery towards a nearby machine. Warning: Do not operate in flammable environments." - extended_desc = "This circuit transmits 20 kJ of electricity every time the activator pin is pulsed. The input pin must be \ - a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \ - inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \ - some power is lost due to ineffiency. Warning! Don't stack more than 1 power transmitter, as it becomes less efficient for every other \ - transmission circuit in its own assembly and other nearby ones." - w_class = ITEM_SIZE_LARGE - complexity = 32 - power_draw_per_use = 2000 - amount_to_move = 20000 - -/obj/item/integrated_circuit/power/transmitter/do_work() - - var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj) - if(!O) - return FALSE - if(istype(O, /obj/item/gun/energy)) - return FALSE - if(!assembly) - return FALSE // Pointless to do everything else if there's no battery to draw from. - var/obj/item/cell/cell = O.get_cell() - if(cell) - var/transfer_amount = amount_to_move - var/turf/A = get_turf(src) - var/turf/B = get_turf(O) - if(A.Adjacent(B)) - if(O.loc != assembly) - transfer_amount *= 0.8 // Losses due to distance. - var/transmitter_count = 0 - for(var/obj/item/integrated_circuit/power/transmitter in A.GetAllContents()) - transmitter_count++ - if(!transmitter_count) - return FALSE - transfer_amount /= transmitter_count - set_pin_data(IC_OUTPUT, 1, cell.charge) - set_pin_data(IC_OUTPUT, 2, cell.maxcharge) - set_pin_data(IC_OUTPUT, 3, cell.percent()) - activate_pin(2) - push_data() - if(cell.charge == cell.maxcharge) - return FALSE - if(transfer_amount && assembly.draw_power(amount_to_move)) // CELLRATE is already handled in draw_power() - cell.give(transfer_amount * CELLRATE) - if(istype(O, /obj/item)) - var/obj/item/I = O - I.update_icon() - return TRUE - else - set_pin_data(IC_OUTPUT, 1, null) - set_pin_data(IC_OUTPUT, 2, null) - set_pin_data(IC_OUTPUT, 3, null) - activate_pin(2) - push_data() - return FALSE - -/obj/item/integrated_circuit/power/transmitter/large/do_work() - if(..()) // If the above code succeeds, do this below. - var/atom/movable/acting_object = get_object() - if(prob(20)) - var/datum/effect/effect/system/spark_spread/s = new() - s.set_up(12, 1, src) - s.start() - acting_object.visible_message("\The [acting_object] makes some sparks!") - return TRUE diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm deleted file mode 100644 index 8dd145aad80b..000000000000 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ /dev/null @@ -1,648 +0,0 @@ -#define IC_SMOKE_REAGENTS_MINIMUM_UNITS 10 -#define IC_REAGENTS_DRAW 0 -#define IC_REAGENTS_INJECT 1 -#define IC_HEATER_MODE_HEAT "heat" -#define IC_HEATER_MODE_COOL "cool" - -/obj/item/integrated_circuit/reagent - category_text = "Reagent" - unacidable = 1 - cooldown_per_use = 10 - var/volume = 0 - -/obj/item/integrated_circuit/reagent/Initialize() - . = ..() - if(volume) - create_reagents(volume) - push_vol() - -/obj/item/integrated_circuit/reagent/proc/push_vol() - set_pin_data(IC_OUTPUT, 1, reagents.total_volume) - push_data() - -/obj/item/integrated_circuit/reagent/smoke - name = "smoke generator" - desc = "Unlike most electronics, creating smoke is completely intentional." - icon_state = "smoke" - extended_desc = "This smoke generator creates clouds of smoke on command. It can also hold liquids inside, which will go \ - into the smoke clouds when activated. The reagents are consumed when the smoke is made." - ext_cooldown = 1 - atom_flags = ATOM_FLAG_OPEN_CONTAINER - volume = 100 - - complexity = 20 - cooldown_per_use = 1 SECONDS - inputs = list() - outputs = list( - "volume used" = IC_PINTYPE_NUMBER, - "self reference" = IC_PINTYPE_REF - ) - activators = list( - "create smoke" = IC_PINTYPE_PULSE_IN, - "on smoked" = IC_PINTYPE_PULSE_OUT, - "push ref" = IC_PINTYPE_PULSE_IN - ) - spawn_flags = IC_SPAWN_RESEARCH - power_draw_per_use = 20 - var/smoke_radius = 5 - var/notified = FALSE - -/obj/item/integrated_circuit/reagent/smoke/on_reagent_change() - push_vol() - -/obj/item/integrated_circuit/reagent/smoke/do_work(ord) - switch(ord) - if(1) - if(!reagents || (reagents.total_volume < IC_SMOKE_REAGENTS_MINIMUM_UNITS)) - return - var/location = get_turf(src) - var/datum/effect/effect/system/smoke_spread/chem/S = new - S.attach(location) - playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) - if(S) - S.set_up(reagents, smoke_radius, 0, location) - if(!notified) - notified = TRUE - S.start() - reagents.clear_reagents() - activate_pin(2) - if(3) - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() - -/obj/item/integrated_circuit/reagent/injector - name = "integrated hypo-injector" - desc = "This scary looking thing is able to pump liquids into, or suck liquids out of, whatever it's pointed at." - icon_state = "injector" - extended_desc = "This autoinjector can push up to 30 units of reagents into another container or someone else outside of the machine. The target \ - must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing. Negative given amounts makes the injector suck out reagents instead." - - atom_flags = ATOM_FLAG_OPEN_CONTAINER - volume = 30 - - complexity = 20 - cooldown_per_use = 6 SECONDS - inputs = list( - "target" = IC_PINTYPE_REF, - "injection amount" = IC_PINTYPE_NUMBER - ) - inputs_default = list( - "2" = 5 - ) - outputs = list( - "volume used" = IC_PINTYPE_NUMBER, - "self reference" = IC_PINTYPE_REF - ) - activators = list( - "inject" = IC_PINTYPE_PULSE_IN, - "on injected" = IC_PINTYPE_PULSE_OUT, - "on fail" = IC_PINTYPE_PULSE_OUT, - "push ref" = IC_PINTYPE_PULSE_IN - - ) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - power_draw_per_use = 15 - var/direction_mode = IC_REAGENTS_INJECT - var/transfer_amount = 10 - var/busy = FALSE - -/obj/item/integrated_circuit/reagent/injector/on_reagent_change(changetype) - push_vol() - -/obj/item/integrated_circuit/reagent/injector/on_data_written() - var/new_amount = get_pin_data(IC_INPUT, 2) - if(new_amount < 0) - new_amount = -new_amount - direction_mode = IC_REAGENTS_DRAW - else - direction_mode = IC_REAGENTS_INJECT - if(isnum(new_amount)) - new_amount = Clamp(new_amount, 0, volume) - transfer_amount = new_amount - - -/obj/item/integrated_circuit/reagent/injector/do_work(ord) - switch(ord) - if(1) - inject() - if(4) - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() - -/obj/item/integrated_circuit/reagent/injector/proc/target_nearby(var/weakref/target) - var/mob/living/L = target.resolve() - if(!L || get_dist(src,L) > 1) - return - return L - -/obj/item/integrated_circuit/reagent/injector/proc/inject_after(var/weakref/target) - busy = FALSE - var/mob/living/L = target_nearby(target) - if(!L) - activate_pin(3) - return - var/atom/movable/acting_object = get_object() - log_admin("[key_name(L)] was successfully injected with " + reagents.get_reagents() + " by \the [acting_object]") - L.visible_message("\The [acting_object] injects [L] with its needle!", \ - "\The [acting_object] injects you with its needle!") - reagents.trans_to_mob(L, transfer_amount, CHEM_INJECT) - activate_pin(2) - -/obj/item/integrated_circuit/reagent/injector/proc/draw_after(var/weakref/target, var/amount) - busy = FALSE - var/mob/living/carbon/C = target_nearby(target) - if(!C) - activate_pin(3) - return - var/atom/movable/acting_object = get_object() - - C.visible_message("\The [acting_object] draws blood from \the [C]", - "\The [acting_object] draws blood from you." - ) - C.take_blood(src, amount) - activate_pin(2) - - -/obj/item/integrated_circuit/reagent/injector/proc/inject() - set waitfor = FALSE // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing - var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) - var/atom/movable/acting_object = get_object() - - if(busy || !check_target(AM)) - activate_pin(3) - return - - if(!AM.reagents) - activate_pin(3) - return - - if(direction_mode == IC_REAGENTS_INJECT) - if(!reagents.total_volume || !AM.reagents || !REAGENTS_FREE_SPACE(AM.reagents)) - activate_pin(3) - return - - if(isliving(AM)) - var/mob/living/L = AM - var/injection_status = L.can_inject(null, BP_CHEST) - log_world("Injection status? [injection_status]") - var/injection_delay = 3 SECONDS - if(injection_status == INJECTION_PORT) - injection_delay += INJECTION_PORT_DELAY - if(!injection_status) - activate_pin(3) - return - //Always log attemped injections for admins - log_admin("[key_name(L)] is getting injected with " + reagents.get_reagents() + " by \the [acting_object]") - L.visible_message("\The [acting_object] is trying to inject [L]!", \ - "\The [acting_object] is trying to inject you!") - busy = TRUE - addtimer(CALLBACK(src, .proc/inject_after, weakref(L)), injection_delay) - return - else - if(!ATOM_IS_OPEN_CONTAINER(AM)) - activate_pin(3) - return - - - reagents.trans_to(AM, transfer_amount) - - else if(direction_mode == IC_REAGENTS_DRAW) - if(reagents.total_volume >= reagents.maximum_volume) - acting_object.visible_message("\The [acting_object] tries to draw from [AM], but the injector is full.") - activate_pin(3) - return - - var/tramount = abs(transfer_amount) - - if(istype(AM, /mob/living/carbon)) - var/mob/living/carbon/C = AM - var/injection_status = C.can_inject(null, BP_CHEST) - var/injection_delay = 3 SECONDS - if(injection_status == INJECTION_PORT) - injection_delay += INJECTION_PORT_DELAY - if(istype(C, /mob/living/carbon/slime) || !C.dna || !injection_status) - activate_pin(3) - return - C.visible_message("\The [acting_object] is trying to take a blood sample from [C]!", \ - "\The [acting_object] is trying to take a blood sample from you!") - busy = TRUE - addtimer(CALLBACK(src, .proc/draw_after, weakref(C), tramount), injection_delay) - return - - else - if(!AM.reagents.total_volume) - acting_object.visible_message("\The [acting_object] tries to draw from [AM], but it is empty!") - activate_pin(3) - return - - if(!ATOM_IS_OPEN_CONTAINER(AM)) - activate_pin(3) - return - tramount = min(tramount, AM.reagents.total_volume) - AM.reagents.trans_to(src, tramount) - activate_pin(2) - - - -/obj/item/integrated_circuit/reagent/pump - name = "reagent pump" - desc = "Moves liquids safely inside a machine, or even nearby it." - icon_state = "reagent_pump" - extended_desc = "This is a pump which will move liquids from the source ref to the target ref. The third pin determines \ - how much liquid is moved per pulse, between 0 and 50. The pump can move reagents to any open container inside the machine, or \ - outside the machine if it is adjacent to the machine." - - complexity = 8 - inputs = list("source" = IC_PINTYPE_REF, "target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER) - inputs_default = list("3" = 5) - outputs = list() - activators = list("transfer reagents" = IC_PINTYPE_PULSE_IN, "on transfer" = IC_PINTYPE_PULSE_OUT) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - var/transfer_amount = 10 - var/direction_mode = IC_REAGENTS_INJECT - power_draw_per_use = 10 - -/obj/item/integrated_circuit/reagent/pump/on_data_written() - var/new_amount = get_pin_data(IC_INPUT, 3) - if(new_amount < 0) - new_amount = -new_amount - direction_mode = IC_REAGENTS_DRAW - else - direction_mode = IC_REAGENTS_INJECT - if(isnum(new_amount)) - new_amount = Clamp(new_amount, 0, 50) - transfer_amount = new_amount - -/obj/item/integrated_circuit/reagent/pump/do_work() - var/atom/movable/source = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) - var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 2, /atom/movable) - - // Check for invalid input. - if(!check_target(source) || !check_target(target)) - return - - // If the pump is pumping backwards, swap target and source. - if(!direction_mode) - var/temp_source = source - source = target - target = temp_source - - if(!source.reagents) - return - - if(!ATOM_IS_OPEN_CONTAINER(source)) - return - - source.reagents.trans_to(target, transfer_amount) - activate_pin(2) - -/obj/item/integrated_circuit/reagent/storage - cooldown_per_use = 1 - name = "reagent storage" - desc = "Stores liquid inside the device away from electrical components. It can store up to 60u." - icon_state = "reagent_storage" - extended_desc = "This is effectively an internal beaker." - - atom_flags = ATOM_FLAG_OPEN_CONTAINER - volume = 60 - - complexity = 4 - inputs = list() - outputs = list( - "volume used" = IC_PINTYPE_NUMBER, - "self reference" = IC_PINTYPE_REF - ) - activators = list("push ref" = IC_PINTYPE_PULSE_IN) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - - - -/obj/item/integrated_circuit/reagent/storage/do_work() - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() - -/obj/item/integrated_circuit/reagent/storage/on_reagent_change(changetype) - push_vol() - -/obj/item/integrated_circuit/reagent/storage/big - name = "big reagent storage" - icon_state = "reagent_storage_big" - desc = "Stores liquid inside the device away from electrical components. Can store up to 180u." - - volume = 180 - - complexity = 16 - spawn_flags = IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/reagent/storage/cryo - name = "cryo reagent storage" - desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. This will also prevent reactions." - icon_state = "reagent_storage_cryo" - extended_desc = "This is effectively an internal cryo beaker." - - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT - complexity = 8 - spawn_flags = IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/reagent/storage/grinder - name = "reagent grinder" - desc = "This is a reagent grinder. It accepts a ref to something, and refines it into reagents. It cannot grind materials. It can store up to 100u." - icon_state = "blender" - extended_desc = "" - inputs = list( - "target" = IC_PINTYPE_REF, - ) - outputs = list( - "volume used" = IC_PINTYPE_NUMBER, - "self reference" = IC_PINTYPE_REF - ) - activators = list( - "grind" = IC_PINTYPE_PULSE_IN, - "on grind" = IC_PINTYPE_PULSE_OUT, - "on fail" = IC_PINTYPE_PULSE_OUT, - "push ref" = IC_PINTYPE_PULSE_IN - ) - volume = 100 - power_draw_per_use = 150 - complexity = 16 - spawn_flags = IC_SPAWN_RESEARCH - - -/obj/item/integrated_circuit/reagent/storage/grinder/do_work(ord) - switch(ord) - if(1) - grind() - if(4) - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() - -/obj/item/integrated_circuit/reagent/storage/grinder/proc/grind() - if(reagents.total_volume >= reagents.maximum_volume) - activate_pin(3) - return FALSE - var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item) - - if(isnull(I)) - return FALSE - - if(!I.reagents || !I.reagents.total_volume) - activate_pin(3) - return FALSE - - I.reagents.trans_to(src,I.reagents.total_volume) - if(!I.reagents.total_volume) - qdel(I) - - activate_pin(2) - return FALSE - - - -/obj/item/integrated_circuit/reagent/storage/scan - name = "reagent scanner" - desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. On pulse this beaker will send list of contained reagents." - icon_state = "reagent_scan" - extended_desc = "Mostly useful for filtering reagents." - - complexity = 8 - outputs = list( - "volume used" = IC_PINTYPE_NUMBER, - "self reference" = IC_PINTYPE_REF, - "list of reagents" = IC_PINTYPE_LIST - ) - activators = list( - "scan" = IC_PINTYPE_PULSE_IN, - "push ref" = IC_PINTYPE_PULSE_IN - ) - spawn_flags = IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/reagent/storage/scan/do_work(ord) - switch(ord) - if(1) - var/cont[0] - for(var/rtype in reagents.reagent_volumes) - var/decl/material/RE = decls_repository.get_decl(rtype) - cont += RE.name - set_pin_data(IC_OUTPUT, 3, cont) - push_data() - if(2) - set_pin_data(IC_OUTPUT, 2, weakref(src)) - push_data() - -/obj/item/integrated_circuit/reagent/filter - name = "reagent filter" - desc = "Filters liquids by list of desired or unwanted reagents." - icon_state = "reagent_filter" - extended_desc = "This is a filter which will move liquids from the source to its target. \ - If the amount in the fourth pin is positive, it will move all reagents except those in the unwanted list. \ - If the amount in the fourth pin is negative, it will only move the reagents in the wanted list. \ - The third pin determines how many reagents are moved per pulse, between 0 and 50. Amount is given for each separate reagent." - - complexity = 8 - inputs = list( - "source" = IC_PINTYPE_REF, - "target" = IC_PINTYPE_REF, - "injection amount" = IC_PINTYPE_NUMBER, - "list of reagents" = IC_PINTYPE_LIST - ) - inputs_default = list( - "3" = 5 - ) - outputs = list() - activators = list( - "transfer reagents" = IC_PINTYPE_PULSE_IN, - "on transfer" = IC_PINTYPE_PULSE_OUT - ) - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - var/transfer_amount = 10 - var/direction_mode = IC_REAGENTS_INJECT - power_draw_per_use = 10 - -/obj/item/integrated_circuit/reagent/filter/on_data_written() - var/new_amount = get_pin_data(IC_INPUT, 3) - if(new_amount < 0) - new_amount = -new_amount - direction_mode = IC_REAGENTS_DRAW - else - direction_mode = IC_REAGENTS_INJECT - if(isnum(new_amount)) - new_amount = Clamp(new_amount, 0, 50) - transfer_amount = new_amount - -/obj/item/integrated_circuit/reagent/filter/do_work() - var/atom/movable/source = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) - var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 2, /atom/movable) - var/list/demand = get_pin_data(IC_INPUT, 4) - - // Check for invalid input. - if(!check_target(source) || !check_target(target)) - return - - if(!source.reagents || !target.reagents) - return - - if(!ATOM_IS_OPEN_CONTAINER(source) || istype(source, /mob)) - return - - if(target.reagents.maximum_volume - target.reagents.total_volume <= 0) - return - - for(var/rtype in source.reagents.reagent_volumes) - var/decl/material/G = decls_repository.get_decl(rtype) - if(!direction_mode) - if(G.name in demand) - source.reagents.trans_type_to(target, G.type, transfer_amount) - else - if(!(G.name in demand)) - source.reagents.trans_type_to(target, G.type, transfer_amount) - activate_pin(2) - push_data() - -// This is an input circuit because attackby_react is only called for input circuits -/obj/item/integrated_circuit/input/funnel - category_text = "Reagent" - name = "reagent funnel" - desc = "A funnel with a small pump that lets you refill an internal reagent storage." - icon_state = "reagent_funnel" - - inputs = list( - "target" = IC_PINTYPE_REF - ) - activators = list( - "on transfer" = IC_PINTYPE_PULSE_OUT - ) - - unacidable = 1 - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - complexity = 4 - power_draw_per_use = 5 - -/obj/item/integrated_circuit/input/funnel/attackby_react(obj/item/I, mob/living/user, intent) - var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) - var/obj/item/chems/container = I - - if(!check_target(target)) - return FALSE - - if(!istype(container)) - return FALSE - - // Messages are provided by standard_pour_into - if(container.standard_pour_into(user, target)) - activate_pin(1) - return TRUE - - return FALSE - -// Most of this is just chemical heater code refitted for ICs -/obj/item/integrated_circuit/reagent/temp - inputs = list( - "target temperature" = IC_PINTYPE_NUMBER - ) - outputs = list( - "volume used" = IC_PINTYPE_NUMBER, - "temperature" = IC_PINTYPE_NUMBER, - "enabled" = IC_PINTYPE_BOOLEAN, - "self reference" = IC_PINTYPE_REF - ) - activators = list( - "toggle" = IC_PINTYPE_PULSE_IN, - "on toggle" = IC_PINTYPE_PULSE_OUT, - "push ref" = IC_PINTYPE_PULSE_IN - ) - - atom_flags = ATOM_FLAG_OPEN_CONTAINER - complexity = 12 - cooldown_per_use = 1 - power_draw_per_use = 50 - volume = 30 - - var/active = 0 - var/min_temp = 40 CELSIUS - var/max_temp = 200 CELSIUS - var/heating_power = 5 - var/target_temp = T20C - var/last_temperature = 0 - var/mode = IC_HEATER_MODE_HEAT - -/obj/item/integrated_circuit/reagent/temp/Initialize() - . = ..() - - set_pin_data(IC_OUTPUT, 2, temperature - T0C) - push_data() - -/obj/item/integrated_circuit/reagent/temp/do_work(ord) - switch(ord) - if(1) - target_temp = get_pin_data(IC_INPUT, 1) - if(isnull(target_temp)) - return - - // +/- T0C to convert to/from kelvin - target_temp = Clamp(target_temp + T0C, min_temp, max_temp) - set_pin_data(IC_INPUT, 1, target_temp - T0C) - - active = !active - set_pin_data(IC_OUTPUT, 3, active) - push_data() - activate_pin(2) - - // begin processing temperature - if(active) - QUEUE_TEMPERATURE_ATOMS(src) - if(3) - set_pin_data(IC_OUTPUT, 4, weakref(src)) - push_data() - -/obj/item/integrated_circuit/reagent/temp/on_reagent_change() - push_vol() - -/obj/item/integrated_circuit/reagent/temp/power_fail() - active = 0 - -/obj/item/integrated_circuit/reagent/temp/ProcessAtomTemperature() - if(!active) - return PROCESS_KILL - - last_temperature = temperature - - if(mode == IC_HEATER_MODE_HEAT && temperature < target_temp) - temperature = min(temperature + heating_power, max_temp) - else if(mode == IC_HEATER_MODE_COOL && temperature > target_temp) - temperature = max(temperature - heating_power, min_temp) - - if(temperature != last_temperature) - // Lost power - if(!check_power()) - power_fail() - return ..() - - set_pin_data(IC_OUTPUT, 2, temperature - T0C) - push_data() - - return TRUE - -/obj/item/integrated_circuit/reagent/temp/heater - name = "reagent heater" - desc = "A small reagent container capable of heating reagents. It can hold up to 30u." - icon_state = "reagent_heater" - extended_desc = "This is effectively an internal beaker. It has a heating coil wrapped around it, which allows it to heat the contents of the beaker. Temperature is given in celsius." - - spawn_flags = IC_SPAWN_RESEARCH - -/obj/item/integrated_circuit/reagent/temp/cooler - name = "reagent cooler" - desc = "A small reagent container capable of cooling reagents. It can hold up to 30u." - icon_state = "reagent_cooler" - extended_desc = "This is effectively an internal beaker. It has a cooling mechanism wrapped around it, which allows it to cool the contents of the beaker. Temperature is given in celsius." - - spawn_flags = IC_SPAWN_RESEARCH - - min_temp = -80 CELSIUS - max_temp = 30 CELSIUS - mode = IC_HEATER_MODE_COOL - -#undef IC_HEATER_MODE_HEAT -#undef IC_HEATER_MODE_COOL -#undef IC_REAGENTS_DRAW -#undef IC_REAGENTS_INJECT \ No newline at end of file diff --git a/code/modules/interactions/_interactions.dm b/code/modules/interactions/_interactions.dm new file mode 100644 index 000000000000..1898e27ee8c4 --- /dev/null +++ b/code/modules/interactions/_interactions.dm @@ -0,0 +1,52 @@ +/decl/interaction_handler + abstract_type = /decl/interaction_handler + var/name + /// A string displayed when examining an atom that provides this handler as an alt interaction. + var/examine_desc + /// If set to TRUE, alt interactions will skip is_possible() before displaying in examined_by(). + var/always_show_on_examine = FALSE + var/icon + var/icon_state + var/expected_target_type = /atom + var/expected_user_type = /mob/living + var/interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION + var/incapacitation_flags + var/apply_click_cooldown = DEFAULT_ATTACK_COOLDOWN + +/decl/interaction_handler/proc/is_possible(var/atom/target, var/mob/user, var/obj/item/prop) + + SHOULD_CALL_PARENT(TRUE) + + if(QDELETED(target) || QDELETED(user)) + return FALSE + + if(expected_user_type && !istype(user, expected_user_type)) + return FALSE + + if(expected_target_type && !istype(target, expected_target_type)) + return FALSE + + if(isturf(target) || isturf(target.loc)) + if(interaction_flags & INTERACTION_NEEDS_INVENTORY) + return FALSE + else + if(interaction_flags & INTERACTION_NEEDS_TURF) + return FALSE + + // CanPhysicallyInteract() checks Adjacent() so doing it twice is redundant. + if(interaction_flags & INTERACTION_NEEDS_PHYSICAL_INTERACTION) + if(!CanPhysicallyInteractWith(user, target)) + return FALSE + else if((interaction_flags & INTERACTION_NEEDS_ADJACENCY) && !user.Adjacent(target)) + return FALSE + + // CanPhysicallyInteract() also checks default incapacitation, so don't set + // incapacitation_flags unless needed. + if(incapacitation_flags && user.incapacitated(incapacitation_flags)) + return FALSE + + return TRUE + +/decl/interaction_handler/proc/invoked(atom/target, mob/user, obj/item/prop) + SHOULD_CALL_PARENT(FALSE) + PRINT_STACK_TRACE("Alt interaction handler called with no invoked logic defined: [type]") diff --git a/code/modules/interactions/interactions_atom.dm b/code/modules/interactions/interactions_atom.dm new file mode 100644 index 000000000000..980172b26b27 --- /dev/null +++ b/code/modules/interactions/interactions_atom.dm @@ -0,0 +1,34 @@ +/atom/proc/try_handle_interactions(var/mob/user, var/list/interactions, var/obj/item/prop, var/check_alt_interactions) + + if(!length(interactions)) + return FALSE + + var/list/possibilities + for(var/interaction_type in interactions) + var/decl/interaction_handler/interaction = GET_DECL(interaction_type) + if(interaction.is_possible(src, user, prop)) + var/image/label = image(interaction.icon, interaction.icon_state) + label.name = interaction.name + LAZYSET(possibilities, interaction, label) + + if(!length(possibilities)) + return FALSE + + var/decl/interaction_handler/choice = possibilities[1] + if(length(possibilities) > 1 || (choice.interaction_flags & INTERACTION_NEVER_AUTOMATIC)) + choice = null + choice = show_radial_menu(user, src, possibilities, use_labels = RADIAL_LABELS_CENTERED) + if(!istype(choice) || QDELETED(user) || QDELETED(src)) + return TRUE + // This is not ideal but I don't want to pass a callback through here as a param and call it. :( + var/list/new_interactions = check_alt_interactions ? get_alt_interactions(user) : get_standard_interactions(user) + if(!(choice.type in new_interactions)) + return TRUE + if(!choice.is_possible(src, user, user.get_active_held_item())) + return TRUE + + user.face_atom(src) + choice.invoked(src, user, prop) + if(choice.apply_click_cooldown) + user.setClickCooldown(choice.apply_click_cooldown) + return TRUE diff --git a/code/modules/interactions/interactions_reagents.dm b/code/modules/interactions/interactions_reagents.dm new file mode 100644 index 000000000000..213da09980da --- /dev/null +++ b/code/modules/interactions/interactions_reagents.dm @@ -0,0 +1,153 @@ +/decl/interaction_handler/dip_item + name = "Dip Into" + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEVER_AUTOMATIC + examine_desc = "dip an item into $TARGET_THEM$" + +/decl/interaction_handler/dip_item/is_possible(atom/target, mob/user, obj/item/prop) + return ..() && target != prop && REAGENT_TOTAL_VOLUME(target.reagents) >= FLUID_MINIMUM_TRANSFER && istype(prop) && target.can_be_poured_from(user, prop) + +/decl/interaction_handler/dip_item/invoked(atom/target, mob/user, obj/item/prop) + user.visible_message(SPAN_NOTICE("\The [user] dips \the [prop] into \the [target.reagents.get_primary_reagent_name()].")) + if(istype(prop, /obj/item/food) && isobj(target)) + var/obj/target_obj = target + var/transferring = min(target_obj.get_food_default_transfer_amount(user), REAGENTS_FREE_SPACE(prop.reagents)) + if(transferring) + target.reagents.trans_to_holder(prop.reagents, transferring) + if(REAGENT_TOTAL_VOLUME(target.reagents) >= FLUID_MINIMUM_TRANSFER) + prop.fluid_act(target.reagents) + return TRUE + +/decl/interaction_handler/fill_from + name = "Fill From" + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEVER_AUTOMATIC + examine_desc = "fill a held item from $TARGET_THEM$" + +/decl/interaction_handler/fill_from/is_possible(atom/target, mob/user, obj/item/prop) + if(!(. = ..())) + return + if(target == prop || REAGENT_TOTAL_VOLUME(target.reagents) < FLUID_PUDDLE) + return FALSE + if(!istype(prop) || (!isitem(target) && !istype(target, /obj/structure))) + return FALSE + if(istype(target, /obj/structure)) + var/obj/structure/struct = target + if(isnull(struct.get_possible_reagent_transfer_amounts())) + return FALSE // Not a dispenser + return target.can_be_poured_from(user, prop) && prop.can_be_poured_into(user, target) + +/decl/interaction_handler/fill_from/invoked(atom/target, mob/user, obj/item/prop) + if(isitem(target)) + var/obj/item/vessel = target + return vessel.standard_pour_into(user, prop) + if(istype(target, /obj/structure)) + // Reagent dispensers have some wonky assumptions due to old UX around filling/emptying so we skip the atom flags check. + return prop.standard_dispenser_refill(user, target, skip_container_check = TRUE) + return FALSE + +/decl/interaction_handler/empty_into + name = "Pour Into" + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEVER_AUTOMATIC + examine_desc = "pour a held item into $TARGET_THEM$" + +/decl/interaction_handler/empty_into/is_possible(atom/target, mob/user, obj/item/prop) + if(!(. = ..())) + return + if(target == prop || !istype(prop) || REAGENT_TOTAL_VOLUME(prop.reagents) <= 0) + return FALSE + return target.can_be_poured_into(user, prop) && prop.can_be_poured_from(user, target) + +/decl/interaction_handler/empty_into/invoked(atom/target, mob/user, obj/item/prop) + prop.standard_pour_into(user, target) + return TRUE + +/decl/interaction_handler/wash_hands + name = "Wash Hands" + expected_target_type = /atom + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEVER_AUTOMATIC + examine_desc = "wash your hands in $TARGET_THEM$" + +/decl/interaction_handler/wash_hands/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && !istype(prop) && target?.reagents?.has_reagent(/decl/material/liquid/water, 150) + if(.) + for(var/hand_slot in user.get_held_item_slots()) + var/obj/item/organ/external/organ = user.get_organ(hand_slot) + if(istype(organ) && organ.is_washable) + return TRUE + +/decl/interaction_handler/wash_hands/invoked(atom/target, mob/user, obj/item/prop) + + // Probably needs debounce and do_after() but showers and wading into water don't, so whatever. + if(!target?.reagents?.has_reagent(/decl/material/liquid/water, 150)) // To avoid washing your hands in beakers. + to_chat(user, SPAN_WARNING("\The [src] doesn't have enough water in it to wash your hands.")) + return + + var/found_hand = FALSE + for(var/hand_slot in user.get_held_item_slots()) + var/obj/item/organ/external/organ = user.get_organ(hand_slot) + if(istype(organ) && organ.is_washable) + found_hand = TRUE + break + + if(!found_hand) + return FALSE + + var/decl/pronouns/pronouns = user.get_pronouns() + if(isturf(target)) + var/turf/turf = target + var/fluid = turf.get_fluid_name() + user.visible_message( + SPAN_NOTICE("\The [user] washes [pronouns.his] hands in \the [fluid]."), + SPAN_NOTICE("You wash your hands in \the [fluid].") + ) + else + user.visible_message( + SPAN_NOTICE("\The [user] washes [pronouns.his] hands in \the [target]."), + SPAN_NOTICE("You wash your hands in \the [target].") + ) + + user.clean() + playsound(user.loc, 'sound/effects/slosh.ogg', 25, 1) + return TRUE + +/decl/interaction_handler/drink + name = "Drink" + expected_target_type = /atom + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEVER_AUTOMATIC + examine_desc = "drink from $TARGET_THEM$" + +/decl/interaction_handler/drink/is_possible(atom/target, mob/user, obj/item/prop) + return ..() && !istype(prop) && target.can_drink_from(user) + +/decl/interaction_handler/drink/invoked(atom/target, mob/user, obj/item/prop) + + // Items can be picked up and drunk from, this interaction is for turfs and structures. + if(istype(target, /obj/item)) + return + + if(!user.check_has_mouth()) + target.show_food_no_mouth_message(user, user) + return + + if(!REAGENT_TOTAL_VOLUME(target?.reagents)) + target.show_food_empty_message(user, EATING_METHOD_DRINK) + return + + if(!user.can_eat_food_currently(null, user, EATING_METHOD_DRINK)) + return + + var/blocked = user.check_mouth_coverage() + if(blocked) + to_chat(user, SPAN_NOTICE("\The [blocked] is in the way!")) + return + + var/fluid_name = "\the [target]" + if(isturf(target)) + var/turf/target_turf = target + fluid_name = "\the [target_turf.get_fluid_name()]" + + user.visible_message( + SPAN_NOTICE("\The [user] drinks from [fluid_name]."), + SPAN_NOTICE("You drink from [fluid_name].") + ) + target.reagents.trans_to_mob(user, 5, CHEM_INGEST) + playsound(user.loc, 'sound/items/drink.ogg', rand(10, 50), 1) diff --git a/code/modules/interactions/interactions_shared.dm b/code/modules/interactions/interactions_shared.dm new file mode 100644 index 000000000000..b8f50f151132 --- /dev/null +++ b/code/modules/interactions/interactions_shared.dm @@ -0,0 +1,32 @@ +/decl/interaction_handler/remove_disk + abstract_type = /decl/interaction_handler/remove_disk + name = "Eject Disk" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject" + examine_desc = "remove a disk" + +/decl/interaction_handler/set_transfer + name = "Set Transfer Amount" + abstract_type = /decl/interaction_handler/set_transfer + examine_desc = "set the transfer amount" + +/decl/interaction_handler/remove_id + name = "Remove ID" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject_id" + abstract_type = /decl/interaction_handler/remove_id + examine_desc = "remove an ID card" + +/decl/interaction_handler/remove_pen + name = "Remove Pen" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject_pen" + abstract_type = /decl/interaction_handler/remove_pen + examine_desc = "remove a pen" + +/decl/interaction_handler/rename + name = "Rename" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_rename" + abstract_type = /decl/interaction_handler/rename + examine_desc = "rename $TARGET_THEM$" diff --git a/code/modules/item_effects/_item_effect.dm b/code/modules/item_effects/_item_effect.dm new file mode 100644 index 000000000000..54199b3584da --- /dev/null +++ b/code/modules/item_effects/_item_effect.dm @@ -0,0 +1,76 @@ +/decl/item_effect + abstract_type = /decl/item_effect + +/decl/item_effect/proc/do_process_effect(obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/can_do_strike_effect(mob/user, obj/item/item, atom/target, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/do_strike_effect(mob/user, obj/item/item, atom/target, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/can_do_parried_effect(mob/user, obj/item/item, parried, atom/attacker, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/do_parried_effect(mob/user, obj/item/item, parried, atom/attacker, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/can_do_used_effect(mob/user, obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/do_used_effect(mob/user, obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/can_do_wielded_effect(mob/user, obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/do_wielded_effect(mob/user, obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/can_do_unwielded_effect(mob/user, obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/do_unwielded_effect(mob/user, obj/item/item, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/can_do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/apply_icon_appearance_to(obj/item/item) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/apply_onmob_appearance_to(obj/item/item, mob/user, bodytype, image/overlay, slot, bodypart) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/hear_speech(obj/item/item, mob/user, message, decl/language/speaking) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/on_examined(obj/item/item, mob/user, distance, list/parameters) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/decl/item_effect/proc/modify_attack_damage(base_damage, obj/item/used_item, mob/user, dry_run, list/parameters) + return base_damage + +/decl/item_effect/proc/expend_attack_use(obj/item/used_item, mob/user, dry_run, list/parameters) + return diff --git a/code/modules/item_effects/item_effect_charges.dm b/code/modules/item_effects/item_effect_charges.dm new file mode 100644 index 000000000000..ff68fdb348eb --- /dev/null +++ b/code/modules/item_effects/item_effect_charges.dm @@ -0,0 +1,24 @@ +/decl/item_effect/charges + var/effect_descriptor + abstract_type = /decl/item_effect/charges + +/decl/item_effect/charges/do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + var/charges = (LAZYACCESS(parameters, IE_PAR_USES) || 0) + if(charges <= 0) + return FALSE + item.set_item_effect_parameter(src, IE_CAT_RANGED, IE_PAR_USES, charges-1) + return TRUE + +/decl/item_effect/charges/on_examined(obj/item/item, mob/user) + to_chat(user, SPAN_NOTICE("\The [item] has [item.get_item_effect_parameter(src, IE_CAT_RANGED, IE_PAR_USES) || 0] charge\s of [effect_descriptor] left.")) + +// Example effect; casts a fireball n times. +/decl/item_effect/charges/fireball + effect_descriptor = "fireball" +/decl/item_effect/charges/fireball/can_do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + return TRUE +/decl/item_effect/charges/fireball/do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + . = ..() + if(.) + var/obj/item/projectile/fireball/projectile = new(get_turf(user)) + projectile.launch_from_gun(target, user.get_target_zone(), user) diff --git a/code/modules/item_effects/item_effect_debug.dm b/code/modules/item_effects/item_effect_debug.dm new file mode 100644 index 000000000000..ae834c4bf2c5 --- /dev/null +++ b/code/modules/item_effects/item_effect_debug.dm @@ -0,0 +1,76 @@ +/decl/item_effect/debug/can_do_strike_effect(mob/user, obj/item/item, atom/target, list/parameters) + return TRUE +/decl/item_effect/debug/do_strike_effect(mob/user, obj/item/item, atom/target, list/parameters) + log_debug("[type]: [user] struck [target] with [item] ([json_encode(args)])") + +/decl/item_effect/debug/can_do_parried_effect(mob/user, obj/item/item, parried, atom/attacker, list/parameters) + return TRUE +/decl/item_effect/debug/do_parried_effect(mob/user, obj/item/item, parried, atom/attacker, list/parameters) + log_debug("[type]: [user] parried [parried] from [attacker] with [item] ([json_encode(args)])") + +/decl/item_effect/debug/can_do_used_effect(mob/user, obj/item/item, list/parameters) + return TRUE +/decl/item_effect/debug/do_used_effect(mob/user, obj/item/item, list/parameters) + log_debug("[type]: [user] used [item] ([json_encode(args)])") + +/decl/item_effect/debug/can_do_wielded_effect(mob/user, obj/item/item, list/parameters) + return TRUE +/decl/item_effect/debug/do_wielded_effect(mob/user, obj/item/item, list/parameters) + log_debug("[type]: [user] wielded [item] ([json_encode(args)])") + +/decl/item_effect/debug/can_do_unwielded_effect(mob/user, obj/item/item, list/parameters) + return TRUE +/decl/item_effect/debug/do_unwielded_effect(mob/user, obj/item/item, list/parameters) + log_debug("[type]: [user] unwielded [item] ([json_encode(args)])") + +/decl/item_effect/debug/can_do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + return TRUE +/decl/item_effect/debug/do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) + log_debug("[type]: [user] did ranged attack on [target] with [item] ([json_encode(args)])") + +/decl/item_effect/debug/apply_icon_appearance_to(obj/item/item) + log_debug("[type]: [item] updated appearance ([json_encode(args)])") + +/decl/item_effect/debug/apply_onmob_appearance_to(obj/item/item, mob/user, bodytype, image/overlay, slot, bodypart) + log_debug("[type]: [user] updated onmob appearance for [item] in [slot] for [bodytype]/[bodypart] ([json_encode(args)])") + +/decl/item_effect/debug/hear_speech(obj/item/item, mob/user, message, decl/language/speaking) + log_debug("[type]: [item] heard [user] say [message] in [speaking] ([json_encode(args)])") + +/decl/item_effect/debug/on_examined(obj/item/item, mob/user) + log_debug("[type]: [user] examined [item] ([json_encode(args)])") + +/decl/item_effect/debug/do_process_effect(obj/item/item, list/parameters) + log_debug("[type]: [item] processed ([json_encode(args)])") + +/obj/item/sword/katana/debug/Initialize() + . = ..() + add_item_effect(/decl/item_effect/debug, list( + (IE_CAT_VISUAL) = list("vis" = "ual"), + (IE_CAT_STRIKE) = list("foo" = "bar"), + (IE_CAT_PARRY) = list("fizz" = "buzz"), + (IE_CAT_USED) = list("aard" = "vark"), + (IE_CAT_EXAMINE) = list("ooo" = "aaa"), + (IE_CAT_LISTENER) = list("walla walla" = "bing bong"), + (IE_CAT_PROCESS) = list("hyonk" = "hjonk") + )) + add_item_effect(/decl/item_effect/charges/fireball, list( + (IE_CAT_EXAMINE), + (IE_CAT_RANGED) = list(IE_PAR_USES = 5) + )) + add_item_effect(/decl/item_effect/mob_modifier/regeneration, list( + (IE_CAT_EXAMINE), + (IE_CAT_WIELDED) + )) + +/obj/item/staff/crystal/beacon/fireball + name = "staff of fireball" + material = /decl/material/solid/organic/wood/ebony + matter = list(/decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE) + +/obj/item/staff/crystal/beacon/fireball/Initialize(ml, material_key) + . = ..() + add_item_effect(/decl/item_effect/charges/fireball, list( + (IE_CAT_EXAMINE), + (IE_CAT_RANGED) = list(IE_PAR_USES = 5) + )) \ No newline at end of file diff --git a/code/modules/item_effects/item_effect_item.dm b/code/modules/item_effects/item_effect_item.dm new file mode 100644 index 000000000000..197c22d8a01f --- /dev/null +++ b/code/modules/item_effects/item_effect_item.dm @@ -0,0 +1,206 @@ +/obj/item + var/list/_item_effects + +/obj/item/proc/has_item_effect(decl/item_effect/effect, effect_category) + if(!length(_item_effects)) + return FALSE + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect)) + return FALSE + return LAZYISIN(LAZYACCESS(_item_effects, effect_category), effect) + +/obj/item/proc/add_item_effect(effect_type, list/effect_parameters) + if(!effect_type || !length(effect_parameters)) + return FALSE + var/decl/item_effect/effect = ispath(effect_type) ? GET_DECL(effect_type) : effect_type + if(!istype(effect)) + return FALSE + LAZYINITLIST(_item_effects) + for(var/effect_category in effect_parameters) + LAZYSET(_item_effects[effect_category], effect, (effect_parameters[effect_category] || TRUE)) + . = TRUE + + if(.) + if(IE_CAT_LISTENER in effect_parameters) + global.listening_objects |= src + if(IE_CAT_PROCESS in effect_parameters) + SSitem_effects.queued_items |= src + +/obj/item/proc/remove_item_effect(decl/item_effect/effect) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects)) + return FALSE + var/list/removed_effect_categories = list() + for(var/effect_category in _item_effects) + if(LAZYISIN(_item_effects[effect_category], effect)) + _item_effects[effect_category] -= effect + if(!length(_item_effects[effect_category])) + removed_effect_categories |= effect_category + LAZYREMOVE(_item_effects, effect_category) + . = TRUE + if(.) + if(IE_CAT_LISTENER in removed_effect_categories) + global.listening_objects -= src + if(IE_CAT_PROCESS in removed_effect_categories) + SSitem_effects.queued_items -= src + +/obj/item/proc/get_item_effect_parameters(decl/item_effect/effect, effect_category) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category) + return null + var/list/effects = LAZYACCESS(_item_effects, effect_category) + return LAZYACCESS(effects, effect) + +/obj/item/proc/get_item_effect_parameter(decl/item_effect/effect, effect_category, parameter_name) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category || !parameter_name) + return null + var/list/effects = LAZYACCESS(_item_effects, effect_category) + if(!LAZYISIN(effects, effect)) + return null + return LAZYACCESS(effects[effect], parameter_name) + +/obj/item/proc/set_item_effect_parameter(decl/item_effect/effect, effect_category, parameter_name, parameter_value) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category || !parameter_name) + return FALSE + var/list/effects = LAZYACCESS(_item_effects, effect_category) + if(!LAZYISIN(effects, effect)) + return FALSE + LAZYSET(effects[effect], parameter_name, parameter_value) + return TRUE + +/obj/item/proc/get_item_effects(effect_category) + return length(_item_effects) ? LAZYACCESS(_item_effects, effect_category) : null + +// STRIKE effects +/obj/item/resolve_attackby(atom/A, mob/user, var/click_params) + if(!(. = ..())) + return + var/list/item_effects = get_item_effects(IE_CAT_STRIKE) + if(!length(item_effects)) + return + if(!istype(user) || QDELETED(user) || QDELETED(src)) + return + for(var/decl/item_effect/strike_effect as anything in item_effects) + var/list/parameters = item_effects[strike_effect] + if(strike_effect.can_do_strike_effect(user, src, A, parameters)) + strike_effect.do_strike_effect(user, src, A, parameters) + +// PARRY effects +/obj/item/on_parry(mob/user, damage_source, mob/attacker) + . = ..() + var/list/item_effects = get_item_effects(IE_CAT_PARRY) + if(!length(item_effects)) + return + if(!istype(user) || QDELETED(user) || QDELETED(src)) + return + for(var/decl/item_effect/parry_effect as anything in item_effects) + var/list/parameters = item_effects[parry_effect] + if(parry_effect.can_do_parried_effect(user, src, damage_source, attacker, parameters)) + parry_effect.do_parried_effect(user, src, damage_source, attacker, parameters) + . = TRUE + +// VISUAL effects (world icon) +/obj/item/on_update_icon() + . = ..() + var/list/item_effects = get_item_effects(IE_CAT_VISUAL) + if(!length(item_effects)) + return + for(var/decl/item_effect/used_effect as anything in item_effects) + used_effect.apply_icon_appearance_to(src, item_effects[used_effect]) + +// VISUAL effects (onmob) +/obj/item/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + // TODO: this might need work to handle items that do a state or appearance update in the parent call. + if(overlay) + var/list/item_effects = get_item_effects(IE_CAT_VISUAL) + if(length(item_effects)) + for(var/decl/item_effect/used_effect as anything in item_effects) + used_effect.apply_onmob_appearance_to(src, user_mob, bodytype, overlay, slot, bodypart, item_effects[used_effect]) + . = ..() + +// USED effects +/obj/item/attack_self(mob/user) + if((. = ..())) + return + var/list/item_effects = get_item_effects(IE_CAT_USED) + if(!length(item_effects)) + return + if(!istype(user) || QDELETED(user) || QDELETED(src)) + return + for(var/decl/item_effect/used_effect as anything in item_effects) + var/list/parameters = item_effects[used_effect] + if(used_effect.can_do_used_effect(user, src, parameters)) + used_effect.do_used_effect(user, src, parameters) + . = TRUE + +// WIELD effects (unwielded) +/obj/item/dropped(mob/user) + . = ..() + var/list/item_effects = get_item_effects(IE_CAT_WIELDED) + if(!length(item_effects)) + return + if(!istype(user) || QDELETED(user) || QDELETED(src)) + return + for(var/decl/item_effect/wield_effect as anything in item_effects) + var/list/parameters = item_effects[wield_effect] + if(wield_effect.can_do_unwielded_effect(user, src, parameters)) + wield_effect.do_unwielded_effect(user, src, parameters) + +// WIELD effects (wielded) +/obj/item/equipped(mob/user, slot) + . = ..() + var/list/item_effects = get_item_effects(IE_CAT_WIELDED) + if(!length(item_effects)) + return + if(!istype(user) || QDELETED(user) || QDELETED(src) || loc != user || !(slot in user.get_held_item_slots())) + return + for(var/decl/item_effect/wield_effect as anything in item_effects) + var/list/parameters = item_effects[wield_effect] + if(wield_effect.can_do_wielded_effect(user, src, parameters)) + wield_effect.do_wielded_effect(user, src, parameters) + +// LISTENING effects +/obj/item/hear_talk(mob/M, text, verb, decl/language/speaking) + . = ..() + var/list/item_effects = get_item_effects(IE_CAT_LISTENER) + if(!length(item_effects)) + return + for(var/decl/item_effect/listening_effect as anything in item_effects) + listening_effect.hear_speech(src, M, text, speaking) + +// VISIBLE effects +/obj/item/examined_by(mob/user, distance, infix, suffix) + . = ..() + if(!user) + return + var/list/item_effects = get_item_effects(IE_CAT_EXAMINE) + if(!length(item_effects)) + return + for(var/decl/item_effect/examine_effect as anything in item_effects) + examine_effect.on_examined(src, user, distance, item_effects[examine_effect]) + +// RANGED effects +/obj/item/afterattack(turf/floor/target, mob/user, proximity) + if((. = ..()) || proximity) + return + var/list/item_effects = get_item_effects(IE_CAT_RANGED) + if(!length(item_effects)) + return + for(var/decl/item_effect/ranged_effect as anything in item_effects) + var/list/parameters = item_effects[ranged_effect] + if(ranged_effect.can_do_ranged_effect(user, src, target, parameters)) + ranged_effect.do_ranged_effect(user, src, target, parameters) + +// PROCESS effects +/obj/item/proc/process_item_effects() + var/list/item_effects = get_item_effects(IE_CAT_PROCESS) + if(length(item_effects)) + for(var/decl/item_effect/process_effect as anything in item_effects) + process_effect.do_process_effect(src, item_effects[process_effect]) diff --git a/code/modules/item_effects/item_effect_modifier.dm b/code/modules/item_effects/item_effect_modifier.dm new file mode 100644 index 000000000000..4535ccf073a1 --- /dev/null +++ b/code/modules/item_effects/item_effect_modifier.dm @@ -0,0 +1,27 @@ +/decl/item_effect/mob_modifier + abstract_type = /decl/item_effect/mob_modifier + var/modifier_archetype + +/decl/item_effect/mob_modifier/can_do_wielded_effect(mob/user, obj/item/item, list/parameters) + return !!modifier_archetype + +/decl/item_effect/mob_modifier/do_wielded_effect(mob/user, obj/item/item, list/parameters) + if(!user.has_mob_modifier(modifier_archetype, source = src)) + user.add_mob_modifier(modifier_archetype, source = item) + return TRUE + +/decl/item_effect/mob_modifier/can_do_unwielded_effect(mob/user, obj/item/item, list/parameters) + return !!modifier_archetype + +/decl/item_effect/mob_modifier/do_unwielded_effect(mob/user, obj/item/item, list/parameters) + if(user.has_mob_modifier(modifier_archetype, source = src)) + user.remove_mob_modifier(modifier_archetype, source = src) + return TRUE + +/decl/item_effect/mob_modifier/on_examined(obj/item/item, mob/user) + var/decl/mob_modifier/archetype = GET_DECL(modifier_archetype) + to_chat(user, SPAN_NOTICE("\The [item] grants \a [archetype] to the wielder.")) + +// Example effect; applies a regeneration modifier. +/decl/item_effect/mob_modifier/regeneration + modifier_archetype = /decl/mob_modifier/regeneration/item diff --git a/code/modules/item_worth/_helpers.dm b/code/modules/item_worth/_helpers.dm deleted file mode 100644 index 8841debc67a8..000000000000 --- a/code/modules/item_worth/_helpers.dm +++ /dev/null @@ -1,3 +0,0 @@ -//Workaround by Ginja due to the fact initial(parent_type) does not work. - -#define PARENT(x) text2path(replacetext("[x]", regex("/\[^/\]+$"), "")) \ No newline at end of file diff --git a/code/modules/keybindings/_defines.dm b/code/modules/keybindings/_defines.dm new file mode 100644 index 000000000000..f80cbd168bd1 --- /dev/null +++ b/code/modules/keybindings/_defines.dm @@ -0,0 +1,8 @@ +#define CATEGORY_CLIENT "CLIENT" +#define CATEGORY_ADMIN "ADMIN" +#define CATEGORY_MOB "MOB" +#define CATEGORY_LIVING "LIVING" +#define CATEGORY_HUMAN "HUMAN" +#define CATEGORY_MISC "MISC" +#define CATEGORY_MOVEMENT "MOVEMENT" +#define CATEGORY_COMMUNICATION "COMMUNICATION" diff --git a/code/modules/keybindings/_keybindings.dm b/code/modules/keybindings/_keybindings.dm new file mode 100644 index 000000000000..67710245b909 --- /dev/null +++ b/code/modules/keybindings/_keybindings.dm @@ -0,0 +1,31 @@ +/datum/keybinding + abstract_type = /datum/keybinding + /// A default hotkey keys. + var/list/hotkey_keys + /// A classic hotkey keys when client don't use hotkey mode. Uses `hotkey_keys` if not defined. + var/list/classic_keys + + // TODO: convert to /decl/keybinding, replace name with uid and full_name with name + /// A unique keybind id for preference storing. + var/name + /// A full keybind name for displaying. + var/full_name + /// A bit informative description what this keybind does. + var/description + + /// A keybind category for sorting in preference menu. + var/category = CATEGORY_MISC + +/datum/keybinding/New() + // Default keys to the master "hotkey_keys" + if(LAZYLEN(hotkey_keys) && !LAZYLEN(classic_keys)) + classic_keys = hotkey_keys.Copy() + +/datum/keybinding/proc/down(client/user) + return FALSE + +/datum/keybinding/proc/up(client/user) + return FALSE + +/datum/keybinding/proc/can_use(client/user) + return TRUE diff --git a/code/modules/keybindings/bindings_atom.dm b/code/modules/keybindings/bindings_atom.dm new file mode 100644 index 000000000000..aaed1a9fbe1d --- /dev/null +++ b/code/modules/keybindings/bindings_atom.dm @@ -0,0 +1,32 @@ +// You might be wondering why this isn't client level. If focus is null, we don't want you to move. +// Only way to do that is to tie the behavior into the focus's keyLoop(). + +/atom/movable/keyLoop(client/user) + var/movement_dir = 0 + for(var/_key in user.keys_held) + movement_dir = movement_dir | user.movement_keys[_key] + if(user.next_move_dir_add) + movement_dir |= user.next_move_dir_add + if(user.next_move_dir_sub) + movement_dir &= ~user.next_move_dir_sub + // Sanity checks in case you hold left and right and up to make sure you only go up + if((movement_dir & NORTH) && (movement_dir & SOUTH)) + movement_dir &= ~(NORTH|SOUTH) + if((movement_dir & EAST) && (movement_dir & WEST)) + movement_dir &= ~(EAST|WEST) + + if(!get_config_value(/decl/config/toggle/on/allow_diagonal_movement)) + if(movement_dir & user.last_move_dir_pressed) + movement_dir = user.last_move_dir_pressed + else + movement_dir = FIRST_DIR(movement_dir) + + if(movement_dir) //If we're not moving, don't compensate, as byond will auto-fill dir otherwise + movement_dir = turn(movement_dir, -dir2angle(user.dir)) //By doing this we ensure that our input direction is offset by the client (camera) direction + if(user.movement_locked) + keybind_face_direction(movement_dir) + else + user.Move(get_step(src, movement_dir), movement_dir) + + user.next_move_dir_add = 0 + user.next_move_dir_sub = 0 diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm new file mode 100644 index 000000000000..cafe738137b0 --- /dev/null +++ b/code/modules/keybindings/bindings_client.dm @@ -0,0 +1,104 @@ +// Clients aren't datums so we have to define these procs indpendently. +// These verbs are called for all key press and release events +/client/verb/keyDown(_key as text) + set hidden = TRUE + + // So here's some eplaination why we use `instant`. + // Due of verbs nature, you can use the same verb limited time per tick. + // This means, you unable to perform combinated keypresses at the same time. + // (i.e multiple movement key press for diagonal direction move) + // (or ShiftF5 where we press two different keys at the same time) + // In current case, we should make this verb instant. + set instant = TRUE + + if(!user_acted(src, "was just autokicked for flooding keysends; likely abuse but potentially lagspike.")) + return + + ///Check if the key is short enough to even be a real key + if(LAZYLEN(_key) > MAX_KEYPRESS_COMMANDLENGTH) + to_chat(src, SPAN_DANGER("Invalid KeyDown detected! You have been disconnected from the server automatically.")) + log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") + message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") + qdel(src) + return + + //Focus Chat failsafe. Overrides movement checks to prevent WASD. + if(!prefs.hotkeys && length(_key) == 1 && _key != "Alt" && _key != "Ctrl" && _key != "Shift") + winset(src, null, "outputwindow.input.focus=true ; input.text=[url_encode(_key)]") + return + + if(length(keys_held) >= HELD_KEY_BUFFER_LENGTH && !keys_held[_key]) + keyUp(keys_held[1]) //We are going over the number of possible held keys, so let's remove the first one. + + //the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking + keys_held[_key] = world.time + if(!movement_locked) + var/movement = movement_keys[_key] + if(!(next_move_dir_sub & movement)) + next_move_dir_add |= movement + + if(movement && !get_config_value(/decl/config/toggle/on/allow_diagonal_movement)) + last_move_dir_pressed = movement + + // Client-level keybindings are ones anyone should be able to do at any time + // Things like taking screenshots, hitting tab, and adminhelps. + var/AltMod = keys_held["Alt"] ? "Alt" : "" + var/CtrlMod = keys_held["Ctrl"] ? "Ctrl" : "" + var/ShiftMod = keys_held["Shift"] ? "Shift" : "" + var/full_key + switch(_key) + if("Alt", "Ctrl", "Shift") + full_key = "[AltMod][CtrlMod][ShiftMod]" + else + if(AltMod || CtrlMod || ShiftMod) + full_key = "[AltMod][CtrlMod][ShiftMod][_key]" + key_combos_held[_key] = full_key + else + _key = capitalize(_key) + full_key = _key + var/keycount = 0 + for(var/kb_name in prefs.key_bindings[full_key]) + keycount++ + var/datum/keybinding/kb = global.keybindings_by_name[kb_name] + if(kb.can_use(src) && kb.down(src) && keycount >= MAX_COMMANDS_PER_KEY) + break + + holder?.key_down(full_key, src) + mob.key_down(full_key, src) + + mob.update_mouse_pointer() + +/client/verb/keyUp(_key as text) + set instant = TRUE + set hidden = TRUE + + var/key_combo = key_combos_held[_key] + if(key_combo) + key_combos_held -= _key + keyUp(key_combo) + + if(!keys_held[_key]) + return + + keys_held -= _key + + if(!movement_locked) + var/movement = movement_keys[_key] + if(!(next_move_dir_add & movement)) + next_move_dir_sub |= movement + + // We don't do full key for release, because for mod keys you + // can hold different keys and releasing any should be handled by the key binding specifically + for (var/kb_name in prefs.key_bindings[_key]) + var/datum/keybinding/kb = global.keybindings_by_name[kb_name] + if(kb.can_use(src) && kb.up(src)) + break + holder?.key_up(_key, src) + mob.key_up(_key, src) + + mob.update_mouse_pointer() + +// Called every game tick +/client/keyLoop() + holder?.keyLoop(src) + mob?.keyLoop(src) diff --git a/code/modules/keybindings/binds/admin.dm b/code/modules/keybindings/binds/admin.dm new file mode 100644 index 000000000000..23a6d425f974 --- /dev/null +++ b/code/modules/keybindings/binds/admin.dm @@ -0,0 +1,96 @@ +/datum/keybinding/admin + abstract_type = /datum/keybinding/admin + category = CATEGORY_ADMIN + +/datum/keybinding/admin/can_use(client/user) + return !!user.holder + +/datum/keybinding/admin/mod_say + hotkey_keys = list("F5") + name = "mod_say" + full_name = "Mod Say" + description = "Talk with other moderators." + +/datum/keybinding/admin/mod_say/down(client/user) + user.cmd_mod_say(input(user, null, "dsay \"text\"") as text|null) + return TRUE + +/datum/keybinding/admin/admin_say + hotkey_keys = list("ShiftF5") + name = "admin_say" + full_name = "Admin Say" + description = "Talk with other admins." + +/datum/keybinding/admin/admin_say/down(client/user) + user.cmd_admin_say(input(user, null, "asay \"text\"") as text|null) + return TRUE + +/datum/keybinding/admin/admin_ghost + hotkey_keys = list("F6") + name = "admin_ghost" + full_name = "Aghost" + description = "Go ghost" + +/datum/keybinding/admin/admin_ghost/down(client/user) + user.admin_ghost() + return TRUE + +/datum/keybinding/admin/list_players + hotkey_keys = list("F7") + name = "list_players" + full_name = "List Players" + description = "Opens up the list players panel" + +/datum/keybinding/admin/list_players/down(client/user) + user.holder.list_players() + return TRUE + +/datum/keybinding/admin/admin_pm + hotkey_keys = list("F8") + name = "admin_pm" + full_name = "Admin PM" + description = "Sends Admin PM message" + +/datum/keybinding/admin/admin_pm/down(client/user) + user.cmd_admin_pm_panel() + return TRUE + +/datum/keybinding/admin/invisimin + hotkey_keys = list("F9") + name = "invisimin" + full_name = "Admin Invisibility" + description = "Toggles ghost-like invisibility (Don't abuse this)" + +/datum/keybinding/admin/invisimin/down(client/user) + user.invisimin() + return TRUE + +/datum/keybinding/admin/dead_say + hotkey_keys = list("F10") + name = "dead_say" + full_name = "Dead Say" + description = "Allows you to send a message to dead chat" + +/datum/keybinding/admin/dead_say/down(client/user) + user.dsay(input(src, null, "dsay \"text\"") as text|null) + return TRUE + +/datum/keybinding/admin/deadmin + hotkey_keys = list("Unbound") + name = "deadmin" + full_name = "De-Admin" + description = "Shed your admin powers" + +/datum/keybinding/admin/deadmin/down(client/user) + user.deadmin_self() + return TRUE + +/datum/keybinding/admin/readmin + hotkey_keys = list("Unbound") + name = "readmin" + full_name = "Re-Admin" + description = "Regain your admin powers" + +/datum/keybinding/admin/readmin/down(client/user) + user.readmin_self() + return TRUE diff --git a/code/modules/keybindings/binds/client.dm b/code/modules/keybindings/binds/client.dm new file mode 100644 index 000000000000..8e1cc489b6e6 --- /dev/null +++ b/code/modules/keybindings/binds/client.dm @@ -0,0 +1,53 @@ +/datum/keybinding/client + abstract_type = /datum/keybinding/client + category = CATEGORY_CLIENT + +/datum/keybinding/client/hotkey_mode + hotkey_keys = list("Tab") + name = "hotkey_mode" + full_name = "Toggle Hotkeys" + +/datum/keybinding/client/hotkey_mode/down(client/user) + if(user.prefs) + user.prefs.hotkeys = !user.prefs.hotkeys + if(user.prefs.hotkeys) + winset(user, null, "outputwindow.input.background-color=[COLOR_INPUT_DISABLED];mapwindow.map.focus=true") + else + winset(user, null, "outputwindow.input.background-color=[COLOR_INPUT_ENABLED];outputwindow.input.focus=true") + return TRUE + +/datum/keybinding/client/admin_help + hotkey_keys = list("F1") + name = "admin_help" + full_name = "Admin Help" + description = "Ask an admin for help" + +/datum/keybinding/client/screenshot + hotkey_keys = list("Unbound") + name = "screenshot" + full_name = "Save screenshot as..." + description = "Take a screenshot" + +/datum/keybinding/client/screenshot/down(client/user) + winset(user, null, "command=.screenshot") + return TRUE + +/datum/keybinding/client/toggle_fullscreen + hotkey_keys = list("F11") + name = "toggle_fullscreen" + full_name = "Toggle Fullscreen" + description = "Toggles fullscreen mode" + +/datum/keybinding/client/toggle_fullscreen/down(client/user) + user.cycle_preference(/datum/client_preference/fullscreen_mode) + return TRUE + +/datum/keybinding/client/fit_viewport + hotkey_keys = list("ShiftF11") + name = "fit_viewport" + full_name = "Fit Viewport" + description = "Fits your viewport" + +/datum/keybinding/client/fit_viewport/down(client/user) + user.fit_viewport() + return TRUE diff --git a/code/modules/keybindings/binds/communication.dm b/code/modules/keybindings/binds/communication.dm new file mode 100644 index 000000000000..7f1b6f76ac72 --- /dev/null +++ b/code/modules/keybindings/binds/communication.dm @@ -0,0 +1,23 @@ +/datum/keybinding/client/communication + abstract_type = /datum/keybinding/client/communication + category = CATEGORY_COMMUNICATION + +/datum/keybinding/client/communication/ooc + hotkey_keys = list("O", "F2") + name = "ooc" + full_name = "Out Of Character Say (OOC)" + +/datum/keybinding/client/communication/looc + hotkey_keys = list("L") + name = "looc" + full_name = "Local Out Of Character Say (LOOC)" + +/datum/keybinding/client/communication/say + hotkey_keys = list("T", "F3") + name = "say" + full_name = "IC Say" + +/datum/keybinding/client/communication/me + hotkey_keys = list("M", "F4") + name = "me" + full_name = "Custom Emote (/Me)" diff --git a/code/modules/keybindings/binds/human.dm b/code/modules/keybindings/binds/human.dm new file mode 100644 index 000000000000..cc283c2f1580 --- /dev/null +++ b/code/modules/keybindings/binds/human.dm @@ -0,0 +1,67 @@ +/datum/keybinding/human + abstract_type = /datum/keybinding/human + category = CATEGORY_HUMAN + +/datum/keybinding/human/can_use(client/user) + return ishuman(user.mob) + +/datum/keybinding/human/quick_equip + hotkey_keys = list("E") + name = "quick_equip" + full_name = "Quick Equip" + description = "Quickly puts an item in the best slot available" + +/datum/keybinding/human/quick_equip/down(client/user) + var/mob/living/human/H = user.mob + H.quick_equip() + return TRUE + +/datum/keybinding/human/holster + hotkey_keys = list("H") + name = "holster" + full_name = "Holster" + description = "Draw or holster weapon" + +/datum/keybinding/human/holster/down(client/user) + var/mob/living/human/H = user.mob + if(H.incapacitated()) + return + + var/obj/item/clothing/U = H.get_equipped_item(slot_w_uniform_str) + if(istype(U)) + for(var/obj/S in U.accessories) + if(istype(S, /obj/item/clothing/webbing/holster)) + var/datum/extension/holster/E = get_extension(S, /datum/extension/holster) + if(!E.holstered) + if(!H.get_active_held_item()) + to_chat(H, SPAN_WARNING("You're not holding anything to holster.")) + return + E.holster(H.get_active_held_item(), H) + else + E.unholster(H, TRUE) + return + + var/obj/item/belt/holster/B = H.get_equipped_item(slot_belt_str) + if(istype(B)) + var/datum/extension/holster/E = get_extension(B, /datum/extension/holster) + if(!E.holstered) + if(!H.get_active_held_item()) + to_chat(H, SPAN_WARNING("You're not holding anything to holster.")) + return + E.holster(H.get_active_held_item(), H) + else + E.unholster(H, TRUE) + return + + return TRUE + +/datum/keybinding/human/give + hotkey_keys = list("G") + name = "give_item" + full_name = "Give Item" + description = "Give the item you're currently holding" + +/datum/keybinding/human/give/down(client/user) + var/mob/living/human/H = user.mob + H.give() + return TRUE diff --git a/code/modules/keybindings/binds/living.dm b/code/modules/keybindings/binds/living.dm new file mode 100644 index 000000000000..7f9ba3530a2c --- /dev/null +++ b/code/modules/keybindings/binds/living.dm @@ -0,0 +1,28 @@ +/datum/keybinding/living + abstract_type = /datum/keybinding/living + category = CATEGORY_LIVING + +/datum/keybinding/living/can_use(client/user) + return isliving(user.mob) + +/datum/keybinding/living/rest + hotkey_keys = list("ShiftB") + name = "rest" + full_name = "Rest" + description = "You lay down/get up" + +/datum/keybinding/living/rest/down(client/user) + var/mob/living/L = user.mob + L.lay_down() + return TRUE + +/datum/keybinding/living/resist + hotkey_keys = list("B") + name = "resist" + full_name = "Resist" + description = "Break free of your current state. Handcuffed? On fire? Resist!" + +/datum/keybinding/living/resist/down(client/user) + var/mob/living/L = user.mob + L.resist() + return TRUE diff --git a/code/modules/keybindings/binds/mob.dm b/code/modules/keybindings/binds/mob.dm new file mode 100644 index 000000000000..73a6bc128a75 --- /dev/null +++ b/code/modules/keybindings/binds/mob.dm @@ -0,0 +1,185 @@ +/datum/keybinding/mob + abstract_type = /datum/keybinding/mob + category = CATEGORY_MOB + +/datum/keybinding/mob/can_use(client/user) + return ismob(user.mob) + +/datum/keybinding/mob/toggle_throw_mode + hotkey_keys = list("R", "Southwest") + name = "toggle_throw_mode" + full_name = "Toggle Throw mode" + description = "Toggle throwing the current item or not." + +/datum/keybinding/mob/toggle_throw_mode/down(client/user) + user.toggle_throw_mode_verb() + return TRUE + +/datum/keybinding/mob/hold_throw_mode + hotkey_keys = list("Space") + name = "hold_throw_mode" + full_name = "Hold throw mode" + description = "Hold this to turn on throw mode, and release it to turn off throw mode" + +/datum/keybinding/mob/hold_throw_mode/down(client/user) + user.mob.toggle_throw_mode(TRUE) + return TRUE + +/datum/keybinding/mob/hold_throw_mode/up(client/user) + user.mob.toggle_throw_mode(FALSE) + return TRUE + +/datum/keybinding/mob/swap_hands + hotkey_keys = list("X", "Northeast") + name = "swap_hands" + full_name = "Swap Hands" + +/datum/keybinding/mob/swap_hands/down(client/user) + user.mob.swap_hand() + return TRUE + +/datum/keybinding/mob/drop_item + hotkey_keys = list("Q", "Northwest") + name = "drop_item" + full_name = "Drop Item" + +/datum/keybinding/mob/drop_item/down(client/user) + user.mob.drop_item() + return TRUE + +/datum/keybinding/mob/select_help_intent + hotkey_keys = list("1") + name = "select_help_intent" + full_name = "Select Help Intent" + +/datum/keybinding/mob/select_help_intent/down(client/user) + user.mob.set_intent(I_FLAG_HELP) + return TRUE + +/datum/keybinding/mob/select_disarm_intent + hotkey_keys = list("2") + name = "select_disarm_intent" + full_name = "Select Disarm Intent" + +/datum/keybinding/mob/select_disarm_intent/down(client/user) + user.mob.set_intent(I_FLAG_DISARM) + return TRUE + +/datum/keybinding/mob/select_grab_intent + hotkey_keys = list("3") + name = "select_grab_intent" + full_name = "Select Grab Intent" + +/datum/keybinding/mob/select_grab_intent/down(client/user) + user.mob.set_intent(I_FLAG_GRAB) + return TRUE + +/datum/keybinding/mob/select_harm_intent + hotkey_keys = list("4") + name = "select_harm_intent" + full_name = "Select Harm Intent" + +/datum/keybinding/mob/select_harm_intent/down(client/user) + user.mob.set_intent(I_FLAG_HARM) + return TRUE + +/datum/keybinding/mob/cycle_intent_right + hotkey_keys = list("G", "Insert") + name = "cycle_intent_right" + full_name = "Сycle Intent: Right" + +/datum/keybinding/mob/cycle_intent_right/down(client/user) + user.mob.cycle_intent(INTENT_HOTKEY_RIGHT) + return TRUE + +/datum/keybinding/mob/cycle_intent_left + hotkey_keys = list("F") + name = "cycle_intent_left" + full_name = "Сycle Intent: Left" + +/datum/keybinding/mob/cycle_intent_left/down(client/user) + user.mob.cycle_intent(INTENT_HOTKEY_LEFT) + return TRUE + +/datum/keybinding/mob/activate_inhand + hotkey_keys = list("Z", "Y","Southeast") // Southeast = PAGEDOWN + name = "activate_inhand" + full_name = "Activate In-Hand" + description = "Uses whatever item you have inhand" + +/datum/keybinding/mob/activate_inhand/down(client/user) + user.mob.mode() + return TRUE + +/datum/keybinding/mob/target_head_cycle + hotkey_keys = list("Numpad8") + name = "target_head_cycle" + full_name = "Target: Cycle Head" + +/datum/keybinding/mob/target_head_cycle/down(client/user) + user.body_toggle_head() + return TRUE + +/datum/keybinding/mob/target_r_arm + hotkey_keys = list("Numpad4") + name = "target_r_arm" + full_name = "Target: Right Arm" + +/datum/keybinding/mob/target_r_arm/down(client/user) + user.body_r_arm() + return TRUE + +/datum/keybinding/mob/target_body_chest + hotkey_keys = list("Numpad5") + name = "target_body_chest" + full_name = "Target: Body" + +/datum/keybinding/mob/target_body_chest/down(client/user) + user.body_chest() + return TRUE + +/datum/keybinding/mob/target_left_arm + hotkey_keys = list("Numpad6") + name = "target_left_arm" + full_name = "Target: Left Arm" + +/datum/keybinding/mob/target_left_arm/down(client/user) + user.body_l_arm() + return TRUE + +/datum/keybinding/mob/target_right_leg + hotkey_keys = list("Numpad1") + name = "target_right_leg" + full_name = "Target: Right leg" + +/datum/keybinding/mob/target_right_leg/down(client/user) + user.body_r_leg() + return TRUE + +/datum/keybinding/mob/target_body_groin + hotkey_keys = list("Numpad2") + name = "target_body_groin" + full_name = "Target: Groin" + +/datum/keybinding/mob/target_body_groin/down(client/user) + user.body_groin() + return TRUE + +/datum/keybinding/mob/target_left_leg + hotkey_keys = list("Numpad3") + name = "target_left_leg" + full_name = "Target: Left Leg" + +/datum/keybinding/mob/target_left_leg/down(client/user) + user.body_l_leg() + return TRUE + +/datum/keybinding/mob/minimal_hud + hotkey_keys = list("F12") + name = "minimal_hud" + full_name = "Minimal HUD" + description = "Hide most HUD features" + +/datum/keybinding/mob/minimal_hud/down(client/user) + user.mob.minimize_hud() + return TRUE diff --git a/code/modules/keybindings/binds/movement.dm b/code/modules/keybindings/binds/movement.dm new file mode 100644 index 000000000000..78e1b4417c86 --- /dev/null +++ b/code/modules/keybindings/binds/movement.dm @@ -0,0 +1,79 @@ +/datum/keybinding/movement + abstract_type = /datum/keybinding/movement + category = CATEGORY_MOVEMENT + +/datum/keybinding/movement/north + hotkey_keys = list("W", "North") + classic_keys = list("North") + name = "north" + full_name = "Move North" + description = "Moves your character north" + +/datum/keybinding/movement/south + hotkey_keys = list("S", "South") + classic_keys = list("South") + name = "south" + full_name = "Move South" + description = "Moves your character south" + +/datum/keybinding/movement/west + hotkey_keys = list("A", "West") + classic_keys = list("West") + name = "west" + full_name = "Move West" + description = "Moves your character left" + +/datum/keybinding/movement/east + hotkey_keys = list("D", "East") + classic_keys = list("East") + name = "east" + full_name = "Move East" + description = "Moves your character east" + +/datum/keybinding/movement/prevent_movement + hotkey_keys = list("Ctrl") + name = "block_movement" + full_name = "Block movement" + description = "Prevents you from moving" + +/datum/keybinding/movement/prevent_movement/down(client/user) + user.movement_locked = TRUE + return TRUE + +/datum/keybinding/movement/prevent_movement/up(client/user) + user.movement_locked = FALSE + return TRUE + +/datum/keybinding/movement/move_up + hotkey_keys = list(",") + name = "move_up" + full_name = "Move Up" + description = "Makes you go up" + +/datum/keybinding/movement/move_up/down(client/user) + user.mob.move_up() + return TRUE + +/datum/keybinding/movement/move_down + hotkey_keys = list(".") + name = "move_down" + full_name = "Move Down" + description = "Makes you go down" + +/datum/keybinding/movement/move_down/down(client/user) + user.mob.move_down() + return TRUE + +/datum/keybinding/movement/move_quickly + hotkey_keys = list("Shift") + name = "moving_quickly" + full_name = "Move Quickly" + description = "Makes you move quickly" + +/datum/keybinding/movement/move_quickly/down(client/user) + user.setmovingquickly() + return TRUE + +/datum/keybinding/movement/move_quickly/up(client/user) + user.setmovingslowly() + return TRUE diff --git a/code/modules/keybindings/readme.md b/code/modules/keybindings/readme.md new file mode 100644 index 000000000000..008135bba340 --- /dev/null +++ b/code/modules/keybindings/readme.md @@ -0,0 +1,40 @@ +# In-code keypress handling system + +This whole system is heavily based off of forum_account's keyboard library. +Thanks to forum_account for saving the day, the library can be found +[here](https://secure.byond.com/developer/Forum_account/Keyboard)! + +.dmf macros have some very serious shortcomings. For example, they do not allow reusing parts +of one macro in another, so giving cyborgs their own shortcuts to swap active module couldn't +inherit the movement that all mobs should have anyways. The webclient only supports one macro, +so having more than one was problematic. Additionally each keybind has to call an actual +verb, which meant a lot of hidden verbs that just call one other proc. Also our existing +macro was really bad and tied unrelated behavior into `Northeast()`, `Southeast()`, `Northwest()`, +and `Southwest()`. + +The basic premise of this system is to not screw with .dmf macro setup at all and handle +pressing those keys in the code instead. We have every key call `client.keyDown()` +or `client.keyUp()` with the pressed key as an argument. Certain keys get processed +directly by the client because they should be doable at any time, then we call +`keyDown()` or `keyUp()` on the client's holder and the client's mob's focus. +By default `mob.focus` is the mob itself, but you can set it to any datum to give control of a +client's keypresses to another object. This would be a good way to handle a menu or driving +a mech. You can also set it to null to disregard input from a certain user. + +Movement is handled by having each client call `client.keyLoop()` every game tick. +As above, this calls holder and `focus.keyLoop()`. `atom/movable/keyLoop()` handles movement +Try to keep the calculations in this proc light. It runs every tick for every client after all! + +You can also tell which keys are being held down now. Each client a list of keys pressed called +`keys_held`. Each entry is a key as a text string associated with the world.time when it was +pressed. + +Notes about certain keys: + +* `Tab` has client-sided behavior but acts normally +* `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away. +* `\` needs to be escaped in the dmf so any usage is `\\` + +You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up +events. They happen outside of a byond tick and have no meaning there. Key looping +works correctly since it's part of a subsystem, not direct input. diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm new file mode 100644 index 000000000000..846dd32d3ad9 --- /dev/null +++ b/code/modules/keybindings/setup.dm @@ -0,0 +1,69 @@ +// Set a client's focus to an object and override these procs on that object to let it handle keypresses + +/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially + return +/datum/proc/key_up(key, client/user) // Called when a key is released + return +/datum/proc/keyLoop(client/user) // Called once every frame + set waitfor = FALSE + return + +// removes all the existing macros +/client/proc/erase_all_macros() + var/erase_output = "" + var/list/macro_set = params2list(winget(src, "default.*", "command")) // The third arg doesnt matter here as we're just removing them all + for(var/k in 1 to length(macro_set)) + var/list/split_name = splittext(macro_set[k], ".") + var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command" + erase_output = "[erase_output];[macro_name].parent=null" + winset(src, null, erase_output) + +/client/proc/set_macros() + set waitfor = FALSE + + //Reset the buffer + reset_held_keys() + + erase_all_macros() + + var/list/macro_set = SSinput.macro_set + for(var/k in 1 to length(macro_set)) + var/key = macro_set[k] + var/command = macro_set[key] + winset(src, "default-\ref[key]", "parent=default;name=[key];command=[command]") + + if(prefs?.hotkeys) + winset(src, null, "outputwindow.input.focus=true input.background-color=[COLOR_INPUT_ENABLED]") + else + winset(src, null, "outputwindow.input.focus=true input.background-color=[COLOR_INPUT_DISABLED]") + + update_special_keybinds() + +// byond bug ID:2694120 +/client/verb/reset_macros_wrapper() + set name = "Fix Keybindings" + set category = "OOC" + reset_macros() + +/client/proc/reset_macros(skip = FALSE) + if(!skip) + if(alert(src, "Change your keyboard language to ENG and press Ok", "Reset macros") != "Ok") + return + to_chat(src, SPAN_NOTICE("Keybindings should be fixed now.")) + set_macros() + +/** + * Manually clears any held keys, in case due to lag or other undefined behavior a key gets stuck. + * + * Hardcoded to the ESC key. + */ +/client/verb/reset_held_keys() + set name = "Reset Held Keys" + set hidden = TRUE + + for(var/key in keys_held) + keyUp(key) + + //In case one got stuck and the previous loop didn't clean it, somehow. + for(var/key in key_combos_held) + keyUp(key_combos_held[key]) diff --git a/code/modules/lighting/__lighting_docs.dm b/code/modules/lighting/__lighting_docs.dm index 95861d4cd19a..f8186cca5103 100644 --- a/code/modules/lighting/__lighting_docs.dm +++ b/code/modules/lighting/__lighting_docs.dm @@ -1,67 +1,46 @@ /* -BS12 object based lighting system -*/ + -- Aurora directional lighting system, based off of /vg/lights. -- -/* -Changes from tg DAL: - - Lighting is done using objects instead of subareas. - - Animated transitions. (newer tg DAL has this) - - Full colours with mixing. - - Support for lights on shuttles. + Documentation is present in most of the code files. + lighting_atom.dm -> procs/vars for tracking/managing lights attached to objects. + lighting_turf.dm -> procs/vars for managing lighting overlays bound to turfs, tracking lights affecting said turf, and getting information about the turf's light level. + lighting_corner.dm -> contains code for tracking per-corner lighting data. + lighting_source.dm -> contains actual light emitter datum & core lighting calculations. Directional lights and Z-lights are implemented here. + lighting_area.dm -> contains area vars/procs for managing an area's dynamic lighting state. - - Code: - - Instead of one flat luminosity var, light is represented by 3 atom vars: - - light_range; diameter in tiles of the light, used for calculating falloff, Cannot be 1. - - light_power; multiplier for the brightness of lights, - - light_color; hex string representing the RGB colour of the light. - - setLuminousity() is now set_light() and takes the three variables above. - - Variables can be left as null to not update them. - - set_opacity() is now set_opacity(). - - Areas have luminosity set to 1 permanently, no hard-lighting. - - Objects inside other objects can have lights and they properly affect the turf. (flashlights) - - area/master and area/list/related have been eviscerated since subareas aren't needed. */ /* -Relevant vars/procs: - -atom: (lighting_atom.dm) - - var/light_range; range in tiles of the light, used for calculating falloff - - var/light_power; multiplier for the brightness of lights - - var/light_color; hex string representing the RGB colour of the light - - - var/datum/light_source/light; light source datum for this atom, only present if light_range && light_power - - var/list/light_sources; light sources in contents that are shining through this object, including this object - - - proc/set_light(l_max_bright, l_inner_range, l_outer_range, l_falloff_curve, l_color): - - Sets light_range/power/color to non-null args and calls update_light() - - proc/set_opacity(new_opacity): - - Sets opacity to new_opacity. - - If opacity has changed, call turf.reconsider_lights() to fix light occlusion - - proc/update_light(): - - Updates the light var on this atom, deleting or creating as needed and calling .update() - - -turf: (lighting_turf.dm) - - var/list/affecting_lights; list of light sources that are shining onto this turf - - - proc/reconsider_lights(): - - Force all light sources shining onto this turf to update - - - proc/lighting_clear_overlays(): - - Delete (manual GC) all light overlays on this turf, used when changing turf to space - - proc/lighting_build_overlays(): - - Create lighting overlays for this turf - - -atom/movable/lighting_overlay: (lighting_overlay.dm) - - var/lum_r, var/lum_g, var/lum_b; lumcounts of each colour - - var/needs_update; set on update_lumcount, checked by lighting process - - - var/xoffset, var/yoffset; (only present when using sub-tile overlays) fractional offset of this overlay in the tile - - - proc/update_lumcount(delta_r, delta_g, delta_b): - - Change the lumcount vars and queue the overlay for update - - proc/update_overlay() - - Called by the lighting process to update the color of the overlay -*/ \ No newline at end of file + Useful procs when using lights: + +/atom/proc/set_light(range, power, color, angle, no_update) + desc: Sets an atom's light emission. `set_light(FALSE)` will disable the light. + args: + range -> the range of the light. 1.4 is the lowest possible value here. + power -> the power (intensity) of the light. Generally should be 1 or lower. Optional. + color -> The hex string (#FFFFFF) color of the light. Optional. + angle -> The angle of the cone that the light should shine at (directional lighting). Behavior of lights over 180 degrees is undefined. Best to stick to using the LIGHT_ defines for this. Optional. + no_update -> if TRUE, the light will not be updated. Useful for when making several of these calls to the same object. Optional. + +/atom/proc/set_opacity(new_opacity) + desc: Sets an atom's opacity, updating affecting lights' visibility. + args: + new_opacity -> the new opacity value. + +/turf/proc/reconsider_lights() + desc: Cause all lights affecting this turf to recalculate visibility. + args: none + +/turf/proc/force_update_lights() + desc: Force all lights affecting this turf to regenerate. Slow, use reconsider_lights instead when possible. + args: none + +/turf/proc/get_avg_color() + desc: Gets the average color of this tile as a hexadecimal color string. Used by cameras. + +/turf/proc/get_lumcount(minlum = 0, maxlum = 1) + desc: Gets the brightness of this tile. If not dynamically lit, always returns 0.5, otherwise returns the average brightness of all 4 corners, scaled between minlum and maxlum. + args: + minlum -> the low-bound of the scalar. + maxlum -> the high-bound of the scalar. +*/ diff --git a/code/modules/lighting/_lighting_defs.dm b/code/modules/lighting/_lighting_defs.dm new file mode 100644 index 000000000000..a49d409fba9a --- /dev/null +++ b/code/modules/lighting/_lighting_defs.dm @@ -0,0 +1,64 @@ +// This is the define used to calculate falloff. +#define LUM_FALLOFF(Cx,Cy,Tx,Ty,HEIGHT) (1 - CLAMP01(sqrt(((Cx) - (Tx)) ** 2 + ((Cy) - (Ty)) ** 2 + HEIGHT) / max(1, actual_range))) + +// Macro that applies light to a new corner. +// It is a macro in the interest of speed, yet not having to copy paste it. +// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line. +// As such this all gets counted as a single line. +// The braces and semicolons are there to be able to do this on a single line. + +#define APPLY_CORNER(C,now,Tx,Ty,hdiff) \ + . = LUM_FALLOFF(C.x, C.y, Tx, Ty, hdiff) * light_power; \ + var/OLD = effect_str[C]; \ + effect_str[C] = .; \ + C.update_lumcount \ + ( \ + (. * lum_r) - (OLD * applied_lum_r), \ + (. * lum_g) - (OLD * applied_lum_g), \ + (. * lum_b) - (OLD * applied_lum_b), \ + now \ + ); + +// Like APPLY_CORNER, but very slightly faster, for the cases where we know there's no previous value. +#define INIT_CORNER(C,now,Tx,Ty,hdiff) \ + . = LUM_FALLOFF(C.x, C.y, Tx, Ty, hdiff) * light_power; \ + effect_str[C] = .; \ + C.update_lumcount \ + ( \ + . * lum_r, \ + . * lum_g, \ + . * lum_b, \ + now \ + ); + +// I don't need to explain what this does, do I? +#define REMOVE_CORNER(C,now) \ + . = -effect_str[C]; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b, \ + now \ + ); + +// Converts two Z levels into a height value for LUM_FALLOFF or HEIGHT_FALLOFF. +#define CALCULATE_CORNER_HEIGHT(ZA,ZB) (((max(ZA,ZB) - min(ZA,ZB)) + 1) * LIGHTING_HEIGHT * LIGHTING_Z_FACTOR) + +#define APPLY_CORNER_BY_HEIGHT(now) \ + if (C.z != Sz) { \ + corner_height = CALCULATE_CORNER_HEIGHT(C.z, Sz); \ + } \ + else { \ + corner_height = LIGHTING_HEIGHT; \ + } \ + APPLY_CORNER(C, now, Sx, Sy, corner_height); + +#define INIT_CORNER_BY_HEIGHT(now) \ + if (C.z != Sz) { \ + corner_height = CALCULATE_CORNER_HEIGHT(C.z, Sz); \ + } \ + else { \ + corner_height = LIGHTING_HEIGHT; \ + } \ + INIT_CORNER(C, now, Sx, Sy, corner_height); \ No newline at end of file diff --git a/code/modules/lighting/ambient_group.dm b/code/modules/lighting/ambient_group.dm new file mode 100644 index 000000000000..7b4665e79c0a --- /dev/null +++ b/code/modules/lighting/ambient_group.dm @@ -0,0 +1,121 @@ +#define BITWISE_MAX_BITS 24 + +/// A bitmap of free ambience group indexes. +var/global/ambience_group_free_bitmap = ~0 +var/global/ambience_group_map[BITWISE_MAX_BITS] + +/datum/ambience_group + var/global_index + var/list/member_turfs_by_z = list() + var/apparent_r + var/apparent_g + var/apparent_b + var/invalid = FALSE + var/busy = FALSE + +/datum/ambience_group/New() + global_index = allocate_index() + if (!global_index) + invalid = TRUE + return + + global.ambience_group_map[global_index] = src + +/datum/ambience_group/Destroy() + if (!invalid) + global.ambience_group_map[global_index] = null + global.ambience_group_free_bitmap |= (1 << global_index) + return ..() + +/datum/ambience_group/proc/allocate_index() + if (global.ambience_group_free_bitmap == 0) + CRASH("Failed to allocate ambience_group: index bitmap is exhausted") + + // Find the first free index in the bitmap. + var/index = 1 + while (!(global.ambience_group_free_bitmap & (1 << index)) && index < BITWISE_MAX_BITS) + index += 1 + + global.ambience_group_free_bitmap &= ~(1 << index) + + return index + +/datum/ambience_group/proc/add_turf(turf/T) + set waitfor = FALSE + + UNTIL(!busy) + if (T.z > member_turfs_by_z.len) + member_turfs_by_z.len = T.z + + LAZYADD(member_turfs_by_z[T.z], T) + T.add_ambient_light_raw(apparent_r, apparent_g, apparent_b) + T.ambience_active_groups += 1 + +/datum/ambience_group/proc/remove_turf(turf/T) + set waitfor = FALSE + + UNTIL(!busy) + if (T.z > member_turfs_by_z.len) + CRASH("Attempt to remove member turf with Z greater than local max -- this turf is not a member") + T.add_ambient_light_raw(-apparent_r, -apparent_g, -apparent_b) + member_turfs_by_z[T.z] -= T + T.ambience_active_groups -= 1 + +/datum/ambience_group/proc/set_ambient_light(color, multiplier) + var/list/new_parts = rgb2num(color) + + var/dr = (new_parts[1] / 255) * multiplier - apparent_r + var/dg = (new_parts[2] / 255) * multiplier - apparent_g + var/db = (new_parts[3] / 255) * multiplier - apparent_b + + if (round(dr/4, LIGHTING_ROUND_VALUE) == 0 && round(dg/4, LIGHTING_ROUND_VALUE) == 0 && round(db/4, LIGHTING_ROUND_VALUE) == 0) + // no-op + return + + busy = TRUE + + // Doing it ordered by zlev should ensure that it looks vaguely coherent mid-update regardless of turf insertion order. + for (var/zlev in 1 to member_turfs_by_z.len) + for (var/turf/T as anything in member_turfs_by_z[zlev]) + T.add_ambient_light_raw(dr, dg, db) + CHECK_TICK + + apparent_r += dr + apparent_g += dg + apparent_b += db + + busy = FALSE + +/turf + /// A bitfield of which global ambience groups are affecting this turf. + var/tmp/ambience_affecting_bitmap = 0 + /// A counter of how many ambience groups are affecting this turf, used to avoid pointlessly iterating the entire 24-bit bitfield. + var/tmp/ambience_active_groups = 0 + +/turf/Destroy() + if (ambience_affecting_bitmap) + var/remaining_groups = ambience_active_groups + for (var/i in 1 to BITWISE_MAX_BITS) + if (ambience_affecting_bitmap & (1 << i)) + var/datum/ambience_group/group = global.ambience_group_map[i] + add_ambient_light_raw(-group.apparent_r, -group.apparent_g, -group.apparent_b) + + remaining_groups -= 1 + + if (!remaining_groups) + break + + return ..() + +/turf/Initialize() + . = ..() + if (ambience_affecting_bitmap) + var/remaining_groups = ambience_active_groups + for (var/i in 1 to BITWISE_MAX_BITS) + if (ambience_affecting_bitmap & (1 << i)) + var/datum/ambience_group/group = global.ambience_group_map[i] + add_ambient_light_raw(group.apparent_r, group.apparent_g, group.apparent_b) + remaining_groups -= 1 + + if (!remaining_groups) + break diff --git a/code/modules/lighting/ambient_turf.dm b/code/modules/lighting/ambient_turf.dm new file mode 100644 index 000000000000..60992f1fcb5d --- /dev/null +++ b/code/modules/lighting/ambient_turf.dm @@ -0,0 +1,119 @@ +/turf + /// If non-null, a hex RGB light color that should be applied to this turf. + var/ambient_light + /// The power of the above is multiplied by this. Setting too high may drown out normal lights on the same turf. + var/ambient_light_multiplier = 0.3 + + // Record-keeping, do not touch -- that means you, admins. + var/tmp/ambient_active = FALSE //! Do we have non-zero ambient light? Use [TURF_IS_AMBIENT_LIT] instead of reading this directly. + var/tmp/ambient_light_old_r = 0 + var/tmp/ambient_light_old_g = 0 + var/tmp/ambient_light_old_b = 0 + +/// Set the turf's self-ambience channel. This can only contain one value at a time, so it should generally only be used by the turf itself. +/turf/proc/set_ambient_light(color, multiplier) + if (color == ambient_light && multiplier == ambient_light_multiplier) + return + + ambient_light = isnull(color) ? ambient_light : color + ambient_light_multiplier = isnull(multiplier) ? ambient_light_multiplier : multiplier + + update_ambient_light() + +/// Replace one ambient light with another. This is effectively a delta update, but it can be used to pretend that our one channel is doing color blending. +/turf/proc/replace_ambient_light(old_color, new_color, old_multiplier, new_multiplier = 0) + if (!TURF_IS_AMBIENT_LIT_UNSAFE(src)) + add_ambient_light(new_color, new_multiplier) + return + + ASSERT(!isnull(old_multiplier)) // omitting new_multiplier is allowed for removing light nondestructively + + old_color ||= COLOR_WHITE + new_color ||= COLOR_WHITE + + var/list/old_parts = rgb2num(old_color) + var/list/new_parts = rgb2num(new_color) + + var/dr = (new_parts[1] / 255) * new_multiplier - (old_parts[1] / 255) * old_multiplier + var/dg = (new_parts[2] / 255) * new_multiplier - (old_parts[2] / 255) * old_multiplier + var/db = (new_parts[3] / 255) * new_multiplier - (old_parts[3] / 255) * old_multiplier + + if (!dr && !dg && !db) + return + + add_ambient_light_raw(dr, dg, db) + +/// Add an ambient light to the turf's self-channel. This is a delta update, retain your applied color if you want to be able to remove it later. +/turf/proc/add_ambient_light(color, multiplier, update = TRUE) + if (!color) + return + + multiplier ||= ambient_light_multiplier + + var/list/ambient_parts = rgb2num(color) + + var/ambient_r = (ambient_parts[1] / 255) * multiplier + var/ambient_g = (ambient_parts[2] / 255) * multiplier + var/ambient_b = (ambient_parts[3] / 255) * multiplier + + add_ambient_light_raw(ambient_r, ambient_g, ambient_b, update) + +/// Directly manipulate the state of the self-ambience channel. Don't use unless you know what you're doing and how ambience works internally. +/turf/proc/add_ambient_light_raw(lr, lg, lb, update = TRUE) + if (!lr && !lg && !lb) + if (!ambient_light_old_r || !ambient_light_old_g || !ambient_light_old_b) + ambient_active = FALSE + SSlighting.total_ambient_turfs -= 1 + return + + // There are four corners per (lit) turf, we don't want to apply our light 4 times -- compensate by dividing by 4. + lr /= 4 + lg /= 4 + lb /= 4 + + lr = round(lr, LIGHTING_ROUND_VALUE) + lg = round(lg, LIGHTING_ROUND_VALUE) + lb = round(lb, LIGHTING_ROUND_VALUE) + + ambient_light_old_r += lr + ambient_light_old_g += lg + ambient_light_old_b += lb + + if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) + if (!corners || !lighting_corners_initialised) + generate_missing_corners() + + // This list can contain nulls on things like space turfs -- they only have their neighbors' corners. + for (var/datum/lighting_corner/C in corners) + C.update_ambient_lumcount(lr, lg, lb, !update) + + if (!ambient_active) + SSlighting.total_ambient_turfs += 1 + ambient_active = TRUE + +/// Wipe the entire self-ambience channel. This will preserve ambience from ambience groups. +/turf/proc/clear_ambient_light() + if (ambient_light == null) + return + + replace_ambient_light(ambient_light, COLOR_WHITE, ambient_light_multiplier, 0) + ambient_light = null + ambient_light_multiplier = initial(ambient_light_multiplier) + +/turf/proc/update_ambient_light(no_corner_update = FALSE) + // These are deltas. + var/ambient_r = 0 + var/ambient_g = 0 + var/ambient_b = 0 + + if (ambient_light) + var/list/parts = rgb2num(ambient_light) + ambient_r = ((parts[1] / 255) * ambient_light_multiplier) - ambient_light_old_r + ambient_g = ((parts[2] / 255) * ambient_light_multiplier) - ambient_light_old_g + ambient_b = ((parts[3] / 255) * ambient_light_multiplier) - ambient_light_old_b + else + ambient_r = -ambient_light_old_r + ambient_g = -ambient_light_old_g + ambient_b = -ambient_light_old_b + + add_ambient_light_raw(ambient_r, ambient_g, ambient_b, !no_corner_update) diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm index e7a2ab270afe..aa5dd82c5ecf 100644 --- a/code/modules/lighting/lighting_area.dm +++ b/code/modules/lighting/lighting_area.dm @@ -1,3 +1,27 @@ /area luminosity = TRUE - var/dynamic_lighting = TRUE \ No newline at end of file + var/dynamic_lighting = TRUE + +/area/Initialize() + . = ..() + + if (dynamic_lighting) + luminosity = FALSE + +/area/proc/set_dynamic_lighting(var/new_dynamic_lighting = TRUE) + if (new_dynamic_lighting == dynamic_lighting) + return FALSE + + dynamic_lighting = new_dynamic_lighting + + if (new_dynamic_lighting) + for (var/turf/T in src) + if (T.dynamic_lighting) + T.lighting_build_overlay() + + else + for (var/turf/T in src) + if (T.lighting_overlay) + T.lighting_clear_overlay() + + return TRUE diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index d37292b0e660..227cec8bb2dd 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -1,76 +1,87 @@ +#define MINIMUM_USEFUL_LIGHT_RANGE 1.4 + /atom - var/light_max_bright = 1 // intensity of the light within the full brightness range. Value between 0 and 1 - var/light_inner_range = 1 // range, in tiles, the light is at full brightness - var/light_outer_range = 0 // range, in tiles, where the light becomes darkness - var/light_falloff_curve = 2 // adjusts curve for falloff gradient. Must be greater than 0. - var/light_color // Hexadecimal RGB string representing the colour of the light + var/light_power = 1 // Intensity of the light. + var/light_range = 0 // Range in tiles of the light. + var/light_color // Hexadecimal RGB string representing the colour of the light. + var/light_wedge // The angle that the light's emission should be restricted to. null for omnidirectional. + // These two vars let you override the default light offset detection (pixel_x/y). + // Useful for objects like light fixtures that aren't visually in the middle of the turf, but aren't offset either. + var/light_offset_x + var/light_offset_y + /// An override for cases where the light is not facing the same direction as the object. + var/light_dir - var/datum/light_source/light - var/list/light_sources + var/tmp/datum/light_source/light // Our light source. Don't fuck with this directly unless you have a good reason! + var/tmp/list/light_source_multi // Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list. + var/tmp/datum/light_source/light_source_solo // Same as above - this is a shortcut to avoid allocating the above list if we can // Nonsensical value for l_color default, so we can detect if it gets set to null. #define NONSENSICAL_VALUE -99999 -#define DEFAULT_FALLOFF_CURVE (2) -/atom/proc/set_light(l_max_bright, l_inner_range, l_outer_range, l_falloff_curve = NONSENSICAL_VALUE, l_color = NONSENSICAL_VALUE) - . = 0 //make it less costly if nothing's changed - - if(l_max_bright != null && l_max_bright != light_max_bright) - light_max_bright = l_max_bright - . = 1 - if(l_outer_range != null && l_outer_range != light_outer_range) - light_outer_range = l_outer_range - . = 1 - if(l_inner_range != null && l_inner_range != light_inner_range) - if(light_inner_range >= light_outer_range) - light_inner_range = light_outer_range / 4 - else - light_inner_range = l_inner_range - . = 1 - if(l_falloff_curve != NONSENSICAL_VALUE) - if(!l_falloff_curve || l_falloff_curve <= 0) - light_falloff_curve = DEFAULT_FALLOFF_CURVE - if(l_falloff_curve != light_falloff_curve) - light_falloff_curve = l_falloff_curve - . = 1 - if(l_color != NONSENSICAL_VALUE && l_color != light_color) + +// The proc you should always use to set the light of this atom. +/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, angle = NONSENSICAL_VALUE, no_update = FALSE) + if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE) + l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4 + if (l_power != null) + light_power = l_power + + if (l_range != null) + light_range = l_range + + if (l_color != NONSENSICAL_VALUE) light_color = l_color - . = 1 - if(.) update_light() + if (angle != NONSENSICAL_VALUE) + light_wedge = angle + + if (no_update) + return + + update_light() #undef NONSENSICAL_VALUE -#undef DEFAULT_FALLOFF_CURVE +// Will update the light (duh). +// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf... /atom/proc/update_light() - set waitfor = FALSE - - if(!light_max_bright || !light_outer_range || light_max_bright > 1) - if(light) - light.destroy() - light = null - if(light_max_bright > 1) - light_max_bright = 1 - CRASH("Attempted to call update_light() on atom [src] \ref[src] with a light_max_bright value greater than one") + if (QDELING(src)) + return + + if (!light_power || !light_range) // We won't emit light anyways, destroy the light source. + QDEL_NULL(light) else - if(!istype(loc, /atom/movable)) + if (!istype(loc, /atom/movable)) // We choose what atom should be the top atom of the light here. . = src else . = loc - if(light) + if (light) light.update(.) else light = new /datum/light_source(src, .) -/atom/Destroy() - if(light) - light.destroy() - light = null - return ..() -/atom/set_opacity() +// Should always be used to change the opacity of an atom. +// It notifies (potentially) affected light sources so they can update (if needed). +/atom/set_opacity(var/new_opacity) . = ..() - if(.) - var/turf/T = loc - if(istype(T)) - T.RecalculateOpacity() + if (!.) + return + + opacity = new_opacity + var/turf/T = loc + if (!isturf(T)) + return + + if (new_opacity == TRUE) + T.has_opaque_atom = TRUE + T.reconsider_lights() +#ifdef AO_USE_LIGHTING_OPACITY + T.regenerate_ao() +#endif + else + var/old_has_opaque_atom = T.has_opaque_atom + T.recalc_atom_opacity() + if (old_has_opaque_atom != T.has_opaque_atom) + T.reconsider_lights() diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index b8fe2b4ae04b..ea6f99e9a915 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -1,134 +1,414 @@ -/var/total_lighting_corners = 0 -/var/datum/lighting_corner/dummy/dummy_lighting_corner = new +var/global/datum/lighting_corner/dummy/dummy_lighting_corner = new // Because we can control each corner of every lighting overlay. // And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). // For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. // This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. -/var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST) +var/global/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST) + +// This is the reverse of the above - the position in the array is a dir. Update this if the above changes. +var/global/list/REVERSE_LIGHTING_CORNER_DIAGONAL = list(0, 0, 0, 0, 3, 4, 0, 0, 2, 1) /datum/lighting_corner - var/list/turf/masters = list() - var/list/datum/light_source/affecting = list() // Light sources affecting us. + // t1 through t4 are our masters, in no particular order. + // They are split into vars like this in the interest of reducing memory usage. + // tX is the turf itself, tXi is the index of this corner in that turf's corners list. + var/turf/t1 + var/t1i + var/turf/t2 + var/t2i + var/turf/t3 + var/t3i + var/turf/t4 + var/t4i + + var/list/datum/light_source/affecting // Light sources affecting us. var/active = FALSE // TRUE if one of our masters has dynamic lighting. - var/x = 0 - var/y = 0 - var/z = 0 + var/x = 0 + var/y = 0 + var/z = 0 + + // Our own intensity, from lights directly shining on us. + var/self_r = 0 + var/self_g = 0 + var/self_b = 0 + + // The intensity we're inheriting from the turf below us, if we're a Z-turf. This is a sum of all below turfs in the Z-stack. + var/below_r = 0 + var/below_g = 0 + var/below_b = 0 + + // Ambient turf lighting that's not inherited from a light source. These are updated as absolute values. + var/ambient_r = 0 + var/ambient_g = 0 + var/ambient_b = 0 - var/lum_r = 0 - var/lum_g = 0 - var/lum_b = 0 + // The turf above us' ambient + var/above_ambient_r = 0 + var/above_ambient_g = 0 + var/above_ambient_b = 0 + + // The final intensity, all things considered. + var/apparent_r = 0 + var/apparent_g = 0 + var/apparent_b = 0 var/needs_update = FALSE - var/cache_r = LIGHTING_SOFT_THRESHOLD - var/cache_g = LIGHTING_SOFT_THRESHOLD - var/cache_b = LIGHTING_SOFT_THRESHOLD + var/cache_r = 0 + var/cache_g = 0 + var/cache_b = 0 var/cache_mx = 0 - var/update_gen = 0 +/datum/lighting_corner/New(turf/new_turf, diagonal, oi) + SSlighting.total_lighting_corners += 1 -/datum/lighting_corner/New(var/turf/new_turf, var/diagonal) - . = ..() + var/has_ambience = FALSE - total_lighting_corners++ + t1 = new_turf.resolve_to_actual_turf() + z = t1.z + t1i = oi - masters[new_turf] = turn(diagonal, 180) - z = new_turf.z + if (TURF_IS_AMBIENT_LIT_UNSAFE(new_turf)) + has_ambience = TRUE var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one. - x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5) - y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5) + x = t1.x + (horizontal == EAST ? 0.5 : -0.5) + y = t1.y + (vertical == NORTH ? 0.5 : -0.5) // My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal). // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. // So we'll have this hardcode instead. var/turf/T - var/i + // This is to resolve the proper diagonal direction relative to the corner position for mimiced turfs. + var/Tc + // Diagonal one is easy. - T = get_step(new_turf, diagonal) + T = get_step_resolving_mimic(t1, diagonal) if (T) // In case we're on the map's border. if (!T.corners) - T.corners = list(null, null, null, null) + T.corners = new(4) - masters[T] = diagonal - i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) - T.corners[i] = src + t2 = T + t2i = REVERSE_LIGHTING_CORNER_DIAGONAL[diagonal] + T.corners[t2i] = src + if (TURF_IS_AMBIENT_LIT_UNSAFE(T)) + has_ambience = TRUE // Now the horizontal one. - T = get_step(new_turf, horizontal) + T = get_step_resolving_mimic(t1, horizontal) + Tc = t1.x + (horizontal == EAST ? 1 : -1) if (T) // Ditto. if (!T.corners) - T.corners = list(null, null, null, null) + T.corners = new(4) - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src + t3 = T + t3i = REVERSE_LIGHTING_CORNER_DIAGONAL[((Tc > x) ? EAST : WEST) | ((t1.y > y) ? NORTH : SOUTH)] // Get the dir based on coordinates. + T.corners[t3i] = src + if (TURF_IS_AMBIENT_LIT_UNSAFE(T)) + has_ambience = TRUE // And finally the vertical one. - T = get_step(new_turf, vertical) + T = get_step_resolving_mimic(t1, vertical) + Tc = t1.y + (vertical == NORTH ? 1 : -1) if (T) if (!T.corners) - T.corners = list(null, null, null, null) + T.corners = new(4) - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src + t4 = T + t4i = REVERSE_LIGHTING_CORNER_DIAGONAL[((t1.x > x) ? EAST : WEST) | ((Tc > y) ? NORTH : SOUTH)] // Get the dir based on coordinates. + T.corners[t4i] = src + if (TURF_IS_AMBIENT_LIT_UNSAFE(T)) + has_ambience = TRUE update_active() + if (has_ambience) + init_ambient() + +#define OVERLAY_PRESENT(T) (T && T.lighting_overlay) /datum/lighting_corner/proc/update_active() active = FALSE - for (var/turf/T in masters) - if (T.lighting_overlay) - active = TRUE + + if (OVERLAY_PRESENT(t1) || OVERLAY_PRESENT(t2) || OVERLAY_PRESENT(t3) || OVERLAY_PRESENT(t4)) + active = TRUE + +#undef OVERLAY_PRESENT + +#define GET_ABOVE(T) (HasAbove(T:z) ? get_step(T, UP) : null) +#define GET_BELOW(T) (HasBelow(T:z) ? get_step(T, DOWN) : null) + +#define UPDATE_APPARENT(T, CH) T.apparent_##CH = T.self_##CH + T.below_##CH + T.ambient_##CH + T.above_ambient_##CH + +/datum/lighting_corner/proc/init_ambient() + var/sum_r = 0 + var/sum_g = 0 + var/sum_b = 0 + + var/turf/T + for (var/i in 1 to 4) + // this is ugly as fuck, but it's still more legible than doing this with a macro + switch (i) + if (1) T = t1 + if (2) T = t2 + if (3) T = t3 + if (4) T = t4 + + if (!T || !T.ambient_light) + continue + + var/list/parts = rgb2num(T.ambient_light) + + sum_r += (parts[1] / 255) * T.ambient_light_multiplier + sum_g += (parts[2] / 255) * T.ambient_light_multiplier + sum_b += (parts[3] / 255) * T.ambient_light_multiplier + + sum_r /= 4 + sum_g /= 4 + sum_b /= 4 + + update_ambient_lumcount(sum_r, sum_g, sum_b) // God that was a mess, now to do the rest of the corner code! Hooray! -/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b) - lum_r += delta_r - lum_g += delta_g - lum_b += delta_b +/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b, now = FALSE) + if (!(delta_r + delta_g + delta_b)) + return - if (!needs_update) + self_r += delta_r + self_g += delta_g + self_b += delta_b + + UPDATE_APPARENT(src, r) + UPDATE_APPARENT(src, g) + UPDATE_APPARENT(src, b) + + var/turf/T + var/Ti + // Grab the first master that's a Z-turf, if one exists. + // The above var cannot be relied on due to init ordering, but we can use it if it is set. + if (t1 && (T = t1.above || GET_ABOVE(t1)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = t1i + else if (t2 && (T = t2.above || GET_ABOVE(t2)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = t2i + else if (t3 && (T = t3.above || GET_ABOVE(t3)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = t3i + else if (t4 && (T = t4.above || GET_ABOVE(t4)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = t4i + else // Nothing above us that cares about below light. + T = null + + if (TURF_IS_DYNAMICALLY_LIT(T)) + do + if (!T.corners || !T.corners[Ti]) + T.generate_missing_corners() + + // Above corners never get instant updates; they're less important, so better to avoid risk of lag. + T.corners[Ti].update_below_lumcount(delta_r, delta_g, delta_b) + while ((T = T.above) && (T.z_flags & ZM_ALLOW_LIGHTING)) + + // This needs to be down here instead of the above if so the lum values are properly updated. + if (needs_update) + return + + if (now) + update_overlays(TRUE) + else needs_update = TRUE SSlighting.corner_queue += src -/datum/lighting_corner/proc/update_overlays() - // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually. - var/lum_r = src.lum_r > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_r) : src.lum_r - var/lum_g = src.lum_g > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_g) : src.lum_g - var/lum_b = src.lum_b > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_b) : src.lum_b +/datum/lighting_corner/proc/update_below_lumcount(delta_r, delta_g, delta_b) + if (!(delta_r + delta_g + delta_b)) + return + + below_r += delta_r + below_g += delta_g + below_b += delta_b + + UPDATE_APPARENT(src, r) + UPDATE_APPARENT(src, g) + UPDATE_APPARENT(src, b) + + // This needs to be down here instead of the above if so the lum values are properly updated. + if (needs_update) + return + + needs_update = TRUE + SSlighting.corner_queue += src + +/datum/lighting_corner/proc/update_ambient_lumcount(delta_r, delta_g, delta_b, skip_update = FALSE) - var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1. + ambient_r += delta_r + ambient_g += delta_g + ambient_b += delta_b + + UPDATE_APPARENT(src, r) + UPDATE_APPARENT(src, g) + UPDATE_APPARENT(src, b) + + var/turf/T + var/Ti + + if (t1) + T = t1 + Ti = t1i + else if (t2) + T = t2 + Ti = t2i + else if (t3) + T = t3 + Ti = t3i + else if (t4) + T = t4 + Ti = t4i + else + // This should be impossible to reach -- how do we exist without at least one master turf? + CRASH("Corner has no masters!") + + var/datum/lighting_corner/below = src + + // We init before Z-Mimic, cannot rely on above/below. + while ((T = GET_BELOW(T)) && ((below.t1?.z_flags | below.t2?.z_flags | below.t3?.z_flags | below.t4?.z_flags) & ZM_ALLOW_LIGHTING) && TURF_IS_DYNAMICALLY_LIT_UNSAFE(T)) + if (!T.corners || !T.corners[Ti]) + T.generate_missing_corners() + + ASSERT(T.corners?.len) + + below = T.corners[Ti] + below.above_ambient_r += delta_r + below.above_ambient_g += delta_g + below.above_ambient_b += delta_b + + UPDATE_APPARENT(below, r) + UPDATE_APPARENT(below, g) + UPDATE_APPARENT(below, b) + + if (!skip_update && !below.needs_update) + below.needs_update = TRUE + SSlighting.corner_queue += below + + if (needs_update || skip_update) + return + + // Always queue for this, not important enough to hit the synchronous path. + needs_update = TRUE + SSlighting.corner_queue += src + +/datum/lighting_corner/proc/update_overlays(now = FALSE) + var/lr = apparent_r + var/lg = apparent_g + var/lb = apparent_b + + // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually. + var/mx = max(lr, lg, lb) // Scale it so 1 is the strongest lum, if it is above 1. . = 1 // factor if (mx > 1) . = 1 / mx - #if LIGHTING_SOFT_THRESHOLD != 0 - else if (mx < LIGHTING_SOFT_THRESHOLD) - . = 0 // 0 means soft lighting. - - cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD - cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD - cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD - #else - cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) - cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) - cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) - #endif + cache_r = round(lr * ., LIGHTING_ROUND_VALUE) + cache_g = round(lg * ., LIGHTING_ROUND_VALUE) + cache_b = round(lb * ., LIGHTING_ROUND_VALUE) + cache_mx = round(mx, LIGHTING_ROUND_VALUE) - for (var/TT in masters) - var/turf/T = TT - if (T.lighting_overlay) - if (!T.lighting_overlay.needs_update) - T.lighting_overlay.needs_update = TRUE - SSlighting.overlay_queue += T.lighting_overlay + var/turf/T + for (var/i in 1 to 4) + // this is ugly as fuck, but it's still more legible than doing this with a macro + switch (i) + if (1) T = t1 + if (2) T = t2 + if (3) T = t3 + if (4) T = t4 + var/atom/movable/lighting_overlay/Ov + if (T && (Ov = T.lighting_overlay)) + if (now) + Ov.update_overlay() + else if (!Ov.needs_update) + Ov.needs_update = TRUE + SSlighting.overlay_queue += Ov + +// This is called when our turf's downward Z-opacity changes. +/datum/lighting_corner/proc/rebuild_ztraversal(new_opacity) + /* + If opacity transitions to off: + - Look down stack, removing below lights contributing to us + - Look up stack, updating turfs with our new below lighting value + If opacity transitions to on: + - Look down stack, add below contributors + - Look up stack, updating turfs with our new below lighting value + */ + below_r = below_g = below_b = 0 + var/turf/T = null + var/datum/lighting_corner/Tcorn = src + var/Ti + + if (!new_opacity) + for (;;) + if (Tcorn.t1 && (T = Tcorn.t1.below || GET_BELOW(Tcorn.t1)) && (T.above?.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t1i + else if (Tcorn.t2 && (T = Tcorn.t2.below || GET_BELOW(Tcorn.t2)) && (T.above?.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t2i + else if (Tcorn.t3 && (T = Tcorn.t3.below || GET_BELOW(Tcorn.t3)) && (T.above?.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t3i + else if (Tcorn.t4 && (T = Tcorn.t4.below || GET_BELOW(Tcorn.t4)) && (T.above?.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t4i + else // Nothing above us that cares about below light. + break + + Tcorn = T.corners[Ti] + below_r += Tcorn.apparent_r + below_g += Tcorn.apparent_g + below_b += Tcorn.apparent_b + + UPDATE_APPARENT(src, r) + UPDATE_APPARENT(src, g) + UPDATE_APPARENT(src, b) + + if (!needs_update) + needs_update = TRUE + SSlighting.corner_queue += src + + T = null + Tcorn = src + + for (;;) + if (Tcorn.t1 && (T = Tcorn.t1.above || GET_ABOVE(Tcorn.t1)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t1i + else if (Tcorn.t2 && (T = Tcorn.t2.above || GET_ABOVE(Tcorn.t2)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t2i + else if (Tcorn.t3 && (T = Tcorn.t3.above || GET_ABOVE(Tcorn.t3)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t3i + else if (Tcorn.t4 && (T = Tcorn.t4.above || GET_ABOVE(Tcorn.t4)) && (T.z_flags & ZM_ALLOW_LIGHTING)) + Ti = Tcorn.t4i + else // Nothing above us that cares about below light. + break + + Tcorn = T.corners[Ti] + Tcorn.below_r += apparent_r + Tcorn.below_g += apparent_g + Tcorn.below_b += apparent_b + + UPDATE_APPARENT(Tcorn, r) + UPDATE_APPARENT(Tcorn, g) + UPDATE_APPARENT(Tcorn, b) + + if (!Tcorn.needs_update) + Tcorn.needs_update = TRUE + SSlighting.corner_queue += Tcorn + +/datum/lighting_corner/Destroy(force = FALSE) + PRINT_STACK_TRACE("Someone [force ? "force-" : ""]deleted a lighting corner.") + if (!force) + return QDEL_HINT_LETMELIVE + + SSlighting.total_lighting_corners -= 1 + return ..() /datum/lighting_corner/dummy/New() return + +#undef UPDATE_APPARENT diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 9dbe2b3dcaec..c4900999b891 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -1,77 +1,83 @@ -/var/total_lighting_overlays = 0 /atom/movable/lighting_overlay - name = "" - mouse_opacity = 0 - simulated = 0 - anchored = 1 - icon = LIGHTING_ICON - plane = LIGHTING_PLANE - layer = LIGHTING_LAYER - invisibility = INVISIBILITY_LIGHTING - color = LIGHTING_BASE_MATRIX - icon_state = "light1" - blend_mode = BLEND_OVERLAY - - appearance_flags = 0 - - var/lum_r = 0 - var/lum_g = 0 - var/lum_b = 0 + name = "" + anchored = TRUE + icon = LIGHTING_ICON + icon_state = LIGHTING_BASE_ICON_STATE + color = LIGHTING_BASE_MATRIX + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + layer = LIGHTING_LAYER + plane = LIGHTING_PLANE + invisibility = INVISIBILITY_LIGHTING + simulated = FALSE + blend_mode = BLEND_OVERLAY var/needs_update = FALSE -/atom/movable/lighting_overlay/Initialize() - // doesn't need special init - SHOULD_CALL_PARENT(FALSE) + #if WORLD_ICON_SIZE != 32 + transform = matrix(WORLD_ICON_SIZE / 32, 0, (WORLD_ICON_SIZE - 32) / 2, 0, WORLD_ICON_SIZE / 32, (WORLD_ICON_SIZE - 32) / 2) + #endif + +/atom/movable/lighting_overlay/New(newloc, update_now = FALSE) atom_flags |= ATOM_FLAG_INITIALIZED - return INITIALIZE_HINT_NORMAL + SSlighting.total_lighting_overlays += 1 -/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE) - var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays outside of turfs. - if(T.dynamic_lighting) - . = ..() - verbs.Cut() - total_lighting_overlays++ + var/turf/T = loc // If this runtimes atleast we'll know what's creating overlays in things that aren't turfs. + T.lighting_overlay = src + T.luminosity = 0 - T.lighting_overlay = src - T.luminosity = 0 - if(no_update) - return + if (T.corners && T.corners.len) + for (var/datum/lighting_corner/C in T.corners) + C.active = TRUE + + if (update_now) update_overlay() + needs_update = FALSE else - qdel(src) + needs_update = TRUE + SSlighting.overlay_queue += src + +/atom/movable/lighting_overlay/Destroy(force = FALSE) + if (!force) + return QDEL_HINT_LETMELIVE // STOP DELETING ME + + SSlighting.total_lighting_overlays -= 1 + + var/turf/T = loc + if (istype(T)) + T.lighting_overlay = null + T.luminosity = 1 + + return ..() + +// This is a macro PURELY so that the if below is actually readable. +#define ALL_EQUAL ((rr == gr && gr == br && br == ar) && (rg == gg && gg == bg && bg == ag) && (rb == gb && gb == bb && bb == ab)) /atom/movable/lighting_overlay/proc/update_overlay() - set waitfor = FALSE var/turf/T = loc + if (!isturf(T)) // Erm... + if (loc) + warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc], [loc.type]) in update_overlay() and got deleted!") - if(!istype(T)) - if(loc) - log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!") else - log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!") - qdel(src) - return - if(!T.dynamic_lighting) - qdel(src) - return + warning("A lighting overlay realised it was in nullspace in update_overlay() and got deleted!") - // To the future coder who sees this and thinks - // "Why didn't he just use a loop?" - // Well my man, it's because the loop performed like shit. - // And there's no way to improve it because - // without a loop you can make the list all at once which is the fastest you're gonna get. - // Oh it's also shorter line wise. - // Including with these comments. + qdel(src, TRUE) + return // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. - // No I seriously cannot think of a more efficient method, fuck off Comic. - var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner - var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner - var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner - var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner + var/list/corners = T.corners + var/datum/lighting_corner/cr = dummy_lighting_corner + var/datum/lighting_corner/cg = dummy_lighting_corner + var/datum/lighting_corner/cb = dummy_lighting_corner + var/datum/lighting_corner/ca = dummy_lighting_corner + if (corners) + cr = corners[3] || dummy_lighting_corner + cg = corners[2] || dummy_lighting_corner + cb = corners[4] || dummy_lighting_corner + ca = corners[1] || dummy_lighting_corner var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) + luminosity = max > 0 var/rr = cr.cache_r var/rg = cr.cache_g @@ -89,62 +95,61 @@ var/ag = ca.cache_g var/ab = ca.cache_b - #if LIGHTING_SOFT_THRESHOLD != 0 - var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD - #else - // Because of floating points, it won't even be a flat 0. - // This number is mostly arbitrary. - var/set_luminosity = max > 1e-6 - #endif - - // If all channels are full lum, there's no point showing the overlay. if(rr + rg + rb + gr + gg + gb + br + bg + bb + ar + ag + ab >= 12) - icon_state = "transparent" + icon_state = LIGHTING_TRANSPARENT_ICON_STATE + color = null + else if (!luminosity) + icon_state = LIGHTING_DARKNESS_ICON_STATE color = null - else if(!set_luminosity) - icon_state = LIGHTING_ICON_STATE_DARK + else if (rr == LIGHTING_DEFAULT_TUBE_R && rg == LIGHTING_DEFAULT_TUBE_G && rb == LIGHTING_DEFAULT_TUBE_B && ALL_EQUAL) + icon_state = LIGHTING_STATION_ICON_STATE color = null else - icon_state = null - color = list( - -rr, -rg, -rb, 00, - -gr, -gg, -gb, 00, - -br, -bg, -bb, 00, - -ar, -ag, -ab, 00, - 01, 01, 01, 01 - ) - - luminosity = set_luminosity - // if (T.above && T.above.shadower) - // T.above.shadower.copy_lighting(src) + icon_state = LIGHTING_BASE_ICON_STATE + if (islist(color)) + // Does this even save a list alloc? + var/list/c_list = color + c_list[CL_MATRIX_RR] = rr + c_list[CL_MATRIX_RG] = rg + c_list[CL_MATRIX_RB] = rb + c_list[CL_MATRIX_GR] = gr + c_list[CL_MATRIX_GG] = gg + c_list[CL_MATRIX_GB] = gb + c_list[CL_MATRIX_BR] = br + c_list[CL_MATRIX_BG] = bg + c_list[CL_MATRIX_BB] = bb + c_list[CL_MATRIX_AR] = ar + c_list[CL_MATRIX_AG] = ag + c_list[CL_MATRIX_AB] = ab + color = c_list + else + color = list( + rr, rg, rb, 0, + gr, gg, gb, 0, + br, bg, bb, 0, + ar, ag, ab, 0, + 0, 0, 0, 1 + ) + + // If there's a Z-turf above us, update its shadower. + if (T.above) + if (T.above.shadower) + T.above.shadower.copy_lighting(src) + else + T.above.update_mimic() + +#undef ALL_EQUAL // Variety of overrides so the overlays don't get affected by weird things. -/atom/movable/lighting_overlay/explosion_act() - SHOULD_CALL_PARENT(FALSE) - return -/atom/movable/lighting_overlay/singularity_pull() +/atom/movable/lighting_overlay/explosion_act(severity) + SHOULD_CALL_PARENT(FALSE) return -/atom/movable/lighting_overlay/Destroy() - total_lighting_overlays-- - SSlighting.overlay_queue -= src +/atom/movable/lighting_overlay/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + return FALSE - var/turf/T = loc - if(istype(T)) - T.lighting_overlay = null - - . = ..() - -/atom/movable/lighting_overlay/forceMove() - //should never move - //In theory... except when getting deleted :C +// Override here to prevent things accidentally moving around overlays. +/atom/movable/lighting_overlay/forceMove(atom/destination, harderforce = FALSE) if(QDELING(src)) - return ..() - return 0 - -/atom/movable/lighting_overlay/Move() - return 0 - -/atom/movable/lighting_overlay/throw_at() - return 0 + . = ..() diff --git a/code/modules/lighting/lighting_planemaster.dm b/code/modules/lighting/lighting_planemaster.dm deleted file mode 100644 index 1e4c95af8867..000000000000 --- a/code/modules/lighting/lighting_planemaster.dm +++ /dev/null @@ -1,49 +0,0 @@ -/obj/lighting_plane - screen_loc = "LEFT+1,BOTTOM+1" - plane = LIGHTING_PLANE - - blend_mode = BLEND_MULTIPLY - appearance_flags = PLANE_MASTER | NO_CLIENT_COLOR - // use 20% ambient lighting; be sure to add full alpha - - color = list( - -1, 00, 00, 00, - 00, -1, 00, 00, - 00, 00, -1, 00, - 00, 00, 00, 00, - 01, 01, 01, 01 - ) - - mouse_opacity = 0 // nothing on this plane is mouse-visible - -/obj/lighting_general - plane = LIGHTING_PLANE - screen_loc = "CENTER,CENTER" - icon = LIGHTING_ICON - icon_state = LIGHTING_ICON_STATE_DARK - color = "#ffffff" - blend_mode = BLEND_MULTIPLY - -/obj/lighting_general/Initialize() - . = ..() - fit_to_client_view() - -/obj/lighting_general/proc/fit_to_client_view(var/x_dim, var/y_dim) - var/matrix/M = matrix() - if(x_dim && y_dim) - M.Scale(x_dim * 2.2, y_dim * 2.2) - else - M.Scale(world.view * 2.2) - transform = M - -/obj/lighting_general/proc/sync(var/new_colour) - color = new_colour - -/mob - var/obj/lighting_plane/l_plane - var/obj/lighting_general/l_general - - -/mob/proc/change_light_colour(var/new_colour) - if(l_general) - l_general.sync(new_colour) diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm deleted file mode 100644 index 68311a32b2f6..000000000000 --- a/code/modules/lighting/lighting_setup.dm +++ /dev/null @@ -1,10 +0,0 @@ -/proc/create_all_lighting_overlays() - for(var/zlevel = 1 to world.maxz) - create_lighting_overlays_zlevel(zlevel) - -/proc/create_lighting_overlays_zlevel(var/zlevel) - ASSERT(zlevel) - - for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) - if(T.dynamic_lighting) - T.lighting_build_overlay() diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 9817ac83f1ac..84bccc897573 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -1,17 +1,16 @@ -/var/total_lighting_sources = 0 // This is where the fun begins. // These are the main datums that emit light. /datum/light_source - var/atom/top_atom // The atom we're emitting light from(for example a mob if we're from a flashlight that's being held). + var/atom/top_atom // The atom we're emitting light from (for example a mob if we're from a flashlight that's being held). var/atom/source_atom // The atom that we belong to. - var/turf/source_turf // The turf under the above. - var/light_max_bright = 1 // intensity of the light within the full brightness range. Value between 0 and 1 - var/light_inner_range = 0 // range, in tiles, the light is at full brightness - var/light_outer_range = 0 // range, in tiles, where the light becomes darkness - var/light_falloff_curve // adjusts curve for falloff gradient - var/light_color // The colour of the light, string, decomposed by parse_light_color() + var/turf/source_turf // The turf under the above. + var/turf/pixel_turf // The turf the top_atom _appears_ to be on + var/light_power // Intensity of the emitter light. + var/light_range // The range of the emitted light. + var/light_color // The colour of the light, string, decomposed by parse_light_color() + var/light_angle // The light's emission angle, in degrees. // Variables for keeping track of the colour. var/lum_r @@ -23,305 +22,423 @@ var/tmp/applied_lum_g var/tmp/applied_lum_b + // Variables used to keep track of the atom's angle. + var/tmp/limit_a_x // The first test point's X coord for the cone. + var/tmp/limit_a_y // The first test point's Y coord for the cone. + var/tmp/limit_b_x // The second test point's X coord for the cone. + var/tmp/limit_b_y // The second test point's Y coord for the cone. + var/tmp/cached_origin_x // The last known X coord of the origin. + var/tmp/cached_origin_y // The last known Y coord of the origin. + var/tmp/old_direction // The last known direction of the origin. + var/tmp/test_x_offset // How much the X coord should be offset due to direction. + var/tmp/test_y_offset // How much the Y coord should be offset due to direction. + var/tmp/facing_opaque = FALSE + var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. var/list/turf/affecting_turfs var/applied = FALSE // Whether we have applied our light yet or not. - var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became(in)visible to us. - var/needs_update // Whether we are queued for an update. - var/destroyed // Whether we are destroyed and need to stop emitting light. - var/force_update + var/needs_update = LIGHTING_NO_UPDATE + +// This macro will only offset up to 1 tile, but anything with a greater offset is an outlier and probably should handle its own lighting offsets. +// Anything pixelshifted 16px or more will be considered on the next tile. +#define GET_APPROXIMATE_PIXEL_DIR(PX, PY) ((!(PX) ? 0 : (((PX) >= 16 ? EAST : ((PX) <= -16 ? WEST : 0)))) | (!(PY) ? 0 : ((PY) >= 16 ? NORTH : ((PY) <= -16 ? SOUTH : 0)))) +#define UPDATE_APPROXIMATE_PIXEL_TURF var/px = top_atom.light_offset_x || top_atom.pixel_x; var/py = top_atom.light_offset_y || top_atom.pixel_y; var/_dir = GET_APPROXIMATE_PIXEL_DIR(px, py); pixel_turf = _dir ? (get_step(source_turf, _dir) || source_turf) : source_turf + +// These macros are for dealing with the multi/solo split. +#define ADD_SOURCE(TARGET) if (!TARGET.light_source_multi && !TARGET.light_source_solo) { TARGET.light_source_solo = src; } else if (TARGET.light_source_solo) { TARGET.light_source_multi = list(TARGET.light_source_solo, src); TARGET.light_source_solo = null; } else { TARGET.light_source_multi += src } +#define REMOVE_SOURCE(TARGET) if (TARGET.light_source_solo == src) { TARGET.light_source_solo = null } else if (TARGET.light_source_multi) { TARGET.light_source_multi -= src; if (TARGET.light_source_multi.len == 1) { TARGET.light_source_solo = TARGET.light_source_multi[1]; TARGET.light_source_multi = null; } } -/datum/light_source/New(var/atom/owner, var/atom/top) - total_lighting_sources++ +/datum/light_source/New(atom/owner, atom/top) + SSlighting.total_lighting_sources += 1 source_atom = owner // Set our new owner. - if(!source_atom.light_sources) - source_atom.light_sources = list() - source_atom.light_sources += src // Add us to the lights of our owner. - top_atom = top - if(top_atom != source_atom) - if(!top.light_sources) - top.light_sources = list() + ADD_SOURCE(source_atom) - top_atom.light_sources += src + top_atom = top + if (top_atom != source_atom) + ADD_SOURCE(top_atom) source_turf = top_atom - light_max_bright = source_atom.light_max_bright - light_inner_range = source_atom.light_inner_range - light_outer_range = source_atom.light_outer_range - light_falloff_curve = source_atom.light_falloff_curve + UPDATE_APPROXIMATE_PIXEL_TURF + light_power = source_atom.light_power + light_range = source_atom.light_range light_color = source_atom.light_color + light_angle = source_atom.light_wedge parse_light_color() - effect_str = list() - affecting_turfs = list() - update() - - return ..() - -/* lighting debugging verb -/mob/verb/self_light() - set name = "set self light" - set category = "Light" - var/v1 = input(usr, "Enter max bright", "max bright", 1) as num|null - var/v2 = input(usr, "Enter inner range", "inner range", 0.1) as num|null - var/v3 = input(usr, "Enter outer range", "outer range", 4) as num|null - var/v4 = input(usr, "Enter curve", "curve", 2) as num|null - set_light(v1, v2, v3, v4, "#0066ff") -*/ - // Kill ourselves. -/datum/light_source/proc/destroy() - total_lighting_sources-- - destroyed = TRUE - force_update() - if(source_atom && source_atom.light_sources) - source_atom.light_sources -= src - - if(top_atom && top_atom.light_sources) - top_atom.light_sources -= src - -// Call it dirty, I don't care. -// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates. -// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a() macro that has no arguments :|. -#define effect_update(BYOND) \ - if(!needs_update) \ - { \ - SSlighting.light_queue += src; \ - needs_update = TRUE; \ +/datum/light_source/Destroy(force) + SSlighting.total_lighting_sources -= 1 + + remove_lum() + if (source_atom) + REMOVE_SOURCE(source_atom) + + if (top_atom) + REMOVE_SOURCE(top_atom) + + . = ..() + if (!force) + return QDEL_HINT_IWILLGC + +#ifdef USE_INTELLIGENT_LIGHTING_UPDATES +// Picks either scheduled or instant updates based on current server load. +#define INTELLIGENT_UPDATE(level) \ + var/_should_update = needs_update == LIGHTING_NO_UPDATE; \ + if (needs_update < level) { \ + needs_update = level; \ + } \ + if (_should_update) { \ + if (world.tick_usage > Master.current_ticklimit || SSlighting.force_queued) { \ + SSlighting.light_queue += src; \ + } \ + else { \ + SSlighting.total_instant_updates += 1; \ + update_corners(TRUE); \ + needs_update = LIGHTING_NO_UPDATE; \ + } \ } +#else +#define INTELLIGENT_UPDATE(level) \ + if (needs_update == LIGHTING_NO_UPDATE) \ + SSlighting.light_queue += src; \ + if (needs_update < level) \ + needs_update = level; +#endif // This proc will cause the light source to update the top atom, and add itself to the update queue. -/datum/light_source/proc/update(var/atom/new_top_atom) +/datum/light_source/proc/update(atom/new_top_atom) // This top atom is different. - if(new_top_atom && new_top_atom != top_atom) + if (new_top_atom && new_top_atom != top_atom) if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom. - top_atom.light_sources -= src + REMOVE_SOURCE(top_atom) top_atom = new_top_atom - if(top_atom != source_atom) - if(!top_atom.light_sources) - top_atom.light_sources = list() + if (top_atom != source_atom) + ADD_SOURCE(top_atom) // Add ourselves to the light sources of our new top atom. - top_atom.light_sources += src // Add ourselves to the light sources of our new top atom. - - effect_update(null) + INTELLIGENT_UPDATE(LIGHTING_CHECK_UPDATE) // Will force an update without checking if it's actually needed. /datum/light_source/proc/force_update() - force_update = 1 - - effect_update(null) + INTELLIGENT_UPDATE(LIGHTING_FORCE_UPDATE) // Will cause the light source to recalculate turfs that were removed or added to visibility only. /datum/light_source/proc/vis_update() - vis_update = 1 + INTELLIGENT_UPDATE(LIGHTING_VIS_UPDATE) - effect_update(null) +// Decompile the hexadecimal colour into lumcounts of each perspective. +/datum/light_source/proc/parse_light_color() + if (light_color) + var/list/color_list = rgb2num(light_color) + lum_r = color_list[1] / 255 + lum_g = color_list[2] / 255 + lum_b = color_list[3] / 255 + else + lum_r = 1 + lum_g = 1 + lum_b = 1 -// Will check if we actually need to update, and update any variables that may need to be updated. -/datum/light_source/proc/check() - if(!source_atom || !light_outer_range || !light_max_bright) - destroy() - return 1 +#define POLAR_TO_CART_X(R,T) ((R) * cos(T)) +#define POLAR_TO_CART_Y(R,T) ((R) * sin(T)) +#define DETERMINANT(A_X,A_Y,B_X,B_Y) ((A_X)*(B_Y) - (A_Y)*(B_X)) +#define ARBITRARY_NUMBER 10 + +/datum/light_source/proc/regenerate_angle(ndir) + old_direction = ndir + + var/turf/front = get_step(source_turf, old_direction) + facing_opaque = (front && front.has_opaque_atom) + + cached_origin_x = test_x_offset = source_turf.x + cached_origin_y = test_y_offset = source_turf.y + + if (facing_opaque) + return + + var/limit_a_t + var/limit_b_t + + var/angle = light_angle * 0.5 + switch (old_direction) + if (NORTH) + limit_a_t = angle + 90 + limit_b_t = -(angle) + 90 + test_y_offset += 1 + + if (SOUTH) + limit_a_t = (angle) - 90 + limit_b_t = -(angle) - 90 + test_y_offset -= 1 + + if (EAST) + limit_a_t = angle + limit_b_t = -(angle) + test_x_offset += 1 + + if (WEST) + limit_a_t = angle + 180 + limit_b_t = -(angle) - 180 + test_x_offset -= 1 + + // Convert our angle + range into a vector. + limit_a_x = POLAR_TO_CART_X(light_range + ARBITRARY_NUMBER, limit_a_t) + limit_a_x = trunc(limit_a_x) + limit_a_y = POLAR_TO_CART_Y(light_range + ARBITRARY_NUMBER, limit_a_t) + limit_a_y = trunc(limit_a_y) + limit_b_x = POLAR_TO_CART_X(light_range + ARBITRARY_NUMBER, limit_b_t) + limit_b_x = trunc(limit_b_x) + limit_b_y = POLAR_TO_CART_Y(light_range + ARBITRARY_NUMBER, limit_b_t) + limit_b_y = trunc(limit_b_y) + +#undef ARBITRARY_NUMBER +#undef POLAR_TO_CART_Y +#undef POLAR_TO_CART_X + +/datum/light_source/proc/remove_lum(now = FALSE) + applied = FALSE - if(!top_atom) - top_atom = source_atom - . = 1 + var/thing + for (thing in affecting_turfs) + var/turf/T = thing + LAZYREMOVE(T.affecting_lights, src) - if(isturf(top_atom)) - if(source_turf != top_atom) - source_turf = top_atom - . = 1 - else if(top_atom.loc != source_turf) - source_turf = top_atom.loc - . = 1 + affecting_turfs = null - if(source_atom.light_max_bright != light_max_bright) - light_max_bright = source_atom.light_max_bright - . = 1 + for (thing in effect_str) + var/datum/lighting_corner/C = thing + REMOVE_CORNER(C,now) - if(source_atom.light_inner_range != light_inner_range) - light_inner_range = source_atom.light_inner_range - . = 1 + LAZYREMOVE(C.affecting, src) - if(source_atom.light_outer_range != light_outer_range) - light_outer_range = source_atom.light_outer_range - . = 1 + effect_str = null - if(source_atom.light_falloff_curve != light_falloff_curve) - light_falloff_curve = source_atom.light_falloff_curve - . = 1 +/datum/light_source/proc/recalc_corner(datum/lighting_corner/C, now = FALSE) + LAZYINITLIST(effect_str) + if (effect_str[C]) // Already have one. + REMOVE_CORNER(C,now) + effect_str[C] = 0 - if(light_max_bright && light_outer_range && !applied) - . = 1 + var/actual_range = (light_angle && facing_opaque) ? light_range * LIGHTING_BLOCKED_FACTOR : light_range - if(source_atom.light_color != light_color) - light_color = source_atom.light_color - parse_light_color() - . = 1 + var/Sx = pixel_turf.x + var/Sy = pixel_turf.y + var/Sz = pixel_turf.z -// Decompile the hexadecimal colour into lumcounts of each perspective. -/datum/light_source/proc/parse_light_color() - if(light_color) - lum_r = HEX_RED(light_color) / 255 - lum_g = HEX_GREEN(light_color) / 255 - lum_b = HEX_BLUE(light_color) / 255 - else - lum_r = 1 - lum_g = 1 - lum_b = 1 + var/height = C.z == Sz ? LIGHTING_HEIGHT : CALCULATE_CORNER_HEIGHT(C.z, Sz) + APPLY_CORNER(C, now, Sx, Sy, height) -// Macro that applies light to a new corner. -// It is a macro in the interest of speed, yet not having to copy paste it. -// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line. -// As such this all gets counted as a single line. -// The braces and semicolons are there to be able to do this on a single line. - -#define APPLY_CORNER(C) \ - . = LUM_FALLOFF(C, source_turf); \ - . *= (light_max_bright ** 2); \ - . *= light_max_bright < 0 ? -1:1;\ - effect_str[C] = .; \ - C.update_lumcount \ - ( \ - . * applied_lum_r, \ - . * applied_lum_g, \ - . * applied_lum_b \ - ); - -// I don't need to explain what this does, do I? -#define REMOVE_CORNER(C) \ - . = -effect_str[C]; \ - C.update_lumcount \ - ( \ - . * applied_lum_r, \ - . * applied_lum_g, \ - . * applied_lum_b \ - ); - -// This is the define used to calculate falloff. -// Assuming a brightness of 1 at range 1, formula should be (brightness = 1 / distance^2) -// However, due to the weird range factor, brightness = (-(distance - full_dark_start) / (full_dark_start - full_light_end)) ^ light_max_bright - -#define LUM_FALLOFF(C, T)(CLAMP01(-((((C.x - T.x) ** 2 +(C.y - T.y) ** 2) ** 0.5 - light_outer_range) / max(light_outer_range - light_inner_range, 1))) ** light_falloff_curve) - - -/datum/light_source/proc/apply_lum() - var/static/update_gen = 1 - applied = 1 - - // Keep track of the last applied lum values so that the lighting can be reversed - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b + UNSETEMPTY(effect_str) - FOR_DVIEW(var/turf/T, light_outer_range, source_turf, INVISIBILITY_LIGHTING) - check_t: - if(!T.lighting_corners_initialised) - T.generate_missing_corners() +/datum/light_source/proc/update_corners(now = FALSE) + var/update = FALSE - for(var/datum/lighting_corner/C in T.get_corners()) - if(C.update_gen == update_gen) - continue + if (QDELETED(source_atom)) + qdel(src) + return - C.update_gen = update_gen - C.affecting += src + if (source_atom.light_power != light_power) + light_power = source_atom.light_power + update = TRUE - if(!C.active) - effect_str[C] = 0 - continue + if (source_atom.light_range != light_range) + light_range = source_atom.light_range + update = TRUE - APPLY_CORNER(C) + if (!top_atom) + top_atom = source_atom + update = TRUE - LAZYADD(T.affecting_lights, src) - affecting_turfs += T + if (top_atom.loc != source_turf) + source_turf = top_atom.loc + UPDATE_APPROXIMATE_PIXEL_TURF + update = TRUE - if (T.z_flags & ZM_ALLOW_LIGHTING) - T = T.below - goto check_t + if (!light_range || !light_power) + qdel(src) + return - END_FOR_DVIEW + if (isturf(top_atom)) + if (source_turf != top_atom) + source_turf = top_atom + UPDATE_APPROXIMATE_PIXEL_TURF + update = TRUE + else if (top_atom.loc != source_turf) + source_turf = top_atom.loc + UPDATE_APPROXIMATE_PIXEL_TURF + update = TRUE - update_gen++ + if (!source_turf) + return // Somehow we've got a light in nullspace, no-op. -/datum/light_source/proc/remove_lum() - applied = FALSE + if (light_range && light_power && !applied) + update = TRUE - for(var/turf/T in affecting_turfs) - LAZYREMOVE(T.affecting_lights, src) + if (source_atom.light_color != light_color) + light_color = source_atom.light_color + parse_light_color() + update = TRUE + + else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b) + update = TRUE + + if (source_atom.light_wedge != light_angle) + light_angle = source_atom.light_wedge + update = TRUE + + if (light_angle) + var/ndir + if (ismob(top_atom) && top_atom:facing_dir) + ndir = top_atom:facing_dir + else if(top_atom.light_dir) + ndir = top_atom.light_dir + else + ndir = top_atom.dir + + if (old_direction != ndir) // If our direction has changed, we need to regenerate all the angle info. + regenerate_angle(ndir) + update = TRUE + else // Check if it was just a x/y translation, and update our vars without an regenerate_angle() call if it is. + var/co_updated = FALSE + if (source_turf.x != cached_origin_x) + test_x_offset += source_turf.x - cached_origin_x + cached_origin_x = source_turf.x + + co_updated = TRUE + + if (source_turf.y != cached_origin_y) + test_y_offset += source_turf.y - cached_origin_y + cached_origin_y = source_turf.y + + co_updated = TRUE + + if (co_updated) + // We might be facing a wall now. + var/turf/front = get_step(source_turf, old_direction) + var/new_fo = (front && front.has_opaque_atom) + if (new_fo != facing_opaque) + facing_opaque = new_fo + regenerate_angle(ndir) + + update = TRUE + + if (update) + needs_update = LIGHTING_CHECK_UPDATE + else if (needs_update == LIGHTING_CHECK_UPDATE) + return // No change. - affecting_turfs.Cut() + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + var/datum/lighting_corner/C + var/turf/T + var/list/Tcorners + var/Sx = pixel_turf.x // these are used by APPLY_CORNER_BY_HEIGHT + var/Sy = pixel_turf.y + var/Sz = pixel_turf.z + var/corner_height = LIGHTING_HEIGHT + var/actual_range = (light_angle && facing_opaque) ? light_range * LIGHTING_BLOCKED_FACTOR : light_range + var/test_x + var/test_y + + var/should_do_wedge = light_angle && !facing_opaque + + FOR_DVIEW(T, NONUNIT_CEILING(actual_range, 1), source_turf, 0) do + if (should_do_wedge) // Directional lighting coordinate filter. + test_x = T.x - test_x_offset + test_y = T.y - test_y_offset + + // If the signs of these are the same, then the point is within the cone. + if ((DETERMINANT(limit_a_x, limit_a_y, test_x, test_y) > 0) || DETERMINANT(test_x, test_y, limit_b_x, limit_b_y) > 0) + continue - for(var/datum/lighting_corner/C in effect_str) - REMOVE_CORNER(C) + Tcorners = T.corners + // These checks are inlined from generate_missing_corners. They must be kept in sync. + if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) || T.light_source_solo || T.light_source_multi || (T.z_flags & ZM_ALLOW_LIGHTING)) + if (!T.lighting_corners_initialised) + T.lighting_corners_initialised = TRUE - C.affecting -= src + if (!Tcorners) + T.corners = list(null, null, null, null) + Tcorners = T.corners - effect_str.Cut() + for (var/i = 1 to 4) + if (Tcorners[i]) + continue -/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) - if(effect_str.Find(C)) // Already have one. - REMOVE_CORNER(C) + Tcorners[i] = new /datum/lighting_corner(T, LIGHTING_CORNER_DIAGONAL[i], i) - APPLY_CORNER(C) + if (Tcorners && !T.has_opaque_atom) + for (var/v in 1 to 4) + var/val = Tcorners[v] + if (val) + corners[val] = 0 -/datum/light_source/proc/smart_vis_update() - var/list/datum/lighting_corner/corners = list() - var/list/turf/turfs = list() - FOR_DVIEW(var/turf/T, light_outer_range, source_turf, 0) - if(!T.lighting_corners_initialised) - T.generate_missing_corners() - corners |= T.get_corners() - turfs += T + turfs += T + + // Upwards lights are handled at the corner level, so only search down. + // This is a do-while associated with the FOR_DVIEW above. + while (T && (T.z_flags & ZM_ALLOW_LIGHTING) && (T = T.below)) + END_FOR_DVIEW - var/turf/simulated/open/O = T - if(istype(O) && O.below) - // Consider the turf below us as well. (Z-lights) - for(T = O.below; !isnull(T); T = update_the_turf(T,corners, turfs)); + LAZYINITLIST(affecting_turfs) var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. affecting_turfs += L - for(var/turf/T in L) + for (T as anything in L) LAZYADD(T.affecting_lights, src) L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. affecting_turfs -= L - for(var/turf/T in L) + for (T as anything in L) LAZYREMOVE(T.affecting_lights, src) - for(var/datum/lighting_corner/C in corners - effect_str) // New corners - C.affecting += src - if(!C.active) - effect_str[C] = 0 - continue + LAZYINITLIST(effect_str) + if (needs_update == LIGHTING_VIS_UPDATE) + for (C as anything in corners - effect_str) // newly added corners + LAZYADD(C.affecting, src) + if (!C.active) + effect_str[C] = 0 + continue + + INIT_CORNER_BY_HEIGHT(now) + else + L = corners - effect_str + for (C as anything in L) + LAZYADD(C.affecting, src) + if (!C.active) + effect_str[C] = 0 + continue + + INIT_CORNER_BY_HEIGHT(now) + + for (C as anything in corners - L) + if (!C.active) + effect_str[C] = 0 + continue - APPLY_CORNER(C) + APPLY_CORNER_BY_HEIGHT(now) - for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners. - REMOVE_CORNER(C) - C.affecting -= src - effect_str -= C + L = effect_str - corners + for (C as anything in L) + REMOVE_CORNER(C, now) + LAZYREMOVE(C.affecting, src) + effect_str -= L -/datum/light_source/proc/update_the_turf(var/turf/T, var/list/datum/lighting_corner/corners, var/list/turf/turfs) - if(!T.lighting_corners_initialised) - T.generate_missing_corners() - corners |= T.get_corners() - turfs += T + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b - var/turf/simulated/open/O = T - if(istype(O) && O.below) - return O.below - return null + UNSETEMPTY(effect_str) + UNSETEMPTY(affecting_turfs) -#undef effect_update -#undef LUM_FALLOFF -#undef REMOVE_CORNER -#undef APPLY_CORNER +#undef INTELLIGENT_UPDATE +#undef DETERMINANT +#undef GET_APPROXIMATE_PIXEL_DIR +#undef UPDATE_APPROXIMATE_PIXEL_TURF diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index a03c2c682f44..5543d1166c1b 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -1,110 +1,158 @@ /turf - var/dynamic_lighting = TRUE // Does the turf use dynamic lighting? - luminosity = 1 + var/dynamic_lighting = TRUE + luminosity = 1 var/tmp/lighting_corners_initialised = FALSE - var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf. - var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay. + /// List of light sources affecting this turf. + var/tmp/list/datum/light_source/affecting_lights + /// Our lighting overlay, used to apply multiplicative lighting to the tile and its contents. + var/tmp/atom/movable/lighting_overlay/lighting_overlay var/tmp/list/datum/lighting_corner/corners - var/opaque_counter + /// Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile. + var/tmp/has_opaque_atom = FALSE -/turf/set_opacity(new_opacity) - if(opacity == new_opacity) - return FALSE - - opacity = new_opacity - return RecalculateOpacity() - -/turf/proc/RecalculateOpacity() - var/old_opaque_counter = opaque_counter - - opaque_counter = opacity - for(var/a in src) - var/atom/A = a - opaque_counter += A.opacity - - // If the counter changed and was or became 0 then lift event/reconsider lights - if(opaque_counter != old_opaque_counter && (!opaque_counter || !old_opaque_counter)) - GLOB.opacity_set_event.raise_event(src, !opaque_counter, !!opaque_counter) - reconsider_lights() - return TRUE - return FALSE - -// Causes any affecting light sources to be queued for a visibility update, for example a door got opened. +/// Causes any affecting light sources to be queued for a visibility update, for example a door got opened. /turf/proc/reconsider_lights() - for(var/datum/light_source/L in affecting_lights) + var/datum/light_source/L + for (var/thing in affecting_lights) + L = thing L.vis_update() +/// Forces a lighting update. Reconsider lights is preferred when possible. +/turf/proc/force_update_lights() + var/datum/light_source/L + for (var/thing in affecting_lights) + L = thing + L.force_update() + /turf/proc/lighting_clear_overlay() - if(lighting_overlay) - qdel(lighting_overlay) + if (lighting_overlay) + if (lighting_overlay.loc != src) + PRINT_STACK_TRACE("Lighting overlay variable on turf [log_info_line(src)] is insane, lighting overlay actually located on [log_info_line(lighting_overlay.loc)]!") + + qdel(lighting_overlay, TRUE) + lighting_overlay = null - for(var/datum/lighting_corner/C in corners) + for (var/datum/lighting_corner/C in corners) C.update_active() // Builds a lighting overlay for us, but only if our area is dynamic. -/turf/proc/lighting_build_overlay() - if(lighting_overlay) - return +/turf/proc/lighting_build_overlay(now = FALSE) + if (lighting_overlay) + CRASH("Attempted to create lighting_overlay on tile that already had one.") - var/area/A = loc - if(A.dynamic_lighting && dynamic_lighting) - if(!lighting_corners_initialised) + if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) + if (!lighting_corners_initialised || !corners) generate_missing_corners() - new /atom/movable/lighting_overlay(src) + new /atom/movable/lighting_overlay(src, now) - for(var/datum/lighting_corner/C in corners) - if(!C.active) // We would activate the corner, calculate the lighting for it. - for(var/L in C.affecting) + for (var/datum/lighting_corner/C in corners) + if (!C.active) // We would activate the corner, calculate the lighting for it. + for (var/L in C.affecting) var/datum/light_source/S = L - S.recalc_corner(C) + S.recalc_corner(C, TRUE) C.active = TRUE -// Used to get a scaled lumcount. -/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) - if(!lighting_overlay) - var/area/A = loc - if(A.dynamic_lighting && dynamic_lighting) - var/atom/movable/lighting_overlay/O = new /atom/movable/lighting_overlay(src) - lighting_overlay = O +/// Returns the average color of this tile. Roughly corresponds to the color of a single old-style lighting overlay. +/turf/proc/get_avg_color() + if (!lighting_overlay) + return null + + var/lum_r + var/lum_g + var/lum_b + + for (var/datum/lighting_corner/L in corners) + lum_r += L.apparent_r + lum_g += L.apparent_g + lum_b += L.apparent_b + + lum_r = CLAMP01(lum_r / 4) * 255 + lum_g = CLAMP01(lum_g / 4) * 255 + lum_b = CLAMP01(lum_b / 4) * 255 + + return rgb(lum_r, lum_g, lum_b) + +#define SCALE(targ,min,max) (targ - min) / (max - min) + +/// Returns a lumcount (average intensity of color channels) scaled between minlum and maxlum. +/turf/proc/get_lumcount(minlum = 0, maxlum = 1) + if (!lighting_overlay) + return 0.5 var/totallums = 0 - for(var/datum/lighting_corner/L in corners) - totallums += max(L.lum_r, L.lum_g, L.lum_b) + for (var/datum/lighting_corner/L in corners) + totallums += L.apparent_r + L.apparent_b + L.apparent_g - totallums /= 4 // 4 corners, max channel selected, return the average + totallums /= 12 // 4 corners, each with 3 channels, get the average. - totallums =(totallums - minlum) /(maxlum - minlum) + totallums = SCALE(totallums, minlum, maxlum) return CLAMP01(totallums) -// If an opaque movable atom moves around we need to potentially update visibility. -/turf/Entered(var/atom/movable/AM, var/atom/OldLoc) +#undef SCALE + +/// Can't think of a good name, this proc will recalculate the has_opaque_atom variable. +/turf/proc/recalc_atom_opacity() +#ifdef AO_USE_LIGHTING_OPACITY + var/old = has_opaque_atom +#endif + + has_opaque_atom = FALSE + if (opacity) + has_opaque_atom = TRUE + else + for (var/thing in src) // Loop through every movable atom on our tile + var/atom/movable/A = thing + if (A.opacity) + has_opaque_atom = TRUE + break // No need to continue if we find something opaque. + +#ifdef AO_USE_LIGHTING_OPACITY + if (old != has_opaque_atom) + regenerate_ao() +#endif + +/turf/Exited(atom/movable/Obj, atom/newloc) . = ..() - if(AM?.opacity) - RecalculateOpacity() -/turf/Exited(var/atom/movable/AM, var/atom/newloc) + if (!Obj) + return + + if (Obj.opacity) + recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates. + reconsider_lights() + +// The normal opacity logic doesn't work for entities not located inside turfs, such as turfs. +/turf/set_opacity(new_opacity) . = ..() - if(AM?.opacity) - RecalculateOpacity() + reconsider_lights() -/turf/proc/get_corners() - if(opaque_counter) - return null // Since this proc gets used in a for loop, null won't be looped though. +// This block isn't needed now, but it's here if supporting area dyn lighting changes is needed later. - return corners +// /turf/change_area(area/old_area, area/new_area) +// if (new_area.dynamic_lighting != old_area.dynamic_lighting) +// if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)) +// lighting_build_overlay() +// else +// lighting_clear_overlay() +// This is inlined in lighting_source.dm. +// Update it too if you change this. /turf/proc/generate_missing_corners() + // If a turf is dynamically lit, has a light source, or mimics lighting, it needs to have corners created. + if (!TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) && !light_source_solo && !light_source_multi && !(z_flags & ZM_ALLOW_LIGHTING)) + return + lighting_corners_initialised = TRUE - if(!corners) - corners = list(null, null, null, null) + if (!corners) + corners = new(4) - for(var/i = 1 to 4) - if(corners[i]) // Already have a corner on this direction. + for (var/i = 1 to 4) + if (corners[i]) // Already have a corner on this direction. continue - corners[i] = new /datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i]) + corners[i] = new/datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i], i) diff --git a/code/modules/lighting/~lighting_undefs.dm b/code/modules/lighting/~lighting_undefs.dm index 7b0fc758090b..e59e3eeda738 100644 --- a/code/modules/lighting/~lighting_undefs.dm +++ b/code/modules/lighting/~lighting_undefs.dm @@ -1,3 +1,12 @@ +#undef LIGHTING_HEIGHT + #undef LIGHTING_ICON #undef LIGHTING_BASE_MATRIX + +#undef LUM_FALLOFF +#undef REMOVE_CORNER +#undef APPLY_CORNER + +#undef CALCULATE_CORNER_HEIGHT +#undef APPLY_CORNER_BY_HEIGHT diff --git a/code/modules/lights/light_bulbs_tubes.dm b/code/modules/lights/light_bulbs_tubes.dm new file mode 100644 index 000000000000..403bf7f4662b --- /dev/null +++ b/code/modules/lights/light_bulbs_tubes.dm @@ -0,0 +1,180 @@ +// the light item +// can be tube or bulb subtypes +// will fit into empty /obj/machinery/light of the corresponding type + +/obj/item/light + icon = 'icons/obj/lighting.dmi' + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/steel + atom_flags = ATOM_FLAG_CAN_BE_PAINTED + obj_flags = OBJ_FLAG_HOLLOW + var/const/MODE_EMERGENCY = "emergency_lighting" + var/const/MODE_READY = "ready" + + var/const/STATUS_OK = 0 + var/const/STATUS_EMPTY = 1 + var/const/STATUS_BROKEN = 2 + var/const/STATUS_BURNED = 3 + + var/status = STATUS_OK // STATUS_OK, STATUS_BURNED or STATUS_BROKEN + var/base_state + var/switchcount = 0 // number of times switched + var/rigged = 0 // true if rigged to explode + var/broken_chance = 2 + + var/b_power = 0.7 + var/b_range = 5 + var/b_color = LIGHT_COLOR_HALOGEN + var/list/lighting_modes = list() + var/sound_on + +/obj/item/light/get_color() + return b_color + +/obj/item/light/set_color(color) + b_color = isnull(color) ? COLOR_WHITE : color + queue_icon_update() // avoid running update_icon before Initialize + +/obj/item/light/tube + name = "light tube" + desc = "A replacement light tube." + icon_state = "ltube" + base_state = "ltube" + item_state = "c_tube" + material = /decl/material/solid/glass + matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT) + + b_range = 8 + b_power = 0.8 + b_color = LIGHT_COLOR_HALOGEN + lighting_modes = list( + MODE_EMERGENCY = list(l_range = 4, l_power = 1, l_color = LIGHT_COLOR_EMERGENCY), + ) + sound_on = 'sound/machines/lightson.ogg' + +/obj/item/light/tube/party/Initialize() //Randomly colored light tubes. Mostly for testing, but maybe someone will find a use for them. + . = ..() + b_color = rgb(pick(0,255), pick(0,255), pick(0,255)) + +/obj/item/light/tube/large + w_class = ITEM_SIZE_SMALL + name = "large light tube" + b_power = 4 + b_range = 12 + +/obj/item/light/tube/large/party/Initialize() //Randomly colored light tubes. Mostly for testing, but maybe someone will find a use for them. + . = ..() + b_color = rgb(pick(0,255), pick(0,255), pick(0,255)) + +/obj/item/light/bulb + name = "light bulb" + desc = "A replacement light bulb." + icon_state = "lbulb" + base_state = "lbulb" + item_state = "contvapour" + broken_chance = 3 + material = /decl/material/solid/glass + b_color = LIGHT_COLOR_TUNGSTEN + lighting_modes = list( + MODE_EMERGENCY = list(l_range = 3, l_power = 1, l_color = LIGHT_COLOR_EMERGENCY), + ) + +/obj/item/light/bulb/red + color = LIGHT_COLOR_RED + b_color = LIGHT_COLOR_RED + +/obj/item/light/bulb/red/readylight + lighting_modes = list( + MODE_READY = list(l_range = 5, l_power = 1, l_color = LIGHT_COLOR_GREEN), + ) + +/obj/item/light/throw_impact(atom/hit_atom) + ..() + shatter() + +/obj/item/light/bulb/fire + name = "fire bulb" + desc = "A replacement fire bulb." + icon_state = "fbulb" + base_state = "fbulb" + item_state = "egg4" + material = /decl/material/solid/glass + +// update the icon state and description of the light +/obj/item/light/on_update_icon() + . = ..() + var/broken + switch(status) + if(STATUS_OK) + icon_state = base_state + desc = "A replacement [name]." + if(STATUS_BURNED) + icon_state = "[base_state]_burned" + desc = "A burnt-out [name]." + if(STATUS_BROKEN) + icon_state = "[base_state]_broken" + desc = "A broken [name]." + broken = TRUE + add_overlay(overlay_image(icon, "[base_state]_attachment[broken ? "_broken" : ""]", flags = RESET_COLOR|RESET_ALPHA)) + +/obj/item/light/Initialize(mapload) + . = ..() + update_icon() + +// attack bulb/tube with object +// if a syringe, can inject flammable liquids to make it explode +/obj/item/light/attackby(var/obj/item/used_item, var/mob/user) + ..() + if(istype(used_item, /obj/item/chems/syringe) && REAGENT_TOTAL_VOLUME(used_item.reagents)) + var/obj/item/chems/syringe/S = used_item + to_chat(user, "You inject the solution into \the [src].") + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(S.reagents)) + if(reagent.accelerant_value > FUEL_VALUE_ACCELERANT) + rigged = TRUE + log_and_message_admins("injected a light with flammable reagents, rigging it to explode.", user) + break + S.reagents.clear_reagents() + return TRUE + . = ..() + +// called after an attack with a light item +// shatter light, unless it was an attempt to put it in a light socket +// now only shatter if the intent was harm + +/obj/item/light/afterattack(atom/target, mob/user, proximity) + if(!proximity) return + if(istype(target, /obj/machinery/light)) + return + if(!user.check_intent(I_FLAG_HARM)) + return + + shatter() + +/obj/item/light/shatter() + if(status == STATUS_OK || status == STATUS_BURNED) + src.visible_message(SPAN_WARNING("[name] shatters."), SPAN_WARNING("You hear a small glass object shatter.")) + status = STATUS_BROKEN + set_sharp(TRUE) + set_base_attack_force(5) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + update_icon() + +/obj/item/light/proc/switch_on() + switchcount++ + if(rigged) + addtimer(CALLBACK(src, PROC_REF(do_rigged_explosion)), 0.2 SECONDS) + status = STATUS_BROKEN + else if(prob(min(60, switchcount*switchcount*0.01))) + status = STATUS_BURNED + else if(sound_on) + playsound(src, sound_on, 75) + return status + +/obj/item/light/proc/do_rigged_explosion() + if(!rigged) + return + log_and_message_admins("Rigged light explosion, last touched by [fingerprintslast]") + var/turf/T = get_turf(src) + explosion(T, 0, 0, 3, 5) + if(!QDELETED(src)) + QDEL_IN(src, 1) diff --git a/code/modules/lights/light_fabrication.dm b/code/modules/lights/light_fabrication.dm new file mode 100644 index 000000000000..dde35d626cfa --- /dev/null +++ b/code/modules/lights/light_fabrication.dm @@ -0,0 +1,26 @@ +// Bulbs and tubes +/datum/fabricator_recipe/tube/large + path = /obj/item/light/tube/large + +/datum/fabricator_recipe/tube + path = /obj/item/light/tube + +/datum/fabricator_recipe/bulb + path = /obj/item/light/bulb + +// Switches +/datum/fabricator_recipe/engineering/light_switch + path = /obj/item/frame/button/light_switch/kit + +/datum/fabricator_recipe/engineering/window_tint + path = /obj/item/frame/button/light_switch/windowtint/kit + +// Frames +/datum/fabricator_recipe/engineering/spotlight + path = /obj/item/frame/light/spot + +/datum/fabricator_recipe/engineering/navlight + path = /obj/item/frame/light/nav + +/datum/fabricator_recipe/engineering/floorlamp + path = /obj/item/machine_chassis/flamp \ No newline at end of file diff --git a/code/modules/lights/light_fixture_base.dm b/code/modules/lights/light_fixture_base.dm new file mode 100644 index 000000000000..0f2f5741a626 --- /dev/null +++ b/code/modules/lights/light_fixture_base.dm @@ -0,0 +1,396 @@ +// the standard tube light fixture +/obj/machinery/light + name = "light fixture" + icon = 'icons/obj/lighting.dmi' + var/base_state = "tube" // base description and icon_state + icon_state = "tube_map" + desc = "A lighting fixture." + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + layer = ABOVE_HUMAN_LAYER // They were appearing under mobs which is a little weird - Ostaf + use_power = POWER_USE_ACTIVE + idle_power_usage = 2 + active_power_usage = 20 + power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list + + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc + ) + construct_state = /decl/machine_construction/wall_frame/panel_closed/simple + base_type = /obj/machinery/light + frame_type = /obj/item/frame/light + directional_offset = @'{"NORTH":{"y":21}, "EAST":{"x":10}, "WEST":{"x":-10}}' + + var/const/LIGHT_BULB_TEMPERATURE = 400 //K - used value for a 60W bulb + + var/const/WATTS_PER_LUM_RANGE = 5 // watts per luminosity-range + + var/on = 0 // 1 if on, 0 if off + var/flickering = 0 + var/light_type = /obj/item/light/tube // the type of light item + var/accepts_light_type = /obj/item/light/tube + /// A debounce var to prevent lights from causing infinite loops due to machinery power updates. + var/currently_updating = FALSE + + var/obj/item/light/lightbulb + + var/current_mode = null + +/obj/machinery/light/get_color() + return lightbulb?.get_color() + +/obj/machinery/light/set_color(color) + . = lightbulb?.set_color(color) + if(.) + update_light_status(TRUE) + update_icon() + +// create a new lighting fixture +/obj/machinery/light/Initialize(mapload, d=0, populate_parts = TRUE) + . = ..() + + switch (dir) + if (NORTH) + light_offset_y = WORLD_ICON_SIZE * 0.5 + if (SOUTH) + light_offset_y = WORLD_ICON_SIZE * -0.5 + if (EAST) + light_offset_x = WORLD_ICON_SIZE * 0.5 + if (WEST) + light_offset_x = WORLD_ICON_SIZE * -0.5 + + if(populate_parts && ispath(light_type)) + lightbulb = new light_type(src) + if(prob(lightbulb.broken_chance)) + broken(1) + + on = expected_to_be_on() + update_light_status(FALSE) + update_icon() + +/obj/machinery/light/Destroy() + QDEL_NULL(lightbulb) + . = ..() + +/// Handles light updates that were formerly done in update_icon. +/// * trigger (BOOL): if TRUE, this can trigger effects like burning out, rigged light explosions, etc. +/obj/machinery/light/proc/update_light_status(trigger = TRUE) + if(currently_updating) // avoid infinite loops during power usage updates + return + currently_updating = TRUE + if(get_bulb_status() == lightbulb::STATUS_OK) // we can't reuse this value later because update_use_power might change our status + atom_flags |= ATOM_FLAG_CAN_BE_PAINTED + else + atom_flags &= ~ATOM_FLAG_CAN_BE_PAINTED + on = FALSE + if(on) + update_use_power(POWER_USE_ACTIVE) + if(current_mode && (current_mode in lightbulb.lighting_modes)) + set_light(arglist(lightbulb.lighting_modes[current_mode])) + else + set_light(lightbulb.b_range, lightbulb.b_power, lightbulb.b_color) + if(trigger && get_bulb_status() == lightbulb::STATUS_OK) + switch_check() + else + update_use_power(POWER_USE_OFF) + set_light(0) + change_power_consumption((light_range * light_power) * WATTS_PER_LUM_RANGE, POWER_USE_ACTIVE) + currently_updating = FALSE + +/obj/machinery/light/update_use_power(new_use_power) + . = ..() + update_light_status(TRUE) + +/obj/machinery/light/on_update_icon() + // Update icon state + cut_overlays() + if(istype(construct_state)) + switch(construct_state.type) //Never use the initial state. That'll just reset it to the mapping icon. + if(/decl/machine_construction/wall_frame/no_wires/simple) + icon_state = "[base_state]-construct-stage1" + return + if(/decl/machine_construction/wall_frame/panel_open/simple) + icon_state = "[base_state]-construct-stage2" + return + + icon_state = "[base_state]_empty" + + // Extra overlays if we're active + var/_state + switch(get_bulb_status()) // set icon_states + if(lightbulb::STATUS_OK) + _state = "[base_state][on]" + if(lightbulb::STATUS_BURNED) + _state = "[base_state]_burned" + if(lightbulb::STATUS_BROKEN) + _state = "[base_state]_broken" + + if(istype(lightbulb, /obj/item/light)) + var/image/overlay_image = image(icon, _state) + overlay_image.color = get_mode_color() + add_overlay(overlay_image) + + if(on) + compile_overlays() // force a compile so that we update prior to the light being set + +/obj/machinery/light/proc/get_bulb_status() + return lightbulb ? lightbulb.status : lightbulb::STATUS_EMPTY + +/obj/machinery/light/proc/switch_check() + lightbulb.switch_on() + if(get_bulb_status() != lightbulb::STATUS_OK) + set_light(0) + +/obj/machinery/light/proc/set_mode(var/new_mode) + if(current_mode != new_mode) + current_mode = new_mode + update_light_status(FALSE) + update_icon() + +/obj/machinery/light/proc/get_mode_color() + if (current_mode && (current_mode in lightbulb.lighting_modes)) + return lightbulb.lighting_modes[current_mode]["l_color"] + else + return lightbulb.b_color + +/obj/machinery/light/proc/set_emergency_lighting(var/enable) + if(!lightbulb) + return + + if(enable) + if(lightbulb::MODE_EMERGENCY in lightbulb.lighting_modes) + set_mode(lightbulb::MODE_EMERGENCY) + update_power_channel(ENVIRON) + else + if(current_mode == lightbulb::MODE_EMERGENCY) + set_mode(null) + update_power_channel(initial(power_channel)) + +// attempt to set the light's on/off status +// will not switch on if broken/burned/empty +/obj/machinery/light/proc/seton(var/state) + on = (state && get_bulb_status() == lightbulb::STATUS_OK) + update_light_status(TRUE) + update_icon() + +// examine verb +/obj/machinery/light/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/fitting = get_fitting_name() + switch(get_bulb_status()) + if(lightbulb::STATUS_OK) + . += "It is turned [on? "on" : "off"]." + if(lightbulb::STATUS_EMPTY) + . += "The [fitting] has been removed." + if(lightbulb::STATUS_BURNED) + . += "The [fitting] is burnt out." + if(lightbulb::STATUS_BROKEN) + . += "The [fitting] has been smashed." + +/obj/machinery/light/proc/get_fitting_name() + // use accepts_light_type so stuff that begins blank is fine + var/obj/item/light/type_used = accepts_light_type + return type_used::name + +// attack with item - insert light (if right type), otherwise try to break the light + +/obj/machinery/light/proc/insert_bulb(obj/item/light/L) + L.forceMove(src) + lightbulb = L + + on = expected_to_be_on() + update_light_status(TRUE) + update_icon() + +/obj/machinery/light/proc/remove_bulb() + . = lightbulb + lightbulb.dropInto(loc) + lightbulb.update_icon() + lightbulb = null + update_light_status(TRUE) + update_icon() + +// Just... skip the entire test. We don't need to remove the bulbs from every single light just to test this. +/obj/machinery/light/fail_construct_state_unit_test() + return FALSE + +/obj/machinery/light/cannot_transition_to(state_path, mob/user) + if(lightbulb && !ispath(state_path, /decl/machine_construction/wall_frame/panel_closed)) + return SPAN_WARNING("You must first remove the lightbulb!") + return ..() + +/obj/machinery/light/attackby(obj/item/used_item, mob/user) + . = ..() + if(. || panel_open) + return + + // attempt to insert light + if(istype(used_item, /obj/item/light)) + if(lightbulb) + to_chat(user, "There is a [get_fitting_name()] already inserted.") + return + if(!istype(used_item, accepts_light_type)) + to_chat(user, "This type of light requires a [get_fitting_name()].") + return + if(!user.try_unequip(used_item, src)) + return + to_chat(user, "You insert [used_item].") + insert_bulb(used_item) + src.add_fingerprint(user) + + // attempt to break the light + //If xenos decide they want to smash a light bulb with a toolbox, who am I to stop them? /N + + else if(lightbulb && (lightbulb.status != lightbulb::STATUS_BROKEN) && !user.check_intent(I_FLAG_HELP)) + + if(prob(1 + used_item.expend_attack_force(user) * 5)) + + user.visible_message("[user.name] smashed the light!", "You smash the light!", "You hear a tinkle of breaking glass.") + if(on && (used_item.obj_flags & OBJ_FLAG_CONDUCTIBLE)) + if (prob(12)) + electrocute_mob(user, get_area(src), src, 0.3) + broken() + + else + to_chat(user, "You hit the light!") + + // attempt to stick weapon into light socket + else if(!lightbulb) + to_chat(user, "You stick \the [used_item] into the light socket!") + if(expected_to_be_on() && (used_item.obj_flags & OBJ_FLAG_CONDUCTIBLE)) + spark_at(src, cardinal_only = TRUE) + if (prob(75)) + electrocute_mob(user, get_area(src), src, rand(0.7,1.0)) + + +// returns whether this light is expected to be on, disregarding internal state other than power +// true if area has power and lightswitch is on +/obj/machinery/light/proc/expected_to_be_on() + var/area/A = get_area(src) + return A?.lightswitch && !(stat & NOPOWER) + +/obj/machinery/light/proc/flicker(var/amount = rand(10, 20)) + if(flickering) return + flickering = 1 + spawn(0) + if(on && get_bulb_status() == lightbulb::STATUS_OK) + for(var/i = 0; i < amount; i++) + if(get_bulb_status() != lightbulb::STATUS_OK) break + on = !on + update_light_status(FALSE) + sleep(rand(5, 15)) + on = (get_bulb_status() == lightbulb::STATUS_OK) + update_light_status(FALSE) + update_icon() + flickering = 0 + +// ai attack - make lights flicker, because why not + +/obj/machinery/light/attack_ai(mob/living/silicon/ai/user) + src.flicker(1) + +// attack with hand - remove tube/bulb +// if hands aren't protected and the light is on, burn the player +/obj/machinery/light/physical_attack_hand(mob/living/user) + if(!lightbulb) + to_chat(user, "There is no [get_fitting_name()] in this light.") + return TRUE + + if(user.can_shred()) + visible_message( + SPAN_DANGER("\The [user] smashes the light!"), + blind_message = "You hear a tinkle of breaking glass." + ) + broken() + return TRUE + + // make it burn hands if not wearing fire-insulated gloves + if(on) + + var/prot = FALSE + var/mob/living/human/H = user + if(istype(H)) + var/obj/item/clothing/gloves/gloves = H.get_equipped_item(slot_gloves_str) + if(istype(gloves) && gloves.max_heat_protection_temperature > LIGHT_BULB_TEMPERATURE) + prot = TRUE + + if(prot > 0 || user.has_genetic_condition(GENE_COND_COLD_RESISTANCE)) + to_chat(user, "You remove the [get_fitting_name()].") + else if(istype(user) && user.is_telekinetic()) + to_chat(user, "You telekinetically remove the [get_fitting_name()].") + else if(!user.check_intent(I_FLAG_HELP)) + var/obj/item/organ/external/hand = GET_EXTERNAL_ORGAN(H, user.get_active_held_item_slot()) + if(hand && hand.is_usable() && !hand.can_feel_pain()) + user.apply_damage(3, BURN, hand.organ_tag, used_weapon = src) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + SPAN_DANGER("\The [user]'s [hand.name] burns and sizzles as [pronouns.he] touch[pronouns.es] the hot [get_fitting_name()]."), \ + SPAN_DANGER("Your [hand.name] burns and sizzles as you remove the hot [get_fitting_name()].")) + else + to_chat(user, SPAN_WARNING("You try to remove the [get_fitting_name()], but it's too hot and you don't want to burn your hand.")) + return TRUE + else + to_chat(user, SPAN_NOTICE("You remove the [get_fitting_name()].")) + + // create a light tube/bulb item and put it in the user's hand + user.put_in_active_hand(remove_bulb()) //puts it in our active hand + return TRUE + +// break the light and make sparks if was on +/obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0) + if(!lightbulb) + return + + if(!skip_sound_and_sparks) + if(lightbulb && !(lightbulb.status == lightbulb::STATUS_BROKEN)) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + if(on) + spark_at(src, cardinal_only = TRUE) + lightbulb.status = lightbulb::STATUS_BROKEN + update_light_status(TRUE) + update_icon() + +/obj/machinery/light/proc/fix() + if(get_bulb_status() == lightbulb::STATUS_OK || !lightbulb) + return + lightbulb.status = lightbulb::STATUS_OK + on = TRUE + update_light_status(TRUE) + update_icon() + +// explosion effect +// destroy the whole light fixture or just shatter it + +/obj/machinery/light/explosion_act(severity) + . = ..() + if(. && !QDELETED(src)) + if(severity == 1) + physically_destroyed() + else if((severity == 2 && prob(75)) || (severity == 3 && prob(50))) + broken() + +// timed process +// use power + +// called when area power state changes +/obj/machinery/light/power_change() + . = ..() + if(.) + delay_and_set_on(expected_to_be_on(), 1 SECOND) + +/obj/machinery/light/proc/delay_and_set_on(var/new_state, var/delay) + set waitfor = FALSE + sleep(delay) + seton(new_state) + +// called when on fire + +/obj/machinery/light/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C + broken() + return ..() + +/obj/machinery/light/do_simple_ranged_interaction(var/mob/user) + if(lightbulb) + remove_bulb() + return TRUE \ No newline at end of file diff --git a/code/modules/lights/light_fixture_construction.dm b/code/modules/lights/light_fixture_construction.dm new file mode 100644 index 000000000000..eb0b410aab85 --- /dev/null +++ b/code/modules/lights/light_fixture_construction.dm @@ -0,0 +1,56 @@ +// Frames +/obj/item/frame/light + name = "light fixture frame" + desc = "Used for building lights." + icon = 'icons/obj/lighting.dmi' + icon_state = "tube-construct-item" + build_machine_type = /obj/machinery/light + reverse = 1 + +/obj/item/frame/light/small + name = "small light fixture frame" + icon_state = "bulb-construct-item" + material = /decl/material/solid/metal/steel + build_machine_type = /obj/machinery/light/small + +/obj/item/frame/light/spot + name = "spotlight fixture frame" + icon_state = "tube-construct-item" + material = /decl/material/solid/metal/steel + build_machine_type = /obj/machinery/light/spot + +/obj/item/frame/light/nav + name = "navigation light fixture frame" + icon_state = "tube-construct-item" + material = /decl/material/solid/metal/steel + build_machine_type = /obj/machinery/light/navigation + +/obj/item/machine_chassis/flamp + name = "lamp fixture frame" + desc = "A bare frame for a standing lamp fixture. Must be secured to the floor with a wrench." + icon = 'icons/obj/floorlamp.dmi' + icon_state = "flamp-construct-item" + w_class = ITEM_SIZE_STRUCTURE + material = /decl/material/solid/metal/steel + build_type = /obj/machinery/light/flamp/noshade/deconstruct + +// Partially-constructed presets for mapping +/obj/machinery/light/fixture + icon_state = "tube-construct-stage1" + +/obj/machinery/light/fixture/Initialize(mapload, d, populate_parts) + . = ..(mapload, d, populate_parts = FALSE) + construct_state.post_construct(src) + +/obj/machinery/light/small/fixture + icon_state = "bulb-construct-stage1" + +/obj/machinery/light/small/fixture/Initialize(mapload, d, populate_parts) + . = ..(mapload, d, populate_parts = FALSE) + construct_state.post_construct(src) + +// Subtype used for creation via crafting. +/obj/machinery/light/flamp/noshade/deconstruct + light_type = null + panel_open = TRUE + construct_state = /decl/machine_construction/wall_frame/no_wires/simple \ No newline at end of file diff --git a/code/modules/lights/light_fixture_floorlamp.dm b/code/modules/lights/light_fixture_floorlamp.dm new file mode 100644 index 000000000000..a580651cb975 --- /dev/null +++ b/code/modules/lights/light_fixture_floorlamp.dm @@ -0,0 +1,79 @@ +/obj/machinery/light/flamp + name = "lamp fixture" + desc = "A standing lamp fixture. Can be outfitted with a lampshade." + icon = 'icons/obj/floorlamp.dmi' + icon_state = "flampshade_map" + base_state = "flamp" + base_type = /obj/machinery/light/flamp + frame_type = /obj/item/machine_chassis/flamp + light_type = /obj/item/light/bulb/large + accepts_light_type = /obj/item/light/bulb/large + var/switch_state = TRUE + var/obj/item/lampshade/lampshade = new + +/obj/machinery/light/flamp/on_update_icon() + if(lampshade) + base_state = "flampshade" + else + base_state = "flamp" + . = ..() + +/obj/machinery/light/flamp/attackby(obj/item/used_item, mob/user) + if(!lampshade) + if(istype(used_item, /obj/item/lampshade)) + lampshade = used_item + user.drop_from_inventory(used_item, src) + update_light_status(FALSE) + update_icon() + return TRUE + else if(used_item.do_tool_interaction(TOOL_SCREWDRIVER, user, src, 1 SECOND, "unscrewing", "unscrewing")) + lampshade.dropInto(loc) + lampshade = null + update_light_status(FALSE) + update_icon() + return TRUE + return ..() + +/obj/machinery/light/flamp/expected_to_be_on() + // Lamps with lampshades are controlled by a switch on the lamp instead of a lightswitch. + if(lampshade) + return switch_state && !(stat & NOPOWER) + return ..() + +// Lamps with lampshades can be toggled by hand. +/obj/machinery/light/flamp/attack_hand(mob/user) + if(lampshade) + switch_state = !switch_state + playsound(src, 'sound/items/penclick.ogg', 5, FALSE) + user.visible_message( + "[user] pushes the lamp's lightswitch.", + SPAN_NOTICE("You push the lamp's lightswitch, turning it [switch_state ? "on" : "off"]."), + SPAN_NOTICE("You hear a click.")) + delay_and_set_on(expected_to_be_on(), 0.5 SECONDS) + return TRUE + return ..() + +/obj/item/light/bulb/large + name = "large light bulb" + b_range = 6 + b_power = 1 + lighting_modes = list( + MODE_EMERGENCY = list(l_range = 6, l_power = 0.45, l_color = LIGHT_COLOR_EMERGENCY), + ) + +/obj/item/light/bulb/large/Initialize(mapload, obj/machinery/light/fixture) + . = ..() + set_scale(1.2, 1.2) // i hate this + +/obj/machinery/light/flamp/noshade + icon_state = "flampshade_map" + lampshade = null + +/obj/item/lampshade + name = "lampshade" + desc = "A lampshade for a lamp." + icon = 'icons/obj/floorlamp.dmi' + icon_state = "lampshade" + material = /decl/material/solid/organic/cloth + obj_flags = OBJ_FLAG_HOLLOW + w_class = ITEM_SIZE_NORMAL diff --git a/code/modules/lights/light_fixture_navigation.dm b/code/modules/lights/light_fixture_navigation.dm new file mode 100644 index 000000000000..1e0046ef3fbb --- /dev/null +++ b/code/modules/lights/light_fixture_navigation.dm @@ -0,0 +1,36 @@ +/obj/machinery/light/navigation + name = "navigation light" + desc = "A periodically flashing light." + icon = 'icons/obj/lighting_nav.dmi' + icon_state = "nav10" + base_state = "nav1" + light_type = /obj/item/light/tube/large + accepts_light_type = /obj/item/light/tube/large + on = TRUE + var/delay = 1 + base_type = /obj/machinery/light/navigation + frame_type = /obj/item/frame/light/nav + stat_immune = NOPOWER | NOINPUT | NOSCREEN + +/obj/machinery/light/navigation/on_update_icon() + . = ..() // this will handle pixel offsets + icon_state = "nav[delay][!!(lightbulb && on)]" + +/obj/machinery/light/navigation/attackby(obj/item/used_item, mob/user) + . = ..() + if(!. && IS_MULTITOOL(used_item)) + delay = 5 + ((delay + 1) % 5) + to_chat(user, SPAN_NOTICE("You adjust the delay on \the [src].")) + return TRUE + +/obj/machinery/light/navigation/delay2 + delay = 2 + +/obj/machinery/light/navigation/delay3 + delay = 3 + +/obj/machinery/light/navigation/delay4 + delay = 4 + +/obj/machinery/light/navigation/delay5 + delay = 5 \ No newline at end of file diff --git a/code/modules/lights/light_fixture_small.dm b/code/modules/lights/light_fixture_small.dm new file mode 100644 index 000000000000..c3b745ee6602 --- /dev/null +++ b/code/modules/lights/light_fixture_small.dm @@ -0,0 +1,26 @@ +// the smaller bulb light fixture +/obj/machinery/light/small + icon_state = "bulb_map" + base_state = "bulb" + desc = "A small lighting fixture." + light_type = /obj/item/light/bulb + accepts_light_type = /obj/item/light/bulb + base_type = /obj/machinery/light/small + frame_type = /obj/item/frame/light/small + +/obj/machinery/light/small/emergency + light_type = /obj/item/light/bulb/red + +/obj/machinery/light/small/red + light_type = /obj/item/light/bulb/red + +/obj/machinery/light/small/readylight + light_type = /obj/item/light/bulb/red/readylight + var/state = 0 + +/obj/machinery/light/small/readylight/proc/set_state(var/new_state) + state = new_state + if(state) + set_mode(lightbulb::MODE_READY) + else + set_mode(null) diff --git a/code/modules/lights/light_fixture_spot.dm b/code/modules/lights/light_fixture_spot.dm new file mode 100644 index 000000000000..380a9d5a1563 --- /dev/null +++ b/code/modules/lights/light_fixture_spot.dm @@ -0,0 +1,7 @@ +/obj/machinery/light/spot + name = "spotlight" + desc = "A more robust socket for light tubes that demand more power." + light_type = /obj/item/light/tube/large + accepts_light_type = /obj/item/light/tube/large + base_type = /obj/machinery/light/spot + frame_type = /obj/item/frame/light/spot \ No newline at end of file diff --git a/code/modules/lights/light_replacer.dm b/code/modules/lights/light_replacer.dm new file mode 100644 index 000000000000..0292a67ce847 --- /dev/null +++ b/code/modules/lights/light_replacer.dm @@ -0,0 +1,168 @@ + +// Light Replacer (LR) +// +// ABOUT THE DEVICE +// +// This is a device supposedly to be used by Janitors and Janitor Cyborgs which will +// allow them to easily replace lights. This was mostly designed for Janitor Cyborgs since +// they don't have hands or a way to replace lightbulbs. +// +// HOW IT WORKS +// +// You attack a light fixture with it, if the light fixture is broken it will replace the +// light fixture with a working light; the broken light is then placed on the floor for the +// user to then pickup with a trash bag. If it's empty then it will just place a light in the fixture. +// +// HOW TO REFILL THE DEVICE +// +// It can be manually refilled or by clicking on a storage item containing lights. +// If it's part of a robot module, it will charge when the Robot is inside a Recharge Station. +// +// EMAGGED FEATURES +// +// NOTICE: The Cyborg cannot use the emagged Light Replacer and the light's explosion was nerfed. It cannot create holes in the station anymore. +// +// I'm not sure everyone will react the emag's features so please say what your opinions are of it. +// +// When emagged it will rig every light it replaces, which will explode when the light is on. +// This is VERY noticable, even the device's name changes when you emag it so if anyone +// examines you when you're holding it in your hand, you will be discovered. +// It will also be very obvious who is setting all these lights off, since only Janitor Borgs and Janitors have easy +// access to them, and only one of them can emag their device. +// +// The explosion cannot insta-kill anyone with 30% or more health. + +/obj/item/lightreplacer + name = "light replacer" + desc = "A lightweight automated device, capable of interfacing with and rapidly replacing standard light installations." + icon = 'icons/obj/items/light_replacer.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE + ) + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + origin_tech = @'{"magnets":3,"materials":2}' + + var/max_uses = 32 + var/uses = 32 + var/emagged = 0 + var/charge = 0 + +/obj/item/lightreplacer/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 2) + . += "It has [uses] light\s remaining." + +/obj/item/lightreplacer/resolve_attackby(var/atom/A, mob/user) + + //Check for lights in a container, refilling our charges. + if(A?.storage) + var/amt_inserted = 0 + var/turf/T = get_turf(user) + for(var/obj/item/light/L in A.storage.get_contents()) + if(!user.stat && src.uses < src.max_uses && L.status == 0) + src.AddUses(1) + amt_inserted++ + A.storage.remove_from_storage(user, L, T, TRUE) + qdel(L) + A.storage.finish_bulk_removal() + if(amt_inserted) + to_chat(user, "You insert [amt_inserted] light\s into \The [src]. It has [uses] light\s remaining.") + add_fingerprint(user) + return + + //Actually replace the light. + if(istype(A, /obj/machinery/light/)) + var/obj/machinery/light/L = A + if(isliving(user)) + var/mob/living/U = user + ReplaceLight(L, U) + add_fingerprint(user) + return + . = ..() + +// TODO: Refactor this to check matter or maybe even just use the fabricator recipe for lights directly +/obj/item/lightreplacer/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/stack/material) && used_item.get_material_type() == /decl/material/solid/glass) + var/obj/item/stack/G = used_item + if(uses >= max_uses) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + else if(G.use(1)) + AddUses(16) //Autolathe converts 1 sheet into 16 lights. // TODO: Make this use matter instead + to_chat(user, SPAN_NOTICE("You insert a piece of glass into \the [src]. You have [uses] light\s remaining.")) + else + to_chat(user, SPAN_WARNING("You need one sheet of glass to replace lights.")) + return TRUE + + if(istype(used_item, /obj/item/light)) + var/obj/item/light/L = used_item + if(L.status == 0) // LIGHT OKAY + if(uses < max_uses) + if(!user.try_unequip(L)) + return TRUE + AddUses(1) + to_chat(user, "You insert \the [L] into \the [src]. You have [uses] light\s remaining.") + qdel(L) + return TRUE + else + to_chat(user, "You need a working light.") + return TRUE + return ..() + +/obj/item/lightreplacer/attack_self(mob/user) + to_chat(usr, "It has [uses] lights remaining.") + return TRUE + +/obj/item/lightreplacer/on_update_icon() + . = ..() + if(emagged) + add_overlay("[icon_state]-emagged") + +/obj/item/lightreplacer/proc/Use(var/mob/user) + + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + AddUses(-1) + return 1 + +// Negative numbers will subtract +/obj/item/lightreplacer/proc/AddUses(var/amount = 1) + uses = min(max(uses + amount, 0), max_uses) + +/obj/item/lightreplacer/proc/Charge(var/mob/user, var/amount = 1) + charge += amount + if(charge > 6) + AddUses(1) + charge = 0 + +/obj/item/lightreplacer/proc/ReplaceLight(var/obj/machinery/light/target, var/mob/living/U) + + if(target.get_bulb_status() == /obj/item/light::STATUS_OK) + to_chat(U, "There is a working [target.get_fitting_name()] already inserted.") + else if(!CanUse(U)) + to_chat(U, "\The [src]'s refill light blinks red.") + else if(Use(U)) + to_chat(U, SPAN_NOTICE("You replace the [target.get_fitting_name()] with \the [src].")) + + if(target.lightbulb) + target.remove_bulb() + + var/obj/item/light/L = new target.light_type() + L.rigged = emagged + target.insert_bulb(L) + + +/obj/item/lightreplacer/emag_act(var/remaining_charges, var/mob/user) + emagged = !emagged + playsound(src.loc, "sparks", 100, 1) + update_icon() + return 1 + +//Can you use it? + +/obj/item/lightreplacer/proc/CanUse(var/mob/living/user) + src.add_fingerprint(user) + //Not sure what else to check for. Maybe if clumsy? + return uses > 0 diff --git a/code/modules/lights/light_switch.dm b/code/modules/lights/light_switch.dm new file mode 100644 index 000000000000..e35cfd1c9270 --- /dev/null +++ b/code/modules/lights/light_switch.dm @@ -0,0 +1,106 @@ +// the light switch +// can have multiple per area +// can also operate on non-loc area through "otherarea" var +/obj/machinery/light_switch + name = "light switch" + desc = "It switches lights on and off, obviously." + icon = 'icons/obj/power.dmi' + icon_state = "light0" + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + anchored = TRUE + idle_power_usage = 20 + power_channel = LIGHT + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + z_flags = ZMM_MANGLE_PLANES + layer = ABOVE_WINDOW_LAYER + + var/on = null // if null, takes from config option on init + var/area/connected_area = null + var/other_area = null + + construct_state = /decl/machine_construction/wall_frame/panel_closed/simple + frame_type = /obj/item/frame/button/light_switch + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc + ) + base_type = /obj/machinery/light_switch + directional_offset = @'{"NORTH":{"y":-20}, "SOUTH":{"y":25}, "EAST":{"x":-24}, "WEST":{"x":24}}' + +/obj/machinery/light_switch/on + on = TRUE + +/obj/machinery/light_switch/Initialize() + ..() + if(other_area) + connected_area = locate(other_area) + else + connected_area = get_area(src) + + if(connected_area && name == initial(name)) + SetName("light switch ([connected_area.proper_name])") + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/light_switch/LateInitialize() + . = ..() + + if(isnull(on)) + if(isnull(connected_area?.area_start_lit)) + on = get_config_value(/decl/config/toggle/lights_start_on) + else + on = connected_area.lightswitch + + connected_area?.set_lightswitch(on) + update_icon() + +/obj/machinery/light_switch/on_update_icon() + cut_overlays() + if(stat & (NOPOWER|BROKEN)) + icon_state = "light-p" + set_light(0) + z_flags &= ~ZMM_MANGLE_PLANES + else + icon_state = "light[on]" + add_overlay(emissive_overlay(icon, "[icon_state]-overlay")) + set_light(2, 0.25, on ? "#82ff4c" : "#f86060") + z_flags |= ZMM_MANGLE_PLANES + +/obj/machinery/light_switch/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance) + . += "It is [on? "on" : "off"]." + +/obj/machinery/light_switch/proc/set_state(var/newstate) + if(on != newstate) + on = newstate + connected_area.set_lightswitch(on) + update_icon() + +/obj/machinery/light_switch/proc/sync_state() + if(connected_area && on != connected_area.lightswitch) + on = connected_area.lightswitch + update_icon() + return 1 + +/obj/machinery/light_switch/interface_interact(mob/user) + if(CanInteract(user, DefaultTopicState())) + playsound(src, "switch", 30) + set_state(!on) + return TRUE + +/obj/machinery/light_switch/attackby(obj/item/used_item, mob/user) + . = ..() + if(!.) + to_chat(user, SPAN_NOTICE("You flick \the [src] with \the [used_item].")) + interface_interact(user) + return TRUE + +/obj/machinery/light_switch/area_changed(area/old_area, area/new_area) + . = ..() + if(QDELETED(src)) + return + if(other_area) + return + if(!new_area || old_area == new_area) + return + connected_area = new_area + sync_state() \ No newline at end of file diff --git a/code/modules/lights/light_switch_frames.dm b/code/modules/lights/light_switch_frames.dm new file mode 100644 index 000000000000..a415018a29c8 --- /dev/null +++ b/code/modules/lights/light_switch_frames.dm @@ -0,0 +1,24 @@ +/obj/item/frame/button/light_switch + name = "light switch frame" + desc = "Used for building a light switch." + icon = 'icons/obj/power.dmi' + icon_state = "light-p" + obj_flags = OBJ_FLAG_CONDUCTIBLE + build_machine_type = /obj/machinery/light_switch + +/obj/item/frame/button/light_switch/kit + name = "light switch kit" + fully_construct = TRUE + build_machine_type = /obj/machinery/light_switch + +/obj/item/frame/button/light_switch/windowtint + name = "window tint switch frame" + desc = "Used for building a window tint switch." + icon = 'icons/obj/power.dmi' + icon_state = "light-p" + build_machine_type = /obj/machinery/button/windowtint + +/obj/item/frame/button/light_switch/windowtint/kit + name = "window tint switch kit" + fully_construct = TRUE + build_machine_type = /obj/machinery/button/windowtint \ No newline at end of file diff --git a/code/modules/locks/key.dm b/code/modules/locks/key.dm index 11a5070c320f..ecfebc2fdc59 100644 --- a/code/modules/locks/key.dm +++ b/code/modules/locks/key.dm @@ -2,28 +2,53 @@ name = "key" desc = "Used to unlock things." icon = 'icons/obj/items/key.dmi' - icon_state = "keys" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_TINY - var/key_data = "" + material = /decl/material/solid/metal/brass + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + var/key_data -/obj/item/key/Initialize(mapload,var/data) - . = ..(mapload) - if(data) - key_data = data +/obj/item/key/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + if(key_data) + . += SPAN_NOTICE("\The [src] unlocks '[key_data]'.") + else + . += SPAN_NOTICE("\The [src] is blank.") /obj/item/key/proc/get_data(var/mob/user) return key_data -/obj/item/key/soap - name = "soap key" - desc = "a fragile key made using a bar of soap." +/obj/item/key/Initialize(mapload, material_key, _data) + . = ..(mapload, material_key) + key_data = _data + +/obj/item/key/get_mould_product_type() + return /obj/item/key + +/obj/item/key/take_mould_metadata(list/metadata) + if("key_data" in metadata) + key_data = metadata["key_data"] + return ..() + +/obj/item/key/get_mould_metadata() + . = list("key_data" = get_data()) + +/obj/item/key/temporary + name = "key" + desc = "A fragile key with limited uses." + material = /decl/material/liquid/cleaner/soap var/uses = 0 -/obj/item/key/soap/get_data(var/mob/user) +/obj/item/key/temporary/Initialize(mapload, material_key, _data, _uses) + . = ..(mapload, material_key, _data) + uses = _uses + +/obj/item/key/temporary/get_data(var/mob/user) uses-- if(uses == 1) - to_chat(user, "\The [src] is going to break soon!") + to_chat(user, SPAN_DANGER("\The [src] is going to break soon!")) else if(uses <= 0) - to_chat(user, "\The [src] crumbles in your hands.") + to_chat(user, SPAN_DANGER("\The [src] crumbles in your hands.")) qdel(src) return ..() diff --git a/code/modules/locks/keyring.dm b/code/modules/locks/keyring.dm new file mode 100644 index 000000000000..75225770e11b --- /dev/null +++ b/code/modules/locks/keyring.dm @@ -0,0 +1,46 @@ +/obj/item/keyring + name = "keyring" + desc = "A simple loop for threading keys onto." + icon = 'icons/obj/items/keyring.dmi' + icon_state = ICON_STATE_WORLD + storage = /datum/storage/keyring + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY | SLOT_POCKET + material = /decl/material/solid/metal/brass + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/keyring/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(length(contents) && distance <= 1) + var/key_strings = list() + for(var/obj/item/key/key in contents) + if(key.key_data) + key_strings += SPAN_NOTICE("\The [key] unlocks '[key.key_data]'.") + else + key_strings += SPAN_NOTICE("\The [key] is blank.") + if(length(key_strings)) + . += "\The [src] holds [length(key_strings)] key\s:" + . += key_strings + +/obj/item/keyring/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + var/key_count = 0 + for(var/obj/item/key/key in contents) + key_count++ + var/image/I = image(icon, "[icon_state]-[key_count]") + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + I.color = key.material?.color + I.alpha = key.alpha + add_overlay(I) + if(key_count >= 3) + break + +/datum/storage/keyring + can_hold = list( + /obj/item/key, + /obj/item/screwdriver, + /obj/item/stack/material/bow_ammo + ) + max_w_class = ITEM_SIZE_TINY + max_storage_space = 8 diff --git a/code/modules/locks/lock.dm b/code/modules/locks/lock.dm index efe2d0920d34..abb183d04b2f 100644 --- a/code/modules/locks/lock.dm +++ b/code/modules/locks/lock.dm @@ -1,48 +1,62 @@ #define LOCK_LOCKED 1 #define LOCK_BROKEN 2 +/obj/abstract/landmark/lock_preset + name = "locked door" + var/lock_preset_id = "default" + var/lock_material = /decl/material/solid/metal/iron + /// If lock_preset_id is null, a random key with this complexity will be generated instead. + var/lock_complexity = 1 + +/obj/abstract/landmark/lock_preset/Initialize() + ..() + for(var/obj/structure/thing in loc) + if(!thing.lock && thing.can_install_lock()) + thing.lock = new /datum/lock(thing, lock_preset_id || lock_complexity, lock_material) + thing.update_icon() + return INITIALIZE_HINT_QDEL /datum/lock var/status = 1 //unlocked, 1 == locked 2 == broken var/lock_data = "" //basically a randomized string. The longer the string the more complex the lock. var/atom/holder + var/material + var/lockpicking_skill = SKILL_DEVICES -/datum/lock/New(var/atom/h, var/complexity = 1) +/datum/lock/New(var/atom/h, var/complexity = 1, var/mat) holder = h if(istext(complexity)) lock_data = complexity else lock_data = generateRandomString(complexity) + material = mat || /decl/material/solid/metal/iron /datum/lock/Destroy() holder = null . = ..() /datum/lock/proc/unlock(var/key = "", var/mob/user) - if(status ^ LOCK_LOCKED) - to_chat(user, "Its already unlocked!") - return 2 + if(!isLocked()) + to_chat(user, SPAN_WARNING("It's already unlocked!")) + return FALSE key = get_key_data(key, user) - if(cmptext(lock_data,key) && (status ^ LOCK_BROKEN)) + if(cmptextEx(lock_data,key) && !(status & LOCK_BROKEN)) status &= ~LOCK_LOCKED - return 1 - return 0 + return TRUE + return FALSE /datum/lock/proc/lock(var/key = "", var/mob/user) - if(status & LOCK_LOCKED) - to_chat(user, "Its already locked!") - return 2 + if(isLocked()) + to_chat(user, SPAN_WARNING("It's already locked!")) + return FALSE key = get_key_data(key, user) - if(cmptext(lock_data,key) && (status ^ LOCK_BROKEN)) + if(cmptextEx(lock_data,key) && !(status & LOCK_BROKEN)) status |= LOCK_LOCKED - return 1 - return 0 + return TRUE + return FALSE /datum/lock/proc/toggle(var/key = "", var/mob/user) - if(status & LOCK_LOCKED) - return unlock(key, user) - else - return lock(key, user) + return isLocked() ? unlock(key, user) : lock(key, user) /datum/lock/proc/getComplexity() return length(lock_data) @@ -59,21 +73,21 @@ return status & LOCK_LOCKED /datum/lock/proc/pick_lock(var/obj/item/I, var/mob/user) - if(!istype(I) || (status ^ LOCK_LOCKED)) - return 0 + if(!istype(I) || !isLocked()) + return FALSE var/unlock_power = I.lock_picking_level if(!unlock_power) - return 0 - user.visible_message("\The [user] takes out \the [I], picking \the [holder]'s lock.") - if(!do_after(user, 20, holder)) - return 0 - if(prob(20*(unlock_power/getComplexity()))) - to_chat(user, "You pick open \the [holder]'s lock!") + return FALSE + user.visible_message("\The [user] begins to pick \the [holder]'s lock with \the [I].", SPAN_NOTICE("You begin picking \the [holder]'s lock.")) + if(!user.do_skilled(2 SECONDS, lockpicking_skill, holder, check_holding = TRUE, set_cooldown = TRUE)) + return FALSE + if(!user.skill_fail_prob(lockpicking_skill, 100 - (20*(unlock_power/getComplexity())), SKILL_EXPERT)) + to_chat(user, SPAN_NOTICE("You pick open \the [holder]'s lock!")) unlock(lock_data) - return 1 + return TRUE else if(prob(5 * unlock_power)) - to_chat(user, "You accidently break \the [holder]'s lock with your [I]!") - status |= LOCK_BROKEN + to_chat(user, SPAN_WARNING("You accidentally damage \the [I]!")) + I.take_damage(rand(5,10)) else - to_chat(user, "You fail to pick open \the [holder].") - return 0 \ No newline at end of file + to_chat(user, SPAN_WARNING("You fail to pick open \the [holder].")) + return FALSE diff --git a/code/modules/locks/lock_construct.dm b/code/modules/locks/lock_construct.dm index 4d69dbe92dbb..e8561f9b5b69 100644 --- a/code/modules/locks/lock_construct.dm +++ b/code/modules/locks/lock_construct.dm @@ -1,34 +1,41 @@ /obj/item/lock_construct name = "lock" - desc = "a crude but useful lock and bolt." + desc = "A simple tumbler lock and bolt, suitable for affixing to a door or closet." icon = 'icons/obj/items/doorlock.dmi' icon_state = "lock_construct" w_class = ITEM_SIZE_TINY + material = /decl/material/solid/metal/steel var/lock_data /obj/item/lock_construct/Initialize() . = ..() - force = 0 - throwforce = 0 lock_data = generateRandomString(round(material.integrity/50)) -/obj/item/lock_construct/attackby(var/obj/item/I, var/mob/user) - if(istype(I,/obj/item/key)) - var/obj/item/key/K = I +/obj/item/lock_construct/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(user && distance <= 1) + if(lock_data) + . += SPAN_NOTICE("\The [src] is unlocked with '[lock_data]'.") + else + . += SPAN_NOTICE("\The [src] is blank. Use a key on the lock to pair the two items.") + +/obj/item/lock_construct/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/key)) + var/obj/item/key/K = used_item if(!K.key_data) - to_chat(user, SPAN_NOTICE("You fashion \the [I] to unlock \the [src].")) + to_chat(user, SPAN_NOTICE("You fashion \the [used_item] to unlock \the [src].")) K.key_data = lock_data else - to_chat(user, SPAN_WARNING("\The [I] already unlocks something...")) - return - if(istype(I,/obj/item/lock_construct)) - var/obj/item/lock_construct/L = I + to_chat(user, SPAN_WARNING("\The [used_item] already unlocks something...")) + return TRUE + if(istype(used_item,/obj/item/lock_construct)) + var/obj/item/lock_construct/L = used_item src.lock_data = L.lock_data to_chat(user, SPAN_NOTICE("You copy the lock from \the [L] to \the [src], making them identical.")) - return - ..() + return TRUE + return ..() /obj/item/lock_construct/proc/create_lock(var/atom/target, var/mob/user) - . = new /datum/lock(target,lock_data) + . = new /datum/lock(target, lock_data, material?.type) user.visible_message(SPAN_NOTICE("\The [user] attaches \the [src] to \the [target].")) qdel(src) \ No newline at end of file diff --git a/code/modules/maps/__dmm_suite_docs.dm b/code/modules/maps/__dmm_suite_docs.dm new file mode 100644 index 000000000000..dd554aa01fd9 --- /dev/null +++ b/code/modules/maps/__dmm_suite_docs.dm @@ -0,0 +1,53 @@ +/* + + dmm_suite version 1.0 + Released January 30th, 2011. + + NOTE: Map saving functionality removed + + defines the object /dmm_suite + - Provides the proc load_map() + - Loads the specified map file onto the specified z-level. + - provides the proc write_map() + - Returns a text string of the map in dmm format + ready for output to a file. + - provides the proc save_map() + - Returns a .dmm file if map is saved + - Returns FALSE if map fails to save + + The dmm_suite provides saving and loading of map files in BYOND's native DMM map + format. It approximates the map saving and loading processes of the Dream Maker + and Dream Seeker programs so as to allow editing, saving, and loading of maps at + runtime. + + ------------------------ + + To save a map at runtime, create an instance of /dmm_suite, and then call + write_map(), which accepts three arguments: + - A turf representing one corner of a three dimensional grid (Required). + - Another turf representing the other corner of the same grid (Required). + - Any, or a combination, of several bit flags (Optional, see documentation). + + The order in which the turfs are supplied does not matter, the /dmm_writer will + determine the grid containing both, in much the same way as DM's block() function. + write_map() will then return a string representing the saved map in dmm format; + this string can then be saved to a file, or used for any other purose. + + ------------------------ + + To load a map at runtime, create an instance of /dmm_suite, and then call load_map(), + which accepts two arguments: + - A .dmm file to load (Required). + - A number representing the z-level on which to start loading the map (Optional). + + The /dmm_suite will load the map file starting on the specified z-level. If no + z-level was specified, world.maxz will be increased so as to fit the map. Note + that if you wish to load a map onto a z-level that already has objects on it, + you will have to handle the removal of those objects. Otherwise the new map will + simply load the new objects on top of the old ones. + + Also note that all type paths specified in the .dmm file must exist in the world's + code, and that the /dmm_reader trusts that files to be loaded are in fact valid + .dmm files. Errors in the .dmm format will cause runtime errors. + + */ diff --git a/code/modules/maps/_map_template.dm b/code/modules/maps/_map_template.dm new file mode 100644 index 000000000000..7f485c209677 --- /dev/null +++ b/code/modules/maps/_map_template.dm @@ -0,0 +1,238 @@ +/datum/map_template + abstract_type = /datum/map_template + ///Name for differentiating templates + var/name = "Default Template Name" + ///The width of the template's levels. Size is preloaded from template during template registration. + var/tmp/width = 0 + ///The height of the template's levels. Size is preloaded from template during template registration. + var/tmp/height = 0 + ///The amount of template levels. Size is preloaded from template during template registration. + var/tmp/tallness = 0 + ///Path to the map files to load for this template. + var/list/mappaths = null + ///Amount of times this template was loaded at runtime. + var/tmp/loaded = 0 // Times loaded this round + ///Shuttles in this template's levels that need to be initialized with SSshuttle. + var/list/shuttles_to_initialise = list() + ///Sub-templates to spawn on this template if any. Ruins and sites and etc.. + var/list/subtemplates_to_spawn = list() + ///Percent of chances to end up onto a level from this template by spacewalking between space z-levels. + var/accessibility_weight = 0 + ///Flags for defining special properties of this template. + var/template_flags = TEMPLATE_FLAG_ALLOW_DUPLICATES + ///Will modify tag vars so that duplicate templates are handled properly. May have compatibility issues with legacy maps (esp. with ferry shuttles). + var/modify_tag_vars = TRUE + ///List of strings to store the templates under for mass retrieval. + var/list/template_categories + ///The initial type of level_data to instantiate new z-level with initially. (Is replaced by whatever is in the map file.) If null, will use default. + var/level_data_type + /// Whether or not this should show up for admin map spawning. + var/is_spawnable = TRUE + /// Various tags used for selecting templates for placement on a map. + var/template_tags = 0 + +/datum/map_template/New(var/created_ad_hoc) + if(created_ad_hoc != SSmapping.type) + PRINT_STACK_TRACE("Ad hoc map template created ([type])!") + +/datum/map_template/proc/preload() + if(length(mappaths)) + preload_size() + return TRUE + +/datum/map_template/proc/get_spawn_weight() + return 0 + +/datum/map_template/proc/get_template_cost() + return 0 + +/datum/map_template/proc/get_template_tags() + return template_tags + +/datum/map_template/proc/preload_size() + var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF) + var/z_offset = 1 // needed to calculate z-bounds correctly + for (var/mappath in mappaths) + var/datum/map_load_metadata/M = maploader.load_map(file(mappath), 1, 1, z_offset, cropMap=FALSE, measureOnly=TRUE, no_changeturf=TRUE, clear_contents=(template_flags & TEMPLATE_FLAG_CLEAR_CONTENTS), level_data_type=src.level_data_type) + if(M) + extend_bounds_if_needed(bounds, M.bounds) + z_offset++ + else + return FALSE + width = bounds[MAP_MAXX] - bounds[MAP_MINX] + 1 + height = bounds[MAP_MAXY] - bounds[MAP_MINX] + 1 + tallness = bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1 + return TRUE + +/datum/map_template/proc/init_atoms(var/list/atoms) + if (SSatoms.atom_init_stage == INITIALIZATION_INSSATOMS) + return // let proper initialisation handle it later + + SSatoms.InitializeAtoms() // The atoms should have been getting queued there. This flushes the queue. + + for(var/obj/abstract/landmark/map_load_mark/landmark in atoms) + subtemplates_to_spawn += landmark + + // fun fact: these already filter for us, so it's pointless to sort + SSmachines.setup_powernets_for_cables(atoms) + SSmachines.setup_atmos_machinery(atoms) + + for (var/turf/T in atoms) + if(template_flags & TEMPLATE_FLAG_NO_RUINS) + T.turf_flags |= TURF_FLAG_NO_POINTS_OF_INTEREST + if(template_flags & TEMPLATE_FLAG_NO_RADS) + qdel(SSradiation.sources_assoc[T]) + if(T.simulated) + SSair.mark_for_update(T) + +/datum/map_template/proc/pre_init_shuttles() + . = SSshuttle.block_queue + SSshuttle.block_queue = TRUE + +/datum/map_template/proc/init_shuttles(var/pre_init_state, var/map_hash, var/list/initialized_areas_by_type) + for (var/shuttle_type in shuttles_to_initialise) + LAZYSET(SSshuttle.shuttles_to_initialize, shuttle_type, map_hash) // queue up for init. + if(map_hash) + SSshuttle.map_hash_to_areas[map_hash] = initialized_areas_by_type + for(var/area/A in initialized_areas_by_type) + A.saved_map_hash = map_hash + events_repository.register(/decl/observ/destroyed, A, src, PROC_REF(cleanup_lateloaded_area)) + SSshuttle.block_queue = pre_init_state + SSshuttle.clear_init_queue() // We will flush the queue unless there were other blockers, in which case they will do it. + +/datum/map_template/proc/cleanup_lateloaded_area(area/destroyed_area) + events_repository.unregister(/decl/observ/destroyed, destroyed_area, src, PROC_REF(cleanup_lateloaded_area)) + if(destroyed_area.saved_map_hash) + SSshuttle.map_hash_to_areas[destroyed_area.saved_map_hash] -= destroyed_area + +///Handle loading a single map path its bottom left corner starting at x,y,z. +/// Returns a /datum/map_load_metadata if loading was successful. +/// Meant to be overridden for handling extra per-map file processing. +/datum/map_template/proc/load_single_path(var/mappath, var/x, var/y, var/z, var/list/bounds, var/list/initialized_areas_by_type, var/no_changeturf, var/cropMap) + var/datum/map_load_metadata/M = maploader.load_map( + dmm_file = file(mappath), + x_offset = x, + y_offset = y, + z_offset = z, + cropMap = cropMap, + no_changeturf = no_changeturf, + initialized_areas_by_type = initialized_areas_by_type, + clear_contents = (template_flags & TEMPLATE_FLAG_CLEAR_CONTENTS), + level_data_type = src.level_data_type + ) + if(!M) + PRINT_STACK_TRACE("Template '[src]' failed to load map '[mappath]' at ([x], [y], [z]).") + else if(bounds) + extend_bounds_if_needed(bounds, M.bounds) + return M + +///Load the template onto a freshly created z-level. +/// * If centered is TRUE, the template's center will be aligned to the world's center. Otherwise, the template will load at pos 1,1. +/datum/map_template/proc/load_new_z(no_changeturf = TRUE, centered = TRUE) + //When we're set to centered we're aligning the center of the template to the center of the map + var/x = max(ceil((WORLD_CENTER_X - width/2)), 1) + var/y = max(ceil((WORLD_CENTER_Y - height/2)), 1) + if(!centered) + x = 1 + y = 1 + + var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF) + var/list/atoms_to_initialise = list() + var/shuttle_state = pre_init_shuttles() + var/map_hash = modify_tag_vars && "[sequential_id("map_id")]" + ASSERT(isnull(global._preloader.current_map_hash)) // Recursive maploading is possible, but not from this block: recursive loads should be triggered in Initialize, from init_atoms below. + global._preloader.current_map_hash = map_hash + + var/initialized_areas_by_type = list() + for (var/mappath in mappaths) + var/datum/map_load_metadata/M = load_single_path(mappath, x, y, world.maxz + 1, bounds, initialized_areas_by_type, no_changeturf, FALSE) + if (M) + atoms_to_initialise += M.atoms_to_initialise + else + //Abort if loading failed + global._preloader.current_map_hash = null //Clear current map hash to prevent problems if we load something else later and cause false positives + CRASH("Failed to load '[src]''s '[mappath]' map file!") + + global._preloader.current_map_hash = null + + //initialize things that are normally initialized after map load + Master.StartLoadingMap() + init_atoms(atoms_to_initialise) + init_shuttles(shuttle_state, map_hash, initialized_areas_by_type) + after_load() + for(var/z_index = bounds[MAP_MINZ] to bounds[MAP_MAXZ]) + var/datum/level_data/level = SSmapping.levels_by_z[z_index] + level.after_template_load(src) + Master.StopLoadingMap() + log_game("Z-level [name] loaded at [x],[y],[world.maxz]") + loaded++ + + return WORLD_CENTER_TURF(world.maxz) + +/datum/map_template/proc/load(turf/T, centered=FALSE) + if(centered) + T = locate(ceil(T.x - width/2), ceil(T.y - height/2), T.z) + if(!T) + CRASH("Can't load '[src]' (size: [width]x[height]) onto a null turf! Current world size ([WORLD_SIZE_TO_STRING]).") + if(!IS_WITHIN_WORLD((T.x + width - 1), (T.y + height - 1))) // the first row/column begins with T, so subtract 1 + CRASH("Couldn't fit the entire template '[src]' (size: [width]x[height]) between lower left corner ([T.x], [T.y])[centered?"(WORLD CENTER)":""] and upper right corner ([T.x + width], [T.y + height]) in current world size ([WORLD_SIZE_TO_STRING]).") + + var/list/atoms_to_initialise = list() + var/shuttle_state = pre_init_shuttles() + + var/map_hash = modify_tag_vars && "[sequential_id("map_id")]" + ASSERT(isnull(global._preloader.current_map_hash)) + global._preloader.current_map_hash = map_hash + + var/initialized_areas_by_type = list() + for (var/mappath in mappaths) + var/datum/map_load_metadata/M = load_single_path(mappath, T.x, T.y, T.z, null, initialized_areas_by_type, FALSE, TRUE) + if (M) + atoms_to_initialise += M.atoms_to_initialise + else + //Abort if loading failed + global._preloader.current_map_hash = null //Clear current map hash to prevent problems if we load something else later and cause false positives + CRASH("Failed to load '[src]''s '[mappath]' map file!") + + global._preloader.current_map_hash = null + + //initialize things that are normally initialized after map load + Master.StartLoadingMap() + init_atoms(atoms_to_initialise) + init_shuttles(shuttle_state, map_hash, initialized_areas_by_type) + after_load() + Master.StopLoadingMap() + + log_game("[name] loaded at [T.x],[T.y],[T.z]") + loaded++ + + return TRUE + +/datum/map_template/proc/after_load() + for(var/obj/abstract/landmark/map_load_mark/mark as anything in subtemplates_to_spawn) + subtemplates_to_spawn -= mark + mark.load_subtemplate() + if(!QDELETED(mark)) // for if the tile that lands on the landmark is a no-op tile + qdel(mark) + subtemplates_to_spawn = null + generate_multi_spawn_items() + +/datum/map_template/proc/extend_bounds_if_needed(var/list/existing_bounds, var/list/new_bounds) + var/list/bounds_to_combine = existing_bounds + for (var/min_bound in list(MAP_MINX, MAP_MINY, MAP_MINZ)) + bounds_to_combine[min_bound] = min(existing_bounds[min_bound], new_bounds[min_bound]) + for (var/max_bound in list(MAP_MAXX, MAP_MAXY, MAP_MAXZ)) + bounds_to_combine[max_bound] = max(existing_bounds[max_bound], new_bounds[max_bound]) + return bounds_to_combine + +/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE) + var/turf/placement = T + if(centered) + var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z) + if(corner) + placement = corner + return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z)) + +///Returns whether a given map template is generated at runtime. Mainly used by unit tests. +/datum/map_template/proc/is_runtime_generated() + return FALSE diff --git a/code/modules/maps/_map_template_unit_testing.dm b/code/modules/maps/_map_template_unit_testing.dm new file mode 100644 index 000000000000..13e82ac10b78 --- /dev/null +++ b/code/modules/maps/_map_template_unit_testing.dm @@ -0,0 +1,19 @@ +/datum/map_template + var/const/NO_APC = BITFLAG(0) + var/const/NO_VENT = BITFLAG(1) + var/const/NO_SCRUBBER = BITFLAG(2) + var/const/SKIP_ALL_TESTS = BITFLAG(3) + + var/list/area_usage_test_exempted_areas = list() + var/list/area_usage_test_exempted_root_areas = list() + var/list/apc_test_exempt_areas = list() + var/list/area_coherency_test_exempt_areas = list() + var/list/area_coherency_test_subarea_count = list() + +/datum/map_template/New(var/created_ad_hoc) + ..(created_ad_hoc) + global.using_map.area_usage_test_exempted_areas |= area_usage_test_exempted_areas + global.using_map.area_usage_test_exempted_root_areas |= area_usage_test_exempted_root_areas + global.using_map.apc_test_exempt_areas |= apc_test_exempt_areas + global.using_map.area_coherency_test_exempt_areas |= area_coherency_test_exempt_areas + global.using_map.area_coherency_test_subarea_count |= area_coherency_test_subarea_count \ No newline at end of file diff --git a/code/modules/maps/dmm_suite.dm b/code/modules/maps/dmm_suite.dm deleted file mode 100644 index 8b9ec2958c52..000000000000 --- a/code/modules/maps/dmm_suite.dm +++ /dev/null @@ -1,65 +0,0 @@ -var/global/dmm_suite/maploader = new - -dmm_suite{ - /* - - dmm_suite version 1.0 - Released January 30th, 2011. - - NOTE: Map saving functionality removed - - defines the object /dmm_suite - - Provides the proc load_map() - - Loads the specified map file onto the specified z-level. - - provides the proc write_map() - - Returns a text string of the map in dmm format - ready for output to a file. - - provides the proc save_map() - - Returns a .dmm file if map is saved - - Returns FALSE if map fails to save - - The dmm_suite provides saving and loading of map files in BYOND's native DMM map - format. It approximates the map saving and loading processes of the Dream Maker - and Dream Seeker programs so as to allow editing, saving, and loading of maps at - runtime. - - ------------------------ - - To save a map at runtime, create an instance of /dmm_suite, and then call - write_map(), which accepts three arguments: - - A turf representing one corner of a three dimensional grid (Required). - - Another turf representing the other corner of the same grid (Required). - - Any, or a combination, of several bit flags (Optional, see documentation). - - The order in which the turfs are supplied does not matter, the /dmm_writer will - determine the grid containing both, in much the same way as DM's block() function. - write_map() will then return a string representing the saved map in dmm format; - this string can then be saved to a file, or used for any other purose. - - ------------------------ - - To load a map at runtime, create an instance of /dmm_suite, and then call load_map(), - which accepts two arguments: - - A .dmm file to load (Required). - - A number representing the z-level on which to start loading the map (Optional). - - The /dmm_suite will load the map file starting on the specified z-level. If no - z-level was specified, world.maxz will be increased so as to fit the map. Note - that if you wish to load a map onto a z-level that already has objects on it, - you will have to handle the removal of those objects. Otherwise the new map will - simply load the new objects on top of the old ones. - - Also note that all type paths specified in the .dmm file must exist in the world's - code, and that the /dmm_reader trusts that files to be loaded are in fact valid - .dmm files. Errors in the .dmm format will cause runtime errors. - - */ - - proc/load_map(var/list/dmm_files, var/x_offset, var/y_offset, var/z_offset, var/cropMap, var/measureOnly, var/no_changeturf){ - // dmm_files: A list of .dmm files to load (Required). - // z_offset: A number representing the z-level on which to start loading the map (Optional). - // cropMap: When true, the map will be cropped to fit the existing world dimensions (Optional). - // measureOnly: When true, no changes will be made to the world (Optional). - // no_changeturf: When true, turf/AfterChange won't be called on loaded turfs - } -} \ No newline at end of file diff --git a/code/modules/maps/helper_landmarks.dm b/code/modules/maps/helper_landmarks.dm index 3cecaa69442e..990300442c85 100644 --- a/code/modules/maps/helper_landmarks.dm +++ b/code/modules/maps/helper_landmarks.dm @@ -1,73 +1,251 @@ //Load a random map template from the list. Maploader handles it to avoid order of init madness -/obj/effect/landmark/map_load_mark +/obj/abstract/landmark/map_load_mark name = "map loader landmark" - var/list/templates //list of template types to pick from + is_spawnable_type = FALSE + var/centered = TRUE + var/list/map_template_names //list of template names to pick from + +INITIALIZE_IMMEDIATE(/obj/abstract/landmark/map_load_mark) +/obj/abstract/landmark/map_load_mark/Initialize() + . = ..() + if(Master.map_loading) // If we're created while a map is being loaded + return // Let after_load() handle us + if(!SSmapping.initialized) // If we're being created prior to SSmapping + SSmapping.queued_markers += src // Then run after SSmapping + else + // How did we get here? + // These should only be loaded from compiled maps or map templates. + PRINT_STACK_TRACE("map_load_mark created outside of maploading") + init_load_subtemplate() + +/obj/abstract/landmark/map_load_mark/proc/get_subtemplate() + if(isnull(map_template_names)) + return null + if(istext(map_template_names)) + return map_template_names + if(length(map_template_names)) + return pick(map_template_names) + +/obj/abstract/landmark/map_load_mark/proc/init_load_subtemplate() + set waitfor = FALSE + load_subtemplate() + +/obj/abstract/landmark/map_load_mark/proc/load_subtemplate() + // Commenting this out temporarily as DMMS breaks when asychronously + // loading overlapping map templates. TODO: more robust queuing behavior + //set waitfor = FALSE + + var/datum/map_template/template = get_subtemplate() + var/turf/spawn_loc = get_turf(src) + + if(istype(spawn_loc)) + if(istext(template)) + template = SSmapping.get_template(template) + if(istype(template)) + template.load(spawn_loc, centered = centered) + + if(!QDELETED(src)) + qdel(src) //Throw things in the area around randomly -/obj/effect/landmark/carnage_mark +/obj/abstract/landmark/carnage_mark name = "carnage landmark" var/movement_prob = 50 // a chance random unanchored item in the room will be moved randomly var/movement_range = 3 // how far would items get thrown -/obj/effect/landmark/carnage_mark/Initialize() +/obj/abstract/landmark/carnage_mark/Initialize() . = ..() return INITIALIZE_HINT_LATELOAD -/obj/effect/landmark/carnage_mark/LateInitialize() - var/area/A = get_area(src) - for(var/atom/movable/AM in A) - if(AM && !AM.anchored && AM.simulated && prob(movement_prob)) - spawn() - AM.throw_at_random(FALSE, movement_range, 1) +/obj/abstract/landmark/carnage_mark/LateInitialize() + do_throw() + +/obj/abstract/landmark/carnage_mark/proc/do_throw() + set waitfor = FALSE + sleep(0) + var/area/our_area = get_area(src) + for(var/atom/movable/throw_candidate in our_area) + if(!QDELETED(throw_candidate) && !throw_candidate.anchored && throw_candidate.simulated && prob(movement_prob)) + throw_candidate.throw_at_random(FALSE, movement_range, 1) qdel(src) //Clears walls -/obj/effect/landmark/clear +/obj/abstract/landmark/clear name = "clear turf" icon_state = "clear" - delete_me = TRUE + //Don't set delete_me to true, since we work inside lateinitialize + +/obj/abstract/landmark/clear/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD -/obj/effect/landmark/clear/Initialize() - var/turf/simulated/wall/W = get_turf(src) - if(istype(W)) - W.dismantle_wall(1,1,1) +/obj/abstract/landmark/clear/LateInitialize() . = ..() + var/turf/wall/wall = get_turf(src) + if(istype(wall)) + wall.dismantle_turf(TRUE, TRUE, TRUE) + qdel(src) //Applies fire act to the turf -/obj/effect/landmark/scorcher +/obj/abstract/landmark/scorcher name = "fire" icon_state = "fire" - var/temp = T0C + 3000 + var/temp = T0C + 4000 -/obj/effect/landmark/scorcher/Initialize() - var/turf/simulated/T = get_turf(src) +/obj/abstract/landmark/scorcher/Initialize() + var/turf/T = get_turf(src) if(istype(T)) T.fire_act(exposed_temperature = temp) . = ..() //Delete specified things when a specified shuttle moves -/obj/effect/landmark/delete_on_shuttle +/obj/abstract/landmark/delete_on_shuttle var/shuttle_name var/shuttle_datum var/list/typetodelete = list(/obj/machinery, /obj/item/gun, /mob/living/exosuit, /obj/item/transfer_valve) -/obj/effect/landmark/delete_on_shuttle/Initialize() +/obj/abstract/landmark/delete_on_shuttle/Initialize() . = ..() - GLOB.shuttle_added.register_global(src, .proc/check_shuttle) + events_repository.register_global(/decl/observ/shuttle_added, src, PROC_REF(check_shuttle)) -/obj/effect/landmark/delete_on_shuttle/proc/check_shuttle(var/shuttle) +/obj/abstract/landmark/delete_on_shuttle/proc/check_shuttle(var/shuttle) if(SSshuttle.shuttles[shuttle_name] == shuttle) - GLOB.shuttle_moved_event.register(shuttle, src, .proc/delete_everything) + events_repository.register(/decl/observ/shuttle_moved, shuttle, src, PROC_REF(delete_everything)) shuttle_datum = shuttle -/obj/effect/landmark/delete_on_shuttle/proc/delete_everything() +/obj/abstract/landmark/delete_on_shuttle/proc/delete_everything() for(var/O in loc) if(is_type_in_list(O,typetodelete)) qdel(O) qdel(src) -/obj/effect/landmark/delete_on_shuttle/Destroy() - GLOB.shuttle_added.unregister_global(src, .proc/check_shuttle) +/obj/abstract/landmark/delete_on_shuttle/Destroy() + events_repository.unregister_global(/decl/observ/shuttle_added, src, PROC_REF(check_shuttle)) if(shuttle_datum) - GLOB.shuttle_moved_event.unregister(shuttle_datum, src, .proc/delete_everything) - . = ..() \ No newline at end of file + events_repository.unregister(/decl/observ/shuttle_moved, shuttle_datum, src, PROC_REF(delete_everything)) + . = ..() + +// Has a percent chance on spawn to set the specified variable on the specified type to the specified value. + +/obj/abstract/landmark/variable_setter + is_spawnable_type = FALSE + var/type_to_find + var/variable_to_set + var/value_to_set + var/probability = 100 + +/obj/abstract/landmark/variable_setter/Initialize() + . = ..() + if(!prob(probability)) + return // Do nothing. + var/turf/our_turf = get_turf(src) + if(ispath(type_to_find, /turf) && istype(our_turf, type_to_find) && try_set_variable(our_turf)) + return INITIALIZE_HINT_QDEL + for(var/atom/candidate_atom in get_turf(src)) + if(!istype(candidate_atom, type_to_find)) + continue + if(try_set_variable(candidate_atom)) + break + return INITIALIZE_HINT_QDEL + +/obj/abstract/landmark/variable_setter/proc/try_set_variable(atom/atom_to_modify) + // We don't have that variable! Give our own runtime to be more informative than the default one. + if(!(variable_to_set in atom_to_modify.vars)) + CRASH("Unable to find variable [variable_to_set] to modify on type [atom_to_modify.type].") + // Already modified, if we're stacked we shouldn't modify the same one twice. + if(atom_to_modify.vars[variable_to_set] == value_to_set) + return FALSE + atom_to_modify.vars[variable_to_set] = value_to_set + return TRUE + +/obj/abstract/landmark/variable_setter/closet_opener + type_to_find = /obj/structure/closet + variable_to_set = "opened" + value_to_set = TRUE + +// Has a percent chance on spawn to call the specified proc on the specified type with the specified arguments. +/obj/abstract/landmark/proc_caller + is_spawnable_type = FALSE + var/type_to_find + var/proc_to_call + var/arguments_to_pass + var/probability = 100 + +/obj/abstract/landmark/proc_caller/Initialize() + . = ..() + if(!prob(probability)) + return // Do nothing. + // turf is not in turf contents, oops + var/turf/our_turf = get_turf(src) + if(ispath(type_to_find, /turf) && istype(our_turf, type_to_find) && try_call_proc(our_turf)) + return INITIALIZE_HINT_QDEL + // we don't use locate in case try_call_proc returns false on our first attempt + for(var/atom/candidate_atom in get_turf(src)) + if(!istype(candidate_atom, type_to_find)) + continue + if(try_call_proc(candidate_atom)) + break + return INITIALIZE_HINT_QDEL + +/obj/abstract/landmark/proc_caller/proc/try_call_proc(atom/atom_to_modify) + // We don't have that proc! Give our own runtime to be more informative than the default one. + if(!hascall(atom_to_modify, proc_to_call)) + CRASH("Unable to find proc [proc_to_call] to call on type [atom_to_modify.type].") + if(length(arguments_to_pass)) + call(atom_to_modify, proc_to_call)(arglist(arguments_to_pass)) + else + call(atom_to_modify, proc_to_call)() + return TRUE + +/obj/abstract/landmark/proc_caller/floor_burner + type_to_find = /turf/floor + proc_to_call = TYPE_PROC_REF(/turf/floor, burn_tile) + arguments_to_pass = null + +/obj/abstract/landmark/proc_caller/floor_breaker + type_to_find = /turf/floor + proc_to_call = TYPE_PROC_REF(/turf/floor, break_tile) + arguments_to_pass = null + +/// Used to tell pipe leak unit tests that a leak is intentional. Placed over the pipe that leaks, not the tile missing a pipe. +/obj/abstract/landmark/allowed_leak +#ifndef UNIT_TEST + delete_me = TRUE +#endif + +/obj/abstract/landmark/organize + abstract_type = /obj/abstract/landmark/organize + var/list/sort_types = list(/obj/item) + +/obj/abstract/landmark/organize/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/abstract/landmark/organize/LateInitialize() + ..() + var/list/sorting_atoms = list() + for(var/atom/movable/AM in loc) + if(AM.simulated && !AM.anchored && is_type_in_list(AM, sort_types)) + sorting_atoms += AM + if(length(sorting_atoms)) + organize(shuffle(sorting_atoms)) + qdel(src) + +/obj/abstract/landmark/organize/proc/organize(list/organize) + return + +/obj/abstract/landmark/organize/horizontal/organize(list/organize) + var/offset = round(world.icon_size / length(organize)) + var/initial_x = -((offset * length(organize)) / 2) + var/sorted_atoms = 0 + for(var/atom/movable/AM as anything in organize) + AM.pixel_x = initial_x + (offset * sorted_atoms) + sorted_atoms++ + +/obj/abstract/landmark/organize/vertical/organize(list/organize) + var/offset = round(world.icon_size / length(organize)) + var/initial_y = -((offset * length(organize)) / 2) + var/sorted_atoms = 0 + for(var/atom/movable/AM as anything in organize) + AM.pixel_y = initial_y + (offset * sorted_atoms) + sorted_atoms++ diff --git a/code/modules/maps/map_template.dm b/code/modules/maps/map_template.dm deleted file mode 100644 index ebacf50445a4..000000000000 --- a/code/modules/maps/map_template.dm +++ /dev/null @@ -1,202 +0,0 @@ -/datum/map_template - var/name = "Default Template Name" - var/id = null // All maps that should be loadable during runtime needs an id - var/width = 0 - var/height = 0 - var/tallness = 0 - var/list/mappaths = null - var/loaded = 0 // Times loaded this round - var/list/shuttles_to_initialise = list() - var/list/subtemplates_to_spawn - var/base_turf_for_zs = null - var/accessibility_weight = 0 - var/template_flags = TEMPLATE_FLAG_ALLOW_DUPLICATES - -/datum/map_template/New(var/list/paths = null, var/rename = null) - if(paths && !islist(paths)) - crash_with("Non-list paths passed into map template constructor.") - if(paths) - mappaths = paths - if(mappaths) - preload_size(mappaths) - if(rename) - name = rename - if(!name && id) - name = id - -/datum/map_template/proc/preload_size() - var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF) - var/z_offset = 1 // needed to calculate z-bounds correctly - for (var/mappath in mappaths) - var/datum/map_load_metadata/M = maploader.load_map(file(mappath), 1, 1, z_offset, cropMap=FALSE, measureOnly=TRUE, no_changeturf=TRUE, clear_contents= template_flags & TEMPLATE_FLAG_CLEAR_CONTENTS) - if(M) - bounds = extend_bounds_if_needed(bounds, M.bounds) - z_offset++ - else - return FALSE - width = bounds[MAP_MAXX] - bounds[MAP_MINX] + 1 - height = bounds[MAP_MAXY] - bounds[MAP_MINX] + 1 - tallness = bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1 - return TRUE - -/datum/map_template/proc/init_atoms(var/list/atoms) - if (SSatoms.atom_init_stage == INITIALIZATION_INSSATOMS) - return // let proper initialisation handle it later - - var/list/turf/turfs = list() - var/list/obj/machinery/atmospherics/atmos_machines = list() - var/list/obj/machinery/machines = list() - var/list/obj/structure/cable/cables = list() - - for(var/atom/A in atoms) - if(istype(A, /turf)) - turfs += A - if(istype(A, /obj/structure/cable)) - cables += A - if(istype(A, /obj/machinery/atmospherics)) - atmos_machines += A - if(istype(A, /obj/machinery)) - machines += A - if(istype(A,/obj/effect/landmark/map_load_mark)) - LAZYADD(subtemplates_to_spawn, A) - - var/notsuspended - if(!SSmachines.suspended) - SSmachines.suspend() - notsuspended = TRUE - - SSatoms.InitializeAtoms() // The atoms should have been getting queued there. This flushes the queue. - - SSmachines.setup_powernets_for_cables(cables) - SSmachines.setup_atmos_machinery(atmos_machines) - if(notsuspended) - SSmachines.wake() - - for (var/i in machines) - var/obj/machinery/machine = i - machine.power_change() - - for (var/i in turfs) - var/turf/T = i - T.post_change() - if(template_flags & TEMPLATE_FLAG_NO_RUINS) - T.turf_flags |= TURF_FLAG_NORUINS - if(template_flags & TEMPLATE_FLAG_NO_RADS) - qdel(SSradiation.sources_assoc[i]) - if(istype(T,/turf/simulated)) - var/turf/simulated/sim = T - sim.update_air_properties() - -/datum/map_template/proc/pre_init_shuttles() - . = SSshuttle.block_queue - SSshuttle.block_queue = TRUE - -/datum/map_template/proc/init_shuttles(var/pre_init_state) - for (var/shuttle_type in shuttles_to_initialise) - LAZYADD(SSshuttle.shuttles_to_initialize, shuttle_type) // queue up for init. - SSshuttle.block_queue = pre_init_state - SSshuttle.clear_init_queue() // We will flush the queue unless there were other blockers, in which case they will do it. - -/datum/map_template/proc/load_new_z(no_changeturf = TRUE) - - var/x = round((world.maxx - width)/2) - var/y = round((world.maxy - height)/2) - var/initial_z = world.maxz + 1 - - if (x < 1) x = 1 - if (y < 1) y = 1 - - var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF) - var/list/atoms_to_initialise = list() - var/shuttle_state = pre_init_shuttles() - - var/initialized_areas_by_type = list() - for (var/mappath in mappaths) - var/datum/map_load_metadata/M = maploader.load_map(file(mappath), x, y, no_changeturf = no_changeturf, initialized_areas_by_type = initialized_areas_by_type) - if (M) - bounds = extend_bounds_if_needed(bounds, M.bounds) - atoms_to_initialise += M.atoms_to_initialise - else - return FALSE - - for (var/z_index = bounds[MAP_MINZ]; z_index <= bounds[MAP_MAXZ]; z_index++) - if (accessibility_weight) - GLOB.using_map.accessible_z_levels[num2text(z_index)] = accessibility_weight - if (base_turf_for_zs) - GLOB.using_map.base_turf_by_z[num2text(z_index)] = base_turf_for_zs - GLOB.using_map.player_levels |= z_index - - //initialize things that are normally initialized after map load - init_atoms(atoms_to_initialise) - init_shuttles(shuttle_state) - after_load(initial_z) - for(var/light_z = initial_z to world.maxz) - create_lighting_overlays_zlevel(light_z) - log_game("Z-level [name] loaded at [x],[y],[world.maxz]") - loaded++ - - return locate(world.maxx/2, world.maxy/2, world.maxz) - -/datum/map_template/proc/load(turf/T, centered=FALSE) - if(centered) - T = locate(T.x - round(width/2) , T.y - round(height/2) , T.z) - if(!T) - return - if(T.x+width > world.maxx) - return - if(T.y+height > world.maxy) - return - - var/list/atoms_to_initialise = list() - var/shuttle_state = pre_init_shuttles() - - var/initialized_areas_by_type = list() - for (var/mappath in mappaths) - var/datum/map_load_metadata/M = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, clear_contents=(template_flags & TEMPLATE_FLAG_CLEAR_CONTENTS), initialized_areas_by_type = initialized_areas_by_type) - if (M) - atoms_to_initialise += M.atoms_to_initialise - else - return FALSE - - //initialize things that are normally initialized after map load - init_atoms(atoms_to_initialise) - init_shuttles(shuttle_state) - after_load(T.z) - SSlighting.InitializeTurfs(atoms_to_initialise) // Hopefully no turfs get placed on new coords by SSatoms. - log_game("[name] loaded at at [T.x],[T.y],[T.z]") - loaded++ - - return TRUE - -/datum/map_template/proc/after_load(z) - for(var/obj/effect/landmark/map_load_mark/mark in subtemplates_to_spawn) - subtemplates_to_spawn -= mark - if(LAZYLEN(mark.templates)) - var/template = pick(mark.templates) - var/datum/map_template/M = new template() - M.load(get_turf(mark), TRUE) - qdel(mark) - LAZYCLEARLIST(subtemplates_to_spawn) - -/datum/map_template/proc/extend_bounds_if_needed(var/list/existing_bounds, var/list/new_bounds) - var/list/bounds_to_combine = existing_bounds.Copy() - for (var/min_bound in list(MAP_MINX, MAP_MINY, MAP_MINZ)) - bounds_to_combine[min_bound] = min(existing_bounds[min_bound], new_bounds[min_bound]) - for (var/max_bound in list(MAP_MAXX, MAP_MAXY, MAP_MAXZ)) - bounds_to_combine[max_bound] = max(existing_bounds[max_bound], new_bounds[max_bound]) - return bounds_to_combine - - -/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE) - var/turf/placement = T - if(centered) - var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z) - if(corner) - placement = corner - return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z)) - -//for your ever biggening badminnery kevinz000 -//? - Cyberboss -/proc/load_new_z_level(var/file, var/name) - var/datum/map_template/template = new(file, name) - template.load_new_z() diff --git a/code/modules/maps/map_template_unit_testing.dm b/code/modules/maps/map_template_unit_testing.dm deleted file mode 100644 index 732ce7fe9162..000000000000 --- a/code/modules/maps/map_template_unit_testing.dm +++ /dev/null @@ -1,18 +0,0 @@ -/datum/map_template - var/const/NO_APC = 1 - var/const/NO_VENT = 2 - var/const/NO_SCRUBBER = 4 - - var/list/area_usage_test_exempted_areas = list() - var/list/area_usage_test_exempted_root_areas = list() - var/list/apc_test_exempt_areas = list() - var/list/area_coherency_test_exempt_areas = list() - var/list/area_coherency_test_subarea_count = list() - -/datum/map_template/New(var/list/paths = null, var/rename = null) - ..() - GLOB.using_map.area_usage_test_exempted_areas |= area_usage_test_exempted_areas - GLOB.using_map.area_usage_test_exempted_root_areas |= area_usage_test_exempted_root_areas - GLOB.using_map.apc_test_exempt_areas |= apc_test_exempt_areas - GLOB.using_map.area_coherency_test_exempt_areas |= area_coherency_test_exempt_areas - GLOB.using_map.area_coherency_test_subarea_count |= area_coherency_test_subarea_count \ No newline at end of file diff --git a/code/modules/maps/reader.dm b/code/modules/maps/reader.dm index de89d3ad2003..9f7dff608187 100644 --- a/code/modules/maps/reader.dm +++ b/code/modules/maps/reader.dm @@ -3,26 +3,42 @@ ////////////////////////////////////////////////////////////// //global datum that will preload variables on atoms instanciation -GLOBAL_VAR_INIT(use_preloader, FALSE) -GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) +var/global/use_preloader = FALSE +var/global/dmm_suite/maploader = new +var/global/dmm_suite/preloader/_preloader = new /datum/map_load_metadata var/bounds var/list/atoms_to_initialise + var/list/turfs_to_mark_modified /dmm_suite - // /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g - var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g") + // /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"\n*([a-zA-Z\n]*)\n?"\}/g + var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"\n*(\[a-zA-Z\n]*)\n?"\\}"}, "g") // /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g") // /^[\s\n]+|[\s\n]+$/ var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g") var/static/list/modelCache = list() var/static/space_key + var/static/list/types_to_delete #ifdef TESTING var/static/turfsSkipped #endif +// Set up some basic cached vars, like types_to_delete, that have to check things like subtypes. +/dmm_suite/New() + if(!types_to_delete) + types_to_delete = typecacheof(list( + /mob/living, + /obj/effect, + /obj/item, + /obj/machinery, + /obj/structure, + /obj/abstract/landmark/exoplanet_spawn, + )) + ..() + /** * Construct the model map and control the loading process * @@ -33,7 +49,13 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) * 2) Read the map line by line, parsing the result (using parse_grid) * */ -/dmm_suite/load_map(var/dmm_file, var/x_offset, var/y_offset, var/z_offset, var/cropMap, var/measureOnly, var/no_changeturf, var/clear_contents, var/lower_crop_x, var/lower_crop_y, var/upper_crop_x, var/upper_crop_y, var/initialized_areas_by_type) + +// dmm_files: A list of .dmm files to load (Required). +// z_offset: A number representing the z-level on which to start loading the map (Optional). +// cropMap: When true, the map will be cropped to fit the existing world dimensions (Optional). +// measureOnly: When true, no changes will be made to the world (Optional). +// no_changeturf: When true, turf/AfterChange won't be called on loaded turfs +/dmm_suite/proc/load_map(var/dmm_file, var/x_offset, var/y_offset, var/z_offset, var/cropMap, var/measureOnly, var/no_changeturf, var/clear_contents, var/lower_crop_x, var/lower_crop_y, var/upper_crop_x, var/upper_crop_y, var/initialized_areas_by_type, var/level_data_type) //How I wish for RAII Master.StartLoadingMap() space_key = null @@ -43,17 +65,24 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) initialized_areas_by_type = initialized_areas_by_type || list() if(!(world.area in initialized_areas_by_type)) initialized_areas_by_type[world.area] = locate(world.area) - . = load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, lower_crop_x, upper_crop_x, lower_crop_y, upper_crop_y, initialized_areas_by_type) + + var/datum/map_load_metadata/M = load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, lower_crop_x, upper_crop_x, lower_crop_y, upper_crop_y, initialized_areas_by_type, level_data_type) + + if(length(M.turfs_to_mark_modified)) + for(var/turf/turf in M.turfs_to_mark_modified) + turf.state_was_modified() + #ifdef TESTING if(turfsSkipped) testing("Skipped loading [turfsSkipped] default turfs") #endif Master.StopLoadingMap() + return M -/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, initialized_areas_by_type) +/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, clear_contents, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, initialized_areas_by_type, level_data_type = /datum/level_data/space) var/tfile = dmm_file//the map file we're creating if(isfile(tfile)) - tfile = file2text(tfile) + tfile = safe_file2text(tfile, FALSE) if(!x_offset) x_offset = 1 @@ -70,6 +99,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) var/list/atoms_to_initialise = list() var/list/atoms_to_delete = list() + var/list/turfs_to_mark_modified = list() while(dmmRegex.Find(tfile, stored_index)) stored_index = dmmRegex.next @@ -103,47 +133,32 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) var/ycrd = text2num(dmmRegex.group[4]) + y_offset - 1 var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1 - var/is_connected_to_lower_levels = ARE_Z_CONNECTED(zcrd, z_offset) - var/is_on_an_existing_zlevel = zcrd <= world.maxz - - if (is_on_an_existing_zlevel && !is_connected_to_lower_levels) + var/zexpansion = zcrd > world.maxz + if(!zexpansion && !LEVELS_ARE_Z_CONNECTED(zcrd, z_offset)) continue - var/zexpansion = zcrd > world.maxz if(zexpansion && !measureOnly) // don't actually expand the world if we're only measuring bounds if(cropMap) continue - else - world.maxz = zcrd //create a new z_level if needed - if(!no_changeturf) - WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/post_change is called.") - - bounds[MAP_MINX] = min(bounds[MAP_MINX], Clamp(xcrdStart, x_lower, x_upper)) + while(world.maxz < zcrd) //create new z_levels if needed. + SSmapping.increment_world_z_size(level_data_type) + bounds[MAP_MINX] = min(bounds[MAP_MINX], clamp(xcrdStart, x_lower, x_upper)) bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd) bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd) var/list/gridLines = splittext(dmmRegex.group[6], "\n") - - var/leadingBlanks = 0 - while(leadingBlanks < gridLines.len && gridLines[++leadingBlanks] == "") - if(leadingBlanks > 1) - gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines. - - if(!gridLines.len) // Skip it if only blank lines exist. + if(!length(gridLines)) // Skip it if only blank lines exist. continue - if(gridLines.len && gridLines[gridLines.len] == "") - gridLines.Cut(gridLines.len) // Remove only one blank line at the end. - - bounds[MAP_MINY] = min(bounds[MAP_MINY], Clamp(ycrd, y_lower, y_upper)) - ycrd += gridLines.len - 1 // Start at the top and work down + bounds[MAP_MINY] = min(bounds[MAP_MINY], clamp(ycrd, y_lower, y_upper)) + ycrd += length(gridLines) - 1 // Start at the top and work down if(!cropMap && ycrd > world.maxy) if(!measureOnly) world.maxy = ycrd // Expand Y here. X is expanded in the loop below - bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(ycrd, y_lower, y_upper)) + bounds[MAP_MAXY] = max(bounds[MAP_MAXY], clamp(ycrd, y_lower, y_upper)) else - bounds[MAP_MAXY] = max(bounds[MAP_MAXY], Clamp(min(ycrd, world.maxy), y_lower, y_upper)) + bounds[MAP_MAXY] = max(bounds[MAP_MAXY], clamp(min(ycrd, world.maxy), y_lower, y_upper)) var/maxx = xcrdStart if(measureOnly) @@ -174,7 +189,11 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) throw EXCEPTION("Undefined model key in DMM.") var/datum/grid_load_metadata/M = parse_grid(grid_models[model_key], model_key, xcrd, ycrd, zcrd, no_changeturf || zexpansion, clear_contents, initialized_areas_by_type) if (M) - atoms_to_initialise += M.atoms_to_initialise + if(length(M.atoms_to_initialise)) + atoms_to_initialise += M.atoms_to_initialise + if(length(M.turfs_to_mark_modified)) + turfs_to_mark_modified += M.turfs_to_mark_modified + atoms_to_delete += M.atoms_to_delete #ifdef TESTING else @@ -184,24 +203,23 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) maxx = max(maxx, xcrd) ++xcrd --ycrd - if (zexpansion) - create_lighting_overlays_zlevel(zcrd) - bounds[MAP_MAXX] = Clamp(max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx), x_lower, x_upper) + bounds[MAP_MAXX] = clamp(max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx), x_lower, x_upper) CHECK_TICK if(bounds[1] == 1.#INF) // Shouldn't need to check every item return null - else - if(!measureOnly) - if(clear_contents) - for(var/atom/to_delete in atoms_to_delete) - qdel(to_delete) - var/datum/map_load_metadata/M = new - M.bounds = bounds - M.atoms_to_initialise = atoms_to_initialise - return M + + if(!measureOnly) + if(clear_contents) + for(var/atom/to_delete in atoms_to_delete) + qdel(to_delete) + var/datum/map_load_metadata/M = new + M.bounds = bounds + M.atoms_to_initialise = atoms_to_initialise + M.turfs_to_mark_modified = turfs_to_mark_modified + return M /** * Fill a given tile with its area/turf/objects/mobs @@ -224,15 +242,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) /datum/grid_load_metadata var/list/atoms_to_initialise var/list/atoms_to_delete - -/dmm_suite/proc/types_to_delete() - return list( - /mob/living, - /obj/effect, - /obj/item, - /obj/machinery, - /obj/structure, - ) + var/list/turfs_to_mark_modified /dmm_suite/proc/parse_grid(model as text, model_key as text, xcrd as num,ycrd as num,zcrd as num, no_changeturf as num, clear_contents as num, initialized_areas_by_type) /*Method parse_grid() @@ -286,8 +296,8 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) if(variables_start)//if there's any variable full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}' fields = readlist(full_def, ";") - if(fields.len) - if(!trim(fields[fields.len])) + if(length(fields)) + if(!trim(fields[length(fields)])) --fields.len for(var/I in fields) var/value = fields[I] @@ -310,7 +320,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) // 5. and the members are world.turf and world.area // Basically, if we find an entry like this: "XXX" = (/turf/default, /area/default) // We can skip calling this proc every time we see XXX - if(no_changeturf && !space_key && members.len == 2 && members_attributes.len == 2 && length(members_attributes[1]) == 0 && length(members_attributes[2]) == 0 && (world.area in members) && (world.turf in members)) + if(no_changeturf && !space_key && length(members) == 2 && length(members_attributes) == 2 && length(members_attributes[1]) == 0 && length(members_attributes[2]) == 0 && (world.area in members) && (world.turf in members)) space_key = model_key return @@ -327,22 +337,18 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) var/atoms_to_delete = list() //first instance the /area and remove it from the members list - index = members.len + index = length(members) if(members[index] != /area/template_noop) is_not_noop = TRUE var/list/attr = members_attributes[index] - if (LAZYLEN(attr)) - GLOB._preloader.setup(attr)//preloader for assigning set variables on atom creation var/atype = members[index] var/atom/instance = initialized_areas_by_type[atype] if(!instance) + global._preloader.setup(attr, atype) instance = new atype(null) initialized_areas_by_type[atype] = instance if(crds) - instance.contents.Add(crds) - - if(GLOB.use_preloader && instance) - GLOB._preloader.load(instance) + ChangeArea(crds, instance) //then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect @@ -354,39 +360,51 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) SSatoms.map_loader_begin() //since we've switched off autoinitialisation, record atoms to initialise later var/list/atoms_to_initialise = list() + var/list/turfs_to_mark_modified = list() //instanciate the first /turf var/turf/T if(members[first_turf_index] != /turf/template_noop) is_not_noop = TRUE - T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],crds,no_changeturf) + T = instance_atom(members[first_turf_index], members_attributes[first_turf_index], crds, no_changeturf) atoms_to_initialise += T + if(isturf(T)) + turfs_to_mark_modified += T if(T) //if others /turf are presents, simulates the underlays piling effect index = first_turf_index + 1 - while(index <= members.len - 1) // Last item is an /area + while(index < length(members)) // Last item is an /area var/underlay = T.appearance - T = instance_atom(members[index],members_attributes[index],crds,no_changeturf)//instance new turf + T = instance_atom(members[index], members_attributes[index], crds, no_changeturf)//instance new turf T.underlays += underlay index++ atoms_to_initialise += T + if(isturf(T)) + turfs_to_mark_modified += T - if (clear_contents && is_not_noop) - for (var/type_to_delete in types_to_delete()) - for (var/atom/pre_existing in crds) - if (istype(pre_existing, type_to_delete)) - atoms_to_delete |= pre_existing + if (clear_contents && is_not_noop && length(crds.contents)) + for (var/atom/movable/pre_existing as anything in crds) + if(!types_to_delete[pre_existing.type]) + continue + if(crds != pre_existing.loc) // avoid deleting multitile objects unnecessarily, only check their 'real' loc + continue + atoms_to_delete += pre_existing //finally instance all remainings objects/mobs for(index in 1 to first_turf_index-1) - atoms_to_initialise += instance_atom(members[index],members_attributes[index],crds,no_changeturf) + var/atom/thing = instance_atom(members[index], members_attributes[index], crds, no_changeturf) + atoms_to_initialise += thing + if(isturf(thing)) + turfs_to_mark_modified += thing + //Restore initialization to the previous valsue SSatoms.map_loader_stop() var/datum/grid_load_metadata/M = new M.atoms_to_initialise = atoms_to_initialise M.atoms_to_delete = atoms_to_delete + M.turfs_to_mark_modified = turfs_to_mark_modified return M //////////////// @@ -394,18 +412,17 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) //////////////// //Instance an atom at (x,y,z) and gives it the variables in attributes -/dmm_suite/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf) - if (LAZYLEN(attributes)) - GLOB._preloader.setup(attributes, path) +/dmm_suite/proc/instance_atom(path, list/attributes, turf/crds, no_changeturf) + global._preloader.setup(attributes, path) if(crds) - if(!no_changeturf && ispath(path, /turf)) - . = crds.ChangeTurf(path, FALSE, TRUE) + if(ispath(path, /turf)) + if(no_changeturf) + . = new path(crds) + else + . = crds.ChangeTurf(path, FALSE, TRUE) else - . = create_atom(path, crds)//first preloader pass - - if(GLOB.use_preloader && .)//second preloader pass, for those atoms that don't ..() in New() - GLOB._preloader.load(.) + . = new path(crds)// preloader called from atom/New //custom CHECK_TICK here because we don't want things created while we're sleeping to delay initialization. if(TICK_CHECK) @@ -413,10 +430,6 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) stoplag() SSatoms.map_loader_begin() -/dmm_suite/proc/create_atom(path, crds) - // Doing this async is impossible, as we must return the ref. - return new path (crds) - //text trimming (both directions) helper proc //optionally removes quotes before and after the text (for variable name) /dmm_suite/proc/trim_text(what as text,trim_quotes=0) @@ -499,7 +512,7 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) if(equal_position)//associative var, so do the association if(isnum(left)) - crash_with("Numerical key in associative list.") + PRINT_STACK_TRACE("Numerical key in associative list.") break // This is invalid; apparently dm will runtime in this situation. var/trim_right = trim_text(copytext(text,equal_position+1,position))//the content of the variable to_return[left] = readlistitem(trim_right) @@ -520,12 +533,12 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) parent_type = /datum var/list/attributes var/target_path + var/current_map_hash /dmm_suite/preloader/proc/setup(list/the_attributes, path) - if(LAZYLEN(the_attributes)) - GLOB.use_preloader = TRUE - attributes = the_attributes - target_path = path + global.use_preloader = TRUE + attributes = the_attributes + target_path = path /dmm_suite/preloader/proc/load(atom/what) for(var/attribute in attributes) @@ -544,7 +557,9 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) break if (!found) throw ex - GLOB.use_preloader = FALSE + if(current_map_hash) + what.modify_mapped_vars(current_map_hash) + global.use_preloader = FALSE /area/template_noop name = "Area Passthrough" diff --git a/code/modules/maps/ruins.dm b/code/modules/maps/ruins.dm deleted file mode 100644 index 07a4cc25f745..000000000000 --- a/code/modules/maps/ruins.dm +++ /dev/null @@ -1,85 +0,0 @@ -GLOBAL_LIST_EMPTY(banned_ruin_ids) - -/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = /area/space, list/potentialRuins, var/maxx = world.maxx, var/maxy = world.maxy) - if(!z_levels || !z_levels.len) - UNLINT(WARNING("No Z levels provided - Not generating ruins")) - return - - for(var/zl in z_levels) - var/turf/T = locate(1, 1, zl) - if(!T) - UNLINT(WARNING("Z level [zl] does not exist - Not generating ruins")) - return - - var/list/ruins = potentialRuins.Copy() - for(var/R in potentialRuins) - var/datum/map_template/ruin/ruin = R - if(ruin.id in GLOB.banned_ruin_ids) - ruins -= ruin //remove all prohibited ids from the candidate list; used to forbit global duplicates. - var/list/spawned_ruins = list() -//Each iteration needs to either place a ruin or strictly decrease either the budget or ruins.len (or break). - while(budget > 0) - // Pick a ruin - var/datum/map_template/ruin/ruin = null - if(ruins && ruins.len) - ruin = pick(ruins) - if(ruin.cost > budget) - ruins -= ruin - continue //Too expensive, get rid of it and try again - else - log_world("Ruin loader had no ruins to pick from with [budget] left to spend.") - break - // Try to place it - var/sanity = 20 - // And if we can't fit it anywhere, give up, try again - - while(sanity > 0) - sanity-- - - var/width_border = TRANSITIONEDGE + RUIN_MAP_EDGE_PAD + round(ruin.width / 2) - var/height_border = TRANSITIONEDGE + RUIN_MAP_EDGE_PAD + round(ruin.height / 2) - var/z_level = pick(z_levels) - if(width_border > maxx - width_border || height_border > maxx - height_border) // Too big and will never fit. - ruins -= ruin //So let's not even try anymore with this one. - break - - var/turf/T = locate(rand(width_border, maxx - width_border), rand(height_border, maxy - height_border), z_level) - var/valid = TRUE - - for(var/turf/check in ruin.get_affected_turfs(T,1)) - var/area/new_area = get_area(check) - if(!(istype(new_area, whitelist)) || check.turf_flags & TURF_FLAG_NORUINS) - if(sanity == 0) - ruins -= ruin //It didn't fit, and we are out of sanity. Let's make sure not to keep trying the same one. - valid = FALSE - break //Let's try again - - if(!valid) - continue - log_world("Ruin \"[ruin.name]\" placed at ([T.x], [T.y], [T.z])") - - load_ruin(T, ruin) - spawned_ruins += ruin - if(ruin.cost >= 0) - budget -= ruin.cost - if(!(ruin.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES)) - for(var/other_ruin_datum in ruins) - var/datum/map_template/ruin/other_ruin = other_ruin_datum - if(ruin.id == other_ruin.id) - ruins -= ruin //Remove all ruins with the same id if we don't allow duplicates - GLOB.banned_ruin_ids += ruin.id //and ban them globally too - break - return spawned_ruins - -/proc/load_ruin(turf/central_turf, datum/map_template/template) - if(!template) - return FALSE - for(var/i in template.get_affected_turfs(central_turf, 1)) - var/turf/T = i - for(var/mob/living/simple_animal/monster in T) - qdel(monster) - template.load(central_turf,centered = TRUE) - var/datum/map_template/ruin = template - if(istype(ruin)) - new /obj/effect/landmark/ruin(central_turf, ruin) - return TRUE diff --git a/code/modules/maps/template_types/antag_spawn.dm b/code/modules/maps/template_types/antag_spawn.dm new file mode 100644 index 000000000000..8b8b167bd0fd --- /dev/null +++ b/code/modules/maps/template_types/antag_spawn.dm @@ -0,0 +1,3 @@ +/datum/map_template/ruin/antag_spawn + prefix = "maps/antag_spawn/" + abstract_type = /datum/map_template/ruin/antag_spawn diff --git a/code/modules/maps/template_types/away_site.dm b/code/modules/maps/template_types/away_site.dm new file mode 100644 index 000000000000..81d77b0152ef --- /dev/null +++ b/code/modules/maps/template_types/away_site.dm @@ -0,0 +1,8 @@ +/datum/map_template/ruin/away_site + prefix = "maps/away/" + template_categories = list(MAP_TEMPLATE_CATEGORY_AWAYSITE) + abstract_type = /datum/map_template/ruin/away_site + var/spawn_weight = 1 + +/datum/map_template/ruin/away_site/get_spawn_weight() + return spawn_weight diff --git a/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm b/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm new file mode 100644 index 000000000000..4a7f663352e1 --- /dev/null +++ b/code/modules/maps/template_types/mapped_planet/mapped_planet_template.dm @@ -0,0 +1,48 @@ + +/** + * Base map template for planetoids, which need to instantiate a planetoid data object early during template spawn. + * Can be used to load a planetoid from a map file. + */ +/datum/map_template/planetoid + name = "planetoid" + abstract_type = /datum/map_template/planetoid + template_categories = list(MAP_TEMPLATE_CATEGORY_PLANET) + level_data_type = /datum/level_data/planetoid + modify_tag_vars = TRUE + + ///The type of planetoid data to instantiate for this planetoid. We'll use it as blueprint for the planet. + var/planetoid_data_type = /datum/planetoid_data + +/datum/map_template/planetoid/is_runtime_generated() + return FALSE //We're loaded from a map file + +///Returns a new instance of a datum used for containing runtime info on the planet generated by this template. +/datum/map_template/planetoid/proc/create_planetoid_instance() + var/datum/planetoid_data/PD = new planetoid_data_type + PD.setup_planetoid() //Run generation/setup + return PD + +/datum/map_template/planetoid/load(turf/T, centered = FALSE) + //Main reason for this is, map bounds are up to level_data. + // The /datum/level_data of a level needed to tell how to connect to adjacent levels, define level atmos and map generators. + // And we cannot combine level_data instances or slap the entire stack of z-levels onto a single level. + CRASH("Cannot load a planet template over an existing level") + +//The extra datum/planetoid_data/planet_data arg is only for admin spawming exoplanets, since some parameters are taken from the user +/datum/map_template/planetoid/load_new_z(no_changeturf = TRUE, centered = TRUE, var/datum/planetoid_data/planet_data) //centered == false should probably runtime, because it will never work properly + if(!planet_data) + planet_data = create_planetoid_instance() + + //Load levels from map files + . = ..(no_changeturf, centered) + + //Might as well force these to update if some were manually set + for(var/datum/exoplanet_theme/T in planet_data.themes) + T.after_map_generation(planet_data) + + //Create or update the overmap marker for the planet + setup_planet_overmap(planet_data) + +///Call after map is fully generated. Setup the overmap obj to match the planet we just generated. +/datum/map_template/planetoid/proc/setup_planet_overmap(var/datum/planetoid_data/planet_data) + planet_data.try_update_overmap_marker() diff --git a/code/modules/maps/template_types/random_exoplanet/fauna_generator.dm b/code/modules/maps/template_types/random_exoplanet/fauna_generator.dm new file mode 100644 index 000000000000..08cbad00e174 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/fauna_generator.dm @@ -0,0 +1,273 @@ +///An internal template to generate randomized planet fauna that's adapted to where it was generated to spawn on. +/datum/generated_fauna_template + var/list/min_gases + var/list/max_gases + var/body_temp_low = T0C + var/body_temp_high = T0C + 60 + var/body_temp_init = T0C + 30 + var/heat_damage_per_tick + ///The type of mob to spawn + var/spawn_type + +/datum/generated_fauna_template/New(var/fauna_type, var/atmos_temp, var/list/min_gas, var/list/max_gas) + var/min_body_temp = atmos_temp - 20 + var/max_body_temp = atmos_temp + 30 + var/initial_body_temp = (max_body_temp + min_body_temp)/2 + spawn_type = fauna_type + min_gases = min_gas?.Copy() + max_gases = max_gas?.Copy() + body_temp_low = min_body_temp + body_temp_high = max_body_temp + body_temp_init = initial_body_temp + +/datum/generated_fauna_template/proc/try_spawn(var/turf/T, var/datum/planetoid_data/P = null) + var/mob/living/simple_animal/A = new spawn_type(T) + A.minbodytemp = body_temp_low + A.maxbodytemp = body_temp_high + A.bodytemperature = body_temp_init + A.heat_damage_per_tick = heat_damage_per_tick + if(A.min_gas) + A.min_gas = min_gases?.Copy() + if(A.max_gas) + A.max_gas = max_gases?.Copy() + + //Need to always fetch the species name, since it can change at any time + var/overridden_name = LAZYACCESS(P?.fauna?.species_names, spawn_type) //#TODO: Really need some kind of centralized species repo + if(overridden_name) + A.fully_replace_character_name(overridden_name) + else + A.fully_replace_character_name("alien creature") + if(isanimal(A)) + A.verbs |= /mob/living/simple_animal/proc/name_species + + for(var/datum/exoplanet_theme/theme in P?.themes) + theme.adapt_animal(P, A) + return A + +//#TODO: Make some kind of stand-alone fauna manager instead? +/datum/fauna_generator + ///Weighted list of fauna that can possibly spawn. + var/list/fauna_types + ///Weighted list of megafauna that can possibly spawn. + var/list/megafauna_types + ///Spawn info cached for each fauna types. Basically a cached entry for each critter that tells us what to change on them after spawn. + var/list/fauna_templates + ///Spawn info cached for each megafauna types. Basically a cached entry for each critter that tells us what to change on them after spawn. + var/list/megafauna_templates + + ///List of fauna/megafauna types to respawn after they died. + var/tmp/list/respawn_queue + + ///List of fauna refs to those that are alive currently and tied to this generator. + var/list/live_fauna + ///List of megafauna refs to those that are alive currently and tied to this generator. + var/list/live_megafauna + + ///Maximum amount of live fauna at one time + var/max_fauna_alive = 10 + ///Maximum amount of mega fauna at one time + var/max_megafauna_alive = 1 + + ///Amount of animal alive below which we'll try to respawn animals. This value starts at max_alive, and goes down each times we empty the respawn queue by half + var/repopulate_fauna_threshold + ///Amount of live megafauna below which respawning will occur + var/repopulate_megafauna_threshold + + ///Realtime of day when we last repopulated + var/tmp/time_last_repop + ///Realtime interval between checks for repopulation + var/repopulation_interval = 5 MINUTES + ///List of named species for this planet. Handles custom species names that can be attributed to animal via xenobio stuff. + var/list/species_names //#TODO: move somewhere more sensible? This definitely should be in some repository of some kind, and not on each individual planets? + + ///Id of the level we operate on + var/level_data_id + +/datum/fauna_generator/New(var/level_id) + . = ..() + level_data_id = level_id + repopulate_fauna_threshold = max_fauna_alive + repopulate_megafauna_threshold = max_megafauna_alive + +/datum/fauna_generator/Destroy(force) + LAZYCLEARLIST(live_fauna) + . = ..() + +/datum/fauna_generator/proc/apply_theme(var/datum/exoplanet_theme/theme) + LAZYDISTINCTADD(fauna_types, theme.get_extra_fauna()) + LAZYDISTINCTADD(megafauna_types, theme.get_extra_megafauna()) + +/datum/fauna_generator/proc/register_fauna(var/mob/living/A) + if(A in live_fauna) + return + events_repository.register(/decl/observ/destroyed, A, src, TYPE_PROC_REF(/datum/fauna_generator, on_fauna_death)) + events_repository.register(/decl/observ/death, A, src, TYPE_PROC_REF(/datum/fauna_generator, on_fauna_death)) + LAZYADD(live_fauna, A) + +/datum/fauna_generator/proc/on_fauna_death(var/mob/living/A) + unregister_fauna(A) + LAZYADD(respawn_queue, A.type) + +/datum/fauna_generator/proc/unregister_fauna(var/mob/living/A) + if(!(A in live_fauna)) + return + events_repository.unregister(/decl/observ/destroyed, A, src, TYPE_PROC_REF(/datum/fauna_generator, on_fauna_death)) + events_repository.unregister(/decl/observ/death, A, src, TYPE_PROC_REF(/datum/fauna_generator, on_fauna_death)) + LAZYREMOVE(live_fauna, A) + +/datum/fauna_generator/proc/generate_fauna(var/datum/gas_mixture/atmosphere, var/list/breath_gases = list(), var/list/toxic_gases = list()) + var/list/generated_gases = generate_breathable_gases(atmosphere, breath_gases, toxic_gases) + + for(var/afauna in fauna_types | megafauna_types) + if(afauna in fauna_types) + LAZYSET(fauna_templates, afauna, generate_template(afauna, atmosphere.temperature, generated_gases[1], generated_gases[2])) + else + LAZYSET(megafauna_templates, afauna, generate_template(afauna, atmosphere.temperature, generated_gases[1], generated_gases[2])) + +/datum/fauna_generator/proc/generate_breathable_gases(var/datum/gas_mixture/atmosphere, var/list/breath_gases, var/list/toxic_gases) + //Set up gases for living things + var/list/all_gasses = get_filterable_material_types(as_list = TRUE) + if(!length(breath_gases)) + var/list/goodgases = all_gasses.Copy() + var/gasnum = min(rand(1,3), goodgases.len) + for(var/i = 1 to gasnum) + var/gas = pick(goodgases) + breath_gases[gas] = round(0.4*goodgases[gas], 0.1) + goodgases -= gas + + if(!length(toxic_gases)) + var/list/badgases = all_gasses.Copy() + badgases -= atmosphere.gas + toxic_gases = list(pick(badgases)) + for(var/agas in toxic_gases) + toxic_gases[agas] = 5 + + return list(breath_gases, toxic_gases) + +/datum/fauna_generator/proc/generate_template(var/spawn_type, var/atmos_temp, var/list/min_gas, var/list/max_gas) + return new /datum/generated_fauna_template(spawn_type, atmos_temp, min_gas, max_gas) + +/datum/fauna_generator/proc/try_respawn_from_queue() + . = LAZYACCESS(respawn_queue, 1) + if(.) + respawn_queue.Cut(1,2) //Clear first entry + +/datum/fauna_generator/proc/pick_fauna_to_respawn() + . = LAZYACCESS(respawn_queue & fauna_types, 1) + if(.) + respawn_queue.Cut(1,2) //Clear first entry + else + //Grab from our fauna list if we don't have anything set to respawn + . = pickweight(fauna_types) + +/datum/fauna_generator/proc/pick_megafauna_to_respawn() + . = LAZYACCESS(respawn_queue & megafauna_types, 1) + if(.) + respawn_queue.Cut(1,2) //Clear first entry + else + //Grab from our fauna list if we don't have anything set to respawn + . = pickweight(megafauna_types) + +/datum/fauna_generator/proc/try_spawn_fauna(var/turf/T, var/force = FALSE) + if(!LAZYLEN(fauna_types)) + log_warning("Tried spawning fauna at ([T.x], [T.y], [T.z]) but the fauna_types list is empty!") + return + if(!force && LAZYLEN(live_fauna) >= max_fauna_alive) + return + var/spawning = pick_fauna_to_respawn() + var/datum/generated_fauna_template/Tmpl = fauna_templates[spawning] + var/datum/planetoid_data/P = SSmapping.planetoid_data_by_z[T.z] + . = Tmpl.try_spawn(T, P) + + //Add to tracking + register_fauna(.) + +/datum/fauna_generator/proc/try_spawn_megafauna(var/turf/T, var/force = FALSE) + if(!LAZYLEN(megafauna_types)) + log_warning("Tried spawning megafauna at ([T.x], [T.y], [T.z]) but the megafauna_types list is empty!") + return + if(!force && LAZYLEN(live_megafauna) >= max_megafauna_alive) + return + var/spawning = pick_megafauna_to_respawn() + var/datum/generated_fauna_template/Tmpl = megafauna_templates[spawning] + var/datum/planetoid_data/P = SSmapping.planetoid_data_by_z[T.z] + . = Tmpl.try_spawn(T, P) + + //Add to tracking + register_fauna(.) + +//#TODO: move to subsystem/manager +/datum/fauna_generator/Process() + if(time_last_repop < (time_last_repop + repopulation_interval)) + return //Wait a bit before repopulating + if(LAZYLEN(respawn_queue) > 0) + handle_repopulation() + +/datum/fauna_generator/proc/handle_repopulation() + var/datum/level_data/LD = SSmapping.levels_by_id[level_data_id] + var/area/spawn_area = LD.get_base_area_instance() + + for(var/i = 1 to round(repopulate_megafauna_threshold - length(live_megafauna))) + if(prob(90)) + continue + var/turf/T = pick_area_turf(spawn_area, list(/proc/not_turf_contains_dense_objects, /proc/turf_is_simulated)) + try_spawn_megafauna(T) + + for(var/i = 1 to round(repopulate_fauna_threshold - length(live_fauna))) + if(prob(90)) + continue + var/turf/T = pick_area_turf(spawn_area, list(/proc/not_turf_contains_dense_objects, /proc/turf_is_simulated)) + try_spawn_fauna(T) + + time_last_repop = REALTIMEOFDAY + //Half the repop threshold each times we empty the respawn list + if(LAZYLEN(respawn_queue) <= 0) + repopulate_megafauna_threshold = round(repopulate_megafauna_threshold / 2) + repopulate_fauna_threshold = round(repopulate_fauna_threshold / 2) + +//#TOOD: Move this somewhere sensible. +/datum/fauna_generator/proc/rename_species(var/species_type, var/newname, var/force = FALSE) + if(LAZYACCESS(species_names, species_type) && !force) + return FALSE + LAZYSET(species_names, species_type, newname) + log_and_message_admins("renamed [species_type] to [newname]") + for(var/mob/living/simple_animal/A in live_fauna) + if(istype(A, species_type)) + A.fully_replace_character_name(newname) + A.verbs -= /mob/living/simple_animal/proc/name_species //#FIXME: This really should be handled by the animals themselves... + return TRUE + +//#TOOD: Move this somewhere sensible. +/datum/fauna_generator/proc/pick_species_name_prefix() + return pick( + "nol", + "shan", + "can", + "fel", + "xor", + ) + +//#TOOD: Move this somewhere sensible. +/datum/fauna_generator/proc/pick_species_name_middle() + return pick( + "a", + "e", + "o", + "t", + "ar", + ) + +//#TOOD: Move this somewhere sensible. +/datum/fauna_generator/proc/pick_species_name_suffix() + return pick( + "ian", + "oid", + "ac", + "ese", + "inian", + "rd", + ) + +//#TOOD: Move this somewhere sensible. +/datum/fauna_generator/proc/get_random_species_name() + return "[pick_species_name_prefix()][pick_species_name_middle()][pick_species_name_suffix()]" \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/flora_generator.dm b/code/modules/maps/template_types/random_exoplanet/flora_generator.dm new file mode 100644 index 000000000000..75c97b70ffc0 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/flora_generator.dm @@ -0,0 +1,167 @@ +//////////////////////////////////////////////////////////////////////// +// Pre-Defined Planet Flora +//////////////////////////////////////////////////////////////////////// + +///Contains data about the flora found on a planetoid, and facilities to pick and spawn them randomly. +/// This base type is meant to be used on its own only for fixed flora lists defined at compile time. +/datum/planet_flora + /// Seeds of 'small' flora at runtime. At definition is a list of /datum/seed types or plant names. + var/list/small_flora_types + /// Seeds of tree-tier flora at runtime. At definition is a list of /datum/seed types or plant names. + var/list/big_flora_types + /// Color used for grass floors. + var/grass_color + /// Colors allowed for generated flora. + var/list/plant_colors + ///Gases that plants should never produce during their lives. + var/list/exuded_gases_exclusions + +///Make sure our flora seed lists actually contains valid seeds! +/// Call this after creating the datum to ensure everything is ready! +/datum/planet_flora/proc/setup_flora(var/datum/gas_mixture/atmos) + if(length(small_flora_types)) + setup_flora_list(atmos, small_flora_types) + + if(length(big_flora_types)) + setup_flora_list(atmos, big_flora_types) + +///Go through a flora list and ensure any seed names and seed datum types are properly turned into a seed instance, and carry over any existing seed instances. +/datum/planet_flora/proc/setup_flora_list(var/datum/gas_mixture/atmos, var/list/flora_list) + var/list/old_flora = flora_list?.Copy() + if(flora_list) + flora_list.Cut() + else + flora_list = list() + + for(var/flora_type in old_flora) + if(istext(flora_type)) + ASSERT(SSplants?.initialized) + var/datum/seed/flora_existing_seed = SSplants.seeds[flora_type] + if(!flora_existing_seed) + CRASH("Trying to add non-existant seed named '[flora_type]' to planet flora!") + + var/datum/seed/seedcopy = flora_existing_seed.Clone() + adapt_seed(seedcopy, atmos) + //Make sure we got our plant color in the list + LAZYDISTINCTADD(plant_colors, seedcopy.get_trait(TRAIT_PLANT_COLOUR)) + flora_list += seedcopy + + else if(ispath(flora_type, /datum/seed)) + var/datum/seed/newseed = new flora_type + adapt_seed(newseed, atmos) + //Make sure we got our plant color in the list + LAZYDISTINCTADD(plant_colors, newseed.get_trait(TRAIT_PLANT_COLOUR)) + flora_list += newseed + + else if(istype(flora_type, /datum/seed)) + //We can just move actual datums over without any tampering + flora_list += flora_type + + return flora_list + +//Adapts seeds to this planet's atmopshere. Any special planet-speicific adaptations should go here too +/datum/planet_flora/proc/adapt_seed(var/datum/seed/S, var/datum/gas_mixture/atmos) + var/expected_pressure = atmos.return_pressure() + S.set_trait(TRAIT_IDEAL_HEAT, atmos.temperature + rand(-5,5),800,70) + S.set_trait(TRAIT_HEAT_TOLERANCE, S.get_trait(TRAIT_HEAT_TOLERANCE) + rand(-5,5),800,70) + S.set_trait(TRAIT_LOWKPA_TOLERANCE, expected_pressure + rand(-5,-50), 80, 0) + S.set_trait(TRAIT_HIGHKPA_TOLERANCE, expected_pressure + rand(5,50), 500, 110) + + if(S.exude_gasses) + S.exude_gasses -= exuded_gases_exclusions + if(length(atmos.gas)) + if(S.consume_gasses) + S.consume_gasses = list(pick(atmos.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it + for(var/g in atmos.gas) + var/decl/material/mat = GET_DECL(g) + if(mat.gas_flags & XGM_GAS_CONTAMINANT) + S.set_trait(TRAIT_TOXINS_TOLERANCE, rand(10,15)) + if(prob(50)) + var/chem_type = SSmaterials.get_random_chem(TRUE, atmos.temperature || T0C) + if(chem_type) + var/nutriment = S.get_chemical_amount(_chem = /decl/material/liquid/nutriment) + S.clear_chemical_composition() + S.set_chemical_amount(/decl/material/liquid/nutriment, nutriment) + S.set_chemical_amount(chem_type, list(rand(1,10),rand(10,20))) + + return S + +///Spawns a randomly chosen small flora from our small flora seed list. +/datum/planet_flora/proc/spawn_random_small_flora(var/turf/T) + if(LAZYLEN(small_flora_types)) + . = new /obj/structure/flora/plant(T, null, null, pick(small_flora_types)) + +///Spawns a randomly chosen big flora from our big flora seed list. +/datum/planet_flora/proc/spawn_random_big_flora(var/turf/T) + if(LAZYLEN(big_flora_types)) + . = new /obj/structure/flora/plant/large(T, null, null, pick(big_flora_types)) + + +//////////////////////////////////////////////////////////////////////// +// Randomly Generated Planet Flora +//////////////////////////////////////////////////////////////////////// + +///A randomly generating planet_flora data datum +/datum/planet_flora/random + plant_colors = list("RANDOM") + /// Max number of different seeds growing here + var/flora_diversity = 4 + /// If large flora should be generated + var/has_trees = TRUE + + +/datum/planet_flora/random/setup_flora(datum/gas_mixture/atmos) + generate_flora(atmos) + . = ..() + +///Generates a bunch of seeds adapted to the specified climate +/datum/planet_flora/random/proc/generate_flora(var/datum/gas_mixture/atmos) + if(atmos?.total_moles <= 0) + return + if(!grass_color && LAZYLEN(plant_colors)) + var/list/possible_grass = (plant_colors.Copy() - "RANDOM") + if(length(possible_grass)) + grass_color = pick(possible_grass) + + generate_small_flora(atmos) + if(has_trees) + generate_large_flora(atmos) + +/datum/planet_flora/random/proc/generate_small_flora(var/datum/gas_mixture/atmos) + for(var/i = 1 to flora_diversity) + var/datum/seed/S = new + var/planticon = "alien[rand(1,4)]" + var/color = pick(plant_colors) + var/carnivorous = prob(10)? 2 : (prob(20)? 1 : 0) + if(color == "RANDOM") + color = get_random_colour(0, 75, 190) + + S.randomize(atmos.temperature, atmos.return_pressure()) + S.set_trait(TRAIT_PRODUCT_ICON, planticon) + S.set_trait(TRAIT_PLANT_ICON, planticon) + S.set_trait(TRAIT_PLANT_COLOUR, color) + S.set_trait(TRAIT_CARNIVOROUS, carnivorous) + if(carnivorous == 2) + S.set_trait(TRAIT_SPREAD,1) + + adapt_seed(S, atmos) + LAZYADD(small_flora_types, S) + +/datum/planet_flora/random/proc/generate_large_flora(var/datum/gas_mixture/atmos) + var/tree_diversity = max(1, flora_diversity/2) + for(var/i = 1 to tree_diversity) + var/datum/seed/S = new + var/color = pick(plant_colors) + if(color == "RANDOM") + color = get_random_colour(0, 75, 190) + + S.randomize(atmos.temperature, atmos.return_pressure()) + S.set_trait(TRAIT_PRODUCT_ICON, "alien[rand(1,5)]") + S.set_trait(TRAIT_PLANT_ICON, "tree") + S.set_trait(TRAIT_SPREAD, 0) + S.set_trait(TRAIT_HARVEST_REPEAT, 1) + S.set_trait(TRAIT_LARGE, 1) + S.set_trait(TRAIT_LEAVES_COLOUR, color) + S.set_chemical_amount(/decl/material/solid/organic/wood, list(1,0)) //#TODO: Maybe look at Why the seed creates injectable wood? + adapt_seed(S, atmos) + LAZYADD(big_flora_types, S) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_themes/_planet_theme.dm b/code/modules/maps/template_types/random_exoplanet/planet_themes/_planet_theme.dm new file mode 100644 index 000000000000..a15b1f470889 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_themes/_planet_theme.dm @@ -0,0 +1,26 @@ +/datum/exoplanet_theme + var/name = "Nothing Special" + +/datum/exoplanet_theme/proc/get_map_generators(var/datum/planetoid_data/E) + +// Called by exoplanet datum before applying its map generators +/datum/exoplanet_theme/proc/before_map_generation(var/datum/planetoid_data/E) + +// Called by exoplanet datum after applying its map generators and spawning ruins +/datum/exoplanet_theme/proc/after_map_generation(var/datum/planetoid_data/E) + +/datum/exoplanet_theme/proc/adjust_atmosphere(var/datum/planetoid_data/E) + +/datum/exoplanet_theme/proc/get_planet_image_extra(var/datum/planetoid_data/E) + +/datum/exoplanet_theme/proc/get_sensor_data() + +/datum/exoplanet_theme/proc/adapt_animal(var/datum/planetoid_data/E, var/mob/A) + +/datum/exoplanet_theme/proc/modify_template_whitelist(var/whitelist_flags) + +/datum/exoplanet_theme/proc/modify_template_blacklist(var/blacklist_flags) + +/datum/exoplanet_theme/proc/get_extra_fauna() + +/datum/exoplanet_theme/proc/get_extra_megafauna() \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/planet_themes/mountains.dm b/code/modules/maps/template_types/random_exoplanet/planet_themes/mountains.dm new file mode 100644 index 000000000000..b4d70dcabdb6 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_themes/mountains.dm @@ -0,0 +1,32 @@ +/datum/exoplanet_theme/mountains + name = "Mountains" + +/datum/exoplanet_theme/mountains/get_map_generators(datum/planetoid_data/E) + return list(/datum/random_map/automata/cave_system/mountains) + +/datum/exoplanet_theme/mountains/get_planet_image_extra(datum/planetoid_data/E) + var/image/res = image('icons/skybox/planet.dmi', "mountains") + res.color = E.get_rock_color() + return res + +/datum/random_map/automata/cave_system/mountains + iterations = 2 + descriptor = "space mountains" + wall_type = /turf/wall/natural + cell_threshold = 6 + target_turf_type = null + floor_type = null + change_area = TRUE + +/datum/random_map/automata/cave_system/mountains/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) + var/datum/level_data/LD = SSmapping.levels_by_z[tz] + if(target_turf_type == null) + target_turf_type = SSmapping.base_turf_by_z[tz] || LD.base_turf || world.turf + if(floor_type == null) + floor_type = SSmapping.base_turf_by_z[tz] || LD.base_turf || world.turf + ..() + +/datum/random_map/automata/cave_system/mountains/get_additional_spawns(value, turf/T) + if(istype(T, /turf/wall/natural) && use_area) + var/turf/wall/natural/N = T + N.floor_type = use_area.base_turf diff --git a/code/modules/maps/template_types/random_exoplanet/planet_themes/radiation_bombing.dm b/code/modules/maps/template_types/random_exoplanet/planet_themes/radiation_bombing.dm new file mode 100644 index 000000000000..3eb3b9626931 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_themes/radiation_bombing.dm @@ -0,0 +1,40 @@ +/datum/exoplanet_theme/radiation_bombing + name = "Radiation Bombardment" + +/datum/exoplanet_theme/radiation_bombing/adjust_atmosphere(datum/planetoid_data/E) + var/add_temp = rand(20, 100) + if(E.atmosphere) + E.atmosphere.temperature += add_temp + E.atmosphere.update_values() + +/datum/exoplanet_theme/radiation_bombing/get_sensor_data() + return "Hotspots of radiation detected." + +/datum/exoplanet_theme/radiation_bombing/after_map_generation(datum/planetoid_data/E) + var/datum/level_data/LD = SSmapping.levels_by_id[E.surface_level_id] + var/radiation_power = rand(10, 37.5) + var/num_craters = round(min(0.5, rand()) * 0.02 * LD.level_inner_width * LD.level_inner_height) + + //Grab all turfs that are within the level's borders + var/list/available_turfs = block(LD.level_inner_min_x, LD.level_inner_min_y, LD.level_z, LD.level_inner_max_x, LD.level_inner_max_y, LD.level_z) + var/list/picked_turfs = list() + + //Manually filter out turfs + for(var/turf/T in available_turfs) + if(!turf_contains_dense_objects(T) && (T.loc == E.surface_area)) + picked_turfs += T + + for(var/i = 1 to num_craters) + var/turf/crater_center = pick_n_take(picked_turfs) + if(!crater_center) // ran out of space somehow + return + new/obj/structure/rubble/war(crater_center) + var/datum/radiation_source/source = new(crater_center, radiation_power, FALSE) + source.range = 4 + SSradiation.add_source(source) + crater_center.set_light(2, 0.4, PIPE_COLOR_GREEN) + for(var/turf/floor/crater in circlerangeturfs(crater_center, 3)) + if(prob(10)) + new/obj/item/remains/xeno/charred(crater) + crater.handle_melting() + crater.update_icon() diff --git a/code/modules/maps/template_types/random_exoplanet/planet_themes/robotic_guardians.dm b/code/modules/maps/template_types/random_exoplanet/planet_themes/robotic_guardians.dm new file mode 100644 index 000000000000..d9d6608eac8a --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_themes/robotic_guardians.dm @@ -0,0 +1,27 @@ +/datum/exoplanet_theme/robotic_guardians + name = "Robotic Guardians" + var/list/guardian_types = list( + /mob/living/simple_animal/hostile/hivebot, + /mob/living/simple_animal/hostile/hivebot/ranged, + /mob/living/simple_animal/hostile/viscerator/hive + ) + var/list/mega_guardian_types = list( + /mob/living/simple_animal/hostile/hivebot/mega + ) + +/datum/exoplanet_theme/robotic_guardians/modify_template_whitelist(whitelist_flags) + return whitelist_flags | TEMPLATE_TAG_ALIEN + +/datum/exoplanet_theme/robotic_guardians/get_extra_fauna() + return guardian_types + +/datum/exoplanet_theme/robotic_guardians/get_extra_megafauna() + return mega_guardian_types + +/datum/exoplanet_theme/robotic_guardians/adapt_animal(datum/planetoid_data/E, mob/A) + // Stopping robots from fighting each other + if(is_type_in_list(A, guardian_types | mega_guardian_types)) + A.faction = "Ancient Guardian" + +/datum/exoplanet_theme/robotic_guardians/get_sensor_data() + return "Movement without corresponding lifesigns detected on the surface." diff --git a/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm b/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm new file mode 100644 index 000000000000..ab81f74de2a0 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_themes/ruined_city.dm @@ -0,0 +1,226 @@ + +#define FLOOR_VALUE 0 +#define WALL_VALUE 1 +#define DOOR_VALUE 3 +#define ROAD_VALUE 10 +#define ARTIFACT_VALUE 11 + +#define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) + +/datum/exoplanet_theme/ruined_city + name = "Ruined City" + var/spooky_ambience = list( + 'sound/ambience/ominous1.ogg', + 'sound/ambience/ominous2.ogg', + 'sound/ambience/ominous3.ogg' + ) + +/datum/exoplanet_theme/ruined_city/modify_template_whitelist(whitelist_flags) + return whitelist_flags | TEMPLATE_TAG_ALIEN + +/datum/exoplanet_theme/ruined_city/get_map_generators(/datum/planetoid_data/E) + return list(/datum/random_map/city) + +/datum/exoplanet_theme/ruined_city/after_map_generation(datum/planetoid_data/E) + var/datum/level_data/LD = SSmapping.levels_by_id[E.surface_level_id] + var/area/A = LD.get_base_area_instance() + if(istype(A, world.area)) + PRINT_STACK_TRACE("Got '[world.area]' area as area for the surface level '[LD]' of planetoid '[E]'.") //Don't modify the ambience of the space area. + LAZYDISTINCTADD(A.ambience, spooky_ambience) + +/datum/exoplanet_theme/ruined_city/get_sensor_data() + return "Extensive artificial structures detected on the surface." + +/datum/exoplanet_theme/ruined_city/get_planet_image_extra(datum/planetoid_data/E) + return image('icons/skybox/planet.dmi', "ruins") + +// Generates a grid of roads with buildings between them +/datum/random_map/city + descriptor = "ruined city" + initial_wall_cell = 0 + initial_cell_char = -1 + var/max_building_size = 11 //Size of buildings in tiles. Must be odd number for building generation to work properly. + var/buildings_number = 4 //Buildings per block + var/list/blocks_x = list(2) //coordinates for start of blocs + var/list/blocks_y = list(2) + var/list/building_types = list( + /datum/random_map/maze/concrete = 90, + /datum/random_map/maze/lab + ) + var/list/building_maps + +/datum/random_map/city/generate_map() + var/block_size = buildings_number * max_building_size + 2 + var/num_blocks_x = round(limit_x/block_size) + var/num_blocks_y = round(limit_y/block_size) + + //Get blocks borders coordinates + for(var/i = 1 to num_blocks_x) + blocks_x += blocks_x[i] + block_size + 1 + for(var/i = 1 to num_blocks_y) + blocks_y += blocks_x[i] + block_size + 1 + blocks_x += limit_x - 1 + blocks_y += limit_y - 1 + + //Draw roads + for(var/x in blocks_x) + if(x > limit_x) + continue + for(var/y = 1 to limit_y) + if(x > 1) + map[TRANSLATE_COORD(x-1,y)] = ROAD_VALUE + map[TRANSLATE_COORD(x,y)] = ROAD_VALUE + if(x < limit_x) + map[TRANSLATE_COORD(x+1,y)] = ROAD_VALUE + + for(var/y in blocks_y) + if(y > limit_y) + continue + for(var/x = 1 to limit_x) + if(y > 1) + map[TRANSLATE_COORD(x,y-1)] = ROAD_VALUE + map[TRANSLATE_COORD(x,y)] = ROAD_VALUE + if(y < limit_y) + map[TRANSLATE_COORD(x,y+1)] = ROAD_VALUE + + //Place buildings + for(var/i = 1 to blocks_x.len - 1) + for(var/j = 1 to blocks_y.len - 1) + for(var/k = 0 to buildings_number - 1) + for(var/l = 0 to buildings_number - 1) + var/building_x = blocks_x[i] + 1 + max_building_size * k + var/building_y = blocks_y[j] + 1 + max_building_size * l + var/building_size_x = pick(7,9,9,11,11,11) + var/building_size_y = pick(7,9,9,11,11,11) + if(building_x + building_size_x >= limit_x) + continue + if(building_y + building_size_y >= limit_y) + continue + var/building_type = pickweight(building_types) + var/datum/random_map/building = new building_type(origin_x + building_x, origin_y + building_y, origin_z, building_size_x, building_size_y, TRUE, TRUE, use_area) + LAZYADD(building_maps, building) // They're applied later to let buildings handle their own shit + return 1 + +/datum/random_map/city/get_appropriate_path(var/value) + if(value == ROAD_VALUE && prob(99)) + return /turf/floor/concrete/reinforced/road + +/datum/random_map/city/get_additional_spawns(var/value, var/turf/floor/T) + if(istype(T, /turf/floor/concrete/reinforced/road)) + if(prob(1)) + new/obj/structure/rubble/house(T) + if(prob(5)) + T.set_floor_broken(TRUE) + +/datum/random_map/city/apply_to_map() + ..() + for(var/datum/random_map/building in building_maps) + building.apply_to_map() + +// Buildings +/turf/wall/concrete + icon_state = "stone" + floor_type = null + material = /decl/material/solid/stone/concrete + +/turf/wall/concrete/reinforced + reinf_material = /decl/material/solid/metal/steel + +//Generic ruin +/datum/random_map/maze/concrete + wall_type = /turf/wall/concrete + floor_type = /turf/floor/concrete/reinforced + preserve_map = 0 + +/datum/random_map/maze/concrete/get_appropriate_path(var/value) + if(value == WALL_VALUE) + if(prob(80)) + return /turf/wall/concrete + else + return /turf/floor/concrete/reinforced/damaged + return ..() + +/datum/random_map/maze/concrete/get_additional_spawns(var/value, var/turf/floor/T) + if(!istype(T)) + return + if(prob(10)) + new/obj/item/remains/xeno/charred(T) + if((T.is_floor_broken() && prob(80)) || prob(10)) + new/obj/structure/rubble/house(T) + if(prob(1)) + new/obj/abstract/landmark/exoplanet_spawn/animal(T) + +//Artifact containment lab +/turf/wall/containment + paint_color = COLOR_GRAY20 + floor_type = /turf/floor/fixed/alium/airless + +/turf/wall/containment/Initialize(var/ml) + . = ..(ml, /decl/material/solid/stone/concrete, /decl/material/solid/metal/aliumium) + +/datum/random_map/maze/lab + wall_type = /turf/wall/containment + floor_type = /turf/floor/fixed/alium/airless + preserve_map = 0 + var/artifacts_to_spawn = 1 + +/datum/random_map/maze/lab/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) + if(prob(10)) + artifacts_to_spawn = rand(2,3) + ..() + +/datum/random_map/maze/lab/generate_map() + ..() + for(var/x in 1 to limit_x - 1) + for(var/y in 1 to limit_y - 1) + var/value = map[TRANSLATE_COORD(x,y)] + if(value != FLOOR_VALUE) + continue + var/list/neighbors = list() + for(var/offset in list(list(0,1), list(0,-1), list(1,0), list(-1,0))) + var/tmp_cell = TRANSLATE_COORD(x + offset[1], y+offset[2]) + var/char = LAZYACCESS(map, tmp_cell) + if(char == FLOOR_VALUE || char == DOOR_VALUE) + neighbors.Add(tmp_cell) + if(length(neighbors) > 1) + continue + + map[neighbors[1]] = DOOR_VALUE + if(artifacts_to_spawn) + map[TRANSLATE_COORD(x,y)] = ARTIFACT_VALUE + artifacts_to_spawn-- + var/entrance_x = pick(rand(2,limit_x-1), 1, limit_x) + var/entrance_y = pick(1, limit_y) + if(entrance_x == 1 || entrance_x == limit_x) + entrance_y = rand(2,limit_y-1) + map[TRANSLATE_COORD(entrance_x,entrance_y)] = DOOR_VALUE + +/datum/random_map/maze/lab/get_appropriate_path(var/value) + if(value == ARTIFACT_VALUE) + return floor_type + if(value == DOOR_VALUE) + return floor_type + . = ..() + +/datum/random_map/maze/lab/get_additional_spawns(var/value, var/turf/floor/T) + if(!istype(T)) + return + + if(value == DOOR_VALUE) + new /obj/machinery/door/airlock/alien(T) + return + + if(value == ARTIFACT_VALUE) + var/datum/artifact_find/A = new() + new A.artifact_find_type(T) + qdel(A) + return + + if(value == FLOOR_VALUE) + if(prob(20)) + new/obj/structure/rubble/lab(T) + if(prob(20)) + new/obj/item/remains/xeno/charred(T) + + +#undef TRANSLATE_COORD \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm new file mode 100644 index 000000000000..6de9ef4a6001 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/barren.dm @@ -0,0 +1,122 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/barren + name = "barren exoplanet" + desc = "A planet that couldn't hold its atmosphere from either low gravity, or the lack of a strong magnetosphere, or even from intense solar winds." + color = "#6c6c6c" + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/barren + base_area = /area/exoplanet/barren + base_turf = /turf/floor/barren + exterior_atmosphere = null //Generate me + exterior_atmos_temp = null //Generate me + level_generators = list( + /datum/random_map/noise/exoplanet/barren, + /datum/random_map/noise/ore/rich, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/barren + has_trees = FALSE +/datum/planet_flora/random/barren/New() + . = ..() + if(prob(10)) + flora_diversity = 1 + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +//#FIXME: Barren is kind of a wide encompassing planet type. There's a lot of extremes to take into accounts for a single type... + +/datum/planetoid_data/random/barren + habitability_class = null + flora = /datum/planet_flora/random/barren + atmosphere_gen_pressure_min = 0.01 ATM + atmosphere_gen_pressure_max = 0.05 ATM + atmosphere_gen_temperature_min = -240 CELSIUS //-240c is about the surface temp of pluto for ref + atmosphere_gen_temperature_max = 450 CELSIUS //450c is the temperature at the surface of mercury for ref + initial_weather_state = null // No weather. + surface_color = "#807d7a" + water_color = null + possible_rock_colors = list( + COLOR_BEIGE, + COLOR_GRAY80, + COLOR_BROWN + ) + +/datum/planetoid_data/random/barren/generate_habitability() + //Barren worlds should definitely not be habitable by definition + if(isnull(habitability_class)) + if(prob(30)) + . = HABITABILITY_BAD + else + . = HABITABILITY_DEAD + else + . = habitability_class + set_habitability(.) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +///Template for spawning a randomly generated barren exoplanet. +/datum/map_template/planetoid/random/exoplanet/barren + name = "barren exoplanet" + planetoid_data_type = /datum/planetoid_data/random/barren + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/barren + template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_WATER + subtemplate_budget = 6 + level_data_type = /datum/level_data/planetoid/exoplanet/barren + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/barren, //surface level + /datum/level_data/planetoid/exoplanet/underground //bottom level + ) + template_categories = list( + MAP_TEMPLATE_CATEGORY_EXOPLANET + ) + possible_themes = list( + /datum/exoplanet_theme/mountains + ) + +/datum/map_template/planetoid/random/exoplanet/barren/get_spawn_weight() + return 50 + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +///Generator for fauna and flora spawners for the surface of the barren exoplanet +/datum/random_map/noise/exoplanet/barren + descriptor = "barren exoplanet" + land_type = /turf/floor/barren + flora_prob = 0.1 + large_flora_prob = 0 + fauna_prob = 0 + smoothing_iterations = 4 + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/barren + name = "\improper Planetary surface" + base_turf = /turf/floor/barren + is_outside = OUTSIDE_YES + ambience = list( + 'sound/effects/wind/wind_2_1.ogg', + 'sound/effects/wind/wind_2_2.ogg', + 'sound/effects/wind/wind_3_1.ogg', + 'sound/effects/wind/wind_4_1.ogg', + 'sound/effects/wind/wind_4_2.ogg', + 'sound/effects/wind/wind_5_1.ogg' + ) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm new file mode 100644 index 000000000000..9ec7a8823884 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/chlorine.dm @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/chlorine + name = "chlorine exoplanet" + desc = "An exoplanet with a chlorine based ecosystem. Large quantities of liquid chlorine are present." + color = "#c9df9f" + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/chlorine/get_atmosphere_color() + return "#e5f2bd" + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/chlorine + base_area = /area/exoplanet/chlorine + base_turf = /turf/floor/chlorine_sand + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/chlorine, + /datum/random_map/noise/ore/poor, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/chlorine + has_trees = FALSE + flora_diversity = 5 + plant_colors = list( + "#eba487", + "#ceeb87", + "#eb879c", + "#ebd687", + "#f6d6c9", + "#f2b3e0" + ) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/chlorine + fauna_types = list( + /mob/living/simple_animal/thinbug, + /mob/living/simple_animal/hostile/beast/samak/alt, + /mob/living/simple_animal/yithian, + /mob/living/simple_animal/tindalos, + /mob/living/simple_animal/hostile/jelly, + ) + megafauna_types = list( + /mob/living/simple_animal/hostile/jelly/mega, + ) + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// +/datum/planetoid_data/random/chlorine + habitability_class = null + forced_atmosphere_gen_gases = list(/decl/material/gas/chlorine = MOLES_O2STANDARD) + atmosphere_gen_pressure_min = 0.01 ATM + atmosphere_gen_pressure_max = 0.05 ATM + atmosphere_gen_temperature_min = T0C + atmosphere_gen_temperature_max = T100C + surface_light_gen_level_min = 0.65 + surface_light_gen_level_max = 0.85 + flora = /datum/planet_flora/random/chlorine + fauna = /datum/fauna_generator/chlorine + surface_color = "#a3b879" + water_color = COLOR_BOTTLE_GREEN + possible_rock_colors = list( + COLOR_GRAY80, + COLOR_PALE_GREEN_GRAY, + COLOR_PALE_BTL_GREEN + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/random/exoplanet/chlorine + name = "chlorine exoplanet" + planetoid_data_type = /datum/planetoid_data/random/chlorine + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/chlorine + template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_WATER + level_data_type = /datum/level_data/planetoid/exoplanet/chlorine + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/chlorine, + /datum/level_data/planetoid/exoplanet/underground + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +/datum/random_map/noise/exoplanet/chlorine + descriptor = "chlorine exoplanet" + land_type = /turf/floor/chlorine_sand + water_type = /turf/floor/chlorine_sand/marsh + water_level_min = 2 + water_level_max = 3 + fauna_prob = 2 + flora_prob = 5 + large_flora_prob = 0 + smoothing_iterations = 3 + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/chlorine + ambience = list( + 'sound/effects/wind/desert0.ogg', + 'sound/effects/wind/desert1.ogg', + 'sound/effects/wind/desert2.ogg', + 'sound/effects/wind/desert3.ogg', + 'sound/effects/wind/desert4.ogg', + 'sound/effects/wind/desert5.ogg' + ) + base_turf = /turf/floor/chlorine_sand \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm new file mode 100644 index 000000000000..098a604152cb --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/desert.dm @@ -0,0 +1,140 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/desert + name = "desert exoplanet" + desc = "An arid exoplanet with sparse biological resources but rich mineral deposits underground." + color = "#a08444" + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/desert + base_turf = /turf/floor/rock/sand + base_area = /area/exoplanet/desert + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/desert, + /datum/random_map/noise/ore/rich, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/desert + has_trees = FALSE + flora_diversity = 4 + plant_colors = list( + "#efdd6f", + "#7b4a12", + "#e49135", + "#ba6222", + "#5c755e", + "#701732" + ) + +/datum/planet_flora/random/desert/adapt_seed(var/datum/seed/S) + ..() + if(prob(90)) + S.set_trait(TRAIT_REQUIRES_WATER,0) + else + S.set_trait(TRAIT_REQUIRES_WATER,1) + S.set_trait(TRAIT_WATER_CONSUMPTION,1) + if(prob(75)) + S.set_trait(TRAIT_STINGS,1) + if(prob(75)) + S.set_trait(TRAIT_CARNIVOROUS,2) + S.set_trait(TRAIT_SPREAD,0) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/desert + fauna_types = list( + /mob/living/simple_animal/thinbug, + /mob/living/simple_animal/tindalos, + /mob/living/simple_animal/hostile/slug, + /mob/living/simple_animal/hostile/antlion, + ) + megafauna_types = list( + /mob/living/simple_animal/hostile/antlion/mega, + ) + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/random/desert + habitability_class = null //Generate randomly + atmosphere_gen_temperature_min = 40 CELSIUS + atmosphere_gen_temperature_max = 120 CELSIUS + initial_weather_state = null // No weather. + surface_light_gen_level_min = 0.5 + surface_light_gen_level_max = 0.95 + flora = /datum/planet_flora/random/desert + fauna = /datum/fauna_generator/desert + surface_color = "#d6cca4" + water_color = null + possible_rock_colors = list( + COLOR_BEIGE, + COLOR_PALE_YELLOW, + COLOR_GRAY80, + COLOR_BROWN + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/random/exoplanet/desert + name = "desert exoplanet" + planetoid_data_type = /datum/planetoid_data/random/desert + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/desert + level_data_type = /datum/level_data/planetoid/exoplanet/desert + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/desert, + /datum/level_data/planetoid/exoplanet/underground + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +/datum/random_map/noise/exoplanet/desert + descriptor = "desert exoplanet" + land_type = /turf/floor/rock/sand + flora_prob = 5 + grass_prob = 2 + large_flora_prob = 0 + smoothing_iterations = 4 + +/datum/random_map/noise/exoplanet/desert/get_additional_spawns(var/value, var/turf/T) + ..() + var/v = noise2value(value) + if(v > 6 && prob(10)) + new/obj/effect/quicksand(T) + +/datum/random_map/noise/exoplanet/desert/get_appropriate_path(var/value) + . = ..() + if(noise2value(value) > 6) + return /turf/floor/dry + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/desert + ambience = list( + 'sound/effects/wind/desert0.ogg', + 'sound/effects/wind/desert1.ogg', + 'sound/effects/wind/desert2.ogg', + 'sound/effects/wind/desert3.ogg', + 'sound/effects/wind/desert4.ogg', + 'sound/effects/wind/desert5.ogg' + ) + base_turf = /turf/floor/rock/sand diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm new file mode 100644 index 000000000000..d6ecd767659b --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/grass.dm @@ -0,0 +1,183 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +///Overmap marker for the grass exoplanet +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/grass + name = "lush exoplanet" + desc = "Planet with abundant flora and fauna." + color = "#407c40" + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/grass/get_surface_color() + var/datum/planetoid_data/E = SSmapping.planetoid_data_by_id[planetoid_id] + return E?.get_grass_color() + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +///Surface of a grass exoplanet +/datum/level_data/planetoid/exoplanet/grass + base_area = /area/exoplanet/grass + base_turf = /turf/floor/grass/wild + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/grass + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +///Flora data for a grass exoplanet +/datum/planet_flora/random/grass + flora_diversity = 6 + plant_colors = list( + "#215a00", + "#195a47", + "#5a7467", + "#9eab88", + "#6e7248", + "RANDOM" + ) +/datum/planet_flora/random/grass/adapt_seed(var/datum/seed/S) + . = ..() + var/carnivore_prob = rand(100) + if(carnivore_prob < 30) + S.set_trait(TRAIT_CARNIVOROUS,2) + if(prob(75)) + S.get_trait(TRAIT_STINGS, 1) + else if(carnivore_prob < 60) + S.set_trait(TRAIT_CARNIVOROUS,1) + if(prob(50)) + S.get_trait(TRAIT_STINGS) + if(prob(15) || (S.get_trait(TRAIT_CARNIVOROUS) && prob(40))) + S.set_trait(TRAIT_BIOLUM,1) + S.set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190)) + + if(prob(30)) + S.set_trait(TRAIT_PARASITE,1) + if(!S.get_trait(TRAIT_LARGE)) + var/vine_prob = rand(100) + if(vine_prob < 15) + S.set_trait(TRAIT_SPREAD,2) + else if(vine_prob < 30) + S.set_trait(TRAIT_SPREAD,1) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/grass + fauna_types = list( + /mob/living/simple_animal/yithian, + /mob/living/simple_animal/tindalos, + /mob/living/simple_animal/hostile/jelly + ) + megafauna_types = list( + /mob/living/simple_animal/hostile/parrot/space/megafauna, + /mob/living/simple_animal/hostile/goose/dire + ) + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/random/grass + habitability_class = null + atmosphere_gen_pressure_min = 0.8 ATM + atmosphere_gen_pressure_max = 1.5 ATM + atmosphere_gen_temperature_min = 20 CELSIUS //Within liquid water/humanoid "comfort" range. Gets adjusted to default species. + atmosphere_gen_temperature_max = 50 CELSIUS //Within liquid water/humanoid "comfort" range. Gets adjusted to default species. + surface_light_gen_level_min = 0.25 //give a chance of twilight jungle + surface_light_gen_level_max = 0.75 + flora = /datum/planet_flora/random/grass + fauna = /datum/fauna_generator/grass + possible_rock_colors = list( + COLOR_ASTEROID_ROCK, + COLOR_GRAY80, + COLOR_BROWN + ) + +/datum/planetoid_data/random/grass/generate_habitability() + if(isnull(habitability_class)) + if(prob(10)) + . = HABITABILITY_IDEAL + else + . = HABITABILITY_OKAY + else + . = habitability_class + set_habitability(.) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +///Map template for generating a grass exoplanet +/datum/map_template/planetoid/random/exoplanet/grass + name = "lush exoplanet" + planetoid_data_type = /datum/planetoid_data/random/grass + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/grass + level_data_type = /datum/level_data/planetoid/exoplanet/grass + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/grass, + /datum/level_data/planetoid/exoplanet/underground + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +///Map generator for the grass exoplanet surface +/datum/random_map/noise/exoplanet/grass + descriptor = "grass exoplanet" + land_type = /turf/floor/grass/wild + water_type = /turf/floor/mud/water + coast_type = /turf/floor/mud + water_level_min = 3 + flora_prob = 10 + grass_prob = 50 + large_flora_prob = 30 + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +///Area for the grass exoplanet surface +/area/exoplanet/grass + base_turf = /turf/floor/grass/wild + ambience = list( + 'sound/effects/wind/wind_2_1.ogg', + 'sound/effects/wind/wind_2_2.ogg', + 'sound/effects/wind/wind_3_1.ogg', + 'sound/effects/wind/wind_4_1.ogg', + 'sound/ambience/eeriejungle2.ogg', + 'sound/ambience/eeriejungle1.ogg' + ) + forced_ambience = list( + 'sound/ambience/jungle.ogg' + ) + fishing_failure_prob = 10 + // TODO: waterweed? + // Hardcoding the contents of /obj/random/natural_debris to avoid hacks to get results out of /obj/random. + fishing_results = list( + /mob/living/simple_animal/aquatic/fish = 10, + /mob/living/simple_animal/aquatic/fish/grump = 10, + /obj/item/mollusc = 5, + /obj/item/mollusc/barnacle/fished = 5, + /mob/living/simple_animal/aquatic/fish/large = 5, + /mob/living/simple_animal/aquatic/fish/large/bass = 5, + /mob/living/simple_animal/aquatic/fish/large/salmon = 5, + /mob/living/simple_animal/aquatic/fish/large/trout = 5, + /mob/living/simple_animal/aquatic/fish/large/pike = 3, + /mob/living/simple_animal/aquatic/fish/large/javelin = 3, + /obj/item/mollusc/clam/fished/pearl = 3, + /obj/item/trash/mollusc_shell/clam = 2, + /obj/item/trash/mollusc_shell/barnacle = 2, + /obj/item/remains/mouse = 2, + /obj/item/remains/lizard = 2, + /obj/item/stick = 1, + /obj/item/trash/mollusc_shell = 1, + /mob/living/simple_animal/aquatic/fish/large/koi = 1 + ) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm new file mode 100644 index 000000000000..d1515fe6582f --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/meat.dm @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/meat + name = "organic exoplanet" + desc = "An exoplanet made entirely of organic matter." + color = "#ac4653" + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/meat + base_area = /area/exoplanet/meat + base_turf = /turf/floor/meat + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/meat, + /datum/random_map/noise/ore/poor, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/meat + flora_diversity = 3 + plant_colors = list( + "#924585", + "#f37474", + "#eb9ee4", + "#4e348b" + ) + +/datum/planet_flora/random/meat/adapt_seed(var/datum/seed/S) + ..() + S.set_trait(TRAIT_CARNIVOROUS,2) + if(prob(75)) + S.get_trait(TRAIT_STINGS, 1) + + S.set_chemical_amount(/decl/material/solid/organic/meat, list(10,30)) + S.set_chemical_amount(/decl/material/liquid/blood, list(5,10)) + S.set_chemical_amount(/decl/material/liquid/acid/stomach, list(5,10)) + + S.set_trait(TRAIT_PARASITE,1) + + if(prob(40)) + S.set_trait(TRAIT_SPREAD,2) + else + S.set_trait(TRAIT_SPREAD,1) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/meat + fauna_types = list( + /mob/living/simple_animal/hostile/jelly/alt, + /mob/living/simple_animal/hostile/leech + ) + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/random/meat + habitability_class = null + atmosphere_gen_temperature_min = 30 CELSIUS + atmosphere_gen_temperature_max = 40 CELSIUS + surface_light_gen_level_min = 0.1 + surface_light_gen_level_max = 0.7 + flora = /datum/planet_flora/random/meat + fauna = /datum/fauna_generator/meat + strata = /decl/strata/sedimentary + surface_color = "#e2768d" + water_color = "#c7c27c" + possible_rock_colors = list( + COLOR_OFF_WHITE, + "#f3ebd4", + "#f3d4f0" + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/random/exoplanet/meat + name = "organic exoplanet" + planetoid_data_type = /datum/planetoid_data/random/meat + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/meat + template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WATER + level_data_type = /datum/level_data/planetoid/exoplanet/meat + prefered_level_data_per_z = null + +/datum/map_template/planetoid/random/exoplanet/meat/get_spawn_weight() + return 10 + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +/datum/random_map/noise/exoplanet/meat + descriptor = "meat exoplanet" + smoothing_iterations = 3 + flora_prob = 5 + large_flora_prob = 0 + megafauna_spawn_prob = 2 //Remember to change this if more types are added. + water_level_max = 3 + water_level_min = 2 + land_type = /turf/floor/meat + water_type = /turf/floor/meat/acid + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/meat + base_turf = /turf/floor/meat + forced_ambience = list( + "sound/ambience/spookyspace1.ogg", + "sound/ambience/spookyspace2.ogg" + ) + +//////////////////////////////////////////////////////////////////////////// +// Turfs +//////////////////////////////////////////////////////////////////////////// + +/turf/floor/meat + name = "fleshy ground" + icon = 'icons/turf/flooring/flesh.dmi' + icon_state = "meat" + _base_flooring = /decl/flooring/meat + material = /decl/material/solid/organic/meat + +/turf/floor/meat/acid + name = "juices" + desc = "Half-digested chunks of vines are floating in the puddle of some liquid." + gender = PLURAL + fill_reagent_type = /decl/material/liquid/acid/stomach + height = -(FLUID_SHALLOW) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm new file mode 100644 index 000000000000..4ef94c9de02c --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/shrouded.dm @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/shrouded + name = "shrouded exoplanet" + desc = "An exoplanet shrouded in a perpetual storm of bizarre, light-absorbing particles." + color = "#783ca4" + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/shrouded/get_atmosphere_color() + return COLOR_BLACK + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/shrouded + base_area = /area/exoplanet/shrouded + base_turf = /turf/floor/shrouded + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/shrouded, + /datum/random_map/noise/ore/poor, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/shrouded + flora_diversity = 3 + plant_colors = list( + "#3c5434", + "#2f6655", + "#0e703f", + "#495139", + "#394c66", + "#1a3b77", + "#3e3166", + "#52457c", + "#402d56", + "#580d6d" + ) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/shrouded + fauna_types = list( + /mob/living/simple_animal/hostile/royalcrab, + /mob/living/simple_animal/hostile/jelly/alt, + /mob/living/simple_animal/hostile/beast/shantak/alt, + /mob/living/simple_animal/hostile/leech + ) + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/random/shrouded + habitability_class = null + atmosphere_gen_pressure_min = 1 ATM + atmosphere_gen_pressure_max = 2.5 ATM + atmosphere_gen_temperature_min = 0 CELSIUS + atmosphere_gen_temperature_max = 10 CELSIUS + surface_light_gen_level_min = 0.15 + surface_light_gen_level_max = 0.25 + flora = /datum/planet_flora/random/shrouded + fauna = /datum/fauna_generator/shrouded + surface_color = "#3e3960" + water_color = "#2b2840" + possible_rock_colors = list( + COLOR_INDIGO, + COLOR_DARK_BLUE_GRAY, + COLOR_NAVY_BLUE + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/random/exoplanet/shrouded + name = "shrouded exoplanet" + planetoid_data_type = /datum/planetoid_data/random/shrouded + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/shrouded + template_tags_blacklist = TEMPLATE_TAG_HABITAT + level_data_type = /datum/level_data/planetoid/exoplanet/shrouded + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/shrouded, + /datum/level_data/planetoid/exoplanet/underground + ) + +/datum/map_template/planetoid/random/exoplanet/shrouded/get_spawn_weight() + return 50 + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +/datum/random_map/noise/exoplanet/shrouded + descriptor = "shrouded exoplanet" + smoothing_iterations = 2 + flora_prob = 5 + large_flora_prob = 20 + megafauna_spawn_prob = 2 //Remember to change this if more types are added. + water_level_max = 3 + water_level_min = 2 + land_type = /turf/floor/shrouded + water_type = /turf/floor/shrouded/tar + +/datum/random_map/noise/exoplanet/shrouded/get_additional_spawns(var/value, var/turf/T) + ..() + if(!T.density && prob(0.045)) // about 1 in 10 screens or so + new /obj/structure/leech_spawner/exoplanet(T) + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/shrouded + forced_ambience = list( + "sound/ambience/spookyspace1.ogg", + "sound/ambience/spookyspace2.ogg" + ) + base_turf = /turf/floor/shrouded diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm new file mode 100644 index 000000000000..567c152b7587 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/snow.dm @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/snow + name = "snow exoplanet" + desc = "Cold planet with limited plant life." + color = "#dcdcdc" + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/snow + base_area = /area/exoplanet/snow + base_turf = /turf/floor/snow + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/snow, + /datum/random_map/noise/ore/poor, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/snow + plant_colors = list( + "#d0fef5", + "#93e1d8", + "#93e1d8", + "#b2abbf", + "#3590f3", + "#4b4e6d" + ) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/snow + fauna_types = list( + /mob/living/simple_animal/hostile/beast/samak, + /mob/living/simple_animal/hostile/beast/diyaab, + /mob/living/simple_animal/hostile/beast/shantak + ) + megafauna_types = list( + /mob/living/simple_animal/hostile/giant_crab + ) + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/random/snow + habitability_class = null + atmosphere_gen_temperature_min = -120 CELSIUS // a bit lower than arctic temperatures + atmosphere_gen_temperature_max = -10 CELSIUS + initial_weather_state = /decl/state/weather/snow + flora = /datum/planet_flora/random/snow + fauna = /datum/fauna_generator/snow + surface_color = "#e8faff" + water_color = "#b5dfeb" + possible_rock_colors = list( + COLOR_DARK_BLUE_GRAY, + COLOR_GUNMETAL, + COLOR_GRAY80, + COLOR_DARK_GRAY + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/random/exoplanet/snow + name = "snow exoplanet" + planetoid_data_type = /datum/planetoid_data/random/snow + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/snow + level_data_type = /datum/level_data/planetoid/exoplanet/snow + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/snow, + /datum/level_data/planetoid/exoplanet/underground + ) + //#TODO: Do weather stuff to init properly + //water_material = null // Will prevent the weather system causing rainfall. + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +/datum/random_map/noise/exoplanet/snow + descriptor = "snow exoplanet" + flora_prob = 5 + large_flora_prob = 10 + water_level_max = 3 + land_type = /turf/floor/snow + water_type = /turf/floor/ice + smoothing_iterations = 1 + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/snow + base_turf = /turf/floor/snow + ambience = list( + 'sound/effects/wind/tundra0.ogg', + 'sound/effects/wind/tundra1.ogg', + 'sound/effects/wind/tundra2.ogg', + 'sound/effects/wind/spooky0.ogg', + 'sound/effects/wind/spooky1.ogg' + ) diff --git a/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm b/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm new file mode 100644 index 000000000000..fc24c4a289fc --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planet_types/volcanic.dm @@ -0,0 +1,128 @@ +//////////////////////////////////////////////////////////////////////////// +// Overmap Marker +//////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/volcanic + name = "volcanic exoplanet" + desc = "A tectonically unstable planet, extremely rich in minerals." + color = "#9c2020" + +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/volcanic/get_atmosphere_color() + return COLOR_GRAY20 + +//////////////////////////////////////////////////////////////////////////// +// Level Data +//////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/exoplanet/volcanic + base_area = /area/exoplanet/volcanic + base_turf = /turf/floor/rock/volcanic + exterior_atmosphere = null + exterior_atmos_temp = null + level_generators = list( + /datum/random_map/noise/exoplanet/volcanic, + /datum/random_map/noise/ore/filthy_rich, + ) + +//////////////////////////////////////////////////////////////////////////// +// Flora Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/volcanic + has_trees = FALSE + flora_diversity = 3 + plant_colors = list( + "#a23c05", + "#3f1f0d", + "#662929", + "#ba6222", + "#7a5b3a", + "#471429" + ) +/datum/planet_flora/random/volcanic/adapt_seed(datum/seed/S) + ..() + S.set_trait(TRAIT_REQUIRES_WATER, 0) + S.set_trait(TRAIT_HEAT_TOLERANCE, 1000 + S.get_trait(TRAIT_HEAT_TOLERANCE)) + +//////////////////////////////////////////////////////////////////////////// +// Fauna Generator +//////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/volcanic + fauna_types = list( + /mob/living/simple_animal/thinbug, + /mob/living/simple_animal/hostile/beast/shantak/lava, + /mob/living/simple_animal/hostile/beast/charbaby + ) + megafauna_types = list( + /mob/living/simple_animal/hostile/space_dragon + ) + +/datum/fauna_generator/volcanic/generate_template(spawn_type, atmos_temp, list/min_gas, list/max_gas) + var/datum/generated_fauna_template/Tmpl = ..() + Tmpl.heat_damage_per_tick = 0 //animals not hot, no burning in lava + return Tmpl + +//////////////////////////////////////////////////////////////////////////// +// Planetoid Data +//////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/random/volcanic + habitability_class = HABITABILITY_BAD + atmosphere_gen_temperature_min = 240 CELSIUS + atmosphere_gen_temperature_max = 820 CELSIUS + atmosphere_gen_pressure_min = 10 ATM //It's safe to say a volcanic world probably has a thick gas blanket if it's big enough to hold an atmosphere + atmosphere_gen_pressure_max = 90 ATM //Venus is 92.10 atm or 93 bar for reference + initial_weather_state = /decl/state/weather/ash + flora = /datum/planet_flora/random/volcanic + fauna = /datum/fauna_generator/volcanic + surface_color = "#261e19" + water_color = "#c74d00" + possible_rock_colors = list( + COLOR_DARK_GRAY + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Template +//////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/random/exoplanet/volcanic + name = "volcanic exoplanet" + planetoid_data_type = /datum/planetoid_data/random/volcanic + overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid/exoplanet/volcanic + max_themes = 1 + template_tags_blacklist = TEMPLATE_TAG_HABITAT|TEMPLATE_TAG_WATER + level_data_type = /datum/level_data/planetoid/exoplanet/volcanic + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet/volcanic, + /datum/level_data/planetoid/exoplanet/underground + ) + possible_themes = list( + /datum/exoplanet_theme/mountains = 190, + /datum/exoplanet_theme/robotic_guardians = 10 + ) + +//////////////////////////////////////////////////////////////////////////// +// Map Generator Surface +//////////////////////////////////////////////////////////////////////////// + +/datum/random_map/noise/exoplanet/volcanic + descriptor = "volcanic exoplanet" + smoothing_iterations = 5 + land_type = /turf/floor/rock/volcanic + water_type = /turf/floor/lava + water_level_min = 5 + water_level_max = 6 + fauna_prob = 1 + flora_prob = 3 + grass_prob = 0 + large_flora_prob = 0 + smooth_single_tiles = TRUE + +//////////////////////////////////////////////////////////////////////////// +// Areas +//////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/volcanic + forced_ambience = list('sound/ambience/magma.ogg') + base_turf = /turf/floor/rock/volcanic diff --git a/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm b/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm new file mode 100644 index 000000000000..95df86b82f93 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/planetoid_data.dm @@ -0,0 +1,645 @@ +////////////////////////////////////////////////////////////////////// +// Planetoid Data +////////////////////////////////////////////////////////////////////// + +/** + * Data for a planetoid. Used by SSmapping for keeping track of a lot of details about specific planetoids. + */ +/datum/planetoid_data + ///Unique internal Id string for looking up this planetoid in SSmapping + var/id + //The name for this planetoid that's displayed to users + var/name + + // *** Level *** + ///Preferred width for all the planet z-levels. Null means it's up to each z-levels. Not reliable for telling the width of the levels under this planet. + var/width + ///Preferred height for all the planet z-levels. Null means it's up to each z-levels. Not reliable for telling the height of the levels under this planet. + var/height + ///Preferred amount of vertically connected z-levels for this planets. Null means it's up to each z-levels. + var/tallness = 1 + ///Topmost level data datum id of the root z stack (ID only, because this datum has an uncontrolled lifetime, and we don't want dangling refs) + var/topmost_level_id + ///Level data id for the level that's considered to be the planet's surface. In other words, the topmost firm ground level of the root z stack. + var/surface_level_id + ///A reference to the surface area of the planet. + var/area/surface_area + + // *** Atmos *** + ///The habitability rating for this planetoid + var/habitability_class = HABITABILITY_DEAD + ///The cached planet's atmosphere that sub-levels of this planet should use. Can be a type path at definition, and an instance at runtime. + var/datum/gas_mixture/atmosphere + ///What weather state to use for this planet initially. If null, will not initialize any weather system. Must be a typepath rather than an instance. + var/decl/state/weather/initial_weather_state = /decl/state/weather/calm + + // *** Appearence *** + ///A weak reference to the overmap marker for this template instance if any exists. Or at definition the type path of the marker to use + var/weakref/overmap_marker + ///Color of the primary layer of the skybox image. Used by the overmap marker. + var/surface_color = COLOR_ASTEROID_ROCK + ///Color of the secondary layer of the skybox image. Is usually water-like features. Used by the overmap marker. + var/water_color = "#436499" + ///The color for rocks on this planet. Null is the rock wall's material's default. + var/rock_color = COLOR_ASTEROID_ROCK + ///Whether this planetoid has rings, used by the overmap marker to draw rings in the skybox and etc.. + var/has_rings = FALSE + ///If we have rings, this is the color they'll have on the overmap + var/ring_color = COLOR_OFF_WHITE + ///If we have rings, this is the sprite we picked for it + var/ring_type_name = SKYBOX_PLANET_RING_TYPE_SPARSE + ///The overall strata of the planet. May be a type path at definition, or instance at runtime. + var/decl/strata/strata + + // *** Generated Features *** + ///List of theme types that were randomly picked from the possible list at runtime. Also used by the overmap marker. + var/list/themes + ///List of subtemplates types we picked and spawned on this planet. + var/list/subtemplates + + // *** Xenorach *** + ///A xenoarch flavor text generator instance for this planet. Used for unique engravings and weird visions stuff. + var/datum/xenoarch_engraving_flavor/engraving_generator = /datum/xenoarch_engraving_flavor + + // *** Ambient Lighting *** + /// ID used for registering/deregistering with a daycycle. + var/daycycle_id = "daycycle_solars" + /// Type of daycycle to use. + var/daycycle_type = /datum/daycycle/solars + ///Ambient lighting level across the surface. All surface height levels will be set to this. + var/surface_light_level + ///Lighjting color used for the entire surface. + var/surface_light_color + + // *** fauna/flora handling *** + ///The flora generator instance that generates and keep track of the flora types for this planet. May be set to a path to instantiate. + var/datum/planet_flora/flora + ///The instance of the fauna generator currently managing our fauna if any. May be set to a path to instantiate. + var/datum/fauna_generator/fauna //#TODO: Temporary thing for allowing animal stuff to be customized in the map_template + + // *** Special Overrides *** + //#TODO: There is probably a way to handle options set from manually spawning planets that is less shitty? + ///Subtemplate budget override. If something overrode the map_template's base budget, this will be set. Otherwise, it'll stay null. (Used in manual exoplanet generation verb) + var/tmp/_budget_override + ///Enforces a single theme. If something overrode the map template's base random themes list, this will be set. Otherwise it'll stay null. (Used in manual exoplanet generation verb) + var/tmp/_theme_forced + +/datum/planetoid_data/New() + generate_planetoid_id() + +/datum/planetoid_data/Destroy(force) + //shouldn't delete before end. Turfs refers to this + end_processing() + SSmapping.unregister_planetoid(src) //Clears refs to us, doesn't mess with the levels + log_debug("Desroying planetoid data ([id], [name]): [log_info_line(src)]") + . = ..() + +///Generate and sets the planetary id for this planetoid if it doesn't have one yet. Called on instantiation. +/datum/planetoid_data/proc/generate_planetoid_id() + if(isnull(daycycle_id)) + daycycle_id = "daycycle_[sequential_id(/datum/planetoid_data)]" + if(length(id)) + return + return id = "planetoid_[sequential_id(/datum/planetoid_data)]" + +///Initializes the internal state of the planetoid, so its data can be used. Should be called no earlier than when SSmapping is running. +/datum/planetoid_data/proc/setup_planetoid() + SSmapping.register_planetoid(src) + + //Planet composition + if(ispath(atmosphere)) + set_atmosphere(atmosphere) + if(ispath(strata)) + set_strata(strata) + if(ispath(initial_weather_state)) + generate_weather() + + //Handle fauna/flora + if(ispath(flora)) + setup_flora_data(flora) + if(ispath(fauna)) + setup_fauna_generator(fauna) + generate_life() + + //Xenoarch stuff + if(ispath(engraving_generator)) + set_engraving_generator(engraving_generator) + + //Always keep the overmap marker in sync if we have one set already + try_update_overmap_marker() + +// ** Bunch of overrideables below ** + +///Sets the name of the planetoid, and causes updates to happen to anything linked to us. +/datum/planetoid_data/proc/SetName(var/newname) + name = newname + //#TODO: Maybe force an update on linked areas, overmap markers and levels? + try_update_overmap_marker() + +///Sets the habitability of the planetoid for generation and display. Causes the overmap marker to be updated to reflect the changes. +/datum/planetoid_data/proc/set_habitability(var/habitability) + habitability_class = habitability + //#TODO: Maybe force an update on linked areas, overmap markers and levels? + try_update_overmap_marker() + +///Sets the atmosphere of the planet to the given gas_mixture instance or type path. Will Clone() the mixture in the arguments for itself. +/datum/planetoid_data/proc/set_atmosphere(var/datum/gas_mixture/A) + if(ispath(A)) + atmosphere = new A + return + //Externally set atmos instances should make a clone always to be the safe side + atmosphere = A.Clone() + +///Resets the given weather state to our planet replacing the old one, and trigger updates. Can be a type path or instance. +/datum/planetoid_data/proc/reset_weather(var/decl/state/weather/weather) + initial_weather_state = weather + if(!(topmost_level_id in SSmapping.levels_by_id)) + return //It's entire possible the levels weren't initialized yet, so don't bother. + //Tells all our levels exposed to the sky to force change the weather. + SSweather.setup_weather_system(topmost_level_id, initial_weather_state) + +///Associate an overmap marker with this planetoid data so we can synchronize the information displayed on the overmap with the actual state of the planet. +/datum/planetoid_data/proc/set_overmap_marker(var/obj/effect/overmap/visitable/sector/planetoid/P) + if(isnull(P)) + overmap_marker = null + else + overmap_marker = weakref(P) + P.update_from_data(src) + +///Sets the planet's strata to the given one. The argument may be a type path or instance. Shouldn't be used outside of setup after the world was generated. +/datum/planetoid_data/proc/set_strata(var/decl/strata/_strata) + if(ispath(_strata, /decl/strata)) + _strata = GET_DECL(_strata) + strata = _strata + +///Sets the xenoarch engraving generator for the planet. The argument can be either an instance, or a type path. +/datum/planetoid_data/proc/set_engraving_generator(var/datum/xenoarch_engraving_flavor/X) + if(ispath(X)) + X = new X + engraving_generator = X + +///Set the id of the topmost level of the planetoid. Argument can be a level_data, or level_id string. Should only be set once during setup ideally. +/datum/planetoid_data/proc/set_topmost_level(var/datum/level_data/LD) + topmost_level_id = istext(LD)? LD : LD.level_id + +///Sets the id of the surface level of the planetoid. Argument can be a level_data, or level_id string(make sure the level_data is reachable from SSmapping's level_data by id list). +/// Should be set only once during setup. Also updates our base surface area var. +/datum/planetoid_data/proc/set_surface_level(var/datum/level_data/LD) + if(istext(LD)) + LD = SSmapping.levels_by_id[LD] + surface_level_id = LD.level_id + if(LD.base_area) + surface_area = LD.get_base_area_instance() + +///Is there any flora species on this planetoid? +/datum/planetoid_data/proc/has_flora() + return LAZYLEN(flora?.small_flora_types) > 0 || LAZYLEN(flora?.big_flora_types) > 0 + +///Is there any currently live fauna on this planetoid? +/datum/planetoid_data/proc/has_fauna() + return LAZYLEN(fauna?.live_fauna) > 0 + +///If the animal is native of this planet returns TRUE. +/datum/planetoid_data/proc/is_native_animal(mob/living/simple_animal/A) + return LAZYISIN(fauna?.live_fauna, A) || is_type_in_list(A, fauna?.respawn_queue) + +///If the plant is native of this planet it will return TRUE. +/datum/planetoid_data/proc/is_native_plant(datum/seed/S) + return LAZYISIN(flora?.small_flora_types, S) || LAZYISIN(flora?.big_flora_types, S) + +///Returns the strata picked for the planet, if there is one. +/datum/planetoid_data/proc/get_strata() + return strata + +///Returns the color of grass picked for this planet or null. +/datum/planetoid_data/proc/get_grass_color() + return flora?.grass_color + +///Returns the color of rock walls on this planet, or null. +/datum/planetoid_data/proc/get_rock_color() + return rock_color + +///Create the specified type of flora data type for this planetoid +/datum/planetoid_data/proc/setup_flora_data(var/flora_data_type) + if(istype(flora)) + QDEL_NULL(flora) + else + flora = null + flora = new flora_data_type + flora.setup_flora(atmosphere) + return flora + +///Create the specified type of fauna manager type for this planetoid +/datum/planetoid_data/proc/setup_fauna_generator(var/generator_type) + if(istype(fauna)) + QDEL_NULL(fauna) + else + fauna = null + return (fauna = new generator_type()) + +///Registers to neccessary processors and begin running all processing needed by the planet +/datum/planetoid_data/proc/begin_processing() + set waitfor = FALSE + if(daycycle_id) + SSdaycycle.register_level(get_linked_level_zs(), daycycle_id, daycycle_type) + +///Stop running any processing needed by the planet, and unregister from processors. +/datum/planetoid_data/proc/end_processing() + set waitfor = FALSE + if(daycycle_id) + SSdaycycle.remove_level(get_linked_level_zs(), daycycle_id) + +//#TODO: Move this into some SS for planet processing stuff or something? +/datum/planetoid_data/Process(wait, tick) + //#TODO: Repopulation stuff could go into some mob manager thing + if(fauna) + fauna.Process(wait, tick) + +//#TOOD: Move this somewhere sensible. +/datum/planetoid_data/proc/rename_species(var/species_type, var/newname, var/force = FALSE) + if(!fauna) + return FALSE + . = fauna.rename_species(species_type, newname, force) + //Overmap has some species stuff, so keep it up to date + try_update_overmap_marker() + +/datum/planetoid_data/proc/get_random_species_name() + if(!fauna) + return "alien creature" + return fauna.get_random_species_name() + +/datum/planetoid_data/proc/get_linked_level_zs() + for(var/linked_level_id in get_linked_level_ids()) + var/datum/level_data/LD = SSmapping.levels_by_id[topmost_level_id] + LAZYDISTINCTADD(., LD.level_z) + +///Returns a list of all the level id of the levels associated to this planet +/datum/planetoid_data/proc/get_linked_level_ids() + var/datum/level_data/LD = SSmapping.levels_by_id[topmost_level_id] + return SSmapping.get_connected_levels_ids(LD.level_z) + +///Make our fauna and flora gen setup. +/datum/planetoid_data/proc/generate_life(var/list/breathable_gas, var/list/toxic_gases) + if(fauna) + fauna.generate_fauna(atmosphere, breathable_gas?.Copy(), toxic_gases?.Copy()) //Must be copies here #TODO: Fix this + for(var/datum/exoplanet_theme/theme in themes) + fauna.apply_theme(theme) + +///Setup the initial weather state for the planet. Doesn't apply it to our z levels however. +/datum/planetoid_data/proc/generate_weather() + if(ispath(initial_weather_state)) + initial_weather_state = GET_DECL(initial_weather_state) + +///Force any overmap markers linked to us to update to match our state +/datum/planetoid_data/proc/try_update_overmap_marker() + var/obj/effect/overmap/visitable/sector/planetoid/P = overmap_marker?.resolve() + if(istype(P)) + P.update_from_data(src) + return TRUE + return FALSE + +// +// Plants and Critter Spawner Procs +// +//#TOOD: Move this somewhere sensible. +/datum/planetoid_data/proc/spawn_random_fauna(var/turf/T) + if(!fauna) + return FALSE + return fauna.try_spawn_fauna(T) + +//#TOOD: Move this somewhere sensible. +/datum/planetoid_data/proc/spawn_random_megafauna(var/turf/T) + if(!fauna) + return FALSE + return fauna.try_spawn_megafauna(T) + +/datum/planetoid_data/proc/spawn_random_small_flora(var/turf/T) + if(!flora) + return FALSE + return flora.spawn_random_small_flora(T) + +/datum/planetoid_data/proc/spawn_random_big_flora(var/turf/T) + if(!flora) + return FALSE + return flora.spawn_random_big_flora(T) + + +// +// Random Planetoid +// + +///A randomly generating planetoid_data, used by random planet map_templates +/datum/planetoid_data/random + name = null //Must be null for randomly generated name + + ///The chance that this planetoid template creates a planetoid with a ring. + var/ring_gen_probability = 25 + ///Possible ring colors + var/list/possible_ring_color = list(COLOR_OFF_WHITE, "#f0fcff", "#dcc4ad", "#d1dcad", "#adb8dc") + ///Possible ring sprites that can be used for a possible ring + var/list/possible_ring_type_name = list(SKYBOX_PLANET_RING_TYPE_SPARSE, SKYBOX_PLANET_RING_TYPE_DENSE) + + ///Possible colors for rock walls and rocks in general on this planet (Honestly, should be handled via materal system maybe?) + var/list/possible_rock_colors = list(COLOR_ASTEROID_ROCK) + + ///A list of gas and their proportion to enforce on this planet when generating the atmosphere. + ///If a level's get_mandatory_gases() returns gases, they will be added to this. If null is randomly generated. + var/list/forced_atmosphere_gen_gases + ///Minimum amount of different atmospheric gases that may be generated for this planet, not counting the forced gases + var/atmospheric_gen_gases_min = 1 + ///Maximum amount of different atmospheric gases that may be generated for this planet, not counting the forced gases + var/atmospheric_gen_gases_max = 4 + ///Minimum possible base temperature range to pick from, in kelvins, when generating the atmosphere on this planet. + var/atmosphere_gen_temperature_min = TCMB + ///Maximum possible base temperature range to pick from, in kelvins, when generating the atmosphere on this planet. + var/atmosphere_gen_temperature_max = T100C + ///Minimum atmospheric pressure in the range to pick from for this planet template. + var/atmosphere_gen_pressure_min = 0.5 ATM + ///Maximum atmospheric pressure in the range to pick from for this planet template. + var/atmosphere_gen_pressure_max = 2 ATM + + ///Planet ambient lighting minimum possible value from 0 to 1. This value may be overridden in individual /datum/level_data. + var/surface_light_gen_level_min = 0.45 + ///Planet ambient lighting maximum possible value from 0 to 1. This value may be overridden in individual /datum/level_data. + var/surface_light_gen_level_max = 0.75 + + ///Possible list of colors to pick for the ambient lighting color. Null means a random color will be generated. + ///This value may be overridden by individual /datum/level_data. + var/list/possible_surface_light_gen_colors + +/datum/planetoid_data/random/setup_planetoid() + //Generate random stuff first + pregenerate() + . = ..() + +///Pre-generate the random planetoid's data before it has any actual level or overmap marker tied to it. +/datum/planetoid_data/random/proc/pregenerate() + make_planet_name() + generate_habitability() + generate_atmosphere() + generate_planet_materials() + generate_planetoid_rings() + generate_ambient_lighting() + generate_weather() + +///If the planet doesn't have a name defined, a name will be randomly generated for it. (Named this way because a global proc generate_planet_name already exists) +/datum/planetoid_data/random/proc/make_planet_name() + if(length(name)) + return + SetName(global.generate_planet_name()) + +/datum/planetoid_data/random/proc/generate_planetoid_rings() + if(!prob(ring_gen_probability) || !length(possible_ring_type_name)) + return + has_rings = TRUE + ring_color = length(possible_ring_color)? pick(possible_ring_color) : COLOR_OFF_WHITE + ring_type_name = pick(possible_ring_type_name) + +///Generate the planet's minable resources, material for rocks and etc. +/datum/planetoid_data/random/proc/generate_planet_materials() + select_strata() + if(islist(possible_rock_colors) && length(possible_rock_colors)) + rock_color = pick(possible_rock_colors) + else if(possible_rock_colors) + rock_color = possible_rock_colors + +///Selects the base strata for the whole planet. The levels have the final say however in what to do with that. +/datum/planetoid_data/random/proc/select_strata() + if(isnull(strata)) + //No stratas, so pick one + var/list/all_strata = decls_repository.get_decls_of_subtype(/decl/strata) + var/list/possible_strata = list() + + for(var/stype in all_strata) + var/decl/strata/strata = all_strata[stype] + if(strata.is_valid_exoplanet_strata(src)) + possible_strata += stype + + if(length(possible_strata)) + . = pick(possible_strata) + else + //If we have one defined, or have an instance alreaddy, just go with it + if(ispath(strata)) + . = GET_DECL(strata) + else + . = strata + set_strata(.) + +///Pick an hability class for this planet. Should be done as early as possible during generation. +/datum/planetoid_data/random/proc/generate_habitability() + if(isnull(habitability_class)) + if(prob(10)) + . = HABITABILITY_IDEAL + else if(prob(30)) + . = HABITABILITY_OKAY + else if(prob(40)) + . = HABITABILITY_BAD + else + . = HABITABILITY_DEAD + else + . = habitability_class + set_habitability(.) + +///Go through all materials and pick those that we could pick from on this planet +/datum/planetoid_data/random/proc/pick_atmospheric_gases_candidates(var/atmos_temperature, var/atmos_pressure, var/blacklisted_flags, var/list/blacklisted_gases) + var/list/candidates = list() + var/list/all_materials = decls_repository.get_decls_of_subtype(/decl/material) - blacklisted_gases + + //Filter and list gases paths with their exoplanet rarity + for(var/mat_type in all_materials) + var/decl/material/mat = all_materials[mat_type] + //Check if this material is allowed + if((mat.gas_flags & blacklisted_flags) || (mat.exoplanet_rarity_gas == MAT_RARITY_NOWHERE)) + continue + // No gaseous ice. + // Maybe consider adding heating products instead, but it'd have to change how this loop is done. + // Also that'd result in a ton of water vapor when really we'd only be interested in the volatiles... + if(!isnull(mat.heating_point) && length(mat.heating_products) && atmos_temperature >= mat.heating_point) + continue + if(!isnull(mat.chilling_point) && length(mat.chilling_products) && atmos_temperature <= mat.chilling_point) + continue + //Check if this gas can exist in the atmosphere + // For now, we skip materials above their ignition point entirely. + // However, it's also checked in generate_atmosphere and applies the fuel flag, + // so if including them is ever desirable it'll be handled properly. + if(!isnull(mat.ignition_point) && atmos_temperature >= mat.ignition_point) + continue + var/will_condensate = !isnull(mat.gas_condensation_point) && (atmos_temperature <= mat.gas_condensation_point) + switch(mat.phase_at_temperature(atmos_temperature, atmos_pressure)) + if(MAT_PHASE_LIQUID) + if(will_condensate) + continue //A liquid below dew point cannot be in the atmosphere + //Otherwise allow liquids if they may exist as vapor + if(MAT_PHASE_SOLID, MAT_PHASE_PLASMA) + continue //In any other cases if we're not a gas skip + candidates[mat.type] = mat.exoplanet_rarity_gas + + if(prob(50)) //alium gas should be slightly less common than mundane shit + candidates -= /decl/material/gas/alien + + return candidates + +///Generates a valid surface temperature for the planet's atmosphere matching its habitability class +/datum/planetoid_data/random/proc/generate_surface_temperature() + . = rand(atmosphere_gen_temperature_min, atmosphere_gen_temperature_max) + + //Adjust for species habitability + if(habitability_class == HABITABILITY_OKAY || habitability_class == HABITABILITY_IDEAL) + var/decl/species/S = decls_repository.get_decl_by_id(global.using_map.default_species) + if(habitability_class == HABITABILITY_IDEAL) + . = clamp(., S.default_bodytype.cold_discomfort_level + rand(1,5), S.default_bodytype.heat_discomfort_level - rand(1,5)) //Clamp between comfortable levels since we're ideal + else + . = clamp(., S.default_bodytype.cold_level_1 + 1, S.default_bodytype.heat_level_1 - 1) //clamp between values species starts taking damages at + +///Generates a valid surface pressure for the planet's atmosphere matching it's habitability class +/datum/planetoid_data/random/proc/generate_surface_pressure() + . = rand(atmosphere_gen_pressure_min, atmosphere_gen_pressure_max) + + //Adjust for species habitability + if(habitability_class == HABITABILITY_OKAY || habitability_class == HABITABILITY_IDEAL) + var/decl/species/S = decls_repository.get_decl_by_id(global.using_map.default_species) + var/breathed_min_pressure = S.breath_pressure + var/safe_max_pressure = S.get_hazard_high_pressure() + var/safe_min_pressure = S.get_hazard_low_pressure() + var/comfortable_max_pressure = S.get_warning_high_pressure() + var/comfortable_min_pressure = S.get_warning_low_pressure() + + //On ideal planets, clamp against the comfortability limit pressures, since it shouldn't hit any extremes + if(habitability_class == HABITABILITY_IDEAL) + . = clamp(., comfortable_min_pressure, comfortable_max_pressure) + //On okay planets, clamp against the safety limit pressures, so it's uncomfortable, but not harmful + else + . = clamp(., safe_min_pressure + 1, safe_max_pressure - 1) //Safety check inclusively compares against those values, so remove/add one from both + + //Ensure we at least have the minimum breathable pressure + . = max(., breathed_min_pressure) + +///Creates the atmosphere for the planet randomly or not. +/datum/planetoid_data/random/proc/generate_atmosphere() + //Determine the temp, pressure, and mol count + var/datum/gas_mixture/new_atmos = new + var/target_temperature = generate_surface_temperature() + var/target_pressure = generate_surface_pressure() + var/total_moles = (target_pressure * CELL_VOLUME) / (target_temperature * R_IDEAL_GAS_EQUATION) + var/available_moles = total_moles + new_atmos.temperature = target_temperature + + //Forced gases get added in first + var/forced_flag_check = 0 + for(var/gas_path in forced_atmosphere_gen_gases) + var/decl/material/gas_mat = GET_DECL(gas_path) + forced_flag_check |= gas_mat.gas_flags + new_atmos.gas[gas_path] = forced_atmosphere_gen_gases[gas_path] * total_moles + //Subtract any forced gases from the total available moles amount + available_moles = max(0, available_moles - new_atmos.gas[gas_path]) + + //Sanity warning so people don't accidently set a combustible mixture as forced atmos + if((forced_flag_check & XGM_GAS_OXIDIZER) && (forced_flag_check & XGM_GAS_FUEL)) + log_warning("The list of forced gases user-defined for [src]'s atmoshpere contains both an oxidizer and a fuel!") + + //Make a list of gas flags to avoid + var/blacklisted_flags = forced_flag_check & (XGM_GAS_OXIDIZER | XGM_GAS_FUEL) //Prevents combustible mixtures + var/list/blacklisted_gases //list of gases that shouldn't be in the atmosphere + + //Habitable planets do not want any contaminants in the air + if(habitability_class == HABITABILITY_OKAY || habitability_class == HABITABILITY_IDEAL) + blacklisted_flags |= XGM_GAS_CONTAMINANT + + //Make sure temperature can't damage people on casual planets (Only when not forcing an atmosphere) + var/decl/species/S = decls_repository.get_decl_by_id(global.using_map.default_species) + var/lower_temp = max(S.default_bodytype.cold_level_1, atmosphere_gen_temperature_min) + var/higher_temp = min(S.default_bodytype.heat_level_1, atmosphere_gen_temperature_max) + var/breathed_gas = S.breath_type + var/breathed_min_pressure = S.breath_pressure + + //Make sure we add all the poisons to the blacklist + for(var/gas_path in S.poison_types) + LAZYDISTINCTADD(blacklisted_gases, gas_path) + + //Adjust temperatures to be for the species + new_atmos.temperature = clamp(new_atmos.temperature, lower_temp + rand(1,5), higher_temp - rand(1,5)) + + //#TODO: Take into account if a species is aquatic? + //Synths don't breath, so make sure we validate this here + if(breathed_gas) + //Calculate the minimum amount of moles of breathable gas needed by the default species + new_atmos.gas[breathed_gas] = (breathed_min_pressure * CELL_VOLUME) / (new_atmos.temperature * R_IDEAL_GAS_EQUATION) + + //Pick the list of possible gases we can use in our random atmosphere, if we are set to generate any + if(atmospheric_gen_gases_min > 0 && atmospheric_gen_gases_max > 0) + var/list/candidate_gases = pick_atmospheric_gases_candidates(new_atmos.temperature, target_pressure, blacklisted_flags, blacklisted_gases) + if(length(candidate_gases)) + //All the toggled flags of the gases we added this far. Used to avoid mixing dangerous gases. + var/current_merged_flags = 0 + var/number_gases = rand(atmospheric_gen_gases_min, atmospheric_gen_gases_max) + var/i = 1 + + while((i <= number_gases) && (available_moles > 0) && length(candidate_gases)) + var/picked_gas = pickweight(candidate_gases) //pick a gas + candidate_gases -= picked_gas + + // Make sure atmosphere is not flammable + var/decl/material/mat = GET_DECL(picked_gas) + if(((current_merged_flags & XGM_GAS_OXIDIZER) && (mat.gas_flags & XGM_GAS_FUEL)) || \ + ((current_merged_flags & XGM_GAS_FUEL) && (mat.gas_flags & XGM_GAS_OXIDIZER))) + continue + + // If we have an ignition point we're basically XGM_GAS_FUEL, kind of. TODO: Combine those somehow? + // These don't actually burn but it's still weird to see vaporized skin gas in an oxygen-rich atmosphere, + // so skip them. + if(!isnull(mat.ignition_point) && new_atmos.temperature >= mat.ignition_point) + if(current_merged_flags & XGM_GAS_OXIDIZER) + continue + current_merged_flags |= XGM_GAS_FUEL + + current_merged_flags |= mat.gas_flags + var/min_percent = 10 + var/max_percent = 90 + switch(mat.exoplanet_rarity_gas) + if(MAT_RARITY_UNCOMMON) + min_percent = 5 + max_percent = 60 + if(MAT_RARITY_EXOTIC) + min_percent = 1 + max_percent = 10 + var/part = available_moles * (rand(min_percent, max_percent)/100) //allocate percentage to it + if(i == number_gases || !length(candidate_gases)) //if it's last gas, let it have all remaining moles + part = available_moles + new_atmos.gas[picked_gas] += part + available_moles = max(available_moles - part, 0) + i++ + + new_atmos.update_values() + set_atmosphere(new_atmos) + +///Calculate the color and intensity of the ambient starlight that this planet receives. +/datum/planetoid_data/random/proc/generate_ambient_lighting() + //Try to generate a surface light intensity if we don't have it yet + if(!surface_light_level) + surface_light_level = generate_surface_light_level() + + //Try to generate surface light color if we don't have any yet + if(!surface_light_color) + surface_light_color = generate_surface_light_color() + +///Calculate the ambient lighting intensity for the planet. +/datum/planetoid_data/random/proc/generate_surface_light_level() + if((surface_light_gen_level_min >= 0) && (surface_light_gen_level_max > 0) && (min(surface_light_gen_level_max, 1) <= 1.0)) + //We got a range of random values to generate the lighting level from, so use that + return rand(surface_light_gen_level_min * 100, surface_light_gen_level_max * 100) / 100 //rand() doesn't work on decimal numbers + else + return 0.9 + +/datum/planetoid_data/random/proc/generate_surface_light_color() + if(length(possible_surface_light_gen_colors)) + //If we have colors to pick from, go for it + return pick(possible_surface_light_gen_colors) + else + //Otherwise generate it randomly + var/atmos_color = atmosphere?.get_overall_color() || get_random_colour() + var/list/HSV = rgb2num(atmos_color, COLORSPACE_HSV) + var/sat_factor = rand(50, 80) / 100 //Make the color less saturated to around 50% to 80% + var/val_factor = 1 + (rand(10, 50) / 100) //Make the color brighter within a factor of 10%-50% + //Scale and clamp to sane-ish values for lighting + return hsv(HSV[1], clamp(round(HSV[2] * sat_factor), 40, 80), clamp(round(HSV[3] * val_factor), 60, 90), 200) + diff --git a/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm b/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm new file mode 100644 index 000000000000..3cdd8d4a0f37 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_exoplanet.dm @@ -0,0 +1,22 @@ +///Random map generator for exo planets +/datum/map_template/planetoid/random/exoplanet + name = "random exoplanet" + abstract_type = /datum/map_template/planetoid/random/exoplanet + template_categories = list(MAP_TEMPLATE_CATEGORY_EXOPLANET) + template_category = MAP_TEMPLATE_CATEGORY_EXOPLANET_SITE + tallness = 1 + level_data_type = /datum/level_data/planetoid/exoplanet + prefered_level_data_per_z = list( + /datum/level_data/planetoid/exoplanet, + ) + possible_themes = list( + /datum/exoplanet_theme/mountains = 130, + /datum/exoplanet_theme/radiation_bombing = 10, + /datum/exoplanet_theme/ruined_city = 5, + /datum/exoplanet_theme/robotic_guardians = 10 + ) + +/datum/map_template/planetoid/random/exoplanet/preload() + . = ..() + if(.) + tallness = global.using_map.planet_depth \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/random_map.dm b/code/modules/maps/template_types/random_exoplanet/random_map.dm new file mode 100644 index 000000000000..5f9d27d367c0 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_map.dm @@ -0,0 +1,173 @@ +#define COAST_VALUE (cell_range + 1) +#define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) + +///Place down flora/fauna spawners, grass, water, and apply selected land type. +/datum/random_map/noise/exoplanet + descriptor = "exoplanet" + smoothing_iterations = 1 + smooth_single_tiles = TRUE + + var/water_level + var/water_level_min = 0 + var/water_level_max = 5 + var/land_type = /turf/floor/barren + var/water_type + var/coast_type + + //intended x*y size, used to adjust spawn probs + var/intended_x = 150 + var/intended_y = 150 + var/large_flora_prob = 30 + var/flora_prob = 10 + var/fauna_prob = 2 + var/grass_prob + var/megafauna_spawn_prob = 0.5 //chance that a given fauna mob will instead be a megafauna + + var/list/plantcolors = list("RANDOM") + var/list/grass_cache + +/datum/random_map/noise/exoplanet/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) + var/datum/level_data/LD = SSmapping.levels_by_z[tz] + if(target_turf_type == null) + target_turf_type = SSmapping.base_turf_by_z[tz] || LD.base_turf || world.turf + water_level = rand(water_level_min,water_level_max) + + //automagically adjust probs for bigger maps to help with lag + if(isnull(grass_prob)) + grass_prob = flora_prob * 2 + var/size_mod = intended_x / tlx * intended_y / tly + flora_prob *= size_mod + large_flora_prob *= size_mod + fauna_prob *= size_mod + + var/datum/planetoid_data/P = SSmapping.planetoid_data_by_z[tz] + if(istype(P)) + var/datum/planet_flora/floragen = P.flora + var/datum/fauna_generator/faunagen = P.fauna + + //Prevent spawning some flora spawner type if they aren't available + if(!length(floragen?.small_flora_types)) + flora_prob = 0 + if(!length(floragen?.big_flora_types)) + large_flora_prob = 0 + if(floragen?.plant_colors) + plantcolors = floragen.plant_colors.Copy() + if(!floragen) + grass_prob = 0 + + //Prevent spawning some fauna spawner types if they aren't available + if(!length(faunagen?.megafauna_types)) + megafauna_spawn_prob = 0 + if(!length(faunagen?.fauna_types)) + fauna_prob = 0 + ..() + + //#TODO: Doublec check why random maps are messing with the base turf at all?? + SSmapping.base_turf_by_z[tz] = land_type || SSmapping.base_turf_by_z[tz] || LD.base_turf || world.turf //Yes, it is necessary to be this thorough here + +/datum/random_map/noise/exoplanet/get_map_char(var/value) + if(water_type && noise2value(value) < water_level) + return "~" + return "[noise2value(value)]" + +/datum/random_map/noise/exoplanet/get_appropriate_path(var/value) + if(water_type && noise2value(value) < water_level) + return water_type + else + if(coast_type && value == COAST_VALUE) + return coast_type + return land_type + +/datum/random_map/noise/exoplanet/get_additional_spawns(var/value, var/turf/T) + if(T.is_wall()) + return + var/parsed_value = noise2value(value) + switch(parsed_value) + if(2 to 3) + if(prob(fauna_prob)) + spawn_fauna(T) + if(5 to 6) + if(grass_prob > 10 && prob(grass_prob)) + spawn_grass(T) + if(prob(flora_prob/3)) + spawn_flora(T) + if(7 to 9) + if(grass_prob > 1 && prob(grass_prob * 3)) + spawn_grass(T) + if(prob(flora_prob)) + spawn_flora(T) + else if(prob(large_flora_prob)) + spawn_flora(T, 1) + +/datum/random_map/noise/exoplanet/proc/spawn_fauna(var/turf/T) + if(prob(megafauna_spawn_prob)) + new /obj/abstract/landmark/exoplanet_spawn/megafauna(T) + else + new /obj/abstract/landmark/exoplanet_spawn/animal(T) + +/datum/random_map/noise/exoplanet/proc/get_grass_overlay() + var/grass_num = "[rand(1,6)]" + if(!LAZYACCESS(grass_cache, grass_num)) + var/color = pick(plantcolors) + if(color == "RANDOM") + color = get_random_colour(0,75,190) + var/image/grass = overlay_image('icons/obj/flora/greygrass.dmi', "grass_[grass_num]", color, RESET_COLOR) + grass.underlays += overlay_image('icons/obj/flora/greygrass.dmi', "grass_[grass_num]_shadow", null, RESET_COLOR) + LAZYSET(grass_cache, grass_num, grass) + return grass_cache[grass_num] + +/datum/random_map/noise/exoplanet/proc/spawn_flora(var/turf/T, var/big) + if(big) + new /obj/abstract/landmark/exoplanet_spawn/large_plant(T) + for(var/turf/neighbor as anything in RANGE_TURFS(T, 1)) + spawn_grass(neighbor) + else + new /obj/abstract/landmark/exoplanet_spawn/plant(T) + spawn_grass(T) + +/datum/random_map/noise/exoplanet/proc/spawn_grass(var/turf/T) + if(istype(T, water_type)) + return + if(locate(/obj/effect/floor_decal) in T) + return + new /obj/effect/floor_decal(T, null, null, get_grass_overlay()) + +/datum/random_map/noise/exoplanet/cleanup() + ..() + if(!water_type || !water_level || !coast_type) + return + for(var/x in 1 to limit_x - 1) + for(var/y in 1 to limit_y - 1) + var/mapcell = TRANSLATE_COORD(x,y) + if(noise2value(map[mapcell]) < water_level) + var/neighbors = get_neighbors(x, y, TRUE) + for(var/cell in neighbors) + if(noise2value(map[cell]) >= water_level) + map[cell] = COAST_VALUE + +////////////////////////////////////////////////////////////////////////////// +// Definitions +////////////////////////////////////////////////////////////////////////////// + +///Random map generator for generating underground planetary levels. +/datum/random_map/noise/exoplanet/mantle + descriptor = "planetary mantle" + smoothing_iterations = 3 + land_type = /turf/floor/rock/volcanic + water_type = /turf/floor/lava + water_level_min = 4 + water_level_max = 6 + fauna_prob = 0 + megafauna_spawn_prob = 0 + flora_prob = 0 + grass_prob = 0 + large_flora_prob = 0 + +//Random map generator to create rock walls underground +/datum/random_map/automata/cave_system/mantle + descriptor = "planetary mantle caves" + target_turf_type = /turf/floor/rock/volcanic //Only let it apply to non-lava turfs + floor_type = null + wall_type = /turf/wall/natural + +#undef TRANSLATE_COORD \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet.dm b/code/modules/maps/template_types/random_exoplanet/random_planet.dm new file mode 100644 index 000000000000..d19a9ee7625d --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_planet.dm @@ -0,0 +1,277 @@ + +/////////////////////////////////////////////////////////////////////// +// Random Planetoid Template +/////////////////////////////////////////////////////////////////////// + +/// A randomly generated "tempate" for an planet-like objects. Meant to standardize how random planets are generated so it behave like all other map templates. +/datum/map_template/planetoid/random + name = "random planetoid" + abstract_type = /datum/map_template/planetoid/random + modify_tag_vars = TRUE //Would set it to false, since we're generating everything on the fly, but unit test doesn't like it + tallness = 1 //Amount of vertical z-levels to generate for this planet. + + //#TODO: This could probably be simplified down. + ///Amount of adjacent stacked z-levels to generate north of the root z-level stack. + ///Setting this to 1 for instance will generate a stack of zlevels connecting to the north of all z-levels below the root level. Tallness is same as root. + var/adjacent_levels_north = 0 + ///Amount of adjacent stacked z-levels to generate south of the root z-level stack. Tallness is same as root. + var/adjacent_levels_south = 0 + ///Amount of adjacent stacked z-levels to generate east of the root z-level stack. Tallness is same as root. + var/adjacent_levels_east = 0 + ///Amount of adjacent stacked z-levels to generate west of the root z-level stack. Tallness is same as root. + var/adjacent_levels_west = 0 + + ///A list of the same length as there are zlevels on this map(index is z level count in order). + ///Each entry is a level_data type, or null. If defined, will override the level_data_type var for the specified z-level. + var/list/prefered_level_data_per_z + + ///The type of overmap marker object to use for this planet + var/overmap_marker_type = /obj/effect/overmap/visitable/sector/planetoid + ///The index of the generated level that will be considered the planet's surface for this generated planet counting from top to bottom. + /// The surface here implies the first "solid ground" z-level from the top. + var/surface_level_index = 1 + + ///Amount of shuttle landing points to generate on the surface level of the planet. If null, none will be generated. + var/amount_shuttle_landing_points = 2 + ///The maximum shuttle "radius" for the shuttle landing points that will be generated. + var/max_shuttle_radius = 20 + + // *** Map Gen *** + ///Maximum amount of themes that can be picked for the same planet. + var/max_themes = 2 + ///List of theme types that can be picked by this planet when generating. + var/list/possible_themes + ///Bit flag of the only ruin tags that may be picked by this planet. + var/template_tags_whitelist + ///Bit flag of the ruin tags that may never be picked for this planet. + var/template_tags_blacklist + ///Maximume amount of subtemplates/ruins/sites that may be picked and spawned on the planet. + var/subtemplate_budget = 4 + ///Ruin sites map template category to use for creating ruins on this planet. + var/template_category = MAP_TEMPLATE_CATEGORY_PLANET_SITE + +/datum/map_template/planetoid/random/is_runtime_generated() + return TRUE + +/datum/map_template/planetoid/random/get_spawn_weight() + return 100 + +/datum/map_template/planetoid/random/get_template_cost() + return 1 + +///Create individual levels linked to this planet. Must be called after basic planet stuff has been generated(atmosphere, habitability, etc..) +/datum/map_template/planetoid/random/proc/generate_levels(var/datum/planetoid_data/gen_data, var/list/theme_generators) + //Setup a list of level data types to use for each new z-levels + var/list/lvl_to_build = list() + for(var/i = 1 to tallness) + lvl_to_build += LAZYACCESS(prefered_level_data_per_z, i) || level_data_type + log_debug("Planet Levels:\n\tRoot Level:[world.maxz + 1]") + + //Build root z-stack first + var/list/root_stack = build_z_stack(null, null, lvl_to_build, gen_data) + + //Build any amount of adjacent stacks at our desired cardinal directions + var/list/north_stack = build_adjacent_z_stacks(adjacent_levels_north, NORTH, root_stack, lvl_to_build, gen_data) + var/list/south_stack = build_adjacent_z_stacks(adjacent_levels_south, SOUTH, root_stack, lvl_to_build, gen_data) + var/list/east_stack = build_adjacent_z_stacks(adjacent_levels_east, EAST, root_stack, lvl_to_build, gen_data) + var/list/west_stack = build_adjacent_z_stacks(adjacent_levels_west, WEST, root_stack, lvl_to_build, gen_data) + + //Add the stacks for each cardinal directions up, avoiding null lists + . = root_stack + if(length(north_stack)) + . += north_stack + if(length(south_stack)) + . += south_stack + if(length(east_stack)) + . += east_stack + if(length(west_stack)) + . += west_stack + + log_debug("Preparing [length(.)] planet levels...") + //Generate individual levels now that the z-level structure is properly setup + for(var/datum/level_data/planetoid/LD in .) + log_debug("Setting up level [LD] ([LD.level_z]).") + //place level transition borders and etc, but skip level gen + LD.setup_level_data(TRUE) + //Apply the theme's level gen (rock walls, debris, buildings, etc..) + if(length(theme_generators)) + LD.apply_map_generators(theme_generators) //#TODO: Theme generators should probably selectively apply to levels + //Let the level apply its level-specific generators (terrain/flora/fauna/grass) + LD.generate_level() + +///Build a stack that's adjacent to the specified stack. +/datum/map_template/planetoid/random/proc/build_adjacent_z_stacks(var/amount, var/direction_from_root, var/list/adjacent_level_data, var/list/new_level_data_types, var/datum/planetoid_data/gen_data) + var/list/lvl_data = list() + if(amount < 1) + return lvl_data + lvl_data = build_z_stack(direction_from_root, adjacent_level_data, new_level_data_types, gen_data) + if(amount < 2) + return lvl_data + //If amount if bigger than 2, build another adjacent stack to us + lvl_data += build_adjacent_z_stacks(amount - 1, direction_from_root, lvl_data, new_level_data_types, gen_data) + return lvl_data + +///Create a new z-level stack that's connected to an existing z stack, on the given direction. +/datum/map_template/planetoid/random/proc/build_z_stack(var/direction_from_root, var/list/adjacent_level_data, var/list/new_level_data_types, var/datum/planetoid_data/gen_data) + . = list() + var/stack_height = length(new_level_data_types) + + //Must build levels from bottom to top for multi-z to work + for(var/i = stack_height, i >= 1, i--) + //Register the z-level to the planetoid, BEFORE the level_data runs its init code, so turfs get linked properly + SSmapping.register_planetoid_levels(world.maxz + 1, gen_data) + var/myty = new_level_data_types[i] + var/datum/level_data/LDadj = LAZYACCESS(adjacent_level_data, (stack_height - i) + 1) //stack is filled lowest level first, so we have to match in reverse + var/datum/level_data/planetoid/LDnew = SSmapping.increment_world_z_size(myty, TRUE) + + log_debug("\n\t\tLevel Z:[world.maxz], [dir_name(direction_from_root)] of z-level [LDadj?.level_z]") + + //Make sure the level connects to us if we have an adjacent level + if(LDadj) + LAZYSET(LDnew.connected_levels, LDadj.level_id, global.reverse_dir[direction_from_root]) + LAZYSET(LDadj.connected_levels, LDnew.level_id, direction_from_root) + else + //We have to manually set those, since we don't rely on level_id to get the topmost and surface level + //If we don't have an adjacent level, we're the root level stack and need to set some extra stuff + if(i == stack_height) + gen_data.set_topmost_level(LDnew) + //Make sure we mark the surface level id + if(i == surface_level_index) + gen_data.set_surface_level(LDnew) + + //Apply planet name, etc.. + LDnew.set_planetoid(gen_data) + . += LDnew + + log_debug("\n\tZ-Stack Top:[world.maxz], Direction:[dir_name(direction_from_root)]") + //Make sure the stack has its stack top object + var/obj/abstract/map_data/MD = new /obj/abstract/map_data(locate(1, 1, world.maxz), stack_height) //#TODO: maybe combine map_data with level_data? + MD.SetName("ZStack: [gen_data.name] - [.[length(.)]]") + +//The extra datum/planetoid_data/gen_data arg is only for admin spawming exoplanets, since some parameters are taken from the user +/datum/map_template/planetoid/random/load_new_z(no_changeturf = TRUE, centered = TRUE, var/datum/planetoid_data/gen_data) //centered == false should probably runtime, because it will never work properly + if(!gen_data) + gen_data = create_planetoid_instance() + + // Update our blacklist for habitability + if(gen_data.habitability_class >= HABITABILITY_BAD) + template_tags_blacklist |= TEMPLATE_TAG_HABITABLE + + //Generate some of the background stuff for our new planet + before_planet_gen(gen_data) + + //Prepare themes, and apply ruin overrides + var/new_template_whitelist = template_tags_whitelist + var/new_template_blacklist = template_tags_blacklist + var/list/theme_map_generators + for(var/datum/exoplanet_theme/T in gen_data.themes) + new_template_whitelist = T.modify_template_whitelist(new_template_whitelist) + new_template_blacklist = T.modify_template_blacklist(new_template_blacklist) + T.before_map_generation(gen_data) + + var/list/gennies = T.get_map_generators() + if(length(gennies)) //Make sure we don't add null entries if this returns nothing + LAZYADD(theme_map_generators, gennies) + + //Figure out if we generate from scratch the planet, or we're loading a pre-made map + var/list/datum/level_data/new_level_data = list() + if(length(mappaths)) + var/zbefore = world.maxz + + //Load levels from map files + ..(no_changeturf, centered) + + ///Add all the level_data from the levels we loaded, so we can sync the levels + for(var/cntz = zbefore to world.maxz) + var/datum/level_data/LD = SSmapping.levels_by_z[cntz] + ASSERT(istype(LD)) + new_level_data += LD + else + //Create levels from scratch + ///Create all needed z-levels, tell each of them to generate themselves + new_level_data = generate_levels(gen_data, theme_map_generators) + //Spawn the ruins and sites on the planet + generate_features(gen_data, new_level_data, new_template_whitelist, new_template_blacklist) + + //Notify themes we finished gen. Since some themes may not change level gen, we run it for either random or mapped planets + for(var/datum/exoplanet_theme/T in gen_data.themes) + T.after_map_generation(gen_data) + + //Setup overmap, landing positions, and all the misc things that require the planet to be fully initialized + after_planet_gen(gen_data, SSmapping.levels_by_id[gen_data.topmost_level_id], SSmapping.levels_by_id[gen_data.surface_level_id]) + + //Run the finishing touch on all loaded levels + for(var/datum/level_data/LD in new_level_data) + //This is done in parent if we have mappaths, so skip it unless we don't have any + if(!length(mappaths)) + LD.after_template_load(src) + log_game("Z-level '[LD.name]'(planetoid:'[name]') loaded at [LD.level_z]") + loaded++ + return WORLD_CENTER_TURF(world.maxz) + +/datum/map_template/planetoid/random/proc/before_planet_gen(var/datum/planetoid_data/gen_data) + //Make sure to apply theme stuff + select_themes(gen_data) + for(var/datum/exoplanet_theme/T in gen_data.themes) + T.adjust_atmosphere(gen_data) + +/datum/map_template/planetoid/random/proc/after_planet_gen(var/datum/planetoid_data/gen_data, var/datum/level_data/topmost_level_data, var/datum/level_data/surface_level_data) + //#TODO: Generate vertical z-level connections (holes/stairs/ladders)? + generate_weather(gen_data, topmost_level_data) + + generate_landing(gen_data, surface_level_data) + + //Fill in the overmap object + setup_planet_overmap(gen_data, topmost_level_data) + +///Call after map is fully generated. Setup the overmap obj to match the planet we just generated. +/datum/map_template/planetoid/random/setup_planet_overmap(var/datum/planetoid_data/gen_data, var/datum/level_data/topmost_level_data) + //Update if loaded from map, or create one if created at runtime + if(is_runtime_generated()) + gen_data.set_overmap_marker(new overmap_marker_type( + locate(topmost_level_data.level_inner_min_x, topmost_level_data.level_inner_min_y, topmost_level_data.level_z), + topmost_level_data.level_z)) + else + . = ..() + +///Make sure all levels of this planet have the weather system setup. +/datum/map_template/planetoid/random/proc/generate_weather(var/datum/planetoid_data/gen_data, var/datum/level_data/topmost_level_data) + if(!gen_data.initial_weather_state) + return + gen_data.reset_weather(gen_data.initial_weather_state) + +///Tries to place landing areas for shuttles on the surface level of the planet. Run after generation is complete to avoid bad surprises! +/datum/map_template/planetoid/random/proc/generate_landing(var/datum/planetoid_data/gen_data, var/datum/level_data/surface_level) + var/list/places + var/attempts = 10 * amount_shuttle_landing_points + var/points_left = amount_shuttle_landing_points + var/landing_radius = ceil(max_shuttle_radius / 2) + var/border_padding = landing_radius + 3 + + while(points_left) + attempts-- + var/turf/T = locate( + rand(surface_level.level_inner_min_x + border_padding, surface_level.level_inner_max_x - border_padding), + rand(surface_level.level_inner_min_y + border_padding, surface_level.level_inner_max_y - border_padding), + surface_level.level_z) + + if(!T || (T in places)) // Two landmarks on one turf is forbidden as the landmark code doesn't work with it. + continue + + if(attempts >= 0) // While we have the patience, try to find better spawn points. If out of patience, put them down wherever, so long as there are no repeats. + var/valid = 1 + var/list/block_to_check = block(T.x - landing_radius, T.y - landing_radius, T.z, T.x + landing_radius, T.y + landing_radius, T.z) + for(var/turf/check in block_to_check) + if(!istype(get_area(check), gen_data.surface_area) || check.turf_flags & TURF_FLAG_NO_POINTS_OF_INTEREST) + valid = 0 + break + if(attempts >= 10) + if(check_collision(T.loc, block_to_check)) //While we have lots of patience, ensure landability + valid = 0 + + if(!valid) + continue + + points_left-- + LAZYADD(places, T) + new /obj/effect/shuttle_landmark/automatic/clearing(T, landing_radius) diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet_areas.dm b/code/modules/maps/template_types/random_exoplanet/random_planet_areas.dm new file mode 100644 index 000000000000..6964c4dbd2f6 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_planet_areas.dm @@ -0,0 +1,33 @@ +///Windy surface +/area/exoplanet + name = "\improper Planetary surface" + ambience = list( + 'sound/effects/wind/wind_2_1.ogg', + 'sound/effects/wind/wind_2_2.ogg', + 'sound/effects/wind/wind_3_1.ogg', + 'sound/effects/wind/wind_4_1.ogg', + 'sound/effects/wind/wind_4_2.ogg', + 'sound/effects/wind/wind_5_1.ogg' + ) + always_unpowered = TRUE + area_flags = AREA_FLAG_IS_BACKGROUND | AREA_FLAG_EXTERNAL | AREA_FLAG_HIDE_FROM_HOLOMAP + is_outside = OUTSIDE_YES + +// Let's make a token effort at making the fish somewhat alien I guess. +/area/exoplanet/get_fishing_result(turf/origin, obj/item/food/bait) + . = ..() + if(ismob(.)) + var/mob/M = . + M.SetName("xeno-[M.name]") + M.set_color(get_random_colour(simple = TRUE)) + +///Spoopy undergrounds +/area/exoplanet/underground + name = "\improper Planetary mantle" + ambience = list( + 'sound/ambience/ominous1.ogg', + 'sound/ambience/ominous2.ogg', + 'sound/ambience/ominous3.ogg', + ) + area_flags = AREA_FLAG_IS_BACKGROUND | AREA_FLAG_HIDE_FROM_HOLOMAP | AREA_FLAG_ION_SHIELDED | AREA_FLAG_RAD_SHIELDED + is_outside = OUTSIDE_NO diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet_landmarks.dm b/code/modules/maps/template_types/random_exoplanet/random_planet_landmarks.dm new file mode 100644 index 000000000000..c714865f07e0 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_planet_landmarks.dm @@ -0,0 +1,69 @@ + +///Landmarks placed by random map generator +/obj/abstract/landmark/exoplanet_spawn + name = "base exoplanet spawner" + abstract_type = /obj/abstract/landmark/exoplanet_spawn + is_spawnable_type = FALSE + +/obj/abstract/landmark/exoplanet_spawn/Initialize(ml) + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/abstract/landmark/exoplanet_spawn/LateInitialize() + . = ..() + var/datum/planetoid_data/D = SSmapping.planetoid_data_by_z[z] + if(istype(D)) + do_spawn(D) + +/obj/abstract/landmark/exoplanet_spawn/proc/do_spawn(var/datum/planetoid_data/planet) + CRASH("Implement do_spawn()") + +//////////////////////////////////////////////////////////////////////////////// +// Animal Spawner Landmark +//////////////////////////////////////////////////////////////////////////////// +///Landmarks placed by random map generator +/obj/abstract/landmark/exoplanet_spawn/animal + name = "spawn exoplanet animal" + icon_state = "fauna_spawn" + +/obj/abstract/landmark/exoplanet_spawn/animal/do_spawn(datum/planetoid_data/planet) + if(!istype(planet)) + return + planet.spawn_random_fauna(get_turf(src)) + +//////////////////////////////////////////////////////////////////////////////// +// Megafauna Spawner Landmark +//////////////////////////////////////////////////////////////////////////////// +/obj/abstract/landmark/exoplanet_spawn/megafauna + name = "spawn exoplanet megafauna" + icon_state = "megafauna_spawn" + +/obj/abstract/landmark/exoplanet_spawn/megafauna/do_spawn(datum/planetoid_data/planet) + if(!istype(planet)) + return + planet.spawn_random_megafauna(get_turf(src)) + +///////////////////////////////////////////////////////////////////////////////// +// Flora Spawners Landmarks +///////////////////////////////////////////////////////////////////////////////// +// Landmarks placed by random map generator +/obj/abstract/landmark/exoplanet_spawn/plant + name = "spawn exoplanet plant" + icon_state = "flora_spawn" + +/obj/abstract/landmark/exoplanet_spawn/plant/do_spawn(var/datum/planetoid_data/planet) + if(!istype(planet) || !planet.has_flora()) + return + planet.spawn_random_small_flora(get_turf(src)) + +///////////////////////////////////////////////////////////////////////////////// +// Large Flora Spawner Landmark +///////////////////////////////////////////////////////////////////////////////// +/obj/abstract/landmark/exoplanet_spawn/large_plant + name = "spawn exoplanet large plant" + icon_state = "bigflora_spawn" + +/obj/abstract/landmark/exoplanet_spawn/large_plant/do_spawn(var/datum/planetoid_data/planet) + if(!istype(planet) || !planet.flora) + return + planet.spawn_random_big_flora(get_turf(src)) \ No newline at end of file diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet_level_data.dm b/code/modules/maps/template_types/random_exoplanet/random_planet_level_data.dm new file mode 100644 index 000000000000..8166b19f7f61 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_planet_level_data.dm @@ -0,0 +1,107 @@ +///Base level data for levels that are subordinated to a /datum/planetoid_data entry. +///A bunch of things are fetched from planet gen to stay in sync. +/datum/level_data/planetoid + level_flags = (ZLEVEL_PLAYER|ZLEVEL_SEALED) + border_filler = /turf/unsimulated/mineral + loop_turf_type = /turf/mimic_edge/transition/loop + transition_turf_type = /turf/mimic_edge/transition + use_global_exterior_ambience = FALSE + forbid_strata = null + + ///The planetoid_data datum owning this level. At definition can be set to the planetoid_id of the planetoid to link up with on creation. + ///Ideally this will eventually be the main reference for the z-level to the planet level contents are located on. So we don't need to link every single turfs to it. + var/datum/planetoid_data/parent_planetoid + +///Level data for generating surface levels on exoplanets +/datum/level_data/planetoid/exoplanet + base_area = /area/exoplanet + base_turf = /turf/floor/dirt + daycycle_id = null // will be generated + daycycle_type = /datum/daycycle/exoplanet + +///Level data for generating underground levels on exoplanets +/datum/level_data/planetoid/exoplanet/underground + base_area = /area/exoplanet/underground + base_turf = /turf/floor/rock + level_generators = list( + /datum/random_map/noise/exoplanet/mantle, + /datum/random_map/automata/cave_system/mantle, + ) + +/datum/level_data/planetoid/setup_level_data(skip_gen) + //setup level may be run post level gen, or as soon as the level_data is constructed. + if(istext(parent_planetoid)) + set_planetoid(parent_planetoid) + . = ..() + +/datum/level_data/planetoid/copy_from(datum/level_data/planetoid/old_level) + //Make sure we pass over the planetoid_data that's been assigned to our turfs for coherency's sake + if(istype(old_level) && old_level.parent_planetoid) + set_planetoid(old_level.parent_planetoid) + +/datum/level_data/planetoid/initialize_level_id() + if(level_id) + return + level_id = "planetoid_[level_z]_[sequential_id(/datum/level_data)]" + +/datum/level_data/planetoid/setup_strata() + //If no fixed strata, grab the one from the owning planetoid_data if we have any + if(!strata) + strata = parent_planetoid?.get_strata() + . = ..() + +///Make sure the planetoid we belong to knows about us and that we know about them. +/// * P: The planetoid data datum, or the planetoid id string of the planet. +/datum/level_data/planetoid/proc/set_planetoid(var/datum/planetoid_data/P) + if(istext(P)) + P = SSmapping.planetoid_data_by_id[P] + if(istype(P)) + parent_planetoid = P + SSmapping.register_planetoid_levels(level_z, P) + if(!parent_planetoid) + CRASH("Failed to set planetoid data for level '[level_id]', z:[level_z]") + + //If the planetoid_data has some pre-defined level id for top and surface levels, be sure to let it know we exist. + if(parent_planetoid.topmost_level_id == level_id) + parent_planetoid.set_topmost_level(src) + if(parent_planetoid.surface_level_id == level_id) + parent_planetoid.set_surface_level(src) + + //Apply parent's prefered bounds if we don't have any preferences + if(!level_max_width && parent_planetoid.width) + level_max_width = parent_planetoid.width + if(!level_max_height && parent_planetoid.height) + level_max_height = parent_planetoid.height + + //Refresh bounds + setup_level_bounds() + //override atmosphere + apply_planet_atmosphere(parent_planetoid) + //Try to adopt our parent planet's ambient lighting preferences + apply_planet_ambient_lighting(parent_planetoid) + //Rename the surface area if we have one yet + adapt_to_location_name(parent_planetoid.name) + +///If we're getting atmos from our parent planet, apply it. +/datum/level_data/planetoid/proc/apply_planet_atmosphere(var/datum/planetoid_data/P) + if(istype(P) && istype(P.atmosphere)) + exterior_atmosphere = P.atmosphere.Clone() + exterior_atmosphere.update_values() + exterior_atmosphere.check_tile_graphic() + +///Apply our parent planet's ambient lighting settings if we want to. +/datum/level_data/planetoid/proc/apply_planet_ambient_lighting(var/datum/planetoid_data/P) + if(!ambient_light_level) + ambient_light_level = P.surface_light_level + if(!ambient_light_color) + ambient_light_level = P.surface_light_color + +/datum/level_data/planetoid/adapt_to_location_name(location_name) + if(!ispath(base_area) || ispath(base_area, world.area)) + return + var/area/A = get_base_area_instance() + //Make sure we're not going to rename the world's base area + if(!istype(A, world.area)) + // vvvv This feels bad, should we be doing this? vvvv + global.using_map.area_purity_test_exempt_areas |= A.type //Make sure we add any of those, so unit tests calm down when we rename + A.SetName("[location_name]") diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet_subtemplates.dm b/code/modules/maps/template_types/random_exoplanet/random_planet_subtemplates.dm new file mode 100644 index 000000000000..ec100a3847a9 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_planet_subtemplates.dm @@ -0,0 +1,6 @@ +///Picks all ruins and tries to spawn them on the levels that make up the planet. +/datum/map_template/planetoid/random/proc/generate_features(var/datum/planetoid_data/gen_data, var/list/created_level_data, var/whitelist = template_tags_whitelist, var/blacklist = template_tags_blacklist) + //#TODO: Properly handle generating ruins and sites on the various levels of the planet. + var/datum/level_data/planetoid/surface_level = SSmapping.levels_by_id[gen_data.surface_level_id] + //#TODO: dimensions and area have to be handled on a per level_data basis!! + LAZYADD(gen_data.subtemplates, surface_level.spawn_subtemplates((gen_data._budget_override || subtemplate_budget), template_category, blacklist, whitelist)) diff --git a/code/modules/maps/template_types/random_exoplanet/random_planet_themes.dm b/code/modules/maps/template_types/random_exoplanet/random_planet_themes.dm new file mode 100644 index 000000000000..e2240507d243 --- /dev/null +++ b/code/modules/maps/template_types/random_exoplanet/random_planet_themes.dm @@ -0,0 +1,12 @@ +/datum/map_template/planetoid/random/proc/select_themes(var/datum/planetoid_data/gen_data) + //Apply forced theme if there's one + if(gen_data._theme_forced) + LAZYADD(gen_data.themes, new gen_data._theme_forced) + return + + var/themes_num = min(length(possible_themes), rand(1, max_themes)) + var/list/possible = possible_themes?.Copy() + for(var/i = 1 to themes_num) + var/datum/exoplanet_theme/T = pickweight(possible) + LAZYADD(gen_data.themes, new T) + possible -= T \ No newline at end of file diff --git a/code/modules/maps/template_types/ruins.dm b/code/modules/maps/template_types/ruins.dm new file mode 100644 index 000000000000..9e26f2c6212a --- /dev/null +++ b/code/modules/maps/template_types/ruins.dm @@ -0,0 +1,17 @@ +/datum/map_template/ruin + name = null + template_flags = 0 // No duplicates by default + abstract_type = /datum/map_template/ruin + var/description + var/cost = 0 + var/prefix + var/suffixes + +// Negative numbers will always be placed, with lower (negative) numbers being placed first; positive and 0 numbers will be placed randomly +/datum/map_template/ruin/get_template_cost() + return cost + +/datum/map_template/ruin/New() + for (var/suffix in suffixes) + LAZYADD(mappaths, "[prefix][suffix]") + ..() diff --git a/code/modules/maps/template_types/ruins_exoplanet.dm b/code/modules/maps/template_types/ruins_exoplanet.dm new file mode 100644 index 000000000000..d6c405132afa --- /dev/null +++ b/code/modules/maps/template_types/ruins_exoplanet.dm @@ -0,0 +1,4 @@ +/datum/map_template/ruin/exoplanet + prefix = "maps/random_ruins/exoplanet_ruins/" + template_categories = list(MAP_TEMPLATE_CATEGORY_EXOPLANET_SITE) + abstract_type = /datum/map_template/ruin/exoplanet diff --git a/code/modules/materials/_material_stack.dm b/code/modules/materials/_material_stack.dm new file mode 100644 index 000000000000..113e54a57647 --- /dev/null +++ b/code/modules/materials/_material_stack.dm @@ -0,0 +1,264 @@ +// Stacked resources. They use a material datum for a lot of inherited values. +/obj/item/stack/material + name = "material sheet" + w_class = ITEM_SIZE_LARGE + throw_speed = 3 + throw_range = 3 + max_amount = 60 + randpixel = 3 + icon = 'icons/obj/items/stacks/materials.dmi' + material = null //! Material will be set only during Initialize, or the stack is invalid. + matter = null //! As with material, these stacks should only set this in Initialize as they are abstract 'shapes' rather than discrete objects. + pickup_sound = 'sound/foley/tooldrop3.ogg' + drop_sound = 'sound/foley/tooldrop2.ogg' + singular_name = "sheet" + plural_name = "sheets" + abstract_type = /obj/item/stack/material + is_spawnable_type = FALSE // Mapped subtypes set this so they can be spawned from the verb. + material_alteration = MAT_FLAG_ALTERATION_COLOR + var/can_be_pulverized = FALSE + var/can_be_reinforced = FALSE + +/obj/item/stack/material/Initialize(mapload, var/amount, var/_material, var/_reinf_material) + + if(!_reinf_material) + _reinf_material = reinf_material + + if(_reinf_material) + reinf_material = GET_DECL(_reinf_material) + if(!istype(reinf_material)) + reinf_material = null + + . = ..(mapload, amount, _material) + if(!istype(material)) + PRINT_STACK_TRACE("[src] ([x],[y],[z]) was deleted because it didn't have a valid material set('[material]')!") + return INITIALIZE_HINT_QDEL + + base_state = icon_state + if(material.conductive) + obj_flags |= OBJ_FLAG_CONDUCTIBLE + else + obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) + //Sound setup + if(material.sound_manipulate) + pickup_sound = material.sound_manipulate + if(material.sound_dropped) + drop_sound = material.sound_dropped + update_strings() + update_icon() + +/obj/item/stack/material/get_codex_value() + return (material && !material.hidden_from_codex) ? "[lowertext(material.codex_name || material.name)] (substance)" : ..() + +/obj/item/stack/material/get_reinforced_material() + return reinf_material + +/obj/item/stack/material/create_matter() + // Set our reinf material in the matter list so that the base + // stack material population runs properly and includes it. + if(istype(reinf_material)) + LAZYSET(matter, reinf_material.type, MATTER_AMOUNT_REINFORCEMENT) // No matter_multiplier as this is applied in parent. + ..() + +/obj/item/stack/material/proc/special_crafting_check() + return TRUE + +/obj/item/stack/material/update_name() + update_strings() + +/obj/item/stack/material/proc/update_strings() + var/prefix_name = name_modifier ? "[name_modifier] " : "" + if(amount>1) + SetName("[prefix_name][material.use_name] [plural_name]") + desc = "A stack of [prefix_name][material.use_name] [plural_name]." + gender = PLURAL + else + SetName("[prefix_name][material.use_name] [singular_name]") + desc = "\A [prefix_name][singular_name] of [material.use_name]." + gender = NEUTER + if(reinf_material) + SetName("reinforced [name]") + desc = "[desc]\nIt is reinforced with the [reinf_material.use_name] lattice." + + if(material.stack_origin_tech) + origin_tech = material.stack_origin_tech + else if(reinf_material && reinf_material.stack_origin_tech) + origin_tech = reinf_material.stack_origin_tech + else + origin_tech = initial(origin_tech) + +/obj/item/stack/material/clear_matter() + ..() + reinf_material = null + matter_per_piece = null + +/obj/item/stack/material/proc/is_same(obj/item/stack/material/M) + if(!istype(M)) + return FALSE + if(matter_multiplier != M.matter_multiplier) + return FALSE + if(material.type != M.material.type) + return FALSE + if((reinf_material && reinf_material.type) != (M.reinf_material && M.reinf_material.type)) + return FALSE + return TRUE + +/obj/item/stack/material/transfer_to(obj/item/stack/material/M, var/tamount=null) + if(!is_same(M)) + return 0 + . = ..(M,tamount,1) + +/obj/item/stack/material/copy_from(var/obj/item/stack/material/other) + ..() + if(istype(other)) + material = other.material + reinf_material = other.reinf_material + update_strings() + update_icon() + +/obj/item/stack/material/proc/get_stack_conversion_dictionary() + return + +/obj/item/stack/material/proc/reinforce_with(var/mob/user, var/obj/item/stack/material/used_stack, var/use_sheets = 1) + if(reinf_material) // already reinforced + return FALSE + var/decl/material/our_material = get_material() + if(!used_stack.can_use(use_sheets)) + to_chat(user, SPAN_WARNING("You need at least one [used_stack.singular_name] to reinforce [src].")) + return FALSE + + var/decl/material/reinf_mat = used_stack.get_material() + if(reinf_mat.integrity <= our_material.integrity || reinf_mat.is_brittle()) + to_chat(user, SPAN_WARNING("The [reinf_mat.solid_name] is too structurally weak to reinforce \the [src].")) + return FALSE + + if(!can_use(use_sheets)) + to_chat(user, SPAN_WARNING("You need at least [use_sheets] [use_sheets == 1 ? singular_name : plural_name] for reinforcement with \the [used_stack].")) + return FALSE + + to_chat(user, SPAN_NOTICE("You reinforce \the [src] with [reinf_mat.solid_name].")) + used_stack.use(use_sheets) + var/obj/item/stack/material/new_stack = split(1) + new_stack.reinf_material = reinf_mat + new_stack.update_strings() + new_stack.update_icon() + if(!QDELETED(src)) + new_stack.dropInto(get_turf(src)) + else if(user) + new_stack.dropInto(get_turf(user)) + else + new_stack.dropInto(get_turf(used_stack)) + new_stack.add_to_stacks(user, TRUE) + return TRUE + +/obj/item/stack/material/attackby(var/obj/item/used_item, var/mob/user) + + if(can_be_reinforced && istype(used_item, /obj/item/stack/material)) + if(is_same(used_item)) + return ..() + if(!reinf_material) + reinforce_with(user, used_item) + return TRUE + + // TODO: convert to converts_into entry. + if(can_be_pulverized && IS_HAMMER(used_item) && material?.hardness >= MAT_VALUE_RIGID && user.check_intent(I_FLAG_HARM)) + + if(used_item.material?.hardness < material.hardness) + to_chat(user, SPAN_WARNING("\The [used_item] is not hard enough to pulverize [material.solid_name].")) + return TRUE + + var/converting = clamp(get_amount(), 0, 5) + if(converting && used_item.do_tool_interaction(TOOL_HAMMER, user, src, 1 SECOND, "pulverizing", "pulverizing", set_cooldown = TRUE) && !QDELETED(src) && get_amount() >= converting) + // TODO: make a gravel type? + // TODO: pass actual stone material to gravel? + new /obj/item/stack/material/ore/handful/sand(get_turf(user), converting) + user.visible_message("\The [user] pulverizes [converting == 1 ? "a [singular_name]" : "some [plural_name]"] with \the [used_item].") + use(converting) + + return TRUE + + if(reinf_material?.default_solid_form && IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.isOn() && welder.get_fuel() > 2 && use(2)) + welder.weld(2, user) + to_chat(user, SPAN_NOTICE("You recover some [reinf_material.use_name] from \the [src].")) + reinf_material.create_object(get_turf(user), 1) + return TRUE + + var/list/can_be_converted_into = get_stack_conversion_dictionary() + if(length(can_be_converted_into) && !user.check_intent(I_FLAG_HARM)) + + var/convert_tool + var/obj/item/stack/convert_type + for(var/tool_type in can_be_converted_into) + if(IS_TOOL(used_item, tool_type)) + convert_tool = tool_type + convert_type = can_be_converted_into[tool_type] + break + + if(convert_type) + + var/product_per_sheet = matter_multiplier / initial(convert_type.matter_multiplier) + var/minimum_per_one_product = ceil(1 / product_per_sheet) + + if(get_amount() < minimum_per_one_product) + to_chat(user, SPAN_WARNING("You will need [minimum_per_one_product] [minimum_per_one_product == 1 ? singular_name : plural_name] to produce [product_per_sheet] [product_per_sheet == 1 ? initial(convert_type.singular_name) : initial(convert_type.plural_name)].")) + else if(used_item.do_tool_interaction(convert_tool, user, src, 1 SECOND, set_cooldown = TRUE) && !QDELETED(src) && get_amount() >= minimum_per_one_product) + var/obj/item/stack/product = new convert_type(loc, ceil(product_per_sheet), material?.type, reinf_material?.type) + product.dropInto(loc) + use(minimum_per_one_product) + if(product.add_to_stacks(user, TRUE)) + user.put_in_hands(product) + return TRUE + + return ..() + +/obj/item/stack/material/get_max_drying_wetness() + return 120 + +/obj/item/stack/material/on_update_icon() + . = ..() + if(material) + alpha = 100 + max(1, amount/25)*(material.opacity * 255) + else + alpha = initial(alpha) + update_state_from_amount() + if(drying_wetness > 0) + var/image/I = new(icon, icon_state) + I.appearance_flags |= RESET_COLOR | RESET_ALPHA + I.alpha = 255 * (get_max_drying_wetness() / drying_wetness) + I.color = COLOR_GRAY40 + I.blend_mode = BLEND_MULTIPLY + add_overlay(I) + +/obj/item/stack/material/ProcessAtomTemperature() + . = ..() + if(!QDELETED(src)) + update_strings() + +/obj/item/stack/material/proc/update_state_from_amount() + if(max_icon_state && amount == max_amount) + icon_state = max_icon_state + else if(plural_icon_state && amount > 2) + icon_state = plural_icon_state + else + icon_state = base_state + +/obj/item/stack/material/get_string_for_amount(amount) + . = "[reinf_material ? "reinforced " : null][material.use_name]" + if(amount == 1) + . += " [singular_name]" + if(gender == PLURAL) + return "some [.]" + return indefinite_article ? "[indefinite_article] [.]" : ADD_ARTICLE(.) + return "[amount] [.] [plural_name]" + +/obj/item/stack/material/proc/matter_units_to_sheets(used) + if(!material || get_reinforced_material()) + return 0 + return ceil(used / matter_per_piece[material.type]) + +// Horrible solution to heat damage for atoms causing logs and +// fuel to vanish. Replace this when the atom fire system exists. +/obj/item/stack/material/should_take_heat_damage(datum/gas_mixture/air, exposed_temperature) + return istype(loc, /obj/structure/fire_source) ? FALSE : ..() diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm index 809134b0b774..ada5e9a86c73 100644 --- a/code/modules/materials/_materials.dm +++ b/code/modules/materials/_materials.dm @@ -1,122 +1,157 @@ -/obj/effect/gas_overlay - name = "gas" - desc = "You shouldn't be clicking this." - icon = 'icons/effects/tile_effects.dmi' - icon_state = "generic" - layer = FIRE_LAYER - appearance_flags = RESET_COLOR - mouse_opacity = 0 - var/decl/material/material - -/obj/effect/gas_overlay/proc/update_alpha_animation(var/new_alpha) - animate(src, alpha = new_alpha) - alpha = new_alpha - animate(src, alpha = 0.8 * new_alpha, time = 10, easing = SINE_EASING | EASE_OUT, loop = -1) - animate(alpha = new_alpha, time = 10, easing = SINE_EASING | EASE_IN, loop = -1) - -/obj/effect/gas_overlay/Initialize(mapload, gas) - . = ..() - material = decls_repository.get_decl(gas) - if(!istype(material)) - return INITIALIZE_HINT_QDEL - if(material.gas_tile_overlay) - icon_state = material.gas_tile_overlay - color = material.color +var/global/alist/_filterable_mats_alist +var/global/list/_filterable_mats_list + +/proc/get_filterable_material_types(as_list = FALSE) + + if(isnull(_filterable_mats_alist)) + _filterable_mats_alist = alist() + for(var/decl/material/mat in decls_repository.get_decls_of_subtype_unassociated(/decl/material)) + if(!isnull(mat.boiling_point)) + _filterable_mats_alist[mat.type] = mat + + if(as_list) + if(isnull(_filterable_mats_list)) + _filterable_mats_list = alist2list(_filterable_mats_alist) + return _filterable_mats_list + return _filterable_mats_alist /* - MATERIAL DATUMS + MATERIAL DECLS This data is used by various parts of the game for basic physical properties and behaviors of the metals/materials used for constructing many objects. Each var is commented and should be pretty self-explanatory but the various object types may have their own documentation. - - PATHS THAT USE DATUMS - turf/simulated/wall - obj/item - obj/structure/barricade - obj/structure/table - - VALID ICONS - WALLS - stone - metal - solid - cult - DOORS - stone - metal - resin - wood */ -//Returns the material the object is made of, if applicable. -//Will we ever need to return more than one value here? Or should we just return the "dominant" material. -/obj/proc/get_material() - return - -//mostly for convenience -/obj/proc/get_material_type() - var/decl/material/mat = get_material() - . = mat && mat.type +/// A lookup table of material decls by their gas symbol, used for selection in atmos filters. +var/global/list/materials_by_gas_symbol = list() // Material definition and procs follow. /decl/material - var/name // Prettier name for display. + + abstract_type = /decl/material + decl_flags = DECL_FLAG_MANDATORY_UID + + var/name // Prettier name for display. + var/codex_name // Override for the codex article name. var/adjective_name var/solid_name var/gas_name var/liquid_name + var/solution_name // Name for the material in solution. var/use_name - var/wall_name = "wall" // Name given to walls of this material - var/flags = 0 // Various status modifiers. - var/sheet_singular_name = "sheet" - var/sheet_plural_name = "sheets" + var/wall_name = "wall" // Name given to walls of this material + var/flags = 0 // Various status modifiers. var/hidden_from_codex var/lore_text var/mechanics_text var/antag_text + var/default_solid_form = /obj/item/stack/material/sheet + + var/soup_hot_desc = "simmering" + + var/affect_blood_on_ingest = 0.5 + var/affect_blood_on_inhale = 0.75 var/narcosis = 0 // Not a great word for it. Constant for causing mild confusion when ingested. var/toxicity = 0 // Organ damage from ingestion. var/toxicity_targets_organ // Bypass liver/kidneys when ingested, harm this organ directly (using BP_FOO defines). + var/can_backfill_floor_type + // Shards/tables/structures - var/shard_type = SHARD_SHRAPNEL // Path of debris object. + var/shard_type = /obj/item/shard + var/shard_name = SHARD_SHRAPNEL as text // Path of debris object. var/shard_icon // Related to above. var/shard_can_repair = 1 // Can shards be turned into sheets with a welder? - var/list/recipes // Holder for all recipes usable with a sheet of this material. var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding. + var/destruction_sound = "fracture" // As above, but the sound that plays. // Icons - var/icon_base = "metal" // Wall and table base icon tag. See header. + var/icon_base = 'icons/turf/walls/solid.dmi' + var/icon_base_natural = 'icons/turf/walls/natural.dmi' + /// Either the icon used for reinforcement, or a list of icons to pick from. + var/icon_reinf = 'icons/turf/walls/reinforced_metal.dmi' + var/wall_flags = 0 + var/list/wall_blend_icons = list() // Which wall icon types walls of this material type will consider blending with. Assoc list (icon path = TRUE/FALSE) + var/use_reinf_state = "full" + var/door_icon_base = "metal" // Door base icon tag. See header. - var/icon_reinf = "reinf_metal" // Overlay used var/table_icon_base = "metal" - var/table_reinf = "reinf_metal" - var/list/stack_origin_tech = "{'materials':1}" // Research level for stacks. + var/table_icon_reinforced = "reinf_metal" + + // TODO: Refactor these to just apply a generic material overlay (e.g. wood grain) instead of entirely-separate icon files? + // Alternatively, find some other way for icon variation based on material. + // You can't do it by having separate states in the base icons, + // because then modpacked materials can't add new states, + // and what if we really really want a special nullglass pew sprite or something? + var/bench_icon = 'icons/obj/structures/furniture/bench.dmi' + var/pew_icon = 'icons/obj/structures/furniture/pew.dmi' + var/slatted_seat_icon = 'icons/obj/structures/furniture/chair_slatted.dmi' + var/backed_chair_icon = 'icons/obj/structures/furniture/chair_backed.dmi' + + var/list/stack_origin_tech = @'{"materials":1}' // Research level for stacks. // Attributes - var/cut_delay = 0 // Delay in ticks when cutting through this wall. - var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings. - var/ignition_point // K, point at which the material catches on fire. - var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this - var/boiling_point = 3000 // K, point that material will become a gas. - var/brute_armor = 2 // Brute damage to a wall is divided by this value if the wall is reinforced by this material. - var/burn_armor // Same as above, but for Burn damage type. If blank brute_armor's value is used. - var/integrity = 150 // General-use HP value for products. - var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors. - var/explosion_resistance = 5 // Only used by walls currently. - var/conductive = 1 // Objects with this var add CONDUCTS to flags on spawn. + /// Does this material float to the top of liquids, allowing it to be skimmed off? Specific to cream at time of writing. + var/skimmable = FALSE + /// How rare is this material in exoplanet xenoflora? + var/exoplanet_rarity_plant = MAT_RARITY_MUNDANE + /// How rare is this material in exoplanet atmospheres? + var/exoplanet_rarity_gas = MAT_RARITY_MUNDANE + /// Delay in ticks when cutting through this wall. + var/cut_delay = 0 + /// Radiation var. Used in wall and object processing to irradiate surroundings. + var/radioactivity + /// K, point at which the material catches on fire. + var/ignition_point + /// K, walls will take damage if they're next to a fire hotter than this + var/melting_point = 1800 + /// K, point that material will become a gas. + var/boiling_point = 3000 + /// Set automatically if null based on ignition, boiling and melting point + var/temperature_damage_threshold + /// kJ/kg, enthalpy of vaporization + var/latent_heat = 7000 + /// kg/mol + var/molar_mass = 0.06 + /// g/ml + var/liquid_density = 0.997 + /// g/ml + var/solid_density = 0.9168 + /// Brute damage to a wall is divided by this value if the wall is reinforced by this material. + var/brute_armor = 2 + /// Same as above, but for Burn damage type. If blank brute_armor's value is used. + var/burn_armor + /// General-use HP value for products. + var/integrity = 150 + /// Is the material transparent? 0.5< makes transparent walls/doors. + var/opacity = 1.0 + /// Only used by walls currently. + var/explosion_resistance = 5 + /// Objects with this var add CONDUCTS to flags on spawn. + var/conductive = 1 + /// Does this material glow? var/luminescence - var/list/alloy_materials // If set, material can be produced via alloying these materials in these amounts. + /// Used for checking if a material can function as a wall support. var/wall_support_value = 30 + /// Ore generation constant for rare materials. var/sparse_material_weight + /// Ore generation constant for common materials. var/rich_material_weight + /// How transparent can fluids be? + var/min_fluid_opacity = FLUID_MIN_ALPHA + /// How opaque can fluids be? + var/max_fluid_opacity = FLUID_MAX_ALPHA + /// Point at which the fluid will proc turf interaction logic. Workaround for mops being ruined forever by 1u of anything else being added. + var/turf_touch_threshold = FLUID_QDEL_POINT + /// Whether or not billets of this material will glow with heat. + var/glows_with_heat = FALSE // Damage values. - var/hardness = MAT_VALUE_HARD // Prob of wall destruction by hulk, used for edge damage in weapons. - var/reflectiveness = MAT_VALUE_DULL - - var/weight = MAT_VALUE_NORMAL // Determines blunt damage/throwforce for weapons. + var/hardness = MAT_VALUE_HARD // Used for edge damage in weapons. + var/weight = MAT_VALUE_NORMAL // Determines blunt damage/throw force for weapons. + var/reflectiveness = MAT_VALUE_DULL // How effective is this at reflecting light? + var/ferrous = FALSE // Can be used as a striker for firemaking. // Noise when someone is faceplanted onto a table made of this material. var/tableslam_noise = 'sound/weapons/tablehit1.ogg' @@ -124,20 +159,18 @@ var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg' // Noise made when you hit structure made of this material. var/hitsound = 'sound/weapons/genhit.ogg' - // Path to resulting stacktype. Todo remove need for this. - var/stack_type = /obj/item/stack/material/generic // Wallrot crumble message. var/rotting_touch_message = "crumbles under your touch" + /// When a stack recipe doesn't specify a skill to use, use this skill. + var/crafting_skill = SKILL_CONSTRUCTION // Modifies skill checks when constructing with this material. var/construction_difficulty = MAT_VALUE_EASY_DIY // Determines what is used to remove or dismantle this material. var/removed_by_welder // Mining behavior. - var/alloy_product var/ore_name var/ore_desc - var/ore_smelts_to var/ore_compresses_to var/ore_result_amount var/ore_spread_chance @@ -145,6 +178,7 @@ var/ore_icon_overlay var/ore_type_value var/ore_data_value + var/ore_type = /obj/item/stack/material/ore var/value = 1 @@ -153,40 +187,49 @@ // Gas behavior. var/gas_overlay_limit - var/gas_burn_product - var/gas_specific_heat - var/gas_molar_mass + var/gas_specific_heat = 20 // J/(mol*K) var/gas_symbol_html var/gas_symbol var/gas_flags = 0 var/gas_tile_overlay = "generic" - var/gas_condensation_point = 0 + var/gas_condensation_point = null var/gas_metabolically_inert = FALSE // If false, material will move into the bloodstream when breathed. // Armor values generated from properties var/list/basic_armor var/armor_degradation_speed + // Allergen values, used by /mob/living and /datum/reagents + /// What allergens are present on this material? + var/allergen_flags = ALLERGEN_NONE + var/allergen_factor = 2 + // Copied reagent values. Todo: integrate. - var/taste_description = "old rotten bandaids" + var/taste_description var/taste_mult = 1 //how this taste compares to others. Higher values means it is more noticable var/metabolism = REM // This would be 0.2 normally var/ingest_met = 0 var/touch_met = 0 + var/inhale_met = 0 var/overdose = 0 var/scannable = 0 // Shows up on health analyzers. var/color = COLOR_BEIGE + // How much variance in color do objects of this material have, in fraction of maximum brightness/hue. + var/color_variance = 0.04 var/color_weight = 1 var/cocktail_ingredient var/defoliant var/fruit_descriptor // String added to fruit desc if this chemical is present. + /// Does this reagent have an antibiotic effect (helping with infections)? + var/antibiotic_strength = 0 var/dirtiness = DIRTINESS_NEUTRAL // How dirty turfs are after being exposed to this material. Negative values cause a cleaning/sterilizing effect. + var/decontamination_dose = 0 // Amount required for a decontamination effect, if any. var/solvent_power = MAT_SOLVENT_NONE var/solvent_melt_dose = 0 var/solvent_max_damage = 0 - var/slipperiness + var/slipperiness = 0 + var/slippery_amount = 1 var/euphoriant // If set, ingesting/injecting this material will cause the rainbow high overlay/behavior. - var/euphoriant_max // Set a cap on how much drugged state the material can cause. var/glass_icon = DRINK_ICON_DEFAULT var/glass_name = "something" @@ -203,374 +246,293 @@ var/chilling_message = "crackles and freezes!" var/chilling_sound = 'sound/effects/bubbles.ogg' var/list/chilling_products - var/bypass_cooling_products_for_root_type var/heating_point var/heating_message = "begins to boil!" var/heating_sound = 'sound/effects/bubbles.ogg' var/list/heating_products - var/bypass_heating_products_for_root_type - - var/fuel_value = 0 - + var/accelerant_value = FUEL_VALUE_NONE + var/burn_temperature = 100 CELSIUS + var/burn_product var/list/vapor_products // If splashed, releases these gasses in these proportions. // TODO add to unit test after solvent PR is merged - + /// A divisor applied to volume when calculating explosive force (lower is stronger) - if null, reagent is no explosive + var/explosive_power_divisor var/scent //refer to _scent.dm var/scent_intensity = /decl/scent_intensity/normal - var/scent_descriptor = SCENT_DESC_SMELL + var/scent_descriptor = "smell" var/scent_range = 1 -// Placeholders for light tiles and rglass. -/decl/material/proc/reinforce(var/mob/user, var/obj/item/stack/material/used_stack, var/obj/item/stack/material/target_stack) - if(!used_stack.can_use(1)) - to_chat(user, "You need need at least one [used_stack.singular_name] to reinforce [target_stack].") - return + var/list/neutron_interactions // Associative List of potential neutron interactions for the material to undergo, corresponding to the ideal + // neutron energy for that reaction to occur. - var/needed_sheets = 2 * used_stack.matter_multiplier - if(!target_stack.can_use(needed_sheets)) - to_chat(user, "You need need at least [needed_sheets] [target_stack.plural_name] for reinforcement with [used_stack].") - return + var/neutron_cross_section // How broad the neutron interaction curve is, independent of temperature. Materials that are harder to react with will have lower values. + var/absorption_products // Transmutes into these reagents following neutron absorption and/or subsequent beta decay. Generally forms heavier reagents. + var/fission_products // Transmutes into these reagents following fission. Forms lighter reagents, and a lot of heat. + var/neutron_production // How many neutrons are created per unit per fission event. + var/neutron_absorption // How many neutrons are absorbed per unit per absorption event. + var/fission_heat // How much thermal energy per unit per fission event this material releases. + var/fission_energy // Energy of neutrons released by fission. + var/moderation_target // The 'target' neutron energy value that the fission environment shifts towards after a moderation event. + // Neutron moderators can only slow down neutrons. - var/decl/material/reinf_mat = used_stack.material - if(reinf_mat.integrity <= integrity || reinf_mat.is_brittle()) - to_chat(user, "The [reinf_mat.solid_name] is too structurally weak to reinforce the [name].") - return + var/sound_manipulate //Default sound something like a material stack made of this material does when picked up + var/sound_dropped //Default sound something like a material stack made of this material does when hitting the ground or placed down - to_chat(user, "You reinforce the [target_stack] with the [reinf_mat.solid_name].") - used_stack.use(1) - var/obj/item/stack/material/S = target_stack.split(needed_sheets) - S.reinf_material = reinf_mat - S.update_strings() - S.update_icon() - S.dropInto(target_stack.loc) + var/holographic // Set to true if this material is fake/visual only. + /// Does high temperature baking change this material into something else? + var/bakes_into_material + var/bakes_into_at_temperature -// Make sure we have a use name and shard icon even if they aren't explicitly set. -/decl/material/Initialize() - . = ..() - if(!use_name) - use_name = name - if(!liquid_name) - liquid_name = name - if(!solid_name) - solid_name = name - if(!gas_name) - gas_name = name - if(!adjective_name) - adjective_name = name - if(!shard_icon) - shard_icon = shard_type - if(!burn_armor) - burn_armor = brute_armor + /// If set to a material type, stacks of this material will be able to be tanned on a drying rack after being wetted to convert them to tans_to. + var/tans_to + /// A multiplier for this material when used in fishing bait. + var/fishing_bait_value = 0 + /// A relative value used only by fishing line at time of commit. + var/tensile_strength = 0 - generate_armor_values() - var/list/cocktails = decls_repository.get_decls_of_subtype(/decl/cocktail) - for(var/ctype in cocktails) - var/decl/cocktail/cocktail = cocktails[ctype] - if(type in cocktail.ratios) - cocktail_ingredient = TRUE - break + /// What form does this take if dug out of the ground, if any? + var/dug_drop_type -// Return the matter comprising this material. -/decl/material/proc/get_matter() - var/list/temp_matter = list() - temp_matter[type] = SHEET_MATERIAL_AMOUNT - return temp_matter + /// Can objects containing this material be used for textile spinning? + var/has_textile_fibers = FALSE -// Weapons handle applying a divisor for this value locally. -/decl/material/proc/get_blunt_damage() - return weight //todo + /// Whether or not turfs made of this material can support plants. + var/tillable = FALSE -// As above. -/decl/material/proc/get_edge_damage() - return hardness //todo + var/compost_value = 0 -/decl/material/proc/get_attack_cooldown() - if(weight <= MAT_VALUE_LIGHT) - return FAST_WEAPON_COOLDOWN - if(weight >= MAT_VALUE_HEAVY) - return SLOW_WEAPON_COOLDOWN - return DEFAULT_WEAPON_COOLDOWN + /// Nutrition values! + var/nutriment_factor = 0 // Per removed amount each tick + var/hydration_factor = 0 // Per removed amount each tick + var/injectable_nutrition = FALSE + var/reagent_overlay + var/reagent_overlay_base = "reagent_base" + + /// Set to a type to indicate that a type with a matching milestone type should be used as a reference point for burn temperatures. + var/temperature_burn_milestone_material + + /// Semi-temporary fix to issues with soup/tea boil-off - only set to TRUE on water and ethanol at time of commit. + var/can_boil_to_gas = FALSE + /// How much of this boils away per evaporation run? + var/boil_evaporation_per_run = 1 -// Snowflakey, only checked for alien doors at the moment. -/decl/material/proc/can_open_material_door(var/mob/living/user) - return 1 + /// What verb is used when describing a colored piece of this material? e.g. 'dyed' or 'painted' + /// If an item has a null paint_verb, it automatically sets it based on material. + var/paint_verb = "painted" -// Currently used for weapons and objects made of uranium to irradiate things. -/decl/material/proc/products_need_process() - return (radioactivity>0) //todo + /// Chance of a natural wall made of this material dropping a gemstone, if the gemstone_types list is populated. + var/gemstone_chance = 5 + /// Assoc weighted list of gemstone material types to weighting. + var/list/gemstone_types + + var/forgable = FALSE // Can this material be forged in bar/billet form? // Used by walls when qdel()ing to avoid neighbor merging. /decl/material/placeholder name = "placeholder" + uid = "mat_placeholder" hidden_from_codex = TRUE + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + holographic = TRUE -// Places a girder object when a wall is dismantled, also applies reinforced material. -/decl/material/proc/place_dismantled_girder(var/turf/target, var/decl/material/reinf_material) - new /obj/structure/girder(target, type, reinf_material && reinf_material.type) - -// General wall debris product placement. -// Not particularly necessary aside from snowflakey cult girders. -/decl/material/proc/place_dismantled_product(var/turf/target,var/is_devastated) - place_sheet(target, is_devastated ? 1 : 2) +// Make sure we have a use name and shard icon even if they aren't explicitly set. +/decl/material/Initialize() + . = ..() + if(!name) + CRASH("Unnamed material /decl tried to initialize.") + // Default use_name to name if unset. + use_name ||= name + // Default the other state names to use_name, so that if it's overridden, we use that instead of base name. + liquid_name ||= use_name + solid_name ||= use_name + gas_name ||= use_name + // Use solid_name for adjective_name so that we get "ice bracelet" instead of "water bracelet" for things made of water below 0C. + adjective_name ||= solid_name + adjective_name ||= use_name + + // Null/clear a bunch of physical vars as this material is fake. + if(holographic) + temperature_burn_milestone_material = null + can_boil_to_gas = FALSE + shard_name = SHARD_NONE + shard_type = null + conductive = 0 + hidden_from_codex = TRUE + value = 0 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + dissolves_into = null + dissolves_in = MAT_SOLVENT_IMMUNE + solvent_power = MAT_SOLVENT_NONE + heating_products = null + chilling_products = null + heating_point = null + chilling_point = null + solvent_melt_dose = 0 + solvent_max_damage = 0 + slipperiness = 0 + bakes_into_at_temperature = null + ignition_point = null + melting_point = null + boiling_point = null + temperature_damage_threshold = INFINITY + accelerant_value = FUEL_VALUE_NONE + burn_product = null + vapor_products = null + compost_value = 0 + forgable = FALSE + else if(isnull(temperature_damage_threshold)) + var/new_temperature_damage_threshold = max(melting_point, boiling_point, heating_point) + // Don't let the threshold be lower than the ignition point. + if(isnull(new_temperature_damage_threshold) && !isnull(ignition_point)) + temperature_damage_threshold = ignition_point + else if(isnull(ignition_point) || (new_temperature_damage_threshold > ignition_point)) + temperature_damage_threshold = new_temperature_damage_threshold -// Debris product. Used ALL THE TIME. -/decl/material/proc/place_sheet(var/turf/target, var/amount = 1) - return stack_type ? new stack_type(target, amount, type) : null + if(!shard_icon) + shard_icon = shard_name + if(!burn_armor) + burn_armor = brute_armor + if(!gas_symbol) + gas_symbol = "[name]_[sequential_id(abstract_type)]" + if(!gas_symbol_html) + gas_symbol_html = gas_symbol + global.materials_by_gas_symbol[gas_symbol] = type + generate_armor_values() -// As above. -/decl/material/proc/place_shard(var/turf/target) - if(shard_type) - return new /obj/item/shard(target, type) + if(!holographic) + var/list/cocktails = decls_repository.get_decls_of_subtype(/decl/cocktail) + for(var/ctype in cocktails) + var/decl/cocktail/cocktail = cocktails[ctype] + if(type in cocktail.ratios) + cocktail_ingredient = TRUE + break -// Used by walls and weapons to determine if they break or not. -/decl/material/proc/is_brittle() - return !!(flags & MAT_FLAG_BRITTLE) +/decl/material/validate() + . = ..() -/decl/material/proc/combustion_effect(var/turf/T, var/temperature) - return + if(!crafting_skill) + . += "no construction skill set" + else if(!isnull(construction_difficulty)) + var/decl/skill/used_skill = GET_DECL(crafting_skill) + if(!istype(used_skill)) + . += "invalid skill decl [used_skill]" + else if(length(used_skill.levels) < construction_difficulty) + . += "required skill [used_skill] is missing skill level [json_encode(construction_difficulty)]" + + if(isnull(construction_difficulty)) + . += "no construction difficulty set" + + if(!isnull(bakes_into_at_temperature)) + // all of these variables should be above our baking temperature, because we assume only solids not currently on fire can bake + // modify this if a material ever needs to bake while liquid or gaseous + var/list/temperatures = list("melting point" = melting_point, "boiling point" = boiling_point, "heating point" = heating_point, "ignition point" = ignition_point) + for(var/temperature in temperatures) + if(isnull(temperatures[temperature])) + continue + if(temperatures[temperature] <= bakes_into_at_temperature) + . += "baking point is set but [temperature] is lower or equal to it" + + // this is a little overengineered for only two values... + // but requiring heating_point > boiling_point caused a bunch of issues + // at least it's easy to add more if we want to enforce order more + var/list/transition_temperatures_ascending = list("melting point" = melting_point, "boiling point" = boiling_point) + var/max_key // if not null, this is a key from the above list + for(var/temperature_key in transition_temperatures_ascending) + var/temperature = transition_temperatures_ascending[temperature_key] + if(isnull(temperature)) + continue + if(!isnull(max_key) && temperature <= transition_temperatures_ascending[max_key]) + var/expected_temp = transition_temperatures_ascending[max_key] + . += "transition temperature [temperature_key] ([temperature]K, [temperature - T0C]C) is colder than [max_key], expected >[expected_temp]K ([expected_temp - T0C]C)!" + else + max_key = temperature_key + + if(accelerant_value > FUEL_VALUE_NONE && isnull(ignition_point)) + . += "accelerant value larger than zero but null ignition point" + if(!isnull(ignition_point) && accelerant_value <= FUEL_VALUE_NONE) + . += "accelerant value below zero but non-null ignition point" + if(length(dissolves_into) && isnull(dissolves_in)) + . += "dissolves_into set but dissolves_in is undefined" + if(length(heating_products) && isnull(heating_point)) + . += "heating_products set but heating_point is undefined" + if(length(chilling_products) && isnull(chilling_point)) + . += "chilling_products set but chilling_point is undefined" + + var/list/checking = list( + "dissolves" = dissolves_into, + "heats" = heating_products, + "chills" = chilling_products + ) + for(var/field in checking) + var/list/checking_list = checking[field] + if(length(checking_list)) + var/total = 0 + for(var/chem in checking_list) + total += checking_list[chem] + if(total != 1) + . += "[field] adds up to [total] (should be 1)" + + if(dissolves_in == MAT_SOLVENT_IMMUNE && LAZYLEN(dissolves_into)) + . += "material is immune to solvents, but has dissolves_into products." + + if(!paint_verb) + . += "material does not have a paint_verb set" + else if(!istext(paint_verb)) + . += "material has a non-text paint_verb value" + + for(var/i = 0 to 7) + if(icon_base) + if(!check_state_in_icon("[i]", icon_base)) + . += "'[icon_base]' - missing directional base icon state '[i]'" + if(!check_state_in_icon("other[i]", icon_base)) + . += "'[icon_base]' - missing connective base icon state 'other[i]'" + + if(wall_flags & PAINT_PAINTABLE) + if(!check_state_in_icon("paint[i]", icon_base)) + . += "'[icon_base]' - missing directional paint icon state '[i]'" + if(wall_flags & PAINT_STRIPABLE) + if(!check_state_in_icon("stripe[i]", icon_base)) + . += "'[icon_base]' - missing directional stripe icon state '[i]'" + if(wall_flags & WALL_HAS_EDGES) + if(!check_state_in_icon("other[i]", icon_base)) + . += "'[icon_base]' - missing directional edge icon state '[i]'" + + if(icon_base_natural) + if(!check_state_in_icon("[i]", icon_base_natural)) + . += "'[icon_base_natural]' - missing directional natural icon state '[i]'" + if(!check_state_in_icon("shine[i]", icon_base_natural)) + . += "'[icon_base_natural]' - missing natural shine icon state 'shine[i]'" + + if(icon_reinf) + var/list/all_reinf_icons = islist(icon_reinf) ? icon_reinf : list(icon_reinf) + for(var/sub_icon in all_reinf_icons) + if(use_reinf_state) + if(!check_state_in_icon(use_reinf_state, sub_icon)) + . += "'[sub_icon]' - missing reinf icon state '[use_reinf_state]'" + else + for(var/i = 0 to 7) + if(!check_state_in_icon(num2text(i), sub_icon)) + . += "'[sub_icon]' - missing directional reinf icon state '[i]'" -// Dumb overlay to apply over wall sprite for cheap texture effect -/decl/material/proc/get_wall_texture() - return + if(length(color) != 7) + . += "invalid color (not #RRGGBB)" -/decl/material/proc/on_leaving_metabolism(var/mob/parent, var/metabolism_class) - return +// Return the matter comprising this material. +/decl/material/proc/get_matter() + var/list/temp_matter = list() + temp_matter[type] = SHEET_MATERIAL_AMOUNT + return temp_matter -#define ACID_MELT_DOSE 10 -/decl/material/proc/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) // Acid melting, cleaner cleaning, etc - - if(solvent_power >= MAT_SOLVENT_MILD) - if(istype(O, /obj/item/paper)) - var/obj/item/paper/paperaffected = O - paperaffected.clearpaper() - to_chat(usr, SPAN_NOTICE("The solution dissolves the ink on the paper.")) - else if(istype(O, /obj/item/book) && REAGENT_VOLUME(holder, type) >= 5) - if(istype(O, /obj/item/book/tome)) - to_chat(usr, SPAN_WARNING("The solution does nothing. Whatever this is, it isn't normal ink.")) - else - var/obj/item/book/affectedbook = O - affectedbook.dat = null - to_chat(usr, SPAN_NOTICE("The solution dissolves the ink on the book.")) - - if(solvent_power >= MAT_SOLVENT_STRONG && !O.unacidable && (istype(O, /obj/item) || istype(O, /obj/effect/vine)) && (REAGENT_VOLUME(holder, type) > solvent_melt_dose)) - var/obj/effect/decal/cleanable/molten_item/I = new(O.loc) - I.visible_message(SPAN_DANGER("\The [O] dissolves!")) - I.desc = "It looks like it was \a [O] some time ago." - qdel(O) - holder?.remove_reagent(type, solvent_melt_dose) - - if(dirtiness <= DIRTINESS_STERILE) - O.germ_level -= min(REAGENT_VOLUME(holder, type)*20, O.germ_level) - O.was_bloodied = null - - if(dirtiness <= DIRTINESS_CLEAN) - O.clean_blood() - - if(defoliant && istype(O, /obj/effect/vine)) - qdel(O) - -#define FLAMMABLE_LIQUID_DIVISOR 7 -// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing. -/decl/material/proc/touch_mob(var/mob/living/M, var/amount, var/datum/reagents/holder) - if(fuel_value && amount && istype(M)) - M.fire_stacks += Floor((amount * fuel_value)/FLAMMABLE_LIQUID_DIVISOR) -#undef FLAMMABLE_LIQUID_DIVISOR - -/decl/material/proc/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) // Cleaner cleaning, lube lubbing, etc, all go here - - if(istype(T, /turf/simulated)) - var/turf/simulated/wall/W = T - if(defoliant) - for(var/obj/effect/overlay/wallrot/E in W) - W.visible_message(SPAN_NOTICE("\The [E] is completely dissolved by the solution!")) - qdel(E) - if(slipperiness != 0 && REAGENT_VOLUME(holder, type) >= 5) - if(slipperiness < 0) - W.unwet_floor(TRUE) - else - W.wet_floor(slipperiness) - if(dirtiness != DIRTINESS_NEUTRAL && REAGENT_VOLUME(holder, type) >= 1) - if(dirtiness > DIRTINESS_NEUTRAL) - var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate() in W - if (!dirtoverlay) - dirtoverlay = new /obj/effect/decal/cleanable/dirt(W) - dirtoverlay.alpha = REAGENT_VOLUME(holder, src) * dirtiness - else - dirtoverlay.alpha = min(dirtoverlay.alpha + REAGENT_VOLUME(holder, src) * dirtiness, 255) - else - if(dirtiness <= DIRTINESS_STERILE) - W.germ_level -= min(REAGENT_VOLUME(holder, type)*20, T.germ_level) - for(var/obj/item/I in W.contents) - I.was_bloodied = null - for(var/obj/effect/decal/cleanable/blood/B in W) - qdel(B) - if(dirtiness <= DIRTINESS_CLEAN) - W.dirt = 0 - if(W.wet > 1) - W.unwet_floor(FALSE) - W.clean_blood() - for(var/mob/living/carbon/slime/M in W) - M.adjustToxLoss(rand(5, 10)) - - if(length(vapor_products)) - var/volume = REAGENT_VOLUME(holder, type) - var/temperature = holder?.my_atom?.temperature || T20C - for(var/vapor in vapor_products) - T.assume_gas(vapor, (volume * vapor_products[vapor]), temperature) - holder.remove_reagent(type, volume) - -/decl/material/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/location, var/datum/reagents/holder) // Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob. - if(QDELETED(src)) - return // Something else removed us. - if(!istype(M)) - return - if(!(flags & AFFECTS_DEAD) && M.stat == DEAD && (world.time - M.timeofdeath > 150)) - return - if(overdose && (location != CHEM_TOUCH)) - var/overdose_threshold = overdose * (flags & IGNORE_MOB_SIZE? 1 : MOB_SIZE_MEDIUM/M.mob_size) - if(REAGENT_VOLUME(holder, type) > overdose_threshold) - affect_overdose(M, alien, holder) - - //determine the metabolism rate - var/removed = metabolism - if(ingest_met && (location == CHEM_INGEST)) - removed = ingest_met - if(touch_met && (location == CHEM_TOUCH)) - removed = touch_met - removed = M.get_adjusted_metabolism(removed) - - //adjust effective amounts - removed, dose, and max_dose - for mob size - var/effective = removed - if(!(flags & IGNORE_MOB_SIZE) && location != CHEM_TOUCH) - effective *= (MOB_SIZE_MEDIUM/M.mob_size) - - M.chem_doses[type] = M.chem_doses[type] + effective - if(effective >= (metabolism * 0.1) || effective >= 0.1) // If there's too little chemical, don't affect the mob, just remove it - switch(location) - if(CHEM_INJECT) - affect_blood(M, alien, effective, holder) - if(CHEM_INGEST) - affect_ingest(M, alien, effective, holder) - if(CHEM_TOUCH) - affect_touch(M, alien, effective, holder) - holder.remove_reagent(type, removed) - -/decl/material/proc/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(radioactivity) - M.apply_damage(radioactivity * removed, IRRADIATE, armor_pen = 100) - - if(toxicity) - M.add_chemical_effect(CE_TOXIN, toxicity) - var/dam = (toxicity * removed) - if(toxicity_targets_organ && ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/internal/I = H.internal_organs_by_name[toxicity_targets_organ] - if(I) - var/can_damage = I.max_damage - I.damage - if(can_damage > 0) - if(dam > can_damage) - I.take_internal_damage(can_damage, silent=TRUE) - dam -= can_damage - else - I.take_internal_damage(dam, silent=TRUE) - dam = 0 - if(dam > 0) - M.adjustToxLoss(toxicity_targets_organ ? (dam * 0.75) : dam) - - if(solvent_power >= MAT_SOLVENT_STRONG) - M.take_organ_damage(0, removed * solvent_power) - - if(narcosis) - if(prob(10)) - M.SelfMove(pick(GLOB.cardinal)) - if(prob(narcosis)) - M.emote(pick("twitch", "drool", "moan")) - - if(euphoriant) - M.adjust_drugged(euphoriant, euphoriant_max) - -/decl/material/proc/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - affect_blood(M, alien, removed * 0.5, holder) - -/decl/material/proc/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - - if(!istype(M)) - return - - if(radioactivity) - M.apply_damage((radioactivity / 2) * removed, IRRADIATE) - - if(dirtiness <= DIRTINESS_STERILE) - if(M.germ_level < INFECTION_LEVEL_TWO) // rest and antibiotics is required to cure serious infections - M.germ_level -= min(removed*20, M.germ_level) - for(var/obj/item/I in M.contents) - I.was_bloodied = null - M.was_bloodied = null - - if(dirtiness <= DIRTINESS_CLEAN) - if(M.r_hand) - M.r_hand.clean_blood() - if(M.l_hand) - M.l_hand.clean_blood() - if(M.wear_mask) - if(M.wear_mask.clean_blood()) - M.update_inv_wear_mask(0) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.head) - if(H.head.clean_blood()) - H.update_inv_head(0) - if(H.wear_suit) - if(H.wear_suit.clean_blood()) - H.update_inv_wear_suit(0) - else if(H.w_uniform) - if(H.w_uniform.clean_blood()) - H.update_inv_w_uniform(0) - if(H.shoes) - if(H.shoes.clean_blood()) - H.update_inv_shoes(0) - else - H.clean_blood(1) - return - M.clean_blood() - - if(solvent_power >= MAT_SOLVENT_STRONG && removed >= solvent_melt_dose) - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - for(var/obj/item/thing in list(H.head, H.wear_mask, H.glasses)) - if(thing.unacidable || !H.unEquip(thing)) - to_chat(H, SPAN_NOTICE("Your [thing] protects you from the acid.")) - holder.remove_reagent(type, REAGENT_VOLUME(holder, type)) - return - to_chat(H, SPAN_DANGER("Your [thing] dissolves!")) - qdel(thing) - removed -= solvent_melt_dose - if(removed <= 0) - return - - if(!H.unacidable) - var/screamed - for(var/obj/item/organ/external/affecting in H.organs) - if(!screamed && affecting.can_feel_pain()) - screamed = TRUE - H.emote("scream") - affecting.status |= ORGAN_DISFIGURED - - if(!M.unacidable) - M.take_organ_damage(0, min(removed * solvent_power * ((removed < solvent_melt_dose) ? 0.1 : 0.2), solvent_max_damage)) - -/decl/material/proc/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) // Overdose effect. Doesn't happen instantly. - M.add_chemical_effect(CE_TOXIN, 1) - M.adjustToxLoss(REM) - -/decl/material/proc/initialize_data(var/newdata) // Called when the reagent is created. - if(newdata) - . = newdata - -/decl/material/proc/mix_data(var/datum/reagents/reagents, var/list/newdata, var/amount) - . = REAGENT_DATA(reagents, type) +// todo: should this lerp instead of using hard cutoffs? +/decl/material/proc/get_attack_cooldown() + if(weight <= MAT_VALUE_LIGHT) + return FAST_WEAPON_COOLDOWN + if(weight >= MAT_VALUE_HEAVY) + return SLOW_WEAPON_COOLDOWN + return DEFAULT_WEAPON_COOLDOWN /decl/material/proc/explosion_act(obj/item/chems/holder, severity) SHOULD_CALL_PARENT(TRUE) @@ -579,18 +541,48 @@ /decl/material/proc/get_value() . = value -/decl/material/proc/get_presentation_name(var/obj/item/prop) - . = glass_name || liquid_name - if(prop?.reagents?.total_volume) - . = build_presentation_name_from_reagents(prop, .) - -/decl/material/proc/build_presentation_name_from_reagents(var/obj/item/prop, var/supplied) - . = supplied - - if(cocktail_ingredient) - for(var/decl/cocktail/cocktail in SSmaterials.get_cocktails_by_primary_ingredient(type)) - if(cocktail.matches(prop)) - return cocktail.get_presentation_name(prop) +/decl/material/proc/combustion_effect(var/turf/T, var/temperature) + return - if(prop.reagents.has_reagent(/decl/material/solid/ice)) - . = "iced [.]" +/// Used for material-dependent effects on stain dry. +/// Return TRUE to skip default drying handling. +/decl/material/proc/handle_stain_dry(obj/effect/decal/cleanable/blood/stain) + return FALSE + +/// Returns (in deciseconds) how long until dry() will be called on this stain, +/// or null to use the stain's default. +/// If 0 is returned, it dries instantly. +/// If any value below 0 is returned, it doesn't start processing. +/decl/material/proc/get_time_to_dry_stain(obj/effect/decal/cleanable/blood/stain) + return initial(stain.time_to_dry) + +var/global/list/_descriptive_temperature_strings +/// Returns a list of strings explaining certain material transitions that can happen at the given temperature, +/// e.g. 'ignite paper', 'melt lead', 'boil water' and so on. +/proc/get_descriptive_temperature_strings(temperature as num) + if(!_descriptive_temperature_strings) + _descriptive_temperature_strings = list() + + for(var/decl/material/desc_material as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/material)) + + if(desc_material.type != desc_material.temperature_burn_milestone_material) + continue + + if(!isnull(desc_material.bakes_into_at_temperature) && desc_material.bakes_into_material) + var/decl/material/cook = GET_DECL(desc_material.bakes_into_material) + global._descriptive_temperature_strings["bake [desc_material.name] into [cook.name]"] = desc_material.bakes_into_at_temperature + continue + + switch(desc_material.phase_at_temperature()) + if(MAT_PHASE_SOLID) + if(!isnull(desc_material.ignition_point)) + global._descriptive_temperature_strings["ignite [desc_material.name]"] = desc_material.ignition_point + else if(!isnull(desc_material.melting_point)) + global._descriptive_temperature_strings["melt [desc_material.name]"] = desc_material.melting_point + if(MAT_PHASE_LIQUID) + if(!isnull(desc_material.boiling_point)) + global._descriptive_temperature_strings["boil [desc_material.name]"] = desc_material.boiling_point + + for(var/burn_string in global._descriptive_temperature_strings) + if(temperature >= global._descriptive_temperature_strings[burn_string]) + LAZYADD(., burn_string) \ No newline at end of file diff --git a/code/modules/materials/_stack_recipe.dm b/code/modules/materials/_stack_recipe.dm deleted file mode 100644 index 7dd067dfbe3f..000000000000 --- a/code/modules/materials/_stack_recipe.dm +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Recipe datum - */ -/datum/stack_recipe - var/title = "ERROR" - var/result_type - var/req_amount // amount of material needed for this recipe - var/res_amount = 1 // amount of stuff that is produced in one batch (e.g. 4 for floor tiles) - var/max_res_amount = 1 - var/time = 0 - var/one_per_turf = 0 - var/on_floor = 0 - var/use_material - var/use_reinf_material - var/difficulty = 1 // higher difficulty requires higher skill level to make. - var/apply_material_name = 1 //Whether the recipe will prepend a material name to the title - 'steel clipboard' vs 'clipboard' - -/datum/stack_recipe/New(decl/material/material, var/reinforce_material) - if(material) - use_material = material.type - difficulty += material.construction_difficulty - if(reinforce_material) - use_reinf_material = reinforce_material - SSfabrication.init_crafting_recipe(src) - -#define CRAFTING_EXTRA_COST_FACTOR 1.2 -/datum/stack_recipe/proc/InitializeMaterials() - if(result_type && isnull(req_amount)) - req_amount = 0 - var/list/materials = atom_info_repository.get_matter_for(result_type, use_material, res_amount) - for(var/mat in materials) - req_amount += round(materials[mat]/res_amount) - req_amount = Clamp(ceil(((req_amount*CRAFTING_EXTRA_COST_FACTOR)/SHEET_MATERIAL_AMOUNT) * res_amount), 1, 50) - -#undef CRAFTING_EXTRA_COST_FACTOR - -/datum/stack_recipe/proc/display_name() - if(!use_material || !apply_material_name) - return title - var/decl/material/material = decls_repository.get_decl(use_material) - . = "[material.solid_name] [title]" - if(use_reinf_material) - material = decls_repository.get_decl(use_reinf_material) - . = "[material.solid_name]-reinforced [.]" - -/datum/stack_recipe/proc/spawn_result(mob/user, location, amount) - var/atom/O - if(use_material) - //TODO: standardize material argument passing in Initialize(). - if(ispath(result_type, /obj/item/stack)) // Amount is set manually in some overrides as well. - O = new result_type(location, amount, use_material, use_reinf_material) - else - O = new result_type(location, use_material, use_reinf_material) - else - O = new result_type(location) - if(user) - O.set_dir(user?.dir) - - // Temp block pending material/matter rework - if(use_material && use_material != DEFAULT_FURNITURE_MATERIAL && istype(O, /obj)) - var/obj/struct = O - if(LAZYACCESS(struct.matter, DEFAULT_FURNITURE_MATERIAL) > 0) - struct.matter[use_material] = max(struct.matter[use_material], struct.matter[DEFAULT_FURNITURE_MATERIAL]) - struct.matter -= DEFAULT_FURNITURE_MATERIAL - // End temp block - - return O - -/datum/stack_recipe/proc/can_make(mob/user) - if (one_per_turf && (locate(result_type) in user.loc)) - to_chat(user, "There is another [display_name()] here!") - return FALSE - - var/turf/T = get_turf(user.loc) - if (on_floor && !T.is_floor()) - to_chat(user, "\The [display_name()] must be constructed on the floor!") - return FALSE - - return TRUE - -/* - * Recipe list datum - */ -/datum/stack_recipe_list - var/title = "ERROR" - var/list/recipes = null - -/datum/stack_recipe_list/New(title, recipes) - src.title = title - src.recipes = recipes \ No newline at end of file diff --git a/code/modules/materials/definitions/gasses/_mat_gas.dm b/code/modules/materials/definitions/gasses/_mat_gas.dm index c7217113049e..7cec0aa4a231 100644 --- a/code/modules/materials/definitions/gasses/_mat_gas.dm +++ b/code/modules/materials/definitions/gasses/_mat_gas.dm @@ -3,15 +3,24 @@ melting_point = 70 boiling_point = 180 // -90 C - cryogenic liquid threshold color = COLOR_GRAY80 - stack_type = null - shard_type = SHARD_NONE + shard_name = SHARD_NONE conductive = 0 - alloy_materials = null - alloy_product = FALSE - value = 0 - gas_burn_product = /decl/material/gas/carbon_dioxide - gas_specific_heat = 20 // J/(mol*K) - gas_molar_mass = 0.032 // kg/mol + value = 0.15 + burn_product = /decl/material/gas/carbon_dioxide + molar_mass = 0.032 // kg/mol + latent_heat = 213 reflectiveness = 0 hardness = 0 - weight = 1 \ No newline at end of file + weight = 1 + opacity = 0.3 + default_solid_form = /obj/item/stack/material/aerogel + abstract_type = /decl/material/gas + +/decl/material/gas/Initialize() + if(!liquid_name) + liquid_name = "liquid [name]" + if(!solid_name) + solid_name = "frozen [name]" + if(!solution_name) + solution_name = "[name] solution" + . = ..() diff --git a/code/modules/materials/definitions/gasses/material_gas_alien.dm b/code/modules/materials/definitions/gasses/material_gas_alien.dm index 45b35d5077a2..fececde65bec 100644 --- a/code/modules/materials/definitions/gasses/material_gas_alien.dm +++ b/code/modules/materials/definitions/gasses/material_gas_alien.dm @@ -1,14 +1,19 @@ /decl/material/gas/alien name = "alien gas" + uid = "gas_alien" hidden_from_codex = TRUE gas_symbol_html = "X" gas_symbol = "X" + value = 0.6 + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_EXOTIC -/decl/material/gas/alien/New() +/decl/material/gas/alien/Initialize() var/num = rand(100,999) name = "compound #[num]" gas_specific_heat = rand(1, 400) - gas_molar_mass = rand(20,800)/1000 + molar_mass = rand(20,800)/1000 + latent_heat = rand(100, 50000) if(prob(40)) gas_flags |= XGM_GAS_FUEL else if(prob(40)) //it's prooobably a bad idea for gas being oxidizer to itself. @@ -21,4 +26,5 @@ gas_symbol = "X-[num]" if(prob(50)) color = RANDOM_RGB - gas_overlay_limit = 0.5 \ No newline at end of file + gas_overlay_limit = 0.5 + . = ..() diff --git a/code/modules/materials/definitions/gasses/material_gas_mundane.dm b/code/modules/materials/definitions/gasses/material_gas_mundane.dm index 02ba006181e5..cff373e83716 100644 --- a/code/modules/materials/definitions/gasses/material_gas_mundane.dm +++ b/code/modules/materials/definitions/gasses/material_gas_mundane.dm @@ -1,187 +1,242 @@ /decl/material/gas/oxygen name = "oxygen" - lore_text = "An ubiquitous oxidizing agent." + uid = "gas_oxygen" + lore_text = "A ubiquitous oxidizing agent." flags = MAT_FLAG_FUSION_FUEL - gas_specific_heat = 20 - gas_molar_mass = 0.032 + gas_specific_heat = 20 + molar_mass = 0.032 + latent_heat = 213 + boiling_point = -183 CELSIUS gas_flags = XGM_GAS_OXIDIZER gas_symbol_html = "O2" gas_symbol = "O2" gas_metabolically_inert = TRUE + value = 0.25 /decl/material/gas/helium name = "helium" + uid = "gas_helium" lore_text = "A noble gas. It makes your voice squeaky." flags = MAT_FLAG_FUSION_FUEL gas_specific_heat = 80 - gas_molar_mass = 0.004 + molar_mass = 0.004 + latent_heat = 21 + melting_point = 0 // Helium does not ever freeze at standard pressure, but this temperature rises at higher pressures. + boiling_point = -269 CELSIUS gas_symbol_html = "He" gas_symbol = "He" taste_description = "nothing" metabolism = 0.05 + value = 0.3 -/decl/material/gas/helium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/gas/helium/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() M.add_chemical_effect(CE_SQUEAKY, 1) /decl/material/gas/carbon_dioxide name = "carbon dioxide" + uid = "gas_carbon_dioxide" lore_text = "A byproduct of respiration." - gas_specific_heat = 30 - gas_molar_mass = 0.044 + gas_specific_heat = 30 + molar_mass = 0.044 + latent_heat = 380 + boiling_point = -78 CELSIUS + melting_point = null // at standard pressure it never becomes a liquid, it can only be a gas or solid gas_symbol_html = "CO2" gas_symbol = "CO2" + gas_metabolically_inert = TRUE /decl/material/gas/carbon_monoxide name = "carbon monoxide" + uid = "gas_carbon_monoxide" lore_text = "A highly poisonous gas." gas_specific_heat = 30 - gas_molar_mass = 0.028 + molar_mass = 0.028 + latent_heat = 216 + boiling_point = -192 CELSIUS gas_symbol_html = "CO" gas_symbol = "CO" taste_description = "stale air" metabolism = 0.05 // As with helium. -/decl/material/gas/carbon_monoxide/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/gas/carbon_monoxide/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) if(!istype(M)) return + . = ..() var/warning_message var/warning_prob = 10 - var/dosage = M.chem_doses[type] + var/dosage = CHEM_DOSE(M, src) + var/mob/living/human/H = M if(dosage >= 3) warning_message = pick("extremely dizzy","short of breath","faint","confused") warning_prob = 15 - M.adjustOxyLoss(10,20) - M.co2_alert = 1 + M.take_damage(10, OXY,20) + if(istype(H)) + SET_HUD_ALERT(H, HUD_OXY, 1) else if(dosage >= 1.5) warning_message = pick("dizzy","short of breath","faint","momentarily confused") - M.co2_alert = 1 - M.adjustOxyLoss(3,5) + M.take_damage(3, OXY,5) + if(istype(H)) + SET_HUD_ALERT(H, HUD_OXY, 1) else if(dosage >= 0.25) warning_message = pick("a little dizzy","short of breath") warning_prob = 10 - M.co2_alert = 0 - else - M.co2_alert = 0 - if(dosage > 1 && M.losebreath < 15) - M.losebreath++ + if(istype(H) && dosage > 1 && H.suffocation_counter < 15) + H.suffocation_counter++ if(warning_message && prob(warning_prob)) - to_chat(M, "You feel [warning_message].") + to_chat(M, SPAN_WARNING("You feel [warning_message].")) /decl/material/gas/methyl_bromide name = "methyl bromide" + uid = "gas_methyl_bromide" lore_text = "A once-popular fumigant and weedkiller." - gas_specific_heat = 42.59 - gas_molar_mass = 0.095 + gas_specific_heat = 42.59 + molar_mass = 0.095 + latent_heat = 253 + boiling_point = 4 CELSIUS gas_symbol_html = "CH3Br" gas_symbol = "CH3Br" taste_description = "pestkiller" vapor_products = list( /decl/material/gas/methyl_bromide = 1 ) + value = 0.25 -/decl/material/gas/methyl_bromide/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/gas/methyl_bromide/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) . = ..() - if(istype(M)) - for(var/obj/item/organ/external/E in M.organs) - if(LAZYLEN(E.implants)) - for(var/obj/effect/spider/spider in E.implants) - if(prob(25)) - E.implants -= spider - M.visible_message("The dying form of \a [spider] emerges from inside \the [M]'s [E.name].") - qdel(spider) - break + if(!ishuman(M)) + return + var/mob/living/human/H = M + for(var/obj/item/organ/external/E in H.get_external_organs()) + for(var/obj/effect/spider/spider in E.implants) + if(prob(25)) + E.implants -= spider + H.visible_message(SPAN_NOTICE("The dying form of \a [spider] emerges from inside \the [M]'s [E.name].")) + qdel(spider) + break /decl/material/gas/nitrous_oxide name = "sleeping agent" + uid = "gas_sleeping_agent" lore_text = "A mild sedative. Also known as laughing gas." - gas_specific_heat = 40 - gas_molar_mass = 0.044 + gas_specific_heat = 40 + molar_mass = 0.044 + latent_heat = 376 + boiling_point = -90 CELSIUS gas_tile_overlay = "sleeping_agent" gas_overlay_limit = 1 gas_flags = XGM_GAS_OXIDIZER //N2O is a powerful oxidizer gas_symbol_html = "N2O" gas_symbol = "N2O" metabolism = 0.05 // So that low dosages have a chance to build up in the body. + value = 0.25 -/decl/material/gas/nitrous_oxide/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/dosage = M.chem_doses[type] +/decl/material/gas/nitrous_oxide/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/dosage = CHEM_DOSE(M, src) if(dosage >= 1) - if(prob(5)) M.Sleeping(3) - M.dizziness = max(M.dizziness, 3) - M.confused = max(M.confused, 3) + if(prob(5)) SET_STATUS_MAX(M, STAT_ASLEEP, 3) + SET_STATUS_MAX(M, STAT_DIZZY, 3) + SET_STATUS_MAX(M, STAT_CONFUSE, 3) if(dosage >= 0.3) - if(prob(5)) M.Paralyse(1) - M.drowsyness = max(M.drowsyness, 3) - M.slurring = max(M.slurring, 3) + if(prob(5)) SET_STATUS_MAX(M, STAT_PARA, 1) + SET_STATUS_MAX(M, STAT_DROWSY, 3) + SET_STATUS_MAX(M, STAT_SLUR, 3) if(prob(20)) - M.emote(pick("giggle", "laugh")) + M.emote(pick(/decl/emote/audible/giggle, /decl/emote/audible/laugh)) M.add_chemical_effect(CE_PULSE, -1) /decl/material/gas/nitrogen name = "nitrogen" - lore_text = "An ubiquitous noble gas." - gas_specific_heat = 20 - gas_molar_mass = 0.028 + uid = "gas_nitrogen" + lore_text = "A ubiquitous noble gas." + gas_specific_heat = 20 + molar_mass = 0.028 + latent_heat = 199 + boiling_point = -195 CELSIUS gas_symbol_html = "N2" gas_symbol = "N2" gas_metabolically_inert = TRUE /decl/material/gas/nitrodioxide name = "nitrogen dioxide" + uid = "gas_nitrogen_dioxide" color = "#ca6409" gas_specific_heat = 37 - gas_molar_mass = 0.054 + molar_mass = 0.054 + latent_heat = 272 + boiling_point = -9 CELSIUS gas_flags = XGM_GAS_OXIDIZER gas_symbol_html = "NO2" gas_symbol = "NO2" /decl/material/gas/nitricoxide name = "nitric oxide" + uid = "gas_nitric_oxide" gas_specific_heat = 10 - gas_molar_mass = 0.030 + molar_mass = 0.030 + latent_heat = 410 + boiling_point = -152 CELSIUS gas_flags = XGM_GAS_OXIDIZER gas_symbol_html = "NO" gas_symbol = "NO" /decl/material/gas/methane name = "methane" - gas_specific_heat = 30 - gas_molar_mass = 0.016 + uid = "gas_methane" + gas_specific_heat = 30 + molar_mass = 0.016 + latent_heat = 510 + boiling_point = -162 CELSIUS gas_flags = XGM_GAS_FUEL gas_symbol_html = "CH4" gas_symbol = "CH4" /decl/material/gas/argon name = "argon" + uid = "gas_argon" lore_text = "Just when you need it, all of your supplies argon." gas_specific_heat = 10 - gas_molar_mass = 0.018 + molar_mass = 0.039 + latent_heat = 163 + boiling_point = -185 CELSIUS gas_symbol_html = "Ar" gas_symbol = "Ar" + value = 0.25 // If narcosis is ever simulated, krypton has a narcotic potency seven times greater than regular airmix. /decl/material/gas/krypton name = "krypton" + uid = "gas_krypton" gas_specific_heat = 5 - gas_molar_mass = 0.036 + molar_mass = 0.083 + latent_heat = 108 + boiling_point = -153 CELSIUS gas_symbol_html = "Kr" gas_symbol = "Kr" + value = 0.25 /decl/material/gas/neon name = "neon" + uid = "gas_neon" gas_specific_heat = 20 - gas_molar_mass = 0.01 + molar_mass = 0.02 + latent_heat = 86 + melting_point = -249 CELSIUS + boiling_point = -246 CELSIUS gas_symbol_html = "Ne" gas_symbol = "Ne" + value = 0.25 /decl/material/gas/ammonia name = "ammonia" + uid = "gas_ammonia" gas_specific_heat = 20 - gas_molar_mass = 0.017 + molar_mass = 0.017 + latent_heat = 1370 + boiling_point = -33 CELSIUS gas_symbol_html = "NH3" gas_symbol = "NH3" - metabolism = 0.05 // So that low dosages have a chance to build up in the body. taste_description = "mordant" taste_mult = 2 lore_text = "A caustic substance commonly used in fertilizer or household cleaners." @@ -191,42 +246,51 @@ /decl/material/gas/xenon name = "xenon" + uid = "gas_xenon" gas_specific_heat = 3 - gas_molar_mass = 0.054 + molar_mass = 0.131 + latent_heat = 96 + boiling_point = -108 CELSIUS gas_symbol_html = "Xe" gas_symbol = "Xe" + value = 0.25 -/decl/material/gas/xenon/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/dosage = M.chem_doses[type] +/decl/material/gas/xenon/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/dosage = CHEM_DOSE(M, src) if(dosage >= 1) - if(prob(5)) M.Sleeping(3) - M.dizziness = max(M.dizziness, 3) - M.confused = max(M.confused, 3) + if(prob(5)) SET_STATUS_MAX(M, STAT_ASLEEP, 3) + SET_STATUS_MAX(M, STAT_DIZZY, 3) + SET_STATUS_MAX(M, STAT_CONFUSE, 3) if(dosage >= 0.3) - if(prob(5)) M.Paralyse(1) - M.drowsyness = max(M.drowsyness, 3) - M.slurring = max(M.slurring, 3) + if(prob(5)) SET_STATUS_MAX(M, STAT_PARA, 1) + SET_STATUS_MAX(M, STAT_DROWSY, 3) + SET_STATUS_MAX(M, STAT_SLUR, 3) M.add_chemical_effect(CE_PULSE, -1) /decl/material/gas/chlorine name = "chlorine" + uid = "gas_chlorine" color = "#c5f72d" gas_overlay_limit = 0.5 gas_specific_heat = 5 - gas_molar_mass = 0.017 + molar_mass = 0.071 //Cl2 gas + latent_heat = 254 + boiling_point = -34 CELSIUS gas_flags = XGM_GAS_CONTAMINANT - gas_symbol_html = "Cl" + gas_symbol_html = "Cl2" gas_symbol = "Cl" taste_description = "bleach" metabolism = REM - heating_point = null - heating_products = null toxicity = 15 /decl/material/gas/sulfur_dioxide name = "sulfur dioxide" + uid = "gas_sulfur_dioxide" gas_specific_heat = 30 - gas_molar_mass = 0.044 + molar_mass = 0.064 + latent_heat = 389 + boiling_point = -10 CELSIUS gas_symbol_html = "SO2" gas_symbol = "SO2" dissolves_into = list( @@ -236,39 +300,65 @@ /decl/material/gas/hydrogen name = "hydrogen" + codex_name = "elemental hydrogen" + uid = "gas_hydrogen" lore_text = "A colorless, flammable gas." - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" flags = MAT_FLAG_FUSION_FUEL wall_name = "bulkhead" construction_difficulty = MAT_VALUE_HARD_DIY gas_specific_heat = 100 - gas_molar_mass = 0.002 + molar_mass = 0.002 + latent_heat = 454 + melting_point = -259 CELSIUS + boiling_point = -252 CELSIUS gas_flags = XGM_GAS_FUEL - gas_burn_product = /decl/material/liquid/water + burn_product = /decl/material/liquid/water gas_symbol_html = "H2" gas_symbol = "H2" dissolves_into = list( /decl/material/liquid/fuel/hydrazine = 1 ) + value = 0.4 /decl/material/gas/hydrogen/tritium name = "tritium" + codex_name = null + uid = "gas_tritium" lore_text = "A radioactive isotope of hydrogen. Useful as a fusion reactor fuel material." - mechanics_text = "Tritium is useable as a fuel in some forms of portable generator. It can also be converted into a fuel rod suitable for a R-UST fusion plant injector by clicking a stack on a fuel compressor. It fuses hotter than deuterium but is correspondingly more unstable." - stack_type = /obj/item/stack/material/tritium + mechanics_text = "Tritium is useable as a fuel in some forms of portable generator. It can also be converted into a fuel rod suitable for a R-UST fusion plant injector by using a fuel compressor. It fuses hotter than deuterium but is correspondingly more unstable." color = "#777777" - stack_origin_tech = "{'materials':5}" - value = 1.5 + stack_origin_tech = @'{"materials":5}' + value = 0.45 + melting_point = -252 CELSIUS + boiling_point = -248 CELSIUS gas_symbol_html = "T" gas_symbol = "T" + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_UNCOMMON /decl/material/gas/hydrogen/deuterium name = "deuterium" + codex_name = null + uid = "gas_deuterium" lore_text = "One of the two stable isotopes of hydrogen; also known as heavy hydrogen. Useful as a chemically synthesised fusion reactor fuel material." - mechanics_text = "Deuterium can be converted into a fuel rod suitable for a R-UST fusion plant injector by clicking a stack on a fuel compressor. It is the most 'basic' fusion fuel." - stack_type = /obj/item/stack/material/deuterium + mechanics_text = "Deuterium can be converted into a fuel rod suitable for a R-UST fusion plant injector by using a fuel compressor. It is the most 'basic' fusion fuel." + flags = MAT_FLAG_FUSION_FUEL | MAT_FLAG_FISSIBLE color = "#999999" - stack_origin_tech = "{'materials':3}" + stack_origin_tech = @'{"materials":3}' gas_symbol_html = "D" gas_symbol = "D" + value = 0.5 + melting_point = -254 CELSIUS + boiling_point = -250 CELSIUS + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_UNCOMMON + + neutron_interactions = list( + INTERACTION_ABSORPTION = 1250 + ) + absorption_products = list( + /decl/material/gas/hydrogen/tritium = 1 + ) + neutron_absorption = 5 + neutron_cross_section = 3 + diff --git a/code/modules/materials/definitions/liquids/_mat_liquid.dm b/code/modules/materials/definitions/liquids/_mat_liquid.dm index 6310e64df38f..e38d0dd33063 100644 --- a/code/modules/materials/definitions/liquids/_mat_liquid.dm +++ b/code/modules/materials/definitions/liquids/_mat_liquid.dm @@ -2,3 +2,18 @@ name = null melting_point = T0C boiling_point = T100C + opacity = 0.5 + molar_mass = 0.018 //water + latent_heat = 2258 + abstract_type = /decl/material/liquid + accelerant_value = FUEL_VALUE_SUPPRESSANT // Abstract way of dousing fires with fluid; realistically it should deprive them of oxidizer but heigh ho + // Assume if we're dealing with stacks, then it's solid (like ice) + sound_manipulate = 'sound/foley/rockscrape.ogg' + sound_dropped = 'sound/foley/rockscrape.ogg' + +/decl/material/liquid/Initialize() + if(!gas_name) + gas_name = "vaporized [name]" + if(!solid_name) + solid_name = "frozen [name]" + . = ..() diff --git a/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm b/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm index a306b997751b..e8e943197826 100644 --- a/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm +++ b/code/modules/materials/definitions/liquids/materials_liquid_chemistry.dm @@ -1,21 +1,41 @@ /decl/material/liquid/surfactant // Foam precursor - name = "surfacant" - lore_text = "A isocyanate liquid that forms a foam when mixed with water." + name = "surfactant" + uid = "liquid_surfactant" + lore_text = "An isocyanate liquid that forms a foam when mixed with water." taste_description = "metal" color = "#9e6b38" value = 0.1 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC /decl/material/liquid/foaming_agent // Metal foaming agent. This is lithium hydride. Add other recipes (e.g. LiH + H2O -> LiOH + H2) eventually. name = "foaming agent" - lore_text = "A agent that yields metallic foam when mixed with light metal and a strong acid." + uid = "liquid_foaming_agent" + lore_text = "An agent that yields metallic foam when mixed with light metal and a strong acid." taste_description = "metal" color = "#664b63" value = 0.1 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/foam + name = "foam" + uid = "liquid_foam" + lore_text = "A frothy, sticky, well-aerated fluid." + taste_description = "chemical blandness" + color = "#a59da4" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC /decl/material/liquid/lube name = "lubricant" + uid = "liquid_lubricant" lore_text = "Lubricant is a substance introduced between two moving surfaces to reduce the friction and wear between them. giggity." taste_description = "slime" - color = "#009ca8" + color = SYNTH_BLOOD_COLOR + opacity = 1.0 // liquid default is 0.5, we want oil to be fully opaque so the footsteps are too value = 0.1 slipperiness = 80 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + coated_adjective = "oily" + +// Prevent oil stains from drying. +/decl/material/liquid/lube/get_time_to_dry_stain(obj/effect/decal/cleanable/blood/stain) + return -1 \ No newline at end of file diff --git a/code/modules/materials/definitions/liquids/materials_liquid_mundane.dm b/code/modules/materials/definitions/liquids/materials_liquid_mundane.dm new file mode 100644 index 000000000000..97cfe6b65f94 --- /dev/null +++ b/code/modules/materials/definitions/liquids/materials_liquid_mundane.dm @@ -0,0 +1,12 @@ +/decl/material/liquid/mucus + name = "mucus" + uid = "chem_mucus" + lore_text = "A gooey semi-liquid produced by a wide variety of organisms. In some, it's associated with disease and illness." + taste_description = "slime" + color = COLOR_LIQUID_WATER + opacity = 0.5 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + +/decl/material/liquid/mucus/handle_stain_dry(obj/effect/decal/cleanable/blood/stain) + qdel(stain) + return TRUE // skip blood handling \ No newline at end of file diff --git a/code/modules/materials/definitions/liquids/materials_liquid_solvents.dm b/code/modules/materials/definitions/liquids/materials_liquid_solvents.dm index cbf9b39011f2..58d11660565d 100644 --- a/code/modules/materials/definitions/liquids/materials_liquid_solvents.dm +++ b/code/modules/materials/definitions/liquids/materials_liquid_solvents.dm @@ -1,16 +1,22 @@ /decl/material/liquid/acid - name = "sulphuric acid" + name = "sulfuric acid" + uid = "liquid_sulfuric_acid" lore_text = "A very corrosive mineral acid with the molecular formula H2SO4." taste_description = "acid" color = "#db5008" metabolism = REM * 2 touch_met = 50 // It's acid! value = 1.2 - solvent_power = MAT_SOLVENT_STRONG + 2 + solvent_power = MAT_SOLVENT_VERY_STRONG solvent_melt_dose = 10 + melting_point = 284 + boiling_point = 611 + latent_heat = 612 + molar_mass = 0.098 /decl/material/liquid/acid/hydrochloric //Like sulfuric, but less toxic and more acidic. name = "hydrochloric acid" + uid = "liquid_hydrochloric_acid" lore_text = "A very corrosive mineral acid with the molecular formula HCl." taste_description = "stomach acid" color = "#808080" @@ -18,27 +24,37 @@ solvent_melt_dose = 8 solvent_max_damage = 30 value = 1.5 + boiling_point = 382 + melting_point = 160 + molar_mass = 0.036 /decl/material/liquid/acid/polyacid name = "polytrinic acid" - lore_text = "Polytrinic acid is a an extremely corrosive chemical substance." + uid = "liquid_polytrinic_acid" + lore_text = "Polytrinic acid is an extremely corrosive chemical substance." taste_description = "acid" color = "#8e18a9" - solvent_power = MAT_SOLVENT_STRONG + 7 + solvent_power = MAT_SOLVENT_STRONGEST solvent_melt_dose = 4 solvent_max_damage = 60 value = 1.8 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_UNCOMMON /decl/material/liquid/acid/stomach name = "stomach acid" + uid = "liquid_stomach_acid" taste_description = "coppery foulness" solvent_power = MAT_SOLVENT_MODERATE color = "#d8ff00" hidden_from_codex = TRUE value = 0 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC /decl/material/liquid/acetone name = "acetone" + uid = "liquid_acetone" lore_text = "A colorless liquid solvent used in chemical synthesis." taste_description = "acid" color = "#808080" @@ -46,3 +62,7 @@ value = 0.1 solvent_power = MAT_SOLVENT_MODERATE toxicity = 3 + boiling_point = 330 + melting_point = 179 + latent_heat = 525 + molar_mass = 0.058 diff --git a/code/modules/materials/definitions/liquids/materials_liquid_soup.dm b/code/modules/materials/definitions/liquids/materials_liquid_soup.dm new file mode 100644 index 000000000000..ff7723e0ae4a --- /dev/null +++ b/code/modules/materials/definitions/liquids/materials_liquid_soup.dm @@ -0,0 +1,143 @@ +/decl/material/liquid/nutriment/soup + name = "abstract soup" + abstract_type = /decl/material/liquid/nutriment/soup + nutriment_factor = 4 + hydration_factor = 5 // Per removed amount each tick + glass_name = "soup" + opacity = 0.9 + melting_point = T0C // We assume soup is water-based by default and so it freezes at 0C. + boiling_point = null // It kind of sucks for your soup to boil away honestly + var/mask_name_suffix = "soup" + +/decl/material/liquid/nutriment/soup/initialize_data(list/newdata) + . = ..() + var/list/ingredients = LAZYACCESS(., DATA_INGREDIENT_LIST) + if(length(ingredients)) + ingredients = sortTim(ingredients, /proc/cmp_numeric_dsc, associative = TRUE) + LAZYSET(., DATA_INGREDIENT_LIST, ingredients) + var/list/name_ingredients = ingredients.Copy() + if(length(name_ingredients) > 3) + name_ingredients.Cut(4) + if(!(DATA_MASK_NAME in .)) + .[DATA_MASK_NAME] = "[english_list(name_ingredients)] [mask_name_suffix]" + +/decl/material/liquid/nutriment/soup/mix_data(var/datum/reagents/reagents, var/list/newdata, var/newamount) + + var/allergen_flags = ALLERGEN_NONE + var/list/ingredients = list() + var/new_fraction = newamount / REAGENT_VOLUME(reagents, type) // the fraction of the total reagent volume that the new data is associated with + var/old_fraction = 1 - new_fraction + + . = ..() + if(islist(.) && length(.)) + allergen_flags |= .[DATA_INGREDIENT_FLAGS] + var/list/old_ingredients = .[DATA_INGREDIENT_LIST] + for(var/ingredient in old_ingredients) + ingredients[ingredient] += old_ingredients[ingredient] * old_fraction + + if(islist(newdata) && length(newdata)) + allergen_flags |= newdata[DATA_INGREDIENT_FLAGS] + var/list/new_ingredients = newdata[DATA_INGREDIENT_LIST] + for(var/ingredient in new_ingredients) + ingredients[ingredient] += new_ingredients[ingredient] * new_fraction + + if(length(ingredients)) + ingredients = sortTim(ingredients, /proc/cmp_numeric_dsc, associative = TRUE) + LAZYSET(., DATA_INGREDIENT_LIST, ingredients) + var/list/name_ingredients = ingredients.Copy() + if(length(name_ingredients) > 3) + name_ingredients.Cut(4) + if(isnull(.[DATA_MASK_NAME]) || .[DATA_MASK_NAME] != newdata?[DATA_MASK_NAME]) // preserve custom name if both have it + if(allergen_flags & ALLERGEN_DAIRY) // TODO: check ALLEGEN_CHEESE for cheese-based soups + LAZYSET(., DATA_MASK_NAME, "[english_list(name_ingredients)] cream [mask_name_suffix]") + else + LAZYSET(., DATA_MASK_NAME, "[english_list(name_ingredients)] [mask_name_suffix]") + else + LAZYREMOVE(., DATA_MASK_NAME) + + if(allergen_flags) + LAZYSET(., DATA_INGREDIENT_FLAGS, allergen_flags) + else + LAZYREMOVE(., DATA_INGREDIENT_FLAGS) + +/decl/material/liquid/nutriment/soup/stock + name = "broth" + codex_name = "simple broth" + uid = "liquid_soup_broth" + solid_name = "stock" + color = "#8a7452" + mask_name_suffix = "broth" + taste_description = "salty, savoury flavours" + taste_mult = 1 + nutriment_factor = 5 + glass_name = "broth" + +/decl/material/liquid/nutriment/soup/stock/bone + name = "bone broth" + uid = "liquid_soup_stock_bone" + liquid_name = "bone broth" + solid_name = "powdered bone broth" + color = "#c0b067" + mask_name_suffix = "broth" + taste_description = "salty, savoury flavours" + +/decl/material/liquid/nutriment/soup/simple + name = "soup" + liquid_name = "soup" + codex_name = "simple soup" + solid_name = "powdered soup" + uid = "liquid_soup_simple" + mask_name_suffix = "soup" + nutriment_factor = 10 + +/decl/material/liquid/nutriment/soup/simple/meatball + uid = "liquid_soup_meatball" + reagent_overlay = "soup_meatballs" + reagent_overlay_base = "reagent_base_chunky" + +/decl/material/liquid/nutriment/soup/stew + name = "stew" + liquid_name = "stew" + solid_name = "powdered stew" + uid = "liquid_soup_stew" + mask_name_suffix = "stew" + reagent_overlay = "soup_chunks" + nutriment_factor = 10 + glass_name = "stew" + reagent_overlay_base = "reagent_base_chunky" + opacity = 1.0 + +/decl/material/liquid/nutriment/soup/chili + name = "chili" + liquid_name = "chili" + solid_name = "powdered chili" + uid = "liquid_soup_chili" + mask_name_suffix = "chili" + reagent_overlay = "decoration_chili" + glass_name = "chili" + nutriment_factor = 10 + reagent_overlay_base = "reagent_base_chunky" + opacity = 1.0 + +/decl/material/liquid/nutriment/soup/curry + name = "curry" + liquid_name = "curry" + solid_name = "curry powder" + uid = "liquid_soup_curry" + mask_name_suffix = "curry" + reagent_overlay = "soup_dumplings" + glass_name = "curry" + nutriment_factor = 10 + opacity = 1.0 + +/decl/material/liquid/nutriment/soup/noodle + name = "noodle soup" + liquid_name = "noodle soup" + solid_name = "noodles" + uid = "liquid_soup_noodles" + mask_name_suffix = "noodle soup" + reagent_overlay = "soup_chunks" // todo: maybe differentiate meat vs veggie noodle soup + glass_name = "noodle soup" + nutriment_factor = 10 + color = COLOR_POLISHED_BRASS + opacity = 0.7 diff --git a/code/modules/materials/definitions/liquids/materials_liquid_toxins.dm b/code/modules/materials/definitions/liquids/materials_liquid_toxins.dm index b61ef45e9938..366f04608344 100644 --- a/code/modules/materials/definitions/liquids/materials_liquid_toxins.dm +++ b/code/modules/materials/definitions/liquids/materials_liquid_toxins.dm @@ -1,41 +1,32 @@ /decl/material/liquid/denatured_toxin name = "denatured toxin" + uid = "liquid_denatured_toxin" lore_text = "Once toxic, now harmless." taste_description = null taste_mult = null color = "#808080" metabolism = REM - heating_products = null - heating_point = null toxicity_targets_organ = null toxicity = 0 hidden_from_codex = TRUE - -/decl/material/liquid/slimejelly - name = "slime jelly" - lore_text = "A gooey semi-liquid produced from one of the deadliest lifeforms in existence." - taste_description = "slime" - taste_mult = 1.3 - toxicity = 10 - heating_products = list( - /decl/material/liquid/denatured_toxin = 1 - ) - heating_point = 100 CELSIUS - heating_message = "becomes clear." - color = "#cf3600" - metabolism = REM * 0.25 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // It's useless, don't use it. /decl/material/liquid/plasticide name = "plasticide" + uid = "liquid_plasticide" lore_text = "Liquid plastic, do not eat." taste_description = "plastic" color = "#cf3600" toxicity = 5 taste_mult = 1.2 metabolism = REM * 0.25 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC /decl/material/liquid/amatoxin name = "amatoxin" + uid = "liquid_amatoxin" lore_text = "A powerful poison derived from certain species of mushroom." taste_description = "mushroom" color = "#792300" @@ -47,9 +38,13 @@ heating_message = "becomes clear." taste_mult = 1.2 metabolism = REM * 0.25 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + compost_value = 0.1 // a pittance, but it's so that compost bins don't end up filled with uncompostable amatoxin /decl/material/liquid/carpotoxin name = "carpotoxin" + uid = "liquid_carpotoxin" lore_text = "A deadly neurotoxin produced by the dreaded space carp." taste_description = "fish" color = "#003333" @@ -62,11 +57,15 @@ heating_message = "becomes clear." taste_mult = 1.2 metabolism = REM * 0.25 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + compost_value = 0.3 // a bit more than amatoxin or wax, but still not much /decl/material/liquid/venom name = "spider venom" + uid = "liquid_spider_venom" lore_text = "A deadly necrotic toxin produced by giant spiders to disable their prey." - taste_description = "absolutely vile" + taste_description = "vile poison" color = "#91d895" toxicity_targets_organ = BP_LIVER toxicity = 5 @@ -77,27 +76,43 @@ heating_message = "becomes clear." taste_mult = 1.2 metabolism = REM * 0.25 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + compost_value = 0.3 // a bit more than amatoxin or wax, but still not much + +/decl/material/liquid/venom/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + if(M.has_trait(/decl/trait/metabolically_inert)) + return + return ..() -/decl/material/liquid/venom/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(prob(REAGENT_VOLUME(holder, type)*2)) - M.confused = max(M.confused, 3) +/decl/material/liquid/venom/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + if(M.has_trait(/decl/trait/metabolically_inert)) + return + if(prob(REAGENT_VOLUME(holder, src)*2)) + SET_STATUS_MAX(M, STAT_CONFUSE, 3) ..() /decl/material/liquid/cyanide //Fast and Lethal name = "cyanide" + uid = "liquid_cyanide" lore_text = "A highly toxic chemical." taste_mult = 0.6 color = "#cf3600" + melting_point = 261 + boiling_point = 299 toxicity = 20 metabolism = REM * 2 toxicity_targets_organ = BP_HEART + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC -/decl/material/liquid/cyanide/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/cyanide/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.sleeping += 1 + ADJ_STATUS(M, STAT_ASLEEP, 1) /decl/material/liquid/heartstopper name = "heartstopper" + uid = "liquid_heartstopper" lore_text = "A potent cardiotoxin that paralyzes the heart." taste_description = "intense bitterness" color = "#6b833b" @@ -106,110 +121,135 @@ metabolism = REM * 2 toxicity_targets_organ = BP_HEART taste_mult = 1.2 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC -/decl/material/liquid/heartstopper/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/heartstopper/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.confused += 1.5 + ADJ_STATUS(M, STAT_CONFUSE, 1.5) -/decl/material/liquid/heartstopper/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) +/decl/material/liquid/heartstopper/affect_overdose(mob/living/victim, total_dose) ..() - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.stat != UNCONSCIOUS) - if(H.losebreath >= 10) - H.losebreath = max(10, M.losebreath-10) - H.adjustOxyLoss(2) - H.Weaken(10) - M.add_chemical_effect(CE_NOPULSE, 1) + if(victim.stat != UNCONSCIOUS) + if(victim.suffocation_counter >= 10) + victim.suffocation_counter = max(10, victim.suffocation_counter-10) + victim.take_damage(2, OXY) + SET_STATUS_MAX(victim, STAT_WEAK, 10) + victim.add_chemical_effect(CE_NOPULSE, 1) /decl/material/liquid/zombiepowder name = "zombie powder" + uid = "liquid_zombie_powder" lore_text = "A strong neurotoxin that puts the subject into a death-like state." taste_description = "death" color = "#669900" metabolism = REM toxicity = 3 toxicity_targets_organ = BP_BRAIN + heating_point = 100 CELSIUS heating_message = "melts into a liquid slurry." heating_products = list( - /decl/material/liquid/carpotoxin = 0.2, - /decl/material/liquid/sedatives = 0.4, + /decl/material/liquid/carpotoxin = 0.2, + /decl/material/liquid/sedatives = 0.4, /decl/material/solid/metal/copper = 0.4 ) taste_mult = 1.2 + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_EXOTIC -/decl/material/liquid/zombiepowder/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/zombiepowder/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() M.status_flags |= FAKEDEATH - M.adjustOxyLoss(3 * removed) - M.Weaken(10) - M.silent = max(M.silent, 10) - if(M.chem_doses[type] <= removed) //half-assed attempt to make timeofdeath update only at the onset + M.take_damage(3 * removed, OXY) + SET_STATUS_MAX(M, STAT_WEAK, 10) + SET_STATUS_MAX(M, STAT_SILENCE, 10) + if(CHEM_DOSE(M, src) <= removed) //half-assed attempt to make timeofdeath update only at the onset M.timeofdeath = world.time M.add_chemical_effect(CE_NOPULSE, 1) -/decl/material/liquid/zombiepowder/on_leaving_metabolism(mob/parent, metabolism_class) - parent?.status_flags &= ~FAKEDEATH +/decl/material/liquid/zombiepowder/on_leaving_metabolism(datum/reagents/metabolism/holder) + var/mob/M = REAGENT_GET_ATOM(holder) + if(istype(M)) + M.status_flags &= ~FAKEDEATH . = ..() /decl/material/liquid/fertilizer //Reagents used for plant fertilizers. name = "fertilizer" + uid = "liquid_fertilizer" lore_text = "A chemical mix good for growing plants with." taste_description = "plant food" taste_mult = 0.5 toxicity = 0.5 // It's not THAT poisonous. color = "#664330" - heating_point = null - heating_products = null metabolism = REM * 0.25 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/fertilizer/compost + name = "compost" + uid = "liquid_compost" + lore_text = "A mulch of organics good for feeding to plants." + taste_description = "organic rot" + toxicity = 0.1 /decl/material/liquid/weedkiller name = "weedkiller" + uid = "liquid_weedkiller" lore_text = "A harmful toxic mixture to kill plantlife. Do not ingest!" taste_mult = 1 color = "#49002e" toxicity = 4 heating_products = list( - /decl/material/liquid/bromide = 0.4, + /decl/material/liquid/bromide = 0.4, /decl/material/liquid/water = 0.6 ) + heating_point = 100 CELSIUS metabolism = REM * 0.25 defoliant = TRUE + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE /decl/material/liquid/tar name = "tar" + solid_name = "asphalt" + uid = "liquid_tar" + coated_adjective = "tarry" lore_text = "A dark, viscous liquid." taste_description = "petroleum" color = "#140b30" toxicity = 4 heating_products = list( - /decl/material/liquid/acetone = 0.4, - /decl/material/solid/carbon = 0.4, - /decl/material/liquid/ethanol = 0.2 + /decl/material/liquid/acetone = 0.4, + /decl/material/solid/carbon = 0.4, + /decl/material/liquid/alcohol/ethanol = 0.2 ) heating_point = 145 CELSIUS - heating_message = "separates" + heating_message = "separates." taste_mult = 1.2 metabolism = REM * 0.25 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + opacity = 1.0 /decl/material/liquid/hair_remover name = "hair remover" + uid = "liquid_hair_remover" lore_text = "An extremely effective chemical depilator. Do not ingest." taste_description = "acid" color = "#d9ffb3" toxicity = 1 overdose = REAGENTS_OVERDOSE - heating_products = null - heating_point = null taste_mult = 1.2 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // i am so tired of seeing hair remover planets metabolism = REM * 0.25 -/decl/material/liquid/hair_remover/affect_touch(var/mob/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/hair_remover/affect_touch(var/mob/M, var/removed, var/datum/reagents/holder) + . = ..() M.lose_hair() - holder.remove_reagent(type, REAGENT_VOLUME(holder, type)) + holder.remove_reagent(type, REAGENT_VOLUME(holder, src)) + return TRUE /decl/material/liquid/zombie name = "liquid corruption" + uid = "liquid_corruption" lore_text = "A filthy, oily substance which slowly churns of its own accord." taste_description = "decaying blood" color = "#800000" @@ -218,16 +258,20 @@ metabolism = REM * 5 overdose = 30 hidden_from_codex = TRUE + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_NOWHERE var/amount_to_zombify = 5 -/decl/material/liquid/zombie/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - affect_blood(M, alien, removed * 0.5, holder) +/decl/material/liquid/zombie/affect_touch(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + affect_blood(M, removed * 0.5, holder) + return TRUE -/decl/material/liquid/zombie/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/zombie/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - if (istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/true_dose = H.chem_doses[type] + REAGENT_VOLUME(holder, type) + if (ishuman(M)) + var/mob/living/human/H = M + var/true_dose = CHEM_DOSE(H, src) + REAGENT_VOLUME(holder, src) if (true_dose >= amount_to_zombify) H.zombify() else if (true_dose > 1 && prob(20)) @@ -235,8 +279,19 @@ else if (prob(10)) to_chat(H, "You feel terribly ill!") +/decl/material/liquid/acrylamide + name = "acrylamide" + uid = "liquid_acrylamide" + lore_text = "A colourless substance formed when food is burned. Rumoured to cause cancer, but mostly just nasty to eat." + taste_description = "bitter char" + color = "#a39894" + toxicity = 2 + taste_mult = 2 + /decl/material/liquid/bromide name = "bromide" + codex_name = "elemental bromide" + uid = "liquid_bromide" lore_text = "A dark, nearly opaque, red-orange, toxic element." taste_description = "pestkiller" color = "#4c3b34" @@ -246,8 +301,11 @@ /decl/material/liquid/mercury name = "mercury" + uid = "liquid_mercury" lore_text = "A chemical element." taste_mult = 0 //mercury apparently is tasteless. IDK + melting_point = 234 + boiling_point = 629 color = "#484848" value = 0.5 narcosis = 5 diff --git a/code/modules/materials/definitions/liquids/materials_liquid_water.dm b/code/modules/materials/definitions/liquids/materials_liquid_water.dm index a0ba65f4e646..20950348514f 100644 --- a/code/modules/materials/definitions/liquids/materials_liquid_water.dm +++ b/code/modules/materials/definitions/liquids/materials_liquid_water.dm @@ -1,13 +1,18 @@ /decl/material/liquid/water name = "water" + codex_name = "liquid water" // need a better name than this so it passes the overlapping ID unit tests :( + uid = "liquid_water" solid_name = "ice" gas_name = "water vapour" lore_text = "A ubiquitous chemical substance composed of hydrogen and oxygen." - color = COLOR_OCEAN + color = COLOR_LIQUID_WATER gas_tile_overlay = "generic" gas_overlay_limit = 0.5 gas_specific_heat = 30 - gas_molar_mass = 0.020 + molar_mass = 0.020 + boiling_point = 100 CELSIUS + melting_point = 0 CELSIUS + latent_heat = 2258 gas_condensation_point = 308.15 // 35C. Dew point is ~20C but this is better for gameplay considerations. gas_symbol_html = "H2O" gas_symbol = "H2O" @@ -17,96 +22,100 @@ glass_name = "water" glass_desc = "The father of all refreshments." slipperiness = 8 + slippery_amount = 5 + dirtiness = DIRTINESS_CLEAN + turf_touch_threshold = 0.1 chilling_point = T0C chilling_products = list( /decl/material/solid/ice = 1 ) + temperature_burn_milestone_material = /decl/material/liquid/water + can_boil_to_gas = TRUE + coated_adjective = "wet" -/decl/material/liquid/water/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/water/build_coated_name(datum/reagents/coating, list/accumulator) + var/coating_volumes = REAGENT_VOLUMES(coating) + if(length(coating_volumes) > 1) + accumulator.Insert(1, "dilute") // dilute always comes first! also this is intentionally not colored in component color mode + return // don't insert 'wet' ..() - if(istype(M, /mob/living/carbon/slime) || alien == IS_SLIME) - M.adjustToxLoss(2 * removed) - else if(ishuman(M)) - var/list/data = REAGENT_DATA(holder, type) - if(data && data["holy"]) - if(iscultist(M)) - if(prob(10)) - GLOB.cult.offer_uncult(M) - if(prob(2)) - var/obj/effect/spider/spiderling/S = new /obj/effect/spider/spiderling(M.loc) - M.visible_message("\The [M] coughs up \the [S]!") - else if(M.mind && GLOB.godcult.is_antagonist(M.mind)) - if(REAGENT_VOLUME(holder, type) > 5) - M.adjustHalLoss(5) - M.adjustBruteLoss(1) - if(prob(10)) //Only annoy them a /bit/ - to_chat(M,"You feel your insides curdle and burn! \[Give Into Purity\]") -/decl/material/liquid/water/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +// make salty water named saltwater +/decl/material/liquid/water/get_reagent_name(datum/reagents/holder, phase = MAT_PHASE_LIQUID) + if(phase == MAT_PHASE_LIQUID && holder?.get_primary_reagent_decl() == src) + if(REAGENT_VOLUME(holder, /decl/material/solid/sodiumchloride)) + return "saltwater" + return ..() // just use the default handling + +// make pure water named fresh water +/decl/material/liquid/water/get_reagent_name(datum/reagents/holder, phase = MAT_PHASE_LIQUID) + . = ..() + // length == 1 implies primary reagent, so checking both is redundant + if(phase == MAT_PHASE_LIQUID && length(REAGENT_VOLUMES(holder)) == 1) + return "fresh [.]" + return + +/decl/material/liquid/water/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + if(ishuman(M)) + var/list/data = REAGENT_DATA(holder, src) + if(data?[DATA_WATER_HOLINESS]) + affect_holy(M, removed, holder) + +/decl/material/liquid/water/proc/affect_holy(mob/living/M, removed, datum/reagents/holder) + return FALSE + +/decl/material/liquid/water/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() M.adjust_hydration(removed * 10) - affect_blood(M, alien, removed, holder) + affect_blood(M, removed, holder) #define WATER_LATENT_HEAT 9500 // How much heat is removed when applied to a hot turf, in J/unit (9500 makes 120 u of water roughly equivalent to 2L -/decl/material/liquid/water/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) - +/decl/material/liquid/water/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) + ..() - if(!istype(T)) + if(!istype(touching_turf)) return - var/datum/gas_mixture/environment = T.return_air() + var/datum/gas_mixture/environment = touching_turf.return_air() var/min_temperature = T20C + rand(0, 20) // Room temperature + some variance. An actual diminishing return would be better, but this is *like* that. In a way. . This has the potential for weird behavior, but I says fuck it. Water grenades for everyone. - var/hotspot = (locate(/obj/fire) in T) - if(hotspot && !istype(T, /turf/space)) - var/datum/gas_mixture/lowertemp = T.remove_air(T:air:total_moles) + // TODO: Cannot for the life of me work out what this is doing or why it's reducing the air temp by 2000; shouldn't it just be using environment? + var/hotspot = (locate(/obj/fire) in touching_turf) + if(hotspot && !isspaceturf(touching_turf)) + var/datum/gas_mixture/lowertemp = touching_turf.remove_air(touching_turf:air:total_moles) lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0) lowertemp.react() - T.assume_air(lowertemp) + touching_turf.assume_air(lowertemp) qdel(hotspot) - var/volume = REAGENT_VOLUME(holder, type) + var/affect_volume = REAGENT_VOLUME(holder, src) if (environment && environment.temperature > min_temperature) // Abstracted as steam or something - var/removed_heat = between(0, volume * WATER_LATENT_HEAT, -environment.get_thermal_energy_change(min_temperature)) + var/removed_heat = clamp(affect_volume * WATER_LATENT_HEAT, 0, -environment.get_thermal_energy_change(min_temperature)) environment.add_thermal_energy(-removed_heat) if (prob(5) && environment && environment.temperature > T100C) - T.visible_message("The water sizzles as it lands on \the [T]!") + touching_turf.visible_message(SPAN_NOTICE("The water sizzles as it lands on \the [touching_turf]!")) - var/list/data = REAGENT_DATA(holder, type) - if(data && data["holy"]) - T.holy = TRUE + var/list/data = REAGENT_DATA(holder, src) + if(LAZYACCESS(data, DATA_WATER_HOLINESS)) + touching_turf.turf_flags |= TURF_FLAG_HOLY /decl/material/liquid/water/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) ..() - if(istype(O, /obj/item/chems/food/snacks/monkeycube)) - var/obj/item/chems/food/snacks/monkeycube/cube = O - if(!cube.wrapped) - cube.Expand() + if(istype(O, /obj/item/food/animal_cube)) + var/obj/item/food/animal_cube/cube = O + if(!cube.wrapper_type) + cube.spawn_creature() /decl/material/liquid/water/touch_mob(var/mob/living/M, var/amount, var/datum/reagents/holder) ..() if(istype(M)) - var/needed = M.fire_stacks * 10 + var/needed = M.get_fire_intensity() * 10 if(amount > needed) - M.fire_stacks = 0 - M.ExtinguishMob() + M.set_fire_intensity(0) + M.extinguish_fire() holder.remove_reagent(type, needed) else - M.adjust_fire_stacks(-(amount / 10)) + M.adjust_fire_intensity(-(amount / 10)) holder.remove_reagent(type, amount) - -/decl/material/liquid/water/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - if(!istype(M, /mob/living/carbon/slime) && alien != IS_SLIME) - return - M.adjustToxLoss(10 * removed) // Babies have 150 health, adults have 200; So, 15 units and 20 - var/mob/living/carbon/slime/S = M - if(!S.client && istype(S)) - if(S.Target) // Like cats - S.Target = null - if(S.Victim) - S.Feedstop() - if(M.chem_doses[type] == removed) - M.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") - M.confused = max(M.confused, 2) diff --git a/code/modules/materials/definitions/solids/_mat_solid.dm b/code/modules/materials/definitions/solids/_mat_solid.dm index 334a346c6d1c..88085e5c1d9c 100644 --- a/code/modules/materials/definitions/solids/_mat_solid.dm +++ b/code/modules/materials/definitions/solids/_mat_solid.dm @@ -2,18 +2,24 @@ name = null melting_point = 1000 boiling_point = 30000 + molar_mass = 0.232 //iron Fe3O4 + latent_heat = 6120 //iron door_icon_base = "stone" - sheet_singular_name = "brick" - sheet_plural_name = "bricks" - icon_base = "stone" + icon_base = 'icons/turf/walls/stone.dmi' table_icon_base = "stone" - icon_reinf = "reinf_stone" + icon_reinf = 'icons/turf/walls/reinforced_stone.dmi' + dug_drop_type = /obj/item/stack/material/ore + default_solid_form = /obj/item/stack/material/brick + abstract_type = /decl/material/solid + bakes_into_material = null -/decl/material/solid/New() +/decl/material/solid/Initialize() if(!liquid_name) liquid_name = "molten [name]" if(!gas_name) gas_name = "vaporized [name]" + if(!solution_name) + solution_name = "[name] solution" if(!ore_compresses_to) ore_compresses_to = type - ..() \ No newline at end of file + . = ..() diff --git a/code/modules/materials/definitions/solids/materials_solid_alien.dm b/code/modules/materials/definitions/solids/materials_solid_alien.dm index 8a86c0f516ba..8b4c33935d44 100644 --- a/code/modules/materials/definitions/solids/materials_solid_alien.dm +++ b/code/modules/materials/definitions/solids/materials_solid_alien.dm @@ -1,19 +1,21 @@ /decl/material/solid/metal/aliumium name = "alien alloy" - stack_type = null - icon_base = "jaggy" + uid = "solid_alien" + icon_base = 'icons/turf/walls/metal.dmi' + wall_flags = PAINT_PAINTABLE door_icon_base = "metal" - icon_reinf = "reinf_metal" + icon_reinf = 'icons/turf/walls/reinforced_metal.dmi' hitsound = 'sound/weapons/smash.ogg' - sheet_singular_name = "chunk" - sheet_plural_name = "chunks" - stack_type = /obj/item/stack/material/aliumium construction_difficulty = MAT_VALUE_VERY_HARD_DIY hidden_from_codex = TRUE value = 2.5 + default_solid_form = /obj/item/stack/material/cubes + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_NOWHERE -/decl/material/solid/metal/aliumium/New() - icon_base = "metal" +/decl/material/solid/metal/aliumium/Initialize() + icon_base = 'icons/turf/walls/metal.dmi' + wall_flags = PAINT_PAINTABLE color = rgb(rand(10,150),rand(10,150),rand(10,150)) explosion_resistance = rand(25,40) brute_armor = rand(10,20) @@ -21,8 +23,8 @@ hardness = rand(15,100) reflectiveness = rand(15,100) integrity = rand(200,400) - melting_point = rand(400,10000) - ..() + melting_point = rand(400,11000) + . = ..() -/decl/material/solid/metal/aliumium/place_dismantled_girder(var/turf/target, var/decl/material/reinf_material) +/decl/material/solid/metal/aliumium/place_dismantled_girder(var/turf/target, var/decl/material/r_mat) return \ No newline at end of file diff --git a/code/modules/materials/definitions/solids/materials_solid_butchery.dm b/code/modules/materials/definitions/solids/materials_solid_butchery.dm new file mode 100644 index 000000000000..fb78922a5f65 --- /dev/null +++ b/code/modules/materials/definitions/solids/materials_solid_butchery.dm @@ -0,0 +1,256 @@ +/decl/material/solid/organic/meat + name = "meat" + codex_name = "animal protein" + uid = "solid_meat" + taste_description = "umami" + color = "#c03b2a" + flags = MAT_FLAG_PADDING + ignition_point = T0C+300 + conductive = 1 + construction_difficulty = MAT_VALUE_NORMAL_DIY + integrity = 60 + hardness = MAT_VALUE_SOFT + weight = MAT_VALUE_NORMAL + explosion_resistance = 1 + reflectiveness = MAT_VALUE_DULL + wall_support_value = MAT_VALUE_LIGHT + value = 0.8 + default_solid_form = /obj/item/stack/material/slab + sound_manipulate = 'sound/foley/meat1.ogg' + sound_dropped = 'sound/foley/meat2.ogg' + hitsound = 'sound/effects/squelch1.ogg' + fishing_bait_value = 1 + reagent_overlay = "soup_chunks" + nutriment_factor = 10 + allergen_flags = ALLERGEN_MEAT + affect_blood_on_ingest = 0 + affect_blood_on_inhale = 0 + +/decl/material/solid/organic/meat/egg + name = "egg yolk" + codex_name = "egg yolk" + taste_description = "egg" + color = "#ffffaa" + uid = "solid_egg" + melting_point = 273 + boiling_point = 373 + reagent_overlay = "soup_dumplings" + allergen_flags = ALLERGEN_EGG + +/decl/material/solid/organic/meat/fish + name = "fish meat" + codex_name = "fish protein" + uid = "solid_meat_fish" + color = "#ff9b9b" + allergen_flags = ALLERGEN_FISH + +/decl/material/solid/organic/meat/chicken + name = "chicken meat" + codex_name = "chicken protein" + uid = "solid_meat_chicken" + color = "#e98a8a" + +/decl/material/solid/organic/meat/xeno + name = "alien meat" + codex_name = "xenoprotein" + uid = "solid_meat_xeno" + color = COLOR_LIME + +/decl/material/solid/organic/meat/gut + name = "gut" + codex_name = null + uid = "solid_gut" + color = "#ffd6d6" + tans_to = /decl/material/solid/organic/leather/gut + +/decl/material/solid/organic/skin + name = "skin" + uid = "solid_skin" + color = "#9e8c72" + flags = MAT_FLAG_PADDING + ignition_point = T0C+300 + conductive = 0 + hidden_from_codex = TRUE + construction_difficulty = MAT_VALUE_NORMAL_DIY + integrity = 50 + hardness = MAT_VALUE_SOFT+5 + weight = MAT_VALUE_EXTREMELY_LIGHT + explosion_resistance = 1 + reflectiveness = MAT_VALUE_DULL + wall_support_value = MAT_VALUE_EXTREMELY_LIGHT + value = 1.2 + default_solid_form = /obj/item/stack/material/skin + sound_manipulate = 'sound/foley/meat1.ogg' + sound_dropped = 'sound/foley/meat2.ogg' + hitsound = "punch" + fishing_bait_value = 0.75 + tans_to = /decl/material/solid/organic/leather + compost_value = 0.8 + allergen_flags = ALLERGEN_MEAT + +/decl/material/solid/organic/skin/lizard + name = "lizardskin" + uid = "solid_lizardskin" + color = "#626952" + tans_to = /decl/material/solid/organic/leather/lizard + hardness = MAT_VALUE_FLEXIBLE + weight = MAT_VALUE_VERY_LIGHT + +/decl/material/solid/organic/skin/insect + name = "chitin" + uid = "solid_chitin" + color = "#7a776d" + tans_to = /decl/material/solid/organic/leather/chitin + integrity = 75 + hardness = MAT_VALUE_RIGID + weight = MAT_VALUE_VERY_LIGHT + brute_armor = 2 + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + +/decl/material/solid/organic/skin/fur + name = "fur" + uid = "solid_fur" + color = "#7a726d" + tans_to = /decl/material/solid/organic/leather/fur + default_solid_form = /obj/item/stack/material/skin/pelt + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + fishing_bait_value = 0 + paint_verb = "dyed" + +/decl/material/solid/organic/skin/fur/gray + uid = "solid_fur_gray" + +/decl/material/solid/organic/skin/fur/white + uid = "solid_fur_white" + +/decl/material/solid/organic/skin/fur/orange + color = COLOR_ORANGE + uid = "solid_fur_orange" + +/decl/material/solid/organic/skin/fur/black + color = COLOR_GRAY20 + uid = "solid_fur_black" + +/decl/material/solid/organic/skin/fur/brown + color = COLOR_DARK_BROWN + uid = "solid_fur_brown" + +/decl/material/solid/organic/skin/fur/heavy + color = COLOR_GUNMETAL + uid = "solid_fur_heavy" + +/decl/material/solid/organic/skin/sheep + color = COLOR_DARK_GRAY + uid = "solid_skin_sheep" + +/decl/material/solid/organic/skin/goat + color = COLOR_SILVER + uid = "solid_skin_goat" + +/decl/material/solid/organic/skin/cow + color = COLOR_GRAY40 + uid = "solid_skin_cow" + +/decl/material/solid/organic/skin/deer + color = COLOR_BROWN + uid = "solid_skin_deer" + +/decl/material/solid/organic/skin/shark + name = "sharkskin" + color = COLOR_PURPLE_GRAY + uid = "solid_skin_shark" + +/decl/material/solid/organic/skin/fish + color = COLOR_BOTTLE_GREEN + name = "fishskin" + uid = "solid_skin_fish" + +/decl/material/solid/organic/skin/fish/purple + color = COLOR_PALE_PURPLE_GRAY + uid = "solid_skin_carp" + +/decl/material/solid/organic/skin/feathers + name = "feathers" + uid = "solid_feathers" + color = COLOR_SILVER + default_solid_form = /obj/item/stack/material/skin/feathers + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + fishing_bait_value = 0 + +/decl/material/solid/organic/skin/feathers/purple + color = COLOR_PALE_PURPLE_GRAY + uid = "solid_feathers_purple" + +/decl/material/solid/organic/skin/feathers/blue + color = COLOR_SKY_BLUE + uid = "solid_feathers_blue" + +/decl/material/solid/organic/skin/feathers/green + color = COLOR_BOTTLE_GREEN + uid = "solid_feathers_green" + +/decl/material/solid/organic/skin/feathers/brown + color = COLOR_BEASTY_BROWN + uid = "solid_feathers_brown" + +/decl/material/solid/organic/skin/feathers/red + color = COLOR_RED + uid = "solid_feathers_red" + +/decl/material/solid/organic/skin/feathers/black + color = COLOR_GRAY15 + uid = "solid_feathers_black" + +/decl/material/solid/organic/bone + name = "bone" + uid = "solid_bone" + color = "#f0edc7" + ignition_point = T0C+1100 + conductive = 0 + hidden_from_codex = TRUE + construction_difficulty = MAT_VALUE_NORMAL_DIY + hitsound = 'sound/weapons/smash.ogg' + integrity = 75 + hardness = MAT_VALUE_RIGID + reflectiveness = MAT_VALUE_MATTE + weight = MAT_VALUE_NORMAL + wall_support_value = MAT_VALUE_NORMAL + default_solid_form = /obj/item/stack/material/bone + sound_manipulate = 'sound/foley/stickspickup1.ogg' + sound_dropped = 'sound/foley/sticksdrop1.ogg' + compost_value = 0.5 + allergen_flags = ALLERGEN_MEAT + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + +// Stub to stop eggs melting while being boiled. +/decl/material/solid/organic/bone/eggshell + name = "eggshell" + uid = "solid_eggshell" + color = "#eae0c8" + default_solid_form = /obj/item/stack/material/lump + hardness = MAT_VALUE_FLEXIBLE + weight = MAT_VALUE_VERY_LIGHT + +// Stub for earrings. TODO: put it in clams +/decl/material/solid/organic/bone/pearl + name = "pearl" + uid = "solid_pearl" + color = "#eae0c8" + default_solid_form = /obj/item/stack/material/lump + hardness = MAT_VALUE_FLEXIBLE + weight = MAT_VALUE_VERY_LIGHT + +/decl/material/solid/organic/bone/fish + name = "fishbone" + uid = "solid_fishbone" + hardness = MAT_VALUE_FLEXIBLE + weight = MAT_VALUE_VERY_LIGHT + +/decl/material/solid/organic/bone/cartilage + name = "cartilage" + uid = "solid_cartilage" + hardness = 0 + weight = MAT_VALUE_EXTREMELY_LIGHT diff --git a/code/modules/materials/definitions/solids/materials_solid_elements.dm b/code/modules/materials/definitions/solids/materials_solid_elements.dm index 943aca7197d8..0cbed95b3386 100644 --- a/code/modules/materials/definitions/solids/materials_solid_elements.dm +++ b/code/modules/materials/definitions/solids/materials_solid_elements.dm @@ -1,11 +1,27 @@ /decl/material/solid/boron name = "boron" + uid = "solid_boron" lore_text = "Boron is a chemical element with the symbol B and atomic number 5." - flags = MAT_FLAG_FUSION_FUEL + melting_point = 2349 + boiling_point = 4200 + flags = MAT_FLAG_FUSION_FUEL | MAT_FLAG_FISSIBLE + + neutron_cross_section = 10 + neutron_interactions = list( + INTERACTION_ABSORPTION = 2500 + ) + absorption_products = list( + /decl/material/solid/lithium = 0.5, + /decl/material/gas/helium = 0.5 + ) + neutron_absorption = 20 /decl/material/solid/lithium name = "lithium" + uid = "solid_lithium" lore_text = "A chemical element, used as antidepressant." + melting_point = 453 + boiling_point = 1615 flags = MAT_FLAG_FUSION_FUEL taste_description = "metal" color = "#808080" @@ -14,58 +30,88 @@ /decl/material/solid/carbon name = "carbon" + uid = "solid_carbon" lore_text = "A chemical element, the building block of life." + melting_point = 3800 + boiling_point = 4300 taste_description = "sour chalk" taste_mult = 1.5 color = "#1c1300" value = 0.5 dirtiness = 30 -/decl/material/solid/carbon/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/solid/carbon/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() var/datum/reagents/ingested = M.get_ingested_reagents() - if(ingested && LAZYLEN(ingested.reagent_volumes) > 1) - var/effect = 1 / (LAZYLEN(ingested.reagent_volumes) - 1) - for(var/R in ingested.reagent_volumes) - if(R != type) - ingested.remove_reagent(R, removed * effect) + var/ingested_volumes = REAGENT_VOLUMES(ingested) + if(ingested && LAZYLEN(ingested_volumes) > 1) + var/effect = 1 / (LAZYLEN(ingested_volumes) - 1) + for(var/decl/material/reagent as anything in ingested_volumes) + if(reagent.type != type) + ingested.remove_reagent(reagent, removed * effect) + +/decl/material/solid/carbon/ashes + name = "ashes" + uid = "solid_ashes" + lore_text = "The powdery remains of burned organic material." + color = "#5c5c5c" + dissolves_in = MAT_SOLVENT_MODERATE + // Todo: calcium + dissolves_into = list( + /decl/material/solid/carbon = 1 + ) /decl/material/solid/phosphorus name = "phosphorus" + uid = "solid_phosphorus" lore_text = "A chemical element, the backbone of biological energy carriers." + melting_point = 317 + boiling_point = 550 taste_description = "vinegar" color = "#832828" value = 0.5 /decl/material/solid/silicon name = "silicon" + uid = "solid_silicon" lore_text = "A tetravalent metalloid, silicon is less reactive than its chemical analog carbon." color = "#a8a8a8" value = 0.5 /decl/material/solid/sodium name = "sodium" + uid = "solid_sodium" lore_text = "A chemical element, readily reacts with water." + melting_point = 1687 + boiling_point = 3173 taste_description = "salty metal" color = "#808080" value = 0.5 /decl/material/solid/sulfur name = "sulfur" + uid = "solid_sulfur" lore_text = "A chemical element with a pungent smell." + melting_point = 388 + boiling_point = 717 taste_description = "old eggs" color = "#bf8c00" value = 0.5 /decl/material/solid/potassium name = "potassium" + uid = "solid_potassium" lore_text = "A soft, low-melting solid that can easily be cut with a knife. Reacts violently with water." + melting_point = 336 + boiling_point = 1032 taste_description = "sweetness" //potassium is bitter in higher doses but sweet in lower ones. color = "#a0a0a0" value = 0.5 -/decl/material/solid/potassium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - if(volume > 3) +/decl/material/solid/potassium/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/affect_volume = REAGENT_VOLUME(holder, src) + if(affect_volume > 3) M.add_chemical_effect(CE_PULSE, 1) - if(volume > 10) + if(affect_volume > 10) M.add_chemical_effect(CE_PULSE, 1) diff --git a/code/modules/materials/definitions/solids/materials_solid_exotic.dm b/code/modules/materials/definitions/solids/materials_solid_exotic.dm index 37853351f2c3..a7ac24e2f338 100644 --- a/code/modules/materials/definitions/solids/materials_solid_exotic.dm +++ b/code/modules/materials/definitions/solids/materials_solid_exotic.dm @@ -1,54 +1,56 @@ /decl/material/solid/metallic_hydrogen name = "metallic hydrogen" + uid = "solid_metallic_hydrogen" lore_text = "When hydrogen is exposed to extremely high pressures and temperatures, such as at the core of gas giants like Jupiter, it can take on metallic properties and - more importantly - acts as a room temperature superconductor. Achieving solid metallic hydrogen at room temperature, though, has proven to be rather tricky." - name = "metallic hydrogen" - stack_type = /obj/item/stack/material/mhydrogen color = "#e6c5de" - stack_origin_tech = "{'materials':6,'powerstorage':6,'magnets':5}" - ore_smelts_to = /decl/material/gas/hydrogen/tritium + stack_origin_tech = @'{"materials":6,"powerstorage":6,"magnets":5}' + heating_products = list( + /decl/material/gas/hydrogen/tritium = 0.7, + /decl/material/gas/hydrogen/deuterium = 0.3 + ) + heating_point = 990 ore_name = "raw hydrogen" ore_scan_icon = "mineral_rare" ore_icon_overlay = "gems" value = 2 gas_symbol_html = "H*" gas_symbol = "H*" - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" flags = MAT_FLAG_FUSION_FUEL wall_name = "bulkhead" construction_difficulty = MAT_VALUE_HARD_DIY gas_specific_heat = 100 - gas_molar_mass = 0.002 + molar_mass = 0.002 gas_flags = XGM_GAS_FUEL - gas_burn_product = /decl/material/liquid/water - gas_symbol_html = "H2" - gas_symbol = "H2" + burn_product = /decl/material/liquid/water ore_type_value = ORE_EXOTIC ore_data_value = 4 dissolves_into = list( /decl/material/liquid/fuel/hydrazine = 1 ) + default_solid_form = /obj/item/stack/material/segment + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_NOWHERE /decl/material/solid/exotic_matter name = "exotic matter" - lore_text = "Hypercrystalline supermatter is a subset of non-baryonic 'exotic' matter. It is found mostly in the heart of large stars, and features heavily in all kinds of fringe physics-defying technology." + uid = "solid_exotic_matter" + lore_text = "Exotic matter is a non-baryonic form of matter, which features heavily in all kinds of fringe physics-defying technology." color = "#ffff00" radioactivity = 20 - stack_origin_tech = "{'wormholes':2,'materials':6,'exoticmatter':4}" + stack_origin_tech = @'{"wormholes":2,"materials":6,"exoticmatter":4}' luminescence = 3 value = 3 - icon_base = "stone" + icon_base = 'icons/turf/walls/stone.dmi' + wall_flags = 0 table_icon_base = "stone" - shard_type = SHARD_SHARD + shard_name = SHARD_SHARD hardness = MAT_VALUE_RIGID - sheet_singular_name = "crystal" - sheet_plural_name = "crystals" flags = MAT_FLAG_FUSION_FUEL construction_difficulty = MAT_VALUE_HARD_DIY reflectiveness = MAT_VALUE_SHINY ignition_point = FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE gas_specific_heat = 200 // J/(mol*K) - gas_molar_mass = 0.405 // kg/mol + molar_mass = 0.405 // kg/mol gas_overlay_limit = 0.7 gas_flags = XGM_GAS_FUEL | XGM_GAS_CONTAMINANT gas_symbol_html = "Ex*" @@ -56,7 +58,10 @@ taste_mult = 1.5 toxicity = 30 touch_met = 5 - fuel_value = 2 + accelerant_value = FUEL_VALUE_VOLATILE vapor_products = list( /decl/material/solid/exotic_matter = 1 ) + default_solid_form = /obj/item/stack/material/segment + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_NOWHERE diff --git a/code/modules/materials/definitions/solids/materials_solid_fission.dm b/code/modules/materials/definitions/solids/materials_solid_fission.dm new file mode 100644 index 000000000000..f68c8c856730 --- /dev/null +++ b/code/modules/materials/definitions/solids/materials_solid_fission.dm @@ -0,0 +1,108 @@ +/decl/material/solid/metal/depleted_uranium + name = "depleted uranium" + uid = "solid_depleted_uranium" + lore_text = "Uranium that does not posess a significant amount of radioactive isotopes. Extremely dense, and can be enriched to produce more fission fuel." + mechanics_text = "Depleted uranium can be enriched in fission reactors for use as fuel." + taste_description = "the outside of a reactor" + flags = MAT_FLAG_FISSIBLE + icon_base = 'icons/turf/walls/stone.dmi' + table_icon_base = "stone" + icon_reinf = 'icons/turf/walls/reinforced_stone.dmi' + wall_flags = 0 //Since we're using an unpaintable icon_base and icon_reinf + value = 1.5 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + neutron_cross_section = 5 + neutron_interactions = list( + INTERACTION_ABSORPTION = 2500, + INTERACTION_FISSION = 4500 + ) + absorption_products = list( + /decl/material/solid/metal/plutonium = 0.8 + ) + fission_products = list( + /decl/material/solid/metal/fission_byproduct = 0.8 + ) + fission_heat = 35000 + fission_energy = 4000 + neutron_absorption = 4 + + +/decl/material/solid/metal/neptunium // Np-237. + name = "neptunium" + uid = "solid_neptunium" + lore_text = "A byproduct of uranium undergoing beta decay. Extremely radioactive, can be used as fission fuel, with difficulty." + mechanics_text = "Neptunium can be used as fuel in fission reactors at high neutron energies." + taste_description = "lemon juice and hot concrete." + flags = MAT_FLAG_FISSIBLE + radioactivity = 30 + icon_base = 'icons/turf/walls/stone.dmi' + table_icon_base = "stone" + icon_reinf = 'icons/turf/walls/reinforced_stone.dmi' + wall_flags = 0 //Since we're using an unpaintable icon_base and icon_reinf + melting_point = 910 + boiling_point = 4300 + color = "#404c53" + value = 0.5 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + neutron_cross_section = 4 // Difficult to use as fuel. + neutron_interactions = list( + INTERACTION_FISSION = 3000 + ) + fission_products = list( + /decl/material/solid/metal/fission_byproduct = 0.2 + ) + +/decl/material/solid/metal/plutonium + name = "plutonium" + uid = "solid_plutonium" + lore_text = "A mundane silver-grey metal that is highly fissible. Often used as fuel in nuclear fission reactors and weapons." + mechanics_text = "Plutonium can be used as fuel in fission reactors." + taste_description = "nuclear fallout" + flags = MAT_FLAG_FISSIBLE + icon_base = 'icons/turf/walls/stone.dmi' + table_icon_base = "stone" + icon_reinf = 'icons/turf/walls/reinforced_stone.dmi' + wall_flags = 0 //Since we're using an unpaintable icon_base and icon_reinf + melting_point = 912 + boiling_point = 3503 + color = "#b5c5a2" + value = 3 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + neutron_cross_section = 10 + neutron_interactions = list( + INTERACTION_FISSION = 1000 + ) + fission_products = list( + /decl/material/solid/metal/fission_byproduct = 0.5 + ) + neutron_production = 12 + fission_heat = 60000 + fission_energy = 5000 + +// Catch-all for the nasty byproducts of fission reactions. +/decl/material/solid/metal/fission_byproduct + name = "nuclear waste" + uid = "solid_nuclear_waste" + lore_text = "An unfortunate byproduct of nuclear fission. Extremely radioactive, can be recycled into various useful materials." + mechanics_text = "Nuclear waste can be processed into various exotic chemicals." + taste_description = "paprika" + radioactivity = 30 + icon_base = 'icons/turf/walls/stone.dmi' + table_icon_base = "stone" + icon_reinf = 'icons/turf/walls/reinforced_stone.dmi' + wall_flags = 0 //Since we're using an unpaintable icon_base and icon_reinf + color = "#98be30" + value = 0.5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // Don't spawn this in plants. + + dissolves_into = list( + /decl/material/solid/metal/radium = 0.5, + /decl/material/solid/lithium = 0.5 + ) diff --git a/code/modules/materials/definitions/solids/materials_solid_gemstones.dm b/code/modules/materials/definitions/solids/materials_solid_gemstones.dm index c7776735ace4..d9a0253e53a4 100644 --- a/code/modules/materials/definitions/solids/materials_solid_gemstones.dm +++ b/code/modules/materials/definitions/solids/materials_solid_gemstones.dm @@ -1,41 +1,69 @@ /decl/material/solid/gemstone - name = null - flags = MAT_FLAG_UNMELTABLE - cut_delay = 60 - color = COLOR_DIAMOND - opacity = 0.4 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - reflectiveness = MAT_VALUE_MIRRORED - conductive = 0 - ore_icon_overlay = "gems" - sheet_singular_name = "gem" - sheet_plural_name = "gems" + flags = MAT_FLAG_UNMELTABLE + cut_delay = 60 + color = COLOR_DIAMOND + opacity = 0.4 + shard_name = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + conductive = 0 + ore_icon_overlay = "gems" + default_solid_form = /obj/item/stack/material/gemstone + abstract_type = /decl/material/solid/gemstone + sound_manipulate = 'sound/foley/pebblespickup1.ogg' + sound_dropped = 'sound/foley/pebblesdrop1.ogg' + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null + hardness = MAT_VALUE_VERY_HARD + reflectiveness = MAT_VALUE_VERY_SHINY + construction_difficulty = MAT_VALUE_VERY_HARD_DIY /decl/material/solid/gemstone/diamond - name = "diamond" - lore_text = "An extremely hard allotrope of carbon. Valued for its use in industrial tools." - stack_type = /obj/item/stack/material/diamond - brute_armor = 10 - burn_armor = 50 // Diamond walls are immune to fire, therefore it makes sense for them to be almost undamageable by burn damage type. - stack_origin_tech = "{'materials':6}" - hardness = MAT_VALUE_VERY_HARD + 20 - construction_difficulty = MAT_VALUE_VERY_HARD_DIY - ore_name = "rough diamonds" - ore_result_amount = 5 - ore_spread_chance = 10 - ore_scan_icon = "mineral_rare" - xarch_source_mineral = /decl/material/gas/ammonia - value = 1.8 - sparse_material_weight = 5 - rich_material_weight = 5 - ore_type_value = ORE_PRECIOUS - ore_data_value = 2 + name = "diamond" + uid = "solid_diamond" + lore_text = "An extremely hard allotrope of carbon. Valued for its use in industrial tools." + melting_point = 4300 + boiling_point = null + ignition_point = null + brute_armor = 10 + burn_armor = 50 // Diamond walls are immune to fire, therefore it makes sense for them to be almost undamageable by burn damage type. + stack_origin_tech = @'{"materials":6}' + hardness = MAT_VALUE_VERY_HARD + 20 + ore_name = "rough diamonds" + ore_result_amount = 1 + ore_spread_chance = 10 + ore_scan_icon = "mineral_rare" + xarch_source_mineral = /decl/material/gas/ammonia + value = 1.8 + sparse_material_weight = 5 + rich_material_weight = 5 + ore_type_value = ORE_PRECIOUS + ore_data_value = 2 /decl/material/solid/gemstone/crystal - name = "crystal" - hardness = MAT_VALUE_VERY_HARD - reflectiveness = MAT_VALUE_VERY_SHINY - stack_type = null + name = "crystal" + uid = "solid_crystal" + value = 2 hidden_from_codex = TRUE - value = 2 + +/decl/material/solid/gemstone/ruby + name = "ruby" + lore_text = "A rich red stone sometimes found in marble." + uid = "solid_ruby" + value = 1.6 + color = "#d00000" + +/decl/material/solid/gemstone/sapphire + name = "sapphire" + lore_text = "A deep blue gemstone sometimes found in clay or other sediment." + uid = "solid_sapphite" + value = 1.6 + color = "#2983de" + +/decl/material/solid/gemstone/topaz + name = "topaz" + lore_text = "A golden gemstone sometimes found in granite." + uid = "solid_topaz" + value = 1.6 + color = "#f7b92d" diff --git a/code/modules/materials/definitions/solids/materials_solid_glass.dm b/code/modules/materials/definitions/solids/materials_solid_glass.dm index 465d73faa816..c93baa2bc708 100644 --- a/code/modules/materials/definitions/solids/materials_solid_glass.dm +++ b/code/modules/materials/definitions/solids/materials_solid_glass.dm @@ -1,24 +1,32 @@ /decl/material/solid/glass name = "glass" + codex_name = "silica glass" + uid = "solid_glass" lore_text = "A brittle, transparent material made from molten silicates. It is generally not a liquid." - stack_type = /obj/item/stack/material/glass flags = MAT_FLAG_BRITTLE color = GLASS_COLOR opacity = 0.3 integrity = 50 - shard_type = SHARD_SHARD + shard_name = SHARD_SHARD tableslam_noise = 'sound/effects/Glasshit.ogg' - hardness = MAT_VALUE_RIGID + 10 + hardness = MAT_VALUE_RIGID + 10 + door_icon_base = "metal" reflectiveness = MAT_VALUE_SHINY - melting_point = T100C + melting_point = 1674 + boiling_point = null + ignition_point = null weight = MAT_VALUE_VERY_LIGHT brute_armor = 1 burn_armor = 2 table_icon_base = "solid" destruction_desc = "shatters" + destruction_sound = "shatter" hitsound = 'sound/effects/Glasshit.ogg' conductive = 0 wall_support_value = MAT_VALUE_LIGHT + default_solid_form = /obj/item/stack/material/pane + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null /decl/material/solid/glass/proc/is_reinforced() return (integrity > 75) //todo @@ -27,19 +35,49 @@ return ..() && !is_reinforced() /decl/material/solid/glass/borosilicate - name = "borosilicate glass" + name = "heat-resistant glass" + codex_name = null + uid = "solid_borosilicate_glass" lore_text = "An extremely heat-resistant form of glass." - stack_type = /obj/item/stack/material/glass/borosilicate flags = MAT_FLAG_BRITTLE hardness = MAT_VALUE_HARD weight = MAT_VALUE_LIGHT integrity = 70 brute_armor = 2 burn_armor = 5 - melting_point = T0C + 4000 + melting_point = 4274 color = GLASS_COLOR_SILICATE - stack_origin_tech = "{'materials':4}" + stack_origin_tech = @'{"materials":4}' construction_difficulty = MAT_VALUE_HARD_DIY - alloy_product = TRUE - alloy_materials = list(/decl/material/solid/glass = 2500, /decl/material/solid/metal/platinum = 1250) - value = 1.8 \ No newline at end of file + value = 1.8 + +/decl/material/solid/fiberglass + name = "fiberglass" + uid = "solid_fiberglass" + lore_text = "A form of glass-reinforced plastic made from glass fibers and a polymer resin." + dissolves_into = list( + /decl/material/solid/glass = 0.7, + /decl/material/solid/organic/plastic = 0.3 + ) + color = COLOR_OFF_WHITE + opacity = 0.6 + melting_point = 1674 + hardness = MAT_VALUE_HARD + weight = MAT_VALUE_LIGHT + integrity = 120 + icon_base = 'icons/turf/walls/plastic.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = 0 + use_reinf_state = null + door_icon_base = "plastic" + hardness = MAT_VALUE_FLEXIBLE + weight = MAT_VALUE_LIGHT + stack_origin_tech = @'{"materials":3}' + conductive = 0 + construction_difficulty = MAT_VALUE_NORMAL_DIY + reflectiveness = MAT_VALUE_MATTE + wall_support_value = MAT_VALUE_LIGHT + burn_product = /decl/material/gas/carbon_monoxide + dooropen_noise = 'sound/effects/doorcreaky.ogg' + default_solid_form = /obj/item/stack/material/sheet/reinforced + tensile_strength = 1.2 // very good for line diff --git a/code/modules/materials/definitions/solids/materials_solid_ice.dm b/code/modules/materials/definitions/solids/materials_solid_ice.dm index aad50c30fe46..fc679cc6a9be 100644 --- a/code/modules/materials/definitions/solids/materials_solid_ice.dm +++ b/code/modules/materials/definitions/solids/materials_solid_ice.dm @@ -1,75 +1,253 @@ /decl/material/solid/ice - stack_type = null - color = "#a5f2f3" - heating_products = list( + name = "water" + use_name = "ice" + solid_name = "ice" + liquid_name = "water" + gas_name = "steam" + color = "#a5f2f3" + codex_name = "water ice" + taste_description = "ice" + ore_spread_chance = 25 + ore_scan_icon = "mineral_common" + ore_icon_overlay = "lump" + removed_by_welder = TRUE + value = 0.2 + sparse_material_weight = 2 + ore_result_amount = 4 + rich_material_weight = 37 + heating_point = T20C + 10 // Above room temperature, to avoid drinks melting. + uid = "solid_ice" + heating_products = list( /decl/material/liquid/water = 1 ) - name = "ice" - ore_name = "ice" - ore_spread_chance = 25 - ore_scan_icon = "mineral_common" - ore_icon_overlay = "lump" - removed_by_welder = TRUE - value = 0.2 - sparse_material_weight = 2 - rich_material_weight = 37 - heating_point = T20C + 10 // Above room temperature, to avoid drinks melting. + +/decl/material/solid/ice/Initialize() + liquid_name ||= "liquid [name]" // avoiding the 'molten ice' issue + gas_name ||= name + solid_name ||= "[name] ice" + use_name ||= solid_name + ore_name ||= solid_name + . = ..() + +/decl/material/solid/ice/snow + name = "snow" + liquid_name = "water" + solid_name = "snow" + gas_name = "steam" + adjective_name = "snow" + coated_adjective = "snowy" + color = COLOR_WHITE + codex_name = null + uid = "solid_snow" + hardness = MAT_VALUE_MALLEABLE + dug_drop_type = /obj/item/stack/material/ore/handful + default_solid_form = /obj/item/stack/material/lump/large + can_backfill_floor_type = /decl/flooring/snow + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + +/decl/material/solid/ice/snow/handle_stain_dry(obj/effect/decal/cleanable/blood/stain) + var/ambient_temperature = stain.get_ambient_temperature() + if(ambient_temperature < melting_point) + // reset the drying timer, it's not warm enough to melt + stain.start_drying() // you'd better not ever melt instantly below your melting point, or else this will cause infinite recursion + else if(ambient_temperature > boiling_point) + qdel(src) // melt instantly, no questions asked + else + if(--stain.amount < 0) // reduce the amount of snow (amount is always 0 for footprints currently, but maybe someday?) + qdel(src) + return TRUE // skip base blood handling + +// For snowy footprints melting. +/decl/material/solid/ice/snow/get_time_to_dry_stain(obj/effect/decal/cleanable/blood/stain) + // Attempt to melt once every two minutes at T20C, + // and every 5 minutes at T0C, trying to 'fake' latent heat. + // Above T20C it scales based on (temperature / T20C). + // At or above the boiling point it melts instantly. + // This doesn't mean it WILL melt at that point, just that it'll attempt to. + var/ambient_temperature = max(stain.get_ambient_temperature(), melting_point) + if(ambient_temperature >= boiling_point) + return 0 // dry instantly + if(ambient_temperature < melting_point) + return 5 MINUTES + // convert from kelvins to celsius by subtracting the 0C point in Kelvins + return Interpolate(5 MINUTES, 2 MINUTES, (ambient_temperature - T0C) / 20) / (stain.amount + 1) // Undo the scaling done by blood. /decl/material/solid/ice/aspium + name = "aspium" + use_name = null + codex_name = null + solid_name = null + liquid_name = null + gas_name = null heating_products = list( /decl/material/liquid/fuel/hydrazine = 0.3, /decl/material/liquid/water = 0.7 ) - name = "aspium ice" - ore_name = "aspium ice" + uid = "solid_ice_aspium" value = 0.4 sparse_material_weight = 2 rich_material_weight = 37 /decl/material/solid/ice/lukrite + name = "lukrite" + use_name = null + codex_name = null + solid_name = null + liquid_name = null + gas_name = null heating_products = list( /decl/material/solid/sulfur = 0.4, /decl/material/liquid/water = 0.2, /decl/material/liquid/acid = 0.4 ) - name = "lukrite ice" - ore_name = "lukrite ice" + uid = "solid_ice_lukrite" value = 0.3 - sparse_material_weight = 27 - rich_material_weight = 22 + sparse_material_weight = 20 + rich_material_weight = 16 /decl/material/solid/ice/rubenium + name = "rubenium" + use_name = null + codex_name = null + solid_name = null + liquid_name = null + gas_name = null heating_products = list( /decl/material/solid/metal/radium = 0.4, /decl/material/liquid/water = 0.4, /decl/material/liquid/acetone = 0.2 ) - name = "rubenium ice" - ore_name = "rubenium ice" + uid = "solid_ice_rubenium" value = 0.4 - sparse_material_weight = 35 - rich_material_weight = 12 + sparse_material_weight = 20 + rich_material_weight = 13 /decl/material/solid/ice/trigarite + name = "trigarite" + use_name = null + codex_name = null + solid_name = null + liquid_name = null + gas_name = null heating_products = list( /decl/material/liquid/acid/hydrochloric = 0.2, /decl/material/liquid/water = 0.2, /decl/material/liquid/mercury = 0.6 ) - name = "trigarite ice" - ore_name = "trigarite ice" + uid = "solid_ice_trigarite" value = 0.5 - sparse_material_weight = 38 - rich_material_weight = 23 + sparse_material_weight = 20 + rich_material_weight = 15 /decl/material/solid/ice/ediroite + name = "ediroite" + use_name = null + codex_name = null + solid_name = null + liquid_name = null + gas_name = null heating_products = list( - /decl/material/gas/ammonia = 0.4, - /decl/material/liquid/water = 0.2, - /decl/material/liquid/ethanol = 0.4 + /decl/material/gas/ammonia = 0.05, + /decl/material/liquid/water = 0.55, + /decl/material/liquid/alcohol/ethanol = 0.4 ) - name = "ediroite ice" - ore_name = "ediroite ice" + uid = "solid_ice_ediroite" value = 0.2 - sparse_material_weight = 21 - rich_material_weight = 39 + sparse_material_weight = 20 + rich_material_weight = 16 + +/decl/material/solid/ice/hydrogen + name = "hydrogen ice" + use_name = null + codex_name = null + solid_name = null + liquid_name = null + gas_name = null + uid = "solid_ice_hydrogen" + heating_products = list( + /decl/material/gas/hydrogen = 0.05, + /decl/material/liquid/water = 0.92, + /decl/material/gas/hydrogen/deuterium = 0.02, + /decl/material/gas/hydrogen/tritium = 0.01 + ) + value = 0.3 + sparse_material_weight = 20 + rich_material_weight = 20 + +//////////////////////////////////// +// Gas Hydrates/Clathrates +//////////////////////////////////// + +//Hydrates gas are basically bubbles of gas trapped in water ice lattices +/decl/material/solid/ice/hydrate + codex_name = null + use_name = null + solid_name = null + liquid_name = null + gas_name = null + uid = "solid_hydrate" + heating_point = T0C //the melting point is always water's + abstract_type = /decl/material/solid/ice/hydrate + +//Little helper macro, since hydrates are all basically the same +// DISPLAY_NAME is needed because of compounds with white spaces in their names +#define DECLARE_HYDRATE_DNAME_PATH(PATH, NAME, DISPLAY_NAME) \ +/decl/material/solid/ice/hydrate/##NAME/uid = "solid_hydrate_" + #NAME; \ +/decl/material/solid/ice/hydrate/##NAME/name = DISPLAY_NAME + " hydrate"; \ +/decl/material/solid/ice/hydrate/##NAME/heating_products = list( \ + PATH = 0.1, \ + /decl/material/liquid/water = 0.9 \ +); \ +/decl/material/solid/ice/hydrate/##NAME + +#define DECLARE_HYDRATE_DNAME(NAME, DISPLAY_NAME) DECLARE_HYDRATE_DNAME_PATH(/decl/material/gas/##NAME, NAME, DISPLAY_NAME) +#define DECLARE_HYDRATE(NAME) DECLARE_HYDRATE_DNAME(NAME, #NAME) + +// +// Definitions +// +DECLARE_HYDRATE(methane) + uid = "solid_ice_methane" + value = 0.3 + sparse_material_weight = 10 + rich_material_weight = 10 + +DECLARE_HYDRATE(oxygen) + uid = "solid_ice_oxygen" + sparse_material_weight = 10 + rich_material_weight = 10 + +DECLARE_HYDRATE(nitrogen) + uid = "solid_ice_nitrogen" + sparse_material_weight = 10 + rich_material_weight = 10 + +DECLARE_HYDRATE_DNAME(carbon_dioxide, "carbon dioxide") + uid = "solid_ice_carbon_dioxide" + sparse_material_weight = 8 + rich_material_weight = 8 + +DECLARE_HYDRATE(argon) + uid = "solid_ice_argon" + sparse_material_weight = 8 + rich_material_weight = 8 + +DECLARE_HYDRATE(neon) + uid = "solid_ice_neon" + sparse_material_weight = 15 + rich_material_weight = 15 + +DECLARE_HYDRATE(krypton) + uid = "solid_ice_krypton" + sparse_material_weight = 12 + rich_material_weight = 12 + +DECLARE_HYDRATE(xenon) + uid = "solid_ice_xenon" + sparse_material_weight = 12 + rich_material_weight = 12 + +#undef DECLARE_HYDRATE_DNAME_PATH +#undef DECLARE_HYDRATE_DNAME +#undef DECLARE_HYDRATE \ No newline at end of file diff --git a/code/modules/materials/definitions/solids/materials_solid_metal.dm b/code/modules/materials/definitions/solids/materials_solid_metal.dm index 4cde9f3eab10..51f1a2db4bfd 100644 --- a/code/modules/materials/definitions/solids/materials_solid_metal.dm +++ b/code/modules/materials/definitions/solids/materials_solid_metal.dm @@ -1,53 +1,96 @@ /decl/material/solid/metal name = null - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" construction_difficulty = MAT_VALUE_HARD_DIY reflectiveness = MAT_VALUE_SHINY removed_by_welder = TRUE wall_name = "bulkhead" weight = MAT_VALUE_HEAVY - hardness = MAT_VALUE_FLEXIBLE + hardness = MAT_VALUE_RIGID wall_support_value = MAT_VALUE_HEAVY - -/decl/material/solid/metal/New() - if(!ore_smelts_to) - ore_smelts_to = type - ..() + wall_flags = PAINT_PAINTABLE + wall_blend_icons = list( + 'icons/turf/walls/wood.dmi' = TRUE, + 'icons/turf/walls/stone.dmi' = TRUE + ) + default_solid_form = /obj/item/stack/material/ingot + table_icon_base = "metal" + door_icon_base = "metal" + abstract_type = /decl/material/solid/metal + icon_base = 'icons/turf/walls/metal.dmi' + icon_reinf = 'icons/turf/walls/reinforced_metal.dmi' + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + tensile_strength = 0.8 // metal wire is probably better than plastic? + forgable = TRUE + glows_with_heat = TRUE /decl/material/solid/metal/uranium name = "uranium" + codex_name = "elemental uranium" + uid = "solid_uranium" lore_text = "A silvery-white metallic chemical element in the actinide series, weakly radioactive. Commonly used as fuel in fission reactors." - mechanics_text = "Uranium ingots are used as fuel in some forms of portable generator." + mechanics_text = "Uranium can be used as fuel in fission reactors." taste_description = "the inside of a reactor" - stack_type = /obj/item/stack/material/uranium + melting_point = 1407 + boiling_point = 4074 + flags = MAT_FLAG_FISSIBLE radioactivity = 12 - icon_base = "stone" + icon_base = 'icons/turf/walls/stone.dmi' + wall_flags = 0 table_icon_base = "stone" - icon_reinf = "reinf_stone" + icon_reinf = 'icons/turf/walls/reinforced_stone.dmi' color = "#007a00" - stack_origin_tech = "{'materials':5}" + weight = MAT_VALUE_VERY_HEAVY + stack_origin_tech = @'{"materials":5}' reflectiveness = MAT_VALUE_MATTE value = 1.5 + default_solid_form = /obj/item/stack/material/puck + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + neutron_cross_section = 10 + neutron_interactions = list( + INTERACTION_FISSION = 1500, + INTERACTION_ABSORPTION = 4000, + INTERACTION_SCATTER = 5000 + ) + fission_products = list( + /decl/material/solid/metal/depleted_uranium = 0.6, + /decl/material/solid/metal/fission_byproduct = 0.4 + ) + absorption_products = list( + /decl/material/solid/metal/neptunium = 1 + ) + neutron_production = 10 + neutron_absorption = 6 + moderation_target = 3000 + fission_heat = 35000 + fission_energy = 4000 /decl/material/solid/metal/radium name = "radium" + uid = "solid_radium" lore_text = "Radium is an alkaline earth metal. It is extremely radioactive." + mechanics_text = "Radium can be used as a neutron source in fission reactors." taste_description = "the color blue, and regret" + melting_point = 1234 + boiling_point = 1414 color = "#c7c7c7" value = 0.5 radioactivity = 18 /decl/material/solid/metal/gold name = "gold" + adjective_name = "golden" + codex_name = "elemental gold" + uid = "solid_gold" lore_text = "A heavy, soft, ductile metal. Once considered valuable enough to back entire currencies, now predominantly used in corrosion-resistant electronics." - stack_type = /obj/item/stack/material/gold + melting_point = 1337 + boiling_point = 2974 color = COLOR_GOLD hardness = MAT_VALUE_FLEXIBLE + 5 integrity = 100 - stack_origin_tech = "{'materials':4}" - ore_smelts_to = /decl/material/solid/metal/gold - ore_result_amount = 5 + stack_origin_tech = @'{"materials":4}' + ore_result_amount = 1 ore_name = "native gold" ore_spread_chance = 10 ore_scan_icon = "mineral_uncommon" @@ -59,26 +102,83 @@ ore_data_value = 2 /decl/material/solid/metal/bronze - lore_text = "An alloy of copper and tin." - color = "#edd12f" + name = "bronze" + codex_name = "bronze alloy" + uid = "solid_bronze" + lore_text = "An alloy of copper and tin. Once used in weapons and laboring tools." + melting_point = 1184 + boiling_point = 2574 + color = "#ccbc63" + brute_armor = 3 + hardness = MAT_VALUE_RIGID + 10 + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null value = 1.2 + default_solid_form = /obj/item/stack/material/sheet + +/decl/material/solid/metal/blackbronze + name = "black bronze" + uid = "solid_black_bronze" + lore_text = "An alloy of copper and silver. Used in ancient ceremonial gear." + color = "#3f352a" + brute_armor = 4 + hardness = MAT_VALUE_HARD + reflectiveness = MAT_VALUE_MATTE + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null + value = 1.4 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + +/decl/material/solid/metal/redgold + name = "red gold" + uid = "solid_red_gold" + lore_text = "An alloy of copper and gold. A soft metal used for its ornamental properties." + color = "#ff7a59" + reflectiveness = MAT_VALUE_SHINY + value = 1.4 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + +/decl/material/solid/metal/brass + name = "brass" + uid = "solid_brass" + lore_text = "An alloy of copper and zinc. Renowned for its golden color." + melting_point = 1174 + boiling_point = 1374 + color = "#dab900" + reflectiveness = MAT_VALUE_VERY_SHINY + value = 1.2 + default_solid_form = /obj/item/stack/material/sheet + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE /decl/material/solid/metal/copper name = "copper" + uid = "solid_copper" + lore_text = "A metal used in some components and many alloys. Known for its color-shifting properties when oxidized." + melting_point = 1357 + boiling_point = 2774 color = COLOR_COPPER weight = MAT_VALUE_NORMAL hardness = MAT_VALUE_FLEXIBLE + 10 - stack_origin_tech = "{'materials':2}" + stack_origin_tech = @'{"materials":2}' + temperature_burn_milestone_material = /decl/material/solid/metal/copper /decl/material/solid/metal/silver name = "silver" + uid = "solid_silver" lore_text = "A soft, white, lustrous transition metal. Has many and varied industrial uses in electronics, solar panels and mirrors." - stack_type = /obj/item/stack/material/silver + melting_point = 1234 + boiling_point = 2444 color = "#d1e6e3" hardness = MAT_VALUE_FLEXIBLE + 10 - stack_origin_tech = "{'materials':3}" - ore_smelts_to = /decl/material/solid/metal/silver - ore_result_amount = 5 + stack_origin_tech = @'{"materials":3}' + ore_result_amount = 1 ore_spread_chance = 10 ore_name = "native silver" ore_scan_icon = "mineral_uncommon" @@ -91,188 +191,180 @@ /decl/material/solid/metal/steel name = "steel" + codex_name = "carbon steel" + uid = "solid_steel" lore_text = "A strong, flexible alloy of iron and carbon. Probably the single most fundamentally useful and ubiquitous substance in human space." - stack_type = /obj/item/stack/material/steel + melting_point = 1734 + boiling_point = 2774 weight = MAT_VALUE_NORMAL wall_support_value = MAT_VALUE_VERY_HEAVY // Ideal construction material. + hardness = MAT_VALUE_HARD + 5 integrity = 150 brute_armor = 5 - icon_base = "solid" - icon_reinf = "reinf_over" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null color = COLOR_STEEL hitsound = 'sound/weapons/smash.ogg' - alloy_materials = list(/decl/material/solid/metal/iron = 1875, /decl/material/solid/mineral/graphite = 1875) - alloy_product = TRUE - ore_smelts_to = /decl/material/solid/metal/steel construction_difficulty = MAT_VALUE_NORMAL_DIY value = 1.1 + dissolves_in = MAT_SOLVENT_STRONGEST dissolves_into = list( /decl/material/solid/metal/iron = 0.98, /decl/material/solid/carbon = 0.02 ) - -/decl/material/solid/metal/steel/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe_list("office chairs",list( - new/datum/stack_recipe/furniture/chair/office/dark(src), - new/datum/stack_recipe/furniture/chair/office/light(src) - )) - . += new/datum/stack_recipe_list("comfy office chairs", create_recipe_list(/datum/stack_recipe/furniture/chair/office/comfy)) - . += new/datum/stack_recipe_list("comfy chairs", create_recipe_list(/datum/stack_recipe/furniture/chair/comfy)) - . += new/datum/stack_recipe_list("armchairs", create_recipe_list(/datum/stack_recipe/furniture/chair/arm)) - . += new/datum/stack_recipe/key(src) - . += new/datum/stack_recipe/furniture/table_frame(src) - . += new/datum/stack_recipe/furniture/rack(src) - . += new/datum/stack_recipe/furniture/closet(src) - . += new/datum/stack_recipe/furniture/canister(src) - . += new/datum/stack_recipe/furniture/tank(src) - . += new/datum/stack_recipe/cannon(src) - . += create_recipe_list(/datum/stack_recipe/tile/metal) - . += new/datum/stack_recipe/furniture/computerframe(src) - . += new/datum/stack_recipe/furniture/machine(src) - . += new/datum/stack_recipe/furniture/turret(src) - . += new/datum/stack_recipe_list("airlock assemblies", create_recipe_list(/datum/stack_recipe/furniture/door_assembly)) - . += new/datum/stack_recipe/grenade(src) - . += new/datum/stack_recipe/light(src) - . += new/datum/stack_recipe/light_small(src) - . += new/datum/stack_recipe/light_switch(src) - . += new/datum/stack_recipe/light_switch/windowtint(src) - . += new/datum/stack_recipe/apc(src) - . += new/datum/stack_recipe/air_alarm(src) - . += new/datum/stack_recipe/fire_alarm(src) - . += new/datum/stack_recipe_list("modular computer frames", create_recipe_list(/datum/stack_recipe/computer)) - . += new/datum/stack_recipe/furniture/coffin(src) - . += new/datum/stack_recipe/butcher_hook(src) + default_solid_form = /obj/item/stack/material/sheet + ferrous = TRUE /decl/material/solid/metal/steel/holographic name = "holographic steel" - stack_type = null - shard_type = SHARD_NONE - conductive = 0 - alloy_materials = null - alloy_product = FALSE - hidden_from_codex = TRUE - value = 0 + uid = "solid_holographic_steel" + holographic = TRUE -/decl/material/solid/metal/steel/holographic/get_recipes(reinf_mat) - return list() +/decl/material/solid/metal/stainlesssteel + name = "stainless steel" + uid = "solid_stainless_steel" + lore_text = "A reflective alloy of steel and chromium. Used for its reflective and sturdy properties." + melting_point = 1784 + boiling_point = null + wall_support_value = MAT_VALUE_HEAVY + hardness = MAT_VALUE_HARD + 5 + integrity = 175 + burn_armor = 10 + color = "#a5a5a5" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null + hitsound = 'sound/weapons/smash.ogg' + construction_difficulty = MAT_VALUE_VERY_HARD_DIY + reflectiveness = MAT_VALUE_MIRRORED + value = 1.3 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null + ferrous = TRUE /decl/material/solid/metal/aluminium name = "aluminium" + uid = "solid_aluminium" lore_text = "A low-density ductile metal with a silvery-white sheen." - stack_type = /obj/item/stack/material/aluminium + melting_point = 932 + boiling_point = 2474 integrity = 125 weight = MAT_VALUE_LIGHT - icon_base = "solid" - icon_reinf = "reinf_over" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null color = "#cccdcc" hitsound = 'sound/weapons/smash.ogg' taste_description = "metal" - -/decl/material/solid/metal/aluminium/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/grenade(src) + default_solid_form = /obj/item/stack/material/sheet/shiny /decl/material/solid/metal/aluminium/holographic name = "holoaluminium" - stack_type = null - shard_type = SHARD_NONE - conductive = 0 - alloy_materials = null - alloy_product = FALSE - hidden_from_codex = TRUE - -/decl/material/solid/metal/aluminium/holographic/get_recipes(reinf_mat) - return list() + uid = "solid_holographic_aluminium" + holographic = TRUE /decl/material/solid/metal/plasteel name = "plasteel" + codex_name = "plasteel alloy" + uid = "solid_plasteel" lore_text = "An alloy of steel and platinum. When regular high-tensile steel isn't tough enough to get the job done, the smart consumer turns to frankly absurd alloys of steel and platinum." - stack_type = /obj/item/stack/material/plasteel integrity = 400 melting_point = 6000 - icon_base = "solid" - icon_reinf = "reinf_over" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null color = "#a8a9b2" explosion_resistance = 25 - brute_armor = 6 + brute_armor = 8 burn_armor = 10 hardness = MAT_VALUE_VERY_HARD - stack_origin_tech = "{'materials':2}" + stack_origin_tech = @'{"materials":2}' hitsound = 'sound/weapons/smash.ogg' - alloy_materials = list(/decl/material/solid/metal/steel = 2500, /decl/material/solid/metal/platinum = 1250) - alloy_product = TRUE - ore_smelts_to = /decl/material/solid/metal/plasteel value = 1.4 reflectiveness = MAT_VALUE_MATTE + default_solid_form = /obj/item/stack/material/sheet/reinforced + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null + ferrous = TRUE -/decl/material/solid/metal/plasteel/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/ai_core(src) - . += new/datum/stack_recipe/furniture/crate(src) - . += new/datum/stack_recipe/grip(src) - -/decl/material/solid/metal/plasteel/titanium +/decl/material/solid/metal/titanium name = "titanium" + uid = "solid_titanium" lore_text = "A light, strong, corrosion-resistant metal. Perfect for cladding high-velocity ballistic supply pods." brute_armor = 10 burn_armor = 8 integrity = 200 - melting_point = 3000 + melting_point = 1944 + boiling_point = 3474 weight = MAT_VALUE_LIGHT - stack_type = /obj/item/stack/material/titanium - icon_base = "metal" + icon_base = 'icons/turf/walls/metal.dmi' + wall_flags = PAINT_PAINTABLE door_icon_base = "metal" color = "#d1e6e3" - icon_reinf = "reinf_metal" + icon_reinf = 'icons/turf/walls/reinforced_metal.dmi' construction_difficulty = MAT_VALUE_VERY_HARD_DIY - alloy_materials = null - alloy_product = FALSE value = 1.5 + explosion_resistance = 25 + hardness = MAT_VALUE_VERY_HARD + stack_origin_tech = @'{"materials":2}' + hitsound = 'sound/weapons/smash.ogg' + reflectiveness = MAT_VALUE_MATTE + default_solid_form = /obj/item/stack/material/sheet/reinforced + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null /decl/material/solid/metal/plasteel/ocp name = "osmium-carbide plasteel" - stack_type = /obj/item/stack/material/ocp + codex_name = null + uid = "solid_osmium_carbide_plasteel" integrity = 200 melting_point = 12000 - icon_base = "solid" - icon_reinf = "reinf_over" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null color = "#9bc6f2" brute_armor = 4 burn_armor = 20 - stack_origin_tech = "{'materials':3}" - alloy_materials = list(/decl/material/solid/metal/plasteel = 7500, /decl/material/solid/metal/osmium = 3750) + stack_origin_tech = @'{"materials":3}' construction_difficulty = MAT_VALUE_VERY_HARD_DIY - alloy_product = TRUE value = 1.8 + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_NOWHERE /decl/material/solid/metal/osmium name = "osmium" + uid = "solid_osmium" lore_text = "An extremely hard form of platinum." - stack_type = /obj/item/stack/material/osmium + melting_point = 3307 + boiling_point = 5285 color = "#9999ff" - stack_origin_tech = "{'materials':5}" + stack_origin_tech = @'{"materials":5}' construction_difficulty = MAT_VALUE_VERY_HARD_DIY - ore_smelts_to = /decl/material/solid/metal/osmium value = 1.3 /decl/material/solid/metal/platinum name = "platinum" + uid = "solid_platinum" lore_text = "A very dense, unreactive, precious metal. Has many industrial uses, particularly as a catalyst." - stack_type = /obj/item/stack/material/platinum + melting_point = 2041 + boiling_point = 4098 color = "#deddff" weight = MAT_VALUE_VERY_HEAVY wall_support_value = MAT_VALUE_VERY_HEAVY - stack_origin_tech = "{'materials':2}" - ore_smelts_to = /decl/material/solid/metal/platinum + hardness = MAT_VALUE_VERY_HARD + stack_origin_tech = @'{"materials":2}' ore_compresses_to = /decl/material/solid/metal/osmium - ore_result_amount = 5 + ore_result_amount = 1 ore_spread_chance = 10 ore_name = "raw platinum" ore_scan_icon = "mineral_rare" @@ -285,21 +377,83 @@ /decl/material/solid/metal/iron name = "iron" + uid = "solid_iron" lore_text = "A ubiquitous, very common metal. The epitaph of stars and the primary ingredient in Earth's core." - stack_type = /obj/item/stack/material/iron + melting_point = 1811 + boiling_point = 3134 color = "#5c5454" hitsound = 'sound/weapons/smash.ogg' + hardness = MAT_VALUE_HARD construction_difficulty = MAT_VALUE_NORMAL_DIY reflectiveness = MAT_VALUE_MATTE taste_description = "metal" + ferrous = TRUE + temperature_burn_milestone_material = /decl/material/solid/metal/iron -/decl/material/solid/metal/iron/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/solid/metal/iron/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(M.has_trait(/decl/trait/metabolically_inert)) + return M.add_chemical_effect(CE_BLOODRESTORE, 8 * removed) +/decl/material/solid/metal/tin + name = "tin" + uid = "solid_tin" + lore_text = "A soft metal that can be cut without much force. Used in many alloys." + melting_point = 505 + boiling_point = 2875 + color = "#c5c5a8" + hardness = MAT_VALUE_FLEXIBLE + construction_difficulty = MAT_VALUE_EASY_DIY + reflectiveness = MAT_VALUE_MATTE + +/decl/material/solid/metal/lead + name = "lead" + uid = "solid_lead" + lore_text = "A very soft, heavy and poisonous metal. You probably shouldn't lick it." + melting_point = 600 + boiling_point = 2022 + color = "#3f3f4d" + hardness = MAT_VALUE_FLEXIBLE + construction_difficulty = MAT_VALUE_NORMAL_DIY + reflectiveness = MAT_VALUE_MATTE + taste_description = "metallic sugar" + toxicity = 1 + temperature_burn_milestone_material = /decl/material/solid/metal/lead + +/decl/material/solid/metal/zinc + name = "zinc" + uid = "solid_zinc" + lore_text = "A dull-looking metal with some use in alloying." + melting_point = 692 + boiling_point = 1180 + color = "#92aae4" + construction_difficulty = MAT_VALUE_NORMAL_DIY + reflectiveness = MAT_VALUE_MATTE + +/decl/material/solid/metal/chromium + name = "chromium" + uid = "solid_chromium" + lore_text = "A heavy metal with near perfect reflectiveness. Used in stainless alloys." + color = "#dadada" + integrity = 200 + burn_armor = 15 // Strong against laser weaponry, but not as good as OCP. + melting_point = 2180 + boiling_point = 2944 + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null + value = 1.5 + weight = MAT_VALUE_VERY_HEAVY + hardness = MAT_VALUE_HARD + 10 + construction_difficulty = MAT_VALUE_VERY_HARD_DIY + reflectiveness = MAT_VALUE_MIRRORED + // Adminspawn only, do not let anyone get this. -/decl/material/solid/metal/voxalloy +/decl/material/solid/metal/alienalloy name = "dense alloy" - stack_type = null + uid = "solid_alienalloy" color = "#6c7364" integrity = 1200 melting_point = 6000 // Hull plating. @@ -309,16 +463,30 @@ wall_support_value = MAT_VALUE_VERY_HEAVY hidden_from_codex = TRUE value = 3 + default_solid_form = /obj/item/stack/material/cubes + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + use_reinf_state = null + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES // Likewise. -/decl/material/solid/metal/voxalloy/elevatorium +/decl/material/solid/metal/alienalloy/elevatorium name = "elevator panelling" + uid = "solid_elevator" color = "#666666" hidden_from_codex = TRUE + default_solid_form = /obj/item/stack/material/sheet + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE /decl/material/solid/metal/tungsten name = "tungsten" + uid = "solid_tungsten" lore_text = "A chemical element, and a strong oxidising agent." + weight = MAT_VALUE_VERY_HEAVY taste_mult = 0 //no taste color = "#dcdcdc" value = 0.5 + melting_point = 3422 CELSIUS diff --git a/code/modules/materials/definitions/solids/materials_solid_mineral.dm b/code/modules/materials/definitions/solids/materials_solid_mineral.dm index ac4538e62783..40396f7316e7 100644 --- a/code/modules/materials/definitions/solids/materials_solid_mineral.dm +++ b/code/modules/materials/definitions/solids/materials_solid_mineral.dm @@ -1,113 +1,135 @@ -/decl/material/solid/mineral/pitchblende +/decl/material/solid/pitchblende name = "pitchblende" + uid = "solid_pitchblende" color = "#917d1a" - ore_smelts_to = /decl/material/solid/metal/uranium - ore_result_amount = 5 + ore_result_amount = 1 ore_spread_chance = 10 ore_name = "pitchblende" ore_scan_icon = "mineral_uncommon" - stack_origin_tech = "{'materials':5}" + stack_origin_tech = @'{"materials":5}' xarch_source_mineral = /decl/material/solid/phosphorus ore_icon_overlay = "nugget" - sheet_singular_name = "brick" - sheet_plural_name = "bricks" value = 0.8 sparse_material_weight = 8 rich_material_weight = 10 dissolves_into = list( - /decl/material/solid/metal/uranium = 0.5, - /decl/material/solid/metal/radium = 0.5 + /decl/material/solid/metal/uranium = 0.6, + /decl/material/solid/metal/radium = 0.3, + /decl/material/solid/slag = 0.1 ) ore_type_value = ORE_NUCLEAR ore_data_value = 3 -/decl/material/solid/mineral/graphite +/decl/material/solid/graphite name = "graphite" + codex_name = "loose graphite" + uid = "solid_graphite" color = "#444444" ore_name = "graphite" - ore_result_amount = 5 + ore_result_amount = 2 ore_spread_chance = 25 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" ore_type_value = ORE_SURFACE ore_data_value = 1 + melting_point = 4074 + boiling_point = 4474 + ignition_point = 774 + accelerant_value = 0.8 + burn_product = /decl/material/gas/carbon_monoxide value = 0.8 sparse_material_weight = 35 rich_material_weight = 20 dirtiness = 15 + burn_temperature = 1350 CELSIUS + + flags = MAT_FLAG_FISSIBLE + neutron_cross_section = 30 + neutron_interactions = list( + INTERACTION_SCATTER = 2000 + ) + moderation_target = 1500 dissolves_into = list( /decl/material/solid/carbon = 0.6, /decl/material/liquid/plasticide = 0.2, /decl/material/liquid/acetone = 0.2 ) -/decl/material/solid/mineral/quartz +/decl/material/solid/quartz name = "quartz" + uid = "solid_quartz" ore_name = "quartz" opacity = 0.5 - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" + melting_point = 1744 + boiling_point = 2504 color = "#effffe" reflectiveness = MAT_VALUE_SHINY + hardness = MAT_VALUE_VERY_HARD - 5 // Hard enough to whet steel. sparse_material_weight = 3 rich_material_weight = 1 dissolves_into = list( /decl/material/solid/silicon = 1 ) -/decl/material/solid/mineral/pyrite - name = "pyrite" +/decl/material/solid/pyrite + name = "fool's gold" + uid = "solid_pyrite" ore_name = "pyrite" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" color = "#ccc9a3" reflectiveness = MAT_VALUE_SHINY value = 0.8 - sparse_material_weight = 3 - rich_material_weight = 1 + sparse_material_weight = 9 + rich_material_weight = 3 dissolves_into = list( /decl/material/solid/sulfur = 0.75, - /decl/material/solid/metal/iron = 0.25 + /decl/material/solid/metal/iron = 0.25 ) -/decl/material/solid/mineral/spodumene +/decl/material/solid/spodumene name = "spodumene" + uid = "solid_spodumene" ore_name = "spodumene" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" color = "#e5becb" value = 0.8 - sparse_material_weight = 3 - rich_material_weight = 1 + sparse_material_weight = 9 + rich_material_weight = 3 dissolves_into = list( /decl/material/solid/lithium = 1 ) -/decl/material/solid/mineral/cinnabar +/decl/material/solid/cinnabar name = "cinnabar" + uid = "solid_cinnabar" ore_name = "cinnabar" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" color = "#e54e4e" value = 0.8 - sparse_material_weight = 3 - rich_material_weight = 1 + sparse_material_weight = 9 + rich_material_weight = 3 dissolves_into = list( /decl/material/liquid/mercury = 1 ) -/decl/material/solid/mineral/phosphorite +/decl/material/solid/phosphorite name = "phosphorite" + uid = "solid_phosphorite" ore_name = "phosphorite" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" @@ -116,34 +138,38 @@ ) color = "#832828" value = 0.8 - sparse_material_weight = 3 - rich_material_weight = 1 + sparse_material_weight = 9 + rich_material_weight = 3 lore_text = "A chemical element, the backbone of biological energy carriers." taste_description = "vinegar" -/decl/material/solid/mineral/sodiumchloride +/decl/material/solid/sodiumchloride name = "sodium chloride" + uid = "solid_sodium_chloride" lore_text = "A chemical element, readily reacts with water." ore_name = "rock salt" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" color = "#d1c0bc" value = 0.8 - sparse_material_weight = 3 - rich_material_weight = 1 + sparse_material_weight = 12 + rich_material_weight = 4 taste_description = "salt" overdose = REAGENTS_OVERDOSE dissolves_into = list( /decl/material/solid/sodium = 1 ) + solid_name = "salt" + soup_hot_desc = null -/decl/material/solid/mineral/potash +/decl/material/solid/potash name = "potash" + uid = "solid_potash" lore_text = "A soft, low-melting solid that can easily be cut with a knife. Reacts violently with water." ore_name = "potash" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" @@ -156,22 +182,30 @@ /decl/material/solid/potassium = 1 ) -/decl/material/solid/mineral/potassium/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - if(volume > 3) +/decl/material/solid/potash/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/affect_volume = REAGENT_VOLUME(holder, src) + if(affect_volume > 3) M.add_chemical_effect(CE_PULSE, 1) - if(volume > 10) + if(affect_volume > 10) M.add_chemical_effect(CE_PULSE, 1) -/decl/material/solid/mineral/bauxite +/decl/material/solid/bauxite name = "bauxite" + uid = "solid_bauxite" ore_name = "bauxite" - ore_result_amount = 10 + ore_result_amount = 3 ore_spread_chance = 10 ore_scan_icon = "mineral_common" ore_icon_overlay = "lump" color = "#d8ad97" - ore_smelts_to = /decl/material/solid/metal/aluminium + heating_products = list( + /decl/material/solid/metal/aluminium = 0.8, + /decl/material/solid/slag = 0.2 + ) + heating_point = GENERIC_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null value = 0.8 sparse_material_weight = 3 rich_material_weight = 1 @@ -179,39 +213,102 @@ /decl/material/solid/metal/aluminium = 1 ) -/decl/material/solid/mineral/sand +/decl/material/solid/sand name = "sand" - stack_type = null + uid = "solid_sand" color = "#e2dbb5" - ore_smelts_to = /decl/material/solid/glass + heating_products = list(/decl/material/solid/glass = 1) + heating_point = 2000 CELSIUS + heating_sound = null + heating_message = null ore_compresses_to = /decl/material/solid/stone/sandstone ore_name = "sand" ore_icon_overlay = "dust" ore_type_value = ORE_SURFACE ore_data_value = 1 value = 0.8 + hardness = MAT_VALUE_MALLEABLE + integrity = 10 dirtiness = 15 dissolves_into = list( /decl/material/solid/silicon = 1 ) + dug_drop_type = /obj/item/stack/material/ore/handful + default_solid_form = /obj/item/stack/material/ore/handful + can_backfill_floor_type = /decl/flooring/sand + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' -/decl/material/solid/mineral/clay +/decl/material/solid/clay name = "clay" - stack_type = null - color = COLOR_OFF_WHITE + codex_name = "raw clay" + uid = "solid_clay" + color = "#807f7a" ore_name = "clay" - ore_icon_overlay = "lump" - ore_smelts_to = /decl/material/solid/stone/ceramic ore_compresses_to = null - ore_icon_overlay = "dust" + ore_icon_overlay = "lump_large" + ore_type_value = ORE_SURFACE + ore_data_value = 1 value = 0.8 + hardness = MAT_VALUE_MALLEABLE + integrity = 10 + dirtiness = 10 + dug_drop_type = /obj/item/stack/material/lump/large + default_solid_form = /obj/item/stack/material/lump/large + bakes_into_material = /decl/material/solid/stone/pottery + temperature_burn_milestone_material = /decl/material/solid/clay + melting_point = null // Clay is already almost a liquid... + // lower than the temperature expected from a kiln so that clay can be used to make bricks to make a high-temperature kiln. + bakes_into_at_temperature = 950 CELSIUS + can_backfill_floor_type = /decl/flooring/clay + gemstone_chance = 0.01 + gemstone_types = list(/decl/material/solid/gemstone/sapphire = 1) + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + +/decl/material/solid/soil + name = "soil" + codex_name = "soil" + uid = "solid_soil" + color = "#41311b" + value = 0 + default_solid_form = /obj/item/stack/material/lump/large + melting_point = null + hardness = MAT_VALUE_MALLEABLE + integrity = 10 + dirtiness = 30 + dug_drop_type = /obj/item/stack/material/lump/large + tillable = TRUE + can_backfill_floor_type = list( + /decl/flooring/mud, + /decl/flooring/dirt + ) + solution_name = "mud" + coated_adjective = "muddy" + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + +// todo: make mud either its own material or a mix of dirt and water +// or let dirt be in the liquid volumes list for mud? +// would a ball of mud just be a ball of dirt coated with water? +// or would water be part of its matter? +// well anyway. +// for now, at least, we assume dirt coatings are always mud. +/decl/material/solid/soil/get_primary_coating_name(datum/reagents/coating) + return solution_name -/decl/material/solid/mineral/hematite +/decl/material/solid/hematite name = "hematite" - stack_type = null + uid = "solid_hematite" color = "#aa6666" - ore_smelts_to = /decl/material/solid/metal/iron - ore_result_amount = 5 + heating_products = list( + /decl/material/solid/metal/iron = 0.8, + /decl/material/solid/slag = 0.2 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_result_amount = 2 ore_spread_chance = 25 ore_scan_icon = "mineral_common" ore_name = "hematite" @@ -221,13 +318,20 @@ rich_material_weight = 20 ore_type_value = ORE_SURFACE ore_data_value = 1 + ferrous = TRUE -/decl/material/solid/mineral/rutile +/decl/material/solid/rutile name = "rutile" - stack_type = null + uid = "solid_rutile" color = "#d8ad97" - ore_smelts_to = /decl/material/solid/metal/plasteel/titanium - ore_result_amount = 5 + heating_products = list( + /decl/material/solid/metal/titanium = 0.8, + /decl/material/solid/slag = 0.2 + ) + heating_point = GENERIC_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_result_amount = 2 ore_spread_chance = 15 ore_scan_icon = "mineral_uncommon" ore_name = "rutile" @@ -238,10 +342,18 @@ sparse_material_weight = 3 rich_material_weight = 1 -/decl/material/solid/mineral/tetrahedrite +/decl/material/solid/tetrahedrite name = "tetrahedrite" - ore_smelts_to = /decl/material/solid/metal/copper - ore_result_amount = 5 + uid = "solid_tetrahedrite" + heating_products = list( + /decl/material/solid/metal/copper = 0.4, + /decl/material/solid/metal/silver = 0.4, + /decl/material/solid/slag = 0.2 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_result_amount = 2 ore_spread_chance = 10 ore_name = "tetrahedrite" ore_scan_icon = "mineral_common" @@ -249,4 +361,310 @@ dissolves_into = list( /decl/material/solid/metal/copper = 0.5, /decl/material/solid/metal/silver = 0.5 - ) \ No newline at end of file + ) + +/decl/material/solid/magnetite + name = "magnetite" + uid = "solid_magnetite" + color = "#aa6666" + heating_products = list( + /decl/material/solid/metal/iron = 0.8, + /decl/material/solid/metal/copper = 0.1, + /decl/material/solid/slag = 0.1 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_result_amount = 2 + ore_spread_chance = 20 + ore_scan_icon = "mineral_common" + ore_name = "magnetite" + ore_icon_overlay = "lump" + value = 0.9 + sparse_material_weight = 20 + rich_material_weight = 10 + ore_type_value = ORE_SURFACE + ore_data_value = 1 + dissolves_into = list( + /decl/material/solid/metal/iron = 0.8, + /decl/material/solid/metal/copper = 0.1, + /decl/material/solid/sulfur = 0.1 + ) + +/decl/material/solid/chalcopyrite + name = "chalcopyrite" + uid = "solid_chalcopyrite" + color = "#9e9357" + heating_products = list( + /decl/material/solid/metal/copper = 0.6, + /decl/material/solid/slag = 0.4 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_result_amount = 2 + ore_spread_chance = 20 + ore_scan_icon = "mineral_common" + ore_name = "chalcopyrite" + ore_icon_overlay = "lump" + value = 0.9 + sparse_material_weight = 20 + rich_material_weight = 10 + ore_type_value = ORE_SURFACE + ore_data_value = 1 + dissolves_into = list( + /decl/material/solid/metal/iron = 0.1, + /decl/material/solid/metal/copper = 0.6, + /decl/material/solid/sulfur = 0.3 + ) + +/decl/material/solid/densegraphite + name = "dense graphite" + uid = "solid_dense_graphite" + color = "#2c2c2c" + heating_products = list( + /decl/material/solid/gemstone/diamond = 0.02, + /decl/material/solid/carbon = 0.98 + ) + burn_temperature = 1750 CELSIUS + heating_point = GENERIC_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "dense graphite" + ore_result_amount = 2 + ore_spread_chance = 10 + ore_scan_icon = "mineral_uncommon" + ore_icon_overlay = "lump" + ore_type_value = ORE_SURFACE + ore_data_value = 1 + value = 1.2 + sparse_material_weight = 10 + rich_material_weight = 5 + ignition_point = 774 + accelerant_value = 0.9 + dirtiness = 15 + dissolves_into = list( + /decl/material/solid/carbon = 0.1, + /decl/material/liquid/plasticide = 0.4, + /decl/material/liquid/acetone = 0.4, + /decl/material/solid/gemstone/diamond = 0.1 + ) + +/decl/material/solid/cassiterite + name = "cassiterite" + uid = "solid_cassiterite" + color = "#a1a4cf" + heating_products = list( + /decl/material/solid/metal/tin = 0.7, + /decl/material/solid/metal/tungsten = 0.2, + /decl/material/solid/slag = 0.1 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "cassiterite" + ore_result_amount = 3 + ore_spread_chance = 10 + ore_scan_icon = "mineral_common" + ore_icon_overlay = "lump" + ore_type_value = ORE_SURFACE + ore_data_value = 1 + value = 0.9 + sparse_material_weight = 20 + rich_material_weight = 10 + dissolves_into = list( + /decl/material/solid/metal/tin = 0.8, + /decl/material/solid/metal/tungsten = 0.2 + ) + +/decl/material/solid/wolframite + name = "wolframite" + uid = "solid_wolframite" + color = "#8184ac" + heating_products = list( + /decl/material/solid/metal/tin = 0.1, + /decl/material/solid/metal/tungsten = 0.2, + /decl/material/solid/metal/iron = 0.2, + /decl/material/solid/slag = 0.5 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "wolframite" + ore_result_amount = 2 + ore_spread_chance = 15 + ore_scan_icon = "mineral_uncommon" + ore_icon_overlay = "lump" + ore_type_value = ORE_SURFACE + ore_data_value = 1 + value = 0.9 + sparse_material_weight = 15 + rich_material_weight = 10 + dissolves_into = list( + /decl/material/solid/metal/tin = 0.1, + /decl/material/solid/metal/tungsten = 0.6, + /decl/material/solid/metal/iron = 0.3 + ) + +/decl/material/solid/sperrylite + name = "sperrylite" + uid = "solid_sperrylite" + color = "#cfd0d8" + heating_products = list( + /decl/material/solid/metal/platinum = 0.5, + /decl/material/solid/metal/iron = 0.1, + /decl/material/solid/glass = 0.1, + /decl/material/solid/slag = 0.3 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "sperrylite" + ore_result_amount = 2 + ore_spread_chance = 15 + ore_scan_icon = "mineral_uncommon" + ore_icon_overlay = "lump" + ore_type_value = ORE_PRECIOUS + ore_data_value = 1 + value = 1.1 + sparse_material_weight = 10 + rich_material_weight = 5 + dissolves_into = list( + /decl/material/solid/metal/platinum = 0.7, + /decl/material/solid/metal/iron = 0.1, + /decl/material/solid/glass = 0.1, + /decl/material/solid/metal/titanium = 0.1 + ) + +/decl/material/solid/sphalerite + name = "sphalerite" + uid = "solid_sphalerite" + color = "#aaaa9c" + heating_products = list( + /decl/material/solid/metal/zinc = 0.7, + /decl/material/solid/metal/iron = 0.1, + /decl/material/solid/slag = 0.2 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "sphalerite" + ore_result_amount = 3 + ore_spread_chance = 15 + ore_scan_icon = "mineral_common" + ore_icon_overlay = "lump" + ore_type_value = ORE_SURFACE + ore_data_value = 1 + value = 0.8 + sparse_material_weight = 25 + rich_material_weight = 15 + dissolves_into = list( + /decl/material/solid/metal/zinc = 0.7, + /decl/material/solid/metal/iron = 0.2, + /decl/material/solid/silicon = 0.1 + ) + +/decl/material/solid/galena + name = "galena" + uid = "solid_galena" + color = "#aaaa9c" + heating_products = list( + /decl/material/solid/metal/lead = 0.6, + /decl/material/solid/metal/iron = 0.2, + /decl/material/solid/metal/silver = 0.1, + /decl/material/solid/slag = 0.1 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "galena" + ore_result_amount = 2 + ore_spread_chance = 10 + ore_scan_icon = "mineral_common" + ore_icon_overlay = "lump" + ore_type_value = ORE_SURFACE + ore_data_value = 1 + value = 0.8 + sparse_material_weight = 20 + rich_material_weight = 10 + dissolves_into = list( + /decl/material/solid/metal/lead = 0.7, + /decl/material/solid/metal/iron = 0.2, + /decl/material/solid/metal/silver = 0.1 + ) + +/decl/material/solid/calaverite + name = "calaverite" + uid = "solid_calaverite" + color = "#aaaa9c" + heating_products = list( + /decl/material/solid/metal/gold = 0.6, + /decl/material/solid/metal/silver = 0.3, + /decl/material/solid/slag = 0.1 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "calaverite" + ore_result_amount = 2 + ore_spread_chance = 5 + ore_scan_icon = "mineral_uncommon" + ore_icon_overlay = "lump" + ore_type_value = ORE_PRECIOUS + ore_data_value = 1 + value = 0.8 + sparse_material_weight = 5 + rich_material_weight = 5 + dissolves_into = list( + /decl/material/solid/metal/gold = 0.7, + /decl/material/solid/metal/silver = 0.3 + ) + +/decl/material/solid/crocoite + name = "crocoite" + uid = "solid_crocoite" + color = "#fa672c" + heating_products = list( + /decl/material/solid/metal/chromium = 0.3, + /decl/material/solid/metal/lead = 0.4, + /decl/material/solid/slag = 0.3 + ) + heating_point = LOW_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "crocoite" + ore_result_amount = 3 + ore_spread_chance = 5 + ore_scan_icon = "mineral_uncommon" + ore_icon_overlay = "lump" + ore_type_value = ORE_PRECIOUS + ore_data_value = 1 + value = 0.9 + sparse_material_weight = 5 + rich_material_weight = 10 + dissolves_into = list( + /decl/material/solid/metal/chromium = 0.6, + /decl/material/solid/metal/lead = 0.4 + ) + +/decl/material/solid/borax + name = "borax" + uid = "solid_borax" + color = "#a9aa81" + heating_products = list( + /decl/material/solid/boron = 0.8, + /decl/material/solid/slag = 0.2 + ) + heating_point = GENERIC_SMELTING_HEAT_POINT + heating_sound = null + heating_message = null + ore_name = "borax" + ore_result_amount = 3 + ore_spread_chance = 5 + ore_scan_icon = "mineral_uncommon" + ore_icon_overlay = "lump" + ore_type_value = ORE_SURFACE + ore_data_value = 1 + value = 0.5 + sparse_material_weight = 4 + rich_material_weight = 2 diff --git a/code/modules/materials/definitions/solids/materials_solid_mundane.dm b/code/modules/materials/definitions/solids/materials_solid_mundane.dm index 76be4c8a8893..039405d95068 100644 --- a/code/modules/materials/definitions/solids/materials_solid_mundane.dm +++ b/code/modules/materials/definitions/solids/materials_solid_mundane.dm @@ -1,11 +1,25 @@ /decl/material/solid/slag name = "slag" - stack_type = null + uid = "solid_slag" color = "#2e3a07" ore_name = "slag" ore_desc = "Someone messed up..." ore_icon_overlay = "lump" - hidden_from_codex = TRUE reflectiveness = MAT_VALUE_DULL wall_support_value = MAT_VALUE_LIGHT value = 0.1 + default_solid_form = /obj/item/stack/material/lump + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + // Slag can be reclaimed into more useful forms by grinding it up and mixing it with strong acid. + dissolves_in = MAT_SOLVENT_STRONG + dissolves_into = list( + /decl/material/solid/sand = 0.5, + /decl/material/solid/clay = 0.2, + /decl/material/solid/metal/iron = 0.1, + /decl/material/solid/metal/aluminium = 0.05, + /decl/material/solid/phosphorus = 0.05, + /decl/material/gas/sulfur_dioxide = 0.05, + /decl/material/gas/carbon_dioxide = 0.05 + ) diff --git a/code/modules/materials/definitions/solids/materials_solid_organic.dm b/code/modules/materials/definitions/solids/materials_solid_organic.dm index 761db3e2e932..7bfb29fb0ab5 100644 --- a/code/modules/materials/definitions/solids/materials_solid_organic.dm +++ b/code/modules/materials/definitions/solids/materials_solid_organic.dm @@ -1,321 +1,308 @@ -/decl/material/solid/plastic +/decl/material/solid/organic + abstract_type = /decl/material/solid/organic + ignition_point = T0C+500 // Based on loose ignition temperature of plastic + accelerant_value = 0.1 + burn_product = /decl/material/gas/carbon_monoxide + boiling_point = null + melting_point = null + compost_value = 1 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON +/* TODO: burn products for solids + bakes_into_at_temperature = T0C+500 + bakes_into_material = /decl/material/solid/carbon +*/ + +/decl/material/solid/organic/plastic name = "plastic" + uid = "solid_plastic" lore_text = "A generic polymeric material. Probably the most flexible and useful substance ever created by human science; mostly used to make disposable cutlery." - stack_type = /obj/item/stack/material/plastic flags = MAT_FLAG_BRITTLE - icon_base = "solid" - icon_reinf = "reinf_over" + icon_base = 'icons/turf/walls/plastic.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = 0 + use_reinf_state = null color = COLOR_EGGSHELL - hardness = MAT_VALUE_SOFT + door_icon_base = "plastic" + hardness = MAT_VALUE_FLEXIBLE + 10 weight = MAT_VALUE_LIGHT melting_point = T0C+371 //assuming heat resistant plastic - stack_origin_tech = "{'materials':3}" + stack_origin_tech = @'{"materials":3}' conductive = 0 construction_difficulty = MAT_VALUE_NORMAL_DIY reflectiveness = MAT_VALUE_SHINY wall_support_value = MAT_VALUE_EXTREMELY_LIGHT taste_description = "plastic" - -/decl/material/solid/plastic/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/furniture/crate/plastic(src) - . += new/datum/stack_recipe/bag(src) - . += new/datum/stack_recipe/ivbag(src) - . += create_recipe_list(/datum/stack_recipe/cartridge) - . += create_recipe_list(/datum/stack_recipe/tile/light) - . += new/datum/stack_recipe/hazard_cone(src) - . += new/datum/stack_recipe/furniture/flaps(src) - -/decl/material/solid/plastic/holographic + accelerant_value = 0.6 + dooropen_noise = 'sound/effects/doorcreaky.ogg' + default_solid_form = /obj/item/stack/material/panel + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + tensile_strength = 0.75 + compost_value = 0 + +/decl/material/solid/organic/plastic/foam + name = "foam" + lore_text = "A plastic polymer in a sponge-like form, filled with air bubbles that make it springy and compressible." + hardness = MAT_VALUE_SOFT + 5 + taste_description = "foam" + color = COLOR_BLUE_GRAY // dunno why foam is this gray-teal color in my mind, but it is. maybe gray would also work + uid = "solid_foam" + +/decl/material/solid/organic/wax + name = "wax" + uid = "solid_wax" + taste_description = "waxy blandness" + lore_text = "A soft, easily melted substance produced by bees. Used to make candles." + accelerant_value = 0.6 + construction_difficulty = MAT_VALUE_NORMAL_DIY + reflectiveness = MAT_VALUE_SHINY + wall_support_value = MAT_VALUE_EXTREMELY_LIGHT + default_solid_form = /obj/item/stack/material/bar + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + color = "#fffccc" + door_icon_base = "plastic" + hardness = MAT_VALUE_FLEXIBLE - 10 + weight = MAT_VALUE_LIGHT + melting_point = 363 + ignition_point = 473 + boiling_point = 643 + compost_value = 0.2 + paint_verb = "colored" + exoplanet_rarity_plant = MAT_RARITY_MUNDANE + +/decl/material/solid/organic/plastic/holographic name = "holographic plastic" - stack_type = null - shard_type = SHARD_NONE - hidden_from_codex = TRUE + uid = "solid_holographic_plastic" + holographic = TRUE -/decl/material/solid/plastic/holographic/get_recipes(reinf_mat) - return list() - -/decl/material/solid/cardboard +/decl/material/solid/organic/cardboard name = "cardboard" + uid = "solid_cardboard" lore_text = "What with the difficulties presented by growing plants in orbit, a stock of cardboard in space is probably more valuable than gold." - stack_type = /obj/item/stack/material/cardboard flags = MAT_FLAG_BRITTLE integrity = 10 - icon_base = "solid" - icon_reinf = "reinf_over" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + use_reinf_state = null color = "#aaaaaa" - hardness = MAT_VALUE_SOFT + hardness = MAT_VALUE_SOFT+5 brute_armor = 1 weight = MAT_VALUE_EXTREMELY_LIGHT - 5 ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough - melting_point = T0C+232 //temperature at which cardboard walls would be destroyed - stack_origin_tech = "{'materials':1}" + stack_origin_tech = @'{"materials":1}' door_icon_base = "wood" destruction_desc = "crumples" + destruction_sound = "pageturn" conductive = 0 value = 0.5 reflectiveness = MAT_VALUE_DULL wall_support_value = MAT_VALUE_EXTREMELY_LIGHT - -/decl/material/solid/cardboard/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += create_recipe_list(/datum/stack_recipe/box) - . += new/datum/stack_recipe/cardborg_suit(src) - . += new/datum/stack_recipe/cardborg_helmet(src) - . += new/datum/stack_recipe_list("folders", create_recipe_list(/datum/stack_recipe/folder)) - -/decl/material/solid/cloth //todo + default_solid_form = /obj/item/stack/material/cardstock + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + compost_value = 0.8 + +/decl/material/solid/organic/paper + name = "paper" + uid = "solid_paper" + lore_text = "Low tech writing medium made from cellulose fibers. Also used in wrappings and packaging." + color = "#cfcece" + stack_origin_tech = @'{"materials":1}' + door_icon_base = "wood" + destruction_desc = "tears" + destruction_sound = "pageturn" + icon_base = 'icons/turf/walls/solid.dmi' + icon_reinf = 'icons/turf/walls/reinforced.dmi' + integrity = 10 //Probably don't wanna go below 10, because of the health multiplier on things, that would result in a value smaller than 1. + use_reinf_state = null + flags = MAT_FLAG_BRITTLE + reflectiveness = MAT_VALUE_DULL + hardness = MAT_VALUE_FLEXIBLE-5 + wall_support_value = MAT_VALUE_EXTREMELY_LIGHT - 9 + weight = MAT_VALUE_EXTREMELY_LIGHT - 9 + construction_difficulty = MAT_VALUE_EASY_DIY + wall_flags = PAINT_PAINTABLE | PAINT_STRIPABLE | WALL_HAS_EDGES + brute_armor = 0.5 + ignition_point = T0C + 232 //"the temperature at which book-paper catches fire, and burns." close enough + conductive = FALSE + value = 0.25 + default_solid_form = /obj/item/stack/material/bolt + shard_name = SHARD_NONE + shard_type = /obj/item/shreddedp + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + compost_value = 0.8 + paint_verb = "painted" + +/decl/material/solid/organic/cloth name = "cotton" - use_name = "cotton" + uid = "solid_cotton" color = "#ffffff" - stack_origin_tech = "{'materials':2}" + stack_origin_tech = @'{"materials":2}' door_icon_base = "wood" ignition_point = T0C+232 - melting_point = T0C+300 flags = MAT_FLAG_PADDING brute_armor = 1 conductive = 0 - stack_type = null hidden_from_codex = TRUE construction_difficulty = MAT_VALUE_NORMAL_DIY reflectiveness = MAT_VALUE_DULL - hardness = MAT_VALUE_SOFT + hardness = MAT_VALUE_SOFT+5 weight = MAT_VALUE_EXTREMELY_LIGHT wall_support_value = MAT_VALUE_EXTREMELY_LIGHT - -/decl/material/solid/cloth/yellow - name = "yellow" - use_name = "yellow cloth" - color = "#ffbf00" - -/decl/material/solid/cloth/teal - name = "teal" - use_name = "teal cloth" - color = "#00e1ff" - -/decl/material/solid/cloth/black - name = "black" - use_name = "black cloth" - color = "#505050" - -/decl/material/solid/cloth/green - name = "green" - use_name = "green cloth" - color = "#b7f27d" - -/decl/material/solid/cloth/purple - name = "purple" - use_name = "purple cloth" - color = "#9933ff" - -/decl/material/solid/cloth/blue - name = "blue" - use_name = "blue cloth" - color = "#46698c" - -/decl/material/solid/cloth/beige - name = "beige" - use_name = "beige cloth" - color = "#ceb689" - -/decl/material/solid/cloth/lime - name = "lime" - use_name = "lime cloth" - color = "#62e36c" - -/decl/material/solid/carpet - name = "red" - use_name = "red upholstery" - color = "#9d2300" - flags = MAT_FLAG_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - sheet_singular_name = "tile" - sheet_plural_name = "tiles" - conductive = 0 - stack_type = null - construction_difficulty = MAT_VALUE_NORMAL_DIY - reflectiveness = MAT_VALUE_DULL - hardness = MAT_VALUE_SOFT - weight = MAT_VALUE_EXTREMELY_LIGHT - wall_support_value = MAT_VALUE_EXTREMELY_LIGHT - hidden_from_codex = TRUE - -/decl/material/solid/skin - name = "skin" - stack_type = /obj/item/stack/material/generic/skin - color = "#9e8c72" + default_solid_form = /obj/item/stack/material/bolt + dug_drop_type = /obj/item/stack/material/bolt + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + compost_value = 0.8 + has_textile_fibers = TRUE + paint_verb = "dyed" + +/decl/material/solid/organic/cloth/hemp + name = "hemp" + adjective_name = "hempen" + lore_text = "Sturdy fibers from the hemp plant, woven into strong cloth." + uid = "solid_hemp" + color = "#b4a374" + +/decl/material/solid/organic/cloth/linen + name = "linen" + lore_text = "Fibers from the flax plant, woven into sturdy, absorbent cloth." + uid = "solid_linen" + color = "#eee4c7" + +/decl/material/solid/organic/cloth/wool + name = "wool" + adjective_name = "woolen" + lore_text = "Fibers from the wooly fleece of a sheep or similar animal." + uid = "solid_wool" + color = "#fbfcdb" + +/decl/material/solid/organic/cloth/wool/diyaab + name = "diyaab wool" + adjective_name = null // override base wool + lore_text = "Fibers from the wooly fleece of a diyaab." + uid = "solid_wool_diyaab" + color = "#c9eeff" + +/decl/material/solid/organic/cloth/synthetic + name = "nylon" + uid = "solid_cloth_synthetic" + melting_point = T0C+300 // plastic + compost_value = 0 + +/decl/material/solid/organic/plantmatter + name = "plant matter" + uid = "solid_plantmatter" + color = COLOR_GREEN_GRAY flags = MAT_FLAG_PADDING ignition_point = T0C+300 - melting_point = T0C+300 - conductive = 0 + conductive = 1 hidden_from_codex = TRUE - construction_difficulty = MAT_VALUE_NORMAL_DIY - integrity = 50 + construction_difficulty = MAT_VALUE_EASY_DIY + integrity = 70 hardness = MAT_VALUE_SOFT - weight = MAT_VALUE_EXTREMELY_LIGHT + weight = MAT_VALUE_NORMAL explosion_resistance = 1 reflectiveness = MAT_VALUE_DULL - wall_support_value = MAT_VALUE_EXTREMELY_LIGHT - value = 1.2 - var/tans_to = /decl/material/solid/leather - -/decl/material/solid/skin/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/cloak(src) - . += new/datum/stack_recipe/shoes(src) - -/decl/material/solid/skin/lizard - name = "lizardskin" - color = "#626952" - tans_to = /decl/material/solid/leather/lizard - hardness = MAT_VALUE_FLEXIBLE - weight = MAT_VALUE_VERY_LIGHT - -/decl/material/solid/skin/insect - name = "chitin" - color = "#7a776d" - tans_to = /decl/material/solid/leather/chitin - integrity = 75 - hardness = MAT_VALUE_RIGID - weight = MAT_VALUE_VERY_LIGHT - brute_armor = 2 - -/decl/material/solid/skin/fur - name = "fur" - color = "#7a726d" - tans_to = /decl/material/solid/leather/fur - -/decl/material/solid/skin/fur/gray - -/decl/material/solid/skin/fur/white - -/decl/material/solid/skin/fur/orange - color = COLOR_ORANGE - -/decl/material/solid/skin/fur/black - color = COLOR_GRAY20 - -/decl/material/solid/skin/fur/heavy - color = COLOR_GUNMETAL - -/decl/material/solid/skin/goat - color = COLOR_SILVER - -/decl/material/solid/skin/cow - color = COLOR_GRAY40 - -/decl/material/solid/skin/shark - name = "sharkskin" - color = COLOR_PURPLE_GRAY - -/decl/material/solid/skin/fish - color = COLOR_BOTTLE_GREEN - name = "fishskin" - -/decl/material/solid/skin/fish/purple - color = COLOR_PALE_PURPLE_GRAY - -/decl/material/solid/skin/feathers - name = "feathers" - color = COLOR_SILVER - -/decl/material/solid/skin/feathers/purple - color = COLOR_PALE_PURPLE_GRAY - -/decl/material/solid/skin/feathers/blue - color = COLOR_SKY_BLUE - -/decl/material/solid/skin/feathers/green - color = COLOR_BOTTLE_GREEN - -/decl/material/solid/skin/feathers/brown - color = COLOR_BEASTY_BROWN - -/decl/material/solid/skin/feathers/red - color = COLOR_RED - -/decl/material/solid/skin/feathers/black - color = COLOR_GRAY15 - -/decl/material/solid/bone - name = "bone" - sheet_singular_name = "length" - sheet_plural_name = "lengths" - color = "#f0edc7" - stack_type = /obj/item/stack/material/generic/bone - ignition_point = T0C+1100 - melting_point = T0C+1800 - conductive = 0 - hidden_from_codex = TRUE - construction_difficulty = MAT_VALUE_NORMAL_DIY - hitsound = 'sound/weapons/smash.ogg' - integrity = 75 - hardness = MAT_VALUE_RIGID - reflectiveness = MAT_VALUE_MATTE - weight = MAT_VALUE_NORMAL - wall_support_value = MAT_VALUE_NORMAL - -/decl/material/solid/bone/fish - name = "fishbone" + wall_support_value = MAT_VALUE_LIGHT + value = 0.8 + default_solid_form = /obj/item/stack/material/slab + dug_drop_type = /obj/item/stack/material/slab + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + fishing_bait_value = 0.75 + allergen_flags = ALLERGEN_VEGETABLE + exoplanet_rarity_plant = MAT_RARITY_MUNDANE + +/// Used for plant products that aren't quite wood, but are still tougher than normal plant matter. +/decl/material/solid/organic/plantmatter/pith + name = "plant pith" + uid = "solid_plantpith" + melting_point = null hardness = MAT_VALUE_FLEXIBLE - weight = MAT_VALUE_VERY_LIGHT - -/decl/material/solid/bone/cartilage - name = "cartilage" - hardness = 0 - weight = MAT_VALUE_EXTREMELY_LIGHT - -/decl/material/solid/leather + value = 0.4 + +/decl/material/solid/organic/plantmatter/pith/husk + name = "plant husk" + uid = "solid_planthusk" + +/decl/material/solid/organic/plantmatter/grass + name = "grass" + uid = "solid_grass" + default_solid_form = /obj/item/stack/material/bundle + melting_point = null // can grass melt?? + ignition_point = T0C+100 + tans_to = /decl/material/solid/organic/plantmatter/grass/dry + tensile_strength = 0.2 + dug_drop_type = /obj/item/stack/material/bundle/grass // Sets drying_wetness etc + +/decl/material/solid/organic/plantmatter/grass/dry + name = "dried grass" + uid = "solid_dry_grass" + color = COLOR_BEIGE + ignition_point = T0C+50 + tensile_strength = 0.5 + compost_value = 0.5 + dug_drop_type = /obj/item/stack/material/bundle // Unsets drying_wetness etc + +/decl/material/solid/organic/leather name = "leather" + uid = "solid_leather" color = "#5c4831" - stack_origin_tech = "{'materials':2}" + stack_origin_tech = @'{"materials":2}' flags = MAT_FLAG_PADDING ignition_point = T0C+300 - melting_point = T0C+300 conductive = 0 - stack_type = /obj/item/stack/material/generic/skin hidden_from_codex = TRUE - construction_difficulty = MAT_VALUE_NORMAL_DIY + construction_difficulty = MAT_VALUE_HARD_DIY integrity = 50 hardness = MAT_VALUE_FLEXIBLE weight = MAT_VALUE_EXTREMELY_LIGHT reflectiveness = MAT_VALUE_MATTE wall_support_value = MAT_VALUE_EXTREMELY_LIGHT - -/decl/material/solid/leather/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/cloak(src) - . += new/datum/stack_recipe/shoes(src) - . += new/datum/stack_recipe/boots(src) - -/decl/material/solid/leather/synth + default_solid_form = /obj/item/stack/material/skin + sound_manipulate = 'sound/foley/paperpickup2.ogg' + sound_dropped = 'sound/foley/paperpickup1.ogg' + tensile_strength = 0.8 // TODO: dried sinew? Should this be crappier than plastic/metal? + compost_value = 0.2 + +/decl/material/solid/organic/leather/gut + name = "dried gut" + uid = "solid_dried_gut" + color = "#736754" + +/decl/material/solid/organic/leather/synth name = "synthleather" + uid = "solid_synthleather" color = "#1f1f20" ignition_point = T0C+150 - melting_point = T0C+100 + melting_point = T0C+100 // Assuming synthetic leather. + compost_value = 0 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE -/decl/material/solid/leather/lizard +/decl/material/solid/organic/leather/lizard name = "scaled hide" + uid = "solid_scaled_hide" color = "#434b31" integrity = 75 - hardness = MAT_VALUE_RIGID + hardness = MAT_VALUE_FLEXIBLE + 5 weight = MAT_VALUE_LIGHT reflectiveness = MAT_VALUE_SHINY -/decl/material/solid/leather/fur +/decl/material/solid/organic/leather/fur name = "tanned pelt" + uid = "solid_tanned_pelt" + paint_verb = "dyed" -/decl/material/solid/leather/chitin +/decl/material/solid/organic/leather/chitin name = "treated chitin" + uid = "solid_treated_chitin" integrity = 100 color = "#5c5a54" hardness = MAT_VALUE_HARD diff --git a/code/modules/materials/definitions/solids/materials_solid_stone.dm b/code/modules/materials/definitions/solids/materials_solid_stone.dm index c3ee83e46787..076159985493 100644 --- a/code/modules/materials/definitions/solids/materials_solid_stone.dm +++ b/code/modules/materials/definitions/solids/materials_solid_stone.dm @@ -1,90 +1,135 @@ /decl/material/solid/stone name = null + abstract_type = /decl/material/solid/stone color = "#d9c179" - shard_type = SHARD_STONE_PIECE + shard_name = SHARD_STONE_PIECE weight = MAT_VALUE_HEAVY hardness = MAT_VALUE_HARD - 5 reflectiveness = MAT_VALUE_MATTE brute_armor = 3 conductive = 0 construction_difficulty = MAT_VALUE_NORMAL_DIY + wall_flags = WALL_HAS_EDGES + wall_blend_icons = list( + 'icons/turf/walls/solid.dmi' = TRUE, + 'icons/turf/walls/wood.dmi' = TRUE, + 'icons/turf/walls/brick.dmi' = TRUE, + 'icons/turf/walls/log.dmi' = TRUE, + 'icons/turf/walls/wattle.dmi' = TRUE, + 'icons/turf/walls/wattledaub.dmi' = TRUE, + 'icons/turf/walls/metal.dmi' = TRUE + ) dissolves_into = list( /decl/material/solid/silicon = 1 ) + ore_result_amount = 4 + sound_manipulate = 'sound/foley/rockscrape.ogg' + sound_dropped = 'sound/foley/rockscrape.ogg' + var/image/texture -/decl/material/solid/stone/generate_recipes(var/reinforce_material) +/decl/material/solid/stone/Initialize() . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/furniture/planting_bed(src) + texture = image('icons/turf/wall_texture.dmi', "concrete") + texture.appearance_flags |= RESET_COLOR | RESET_ALPHA + texture.blend_mode = BLEND_MULTIPLY + +/decl/material/solid/stone/get_wall_texture() + return texture /decl/material/solid/stone/sandstone name = "sandstone" + uid = "solid_sandstone" lore_text = "A clastic sedimentary rock. The cost of boosting it to orbit is almost universally much higher than the actual value of the material." - stack_type = /obj/item/stack/material/sandstone value = 1.5 + melting_point = T0C + 600 + hardness = MAT_VALUE_RIGID + 5 + +/decl/material/solid/stone/limestone + name = "limestone" + uid = "solid_limestone" + lore_text = "A pale sedimentary rock, often containing fossils. The cost of boosting it to orbit is almost universally much higher than the actual value of the material." + color = COLOR_BEIGE + value = 1.5 + melting_point = T0C + 600 + hardness = MAT_VALUE_RIGID + 5 + +/decl/material/solid/stone/flint + name = "flint" + uid = "solid_flint" + lore_text = "A hard, smooth stone traditionally used for making fire." + value = 3 + color = "#615f5f" + +/decl/material/solid/stone/granite + name = "granite" + uid = "solid_granite" + lore_text = "A coarse-grained igneous rock formed by magma containing sillicon and alkali metal oxides." + color = "#615f5f" + exoplanet_rarity_plant = MAT_RARITY_MUNDANE + exoplanet_rarity_gas = MAT_RARITY_MUNDANE + hardness = MAT_VALUE_HARD + melting_point = T0C + 1260 + brute_armor = 15 + explosion_resistance = 15 + integrity = 500 //granite is very strong + gemstone_types = list(/decl/material/solid/gemstone/topaz = 1) + dissolves_into = list( + /decl/material/solid/silicon = 0.75, + /decl/material/solid/bauxite = 0.15, + /decl/material/solid/slag = 0.10, + ) + +/decl/material/solid/stone/pottery + name = "fired clay" + uid = "solid_pottery" + lore_text = "A hard but brittle substance produced by firing clay in a kiln." + color = "#cd8f75" + adjective_name = "earthenware" + melting_point = 2000 // Arbitrary, hotter than the kiln currently reaches. /decl/material/solid/stone/ceramic name = "ceramic" - lore_text = "A hard substance produced by firing clay in a kiln." - stack_type = /obj/item/stack/material/generic + uid = "solid_ceramic" + lore_text = "A very hard, heat-resistant substance produced by firing glazed clay in a kiln." color = COLOR_OFF_WHITE + melting_point = 6000 // Arbitrary, very heat-resistant. + + dissolves_in = MAT_SOLVENT_IMMUNE + dissolves_into = null /decl/material/solid/stone/marble name = "marble" + uid = "solid_marble" lore_text = "A metamorphic rock largely sourced from Earth. Prized for use in extremely expensive decorative surfaces." color = "#aaaaaa" weight = MAT_VALUE_VERY_HEAVY wall_support_value = MAT_VALUE_VERY_HEAVY hardness = MAT_VALUE_HARD reflectiveness = MAT_VALUE_SHINY + melting_point = T0C + 1200 brute_armor = 3 integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system - stack_type = /obj/item/stack/material/marble construction_difficulty = MAT_VALUE_HARD_DIY + gemstone_types = list(/decl/material/solid/gemstone/ruby = 1) /decl/material/solid/stone/basalt name = "basalt" + uid = "solid_basalt" lore_text = "A ubiquitous volcanic stone." color = COLOR_DARK_GRAY - stack_type = /obj/item/stack/material/generic weight = MAT_VALUE_VERY_HEAVY wall_support_value = MAT_VALUE_VERY_HEAVY hardness = MAT_VALUE_HARD reflectiveness = MAT_VALUE_SHINY + melting_point = T0C + 1200 construction_difficulty = MAT_VALUE_HARD_DIY /decl/material/solid/stone/concrete name = "concrete" + uid = "solid_concrete" lore_text = "The most ubiquitous building material of old Earth, now in space. Consists of mineral aggregate bound with some sort of cementing solution." - stack_type = /obj/item/stack/material/generic/brick color = COLOR_GRAY value = 0.9 - var/image/texture - -/decl/material/solid/stone/concrete/New() - ..() - texture = image('icons/turf/wall_texture.dmi', "concrete") - texture.blend_mode = BLEND_MULTIPLY - -/decl/material/solid/stone/concrete/get_wall_texture() - return texture - -/decl/material/solid/stone/cult - name = "disturbing stone" - icon_base = "cult" - color = "#402821" - icon_reinf = "reinf_cult" - shard_type = SHARD_STONE_PIECE - sheet_singular_name = "brick" - sheet_plural_name = "bricks" - conductive = 0 - construction_difficulty = MAT_VALUE_NORMAL_DIY - hidden_from_codex = TRUE - reflectiveness = MAT_VALUE_DULL - -/decl/material/solid/stone/cult/place_dismantled_girder(var/turf/target) - new /obj/structure/girder/cult(target) - -/decl/material/solid/stone/cult/reinforced - name = "runic inscriptions" + melting_point = T0C + 1200 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE diff --git a/code/modules/materials/definitions/solids/materials_solid_wood.dm b/code/modules/materials/definitions/solids/materials_solid_wood.dm index 43b8751cada7..a20bd4d5a986 100644 --- a/code/modules/materials/definitions/solids/materials_solid_wood.dm +++ b/code/modules/materials/definitions/solids/materials_solid_wood.dm @@ -1,28 +1,45 @@ -/decl/material/solid/wood +/decl/material/solid/organic/wood name = "wood" - liquid_name = "wood pulp" - lore_text = "A fibrous structural material harvested from an indeterminable plant. Don't get a splinter." - adjective_name = "wooden" - stack_type = /obj/item/stack/material/wood + abstract_type = /decl/material/solid/organic/wood color = WOOD_COLOR_GENERIC integrity = 75 - icon_base = "wood" + icon_base = 'icons/turf/walls/wood.dmi' + wall_flags = PAINT_PAINTABLE|PAINT_STRIPABLE|WALL_HAS_EDGES + wall_blend_icons = list( + 'icons/turf/walls/solid.dmi' = TRUE, + 'icons/turf/walls/stone.dmi' = TRUE, + 'icons/turf/walls/brick.dmi' = TRUE, + 'icons/turf/walls/log.dmi' = TRUE, + 'icons/turf/walls/wattle.dmi' = TRUE, + 'icons/turf/walls/wattledaub.dmi' = TRUE, + 'icons/turf/walls/metal.dmi' = TRUE + ) + icon_reinf = list( + 'icons/turf/walls/reinforced_timber.dmi', + 'icons/turf/walls/reinforced_timber_alt_1.dmi', + 'icons/turf/walls/reinforced_timber_alt_2.dmi', + 'icons/turf/walls/reinforced_timber_alt_3.dmi', + 'icons/turf/walls/reinforced_timber_alt_4.dmi' + ) + use_reinf_state = null table_icon_base = "wood" + bench_icon = 'icons/obj/structures/furniture/bench_wood.dmi' + pew_icon = 'icons/obj/structures/furniture/pew_wood.dmi' + slatted_seat_icon = 'icons/obj/structures/furniture/chair_slatted_wood.dmi' + backed_chair_icon = 'icons/obj/structures/furniture/chair_backed_wood.dmi' explosion_resistance = 2 - shard_type = SHARD_SPLINTER + shard_name = SHARD_SPLINTER shard_can_repair = 0 // you can't weld splinters back into planks hardness = MAT_VALUE_FLEXIBLE + 10 brute_armor = 1 weight = MAT_VALUE_NORMAL - melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood + burn_temperature = 1000 CELSIUS ignition_point = T0C+288 - stack_origin_tech = "{'materials':1,'biotech':1}" + stack_origin_tech = @'{"materials":1,"biotech":1}' dooropen_noise = 'sound/effects/doorcreaky.ogg' door_icon_base = "wood" destruction_desc = "splinters" - sheet_singular_name = "plank" - sheet_plural_name = "planks" - hitsound = 'sound/effects/woodhit.ogg' + hitsound = 'sound/effects/hit_wood.ogg' conductive = 0 construction_difficulty = MAT_VALUE_NORMAL_DIY dissolves_into = list( @@ -32,84 +49,60 @@ value = 1.5 reflectiveness = MAT_VALUE_DULL wall_support_value = MAT_VALUE_NORMAL + accelerant_value = 0.8 + default_solid_form = /obj/item/stack/material/plank + sound_manipulate = 'sound/foley/woodpickup1.ogg' + sound_dropped = 'sound/foley/wooddrop1.ogg' + compost_value = 0.2 + paint_verb = "stained" + liquid_name = "wood pulp" -/decl/material/solid/wood/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) //recipes below don't support composite materials - return - . += new/datum/stack_recipe/sandals(src) - . += new/datum/stack_recipe/tile/wood(src) - . += create_recipe_list(/datum/stack_recipe/furniture/chair/wood) - . += new/datum/stack_recipe/crossbowframe(src) - . += new/datum/stack_recipe/furniture/coffin/wooden(src) - . += new/datum/stack_recipe/beehive_assembly(src) - . += new/datum/stack_recipe/beehive_frame(src) - . += new/datum/stack_recipe/furniture/bookcase(src) - . += new/datum/stack_recipe/zipgunframe(src) - . += new/datum/stack_recipe/coilgun(src) - . += new/datum/stack_recipe/stick(src) - . += new/datum/stack_recipe/noticeboard(src) - . += new/datum/stack_recipe/furniture/table_frame(src) - . += new/datum/stack_recipe/wooden_prosthetic(src) - . += new/datum/stack_recipe/wooden_prosthetic/right_arm(src) - . += new/datum/stack_recipe/wooden_prosthetic/left_leg(src) - . += new/datum/stack_recipe/wooden_prosthetic/right_leg(src) - . += new/datum/stack_recipe/wooden_prosthetic/left_hand(src) - . += new/datum/stack_recipe/wooden_prosthetic/right_hand(src) - . += new/datum/stack_recipe/wooden_prosthetic/left_foot(src) - . += new/datum/stack_recipe/wooden_prosthetic/right_foot(src) - -/decl/material/solid/wood/mahogany/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) - return - . += new/datum/stack_recipe/tile/mahogany(src) - -/decl/material/solid/wood/maple/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) - return - . += new/datum/stack_recipe/tile/maple(src) - -/decl/material/solid/wood/ebony/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) - return - . += new/datum/stack_recipe/tile/ebony(src) - -/decl/material/solid/wood/walnut/generate_recipes(var/reinforce_material) - . = ..() - if(reinforce_material) - return - . += new/datum/stack_recipe/tile/walnut(src) - -/decl/material/solid/wood/holographic - color = WOOD_COLOR_CHOCOLATE //the very concept of wood should be brown - stack_type = null - shard_type = SHARD_NONE - value = 0 - hidden_from_codex = TRUE +/decl/material/solid/organic/wood/oak + name = "oak" + uid = "solid_wood" + adjective_name = "oaken" + lore_text = "Oak timber is strong yet simple to carve, making it a fine choice for wooden handicrafts." + adjective_name = "oaken" + temperature_burn_milestone_material = /decl/material/solid/organic/wood/oak + +// Wood is hard but can't really give it an edge. +/decl/material/solid/organic/wood/can_hold_edge() + return FALSE -/decl/material/solid/wood/holographic/get_recipes(reinf_mat) - return list() +/decl/material/solid/organic/wood/fungal + name = "towercap" + adjective_name = "towercap" + uid = "solid_wood_fungal" + color = "#e6d8dd" + hardness = MAT_VALUE_FLEXIBLE + 10 -/decl/material/solid/wood/mahogany +/decl/material/solid/organic/wood/holographic + name = "holographic wood" + uid = "solid_holographic_wood" + color = WOOD_COLOR_CHOCOLATE //the very concept of wood should be brown + adjective_name = "holowood" + holographic = TRUE + +/decl/material/solid/organic/wood/mahogany name = "mahogany" + uid = "solid_mahogany" adjective_name = "mahogany" lore_text = "Mahogany is prized for its beautiful grain and rich colour, and as such is typically used for fine furniture and cabinetry." color = WOOD_COLOR_RICH construction_difficulty = MAT_VALUE_HARD_DIY value = 1.6 -/decl/material/solid/wood/maple +/decl/material/solid/organic/wood/maple name = "maple" + uid = "solid_maple" adjective_name = "maple" lore_text = "Owing to its fast growth and ease of working, silver maple is a popular wood for flooring and furniture." color = WOOD_COLOR_PALE value = 1.8 -/decl/material/solid/wood/ebony +/decl/material/solid/organic/wood/ebony name = "ebony" + uid = "solid_ebony" adjective_name = "ebony" lore_text = "Ebony is the name for a group of dark coloured, extremely dense, and fine grained hardwoods. \ Despite gene modification to produce larger source trees and ample land to plant them on, \ @@ -121,8 +114,9 @@ construction_difficulty = MAT_VALUE_VERY_HARD_DIY value = 1.8 -/decl/material/solid/wood/walnut +/decl/material/solid/organic/wood/walnut name = "walnut" + uid = "solid_walnut" adjective_name = "walnut" lore_text = "Walnut is a dense hardwood that polishes to a very fine finish. \ Walnut is especially favoured for construction of figurines (where it contrasts with lighter coloured woods) and tables. \ @@ -131,8 +125,9 @@ weight = MAT_VALUE_NORMAL construction_difficulty = MAT_VALUE_HARD_DIY -/decl/material/solid/wood/bamboo +/decl/material/solid/organic/wood/bamboo name = "bamboo" + uid = "solid_bamboo" liquid_name = "bamboo pulp" adjective_name = "bamboo" lore_text = "Bamboo is a fast-growing grass which can be used similar to wood after processing. Due to its swift growth \ @@ -141,8 +136,9 @@ weight = MAT_VALUE_VERY_LIGHT hardness = MAT_VALUE_RIGID -/decl/material/solid/wood/yew +/decl/material/solid/organic/wood/yew name = "yew" + uid = "solid_yew" adjective_name = "yew" lore_text = "Although favoured in days past for the construction of bows, yew has a multitude of uses, including medicine. The yew \ tree can live for nearly a thousand years thanks to its natural disease resistance." @@ -153,3 +149,55 @@ /decl/material/liquid/heartstopper = 0.1 ) value = 1.8 + +// Used solely to give the old smooth table icons for spacer tables. +// Easy to work, not very strong or valuable. +/decl/material/solid/organic/wood/chipboard + name = "oak chipboard" + adjective_name = "oak laminate" + uid = "solid_wood_chipboard_oak" + lore_text = "Also known as particle board, this material is made from various kinds of oak wood chips and resin, with a plastic laminate." + bench_icon = 'icons/obj/structures/furniture/bench.dmi' + pew_icon = 'icons/obj/structures/furniture/pew.dmi' + slatted_seat_icon = 'icons/obj/structures/furniture/chair_slatted.dmi' + backed_chair_icon = 'icons/obj/structures/furniture/chair_backed.dmi' + door_icon_base = "metal" + table_icon_base = "metal" + color = WOOD_COLOR_GENERIC + value = 1.1 + default_solid_form = /obj/item/stack/material/sheet + +/decl/material/solid/organic/wood/chipboard/maple + name = "maple chipboard" + lore_text = "Also known as particle board, this material is made from various kinds of maple wood chips and resin, with a plastic laminate." + adjective_name = "maple laminate" + uid = "solid_wood_chipboard_maple" + color = WOOD_COLOR_PALE + +/decl/material/solid/organic/wood/chipboard/mahogany + name = "mahogany chipboard" + lore_text = "Also known as particle board, this material is made from various kinds of mahogany wood chips and resin, with a plastic laminate." + adjective_name = "mahogany laminate" + uid = "solid_wood_chipboard_mahogany" + color = WOOD_COLOR_RICH + +/decl/material/solid/organic/wood/chipboard/ebony + name = "ebony chipboard" + lore_text = "Also known as particle board, this material is made from various kinds of ebony wood chips and resin, with a plastic laminate." + adjective_name = "ebony laminate" + uid = "solid_wood_chipboard_ebony" + color = WOOD_COLOR_BLACK + +/decl/material/solid/organic/wood/chipboard/walnut + name = "walnut chipboard" + lore_text = "Also known as particle board, this material is made from various kinds of walnut wood chips and resin, with a plastic laminate." + adjective_name = "walnut laminate" + uid = "solid_wood_chipboard_walnut" + color = WOOD_COLOR_CHOCOLATE + +/decl/material/solid/organic/wood/chipboard/yew + name = "yew chipboard" + lore_text = "Also known as particle board, this material is made from various kinds of yew wood chips and resin, with a plastic laminate." + adjective_name = "yew laminate" + uid = "solid_wood_chipboard_yew" + color = WOOD_COLOR_YELLOW \ No newline at end of file diff --git a/code/modules/materials/geology/_strata.dm b/code/modules/materials/geology/_strata.dm deleted file mode 100644 index 0cd28673fe53..000000000000 --- a/code/modules/materials/geology/_strata.dm +++ /dev/null @@ -1,25 +0,0 @@ -/decl/strata - var/name - var/list/base_materials - var/list/ores_sparse - var/list/ores_rich - var/default_strata_candidate = FALSE - -/decl/strata/igneous - name = "igneous rock" - base_materials = list(/decl/material/solid/stone/basalt) - default_strata_candidate = TRUE - -/decl/strata/sedimentary - name = "sedimentary rock" - base_materials = list(/decl/material/solid/stone/sandstone) - default_strata_candidate = TRUE - -/decl/strata/metamorphic - name = "metamorphic rock" - base_materials = list(/decl/material/solid/stone/marble) - default_strata_candidate = TRUE - -/decl/strata/permafrost - name = "permafrost" - base_materials = list(/decl/material/solid/ice) diff --git a/code/modules/materials/material_armor.dm b/code/modules/materials/material_armor.dm index 5eb62568a128..708856750511 100644 --- a/code/modules/materials/material_armor.dm +++ b/code/modules/materials/material_armor.dm @@ -1,4 +1,4 @@ -#define BASIC_ARMOUR_VALUES list(melee = ARMOR_MELEE_MAJOR, bullet = ARMOR_BALLISTIC_RIFLE, laser = ARMOR_LASER_HEAVY, energy = ARMOR_ENERGY_STRONG, bomb = ARMOR_BOMB_RESISTANT,rad = ARMOR_RAD_SHIELDED) +#define BASIC_ARMOUR_VALUES list(ARMOR_MELEE = ARMOR_MELEE_MAJOR, ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, ARMOR_LASER = ARMOR_LASER_HEAVY, ARMOR_ENERGY = ARMOR_ENERGY_STRONG, ARMOR_BOMB = ARMOR_BOMB_RESISTANT,ARMOR_RAD = ARMOR_RAD_SHIELDED) /decl/material/proc/generate_armor_values() if(is_brittle()) @@ -7,15 +7,15 @@ armor_degradation_speed = max(0.01, 0.5 * (200-integrity)/200) var/list/armor = BASIC_ARMOUR_VALUES - for(var/val in list("melee", "bomb")) + for(var/val in list(ARMOR_MELEE, ARMOR_BOMB)) armor[val] *= hardness / 100 - armor["bomb"] *= weight / MAT_VALUE_NORMAL - armor["bullet"] *= (hardness / 100) ** 2 + armor[ARMOR_BOMB] *= weight / MAT_VALUE_NORMAL + armor[ARMOR_BULLET] *= (hardness / 100) ** 2 if(is_brittle()) - armor["bullet"] *= 0.2 - armor["laser"] *= (reflectiveness / 100) ** 2 - armor["energy"] *= reflectiveness / 100 - armor["rad"] *= (weight / 100) ** 2 + armor[ARMOR_BULLET] *= 0.2 + armor[ARMOR_LASER] *= (reflectiveness / 100) ** 2 + armor[ARMOR_ENERGY] *= reflectiveness / 100 + armor[ARMOR_RAD] *= (weight / 100) ** 2 //Sanitizing the list, rounding and discarding empty entries for(var/val in armor) diff --git a/code/modules/materials/material_coatings.dm b/code/modules/materials/material_coatings.dm new file mode 100644 index 000000000000..1eff783e5bc0 --- /dev/null +++ b/code/modules/materials/material_coatings.dm @@ -0,0 +1,29 @@ +/decl/material + /// What word is used to describe an item covered in/stained by this by default? + /// Can be overridden by get_coated_adjective(). + var/coated_adjective = "stained" + +// TODO: Maybe make this use a strengths system like taste? +/// Returns a string to describe an item coated with this reagent (and others). +/// Receives the coating reagent holder as an argument, so coating.my_atom is accessible +/// and it can also conditionally use a different string for primary/non-primary materials, or +/// if another liquid is present, e.g. 'wet bloody muddy shoes'. +/decl/material/proc/get_coated_adjective(datum/reagents/coating) + var/used_color = get_reagent_color(coating) + if(get_config_value(/decl/config/enum/colored_coating_names) == CONFIG_COATING_COLOR_COMPONENTS) + return FONT_COLORED(used_color, coated_adjective) + return coated_adjective + +/// Gets the name used to describe a coating with this material as its primary reagent. +/// This is mostly for handling special cases like mud. +/decl/material/proc/get_primary_coating_name(datum/reagents/coating) + // this should probably respect current phase/solution/etc better, but coating sure doesn't + return get_reagent_name(coating, phase_at_temperature()) + +/// Builds a string to describe a coating made up of this reagent (and others). +/// This reagent will never be the primary reagent, however; that's handled in get_primary_coating_name. +/// Receives the coating as an argument like get_coated_adjective, but also receives the accumulator list +/// for more complex behaviors like adding to the start. It can't reliably handle things like removing +/// another entry because ordering is not guaranteed, so beware if you need something like that. +/decl/material/proc/build_coated_name(datum/reagents/coating, list/accumulator) + accumulator |= get_coated_adjective(coating) \ No newline at end of file diff --git a/code/modules/materials/material_data.dm b/code/modules/materials/material_data.dm new file mode 100644 index 000000000000..dddb985f8ada --- /dev/null +++ b/code/modules/materials/material_data.dm @@ -0,0 +1,61 @@ +/decl/material/proc/initialize_data(list/newdata) // Called when the reagent is first added to a reagents datum. + . = newdata + if(allergen_flags) + LAZYINITLIST(.) + .[DATA_INGREDIENT_FLAGS] |= allergen_flags + +/decl/material/proc/mix_data(var/datum/reagents/reagents, var/list/newdata, var/amount) + + if(!istype(reagents)) + return + + UNLINT(reagents.cached_color = null) // colour masking may change + + . = REAGENT_DATA(reagents, src) + if(!length(newdata) || !islist(newdata)) + return + + // Blend in any allergen flags. + var/new_allergens = newdata[DATA_INGREDIENT_FLAGS] + if(new_allergens) + LAZYINITLIST(.) + .[DATA_INGREDIENT_FLAGS] |= new_allergens + + // Sum our existing taste data with the incoming taste data. + var/total_taste = 0 + var/new_fraction = amount / REAGENT_VOLUME(reagents, src) // the fraction of the total reagent volume that the new data is associated with + var/list/tastes = list() + var/list/newtastes = LAZYACCESS(newdata, DATA_TASTE) + for(var/taste in newtastes) + var/newtaste = newtastes[taste] * new_fraction + tastes[taste] += newtaste + total_taste += newtaste + + // If we have an old taste list, keep it, but if we don't, generate + // one to hold our base taste information. This is so pouring nutriment + // with a taste list into honey for example won't completely mask the + // taste of honey. + var/list/oldtastes = LAZYACCESS(., DATA_TASTE) + var/old_fraction = 1 - new_fraction + if(length(oldtastes)) + for(var/taste in oldtastes) + var/oldtaste = oldtastes[taste] * old_fraction + tastes[taste] += oldtaste + total_taste += oldtaste + else if(length(tastes) && taste_description) // only add it to the list if we already have other tastes + tastes[taste_description] += taste_mult * old_fraction + total_taste += taste_mult * old_fraction + + // Cull all tastes below 10% of total + if(length(tastes)) + if(total_taste) + for(var/taste in tastes) + if((tastes[taste] / total_taste) < 0.1) + tastes -= taste + if(length(tastes)) + LAZYSET(., DATA_TASTE, tastes) + + // Blend our extra_colour... + var/new_extra_color = newdata?[DATA_EXTRA_COLOR] + if(new_extra_color) + .[DATA_EXTRA_COLOR] = BlendHSV(new_extra_color, .[DATA_EXTRA_COLOR], new_fraction) \ No newline at end of file diff --git a/code/modules/materials/material_debris.dm b/code/modules/materials/material_debris.dm new file mode 100644 index 000000000000..879efc811ad5 --- /dev/null +++ b/code/modules/materials/material_debris.dm @@ -0,0 +1,220 @@ +/obj/item/debris + is_spawnable_type = FALSE + abstract_type = /obj/item/debris + icon = 'icons/obj/debris.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material_alteration = MAT_FLAG_ALTERATION_COLOR + +/obj/item/debris/scraps + name = "scraps" + desc = "A small pile of tailings and scraps." + +/obj/item/debris/scraps/proc/update_primary_material() + + var/list/mat_names = list() + var/highest_mat + + var/total_matter = 0 + + for(var/mat in matter) + var/mat_amt = matter[mat] + if(!highest_mat || matter[highest_mat] < mat_amt) + highest_mat = mat + var/decl/material/scrap_material = GET_DECL(mat) + mat_names += scrap_material.solid_name + total_matter += mat_amt + + // Safety check, although this should be prevented for player side interactions + if(total_matter > MAX_SCRAP_MATTER) + var/divisor = ceil(total_matter / MAX_SCRAP_MATTER) + var/list/matter_per_pile = list() + + for(var/mat in matter) + matter_per_pile[mat] = round(matter[mat] / divisor) + + for(var/i in 1 to (divisor - 1)) + var/obj/item/debris/scraps/pile = new type(get_turf(src)) + pile.matter = matter_per_pile.Copy() + pile.update_primary_material() + + matter = matter_per_pile + + if(!highest_mat) + qdel(src) + else + material = GET_DECL(highest_mat) + name = "[english_list(mat_names)] [initial(name)]" + color = material.color + +/obj/item/debris/scraps/proc/get_total_matter() + . = 0 + for(var/mat in matter) + . += matter[mat] + +/obj/item/debris/scraps/attack_self(mob/user) + + // We can only split up scraps that are pure. + if(length(matter) == 1) + var/decl/material/split_material = GET_DECL(matter[1]) + var/sheet_amount = round(matter[split_material.type] / SHEET_MATERIAL_AMOUNT) + if(sheet_amount < 1) + to_chat(user, SPAN_WARNING("There is not enough [split_material.solid_name] to shape into lumps.")) + return TRUE + var/obj/item/stack/material/lump/lumps = new(get_turf(user), sheet_amount, split_material.type) + matter[split_material.type] -= sheet_amount * SHEET_MATERIAL_AMOUNT + if(matter[split_material.type] <= 0) + qdel(src) + to_chat(user, SPAN_NOTICE("You separate the [split_material.solid_name] into [sheet_amount] lump\s.")) + user.put_in_hands(lumps) + return TRUE + + return ..() + +/obj/item/debris/scraps/attackby(obj/item/used_item, mob/user) + if(istype(used_item, type) && user.try_unequip(used_item)) + var/obj/item/debris/scraps/other = used_item + var/space_remaining = MAX_SCRAP_MATTER - get_total_matter() + var/other_total_matter = other.get_total_matter() + LAZYINITLIST(matter) + + if(space_remaining <= 0) + to_chat(user, SPAN_WARNING("You can't add any more material to \the [src]!")) + user.put_in_hands(other) + return TRUE + + else if(space_remaining >= other_total_matter) + for(var/mat in other.matter) + matter[mat] += other.matter[mat] + + other.matter = null + other.material = null + to_chat(user, SPAN_NOTICE("You combine \the [src] and \the [other].")) + qdel(other) + update_primary_material() + user.put_in_hands(src) + else + for(var/mat in other.matter) + var/ratio = other.matter[mat] / other_total_matter + matter[mat] += round(space_remaining*ratio) + other.matter[mat] -= round(space_remaining*ratio) + + to_chat(user, SPAN_NOTICE("You partially combine \the [src] and \the [other].")) + update_primary_material() + other.update_primary_material() + if(!QDELETED(other)) + user.put_in_hands(other) + + if(isatom(loc) && !QDELETED(loc?.storage)) + loc.storage.update_ui_after_item_insertion() + + UNSETEMPTY(matter) + + return TRUE + . = ..() + +// Override as squashing items produces this item type. +/obj/item/debris/scraps/squash_item(skip_qdel = FALSE) + return + +// Physical object for holding solid reagents which are out of solution or slurry. +/obj/item/debris/scraps/chemical + desc = "A pile of dust and small filings." + + // Track this to stop endless creation and deletion while fluids settle. + var/time_created + +/obj/item/debris/scraps/chemical/Initialize(ml, material_key) + . = ..() + time_created = REALTIMEOFDAY + +/obj/item/debris/scraps/chemical/fluid_act(datum/reagents/fluids) + SHOULD_CALL_PARENT(FALSE) + + if(!istype(loc, /turf)) + return + if((REALTIMEOFDAY - time_created) < 5 SECONDS) + return + if(!QDELETED(src) && REAGENT_TOTAL_LIQUID_VOLUME(fluids) >= FLUID_SLURRY) + var/free_space = REAGENTS_FREE_SPACE(fluids) + for(var/matter_type in matter) + if(free_space <= MINIMUM_CHEMICAL_VOLUME) + break + var/reagents_added = min(free_space, MATERIAL_UNITS_TO_REAGENTS_UNITS(matter[matter_type])) + fluids.add_reagent(matter_type, reagents_added, defer_update = TRUE, phase = MAT_PHASE_SOLID) + matter[matter_type] -= reagents_added/REAGENT_UNITS_PER_MATERIAL_UNIT + if(matter[matter_type] <= 0) + matter -= matter_type + + free_space -= reagents_added + + fluids.handle_update() + update_primary_material() + +/obj/item/debris/scraps/chemical/afterattack(atom/target, mob/user, proximity) + if(!ATOM_IS_OPEN_CONTAINER(target) || !proximity || !target.reagents) + return ..() + + var/free_space = target.get_reagent_space() + if(free_space <= 0) + to_chat(user, SPAN_WARNING("\The [target] is full!")) + return FALSE + + var/total_matter = get_total_matter() + + for(var/matter_type in matter) + if(free_space <= MINIMUM_CHEMICAL_VOLUME) + break + + var/adj_mat_amt = min(1, (free_space/REAGENT_UNITS_PER_MATERIAL_UNIT)/total_matter)*matter[matter_type] + var/reagents_added = max(min(free_space, MATERIAL_UNITS_TO_REAGENTS_UNITS(adj_mat_amt)), MINIMUM_CHEMICAL_VOLUME) + target.reagents.add_reagent(matter_type, reagents_added, defer_update = TRUE, phase = MAT_PHASE_SOLID) + matter[matter_type] -= reagents_added/REAGENT_UNITS_PER_MATERIAL_UNIT + if(matter[matter_type] <= 0) + matter -= matter_type + + free_space -= reagents_added + + if(!length(matter)) + to_chat(user, SPAN_NOTICE("You carefully dump \the [src] into \the [target].")) + user?.drop_from_inventory(src) + qdel(src) + else + to_chat(user, SPAN_NOTICE("You carefully dump some of \the [src] into \the [target].")) + update_primary_material() + + playsound(src, 'sound/effects/refill.ogg', 25, 1) + return TRUE + +// This object is sort of a placeholder for a more nuanced melting and item damage system. +// The idea is if your gun is half-melted it should not function as a gun anymore. +/obj/item/debris/melted + name = "melted thing" + desc = "A half-melted object of some kind." + material = /decl/material/solid/slag + +/obj/item/debris/melted/handle_melting(var/list/meltable_materials) + SHOULD_CALL_PARENT(FALSE) + if(!LAZYLEN(matter) || !LAZYLEN(meltable_materials)) + return // Nothing to melt, don't automatically destroy non-matter objects here. + var/remaining_volume = loc?.get_reagent_space() || 0 + for(var/decl/material/melt_material as anything in meltable_materials) + var/melting_amount = max(1, max(min(matter[melt_material.type], round(remaining_volume / REAGENT_UNITS_PER_MATERIAL_UNIT)), SHEET_MATERIAL_AMOUNT)) + // Remove matter. + matter[melt_material.type] -= melting_amount + if(matter[melt_material.type] <= 0) + LAZYREMOVE(matter, melt_material.type) + // Add The Goo:tm: to our loc's reagents via a tracking var. + var/melted_result = melting_amount * REAGENT_UNITS_PER_MATERIAL_UNIT + if(remaining_volume > 0) + loc.add_to_reagents(melt_material.type, melted_result) + remaining_volume = loc.get_reagent_space() + // If our loc is full, spill into our loc's loc (could probably be handled by a recursive helper?) + else if(loc?.loc) + melted_result = min(melted_result, loc.loc.get_reagent_space()) + if(melted_result) + loc.loc.add_to_reagents(melt_material.type, melted_result) + // If we've melted all our matter, destroy the object. + if(!LAZYLEN(matter) && !QDELETED(src)) + material = null + physically_destroyed() \ No newline at end of file diff --git a/code/modules/materials/material_debris_fragment.dm b/code/modules/materials/material_debris_fragment.dm new file mode 100644 index 000000000000..d34e944b6dc3 --- /dev/null +++ b/code/modules/materials/material_debris_fragment.dm @@ -0,0 +1,47 @@ +/obj/item/debris/salvage + abstract_type = /obj/item/debris/salvage + icon_state = ICON_STATE_WORLD + material_alteration = MAT_FLAG_ALTERATION_NONE + is_spawnable_type = TRUE + +/obj/item/debris/salvage/metal + name = "fragment" + desc = "A large, ragged chunk of some worked material." + icon = 'icons/obj/debris_metal.dmi' + material_alteration = MAT_FLAG_ALTERATION_ALL + material = /decl/material/solid/metal/steel + +/obj/item/debris/salvage/metal/Initialize(ml, material_key) + . = ..() + icon_state = "[icon_state][rand(0, 4)]" + +/obj/item/debris/salvage/metal/plasteel + material = /decl/material/solid/metal/plasteel + +/obj/item/debris/salvage/circuit + name = "broken circuit" + desc = "A burned-out circuitboard. Only good for the base materials now." + icon = 'icons/obj/debris_circuit.dmi' + material = /decl/material/solid/fiberglass + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE + ) + +/obj/item/debris/salvage/circuit/Initialize(ml, material_key) + . = ..() + icon_state = "[icon_state][rand(0, 3)]" + +/obj/item/debris/salvage/device + name = "broken device" + desc = "A destroyed device of some kind. Only good for recycling now." + icon = 'icons/obj/debris_device.dmi' + material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE + ) + +/obj/item/debris/salvage/device/Initialize(ml, material_key) + . = ..() + icon_state = "[icon_state][rand(0, 3)]" diff --git a/code/modules/materials/material_display.dm b/code/modules/materials/material_display.dm new file mode 100644 index 000000000000..6ec5d67c60a9 --- /dev/null +++ b/code/modules/materials/material_display.dm @@ -0,0 +1,74 @@ +/decl/material/proc/get_presentation_name(var/obj/item/prop) + var/list/presentation_data = REAGENT_DATA(prop.reagents, src) + if(islist(presentation_data)) + . = LAZYACCESS(presentation_data, DATA_MASK_NAME) + . ||= glass_name || get_reagent_name(prop?.reagents) + if(REAGENT_TOTAL_VOLUME(prop?.reagents)) + . = build_presentation_name_from_reagents(prop, .) + +/decl/material/proc/build_presentation_name_from_reagents(var/obj/item/prop, var/supplied) + . = supplied + if(cocktail_ingredient) + for(var/decl/cocktail/cocktail in SSmaterials.get_cocktails_by_primary_ingredient(type)) + if(cocktail.matches(prop)) + return cocktail.get_presentation_name(prop) + if(prop.reagents.has_reagent(/decl/material/solid/ice)) + . = "iced [.]" + +/decl/material/proc/get_presentation_desc(var/obj/item/prop) + . = glass_desc + if(REAGENT_TOTAL_VOLUME(prop?.reagents)) + . = build_presentation_desc_from_reagents(prop, .) + +/decl/material/proc/build_presentation_desc_from_reagents(var/obj/item/prop, var/supplied) + . = supplied + + if(cocktail_ingredient) + for(var/decl/cocktail/cocktail in SSmaterials.get_cocktails_by_primary_ingredient(type)) + if(cocktail.matches(prop)) + return cocktail.get_presentation_desc(prop) + +/decl/material/proc/get_reagent_name(datum/reagents/holder, phase = MAT_PHASE_LIQUID) + + var/reagent_data = REAGENT_DATA(holder, src) + if(istype(holder) && islist(reagent_data)) + var/list/rdata = reagent_data[src] + if(rdata) + var/data_name = rdata[DATA_MASK_NAME] + if(data_name) + return data_name + + if(phase == MAT_PHASE_SOLID) + return solid_name + + // Check if the material is in solution. This is a much simpler check than normal solubility. + if(phase == MAT_PHASE_LIQUID) + if(!istype(holder)) + return liquid_name + var/atom/location = holder.get_reaction_loc() + var/temperature = location?.temperature || T20C + + if(melting_point > temperature) + return solution_name + else + return liquid_name + + return "something" + +/decl/material/proc/get_reagent_color(datum/reagents/holder) + var/list/reagent_data = REAGENT_DATA(holder, src) + if(istype(holder) && islist(reagent_data)) + var/list/rdata = reagent_data[src] + if(rdata) + var/data_color = rdata[DATA_MASK_COLOR] + if(data_color) + return data_color + return color + +/decl/material/proc/get_reagent_overlay_color(datum/reagents/holder) + var/list/rdata = REAGENT_DATA(holder, src) + return LAZYACCESS(rdata, DATA_EXTRA_COLOR) || get_reagent_color(holder) + num2hex(opacity * 255) + +// Dumb overlay to apply over wall sprite for cheap texture effect +/decl/material/proc/get_wall_texture() + return \ No newline at end of file diff --git a/code/modules/materials/material_drying.dm b/code/modules/materials/material_drying.dm new file mode 100644 index 000000000000..eb57baa10228 --- /dev/null +++ b/code/modules/materials/material_drying.dm @@ -0,0 +1,28 @@ +/obj/item/stack/material/fluid_act(var/datum/reagents/fluids) + . = ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids) && material?.tans_to) + if(!dried_type) + dried_type = type + drying_wetness = get_max_drying_wetness() + update_icon() + +/obj/item/stack/material/dry_out(var/obj/rack, var/drying_power = 1, var/fire_exposed = FALSE, var/silent = FALSE) + . = ..() + if(!QDELETED(src)) + update_icon() + +/obj/item/stack/material/get_dried_product() + if(ispath(dried_type, /obj/item/stack/material) && material) + return new dried_type(loc, amount, (material.tans_to || material.type)) + return ..() + +/obj/item/stack/material/get_drying_overlay(var/obj/rack) + var/image/I = ..() + if(I && drying_wetness > 0) + var/image/soggy = image(I.icon, I.icon_state) + soggy.appearance_flags |= RESET_COLOR | RESET_ALPHA + soggy.alpha = 255 * (get_max_drying_wetness() / drying_wetness) + soggy.color = COLOR_GRAY40 + soggy.blend_mode = BLEND_MULTIPLY + I.overlays += soggy + return I diff --git a/code/modules/materials/material_gas_overlay.dm b/code/modules/materials/material_gas_overlay.dm new file mode 100644 index 000000000000..0eb154f43058 --- /dev/null +++ b/code/modules/materials/material_gas_overlay.dm @@ -0,0 +1,25 @@ +/obj/effect/gas_overlay + name = "gas" + desc = "You shouldn't be clicking this." + icon = 'icons/effects/tile_effects.dmi' + icon_state = "generic" + layer = FIRE_LAYER + appearance_flags = RESET_COLOR + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + +INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) + +/obj/effect/gas_overlay/proc/update_alpha_animation(var/new_alpha as num) + animate(src, alpha = new_alpha) + alpha = new_alpha + animate(src, alpha = 0.8 * new_alpha, time = 10, easing = SINE_EASING | EASE_OUT, loop = -1) + animate(alpha = new_alpha, time = 10, easing = SINE_EASING | EASE_IN, loop = -1) + +/obj/effect/gas_overlay/Initialize(mapload, gas) + . = ..() + material = GET_DECL(gas) + if(!istype(material)) + return INITIALIZE_HINT_QDEL + if(material.gas_tile_overlay) + icon_state = material.gas_tile_overlay + color = material.color \ No newline at end of file diff --git a/code/modules/materials/material_metabolism.dm b/code/modules/materials/material_metabolism.dm new file mode 100644 index 000000000000..71714cf27fb7 --- /dev/null +++ b/code/modules/materials/material_metabolism.dm @@ -0,0 +1,300 @@ +/decl/material/proc/on_leaving_metabolism(datum/reagents/metabolism/holder) + return + +/decl/material/proc/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) // Acid melting, cleaner cleaning, etc + if(solvent_power >= MAT_SOLVENT_MODERATE) + if(istype(O, /obj/item/paper) && amount >= FLUID_MINIMUM_TRANSFER) + var/obj/item/paper/paperaffected = O + paperaffected.clearpaper() + O.visible_message(SPAN_NOTICE("The solution dissolves the ink on the paper."), range = 1) + else if(istype(O, /obj/item/book) && amount >= FLUID_PUDDLE) + var/obj/item/book/affectedbook = O + if(affectedbook.clear_text()) + O.visible_message(SPAN_NOTICE("The solution dissolves the ink on the book."), range = 1) + else + O.visible_message(SPAN_WARNING("The solution does nothing. Whatever this is, it isn't normal ink."), range = 1) + + if(solvent_power >= MAT_SOLVENT_STRONG && O.solvent_can_melt(solvent_power) && (istype(O, /obj/item) || istype(O, /obj/effect/vine)) && (amount > solvent_melt_dose)) + O.visible_message(SPAN_DANGER("\The [O] dissolves!")) + O.handle_melting() + holder?.remove_reagent(src, solvent_melt_dose) + else if(defoliant && istype(O, /obj/effect/vine)) + qdel(O) + else + if(dirtiness <= DIRTINESS_DECONTAMINATE) + if(amount >= decontamination_dose && istype(O, /obj/item)) + var/obj/item/thing = O + if(thing.contaminated) + thing.decontaminate() + if(dirtiness <= DIRTINESS_STERILE) + O.germ_level -= min(amount*20, O.germ_level) + O.was_bloodied = FALSE + if(dirtiness <= DIRTINESS_CLEAN) + O.clean() + +#define FLAMMABLE_LIQUID_DIVISOR 7 +// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing. +/decl/material/proc/touch_mob(var/mob/living/M, var/amount, var/datum/reagents/holder) + if(accelerant_value != FUEL_VALUE_NONE && amount && istype(M)) + M.adjust_fire_intensity(floor((amount * accelerant_value)/FLAMMABLE_LIQUID_DIVISOR)) +#undef FLAMMABLE_LIQUID_DIVISOR + +/decl/material/proc/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) // Cleaner cleaning, lube lubbing, etc, all go here + + if(REAGENT_VOLUME(holder, src) < turf_touch_threshold) + return + + if(istype(touching_turf) && touching_turf.simulated) + if(defoliant) + for(var/obj/effect/overlay/wallrot/rot in touching_turf) + touching_turf.visible_message(SPAN_NOTICE("\The [rot] is completely dissolved by the solution!")) + qdel(rot) + if(slipperiness != 0 && !touching_turf.check_fluid_depth()) // Don't make floors slippery if they have an active fluid on top of them please. + if(slipperiness < 0) + touching_turf.unwet_floor(TRUE) + else if (REAGENT_VOLUME(holder, src) >= slippery_amount) + touching_turf.wet_floor(slipperiness) + + if(length(vapor_products)) + var/result_volume = REAGENT_VOLUME(holder, src) + var/atom/reagent_atom = REAGENT_GET_ATOM(holder) + var/temperature = reagent_atom?.temperature || T20C + for(var/vapor in vapor_products) + touching_turf.assume_gas(vapor, (result_volume * vapor_products[vapor]), temperature) + holder.remove_reagent(src, result_volume) + +/decl/material/proc/on_mob_life(var/mob/living/M, var/metabolism_class, var/datum/reagents/holder, var/list/life_dose_tracker) + + if(QDELETED(src)) + return // Something else removed us. + if(!istype(M)) + return + if(!(flags & AFFECTS_DEAD) && M.stat == DEAD && (world.time - M.timeofdeath > 150)) + return + + // Keep track of dosage of chems across holders for overdosing purposes + if(overdose && metabolism_class != CHEM_TOUCH && islist(life_dose_tracker)) + life_dose_tracker[src] += REAGENT_VOLUME(holder, src) + + //determine the metabolism rate + var/removed + switch(metabolism_class) + if(CHEM_INGEST) + removed = ingest_met + if(CHEM_TOUCH) + removed = touch_met + if(CHEM_INHALE) + removed = inhale_met + if(!removed) + removed = metabolism + if(!removed) + removed = metabolism + removed = M.get_adjusted_metabolism(removed) + + //adjust effective amounts - removed, dose, and max_dose - for mob size + var/effective = removed + if(!(flags & IGNORE_MOB_SIZE)) + effective *= (MOB_SIZE_MEDIUM/M.mob_size) + if(metabolism_class != CHEM_TOUCH) + var/dose = CHEM_DOSE(M, src) + effective + LAZYSET(M._chem_doses, src, dose) + + var/remove_dose = TRUE + if(effective >= (metabolism * 0.1) || effective >= 0.1) // If there's too little chemical, don't affect the mob, just remove it + switch(metabolism_class) + if(CHEM_INJECT) + affect_blood(M, effective, holder) + if(CHEM_INGEST) + affect_ingest(M, effective, holder) + if(CHEM_TOUCH) + remove_dose = affect_touch(M, effective, holder) + if(CHEM_INHALE) + affect_inhale(M, effective, holder) + if(remove_dose) + holder.remove_reagent(src, removed) + +/decl/material/proc/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + + SHOULD_CALL_PARENT(TRUE) + + if(M.status_flags & GODMODE) + return + + if(antibiotic_strength) + M.adjust_immunity(-0.1 * antibiotic_strength) + M.add_chemical_effect(CE_ANTIBIOTIC, antibiotic_strength) + if(REAGENT_VOLUME(holder, src) > 10) + M.adjust_immunity(-0.3 * antibiotic_strength) + if(CHEM_DOSE(M, src) > 15) + M.adjust_immunity(-0.25 * antibiotic_strength) + + if(nutriment_factor || hydration_factor) + if(injectable_nutrition) + adjust_mob_nutrition(M, removed, holder, CHEM_INJECT) + else + apply_intolerances(M, removed, holder, CHEM_INJECT) + M.take_damage(0.2 * removed, TOX) + else if(!injectable_nutrition) + apply_intolerances(M, removed, holder, CHEM_INJECT) + + if(radioactivity) + M.apply_damage(radioactivity * removed, IRRADIATE, armor_pen = 100) + + if(toxicity) + M.add_chemical_effect(CE_TOXIN, toxicity) + var/dam = (toxicity * removed) + if(toxicity_targets_organ && ishuman(M)) + var/organ_damage = dam * M.get_toxin_resistance() + if(organ_damage > 0) + var/mob/living/human/H = M + var/obj/item/organ/internal/organ = GET_INTERNAL_ORGAN(H, toxicity_targets_organ) + if(organ) + var/can_damage = organ.max_damage - organ.get_organ_damage() + if(can_damage > 0) + if(organ_damage > can_damage) + organ.take_damage(can_damage, silent=TRUE) + dam -= can_damage + else + organ.take_damage(organ_damage, silent=TRUE) + dam = 0 + if(dam > 0) + M.take_damage(toxicity_targets_organ ? (dam * 0.75) : dam, TOX) + + if(solvent_power >= MAT_SOLVENT_STRONG) + M.take_organ_damage(0, removed * solvent_power, override_droplimb = DISMEMBER_METHOD_ACID) + + if(narcosis) + if(prob(10)) + M.SelfMove(pick(global.cardinal)) + if(prob(narcosis)) + M.emote(pick(/decl/emote/visible/twitch, /decl/emote/visible/drool, /decl/emote/audible/moan)) + + if(euphoriant) + SET_STATUS_MAX(M, STAT_DRUGGY, euphoriant) + +/decl/material/proc/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + + SHOULD_CALL_PARENT(TRUE) + + adjust_mob_nutrition(M, removed, holder, CHEM_INGEST) + if(affect_blood_on_ingest) + affect_blood(M, removed * affect_blood_on_ingest, holder) + +/decl/material/proc/affect_inhale(var/mob/living/M, var/removed, var/datum/reagents/holder) + + SHOULD_CALL_PARENT(TRUE) + + apply_intolerances(M, removed, holder, CHEM_INHALE) + if(affect_blood_on_inhale) + affect_blood(M, removed * affect_blood_on_inhale, holder) + +// Major allergy - handled by handle_allergens() on /mob/living by default. +/decl/material/proc/apply_allergy_effects(mob/living/subject, removed, severity, ingestion_method) + if(allergen_factor > 0) + subject.add_chemical_effect(CE_ALLERGEN, removed * severity * allergen_factor) + else if(allergen_factor < 0) + subject.remove_chemical_effect(CE_ALLERGEN, removed * severity * allergen_factor) + +// Intolerance - TODO: more messages +/decl/material/proc/apply_intolerance_effects(mob/living/subject, removed, severity, ingestion_method) + if(ingestion_method != CHEM_INGEST) + return + if(ishuman(subject) && prob(removed)) + var/mob/living/human/puker = subject + puker.vomit() + else if(prob(1)) + var/static/list/intolerance_messages = list( + "Your innards churn and cramp unhappily." + ) + subject.custom_pain(pick(intolerance_messages), 1) + +/decl/material/proc/apply_intolerances(mob/living/subject, removed, datum/reagents/holder, ingestion_method) + + var/list/data = REAGENT_DATA(holder, src) + var/check_flags = LAZYACCESS(data, DATA_INGREDIENT_FLAGS) | allergen_flags + if(!check_flags) + return 1 + + var/list/intolerances = get_intolerances_by_flag(check_flags, ingestion_method) + if(!length(intolerances)) + return 1 + + var/malus_level = 0 + for(var/decl/trait/intolerance as anything in intolerances) + malus_level = max(malus_level, subject.get_trait_level(intolerance.type)) + if(!malus_level) + return 1 + + if(malus_level >= TRAIT_LEVEL_MAJOR) + apply_allergy_effects(subject, removed, malus_level, ingestion_method) + else if(malus_level >= TRAIT_LEVEL_MINOR) + apply_intolerance_effects(subject, removed, malus_level, ingestion_method) + return max(0, (1 - (malus_level * 0.25))) + +// Defined as a proc so it can be overridden. +/decl/material/proc/adjust_mob_nutrition(mob/living/subject, removed, datum/reagents/holder, ingestion_method) + var/metabolic_penalty = apply_intolerances(subject, removed, holder, ingestion_method) + if(nutriment_factor) + var/effective_power = nutriment_factor * metabolic_penalty * removed + if(effective_power) + subject.adjust_nutrition(effective_power) + if(hydration_factor) + var/effective_power = hydration_factor * metabolic_penalty * removed + if(effective_power) + subject.adjust_hydration(effective_power) + +// Slightly different to other reagent processing - return TRUE to consume the removed amount, FALSE not to consume. +/decl/material/proc/affect_touch(var/mob/living/victim, var/removed, var/datum/reagents/holder) + + SHOULD_CALL_PARENT(TRUE) + . = FALSE + if(!istype(victim)) + return FALSE + + if(radioactivity) + victim.apply_damage((radioactivity / 2) * removed, IRRADIATE) + . = TRUE + + if(dirtiness <= DIRTINESS_STERILE) + if(victim.germ_level < INFECTION_LEVEL_TWO) // rest and antibiotics is required to cure serious infections + victim.germ_level -= min(removed*20, victim.germ_level) + for(var/obj/item/organ in victim.contents) + organ.was_bloodied = FALSE + victim.was_bloodied = FALSE + . = TRUE + + // TODO: clean should add the gross reagents washed off to a holder to dump on the loc. + if(dirtiness <= DIRTINESS_CLEAN) + for(var/obj/item/thing in victim.get_held_items()) + thing.clean() + var/obj/item/mask = victim.get_equipped_item(slot_wear_mask_str) + if(mask) + mask.clean() + if(ishuman(victim)) + var/mob/living/human/human_victim = victim + var/obj/item/head = human_victim.get_equipped_item(slot_head_str) + if(head) + head.clean() + var/obj/item/suit = human_victim.get_equipped_item(slot_wear_suit_str) + if(suit) + suit.clean() + else + var/obj/item/uniform = human_victim.get_equipped_item(slot_w_uniform_str) + if(uniform) + uniform.clean() + + var/obj/item/shoes = human_victim.get_equipped_item(slot_shoes_str) + if(shoes) + shoes.clean() + else + human_victim.clean() + else + victim.clean() + + if(solvent_power > MAT_SOLVENT_NONE && removed >= solvent_melt_dose && victim.solvent_act(min(removed * solvent_power * ((removed < solvent_melt_dose) ? 0.1 : 0.2), solvent_max_damage), solvent_melt_dose, solvent_power)) + holder.remove_reagent(src, REAGENT_VOLUME(holder, src)) + . = TRUE + +/decl/material/proc/affect_overdose(mob/living/victim, total_dose) // Overdose effect. Doesn't happen instantly. + victim.add_chemical_effect(CE_TOXIN, 1) + victim.take_damage(REM, TOX) \ No newline at end of file diff --git a/code/modules/materials/material_physics.dm b/code/modules/materials/material_physics.dm new file mode 100644 index 000000000000..337989dd2109 --- /dev/null +++ b/code/modules/materials/material_physics.dm @@ -0,0 +1,76 @@ +//Clausius–Clapeyron relation +/decl/material/proc/get_boiling_temp(var/pressure = ONE_ATMOSPHERE) + var/pressure_ratio = (pressure > 0)? log(pressure / ONE_ATMOSPHERE) : 0 + return (1 / (1/max(boiling_point, TCMB)) - ((R_IDEAL_GAS_EQUATION * pressure_ratio) / (latent_heat * molar_mass))) + +/// Returns the phase of the matterial at the given temperature and pressure +/// Defaults to standard temperature and pressure (20c at one atmosphere) +/decl/material/proc/phase_at_temperature(var/temperature = T20C, var/pressure = ONE_ATMOSPHERE) + //#TODO: implement plasma temperature and do pressure checks + if(!isnull(boiling_point) && temperature >= get_boiling_temp(pressure)) + return MAT_PHASE_GAS + else if(!isnull(heating_point) && temperature >= heating_point || \ + !isnull(melting_point) && temperature >= melting_point) + return MAT_PHASE_LIQUID + return MAT_PHASE_SOLID + +// Returns the number of mols of material for the amount of solid or liquid units passed. +/decl/material/proc/get_mols_from_units(units, phase) + var/ml = units*10 // Rough estimation. + switch(phase) + if(MAT_PHASE_LIQUID) + var/kg = (liquid_density*ml)/1000 + return kg/molar_mass + if(MAT_PHASE_SOLID) + var/kg = (solid_density*ml)/1000 + return kg/molar_mass + else + log_warning("Invalid phase '[phase]' passed to get_mols_from_units!") + return units + +/decl/material/proc/neutron_interact(var/neutron_energy, var/total_interacted_units, var/total_units) + . = list() // Returns associative list of interaction -> interacted units + if(!length(neutron_interactions)) + return + for(var/interaction in neutron_interactions) + var/ideal_energy = neutron_interactions[interaction] + var/interacted_units_ratio = (clamp(-((((neutron_energy-ideal_energy)**2)/(neutron_cross_section*1000)) - 100), 0, 100))/100 + var/interacted_units = round(interacted_units_ratio*total_interacted_units, 0.001) + + if(interacted_units > 0) + .[interaction] = interacted_units + total_interacted_units -= interacted_units + if(total_interacted_units <= 0) + return + +/decl/material/proc/add_burn_product(var/datum/gas_mixture/environment, var/amount) + if(!environment || amount <= 0 || !burn_product) + return + environment.adjust_gas(burn_product, amount) + +// Returns null for no burn, empty list for burn with no products, assoc +// matter to value list for waste products. +// We assume a normalized mole amount for 'amount'. +/decl/material/proc/get_burn_products(var/amount, var/burn_temperature, var/ambient_pressure) + + // No chance of burning. + if(isnull(ignition_point) && isnull(boiling_point) && !length(vapor_products)) + return + + // Burning a reagent of any kind. + if(ignition_point && burn_temperature >= ignition_point) + . = list() // We need to return a non-null value to indicate we consumed the material. + if(burn_product) + .[burn_product] = amount + return + + // If it has a vapor product, turn it into that. + if(length(vapor_products)) + . = list() + for(var/vapor in vapor_products) + .[vapor] = (amount * vapor_products[vapor]) + return + + // If it's not ignitable but can be boiled, consider vaporizing it. + if(!isnull(boiling_point) && phase_at_temperature(burn_temperature, ambient_pressure) == MAT_PHASE_GAS) + LAZYSET(., src, amount) diff --git a/code/modules/materials/material_product_spawning.dm b/code/modules/materials/material_product_spawning.dm new file mode 100644 index 000000000000..8e5711291cd7 --- /dev/null +++ b/code/modules/materials/material_product_spawning.dm @@ -0,0 +1,64 @@ +/// Generic material product (sheets, bricks, etc). Used ALL THE TIME. +/// May return an instance list, a single instance, or nothing if there is no instance produced. +/decl/material/proc/create_object(var/atom/target, var/amount = 1, var/object_type, var/reinf_type) + + if(!object_type) + object_type = default_solid_form + + if(!ispath(object_type, /atom/movable)) + CRASH("Non-movable path '[object_type || "NULL"]' supplied to [type] create_object()") + + if(ispath(object_type, /obj/item/stack)) + var/obj/item/stack/stack_type = object_type + var/divisor = initial(stack_type.max_amount) + while(amount >= divisor) + LAZYADD(., new object_type(target, divisor, type, reinf_type)) + amount -= divisor + if(amount >= 1) + LAZYADD(., new object_type(target, amount, type, reinf_type)) + else + for(var/i = 1 to amount) + var/atom/movable/placed = new object_type(target, type, reinf_type) + if(istype(placed)) + LAZYADD(., placed) + + if(istype(target) && LAZYLEN(.)) + for(var/atom/movable/placed in .) + placed.dropInto(target) + +// Places a girder object when a wall is dismantled, also applies reinforced material. +/decl/material/proc/place_dismantled_girder(var/turf/target, var/decl/material/r_mat) + return create_object(target, 1, /obj/structure/girder, ispath(r_mat) ? r_mat : r_mat?.type) + +// General wall debris product placement. +// Not particularly necessary aside from snowflakey cult girders. +/decl/material/proc/place_dismantled_product(var/turf/target, var/is_devastated, var/amount = 2, var/drop_type) + amount = is_devastated ? floor(amount * 0.5) : amount + if(amount > 0) + return create_object(target, amount, object_type = drop_type) + +// As above. +/decl/material/proc/place_shards(var/turf/target, var/amount = 1) + if(shard_name) + return create_object(target, amount, /obj/item/shard) + +/**Places down as many shards as needed for the given amount of matter units. Returns a list of all the cuttings. */ +/decl/material/proc/place_cuttings(var/turf/target, var/matter_units) + if(!shard_type && matter_units <= 0) + return + var/list/shard_mat = atom_info_repository.get_matter_for(shard_type, type, 1) + var/amount_per_shard = LAZYACCESS(shard_mat, type) + if(amount_per_shard < 1) + return + + //Make all the shards we can + var/shard_amount = round(matter_units / amount_per_shard) + var/matter_left = round(matter_units % amount_per_shard) + LAZYADD(., create_object(target, shard_amount, shard_type)) + + //If we got more than expected, just make a shard with that amount + if(matter_left > 0) + var/list/O = create_object(target, 1, shard_type) + var/obj/S = O[O.len] + LAZYSET(S.matter, type, matter_left) + LAZYADD(., S) \ No newline at end of file diff --git a/code/modules/materials/material_properties.dm b/code/modules/materials/material_properties.dm new file mode 100644 index 000000000000..187544ed00e9 --- /dev/null +++ b/code/modules/materials/material_properties.dm @@ -0,0 +1,17 @@ +// Currently used for weapons and objects made of uranium to irradiate things. +/decl/material/proc/products_need_process() + return (radioactivity>0) //todo + +// Used by walls and weapons to determine if they break or not. +/decl/material/proc/is_brittle() + return !!(flags & MAT_FLAG_BRITTLE) + +/decl/material/proc/can_hold_sharpness() + return hardness > MAT_VALUE_FLEXIBLE + +/decl/material/proc/can_hold_edge() + return hardness > MAT_VALUE_FLEXIBLE + +// TODO: expand this to more than just Actual Poison. +/decl/material/proc/is_unsafe_to_drink(mob/user) + return toxicity > 0 \ No newline at end of file diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm deleted file mode 100644 index 4302ea302266..000000000000 --- a/code/modules/materials/material_recipes.dm +++ /dev/null @@ -1,65 +0,0 @@ -/decl/material/proc/get_recipes(var/reinf_mat) - var/key = reinf_mat ? reinf_mat : "base" - if(!LAZYACCESS(recipes,key)) - LAZYSET(recipes,key,generate_recipes(reinf_mat)) - return recipes[key] - -/decl/material/proc/create_recipe_list(base_type) - . = list() - for(var/recipe_type in subtypesof(base_type)) - . += new recipe_type(src) - -/decl/material/proc/generate_recipes(var/reinforce_material) - . = list() - - if(opacity < 0.6) - . += new/datum/stack_recipe/furniture/borderwindow(src, reinforce_material) - . += new/datum/stack_recipe/furniture/fullwindow(src, reinforce_material) - if(integrity > 75 || reinforce_material) - . += new/datum/stack_recipe/furniture/windoor(src, reinforce_material) - - if(reinforce_material) //recipes below don't support composite materials - return - - // If is_brittle() returns true, these are only good for a single strike. - . += new/datum/stack_recipe/ashtray(src) - . += new/datum/stack_recipe/ring(src) - . += new/datum/stack_recipe/clipboard(src) - . += new/datum/stack_recipe/cross(src) - . += new/datum/stack_recipe/improvised_armour(src) - . += new/datum/stack_recipe/armguards(src) - . += new/datum/stack_recipe/legguards(src) - . += new/datum/stack_recipe/gauntlets(src) - - if(hardness >= MAT_VALUE_FLEXIBLE) - . += new/datum/stack_recipe/baseball_bat(src) - . += new/datum/stack_recipe/urn(src) - . += new/datum/stack_recipe/spoon(src) - . += new/datum/stack_recipe/coin(src) - - if(wall_support_value >= 10) - . += new/datum/stack_recipe/furniture/girder(src) - . += new/datum/stack_recipe/furniture/ladder(src) - - if(integrity >= 50 && hardness >= MAT_VALUE_FLEXIBLE + 10) - . += new/datum/stack_recipe/furniture/door(src) - . += new/datum/stack_recipe/furniture/barricade(src) - . += new/datum/stack_recipe/furniture/stool(src) - . += new/datum/stack_recipe/furniture/bar_stool(src) - . += new/datum/stack_recipe/furniture/bed(src) - . += new/datum/stack_recipe/furniture/pew(src) - . += new/datum/stack_recipe/furniture/pew_left(src) - . += new/datum/stack_recipe/furniture/chair(src) //NOTE: the wood material has it's own special chair recipe - . += new/datum/stack_recipe_list("padded [name] chairs", create_recipe_list(/datum/stack_recipe/furniture/chair/padded)) - . += new/datum/stack_recipe/lock(src) - . += new/datum/stack_recipe/railing(src) - . += new/datum/stack_recipe/rod(src) - . += new/datum/stack_recipe/furniture/wall_frame(src) - . += new/datum/stack_recipe/furniture/table_frame(src) - - if(hardness > MAT_VALUE_RIGID + 10) - . += new/datum/stack_recipe/fork(src) - . += new/datum/stack_recipe/knife(src) - . += new/datum/stack_recipe/bell(src) - . += new/datum/stack_recipe/blade(src) - . += new/datum/stack_recipe/drill_head(src) diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm deleted file mode 100644 index 76d5266c2a72..000000000000 --- a/code/modules/materials/material_sheets.dm +++ /dev/null @@ -1,527 +0,0 @@ -// Stacked resources. They use a material datum for a lot of inherited values. -/obj/item/stack/material - force = 5.0 - throwforce = 5 - w_class = ITEM_SIZE_LARGE - throw_speed = 3 - throw_range = 3 - max_amount = 60 - randpixel = 3 - icon = 'icons/obj/materials.dmi' - matter = null - - var/decl/material/reinf_material - var/material_flags = USE_MATERIAL_COLOR|USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME - -/obj/item/stack/material/Initialize(mapload, var/amount, var/_material, var/_reinf_material) - . = ..(mapload, amount, _material) - if(!istype(material)) - return INITIALIZE_HINT_QDEL - if(!_reinf_material) - _reinf_material = reinf_material - if(_reinf_material) - reinf_material = decls_repository.get_decl(_reinf_material) - if(!istype(reinf_material)) - reinf_material = null - base_state = icon_state - - if(!stacktype) - stacktype = material.stack_type - origin_tech = origin_tech || material.stack_origin_tech - - if(material.conductive) - obj_flags |= OBJ_FLAG_CONDUCTIBLE - else - obj_flags &= (~OBJ_FLAG_CONDUCTIBLE) - update_strings() - -/obj/item/stack/material/list_recipes(mob/user, recipes_sublist) - if(!material) - return - recipes = material.get_recipes(reinf_material && reinf_material.type) - ..() - -/obj/item/stack/material/get_codex_value() - return (material && !material.hidden_from_codex) ? "[lowertext(material.solid_name)] (material)" : ..() - -/obj/item/stack/material/get_material() - return material - -/obj/item/stack/material/update_matter() - create_matter() - -/obj/item/stack/material/create_matter() - matter = list() - if(istype(material)) - matter[material.type] = MATTER_AMOUNT_PRIMARY * get_matter_amount_modifier() - if(istype(reinf_material)) - matter[reinf_material.type] = MATTER_AMOUNT_REINFORCEMENT * get_matter_amount_modifier() - -/obj/item/stack/material/proc/update_strings() - // Update from material datum. - if(material_flags & USE_MATERIAL_SINGULAR_NAME) - singular_name = material.sheet_singular_name - - if(material_flags & USE_MATERIAL_PLURAL_NAME) - plural_name = material.sheet_plural_name - - if(amount>1) - SetName("[material.use_name] [plural_name]") - desc = "A stack of [material.use_name] [plural_name]." - gender = PLURAL - else - SetName("[material.use_name] [singular_name]") - desc = "A [singular_name] of [material.use_name]." - gender = NEUTER - if(reinf_material) - SetName("reinforced [name]") - desc = "[desc]\nIt is reinforced with the [reinf_material.use_name] lattice." - -/obj/item/stack/material/use(var/used) - . = ..() - update_strings() - -/obj/item/stack/material/proc/is_same(obj/item/stack/material/M) - if(!istype(M)) - return FALSE - if(matter_multiplier != M.matter_multiplier) - return FALSE - if(material.type != M.material.type) - return FALSE - if((reinf_material && reinf_material.type) != (M.reinf_material && M.reinf_material.type)) - return FALSE - return TRUE - -/obj/item/stack/material/transfer_to(obj/item/stack/material/M, var/tamount=null, var/type_verified) - if(!is_same(M)) - return 0 - var/transfer = ..(M,tamount,1) - if(!QDELETED(src)) - update_strings() - if(!QDELETED(M)) - M.update_strings() - return transfer - -/obj/item/stack/material/copy_from(var/obj/item/stack/material/other) - ..() - if(istype(other)) - material = other.material - reinf_material = other.reinf_material - update_strings() - update_icon() - -/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/stack/material)) - if(is_same(W)) - ..() - else if(!reinf_material) - material.reinforce(user, W, src) - return - else if(reinf_material && reinf_material.stack_type && isWelder(W)) - var/obj/item/weldingtool/WT = W - if(WT.isOn() && WT.get_fuel() > 2 && use(2)) - WT.remove_fuel(2, user) - to_chat(user,"You recover some [reinf_material.use_name] from the [src].") - reinf_material.place_sheet(get_turf(user), 1) - return - return ..() - -/obj/item/stack/material/on_update_icon() - if(material_flags & USE_MATERIAL_COLOR) - color = material.color - alpha = 100 + max(1, amount/25)*(material.opacity * 255) - if(max_icon_state && amount == max_amount) - icon_state = max_icon_state - else if(plural_icon_state && amount > 2) - icon_state = plural_icon_state - else - icon_state = base_state - -/obj/item/stack/material/iron - name = "iron" - icon_state = "ingot" - plural_icon_state = "ingot-mult" - max_icon_state = "ingot-max" - material = /decl/material/solid/metal/iron - -/obj/item/stack/material/sandstone - name = "sandstone brick" - icon_state = "brick" - plural_icon_state = "brick-mult" - max_icon_state = "brick-max" - material = /decl/material/solid/stone/sandstone - -/obj/item/stack/material/marble - name = "marble brick" - icon_state = "brick" - plural_icon_state = "brick-mult" - max_icon_state = "brick-max" - material = /decl/material/solid/stone/marble - -/obj/item/stack/material/marble/ten - amount = 10 - -/obj/item/stack/material/marble/fifty - amount = 50 - -/obj/item/stack/material/diamond - name = "diamond" - icon_state = "diamond" - plural_icon_state = "diamond-mult" - max_icon_state = "diamond-max" - material = /decl/material/solid/gemstone/diamond - -/obj/item/stack/material/diamond/ten - amount = 10 - -/obj/item/stack/material/uranium - name = "uranium" - icon_state = "sheet-faery-uranium" - plural_icon_state = "sheet-faery-uranium-mult" - max_icon_state = "sheet-faery-uranium-max" - material = /decl/material/solid/metal/uranium - material_flags = USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME - -/obj/item/stack/material/uranium/ten - amount = 10 - -/obj/item/stack/material/plastic - name = "plastic" - icon_state = "sheet-plastic" - plural_icon_state = "sheet-plastic-mult" - max_icon_state = "sheet-plastic-max" - material = /decl/material/solid/plastic - -/obj/item/stack/material/plastic/ten - amount = 10 - -/obj/item/stack/material/plastic/fifty - amount = 50 - -/obj/item/stack/material/gold - name = "gold" - icon_state = "ingot" - plural_icon_state = "ingot-mult" - max_icon_state = "ingot-max" - material = /decl/material/solid/metal/gold - -/obj/item/stack/material/gold/ten - amount = 10 - -/obj/item/stack/material/silver - name = "silver" - icon_state = "ingot" - plural_icon_state = "ingot-mult" - max_icon_state = "ingot-max" - material = /decl/material/solid/metal/silver - -/obj/item/stack/material/silver/ten - amount = 10 - -//Valuable resource, cargo can sell it. -/obj/item/stack/material/platinum - name = "platinum" - icon_state = "ingot" - plural_icon_state = "ingot-mult" - max_icon_state = "ingot-max" - material = /decl/material/solid/metal/platinum - -/obj/item/stack/material/platinum/ten - amount = 10 - -//Extremely valuable to Research. -/obj/item/stack/material/mhydrogen - name = "metallic hydrogen" - icon_state = "sheet-mythril" - material = /decl/material/solid/metallic_hydrogen - material_flags = USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME - -/obj/item/stack/material/mhydrogen/ten - amount = 10 - -//Fuel for MRSPACMAN generator. -/obj/item/stack/material/tritium - name = "tritium" - icon_state = "puck" - plural_icon_state = "puck-mult" - max_icon_state = "puck-max" - material = /decl/material/gas/hydrogen/tritium - -/obj/item/stack/material/tritium/ten - amount = 10 - -/obj/item/stack/material/tritium/fifty - amount = 50 - -/obj/item/stack/material/osmium - name = "osmium" - icon_state = "ingot" - plural_icon_state = "ingot-mult" - max_icon_state = "ingot-max" - material = /decl/material/solid/metal/osmium - -/obj/item/stack/material/osmium/ten - amount = 10 - -/obj/item/stack/material/ocp - name = "osmium-carbide plasteel" - icon_state = "sheet-reinf" - item_state = "sheet-metal" - plural_icon_state = "sheet-reinf-mult" - max_icon_state = "sheet-reinf-max" - material = /decl/material/solid/metal/plasteel/ocp - -/obj/item/stack/material/ocp/ten - amount = 10 - -/obj/item/stack/material/ocp/fifty - amount = 50 - -// Fusion fuel. -/obj/item/stack/material/deuterium - name = "deuterium" - icon_state = "puck" - plural_icon_state = "puck-mult" - max_icon_state = "puck-max" - material = /decl/material/gas/hydrogen/deuterium - -/obj/item/stack/material/deuterium/fifty - amount = 50 - -/obj/item/stack/material/steel - name = "steel" - icon_state = "sheet" - plural_icon_state = "sheet-mult" - max_icon_state = "sheet-max" - material = /decl/material/solid/metal/steel - -/obj/item/stack/material/steel/ten - amount = 10 - -/obj/item/stack/material/steel/fifty - amount = 50 - -/obj/item/stack/material/aluminium - name = "aluminium" - icon_state = "sheet-sheen" - item_state = "sheet-shiny" - plural_icon_state = "sheet-sheen-mult" - max_icon_state = "sheet-sheen-max" - material = /decl/material/solid/metal/aluminium - -/obj/item/stack/material/aluminium/ten - amount = 10 - -/obj/item/stack/material/aluminium/fifty - amount = 50 - -/obj/item/stack/material/titanium - name = "titanium" - icon_state = "sheet" - plural_icon_state = "sheet-mult" - material = /decl/material/solid/metal/plasteel/titanium - -/obj/item/stack/material/titanium/ten - amount = 10 - -/obj/item/stack/material/titanium/fifty - amount = 50 - -/obj/item/stack/material/plasteel - name = "plasteel" - icon_state = "sheet-reinf" - item_state = "sheet-metal" - plural_icon_state = "sheet-reinf-mult" - max_icon_state = "sheet-reinf-max" - material = /decl/material/solid/metal/plasteel - -/obj/item/stack/material/plasteel/ten - amount = 10 - -/obj/item/stack/material/plasteel/fifty - amount = 50 - -/obj/item/stack/material/wood - name = "wooden plank" - icon_state = "sheet-wood" - plural_icon_state = "sheet-wood-mult" - max_icon_state = "sheet-wood-max" - material = /decl/material/solid/wood - -/obj/item/stack/material/wood/ten - amount = 10 - -/obj/item/stack/material/wood/fifty - amount = 50 - -/obj/item/stack/material/wood/mahogany - name = "mahogany plank" - material = /decl/material/solid/wood/mahogany - -/obj/item/stack/material/wood/mahogany/ten - amount = 10 - -/obj/item/stack/material/wood/mahogany/twentyfive - amount = 25 - -/obj/item/stack/material/wood/maple - name = "maple plank" - material = /decl/material/solid/wood/maple - -/obj/item/stack/material/wood/maple/ten - amount = 10 - -/obj/item/stack/material/wood/maple/twentyfive - amount = 25 - -/obj/item/stack/material/wood/ebony - name = "ebony plank" - material = /decl/material/solid/wood/ebony - -/obj/item/stack/material/wood/ebony/ten - amount = 10 - -/obj/item/stack/material/wood/ebony/twentyfive - amount = 25 - -/obj/item/stack/material/wood/walnut - name = "walnut plank" - material = /decl/material/solid/wood/walnut - -/obj/item/stack/material/wood/walnut/ten - amount = 10 - -/obj/item/stack/material/wood/walnut/twentyfive - amount = 25 - -/obj/item/stack/material/wood/bamboo - name = "bamboo plank" - material = /decl/material/solid/wood/bamboo - -/obj/item/stack/material/wood/bamboo/ten - amount = 10 - -/obj/item/stack/material/wood/bamboo/fifty - amount = 50 - -/obj/item/stack/material/wood/yew - name = "yew plank" - material = /decl/material/solid/wood/yew - -/obj/item/stack/material/wood/yew/ten - amount = 10 - -/obj/item/stack/material/wood/yew/twentyfive - amount = 25 - -/obj/item/stack/material/cloth - name = "cloth" - icon_state = "sheet-cloth" - material = /decl/material/solid/cloth - -/obj/item/stack/material/cardboard - name = "cardboard" - icon_state = "sheet-card" - plural_icon_state = "sheet-card-mult" - max_icon_state = "sheet-card-max" - material = /decl/material/solid/cardboard - material_flags = USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME - -/obj/item/stack/material/cardboard/ten - amount = 10 - -/obj/item/stack/material/cardboard/fifty - amount = 50 - -/obj/item/stack/material/leather - name = "leather" - desc = "The by-product of mob grinding." - icon_state = "sheet-leather" - material = /decl/material/solid/leather - material_flags = USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME - -/obj/item/stack/material/glass - name = "glass" - icon_state = "sheet-clear" - plural_icon_state = "sheet-clear-mult" - max_icon_state = "sheet-clear-max" - material = /decl/material/solid/glass - -/obj/item/stack/material/glass/on_update_icon() - if(reinf_material) - icon_state = "sheet-glass-reinf" - base_state = icon_state - plural_icon_state = "sheet-glass-reinf-mult" - max_icon_state = "sheet-glass-reinf-max" - else - icon_state = "sheet-clear" - base_state = icon_state - plural_icon_state = "sheet-clear-mult" - max_icon_state = "sheet-clear-max" - ..() - -/obj/item/stack/material/glass/ten - amount = 10 - -/obj/item/stack/material/glass/fifty - amount = 50 - -/obj/item/stack/material/glass/reinforced - name = "reinforced glass" - icon_state = "sheet-reinf" - plural_icon_state = "sheet-reinf-mult" - max_icon_state = "sheet-reinf-max" - material = /decl/material/solid/glass - reinf_material = /decl/material/solid/metal/steel - -/obj/item/stack/material/glass/reinforced/ten - amount = 10 - -/obj/item/stack/material/glass/reinforced/fifty - amount = 50 - -/obj/item/stack/material/glass/borosilicate - name = "borosilicate glass" - material = /decl/material/solid/glass/borosilicate - -/obj/item/stack/material/glass/reinforced_borosilicate - name = "reinforced borosilicate glass" - material = /decl/material/solid/glass/borosilicate - reinf_material = /decl/material/solid/metal/steel - -/obj/item/stack/material/glass/reinforced_borosilicate/ten - amount = 10 - -/obj/item/stack/material/aliumium - name = "alien alloy" - icon_state = "sheet" - plural_icon_state = "sheet-mult" - max_icon_state = "sheet-max" - material = /decl/material/solid/metal/aliumium - -/obj/item/stack/material/aliumium/ten - amount = 10 - -/obj/item/stack/material/generic - icon_state = "sheet" - plural_icon_state = "sheet-mult" - max_icon_state = "sheet-max" - -/obj/item/stack/material/generic/Initialize() - . = ..() - if(material) color = material.color - -/obj/item/stack/material/generic/skin - icon_state = "skin" - plural_icon_state = "skin-mult" - max_icon_state = "skin-max" - -/obj/item/stack/material/generic/bone - icon_state = "bone" - plural_icon_state = "bone-mult" - max_icon_state = "bone-max" - -/obj/item/stack/material/generic/brick - icon_state = "brick" - plural_icon_state = "brick-mult" - max_icon_state = "brick-max" diff --git a/code/modules/materials/material_stack_mapping.dm b/code/modules/materials/material_stack_mapping.dm new file mode 100644 index 000000000000..c98670be7bc1 --- /dev/null +++ b/code/modules/materials/material_stack_mapping.dm @@ -0,0 +1,78 @@ +DEFINE_STACK_SUBTYPES(tritium, "tritium", gas/hydrogen/tritium, aerogel, null) +DEFINE_STACK_SUBTYPES(deuterium, "deuterium", gas/hydrogen/deuterium, aerogel, null) +DEFINE_STACK_SUBTYPES(iron, "iron", solid/metal/iron, ingot, null) +DEFINE_STACK_SUBTYPES(copper, "copper", solid/metal/copper, ingot, null) +DEFINE_STACK_SUBTYPES(sandstone, "sandstone", solid/stone/sandstone, brick, null) +DEFINE_STACK_SUBTYPES(marble, "marble", solid/stone/marble, brick, null) +DEFINE_STACK_SUBTYPES(basalt, "basalt", solid/stone/basalt, brick, null) +DEFINE_STACK_SUBTYPES(concrete, "concrete", solid/stone/concrete, brick, null) +DEFINE_STACK_SUBTYPES(graphite, "graphite", solid/graphite, brick, null) +DEFINE_STACK_SUBTYPES(diamond, "diamond", solid/gemstone/diamond, gemstone, null) +DEFINE_STACK_SUBTYPES(uranium, "uranium", solid/metal/uranium, puck, null) +DEFINE_STACK_SUBTYPES(plastic, "plastic", solid/organic/plastic, panel, null) +DEFINE_STACK_SUBTYPES(fiberglass, "fiberglass", solid/fiberglass, sheet/reinforced, null) +DEFINE_STACK_SUBTYPES(gold, "gold", solid/metal/gold, ingot, null) +DEFINE_STACK_SUBTYPES(silver, "silver", solid/metal/silver, ingot, null) +DEFINE_STACK_SUBTYPES(platinum, "platinum", solid/metal/platinum, ingot, null) +DEFINE_STACK_SUBTYPES(mhydrogen, "metallic hydrogen", solid/metallic_hydrogen, segment, null) +DEFINE_STACK_SUBTYPES(osmium, "osmium", solid/metal/osmium, ingot, null) +DEFINE_STACK_SUBTYPES(ocp, "osmium-carbide plasteel", solid/metal/plasteel/ocp, sheet/reinforced, null) +DEFINE_STACK_SUBTYPES(steel, "steel", solid/metal/steel, sheet, null) +DEFINE_STACK_SUBTYPES(aluminium, "aluminium", solid/metal/aluminium, sheet/shiny, null) +DEFINE_STACK_SUBTYPES(titanium, "titanium", solid/metal/titanium, sheet/reinforced, null) +DEFINE_STACK_SUBTYPES(plasteel, "plasteel", solid/metal/plasteel, sheet/reinforced, null) +DEFINE_STACK_SUBTYPES(wood, "wood", solid/organic/wood/oak, plank, null) +DEFINE_STACK_SUBTYPES(mahogany, "mahogany", solid/organic/wood/mahogany, plank, null) +DEFINE_STACK_SUBTYPES(maple, "maple", solid/organic/wood/maple, plank, null) +DEFINE_STACK_SUBTYPES(ebony, "ebony", solid/organic/wood/ebony, plank, null) +DEFINE_STACK_SUBTYPES(walnut, "walnut", solid/organic/wood/walnut, plank, null) +DEFINE_STACK_SUBTYPES(bamboo, "bamboo", solid/organic/wood/bamboo, plank, null) +DEFINE_STACK_SUBTYPES(yew, "yew", solid/organic/wood/yew, plank, null) +DEFINE_STACK_SUBTYPES(wood, "wood", solid/organic/wood/oak, log, null) +DEFINE_STACK_SUBTYPES(mahogany, "mahogany", solid/organic/wood/mahogany, log, null) +DEFINE_STACK_SUBTYPES(maple, "maple", solid/organic/wood/maple, log, null) +DEFINE_STACK_SUBTYPES(ebony, "ebony", solid/organic/wood/ebony, log, null) +DEFINE_STACK_SUBTYPES(walnut, "walnut", solid/organic/wood/walnut, log, null) +DEFINE_STACK_SUBTYPES(bamboo, "bamboo", solid/organic/wood/bamboo, log, null) +DEFINE_STACK_SUBTYPES(yew, "yew", solid/organic/wood/yew, log, null) +DEFINE_STACK_SUBTYPES(cardboard, "cardboard", solid/organic/cardboard, cardstock, null) +DEFINE_STACK_SUBTYPES(leather, "leather", solid/organic/leather, skin, null) +DEFINE_STACK_SUBTYPES(synthleather, "synthleather", solid/organic/leather/synth, skin, null) +DEFINE_STACK_SUBTYPES(chitin, "chitin", solid/organic/leather/chitin, skin, null) +DEFINE_STACK_SUBTYPES(bone, "bone", solid/organic/bone, bone, null) +DEFINE_STACK_SUBTYPES(glass, "glass", solid/glass, pane, null) +DEFINE_STACK_SUBTYPES(borosilicate, "borosilicate glass", solid/glass/borosilicate, pane, null) +DEFINE_STACK_SUBTYPES(aliumium, "aliumium", solid/metal/aliumium, cubes, null) +DEFINE_STACK_SUBTYPES(rglass, "reinforced glass", solid/glass, pane, /decl/material/solid/metal/steel) +DEFINE_STACK_SUBTYPES(rborosilicate, "reinforced borosilicate glass", solid/glass/borosilicate, pane, /decl/material/solid/metal/steel) +DEFINE_STACK_SUBTYPES(zinc, "zinc", solid/metal/zinc, ingot, null) +DEFINE_STACK_SUBTYPES(tin, "tin", solid/metal/tin, ingot, null) +DEFINE_STACK_SUBTYPES(lead, "lead", solid/metal/lead, ingot, null) +DEFINE_STACK_SUBTYPES(brass, "brass", solid/metal/brass, ingot, null) +DEFINE_STACK_SUBTYPES(bronze, "bronze", solid/metal/bronze, ingot, null) +DEFINE_STACK_SUBTYPES(chromium, "chromium", solid/metal/chromium, ingot, null) +DEFINE_STACK_SUBTYPES(blackbronze, "black bronze", solid/metal/blackbronze, ingot, null) +DEFINE_STACK_SUBTYPES(redgold, "red gold", solid/metal/redgold, ingot, null) +DEFINE_STACK_SUBTYPES(stainlesssteel, "stainless steel", solid/metal/stainlesssteel, ingot, null) +DEFINE_STACK_SUBTYPES(ice, "ice", liquid/water, cubes, null) +DEFINE_STACK_SUBTYPES(nutriment, "nutriment", liquid/nutriment, segment, null) + +DEFINE_STACK_SUBTYPES(steel, "steel", solid/metal/steel, rods, null) +DEFINE_STACK_SUBTYPES(plastic, "plastic", solid/organic/plastic, rods, null) +DEFINE_STACK_SUBTYPES(aluminium, "aluminium", solid/metal/aluminium, rods, null) +DEFINE_STACK_SUBTYPES(titanium, "titanium", solid/metal/titanium, rods, null) + +DEFINE_STACK_SUBTYPES(cotton, "cotton", solid/organic/cloth, thread, null) +DEFINE_STACK_SUBTYPES(cloth, "cloth", solid/organic/cloth, bolt, null) + +DEFINE_STACK_SUBTYPES(dried_gut, "dried gut", solid/organic/leather/gut, thread, null) + +DEFINE_STACK_SUBTYPES(iron, "iron", solid/metal/iron, bar, null) +DEFINE_STACK_SUBTYPES(copper, "copper", solid/metal/copper, bar, null) + +DEFINE_STACK_SUBTYPES(chipboard_oak, "oak chipboard", solid/organic/wood/chipboard, sheet, null) +DEFINE_STACK_SUBTYPES(chipboard_maple, "maple chipboard", solid/organic/wood/chipboard/maple, sheet, null) +DEFINE_STACK_SUBTYPES(chipboard_mahogany, "mahogany chipboard", solid/organic/wood/chipboard/mahogany, sheet, null) +DEFINE_STACK_SUBTYPES(chipboard_ebony, "ebony chipboard", solid/organic/wood/chipboard/ebony, sheet, null) +DEFINE_STACK_SUBTYPES(chipboard_walnut, "walnut chipboard", solid/organic/wood/chipboard/walnut, sheet, null) +DEFINE_STACK_SUBTYPES(chipboard_yew, "yew chipboard", solid/organic/wood/chipboard/yew, sheet, null) diff --git a/code/modules/materials/material_stack_synth.dm b/code/modules/materials/material_stack_synth.dm new file mode 100644 index 000000000000..26d3323a81ca --- /dev/null +++ b/code/modules/materials/material_stack_synth.dm @@ -0,0 +1,62 @@ +// These objects are used by cyborgs to get around a lot of the limitations on stacks +// and the weird bugs that crop up when expecting borg module code to behave sanely. +/obj/item/stack/material/cyborg + uses_charge = 1 + charge_costs = list(1000) + gender = NEUTER + matter = null // Don't shove it in the autholathe. + max_health = ITEM_HEALTH_NO_DAMAGE + is_spawnable_type = FALSE + +/obj/item/stack/material/cyborg/Initialize() + . = ..() + if(material) + if(reinf_material) + name = "[reinf_material.solid_name]-reinforced [material.solid_name] synthesiser" + desc = "A device that synthesises [reinf_material.solid_name]-reinforced[material.solid_name]." + else + name = "[material.solid_name] synthesiser" + desc = "A device that synthesises [material.solid_name]." + matter = null + +/obj/item/stack/material/cyborg/plastic + name = "cyborg plastic synthesiser" + icon_state = "sheet" + material = /decl/material/solid/organic/plastic + +/obj/item/stack/material/cyborg/steel + name = "cyborg steel synthesiser" + icon_state = "sheet" + material = /decl/material/solid/metal/steel + +/obj/item/stack/material/cyborg/plasteel + name = "cyborg plasteel synthesiser" + icon_state = "sheet-reinf" + material = /decl/material/solid/metal/plasteel + +/obj/item/stack/material/cyborg/wood + name = "cyborg wood synthesiser" + icon_state = "sheet-wood" + material = /decl/material/solid/organic/wood/oak + +/obj/item/stack/material/cyborg/glass + name = "cyborg glass synthesiser" + icon_state = "sheet" + material = /decl/material/solid/glass + +/obj/item/stack/material/cyborg/fiberglass + name = "cyborg fiberglass synthesiser" + icon_state = "sheet" + material = /decl/material/solid/fiberglass + +/obj/item/stack/material/cyborg/glass/reinforced + name = "cyborg reinforced glass synthesiser" + icon_state = "sheet-reinf" + material = /decl/material/solid/glass + reinf_material = /decl/material/solid/metal/steel + charge_costs = list(500, 1000) + +/obj/item/stack/material/cyborg/aluminium + name = "cyborg aluminium synthesiser" + icon_state = "sheet" + material = /decl/material/solid/metal/aluminium diff --git a/code/modules/materials/material_synth.dm b/code/modules/materials/material_synth.dm deleted file mode 100644 index f755f65f4b14..000000000000 --- a/code/modules/materials/material_synth.dm +++ /dev/null @@ -1,46 +0,0 @@ -// These objects are used by cyborgs to get around a lot of the limitations on stacks -// and the weird bugs that crop up when expecting borg module code to behave sanely. -/obj/item/stack/material/cyborg - uses_charge = 1 - charge_costs = list(1000) - gender = NEUTER - matter = null // Don't shove it in the autholathe. - -/obj/item/stack/material/cyborg/Initialize() - . = ..() - if(material) - name = "[material.solid_name] synthesiser" - desc = "A device that synthesises [material.solid_name]." - matter = null - -/obj/item/stack/material/cyborg/plastic - icon_state = "sheet" - material = /decl/material/solid/plastic - -/obj/item/stack/material/cyborg/steel - icon_state = "sheet" - material = /decl/material/solid/metal/steel - -/obj/item/stack/material/cyborg/plasteel - icon_state = "sheet-reinf" - material = /decl/material/solid/metal/plasteel - -/obj/item/stack/material/cyborg/wood - icon_state = "sheet-wood" - material = /decl/material/solid/wood - -/obj/item/stack/material/cyborg/glass - icon_state = "sheet" - material = /decl/material/solid/glass - material_flags = USE_MATERIAL_COLOR|USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME - -/obj/item/stack/material/cyborg/glass/reinforced - icon_state = "sheet-reinf" - material = /decl/material/solid/glass - reinf_material = /decl/material/solid/metal/steel - charge_costs = list(500, 1000) - -/obj/item/stack/material/cyborg/aluminium - icon_state = "sheet" - material = /decl/material/solid/metal/aluminium - material_flags = USE_MATERIAL_COLOR|USE_MATERIAL_SINGULAR_NAME|USE_MATERIAL_PLURAL_NAME diff --git a/code/modules/materials/materials_ore.dm b/code/modules/materials/materials_ore.dm deleted file mode 100644 index 8377592cd36b..000000000000 --- a/code/modules/materials/materials_ore.dm +++ /dev/null @@ -1,64 +0,0 @@ -/obj/item/ore - name = "ore" - icon_state = "lump" - icon = 'icons/obj/materials/ore.dmi' - randpixel = 8 - w_class = ITEM_SIZE_SMALL - -/obj/item/ore/set_material(var/new_material) - . = ..() - if(istype(material)) - matter = list() - matter[material.type] = SHEET_MATERIAL_AMOUNT - name = material.ore_name - desc = material.ore_desc ? material.ore_desc : "A lump of ore." - color = material.color - icon_state = material.ore_icon_overlay - if(material.ore_desc) - desc = material.ore_desc - if(icon_state == "dust") - slot_flags = SLOT_HOLSTER - -// POCKET SAND! -/obj/item/ore/throw_impact(atom/hit_atom) - ..() - if(icon_state == "dust") - var/mob/living/carbon/human/H = hit_atom - if(istype(H) && H.check_has_eyes() && prob(85)) - H << "Some of \the [src] gets in your eyes!" - H.eye_blind += 5 - H.eye_blurry += 10 - QDEL_IN(src, 1) - -/obj/item/ore/explosion_act(var/severity) - SHOULD_CALL_PARENT(FALSE) - if(severity == 1 && prob(25)) - qdel(src) - -// Map definitions. -/obj/item/ore/uranium - material = /decl/material/solid/mineral/pitchblende -/obj/item/ore/iron - material = /decl/material/solid/mineral/hematite -/obj/item/ore/coal - material = /decl/material/solid/mineral/graphite -/obj/item/ore/glass - material = /decl/material/solid/mineral/sand -/obj/item/ore/silver - material = /decl/material/solid/metal/silver -/obj/item/ore/gold - material = /decl/material/solid/metal/gold -/obj/item/ore/diamond - material = /decl/material/solid/gemstone/diamond -/obj/item/ore/osmium - material = /decl/material/solid/metal/platinum -/obj/item/ore/hydrogen - material = /decl/material/solid/metallic_hydrogen -/obj/item/ore/slag - material = /decl/material/solid/slag -/obj/item/ore/phosphorite - material = /decl/material/solid/mineral/phosphorite -/obj/item/ore/aluminium - material = /decl/material/solid/mineral/bauxite -/obj/item/ore/rutile - material = /decl/material/solid/mineral/rutile diff --git a/code/modules/materials/recipes_furniture.dm b/code/modules/materials/recipes_furniture.dm deleted file mode 100644 index 47c0a6a7ec3d..000000000000 --- a/code/modules/materials/recipes_furniture.dm +++ /dev/null @@ -1,319 +0,0 @@ - -/datum/stack_recipe/furniture - one_per_turf = 1 - on_floor = 1 - difficulty = 2 - time = 5 - -/datum/stack_recipe/furniture/chair - title = "chair" - result_type = /obj/structure/bed/chair - time = 10 - var/list/modifiers - -/datum/stack_recipe/furniture/chair/display_name() - return modifiers ? jointext(modifiers + ..(), " ") : ..() - -/datum/stack_recipe/furniture/chair/padded - -#define PADDED_CHAIR(color) /datum/stack_recipe/furniture/chair/padded/##color{\ - result_type = /obj/structure/bed/chair/padded/##color;\ - modifiers = list("padded", #color)\ - } -PADDED_CHAIR(beige) -PADDED_CHAIR(black) -PADDED_CHAIR(brown) -PADDED_CHAIR(lime) -PADDED_CHAIR(teal) -PADDED_CHAIR(red) -PADDED_CHAIR(purple) -PADDED_CHAIR(green) -PADDED_CHAIR(yellow) -#undef PADDED_CHAIR - -/datum/stack_recipe/furniture/chair/office - title = "office chair" - -/datum/stack_recipe/furniture/chair/office/display_name() - return modifiers ? jointext(modifiers + title, " ") : title // Bypass material - -/datum/stack_recipe/furniture/chair/office/light - result_type = /obj/structure/bed/chair/office/light - modifiers = list("light") - -/datum/stack_recipe/furniture/chair/office/dark - result_type = /obj/structure/bed/chair/office/dark - modifiers = list("dark") - -#define COMFY_OFFICE_CHAIR(color) /datum/stack_recipe/furniture/chair/office/comfy/##color{\ - result_type = /obj/structure/bed/chair/office/comfy/##color;\ - modifiers = list(#color, "comfy")\ - } -COMFY_OFFICE_CHAIR(beige) -COMFY_OFFICE_CHAIR(black) -COMFY_OFFICE_CHAIR(brown) -COMFY_OFFICE_CHAIR(lime) -COMFY_OFFICE_CHAIR(teal) -COMFY_OFFICE_CHAIR(red) -COMFY_OFFICE_CHAIR(purple) -COMFY_OFFICE_CHAIR(green) -COMFY_OFFICE_CHAIR(yellow) -#undef COMFY_OFFICE_CHAIR - -/datum/stack_recipe/furniture/chair/comfy - title = "comfy chair" - -#define COMFY_CHAIR(color) /datum/stack_recipe/furniture/chair/comfy/##color{\ - result_type = /obj/structure/bed/chair/comfy/##color;\ - modifiers = list(#color)\ - } -COMFY_CHAIR(beige) -COMFY_CHAIR(black) -COMFY_CHAIR(brown) -COMFY_CHAIR(lime) -COMFY_CHAIR(teal) -COMFY_CHAIR(red) -COMFY_CHAIR(purple) -COMFY_CHAIR(green) -COMFY_CHAIR(yellow) -#undef COMFY_CHAIR - -/datum/stack_recipe/furniture/chair/arm - title = "armchair" - -#define ARMCHAIR(color) /datum/stack_recipe/furniture/chair/arm/##color{\ - result_type = /obj/structure/bed/chair/armchair/##color;\ - modifiers = list(#color)\ - } -ARMCHAIR(beige) -ARMCHAIR(black) -ARMCHAIR(brown) -ARMCHAIR(lime) -ARMCHAIR(teal) -ARMCHAIR(red) -ARMCHAIR(purple) -ARMCHAIR(green) -ARMCHAIR(yellow) -#undef ARMCHAIR - -/datum/stack_recipe/furniture/chair/wood - -/datum/stack_recipe/furniture/chair/wood/normal - result_type = /obj/structure/bed/chair/wood - -/datum/stack_recipe/furniture/chair/wood/fancy - result_type = /obj/structure/bed/chair/wood/wings - modifiers = list("fancy") - -/datum/stack_recipe/furniture/door - title = "door" - result_type = /obj/structure/door - time = 50 - -/datum/stack_recipe/furniture/barricade - title = "barricade" - result_type = /obj/structure/barricade - time = 50 - -/datum/stack_recipe/furniture/stool - title = "stool" - result_type = /obj/item/stool - -/datum/stack_recipe/furniture/bar_stool - title = "bar stool" - result_type = /obj/item/stool/bar - -/datum/stack_recipe/furniture/bed - title = "bed" - result_type = /obj/structure/bed - -/datum/stack_recipe/furniture/pew - title = "pew, right" - result_type = /obj/structure/bed/chair/pew - -/datum/stack_recipe/furniture/pew_left - title = "pew, left" - result_type = /obj/structure/bed/chair/pew/left - -/datum/stack_recipe/furniture/table_frame - title = "table frame" - result_type = /obj/structure/table - time = 10 - -/datum/stack_recipe/furniture/rack - title = "rack" - result_type = /obj/structure/table/rack - -/datum/stack_recipe/furniture/closet - title = "closet" - result_type = /obj/structure/closet - time = 15 - -/datum/stack_recipe/furniture/canister - title = "canister" - result_type = /obj/machinery/portable_atmospherics/canister - req_amount = 20 - time = 10 - -/datum/stack_recipe/furniture/tank - title = "pressure tank" - result_type = /obj/item/pipe/tank - time = 20 - -/datum/stack_recipe/furniture/computerframe - title = "computer frame" - result_type = /obj/machinery/constructable_frame/computerframe - req_amount = 5 - time = 25 - -/datum/stack_recipe/furniture/ladder - title = "ladder" - result_type = /obj/structure/ladder - time = 50 - one_per_turf = TRUE - on_floor = FALSE - -/datum/stack_recipe/furniture/girder - title = "wall support" - result_type = /obj/structure/girder - time = 50 - -/datum/stack_recipe/furniture/wall_frame - title = "low wall frame" - result_type = /obj/structure/wall_frame - time = 50 - -/datum/stack_recipe/furniture/machine - title = "machine frame" - result_type = /obj/machinery/constructable_frame/machine_frame - req_amount = 5 - time = 25 - -/datum/stack_recipe/furniture/turret - title = "turret frame" - result_type = /obj/machinery/porta_turret_construct - req_amount = 5 - time = 25 - -/datum/stack_recipe/furniture/door_assembly - time = 50 - -/datum/stack_recipe/furniture/door_assembly/standard - title = "standard airlock assembly" - result_type = /obj/structure/door_assembly - -/datum/stack_recipe/furniture/door_assembly/airtight - title = "airtight hatch assembly" - result_type = /obj/structure/door_assembly/door_assembly_hatch - -/datum/stack_recipe/furniture/door_assembly/highsec - title = "high security airlock assembly" - result_type = /obj/structure/door_assembly/door_assembly_highsecurity - -/datum/stack_recipe/furniture/door_assembly/ext - title = "exterior airlock assembly" - result_type = /obj/structure/door_assembly/door_assembly_ext - -/datum/stack_recipe/furniture/door_assembly/firedoor - title = "emergency shutter" - result_type = /obj/structure/firedoor_assembly - -/datum/stack_recipe/furniture/door_assembly/multi_tile - title = "multi-tile airlock assembly" - result_type = /obj/structure/door_assembly/multi_tile - -/datum/stack_recipe/furniture/door_assembly/blast - title = "blast door assembly" - result_type = /obj/structure/door_assembly/blast - -/datum/stack_recipe/furniture/door_assembly/shutter - title = "shutter assembly" - result_type = /obj/structure/door_assembly/blast/shutter - -/datum/stack_recipe/furniture/door_assembly/morgue - title = "morgue door assembly" - result_type = /obj/structure/door_assembly/blast/morgue - -/datum/stack_recipe/furniture/crate - title = "crate" - result_type = /obj/structure/closet/crate - time = 50 - -/datum/stack_recipe/furniture/crate/plastic - result_type = /obj/structure/closet/crate/plastic - -/datum/stack_recipe/furniture/flaps - title = "flaps" - result_type = /obj/structure/plasticflaps - time = 50 - -/datum/stack_recipe/furniture/coffin - title = "coffin" - result_type = /obj/structure/closet/coffin - time = 15 - -/datum/stack_recipe/furniture/coffin/wooden - title = "coffin" - result_type = /obj/structure/closet/coffin/wooden - time = 15 - -/datum/stack_recipe/furniture/bookcase - title = "book shelf" - result_type = /obj/structure/bookcase - time = 15 - -/datum/stack_recipe/furniture/planting_bed - title = "planting bed" - result_type = /obj/machinery/portable_atmospherics/hydroponics/soil - req_amount = 3 - time = 10 - -/datum/stack_recipe/furniture/fullwindow - title = "full-tile window" - result_type = /obj/structure/window - time = 15 - one_per_turf = 0 - -/datum/stack_recipe/furniture/fullwindow/can_make(mob/user) - . = ..() - if(.) - for(var/obj/structure/window/check_window in user.loc) - if(check_window.is_fulltile()) - to_chat(user, "There is already a fll-tile window here!") - return FALSE - -/datum/stack_recipe/furniture/fullwindow/spawn_result(mob/user, location, amount) - return new result_type(user?.loc, SOUTHWEST, 1, use_material, use_reinf_material) - -/datum/stack_recipe/furniture/borderwindow - title = "border window" - result_type = /obj/structure/window - time = 5 - one_per_turf = 0 - -/datum/stack_recipe/furniture/borderwindow/can_make(mob/user) - . = ..() - if(.) - for(var/obj/structure/window/check_window in user.loc) - if(check_window.dir == user.dir) - to_chat(user, "There is already a window facing that direction here!") - return FALSE - -/datum/stack_recipe/furniture/borderwindow/spawn_result(mob/user, location, amount) - return new result_type(user?.loc, user?.dir, 1, use_material, use_reinf_material) - -/datum/stack_recipe/furniture/windoor - title = "windoor assembly" - result_type = /obj/structure/windoor_assembly - time = 20 - one_per_turf = 1 - -/datum/stack_recipe/furniture/windoor/can_make(mob/user) - . = ..() - if(.) - if(locate(/obj/machinery/door/window) in user.loc) - to_chat(user, "There is already a windoor here!") - return FALSE - -/datum/stack_recipe/furniture/windoor/spawn_result(mob/user, location, amount) - return new result_type(user?.loc, use_material, use_reinf_material) diff --git a/code/modules/materials/recipes_items.dm b/code/modules/materials/recipes_items.dm deleted file mode 100644 index 4473d17e719e..000000000000 --- a/code/modules/materials/recipes_items.dm +++ /dev/null @@ -1,281 +0,0 @@ -//Recipes that produce items which aren't stacks or storage. - -/datum/stack_recipe/baseball_bat - title = "baseball bat" - result_type = /obj/item/twohanded/baseballbat - time = 20 - difficulty = 2 - -/datum/stack_recipe/bell - title = "bell" - result_type = /obj/item/bell - time = 20 - -/datum/stack_recipe/ashtray - title = "ashtray" - result_type = /obj/item/ashtray - one_per_turf = 1 - -/datum/stack_recipe/improvised_armour - title = "improvised armour" - result_type = /obj/item/clothing/suit/armor/crafted - one_per_turf = 1 - -/datum/stack_recipe/coin - title = "coin" - result_type = /obj/item/coin - one_per_turf = 1 - -/datum/stack_recipe/ring - title = "ring" - result_type = /obj/item/clothing/ring/material - -/datum/stack_recipe/lock - title = "lock" - result_type = /obj/item/lock_construct - time = 20 - -/datum/stack_recipe/fork - title = "fork" - result_type = /obj/item/kitchen/utensil/fork/plastic - -/datum/stack_recipe/knife - title = "table knife" - result_type = /obj/item/knife/table - difficulty = 2 - -/datum/stack_recipe/spoon - title = "spoon" - result_type = /obj/item/kitchen/utensil/spoon/plastic - -/datum/stack_recipe/blade - title = "knife" - result_type = /obj/item/butterflyblade - time = 20 - difficulty = 1 - -/datum/stack_recipe/grip - title = "knife grip" - result_type = /obj/item/butterflyhandle - time = 20 - on_floor = 1 - difficulty = 1 - -/datum/stack_recipe/key - title = "key" - result_type = /obj/item/key - time = 10 - -/datum/stack_recipe/cannon - title = "cannon frame" - result_type = /obj/item/cannonframe - time = 15 - difficulty = 3 - -/datum/stack_recipe/grenade - title = "grenade casing" - result_type = /obj/item/grenade/chem_grenade - difficulty = 3 - -/datum/stack_recipe/light - title = "light fixture frame" - result_type = /obj/item/frame/light - difficulty = 2 - -/datum/stack_recipe/light_small - title = "small light fixture frame" - result_type = /obj/item/frame/light/small - difficulty = 2 - -/datum/stack_recipe/light_switch - title = "light switch frame" - result_type = /obj/item/frame/button/light_switch - difficulty = 2 - -/datum/stack_recipe/light_switch/windowtint - title = "window tint switch frame" - result_type = /obj/item/frame/button/light_switch/windowtint - difficulty = 2 - -/datum/stack_recipe/apc - title = "APC frame" - result_type = /obj/item/frame/apc - difficulty = 2 - -/datum/stack_recipe/air_alarm - title = "air alarm frame" - result_type = /obj/item/frame/air_alarm - difficulty = 2 - -/datum/stack_recipe/fire_alarm - title = "fire alarm frame" - result_type = /obj/item/frame/fire_alarm - difficulty = 2 - -/datum/stack_recipe/computer/telescreen - title = "modular telescreen frame" - result_type = /obj/item/modular_computer/telescreen - difficulty = 2 - -/datum/stack_recipe/computer/laptop - title = "modular laptop frame" - result_type = /obj/item/modular_computer/laptop - difficulty = 2 - -/datum/stack_recipe/computer/tablet - title = "modular tablet frame" - result_type = /obj/item/modular_computer/tablet - difficulty = 2 - -/datum/stack_recipe/hazard_cone - title = "hazard cone" - result_type = /obj/item/caution/cone - on_floor = 1 - -/datum/stack_recipe/ivbag - title = "IV bag" - result_type = /obj/item/chems/ivbag - difficulty = 2 - -/datum/stack_recipe/cartridge - title = "reagent dispenser cartridge" - var/modifier = "" - difficulty = 2 - -/datum/stack_recipe/cartridge/display_name() - return "[title] ([modifier])" - -/datum/stack_recipe/cartridge/small - result_type = /obj/item/chems/chem_disp_cartridge/small - modifier = "small" - -/datum/stack_recipe/cartridge/medium - result_type = /obj/item/chems/chem_disp_cartridge/medium - modifier = "medium" - -/datum/stack_recipe/cartridge/large - result_type = /obj/item/chems/chem_disp_cartridge - modifier = "large" - -/datum/stack_recipe/sandals - title = "sandals" - result_type = /obj/item/clothing/shoes/sandal - -/datum/stack_recipe/zipgunframe - title = "zip gun frame" - result_type = /obj/item/zipgunframe - difficulty = 3 - -/datum/stack_recipe/coilgun - title = "coilgun stock" - result_type = /obj/item/coilgun_assembly - difficulty = 3 - -/datum/stack_recipe/stick - title = "stick" - result_type = /obj/item/stick - difficulty = 0 - -/datum/stack_recipe/crossbowframe - title = "crossbow frame" - result_type = /obj/item/crossbowframe - time = 25 - difficulty = 3 - -/datum/stack_recipe/beehive_assembly - title = "beehive assembly" - result_type = /obj/item/beehive_assembly - -/datum/stack_recipe/beehive_frame - title = "beehive frame" - result_type = /obj/item/honey_frame - -/datum/stack_recipe/cardborg_suit - title = "cardborg suit" - result_type = /obj/item/clothing/suit/cardborg - difficulty = 0 - -/datum/stack_recipe/cardborg_helmet - title = "cardborg helmet" - result_type = /obj/item/clothing/head/cardborg - difficulty = 0 - -/datum/stack_recipe/candle - title = "candle" - result_type = /obj/item/flame/candle - difficulty = 0 - -/datum/stack_recipe/clipboard - title = "clipboard" - result_type = /obj/item/clipboard - -/datum/stack_recipe/urn - title = "urn" - result_type = /obj/item/urn - -/datum/stack_recipe/drill_head - title = "drill head" - result_type = /obj/item/drill_head - difficulty = 0 - -/datum/stack_recipe/cross - title = "cross" - result_type = /obj/item/cross - on_floor = 1 - -/datum/stack_recipe/wooden_prosthetic - title = "left arm" - result_type = /obj/item/organ/external/arm/wooden - difficulty = 0 - -/datum/stack_recipe/wooden_prosthetic/right_arm - title = "right arm" - result_type = /obj/item/organ/external/arm/right/wooden - -/datum/stack_recipe/wooden_prosthetic/left_leg - title = "left leg" - result_type = /obj/item/organ/external/leg/wooden - -/datum/stack_recipe/wooden_prosthetic/right_leg - title = "right leg" - result_type = /obj/item/organ/external/leg/right/wooden - -/datum/stack_recipe/wooden_prosthetic/left_hand - title = "left hand" - result_type = /obj/item/organ/external/hand/wooden - -/datum/stack_recipe/wooden_prosthetic/right_hand - title = "right hand" - result_type = /obj/item/organ/external/hand/right/wooden - -/datum/stack_recipe/wooden_prosthetic/left_foot - title = "left foot" - result_type = /obj/item/organ/external/foot/wooden - -/datum/stack_recipe/wooden_prosthetic/right_foot - title = "right foot" - result_type = /obj/item/organ/external/foot/right/wooden - -/datum/stack_recipe/cloak - title = "cloak" - result_type = /obj/item/clothing/accessory/cloak/hide - -/datum/stack_recipe/shoes - title = "shoes" - result_type = /obj/item/clothing/shoes/craftable - -/datum/stack_recipe/boots - title = "boots" - result_type = /obj/item/clothing/shoes/craftable/boots - -/datum/stack_recipe/armguards - title = "arm guards" - result_type = /obj/item/clothing/accessory/armguards/craftable - -/datum/stack_recipe/legguards - title = "leg guards" - result_type = /obj/item/clothing/accessory/legguards/craftable - -/datum/stack_recipe/gauntlets - title = "gauntlets" - result_type = /obj/item/clothing/gloves/thick/craftable diff --git a/code/modules/materials/recipes_stacks.dm b/code/modules/materials/recipes_stacks.dm deleted file mode 100644 index 696522c2e06d..000000000000 --- a/code/modules/materials/recipes_stacks.dm +++ /dev/null @@ -1,94 +0,0 @@ -/datum/stack_recipe/rod - title = "rod" - result_type = /obj/item/stack/material/rods - res_amount = 2 - max_res_amount = 60 - time = 5 - difficulty = 1 - -/datum/stack_recipe/rod/spawn_result(user, location, amount) - var/obj/item/stack/S = new result_type(location, amount, use_material) - if(user) - S.add_to_stacks(user, 1) - return S - -// Tiles -/datum/stack_recipe/tile - res_amount = 4 - max_res_amount = 20 - time = 5 - difficulty = 1 - apply_material_name = FALSE - -/datum/stack_recipe/tile/spawn_result(user, location, amount) - var/obj/item/stack/S = ..() - if(istype(S)) - S.amount = amount - if(user) - S.add_to_stacks(user, 1) - return S - -/datum/stack_recipe/tile/metal/floor - title = "regular floor tile" - result_type = /obj/item/stack/tile/floor - -/datum/stack_recipe/tile/metal/mono - title = "mono floor tile" - result_type = /obj/item/stack/tile/mono - -/datum/stack_recipe/tile/metal/mono_dark - title = "dark mono floor tile" - result_type = /obj/item/stack/tile/mono/dark - -/datum/stack_recipe/tile/metal/grid - title = "grid floor tile" - result_type = /obj/item/stack/tile/grid - -/datum/stack_recipe/tile/metal/ridged - title = "ridged floor tile" - result_type = /obj/item/stack/tile/ridge - -/datum/stack_recipe/tile/metal/tech_grey - title = "grey techfloor tile" - result_type = /obj/item/stack/tile/techgrey - -/datum/stack_recipe/tile/metal/tech_grid - title = "grid techfloor tile" - result_type = /obj/item/stack/tile/techgrid - -/datum/stack_recipe/tile/metal/tech_maint - title = "dark techfloor tile" - result_type = /obj/item/stack/tile/techmaint - -/datum/stack_recipe/tile/metal/dark - title = "dark floor tile" - result_type = /obj/item/stack/tile/floor_dark - -/datum/stack_recipe/tile/light/floor - title = "white floor tile" - result_type = /obj/item/stack/tile/floor_white - -/datum/stack_recipe/tile/light/freezer - title = "freezer floor tile" - result_type = /obj/item/stack/tile/floor_freezer - -/datum/stack_recipe/tile/wood - title = "wood floor tile" - result_type = /obj/item/stack/tile/wood - -/datum/stack_recipe/tile/mahogany - title = "mahogany floor tile" - result_type = /obj/item/stack/tile/mahogany - -/datum/stack_recipe/tile/maple - title = "maple floor tile" - result_type = /obj/item/stack/tile/maple - -/datum/stack_recipe/tile/ebony - title = "ebony floor tile" - difficulty = 3 - result_type = /obj/item/stack/tile/ebony - -/datum/stack_recipe/tile/walnut - title = "walnut floor tile" - result_type = /obj/item/stack/tile/walnut \ No newline at end of file diff --git a/code/modules/materials/recipes_storage.dm b/code/modules/materials/recipes_storage.dm deleted file mode 100644 index f1e5bbccdf94..000000000000 --- a/code/modules/materials/recipes_storage.dm +++ /dev/null @@ -1,57 +0,0 @@ - -/datum/stack_recipe/box/box - title = "box" - result_type = /obj/item/storage/box - -/datum/stack_recipe/box/large - title = "large box" - result_type = /obj/item/storage/box/large - -/datum/stack_recipe/box/donut - title = "donut box" - result_type = /obj/item/storage/box/donut/empty - -/datum/stack_recipe/box/egg - title = "egg box" - result_type = /obj/item/storage/fancy/egg_box/empty - -/datum/stack_recipe/box/light_tubes - title = "light tubes box" - result_type = /obj/item/storage/box/lights/tubes/empty - -/datum/stack_recipe/box/light_bulbs - title = "light bulbs box" - result_type = /obj/item/storage/box/lights/bulbs/empty - -/datum/stack_recipe/box/mouse_traps - title = "mouse traps box" - result_type = /obj/item/storage/box/mousetraps/empty - -/datum/stack_recipe/box/pizza - title = "pizza box" - result_type = /obj/item/pizzabox - -/datum/stack_recipe/bag - title = "bag" - result_type = /obj/item/storage/bag/plasticbag - on_floor = 1 - -/datum/stack_recipe/folder - title = "folder" - result_type = /obj/item/folder - var/modifier = "grey" - -/datum/stack_recipe/folder/display_name() - return "[modifier] [title]" - -/datum/stack_recipe/folder/normal - -#define COLORED_FOLDER(color) /datum/stack_recipe/folder/##color{\ - result_type = /obj/item/folder/##color;\ - modifier = #color\ - } -COLORED_FOLDER(blue) -COLORED_FOLDER(red) -COLORED_FOLDER(cyan) -COLORED_FOLDER(yellow) -#undef COLORED_FOLDER \ No newline at end of file diff --git a/code/modules/materials/recipes_structures.dm b/code/modules/materials/recipes_structures.dm deleted file mode 100644 index 2c10af86bcbe..000000000000 --- a/code/modules/materials/recipes_structures.dm +++ /dev/null @@ -1,28 +0,0 @@ -//Furniture is in a separate file. -/datum/stack_recipe/butcher_hook - title = "meat hook" - result_type = /obj/structure/kitchenspike - time = 40 - one_per_turf = 1 - difficulty = 1 - -/datum/stack_recipe/ai_core - title = "AI core" - result_type = /obj/structure/aicore - time = 50 - one_per_turf = 1 - difficulty = 2 - -/datum/stack_recipe/railing - title = "railing" - result_type = /obj/structure/railing - time = 40 - on_floor = 1 - difficulty = 2 - -/datum/stack_recipe/noticeboard - title = "noticeboard" - result_type = /obj/structure/noticeboard - time = 50 - on_floor = 1 - difficulty = 2 diff --git a/code/modules/materials/stack_types/material_stack_aerogel.dm b/code/modules/materials/stack_types/material_stack_aerogel.dm new file mode 100644 index 000000000000..11ebc5ed9ed9 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_aerogel.dm @@ -0,0 +1,13 @@ +/obj/item/stack/material/aerogel + name = "aerogel" + singular_name = "gel block" + plural_name = "gel blocks" + icon_state = "puck" + plural_icon_state = "puck-mult" + max_icon_state = "puck-max" + stack_merge_type = /obj/item/stack/material/aerogel + crafting_stack_type = /obj/item/stack/material/aerogel + +// Aerogel melting point is below 0 as it is a physical container for gas; hack around that here. +/obj/item/stack/material/aerogel/ProcessAtomTemperature() + return PROCESS_KILL diff --git a/code/modules/materials/stack_types/material_stack_animal.dm b/code/modules/materials/stack_types/material_stack_animal.dm new file mode 100644 index 000000000000..eaa7a353bb21 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_animal.dm @@ -0,0 +1,94 @@ +/obj/item/stack/material/skin + name = "skin" + icon_state = "skin" + plural_icon_state = "skin-mult" + max_icon_state = "skin-max" + singular_name = "length" + plural_name = "lengths" + stack_merge_type = /obj/item/stack/material/skin + crafting_stack_type = /obj/item/stack/material/skin + var/_cleaned = FALSE + var/work_skill = SKILL_CONSTRUCTION + +/obj/item/stack/material/skin/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(user && distance <= 1 && user.skill_check(work_skill, SKILL_BASIC) && material?.tans_to) + if(_cleaned && drying_wetness) + . += SPAN_NOTICE("\The [src] is ready for tanning on a drying rack or in a drying oven.") + else if(!_cleaned) + . += SPAN_NOTICE("\The [src] must be scraped clean with a knife or other sharp object before it can be tanned.") + else if(!drying_wetness) + . += SPAN_NOTICE("\The [src] must be soaked in water before it can be tanned.") + +/obj/item/stack/material/skin/proc/set_cleaned() + if(_cleaned) + return + _cleaned = TRUE + name_modifier = "cleaned" + +/obj/item/stack/material/skin/attackby(obj/item/used_item, mob/user) + if(IS_KNIFE(used_item) && !_cleaned) + var/cleaned_sheets = 0 + while(used_item.do_tool_interaction(TOOL_KNIFE, user, src, 2 SECONDS, "scraping", "scraping", check_skill = work_skill, set_cooldown = TRUE)) + + if(QDELETED(src) || _cleaned || get_amount() <= 0 || QDELETED(user) || (loc != user && !user.Adjacent(src)) || QDELETED(used_item) || user.get_active_held_item() != used_item) + break + + var/sheets = min(5, get_amount()) + var/obj/item/stack/material/skin/product = (get_amount() <= sheets) ? src : split(sheets) + if(product) + product.set_cleaned() + cleaned_sheets += product.get_amount() + product.add_to_stacks(user, TRUE) + + if(QDELETED(src) || get_amount() <= 0 || QDELETED(user) || _cleaned) + break + + if(cleaned_sheets > 0) + to_chat(user, SPAN_NOTICE("You finish scraping, having cleaned [cleaned_sheets] [cleaned_sheets == 1 ? singular_name : plural_name].")) + return TRUE + + return ..() + +/obj/item/stack/material/skin/is_dryable() + return _cleaned && ..() + +/obj/item/stack/material/skin/can_merge_stacks(var/obj/item/stack/other) + . = ..() + if(.) + if(!istype(other, /obj/item/stack/material/skin)) + return FALSE + var/obj/item/stack/material/skin/skin = other + return skin._cleaned == _cleaned + +/obj/item/stack/material/skin/split(var/tamount, var/force=FALSE) + var/is_cleaned = _cleaned + var/obj/item/stack/material/skin/skin = ..() + if(istype(skin) && is_cleaned) + skin.set_cleaned() + return skin + +/obj/item/stack/material/skin/pelt + name = "pelts" + singular_name = "pelt" + plural_name = "pelts" + stack_merge_type = /obj/item/stack/material/skin/pelt + +/obj/item/stack/material/skin/feathers + name = "feathers" + singular_name = "feather" + plural_name = "feathers" + stack_merge_type = /obj/item/stack/material/skin/feathers + paint_verb = "dyed" + +/obj/item/stack/material/bone + name = "bones" + icon_state = "bone" + plural_icon_state = "bone-mult" + max_icon_state = "bone-max" + singular_name = "length" + plural_name = "lengths" + stack_merge_type = /obj/item/stack/material/bone + crafting_stack_type = /obj/item/stack/material/bone + craft_verb = "carve" + craft_verbing = "carving" diff --git a/code/modules/materials/stack_types/material_stack_bar.dm b/code/modules/materials/stack_types/material_stack_bar.dm new file mode 100644 index 000000000000..b5ca5ef901fa --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_bar.dm @@ -0,0 +1,13 @@ +/obj/item/stack/material/bar + name = "bar" + singular_name = "bar" + plural_name = "bars" + icon_state = "bar" + plural_icon_state = "bar-mult" + max_icon_state = "bar-max" + stack_merge_type = /obj/item/stack/material/bar + crafting_stack_type = /obj/item/stack/material/bar + +/obj/item/stack/material/bar/wax + material = /decl/material/solid/organic/wax + is_spawnable_type = TRUE diff --git a/code/modules/materials/stack_types/material_stack_brick.dm b/code/modules/materials/stack_types/material_stack_brick.dm new file mode 100644 index 000000000000..db6454a53043 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_brick.dm @@ -0,0 +1,16 @@ + +/obj/item/stack/material/brick + name = "bricks" + singular_name = "brick" + plural_name = "bricks" + icon_state = "brick" + plural_icon_state = "brick-mult" + max_icon_state = "brick-max" + stack_merge_type = /obj/item/stack/material/brick + crafting_stack_type = /obj/item/stack/material/brick + can_be_pulverized = TRUE + +// Extra subtype defined for the clay stack recipes to not freak out about null material. +/obj/item/stack/material/brick/clay + material = /decl/material/solid/clay + is_spawnable_type = TRUE diff --git a/code/modules/materials/stack_types/material_stack_cloth.dm b/code/modules/materials/stack_types/material_stack_cloth.dm new file mode 100644 index 000000000000..2bc3692b6a7d --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_cloth.dm @@ -0,0 +1,65 @@ +/obj/item/stack/material/bolt + name = "bolts" + icon_state = "sheet-cloth" + singular_name = "bolt" + plural_name = "bolts" + w_class = ITEM_SIZE_NORMAL + stack_merge_type = /obj/item/stack/material/bolt + crafting_stack_type = /obj/item/stack/material/bolt + craft_verb = "tailor" + craft_verbing = "tailoring" + +// Subtypes for dyed cloth. +#define SET_COLOR(COLOR) paint_color = COLOR; color = COLOR +/obj/item/stack/material/bolt/yellow + SET_COLOR("#ffbf00") +/obj/item/stack/material/bolt/teal + SET_COLOR("#00e1ff") +/obj/item/stack/material/bolt/black + SET_COLOR("#505050") +/obj/item/stack/material/bolt/green + SET_COLOR("#b7f27d") +/obj/item/stack/material/bolt/purple + SET_COLOR("#9933ff") +/obj/item/stack/material/bolt/blue + SET_COLOR("#46698c") +/obj/item/stack/material/bolt/beige + SET_COLOR("#ceb689") +/obj/item/stack/material/bolt/lime + SET_COLOR("#62e36c") +/obj/item/stack/material/bolt/red + SET_COLOR("#9d2300") + +/obj/item/stack/material/thread + name = "thread spools" + singular_name = "thread spool" + plural_name = "thread spools" + stack_merge_type = /obj/item/stack/material/thread + crafting_stack_type = /obj/item/stack/material/thread + craft_verb = "weave" + craft_verbing = "weaving" + w_class = ITEM_SIZE_TINY + matter_multiplier = 0.125 // 250 matter units = 1 thread, each small offal is 4 thread, so a large offal is 16 thread. + icon_state = "thread" + plural_icon_state = "thread-mult" + max_icon_state = "thread-max" + +/obj/item/stack/material/thread/yellow + SET_COLOR("#ffbf00") +/obj/item/stack/material/thread/teal + SET_COLOR("#00e1ff") +/obj/item/stack/material/thread/black + SET_COLOR("#505050") +/obj/item/stack/material/thread/green + SET_COLOR("#b7f27d") +/obj/item/stack/material/thread/purple + SET_COLOR("#9933ff") +/obj/item/stack/material/thread/blue + SET_COLOR("#46698c") +/obj/item/stack/material/thread/beige + SET_COLOR("#ceb689") +/obj/item/stack/material/thread/lime + SET_COLOR("#62e36c") +/obj/item/stack/material/thread/red + SET_COLOR("#9d2300") +#undef SET_COLOR \ No newline at end of file diff --git a/code/modules/materials/stack_types/material_stack_logs.dm b/code/modules/materials/stack_types/material_stack_logs.dm new file mode 100644 index 000000000000..8b28328d1952 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_logs.dm @@ -0,0 +1,31 @@ +/obj/item/stack/material/plank + name = "planks" + singular_name = "plank" + plural_name = "planks" + icon_state = "sheet-wood" + plural_icon_state = "sheet-wood-mult" + max_icon_state = "sheet-wood-max" + pickup_sound = 'sound/foley/wooden_drop.ogg' + drop_sound = 'sound/foley/wooden_drop.ogg' + stack_merge_type = /obj/item/stack/material/plank + crafting_stack_type = /obj/item/stack/material/plank + +/obj/item/stack/material/log + name = "logs" + singular_name = "log" + plural_name = "logs" + icon_state = "log" + plural_icon_state = "log-mult" + max_icon_state = "log-max" + stack_merge_type = /obj/item/stack/material/log + crafting_stack_type = /obj/item/stack/material/log + craft_verb = "whittle" + craft_verbing = "whittling" + matter_multiplier = 3 + +/obj/item/stack/material/log/get_stack_conversion_dictionary() + var/static/list/converts_into = list( + TOOL_HATCHET = /obj/item/stack/material/plank, + TOOL_SAW = /obj/item/stack/material/plank + ) + return converts_into diff --git a/code/modules/materials/stack_types/material_stack_lump.dm b/code/modules/materials/stack_types/material_stack_lump.dm new file mode 100644 index 000000000000..3379a99caae6 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_lump.dm @@ -0,0 +1,56 @@ +/obj/item/stack/material/lump + name = "lumps" + singular_name = "lump" + plural_name = "lumps" + icon_state = "lump" + plural_icon_state = "lump-mult" + max_icon_state = "lump-max" + stack_merge_type = /obj/item/stack/material/lump + crafting_stack_type = /obj/item/stack/material/lump + craft_verb = "sculpt" + craft_verbing = "sculpting" + can_be_pulverized = TRUE + matter_multiplier = 1.5 + +// Override as squashing items produces this item type. +/obj/item/stack/material/lump/squash_item(skip_qdel = FALSE) + return + +/obj/item/stack/material/lump/get_stack_conversion_dictionary() + var/static/list/converts_into = list( + TOOL_HAMMER = /obj/item/stack/material/brick + ) + return converts_into + +/obj/item/stack/material/lump/clay + material = /decl/material/solid/clay + is_spawnable_type = TRUE + +/obj/item/stack/material/lump/large + base_state = "lump_large" + icon_state = "lump_large" + plural_icon_state = "lump_large-mult" + max_icon_state = "lump_large-max" + stack_merge_type = /obj/item/stack/material/lump/large + crafting_stack_type = /obj/item/stack/material/lump/large + matter_multiplier = 3 + +/obj/item/stack/material/lump/large/marble + material = /decl/material/solid/stone/marble + +/obj/item/stack/material/lump/large/marble/five + amount = 5 + +/obj/item/stack/material/lump/large/clay + material = /decl/material/solid/clay + is_spawnable_type = TRUE + +/obj/item/stack/material/lump/large/soil + material = /decl/material/solid/soil + is_spawnable_type = TRUE + +/obj/item/stack/material/lump/large/marble + material = /decl/material/solid/stone/marble + is_spawnable_type = TRUE +/obj/item/stack/material/lump/large/marble/five + amount = 5 diff --git a/code/modules/materials/stack_types/material_stack_misc.dm b/code/modules/materials/stack_types/material_stack_misc.dm new file mode 100644 index 000000000000..64017b9fdd6e --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_misc.dm @@ -0,0 +1,166 @@ +/obj/item/stack/material/ingot + name = "ingots" + singular_name = "ingot" + plural_name = "ingots" + icon_state = "ingot" + plural_icon_state = "ingot-mult" + max_icon_state = "ingot-max" + stack_merge_type = /obj/item/stack/material/ingot + crafting_stack_type = /obj/item/stack/material/ingot + can_be_pulverized = TRUE + +/obj/item/stack/material/sheet + name = "sheets" + icon_state = "sheet" + plural_icon_state = "sheet-mult" + max_icon_state = "sheet-max" + stack_merge_type = /obj/item/stack/material/sheet + crafting_stack_type = /obj/item/stack/material/sheet + +/obj/item/stack/material/panel + name = "panels" + icon_state = "sheet-plastic" + plural_icon_state = "sheet-plastic-mult" + max_icon_state = "sheet-plastic-max" + singular_name = "panel" + plural_name = "panels" + stack_merge_type = /obj/item/stack/material/panel + crafting_stack_type = /obj/item/stack/material/panel + +/obj/item/stack/material/pane + name = "panes" + singular_name = "pane" + plural_name = "panes" + icon_state = "sheet-clear" + plural_icon_state = "sheet-clear-mult" + max_icon_state = "sheet-clear-max" + stack_merge_type = /obj/item/stack/material/pane + crafting_stack_type = /obj/item/stack/material/pane + can_be_reinforced = TRUE + +/obj/item/stack/material/pane/update_state_from_amount() + if(reinf_material) + icon_state = "sheet-glass-reinf" + base_state = icon_state + plural_icon_state = "sheet-glass-reinf-mult" + max_icon_state = "sheet-glass-reinf-max" + else + icon_state = "sheet-clear" + base_state = icon_state + plural_icon_state = "sheet-clear-mult" + max_icon_state = "sheet-clear-max" + ..() + +/obj/item/stack/material/cardstock + icon_state = "sheet-card" + plural_icon_state = "sheet-card-mult" + max_icon_state = "sheet-card-max" + stack_merge_type = /obj/item/stack/material/cardstock + crafting_stack_type = /obj/item/stack/material/cardstock + craft_verb = "fold" + craft_verbing = "folding" + +/obj/item/stack/material/gemstone + name = "gems" + singular_name = "gem" + plural_name = "gems" + icon_state = "diamond" + plural_icon_state = "diamond-mult" + max_icon_state = "diamond-max" + stack_merge_type = /obj/item/stack/material/gemstone + crafting_stack_type = /obj/item/stack/material/gemstone + can_be_pulverized = TRUE + +/obj/item/stack/material/puck + name = "pucks" + singular_name = "puck" + plural_name = "pucks" + icon_state = "puck" + plural_icon_state = "puck-mult" + max_icon_state = "puck-max" + stack_merge_type = /obj/item/stack/material/puck + crafting_stack_type = /obj/item/stack/material/puck + can_be_pulverized = TRUE + +/obj/item/stack/material/crystal + name = "crystal" + singular_name = "crystal" + plural_name = "crystals" + icon_state = "sheet-phoron" + plural_icon_state = "sheet-phoron-mult" + max_icon_state = "sheet-phoron-max" + stack_merge_type = /obj/item/stack/material/crystal + can_be_pulverized = TRUE + +/obj/item/stack/material/segment + name = "segments" + singular_name = "segment" + plural_name = "segments" + icon_state = "sheet-mythril" + stack_merge_type = /obj/item/stack/material/segment + crafting_stack_type = /obj/item/stack/material/segment + +/obj/item/stack/material/sheet/reinforced + icon_state = "sheet-reinf" + item_state = "sheet-metal" + plural_icon_state = "sheet-reinf-mult" + max_icon_state = "sheet-reinf-max" + stack_merge_type = /obj/item/stack/material/sheet/reinforced + +/obj/item/stack/material/sheet/shiny + icon_state = "sheet-sheen" + item_state = "sheet-shiny" + plural_icon_state = "sheet-sheen-mult" + max_icon_state = "sheet-sheen-max" + stack_merge_type = /obj/item/stack/material/sheet/shiny + +/obj/item/stack/material/cubes + name = "cube" + desc = "Some featureless cubes." + singular_name = "cube" + plural_name = "cubes" + icon_state = "cube" + plural_icon_state = "cube-mult" + max_icon_state = "cube-max" + max_amount = 100 + attack_verb = "cubed" + stack_merge_type = /obj/item/stack/material/cubes + crafting_stack_type = /obj/item/stack/material // cubes can be used for any crafting + can_be_pulverized = TRUE + +/obj/item/stack/material/slab + name = "slabs" + singular_name = "slab" + plural_name = "slabs" + icon_state = "puck" + plural_icon_state = "puck-mult" + max_icon_state = "puck-max" + stack_merge_type = /obj/item/stack/material/slab + crafting_stack_type = /obj/item/stack/material/slab + can_be_pulverized = TRUE + +/obj/item/stack/material/bundle + name = "bundles" + singular_name = "bundle" + plural_name = "bundles" + icon_state = "bundle" + plural_icon_state = "bundle-mult" + max_icon_state = "bundle-max" + stack_merge_type = /obj/item/stack/material/bundle + crafting_stack_type = /obj/item/stack/material/bundle + craft_verb = "weave" + craft_verbing = "weaving" + +// Hacky fix for grass crafting. +/obj/item/stack/material/bundle/special_crafting_check() + return !dried_type || drying_wetness <= 0 + +/obj/item/stack/material/bundle/grass + material = /decl/material/solid/organic/plantmatter/grass + drying_wetness = 50 + dried_type = /obj/item/stack/material/bundle/grass/dry + +/obj/item/stack/material/bundle/grass/dry + material = /decl/material/solid/organic/plantmatter/grass/dry + drying_wetness = null + dried_type = null diff --git a/code/modules/materials/stack_types/material_stack_nail.dm b/code/modules/materials/stack_types/material_stack_nail.dm new file mode 100644 index 000000000000..fb0efb778825 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_nail.dm @@ -0,0 +1,16 @@ +/obj/item/stack/material/nail + name = "nails" + singular_name = "nail" + plural_name = "nails" + icon_state = "nail" + plural_icon_state = "nail-mult" + max_icon_state = "nail-max" + stack_merge_type = /obj/item/stack/material/nail + crafting_stack_type = /obj/item/stack/material/nail + icon = 'icons/obj/items/stacks/nails.dmi' + is_spawnable_type = TRUE + matter_multiplier = 0.05 // 20 per standard sheet + material = /decl/material/solid/metal/iron + +/obj/item/stack/material/nail/twelve + amount = 12 diff --git a/code/modules/materials/stack_types/material_stack_ore.dm b/code/modules/materials/stack_types/material_stack_ore.dm new file mode 100644 index 000000000000..391166a8bb14 --- /dev/null +++ b/code/modules/materials/stack_types/material_stack_ore.dm @@ -0,0 +1,234 @@ +#define ORE_MAX_AMOUNT 200 +#define ORE_MAX_OVERLAYS 10 + +/obj/item/stack/material/ore + name = "ore pile" + singular_name = "ore" + plural_name = "ores" + icon_state = "lump" + plural_icon_state = null + max_icon_state = null + icon = 'icons/obj/materials/ore.dmi' + w_class = ITEM_SIZE_SMALL + max_amount = ORE_MAX_AMOUNT + material = /decl/material/solid/stone/granite //By default is just a rock + material_health_multiplier = 0.5 + stack_merge_type = /obj/item/stack/material/ore + material_alteration = MAT_FLAG_ALTERATION_COLOR //Name is handled in override + randpixel = 6 + is_spawnable_type = TRUE + crafting_stack_type = /obj/item/stack/material/ore + craft_verb = "knap" + craft_verbing = "knapping" + can_be_pulverized = TRUE + matter_multiplier = 1.5 + + ///Associative list of cache key to the generate icons for the ore piles. We pre-generate a pile of all possible ore icon states, and make them available + var/static/list/cached_ore_icon_states + ///A list of all the existing ore icon states in the ore file + var/static/list/ore_icon_states = icon_states('icons/obj/materials/ore.dmi') + +/obj/item/stack/material/ore/get_stack_conversion_dictionary() + var/static/list/converts_into = list( + TOOL_HAMMER = /obj/item/stack/material/brick + ) + return converts_into + +///Returns a cached ore pile icon state +/obj/item/stack/material/ore/proc/get_cached_ore_pile_overlay(var/state_name, var/stack_icon_index) + if(!cached_ore_icon_states) + cache_ore_pile_icons() + var/nb_icon_states = length(cached_ore_icon_states[state_name]) + if(nb_icon_states <= 0) + CRASH("Ore pile is missing an icon state!") + stack_icon_index = clamp(stack_icon_index, 1, nb_icon_states) + return cached_ore_icon_states[state_name][stack_icon_index] + +///Caches the icon state of the ore piles for each possible icon states. The images are greyscale so their color can be changed by the individual materials. +/obj/item/stack/material/ore/proc/cache_ore_pile_icons() + //#TODO: Replace with pre-made icons. This is more or less a placeholder. + cached_ore_icon_states = list() + for(var/IS in ore_icon_states) + var/list/states = list(null) //First index is null since we're creating overlays + var/image/scrapboard = image(null) + //Generate base image + for(var/i = 2 to ORE_MAX_OVERLAYS) + //Randomize the orientation and position of each ores in the image + var/matrix/M = matrix() + M.Translate(rand(-6, 6), rand(-6, 6)) + M.Turn(pick(-72, -58, -45, -27.-5, 0, 0, 0, 0, 0, 27.5, 45, 58, 72)) + var/image/oreoverlay = image('icons/obj/materials/ore.dmi', IS) + oreoverlay.transform = M + scrapboard.overlays += oreoverlay + + //Generate all indices from generated overlays + for(var/i = length(scrapboard.overlays), i > 1, i--) + var/image/copy = new(scrapboard) + copy.overlays.Cut(1, i) + states += copy + + //inseert full state last + states += scrapboard + cached_ore_icon_states[IS] = states + +/obj/item/stack/material/ore/update_state_from_amount() + if(amount > 1) + add_overlay(get_cached_ore_pile_overlay(icon_state, amount)) +//#TODO: Ideally, since ore piles contain a lot of ores for performances reasons, +// it might be a good idea to scale the item size dynamically. But currently containers and inventories do not support that. +// if(amount >= (max_amount * 0.75)) +// w_class = ITEM_SIZE_HUGE +// else if(amount >= (max_amount * 0.5)) +// w_class = ITEM_SIZE_LARGE +// else if(amount >= (max_amount * 0.25)) +// w_class = ITEM_SIZE_NORMAL +// else +// w_class = ITEM_SIZE_SMALL + +/obj/item/stack/material/ore/set_material(var/new_material) + . = ..() + if(istype(material)) + LAZYSET(matter, material.type, SHEET_MATERIAL_AMOUNT) + icon_state = material.ore_icon_overlay ? material.ore_icon_overlay : initial(icon_state) + if(icon_state == "dust") + slot_flags = SLOT_HOLSTER + queue_icon_update() + +/obj/item/stack/material/ore/update_strings() + . = ..() + SetName("[(material.ore_name ? material.ore_name : "[material.name] chunk")][(amount > 1? " pile" : "")]") + desc = material.ore_desc ? material.ore_desc : "A lump of ore." + +/obj/item/stack/material/ore/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/stack/material) && !is_same(used_item)) + return FALSE //Don't reinforce + if(reinf_material && reinf_material.default_solid_form && IS_WELDER(used_item)) + return FALSE //Don't melt stuff with welder + return ..() + +/// POCKET SAND! +/obj/item/stack/material/ore/throw_impact(atom/hit_atom) + . = ..() + if(icon_state == "dust") + var/mob/living/human/H = hit_atom + if(istype(H) && H.check_has_eyes() && prob(85)) + to_chat(H, SPAN_DANGER("Some of \the [src] gets in your eyes!")) + ADJ_STATUS(H, STAT_BLIND, 5) + ADJ_STATUS(H, STAT_BLURRY, 10) + QDEL_IN(src, 1) + +// Map definitions. +/obj/item/stack/material/ore/uranium + material = /decl/material/solid/pitchblende +/obj/item/stack/material/ore/uranium/three + amount = 3 +/obj/item/stack/material/ore/iron + material = /decl/material/solid/hematite +/obj/item/stack/material/ore/iron/ten + amount = 10 +/obj/item/stack/material/ore/coal + material = /decl/material/solid/graphite +/obj/item/stack/material/ore/coal/ten + amount = 10 +/obj/item/stack/material/ore/silver + material = /decl/material/solid/metal/silver +/obj/item/stack/material/ore/silver/five + amount = 5 +/obj/item/stack/material/ore/gold + material = /decl/material/solid/metal/gold +/obj/item/stack/material/ore/gold/five + amount = 5 +/obj/item/stack/material/ore/diamond + material = /decl/material/solid/gemstone/diamond +/obj/item/stack/material/ore/diamond/three + amount = 3 +/obj/item/stack/material/ore/osmium + material = /decl/material/solid/metal/platinum +/obj/item/stack/material/ore/osmium/three + amount = 3 +/obj/item/stack/material/ore/hydrogen + material = /decl/material/solid/metallic_hydrogen +/obj/item/stack/material/ore/hydrogen/two + amount = 2 +/obj/item/stack/material/ore/slag + material = /decl/material/solid/slag +/obj/item/stack/material/ore/phosphorite + material = /decl/material/solid/phosphorite +/obj/item/stack/material/ore/bauxite + material = /decl/material/solid/bauxite +/obj/item/stack/material/ore/bauxite/ten + amount = 10 +/obj/item/stack/material/ore/rutile + material = /decl/material/solid/rutile +/obj/item/stack/material/ore/rutile/five + amount = 5 +/obj/item/stack/material/ore/galena + material = /decl/material/solid/galena +/obj/item/stack/material/ore/galena/ten + amount = 10 +/obj/item/stack/material/ore/tetrahedrite + material = /decl/material/solid/tetrahedrite +/obj/item/stack/material/ore/tetrahedrite/ten + amount = 10 +/obj/item/stack/material/ore/hydrogen_hydrate + material = /decl/material/solid/ice/hydrogen // todo: set back to hydrate when clathrate is added to hydrogen hydrate dname +/obj/item/stack/material/ore/methane + material = /decl/material/solid/ice/hydrate/methane +/obj/item/stack/material/ore/oxygen + material = /decl/material/solid/ice/hydrate/oxygen +/obj/item/stack/material/ore/nitrogen + material = /decl/material/solid/ice/hydrate/nitrogen +/obj/item/stack/material/ore/carbon_dioxide + material = /decl/material/solid/ice/hydrate/carbon_dioxide +/obj/item/stack/material/ore/argon + material = /decl/material/solid/ice/hydrate/argon +/obj/item/stack/material/ore/neon + material = /decl/material/solid/ice/hydrate/neon +/obj/item/stack/material/ore/krypton + material = /decl/material/solid/ice/hydrate/krypton +/obj/item/stack/material/ore/xenon + material = /decl/material/solid/ice/hydrate/xenon +/obj/item/stack/material/ore/meat + material = /decl/material/solid/organic/meat + +/obj/item/stack/material/ore/handful + singular_name = "handful" + plural_name = "handfuls" + stack_merge_type = /obj/item/stack/material/ore/handful + matter_multiplier = 1 + can_be_pulverized = FALSE + +// Override as it doesn't make much sense to squash sand. +/obj/item/stack/material/ore/handful/squash_item(skip_qdel = FALSE) + return + +/obj/item/stack/material/ore/handful/get_stack_conversion_dictionary() + return + +/obj/item/stack/material/ore/handful/sand + material = /decl/material/solid/sand + +/obj/item/stack/material/ore/handful/sand/fifteen + amount = 15 + +/client/proc/spawn_ore_pile() + set name = "Spawn Ore Pile" + set category = "Debug" + set src = usr + + if(!check_rights(R_SPAWN)) + return + + var/turf/T = get_turf(usr) + if(!istype(T)) + return + + var/list/all_materials = decls_repository.get_decls_of_subtype(/decl/material) + for(var/mtype in all_materials) + var/decl/material/mat = all_materials[mtype] + if(mat.ore_result_amount) + var/drop_type = mat.ore_type || /obj/item/stack/material/ore + new drop_type(T, mat.ore_result_amount, mtype) + +#undef ORE_MAX_AMOUNT +#undef ORE_MAX_OVERLAYS \ No newline at end of file diff --git a/code/modules/mechs/_mech_setup.dm b/code/modules/mechs/_mech_setup.dm index b11ffac6a411..4b3f2949bcc3 100644 --- a/code/modules/mechs/_mech_setup.dm +++ b/code/modules/mechs/_mech_setup.dm @@ -1,41 +1,9 @@ -GLOBAL_DATUM_INIT(default_hardpoint_background, /image, null) -GLOBAL_DATUM_INIT(hardpoint_error_icon, /image, null) -GLOBAL_DATUM_INIT(hardpoint_bar_empty, /image, null) - -GLOBAL_LIST_INIT(hardpoint_bar_cache, new) -GLOBAL_LIST_INIT(mech_damage_overlay_cache, new) -GLOBAL_LIST_INIT(mech_image_cache, new) -GLOBAL_LIST_INIT(mech_icon_cache, new) -GLOBAL_LIST_INIT(mech_weapon_overlays, icon_states('icons/mecha/mech_weapon_overlays.dmi')) - -#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 +var/global/image/default_hardpoint_background = null +var/global/image/hardpoint_error_icon = null +var/global/image/hardpoint_bar_empty = null + +var/global/list/hardpoint_bar_cache = list() +var/global/list/mech_damage_overlay_cache = list() +var/global/list/mech_image_cache = list() +var/global/list/mech_icon_cache = list() +var/global/list/mech_weapon_overlays = icon_states('icons/mecha/mech_weapon_overlays.dmi') diff --git a/code/modules/mechs/components/_components.dm b/code/modules/mechs/components/_components.dm index 7f3f21004a43..e3f6f5617cdb 100644 --- a/code/modules/mechs/components/_components.dm +++ b/code/modules/mechs/components/_components.dm @@ -3,6 +3,14 @@ w_class = ITEM_SIZE_HUGE gender = PLURAL color = COLOR_GUNMETAL + atom_flags = ATOM_FLAG_CAN_BE_PAINTED + + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/osmium = MATTER_AMOUNT_TRACE + ) + dir = SOUTH var/on_mech_icon = 'icons/mecha/mech_parts.dmi' var/exosuit_desc_string @@ -13,34 +21,26 @@ var/damage_state = 1 var/list/has_hardpoints = list() var/decal + var/decal_blend = BLEND_MULTIPLY var/power_use = 0 - material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/metal/osmium = MATTER_AMOUNT_TRACE - ) - dir = SOUTH - -/obj/item/mech_component/proc/set_colour(new_colour) - var/last_colour = color - color = new_colour - return color != last_colour /obj/item/mech_component/emp_act(var/severity) take_burn_damage(rand((10 - (severity*3)),15-(severity*4))) for(var/obj/item/thing in contents) thing.emp_act(severity) -/obj/item/mech_component/examine(mob/user) +/obj/item/mech_component/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(ready_to_install()) - to_chat(user, SPAN_NOTICE("It is ready for installation.")) + . += SPAN_NOTICE("It is ready for installation.") else - show_missing_parts(user) + var/list/missing_parts = show_missing_parts(user) + if(length(missing_parts)) + . += missing_parts //These icons have multiple directions but before they're attached we only want south. /obj/item/mech_component/set_dir() - ..(SOUTH) + return ..(SOUTH) /obj/item/mech_component/proc/show_missing_parts(var/mob/user) return @@ -49,14 +49,21 @@ return /obj/item/mech_component/proc/install_component(var/obj/item/thing, var/mob/user) - if(user.unEquip(thing, src)) + if(user.try_unequip(thing, src)) user.visible_message(SPAN_NOTICE("\The [user] installs \the [thing] in \the [src].")) - return 1 + return TRUE + return FALSE -/obj/item/mech_component/proc/update_health() +/obj/item/mech_component/proc/update_component_health() total_damage = brute_damage + burn_damage if(total_damage > max_damage) total_damage = max_damage - damage_state = Clamp(round((total_damage/max_damage) * 4), MECH_COMPONENT_DAMAGE_UNDAMAGED, MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL) + var/prev_state = damage_state + damage_state = clamp(round((total_damage/max_damage) * 4), MECH_COMPONENT_DAMAGE_UNDAMAGED, MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL) + if(damage_state > prev_state) + if(damage_state == MECH_COMPONENT_DAMAGE_DAMAGED_BAD) + playsound(src.loc, 'sound/mecha/internaldmgalarm.ogg', 40, 1) + if(damage_state == MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL) + playsound(src.loc, 'sound/mecha/critdestr.ogg', 50) /obj/item/mech_component/proc/ready_to_install() return 1 @@ -69,13 +76,13 @@ /obj/item/mech_component/proc/take_brute_damage(var/amt) brute_damage = max(0, brute_damage + amt) - update_health() + update_component_health() if(total_damage == max_damage) take_component_damage(amt,0) /obj/item/mech_component/proc/take_burn_damage(var/amt) burn_damage = max(0, burn_damage + amt) - update_health() + update_component_health() if(total_damage == max_damage) take_component_damage(0,amt) @@ -85,12 +92,13 @@ damageable_components += RC if(!damageable_components.len) return var/obj/item/robot_parts/robot_component/RC = pick(damageable_components) - if(RC.take_damage(brute, burn)) + if(RC.take_damage(brute, BRUTE) || RC.take_damage(burn, BURN)) qdel(RC) update_components() -/obj/item/mech_component/attackby(var/obj/item/thing, var/mob/user) - if(isScrewdriver(thing)) +/obj/item/mech_component/attackby(var/obj/item/used_item, var/mob/user) + + if(IS_SCREWDRIVER(used_item)) if(contents.len) //Filter non movables var/list/valid_contents = list() @@ -98,39 +106,50 @@ if(!A.anchored) valid_contents += A if(!valid_contents.len) - return + return TRUE var/obj/item/removed = pick(valid_contents) if(!(removed in contents)) - return + return TRUE user.visible_message(SPAN_NOTICE("\The [user] removes \the [removed] from \the [src].")) removed.forceMove(user.loc) playsound(user.loc, 'sound/effects/pop.ogg', 50, 0) update_components() else to_chat(user, SPAN_WARNING("There is nothing to remove.")) - return - if(isWelder(thing)) - repair_brute_generic(thing, user) - return - if(isCoil(thing)) - repair_burn_generic(thing, user) - return + return TRUE + + if(IS_WELDER(used_item)) + repair_brute_generic(used_item, user) + return TRUE + + if(IS_COIL(used_item)) + repair_burn_generic(used_item, user) + return TRUE + + if(istype(used_item, /obj/item/robotanalyzer)) + to_chat(user, SPAN_NOTICE("Diagnostic Report for \the [src]:")) + return_diagnostics(user) + return TRUE return ..() /obj/item/mech_component/proc/update_components() return -/obj/item/mech_component/proc/repair_brute_generic(var/obj/item/weldingtool/WT, var/mob/user) - if(!istype(WT)) +/obj/item/mech_component/proc/repair_brute_generic(var/obj/item/weldingtool/welder, var/mob/user) + if(!istype(welder)) return if(!brute_damage) to_chat(user, SPAN_NOTICE("You inspect \the [src] but find nothing to weld.")) return - if(!WT.isOn()) - to_chat(user, SPAN_WARNING("Turn \the [WT] on, first.")) + if(!welder.isOn()) + to_chat(user, SPAN_WARNING("Turn \the [welder] on, first.")) return - if(WT.remove_fuel((SKILL_MAX + 1) - user.get_skill_value(SKILL_CONSTRUCTION), user)) + if(welder.weld((SKILL_MAX + 1) - user.get_skill_value(SKILL_CONSTRUCTION), user)) + user.visible_message( + SPAN_NOTICE("\The [user] begins welding the damage on \the [src]..."), + SPAN_NOTICE("You begin welding the damage on \the [src]...") + ) var/repair_value = 10 * max(user.get_skill_value(SKILL_CONSTRUCTION), user.get_skill_value(SKILL_DEVICES)) if(user.do_skilled(10, SKILL_DEVICES , src, 0.6) && brute_damage) repair_brute_damage(repair_value) @@ -154,7 +173,7 @@ if(user.do_skilled(10, SKILL_DEVICES , src, 0.6) && burn_damage) if(QDELETED(CC) || QDELETED(src) || !CC.use(needed_amount)) return - + repair_burn_damage(25) to_chat(user, SPAN_NOTICE("You mend the damage to \the [src]'s wiring.")) playsound(user.loc, 'sound/items/Deconstruct.ogg', 25, 1) @@ -163,11 +182,15 @@ /obj/item/mech_component/proc/get_damage_string() switch(damage_state) if(MECH_COMPONENT_DAMAGE_UNDAMAGED) - return FONT_COLORED(COLOR_GREEN, "undamaged") + return SPAN_GREEN("undamaged") if(MECH_COMPONENT_DAMAGE_DAMAGED) - return FONT_COLORED(COLOR_YELLOW, "damaged") + return SPAN_YELLOW("damaged") if(MECH_COMPONENT_DAMAGE_DAMAGED_BAD) - return FONT_COLORED(COLOR_ORANGE, "badly damaged") + return SPAN_ORANGE("badly damaged") if(MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL) - return FONT_COLORED(COLOR_RED, "almost destroyed") - return FONT_COLORED(COLOR_RED, "destroyed") \ No newline at end of file + return SPAN_RED("almost destroyed") + return SPAN_RED("destroyed") + +/obj/item/mech_component/proc/return_diagnostics(var/mob/user) + to_chat(user, SPAN_NOTICE("[capitalize(src.name)]:")) + to_chat(user, SPAN_NOTICE(" - Integrity: [round((((max_damage - total_damage) / max_damage)) * 100)]%" )) diff --git a/code/modules/mechs/components/armour.dm b/code/modules/mechs/components/armour.dm index 13802158bf22..a5c122dfadea 100644 --- a/code/modules/mechs/components/armour.dm +++ b/code/modules/mechs/components/armour.dm @@ -4,60 +4,60 @@ /obj/item/robot_parts/robot_component/armour/exosuit name = "exosuit armour plating" armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_MINOR + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_MINOR ) - origin_tech = "{'materials':1}" + origin_tech = @'{"materials":1}' material = /decl/material/solid/metal/steel /obj/item/robot_parts/robot_component/armour/exosuit/radproof name = "radiation-proof armour plating" - desc = "A fully enclosed radiation hardened shell designed to protect the pilot from radiation" + desc = "A fully enclosed radiation hardened shell designed to protect the pilot from radiation." armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED ) - origin_tech = "{'materials':3}" + origin_tech = @'{"materials":3}' material = /decl/material/solid/metal/steel /obj/item/robot_parts/robot_component/armour/exosuit/em name = "EM-shielded armour plating" - desc = "A shielded plating that sorrounds the eletronics and protects them from electromagnetic radiation" + desc = "A shielded plating that surrounds sensitive electronic components and protects them from electromagnetic radiation." armor = list( - melee = ARMOR_MELEE_RESISTANT , - bullet = ARMOR_BALLISTIC_SMALL, - laser = ARMOR_LASER_SMALL, - energy = ARMOR_ENERGY_SHIELDED, - bomb = ARMOR_BOMB_MINOR, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SMALL + ARMOR_MELEE = ARMOR_MELEE_RESISTANT , + ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, + ARMOR_LASER = ARMOR_LASER_SMALL, + ARMOR_ENERGY = ARMOR_ENERGY_SHIELDED, + ARMOR_BOMB = ARMOR_BOMB_MINOR, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SMALL ) - origin_tech = "{'materials':3}" + origin_tech = @'{"materials":3}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT) /obj/item/robot_parts/robot_component/armour/exosuit/combat name = "heavy combat plating" - desc = "Plating designed to deflect incoming attacks and explosions" + desc = "Plating designed to deflect incoming attacks and explosions." armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED ) - origin_tech = "{'materials':5}" + origin_tech = @'{"materials":5}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT) diff --git a/code/modules/mechs/components/arms.dm b/code/modules/mechs/components/arms.dm index 5859bf5652cf..f420a8b3d853 100644 --- a/code/modules/mechs/components/arms.dm +++ b/code/modules/mechs/components/arms.dm @@ -16,7 +16,7 @@ /obj/item/mech_component/manipulators/show_missing_parts(var/mob/user) if(!motivator) - to_chat(user, SPAN_WARNING("It is missing an actuator.")) + return list(SPAN_WARNING("It is missing an actuator.")) /obj/item/mech_component/manipulators/ready_to_install() return motivator @@ -24,12 +24,15 @@ /obj/item/mech_component/manipulators/prebuild() motivator = new(src) -/obj/item/mech_component/manipulators/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing,/obj/item/robot_parts/robot_component/actuator)) +/obj/item/mech_component/manipulators/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item,/obj/item/robot_parts/robot_component/actuator)) if(motivator) to_chat(user, SPAN_WARNING("\The [src] already has an actuator installed.")) - return - if(install_component(thing, user)) motivator = thing + return TRUE + if(install_component(used_item, user)) + motivator = used_item + return TRUE + return FALSE else return ..() @@ -39,4 +42,11 @@ /obj/item/mech_component/manipulators/get_damage_string() if(!motivator || !motivator.is_functional()) return SPAN_DANGER("disabled") - return ..() \ No newline at end of file + return ..() + +/obj/item/mech_component/manipulators/return_diagnostics(mob/user) + ..() + if(motivator) + to_chat(user, SPAN_NOTICE(" Actuator Integrity: [round(motivator.get_percent_health())]%")) + else + to_chat(user, SPAN_WARNING(" Actuator Missing or Non-functional.")) diff --git a/code/modules/mechs/components/body.dm b/code/modules/mechs/components/body.dm index f5983e08510c..90890403e105 100644 --- a/code/modules/mechs/components/body.dm +++ b/code/modules/mechs/components/body.dm @@ -1,9 +1,8 @@ -/obj/item/storage/mech - w_class = ITEM_SIZE_NO_CONTAINER - max_w_class = ITEM_SIZE_LARGE - storage_slots = 4 - use_sound = 'sound/effects/storage/toolbox.ogg' - anchored = 1 +/obj/item/mech_storage + storage = /datum/storage/mech + anchored = TRUE + max_health = ITEM_HEALTH_NO_DAMAGE + obj_flags = OBJ_FLAG_NO_STORAGE /obj/item/mech_component/chassis/Adjacent(var/atom/neighbor, var/recurse = 1) //For interaction purposes we consider body to be adjacent to whatever holder mob is adjacent var/mob/living/exosuit/E = loc @@ -11,7 +10,7 @@ . = E.Adjacent(neighbor, recurse) return . || ..() -/obj/item/storage/mech/Adjacent(var/atom/neighbor, var/recurse = 1) //in order to properly retrieve items +/obj/item/mech_storage/Adjacent(var/atom/neighbor, var/recurse = 1) //in order to properly retrieve items var/obj/item/mech_component/chassis/C = loc if(istype(C)) . = C.Adjacent(neighbor, recurse-1) @@ -29,7 +28,7 @@ var/obj/item/robot_parts/robot_component/diagnosis_unit/diagnostics var/obj/item/robot_parts/robot_component/armour/exosuit/m_armour var/obj/machinery/portable_atmospherics/canister/air_supply - var/obj/item/storage/mech/storage_compartment + var/obj/item/mech_storage/storage_compartment var/datum/gas_mixture/cockpit var/transparent_cabin = FALSE var/hide_pilot = FALSE @@ -51,6 +50,21 @@ "[WEST]" = list("x" = 8, "y" = 0) ) ) + if(pilot_coverage >= 100) //Open cockpits dont get to have air + cockpit = new + cockpit.total_volume = 200 + if(loc) + var/datum/gas_mixture/air = loc.return_air() + if(air) + //Essentially at this point its like we created a vacuum, but realistically making a bottle doesnt actually increase volume of a room and neither should a mech + for(var/g in air.gas) + cockpit.gas[g] = (air.gas[g] / air.total_volume) * cockpit.total_volume + + cockpit.temperature = air.temperature + cockpit.update_values() + + air_supply = new /obj/machinery/portable_atmospherics/canister/air(src) + storage_compartment = new(src) /obj/item/mech_component/chassis/Destroy() QDEL_NULL(cell) @@ -68,26 +82,19 @@ storage_compartment = locate() in src /obj/item/mech_component/chassis/show_missing_parts(var/mob/user) + . = list() if(!cell) - to_chat(user, SPAN_WARNING("It is missing a power cell.")) + . += SPAN_WARNING("It is missing a power cell.") if(!diagnostics) - to_chat(user, SPAN_WARNING("It is missing a diagnostics unit.")) + . += SPAN_WARNING("It is missing a diagnostics unit.") if(!m_armour) - to_chat(user, SPAN_WARNING("It is missing exosuit armour plating.")) - -/obj/item/mech_component/chassis/Initialize() - . = ..() - cockpit = new(20) - if(loc) - var/datum/gas_mixture/air = loc.return_air() - if(air) - cockpit.equalize(air) - air_supply = new /obj/machinery/portable_atmospherics/canister/air(src) - storage_compartment = new(src) + . += SPAN_WARNING("It is missing exosuit armour plating.") /obj/item/mech_component/chassis/proc/update_air(var/take_from_supply) var/changed + if(!cockpit) + return if(!take_from_supply || pilot_coverage < 100) var/turf/T = get_turf(src) if(!T) @@ -97,11 +104,29 @@ else if(air_supply) var/env_pressure = cockpit.return_pressure() var/pressure_delta = air_supply.release_pressure - env_pressure - if((air_supply.air_contents.temperature > 0) && (pressure_delta > 0)) - var/transfer_moles = calculate_transfer_moles(air_supply.air_contents, cockpit, pressure_delta) - transfer_moles = min(transfer_moles, (air_supply.release_flow_rate/air_supply.air_contents.volume)*air_supply.air_contents.total_moles) - pump_gas_passive(air_supply, air_supply.air_contents, cockpit, transfer_moles) - changed = TRUE + if(pressure_delta > 0) + if(air_supply.air_contents.temperature > 0) + var/transfer_moles = calculate_transfer_moles(air_supply.air_contents, cockpit, pressure_delta) + transfer_moles = min(transfer_moles, (air_supply.release_flow_rate/air_supply.air_contents.total_volume)*air_supply.air_contents.total_moles) + pump_gas_passive(air_supply, air_supply.air_contents, cockpit, transfer_moles) + changed = TRUE + else if(pressure_delta < 0) //Release overpressure. + var/turf/T = get_turf(src) + if(!T) + return + var/datum/gas_mixture/t_air = T.return_air() + if(t_air) + pressure_delta = min(env_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //Location is at a lower pressure (so we can vent into it) + var/transfer_moles = calculate_transfer_moles(cockpit, t_air, pressure_delta) + var/datum/gas_mixture/removed = cockpit.remove(transfer_moles) + if(!removed) + return + if(t_air) + t_air.merge(removed) + else //just delete the cabin gas, we are somewhere with invalid air, so they wont mind the additional nothingness + qdel(removed) + changed = TRUE if(changed) cockpit.react() @@ -113,43 +138,64 @@ cell = new /obj/item/cell/exosuit(src) cell.charge = cell.maxcharge -/obj/item/mech_component/chassis/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing,/obj/item/robot_parts/robot_component/diagnosis_unit)) +/obj/item/mech_component/chassis/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item,/obj/item/robot_parts/robot_component/diagnosis_unit)) if(diagnostics) to_chat(user, SPAN_WARNING("\The [src] already has a diagnostic system installed.")) - return - if(install_component(thing, user)) diagnostics = thing - else if(istype(thing, /obj/item/cell)) + return TRUE + if(install_component(used_item, user)) + diagnostics = used_item + return TRUE + return FALSE + else if(istype(used_item, /obj/item/cell)) if(cell) to_chat(user, SPAN_WARNING("\The [src] already has a cell installed.")) - return - if(install_component(thing,user)) cell = thing - else if(istype(thing, /obj/item/robot_parts/robot_component/armour/exosuit)) + return TRUE + if(install_component(used_item,user)) + cell = used_item + return TRUE + return FALSE + else if(istype(used_item, /obj/item/robot_parts/robot_component/armour/exosuit)) if(m_armour) to_chat(user, SPAN_WARNING("\The [src] already has armour installed.")) - return - if(install_component(thing, user)) - m_armour = thing + return TRUE + if(install_component(used_item, user)) + m_armour = used_item + return TRUE + return FALSE else return ..() -/obj/item/mech_component/chassis/MouseDrop_T(atom/dropping, mob/user) - var/obj/machinery/portable_atmospherics/canister/C = dropping - if(istype(C) && !C.anchored && do_after(user, 5, src)) - if(C.anchored) - return - to_chat(user, SPAN_NOTICE("You install the canister in the [src].")) - if(air_supply) - air_supply.forceMove(get_turf(src)) - air_supply = null - C.forceMove(src) - update_components() - else . = ..() - -obj/item/mech_component/chassis/MouseDrop(atom/over) - if(CanMouseDrop(over)) - if(storage_compartment) - return storage_compartment.MouseDrop(over) - - +/obj/item/mech_component/chassis/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && istype(dropping, /obj/machinery/portable_atmospherics/canister)) + var/obj/machinery/portable_atmospherics/canister/C = dropping + if(pilot_coverage < 100) + to_chat(user, SPAN_NOTICE("This type of chassis doesn't support internals.")) + return TRUE + if(!C.anchored && do_after(user, 5, src)) + if(C.anchored) + return + to_chat(user, SPAN_NOTICE("You install the canister in \the [src].")) + if(air_supply) + air_supply.dropInto(get_turf(src)) + air_supply = null + C.forceMove(src) + update_components() + return TRUE + +/obj/item/mech_component/chassis/handle_mouse_drop(atom/over, mob/user, params) + if(storage_compartment) + return storage_compartment.handle_mouse_drop(over, user, params) + . = ..() +/obj/item/mech_component/chassis/return_diagnostics(mob/user) + ..() + if(diagnostics) + to_chat(user, SPAN_NOTICE(" Diagnostics Unit Integrity: [round(get_percent_health())]%")) + else + to_chat(user, SPAN_WARNING(" Diagnostics Unit Missing or Non-functional.")) + if(m_armour) + to_chat(user, SPAN_NOTICE(" Armor Integrity: [round(m_armour.get_percent_health())]%")) + else + to_chat(user, SPAN_WARNING(" Armor Missing or Non-functional.")) diff --git a/code/modules/mechs/components/frame.dm b/code/modules/mechs/components/frame.dm index 59679b455c0b..867a6b831ec7 100644 --- a/code/modules/mechs/components/frame.dm +++ b/code/modules/mechs/components/frame.dm @@ -1,23 +1,13 @@ -/obj/item/frame_holder - material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/metal/osmium = MATTER_AMOUNT_TRACE - ) - -/obj/item/frame_holder/Initialize(mapload, var/newloc) - ..() - new /obj/structure/heavy_vehicle_frame(newloc) - return INITIALIZE_HINT_QDEL - /obj/structure/heavy_vehicle_frame name = "exosuit frame" desc = "The frame for an exosuit, apparently." icon = 'icons/mecha/mech_parts.dmi' icon_state = "backbone" - density = 1 + density = TRUE pixel_x = -8 material = /decl/material/solid/metal/steel + atom_flags = ATOM_FLAG_CAN_BE_PAINTED + dir = SOUTH // Holders for the final product. var/obj/item/mech_component/manipulators/arms @@ -27,12 +17,11 @@ var/is_wired = 0 var/is_reinforced = 0 var/set_name - dir = SOUTH -/obj/structure/heavy_vehicle_frame/proc/set_colour(var/new_colour) +/obj/structure/heavy_vehicle_frame/set_color(new_colour) var/painted_component = FALSE for(var/obj/item/mech_component/comp in list(body, arms, legs, head)) - if(comp.set_colour(new_colour)) + if(comp.set_color(new_colour)) painted_component = TRUE if(painted_component) queue_icon_update() @@ -44,61 +33,61 @@ QDEL_NULL(body) . = ..() -/obj/structure/heavy_vehicle_frame/examine(mob/user) +/obj/structure/heavy_vehicle_frame/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(!arms) - to_chat(user, SPAN_WARNING("It is missing manipulators.")) + . += SPAN_WARNING("It is missing manipulators.") if(!legs) - to_chat(user, SPAN_WARNING("It is missing propulsion.")) + . += SPAN_WARNING("It is missing propulsion.") if(!head) - to_chat(user, SPAN_WARNING("It is missing sensors.")) + . += SPAN_WARNING("It is missing sensors.") if(!body) - to_chat(user, SPAN_WARNING("It is missing a chassis.")) + . += SPAN_WARNING("It is missing a chassis.") if(is_wired == FRAME_WIRED) - to_chat(user, SPAN_WARNING("It has not had its wiring adjusted.")) + . += SPAN_WARNING("It has not had its wiring adjusted.") else if(!is_wired) - to_chat(user, SPAN_WARNING("It has not yet been wired.")) + . += SPAN_WARNING("It has not yet been wired.") if(is_reinforced == FRAME_REINFORCED) - to_chat(user, SPAN_WARNING("It has not had its internal reinforcement secured.")) + . += SPAN_WARNING("It has not had its internal reinforcement secured.") else if(is_reinforced == FRAME_REINFORCED_SECURE) - to_chat(user, SPAN_WARNING("It has not had its internal reinforcement welded in.")) + . += SPAN_WARNING("It has not had its internal reinforcement welded in.") else if(!is_reinforced) - to_chat(user, SPAN_WARNING("It does not have any internal reinforcement.")) + . += SPAN_WARNING("It does not have any internal reinforcement.") /obj/structure/heavy_vehicle_frame/on_update_icon() - var/list/new_overlays = get_mech_images(list(legs, head, body, arms), layer) + ..() + for(var/obj/item/mech_component/comp in list(legs, head, body, arms)) + add_overlay(get_mech_image(comp.decal, comp.decal_blend, comp.icon_state, comp.on_mech_icon, comp.color, overlay_layer = FLOAT_LAYER)) if(body) - density = TRUE - overlays += get_mech_image(null, "[body.icon_state]_cockpit", body.icon, body.color) + set_density(TRUE) + add_overlay(get_mech_image(body.decal, body.decal_blend, "[body.icon_state]_cockpit", body.icon, body.color)) if(body.pilot_coverage < 100 || body.transparent_cabin) - new_overlays += get_mech_image(null, "[body.icon_state]_open_overlay", body.icon, body.color) + add_overlay(get_mech_image(body.decal, body.decal_blend, "[body.icon_state]_open_overlay", body.icon, body.color)) else - density = FALSE - overlays = new_overlays + set_density(FALSE) if(density != opacity) set_opacity(density) /obj/structure/heavy_vehicle_frame/set_dir() - ..(SOUTH) - -/obj/structure/heavy_vehicle_frame/attackby(var/obj/item/thing, var/mob/user) + return ..(SOUTH) +/obj/structure/heavy_vehicle_frame/attackby(var/obj/item/used_item, var/mob/user) // Removing components. - if(isCrowbar(thing)) + if(IS_CROWBAR(used_item)) if(is_reinforced == FRAME_REINFORCED) - if(!do_after(user, 5 * user.skill_delay_mult(SKILL_DEVICES)) || !material) - return + if(!user.do_skilled(0.5 SECONDS, SKILL_DEVICES, src) || !material) + return TRUE user.visible_message(SPAN_NOTICE("\The [user] crowbars the reinforcement off \the [src].")) - material.place_sheet(src.loc, 10) + material.create_object(src.loc, 10) material = null is_reinforced = 0 - return + return TRUE var/to_remove = input("Which component would you like to remove") as null|anything in list(arms, body, legs, head) if(!to_remove) to_chat(user, SPAN_WARNING("There are no components to remove.")) - return + return TRUE if(uninstall_component(to_remove, user)) if(to_remove == arms) @@ -111,15 +100,15 @@ head = null update_icon() - return + return TRUE // Final construction step. - else if(isScrewdriver(thing)) + else if(IS_SCREWDRIVER(used_item)) // Check for basic components. if(!(arms && legs && head && body)) to_chat(user, SPAN_WARNING("There are still parts missing from \the [src].")) - return + return TRUE // Check for wiring. if(is_wired < FRAME_WIRED_ADJUSTED) @@ -127,7 +116,7 @@ to_chat(user, SPAN_WARNING("\The [src]'s wiring has not been adjusted!")) else to_chat(user, SPAN_WARNING("\The [src] is not wired!")) - return + return TRUE // Check for basing metal internal plating. if(is_reinforced < FRAME_REINFORCED_WELDED) @@ -137,14 +126,14 @@ to_chat(user, SPAN_WARNING("\The [src]'s internal reinforcement has not been welded down!")) else to_chat(user, SPAN_WARNING("\The [src] has no internal reinforcement!")) - return + return TRUE visible_message(SPAN_NOTICE("\The [user] begins tightening screws, flipping connectors and finishing off \the [src].")) if(!user.do_skilled(50, SKILL_DEVICES, src)) - return + return TRUE if(is_reinforced < FRAME_REINFORCED_WELDED || is_wired < FRAME_WIRED_ADJUSTED || !(arms && legs && head && body) || QDELETED(src) || QDELETED(user)) - return + return TRUE // We're all done. Finalize the exosuit and pass the frame to the new system. var/mob/living/exosuit/M = new(get_turf(src), src) @@ -157,61 +146,61 @@ body = null qdel(src) - return + return TRUE // Installing wiring. - else if(isCoil(thing)) + else if(IS_COIL(used_item)) if(is_wired) to_chat(user, SPAN_WARNING("\The [src] has already been wired.")) - return + return TRUE - var/obj/item/stack/cable_coil/CC = thing + var/obj/item/stack/cable_coil/CC = used_item if(CC.get_amount() < 10) to_chat(user, SPAN_WARNING("You need at least ten units of cable to complete the exosuit.")) - return + return TRUE user.visible_message("\The [user] begins wiring \the [src]...") - if(!do_after(user, 30 * user.skill_delay_mult(SKILL_ELECTRICAL))) - return + if(!user.do_skilled(3 SECONDS, SKILL_ELECTRICAL, src)) + return TRUE if(!CC || !user || !src || CC.get_amount() < 10 || is_wired) - return + return TRUE CC.use(10) user.visible_message("\The [user] installs wiring in \the [src].") playsound(user.loc, 'sound/items/Deconstruct.ogg', 50, 1) is_wired = FRAME_WIRED // Securing wiring. - else if(isWirecutter(thing)) + else if(IS_WIRECUTTER(used_item)) if(!is_wired) to_chat(user, "There is no wiring in \the [src] to neaten.") - return + return TRUE user.visible_message("\The [user] begins adjusting the wiring inside \the [src]...") var/last_wiring_state = is_wired - if(!do_after(user, 30 * user.skill_delay_mult(SKILL_ELECTRICAL)) || last_wiring_state != is_wired) - return + if(!user.do_skilled(3 SECONDS, SKILL_ELECTRICAL, src) || last_wiring_state != is_wired) + return TRUE visible_message("\The [user] [(is_wired == FRAME_WIRED_ADJUSTED) ? "snips some of" : "neatens"] the wiring in \the [src].") playsound(user.loc, 'sound/items/Wirecutter.ogg', 100, 1) is_wired = (is_wired == FRAME_WIRED_ADJUSTED) ? FRAME_WIRED : FRAME_WIRED_ADJUSTED // Installing metal. - else if(istype(thing, /obj/item/stack/material)) - var/obj/item/stack/material/M = thing + else if(istype(used_item, /obj/item/stack/material)) + var/obj/item/stack/material/M = used_item if(M.material) if(is_reinforced) to_chat(user, SPAN_WARNING("There is already a material reinforcement installed in \the [src].")) - return + return TRUE if(M.get_amount() < 10) to_chat(user, SPAN_WARNING("You need at least ten sheets to reinforce \the [src].")) - return + return TRUE - visible_message("\The [user] begins layering the interior of the \the [src] with \the [M].") + visible_message("\The [user] begins layering the interior of \the [src] with \the [M].") - if(!do_after(user, 30 * user.skill_delay_mult(SKILL_DEVICES)) || is_reinforced) - return + if(!user.do_skilled(3 SECONDS, SKILL_DEVICES, src) || is_reinforced) + return TRUE visible_message("\The [user] reinforces \the [src] with \the [M].") playsound(user.loc, 'sound/items/Deconstruct.ogg', 50, 1) @@ -221,99 +210,101 @@ else return ..() // Securing metal. - else if(isWrench(thing)) + else if(IS_WRENCH(used_item)) if(!is_reinforced) to_chat(user, SPAN_WARNING("There is no metal to secure inside \the [src].")) - return + return TRUE if(is_reinforced == FRAME_REINFORCED_WELDED) to_chat(user, SPAN_WARNING("\The [src]'s internal reinforcment has been welded in.")) - return + return TRUE var/last_reinforced_state = is_reinforced visible_message("\The [user] begins adjusting the metal reinforcement inside \the [src].") if(!user.do_skilled(4 SECONDS, SKILL_DEVICES,src) || last_reinforced_state != is_reinforced) - return + return TRUE visible_message("\The [user] [(is_reinforced == 2) ? "unsecures" : "secures"] the metal reinforcement inside \the [src].") playsound(user.loc, 'sound/items/Ratchet.ogg', 100, 1) is_reinforced = (is_reinforced == FRAME_REINFORCED_SECURE) ? FRAME_REINFORCED : FRAME_REINFORCED_SECURE // Welding metal. - else if(isWelder(thing)) - var/obj/item/weldingtool/WT = thing + else if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item if(!is_reinforced) to_chat(user, SPAN_WARNING("There is no metal to secure inside \the [src].")) - return + return TRUE if(is_reinforced == FRAME_REINFORCED) to_chat(user, SPAN_WARNING("The reinforcement inside \the [src] has not been secured.")) - return - if(!WT.isOn()) - to_chat(user, SPAN_WARNING("Turn \the [WT] on, first.")) - return - if(WT.remove_fuel(1, user)) + return TRUE + if(!welder.isOn()) + to_chat(user, SPAN_WARNING("Turn \the [welder] on, first.")) + return TRUE + if(welder.weld(1, user)) var/last_reinforced_state = is_reinforced visible_message("\The [user] begins welding the metal reinforcement inside \the [src].") - if(!do_after(user, 20 * user.skill_delay_mult(SKILL_DEVICES)) || last_reinforced_state != is_reinforced) - return + if(!user.do_skilled(2 SECONDS, SKILL_DEVICES, src) || last_reinforced_state != is_reinforced) + return TRUE visible_message("\The [user] [(is_reinforced == FRAME_REINFORCED_WELDED) ? "unwelds the reinforcement from" : "welds the reinforcement into"] \the [src].") is_reinforced = (is_reinforced == FRAME_REINFORCED_WELDED) ? FRAME_REINFORCED_SECURE : FRAME_REINFORCED_WELDED playsound(user.loc, 'sound/items/Welder.ogg', 50, 1) else to_chat(user, SPAN_WARNING("Not enough fuel!")) - return + return TRUE // Installing basic components. - else if(istype(thing,/obj/item/mech_component/manipulators)) + else if(istype(used_item,/obj/item/mech_component/manipulators)) if(arms) to_chat(user, SPAN_WARNING("\The [src] already has manipulators installed.")) - return - if(install_component(thing, user)) + return TRUE + if(install_component(used_item, user)) if(arms) - thing.dropInto(loc) - return - arms = thing - else if(istype(thing,/obj/item/mech_component/propulsion)) + used_item.dropInto(loc) + return TRUE + arms = used_item + else if(istype(used_item,/obj/item/mech_component/propulsion)) if(legs) to_chat(user, SPAN_WARNING("\The [src] already has a propulsion system installed.")) - return - if(install_component(thing, user)) + return TRUE + if(install_component(used_item, user)) if(legs) - thing.dropInto(loc) - return - legs = thing - else if(istype(thing,/obj/item/mech_component/sensors)) + used_item.dropInto(loc) + return TRUE + legs = used_item + else if(istype(used_item,/obj/item/mech_component/sensors)) if(head) to_chat(user, SPAN_WARNING("\The [src] already has a sensor array installed.")) - return - if(install_component(thing, user)) + return TRUE + if(install_component(used_item, user)) if(head) - thing.dropInto(loc) - return - head = thing - else if(istype(thing,/obj/item/mech_component/chassis)) + used_item.dropInto(loc) + return TRUE + head = used_item + else if(istype(used_item,/obj/item/mech_component/chassis)) if(body) to_chat(user, SPAN_WARNING("\The [src] already has an outer chassis installed.")) - return - if(install_component(thing, user)) + return TRUE + if(install_component(used_item, user)) if(body) - thing.dropInto(loc) - return - body = thing + used_item.dropInto(loc) + return TRUE + body = used_item else return ..() update_icon() + return TRUE /obj/structure/heavy_vehicle_frame/proc/install_component(var/obj/item/thing, var/mob/user) - var/obj/item/mech_component/MC = thing - if(istype(MC) && !MC.ready_to_install()) - to_chat(user, SPAN_WARNING("\The [MC] [MC.gender == PLURAL ? "are" : "is"] not ready to install.")) + var/obj/item/mech_component/component = thing + if(istype(component) && !component.ready_to_install()) + var/decl/pronouns/component_pronouns = component.get_pronouns() + to_chat(user, SPAN_WARNING("\The [component] [component_pronouns.is] not ready to install.")) return 0 if(user) visible_message(SPAN_NOTICE("\The [user] begins installing \the [thing] into \the [src].")) - if(!user.canUnEquip(thing) || !do_after(user, 30 * user.skill_delay_mult(SKILL_DEVICES)) || user.get_active_hand() != thing) + if(!user.can_unequip_item(thing) || !user.do_skilled(3 SECONDS, SKILL_DEVICES, src) || user.get_active_held_item() != thing) return - if(!user.unEquip(thing)) + if(!user.try_unequip(thing)) return thing.forceMove(src) visible_message(SPAN_NOTICE("\The [user] installs \the [thing] into \the [src].")) @@ -323,7 +314,7 @@ /obj/structure/heavy_vehicle_frame/proc/uninstall_component(var/obj/item/component, var/mob/user) if(!istype(component) || (component.loc != src) || !istype(user)) return FALSE - if(!do_after(user, 40 * user.skill_delay_mult(SKILL_DEVICES)) || component.loc != src) + if(!user.do_skilled(4 SECONDS, SKILL_DEVICES, src) || component.loc != src) return FALSE user.visible_message(SPAN_NOTICE("\The [user] crowbars \the [component] off \the [src].")) component.forceMove(get_turf(src)) diff --git a/code/modules/mechs/components/head.dm b/code/modules/mechs/components/head.dm index e566f6d3c166..8c4869494e1d 100644 --- a/code/modules/mechs/components/head.dm +++ b/code/modules/mechs/components/head.dm @@ -19,12 +19,13 @@ . = ..() /obj/item/mech_component/sensors/show_missing_parts(var/mob/user) + . = list() if(!radio) - to_chat(user, SPAN_WARNING("It is missing a radio.")) + . += SPAN_WARNING("It is missing a radio.") if(!camera) - to_chat(user, SPAN_WARNING("It is missing a camera.")) + . += SPAN_WARNING("It is missing a camera.") if(!software) - to_chat(user, SPAN_WARNING("It is missing a software control module.")) + . += SPAN_WARNING("It is missing a software control module.") /obj/item/mech_component/sensors/prebuild() radio = new(src) @@ -35,18 +36,18 @@ camera = locate() in src software = locate() in src -/obj/item/mech_component/sensors/proc/get_sight() +/obj/item/mech_component/sensors/proc/get_sight(powered) var/flags = 0 - if(total_damage >= 0.8 * max_damage) + if(total_damage >= 0.8 * max_damage || !powered) flags |= BLIND - else if(active_sensors) + else if(active_sensors && powered) flags |= vision_flags return flags -/obj/item/mech_component/sensors/proc/get_invisible() +/obj/item/mech_component/sensors/proc/get_invisible(powered) var/invisible = 0 - if((total_damage <= 0.8 * max_damage) && active_sensors) + if((total_damage <= 0.8 * max_damage) && active_sensors && powered) invisible = see_invisible return invisible @@ -55,25 +56,51 @@ /obj/item/mech_component/sensors/ready_to_install() return (radio && camera) -/obj/item/mech_component/sensors/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing, /obj/item/mech_component/control_module)) +/obj/item/mech_component/sensors/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/mech_component/control_module)) if(software) to_chat(user, SPAN_WARNING("\The [src] already has a control modules installed.")) - return - if(install_component(thing, user)) software = thing - else if(istype(thing,/obj/item/robot_parts/robot_component/radio)) + return TRUE + if(install_component(used_item, user)) + software = used_item + return TRUE + return FALSE + else if(istype(used_item,/obj/item/robot_parts/robot_component/radio)) if(radio) to_chat(user, SPAN_WARNING("\The [src] already has a radio installed.")) - return - if(install_component(thing, user)) radio = thing - else if(istype(thing,/obj/item/robot_parts/robot_component/camera)) + return TRUE + if(install_component(used_item, user)) + radio = used_item + return TRUE + return FALSE + else if(istype(used_item,/obj/item/robot_parts/robot_component/camera)) if(camera) to_chat(user, SPAN_WARNING("\The [src] already has a camera installed.")) - return - if(install_component(thing, user)) camera = thing + return TRUE + if(install_component(used_item, user)) + camera = used_item + return TRUE + return FALSE else return ..() +/obj/item/mech_component/sensors/return_diagnostics(mob/user) + ..() + if(software) + to_chat(user, SPAN_NOTICE(" Installed Software")) + for(var/exosystem_software in software.installed_software) + to_chat(user, SPAN_NOTICE(" - [capitalize(exosystem_software)]")) + else + to_chat(user, SPAN_WARNING(" Control Module Missing or Non-functional.")) + if(radio) + to_chat(user, SPAN_NOTICE(" Radio Integrity: [round(radio.get_percent_health())]%")) + else + to_chat(user, SPAN_WARNING(" Radio Missing or Non-functional.")) + if(camera) + to_chat(user, SPAN_NOTICE(" Camera Integrity: [round(camera.get_percent_health())]%")) + else + to_chat(user, SPAN_WARNING(" Camera Missing or Non-functional.")) + /obj/item/mech_component/control_module name = "exosuit control module" desc = "A clump of circuitry and software chip docks, used to program exosuits." @@ -85,38 +112,37 @@ var/list/installed_software = list() var/max_installed_software = 2 -/obj/item/mech_component/control_module/examine(mob/user) +/obj/item/mech_component/control_module/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, SPAN_NOTICE("It has [max_installed_software - LAZYLEN(installed_software)] empty slot\s remaining out of [max_installed_software].")) + . += SPAN_NOTICE("It has [max_installed_software - LAZYLEN(installed_software)] empty slot\s remaining out of [max_installed_software].") -/obj/item/mech_component/control_module/attackby(var/obj/item/thing, var/mob/user) +/obj/item/mech_component/control_module/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/stock_parts/circuitboard/exosystem)) + install_software(used_item, user) + return TRUE - if(istype(thing, /obj/item/circuitboard/exosystem)) - install_software(thing, user) - return - - if(isScrewdriver(thing)) - var/result = ..() + if(IS_SCREWDRIVER(used_item)) + . = ..() update_software() - return result + return else return ..() -/obj/item/mech_component/control_module/proc/install_software(var/obj/item/circuitboard/exosystem/software, var/mob/user) +/obj/item/mech_component/control_module/proc/install_software(var/obj/item/stock_parts/circuitboard/exosystem/software, var/mob/user) if(installed_software.len >= max_installed_software) if(user) to_chat(user, SPAN_WARNING("\The [src] can only hold [max_installed_software] software modules.")) return - if(user && !user.unEquip(software)) + if(user && !user.try_unequip(software)) return if(user) to_chat(user, SPAN_NOTICE("You load \the [software] into \the [src]'s memory.")) - + software.forceMove(src) update_software() /obj/item/mech_component/control_module/proc/update_software() installed_software = list() - for(var/obj/item/circuitboard/exosystem/program in contents) + for(var/obj/item/stock_parts/circuitboard/exosystem/program in contents) installed_software |= program.contains_software diff --git a/code/modules/mechs/components/legs.dm b/code/modules/mechs/components/legs.dm index 1ee620990af3..1270dbfda92f 100644 --- a/code/modules/mechs/components/legs.dm +++ b/code/modules/mechs/components/legs.dm @@ -6,6 +6,7 @@ var/turn_delay = 5 var/obj/item/robot_parts/robot_component/actuator/motivator power_use = 50 + var/max_fall_damage = 30 /obj/item/mech_component/propulsion/Destroy() QDEL_NULL(motivator) @@ -13,7 +14,7 @@ /obj/item/mech_component/propulsion/show_missing_parts(var/mob/user) if(!motivator) - to_chat(user, SPAN_WARNING("It is missing an actuator.")) + return list(SPAN_WARNING("It is missing an actuator.")) /obj/item/mech_component/propulsion/ready_to_install() return motivator @@ -21,12 +22,15 @@ /obj/item/mech_component/propulsion/update_components() motivator = locate() in src -/obj/item/mech_component/propulsion/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing,/obj/item/robot_parts/robot_component/actuator)) +/obj/item/mech_component/propulsion/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item,/obj/item/robot_parts/robot_component/actuator)) if(motivator) to_chat(user, SPAN_WARNING("\The [src] already has an actuator installed.")) - return - if(install_component(thing, user)) motivator = thing + return TRUE + if(install_component(used_item, user)) + motivator = used_item + return TRUE + return FALSE else return ..() @@ -45,4 +49,18 @@ /obj/item/mech_component/propulsion/get_damage_string() if(!motivator || !motivator.is_functional()) return SPAN_DANGER("disabled") - return ..() \ No newline at end of file + return ..() + +/obj/item/mech_component/propulsion/return_diagnostics(mob/user) + ..() + if(motivator) + to_chat(user, SPAN_NOTICE(" Actuator Integrity: [round(motivator.get_percent_health())]%")) + else + to_chat(user, SPAN_WARNING(" Actuator Missing or Non-functional.")) + +//Expand here if the legs increase, reduce or otherwise affect fall damage for exosuit +/obj/item/mech_component/propulsion/proc/handle_vehicle_fall() + if(max_fall_damage > 0) + var/mob/living/exosuit/E = loc + if(istype(E)) //route it through exosuit for proper handling + E.apply_damage(rand(0, max_fall_damage), BRUTE, BP_R_LEG) //Any leg is good, will damage us correctly \ No newline at end of file diff --git a/code/modules/mechs/components/software.dm b/code/modules/mechs/components/software.dm index 09374d9c06eb..49cc737083de 100644 --- a/code/modules/mechs/components/software.dm +++ b/code/modules/mechs/components/software.dm @@ -1,33 +1,27 @@ -#define T_BOARD_MECH(name) "exosuit software (" + (name) + ")" - -/obj/item/circuitboard/exosystem +/obj/item/stock_parts/circuitboard/exosystem name = "exosuit software template" - icon = 'icons/obj/module.dmi' - icon_state = "std_mod" - item_state = "electronic" + icon = 'icons/obj/modules/module_standard.dmi' var/list/contains_software = list() -/obj/item/circuitboard/exosystem/engineering - name = T_BOARD_MECH("engineering systems") +/obj/item/stock_parts/circuitboard/exosystem/engineering + name = "exosuit circuit (engineering systems)" contains_software = list(MECH_SOFTWARE_ENGINEERING) - origin_tech = "{'programming':1}" + origin_tech = @'{"programming":1}' -/obj/item/circuitboard/exosystem/utility - name = T_BOARD_MECH("utility systems") +/obj/item/stock_parts/circuitboard/exosystem/utility + name = "exosuit circuit (utility systems)" contains_software = list(MECH_SOFTWARE_UTILITY) - icon_state = "mcontroller" - origin_tech = "{'programming':1}" + icon = 'icons/obj/modules/module_controller.dmi' + origin_tech = @'{"programming":1}' -/obj/item/circuitboard/exosystem/medical - name = T_BOARD_MECH("medical systems") +/obj/item/stock_parts/circuitboard/exosystem/medical + name = "exosuit circuit (medical systems)" contains_software = list(MECH_SOFTWARE_MEDICAL) - icon_state = "mcontroller" - origin_tech = "{'programming':3,'biotech':2}" + icon = 'icons/obj/modules/module_controller.dmi' + origin_tech = @'{"programming":3,"biotech":2}' -/obj/item/circuitboard/exosystem/weapons - name = T_BOARD_MECH("basic weapon systems") +/obj/item/stock_parts/circuitboard/exosystem/weapons + name = "exosuit circuit (basic weapon systems)" contains_software = list(MECH_SOFTWARE_WEAPONS) - icon_state = "mainboard" - origin_tech = "{'programming':4,'combat':3}" - -#undef T_BOARD_MECH \ No newline at end of file + icon = 'icons/obj/modules/module_mainboard.dmi' + origin_tech = @'{"programming":4,"combat":3}' diff --git a/code/modules/mechs/equipment/_equipment.dm b/code/modules/mechs/equipment/_equipment.dm index 13cc7214878c..ca8273afd3b2 100644 --- a/code/modules/mechs/equipment/_equipment.dm +++ b/code/modules/mechs/equipment/_equipment.dm @@ -6,10 +6,10 @@ icon_state = "" material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/osmium = MATTER_AMOUNT_TRACE ) - force = 10 + _base_attack_force = 10 var/list/restricted_hardpoints var/mob/living/exosuit/owner @@ -19,41 +19,46 @@ var/passive_power_use = 0 // For gear that for some reason takes up power even if it's supposedly doing nothing (mech will idly consume power) var/mech_layer = MECH_GEAR_LAYER //For the part where it's rendered as mech gear var/require_adjacent = TRUE + var/active = FALSE //For gear that has an active state (ie, floodlights) -/obj/item/mech_equipment/attack() //Generally it's not desired to be able to attack with items - return 0 +/obj/item/mech_equipment/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE /obj/item/mech_equipment/afterattack(var/atom/target, var/mob/living/user, var/inrange, var/params) if(require_adjacent) if(!inrange) - return 0 + return 0 if (owner && loc == owner && ((user in owner.pilots) || user == owner)) if(target in owner.contents) return 0 if(!(owner.get_cell()?.check_charge(active_power_use * CELLRATE))) - to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]")) - return 0 + to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src].")) + return 0 return 1 - else + else return 0 /obj/item/mech_equipment/attack_self(var/mob/user) if (owner && loc == owner && ((user in owner.pilots) || user == owner)) if(!(owner.get_cell()?.check_charge(active_power_use * CELLRATE))) - to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src]")) - return 0 + to_chat(user, SPAN_WARNING("The power indicator flashes briefly as you attempt to use \the [src].")) + return 0 return 1 - else + else return 0 -/obj/item/mech_equipment/examine(mob/user, distance) +/obj/item/mech_equipment/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(user.skill_check(SKILL_DEVICES, SKILL_BASIC)) - if(restricted_software.len) - to_chat(user, SPAN_SUBTLE("It seems it would require [english_list(restricted_software)] to be used.")) - if(restricted_hardpoints.len) - to_chat(user, SPAN_SUBTLE("You figure it could be mounted in the [english_list(restricted_hardpoints)].")) + if(length(restricted_software)) + . += SPAN_SUBTLE("It seems it would require [english_list(restricted_software)] to be used.") + if(length(restricted_hardpoints)) + . += SPAN_SUBTLE("You figure it could be mounted in the [english_list(restricted_hardpoints)].") + +/obj/item/mech_equipment/proc/deactivate() + active = FALSE + return /obj/item/mech_equipment/proc/installed(var/mob/living/exosuit/_owner) owner = _owner @@ -61,27 +66,31 @@ canremove = FALSE /obj/item/mech_equipment/proc/uninstalled() + if(active) + deactivate() owner = null canremove = TRUE -/obj/item/mech_equipment/Destroy() - owner = null - . = ..() - /obj/item/mech_equipment/proc/get_effective_obj() return src /obj/item/mech_equipment/proc/MouseDragInteraction() return 0 -/obj/item/mech_equipment/mob_can_unequip(mob/M, slot, disable_warning) +/obj/item/mech_equipment/proc/MouseDownInteraction() + return 0 + +/obj/item/mech_equipment/proc/MouseUpInteraction() + return 0 + +/obj/item/mech_equipment/mob_can_unequip(mob/user, slot, disable_warning = FALSE, dropping = FALSE) . = ..() if(. && owner) //Installed equipment shall not be unequiped. return FALSE /obj/item/mech_equipment/mounted_system - var/holding_type + abstract_type = /obj/item/mech_equipment/mounted_system var/obj/item/holding /obj/item/mech_equipment/mounted_system/attack_self(var/mob/user) @@ -91,29 +100,29 @@ /obj/item/mech_equipment/mounted_system/proc/forget_holding() if(holding) //It'd be strange for this to be called with this var unset - GLOB.destroyed_event.unregister(holding, src, .proc/forget_holding) + events_repository.unregister(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding)) holding = null if(!QDELETED(src)) qdel(src) /obj/item/mech_equipment/mounted_system/Initialize() . = ..() - if(holding_type) - holding = new holding_type(src) - GLOB.destroyed_event.register(holding, src, .proc/forget_holding) - if(holding) - if(!icon_state) - icon = holding.icon - icon_state = holding.icon_state - SetName(holding.name) - desc = "[holding.desc] This one is suitable for installation on an exosuit." - + if(ispath(holding)) + holding = new holding(src) + events_repository.register(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding)) + if(!istype(holding)) + return + if(!icon_state) + icon = holding.icon + icon_state = holding.icon_state + SetName(holding.name) + desc = "[holding.desc] This one is suitable for installation on an exosuit." /obj/item/mech_equipment/mounted_system/Destroy() + events_repository.unregister(/decl/observ/destroyed, holding, src, PROC_REF(forget_holding)) if(holding) QDEL_NULL(holding) . = ..() - /obj/item/mech_equipment/mounted_system/get_effective_obj() return (holding ? holding : src) diff --git a/code/modules/mechs/equipment/combat.dm b/code/modules/mechs/equipment/combat.dm index 89f5cd583cee..750d69df49de 100644 --- a/code/modules/mechs/equipment/combat.dm +++ b/code/modules/mechs/equipment/combat.dm @@ -2,7 +2,8 @@ name = "mounted electrolaser carbine" desc = "A dual fire mode electrolaser system connected to the exosuit's targetting system." icon_state = "mech_taser" - holding_type = /obj/item/gun/energy/taser/mounted/mech + origin_tech = @'{"combat":1,"magnets":1,"engineering":1}' + holding = /obj/item/gun/energy/taser/mounted/mech restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) restricted_software = list(MECH_SOFTWARE_WEAPONS) @@ -10,13 +11,15 @@ name = "mounted ion rifle" desc = "An exosuit-mounted ion rifle. Handle with care." icon_state = "mech_ionrifle" - holding_type = /obj/item/gun/energy/ionrifle/mounted/mech + holding = /obj/item/gun/energy/ionrifle/mounted/mech + origin_tech = @'{"combat":2,"powerstorage":2,"magnets":4,"engineering":2}' /obj/item/mech_equipment/mounted_system/taser/laser name = "\improper CH-PS \"Immolator\" laser" desc = "An exosuit-mounted laser rifle. Handle with care." icon_state = "mech_lasercarbine" - holding_type = /obj/item/gun/energy/laser/mounted/mech + holding = /obj/item/gun/energy/laser/mounted/mech + origin_tech = @'{"combat":3,"magnets":2,"engineering":2}' /obj/item/gun/energy/taser/mounted/mech use_external_power = TRUE @@ -36,12 +39,15 @@ self_recharge = TRUE /obj/item/gun/energy/get_hardpoint_maptext() + var/obj/item/cell/power_supply = get_cell() + if(!power_supply) + return 0 return "[round(power_supply.charge / charge_cost)]/[max_shots]" /obj/item/gun/energy/get_hardpoint_status_value() - var/obj/item/cell/C = get_cell() - if(istype(C)) - return C.charge/C.maxcharge + var/obj/item/cell/cell = get_cell() + if(istype(cell)) + return cell.charge/cell.maxcharge return null /obj/item/mech_equipment/shields @@ -51,12 +57,11 @@ restricted_hardpoints = list(HARDPOINT_BACK) restricted_software = list(MECH_SOFTWARE_WEAPONS) material = /decl/material/solid/metal/steel + origin_tech = @'{"magnets":3,"powerstorage":4,"materials":2,"engineering":2}' matter = list( /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) - - var/obj/aura/mechshield/aura = null var/max_charge = 150 var/charge = 150 var/last_recharge = 0 @@ -65,10 +70,12 @@ /obj/item/mech_equipment/shields/installed(var/mob/living/exosuit/_owner) . = ..() - aura = new(owner, src) + if(owner) + owner.add_mob_modifier(/decl/mob_modifier/mechshield, source = src) /obj/item/mech_equipment/shields/uninstalled() - QDEL_NULL(aura) + if(owner) + owner.remove_mob_modifier(/decl/mob_modifier/mechshield, source = src) . = ..() /obj/item/mech_equipment/shields/attack_self(var/mob/user) @@ -78,138 +85,266 @@ /obj/item/mech_equipment/shields/proc/stop_damage(var/damage) var/difference = damage - charge - charge = Clamp(charge - damage, 0, max_charge) + charge = clamp(charge - damage, 0, max_charge) last_recharge = world.time if(difference > 0) for(var/mob/pilot in owner.pilots) - to_chat(pilot, SPAN_DANGER("Warning: Deflector shield failure detect, shutting down")) + to_chat(pilot, SPAN_DANGER("Warning: Deflector shield failure detected, shutting down!")) toggle() playsound(owner.loc,'sound/mecha/internaldmgalarm.ogg',35,1) return difference else return 0 - + /obj/item/mech_equipment/shields/proc/toggle() - if(!aura) - return - aura.toggle() + + if(owner?.has_mob_modifier(/decl/mob_modifier/mechshield, source = src)) + owner.remove_mob_modifier(/decl/mob_modifier/mechshield, source = src) + else if(owner) + owner.add_mob_modifier(/decl/mob_modifier/mechshield, source = src) + + active = owner?.has_mob_modifier(/decl/mob_modifier/mechshield, source = src) + playsound(owner,'sound/weapons/flash.ogg',35,1) update_icon() - if(aura.active) + if(active) START_PROCESSING(SSobj, src) - else + else STOP_PROCESSING(SSobj, src) + passive_power_use = active ? 1 KILOWATTS : 0 owner.update_icon() +/obj/item/mech_equipment/shields/deactivate() + if(active) + toggle() + ..() + /obj/item/mech_equipment/shields/on_update_icon() . = ..() - if(!aura) - return - if(aura.active) + if(owner?.has_mob_modifier(/decl/mob_modifier/mechshield, source = src)) icon_state = "shield_droid_a" - else + else icon_state = "shield_droid" /obj/item/mech_equipment/shields/Process() if(charge >= max_charge) return if((world.time - last_recharge) < cooldown) - return + return var/obj/item/cell/cell = owner.get_cell() - - var/actual_required_power = Clamp(max_charge - charge, 0, charging_rate) - charge += cell.use(actual_required_power) + var/actual_required_power = clamp(max_charge - charge, 0, charging_rate) + + if(cell) + charge += cell.use(actual_required_power) /obj/item/mech_equipment/shields/get_hardpoint_status_value() return charge / max_charge -/obj/item/mech_equipment/shields/get_hardpoint_maptext() - return "[(aura && aura.active) ? "ONLINE" : "OFFLINE"]: [round((charge / max_charge) * 100)]%" - -/obj/aura/mechshield - icon = 'icons/mecha/shield.dmi' - name = "mechshield" - var/obj/item/mech_equipment/shields/shields = null - var/active = 0 - layer = ABOVE_HUMAN_LAYER - var/north_layer = MECH_UNDER_LAYER - plane = DEFAULT_PLANE - pixel_x = 8 - pixel_y = 4 - mouse_opacity = 0 - -/obj/aura/mechshield/Initialize(var/maploading, var/obj/item/mech_equipment/shields/holder) +/obj/item/mech_equipment/shields/get_hardpoint_maptext() + return "[owner?.has_mob_modifier(/decl/mob_modifier/mechshield, source = src) ? "ONLINE" : "OFFLINE"]: [round((charge / max_charge) * 100)]%" + +//Melee! As a general rule I would recommend using regular objects and putting logic in them. +/obj/item/mech_equipment/mounted_system/melee + abstract_type = /obj/item/mech_equipment/mounted_system/melee + origin_tech = @'{"combat":1,"materials":1,"engineering":1}' + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_UTILITY) + +/obj/item/tool/machete/mech + name = "mechete" + desc = "That thing is too big to be called a machete. Too big, too thick, too heavy, and too rough, it is more like a large hunk of iron." + w_class = ITEM_SIZE_GARGANTUAN + slot_flags = 0 + base_parry_chance = 0 //Irrelevant for exosuits, revise if this changes + max_health = ITEM_HEALTH_NO_DAMAGE //Else we need a whole system for replacement blades + _base_attack_force = 25 + +/obj/item/tool/machete/mech/apply_hit_effect(mob/living/target, mob/living/user, hit_zone) . = ..() - shields = holder - -/obj/aura/mechshield/added_to(var/mob/living/target) + if (.) + do_attack_effect(target, "smash") + if (target.mob_size < user.mob_size) //Damaging attacks overwhelm smaller mobs + target.throw_at(get_edge_target_turf(target,get_dir(user, target)),1, 1) + +/obj/item/tool/machete/mech/resolve_attackby(atom/A, mob/user, click_params) + //Case 1: Default, you are hitting something that isn't a mob. Just do whatever, this isn't dangerous or op. + if (!isliving(A)) + return ..() + + if (user.check_intent(I_FLAG_HARM)) + user.visible_message(SPAN_DANGER("\The [user] swings \the [src] at \the [A]!")) + playsound(user, 'sound/mecha/mechmove03.ogg', 35, 1) + return ..() + +/obj/item/tool/machete/mech/attack_self(mob/living/user) . = ..() - target.vis_contents += src - set_dir() - GLOB.dir_set_event.register(user, src, /obj/aura/mechshield/proc/update_dir) + if (!user.check_intent(I_FLAG_HARM)) + return + var/obj/item/mech_equipment/mounted_system/melee/machete/MC = loc + if (istype(MC)) + //SPIN BLADE ATTACK GO! + var/mob/living/exosuit/E = MC.owner + if (E) + E.setClickCooldown(1.35 SECONDS) + E.visible_message(SPAN_DANGER("\The [E] swings \the [src] back, preparing for an attack!"), blind_message = SPAN_DANGER("You hear the loud hissing of hydraulics!")) + playsound(E, 'sound/mecha/mechmove03.ogg', 35, 1) + if (do_after(E, 1.2 SECONDS, get_turf(user)) && E && MC) + for (var/mob/living/M in orange(1, E)) + use_on_mob(M, E, animate = FALSE) + E.spin(0.65 SECONDS, 0.125 SECONDS) + playsound(E, 'sound/mecha/mechturn.ogg', 40, 1) + +/obj/item/mech_equipment/mounted_system/melee/machete + icon_state = "mech_blade" + holding = /obj/item/tool/machete/mech + -/obj/aura/mechshield/proc/update_dir(var/user, var/old_dir, var/dir) - set_dir(dir) +//Ballistic shield +/obj/item/mech_equipment/ballistic_shield + name = "exosuit ballistic shield" + desc = "This formidable line of defense, sees widespread use in planetary peacekeeping operations and military formations alike." + icon_state = "mech_shield" + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_UTILITY) + origin_tech = @'{"materials":2,"engineering":2}' + var/last_push = 0 + var/chance = 60 //For attacks from the front, diminishing returns + var/last_max_block = 0 //Blocking during a perfect block window resets this, else there is an anti spam + var/max_block = 60 // Should block most things + var/blocking = FALSE -/obj/aura/mechshield/set_dir(new_dir) +/obj/item/mech_equipment/ballistic_shield/installed(mob/living/exosuit/_owner) . = ..() - if(dir == NORTH) - layer = north_layer - else layer = initial(layer) - -/obj/aura/mechshield/Destroy() - if(user) - GLOB.dir_set_event.unregister(user, src, /obj/aura/mechshield/proc/update_dir) - user.vis_contents -= src - shields = null + owner?.add_mob_modifier(/decl/mob_modifier/mech_ballistic, source = src) + +/obj/item/mech_equipment/ballistic_shield/uninstalled() + owner?.remove_mob_modifier(/decl/mob_modifier/mech_ballistic, source = src) . = ..() - -/obj/aura/mechshield/proc/toggle() - active = !active - update_icon() +/obj/item/mech_equipment/ballistic_shield/afterattack(atom/target, mob/living/user, inrange, params) + . = ..() + if (. && user.check_intent(I_FLAG_HARM) && (last_push + 1.6 SECONDS < world.time)) + owner.visible_message(SPAN_WARNING("\The [owner] retracts \the [src], preparing to push with it!"), blind_message = SPAN_WARNING("You hear the whine of hydraulics and feel a rush of air!")) + owner.setClickCooldown(0.7 SECONDS) + last_push = world.time + if (do_after(owner, 0.5 SECONDS, get_turf(owner)) && owner) + owner.visible_message(SPAN_WARNING("\The [owner] slams the area in front \the [src]!"), blind_message = SPAN_WARNING("You hear a loud hiss and feel a strong gust of wind!")) + playsound(src ,'sound/effects/bang.ogg',35,1) + var/list/turfs = list() + var/front = get_step(get_turf(owner), owner.dir) + turfs += front + turfs += get_step(front, turn(owner.dir, -90)) + turfs += get_step(front, turn(owner.dir, 90)) + for(var/turf/T in turfs) + for(var/mob/living/M in T) + if (!M.Adjacent(owner)) + continue + M.attack_generic(owner, (owner.arms ? owner.arms.melee_damage * 1.2 : 0), "slammed") + M.throw_at(get_edge_target_turf(owner ,owner.dir),5, 2) + do_attack_effect(T, "smash") - if(active) - flick("shield_raise", src) - else - flick("shield_drop", src) - +/obj/item/mech_equipment/ballistic_shield/attack_self(mob/user) + . = ..() + if (.) //FORM A SHIELD WALL! + if (last_max_block + 2 SECONDS < world.time) + owner.visible_message(SPAN_WARNING("\The [owner] raises \the [src], locking it in place!"), blind_message = SPAN_WARNING("You hear the whir of motors and scratching metal!")) + playsound(src ,'sound/effects/bamf.ogg',35,1) + owner.setClickCooldown(0.8 SECONDS) + blocking = TRUE + last_max_block = world.time + do_after(owner, 0.75 SECONDS, get_turf(user)) + blocking = FALSE + else + to_chat(user, SPAN_WARNING("You are not ready to block again!")) + +/obj/item/mech_equipment/ballistic_shield/proc/block_chance(damage, pen, atom/source, mob/attacker) + if (damage > max_block || pen > max_block) + return 0 + + var/effective_block = blocking ? chance * 1.5 : chance + + var/conscious_pilot_exists = FALSE + for (var/mob/living/pilot in owner.pilots) + if (!pilot.incapacitated()) + conscious_pilot_exists = TRUE + break + + if (!conscious_pilot_exists) + effective_block *= 0.5 //Who is going to block anything? + + //Bit copypasta but I am doing something different from normal shields + var/attack_dir = 0 + if (istype(source, /obj/item/projectile)) + var/obj/item/projectile/P = source + attack_dir = get_dir(get_turf(src), P.starting) + else if (attacker) + attack_dir = get_dir(get_turf(src), get_turf(attacker)) + else if (source) + attack_dir = get_dir(get_turf(src), get_turf(source)) + + if (attack_dir == turn(owner.dir, -90) || attack_dir == turn(owner.dir, 90)) + effective_block *= 0.8 + else if (attack_dir == turn(owner.dir, 180)) + effective_block = 0 + + return effective_block + +/obj/item/mech_equipment/ballistic_shield/proc/on_block_attack() + if (blocking) + //Reset timer for maximum chainblocks + last_max_block = 0 + +/obj/item/mech_equipment/flash + name = "exosuit flash" + icon_state = "mech_flash" + var/flash_min = 7 + var/flash_max = 9 + var/flash_range = 3 + restricted_hardpoints = list(HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) + restricted_software = list(MECH_SOFTWARE_WEAPONS) + active_power_use = 7 KILOWATTS + var/next_use = 0 + origin_tech = @'{"magnets":2,"combat":3}' -/obj/aura/mechshield/on_update_icon() +/obj/item/mech_equipment/flash/proc/area_flash() + playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + var/flash_time = (rand(flash_min,flash_max) - 1) + + var/obj/item/cell/cell = owner.get_cell() + cell.use(active_power_use * CELLRATE) + + for (var/mob/living/O in oviewers(flash_range, owner)) + if(istype(O)) + O.handle_flashed(flash_time, do_stun = FALSE) + +/obj/item/mech_equipment/flash/attack_self(mob/user) . = ..() - if(active) - icon_state = "shield" - else - icon_state = "shield_null" + if(.) + if(world.time < next_use) + to_chat(user, SPAN_WARNING("\The [src] is recharging!")) + return + next_use = world.time + 20 + area_flash() + owner.setClickCooldown(5) -/obj/aura/mechshield/bullet_act(var/obj/item/projectile/P, var/def_zone) - if(!active) - return - if(shields) - if(shields.charge) - P.damage = shields.stop_damage(P.damage) - user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash and crackle.")) - flick("shield_impact", src) - playsound(user,'sound/effects/basscannon.ogg',35,1) - //light up the night. - new /obj/effect/effect/smoke/illumination(user.loc, 5, 4, 1, "#ffffff") - if(P.damage <= 0) - return AURA_FALSE|AURA_CANCEL - - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, user) - spark_system.start() - playsound(loc, "sparks", 25, 1) - -/obj/aura/mechshield/hitby(atom/movable/M, var/datum/thrownthing/TT) +/obj/item/mech_equipment/flash/afterattack(atom/target, mob/living/user, inrange, params) . = ..() - if(!active) - return - if(shields.charge && TT.speed <= 5) - user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash briefly as they deflect \the [M].")) - flick("shield_impact", src) - playsound(user,'sound/effects/basscannon.ogg',10,1) - return AURA_FALSE|AURA_CANCEL - //Too fast! \ No newline at end of file + if(.) + if(world.time < next_use) + to_chat(user, SPAN_WARNING("\The [src] is recharging!")) + return + var/mob/living/O = target + owner.setClickCooldown(5) + next_use = world.time + 15 + + if(istype(O)) + + playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + var/flash_time = (rand(flash_min,flash_max)) + + var/obj/item/cell/cell = owner.get_cell() + cell.use(active_power_use * CELLRATE) + + O.handle_flashed(flash_time) diff --git a/code/modules/mechs/equipment/combat_projectile.dm b/code/modules/mechs/equipment/combat_projectile.dm new file mode 100644 index 000000000000..f71d5a2a5e59 --- /dev/null +++ b/code/modules/mechs/equipment/combat_projectile.dm @@ -0,0 +1,170 @@ +/obj/item/mech_equipment/mounted_system/projectile/attackby(var/obj/item/used_item, var/mob/user) + var/obj/item/gun/projectile/automatic/A = holding + if(!istype(A)) + return FALSE + if(istype(used_item, /obj/item/crowbar)) + A.unload_ammo(user) + to_chat(user, SPAN_NOTICE("You remove the ammo magazine from \the [src].")) + else if(istype(used_item, A.magazine_type)) + A.load_ammo(used_item, user) + to_chat(user, SPAN_NOTICE("You load the ammo magazine into \the [src].")) + return TRUE + +/obj/item/mech_equipment/mounted_system/projectile/attack_self(var/mob/user) + . = ..() + if(. && holding) + var/obj/item/gun/M = holding + return M.switch_firemodes() + +/obj/item/gun/projectile/automatic/get_hardpoint_status_value() + if(!isnull(ammo_magazine)) + return ammo_magazine.get_stored_ammo_count() + +/obj/item/gun/projectile/automatic/get_hardpoint_maptext() + if(!isnull(ammo_magazine)) + return "[ammo_magazine.get_stored_ammo_count()]/[ammo_magazine.max_ammo]" + return 0 + +//Weapons below this. +/obj/item/mech_equipment/mounted_system/projectile + name = "mounted submachine gun" + icon_state = "mech_ballistic" + holding = /obj/item/gun/projectile/automatic/smg/mech + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_WEAPONS) + origin_tech = @'{"programming":4,"combat":6,"engineering":5}' + +/obj/item/gun/projectile/automatic/smg/mech + magazine_type = /obj/item/ammo_magazine/mech/smg_top + allowed_magazines = /obj/item/ammo_magazine/mech/smg_top + one_hand_penalty = 0 + has_safety = FALSE + manual_unload = FALSE + firemodes = list( + list(mode_name="semi auto", burst=1, fire_delay=null, one_hand_penalty=0, burst_accuracy=null, dispersion=null), + list(mode_name="3-round bursts", burst=3, fire_delay=null, one_hand_penalty=0, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 1.6, 2.4, 2.4), autofire_enabled=0), + list(mode_name="short bursts", burst=5, fire_delay=null, one_hand_penalty=0, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(1.6, 1.6, 2.0, 2.0, 2.4), autofire_enabled=0), + list(mode_name="full auto", burst=1, fire_delay=null, burst_delay=1, one_hand_penalty=0, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(1.6, 1.6, 2.0, 2.0, 2.4), autofire_enabled=1) + ) + +/obj/item/mech_equipment/mounted_system/projectile/assault_rifle + name = "mounted assault rifle" + icon_state = "mech_ballistic2" + holding = /obj/item/gun/projectile/automatic/assault_rifle/mech + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_WEAPONS) + origin_tech = @'{"programming":4,"combat":8,"engineering":6}' + +/obj/item/gun/projectile/automatic/assault_rifle/mech + magazine_type = /obj/item/ammo_magazine/mech/rifle + allowed_magazines = /obj/item/ammo_magazine/mech/rifle + one_hand_penalty = 0 + has_safety = FALSE + manual_unload = FALSE + firemodes = list( + list(mode_name="semi auto", burst=1, fire_delay=null, one_hand_penalty=0, burst_accuracy=null, dispersion=null, autofire_enabled=0), + list(mode_name="3-round bursts", burst=3, fire_delay=null, one_hand_penalty=0, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), autofire_enabled=0), + list(mode_name="full auto", burst=1, fire_delay=null, burst_delay=1, one_hand_penalty=0, burst_accuracy = list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), autofire_enabled=1) + ) + +/obj/item/mech_equipment/mounted_system/projectile/machine + name = "mounted machine gun" + icon_state = "mech_machine_gun" + holding = /obj/item/gun/projectile/automatic/machine/mech + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_WEAPONS) + origin_tech = @'{"programming":4,"combat":8,"engineering":6}' + +/obj/item/gun/projectile/automatic/machine/mech + magazine_type = /obj/item/ammo_magazine/mech/rifle/drum + allowed_magazines = /obj/item/ammo_magazine/mech/rifle/drum + one_hand_penalty = 0 + has_safety = FALSE + manual_unload = FALSE + +// Magazines below this. + +/obj/item/ammo_magazine/mech/attack_self(mob/user) + to_chat(user, SPAN_WARNING("It's pretty hard to extract ammo from a magazine that fits on a mech. You'll have to do it one round at a time.")) + return + +/obj/item/ammo_magazine/mech/smg_top + name = "large 7mm magazine" + desc = "A large magazine for a mech's gun. Looks way too big for a normal gun." + icon_state = "smg_top" + mag_type = MAGAZINE + ammo_type = /obj/item/ammo_casing/pistol/small + material = /decl/material/solid/metal/steel + caliber = CALIBER_PISTOL_SMALL + max_ammo = 90 + +/obj/item/ammo_magazine/mech/rifle + name = "large assault rifle magazine" + icon_state = "assault_rifle" + mag_type = MAGAZINE + caliber = CALIBER_RIFLE + material = /decl/material/solid/metal/steel + ammo_type = /obj/item/ammo_casing/rifle + max_ammo = 100 + +/obj/item/ammo_magazine/mech/rifle/drum + name = "large machine gun magazine" + icon_state = "drum" + mag_type = MAGAZINE + caliber = CALIBER_RIFLE + material = /decl/material/solid/metal/steel + ammo_type = /obj/item/ammo_casing/rifle + max_ammo = 300 + +// Handling for auto-fire mechanic +/mob/living/exosuit/can_autofire(obj/item/gun/autofiring, atom/autofiring_at) + if(autofiring.autofiring_by != src) + return FALSE + var/client/C = current_user ? current_user.client : client + + if(!C || !C.mob || C.mob.incapacitated()) + return FALSE + + if(!(autofiring_at in view(C.view, src))) + return FALSE + if(!(get_dir(src, autofiring_at) & dir)) + return FALSE + if(!(autofiring in selected_system)) // Make sure the gun is still selected. + return FALSE + return TRUE + +/obj/item/mech_equipment/mounted_system/projectile/MouseDownInteraction(atom/object, location, control, params, mob/user) + var/obj/item/gun/gun = holding + if(istype(object) && (isturf(object) || isturf(object.loc)) && istype(gun)) + if(user != src) + if(!user.incapacitated()) + gun.set_autofire(object, owner, FALSE) // Passed gun-firer is still the exosuit since all checks need to be done on the suit. + owner.current_user = user + else + if(!owner.incapacitated()) + gun.set_autofire(object, owner, FALSE) + owner.current_user = null + +/obj/item/mech_equipment/mounted_system/projectile/MouseUpInteraction(atom/object, location, control, params, mob/user) + var/obj/item/gun/gun = holding + if(istype(gun)) + gun.clear_autofire() + if(owner) // In case the owning exosuit has been gibbed etc. + owner.current_user = null + +/obj/item/mech_equipment/mounted_system/projectile/MouseDragInteraction(atom/src_object, atom/over_object, src_location, over_location, src_control, over_control, params, mob/user) + var/obj/item/gun/gun = holding + if(!owner) + gun?.clear_autofire() + return + if(!istype(gun)) + owner?.current_user = null + return + if(istype(over_object) && (isturf(over_object) || isturf(over_object.loc))) + if(user.incapacitated() || (user != owner && user != owner.current_user)) + gun.clear_autofire() + return + gun.set_autofire(over_object, owner, FALSE) + return + + gun.clear_autofire() \ No newline at end of file diff --git a/code/modules/mechs/equipment/engineering.dm b/code/modules/mechs/equipment/engineering.dm index b0a3597e8e53..607226f683e0 100644 --- a/code/modules/mechs/equipment/engineering.dm +++ b/code/modules/mechs/equipment/engineering.dm @@ -1,11 +1,12 @@ /obj/item/mech_equipment/mounted_system/rcd icon_state = "mech_rcd" - holding_type = /obj/item/rcd/mounted + holding = /obj/item/rcd/mounted + origin_tech = @'{"engineering":4,"materials":3,"powerstorage":1}' restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) restricted_software = list(MECH_SOFTWARE_ENGINEERING) material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) @@ -13,31 +14,175 @@ /obj/item/rcd/mounted/get_hardpoint_maptext() var/obj/item/mech_equipment/mounted_system/MS = loc if(istype(MS) && MS.owner) - var/obj/item/cell/C = MS.owner.get_cell() - if(istype(C)) - return "[round(C.charge)]/[round(C.maxcharge)]" + var/obj/item/cell/cell = MS.owner.get_cell() + if(istype(cell)) + return "[round(cell.charge)]/[round(cell.maxcharge)]" return null /obj/item/rcd/mounted/get_hardpoint_status_value() var/obj/item/mech_equipment/mounted_system/MS = loc if(istype(MS) && MS.owner) - var/obj/item/cell/C = MS.owner.get_cell() - if(istype(C)) - return C.charge/C.maxcharge + var/obj/item/cell/cell = MS.owner.get_cell() + if(istype(cell)) + return cell.charge/cell.maxcharge return null -/obj/item/extinguisher/mech - max_water = 4000 //Good is gooder +/obj/item/chems/spray/extinguisher/mech + chem_volume = 4000 //Good is gooder icon_state = "mech_exting" -/obj/item/extinguisher/mech/get_hardpoint_maptext() - return "[reagents.total_volume]/[max_water]" +/obj/item/chems/spray/extinguisher/mech/get_hardpoint_maptext() + return "[REAGENT_TOTAL_VOLUME(reagents)]/[REAGENT_MAXIMUM_VOLUME(reagents)]" -/obj/item/extinguisher/mech/get_hardpoint_status_value() - return reagents.total_volume/max_water +/obj/item/chems/spray/extinguisher/mech/get_hardpoint_status_value() + return REAGENT_TOTAL_VOLUME(reagents)/REAGENT_MAXIMUM_VOLUME(reagents) /obj/item/mech_equipment/mounted_system/extinguisher icon_state = "mech_exting" - holding_type = /obj/item/extinguisher/mech + holding = /obj/item/chems/spray/extinguisher/mech restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) restricted_software = list(MECH_SOFTWARE_ENGINEERING) + origin_tech = @'{"engineering":1,"materials":1}' + +/obj/item/mech_equipment/atmos_shields + icon_state = "mech_atmoshield_off" + name = "exosuit airshield" + desc = "A 'Zephyros' portable Atmospheric Isolation and Retention Screen. It keeps air where it should be... most of the time. Press ctrl-click to switch modes." + restricted_hardpoints = list(HARDPOINT_BACK) + restricted_software = list(MECH_SOFTWARE_ENGINEERING) + equipment_delay = 0.25 SECONDS + origin_tech = @'{"engineering":2,"powerstorage":2,"materials":3}' + var/list/segments + var/current_mode = 0 //0 barrier, 1 bubble + var/shield_range = 2 + +/obj/item/mech_equipment/atmos_shields/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/mech_equipment/adjust_atmos_shields) + +/decl/interaction_handler/mech_equipment/adjust_atmos_shields + name = "Adjust Atmos Shields" + expected_target_type = /obj/item/mech_equipment/atmos_shields + examine_desc = "adjust the atmos shields" + +/decl/interaction_handler/mech_equipment/adjust_atmos_shields/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/mech_equipment/atmos_shields/shields = target + if (shields.active) + to_chat(user, SPAN_WARNING("You cannot modify the projection mode while the shield is active.")) + else + shields.current_mode = !shields.current_mode + to_chat(user, SPAN_NOTICE("You set the shields to [shields.current_mode ? "bubble" : "barrier"] mode.")) + return TRUE + +/obj/effect/mech_shield + name = "energy shield" + desc = "A thin energy shield. It doesn't look like it could stop much." + icon = 'icons/obj/machines/shielding.dmi' + icon_state = "shield_normal" + anchored = TRUE + layer = ABOVE_HUMAN_LAYER + density = FALSE + invisibility = INVISIBILITY_NONE + atmos_canpass = CANPASS_NEVER + var/obj/item/mech_equipment/atmos_shields/shields + color = COLOR_SABER_BLUE + +/obj/effect/mech_shield/Initialize() + . = ..() + set_light(0.8, 0.1, 1, 2, COLOR_SABER_BLUE) + update_nearby_tiles(need_rebuild=1) + +/obj/effect/mech_shield/Destroy() + if(shields) + if(LAZYLEN(shields.segments)) + shields.segments -= src + shields = null + atmos_canpass = CANPASS_ALWAYS + update_nearby_tiles(need_rebuild=1) + + . = ..() + +/obj/item/mech_equipment/atmos_shields/get_hardpoint_maptext() + return "[current_mode ? "BUBBLE" : "BARRIER"]\n[active ? "ONLINE" : "OFFLINE"]" + +/obj/item/mech_equipment/atmos_shields/proc/on_moved() + if(active) + deactivate() + +/obj/item/mech_equipment/atmos_shields/proc/on_turned() + if(active && !current_mode) + deactivate() + +/obj/item/mech_equipment/atmos_shields/proc/activate() + owner.visible_message(SPAN_WARNING("\The [src] starts glowing as it becomes energized!"), blind_message = SPAN_WARNING("You hear the crackle of electricity.")) + owner.setClickCooldown(2.5 SECONDS) + if (do_after(owner, 0.5 SECONDS, get_turf(owner)) && owner) + owner.visible_message(SPAN_WARNING("The air shimmers as energy shields form in front of \the [owner]!")) + playsound(src ,'sound/effects/phasein.ogg',35,1) + active = TRUE + var/list/turfs = list() + + if(current_mode) //Generate a bubble + var/turf/T = null + for (var/x_offset = -shield_range +1; x_offset <= shield_range -1; x_offset++) + T = locate(owner.x + x_offset, owner.y - shield_range, owner.z) + if(T) + turfs += T + T = locate(owner.x + x_offset, owner.y + 2, owner.z) + if(T) + turfs += T + + for (var/y_offset = -shield_range+1; y_offset < shield_range; y_offset++) + T = locate(owner.x - shield_range, owner.y + y_offset, owner.z) + if(T) + turfs += T + T = locate(owner.x + shield_range, owner.y + y_offset, owner.z) + if(T) + turfs += T + else + var/front = get_step(get_turf(owner), owner.dir) + turfs += front + turfs += get_step(front, turn(owner.dir, -90)) + turfs += get_step(front, turn(owner.dir, 90)) + + segments = list() + for(var/turf/T in turfs) + var/obj/effect/mech_shield/MS = new(T) + if(istype(MS)) + MS.shields = src + segments += MS + events_repository.register(/decl/observ/moved, MS, src, PROC_REF(on_moved)) + + passive_power_use = 0.8 KILOWATTS * segments.len + + update_icon() + owner.update_icon() + events_repository.register(/decl/observ/moved, owner, src, PROC_REF(on_moved)) + events_repository.register(/decl/observ/dir_set, owner, src, PROC_REF(on_turned)) + +/obj/item/mech_equipment/atmos_shields/on_update_icon() + . = ..() + icon_state = "mech_atmoshield[active ? "_on" : "_off"]" + +/obj/item/mech_equipment/atmos_shields/deactivate() + for(var/obj/effect/mech_shield/MS in segments) + if(istype(MS)) + events_repository.unregister(/decl/observ/moved, MS, src, PROC_REF(on_moved)) + if(segments.len) + owner.visible_message(SPAN_WARNING("The energy shields in front of \the [owner] disappear!")) + QDEL_NULL_LIST(segments) + passive_power_use = 0 + events_repository.unregister(/decl/observ/moved, owner, src, PROC_REF(on_moved)) + events_repository.unregister(/decl/observ/dir_set, owner, src, PROC_REF(on_turned)) + . = ..() + update_icon() + owner.update_icon() + +/obj/item/mech_equipment/atmos_shields/attack_self(mob/user) + . = ..() + if(.) + if(active) + deactivate() + else + activate() + to_chat(user, SPAN_NOTICE("You toggle \the [src] [active ? "on" : "off"]")) diff --git a/code/modules/mechs/equipment/medical.dm b/code/modules/mechs/equipment/medical.dm index 7a6ea5c901c8..f18d56ea2e0e 100644 --- a/code/modules/mechs/equipment/medical.dm +++ b/code/modules/mechs/equipment/medical.dm @@ -1,12 +1,12 @@ /obj/item/mech_equipment/sleeper name = "\improper exosuit sleeper" - desc = "An exosuit-mounted sleeper designed to mantain patients stabilized on their way to medical facilities." + desc = "An exosuit-mounted sleeper designed to maintain patients stabilized on their way to medical facilities." icon_state = "mech_sleeper" restricted_hardpoints = list(HARDPOINT_BACK) restricted_software = list(MECH_SOFTWARE_MEDICAL) equipment_delay = 30 //don't spam it on people pls active_power_use = 0 //Usage doesn't really require power. We don't want people stuck inside - origin_tech = "{'programming':2,'biotech':3}" + origin_tech = @'{"programming":2,"biotech":3}' passive_power_use = 1.5 KILOWATTS var/obj/machinery/sleeper/mounted/sleeper = null @@ -22,23 +22,24 @@ /obj/item/mech_equipment/sleeper/uninstalled() . = ..() - sleeper.go_out() + sleeper?.go_out() /obj/item/mech_equipment/sleeper/attack_self(var/mob/user) . = ..() if(.) sleeper.ui_interact(user) -/obj/item/mech_equipment/sleeper/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/chems/glass)) - sleeper.attackby(I, user) - else return ..() +/obj/item/mech_equipment/sleeper/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/chems/glass)) + return sleeper.attackby(used_item, user) + else + return ..() /obj/item/mech_equipment/sleeper/afterattack(var/atom/target, var/mob/living/user, var/inrange, var/params) . = ..() if(.) if(ishuman(target) && !sleeper.occupant) - owner.visible_message(SPAN_NOTICE("\The [src] is lowered down to load [target]")) + owner.visible_message(SPAN_NOTICE("\The [src] is lowered down to load [target].")) sleeper.go_in(target, user) else to_chat(user, SPAN_WARNING("You cannot load that in!")) @@ -48,23 +49,29 @@ /obj/machinery/sleeper/mounted name = "\improper mounted sleeper" - density = 0 - anchored = 0 + density = FALSE + anchored = FALSE idle_power_usage = 0 active_power_usage = 0 //It'd be hard to handle, so for now all power is consumed by mech sleeper object stasis_power = 0 interact_offline = TRUE stat_immune = NOPOWER + // Spawned inside a mech component, not built as a machine. + construct_state = null + base_type = /obj/machinery/sleeper/mounted /obj/machinery/sleeper/mounted/standard/Initialize(mapload, d, populate_parts) . = ..() - add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/adrenaline()) + add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/adrenaline()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/sedatives()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/painkillers()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/antitoxins()) add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/oxy_meds()) -/obj/machinery/sleeper/mounted/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.mech_state) +/obj/machinery/sleeper/mounted/DefaultTopicState() + return global.mech_topic_state + +/obj/machinery/sleeper/mounted/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.mech_topic_state) . = ..() /obj/machinery/sleeper/mounted/nano_host() @@ -74,14 +81,14 @@ return null //You cannot modify these, it'd probably end with something in nullspace. In any case basic meds are plenty for an ambulance -/obj/machinery/sleeper/mounted/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/chems/glass)) - if(!user.unEquip(I, src)) - return - +/obj/machinery/sleeper/mounted/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/chems/glass)) + if(!user.try_unequip(used_item, src)) + return TRUE if(beaker) - beaker.forceMove(get_turf(src)) + user.put_in_hands(beaker) user.visible_message("\The [user] removes \the [beaker] from \the [src].", "You remove \the [beaker] from \the [src].") - beaker = I - user.visible_message("\The [user] adds \a [I] to \the [src].", "You add \a [I] to \the [src].") - + beaker = used_item + user.visible_message("\The [user] adds \a [used_item] to \the [src].", "You add \a [used_item] to \the [src].") + return TRUE + return FALSE diff --git a/code/modules/mechs/equipment/utility.dm b/code/modules/mechs/equipment/utility.dm index 3b0ac46e14ee..37b955a8ddfe 100644 --- a/code/modules/mechs/equipment/utility.dm +++ b/code/modules/mechs/equipment/utility.dm @@ -4,28 +4,31 @@ icon_state = "mech_clamp" restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) restricted_software = list(MECH_SOFTWARE_UTILITY) - origin_tech = "{'materials':2,'engineering':2}" + origin_tech = @'{"materials":2,"engineering":2}' var/carrying_capacity = 5 var/list/obj/carrying = list() /obj/item/mech_equipment/clamp/resolve_attackby(atom/A, mob/user, click_params) - if(istype(A, /obj/structure/closet) && owner) + if(owner) return 0 return ..() /obj/item/mech_equipment/clamp/attack_hand(mob/user) - if(owner && LAZYISIN(owner.pilots, user)) - if(!owner.hatch_closed && length(carrying)) - var/obj/chosen_obj = input(user, "Choose an object to grab.", "Clamp Claw") as null|anything in carrying - if(!chosen_obj) - return - if(!do_after(user, 20, owner)) return - if(owner.hatch_closed || !chosen_obj) return - if(user.put_in_active_hand(chosen_obj)) - owner.visible_message(SPAN_NOTICE("\The [user] carefully grabs \the [chosen_obj] from \the [src].")) - playsound(src, 'sound/mecha/hydraulic.ogg', 50, 1) - carrying -= chosen_obj - . = ..() + if(!owner || !LAZYISIN(owner.pilots, user) || owner.hatch_closed || !length(carrying) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + // Filter out non-items. + var/list/carrying_items = list() + for(var/obj/item/thing in carrying) + carrying_items += thing + if(!length(carrying_items)) + return TRUE + var/obj/item/chosen_obj = input(user, "Choose an object to grab.", "Clamp Claw") as null|anything in carrying_items + if(chosen_obj && do_after(user, 20, owner) && !owner.hatch_closed && !QDELETED(chosen_obj) && (chosen_obj in carrying)) + owner.visible_message(SPAN_NOTICE("\The [user] carefully grabs \the [chosen_obj] from \the [src].")) + playsound(src, 'sound/mecha/hydraulic.ogg', 50, 1) + carrying -= chosen_obj + user.put_in_active_hand(chosen_obj) + return TRUE /obj/item/mech_equipment/clamp/afterattack(var/atom/target, var/mob/living/user, var/inrange, var/params) . = ..() @@ -43,12 +46,67 @@ return if(O.anchored) + //Special door handling + if(istype(O, /obj/machinery/door/firedoor)) + var/obj/machinery/door/firedoor/FD = O + if(FD.blocked) + FD.visible_message(SPAN_DANGER("\The [owner] begins prying on \the [FD]!")) + if(do_after(owner,10 SECONDS,FD) && FD.blocked) + playsound(FD, 'sound/effects/meteorimpact.ogg', 100, 1) + playsound(FD, 'sound/machines/airlock_creaking.ogg', 100, 1) + FD.blocked = FALSE + addtimer(CALLBACK(FD, TYPE_PROC_REF(/obj/machinery/door/firedoor, open), TRUE), 0) + FD.set_broken(TRUE) + FD.visible_message(SPAN_WARNING("\The [owner] tears \the [FD] open!")) + else + FD.visible_message(SPAN_DANGER("\The [owner] begins forcing \the [FD]!")) + if(do_after(owner, 4 SECONDS,FD) && !FD.blocked) + playsound(FD, 'sound/machines/airlock_creaking.ogg', 100, 1) + if(FD.density) + FD.visible_message(SPAN_DANGER("\The [owner] forces \the [FD] open!")) + addtimer(CALLBACK(FD, TYPE_PROC_REF(/obj/machinery/door/firedoor, open), TRUE), 0) + else + FD.visible_message(SPAN_WARNING("\The [owner] forces \the [FD] closed!")) + addtimer(CALLBACK(FD, TYPE_PROC_REF(/obj/machinery/door/firedoor, close), TRUE), 0) + return + else if(istype(O, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/AD = O + if(!AD.operating && !AD.locked) + if(AD.welded) + AD.visible_message(SPAN_DANGER("\The [owner] begins prying on \the [AD]!")) + if(do_after(owner, 15 SECONDS,AD) && !AD.locked) + AD.welded = FALSE + AD.update_icon() + playsound(AD, 'sound/effects/meteorimpact.ogg', 100, 1) + playsound(AD, 'sound/machines/airlock_creaking.ogg', 100, 1) + AD.visible_message(SPAN_DANGER("\The [owner] tears \the [AD] open!")) + addtimer(CALLBACK(AD, TYPE_PROC_REF(/obj/machinery/door/airlock, open), TRUE), 0) + AD.set_broken(TRUE) + return + else + AD.visible_message(SPAN_DANGER("\The [owner] begins forcing \the [AD]!")) + if((AD.is_broken(NOPOWER) || do_after(owner, 5 SECONDS,AD)) && !(AD.operating || AD.welded || AD.locked)) + playsound(AD, 'sound/machines/airlock_creaking.ogg', 100, 1) + if(AD.density) + addtimer(CALLBACK(AD, TYPE_PROC_REF(/obj/machinery/door/airlock, open), TRUE), 0) + if(!AD.is_broken(NOPOWER)) + AD.set_broken(TRUE) + AD.visible_message(SPAN_DANGER("\The [owner] forces \the [AD] open!")) + else + addtimer(CALLBACK(AD, TYPE_PROC_REF(/obj/machinery/door/airlock, close), TRUE), 0) + if(!AD.is_broken(NOPOWER)) + AD.set_broken(TRUE) + AD.visible_message(SPAN_DANGER("\The [owner] forces \the [AD] closed!")) + if(AD.locked) + to_chat(user, SPAN_NOTICE("The airlock's bolts prevent it from being forced.")) + return + to_chat(user, SPAN_WARNING("\The [target] is firmly secured.")) return owner.visible_message(SPAN_NOTICE("\The [owner] begins loading \the [O].")) if(do_after(owner, 20, O, 0, 1)) - if(O in carrying || O.buckled_mob || O.anchored || (locate(/mob/living) in O)) //Repeat checks + if((O in carrying) || O.buckled_mob || O.anchored || (locate(/mob/living) in O)) //Repeat checks return if(length(carrying) >= carrying_capacity) to_chat(user, SPAN_WARNING("\The [src] is fully loaded!")) @@ -59,9 +117,9 @@ playsound(src, 'sound/mecha/hydraulic.ogg', 50, 1) //attacking - Cannot be carrying something, cause then your clamp would be full - else if(istype(target,/mob/living)) + else if(isliving(target)) var/mob/living/M = target - if(user.a_intent == I_HURT) + if(user.check_intent(I_FLAG_HARM)) admin_attack_log(user, M, "attempted to clamp [M] with [src] ", "Was subject to a clamping attempt.", ", using \a [src], attempted to clamp") owner.setClickCooldown(owner.arms ? owner.arms.action_delay * 3 : 30) //This is an inefficient use of your powers if(prob(33)) @@ -81,11 +139,9 @@ if(.) drop_carrying(user, TRUE) -/obj/item/mech_equipment/clamp/CtrlClick(mob/user) - if(owner) - drop_carrying(user, FALSE) - else - ..() +/obj/item/mech_equipment/clamp/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/mech_equipment/clamp) /obj/item/mech_equipment/clamp/proc/drop_carrying(var/mob/user, var/choose_object) if(!length(carrying)) @@ -137,41 +193,64 @@ carrying -= load . = ..() +/decl/interaction_handler/mech_equipment/clamp + name = "Release Clamp" + expected_target_type = /obj/item/mech_equipment/clamp + examine_desc = "release $TARGET_THEM$" + +/decl/interaction_handler/mech_equipment/clamp/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/mech_equipment/clamp/clamp = target + clamp.drop_carrying(user, FALSE) + // A lot of this is copied from floodlights. /obj/item/mech_equipment/light name = "floodlight" desc = "An exosuit-mounted light." icon_state = "mech_floodlight" item_state = "mech_floodlight" - restricted_hardpoints = list(HARDPOINT_HEAD) + restricted_hardpoints = list(HARDPOINT_HEAD, HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) mech_layer = MECH_INTERMEDIATE_LAYER + origin_tech = @'{"materials":1,"engineering":1}' var/on = 0 - var/l_max_bright = 0.9 - var/l_inner_range = 1 - var/l_outer_range = 6 - origin_tech = "{'materials':1,'engineering':1}" + var/l_power = 0.9 + var/l_range = 6 + +/obj/item/mech_equipment/light/installed(mob/living/exosuit/_owner) + . = ..() + update_icon() /obj/item/mech_equipment/light/attack_self(var/mob/user) . = ..() if(.) - on = !on + toggle() to_chat(user, "You switch \the [src] [on ? "on" : "off"].") - update_icon() - owner.update_icon() + +/obj/item/mech_equipment/light/proc/toggle() + on = !on + update_icon() + owner.update_icon() + active = on + passive_power_use = on ? 0.1 KILOWATTS : 0 + +/obj/item/mech_equipment/light/deactivate() + if(on) + toggle() + ..() /obj/item/mech_equipment/light/on_update_icon() + . = ..() if(on) icon_state = "[initial(icon_state)]-on" - set_light(l_max_bright, l_inner_range, l_outer_range) + set_light(l_range, l_power) else icon_state = "[initial(icon_state)]" set_light(0, 0) -/obj/item/mech_equipment/light/uninstalled() - on = FALSE - update_icon() - . = ..() + //Check our layers + if(owner && (owner.hardpoints[HARDPOINT_HEAD] == src)) + mech_layer = MECH_INTERMEDIATE_LAYER + else mech_layer = initial(mech_layer) #define CATAPULT_SINGLE 1 #define CATAPULT_AREA 2 @@ -179,13 +258,13 @@ /obj/item/mech_equipment/catapult name = "gravitational catapult" desc = "An exosuit-mounted gravitational catapult." - icon_state = "mech_clamp" + icon_state = "mech_wormhole" restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) restricted_software = list(MECH_SOFTWARE_UTILITY) var/mode = CATAPULT_SINGLE var/atom/movable/locked equipment_delay = 30 //Stunlocks are not ideal - origin_tech = "{'materials':4,'engineering':4,'magnets':4}" + origin_tech = @'{"materials":4,"engineering":4,"magnets":4}' require_adjacent = FALSE /obj/item/mech_equipment/catapult/get_hardpoint_maptext() @@ -226,9 +305,9 @@ log_and_message_admins("used [src] to throw [locked] at [target].", user, owner.loc) locked = null - var/obj/item/cell/C = owner.get_cell() - if(istype(C)) - C.use(active_power_use * CELLRATE) + var/obj/item/cell/cell = owner.get_cell() + if(istype(cell)) + cell.use(active_power_use * CELLRATE) else locked = null @@ -247,9 +326,9 @@ log_and_message_admins("used [src]'s area throw on [target].", user, owner.loc) - var/obj/item/cell/C = owner.get_cell() - if(istype(C)) - C.use(active_power_use * CELLRATE * 2) //bit more expensive to throw all + var/obj/item/cell/cell = owner.get_cell() + if(istype(cell)) + cell.use(active_power_use * CELLRATE * 2) //bit more expensive to throw all @@ -262,25 +341,35 @@ desc = "A replaceable drill head usually used in exosuit drills." icon = 'icons/obj/items/tool/drill_head.dmi' icon_state = "drill_head" + material = /decl/material/solid/metal/steel var/durability = 0 -/obj/item/drill_head/proc/get_durability_percentage() - return (durability * 100) / (2 * material.integrity) +/obj/item/drill_head/proc/get_percent_durability() + return round((durability / material.integrity) * 50) -/obj/item/drill_head/examine(mob/user, distance) +/obj/item/drill_head/proc/get_visible_durability() + switch (get_percent_durability()) + if (95 to INFINITY) . = "shows no wear" + if (75 to 95) . = "shows some wear" + if (50 to 75) . = "is fairly worn" + if (10 to 50) . = "is very worn" + else . = "looks close to breaking" + +/obj/item/drill_head/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - var/percentage = get_durability_percentage() - var/descriptor = "looks close to breaking" - if(percentage > 10) - descriptor = "is very worn" - if(percentage > 50) - descriptor = "is fairly worn" - if(percentage > 75) - descriptor = "shows some signs of wear" - if(percentage > 95) - descriptor = "shows no wear" - - to_chat(user, "It [descriptor].") + . += "It [get_visible_durability()]." + +/obj/item/drill_head/steel + material = /decl/material/solid/metal/steel + +/obj/item/drill_head/titanium + material = /decl/material/solid/metal/titanium + +/obj/item/drill_head/plasteel + material = /decl/material/solid/metal/plasteel + +/obj/item/drill_head/diamond + material = /decl/material/solid/gemstone/diamond /obj/item/drill_head/Initialize() . = ..() @@ -296,11 +385,12 @@ //Drill can have a head var/obj/item/drill_head/drill_head - origin_tech = "{'materials':2,'engineering':2}" + origin_tech = @'{"materials":2,"engineering":2}' /obj/item/mech_equipment/drill/Initialize() . = ..() - drill_head = new /obj/item/drill_head(src, /decl/material/solid/metal/steel) //You start with a basic steel head + if (ispath(drill_head)) + drill_head = new drill_head(src) /obj/item/mech_equipment/drill/attack_self(var/mob/user) . = ..() @@ -311,121 +401,376 @@ /obj/item/mech_equipment/drill/get_hardpoint_maptext() if(drill_head) - return "Integrity: [round(drill_head.get_durability_percentage())]%" + return "Integrity: [drill_head.get_percent_durability()]%" return -/obj/item/mech_equipment/drill/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/drill_head)) - var/obj/item/drill_head/DH = W - if(!user.unEquip(DH)) - return - if(drill_head) - visible_message(SPAN_NOTICE("\The [user] detaches the [drill_head] mounted on the [src].")) - drill_head.forceMove(get_turf(src)) - DH.forceMove(src) - drill_head = DH - to_chat(user, SPAN_NOTICE("You install \the [drill_head] in \the [src].")) - visible_message(SPAN_NOTICE("\The [user] mounts the [drill_head] on the [src].")) - return +/obj/item/mech_equipment/drill/get_examine_strings(mob/user, distance, infix, suffix) . = ..() + if (drill_head) + . += "It has a[distance > 3 ? "" : " [drill_head.material.name]"] drill head installed." + if (distance < 4) + . += "The drill head [drill_head.get_visible_durability()]." + else + . += "It does not have a drill head installed." -/obj/item/mech_equipment/drill/afterattack(var/atom/target, var/mob/living/user, var/inrange, var/params) +/obj/item/mech_equipment/drill/proc/attach_head(obj/item/drill_head/DH, mob/user) + if (user && !user.try_unequip(DH)) + return + if (drill_head) + visible_message(SPAN_NOTICE("\The [user] detaches \the [drill_head] mounted on \the [src].")) + drill_head.dropInto(get_turf(src)) + user.visible_message(SPAN_NOTICE("\The [user] mounts \the [drill_head] on \the [src].")) + DH.forceMove(src) + drill_head = DH + +/obj/item/mech_equipment/drill/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/drill_head)) + attach_head(used_item, user) + return TRUE . = ..() - if(.) - if(isobj(target)) - var/obj/target_obj = target - if(target_obj.unacidable) - return - if(istype(target,/obj/item/drill_head)) - var/obj/item/drill_head/DH = target - if(drill_head) - owner.visible_message(SPAN_NOTICE("\The [owner] detaches the [drill_head] mounted on the [src].")) - drill_head.forceMove(owner.loc) - DH.forceMove(src) - drill_head = DH - owner.visible_message(SPAN_NOTICE("\The [owner] mounts the [drill_head] on the [src].")) - playsound(src, 'sound/weapons/circsawhit.ogg', 50, 1) + +/obj/item/mech_equipment/drill/proc/scoop_ore(at_turf) + if (!owner) + return + for (var/hardpoint in owner.hardpoints) + var/obj/item/item = owner.hardpoints[hardpoint] + if (!istype(item)) + continue + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in item + if (!ore_box) + continue + for(var/obj/item/stack/material/ore/ore in range(1, at_turf)) + if (!(get_dir(owner, ore) & owner.dir)) + continue + ore_box.insert_ore(ore) + +/obj/item/mech_equipment/drill/afterattack(atom/target, mob/living/user, inrange, params) + if (!..()) // /obj/item/mech_equipment/afterattack implements a usage guard + return + + if(!target.simulated) + return + + if (!drill_head) + if (istype(target, /obj/item/drill_head)) + attach_head(target, user) + else + to_chat(user, SPAN_WARNING("\The [src] doesn't have a head!")) + return + + if (ismob(target)) + to_chat(target, FONT_HUGE(SPAN_DANGER("You're about to get drilled - dodge!"))) + + else if (isobj(target)) + var/obj/tobj = target + var/decl/material/mat = tobj.get_material() + if (mat && mat.hardness < drill_head.material?.hardness) + to_chat(user, SPAN_WARNING("\The [target] is too hard to be destroyed by [drill_head.material ? "a [drill_head.material.adjective_name]" : "this"] drill.")) return - if(drill_head == null) - to_chat(user, SPAN_WARNING("Your drill doesn't have a head!")) + else if (istype(target, /turf/unsimulated)) + to_chat(user, SPAN_WARNING("\The [target] can't be drilled away.")) + return + + var/obj/item/cell/mech_cell = owner.get_cell() + mech_cell.use(active_power_use * CELLRATE) //supercall made sure we have one + + var/delay = 3 SECONDS //most things + switch (drill_head.material.brute_armor) + if (15 to INFINITY) delay = 0.5 SECONDS //voxalloy on a good roll + if (10 to 15) delay = 1 SECOND //titanium, diamond + if (5 to 10) delay = 2 SECONDS //plasteel, steel + owner.setClickCooldown(delay) + + playsound(src, 'sound/mecha/mechdrill.ogg', 50, 1) + owner.visible_message( + SPAN_WARNING("\The [owner] starts to drill \the [target]."), + blind_message = SPAN_WARNING("You hear a large motor whirring.") + ) + if (!do_after(owner, delay, target)) + return + if (src != owner.selected_system) + to_chat(user, SPAN_WARNING("You must keep \the [src] selected to use it.")) + return + if (drill_head.durability <= 0) + drill_head.shatter() + drill_head = null + return + + if (istype(target, /turf/wall/natural)) + for (var/turf/wall/natural/M in RANGE_TURFS(target, 1)) + if (!(get_dir(owner, M) & owner.dir)) + continue + drill_head.durability -= 1 + M.dismantle_turf() + scoop_ore(target) + return + + if (istype(target, /turf/wall)) + var/turf/wall/wall = target + var/wall_hardness = max(wall.material.hardness, wall.reinf_material ? wall.reinf_material.hardness : 0) + if (wall_hardness > drill_head.material.hardness) + to_chat(user, SPAN_WARNING("\The [wall] is too hard to drill through with \the [drill_head].")) + drill_head.durability -= 2 return - var/obj/item/cell/C = owner.get_cell() - if(istype(C)) - C.use(active_power_use * CELLRATE) - owner.visible_message("\The [owner] starts to drill \the [target]", "You hear a large drill.") - playsound(src, 'sound/mecha/mechdrill.ogg', 50, 1) - - var/T = target.loc - - //Better materials = faster drill! - var/delay = max(5, 20 - drill_head.material.brute_armor) - owner.setClickCooldown(delay) //Don't spamclick! - if(do_after(owner, delay, target) && drill_head) - if(src == owner.selected_system) - if(drill_head.durability <= 0) - drill_head.shatter() - drill_head = null - return + if(istype(target, /turf)) + for(var/turf/asteroid as anything in RANGE_TURFS(target, 1)) + if (!(get_dir(owner, asteroid) & owner.dir)) + continue + if(asteroid.can_be_dug(drill_head.material?.hardness) && asteroid.drop_diggable_resources(user)) + drill_head.durability -= 1 + scoop_ore(asteroid) + return - if(istype(target, /turf/simulated/wall/natural)) - for(var/turf/simulated/wall/natural/M in range(target,1)) - if(get_dir(owner,M)&owner.dir) - M.dismantle_wall() - drill_head.durability -= 1 - else if(istype(target, /turf/simulated/wall)) - var/turf/simulated/wall/W = target - if(max(W.material.hardness, W.reinf_material ? W.reinf_material.hardness : 0) > drill_head.material.hardness) - to_chat(user, "\The [target] is too hard to drill through with this drill head.") - target.explosion_act(2) - drill_head.durability -= 1 - log_and_message_admins("used [src] on the wall [W].", user, owner.loc) - else if(istype(target, /turf/simulated/floor/asteroid)) - for(var/turf/simulated/floor/asteroid/M in range(target,1)) - if(get_dir(owner,M)&owner.dir) - M.gets_dug() - drill_head.durability -= 1 - else if(target.loc == T) - target.explosion_act(2) - drill_head.durability -= 1 - log_and_message_admins("[src] used to drill [target].", user, owner.loc) - - - - - if(owner.hardpoints.len) //if this isn't true the drill should not be working to be fair - for(var/hardpoint in owner.hardpoints) - var/obj/item/I = owner.hardpoints[hardpoint] - if(!istype(I)) - continue - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in I //clamps work, but anythin that contains an ore crate internally is valid - if(ore_box) - for(var/obj/item/ore/ore in range(T,1)) - if(get_dir(owner,ore)&owner.dir) - ore.Move(ore_box) + var/audible = "loudly grinding machinery" + if (isliving(target)) //splorch + audible = "a terrible rending of metal and flesh" - else - to_chat(user, "You must stay still while the drill is engaged!") + owner.visible_message( + SPAN_DANGER("\The [owner] drives \the [src] into \the [target]."), + blind_message = SPAN_WARNING("You hear [audible].") + ) + log_and_message_admins("used [src] on [target]", user, owner.loc) + drill_head.durability -= 1 + target.explosion_act(2) - return 1 +/obj/item/mech_equipment/drill/steel + drill_head = /obj/item/drill_head/steel +/obj/item/mech_equipment/drill/titanium + drill_head = /obj/item/drill_head/titanium +/obj/item/mech_equipment/drill/plasteel + drill_head = /obj/item/drill_head/plasteel + +/obj/item/mech_equipment/drill/diamond + drill_head = /obj/item/drill_head/diamond + +/obj/item/gun/energy/plasmacutter/mounted/mech + use_external_power = TRUE + has_safety = FALSE /obj/item/mech_equipment/mounted_system/taser/plasma name = "mounted plasma cutter" desc = "An industrial plasma cutter mounted onto the chassis of the mech. " - icon_state = "railauto" //TODO: Make a new sprite that doesn't get sec called on you. - holding_type = /obj/item/gun/energy/plasmacutter/mounted/mech + icon_state = "mech_plasma" + holding = /obj/item/gun/energy/plasmacutter/mounted/mech restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND, HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) restricted_software = list(MECH_SOFTWARE_UTILITY) - origin_tech = "{'materials':4,'exoticmatter':4,'engineering':6,'combat':3}" - material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":4,"engineering":6,"exoticmatter":4,"combat":3}' -/obj/item/gun/energy/plasmacutter/mounted/mech - use_external_power = TRUE - has_safety = FALSE +/obj/item/mech_equipment/mounted_system/taser/autoplasma + icon_state = "mech_energy" + holding = /obj/item/gun/energy/plasmacutter/mounted/mech/auto + restricted_hardpoints = list(HARDPOINT_LEFT_HAND, HARDPOINT_RIGHT_HAND) + restricted_software = list(MECH_SOFTWARE_UTILITY) + origin_tech = @'{"materials":5,"engineering":6,"exoticmatter":4,"combat":4}' + +/obj/item/gun/energy/plasmacutter/mounted/mech/auto + charge_cost = 13 + name = "rotatory plasma cutter" + desc = "A state-of-the-art rotating, variable intensity, sequential-cascade plasma cutter. Resist the urge to aim this at your coworkers." + max_shots = 15 + firemodes = list( + list(mode_name="single shot", autofire_enabled=0, burst=1, fire_delay=6, dispersion = list(0.0)), + list(mode_name="full auto", autofire_enabled=1, burst=1, fire_delay=1, burst_accuracy = list(0,-1,-1,-1,-1,-2,-2,-2), dispersion = list(1.0, 1.0, 1.0, 1.0, 1.1)), + ) + +/obj/item/mech_equipment/ionjets + name = "\improper exosuit manouvering unit" + desc = "A testament to the fact that sometimes more is actually more. These oversized electric resonance boosters allow exosuits to move in microgravity and can even provide brief speed boosts. The stabilizers can be toggled with ctrl-click." + icon_state = "mech_jet_off" + restricted_hardpoints = list(HARDPOINT_BACK) + restricted_software = list(MECH_SOFTWARE_UTILITY) + active_power_use = 90 KILOWATTS + passive_power_use = 0 KILOWATTS + var/activated_passive_power = 2 KILOWATTS + var/movement_power = 75 + origin_tech = @'{"magnets":3,"engineering":3,"exoticmatter":3}' + var/datum/effect/effect/system/trail/ion/ion_trail + require_adjacent = FALSE + var/stabilizers = FALSE + var/slide_distance = 6 + +/obj/item/mech_equipment/ionjets/Initialize() + . = ..() + ion_trail = new /datum/effect/effect/system/trail/ion() + ion_trail.set_up(src) + +/obj/item/mech_equipment/ionjets/Destroy() + QDEL_NULL(ion_trail) + return ..() + +/obj/item/mech_equipment/ionjets/proc/provides_thrust() + if(!active) + return FALSE + var/obj/item/cell/cell = owner?.get_cell() + if(istype(cell)) + if(cell.checked_use(movement_power * CELLRATE)) + return TRUE + deactivate() + return FALSE + +/obj/item/mech_equipment/ionjets/attack_self(mob/user) + . = ..() + if (!.) + return + + if (active) + deactivate() + else + activate() + +/obj/item/mech_equipment/ionjets/proc/activate() + passive_power_use = activated_passive_power + ion_trail.start() + active = TRUE + update_icon() + +/obj/item/mech_equipment/ionjets/deactivate() + . = ..() + passive_power_use = 0 KILOWATTS + ion_trail.stop() + update_icon() + +/obj/item/mech_equipment/ionjets/on_update_icon() + . = ..() + if (active) + icon_state = "mech_jet_on" + set_light(1, 1, 1, l_color = COLOR_LIGHT_CYAN) + else + icon_state = "mech_jet_off" + set_light(0) + if(owner) + owner.update_icon() + +/obj/item/mech_equipment/ionjets/get_hardpoint_maptext() + if (active) + return "ONLINE - Stabilizers [stabilizers ? "on" : "off"]" + else return "OFFLINE" + +/obj/item/mech_equipment/ionjets/proc/slideCheck(turf/target) + if (owner && istype(target)) + if ((get_dist(owner, target) <= slide_distance) && (get_dir(get_turf(owner), target) == owner.dir)) + return TRUE + return FALSE + +/obj/item/mech_equipment/ionjets/afterattack(atom/target, mob/living/user, inrange, params) + . = ..() + if (. && active) + if (owner.z != target.z) + to_chat(user, SPAN_WARNING("You cannot reach that level!")) + return FALSE + var/turf/TT = get_turf(target) + if (slideCheck(TT)) + playsound(src, 'sound/magic/forcewall.ogg', 30, 1) + owner.visible_message( + SPAN_WARNING("\The [src] charges up in preparation for a slide!"), + blind_message = SPAN_WARNING("You hear a loud hum and an intense crackling.") + ) + new /obj/effect/temporary(get_step(owner.loc, global.reverse_dir[owner.dir]), 2 SECONDS, 'icons/effects/effects.dmi',"cyan_sparkles") + owner.setClickCooldown(2 SECONDS) + if (do_after(owner, 2 SECONDS, same_direction = TRUE) && slideCheck(TT)) + owner.visible_message(SPAN_DANGER("Burning hard, \the [owner] thrusts forward!")) + owner.throw_at(get_ranged_target_turf(owner, owner.dir, slide_distance), slide_distance, 1, owner, FALSE) + else + owner.visible_message(SPAN_DANGER("\The [src] sputters and powers down.")) + owner.sparks.set_up(3,0,owner) + owner.sparks.start() + + else + to_chat(user, SPAN_WARNING("You cannot slide there!")) + +/obj/item/mech_equipment/ionjets/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/mech_equipment/ionjets) + +/decl/interaction_handler/mech_equipment/ionjets + name = "Toggle Stabilizers" + expected_target_type = /obj/item/mech_equipment/ionjets + examine_desc = "toggle the stabilizers" + +/decl/interaction_handler/mech_equipment/ionjets/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/obj/item/mech_equipment/ionjets/jets = target + return jets.active + +/decl/interaction_handler/mech_equipment/ionjets/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/mech_equipment/ionjets/jets = target + jets.stabilizers = !jets.stabilizers + to_chat(user, SPAN_NOTICE("You toggle the stabilizers [jets.stabilizers ? "on" : "off"]")) + return TRUE + +//Exosuit camera +/datum/extension/network_device/camera/mech + expected_type = /obj/item/mech_equipment/camera + cameranet_enabled = FALSE + requires_connection = FALSE + +/datum/extension/network_device/camera/mech/is_functional() + var/obj/item/mech_equipment/camera/R = holder + return R.active + +/obj/item/mech_equipment/camera + name = "exosuit camera" + desc = "A dedicated visible light spectrum camera for remote feeds. It comes with its own transmitter!" + icon_state = "mech_camera" + restricted_hardpoints = list(HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) + restricted_software = list(MECH_SOFTWARE_UTILITY) + equipment_delay = 10 + + origin_tech = @'{"materials":1,"engineering":1,"magnets":2}' + + +/obj/item/mech_equipment/camera/Initialize() + . = ..() + + set_extension(src, /datum/extension/network_device/camera/mech, null, null, null, TRUE, list(CAMERA_CHANNEL_PUBLIC), "unregistered exocamera") +/obj/item/mech_equipment/camera/installed(mob/living/exosuit/_owner) + . = ..() + if(owner) + var/datum/extension/network_device/camera/mech/D = get_extension(src, /datum/extension/network_device) + D.display_name = "[owner.name] camera feed" + +/obj/item/mech_equipment/camera/uninstalled() + . = ..() + var/datum/extension/network_device/camera/mech/D = get_extension(src, /datum/extension/network_device) + D.display_name = "unregistered exocamera" + +/obj/item/mech_equipment/camera/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/datum/extension/network_device/camera/mech/D = get_extension(src, /datum/extension/network_device) + . += "Channel: [english_list(D.channels)]; Feed is currently: [active ? "Online" : "Offline"]." + +/obj/item/mech_equipment/camera/proc/activate() + passive_power_use = 0.2 KILOWATTS + active = TRUE + +/obj/item/mech_equipment/camera/deactivate() + passive_power_use = 0 + . = ..() + +/obj/item/mech_equipment/camera/attackby(obj/item/used_item, mob/user) + . = ..() + + if(IS_SCREWDRIVER(used_item)) + var/datum/extension/network_device/camera/mech/D = get_extension(src, /datum/extension/network_device) + D.ui_interact(user) + +/obj/item/mech_equipment/camera/attack_self(mob/user) + . = ..() + if(.) + if(active) + deactivate() + else + activate() + to_chat(user, SPAN_NOTICE("You toggle \the [src] [active ? "on" : "off"]")) +/obj/item/mech_equipment/camera/get_hardpoint_maptext() + var/datum/extension/network_device/camera/mech/D = get_extension(src, /datum/extension/network_device) + return "[english_list(D.channels)]: [active ? "ONLINE" : "OFFLINE"]" diff --git a/code/modules/mechs/interface/_interface.dm b/code/modules/mechs/interface/_interface.dm index 95665b94bcc7..f9090602be10 100644 --- a/code/modules/mechs/interface/_interface.dm +++ b/code/modules/mechs/interface/_interface.dm @@ -1,4 +1,15 @@ -#define BAR_CAP 12 +/mob/living/exosuit + var/static/list/additional_hud_elements = list( + /obj/screen/exosuit/toggle/power_control, + /obj/screen/exosuit/toggle/maint, + /obj/screen/exosuit/eject, + /obj/screen/exosuit/toggle/hardpoint, + /obj/screen/exosuit/toggle/hatch, + /obj/screen/exosuit/toggle/hatch_open, + /obj/screen/exosuit/radio, + /obj/screen/exosuit/rename, + /obj/screen/exosuit/toggle/camera + ) /mob/living/exosuit/proc/refresh_hud() if(LAZYLEN(pilots)) @@ -9,59 +20,62 @@ if(client) client.screen |= hud_elements -/mob/living/exosuit/InitializeHud() - zone_sel = new +/obj/screen/zone_selector/exosuit + requires_ui_style = FALSE + +/mob/living/exosuit/initialize_hud() if(!LAZYLEN(hud_elements)) var/i = 1 for(var/hardpoint in hardpoints) - var/obj/screen/movable/exosuit/hardpoint/H = new(src, hardpoint) - H.screen_loc = "LEFT+1:6,TOP-[i]" //temp + var/obj/screen/exosuit/hardpoint/H = new(null, src, null, null, null, null, hardpoint) + H.screen_loc = "LEFT:6,TOP-[i]:-16" hud_elements |= H hardpoint_hud_elements[hardpoint] = H i++ - var/list/additional_hud_elements = list( - /obj/screen/movable/exosuit/toggle/maint, - /obj/screen/movable/exosuit/eject, - /obj/screen/movable/exosuit/toggle/hardpoint, - /obj/screen/movable/exosuit/toggle/hatch, - /obj/screen/movable/exosuit/toggle/hatch_open, - /obj/screen/movable/exosuit/radio, - /obj/screen/movable/exosuit/rename, - /obj/screen/movable/exosuit/toggle/camera - ) if(body && body.pilot_coverage >= 100) - additional_hud_elements += /obj/screen/movable/exosuit/toggle/air + additional_hud_elements += /obj/screen/exosuit/toggle/air i = 0 var/pos = 7 for(var/additional_hud in additional_hud_elements) - var/obj/screen/movable/exosuit/M = new additional_hud(src) - M.screen_loc = "LEFT+1:6,BOTTOM+[pos]:[i * -12]" + var/obj/screen/exosuit/M = new additional_hud(null, src) + M.screen_loc = "LEFT:6,BOTTOM+[pos]:[i]" hud_elements |= M - i++ - if(i == 3) - pos-- - i = 0 + i -= M.height - hud_health = new /obj/screen/movable/exosuit/health(src) + hud_health = new /obj/screen/exosuit/health(null, src) hud_health.screen_loc = "RIGHT-1:28,CENTER-3:11" hud_elements |= hud_health - hud_open = locate(/obj/screen/movable/exosuit/toggle/hatch_open) in hud_elements - hud_power = new /obj/screen/movable/exosuit/power(src) - hud_power.screen_loc = "RIGHT-1:12,CENTER-4:25" + hud_open = locate(/obj/screen/exosuit/toggle/hatch_open) in hud_elements + hud_power = new /obj/screen/exosuit/power(null, src) + hud_power.screen_loc = "RIGHT-1:28,CENTER-4:25" hud_elements |= hud_power + hud_power_control = locate(/obj/screen/exosuit/toggle/power_control) in hud_elements + hud_camera = locate(/obj/screen/exosuit/toggle/camera) in hud_elements + hud_heat = new /obj/screen/exosuit/heat(null, src) + hud_heat.screen_loc = "RIGHT-1:28,CENTER-4" + hud_elements |= hud_heat refresh_hud() +/mob/living/exosuit/should_do_hud_updates() + . = ..() + if(!. && length(pilots)) + for(var/mob/living/pilot in pilots) + if(pilot.should_do_hud_updates()) + return TRUE + /mob/living/exosuit/handle_hud_icons() for(var/hardpoint in hardpoint_hud_elements) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] if(H) H.update_system_info() handle_hud_icons_health() - var/obj/item/cell/C = get_cell() - if(istype(C)) - hud_power.maptext = SPAN_STYLE("font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: 7px;", "[round(get_cell().charge)]/[round(get_cell().maxcharge)]") - else hud_power.maptext = SPAN_STYLE("font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: 7px;", "CHECK POWER") + + var/maptext_string = "CHECK
          POWER" + var/obj/item/cell/cell = get_cell() + if(istype(cell)) + maptext_string = "[round(get_cell().charge)]/[round(get_cell().maxcharge)]" + hud_power.maptext = STYLE_SMALLFONTS_OUTLINE("
          [maptext_string]
          ", 5, COLOR_WHITE, COLOR_BLACK) refresh_hud() /mob/living/exosuit/handle_hud_icons_health() @@ -72,9 +86,9 @@ return if(!body.diagnostics || !body.diagnostics.is_functional() || ((emp_damage>EMP_GUI_DISRUPT) && prob(emp_damage*2))) - if(!GLOB.mech_damage_overlay_cache["critfail"]) - GLOB.mech_damage_overlay_cache["critfail"] = image(icon='icons/mecha/mech_hud.dmi',icon_state="dam_error") - hud_health.overlays |= GLOB.mech_damage_overlay_cache["critfail"] + if(!global.mech_damage_overlay_cache["critfail"]) + global.mech_damage_overlay_cache["critfail"] = image(icon='icons/mecha/mech_hud.dmi',icon_state="dam_error") + hud_health.overlays |= global.mech_damage_overlay_cache["critfail"] return var/list/part_to_state = list("legs" = legs,"body" = body,"head" = head,"arms" = arms) @@ -86,7 +100,7 @@ state = rand(0,4) else state = MC.damage_state - if(!GLOB.mech_damage_overlay_cache["[part]-[state]"]) + if(!global.mech_damage_overlay_cache["[part]-[state]"]) var/image/I = image(icon='icons/mecha/mech_hud.dmi',icon_state="dam_[part]") switch(state) if(1) @@ -99,20 +113,20 @@ I.color = "#ff0000" else I.color = "#f5f5f0" - GLOB.mech_damage_overlay_cache["[part]-[state]"] = I - hud_health.overlays |= GLOB.mech_damage_overlay_cache["[part]-[state]"] + global.mech_damage_overlay_cache["[part]-[state]"] = I + hud_health.overlays |= global.mech_damage_overlay_cache["[part]-[state]"] /mob/living/exosuit/proc/reset_hardpoint_color() for(var/hardpoint in hardpoint_hud_elements) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] if(H) H.color = COLOR_WHITE /mob/living/exosuit/setClickCooldown(var/timeout) . = ..() for(var/hardpoint in hardpoint_hud_elements) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] if(H) H.color = "#a03b3b" - animate(H, color = COLOR_WHITE, time = timeout, easing = CUBIC_EASING | EASE_IN) - addtimer(CALLBACK(src, .proc/reset_hardpoint_color), timeout) \ No newline at end of file + animate(H, color = COLOR_WHITE, time = timeout, easing = CUBIC_EASING | EASE_IN) + addtimer(CALLBACK(src, PROC_REF(reset_hardpoint_color)), timeout) \ No newline at end of file diff --git a/code/modules/mechs/interface/screen_objects.dm b/code/modules/mechs/interface/screen_objects.dm deleted file mode 100644 index 6af6f2d021ad..000000000000 --- a/code/modules/mechs/interface/screen_objects.dm +++ /dev/null @@ -1,253 +0,0 @@ -// Screen objects hereon out. -/obj/screen/movable/exosuit - name = "hardpoint" - icon = 'icons/mecha/mech_hud.dmi' - icon_state = "hardpoint" - var/mob/living/exosuit/owner - -/obj/screen/movable/exosuit/radio - name = "radio" - icon_state = "radio" - -/obj/screen/movable/exosuit/radio/Click() - if(..()) - if(owner.radio) - owner.radio.attack_self(usr) - else - to_chat(usr, SPAN_WARNING("There is no radio installed.")) - -/obj/screen/movable/exosuit/Initialize() - . = ..() - var/mob/living/exosuit/newowner = loc - if(!istype(newowner)) - return qdel(src) - owner = newowner - -/obj/screen/movable/exosuit/Click() - return (!owner || !usr.incapacitated() && (usr == owner || usr.loc == owner)) - -/obj/screen/movable/exosuit/hardpoint - name = "hardpoint" - var/hardpoint_tag - var/obj/item/holding - - maptext_x = 34 - maptext_y = 3 - maptext_width = 72 - -/obj/screen/movable/exosuit/hardpoint/MouseDrop() - ..() - if(holding) holding.screen_loc = screen_loc - -/obj/screen/movable/exosuit/hardpoint/proc/update_system_info() - - // No point drawing it if we have no item to use or nobody to see it. - if(!holding || !owner) - return - - var/has_pilot_with_client = owner.client - if(!has_pilot_with_client && LAZYLEN(owner.pilots)) - for(var/thing in owner.pilots) - var/mob/pilot = thing - if(pilot.client) - has_pilot_with_client = TRUE - break - if(!has_pilot_with_client) - return - - var/list/new_overlays = list() - if(!owner.get_cell() || (owner.get_cell().charge <= 0)) - overlays.Cut() - return - - maptext = SPAN_STYLE("font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: 7px;", "[holding.get_hardpoint_maptext()]") - - var/ui_damage = (!owner.body.diagnostics || !owner.body.diagnostics.is_functional() || ((owner.emp_damage>EMP_GUI_DISRUPT) && prob(owner.emp_damage))) - - var/value = holding.get_hardpoint_status_value() - if(isnull(value)) - overlays.Cut() - return - - if(ui_damage) - value = -1 - maptext = SPAN_STYLE("font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: 7px;", "ERROR") - else - if((owner.emp_damage>EMP_GUI_DISRUPT) && prob(owner.emp_damage*2)) - if(prob(10)) - value = -1 - else - value = rand(1,BAR_CAP) - else - value = round(value * BAR_CAP) - - // Draw background. - if(!GLOB.default_hardpoint_background) - GLOB.default_hardpoint_background = image(icon = 'icons/mecha/mech_hud.dmi', icon_state = "bar_bkg") - GLOB.default_hardpoint_background.pixel_x = 34 - new_overlays += GLOB.default_hardpoint_background - - if(value == 0) - if(!GLOB.hardpoint_bar_empty) - GLOB.hardpoint_bar_empty = image(icon='icons/mecha/mech_hud.dmi',icon_state="bar_flash") - GLOB.hardpoint_bar_empty.pixel_x = 24 - GLOB.hardpoint_bar_empty.color = "#ff0000" - new_overlays += GLOB.hardpoint_bar_empty - else if(value < 0) - if(!GLOB.hardpoint_error_icon) - GLOB.hardpoint_error_icon = image(icon='icons/mecha/mech_hud.dmi',icon_state="bar_error") - GLOB.hardpoint_error_icon.pixel_x = 34 - new_overlays += GLOB.hardpoint_error_icon - else - value = min(value, BAR_CAP) - // Draw statbar. - if(!LAZYLEN(GLOB.hardpoint_bar_cache)) - for(var/i=0;i5) - bar.color = "#00ff00" - else if(i>1) - bar.color = "#ffff00" - else - bar.color = "#ff0000" - GLOB.hardpoint_bar_cache += bar - for(var/i=1;i<=value;i++) - new_overlays += GLOB.hardpoint_bar_cache[i] - overlays = new_overlays - -/obj/screen/movable/exosuit/hardpoint/Initialize(mapload, var/newtag) - . = ..() - hardpoint_tag = newtag - name = "hardpoint ([hardpoint_tag])" - -/obj/screen/movable/exosuit/hardpoint/Click(var/location, var/control, var/params) - - if(!(..())) - return - - if(!owner.hatch_closed) - to_chat(usr, SPAN_WARNING("Error: Hardpoint interface disabled while [owner.body.hatch_descriptor] is open.")) - return - - var/modifiers = params2list(params) - if(modifiers["ctrl"]) - if(owner.hardpoints_locked) - to_chat(usr, SPAN_WARNING("Hardpoint ejection system is locked.")) - return - if(owner.remove_system(hardpoint_tag)) - to_chat(usr, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint.")) - else - to_chat(usr, SPAN_DANGER("You fail to remove the system mounted to your [hardpoint_tag] hardpoint.")) - return - - if(owner.selected_hardpoint == hardpoint_tag) - icon_state = "hardpoint" - owner.clear_selected_hardpoint() - else - if(owner.set_hardpoint(hardpoint_tag)) - icon_state = "hardpoint_selected" - -/obj/screen/movable/exosuit/eject - name = "eject" - icon_state = "eject" - -/obj/screen/movable/exosuit/eject/Click() - if(..()) - owner.eject(usr) - -/obj/screen/movable/exosuit/rename - name = "rename" - icon_state = "rename" - -/obj/screen/movable/exosuit/power - name = "power" - icon_state = null - - maptext_width = 64 - -/obj/screen/movable/exosuit/rename/Click() - if(..()) - owner.rename(usr) - -/obj/screen/movable/exosuit/toggle - name = "toggle" - var/toggled - -/obj/screen/movable/exosuit/toggle/Click() - if(..()) toggled() - -/obj/screen/movable/exosuit/toggle/proc/toggled() - toggled = !toggled - icon_state = "[initial(icon_state)][toggled ? "_enabled" : ""]" - return toggled - -/obj/screen/movable/exosuit/toggle/air - name = "air" - icon_state = "air" - -/obj/screen/movable/exosuit/toggle/air/toggled() - owner.use_air = ..() - to_chat(usr, SPAN_NOTICE("Auxiliary atmospheric system [owner.use_air ? "enabled" : "disabled"].")) - -/obj/screen/movable/exosuit/toggle/maint - name = "toggle maintenance protocol" - icon_state = "maint" - -/obj/screen/movable/exosuit/toggle/maint/toggled() - owner.maintenance_protocols = ..() - to_chat(usr, SPAN_NOTICE("Maintenance protocols [owner.maintenance_protocols ? "enabled" : "disabled"].")) - -/obj/screen/movable/exosuit/toggle/hardpoint - name = "toggle hardpoint lock" - icon_state = "hardpoint_lock" - -/obj/screen/movable/exosuit/toggle/hardpoint/toggled() - owner.hardpoints_locked = ..() - to_chat(usr, SPAN_NOTICE("Hardpoint system access is now [owner.hardpoints_locked ? "disabled" : "enabled"].")) - -/obj/screen/movable/exosuit/toggle/hatch - name = "toggle hatch lock" - icon_state = "hatch_lock" - -/obj/screen/movable/exosuit/toggle/hatch/toggled() - if(!owner.hatch_locked && !owner.hatch_closed) - to_chat(usr, SPAN_WARNING("You cannot lock the hatch while it is open.")) - return - owner.hatch_locked = ..() - to_chat(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked.")) - -/obj/screen/movable/exosuit/toggle/hatch_open - name = "open or close hatch" - icon_state = "hatch_status" - -/obj/screen/movable/exosuit/toggle/hatch_open/toggled() - if(owner.hatch_locked && owner.hatch_closed) - to_chat(usr, SPAN_WARNING("You cannot open the hatch while it is locked.")) - return - owner.hatch_closed = ..() - to_chat(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ].")) - owner.update_icon() - -// This is basically just a holder for the updates the exosuit does. -/obj/screen/movable/exosuit/health - name = "exosuit integrity" - icon_state = "health" - -//Controls if cameras set the vision flags -/obj/screen/movable/exosuit/toggle/camera - name = "toggle camera matrix" - icon_state = "camera" - -/obj/screen/movable/exosuit/toggle/camera/toggled() - if(!owner.head) - to_chat(usr, SPAN_WARNING("I/O Error: Camera systems not found.")) - return - if(!owner.head.vision_flags) - to_chat(usr, SPAN_WARNING("Alternative sensor configurations not found. Contact manufacturer for more details.")) - return - owner.head.active_sensors = ..() - to_chat(usr, SPAN_NOTICE("[owner.head.name] advanced sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active.")) - - -#undef BAR_CAP \ No newline at end of file diff --git a/code/modules/mechs/mech.dm b/code/modules/mechs/mech.dm index 3f63003e805b..25f9ecbf7873 100644 --- a/code/modules/mechs/mech.dm +++ b/code/modules/mechs/mech.dm @@ -10,15 +10,9 @@ default_pixel_x = -8 default_pixel_y = 0 status_flags = PASSEMOTES - a_intent = I_HURT mob_size = MOB_SIZE_LARGE - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 + atom_flags = ATOM_FLAG_SHIELD_CONTENTS | ATOM_FLAG_BLOCK_DIAGONAL_FACING + butchery_data = null var/emp_damage = 0 @@ -53,9 +47,6 @@ var/hardpoints_locked var/maintenance_protocols - // Material - var/decl/material/material - // Cockpit access vars. var/hatch_closed = FALSE var/hatch_locked = FALSE @@ -66,9 +57,27 @@ // Interface stuff. var/list/hud_elements = list() var/list/hardpoint_hud_elements = list() - var/obj/screen/movable/exosuit/health/hud_health - var/obj/screen/movable/exosuit/toggle/hatch_open/hud_open - var/obj/screen/movable/exosuit/power/hud_power + var/obj/screen/exosuit/health/hud_health + var/obj/screen/exosuit/toggle/hatch_open/hud_open + var/obj/screen/exosuit/power/hud_power + var/obj/screen/exosuit/heat/hud_heat + var/obj/screen/exosuit/toggle/power_control/hud_power_control + var/obj/screen/exosuit/toggle/camera/hud_camera + //POWER + var/power = MECH_POWER_OFF + + var/mob/living/current_user = null + + +//Pixel projectiles need a client, so we need a way to pass who the last user was for view calcs +/mob/living/proc/get_effective_gunner() + return src + +/mob/living/exosuit/get_effective_gunner() + return current_user + +/mob/living/exosuit/can_be_buckled(mob/user) + return FALSE /mob/living/exosuit/is_flooded(lying_mob, absolute) . = (body && body.pilot_coverage >= 100 && hatch_closed) ? FALSE : ..() @@ -78,8 +87,7 @@ if(!access_card) access_card = new (src) - pixel_x = default_pixel_x - pixel_y = default_pixel_y + reset_offsets(0) sparks = new(src) // Grab all the supplied components. @@ -101,8 +109,6 @@ if(source_frame.material) material = source_frame.material - updatehealth() - // Generate hardpoint list. var/list/component_descriptions for(var/obj/item/mech_component/comp in list(arms, legs, head, body)) @@ -119,7 +125,7 @@ desc = "[desc] It has been built with [english_list(component_descriptions)]." // Create HUD. - InitializeHud() + initialize_hud() // Build icon. queue_icon_update() @@ -130,67 +136,128 @@ for(var/thing in pilots) var/mob/pilot = thing - if(pilot.client) + if(pilot && pilot.client) pilot.client.screen -= hud_elements pilot.client.images -= hud_elements pilot.forceMove(get_turf(src)) pilots = null + hud_health = null + hud_open = null + hud_power = null + hud_heat = null + hud_power_control = null + hud_camera = null + for(var/thing in hud_elements) qdel(thing) hud_elements.Cut() for(var/hardpoint in hardpoints) - qdel(hardpoints[hardpoint]) + var/obj/item/mech_equipment/equipment = hardpoints[hardpoint] + if(istype(equipment)) + equipment.uninstalled() + QDEL_NULL(equipment) hardpoints.Cut() QDEL_NULL(access_card) + QDEL_NULL(radio) QDEL_NULL(arms) QDEL_NULL(legs) QDEL_NULL(head) QDEL_NULL(body) for(var/hardpoint in hardpoint_hud_elements) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] - H.owner = null + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] + H.owner_ref = null H.holding = null qdel(H) hardpoint_hud_elements.Cut() . = ..() -/mob/living/exosuit/examine(mob/user) +/mob/living/exosuit/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) . = ..() if(LAZYLEN(pilots) && (!hatch_closed || body.pilot_coverage < 100 || body.transparent_cabin)) - to_chat(user, "It is being piloted by [english_list(pilots, nothing_text = "nobody")].") + . += "It is being piloted by [english_list(pilots, nothing_text = "nobody")]." + if(body && LAZYLEN(body.pilot_positions)) + . += "It can seat [body.pilot_positions.len] pilot\s total." if(hardpoints.len) - to_chat(user, "It has the following hardpoints:") + . += "It has the following hardpoints:" for(var/hardpoint in hardpoints) var/obj/item/I = hardpoints[hardpoint] - to_chat(user, "- [hardpoint]: [istype(I) ? "[I]" : "nothing"].") + . += "- [hardpoint]: [istype(I) ? "[I]" : "nothing"]." else - to_chat(user, "It has no visible hardpoints.") - + . += "It has no visible hardpoints." for(var/obj/item/mech_component/thing in list(arms, legs, head, body)) if(!thing) continue - - var/damage_string = thing.get_damage_string() - to_chat(user, "Its [thing.name] [thing.gender == PLURAL ? "are" : "is"] [damage_string].") - - to_chat(user, "It menaces with reinforcements of [material].") + var/decl/pronouns/component_pronouns = thing.get_pronouns() + . += "Its [thing.name] [component_pronouns.is] [thing.get_damage_string()]." + . += "It menaces with reinforcements of [material]." /mob/living/exosuit/return_air() - return (body && body.pilot_coverage >= 100 && hatch_closed) ? body.cockpit : loc.return_air() + return (body && body.pilot_coverage >= 100 && hatch_closed && body.cockpit) ? body.cockpit : loc?.return_air() -/mob/living/exosuit/GetIdCard() - return access_card +/mob/living/exosuit/GetIdCards(list/exceptions) + . = ..() + if(istype(access_card) && !is_type_in_list(access_card, exceptions)) + LAZYDISTINCTADD(., access_card) /mob/living/exosuit/set_dir() . = ..() if(.) update_pilots() - - +/mob/living/exosuit/increaseBodyTemp(value) + bodytemperature += value + return bodytemperature + +/mob/living/exosuit/proc/toggle_power(var/mob/user) + if(power == MECH_POWER_TRANSITION) + to_chat(user, SPAN_NOTICE("Power transition in progress. Please wait.")) + else if(power == MECH_POWER_ON) //Turning it off is instant + playsound(src, 'sound/mecha/mech-shutdown.ogg', 100, 0) + power = MECH_POWER_OFF + else if(get_cell(TRUE)) + //Start power up sequence + power = MECH_POWER_TRANSITION + playsound(src, 'sound/mecha/powerup.ogg', 50, 0) + if(user.do_skilled(1.5 SECONDS, SKILL_MECH, src, 0.5) && power == MECH_POWER_TRANSITION) + playsound(src, 'sound/mecha/nominal.ogg', 50, 0) + power = MECH_POWER_ON + else + to_chat(user, SPAN_WARNING("You abort the powerup sequence.")) + power = MECH_POWER_OFF + hud_power_control?.queue_icon_update() + else + to_chat(user, SPAN_WARNING("Error: No power cell was detected.")) + +// Dump exhaled air into the environment to avoid the tank filling +// up with CO2 and the cockpit filling up with N2. This isn't an +// ideal fix; regulators or something would be a better solution. +/mob/living/exosuit/merge_exhaled_volume(datum/gas_mixture/exhaled) + return loc?.merge_exhaled_volume(exhaled) + +// Override this to avoid triggering the ancient vore code. +/mob/living/exosuit/relaymove(mob/living/user, direction) + return + +/mob/living/exosuit/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing + ) + return available_postures + +/mob/living/exosuit/try_awaken(mob/user) + return FALSE + +/mob/living/exosuit/handle_stance() + stance_damage = 0 + return + +/mob/living/exosuit/is_valid_merchant_pad_target() + if(current_user) + return FALSE + return ..() diff --git a/code/modules/mechs/mech_construction.dm b/code/modules/mechs/mech_construction.dm index 73d5197a9f04..fb4f5f6b705e 100644 --- a/code/modules/mechs/mech_construction.dm +++ b/code/modules/mechs/mech_construction.dm @@ -45,9 +45,9 @@ if(target == selected_hardpoint) clear_selected_hardpoint() - GLOB.destroyed_event.unregister(module_to_forget, src, .proc/forget_module) + events_repository.unregister(/decl/observ/destroyed, module_to_forget, src, PROC_REF(forget_module)) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[target] + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[target] H.holding = null hud_elements -= module_to_forget @@ -60,22 +60,10 @@ pilot.client.screen -= module_to_forget /mob/living/exosuit/proc/install_system(var/obj/item/system, var/system_hardpoint, var/mob/user) - + set waitfor = FALSE if(hardpoints_locked || hardpoints[system_hardpoint]) return FALSE - if(user) - var/delay = 30 * user.skill_delay_mult(SKILL_DEVICES) - if(delay > 0) - user.visible_message(SPAN_NOTICE("\The [user] begins trying to install \the [system] into \the [src].")) - if(!do_after(user, delay, src) || user.get_active_hand() != system) - return FALSE - - if(user.unEquip(system)) - to_chat(user, SPAN_NOTICE("You install \the [system] in \the [src]'s [system_hardpoint].")) - playsound(user.loc, 'sound/items/Screwdriver.ogg', 100, 1) - else return FALSE - var/obj/item/mech_equipment/ME = system if(istype(ME)) if(ME.restricted_hardpoints && !(system_hardpoint in ME.restricted_hardpoints)) @@ -90,34 +78,51 @@ break if(!found) return FALSE - ME.installed(src) - GLOB.destroyed_event.register(system, src, .proc/forget_module) + else + return FALSE + + if(user) + var/delay = 3 SECONDS * user.skill_delay_mult(SKILL_DEVICES) + if(delay > 0) + user.visible_message( + SPAN_NOTICE("\The [user] begins trying to install \the [system] into \the [src]."), + SPAN_NOTICE("You begin trying to install \the [system] into \the [src].") + ) + if(!do_after(user, delay, src) || user.get_active_held_item() != system) + return FALSE + + if(user.try_unequip(system)) + to_chat(user, SPAN_NOTICE("You install \the [system] in \the [src]'s [system_hardpoint].")) + playsound(user.loc, 'sound/items/Screwdriver.ogg', 100, 1) + else return FALSE - + events_repository.register(/decl/observ/destroyed, system, src, PROC_REF(forget_module)) system.forceMove(src) hardpoints[system_hardpoint] = system + ME.installed(src) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[system_hardpoint] - H.holding = system + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[system_hardpoint] + if(H) + H.holding = system + system.screen_loc = H.screen_loc - system.screen_loc = H.screen_loc system.hud_layerise() hud_elements |= system refresh_hud() queue_icon_update() - return 1 + return TRUE /mob/living/exosuit/proc/remove_system(var/system_hardpoint, var/mob/user, var/force) - + set waitfor = FALSE if((hardpoints_locked && !force) || !hardpoints[system_hardpoint]) return 0 var/obj/item/system = hardpoints[system_hardpoint] if(user) - var/delay = 30 * user.skill_delay_mult(SKILL_DEVICES) + var/delay = 3 SECONDS * user.skill_delay_mult(SKILL_DEVICES) if(delay > 0) user.visible_message(SPAN_NOTICE("\The [user] begins trying to remove \the [system] from \the [src].")) if(!do_after(user, delay, src) || hardpoints[system_hardpoint] != system) @@ -134,9 +139,9 @@ system.forceMove(get_turf(src)) system.screen_loc = null system.layer = initial(system.layer) - GLOB.destroyed_event.unregister(system, src, .proc/forget_module) + events_repository.unregister(/decl/observ/destroyed, system, src, PROC_REF(forget_module)) - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[system_hardpoint] + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[system_hardpoint] H.holding = null for(var/thing in pilots) diff --git a/code/modules/mechs/mech_damage.dm b/code/modules/mechs/mech_damage.dm index c21129acf25b..a83ea60f14ab 100644 --- a/code/modules/mechs/mech_damage.dm +++ b/code/modules/mechs/mech_damage.dm @@ -1,3 +1,21 @@ +/mob/living/exosuit/explosion_act(severity) + . = ..(4) //We want to avoid the automatic handling of damage to contents + var/b_loss = 0 + var/f_loss = 0 + switch (severity) + if (1) + b_loss = 200 + f_loss = 200 + if (2) + b_loss = 90 + f_loss = 90 + if(3) + b_loss = 45 + + // spread damage overall + apply_damage(b_loss, BRUTE, null, DAM_EXPLODE | DAM_DISPERSED, used_weapon = "Explosive blast") + apply_damage(f_loss, BURN, null, DAM_EXPLODE | DAM_DISPERSED, used_weapon = "Explosive blast") + /mob/living/exosuit/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) if(!effect || (blocked >= 100)) return 0 @@ -10,7 +28,7 @@ . = ..() /mob/living/exosuit/resolve_item_attack(var/obj/item/I, var/mob/living/user, var/def_zone) - if(!I.force) + if(!I.expend_attack_force(user)) user.visible_message(SPAN_NOTICE("\The [user] bonks \the [src] harmlessly with \the [I].")) return @@ -26,11 +44,26 @@ return AR return def_zone //Careful with effects, mechs shouldn't be stunned - + /mob/living/exosuit/hitby(atom/movable/AM, var/datum/thrownthing/TT) - if(LAZYLEN(pilots) && (!hatch_closed || !prob(body.pilot_coverage))) + if (!hatch_closed && (LAZYLEN(pilots) < body.pilot_positions.len)) + var/mob/living/M = AM + if (istype(M)) + var/chance = 50 //Throwing someone at an empty exosuit MAY put them in the seat + var/message = "\The [AM] lands in \the [src]'s cockpit with a crash. Get in the damn exosuit!" + if (TT.thrower == TT.thrownthing) + //This is someone jumping + chance = M.skill_check_multiple(list(SKILL_MECH = HAS_PERK, SKILL_HAULING = SKILL_ADEPT)) ? 100 : chance + message = "\The [AM] gets in \the [src]'s cockpit in one fluid motion." + if (prob(chance)) + if (enter(AM, silent = TRUE, check_incap = FALSE, instant = TRUE)) + visible_message(SPAN_NOTICE("[message]")) + return TRUE + + if (LAZYLEN(pilots) && (!hatch_closed || !prob(body.pilot_coverage))) var/mob/living/pilot = pick(pilots) return pilot.hitby(AM, TT) + . = ..() /mob/living/exosuit/bullet_act(obj/item/projectile/P, def_zone, used_weapon) @@ -48,22 +81,22 @@ if(body_armor) . += body_armor -/mob/living/exosuit/updatehealth() - if(body) - maxHealth = body.mech_health - health = maxHealth-(getFireLoss()+getBruteLoss()) - else - health = 0 // Shouldn't exist without a body, no idea how the runtime is being generated. +/mob/living/exosuit/get_max_health() + return (body ? body.mech_health : 0) + +/mob/living/exosuit/get_total_life_damage() + return (get_damage(BURN)+get_damage(BRUTE)) -/mob/living/exosuit/adjustFireLoss(var/amount, var/obj/item/mech_component/MC = pick(list(arms, legs, body, head))) +/mob/living/exosuit/adjustFireLoss(var/amount, var/obj/item/mech_component/MC = pick(list(arms, legs, body, head)), var/do_update_health = TRUE) if(MC) MC.take_burn_damage(amount) - MC.update_health() + if(do_update_health) + update_health() // TODO: unify these procs somehow instead of having weird brute-wrapping behavior as the default. -/mob/living/exosuit/adjustBruteLoss(var/amount, var/obj/item/mech_component/MC = pick(list(arms, legs, body, head))) +/mob/living/exosuit/adjustBruteLoss(var/amount, var/obj/item/mech_component/MC = pick(list(arms, legs, body, head)), var/do_update_health = TRUE) if(MC) MC.take_brute_damage(amount) - MC.update_health() + ..() /mob/living/exosuit/proc/zoneToComponent(var/zone) switch(zone) @@ -76,15 +109,36 @@ else return body - -/mob/living/exosuit/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/damage_flags = 0, var/used_weapon = null, var/armor_pen, var/silent = FALSE) +/mob/living/exosuit/apply_damage(damage = 0, damagetype = BRUTE, def_zone, damage_flags = 0, obj/used_weapon, armor_pen, silent = FALSE, obj/item/organ/external/given_organ) if(!damage) return 0 + if(!def_zone) + if(damage_flags & DAM_DISPERSED) + var/old_damage = damage + var/tally + silent = FALSE + for(var/obj/item/part in list(arms, legs, body, head)) + tally += part.w_class + for(var/obj/item/part in list(arms, legs, body, head)) + damage = old_damage * part.w_class/tally + def_zone = BP_CHEST + if(part == arms) + def_zone = BP_L_ARM + else if(part == legs) + def_zone = BP_L_LEG + else if(part == head) + def_zone = BP_HEAD + + . = .() || . + return + + def_zone = ran_zone(def_zone) + var/list/after_armor = modify_damage_by_armor(def_zone, damage, damagetype, damage_flags, src, armor_pen, TRUE) damage = after_armor[1] damagetype = after_armor[2] - + if(!damage) return 0 @@ -92,27 +146,27 @@ //Only 3 types of damage concern mechs and vehicles switch(damagetype) if(BRUTE) - adjustBruteLoss(damage, target) + take_damage(damage, inflicter = target) if(BURN) - adjustFireLoss(damage, target) + take_damage(damage, BURN, inflicter = target) if(IRRADIATE) - radiation += damage + for(var/mob/living/pilot in pilots) + pilot.apply_damage(damage, IRRADIATE, def_zone, damage_flags, used_weapon) if((damagetype == BRUTE || damagetype == BURN) && prob(25+(damage*2))) sparks.set_up(3,0,src) sparks.start() - updatehealth() - return 1 /mob/living/exosuit/rad_act(var/severity) - if(severity) - apply_damage(severity, IRRADIATE, damage_flags = DAM_DISPERSED) + return FALSE // Pilots already query rads, modify this for radiation alerts and such /mob/living/exosuit/get_rads() + . = ..() if(!hatch_closed || (body.pilot_coverage < 100)) //Open, environment is the source - return ..() - return radiation //Closed, what made it through our armour? + return . + var/list/after_armor = modify_damage_by_armor(null, ., IRRADIATE, DAM_DISPERSED, src, 0, TRUE) + return after_armor[1] /mob/living/exosuit/getFireLoss() var/total = 0 @@ -148,3 +202,6 @@ for(var/thing in pilots) var/mob/pilot = thing pilot.emp_act(severity) + +/mob/living/exosuit/get_bullet_impact_effect_type(def_zone) + return BULLET_IMPACT_METAL diff --git a/code/modules/mechs/mech_damage_immunity.dm b/code/modules/mechs/mech_damage_immunity.dm index 6b2dde3abaa8..01a8ef4a0f13 100644 --- a/code/modules/mechs/mech_damage_immunity.dm +++ b/code/modules/mechs/mech_damage_immunity.dm @@ -1,11 +1,12 @@ -/mob/living/exosuit/Stun() - return 0 - -/mob/living/exosuit/Weaken() - return 0 +/mob/living/exosuit + var/static/list/ignore_status_conditions = list( + STAT_STUN, + STAT_WEAK, + STAT_PARA + ) -/mob/living/exosuit/Paralyse() - return 0 +/mob/living/exosuit/set_status_condition(condition, amount) + . = !(condition in ignore_status_conditions) && ..() /mob/living/exosuit/getOxyLoss() return 0 @@ -13,7 +14,8 @@ /mob/living/exosuit/setOxyLoss() return 0 -/mob/living/exosuit/adjustOxyLoss() +/mob/living/exosuit/adjustOxyLoss(var/damage, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) return 0 /mob/living/exosuit/getToxLoss() @@ -22,7 +24,7 @@ /mob/living/exosuit/setToxLoss() return 0 -/mob/living/exosuit/adjustToxLoss() +/mob/living/exosuit/adjustToxLoss(var/amount, var/do_update_health = TRUE) return 0 /mob/living/exosuit/getBrainLoss() @@ -31,7 +33,8 @@ /mob/living/exosuit/setBrainLoss() return 0 -/mob/living/exosuit/adjustBrainLoss() +/mob/living/exosuit/adjustBrainLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) return 0 /mob/living/exosuit/getCloneLoss() @@ -40,7 +43,8 @@ /mob/living/exosuit/setCloneLoss() return 0 -/mob/living/exosuit/adjustCloneLoss() +/mob/living/exosuit/adjustCloneLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) return 0 /mob/living/exosuit/getHalLoss() @@ -49,5 +53,6 @@ /mob/living/exosuit/setHalLoss() return 0 -/mob/living/exosuit/adjustHalLoss() +/mob/living/exosuit/adjustHalLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) return 0 \ No newline at end of file diff --git a/code/modules/mechs/mech_grabs.dm b/code/modules/mechs/mech_grabs.dm index 58d82b41b0fc..7b0a023a7d32 100644 --- a/code/modules/mechs/mech_grabs.dm +++ b/code/modules/mechs/mech_grabs.dm @@ -1,11 +1,20 @@ -/mob/living/exosuit/can_grab(atom/movable/target, target_zone) +/mob/living/exosuit/can_grab(atom/movable/target, target_zone, defer_hand = FALSE) return FALSE /mob/living/exosuit/can_be_grabbed(mob/grabber, target_zone) return FALSE -/mob/living/exosuit/adjust_pixel_offsets_for_grab(var/obj/item/grab/G, var/grab_dir) - reset_plane_and_layer() - -/mob/living/exosuit/reset_pixel_offsets_for_grab(var/obj/item/grab/G) - reset_plane_and_layer() \ No newline at end of file +/mob/living/exosuit/reset_offsets(var/anim_time = 2) + pixel_x = default_pixel_x + pixel_y = default_pixel_y + pixel_z = default_pixel_z + +/mob/living/exosuit/reset_plane() + plane = initial(plane) + +/mob/living/exosuit/reset_layer() + layer = initial(layer) + +/mob/living/exosuit/reset_plane_and_layer() + reset_plane() + reset_layer() \ No newline at end of file diff --git a/code/modules/mechs/mech_icon.dm b/code/modules/mechs/mech_icon.dm index 5d717c27f49d..d0beae151793 100644 --- a/code/modules/mechs/mech_icon.dm +++ b/code/modules/mechs/mech_icon.dm @@ -1,63 +1,87 @@ -proc/get_mech_image(var/decal, var/cache_key, var/cache_icon, var/image_colour, var/overlay_layer = FLOAT_LAYER) - var/use_key = "[cache_key]-[cache_icon]-[decal ? decal : "none"]-[image_colour ? image_colour : "none"]" - if(!GLOB.mech_image_cache[use_key]) +/proc/get_mech_image(var/decal, var/decal_blend = BLEND_MULTIPLY, var/cache_key, var/cache_icon, var/image_colour, var/overlay_layer = FLOAT_LAYER) + + var/use_key = "[cache_key]-[cache_icon]-[overlay_layer]-[decal ? decal : "none"]-[decal_blend]-[image_colour ? image_colour : "none"]" + if(!global.mech_image_cache[use_key]) var/image/I = image(icon = cache_icon, icon_state = cache_key) if(image_colour) - I.color = image_colour + var/image/masked_color = image(icon = cache_icon, icon_state = "[cache_key]_mask") + masked_color.color = image_colour + masked_color.blend_mode = BLEND_MULTIPLY + I.overlays += masked_color if(decal) - var/decal_key = "[decal]-[cache_key]" - if(!GLOB.mech_icon_cache[decal_key]) + var/decal_key = "[decal]-[decal_blend]-[cache_key]" + if(!global.mech_icon_cache[decal_key]) var/template_key = "template-[cache_key]" - if(!GLOB.mech_icon_cache[template_key]) - GLOB.mech_icon_cache[template_key] = icon(cache_icon, "[cache_key]_mask") - var/icon/decal_icon = icon('icons/mecha/mech_decals.dmi',decal) - decal_icon.AddAlphaMask(GLOB.mech_icon_cache[template_key]) - GLOB.mech_icon_cache[decal_key] = decal_icon - I.overlays += get_mech_image(null, decal_key, GLOB.mech_icon_cache[decal_key]) + var/icon/decal_icon = icon('icons/mecha/mech_decals.dmi', decal) + if(!global.mech_icon_cache[template_key]) + global.mech_icon_cache[template_key] = icon(cache_icon, "[cache_key]_mask") + decal_icon.AddAlphaMask(global.mech_icon_cache[template_key]) + global.mech_icon_cache[decal_key] = decal_icon + var/image/decal_image = get_mech_image(null, null, decal_key, global.mech_icon_cache[decal_key]) + decal_image.blend_mode = decal_blend + decal_image.appearance_flags |= RESET_COLOR + I.overlays += decal_image I.appearance_flags |= RESET_COLOR I.layer = overlay_layer I.plane = FLOAT_PLANE - GLOB.mech_image_cache[use_key] = I - return GLOB.mech_image_cache[use_key] + global.mech_image_cache[use_key] = I -proc/get_mech_images(var/list/components = list(), var/overlay_layer = FLOAT_LAYER) - var/list/all_images = list() - for(var/obj/item/mech_component/comp in components) - all_images += get_mech_image(comp.decal, comp.icon_state, comp.on_mech_icon, comp.color, overlay_layer) - return all_images + var/image/I = new + I.appearance = global.mech_image_cache[use_key] + return I /mob/living/exosuit/on_update_icon() - var/list/new_overlays = get_mech_images(list(body, head), MECH_BASE_LAYER) - if(body && !hatch_closed) - new_overlays += get_mech_image(body.decal, "[body.icon_state]_cockpit", body.on_mech_icon, MECH_BASE_LAYER) + ..() + var/list/new_overlays = list() + if(body) + new_overlays += get_mech_image(body.decal, body.decal_blend, body.icon_state, body.on_mech_icon, body.color, overlay_layer = MECH_BASE_LAYER) + new_overlays += get_mech_image(body.decal, body.decal_blend, "[body.icon_state]_cockpit", body.on_mech_icon, overlay_layer = MECH_INTERMEDIATE_LAYER) update_pilots(FALSE) if(LAZYLEN(pilot_overlays)) new_overlays += pilot_overlays if(body) - new_overlays += get_mech_image(body.decal, "[body.icon_state]_overlay[hatch_closed ? "" : "_open"]", body.on_mech_icon, body.color, MECH_COCKPIT_LAYER) + new_overlays += get_mech_image(body.decal, body.decal_blend, "[body.icon_state]_overlay[hatch_closed ? "" : "_open"]", body.on_mech_icon, body.color, MECH_COCKPIT_LAYER) if(arms) - new_overlays += get_mech_image(arms.decal, arms.icon_state, arms.on_mech_icon, arms.color, MECH_ARM_LAYER) + new_overlays += get_mech_image(arms.decal, arms.decal_blend, arms.icon_state, arms.on_mech_icon, arms.color, MECH_ARM_LAYER) if(legs) - new_overlays += get_mech_image(legs.decal, legs.icon_state, legs.on_mech_icon, legs.color, MECH_LEG_LAYER) + new_overlays += get_mech_image(legs.decal, legs.decal_blend, legs.icon_state, legs.on_mech_icon, legs.color, MECH_LEG_LAYER) for(var/hardpoint in hardpoints) var/obj/item/mech_equipment/hardpoint_object = hardpoints[hardpoint] if(hardpoint_object) var/use_icon_state = "[hardpoint_object.icon_state]_[hardpoint]" - if(use_icon_state in GLOB.mech_weapon_overlays) - new_overlays += get_mech_image(null, use_icon_state, 'icons/mecha/mech_weapon_overlays.dmi', null, hardpoint_object.mech_layer ) - overlays = new_overlays + if(use_icon_state in global.mech_weapon_overlays) + var/color = COLOR_WHITE + var/decal = null + var/decal_blend = BLEND_MULTIPLY + if(hardpoint in list(HARDPOINT_BACK, HARDPOINT_RIGHT_SHOULDER, HARDPOINT_LEFT_SHOULDER)) + color = body.color + decal = body.decal + decal_blend = body.decal_blend + else if(hardpoint in list(HARDPOINT_RIGHT_HAND, HARDPOINT_LEFT_HAND)) + color = arms.color + decal = arms.decal + decal_blend = arms.decal_blend + else + color = head.color + decal = head.decal + decal_blend = head.decal_blend + new_overlays += get_mech_image(decal, decal_blend, use_icon_state, 'icons/mecha/mech_weapon_overlays.dmi', color, hardpoint_object.mech_layer ) + + set_overlays(new_overlays) /mob/living/exosuit/proc/update_pilots(var/update_overlays = TRUE) if(update_overlays && LAZYLEN(pilot_overlays)) overlays -= pilot_overlays pilot_overlays = null - if(!body || ((body.pilot_coverage < 100 || body.transparent_cabin) && !body.hide_pilot)) + if(body && !(body.hide_pilot)) for(var/i = 1 to LAZYLEN(pilots)) var/mob/pilot = pilots[i] var/image/draw_pilot = new draw_pilot.appearance = pilot - draw_pilot.layer = MECH_PILOT_LAYER + (body ? ((LAZYLEN(body.pilot_positions)-i)*0.001) : 0) + var/rel_pos = dir == NORTH ? -1 : 1 + draw_pilot.layer = MECH_PILOT_LAYER + (body ? ((LAZYLEN(body.pilot_positions)-i)*0.001 * rel_pos) : 0) draw_pilot.plane = FLOAT_PLANE + draw_pilot.appearance_flags = KEEP_TOGETHER if(body && i <= LAZYLEN(body.pilot_positions)) var/list/offset_values = body.pilot_positions[i] var/list/directional_offset_values = offset_values["[dir]"] @@ -65,9 +89,13 @@ proc/get_mech_images(var/list/components = list(), var/overlay_layer = FLOAT_LAY draw_pilot.pixel_y = pilot.default_pixel_y + directional_offset_values["y"] draw_pilot.pixel_z = 0 draw_pilot.transform = null + + //Mask pilots! + //Masks are 48x48 and pilots 32x32 (in theory at least) so some math is required for centering + var/diff_x = 8 - draw_pilot.pixel_x + var/diff_y = 8 - draw_pilot.pixel_y + draw_pilot.add_filter("pilot_mask", 1, list(type = "alpha", icon = icon(body.on_mech_icon, "[body.icon_state]_pilot_mask[hatch_closed ? "" : "_open"]", dir), x = diff_x, y = diff_y)) + LAZYADD(pilot_overlays, draw_pilot) if(update_overlays && LAZYLEN(pilot_overlays)) overlays += pilot_overlays - -/mob/living/exosuit/regenerate_icons() - return \ No newline at end of file diff --git a/code/modules/mechs/mech_interaction.dm b/code/modules/mechs/mech_interaction.dm index 48c9fde6add9..8a8e9b671675 100644 --- a/code/modules/mechs/mech_interaction.dm +++ b/code/modules/mechs/mech_interaction.dm @@ -1,33 +1,20 @@ -/mob/living/MouseDrop(atom/over) - if(usr == src && usr != over) - if(istype(over, /mob/living/exosuit)) - var/mob/living/exosuit/exosuit = over - if(exosuit.body) - if(usr.mob_size >= exosuit.body.min_pilot_size && usr.mob_size <= exosuit.body.max_pilot_size) - if(exosuit.enter(src)) - return - else - to_chat(usr, SPAN_WARNING("You cannot pilot a exosuit of this size.")) - return - return ..() +/mob/living/exosuit/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && istype(dropping, /obj/machinery/portable_atmospherics/canister)) + body.receive_mouse_drop(dropping, user, params) + return TRUE + +/mob/living/exosuit/handle_mouse_drop(atom/over, mob/user, params) + if(body?.handle_mouse_drop(over, user, params)) + return TRUE + . = ..() -/mob/living/exosuit/MouseDrop_T(atom/dropping, mob/user) - var/obj/machinery/portable_atmospherics/canister/C = dropping - if(istype(C)) - body.MouseDrop_T(dropping, user) - else . = ..() - -/mob/living/exosuit/MouseDrop(mob/living/carbon/human/over_object) //going from assumption none of previous options are relevant to exosuit - if(body) - if(!body.MouseDrop(over_object)) - return ..() - -/mob/living/exosuit/RelayMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params, var/mob/user) +/mob/living/exosuit/RelayMouseDrag(atom/src_object, atom/over_object, src_location, over_location, src_control, over_control, params, mob/user) if(user && (user in pilots) && user.loc == src) return OnMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params, user) return ..() -/mob/living/exosuit/OnMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params, var/mob/user) +/mob/living/exosuit/OnMouseDrag(atom/src_object, atom/over_object, src_location, over_location, src_control, over_control, params, mob/user) if(!user || incapacitated() || user.incapacitated()) return FALSE @@ -38,6 +25,36 @@ if(selected_system) return selected_system.MouseDragInteraction(src_object, over_object, src_location, over_location, src_control, over_control, params, user) +/mob/living/exosuit/RelayMouseDown(atom/object, location, control, params, mob/user) + if(user && (user in pilots) && user.loc == src) + return OnMouseDown(object, location, control, params, user) + return ..() + +/mob/living/exosuit/OnMouseDown(atom/object, location, control, params, mob/user) + if(!user || incapacitated() || user.incapacitated()) + return FALSE + + if(!(user in pilots) && user != src) + return FALSE + + if(selected_system) + return selected_system.MouseDownInteraction(object, location, control, params, user) + +/mob/living/exosuit/RelayMouseUp(atom/object, location, control, params, mob/user) + if(user && (user in pilots) && user.loc == src) + return OnMouseUp(object, location, control, params, user) + return ..() + +/mob/living/exosuit/OnMouseUp(atom/object, location, control, params, mob/user) + if(!user || incapacitated() || user.incapacitated()) + return FALSE + + if(!(user in pilots) && user != src) + return FALSE + + if(selected_system) + return selected_system.MouseUpInteraction(object, location, control, params, user) + /datum/click_handler/default/mech/OnClick(var/atom/A, var/params) var/mob/living/exosuit/E = user.loc if(!istype(E)) @@ -59,9 +76,19 @@ //UI distance checks /mob/living/exosuit/contents_nano_distance(src_object, mob/living/user) . = ..() + if((user in pilots) && (src_object == src)) + return STATUS_INTERACTIVE //Pilots can always interact with exosuit hosted uis if(!hatch_closed) return max(shared_living_nano_distance(src_object), .) //Either visible to mech(outside) or visible to user (inside) - + +/mob/living/exosuit/CanUseTopic(mob/user, datum/topic_state/state, href_list) + if(user in pilots) + return STATUS_INTERACTIVE + return ..() + +/mob/living/exosuit/get_dexterity(var/silent) + return DEXTERITY_FULL + /mob/living/exosuit/ClickOn(var/atom/A, var/params, var/mob/user) if(!user || incapacitated() || user.incapacitated()) @@ -72,20 +99,20 @@ var/modifiers = params2list(params) if(modifiers["shift"]) - user.examinate(A) + user.examine_verb(A) return - + if(modifiers["ctrl"] && selected_system == A) selected_system.CtrlClick(user) setClickCooldown(3) - return + return if(!(user in pilots) && user != src) return if(!canClick()) return - + // Are we facing the target? if(A.loc != src && !(get_dir(src, A) & dir)) return @@ -101,15 +128,14 @@ return if(!get_cell()?.checked_use(arms.power_use * CELLRATE)) - to_chat(user, SPAN_WARNING("Error: Power levels insufficient.")) + to_chat(user, power == MECH_POWER_ON ? SPAN_WARNING("Error: Power levels insufficient.") : SPAN_WARNING("\The [src] is powered off.")) + return // User is not necessarily the exosuit, or the same person, so update intent. if(user != src) - a_intent = user.a_intent - if(user.zone_sel) - zone_sel.set_selected_zone(user.zone_sel.selecting) - else - zone_sel.set_selected_zone(BP_CHEST) + set_intent(user.get_intent()) + set_target_zone(user.get_target_zone()) + // You may attack the target with your exosuit FIST if you're malfunctioning. var/atom/movable/AM = A var/fail_prob = (user != src && istype(AM) && AM.loc != src) ? (user.skill_check(SKILL_MECH, HAS_PERK) ? 0: 15 ) : 0 @@ -133,14 +159,19 @@ var/system_moved = FALSE var/obj/item/temp_system var/obj/item/mech_equipment/ME + var/temp_old_anchored if(istype(selected_system, /obj/item/mech_equipment)) ME = selected_system temp_system = ME.get_effective_obj() if(temp_system in ME) - system_moved = 1 + system_moved = TRUE temp_system.forceMove(src) else temp_system = selected_system + // Hackery for preventing embedding of melee weapons. + if(temp_system) + temp_old_anchored = temp_system.anchored + temp_system.anchored = TRUE // Slip up and attack yourself maybe. failed = FALSE @@ -163,28 +194,36 @@ adj = A.Adjacent(src) var/resolved + current_user = user - if(adj) resolved = temp_system.resolve_attackby(A, src, params) + if(adj) + resolved = temp_system.resolve_attackby(A, src, params) if(!resolved && A && temp_system) var/mob/ruser = src if(!system_moved) //It's more useful to pass along clicker pilot when logic is fully mechside ruser = user temp_system.afterattack(A,ruser,adj,params) if(system_moved) //We are using a proxy system that may not have logging like mech equipment does - log_and_message_admins("used [temp_system] targetting [A]", user, src.loc) + admin_attack_log(user, A, "Attacked using \a [temp_system] (MECH)", "Was attacked with \a [temp_system] (MECH)", "used \a [temp_system] (MECH) to attack") //Mech equipment subtypes can add further click delays var/extra_delay = 0 if(ME != null) ME = selected_system extra_delay = ME.equipment_delay setClickCooldown(arms ? arms.action_delay + extra_delay : 15 + extra_delay) - if(system_moved) - temp_system.forceMove(selected_system) + + if(!QDELETED(temp_system)) + if(system_moved) + temp_system.forceMove(selected_system) + temp_system.anchored = temp_old_anchored + + current_user = null return if(A == src) setClickCooldown(5) - return attack_self(user) + visible_message("\The [src] pokes itself.") + return TRUE else if(adj) setClickCooldown(arms ? arms.action_delay : 15) admin_attack_log(user, A, "Attacked using \a [arms]", "Was attacked with \a [arms]", "used \a [arms] to attack") @@ -206,50 +245,57 @@ for(var/hardpoint in hardpoints) if(hardpoint != selected_hardpoint) continue - var/obj/screen/movable/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] + var/obj/screen/exosuit/hardpoint/H = hardpoint_hud_elements[hardpoint] if(istype(H)) H.icon_state = "hardpoint" break selected_system = null selected_hardpoint = null -/mob/living/exosuit/proc/check_enter(var/mob/user) - if(!user || user.incapacitated()) +/mob/living/exosuit/proc/check_enter(mob/user, silent = FALSE, check_incap = TRUE) + if(!user || (check_incap && user.incapacitated())) + return FALSE + if(!(user.mob_size >= body.min_pilot_size && user.mob_size <= body.max_pilot_size)) + if(!silent) + to_chat(user, SPAN_WARNING("You cannot pilot an exosuit of this size.")) return FALSE - if(!user.Adjacent(src)) + if(!user.Adjacent(src) || user.buckled) return FALSE if(hatch_locked) - to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) + if(!silent) + to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) return FALSE if(hatch_closed) - to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is closed.")) + if(!silent) + to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is closed.")) return FALSE if(LAZYLEN(pilots) >= LAZYLEN(body.pilot_positions)) - to_chat(user, SPAN_WARNING("\The [src] is occupied to capacity.")) + if(!silent) + to_chat(user, SPAN_WARNING("\The [src] is occupied to capacity.")) return FALSE return TRUE -/mob/living/exosuit/proc/enter(var/mob/user) - if(!check_enter(user)) - return +/mob/living/exosuit/proc/enter(mob/user, silent = FALSE, check_incap = TRUE, instant = FALSE) + if(!check_enter(user, silent, check_incap)) + return FALSE to_chat(user, SPAN_NOTICE("You start climbing into \the [src]...")) - if(!body || !do_after(user, body.climb_time)) - return if(!body) - return - if(!check_enter(user)) - return - to_chat(user, SPAN_NOTICE("You climb into \the [src].")) + return FALSE + if(!instant && !do_after(user, body.climb_time)) + return FALSE + if(!check_enter(user, silent, check_incap)) + return FALSE + if(!silent) + to_chat(user, SPAN_NOTICE("You climb into \the [src].")) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) user.forceMove(src) LAZYDISTINCTADD(pilots, user) sync_access() - playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - user.playsound_local(get_turf(src), 'sound/mecha/nominal.ogg', 50) if(user.client) user.client.screen |= hud_elements LAZYDISTINCTADD(user.additional_vision_handlers, src) update_pilots() user.PushClickHandler(/datum/click_handler/default/mech) - return 1 + return TRUE /mob/living/exosuit/proc/sync_access() access_card.access = saved_access?.Copy() @@ -266,7 +312,7 @@ if(!silent) to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) return - hud_open.toggled() + hud_open.toggled(user) if(!silent) to_chat(user, SPAN_NOTICE("You open the hatch and climb out of \the [src].")) else @@ -280,135 +326,191 @@ user.client.screen -= hud_elements user.client.eye = user if(user in pilots) - a_intent = I_HURT + set_intent(I_FLAG_HARM) LAZYREMOVE(pilots, user) UNSETEMPTY(pilots) update_pilots() return 1 -/mob/living/exosuit/attackby(var/obj/item/thing, var/mob/user) +/mob/living/exosuit/attackby(var/obj/item/used_item, var/mob/user) - if(user.a_intent != I_HURT && istype(thing, /obj/item/mech_equipment)) + // Install equipment. + if(!user.check_intent(I_FLAG_HARM) && istype(used_item, /obj/item/mech_equipment)) if(hardpoints_locked) to_chat(user, SPAN_WARNING("Hardpoint system access is disabled.")) - return - - var/obj/item/mech_equipment/realThing = thing + return TRUE + var/obj/item/mech_equipment/realThing = used_item if(realThing.owner) - return - + return TRUE var/free_hardpoints = list() for(var/hardpoint in hardpoints) if(hardpoints[hardpoint] == null) free_hardpoints += hardpoint var/to_place = input("Where would you like to install it?") as null|anything in (realThing.restricted_hardpoints & free_hardpoints) - if(install_system(thing, to_place, user)) - return - to_chat(user, SPAN_WARNING("\The [src] could not be installed in that hardpoint.")) - return + if(!to_place) + to_chat(user, SPAN_WARNING("There is no room to install \the [used_item].")) + else if(!install_system(used_item, to_place, user)) + to_chat(user, SPAN_WARNING("\The [used_item] could not be installed in that hardpoint.")) + return TRUE - else if(istype(thing, /obj/item/kit/paint)) - user.visible_message(SPAN_NOTICE("\The [user] opens \the [thing] and spends some quality time customising \the [src].")) - var/obj/item/kit/paint/P = thing + // Apply customisation. + if(istype(used_item, /obj/item/kit/paint)) + user.visible_message(SPAN_NOTICE("\The [user] opens \the [used_item] and spends some quality time customising \the [src].")) + + var/obj/item/kit/paint/P = used_item SetName(P.new_name) desc = P.new_desc - for(var/obj/item/mech_component/comp in list(arms, legs, head, body)) - comp.decal = P.new_icon - if(P.new_icon_file) - icon = P.new_icon_file - queue_icon_update() - P.use(1, user) - return 1 - else - if(user.a_intent != I_HURT) - if(isMultitool(thing)) - if(hardpoints_locked) - to_chat(user, SPAN_WARNING("Hardpoint system access is disabled.")) - return + if(P.new_state) + for(var/obj/item/mech_component/comp in list(arms, legs, head, body)) + comp.decal = P.new_state - var/list/parts = list() - for(var/hardpoint in hardpoints) - if(hardpoints[hardpoint]) - parts += hardpoint + if(!isnull(P.new_blend)) + for(var/obj/item/mech_component/comp in list(arms, legs, head, body)) + comp.decal_blend = P.new_blend - var/to_remove = input("Which component would you like to remove") as null|anything in parts + if(P.new_icon) + for(var/obj/item/mech_component/comp in list(arms, legs, head, body)) + comp.icon = P.new_icon - if(remove_system(to_remove, user)) - return + update_icon() + P.use(1, user) + return TRUE + + // Various tool and construction interactions. + if(!user.check_intent(I_FLAG_HARM)) + + // Removing systems from hardpoints. + if(IS_MULTITOOL(used_item)) + if(hardpoints_locked) + to_chat(user, SPAN_WARNING("Hardpoint system access is disabled.")) + return TRUE + var/list/parts = list() + for(var/hardpoint in hardpoints) + if(hardpoints[hardpoint]) + parts += hardpoint + var/to_remove = input("Which component would you like to remove") as null|anything in parts + if(!remove_system(to_remove, user)) to_chat(user, SPAN_WARNING("\The [src] has no hardpoint systems to remove.")) - return - else if(isWrench(thing)) - if(!maintenance_protocols) - to_chat(user, SPAN_WARNING("The securing bolts are not visible while maintenance protocols are disabled.")) - return - - visible_message(SPAN_WARNING("\The [user] begins unwrenching the securing bolts holding \the [src] together.")) - var/delay = 60 * user.skill_delay_mult(SKILL_DEVICES) - if(!do_after(user, delay) || !maintenance_protocols) - return + return TRUE + + // Dismantling an exosuit entirely. + if(IS_WRENCH(used_item)) + if(!maintenance_protocols) + to_chat(user, SPAN_WARNING("The securing bolts are not visible while maintenance protocols are disabled.")) + return TRUE + visible_message(SPAN_WARNING("\The [user] begins unwrenching the securing bolts holding \the [src] together.")) + if(user.do_skilled(6 SECONDS, SKILL_DEVICES, src) && maintenance_protocols) visible_message(SPAN_NOTICE("\The [user] loosens and removes the securing bolts, dismantling \the [src].")) dismantle() - return - else if(isWelder(thing)) - if(!getBruteLoss()) - return - var/list/damaged_parts = list() - for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) - if(MC && MC.brute_damage) - damaged_parts += MC - var/obj/item/mech_component/to_fix = input(user,"Which component would you like to fix") as null|anything in damaged_parts - if(CanPhysicallyInteract(user) && !QDELETED(to_fix) && (to_fix in src) && to_fix.brute_damage) - to_fix.repair_brute_generic(thing, user) - return - else if(isCoil(thing)) - if(!getFireLoss()) - return - var/list/damaged_parts = list() - for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) - if(MC && MC.burn_damage) - damaged_parts += MC - var/obj/item/mech_component/to_fix = input(user,"Which component would you like to fix") as null|anything in damaged_parts - if(CanPhysicallyInteract(user) && !QDELETED(to_fix) && (to_fix in src) && to_fix.burn_damage) - to_fix.repair_burn_generic(thing, user) - return - else if(isCrowbar(thing)) - if(!maintenance_protocols) - to_chat(user, SPAN_WARNING("The cell compartment remains locked while maintenance protocols are disabled.")) - return - if(!body || !body.cell) - to_chat(user, SPAN_WARNING("There is no cell here for you to remove!")) - return - var/delay = 20 * user.skill_delay_mult(SKILL_DEVICES) - if(!do_after(user, delay) || !maintenance_protocols || !body || !body.cell) - return - + return TRUE + + // Brute damage repair. + if(IS_WELDER(used_item)) + if(!get_damage(BRUTE)) + return TRUE + var/list/damaged_parts = list() + for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) + if(MC && MC.brute_damage) + damaged_parts += MC + var/obj/item/mech_component/to_fix = input(user,"Which component would you like to fix") as null|anything in damaged_parts + if(CanPhysicallyInteract(user) && !QDELETED(to_fix) && (to_fix in src) && to_fix.brute_damage) + to_fix.repair_brute_generic(used_item, user) + return TRUE + + // Burn damage repair. + if(IS_COIL(used_item)) + if(!get_damage(BURN)) + return TRUE + var/list/damaged_parts = list() + for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) + if(MC && MC.burn_damage) + damaged_parts += MC + var/obj/item/mech_component/to_fix = input(user,"Which component would you like to fix") as null|anything in damaged_parts + if(CanPhysicallyInteract(user) && !QDELETED(to_fix) && (to_fix in src) && to_fix.burn_damage) + to_fix.repair_burn_generic(used_item, user) + return TRUE + + // Cell removal. + if(IS_SCREWDRIVER(used_item)) + if(!maintenance_protocols) + to_chat(user, SPAN_WARNING("The cell compartment remains locked while maintenance protocols are disabled.")) + return TRUE + if(!body || !body.cell) + to_chat(user, SPAN_WARNING("There is no cell here for you to remove!")) + return TRUE + var/delay = (2 SECONDS) * user.skill_delay_mult(SKILL_DEVICES) + if(do_after(user, delay) && maintenance_protocols && body?.cell) user.put_in_hands(body.cell) to_chat(user, SPAN_NOTICE("You remove \the [body.cell] from \the [src].")) playsound(user.loc, 'sound/items/Crowbar.ogg', 50, 1) - visible_message(SPAN_NOTICE("\The [user] pries out \the [body.cell] using the \the [thing].")) + visible_message(SPAN_NOTICE("\The [user] pries out \the [body.cell] using \the [used_item].")) + power = MECH_POWER_OFF + hud_power_control.queue_icon_update() body.cell = null - return - else if(istype(thing, /obj/item/cell)) - if(!maintenance_protocols) - to_chat(user, SPAN_WARNING("The cell compartment remains locked while maintenance protocols are disabled.")) - return - if(!body || body.cell) - to_chat(user, SPAN_WARNING("There is already a cell in there!")) - return - - if(user.unEquip(thing)) - thing.forceMove(body) - body.cell = thing - to_chat(user, SPAN_NOTICE("You install \the [body.cell] into \the [src].")) - playsound(user.loc, 'sound/items/Screwdriver.ogg', 50, 1) - visible_message(SPAN_NOTICE("\The [user] installs \the [body.cell] into \the [src].")) - return + return TRUE + + // Force-opening the cockpit. + if(IS_CROWBAR(used_item)) + if(!hatch_locked) + to_chat(user, SPAN_NOTICE("The cockpit isn't locked. There is no need for this.")) + return TRUE + if(!body) //Error + return TRUE + var/delay = min(5 SECONDS * user.skill_delay_mult(SKILL_DEVICES), 5 SECONDS * user.skill_delay_mult(SKILL_EVA)) + visible_message(SPAN_NOTICE("\The [user] starts forcing \the [src]'s emergency [body.hatch_descriptor] release using \the [used_item].")) + if(do_after(user, delay, src)) + visible_message(SPAN_NOTICE("\The [user] forces \the [src]'s [body.hatch_descriptor] open using \the [used_item].")) + playsound(user.loc, 'sound/machines/bolts_up.ogg', 25, 1) + hatch_locked = FALSE + hatch_closed = FALSE + for(var/mob/pilot in pilots) + eject(pilot, silent = 1) + hud_open.queue_icon_update() + queue_icon_update() + return TRUE + + // Cell replacement. + if(istype(used_item, /obj/item/cell)) + if(!maintenance_protocols) + to_chat(user, SPAN_WARNING("The cell compartment remains locked while maintenance protocols are disabled.")) + return TRUE + if(body?.cell) + to_chat(user, SPAN_WARNING("There is already a cell in there!")) + return TRUE + if(user.try_unequip(used_item)) + used_item.forceMove(body) + body.cell = used_item + to_chat(user, SPAN_NOTICE("You install \the [body.cell] into \the [src].")) + playsound(user.loc, 'sound/items/Screwdriver.ogg', 50, 1) + visible_message(SPAN_NOTICE("\The [user] installs \the [body.cell] into \the [src].")) + return TRUE + + // Diagnostic scan. + if(istype(used_item, /obj/item/robotanalyzer)) + to_chat(user, SPAN_NOTICE("Diagnostic Report for \the [src]:")) + for(var/obj/item/mech_component/MC in list(arms, legs, body, head)) + if(MC) + MC.return_diagnostics(user) + return TRUE + return ..() -/mob/living/exosuit/attack_hand(var/mob/user) - // Drag the pilot out if possible. - if(user.a_intent == I_HURT) +/mob/living/exosuit/default_interaction(var/mob/user) + . = ..() + if(!.) + // Toggle the hatch. + if(hatch_locked) + to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) + return TRUE + if(hud_open) + hud_open.toggled(user) + return TRUE + +/mob/living/exosuit/default_hurt_interaction(var/mob/user) + . = ..() + if(.) + // Drag the pilot out if possible. if(!LAZYLEN(pilots)) to_chat(user, SPAN_WARNING("There is nobody inside \the [src].")) else if(!hatch_closed) @@ -417,20 +519,13 @@ if(do_after(user, 30) && user.Adjacent(src) && (pilot in pilots) && !hatch_closed) user.visible_message(SPAN_DANGER("\The [user] drags \the [pilot] out of \the [src]!")) eject(pilot, silent=1) - return TRUE - - // Otherwise toggle the hatch. - if(hatch_locked) - to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) - return TRUE - hatch_closed = !hatch_closed - to_chat(user, SPAN_NOTICE("You [hatch_closed ? "close" : "open"] the [body.hatch_descriptor].")) - hud_open.queue_icon_update() - queue_icon_update() - return TRUE + return TRUE + return -/mob/living/exosuit/proc/attack_self(var/mob/user) - return visible_message("\The [src] pokes itself.") +/mob/living/exosuit/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes into") + if(..()) + playsound(loc, 'sound/effects/metal_close.ogg', 40, 1) + playsound(loc, 'sound/weapons/tablehit1.ogg', 40, 1) /mob/living/exosuit/proc/rename(var/mob/user) if(user != src && !(user in pilots)) @@ -441,8 +536,23 @@ SetName(new_name) to_chat(user, SPAN_NOTICE("You have redesignated this exosuit as \the [name].")) -/mob/living/exosuit/get_inventory_slot(obj/item/I) +/mob/living/exosuit/get_equipped_slot_for_item(obj/item/I) for(var/h in hardpoints) if(hardpoints[h] == I) return h return 0 + +/decl/interaction_handler/mech_equipment + abstract_type = /decl/interaction_handler/mech_equipment + expected_target_type = /obj/item/mech_equipment + interaction_flags = 0 // Mech gear is a bit special, see is_possible() below. + +/decl/interaction_handler/mech_equipment/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + if(user.incapacitated()) + return FALSE + var/obj/item/mech_equipment/gear = target + if(!gear.owner) + return FALSE + return gear.owner.hatch_closed && ((user in gear.owner.pilots) || user == gear.owner) diff --git a/code/modules/mechs/mech_life.dm b/code/modules/mechs/mech_life.dm index b6ca6feab392..3a128a552952 100644 --- a/code/modules/mechs/mech_life.dm +++ b/code/modules/mechs/mech_life.dm @@ -1,7 +1,13 @@ /mob/living/exosuit/handle_disabilities() return -/mob/living/exosuit/Life() +/mob/living/exosuit/handle_regular_status_updates() + + if(!body && !QDELETED(src)) + physically_destroyed() + return FALSE + + . = ..() for(var/thing in pilots) var/mob/pilot = thing @@ -12,40 +18,30 @@ UNSETEMPTY(pilots) update_pilots() - if(!body && !QDELETED(src)) - qdel(src) - return - if(radio) - radio.on = (head && head.radio && head.radio.is_functional()) - - body.update_air(hatch_closed && use_air) - - if((client || LAZYLEN(pilots)) && get_cell()) - get_cell().drain_power(0, 0, calc_power_draw()) - - updatehealth() - if(health <= 0 && stat != DEAD) - death() - - ..() //Handles stuff like environment - - handle_mutations_and_radiation() + radio.on = (head && head.radio && head.radio.is_functional() && get_cell()) - handle_hud_icons() + if(!is_suit_powered()) + //Shut down all systems + if(head) + head.active_sensors = FALSE + hud_camera.queue_icon_update() + for(var/hardpoint in hardpoints) + var/obj/item/mech_equipment/M = hardpoints[hardpoint] + if(istype(M) && M.active && M.passive_power_use) + M.deactivate() - lying = FALSE // Fuck off, carp. - handle_vision() + if(emp_damage > 0) + emp_damage -= min(1, emp_damage) //Reduce emp accumulation over time -/mob/living/exosuit/handle_mutations_and_radiation() - radiation = Clamp(radiation,0,500) //Dont let exosuits accumulate radiation +/mob/living/exosuit/proc/is_suit_powered() + return (get_cell()?.drain_power(0, 0, calc_power_draw())) > 0 - if(radiation) - radiation-- - -/mob/living/exosuit/get_cell() +/mob/living/exosuit/get_cell(force) RETURN_TYPE(/obj/item/cell) - return body ? body.cell : null + if(power == MECH_POWER_ON || force) //For most intents we can assume that a powered off exosuit acts as if it lacked a cell + return body ? body.cell : null + return null /mob/living/exosuit/proc/calc_power_draw() //Passive power stuff here. You can also recharge cells or hardpoints if those make sense @@ -65,78 +61,88 @@ return total_draw /mob/living/exosuit/handle_environment(var/datum/gas_mixture/environment) - if(!environment) return - //Mechs and vehicles in general can be assumed to just tend to whatever ambient temperature - if(abs(environment.temperature - bodytemperature) > 10 ) - bodytemperature += ((environment.temperature - bodytemperature) / 3) + ..() + + if(body) + body.update_air(hatch_closed && use_air) - if(environment.temperature > material.melting_point * 1.25 ) //A bit higher because I like to assume there's a difference between a mech and a wall - apply_damage(damage = (environment.temperature - (material.melting_point))/5 , damagetype = BURN) + if(!environment) + return + + //Mechs and vehicles in general can be assumed to just tend to whatever ambient temperature + if(abs(environment.temperature - bodytemperature) > 0 ) + bodytemperature += ((environment.temperature - bodytemperature) / 6) + + if(bodytemperature > material.temperature_damage_threshold * 1.45 ) //A bit higher because I like to assume there's a difference between a mech and a wall + var/damage = 5 + if(bodytemperature > material.temperature_damage_threshold * 1.75 ) + damage = 10 + if(bodytemperature > material.temperature_damage_threshold * 2.15 ) + damage = 15 + apply_damage(damage, BURN) //A possibility is to hook up interface icons here. But this works pretty well in my experience - if(prob(5)) + if(prob(damage)) visible_message(SPAN_DANGER("\The [src]'s hull bends and buckles under the intense heat!")) - - -/mob/living/exosuit/death(var/gibbed) - - // Salvage moves into the wreck unless we're exploding violently. - var/obj/wreck = new wreckage_path(get_turf(src), src, gibbed) - wreck.name = "wreckage of \the [name]" - if(!gibbed) - if(arms.loc != src) - arms = null - if(legs.loc != src) - legs = null - if(head.loc != src) - head = null - if(body.loc != src) - body = null - - // Eject the pilot. - if(LAZYLEN(pilots)) - hatch_locked = 0 // So they can get out. - for(var/pilot in pilots) - eject(pilot, silent=1) - - // Handle the rest of things. - ..(gibbed, (gibbed ? "explodes!" : "grinds to a halt before collapsing!")) - if(!gibbed) qdel(src) - -/mob/living/exosuit/gib() - death(1) - - // Get a turf to play with. - var/turf/T = get_turf(src) - if(!T) - qdel(src) - return - // Hurl our component pieces about. - var/list/stuff_to_throw = list() - for(var/obj/item/thing in list(arms, legs, head, body)) - if(thing) stuff_to_throw += thing - for(var/hardpoint in hardpoints) - if(hardpoints[hardpoint]) - var/obj/item/thing = hardpoints[hardpoint] - thing.screen_loc = null - stuff_to_throw += thing - for(var/obj/item/thing in stuff_to_throw) - thing.forceMove(T) - thing.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(3,6),40) - explosion(T, -1, 0, 2) - qdel(src) - return + hud_heat.Update() + +/mob/living/exosuit/death(gibbed) + . = ..() + if(.) + // Eject the pilot. + if(LAZYLEN(pilots)) + hatch_locked = 0 // So they can get out. + for(var/pilot in pilots) + eject(pilot, silent=1) + new wreckage_path(get_turf(src), src, gibbed) + +/mob/living/exosuit/get_death_message(gibbed) + return gibbed ? "explodes!" : "grinds to a halt before collapsing!" + +/mob/living/exosuit/get_gibbed_state(dusted) + return null + +/mob/living/exosuit/get_gibbed_icon() + return null + +/mob/living/exosuit/gib(do_gibs = TRUE) + SHOULD_CALL_PARENT(FALSE) + if(stat != DEAD) + death(gibbed = TRUE) + if(stat == DEAD) + // Get a turf to play with. + var/turf/T = get_turf(src) + if(T) + // Hurl our component pieces about. + var/list/stuff_to_throw = list() + for(var/obj/item/thing in list(arms, legs, head, body)) + if(thing) + stuff_to_throw += thing + for(var/hardpoint in hardpoints) + if(hardpoints[hardpoint]) + var/obj/item/thing = hardpoints[hardpoint] + thing.screen_loc = null + stuff_to_throw += thing + for(var/obj/item/thing in stuff_to_throw) + thing.forceMove(T) + thing.throw_at(get_edge_target_turf(src,pick(global.alldirs)),rand(3,6),40) + explosion(T, -1, 0, 2) + qdel(src) /mob/living/exosuit/handle_vision() + var/was_blind = sight & BLIND if(head) - sight = head.get_sight() - see_invisible = head.get_invisible() - if(body && (body.pilot_coverage < 100 || body.transparent_cabin)) + var/powered = is_suit_powered() + sight = head.get_sight(powered) + see_invisible = head.get_invisible(powered) + if(body && (body.pilot_coverage < 100 || body.transparent_cabin) || !hatch_closed) sight &= ~BLIND + if(sight & BLIND && !was_blind) + for(var/mob/pilot in pilots) + to_chat(pilot, SPAN_WARNING("The sensors are not operational and you cannot see a thing!")) /mob/living/exosuit/additional_sight_flags() return sight /mob/living/exosuit/additional_see_invisible() return see_invisible - diff --git a/code/modules/mechs/mech_movement.dm b/code/modules/mechs/mech_movement.dm index a95117d91c0b..7bc1f6bae1b1 100644 --- a/code/modules/mechs/mech_movement.dm +++ b/code/modules/mechs/mech_movement.dm @@ -1,60 +1,86 @@ /mob/living/exosuit movement_handlers = list( - /datum/movement_handler/deny_multiz, + /datum/movement_handler/mob/delay/exosuit, /datum/movement_handler/mob/space/exosuit, + /datum/movement_handler/mob/multiz, /datum/movement_handler/mob/exosuit ) /mob/living/exosuit/Move() . = ..() if(.) - if(!istype(loc, /turf/space)) + if(!isspaceturf(loc)) playsound(src.loc, mech_step_sound, 40, 1) + for(var/mob/pilot as anything in pilots) + pilot.refresh_hud_element(HUD_UP_HINT) - var/turf/B = GetAbove(src) +//Inertia drift making us face direction makes exosuit flight a bit difficult, plus newtonian flight model yo +/mob/living/exosuit/set_dir(ndir) + if(inertia_dir && inertia_dir == ndir) + return ..(dir) + return ..(ndir) - for(var/thing in pilots) - var/mob/pilot = thing - if(pilot.up_hint) - pilot.up_hint.icon_state = "uphint[(B ? B.is_open() : 0)]" - -/mob/living/exosuit/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = src.loc) +/mob/living/exosuit/can_fall(anchor_bypass = FALSE, turf/location_override = loc) //mechs are always anchored, so falling should always ignore it - if(..(TRUE, location_override)) + if((. = ..(TRUE, location_override))) return !(can_overcome_gravity()) +//For swimming +// /mob/living/exosuit/can_float() +// return FALSE //Nope + +/datum/movement_handler/mob/delay/exosuit + expected_host_type = /mob/living/exosuit + +/datum/movement_handler/mob/delay/exosuit/MayMove(mob/mover, is_external) + var/mob/living/exosuit/exosuit = host + if(mover && (mover != exosuit) && (!(mover in exosuit.pilots)) && is_external) + return MOVEMENT_PROCEED + else if(world.time >= next_move) + return MOVEMENT_PROCEED + return MOVEMENT_STOP + +/datum/movement_handler/mob/delay/exosuit/DoMove(direction, mob/mover, is_external) //Delay must be handled by other handlers. + return + +/mob/living/exosuit/SetMoveCooldown(timeout) + var/datum/movement_handler/mob/delay/delay = GetMovementHandler(/datum/movement_handler/mob/delay/exosuit) + if(delay) + delay.SetDelay(timeout) + +/mob/living/exosuit/ExtraMoveCooldown(timeout) + var/datum/movement_handler/mob/delay/delay = GetMovementHandler(/datum/movement_handler/mob/delay/exosuit) + if(delay) + delay.AddDelay(timeout) + /datum/movement_handler/mob/exosuit expected_host_type = /mob/living/exosuit - var/next_move -/datum/movement_handler/mob/exosuit/MayMove(var/mob/mover, var/is_external) +/datum/movement_handler/mob/exosuit/MayMove(mob/mover, is_external) var/mob/living/exosuit/exosuit = host - if(world.time < next_move) - return MOVEMENT_STOP if((!(mover in exosuit.pilots) && mover != exosuit) || exosuit.incapacitated() || mover.incapacitated()) return MOVEMENT_STOP if(!exosuit.legs) to_chat(mover, SPAN_WARNING("\The [exosuit] has no means of propulsion!")) - next_move = world.time + 3 // Just to stop them from getting spammed with messages. + exosuit.SetMoveCooldown(3) return MOVEMENT_STOP if(!exosuit.legs.motivator || !exosuit.legs.motivator.is_functional()) to_chat(mover, SPAN_WARNING("Your motivators are damaged! You can't move!")) - next_move = world.time + 15 + exosuit.SetMoveCooldown(15) return MOVEMENT_STOP if(exosuit.maintenance_protocols) to_chat(mover, SPAN_WARNING("Maintenance protocols are in effect.")) - next_move = world.time + 3 // Just to stop them from getting spammed with messages. + exosuit.SetMoveCooldown(3) return MOVEMENT_STOP - var/obj/item/cell/C = exosuit.get_cell() - if(!C || !C.check_charge(exosuit.legs.power_use * CELLRATE)) + var/obj/item/cell/cell = exosuit.get_cell() + if(!cell || !cell.check_charge(exosuit.legs.power_use * CELLRATE)) to_chat(mover, SPAN_WARNING("The power indicator flashes briefly.")) - next_move = world.time + 3 //On fast exosuits this got annoying fast + exosuit.SetMoveCooldown(3) //On fast exosuits this got annoying fast return MOVEMENT_STOP - - next_move = world.time + (exosuit.legs ? exosuit.legs.move_delay : 3) + return MOVEMENT_PROCEED -/datum/movement_handler/mob/exosuit/DoMove(var/direction, var/mob/mover, var/is_external) +/datum/movement_handler/mob/exosuit/DoMove(direction, mob/mover, is_external) var/mob/living/exosuit/exosuit = host var/moving_dir = direction @@ -66,67 +92,94 @@ else if(exosuit.emp_damage >= EMP_MOVE_DISRUPT && prob(30)) failed = TRUE if(failed) - moving_dir = pick(GLOB.cardinal - exosuit.dir) + moving_dir = pick(global.cardinal - exosuit.dir) exosuit.get_cell()?.use(exosuit.legs.power_use * CELLRATE) - if(exosuit.dir != moving_dir) + + if(direction & (UP|DOWN)) + var/txt_dir = direction & UP ? "upwards" : "downwards" + exosuit.visible_message(SPAN_NOTICE("\The [exosuit] moves [txt_dir].")) + + if(exosuit.dir != moving_dir && !(direction & (UP|DOWN))) playsound(exosuit.loc, exosuit.mech_turn_sound, 40,1) exosuit.set_dir(moving_dir) - next_move = world.time + exosuit.legs.turn_delay + exosuit.SetMoveCooldown(exosuit.legs.turn_delay) else + exosuit.SetMoveCooldown(exosuit.legs ? exosuit.legs.move_delay : 3) var/turf/target_loc = get_step(exosuit, direction) if(target_loc && exosuit.legs && exosuit.legs.can_move_on(exosuit.loc, target_loc) && exosuit.MayEnterTurf(target_loc)) exosuit.Move(target_loc) return MOVEMENT_HANDLED - /datum/movement_handler/mob/space/exosuit expected_host_type = /mob/living/exosuit // Space movement -/datum/movement_handler/mob/space/exosuit/MayMove(var/mob/mover, var/is_external) +/datum/movement_handler/mob/space/exosuit/DoMove(direction, mob/mover, is_external) + if(!mob.has_gravity() && (last_space_move_result == SPACE_MOVE_FORBIDDEN || (last_space_move_result == SPACE_MOVE_SUPPORTED && mob.handle_spaceslipping()))) + return MOVEMENT_HANDLED + mob.inertia_dir = 0 + +/datum/movement_handler/mob/space/exosuit/MayMove(mob/mover, is_external) if((mover != host) && is_external) return MOVEMENT_PROCEED if(!mob.has_gravity()) - allow_move = mob.Process_Spacemove(1) - if(!allow_move) + last_space_move_result = mob.is_space_movement_permitted(allow_movement = TRUE) + if(last_space_move_result == SPACE_MOVE_FORBIDDEN) return MOVEMENT_STOP - return MOVEMENT_PROCEED -/mob/living/exosuit/Check_Shoegrip()//mechs are always magbooting +/mob/living/exosuit/has_non_slip_footing() return TRUE -/mob/living/exosuit/Process_Spacemove() - if(has_gravity() || throwing || !isturf(loc) || length(grabbed_by) || check_space_footing() || locate(/obj/structure/lattice) in range(1, get_turf(src))) - anchored = 1 - return 1 - - anchored = 0 - return 0 - -/mob/living/exosuit/check_space_footing()//mechs can't push off things to move around in space, they stick to hull or float away - for(var/thing in RANGE_TURFS(src, 1)) - var/turf/T = thing - if(T.density || T.is_wall() || T.is_floor()) - return T +/mob/living/exosuit/has_magnetised_footing() + return TRUE -/mob/living/exosuit/space_do_move() - return 1 +/mob/living/exosuit/is_space_movement_permitted(allow_movement = FALSE) + . = SPACE_MOVE_FORBIDDEN + anchored = FALSE + //Regardless of modules, emp prevents control + + if(length(grabbed_by)) + for(var/obj/item/grab/grab as anything in grabbed_by) + if(grab.assailant == src) + continue + . = SPACE_MOVE_PERMITTED + break + + if(. != SPACE_MOVE_PERMITTED) + if(has_gravity() || throwing || !isturf(loc) || length(grabbed_by) || !can_slip(magboots_only = TRUE) || locate(/obj/structure/lattice) in range(1, get_turf(src))) + . = SPACE_MOVE_PERMITTED + else + var/obj/item/mech_equipment/ionjets/J = hardpoints[HARDPOINT_BACK] + if(istype(J) && ((allow_movement || J.stabilizers) && J.provides_thrust())) + . = SPACE_MOVE_PERMITTED + + if(. == SPACE_MOVE_PERMITTED) + anchored = TRUE + +/mob/living/exosuit/try_space_move(space_move_result, direction) + if(space_move_result == SPACE_MOVE_PERMITTED) + if(emp_damage >= EMP_MOVE_DISRUPT && prob(25)) + var/obj/item/mech_equipment/ionjets/J = hardpoints[HARDPOINT_BACK] + if(istype(J) && J.provides_thrust()) + to_chat(src, SPAN_WARNING("\The [J] misfire, drifting \the [src] off course!")) + SetMoveCooldown(15) //2 seconds of random rando panic drifting + step(src, pick(global.alldirs)) + return FALSE + return ..() -/mob/living/exosuit/lost_in_space() +/mob/living/exosuit/overmap_can_discard() for(var/atom/movable/AM in contents) - if(!AM.lost_in_space()) + if(!AM.overmap_can_discard()) return FALSE - return !pilots.len + return LAZYLEN(pilots) <= 0 /mob/living/exosuit/fall_damage() - return 100 //Exosuits are big and heavy + return 175 //Exosuits are big and heavy -/mob/living/exosuit/handle_fall_effect(var/turf/landing) +/mob/living/exosuit/apply_fall_damage(var/turf/landing) // Return here if for any reason you shouldn´t take damage - ..() - var/damage = 30 //Enough to cause a malfunction if unlucky - apply_damage(rand(0, damage), BRUTE, BP_R_LEG) //Any leg is good, will damage both - + if(legs) + legs.handle_vehicle_fall() diff --git a/code/modules/mechs/mech_wreckage.dm b/code/modules/mechs/mech_wreckage.dm index 0d5786c14fe8..f52c3812e14a 100644 --- a/code/modules/mechs/mech_wreckage.dm +++ b/code/modules/mechs/mech_wreckage.dm @@ -1,50 +1,73 @@ /obj/structure/mech_wreckage name = "wreckage" - desc = "It might have some salvagable parts." - density = 1 - opacity = 1 - anchored = 1 + desc = "It might have some salvageable parts." + density = TRUE + opacity = TRUE + anchored = TRUE icon_state = "wreck" icon = 'icons/mecha/mech_part_items.dmi' var/prepared + var/list/loot_pool /obj/structure/mech_wreckage/Initialize(mapload, var/mob/living/exosuit/exosuit, var/gibbed) . = ..(mapload) if(exosuit) - name = "wreckage of \the [exosuit.name]" + name = "wreckage of \the [exosuit]" + loot_pool = list() if(!gibbed) for(var/obj/item/thing in list(exosuit.arms, exosuit.legs, exosuit.head, exosuit.body)) if(thing && prob(40)) - thing.forceMove(src) + loot_pool += thing + if(thing == exosuit.arms) + exosuit.arms = null + else if(thing == exosuit.legs) + exosuit.legs = null + else if(thing == exosuit.head) + exosuit.head = null + else if(thing == exosuit.body) + exosuit.body = null for(var/hardpoint in exosuit.hardpoints) if(exosuit.hardpoints[hardpoint] && prob(40)) var/obj/item/thing = exosuit.hardpoints[hardpoint] if(exosuit.remove_system(hardpoint)) - thing.forceMove(src) + loot_pool += thing + + if(!QDELETED(exosuit)) + qdel(exosuit) + + if(length(loot_pool)) + if(loc) + for(var/atom/movable/thing as anything in loot_pool) + if(ispath(thing) && prob(loot_pool[thing])) + thing = new thing(src) + if(istype(thing, /obj/item/mech_component)) + var/obj/item/mech_component/comp = thing + comp.prebuild() + if(istype(thing)) + thing.forceMove(src) + loot_pool = null -/obj/structure/mech_wreckage/powerloader/Initialize(mapload) - . = ..(mapload, new /mob/living/exosuit/premade/powerloader(loc), FALSE) /obj/structure/mech_wreckage/attack_hand(var/mob/user) - if(contents.len) - var/obj/item/thing = pick(contents) - if(istype(thing)) - thing.forceMove(get_turf(user)) - user.put_in_hands(thing) - to_chat(user, "You retrieve \the [thing] from \the [src].") - return - return ..() + var/list/contained_atoms = get_contained_external_atoms() + if(!length(contained_atoms) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/obj/item/thing = pick(contained_atoms) + thing.forceMove(get_turf(user)) + user.put_in_hands(thing) + to_chat(user, "You retrieve \the [thing] from \the [src].") + return TRUE -/obj/structure/mech_wreckage/attackby(var/obj/item/W, var/mob/user) +/obj/structure/mech_wreckage/attackby(var/obj/item/used_item, var/mob/user) var/cutting - if(isWelder(W)) - var/obj/item/weldingtool/WT = W - if(WT.isOn()) + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item + if(welder.isOn()) cutting = TRUE else - to_chat(user, SPAN_WARNING("Turn \the [WT] on, first.")) - else if(istype(W, /obj/item/gun/energy/plasmacutter)) + to_chat(user, SPAN_WARNING("Turn \the [welder] on, first.")) + else if(istype(used_item, /obj/item/gun/energy/plasmacutter)) cutting = TRUE if(cutting) @@ -55,19 +78,18 @@ to_chat(user, SPAN_WARNING("\The [src] has already been weakened.")) return 1 - else if(isWrench(W)) + else if(IS_WRENCH(used_item)) if(prepared) to_chat(user, SPAN_NOTICE("You finish dismantling \the [src].")) - new /obj/item/stack/material/steel(get_turf(src),rand(5,10)) + SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(src), rand(5, 10)) qdel(src) else to_chat(user, SPAN_WARNING("It's too solid to dismantle. Try cutting through some of the bigger bits.")) return 1 - else if(istype(W) && W.force > 20) - visible_message(SPAN_DANGER("\The [src] has been smashed with \the [W] by \the [user]!")) + else if(istype(used_item) && used_item.expend_attack_force(user) > 20) + visible_message(SPAN_DANGER("\The [src] has been smashed with \the [used_item] by \the [user]!")) if(prob(20)) - new /obj/item/stack/material/steel(get_turf(src),rand(1,3)) - qdel(src) + physically_destroyed() return 1 return ..() @@ -77,4 +99,4 @@ thing.forceMove(get_turf(src)) else qdel(thing) - ..() + return ..() diff --git a/code/modules/mechs/premade/_premade.dm b/code/modules/mechs/premade/_premade.dm index c22380cbc59c..6498521605a7 100644 --- a/code/modules/mechs/premade/_premade.dm +++ b/code/modules/mechs/premade/_premade.dm @@ -1,25 +1,36 @@ -//GLOBAL_LIST_INIT(mech_decals, (icon_states('icons/mecha/mech_decals.dmi')-list("template", "mask"))) +//var/list/mech_decals = (icon_states('icons/mecha/mech_decals.dmi')-list("template", "mask"))) /mob/living/exosuit/premade name = "impossible exosuit" desc = "It seems to be saying 'please let me die'." + abstract_type = /mob/living/exosuit/premade + icon = 'icons/mecha/mecha_preview.dmi' + icon_state = "preview" + pixel_x = 0 + pixel_y = 0 var/decal + var/decal_blend = BLEND_MULTIPLY /mob/living/exosuit/premade/Initialize() - if(arms) - arms.decal = decal - arms.prebuild() - if(legs) - legs.decal = decal - legs.prebuild() - if(head) - head.decal = decal - head.prebuild() - if(body) - body.decal = decal - body.prebuild() + + // Reset our mapping helpers. + default_pixel_x = -8 + default_pixel_y = 0 + pixel_x = default_pixel_x + pixel_y = default_pixel_y + icon = null + icon_state = null + + for(var/obj/item/mech_component/comp in list(arms, legs, head, body)) + if(decal) + comp.decal = decal + if(!isnull(decal_blend)) + comp.decal_blend = decal_blend + comp.prebuild() + if(!material) - material = decls_repository.get_decl(/decl/material/solid/metal/steel) + material = GET_DECL(/decl/material/solid/metal/steel) + . = ..() spawn_mech_equipment() @@ -29,12 +40,9 @@ /mob/living/exosuit/premade/random name = "mismatched exosuit" - desc = "It seems to have been roughly thrown together and then spraypainted a single colour." + desc = "It seems to have been roughly thrown together and then spray-painted a single colour." /mob/living/exosuit/premade/random/Initialize(mapload, var/obj/structure/heavy_vehicle_frame/source_frame, var/super_random = FALSE, var/using_boring_colours = FALSE) - //if(!prob(100/(LAZYLEN(GLOB.mech_decals)+1))) - // decal = pick(GLOB.mech_decals) - var/list/use_colours if(using_boring_colours) use_colours = list( @@ -129,19 +137,19 @@ var/mech_colour = super_random ? FALSE : pick(use_colours) if(!arms) - var/armstype = pick(typesof(/obj/item/mech_component/manipulators)-/obj/item/mech_component/manipulators) + var/armstype = pick(subtypesof(/obj/item/mech_component/manipulators)) arms = new armstype(src) arms.color = mech_colour ? mech_colour : pick(use_colours) if(!legs) - var/legstype = pick(typesof(/obj/item/mech_component/propulsion)-/obj/item/mech_component/propulsion) + var/legstype = pick(subtypesof(/obj/item/mech_component/propulsion)) legs = new legstype(src) legs.color = mech_colour ? mech_colour : pick(use_colours) if(!head) - var/headtype = pick(typesof(/obj/item/mech_component/sensors)-/obj/item/mech_component/sensors) + var/headtype = pick(subtypesof(/obj/item/mech_component/sensors)) head = new headtype(src) head.color = mech_colour ? mech_colour : pick(use_colours) if(!body) - var/bodytype = pick(typesof(/obj/item/mech_component/chassis)-/obj/item/mech_component/chassis) + var/bodytype = pick(subtypesof(/obj/item/mech_component/chassis)) body = new bodytype(src) body.color = mech_colour ? mech_colour : pick(use_colours) . = ..() @@ -150,7 +158,7 @@ /mob/living/exosuit/premade/random/normal /mob/living/exosuit/premade/random/boring/Initialize(mapload, var/obj/structure/heavy_vehicle_frame/source_frame) - ..(mapload, source_frame, using_boring_colours = TRUE) + . = ..(mapload, source_frame, using_boring_colours = TRUE) /mob/living/exosuit/premade/random/extra/Initialize(mapload, var/obj/structure/heavy_vehicle_frame/source_frame) - ..(mapload, source_frame, super_random = TRUE) + . = ..(mapload, source_frame, super_random = TRUE) diff --git a/code/modules/mechs/premade/combat.dm b/code/modules/mechs/premade/combat.dm index 5c0c06b8f2aa..ec7bc6b2688f 100644 --- a/code/modules/mechs/premade/combat.dm +++ b/code/modules/mechs/premade/combat.dm @@ -4,24 +4,33 @@ /mob/living/exosuit/premade/combat/Initialize() if(!arms) - arms = new /obj/item/mech_component/manipulators/combat(src) - arms.color = COLOR_DARK_GUNMETAL + arms = new /obj/item/mech_component/manipulators/combat/painted(src) if(!legs) - legs = new /obj/item/mech_component/propulsion/combat(src) - legs.color = COLOR_DARK_GUNMETAL + legs = new /obj/item/mech_component/propulsion/combat/painted(src) if(!head) - head = new /obj/item/mech_component/sensors/combat(src) - head.color = COLOR_DARK_GUNMETAL + head = new /obj/item/mech_component/sensors/combat/painted(src) if(!body) - body = new /obj/item/mech_component/chassis/combat(src) - body.color = COLOR_DARK_GUNMETAL + body = new /obj/item/mech_component/chassis/combat/painted(src) . = ..() /mob/living/exosuit/premade/combat/spawn_mech_equipment() ..() install_system(new /obj/item/mech_equipment/mounted_system/taser(src), HARDPOINT_LEFT_HAND) - install_system(new /obj/item/mech_equipment/mounted_system/taser/ion(src), HARDPOINT_RIGHT_HAND) + install_system(new /obj/item/mech_equipment/mounted_system/projectile/assault_rifle(src), HARDPOINT_RIGHT_HAND) + install_system(new /obj/item/mech_equipment/flash(src), HARDPOINT_LEFT_SHOULDER) + install_system(new /obj/item/mech_equipment/light(src), HARDPOINT_RIGHT_SHOULDER) + +/mob/living/exosuit/premade/combat/military + decal = "cammo1" + +/mob/living/exosuit/premade/combat/military/alpine + decal = "cammo2" + +/mob/living/exosuit/premade/combat/military/Initialize() + . = ..() + for(var/obj/thing in list(arms,legs,head,body)) + thing.color = COLOR_WHITE /obj/item/mech_component/manipulators/combat name = "combat arms" @@ -31,6 +40,9 @@ action_delay = 10 power_use = 50 +/obj/item/mech_component/manipulators/combat/painted + color = COLOR_DARK_GUNMETAL + /obj/item/mech_component/propulsion/combat name = "combat legs" exosuit_desc_string = "sleek hydraulic legs" @@ -39,6 +51,9 @@ turn_delay = 3 power_use = 20 +/obj/item/mech_component/propulsion/combat/painted + color = COLOR_DARK_GUNMETAL + /obj/item/mech_component/sensors/combat name = "combat sensors" gender = PLURAL @@ -49,6 +64,9 @@ power_use = 200 material = /decl/material/solid/metal/steel +/obj/item/mech_component/sensors/combat/painted + color = COLOR_DARK_GUNMETAL + /obj/item/mech_component/sensors/combat/prebuild() ..() software = new(src) @@ -58,12 +76,14 @@ name = "sealed exosuit chassis" hatch_descriptor = "canopy" pilot_coverage = 100 - transparent_cabin = TRUE exosuit_desc_string = "an armoured chassis" icon_state = "combat_body" power_use = 40 material = /decl/material/solid/metal/steel +/obj/item/mech_component/chassis/combat/painted + color = COLOR_DARK_GUNMETAL + /obj/item/mech_component/chassis/combat/prebuild() . = ..() m_armour = new /obj/item/robot_parts/robot_component/armour/exosuit/combat(src) @@ -77,5 +97,18 @@ "[WEST]" = list("x" = 12, "y" = 8) ) ) - + . = ..() + +/obj/structure/mech_wreckage/military + name = "military exosuit wreckage" + loot_pool = list( + /obj/item/mech_equipment/mounted_system/taser = 80, + /obj/item/mech_equipment/mounted_system/taser/ion = 80, + /obj/item/mech_equipment/flash = 50, + /obj/item/mech_equipment/light = 50, + /obj/item/mech_component/manipulators/combat/painted = 40, + /obj/item/mech_component/propulsion/combat/painted = 40, + /obj/item/mech_component/sensors/combat/painted = 40, + /obj/item/mech_component/chassis/combat/painted = 40 + ) diff --git a/code/modules/mechs/premade/exploration.dm b/code/modules/mechs/premade/exploration.dm new file mode 100644 index 000000000000..424a08d64051 --- /dev/null +++ b/code/modules/mechs/premade/exploration.dm @@ -0,0 +1,48 @@ +/mob/living/exosuit/premade/light/exploration + name = "exploration mech" + desc = "It looks a bit charred." + +/obj/item/mech_component/manipulators/powerloader/exploration + color = COLOR_PURPLE + +/obj/item/mech_component/chassis/pod/exploration + color = COLOR_GUNMETAL + +/obj/item/mech_component/propulsion/tracks/exploration + color = COLOR_GUNMETAL + +/mob/living/exosuit/premade/light/exploration/Initialize() + if(!body) + body = new /obj/item/mech_component/chassis/pod/exploration(src) + if(!legs) + legs = new /obj/item/mech_component/propulsion/tracks/exploration(src) + if(!arms) + arms = new /obj/item/mech_component/manipulators/powerloader/exploration(src) + + . = ..() + + //Damage it + var/list/parts = list(arms,legs,head,body) + var/obj/item/mech_component/damaged = pick(parts) + damaged.take_burn_damage((damaged.max_damage / 4 ) * MECH_COMPONENT_DAMAGE_DAMAGED) + if(prob(33)) + parts -= damaged + damaged = pick(parts) + damaged.take_burn_damage((damaged.max_damage / 4 ) * MECH_COMPONENT_DAMAGE_DAMAGED) + +/mob/living/exosuit/premade/light/exploration/spawn_mech_equipment() + install_system(new /obj/item/mech_equipment/light(src), HARDPOINT_HEAD) + install_system(new /obj/item/mech_equipment/clamp(src), HARDPOINT_RIGHT_HAND) + install_system(new /obj/item/mech_equipment/mounted_system/taser/plasma(src), HARDPOINT_LEFT_HAND) + +/obj/structure/mech_wreckage/exploration + name = "exploration exosuit wreckage" + loot_pool = list( + /obj/item/mech_component/manipulators/powerloader/exploration = 40, + /obj/item/mech_component/chassis/pod/exploration = 40, + /obj/item/mech_component/propulsion/tracks/exploration = 40, + /obj/item/mech_component/sensors/light/painted = 40, + /obj/item/mech_equipment/light = 50, + /obj/item/mech_equipment/clamp = 80, + /obj/item/mech_equipment/mounted_system/taser/plasma = 80 + ) diff --git a/code/modules/mechs/premade/heavy.dm b/code/modules/mechs/premade/heavy.dm index bb5934f24803..e1dfd62d77f5 100644 --- a/code/modules/mechs/premade/heavy.dm +++ b/code/modules/mechs/premade/heavy.dm @@ -2,20 +2,27 @@ name = "Heavy exosuit" desc = "A heavily armored combat exosuit." +/obj/item/mech_component/manipulators/heavy/painted + color = COLOR_TITANIUM + +/obj/item/mech_component/propulsion/heavy/painted + color = COLOR_TITANIUM + +/obj/item/mech_component/sensors/heavy/painted + color = COLOR_TITANIUM + +/obj/item/mech_component/chassis/heavy/painted + color = COLOR_TITANIUM + /mob/living/exosuit/premade/heavy/Initialize() if(!arms) - arms = new /obj/item/mech_component/manipulators/heavy(src) - arms.color = COLOR_TITANIUM + arms = new /obj/item/mech_component/manipulators/heavy/painted(src) if(!legs) - legs = new /obj/item/mech_component/propulsion/heavy(src) - legs.color = COLOR_TITANIUM + legs = new /obj/item/mech_component/propulsion/heavy/painted(src) if(!head) - head = new /obj/item/mech_component/sensors/heavy(src) - head.color = COLOR_TITANIUM + head = new /obj/item/mech_component/sensors/heavy/painted(src) if(!body) - body = new /obj/item/mech_component/chassis/heavy(src) - body.color = COLOR_TITANIUM - + body = new /obj/item/mech_component/chassis/heavy/painted(src) . = ..() /mob/living/exosuit/premade/heavy/spawn_mech_equipment() @@ -75,6 +82,14 @@ matter = list(/decl/material/solid/metal/uranium = MATTER_AMOUNT_REINFORCEMENT) /obj/item/mech_component/chassis/heavy/prebuild() + pilot_positions = list( + list( + "[NORTH]" = list("x" = 8, "y" = 8), + "[SOUTH]" = list("x" = 9, "y" = 2), + "[EAST]" = list("x" = 4, "y" = 8), + "[WEST]" = list("x" = 12, "y" = 8) + ) + ) . = ..() m_armour = new /obj/item/robot_parts/robot_component/armour/exosuit/combat(src) @@ -92,4 +107,16 @@ /mob/living/exosuit/premade/heavy/merc/spawn_mech_equipment() install_system(new /obj/item/mech_equipment/mounted_system/taser(src), HARDPOINT_LEFT_HAND) install_system(new /obj/item/mech_equipment/mounted_system/taser/laser(src), HARDPOINT_RIGHT_HAND) - install_system(new /obj/item/mech_equipment/shields(src), HARDPOINT_BACK) \ No newline at end of file + install_system(new /obj/item/mech_equipment/shields(src), HARDPOINT_BACK) + +/obj/structure/mech_wreckage/heavy + name = "heavy exosuit wreckage" + loot_pool = list( + /obj/item/mech_equipment/mounted_system/taser = 80, + /obj/item/mech_equipment/mounted_system/taser/laser = 80, + /obj/item/mech_equipment/shields = 80, + /obj/item/mech_component/manipulators/heavy/painted = 40, + /obj/item/mech_component/propulsion/heavy/painted = 40, + /obj/item/mech_component/sensors/heavy/painted = 40, + /obj/item/mech_component/chassis/heavy/painted = 40 + ) diff --git a/code/modules/mechs/premade/light.dm b/code/modules/mechs/premade/light.dm index 6383524119a0..26dc7e2af41e 100644 --- a/code/modules/mechs/premade/light.dm +++ b/code/modules/mechs/premade/light.dm @@ -2,19 +2,27 @@ name = "light exosuit" desc = "A light and agile exosuit." +/obj/item/mech_component/manipulators/light/painted + color = COLOR_OFF_WHITE + +/obj/item/mech_component/propulsion/light/painted + color = COLOR_OFF_WHITE + +/obj/item/mech_component/sensors/light/painted + color = COLOR_OFF_WHITE + +/obj/item/mech_component/chassis/light/painted + color = COLOR_OFF_WHITE + /mob/living/exosuit/premade/light/Initialize() if(!arms) - arms = new /obj/item/mech_component/manipulators/light(src) - arms.color = COLOR_OFF_WHITE + arms = new /obj/item/mech_component/manipulators/light/painted(src) if(!legs) - legs = new /obj/item/mech_component/propulsion/light(src) - legs.color = COLOR_OFF_WHITE + legs = new /obj/item/mech_component/propulsion/light/painted(src) if(!head) - head = new /obj/item/mech_component/sensors/light(src) - head.color = COLOR_OFF_WHITE + head = new /obj/item/mech_component/sensors/light/painted(src) if(!body) - body = new /obj/item/mech_component/chassis/light(src) - body.color = COLOR_OFF_WHITE + body = new /obj/item/mech_component/chassis/light/painted(src) . = ..() @@ -68,13 +76,12 @@ hatch_descriptor = "canopy" pilot_coverage = 100 transparent_cabin = TRUE - hide_pilot = TRUE //Sprite too small, legs clip through, so for now hide pilot exosuit_desc_string = "an open and light chassis" icon_state = "light_body" max_damage = 50 power_use = 5 has_hardpoints = list(HARDPOINT_BACK) - desc = "The Veymed Odysseus series cockpits combine ultralight materials and clear aluminum laminates to provide an optimized cockpit experience." + desc = "The Veymed Odysseus series cockpits combine ultralight materials and clear aluminium laminates to provide an optimized cockpit experience." climb_time = 15 material = /decl/material/solid/metal/steel @@ -85,10 +92,10 @@ /obj/item/mech_component/chassis/light/Initialize() pilot_positions = list( list( - "[NORTH]" = list("x" = 8, "y" = -2), - "[SOUTH]" = list("x" = 8, "y" = -2), - "[EAST]" = list("x" = 1, "y" = -2), - "[WEST]" = list("x" = 9, "y" = -2) + "[NORTH]" = list("x" = 8, "y" = 0), + "[SOUTH]" = list("x" = 8, "y" = 0), + "[EAST]" = list("x" = 3, "y" = 0), + "[WEST]" = list("x" = 13, "y" = 0) ) ) . = ..() diff --git a/code/modules/mechs/premade/misc.dm b/code/modules/mechs/premade/misc.dm index 11f6fc3e0485..dafb3bc44d58 100644 --- a/code/modules/mechs/premade/misc.dm +++ b/code/modules/mechs/premade/misc.dm @@ -25,7 +25,6 @@ hatch_descriptor = "hatch" pilot_coverage = 100 transparent_cabin = TRUE - hide_pilot = TRUE //Sprite too small, legs clip through, so for now hide pilot exosuit_desc_string = "a spherical chassis" icon_state = "pod_body" max_damage = 70 @@ -36,4 +35,21 @@ /obj/item/mech_component/chassis/pod/prebuild() . = ..() - m_armour = new /obj/item/robot_parts/robot_component/armour/exosuit/radproof(src) \ No newline at end of file + m_armour = new /obj/item/robot_parts/robot_component/armour/exosuit/radproof(src) + +/obj/item/mech_component/chassis/pod/Initialize() + pilot_positions = list( + list( + "[NORTH]" = list("x" = 8, "y" = 4), + "[SOUTH]" = list("x" = 8, "y" = 4), + "[EAST]" = list("x" = 12, "y" = 4), + "[WEST]" = list("x" = 4, "y" = 4) + ), + list( + "[NORTH]" = list("x" = 8, "y" = 8), + "[SOUTH]" = list("x" = 8, "y" = 8), + "[EAST]" = list("x" = 10, "y" = 8), + "[WEST]" = list("x" = 6, "y" = 8) + ) + ) + . = ..() diff --git a/code/modules/mechs/premade/powerloader.dm b/code/modules/mechs/premade/powerloader.dm index e31cc46370bf..20c9babd52fd 100644 --- a/code/modules/mechs/premade/powerloader.dm +++ b/code/modules/mechs/premade/powerloader.dm @@ -2,25 +2,32 @@ name = "power loader" desc = "An ancient, but well-liked cargo handling exosuit." -/mob/living/exosuit/premade/powerloader/Initialize() - if(!arms) - arms = new /obj/item/mech_component/manipulators/powerloader(src) - arms.color = "#ffbc37" - if(!legs) - legs = new /obj/item/mech_component/propulsion/powerloader(src) - legs.color = "#ffbc37" - if(!head) - head = new /obj/item/mech_component/sensors/powerloader(src) - head.color = "#ffbc37" - if(!body) - body = new /obj/item/mech_component/chassis/powerloader(src) - body.color = "#ffdc37" +/obj/item/mech_component/manipulators/powerloader/painted + color = "#ffbc37" + +/obj/item/mech_component/propulsion/powerloader/painted + color = "#ffbc37" +/obj/item/mech_component/sensors/powerloader/painted + color = "#ffbc37" + +/obj/item/mech_component/chassis/powerloader/painted + color = "#ffdc37" + +/mob/living/exosuit/premade/powerloader/Initialize() + if(!arms) + arms = new /obj/item/mech_component/manipulators/powerloader/painted(src) + if(!legs) + legs = new /obj/item/mech_component/propulsion/powerloader/painted(src) + if(!head) + head = new /obj/item/mech_component/sensors/powerloader/painted(src) + if(!body) + body = new /obj/item/mech_component/chassis/powerloader/painted(src) . = ..() /mob/living/exosuit/premade/powerloader/spawn_mech_equipment() ..() - install_system(new /obj/item/mech_equipment/drill(src), HARDPOINT_LEFT_HAND) + install_system(new /obj/item/mech_equipment/drill/steel(src), HARDPOINT_LEFT_HAND) install_system(new /obj/item/mech_equipment/clamp(src), HARDPOINT_RIGHT_HAND) /obj/item/mech_component/manipulators/powerloader @@ -84,37 +91,55 @@ ) . = ..() +/mob/living/exosuit/premade/powerloader/mechete/Initialize() + . = ..() + + if (arms) + arms.color = "#6c8aaf" + if (legs) + legs.color = "#6c8aaf" + if (head) + head.color = "#6c8aaf" + if (body) + body.color = "#6c8aaf" + +/mob/living/exosuit/premade/powerloader/mechete/spawn_mech_equipment() + install_system(new /obj/item/mech_equipment/ballistic_shield(src), HARDPOINT_LEFT_HAND) + install_system(new /obj/item/mech_equipment/mounted_system/melee/machete(src), HARDPOINT_RIGHT_HAND) + /mob/living/exosuit/premade/powerloader/flames_red name = "APLU \"Firestarter\"" desc = "An ancient, but well-liked cargo handling exosuit. This one has cool red flames." decal = "flames_red" + decal_blend = BLEND_OVERLAY /mob/living/exosuit/premade/powerloader/flames_blue name = "APLU \"Burning Chrome\"" desc = "An ancient, but well-liked cargo handling exosuit. This one has cool blue flames." decal = "flames_blue" - + decal_blend = BLEND_OVERLAY /mob/living/exosuit/premade/firefighter name = "firefighting exosuit" desc = "A mix and match of industrial parts designed to withstand fires." /mob/living/exosuit/premade/firefighter/Initialize() - . = ..() - if(!arms) + if(!arms) arms = new /obj/item/mech_component/manipulators/powerloader(src) arms.color = "#385b3c" - if(!legs) + if(!legs) legs = new /obj/item/mech_component/propulsion/powerloader(src) legs.color = "#385b3c" - if(!head) + if(!head) head = new /obj/item/mech_component/sensors/powerloader(src) head.color = "#385b3c" - if(!body) + if(!body) body = new /obj/item/mech_component/chassis/heavy(src) body.color = "#385b3c" - material = decls_repository.get_decl(/decl/material/solid/metal/plasteel/ocp) + material = GET_DECL(/decl/material/solid/metal/plasteel/ocp) + + . = ..() /mob/living/exosuit/premade/firefighter/spawn_mech_equipment() ..() @@ -147,4 +172,15 @@ /mob/living/exosuit/premade/powerloader/old/spawn_mech_equipment() install_system(new /obj/item/mech_equipment/light(src), HARDPOINT_HEAD) install_system(new /obj/item/mech_equipment/clamp(src), HARDPOINT_LEFT_HAND) - install_system(new /obj/item/mech_equipment/clamp(src), HARDPOINT_RIGHT_HAND) \ No newline at end of file + install_system(new /obj/item/mech_equipment/clamp(src), HARDPOINT_RIGHT_HAND) + +/obj/structure/mech_wreckage/powerloader + name = "powerloader wrecakge" + loot_pool = list( + /obj/item/mech_component/manipulators/powerloader/painted = 40, + /obj/item/mech_component/propulsion/powerloader/painted = 40, + /obj/item/mech_component/sensors/powerloader/painted = 40, + /obj/item/mech_component/chassis/powerloader/painted = 40, + /obj/item/mech_equipment/drill/steel = 80, + /obj/item/mech_equipment/clamp = 80 + ) diff --git a/code/modules/merchant/merchant_guns.dm b/code/modules/merchant/merchant_guns.dm index c0522a25ded6..939a570aab1f 100644 --- a/code/modules/merchant/merchant_guns.dm +++ b/code/modules/merchant/merchant_guns.dm @@ -1,4 +1,4 @@ -/obj/item/gun/projectile/heavysniper/ant +/obj/item/gun/projectile/bolt_action/sniper/ant name = "anti-material rifle" desc = "A portable anti-armour rifle fitted with a scope, the HI PTR-7 Rifle was originally designed to used against armoured exosuits. It is capable of punching through windows and non-reinforced walls with ease. Fires armor piercing 14.5mm shells. This replica however fires pistol rounds." ammo_type = /obj/item/ammo_magazine/pistol/small @@ -12,5 +12,5 @@ return ..() /obj/item/gun/projectile/automatic/smg/usi - desc = "A cheap mass produced SMG. This one looks especially run-down. Uses pistol rounds." + desc = "A cheap mass-produced SMG. This one looks especially run-down. Uses pistol rounds." jam_chance = 20 \ No newline at end of file diff --git a/code/modules/merchant/merchant_machinery.dm b/code/modules/merchant/merchant_machinery.dm index 3e536da81bd1..5a61211ae088 100644 --- a/code/modules/merchant/merchant_machinery.dm +++ b/code/modules/merchant/merchant_machinery.dm @@ -3,8 +3,8 @@ desc = "Place things here to trade." icon = 'icons/obj/machines/teleporter.dmi' icon_state = "tele0" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE uncreated_component_parts = null construct_state = /decl/machine_construction/default/panel_closed @@ -12,7 +12,7 @@ /obj/machinery/merchant_pad/proc/get_target() var/turf/T = get_turf(src) for(var/a in T) - if(a == src || (!istype(a,/obj) && !istype(a,/mob/living)) || istype(a,/obj/effect)) + if(!is_valid_target(a)) continue return a @@ -20,6 +20,13 @@ . = list() var/turf/T = get_turf(src) for(var/a in T) - if(a == src || (!istype(a,/obj) && !istype(a,/mob/living)) || istype(a,/obj/effect)) + if(!is_valid_target(a)) continue - . += a \ No newline at end of file + . += a + +/obj/machinery/merchant_pad/proc/is_valid_target(atom/movable/thing) + if(!istype(thing)) + return FALSE + if(thing == src) + return FALSE + return thing.is_valid_merchant_pad_target() \ No newline at end of file diff --git a/code/modules/merchant/merchant_programs.dm b/code/modules/merchant/merchant_programs.dm index c0e926db459b..9eaf55156e0a 100644 --- a/code/modules/merchant/merchant_programs.dm +++ b/code/modules/merchant/merchant_programs.dm @@ -1,45 +1,71 @@ /datum/computer_file/program/merchant filename = "mlist" filedesc = "Merchant's List" - extended_desc = "Allows communication and trade between passing vessels, even while jumping." + extended_desc = "Allows communication and trade between vessels and trade hubs." program_icon_state = "comm" program_menu_icon = "cart" nanomodule_path = /datum/nano_module/program/merchant size = 12 usage_flags = PROGRAM_CONSOLE - required_access = access_merchant + read_access = list(access_merchant) + var/datum/trade_hub/current_hub + var/datum/trader/current_trader var/obj/machinery/merchant_pad/pad = null - var/current_merchant = 0 var/show_trades = 0 var/hailed_merchant = 0 var/last_comms = null var/temp = null var/bank = 0 //A straight up money till +/datum/computer_file/program/merchant/proc/get_current_hub(var/datum/trade_hub/supplied_hub) + if(supplied_hub) + current_hub = supplied_hub + var/obj/item/stock_parts/computer/hard_drive/hard_drive = holder?.resolve() + if(!istype(current_hub) || QDELETED(current_hub) || !hard_drive || !current_hub.is_accessible_from(get_turf(hard_drive))) + current_hub = null + current_trader = null + return current_hub + +/datum/computer_file/program/merchant/proc/get_current_trader() + var/datum/trade_hub/hub = get_current_hub() + if(QDELETED(hub) || QDELETED(current_trader) || (current_trader && !(current_trader in hub.traders))) + current_trader = null + return current_trader + +/datum/computer_file/program/merchant/Destroy() + current_hub = null + current_trader = null + . = ..() + +/datum/computer_file/program/merchant/proc/get_available_hubs() + . = list() + var/turf/T = get_turf(holder.resolve()) + for(var/datum/trade_hub/hub in SStrade.trade_hubs) + if(hub.is_accessible_from(T)) + . |= hub + /datum/nano_module/program/merchant name = "Merchant's List" -/datum/computer_file/program/merchant/proc/get_merchant(var/num) - if(num > SStrade.traders.len) - num = SStrade.traders.len - if(num) - return SStrade.traders[num] - -/datum/nano_module/program/merchant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/merchant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/show_trade = 0 var/hailed = 0 var/datum/trader/T if(program) var/datum/computer_file/program/merchant/P = program + T = P.get_current_trader() data["temp"] = P.temp - data["mode"] = !!P.current_merchant + data["mode"] = !isnull(T) data["last_comms"] = P.last_comms data["pad"] = !!P.pad data["bank"] = P.bank show_trade = P.show_trades hailed = P.hailed_merchant - T = P.get_merchant(P.current_merchant) + var/list/hub_data = list() + for(var/datum/trade_hub/hub in P.get_available_hubs()) + hub_data += list(list("name" = hub.name, "ref" = "\ref[hub]")) + data["hubs"] = hub_data data["mode"] = !!T if(T) data["traderName"] = T.name @@ -51,6 +77,7 @@ for(var/i in 1 to T.trading_items.len) trades += T.print_trading_items(i) data["trades"] = trades + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "merchant.tmpl", "Merchant List", 575, 700, state = state) @@ -74,7 +101,7 @@ if(istext(response)) last_comms = T.get_response(response, "No thank you.") else - last_comms = T.get_response("trade_complete", "Thank you!") + last_comms = T.get_response(TRADER_TRADE_COMPLETE, "Thank you!") T.trade(null,num, get_turf(pad)) bank -= response return @@ -92,14 +119,14 @@ if(pad) var/list/targets = pad.get_targets() for(var/target in targets) - if(!computer_emagged && istype(target,/mob/living/carbon/human)) + if(!computer_emagged && ishuman(target)) last_comms = "SAFETY LOCK ENABLED: SENTIENT MATTER UNTRANSMITTABLE" return var/response = T.offer_items_for_trade(targets,num, get_turf(pad), skill) if(istext(response)) - last_comms = T.get_response(response,"No, a million times no.") + last_comms = T.get_response(response, "No, a million times no.") else - last_comms = T.get_response("trade_complete","Thanks for your business!") + last_comms = T.get_response(TRADER_TRADE_COMPLETE, "Thanks for your business!") return last_comms = "PAD NOT CONNECTED" @@ -111,7 +138,7 @@ if(istext(response)) last_comms = T.get_response(response, "Nope. Nope nope nope.") else - last_comms = T.get_response("trade_complete", "Glad to be of service!") + last_comms = T.get_response(TRADER_TRADE_COMPLETE, "Glad to be of service!") bank += response return last_comms = "PAD NOT CONNECTED" @@ -155,39 +182,39 @@ get_money() if(href_list["PRG_main_menu"]) . = 1 - current_merchant = 0 + current_trader = null + current_hub = null + if(href_list["PRG_merchant_list"]) - if(SStrade.traders.len == 0) - . = 0 - temp = "Cannot find any traders within broadcasting range." - else - . = 1 - current_merchant = 1 - hailed_merchant = 0 + . = 1 + current_trader = null + current_hub = get_current_hub(locate(href_list["PRG_merchant_list"])) + if(current_hub && length(current_hub.traders)) + current_trader = current_hub.traders[1] last_comms = null + hailed_merchant = FALSE + else + temp = "There are no available traders at the target hub, or the target hub has moved out of range." + if(href_list["PRG_test_fire"]) . = 1 if(test_fire()) - temp = "Test Fire Successful" + temp = "Test fire successful." else - temp = "Test Fire Unsuccessful" + temp = "Test fire unsuccessful." if(href_list["PRG_scroll"]) . = 1 - var/scrolled = 0 - switch(href_list["PRG_scroll"]) - if("right") - scrolled = 1 - if("left") - scrolled = -1 - var/new_merchant = Clamp(current_merchant + scrolled, 1, SStrade.traders.len) - if(new_merchant != current_merchant) - hailed_merchant = 0 - last_comms = null - current_merchant = new_merchant - if(current_merchant) - var/datum/trader/T = get_merchant(current_merchant) + var/datum/trader/T = get_current_trader() + if(T) + var/new_merchant = (href_list["PRG_scroll"] == "right") ? next_in_list(T, current_hub.traders) : previous_in_list(T, current_hub.traders) + if(new_merchant != T) + hailed_merchant = 0 + last_comms = null + current_trader = new_merchant + var/datum/trader/T = get_current_trader() + if(T) if(!T.can_hail()) - last_comms = T.get_response("hail_deny", "No, I'm not speaking with you.") + last_comms = T.get_response(TRADER_HAIL_DENY, "No, I'm not speaking with you.") . = 1 else if(href_list["PRG_hail"]) diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm index be3138f21902..06ff4ce3e1b9 100644 --- a/code/modules/mining/abandonedcrates.dm +++ b/code/modules/mining/abandonedcrates.dm @@ -22,117 +22,114 @@ var/loot = rand(1, 100) switch(loot) if(1 to 5) // Common things go, 5% - new/obj/item/chems/food/drinks/bottle/rum(src) - new/obj/item/chems/food/drinks/bottle/whiskey(src) - new/obj/item/chems/food/snacks/grown/ambrosiadeus(src) - new/obj/item/flame/lighter/zippo(src) + new /obj/item/chems/drinks/bottle/rum(src) + new /obj/item/chems/drinks/bottle/whiskey(src) + new /obj/item/food/grown/ambrosiadeus(src) + new /obj/item/flame/fuelled/lighter/zippo(src) if(6 to 10) - new/obj/item/pickaxe/drill(src) - new/obj/item/taperecorder(src) - new/obj/item/clothing/suit/space(src) - new/obj/item/clothing/head/helmet/space(src) + new /obj/item/tool/drill(src) + new /obj/item/taperecorder(src) + new /obj/item/clothing/suit/space(src) + new /obj/item/clothing/head/helmet/space(src) if(11 to 15) - new/obj/item/chems/glass/beaker/advanced(src) + new /obj/item/chems/glass/beaker/advanced(src) if(16 to 20) - for(var/i = 0, i < 10, i++) - new/obj/item/ore/diamond(src) + new /obj/item/stack/material/ore/diamond(src, 10) if(21 to 25) for(var/i = 0, i < 3, i++) - new/obj/machinery/portable_atmospherics/hydroponics(src) + new /obj/machinery/portable_atmospherics/hydroponics(src) if(26 to 30) for(var/i = 0, i < 3, i++) - new/obj/item/chems/glass/beaker/noreact(src) + new /obj/item/chems/glass/beaker/noreact(src) if(31 to 35) var/obj/item/cash/cash = new(src) cash.adjust_worth(rand(300,800)) if(36 to 40) - new/obj/item/baton(src) + new /obj/item/baton(src) if(41 to 45) - new/obj/item/clothing/under/shorts/red(src) - new/obj/item/clothing/under/shorts/blue(src) + new /obj/item/clothing/pants/shorts/athletic/red(src) + new /obj/item/clothing/pants/shorts/athletic/blue(src) if(46 to 50) - new/obj/item/clothing/under/chameleon(src) + new/obj/item/clothing/jumpsuit/chameleon(src) for(var/i = 0, i < 7, i++) - new/obj/item/clothing/accessory/horrible(src) + new /obj/item/clothing/neck/tie/horrible(src) if(51 to 52) // Uncommon, 2% each - new/obj/item/classic_baton(src) + new /obj/item/classic_baton(src) if(53 to 54) - new/obj/item/latexballon(src) + new /obj/item/latexballon(src) if(55 to 56) - var/newitem = pick(typesof(/obj/item/toy/prize) - /obj/item/toy/prize) + var/newitem = pick(subtypesof(/obj/item/toy/prize)) new newitem(src) if(57 to 58) - new/obj/item/toy/balloon(src) + new /obj/item/toy/balloon(src) if(59 to 60) - new/obj/item/rig(src) + new /obj/item/rig(src) if(61 to 62) for(var/i = 0, i < 12, ++i) - new/obj/item/clothing/head/kitty(src) + new /obj/item/clothing/head/kitty(src) if(63 to 64) var/t = rand(4,7) for(var/i = 0, i < t, ++i) var/newcoin = pick(subtypesof(/obj/item/coin)) new newcoin(src) if(65 to 66) - new/obj/item/clothing/suit/ianshirt(src) + new /obj/item/clothing/suit/ianshirt(src) if(67 to 68) var/t = rand(4,7) for(var/i = 0, i < t, ++i) - var/newitem = pick(typesof(/obj/item/stock_parts) - /obj/item/stock_parts - /obj/item/stock_parts/subspace) + var/newitem = pick(subtypesof(/obj/item/stock_parts) - /obj/item/stock_parts/subspace) new newitem(src) if(69 to 70) - new/obj/item/pickaxe/silver(src) + new /obj/item/tool/pickaxe/titanium(src) if(71 to 72) - new/obj/item/pickaxe/drill(src) + new /obj/item/tool/drill(src) if(73 to 74) - new/obj/item/pickaxe/jackhammer(src) + new /obj/item/tool/hammer/jack(src) if(75 to 76) - new/obj/item/pickaxe/diamond(src) + new /obj/item/tool/pickaxe/ocp(src) if(77 to 78) - new/obj/item/pickaxe/diamonddrill(src) + new /obj/item/tool/drill/diamond(src) if(79 to 80) - new/obj/item/pickaxe/gold(src) + new /obj/item/tool/pickaxe/plasteel(src) if(81 to 82) - new/obj/item/gun/energy/plasmacutter(src) + new /obj/item/gun/energy/plasmacutter(src) if(83 to 84) - new/obj/item/sword/katana/toy(src) + new /obj/item/sword/katana/toy(src) if(85 to 88) - new/obj/item/seeds/random(src) + new /obj/item/seeds/random(src) if(89, 90) - new/obj/item/organ/internal/heart(src) - if(91) - new/obj/item/soulstone(src) - if(92) - new/obj/item/sword/katana(src) + new /obj/item/organ/internal/heart(src) + if(91,92) + new /obj/item/sword/katana(src) if(93) - new/obj/item/storage/firstaid/combat(src) // Probably the least OP + new /obj/item/firstaid/combat(src) // Probably the least OP if(94) // Why the hell not - new/obj/item/storage/backpack/clown(src) - new/obj/item/clothing/under/rank/clown(src) - new/obj/item/clothing/shoes/clown_shoes(src) - new/obj/item/clothing/mask/gas/clown_hat(src) - new/obj/item/bikehorn(src) - new/obj/item/pen/crayon/rainbow(src) - new/obj/item/chems/spray/waterflower(src) + new /obj/item/backpack/clown(src) + new /obj/item/clothing/costume/clown(src) + new /obj/item/clothing/shoes/clown_shoes(src) + new /obj/item/clothing/mask/gas/clown_hat(src) + new /obj/item/bikehorn(src) + new /obj/item/pen/crayon/rainbow(src) + new /obj/item/chems/spray/waterflower(src) if(95) - new/obj/item/clothing/under/mime(src) - new/obj/item/clothing/shoes/color/black(src) - new/obj/item/clothing/gloves/color/white(src) - new/obj/item/clothing/mask/gas/mime(src) - new/obj/item/clothing/head/beret(src) - new/obj/item/clothing/accessory/suspenders(src) - new/obj/item/pen/crayon/mime(src) + new /obj/item/clothing/costume/mime(src) + new /obj/item/clothing/shoes/color/black(src) + new /obj/item/clothing/gloves(src) + new /obj/item/clothing/mask/gas/mime(src) + new /obj/item/clothing/head/beret(src) + new /obj/item/clothing/suspenders(src) + new /obj/item/pen/crayon/mime(src) if(96) - new/obj/item/vampiric(src) + new /obj/item/vampiric(src) if(97) - new/obj/item/archaeological_find(src) + new /obj/random/archaeological_find(src) if(98) - new/obj/item/energy_blade/sword(src) + new /obj/item/energy_blade/sword(src) if(99) - new/obj/item/storage/belt/champion(src) - new/obj/item/clothing/mask/luchador(src) + new /obj/item/belt/champion(src) + new /obj/item/clothing/mask/luchador(src) if(100) - new/obj/item/clothing/head/bearpelt(src) + new /obj/item/clothing/head/bearpelt(src) /obj/structure/closet/crate/secure/loot/togglelock(mob/user) if(!locked) @@ -175,25 +172,25 @@ if(guesschar != code[i]) . = 0 -/obj/structure/closet/crate/secure/loot/attackby(obj/item/W, mob/user) - if(locked) - if (istype(W, /obj/item/multitool)) // Greetings Urist McProfessor, how about a nice game of cows and bulls? - to_chat(user, "DECA-CODE LOCK ANALYSIS:") - if (attempts == 1) - to_chat(user, "* Anti-Tamper system will activate on the next failed access attempt.") - else - to_chat(user, "* Anti-Tamper system will activate after [src.attempts] failed access attempts.") - if(lastattempt.len) - var/bulls = 0 - var/cows = 0 +/obj/structure/closet/crate/secure/loot/attackby(obj/item/used_item, mob/user) + if(!locked || !IS_MULTITOOL(used_item)) + return ..() + // Greetings Urist McProfessor, how about a nice game of cows and bulls? + to_chat(user, "DECA-CODE LOCK ANALYSIS:") + if (attempts == 1) + to_chat(user, "* Anti-Tamper system will activate on the next failed access attempt.") + else + to_chat(user, "* Anti-Tamper system will activate after [src.attempts] failed access attempts.") + if(lastattempt.len) + var/bulls = 0 + var/cows = 0 - var/list/code_contents = code.Copy() - for(var/i in 1 to codelen) - if(lastattempt[i] == code[i]) - ++bulls - else if(lastattempt[i] in code_contents) - ++cows - code_contents -= lastattempt[i] - to_chat(user, "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions.") - return - ..() + var/list/code_contents = code.Copy() + for(var/i in 1 to codelen) + if(lastattempt[i] == code[i]) + ++bulls + else if(lastattempt[i] in code_contents) + ++cows + code_contents -= lastattempt[i] + to_chat(user, "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions.") + return TRUE diff --git a/code/modules/mining/drilling/brace.dm b/code/modules/mining/drilling/brace.dm new file mode 100644 index 000000000000..44441e2f8347 --- /dev/null +++ b/code/modules/mining/drilling/brace.dm @@ -0,0 +1,56 @@ +/obj/structure/drill_brace + name = "mining drill brace" + desc = "A machinery brace for an industrial drill. It looks like it's about half a metre thick." + icon = 'icons/obj/mining_drill.dmi' + icon_state = "mining_brace" + density = TRUE + layer = ABOVE_HUMAN_LAYER + obj_flags = OBJ_FLAG_ROTATABLE|OBJ_FLAG_ANCHORABLE + var/obj/machinery/mining_drill/connected = null + +/obj/structure/drill_brace/Destroy() + if(connected) + disconnect_from_drill() + return ..() + +/obj/structure/drill_brace/on_update_icon() + icon_state = "mining_brace[connected ? "_active" : ""]" + return ..() + +/obj/structure/drill_brace/wrench_floor_bolts(mob/user, delay, obj/item/tool) + if(connected && connected.use_power != POWER_USE_OFF) + to_chat(user, SPAN_NOTICE("You can't work with the brace of a running drill!")) + return + if(isspaceturf(get_turf(src))) + to_chat(user, SPAN_NOTICE("You can't anchor something to empty space. Idiot.")) + return + + var/old_anchored = anchored + ..() // Call parent to try to actually anchor/unanchor it. + if(anchored != old_anchored) + if(anchored && connect_to_drill()) + to_chat(user, SPAN_NOTICE("You attach \the [src] to \the [connected].")) + else if(disconnect_from_drill()) + to_chat(user, SPAN_NOTICE("You detatch \the [src].")) + +/obj/structure/drill_brace/proc/connect_to_drill() + var/turf/front_turf = get_step(get_turf(src), dir) + if(!istype(front_turf)) + return FALSE + var/obj/machinery/mining_drill/drill = locate(/obj/machinery/mining_drill) in front_turf + if(drill) + connected = drill + connected.supports += src + connected.handle_supports() + update_icon() + return TRUE + return FALSE + +/obj/structure/drill_brace/proc/disconnect_from_drill() + if(!connected) + return FALSE + connected.supports -= src + connected.handle_supports() + connected = null + update_icon() + return TRUE diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm index d33b6769f12f..c3da14cb1ea6 100644 --- a/code/modules/mining/drilling/drill.dm +++ b/code/modules/mining/drilling/drill.dm @@ -1,311 +1,204 @@ -/obj/machinery/mining - icon = 'icons/obj/mining_drill.dmi' - anchored = 0 - use_power = POWER_USE_OFF //The drill takes power directly from a cell. - density = 1 - layer = ABOVE_HUMAN_LAYER //So it draws over mobs in the tile north of it. - construct_state = /decl/machine_construction/default/panel_closed - uncreated_component_parts = null - stat_immune = 0 - -/obj/machinery/mining/drill +/obj/machinery/mining_drill name = "mining drill head" desc = "An enormous drill." - icon_state = "mining_drill" + icon = 'icons/obj/mining_drill.dmi' + icon_state = "mining_drill_off" + layer = ABOVE_HUMAN_LAYER + anchored = FALSE + density = TRUE + use_power = POWER_USE_OFF power_channel = LOCAL active_power_usage = 10 KILOWATTS - base_type = /obj/machinery/mining/drill - var/braces_needed = 2 - var/list/supports = list() - var/supported = 0 - var/active = FALSE - var/list/resource_field = list() + idle_power_usage = 500 + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + base_type = /obj/machinery/mining_drill + z_flags = ZMM_WIDE_LOAD - //Upgrades - var/harvest_speed - var/capacity + /// The drill's FSM, keeping track of which state the drill is currently in. + var/datum/state_machine/drill/state_machine = null - //Flags - var/need_update_field = 0 - var/need_player_check = 0 + /// Ore that is presently inside of the drill, ready to be extracted. + var/list/contained_ore = list() -/obj/machinery/mining/drill/Process() - if(need_player_check) - return + /// Drill supports presently connected to the drill head. + var/list/supports = list() - check_supports() + /// How many braces are required for the drill to operate. + var/const/MINIMUM_SUPPORT_NUMBER = 2 - if(!active) return + /// List of turfs that the drill will attempt to mine. + var/list/turfs_to_mine = list() - if(!anchored) - system_error("system configuration error") - return + /// The turf that the drill is presently mining. + var/turf/current_turf = null - if(stat & NOPOWER) - system_error("insufficient charge") - return + //Upgrades + /// The radius for the drill to use when populating `turfs_to_mine`. Upgraded with scanning modules. + var/drill_radius = 2 - if(need_update_field) - get_resource_field() + /// The ore capacity for the drill. The drill will stop mining if it gets full. Upgraded with matter bins. + var/ore_capacity = 200 - if(world.time % 10 == 0) - update_icon() + /// How fast the drill mines out the ore contained within `turfs_to_mine`. Faster speed requires more power. Upgraded with micro lasers. + var/mining_speed = 1 - if(!active) - return + /// Modifies how much energy is required to extract one piece of ore, with diminishing returns for higher values. Upgraded with capacitors. + var/efficiency_rating = 1 - //Drill through the flooring, if any. - if(istype(get_turf(src), /turf/simulated/floor/asteroid)) - var/turf/simulated/floor/asteroid/T = get_turf(src) - if(!T.dug) - T.gets_dug() - else if(istype(get_turf(src), /turf/simulated/floor/exoplanet)) - var/turf/simulated/floor/exoplanet/T = get_turf(src) - if(T.diggable) - new /obj/structure/pit(T) - T.diggable = 0 - else if(istype(get_turf(src), /turf/simulated/floor)) - var/turf/simulated/floor/T = get_turf(src) - T.explosion_act(2) - - //Dig out the tasty ores. - if(length(resource_field)) - var/turf/simulated/harvesting = pick(resource_field) - - while(resource_field.len && !harvesting.resources) - harvesting.has_resources = 0 - harvesting.resources = null - resource_field -= harvesting - if(resource_field.len) - harvesting = pick(resource_field) - - if(!harvesting || !harvesting.resources) - return - - var/total_harvest = harvest_speed //Ore harvest-per-tick. - for(var/metal in harvesting.resources) - - if(contents.len >= capacity) - system_error("insufficient storage space") - set_active(FALSE) - need_player_check = 1 - update_icon() - return - - if(contents.len + total_harvest >= capacity) - total_harvest = capacity - contents.len - - if(total_harvest <= 0) - break - - var/create_ore = 0 - if(harvesting.resources[metal] >= total_harvest) - harvesting.resources[metal] -= total_harvest - create_ore = total_harvest - total_harvest = 0 - else - total_harvest -= harvesting.resources[metal] - create_ore = harvesting.resources[metal] - harvesting.resources -= metal - - for(var/i=1, i <= create_ore, i++) - new /obj/item/ore(src, metal) - - if(!length(harvesting.resources)) - harvesting.has_resources = 0 - harvesting.resources = null - resource_field -= harvesting - else - set_active(FALSE) - need_player_check = 1 - update_icon() + /// Determines how much less energy each capacitor rating reduces. Every capacitor after the first reduces the power draw by this amount each time. + var/const/EFFICIENCY_EXPONENT = 0.8 // Raise this closer to 1 to make capacitors less powerful. -/obj/machinery/mining/drill/proc/set_active(var/new_active) - if(active != new_active) - active = new_active - update_use_power(active ? POWER_USE_ACTIVE : POWER_USE_OFF) +/obj/machinery/mining_drill/Initialize() + state_machine = add_state_machine(src, /datum/state_machine/drill) + return ..() -/obj/machinery/mining/drill/cannot_transition_to(state_path) - if(active) - return SPAN_NOTICE("You must turn \the [src] off first.") +/obj/machinery/mining_drill/Destroy() + remove_state_machine(src, /datum/state_machine/drill) + turfs_to_mine.Cut() + current_turf = null + QDEL_NULL_LIST(contained_ore) + for(var/thing in supports) + var/obj/structure/drill_brace/B = thing + B.disconnect_from_drill() return ..() -/obj/machinery/mining/drill/components_are_accessible(path) - return !active && ..() - -/obj/machinery/mining/drill/physical_attack_hand(mob/user) - check_supports() - if(need_player_check) - if(can_use_power_oneoff(10 KILOWATTS)) - system_error("insufficient charge") - else if(anchored) - get_resource_field() - to_chat(user, "You hit the manual override and reset the drill's error checking.") - need_player_check = 0 - update_icon() - return TRUE - if(supported && !panel_open) - if(!(stat & NOPOWER)) - set_active(!active) - if(active) - visible_message("\The [src] lurches downwards, grinding noisily.") - need_update_field = 1 - else - visible_message("\The [src] shudders to a grinding halt.") +/obj/machinery/mining_drill/Process() + state_machine.evaluate() + var/decl/state/drill/current_state = state_machine.current_state + current_state.process(src) + +/obj/machinery/mining_drill/physical_attack_hand(mob/user) + if(!panel_open) + var/on = use_power ? TRUE : FALSE + on = !on + if(on) + update_use_power(POWER_USE_IDLE) else - to_chat(user, "The drill is unpowered.") - else - to_chat(user, "Turning on a piece of industrial machinery without sufficient bracing or wires exposed is a bad idea.") - - update_icon() - return TRUE - -/obj/machinery/mining/drill/on_update_icon() - if(need_player_check) - icon_state = "mining_drill_error" - else if(active) - var/status = Clamp(round( (contents.len / capacity) * 4 ), 0, 3) - icon_state = "mining_drill_active[status]" - else if(supported) - icon_state = "mining_drill_braced" + update_use_power(POWER_USE_OFF) + playsound(src, "button", 60) + to_chat(user, SPAN_NOTICE("You turn \the [src] [use_power ? "on" : "off"].")) + state_machine.evaluate() + return TRUE + return FALSE + +/obj/machinery/mining_drill/on_update_icon() + icon_state = "mining_drill_[use_power == POWER_USE_ACTIVE ? "on" : "off"]" + z_flags &= ~ZMM_MANGLE_PLANES + cut_overlays() + var/decl/state/drill/current_state = state_machine.current_state + if(current_state.light_icon_state) + add_overlay(emissive_overlay(icon, current_state.light_icon_state, src, SOUTH, current_state.light_color)) + z_flags |= ZMM_MANGLE_PLANES + set_light(2, 0.4, current_state.light_color) else - icon_state = "mining_drill" - return + set_light(0) + return ..() -/obj/machinery/mining/drill/RefreshParts() - ..() - harvest_speed = Clamp(total_component_rating_of_type(/obj/item/stock_parts/micro_laser), 0, 10) - capacity = 200 * Clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 10) - var/charge_multiplier = Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0.1, 10) - change_power_consumption(initial(active_power_usage) / charge_multiplier, POWER_USE_ACTIVE) +/obj/machinery/mining_drill/proc/handle_supports() + state_machine.evaluate() + anchored = length(supports) >= 1 ? TRUE : FALSE + if(can_fall()) + fall() -/obj/machinery/mining/drill/proc/check_supports() - supported = 0 +/obj/machinery/mining_drill/proc/reset_drill() + turfs_to_mine.Cut() + current_turf = null - if((!supports || !supports.len) && initial(anchored) == 0) - anchored = 0 - set_active(FALSE) - else - anchored = 1 +/obj/machinery/mining_drill/cannot_transition_to(state_path) + if(use_power != POWER_USE_OFF) + return SPAN_NOTICE("You must turn \the [src] off first.") + return ..() - if(supports && supports.len >= braces_needed) - supported = 1 +/obj/machinery/mining_drill/components_are_accessible(path) + return (use_power == POWER_USE_OFF) && ..() - update_icon() -/obj/machinery/mining/drill/proc/system_error(var/error) +/obj/machinery/mining_drill/RefreshParts() + . = ..() + drill_radius = 1 + total_component_rating_of_type(/obj/item/stock_parts/scanning_module) + ore_capacity = 200 * total_component_rating_of_type(/obj/item/stock_parts/matter_bin) + mining_speed = total_component_rating_of_type(/obj/item/stock_parts/micro_laser) + efficiency_rating = total_component_rating_of_type(/obj/item/stock_parts/capacitor) - if(error) - src.visible_message("\The [src] flashes a '[error]' warning.") - need_player_check = 1 - set_active(FALSE) - update_icon() + var/efficiency = EFFICIENCY_EXPONENT ** (efficiency_rating - 1) + change_power_consumption(initial(active_power_usage) * efficiency * mining_speed, POWER_USE_ACTIVE) -/obj/machinery/mining/drill/proc/get_resource_field() +/obj/machinery/mining_drill/proc/populate_turfs_to_mine() + turfs_to_mine.Cut() + var/list/turf_candidates = RANGE_TURFS(src, drill_radius) + for(var/thing in turf_candidates) + var/turf/T = thing + if(turf_has_ore(T)) + turfs_to_mine += T - resource_field = list() - need_update_field = 0 +/obj/machinery/mining_drill/proc/scan_visuals() + for(var/thing in RANGE_TURFS(src, drill_radius)) + var/turf/T = thing + var/delay = (get_dist(get_turf(src), T) + 1) * 3 + addtimer(CALLBACK(src, PROC_REF(scan_visual_tile), T), delay) - var/turf/T = get_turf(src) - if(!istype(T)) return - var/tx = T.x - 2 - var/ty = T.y - 2 - var/turf/simulated/mine_turf - for(var/iy = 0,iy < 5, iy++) - for(var/ix = 0, ix < 5, ix++) - mine_turf = locate(tx + ix, ty + iy, T.z) - if(mine_turf && mine_turf.has_resources) - resource_field += mine_turf +/obj/machinery/mining_drill/proc/scan_visual_tile(turf/T) + var/obj/effect/temporary/temp = new(T, 1 SECOND, 'icons/effects/effects.dmi', "sonar_ping") + temp.color = "#00ffff77" - if(!resource_field.len) - system_error("resources depleted") +/obj/machinery/mining_drill/proc/turf_has_ore(turf/T) + if(!istype(T) || !has_extension(T, /datum/extension/buried_resources)) + return FALSE + var/datum/extension/buried_resources/resources = get_extension(T, /datum/extension/buried_resources) + return length(resources?.resources) -/obj/machinery/mining/drill/verb/unload() +/obj/machinery/mining_drill/proc/mine_ore(turf/T) + if(!T) + return + // Was tempted to add a drilling sound but it was awful. + var/datum/extension/buried_resources/resources = get_extension(T, /datum/extension/buried_resources) + for(var/i in 1 to mining_speed) + if(!length(resources.resources)) + break + var/material_typepath = pick(resources.resources) + contained_ore += new /obj/item/stack/material/ore(src, 1, material_typepath) + resources.resources[material_typepath] -= 1 + if(resources.resources[material_typepath] <= 0) + // Remove the typepath if it ran out. + resources.resources -= material_typepath + +/obj/machinery/mining_drill/proc/deplete_turf(turf/T) + if(!turf_has_ore(T) && istype(T)) + turfs_to_mine -= T + if(has_extension(T, /datum/extension/buried_resources)) + remove_extension(T, /datum/extension/buried_resources) + +/obj/machinery/mining_drill/proc/choose_turf_to_mine() + current_turf = turfs_to_mine[1] + +/obj/machinery/mining_drill/verb/unload_verb() set name = "Unload Drill" set category = "Object" set src in oview(1) - if(usr.stat) return - var/obj/structure/ore_box/B = locate() in orange(1) if(B) - for(var/obj/item/ore/O in contents) - O.forceMove(B) - to_chat(usr, "You unload the drill's storage cache into the ore box.") - else - to_chat(usr, "You must move an ore box up to the drill before you can unload it.") - - -/obj/machinery/mining/brace - name = "mining drill brace" - desc = "A machinery brace for an industrial drill. It looks easily two feet thick." - icon_state = "mining_brace" - obj_flags = OBJ_FLAG_ROTATABLE - interact_offline = 1 - - var/obj/machinery/mining/drill/connected - -/obj/machinery/mining/brace/cannot_transition_to(state_path) - if(connected && connected.active) - return SPAN_NOTICE("You can't work with the brace of a running drill!") - return ..() - -/obj/machinery/mining/brace/attackby(obj/item/W, mob/user) - if(connected && connected.active) - to_chat(user, "You can't work with the brace of a running drill!") - return TRUE - if(component_attackby(W, user)) - return TRUE - if(isWrench(W)) - - if(istype(get_turf(src), /turf/space)) - to_chat(user, "You can't anchor something to empty space. Idiot.") - return - - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - to_chat(user, "You [anchored ? "un" : ""]anchor the brace.") - - anchored = !anchored - if(anchored) - connect() - else - disconnect() + unload_into_box(B, usr) -/obj/machinery/mining/brace/proc/connect() - - var/turf/T = get_step(get_turf(src), src.dir) - - for(var/thing in T.contents) - if(istype(thing, /obj/machinery/mining/drill)) - connected = thing - break - - if(!connected) +/obj/machinery/mining_drill/proc/unload_into_box(obj/structure/ore_box/box, mob/user) + if(!CanPhysicallyInteract(user)) return - if(!connected.supports) - connected.supports = list() - - icon_state = "mining_brace_active" - - connected.supports += src - connected.check_supports() - -/obj/machinery/mining/brace/proc/disconnect() - - if(!connected) return - - if(!connected.supports) connected.supports = list() - - icon_state = "mining_brace" - - connected.supports -= src - connected.check_supports() - connected = null - -/obj/machinery/mining/brace/dismantle() - if(connected) - disconnect() - ..() \ No newline at end of file + if(box?.Adjacent(src)) + if(!length(contained_ore)) + to_chat(user, SPAN_NOTICE("\The [src]'s storage cache is empty.")) + return + box.insert_ores(contained_ore, user) + contained_ore.Cut() + playsound(src, 'sound/machines/vending_machine.ogg', 60, 1) + playsound(box, 'sound/effects/rockcrumble.ogg', 60, 1) + visible_message( + SPAN_NOTICE("\The [user] unloads \the [src]'s storage cache into \the [box]."), + SPAN_NOTICE("You unload \the [src]'s storage cache into \the [box]."), + SPAN_NOTICE("You hear rocks falling into a container.") + ) + else + to_chat(user, SPAN_NOTICE("You must move an ore box up to \the [src] before you can unload it.")) diff --git a/code/modules/mining/drilling/drill_act.dm b/code/modules/mining/drilling/drill_act.dm new file mode 100644 index 000000000000..39759df1a4c2 --- /dev/null +++ b/code/modules/mining/drilling/drill_act.dm @@ -0,0 +1,21 @@ +/turf/proc/drill_act() + SHOULD_CALL_PARENT(TRUE) + drop_diggable_resources() + dig_pit(tool_hardness = MAT_VALUE_VERY_HARD) + var/base_turf = get_base_turf_by_area(src) + if(!istype(src, base_turf)) + return ChangeTurf(base_turf) + return src + // This could have some kind of 'drill everything on the turf' block as well + // but there is no visual indicator for a drill above you currently and that + // seems like it would be a bit unfair on people wandering into the beam. + +/turf/wall/drill_act() + SHOULD_CALL_PARENT(FALSE) + physically_destroyed() + +/turf/unsimulated/drill_act() + SHOULD_CALL_PARENT(FALSE) + +/turf/space/drill_act() + SHOULD_CALL_PARENT(FALSE) diff --git a/code/modules/mining/drilling/drill_fsm.dm b/code/modules/mining/drilling/drill_fsm.dm new file mode 100644 index 000000000000..0c6557124ed8 --- /dev/null +++ b/code/modules/mining/drilling/drill_fsm.dm @@ -0,0 +1,208 @@ +/datum/state_machine/drill + current_state = /decl/state/drill/unpowered + expected_type = /obj/machinery/mining_drill + base_type = /datum/state_machine/drill + + +/decl/state/drill + var/light_color = null + var/light_icon_state = "blink_slow" + var/entered_sound = null + var/exited_sound = null + var/power_usage = POWER_USE_IDLE + +/decl/state/drill/entered_state(obj/machinery/mining_drill/drill) + drill.queue_icon_update() + if(entered_sound) + playsound(drill, entered_sound, 40, FALSE) + drill.update_use_power(power_usage) + +/decl/state/drill/exited_state(obj/machinery/mining_drill/drill) + if(exited_sound) + playsound(drill, exited_sound, 40, FALSE) + +/decl/state/drill/proc/process(obj/machinery/mining_drill/drill) + + +/decl/state_transition/drill/is_open(obj/machinery/mining_drill/drill) + return drill.operable() + + +/// Unpowered state. Occurs when the battery dies or when turned off. +/decl/state/drill/unpowered + light_color = "#00000000" + power_usage = POWER_USE_OFF + light_icon_state = null + entered_sound = 'sound/mecha/mech-shutdown.ogg' + exited_sound = 'sound/mecha/powerup.ogg' + transitions = list( + /decl/state_transition/drill/recover_from_unpowered + ) + +/decl/state_transition/drill/unpowered + target = /decl/state/drill/unpowered + +/decl/state_transition/drill/unpowered/is_open(obj/machinery/mining_drill/drill) + return drill.inoperable() || drill.use_power == POWER_USE_OFF + + +/decl/state_transition/drill/recover_from_unpowered + target = /decl/state/drill/idle + +/decl/state_transition/drill/recover_from_unpowered/is_open(obj/machinery/mining_drill/drill) + return drill.operable() && drill.use_power != POWER_USE_OFF + + +/// Starting state for drills that are turned on or recovered from an issue. +/decl/state/drill/idle + light_color = "#ffffff" + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/error, + /decl/state_transition/drill/storage_full, + /decl/state_transition/drill/scanning, + /decl/state_transition/drill/switching_target, + /decl/state_transition/drill/mining, + /decl/state_transition/drill/finished + ) + +/decl/state/drill/idle/entered_state(obj/machinery/mining_drill/drill) + . = ..() + drill.reset_drill() + + +/// State that occurs if there is a problem with the drill setup, such as lacking braces. +/decl/state/drill/error + light_color = "#ff0000" + entered_sound = 'sound/machines/buzz-sigh.ogg' + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/recover_from_error + ) + +/decl/state_transition/drill/error + target = /decl/state/drill/error + +/decl/state_transition/drill/error/is_open(obj/machinery/mining_drill/drill) + return ..() && length(drill.supports) < drill.MINIMUM_SUPPORT_NUMBER + + +/decl/state_transition/drill/recover_from_error + target = /decl/state/drill/idle + +/decl/state_transition/drill/recover_from_error/is_open(obj/machinery/mining_drill/drill) + return ..() && length(drill.supports) >= drill.MINIMUM_SUPPORT_NUMBER + + +/// State that follows the starting state, where it determines which turfs to mine, and gives a visual effect of it scanning the surrounding ground. +/decl/state/drill/scanning + light_color = "#00ffff" + entered_sound = 'sound/effects/scanbeep.ogg' + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/error, + /decl/state_transition/drill/switching_target, + /decl/state_transition/drill/finished + ) + +/decl/state/drill/scanning/process(obj/machinery/mining_drill/drill) + drill.populate_turfs_to_mine() + drill.scan_visuals() + + +/decl/state_transition/drill/scanning + target = /decl/state/drill/scanning + +/decl/state_transition/drill/scanning/is_open(obj/machinery/mining_drill/drill) + return ..() && !length(drill.turfs_to_mine) + + +/// State where the drill is actively mining a specific turf. +/decl/state/drill/mining + light_color = "#00ff00" + light_icon_state = "blink_fast" + power_usage = POWER_USE_ACTIVE + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/error, + /decl/state_transition/drill/storage_full, + /decl/state_transition/drill/switching_target, + /decl/state_transition/drill/finished + ) + +/decl/state/drill/mining/process(obj/machinery/mining_drill/drill) + drill.mine_ore(drill.current_turf) + +/decl/state_transition/drill/mining + target = /decl/state/drill/mining + +/decl/state_transition/drill/mining/is_open(obj/machinery/mining_drill/drill) + return ..() && length(drill.turfs_to_mine) && drill.current_turf + + +/// State which occurs when the currently mined turf is depleted, and there is another turf to mine from, +/// thus the drill visually targets the next spot and provides some feedback to the player on how fast the mining is going. +/decl/state/drill/switching_target + light_color = "#008800" + light_icon_state = "blink_fast" + power_usage = POWER_USE_IDLE + entered_sound = 'sound/machines/airlock_open_force.ogg' + exited_sound = 'sound/machines/airlock_close_force.ogg' + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/error, + /decl/state_transition/drill/mining, + /decl/state_transition/drill/finished + ) + +/decl/state/drill/switching_target/process(obj/machinery/mining_drill/drill) + drill.deplete_turf(drill.current_turf) + if(length(drill.turfs_to_mine)) + drill.choose_turf_to_mine() + else + drill.current_turf = null + +/decl/state_transition/drill/switching_target + target = /decl/state/drill/switching_target + +/decl/state_transition/drill/switching_target/is_open(obj/machinery/mining_drill/drill) + return ..() && length(drill.turfs_to_mine) && !drill.turf_has_ore(drill.current_turf) + + +/// State which occurs when the ore storage is full, and the player needs to unload the ore for it to resume mining. +/decl/state/drill/storage_full + light_color = "#ffff00" + entered_sound = 'sound/machines/buzz-two.ogg' + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/error, + /decl/state_transition/drill/recover_from_storage_full + ) + +/decl/state_transition/drill/storage_full + target = /decl/state/drill/storage_full + +/decl/state_transition/drill/storage_full/is_open(obj/machinery/mining_drill/drill) + return ..() && length(drill.contained_ore) >= drill.ore_capacity + +/decl/state_transition/drill/recover_from_storage_full + target = /decl/state/drill/idle + +/decl/state_transition/drill/recover_from_storage_full/is_open(obj/machinery/mining_drill/drill) + return ..() && length(drill.contained_ore) < drill.ore_capacity + + +/// State which occurs when there is no more ore to mine from the surrounding tiles. +/decl/state/drill/finished + light_color = "#0000ff" + entered_sound = 'sound/machines/ping.ogg' + transitions = list( + /decl/state_transition/drill/unpowered, + /decl/state_transition/drill/error + ) + +/decl/state_transition/drill/finished + target = /decl/state/drill/finished + +/decl/state_transition/drill/finished/is_open(obj/machinery/mining_drill/drill) + return ..() && !drill.current_turf && !length(drill.turfs_to_mine) \ No newline at end of file diff --git a/code/modules/mining/machinery/_material_processing.dm b/code/modules/mining/machinery/_material_processing.dm new file mode 100644 index 000000000000..d5b082136efc --- /dev/null +++ b/code/modules/mining/machinery/_material_processing.dm @@ -0,0 +1,135 @@ +#define SET_INPUT(_dir) input_turf = _dir ? get_step(loc, _dir) : null +#define SET_OUTPUT(_dir) output_turf = _dir ? get_step(loc, _dir) : null + +/obj/machinery/material_processing + density = TRUE + anchored = TRUE + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = 0 + icon = 'icons/obj/machines/mining_machines.dmi' + var/use_ui_template + var/allow_ui_config = FALSE + var/turf/input_turf = WEST + var/turf/output_turf = EAST + +/obj/machinery/material_processing/emp_act(severity) + if(severity == 1 || (severity == 2 && prob(50))) + emagged = TRUE + . = ..() + +/obj/machinery/material_processing/emag_act(remaining_charges, mob/user, emag_source) + if(!emagged) + emagged = TRUE + to_chat(user, SPAN_NOTICE("You short out \the [src]'s intake safety protocol.")) + return TRUE + +/obj/machinery/material_processing/on_update_icon() + + cut_overlays() + + icon_state = initial(icon_state) + if(panel_open) + add_overlay("[icon_state]-open") + if(!use_power || (stat & (BROKEN|NOPOWER))) + icon_state = "[icon_state]-off" + + var/overlay_dir = 0 + if(input_turf) + overlay_dir = get_dir(src, input_turf) + if(overlay_dir != 0) + var/image/I = image('icons/obj/machines/mining_machine_overlays.dmi', "[global.reverse_dir[overlay_dir]]") + I.layer = DECAL_LAYER + switch(overlay_dir) + if(NORTH) I.pixel_y += world.icon_size + if(SOUTH) I.pixel_y -= world.icon_size + if(EAST) I.pixel_x += world.icon_size + if(WEST) I.pixel_x -= world.icon_size + add_overlay(I) + if(output_turf) + overlay_dir = get_dir(src, output_turf) + if(overlay_dir != 0) + var/image/I = image('icons/obj/machines/mining_machine_overlays.dmi', "[overlay_dir]") + I.layer = DECAL_LAYER + switch(overlay_dir) + if(NORTH) I.pixel_y += world.icon_size + if(SOUTH) I.pixel_y -= world.icon_size + if(EAST) I.pixel_x += world.icon_size + if(WEST) I.pixel_x -= world.icon_size + add_overlay(I) + if(overlay_dir == 0) + var/image/I = image('icons/obj/machines/mining_machine_overlays.dmi', "0") + I.layer = DECAL_LAYER + add_overlay(I) + +/obj/machinery/material_processing/proc/get_ui_data() + var/list/data = list() + data["on"] = (use_power > 0) + data["can_configure"] = allow_ui_config + data["output_value"] = output_turf ? get_dir(src, output_turf) : 0 + data["output_label"] = data["output_value"] ? dir2text(data["output_value"]) : "disabled" + data["input_value"] = input_turf ? get_dir(src, input_turf) : 0 + data["input_label"] = data["input_value"] ? dir2text(data["input_value"]) : "disabled" + return data + +/obj/machinery/material_processing/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui=null, force_open=1) + if(!use_ui_template) + return + var/list/data = get_ui_data() + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, use_ui_template, "[capitalize(name)]", 600, 800, state = global.physical_topic_state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/material_processing/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/material_processing/Destroy() + input_turf = null + output_turf = null + events_repository.unregister(/decl/observ/moved, src, src, PROC_REF(on_moved)) + . = ..() + +/obj/machinery/material_processing/Initialize() + dir = output_turf || input_turf + SET_INPUT(input_turf) + SET_OUTPUT(output_turf) + . = ..() + queue_icon_update() + events_repository.register(/decl/observ/moved, src, src, PROC_REF(on_moved)) + events_repository.register(/decl/observ/dir_set, src, src, PROC_REF(on_dir_set)) + +/obj/machinery/material_processing/proc/on_moved(atom/moving, atom/old_loc, atom/new_loc) + var/turf/our_turf = get_turf(src) + if(istype(input_turf, /turf)) + input_turf = get_step(our_turf, get_dir(get_turf(old_loc), input_turf)) + if(istype(output_turf, /turf)) + output_turf = get_step(our_turf, get_dir(get_turf(old_loc), output_turf)) + +/obj/machinery/material_processing/proc/on_dir_set(atom/dir_changer, old_dir, new_dir) + var/angle_offset = dir2angle(old_dir) - dir2angle(new_dir) + var/turf/our_turf = get_turf(src) + if(istype(input_turf, /turf)) + input_turf = get_step(our_turf, SAFE_TURN(get_dir(our_turf, input_turf), angle_offset)) + if(istype(output_turf, /turf)) + output_turf = get_step(our_turf, SAFE_TURN(get_dir(our_turf, output_turf), angle_offset)) + +/obj/machinery/material_processing/OnTopic(var/user, var/list/href_list) + if(href_list["toggle_power"]) + update_use_power(use_power ? 0 : POWER_USE_IDLE) + . = TOPIC_REFRESH + if(href_list["set_input"]) + SET_INPUT(text2num(href_list["set_input"])) + queue_icon_update() + . = TOPIC_REFRESH + if(href_list["set_output"]) + dir = text2num(href_list["set_output"]) + SET_OUTPUT(dir) + queue_icon_update() + . = TOPIC_REFRESH + if(href_list["toggle_configuration"]) + allow_ui_config = !allow_ui_config + . = TOPIC_REFRESH diff --git a/code/modules/mining/machinery/_mineral.dm b/code/modules/mining/machinery/_mineral.dm deleted file mode 100644 index 17e933e07186..000000000000 --- a/code/modules/mining/machinery/_mineral.dm +++ /dev/null @@ -1,105 +0,0 @@ -/obj/machinery/mineral - icon = 'icons/obj/machines/mining_machines.dmi' - density = TRUE - anchored = TRUE - construct_state = /decl/machine_construction/default/panel_closed - uncreated_component_parts = null - stat_immune = 0 - - var/turf/input_turf - var/turf/output_turf - var/obj/machinery/computer/mining/console - -/obj/machinery/mineral/Destroy() - input_turf = null - output_turf = null - if(console) - if(console.connected == src) - console.connected = null - console = null - . = ..() - -/obj/machinery/mineral/Initialize() - set_input(input_turf) - set_output(output_turf) - find_console() - . = ..() - -/obj/machinery/mineral/state_transition(var/decl/machine_construction/default/new_state) - . = ..() - if(istype(new_state)) - updateUsrDialog() - -/obj/machinery/mineral/proc/set_input(var/_dir) - input_turf = _dir ? get_step(loc, _dir) : null - -/obj/machinery/mineral/proc/set_output(var/_dir) - output_turf = _dir ? get_step(loc, _dir) : null - -/obj/machinery/mineral/proc/get_console_data() - . = list("

          Input/Output

          ") - if(input_turf) - . += "Input: [dir2text(get_dir(src, input_turf))]." - else - . += "Input: disabled." - if(output_turf) - . += "Output: [dir2text(get_dir(src, output_turf))]." - else - . += "Output: disabled." - . += "
          Configure" - -/obj/machinery/mineral/CanUseTopic(var/mob/user) - return max(..(), (console && console.CanUseTopic(user))) - -/obj/machinery/mineral/proc/find_console() - if(ispath(console)) - for(var/c in GLOB.alldirs) - var/turf/T = get_step(loc, c) - if(T) - var/obj/machinery/computer/mining/tmpconsole = locate(console) in T - if(tmpconsole && !tmpconsole.connected) - console = tmpconsole - console.connected = src - break - -/obj/machinery/mineral/Topic(href, href_list) - if((. = ..())) - return - if(href_list["configure_input_output"]) - interact(usr) - . = TRUE - else if(href_list["scan_for_console"]) - find_console() - . = TRUE - if(console && usr.Adjacent(console)) - usr.set_machine(console) - console.add_fingerprint(usr) - -/obj/machinery/mineral/interface_interact(var/mob/user) - interact(user) - return TRUE - -/obj/machinery/mineral/proc/can_configure(var/mob/user) - if(user.incapacitated()) - return FALSE - if(istype(user, /mob/living/silicon)) - return TRUE - return (Adjacent(user) || (console && console.Adjacent(user))) - -/obj/machinery/mineral/interact(var/mob/user) - - if(!can_configure(user)) return - - var/choice = input("Do you wish to change the input direction, or the output direction?") as null|anything in list("Input", "Output") - if(isnull(choice) || !can_configure(user)) return - - var/list/_dirs = list("North" = NORTH, "South" = SOUTH, "East" = EAST, "West" = WEST, "Clear" = 0) - var/dchoice = input("Do you wish to change the input direction, or the output direction?") as null|anything in _dirs - if(isnull(dchoice) || !can_configure(user)) return - - if(choice == "Input") - set_input(dchoice ? _dirs[dchoice] : null) - to_chat(user, "You [input_turf ? "configure" : "disable"] \the [src]'s input system.") - else - set_output(dchoice ? _dirs[dchoice] : null) - to_chat(user, "You [output_turf ? "configure" : "disable"] \the [src]'s output system.") \ No newline at end of file diff --git a/code/modules/mining/machinery/material_compressor.dm b/code/modules/mining/machinery/material_compressor.dm new file mode 100644 index 000000000000..32ae10fdc219 --- /dev/null +++ b/code/modules/mining/machinery/material_compressor.dm @@ -0,0 +1,54 @@ +#define MAX_COMPRESS_ORE_PER_TICK 10 + +/obj/machinery/material_processing/compressor + name = "material compressor" + icon_state = "compressor" + use_ui_template = "material_processing_compressor.tmpl" + var/list/stored = list() + +/obj/machinery/material_processing/compressor/Process() + + if(!use_power || (stat & (BROKEN|NOPOWER))) + return + + if(input_turf) + var/compressed = 0 + for(var/obj/item/O in input_turf) + if(!O.simulated || O.anchored) + continue + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(O.reagents)) + stored[reagent.type] = stored[reagent.type] + floor((REAGENT_VOLUME(O.reagents, reagent) / REAGENT_UNITS_PER_MATERIAL_UNIT) * 0.75) // liquid reagents, lossy + for(var/mat in O.matter) + stored[mat] = stored[mat] + O.matter[mat] + qdel(O) + compressed++ + if(compressed >= MAX_COMPRESS_ORE_PER_TICK) + break + if(emagged) + for(var/mob/living/human/H in input_turf) + for(var/obj/item/organ/external/crushing in H.get_external_organs()) + if(!crushing.simulated || crushing.anchored || !prob(5)) + continue + visible_message(SPAN_DANGER("\The [src] crushes \the [H]'s [crushing.name]!")) + for(var/mat in crushing.matter) + if(stored[mat]) + stored[mat] += crushing.matter[mat] + else + stored[mat] = crushing.matter[mat] + crushing.dismember(disintegrate = DISMEMBER_METHOD_BLUNT, silent = TRUE) + break + if(output_turf) + var/produced = 0 + for(var/mat in stored) + var/sheets = min(floor((stored[mat] / SHEET_MATERIAL_AMOUNT) / 2), (MAX_COMPRESS_ORE_PER_TICK - produced)) + if(sheets <= 0) + continue + var/decl/material/source = GET_DECL(mat) + var/decl/material/product = source.ore_compresses_to ? GET_DECL(source.ore_compresses_to) : source + product.create_object(output_turf, sheets) + stored[mat] -= ceil(sheets * SHEET_MATERIAL_AMOUNT * 2) + if(stored[mat] <= 0) + stored -= mat + produced += sheets + if(produced >= MAX_COMPRESS_ORE_PER_TICK) + break diff --git a/code/modules/mining/machinery/material_extractor.dm b/code/modules/mining/machinery/material_extractor.dm new file mode 100644 index 000000000000..b93b539f40af --- /dev/null +++ b/code/modules/mining/machinery/material_extractor.dm @@ -0,0 +1,292 @@ +#define GAS_EXTRACTOR_OPERATING_TEMP T20C + 15 +#define MAX_INTAKE_ORE_PER_TICK 10 + +/obj/machinery/material_processing/extractor + name = "material extractor" + desc = "A machine for extracting liquids and gases from ices and hydrates." + icon = 'icons/obj/machines/mining_machines.dmi' + icon_state = "extractor" + use_ui_template = "material_processing_extractor.tmpl" + atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_NO_REACT | ATOM_FLAG_NO_DISSOLVE + + var/static/list/eating_whitelist = list(/obj/item/stack/material) + + var/datum/gas_mixture/gas_contents + + var/obj/item/chems/glass/output_container + var/dispense_amount = 50 + + // Since reactions and heating products may overfill the reagent tank, the reagent tank has 1.25x this volume. + var/const/MAX_LIQUID = 3000 + +/obj/machinery/material_processing/extractor/Initialize() + chem_volume = round(MAX_LIQUID * 1.25) + . = ..() + if(!gas_contents) + gas_contents = new(800) + set_extension(src, /datum/extension/atmospherics_connection, FALSE, gas_contents) + + queue_temperature_atoms(src) + + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/material_processing/extractor/Destroy() + QDEL_NULL(output_container) + . = ..() + +/obj/machinery/material_processing/extractor/physically_destroyed(skip_qdel) + var/obj/container = remove_container() + if(container) + container.dropInto(get_turf(src)) + . = ..() + +/obj/machinery/material_processing/extractor/dismantle() + var/obj/container = remove_container() + if(container) + container.dropInto(get_turf(src)) + . = ..() + +/obj/machinery/material_processing/extractor/LateInitialize() + . = ..() + + var/obj/machinery/atmospherics/portables_connector/port = locate() in loc + if(port) + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) + if(connection) + connection.connect(port) + + +/obj/machinery/material_processing/extractor/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) + if(connection.connected_port) + . += SPAN_NOTICE("It is connected to \the [connection.connected_port].") + else + . += SPAN_NOTICE("It may be connected to an atmospherics connector port with a wrench.") + if(output_container) + . += SPAN_NOTICE("It has \a [output_container] inserted.") + +/obj/machinery/material_processing/extractor/Process() + if(!use_power || (stat & (BROKEN|NOPOWER))) + return + + if(REAGENT_TOTAL_VOLUME(reagents) >= MAX_LIQUID) + return + + if(input_turf) + var/eaten = 0 + for(var/obj/item/eating in input_turf) + if(!eating.simulated || eating.anchored) + continue + if(!can_eat(eating)) + if(output_turf) + eating.dropInto(output_turf) + continue + eaten++ + if(REAGENT_TOTAL_VOLUME(eating.reagents)) + eating.reagents.trans_to_obj(src, REAGENT_TOTAL_VOLUME(eating.reagents)) + for(var/mtype in eating.matter) + add_to_reagents(mtype, floor(eating.matter[mtype] * REAGENT_UNITS_PER_MATERIAL_UNIT)) + qdel(eating) + if(eaten >= MAX_INTAKE_ORE_PER_TICK) + break + +/obj/machinery/material_processing/extractor/on_reagent_change() + + if(!(. = ..()) || !reagents) + return + + var/adjusted_reagents = FALSE + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + adjusted_reagents = max(adjusted_reagents, process_non_liquid(reagent)) + + if(adjusted_reagents) + if(gas_contents) + gas_contents.update_values() + reagents.update_total() + +/obj/machinery/material_processing/extractor/proc/process_non_liquid(var/mtype) + var/adjusted_reagents = FALSE + var/flashed_warning = FALSE + var/decl/material/mat = RESOLVE_TO_DECL(mtype) + // TODO: Change this to ambient/tank pressure when phase changes are properly implemented. + switch(mat.phase_at_temperature(temperature, ONE_ATMOSPHERE)) + if(MAT_PHASE_GAS) + if(gas_contents) + adjusted_reagents = TRUE + var/reagent_vol = REAGENT_VOLUME(reagents, mtype) + var/mols = mat.get_mols_from_units(reagent_vol, MAT_PHASE_LIQUID) + + // Because this generates heated gas, we draw some additional power for heating it + // from the ice temperature, ignoring latent heats. + var/power_draw_per_mol = (temperature - T0C)*mat.gas_specific_heat + + var/avail_power = power_draw_per_mol*mols - max(can_use_power_oneoff(power_draw_per_mol*mols), 0) + var/processed_mols = avail_power/power_draw_per_mol + + if(processed_mols) + // The ratio processed_moles/moles gives us the ratio of the reagent volume to what should be removed + // since the mole to unit conversion is linear. + remove_from_reagents(mtype, reagent_vol*(processed_mols/mols), defer_update = TRUE) + + use_power_oneoff(power_draw_per_mol*mols) + // Still somewhat arbitary + gas_contents.adjust_gas_temp(mtype, mols, temperature, FALSE) + + // Some feedback for the user + if(!flashed_warning && processed_mols < mols) + visible_message(SPAN_WARNING("\The [src] flashes an 'Insufficient Power' error!"), range = 2) + flashed_warning = TRUE + // Unlike the smelter or compressor, we don't hold on to solids indefinitely. Spit them out, losing any remainders. + if(MAT_PHASE_SOLID) + if(!can_process_material_name(mtype)) + var/removing = REAGENT_VOLUME(reagents, mtype) || 0 + var/sheets = floor((removing / REAGENT_UNITS_PER_MATERIAL_UNIT) / SHEET_MATERIAL_AMOUNT) + if(sheets > 0) // If we can't process any sheets at all, leave it for manual processing. + adjusted_reagents = TRUE + SSmaterials.create_object(mtype, output_turf, sheets) + remove_from_reagents(mtype, removing) + + return adjusted_reagents + +/obj/machinery/material_processing/extractor/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item) && !panel_open) + var/datum/extension/atmospherics_connection/connection = get_extension(src, /datum/extension/atmospherics_connection) + if(connection.disconnect()) + to_chat(user, SPAN_NOTICE("You disconnect \the [src] from the port.")) + return TRUE + else + var/obj/machinery/atmospherics/portables_connector/possible_port = locate(/obj/machinery/atmospherics/portables_connector) in loc + if(possible_port) + if(connection.connect(possible_port)) + to_chat(user, SPAN_NOTICE("You connect \the [src] to the port.")) + return TRUE + else + to_chat(user, SPAN_WARNING("\The [src] failed to connect to the port.")) + return TRUE + + if(istype(used_item, /obj/item/chems/glass)) + if(isnull(output_container)) + if(!user.try_unequip(used_item, src)) + return TRUE + output_container = used_item + events_repository.register(/decl/observ/destroyed, output_container, src, TYPE_PROC_REF(/obj/machinery/material_processing/extractor, remove_container)) + user.visible_message(SPAN_NOTICE("\The [user] places \a [used_item] in \the [src]."), SPAN_NOTICE("You place \a [used_item] in \the [src].")) + return TRUE + + to_chat(user, SPAN_WARNING("\The [src] already has an output container!")) + return TRUE + . = ..() + +/obj/machinery/material_processing/extractor/proc/remove_container() + if(!output_container) + return + . = output_container + events_repository.unregister(/decl/observ/destroyed, output_container, src, TYPE_PROC_REF(/obj/machinery/material_processing/extractor, remove_container)) + output_container = null + +/obj/machinery/material_processing/extractor/OnTopic(var/mob/user, var/list/href_list) + . = ..() + + if(href_list["change_amount"]) + var/amount = input(user, "Enter the amount of units to transfer to the container (max 120):", "Units transfer", dispense_amount) as num + + if(!CanInteract(user, global.default_topic_state)) + return TOPIC_HANDLED + + dispense_amount = clamp(amount, 0, 120) + return TOPIC_REFRESH + + if(href_list["dispense"]) + var/reagent_index = text2num(href_list["dispense"]) + if(!reagent_index || length(REAGENT_VOLUMES(reagents)) < reagent_index) + return TOPIC_HANDLED + + var/mtype = REAGENT_VOLUME(reagents, reagent_index) + + // Only liquids are allowed to dispense. Otherwise, try to process the reagent. + if(process_non_liquid(mtype)) + if(gas_contents) + gas_contents.update_values() + reagents.update_total() + return TOPIC_REFRESH + + if(!output_container || !output_container.reagents) + return TOPIC_HANDLED + + reagents.trans_type_to(output_container, mtype, dispense_amount) + return TOPIC_REFRESH + + if(href_list["eject"]) + var/obj/container = remove_container() + if(!container) + return TOPIC_HANDLED + if(CanPhysicallyInteract(user)) + user.put_in_hands(container) + else + container.dropInto(get_turf(src)) + return TOPIC_REFRESH + +/obj/machinery/material_processing/extractor/get_ui_data(mob/user) + var/list/data = ..() + + data["dispense_amount"] = dispense_amount + if(output_container) + var/curr_volume = REAGENT_TOTAL_VOLUME(output_container.reagents) + var/max_volume = REAGENT_MAXIMUM_VOLUME(output_container.reagents) + + data["container"] = "[output_container.name] ([curr_volume] / [max_volume] U)" + + data["reagents"] = list() + var/index = 0 + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + index += 1 + // TODO: Must be revised once state changes are in. Reagent names might be a litle odd in the meantime. + var/is_liquid = reagent.phase_at_temperature(temperature, ONE_ATMOSPHERE) == MAT_PHASE_LIQUID + data["reagents"] += list(list("label" = "[reagent.liquid_name] ([REAGENT_VOLUME(reagents, reagent)] U)", "index" = index, "liquid" = is_liquid)) + + data["full"] = REAGENT_TOTAL_VOLUME(reagents) >= MAX_LIQUID + data["gas_pressure"] = gas_contents?.return_pressure() + return data + +/obj/machinery/material_processing/extractor/return_air() + return gas_contents + +/obj/machinery/material_processing/extractor/proc/can_eat(obj/eating) + if(istype(eating) && length(eating.matter) && is_type_in_list(eating, eating_whitelist)) + for(var/mtype in eating.matter) + if(can_process_material_name(mtype)) + return TRUE + return FALSE + +/obj/machinery/material_processing/extractor/proc/can_process_material_name(mtype) + var/decl/material/mat = GET_DECL(mtype) + ASSERT(istype(mat)) + return (is_material_extractable(mat) || has_extractable_heating_products(mat)) + +/obj/machinery/material_processing/extractor/proc/has_extractable_heating_products(decl/material/M) + for(var/mtype in M.heating_products) + var/decl/material/mat = GET_DECL(mtype) + ASSERT(istype(mat)) + if(is_material_extractable(mat)) + return TRUE + return FALSE + +/obj/machinery/material_processing/extractor/proc/is_material_extractable(decl/material/M) + //If is gas or liquid at operating temp we can process + var/phase = M.phase_at_temperature(temperature) + return phase == MAT_PHASE_LIQUID || phase == MAT_PHASE_GAS + +/obj/machinery/material_processing/extractor/ProcessAtomTemperature() + if(use_power && operable()) + temperature = GAS_EXTRACTOR_OPERATING_TEMP + return TRUE + . = ..() + +/obj/machinery/material_processing/extractor/power_change() + . = ..() + if(.) + queue_temperature_atoms(src) + +#undef MAX_INTAKE_ORE_PER_TICK +#undef GAS_EXTRACTOR_OPERATING_TEMP diff --git a/code/modules/mining/machinery/material_smelter.dm b/code/modules/mining/machinery/material_smelter.dm new file mode 100644 index 000000000000..489327ec51c4 --- /dev/null +++ b/code/modules/mining/machinery/material_smelter.dm @@ -0,0 +1,141 @@ +#define MAX_INTAKE_ORE_PER_TICK 10 + +/obj/machinery/material_processing/smeltery + name = "electric smelter" + icon_state = "furnace" + use_ui_template = "material_processing_smeltery.tmpl" + atom_flags = ATOM_FLAG_CLIMBABLE | ATOM_FLAG_OPEN_CONTAINER + chem_volume = INFINITY + + var/show_all_materials = FALSE + var/list/casting + var/static/list/always_show_materials = list( + /decl/material/solid/metal/iron, + /decl/material/solid/metal/gold, + /decl/material/solid/metal/uranium, + /decl/material/solid/metal/silver, + /decl/material/solid/metal/platinum, + /decl/material/solid/metal/steel, + /decl/material/solid/graphite + ) + var/list/show_materials + +/obj/machinery/material_processing/smeltery/Initialize() + show_materials = always_show_materials.Copy() + . = ..() + queue_temperature_atoms(src) + +// Update displayed materials +/obj/machinery/material_processing/smeltery/on_reagent_change() + + if(!(. = ..()) || !reagents) + return + + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + show_materials |= reagent.type + +/obj/machinery/material_processing/smeltery/ProcessAtomTemperature() + if(use_power) + if(temperature < HIGH_SMELTING_HEAT_POINT) + temperature = min(temperature + rand(100, 200), HIGH_SMELTING_HEAT_POINT) + else if(temperature > HIGH_SMELTING_HEAT_POINT) + temperature = HIGH_SMELTING_HEAT_POINT + return TRUE + . = ..() + +/obj/machinery/material_processing/smeltery/power_change() + . = ..() + if(.) + queue_temperature_atoms(src) + +/obj/machinery/material_processing/smeltery/proc/can_eat(var/obj/item/eating) + for(var/mtype in eating.matter) + var/decl/material/mat = GET_DECL(mtype) + if(isnull(mat.melting_point) || mat.melting_point > temperature) + return FALSE + return TRUE + +/obj/machinery/material_processing/smeltery/Process() + + if(!use_power || (stat & (BROKEN|NOPOWER))) + return + + if(input_turf) + var/eaten = 0 + for(var/obj/item/eating in input_turf) + if(!eating.simulated || eating.anchored) + continue + if(!can_eat(eating)) + if(output_turf) + eating.dropInto(output_turf) + continue + eaten++ + if(REAGENT_TOTAL_VOLUME(eating.reagents)) + eating.reagents.trans_to_obj(src, floor(REAGENT_TOTAL_VOLUME(eating.reagents) * 0.75)) // liquid reagents, lossy + for(var/mtype in eating.matter) + add_to_reagents(mtype, floor(eating.matter[mtype] * REAGENT_UNITS_PER_MATERIAL_UNIT)) + qdel(eating) + if(eaten >= MAX_INTAKE_ORE_PER_TICK) + break + if(emagged) + for(var/mob/living/human/H in input_turf) + for(var/obj/item/organ/external/eating in H.get_external_organs()) + if(!eating.simulated || eating.anchored || !can_eat(eating) || !prob(5)) + continue + visible_message(SPAN_DANGER("\The [src] rips \the [H]'s [eating.name] clean off!")) + for(var/mtype in eating.matter) + add_to_reagents(mtype, floor(eating.matter[mtype] * REAGENT_UNITS_PER_MATERIAL_UNIT)) + eating.dismember(silent = TRUE) + qdel(eating) + break + + if(output_turf) + for(var/mtype in casting) + var/ramt = REAGENT_VOLUME(reagents, mtype) || 0 + var/samt = floor((ramt / REAGENT_UNITS_PER_MATERIAL_UNIT) / SHEET_MATERIAL_AMOUNT) + if(samt > 0) + SSmaterials.create_object(mtype, output_turf, samt) + remove_from_reagents(mtype, ramt) + +/obj/machinery/material_processing/smeltery/OnTopic(mob/user, href_list) + if((. = ..())) + return + + if(href_list["toggle_alloying"]) + if(atom_flags & ATOM_FLAG_NO_REACT) + atom_flags &= ~ATOM_FLAG_NO_REACT + HANDLE_REACTIONS(reagents) + else + atom_flags |= ATOM_FLAG_NO_REACT + . = TOPIC_REFRESH + + if(href_list["toggle_show_mats"]) + show_all_materials = !show_all_materials + . = TOPIC_REFRESH + + if(href_list["toggle_casting"]) + var/decl/material/mat = locate(href_list["toggle_casting"]) + if(istype(mat)) + if(mat.type in casting) + casting -= mat.type + else + LAZYSET(casting, mat.type, TRUE) + . = TOPIC_REFRESH + +/obj/machinery/material_processing/smeltery/get_ui_data() + var/list/data = ..() + data["is_alloying"] = !(atom_flags & ATOM_FLAG_NO_REACT) + data["show_all_mats"] = show_all_materials + var/list/materials = list() + for(var/mtype in show_materials) + var/decl/material/mat = GET_DECL(mtype) + var/ramt = REAGENT_VOLUME(reagents, mtype) || 0 + if(ramt <= 0 && !show_all_materials && !(mtype in always_show_materials)) + continue + var/samt = floor((ramt / REAGENT_UNITS_PER_MATERIAL_UNIT) / SHEET_MATERIAL_AMOUNT) + var/obj/item/stack/material/sheet = mat.default_solid_form + materials += list(list("label" = "[mat.liquid_name]
          [ramt]u ([samt] [samt == 1 ? initial(sheet.singular_name) : initial(sheet.plural_name)])", "casting" = (mtype in casting), "key" = "\ref[mat]")) + data["materials"] = materials + return data + +#undef MAX_INTAKE_ORE_PER_TICK diff --git a/code/modules/mining/machinery/material_stacker.dm b/code/modules/mining/machinery/material_stacker.dm new file mode 100644 index 000000000000..593137e6e404 --- /dev/null +++ b/code/modules/mining/machinery/material_stacker.dm @@ -0,0 +1,58 @@ +/obj/machinery/material_processing/stacker + name = "ingot stacker" + icon_state = "stacker" + use_ui_template = "material_processing_stacker.tmpl" + var/stack_max = 50 + var/list/stacked = list() + +/obj/machinery/material_processing/stacker/OnTopic(var/user, var/list/href_list) + . = ..() + if(href_list["change_stack_max"]) + stack_max = text2num(href_list["change_stack_max"]) + . = TOPIC_REFRESH + if(href_list["release_sheets"] && output_turf) + var/decl/material/mat = locate(href_list["release_sheets"]) + if(istype(mat) && stacked[mat.type] > 0) + mat.create_object(output_turf, stacked[mat.type]) + stacked -= mat.type + . = TOPIC_REFRESH + +/obj/machinery/material_processing/stacker/get_ui_data() + var/list/data = ..() + data["stack_max"] = stack_max + var/list/stacks = list() + for(var/stack in stacked) + if(stacked[stack] > 0) + var/decl/material/mat = GET_DECL(stack) + stacks += list(list("name" = "[capitalize(mat.solid_name)] x [stacked[stack]]", "key" = "\ref[mat]")) + data["stacks"] = stacks + return data + +/obj/machinery/material_processing/stacker/Process() + + if(!use_power || (stat & (BROKEN|NOPOWER))) + return + + if(input_turf) + for(var/obj/item/stack/material/S in input_turf) + if(!S.material) + continue + if(isnull(stacked[S.material.type])) + stacked[S.material.type] = S.amount + else + stacked[S.material.type] += S.amount + qdel(S) + + if(emagged) + for(var/mob/living/victim in input_turf) + if(!victim.simulated) + continue + visible_message(SPAN_DANGER("\The [src] squashes \the [victim] with its stacking mechanism!")) + victim.take_overall_damage(rand(10, 20), 0) + break + + if(output_turf) + for(var/sheet in stacked) + if(stacked[sheet] >= stack_max) + SSmaterials.create_object(sheet, output_turf, stack_max) + stacked[sheet] -= stack_max diff --git a/code/modules/mining/machinery/material_unloader.dm b/code/modules/mining/machinery/material_unloader.dm new file mode 100644 index 000000000000..420596abfc9b --- /dev/null +++ b/code/modules/mining/machinery/material_unloader.dm @@ -0,0 +1,44 @@ +/obj/machinery/material_processing/unloader + name = "ore unloader" + icon_state = "unloader" + use_ui_template = "material_processing_unloader.tmpl" + +#define MAX_UNLOAD_TURF_CONTENTS 15 +#define MAX_UNLOAD_ORE_PER_TICK 10 + +/obj/machinery/material_processing/unloader/Process() + + if(!use_power || (stat & (BROKEN|NOPOWER))) + return + + if(!output_turf || !input_turf) + return + + if(length(output_turf.contents) >= MAX_UNLOAD_TURF_CONTENTS) + return + + var/ore_this_tick = 0 + for(var/obj/structure/ore_box/unloading in input_turf) + for(var/obj/item/stack/material/ore in unloading) + unloading.remove_ore(ore) + ore.dropInto(output_turf) + ore_this_tick++ + if(ore_this_tick >= MAX_UNLOAD_ORE_PER_TICK || length(output_turf.contents) >= MAX_UNLOAD_TURF_CONTENTS) + return + + for(var/obj/item/stack/material/ore in input_turf) + if(ore.simulated && !ore.anchored) + ore.dropInto(output_turf) + ore_this_tick++ + if(ore_this_tick >= MAX_UNLOAD_ORE_PER_TICK || length(output_turf.contents) >= MAX_UNLOAD_TURF_CONTENTS) + return + + if(emagged) + for(var/mob/living/M in input_turf) + visible_message(SPAN_DANGER("\The [M] is yanked violently through \the [src]!")) + M.take_overall_damage(rand(10, 20), 0) + M.dropInto(output_turf) + break + +#undef MAX_UNLOAD_TURF_CONTENTS +#undef MAX_UNLOAD_ORE_PER_TICK \ No newline at end of file diff --git a/code/modules/mining/machinery/mineral_console.dm b/code/modules/mining/machinery/mineral_console.dm deleted file mode 100644 index 1a11c9253978..000000000000 --- a/code/modules/mining/machinery/mineral_console.dm +++ /dev/null @@ -1,50 +0,0 @@ -/obj/machinery/computer/mining - name = "ore processing console" - icon = 'icons/obj/machines/mining_machines.dmi' - var/obj/machinery/mineral/connected - -// Apparently mapped on walls, so must do this to avoid being hidden behind them. -/obj/machinery/computer/mining/hide() - return - -/obj/machinery/computer/mining/on_update_icon() - if(panel_open) - icon_state = "console-open" - else - icon_state = "console" - -/obj/machinery/computer/mining/interface_interact(var/mob/user) - interact(user) - return TRUE - -/obj/machinery/computer/mining/interact(var/mob/user) - var/datum/browser/written/popup = new(user, "mining-[name]", "[src] Control Panel") - popup.set_content(jointext(connected.get_console_data(), "
          ")) - popup.open() - -/obj/machinery/computer/mining/CanUseTopic(mob/user) - if(!connected) - to_chat(user, "\The [src] is not connected to a processing machine. Scan") - return STATUS_CLOSE - . = ..() - -/obj/machinery/computer/mining/Topic(href, href_list) - if((. = ..())) - return - if(href_list["scan_for_machine"]) - for(var/c in GLOB.alldirs) - var/turf/T = get_step(loc, c) - if(T) - var/obj/machinery/mineral/M = locate(/obj/machinery/mineral) in T - if(M && ispath(M.console) && istype(src, M.console)) - M.console = src - connected = M - break - return TRUE - -/obj/machinery/computer/mining/Destroy() - if(connected) - if(connected.console == src) - connected.console = initial(connected.console) - connected = null - . = ..() diff --git a/code/modules/mining/machinery/mineral_processor.dm b/code/modules/mining/machinery/mineral_processor.dm deleted file mode 100644 index ef4eb1eaa34c..000000000000 --- a/code/modules/mining/machinery/mineral_processor.dm +++ /dev/null @@ -1,175 +0,0 @@ -#define ORE_DISABLED 0 -#define ORE_SMELT 1 -#define ORE_COMPRESS 2 -#define ORE_ALLOY 3 - -/obj/machinery/mineral/processing_unit - name = "mineral processor" - icon_state = "furnace" - console = /obj/machinery/computer/mining - input_turf = NORTH - output_turf = SOUTH - - var/sheets_per_tick = 10 - var/list/ores_processing - var/list/ores_stored - var/report_all_ores - var/active = FALSE - -/obj/machinery/mineral/processing_unit/Initialize() - ores_processing = list() - ores_stored = list() - for(var/orename in SSmaterials.processable_ores) - ores_processing[orename] = 0 - ores_stored[orename] = 0 - . = ..() - -/obj/machinery/mineral/processing_unit/Process() - //Grab some more ore to process this tick. - if(input_turf) - for(var/obj/item/I in recursive_content_check(input_turf, sight_check = FALSE, include_mobs = FALSE)) - if(QDELETED(I) || !I.simulated || I.anchored) - continue - if(LAZYLEN(I.matter)) - for(var/o_material in I.matter) - if(!isnull(ores_stored[o_material])) - ores_stored[o_material] += I.matter[o_material] - qdel(I) - - if(!active) - return - - //Process our stored ores and spit out sheets. - if(output_turf) - var/sheets = 0 - var/list/attempt_to_alloy = list() - for(var/metal in ores_stored) - - if(sheets >= sheets_per_tick) - break - - if(ores_stored[metal] <= 0 || ores_processing[metal] == ORE_DISABLED) - continue - - var/decl/material/M = decls_repository.get_decl(metal) - var/result = 0 // For reference: a positive result indicates sheets were produced, - // and a negative result indicates slag was produced. - var/ore_mode = ores_processing[metal] - if(ore_mode == ORE_ALLOY) - if(SSmaterials.alloy_components[metal]) - attempt_to_alloy[metal] = TRUE - else - result = min(sheets_per_tick - sheets, Floor(ores_processing[metal] / SHEET_MATERIAL_AMOUNT)) - ores_processing[metal] -= result * SHEET_MATERIAL_AMOUNT - result = -(result) - else if(ore_mode == ORE_COMPRESS) - result = attempt_compression(M, sheets_per_tick - sheets) - else if(ore_mode == ORE_SMELT) - result = attempt_smelt(M, sheets_per_tick - sheets) - - sheets += abs(result) - while(result < 0) - new /obj/item/ore(output_turf, /decl/material/solid/slag) - result++ - - // Try to make any available alloys. - if(LAZYLEN(attempt_to_alloy)) - - var/list/making_alloys = list() - for(var/thing in SSmaterials.alloy_products) - var/decl/material/M = thing - var/failed = FALSE - for(var/otherthing in M.alloy_materials) - if(!attempt_to_alloy[otherthing] || ores_stored[otherthing] < M.alloy_materials[otherthing]) - failed = TRUE - break - if(!failed) making_alloys += M - - for(var/thing in making_alloys) - if(sheets >= sheets_per_tick) break - var/decl/material/M = thing - var/making - for(var/otherthing in M.alloy_materials) - var/_make = Floor(ores_stored[otherthing] / M.alloy_materials[otherthing]) - if(isnull(making) || making > _make) - making = _make - making = min(sheets_per_tick-sheets, making) - for(var/otherthing in M.alloy_materials) - ores_stored[otherthing] -= making * M.alloy_materials[otherthing] - if(making > 0) - M.place_sheet(output_turf, making) - break - -/obj/machinery/mineral/processing_unit/proc/attempt_smelt(var/decl/material/metal, var/max_result) - . = Clamp(Floor(ores_stored[metal.type]/SHEET_MATERIAL_AMOUNT),1,max_result) - ores_stored[metal.type] -= . * SHEET_MATERIAL_AMOUNT - var/decl/material/M = decls_repository.get_decl(metal.ore_smelts_to) - if(istype(M)) - M.place_sheet(output_turf, .) - else - . = -(.) - -/obj/machinery/mineral/processing_unit/proc/attempt_compression(var/decl/material/metal, var/max_result) - var/making = Clamp(Floor(ores_stored[metal.type]/SHEET_MATERIAL_AMOUNT),1,max_result) - if(making >= 2) - ores_stored[metal.type] -= making * SHEET_MATERIAL_AMOUNT - . = Floor(making * 0.5) - var/decl/material/M = decls_repository.get_decl(metal.ore_compresses_to) - if(istype(M)) - M.place_sheet(output_turf, .) - else - . = -(.) - else - . = 0 - -/obj/machinery/mineral/processing_unit/get_console_data() - . = ..() + "

          Mineral Processing

          " - var/result = "" - for(var/ore in ores_processing) - if(!ores_stored[ore] && !report_all_ores) continue - var/decl/material/M = decls_repository.get_decl(ore) - var/line = "[capitalize(M.solid_name)][Floor(ores_stored[ore] / SHEET_MATERIAL_AMOUNT)] ([ores_stored[ore]]u)" - var/status_string - if(ores_processing[ore]) - switch(ores_processing[ore]) - if(ORE_DISABLED) - status_string = "not processing" - if(ORE_SMELT) - status_string = "smelting" - if(ORE_COMPRESS) - status_string = "compressing" - if(ORE_ALLOY) - status_string = "alloying" - else - status_string = "not processing" - result += "[line][status_string]" - . += "[result]
          " - . += "Currently displaying [report_all_ores ? "all ore types" : "only available ore types"]. [report_all_ores ? "Show less" : "Show more"]" - . += "The ore processor is currently [(active ? "enabled" : "disabled")]." - -/obj/machinery/mineral/processing_unit/Topic(href, href_list) - if((. = ..())) - return - if(href_list["toggle_smelting"]) - var/choice = input("What setting do you wish to use for processing [href_list["toggle_smelting"]]?") as null|anything in list("Smelting","Compressing","Alloying","Nothing") - if(!choice) return - switch(choice) - if("Nothing") choice = ORE_DISABLED - if("Smelting") choice = ORE_SMELT - if("Compressing") choice = ORE_COMPRESS - if("Alloying") choice = ORE_ALLOY - ores_processing[href_list["toggle_smelting"]] = choice - . = TRUE - else if(href_list["toggle_power"]) - active = !active - . = TRUE - else if(href_list["toggle_ores"]) - report_all_ores = !report_all_ores - . = TRUE - if(. && console) - console.updateUsrDialog() - -#undef ORE_DISABLED -#undef ORE_SMELT -#undef ORE_COMPRESS -#undef ORE_ALLOY \ No newline at end of file diff --git a/code/modules/mining/machinery/mineral_stacker.dm b/code/modules/mining/machinery/mineral_stacker.dm deleted file mode 100644 index f9fa19ca3840..000000000000 --- a/code/modules/mining/machinery/mineral_stacker.dm +++ /dev/null @@ -1,60 +0,0 @@ -/obj/machinery/mineral/stacking_machine - name = "stacking machine" - console = /obj/machinery/computer/mining - input_turf = EAST - output_turf = WEST - var/stack_amt = 50 - var/list/stacks = list() - -/obj/machinery/mineral/stacking_machine/Process() - if(input_turf) - for(var/obj/item/I in input_turf) - if(istype(I, /obj/item/stack/material)) - var/obj/item/stack/material/S = I - if(S.material && S.material.stack_type) - if(isnull(stacks[S.material.type])) - stacks[S.material.type] = 0 - stacks[S.material.type] += S.amount - qdel(S) - continue - if(output_turf) - I.forceMove(output_turf) - - if(output_turf) - for(var/sheet in stacks) - if(stacks[sheet] >= stack_amt) - var/decl/material/stackmat = decls_repository.get_decl(sheet) - stackmat.place_sheet(output_turf, stack_amt) - stacks[sheet] -= stack_amt - -/obj/machinery/mineral/stacking_machine/get_console_data() - . = ..() - . += "

          Sheet Stacking

          " - . += "Stacking: [stack_amt] \[change\]" - var/line = "" - for(var/stacktype in stacks) - if(stacks[stacktype] > 0) - line += "[capitalize(stacktype)][stacks[stacktype]]Release" - . += "[line]
          " - -/obj/machinery/mineral/stacking_machine/Topic(href, href_list) - if((. = ..())) - return - if(href_list["change_stack"]) - var/choice = input("What would you like to set the stack amount to?") as null|anything in list(1,5,10,20,30,50,60) - if(!choice) return - stack_amt = choice - . = TRUE - else if(href_list["release_stack"] && stacks[href_list["release_stack"]] > 0) - var/decl/material/stackmat = decls_repository.get_decl(href_list["release_stack"]) - stackmat.place_sheet(output_turf, stacks[href_list["release_stack"]]) - stacks[href_list["release_stack"]] = 0 - . = TRUE - if(. && console) - console.updateUsrDialog() - -/obj/machinery/mineral/stacking_machine/on_update_icon() - if(panel_open) - icon_state = "stacker-open" - else - icon_state = "stacker" \ No newline at end of file diff --git a/code/modules/mining/machinery/mineral_unloader.dm b/code/modules/mining/machinery/mineral_unloader.dm deleted file mode 100644 index 20a74503eca8..000000000000 --- a/code/modules/mining/machinery/mineral_unloader.dm +++ /dev/null @@ -1,18 +0,0 @@ -/obj/machinery/mineral/unloading_machine - name = "unloading machine" - icon_state = "unloader" - input_turf = WEST - output_turf = EAST - -/obj/machinery/mineral/unloading_machine/Process() - if(input_turf && output_turf) - if(length(output_turf.contents) < 15) - var/ore_this_tick = 10 - for(var/obj/structure/ore_box/unloading in input_turf) - for(var/obj/item/ore/_ore in unloading) - _ore.dropInto(output_turf) - if(--ore_this_tick<=0) return - for(var/obj/item/_ore in input_turf) - if(_ore.simulated && !_ore.anchored) - _ore.dropInto(output_turf) - if(--ore_this_tick<=0) return \ No newline at end of file diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index ea1f7ae30b21..7b3c5a3d2aaa 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -8,183 +8,39 @@ /obj/structure/closet/secure_closet/miner/WillContain() return list( new /datum/atom_creator/weighted(list( - /obj/item/storage/backpack/industrial, - /obj/item/storage/backpack/satchel/eng + /obj/item/backpack/industrial, + /obj/item/backpack/satchel/eng )), /obj/item/radio/headset/headset_cargo, - /obj/item/clothing/under/rank/miner, + /obj/item/clothing/jumpsuit/miner, /obj/item/clothing/gloves/thick, /obj/item/clothing/shoes/color/black, /obj/item/scanner/gas, - /obj/item/storage/ore, + /obj/item/ore_satchel, /obj/item/flashlight/lantern, - /obj/item/shovel, - /obj/item/pickaxe, + /obj/item/tool/shovel, + /obj/item/tool/pickaxe, /obj/item/clothing/glasses/meson ) -/**********'pickaxes' but theyre drills actually***************/ - -/obj/item/pickaxe - name = "mining drill" - desc = "The most basic of mining drills, for short excavations and small mineral extractions." - icon = 'icons/obj/items/tool/mining_drill.dmi' - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - force = 15.0 - throwforce = 4.0 - icon_state = "drill" - item_state = "jackhammer" - w_class = ITEM_SIZE_HUGE - material = /decl/material/solid/metal/steel - var/digspeed = 40 //moving the delay to an item var so R&D can make improved picks. --NEO - origin_tech = "{'materials':1,'engineering':1}" - attack_verb = list("hit", "pierced", "sliced", "attacked") - var/drill_sound = 'sound/weapons/Genhit.ogg' - var/drill_verb = "drilling" - sharp = 0 - - var/excavation_amount = 200 - var/build_from_parts = FALSE - var/hardware_color - -/obj/item/pickaxe/Initialize() - if(build_from_parts) - icon_state = "pick_hardware" - color = hardware_color - overlays += overlay_image(icon, "pick_handle", flags=RESET_COLOR) - . = ..() - -/obj/item/pickaxe/hammer - name = "sledgehammer" - desc = "A mining hammer made of reinforced metal. You feel like smashing your boss in the face with this." - icon = 'icons/obj/items/tool/sledgehammer.dmi' - icon_state = "sledgehammer" - -/obj/item/pickaxe/drill - name = "advanced mining drill" // Can dig sand as well! - icon_state = "handdrill" - item_state = "jackhammer" - digspeed = 30 - origin_tech = "{'materials':2,'powerstorage':3,'engineering':2}" - desc = "Yours is the drill that will pierce through the rock walls." - drill_verb = "drilling" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - -/obj/item/pickaxe/jackhammer - name = "sonic jackhammer" - icon_state = "jackhammer" - item_state = "jackhammer" - digspeed = 20 //faster than drill, but cannot dig - origin_tech = "{'materials':3,'powerstorage':2,'engineering':2}" - desc = "Cracks rocks with sonic blasts, perfect for killing cave lizards." - drill_verb = "hammering" - -/obj/item/pickaxe/diamonddrill //When people ask about the badass leader of the mining tools, they are talking about ME! - name = "diamond mining drill" - icon_state = "diamonddrill" - item_state = "jackhammer" - digspeed = 5 //Digs through walls, girders, and can dig up sand - origin_tech = "{'materials':6,'powerstorage':4,'engineering':5}" - desc = "Yours is the drill that will pierce the heavens!" - drill_verb = "drilling" - material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE - ) - -/obj/item/pickaxe/borgdrill - name = "cyborg mining drill" - icon_state = "diamonddrill" - item_state = "jackhammer" - digspeed = 15 - desc = "" - drill_verb = "drilling" - -//****************************actual pickaxes*********************** -/obj/item/pickaxe/silver - name = "silver pickaxe" - desc = "This makes no metallurgic sense." - icon = 'icons/obj/items/tool/pickaxe.dmi' - icon_state = "pick_preview" - item_state = "pickaxe" - digspeed = 30 - origin_tech = "{'materials':3}" - drill_verb = "picking" - sharp = 1 - build_from_parts = TRUE - hardware_color = COLOR_SILVER - -/obj/item/pickaxe/gold - name = "golden pickaxe" - desc = "This makes no metallurgic sense." - icon = 'icons/obj/items/tool/pickaxe.dmi' - icon_state = "pick_preview" - item_state = "pickaxe" - digspeed = 20 - origin_tech = "{'materials':4}" - drill_verb = "picking" - sharp = 1 - build_from_parts = TRUE - hardware_color = COLOR_GOLD - -/obj/item/pickaxe/diamond - name = "diamond pickaxe" - desc = "A pickaxe with a diamond pick head." - icon = 'icons/obj/items/tool/pickaxe.dmi' - icon_state = "pick_preview" - item_state = "pickaxe" - digspeed = 10 - origin_tech = "{'materials':6,'engineering':4}" - drill_verb = "picking" - sharp = 1 - build_from_parts = TRUE - hardware_color = COLOR_DIAMOND - material = /decl/material/solid/gemstone/diamond /*****************************Shovel********************************/ -/obj/item/shovel - name = "shovel" - desc = "A large tool for digging and moving dirt." - icon = 'icons/obj/items/tool/shovel.dmi' - icon_state = "shovel" - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - force = 8.0 - throwforce = 4.0 - item_state = "shovel" - w_class = ITEM_SIZE_HUGE - origin_tech = "{'materials':1,'engineering':1}" - material = /decl/material/solid/metal/steel - attack_verb = list("bashed", "bludgeoned", "thrashed", "whacked") - sharp = 0 - edge = 1 - -/obj/item/shovel/spade - name = "spade" - desc = "A small tool for digging and moving dirt." - icon = 'icons/obj/items/tool/spade.dmi' - icon_state = "spade" - item_state = "spade" - force = 5.0 - throwforce = 7.0 - w_class = ITEM_SIZE_SMALL - // Flags. /obj/item/stack/flag name = "beacon" - desc = "Some deployable high-visibilty beacons." + desc = "Some deployable high-visibility beacons." singular_name = "beacon" icon_state = "folded" amount = 10 max_amount = 10 icon = 'icons/obj/items/marking_beacon.dmi' + z_flags = ZMM_MANGLE_PLANES + + var/upright = FALSE - var/upright = 0 - var/fringe = null +/obj/item/stack/flag/ten + amount = 10 /obj/item/stack/flag/red light_color = COLOR_RED @@ -205,23 +61,22 @@ . = ..() update_icon() -/obj/item/stack/flag/attackby(var/obj/item/W, var/mob/user) +/obj/item/stack/flag/attackby(var/obj/item/used_item, var/mob/user) if(upright) - attack_hand(user) - return + return attack_hand_with_interaction_checks(user) return ..() /obj/item/stack/flag/attack_hand(var/mob/user) - if(upright) - knock_down() - user.visible_message("\The [user] knocks down \the [singular_name].") - return - return ..() + if(!upright) + return ..() + knock_down() + user.visible_message("\The [user] knocks down \the [singular_name].") + return TRUE /obj/item/stack/flag/attack_self(var/mob/user) var/turf/T = get_turf(src) - if(istype(T, /turf/space) || istype(T, /turf/simulated/open)) + if(!istype(T) || T.is_open()) to_chat(user, "There's no solid surface to plant \the [singular_name] on.") return @@ -233,38 +88,34 @@ if(use(1)) // Don't skip use() checks even if you only need one! Stacks with the amount of 0 are possible, e.g. on synthetics! var/obj/item/stack/flag/newflag = new src.type(T, 1) newflag.set_up() - if(istype(T, /turf/simulated/floor/asteroid) || istype(T, /turf/simulated/floor/exoplanet)) + if(T.can_be_dug()) user.visible_message("\The [user] plants \the [newflag.singular_name] firmly in the ground.") else user.visible_message("\The [user] attaches \the [newflag.singular_name] firmly to the ground.") /obj/item/stack/flag/proc/set_up() upright = 1 - anchored = 1 + anchored = TRUE update_icon() /obj/item/stack/flag/on_update_icon() - overlays.Cut() + . = ..() if(upright) pixel_x = 0 pixel_y = 0 icon_state = "base" - var/image/addon = image(icon = icon, icon_state = "glowbit") - addon.color = light_color - addon.layer = ABOVE_LIGHTING_LAYER - addon.plane = EFFECTS_ABOVE_LIGHTING_PLANE - overlays += addon - set_light(0.2, 0.1, 1) // Very dim so the rest of the thingie is barely visible - if the turf is completely dark, you can't see anything on it, no matter what + add_overlay(emissive_overlay(icon = icon, icon_state = "glowbit", color = light_color)) + z_flags |= ZMM_MANGLE_PLANES + set_light(2, 0.1) // Very dim so the rest of the thingie is barely visible - if the turf is completely dark, you can't see anything on it, no matter what else pixel_x = rand(-randpixel, randpixel) pixel_y = rand(-randpixel, randpixel) icon_state = "folded" - var/image/addon = image(icon = icon, icon_state = "basebit") - addon.color = light_color - overlays += addon + add_overlay(overlay_image(icon, "basebit", light_color)) + z_flags &= ~ZMM_MANGLE_PLANES set_light(0) /obj/item/stack/flag/proc/knock_down() upright = 0 - anchored = 0 + anchored = FALSE update_icon() diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 9b65ae9df9a8..3c6fc6674592 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -3,147 +3,6 @@ icon = 'icons/turf/walls.dmi' icon_state = "rock-dark" blocks_air = 1 - density = 1 - opacity = 1 - -var/list/mining_floors = list() -/**********************Asteroid**************************/ -// Setting icon/icon_state initially will use these values when the turf is built on/replaced. -// This means you can put grass on the asteroid etc. -/turf/simulated/floor/asteroid - name = "sand" - icon = 'icons/turf/flooring/asteroid.dmi' - icon_state = "asteroid" - base_name = "sand" - base_desc = "Gritty and unpleasant." - base_icon = 'icons/turf/flooring/asteroid.dmi' - base_icon_state = "asteroid" - footstep_type = /decl/footsteps/asteroid - - initial_flooring = null - initial_gas = null - temperature = TCMB - var/dug = 0 //0 = has not yet been dug, 1 = has already been dug - var/overlay_detail - has_resources = 1 - -/turf/simulated/floor/asteroid/Initialize() - . = ..() - if (!mining_floors["[src.z]"]) - mining_floors["[src.z]"] = list() - mining_floors["[src.z]"] += src - if(prob(20)) - overlay_detail = "asteroid[rand(0,9)]" - -/turf/simulated/floor/asteroid/Destroy() - if (mining_floors["[src.z]"]) - mining_floors["[src.z]"] -= src - return ..() - -/turf/simulated/floor/asteroid/explosion_act(severity) - SHOULD_CALL_PARENT(FALSE) - if(severity == 1 || (severity == 2 && prob(70))) - gets_dug() - -/turf/simulated/floor/asteroid/is_plating() - return !density - -/turf/simulated/floor/asteroid/attackby(obj/item/W, mob/user) - if(!W || !user) - return 0 - - var/list/usable_tools = list( - /obj/item/shovel, - /obj/item/pickaxe/diamonddrill, - /obj/item/pickaxe/drill, - /obj/item/pickaxe/borgdrill - ) - - var/valid_tool - for(var/valid_type in usable_tools) - if(istype(W,valid_type)) - valid_tool = 1 - break - - if(valid_tool) - if (dug) - to_chat(user, "This area has already been dug") - return TRUE - - var/turf/T = user.loc - if (!(istype(T))) - return - - to_chat(user, "You start digging.") - playsound(user.loc, 'sound/effects/rustle1.ogg', 50, 1) - . = TRUE - - if(!do_after(user,40, src)) return - - to_chat(user, "You dug a hole.") - gets_dug() - - else if(istype(W,/obj/item/storage/ore)) - var/obj/item/storage/ore/S = W - if(S.collection_mode) - for(var/obj/item/ore/O in contents) - return O.attackby(W,user) - else if(istype(W,/obj/item/storage/bag/fossils)) - var/obj/item/storage/bag/fossils/S = W - if(S.collection_mode) - for(var/obj/item/fossil/F in contents) - return F.attackby(W,user) - - else - return ..(W,user) - -/turf/simulated/floor/asteroid/proc/gets_dug() - - if(dug) - return - - for(var/i=0;i<(rand(3)+2);i++) - new/obj/item/ore/glass(src) - - dug = 1 - icon_state = "asteroid_dug" - return - -/turf/simulated/floor/asteroid/proc/updateMineralOverlays(var/update_neighbors) - - overlays.Cut() - - var/list/step_overlays = list("n" = NORTH, "s" = SOUTH, "e" = EAST, "w" = WEST) - for(var/direction in step_overlays) - - if(istype(get_step(src, step_overlays[direction]), /turf/space)) - var/image/aster_edge = image('icons/turf/flooring/asteroid.dmi', "asteroid_edges", dir = step_overlays[direction]) - aster_edge.layer = DECAL_LAYER - overlays += aster_edge - - if(overlay_detail) - var/image/floor_decal = image(icon = 'icons/turf/flooring/decals.dmi', icon_state = overlay_detail) - floor_decal.layer = DECAL_LAYER - overlays |= floor_decal - - if(update_neighbors) - var/list/all_step_directions = list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,SOUTHWEST,WEST,NORTHWEST) - for(var/direction in all_step_directions) - var/turf/simulated/floor/asteroid/A - if(istype(get_step(src, direction), /turf/simulated/floor/asteroid)) - A = get_step(src, direction) - A.updateMineralOverlays() - -/turf/simulated/floor/asteroid/Entered(atom/movable/M) - ..() - if(istype(M,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = M - if(R.module) - if(istype(R.module_state_1,/obj/item/storage/ore)) - attackby(R.module_state_1,R) - else if(istype(R.module_state_2,/obj/item/storage/ore)) - attackby(R.module_state_2,R) - else if(istype(R.module_state_3,/obj/item/storage/ore)) - attackby(R.module_state_3,R) - else - return + density = TRUE + opacity = TRUE + turf_flags = TURF_IS_HOLOMAP_OBSTACLE diff --git a/code/modules/mining/ore_box.dm b/code/modules/mining/ore_box.dm new file mode 100644 index 000000000000..cc4cb28c8c6d --- /dev/null +++ b/code/modules/mining/ore_box.dm @@ -0,0 +1,160 @@ + +/**********************Ore box**************************/ + +/obj/structure/ore_box + name = "ore box" + desc = "A heavy box used for storing ore." + icon = 'icons/obj/structures/ore_box.dmi' + icon_state = ICON_STATE_WORLD + density = TRUE + material = /decl/material/solid/organic/wood/oak + atom_flags = ATOM_FLAG_CLIMBABLE + tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) + ///Maximum amount of ores of all types that can be stored in the box. + var/tmp/maximum_ores = 1200 + ///The current total amount of ores of all types that were placed inside. + var/total_ores = 0 + ///A list with all the ores of every types that are currently inside. Associative list (ore name = ore amount). + var/list/stored_ore + +/obj/structure/ore_box/attack_hand(mob/user) + if(total_ores <= 0 || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/obj/item/stack/material/ore/O = pick(get_contained_external_atoms()) + if(!remove_ore(O, user)) + return ..() + to_chat(user, SPAN_NOTICE("You grab a random ore pile from \the [src].")) + return TRUE + +/obj/structure/ore_box/attackby(obj/item/used_item, mob/user) + if (istype(used_item, /obj/item/stack/material/ore)) + return insert_ore(used_item, user) + if(used_item.storage) + var/added_ore = FALSE + used_item.storage.hide_from(user) + for(var/obj/item/stack/material/ore/O in used_item.storage.get_contents()) + if(total_ores >= maximum_ores) + break + used_item.storage.remove_from_storage(user, O, src, TRUE) + insert_ore(O) + added_ore = TRUE + if(added_ore) + used_item.storage.finish_bulk_removal() + to_chat(user, SPAN_NOTICE("You empty \the [used_item] into \the [src].")) + return TRUE + return ..() + +///Insert many ores into the box +/obj/structure/ore_box/proc/insert_ores(var/list/ores, var/mob/user) + var/inserted = 0 + for(var/obj/item/stack/material/ore/O in ores) + if(total_ores >= maximum_ores) + if(user) + to_chat(user, SPAN_WARNING("You insert only what you can.")) + break + inserted += O.amount + insert_ore(O) + return inserted + +///Inserts an ore pile into the box +/obj/structure/ore_box/proc/insert_ore(var/obj/item/stack/material/ore/O, var/mob/user) + var/possible_amount = max(0, maximum_ores - (O.amount + total_ores)) + if(possible_amount == 0) + if(user) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return FALSE + else if(possible_amount < O.amount) //Only split if we have more than one, and if the whole stack doesn't fit + if(!O.can_split()) + if(user) + to_chat(user, SPAN_WARNING("You can't fit that in there!")) + return FALSE + O = O.split(possible_amount) + + if(user) + user.try_unequip(O, src) + add_fingerprint(user) + else + O.forceMove(src) + + LAZYSET(stored_ore, O.name, min(LAZYACCESS(stored_ore, O.name) + O.amount, maximum_ores)) + total_ores = min(O.amount + total_ores, maximum_ores) + return TRUE + +///Remove the given ore from the box +/obj/structure/ore_box/proc/remove_ore(var/obj/item/stack/material/ore/O, var/mob/user) + if(total_ores <= 0) + if(user) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return FALSE + if(user && !user.check_dexterity(DEXTERITY_HOLD_ITEM)) + to_chat(user, SPAN_WARNING("You lack the dexterity to empty \the [src]!")) + return FALSE + + if(user) + user.put_in_hands(O) + add_fingerprint(user) + else + O.forceMove(loc) + + LAZYSET(stored_ore, O.name, max(0, LAZYACCESS(stored_ore, O.name) - O.amount)) + total_ores = max(0, total_ores - O.amount) + return O + +/obj/structure/ore_box/proc/empty_box(var/mob/user) + if(total_ores <= 0) + if(user) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return FALSE + if(user && !user.check_dexterity(DEXTERITY_HOLD_ITEM)) + to_chat(user, SPAN_WARNING("You lack the dexterity to empty \the [src]!")) + return FALSE + if(user) + add_fingerprint(user) + to_chat(user, SPAN_NOTICE("You empty \the [src].")) + dump_contents() + LAZYCLEARLIST(stored_ore) + total_ores = 0 + return TRUE + +/obj/structure/ore_box/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1) //Can only check the contents of ore boxes if you can physically reach them. + return + + add_fingerprint(user) + if(total_ores <= 0) + . += "It is empty." + return + . += "It holds:" + for(var/ore in stored_ore) + if(stored_ore[ore] == 0) + continue + . += "- [stored_ore[ore]] [ore]" + +/obj/structure/ore_box/explosion_act(severity) + . = ..() + if(. && !QDELETED(src) && (severity == 1 || prob(50))) + physically_destroyed() + +/obj/structure/ore_box/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && istype(dropping, /obj/machinery/mining_drill)) + var/obj/machinery/mining_drill/D = dropping + D.unload_into_box(src, user) + + +/obj/structure/ore_box/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/empty/ore_box) + +/decl/interaction_handler/empty/ore_box + name = "Empty Box" + expected_target_type = /obj/structure/ore_box + examine_desc = "empty $TARGET_THEM$" + +/decl/interaction_handler/empty/ore_box/is_possible(obj/structure/ore_box/target, mob/user, obj/item/prop) + return ..() && target.total_ores > 0 + +/decl/interaction_handler/empty/ore_box/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/ore_box/box = target + box.empty_box(user) diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm deleted file mode 100644 index fdbc06d4db8b..000000000000 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ /dev/null @@ -1,92 +0,0 @@ - -/**********************Ore box**************************/ - -/obj/structure/ore_box - icon = 'icons/obj/mining.dmi' - icon_state = "orebox0" - name = "ore box" - desc = "A heavy box used for storing ore." - density = 1 - var/last_update = 0 - var/list/stored_ore = list() - -/obj/structure/ore_box/attackby(obj/item/W, mob/user) - if (istype(W, /obj/item/ore)) - user.unEquip(W, src) - else if (istype(W, /obj/item/storage)) - var/obj/item/storage/S = W - S.hide_from(usr) - for(var/obj/item/ore/O in S.contents) - S.remove_from_storage(O, src, 1) //This will move the item to this item's contents - S.finish_bulk_removal() - to_chat(user, "You empty the satchel into the box.") - - update_ore_count() - -/obj/structure/ore_box/proc/update_ore_count() - - stored_ore = list() - - for(var/obj/item/ore/O in contents) - - if(stored_ore[O.name]) - stored_ore[O.name]++ - else - stored_ore[O.name] = 1 - -/obj/structure/ore_box/examine(mob/user) - . = ..() - - // Borgs can now check contents too. - if((!istype(user, /mob/living/carbon/human)) && (!istype(user, /mob/living/silicon/robot))) - return - - if(!Adjacent(user)) //Can only check the contents of ore boxes if you can physically reach them. - return - - add_fingerprint(user) - - if(!contents.len) - to_chat(user, "It is empty.") - return - - if(world.time > last_update + 10) - update_ore_count() - last_update = world.time - - to_chat(user, "It holds:") - for(var/ore in stored_ore) - to_chat(user, "- [stored_ore[ore]] [ore]") - return - - -/obj/structure/ore_box/verb/empty_box() - set name = "Empty Ore Box" - set category = "Object" - set src in view(1) - - if(!istype(usr, /mob/living/carbon/human)) //Only living, intelligent creatures with hands can empty ore boxes. - to_chat(usr, "You are physically incapable of emptying the ore box.") - return - - if( usr.stat || usr.restrained() ) - return - - if(!Adjacent(usr)) //You can only empty the box if you can physically reach it - to_chat(usr, "You cannot reach the ore box.") - return - - add_fingerprint(usr) - - if(contents.len < 1) - to_chat(usr, "The ore box is empty") - return - - for (var/obj/item/ore/O in contents) - O.dropInto(loc) - to_chat(usr, "You empty the ore box") - -/obj/structure/ore_box/explosion_act(severity) - . = ..() - if(. && !QDELETED(src) && (severity == 1 || prob(50))) - physically_destroyed(src) \ No newline at end of file diff --git a/code/modules/mob/animations.dm b/code/modules/mob/animations.dm index 48a9f6c91229..574b2f558962 100644 --- a/code/modules/mob/animations.dm +++ b/code/modules/mob/animations.dm @@ -1,109 +1,30 @@ -/* -adds a dizziness amount to a mob -use this rather than directly changing var/dizziness -since this ensures that the dizzy_process proc is started -currently only humans get dizzy - -value of dizziness ranges from 0 to 1000 -below 100 is not dizzy -*/ - -/mob/var/dizziness = 0//Carbon -/mob/var/is_dizzy = 0 - -/mob/proc/make_dizzy(var/amount) - if(!istype(src, /mob/living/carbon/human)) // for the moment, only humans get dizzy - return - - dizziness = min(1000, dizziness + amount) // store what will be new value - // clamped to max 1000 - if(dizziness > 100 && !is_dizzy) - spawn(0) - dizzy_process() - - -/* -dizzy process - wiggles the client's pixel offset over time -spawned from make_dizzy(), will terminate automatically when dizziness gets <100 -note dizziness decrements automatically in the mob's Life() proc. -*/ -/mob/proc/dizzy_process() - is_dizzy = 1 - while(dizziness > 100) - if(client) - var/amplitude = dizziness*(sin(dizziness * 0.044 * world.time) + 1) / 70 - client.pixel_x = amplitude * sin(0.008 * dizziness * world.time) - client.pixel_y = amplitude * cos(0.008 * dizziness * world.time) - - sleep(1) - //endwhile - reset the pixel offsets to zero - is_dizzy = 0 - if(client) - client.pixel_x = 0 - client.pixel_y = 0 - -// jitteriness - copy+paste of dizziness -/mob/var/is_jittery = FALSE -/mob/var/jitteriness = 0//Carbon - -/mob/proc/make_jittery(var/amount) - return //Only for living/carbon/human/ - -/mob/living/carbon/human/make_jittery(var/amount) - if(jittery_damage()) - jitteriness = Clamp(jitteriness + amount, 0, 1000) - if(jitteriness > 100) - jittery_process() - -// Typo from the original coder here, below lies the jitteriness process. So make of his code what you will, the previous comment here was just a copypaste of the above. -/mob/proc/jittery_process() - set waitfor = 0 - if(is_jittery) - return - is_jittery = TRUE - while(jitteriness > 100) - var/amplitude = min(4, jitteriness / 100) - do_jitter(amplitude) - sleep(1) - //endwhile - reset the pixel offsets to zero - is_jittery = FALSE - do_jitter(0) - /mob/proc/do_jitter(amplitude) pixel_x = default_pixel_x + rand(-amplitude, amplitude) pixel_y = default_pixel_y + rand(-amplitude/3, amplitude/3) //handles up-down floaty effect in space and zero-gravity /mob/var/is_floating = 0 -/mob/var/floatiness = 0 /mob/proc/update_floating() if(anchored || buckled || has_gravity()) - make_floating(0) + stop_floating() return - if(check_space_footing()) - make_floating(0) + if(!can_slip(magboots_only = TRUE)) + stop_floating() return - make_floating(1) + start_floating() return -/mob/proc/make_floating(var/n) - floatiness = n - - if(floatiness && !is_floating) - start_floating() - else if(!floatiness && is_floating) - stop_floating() - /mob/proc/start_floating() - is_floating = 1 + is_floating = TRUE + update_turf_alpha_mask() var/amplitude = 2 //maximum displacement from original position - var/period = 36 //time taken for the mob to go up >> down >> original position, in deciseconds. Should be multiple of 4 + var/period = 36 //time taken for the mob to go up > down > original position, in deciseconds. Should be multiple of 4 var/top = default_pixel_z + amplitude var/bottom = default_pixel_z - amplitude @@ -117,84 +38,100 @@ note dizziness decrements automatically in the mob's Life() proc. /mob/proc/stop_floating() animate(src, pixel_z = default_pixel_z, time = 5, easing = SINE_EASING | EASE_IN) //halt animation //reset the pixel offsets to zero - is_floating = 0 + is_floating = FALSE + update_turf_alpha_mask() + +/atom/movable/proc/do_attack_animation(atom/A, atom/movable/weapon) -/atom/movable/proc/do_attack_animation(atom/A) + set waitfor = FALSE var/pixel_x_diff = 0 var/pixel_y_diff = 0 + var/turn_dir = 1 + var/direction = get_dir(src, A) - switch(direction) - if(NORTH) - pixel_y_diff = 8 - if(SOUTH) - pixel_y_diff = -8 - if(EAST) - pixel_x_diff = 8 - if(WEST) - pixel_x_diff = -8 - if(NORTHEAST) - pixel_x_diff = 8 - pixel_y_diff = 8 - if(NORTHWEST) - pixel_x_diff = -8 - pixel_y_diff = 8 - if(SOUTHEAST) - pixel_x_diff = 8 - pixel_y_diff = -8 - if(SOUTHWEST) - pixel_x_diff = -8 - pixel_y_diff = -8 - - var/default_pixel_x = initial(pixel_x) - var/default_pixel_y = initial(pixel_y) - var/mob/mob = src - if(istype(mob)) - default_pixel_x = mob.default_pixel_x - default_pixel_y = mob.default_pixel_y - - animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2) - animate(pixel_x = default_pixel_x, pixel_y = default_pixel_y, time = 2) - -/mob/do_attack_animation(atom/A) + if(direction & NORTH) + pixel_y_diff = 8 + turn_dir = rand(50) ? -1 : 1 + else if(direction & SOUTH) + pixel_y_diff = -8 + turn_dir = rand(50) ? -1 : 1 + + if(direction & EAST) + pixel_x_diff = 8 + else if(direction & WEST) + pixel_x_diff = -8 + turn_dir = -1 + + var/matrix/initial_transform = matrix(transform) + var/matrix/rotated_transform = transform.Turn(15 * turn_dir) + + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform = rotated_transform, time = 2, easing = BACK_EASING | EASE_IN) + animate(pixel_x = pixel_x, pixel_y = pixel_y, transform = initial_transform, time = 2, easing = BACK_EASING | EASE_IN) + + if(buckled_mob) + buckled_mob.do_attack_animation(A, weapon) + + sleep(4) + reset_offsets() + + if(buckled_mob) + buckled_mob.do_attack_animation(A, weapon) + +/mob/proc/clear_shown_overlays(var/list/show_to, var/image/I) + for(var/client/C in show_to) + C.images -= I + +/mob/do_attack_animation(atom/A, atom/movable/weapon) ..() is_floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement. - // What icon do we use for the attack? - var/image/I - if(hand && l_hand) // Attacked with item in left hand. - I = image(l_hand.icon, A, l_hand.icon_state, A.layer + 1) - else if (!hand && r_hand) // Attacked with item in right hand. - I = image(r_hand.icon, A, r_hand.icon_state, A.layer + 1) - else // Attacked with a fist? - return + // What are we attacking with? + if(!weapon) + weapon = get_active_held_item() + if(!weapon) + return + + // Create an image to show to viewers. + // Reset plane and layer so that it doesn't inherit the UI settings from equipped items. + var/image/I = new(loc = A) + I.appearance = weapon + I.plane = DEFAULT_PLANE + I.layer = A.layer + 0.1 + I.pixel_x = -(A.pixel_x) + I.pixel_y = -(A.pixel_y) + I.pixel_z = -(A.pixel_z) + I.pixel_w = -(A.pixel_w) // Who can see the attack? var/list/viewing = list() - for (var/mob/M in viewers(A)) - if (M.client) + for(var/mob/M in viewers(A)) + if(M.client) viewing |= M.client - flick_overlay(I, viewing, 5) // 5 ticks/half a second + + for(var/client/C in viewing) + C.images += I + addtimer(CALLBACK(src, PROC_REF(clear_shown_overlays), viewing, I), 5) // Scale the icon. I.transform *= 0.75 // Set the direction of the icon animation. var/direction = get_dir(src, A) if(direction & NORTH) - I.pixel_y = -16 + I.pixel_y -= 16 else if(direction & SOUTH) - I.pixel_y = 16 + I.pixel_y += 16 if(direction & EAST) - I.pixel_x = -16 + I.pixel_x -= 16 else if(direction & WEST) - I.pixel_x = 16 + I.pixel_x += 16 if(!direction) // Attacked self?! - I.pixel_z = 16 + I.pixel_z += 16 // And animate the attack! - animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3) + animate(I, alpha = 175, pixel_x = -(A.pixel_x), pixel_y = -(A.pixel_y), pixel_z = -(A.pixel_z), pixel_w = -(A.pixel_w), time = 3) /mob/proc/spin(spintime, speed) spawn() @@ -228,29 +165,24 @@ note dizziness decrements automatically in the mob's Life() proc. playsound(T, "sparks", 50, 1) anim(src,'icons/mob/mob.dmi',,"phaseout",,dir) -/mob/living/proc/on_structure_offset(var/offset = 0) - - var/next_x = default_pixel_x - var/next_y = default_pixel_y - var/next_z = default_pixel_z - - if(offset) - next_z += offset - else if(pixel_z != default_pixel_z) - var/turf/T = get_turf(src) - for(var/obj/structure/S in T.contents) - if(S && S.mob_offset) - return - - if(buckled && buckled.buckle_pixel_shift) - var/list/pixel_shift = cached_json_decode(buckled.buckle_pixel_shift) - next_x = default_pixel_x + pixel_shift["x"] - next_y = default_pixel_y + pixel_shift["y"] - next_z = default_pixel_z + pixel_shift["z"] - - if(pixel_x != next_x || pixel_y != next_y || pixel_z != next_z) - animate(src, pixel_x = next_x, pixel_y = next_y, pixel_z = next_z, 2, 1, SINE_EASING) - -/mob/living/Move() - . = ..() - on_structure_offset(0) +// Similar to attack animations, but in reverse and is longer to act as a telegraph. +/atom/movable/proc/do_windup_animation(atom/A, windup_time, no_reset) + + var/pixel_x_diff = 0 + var/pixel_y_diff = 0 + + var/direction = get_dir(src, A) + if(direction & NORTH) + pixel_y_diff = -8 + else if(direction & SOUTH) + pixel_y_diff = 8 + if(direction & EAST) + pixel_x_diff = -8 + else if(direction & WEST) + pixel_x_diff = 8 + + if(no_reset) + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = windup_time) + else + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = windup_time-2) + animate(pixel_x = default_pixel_x, pixel_y = default_pixel_y, time = 2) diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 0bd8c8770aaa..65c207b4ec7c 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -1,89 +1,107 @@ -//This is the proc for gibbing a mob. Cannot gib ghosts. -//added different sort of gibs and animations. N -/mob/proc/gib(anim="gibbed-m",do_gibs) - death(1) - ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) - icon = null - set_invisibility(101) - UpdateLyingBuckledAndVerbStatus() - remove_from_dead_mob_list() - - var/atom/movable/overlay/animation = new(src) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' +/mob/proc/handle_existence_failure(dusted) - flick(anim, animation) - if(do_gibs) gibs(loc, dna) + // Make sure they're actually dead. + if(stat != DEAD) + death(gibbed = TRUE) + if(stat != DEAD) + return FALSE - addtimer(CALLBACK(src, .proc/check_delete, animation), 15) + ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) -/mob/proc/check_delete(var/atom/movable/overlay/animation) - if(animation) qdel(animation) - if(src) qdel(src) + var/animation_state = get_gibbed_state(dusted) + var/animation_icon = get_gibbed_icon() // Needs to be done before nulling icon below. -//This is the proc for turning a mob into ash. Mostly a copy of gib code (above). -//Originally created for wizard disintegrate. I've removed the virus code since it's irrelevant here. -//Dusting robots does not eject the MMI, so it's a bit more powerful than gib() /N -/mob/proc/dust(anim="dust-m",remains=/obj/effect/decal/cleanable/ash) - death(1) - var/atom/movable/overlay/animation = null - ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) icon = null - set_invisibility(101) + set_invisibility(INVISIBILITY_ABSTRACT) + dump_contents() + QDEL_IN(src, 1.5 SECONDS) + + if(animation_state && animation_icon) + var/atom/movable/overlay/animation + animation = new(loc) + animation.icon_state = "blank" + animation.icon = animation_icon + animation.master = src + flick(animation_state, animation) + QDEL_IN(animation, 1.5 SECONDS) + + return TRUE + +/mob/proc/get_dusted_remains() + var/decl/species/my_species = get_species() + return my_species ? my_species.remains_type : /obj/effect/decal/cleanable/ash + +/mob/proc/get_gibbed_state(dusted) + var/decl/species/my_species = get_species() + if(dusted) + return my_species ? my_species.dusted_anim : "dust-m" + return my_species ? my_species.gibbed_anim : "gibbed-m" + +/mob/proc/get_gibbed_icon() + return 'icons/mob/mob.dmi' + +//This is the proc for gibbing a mob. Cannot gib ghosts. +//added different sort of gibs and animations. N +/mob/proc/gib(do_gibs = TRUE) + SHOULD_CALL_PARENT(TRUE) + set waitfor = FALSE + var/lastloc = loc + . = handle_existence_failure(dusted = FALSE) + if(. && do_gibs) + spawn_gibber(lastloc) - animation = new(loc) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src +//This is the proc for turning a mob into ash. Mostly a copy of gib code (above). +//Originally created for Disintegrate. I've removed the virus code since it's irrelevant here. +//Dusting robots does not eject the brain, so it's a bit more powerful than gib() /N +/mob/proc/dust() + SHOULD_CALL_PARENT(TRUE) + set waitfor = FALSE + var/lastloc = loc + . = handle_existence_failure(dusted = TRUE) + if(. && lastloc) + var/remains = get_dusted_remains() + if(remains) + new remains(lastloc) - flick(anim, animation) - new remains(loc) +/mob/proc/get_death_message(gibbed) + return SKIP_DEATH_MESSAGE - remove_from_dead_mob_list() - addtimer(CALLBACK(src, .proc/check_delete, animation), 15) +/mob/proc/get_self_death_message(gibbed) + return "You have died." +/mob/proc/death(gibbed) -/mob/proc/death(gibbed,deathmessage="seizes up and falls limp...", show_dead_message = "You have died.") + SHOULD_CALL_PARENT(TRUE) if(stat == DEAD) - return 0 + return FALSE + stop_automove() facing_dir = null - if(!gibbed && deathmessage != "no message") // This is gross, but reliable. Only brains use it. - src.visible_message("\The [src.name] [deathmessage]") + if(!gibbed) + var/death_message = get_death_message(gibbed) + if(death_message != SKIP_DEATH_MESSAGE) + visible_message("\The [src] [death_message]") + + for(var/obj/item/organ/O in get_organs()) + O.on_holder_death(gibbed) set_stat(DEAD) adjust_stamina(-100) reset_plane_and_layer() - UpdateLyingBuckledAndVerbStatus() - - dizziness = 0 - jitteriness = 0 + update_posture() + if(!gibbed) + clear_status_conditions() set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) set_see_in_dark(8) set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) - drop_r_hand() - drop_l_hand() - - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable?.hat) - hattable.hat.dropInto(get_turf(src)) - hattable.hat = null + drop_held_items() SSstatistics.report_death(src) - //TODO: Change death state to health_dead for all these icon files. This is a stop gap. - if(healths) - healths.overlays.Cut() // This is specific to humans but the relevant code is here; shouldn't mess with other mobs. - if("health7" in icon_states(healths.icon)) - healths.icon_state = "health7" - else - healths.icon_state = "health6" - log_debug("[src] ([src.type]) died but does not have a valid health7 icon_state (using health6 instead). report this error to Ccomp5950 or your nearest Developer") - timeofdeath = world.time if(mind) mind.StoreMemory("Time of death: [stationtime2text()]", /decl/memory_options/system) @@ -93,5 +111,9 @@ if(SSticker.mode) SSticker.mode.check_win() - to_chat(src,"[show_dead_message]") - return 1 + + var/show_dead_message = get_self_death_message(gibbed) + if(show_dead_message) + to_chat(src,"[show_dead_message]") + + return TRUE diff --git a/code/modules/mob/dview.dm b/code/modules/mob/dview.dm new file mode 100644 index 000000000000..67149bcf7861 --- /dev/null +++ b/code/modules/mob/dview.dm @@ -0,0 +1,29 @@ +//DVIEW is a hack that uses a mob with darksight in order to find lists of viewable stuff while ignoring darkness +// Defines for dview are elsewhere. + +var/global/mob/dview/dview_mob = new + +/mob/dview + anchored = TRUE + density = FALSE + invisibility = INVISIBILITY_ABSTRACT + see_in_dark = 1e6 + simulated = FALSE + virtual_mob = null + is_spawnable_type = FALSE + +/mob/dview/Destroy(force = FALSE) + SHOULD_CALL_PARENT(FALSE) + PRINT_STACK_TRACE("Someone [force ? "force-" : ""]qdeleted the dview mob.") + if (!force) + return QDEL_HINT_LETMELIVE + + to_world_log("Dview was force-qdeleted, this should never happen!") + + dview_mob = new + return QDEL_HINT_QUEUE + +/mob/dview/Initialize() + . = ..() + // We don't want to be in any mob lists; we're a dummy not a mob. + STOP_PROCESSING(SSmobs, src) diff --git a/code/modules/mob/examine.dm b/code/modules/mob/examine.dm new file mode 100644 index 000000000000..c269075eb9b3 --- /dev/null +++ b/code/modules/mob/examine.dm @@ -0,0 +1,65 @@ +/mob/proc/get_visible_pronouns(hideflags) + //suits/masks/helmets make it hard to tell their gender + if((hideflags & HIDEJUMPSUIT) && (hideflags & HIDEFACE)) + return GET_DECL(/decl/pronouns/pseudoplural) + return get_pronouns() + +// At some point this could have a client pref or server config option that switches second-person to first-person. +/mob/proc/get_self_pronouns() + return GET_DECL(/decl/pronouns/second_person_singular) + +/mob/proc/get_visible_pronouns_for_viewer(mob/viewer, hideflags) + if(viewer == src) + return get_self_pronouns() + return get_visible_pronouns(hideflags) + +/mob/proc/get_equipment_visibility() + . = 0 + for(var/obj/item/thing in get_equipped_items(include_carried = FALSE)) + . |= thing.flags_inv + return . & EQUIPMENT_VISIBILITY_FLAGS + +/mob/proc/get_examined_worn_held_items(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = list() + var/slot_datums = get_inventory_slots() + if(length(slot_datums)) + for(var/slot in slot_datums) + var/datum/inventory_slot/inv_slot = slot_datums[slot] + if(!inv_slot || inv_slot.skip_on_inventory_display) + continue + var/slot_desc = inv_slot.get_examined_string(src, user, distance, hideflags, pronouns) + if(slot_desc) + . += slot_desc + if(buckled) + // pronouns can be second-person here if user == src so no need to handle that explicitly + . += SPAN_WARNING("[pronouns.He] [pronouns.is] [html_icon(buckled)] buckled to [buckled]!") + +/mob/proc/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + return list() + +// We add a default parameter here for hidden inventory flags. +/mob/get_examine_header(mob/user, distance, infix, suffix, hideflags) + return ..(user, distance, infix, suffix) + +/mob/get_examine_strings(mob/user, distance, infix, suffix) + + SHOULD_CALL_PARENT(FALSE) + . = list() + + if(desc) + . += desc + + // Collect equipment visibility flags. + var/hideflags = get_equipment_visibility() + //no accuately spotting headsets from across the room. + if(distance > 3) + hideflags |= HIDEEARS + + // Show our equipment, held items, desc, etc. + var/decl/pronouns/pronouns = get_visible_pronouns_for_viewer(user, hideflags) // handles second-person if src == user + var/list/examine_items = get_examined_worn_held_items(user, distance, infix, suffix, hideflags, pronouns) + if(length(examine_items)) + . += examine_items + var/list/other_items = get_other_examine_strings(user, distance, infix, suffix, hideflags, pronouns) + if(length(other_items)) + . += other_items diff --git a/code/modules/mob/floating_message.dm b/code/modules/mob/floating_message.dm index 12fe2f61a797..a6cc4a3bb3f7 100644 --- a/code/modules/mob/floating_message.dm +++ b/code/modules/mob/floating_message.dm @@ -1,63 +1,94 @@ // Thanks to Burger from Burgerstation for the foundation for this -var/list/floating_chat_colors = list() +var/global/list/floating_chat_colors = list() + +/// How long the chat message's spawn-in animation will occur for +#define CHAT_MESSAGE_SPAWN_TIME 0.2 SECONDS +/// How long the chat message will exist prior to any exponential decay +#define CHAT_MESSAGE_LIFESPAN 5 SECONDS +/// How long the chat message's end of life fading animation will occur for +#define CHAT_MESSAGE_EOL_FADE 0.7 SECONDS +/// Max width of chat message in pixels +#define CHAT_MESSAGE_WIDTH 128 +/// Max width of chat message in pixels +#define CHAT_MESSAGE_HEIGHT 64 /atom/movable var/list/stored_chat_text -/atom/movable/proc/animate_chat(message, decl/language/language, small, list/show_to, duration) +/atom/movable/proc/animate_chat(message, decl/language/language, small, list/show_to, duration = CHAT_MESSAGE_LIFESPAN) set waitfor = FALSE - - var/style //additional style params for the message - var/fontsize = 6 + + /// Get rid of any URL schemes that might cause BYOND to automatically wrap something in an anchor tag + var/static/regex/url_scheme = new(@"[A-Za-z][A-Za-z0-9+-\.]*:\/\/", "g") + message = replacetext(message, url_scheme, "") + + var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g") + message = replacetext(message, html_metachars, "") + + //additional style params for the message + var/style + var/fontsize = 7 + var/limit = 120 + if(small) - fontsize = 5 - var/limit = 50 - if(copytext(message, length(message) - 1) == "!!") + fontsize = 6 + + if(copytext_char(message, length_char(message) - 1) == "!!") fontsize = 8 - limit = 30 + limit = 60 style += "font-weight: bold;" - if(length(message) > limit) - message = "[copytext(message, 1, limit)]..." + if(length_char(message) > limit) + message = "[copytext_char(message, 1, limit)]..." - if(!floating_chat_colors[name]) - floating_chat_colors[name] = get_random_colour(0,160,230) - style += "color: [floating_chat_colors[name]];" + if(!global.floating_chat_colors[name]) + global.floating_chat_colors[name] = get_random_colour(0, 160, 230) + style += "color: [global.floating_chat_colors[name]];" // create 2 messages, one that appears if you know the language, and one that appears when you don't know the language var/image/understood = generate_floating_text(src, capitalize(message), style, fontsize, duration, show_to) - var/image/gibberish = language ? generate_floating_text(src, language.scramble(message), style, fontsize, duration, show_to) : understood + var/image/gibberish = language ? generate_floating_text(src, language.scramble(src, message), style, fontsize, duration, show_to) : understood for(var/client/C in show_to) - if(!C.mob.is_deaf() && C.get_preference_value(/datum/client_preference/floating_messages) == GLOB.PREF_SHOW) - if(C.mob.say_understands(null, language)) + if(!C.mob.is_deaf() && C.get_preference_value(/datum/client_preference/floating_messages) == PREF_SHOW) + if(C.mob.say_understands(src, language)) C.images += understood else C.images += gibberish -/proc/generate_floating_text(atom/movable/holder, message, style, size, duration, show_to) - var/image/I = image(null, holder) - I.layer=FLY_LAYER +/proc/generate_floating_text(atom/movable/holder, message, style, size, duration, show_to) + var/image/I = image(null, get_atom_on_turf(holder)) + I.plane = HUD_PLANE + I.layer = HUD_ABOVE_ITEM_LAYER I.alpha = 0 - I.maptext_width = 80 - I.maptext_height = 64 - I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - I.pixel_x = -round(I.maptext_width/2) + 16 + I.maptext_width = CHAT_MESSAGE_WIDTH + I.maptext_height = CHAT_MESSAGE_HEIGHT + I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART + I.pixel_w = -round(I.maptext_width/2) + 16 + holder.get_overhead_text_x_offset() + I.pixel_z = holder.get_overhead_text_y_offset() - style = "font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: [size]px; [style]" + style = "font-family: 'Small Fonts'; -dm-text-outline: 1px black; font-size: [size]px; line-height: 1.1; [style]" I.maptext = "
          [message]
          " - animate(I, 1, alpha = 255, pixel_y = 16) - + animate(I, CHAT_MESSAGE_SPAWN_TIME, alpha = 255, pixel_z = 16) + + var/move_up_z = 10 for(var/image/old in holder.stored_chat_text) - animate(old, 2, pixel_y = old.pixel_y + 8) + var/pixel_z_new = old.pixel_z + move_up_z + animate(old, CHAT_MESSAGE_SPAWN_TIME, pixel_z = pixel_z_new) + LAZYADD(holder.stored_chat_text, I) - - addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_floating_text, holder, I), duration) - addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_images_from_clients, I, show_to), duration + 2) + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_floating_text), holder, I), duration) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_images_from_clients), I, show_to), duration + CHAT_MESSAGE_EOL_FADE) return I /proc/remove_floating_text(atom/movable/holder, image/I) - animate(I, 2, pixel_y = I.pixel_y + 10, alpha = 0) - LAZYREMOVE(holder.stored_chat_text, I) \ No newline at end of file + animate(I, CHAT_MESSAGE_EOL_FADE, pixel_z = I.pixel_z + 12, alpha = 0, flags = ANIMATION_PARALLEL) + LAZYREMOVE(holder.stored_chat_text, I) + +#undef CHAT_MESSAGE_SPAWN_TIME +#undef CHAT_MESSAGE_LIFESPAN +#undef CHAT_MESSAGE_EOL_FADE +#undef CHAT_MESSAGE_WIDTH +#undef CHAT_MESSAGE_HEIGHT diff --git a/code/modules/mob/gender.dm b/code/modules/mob/gender.dm deleted file mode 100644 index c2eb65c68bc6..000000000000 --- a/code/modules/mob/gender.dm +++ /dev/null @@ -1,68 +0,0 @@ - -/var/list/gender_datums = list() - -/hook/startup/proc/populate_gender_datum_list() - for(var/type in subtypesof(/datum/gender)) - var/datum/gender/G = new type - gender_datums[G.key] = G - if(!G.formal_term) - G.formal_term = G.key - return 1 - -/datum/gender - var/key - var/formal_term - - var/He = "They" - var/he = "they" - var/His = "Their" - var/his = "their" - var/him = "them" - var/has = "have" - var/is = "are" - var/does = "do" - var/self = "themselves" - -/datum/gender/plural - key = PLURAL - formal_term = "other" - -/datum/gender/male - key = MALE - - He = "He" - he = "he" - His = "His" - his = "his" - him = "him" - has = "has" - is = "is" - does = "does" - self = "himself" - -/datum/gender/female - key = FEMALE - - He = "She" - he = "she" - His = "Her" - his = "her" - him = "her" - has = "has" - is = "is" - does = "does" - self = "herself" - -/datum/gender/neuter - key = NEUTER - formal_term = "other" - - He = "It" - he = "it" - His = "Its" - his = "its" - him = "it" - has = "has" - is = "is" - does = "does" - self = "itself" diff --git a/code/modules/mob/grab/grab_datum.dm b/code/modules/mob/grab/grab_datum.dm index 15aab2ef2b1f..2783cfb571f9 100644 --- a/code/modules/mob/grab/grab_datum.dm +++ b/code/modules/mob/grab/grab_datum.dm @@ -1,243 +1,256 @@ /decl/grab - - var/name = "generic grab" - var/fancy_desc - var/decl/grab/upgrab // The grab that this will upgrade to if it upgrades, null means no upgrade - var/decl/grab/downgrab // The grab that this will downgrade to if it downgrades, null means break grab on downgrade - var/stop_move = 0 // Whether or not the grabbed person can move out of the grab - var/reverse_facing = 0 // Whether the person being grabbed is facing forwards or backwards. - var/can_absorb = 0 // Whether this grab state is strong enough to, as a changeling, absorb the person you're grabbing. - var/shield_assailant = 0 // Whether the person you're grabbing will shield you from bullets.,, - var/point_blank_mult = 1 // How much the grab increases point blank damage. - var/damage_stage = 1 // Affects how much damage is being dealt using certain actions. - var/same_tile = 0 // If the grabbed person and the grabbing person are on the same tile. - var/can_throw = 0 // If the grabber can throw the person grabbed. - var/downgrade_on_action = 0 // If the grab needs to be downgraded when the grabber does stuff. - var/downgrade_on_move = 0 // If the grab needs to be downgraded when the grabber moves. - var/force_danger = 0 // If the grab is strong enough to be able to force someone to do something harmful to them. - var/restrains = 0 // If the grab acts like cuffs and prevents action from the victim. - var/grab_slowdown = 7 - var/shift = 0 - var/success_up = "You get a better grip on rep_affecting." - var/success_down = "You adjust your grip on rep_affecting." - var/fail_up = "You can't get a better grip on rep_affecting!" - var/fail_down = "You can't seem to shift your grip on rep_affecting!" - var/icon - var/icon_state - var/upgrade_cooldown = 40 - var/action_cooldown = 40 + var/name = "generic grab" + /// Whether or not the grabbed person can move out of the grab + var/stop_move = 0 + /// Whether the person being grabbed is facing forwards or backwards. + var/reverse_facing = 0 + /// Whether the person you're grabbing will shield you from bullets.,, + var/shield_assailant = 0 + /// How much the grab increases point blank damage. + var/point_blank_mult = 1 + /// Affects how much damage is being dealt using certain actions. + var/damage_stage = 1 + /// If the grabbed person and the grabbing person are on the same tile. + var/same_tile = 0 + /// If the grabber can throw the person grabbed. + var/can_throw = 0 + /// If the grab needs to be downgraded when the grabber does stuff. + var/downgrade_on_action = 0 + /// If the grab needs to be downgraded when the grabber moves. + var/downgrade_on_move = 0 + /// If the grab is strong enough to be able to force someone to do something harmful to them. + var/force_danger = 0 + /// If the grab acts like cuffs and prevents action from the victim. + var/restrains = 0 + /// Multiplier for the object size (w_class or mob_size) of the grabbed atom, applied as slowdown. + var/grab_slowdown = 0.15 + /// Whether or not this grab causes atoms to adjust their pixel offsets according to grabber dir. + var/shift = 0 + /// Whether or not this grab causes atoms to adjust their plane/layer according to grabber dir. + var/adjust_plane = TRUE + // This grab will adjust the victim's layering. + var/adjust_layer = TRUE + + var/success_up = "You get a better grip on $rep_affecting$." + var/success_down = "You adjust your grip on $rep_affecting$." + var/fail_up = "You can't get a better grip on $rep_affecting$!" + var/fail_down = "You can't seem to relax your grip on $rep_affecting$!" + var/grab_icon = 'icons/mob/screen/grabs.dmi' + var/grab_icon_state = "reinforce" + var/upgrade_cooldown = 40 + var/action_cooldown = 40 var/can_downgrade_on_resist = 1 var/list/break_chance_table = list(100) - var/breakability = 2 + var/breakability = 2 + /// The names of different intents for use in attack logs + var/help_action = "help intent" + var/disarm_action = "disarm intent" + var/grab_action = "grab intent" + var/harm_action = "harm intent" + /// The grab that this will upgrade to if it upgrades, null means no upgrade + var/decl/grab/upgrab + /// The grab that this will downgrade to if it downgrades, null means break grab on downgrade + var/decl/grab/downgrab - // The names of different intents for use in attack logs - var/help_action = "help intent" - var/disarm_action = "disarm intent" - var/grab_action = "grab intent" - var/harm_action = "harm intent" /decl/grab/Initialize() if(ispath(upgrab, /decl/grab)) - upgrab = decls_repository.get_decl(upgrab) + upgrab = GET_DECL(upgrab) if(ispath(downgrab, /decl/grab)) - downgrab = decls_repository.get_decl(downgrab) + downgrab = GET_DECL(downgrab) . = ..() -/decl/grab/proc/string_process(var/obj/item/grab/G, var/to_write, var/obj/item/used_item) - to_write = replacetext(to_write, "rep_affecting", G.affecting) - to_write = replacetext(to_write, "rep_assailant", G.assailant) +/decl/grab/proc/string_process(var/obj/item/grab/grab, var/to_write, var/obj/item/used_item) + to_write = replacetext(to_write, "$rep_affecting$", grab.affecting) + to_write = replacetext(to_write, "$rep_assailant$", grab.assailant) if(used_item) - to_write = replacetext(to_write, "rep_item", used_item) + to_write = replacetext(to_write, "$rep_item$", used_item) return to_write -/decl/grab/proc/upgrade(var/obj/item/grab/G) - if(!upgrab) - return - - if(can_upgrade(G)) - upgrade_effect(G) - admin_attack_log(G.assailant, G.affecting, "upgraded grab on their victim to [upgrab]", "was grabbed more tightly to [upgrab]", "upgraded grab to [upgrab] on") +/decl/grab/proc/upgrade(var/obj/item/grab/grab) + if(can_upgrade(grab) && upgrade_effect(grab)) + to_chat(grab.assailant, SPAN_WARNING("[string_process(grab, success_up)]")) return upgrab - else - to_chat(G.assailant, "[string_process(G, fail_up)]") - return + to_chat(grab.assailant, SPAN_WARNING("[string_process(grab, fail_up)]")) -/decl/grab/proc/downgrade(var/obj/item/grab/G) - // Starts the process of letting go if there's no downgrade grab - if(can_downgrade()) - downgrade_effect(G) - return downgrab - else - to_chat(G.assailant, "[string_process(G, fail_down)]") +/decl/grab/proc/downgrade(var/obj/item/grab/grab) + // If we have no downgrab at all, assume we just drop the grab. + if(!downgrab) + let_go(grab) return - -/decl/grab/proc/let_go(var/obj/item/grab/G) - let_go_effect(G) - G.force_drop() - -/decl/grab/proc/on_target_change(var/obj/item/grab/G, old_zone, new_zone) - G.special_target_functional = check_special_target(G) - if(G.special_target_functional) - special_target_change(G, old_zone, new_zone) - special_target_effect(G) - -/decl/grab/proc/process(var/obj/item/grab/G) - special_target_effect(G) - process_effect(G) - -/decl/grab/proc/throw_held(var/obj/item/grab/G) - if(G.assailant == G.affecting) + if(can_downgrade(grab) && downgrade_effect(grab)) + to_chat(grab.assailant, SPAN_NOTICE("[string_process(grab, success_down)]")) + return downgrab + to_chat(grab.assailant, SPAN_WARNING("[string_process(grab, fail_down)]")) + +/decl/grab/proc/let_go(var/obj/item/grab/grab) + if(grab.assailant && grab.affecting) + to_chat(grab.assailant, SPAN_NOTICE("You release \the [grab.affecting].")) + let_go_effect(grab) + grab.force_drop() + +/decl/grab/proc/on_target_change(var/obj/item/grab/grab, old_zone, new_zone) + grab.special_target_functional = check_special_target(grab) + if(grab.special_target_functional) + special_target_change(grab, old_zone, new_zone) + special_target_effect(grab) + +/decl/grab/proc/process(var/obj/item/grab/grab) + special_target_effect(grab) + process_effect(grab) + +/decl/grab/proc/throw_held(var/obj/item/grab/grab) + if(grab.assailant == grab.affecting) return if(can_throw) - . = G.affecting - var/mob/thrower = G.loc - if(ismob(G.affecting)) - animate(G.affecting, pixel_x = initial(G.affecting.pixel_x), pixel_y = initial(G.affecting.pixel_y), 4, 1) - qdel(G) + . = grab.affecting + var/mob/thrower = grab.loc + qdel(grab) // check if we're grabbing with our inactive hand - G = thrower.get_inactive_hand() - if(istype(G)) - qdel(G) - -/decl/grab/proc/hit_with_grab(var/obj/item/grab/G) - if(downgrade_on_action) - G.downgrade() - - if(G.check_action_cooldown() && !G.attacking) - var/intent = G.assailant.a_intent - switch(intent) - - if(I_HELP) - if(on_hit_help(G)) - G.action_used() - make_log(G, help_action) - - if(I_DISARM) - if(on_hit_disarm(G)) - G.action_used() - make_log(G, disarm_action) - - if(I_GRAB) - if(on_hit_grab(G)) - G.action_used() - make_log(G, grab_action) - - if(I_HURT) - if(on_hit_harm(G)) - G.action_used() - make_log(G, harm_action) - - else - to_chat(G.assailant, "You must wait before you can do that.") - -/decl/grab/proc/make_log(var/obj/item/grab/G, var/action) - admin_attack_log(G.assailant, G.affecting, "[action]s their victim", "was [action]ed", "used [action] on") + for(var/obj/item/grab/inactive_grab as anything in thrower.get_inactive_held_items()) + qdel(inactive_grab) + +/decl/grab/proc/hit_with_grab(var/obj/item/grab/grab, var/atom/A, var/P = TRUE) + + if(QDELETED(grab) || !istype(grab)) + return FALSE + + if(!grab.check_action_cooldown() || grab.is_currently_resolving_hit) + to_chat(grab.assailant, SPAN_WARNING("You must wait before you can do that.")) + return FALSE + + grab.is_currently_resolving_hit = TRUE + + var/intent_flags = grab.assailant.get_intent().intent_flags + if((intent_flags & I_FLAG_HELP) && on_hit_help(grab, A, P)) + . = help_action || TRUE + if(!. && (intent_flags & I_FLAG_DISARM) && on_hit_disarm(grab, A, P)) + . = disarm_action || TRUE + if(!. && (intent_flags & I_FLAG_GRAB) && on_hit_grab(grab, A, P)) + . = grab_action || TRUE + if(!. && (intent_flags & I_FLAG_HARM) && on_hit_harm(grab, A, P)) + . = harm_action || TRUE + + if(!QDELETED(grab)) + grab.is_currently_resolving_hit = FALSE + if(.) + grab.action_used() + if(grab.assailant) + grab.assailant.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(istext(.) && grab.affecting) + admin_attack_log(grab.assailant, grab.affecting, "[.]s their victim", "was [.]ed", "used [.] on") + if(downgrade_on_action) + grab.downgrade() // This is called whenever the assailant moves. -/decl/grab/proc/assailant_moved(var/obj/item/grab/G) - G.adjust_position() - moved_effect(G) +/decl/grab/proc/assailant_moved(var/obj/item/grab/grab) + grab.adjust_position() + moved_effect(grab) if(downgrade_on_move) - G.downgrade() + grab.downgrade() /* Override these procs to set how the grab state will work. Some of them are best - overriden in the parent of the grab set (for example, the behaviour for on_hit_intent(var/obj/item/grab/G) + overriden in the parent of the grab set (for example, the behaviour for on_hit_intent() procs is determined in /decl/grab/normal and then inherited by each intent). */ // What happens when you upgrade from one grab state to the next. -/decl/grab/proc/upgrade_effect(var/obj/item/grab/G) +/decl/grab/proc/upgrade_effect(var/obj/item/grab/grab) + admin_attack_log(grab.assailant, grab.affecting, "upgraded grab on their victim to [upgrab]", "was grabbed more tightly to [upgrab]", "upgraded grab to [upgrab] on") + return TRUE // Conditions to see if upgrading is possible // Only works on mobs. -/decl/grab/proc/can_upgrade(var/obj/item/grab/G) - return !!G.get_affecting_mob() +/decl/grab/proc/can_upgrade(var/obj/item/grab/grab) + return !!upgrab && !!grab.get_affecting_mob() // What happens when you downgrade from one grab state to the next. -/decl/grab/proc/downgrade_effect(var/obj/item/grab/G) +/decl/grab/proc/downgrade_effect(var/obj/item/grab/grab) + return TRUE // Conditions to see if downgrading is possible -/decl/grab/proc/can_downgrade(var/obj/item/grab/G) - return 1 +/decl/grab/proc/can_downgrade(var/obj/item/grab/grab) + return !!downgrab // What happens when you let go of someone by either dropping the grab // or by downgrading from the lowest grab state. -/decl/grab/proc/let_go_effect(var/obj/item/grab/G) +/decl/grab/proc/let_go_effect(var/obj/item/grab/grab) // What happens each tic when process is called. -/decl/grab/proc/process_effect(var/obj/item/grab/G) +/decl/grab/proc/process_effect(var/obj/item/grab/grab) // Handles special targeting like eyes and mouth being covered. -/decl/grab/proc/special_target_effect(var/obj/item/grab/G) +/decl/grab/proc/special_target_effect(var/obj/item/grab/grab) // Handles when they change targeted areas and something is supposed to happen. -/decl/grab/proc/special_target_change(var/obj/item/grab/G, var/diff_zone) +/decl/grab/proc/special_target_change(var/obj/item/grab/grab, var/diff_zone) // Checks if the special target works on the grabbed humanoid. -/decl/grab/proc/check_special_target(var/obj/item/grab/G) +/decl/grab/proc/check_special_target(var/obj/item/grab/grab) -// What happens when you hit the grabbed person with the grab on help intent. -/decl/grab/proc/on_hit_help(var/obj/item/grab/G) - return 1 +// What happens when you a target with the grab on help intent. +/decl/grab/proc/on_hit_help(var/obj/item/grab/grab, var/atom/A, var/proximity) + return TRUE -// What happens when you hit the grabbed person with the grab on disarm intent. -/decl/grab/proc/on_hit_disarm(var/obj/item/grab/G) - return 1 +// What happens when you a target with the grab on disarm intent. +/decl/grab/proc/on_hit_disarm(var/obj/item/grab/grab, var/atom/A, var/proximity) + return TRUE -// What happens when you hit the grabbed person with the grab on grab intent. -/decl/grab/proc/on_hit_grab(var/obj/item/grab/G) - return 1 +// What happens when you a target with the grab on grab intent. +/decl/grab/proc/on_hit_grab(var/obj/item/grab/grab, var/atom/A, var/proximity) + return TRUE -// What happens when you hit the grabbed person with the grab on harm intent. -/decl/grab/proc/on_hit_harm(var/obj/item/grab/G) - return 1 +// What happens when you a target with the grab on harm intent. +/decl/grab/proc/on_hit_harm(var/obj/item/grab/grab, var/atom/A, var/proximity) + return TRUE -// What happens when you hit the grabbed person with an open hand and you want it +// What happens when you hit a target with an open hand and you want it // to do some special snowflake action based on some other factor such as // intent. -/decl/grab/proc/resolve_openhand_attack(var/obj/item/grab/G) +/decl/grab/proc/resolve_openhand_attack(var/obj/item/grab/grab) return 0 // Used when you want an effect to happen when the grab enters this state as an upgrade -/decl/grab/proc/enter_as_up(var/obj/item/grab/G) +/decl/grab/proc/enter_as_up(var/obj/item/grab/grab) -/decl/grab/proc/item_attack(var/obj/item/grab/G, var/obj/item) +/decl/grab/proc/item_attack(var/obj/item/grab/grab, var/obj/item) + return FALSE -/decl/grab/proc/resolve_item_attack(var/obj/item/grab/G, var/mob/living/carbon/human/user, var/obj/item/I, var/target_zone) - return 0 +/decl/grab/proc/resolve_item_attack(var/obj/item/grab/grab, var/mob/living/human/user, var/obj/item/I, var/target_zone) + return FALSE -/decl/grab/proc/handle_resist(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() - var/mob/living/assailant = G.assailant +/decl/grab/proc/handle_resist(var/obj/item/grab/grab) + var/mob/living/affecting = grab.get_affecting_mob() + var/mob/living/assailant = grab.assailant if(!affecting) return if(affecting.incapacitated(INCAPACITATION_KNOCKOUT | INCAPACITATION_STUNNED)) - to_chat(G.affecting, "You can't resist in your current state!") - var/skill_mod = Clamp(affecting.get_skill_difference(SKILL_COMBAT, assailant), -1, 1) + to_chat(grab.affecting, SPAN_WARNING("You can't resist in your current state!")) + var/skill_mod = clamp(affecting.get_skill_difference(SKILL_COMBAT, assailant), -1, 1) var/break_strength = breakability + size_difference(affecting, assailant) + skill_mod if(affecting.incapacitated(INCAPACITATION_ALL)) break_strength-- - if(affecting.confused) + if(HAS_STATUS(affecting, STAT_CONFUSE)) break_strength-- if(break_strength < 1) - to_chat(G.affecting, "You try to break free but feel that unless something changes, you'll never escape!") + to_chat(grab.affecting, SPAN_WARNING("You try to break free but feel that unless something changes, you'll never escape!")) return - var/break_chance = break_chance_table[Clamp(break_strength, 1, break_chance_table.len)] + var/break_chance = break_chance_table[clamp(break_strength, 1, break_chance_table.len)] if(prob(break_chance)) if(can_downgrade_on_resist && !prob((break_chance+100)/2)) - affecting.visible_message("[affecting] has loosened [assailant]'s grip!") - G.downgrade() + affecting.visible_message(SPAN_WARNING("\The [affecting] has loosened \the [assailant]'s grip!")) + grab.downgrade() return else - affecting.visible_message("[affecting] has broken free of [assailant]'s grip!") - let_go(G) + affecting.visible_message(SPAN_WARNING("\The [affecting] has broken free of \the [assailant]'s grip!")) + let_go(grab) /decl/grab/proc/size_difference(mob/A, mob/B) return mob_size_difference(A.mob_size, B.mob_size) -/decl/grab/proc/moved_effect(var/obj/item/grab/G) +/decl/grab/proc/moved_effect(var/obj/item/grab/grab) return \ No newline at end of file diff --git a/code/modules/mob/grab/grab_object.dm b/code/modules/mob/grab/grab_object.dm index 98f5fa0b0f49..c4a5015aa4d5 100644 --- a/code/modules/mob/grab/grab_object.dm +++ b/code/modules/mob/grab/grab_object.dm @@ -1,104 +1,129 @@ /obj/item/grab - name = "grab" - canremove = 0 - item_flags = ITEM_FLAG_NO_BLUDGEON - w_class = ITEM_SIZE_NO_CONTAINER - - var/atom/movable/affecting = null - var/mob/assailant = null - var/decl/grab/current_grab - var/last_action - var/last_upgrade - var/special_target_functional = 1 - var/attacking = 0 - var/target_zone - var/done_struggle = FALSE // Used by struggle grab datum to keep track of state. + name = "grab" + canremove = FALSE + item_flags = ITEM_FLAG_NO_BLUDGEON + pickup_sound = null + drop_sound = null + equip_sound = null + is_spawnable_type = FALSE + obj_flags = OBJ_FLAG_NO_STORAGE + needs_attack_dexterity = DEXTERITY_GRAPPLE + + var/atom/movable/affecting // Atom being targeted by this grab. + var/mob/assailant // Mob that instantiated this grab. + var/decl/grab/current_grab // Current grab archetype, used to handle actions/overrides/etc. + var/last_action // Tracks world.time of last action. + var/last_upgrade // Tracks world.time of last upgrade. + var/special_target_functional = TRUE // Indicates if the current grab has special interactions applied to the target organ (eyes and mouth at time of writing) + var/is_currently_resolving_hit = FALSE // Used to avoid stacking interactions that sleep during /decl/grab/proc/on_hit_foo() (ie. do_after() is used) + var/target_zone // Records a specific bodypart that was targetted by this grab. + var/done_struggle = FALSE // Used by struggle grab datum to keep track of state. /* This section is for overrides of existing procs. */ -/obj/item/grab/Initialize(mapload, atom/movable/target, var/use_grab_state) +/obj/item/grab/Initialize(mapload, atom/movable/target, var/use_grab_state, var/defer_hand) . = ..(mapload) if(. == INITIALIZE_HINT_QDEL) return - current_grab = decls_repository.get_decl(use_grab_state) + current_grab = GET_DECL(use_grab_state) if(!istype(current_grab)) return INITIALIZE_HINT_QDEL assailant = loc - if(!istype(assailant) || !assailant.add_grab(src)) + if(!istype(assailant) || !assailant.add_grab(src, defer_hand = defer_hand)) return INITIALIZE_HINT_QDEL affecting = target if(!istype(affecting)) return INITIALIZE_HINT_QDEL - target_zone = assailant.zone_sel?.selecting + target_zone = assailant.get_target_zone() - var/mob/affecting_mob = get_affecting_mob() + var/mob/living/affecting_mob = get_affecting_mob() if(affecting_mob) - affecting_mob.UpdateLyingBuckledAndVerbStatus() + affecting_mob.update_posture() if(ishuman(affecting_mob)) - var/mob/living/carbon/human/H = affecting_mob - if(H.w_uniform) - H.w_uniform.add_fingerprint(assailant) + var/mob/living/human/H = affecting_mob + var/obj/item/uniform = H.get_equipped_item(slot_w_uniform_str) + if(uniform) + uniform.add_fingerprint(assailant) LAZYADD(affecting.grabbed_by, src) // This is how we handle affecting being deleted. adjust_position() action_used() - assailant.do_attack_animation(affecting) + INVOKE_ASYNC(assailant, TYPE_PROC_REF(/atom/movable, do_attack_animation), affecting) playsound(affecting.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) update_icon() - GLOB.moved_event.register(affecting, src, .proc/on_affecting_move) - if(assailant.zone_sel) - GLOB.zone_selected_event.register(assailant.zone_sel, src, .proc/on_target_change) - var/obj/item/organ/O = get_targeted_organ() + events_repository.register(/decl/observ/moved, affecting, src, PROC_REF(on_affecting_move)) + var/obj/screen/zone_selector/zone_selector = assailant.get_hud_element(HUD_ZONE_SELECT) + if(zone_selector) + events_repository.register(/decl/observ/zone_selected, zone_selector, src, PROC_REF(on_target_change)) - var/datum/gender/T = gender_datums[assailant.get_gender()] - if(O) - SetName("[name] ([O.name])") - GLOB.dismembered_event.register(affecting, src, .proc/on_organ_loss) - if(affecting != assailant) - visible_message(SPAN_DANGER("\The [assailant] has grabbed [affecting]'s [O.name]!")) + var/obj/item/organ/O = get_targeted_organ() + var/decl/pronouns/pronouns = assailant.get_pronouns() + if(affecting_mob && O) // may have grabbed a buckled mob, so may be grabbing their holder + SetName("[name] (\the [affecting_mob]'s [O.name])") + events_repository.register(/decl/observ/dismembered, affecting_mob, src, PROC_REF(on_organ_loss)) + if(affecting_mob != assailant) + visible_message(SPAN_DANGER("\The [assailant] has grabbed [affecting_mob]'s [O.name]!")) else - visible_message(SPAN_NOTICE("\The [assailant] has grabbed [T.his] [O.name]!")) + visible_message(SPAN_NOTICE("\The [assailant] has grabbed [pronouns.his] [O.name]!")) else if(affecting != assailant) visible_message(SPAN_DANGER("\The [assailant] has grabbed \the [affecting]!")) else - visible_message(SPAN_NOTICE("\The [assailant] has grabbed [T.self]!")) + visible_message(SPAN_NOTICE("\The [assailant] has grabbed [pronouns.self]!")) - if(affecting_mob && affecting_mob.a_intent != I_HELP) + if(affecting_mob && assailant?.check_intent(I_FLAG_HARM)) upgrade(TRUE) -/obj/item/grab/examine(mob/user) +/obj/item/grab/ShouldSerialize(_age) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/obj/item/grab/mob_can_unequip(mob/user, slot, disable_warning = FALSE, dropping = FALSE) + if(dropping) + return TRUE + return FALSE + +/obj/item/grab/get_examine_strings(mob/user, distance, infix, suffix) . = ..() + var/mob/M = get_affecting_mob() var/obj/item/O = get_targeted_organ() - if(O) - to_chat(user, "A grip on \the [affecting]'s [O.name].") + if(M && O) + . += "A grip on \the [M]'s [O.name]." else - to_chat(user, "A grip on \the [affecting].") + . += "A grip on \the [affecting]." /obj/item/grab/Process() current_grab.process(src) /obj/item/grab/attack_self(mob/user) - switch(assailant.a_intent) - if(I_HELP) - downgrade() - else - upgrade() + if(assailant.check_intent(I_FLAG_HELP)) + downgrade() + else + upgrade() + +/obj/item/grab/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(affecting == target) + var/datum/extension/abilities/abilities = get_extension(user, /datum/extension/abilities) + if(abilities?.do_grabbed_invocation(target)) + return TRUE + . = ..() -/obj/item/grab/attack(mob/M, mob/living/user) - current_grab.hit_with_grab(src) +/obj/item/grab/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(QDELETED(src) || !current_grab || !assailant || proximity_flag) // Close-range is handled in resolve_attackby(). + return + if(current_grab.hit_with_grab(src, target, proximity_flag)) + return + . = ..() /obj/item/grab/resolve_attackby(atom/A, mob/user, var/click_params) - assailant.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!A.grab_attack(src)) - return ..() - action_used() - if (current_grab.downgrade_on_action) - downgrade() - return TRUE + if(QDELETED(src) || !current_grab || !assailant) + return TRUE + if(A.grab_attack(src, user) || current_grab.hit_with_grab(src, A, get_dist(user, A) <= 1)) + return TRUE + . = ..() /obj/item/grab/dropped() ..() @@ -108,40 +133,45 @@ /obj/item/grab/can_be_dropped_by_client(mob/M) if(M == assailant) return TRUE + return FALSE /obj/item/grab/Destroy() + var/atom/old_affecting = affecting if(affecting) - GLOB.dismembered_event.unregister(affecting, src) - GLOB.moved_event.unregister(affecting, src) - reset_position() + events_repository.unregister(/decl/observ/dismembered, affecting, src) + events_repository.unregister(/decl/observ/moved, affecting, src) LAZYREMOVE(affecting.grabbed_by, src) affecting.reset_plane_and_layer() affecting = null if(assailant) - if(assailant.zone_sel) - GLOB.zone_selected_event.unregister(assailant.zone_sel, src) + var/obj/screen/zone_selector/zone_selector = assailant.get_hud_element(HUD_ZONE_SELECT) + if(zone_selector) + events_repository.unregister(/decl/observ/zone_selected, zone_selector, src) assailant = null - return ..() + . = ..() + if(old_affecting) + old_affecting.reset_offsets(5) + old_affecting.reset_plane_and_layer() /* This section is for newly defined useful procs. */ -/obj/item/grab/proc/on_target_change(obj/screen/zone_sel/zone, old_sel, new_sel) - if(src != assailant.get_active_hand()) +/obj/item/grab/proc/on_target_change(obj/screen/zone_selector/zone, old_sel, new_sel) + if(src != assailant.get_active_held_item()) return // Note that because of this condition, there's no guarantee that target_zone = old_sel if(target_zone == new_sel) return var/old_zone = target_zone - target_zone = new_sel + target_zone = check_zone(new_sel, affecting) if(!istype(get_targeted_organ(), /obj/item/organ)) current_grab.let_go(src) return - current_grab.on_target_change(src, old_zone, target_zone) + current_grab.on_target_change(src, old_zone, new_sel) /obj/item/grab/proc/on_organ_loss(mob/victim, obj/item/organ/lost) if(affecting != victim) - crash_with("A grab switched affecting targets without properly re-registering for dismemberment updates.") + PRINT_STACK_TRACE("A grab switched affecting targets without properly re-registering for dismemberment updates.") return var/obj/item/organ/O = get_targeted_organ() if(!istype(O)) @@ -152,21 +182,24 @@ current_grab.let_go(src) /obj/item/grab/proc/on_affecting_move() - if(!affecting || !isturf(affecting.loc) || get_dist(affecting, assailant) > 1) + if(!affecting || !isturf(affecting.loc) || (get_dist_3d(affecting, assailant) > 1 && affecting.moving_diagonally != /atom/movable::FIRST_DIAGONAL_STEP)) force_drop() /obj/item/grab/proc/force_drop() assailant.drop_from_inventory(src) /obj/item/grab/proc/get_affecting_mob() - . = ismob(affecting) && affecting + if(isobj(affecting)) + var/obj/O = affecting + return O.buckled_mob + if(isliving(affecting)) + return affecting // Returns the organ of the grabbed person that the grabber is targeting /obj/item/grab/proc/get_targeted_organ() - if(ishuman(affecting)) - var/mob/living/carbon/human/affecting_mob = affecting - . = affecting_mob.get_organ(target_zone) - + var/mob/affecting_mob = get_affecting_mob() + if(istype(affecting_mob)) + . = GET_EXTERNAL_ORGAN(affecting_mob, check_zone(target_zone, affecting_mob)) /obj/item/grab/proc/resolve_item_attack(var/mob/living/M, var/obj/item/I, var/target_zone) if(M && ishuman(M) && I) return current_grab.resolve_item_attack(src, M, I, target_zone) @@ -174,8 +207,8 @@ /obj/item/grab/proc/action_used() if(ishuman(assailant)) - var/mob/living/carbon/human/H = assailant - H.remove_cloaking_source(H.species) + var/mob/living/human/H = assailant + H.remove_mob_modifier(/decl/mob_modifier/cloaked, source = H.species) last_action = world.time leave_forensic_traces() @@ -187,7 +220,7 @@ /obj/item/grab/proc/leave_forensic_traces() if(ishuman(affecting)) - var/mob/living/carbon/human/affecting_mob = affecting + var/mob/living/human/affecting_mob = affecting var/obj/item/clothing/C = affecting_mob.get_covering_equipped_item_by_zone(target_zone) if(istype(C)) C.leave_evidence(assailant) @@ -210,13 +243,15 @@ var/decl/grab/downgrab = current_grab.downgrade(src) if(downgrab) current_grab = downgrab + adjust_position() update_icon() /obj/item/grab/on_update_icon() - if(current_grab.icon) - icon = current_grab.icon - if(current_grab.icon_state) - icon_state = current_grab.icon_state + . = ..() + if(current_grab.grab_icon) + icon = current_grab.grab_icon + if(current_grab.grab_icon_state) + icon_state = current_grab.grab_icon_state /obj/item/grab/proc/throw_held() return current_grab.throw_held(src) @@ -225,21 +260,22 @@ current_grab.handle_resist(src) /obj/item/grab/proc/adjust_position(var/force = 0) - if(force) + + if(!QDELETED(assailant) && force) affecting.forceMove(assailant.loc) - if(!assailant || !affecting || !assailant.Adjacent(affecting)) + + if(QDELETED(assailant) || QDELETED(affecting) || !assailant.IsMultiZAdjacent(affecting)) qdel(src) return 0 + var/adir = get_dir(assailant, affecting) if(assailant) assailant.set_dir(adir) if(current_grab.same_tile) affecting.forceMove(get_turf(assailant)) affecting.set_dir(assailant.dir) - affecting.adjust_pixel_offsets_for_grab(src, adir) - -/obj/item/grab/proc/reset_position() - affecting.reset_pixel_offsets_for_grab(src) + affecting.reset_offsets(5) + affecting.reset_plane_and_layer() /* This section is for the simple procs used to return things from current_grab. @@ -247,12 +283,10 @@ /obj/item/grab/proc/stop_move() return current_grab.stop_move -/obj/item/grab/attackby(obj/W, mob/user) +/obj/item/grab/attackby(obj/item/used_item, mob/user) if(user == assailant) - current_grab.item_attack(src, W) - -/obj/item/grab/proc/can_absorb() - return current_grab.can_absorb + return current_grab.item_attack(src, used_item) + return FALSE /obj/item/grab/proc/assailant_reverse_facing() return current_grab.reverse_facing @@ -270,9 +304,12 @@ return current_grab.force_danger /obj/item/grab/proc/grab_slowdown() - return current_grab.grab_slowdown + . = ceil(affecting?.get_object_size() * current_grab.grab_slowdown) + . /= (affecting?.movable_flags & MOVABLE_FLAG_WHEELED) ? 2 : 1 + . = max(.,1) /obj/item/grab/proc/assailant_moved() + affecting.glide_size = assailant.glide_size // Note that this is called _after_ the Move() call resolves, so while it adjusts affecting's move animation, it won't adjust anything else depending on it. current_grab.assailant_moved(src) /obj/item/grab/proc/restrains() diff --git a/code/modules/mob/grab/normal/grab_normal.dm b/code/modules/mob/grab/normal/grab_normal.dm index b06591b359e1..dc9af610c6c9 100644 --- a/code/modules/mob/grab/normal/grab_normal.dm +++ b/code/modules/mob/grab/normal/grab_normal.dm @@ -1,128 +1,133 @@ /decl/grab/normal - name = "grab" - icon = 'icons/mob/screen1.dmi' - help_action = "inspect" - disarm_action = "pin" - grab_action = "jointlock" - harm_action = "dislocate" + name = "grab" + help_action = "inspect" + disarm_action = "pin" + grab_action = "jointlock" + harm_action = "dislocate" var/drop_headbutt = 1 -/decl/grab/normal/on_hit_help(var/obj/item/grab/G) - var/obj/item/organ/external/O = G.get_targeted_organ() - if(O) - return O.inspect(G.assailant) +/decl/grab/normal/on_hit_help(var/obj/item/grab/grab, var/atom/A, var/proximity) -/decl/grab/normal/on_hit_disarm(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() - var/mob/living/assailant = G.assailant - if(!affecting) - return - if(!G.attacking && !affecting.lying) + var/obj/item/organ/external/O = grab.get_targeted_organ() + if(!O || !proximity || (A && A != grab.get_affecting_mob())) + return FALSE + return O.inspect(grab.assailant) + +/decl/grab/normal/on_hit_disarm(var/obj/item/grab/grab, var/atom/A, var/proximity) + + if(!proximity) + return FALSE - affecting.visible_message("[assailant] is trying to pin [affecting] to the ground!") - G.attacking = 1 + var/mob/living/affecting = grab.get_affecting_mob() + var/mob/living/assailant = grab.assailant + if(affecting && A && A == affecting && !affecting.current_posture.prone) + affecting.visible_message(SPAN_DANGER("\The [assailant] is trying to pin \the [affecting] to the ground!")) if(do_mob(assailant, affecting, action_cooldown - 1)) - G.attacking = 0 - G.action_used() - affecting.Weaken(2) - affecting.visible_message("[assailant] pins [affecting] to the ground!") + grab.action_used() + SET_STATUS_MAX(affecting, STAT_WEAK, 2) + affecting.visible_message(SPAN_DANGER("\The [assailant] pins \the [affecting] to the ground!")) + return TRUE + affecting.visible_message(SPAN_WARNING("\The [assailant] fails to pin \the [affecting] to the ground.")) - return 1 - else - affecting.visible_message("[assailant] fails to pin [affecting] to the ground.") - G.attacking = 0 - return 0 - else - return 0 + return FALSE -/decl/grab/normal/on_hit_grab(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() - var/mob/living/assailant = G.assailant - if(!affecting) - return +/decl/grab/normal/on_hit_grab(var/obj/item/grab/grab, var/atom/A, var/proximity) - if(!assailant.skill_check(SKILL_COMBAT, SKILL_ADEPT)) - return + if(!proximity) + return FALSE + + var/mob/living/affecting = grab.get_affecting_mob() + if(!affecting || (A && A != affecting)) + return FALSE + + var/mob/living/assailant = grab.assailant + if(!assailant) + return FALSE - var/obj/item/organ/external/O = G.get_targeted_organ() + var/obj/item/organ/external/O = grab.get_targeted_organ() if(!O) - to_chat(assailant, "[affecting] is missing that body part!") - return 0 + to_chat(assailant, SPAN_WARNING("\The [affecting] is missing that body part!")) + return FALSE - assailant.visible_message("[assailant] begins to [pick("bend", "twist")] [affecting]'s [O.name] into a jointlock!") - G.attacking = 1 + if(!assailant.skill_check(SKILL_COMBAT, SKILL_ADEPT)) + to_chat(assailant, SPAN_WARNING("You clumsily attempt to jointlock \the [affecting]'s [O.name], but fail!")) + return FALSE + assailant.visible_message(SPAN_DANGER("\The [assailant] begins to [pick("bend", "twist")] \the [affecting]'s [O.name] into a jointlock!")) if(do_mob(assailant, affecting, action_cooldown - 1)) - G.attacking = 0 - G.action_used() + grab.action_used() O.jointlock(assailant) - assailant.visible_message("[affecting]'s [O.name] is twisted!") + assailant.visible_message(SPAN_DANGER("\The [affecting]'s [O.name] is twisted!")) playsound(assailant.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return 1 - else - affecting.visible_message("[assailant] fails to jointlock [affecting]'s [O.name].") - G.attacking = 0 - return 0 + return TRUE -/decl/grab/normal/on_hit_harm(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() - var/mob/living/assailant = G.assailant - if(!affecting) - return - if(!assailant.skill_check(SKILL_COMBAT, SKILL_ADEPT)) - return + affecting.visible_message(SPAN_WARNING("\The [assailant] fails to jointlock \the [affecting]'s [O.name].")) + return FALSE + +/decl/grab/normal/on_hit_harm(var/obj/item/grab/grab, var/atom/A, var/proximity) + + if(!proximity) + return FALSE + + var/mob/living/affecting = grab.get_affecting_mob() + if(!affecting || (A && A != affecting)) + return FALSE + + var/mob/living/assailant = grab.assailant + if(!assailant) + return FALSE - var/obj/item/organ/external/O = G.get_targeted_organ() + var/obj/item/organ/external/O = grab.get_targeted_organ() if(!O) - to_chat(assailant, "[affecting] is missing that body part!") - return 0 + to_chat(assailant, SPAN_WARNING("\The [affecting] is missing that body part!")) + return FALSE + + if(!assailant.skill_check(SKILL_COMBAT, SKILL_ADEPT)) + to_chat(assailant, SPAN_WARNING("You clumsily attempt to dislocate \the [affecting]'s [O.name], but fail!")) + return FALSE - if(!O.dislocated) - assailant.visible_message("[assailant] begins to dislocate [affecting]'s [O.joint]!") - G.attacking = 1 + if(!O.is_dislocated() && (O.limb_flags & ORGAN_FLAG_CAN_DISLOCATE)) + assailant.visible_message(SPAN_DANGER("\The [assailant] begins to dislocate \the [affecting]'s [O.joint]!")) if(do_mob(assailant, affecting, action_cooldown - 1)) - G.attacking = 0 - G.action_used() - O.dislocate(1) - assailant.visible_message("[affecting]'s [O.joint] [pick("gives way","caves in","crumbles","collapses")]!") + grab.action_used() + O.dislocate() + assailant.visible_message(SPAN_DANGER("\The [affecting]'s [O.joint] [pick("gives way","caves in","crumbles","collapses")]!")) playsound(assailant.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return 1 - else - affecting.visible_message("[assailant] fails to dislocate [affecting]'s [O.joint].") - G.attacking = 0 - return 0 + return TRUE + affecting.visible_message(SPAN_WARNING("\The [assailant] fails to dislocate \the [affecting]'s [O.joint].")) + return FALSE - else if (O.dislocated > 0) - to_chat(assailant, "[affecting]'s [O.joint] is already dislocated!") - return 0 + if(O.limb_flags & ORGAN_FLAG_CAN_DISLOCATE) + to_chat(assailant, SPAN_WARNING("\The [affecting]'s [O.joint] is already dislocated!")) else - to_chat(assailant, "You can't dislocate [affecting]'s [O.joint]!") - return 0 - -/decl/grab/normal/resolve_openhand_attack(var/obj/item/grab/G) - if(G.assailant.a_intent != I_HELP) - if(G.target_zone == BP_HEAD) - if(G.assailant.zone_sel.selecting == BP_EYES) - if(attack_eye(G)) - return 1 + to_chat(assailant, SPAN_WARNING("You can't dislocate \the [affecting]'s [O.joint]!")) + return FALSE + +/decl/grab/normal/resolve_openhand_attack(var/obj/item/grab/grab) + if(!grab.assailant.check_intent(I_FLAG_HELP)) + if(grab.target_zone == BP_HEAD) + if(grab.assailant.get_target_zone() == BP_EYES) + if(attack_eye(grab)) + return TRUE else - if(headbutt(G)) + if(headbutt(grab)) if(drop_headbutt) let_go() - return 1 - return 0 + return TRUE + return FALSE -/decl/grab/normal/proc/attack_eye(var/obj/item/grab/G) - var/mob/living/carbon/human/target = G.get_affecting_mob() - var/mob/living/carbon/human/attacker = G.assailant +/decl/grab/normal/proc/attack_eye(var/obj/item/grab/grab) + var/mob/living/human/target = grab.get_affecting_mob() + var/mob/living/human/attacker = grab.assailant if(!istype(target) || !istype(attacker)) return var/decl/natural_attack/attack = attacker.get_unarmed_attack(target, BP_EYES) if(!istype(attack)) return - for(var/obj/item/protection in list(target.head, target.wear_mask, target.glasses)) - if(protection && (protection.body_parts_covered & EYES)) + for(var/slot in global.standard_headgear_slots) + var/obj/item/protection = target.get_equipped_item(slot) + if(istype(protection) && (protection.body_parts_covered & SLOT_EYES)) to_chat(attacker, "You're going to need to remove the eye covering first.") return if(!target.check_has_eyes()) @@ -134,28 +139,32 @@ attack.handle_eye_attack(attacker, target) return 1 -/decl/grab/normal/proc/headbutt(var/obj/item/grab/G) - var/mob/living/carbon/human/target = G.get_affecting_mob() - var/mob/living/carbon/human/attacker = G.assailant +/decl/grab/normal/proc/headbutt(var/obj/item/grab/grab) + var/mob/living/human/target = grab.get_affecting_mob() + var/mob/living/human/attacker = grab.assailant if(!istype(target) || !istype(attacker)) return if(!attacker.skill_check(SKILL_COMBAT, SKILL_BASIC)) return - if(target.lying) + if(target.current_posture.prone) return var/damage = 20 - var/obj/item/clothing/hat = attacker.head + var/obj/item/clothing/hat = attacker.get_equipped_item(slot_head_str) var/damage_flags = 0 if(istype(hat)) - damage += hat.force * 3 + damage += hat.expend_attack_force(attacker) * 3 damage_flags = hat.damage_flags() if(damage_flags & DAM_SHARP) - attacker.visible_message("[attacker] gores [target][istype(hat)? " with \the [hat]" : ""]!") + if(istype(hat)) + attacker.visible_message(SPAN_DANGER("\The [attacker] gores \the [target] with \the [hat]!")) + else + attacker.visible_message(SPAN_DANGER("\The [attacker] gores \the [target]!")) else - attacker.visible_message("[attacker] thrusts \his head into [target]'s skull!") + var/decl/pronouns/attacker_gender = attacker.get_pronouns() + attacker.visible_message(SPAN_DANGER("\The [attacker] thrusts [attacker_gender.his] head into \the [target]'s skull!")) var/armor = target.get_blocked_ratio(BP_HEAD, BRUTE, damage = 10) target.apply_damage(damage, BRUTE, BP_HEAD, damage_flags) @@ -163,7 +172,7 @@ if(armor < 0.5 && target.headcheck(BP_HEAD) && prob(damage)) target.apply_effect(20, PARALYZE) - target.visible_message("[target] [target.species.get_knockout_message(target)]") + target.visible_message(SPAN_DANGER("\The [target] [target.species.get_knockout_message(target)]")) playsound(attacker.loc, "swing_hit", 25, 1, -1) @@ -171,115 +180,114 @@ return 1 // Handles special targeting like eyes and mouth being covered. -/decl/grab/normal/special_target_effect(var/obj/item/grab/G) - var/mob/living/affecting_mob = G.get_affecting_mob() - if(istype(affecting_mob) && G.special_target_functional) - switch(G.target_zone) +/decl/grab/normal/special_target_effect(var/obj/item/grab/grab) + var/mob/living/affecting_mob = grab.get_affecting_mob() + if(istype(affecting_mob) && grab.special_target_functional) + switch(grab.target_zone) if(BP_MOUTH) - if(affecting_mob.silent < 2) - affecting_mob.silent = 2 + SET_STATUS_MAX(affecting_mob, STAT_SILENCE, 2) if(BP_EYES) - if(affecting_mob.eye_blind < 2) - affecting_mob.eye_blind = 2 + SET_STATUS_MAX(affecting_mob, STAT_BLIND, 2) // Handles when they change targeted areas and something is supposed to happen. -/decl/grab/normal/special_target_change(var/obj/item/grab/G, old_zone, new_zone) - if(old_zone != BP_HEAD && old_zone != BP_CHEST || !G.get_affecting_mob()) +/decl/grab/normal/special_target_change(var/obj/item/grab/grab, old_zone, new_zone) + if((old_zone != BP_HEAD && old_zone != BP_CHEST) || !grab.get_affecting_mob()) return switch(new_zone) if(BP_MOUTH) - G.assailant.visible_message("\The [G.assailant] covers [G.affecting]'s mouth!") + grab.assailant.visible_message(SPAN_DANGER("\The [grab.assailant] covers [grab.affecting]'s mouth!")) if(BP_EYES) - G.assailant.visible_message("\The [G.assailant] covers [G.affecting]'s eyes!") + grab.assailant.visible_message(SPAN_DANGER("\The [grab.assailant] covers [grab.affecting]'s eyes!")) -/decl/grab/normal/check_special_target(var/obj/item/grab/G) - var/mob/affecting_mob = G.get_affecting_mob() - if(affecting_mob) +/decl/grab/normal/check_special_target(var/obj/item/grab/grab) + var/mob/living/affecting_mob = grab.get_affecting_mob() + if(!istype(affecting_mob)) return FALSE - switch(G.target_zone) + switch(grab.target_zone) if(BP_MOUTH) if(!affecting_mob.check_has_mouth()) - to_chat(G.assailant, "You cannot locate a mouth on [G.affecting]!") + to_chat(grab.assailant, SPAN_WARNING("You cannot locate a mouth on [grab.affecting]!")) return FALSE if(BP_EYES) if(!affecting_mob.check_has_eyes()) - to_chat(G.assailant, "You cannot locate any eyes on [G.affecting]!") + to_chat(grab.assailant, SPAN_WARNING("You cannot locate any eyes on [grab.affecting]!")) return FALSE return TRUE -/decl/grab/normal/resolve_item_attack(var/obj/item/grab/G, var/mob/living/carbon/human/user, var/obj/item/I) - switch(G.target_zone) +/decl/grab/normal/resolve_item_attack(var/obj/item/grab/grab, var/mob/living/human/user, var/obj/item/I) + switch(grab.target_zone) if(BP_HEAD) - return attack_throat(G, I, user) + return attack_throat(grab, I, user) else - return attack_tendons(G, I, user, G.target_zone) + return attack_tendons(grab, I, user, grab.target_zone) -/decl/grab/normal/proc/attack_throat(var/obj/item/grab/G, var/obj/item/W, var/mob/living/carbon/human/user) - var/mob/living/affecting = G.get_affecting_mob() +/decl/grab/normal/proc/attack_throat(var/obj/item/grab/grab, var/obj/item/used_item, mob/user) + var/mob/living/affecting = grab.get_affecting_mob() if(!affecting) return - if(user.a_intent != I_HURT) + if(!user.check_intent(I_FLAG_HARM)) return 0 // Not trying to hurt them. - if(!W.edge || !W.force || W.damtype != BRUTE) + if(!used_item.has_edge() || !used_item.get_attack_force(user) || used_item.atom_damage_type != BRUTE) return 0 //unsuitable weapon - user.visible_message("\The [user] begins to slit [affecting]'s throat with \the [W]!") + user.visible_message("\The [user] begins to slit [affecting]'s throat with \the [used_item]!") user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly if(!do_after(user, 20*user.skill_delay_mult(SKILL_COMBAT) , progress = 0)) return 0 - if(!(G && G.affecting == affecting)) //check that we still have a grab + if(!(grab && grab.affecting == affecting)) //check that we still have a grab return 0 var/damage_mod = 1 - var/damage_flags = W.damage_flags() + var/damage_flags = used_item.damage_flags() //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well - var/obj/item/clothing/head/helmet = affecting.get_equipped_item(slot_head) - if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.item_flags & ITEM_FLAG_AIRTIGHT) && !isnull(helmet.max_pressure_protection)) + var/force = used_item.expend_attack_force(user) + var/obj/item/clothing/head/helmet = affecting.get_equipped_item(slot_head_str) + if(istype(helmet) && (helmet.body_parts_covered & SLOT_HEAD) && (helmet.item_flags & ITEM_FLAG_AIRTIGHT) && !isnull(helmet.max_pressure_protection)) var/datum/extension/armor/armor_datum = get_extension(helmet, /datum/extension/armor) if(armor_datum) - damage_mod -= armor_datum.get_blocked(BRUTE, damage_flags, W.armor_penetration, W.force*1.5) + damage_mod -= armor_datum.get_blocked(BRUTE, damage_flags, used_item.armor_penetration, force*1.5) var/total_damage = 0 for(var/i in 1 to 3) - var/damage = min(W.force*1.5, 20)*damage_mod - affecting.apply_damage(damage, W.damtype, BP_HEAD, damage_flags, armor_pen = 100, used_weapon=W) + var/damage = min(force*1.5, 20)*damage_mod + affecting.apply_damage(damage, used_item.atom_damage_type, BP_HEAD, damage_flags, armor_pen = 100, used_weapon=used_item) total_damage += damage if(total_damage) - user.visible_message("\The [user] slit [affecting]'s throat open with \the [W]!") + user.visible_message("\The [user] slit [affecting]'s throat open with \the [used_item]!") - if(W.hitsound) - playsound(affecting.loc, W.hitsound, 50, 1, -1) + if(used_item.hitsound) + playsound(affecting.loc, used_item.hitsound, 50, 1, -1) - G.last_action = world.time + grab.last_action = world.time admin_attack_log(user, affecting, "Knifed their victim", "Was knifed", "knifed") return 1 -/decl/grab/normal/proc/attack_tendons(var/obj/item/grab/G, var/obj/item/W, var/mob/living/carbon/human/user, var/target_zone) - var/mob/living/affecting = G.get_affecting_mob() +/decl/grab/normal/proc/attack_tendons(var/obj/item/grab/grab, var/obj/item/used_item, mob/user, var/target_zone) + var/mob/living/affecting = grab.get_affecting_mob() if(!affecting) return if(!user.skill_check(SKILL_COMBAT, SKILL_ADEPT)) return - if(user.a_intent != I_HURT) + if(!user.check_intent(I_FLAG_HARM)) return 0 // Not trying to hurt them. - if(!W.edge || !W.force || W.damtype != BRUTE) + if(!used_item.has_edge() || !used_item.expend_attack_force(user) || used_item.atom_damage_type != BRUTE) return 0 //unsuitable weapon - var/obj/item/organ/external/O = G.get_targeted_organ() - if(!O || O.is_stump() || !(O.limb_flags & ORGAN_FLAG_HAS_TENDON) || (O.status & ORGAN_TENDON_CUT)) + var/obj/item/organ/external/O = grab.get_targeted_organ() + if(!O || !(O.limb_flags & ORGAN_FLAG_HAS_TENDON) || (O.status & ORGAN_TENDON_CUT)) return FALSE - user.visible_message(SPAN_DANGER("\The [user] begins to cut \the [affecting]'s [O.tendon_name] with \the [W]!")) + user.visible_message(SPAN_DANGER("\The [user] begins to cut \the [affecting]'s [O.tendon_name] with \the [used_item]!")) user.next_move = world.time + 20 if(!do_after(user, 20, progress=0)) return 0 - if(!(G && G.affecting == affecting)) //check that we still have a grab + if(!(grab && grab.affecting == affecting)) //check that we still have a grab return 0 - if(!O || O.is_stump() || !O.sever_tendon()) + if(!O || !O.sever_tendon()) return 0 - user.visible_message(SPAN_DANGER("\The [user] cut \the [affecting]'s [O.tendon_name] with \the [W]!")) - if(W.hitsound) playsound(affecting.loc, W.hitsound, 50, 1, -1) - G.last_action = world.time + user.visible_message(SPAN_DANGER("\The [user] cut \the [affecting]'s [O.tendon_name] with \the [used_item]!")) + if(used_item.hitsound) playsound(affecting.loc, used_item.hitsound, 50, 1, -1) + grab.last_action = world.time admin_attack_log(user, affecting, "hamstrung their victim", "was hamstrung", "hamstrung") - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/mob/grab/normal/norm_aggressive.dm b/code/modules/mob/grab/normal/norm_aggressive.dm index fabbe2941343..5a48b8a9130f 100644 --- a/code/modules/mob/grab/normal/norm_aggressive.dm +++ b/code/modules/mob/grab/normal/norm_aggressive.dm @@ -1,44 +1,49 @@ /decl/grab/normal/aggressive - name = "aggressive grab" - upgrab = /decl/grab/normal/neck - downgrab = /decl/grab/normal/passive - shift = 12 - stop_move = 1 - reverse_facing = 0 - can_absorb = 0 - shield_assailant = 0 - point_blank_mult = 1.5 - damage_stage = 1 - same_tile = 0 - can_throw = 1 - force_danger = 1 - breakability = 3 - icon_state = "reinforce1" + name = "aggressive grab" + upgrab = /decl/grab/normal/neck + downgrab = /decl/grab/normal/passive + shift = 12 + stop_move = 1 + reverse_facing = 0 + shield_assailant = 0 + point_blank_mult = 1.5 + damage_stage = 1 + same_tile = 0 + can_throw = 1 + force_danger = 1 + breakability = 3 + grab_icon_state = "reinforce1" break_chance_table = list(5, 20, 40, 80, 100) + help_action = "wound pressure" // A bit clunky, but this is only used for admin logs presently! -/decl/grab/normal/aggressive/process_effect(var/obj/item/grab/G) - var/mob/affecting_mob = G.get_affecting_mob() +/decl/grab/normal/aggressive/on_hit_help(obj/item/grab/grab, atom/target, proximity) + var/mob/living/human/grab_victim = grab.get_affecting_mob() + if(!istype(grab_victim) || !proximity || (target && target != grab_victim)) + return FALSE + return grab_victim.apply_pressure(grab.assailant, grab.target_zone) + +/decl/grab/normal/aggressive/process_effect(var/obj/item/grab/grab) + var/mob/living/affecting_mob = grab.get_affecting_mob() if(istype(affecting_mob)) - if(G.target_zone in list(BP_L_HAND, BP_R_HAND)) - affecting_mob.drop_l_hand() - affecting_mob.drop_r_hand() + if(grab.target_zone in list(BP_L_HAND, BP_R_HAND)) + affecting_mob.drop_held_items() // Keeps those who are on the ground down - if(affecting_mob.lying) - affecting_mob.Weaken(4) + if(affecting_mob.current_posture.prone) + SET_STATUS_MAX(affecting_mob, STAT_WEAK, 4) -/decl/grab/normal/aggressive/can_upgrade(var/obj/item/grab/G) +/decl/grab/normal/aggressive/can_upgrade(var/obj/item/grab/grab) . = ..() if(.) - if(!ishuman(G.affecting)) - to_chat(G.assailant, SPAN_WARNING("You can only upgrade an aggressive grab when grappling a human!")) + if(!ishuman(grab.affecting)) + to_chat(grab.assailant, SPAN_WARNING("You can only upgrade an aggressive grab when grappling a human!")) return FALSE - if(!(G.target_zone in list(BP_CHEST, BP_HEAD))) - to_chat(G.assailant, SPAN_WARNING("You need to be grabbing their torso or head for this!")) + if(!(grab.target_zone in list(BP_CHEST, BP_HEAD))) + to_chat(grab.assailant, SPAN_WARNING("You need to be grabbing their torso or head for this!")) return FALSE - var/mob/living/carbon/human/affecting_mob = G.get_affecting_mob() + var/mob/living/human/affecting_mob = grab.get_affecting_mob() if(istype(affecting_mob)) - var/obj/item/clothing/C = affecting_mob.head + var/obj/item/clothing/C = affecting_mob.get_equipped_item(slot_head_str) if(istype(C)) //hardsuit helmets etc - if((C.max_pressure_protection) && C.armor["melee"] > 20) - to_chat(G.assailant, SPAN_WARNING("\The [C] is in the way!")) + if((C.max_pressure_protection) && C.armor[ARMOR_MELEE] > 20) + to_chat(grab.assailant, SPAN_WARNING("\The [C] is in the way!")) return FALSE diff --git a/code/modules/mob/grab/normal/norm_kill.dm b/code/modules/mob/grab/normal/norm_kill.dm index 038e4ab4621a..e716be668640 100644 --- a/code/modules/mob/grab/normal/norm_kill.dm +++ b/code/modules/mob/grab/normal/norm_kill.dm @@ -1,32 +1,30 @@ /decl/grab/normal/kill - name = "strangle" - downgrab = /decl/grab/normal/neck - shift = 0 - stop_move = 1 - reverse_facing = 1 - can_absorb = 1 - shield_assailant = 0 - point_blank_mult = 2 - damage_stage = 3 - same_tile = 1 - force_danger = 1 - restrains = 1 + name = "strangle" + downgrab = /decl/grab/normal/neck + shift = 0 + stop_move = 1 + reverse_facing = 1 + shield_assailant = 0 + point_blank_mult = 2 + damage_stage = 3 + same_tile = 1 + force_danger = 1 + restrains = 1 downgrade_on_action = 1 - downgrade_on_move = 1 - icon_state = "kill1" - break_chance_table = list(5, 20, 40, 80, 100) + downgrade_on_move = 1 + grab_icon_state = "kill1" + break_chance_table = list(5, 20, 40, 80, 100) -/decl/grab/normal/kill/process_effect(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() +/decl/grab/normal/kill/process_effect(var/obj/item/grab/grab) + var/mob/living/affecting = grab.get_affecting_mob() if(!istype(affecting)) return - affecting.drop_l_hand() - affecting.drop_r_hand() - if(affecting.lying) - affecting.Weaken(4) - affecting.adjustOxyLoss(1) + affecting.drop_held_items() + if(affecting.current_posture.prone) + SET_STATUS_MAX(affecting, STAT_WEAK, 4) + affecting.take_damage(1, OXY) affecting.apply_effect(STUTTER, 5) //It will hamper your voice, being choked and all. - affecting.Weaken(5) //Should keep you down unless you get help. - if(iscarbon(affecting)) - var/mob/living/carbon/C = affecting - C.losebreath = max(C.losebreath + 2, 3) + SET_STATUS_MAX(affecting, STAT_WEAK, 5) //Should keep you down unless you get help. + if(isliving(affecting)) + var/mob/living/M = affecting + M.suffocation_counter = max(M.suffocation_counter + 2, 3) diff --git a/code/modules/mob/grab/normal/norm_neck.dm b/code/modules/mob/grab/normal/norm_neck.dm index 1f9c8ebc6a51..b79daeca1985 100644 --- a/code/modules/mob/grab/normal/norm_neck.dm +++ b/code/modules/mob/grab/normal/norm_neck.dm @@ -1,28 +1,26 @@ /decl/grab/normal/neck - name = "chokehold" - upgrab = /decl/grab/normal/kill - downgrab = /decl/grab/normal/aggressive - drop_headbutt = 0 - shift = -10 - stop_move = 1 - reverse_facing = 1 - can_absorb = 1 - shield_assailant = 1 - point_blank_mult = 2 - damage_stage = 2 - same_tile = 1 - can_throw = 1 - force_danger = 1 - restrains = 1 - icon_state = "kill" + name = "chokehold" + upgrab = /decl/grab/normal/kill + downgrab = /decl/grab/normal/aggressive + drop_headbutt = 0 + shift = -10 + stop_move = 1 + reverse_facing = 1 + shield_assailant = 1 + point_blank_mult = 2 + damage_stage = 2 + same_tile = 1 + can_throw = 1 + force_danger = 1 + restrains = 1 + grab_icon_state = "kill" break_chance_table = list(3, 18, 45, 100) -/decl/grab/normal/neck/process_effect(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() +/decl/grab/normal/neck/process_effect(var/obj/item/grab/grab) + var/mob/living/affecting = grab.get_affecting_mob() if(!istype(affecting)) return - affecting.drop_l_hand() - affecting.drop_r_hand() - if(affecting.lying) - affecting.Weaken(4) - affecting.adjustOxyLoss(1) + affecting.drop_held_items() + if(affecting.current_posture.prone) + SET_STATUS_MAX(affecting, STAT_WEAK, 4) + affecting.take_damage(1, OXY) diff --git a/code/modules/mob/grab/normal/norm_passive.dm b/code/modules/mob/grab/normal/norm_passive.dm index 42aad7eea105..d57f421e944e 100644 --- a/code/modules/mob/grab/normal/norm_passive.dm +++ b/code/modules/mob/grab/normal/norm_passive.dm @@ -1,28 +1,29 @@ /decl/grab/normal/passive - name = "passive hold" - fancy_desc = "holding" - upgrab = /decl/grab/normal/struggle - shift = 8 - stop_move = 0 - reverse_facing = 0 - can_absorb = 0 - shield_assailant = 0 - point_blank_mult = 1.1 - same_tile = 0 - icon_state = "reinforce" + name = "passive hold" + upgrab = /decl/grab/normal/struggle + shift = 8 + stop_move = 0 + reverse_facing = 0 + shield_assailant = 0 + point_blank_mult = 1.1 + same_tile = 0 + grab_icon_state = "reinforce" break_chance_table = list(15, 60, 100) -/decl/grab/normal/passive/on_hit_disarm(var/obj/item/grab/G) - to_chat(G.assailant, SPAN_WARNING("Your grip isn't strong enough to pin.")) - return 0 +/decl/grab/normal/passive/on_hit_disarm(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(proximity) + to_chat(grab.assailant, SPAN_WARNING("Your grip isn't strong enough to pin.")) + return FALSE -/decl/grab/normal/passive/on_hit_grab(var/obj/item/grab/G) - to_chat(G.assailant, SPAN_WARNING("Your grip isn't strong enough to jointlock.")) - return 0 +/decl/grab/normal/passive/on_hit_grab(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(proximity) + to_chat(grab.assailant, SPAN_WARNING("Your grip isn't strong enough to jointlock.")) + return FALSE -/decl/grab/normal/passive/on_hit_harm(var/obj/item/grab/G) - to_chat(G.assailant, SPAN_WARNING("Your grip isn't strong enough to dislocate.")) - return 0 +/decl/grab/normal/passive/on_hit_harm(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(proximity) + to_chat(grab.assailant, SPAN_WARNING("Your grip isn't strong enough to dislocate.")) + return FALSE -/decl/grab/normal/passive/resolve_openhand_attack(var/obj/item/grab/G) - return 0 +/decl/grab/normal/passive/resolve_openhand_attack(var/obj/item/grab/grab) + return FALSE diff --git a/code/modules/mob/grab/normal/norm_struggle.dm b/code/modules/mob/grab/normal/norm_struggle.dm index d5c91362cfaf..84c212e5bc78 100644 --- a/code/modules/mob/grab/normal/norm_struggle.dm +++ b/code/modules/mob/grab/normal/norm_struggle.dm @@ -1,73 +1,76 @@ /decl/grab/normal/struggle - name = "struggle grab" - fancy_desc = "holding" - upgrab = /decl/grab/normal/aggressive - downgrab = /decl/grab/normal/passive - shift = 8 - stop_move = 1 - reverse_facing = 0 - can_absorb = 0 - point_blank_mult = 1 - same_tile = 0 - breakability = 3 - grab_slowdown = 10 - upgrade_cooldown = 20 + name = "struggle grab" + upgrab = /decl/grab/normal/aggressive + downgrab = /decl/grab/normal/passive + shift = 8 + stop_move = 1 + reverse_facing = 0 + point_blank_mult = 1 + same_tile = 0 + breakability = 3 + grab_slowdown = 0.35 + upgrade_cooldown = 20 can_downgrade_on_resist = 0 - icon_state = "reinforce" - break_chance_table = list(5, 20, 30, 80, 100) + grab_icon_state = "reinforce" + break_chance_table = list(5, 20, 30, 80, 100) -/decl/grab/normal/struggle/process_effect(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() - var/mob/living/assailant = G.assailant +/decl/grab/normal/struggle/process_effect(var/obj/item/grab/grab) + var/mob/living/affecting = grab.get_affecting_mob() + var/mob/living/assailant = grab.assailant if(!affecting) return - if(affecting.incapacitated(INCAPACITATION_UNRESISTING) || affecting.a_intent == I_HELP) - affecting.visible_message("[affecting] isn't prepared to fight back as [assailant] tightens \his grip!") - G.done_struggle = TRUE - G.upgrade(TRUE) + if(affecting.incapacitated(INCAPACITATION_UNRESISTING) || affecting.check_intent(I_FLAG_HELP)) + var/decl/pronouns/assailant_gender = assailant.get_pronouns() + affecting.visible_message(SPAN_DANGER("\The [affecting] isn't prepared to fight back as [assailant] tightens [assailant_gender.his] grip!")) + grab.done_struggle = TRUE + grab.upgrade(TRUE) -/decl/grab/normal/struggle/enter_as_up(var/obj/item/grab/G) - var/mob/living/affecting = G.get_affecting_mob() - var/mob/living/assailant = G.assailant +/decl/grab/normal/struggle/enter_as_up(var/obj/item/grab/grab) + var/mob/living/affecting = grab.get_affecting_mob() + var/mob/living/assailant = grab.assailant if(!affecting) return if(affecting == assailant) - G.done_struggle = TRUE - G.upgrade(TRUE) + grab.done_struggle = TRUE + grab.upgrade(TRUE) return - if(affecting.incapacitated(INCAPACITATION_UNRESISTING) || affecting.a_intent == I_HELP) - affecting.visible_message("[affecting] isn't prepared to fight back as [assailant] tightens \his grip!") - G.done_struggle = TRUE - G.upgrade(TRUE) + if(affecting.incapacitated(INCAPACITATION_UNRESISTING) || affecting.check_intent(I_FLAG_HELP)) + var/decl/pronouns/assailant_gender = assailant.get_pronouns() + affecting.visible_message(SPAN_DANGER("\The [affecting] isn't prepared to fight back as [assailant] tightens [assailant_gender.his] grip!")) + grab.done_struggle = TRUE + grab.upgrade(TRUE) else affecting.visible_message("[affecting] struggles against [assailant]!") - G.done_struggle = FALSE - addtimer(CALLBACK(G, .proc/handle_resist), 1 SECOND) - resolve_struggle(G) + grab.done_struggle = FALSE + addtimer(CALLBACK(grab, PROC_REF(handle_resist)), 1 SECOND) + resolve_struggle(grab) -/decl/grab/normal/struggle/proc/resolve_struggle(var/obj/item/grab/G) +/decl/grab/normal/struggle/proc/resolve_struggle(var/obj/item/grab/grab) set waitfor = FALSE - if(do_after(G.assailant, upgrade_cooldown, G, can_move = 1)) - G.done_struggle = TRUE - G.upgrade(TRUE) + if(do_after(grab.assailant, upgrade_cooldown, grab, can_move = 1)) + grab.done_struggle = TRUE + grab.upgrade(TRUE) else - G.downgrade() + grab.downgrade() -/decl/grab/normal/struggle/can_upgrade(var/obj/item/grab/G) - . = ..() && G.done_struggle +/decl/grab/normal/struggle/can_upgrade(var/obj/item/grab/grab) + . = ..() && grab.done_struggle -/decl/grab/normal/struggle/on_hit_disarm(var/obj/item/grab/G) - to_chat(G.assailant, "Your grip isn't strong enough to pin.") - return 0 +/decl/grab/normal/struggle/on_hit_disarm(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(proximity) + to_chat(grab.assailant, SPAN_WARNING("Your grip isn't strong enough to pin.")) + return FALSE -/decl/grab/normal/struggle/on_hit_grab(var/obj/item/grab/G) - to_chat(G.assailant, "Your grip isn't strong enough to jointlock.") - return 0 +/decl/grab/normal/struggle/on_hit_grab(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(proximity) + to_chat(grab.assailant, SPAN_WARNING("Your grip isn't strong enough to jointlock.")) + return FALSE -/decl/grab/normal/struggle/on_hit_harm(var/obj/item/grab/G) - to_chat(G.assailant, "Your grip isn't strong enough to dislocate.") - return 0 +/decl/grab/normal/struggle/on_hit_harm(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(proximity) + to_chat(grab.assailant, SPAN_WARNING("Your grip isn't strong enough to dislocate.")) + return FALSE -/decl/grab/normal/struggle/resolve_openhand_attack(var/obj/item/grab/G) - return 0 +/decl/grab/normal/struggle/resolve_openhand_attack(var/obj/item/grab/grab) + return FALSE diff --git a/code/modules/mob/grab/simple/simple_control.dm b/code/modules/mob/grab/simple/simple_control.dm new file mode 100644 index 000000000000..bcab5545f070 --- /dev/null +++ b/code/modules/mob/grab/simple/simple_control.dm @@ -0,0 +1,50 @@ +/decl/grab/simple/control + name = "controlling grab" + shift = 0 + adjust_plane = FALSE + adjust_layer = FALSE + +/decl/grab/simple/control/on_hit_help(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(A == grab.assailant) + A = grab.affecting + if(isliving(grab.affecting)) + var/mob/living/living_mob = grab.affecting + return living_mob.handle_rider_help_order(grab.assailant, A, proximity) + return FALSE + +/decl/grab/simple/control/on_hit_disarm(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(A == grab.assailant) + A = grab.affecting + if(isliving(grab.affecting)) + var/mob/living/living_mob = grab.affecting + return living_mob.handle_rider_disarm_order(grab.assailant, A, proximity) + return FALSE + +/decl/grab/simple/control/on_hit_grab(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(A == grab.assailant) + A = grab.affecting + if(isliving(grab.affecting)) + var/mob/living/living_mob = grab.affecting + return living_mob.handle_rider_grab_order(grab.assailant, A, proximity) + return FALSE + +/decl/grab/simple/control/on_hit_harm(var/obj/item/grab/grab, var/atom/A, var/proximity) + if(A == grab.assailant) + A = grab.affecting + if(isliving(grab.affecting)) + var/mob/living/living_mob = grab.affecting + return living_mob.handle_rider_harm_order(grab.assailant, A, proximity) + return FALSE + +// Override these for mobs that will respond to instructions from a rider. +/mob/living/proc/handle_rider_harm_order(mob/user, atom/target, proximity) + return istype(ai) ? ai.process_handler_target(user, target, I_FLAG_HARM) : FALSE + +/mob/living/proc/handle_rider_grab_order(mob/user, atom/target, proximity) + return istype(ai) ? ai.process_handler_target(user, target, I_FLAG_GRAB) : FALSE + +/mob/living/proc/handle_rider_disarm_order(mob/user, atom/target, proximity) + return istype(ai) ? ai.process_handler_target(user, target, I_FLAG_DISARM) : FALSE + +/mob/living/proc/handle_rider_help_order(mob/user, atom/target, proximity) + return istype(ai) ? ai.process_handler_target(user, target, I_FLAG_HELP) : FALSE diff --git a/code/modules/mob/grab/simple/simple_passive.dm b/code/modules/mob/grab/simple/simple_passive.dm index 0d55951da93e..a95988c4074f 100644 --- a/code/modules/mob/grab/simple/simple_passive.dm +++ b/code/modules/mob/grab/simple/simple_passive.dm @@ -3,25 +3,22 @@ shift = 8 stop_move = 0 reverse_facing = 0 - can_absorb = 0 shield_assailant = 0 point_blank_mult = 1 same_tile = 0 - fancy_desc = "holding" - icon_state = "reinforce" break_chance_table = list(15, 60, 100) -/decl/grab/simple/upgrade(obj/item/grab/G) +/decl/grab/simple/upgrade(obj/item/grab/grab) return - -/decl/grab/simple/on_hit_disarm(var/obj/item/grab/G) - return 0 -/decl/grab/simple/on_hit_grab(var/obj/item/grab/G) - return 0 +/decl/grab/simple/on_hit_disarm(var/obj/item/grab/grab, var/atom/A, var/proximity) + return FALSE -/decl/grab/simple/on_hit_harm(var/obj/item/grab/G) - return 0 +/decl/grab/simple/on_hit_grab(var/obj/item/grab/grab, var/atom/A, var/proximity) + return FALSE -/decl/grab/simple/resolve_openhand_attack(var/obj/item/grab/G) - return 0 +/decl/grab/simple/on_hit_harm(var/obj/item/grab/grab, var/atom/A, var/proximity) + return FALSE + +/decl/grab/simple/resolve_openhand_attack(var/obj/item/grab/grab) + return FALSE diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index b1accc3ef8f3..76104279447a 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -1,15 +1,15 @@ // At minimum every mob has a hear_say proc. -/mob/proc/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) +/mob/proc/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) if(!client) return - if(speaker && !speaker.client && isghost(src) && get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH && !(speaker in view(src))) + if(speaker && !speaker.client && isghost(src) && get_preference_value(/datum/client_preference/ghost_ears) == PREF_ALL_SPEECH && !(speaker in view(src))) //Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE') //Or someone snoring. So we make it where they won't hear it. return - if(language && (language.flags & (NONVERBAL|SIGNLANG))) + if(language && (language.flags & (LANG_FLAG_NONVERBAL|LANG_FLAG_SIGNLANG))) sound_vol = 0 speech_sound = null @@ -21,38 +21,28 @@ if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1) return - if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + if (pressure < (0.4 ATM)) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet italics = 1 sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact - if(sleeping || stat == UNCONSCIOUS) + if(HAS_STATUS(src, STAT_ASLEEP) || stat == UNCONSCIOUS) hear_sleep(message) return //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. - if (language && (language.flags & NONVERBAL)) - if (!speaker || (src.sdisabilities & BLINDED || src.blinded) || !(speaker in view(src))) + if (language && (language.flags & LANG_FLAG_NONVERBAL)) + if (!speaker || is_blind() || !(speaker in view(src))) message = stars(message) - if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages - if(!say_understands(speaker,language)) - if(istype(speaker,/mob/living/simple_animal)) - var/mob/living/simple_animal/S = speaker - message = pick(S.speak) + var/understands_language = say_understands(speaker, language) + if(!(language && (language.flags & LANG_FLAG_INNATE))) // skip understanding checks for INNATE languages + if(!understands_language) + if(language) + message = language.scramble(speaker, message, languages) else - if(language) - message = language.scramble(message, languages) - else - message = stars(message) - - var/speaker_name = "Unknown" - if(speaker) - speaker_name = speaker.name - - if(istype(speaker, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = speaker - speaker_name = H.GetVoice() + message = stars(message) + var/speaker_name = speaker?.GetVoice() || "Unknown" if(italics) message = "[message]" @@ -61,34 +51,35 @@ if(speaker_name != speaker.real_name && speaker.real_name) speaker_name = "[speaker.real_name] ([speaker_name])" track = "([ghost_follow_link(speaker, src)]) " - if(get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH && (speaker in view(src))) + if(get_preference_value(/datum/client_preference/ghost_ears) == PREF_ALL_SPEECH && (speaker in view(src))) message = "[message]" if(is_deaf() || get_sound_volume_multiplier() < 0.2) - if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set + if(!language || !(language.flags & LANG_FLAG_INNATE)) // LANG_FLAG_INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set if(speaker == src) - to_chat(src, "You cannot hear yourself speak!") + to_chat(src, SPAN_WARNING("You cannot hear yourself speak!")) else if(!is_blind()) - to_chat(src, "[speaker_name][alt_name] talks but you cannot hear \him.") + var/decl/pronouns/pronouns = speaker.get_pronouns() + to_chat(src, "\The [speaker_name] talks but you cannot hear [pronouns.him].") else if (language) var/nverb = verb - if (say_understands(speaker, language)) + if (understands_language) var/skip = FALSE if (isliving(src)) var/mob/living/L = src skip = L.default_language == language if (!skip) switch(src.get_preference_value(/datum/client_preference/language_display)) - if(GLOB.PREF_FULL) // Full language name + if(PREF_FULL) // Full language name nverb = "[verb] in [language.name]" - if(GLOB.PREF_SHORTHAND) //Shorthand codes + if(PREF_SHORTHAND) //Shorthand codes nverb = "[verb] ([language.shorthand])" - if(GLOB.PREF_OFF)//Regular output + if(PREF_OFF)//Regular output nverb = verb - on_hear_say("[track][speaker_name][alt_name] [language.format_message(message, nverb)]") + on_hear_say("[track]\The [speaker_name] [language.format_message(message, nverb)]") else - on_hear_say("[track][speaker_name][alt_name] [verb], \"[message]\"") + on_hear_say("[track]\The [speaker_name] [verb], \"[message]\"") if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z)) var/turf/source = speaker? get_turf(speaker) : get_turf(src) src.playsound_local(source, speech_sound, sound_vol, 1) @@ -100,33 +91,32 @@ var/time = say_timestamp() to_chat(src, "[time] [message]") -/mob/proc/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") +/mob/proc/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/vsource) if(!client) return - if(sleeping || stat==1) //If unconscious or sleeping + if(HAS_STATUS(src, STAT_ASLEEP) || stat == UNCONSCIOUS) //If unconscious or sleeping hear_sleep(message) return var/track = null //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. - if (language && (language.flags & NONVERBAL)) - if (!speaker || (src.sdisabilities & BLINDED || src.blinded) || !(speaker in view(src))) + if (language && (language.flags & LANG_FLAG_NONVERBAL)) + if (!speaker || is_blind() || !(speaker in view(src))) message = stars(message) - if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!(language && (language.flags & LANG_FLAG_INNATE))) // skip understanding checks for LANG_FLAG_INNATE languages if(!say_understands(speaker,language)) - if(istype(speaker,/mob/living/simple_animal)) - var/mob/living/simple_animal/S = speaker - if(S.speak && S.speak.len) - message = pick(S.speak) + if(isanimal(speaker)) + if(LAZYLEN(speaker.ai?.emote_speech)) + message = pick(speaker.ai.emote_speech) else return else if(language) - message = language.scramble(message, languages) + message = language.scramble(speaker, message, languages) else message = stars(message) @@ -138,9 +128,9 @@ var/speaker_name = vname ? vname : speaker.name - if(istype(speaker, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = speaker - if(H.voice) + if(ishuman(speaker)) + var/mob/living/human/H = speaker + if(H.voice && !vname) speaker_name = H.voice if(hard_to_hear) @@ -148,20 +138,20 @@ var/changed_voice - if(istype(src, /mob/living/silicon/ai) && !hard_to_hear) + if(isAI(src) && !hard_to_hear) var/jobname // the mob's "job" - var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any. + var/mob/living/human/impersonating //The crew member being impersonated, if any. if (ishuman(speaker)) - var/mob/living/carbon/human/H = speaker + var/mob/living/human/H = speaker - if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/chameleon/voice)) + if(istype(H.get_equipped_item(slot_wear_mask_str), /obj/item/clothing/mask/chameleon/voice)) changed_voice = 1 var/list/impersonated = new() - var/mob/living/carbon/human/I = impersonated[speaker_name] + var/mob/living/human/I = impersonated[speaker_name] if(!I) - for(var/mob/living/carbon/human/M in SSmobs.mob_list) + for(var/mob/living/human/M in SSmobs.mob_list) if(M.real_name == speaker_name) I = M impersonated[speaker_name] = I @@ -169,7 +159,7 @@ // If I's display name is currently different from the voice name and using an agent ID then don't impersonate // as this would allow the AI to track I and realize the mismatch. - if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/card/id/syndicate))) + if(I && !(I.name != speaker_name && istype(I.get_equipped_item(slot_wear_id_str),/obj/item/card/id/syndicate))) impersonating = I jobname = impersonating.get_assignment() else @@ -177,13 +167,11 @@ else jobname = H.get_assignment() - else if (iscarbon(speaker)) // Nonhuman carbon mob - jobname = "No id" else if (isAI(speaker)) jobname = "AI" else if (isrobot(speaker)) jobname = "Robot" - else if (istype(speaker, /mob/living/silicon/pai)) + else if (ispAI(speaker)) jobname = "Personal AI" else jobname = "Unknown" @@ -197,7 +185,7 @@ track = "[speaker_name] ([jobname])" if(isghost(src)) - if(speaker) //speaker is null when the arrivals annoucement plays + if(istype(speaker)) //speaker is null when the arrivals annoucement plays if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. speaker_name = "[speaker.real_name] ([speaker_name])" track = "([ghost_follow_link(speaker, src)]) [speaker_name]" @@ -214,60 +202,62 @@ skip = L.default_language == language if (!skip) switch(src.get_preference_value(/datum/client_preference/language_display)) - if (GLOB.PREF_FULL) + if (PREF_FULL) nverb = "[verb] in [language.name]" - if(GLOB.PREF_SHORTHAND) + if(PREF_SHORTHAND) nverb = "[verb] ([language.shorthand])" - if(GLOB.PREF_OFF) + if(PREF_OFF) nverb = verb formatted = language.format_message_radio(message, nverb) else formatted = "[verb], \"[message]\"" - if(sdisabilities & DEAFENED || ear_deaf) - var/mob/living/carbon/human/H = src + if(has_genetic_condition(GENE_COND_DEAFENED) || GET_STATUS(src, STAT_DEAF)) + var/mob/living/human/H = src if(istype(H) && H.has_headset_in_ears() && prob(20)) to_chat(src, SPAN_WARNING("You feel your headset vibrate but can hear nothing from it!")) + else if(vsource) + on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted, " \[[vsource]\]") else - on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) + on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted, null) /proc/say_timestamp() return "\[[stationtime2text()]\]" -/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) - to_chat(src, "[part_a][speaker_name][part_b][formatted][part_c]") +/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted, vsource) + to_chat(src, "[part_a][speaker_name][vsource][part_b][formatted][part_c]") -/mob/observer/ghost/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) - to_chat(src, "[part_a][track][part_b][formatted][part_c]") +/mob/observer/ghost/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted, vsource) + to_chat(src, "[part_a][track][vsource][part_b][formatted][part_c]") -/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) +/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted, vsource) var/time = say_timestamp() - to_chat(src, "[time][part_a][speaker_name][part_b][formatted][part_c]") + to_chat(src, "[time][part_a][speaker_name][vsource][part_b][formatted][part_c]") -/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted) +/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, part_c, formatted, vsource) var/time = say_timestamp() - to_chat(src, "[time][part_a][track][part_b][formatted][part_c]") + to_chat(src, "[time][part_a][track][vsource][part_b][formatted][part_c]") /mob/proc/hear_signlang(var/message, var/verb = "gestures", var/decl/language/language, var/mob/speaker = null) if(!client) return - if(sleeping || stat == UNCONSCIOUS) + if(HAS_STATUS(src, STAT_ASLEEP) || stat == UNCONSCIOUS) return 0 if(say_understands(speaker, language)) var/nverb = null switch(src.get_preference_value(/datum/client_preference/language_display)) - if(GLOB.PREF_FULL) // Full language name + if(PREF_FULL) // Full language name nverb = "[verb] in [language.name]" - if(GLOB.PREF_SHORTHAND) //Shorthand codes + if(PREF_SHORTHAND) //Shorthand codes nverb = "[verb] ([language.shorthand])" - if(GLOB.PREF_OFF)//Regular output + if(PREF_OFF)//Regular output nverb = verb message = "[speaker] [nverb], \"[message]\"" else var/adverb - var/length = length(message) * pick(0.8, 0.9, 1.0, 1.1, 1.2) //Inserts a little fuzziness. - switch(length) + var/msg_length = length(message) * pick(0.8, 0.9, 1.0, 1.1, 1.2) //Inserts a little fuzziness. + switch(msg_length) if(0 to 12) adverb = " briefly" if(12 to 30) adverb = " a short message" if(30 to 48) adverb = " a message" @@ -283,6 +273,8 @@ src.show_message(message) /mob/proc/hear_sleep(var/message) + if (is_deaf()) + return var/heard = "" if(prob(15)) var/list/punctuation = list(",", "!", ".", ";", "?") diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm deleted file mode 100644 index 0efb7ad45a26..000000000000 --- a/code/modules/mob/holder.dm +++ /dev/null @@ -1,232 +0,0 @@ -var/list/holder_mob_icon_cache = list() - -//Helper object for picking creatures up. -/obj/item/holder - name = "holder" - desc = "You shouldn't ever see this." - icon = 'icons/obj/objects.dmi' - slot_flags = SLOT_HEAD | SLOT_HOLSTER - - origin_tech = null - item_icons = list( - slot_l_hand_str = 'icons/mob/onmob/items/lefthand_holder.dmi', - slot_r_hand_str = 'icons/mob/onmob/items/righthand_holder.dmi', - ) - pixel_y = 8 - - var/last_holder - -/obj/item/holder/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/item/holder/proc/destroy_all() - for(var/atom/movable/AM in src) - qdel(AM) - qdel(src) - -/obj/item/holder/Destroy() - for(var/atom/movable/AM in src) - AM.forceMove(get_turf(src)) - last_holder = null - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/holder/Process() - update_state() - -/obj/item/holder/dropped() - ..() - update_state(1) - -/obj/item/holder/throw_impact(atom/hit_atom, datum/thrownthing/TT) - . = ..() - update_state(1) - -/obj/item/holder/proc/update_state(var/delay) - set waitfor = 0 - - if(last_holder != loc) - for(var/mob/M in contents) - unregister_all_movement(last_holder, M) - - if(delay) - sleep(delay) - - if(QDELETED(src) || throwing) - return - - if(istype(loc,/turf) || !contents.len) - for(var/mob/M in contents) - var/atom/movable/mob_container = M - mob_container.dropInto(loc) - M.reset_view() - qdel(src) - else if(last_holder != loc) - for(var/mob/M in contents) - register_all_movement(loc, M) - - last_holder = loc - -/obj/item/holder/onDropInto(var/atom/movable/AM) - if(ismob(loc)) // Bypass our holding mob and drop directly to its loc - return loc.loc - return ..() - -/obj/item/holder/GetIdCard() - for(var/mob/M in contents) - var/obj/item/I = M.GetIdCard() - if(I) - return I - return null - -/obj/item/holder/GetAccess() - var/obj/item/I = GetIdCard() - return I ? I.GetAccess() : ..() - -/obj/item/holder/attack_self() - for(var/mob/M in contents) - M.show_inv(usr) - -/obj/item/holder/attack(mob/target, mob/user) - // Devour on click on self with holder - if(target == user && istype(user,/mob/living/carbon)) - var/mob/living/carbon/M = user - - for(var/mob/victim in src.contents) - M.devour(victim) - - update_state() - - ..() - -/obj/item/holder/proc/sync(var/mob/living/M) - set_dir(SOUTH) - overlays.Cut() - icon = M.icon - icon_state = M.icon_state - item_state = M.item_state - color = M.color - SetName(M.name) - desc = M.desc - overlays |= M.overlays - var/mob/living/carbon/human/H = loc - last_holder = H - register_all_movement(H, M) - - update_held_icon() - -//Mob specific holders. -/obj/item/holder/drone - origin_tech = "{'magnets':3,'engineering':5}" - -/obj/item/holder/mouse - w_class = ITEM_SIZE_TINY - -//need own subtype to work with recipes -/obj/item/holder/corgi - origin_tech = "{'biotech':4}" - -/obj/item/holder/attackby(obj/item/W, mob/user) - for(var/mob/M in src.contents) - M.attackby(W,user) - -//Mob procs and vars for scooping up -/mob/living/var/holder_type - -/mob/living/proc/get_scooped(var/mob/living/carbon/human/grabber, var/self_grab) - - if(!holder_type || buckled || pinned.len) - return - - if(self_grab) - if(src.incapacitated()) return - else - if(grabber.incapacitated()) return - - var/obj/item/holder/H = new holder_type(get_turf(src)) - - if(self_grab) - if(!grabber.equip_to_slot_if_possible(H, slot_back, del_on_fail=0, disable_warning=1)) - to_chat(src, "You can't climb onto [grabber]!") - return - - to_chat(grabber, "\The [src] clambers onto you!") - to_chat(src, "You climb up onto \the [grabber]!") - else - if(!grabber.put_in_hands(H)) - to_chat(grabber, "Your hands are full!") - return - - to_chat(grabber, "You scoop up \the [src]!") - to_chat(src, "\The [grabber] scoops you up!") - - src.forceMove(H) - - grabber.status_flags |= PASSEMOTES - H.sync(src) - return H - -/mob/living/attack_hand(mob/user) - - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable && hattable.hat) - hattable.hat.forceMove(get_turf(src)) - user.put_in_hands(hattable.hat) - user.visible_message(SPAN_DANGER("\The [user] removes \the [src]'s [hattable.hat]!")) - hattable.hat = null - update_icons() - return TRUE - - if(ishuman(user)) - var/mob/living/carbon/H = user - if(H.a_intent == I_GRAB && scoop_check(user)) - get_scooped(user, FALSE) - return TRUE - - . = ..() - -/mob/living/proc/scoop_check(var/mob/living/scooper) - . = TRUE - -/mob/living/carbon/human/scoop_check(var/mob/living/scooper) - . = ..() && scooper.mob_size > src.mob_size - -/obj/item/holder/human - icon = 'icons/mob/holder_complex.dmi' - var/mob_blend_mode = ICON_ADD - slot_flags = SLOT_BACK - var/list/generate_for_slots = list(slot_l_hand_str, slot_r_hand_str, slot_back_str) - -/obj/item/holder/human/sync(var/mob/living/M) - // Generate appropriate on-mob icons. - var/mob/living/carbon/human/owner = M - if(istype(owner) && owner.species && LAZYLEN(generate_for_slots)) - - var/skin_colour = owner.skin_colour - var/hair_colour = owner.hair_colour - var/eye_colour = owner.eye_colour - var/species_name = lowertext(owner.species.get_bodytype(owner)) - - for(var/cache_entry in generate_for_slots) - var/cache_key = "[owner.species]-[cache_entry]-[skin_colour]-[hair_colour]" - if(!holder_mob_icon_cache[cache_key]) - - // Generate individual icons. - var/icon/mob_icon = icon(icon, "[species_name]_holder_[cache_entry]_base") - mob_icon.Blend(skin_colour, ICON_ADD) - var/icon/hair_icon = icon(icon, "[species_name]_holder_[cache_entry]_hair") - hair_icon.Blend(hair_colour, ICON_ADD) - var/icon/eyes_icon = icon(icon, "[species_name]_holder_[cache_entry]_eyes") - eyes_icon.Blend(eye_colour, ICON_ADD) - - // Blend them together. - mob_icon.Blend(eyes_icon, ICON_OVERLAY) - mob_icon.Blend(hair_icon, ICON_OVERLAY) - - // Add to the cache. - holder_mob_icon_cache[cache_key] = mob_icon - item_icons[cache_entry] = holder_mob_icon_cache[cache_key] - - // Handle the rest of sync(). - ..(M) diff --git a/code/modules/mob/hugs.dm b/code/modules/mob/hugs.dm new file mode 100644 index 000000000000..f38eec055bc8 --- /dev/null +++ b/code/modules/mob/hugs.dm @@ -0,0 +1,53 @@ +var/global/list/_default_hug_messages = list( + BP_HEAD = list( + "$USER$ pats $TARGET$ on the head.", + "You pat $TARGET$ on the head." + ) +) + +/mob/proc/get_hug_zone_messages(var/zone) + var/decl/bodytype/bodytype = get_bodytype() + return bodytype?.get_hug_zone_messages(zone) || bodytype?.default_hug_message || global._default_hug_messages[zone] + +/mob/proc/get_default_3p_hug_message(mob/living/target) + if(target && get_dir(src, target) == target.dir) + return "$USER$ rubs $TARGET$'s back soothingly." + return "$USER$ hugs $TARGET$ to make $TARGET_THEM$ feel better." + +/mob/proc/get_default_1p_hug_message(mob/living/target) + if(target && get_dir(src, target) == target.dir) + return "You rub $TARGET$'s back soothingly." + return "You hug $TARGET$ to make $TARGET_THEM$ feel better." + +/mob/proc/attempt_hug(var/mob/living/target, var/hug_3p, var/hug_1p) + + if(!istype(target)) + return FALSE + + var/list/use_hug_messages = target.get_hug_zone_messages(get_target_zone()) + if(length(use_hug_messages) >= 2) + hug_3p = use_hug_messages[1] + hug_1p = use_hug_messages[2] + + if(isnull(hug_3p) || isnull(hug_1p)) + hug_1p = get_default_1p_hug_message(target) + hug_3p = get_default_3p_hug_message(target) + + if(!hug_1p || !hug_3p) + return FALSE + + hug_3p = emote_replace_user_tokens(hug_3p, src) + hug_3p = emote_replace_target_tokens(hug_3p, target) + hug_1p = emote_replace_target_tokens(hug_1p, target) + visible_message( + SPAN_NOTICE(capitalize_proper_html(hug_3p)), + SPAN_NOTICE(capitalize_proper_html(hug_1p)) + ) + + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + if(src != target && client && key && target.client && target.key && !target.incapacitated()) + update_personal_goal(/datum/goal/achievement/givehug, TRUE) + target.update_personal_goal(/datum/goal/achievement/gethug, TRUE) + + return TRUE diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 3d5986bc39c6..a565d1e1aae0 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -1,111 +1,154 @@ //This proc is called whenever someone clicks an inventory ui slot. /mob/proc/attack_ui(slot) - var/obj/item/W = get_active_hand() - var/obj/item/E = get_equipped_item(slot) - if (istype(E)) - if(istype(W)) - E.attackby(W,src) + var/obj/item/holding = get_active_held_item() + var/obj/item/equipped = get_equipped_item(slot) + if (istype(equipped)) + if(istype(holding)) + equipped.attackby(holding, src) else - E.attack_hand(src) + equipped.attack_hand(src) // We can assume it's physically accessible if it's on our person. else - equip_to_slot_if_possible(W, slot) - -/mob/proc/put_in_any_hand_if_possible(obj/item/W, del_on_fail = 0, disable_warning = 1, redraw_mob = 1) - if(equip_to_slot_if_possible(W, slot_l_hand, del_on_fail, disable_warning, redraw_mob)) - return 1 - else if(equip_to_slot_if_possible(W, slot_r_hand, del_on_fail, disable_warning, redraw_mob)) - return 1 - return 0 + equip_to_slot_if_possible(holding, slot) //This is a SAFE proc. Use this instead of equip_to_slot()! -//set del_on_fail to have it delete W if it fails to equip +//set del_on_fail to have it delete prop if it fails to equip //set disable_warning to disable the 'you are unable to equip that' warning. //unset redraw_mob to prevent the mob from being redrawn at the end. //set force to replace items in the slot and ignore blocking overwear -/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1, force = 0) - if(!istype(W)) return 0 +/mob/proc/equip_to_slot_if_possible(obj/item/prop, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1, force = FALSE, delete_old_item = TRUE, ignore_equipped = FALSE) + if(!istype(prop) || !slot) + return FALSE + . = (can_unequip_item(prop) && can_equip_anything_to_slot(slot) && has_organ_for_slot(slot) && prop.mob_can_equip(src, slot, disable_warning, force, ignore_equipped = ignore_equipped)) + if(.) + equip_to_slot(prop, slot, redraw_mob, delete_old_item = delete_old_item) //This proc should not ever fail. + else if(del_on_fail) + qdel(prop) + else if(!disable_warning) + to_chat(src, SPAN_WARNING("You are unable to equip that.")) + +/mob/proc/can_equip_anything_to_slot(var/slot) + + // Held item slots may not have the dexterity to hold an item. + if(slot in get_held_item_slots()) + var/datum/inventory_slot/gripper/hand = get_inventory_slot_datum(slot) + // No actual held item slot, this is a bug or an error. + if(!istype(hand)) + return FALSE + // Hand is organ based, ask the organ if it has the required dexterity. + if(hand.requires_organ_tag) + var/obj/item/organ/external/hand_organ = get_organ(hand.requires_organ_tag) + if(!hand_organ || !(hand_organ.get_manual_dexterity() & DEXTERITY_HOLD_ITEM)) + return FALSE + // Hand is not organ based, ask the gripper slot directly. + else if(!(hand.get_dexterity() & DEXTERITY_HOLD_ITEM)) + return FALSE + + return (slot in get_all_available_equipment_slots()) - if(!W.mob_can_equip(src, slot, disable_warning, force)) - if(del_on_fail) - qdel(W) +//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task. +//In most cases you will want to use equip_to_slot_if_possible() +/mob/proc/equip_to_slot(obj/item/prop, slot, redraw_mob = TRUE, delete_old_item = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(!istype(prop) || isnull(slot)) + return FALSE + + // Handle some special slots. + if(slot == slot_in_backpack_str) + remove_from_mob(prop) + var/obj/item/back = get_equipped_item(slot_back_str) + if(back) + prop.forceMove(back) else - if(!disable_warning) - to_chat(src, "You are unable to equip that.")//Only print if del_on_fail is false + prop.dropInto(loc) + return TRUE + if(slot == slot_in_wallet_str) + remove_from_mob(prop) + var/obj/item/wallet = get_equipped_item(slot_wear_id_str) + if(wallet) + prop.forceMove(wallet) + else + prop.dropInto(loc) + return TRUE - return 0 + // Attempt to equip accessories if the slot is already blocked. + if(!delete_old_item && get_equipped_item(slot)) - if(!canUnEquip(W)) - return 0 + var/attached = FALSE + var/list/check_slots = get_inventory_slots() + if(islist(check_slots)) - equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail. - return 1 + check_slots = check_slots.Copy() + check_slots -= global.all_hand_slots -//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task. -//In most cases you will want to use equip_to_slot_if_possible() -/mob/proc/equip_to_slot(obj/item/W, slot) - return + check_slots -= slot + check_slots.Insert(1, slot) + + var/try_equip_slot = prop.get_fallback_slot() + if(try_equip_slot && slot != try_equip_slot) + check_slots -= try_equip_slot + check_slots.Insert(1, try_equip_slot) + + for(var/slot_string in check_slots) + var/obj/item/clothing/clothes = get_equipped_item(slot_string) + if(istype(clothes) && clothes.can_attach_accessory(prop, src)) + clothes.attach_accessory(src, prop) + attached = TRUE + break + + if(attached) + return TRUE + + unequip(prop) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(slot) + if(inv_slot) + inv_slot.equipped(src, prop, redraw_mob, delete_old_item) + if(prop.action_button_name) + update_action_buttons() + return TRUE + to_chat(src, SPAN_WARNING("You are trying to equip this item to an unsupported inventory slot. If possible, please write a ticket with steps to reproduce. Slot was: [slot]")) + return FALSE //This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such. -/mob/proc/equip_to_slot_or_del(obj/item/W, slot) - return equip_to_slot_if_possible(W, slot, 1, 1, 0) +/mob/proc/equip_to_slot_or_del(obj/item/prop, slot) + return equip_to_slot_if_possible(prop, slot, 1, 1, 0) -/mob/proc/equip_to_slot_or_store_or_drop(obj/item/W, slot) - var/store = equip_to_slot_if_possible(W, slot, 0, 1, 0) +/mob/proc/equip_to_slot_or_store_or_drop(obj/item/prop, slot) + var/store = equip_to_slot_if_possible(prop, slot, 0, 1, 0) if(!store) - return equip_to_storage_or_drop(W) + return equip_to_storage_or_drop(prop) return store -//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot. -var/list/slot_equipment_priority = list( \ - slot_back,\ - slot_wear_id,\ - slot_w_uniform,\ - slot_wear_suit,\ - slot_wear_mask,\ - slot_head,\ - slot_shoes,\ - slot_gloves,\ - slot_l_ear,\ - slot_r_ear,\ - slot_glasses,\ - slot_belt,\ - slot_s_store,\ - slot_tie,\ - slot_l_store,\ - slot_r_store\ - ) - -//Checks if a given slot can be accessed at this time, either to equip or unequip I -/mob/proc/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null) - return 1 - -//puts the item "W" into an appropriate slot in a human's inventory +//puts the item "prop" into an appropriate slot in a human's inventory //returns 0 if it cannot, 1 if successful -/mob/proc/equip_to_appropriate_slot(obj/item/W, var/skip_store = 0) - if(!istype(W)) return 0 - - for(var/slot in slot_equipment_priority) +/mob/proc/equip_to_appropriate_slot(obj/item/prop, var/skip_store = 0) + if(!istype(prop)) + return FALSE + for(var/slot in get_inventory_slot_priorities()) if(skip_store) - if(slot == slot_s_store || slot == slot_l_store || slot == slot_r_store) + if(slot == slot_s_store_str || slot == slot_l_store_str || slot == slot_r_store_str) continue - if(equip_to_slot_if_possible(W, slot, del_on_fail=0, disable_warning=1, redraw_mob=1)) - return 1 - - return 0 + if(equip_to_slot_if_possible(prop, slot, del_on_fail=0, disable_warning=1, redraw_mob=1)) + return TRUE + return FALSE /mob/proc/equip_to_storage(obj/item/newitem) // Try put it in their backpack - if(istype(src.back,/obj/item/storage)) - var/obj/item/storage/backpack = src.back - if(backpack.can_be_inserted(newitem, null, 1)) - newitem.forceMove(src.back) - return backpack + var/obj/item/back = get_equipped_item(slot_back_str) + if(back?.storage?.can_be_inserted(newitem, null, TRUE)) + back.storage.handle_item_insertion(src, newitem) + return back + + // Or in their wallet + var/obj/item/wallet = get_equipped_item(slot_wear_id_str) + if(wallet?.storage?.can_be_inserted(newitem, null, TRUE)) + wallet.storage.handle_item_insertion(src, newitem) + return wallet // Try to place it in any item that can store stuff, on the mob. - for(var/obj/item/storage/S in src.contents) - if(S.can_be_inserted(newitem, null, 1)) - newitem.forceMove(S) - return S + for(var/obj/item/thing in contents) + if(thing?.storage?.can_be_inserted(newitem, null, 1)) + thing.storage.handle_item_insertion(src, newitem) + return thing /mob/proc/equip_to_storage_or_drop(obj/item/newitem) var/stored = equip_to_storage(newitem) @@ -113,79 +156,99 @@ var/list/slot_equipment_priority = list( \ newitem.forceMove(loc) return stored +/mob/proc/equip_to_storage_or_put_in_hands(obj/item/newitem) + var/stored = equip_to_storage(newitem) + if(!stored && newitem) + put_in_hands(newitem) + return stored //These procs handle putting s tuff in your hand. It's probably best to use these rather than setting l_hand = ...etc //as they handle all relevant stuff like adding it to the player's screen and updating their overlays. //Returns the thing in our active hand -/mob/proc/get_active_hand() +/mob/proc/get_active_held_item() RETURN_TYPE(/obj/item) - if(hand) return l_hand - else return r_hand + return null + +/mob/proc/get_active_held_item_slot() + return //Returns the thing in our inactive hand -/mob/proc/get_inactive_hand() - if(hand) return r_hand - else return l_hand - -//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success. -/mob/proc/put_in_l_hand(var/obj/item/W) - if(lying || !istype(W)) - return 0 - return 1 - -//Puts the item into your r_hand if possible and calls all necessary triggers/updates. returns 1 on success. -/mob/proc/put_in_r_hand(var/obj/item/W) - if(lying || !istype(W)) - return 0 - return 1 - -//Puts the item into our active hand if possible. returns 1 on success. -/mob/proc/put_in_active_hand(var/obj/item/W) - return 0 // Moved to human procs because only they need to use hands. - -//Puts the item into our inactive hand if possible. returns 1 on success. -/mob/proc/put_in_inactive_hand(var/obj/item/W) - return 0 // As above. +/mob/proc/get_inactive_held_items() + RETURN_TYPE(/list) + return null + +/mob/proc/get_held_items() + for(var/obj/item/thing in get_inactive_held_items()) + LAZYADD(., thing) + var/obj/item/thing = get_active_held_item() + if(istype(thing)) + LAZYADD(., thing) + +/mob/proc/get_empty_hand_slot() + return + +/mob/proc/get_empty_hand_slots() + return +/mob/proc/put_in_active_hand(var/obj/item/prop) + . = equip_to_slot_if_possible(prop, get_active_held_item_slot(), disable_warning = TRUE) + +//Puts the item into (one of) our inactive hand(s) if possible. returns 1 on success. +/mob/proc/put_in_inactive_hand(var/obj/item/prop) + var/active_slot = get_active_held_item_slot() + for(var/slot in get_empty_hand_slots()) + if(slot == active_slot) + continue + . = equip_to_slot_if_possible(prop, slot, disable_warning = TRUE) + if(.) + break //Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns 1 on success. //If both fail it drops it on the floor and returns 0. //This is probably the main one you need to know :) -/mob/proc/put_in_hands(var/obj/item/W) - if(!W) - return 0 - drop_from_inventory(W) - return 0 + +/mob/proc/put_in_hands_or_del(var/obj/item/prop) + . = put_in_hands(prop) + if(!. && !QDELETED(prop)) + qdel(prop) + +/mob/proc/put_in_hands(var/obj/item/prop) + if(!prop) + return FALSE + if(put_in_active_hand(prop) || put_in_inactive_hand(prop)) + return TRUE + drop_from_inventory(prop) + return FALSE + +/mob/proc/put_in_hands_or_store_or_drop(var/obj/item/prop) + . = put_in_hands(prop) + if(!.) + . = equip_to_storage_or_drop(prop) // Removes an item from inventory and places it in the target atom. // If canremove or other conditions need to be checked then use unEquip instead. -/mob/proc/drop_from_inventory(var/obj/item/W, var/atom/target = null) - if(W) - remove_from_mob(W, target) - if(!(W && W.loc)) return 1 // self destroying objects (tk, grabs) - update_icons() - return 1 - return 0 - -//Drops the item in our left hand -/mob/proc/drop_l_hand(var/atom/Target) - return drop_from_inventory(l_hand, Target) - -//Drops the item in our right hand -/mob/proc/drop_r_hand(var/atom/Target) - return drop_from_inventory(r_hand, Target) +/mob/proc/drop_from_inventory(var/obj/item/dropping_item, var/atom/target = null, var/play_dropsound = TRUE) + if(dropping_item) + remove_from_mob(dropping_item, target, play_dropsound) + return TRUE + return FALSE + +// Drops a held item from a given slot. +/mob/proc/drop_from_slot(slot_id, atom/new_loc) + return FALSE //Drops the item in our active hand. TODO: rename this to drop_active_hand or something /mob/proc/drop_item(var/atom/Target) - if(!Target && !l_hand && !r_hand) + var/obj/item/I = get_active_held_item() + if(!istype(I)) if(length(get_active_grabs())) - for(var/obj/item/grab/grab in get_active_grabs()) + for(var/obj/item/grab/grab as anything in get_active_grabs()) qdel(grab) . = TRUE return - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable?.drop_hat(src)) - return TRUE - return hand ? drop_l_hand(Target) : drop_r_hand(Target) + return FALSE + else if(!I.mob_can_unequip(src, get_equipped_slot_for_item(I), dropping = TRUE)) + return FALSE + . = drop_from_inventory(I, Target) /* Removes the object from any slots the mob might have, calling the appropriate icon update proc. @@ -200,115 +263,257 @@ var/list/slot_equipment_priority = list( \ As far as I can tell the proc exists so that mobs with different inventory slots can override the search through all the slots, without having to duplicate the rest of the item dropping. */ -/mob/proc/u_equip(obj/W) - if (W == r_hand) - r_hand = null - update_inv_r_hand(0) - else if (W == l_hand) - l_hand = null - update_inv_l_hand(0) - else if (W == back) - back = null - update_inv_back(0) - else if (W == wear_mask) - wear_mask = null - update_inv_wear_mask(0) - return +/mob/proc/unequip(obj/prop) + SHOULD_CALL_PARENT(TRUE) + if(!istype(prop)) + return FALSE + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(get_equipped_slot_for_item(prop)) + if(inv_slot) + return inv_slot.unequipped(src, prop) + return FALSE /mob/proc/isEquipped(obj/item/I) if(!I) - return 0 - return get_inventory_slot(I) != 0 + return FALSE + return !!get_equipped_slot_for_item(I) -/mob/proc/canUnEquip(obj/item/I) +/mob/proc/can_unequip_item(obj/item/I) if(!I) //If there's nothing to drop, the drop is automatically successful. - return 1 - var/slot = get_inventory_slot(I) + return TRUE + if(I in get_organs()) + return FALSE + var/slot = get_equipped_slot_for_item(I) if(!slot && !istype(I.loc, /obj/item/rig_module)) - return 1 //already unequipped, so success + return TRUE //already unequipped, so success return I.mob_can_unequip(src, slot) -/mob/proc/get_inventory_slot(obj/item/I) - var/slot = 0 - for(var/s in slot_first to slot_last) //kind of worries me - if(get_equipped_item(s) == I) - slot = s - break - return slot - -//This differs from remove_from_mob() in that it checks if the item can be unequipped first. Use drop_from_inventory if you don't want to check. -/mob/proc/unEquip(obj/item/I, var/atom/target) - if(!canUnEquip(I)) +/// Gets the inventory slot string ID for the mob whose contents we're in, if any. +/// Checks both equipped and held item slots. +/obj/item/proc/get_any_equipped_slot() + if(!ismob(loc)) + return null + var/mob/mob = loc + return mob.get_any_equipped_slot_for_item(src) + +/// Gets the inventory slot string ID for an item that may be in our inventory. +/// Checks both equipped and held item slots. +/mob/proc/get_any_equipped_slot_for_item(obj/item/I) + var/list/slots = get_inventory_slots() + get_held_item_slots() + if(!length(slots)) return - drop_from_inventory(I, target) - return 1 - -/mob/proc/unequip_item(atom/target) - if(!canUnEquip(get_active_hand())) + for(var/slot_str in slots) + if(get_equipped_item(slot_str) == I) // slots[slot]._holding == I + return slot_str + +/// A counterpart to get_any_equipped_slot_for_item that returns the slot datum rather than the slot name. +/// Checks both equipped and held item slots. +/obj/item/proc/get_any_equipped_slot_datum() + if(!ismob(loc)) + return null + var/mob/mob = loc + return mob.get_inventory_slot_datum(mob.get_any_equipped_slot_for_item(src)) + +/// Gets the equipment (worn) slot string ID for the mob whose contents we're in, if any. Does not include held slots. +/obj/item/proc/get_equipped_slot() + if(!ismob(loc)) + return null + var/mob/mob = loc + return mob.get_equipped_slot_for_item(src) + +/// A helper that returns the slot datum rather than the slot name. +/// Does not include held slots. +/// Saves unnecessary duplicate ismob checks and loc casts. +/obj/item/proc/get_equipped_slot_datum() + if(!ismob(loc)) + return null + var/mob/mob = loc + return mob.get_inventory_slot_datum(mob.get_equipped_slot_for_item(src)) + +/// Gets the equipment (worn) slot string ID for an item we may be wearing. Does not include held slots. +/mob/proc/get_equipped_slot_for_item(obj/item/I) + var/list/slots = get_inventory_slots() + if(!length(slots)) return - drop_item(target) - return 1 + for(var/slot_str in slots) + if(get_equipped_item(slot_str) == I) // slots[slot]._holding == I + return slot_str + +/// Gets the held item slot string ID for the mob whose contents we're in, if any. Does not include worn slots. +/obj/item/proc/get_held_slot() + if(!ismob(loc)) + return null + var/mob/mob = loc + return mob.get_held_slot_for_item(src) + +/// Gets the held item slot string ID for an item we may be holding. Does not include worn slots. +/mob/proc/get_held_slot_for_item(obj/item/I) + var/list/slots = get_held_item_slots() + if(!length(slots)) + return + for(var/slot in slots) + if(get_equipped_item(slot) == I) + return slot + +/mob/proc/get_inventory_slot_datum(var/slot) + return + +//This differs from remove_from_mob() in that it checks if the item can be unequipped first. Use drop_from_inventory if you don't want to check. +/mob/proc/try_unequip(obj/item/I, var/atom/target, var/play_dropsound = TRUE) + if(!can_unequip_item(I)) + return FALSE + drop_from_inventory(I, target, play_dropsound) + return TRUE //Attemps to remove an object on a mob. -/mob/proc/remove_from_mob(var/obj/O, var/atom/target) - if(!O) // Nothing to remove, so we succeed. - return 1 - src.u_equip(O) - if (src.client) - src.client.screen -= O - O.reset_plane_and_layer() - O.screen_loc = null - if(istype(O, /obj/item)) - var/obj/item/I = O +/mob/proc/remove_from_mob(var/obj/object, var/atom/target, var/play_dropsound = TRUE) + if(!istype(object)) // Nothing to remove, so we succeed. + return TRUE + unequip(object) + if(client) + client.screen -= object + object.screen_loc = null + if(!QDELETED(object)) if(target) - I.forceMove(target) + object.forceMove(target) else - I.dropInto(loc) - I.dropped(src) - return 1 - + object.dropInto(loc) + object.reset_plane_and_layer() // this should be done post-move to avoid wasting an icon update + if(isitem(object)) + var/obj/item/item = object + item.dropped(src, play_dropsound) + if(!QDELETED(object)) // dropped might qdelete us + object.compile_overlays() // avoid world overlays on inventory state and vice versa + return TRUE + +/mob/proc/drop_held_items(drop_loc = loc) + for(var/thing in get_held_items()) + try_unequip(thing, drop_loc) //Returns the item equipped to the specified slot, if any. /mob/proc/get_equipped_item(var/slot) - switch(slot) - if(slot_l_hand) return l_hand - if(slot_r_hand) return r_hand - if(slot_back) return back - if(slot_wear_mask) return wear_mask - return null + SHOULD_CALL_PARENT(TRUE) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(slot) + return inv_slot?.get_equipped_item() /mob/proc/get_equipped_items(var/include_carried = 0) - . = list() - if(back) . += back - if(wear_mask) . += wear_mask - - if(include_carried) - if(l_hand) . += l_hand - if(r_hand) . += r_hand + SHOULD_CALL_PARENT(TRUE) + var/held_item_slots = get_held_item_slots() + for(var/slot in get_inventory_slots()) + var/obj/item/thing = get_equipped_item(slot) + if(istype(thing)) + if(!include_carried && (slot in held_item_slots)) + continue + LAZYADD(., thing) /mob/proc/delete_inventory(var/include_carried = FALSE) for(var/entry in get_equipped_items(include_carried)) drop_from_inventory(entry) qdel(entry) +/mob/proc/has_organ_for_slot(slot) + if(slot in global.abstract_inventory_slots) + return TRUE + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(slot) + if(inv_slot) + return !!inv_slot.check_has_required_organ(src) + return has_organ(slot) + // Returns all currently covered body parts /mob/proc/get_covered_body_parts() . = 0 - for(var/entry in get_equipped_items()) - var/obj/item/I = entry + for(var/obj/item/I as anything in get_equipped_items()) . |= I.body_parts_covered // Returns the first item which covers any given body part /mob/proc/get_covering_equipped_item(var/body_parts) - for(var/entry in get_equipped_items()) - var/obj/item/I = entry + if(!isnum(body_parts)) + return null + for(var/obj/item/I as anything in get_equipped_items()) if(I.body_parts_covered & body_parts) return I // Returns all items which covers any given body part /mob/proc/get_covering_equipped_items(var/body_parts) . = list() - for(var/entry in get_equipped_items()) - var/obj/item/I = entry + for(var/obj/item/I as anything in get_equipped_items()) if(I.body_parts_covered & body_parts) . += I + +// Returns the first item which covers all specified body parts. +/mob/proc/get_covering_equipped_item_exact(var/body_parts) + if(!isnum(body_parts)) + return null + for(var/obj/item/I as anything in get_equipped_items()) + if((I.body_parts_covered & body_parts) == body_parts) + return I + +// Returns all items which cover all specified body parts. +/mob/proc/get_covering_equipped_items_exact(var/body_parts) + . = list() + for(var/obj/item/I as anything in get_equipped_items()) + if((I.body_parts_covered & body_parts) == body_parts) + . += I + +/mob/proc/has_held_item_slot() + return !!length(get_held_item_slots()) + +/mob/proc/is_holding_offhand(var/thing) + return FALSE + +/mob/proc/can_be_buckled(var/mob/user) + . = user.Adjacent(src) && !ispAI(user) + +/// If this proc returns false, reconsider_client_screen_presence will set the item's screen_loc to null. +/mob/proc/item_should_have_screen_presence(obj/item/item, slot) + if(!slot || !istype(hud_used)) + return FALSE + if(hud_used.is_inventory_shown()) + return TRUE + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(slot) + return !(inv_slot?.can_be_hidden) + +/mob/proc/get_held_item_slots() + return + +/mob/proc/add_held_item_slot(var/datum/inventory_slot/held_slot) + return + +/mob/proc/remove_held_item_slot(var/slot) + return + +/mob/proc/select_held_item_slot(var/slot) + SHOULD_CALL_PARENT(TRUE) + clear_available_intents() + +/mob/proc/get_inventory_slots() + return + +/mob/proc/get_inventory_slot_priorities() + return + +/mob/proc/set_inventory_slots(var/list/new_slots) + return + +/mob/proc/add_inventory_slot() + return + +/mob/proc/remove_inventory_slot(var/slot) + return + +/mob/proc/get_all_available_equipment_slots() + for(var/slot in get_held_item_slots()) + LAZYDISTINCTADD(., slot) + for(var/slot in get_inventory_slots()) + LAZYDISTINCTADD(., slot) + +/mob/proc/get_hands_organs() + for(var/hand_slot in get_held_item_slots()) + var/org = GET_EXTERNAL_ORGAN(src, hand_slot) + if(org) + LAZYDISTINCTADD(., org) + +/mob/proc/get_active_hand_bodypart_flags() + var/datum/inventory_slot/gripper/inv_slot = get_inventory_slot_datum(get_active_held_item_slot()) + if(istype(inv_slot)) + . = inv_slot.covering_slot_flags + . ||= SLOT_HANDS diff --git a/code/modules/mob/language/alien/antag.dm b/code/modules/mob/language/alien/antag.dm index e5007ecb5bb8..58a574c10acb 100644 --- a/code/modules/mob/language/alien/antag.dm +++ b/code/modules/mob/language/alien/antag.dm @@ -1,20 +1,3 @@ -/decl/language/ling - name = "Changeling" - desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." - speech_verb = "says" - colour = "changeling" - key = "g" - flags = RESTRICTED | HIVEMIND - shorthand = "N/A" - hidden_from_codex = TRUE - -/decl/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) - - if(speaker.mind && speaker.mind.changeling) - ..(speaker,message,speaker.mind.changeling.changelingID) - else - ..(speaker,message) - /decl/language/cultcommon name = "Cult" desc = "The chants of the occult, the incomprehensible." @@ -23,7 +6,7 @@ exclaim_verb = "chants" colour = "cult" key = "f" - flags = RESTRICTED + flags = LANG_FLAG_RESTRICTED space_chance = 100 syllables = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri", \ "orkan", "allaq", "sas'so", "c'arta", "forbici", "tarem", "n'ath", "reth", "sh'yro", "eth", "d'raggathnor", \ @@ -44,7 +27,7 @@ exclaim_verb = "chants" colour = "cult" key = "y" - flags = RESTRICTED | HIVEMIND + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_HIVEMIND shorthand = "N/A" hidden_from_codex = TRUE @@ -53,7 +36,7 @@ colour = "cult" speech_verb = "hisses" key = "c" - flags = RESTRICTED + flags = LANG_FLAG_RESTRICTED syllables = list("qy","bok","mok","yok","dy","gly","ryl","byl","dok","forbici", "tarem", "n'ath", "reth", "sh'yro", "eth", "d'raggathnor","niii", "d'rekkathnor", "khari'd", "gual'te", "ki","ki","ki","ki","ya","ta","wej","nym","assah","qwssa","nieasl","qyno","shaffar", "eg","bog","voijs","nekks","bollos","qoulsan","borrksakja","neemen","aka","nikka","qyegno","shafra","beolas","Byno") @@ -61,13 +44,13 @@ shorthand = "AL" hidden_from_codex = TRUE -/decl/language/alium/New() +/decl/language/alium/Initialize() + . = ..() speech_verb = pick("hisses","growls","whistles","blubbers","chirps","skreeches","rumbles","clicks") - ..() -/decl/language/alium/get_random_name() +/decl/language/alium/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) var/new_name = "" - var/length = rand(1,3) - for(var/i=0 to length) + var/name_length = rand(1,3) + for(var/i=0 to name_length) new_name += pick(syllables) return capitalize(new_name) \ No newline at end of file diff --git a/code/modules/mob/language/alien/monkey.dm b/code/modules/mob/language/alien/monkey.dm index 4e9c4da33125..9c6d6727c444 100644 --- a/code/modules/mob/language/alien/monkey.dm +++ b/code/modules/mob/language/alien/monkey.dm @@ -5,6 +5,7 @@ ask_verb = "chimpers" exclaim_verb = "screeches" key = "" + flags = LANG_FLAG_RESTRICTED syllables = list("ook", "eek", "hiss", "gronk") shorthand = "Ook" hidden_from_codex = 1 diff --git a/code/modules/mob/language/animal.dm b/code/modules/mob/language/animal.dm new file mode 100644 index 000000000000..e1318a473fe3 --- /dev/null +++ b/code/modules/mob/language/animal.dm @@ -0,0 +1,34 @@ +/decl/language/animal + name = "Animal Noises" // translate them! + desc = "Some varieties of animal can communicate amongst themselves, apparently." + colour = "say_quote" + key = "a" + shorthand = "A" + hidden_from_codex = TRUE + +/decl/language/animal/can_be_understood_by(var/mob/living/speaker, var/mob/living/listener) + if(!istype(listener) || listener.universal_understand || listener.universal_speak) + return TRUE + if(!istype(speaker) || speaker.universal_speak) + return TRUE + if(istype(speaker, listener.type) || istype(listener, speaker.type)) + return TRUE + if(isanimal(speaker)) + var/mob/living/simple_animal/critter = speaker + if(istype(listener, critter.base_animal_type)) + return TRUE + if(isanimal(listener)) + var/mob/living/simple_animal/critter = listener + if(istype(speaker, critter.base_animal_type)) + return TRUE + return FALSE + +/decl/language/animal/scramble(mob/living/speaker, input, list/known_languages) + if(istype(speaker.ai) && length(speaker.ai.emote_speech)) + return DEFAULTPICK(speaker.ai.emote_speech, "...") + return "..." + +/decl/language/animal/get_spoken_verb(mob/living/speaker, msg_end) + if(istype(speaker) && length(speaker.speak_emote)) + return pick(speaker.speak_emote) + . = ..() diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm index 7b1774a777b1..1665c0b215c2 100644 --- a/code/modules/mob/language/generic.dm +++ b/code/modules/mob/language/generic.dm @@ -3,8 +3,8 @@ name = "Noise" desc = "Noises" key = "" - flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER - hidden_from_codex = 1 + flags = LANG_FLAG_RESTRICTED|LANG_FLAG_NONGLOBAL|LANG_FLAG_INNATE|LANG_FLAG_NO_TALK_MSG|LANG_FLAG_NO_STUTTER + hidden_from_codex = TRUE /decl/language/noise/format_message(message, verb) return "[message]" @@ -21,9 +21,10 @@ /decl/language/sign name = "Sign Language" - desc = "A sign language commonly used for those who are deaf or mute." + desc = "In an age of commonplace extra-vehicular activity and habitation of airless worlds, \ + sign language is often an essential communication tool for large portions of the population." signlang_verb = list("gestures") colour = "say_quote" key = "s" - flags = SIGNLANG | NO_STUTTER | NONVERBAL - shorthand = "HS" \ No newline at end of file + flags = LANG_FLAG_SIGNLANG | LANG_FLAG_NO_STUTTER | LANG_FLAG_NONVERBAL + shorthand = "HS" diff --git a/code/modules/mob/language/human/human.dm b/code/modules/mob/language/human/human.dm index 24fbbfdb046b..867b9adccbd4 100644 --- a/code/modules/mob/language/human/human.dm +++ b/code/modules/mob/language/human/human.dm @@ -5,12 +5,12 @@ speech_verb = "says" whisper_verb = "whispers" colour = "solcom" - flags = WHITELISTED + flags = LANG_FLAG_WHITELISTED | LANG_FLAG_RESTRICTED shorthand = "???" space_chance = 40 - category = /decl/language/human + abstract_type = /decl/language/human -/decl/language/human/get_spoken_verb(var/msg_end) +/decl/language/human/get_spoken_verb(mob/living/speaker, msg_end) switch(msg_end) if("!") return pick("exclaims","shouts","yells") @@ -18,14 +18,12 @@ return ask_verb return speech_verb -/decl/language/human/get_random_name(var/gender) +/decl/language/human/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) if (prob(80)) if(gender==FEMALE) - return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - else - return ..() + return capitalize(pick(global.using_map.first_names_female)) + " " + capitalize(pick(global.using_map.last_names)) + return capitalize(pick(global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) + return ..() /*////////////////////////////////////////////////////////////////////////////////////////////////////// Syllable list compiled in this file based on work by Stefan Trost, available at the following URLs @@ -41,7 +39,7 @@ whisper_verb = "whispers" colour = "" key = "1" - flags = WHITELISTED + flags = LANG_FLAG_WHITELISTED shorthand = "C" partial_understanding = list() syllables = list( diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm index 9038c867f3c0..1c7008ad9e63 100644 --- a/code/modules/mob/language/language.dm +++ b/code/modules/mob/language/language.dm @@ -4,55 +4,86 @@ Datum based languages. Easily editable and modular. */ +/* Current unused keys, please update when you use one. + * e + * n + * r + * t + * w +*/ /decl/language - var/name // Fluff name of language if any. - var/desc = "You should not have this language." // Short description for 'Check Languages'. - var/speech_verb = "says" // 'says', 'hisses', 'farts'. - var/ask_verb = "asks" // Used when sentence ends in a ? - var/exclaim_verb = "exclaims" // Used when sentence ends in a ! - var/whisper_verb // Optional. When not specified speech_verb + quietly/softly is used instead. - var/signlang_verb = list("signs", "gestures") // list of emotes that might be displayed if this language has NONVERBAL or SIGNLANG flags - var/colour = "body" // CSS style to use for strings in this language. - var/key = "" // Character used to speak in language - var/flags = 0 // Various language flags. - var/native // If set, non-native speakers will have trouble speaking. - var/list/syllables // Used when scrambling text for a non-speaker. - var/list/space_chance = 55 // Likelihood of getting a space in the random scramble string - var/machine_understands = 1 // Whether machines can parse and understand this language - var/shorthand = "???" // Shorthand that shows up in chat for this language. - var/list/partial_understanding // List of languages that can /somehwat/ understand it, format is: name = chance of understanding a word - var/warning = "" - var/hidden_from_codex // If it should not show up in Codex - var/category = /decl/language // Used to point at root language types that shouldn't be visible + abstract_type = /decl/language // Used to point at root language types that shouldn't be visible + + // Short description for 'Check Languages'. + var/desc = "You should not have this language." + // list of emotes that might be displayed if this language has LANG_FLAG_NONVERBAL or LANG_FLAG_SIGNLANG flags + var/signlang_verb = list("signs", "gestures") + + var/name // Fluff name of language if any. + var/speech_verb = "says" // 'says', 'hisses', 'farts'. + var/ask_verb = "asks" // Used when sentence ends in a ? + var/exclaim_verb = "exclaims" // Used when sentence ends in a ! + var/whisper_verb // Optional. When not specified speech_verb + quietly/softly is used instead. + var/colour = "body" // CSS style to use for strings in this language. + var/key = "" // Character used to speak in language + var/flags = 0 // Various language flags. + /// Syllable list when scrambling text for display to a non-speaker. + var/list/syllables + /// Likelihood of getting a space in the random scramble string + var/space_chance = 55 + /// Whether machines can parse and understand this language + var/machine_understands = TRUE + /// Shorthand that shows up in chat for this language. + var/shorthand = "???" + /// List of languages that can /somehwat/ understand it, format is: typepath = chance of understanding a word + var/list/partial_understanding + /// If it should not show up in Codex + var/hidden_from_codex = FALSE + /// Cached syllable strings for masking when heard by a non-speaker + var/list/scramble_cache = list() + /// List of sounds to randomly play. + var/list/speech_sounds + /// Control for handling some of the random lang/name gen. + var/allow_repeated_syllables = TRUE + +/decl/language/proc/can_be_understood_by(var/mob/living/speaker, var/mob/living/listener) + if(flags & LANG_FLAG_INNATE) + return TRUE + for(var/decl/language/L in listener.languages) + if(name == L.name) + return TRUE + return FALSE + +/decl/language/proc/get_spoken_sound() + if(speech_sounds) + var/list/result[2] + result[1] = pick(speech_sounds) + result[2] = 40 + return result /decl/language/proc/can_be_spoken_properly_by(var/mob/speaker) - return TRUE + return SPEECH_RESULT_GOOD /decl/language/proc/muddle(var/message) return message -/decl/language/proc/get_random_name(var/gender, name_count=2, syllable_count=4, syllable_divisor=2) - if(!syllables || !syllables.len) +/decl/language/proc/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + if(!length(syllables)) if(gender==FEMALE) - return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - - var/full_name = "" - var/new_name = "" + return capitalize(pick(global.using_map.first_names_female)) + " " + capitalize(pick(global.using_map.last_names)) + return capitalize(pick(global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) - for(var/i = 0;i0;x--) - new_name += pick(syllables) - full_name += " [capitalize(lowertext(new_name))]" - - return "[trim(full_name)]" - -/decl/language - var/list/scramble_cache = list() + var/possible_syllables = allow_repeated_syllables ? syllables : syllables.Copy() + for(var/i in 1 to name_count) + var/new_name = "" + for(var/x in rand(floor(syllable_count/syllable_divisor), syllable_count) to 1 step -1) + if(!length(possible_syllables)) + break + new_name += allow_repeated_syllables ? pick(possible_syllables) : pick_n_take(possible_syllables) + LAZYADD(., capitalize(lowertext(new_name))) + . = "[trim(jointext(., " "))]" -/decl/language/proc/scramble(var/input, var/list/known_languages) +/decl/language/proc/scramble(mob/living/speaker, input, list/known_languages) var/understand_chance = 0 for(var/decl/language/L in known_languages) @@ -69,7 +100,7 @@ if(!prob(understand_chance)) nword = scramble_word(w) if(new_sentence) - nword = capitalize(nword) + nword = capitalize_proper_html(nword) new_sentence = FALSE if(ends_sentence) nword = trim(nword) @@ -81,11 +112,16 @@ scrambled_text += nword . = jointext(scrambled_text, null) - . = capitalize(.) + . = capitalize_proper_html(.) . = trim(.) +/decl/language/proc/get_next_scramble_token() + if(length(syllables)) + return pick(syllables) + return "..." + /decl/language/proc/scramble_word(var/input) - if(!syllables || !syllables.len) + if(!LAZYLEN(syllables)) return stars(input) // If the input is cached already, move it to the end of the cache and return it @@ -100,7 +136,7 @@ var/capitalize = 0 while(length(scrambled_text) < input_size) - var/next = pick(syllables) + var/next = get_next_scramble_token() if(capitalize) next = capitalize(next) capitalize = 0 @@ -109,14 +145,14 @@ if(chance <= 5) scrambled_text += ". " capitalize = 1 - else if(chance > 5 && chance <= space_chance) + else if(chance <= space_chance) scrambled_text += " " // Add it to cache, cutting old entries if the list is too long scramble_cache[input] = scrambled_text if(scramble_cache.len > SCRAMBLE_CACHE_LEN) scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) - + return scrambled_text /decl/language/proc/format_message(message, verb) @@ -136,9 +172,8 @@ log_say("[key_name(speaker)] : ([name]) [message]") if(!speaker_mask) speaker_mask = speaker.name - message = format_message(message, get_spoken_verb(message)) - - for(var/mob/player in GLOB.player_list) + message = format_message(message, get_spoken_verb(speaker, message)) + for(var/mob/player in global.player_list) player.hear_broadcast(src, speaker, speaker_mask, message) /mob/proc/hear_broadcast(var/decl/language/language, var/mob/speaker, var/speaker_name, var/message) @@ -158,7 +193,7 @@ /decl/language/proc/check_special_condition(var/mob/other) return 1 -/decl/language/proc/get_spoken_verb(var/msg_end) +/decl/language/proc/get_spoken_verb(mob/living/speaker, msg_end) switch(msg_end) if("!") return exclaim_verb @@ -171,19 +206,19 @@ // Language handling. /mob/proc/add_language(var/language) - var/decl/language/new_language = decls_repository.get_decl(language) + var/decl/language/new_language = GET_DECL(language) if(!istype(new_language) || (new_language in languages)) return 0 languages.Add(new_language) return 1 /mob/proc/remove_language(var/rem_language) - var/decl/language/L = decls_repository.get_decl(rem_language) + var/decl/language/L = GET_DECL(rem_language) . = (L in languages) languages.Remove(L) /mob/living/remove_language(rem_language) - var/decl/language/L = decls_repository.get_decl(rem_language) + var/decl/language/L = GET_DECL(rem_language) if(default_language == L) default_language = null return ..() @@ -193,10 +228,16 @@ if(!speaking) return 0 - if (only_species_language && speaking != decls_repository.get_decl(species_language)) + if (only_species_language && speaking != GET_DECL(species_language)) return 0 - return (speaking.can_speak_special(src) && (universal_speak || (speaking && speaking.flags & INNATE) || (speaking in src.languages))) + return (speaking.can_speak_special(src) && (universal_speak || (speaking && speaking.flags & LANG_FLAG_INNATE) || (speaking in src.languages))) + +/mob/proc/get_common_radio_prefix() + return get_prefix_key(/decl/prefix/radio_main_channel) + +/mob/proc/get_department_radio_prefix() + return get_prefix_key(/decl/prefix/radio_channel_selection) /mob/proc/get_language_prefix() return get_prefix_key(/decl/prefix/language) @@ -213,7 +254,7 @@ var/dat = "Known Languages

          " for(var/decl/language/L in languages) - if(!(L.flags & NONGLOBAL)) + if(!(L.flags & LANG_FLAG_NONGLOBAL)) dat += "[L.name]([L.shorthand]) ([get_language_prefix()][L.key])
          [L.desc]

          " show_browser(src, dat, "window=checklanguage") @@ -223,11 +264,11 @@ var/dat = "Known Languages

          " if(default_language) - var/decl/language/lang = decls_repository.get_decl(default_language) + var/decl/language/lang = GET_DECL(default_language) dat += "Current default language: [lang.name] - reset

          " for(var/decl/language/L in languages) - if(!(L.flags & NONGLOBAL)) + if(!(L.flags & LANG_FLAG_NONGLOBAL)) if(L == default_language) dat += "[L.name]([L.shorthand]) ([get_language_prefix()][L.key]) - default - reset
          [L.desc]

          " else if (can_speak(L)) @@ -254,10 +295,15 @@ return TOPIC_HANDLED return ..() -/proc/transfer_languages(var/mob/source, var/mob/target, var/except_flags) - for(var/decl/language/L in source.languages) - if(L.flags & except_flags) +/mob/proc/copy_languages_to(mob/target, except_flags) + for(var/decl/language/new_lang in languages) + if(new_lang.flags & except_flags) continue - target.add_language(L.name) + target.add_language(new_lang.type) + +/mob/living/copy_languages_to(mob/living/target, except_flags) + ..() + if(isliving(target)) + target.default_language = default_language #undef SCRAMBLE_CACHE_LEN \ No newline at end of file diff --git a/code/modules/mob/language/synthetic.dm b/code/modules/mob/language/synthetic.dm index 0c4d6a85e4cf..ffcc87c400cd 100644 --- a/code/modules/mob/language/synthetic.dm +++ b/code/modules/mob/language/synthetic.dm @@ -1,3 +1,26 @@ +/decl/language/machine + name = "Encoded Audio Language" + shorthand = "EAL" + desc = "An efficient language of encoded tones used by synthetics." + speech_verb = "whistles" + ask_verb = "chirps" + exclaim_verb = "whistles loudly" + colour = "mutant" + key = "6" + flags = LANG_FLAG_NO_STUTTER + syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz") + space_chance = 10 + speech_sounds = list( + 'sound/voice/eal/eal1.ogg', + 'sound/voice/eal/eal2.ogg', + 'sound/voice/eal/eal3.ogg', + 'sound/voice/eal/eal4.ogg', + 'sound/voice/eal/eal5.ogg', + 'sound/voice/eal/eal6.ogg', + 'sound/voice/eal/eal7.ogg', + 'sound/voice/eal/eal8.ogg' + ) + /decl/language/binary name = "Robot Talk" desc = "Most human facilities support free-use communications protocols and routing hubs for synthetic use." @@ -6,7 +29,7 @@ ask_verb = "queries" exclaim_verb = "declares" key = "b" - flags = RESTRICTED | HIVEMIND + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_HIVEMIND shorthand = "N/A" var/drone_only @@ -21,17 +44,17 @@ var/message_start = "[name], [speaker.name]" var/message_body = "[speaker.say_quote(message)], \"[message]\"" - for (var/mob/observer/ghost/O in GLOB.ghost_mob_list) + for (var/mob/observer/ghost/O in global.ghost_mob_list) O.show_message("[message_start] ([ghost_follow_link(speaker, O)]) [message_body]", 2) - for (var/mob/M in GLOB.dead_mob_list_) - if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping + for (var/mob/M in global.dead_mob_list_) + if(!isnewplayer(M) && !isbrain(M)) //No meta-evesdropping M.show_message("[message_start] ([ghost_follow_link(speaker, M)]) [message_body]", 2) - for (var/mob/living/S in GLOB.living_mob_list_) - if(drone_only && !istype(S,/mob/living/silicon/robot/drone)) + for (var/mob/living/S in global.living_mob_list_) + if(drone_only && !isdrone(S)) continue - else if(istype(S , /mob/living/silicon/ai)) + else if(isAI(S)) message_start = "[name], [speaker.name]" else if (!S.binarycheck()) continue @@ -42,15 +65,15 @@ listening -= src for (var/mob/living/M in listening) - if(istype(M, /mob/living/silicon) || M.binarycheck()) + if(issilicon(M) || M.binarycheck()) continue M.show_message("synthesised voice beeps, \"beep beep beep\"",2) //robot binary xmitter component power usage if (isrobot(speaker)) - var/mob/living/silicon/robot/R = speaker - var/datum/robot_component/C = R.components["comms"] - R.cell_use_power(C.active_usage) + var/mob/living/silicon/robot/robot = speaker + var/datum/robot_component/C = robot.components["comms"] + robot.cell_use_power(C.active_usage) /decl/language/binary/drone name = "Drone Talk" @@ -60,6 +83,6 @@ exclaim_verb = "transmits" colour = "say_quote" key = "d" - flags = RESTRICTED | HIVEMIND + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_HIVEMIND drone_only = 1 shorthand = "N/A" diff --git a/code/modules/mob/living/autohiss.dm b/code/modules/mob/living/autohiss.dm index 3aeb52415cb1..9c66c132c1db 100644 --- a/code/modules/mob/living/autohiss.dm +++ b/code/modules/mob/living/autohiss.dm @@ -4,35 +4,37 @@ /mob/living/proc/handle_autohiss(message, decl/language/L) return message // no autohiss at this level -/mob/living/carbon/human/handle_autohiss(message, decl/language/L) - if(!client || get_preference_value(/datum/client_preference/autohiss) == GLOB.PREF_OFF) // no need to process if there's no client or they have autohiss off +/mob/living/human/handle_autohiss(message, decl/language/L) + if(!client || get_preference_value(/datum/client_preference/autohiss) == PREF_OFF) // no need to process if there's no client or they have autohiss off return message return species.handle_autohiss(message, L, get_preference_value(/datum/client_preference/autohiss)) -/datum/species +/decl/species var/list/autohiss_basic_map = null var/list/autohiss_extra_map = null var/list/autohiss_exempt = null -/datum/species/proc/handle_autohiss(message, decl/language/lang, mode) +/decl/species/proc/get_autohiss_map(var/mode) + . = autohiss_basic_map?.Copy() || list() + if(mode == PREF_FULL && autohiss_extra_map) + . |= autohiss_extra_map + +/decl/species/proc/handle_autohiss(message, decl/language/lang, mode) if(!autohiss_basic_map) return message - if(lang.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing + if(lang.flags & LANG_FLAG_NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing return message if(autohiss_exempt && (lang.name in autohiss_exempt)) return message - var/map = autohiss_basic_map.Copy() - if(mode == GLOB.PREF_FULL && autohiss_extra_map) - map |= autohiss_extra_map - + var/map = get_autohiss_map(mode) . = list() while(length(message)) var/min_index = 10000 // if the message is longer than this, the autohiss is the least of your problems var/min_char = null for(var/char in map) - var/i = findtext(message, char) + var/i = findtext_char(message, char) if(!i) // no more of this character anywhere in the string, don't even bother searching next time map -= char else if(i < min_index) @@ -41,8 +43,8 @@ if(!min_char) // we didn't find any of the mapping characters . += message break - . += copytext(message, 1, min_index) - if(copytext(message, min_index, min_index+1) == uppertext(min_char)) + . += copytext_char(message, 1, min_index) + if(copytext_char(message, min_index, min_index+1) == uppertext(min_char)) switch(text2ascii(message, min_index+1)) if(65 to 90) // A-Z, uppercase; uppercase R/S followed by another uppercase letter, uppercase the entire replacement string . += uppertext(pick(map[min_char])) @@ -50,6 +52,6 @@ . += capitalize(pick(map[min_char])) else . += pick(map[min_char]) - message = copytext(message, min_index + 1) + message = copytext_char(message, min_index + 1) return jointext(., null) \ No newline at end of file diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index a81ab6687b3f..e139e0d1ba71 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -1,17 +1,10 @@ /mob/living/bot name = "Bot" - health = 20 - maxHealth = 20 + max_health = 20 icon = 'icons/mob/bot/placeholder.dmi' universal_speak = TRUE - density = 0 - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 + density = FALSE + butchery_data = null var/obj/item/card/id/botcard = null var/list/botcard_access = list() @@ -22,6 +15,7 @@ var/light_strength = 3 var/busy = 0 + // Dummy object used to hold bot access strings. TODO: just put it on the mob. var/obj/access_scanner = null var/list/req_access = list() @@ -40,7 +34,6 @@ var/max_patrol_dist = 250 var/RequiresAccessToToggle = 0 // If 1, will check access to be turned on/off - var/target_patience = 5 var/frustration = 0 var/max_frustration = 0 @@ -48,7 +41,9 @@ /mob/living/bot/Initialize() . = ..() - update_icons() + update_icon() + add_language(/decl/language/human/common) + set_default_language(GET_DECL(/decl/language/human/common)) botcard = new /obj/item/card/id(src) botcard.access = botcard_access?.Copy() @@ -56,74 +51,88 @@ access_scanner = new /obj(src) access_scanner.req_access = req_access?.Copy() -/mob/living/bot/Initialize() - . = ..() if(on) turn_on() // Update lights and other stuff else turn_off() -/mob/living/bot/Life() - ..() - if(health <= 0) - death() - return - weakened = 0 - stunned = 0 - paralysis = 0 +/mob/living/bot/handle_regular_status_updates() + . = ..() + if(.) + set_status_condition(STAT_WEAK, 0) + set_status_condition(STAT_STUN, 0) + set_status_condition(STAT_PARA, 0) + +/mob/living/bot/get_life_damage_types() + var/static/list/life_damage_types = list( + BURN, + BRUTE + ) + return life_damage_types + +/mob/living/bot/get_dusted_remains() + return /obj/effect/decal/cleanable/blood/oil + +/mob/living/bot/gib(do_gibs = TRUE) + if(stat != DEAD) + death(gibbed = TRUE) + if(stat == DEAD) + turn_off() + visible_message(SPAN_DANGER("\The [src] blows apart!")) + spark_at(src, cardinal_only = TRUE) + return ..() - if(on && !client && !busy) - handleAI() +/mob/living/bot/death(gibbed) + . = ..() + if(. && !gibbed) + gib() -/mob/living/bot/updatehealth() - if(status_flags & GODMODE) - health = maxHealth - set_stat(CONSCIOUS) - else - health = maxHealth - getFireLoss() - getBruteLoss() - setOxyLoss(0) - setToxLoss(0) +/mob/living/bot/ssd_check() + return FALSE -/mob/living/bot/death() - explode() +/mob/living/bot/try_awaken(mob/user) + return FALSE -/mob/living/bot/attackby(var/obj/item/O, var/mob/user) - if(O.GetIdCard()) +/mob/living/bot/attackby(var/obj/item/used_item, var/mob/user) + if(used_item.GetIdCard()) if(access_scanner.allowed(user) && !open) locked = !locked to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]") - Interact(usr) + Interact(user) else if(open) to_chat(user, "Please close the access panel before locking it.") else to_chat(user, "Access denied.") - return - else if(isScrewdriver(O)) + return TRUE + else if(IS_SCREWDRIVER(used_item)) if(!locked) open = !open to_chat(user, "Maintenance panel is now [open ? "opened" : "closed"].") - Interact(usr) + Interact(user) else to_chat(user, "You need to unlock the controls first.") - return - else if(isWelder(O)) - if(health < maxHealth) + return TRUE + else if(IS_WELDER(used_item)) + if(current_health < get_max_health()) if(open) - health = min(maxHealth, health + 10) + heal_overall_damage(10) user.visible_message("\The [user] repairs \the [src].","You repair \the [src].") else to_chat(user, "Unable to repair with the maintenance panel closed.") else to_chat(user, "\The [src] does not need a repair.") - return + return TRUE else - ..() + return ..() -/mob/living/bot/attack_ai(var/mob/user) +/mob/living/bot/attack_ai(var/mob/living/user) Interact(user) -/mob/living/bot/attack_hand(var/mob/user) - Interact(user) +/mob/living/bot/default_interaction(mob/user) + . = ..() + if(!.) + Interact(user) + return TRUE /mob/living/bot/proc/Interact(var/mob/user) add_fingerprint(user) @@ -153,7 +162,7 @@ popup.open() /mob/living/bot/DefaultTopicState() - return GLOB.default_state + return global.default_topic_state /mob/living/bot/OnTopic(mob/user, href_list) if(href_list["command"]) @@ -164,7 +173,7 @@ return /mob/living/bot/proc/GetInteractStatus() - . = "Status: [on ? "On" : "Off"]" + . = "Status: [on ? "On" : "Off"]" . += "
          Behaviour controls are [locked ? "locked" : "unlocked"]" . += "
          Maintenance panel is [open ? "opened" : "closed"]" @@ -209,7 +218,12 @@ /mob/living/bot/emag_act(var/remaining_charges, var/mob/user) return 0 -/mob/living/bot/proc/handleAI() +/mob/living/bot/handle_living_non_stasis_processes() + . = ..() + if(!key && on && !busy) + handle_async_ai() + +/mob/living/bot/proc/handle_async_ai() set waitfor = FALSE if(ignore_list.len) for(var/atom/A in ignore_list) @@ -231,7 +245,7 @@ resetTarget() lookForTargets() if(will_patrol && !LAZYLEN(grabbed_by) && !target) - if(patrol_path && patrol_path.len) + if(length(patrol_path)) for(var/i = 1 to patrol_speed) sleep(20 / (patrol_speed + 1)) handlePatrol() @@ -255,7 +269,7 @@ if(!target || !target.loc) return if(get_dist(src, target) > min_target_dist) - if(!target_path.len || get_turf(target) != target_path[target_path.len]) + if(!length(target_path) || get_turf(target) != target_path[target_path.len]) calcTargetPath() if(makeStep(target_path)) frustration = 0 @@ -272,12 +286,12 @@ /mob/living/bot/proc/lookForTargets() return -/mob/living/bot/proc/confirmTarget(var/atom/A) - if(A.invisibility >= INVISIBILITY_LEVEL_ONE) +/mob/living/bot/proc/confirmTarget(atom/target) + if(target.invisibility >= INVISIBILITY_LEVEL_ONE) return 0 - if(A in ignore_list) + if(target in ignore_list) return 0 - if(!A.loc) + if(!target.loc) return 0 return 1 @@ -286,9 +300,9 @@ return /mob/living/bot/proc/startPatrol() - var/turf/T = getPatrolTurf() - if(T) - patrol_path = AStar(get_turf(loc), T, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_patrol_dist, id = botcard, exclude = obstacle) + var/turf/target_turf = getPatrolTurf() + if(target_turf) + patrol_path = SSpathfinding.find_path_immediate(start = get_turf(loc), end = target_turf, max_node_depth = max_patrol_dist, id = botcard, exclude = obstacle, check_tick = TRUE) if(!patrol_path) patrol_path = list() obstacle = null @@ -320,23 +334,22 @@ return /mob/living/bot/proc/calcTargetPath() - target_path = AStar(get_turf(loc), get_turf(target), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard, exclude = obstacle) - if(!target_path) - if(target && target.loc) - ignore_list |= target - resetTarget() - obstacle = null - return + target_path = SSpathfinding.find_path_immediate(start = get_turf(loc), end = get_turf(target), max_node_depth = max_target_dist, min_target_dist = min_target_dist, id = botcard, exclude = obstacle, check_tick = TRUE) + if(length(target_path)) + return + if(target?.loc) + ignore_list |= target + resetTarget() + obstacle = null /mob/living/bot/proc/makeStep(var/list/path) - if(!path.len) - return 0 - var/turf/T = path[1] - if(get_turf(src) == T) - path -= T + if(!length(path)) + return FALSE + var/turf/target_turf = path[1] + if(get_turf(src) == target_turf) + path -= target_turf return makeStep(path) - - return step_towards(src, T) + return step_towards(src, target_turf) /mob/living/bot/proc/resetTarget() target = null @@ -348,8 +361,8 @@ if(stat) return 0 on = 1 - set_light(0.5, 0.1, light_strength) - update_icons() + set_light(light_strength) + update_icon() resetTarget() patrol_path = list() ignore_list = list() @@ -358,74 +371,23 @@ /mob/living/bot/proc/turn_off() on = 0 set_light(0) - update_icons() - -/mob/living/bot/proc/explode() - qdel(src) - -/******************************************************************/ -// Navigation procs -// Used for A-star pathfinding - - -// Returns the surrounding cardinal turfs with open links -// Including through doors openable with the ID -/turf/proc/CardinalTurfsWithAccess(var/obj/item/card/id/ID) - var/L[] = new() - - // for(var/turf/simulated/t in oview(src,1)) - - for(var/d in GLOB.cardinal) - var/turf/simulated/T = get_step(src, d) - if(istype(T) && !T.density) - if(!LinkBlockedWithAccess(src, T, ID)) - L.Add(T) - return L - + update_icon() -// Returns true if a link between A and B is blocked -// Movement through doors allowed if ID has access -/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/card/id/ID) - - if(A == null || B == null) return 1 - var/adir = get_dir(A,B) - var/rdir = get_dir(B,A) - if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal - var/iStep = get_step(A,adir&(NORTH|SOUTH)) - if(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID)) - return 0 - - var/pStep = get_step(A,adir&(EAST|WEST)) - if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID)) - return 0 - return 1 - - if(DirBlockedWithAccess(A,adir, ID)) - return 1 - - if(DirBlockedWithAccess(B,rdir, ID)) - return 1 - - for(var/obj/O in B) - if(O.density && !istype(O, /obj/machinery/door) && !(O.atom_flags & ATOM_FLAG_CHECKS_BORDER)) - return 1 - - return 0 - -// Returns true if direction is blocked from loc -// Checks doors against access with given ID -/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/card/id/ID) - for(var/obj/structure/window/D in loc) - if(!D.density) continue - if(D.dir == SOUTHWEST) return 1 - if(D.dir == dir) return 1 - - for(var/obj/machinery/door/D in loc) - if(!D.density) continue - if(istype(D, /obj/machinery/door/window)) - if( dir & D.dir ) return !D.check_access(ID) - - //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID) - //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID) - else return !D.check_access(ID) // it's a real, air blocking door - return 0 +/mob/living/bot/GetIdCards(list/exceptions) + . = ..() + if(istype(botcard) && !is_type_in_list(botcard, exceptions)) + LAZYDISTINCTADD(., botcard) + +// We don't want to drop these on gib(). +/mob/living/bot/physically_destroyed(skip_qdel) + QDEL_NULL(botcard) + QDEL_NULL(access_scanner) + return ..() + +/mob/living/bot/Destroy() + QDEL_NULL(botcard) + QDEL_NULL(access_scanner) + return ..() + +/mob/living/bot/isSynthetic() + return TRUE diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index 78c37a1155b1..22c803e19495 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -1,5 +1,5 @@ /mob/living/bot/cleanbot - name = "Cleanbot" + name = "cleanbot" desc = "A little cleaning robot, he looks so excited!" icon = 'icons/mob/bot/cleanbot.dmi' icon_state = "cleanbot0" @@ -9,7 +9,6 @@ wait_if_pulled = 1 min_target_dist = 0 - var/cleaning = 0 var/screwloose = 0 var/oddbutton = 0 var/blood = 1 @@ -22,83 +21,72 @@ /mob/living/bot/cleanbot/handleIdle() if(!screwloose && !oddbutton && prob(5)) visible_message("\The [src] makes an excited beeping booping sound!") - if(screwloose && prob(5)) // Make a mess - if(istype(loc, /turf/simulated)) - var/turf/simulated/T = loc - T.wet_floor() - + if(isturf(loc)) + var/turf/T = loc + if(T.simulated) + T.wet_floor() if(oddbutton && prob(5)) // Make a big mess visible_message("Something flies out of [src]. He seems to be acting oddly.") - var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc) + var/obj/effect/decal/cleanable/blood/gibs/gib = new(loc) var/weakref/g = weakref(gib) ignore_list += g spawn(600) ignore_list -= g /mob/living/bot/cleanbot/lookForTargets() - for(var/obj/effect/decal/cleanable/D in view(world.view + 1, src)) - if(confirmTarget(D)) - target = D + for(var/obj/effect/decal/cleanable/decal in view(world.view + 1, src)) + if(confirmTarget(decal)) + target = decal playsound(src, 'sound/machines/boop1.ogg', 30) return -/mob/living/bot/cleanbot/confirmTarget(var/obj/effect/decal/cleanable/D) - if(!..()) - return 0 - for(var/T in target_types) - if(istype(D, T)) - return 1 - return 0 +/mob/living/bot/cleanbot/confirmTarget(atom/target) + . = ..() + if(.) + var/turf/decal_turf = get_turf(target) + if(!istype(decal_turf) || decal_turf.contains_dense_objects()) + return FALSE // Stop trying to clean under full-tile windows. + if(istype(target, /obj/effect/decal/cleanable/dirt)) + var/obj/effect/decal/cleanable/dirt/dirt = target + return dirt.dirt_amount >= 50 // Stop trying to clean invisible dirt. + return is_type_in_list(target, target_types) /mob/living/bot/cleanbot/handleAdjacentTarget() if(get_turf(target) == src.loc) - UnarmedAttack(target) + UnarmedAttack(target, TRUE) -/mob/living/bot/cleanbot/UnarmedAttack(var/obj/effect/decal/cleanable/D, var/proximity) - if(!..()) - return +/mob/living/bot/cleanbot/ResolveUnarmedAttack(var/obj/effect/decal/cleanable/decal) + if(!istype(decal)) + return TRUE - if(!istype(D)) - return - - if(D.loc != loc) - return + if(decal.loc != loc) + return FALSE busy = 1 - visible_message("\The [src] begins to clean up \the [D]") - update_icons() - var/cleantime = istype(D, /obj/effect/decal/cleanable/dirt) ? 10 : 50 - if(do_after(src, cleantime, progress = 0)) - if(istype(loc, /turf/simulated)) - var/turf/simulated/f = loc - f.dirt = 0 - if(!D) - return - qdel(D) - if(D == target) + visible_message("\The [src] begins to clean up \the [decal].") + update_icon() + var/cleantime = istype(decal, /obj/effect/decal/cleanable/dirt) ? 10 : 50 + if(do_after(src, cleantime, progress = 0) && !QDELETED(decal)) + if(decal == target) target = null + qdel(decal) playsound(src, 'sound/machines/boop2.ogg', 30) busy = 0 - update_icons() + update_icon() + return TRUE -/mob/living/bot/cleanbot/explode() - on = 0 - visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - - new /obj/item/chems/glass/bucket(Tsec) - new /obj/item/assembly/prox_sensor(Tsec) - if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(src) - return +/mob/living/bot/cleanbot/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + new /obj/item/chems/glass/bucket(my_turf) + new /obj/item/assembly/prox_sensor(my_turf) + if(prob(50)) + new /obj/item/robot_parts/l_arm(my_turf) -/mob/living/bot/cleanbot/update_icons() +/mob/living/bot/cleanbot/on_update_icon() + ..() if(busy) icon_state = "cleanbot-c" else @@ -109,12 +97,12 @@ . += "Automatic Cleaner v1.0" /mob/living/bot/cleanbot/GetInteractPanel() - . = "Cleans blood: [blood ? "Yes" : "No"]" - . += "
          Patrol station: [will_patrol ? "Yes" : "No"]" + . = "Cleans blood: [blood ? "Yes" : "No"]" + . += "
          Patrol station: [will_patrol ? "Yes" : "No"]" /mob/living/bot/cleanbot/GetInteractMaintenance() - . = "Odd looking screw twiddled: [screwloose ? "Yes" : "No"]" - . += "
          Weird button pressed: [oddbutton ? "Yes" : "No"]" + . = "Odd looking screw twiddled: [screwloose ? "Yes" : "No"]" + . += "
          Weird button pressed: [oddbutton ? "Yes" : "No"]" /mob/living/bot/cleanbot/ProcessCommand(var/mob/user, var/command, var/href_list) ..() @@ -138,7 +126,7 @@ . = ..() if(!screwloose || !oddbutton) if(user) - to_chat(user, "The [src] buzzes and beeps.") + to_chat(user, "\The [src] buzzes and beeps.") oddbutton = 1 screwloose = 1 return 1 diff --git a/code/modules/mob/living/bot/ed209bot.dm b/code/modules/mob/living/bot/ed209bot.dm index e44155414e54..19cb53e0eee4 100644 --- a/code/modules/mob/living/bot/ed209bot.dm +++ b/code/modules/mob/living/bot/ed209bot.dm @@ -5,14 +5,9 @@ icon_state = "ed2090" attack_state = "ed209-c" layer = MOB_LAYER - density = 1 - health = 100 - maxHealth = 100 - - is_ranged = 1 + density = TRUE + max_health = 100 preparing_arrest_sounds = new() - - a_intent = I_HURT mob_bump_flag = HEAVY mob_swap_flags = ~HEAVY mob_push_flags = HEAVY @@ -20,31 +15,26 @@ var/shot_delay = 4 var/last_shot = 0 -/mob/living/bot/secbot/ed209/update_icons() +/mob/living/bot/secbot/ed209/on_update_icon() + ..() icon_state = "ed2090" -/mob/living/bot/secbot/ed209/explode() - visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - - var/obj/item/gun/energy/taser/G = new /obj/item/gun/energy/taser(Tsec) - G.power_supply.charge = 0 - if(prob(50)) - new /obj/item/robot_parts/l_leg(Tsec) - if(prob(50)) - new /obj/item/robot_parts/r_leg(Tsec) - if(prob(50)) +/mob/living/bot/secbot/ed209/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + var/obj/item/gun/energy/taser/G = new /obj/item/gun/energy/taser(my_turf) + var/obj/item/cell/power_supply = G.get_cell() + power_supply?.charge = 0 if(prob(50)) - new /obj/item/clothing/head/helmet(Tsec) - else - new /obj/item/clothing/suit/armor/vest(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - - new /obj/effect/decal/cleanable/blood/oil(Tsec) - qdel(src) + new /obj/item/robot_parts/l_leg(my_turf) + if(prob(50)) + new /obj/item/robot_parts/r_leg(my_turf) + if(prob(50)) + if(prob(50)) + new /obj/item/clothing/head/helmet(my_turf) + else + new /obj/item/clothing/suit/armor/vest(my_turf) /mob/living/bot/secbot/ed209/handleRangedTarget() RangedAttack(target) diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm index 7191f7be98f1..a5b195163b27 100644 --- a/code/modules/mob/living/bot/farmbot.dm +++ b/code/modules/mob/living/bot/farmbot.dm @@ -8,8 +8,7 @@ desc = "The botanist's best friend." icon = 'icons/mob/bot/farmbot.dmi' icon_state = "farmbot0" - health = 50 - maxHealth = 50 + max_health = 50 req_access = list(list(access_hydroponics, access_robotics)) var/action = "" // Used to update icon @@ -41,25 +40,25 @@ . = ..() . += "
          Water tank: " if(tank) - . += "[tank.reagents.total_volume]/[tank.reagents.maximum_volume]" + . += "[REAGENT_TOTAL_VOLUME(tank.reagents)]/[REAGENT_MAXIMUM_VOLUME(tank.reagents)]" else . += "error: not found" /mob/living/bot/farmbot/GetInteractPanel() - . = "Water plants : [waters_trays ? "Yes" : "No"]" - . += "
          Refill watertank : [refills_water ? "Yes" : "No"]" - . += "
          Weed plants: [uproots_weeds ? "Yes" : "No"]" - . += "
          Replace fertilizer: [replaces_nutriment ? "Yes" : "No"]" - . += "
          Collect produce: [collects_produce ? "Yes" : "No"]" - . += "
          Remove dead plants: [removes_dead ? "Yes" : "No"]" + . = "Water plants : [waters_trays ? "Yes" : "No"]" + . += "
          Refill watertank : [refills_water ? "Yes" : "No"]" + . += "
          Weed plants: [uproots_weeds ? "Yes" : "No"]" + . += "
          Replace fertilizer: [replaces_nutriment ? "Yes" : "No"]" + . += "
          Collect produce: [collects_produce ? "Yes" : "No"]" + . += "
          Remove dead plants: [removes_dead ? "Yes" : "No"]" /mob/living/bot/farmbot/GetInteractMaintenance() . = "Plant identifier status: " switch(emagged) if(0) - . += "Normal" + . += "Normal" if(1) - . += "Scrambled (DANGER)" + . += "Scrambled (DANGER)" if(2) . += "ERROROROROROR-----" @@ -95,7 +94,8 @@ emagged = 2 return 1 -/mob/living/bot/farmbot/update_icons() +/mob/living/bot/farmbot/on_update_icon() + ..() if(on && action) icon_state = "farmbot_[action]" else @@ -106,11 +106,11 @@ flick("farmbot_broke", src) /mob/living/bot/farmbot/handleAdjacentTarget() - UnarmedAttack(target) + UnarmedAttack(target, TRUE) /mob/living/bot/farmbot/lookForTargets() if(emagged) - for(var/mob/living/carbon/human/H in view(7, src)) + for(var/mob/living/human/H in view(7, src)) target = H return else @@ -118,44 +118,24 @@ if(confirmTarget(tray)) target = tray return - if(!target && refills_water && tank && tank.reagents.total_volume < tank.reagents.maximum_volume) + if(!target && refills_water && tank && REAGENT_TOTAL_VOLUME(tank.reagents) < REAGENT_MAXIMUM_VOLUME(tank.reagents)) for(var/obj/structure/hygiene/sink/source in view(7, src)) target = source return -/mob/living/bot/farmbot/calcTargetPath() // We need to land NEXT to the tray, because the tray itself is impassable - for(var/trayDir in list(NORTH, SOUTH, EAST, WEST)) - target_path = AStar(get_turf(loc), get_step(get_turf(target), trayDir), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard) - if(target_path) - break - if(!target_path) - ignore_list |= target - target = null - target_path = list() - return - -/mob/living/bot/farmbot/stepToTarget() // Same reason - var/turf/T = get_turf(target) - if(!target_path.len || !T.Adjacent(target_path[target_path.len])) - calcTargetPath() - makeStep(target_path) - return - -/mob/living/bot/farmbot/UnarmedAttack(var/atom/A, var/proximity) - if(!..()) - return +/mob/living/bot/farmbot/ResolveUnarmedAttack(var/atom/A, var/proximity) if(busy) - return + return TRUE if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) var/obj/machinery/portable_atmospherics/hydroponics/T = A var/t = confirmTarget(T) switch(t) if(0) - return + return TRUE if(FARMBOT_COLLECT) action = "water" // Needs a better one - update_icons() + update_icon() visible_message("[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].") busy = 1 if(do_after(src, 30, A)) @@ -163,7 +143,7 @@ T.physical_attack_hand(src) if(FARMBOT_WATER) action = "water" - update_icons() + update_icon() visible_message("[src] starts watering \the [A].") busy = 1 if(do_after(src, 30, A)) @@ -172,7 +152,7 @@ tank.reagents.trans_to(T, 100 - T.waterlevel) if(FARMBOT_UPROOT) action = "hoe" - update_icons() + update_icon() visible_message("[src] starts uprooting the weeds in \the [A].") busy = 1 if(do_after(src, 30, A)) @@ -180,30 +160,30 @@ T.weedlevel = 0 if(FARMBOT_NUTRIMENT) action = "fertile" - update_icons() + update_icon() visible_message("[src] starts fertilizing \the [A].") busy = 1 if(do_after(src, 30, A)) visible_message("[src] fertilizes \the [A].") - T.reagents.add_reagent(/decl/material/gas/ammonia, 10) + T.add_to_reagents(/decl/material/gas/ammonia, 10) busy = 0 action = "" - update_icons() + update_icon() T.update_icon() else if(istype(A, /obj/structure/hygiene/sink)) - if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume) - return + if(!tank || REAGENT_TOTAL_VOLUME(tank.reagents) >= REAGENT_MAXIMUM_VOLUME(tank.reagents)) + return TRUE action = "water" - update_icons() + update_icon() visible_message("[src] starts refilling its tank from \the [A].") busy = 1 - while(do_after(src, 10) && tank.reagents.total_volume < tank.reagents.maximum_volume) - tank.reagents.add_reagent(/decl/material/liquid/water, 100) + while(do_after(src, 10) && REAGENT_TOTAL_VOLUME(tank.reagents) < REAGENT_MAXIMUM_VOLUME(tank.reagents)) + tank.add_to_reagents(/decl/material/liquid/water, 100) if(prob(5)) playsound(loc, 'sound/effects/slosh.ogg', 25, 1) busy = 0 action = "" - update_icons() + update_icon() visible_message("[src] finishes refilling its tank.") else if(emagged && ishuman(A)) var/action = pick("weed", "water") @@ -216,50 +196,43 @@ do_attack_animation(A) if(prob(50)) visible_message("[src] swings wildly at [A] with a minihoe, missing completely!") - return + return TRUE var/t = pick("slashed", "sliced", "cut", "clawed") A.attack_generic(src, 5, t) if("water") flick("farmbot_water", src) visible_message("[src] splashes [A] with water!") tank.reagents.splash(A, 100) + return TRUE -/mob/living/bot/farmbot/explode() - visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - - new /obj/item/minihoe(Tsec) - new /obj/item/chems/glass/bucket(Tsec) - new /obj/item/assembly/prox_sensor(Tsec) - new /obj/item/scanner/plant(Tsec) - - if(tank) - tank.forceMove(Tsec) - - if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(src) - return - -/mob/living/bot/farmbot/confirmTarget(var/atom/targ) +/mob/living/bot/farmbot/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + new /obj/item/tool/hoe/mini(my_turf) + new /obj/item/chems/glass/bucket(my_turf) + new /obj/item/assembly/prox_sensor(my_turf) + new /obj/item/scanner/plant(my_turf) + if(tank) + tank.forceMove(my_turf) + if(prob(50)) + new /obj/item/robot_parts/l_arm(my_turf) + +/mob/living/bot/farmbot/confirmTarget(atom/target) if(!..()) return 0 - if(emagged && ishuman(targ)) - if(targ in view(world.view, src)) + if(emagged && ishuman(target)) + if(target in view(world.view, src)) return 1 return 0 - if(istype(targ, /obj/structure/hygiene/sink)) - if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume) + if(istype(target, /obj/structure/hygiene/sink)) + if(!tank || REAGENT_TOTAL_VOLUME(tank.reagents) >= REAGENT_MAXIMUM_VOLUME(tank.reagents)) return 0 return 1 - var/obj/machinery/portable_atmospherics/hydroponics/tray = targ + var/obj/machinery/portable_atmospherics/hydroponics/tray = target if(!istype(tray)) return 0 @@ -269,13 +242,13 @@ if(tray.dead && removes_dead || tray.harvest && collects_produce) return FARMBOT_COLLECT - else if(refills_water && tray.waterlevel < 40 && !tray.reagents.has_reagent(/decl/material/liquid/water)) + else if(refills_water && tray.waterlevel < 40 && !tray.reagents.has_reagent(/decl/material/liquid/water) && (REAGENT_TOTAL_VOLUME(tank?.reagents) > 0)) return FARMBOT_WATER else if(uproots_weeds && tray.weedlevel > 3) return FARMBOT_UPROOT - else if(replaces_nutriment && tray.nutrilevel < 1 && tray.reagents.total_volume < 1) + else if(replaces_nutriment && tray.nutrilevel < 1 && REAGENT_TOTAL_VOLUME(tray.reagents) < 1) return FARMBOT_NUTRIMENT return 0 diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm index 625d56c3d216..00ae50e7a086 100644 --- a/code/modules/mob/living/bot/floorbot.dm +++ b/code/modules/mob/living/bot/floorbot.dm @@ -27,7 +27,8 @@ src.underlays += B -/mob/living/bot/floorbot/update_icons() +/mob/living/bot/floorbot/on_update_icon() + ..() if(busy) icon_state = "floorbot-c" else if(amount > 0) @@ -44,17 +45,17 @@ . += "
          Tiles left: [amount]" /mob/living/bot/floorbot/GetInteractPanel() - . = "Improves floors: [improvefloors ? "Yes" : "No"]" - . += "
          Finds tiles: [eattiles ? "Yes" : "No"]" - . += "
          Make single pieces of metal into tiles when empty: [maketiles ? "Yes" : "No"]" + . = "Improves floors: [improvefloors ? "Yes" : "No"]" + . += "
          Finds tiles: [eattiles ? "Yes" : "No"]" + . += "
          Make single pieces of metal into tiles when empty: [maketiles ? "Yes" : "No"]" /mob/living/bot/floorbot/GetInteractMaintenance() . = "Disassembly mode: " switch(emagged) if(0) - . += "Off" + . += "Off" if(1) - . += "On (Caution)" + . += "On (Caution)" if(2) . += "ERROROROROROR-----" @@ -80,7 +81,7 @@ if(!emagged) emagged = 1 if(user) - to_chat(user, "The [src] buzzes and beeps.") + to_chat(user, "\The [src] buzzes and beeps.") return 1 /mob/living/bot/floorbot/handleRegular() @@ -94,10 +95,10 @@ /mob/living/bot/floorbot/handleAdjacentTarget() if(get_turf(target) == src.loc) - UnarmedAttack(target) + UnarmedAttack(target, TRUE) /mob/living/bot/floorbot/lookForTargets() - for(var/turf/simulated/floor/T in view(src)) + for(var/turf/floor/T in view(src)) if(confirmTarget(T)) target = T return @@ -108,83 +109,79 @@ target = S return -/mob/living/bot/floorbot/confirmTarget(var/atom/A) // The fact that we do some checks twice may seem confusing but remember that the bot's settings may be toggled while it's moving and we want them to stop in that case +/mob/living/bot/floorbot/confirmTarget(atom/target) // The fact that we do some checks twice may seem confusing but remember that the bot's settings may be toggled while it's moving and we want them to stop in that case anchored = FALSE if(!..()) return 0 - if(istype(A, /obj/item/stack/tile/floor)) + if(istype(target, /obj/item/stack/tile/floor)) return (amount < maxAmount && eattiles) - if(istype(A, /obj/item/stack/material/steel)) - return (amount < maxAmount && maketiles) - if(A.loc.name == "Space") - return 0 + if(istype(target, /obj/item/stack/material)) + var/obj/item/stack/material/S = target + if(S.material?.type == /decl/material/solid/metal/steel) + return (amount < maxAmount && maketiles) - var/turf/simulated/floor/T = A - if(istype(T)) - if(emagged) - return 1 - else - return (amount && (T.broken || T.burnt || (improvefloors && !T.flooring))) + var/turf/floor/my_turf = target + if(!istype(my_turf) || (isturf(my_turf) && my_turf.is_open())) + return FALSE -/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity) - if(!..()) - return + return emagged || (amount && (my_turf.is_floor_damaged() || (improvefloors && !my_turf.has_flooring()))) +/mob/living/bot/floorbot/ResolveUnarmedAttack(var/atom/A) if(busy) - return + return TRUE if(get_turf(A) != loc) - return + return FALSE - if(emagged && istype(A, /turf/simulated/floor)) - var/turf/simulated/floor/F = A + if(emagged && istype(A, /turf/floor)) + var/turf/floor/F = A busy = 1 - update_icons() - if(F.flooring) - visible_message("[src] begins to tear the floor tile from the floor.") + update_icon() + if(F.has_flooring()) + visible_message("[src] begins to tear up \the [F].") if(do_after(src, 50, F)) F.break_tile_to_plating() addTiles(1) else visible_message("[src] begins to tear through the floor!") if(do_after(src, 150, F)) // Extra time because this can and will kill. - F.ReplaceWithLattice() + F.physically_destroyed() addTiles(1) target = null - update_icons() - else if(istype(A, /turf/simulated/floor)) - var/turf/simulated/floor/F = A - if(F.broken || F.burnt) + update_icon() + else if(istype(A, /turf/floor)) + var/turf/floor/F = A + if(F.is_floor_damaged()) busy = 1 - update_icons() + update_icon() visible_message("[src] begins to remove the broken floor.") anchored = TRUE if(do_after(src, 50, F)) - if(F.broken || F.burnt) - F.make_plating() + if(F.is_floor_damaged()) + F.remove_flooring(F.get_topmost_flooring()) anchored = FALSE target = null busy = 0 - update_icons() - else if(!F.flooring && amount) + update_icon() + else if(!F.has_flooring() && amount) busy = 1 - update_icons() + update_icon() visible_message("[src] begins to improve the floor.") anchored = TRUE if(do_after(src, 50, F)) - if(!F.flooring) - F.set_flooring(decls_repository.get_decl(floor_build_type)) + if(!F.has_flooring()) + F.set_flooring(GET_DECL(floor_build_type)) addTiles(-1) anchored = FALSE target = null - update_icons() + update_icon() else if(istype(A, /obj/item/stack/tile/floor) && amount < maxAmount) var/obj/item/stack/tile/floor/T = A visible_message("\The [src] begins to collect tiles.") busy = 1 - update_icons() + update_icon() anchored = TRUE if(do_after(src, 20)) if(T) @@ -193,50 +190,38 @@ addTiles(eaten) anchored = FALSE target = null - update_icons() + update_icon() else if(istype(A, /obj/item/stack/material) && amount + 4 <= maxAmount) var/obj/item/stack/material/M = A if(M.get_material_type() == /decl/material/solid/metal/steel) visible_message("\The [src] begins to make tiles.") busy = 1 anchored = TRUE - update_icons() + update_icon() if(do_after(src, 50)) if(M) M.use(1) addTiles(4) anchored = FALSE + return TRUE -/mob/living/bot/floorbot/explode() - turn_off() - visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - - - var/list/things = list() - for(var/atom/A in orange(5, src.loc)) - things += A - - var/list/shrapnel = list() - - for(var/I = 3, I<3 , I++) //Toolbox shatters. - shrapnel += new /obj/item/shard/shrapnel(Tsec) - - for(var/Amt = amount, Amt>0, Amt--) //Why not just spit them out in a disorganized jumble? - shrapnel += new /obj/item/stack/tile/floor(Tsec) - - if(prob(50)) - shrapnel += new /obj/item/robot_parts/l_arm(Tsec) - shrapnel += new /obj/item/assembly/prox_sensor(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - - for(var/atom/movable/AM in shrapnel) - AM.throw_at(pick(things),5) - - qdel(src) +/mob/living/bot/floorbot/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + var/list/things = list() + for(var/atom/A in orange(5, src.loc)) + things += A + var/list/shrapnel = list() + for(var/I = 3, I<3 , I++) //Toolbox shatters. + shrapnel += new /obj/item/shard/shrapnel(my_turf) + for(var/Amt = amount, Amt>0, Amt--) //Why not just spit them out in a disorganized jumble? + shrapnel += new /obj/item/stack/tile/floor(my_turf) + if(prob(50)) + shrapnel += new /obj/item/robot_parts/l_arm(my_turf) + shrapnel += new /obj/item/assembly/prox_sensor(my_turf) + for(var/atom/movable/AM in shrapnel) + AM.throw_at(pick(things),5) /mob/living/bot/floorbot/proc/addTiles(var/am) amount += am diff --git a/code/modules/mob/living/bot/medibot.dm b/code/modules/mob/living/bot/medibot.dm index 986f400467d8..30a2c37e4250 100644 --- a/code/modules/mob/living/bot/medibot.dm +++ b/code/modules/mob/living/bot/medibot.dm @@ -1,3 +1,11 @@ +#define MEDBOT_PANIC_NONE 0 +#define MEDBOT_PANIC_LOW 15 +#define MEDBOT_PANIC_MED 35 +#define MEDBOT_PANIC_HIGH 55 +#define MEDBOT_PANIC_FUCK 70 +#define MEDBOT_PANIC_ENDING 90 +#define MEDBOT_PANIC_END 100 + /mob/living/bot/medbot name = "Medibot" desc = "A little medical robot. He looks somewhat underwhelmed." @@ -23,92 +31,165 @@ var/treatment_emag = /decl/material/liquid/venom var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds? + // Are we tipped over? + var/is_tipped = FALSE + //How panicked we are about being tipped over (why would you do this?) + var/tipped_status = MEDBOT_PANIC_NONE + //The name we got when we were tipped + var/tipper_name + //The last time we were tipped/righted and said a voice line, to avoid spam + var/last_tipping_action_voice = 0 + +/mob/living/bot/medbot/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = ..() + if(tipped_status == MEDBOT_PANIC_NONE) + return + + switch(tipped_status) + if(MEDBOT_PANIC_NONE to MEDBOT_PANIC_LOW) + . += "It appears to be tipped over, and is quietly waiting for someone to set it right." + if(MEDBOT_PANIC_LOW to MEDBOT_PANIC_MED) + . += "It is tipped over and requesting help." + if(MEDBOT_PANIC_MED to MEDBOT_PANIC_HIGH) + . += SPAN_WARNING("They are tipped over and appear visibly distressed.") // now we humanize the medbot as a they, not an it + if(MEDBOT_PANIC_HIGH to MEDBOT_PANIC_FUCK) + . += SPAN_WARNING("They are tipped over and visibly panicking!") + if(MEDBOT_PANIC_FUCK to INFINITY) + . += SPAN_DANGER("They are freaking out from being tipped over!") + /mob/living/bot/medbot/handleIdle() if(vocal && prob(1)) - var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of infirmary is this? Everyone's dropping like dead flies.", "Delicious!") + var/static/message_options = list( + "Radar, put a mask on!" = 'sound/voice/medbot/mradar.ogg', + "There's always a catch, and it's the best there is." = 'sound/voice/medbot/mcatch.ogg', + "I knew it, I should've been a plastic surgeon." = 'sound/voice/medbot/msurgeon.ogg', + "What kind of medbay is this? Everyone's dropping like flies." = 'sound/voice/medbot/mflies.ogg', + "Delicious!" = 'sound/voice/medbot/mdelicious.ogg' + ) + var/message = pick(message_options) say(message) + playsound(src, message_options[message], 50, 0) /mob/living/bot/medbot/handleAdjacentTarget() - UnarmedAttack(target) + if(is_tipped) // Don't handle targets if we're incapacitated! + return + UnarmedAttack(target, TRUE) /mob/living/bot/medbot/lookForTargets() - for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient! - if(confirmTarget(H)) - target = H - if(last_newpatient_speak + 300 < world.time) - var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!") - say(message) - custom_emote(1, "points at [H.name].") + if(is_tipped) // Don't look for targets if we're incapacitated! + return + for(var/mob/living/human/patient in view(7, src)) // Time to find a patient! + if(confirmTarget(patient)) + target = patient + if(last_newpatient_speak + 300 < world.time && vocal) + if(vocal) + var/message_options = list( + "Hey, [patient.name]! Hold on, I'm coming." = 'sound/voice/medbot/mcoming.ogg', + "Wait [patient.name]! I want to help!" = 'sound/voice/medbot/mhelp.ogg', + "[patient.name], you appear to be injured!" = 'sound/voice/medbot/minjured.ogg' + ) + var/message = pick(message_options) + say(message) + playsound(src, message_options[message], 50, 0) + custom_emote(1, "points at [patient.name].") last_newpatient_speak = world.time break -/mob/living/bot/medbot/UnarmedAttack(var/mob/living/carbon/human/H, var/proximity) - if(!..()) - return - - if(!on) - return - - if(!istype(H)) - return +/mob/living/bot/medbot/ResolveUnarmedAttack(var/mob/living/human/target) + if(!on || !istype(target)) + return FALSE if(busy) - return - - if(H.stat == DEAD) - var/death_message = pick("No! NO!", "Live, damnit! LIVE!", "I... I've never lost a patient before. Not today, I mean.") - say(death_message) - target = null - return - - var/t = confirmTarget(H) + return TRUE + + if(target.stat == DEAD) + if(vocal) + var/static/death_messages = list( + "No! Stay with me!" = 'sound/voice/medbot/mno.ogg', + "Live, damnit! LIVE!" = 'sound/voice/medbot/mlive.ogg', + "I... I've never lost a patient before. Not today, I mean." = 'sound/voice/medbot/mlost.ogg' + ) + var/message = pick(death_messages) + say(message) + playsound(src, death_messages[message], 50, 0) + + var/t = confirmTarget(target) if(!t) - var/message = pick("All patched up!", "An apple a day keeps me away.", "Feel better soon!") - say(message) - target = null - return + if(vocal) + var/static/possible_messages = list( + "All patched up!" = 'sound/voice/medbot/mpatchedup.ogg', + "An apple a day keeps me away." = 'sound/voice/medbot/mapple.ogg', + "Feel better soon!" = 'sound/voice/medbot/mfeelbetter.ogg' + ) + var/message = pick(possible_messages) + say(message) + playsound(src, possible_messages[message], 50, 0) icon_state = "medibots" - visible_message("[src] is trying to inject [H]!") + visible_message("[src] is trying to inject [target]!") if(declare_treatment) var/area/location = get_area(src) - broadcast_medical_hud_message("[src] is treating [H] in [location]", src) + broadcast_medical_hud_message("[src] is treating [target] in [location.proper_name]", src) busy = 1 - update_icons() - if(do_mob(src, H, 30)) + update_icon() + if(do_mob(src, target, 30)) if(t == 1) - reagent_glass.reagents.trans_to_mob(H, injection_amount, CHEM_INJECT) + reagent_glass.reagents.trans_to_mob(target, injection_amount, CHEM_INJECT) else - H.reagents.add_reagent(t, injection_amount) - visible_message("[src] injects [H] with the syringe!") + target.add_to_reagents(t, injection_amount) + visible_message("[src] injects [target] with the syringe!") busy = 0 - update_icons() + update_icon() + return TRUE -/mob/living/bot/medbot/update_icons() - overlays.Cut() +/mob/living/bot/medbot/on_update_icon() + ..() if(skin) - overlays += image('icons/mob/bot/medibot_skins.dmi', "medskin_[skin]") + add_overlay(image('icons/mob/bot/medibot_skins.dmi', "medskin_[skin]")) if(busy) icon_state = "medibots" else icon_state = "medibot[on]" -/mob/living/bot/medbot/attackby(var/obj/item/O, var/mob/user) - if(istype(O, /obj/item/chems/glass)) +/mob/living/bot/medbot/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/chems/glass)) if(locked) to_chat(user, "You cannot insert a beaker because the panel is locked.") - return + return TRUE if(!isnull(reagent_glass)) to_chat(user, "There is already a beaker loaded.") - return + return TRUE - if(!user.unEquip(O, src)) - return - reagent_glass = O - to_chat(user, "You insert [O].") - return + if(!user.try_unequip(used_item, src)) + return TRUE + reagent_glass = used_item + to_chat(user, "You insert [used_item].") + return TRUE else - ..() + return ..() + +/mob/living/bot/medbot/default_disarm_interaction(mob/user) + if(!is_tipped) + user.visible_message(SPAN_DANGER("\The [user] begins tipping over [src]."), SPAN_WARNING("You begin tipping over [src]...")) + + if(world.time > last_tipping_action_voice + 15 SECONDS && vocal) + last_tipping_action_voice = world.time // message for tipping happens when we start interacting, message for righting comes after finishing + var/static/list/messagevoice = list("Hey, wait..." = 'sound/voice/medbot/hey_wait.ogg',"Please don't..." = 'sound/voice/medbot/please_dont.ogg',"I trusted you..." = 'sound/voice/medbot/i_trusted_you.ogg', "Nooo..." = 'sound/voice/medbot/nooo.ogg', "Oh fuck-" = 'sound/voice/medbot/oh_fuck.ogg') + var/message = pick(messagevoice) + say(message) + playsound(src, messagevoice[message], 70, FALSE) + if(do_after(user, 3 SECONDS, target=src)) + tip_over(user) + return TRUE + . = ..() + +/mob/living/bot/medbot/default_help_interaction(mob/user) + if(is_tipped) + user.visible_message(SPAN_NOTICE("\The [user] begins righting [src]."), SPAN_NOTICE("You begin righting [src]...")) + if(do_after(user, 3 SECONDS, target=src)) + set_right(user) + return TRUE + . = ..() /mob/living/bot/medbot/GetInteractTitle() . = "Medibot v1.0 controls" @@ -118,34 +199,34 @@ . = ..() . += "
          Beaker: " if(reagent_glass) - . += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]" + . += "Loaded \[[REAGENT_TOTAL_VOLUME(reagent_glass.reagents)]/[REAGENT_MAXIMUM_VOLUME(reagent_glass.reagents)]\]" else . += "None loaded" /mob/living/bot/medbot/GetInteractPanel() . = "Healing threshold: " - . += "-- " - . += "- " + . += "-- " + . += "- " . += "[heal_threshold] " - . += "+ " - . += "++" + . += "+ " + . += "++" . += "
          Injection level: " - . += "- " + . += "- " . += "[injection_amount] " - . += "+ " + . += "+ " - . += "
          Reagent source: [use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]" - . += "
          Treatment report is [declare_treatment ? "on" : "off"]. Toggle" - . += "
          The speaker switch is [vocal ? "on" : "off"]. Toggle" + . += "
          Reagent source: [use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]" + . += "
          Treatment report is [declare_treatment ? "on" : "off"]. Toggle" + . += "
          The speaker switch is [vocal ? "on" : "off"]. Toggle" /mob/living/bot/medbot/GetInteractMaintenance() . = "Injection mode: " switch(emagged) if(0) - . += "Treatment" + . += "Treatment" if(1) - . += "Random (DANGER)" + . += "Random (DANGER)" if(2) . += "ERROROROROROR-----" @@ -156,11 +237,11 @@ if("adj_threshold") if(!locked || issilicon(user)) var/adjust_num = text2num(href_list["amount"]) - heal_threshold = Clamp(heal_threshold + adjust_num, 5, 75) + heal_threshold = clamp(heal_threshold + adjust_num, 5, 75) if("adj_inject") if(!locked || issilicon(user)) var/adjust_num = text2num(href_list["amount"]) - injection_amount = Clamp(injection_amount + adjust_num, 5, 15) + injection_amount = clamp(injection_amount + adjust_num, 5, 15) if("use_beaker") if(!locked || issilicon(user)) use_beaker = !use_beaker @@ -196,55 +277,119 @@ busy = 0 emagged = 1 on = 1 - update_icons() + update_icon() . = 1 -/mob/living/bot/medbot/explode() - on = 0 - visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - - new /obj/item/storage/firstaid(Tsec) - new /obj/item/assembly/prox_sensor(Tsec) - new /obj/item/scanner/health(Tsec) - if (prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) - - if(reagent_glass) - reagent_glass.forceMove(Tsec) - reagent_glass = null - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(src) - return - -/mob/living/bot/medbot/confirmTarget(var/mob/living/carbon/human/H) - if(!..()) - return 0 +/mob/living/bot/medbot/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + new /obj/item/firstaid(my_turf) + new /obj/item/assembly/prox_sensor(my_turf) + new /obj/item/scanner/health(my_turf) + if (prob(50)) + new /obj/item/robot_parts/l_arm(my_turf) + if(reagent_glass) + reagent_glass.forceMove(my_turf) + reagent_glass = null + +/mob/living/bot/medbot/confirmTarget(atom/target) + if(!(. = ..())) + return - if(H.stat == DEAD) // He's dead, Jim - return 0 + var/mob/living/human/patient = target + if(!istype(patient) || patient.stat == DEAD) // He's dead, Jim + return FALSE if(emagged) return treatment_emag // If they're injured, we're using a beaker, and they don't have on of the chems in the beaker - if(reagent_glass && use_beaker && ((H.getBruteLoss() >= heal_threshold) || (H.getToxLoss() >= heal_threshold) || (H.getToxLoss() >= heal_threshold) || (H.getOxyLoss() >= (heal_threshold + 15)))) - for(var/R in reagent_glass.reagents.reagent_volumes) - if(!H.reagents.has_reagent(R)) + if(reagent_glass && use_beaker && ((patient.get_damage(BRUTE) >= heal_threshold) || (patient.get_damage(TOX) >= heal_threshold) || (patient.get_damage(TOX) >= heal_threshold) || (patient.get_damage(OXY) >= (heal_threshold + 15)))) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagent_glass.reagents)) + if(!patient.reagents.has_reagent(reagent)) return 1 continue - if((H.getBruteLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_brute))) + if((patient.get_damage(BRUTE) >= heal_threshold) && (!patient.reagents.has_reagent(treatment_brute))) return treatment_brute //If they're already medicated don't bother! - if((H.getOxyLoss() >= (15 + heal_threshold)) && (!H.reagents.has_reagent(treatment_oxy))) + if((patient.get_damage(OXY) >= (15 + heal_threshold)) && (!patient.reagents.has_reagent(treatment_oxy))) return treatment_oxy - if((H.getFireLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_fire))) + if((patient.get_damage(BURN) >= heal_threshold) && (!patient.reagents.has_reagent(treatment_fire))) return treatment_fire - if((H.getToxLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_tox))) + if((patient.get_damage(TOX) >= heal_threshold) && (!patient.reagents.has_reagent(treatment_tox))) return treatment_tox + +/mob/living/bot/medbot/proc/tip_over(mob/user) + playsound(src, 'sound/machines/warning-buzzer.ogg', 50) + user.visible_message(SPAN_DANGER("[user] tips over [src]!"), SPAN_DANGER("You tip [src] over!")) + is_tipped = TRUE + tipper_name = user.name + var/matrix/mat = transform + transform = mat.Turn(180) + +/mob/living/bot/medbot/proc/set_right(mob/user) + var/list/messagevoice + if(user) + user.visible_message(SPAN_NOTICE("[user] sets [src] right-side up!"), SPAN_NOTICE("You set [src] right-side up!")) + if(user.name == tipper_name) + messagevoice = list("I forgive you." = 'sound/voice/medbot/forgive.ogg') + else + messagevoice = list("Thank you!" = 'sound/voice/medbot/thank_you.ogg', "You are a good person." = 'sound/voice/medbot/youre_good.ogg') + else + visible_message(SPAN_NOTICE("[src] manages to [pick("writhe", "wriggle", "wiggle")] enough to right itself.")) + messagevoice = list("Fuck you." = 'sound/voice/medbot/fuck_you.ogg', "Your behavior has been reported, have a nice day." = 'sound/voice/medbot/reported.ogg') + + tipper_name = null + if(world.time > last_tipping_action_voice + 15 SECONDS && vocal) + last_tipping_action_voice = world.time + var/message = pick(messagevoice) + say(message) + playsound(src, messagevoice[message], 70) + tipped_status = MEDBOT_PANIC_NONE + is_tipped = FALSE + transform = matrix() + + +/mob/living/bot/medbot/handleRegular() + . = ..() + + if(is_tipped) + handle_panic() + return + +/mob/living/bot/medbot/proc/handle_panic() + tipped_status++ + var/list/messagevoice + switch(tipped_status) + if(MEDBOT_PANIC_LOW) + messagevoice = list("I require assistance." = 'sound/voice/medbot/i_require_asst.ogg') + if(MEDBOT_PANIC_MED) + messagevoice = list("Please put me back." = 'sound/voice/medbot/please_put_me_back.ogg') + if(MEDBOT_PANIC_HIGH) + messagevoice = list("Please, I am scared!" = 'sound/voice/medbot/please_im_scared.ogg') + if(MEDBOT_PANIC_FUCK) + messagevoice = list("I don't like this, I need help!" = 'sound/voice/medbot/dont_like.ogg', "This hurts, my pain is real!" = 'sound/voice/medbot/pain_is_real.ogg') + if(MEDBOT_PANIC_ENDING) + messagevoice = list("Is this the end?" = 'sound/voice/medbot/is_this_the_end.ogg', "Nooo!" = 'sound/voice/medbot/nooo.ogg') + if(MEDBOT_PANIC_END) + broadcast_medical_hud_message("PSYCH ALERT: Crewmember [tipper_name] recorded displaying antisocial tendencies torturing bots in [get_area_name(src)]. Please schedule psych evaluation.", src) + set_right() // strong independent medbot + + if(messagevoice && vocal) + var/message = pick(messagevoice) + say(message) + playsound(src, messagevoice[message], 70) + else if(prob(tipped_status * 0.2) && vocal) + playsound(src, 'sound/machines/warning-buzzer.ogg', 30) + +#undef MEDBOT_PANIC_NONE +#undef MEDBOT_PANIC_LOW +#undef MEDBOT_PANIC_MED +#undef MEDBOT_PANIC_HIGH +#undef MEDBOT_PANIC_FUCK +#undef MEDBOT_PANIC_ENDING +#undef MEDBOT_PANIC_END diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm index b142842d3f10..7648229f6ff9 100644 --- a/code/modules/mob/living/bot/mulebot.dm +++ b/code/modules/mob/living/bot/mulebot.dm @@ -13,10 +13,9 @@ icon = 'icons/mob/bot/mulebot.dmi' icon_state = "mulebot0" layer = MOB_LAYER - anchored = 1 - density = 1 - health = 150 - maxHealth = 150 + anchored = TRUE + density = TRUE + max_health = 150 mob_bump_flag = HEAVY min_target_dist = 0 @@ -36,7 +35,7 @@ var/turf/home var/homeName - var/global/amount = 0 + var/static/amount = 0 /mob/living/bot/mulebot/Initialize() . = ..() @@ -52,14 +51,11 @@ suffix = num2text(++amount) name = "Mulebot #[suffix]" -/mob/living/bot/mulebot/MouseDrop_T(var/atom/movable/C, var/mob/user) - if(user.stat) - return - - if(!istype(C) || C.anchored || get_dist(user, src) > 1 || get_dist(src, C) > 1 ) - return - - load(C) +/mob/living/bot/mulebot/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!.) + load(dropping) + return TRUE /mob/living/bot/mulebot/GetInteractTitle() . = "Mulebot [suffix ? "([suffix])" : ""]" @@ -71,19 +67,19 @@ . += "
          Current Load: [load ? load.name : "none"]" /mob/living/bot/mulebot/GetInteractPanel() - . += "Stop" - . += "
          Proceed" - . += "
          Return to home" - . += "
          Set destination" - . += "
          Set home" - . += "
          Toggle auto return home ([auto_return ? "On" : "Off"])" - . += "
          Toggle non-standard cargo ([crates_only ? "Off" : "On"])" + . += "Stop" + . += "
          Proceed" + . += "
          Return to home" + . += "
          Set destination" + . += "
          Set home" + . += "
          Toggle auto return home ([auto_return ? "On" : "Off"])" + . += "
          Toggle non-standard cargo ([crates_only ? "Off" : "On"])" if(load) - . += "
          Unload now" + . += "
          Unload now" /mob/living/bot/mulebot/GetInteractMaintenance() - . = "Toggle safety ([safety ? "On" : "Off - DANGER"])" + . = "Toggle safety ([safety ? "On" : "Off - DANGER"])" /mob/living/bot/mulebot/ProcessCommand(var/mob/user, var/command, var/href_list) ..() @@ -119,9 +115,9 @@ if("safety") safety = !safety -/mob/living/bot/mulebot/attackby(var/obj/item/O, var/mob/user) - ..() - update_icons() +/mob/living/bot/mulebot/attackby(var/obj/item/used_item, var/mob/user) + . = ..() + update_icon() /mob/living/bot/mulebot/proc/obeyCommand(var/command) switch(command) @@ -152,7 +148,8 @@ playsound(loc, 'sound/effects/sparks1.ogg', 100, 0) return 1 -/mob/living/bot/mulebot/update_icons() +/mob/living/bot/mulebot/on_update_icon() + ..() if(open) icon_state = "mulebot-hatch" return @@ -164,7 +161,7 @@ /mob/living/bot/mulebot/handleRegular() if(!safety && prob(1)) flick("mulebot-emagged", src) - update_icons() + update_icon() /mob/living/bot/mulebot/handleFrustrated() custom_emote(2, "makes a sighing buzz.") @@ -175,18 +172,18 @@ if(target == src.loc) custom_emote(2, "makes a chiming sound.") playsound(loc, 'sound/machines/chime.ogg', 50, 0) - UnarmedAttack(target) + UnarmedAttack(target, TRUE) resetTarget() if(auto_return && home && (loc != home)) target = home targetName = "Home" -/mob/living/bot/mulebot/confirmTarget() +/mob/living/bot/mulebot/confirmTarget(atom/target) return 1 /mob/living/bot/mulebot/calcTargetPath() ..() - if(!target_path.len && target != home) // I presume that target is not null + if(!length(target_path) && target != home) // I presume that target is not null resetTarget() target = home targetName = "Home" @@ -196,53 +193,42 @@ return ..() -/mob/living/bot/mulebot/UnarmedAttack(var/turf/T) +/mob/living/bot/mulebot/ResolveUnarmedAttack(var/turf/T) if(T == src.loc) unload(dir) -/mob/living/bot/mulebot/Bump(var/mob/living/carbon/human/M) +/mob/living/bot/mulebot/Bump(var/mob/living/human/M) if(!safety && istype(M)) visible_message("[src] knocks over [M]!") - M.Stun(8) - M.Weaken(5) + SET_STATUS_MAX(M, STAT_STUN, 8) + SET_STATUS_MAX(M, STAT_WEAK, 5) ..() -/mob/living/bot/mulebot/proc/runOver(var/mob/living/carbon/human/H) - if(istype(H)) // No safety checks - WILL run over lying humans. Stop ERPing in the maint! - visible_message("[src] drives over [H]!") - playsound(loc, 'sound/effects/splat.ogg', 50, 1) - - var/damage = rand(5, 7) - H.apply_damage(2 * damage, BRUTE, BP_HEAD) - H.apply_damage(2 * damage, BRUTE, BP_CHEST) - H.apply_damage(0.5 * damage, BRUTE, BP_L_LEG) - H.apply_damage(0.5 * damage, BRUTE, BP_R_LEG) - H.apply_damage(0.5 * damage, BRUTE, BP_L_ARM) - H.apply_damage(0.5 * damage, BRUTE, BP_R_ARM) - - blood_splatter(src, H, 1) +/mob/living/bot/mulebot/crossed_mob(var/mob/living/victim) + // No safety checks - WILL run over lying humans. Stop ERPing in the maint! + visible_message(SPAN_WARNING("\The [src] drives over \the [victim]!")) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + var/damage = rand(5, 7) + victim.apply_damage(2 * damage, BRUTE, BP_HEAD) + victim.apply_damage(2 * damage, BRUTE, BP_CHEST) + victim.apply_damage(0.5 * damage, BRUTE, BP_L_LEG) + victim.apply_damage(0.5 * damage, BRUTE, BP_R_LEG) + victim.apply_damage(0.5 * damage, BRUTE, BP_L_ARM) + victim.apply_damage(0.5 * damage, BRUTE, BP_R_ARM) + blood_splatter(src, victim, 1) /mob/living/bot/mulebot/relaymove(var/mob/user, var/direction) if(load == user) unload(direction) -/mob/living/bot/mulebot/explode() +/mob/living/bot/mulebot/gib(do_gibs = TRUE) unload(pick(0, 1, 2, 4, 8)) - - visible_message("[src] blows apart!") - - var/turf/Tsec = get_turf(src) - new /obj/item/assembly/prox_sensor(Tsec) - new /obj/item/stack/material/rods(Tsec) - new /obj/item/stack/material/rods(Tsec) - new /obj/item/stack/cable_coil/cut(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - - new /obj/effect/decal/cleanable/blood/oil(Tsec) - ..() + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + new /obj/item/assembly/prox_sensor(my_turf) + new /obj/item/stack/cable_coil/cut(my_turf) + SSmaterials.create_object(/decl/material/solid/metal/steel, get_turf(src), 2, /obj/item/stack/material/rods) /mob/living/bot/mulebot/proc/GetBeaconList() var/list/beaconlist = list() @@ -254,10 +240,10 @@ return beaconlist /mob/living/bot/mulebot/proc/load(var/atom/movable/C) - if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc)) + if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc) || C.anchored) return - for(var/obj/structure/plasticflaps/P in src.loc)//Takes flaps into account + for(var/obj/structure/flaps/P in src.loc)//Takes flaps into account if(!CanPass(C,P)) return @@ -326,3 +312,8 @@ M.client.perspective = MOB_PERSPECTIVE M.client.eye = src busy = 0 + +/mob/living/bot/mulebot/get_mob() + if(load && isliving(load)) + return list(src, load) + return src diff --git a/code/modules/mob/living/bot/remotebot.dm b/code/modules/mob/living/bot/remotebot.dm index aa84bf5bbbf5..ffdf2de4119d 100644 --- a/code/modules/mob/living/bot/remotebot.dm +++ b/code/modules/mob/living/bot/remotebot.dm @@ -3,54 +3,48 @@ desc = "A remote controlled robot used by lazy people to switch channels and get pizza." icon = 'icons/mob/bot/fetchbot.dmi' icon_state = "fetchbot1" - health = 15 - maxHealth = 15 + max_health = 15 var/working = 0 - var/next_movement_time = 0 var/speed = 10 //lower = better var/obj/item/holding = null var/obj/item/bot_controller/controller = null -/mob/living/bot/remotebot/movement_delay() +/mob/living/bot/remotebot/get_movement_delay(var/travel_dir) var/tally = ..() tally += speed if(holding) tally += (2 * holding.w_class) return tally -/mob/living/bot/remotebot/examine(mob/user) +/mob/living/bot/remotebot/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) . = ..() if(holding) - to_chat(user, "It is holding \the \icon[holding] [holding].") - -/mob/living/bot/remotebot/explode() - on = 0 - new /obj/effect/decal/cleanable/blood/oil(get_turf(src.loc)) - visible_message("[src] blows apart!") - if(controller) - controller.bot = null - controller = null - for(var/i in 1 to rand(3,5)) - var/obj/item/stack/material/cardboard/C = new(src.loc) - if(prob(50)) - C.forceMove(get_step(src, pick(GLOB.alldirs))) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(src) - -/mob/living/bot/remotebot/attackby(var/obj/item/I, var/mob/living/user) - if(istype(I, /obj/item/bot_controller) && !controller) - user.visible_message("\The [user] waves \the [I] over \the [src].") - to_chat(user, "You link \the [src] to \the [I].") - var/obj/item/bot_controller/B = I + . += SPAN_NOTICE("It is holding \the [html_icon(holding)] [holding].") + +/mob/living/bot/remotebot/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + if(controller) + controller.bot = null + controller = null + for(var/i in 1 to rand(3,5)) + var/obj/item/stack/material/cardstock/mapped/cardboard/C = new(my_turf) + if(prob(50)) + C.forceMove(get_step(src, pick(global.alldirs))) + +/mob/living/bot/remotebot/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/bot_controller) && !controller) + user.visible_message("\The [user] waves \the [used_item] over \the [src].") + to_chat(user, "You link \the [src] to \the [used_item].") + var/obj/item/bot_controller/B = used_item B.bot = src controller = B return ..() -/mob/living/bot/remotebot/update_icons() +/mob/living/bot/remotebot/on_update_icon() + ..() icon_state = "fetchbot[on]" /mob/living/bot/remotebot/Destroy() @@ -59,16 +53,16 @@ holding = null return ..() -/mob/living/bot/remotebot/proc/pickup(var/obj/item/I) - if(holding || get_dist(src,I) > 1) +/mob/living/bot/remotebot/proc/pickup(var/obj/item/used_item) + if(holding || get_dist(src,used_item) > 1) return - src.visible_message("\The [src] picks up \the [I].") + src.visible_message("\The [src] picks up \the [used_item].") flick("fetchbot-c", src) working = 1 sleep(10) working = 0 - I.forceMove(src) - holding = I + used_item.forceMove(src) + holding = used_item /mob/living/bot/remotebot/proc/drop() if(working || !holding) @@ -87,7 +81,7 @@ if(working || stat || !on || a == src) //can't touch itself return if(isturf(a) || get_dist(src,a) > 1) - walk_to(src,a,0,movement_delay()) + start_automove(a) else if(istype(a, /obj/item)) pickup(a) else @@ -96,10 +90,16 @@ /obj/item/bot_controller name = "remote control" desc = "Used to control something remotely. Even has a tiny screen!" - icon_state = "forensic1" + icon = 'icons/obj/items/remote_control.dmi' + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL - slot_flags = SLOT_BELT - item_state = "electronic" + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + ) var/mob/living/bot/remotebot/bot /obj/item/bot_controller/attack_self(var/mob/user) @@ -161,8 +161,10 @@ desc = "The cover says 'control your own cardboard nuclear powered robot. Comes with real plutonium!" icon = 'icons/obj/items/bot_kit.dmi' icon_state = "remotebot" + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/organic/cardboard -/obj/item/bot_kit/attack_self(var/mob/living/user) +/obj/item/bot_kit/attack_self(var/mob/user) to_chat(user, "You quickly dismantle the box and retrieve the controller and the remote bot itself.") var/turf/T = get_turf(src.loc) new /mob/living/bot/remotebot(T) diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index 0637b93570fe..380a8ab66a45 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -7,10 +7,8 @@ desc = "A little security robot. He looks less than thrilled." icon = 'icons/mob/bot/secbot.dmi' icon_state = "secbot0" - var/attack_state = "secbot-c" layer = MOB_LAYER - maxHealth = 50 - health = 50 + max_health = 50 req_access = list(list(access_security, access_forensics_lockers)) botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels) @@ -20,12 +18,12 @@ RequiresAccessToToggle = 1 // Haha no + var/attack_state = "secbot-c" var/idcheck = 0 // If true, arrests for having weapons without authorization. var/check_records = 0 // If true, arrests people without a record. var/check_arrest = 1 // If true, arrests people who are set to arrest. var/declare_arrests = 0 // If true, announces arrests over sechuds. - var/is_ranged = 0 var/awaiting_surrender = 0 var/obj/item/baton/stun_baton @@ -40,12 +38,9 @@ will_patrol = 1 /mob/living/bot/secbot/Initialize() - stun_baton = new(src) - stun_baton.bcell = new /obj/item/cell/infinite(stun_baton) - stun_baton.set_status(1, null) - . = ..() - + stun_baton = new /obj/item/baton/infinite(src) handcuffs = new(src) + . = ..() /mob/living/bot/secbot/Destroy() qdel(stun_baton) @@ -56,13 +51,14 @@ /mob/living/bot/secbot/turn_on() ..() - stun_baton.set_status(on, null) + stun_baton.set_cell_status(on, null) /mob/living/bot/secbot/turn_off() ..() - stun_baton.set_status(on, null) + stun_baton.set_cell_status(on, null) -/mob/living/bot/secbot/update_icons() +/mob/living/bot/secbot/on_update_icon() + ..() icon_state = "secbot[on]" /mob/living/bot/secbot/GetInteractTitle() @@ -70,19 +66,19 @@ . += "Automatic Security Unit" /mob/living/bot/secbot/GetInteractPanel() - . = "Check for weapon authorization: [idcheck ? "Yes" : "No"]" - . += "
          Check security records: [check_records ? "Yes" : "No"]" - . += "
          Check arrest status: [check_arrest ? "Yes" : "No"]" - . += "
          Report arrests: [declare_arrests ? "Yes" : "No"]" - . += "
          Auto patrol: [will_patrol ? "On" : "Off"]" + . = "Check for weapon authorization: [idcheck ? "Yes" : "No"]" + . += "
          Check security records: [check_records ? "Yes" : "No"]" + . += "
          Check arrest status: [check_arrest ? "Yes" : "No"]" + . += "
          Report arrests: [declare_arrests ? "Yes" : "No"]" + . += "
          Auto patrol: [will_patrol ? "On" : "Off"]" /mob/living/bot/secbot/GetInteractMaintenance() . = "Threat identifier status: " switch(emagged) if(0) - . += "Normal" + . += "Normal" if(1) - . += "Scrambled (DANGER)" + . += "Scrambled (DANGER)" if(2) . += "ERROROROROROR-----" @@ -107,10 +103,10 @@ if(emagged < 2) emagged = !emagged -/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user) - var/curhealth = health +/mob/living/bot/secbot/attackby(var/obj/item/used_item, var/mob/user) + var/curhealth = current_health . = ..() - if(health < curhealth) + if(current_health < curhealth) react_to_attack(user) /mob/living/bot/secbot/emag_act(var/remaining_charges, var/mob/user) @@ -123,48 +119,48 @@ return 1 /mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P) - var/curhealth = health + var/curhealth = current_health var/mob/shooter = P.firer . = ..() //if we already have a target just ignore to avoid lots of checking - if(!target && health < curhealth && shooter && (shooter in view(world.view, src))) + if(!target && current_health < curhealth && istype(shooter) && (shooter in view(world.view, src))) react_to_attack(shooter) /mob/living/bot/secbot/proc/begin_arrest(mob/target, var/threat) var/suspect_name = target_name(target) if(declare_arrests) - broadcast_security_hud_message("[src] is arresting a level [threat] suspect [suspect_name] in [get_area(src)].", src) + broadcast_security_hud_message("[src] is arresting a level [threat] suspect [suspect_name] in [get_area_name(src)].", src) say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME] seconds to comply.") playsound(src.loc, pick(preparing_arrest_sounds), 50) - GLOB.moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved) + events_repository.register(/decl/observ/moved, target, src, TYPE_PROC_REF(/mob/living/bot/secbot, target_moved)) /mob/living/bot/secbot/proc/target_moved(atom/movable/moving_instance, atom/old_loc, atom/new_loc) if(get_dist(get_turf(src), get_turf(target)) >= 1) awaiting_surrender = INFINITY - GLOB.moved_event.unregister(moving_instance, src) + events_repository.unregister(/decl/observ/moved, moving_instance, src) /mob/living/bot/secbot/proc/react_to_attack(mob/attacker) if(!target) playsound(src.loc, pick(threat_found_sounds), 50) - broadcast_security_hud_message("[src] was attacked by a hostile [target_name(attacker)] in [get_area(src)].", src) + broadcast_security_hud_message("[src] was attacked by a hostile [target_name(attacker)] in [get_area_name(src)].", src) target = attacker awaiting_surrender = INFINITY /mob/living/bot/secbot/resetTarget() ..() - GLOB.moved_event.unregister(target, src) + events_repository.unregister(/decl/observ/moved, target, src) awaiting_surrender = -1 - walk_to(src, 0) + stop_automove() /mob/living/bot/secbot/startPatrol() if(!locked) // Stop running away when we set you up return ..() -/mob/living/bot/secbot/confirmTarget(var/atom/A) +/mob/living/bot/secbot/confirmTarget(atom/target) if(!..()) return 0 - return (check_threat(A) >= SECBOT_THREAT_ARREST) + return (check_threat(target) >= SECBOT_THREAT_ARREST) /mob/living/bot/secbot/lookForTargets() for(var/mob/living/M in view(src)) @@ -179,58 +175,55 @@ return /mob/living/bot/secbot/handleAdjacentTarget() - var/mob/living/carbon/human/H = target + var/mob/living/human/H = target var/threat = check_threat(target) - if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK) + if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.current_posture.prone && threat < SECBOT_THREAT_ATTACK) if(awaiting_surrender == -1) begin_arrest(target, threat) ++awaiting_surrender else - UnarmedAttack(target) + UnarmedAttack(target, TRUE) -/mob/living/bot/secbot/proc/cuff_target(var/mob/living/carbon/C) - if(istype(C) && !C.handcuffed) - handcuffs.place_handcuffs(C, src) - resetTarget() //we're done, failed or not. Don't want to get stuck if C is not +/mob/living/bot/secbot/proc/cuff_target(var/mob/living/target) + if(istype(target) && !target.get_equipped_item(slot_handcuffed_str)) + handcuffs.place_handcuffs(target, src) + resetTarget() //we're done, failed or not. Don't want to get stuck if target is not -/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity) - if(!..()) - return +/mob/living/bot/get_target_zone() + if(!client) + return BP_CHEST + return ..() +/mob/living/bot/secbot/ResolveUnarmedAttack(var/mob/M) if(!istype(M)) - return + return FALSE - var/mob/living/carbon/human/H = M - if(istype(H) && H.lying) + var/mob/living/human/H = M + if(istype(H) && H.current_posture.prone) cuff_target(H) - return + return TRUE - if(istype(M, /mob/living/simple_animal)) - a_intent = I_HURT + if(isanimal(M)) + set_intent(I_FLAG_HARM) else - a_intent = I_GRAB + set_intent(I_FLAG_GRAB) - stun_baton.attack(M, src, BP_CHEST) //robots and turrets aim for center of mass + stun_baton.use_on_mob(M, src) //robots and turrets aim for center of mass flick(attack_state, src) + return TRUE -/mob/living/bot/secbot/explode() - visible_message("[src] blows apart!") - var/turf/Tsec = get_turf(src) - new /obj/item/assembly/prox_sensor(Tsec) - new /obj/item/baton(Tsec) - if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - - new /obj/effect/decal/cleanable/blood/oil(Tsec) - qdel(src) +/mob/living/bot/secbot/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(. && my_turf) + new /obj/item/assembly/prox_sensor(my_turf) + new /obj/item/baton(my_turf) + if(prob(50)) + new /obj/item/robot_parts/l_arm(my_turf) /mob/living/bot/secbot/proc/target_name(mob/living/T) if(ishuman(T)) - var/mob/living/carbon/human/H = T + var/mob/living/human/H = T return H.get_id_name("unidentified person") return "unidentified lifeform" diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm new file mode 100644 index 000000000000..7fbab9b36654 --- /dev/null +++ b/code/modules/mob/living/brain/brain.dm @@ -0,0 +1,114 @@ +/mob/living/brain + name = "brain" + icon = 'icons/obj/surgery.dmi' + icon_state = "brain1" + + // Used for EMP damage when inside an interface or robobrain. + var/emp_damage = 0 + var/last_emp_message = 0 + var/static/max_emp_damage = 30 + var/static/list/emp_reboot_strings = list( + SPAN_NOTICE("System reboot nearly complete."), + SPAN_NOTICE("Primary systems are now online."), + SPAN_DANGER("Major electrical distruption detected: System rebooting.") + ) + +/mob/living/brain/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/audible/alarm, + /decl/emote/audible/alert, + /decl/emote/audible/notice, + /decl/emote/audible/whistle, + /decl/emote/audible/synth, + /decl/emote/audible/boop, + /decl/emote/visible/blink, + /decl/emote/visible/flash + ) + return default_emotes + +/mob/living/brain/is_deaf() + return emp_damage || stat == DEAD || !is_in_interface() + +/mob/living/brain/is_blind() + return emp_damage || stat == DEAD || !is_in_interface() + +/mob/living/brain/Logout() + . = ..() + var/obj/item/organ/internal/container = get_container() + if(istype(container)) + container.queue_icon_update() + +/mob/living/brain/proc/get_container() + return get_recursive_loc_of_type(/obj/item/organ/internal) + +/mob/living/brain/Login() + . = ..() + var/obj/item/organ/internal/container = get_container() + if(istype(container)) + var/obj/item/organ/internal/brain_interface/interface = container + if(istype(interface)) + interface.locked = TRUE + container.update_icon() + +/mob/living/brain/proc/is_in_interface() + var/container = get_container() + return istype(container, /obj/item/organ/internal/brain_interface) || istype(container, /obj/item/organ/internal/brain/robotic) + +/mob/living/brain/can_emote(emote_type, show_message) + return is_in_interface() && ..() + +/mob/living/brain/can_use_rig() + return is_in_interface() + +/mob/living/brain/Destroy() + ghostize() + . = ..() + +/mob/living/brain/say_understands(var/other) + . = ishuman(other) || (is_in_interface() && issilicon(other)) || ..() + +/mob/living/brain/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing + ) + return available_postures + +/mob/living/brain/isSynthetic() + return istype(get_container(), /obj/item/organ/internal/brain/robotic) + +/mob/living/brain/binarycheck() + return isSynthetic() + +/mob/living/brain/check_has_mouth() + return FALSE + +/mob/living/brain/emp_act(severity) + if(!isSynthetic()) + return + switch(severity) + if(1) + emp_damage += rand(20,30) + if(2) + emp_damage += rand(10,20) + if(3) + emp_damage += rand(0,10) + emp_damage = clamp(emp_damage, 0, max_emp_damage) + +/mob/living/brain/handle_regular_status_updates() // Status & health update, are we dead or alive, can we communicate, etc. + . = ..() + if(emp_damage || stat == DEAD || !is_in_interface()) + SET_STATUS_MAX(src, STAT_SILENCE, 2) + if(stat == DEAD || !isSynthetic()) + emp_damage = 0 + return + if(emp_damage <= 0) + return + emp_damage -= 1 + var/msg_threshold = clamp(ceil(emp_damage / (max_emp_damage / length(emp_reboot_strings))), 1, length(emp_reboot_strings)) + if(last_emp_message != msg_threshold) + last_emp_message = msg_threshold + to_chat(src, emp_reboot_strings[msg_threshold]) + if(emp_damage <= 0) + last_emp_message = 0 + emp_damage = 0 + to_chat(src, SPAN_NOTICE("All systems restored.")) \ No newline at end of file diff --git a/code/modules/mob/living/brain/death.dm b/code/modules/mob/living/brain/death.dm new file mode 100644 index 000000000000..1c185d241c60 --- /dev/null +++ b/code/modules/mob/living/brain/death.dm @@ -0,0 +1,25 @@ +/mob/living/brain/get_death_message(gibbed) + var/obj/item/organ/internal/brain_interface/container = get_container() + if(!gibbed && istype(container)) + return "beeps shrilly as \the [container] flatlines!" + return ..() + +/mob/living/brain/death(gibbed) + var/obj/item/organ/holder = loc + var/obj/item/organ/internal/brain_interface/container = get_container() + . = ..() + if(.) + if(stat == DEAD && istype(holder)) + holder.die() + if(istype(container) && !QDELETED(container)) + container.update_icon() + +/mob/living/brain/gib(do_gibs = TRUE) + var/obj/item/organ/internal/brain_interface/container = get_container() + var/obj/item/organ/internal/brain/sponge = loc + . = ..() + if(.) + if(istype(container) && !QDELETED(container)) + qdel(container) + if(istype(sponge) && !QDELETED(sponge)) + qdel(sponge) diff --git a/code/modules/mob/living/brain/say.dm b/code/modules/mob/living/brain/say.dm new file mode 100644 index 000000000000..c2542360968b --- /dev/null +++ b/code/modules/mob/living/brain/say.dm @@ -0,0 +1,16 @@ +/mob/living/brain/say(var/message, var/decl/language/speaking, var/verb = "says", whispering) + if(GET_STATUS(src, STAT_SILENCE) || !is_in_interface()) + return + if(prob(emp_damage*4)) + if(prob(10)) + return + message = Gibberish(message, (emp_damage*6)) + . = ..(message, speaking, verb, whispering) + var/obj/item/radio/radio = get_radio() + if(radio) + radio.hear_talk(src, sanitize(message), verb, speaking) + +/mob/living/brain/get_radio() + var/obj/item/organ/internal/brain_interface/container = get_container() + if(istype(container)) + return container.get_radio() diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm deleted file mode 100644 index fcfbeb47140b..000000000000 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ /dev/null @@ -1,35 +0,0 @@ -/mob/living/carbon/alien - name = "alien" - desc = "What IS that?" - pass_flags = PASS_FLAG_TABLE - health = 100 - maxHealth = 100 - mob_size = MOB_SIZE_TINY - var/dead_icon - var/language - var/death_msg = "lets out a waning guttural screech, green blood bubbling from its maw." - var/instance_num - -/mob/living/carbon/alien/Initialize() - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide - - instance_num = rand(1, 1000) - name = "[initial(name)] ([instance_num])" - real_name = name - regenerate_icons() - - if(language) - add_language(language) - - gender = NEUTER - . = ..() - -/mob/living/carbon/alien/u_equip(obj/item/W) - return - -/mob/living/carbon/alien/restrained() - return 0 - -/mob/living/carbon/alien/show_inv(mob/user) - return //Consider adding cuffs and hats to this, for the sake of fun. \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien_attacks.dm b/code/modules/mob/living/carbon/alien/alien_attacks.dm deleted file mode 100644 index 6c4e4060d45b..000000000000 --- a/code/modules/mob/living/carbon/alien/alien_attacks.dm +++ /dev/null @@ -1,40 +0,0 @@ -//can't equip anything -/mob/living/carbon/alien/attack_ui(slot_id) - return - -/mob/living/carbon/alien/attack_hand(mob/living/carbon/M) - - switch(M.a_intent) - - if(I_GRAB) - return ..() - - if (I_HELP) - help_shake_act(M) - - else - var/damage = rand(1, 9) - if (prob(90)) - if (MUTATION_HULK in M.mutations) - damage += 5 - spawn(0) - Paralyse(1) - step_away(src,M,15) - sleep(3) - step_away(src,M,15) - playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\The [M] has punched \the [src]!", 1) - if (damage > 4.9) - Weaken(rand(10,15)) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\The [M] has weakened \the [src]!", 1, "You hear someone fall.", 2) - adjustBruteLoss(damage) - updatehealth() - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\The [M] has attempted to punch \the [src]!", 1) diff --git a/code/modules/mob/living/carbon/alien/alien_damage.dm b/code/modules/mob/living/carbon/alien/alien_damage.dm deleted file mode 100644 index c0d262f35f3c..000000000000 --- a/code/modules/mob/living/carbon/alien/alien_damage.dm +++ /dev/null @@ -1,22 +0,0 @@ -/mob/living/carbon/alien/explosion_act(severity) - ..() - var/b_loss = null - var/f_loss = null - switch (severity) - if (1) - b_loss += 500 - gib() - if (2.0) - b_loss += 60 - f_loss += 60 - ear_damage += 30 - ear_deaf += 120 - if(3) - b_loss += 30 - if (prob(50)) - Paralyse(1) - ear_damage += 15 - ear_deaf += 60 - adjustBruteLoss(b_loss) - adjustFireLoss(f_loss) - updatehealth() diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm deleted file mode 100644 index 87990ae75645..000000000000 --- a/code/modules/mob/living/carbon/alien/death.dm +++ /dev/null @@ -1,4 +0,0 @@ -/mob/living/carbon/alien/death(gibbed) - if(!gibbed && dead_icon) - icon_state = dead_icon - return ..(gibbed,death_msg) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm deleted file mode 100644 index c048116f730c..000000000000 --- a/code/modules/mob/living/carbon/alien/life.dm +++ /dev/null @@ -1,138 +0,0 @@ -// Alien larva are quite simple. -/mob/living/carbon/alien/Life() - - set invisibility = 0 - set background = 1 - - if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return - if(!loc) return - - ..() - - blinded = null - - //Status updates, death etc. - update_icons() - -/mob/living/carbon/alien/handle_mutations_and_radiation() - - if(!radiation) - return - - var/rads = radiation/25 - radiation -= rads - adjust_nutrition(rads) - heal_overall_damage(rads,rads) - adjustOxyLoss(-(rads)) - adjustToxLoss(-(rads)) - return - -/mob/living/carbon/alien/handle_regular_status_updates() - - if(status_flags & GODMODE) return 0 - - if(stat == DEAD) - blinded = 1 - silent = 0 - else - updatehealth() - if(health <= 0) - death() - blinded = 1 - silent = 0 - return 1 - - if(paralysis && paralysis > 0) - blinded = 1 - set_stat(UNCONSCIOUS) - if(getHalLoss() > 0) - adjustHalLoss(-3) - - if(sleeping) - adjustHalLoss(-3) - if (mind) - if(mind.active && client != null) - sleeping = max(sleeping-1, 0) - blinded = 1 - set_stat(UNCONSCIOUS) - else if(resting) - if(getHalLoss() > 0) - adjustHalLoss(-3) - - else - set_stat(CONSCIOUS) - if(getHalLoss() > 0) - adjustHalLoss(-1) - - // Eyes and blindness. - if(!check_has_eyes()) - eye_blind = 1 - blinded = 1 - eye_blurry = 1 - else if(eye_blind) - eye_blind = max(eye_blind-1,0) - blinded = 1 - else if(eye_blurry) - eye_blurry = max(eye_blurry-1, 0) - - update_icons() - - return 1 - -/mob/living/carbon/alien/handle_regular_hud_updates() - update_sight() - if (healths) - if(stat != DEAD) - switch(health) - if(100 to INFINITY) - healths.icon_state = "health0" - if(80 to 100) - healths.icon_state = "health1" - if(60 to 80) - healths.icon_state = "health2" - if(40 to 60) - healths.icon_state = "health3" - if(20 to 40) - healths.icon_state = "health4" - if(0 to 20) - healths.icon_state = "health5" - else - healths.icon_state = "health6" - else - healths.icon_state = "health7" - - if(stat != DEAD) - if(blinded) - overlay_fullscreen("blind", /obj/screen/fullscreen/blind) - else - clear_fullscreen("blind") - set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) - set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) - set_fullscreen(drugged, "high", /obj/screen/fullscreen/high) - if(machine) - if(machine.check_eye(src) < 0) - reset_view(null) - else - if(client && !client.adminobs) - reset_view(null) - - return 1 - -/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment) - // Both alien subtypes survive in vaccum and suffer in high temperatures, - // so I'll just define this once, for both (see radiation comment above) - if(!environment) return - - if(environment.temperature > (T0C+66)) - adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing. - if (fire) fire.icon_state = "fire2" - if(prob(20)) - to_chat(src, "You feel a searing heat!") - else - if (fire) fire.icon_state = "fire0" - -/mob/living/carbon/alien/handle_fire() - if(..()) - return - bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up! - return diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm deleted file mode 100644 index ba4c626eae5c..000000000000 --- a/code/modules/mob/living/carbon/alien/say.dm +++ /dev/null @@ -1,25 +0,0 @@ -/mob/living/carbon/alien/say(var/message) - var/verb = "says" - var/message_range = world.view - - if(client) - if(client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot speak in IC (Muted).") - return - - message = sanitize(message) - - if(stat == 2) - return say_dead(message) - - if(copytext(message,1,2) == get_prefix_key(/decl/prefix/custom_emote)) - return emote(copytext(message,2)) - - var/decl/language/speaking = parse_language(message) - - message = trim(message) - - if(!message || stat) - return - - ..(message, speaking, verb, null, null, message_range, null) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm deleted file mode 100644 index 748b863815ed..000000000000 --- a/code/modules/mob/living/carbon/alien/update_icons.dm +++ /dev/null @@ -1,3 +0,0 @@ -/mob/living/carbon/alien/regenerate_icons() - overlays.Cut() - update_icons() diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm deleted file mode 100644 index 6120e799e596..000000000000 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ /dev/null @@ -1,195 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/mmi/digital/Initialize() - src.brainmob = new(src) - src.brainmob.set_stat(CONSCIOUS) - src.brainmob.add_language("Robot Talk") - src.brainmob.add_language("Encoded Audio Language") - - src.brainmob.container = src - src.brainmob.silent = 0 - PickName() - . = ..() - -/obj/item/mmi/digital/proc/PickName() - return - -/obj/item/mmi/digital/attackby() - return - -/obj/item/mmi/digital/attack_self() - return - -/obj/item/mmi/digital/transfer_identity(var/mob/living/carbon/H) - brainmob.dna = H.dna - brainmob.timeofhostdeath = H.timeofdeath - brainmob.set_stat(CONSCIOUS) - if(H.mind) - H.mind.transfer_to(brainmob) - return - -/obj/item/mmi - name = "\improper Man-Machine Interface" - desc = "A complex life support shell that interfaces between a brain and electronic devices." - icon = 'icons/obj/assemblies.dmi' - icon_state = "mmi_empty" - w_class = ITEM_SIZE_NORMAL - origin_tech = "{'biotech':3}" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - req_access = list(access_robotics) - - //Revised. Brainmob is now contained directly within object of transfer. MMI in this case. - - var/locked = 0 - var/mob/living/carbon/brain/brainmob = null//The current occupant. - var/obj/item/organ/internal/brain/brainobj = null //The current brain organ. - -/obj/item/mmi/attackby(var/obj/item/O, var/mob/user) - if(istype(O,/obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO - - var/obj/item/organ/internal/brain/B = O - if(B.damage >= B.max_damage) - to_chat(user, "That brain is well and truly dead.") - return - else if(!B.brainmob || !B.can_use_mmi) - to_chat(user, "This brain is completely useless to you.") - return - if(!user.unEquip(O, src)) - return - user.visible_message("\The [user] sticks \a [O] into \the [src].") - - brainmob = B.brainmob - B.brainmob = null - brainmob.forceMove(src) - brainmob.container = src - brainmob.set_stat(CONSCIOUS) - brainmob.switch_from_dead_to_living_mob_list() //Update dem lists - - brainobj = O - - SetName("[initial(name)]: ([brainmob.real_name])") - update_icon() - - locked = 1 - - SSstatistics.add_field("cyborg_mmis_filled",1) - - return - - if((istype(O,/obj/item/card/id)||istype(O,/obj/item/modular_computer)) && brainmob) - if(allowed(user)) - locked = !locked - to_chat(user, "You [locked ? "lock" : "unlock"] the brain holder.") - else - to_chat(user, "Access denied.") - return - if(brainmob) - O.attack(brainmob, user)//Oh noooeeeee - return - ..() - - //TODO: ORGAN REMOVAL UPDATE. Make the brain remain in the MMI so it doesn't lose organ data. -/obj/item/mmi/attack_self(mob/user) - if(!brainmob) - to_chat(user, "You upend the MMI, but there's nothing in it.") - else if(locked) - to_chat(user, "You upend the MMI, but the brain is clamped into place.") - else - to_chat(user, "You upend the MMI, spilling the brain onto the floor.") - var/obj/item/organ/internal/brain/brain - if (brainobj) //Pull brain organ out of MMI. - brainobj.forceMove(user.loc) - brain = brainobj - brainobj = null - else //Or make a new one if empty. - brain = new(user.loc) - brainmob.container = null//Reset brainmob mmi var. - brainmob.forceMove(brain)//Throw mob into brain. - brainmob.remove_from_living_mob_list() //Get outta here - brain.brainmob = brainmob//Set the brain to use the brainmob - brainmob = null//Set mmi brainmob var to null - - update_icon() - SetName(initial(name)) - -/obj/item/mmi/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->robot people. - brainmob = new(src) - brainmob.SetName(H.real_name) - brainmob.real_name = H.real_name - brainmob.dna = H.dna - brainmob.container = src - - SetName("[initial(name)]: [brainmob.real_name]") - update_icon() - locked = 1 - return - -/obj/item/mmi/relaymove(var/mob/user, var/direction) - if(user.stat || user.stunned) - return - var/obj/item/rig/rig = src.get_rig() - if(rig) - rig.forced_move(direction, user) - -/obj/item/mmi/Destroy() - if(isrobot(loc)) - var/mob/living/silicon/robot/borg = loc - borg.mmi = null - QDEL_NULL(brainmob) - return ..() - -/obj/item/mmi/radio_enabled - name = "radio-enabled man-machine interface" - desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio." - origin_tech = "{'biotech':4}" - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - var/obj/item/radio/radio = null//Let's give it a radio. - -/obj/item/mmi/radio_enabled/Initialize() - . = ..() - radio = new(src)//Spawns a radio inside the MMI. - radio.broadcasting = 1//So it's broadcasting from the start. - -/obj/item/mmi/radio_enabled/verb/Toggle_Broadcasting() //Allows the brain to toggle the radio functions. - set name = "Toggle Broadcasting" - set desc = "Toggle broadcasting channel on or off." - set category = "MMI" - set src = usr.loc//In user location, or in MMI in this case. - set popup_menu = 0//Will not appear when right clicking. - - if(brainmob.stat)//Only the brainmob will trigger these so no further check is necessary. - to_chat(brainmob, "Can't do that while incapacitated or dead.") - - radio.broadcasting = radio.broadcasting==1 ? 0 : 1 - to_chat(brainmob, "Radio is [radio.broadcasting==1 ? "now" : "no longer"] broadcasting.") - -/obj/item/mmi/radio_enabled/verb/Toggle_Listening() - set name = "Toggle Listening" - set desc = "Toggle listening channel on or off." - set category = "MMI" - set src = usr.loc - set popup_menu = 0 - - if(brainmob.stat) - to_chat(brainmob, "Can't do that while incapacitated or dead.") - - radio.listening = radio.listening==1 ? 0 : 1 - to_chat(brainmob, "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast.") - -/obj/item/mmi/emp_act(severity) - if(!brainmob) - return - else - switch(severity) - if(1) - brainmob.emp_damage += rand(20,30) - if(2) - brainmob.emp_damage += rand(10,20) - if(3) - brainmob.emp_damage += rand(0,10) - ..() - -/obj/item/mmi/on_update_icon() - icon_state = brainmob ? "mmi_full" : "mmi_empty" diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm deleted file mode 100644 index 157011702f15..000000000000 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ /dev/null @@ -1,57 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/mob/living/carbon/brain - var/obj/item/container = null - var/timeofhostdeath = 0 - var/emp_damage = 0//Handles a type of MMI damage - var/alert = null - use_me = 0 //Can't use the me verb, it's a freaking immobile brain - icon = 'icons/obj/surgery.dmi' - icon_state = "brain1" - -/mob/living/carbon/brain/Initialize() - create_reagents(1000) - . = ..() - -/mob/living/carbon/brain/Destroy() - if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. - if(stat!=DEAD) //If not dead. - death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA - ghostize() //Ghostize checks for key so nothing else is necessary. - . = ..() - -/mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd - if (istype(other, /mob/living/silicon/ai)) - if(!(container && istype(container, /obj/item/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/silicon/pai)) - if(!(container && istype(container, /obj/item/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/silicon/robot)) - if(!(container && istype(container, /obj/item/mmi))) - return 0 - else - return 1 - if (istype(other, /mob/living/carbon/human)) - return 1 - if (istype(other, /mob/living/carbon/slime)) - return 1 - return ..() - -/mob/living/carbon/brain/UpdateLyingBuckledAndVerbStatus() - if(istype(loc, /obj/item/mmi)) - use_me = 1 - -/mob/living/carbon/brain/isSynthetic() - return istype(loc, /obj/item/mmi/digital) - -/mob/living/carbon/brain/binarycheck() - return isSynthetic() - -/mob/living/carbon/brain/check_has_mouth() - return 0 - diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm deleted file mode 100644 index d233026468b6..000000000000 --- a/code/modules/mob/living/carbon/brain/death.dm +++ /dev/null @@ -1,14 +0,0 @@ -/mob/living/carbon/brain/death(gibbed) - if(!gibbed && istype(container, /obj/item/mmi)) //If not gibbed but in a container. - container.icon_state = "mmi_dead" - return ..(gibbed,"beeps shrilly as the MMI flatlines!") - else - return ..(gibbed,"no message") - -/mob/living/carbon/brain/gib() - if(istype(container, /obj/item/mmi)) - qdel(container)//Gets rid of the MMI if there is one - if(loc) - if(istype(loc,/obj/item/organ/internal/brain)) - qdel(loc)//Gets rid of the brain item - ..(null,1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm deleted file mode 100644 index 95b76253e848..000000000000 --- a/code/modules/mob/living/carbon/brain/life.dm +++ /dev/null @@ -1,195 +0,0 @@ -/mob/living/carbon/brain/handle_breathing() - return - -/mob/living/carbon/brain/handle_mutations_and_radiation() - if (radiation) - if (radiation > 100) - radiation = 100 - if(!container)//If it's not in an MMI - to_chat(src, "You feel weak.") - else//Fluff-wise, since the brain can't detect anything itself, the MMI handles thing like that - to_chat(src, "STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED.") - switch(radiation) - if(1 to 49) - radiation-- - if(prob(25)) - adjustToxLoss(1) - updatehealth() - - if(50 to 74) - radiation -= 2 - adjustToxLoss(1) - if(prob(5)) - radiation -= 5 - if(!container) - to_chat(src, "You feel weak.") - else - to_chat(src, "STATUS: DANGEROUS LEVELS OF RADIATION DETECTED.") - updatehealth() - - if(75 to 100) - radiation -= 3 - adjustToxLoss(3) - updatehealth() - - -/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment) - if(!environment) - return - var/environment_heat_capacity = environment.heat_capacity() - if(istype(get_turf(src), /turf/space)) - var/turf/heat_turf = get_turf(src) - environment_heat_capacity = heat_turf.heat_capacity - - if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10))) - var/transfer_coefficient = 1 - - handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient) - - if(stat==2) - bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000) - - //Account for massive pressure differences - - return //TODO: DEFERRED - -/mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity) - if(status_flags & GODMODE) return - - if(exposed_temperature > bodytemperature) - var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0) - //adjustFireLoss(2.5*discomfort) - //adjustFireLoss(5.0*discomfort) - adjustFireLoss(20.0*discomfort) - - else - var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0) - //adjustFireLoss(2.5*discomfort) - adjustFireLoss(5.0*discomfort) - - -/mob/living/carbon/brain/handle_chemicals_in_body() - chem_effects.Cut() - - if(touching) touching.metabolize() - var/datum/reagents/metabolism/ingested = get_ingested_reagents() - if(istype(ingested)) ingested.metabolize() - if(bloodstr) bloodstr.metabolize() - - handle_confused() - // decrement dizziness counter, clamped to 0 - if(resting) - dizziness = max(0, dizziness - 5) - else - dizziness = max(0, dizziness - 1) - - updatehealth() - - return //TODO: DEFERRED - -/mob/living/carbon/brain/handle_regular_status_updates() //TODO: comment out the unused bits >_> - updatehealth() - - if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP - blinded = 1 - silent = 0 - else //ALIVE. LIGHTS ARE ON - if( !container && (health < config.health_threshold_dead || ((world.time - timeofhostdeath) > config.revival_brain_life)) ) - death() - blinded = 1 - silent = 0 - return 1 - - //Handling EMP effect in the Life(), it's made VERY simply, and has some additional effects handled elsewhere - if(emp_damage) //This is pretty much a damage type only used by MMIs, dished out by the emp_act - if(!(container && istype(container, /obj/item/mmi))) - emp_damage = 0 - else - emp_damage = round(emp_damage,1)//Let's have some nice numbers to work with - switch(emp_damage) - if(31 to INFINITY) - emp_damage = 30//Let's not overdo it - if(21 to 30)//High level of EMP damage, unable to see, hear, or speak - eye_blind = 1 - blinded = 1 - ear_deaf = 1 - silent = 1 - if(!alert)//Sounds an alarm, but only once per 'level' - emote("alarm") - to_chat(src, "Major electrical distruption detected: System rebooting.") - alert = 1 - if(prob(75)) - emp_damage -= 1 - if(20) - alert = 0 - blinded = 0 - eye_blind = 0 - ear_deaf = 0 - silent = 0 - emp_damage -= 1 - if(11 to 19)//Moderate level of EMP damage, resulting in nearsightedness and ear damage - eye_blurry = 1 - ear_damage = 1 - if(!alert) - emote("alert") - to_chat(src, "Primary systems are now online.") - alert = 1 - if(prob(50)) - emp_damage -= 1 - if(10) - alert = 0 - eye_blurry = 0 - ear_damage = 0 - emp_damage -= 1 - if(2 to 9)//Low level of EMP damage, has few effects(handled elsewhere) - if(!alert) - emote("notice") - to_chat(src, "System reboot nearly complete.") - alert = 1 - if(prob(25)) - emp_damage -= 1 - if(1) - alert = 0 - to_chat(src, "All systems restored.") - emp_damage -= 1 - - return 1 - -/mob/living/carbon/brain/handle_regular_hud_updates() - update_sight() - if (healths) - if (stat != 2) - switch(health) - if(100 to INFINITY) - healths.icon_state = "health0" - if(80 to 100) - healths.icon_state = "health1" - if(60 to 80) - healths.icon_state = "health2" - if(40 to 60) - healths.icon_state = "health3" - if(20 to 40) - healths.icon_state = "health4" - if(0 to 20) - healths.icon_state = "health5" - else - healths.icon_state = "health6" - else - healths.icon_state = "health7" - - if(stat != DEAD) - if(blinded) - overlay_fullscreen("blind", /obj/screen/fullscreen/blind) - else - clear_fullscreen("blind") - set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) - set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) - set_fullscreen(drugged, "high", /obj/screen/fullscreen/high) - if (machine) - if (!( machine.check_eye(src) )) - reset_view(null) - else - if(client && !client.adminobs) - reset_view(null) - - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/login.dm b/code/modules/mob/living/carbon/brain/login.dm deleted file mode 100644 index 57c41cc659bc..000000000000 --- a/code/modules/mob/living/carbon/brain/login.dm +++ /dev/null @@ -1,3 +0,0 @@ -/mob/living/carbon/brain/Login() - ..() - sleeping = 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/robot.dm b/code/modules/mob/living/carbon/brain/robot.dm deleted file mode 100644 index 59b26db26d2a..000000000000 --- a/code/modules/mob/living/carbon/brain/robot.dm +++ /dev/null @@ -1,18 +0,0 @@ -/obj/item/mmi/digital/robot - name = "robotic intelligence circuit" - desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science." - icon = 'icons/obj/module.dmi' - icon_state = "mainboard" - w_class = ITEM_SIZE_NORMAL - origin_tech = "{'engineering':4,'materials':3,'programming':4}" - -/obj/item/mmi/digital/robot/PickName() - src.brainmob.SetName("[pick(list("ADA","DOS","GNU","MAC","WIN"))]-[random_id(type,1000,9999)]") - src.brainmob.real_name = src.brainmob.name - -/obj/item/mmi/digital/robot/transfer_identity(var/mob/living/carbon/H) - ..() - if(brainmob.mind) - brainmob.mind.assigned_role = "Robotic Intelligence" - to_chat(brainmob, "You feel slightly disoriented. That's normal when you're little more than a complex circuit.") - return diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm deleted file mode 100644 index a884a2f633ca..000000000000 --- a/code/modules/mob/living/carbon/brain/say.dm +++ /dev/null @@ -1,38 +0,0 @@ -//TODO: Convert this over for languages. -/mob/living/carbon/brain/say(var/message) - if (silent) - return - - message = sanitize(message) - - if(!(container && istype(container, /obj/item/mmi))) - return //No MMI, can't speak, bucko./N - else - var/decl/language/speaking = parse_language(message) - if(speaking) - message = copytext(message, 2+length(speaking.key)) - var/verb = "says" - var/ending = copytext(message, length(message)) - if (speaking) - verb = speaking.get_spoken_verb(ending) - else - if(ending=="!") - verb=pick("exclaims","shouts","yells") - if(ending=="?") - verb="asks" - - if(prob(emp_damage*4)) - if(prob(10))//10% chane to drop the message entirely - return - else - message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher - - if(speaking && speaking.flags & HIVEMIND) - speaking.broadcast(src,trim(message)) - return - - if(istype(container, /obj/item/mmi/radio_enabled)) - var/obj/item/mmi/radio_enabled/R = container - if(R.radio) - spawn(0) R.radio.hear_talk(src, sanitize(message), verb, speaking) - ..(trim(message), speaking, verb) diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm deleted file mode 100644 index f29b0be4082d..000000000000 --- a/code/modules/mob/living/carbon/breathe.dm +++ /dev/null @@ -1,98 +0,0 @@ -//Common breathing procs - -#define MOB_BREATH_DELAY 2 - -//Start of a breath chain, calls breathe() -/mob/living/carbon/handle_breathing() - if((life_tick % MOB_BREATH_DELAY) == 0 || failed_last_breath || is_asystole()) //First, resolve location and get a breath - breathe() - -/mob/living/carbon/proc/breathe(var/active_breathe = 1) - - if(!need_breathe()) return - - var/datum/gas_mixture/breath = null - - //First, check if we can breathe at all - if(handle_drowning() || (is_asystole() && !(CE_STABLE in chem_effects) && active_breathe)) //crit aka circulatory shock - losebreath = max(2, losebreath + 1) - - if(losebreath>0) //Suffocating so do not take a breath - losebreath-- - if (prob(10) && !is_asystole() && active_breathe) //Gasp per 10 ticks? Sounds about right. - INVOKE_ASYNC(src, .proc/emote, "gasp") - else - //Okay, we can breathe, now check if we can get air - var/volume_needed = get_breath_volume() - breath = get_breath_from_internal(volume_needed) //First, check for air from internals - if(!breath) - breath = get_breath_from_environment(volume_needed) //No breath from internals so let's try to get air from our location - if(!breath) - var/static/datum/gas_mixture/vacuum //avoid having to create a new gas mixture for each breath in space - if(!vacuum) vacuum = new - - breath = vacuum //still nothing? must be vacuum - - handle_breath(breath) - handle_post_breath(breath) - -/mob/living/carbon/proc/get_breath_from_internal(var/volume_needed=STD_BREATH_VOLUME) //hopefully this will allow overrides to specify a different default volume without breaking any cases where volume is passed in. - if(internal) - if (!contents.Find(internal)) - set_internals(null) - if (!(wear_mask && (wear_mask.item_flags & ITEM_FLAG_AIRTIGHT))) - set_internals(null) - if(internal) - if (internals) - internals.icon_state = "internal1" - return internal.remove_air_volume(volume_needed) - else - if (internals) - internals.icon_state = "internal0" - return null - -/mob/living/carbon/proc/get_breath_from_environment(var/volume_needed=STD_BREATH_VOLUME) - if(volume_needed <= 0) - return - var/datum/gas_mixture/breath = null - - var/datum/gas_mixture/environment - if(loc) - environment = loc.return_air() - - if(environment) - breath = environment.remove_volume(volume_needed) - handle_chemical_smoke(environment) //handle chemical smoke while we're at it - - if(breath && breath.total_moles) - //handle mask filtering - if(istype(wear_mask, /obj/item/clothing/mask) && breath) - var/obj/item/clothing/mask/M = wear_mask - var/datum/gas_mixture/filtered = M.filter_air(breath) - loc.assume_air(filtered) - return breath - return null - -//Handle possble chem smoke effect -/mob/living/carbon/proc/handle_chemical_smoke(var/datum/gas_mixture/environment) - if(species && environment.return_pressure() < species.breath_pressure/5) - return //pressure is too low to even breathe in. - if(wear_mask && (wear_mask.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) - return - - for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) - if(smoke.reagents.total_volume) - smoke.reagents.trans_to_mob(src, 5, CHEM_INGEST, copy = 1) - smoke.reagents.trans_to_mob(src, 5, CHEM_INJECT, copy = 1) - // I dunno, maybe the reagents enter the blood stream through the lungs? - break // If they breathe in the nasty stuff once, no need to continue checking - -/mob/living/carbon/proc/get_breath_volume() - return STD_BREATH_VOLUME - -/mob/living/carbon/proc/handle_breath(datum/gas_mixture/breath) - return - -/mob/living/carbon/proc/handle_post_breath(datum/gas_mixture/breath) - if(breath) - loc.assume_air(breath) //by default, exhale diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm deleted file mode 100644 index fb72f535ea7f..000000000000 --- a/code/modules/mob/living/carbon/carbon.dm +++ /dev/null @@ -1,516 +0,0 @@ -/mob/living/carbon/Initialize() - //setup reagent holders - bloodstr = new/datum/reagents/metabolism(120, src, CHEM_INJECT) - touching = new/datum/reagents/metabolism(1000, src, CHEM_TOUCH) - reagents = bloodstr - - if (!default_language && species_language) - default_language = species_language - . = ..() - -/mob/living/carbon/Destroy() - QDEL_NULL(touching) - bloodstr = null // We don't qdel(bloodstr) because it's the same as qdel(reagents) - QDEL_NULL_LIST(internal_organs) - QDEL_NULL_LIST(hallucinations) - if(loc) - for(var/mob/M in contents) - M.dropInto(loc) - else - for(var/mob/M in contents) - qdel(M) - return ..() - -/mob/living/carbon/rejuvenate() - bloodstr.clear_reagents() - touching.clear_reagents() - var/datum/reagents/R = get_ingested_reagents() - if(istype(R)) - R.clear_reagents() - set_nutrition(400) - set_hydration(400) - ..() - -/mob/living/carbon/get_ai_type() - if(ispath(species?.ai)) - return species.ai - return ..() - -/mob/living/carbon/Move(NewLoc, direct) - . = ..() - if(!.) - return - - if(stat != DEAD) - - if((MUTATION_FAT in src.mutations) && (move_intent.flags & MOVE_INTENT_EXERTIVE) && src.bodytemperature <= 360) - bodytemperature += 2 - - var/nut_removed = DEFAULT_HUNGER_FACTOR/10 - var/hyd_removed = DEFAULT_THIRST_FACTOR/10 - if (move_intent.flags & MOVE_INTENT_EXERTIVE) - nut_removed *= 2 - hyd_removed *= 2 - adjust_nutrition(-nut_removed) - adjust_hydration(-hyd_removed) - - // Moving around increases germ_level faster - if(germ_level < GERM_LEVEL_MOVE_CAP && prob(8)) - germ_level++ - -/mob/living/carbon/relaymove(var/mob/living/user, direction) - if((user in contents) && istype(user)) - if(user.last_special <= world.time) - user.last_special = world.time + 50 - src.visible_message("You hear something rumbling inside [src]'s stomach...") - var/obj/item/I = user.get_active_hand() - if(I && I.force) - var/d = rand(round(I.force / 4), I.force) - if(istype(src, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = src - var/obj/item/organ/external/organ = H.get_organ(BP_CHEST) - if (istype(organ)) - organ.take_external_damage(d, 0) - H.updatehealth() - else - src.take_organ_damage(d) - user.visible_message("[user] attacks [src]'s stomach wall with the [I.name]!") - playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1) - - if(prob(src.getBruteLoss() - 50)) - gib() - -/mob/living/carbon/gib() - for(var/mob/M in contents) - M.dropInto(loc) - visible_message(SPAN_DANGER("\The [M] bursts out of \the [src]!")) - ..() - -/mob/living/carbon/attack_hand(var/mob/living/carbon/human/M) - if(istype(M)) - var/obj/item/organ/external/temp = M.organs_by_name[M.hand ? BP_L_HAND : BP_R_HAND] - if(!temp || !temp.is_usable()) - to_chat(M, SPAN_WARNING("You can't use your [temp.name].")) - return TRUE - . = ..() - -/mob/living/carbon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null) - if(status_flags & GODMODE) return 0 //godmode - - shock_damage = apply_shock(shock_damage, def_zone, siemens_coeff) - - if(!shock_damage) - return 0 - - stun_effect_act(agony_amount=shock_damage, def_zone=def_zone) - - playsound(loc, "sparks", 50, 1, -1) - if (shock_damage > 15) - src.visible_message( - "[src] was electrocuted[source ? " by the [source]" : ""]!", \ - "You feel a powerful shock course through your body!", \ - "You hear a heavy electrical crack." \ - ) - else - src.visible_message( - "[src] was shocked[source ? " by the [source]" : ""].", \ - "You feel a shock course through your body.", \ - "You hear a zapping sound." \ - ) - - switch(shock_damage) - if(11 to 15) - Stun(1) - if(16 to 20) - Stun(2) - if(21 to 25) - Weaken(2) - if(26 to 30) - Weaken(5) - if(31 to INFINITY) - Weaken(10) //This should work for now, more is really silly and makes you lay there forever - - make_jittery(min(shock_damage*5, 200)) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, loc) - s.start() - - return shock_damage - -/mob/living/carbon/proc/apply_shock(var/shock_damage, var/def_zone, var/siemens_coeff = 1.0) - shock_damage *= siemens_coeff - if(shock_damage < 0.5) - return 0 - if(shock_damage < 1) - shock_damage = 1 - apply_damage(shock_damage, BURN, def_zone, used_weapon="Electrocution") - return(shock_damage) - -/mob/proc/swap_hand() - return - -/mob/living/carbon/swap_hand() - hand = !hand - if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) - if(hand) //This being 1 means the left hand is in use - hud_used.l_hand_hud_object.icon_state = "l_hand_active" - hud_used.r_hand_hud_object.icon_state = "r_hand_inactive" - else - hud_used.l_hand_hud_object.icon_state = "l_hand_inactive" - hud_used.r_hand_hud_object.icon_state = "r_hand_active" - var/obj/item/I = get_active_hand() - if(istype(I)) - I.on_active_hand() - -/mob/living/carbon/proc/activate_hand(var/selhand) //0 or "r" or "right" for right hand; 1 or "l" or "left" for left hand. - - if(istext(selhand)) - selhand = lowertext(selhand) - - if(selhand == "right" || selhand == "r") - selhand = 0 - if(selhand == "left" || selhand == "l") - selhand = 1 - - if(selhand != src.hand) - swap_hand() - -/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) - if(!is_asystole()) - if (on_fire) - playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - if (M.on_fire) - M.visible_message("[M] tries to pat out [src]'s flames, but to no avail!", - "You try to pat out [src]'s flames, but to no avail! Put yourself out first!") - else - M.visible_message("[M] tries to pat out [src]'s flames!", - "You try to pat out [src]'s flames! Hot!") - if(do_mob(M, src, 15)) - src.fire_stacks -= 0.5 - if (prob(10) && (M.fire_stacks <= 0)) - M.fire_stacks += 1 - M.IgniteMob() - if (M.on_fire) - M.visible_message("The fire spreads from [src] to [M]!", - "The fire spreads to you as well!") - else - src.fire_stacks -= 0.5 //Less effective than stop, drop, and roll - also accounting for the fact that it takes half as long. - if (src.fire_stacks <= 0) - M.visible_message("[M] successfully pats out [src]'s flames.", - "You successfully pat out [src]'s flames.") - src.ExtinguishMob() - src.fire_stacks = 0 - else - var/t_him = "it" - if (src.gender == MALE) - t_him = "him" - else if (src.gender == FEMALE) - t_him = "her" - if (istype(src,/mob/living/carbon/human) && src:w_uniform) - var/mob/living/carbon/human/H = src - H.w_uniform.add_fingerprint(M) - - var/show_ssd - var/mob/living/carbon/human/H = src - if(istype(H)) show_ssd = H.species.show_ssd - if(show_ssd && ssd_check()) - M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ - "You shake [src], but they do not respond... Maybe they have S.S.D?") - else if(lying || src.sleeping || player_triggered_sleeping) - src.player_triggered_sleeping = 0 - src.sleeping = max(0,src.sleeping - 5) - if(src.sleeping == 0) - src.resting = 0 - M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ - "You shake [src] trying to wake [t_him] up!") - else - var/mob/living/carbon/human/hugger = M - if(istype(hugger)) - hugger.species.hug(hugger,src) - else - M.visible_message("[M] hugs [src] to make [t_him] feel better!", \ - "You hug [src] to make [t_him] feel better!") - if(M.fire_stacks >= (src.fire_stacks + 3)) - src.fire_stacks += 1 - M.fire_stacks -= 1 - if(M.on_fire) - src.IgniteMob() - - if(stat != DEAD) - AdjustParalysis(-3) - AdjustStunned(-3) - AdjustWeakened(-3) - - playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - -/mob/living/carbon/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) - if(eyecheck() < intensity || override_blindness_check) - return ..() - -// ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching. -// Stop! ... Hammertime! ~Carn - -/mob/living/carbon/proc/getDNA() - return dna - -/mob/living/carbon/proc/setDNA(var/datum/dna/newDNA) - dna = newDNA - -// ++++ROCKDTBEN++++ MOB PROCS //END - -//Throwing stuff -/mob/proc/throw_item(atom/target) - return - -/mob/living/carbon/throw_item(atom/target) - src.throw_mode_off() - if(src.stat || !target) - return - if(target.type == /obj/screen) return - - var/atom/movable/item = src.get_active_hand() - - if(!item) return - - var/throw_range = item.throw_range - var/itemsize - if (istype(item, /obj/item/grab)) - var/obj/item/grab/G = item - item = G.throw_held() //throw the person instead of the grab - if(ismob(item)) - var/mob/M = item - - //limit throw range by relative mob size - throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1)) - itemsize = round(M.mob_size/4) - var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors - var/turf/end_T = get_turf(target) - if(start_T && end_T && usr == src) - var/start_T_descriptor = "[start_T] \[[start_T.x],[start_T.y],[start_T.z]\] ([start_T.loc])" - var/end_T_descriptor = "[start_T] \[[end_T.x],[end_T.y],[end_T.z]\] ([end_T.loc])" - admin_attack_log(usr, M, "Threw the victim from [start_T_descriptor] to [end_T_descriptor].", "Was from [start_T_descriptor] to [end_T_descriptor].", "threw, from [start_T_descriptor] to [end_T_descriptor], ") - - else if (istype(item, /obj/item/)) - var/obj/item/I = item - itemsize = I.w_class - - if(!unEquip(item)) - return - if(!item || !isturf(item.loc)) - return - - var/message = "\The [src] has thrown \the [item]." - var/skill_mod = 0.2 - if(!skill_check(SKILL_HAULING, min(round(itemsize - ITEM_SIZE_HUGE) + 2, SKILL_MAX))) - if(prob(30)) - Weaken(2) - message = "\The [src] barely manages to throw \the [item], and is knocked off-balance!" - else - skill_mod += 0.2 - - skill_mod += 0.8 * (get_skill_value(SKILL_HAULING) - SKILL_MIN)/(SKILL_MAX - SKILL_MIN) - throw_range *= skill_mod - - //actually throw it! - src.visible_message("[message]", range = min(itemsize*2,world.view)) - - if(!src.lastarea) - src.lastarea = get_area(src.loc) - if(!check_space_footing()) - if(prob((itemsize * itemsize * 10) * MOB_SIZE_MEDIUM/src.mob_size)) - var/direction = get_dir(target, src) - step(src,direction) - space_drift(direction) - - item.throw_at(target, throw_range, item.throw_speed * skill_mod, src) - -/mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - ..() - var/temp_inc = max(min(BODYTEMP_HEATING_MAX*(1-get_heat_protection()), exposed_temperature - bodytemperature), 0) - bodytemperature += temp_inc - -/mob/living/carbon/can_use_hands() - if(handcuffed) - return 0 - if(buckled && ! istype(buckled, /obj/structure/bed/chair)) // buckling does not restrict hands - return 0 - return 1 - -/mob/living/carbon/restrained() - if (handcuffed) - return 1 - return - -/mob/living/carbon/u_equip(obj/item/W) - if(!W) return 0 - - else if (W == handcuffed) - handcuffed = null - update_inv_handcuffed() - if(buckled && buckled.buckle_require_restraints) - buckled.unbuckle_mob() - else - ..() - - return - -/mob/living/carbon/verb/mob_sleep() - set name = "Sleep" - set category = "IC" - - if(alert("Are you sure you want to [player_triggered_sleeping ? "wake up?" : "sleep for a while? Use 'sleep' again to wake up"]", "Sleep", "No", "Yes") == "Yes") - player_triggered_sleeping = !player_triggered_sleeping - -/mob/living/carbon/Bump(var/atom/movable/AM, yes) - if(now_pushing || !yes) - return - ..() - -/mob/living/carbon/slip(slipped_on, stun_duration = 8) - if(!has_gravity()) - return FALSE - if(buckled) - return FALSE - to_chat(src, SPAN_WARNING("You slipped on [slipped_on]!")) - playsound(loc, 'sound/misc/slip.ogg', 50, 1, -3) - Weaken(Floor(stun_duration/2)) - return TRUE - -/mob/living/carbon/add_chemical_effect(var/effect, var/magnitude = 1) - if(effect in chem_effects) - chem_effects[effect] += magnitude - else - chem_effects[effect] = magnitude - -/mob/living/carbon/add_up_to_chemical_effect(var/effect, var/magnitude = 1) - if(effect in chem_effects) - chem_effects[effect] = max(magnitude, chem_effects[effect]) - else - chem_effects[effect] = magnitude - -/mob/living/carbon/get_default_language() - . = ..() - if(. && !can_speak(.)) - . = null - -/mob/living/carbon/proc/get_any_good_language(set_default=FALSE) - var/decl/language/result = get_default_language() - if (!result) - for (var/decl/language/L in languages) - if (can_speak(L)) - result = L - if (set_default) - set_default_language(result) - break - return result - -/mob/living/carbon/show_inv(mob/user) - user.set_machine(src) - var/dat = {" -
          [name]
          -

          -
          Head(Mask): [(wear_mask ? wear_mask : "Nothing")] -
          Left Hand: [(l_hand ? l_hand : "Nothing")] -
          Right Hand: [(r_hand ? r_hand : "Nothing")] -
          Back: [(back ? back : "Nothing")] [((istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank) && !( internal )) ? text(" Set Internal", src) : "")] -
          [(internal ? text("Remove Internal") : "")] -
          Empty Pockets -
          Refresh -
          Close -
          "} - show_browser(user, dat, text("window=mob[];size=325x500", name)) - onclose(user, "mob[name]") - return - -/** - * Return FALSE if victim can't be devoured, DEVOUR_FAST if they can be devoured quickly, DEVOUR_SLOW for slow devour - */ -/mob/living/carbon/proc/can_devour(atom/movable/victim) - return FALSE - -/mob/living/carbon/proc/should_have_organ(var/organ_check) - return 0 - -/mob/living/carbon/proc/can_feel_pain(var/check_organ) - if(isSynthetic()) - return 0 - return !(species && species.species_flags & SPECIES_FLAG_NO_PAIN) - -/mob/living/carbon/proc/get_adjusted_metabolism(metabolism) - return metabolism - -/mob/living/carbon/proc/need_breathe() - return - -/mob/living/carbon/check_has_mouth() - // carbon mobs have mouths by default - // behavior of this proc for humans is overridden in human.dm - return 1 - -/mob/living/carbon/proc/check_mouth_coverage() - // carbon mobs do not have blocked mouths by default - // overridden in human_defense.dm - return null - -/mob/living/carbon/proc/SetStasis(var/factor, var/source = "misc") - if((species && (species.species_flags & SPECIES_FLAG_NO_SCAN)) || isSynthetic()) - return - stasis_sources[source] = factor - -/mob/living/carbon/proc/InStasis() - if(!stasis_value) - return FALSE - return life_tick % stasis_value - -// call only once per run of life -/mob/living/carbon/proc/UpdateStasis() - stasis_value = 0 - if((species && (species.species_flags & SPECIES_FLAG_NO_SCAN)) || isSynthetic()) - return - for(var/source in stasis_sources) - stasis_value += stasis_sources[source] - stasis_sources.Cut() - -/mob/living/carbon/has_chem_effect(chem, threshold) - return (chem_effects[chem] >= threshold) - -/mob/living/carbon/get_sex() - return species.get_sex(src) - -/mob/living/carbon/proc/set_nutrition(var/amt) - nutrition = Clamp(amt, 0, initial(nutrition)) - -/mob/living/carbon/adjust_nutrition(var/amt) - set_nutrition(nutrition + amt) - -/mob/living/carbon/proc/set_hydration(var/amt) - hydration = Clamp(amt, 0, initial(hydration)) - -/mob/living/carbon/adjust_hydration(var/amt) - set_hydration(hydration + amt) - -/mob/living/carbon/proc/set_internals(obj/item/tank/source, source_string) - var/old_internal = internal - - internal = source - - if(!old_internal && internal) - if(!source_string) - source_string = source.name - to_chat(src, "You are now running on internals from \the [source_string].") - playsound(src, 'sound/effects/internals.ogg', 50, 0) - if(old_internal && !internal) - to_chat(src, "You are no longer running on internals.") - if(internals) - internals.icon_state = "internal[!!internal]" - -/mob/living/carbon/has_dexterity(var/dex_level) - . = ..() && (species.get_manual_dexterity() >= dex_level) - -/mob/living/carbon/fluid_act(var/datum/reagents/fluids) - var/saturation = min(fluids.total_volume, round(mob_size * 1.5 * reagent_permeability()) - touching.total_volume) - if(saturation > 0) - fluids.trans_to_holder(touching, saturation) - if(fluids.total_volume) - ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm deleted file mode 100644 index 8919cec53b38..000000000000 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ /dev/null @@ -1,29 +0,0 @@ - -/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - if(!effective_force) - return 0 - - //Hulk modifier - if(MUTATION_HULK in user.mutations) - effective_force *= 2 - - //Apply weapon damage - var/damage_flags = I.damage_flags() - var/datum/wound/created_wound = apply_damage(effective_force, I.damtype, hit_zone, damage_flags, used_weapon=I) - - //Melee weapon embedded object code. - if(istype(created_wound) && I && I.can_embed() && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) - var/weapon_sharp = (damage_flags & DAM_SHARP) - var/damage = effective_force //just the effective damage used for sorting out embedding, no further damage is applied here - damage *= 1 - get_blocked_ratio(hit_zone, I.damtype, I.damage_flags(), I.armor_penetration, I.force) - - //blunt objects should really not be embedding in things unless a huge amount of force is involved - var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) - var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class - - //Sharp objects will always embed if they do enough damage. - if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) - src.embed(I, hit_zone, supplied_wound = created_wound) - I.has_embedded() - - return 1 diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm deleted file mode 100644 index 9d587e90d0e2..000000000000 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ /dev/null @@ -1,40 +0,0 @@ -/mob/living/carbon/ - gender = MALE - - var/life_tick = 0 // The amount of life ticks that have processed on this mob. - var/obj/item/handcuffed = null //Whether or not the mob is handcuffed - //Surgery info - var/list/surgeries_in_progress - //Active emote/pose - var/pose = null - var/list/chem_effects = list() - var/list/chem_doses = list() - var/datum/reagents/metabolism/bloodstr = null - var/datum/reagents/metabolism/touching = null - var/losebreath = 0 //if we failed to breathe last tick - - var/coughedtime = null - var/ignore_rads = FALSE - var/cpr_time = 1.0 - var/lastpuke = 0 - var/nutrition = 400 - var/hydration = 400 - - var/obj/item/tank/internal = null//Human/Monkey - var/datum/species/species //Contains icon generation and language information, set during New(). - - //these two help govern taste. The first is the last time a taste message was shown to the plaer. - //the second is the message in question. - var/last_taste_time = 0 - var/last_taste_text = "" - - // organ-related variables, see organ.dm and human_organs.dm - var/list/internal_organs = list() - var/list/organs = list() - var/list/obj/item/organ/external/organs_by_name = list() // map organ names to organs - var/list/internal_organs_by_name = list() // so internal organs have less ickiness too - - var/list/stasis_sources = list() - var/stasis_value - - var/player_triggered_sleeping = 0 diff --git a/code/modules/mob/living/carbon/carbon_grabs.dm b/code/modules/mob/living/carbon/carbon_grabs.dm deleted file mode 100644 index 837f26d11f9a..000000000000 --- a/code/modules/mob/living/carbon/carbon_grabs.dm +++ /dev/null @@ -1,12 +0,0 @@ -/mob/living/carbon/get_active_grabs() - . = list() - for(var/obj/item/grab/grab in list(l_hand, r_hand)) - . += grab - -/mob/living/carbon/make_grab(var/atom/movable/target, var/grab_tag = /decl/grab/simple) - . = ..(target, species?.grab_type || grab_tag) - -/mob/living/carbon/can_be_grabbed(var/mob/grabber, var/target_zone) - . = ..() - if(.) - LAssailant = iscarbon(grabber) && grabber diff --git a/code/modules/mob/living/carbon/carbon_powers.dm b/code/modules/mob/living/carbon/carbon_powers.dm deleted file mode 100644 index 6ec908e46064..000000000000 --- a/code/modules/mob/living/carbon/carbon_powers.dm +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Attempt to devour victim - * - * Returns TRUE on success, FALSE on failure - */ -/mob/living/carbon/proc/devour(atom/movable/victim) - var/can_eat = can_devour(victim) - if(!can_eat) - return FALSE - - var/eat_speed = 100 - if(can_eat == DEVOUR_FAST) - eat_speed = 30 - src.visible_message("\The [src] is attempting to devour \the [victim] whole!") - var/mob/target = victim - if(isobj(victim)) - target = src - if(!do_mob(src,target,eat_speed)) - return FALSE - src.visible_message("\The [src] devours \the [victim] whole!") - if(ismob(victim)) - admin_attack_log(src, victim, "Devoured.", "Was devoured by.", "devoured") - else - src.drop_from_inventory(victim) - move_to_stomach(victim) - - return TRUE - -/mob/living/carbon/proc/move_to_stomach(atom/movable/victim) - return diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm deleted file mode 100644 index 0329801ad702..000000000000 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ /dev/null @@ -1,13 +0,0 @@ -/* -Contians the proc to handle radiation. -Specifically made to do radiation burns. -*/ - - -/mob/living/carbon/apply_radiation(damage) - ..() - if(!isSynthetic() && !ignore_rads) - damage = 0.25 * damage * (species ? species.get_radiation_mod(src) : 1) - adjustFireLoss(damage) - updatehealth() - return TRUE diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm deleted file mode 100644 index 9c5ec6da98ab..000000000000 --- a/code/modules/mob/living/carbon/give.dm +++ /dev/null @@ -1,46 +0,0 @@ -/mob/living/carbon/human/verb/give(var/mob/living/target in view(1)-usr) - set category = "IC" - set name = "Give" - - if(incapacitated()) - return - if(!istype(target) || target.incapacitated() || target.client == null) - return - - var/obj/item/I = usr.get_active_hand() - if(!I) - I = usr.get_inactive_hand() - if(!I) - to_chat(usr, SPAN_WARNING("You don't have anything in your hands to give to \the [target].")) - return - - if(istype(I, /obj/item/grab)) - to_chat(usr, SPAN_WARNING("You can't give someone a grab.")) - return - - usr.visible_message(SPAN_NOTICE("\The [usr] holds out \the [I] to \the [target]."), SPAN_NOTICE("You hold out \the [I] to \the [target], waiting for them to accept it.")) - - if(alert(target,"[usr] wants to give you \a [I]. Will you accept it?",,"Yes","No") == "No") - target.visible_message(SPAN_NOTICE("\The [usr] tried to hand \the [I] to \the [target], but \the [target] didn't want it.")) - return - - if(!I) return - - if(!Adjacent(target)) - to_chat(usr, SPAN_WARNING("You need to stay in reaching distance while giving an object.")) - to_chat(target, SPAN_WARNING("\The [usr] moved too far away.")) - return - - if(I.loc != usr || (usr.l_hand != I && usr.r_hand != I)) - to_chat(usr, SPAN_WARNING("You need to keep the item in your hands.")) - to_chat(target, SPAN_WARNING("\The [usr] seems to have given up on passing \the [I] to you.")) - return - - if(target.r_hand != null && target.l_hand != null) - to_chat(target, SPAN_WARNING("Your hands are full.")) - to_chat(usr, SPAN_WARNING("Their hands are full.")) - return - - if(usr.unEquip(I)) - target.put_in_hands(I) // If this fails it will just end up on the floor. - usr.visible_message(SPAN_NOTICE("\The [usr] handed \the [I] to \the [target]."), SPAN_NOTICE("You give \the [I] to \the [target].")) diff --git a/code/modules/mob/living/carbon/hallucinations.dm b/code/modules/mob/living/carbon/hallucinations.dm deleted file mode 100644 index 1a6e8c2c2fce..000000000000 --- a/code/modules/mob/living/carbon/hallucinations.dm +++ /dev/null @@ -1,307 +0,0 @@ -/mob/living/carbon/var/hallucination_power = 0 -/mob/living/carbon/var/hallucination_duration = 0 -/mob/living/carbon/var/next_hallucination -/mob/living/carbon/var/list/hallucinations = list() - -/mob/living/proc/adjust_hallucination(duration, power) - return - -/mob/living/carbon/proc/hallucination(duration, power) - hallucination_duration = max(hallucination_duration, duration) - hallucination_power = max(hallucination_power, power) - -/mob/living/carbon/adjust_hallucination(duration, power) - hallucination_duration = max(0, hallucination_duration + duration) - hallucination_power = max(0, hallucination_power + power) - -/mob/living/carbon/proc/handle_hallucinations() - //Tick down the duration - hallucination_duration = max(0, hallucination_duration - 1) - if(chem_effects[CE_MIND] > 0) - hallucination_duration = max(0, hallucination_duration - 1) - - //Adjust power if we have some chems that affect it - if(chem_effects[CE_MIND] < 0) - hallucination_power = min(hallucination_power++, 50) - if(chem_effects[CE_MIND] < -1) - hallucination_power = hallucination_power++ - if(chem_effects[CE_MIND] > 0) - hallucination_power = max(hallucination_power - chem_effects[CE_MIND], 0) - - //See if hallucination is gone - if(!hallucination_power) - hallucination_duration = 0 - return - if(!hallucination_duration) - hallucination_power = 0 - return - - if(!client || stat || world.time < next_hallucination) - return - if(chem_effects[CE_MIND] > 0 && prob(chem_effects[CE_MIND]*40)) //antipsychotics help - return - var/hall_delay = rand(10,20) SECONDS - - if(hallucination_power < 50) - hall_delay *= 2 - next_hallucination = world.time + hall_delay - var/list/candidates = list() - for(var/T in subtypesof(/datum/hallucination/)) - var/datum/hallucination/H = new T - if(H.can_affect(src)) - candidates += H - if(candidates.len) - var/datum/hallucination/H = pick(candidates) - H.holder = src - H.activate() - -////////////////////////////////////////////////////////////////////////////////////////////////////// -//Hallucination effects datums -////////////////////////////////////////////////////////////////////////////////////////////////////// - -/datum/hallucination - var/mob/living/carbon/holder - var/allow_duplicates = 1 - var/duration = 0 - var/min_power = 0 //at what levels of hallucination power mobs should get it - var/max_power = INFINITY - -/datum/hallucination/proc/start() - -/datum/hallucination/proc/end() - -/datum/hallucination/proc/can_affect(var/mob/living/carbon/C) - if(!C.client) - return 0 - if(min_power > C.hallucination_power) - return 0 - if(max_power < C.hallucination_power) - return 0 - if(!allow_duplicates && (locate(type) in C.hallucinations)) - return 0 - return 1 - -/datum/hallucination/Destroy() - . = ..() - holder = null - -/datum/hallucination/proc/activate() - if(!holder || !holder.client) - return - holder.hallucinations += src - start() - spawn(duration) - if(holder) - end() - holder.hallucinations -= src - qdel(src) - - -//Playing a random sound -/datum/hallucination/sound - var/list/sounds = list('sound/machines/airlock.ogg','sound/effects/explosionfar.ogg','sound/machines/windowdoor.ogg','sound/machines/twobeep.ogg') - -/datum/hallucination/sound/start() - var/turf/T = locate(holder.x + rand(6,11), holder.y + rand(6,11), holder.z) - holder.playsound_local(T,pick(sounds),70) - -/datum/hallucination/sound/tools - sounds = list('sound/items/Ratchet.ogg','sound/items/Welder.ogg','sound/items/Crowbar.ogg','sound/items/Screwdriver.ogg') - -/datum/hallucination/sound/danger - min_power = 30 - sounds = list('sound/effects/Explosion1.ogg','sound/effects/Explosion2.ogg','sound/effects/Glassbr1.ogg','sound/effects/Glassbr2.ogg','sound/effects/Glassbr3.ogg','sound/weapons/smash.ogg') - -/datum/hallucination/sound/spooky - min_power = 50 - sounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\ - 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\ - 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\ - 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\ - 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg') - -//Hearing someone being shot twice -/datum/hallucination/gunfire - var/gunshot - var/turf/origin - duration = 15 - min_power = 30 - -/datum/hallucination/gunfire/start() - gunshot = pick('sound/weapons/gunshot/gunshot_strong.ogg', 'sound/weapons/gunshot/gunshot2.ogg', 'sound/weapons/gunshot/shotgun.ogg', 'sound/weapons/gunshot/gunshot.ogg','sound/weapons/Taser.ogg') - origin = locate(holder.x + rand(4,8), holder.y + rand(4,8), holder.z) - holder.playsound_local(origin,gunshot,50) - -/datum/hallucination/gunfire/end() - holder.playsound_local(origin,gunshot,50) - -//Hearing someone talking to/about you. -/datum/hallucination/talking/can_affect(var/mob/living/carbon/C) - if(!..()) - return 0 - for(var/mob/living/M in oview(C)) - return TRUE - -/datum/hallucination/talking/start() - var/sanity = 5 //even insanity needs some sanity - for(var/mob/living/talker in oview(holder)) - if(talker.stat) - continue - var/message - if(prob(80)) - var/list/names = list() - var/lastname = copytext(holder.real_name, findtext(holder.real_name, " ")+1) - var/firstname = copytext(holder.real_name, 1, findtext(holder.real_name, " ")) - if(lastname) names += lastname - if(firstname) names += firstname - if(!names.len) - names += holder.real_name - var/add = prob(20) ? ", [pick(names)]" : "" - var/list/phrases = list("[prob(50) ? "Hey, " : ""][pick(names)]!","[prob(50) ? "Hey, " : ""][pick(names)]?","Get out[add]!","Go away[add].","What are you doing[add]?","Where's your ID[add]?") - if(holder.hallucination_power > 50) - phrases += list("What did you come here for[add]?","Don't touch me[add].","You're not getting out of here[add].", "You are a failure, [pick(names)].","Just kill yourself already, [pick(names)].","Put on some clothes[add].","Take off your clothes[add].") - message = pick(phrases) - to_chat(holder,"[talker.name] [holder.say_quote(message)], \"[message]\"") - else - to_chat(holder,"[talker.name] points at [holder.name]") - to_chat(holder,"[talker.name] says something softly.") - var/image/speech_bubble = image('icons/mob/talk.dmi',talker,"h[holder.say_test(message)]") - spawn(30) qdel(speech_bubble) - show_image(holder,speech_bubble) - sanity-- //don't spam them in very populated rooms. - if(!sanity) - return - -//Spiderling skitters -/datum/hallucination/skitter/start() - to_chat(holder,"The spiderling skitters[pick(" away"," around","")].") - -//Spiders in your body -/datum/hallucination/spiderbabies - min_power = 40 - -/datum/hallucination/spiderbabies/start() - if(istype(holder,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = holder - var/obj/O = pick(H.organs) - to_chat(H,"You feel something [pick("moving","squirming","skittering")] inside of your [O.name]!") - -//Seeing stuff -/datum/hallucination/mirage - duration = 30 SECONDS - max_power = 30 - var/number = 1 - var/list/things = list() //list of images to display - -/datum/hallucination/mirage/Destroy() - end() - . = ..() - -/datum/hallucination/mirage/proc/generate_mirage() - var/icon/T = new('icons/obj/trash.dmi') - return image(T, pick(T.IconStates()), layer = BELOW_TABLE_LAYER) - -/datum/hallucination/mirage/start() - var/list/possible_points = list() - for(var/turf/simulated/floor/F in view(holder, world.view+1)) - possible_points += F - if(possible_points.len) - for(var/i = 1 to number) - var/image/thing = generate_mirage() - things += thing - thing.loc = pick(possible_points) - holder.client.images += things - -/datum/hallucination/mirage/end() - if(holder.client) - holder.client.images -= things - -//LOADSEMONEY -/datum/hallucination/mirage/money - min_power = 20 - max_power = 45 - number = 2 - -/datum/hallucination/mirage/money/generate_mirage() - return image('icons/obj/items/money.dmi', "spacecash[pick(1000,500,200,100,50)]", layer = BELOW_TABLE_LAYER) - -//Blood and aftermath of firefight -/datum/hallucination/mirage/carnage - min_power = 50 - number = 10 - -/datum/hallucination/mirage/carnage/generate_mirage() - if(prob(50)) - var/image/I = image('icons/effects/blood.dmi', pick("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7"), layer = BELOW_TABLE_LAYER) - I.color = COLOR_BLOOD_HUMAN - return I - else - var/image/I = image('icons/obj/ammo.dmi', "s-casing-spent", layer = BELOW_TABLE_LAYER) - I.layer = BELOW_TABLE_LAYER - I.dir = pick(GLOB.alldirs) - I.pixel_x = rand(-10,10) - I.pixel_y = rand(-10,10) - return I - -//Fake telepathy -/datum/hallucination/telepahy - allow_duplicates = 0 - duration = 20 MINUTES - -/datum/hallucination/telepahy/start() - to_chat(holder,"You expand your mind outwards.") - holder.verbs += /mob/living/carbon/human/proc/fakeremotesay - -/datum/hallucination/telepahy/end() - if(holder) - holder.verbs -= /mob/living/carbon/human/proc/fakeremotesay - -/mob/living/carbon/human/proc/fakeremotesay() - set name = "Telepathic Message" - set category = "Superpower" - - if(!hallucination_power) - src.verbs -= /mob/living/carbon/human/proc/fakeremotesay - return - - if(stat) - to_chat(usr, "You're not in any state to use your powers right now!'") - return - - if(chem_effects[CE_MIND] > 0) - to_chat(usr, "Chemicals in your blood prevent you from using your power!'") - - var/list/creatures = list() - for(var/mob/living/carbon/C in SSmobs.mob_list) - creatures += C - creatures -= usr - var/mob/target = input("Who do you want to project your mind to ?") as null|anything in creatures - if (isnull(target)) - return - - var/msg = sanitize(input(usr, "What do you wish to transmit")) - show_message("You project your mind into [target.name]: \"[msg]\"") - if(!stat && prob(20)) - say(msg) - -//Fake attack -/datum/hallucination/fakeattack - min_power = 30 - -/datum/hallucination/fakeattack/can_affect(var/mob/living/carbon/C) - if(!..()) - return 0 - for(var/mob/living/M in oview(C,1)) - return TRUE - -/datum/hallucination/fakeattack/start() - for(var/mob/living/M in oview(holder,1)) - to_chat(holder, "[M] has punched [holder]!") - holder.playsound_local(get_turf(holder),"punch",50) - -//Fake injection -/datum/hallucination/fakeattack/hypo - min_power = 30 - -/datum/hallucination/fakeattack/hypo/start() - to_chat(holder, "You feel a tiny prick!") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/MedicalSideEffects.dm b/code/modules/mob/living/carbon/human/MedicalSideEffects.dm deleted file mode 100644 index ad36e842773c..000000000000 --- a/code/modules/mob/living/carbon/human/MedicalSideEffects.dm +++ /dev/null @@ -1,160 +0,0 @@ -// MEDICAL SIDE EFFECT BASE -// ======================== -/datum/medical_effect - var/name = "None" - var/strength = 0 - var/start = 0 - var/list/triggers - var/list/cures - var/cure_message - -/datum/medical_effect/proc/manifest(mob/living/carbon/human/H) - for(var/R in cures) - if(!H.reagents || H.reagents.has_reagent(R)) - return FALSE - for(var/R in triggers) - if(REAGENT_VOLUME(H.reagents, R) >= triggers[R]) - return TRUE - return FALSE - -/datum/medical_effect/proc/on_life(mob/living/carbon/human/H, strength) - return - -/datum/medical_effect/proc/cure(mob/living/carbon/human/H) - for(var/R in cures) - if(H.reagents.has_reagent(R)) - if (cure_message) - to_chat(H, SPAN_NOTICE("[cure_message]")) - return TRUE - return FALSE - -// MOB HELPERS -// =========== -/mob/living/carbon/human/var/list/datum/medical_effect/side_effects = list() -/mob/proc/add_side_effect(name, strength = 0) -/mob/living/carbon/human/add_side_effect(name, strength = 0) - for(var/datum/medical_effect/M in src.side_effects) - if(M.name == name) - M.strength = max(M.strength, 10) - M.start = life_tick - return - - for(var/T in subtypesof(/datum/medical_effect)) - var/datum/medical_effect/M = T - if(initial(M.name) == name) - M = new T - M.strength = strength - M.start = life_tick - side_effects += M - break - -/mob/living/carbon/human/proc/handle_medical_side_effects() - //Going to handle those things only every few ticks. - if(life_tick % 15 != 0) - return FALSE - - var/list/L = subtypesof(/datum/medical_effect) - for(var/T in L) - var/datum/medical_effect/M = new T - if (M.manifest(src)) - src.add_side_effect(M.name) - else - qdel(M) - - // One full cycle(in terms of strength) every 10 minutes - for (var/datum/medical_effect/M in side_effects) - if (!M) continue - var/strength_percent = sin((life_tick - M.start) / 2) - - // Only do anything if the effect is currently strong enough - if(strength_percent >= 0.4) - if (M.cure(src) || M.strength > 50) - side_effects -= M - M = null - else - if(life_tick % 45 == 0) - M.on_life(src, strength_percent*M.strength) - // Effect slowly growing stronger - M.strength+=0.08 - -// HEADACHE -// ======== -/datum/medical_effect/headache - name = "Headache" - triggers = list(/decl/material/liquid/brute_meds = 15, /decl/material/liquid/regenerator = 15) - cures = list(/decl/material/liquid/neuroannealer, /decl/material/liquid/painkillers) - cure_message = "Your head stops throbbing..." - -/datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength) - var/obj/item/organ/external/head/head = H.get_organ(BP_HEAD) - if(head) - switch(strength) - if(1 to 10) - H.custom_pain("You feel a light pain in your [head.name].", 5, affecting = head) - if(11 to 30) - H.custom_pain("You feel a throbbing pain in your [head.name]!", 15, affecting = head) - H.eye_blurry += rand(3,6) - H.stamina -= rand(10,20) - shake_camera(H, 7, 0.5) - if(31 to INFINITY) - H.custom_pain("You feel an excrutiating pain in your [head.name]!", 40, affecting = head) - H.eye_blurry += rand(10,20) - H.stamina -= rand(20,35) - shake_camera(H, 7, 1) - -// BAD STOMACH -// =========== -/datum/medical_effect/bad_stomach - name = "Bad Stomach" - triggers = list(/decl/material/liquid/burn_meds = 30) - cures = list(/decl/material/liquid/antitoxins) - cure_message = "Your stomach feels a little better now..." - -/datum/medical_effect/bad_stomach/on_life(mob/living/carbon/human/H, strength) - var/obj/item/organ/internal/stomach/stomach = H.get_organ(BP_STOMACH) //INF - if(stomach) - switch(strength) - if(1 to 10) - H.custom_pain("You feel a bit light around \the [stomach.name].", 10, affecting = stomach) - if(11 to 30) - H.custom_pain("Your [stomach.name] hurts.", 20, affecting = stomach) - if(31 to INFINITY) - H.custom_pain("You feel sick.", 30, affecting = stomach) - -// CRAMPS -// ====== -/datum/medical_effect/cramps - name = "Cramps" - triggers = list(/decl/material/liquid/antitoxins = 30, /decl/material/liquid/painkillers = 15) - cures = list(/decl/material/liquid/adrenaline) - cure_message = "The cramps let up..." - -/datum/medical_effect/cramps/on_life(mob/living/carbon/human/H, strength) - switch(strength) - if(1 to 10) - H.custom_pain("The muscles in your body hurt a little.", 20) - if(11 to 30) - H.custom_pain("The muscles in your body cramp up painfully.", 30) - if(31 to INFINITY) - H.visible_message("\The [src] flinches as all the muscles in their body cramp up.") - H.custom_pain("There's pain all over your body.", 70) - shake_camera(H, 10, 1) - -// ITCH -// ==== -/datum/medical_effect/itch - name = "Itch" - triggers = list(/decl/material/liquid/psychoactives = 10) - cures = list(/decl/material/liquid/adrenaline) - cure_message = "The itching stops..." - -/datum/medical_effect/itch/on_life(mob/living/carbon/human/H, strength) - switch(strength) - if(1 to 10) - H.custom_pain("You feel a slight itch.", 10) - if(11 to 30) - H.custom_pain("You want to scratch your itch badly.", 15) - if(31 to INFINITY) - H.visible_message("\The [src] shivers slightly.") - H.custom_pain("This itch makes it really hard to concentrate.", 20) - shake_camera(H, 20, 4) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm deleted file mode 100644 index 1dbf5df29c9b..000000000000 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ /dev/null @@ -1,166 +0,0 @@ -/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, var/location = src, var/mob/user = src, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list(), var/datum/topic_state/state = GLOB.default_state) - var/datum/nano_module/appearance_changer/AC = new(location, src, check_species_whitelist, species_whitelist, species_blacklist) - AC.flags = flags - AC.ui_interact(user, state = state) - -/mob/living/carbon/human/proc/change_species(var/new_species) - if(!new_species) - return - - if(species == new_species) - return - - if(!(new_species in get_all_species())) - return - - set_species(new_species) - var/datum/antagonist/antag = mind && player_is_antag(mind) - if (antag && antag.required_language) - add_language(antag.required_language) - set_default_language(antag.required_language) - reset_hair() - return 1 - -/mob/living/carbon/human/proc/change_gender(var/gender) - if(src.gender == gender) - return - - src.gender = gender - reset_hair() - update_body() - update_dna() - return 1 - -/mob/living/carbon/human/proc/randomize_gender() - change_gender(pick(species.genders)) - -/mob/living/carbon/human/proc/change_hair(var/hair_style) - if(!hair_style) - return - - if(h_style == hair_style) - return - - if(!(hair_style in GLOB.hair_styles_list)) - return - - h_style = hair_style - - update_hair() - return 1 - -/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style) - if(!facial_hair_style) - return - - if(f_style == facial_hair_style) - return - - if(!(facial_hair_style in GLOB.facial_hair_styles_list)) - return - - f_style = facial_hair_style - - update_hair() - return 1 - -/mob/living/carbon/human/proc/reset_hair() - var/list/valid_hairstyles = generate_valid_hairstyles() - var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles() - - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) - else - //this shouldn't happen - h_style = "Bald" - - if(valid_facial_hairstyles.len) - f_style = pick(valid_facial_hairstyles) - else - //this shouldn't happen - f_style = "Shaved" - - update_hair() - -/mob/living/carbon/human/proc/change_eye_color(var/new_colour) - if(eye_colour != new_colour) - eye_colour = new_colour - update_eyes() - update_body() - return TRUE - return FALSE - -/mob/living/carbon/human/proc/change_hair_color(var/new_colour) - if(hair_colour != new_colour) - hair_colour = new_colour - force_update_limbs() - update_body() - update_hair() - return TRUE - return FALSE - -/mob/living/carbon/human/proc/change_facial_hair_color(var/new_colour) - if(facial_hair_colour != new_colour) - facial_hair_colour = new_colour - update_hair() - return TRUE - return FALSE - -/mob/living/carbon/human/proc/change_skin_color(var/new_colour) - if(skin_colour == new_colour || !(species.appearance_flags & HAS_SKIN_COLOR)) - return FALSE - skin_colour = new_colour - force_update_limbs() - update_body() - return TRUE - -/mob/living/carbon/human/proc/change_skin_tone(var/tone) - if(skin_tone == tone || !(species.appearance_flags & HAS_A_SKIN_TONE)) - return - skin_tone = tone - force_update_limbs() - update_body() - return 1 - -/mob/living/carbon/human/proc/update_dna() - check_dna() - dna.ready_dna(src) - -/mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list()) - var/list/valid_species = new() - for(var/current_species_name in get_all_species()) - var/datum/species/current_species = get_species_by_key(current_species_name) - - if(check_whitelist) //If we're using the whitelist, make sure to check it! - if((current_species.spawn_flags & SPECIES_IS_RESTRICTED) && !check_rights(R_ADMIN, 0, src)) - continue - if(!is_alien_whitelisted(src, current_species)) - continue - if(whitelist.len && !(current_species_name in whitelist)) - continue - if(blacklist.len && (current_species_name in blacklist)) - continue - - valid_species += current_species_name - - return valid_species - -/mob/living/carbon/human/proc/generate_valid_hairstyles(var/check_gender = 1) - . = list() - var/list/hair_styles = species.get_hair_styles() - for(var/hair_style in hair_styles) - var/datum/sprite_accessory/S = hair_styles[hair_style] - if(check_gender) - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - .[hair_style] = S - -/mob/living/carbon/human/proc/generate_valid_facial_hairstyles() - return species.get_facial_hair_styles(gender) - -/mob/living/carbon/human/proc/force_update_limbs() - for(var/obj/item/organ/external/O in organs) - O.sync_colour_to_human(src) - update_body(0) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm deleted file mode 100644 index 5bf4cf4143d8..000000000000 --- a/code/modules/mob/living/carbon/human/death.dm +++ /dev/null @@ -1,87 +0,0 @@ -/mob/living/carbon/human/gib() - for(var/obj/item/organ/I in internal_organs) - I.removed() - if(!QDELETED(I) && isturf(loc)) - I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) - - for(var/obj/item/organ/external/E in src.organs) - E.droplimb(0,DROPLIMB_EDGE,1) - - sleep(1) - - for(var/obj/item/I in src) - drop_from_inventory(I) - if(!QDELETED(I)) - I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)), rand(1,3), round(30/I.w_class)) - - ..(species.gibbed_anim) - gibs(loc, dna, null, species.get_flesh_colour(src), species.get_blood_colour(src)) - -/mob/living/carbon/human/dust() - if(species) - ..(species.dusted_anim, species.remains_type) - else - ..() - -/mob/living/carbon/human/death(gibbed,deathmessage="seizes up and falls limp...", show_dead_message = "You have died.") - - if(stat == DEAD) return - - BITSET(hud_updateflag, HEALTH_HUD) - BITSET(hud_updateflag, STATUS_HUD) - BITSET(hud_updateflag, LIFE_HUD) - - //Handle species-specific deaths. - species.handle_death(src) - - animate_tail_stop() - - callHook("death", list(src, gibbed)) - - if(SSticker.mode) - SSticker.mode.check_win() - - if(wearing_rig) - wearing_rig.notify_ai("Warning: user death event. Mobility control passed to integrated intelligence system.") - - . = ..(gibbed,"no message") - if(!gibbed) - handle_organs() - if(species.death_sound) - playsound(loc, species.death_sound, 80, 1, 1) - handle_hud_list() - -/mob/living/carbon/human/proc/ChangeToHusk() - if(MUTATION_HUSK in mutations) return - - if(f_style) - f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE - if(h_style) - h_style = "Bald" - update_hair(0) - - mutations.Add(MUTATION_HUSK) - for(var/obj/item/organ/external/E in organs) - E.status |= ORGAN_DISFIGURED - update_body(1) - return - -/mob/living/carbon/human/proc/Drain() - ChangeToHusk() - mutations |= MUTATION_HUSK - return - -/mob/living/carbon/human/proc/ChangeToSkeleton() - if(MUTATION_SKELETON in src.mutations) return - - if(f_style) - f_style = "Shaved" - if(h_style) - h_style = "Bald" - update_hair(0) - - mutations.Add(MUTATION_SKELETON) - for(var/obj/item/organ/external/E in organs) - E.status |= ORGAN_DISFIGURED - update_body(1) - return diff --git a/code/modules/mob/living/carbon/human/descriptors/_descriptors.dm b/code/modules/mob/living/carbon/human/descriptors/_descriptors.dm deleted file mode 100644 index 95b97f270758..000000000000 --- a/code/modules/mob/living/carbon/human/descriptors/_descriptors.dm +++ /dev/null @@ -1,107 +0,0 @@ -/* - Small, mechanically supported physical customisation options. - Also allows for per-species physical information ('his neck markings are more important than yours'). - ETA till a downstream ports this and adds boob and penis size: 2 days. -*/ - -/mob/living/carbon/human/proc/show_descriptors_to(var/mob/user) - if(LAZYLEN(descriptors)) - if(user == src) - for(var/entry in descriptors) - var/datum/mob_descriptor/descriptor = species.descriptors[entry] - LAZYADD(., "[descriptor.get_first_person_message_start()] [descriptor.get_standalone_value_descriptor(descriptors[entry])].") - else - for(var/entry in descriptors) - var/datum/mob_descriptor/descriptor = species.descriptors[entry] - LAZYADD(., descriptor.get_comparative_value_descriptor(descriptors[entry], user, src)) - -/datum/mob_descriptor - var/name // String ident. - var/chargen_label // String ident for chargen. - var/default_value // Initial value for this descriptor. - var/comparison_offset = 0 // Used for examining similar properties between different species. - var/comparative_value_descriptor_equivalent // String for looking at someone with roughly the same property. - var/list/standalone_value_descriptors // String set for initial descriptor text. - var/list/comparative_value_descriptors_smaller // String set for looking at someone smaller than you. - var/list/comparative_value_descriptors_larger // String set for looking at someone larger than you. - var/list/chargen_value_descriptors // Used for chargen selection of values in cases where there is a hidden meaning. - var/skip_species_mention - -/datum/mob_descriptor/New() - if(!chargen_label) - chargen_label = name - if(!chargen_value_descriptors) - chargen_value_descriptors = list() - for(var/i = 1 to LAZYLEN(standalone_value_descriptors)) - chargen_value_descriptors[standalone_value_descriptors[i]] = i - default_value = ceil(LAZYLEN(standalone_value_descriptors) * 0.5) - ..() - -/datum/mob_descriptor/proc/get_third_person_message_start(var/datum/gender/my_gender) - return "[my_gender.He] [my_gender.is]" - -/datum/mob_descriptor/proc/get_first_person_message_start() - return "You are" - -/datum/mob_descriptor/proc/get_standalone_value_descriptor(var/check_value) - if(isnull(check_value)) - check_value = default_value - if(check_value && LAZYLEN(standalone_value_descriptors) >= check_value) - return standalone_value_descriptors[check_value] - -// Build a species-specific descriptor string. -/datum/mob_descriptor/proc/get_initial_comparison_component(var/mob/me, var/datum/gender/my_gender, var/datum/gender/other_gender, var/my_value) - var/species_text - if(ishuman(me) && !skip_species_mention) - var/mob/living/carbon/human/H = me - var/use_name = "\improper [H.species.name]" - species_text = " for \a [use_name]" - . = "[get_third_person_message_start(my_gender)] [get_standalone_value_descriptor(my_value)][species_text]" - -/datum/mob_descriptor/proc/get_secondary_comparison_component(var/datum/gender/my_gender, var/datum/gender/other_gender, var/my_value, var/comparing_value) - var/raw_value = my_value - my_value += comparison_offset - var/variance = abs((my_value)-comparing_value) - if(variance < 1) - . = "[.], [get_comparative_value_string_equivalent(raw_value, my_gender, other_gender)]" - else - variance = variance / LAZYLEN(standalone_value_descriptors) - if(my_value < comparing_value) - . = "[.], [get_comparative_value_string_smaller(variance, my_gender, other_gender)]" - else if(my_value > comparing_value) - . = "[.], [get_comparative_value_string_larger(variance, my_gender, other_gender)]" - -/datum/mob_descriptor/proc/get_comparative_value_descriptor(var/my_value, var/mob/observer, var/mob/me) - - // Store our gender info for later. - var/datum/gender/my_gender = gender_datums[me.get_gender()] - var/datum/gender/other_gender = gender_datums[observer.get_gender()] - - . = get_initial_comparison_component(me, my_gender, other_gender, my_value) - - // Append the same-descriptor comparison text. - var/comparing_value - if(ishuman(observer)) - var/mob/living/carbon/human/human_observer = observer - if(LAZYLEN(human_observer.descriptors) && !isnull(human_observer.species.descriptors[name]) && !isnull(human_observer.descriptors[name])) - var/datum/mob_descriptor/obs_descriptor = human_observer.species.descriptors[name] - comparing_value = human_observer.descriptors[name] + obs_descriptor.comparison_offset - - if(. && !isnull(comparing_value)) - . = "[.][get_secondary_comparison_component(my_gender, other_gender, my_value, comparing_value)]" - - // We're done, add a full stop. - . = "[.]. " - -/datum/mob_descriptor/proc/get_comparative_value_string_equivalent(var/my_value, var/datum/gender/my_gender, var/datum/gender/other_gender) - return comparative_value_descriptor_equivalent - -/datum/mob_descriptor/proc/get_comparative_value_string_smaller(var/value, var/datum/gender/my_gender, var/datum/gender/other_gender) - var/maxval = LAZYLEN(comparative_value_descriptors_smaller) - value = Clamp(ceil(value * maxval), 1, maxval) - return comparative_value_descriptors_smaller[value] - -/datum/mob_descriptor/proc/get_comparative_value_string_larger(var/value, var/datum/gender/my_gender, var/datum/gender/other_gender) - var/maxval = LAZYLEN(comparative_value_descriptors_larger) - value = Clamp(ceil(value * maxval), 1, maxval) - return comparative_value_descriptors_larger[value] diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm deleted file mode 100644 index 7931171b6fd2..000000000000 --- a/code/modules/mob/living/carbon/human/examine.dm +++ /dev/null @@ -1,419 +0,0 @@ -/mob/living/carbon/human/examine(mob/user, distance) - SHOULD_CALL_PARENT(FALSE) - . = TRUE - var/skipgloves = 0 - var/skipsuitstorage = 0 - var/skipjumpsuit = 0 - var/skipshoes = 0 - var/skipmask = 0 - var/skipears = 0 - var/skipeyes = 0 - var/skipface = 0 - - //exosuits and helmets obscure our view and stuff. - if(wear_suit) - skipgloves = wear_suit.flags_inv & HIDEGLOVES - skipsuitstorage = wear_suit.flags_inv & HIDESUITSTORAGE - skipjumpsuit = wear_suit.flags_inv & HIDEJUMPSUIT - skipshoes = wear_suit.flags_inv & HIDESHOES - - if(head) - skipmask = head.flags_inv & HIDEMASK - skipeyes = head.flags_inv & HIDEEYES - skipears = head.flags_inv & HIDEEARS - skipface = head.flags_inv & HIDEFACE - - if(wear_mask) - skipeyes |= wear_mask.flags_inv & HIDEEYES - skipears |= wear_mask.flags_inv & HIDEEARS - skipface |= wear_mask.flags_inv & HIDEFACE - - //no accuately spotting headsets from across the room. - if(distance > 3) - skipears = 1 - - var/list/msg = list("*---------*\nThis is ") - - var/datum/gender/T = gender_datums[get_gender()] - if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender - T = gender_datums[PLURAL] - else - if(icon) - msg += "\icon[icon] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated - - if(!T) - // Just in case someone VVs the gender to something strange. It'll runtime anyway when it hits usages, better to CRASH() now with a helpful message. - CRASH("Gender datum was null; key was '[(skipjumpsuit && skipface) ? PLURAL : gender]'") - - msg += "[src.name]" - - var/is_synth = isSynthetic() - if(!(skipjumpsuit && skipface)) - var/species_name = "\improper " - if(is_synth && species.cyborg_noun) - species_name += "[species.cyborg_noun] [species.get_root_species_name(src)]" - else - species_name += "[species.name]" - msg += ", \a [species_name]![(user.can_use_codex() && SScodex.get_codex_entry(get_codex_value())) ? SPAN_NOTICE(" \[?\]") : ""]" - - var/extra_species_text = species.get_additional_examine_text(src) - if(extra_species_text) - msg += "[extra_species_text]
          " - - msg += "
          " - - //uniform - if(w_uniform && !skipjumpsuit) - msg += "[T.He] [T.is] wearing [w_uniform.get_examine_line()].\n" - - //head - if(head) - msg += "[T.He] [T.is] wearing [head.get_examine_line()] on [T.his] head.\n" - - //suit/armour - if(wear_suit) - msg += "[T.He] [T.is] wearing [wear_suit.get_examine_line()].\n" - //suit/armour storage - if(s_store && !skipsuitstorage) - msg += "[T.He] [T.is] carrying [s_store.get_examine_line()] on [T.his] [wear_suit.name].\n" - - //back - if(back) - msg += "[T.He] [T.has] [back.get_examine_line()] on [T.his] back.\n" - - //left hand - if(l_hand) - msg += "[T.He] [T.is] holding [l_hand.get_examine_line()] in [T.his] left hand.\n" - - //right hand - if(r_hand) - msg += "[T.He] [T.is] holding [r_hand.get_examine_line()] in [T.his] right hand.\n" - - //gloves - if(gloves && !skipgloves) - msg += "[T.He] [T.has] [gloves.get_examine_line()] on [T.his] hands.\n" - else if(blood_DNA) - msg += "[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!\n" - - //belt - if(belt) - msg += "[T.He] [T.has] [belt.get_examine_line()] about [T.his] waist.\n" - - //shoes - if(shoes && !skipshoes) - msg += "[T.He] [T.is] wearing [shoes.get_examine_line()] on [T.his] feet.\n" - else if(feet_blood_DNA) - msg += "[T.He] [T.has] [(feet_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained feet!\n" - - //mask - if(wear_mask && !skipmask) - msg += "[T.He] [T.has] [wear_mask.get_examine_line()] on [T.his] face.\n" - - //eyes - if(glasses && !skipeyes) - msg += "[T.He] [T.has] [glasses.get_examine_line()] covering [T.his] eyes.\n" - - //left ear - if(l_ear && !skipears) - msg += "[T.He] [T.has] [l_ear.get_examine_line()] on [T.his] left ear.\n" - - //right ear - if(r_ear && !skipears) - msg += "[T.He] [T.has] [r_ear.get_examine_line()] on [T.his] right ear.\n" - - //ID - if(wear_id) - msg += "[T.He] [T.is] wearing [wear_id.get_examine_line()].\n" - - //handcuffed? - if(handcuffed) - if(istype(handcuffed, /obj/item/handcuffs/cable)) - msg += "[T.He] [T.is] \icon[handcuffed] restrained with cable!\n" - else - msg += "[T.He] [T.is] \icon[handcuffed] handcuffed!\n" - - //buckled - if(buckled) - msg += "[T.He] [T.is] \icon[buckled] buckled to [buckled]!\n" - - //Jitters - if(is_jittery) - if(jitteriness >= 300) - msg += "[T.He] [T.is] convulsing violently!\n" - else if(jitteriness >= 200) - msg += "[T.He] [T.is] extremely jittery.\n" - else if(jitteriness >= 100) - msg += "[T.He] [T.is] twitching ever so slightly.\n" - - //Disfigured face - if(!skipface) //Disfigurement only matters for the head currently. - var/obj/item/organ/external/head/E = get_organ(BP_HEAD) - if(E && (E.status & ORGAN_DISFIGURED)) //Check to see if we even have a head and if the head's disfigured. - if(E.species) //Check to make sure we have a species - msg += E.species.disfigure_msg(src) - else //Just in case they lack a species for whatever reason. - msg += "[T.His] face is horribly mangled!\n" - - //splints - for(var/organ in list(BP_L_LEG, BP_R_LEG, BP_L_ARM, BP_R_ARM)) - var/obj/item/organ/external/o = get_organ(organ) - if(o && o.splinted && o.splinted.loc == o) - msg += "[T.He] [T.has] \a [o.splinted] on [T.his] [o.name]!\n" - - if(mSmallsize in mutations) - msg += "[T.He] [T.is] small halfling!\n" - - if (src.stat) - msg += "[T.He] [T.is]n't responding to anything around [T.him] and seems to be unconscious.\n" - if((stat == DEAD || is_asystole() || src.losebreath) && distance <= 3) - msg += "[T.He] [T.does] not appear to be breathing.\n" - if(ishuman(user) && !user.incapacitated() && Adjacent(user)) - spawn(0) - user.visible_message("\The [user] checks \the [src]'s pulse.", "You check \the [src]'s pulse.") - if(do_after(user, 15, src)) - if(pulse() == PULSE_NONE) - to_chat(user, "[T.He] [T.has] no pulse.") - else - to_chat(user, "[T.He] [T.has] a pulse!") - - if(fire_stacks > 0) - msg += "[T.He] is covered in flammable liquid!\n" - else if(fire_stacks < 0) - msg += "[T.He] [T.is] soaking wet.\n" - - if(on_fire) - msg += "[T.He] [T.is] on fire!.\n" - - var/ssd_msg = species.get_ssd(src) - if(ssd_msg && (!should_have_organ(BP_BRAIN) || has_brain()) && stat != DEAD) - if(!key) - msg += "[T.He] [T.is] [ssd_msg]. It doesn't look like [T.he] [T.is] waking up anytime soon.\n" - else if(!client) - msg += "[T.He] [T.is] [ssd_msg].\n" - - var/obj/item/organ/external/head/H = organs_by_name[BP_HEAD] - if(istype(H) && H.forehead_graffiti && H.graffiti_style) - msg += "[T.He] [T.has] \"[H.forehead_graffiti]\" written on [T.his] [H.name] in [H.graffiti_style]!\n" - - if(became_younger) - msg += "[T.He] looks a lot younger than you remember.\n" - if(became_older) - msg += "[T.He] looks a lot older than you remember.\n" - - var/list/wound_flavor_text = list() - var/applying_pressure = "" - var/list/shown_objects = list() - var/list/hidden_bleeders = list() - - for(var/organ_tag in species.has_limbs) - - var/list/organ_data = species.has_limbs[organ_tag] - var/organ_descriptor = organ_data["descriptor"] - var/obj/item/organ/external/E = organs_by_name[organ_tag] - - if(!E) - wound_flavor_text[organ_descriptor] = "[T.He] [T.is] missing [T.his] [organ_descriptor].\n" - continue - - wound_flavor_text[E.name] = "" - - if(E.applied_pressure == src) - applying_pressure = "[T.He] [T.is] applying pressure to [T.his] [E.name].
          " - - var/obj/item/clothing/hidden - var/list/clothing_items = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) - for(var/obj/item/clothing/C in clothing_items) - if(istype(C) && (C.body_parts_covered & E.body_part)) - hidden = C - break - - if(hidden && user != src) - if(E.status & ORGAN_BLEEDING && !(hidden.item_flags & ITEM_FLAG_THICKMATERIAL)) //not through a spacesuit - if(!hidden_bleeders[hidden]) - hidden_bleeders[hidden] = list() - hidden_bleeders[hidden] += E.name - else - if(E.is_stump()) - wound_flavor_text[E.name] += "[T.He] [T.has] a stump where [T.his] [organ_descriptor] should be.\n" - if(LAZYLEN(E.wounds) && E.parent) - wound_flavor_text[E.name] += "[T.He] [T.has] [E.get_wounds_desc()] on [T.his] [E.parent.name].
          " - else - if(!is_synth && BP_IS_PROSTHETIC(E) && (E.parent && !BP_IS_PROSTHETIC(E.parent) && !BP_IS_ASSISTED(E.parent))) - wound_flavor_text[E.name] = "[T.He] [T.has] a [E.name].\n" - var/wounddesc = E.get_wounds_desc() - if(wounddesc != "nothing") - wound_flavor_text[E.name] += "[T.He] [T.has] [wounddesc] on [T.his] [E.name].
          " - if(!hidden || distance <=1) - if(E.dislocated > 0) - wound_flavor_text[E.name] += "[T.His] [E.joint] is dislocated!
          " - if(((E.status & ORGAN_BROKEN) && E.brute_dam > E.min_broken_damage) || (E.status & ORGAN_MUTATED)) - wound_flavor_text[E.name] += "[T.His] [E.name] is dented and swollen!
          " - - for(var/datum/wound/wound in E.wounds) - var/list/embedlist = wound.embedded_objects - if(LAZYLEN(embedlist)) - shown_objects += embedlist - var/parsedembed[0] - for(var/obj/embedded in embedlist) - if(!parsedembed.len || (!parsedembed.Find(embedded.name) && !parsedembed.Find("multiple [embedded.name]"))) - parsedembed.Add(embedded.name) - else if(!parsedembed.Find("multiple [embedded.name]")) - parsedembed.Remove(embedded.name) - parsedembed.Add("multiple "+embedded.name) - wound_flavor_text["[E.name]"] += "The [wound.desc] on [T.his] [E.name] has \a [english_list(parsedembed, and_text = " and \a ", comma_text = ", \a ")] sticking out of it!
          " - for(var/hidden in hidden_bleeders) - wound_flavor_text[hidden] = "[T.He] [T.has] blood soaking through [hidden] around [T.his] [english_list(hidden_bleeders[hidden])]!
          " - - msg += "" - for(var/limb in wound_flavor_text) - msg += wound_flavor_text[limb] - msg += "" - - for(var/obj/implant in get_visible_implants(0)) - if(implant in shown_objects) - continue - msg += "[src] [T.has] \a [implant.name] sticking out of [T.his] flesh!\n" - if(digitalcamo) - msg += "[T.He] [T.is] repulsively uncanny!\n" - - if(hasHUD(user, HUD_SECURITY)) - var/perpname = "wot" - var/criminal = "None" - - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - perpname = id.registered_name - else - perpname = src.name - - if(perpname) - var/datum/computer_network/network = user.getHUDnetwork(HUD_SECURITY) - if(network) - var/datum/computer_file/report/crew_record/R = network.get_crew_record_by_name(perpname) - if(R) - criminal = R.get_criminalStatus() - - msg += "Criminal status: \[[criminal]\]\n" - msg += "Security records: \[View\]\n" - - if(hasHUD(user, HUD_MEDICAL)) - var/perpname = "wot" - var/medical = "None" - - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - perpname = id.registered_name - else - perpname = src.name - - var/datum/computer_network/network = user.getHUDnetwork(HUD_MEDICAL) - if(network) - var/datum/computer_file/report/crew_record/R = network.get_crew_record_by_name(perpname) - if(R) - medical = R.get_status() - - msg += "Physical status: \[[medical]\]\n" - msg += "Medical records: \[View\]\n" - - - if(print_flavor_text()) msg += "[print_flavor_text()]\n" - - if(mind && user.mind && name == real_name) - var/list/relations = matchmaker.get_relationships_between(user.mind, mind, TRUE) - if(length(relations)) - msg += "
          You know them. More...
          " - - msg += "*---------*

          " - msg += applying_pressure - - if (pose) - if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 ) - pose = addtext(pose,".") //Makes sure all emotes end with a period. - msg += "[T.He] [pose]\n" - - var/show_descs = show_descriptors_to(user) - if(show_descs) - msg += "[jointext(show_descs, "
          ")]
          " - to_chat(user, jointext(msg, null)) - -//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records. -/proc/hasHUD(mob/M, hudtype) - return !!M.getHUDsource(hudtype) - -/mob/proc/getHUDsource(hudtype) - return - -/mob/living/carbon/human/getHUDsource(hudtype) - var/obj/item/clothing/glasses/G = glasses - if(!istype(G)) - return - if(G.hud_type & hudtype) - return G - if(G.hud && (G.hud.hud_type & hudtype)) - return G.hud - -/mob/living/silicon/robot/getHUDsource(hudtype) - for(var/obj/item/borg/sight/sight in list(module_state_1, module_state_2, module_state_3)) - if(istype(sight) && (sight.hud_type & hudtype)) - return sight - -//Gets the computer network M's source of hudtype is using -/mob/proc/getHUDnetwork(hudtype) - var/obj/O = getHUDsource(hudtype) - if(!O) - return - var/datum/extension/network_device/D = get_extension(O, /datum/extension/network_device) - return D.get_network() - -/mob/living/silicon/getHUDnetwork(hudtype) - if(getHUDsource(hudtype)) - return get_computer_network() - -/mob/living/carbon/human/verb/pose() - set name = "Set Pose" - set desc = "Sets a description which will be shown when someone examines you." - set category = "IC" - - pose = sanitize(input(usr, "This is [src]. [get_visible_gender() == MALE ? "He" : get_visible_gender() == FEMALE ? "She" : "They"]...", "Pose", null) as text) - -/mob/living/carbon/human/verb/set_flavor() - set name = "Set Flavour Text" - set desc = "Sets an extended description of your character's features." - set category = "IC" - - var/list/HTML = list() - HTML += "" - HTML += "
          " - HTML += "Update Flavour Text
          " - HTML += "
          " - HTML += "General: " - HTML += TextPreview(flavor_texts["general"]) - HTML += "
          " - HTML += "Head: " - HTML += TextPreview(flavor_texts["head"]) - HTML += "
          " - HTML += "Face: " - HTML += TextPreview(flavor_texts["face"]) - HTML += "
          " - HTML += "Eyes: " - HTML += TextPreview(flavor_texts["eyes"]) - HTML += "
          " - HTML += "Body: " - HTML += TextPreview(flavor_texts["torso"]) - HTML += "
          " - HTML += "Arms: " - HTML += TextPreview(flavor_texts["arms"]) - HTML += "
          " - HTML += "Hands: " - HTML += TextPreview(flavor_texts["hands"]) - HTML += "
          " - HTML += "Legs: " - HTML += TextPreview(flavor_texts["legs"]) - HTML += "
          " - HTML += "Feet: " - HTML += TextPreview(flavor_texts["feet"]) - HTML += "
          " - HTML += "
          " - HTML +="\[Done\]" - HTML += "" - show_browser(src, jointext(HTML,null), "window=flavor_changes;size=430x300") diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm deleted file mode 100644 index f2516d504f2e..000000000000 --- a/code/modules/mob/living/carbon/human/human.dm +++ /dev/null @@ -1,1809 +0,0 @@ -/mob/living/carbon/human - name = "unknown" - real_name = "unknown" - voice_name = "unknown" - icon = 'icons/mob/human.dmi' - icon_state = "body_m_s" - - var/list/hud_list[10] - var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. - var/obj/item/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call. - var/list/stance_limbs - var/list/grasp_limbs - var/step_count - -/mob/living/carbon/human/Initialize(mapload, var/new_species = null) - - grasp_limbs = list() - stance_limbs = list() - - if(!dna) - dna = new /datum/dna(null) - // Species name is handled by set_species() - - if(!species) - if(new_species) - set_species(new_species,1) - else - set_species() - - var/decl/cultural_info/culture = SSlore.get_culture(cultural_info[TAG_CULTURE]) - if(culture) - real_name = culture.get_random_name(gender, species.name) - name = real_name - if(mind) - mind.name = real_name - - hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud_med.dmi', src, "100") - hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy") - hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy") - hud_list[ID_HUD] = new /image/hud_overlay(GLOB.using_map.id_hud_icons, src, "hudunknown") - hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPTRACK_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[SPECIALROLE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[STATUS_HUD_OOC] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy") - - GLOB.human_mob_list |= src - . = ..() - - if(dna) - dna.ready_dna(src) - dna.real_name = real_name - dna.skin_base = skin_base - sync_organ_dna() - make_blood() - -/mob/living/carbon/human/Destroy() - GLOB.human_mob_list -= src - worn_underwear = null - for(var/organ in organs) - qdel(organ) - return ..() - -/mob/living/carbon/human/get_ingested_reagents() - if(should_have_organ(BP_STOMACH)) - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(stomach) - return stomach.ingested - return touching // Kind of a shitty hack, but makes more sense to me than digesting them. - -/mob/living/carbon/human/proc/metabolize_ingested_reagents() - if(should_have_organ(BP_STOMACH)) - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(stomach) - stomach.metabolize() - -/mob/living/carbon/human/get_fullness() - if(!should_have_organ(BP_STOMACH)) - return ..() - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(stomach) - return nutrition + (stomach.ingested.total_volume * 10) - return 0 //Always hungry, but you can't actually eat. :( - -/mob/living/carbon/human/Stat() - . = ..() - if(statpanel("Status")) - stat("Intent:", "[a_intent]") - stat("Move Mode:", "[move_intent.name]") - - if(SSevac.evacuation_controller) - var/eta_status = SSevac.evacuation_controller.get_status_panel_eta() - if(eta_status) - stat(null, eta_status) - - if (istype(internal)) - if (!internal.air_contents) - qdel(internal) - else - stat("Internal Atmosphere Info", internal.name) - stat("Tank Pressure", internal.air_contents.return_pressure()) - stat("Distribution Pressure", internal.distribute_pressure) - - var/obj/item/organ/internal/cell/potato = internal_organs_by_name[BP_CELL] - if(potato && potato.cell) - stat("Battery charge:", "[potato.get_charge()]/[potato.cell.maxcharge]") - - if(back && istype(back,/obj/item/rig)) - var/obj/item/rig/suit = back - var/cell_status = "ERROR" - if(suit.cell) cell_status = "[suit.cell.charge]/[suit.cell.maxcharge]" - stat(null, "Suit charge: [cell_status]") - - if(mind) - if(mind.changeling) - stat("Chemical Storage", mind.changeling.chem_charges) - stat("Genetic Damage Time", mind.changeling.geneticdamage) - -/mob/living/carbon/human/explosion_act(severity) - ..() - var/b_loss = null - var/f_loss = null - switch (severity) - if(1) - b_loss = 400 - f_loss = 100 - var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) - throw_at(target, 200, 4) - if(2) - b_loss = 60 - f_loss = 60 - if (get_sound_volume_multiplier() >= 0.2) - ear_damage += 30 - ear_deaf += 120 - if(prob(70)) - Paralyse(10) - if(3) - b_loss = 30 - if (get_sound_volume_multiplier() >= 0.2) - ear_damage += 15 - ear_deaf += 60 - if (prob(50)) - Paralyse(10) - - // focus most of the blast on one organ - apply_damage(0.7 * b_loss, BRUTE, null, DAM_EXPLODE, used_weapon = "Explosive blast") - apply_damage(0.7 * f_loss, BURN, null, DAM_EXPLODE, used_weapon = "Explosive blast") - - // distribute the remaining 30% on all limbs equally (including the one already dealt damage) - apply_damage(0.3 * b_loss, BRUTE, null, DAM_EXPLODE | DAM_DISPERSED, used_weapon = "Explosive blast") - apply_damage(0.3 * f_loss, BURN, null, DAM_EXPLODE | DAM_DISPERSED, used_weapon = "Explosive blast") - -/mob/living/carbon/human/proc/implant_loyalty(mob/living/carbon/human/M, override = FALSE) // Won't override by default. - if(!config.use_loyalty_implants && !override) return // Nuh-uh. - - var/obj/item/implant/loyalty/L = new/obj/item/implant/loyalty(M) - L.imp_in = M - L.implanted = 1 - var/obj/item/organ/external/affected = M.organs_by_name[BP_HEAD] - affected.implants += L - L.part = affected - L.implanted(src) - -/mob/living/carbon/human/proc/is_loyalty_implanted(mob/living/carbon/human/M) - for(var/L in M.contents) - if(istype(L, /obj/item/implant/loyalty)) - for(var/obj/item/organ/external/O in M.organs) - if(L in O.implants) - return 1 - return 0 - -/mob/living/carbon/human/restrained() - if (handcuffed) - return 1 - if(grab_restrained()) - return 1 - if (istype(wear_suit, /obj/item/clothing/suit/straight_jacket)) - return 1 - return 0 - -/mob/living/carbon/human/proc/grab_restrained() - for (var/obj/item/grab/G in grabbed_by) - if(G.restrains()) - return TRUE - -/mob/living/carbon/human/var/co2overloadtime = null -/mob/living/carbon/human/var/temperature_resistance = T0C+75 - - -/mob/living/carbon/human/show_inv(mob/user) - if(user.incapacitated() || !user.Adjacent(src) || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) - return - - user.set_machine(src) - var/dat = "
          [name]


          " - - for(var/entry in species.hud.gear) - var/list/slot_ref = species.hud.gear[entry] - if((slot_ref["slot"] in list(slot_l_store, slot_r_store))) - continue - var/obj/item/thing_in_slot = get_equipped_item(slot_ref["slot"]) - dat += "
          [slot_ref["name"]]: [istype(thing_in_slot) ? thing_in_slot : "nothing"]" - if(istype(thing_in_slot, /obj/item/clothing)) - var/obj/item/clothing/C = thing_in_slot - if(C.accessories.len) - dat += "
          Remove accessory" - dat += "

          " - - if(species.hud.has_hands) - dat += "
          Left hand: [istype(l_hand) ? l_hand : "nothing"]" - dat += "
          Right hand: [istype(r_hand) ? r_hand : "nothing"]" - - // Do they get an option to set internals? - if(istype(wear_mask, /obj/item/clothing/mask) || istype(head, /obj/item/clothing/head/helmet/space)) - if(istype(back, /obj/item/tank) || istype(belt, /obj/item/tank) || istype(s_store, /obj/item/tank)) - dat += "
          Toggle internals." - - var/obj/item/clothing/under/suit = w_uniform - // Other incidentals. - if(istype(suit)) - dat += "
          Pockets: Empty or Place Item" - if(suit.has_sensor == 1) - dat += "
          Set sensors" - if (suit.has_sensor && user.get_multitool()) - dat += "
          [suit.has_sensor == SUIT_LOCKED_SENSORS ? "Unl" : "L"]ock sensors" - if(handcuffed) - dat += "
          Handcuffed" - - for(var/entry in worn_underwear) - var/obj/item/underwear/UW = entry - dat += "
          Remove \the [UW]" - - dat += "
          Refresh" - dat += "
          Close" - - show_browser(user, dat, text("window=mob[name];size=340x540")) - onclose(user, "mob[name]") - return - -// called when something steps onto a human -// this handles mulebots and vehicles -/mob/living/carbon/human/Crossed(var/atom/movable/AM) - if(istype(AM, /mob/living/bot/mulebot)) - var/mob/living/bot/mulebot/MB = AM - MB.runOver(src) - - if(istype(AM, /obj/vehicle)) - var/obj/vehicle/V = AM - V.RunOver(src) - -// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc. -/mob/living/carbon/human/proc/get_authentification_rank(var/if_no_id = "No id", var/if_no_job = "No job") - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - return id.rank ? id.rank : if_no_job - else - return if_no_id - -//gets assignment from ID or ID inside PDA or PDA itself -//Useful when player do something with computers -/mob/living/carbon/human/proc/get_assignment(var/if_no_id = "No id", var/if_no_job = "No job") - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - return id.assignment ? id.assignment : if_no_job - else - return if_no_id - -//gets name from ID or ID inside PDA or PDA itself -//Useful when player do something with computers -/mob/living/carbon/human/proc/get_authentification_name(var/if_no_id = "Unknown") - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - return id.registered_name - else - return if_no_id - -//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere -/mob/living/carbon/human/proc/get_visible_name() - var/face_name = get_face_name() - var/id_name = get_id_name("") - if((face_name == "Unknown") && id_name && (id_name != face_name)) - return "[face_name] (as [id_name])" - return face_name - -//Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable -//Also used in AI tracking people by face, so added in checks for head coverings like masks and helmets -/mob/living/carbon/human/proc/get_face_name() - var/obj/item/organ/external/H = get_organ(BP_HEAD) - if(!H || (H.status & ORGAN_DISFIGURED) || H.is_stump() || !real_name || (MUTATION_HUSK in mutations) || (wear_mask && (wear_mask.flags_inv&HIDEFACE)) || (head && (head.flags_inv&HIDEFACE))) //Face is unrecognizeable, use ID if able - if(istype(wear_mask) && wear_mask.visible_name) - return wear_mask.visible_name - else if(istype(wearing_rig) && wearing_rig.visible_name) - return wearing_rig.visible_name - else - return "Unknown" - return real_name - -//gets name from ID or PDA itself, ID inside PDA doesn't matter -//Useful when player is being seen by other mobs -/mob/living/carbon/human/proc/get_id_name(var/if_no_id = "Unknown") - . = if_no_id - var/obj/item/card/id/I = GetIdCard() - if(istype(I)) - return I.registered_name - -//Removed the horrible safety parameter. It was only being used by ninja code anyways. -//Now checks siemens_coefficient of the affected area by default -/mob/living/carbon/human/electrocute_act(var/shock_damage, var/obj/source, var/base_siemens_coeff = 1.0, var/def_zone = null) - - if(status_flags & GODMODE) return 0 //godmode - - if(species.siemens_coefficient == -1) - if(stored_shock_by_ref["\ref[src]"]) - stored_shock_by_ref["\ref[src]"] += shock_damage - else - stored_shock_by_ref["\ref[src]"] = shock_damage - return - - if (!def_zone) - def_zone = pick(BP_L_HAND, BP_R_HAND) - - return ..(shock_damage, source, base_siemens_coeff, def_zone) - -/mob/living/carbon/human/apply_shock(var/shock_damage, var/def_zone, var/base_siemens_coeff = 1.0) - var/obj/item/organ/external/initial_organ = get_organ(check_zone(def_zone)) - if(!initial_organ) - initial_organ = pick(organs) - - var/obj/item/organ/external/floor_organ - - if(!lying) - var/list/obj/item/organ/external/standing = list() - for(var/limb_tag in list(BP_L_FOOT, BP_R_FOOT)) - var/obj/item/organ/external/E = organs_by_name[limb_tag] - if(E && E.is_usable()) - standing[E.organ_tag] = E - if((def_zone == BP_L_FOOT || def_zone == BP_L_LEG) && standing[BP_L_FOOT]) - floor_organ = standing[BP_L_FOOT] - if((def_zone == BP_R_FOOT || def_zone == BP_R_LEG) && standing[BP_R_FOOT]) - floor_organ = standing[BP_R_FOOT] - else - floor_organ = standing[pick(standing)] - - if(!floor_organ) - floor_organ = pick(organs) - - var/list/obj/item/organ/external/to_shock = trace_shock(initial_organ, floor_organ) - - if(to_shock && to_shock.len) - shock_damage /= to_shock.len - shock_damage = round(shock_damage, 0.1) - else - return 0 - - var/total_damage = 0 - - for(var/obj/item/organ/external/E in to_shock) - total_damage += ..(shock_damage, E.organ_tag, base_siemens_coeff * get_siemens_coefficient_organ(E)) - - if(total_damage > 10) - local_emp(initial_organ, 3) - - return total_damage - -/mob/living/carbon/human/proc/trace_shock(var/obj/item/organ/external/init, var/obj/item/organ/external/floor) - var/list/obj/item/organ/external/traced_organs = list(floor) - - if(!init) - return - - if(!floor || init == floor) - return list(init) - - for(var/obj/item/organ/external/E in list(floor, init)) - while(E && E.parent_organ) - var/candidate = organs_by_name[E.parent_organ] - if(!candidate || (candidate in traced_organs)) - break // Organ parenthood is not guaranteed to be a tree - E = candidate - traced_organs += E - if(E == init) - return traced_organs - - return traced_organs - -/mob/living/carbon/human/proc/local_emp(var/list/limbs, var/severity = 2) - if(!islist(limbs)) - limbs = list(limbs) - - var/list/EMP = list() - for(var/obj/item/organ/external/limb in limbs) - EMP += limb - EMP += limb.internal_organs - EMP += limb.implants - for(var/atom/E in EMP) - E.emp_act(severity) - -/mob/living/carbon/human/OnSelfTopic(href_list) - if (href_list["lookitem"]) - var/obj/item/I = locate(href_list["lookitem"]) - if(I) - src.examinate(I) - return TOPIC_HANDLED - - if (href_list["lookmob"]) - var/mob/M = locate(href_list["lookmob"]) - if(M) - src.examinate(M) - return TOPIC_HANDLED - - return ..() - -/mob/living/carbon/human/CanUseTopic(mob/user, datum/topic_state/state, href_list) - . = ..() - if(href_list && (href_list["refresh"] || href_list["item"])) - return min(., ..(user, GLOB.physical_state, href_list)) - -/mob/living/carbon/human/OnTopic(mob/user, href_list) - if (href_list["refresh"]) - show_inv(user) - return TOPIC_HANDLED - - if(href_list["item"]) - if(!handle_strip(href_list["item"],user,locate(href_list["holder"]))) - show_inv(user) - return TOPIC_HANDLED - - if (href_list["criminal"]) - if(hasHUD(user, HUD_SECURITY)) - - var/modified = 0 - var/perpname = "wot" - if(wear_id) - var/obj/item/card/id/I = wear_id.GetIdCard() - if(I) - perpname = I.registered_name - else - perpname = name - else - perpname = name - - var/datum/computer_network/network = user.getHUDnetwork(HUD_SECURITY) - if(!network) - return TOPIC_HANDLED - var/datum/computer_file/report/crew_record/R = network.get_crew_record_by_name(perpname) - if(R) - var/setcriminal = input(user, "Specify a new criminal status for this person.", "Security HUD", R.get_criminalStatus()) as null|anything in GLOB.security_statuses - if(hasHUD(usr, HUD_SECURITY) && setcriminal) - R.set_criminalStatus(setcriminal) - modified = 1 - - spawn() - BITSET(hud_updateflag, WANTED_HUD) - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/U = user - U.handle_regular_hud_updates() - if(istype(user,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/U = user - U.handle_regular_hud_updates() - - if(!modified) - to_chat(usr, "Unable to locate a data core entry for this person.") - return TOPIC_HANDLED - - if (href_list["secrecord"]) - if(hasHUD(usr, HUD_SECURITY)) - var/perpname = "wot" - var/read = 0 - - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - perpname = id.registered_name - else - perpname = src.name - var/datum/computer_network/network = user.getHUDnetwork(HUD_SECURITY) - if(!network) - return TOPIC_HANDLED - var/datum/computer_file/report/crew_record/E = network.get_crew_record_by_name(perpname) - if(E) - if(hasHUD(user, HUD_SECURITY)) - to_chat(user, "Name: [E.get_name()]") - to_chat(user, "Criminal Status: [E.get_criminalStatus()]") - to_chat(user, "Details: [E.get_secRecord()]") - read = 1 - - if(!read) - to_chat(user, "Unable to locate a data core entry for this person.") - return TOPIC_HANDLED - - if (href_list["medical"]) - if(hasHUD(user, HUD_MEDICAL)) - var/perpname = "wot" - var/modified = 0 - - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - perpname = id.registered_name - else - perpname = src.name - - var/datum/computer_network/network = user.getHUDnetwork(HUD_MEDICAL) - if(!network) - return TOPIC_HANDLED - var/datum/computer_file/report/crew_record/E = network.get_crew_record_by_name(perpname) - if(E) - var/setmedical = input(user, "Specify a new medical status for this person.", "Medical HUD", E.get_status()) as null|anything in GLOB.physical_statuses - if(hasHUD(user, HUD_MEDICAL) && setmedical) - E.set_status(setmedical) - modified = 1 - - spawn() - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/U = user - U.handle_regular_hud_updates() - if(istype(user,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/U = user - U.handle_regular_hud_updates() - - if(!modified) - to_chat(user, "Unable to locate a data core entry for this person.") - return TOPIC_HANDLED - - if (href_list["medrecord"]) - if(hasHUD(user, HUD_MEDICAL)) - var/perpname = "wot" - var/read = 0 - - var/obj/item/card/id/id = GetIdCard() - if(istype(id)) - perpname = id.registered_name - else - perpname = src.name - - var/datum/computer_network/network = user.getHUDnetwork(HUD_MEDICAL) - if(!network) - return TOPIC_HANDLED - var/datum/computer_file/report/crew_record/E = network.get_crew_record_by_name(perpname) - if(E) - if(hasHUD(user, HUD_MEDICAL)) - to_chat(usr, "Name: [E.get_name()]") - to_chat(usr, "Gender: [E.get_sex()]") - to_chat(usr, "Species: [E.get_species()]") - to_chat(usr, "Blood Type: [E.get_bloodtype()]") - to_chat(usr, "Details: [E.get_medRecord()]") - read = 1 - if(!read) - to_chat(user, "Unable to locate a data core entry for this person.") - return TOPIC_HANDLED - - return ..() - -/mob/living/carbon/human/update_flavor_text(key) - var/msg - switch(key) - if("done") - show_browser(src, null, "window=flavor_changes") - return - if("general") - msg = sanitize(input(src,"Update the general description of your character. This will be shown regardless of clothing. Do not include OOC information here.","Flavor Text",html_decode(flavor_texts[key])) as message, extra = 0) - else - if(!(key in flavor_texts)) - return - msg = sanitize(input(src,"Update the flavor text for your [key].","Flavor Text",html_decode(flavor_texts[key])) as message, extra = 0) - if(!CanInteract(src, GLOB.self_state)) - return - flavor_texts[key] = msg - set_flavor() - -///eyecheck() -///Returns a number between -1 to 2 -/mob/living/carbon/human/eyecheck() - var/total_protection = flash_protection - if(species.has_organ[species.vision_organ]) - var/obj/item/organ/internal/eyes/I = internal_organs_by_name[species.vision_organ] - if(!I?.is_usable()) - return FLASH_PROTECTION_MAJOR - total_protection = I.get_total_protection(flash_protection) - else // They can't be flashed if they don't have eyes. - return FLASH_PROTECTION_MAJOR - return total_protection - -/mob/living/carbon/human/flash_eyes(var/intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) - if(species.has_organ[species.vision_organ]) - var/obj/item/organ/internal/eyes/I = internal_organs_by_name[species.vision_organ] - if(!isnull(I)) - I.additional_flash_effects(intensity) - return ..() - -/mob/living/carbon/human/proc/getFlashMod() - if(species.vision_organ) - var/obj/item/organ/internal/eyes/I = internal_organs_by_name[species.vision_organ] - if(istype(I)) - return I.flash_mod - return species.flash_mod - -/mob/living/carbon/human/proc/getDarkvisionRange() - if(species.vision_organ) - var/obj/item/organ/internal/eyes/I = internal_organs_by_name[species.vision_organ] - if(istype(I)) - return I.darksight_range - return species.darksight_range - -/mob/living/carbon/human/proc/getDarkvisionTint() - if(species.vision_organ) - var/obj/item/organ/internal/eyes/I = internal_organs_by_name[species.vision_organ] - if(istype(I)) - return I.darksight_tint - return species.darksight_tint - -//Used by various things that knock people out by applying blunt trauma to the head. -//Checks that the species has a "head" (brain containing organ) and that hit_zone refers to it. -/mob/living/carbon/human/proc/headcheck(var/target_zone, var/brain_tag = BP_BRAIN) - - var/obj/item/organ/affecting = internal_organs_by_name[brain_tag] - - target_zone = check_zone(target_zone) - if(!affecting || affecting.parent_organ != target_zone) - return 0 - - //if the parent organ is significantly larger than the brain organ, then hitting it is not guaranteed - var/obj/item/organ/parent = get_organ(target_zone) - if(!parent) - return 0 - - if(parent.w_class > affecting.w_class + 1) - return prob(100 / 2**(parent.w_class - affecting.w_class - 1)) - - return 1 - -/mob/living/carbon/human/abiotic(var/full_body = TRUE) - if(full_body) - if(src.head || src.shoes || src.w_uniform || src.wear_suit || src.glasses || src.l_ear || src.r_ear || src.gloves) - return FALSE - return ..() - -/mob/living/carbon/human/proc/check_dna() - dna.check_integrity(src) - return - -/mob/living/carbon/human/get_species() - if(!species) - set_species() - return species.name - -/mob/living/carbon/human/proc/play_xylophone() - if(!src.xylophone) - visible_message("\The [src] begins playing \his ribcage like a xylophone. It's quite spooky.","You begin to play a spooky refrain on your ribcage.","You hear a spooky xylophone melody.") - var/song = pick('sound/effects/xylophone1.ogg','sound/effects/xylophone2.ogg','sound/effects/xylophone3.ogg') - playsound(loc, song, 50, 1, -1) - xylophone = 1 - spawn(1200) - xylophone=0 - return - -/mob/living/carbon/human/check_has_mouth() - // Todo, check stomach organ when implemented. - var/obj/item/organ/external/head/H = get_organ(BP_HEAD) - if(!H || !istype(H) || !H.can_intake_reagents) - return 0 - return 1 - -/mob/living/proc/empty_stomach() - return - -/mob/living/carbon/human/empty_stomach() - - Stun(3) - - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - var/nothing_to_puke = FALSE - if(should_have_organ(BP_STOMACH)) - if(!istype(stomach) || (stomach.ingested.total_volume <= 0 && stomach.contents.len == 0)) - nothing_to_puke = TRUE - else if(!(locate(/mob) in contents)) - nothing_to_puke = TRUE - - if(nothing_to_puke) - custom_emote(1,"dry heaves.") - return - - if(should_have_organ(BP_STOMACH)) - for(var/a in stomach.contents) - var/atom/movable/A = a - A.dropInto(get_turf(src)) - if(species.gluttonous & GLUT_PROJECTILE_VOMIT) - A.throw_at(get_edge_target_turf(src,dir),7,7,src) - else - for(var/mob/M in contents) - M.dropInto(get_turf(src)) - if(species.gluttonous & GLUT_PROJECTILE_VOMIT) - M.throw_at(get_edge_target_turf(src,dir),7,7,src) - - visible_message(SPAN_DANGER("\The [src] throws up!"),SPAN_DANGER("You throw up!")) - playsound(loc, 'sound/effects/splat.ogg', 50, 1) - var/turf/location = loc - if(istype(location, /turf/simulated)) - var/obj/effect/decal/cleanable/vomit/splat = new /obj/effect/decal/cleanable/vomit(location) - if(stomach.ingested.total_volume) - stomach.ingested.trans_to_obj(splat, min(15, stomach.ingested.total_volume)) - handle_additional_vomit_reagents(splat) - splat.update_icon() - -/mob/living/carbon/human/proc/vomit(var/timevomit = 1, var/level = 3, var/deliberate = FALSE) - - set waitfor = 0 - - if(!check_has_mouth() || isSynthetic() || !timevomit || !level || stat == DEAD || lastpuke) - return - - if(deliberate) - if(incapacitated()) - to_chat(src, SPAN_WARNING("You cannot do that right now.")) - return - var/datum/gender/G = gender_datums[gender] - visible_message(SPAN_DANGER("\The [src] starts sticking a finger down [G.his] own throat. It looks like [G.he] [G.is] trying to throw up!")) - if(!do_after(src, 30)) - return - timevomit = max(timevomit, 5) - - timevomit = Clamp(timevomit, 1, 10) - level = Clamp(level, 1, 3) - - lastpuke = TRUE - to_chat(src, SPAN_WARNING("You feel nauseous...")) - if(level > 1) - sleep(150 / timevomit) //15 seconds until second warning - to_chat(src, SPAN_WARNING("You feel like you are about to throw up!")) - if(level > 2) - sleep(100 / timevomit) //and you have 10 more for mad dash to the bucket - empty_stomach() - sleep(350) //wait 35 seconds before next volley - lastpuke = FALSE - -/mob/living/carbon/human/proc/morph() - set name = "Morph" - set category = "Superpower" - - if(stat!=CONSCIOUS) - reset_view(0) - remoteview_target = null - return - - if(!(mMorph in mutations)) - src.verbs -= /mob/living/carbon/human/proc/morph - return - - var/new_facial = input("Please select facial hair color.", "Character Generation", facial_hair_colour) as color - if(new_facial) - facial_hair_colour = new_facial - - var/new_hair = input("Please select hair color.", "Character Generation", hair_colour) as color - if(new_hair) - hair_colour = new_hair - - var/new_eyes = input("Please select eye color.", "Character Generation", eye_colour) as color - if(new_eyes) - eye_colour = new_eyes - update_eyes() - - var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[35-skin_tone]") as text - - if (!new_tone) - new_tone = 35 - skin_tone = max(min(round(text2num(new_tone)), 220), 1) - skin_tone = -skin_tone + 35 - - // hair - var/list/all_hairs = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair - var/list/hairs = list() - - // loop through potential hairs - for(var/x in all_hairs) - var/datum/sprite_accessory/hair/H = new x // create new hair datum based on type x - hairs.Add(H.name) // add hair name to hairs - qdel(H) // delete the hair after it's all done - - var/new_style = input("Please select hair style", "Character Generation",h_style) as null|anything in hairs - - // if new style selected (not cancel) - if (new_style) - h_style = new_style - - // facial hair - var/list/all_fhairs = typesof(/datum/sprite_accessory/facial_hair) - /datum/sprite_accessory/facial_hair - var/list/fhairs = list() - - for(var/x in all_fhairs) - var/datum/sprite_accessory/facial_hair/H = new x - fhairs.Add(H.name) - qdel(H) - - new_style = input("Please select facial style", "Character Generation",f_style) as null|anything in fhairs - - if(new_style) - f_style = new_style - - var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female", "Neutral") - if (new_gender) - if(new_gender == "Male") - gender = MALE - else if(new_gender == "Female") - gender = FEMALE - else - gender = NEUTER - regenerate_icons() - check_dna() - - visible_message("\The [src] morphs and changes [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] appearance!", "You change your appearance!", "Oh, god! What the hell was that? It sounded like flesh getting squished and bone ground into a different shape!") - -/mob/living/carbon/human/proc/remotesay() - set name = "Project mind" - set category = "Superpower" - - if(stat!=CONSCIOUS) - reset_view(0) - remoteview_target = null - return - - if(!(mRemotetalk in src.mutations)) - src.verbs -= /mob/living/carbon/human/proc/remotesay - return - var/list/creatures = list() - for(var/mob/living/carbon/h in world) - creatures += h - var/mob/target = input("Who do you want to project your mind to ?") as null|anything in creatures - if (isnull(target)) - return - - var/say = sanitize(input("What do you wish to say")) - if(mRemotetalk in target.mutations) - target.show_message("You hear [src.real_name]'s voice: [say]") - else - target.show_message("You hear a voice that seems to echo around the room: [say]") - usr.show_message("You project your mind into [target.real_name]: [say]") - log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]") - for(var/mob/observer/ghost/G in world) - G.show_message("Telepathic message from [src] to [target]: [say]") - -/mob/living/carbon/human/proc/remoteobserve() - set name = "Remote View" - set category = "Superpower" - - if(stat!=CONSCIOUS) - remoteview_target = null - reset_view(0) - return - - if(!(mRemote in src.mutations)) - remoteview_target = null - reset_view(0) - src.verbs -= /mob/living/carbon/human/proc/remoteobserve - return - - if(client.eye != client.mob) - remoteview_target = null - reset_view(0) - return - - var/list/mob/creatures = list() - - for(var/mob/living/carbon/h in world) - var/turf/temp_turf = get_turf(h) - if((temp_turf.z != 1 && temp_turf.z != 5) || h.stat!=CONSCIOUS) //Not on mining or the station. Or dead - continue - creatures += h - - var/mob/target = input ("Who do you want to project your mind to ?") as mob in creatures - - if (target) - remoteview_target = target - reset_view(target) - else - remoteview_target = null - reset_view(0) - -/atom/proc/get_visible_gender() - return gender - -/mob/living/carbon/human/get_visible_gender() - if(wear_suit && wear_suit.flags_inv & HIDEJUMPSUIT && ((head && head.flags_inv & HIDEMASK) || wear_mask)) - return NEUTER - return ..() - -/mob/living/carbon/human/proc/increase_germ_level(n) - if(gloves) - gloves.germ_level += n - else - germ_level += n - -/mob/living/carbon/human/revive() - - if(should_have_organ(BP_HEART)) - vessel.add_reagent(species.blood_reagent, species.blood_volume-vessel.total_volume) - fixblood() - - species.create_organs(src) // Reset our organs/limbs. - restore_all_organs() // Reapply robotics/amputated status from preferences. - - if(!client || !key) //Don't boot out anyone already in the mob. - for (var/obj/item/organ/internal/brain/H in world) - if(H.brainmob) - if(H.brainmob.real_name == src.real_name) - if(H.brainmob.mind) - H.brainmob.mind.transfer_to(src) - qdel(H) - - losebreath = 0 - UpdateAppearance() - ..() - -/mob/living/carbon/human/proc/is_lung_ruptured() - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[BP_LUNGS] - return L && L.is_bruised() - -/mob/living/carbon/human/proc/rupture_lung() - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[BP_LUNGS] - if(L) - L.rupture() - -/mob/living/carbon/human/add_blood(mob/living/carbon/human/M) - if (!..()) - return 0 - //if this blood isn't already in the list, add it - if(istype(M)) - if(!blood_DNA[M.dna.unique_enzymes]) - blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - var/datum/extension/forensic_evidence/forensics = get_or_create_extension(src, /datum/extension/forensic_evidence) - forensics.add_data(/datum/forensics/blood_dna, M.dna.unique_enzymes) - hand_blood_color = blood_color - src.update_inv_gloves() //handles bloody hands overlays and updating - verbs += /mob/living/carbon/human/proc/bloody_doodle - return 1 //we applied blood to the item - -/mob/living/carbon/human/clean_blood(var/clean_feet) - .=..() - if(gloves) - if(gloves.clean_blood()) - update_inv_gloves(1) - gloves.germ_level = 0 - else - if(!isnull(bloody_hands)) - bloody_hands = null - update_inv_gloves(1) - germ_level = 0 - - for(var/obj/item/organ/external/organ in organs) - if(clean_feet || (organ.organ_tag in list(BP_L_HAND,BP_R_HAND))) - var/datum/extension/forensic_evidence/forensics = get_extension(organ, /datum/extension/forensic_evidence) - if(forensics) - forensics.remove_data(/datum/forensics/gunshot_residue) - - if(clean_feet && !shoes) - feet_blood_color = null - feet_blood_DNA = null - update_inv_shoes(1) - return 1 - -/mob/living/carbon/human/get_visible_implants(var/class = 0) - - var/list/visible_implants = list() - for(var/obj/item/organ/external/organ in src.organs) - for(var/obj/item/O in organ.implants) - if(!istype(O,/obj/item/implant) && (O.w_class > class) && !istype(O,/obj/item/shard/shrapnel)) - visible_implants += O - - return(visible_implants) - -/mob/living/carbon/human/embedded_needs_process() - for(var/obj/item/organ/external/organ in src.organs) - for(var/obj/item/O in organ.implants) - if(!istype(O, /obj/item/implant)) //implant type items do not cause embedding effects, see handle_embedded_objects() - return 1 - return 0 - -/mob/living/carbon/human/handle_embedded_and_stomach_objects() - - if(embedded_flag) - for(var/obj/item/organ/external/organ in organs) - if(organ.splinted) - continue - for(var/obj/item/O in organ.implants) - if(!istype(O,/obj/item/implant) && O.w_class > ITEM_SIZE_TINY && prob(5)) //Moving with things stuck in you could be bad. - jostle_internal_object(organ, O) - - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(stomach && stomach.contents.len) - for(var/obj/item/O in stomach.contents) - if((O.edge || O.sharp) && prob(5)) - var/obj/item/organ/external/parent = get_organ(stomach.parent_organ) - if(prob(1) && can_feel_pain() && O.can_embed()) - to_chat(src, SPAN_DANGER("You feel something rip out of your [stomach.name]!")) - O.dropInto(loc) - if(parent) - parent.embed(O) - else - jostle_internal_object(parent, O) - -/mob/living/carbon/human/proc/jostle_internal_object(var/obj/item/organ/external/organ, var/obj/item/O) - // All kinds of embedded objects cause bleeding. - if(!organ.can_feel_pain()) - to_chat(src, SPAN_DANGER("You feel [O] moving inside your [organ.name].")) - else - var/msg = pick( \ - SPAN_DANGER("A spike of pain jolts your [organ.name] as you bump [O] inside."), \ - SPAN_DANGER("Your movement jostles [O] in your [organ.name] painfully."), \ - SPAN_DANGER("Your movement jostles [O] in your [organ.name] painfully.")) - custom_pain(msg,40,affecting = organ) - organ.take_external_damage(rand(1,3) + O.w_class, DAM_EDGE, 0) - -/mob/living/carbon/human/proc/remove_splints() - set category = "Object" - set name = "Remove Splints" - set desc = "Carefully remove splints from someone's limbs." - set src in view(1) - var/mob/living/user = usr - var/removed_splint = 0 - - if(usr.stat || usr.restrained() || !isliving(usr)) return - - for(var/obj/item/organ/external/o in organs) - if (o && o.splinted) - var/obj/item/S = o.splinted - if(!istype(S) || S.loc != o) //can only remove splints that are actually worn on the organ (deals with hardsuit splints) - to_chat(user, "You cannot remove any splints on [src]'s [o.name] - [o.splinted] is supporting some of the breaks.") - else - S.add_fingerprint(user) - if(o.remove_splint()) - user.put_in_active_hand(S) - removed_splint = 1 - if(removed_splint) - user.visible_message("\The [user] removes \the [src]'s splints!") - else - to_chat(user, "\The [src] has no splints that can be removed.") - verbs -= /mob/living/carbon/human/proc/remove_splints - - -/mob/living/carbon/human/verb/check_pulse() - set category = "Object" - set name = "Check pulse" - set desc = "Approximately count somebody's pulse. Requires you to stand still at least 6 seconds." - set src in view(1) - var/self = 0 - - if(usr.stat || usr.restrained() || !isliving(usr)) return - - if(usr == src) - self = 1 - if(!self) - usr.visible_message("[usr] kneels down, puts \his hand on [src]'s wrist and begins counting their pulse.",\ - "You begin counting [src]'s pulse") - else - usr.visible_message("[usr] begins counting their pulse.",\ - "You begin counting your pulse.") - - if(pulse()) - to_chat(usr, "[self ? "You have a" : "[src] has a"] pulse! Counting...") - else - to_chat(usr, "[src] has no pulse!")//it is REALLY UNLIKELY that a dead person would check his own pulse - return - - to_chat(usr, "You must[self ? "" : " both"] remain still until counting is finished.") - if(do_mob(usr, src, 60)) - var/message = "[self ? "Your" : "[src]'s"] pulse is [src.get_pulse(GETPULSE_HAND)]." - to_chat(usr, message) - else - to_chat(usr, "You failed to check the pulse. Try again.") - -/mob/living/carbon/human/proc/set_species(var/new_species, var/default_colour = 1) - if(!dna) - if(!new_species) - new_species = GLOB.using_map.default_species - else - if(!new_species) - new_species = dna.species - - // No more invisible screaming wheelchairs because of set_species() typos. - if(!get_species_by_key(new_species)) - new_species = GLOB.using_map.default_species - if(dna) - dna.species = new_species - - if(species) - - if(species.name && species.name == new_species) - return - - // Clear out their species abilities. - species.remove_base_auras(src) - species.remove_inherent_verbs(src) - holder_type = null - - species = get_species_by_key(new_species) - species.handle_pre_spawn(src) - - skin_colour = (species.base_color && default_colour) ? species.base_color : COLOR_BLACK - - if(species.holder_type) - holder_type = species.holder_type - - - if(!(gender in species.genders)) - gender = species.genders[1] - - icon_state = lowertext(species.name) - - species.create_organs(src) - species.handle_post_spawn(src) - - maxHealth = species.total_health - remove_extension(src, /datum/extension/armor) - if(species.natural_armour_values) - set_extension(src, /datum/extension/armor, species.natural_armour_values) - - default_pixel_x = initial(pixel_x) + species.pixel_offset_x - default_pixel_y = initial(pixel_y) + species.pixel_offset_y - default_pixel_z = initial(pixel_z) + species.pixel_offset_z - pixel_x = default_pixel_x - pixel_y = default_pixel_y - pixel_z = default_pixel_z - - if(LAZYLEN(descriptors)) - descriptors = null - - if(LAZYLEN(species.descriptors)) - descriptors = list() - for(var/desctype in species.descriptors) - var/datum/mob_descriptor/descriptor = species.descriptors[desctype] - descriptors[desctype] = descriptor.default_value - - if(!(species.appearance_flags & HAS_UNDERWEAR)) - QDEL_NULL_LIST(worn_underwear) - - available_maneuvers = species.maneuvers.Copy() - - meat_type = species.meat_type - meat_amount = species.meat_amount - skin_material = species.skin_material - skin_amount = species.skin_amount - bone_material = species.bone_material - bone_amount = species.bone_amount - - spawn(0) - regenerate_icons() - if(vessel.total_volume < species.blood_volume) - vessel.maximum_volume = species.blood_volume - vessel.add_reagent(species.blood_reagent, species.blood_volume - vessel.total_volume) - else if(vessel.total_volume > species.blood_volume) - vessel.remove_any(vessel.total_volume - species.blood_volume) - vessel.maximum_volume = species.blood_volume - fixblood() - - // Rebuild the HUD and visual elements. - if(client) - Login() - - full_prosthetic = null - - var/update_lang - for(var/token in ALL_CULTURAL_TAGS) - if(species.force_cultural_info && species.force_cultural_info[token]) - update_lang = TRUE - set_cultural_value(token, species.force_cultural_info[token], defer_language_update = TRUE) - else if(!cultural_info[token] || !(cultural_info[token] in species.available_cultural_info[token])) - update_lang = TRUE - set_cultural_value(token, species.default_cultural_info[token], defer_language_update = TRUE) - - default_walk_intent = null - default_run_intent = null - move_intent = null - move_intents = species.move_intents.Copy() - set_move_intent(decls_repository.get_decl(move_intents[1])) - if(!istype(move_intent)) - set_next_usable_move_intent() - - if(update_lang) - languages.Cut() - default_language = null - update_languages() - - //recheck species-restricted clothing - for(var/slot in slot_first to slot_last) - var/obj/item/clothing/C = get_equipped_item(slot) - if(istype(C) && !C.mob_can_equip(src, slot, 1)) - unEquip(C) - - return 1 - -/mob/living/carbon/human/proc/update_languages() - - var/list/permitted_languages = list() - var/list/free_languages = list() - var/list/default_languages = list() - - for(var/thing in cultural_info) - var/decl/cultural_info/check = cultural_info[thing] - if(istype(check)) - if(check.default_language) - free_languages |= check.default_language - default_languages |= check.default_language - if(check.language) - free_languages |= check.language - if(check.name_language) - free_languages |= check.name_language - for(var/lang in check.additional_langs) - free_languages |= lang - for(var/lang in check.get_spoken_languages()) - permitted_languages |= lang - - for(var/decl/language/lang in languages) - if(lang.type in permitted_languages) - continue - if(!(lang.flags & RESTRICTED) && (lang.flags & WHITELISTED) && is_alien_whitelisted(src, lang)) - continue - if(lang.type == default_language) - default_language = null - remove_language(lang.type) - - for(var/thing in free_languages) - add_language(thing) - - if(length(default_languages) && isnull(default_language)) - default_language = default_languages[1] - -/mob/living/carbon/human/proc/bloody_doodle() - set category = "IC" - set name = "Write in blood" - set desc = "Use blood on your hands to write a short message on the floor or a wall, murder mystery style." - - if (src.stat) - return - - if (usr != src) - return 0 //something is terribly wrong - - if (!bloody_hands) - verbs -= /mob/living/carbon/human/proc/bloody_doodle - - if (src.gloves) - to_chat(src, "Your [src.gloves] are getting in the way.") - return - - var/turf/simulated/T = src.loc - if (!istype(T)) //to prevent doodling out of mechs and lockers - to_chat(src, "You cannot reach the floor.") - return - - var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West") - if (direction != "Here") - T = get_step(T,text2dir(direction)) - if (!istype(T)) - to_chat(src, "You cannot doodle there.") - return - - var/num_doodles = 0 - for (var/obj/effect/decal/cleanable/blood/writing/W in T) - num_doodles++ - if (num_doodles > 4) - to_chat(src, "There is no space to write on!") - return - - var/max_length = bloody_hands * 30 //tweeter style - - var/message = sanitize(input("Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")) - - if (message) - var/used_blood_amount = round(length(message) / 30, 1) - bloody_hands = max(0, bloody_hands - used_blood_amount) //use up some blood - - if (length(message) > max_length) - message += "-" - to_chat(src, "You ran out of blood to write with!") - var/obj/effect/decal/cleanable/blood/writing/W = new(T) - W.basecolor = (hand_blood_color) ? hand_blood_color : COLOR_BLOOD_HUMAN - W.update_icon() - W.message = message - W.add_fingerprint(src) - -/mob/living/carbon/human/can_inject(var/mob/user, var/target_zone) - var/obj/item/organ/external/affecting = get_organ(target_zone) - - if(!affecting) - to_chat(user, SPAN_WARNING("\The [src] is missing that limb.")) - return 0 - - if(BP_IS_PROSTHETIC(affecting)) - to_chat(user, SPAN_WARNING("That limb is prosthetic.")) - return 0 - - . = CAN_INJECT - for(var/obj/item/clothing/C in list(head, wear_mask, wear_suit, w_uniform, gloves, shoes)) - if(C && (C.body_parts_covered & affecting.body_part) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) - if(istype(C, /obj/item/clothing/suit/space)) - . = INJECTION_PORT //it was going to block us, but it's a space suit so it doesn't because it has some kind of port - else - to_chat(user, "There is no exposed flesh or thin material on [src]'s [affecting.name] to inject into.") - return 0 - - -/mob/living/carbon/human/print_flavor_text(var/shrink = 1) - var/list/equipment = list(src.head,src.wear_mask,src.glasses,src.w_uniform,src.wear_suit,src.gloves,src.shoes) - var/head_exposed = 1 - var/face_exposed = 1 - var/eyes_exposed = 1 - var/torso_exposed = 1 - var/arms_exposed = 1 - var/legs_exposed = 1 - var/hands_exposed = 1 - var/feet_exposed = 1 - - for(var/obj/item/clothing/C in equipment) - if(C.body_parts_covered & HEAD) - head_exposed = 0 - if(C.body_parts_covered & FACE) - face_exposed = 0 - if(C.body_parts_covered & EYES) - eyes_exposed = 0 - if(C.body_parts_covered & UPPER_TORSO) - torso_exposed = 0 - if(C.body_parts_covered & ARMS) - arms_exposed = 0 - if(C.body_parts_covered & HANDS) - hands_exposed = 0 - if(C.body_parts_covered & LEGS) - legs_exposed = 0 - if(C.body_parts_covered & FEET) - feet_exposed = 0 - - flavor_text = "" - for (var/T in flavor_texts) - if(flavor_texts[T] && flavor_texts[T] != "") - if((T == "general") || (T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed)) - flavor_text += flavor_texts[T] - flavor_text += "\n\n" - if(!shrink) - return flavor_text - else - return ..() - -/mob/living/carbon/human/getDNA() - if(species.species_flags & SPECIES_FLAG_NO_SCAN) - return null - if(isSynthetic()) - return - ..() - -/mob/living/carbon/human/setDNA() - if(species.species_flags & SPECIES_FLAG_NO_SCAN) - return - if(isSynthetic()) - return - ..() - -/mob/living/carbon/human/has_brain() - if(internal_organs_by_name[BP_BRAIN]) - var/obj/item/organ/internal/brain = internal_organs_by_name[BP_BRAIN] - if(brain && istype(brain)) - return 1 - return 0 - -/mob/living/carbon/human/check_has_eyes() - if(internal_organs_by_name[BP_EYES]) - var/obj/item/organ/internal/eyes = internal_organs_by_name[BP_EYES] - . = eyes && eyes.is_usable() - -/mob/living/carbon/human/slip(var/slipped_on, stun_duration=8) - if((species.check_no_slip(src)) || (shoes && (shoes.item_flags & ITEM_FLAG_NOSLIP))) - return 0 - return !!(..(slipped_on,stun_duration)) - -/mob/living/carbon/human/proc/undislocate() - set category = "Object" - set name = "Undislocate Joint" - set desc = "Pop a joint back into place. Extremely painful." - set src in view(1) - - if(!isliving(usr) || !usr.canClick()) - return - - usr.setClickCooldown(20) - - if(usr.stat > 0) - to_chat(usr, "You are unconcious and cannot do that!") - return - - if(usr.restrained()) - to_chat(usr, "You are restrained and cannot do that!") - return - - var/mob/S = src - var/mob/U = usr - var/self = null - if(S == U) - self = 1 // Removing object from yourself. - - var/list/limbs = list() - for(var/limb in organs_by_name) - var/obj/item/organ/external/current_limb = organs_by_name[limb] - if(current_limb && current_limb.dislocated > 0 && !current_limb.is_parent_dislocated()) //if the parent is also dislocated you will have to relocate that first - limbs |= current_limb - var/obj/item/organ/external/current_limb = input(usr,"Which joint do you wish to relocate?") as null|anything in limbs - - if(!current_limb) - return - - if(self) - to_chat(src, "You brace yourself to relocate your [current_limb.joint]...") - else - to_chat(U, "You begin to relocate [S]'s [current_limb.joint]...") - if(!do_after(U, 30, src)) - return - if(!current_limb || !S || !U) - return - - var/fail_prob = U.skill_fail_chance(SKILL_MEDICAL, 60, SKILL_ADEPT, 3) - if(self) - fail_prob += U.skill_fail_chance(SKILL_MEDICAL, 20, SKILL_EXPERT, 1) - var/datum/gender/T = gender_datums[get_gender()] - if(prob(fail_prob)) - visible_message( \ - "[U] pops [self ? "[T.his]" : "[S]'s"] [current_limb.joint] in the WRONG place!", \ - "[self ? "You pop" : "[U] pops"] your [current_limb.joint] in the WRONG place!" \ - ) - current_limb.add_pain(30) - current_limb.take_external_damage(5) - shock_stage += 20 - else - visible_message( \ - "[U] pops [self ? "[T.his]" : "[S]'s"] [current_limb.joint] back in!", \ - "[self ? "You pop" : "[U] pops"] your [current_limb.joint] back in!" \ - ) - current_limb.undislocate() - -/mob/living/carbon/human/reset_view(atom/A, update_hud = 1) - ..() - if(update_hud) - handle_regular_hud_updates() - - -/mob/living/carbon/human/can_stand_overridden() - if(wearing_rig && wearing_rig.ai_can_move_suit(check_for_ai = 1)) - // Actually missing a leg will screw you up. Everything else can be compensated for. - for(var/limbcheck in list(BP_L_LEG,BP_R_LEG)) - var/obj/item/organ/affecting = get_organ(limbcheck) - if(!affecting) - return 0 - return 1 - return 0 - -/mob/living/carbon/human/verb/pull_punches() - set name = "Switch Stance" - set desc = "Try not to hurt them." - set category = "IC" - species.toggle_stance(src) - -// Similar to get_pulse, but returns only integer numbers instead of text. -/mob/living/carbon/human/proc/get_pulse_as_number() - var/obj/item/organ/internal/heart/heart_organ = internal_organs_by_name[BP_HEART] - if(!heart_organ) - return 0 - - switch(pulse()) - if(PULSE_NONE) - return 0 - if(PULSE_SLOW) - return rand(40, 60) - if(PULSE_NORM) - return rand(60, 90) - if(PULSE_FAST) - return rand(90, 120) - if(PULSE_2FAST) - return rand(120, 160) - if(PULSE_THREADY) - return PULSE_MAX_BPM - return 0 - -//generates realistic-ish pulse output based on preset levels as text -/mob/living/carbon/human/proc/get_pulse(var/method) //method 0 is for hands, 1 is for machines, more accurate - var/obj/item/organ/internal/heart/heart_organ = internal_organs_by_name[BP_HEART] - if(!heart_organ) - // No heart, no pulse - return "0" - if(heart_organ.open && !method) - // Heart is a open type (?) and cannot be checked unless it's a machine - return "muddled and unclear; you can't seem to find a vein" - - var/bpm = get_pulse_as_number() - if(bpm >= PULSE_MAX_BPM) - return method ? ">[PULSE_MAX_BPM]" : "extremely weak and fast, patient's artery feels like a thread" - - return "[method ? bpm : bpm + rand(-10, 10)]" -// output for machines ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ output for people - -/mob/living/carbon/human/proc/pulse() - var/obj/item/organ/internal/heart/H = internal_organs_by_name[BP_HEART] - return H ? H.pulse : PULSE_NONE - -/mob/living/carbon/human/can_devour(atom/movable/victim, var/silent = FALSE) - - if(!should_have_organ(BP_STOMACH)) - return ..() - - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(!stomach || !stomach.is_usable()) - if(!silent) - to_chat(src, SPAN_WARNING("Your stomach is not functional!")) - return FALSE - - if(!stomach.can_eat_atom(victim)) - if(!silent) - to_chat(src, SPAN_WARNING("You are not capable of devouring \the [victim] whole!")) - return FALSE - - if(stomach.is_full(victim)) - if(!silent) - to_chat(src, SPAN_WARNING("Your [stomach.name] is full!")) - return FALSE - - . = stomach.get_devour_time(victim) || ..() - -/mob/living/carbon/human/move_to_stomach(atom/movable/victim) - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(istype(stomach)) - victim.forceMove(stomach) - -/mob/living/carbon/human/should_have_organ(var/organ_check) - - var/obj/item/organ/external/affecting - if(organ_check in list(BP_HEART, BP_LUNGS)) - affecting = organs_by_name[BP_CHEST] - else if(organ_check in list(BP_LIVER, BP_KIDNEYS)) - affecting = organs_by_name[BP_GROIN] - - if(affecting && BP_IS_PROSTHETIC(affecting)) - return 0 - return (species && species.has_organ[organ_check]) - -/mob/living/carbon/human/can_feel_pain(var/obj/item/organ/check_organ) - if(isSynthetic()) - return 0 - if(check_organ) - if(!istype(check_organ)) - return 0 - return check_organ.can_feel_pain() - return !(species.species_flags & SPECIES_FLAG_NO_PAIN) - -/mob/living/carbon/human/get_breath_volume() - . = ..() - var/obj/item/organ/internal/heart/H = internal_organs_by_name[BP_HEART] - if(H && !H.open) - . *= (!BP_IS_PROSTHETIC(H)) ? pulse()/PULSE_NORM : 1.5 - -/mob/living/carbon/human/need_breathe() - if(!(mNobreath in mutations) && species.breathing_organ && should_have_organ(species.breathing_organ)) - return 1 - else - return 0 - -/mob/living/carbon/human/get_adjusted_metabolism(metabolism) - return ..() * (species ? species.metabolism_mod : 1) - -/mob/living/carbon/human/is_invisible_to(var/mob/viewer) - return (is_cloaked() || ..()) - -/mob/living/carbon/human/help_shake_act(mob/living/carbon/M) - if(src != M) - ..() - else - var/datum/gender/T = gender_datums[get_gender()] - visible_message( \ - "[src] examines [T.self].", \ - "You check yourself for injuries." \ - ) - - for(var/obj/item/organ/external/org in organs) - var/list/status = list() - - var/feels = 1 + round(org.pain/100, 0.1) - var/brutedamage = org.brute_dam * feels - var/burndamage = org.burn_dam * feels - - switch(brutedamage) - if(1 to 20) - status += "slightly sore" - if(20 to 40) - status += "very sore" - if(40 to INFINITY) - status += "throbbing with agony" - - switch(burndamage) - if(1 to 10) - status += "tingling" - if(10 to 40) - status += "stinging" - if(40 to INFINITY) - status += "burning fiercely" - - if(org.is_stump()) - status += "MISSING" - if(org.status & ORGAN_MUTATED) - status += "misshapen" - if(org.dislocated == 2) - status += "dislocated" - if(org.status & ORGAN_BROKEN) - status += "hurts when touched" - if(org.status & ORGAN_DEAD) - status += "is grey and necrotic" - if(!org.is_usable() || org.is_dislocated()) - status += "dangling uselessly" - if(status.len) - src.show_message("My [org.name] is [english_list(status)].",1) - else - src.show_message("My [org.name] is OK.",1) - - if((MUTATION_SKELETON in mutations) && (!w_uniform) && (!wear_suit)) - play_xylophone() - -/mob/living/carbon/human/proc/resuscitate() - if(!is_asystole() || !should_have_organ(BP_HEART)) - return - var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] - if(istype(heart) && !(heart.status & ORGAN_DEAD)) - var/species_organ = species.breathing_organ - var/active_breaths = 0 - if(species_organ) - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species_organ] - if(L) - active_breaths = L.active_breathing - if(!nervous_system_failure() && active_breaths) - visible_message("\The [src] jerks and gasps for breath!") - else - visible_message("\The [src] twitches a bit as \his heart restarts!") - shock_stage = min(shock_stage, 100) // 120 is the point at which the heart stops. - if(getOxyLoss() >= 75) - setOxyLoss(75) - heart.pulse = PULSE_NORM - heart.handle_pulse() - return TRUE - -/mob/living/carbon/human/proc/make_reagent(amount, reagent_type) - if(stat == CONSCIOUS) - var/limit = max(0, reagents.get_overdose(reagent_type) - REAGENT_VOLUME(reagents, reagent_type)) - reagents.add_reagent(reagent_type, min(amount, limit)) - -//Get fluffy numbers -/mob/living/carbon/human/proc/get_blood_pressure() - if(status_flags & FAKEDEATH) - return "[Floor(120+rand(-5,5))*0.25]/[Floor(80+rand(-5,5)*0.25)]" - var/blood_result = get_blood_circulation() - return "[Floor((120+rand(-5,5))*(blood_result/100))]/[Floor((80+rand(-5,5))*(blood_result/100))]" - -//Point at which you dun breathe no more. Separate from asystole crit, which is heart-related. -/mob/living/carbon/human/nervous_system_failure() - return getBrainLoss() >= maxHealth * 0.75 - -/mob/living/carbon/human/melee_accuracy_mods() - . = ..() - if(get_shock() > 50) - . += 15 - if(shock_stage > 10) - . += 15 - if(shock_stage > 30) - . += 15 - -/mob/living/carbon/human/ranged_accuracy_mods() - . = ..() - if(get_shock() > 10 && !skill_check(SKILL_WEAPONS, SKILL_ADEPT)) - . -= 1 - if(get_shock() > 50) - . -= 1 - if(shock_stage > 10) - . -= 1 - if(shock_stage > 30) - . -= 1 - if(skill_check(SKILL_WEAPONS, SKILL_ADEPT)) - . += 1 - if(skill_check(SKILL_WEAPONS, SKILL_EXPERT)) - . += 1 - if(skill_check(SKILL_WEAPONS, SKILL_PROF)) - . += 2 - -/mob/living/carbon/human/can_drown() - if(!internal && (!istype(wear_mask) || !wear_mask.filters_water())) - var/obj/item/organ/internal/lungs/L = locate() in internal_organs - return (!L || L.can_drown()) - return FALSE - -/mob/living/carbon/human/get_breath_from_environment(var/volume_needed = STD_BREATH_VOLUME) - var/datum/gas_mixture/breath = ..(volume_needed) - var/turf/T = get_turf(src) - if(istype(T) && T.is_flooded(lying) && should_have_organ(BP_LUNGS)) - var/can_breathe_water = (istype(wear_mask) && wear_mask.filters_water()) ? TRUE : FALSE - if(!can_breathe_water) - var/obj/item/organ/internal/lungs/lungs = internal_organs_by_name[BP_LUNGS] - if(lungs && lungs.can_drown()) - can_breathe_water = TRUE - if(can_breathe_water) - if(!breath) - breath = new - breath.volume = volume_needed - breath.temperature = T.temperature - breath.adjust_gas(/decl/material/gas/oxygen, ONE_ATMOSPHERE*volume_needed/(R_IDEAL_GAS_EQUATION*T20C)) - T.show_bubbles() - return breath - -/mob/living/carbon/human/fluid_act(var/datum/reagents/fluids) - species.fluid_act(src, fluids) - ..() - -/mob/living/carbon/human/proc/set_cultural_value(var/token, var/decl/cultural_info/_culture, var/defer_language_update) - if(!istype(_culture)) - _culture = SSlore.get_culture(_culture) - if(istype(_culture)) - cultural_info[token] = _culture - if(!defer_language_update) - update_languages() - -/mob/living/carbon/human/proc/get_cultural_value(var/token) - return cultural_info[token] - -/mob/living/carbon/human/needs_wheelchair() - var/stance_damage = 0 - for(var/limb_tag in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) - var/obj/item/organ/external/E = organs_by_name[limb_tag] - if(!E || !E.is_usable()) - stance_damage += 2 - return stance_damage >= 4 - -/mob/living/carbon/human/get_digestion_product() - return species.get_digestion_product(src) - -// A damaged stomach can put blood in your vomit. -/mob/living/carbon/human/handle_additional_vomit_reagents(var/obj/effect/decal/cleanable/vomit/vomit) - ..() - if(should_have_organ(BP_STOMACH)) - var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH] - if(!stomach || stomach.is_broken() || (stomach.is_bruised() && prob(stomach.damage))) - if(should_have_organ(BP_HEART)) - vessel.trans_to_obj(vomit, 5) - else - reagents.trans_to_obj(vomit, 5) - -/mob/living/carbon/human/get_footstep(var/footstep_type) - . = species.get_footstep(src, footstep_type) || ..() - -/mob/living/carbon/human/get_sound_volume_multiplier() - . = ..() - for(var/obj/item/clothing/ears/C in list(l_ear, r_ear)) - . = min(., C.volume_multiplier) - -/mob/living/carbon/human/get_bullet_impact_effect_type(var/def_zone) - var/obj/item/organ/external/E = get_organ(def_zone) - if(!E || E.is_stump()) - return BULLET_IMPACT_NONE - if(BP_IS_PROSTHETIC(E)) - return BULLET_IMPACT_METAL - return BULLET_IMPACT_MEAT - -/mob/living/carbon/human/bullet_impact_visuals(var/obj/item/projectile/P, var/def_zone, var/damage) - ..() - switch(get_bullet_impact_effect_type(def_zone)) - if(BULLET_IMPACT_MEAT) - if(damage && P.damtype == BRUTE) - var/hit_dir = get_dir(P.starting, src) - var/obj/effect/decal/cleanable/blood/B = blood_splatter(get_step(src, hit_dir), src, 1, hit_dir) - B.icon_state = pick("dir_splatter_1","dir_splatter_2") - var/scale = min(1, round(P.damage / 50, 0.2)) - var/matrix/M = new() - B.transform = M.Scale(scale) - - new /obj/effect/temp_visual/bloodsplatter(loc, hit_dir, species.blood_color) - -/mob/living/carbon/human/has_dexterity(var/dex_level) - . = check_dexterity(dex_level, silent = TRUE) - -/mob/living/carbon/human/check_dexterity(var/dex_level = DEXTERITY_FULL, var/silent, var/force_active_hand) - if(isnull(force_active_hand)) - force_active_hand = hand ? BP_L_HAND : BP_R_HAND - var/obj/item/organ/external/active_hand = organs_by_name[force_active_hand] - if(!active_hand) - if(!silent) - to_chat(src, SPAN_WARNING("Your hand is missing!")) - return FALSE - if(!active_hand.is_usable()) - to_chat(src, SPAN_WARNING("Your [active_hand.name] is unusable!")) - return - if(active_hand.get_dexterity() < dex_level) - if(!silent) - to_chat(src, SPAN_WARNING("Your [active_hand.name] doesn't have the dexterity to use that!")) - return FALSE - return TRUE - - -/mob/living/carbon/human/lose_hair() - if(species.set_default_hair(src)) - . = TRUE - if(species.handle_additional_hair_loss(src)) - . = TRUE - for(var/obj/item/organ/external/E in organs) - for(var/mark in E.markings) - var/list/marking_data = E.markings[mark] - var/datum/sprite_accessory/marking/mark_datum = marking_data["datum"] - if(mark_datum.flags & HAIR_LOSS_VULNERABLE) - E.markings -= mark - marking_data.Cut() - . = TRUE - if(.) - update_body() - to_chat(src, SPAN_DANGER("You feel a chill and your skin feels lighter...")) diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm deleted file mode 100644 index c770893441c7..000000000000 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ /dev/null @@ -1,306 +0,0 @@ -/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/target, var/hit_zone = null) - if(!hit_zone) - hit_zone = zone_sel.selecting - var/list/available_attacks = get_natural_attacks() - if(!default_attack || !default_attack.is_usable(src, target, hit_zone) || !(default_attack.type in available_attacks)) - default_attack = null - var/list/other_attacks = list() - for(var/u_attack_type in available_attacks) - var/decl/natural_attack/u_attack = decls_repository.get_decl(u_attack_type) - if(!u_attack.is_usable(src, target, hit_zone)) - continue - if(u_attack.is_starting_default) - default_attack = u_attack - break - other_attacks += u_attack - if(!default_attack && length(other_attacks)) - default_attack = pick(other_attacks) - . = default_attack && default_attack.resolve_to_soft_variant(src) - -/mob/living/carbon/human/proc/get_natural_attacks() - . = list() - for(var/obj/item/organ/external/limb in organs) - if(length(limb.unarmed_attacks) && limb.is_usable()) - . |= limb.unarmed_attacks - -/mob/living/carbon/human/attack_hand(mob/living/carbon/M) - - . = ..() - if(.) - return - - remove_cloaking_source(species) - - // Grabs are handled at a lower level. - if(istype(M) && M.a_intent == I_GRAB) - return 0 - - // Should this all be in Touch()? - var/mob/living/carbon/human/H = M - if(istype(H)) - if(H != src && check_shields(0, null, H, H.zone_sel.selecting, H.name)) - H.do_attack_animation(src) - return TRUE - - for (var/obj/item/grab/G in H) - if (G.assailant == H && G.affecting == src) - if(G.resolve_openhand_attack()) - return TRUE - - switch(M.a_intent) - if(I_HELP) - if(H != src && istype(H) && (is_asystole() || (status_flags & FAKEDEATH) || failed_last_breath)) - if (!cpr_time) - return TRUE - - var/pumping_skill = max(M.get_skill_value(SKILL_MEDICAL),M.get_skill_value(SKILL_ANATOMY)) - var/cpr_delay = 15 * M.skill_delay_mult(SKILL_ANATOMY, 0.2) - cpr_time = 0 - - H.visible_message("\The [H] is trying to perform CPR on \the [src].") - - if(!do_after(H, cpr_delay, src)) - cpr_time = 1 - return TRUE - cpr_time = 1 - - H.visible_message("\The [H] performs CPR on \the [src]!") - - if(is_asystole()) - if(prob(5 + 5 * (SKILL_EXPERT - pumping_skill))) - var/obj/item/organ/external/chest = get_organ(BP_CHEST) - if(chest) - chest.fracture() - - var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] - if(heart) - heart.external_pump = list(world.time, 0.4 + 0.1*pumping_skill + rand(-0.1,0.1)) - - if(stat != DEAD && prob(10 + 5 * pumping_skill)) - resuscitate() - - if(!H.check_has_mouth()) - to_chat(H, "You don't have a mouth, you cannot do mouth-to-mouth resuscitation!") - return TRUE - if(!check_has_mouth()) - to_chat(H, "They don't have a mouth, you cannot do mouth-to-mouth resuscitation!") - return TRUE - if((H.head && (H.head.body_parts_covered & FACE)) || (H.wear_mask && (H.wear_mask.body_parts_covered & FACE))) - to_chat(H, "You need to remove your mouth covering for mouth-to-mouth resuscitation!") - return TRUE - if((head && (head.body_parts_covered & FACE)) || (wear_mask && (wear_mask.body_parts_covered & FACE))) - to_chat(H, "You need to remove \the [src]'s mouth covering for mouth-to-mouth resuscitation!") - return TRUE - if (!H.internal_organs_by_name[H.species.breathing_organ]) - to_chat(H, "You need lungs for mouth-to-mouth resuscitation!") - return TRUE - if(!need_breathe()) - return TRUE - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species.breathing_organ] - if(L) - var/datum/gas_mixture/breath = H.get_breath_from_environment() - var/fail = L.handle_breath(breath, 1) - if(!fail) - to_chat(src, "You feel a breath of fresh air enter your lungs. It feels good.") - - else if(!(M == src && apply_pressure(M, M.zone_sel.selecting))) - help_shake_act(M) - return TRUE - - if(I_HURT) - if(H.incapacitated()) - to_chat(H, "You can't attack while incapacitated.") - return TRUE - - if(!istype(H)) - attack_generic(H,rand(1,3),"punched") - return TRUE - - var/rand_damage = rand(1, 5) - var/block = 0 - var/accurate = 0 - var/hit_zone = H.zone_sel.selecting - var/obj/item/organ/external/affecting = get_organ(hit_zone) - - // See what attack they use - var/decl/natural_attack/attack = H.get_unarmed_attack(src, hit_zone) - if(!attack) - return TRUE - if(world.time < H.last_attack + attack.delay) - to_chat(H, "You can't attack again so soon.") - return TRUE - else - H.last_attack = world.time - - if(!affecting || affecting.is_stump()) - to_chat(M, "They are missing that limb!") - return TRUE - - switch(src.a_intent) - if(I_HELP) - // We didn't see this coming, so we get the full blow - rand_damage = 5 - accurate = 1 - if(I_HURT, I_GRAB) - // We're in a fighting stance, there's a chance we block - if(MayMove() && src!=H && prob(20)) - block = 1 - - if (LAZYLEN(M.grabbed_by)) - // Someone got a good grip on them, they won't be able to do much damage - rand_damage = max(1, rand_damage - 2) - - if(LAZYLEN(grabbed_by) || !src.MayMove() || src==H || H.species.species_flags & SPECIES_FLAG_NO_BLOCK) - accurate = 1 // certain circumstances make it impossible for us to evade punches - rand_damage = 5 - - // Process evasion and blocking - var/miss_type = 0 - var/attack_message - if(!accurate) - /* ~Hubblenaut - This place is kind of convoluted and will need some explaining. - ran_zone() will pick out of 11 zones, thus the chance for hitting - our target where we want to hit them is circa 9.1%. - - Now since we want to statistically hit our target organ a bit more - often than other organs, we add a base chance of 20% for hitting it. - - This leaves us with the following chances: - - If aiming for chest: - 27.3% chance you hit your target organ - 70.5% chance you hit a random other organ - 2.2% chance you miss - - If aiming for something else: - 23.2% chance you hit your target organ - 56.8% chance you hit a random other organ - 15.0% chance you miss - - Note: We don't use get_zone_with_miss_chance() here since the chances - were made for projectiles. - TODO: proc for melee combat miss chances depending on organ? - */ - if(prob(80)) - hit_zone = ran_zone(hit_zone) - if(prob(15) && hit_zone != BP_CHEST) // Missed! - if(!src.lying) - attack_message = "[H] attempted to strike [src], but missed!" - else - attack_message = "[H] attempted to strike [src], but \he rolled out of the way!" - src.set_dir(pick(GLOB.cardinal)) - miss_type = 1 - - if(!miss_type && block) - attack_message = "[H] went for [src]'s [affecting.name] but was blocked!" - miss_type = 2 - - H.do_attack_animation(src) - if(!attack_message) - attack.show_attack(H, src, hit_zone, rand_damage) - else - H.visible_message("[attack_message]") - - playsound(loc, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1) - admin_attack_log(H, src, "[miss_type ? (miss_type == 1 ? "Has missed" : "Was blocked by") : "Has [pick(attack.attack_verb)]"] their victim.", "[miss_type ? (miss_type == 1 ? "Missed" : "Blocked") : "[pick(attack.attack_verb)]"] their attacker", "[miss_type ? (miss_type == 1 ? "has missed" : "was blocked by") : "has [pick(attack.attack_verb)]"]") - - if(miss_type) - return TRUE - - var/real_damage = rand_damage - real_damage += attack.get_unarmed_damage(H) - real_damage *= damage_multiplier - rand_damage *= damage_multiplier - if(MUTATION_HULK in H.mutations) - real_damage *= 2 // Hulks do twice the damage - rand_damage *= 2 - real_damage = max(1, real_damage) - // Apply additional unarmed effects. - attack.apply_effects(H, src, rand_damage, hit_zone) - // Finally, apply damage to target - apply_damage(real_damage, attack.get_damage_type(), hit_zone, damage_flags=attack.damage_flags()) - return TRUE - - if(I_DISARM) - if(H.species) - admin_attack_log(M, src, "Disarmed their victim.", "Was disarmed.", "disarmed") - H.species.disarm_attackhand(H, src) - return TRUE - -/mob/living/carbon/human/proc/afterattack(atom/target, mob/living/user, inrange, params) - return - -//Breaks all grips and pulls that the mob currently has. -/mob/living/carbon/human/proc/break_all_grabs(mob/living/carbon/user) - var/success = 0 - if(istype(l_hand, /obj/item/grab)) - var/obj/item/grab/lgrab = l_hand - if(lgrab.affecting) - visible_message("[user] has broken [src]'s grip on [lgrab.affecting]!") - success = 1 - spawn(1) - qdel(lgrab) - if(istype(r_hand, /obj/item/grab)) - var/obj/item/grab/rgrab = r_hand - if(rgrab.affecting) - visible_message("[user] has broken [src]'s grip on [rgrab.affecting]!") - success = 1 - spawn(1) - qdel(rgrab) - return success -/* - We want to ensure that a mob may only apply pressure to one organ of one mob at any given time. Currently this is done mostly implicitly through - the behaviour of do_after() and the fact that applying pressure to someone else requires a grab: - - If you are applying pressure to yourself and attempt to grab someone else, you'll change what you are holding in your active hand which will stop do_mob() - If you are applying pressure to another and attempt to apply pressure to yourself, you'll have to switch to an empty hand which will also stop do_mob() - Changing targeted zones should also stop do_mob(), preventing you from applying pressure to more than one body part at once. -*/ -/mob/living/carbon/human/proc/apply_pressure(mob/living/user, var/target_zone) - var/obj/item/organ/external/organ = get_organ(target_zone) - if(!organ || !(organ.status & ORGAN_BLEEDING) || BP_IS_PROSTHETIC(organ)) - return 0 - - if(organ.applied_pressure) - var/message = "[ismob(organ.applied_pressure)? "Someone" : "\A [organ.applied_pressure]"] is already applying pressure to [user == src? "your [organ.name]" : "[src]'s [organ.name]"]." - to_chat(user, message) - return 0 - - if(user == src) - user.visible_message("\The [user] starts applying pressure to \his [organ.name]!", "You start applying pressure to your [organ.name]!") - else - user.visible_message("\The [user] starts applying pressure to [src]'s [organ.name]!", "You start applying pressure to [src]'s [organ.name]!") - spawn(0) - organ.applied_pressure = user - - //apply pressure as long as they stay still and keep grabbing - do_mob(user, src, INFINITY, target_zone, progress = 0) - - organ.applied_pressure = null - - if(user == src) - user.visible_message("\The [user] stops applying pressure to \his [organ.name]!", "You stop applying pressure to your [organ.name]!") - else - user.visible_message("\The [user] stops applying pressure to [src]'s [organ.name]!", "You stop applying pressure to [src]'s [organ.name]!") - - return 1 - -/mob/living/carbon/human/verb/set_default_unarmed_attack() - set name = "Set Default Unarmed Attack" - set category = "IC" - set src = usr - - var/list/choices = list() - for(var/thing in get_natural_attacks()) - var/decl/natural_attack/u_attack = decls_repository.get_decl(thing) - if(istype(u_attack)) - choices[u_attack.attack_name] = u_attack - - var/selection = input("Select a default attack (currently selected: [default_attack ? default_attack.attack_name : "none"]).", "Default Unarmed Attack") as null|anything in choices - var/decl/natural_attack/new_attack = choices[selection] - if(selection && !(new_attack.type in get_natural_attacks())) - return - - default_attack = selection ? choices[selection] : null - to_chat(src, SPAN_NOTICE("Your default unarmed attack is now [default_attack ? default_attack.attack_name : "cleared"].")) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm deleted file mode 100644 index a3f0ef6b5fb0..000000000000 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ /dev/null @@ -1,439 +0,0 @@ -//Updates the mob's health from organs and mob damage variables -/mob/living/carbon/human/updatehealth() - - if(status_flags & GODMODE) - health = maxHealth - set_stat(CONSCIOUS) - return - - health = maxHealth - getBrainLoss() - - //TODO: fix husking - if(((maxHealth - getFireLoss()) < config.health_threshold_dead) && stat == DEAD) - ChangeToHusk() - return - -/mob/living/carbon/human/adjustBrainLoss(var/amount) - if(status_flags & GODMODE) return 0 //godmode - if(should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/sponge = internal_organs_by_name[BP_BRAIN] - if(sponge) - sponge.take_internal_damage(amount) - -/mob/living/carbon/human/setBrainLoss(var/amount) - if(status_flags & GODMODE) return 0 //godmode - if(should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/sponge = internal_organs_by_name[BP_BRAIN] - if(sponge) - sponge.damage = min(max(amount, 0),sponge.species.total_health) - updatehealth() - -/mob/living/carbon/human/getBrainLoss() - if(status_flags & GODMODE) return 0 //godmode - if(should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/sponge = internal_organs_by_name[BP_BRAIN] - if(sponge) - if(sponge.status & ORGAN_DEAD) - return sponge.species.total_health - else - return sponge.damage - else - return species.total_health - return 0 - -//Straight pain values, not affected by painkillers etc -/mob/living/carbon/human/getHalLoss() - var/amount = 0 - for(var/obj/item/organ/external/E in organs) - amount += E.get_pain() - return amount - -/mob/living/carbon/human/setHalLoss(var/amount) - adjustHalLoss(getHalLoss()-amount) - -/mob/living/carbon/human/adjustHalLoss(var/amount) - var/heal = (amount < 0) - amount = abs(amount) - var/list/pick_organs = organs.Copy() - while(amount > 0 && pick_organs.len) - var/obj/item/organ/external/E = pick(pick_organs) - pick_organs -= E - if(!istype(E)) - continue - - if(heal) - amount -= E.remove_pain(amount) - else - amount -= E.add_pain(amount) - BITSET(hud_updateflag, HEALTH_HUD) - -//These procs fetch a cumulative total damage from all organs -/mob/living/carbon/human/getBruteLoss() - var/amount = 0 - for(var/obj/item/organ/external/O in organs) - if(BP_IS_PROSTHETIC(O) && !O.vital) - continue //robot limbs don't count towards shock and crit - amount += O.brute_dam - return amount - -/mob/living/carbon/human/getFireLoss() - var/amount = 0 - for(var/obj/item/organ/external/O in organs) - if(BP_IS_PROSTHETIC(O) && !O.vital) - continue //robot limbs don't count towards shock and crit - amount += O.burn_dam - return amount - -/mob/living/carbon/human/adjustBruteLoss(var/amount) - if(amount > 0) - take_overall_damage(amount, 0) - else - heal_overall_damage(-amount, 0) - BITSET(hud_updateflag, HEALTH_HUD) - -/mob/living/carbon/human/adjustFireLoss(var/amount) - if(amount > 0) - take_overall_damage(0, amount) - else - heal_overall_damage(0, -amount) - BITSET(hud_updateflag, HEALTH_HUD) - -/mob/living/carbon/human/Stun(amount) - amount *= species.stun_mod - if(amount <= 0 || (MUTATION_HULK in mutations)) return - ..() - -/mob/living/carbon/human/Weaken(amount) - amount *= species.weaken_mod - if(amount <= 0 || (MUTATION_HULK in mutations)) return - ..(amount) - -/mob/living/carbon/human/Paralyse(amount) - amount *= species.paralysis_mod - if(amount <= 0 || (MUTATION_HULK in mutations)) return - // Notify our AI if they can now control the suit. - if(wearing_rig && !stat && paralysis < amount) //We are passing out right this second. - wearing_rig.notify_ai("Warning: user consciousness failure. Mobility control passed to integrated intelligence system.") - ..(amount) - -/mob/living/carbon/human/getCloneLoss() - var/amount = 0 - for(var/obj/item/organ/external/E in organs) - amount += E.get_genetic_damage() - return amount - -/mob/living/carbon/human/setCloneLoss(var/amount) - adjustCloneLoss(getCloneLoss()-amount) - -/mob/living/carbon/human/adjustCloneLoss(var/amount) - var/heal = amount < 0 - amount = abs(amount) - - var/list/pick_organs = organs.Copy() - while(amount > 0 && pick_organs.len) - var/obj/item/organ/external/E = pick(pick_organs) - pick_organs -= E - if(heal) - amount -= E.remove_genetic_damage(amount) - else - amount -= E.add_genetic_damage(amount) - BITSET(hud_updateflag, HEALTH_HUD) - -// Defined here solely to take species flags into account without having to recast at mob/living level. -/mob/living/carbon/human/getOxyLoss() - if(!need_breathe()) - return 0 - else - var/obj/item/organ/internal/lungs/breathe_organ = internal_organs_by_name[species.breathing_organ] - if(!breathe_organ) - return maxHealth/2 - return breathe_organ.get_oxygen_deprivation() - -/mob/living/carbon/human/setOxyLoss(var/amount) - if(!need_breathe()) - return 0 - else - adjustOxyLoss(getOxyLoss()-amount) - -/mob/living/carbon/human/adjustOxyLoss(var/amount) - if(!need_breathe()) - return - var/heal = amount < 0 - var/obj/item/organ/internal/lungs/breathe_organ = internal_organs_by_name[species.breathing_organ] - if(breathe_organ) - if(heal) - breathe_organ.remove_oxygen_deprivation(abs(amount)) - else - breathe_organ.add_oxygen_deprivation(abs(amount*species.oxy_mod)) - BITSET(hud_updateflag, HEALTH_HUD) - -/mob/living/carbon/human/getToxLoss() - if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) - return 0 - var/amount = 0 - for(var/obj/item/organ/internal/I in internal_organs) - amount += I.getToxLoss() - return amount - -/mob/living/carbon/human/setToxLoss(var/amount) - if(!(species.species_flags & SPECIES_FLAG_NO_POISON) && !isSynthetic()) - adjustToxLoss(getToxLoss()-amount) - -// TODO: better internal organ damage procs. -/mob/living/carbon/human/adjustToxLoss(var/amount) - - if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) - return - - var/heal = amount < 0 - amount = abs(amount) - - if (!heal) - amount = amount * species.get_toxins_mod(src) - if (CE_ANTITOX in chem_effects) - amount *= 1 - (chem_effects[CE_ANTITOX] * 0.25) - - var/list/pick_organs = shuffle(internal_organs.Copy()) - - // Prioritize damaging our filtration organs first. - var/obj/item/organ/internal/kidneys/kidneys = internal_organs_by_name[BP_KIDNEYS] - if(kidneys) - pick_organs -= kidneys - pick_organs.Insert(1, kidneys) - var/obj/item/organ/internal/liver/liver = internal_organs_by_name[BP_LIVER] - if(liver) - pick_organs -= liver - pick_organs.Insert(1, liver) - - // Move the brain to the very end since damage to it is vastly more dangerous - // (and isn't technically counted as toxloss) than general organ damage. - var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN] - if(brain) - pick_organs -= brain - pick_organs += brain - - for(var/internal in pick_organs) - var/obj/item/organ/internal/I = internal - if(amount <= 0) - break - if(heal) - if(I.damage < amount) - amount -= I.damage - I.damage = 0 - else - I.damage -= amount - amount = 0 - else - var/cap_dam = I.max_damage - I.damage - if(amount >= cap_dam) - I.take_internal_damage(cap_dam, silent=TRUE) - amount -= cap_dam - else - I.take_internal_damage(amount, silent=TRUE) - amount = 0 - -/mob/living/carbon/human/proc/can_autoheal(var/dam_type) - if(!species || !dam_type) return FALSE - - if(dam_type == BRUTE) - return(getBruteLoss() < species.total_health / 2) - else if(dam_type == BURN) - return(getFireLoss() < species.total_health / 2) - return FALSE - -//////////////////////////////////////////// - -//Returns a list of damaged organs -/mob/living/carbon/human/proc/get_damaged_organs(var/brute, var/burn) - var/list/obj/item/organ/external/parts = list() - for(var/obj/item/organ/external/O in organs) - if((brute && O.brute_dam) || (burn && O.burn_dam)) - parts += O - return parts - -//Returns a list of damageable organs -/mob/living/carbon/human/proc/get_damageable_organs() - var/list/obj/item/organ/external/parts = list() - for(var/obj/item/organ/external/O in organs) - if(O.is_damageable()) - parts += O - return parts - -//Heals ONE external organ, organ gets randomly selected from damaged ones. -//It automatically updates damage overlays if necesary -//It automatically updates health status -/mob/living/carbon/human/heal_organ_damage(var/brute, var/burn, var/affect_robo = 0) - var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn) - if(!parts.len) return - var/obj/item/organ/external/picked = pick(parts) - if(picked.heal_damage(brute,burn,robo_repair = affect_robo)) - BITSET(hud_updateflag, HEALTH_HUD) - updatehealth() - - -//TODO reorganize damage procs so that there is a clean API for damaging living mobs - -/* -In most cases it makes more sense to use apply_damage() instead! And make sure to check armour if applicable. -*/ -//Damages ONE external organ, organ gets randomly selected from damagable ones. -//It automatically updates damage overlays if necesary -//It automatically updates health status -/mob/living/carbon/human/take_organ_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0) - var/list/obj/item/organ/external/parts = get_damageable_organs() - if(!parts.len) - return - - var/obj/item/organ/external/picked = pick(parts) - var/damage_flags = (sharp? DAM_SHARP : 0)|(edge? DAM_EDGE : 0) - - if(picked.take_external_damage(brute, burn, damage_flags)) - BITSET(hud_updateflag, HEALTH_HUD) - - updatehealth() - - -//Heal MANY external organs, in random order -/mob/living/carbon/human/heal_overall_damage(var/brute, var/burn) - var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn) - - while(parts.len && (brute>0 || burn>0) ) - var/obj/item/organ/external/picked = pick(parts) - - var/brute_was = picked.brute_dam - var/burn_was = picked.burn_dam - - picked.heal_damage(brute,burn) - - brute -= (brute_was-picked.brute_dam) - burn -= (burn_was-picked.burn_dam) - - parts -= picked - updatehealth() - BITSET(hud_updateflag, HEALTH_HUD) - -// damage MANY external organs, in random order -/mob/living/carbon/human/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0, var/used_weapon = null) - if(status_flags & GODMODE) return //godmode - var/list/obj/item/organ/external/parts = get_damageable_organs() - if(!parts.len) return - - var/dam_flags = (sharp? DAM_SHARP : 0)|(edge? DAM_EDGE : 0) - var/brute_avg = brute / parts.len - var/burn_avg = burn / parts.len - for(var/obj/item/organ/external/E in parts) - if(QDELETED(E)) - continue - if(E.owner != src) - continue // The code below may affect the children of an organ. - - if(brute_avg) - apply_damage(damage = brute_avg, damagetype = BRUTE, damage_flags = dam_flags, used_weapon = used_weapon, silent = TRUE, given_organ = E) - if(burn_avg) - apply_damage(damage = burn_avg, damagetype = BURN, damage_flags = dam_flags, used_weapon = used_weapon, silent = TRUE, given_organ = E) - - updatehealth() - BITSET(hud_updateflag, HEALTH_HUD) - - -//////////////////////////////////////////// - -/* -This function restores the subjects blood to max. -*/ -/mob/living/carbon/human/proc/restore_blood() - if(!should_have_organ(BP_HEART)) - return - if(vessel.total_volume < species.blood_volume) - vessel.add_reagent(species.blood_reagent, species.blood_volume - vessel.total_volume) - -/* -This function restores all organs. -*/ -/mob/living/carbon/human/restore_all_organs(var/ignore_prosthetic_prefs) - for(var/bodypart in BP_BY_DEPTH) - var/obj/item/organ/external/current_organ = organs_by_name[bodypart] - if(istype(current_organ)) - current_organ.rejuvenate(ignore_prosthetic_prefs) - verbs -= /mob/living/carbon/human/proc/undislocate - -/mob/living/carbon/human/proc/HealDamage(zone, brute, burn) - var/obj/item/organ/external/E = get_organ(zone) - if(istype(E, /obj/item/organ/external)) - if (E.heal_damage(brute, burn)) - BITSET(hud_updateflag, HEALTH_HUD) - else - return 0 - return - -/mob/living/carbon/human/get_organ(var/zone) - return organs_by_name[check_zone(zone)] - -/mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/damage_flags = 0, var/obj/used_weapon = null, var/armor_pen, var/silent = FALSE, var/obj/item/organ/external/given_organ = null) - - var/obj/item/organ/external/organ = given_organ - if(!organ) - if(isorgan(def_zone)) - organ = def_zone - else - if(!def_zone) - if(damage_flags & DAM_DISPERSED) - var/old_damage = damage - var/tally - silent = TRUE // Will damage a lot of organs, probably, so avoid spam. - for(var/zone in organ_rel_size) - tally += organ_rel_size[zone] - for(var/zone in organ_rel_size) - damage = old_damage * organ_rel_size[zone]/tally - def_zone = zone - . = .() || . - return - def_zone = ran_zone(def_zone) - organ = get_organ(check_zone(def_zone)) - - //Handle other types of damage - if(!(damagetype in list(BRUTE, BURN, PAIN, CLONE))) - return ..() - if(!istype(organ)) - return 0 // This is reasonable and means the organ is missing. - - handle_suit_punctures(damagetype, damage, def_zone) - - var/list/after_armor = modify_damage_by_armor(def_zone, damage, damagetype, damage_flags, src, armor_pen, silent) - damage = after_armor[1] - damagetype = after_armor[2] - damage_flags = after_armor[3] - if(!damage) - return 0 - - if(damage > 15 && prob(damage*4) && organ.can_feel_pain()) - make_reagent(round(damage/10), /decl/material/liquid/adrenaline) - var/datum/wound/created_wound - damageoverlaytemp = 20 - switch(damagetype) - if(BRUTE) - created_wound = organ.take_external_damage(damage, 0, damage_flags, used_weapon) - if(BURN) - created_wound = organ.take_external_damage(0, damage, damage_flags, used_weapon) - if(PAIN) - organ.add_pain(damage) - if(CLONE) - organ.add_genetic_damage(damage) - - // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). - updatehealth() - BITSET(hud_updateflag, HEALTH_HUD) - return created_wound - -// Find out in how much pain the mob is at the moment. -/mob/living/carbon/human/proc/get_shock() - - if (!can_feel_pain()) - return 0 - - var/traumatic_shock = getHalLoss() // Pain. - traumatic_shock -= chem_effects[CE_PAINKILLER] // TODO: check what is actually stored here. - - if(stat == UNCONSCIOUS) - traumatic_shock *= 0.6 - return max(0,traumatic_shock) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm deleted file mode 100644 index 0a02413ee644..000000000000 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ /dev/null @@ -1,445 +0,0 @@ -/* -Contains most of the procs that are called when a mob is attacked by something - -bullet_act -ex_act -meteor_act - -*/ - -/mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone) - - def_zone = check_zone(def_zone) - if(!has_organ(def_zone)) - return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by. - - //Shields - var/shield_check = check_shields(P.damage, P, null, def_zone, "the [P.name]") - if(shield_check) - if(shield_check < 0) - return shield_check - else - P.on_hit(src, 100, def_zone) - return 100 - - var/blocked = ..(P, def_zone) - - radio_interrupt_cooldown = world.time + (RADIO_INTERRUPT_DEFAULT * 0.8) - - return blocked - -/mob/living/carbon/human/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone) - var/obj/item/organ/external/affected = get_organ(check_zone(def_zone)) - if(!affected) - return - - var/siemens_coeff = get_siemens_coefficient_organ(affected) - stun_amount *= siemens_coeff - agony_amount *= siemens_coeff - agony_amount *= affected.get_agony_multiplier() - - affected.stun_act(stun_amount, agony_amount) - - radio_interrupt_cooldown = world.time + RADIO_INTERRUPT_DEFAULT - - if(!affected.can_feel_pain() || (chem_effects[CE_PAINKILLER]/3 > agony_amount))//stops blurry eyes and stutter if you can't feel pain - agony_amount = 0 - - ..(stun_amount, agony_amount, def_zone) - -/mob/living/carbon/human/get_blocked_ratio(def_zone, damage_type, damage_flags, armor_pen, damage) - if(!def_zone && (damage_flags & DAM_DISPERSED)) - var/tally - for(var/zone in organ_rel_size) - tally += organ_rel_size[zone] - for(var/zone in organ_rel_size) - def_zone = zone - . += .() * organ_rel_size/tally - return - return ..() - -/mob/living/carbon/human/get_armors_by_zone(obj/item/organ/external/def_zone, damage_type, damage_flags) - . = ..() - if(!def_zone) - def_zone = ran_zone() - if(!istype(def_zone)) - def_zone = get_organ(check_zone(def_zone)) - if(!def_zone) - return - var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) - for(var/obj/item/clothing/gear in protective_gear) - if(gear.accessories.len) - for(var/obj/item/clothing/accessory/bling in gear.accessories) - if(bling.body_parts_covered & def_zone.body_part) - var/armor = get_extension(bling, /datum/extension/armor) - if(armor) - . += armor - if(gear.body_parts_covered & def_zone.body_part) - var/armor = get_extension(gear, /datum/extension/armor) - if(armor) - . += armor - -//this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. -/mob/living/carbon/human/proc/get_siemens_coefficient_organ(var/obj/item/organ/external/def_zone) - if (!def_zone) - return 1.0 - - var/siemens_coefficient = max(species.siemens_coefficient,0) - - var/list/clothing_items = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) // What all are we checking? - for(var/obj/item/clothing/C in clothing_items) - if(istype(C) && (C.body_parts_covered & def_zone.body_part)) // Is that body part being targeted covered? - siemens_coefficient *= C.siemens_coefficient - - return siemens_coefficient - -/mob/living/carbon/human/proc/check_head_coverage() - - var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) - for(var/bp in body_parts) - if(!bp) continue - if(bp && istype(bp ,/obj/item/clothing)) - var/obj/item/clothing/C = bp - if(C.body_parts_covered & HEAD) - return 1 - return 0 - -//Used to check if they can be fed food/drinks/pills -/mob/living/carbon/human/check_mouth_coverage() - var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform) - for(var/obj/item/gear in protective_gear) - if(istype(gear) && (gear.body_parts_covered & FACE) && !(gear.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) - return gear - return null - -/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - for(var/obj/item/shield in list(l_hand, r_hand, wear_suit)) - if(!shield) continue - . = shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text) - if(.) return - return 0 - -/mob/living/carbon/human/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) - - for (var/obj/item/grab/G in grabbed_by) - if(G.resolve_item_attack(user, I, target_zone)) - return null - - if(user == src) // Attacking yourself can't miss - return target_zone - - var/accuracy_penalty = user.melee_accuracy_mods() - accuracy_penalty += 10*get_skill_difference(SKILL_COMBAT, user) - accuracy_penalty += 10*(I.w_class - ITEM_SIZE_NORMAL) - accuracy_penalty -= I.melee_accuracy_bonus - - var/hit_zone = get_zone_with_miss_chance(target_zone, src, accuracy_penalty) - - if(!hit_zone) - visible_message("\The [user] misses [src] with \the [I]!") - return null - - if(check_shields(I.force, I, user, target_zone, "the [I.name]")) - return null - - var/obj/item/organ/external/affecting = get_organ(hit_zone) - if (!affecting || affecting.is_stump()) - to_chat(user, "They are missing that limb!") - return null - - return hit_zone - -/mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - var/obj/item/organ/external/affecting = get_organ(hit_zone) - if(!affecting) - return //should be prevented by attacked_with_item() but for sanity. - - var/weapon_mention - if(I.attack_message_name()) - weapon_mention = " with [I.attack_message_name()]" - if(effective_force) - visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name][weapon_mention] by [user]!") - else - visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name][weapon_mention] by [user]!") - return // If it has no force then no need to do anything else. - - return standard_weapon_hit_effects(I, user, effective_force, hit_zone) - -/mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - var/obj/item/organ/external/affecting = get_organ(hit_zone) - if(!affecting) - return 0 - - var/blocked = get_blocked_ratio(hit_zone, I.damtype, I.damage_flags(), I.armor_penetration, I.force) - // Handle striking to cripple. - if(user.a_intent == I_DISARM) - effective_force *= 0.66 //reduced effective force... - if(!..(I, user, effective_force, hit_zone)) - return 0 - - //set the dislocate mult less than the effective force mult so that - //dislocating limbs on disarm is a bit easier than breaking limbs on harm - attack_joint(affecting, I, effective_force, 0.5, blocked) //...but can dislocate joints - else if(!..()) - return 0 - - if(effective_force > 10 || effective_force >= 5 && prob(33)) - forcesay(GLOB.hit_appends) //forcesay checks stat already - radio_interrupt_cooldown = world.time + (RADIO_INTERRUPT_DEFAULT * 0.8) //getting beat on can briefly prevent radio use - - if((I.damtype == BRUTE || I.damtype == PAIN) && prob(25 + (effective_force * 2))) - if(!stat) - if(headcheck(hit_zone)) - //Harder to score a stun but if you do it lasts a bit longer - if(prob(effective_force)) - apply_effect(20, PARALYZE, blocked) - if(lying) - visible_message("[src] [species.knockout_message]") - else - //Easier to score a stun but lasts less time - if(prob(effective_force + 5)) - apply_effect(3, WEAKEN, blocked) - if(lying) - visible_message("[src] has been knocked down!") - - //Apply blood - attack_bloody(I, user, effective_force, hit_zone) - - animate_receive_damage(src) - - return 1 - -/mob/living/carbon/human/proc/attack_bloody(obj/item/W, mob/living/attacker, var/effective_force, var/hit_zone) - if(W.damtype != BRUTE) - return - - //make non-sharp low-force weapons less likely to be bloodied - if(W.sharp || prob(effective_force*4)) - if(!(W.atom_flags & ATOM_FLAG_NO_BLOOD)) - W.add_blood(src) - else - return //if the weapon itself didn't get bloodied than it makes little sense for the target to be bloodied either - - //getting the weapon bloodied is easier than getting the target covered in blood, so run prob() again - if(prob(33 + W.sharp*10)) - var/turf/location = loc - if(istype(location, /turf/simulated)) - location.add_blood(src) - if(ishuman(attacker)) - var/mob/living/carbon/human/H = attacker - if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood - H.bloody_body(src) - H.bloody_hands(src) - - switch(hit_zone) - if(BP_HEAD) - if(wear_mask) - wear_mask.add_blood(src) - update_inv_wear_mask(0) - if(head) - head.add_blood(src) - update_inv_head(0) - if(glasses && prob(33)) - glasses.add_blood(src) - update_inv_glasses(0) - if(BP_CHEST) - bloody_body(src) - -/mob/living/carbon/human/proc/projectile_hit_bloody(obj/item/projectile/P, var/effective_force, var/hit_zone, var/obj/item/organ/external/organ) - if(P.damage_type != BRUTE || P.nodamage) - return - if(!(P.sharp || prob(effective_force*4))) - return - if(prob(effective_force)) - var/turf/location = loc - if(istype(location, /turf/simulated)) - location.add_blood(src) - if(hit_zone) - organ = get_organ(hit_zone) - var/list/bloody = get_covering_equipped_items(organ.body_part) - for(var/obj/item/clothing/C in bloody) - C.add_blood(src) - C.update_clothing_icon() - -/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/effective_force, var/dislocate_mult, var/blocked) - if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 100) - return 0 - if(W.damtype != BRUTE) - return 0 - - //want the dislocation chance to be such that the limb is expected to dislocate after dealing a fraction of the damage needed to break the limb - var/dislocate_chance = effective_force/(dislocate_mult * organ.min_broken_damage * config.organ_health_multiplier)*100 - if(prob(dislocate_chance * blocked_mult(blocked))) - visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!") - organ.dislocate(1) - return 1 - return 0 - -/mob/living/carbon/human/emag_act(var/remaining_charges, mob/user, var/emag_source) - var/obj/item/organ/external/affecting = get_organ(user.zone_sel.selecting) - if(!affecting || !affecting.is_robotic()) - to_chat(user, "That limb isn't robotic.") - return -1 - if(affecting.status & ORGAN_SABOTAGED) - to_chat(user, "[src]'s [affecting.name] is already sabotaged!") - return -1 - to_chat(user, "You sneakily slide [emag_source] into the dataport on [src]'s [affecting.name] and short out the safeties.") - affecting.status |= ORGAN_SABOTAGED - return 1 - -//this proc handles being hit by a thrown atom -/mob/living/carbon/human/hitby(atom/movable/AM, var/datum/thrownthing/TT) - - if(istype(AM,/obj/)) - var/obj/O = AM - - if(in_throw_mode && !get_active_hand() && TT.speed <= THROWFORCE_SPEED_DIVISOR) //empty active hand and we're in throw mode - if(!incapacitated()) - if(isturf(O.loc)) - put_in_active_hand(O) - visible_message("[src] catches [O]!") - throw_mode_off() - process_momentum(AM, TT) - return - - var/dtype = O.damtype - var/throw_damage = O.throwforce*(TT.speed/THROWFORCE_SPEED_DIVISOR) - - var/zone = BP_CHEST - if (TT.target_zone) - zone = check_zone(TT.target_zone) - else - zone = ran_zone() //Hits a random part of the body, -was already geared towards the chest - - //check if we hit - var/miss_chance = max(15*(TT.dist_travelled-2),0) - zone = get_zone_with_miss_chance(zone, src, miss_chance, ranged_attack=1) - - if(zone && TT.thrower && TT.thrower != src) - var/shield_check = check_shields(throw_damage, O, TT.thrower, zone, "[O]") - if(shield_check == PROJECTILE_FORCE_MISS) - zone = null - else if(shield_check) - return - - var/obj/item/organ/external/affecting = (zone && get_organ(zone)) - if(!affecting) - visible_message(SPAN_NOTICE("\The [O] misses \the [src] narrowly!")) - return - - var/datum/wound/created_wound - visible_message(SPAN_DANGER("\The [src] has been hit in \the [affecting.name] by \the [O].")) - created_wound = apply_damage(throw_damage, dtype, zone, O.damage_flags(), O, O.armor_penetration) - - if(TT.thrower) - var/client/assailant = TT.thrower.client - if(assailant) - admin_attack_log(TT.thrower, src, "Threw \an [O] at their victim.", "Had \an [O] thrown at them", "threw \an [O] at") - - //thrown weapon embedded object code. - if(dtype == BRUTE && istype(O,/obj/item)) - var/obj/item/I = O - if (!is_robot_module(I)) - var/sharp = I.can_embed() - var/damage = throw_damage //the effective damage used for embedding purposes, no actual damage is dealt here - damage *= (1 - get_blocked_ratio(zone, BRUTE, O.damage_flags(), O.armor_penetration, I.force)) - - //blunt objects should really not be embedding in things unless a huge amount of force is involved - var/embed_chance = sharp? damage/I.w_class : damage/(I.w_class*3) - var/embed_threshold = sharp? 5*I.w_class : 15*I.w_class - - //Sharp objects will always embed if they do enough damage. - //Thrown sharp objects have some momentum already and have a small chance to embed even if the damage is below the threshold - if((sharp && prob(damage/(10*I.w_class)*100)) || (damage > embed_threshold && prob(embed_chance))) - affecting.embed(I, supplied_wound = created_wound) - I.has_embedded() - - process_momentum(AM, TT) - - else - ..() - -/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null, var/datum/wound/supplied_wound) - if(!def_zone) ..() - - var/obj/item/organ/external/affecting = get_organ(def_zone) - if(affecting) - affecting.embed(O, supplied_wound = supplied_wound) - -/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2) - var/obj/item/clothing/gloves/gloves = get_equipped_item(slot_gloves) - if(istype(gloves)) - gloves.add_blood(source) - gloves.transfer_blood = amount - gloves.bloody_hands_mob = source - else - add_blood(source) - bloody_hands = amount - bloody_hands_mob = source - update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves - -/mob/living/carbon/human/proc/bloody_body(var/mob/living/source) - if(wear_suit) - wear_suit.add_blood(source) - update_inv_wear_suit(0) - if(w_uniform) - w_uniform.add_blood(source) - update_inv_w_uniform(0) - -/mob/living/carbon/human/proc/handle_suit_punctures(var/damtype, var/damage, var/def_zone) - - // Tox and oxy don't matter to suits. - if(damtype != BURN && damtype != BRUTE) return - - // The rig might soak this hit, if we're wearing one. - if(back && istype(back,/obj/item/rig)) - var/obj/item/rig/rig = back - rig.take_hit(damage) - - // We may also be taking a suit breach. - if(!wear_suit) return - if(!istype(wear_suit,/obj/item/clothing/suit/space)) return - var/obj/item/clothing/suit/space/SS = wear_suit - SS.create_breaches(damtype, damage) - -/mob/living/carbon/human/reagent_permeability() - var/perm = 0 - - var/list/perm_by_part = list( - "head" = THERMAL_PROTECTION_HEAD, - "upper_torso" = THERMAL_PROTECTION_UPPER_TORSO, - "lower_torso" = THERMAL_PROTECTION_LOWER_TORSO, - "legs" = THERMAL_PROTECTION_LEG_LEFT + THERMAL_PROTECTION_LEG_RIGHT, - "feet" = THERMAL_PROTECTION_FOOT_LEFT + THERMAL_PROTECTION_FOOT_RIGHT, - "arms" = THERMAL_PROTECTION_ARM_LEFT + THERMAL_PROTECTION_ARM_RIGHT, - "hands" = THERMAL_PROTECTION_HAND_LEFT + THERMAL_PROTECTION_HAND_RIGHT - ) - - for(var/obj/item/clothing/C in src.get_equipped_items()) - if(C.permeability_coefficient == 1 || !C.body_parts_covered) - continue - if(C.body_parts_covered & HEAD) - perm_by_part["head"] *= C.permeability_coefficient - if(C.body_parts_covered & UPPER_TORSO) - perm_by_part["upper_torso"] *= C.permeability_coefficient - if(C.body_parts_covered & LOWER_TORSO) - perm_by_part["lower_torso"] *= C.permeability_coefficient - if(C.body_parts_covered & LEGS) - perm_by_part["legs"] *= C.permeability_coefficient - if(C.body_parts_covered & FEET) - perm_by_part["feet"] *= C.permeability_coefficient - if(C.body_parts_covered & ARMS) - perm_by_part["arms"] *= C.permeability_coefficient - if(C.body_parts_covered & HANDS) - perm_by_part["hands"] *= C.permeability_coefficient - - for(var/part in perm_by_part) - perm += perm_by_part[part] - - return perm - -/mob/living/carbon/human/lava_act(datum/gas_mixture/air, temperature, pressure) - var/was_burned = FireBurn(0.4 * vsc.fire_firelevel_multiplier, temperature, pressure) - if (was_burned) - fire_act(air, temperature) - return FALSE diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm deleted file mode 100644 index 12cf0268793c..000000000000 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ /dev/null @@ -1,100 +0,0 @@ -/mob/living/carbon/human - - var/h_style = "Bald" - var/f_style = "Shaved" - - var/hair_colour - var/facial_hair_colour - var/skin_colour - var/eye_colour - - var/skin_tone = 0 //Skin tone - var/skin_base = "" //Skin base - - var/size_multiplier = 1 //multiplier for the mob's icon size - var/damage_multiplier = 1 //multiplies melee combat damage - var/icon_update = 1 //whether icon updating shall take place - - var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup - - var/age = 30 //Player's age (pure fluff) - var/b_type = "A+" //Player's bloodtype - - var/list/worn_underwear = list() - - var/datum/backpack_setup/backpack_setup - - var/list/cultural_info = list() - - //Equipment slots - var/obj/item/wear_suit = null - var/obj/item/w_uniform = null - var/obj/item/shoes = null - var/obj/item/belt = null - var/obj/item/gloves = null - var/obj/item/glasses = null - var/obj/item/head = null - var/obj/item/l_ear = null - var/obj/item/r_ear = null - var/obj/item/wear_id = null - var/obj/item/r_store = null - var/obj/item/l_store = null - var/obj/item/s_store = null - - var/icon/stand_icon = null - var/icon/lying_icon = null - - var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life() - - var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none. - var/list/bad_external_organs = list()// organs we check until they are good. - - var/xylophone = 0 //For the spoooooooky xylophone cooldown - - var/mob/remoteview_target = null - var/hand_blood_color - - var/list/flavor_texts = list() - var/pulling_punches // Are you trying not to hurt your opponent? - var/full_prosthetic // We are a robutt. - var/robolimb_count = 0 // Number of robot limbs. - var/last_attack = 0 // The world_time where an unarmed attack was done - - mob_bump_flag = HUMAN - mob_push_flags = ~HEAVY - mob_swap_flags = ~HEAVY - - var/flash_protection = 0 // Total level of flash protection - var/equipment_tint_total = 0 // Total level of visualy impairing items - var/equipment_darkness_modifier // Darkvision modifier from equipped items - var/equipment_vision_flags // Extra vision flags from equipped items - var/equipment_see_invis // Max see invibility level granted by equipped items - var/equipment_prescription // Eye prescription granted by equipped items - var/equipment_light_protection - var/list/equipment_overlays = list() // Extra overlays from equipped items - - var/public_record = "" - var/med_record = "" - var/sec_record = "" - var/gen_record = "" - var/exploit_record = "" - - var/datum/mil_branch/char_branch = null - var/datum/mil_rank/char_rank = null - - var/stance_damage = 0 //Whether this mob's ability to stand has been affected - - var/decl/natural_attack/default_attack //default unarmed attack - - var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently. - var/shock_stage - - //vars for fountain of youth examine lines - var/became_older - var/became_younger - - var/list/descriptors - - var/last_smelt = 0 - - ai = /datum/ai/human \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_grabs.dm b/code/modules/mob/living/carbon/human/human_grabs.dm deleted file mode 100644 index 29de5e8eb5eb..000000000000 --- a/code/modules/mob/living/carbon/human/human_grabs.dm +++ /dev/null @@ -1,25 +0,0 @@ -/mob/living/carbon/human/add_grab(var/obj/item/grab/grab) - . = put_in_active_hand(grab) - -/mob/living/carbon/human/can_be_grabbed(var/mob/grabber, var/target_zone) - . = ..() - if(.) - var/obj/item/organ/organ = target_zone && organs_by_name[target_zone] - if(!istype(organ)) - to_chat(grabber, SPAN_WARNING("\The [src] is missing that body part!")) - return FALSE - if(grabber == src) - var/list/bad_parts = hand ? list(BP_L_ARM, BP_L_HAND) : list(BP_R_ARM, BP_R_HAND) - if(organ && (organ.organ_tag in bad_parts)) - to_chat(src, SPAN_WARNING("You can't grab your own [organ.name] with itself!")) - return FALSE - if(pull_damage()) - to_chat(grabber, SPAN_DANGER("Pulling \the [src] in their current condition would probably be a bad idea.")) - var/obj/item/clothing/C = get_covering_equipped_item_by_zone(target_zone) - if(istype(C)) - C.leave_evidence(grabber) - -/mob/living/carbon/human/make_grab(var/atom/movable/target, var/grab_tag = /decl/grab/simple) - . = ..() - if(.) - remove_cloaking_source(species) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm deleted file mode 100644 index 75919767ef99..000000000000 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ /dev/null @@ -1,338 +0,0 @@ -#define HUMAN_EATING_NO_ISSUE 0 -#define HUMAN_EATING_NBP_MOUTH 1 -#define HUMAN_EATING_BLOCKED_MOUTH 2 - -#define add_clothing_protection(A) \ - var/obj/item/clothing/C = A; \ - flash_protection += C.flash_protection; \ - equipment_tint_total += C.tint; - -/mob/living/carbon/human/can_eat(var/food, var/feedback = 1) - var/list/status = can_eat_status() - if(status[1] == HUMAN_EATING_NO_ISSUE) - return 1 - if(feedback) - if(status[1] == HUMAN_EATING_NBP_MOUTH) - to_chat(src, "Where do you intend to put \the [food]? You don't have a mouth!") - else if(status[1] == HUMAN_EATING_BLOCKED_MOUTH) - to_chat(src, "\The [status[2]] is in the way!") - return 0 - -/mob/living/carbon/human/can_force_feed(var/feeder, var/food, var/feedback = 1) - var/list/status = can_eat_status() - if(status[1] == HUMAN_EATING_NO_ISSUE) - return 1 - if(feedback) - if(status[1] == HUMAN_EATING_NBP_MOUTH) - to_chat(feeder, "Where do you intend to put \the [food]? \The [src] doesn't have a mouth!") - else if(status[1] == HUMAN_EATING_BLOCKED_MOUTH) - to_chat(feeder, "\The [status[2]] is in the way!") - return 0 - -/mob/living/carbon/human/proc/can_eat_status() - if(!check_has_mouth()) - return list(HUMAN_EATING_NBP_MOUTH) - var/obj/item/blocked = check_mouth_coverage() - if(blocked) - return list(HUMAN_EATING_BLOCKED_MOUTH, blocked) - return list(HUMAN_EATING_NO_ISSUE) - -#undef HUMAN_EATING_NO_ISSUE -#undef HUMAN_EATING_NBP_MOUTH -#undef HUMAN_EATING_BLOCKED_MOUTH - -/mob/living/carbon/human/proc/update_equipment_vision() - flash_protection = 0 - equipment_tint_total = 0 - equipment_see_invis = 0 - equipment_vision_flags = 0 - equipment_prescription = 0 - equipment_light_protection = 0 - equipment_darkness_modifier = 0 - equipment_overlays.Cut() - - if (!client || client.eye == src || client.eye == src.loc) // !client is so the unit tests function - if(istype(src.head, /obj/item/clothing/head)) - add_clothing_protection(head) - if(istype(src.glasses, /obj/item/clothing/glasses)) - process_glasses(glasses) - if(istype(src.wear_mask, /obj/item/clothing/mask)) - add_clothing_protection(wear_mask) - if(istype(back,/obj/item/rig)) - process_rig(back) - -/mob/living/carbon/human/proc/process_glasses(var/obj/item/clothing/glasses/G) - if(G) - // prescription applies regardless of if the glasses are active - equipment_prescription += G.prescription - if(G.active) - equipment_darkness_modifier += G.darkness_view - equipment_vision_flags |= G.vision_flags - equipment_light_protection += G.light_protection - if(G.overlay) - equipment_overlays |= G.overlay - if(G.see_invisible >= 0) - if(equipment_see_invis) - equipment_see_invis = min(equipment_see_invis, G.see_invisible) - else - equipment_see_invis = G.see_invisible - - add_clothing_protection(G) - G.process_hud(src) - -/mob/living/carbon/human/proc/process_rig(var/obj/item/rig/O) - if(O.visor && O.visor.active && O.visor.vision && O.visor.vision.glasses && (!O.helmet || (head && O.helmet == head))) - process_glasses(O.visor.vision.glasses) - -/mob/living/carbon/human/get_gender() - return gender - -/mob/living/carbon/human/fully_replace_character_name(var/new_name, var/in_depth = TRUE) - var/old_name = real_name - . = ..() - if(!. || !in_depth) - return - - var/datum/computer_file/report/crew_record/R = get_crewmember_record(old_name) - if(R) - R.set_name(new_name) - - //update our pda and id if we have them on our person - var/list/searching = GetAllContents(searchDepth = 3) - var/search_id = 1 - var/search_pda = 1 - - for(var/A in searching) - if(search_id && istype(A,/obj/item/card/id)) - var/obj/item/card/id/ID = A - if(ID.registered_name == old_name) - ID.registered_name = new_name - search_id = 0 - else if(search_pda && istype(A,/obj/item/modular_computer/pda)) - var/obj/item/modular_computer/pda/PDA = A - if(findtext(PDA.name, old_name)) - PDA.SetName(replacetext(PDA.name, old_name, new_name)) - search_pda = 0 - - if(wearing_rig && wearing_rig.update_visible_name) - wearing_rig.visible_name = real_name - - -//Get species or synthetic temp if the mob is a FBP. Used when a synthetic type human mob is exposed to a temp check. -//Essentially, used when a synthetic human mob should act diffferently than a normal type mob. -/mob/living/carbon/human/proc/getSpeciesOrSynthTemp(var/temptype) - switch(temptype) - if(COLD_LEVEL_1) - return isSynthetic()? SYNTH_COLD_LEVEL_1 : species.cold_level_1 - if(COLD_LEVEL_2) - return isSynthetic()? SYNTH_COLD_LEVEL_2 : species.cold_level_2 - if(COLD_LEVEL_3) - return isSynthetic()? SYNTH_COLD_LEVEL_3 : species.cold_level_3 - if(HEAT_LEVEL_1) - return isSynthetic()? SYNTH_HEAT_LEVEL_1 : species.heat_level_1 - if(HEAT_LEVEL_2) - return isSynthetic()? SYNTH_HEAT_LEVEL_2 : species.heat_level_2 - if(HEAT_LEVEL_3) - return isSynthetic()? SYNTH_HEAT_LEVEL_3 : species.heat_level_3 - -/mob/living/carbon/human/proc/getCryogenicFactor(var/bodytemperature) - if(isSynthetic()) - return 0 - if(!species) - return 0 - - if(bodytemperature > species.cold_level_1) - return 0 - else if(bodytemperature > species.cold_level_2) - . = 5 * (1 - (bodytemperature - species.cold_level_2) / (species.cold_level_1 - species.cold_level_2)) - . = max(2, .) - else if(bodytemperature > species.cold_level_3) - . = 20 * (1 - (bodytemperature - species.cold_level_3) / (species.cold_level_2 - species.cold_level_3)) - . = max(5, .) - else - . = 80 * (1 - bodytemperature / species.cold_level_3) - . = max(20, .) - return round(.) - -/mob/living/carbon/human - var/next_sonar_ping = 0 - -/mob/living/carbon/human/proc/sonar_ping() - set name = "Listen In" - set desc = "Allows you to listen in to movement and noises around you." - set category = "IC" - - if(incapacitated()) - to_chat(src, "You need to recover before you can use this ability.") - return - if(world.time < next_sonar_ping) - to_chat(src, "You need another moment to focus.") - return - if(is_deaf() || is_below_sound_pressure(get_turf(src))) - to_chat(src, "You are for all intents and purposes currently deaf!") - return - next_sonar_ping += 10 SECONDS - var/heard_something = FALSE - to_chat(src, "You take a moment to listen in to your environment...") - for(var/mob/living/L in range(get_effective_view(client), src)) - var/turf/T = get_turf(L) - if(!T || L == src || L.stat == DEAD || is_below_sound_pressure(T)) - continue - heard_something = TRUE - var/image/ping_image = image(icon = 'icons/effects/effects.dmi', icon_state = "sonar_ping", loc = src) - ping_image.plane = EFFECTS_ABOVE_LIGHTING_PLANE - ping_image.layer = BEAM_PROJECTILE_LAYER - ping_image.pixel_x = (T.x - src.x) * WORLD_ICON_SIZE - ping_image.pixel_y = (T.y - src.y) * WORLD_ICON_SIZE - show_image(src, ping_image) - spawn(8) - qdel(ping_image) - var/feedback = list("There are noises of movement ") - var/direction = get_dir(src, L) - if(direction) - feedback += "towards the [dir2text(direction)], " - switch(get_dist(src, L) / get_effective_view(client)) - if(0 to 0.2) - feedback += "very close by." - if(0.2 to 0.4) - feedback += "close by." - if(0.4 to 0.6) - feedback += "some distance away." - if(0.6 to 0.8) - feedback += "further away." - else - feedback += "far away." - else // No need to check distance if they're standing right on-top of us - feedback += "right on top of you." - feedback += "" - to_chat(src, jointext(feedback,null)) - if(!heard_something) - to_chat(src, "You hear no movement but your own.") - -/mob/living/carbon/human/reset_layer() - if(hiding) - layer = HIDING_MOB_LAYER - else if(lying) - layer = LYING_HUMAN_LAYER - else - ..() - -/mob/living/carbon/human/proc/has_headset_in_ears() - return istype(get_equipped_item(slot_l_ear), /obj/item/radio/headset) || istype(get_equipped_item(slot_r_ear), /obj/item/radio/headset) - -/mob/living/carbon/human/welding_eyecheck() - var/obj/item/organ/internal/eyes/E = src.internal_organs_by_name[species.vision_organ] - if(!E) - return - var/safety = eyecheck() - switch(safety) - if(FLASH_PROTECTION_MODERATE) - to_chat(src, "Your eyes sting a little.") - E.damage += rand(1, 2) - if(E.damage > 12) - eye_blurry += rand(3,6) - if(FLASH_PROTECTION_MINOR) - to_chat(src, "Your eyes stings!") - E.damage += rand(1, 4) - if(E.damage > 10) - eye_blurry += rand(3,6) - E.damage += rand(1, 4) - if(FLASH_PROTECTION_NONE) - to_chat(src, "Your eyes burn!") - E.damage += rand(2, 4) - if(E.damage > 10) - E.damage += rand(4,10) - if(FLASH_PROTECTION_REDUCED) - to_chat(src, "Your equipment intensifies the welder's glow. Your eyes itch and burn severely.") - eye_blurry += rand(12,20) - E.damage += rand(12, 16) - if(safety 10) - to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!") - if (E.damage >= E.min_bruised_damage) - to_chat(src, "You go blind!") - eye_blind = 5 - eye_blurry = 5 - disabilities |= NEARSIGHTED - spawn(100) - disabilities &= ~NEARSIGHTED - -/mob/living/carbon/human - var/list/cloaking_sources - -// Returns true if, and only if, the human has gone from uncloaked to cloaked -/mob/living/carbon/human/proc/add_cloaking_source(var/datum/cloaking_source) - var/has_uncloaked = clean_cloaking_sources() - LAZYDISTINCTADD(cloaking_sources, weakref(cloaking_source)) - - // We don't present the cloaking message if the human was already cloaked just before cleanup. - if(!has_uncloaked && LAZYLEN(cloaking_sources) == 1) - update_icons() - src.visible_message("\The [src] seems to disappear before your eyes!", "You feel completely invisible.") - return TRUE - return FALSE - -#define CLOAK_APPEAR_OTHER "\The [src] appears from thin air!" -#define CLOAK_APPEAR_SELF "You have re-appeared." - -// Returns true if, and only if, the human has gone from cloaked to uncloaked -/mob/living/carbon/human/proc/remove_cloaking_source(var/datum/cloaking_source) - var/was_cloaked = LAZYLEN(cloaking_sources) - clean_cloaking_sources() - LAZYREMOVE(cloaking_sources, weakref(cloaking_source)) - - if(was_cloaked && !LAZYLEN(cloaking_sources)) - update_icons() - visible_message(CLOAK_APPEAR_OTHER, CLOAK_APPEAR_SELF) - return TRUE - return FALSE - -// Returns true if the human is cloaked, otherwise false (technically returns the number of cloaking sources) -/mob/proc/is_cloaked() - return FALSE - -/mob/living/carbon/human/is_cloaked() - if(clean_cloaking_sources()) - update_icons() - visible_message(CLOAK_APPEAR_OTHER, CLOAK_APPEAR_SELF) - return LAZYLEN(cloaking_sources) - -#undef CLOAK_APPEAR_OTHER -#undef CLOAK_APPEAR_SELF - -// Returns true if the human is cloaked by the given source -/mob/living/carbon/human/proc/is_cloaked_by(var/cloaking_source) - return LAZYISIN(cloaking_sources, weakref(cloaking_source)) - -// Returns true if this operation caused the mob to go from cloaked to uncloaked -/mob/living/carbon/human/proc/clean_cloaking_sources() - if(!cloaking_sources) - return FALSE - - var/list/rogue_entries = list() - for(var/entry in cloaking_sources) - var/weakref/W = entry - if(!W.resolve()) - cloaking_sources -= W - rogue_entries += W - - if(rogue_entries.len) // These entries did not cleanup after themselves before being destroyed - var/rogue_entries_as_string = jointext(map(rogue_entries, /proc/log_info_line), ", ") - crash_with("[log_info_line(src)] - Following cloaking entries were removed during cleanup: [rogue_entries_as_string]") - - UNSETEMPTY(cloaking_sources) - return !cloaking_sources // If cloaking_sources wasn't initially null but is now, we've uncloaked - -/mob/living/carbon/human/set_sdisability(sdisability) - if(isSynthetic()) - return // Can't cure disabilites, so don't give them. - ..() - -/mob/living/carbon/human/proc/has_meson_effect() - . = FALSE - for(var/obj/screen/equipment_screen in equipment_overlays) // check through our overlays to see if we have any source of the meson overlay - if (equipment_screen.icon_state == "meson_hud") - return TRUE - -/mob/living/carbon/human/proc/is_in_pocket(var/obj/item/I) - return I in list(l_store, r_store) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_maneuvers.dm b/code/modules/mob/living/carbon/human/human_maneuvers.dm deleted file mode 100644 index f106bf43d9cd..000000000000 --- a/code/modules/mob/living/carbon/human/human_maneuvers.dm +++ /dev/null @@ -1,19 +0,0 @@ -/mob/living/carbon/human/get_acrobatics_multiplier(var/decl/maneuver/attempting_maneuver) - . = 0.5 + ((get_skill_value(SKILL_HAULING) - SKILL_MIN)/(SKILL_MAX - SKILL_MIN)) - if(skill_check(SKILL_HAULING, SKILL_BASIC)) - . = max(..(), .) - -/mob/living/carbon/human/get_jump_distance() - return species.standing_jump_range - -/mob/living/carbon/human/can_do_maneuver(var/decl/maneuver/maneuver, var/silent = FALSE) - . = ..() - if(.) - if(nutrition <= 20) - if(!silent) - to_chat(src, SPAN_WARNING("You are too hungry to jump around.")) - return FALSE - if(hydration <= 20) - if(!silent) - to_chat(src, SPAN_WARNING("You are too thirsty to jump around.")) - return FALSE diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm deleted file mode 100644 index 6e93d41fb663..000000000000 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ /dev/null @@ -1,164 +0,0 @@ -/mob/living/carbon/human - move_intents = list(/decl/move_intent/walk) - -/mob/living/carbon/human/movement_delay() - var/tally = ..() - - var/obj/item/organ/external/H = get_organ(BP_GROIN) // gets species slowdown, which can be reset by robotize() - if(istype(H)) - tally += H.slowdown - - tally += species.handle_movement_delay_special(src) - - if(!has_gravity()) - if(skill_check(SKILL_EVA, SKILL_PROF)) - tally -= 2 - tally -= 1 - - if(CE_SPEEDBOOST in chem_effects) - tally -= chem_effects[CE_SPEEDBOOST] - - if(CE_SLOWDOWN in chem_effects) - tally += chem_effects[CE_SLOWDOWN] - - var/health_deficiency = (maxHealth - health) - if(health_deficiency >= 40) tally += (health_deficiency / 25) - - if(can_feel_pain()) - if(get_shock() >= 10) tally += (get_shock() / 10) //pain shouldn't slow you down if you can't even feel it - - if(istype(buckled, /obj/structure/bed/chair/wheelchair)) - for(var/organ_name in list(BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM)) - var/obj/item/organ/external/E = get_organ(organ_name) - tally += E ? E.movement_delay(4) : 4 - else - var/total_item_slowdown = -1 - for(var/slot = slot_first to slot_last) - var/obj/item/I = get_equipped_item(slot) - if(istype(I)) - var/item_slowdown = 0 - item_slowdown += I.slowdown_general - item_slowdown += I.slowdown_per_slot[slot] - item_slowdown += I.slowdown_accessory - total_item_slowdown += max(item_slowdown, 0) - tally += total_item_slowdown - - for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) - var/obj/item/organ/external/E = get_organ(organ_name) - tally += E ? E.movement_delay(4) : 4 - - if(shock_stage >= 10 || get_stamina() <= 0) - tally += 3 - - if(is_asystole()) tally += 10 //heart attacks are kinda distracting - - if(aiming && aiming.aiming_at) tally += 5 // Iron sights make you slower, it's a well-known fact. - - if(MUTATION_FAT in src.mutations) - tally += 1.5 - if (bodytemperature < species.cold_discomfort_level) - tally += (species.cold_discomfort_level - bodytemperature) / 10 * 1.75 - - tally += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow - - if(mRun in mutations) - tally = 0 - - return (tally+config.human_delay) - -/mob/living/carbon/human/size_strength_mod() - . = ..() - . += species.strength - -/mob/living/carbon/human/Process_Spacemove(var/allow_movement) - var/obj/item/tank/jetpack/thrust = get_jetpack() - - if(thrust && thrust.on && (allow_movement || thrust.stabilization_on) && thrust.allow_thrust(0.01, src)) - return 1 - - . = ..() - - -/mob/living/carbon/human/space_do_move(var/allow_move, var/direction) - if(allow_move == 1) - var/obj/item/tank/jetpack/thrust = get_jetpack() - if(thrust && thrust.on && prob(skill_fail_chance(SKILL_EVA, 10, SKILL_ADEPT))) - to_chat(src, "You fumble with [thrust] controls!") - if(prob(50)) - thrust.toggle() - if(prob(50)) - thrust.stabilization_on = 0 - SetMoveCooldown(15) //2 seconds of random rando panic drifting - step(src, pick(GLOB.alldirs)) - return 0 - - . = ..() - -/mob/living/carbon/human/proc/get_jetpack() - if(back) - if(istype(back,/obj/item/tank/jetpack)) - return back - else if(istype(back,/obj/item/rig)) - var/obj/item/rig/rig = back - for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules) - return module.jets - -/mob/living/carbon/human/slip_chance(var/prob_slip = 5) - if(!..()) - return 0 - - //Check hands and mod slip - if(!l_hand) prob_slip -= 2 - else if(l_hand.w_class <= ITEM_SIZE_SMALL) prob_slip -= 1 - if (!r_hand) prob_slip -= 2 - else if(r_hand.w_class <= ITEM_SIZE_SMALL) prob_slip -= 1 - - return prob_slip - -/mob/living/carbon/human/Check_Shoegrip() - if(species.check_no_slip(src)) - return 1 - if(shoes && (shoes.item_flags & ITEM_FLAG_NOSLIP) && istype(shoes, /obj/item/clothing/shoes/magboots)) //magboots + dense_object = no floating - return 1 - return 0 - -/mob/living/carbon/human/Move() - . = ..() - if(.) //We moved - handle_exertion() - handle_leg_damage() - - if(client) - var/turf/B = GetAbove(src) - up_hint.icon_state = "uphint[(B ? B.is_open() : 0)]" - -/mob/living/carbon/human/proc/handle_exertion() - if(isSynthetic()) - return - var/lac_chance = 10 * encumbrance() - if(lac_chance && prob(skill_fail_chance(SKILL_HAULING, lac_chance))) - make_reagent(1, /decl/material/liquid/lactate) - adjust_hydration(-DEFAULT_THIRST_FACTOR) - switch(rand(1,20)) - if(1) - visible_message("\The [src] is sweating heavily!", "You are sweating heavily!") - if(2) - visible_message("\The [src] looks out of breath!", "You are out of breath!") - -/mob/living/carbon/human/proc/handle_leg_damage() - if(!can_feel_pain()) - return - var/crutches = 0 - for(var/obj/item/cane/C in list(l_hand, r_hand)) - if(istype(C)) - crutches++ - for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) - var/obj/item/organ/external/E = get_organ(organ_name) - if(E && (E.is_dislocated() || E.is_broken())) - if(crutches) - crutches-- - else - E.add_pain(10) - -/mob/living/carbon/human/can_sprint() - return (stamina > 0) diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm deleted file mode 100644 index 6cc9fb3f7c78..000000000000 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ /dev/null @@ -1,266 +0,0 @@ -/mob/living/carbon/human/proc/update_eyes() - var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[species.vision_organ ? species.vision_organ : BP_EYES] - if(eyes) - eyes.update_colour() - regenerate_icons() - -/mob/living/carbon/human/proc/get_bodypart_name(var/zone) - var/obj/item/organ/external/E = get_organ(zone) - if(E) . = E.name - -/mob/living/carbon/human/proc/recheck_bad_external_organs() - var/damage_this_tick = getToxLoss() - for(var/obj/item/organ/external/O in organs) - damage_this_tick += O.burn_dam + O.brute_dam - - if(damage_this_tick > last_dam) - . = TRUE - last_dam = damage_this_tick - -// Takes care of organ related updates, such as broken and missing limbs -/mob/living/carbon/human/proc/handle_organs() - - var/force_process = recheck_bad_external_organs() - - if(force_process) - bad_external_organs.Cut() - for(var/obj/item/organ/external/Ex in organs) - bad_external_organs |= Ex - - //processing internal organs is pretty cheap, do that first. - for(var/obj/item/organ/I in internal_organs) - I.Process() - - handle_stance() - handle_grasp() - - if(!force_process && !bad_external_organs.len) - return - - for(var/obj/item/organ/external/E in bad_external_organs) - if(!E) - continue - if(!E.need_process()) - bad_external_organs -= E - continue - else - E.Process() - - if (!lying && !buckled && world.time - l_move_time < 15) - //Moving around with fractured ribs won't do you any good - if (prob(10) && !stat && can_feel_pain() && chem_effects[CE_PAINKILLER] < 50 && E.is_broken() && E.internal_organs.len) - custom_pain("Pain jolts through your broken [E.encased ? E.encased : E.name], staggering you!", 50, affecting = E) - unequip_item(loc) - Stun(2) - - //Moving makes open wounds get infected much faster - for(var/datum/wound/W in E.wounds) - if (W.infection_check()) - W.germ_level += 1 - -/mob/living/carbon/human/proc/Check_Proppable_Object() - for(var/turf/simulated/T in RANGE_TURFS(src, 1)) //we only care for non-space turfs - if(T.density) //walls work - return 1 - - for(var/obj/O in orange(1, src)) - if(O && O.density && O.anchored) - return 1 - - return 0 - -/mob/living/carbon/human/proc/handle_stance() - set waitfor = FALSE // Can sleep in emotes. - // Don't need to process any of this if they aren't standing anyways - // unless their stance is damaged, and we want to check if they should stay down - if (!stance_damage && (lying || resting) && (life_tick % 4) != 0) - return - - stance_damage = 0 - - // Buckled to a bed/chair. Stance damage is forced to 0 since they're sitting on something solid - if (istype(buckled, /obj/structure/bed)) - return - - // Can't fall if nothing pulls you down - if(!has_gravity()) - return - - var/limb_pain - for(var/limb_tag in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) - var/obj/item/organ/external/E = organs_by_name[limb_tag] - if(!E || !E.is_usable()) - stance_damage += 2 // let it fail even if just foot&leg - else if (E.is_malfunctioning()) - //malfunctioning only happens intermittently so treat it as a missing limb when it procs - stance_damage += 2 - if(prob(10)) - visible_message("\The [src]'s [E.name] [pick("twitches", "shudders")] and sparks!") - var/datum/effect/effect/system/spark_spread/spark_system = new () - spark_system.set_up(5, 0, src) - spark_system.attach(src) - spark_system.start() - spawn(10) - qdel(spark_system) - else if (E.is_broken()) - stance_damage += 1 - else if (E.is_dislocated()) - stance_damage += 0.5 - - if(E) limb_pain = E.can_feel_pain() - - // Canes and crutches help you stand (if the latter is ever added) - // One cane mitigates a broken leg+foot, or a missing foot. - // Two canes are needed for a lost leg. If you are missing both legs, canes aren't gonna help you. - if (l_hand && istype(l_hand, /obj/item/cane)) - stance_damage -= 2 - if (r_hand && istype(r_hand, /obj/item/cane)) - stance_damage -= 2 - - if(MOVING_DELIBERATELY(src)) //you don't suffer as much if you aren't trying to run - var/working_pair = 2 - if(!organs_by_name[BP_L_LEG] || !organs_by_name[BP_L_FOOT]) //are we down a limb? - working_pair -= 1 - else if((!organs_by_name[BP_L_LEG].is_usable()) || (!organs_by_name[BP_L_FOOT].is_usable())) //if not, is it usable? - working_pair -= 1 - if(!organs_by_name[BP_R_LEG] || !organs_by_name[BP_R_FOOT]) - working_pair -= 1 - else if((!organs_by_name[BP_R_LEG].is_usable()) || (!organs_by_name[BP_R_FOOT].is_usable())) - working_pair -= 1 - if(working_pair >= 1) - stance_damage -= 1 - if(Check_Proppable_Object()) //it helps to lean on something if you've got another leg to stand on - stance_damage -= 1 - - var/list/objects_to_sit_on = list( - /obj/item/stool, - /obj/structure/bed, - ) - - for(var/type in objects_to_sit_on) //things that can't be climbed but can be propped-up-on - if(locate(type) in src.loc) - return - - // standing is poor - if(stance_damage >= 4 || (stance_damage >= 2 && prob(2)) || (stance_damage >= 3 && prob(8))) - if(!(lying || resting)) - if(limb_pain) - emote("scream") - custom_emote(VISIBLE_MESSAGE, "collapses!") - Weaken(3) //can't emote while weakened, apparently. - -/mob/living/carbon/human/proc/handle_grasp() - if(!l_hand && !r_hand) - return - - // You should not be able to pick anything up, but stranger things have happened. - if(l_hand) - for(var/limb_tag in list(BP_L_HAND, BP_L_ARM)) - var/obj/item/organ/external/E = get_organ(limb_tag) - if(!E) - visible_message("Lacking a functioning left hand, \the [src] drops \the [l_hand].") - drop_from_inventory(l_hand) - break - - if(r_hand) - for(var/limb_tag in list(BP_R_HAND, BP_R_ARM)) - var/obj/item/organ/external/E = get_organ(limb_tag) - if(!E) - visible_message("Lacking a functioning right hand, \the [src] drops \the [r_hand].") - drop_from_inventory(r_hand) - break - - // Check again... - if(!l_hand && !r_hand) - return - - for (var/obj/item/organ/external/E in organs) - if(!E || !(E.limb_flags & ORGAN_FLAG_CAN_GRASP)) - continue - if(((E.is_broken() || E.is_dislocated()) && !E.splinted) || E.is_malfunctioning()) - grasp_damage_disarm(E) - -/mob/living/carbon/human/proc/stance_damage_prone(var/obj/item/organ/external/affected) - - if(affected && (!BP_IS_PROSTHETIC(affected) || affected.is_robotic())) - switch(affected.body_part) - if(FOOT_LEFT, FOOT_RIGHT) - if(!BP_IS_PROSTHETIC(affected)) - to_chat(src, SPAN_WARNING("You lose your footing as your [affected.name] spasms!")) - else - to_chat(src, SPAN_WARNING("You lose your footing as your [affected.name] [pick("twitches", "shudders")]!")) - if(LEG_LEFT, LEG_RIGHT) - if(!BP_IS_PROSTHETIC(affected)) - to_chat(src, SPAN_WARNING("Your [affected.name] buckles from the shock!")) - else - to_chat(src, SPAN_WARNING("You lose your balance as [affected.name] [pick("malfunctions", "freezes","shudders")]!")) - else - return - Weaken(4) - -/mob/living/carbon/human/proc/grasp_damage_disarm(var/obj/item/organ/external/affected) - var/disarm_slot - switch(affected.body_part) - if(HAND_LEFT, ARM_LEFT) - disarm_slot = slot_l_hand - if(HAND_RIGHT, ARM_RIGHT) - disarm_slot = slot_r_hand - - if(!disarm_slot) - return - - var/obj/item/thing = get_equipped_item(disarm_slot) - - if(!thing) - return - - if(!unEquip(thing)) - return - - if(affected.is_robotic()) - visible_message("\The [src] drops what they were holding, \his [affected.name] malfunctioning!") - - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src) - spark_system.attach(src) - spark_system.start() - spawn(10) - qdel(spark_system) - - else - var/grasp_name = affected.name - if((affected.body_part in list(ARM_LEFT, ARM_RIGHT)) && affected.children.len) - var/obj/item/organ/external/hand = pick(affected.children) - grasp_name = hand.name - - if(affected.can_feel_pain()) - var/emote_scream = pick("screams in pain", "lets out a sharp cry", "cries out") - var/emote_scream_alt = pick("scream in pain", "let out a sharp cry", "cry out") - visible_message( - "\The [src] [emote_scream] and drops what they were holding in their [grasp_name]!", - null, - "You hear someone [emote_scream_alt]!" - ) - custom_pain("The sharp pain in your [affected.name] forces you to drop [thing]!", 30) - else - visible_message("\The [src] drops what they were holding in their [grasp_name]!") - -/mob/living/carbon/human/proc/sync_organ_dna() - var/list/all_bits = internal_organs|organs - for(var/obj/item/organ/O in all_bits) - O.set_dna(dna) - -/mob/living/proc/is_asystole() - return FALSE - -/mob/living/carbon/human/is_asystole() - if(isSynthetic()) - var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL] - if(istype(C)) - if(!C.is_usable() || !C.percent()) - return TRUE - else if(should_have_organ(BP_HEART)) - var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] - if(!istype(heart) || !heart.is_working()) - return TRUE - return FALSE \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm deleted file mode 100644 index 6f36a1e4856c..000000000000 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ /dev/null @@ -1,94 +0,0 @@ -/**************** - true human verbs -****************/ -/mob/living/carbon/human/proc/tie_hair() - set name = "Tie Hair" - set desc = "Style your hair." - set category = "IC" - - if(incapacitated()) - to_chat(src, "You can't mess with your hair right now!") - return - - if(h_style) - var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_list[h_style] - var/selected_string - if(!(hair_style.flags & HAIR_TIEABLE)) - to_chat(src, "Your hair isn't long enough to tie.") - return - else - var/list/datum/sprite_accessory/hair/valid_hairstyles = list() - for(var/hair_string in GLOB.hair_styles_list) - var/datum/sprite_accessory/hair/test = GLOB.hair_styles_list[hair_string] - if(test.flags & HAIR_TIEABLE) - valid_hairstyles.Add(hair_string) - selected_string = input("Select a new hairstyle", "Your hairstyle", hair_style) as null|anything in valid_hairstyles - if(incapacitated()) - to_chat(src, "You can't mess with your hair right now!") - return - else if(selected_string && h_style != selected_string) - h_style = selected_string - regenerate_icons() - visible_message("[src] pauses a moment to style their hair.") - else - to_chat(src, "You're already using that style.") - -/**************** - misc alien verbs -****************/ -/mob/living/carbon/human/proc/commune() - set category = "Abilities" - set name = "Commune with creature" - set desc = "Send a telepathic message to an unlucky recipient." - - var/list/targets = list() - var/target = null - var/text = null - - targets += getmobs() //Fill list, prompt user with list - target = input("Select a creature!", "Speak to creature", null, null) as null|anything in targets - - if(!target) return - - text = input("What would you like to say?", "Speak to creature", null, null) - - text = sanitize(text) - - if(!text) return - - var/mob/M = targets[target] - - if(isghost(M) || M.stat == DEAD) - to_chat(src, "Not even a [src.species.name] can speak to the dead.") - return - - log_say("[key_name(src)] communed to [key_name(M)]: [text]") - - to_chat(M, "Like lead slabs crashing into the ocean, alien thoughts drop into your mind: [text]") - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.species.name == src.species.name) - return - if(prob(75)) - to_chat(H, "Your nose begins to bleed...") - H.drip(1) - -/mob/living/carbon/human/proc/psychic_whisper(mob/M as mob in oview()) - set name = "Psychic Whisper" - set desc = "Whisper silently to someone over a distance." - set category = "Abilities" - - var/msg = sanitize(input("Message:", "Psychic Whisper") as text|null) - if(msg) - log_say("PsychicWhisper: [key_name(src)]->[M.key] : [msg]") - to_chat(M, "You hear a strange, alien voice in your head... [msg]") - to_chat(src, "You channel a message: \"[msg]\" to [M]") - return - -/mob/living/carbon/human/proc/change_colour() - set category = "Abilities" - set name = "Change Colour" - set desc = "Choose the colour of your skin." - - var/new_skin = input(usr, "Choose your new skin colour: ", "Change Colour", skin_colour) as color|null - change_skin_color(new_skin) diff --git a/code/modules/mob/living/carbon/human/human_skin.dm b/code/modules/mob/living/carbon/human/human_skin.dm deleted file mode 100644 index 5b37b43781f5..000000000000 --- a/code/modules/mob/living/carbon/human/human_skin.dm +++ /dev/null @@ -1,7 +0,0 @@ -/mob/living/carbon/human - var/skin_state = SKIN_NORMAL - -/mob/living/carbon/human/proc/reset_skin() - if(skin_state == SKIN_THREAT) - skin_state = SKIN_NORMAL - update_skin() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm deleted file mode 100644 index f9194b91ef75..000000000000 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ /dev/null @@ -1,44 +0,0 @@ -/mob/living/carbon/human/dummy - real_name = "Test Dummy" - status_flags = GODMODE|CANPUSH - virtual_mob = null - -/mob/living/carbon/human/dummy/mannequin/Initialize() - . = ..() - STOP_PROCESSING(SSmobs, src) - GLOB.human_mob_list -= src - delete_inventory() - -/mob/living/carbon/human/dummy/selfdress/Initialize() - . = ..() - for(var/obj/item/I in loc) - equip_to_appropriate_slot(I) - -/mob/living/carbon/human/corpse/Initialize(mapload, new_species, obj/effect/landmark/corpse/corpse) - . = ..(mapload, new_species) - - adjustOxyLoss(maxHealth)//cease life functions - setBrainLoss(maxHealth) - var/obj/item/organ/internal/heart/corpse_heart = internal_organs_by_name[BP_HEART] - if(corpse_heart) - corpse_heart.pulse = PULSE_NONE//actually stops heart to make worried explorers not care too much - if(corpse) - corpse.randomize_appearance(src, new_species) - corpse.equip_outfit(src) - update_icon() - -/mob/living/carbon/human/dummy/mannequin/add_to_living_mob_list() - return FALSE - -/mob/living/carbon/human/dummy/mannequin/add_to_dead_mob_list() - return FALSE - -/mob/living/carbon/human/dummy/mannequin/fully_replace_character_name(new_name) - ..("[new_name] (mannequin)", FALSE) - -/mob/living/carbon/human/dummy/mannequin/InitializeHud() - return // Mannequins don't get HUDs - -/mob/living/carbon/human/monkey/Initialize(mapload) - gender = pick(MALE, FEMALE) - . = ..(mapload, SPECIES_MONKEY) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm deleted file mode 100644 index 5a9cfd3d79a7..000000000000 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ /dev/null @@ -1,429 +0,0 @@ -/* -Add fingerprints to items when we put them in our hands. -This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically. -*/ - -/mob/living/carbon/human/verb/quick_equip() - set name = "quick-equip" - set hidden = 1 - - if(ishuman(src)) - var/mob/living/carbon/human/H = src - var/obj/item/I = H.get_active_hand() - if(!I) - to_chat(H, "You are not holding anything to equip.") - return - if(H.equip_to_appropriate_slot(I)) - if(hand) - update_inv_l_hand(0) - else - update_inv_r_hand(0) - else - to_chat(H, "You are unable to equip that.") - -/mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1) - for (var/slot in slots) - if (equip_to_slot_if_possible(W, slots[slot], del_on_fail = 0)) - return slot - if (del_on_fail) - qdel(W) - return null - -//Puts the item into our active hand if possible. returns 1 on success. -/mob/living/carbon/human/put_in_active_hand(var/obj/item/W) - return (hand ? put_in_l_hand(W) : put_in_r_hand(W)) - -//Puts the item into our inactive hand if possible. returns 1 on success. -/mob/living/carbon/human/put_in_inactive_hand(var/obj/item/W) - return (hand ? put_in_r_hand(W) : put_in_l_hand(W)) - -/mob/living/carbon/human/put_in_hands(var/obj/item/W) - if(!W) - return 0 - if(put_in_active_hand(W) || put_in_inactive_hand(W)) - W.update_held_icon() - return 1 - return ..() - -/mob/living/carbon/human/put_in_l_hand(var/obj/item/W) - if(!..() || l_hand) - return 0 - if(!check_dexterity(DEXTERITY_GRIP, silent = TRUE, force_active_hand = BP_L_HAND)) - return 0 - equip_to_slot(W,slot_l_hand) - W.add_fingerprint(src) - return 1 - -/mob/living/carbon/human/put_in_r_hand(var/obj/item/W) - if(!..() || r_hand) - return 0 - if(!check_dexterity(DEXTERITY_GRIP, silent = TRUE, force_active_hand = BP_R_HAND)) - return 0 - equip_to_slot(W,slot_r_hand) - W.add_fingerprint(src) - return 1 - -/mob/living/carbon/human/proc/has_organ(name) - var/obj/item/organ/external/O = organs_by_name[name] - return (O && !O.is_stump()) - -/mob/living/carbon/human/proc/has_organ_for_slot(slot) - switch(slot) - if(slot_back) - return has_organ(BP_CHEST) - if(slot_wear_mask) - return has_organ(BP_HEAD) - if(slot_handcuffed) - return has_organ(BP_L_HAND) && has_organ(BP_R_HAND) - if(slot_legcuffed) - return has_organ(BP_L_FOOT) && has_organ(BP_R_FOOT) - if(slot_l_hand) - return has_organ(BP_L_HAND) - if(slot_r_hand) - return has_organ(BP_R_HAND) - if(slot_belt) - return has_organ(BP_CHEST) - if(slot_wear_id) - // the only relevant check for this is the uniform check - return 1 - if(slot_l_ear) - return has_organ(BP_HEAD) - if(slot_r_ear) - return has_organ(BP_HEAD) - if(slot_glasses) - return has_organ(BP_HEAD) - if(slot_gloves) - return has_organ(BP_L_HAND) || has_organ(BP_R_HAND) - if(slot_head) - return has_organ(BP_HEAD) - if(slot_shoes) - return has_organ(BP_L_FOOT) || has_organ(BP_R_FOOT) - if(slot_wear_suit) - return has_organ(BP_CHEST) - if(slot_w_uniform) - return has_organ(BP_CHEST) - if(slot_l_store) - return has_organ(BP_CHEST) - if(slot_r_store) - return has_organ(BP_CHEST) - if(slot_s_store) - return has_organ(BP_CHEST) - if(slot_in_backpack) - return 1 - if(slot_tie) - return 1 - -/mob/living/carbon/human/u_equip(obj/W) - if(!W) return 0 - - if (W == wear_suit) - if(s_store) - drop_from_inventory(s_store) - wear_suit = null - update_inv_wear_suit() - else if (W == w_uniform) - if (r_store) - drop_from_inventory(r_store) - if (l_store) - drop_from_inventory(l_store) - if (wear_id) - drop_from_inventory(wear_id) - if (belt) - drop_from_inventory(belt) - w_uniform = null - update_inv_w_uniform() - else if (W == gloves) - gloves = null - update_inv_gloves() - else if (W == glasses) - glasses = null - update_inv_glasses() - else if (W == head) - head = null - if(istype(W, /obj/item)) - var/obj/item/I = W - if(I.flags_inv & (HIDEMASK|BLOCKHAIR|BLOCKHEADHAIR)) - update_hair(0) //rebuild hair - update_inv_ears(0) - update_inv_wear_mask(0) - if(src) - var/obj/item/clothing/mask/wear_mask = src.get_equipped_item(slot_wear_mask) - if(!(wear_mask && (wear_mask.item_flags & ITEM_FLAG_AIRTIGHT))) - set_internals(null) - update_inv_head() - else if (W == l_ear) - l_ear = null - if(r_ear == W) //check for items that get equipped to both ear slots - r_ear = null - update_inv_ears() - else if (W == r_ear) - r_ear = null - if(l_ear == W) - l_ear = null - update_inv_ears() - else if (W == shoes) - shoes = null - update_inv_shoes() - else if (W == belt) - belt = null - update_inv_belt() - else if (W == wear_mask) - wear_mask = null - if(istype(W, /obj/item)) - var/obj/item/I = W - if(I.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR)) - update_hair(0) //rebuild hair - update_inv_ears(0) - var/obj/item/clothing/mask/head = src.get_equipped_item(slot_head) - if(!(head && (head.item_flags & ITEM_FLAG_AIRTIGHT))) - set_internals(null) - update_inv_wear_mask() - else if (W == wear_id) - wear_id = null - update_inv_wear_id() - else if (W == r_store) - r_store = null - update_inv_pockets() - else if (W == l_store) - l_store = null - update_inv_pockets() - else if (W == s_store) - s_store = null - update_inv_s_store() - else if (W == back) - back = null - update_inv_back() - else if (W == handcuffed) - handcuffed = null - if(buckled && buckled.buckle_require_restraints) - buckled.unbuckle_mob() - update_inv_handcuffed() - else if (W == r_hand) - r_hand = null - if(l_hand) - l_hand.update_twohanding() - update_inv_l_hand() - update_inv_r_hand() - else if (W == l_hand) - l_hand = null - if(r_hand) - r_hand.update_twohanding() - update_inv_l_hand() - update_inv_l_hand() - else - return 0 - - update_action_buttons() - return 1 - - - -//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible() -//set redraw_mob to 0 if you don't wish the hud to be updated - if you're doing it manually in your own proc. -/mob/living/carbon/human/equip_to_slot(obj/item/W, slot, redraw_mob = 1) - - if(!slot) return - if(!istype(W)) return - if(!has_organ_for_slot(slot)) return - if(!species || !species.hud || !(slot in species.hud.equip_slots)) return - W.forceMove(src) - - var/obj/item/old_item = get_equipped_item(slot) - - switch(slot) - if(slot_back) - src.back = W - W.equipped(src, slot) - update_inv_back(redraw_mob) - if(slot_wear_mask) - src.wear_mask = W - if(wear_mask.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR)) - update_hair(redraw_mob) //rebuild hair - update_inv_ears(0) - W.equipped(src, slot) - update_inv_wear_mask(redraw_mob) - if(slot_handcuffed) - src.handcuffed = W - drop_r_hand() - drop_l_hand() - update_inv_handcuffed(redraw_mob) - if(slot_l_hand) - src.l_hand = W - W.equipped(src, slot) - W.screen_loc = ui_lhand - update_inv_l_hand(redraw_mob) - if(slot_r_hand) - src.r_hand = W - W.equipped(src, slot) - W.screen_loc = ui_rhand - update_inv_r_hand(redraw_mob) - if(slot_belt) - src.belt = W - W.equipped(src, slot) - update_inv_belt(redraw_mob) - if(slot_wear_id) - src.wear_id = W - W.equipped(src, slot) - update_inv_wear_id(redraw_mob) - if(slot_l_ear) - src.l_ear = W - if(l_ear.slot_flags & SLOT_TWOEARS) - src.r_ear = W - W.equipped(src, slot) - update_inv_ears(redraw_mob) - if(slot_r_ear) - src.r_ear = W - if(r_ear.slot_flags & SLOT_TWOEARS) - src.l_ear = W - W.equipped(src, slot) - update_inv_ears(redraw_mob) - if(slot_glasses) - src.glasses = W - W.equipped(src, slot) - update_inv_glasses(redraw_mob) - if(slot_gloves) - src.gloves = W - W.equipped(src, slot) - update_inv_gloves(redraw_mob) - if(slot_head) - src.head = W - if(head.flags_inv & (BLOCKHAIR|BLOCKHEADHAIR|HIDEMASK)) - update_hair(redraw_mob) //rebuild hair - update_inv_ears(0) - update_inv_wear_mask(0) - if(istype(W,/obj/item/clothing/head/kitty)) - W.update_icon(src) - W.equipped(src, slot) - update_inv_head(redraw_mob) - if(slot_shoes) - src.shoes = W - W.equipped(src, slot) - update_inv_shoes(redraw_mob) - if(slot_wear_suit) - src.wear_suit = W - if(wear_suit.flags_inv & HIDESHOES) - update_inv_shoes(0) - if(wear_suit.flags_inv & HIDEGLOVES) - update_inv_gloves(0) - if(wear_suit.flags_inv & HIDEJUMPSUIT) - update_inv_w_uniform(0) - W.equipped(src, slot) - update_inv_wear_suit(redraw_mob) - if(slot_w_uniform) - src.w_uniform = W - if(w_uniform.flags_inv & HIDESHOES) - update_inv_shoes(0) - W.equipped(src, slot) - update_inv_w_uniform(redraw_mob) - if(slot_l_store) - src.l_store = W - W.equipped(src, slot) - update_inv_pockets(redraw_mob) - if(slot_r_store) - src.r_store = W - W.equipped(src, slot) - update_inv_pockets(redraw_mob) - if(slot_s_store) - src.s_store = W - W.equipped(src, slot) - update_inv_s_store(redraw_mob) - if(slot_in_backpack) - if(src.get_active_hand() == W) - src.remove_from_mob(W) - W.forceMove(src.back) - if(slot_tie) - var/obj/item/clothing/under/uniform = src.w_uniform - if(uniform) - uniform.attackby(W,src) - else - to_chat(src, "You are trying to eqip this item to an unsupported inventory slot. If possible, please write a ticket with steps to reproduce. Slot was: [slot]") - return - - if((W == src.l_hand) && (slot != slot_l_hand)) - src.l_hand = null - update_inv_l_hand() //So items actually disappear from hands. - else if((W == src.r_hand) && (slot != slot_r_hand)) - src.r_hand = null - update_inv_r_hand() - - W.hud_layerise() - for(var/s in species.hud.gear) - var/list/gear = species.hud.gear[s] - if(gear["slot"] == slot) - W.screen_loc = gear["loc"] - if(W.action_button_name) - update_action_buttons() - - // if we replaced an item, delete the old item. do this at the end to make the replacement seamless - if(old_item) - qdel(old_item) - - return 1 - -//Checks if a given slot can be accessed at this time, either to equip or unequip I -/mob/living/carbon/human/slot_is_accessible(var/slot, var/obj/item/I, mob/user=null) - var/obj/item/covering = null - var/check_flags = 0 - - switch(slot) - if(slot_wear_mask) - covering = src.head - check_flags = FACE - if(slot_glasses) - covering = src.head - check_flags = EYES - if(slot_gloves, slot_w_uniform) - covering = src.wear_suit - - if(covering && (covering.body_parts_covered & (I.body_parts_covered|check_flags))) - to_chat(user, "\The [covering] is in the way.") - return 0 - return 1 - -/mob/living/carbon/human/get_equipped_item(var/slot) - switch(slot) - if(slot_back) return back - if(slot_handcuffed) return handcuffed - if(slot_l_store) return l_store - if(slot_r_store) return r_store - if(slot_wear_mask) return wear_mask - if(slot_l_hand) return l_hand - if(slot_r_hand) return r_hand - if(slot_wear_id) return wear_id - if(slot_glasses) return glasses - if(slot_gloves) return gloves - if(slot_head) return head - if(slot_shoes) return shoes - if(slot_belt) return belt - if(slot_wear_suit) return wear_suit - if(slot_w_uniform) return w_uniform - if(slot_s_store) return s_store - if(slot_l_ear) return l_ear - if(slot_r_ear) return r_ear - return ..() - -/mob/living/carbon/human/get_equipped_items(var/include_carried = 0) - . = ..() - if(belt) . += belt - if(l_ear) . += l_ear - if(r_ear) . += r_ear - if(glasses) . += glasses - if(gloves) . += gloves - if(head) . += head - if(shoes) . += shoes - if(wear_id) . += wear_id - if(wear_suit) . += wear_suit - if(w_uniform) . += w_uniform - - if(include_carried) - if(l_store) . += l_store - if(r_store) . += r_store - if(handcuffed) . += handcuffed - if(s_store) . += s_store - -//Same as get_covering_equipped_items, but using target zone instead of bodyparts flags -/mob/living/carbon/human/proc/get_covering_equipped_item_by_zone(var/zone) - var/obj/item/organ/external/O = get_organ(zone) - if(O) - return get_covering_equipped_item(O.body_part) - diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm deleted file mode 100644 index 814c9306e3da..000000000000 --- a/code/modules/mob/living/carbon/human/life.dm +++ /dev/null @@ -1,1124 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! -#define HUMAN_MAX_OXYLOSS 1 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it. - -#define HUMAN_CRIT_TIME_CUSHION (10 MINUTES) //approximate time limit to stabilize someone in crit -#define HUMAN_CRIT_HEALTH_CUSHION (config.health_threshold_crit - config.health_threshold_dead) - -//The amount of damage you'll get when in critical condition. We want this to be a HUMAN_CRIT_TIME_CUSHION long deal. -//There are HUMAN_CRIT_HEALTH_CUSHION hp to get through, so (HUMAN_CRIT_HEALTH_CUSHION/HUMAN_CRIT_TIME_CUSHION) per tick. -//Breaths however only happen once every MOB_BREATH_DELAY life ticks. The delay between life ticks is set by the mob process. -#define HUMAN_CRIT_MAX_OXYLOSS ( MOB_BREATH_DELAY * process_schedule_interval("mob") * (HUMAN_CRIT_HEALTH_CUSHION/HUMAN_CRIT_TIME_CUSHION) ) - -#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point -#define HEAT_DAMAGE_LEVEL_2 4 //Amount of damage applied when your body temperature passes the 400K point -#define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 1000K point - -#define COLD_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when your body temperature just passes the 260.15k safety point -#define COLD_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 200K point -#define COLD_DAMAGE_LEVEL_3 3 //Amount of damage applied when your body temperature passes the 120K point - -//Note that gas heat damage is only applied once every FOUR ticks. -#define HEAT_GAS_DAMAGE_LEVEL_1 2 //Amount of damage applied when the current breath's temperature just passes the 360.15k safety point -#define HEAT_GAS_DAMAGE_LEVEL_2 4 //Amount of damage applied when the current breath's temperature passes the 400K point -#define HEAT_GAS_DAMAGE_LEVEL_3 8 //Amount of damage applied when the current breath's temperature passes the 1000K point - -#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point -#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point -#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point - -#define RADIATION_SPEED_COEFFICIENT 0.025 - -/mob/living/carbon/human - var/oxygen_alert = 0 - var/toxins_alert = 0 - var/co2_alert = 0 - var/fire_alert = 0 - var/pressure_alert = 0 - var/temperature_alert = 0 - var/heartbeat = 0 - var/stamina = 100 - -/mob/living/carbon/human/Life() - set invisibility = 0 - set background = BACKGROUND_ENABLED - - if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) - return - - fire_alert = 0 //Reset this here, because both breathe() and handle_environment() have a chance to set it. - - //TODO: seperate this out - // update the current life tick, can be used to e.g. only do something every 4 ticks - life_tick++ - - // This is not an ideal place for this but it will do for now. - if(wearing_rig && wearing_rig.offline) - wearing_rig = null - - ..() - - if(life_tick%30==15) - hud_updateflag = 1022 - - voice = GetVoice() - - //No need to update all of these procs if the guy is dead. - if(stat != DEAD && !InStasis()) - //Updates the number of stored chemicals for powers - handle_changeling() - - //Organs and blood - handle_organs() - stabilize_body_temperature() //Body temperature adjusts itself (self-regulation) - - handle_shock() - - handle_pain() - - handle_stamina() - - handle_medical_side_effects() - - if(!handle_some_updates()) - return //We go ahead and process them 5 times for HUD images and other stuff though. - - //Update our name based on whether our face is obscured/disfigured - SetName(get_visible_name()) - -/mob/living/carbon/human/get_stamina() - return stamina - -/mob/living/carbon/human/adjust_stamina(var/amt) - var/last_stamina = stamina - if(stat == DEAD) - stamina = 0 - else - stamina = Clamp(stamina + amt, 0, 100) - if(stamina <= 0) - to_chat(src, SPAN_WARNING("You are exhausted!")) - if(MOVING_QUICKLY(src)) - set_moving_slowly() - if(last_stamina != stamina && hud_used) - hud_used.update_stamina() - -/mob/living/carbon/human/proc/handle_stamina() - if((world.time - last_quick_move_time) > 5 SECONDS) - var/mod = (lying + (nutrition / initial(nutrition))) / 2 - adjust_stamina(max(config.minimum_stamina_recovery, config.maximum_stamina_recovery * mod) * (1+chem_effects[CE_ENERGETIC])) - -/mob/living/carbon/human/set_stat(var/new_stat) - var/old_stat = stat - . = ..() - if(stat) - update_skin(1) - if(client && client.is_afk()) - if(old_stat == UNCONSCIOUS && stat == CONSCIOUS) - playsound_local(null, 'sound/effects/bells.ogg', 100, is_global=TRUE) - -/mob/living/carbon/human/proc/handle_some_updates() - if(life_tick > 5 && timeofdeath && (timeofdeath < 5 || world.time - timeofdeath > 6000)) //We are long dead, or we're junk mobs spawned like the clowns on the clown shuttle - return 0 - return 1 - -/mob/living/carbon/human/breathe() - var/species_organ = species.breathing_organ - - if(species_organ) - var/active_breaths = 0 - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species_organ] - if(L) - active_breaths = L.active_breathing - ..(active_breaths) - -// Calculate how vulnerable the human is to the current pressure. -// Returns 0 (equals 0 %) if sealed in an undamaged suit that's rated for the pressure, 1 if unprotected (equals 100%). -// Suitdamage can modifiy this in 10% steps. -/mob/living/carbon/human/proc/get_pressure_weakness(pressure) - - var/pressure_adjustment_coefficient = 0 - var/list/zones = list(HEAD, UPPER_TORSO, LOWER_TORSO, LEGS, FEET, ARMS, HANDS) - for(var/zone in zones) - var/list/covers = get_covering_equipped_items(zone) - var/zone_exposure = 1 - for(var/obj/item/clothing/C in covers) - zone_exposure = min(zone_exposure, C.get_pressure_weakness(pressure,zone)) - if(zone_exposure >= 1) - return 1 - pressure_adjustment_coefficient = max(pressure_adjustment_coefficient, zone_exposure) - pressure_adjustment_coefficient = Clamp(pressure_adjustment_coefficient, 0, 1) // So it isn't less than 0 or larger than 1. - - return pressure_adjustment_coefficient - -// Calculate how much of the enviroment pressure-difference affects the human. -/mob/living/carbon/human/calculate_affecting_pressure(var/pressure) - var/pressure_difference - - // First get the absolute pressure difference. - if(pressure < ONE_ATMOSPHERE) // We are in an underpressure. - pressure_difference = ONE_ATMOSPHERE - pressure - - else //We are in an overpressure or standard atmosphere. - pressure_difference = pressure - ONE_ATMOSPHERE - - if(pressure_difference < 5) // If the difference is small, don't bother calculating the fraction. - pressure_difference = 0 - - else - // Otherwise calculate how much of that absolute pressure difference affects us, can be 0 to 1 (equals 0% to 100%). - // This is our relative difference. - pressure_difference *= get_pressure_weakness(pressure) - - // The difference is always positive to avoid extra calculations. - // Apply the relative difference on a standard atmosphere to get the final result. - // The return value will be the adjusted_pressure of the human that is the basis of pressure warnings and damage. - if(pressure < ONE_ATMOSPHERE) - return ONE_ATMOSPHERE - pressure_difference - else - return ONE_ATMOSPHERE + pressure_difference - -/mob/living/carbon/human/handle_impaired_vision() - ..() - //Vision - var/obj/item/organ/vision - if(species.vision_organ) - vision = internal_organs_by_name[species.vision_organ] - - if(!species.vision_organ) // Presumably if a species has no vision organs, they see via some other means. - eye_blind = 0 - blinded = 0 - eye_blurry = 0 - else if(!vision || (vision && !vision.is_usable())) // Vision organs cut out or broken? Permablind. - eye_blind = 1 - blinded = 1 - eye_blurry = 1 - else - //blindness - if(!(sdisabilities & BLINDED)) - if(equipment_tint_total >= TINT_BLIND) // Covered eyes, heal faster - eye_blurry = max(eye_blurry-2, 0) - -/mob/living/carbon/human/handle_disabilities() - ..() - if(stat != DEAD) - if ((disabilities & COUGHING) && prob(5) && paralysis <= 1) - unequip_item() - spawn(0) - emote("cough") - -/mob/living/carbon/human/handle_mutations_and_radiation() - if(getFireLoss()) - if((MUTATION_COLD_RESISTANCE in mutations) || (prob(1))) - heal_organ_damage(0,1) - - // DNA2 - Gene processing. - // The HULK stuff that was here is now in the hulk gene. - for(var/datum/dna/gene/gene in dna_genes) - if(!gene.block) - continue - if(gene.is_active(src)) - gene.OnMobLife(src) - - radiation = Clamp(radiation,0,500) - - if(!radiation) - if(species.appearance_flags & RADIATION_GLOWS) - set_light(0) - else - if(species.appearance_flags & RADIATION_GLOWS) - set_light(0.3, 0.1, max(1,min(20,radiation/20)), 2, species.get_flesh_colour(src)) - // END DOGSHIT SNOWFLAKE - var/damage = 0 - radiation -= 1 * RADIATION_SPEED_COEFFICIENT - if(prob(25)) - damage = 2 - - if (radiation > 50) - damage = 2 - radiation -= 2 * RADIATION_SPEED_COEFFICIENT - if(!isSynthetic()) - if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT)) - radiation -= 5 * RADIATION_SPEED_COEFFICIENT - to_chat(src, "You feel weak.") - Weaken(3) - if(!lying) - emote("collapse") - if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT)) - lose_hair() - - if (radiation > 75) - damage = 3 - radiation -= 3 * RADIATION_SPEED_COEFFICIENT - if(!isSynthetic()) - if(prob(5)) - take_overall_damage(0, 5 * RADIATION_SPEED_COEFFICIENT, used_weapon = "Radiation Burns") - if(prob(1)) - to_chat(src, "You feel strange!") - adjustCloneLoss(5 * RADIATION_SPEED_COEFFICIENT) - emote("gasp") - if(radiation > 150) - damage = 8 - radiation -= 4 * RADIATION_SPEED_COEFFICIENT - - damage = Floor(damage * species.get_radiation_mod(src)) - if(damage) - adjustToxLoss(damage * RADIATION_SPEED_COEFFICIENT) - immunity = max(0, immunity - damage * 15 * RADIATION_SPEED_COEFFICIENT) - updatehealth() - if(!isSynthetic() && organs.len) - var/obj/item/organ/external/O = pick(organs) - if(istype(O)) O.add_autopsy_data("Radiation Poisoning", damage) - - /** breathing **/ - -/mob/living/carbon/human/handle_chemical_smoke(var/datum/gas_mixture/environment) - if(wear_mask && (wear_mask.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) - return - if(glasses && (glasses.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) - return - if(head && (head.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) - return - ..() - -/mob/living/carbon/human/get_breath_from_internal(volume_needed=STD_BREATH_VOLUME) - if(internal) - - var/obj/item/tank/rig_supply - if(istype(back,/obj/item/rig)) - var/obj/item/rig/rig = back - if(!rig.offline && (rig.air_supply && internal == rig.air_supply)) - rig_supply = rig.air_supply - - if (!rig_supply && (!contents.Find(internal) || !((wear_mask && (wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) || (head && (head.item_flags & ITEM_FLAG_AIRTIGHT))))) - set_internals(null) - - if(internal) - return internal.remove_air_volume(volume_needed) - return null - -/mob/living/carbon/human/handle_breath(datum/gas_mixture/breath) - if(status_flags & GODMODE) - return - var/species_organ = species.breathing_organ - if(!species_organ) - return - - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species_organ] - if(!L || nervous_system_failure()) - failed_last_breath = 1 - else - failed_last_breath = L.handle_breath(breath) //if breath is null or vacuum, the lungs will handle it for us - return !failed_last_breath - -/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment) - if(!environment || (MUTATION_SPACERES in mutations)) - return - - //Stuff like water absorbtion happens here. - species.handle_environment_special(src) - - //Moved pressure calculations here for use in skip-processing check. - var/pressure = environment.return_pressure() - var/adjusted_pressure = calculate_affecting_pressure(pressure) - - //Check for contaminants before anything else because we don't want to skip it. - for(var/g in environment.gas) - var/decl/material/mat = decls_repository.get_decl(g) - if((mat.gas_flags & XGM_GAS_CONTAMINANT) && environment.gas[g] > mat.gas_overlay_limit + 1) - handle_contaminants() - break - - if(istype(src.loc, /turf/space)) //being in a closet will interfere with radiation, may not make sense but we don't model radiation for atoms in general so it will have to do for now. - //Don't bother if the temperature drop is less than 0.1 anyways. Hopefully BYOND is smart enough to turn this constant expression into a constant - if(bodytemperature > (0.1 * HUMAN_HEAT_CAPACITY/(HUMAN_EXPOSED_SURFACE_AREA*STEFAN_BOLTZMANN_CONSTANT))**(1/4) + COSMIC_RADIATION_TEMPERATURE) - - //Thermal radiation into space - var/heat_gain = get_thermal_radiation(bodytemperature, HUMAN_EXPOSED_SURFACE_AREA, 0.5, SPACE_HEAT_TRANSFER_COEFFICIENT) - - var/temperature_gain = heat_gain/HUMAN_HEAT_CAPACITY - bodytemperature += temperature_gain //temperature_gain will often be negative - - var/relative_density = (environment.total_moles/environment.volume) / (MOLES_CELLSTANDARD/CELL_VOLUME) - if(relative_density > 0.02) //don't bother if we are in vacuum or near-vacuum - var/loc_temp = environment.temperature - - if(adjusted_pressure < species.warning_high_pressure && adjusted_pressure > species.warning_low_pressure && abs(loc_temp - bodytemperature) < 20 && bodytemperature < species.heat_level_1 && bodytemperature > species.cold_level_1 && species.body_temperature) - pressure_alert = 0 - return // Temperatures are within normal ranges, fuck all this processing. ~Ccomp - - //Body temperature adjusts depending on surrounding atmosphere based on your thermal protection (convection) - var/temp_adj = 0 - if(loc_temp < bodytemperature) //Place is colder than we are - var/thermal_protection = get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. - if(thermal_protection < 1) - temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR) //this will be negative - else if (loc_temp > bodytemperature) //Place is hotter than we are - var/thermal_protection = get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. - if(thermal_protection < 1) - temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR) - - //Use heat transfer as proportional to the gas density. However, we only care about the relative density vs standard 101 kPa/20 C air. Therefore we can use mole ratios - bodytemperature += between(BODYTEMP_COOLING_MAX, temp_adj*relative_density, BODYTEMP_HEATING_MAX) - - // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. - if(bodytemperature >= getSpeciesOrSynthTemp(HEAT_LEVEL_1)) - //Body temperature is too hot. - fire_alert = max(fire_alert, 1) - if(status_flags & GODMODE) return 1 //godmode - var/burn_dam = 0 - if(bodytemperature < getSpeciesOrSynthTemp(HEAT_LEVEL_2)) - burn_dam = HEAT_DAMAGE_LEVEL_1 - else if(bodytemperature < getSpeciesOrSynthTemp(HEAT_LEVEL_3)) - burn_dam = HEAT_DAMAGE_LEVEL_2 - else - burn_dam = HEAT_DAMAGE_LEVEL_3 - take_overall_damage(burn=burn_dam, used_weapon = "High Body Temperature") - fire_alert = max(fire_alert, 2) - - else if(bodytemperature <= getSpeciesOrSynthTemp(COLD_LEVEL_1)) - fire_alert = max(fire_alert, 1) - if(status_flags & GODMODE) return 1 //godmode - - var/burn_dam = 0 - - if(bodytemperature > getSpeciesOrSynthTemp(COLD_LEVEL_2)) - burn_dam = COLD_DAMAGE_LEVEL_1 - else if(bodytemperature > getSpeciesOrSynthTemp(COLD_LEVEL_3)) - burn_dam = COLD_DAMAGE_LEVEL_2 - else - burn_dam = COLD_DAMAGE_LEVEL_3 - SetStasis(getCryogenicFactor(bodytemperature), STASIS_COLD) - if(!chem_effects[CE_CRYO]) - take_overall_damage(burn=burn_dam, used_weapon = "Low Body Temperature") - fire_alert = max(fire_alert, 1) - - // Account for massive pressure differences. Done by Polymorph - // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! - if(status_flags & GODMODE) return 1 //godmode - - if(adjusted_pressure >= species.hazard_high_pressure) - var/pressure_damage = min( ( (adjusted_pressure / species.hazard_high_pressure) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) - take_overall_damage(brute=pressure_damage, used_weapon = "High Pressure") - pressure_alert = 2 - else if(adjusted_pressure >= species.warning_high_pressure) - pressure_alert = 1 - else if(adjusted_pressure >= species.warning_low_pressure) - pressure_alert = 0 - else if(adjusted_pressure >= species.hazard_low_pressure) - pressure_alert = -1 - else - var/list/obj/item/organ/external/parts = get_damageable_organs() - for(var/obj/item/organ/external/O in parts) - if(QDELETED(O) || !(O.owner == src)) - continue - if(O.damage + (LOW_PRESSURE_DAMAGE) < O.min_broken_damage) //vacuum does not break bones - O.take_external_damage(brute = LOW_PRESSURE_DAMAGE, used_weapon = "Low Pressure") - if(getOxyLoss() < 55) // 11 OxyLoss per 4 ticks when wearing internals; unconsciousness in 16 ticks, roughly half a minute - adjustOxyLoss(4) // 16 OxyLoss per 4 ticks when no internals present; unconsciousness in 13 ticks, roughly twenty seconds - pressure_alert = -2 - - return - -/mob/living/carbon/human/proc/stabilize_body_temperature() - // We produce heat naturally. - if (species.passive_temp_gain) - bodytemperature += species.passive_temp_gain - - // Robolimbs cause overheating too. - if(robolimb_count) - bodytemperature += round(robolimb_count/2) - - if (species.body_temperature == null || isSynthetic()) - return //this species doesn't have metabolic thermoregulation - - var/body_temperature_difference = species.body_temperature - bodytemperature - - if (abs(body_temperature_difference) < 0.5) - return //fuck this precision - - if (on_fire) - return //too busy for pesky metabolic regulation - - if(bodytemperature < species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects. - var/nut_remove = 10 * DEFAULT_HUNGER_FACTOR - if(nutrition >= nut_remove) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up. - adjust_nutrition(-nut_remove) - bodytemperature += max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM) - else if(species.cold_level_1 <= bodytemperature && bodytemperature <= species.heat_level_1) - bodytemperature += body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR - else if(bodytemperature > species.heat_level_1) //360.15 is 310.15 + 50, the temperature where you start to feel effects. - var/hyd_remove = 10 * DEFAULT_THIRST_FACTOR - if(hydration >= hyd_remove) - adjust_hydration(-hyd_remove) - bodytemperature += min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) - - //This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, UPPER_TORSO, LOWER_TORSO, etc. See setup.dm for the full list) -/mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to. - . = 0 - //Handle normal clothing - for(var/obj/item/clothing/C in list(head,wear_suit,w_uniform,shoes,gloves,wear_mask)) - if(C) - if(C.max_heat_protection_temperature && C.max_heat_protection_temperature >= temperature) - . |= C.heat_protection - if(C.accessories.len) - for(var/obj/item/clothing/accessory/A in C.accessories) - if(A.max_heat_protection_temperature && A.max_heat_protection_temperature >= temperature) - . |= A.heat_protection - -//See proc/get_heat_protection_flags(temperature) for the description of this proc. -/mob/living/carbon/human/proc/get_cold_protection_flags(temperature) - . = 0 - //Handle normal clothing - for(var/obj/item/clothing/C in list(head,wear_suit,w_uniform,shoes,gloves,wear_mask)) - if(C) - if(C.min_cold_protection_temperature && C.min_cold_protection_temperature <= temperature) - . |= C.cold_protection - if(C.accessories.len) - for(var/obj/item/clothing/accessory/A in C.accessories) - if(A.min_cold_protection_temperature && A.min_cold_protection_temperature <= temperature) - . |= A.cold_protection - - -/mob/living/carbon/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to. - var/thermal_protection_flags = get_heat_protection_flags(temperature) - return get_thermal_protection(thermal_protection_flags) - -/mob/living/carbon/human/get_cold_protection(temperature) - if(MUTATION_COLD_RESISTANCE in mutations) - return 1 //Fully protected from the cold. - - temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. - var/thermal_protection_flags = get_cold_protection_flags(temperature) - return get_thermal_protection(thermal_protection_flags) - -/mob/living/carbon/human/proc/get_thermal_protection(var/flags) - .=0 - if(flags) - if(flags & HEAD) - . += THERMAL_PROTECTION_HEAD - if(flags & UPPER_TORSO) - . += THERMAL_PROTECTION_UPPER_TORSO - if(flags & LOWER_TORSO) - . += THERMAL_PROTECTION_LOWER_TORSO - if(flags & LEG_LEFT) - . += THERMAL_PROTECTION_LEG_LEFT - if(flags & LEG_RIGHT) - . += THERMAL_PROTECTION_LEG_RIGHT - if(flags & FOOT_LEFT) - . += THERMAL_PROTECTION_FOOT_LEFT - if(flags & FOOT_RIGHT) - . += THERMAL_PROTECTION_FOOT_RIGHT - if(flags & ARM_LEFT) - . += THERMAL_PROTECTION_ARM_LEFT - if(flags & ARM_RIGHT) - . += THERMAL_PROTECTION_ARM_RIGHT - if(flags & HAND_LEFT) - . += THERMAL_PROTECTION_HAND_LEFT - if(flags & HAND_RIGHT) - . += THERMAL_PROTECTION_HAND_RIGHT - return min(1,.) - -/mob/living/carbon/human/handle_chemicals_in_body() - - chem_effects.Cut() - - if(status_flags & GODMODE) - return 0 - - if(isSynthetic()) - return - - var/datum/reagents/metabolism/ingested = get_ingested_reagents() - - if(reagents) - if(touching) touching.metabolize() - if(bloodstr) bloodstr.metabolize() - if(ingested) metabolize_ingested_reagents() - - // Trace chemicals - for(var/T in chem_doses) - if(bloodstr.has_reagent(T) || ingested.has_reagent(T) || touching.has_reagent(T)) - continue - var/decl/material/R = T - chem_doses[T] -= initial(R.metabolism)*2 - if(chem_doses[T] <= 0) - chem_doses -= T - - // Not an ideal place to handle this, but there doesn't seem to be a more appropriate centralized area. - if(chem_effects[CE_GLOWINGEYES]) - update_eyes() - - updatehealth() - -// Check if we should die. -/mob/living/carbon/human/proc/handle_death_check() - if(should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN] - if(!brain || (brain.status & ORGAN_DEAD)) - return TRUE - return species.handle_death_check(src) - -//DO NOT CALL handle_statuses() from this proc, it's called from living/Life() as long as this returns a true value. -/mob/living/carbon/human/handle_regular_status_updates() - if(!handle_some_updates()) - return 0 - - if(status_flags & GODMODE) return 0 - - //SSD check, if a logged player is awake put them back to sleep! - if(ssd_check() && species.get_ssd(src) || player_triggered_sleeping) - Sleeping(2) - if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP - blinded = 1 - silent = 0 - else //ALIVE. LIGHTS ARE ON - updatehealth() //TODO - - if(handle_death_check()) - death() - blinded = 1 - silent = 0 - return 1 - - if(hallucination_power) - handle_hallucinations() - - if(get_shock() >= species.total_health) - if(!stat) - to_chat(src, "[species.halloss_message_self]") - src.visible_message("[src] [species.halloss_message]") - Paralyse(10) - - if(paralysis || sleeping) - blinded = 1 - set_stat(UNCONSCIOUS) - animate_tail_reset() - adjustHalLoss(-3) - if(sleeping) - handle_dreams() - if (mind) - //Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of sedatives or similar. - if(client || sleeping > 3) - AdjustSleeping(-1) - species.handle_sleeping(src) - if(prob(2) && is_asystole() && isSynthetic()) - visible_message("[src] [pick("emits low pitched whirr","beeps urgently")]") - //CONSCIOUS - else - set_stat(CONSCIOUS) - - // Check everything else. - - //Periodically double-check embedded_flag - if(embedded_flag && !(life_tick % 10)) - if(!embedded_needs_process()) - embedded_flag = 0 - - //Resting - if(resting) - dizziness = max(0, dizziness - 15) - jitteriness = max(0, jitteriness - 15) - adjustHalLoss(-3) - else - dizziness = max(0, dizziness - 3) - jitteriness = max(0, jitteriness - 3) - adjustHalLoss(-1) - - if (drowsyness > 0) - drowsyness = max(0, drowsyness-1) - eye_blurry = max(2, eye_blurry) - if(drowsyness > 10) - var/zzzchance = min(5, 5*drowsyness/30) - if((prob(zzzchance) || drowsyness >= 60)) - if(stat == CONSCIOUS) - to_chat(src, "You are about to fall asleep...") - Sleeping(5) - - // If you're dirty, your gloves will become dirty, too. - if(gloves && germ_level > gloves.germ_level && prob(10)) - gloves.germ_level += 1 - - if(vsc.contaminant_control.CONTAMINATION_LOSS) - var/total_contamination= 0 - for(var/obj/item/I in src) - if(I.contaminated) - total_contamination += vsc.contaminant_control.CONTAMINATION_LOSS - adjustToxLoss(total_contamination) - - // nutrition decrease - if(nutrition > 0) - adjust_nutrition(-species.hunger_factor) - if(hydration > 0) - adjust_hydration(-species.thirst_factor) - - if(stasis_value > 1 && drowsyness < stasis_value * 4) - drowsyness += min(stasis_value, 3) - if(!stat && prob(1)) - to_chat(src, "You feel slow and sluggish...") - - return 1 - -/mob/living/carbon/human/handle_regular_hud_updates() - if(hud_updateflag) // update our mob's hud overlays, AKA what others see flaoting above our head - handle_hud_list() - - // now handle what we see on our screen - - if(!..()) - return - - if(stat != DEAD) - if(stat == UNCONSCIOUS && health < maxHealth/2) - //Critical damage passage overlay - var/severity = 0 - switch(health - maxHealth/2) - if(-20 to -10) severity = 1 - if(-30 to -20) severity = 2 - if(-40 to -30) severity = 3 - if(-50 to -40) severity = 4 - if(-60 to -50) severity = 5 - if(-70 to -60) severity = 6 - if(-80 to -70) severity = 7 - if(-90 to -80) severity = 8 - if(-95 to -90) severity = 9 - if(-INFINITY to -95) severity = 10 - overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity) - else - clear_fullscreen("crit") - //Oxygen damage overlay - if(getOxyLoss()) - var/severity = 0 - switch(getOxyLoss()) - if(10 to 20) severity = 1 - if(20 to 25) severity = 2 - if(25 to 30) severity = 3 - if(30 to 35) severity = 4 - if(35 to 40) severity = 5 - if(40 to 45) severity = 6 - if(45 to INFINITY) severity = 7 - overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity) - else - clear_fullscreen("oxy") - - //Fire and Brute damage overlay (BSSR) - var/hurtdamage = src.getBruteLoss() + src.getFireLoss() + damageoverlaytemp - damageoverlaytemp = 0 // We do this so we can detect if someone hits us or not. - if(hurtdamage) - var/severity = 0 - switch(hurtdamage) - if(10 to 25) severity = 1 - if(25 to 40) severity = 2 - if(40 to 55) severity = 3 - if(55 to 70) severity = 4 - if(70 to 85) severity = 5 - if(85 to INFINITY) severity = 6 - overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity) - else - clear_fullscreen("brute") - - if(healths) - - var/mutable_appearance/healths_ma = new(healths) - healths_ma.icon_state = "blank" - healths_ma.overlays = null - - if (chem_effects[CE_PAINKILLER] > 100) - healths_ma.icon_state = "health_numb" - else - // Generate a by-limb health display. - var/no_damage = 1 - var/trauma_val = 0 // Used in calculating softcrit/hardcrit indicators. - if(can_feel_pain()) - trauma_val = max(shock_stage,get_shock())/(species.total_health-100) - // Collect and apply the images all at once to avoid appearance churn. - var/list/health_images = list() - for(var/obj/item/organ/external/E in organs) - if(no_damage && (E.brute_dam || E.burn_dam)) - no_damage = 0 - health_images += E.get_damage_hud_image() - - // Apply a fire overlay if we're burning. - if(on_fire) - health_images += image('icons/mob/screen1_health.dmi',"burning") - - // Show a general pain/crit indicator if needed. - if(is_asystole()) - health_images += image('icons/mob/screen1_health.dmi',"hardcrit") - else if(trauma_val) - if(can_feel_pain()) - if(trauma_val > 0.7) - health_images += image('icons/mob/screen1_health.dmi',"softcrit") - if(trauma_val >= 1) - health_images += image('icons/mob/screen1_health.dmi',"hardcrit") - else if(no_damage) - health_images += image('icons/mob/screen1_health.dmi',"fullhealth") - healths_ma.overlays += health_images - healths.appearance = healths_ma - - if(nutrition_icon) - switch(nutrition) - if(450 to INFINITY) nutrition_icon.icon_state = "nutrition0" - if(350 to 450) nutrition_icon.icon_state = "nutrition1" - if(250 to 350) nutrition_icon.icon_state = "nutrition2" - if(150 to 250) nutrition_icon.icon_state = "nutrition3" - else nutrition_icon.icon_state = "nutrition4" - - if(hydration_icon) - switch(hydration) - if(450 to INFINITY) hydration_icon.icon_state = "hydration0" - if(350 to 450) hydration_icon.icon_state = "hydration1" - if(250 to 350) hydration_icon.icon_state = "hydration2" - if(150 to 250) hydration_icon.icon_state = "hydration3" - else hydration_icon.icon_state = "hydration4" - - if(isSynthetic()) - var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL] - if (istype(C)) - var/chargeNum = Clamp(ceil(C.percent()/25), 0, 4) //0-100 maps to 0-4, but give it a paranoid clamp just in case. - cells.icon_state = "charge[chargeNum]" - else - cells.icon_state = "charge-empty" - - if(pressure) - pressure.icon_state = "pressure[pressure_alert]" - if(toxin) - toxin.icon_state = "tox[toxins_alert ? "1" : "0"]" - if(oxygen) - oxygen.icon_state = "oxy[oxygen_alert ? "1" : "0"]" - if(fire) - fire.icon_state = "fire[fire_alert ? fire_alert : 0]" - - if(bodytemp) - if (!species) - switch(bodytemperature) //310.055 optimal body temp - if(370 to INFINITY) bodytemp.icon_state = "temp4" - if(350 to 370) bodytemp.icon_state = "temp3" - if(335 to 350) bodytemp.icon_state = "temp2" - if(320 to 335) bodytemp.icon_state = "temp1" - if(300 to 320) bodytemp.icon_state = "temp0" - if(295 to 300) bodytemp.icon_state = "temp-1" - if(280 to 295) bodytemp.icon_state = "temp-2" - if(260 to 280) bodytemp.icon_state = "temp-3" - else bodytemp.icon_state = "temp-4" - else - //TODO: precalculate all of this stuff when the species datum is created - var/base_temperature = species.body_temperature - if(base_temperature == null) //some species don't have a set metabolic temperature - base_temperature = (getSpeciesOrSynthTemp(HEAT_LEVEL_1) + getSpeciesOrSynthTemp(COLD_LEVEL_1))/2 - - var/temp_step - if (bodytemperature >= base_temperature) - temp_step = (getSpeciesOrSynthTemp(HEAT_LEVEL_1) - base_temperature)/4 - - if (bodytemperature >= getSpeciesOrSynthTemp(HEAT_LEVEL_1)) - bodytemp.icon_state = "temp4" - else if (bodytemperature >= base_temperature + temp_step*3) - bodytemp.icon_state = "temp3" - else if (bodytemperature >= base_temperature + temp_step*2) - bodytemp.icon_state = "temp2" - else if (bodytemperature >= base_temperature + temp_step*1) - bodytemp.icon_state = "temp1" - else - bodytemp.icon_state = "temp0" - - else if (bodytemperature < base_temperature) - temp_step = (base_temperature - getSpeciesOrSynthTemp(COLD_LEVEL_1))/4 - - if (bodytemperature <= getSpeciesOrSynthTemp(COLD_LEVEL_1)) - bodytemp.icon_state = "temp-4" - else if (bodytemperature <= base_temperature - temp_step*3) - bodytemp.icon_state = "temp-3" - else if (bodytemperature <= base_temperature - temp_step*2) - bodytemp.icon_state = "temp-2" - else if (bodytemperature <= base_temperature - temp_step*1) - bodytemp.icon_state = "temp-1" - else - bodytemp.icon_state = "temp0" - return 1 - -/mob/living/carbon/human/handle_random_events() - // Puke if toxloss is too high - var/vomit_score = 0 - for(var/tag in list(BP_LIVER,BP_KIDNEYS)) - var/obj/item/organ/internal/I = internal_organs_by_name[tag] - if(I) - vomit_score += I.damage - else if (should_have_organ(tag)) - vomit_score += 45 - if(chem_effects[CE_TOXIN] || radiation) - vomit_score += 0.5 * getToxLoss() - if(chem_effects[CE_ALCOHOL_TOXIC]) - vomit_score += 10 * chem_effects[CE_ALCOHOL_TOXIC] - if(chem_effects[CE_ALCOHOL]) - vomit_score += 10 - if(stat != DEAD && vomit_score > 25 && prob(10)) - vomit(vomit_score, vomit_score/25) - - //0.1% chance of playing a scary sound to someone who's in complete darkness - if(isturf(loc) && rand(1,1000) == 1) - var/turf/T = loc - if(T.get_lumcount() <= LIGHTING_SOFT_THRESHOLD) - playsound_local(src,pick(GLOB.scarySounds),50, 1, -1) - - var/area/A = get_area(src) - if(client && world.time >= client.played + 600) - A.play_ambience(src) - if(stat == UNCONSCIOUS && world.time - l_move_time < 5 && prob(10)) - to_chat(src,"You feel like you're [pick("moving","flying","floating","falling","hovering")].") - -/mob/living/carbon/human/proc/handle_changeling() - if(mind && mind.changeling) - mind.changeling.regenerate() - -/mob/living/carbon/human/proc/handle_shock() - if(status_flags & GODMODE) return 0 //godmode - if(!can_feel_pain()) - shock_stage = 0 - return - - if(is_asystole()) - shock_stage = max(shock_stage + 1, 61) - var/traumatic_shock = get_shock() - if(traumatic_shock >= max(30, 0.8*shock_stage)) - shock_stage += 1 - else if (!is_asystole()) - shock_stage = min(shock_stage, 160) - var/recovery = 1 - if(traumatic_shock < 0.5 * shock_stage) //lower shock faster if pain is gone completely - recovery++ - if(traumatic_shock < 0.25 * shock_stage) - recovery++ - shock_stage = max(shock_stage - recovery, 0) - return - if(stat) return 0 - - if(shock_stage == 10) - // Please be very careful when calling custom_pain() from within code that relies on pain/trauma values. There's the - // possibility of a feedback loop from custom_pain() being called with a positive power, incrementing pain on a limb, - // which triggers this proc, which calls custom_pain(), etc. Make sure you call it with nohalloss = TRUE in these cases! - custom_pain("[pick("It hurts so much", "You really need some painkillers", "Dear god, the pain")]!", 10, nohalloss = TRUE) - - if(shock_stage >= 30) - if(shock_stage == 30) visible_message("[src] is having trouble keeping \his eyes open.") - if(prob(30)) - eye_blurry = max(2, eye_blurry) - stuttering = max(stuttering, 5) - - if(shock_stage == 40) - custom_pain("[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!", 40, nohalloss = TRUE) - if (shock_stage >= 60) - if(shock_stage == 60) visible_message("[src]'s body becomes limp.") - if (prob(2)) - custom_pain("[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!", shock_stage, nohalloss = TRUE) - Weaken(10) - - if(shock_stage >= 80) - if (prob(5)) - custom_pain("[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!", shock_stage, nohalloss = TRUE) - Weaken(20) - - if(shock_stage >= 120) - if (prob(2)) - custom_pain("[pick("You black out", "You feel like you could die any moment now", "You're about to lose consciousness")]!", shock_stage, nohalloss = TRUE) - Paralyse(5) - - if(shock_stage == 150) - visible_message("[src] can no longer stand, collapsing!") - Weaken(20) - - if(shock_stage >= 150) - Weaken(20) - -/* - Called by life(), instead of having the individual hud items update icons each tick and check for status changes - we only set those statuses and icons upon changes. Then those HUD items will simply add those pre-made images. - This proc below is only called when those HUD elements need to change as determined by the mobs hud_updateflag. -*/ - - -/mob/living/carbon/human/proc/handle_hud_list() - if (BITTEST(hud_updateflag, HEALTH_HUD) && hud_list[HEALTH_HUD]) - var/image/holder = hud_list[HEALTH_HUD] - if(stat == DEAD) - holder.icon_state = "0" // X_X - else if(is_asystole()) - holder.icon_state = "flatline" - else - holder.icon_state = "[pulse()]" - hud_list[HEALTH_HUD] = holder - - if (BITTEST(hud_updateflag, LIFE_HUD) && hud_list[LIFE_HUD]) - var/image/holder = hud_list[LIFE_HUD] - if(stat == DEAD) - holder.icon_state = "huddead" - else - holder.icon_state = "hudhealthy" - hud_list[LIFE_HUD] = holder - - if (BITTEST(hud_updateflag, STATUS_HUD) && hud_list[STATUS_HUD] && hud_list[STATUS_HUD_OOC]) - var/image/holder = hud_list[STATUS_HUD] - if(stat == DEAD) - holder.icon_state = "huddead" - else - holder.icon_state = "hudhealthy" - - var/image/holder2 = hud_list[STATUS_HUD_OOC] - if(stat == DEAD) - holder2.icon_state = "huddead" - else - holder2.icon_state = "hudhealthy" - - hud_list[STATUS_HUD] = holder - hud_list[STATUS_HUD_OOC] = holder2 - - if (BITTEST(hud_updateflag, ID_HUD) && hud_list[ID_HUD]) - var/image/holder = hud_list[ID_HUD] - holder.icon_state = "hudunknown" - if(wear_id) - var/obj/item/card/id/I = wear_id.GetIdCard() - if(I) - var/datum/job/J = SSjobs.get_by_title(I.GetJobName()) - if(J) - holder.icon_state = J.hud_icon - - hud_list[ID_HUD] = holder - - if (BITTEST(hud_updateflag, WANTED_HUD) && hud_list[WANTED_HUD]) - var/image/holder = hud_list[WANTED_HUD] - holder.icon_state = "hudblank" - var/perpname = name - if(wear_id) - var/obj/item/card/id/I = wear_id.GetIdCard() - if(I) - perpname = I.registered_name - - var/datum/computer_file/report/crew_record/E = get_crewmember_record(perpname) - if(E) - switch(E.get_criminalStatus()) - if("Arrest") - holder.icon_state = "hudwanted" - if("Incarcerated") - holder.icon_state = "hudprisoner" - if("Parolled") - holder.icon_state = "hudparolled" - if("Released") - holder.icon_state = "hudreleased" - hud_list[WANTED_HUD] = holder - - if ( BITTEST(hud_updateflag, IMPLOYAL_HUD) \ - || BITTEST(hud_updateflag, IMPCHEM_HUD) \ - || BITTEST(hud_updateflag, IMPTRACK_HUD)) - - var/image/holder1 = hud_list[IMPTRACK_HUD] - var/image/holder2 = hud_list[IMPLOYAL_HUD] - var/image/holder3 = hud_list[IMPCHEM_HUD] - - holder1.icon_state = "hudblank" - holder2.icon_state = "hudblank" - holder3.icon_state = "hudblank" - - for(var/obj/item/implant/I in src) - if(I.implanted) - if(istype(I,/obj/item/implant/tracking)) - holder1.icon_state = "hud_imp_tracking" - if(istype(I,/obj/item/implant/loyalty)) - holder2.icon_state = "hud_imp_loyal" - if(istype(I,/obj/item/implant/chem)) - holder3.icon_state = "hud_imp_chem" - - hud_list[IMPTRACK_HUD] = holder1 - hud_list[IMPLOYAL_HUD] = holder2 - hud_list[IMPCHEM_HUD] = holder3 - - if (BITTEST(hud_updateflag, SPECIALROLE_HUD)) - var/image/holder = hud_list[SPECIALROLE_HUD] - holder.icon_state = "hudblank" - if(mind && mind.special_role) - if(GLOB.hud_icon_reference[mind.special_role]) - holder.icon_state = GLOB.hud_icon_reference[mind.special_role] - else - holder.icon_state = "hudsyndicate" - hud_list[SPECIALROLE_HUD] = holder - hud_updateflag = 0 - -/mob/living/carbon/human/handle_stunned() - if(!can_feel_pain()) - stunned = 0 - return 0 - return ..() - -/mob/living/carbon/human/handle_fire() - if(..()) - return - - var/burn_temperature = fire_burn_temperature() - var/thermal_protection = get_heat_protection(burn_temperature) - - if (thermal_protection < 1 && bodytemperature < burn_temperature) - bodytemperature += round(BODYTEMP_HEATING_MAX*(1-thermal_protection), 1) - - var/species_heat_mod = 1 - - var/protected_limbs = get_heat_protection_flags(burn_temperature) - - - if(species) - if(burn_temperature < species.heat_level_2) - species_heat_mod = 0.5 - else if(burn_temperature < species.heat_level_3) - species_heat_mod = 0.75 - - burn_temperature -= species.heat_level_1 - - if(burn_temperature < 1) - return - - for(var/obj/item/organ/external/E in organs) - if(!(E.body_part & protected_limbs) && prob(20)) - E.take_external_damage(burn = round(species_heat_mod * log(10, (burn_temperature + 10)), 0.1), used_weapon = "fire") - -/mob/living/carbon/human/rejuvenate() - restore_blood() - full_prosthetic = null - shock_stage = 0 - ..() - adjust_stamina(100) - -/mob/living/carbon/human/reset_view(atom/A) - ..() - if(machine_visual && machine_visual != A) - machine_visual.remove_visual(src) - if(eyeobj) - eyeobj.remove_visual(src) - -/mob/living/carbon/human/handle_vision() - if(client) - client.screen.Remove(GLOB.global_hud.nvg, GLOB.global_hud.thermal, GLOB.global_hud.meson, GLOB.global_hud.science) - if(machine) - var/viewflags = machine.check_eye(src) - if(viewflags < 0) - reset_view(null, 0) - else if(viewflags) - set_sight(sight|viewflags) - else if(eyeobj) - if(eyeobj.owner != src) - reset_view(null) - else - var/isRemoteObserve = 0 - if(z_eye) - isRemoteObserve = 1 - else if((mRemote in mutations) && remoteview_target) - if(remoteview_target.stat == CONSCIOUS) - isRemoteObserve = 1 - if(!isRemoteObserve && client && !client.adminobs) - remoteview_target = null - reset_view(null, 0) - - update_equipment_vision() - species.handle_vision(src) - -/mob/living/carbon/human/update_living_sight() - ..() - if((CE_THIRDEYE in chem_effects) || (MUTATION_XRAY in mutations)) - set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm deleted file mode 100644 index ea44d6d16805..000000000000 --- a/code/modules/mob/living/carbon/human/login.dm +++ /dev/null @@ -1,5 +0,0 @@ -/mob/living/carbon/human/Login() - ..() - update_hud() - if(species) species.handle_login_special(src) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/logout.dm b/code/modules/mob/living/carbon/human/logout.dm deleted file mode 100644 index f449ce991ad5..000000000000 --- a/code/modules/mob/living/carbon/human/logout.dm +++ /dev/null @@ -1,4 +0,0 @@ -/mob/living/carbon/human/Logout() - ..() - if(species) species.handle_logout_special(src) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/npcs.dm b/code/modules/mob/living/carbon/human/npcs.dm deleted file mode 100644 index c6d2051b257c..000000000000 --- a/code/modules/mob/living/carbon/human/npcs.dm +++ /dev/null @@ -1,46 +0,0 @@ -/mob/living/carbon/human/monkey/punpun/Initialize() - . = ..() - name = "Pun Pun" - real_name = name - var/obj/item/clothing/C - if(prob(50)) - C = new /obj/item/clothing/under/punpun(src) - equip_to_appropriate_slot(C) - else - C = new /obj/item/clothing/under/punpants(src) - C.attach_accessory(null, new/obj/item/clothing/accessory/toggleable/hawaii/random(src)) - equip_to_appropriate_slot(C) - if(prob(10)) - C = new/obj/item/clothing/head/collectable/petehat(src) - equip_to_appropriate_slot(C) - -/decl/hierarchy/outfit/blank_subject - name = "Test Subject" - uniform = /obj/item/clothing/under/color/white - shoes = /obj/item/clothing/shoes/color/white - head = /obj/item/clothing/head/helmet/facecover - mask = /obj/item/clothing/mask/muzzle - suit = /obj/item/clothing/suit/straight_jacket - -/decl/hierarchy/outfit/blank_subject/post_equip(mob/living/carbon/human/H) - ..() - var/obj/item/clothing/under/color/white/C = locate() in H - if(C) - C.has_sensor = SUIT_LOCKED_SENSORS - C.sensor_mode = SUIT_SENSOR_OFF - -/mob/living/carbon/human/blank/Initialize(mapload) - . = ..(mapload, "Vat-Grown Human") - -/mob/living/carbon/human/blank/Initialize() - . = ..() - var/number = "[pick(possible_changeling_IDs)]-[rand(1,30)]" - fully_replace_character_name("Subject [number]") - var/decl/hierarchy/outfit/outfit = outfit_by_type(/decl/hierarchy/outfit/blank_subject) - outfit.equip(src) - var/obj/item/clothing/head/helmet/facecover/F = locate() in src - if(F) - F.SetName("[F.name] ([number])") - -/mob/living/carbon/human/blank/ssd_check() - return FALSE diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm deleted file mode 100644 index 05e77ba400f5..000000000000 --- a/code/modules/mob/living/carbon/human/say.dm +++ /dev/null @@ -1,242 +0,0 @@ -/mob/living/carbon/human/say(var/message, var/decl/language/speaking = null, whispering) - if(name != GetVoice()) - if(get_id_name("Unknown") == GetVoice()) - SetName(get_id_name("Unknown")) - - //parse the language code and consume it - if(!speaking) - speaking = parse_language(message) - if (speaking) - message = copytext(message,2+length(speaking.key)) - else - speaking = get_any_good_language(set_default=TRUE) - if (!speaking) - to_chat(src, SPAN_WARNING("You don't know a language and cannot speak.")) - emote("custom", AUDIBLE_MESSAGE, "[pick("grunts", "babbles", "gibbers", "jabbers", "burbles")] aimlessly.") - return - - if(has_chem_effect(CE_VOICELOSS, 1)) - whispering = TRUE - - message = sanitize(message) - var/obj/item/organ/internal/voicebox/vox = locate() in internal_organs - var/snowflake_speak = (speaking && (speaking.flags & (NONVERBAL|SIGNLANG))) || (vox && vox.is_usable() && vox.assists_languages[speaking]) - if(!isSynthetic() && need_breathe() && failed_last_breath && !snowflake_speak) - var/obj/item/organ/internal/lungs/L = internal_organs_by_name[species.breathing_organ] - if(!L || L.breath_fail_ratio > 0.9) - if(L && world.time < L.last_successful_breath + 2 MINUTES) //if we're in grace suffocation period, give it up for last words - to_chat(src, "You use your remaining air to say something!") - L.last_successful_breath = world.time - 2 MINUTES - return ..(message, speaking = speaking) - - to_chat(src, "You don't have enough air[L ? " in [L]" : ""] to make a sound!") - return - else if(L.breath_fail_ratio > 0.7) - whisper_say(length(message) > 5 ? stars(message) : message, speaking) - else if(L.breath_fail_ratio > 0.4 && length(message) > 10) - whisper_say(message, speaking) - else - return ..(message, speaking = speaking, whispering = whispering) - - -/mob/living/carbon/human/proc/forcesay(list/append) - if(stat == CONSCIOUS) - if(client) - var/virgin = 1 //has the text been modified yet? - var/temp = winget(client, "input", "text") - if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means - var/main_key = get_prefix_key(/decl/prefix/radio_main_channel) - temp = replacetext(temp, main_key, "") //general radio - - var/channel_key = get_prefix_key(/decl/prefix/radio_channel_selection) - if(findtext(trim_left(temp), channel_key, 6, 7)) //dept radio - temp = copytext(trim_left(temp), 8) - virgin = 0 - - if(virgin) - temp = copytext(trim_left(temp), 6) //normal speech - virgin = 0 - - while(findtext(trim_left(temp), channel_key, 1, 2)) //dept radio again (necessary) - temp = copytext(trim_left(temp), 3) - - var/custom_emote_key = get_prefix_key(/decl/prefix/custom_emote) - if(findtext(temp, custom_emote_key, 1, 2)) //emotes - return - temp = copytext(trim_left(temp), 1, rand(5,8)) - - var/trimmed = trim_left(temp) - if(length(trimmed)) - if(append) - temp += pick(append) - - say(temp) - winset(client, "input", "text=[null]") - -/mob/living/carbon/human/say_understands(var/mob/other,var/decl/language/speaking = null) - - if(species.can_understand(other)) - return 1 - - //These only pertain to common. Languages are handled by mob/say_understands() - if (!speaking) - if (istype(other, /mob/living/silicon)) - return 1 - if (istype(other, /mob/living/carbon/brain)) - return 1 - if (istype(other, /mob/living/carbon/slime)) - return 1 - - //This is already covered by mob/say_understands() - //if (istype(other, /mob/living/simple_animal)) - // if((other.universal_speak && !speaking) || src.universal_speak || src.universal_understand) - // return 1 - // return 0 - - return ..() - -/mob/living/carbon/human/GetVoice() - - var/voice_sub - if(istype(back,/obj/item/rig)) - var/obj/item/rig/rig = back - // todo: fix this shit - if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice) - voice_sub = rig.speech.voice_holder.voice - - if(!voice_sub) - - var/list/check_gear = list(wear_mask, head) - if(wearing_rig) - var/datum/extension/armor/rig/armor_datum = get_extension(wearing_rig, /datum/extension/armor) - if(istype(armor_datum) && armor_datum.sealed && wearing_rig.helmet == head) - check_gear |= wearing_rig - - for(var/obj/item/gear in check_gear) - if(!gear) - continue - var/obj/item/voice_changer/changer = locate() in gear - if(changer && changer.active && changer.voice) - voice_sub = changer.voice - - if(voice_sub) - return voice_sub - if(mind && mind.changeling && mind.changeling.mimicing) - return mind.changeling.mimicing - return real_name - -/mob/living/carbon/human/say_quote(var/message, var/decl/language/speaking = null) - var/verb = "says" - var/ending = copytext(message, length(message)) - - if(speaking) - verb = speaking.get_spoken_verb(ending) - else - if(ending == "!") - verb=pick("exclaims","shouts","yells") - else if(ending == "?") - verb="asks" - - return verb - -/mob/living/carbon/human/handle_speech_problems(var/list/message_data) - if(silent || (sdisabilities & MUTED)) - message_data[1] = "" - . = 1 - - else if(istype(wear_mask, /obj/item/clothing/mask)) - var/obj/item/clothing/mask/M = wear_mask - if(M.voicechange) - message_data[1] = pick(M.say_messages) - message_data[2] = pick(M.say_verbs) - . = 1 - - else - . = ..(message_data) - -/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - switch(message_mode) - if("intercom") - if(!src.restrained()) - for(var/obj/item/radio/intercom/I in view(1)) - I.talk_into(src, message, null, verb, speaking) - I.add_fingerprint(src) - used_radios += I - if("headset") - if(l_ear && istype(l_ear,/obj/item/radio)) - var/obj/item/radio/R = l_ear - R.talk_into(src,message,null,verb,speaking) - used_radios += l_ear - else if(r_ear && istype(r_ear,/obj/item/radio)) - var/obj/item/radio/R = r_ear - R.talk_into(src,message,null,verb,speaking) - used_radios += r_ear - if("right ear") - var/obj/item/radio/R - var/has_radio = 0 - if(r_ear && istype(r_ear,/obj/item/radio)) - R = r_ear - has_radio = 1 - if(r_hand && istype(r_hand, /obj/item/radio)) - R = r_hand - has_radio = 1 - if(has_radio) - R.talk_into(src,message,null,verb,speaking) - used_radios += R - if("left ear") - var/obj/item/radio/R - var/has_radio = 0 - if(l_ear && istype(l_ear,/obj/item/radio)) - R = l_ear - has_radio = 1 - if(l_hand && istype(l_hand,/obj/item/radio)) - R = l_hand - has_radio = 1 - if(has_radio) - R.talk_into(src,message,null,verb,speaking) - used_radios += R - if("whisper") //It's going to get sanitized again immediately, so decode. - whisper_say(html_decode(message), speaking, alt_name) - return 1 - else - if(message_mode) - if(l_ear && istype(l_ear,/obj/item/radio)) - l_ear.talk_into(src,message, message_mode, verb, speaking) - used_radios += l_ear - else if(r_ear && istype(r_ear,/obj/item/radio)) - r_ear.talk_into(src,message, message_mode, verb, speaking) - used_radios += r_ear - -/mob/living/carbon/human/handle_speech_sound() - if(species.speech_sounds && prob(species.speech_chance)) - var/list/returns[2] - var/sound_to_play = species.speech_sounds - if(islist(species.speech_sounds)) - sound_to_play = species.speech_sounds[gender] || species.speech_sounds - returns[1] = sound(pick(sound_to_play)) - returns[2] = 50 - return returns - return ..() - -/mob/living/carbon/human/can_speak(decl/language/speaking) - if(ispath(speaking, /decl/language)) - speaking = decls_repository.get_decl(speaking) - if(species && speaking && (speaking.name in species.assisted_langs)) - for(var/obj/item/organ/internal/voicebox/I in src.internal_organs) - if(I.is_usable() && I.assists_languages[speaking]) - return TRUE - return FALSE - . = ..() - -/mob/living/carbon/human/parse_language(var/message) - var/prefix = copytext(message,1,2) - if(length(message) >= 1 && prefix == get_prefix_key(/decl/prefix/audible_emote)) - return decls_repository.get_decl(/decl/language/noise) - - if(length(message) >= 2 && is_language_prefix(prefix)) - var/language_prefix = lowertext(copytext(message, 2 ,3)) - var/decl/language/L = SSlore.get_language_by_key(language_prefix) - if (can_speak(L)) - return L - - return null diff --git a/code/modules/mob/living/carbon/human/stripping.dm b/code/modules/mob/living/carbon/human/stripping.dm deleted file mode 100644 index adfab1e4e669..000000000000 --- a/code/modules/mob/living/carbon/human/stripping.dm +++ /dev/null @@ -1,174 +0,0 @@ -/mob/living/carbon/human/proc/handle_strip(var/slot_to_strip_text,var/mob/living/user,var/obj/item/clothing/holder) - if(!slot_to_strip_text || !istype(user)) - return - - if(user.incapacitated() || !user.Adjacent(src)) - show_browser(user, null, "window=mob[src.name]") - return TRUE - - // Are we placing or stripping? - var/stripping = FALSE - var/obj/item/held = user.get_active_hand() - if(!istype(held) || is_robot_module(held)) - stripping = TRUE - - switch(slot_to_strip_text) - // Handle things that are part of this interface but not removing/replacing a given item. - if("pockets") - if(stripping) - visible_message("\The [user] is trying to empty [src]'s pockets!") - if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) - empty_pockets(user) - else - //should it be possible to discreetly slip something into someone's pockets? - visible_message("\The [user] is trying to stuff \a [held] into [src]'s pocket!") - if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) - place_in_pockets(held, user) - return - if("sensors") - visible_message("\The [user] is trying to set \the [src]'s sensors!") - if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) - toggle_sensors(user) - return - if ("lock_sensors") - if (!istype(w_uniform, /obj/item/clothing/under)) - return - var/obj/item/clothing/under/subject_uniform = w_uniform - visible_message(SPAN_DANGER("\The [user] is trying to [subject_uniform.has_sensor == SUIT_LOCKED_SENSORS ? "un" : ""]lock \the [src]'s sensors!")) - if (do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) - if (subject_uniform != w_uniform) - to_chat(user, SPAN_WARNING("\The [src] is not wearing \the [subject_uniform] anymore.")) - return - if (!subject_uniform.has_sensor) - to_chat(user, SPAN_WARNING("\The [subject_uniform] has no sensors to lock.")) - return - var/obj/item/multitool/user_multitool = user.get_multitool() - if (!istype(user_multitool)) - to_chat(user, SPAN_WARNING("You need a multitool to lock \the [subject_uniform]'s sensors.")) - return - subject_uniform.has_sensor = subject_uniform.has_sensor == SUIT_LOCKED_SENSORS ? SUIT_HAS_SENSORS : SUIT_LOCKED_SENSORS - visible_message(SPAN_NOTICE("\The [user] [subject_uniform.has_sensor == SUIT_LOCKED_SENSORS ? "" : "un"]locks \the [subject_uniform]'s suit sensor controls."), range = 2) - return - if("internals") - visible_message("\The [usr] is trying to set \the [src]'s internals!") - if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) - toggle_internals(user) - return - if("tie") - if(!istype(holder) || !holder.accessories.len) - return - var/obj/item/clothing/accessory/A = holder.accessories[1] - if(holder.accessories.len > 1) - A = input("Select an accessory to remove from [holder]") as null|anything in holder.accessories - if(!istype(A)) - return - visible_message("\The [user] is trying to remove \the [src]'s [A.name]!") - - if(!do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) - return - - if(!A || holder.loc != src || !(A in holder.accessories)) - return - - admin_attack_log(user, src, "Stripped \an [A] from \the [holder].", "Was stripped of \an [A] from \the [holder].", "stripped \an [A] from \the [holder] of") - holder.remove_accessory(user,A) - return - else - var/obj/item/located_item = locate(slot_to_strip_text) in src - if(isunderwear(located_item)) - var/obj/item/underwear/UW = located_item - if(UW.DelayedRemoveUnderwear(user, src)) - user.put_in_active_hand(UW) - return - - var/obj/item/target_slot = get_equipped_item(text2num(slot_to_strip_text)) - if(stripping) - if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here? - return - if(!target_slot.mob_can_unequip(src, text2num(slot_to_strip_text), disable_warning=1)) - to_chat(user, "You cannot remove \the [src]'s [target_slot.name].") - return - - visible_message("\The [user] is trying to remove \the [src]'s [target_slot.name]!") - else - visible_message("\The [user] is trying to put \a [held] on \the [src]!") - - if(!do_mob(user, src, HUMAN_STRIP_DELAY)) - return - - if(stripping) - if(unEquip(target_slot)) - admin_attack_log(user, src, "Stripped \a [target_slot]", "Was stripped of \a [target_slot].", "stripped \a [target_slot] from") - user.put_in_active_hand(target_slot) - else - admin_attack_log(user, src, "Attempted to strip \a [target_slot]", "Target of a failed strip of \a [target_slot].", "attempted to strip \a [target_slot] from") - else if(user.unEquip(held)) - var/obj/item/clothing/C = get_equipped_item(text2num(slot_to_strip_text)) - if(istype(C) && C.can_attach_accessory(held)) - C.attach_accessory(user, held) - else if(!equip_to_slot_if_possible(held, text2num(slot_to_strip_text), del_on_fail=0, disable_warning=1, redraw_mob=1)) - user.put_in_active_hand(held) - -// Empty out everything in the target's pockets. -/mob/living/carbon/human/proc/empty_pockets(var/mob/living/user) - if(!r_store && !l_store) - to_chat(user, "\The [src] has nothing in their pockets.") - return - if(r_store) - unEquip(r_store) - if(l_store) - unEquip(l_store) - visible_message("\The [user] empties [src]'s pockets!") - -/mob/living/carbon/human/proc/place_in_pockets(obj/item/I, var/mob/living/user) - if(!user.unEquip(I)) - return - if(!r_store) - if(equip_to_slot_if_possible(I, slot_r_store, del_on_fail=0, disable_warning=1, redraw_mob=1)) - return - if(!l_store) - if(equip_to_slot_if_possible(I, slot_l_store, del_on_fail=0, disable_warning=1, redraw_mob=1)) - return - to_chat(user, "You are unable to place [I] in [src]'s pockets.") - user.put_in_active_hand(I) - -// Modify the current target sensor level. -/mob/living/carbon/human/proc/toggle_sensors(var/mob/living/user) - var/obj/item/clothing/under/suit = w_uniform - if(!suit) - to_chat(user, "\The [src] is not wearing a suit with sensors.") - return - if (suit.has_sensor >= 2) - to_chat(user, "\The [src]'s suit sensor controls are locked.") - return - - admin_attack_log(user, src, "Toggled their suit sensors.", "Toggled their suit sensors.", "toggled the suit sensors of") - suit.set_sensors(user) - -// Set internals on or off. -/mob/living/carbon/human/proc/toggle_internals(var/mob/living/user) - if(internal) - visible_message("\The [user] disables \the [src]'s internals!") - internal.add_fingerprint(user) - set_internals(null) - return - else - // Check for airtight mask/helmet. - if(!(wear_mask && wear_mask.item_flags & ITEM_FLAG_AIRTIGHT)) - if(!(head && head.item_flags & ITEM_FLAG_AIRTIGHT)) - to_chat(user, "\The [src] does not have a suitable mask or helmet.") - return - - // Find an internal source. - if(istype(back, /obj/item/tank)) - set_internals(back) - else if(istype(s_store, /obj/item/tank)) - set_internals(s_store) - else if(istype(belt, /obj/item/tank)) - set_internals(belt) - else - to_chat(user, "You could not find a suitable tank!") - return - - visible_message("\The [src] is now running on internals!") - internal.add_fingerprint(user) diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm deleted file mode 100644 index 45d27c1a15fb..000000000000 --- a/code/modules/mob/living/carbon/human/unarmed_attack.dm +++ /dev/null @@ -1,331 +0,0 @@ -var/global/list/sparring_attack_cache = list() - -//Species unarmed attacks -/decl/natural_attack - var/attack_verb = list("attacks") // Empty hand hurt intent verb. - var/attack_noun = list("fist") - var/damage = 0 // Extra empty hand attack damage. - var/attack_sound = "punch" - var/miss_sound = 'sound/weapons/punchmiss.ogg' - var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent. - var/sharp = 0 - var/edge = 0 - var/delay = 0 - var/deal_halloss - var/sparring_variant_type = /decl/natural_attack/light_strike - var/eye_attack_text - var/eye_attack_text_victim - var/attack_name = "fist" - var/list/usable_with_limbs = list(BP_L_HAND, BP_R_HAND) - var/is_starting_default = FALSE - -/decl/natural_attack/proc/get_damage_type() - if(deal_halloss) - return PAIN - return BRUTE - -/decl/natural_attack/proc/padded_by_user_gear(var/mob/living/carbon/human/user) - if(istype(user) && length(usable_with_limbs)) - for(var/bp in usable_with_limbs) - var/obj/item/gear = user.get_covering_equipped_item_by_zone(bp) - if(istype(gear) && (gear.item_flags & ITEM_FLAG_PADDED)) - return TRUE - return FALSE - -/decl/natural_attack/proc/resolve_to_soft_variant(var/mob/living/carbon/human/user) - . = src - if(istype(user) && (user.pulling_punches || padded_by_user_gear(user))) - var/decl/natural_attack/soft_variant = get_sparring_variant() - if(soft_variant) - . = soft_variant - -/decl/natural_attack/proc/get_sparring_variant() - return sparring_variant_type && decls_repository.get_decl(sparring_variant_type) - -/decl/natural_attack/proc/is_usable(var/mob/living/carbon/human/user, var/mob/target, var/zone) - if(user.restrained()) - return 0 - - // Check if they have a functioning hand. - var/obj/item/organ/external/E = user.organs_by_name[BP_L_HAND] - if(E && !E.is_stump()) - return 1 - - E = user.organs_by_name[BP_R_HAND] - if(E && !E.is_stump()) - return 1 - - return 0 - -/decl/natural_attack/proc/get_unarmed_damage() - return damage - -/decl/natural_attack/proc/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/attack_damage,var/zone) - - if(target.stat == DEAD) - return - - var/stun_chance = rand(0, 100) - var/armour = target.get_blocked_ratio(zone, BRUTE, damage = attack_damage) - - if(attack_damage >= 5 && armour < 1 && !(target == user) && stun_chance <= attack_damage * 5) // 25% standard chance - switch(zone) // strong punches can have effects depending on where they hit - if(BP_HEAD, BP_EYES, BP_MOUTH) - // Induce blurriness - target.visible_message("[target] looks momentarily disoriented.", "You see stars.") - target.apply_effect(attack_damage*2, EYE_BLUR, armour) - if(BP_L_ARM, BP_L_HAND) - if (target.l_hand) - // Disarm left hand - //Urist McAssistant dropped the macguffin with a scream just sounds odd. - target.visible_message("\The [target.l_hand] was knocked right out of [target]'s grasp!") - target.drop_l_hand() - if(BP_R_ARM, BP_R_HAND) - if (target.r_hand) - // Disarm right hand - target.visible_message("\The [target.r_hand] was knocked right out of [target]'s grasp!") - target.drop_r_hand() - if(BP_CHEST) - if(!target.lying) - var/turf/T = get_step(get_turf(target), get_dir(get_turf(user), get_turf(target))) - if(!T.density) - step(target, get_dir(get_turf(user), get_turf(target))) - target.visible_message("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]") - if(prob(50)) - target.set_dir(GLOB.reverse_dir[target.dir]) - target.apply_effect(attack_damage * 0.4, WEAKEN, armour) - if(BP_GROIN) - target.visible_message("[target] looks like \he is in pain!", "[(target.gender=="female") ? "Oh god that hurt!" : "Oh no, not your[pick("testicles", "crown jewels", "clockweights", "family jewels", "marbles", "bean bags", "teabags", "sweetmeats", "goolies")]!"]") - target.apply_effects(stutter = attack_damage * 2, agony = attack_damage* 3, blocked = armour) - if(BP_L_LEG, BP_L_FOOT, BP_R_LEG, BP_R_FOOT) - if(!target.lying) - target.visible_message("[target] gives way slightly.") - target.apply_effect(attack_damage*3, PAIN, armour) - else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage * 5 >= 100) && armour < 1) // Chance to get the usual throwdown as well (25% standard chance) - if(!target.lying) - target.visible_message("[target] [pick("slumps", "falls", "drops")] down to the ground!") - else - target.visible_message("[target] has been weakened!") - target.apply_effect(3, WEAKEN, armour * 100) - - var/obj/item/clothing/C = target.get_covering_equipped_item_by_zone(zone) - if(istype(C) && prob(10)) - C.leave_evidence(user) - -/decl/natural_attack/proc/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - var/msg = "\The [user] [pick(attack_verb)] \the [target]" - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) - if(affecting) - msg = "[msg] in the [affecting.name]" - if(islist(attack_noun) && length(attack_noun)) - msg = "[msg] with their [pick(attack_noun)]" - if(msg) - user.visible_message(SPAN_DANGER("[msg]!")) - playsound(user.loc, attack_sound, 25, 1, -1) - -/decl/natural_attack/proc/handle_eye_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target) - var/obj/item/organ/internal/eyes/eyes = target.internal_organs_by_name[BP_EYES] - if(eyes) - eyes.take_internal_damage(rand(3,4), 1) - user.visible_message("[user] presses \his [eye_attack_text] into [target]'s [eyes.name]!") - var/eye_pain = eyes.can_feel_pain() - to_chat(target, "You experience[(eye_pain) ? "" : " immense pain as you feel" ] [eye_attack_text_victim] being pressed into your [eyes.name][(eye_pain)? "." : "!"]") - return - user.visible_message("[user] attempts to press \his [eye_attack_text] into [target]'s eyes, but they don't have any!") - -/decl/natural_attack/proc/damage_flags() - return (src.sharp? DAM_SHARP : 0)|(src.edge? DAM_EDGE : 0) - -/decl/natural_attack/bite - attack_verb = list("bit") - attack_noun = list("mouth") - attack_sound = 'sound/weapons/bite.ogg' - shredding = 0 - damage = 0 - sharp = 0 - edge = 0 - attack_name = "bite" - usable_with_limbs = list(BP_HEAD) - -/decl/natural_attack/bite/sharp - attack_verb = list("bit", "chomped") - sharp = 1 - edge = 1 - -/decl/natural_attack/bite/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) - - if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) - return 0 - for(var/obj/item/clothing/C in list(user.wear_mask, user.head, user.wear_suit)) - if(C && (C.body_parts_covered & FACE) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) - return 0 //prevent biting through a space helmet or similar - if (user == target && (zone == BP_HEAD || zone == BP_EYES || zone == BP_MOUTH)) - return 0 //how do you bite yourself in the head? - return 1 - -/decl/natural_attack/punch - attack_verb = list("punched") - attack_noun = list("fist") - eye_attack_text = "fingers" - eye_attack_text_victim = "digits" - damage = 0 - attack_name = "punch" - sparring_variant_type = /decl/natural_attack/light_strike/punch - is_starting_default = TRUE - -/decl/natural_attack/punch/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) - if(!affecting) - return ..() - - var/organ = affecting.name - - attack_damage = Clamp(attack_damage, 1, 5) // We expect damage input of 1 to 5 for this proc. But we leave this check juuust in case. - - if(target == user) - user.visible_message("[user] [pick(attack_verb)] \himself in the [organ]!") - return 0 - - target.update_personal_goal(/datum/goal/achievement/fistfight, TRUE) - user.update_personal_goal(/datum/goal/achievement/fistfight, TRUE) - - if(!target.lying) - switch(zone) - if(BP_HEAD, BP_MOUTH, BP_EYES) - // ----- HEAD ----- // - switch(attack_damage) - if(1 to 2) - user.visible_message("[user] slapped [target] across \his cheek!") - if(3 to 4) - user.visible_message(pick( - 80; "[user] [pick(attack_verb)] [target] in the head!", - 20; "[user] struck [target] in the head[pick("", " with a closed fist")]!", - 50; "[user] threw a hook against [target]'s head!" - )) - if(5) - user.visible_message(pick( - 10; "[user] gave [target] a solid slap across \his face!", - 90; "[user] smashed \his [pick(attack_noun)] into [target]'s [pick("[organ]", "face", "jaw")]!" - )) - else - // ----- BODY ----- // - switch(attack_damage) - if(1 to 2) user.visible_message("[user] threw a glancing punch at [target]'s [organ]!") - if(1 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ]!") - if(5) user.visible_message("[user] smashed \his [pick(attack_noun)] into [target]'s [organ]!") - else - user.visible_message("[user] [pick("punched", "threw a punch at", "struck", "slammed their [pick(attack_noun)] into")] [target]'s [organ]!") //why do we have a separate set of verbs for lying targets? - -/decl/natural_attack/kick - attack_verb = list("struck") - attack_noun = list("foot", "knee") - attack_sound = "swing_hit" - damage = 0 - attack_name = "kick" - usable_with_limbs = list(BP_L_FOOT, BP_R_FOOT) - sparring_variant_type = /decl/natural_attack/light_strike/kick - -/decl/natural_attack/kick/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) - if(!(zone in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT, BP_GROIN))) - return 0 - - var/obj/item/organ/external/E = user.organs_by_name[BP_L_FOOT] - if(E && !E.is_stump()) - return 1 - - E = user.organs_by_name[BP_R_FOOT] - if(E && !E.is_stump()) - return 1 - - return 0 - -/decl/natural_attack/kick/get_unarmed_damage(var/mob/living/carbon/human/user) - var/obj/item/clothing/shoes = user.shoes - if(!istype(shoes)) - return damage - return damage + (shoes ? shoes.force : 0) - -/decl/natural_attack/kick/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) - if(!affecting) - return ..() - - var/organ = affecting.name - attack_damage = Clamp(attack_damage, 1, 5) - switch(attack_damage) - if(1 to 2) user.visible_message("[user] threw [target] a glancing [pick(attack_noun)] to the [organ]!") //it's not that they're kicking lightly, it's that the kick didn't quite connect - if(3 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ]!") - if(5) user.visible_message("[user] landed a strong [pick(attack_noun)] against [target]'s [organ]!") - -/decl/natural_attack/stomp - attack_verb = list("stomped on") - attack_noun = list("foot") - attack_sound = "swing_hit" - damage = 0 - attack_name = "stomp" - usable_with_limbs = list(BP_L_FOOT, BP_R_FOOT) - -/decl/natural_attack/stomp/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) - if(!istype(target)) - return 0 - - if (!user.lying && (target.lying || (zone in list(BP_L_FOOT, BP_R_FOOT)))) - if((user in target.grabbed_by) && target.lying) - return 0 - var/obj/item/organ/external/E = user.organs_by_name[BP_L_FOOT] - if(E && !E.is_stump()) - return 1 - - E = user.organs_by_name[BP_R_FOOT] - if(E && !E.is_stump()) - return 1 - - return 0 - -/decl/natural_attack/stomp/get_unarmed_damage(var/mob/living/carbon/human/user) - var/obj/item/clothing/shoes = user.shoes - return damage + (shoes ? shoes.force : 0) - -/decl/natural_attack/stomp/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) - if(!affecting) - return ..() - - var/organ = affecting.name - var/obj/item/clothing/shoes = user.shoes - attack_damage = Clamp(attack_damage, 1, 5) - - var/shoe_text = shoes ? copytext(shoes.name, 1, -1) : "foot" - switch(attack_damage) - if(1 to 4) - user.visible_message(pick( - "[user] stomped on [target]'s [organ][pick("", "with their [shoe_text]")]!", - "[user] stomped \his [shoe_text] down onto [target]'s [organ]!")) - if(5) - user.visible_message(pick( - "[user] stomped down hard onto [target]'s [organ][pick("", "with their [shoe_text]")]!", - "[user] slammed \his [shoe_text] down onto [target]'s [organ]!")) - -/decl/natural_attack/light_strike - deal_halloss = 3 - attack_noun = list("limb") - attack_verb = list("tapped", "lightly struck") - shredding = 0 - damage = 0 - sharp = 0 - edge = 0 - attack_name = "light strike" - attack_sound = "light_strike" - -/decl/natural_attack/light_strike/punch - attack_name = "light punch" - attack_noun = list("fist") - usable_with_limbs = list(BP_L_HAND, BP_R_HAND) - -/decl/natural_attack/light_strike/kick - attack_name = "light kick" - attack_noun = list("foot") - usable_with_limbs = list(BP_L_FOOT, BP_R_FOOT) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm deleted file mode 100644 index 27ae650b8ccd..000000000000 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ /dev/null @@ -1,854 +0,0 @@ -/* - Global associative list for caching humanoid icons. - Index format m or f, followed by a string of 0 and 1 to represent bodyparts followed by husk fat hulk skeleton 1 or 0. - TODO: Proper documentation - icon_key is [species.get_icon_cache_uid(src)][g][husk][fat][hulk][skeleton][skin_tone] -*/ -var/global/list/human_icon_cache = list() -var/global/list/tail_icon_cache = list() //key is [species.get_icon_cache_uid(src)][skin_colour] -var/global/list/light_overlay_cache = list() - -/proc/overlay_image(icon,icon_state,color,flags) - var/image/ret = image(icon,icon_state) - ret.color = color - ret.appearance_flags = flags - return ret - - /////////////////////// - //UPDATE_ICONS SYSTEM// - /////////////////////// -/* -Calling this a system is perhaps a bit trumped up. It is essentially update_clothing dismantled into its -core parts. The key difference is that when we generate overlays we do not generate either lying or standing -versions. Instead, we generate both and store them in two fixed-length lists, both using the same list-index -(The indexes are in update_icons.dm): Each list for humans is (at the time of writing) of length 19. -This will hopefully be reduced as the system is refined. - - var/overlays_lying[19] //For the lying down stance - var/overlays_standing[19] //For the standing stance - -When we call update_icons, the 'lying' variable is checked and then the appropriate list is assigned to our overlays! -That in itself uses a tiny bit more memory (no more than all the ridiculous lists the game has already mind you). - -On the other-hand, it should be very CPU cheap in comparison to the old system. -In the old system, we updated all our overlays every life() call, even if we were standing still inside a crate! -or dead!. 25ish overlays, all generated from scratch every second for every xeno/human/monkey and then applied. -More often than not update_clothing was being called a few times in addition to that! CPU was not the only issue, -all those icons had to be sent to every client. So really the cost was extremely cumulative. To the point where -update_clothing would frequently appear in the top 10 most CPU intensive procs during profiling. - -Another feature of this new system is that our lists are indexed. This means we can update specific overlays! -So we only regenerate icons when we need them to be updated! This is the main saving for this system. - -In practice this means that: - everytime you fall over, we just switch between precompiled lists. Which is fast and cheap. - Everytime you do something minor like take a pen out of your pocket, we only update the in-hand overlay - etc... - - -There are several things that need to be remembered: - -> Whenever we do something that should cause an overlay to update (which doesn't use standard procs - ( i.e. you do something like l_hand = /obj/item/something new(src) ) - You will need to call the relevant update_inv_* proc: - update_inv_head() - update_inv_wear_suit() - update_inv_gloves() - update_inv_shoes() - update_inv_w_uniform() - update_inv_glasse() - update_inv_l_hand() - update_inv_r_hand() - update_inv_belt() - update_inv_wear_id() - update_inv_ears() - update_inv_s_store() - update_inv_pockets() - update_inv_back() - update_inv_handcuffed() - update_inv_wear_mask() - - All of these are named after the variable they update from. They are defined at the mob/ level like - update_clothing was, so you won't cause undefined proc runtimes with usr.update_inv_wear_id() if the usr is a - slime etc. Instead, it'll just return without doing any work. So no harm in calling it for slimes and such. - - -> There are also these special cases: - update_mutations() //handles updating your appearance for certain mutations. e.g TK head-glows - UpdateDamageIcon() //handles damage overlays for brute/burn damage //(will rename this when I geta round to it) - update_body() //Handles updating your mob's icon to reflect their gender/race/complexion etc - update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and - ...eyes were merged into update_body) - update_targeted() // Updates the target overlay when someone points a gun at you - -> All of these procs update our overlays_lying and overlays_standing, and then call update_icons() by default. - If you wish to update several overlays at once, you can set the argument to 0 to disable the update and call - it manually: - e.g. - update_inv_head(0) - update_inv_l_hand(0) - update_inv_r_hand() //<---calls update_icons() - - or equivillantly: - update_inv_head(0) - update_inv_l_hand(0) - update_inv_r_hand(0) - update_icons() - -> If you need to update all overlays you can use regenerate_icons(). it works exactly like update_clothing used to. - -> I reimplimented an old unused variable which was in the code called (coincidentally) var/update_icon - It can be used as another method of triggering regenerate_icons(). It's basically a flag that when set to non-zero - will call regenerate_icons() at the next life() call and then reset itself to 0. - The idea behind it is icons are regenerated only once, even if multiple events requested it. - -This system is confusing and is still a WIP. It's primary goal is speeding up the controls of the game whilst -reducing processing costs. So please bear with me while I iron out the kinks. It will be worth it, I promise. -If I can eventually free var/lying stuff from the life() process altogether, stuns/death/status stuff -will become less affected by lag-spikes and will be instantaneous! :3 - -If you have any questions/constructive-comments/bugs-to-report/or have a massivly devestated butt... -Please contact me on #coderbus IRC. ~Carn x -*/ - -//Human Overlays Indexes///////// -#define HO_MUTATIONS_LAYER 1 -#define HO_SKIN_LAYER 2 -#define HO_DAMAGE_LAYER 3 -#define HO_SURGERY_LAYER 4 //bs12 specific. -#define HO_UNDERWEAR_LAYER 5 -#define HO_UNIFORM_LAYER 6 -#define HO_ID_LAYER 7 -#define HO_SHOES_LAYER 8 -#define HO_GLOVES_LAYER 9 -#define HO_BELT_LAYER 10 -#define HO_SUIT_LAYER 11 -#define HO_TAIL_LAYER 12 //bs12 specific. this hack is probably gonna come back to haunt me -#define HO_GLASSES_LAYER 13 -#define HO_BELT_LAYER_ALT 14 -#define HO_SUIT_STORE_LAYER 15 -#define HO_BACK_LAYER 16 -#define HO_HAIR_LAYER 17 //TODO: make part of head layer? -#define HO_GOGGLES_LAYER 18 -#define HO_EARS_LAYER 19 -#define HO_FACEMASK_LAYER 20 -#define HO_HEAD_LAYER 21 -#define HO_COLLAR_LAYER 22 -#define HO_HANDCUFF_LAYER 23 -#define HO_L_HAND_LAYER 24 -#define HO_R_HAND_LAYER 25 -#define HO_FIRE_LAYER 26 //If you're on fire -#define TOTAL_LAYERS 26 -////////////////////////////////// - -/mob/living/carbon/human - var/list/overlays_standing[TOTAL_LAYERS] - var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed - -//UPDATES OVERLAYS FROM OVERLAYS_LYING/OVERLAYS_STANDING -/mob/living/carbon/human/update_icons() - lying_prev = lying //so we don't update overlays for lying/standing unless our stance changes again - update_hud() //TODO: remove the need for this - overlays.Cut() - - var/list/overlays_to_apply = list() - if (icon_update) - - var/list/visible_overlays - if(is_cloaked()) - icon = 'icons/mob/human.dmi' - icon_state = "blank" - visible_overlays = list(overlays_standing[HO_R_HAND_LAYER], overlays_standing[HO_L_HAND_LAYER]) - else - icon = stand_icon - icon_state = null - visible_overlays = overlays_standing - - var/matrix/M = matrix() - if(lying && (species.prone_overlay_offset[1] || species.prone_overlay_offset[2])) - M.Translate(species.prone_overlay_offset[1], species.prone_overlay_offset[2]) - - for(var/i = 1 to LAZYLEN(visible_overlays)) - var/entry = visible_overlays[i] - if(istype(entry, /image)) - var/image/overlay = entry - if(i != HO_DAMAGE_LAYER) - overlay.transform = M - overlays_to_apply += overlay - else if(istype(entry, /list)) - for(var/image/overlay in entry) - if(i != HO_DAMAGE_LAYER) - overlay.transform = M - overlays_to_apply += overlay - - var/obj/item/organ/external/head/head = organs_by_name[BP_HEAD] - if(istype(head) && !head.is_stump()) - var/image/I = head.get_eye_overlay() - if(I) overlays_to_apply += I - - if(auras) - overlays_to_apply += auras - - overlays = overlays_to_apply - - var/matrix/M = matrix() - if(lying) - M.Turn(90) - M.Scale(size_multiplier) - M.Translate(1, -6-default_pixel_z) - else - M.Scale(size_multiplier) - M.Translate(0, 16*(size_multiplier-1)) - animate(src, transform = M, time = ANIM_LYING_TIME) - -var/global/list/damage_icon_parts = list() - -//DAMAGE OVERLAYS -//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists -/mob/living/carbon/human/UpdateDamageIcon(var/update_icons=1) - // first check whether something actually changed about damage appearance - var/damage_appearance = "" - - if(!species.damage_overlays || !species.damage_mask) - return - - for(var/obj/item/organ/external/O in organs) - if(O.is_stump()) - continue - damage_appearance += O.damage_state - - if(damage_appearance == previous_damage_appearance) - // nothing to do here - return - - previous_damage_appearance = damage_appearance - - var/image/standing_image = image(species.damage_overlays, icon_state = "00") - - // blend the individual damage states with our icons - for(var/obj/item/organ/external/O in organs) - if(O.is_stump()) - continue - - O.update_damstate() - O.update_icon() - if(O.damage_state == "00") continue - var/icon/DI - var/use_colour = (BP_IS_PROSTHETIC(O) ? SYNTH_BLOOD_COLOUR : O.species.get_blood_colour(src)) - var/cache_index = "[O.damage_state]/[O.icon_name]/[use_colour]/[species.name]" - if(damage_icon_parts[cache_index] == null) - DI = new /icon(species.get_damage_overlays(src), O.damage_state) // the damage icon for whole human - DI.Blend(new /icon(species.get_damage_mask(src), O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels - DI.Blend(use_colour, ICON_MULTIPLY) - damage_icon_parts[cache_index] = DI - else - DI = damage_icon_parts[cache_index] - - standing_image.overlays += DI - - overlays_standing[HO_DAMAGE_LAYER] = standing_image - update_bandages(update_icons) - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/update_bandages(var/update_icons=1) - var/bandage_icon = species.bandages_icon - if(!bandage_icon) - return - var/image/standing_image = overlays_standing[HO_DAMAGE_LAYER] - if(standing_image) - for(var/obj/item/organ/external/O in organs) - if(O.is_stump()) - continue - var/bandage_level = O.bandage_level() - if(bandage_level) - standing_image.overlays += image(bandage_icon, "[O.icon_name][bandage_level]") - - overlays_standing[HO_DAMAGE_LAYER] = standing_image - if(update_icons) - queue_icon_update() - -//BASE MOB SPRITE -/mob/living/carbon/human/proc/update_body(var/update_icons=1) - var/husk_color_mod = rgb(96,88,80) - var/hulk_color_mod = rgb(48,224,40) - - var/husk = (MUTATION_HUSK in src.mutations) - var/fat = (MUTATION_FAT in src.mutations) - var/hulk = (MUTATION_HULK in src.mutations) - var/skeleton = (MUTATION_SKELETON in src.mutations) - - //CACHING: Generate an index key from visible bodyparts. - //0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic. - - //Create a new, blank icon for our mob to use. - if(stand_icon) - qdel(stand_icon) - stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi',"blank") - - var/g = "male" - if(gender == FEMALE) - g = "female" - - var/icon_key = "[species.get_icon_cache_uid(src)][g][skin_tone][skin_colour]" - if(lip_style) - icon_key += "[lip_style]" - else - icon_key += "nolips" - var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[species.vision_organ ? species.vision_organ : BP_EYES] - icon_key += istype(eyes) ? eyes.eye_colour : COLOR_BLACK - - for(var/organ_tag in species.has_limbs) - var/obj/item/organ/external/part = organs_by_name[organ_tag] - if(isnull(part) || part.is_stump()) - icon_key += "0" - continue - for(var/M in part.markings) - icon_key += "[M][part.markings[M]["color"]]" - if(part) - icon_key += "[part.species.get_icon_cache_uid(part.owner)]" - icon_key += "[part.dna.GetUIState(DNA_UI_GENDER)]" - icon_key += "[part.skin_tone]" - icon_key += "[part.skin_base]" - if(part.skin_colour) - icon_key += "[part.skin_colour]" - icon_key += "[part.skin_blend]" - if(part.body_hair && part.hair_colour) - icon_key += "[part.hair_colour]" - else - icon_key += COLOR_BLACK - for(var/M in part.markings) - icon_key += "[M][part.markings[M]["color"]]" - if(BP_IS_PROSTHETIC(part)) - icon_key += "2[part.model ? "-[part.model]": ""]" - else if(part.status & ORGAN_DEAD) - icon_key += "3" - else - icon_key += "1" - - icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0]" - - var/icon/base_icon - if(human_icon_cache[icon_key]) - base_icon = human_icon_cache[icon_key] - else - //BEGIN CACHED ICON GENERATION. - var/obj/item/organ/external/chest = get_organ(BP_CHEST) - base_icon = chest.get_icon() - - for(var/obj/item/organ/external/part in (organs-chest)) - var/icon/temp = part.get_icon() - //That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST - //And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part) - if(part.icon_position & (LEFT | RIGHT)) - var/icon/temp2 = new('icons/mob/human.dmi',"blank") - temp2.Insert(new/icon(temp,dir=NORTH),dir=NORTH) - temp2.Insert(new/icon(temp,dir=SOUTH),dir=SOUTH) - if(!(part.icon_position & LEFT)) - temp2.Insert(new/icon(temp,dir=EAST),dir=EAST) - if(!(part.icon_position & RIGHT)) - temp2.Insert(new/icon(temp,dir=WEST),dir=WEST) - base_icon.Blend(temp2, ICON_OVERLAY) - if(part.icon_position & LEFT) - temp2.Insert(new/icon(temp,dir=EAST),dir=EAST) - if(part.icon_position & RIGHT) - temp2.Insert(new/icon(temp,dir=WEST),dir=WEST) - base_icon.Blend(temp2, ICON_UNDERLAY) - else if(part.icon_position & UNDER) - base_icon.Blend(temp, ICON_UNDERLAY) - else - base_icon.Blend(temp, ICON_OVERLAY) - - if(!skeleton) - if(husk) - base_icon.ColorTone(husk_color_mod) - else if(hulk) - var/list/tone = ReadRGB(hulk_color_mod) - base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3])) - - //Handle husk overlay. - if(husk) - var/husk_icon = species.get_husk_icon(src) - if(husk_icon) - var/icon/mask = new(base_icon) - var/icon/husk_over = new(species.husk_icon,"") - mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0) - husk_over.Blend(mask, ICON_ADD) - base_icon.Blend(husk_over, ICON_OVERLAY) - - human_icon_cache[icon_key] = base_icon - - //END CACHED ICON GENERATION. - stand_icon.Blend(base_icon,ICON_OVERLAY) - - //tail - update_tail_showing(0) - - if(update_icons) - queue_icon_update() - -//UNDERWEAR OVERLAY - -/mob/living/carbon/human/proc/update_underwear(var/update_icons=1) - overlays_standing[HO_UNDERWEAR_LAYER] = list() - for(var/entry in worn_underwear) - var/obj/item/underwear/UW = entry - - var/image/I = image(icon = UW.icon, icon_state = UW.icon_state) - I.appearance_flags = RESET_COLOR - I.color = UW.color - - overlays_standing[HO_UNDERWEAR_LAYER] += I - - if(update_icons) - queue_icon_update() - -//HAIR OVERLAY -/mob/living/carbon/human/proc/update_hair(var/update_icons=1) - //Reset our hair - overlays_standing[HO_HAIR_LAYER] = null - - var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD) - if(!head_organ || head_organ.is_stump() ) - if(update_icons) - queue_icon_update() - return - - //masks and helmets can obscure our hair. - if( (head && (head.flags_inv & BLOCKHAIR)) || (wear_mask && (wear_mask.flags_inv & BLOCKHAIR))) - if(update_icons) - queue_icon_update() - return - - overlays_standing[HO_HAIR_LAYER] = head_organ.get_hair_icon() - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/update_skin(var/update_icons=1) - overlays_standing[HO_SKIN_LAYER] = species.update_skin(src) - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_mutations(var/update_icons=1) - var/fat - if(MUTATION_FAT in mutations) - fat = "fat" - - var/image/standing = overlay_image('icons/effects/genetics.dmi', flags=RESET_COLOR) - var/add_image = 0 - var/g = "m" - if(gender == FEMALE) g = "f" - // DNA2 - Drawing underlays. - for(var/datum/dna/gene/gene in dna_genes) - if(!gene.block) - continue - if(gene.is_active(src)) - var/underlay=gene.OnDrawUnderlays(src,g,fat) - if(underlay) - standing.underlays += underlay - add_image = 1 - for(var/mut in mutations) - switch(mut) - if(MUTATION_LASER) - standing.overlays += "lasereyes_s" - add_image = 1 - if(add_image) - overlays_standing[HO_MUTATIONS_LAYER] = standing - else - overlays_standing[HO_MUTATIONS_LAYER] = null - if(update_icons) - queue_icon_update() -/* --------------------------------------- */ -//For legacy support. -/mob/living/carbon/human/regenerate_icons() - ..() - if(HasMovementHandler(/datum/movement_handler/mob/transformation) || QDELETED(src)) return - - update_mutations(0) - update_body(0) - update_skin(0) - update_underwear(0) - update_hair(0) - update_inv_w_uniform(0) - update_inv_wear_id(0) - update_inv_gloves(0) - update_inv_glasses(0) - update_inv_ears(0) - update_inv_shoes(0) - update_inv_s_store(0) - update_inv_wear_mask(0) - update_inv_head(0) - update_inv_belt(0) - update_inv_back(0) - update_inv_wear_suit(0) - update_inv_r_hand(0) - update_inv_l_hand(0) - update_inv_handcuffed(0) - update_inv_pockets(0) - update_fire(0) - update_surgery(0) - UpdateDamageIcon() - queue_icon_update() - //Hud Stuff - update_hud() - -/* --------------------------------------- */ -//vvvvvv UPDATE_INV PROCS vvvvvv - -/mob/living/carbon/human/update_inv_w_uniform(var/update_icons=1) - if(istype(w_uniform, /obj/item/clothing/under) && !(wear_suit && wear_suit.flags_inv & HIDEJUMPSUIT)) - overlays_standing[HO_UNIFORM_LAYER] = w_uniform.get_mob_overlay(src,slot_w_uniform_str) - else - overlays_standing[HO_UNIFORM_LAYER] = null - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1) - overlays_standing[HO_ID_LAYER] = null - if(wear_id) - var/obj/item/clothing/under/U = w_uniform - if(istype(U) && !U.displays_id && !U.rolled_down) - return - overlays_standing[HO_ID_LAYER] = wear_id.get_mob_overlay(src, slot_wear_id_str) - BITSET(hud_updateflag, ID_HUD) - BITSET(hud_updateflag, WANTED_HUD) - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_gloves(var/update_icons=1) - if(gloves && !(wear_suit && wear_suit.flags_inv & HIDEGLOVES)) - overlays_standing[HO_GLOVES_LAYER] = gloves.get_mob_overlay(src,slot_gloves_str) - else - if(blood_DNA && species.blood_mask) - var/image/bloodsies = overlay_image(species.blood_mask, "bloodyhands", hand_blood_color, RESET_COLOR) - overlays_standing[HO_GLOVES_LAYER] = bloodsies - else - overlays_standing[HO_GLOVES_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_glasses(var/update_icons=1) - if(glasses) - overlays_standing[glasses.use_alt_layer ? HO_GOGGLES_LAYER : HO_GLASSES_LAYER] = glasses.get_mob_overlay(src,slot_glasses_str) - overlays_standing[glasses.use_alt_layer ? HO_GLASSES_LAYER : HO_GOGGLES_LAYER] = null - else - overlays_standing[HO_GLASSES_LAYER] = null - overlays_standing[HO_GOGGLES_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_ears(var/update_icons=1) - overlays_standing[HO_EARS_LAYER] = null - if( (head && (head.flags_inv & (BLOCKHAIR | BLOCKHEADHAIR))) || (wear_mask && (wear_mask.flags_inv & (BLOCKHAIR | BLOCKHEADHAIR)))) - if(update_icons) - queue_icon_update() - return - - if(l_ear || r_ear) - // Blank image upon which to layer left & right overlays. - var/image/both = image("icon" = 'icons/effects/effects.dmi', "icon_state" = "nothing") - if(l_ear) - both.overlays += l_ear.get_mob_overlay(src,slot_l_ear_str) - if(r_ear) - both.overlays += r_ear.get_mob_overlay(src,slot_r_ear_str) - overlays_standing[HO_EARS_LAYER] = both - - else - overlays_standing[HO_EARS_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_shoes(var/update_icons=1) - if(shoes && !((wear_suit && wear_suit.flags_inv & HIDESHOES) || (w_uniform && w_uniform.flags_inv & HIDESHOES))) - overlays_standing[HO_SHOES_LAYER] = shoes.get_mob_overlay(src,slot_shoes_str) - else - if(feet_blood_DNA && species.blood_mask) - var/image/bloodsies = overlay_image(species.blood_mask, "shoeblood", hand_blood_color, RESET_COLOR) - overlays_standing[HO_SHOES_LAYER] = bloodsies - else - overlays_standing[HO_SHOES_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_s_store(var/update_icons=1) - if(s_store) - overlays_standing[HO_SUIT_STORE_LAYER] = s_store.get_mob_overlay(src,slot_s_store_str) - else - overlays_standing[HO_SUIT_STORE_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_head(var/update_icons=1) - if(head) - overlays_standing[HO_HEAD_LAYER] = head.get_mob_overlay(src,slot_head_str) - else - overlays_standing[HO_HEAD_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_belt(var/update_icons=1) - if(belt) - overlays_standing[belt.use_alt_layer ? HO_BELT_LAYER_ALT : HO_BELT_LAYER] = belt.get_mob_overlay(src,slot_belt_str) - overlays_standing[belt.use_alt_layer ? HO_BELT_LAYER : HO_BELT_LAYER_ALT] = null - else - overlays_standing[HO_BELT_LAYER] = null - overlays_standing[HO_BELT_LAYER_ALT] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_wear_suit(var/update_icons=1) - - if(wear_suit) - overlays_standing[HO_SUIT_LAYER] = wear_suit.get_mob_overlay(src,slot_wear_suit_str) - update_tail_showing(0) - else - overlays_standing[HO_SUIT_LAYER] = null - update_tail_showing(0) - update_inv_w_uniform(0) - update_inv_shoes(0) - update_inv_gloves(0) - - update_collar(0) - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_pockets(var/update_icons=1) - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_wear_mask(var/update_icons=1) - if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory) ) && !(head && head.flags_inv & HIDEMASK)) - overlays_standing[HO_FACEMASK_LAYER] = wear_mask.get_mob_overlay(src,slot_wear_mask_str) - else - overlays_standing[HO_FACEMASK_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_back(var/update_icons=1) - if(back) - overlays_standing[HO_BACK_LAYER] = back.get_mob_overlay(src,slot_back_str) - else - overlays_standing[HO_BACK_LAYER] = null - - if(update_icons) - queue_icon_update() - - -/mob/living/carbon/human/update_hud() //TODO: do away with this if possible - if(client) - client.screen |= contents - if(hud_used) - hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar - -/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1) - if(handcuffed) - overlays_standing[HO_HANDCUFF_LAYER] = handcuffed.get_mob_overlay(src,slot_handcuffed_str) - else - overlays_standing[HO_HANDCUFF_LAYER] = null - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_r_hand(var/update_icons=1) - if(r_hand) - var/image/standing = r_hand.get_mob_overlay(src,slot_r_hand_str) - if(standing) - standing.appearance_flags |= RESET_ALPHA - overlays_standing[HO_R_HAND_LAYER] = standing - - if (handcuffed) drop_r_hand() //this should be moved out of icon code - else - overlays_standing[HO_R_HAND_LAYER] = null - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/update_inv_l_hand(var/update_icons=1) - if(l_hand) - var/image/standing = l_hand.get_mob_overlay(src,slot_l_hand_str) - if(standing) - standing.appearance_flags |= RESET_ALPHA - overlays_standing[HO_L_HAND_LAYER] = standing - - if (handcuffed) drop_l_hand() //This probably should not be here - else - overlays_standing[HO_L_HAND_LAYER] = null - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1) - overlays_standing[HO_TAIL_LAYER] = null - - var/species_tail = species.get_tail(src) - - if(species_tail && !(wear_suit && wear_suit.flags_inv & HIDETAIL)) - var/icon/tail_s = get_tail_icon() - overlays_standing[HO_TAIL_LAYER] = image(tail_s, icon_state = "[species_tail]_s") - animate_tail_reset(0) - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/get_tail_icon() - var/icon_key = "[species.get_icon_cache_uid(src)][skin_colour][hair_colour]" - var/icon/tail_icon = tail_icon_cache[icon_key] - if(!tail_icon) - //generate a new one - var/species_tail_anim = species.get_tail_animation(src) - if(!species_tail_anim) species_tail_anim = 'icons/effects/species.dmi' - tail_icon = new/icon(species_tail_anim) - tail_icon.Blend(skin_colour, species.tail_blend) - // The following will not work with animated tails. - var/use_species_tail = species.get_tail_hair(src) - if(use_species_tail) - var/icon/hair_icon = icon('icons/effects/species.dmi', "[species.get_tail(src)]_[use_species_tail]") - hair_icon.Blend(hair_colour, ICON_ADD) - tail_icon.Blend(hair_icon, ICON_OVERLAY) - tail_icon_cache[icon_key] = tail_icon - - return tail_icon - - -/mob/living/carbon/human/proc/set_tail_state(var/t_state) - var/image/tail_overlay = overlays_standing[HO_TAIL_LAYER] - - if(tail_overlay && species.get_tail_animation(src)) - tail_overlay.icon_state = t_state - return tail_overlay - return null - -//Not really once, since BYOND can't do that. -//Update this if the ability to flick() images or make looping animation start at the first frame is ever added. -/mob/living/carbon/human/proc/animate_tail_once(var/update_icons=1) - var/t_state = "[species.get_tail(src)]_once" - - var/image/tail_overlay = overlays_standing[HO_TAIL_LAYER] - if(tail_overlay && tail_overlay.icon_state == t_state) - return //let the existing animation finish - - tail_overlay = set_tail_state(t_state) - if(tail_overlay) - spawn(20) - //check that the animation hasn't changed in the meantime - if(overlays_standing[HO_TAIL_LAYER] == tail_overlay && tail_overlay.icon_state == t_state) - animate_tail_stop() - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/animate_tail_start(var/update_icons=1) - set_tail_state("[species.get_tail(src)]_slow[rand(0,9)]") - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/animate_tail_fast(var/update_icons=1) - set_tail_state("[species.get_tail(src)]_loop[rand(0,9)]") - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/animate_tail_reset(var/update_icons=1) - if(stat != DEAD) - set_tail_state("[species.get_tail(src)]_idle[rand(0,9)]") - else - set_tail_state("[species.get_tail(src)]_static") - - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/animate_tail_stop(var/update_icons=1) - set_tail_state("[species.get_tail(src)]_static") - - if(update_icons) - queue_icon_update() - - -//Adds a collar overlay above the helmet layer if the suit has one -// Suit needs an identically named sprite in icons/mob/collar.dmi -/mob/living/carbon/human/proc/update_collar(var/update_icons=1) - if(istype(wear_suit,/obj/item/clothing/suit)) - var/obj/item/clothing/suit/S = wear_suit - overlays_standing[HO_COLLAR_LAYER] = S.get_collar() - else - overlays_standing[HO_COLLAR_LAYER] = null - - if(update_icons) - queue_icon_update() - - -/mob/living/carbon/human/update_fire(var/update_icons=1) - overlays_standing[HO_FIRE_LAYER] = null - if(on_fire) - var/image/standing = overlay_image('icons/mob/OnFire.dmi', "Standing", RESET_COLOR) - overlays_standing[HO_FIRE_LAYER] = standing - if(update_icons) - queue_icon_update() - -/mob/living/carbon/human/proc/update_surgery(var/update_icons=1) - overlays_standing[HO_SURGERY_LAYER] = null - var/image/total = new - for(var/obj/item/organ/external/E in organs) - if(BP_IS_PROSTHETIC(E) || E.is_stump()) - continue - var/how_open = round(E.how_open()) - if(how_open <= 0) - continue - var/surgery_icon = E.species.get_surgery_overlay_icon(src) - if(!surgery_icon) - continue - var/list/surgery_states = icon_states(surgery_icon) - var/base_state = "[E.icon_name][how_open]" - var/overlay_state = "[base_state]-flesh" - var/list/overlays_to_add - if(overlay_state in surgery_states) - var/image/flesh = image(icon = surgery_icon, icon_state = overlay_state, layer = -HO_SURGERY_LAYER) - flesh.color = E.species.get_flesh_colour(src) - LAZYADD(overlays_to_add, flesh) - overlay_state = "[base_state]-blood" - if(overlay_state in surgery_states) - var/image/blood = image(icon = surgery_icon, icon_state = overlay_state, layer = -HO_SURGERY_LAYER) - blood.color = E.species.get_blood_colour(src) - LAZYADD(overlays_to_add, blood) - overlay_state = "[base_state]-bones" - if(overlay_state in surgery_states) - LAZYADD(overlays_to_add, image(icon = surgery_icon, icon_state = overlay_state, layer = -HO_SURGERY_LAYER)) - total.overlays |= overlays_to_add - - total.appearance_flags = RESET_COLOR - overlays_standing[HO_SURGERY_LAYER] = total - if(update_icons) - queue_icon_update() - -//Human Overlays Indexes///////// -#undef HO_MUTATIONS_LAYER -#undef HO_SKIN_LAYER -#undef HO_DAMAGE_LAYER -#undef HO_SURGERY_LAYER -#undef HO_UNDERWEAR_LAYER -#undef HO_UNIFORM_LAYER -#undef HO_ID_LAYER -#undef HO_SHOES_LAYER -#undef HO_GLOVES_LAYER -#undef HO_BELT_LAYER -#undef HO_EARS_LAYER -#undef HO_SUIT_LAYER -#undef HO_TAIL_LAYER -#undef HO_GLASSES_LAYER -#undef HO_BELT_LAYER_ALT -#undef HO_SUIT_STORE_LAYER -#undef HO_BACK_LAYER -#undef HO_HAIR_LAYER -#undef HO_GOGGLES_LAYER -#undef HO_FACEMASK_LAYER -#undef HO_HEAD_LAYER -#undef HO_COLLAR_LAYER -#undef HO_HANDCUFF_LAYER -#undef HO_L_HAND_LAYER -#undef HO_R_HAND_LAYER -#undef HO_FIRE_LAYER -#undef TOTAL_LAYERS diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm deleted file mode 100644 index 9ecaf74680cb..000000000000 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ /dev/null @@ -1,24 +0,0 @@ -//Lallander was here -/mob/living/carbon/human/whisper(message as text) - message = sanitize(message, encode = 0) - - if (src.client) - if (src.client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot whisper (muted).") - return - - if (src.stat == 2) - return src.say_dead(message) - - if (src.stat) - return - - if(get_id_name("Unknown") == GetVoice()) - SetName(get_id_name("Unknown")) - - whisper_say(message) - - -//This is used by both the whisper verb and human/say() to handle whispering -/mob/living/carbon/human/proc/whisper_say(var/message, var/decl/language/speaking = null, var/alt_name="", var/verb="whispers") - say(message, speaking, verb, alt_name, whispering = 1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/immunity.dm b/code/modules/mob/living/carbon/immunity.dm deleted file mode 100644 index f6c52f8a933e..000000000000 --- a/code/modules/mob/living/carbon/immunity.dm +++ /dev/null @@ -1,19 +0,0 @@ -/mob/living/carbon - var/immunity = 100 //current immune system strength - var/immunity_norm = 100 //it will regenerate to this value - -/mob/living/carbon/proc/handle_immunity() - if(status_flags & GODMODE) return 0 //godmode - - if(immunity > 0.2 * immunity_norm && immunity < immunity_norm) - immunity = min(immunity + 0.25, immunity_norm) - -/mob/living/carbon/adjust_immunity(var/amt) - immunity = Clamp(immunity + amt, 0, immunity_norm) - -/mob/living/carbon/proc/get_immunity() - var/antibiotic_boost = REAGENT_VOLUME(reagents, /decl/material/liquid/antibiotics) / (REAGENTS_OVERDOSE/2) - return max(immunity/100 * (1+antibiotic_boost), antibiotic_boost) - -/mob/living/carbon/proc/immunity_weakness() - return max(2-get_immunity(), 0) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm deleted file mode 100644 index 54331dac7298..000000000000 --- a/code/modules/mob/living/carbon/life.dm +++ /dev/null @@ -1,32 +0,0 @@ -/mob/living/carbon/Life() - if(!..()) - return - - UpdateStasis() - - // Increase germ_level regularly - if(germ_level < GERM_LEVEL_AMBIENT && prob(30)) //if you're just standing there, you shouldn't get more germs beyond an ambient level - germ_level++ - - if(stat != DEAD && !InStasis()) - //Breathing, if applicable - handle_breathing() - - //Mutations and radiation - handle_mutations_and_radiation() - - //Chemicals in the body - handle_chemicals_in_body() - - //Random events (vomiting etc) - handle_random_events() - - // eye, ear, brain damages - handle_disabilities() - - //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc - handle_statuses() - - handle_immunity() - - . = 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm deleted file mode 100644 index 1fa9895e20f6..000000000000 --- a/code/modules/mob/living/carbon/resist.dm +++ /dev/null @@ -1,178 +0,0 @@ -/mob/living/carbon/process_resist() - - //drop && roll - if(on_fire && !buckled) - fire_stacks -= 1.2 - Weaken(3) - spin(32,2) - visible_message( - "[src] rolls on the floor, trying to put themselves out!", - "You stop, drop, and roll!" - ) - sleep(30) - if(fire_stacks <= 0) - visible_message( - "[src] has successfully extinguished themselves!", - "You extinguish yourself." - ) - ExtinguishMob() - return TRUE - - if(istype(buckled, /obj/effect/vine)) - var/obj/effect/vine/V = buckled - spawn() V.manual_unbuckle(src) - return TRUE - - if(..()) - return TRUE - - if(handcuffed) - spawn() escape_handcuffs() - -/mob/living/carbon/proc/get_cuff_breakout_mod() - return 1 - -/mob/living/carbon/proc/escape_handcuffs() - //if(!(last_special <= world.time)) return - - //This line represent a significant buff to grabs... - // We don't have to check the click cooldown because /mob/living/verb/resist() has done it for us, we can simply set the delay - setClickCooldown(100) - - if(can_break_cuffs()) //Don't want to do a lot of logic gating here. - break_handcuffs() - return - - var/obj/item/handcuffs/HC = handcuffed - - //A default in case you are somehow handcuffed with something that isn't an obj/item/handcuffs type - var/breakouttime = istype(HC) ? HC.breakouttime : 2 MINUTES - - var/mob/living/carbon/human/H = src - if(istype(H) && H.gloves && istype(H.gloves,/obj/item/clothing/gloves/rig)) - breakouttime /= 2 - - breakouttime = max(5, breakouttime * get_cuff_breakout_mod()) - - visible_message( - "\The [src] attempts to remove \the [HC]!", - "You attempt to remove \the [HC] (This will take around [breakouttime / (1 SECOND)] second\s and you need to stand still).", range = 2 - ) - - var/stages = 4 - for(var/i = 1 to stages) - if(do_after(src, breakouttime*0.25, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) - if(!handcuffed || buckled) - return - visible_message( - SPAN_WARNING("\The [src] fiddles with \the [handcuffed]."), - SPAN_WARNING("You try to slip free of \the [handcuffed] ([i*100/stages]% done)."), range = 2 - ) - else - if(!handcuffed || buckled) - return - visible_message( - SPAN_WARNING("\The [src] stops fiddling with \the [handcuffed]."), - SPAN_WARNING("You stop trying to slip free of \the [handcuffed]."), range = 2 - ) - return - if(!handcuffed || buckled) - return - if (handcuffed.health) // Improvised cuffs can break because their health is > 0 - handcuffed.health = handcuffed.health - initial(handcuffed.health) / 2 - if (handcuffed.health < 1) - visible_message( - SPAN_DANGER("\The [src] manages to remove \the [handcuffed], breaking them!"), - SPAN_NOTICE("You successfully remove \the [handcuffed], breaking them!"), range = 2 - ) - QDEL_NULL(handcuffed) - if(buckled && buckled.buckle_require_restraints) - buckled.unbuckle_mob() - update_inv_handcuffed() - return - visible_message( - SPAN_WARNING("\The [src] manages to remove \the [handcuffed]!"), - SPAN_NOTICE("You successfully remove \the [handcuffed]!"), range = 2 - ) - drop_from_inventory(handcuffed) - return - -/mob/living/proc/can_break_cuffs() - . = FALSE - -/mob/living/carbon/can_break_cuffs() - . = ..() || (MUTATION_HULK in mutations) - -/mob/living/carbon/proc/break_handcuffs() - visible_message( - "[src] is trying to break \the [handcuffed]!", - "You attempt to break your [handcuffed.name]. (This will take around 5 seconds and you need to stand still)" - ) - - if(do_after(src, 5 SECONDS, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) - if(!handcuffed || buckled) - return - - visible_message( - "[src] manages to break \the [handcuffed]!", - "You successfully break your [handcuffed.name]." - ) - - if(MUTATION_HULK in mutations) - say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - - qdel(handcuffed) - handcuffed = null - if(buckled && buckled.buckle_require_restraints) - buckled.unbuckle_mob() - update_inv_handcuffed() - -/mob/living/carbon/human/can_break_cuffs() - . = ..() || species.can_shred(src,1) - -/mob/living/carbon/proc/get_special_resist_time() - return 0 - -/mob/living/carbon/escape_buckle() - var/unbuckle_time - if(src.handcuffed && istype(src.buckled, /obj/effect/energy_net)) - var/obj/effect/energy_net/N = src.buckled - N.escape_net(src) //super snowflake but is literally used NOWHERE ELSE.-Luke - return - - if(!buckled) return - if(!restrained()) - ..() - else - setClickCooldown(100) - unbuckle_time = max(0, (2 MINUTES) - get_special_resist_time()) - - visible_message( - "[src] attempts to unbuckle themself!", - "You attempt to unbuckle yourself. (This will take around [unbuckle_time / (1 SECOND)] second\s and you need to stand still)", range = 2 - ) - - if(unbuckle_time && buckled) - var/stages = 2 - for(var/i = 1 to stages) - if(!unbuckle_time || do_after(usr, unbuckle_time*0.5, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY))) - if(!buckled) - return - visible_message( - SPAN_WARNING("\The [src] tries to unbuckle themself."), - SPAN_WARNING("You try to unbuckle yourself ([i*100/stages]% done)."), range = 2 - ) - else - if(!buckled) - return - visible_message( - SPAN_WARNING("\The [src] stops trying to unbuckle themself."), - SPAN_WARNING("You stop trying to unbuckle yourself."), range = 2 - ) - return - visible_message( - SPAN_DANGER("\The [src] manages to unbuckle themself!"), - SPAN_NOTICE("You successfully unbuckle yourself."), range = 2 - ) - buckled.user_unbuckle_mob(src) - return diff --git a/code/modules/mob/living/carbon/taste.dm b/code/modules/mob/living/carbon/taste.dm deleted file mode 100644 index 72aca5a1cf21..000000000000 --- a/code/modules/mob/living/carbon/taste.dm +++ /dev/null @@ -1,68 +0,0 @@ - -/mob/living/carbon/proc/ingest(var/datum/reagents/from, var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) //we kind of 'sneak' a proc in here for ingesting stuff so we can play with it. - if(last_taste_time + 50 < world.time) - var/datum/reagents/temp = new(amount, GLOB.temp_reagents_holder) //temporary holder used to analyse what gets transfered. - from.trans_to_holder(temp, amount, multiplier, 1) - - var/text_output = temp.generate_taste_message(src) - if(text_output != last_taste_text || last_taste_time + 100 < world.time) //We dont want to spam the same message over and over again at the person. Give it a bit of a buffer. - to_chat(src, "You can taste [text_output].")//no taste means there are too many tastes and not enough flavor. - - last_taste_time = world.time - last_taste_text = text_output - return from.trans_to_holder(target,amount,multiplier,copy) //complete transfer - -/* what this does: -catalogue the 'taste strength' of each one -calculate text size per text. -*/ -/datum/reagents/proc/generate_taste_message(mob/living/carbon/taster = null) - var/minimum_percent = 15 - if(ishuman(taster)) - var/mob/living/carbon/human/H = taster - minimum_percent = round(15/ (H.isSynthetic() ? TASTE_DULL : H.species.taste_sensitivity)) - - var/list/out = list() - var/list/tastes = list() //descriptor = strength - if(minimum_percent <= 100) - for(var/reagent_type in reagent_volumes) - var/decl/material/R = decls_repository.get_decl(reagent_type) - if(!R.taste_mult) - continue - if(istype(R, /decl/material/liquid/nutriment)) - var/list/taste_data = LAZYACCESS(reagent_data, reagent_type) - for(var/taste in taste_data) - if(taste in tastes) - tastes[taste] += taste_data[taste] - else - tastes[taste] = taste_data[taste] - else - var/taste_desc = R.taste_description - var/taste_amount = REAGENT_VOLUME(src, R.type) * R.taste_mult - if(R.taste_description in tastes) - tastes[taste_desc] += taste_amount - else - tastes[taste_desc] = taste_amount - - //deal with percentages - var/total_taste = 0 - for(var/taste_desc in tastes) - total_taste += tastes[taste_desc] - for(var/taste_desc in tastes) - var/percent = tastes[taste_desc]/total_taste * 100 - if(percent < minimum_percent) - continue - var/intensity_desc = "a hint of" - if(percent > minimum_percent * 2 || percent == 100) - intensity_desc = "" - else if(percent > minimum_percent * 3) - intensity_desc = "the strong flavor of" - if(intensity_desc == "") - out += "[taste_desc]" - else - out += "[intensity_desc] [taste_desc]" - - return english_list(out, "something indescribable") - -/mob/living/carbon/proc/get_fullness() - return nutrition + (REAGENT_VOLUME(reagents, /decl/material/liquid/nutriment) * 25) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/death.dm b/code/modules/mob/living/carbon/xenobiological/death.dm deleted file mode 100644 index 330a6532f64d..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/death.dm +++ /dev/null @@ -1,22 +0,0 @@ -/mob/living/carbon/slime/death(gibbed, deathmessage, show_dead_message) - - if(stat == DEAD) return - - if(!gibbed && is_adult) - var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, colour) - M.rabid = 1 - M.Friends = Friends.Copy() - step_away(M, src) - is_adult = 0 - maxHealth = 150 - revive() - if (!client) rabid = 1 - number = rand(1, 1000) - SetName("[colour] [is_adult ? "adult" : "baby"] slime ([number])") - return - - . = ..(gibbed, deathmessage, show_dead_message) - mood = null - regenerate_icons() - - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/examine.dm b/code/modules/mob/living/carbon/xenobiological/examine.dm deleted file mode 100644 index bf6938a7390a..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/examine.dm +++ /dev/null @@ -1,31 +0,0 @@ -/mob/living/carbon/slime/examine(mob/user) - . = ..() - var/msg = "" - if (src.stat == DEAD) - msg += "It is limp and unresponsive.\n" - else - if (src.getBruteLoss()) - msg += "" - if (src.getBruteLoss() < 40) - msg += "It has some punctures in its flesh!" - else - msg += "It has severe punctures and tears in its flesh!" - msg += "\n" - - switch(powerlevel) - - if(2 to 3) - msg += "It is flickering gently with a little electrical activity.\n" - - if(4 to 5) - msg += "It is glowing gently with moderate levels of electrical activity.\n" - - if(6 to 9) - msg += "It is glowing brightly with high levels of electrical activity.\n" - - if(10) - msg += "It is radiating with massive levels of electrical activity!\n" - - msg += "*---------*" - to_chat(user, msg) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/hud.dm b/code/modules/mob/living/carbon/xenobiological/hud.dm deleted file mode 100644 index c093d61f8cf2..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/hud.dm +++ /dev/null @@ -1,2 +0,0 @@ -/mob/living/carbon/slime/handle_regular_hud_updates() - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/items.dm b/code/modules/mob/living/carbon/xenobiological/items.dm deleted file mode 100644 index 34fda1014ff7..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/items.dm +++ /dev/null @@ -1,301 +0,0 @@ -/obj/item/slime_extract - name = "slime extract" - desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"." - icon = 'icons/mob/simple_animal/slimes.dmi' - icon_state = "grey slime extract" - force = 1.0 - w_class = ITEM_SIZE_TINY - throwforce = 0 - throw_speed = 3 - throw_range = 6 - origin_tech = "{'biotech':4}" - var/Uses = 1 // uses before it goes inert - var/enhanced = 0 //has it been enhanced before? - atom_flags = ATOM_FLAG_OPEN_CONTAINER - - attackby(obj/item/O as obj, mob/user as mob) - if(istype(O, /obj/item/slimesteroid2)) - if(enhanced == 1) - to_chat(user, " This extract has already been enhanced!") - return ..() - if(Uses == 0) - to_chat(user, " You can't enhance a used extract!") - return ..() - to_chat(user, "You apply the enhancer. It now has triple the amount of uses.") - Uses = 3 - enhanced = 1 - qdel(O) - -/obj/item/slime_extract/Initialize() - . = ..() - SSstatistics.extracted_slime_cores_amount++ - create_reagents(100) - reagents.add_reagent(/decl/material/liquid/slimejelly, 30) - -/obj/item/slime_extract/grey - name = "grey slime extract" - icon_state = "grey slime extract" - -/obj/item/slime_extract/gold - name = "gold slime extract" - icon_state = "gold slime extract" - -/obj/item/slime_extract/silver - name = "silver slime extract" - icon_state = "silver slime extract" - -/obj/item/slime_extract/metal - name = "metal slime extract" - icon_state = "metal slime extract" - -/obj/item/slime_extract/purple - name = "purple slime extract" - icon_state = "purple slime extract" - -/obj/item/slime_extract/darkpurple - name = "dark purple slime extract" - icon_state = "dark purple slime extract" - -/obj/item/slime_extract/orange - name = "orange slime extract" - icon_state = "orange slime extract" - -/obj/item/slime_extract/yellow - name = "yellow slime extract" - icon_state = "yellow slime extract" - -/obj/item/slime_extract/red - name = "red slime extract" - icon_state = "red slime extract" - -/obj/item/slime_extract/blue - name = "blue slime extract" - icon_state = "blue slime extract" - -/obj/item/slime_extract/darkblue - name = "dark blue slime extract" - icon_state = "dark blue slime extract" - -/obj/item/slime_extract/pink - name = "pink slime extract" - icon_state = "pink slime extract" - -/obj/item/slime_extract/green - name = "green slime extract" - icon_state = "green slime extract" - -/obj/item/slime_extract/lightpink - name = "light pink slime extract" - icon_state = "light pink slime extract" - -/obj/item/slime_extract/black - name = "black slime extract" - icon_state = "black slime extract" - -/obj/item/slime_extract/oil - name = "oil slime extract" - icon_state = "oil slime extract" - -/obj/item/slime_extract/adamantine - name = "adamantine slime extract" - icon_state = "adamantine slime extract" - -/obj/item/slime_extract/adamantine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/crystal_agent, 10) - -/obj/item/slime_extract/quantum - name = "quantum slime extract" - icon_state = "quantum slime extract" - -/obj/item/slime_extract/pyrite - name = "pyrite slime extract" - icon_state = "pyrite slime extract" - -/obj/item/slime_extract/cerulean - name = "cerulean slime extract" - icon_state = "cerulean slime extract" - -/obj/item/slime_extract/sepia - name = "sepia slime extract" - icon_state = "sepia slime extract" - -/obj/item/slime_extract/rainbow - name = "rainbow slime extract" - icon_state = "rainbow slime extract" - -////Pet Slime Creation/// - -/obj/item/slimepotion - name = "docility potion" - desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame." - icon = 'icons/obj/items/chem/bottle.dmi' - icon_state = "bottle19" - - attack(mob/living/carbon/slime/M as mob, mob/user as mob) - if(!istype(M, /mob/living/carbon/slime))//If target is not a slime. - to_chat(user, " The potion only works on baby slimes!") - return ..() - if(M.is_adult) //Can't tame adults - to_chat(user, " Only baby slimes can be tamed!") - return..() - if(M.stat) - to_chat(user, " The slime is dead!") - return..() - if(M.mind) - to_chat(user, " The slime resists!") - return ..() - var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc) - pet.icon_state = "[M.colour] baby slime" - pet.icon_living = "[M.colour] baby slime" - pet.icon_dead = "[M.colour] baby slime dead" - pet.colour = "[M.colour]" - to_chat(user, "You feed the slime the potion, removing it's powers and calming it.") - qdel(M) - var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) - - if (!newname) - newname = "pet slime" - pet.SetName(newname) - pet.real_name = newname - qdel(src) - -/obj/item/slimepotion2 - name = "advanced docility potion" - desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes." - icon = 'icons/obj/items/chem/bottle.dmi' - icon_state = "bottle19" - - attack(mob/living/carbon/slime/M as mob, mob/user as mob) - if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime. - to_chat(user, " The potion only works on slimes!") - return ..() - if(M.stat) - to_chat(user, " The slime is dead!") - return..() - if(M.mind) - to_chat(user, " The slime resists!") - return ..() - var/mob/living/simple_animal/adultslime/pet = new /mob/living/simple_animal/adultslime(M.loc) - pet.icon_state = "[M.colour] adult slime" - pet.icon_living = "[M.colour] adult slime" - pet.icon_dead = "[M.colour] baby slime dead" - pet.colour = "[M.colour]" - to_chat(user, "You feed the slime the potion, removing it's powers and calming it.") - qdel(M) - var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) - - if (!newname) - newname = "pet slime" - pet.SetName(newname) - pet.real_name = newname - qdel(src) - - -/obj/item/slimesteroid - name = "slime steroid" - desc = "A potent chemical mix that will cause a slime to generate more extract." - icon = 'icons/obj/items/chem/bottle.dmi' - icon_state = "bottle16" - - attack(mob/living/carbon/slime/M as mob, mob/user as mob) - if(!istype(M, /mob/living/carbon/slime))//If target is not a slime. - to_chat(user, " The steroid only works on baby slimes!") - return ..() - if(M.is_adult) //Can't tame adults - to_chat(user, " Only baby slimes can use the steroid!") - return..() - if(M.stat) - to_chat(user, " The slime is dead!") - return..() - if(M.cores == 3) - to_chat(user, " The slime already has the maximum amount of extract!") - return..() - - to_chat(user, "You feed the slime the steroid. It now has triple the amount of extract.") - M.cores = 3 - qdel(src) - -/obj/item/slimesteroid2 - name = "extract enhancer" - desc = "A potent chemical mix that will give a slime extract three uses." - icon = 'icons/obj/items/chem/bottle.dmi' - icon_state = "bottle17" - -/obj/item/slimesteroid2/afterattack(obj/target, mob/user , flag) - if(istype(target, /obj/item/slime_extract)) - var/obj/item/slime_extract/extract = target - if(extract.enhanced == 1) - to_chat(user, " This extract has already been enhanced!") - return ..() - if(extract.Uses == 0) - to_chat(user, " You can't enhance a used extract!") - return ..() - to_chat(user, "You apply the enhancer. It now has triple the amount of uses.") - extract.Uses = 3 - extract.enhanced = 1 - qdel(src) - -/obj/effect/golemrune - anchored = 1 - desc = "a strange rune used to create golems. It glows when it can be activated." - name = "rune" - icon = 'icons/obj/rune.dmi' - icon_state = "golem" - unacidable = 1 - layer = RUNE_LAYER - -/obj/effect/golemrune/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/effect/golemrune/Process() - var/mob/observer/ghost/ghost - for(var/mob/observer/ghost/O in src.loc) - if(!O.client) continue - if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue - ghost = O - break - if(ghost) - icon_state = "golem2" - else - icon_state = "golem" - -/obj/effect/golemrune/attack_hand(mob/living/user) - var/mob/observer/ghost/ghost - for(var/mob/observer/ghost/O in src.loc) - if(!O.client) - continue - if(O.mind && O.mind.current && O.mind.current.stat != DEAD) - continue - ghost = O - break - if(!ghost) - to_chat(user, SPAN_WARNING("The rune fizzles uselessly.")) - return - visible_message(SPAN_WARNING("A craggy humanoid figure coalesces into being!")) - - var/mob/living/carbon/human/G = new(src.loc) - G.set_species(SPECIES_GOLEM) - G.key = ghost.key - - var/obj/item/implant/translator/natural/I = new() - I.implant_in_mob(G, BP_HEAD) - if (user.languages.len) - var/decl/language/lang = user.languages[1] - G.add_language(lang.name) - G.set_default_language(lang) - I.languages[lang.name] = 1 - - to_chat(G, FONT_LARGE(SPAN_BOLD("You are a golem. Serve [user] and assist them at any cost."))) - to_chat(G, SPAN_ITALIC("You move slowly and are vulnerable to trauma, but are resistant to heat and cold.")) - qdel(src) - - -/obj/effect/golemrune/proc/announce_to_ghosts() - for(var/mob/observer/ghost/G in GLOB.player_list) - if(G.client) - var/area/A = get_area(src) - if(A) - to_chat(G, "Golem rune created in [A.name].") - diff --git a/code/modules/mob/living/carbon/xenobiological/life.dm b/code/modules/mob/living/carbon/xenobiological/life.dm deleted file mode 100644 index 37fd23eec5fd..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/life.dm +++ /dev/null @@ -1,169 +0,0 @@ -/mob/living/carbon/slime/Life() - set invisibility = 0 - set background = 1 - - if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) - return - - ..() - - if(stat != DEAD) - handle_nutrition() - - if(!client) - handle_regular_AI() - -/mob/living/carbon/slime/handle_environment(datum/gas_mixture/environment) - if(!environment) - adjustToxLoss(rand(10,20)) - return - - //var/environment_heat_capacity = environment.heat_capacity() - var/loc_temp = T0C - if(istype(get_turf(src), /turf/space)) - //environment_heat_capacity = loc:heat_capacity - var/turf/heat_turf = get_turf(src) - loc_temp = heat_turf.temperature - - else - loc_temp = environment.temperature - - bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1) - - if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc - if(bodytemperature <= hurt_temperature) - if(bodytemperature <= die_temperature) - adjustToxLoss(200) - else - // could be more fancy, but doesn't worth the complexity: when the slimes goes into a cold area - // the damage is mostly determined by how fast its body cools - adjustToxLoss(30) - - updatehealth() - - return //TODO: DEFERRED - -/mob/living/carbon/slime/proc/adjust_body_temperature(current, loc_temp, boost) - var/btemperature = current - var/difference = abs(current-loc_temp) //get difference - var/increments// = difference/10 //find how many increments apart they are - if(difference > 50) - increments = difference/5 - else - increments = difference/10 - var/change = increments*boost // Get the amount to change by (x per increment) - var/temp_change - if(current < loc_temp) - btemperature = min(loc_temp, btemperature+change) - else if(current > loc_temp) - btemperature = max(loc_temp, btemperature-change) - temp_change = (btemperature - current) - return temp_change - -/mob/living/carbon/slime/handle_chemicals_in_body() - chem_effects.Cut() - - if(touching) touching.metabolize() - var/datum/reagents/metabolism/ingested = get_ingested_reagents() - if(istype(ingested)) ingested.metabolize() - if(bloodstr) bloodstr.metabolize() - - src.updatehealth() - - return //TODO: DEFERRED - -/mob/living/carbon/slime/handle_regular_status_updates() - - src.blinded = null - - health = maxHealth - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss()) - - if(health < 0 && stat != DEAD) - death() - return - - if(getHalLoss()) - setHalLoss(0) - - if(prob(30)) - adjustOxyLoss(-1) - adjustToxLoss(-1) - adjustFireLoss(-1) - adjustCloneLoss(-1) - adjustBruteLoss(-1) - - if (src.stat == DEAD) - src.lying = 1 - src.blinded = 1 - else - if (src.paralysis || src.stunned || src.weakened || (status_flags && FAKEDEATH)) //Stunned etc. - if (src.stunned > 0) - src.set_stat(CONSCIOUS) - if (src.weakened > 0) - src.lying = 0 - src.set_stat(CONSCIOUS) - if (src.paralysis > 0) - src.blinded = 0 - src.lying = 0 - src.set_stat(CONSCIOUS) - - else - src.lying = 0 - src.set_stat(CONSCIOUS) - - if (src.stuttering) src.stuttering = 0 - - if (src.eye_blind) - src.eye_blind = 0 - src.blinded = 1 - - if (src.ear_deaf > 0) src.ear_deaf = 0 - if (src.ear_damage < 25) - src.ear_damage = 0 - - src.set_density(!src.lying) - - if (src.sdisabilities & BLINDED) - src.blinded = 1 - if (src.sdisabilities & DEAFENED) - src.ear_deaf = 1 - - if (src.eye_blurry > 0) - src.eye_blurry = 0 - - if (src.drugged > 0) - src.drugged = 0 - - return 1 - -/mob/living/carbon/slime/proc/handle_nutrition() - - adjust_nutrition(-(0.1 + 0.05 * is_adult)) - - if(nutrition <= 0) - adjustToxLoss(2) - if (client && prob(5)) - to_chat(src, "You are starving!") - - else if (nutrition >= get_grow_nutrition() && amount_grown < SLIME_EVOLUTION_THRESHOLD) - adjust_nutrition(-20) - amount_grown++ - -/mob/living/carbon/slime/proc/get_max_nutrition() // Can't go above it - if (is_adult) return 1200 - else return 1000 - -/mob/living/carbon/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat - if (is_adult) return 1000 - else return 800 - -/mob/living/carbon/slime/proc/get_hunger_nutrition() // Below it we will always eat - if (is_adult) return 600 - else return 500 - -/mob/living/carbon/slime/proc/get_starve_nutrition() // Below it we will eat before everything else - if (is_adult) return 300 - else return 200 - -/mob/living/carbon/slime/slip() //Can't slip something without legs. - return 0 diff --git a/code/modules/mob/living/carbon/xenobiological/powers.dm b/code/modules/mob/living/carbon/xenobiological/powers.dm deleted file mode 100644 index eba7cc4d5b9b..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/powers.dm +++ /dev/null @@ -1,180 +0,0 @@ -/mob/living/carbon/slime/proc/Wrap(var/mob/living/M) // This is a proc for the clicks - if (Victim == M || src == M) - Feedstop() - return - - if (Victim) - to_chat(src, "I am already feeding...") - return - - var t = invalidFeedTarget(M) - if (t) - to_chat(src, t) - return - - Feedon(M) - -/mob/living/carbon/slime/proc/invalidFeedTarget(var/mob/living/M) - if (!istype(M)) - return "This subject is incompatible..." - if (istype(M, /mob/living/carbon/slime)) // No cannibalism... yet - return "I cannot feed on other slimes..." - if (!Adjacent(M)) - return "This subject is too far away..." - if (issilicon(M)) - return "This subject does not have an edible life energy..." - if (M.get_blocked_ratio(null, TOX, damage_flags = DAM_DISPERSED | DAM_BIO) >= 1) - return "This subject is protected..." - if (ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species.species_flags & (SPECIES_FLAG_NO_POISON|SPECIES_FLAG_NO_SCAN)) - //they can't take clone or tox damage, then for the most part they aren't affected by being fed on - and presumably feeding on them would not affect the slime either - return "This subject does not have an edible life energy..." - if (istype(M, /mob/living/carbon) && M.getCloneLoss() >= M.maxHealth * 1.5 || istype(M, /mob/living/simple_animal) && M.stat == DEAD) - return "This subject does not have an edible life energy..." - for(var/mob/living/carbon/slime/met in view()) - if(met.Victim == M && met != src) - return "\The [met] is already feeding on this subject..." - return 0 - -/mob/living/carbon/slime/proc/Feedon(var/mob/living/M) - set waitfor = 0 - Victim = M - forceMove(M.loc) - - sleep(20) // A small delay to give the victim a chance to shake them off - - regenerate_icons() - var/happyWithFood = 0 - var/totalDrained = 0 - - while(Victim && stat != 2) - if(Adjacent(M)) - UpdateFeed() - - var/hazmat = 1 - M.get_blocked_ratio(null, TOX, damage_flags = DAM_DISPERSED | DAM_BIO) //scale feeding rate by overall bio protection - if(istype(M, /mob/living/carbon)) - Victim.adjustCloneLoss(5 * hazmat) - Victim.adjustToxLoss(1 * hazmat) - if(Victim.health <= 0) - Victim.adjustToxLoss(1 * hazmat) - - else if(istype(M, /mob/living/simple_animal)) - Victim.adjustBruteLoss(10 * hazmat) - - else - to_chat(src, "[pick("This subject is incompatable", "This subject does not have a life energy", "This subject is empty", "I am not satisified", "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...") - Feedstop() - break - - if(prob(15) && M.client && istype(M, /mob/living/carbon)) - var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!") - if (ishuman(M)) - var/mob/living/carbon/human/H = M - H.custom_pain(painMes,100) - else if (istype(M, /mob/living/carbon)) - var/mob/living/carbon/C = M - if (C.can_feel_pain()) - to_chat(M, "[painMes]") - - gain_nutrition(20 * hazmat) - totalDrained += 20 * hazmat - if(totalDrained > 200) - happyWithFood = 1 - - var/heal_amt = 10 * hazmat - adjustOxyLoss(-heal_amt) //Heal yourself - adjustBruteLoss(-heal_amt) - adjustFireLoss(-heal_amt) - adjustCloneLoss(-heal_amt) - updatehealth() - if(Victim) - Victim.updatehealth() - - if(invalidFeedTarget(M) && totalDrained > 40) // Drained - happyWithFood = 1 - break - - sleep(20) // Deal damage every 2 seconds - else - break - - if(happyWithFood) // This means that the slime has either drained the victim or let it go - if(!client) - if(Victim && !rabid && !attacked && Victim.LAssailant && Victim.LAssailant != Victim) - if(!(Victim.LAssailant in Friends)) - Friends[Victim.LAssailant] = 1 - else - ++Friends[Victim.LAssailant] - - else - to_chat(src, "This subject does not have a strong enough life energy anymore...") - - Victim = null - -/mob/living/carbon/slime/proc/Feedstop() - if(Victim) - Victim = null - -/mob/living/carbon/slime/proc/UpdateFeed() - if(Victim) - forceMove(Victim.loc) // simple "attach to head" effect! - -/mob/living/carbon/slime/verb/Evolve() - set category = "Slime" - set desc = "This will let you evolve from baby to adult slime." - - if(stat) - to_chat(src, "I must be conscious to do this...") - return - - if(!is_adult) - if(amount_grown >= SLIME_EVOLUTION_THRESHOLD) - is_adult = 1 - maxHealth = 200 - amount_grown = 0 - regenerate_icons() - SetName(text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")) - else - to_chat(src, "I am not ready to evolve yet...") - else - to_chat(src, "I have already evolved...") - -/mob/living/carbon/slime/verb/Reproduce() - set category = "Slime" - set desc = "This will make you split into four slimes." - - if(stat) - to_chat(src, "I must be conscious to do this...") - return - - if(is_adult) - if(amount_grown >= SLIME_EVOLUTION_THRESHOLD) - if(stat) - to_chat(src, "I must be conscious to do this...") - return - - var/list/babies = list() - var/list/mutations = GetMutations() - for(var/i = 1 to 4) - var/t = colour - if(prob(mutation_chance)) - t = pick(mutations) - var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, t) - if(i != 1) - step_away(M, src) - M.Friends = Friends.Copy() - babies += M - SSstatistics.add_field_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]") - - var/mob/living/carbon/slime/new_slime = babies[1] - new_slime.universal_speak = universal_speak - if(src.mind) - src.mind.transfer_to(new_slime) - else - new_slime.key = src.key - qdel(src) - else - to_chat(src, "I am not ready to reproduce yet...") - else - to_chat(src, "I am not old enough to reproduce yet...") diff --git a/code/modules/mob/living/carbon/xenobiological/say.dm b/code/modules/mob/living/carbon/xenobiological/say.dm deleted file mode 100644 index 05cd84c403dc..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/say.dm +++ /dev/null @@ -1,37 +0,0 @@ -/mob/living/carbon/slime/say(var/message) - - message = sanitize(message) - - var/verb = say_quote(message) - - if(copytext(message,1,2) == get_prefix_key(/decl/prefix/custom_emote)) - return emote(copytext(message,2)) - - return ..(message, null, verb) - -/mob/living/carbon/slime/say_quote(var/text) - var/ending = copytext(text, length(text)) - if (ending == "?") - return "asks" - else if (ending == "!") - return "cries" - return "chirps" - -/mob/living/carbon/slime/say_understands(var/other) - if (istype(other, /mob/living/carbon/slime)) - return 1 - return ..() - -/mob/living/carbon/slime/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) - if (speaker in Friends) - speech_buffer = list() - speech_buffer.Add(speaker) - speech_buffer.Add(lowertext(html_decode(message))) - ..() - -/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") - if (speaker in Friends) - speech_buffer = list() - speech_buffer.Add(speaker) - speech_buffer.Add(lowertext(html_decode(message))) - ..() diff --git a/code/modules/mob/living/carbon/xenobiological/slime_AI.dm b/code/modules/mob/living/carbon/xenobiological/slime_AI.dm deleted file mode 100644 index 9373dd3da3fd..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/slime_AI.dm +++ /dev/null @@ -1,353 +0,0 @@ -/mob/living/carbon/slime/proc/handle_regular_AI() - if(client) - return - - if(attacked > 0) - if(attacked > 50) - attacked = 50 // Let's not get into absurdly long periods of rage - --attacked - - if(confused > 0) - --confused - return - - if(nutrition < get_starve_nutrition()) // If a slime is starving, it starts losing its friends - if(Friends.len > 0 && prob(1)) - var/mob/nofriend = pick(Friends) - if(nofriend && Friends[nofriend]) - Friends[nofriend] -= 1 - if (Friends[nofriend] <= 0) - Friends[nofriend] = null - Friends -= nofriend - Friends -= null - - handle_targets() - if (!AIproc) - spawn() - handle_AI() - handle_speech_and_mood() - -/mob/living/carbon/slime/proc/handle_targets() - if(Victim) // If it's eating someone already, continue eating! - return - - if(Target) - --target_patience - if (target_patience <= 0 || attacked || rabid) // Tired of chasing or attacking everything nearby - target_patience = 0 - Target = null - - var/hungry = 0 // determines if the slime is hungry - - if (nutrition < get_starve_nutrition()) - hungry = 2 - else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition()) - hungry = 1 - - if(!Target) - if(will_hunt(hungry) || attacked || rabid) // Only add to the list if we need to - var/list/targets = list() - - for(var/mob/living/L in view(7,src)) - if(AssessTarget(L)) - targets += L // Possible target found! - - if(targets.len > 0) - if(attacked || rabid || hungry == 2) - Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care - else - for(var/mob/living/carbon/C in targets) - if(ishuman(C) && prob(5)) - Target = C - break - - if(isalien(C) || issmall(C) || isanimal(C)) - Target = C - break - - if (Target) - target_patience = rand(5,7) - if (is_adult) - target_patience += 3 - - if(!Target) // If we have no target, we are wandering or following orders - if (Leader) - if (holding_still) - holding_still = max(holding_still - 1, 0) - else if(isturf(loc)) - step_to(src, get_dir(src, Leader)) - - else if(hungry) - if (holding_still) - holding_still = max(holding_still - 1 - hungry, 0) - else if(isturf(loc) && prob(50)) - SelfMove(pick(GLOB.cardinal)) - - else - if (holding_still) - holding_still = max(holding_still - 1, 0) - else if(isturf(loc) && prob(33)) - SelfMove(pick(GLOB.cardinal)) - -/mob/living/carbon/slime/proc/AssessTarget(var/mob/living/M) - if(isslime(M)) // Ignore other slimes - return 0 - - if(M in Friends) // Ignore friends - return 0 - - if(M.stat != DEAD) // Checks for those we just want to attack - if(rabid || attacked) // Will attack everything that isn't dead - return 1 - - if(!invalidFeedTarget(M)) // Checks for those we want to eat - return 1 - - return 0 - -/mob/living/carbon/slime/proc/handle_AI() // the master AI process - if(QDELETED(src) || stat == DEAD || client || Victim) - AIproc = 0 - return // If we're dead or have a client, we don't need AI, if we're feeding, we continue feeding - - if(confused) - AIproc = 0 - return - - AIproc = 1 - var/addedDelay = 0 - - if(amount_grown >= SLIME_EVOLUTION_THRESHOLD && !Target) - if(is_adult) - Reproduce() - else - Evolve() - AIproc = 0 - return - - if(Target) // We're chasing the target - if(!AssessTarget(Target) || Target == Victim) // We don't need to chase them anymore - Target = null - AIproc = 0 - return - - for(var/mob/living/carbon/slime/M in view(1, Target)) - if(M.Victim == Target) - Target = null - AIproc = 0 - return - - if(Target.Adjacent(src)) - if(istype(Target, /mob/living/silicon)) // Glomp the silicons - a_intent = I_HURT - UnarmedAttack(Target) - addedDelay = 10 - - else if(Target.client && !Target.lying && prob(60 + powerlevel * 4)) // Try to take down the target first - a_intent = I_DISARM - UnarmedAttack(Target) - addedDelay = 10 - - else - a_intent = I_GRAB - if(invalidFeedTarget(Target)) - a_intent = I_HURT //just glomp them instead - addedDelay = 10 - UnarmedAttack(Target) - - else if(Target in view(7, src)) - step_to(src, Target) - - else - Target = null - AIproc = 0 - return - - else - var/mob/living/carbon/slime/frenemy - for (var/mob/living/carbon/slime/S in view(1, src)) - if (S != src) - frenemy = S - if (frenemy && prob(1) && frenemy.Adjacent(src)) - if (frenemy.colour == colour) - a_intent = I_HELP - else - a_intent = I_HURT - UnarmedAttack(frenemy) - - var/sleeptime = max(movement_delay(), 5) + addedDelay // Maximum one action per half a second - spawn (sleeptime) - handle_AI() - return - -/mob/living/carbon/slime/proc/UpdateFace() - var/newmood = "" - a_intent = I_HELP - if(confused) - newmood = "pout" - else if(rabid || attacked) - newmood = "angry" - a_intent = I_HURT - else if(Target) - newmood = "mischevous" - - if (!newmood) - if (prob(1)) - newmood = pick("sad", ":3") - - if ((mood == "sad" || mood == ":3") && !newmood) - if (prob(75)) newmood = mood - - if (newmood != mood) // This is so we don't redraw them every time - mood = newmood - regenerate_icons() - -/mob/living/carbon/slime/proc/handle_speech_and_mood() - set waitfor = FALSE // Called from Life, and say procs might sleep. - UpdateFace() - - //Speech understanding starts here - var/to_say - if (speech_buffer.len > 0) - var/who = speech_buffer[1] // Who said it? - var/phrase = speech_buffer[2] // What did they say? - if ((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us - if (findtext(phrase, "hello") || findtext(phrase, "hi")) - to_say = pick("Hello...", "Hi...") - else if (findtext(phrase, "follow")) - if (Leader) - if (Leader == who) // Already following him - to_say = pick("Yes...", "Lead...", "Following...") - else if (Friends[who] > Friends[Leader]) // VIVA - Leader = who - to_say = "Yes... I follow [who]..." - else - to_say = "No... I follow [Leader]..." - else - if (Friends[who] > 2) - Leader = who - to_say = "I follow..." - else // Not friendly enough - to_say = pick("No...", "I won't follow...") - else if (findtext(phrase, "stop")) - if (Victim) // We are asked to stop feeding - if (Friends[who] > 4) - Victim = null - Target = null - if (Friends[who] < 7) - --Friends[who] - to_say = "Grrr..." // I'm angry but I do it - else - to_say = "Fine..." - else if (Target) // We are asked to stop chasing - if (Friends[who] > 3) - Target = null - if (Friends[who] < 6) - --Friends[who] - to_say = "Grrr..." // I'm angry but I do it - else - to_say = "Fine..." - else if (Leader) // We are asked to stop following - if (Leader == who) - to_say = "Yes... I'll stay..." - Leader = null - else - if (Friends[who] > Friends[Leader]) - Leader = null - to_say = "Yes... I'll stop..." - else - to_say = "No... I'll keep following..." - else if (findtext(phrase, "stay")) - if (Leader) - if (Leader == who) - holding_still = Friends[who] * 10 - to_say = "Yes... Staying..." - else if (Friends[who] > Friends[Leader]) - holding_still = (Friends[who] - Friends[Leader]) * 10 - to_say = "Yes... Staying..." - else - to_say = "No... I'll keep following..." - else - if (Friends[who] > 2) - holding_still = Friends[who] * 10 - to_say = "Yes... Staying..." - else - to_say = "No... I won't stay..." - speech_buffer = list() - - //Speech starts here - if (to_say) - say (to_say) - else if(prob(1)) - emote(pick("bounce","sway","light","vibrate","jiggle")) - else - var/t = 10 - var/slimes_near = -1 // Don't count myself - var/dead_slimes = 0 - var/friends_near = list() - for (var/mob/living/carbon/M in view(7,src)) - if (isslime(M)) - ++slimes_near - if (M.stat == DEAD) - ++dead_slimes - if (M in Friends) - t += 20 - friends_near += M - if (nutrition < get_hunger_nutrition()) t += 10 - if (nutrition < get_starve_nutrition()) t += 10 - if (prob(2) && prob(t)) - var/phrases = list() - if (Target) phrases += "[Target]... looks tasty..." - if (nutrition < get_starve_nutrition()) - phrases += "So... hungry..." - phrases += "Very... hungry..." - phrases += "Need... food..." - phrases += "Must... eat..." - else if (nutrition < get_hunger_nutrition()) - phrases += "Hungry..." - phrases += "Where is the food?" - phrases += "I want to eat..." - phrases += "Rawr..." - phrases += "Blop..." - phrases += "Blorble..." - if (rabid || attacked) - phrases += "Hrr..." - phrases += "Nhuu..." - phrases += "Unn..." - if (mood == ":3") - phrases += "Purr..." - if (attacked) - phrases += "Grrr..." - if (getToxLoss() > 30) - phrases += "Cold..." - if (getToxLoss() > 60) - phrases += "So... cold..." - phrases += "Very... cold..." - if (getToxLoss() > 90) - phrases += "..." - phrases += "C... c..." - if (Victim) - phrases += "Nom..." - phrases += "Tasty..." - if (powerlevel > 3) phrases += "Bzzz..." - if (powerlevel > 5) phrases += "Zap..." - if (powerlevel > 8) phrases += "Zap... Bzz..." - if (mood == "sad") phrases += "Bored..." - if (slimes_near) phrases += "Brother..." - if (slimes_near > 1) phrases += "Brothers..." - if (dead_slimes) phrases += "What happened?" - if (!slimes_near) - phrases += "Lonely..." - for (var/M in friends_near) - phrases += "[M]... friend..." - if (nutrition < get_hunger_nutrition()) - phrases += "[M]... feed me..." - say (pick(phrases)) - -/mob/living/carbon/slime/proc/will_hunt(var/hunger) // Check for being stopped from feeding and chasing - if (hunger == 2 || rabid || attacked) return 1 - if (Leader) return 0 - if (holding_still) return 0 - if (hunger == 1 || prob(25)) - return 1 - return 0 diff --git a/code/modules/mob/living/carbon/xenobiological/subtypes.dm b/code/modules/mob/living/carbon/xenobiological/subtypes.dm deleted file mode 100644 index 69bec10c6ef3..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/subtypes.dm +++ /dev/null @@ -1,84 +0,0 @@ -/mob/living/carbon/slime/proc/GetMutations() - switch(src.colour) - if("grey") - return list("orange", "metal", "blue", "purple") - if("purple") - return list("dark purple", "dark blue", "green", "green") - if("metal") - return list("silver", "yellow", "gold", "gold") - if("orange") - return list("dark purple", "yellow", "red", "red") - if("blue") - return list("dark blue", "silver", "pink", "pink") - //Tier 3 - if("dark blue") - return list("purple", "cerulean", "blue", "blue") - if("dark purple") - return list("purple", "sepia", "orange", "orange") - if("yellow") - return list("quantum", "metal", "orange", "orange") - if("silver") - return list("metal", "pyrite", "blue", "blue") - //Tier 4 - if("pink") - return list("pink", "pink", "light pink", "light pink") - if("red") - return list("red", "red", "oil", "oil") - if("gold") - return list("gold", "gold", "adamantine", "adamantine") - if("green") - return list("green", "green", "black", "black") - // Tier 5 - else - return list() - -/mob/living/carbon/slime/proc/GetCoreType() - switch(src.colour) - // Tier 1 - if("grey") - return /obj/item/slime_extract/grey - // Tier 2 - if("purple") - return /obj/item/slime_extract/purple - if("metal") - return /obj/item/slime_extract/metal - if("orange") - return /obj/item/slime_extract/orange - if("blue") - return /obj/item/slime_extract/blue - // Tier 3 - if("dark blue") - return /obj/item/slime_extract/darkblue - if("dark purple") - return /obj/item/slime_extract/darkpurple - if("yellow") - return /obj/item/slime_extract/yellow - if("silver") - return /obj/item/slime_extract/silver - // Tier 4 - if("pink") - return /obj/item/slime_extract/pink - if("red") - return /obj/item/slime_extract/red - if("gold") - return /obj/item/slime_extract/gold - if("green") - return /obj/item/slime_extract/green - if("sepia") - return /obj/item/slime_extract/sepia - if("quantum") - return /obj/item/slime_extract/quantum - if("cerulean") - return /obj/item/slime_extract/cerulean - if("pyrite") - return /obj/item/slime_extract/pyrite - //Tier 5 - if("light pink") - return /obj/item/slime_extract/lightpink - if("oil") - return /obj/item/slime_extract/oil - if("adamantine") - return /obj/item/slime_extract/adamantine - if("black") - return /obj/item/slime_extract/black - return /obj/item/slime_extract/grey diff --git a/code/modules/mob/living/carbon/xenobiological/update_icons.dm b/code/modules/mob/living/carbon/xenobiological/update_icons.dm deleted file mode 100644 index cd3860103344..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/update_icons.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/carbon/slime/regenerate_icons() - if (stat == DEAD) - icon_state = "[colour] baby slime dead" - else - icon_state = "[colour] [is_adult ? "adult" : "baby"] slime[Victim ? "" : " eat"]" - overlays.len = 0 - if (mood) - overlays += image('icons/mob/simple_animal/slimes.dmi', icon_state = "aslime-[mood]") - ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/xenobiological/xenobiological.dm b/code/modules/mob/living/carbon/xenobiological/xenobiological.dm deleted file mode 100644 index 0ffc86c33eb0..000000000000 --- a/code/modules/mob/living/carbon/xenobiological/xenobiological.dm +++ /dev/null @@ -1,314 +0,0 @@ -/mob/living/carbon/slime - name = "baby slime" - icon = 'icons/mob/simple_animal/slimes.dmi' - icon_state = "grey baby slime" - pass_flags = PASS_FLAG_TABLE - speak_emote = list("chirps") - - maxHealth = 150 - health = 150 - gender = NEUTER - - update_icon = 0 - nutrition = 800 - - see_in_dark = 8 - update_slimes = 0 - - // canstun and canweaken don't affect slimes because they ignore stun and weakened variables - // for the sake of cleanliness, though, here they are. - status_flags = CANPARALYSE|CANPUSH - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 - - var/toxloss = 0 - var/is_adult = 0 - var/number = 0 // Used to understand when someone is talking to it - var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside - var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35 - - var/powerlevel = 0 // 0-10 controls how much electricity they are generating - var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces - - var/mob/living/Victim = null // the person the slime is currently feeding on - var/mob/living/Target = null // AI variable - tells the slime to hunt this down - var/mob/living/Leader = null // AI variable - tells the slime to follow this person - - var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable - var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with - var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place - var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target - - var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting - - var/list/speech_buffer = list() // Last phrase said near it and person who said it - - var/mood = "" // To show its face - - var/AIproc = 0 // If it's 0, we need to launch an AI proc - - var/hurt_temperature = T0C-50 // slime keeps taking damage when its bodytemperature is below this - var/die_temperature = 50 // slime dies instantly when its bodytemperature is below this - - var/colour = "grey" - - var/core_removal_stage = 0 //For removing cores. - var/datum/reagents/metabolism/ingested - -/mob/living/carbon/slime/get_ingested_reagents() - return ingested - -/mob/living/carbon/slime/getToxLoss() - return toxloss - -/mob/living/carbon/slime/get_digestion_product() - return /decl/material/liquid/slimejelly - -/mob/living/carbon/slime/adjustToxLoss(var/amount) - toxloss = Clamp(toxloss + amount, 0, maxHealth) - -/mob/living/carbon/slime/setToxLoss(var/amount) - adjustToxLoss(amount-getToxLoss()) - -/mob/living/carbon/slime/Initialize(mapload, var/colour="grey") - ingested = new(240, src, CHEM_INGEST) - verbs += /mob/living/proc/ventcrawl - - src.colour = colour - number = random_id(/mob/living/carbon/slime, 1, 1000) - name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])" - real_name = name - mutation_chance = rand(25, 35) - regenerate_icons() - . = ..(mapload) - -/mob/living/carbon/slime/movement_delay() - if (bodytemperature >= 330.23) // 135 F - return -1 // slimes become supercharged at high temperatures - - var/tally = ..() - - var/health_deficiency = (maxHealth - health) - if(health_deficiency >= 30) tally += (health_deficiency / 25) - - if (bodytemperature < 183.222) - tally += (283.222 - bodytemperature) / 10 * 1.75 - - if(reagents) - if(reagents.has_reagent(/decl/material/liquid/amphetamines)) // Stimulants slows slimes down - tally *= 2 - - if(reagents.has_reagent(/decl/material/liquid/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow - tally *= 5 - - if(health <= 0) // if damaged, the slime moves twice as slow - tally *= 2 - - return tally + config.slime_delay - -/mob/living/carbon/slime/Bump(atom/movable/AM, yes) - if ((!(yes) || now_pushing)) - return - now_pushing = 1 - - if(isobj(AM) && !client && powerlevel > 0) - var/probab = 10 - switch(powerlevel) - if(1 to 2) probab = 20 - if(3 to 4) probab = 30 - if(5 to 6) probab = 40 - if(7 to 8) probab = 60 - if(9) probab = 70 - if(10) probab = 95 - if(prob(probab)) - if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille)) - if(nutrition <= get_hunger_nutrition()) - if (is_adult || prob(5)) - UnarmedAttack(AM) - - if(ismob(AM)) - var/mob/tmob = AM - - if(is_adult) - if(istype(tmob, /mob/living/carbon/human)) - if(prob(90)) - now_pushing = 0 - return - else - if(istype(tmob, /mob/living/carbon/human)) - now_pushing = 0 - return - - now_pushing = 0 - - ..() - -/mob/living/carbon/slime/Stat() - . = ..() - - statpanel("Status") - stat(null, "Health: [round((health / maxHealth) * 100)]%") - stat(null, "Intent: [a_intent]") - - if (client.statpanel == "Status") - stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]") - if(amount_grown >= 10) - if(is_adult) - stat(null, "You can reproduce!") - else - stat(null, "You can evolve!") - - stat(null,"Power Level: [powerlevel]") - -/mob/living/carbon/slime/adjustFireLoss(amount) - ..(-abs(amount)) // Heals them - return - -/mob/living/carbon/slime/bullet_act(var/obj/item/projectile/Proj) - attacked += 10 - ..(Proj) - return 0 - -/mob/living/carbon/slime/emp_act(severity) - powerlevel = 0 // oh no, the power! - ..() - -/mob/living/carbon/slime/explosion_act(severity) - ..() - switch(severity) - if(1) - qdel(src) - if(2) - adjustBruteLoss(60) - adjustFireLoss(60) - updatehealth() - if(3) - adjustBruteLoss(30) - updatehealth() - -/mob/living/carbon/slime/u_equip(obj/item/W) - return - -/mob/living/carbon/slime/attack_ui(slot) - return - -/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M) - - ..() - - if(Victim) - if(Victim == M) - if(prob(60)) - visible_message("\The [M] attempts to wrestle \the [src] off!") - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - else - visible_message("\The [M] manages to wrestle \the [src] off!") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - confused = max(confused, 2) - Feedstop() - UpdateFace() - step_away(src, M) - return - - else - if(prob(30)) - visible_message("\The [M] attempts to wrestle \the [src] off \the [Victim]!") - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - else - visible_message("\The [M] manages to wrestle \the [src] off \the [Victim]!") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - confused = max(confused, 2) - Feedstop() - UpdateFace() - step_away(src, M) - return - - switch(M.a_intent) - - if (I_HELP) - help_shake_act(M) - - if (I_DISARM) - var/success = prob(40) - visible_message("\The [M] pushes \the [src]![success ? " \The [src] looks momentarily disoriented!" : ""]") - if(success) - confused = max(confused, 2) - UpdateFace() - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - else - - var/damage = rand(1, 9) - - attacked += 10 - if (prob(90)) - if (MUTATION_HULK in M.mutations) - damage += 5 - if(Victim || Target) - Feedstop() - Target = null - spawn(0) - step_away(src,M,15) - sleep(3) - step_away(src,M,15) - - playsound(loc, "punch", 25, 1, -1) - visible_message("[M] has punched [src]!", \ - "[M] has punched [src]!") - - adjustBruteLoss(damage) - updatehealth() - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to punch [src]!") - return - -/mob/living/carbon/slime/attackby(var/obj/item/W, var/mob/user) - if(W.force > 0) - attacked += 10 - if(!(stat) && prob(25)) //Only run this check if we're alive or otherwise motile, otherwise surgery will be agonizing for xenobiologists. - to_chat(user, "\The [W] passes right through \the [src]!") - return - - . = ..() - - if(Victim && prob(W.force * 5)) - Feedstop() - step_away(src, user) - -/mob/living/carbon/slime/restrained() - return 0 - -/mob/living/carbon/slime/var/co2overloadtime = null -/mob/living/carbon/slime/var/temperature_resistance = T0C+75 - -/mob/living/carbon/slime/toggle_throw_mode() - return - -/mob/living/carbon/slime/check_has_eyes() - return FALSE - -/mob/living/carbon/slime/check_has_mouth() - return 0 - -/mob/living/carbon/slime/proc/gain_nutrition(var/amount) - adjust_nutrition(amount) - if(prob(amount * 2)) // Gain around one level per 50 nutrition - powerlevel++ - if(powerlevel > 10) - powerlevel = 10 - adjustToxLoss(-10) - -/mob/living/carbon/slime/adjust_nutrition(var/amt) - nutrition = Clamp(nutrition + amt, 0, get_max_nutrition()) \ No newline at end of file diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 5c10272903c4..4bd051a75b55 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -7,7 +7,11 @@ Returns standard 0 if fail */ -/mob/living/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/damage_flags = 0, var/used_weapon = null, var/armor_pen, var/silent = FALSE) +/mob/living/apply_damage(damage = 0, damagetype = BRUTE, def_zone, damage_flags = 0, obj/used_weapon, armor_pen, silent = FALSE, obj/item/organ/external/given_organ) + + if(status_flags & GODMODE) + return FALSE + if(!damage) return FALSE @@ -19,33 +23,19 @@ return FALSE switch(damagetype) - if(BRUTE) - adjustBruteLoss(damage) if(BURN) - if(MUTATION_COLD_RESISTANCE in mutations) - damage = 0 - adjustFireLoss(damage) - if(TOX) - adjustToxLoss(damage) - if(OXY) - adjustOxyLoss(damage) - if(CLONE) - adjustCloneLoss(damage) - if(PAIN) - adjustHalLoss(damage) + if(has_genetic_condition(GENE_COND_COLD_RESISTANCE)) + return + take_damage(damage, BURN, damage_flags, used_weapon, armor_pen) if(ELECTROCUTE) electrocute_act(damage, used_weapon, 1, def_zone) - if(IRRADIATE) - apply_radiation(damage) - - updatehealth() + else + take_damage(damage, damagetype, damage_flags, used_weapon, armor_pen) return TRUE - -/mob/living/proc/apply_radiation(var/damage = 0) +/mob/living/apply_radiation(var/damage = 0) if(!damage) return FALSE - radiation = max(0, radiation + damage) return TRUE @@ -60,24 +50,22 @@ /mob/living/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) if(!effect || (blocked >= 100)) return FALSE - switch(effecttype) if(STUN) - Stun(effect * blocked_mult(blocked)) + SET_STATUS_MAX(src, STAT_STUN, effect * blocked_mult(blocked)) if(WEAKEN) - Weaken(effect * blocked_mult(blocked)) + SET_STATUS_MAX(src, STAT_WEAK, effect * blocked_mult(blocked)) if(PARALYZE) - Paralyse(effect * blocked_mult(blocked)) + SET_STATUS_MAX(src, STAT_PARA, effect * blocked_mult(blocked)) if(PAIN) - adjustHalLoss(effect * blocked_mult(blocked)) + take_damage(effect * blocked_mult(blocked), PAIN) if(STUTTER) if(status_flags & CANSTUN) // stun is usually associated with stutter - TODO CANSTUTTER flag? - stuttering = max(stuttering, effect * blocked_mult(blocked)) + SET_STATUS_MAX(src, STAT_STUTTER, effect * blocked_mult(blocked)) if(EYE_BLUR) - eye_blurry = max(eye_blurry, effect * blocked_mult(blocked)) + SET_STATUS_MAX(src, STAT_BLURRY, effect * blocked_mult(blocked)) if(DROWSY) - drowsyness = max(drowsyness, effect * blocked_mult(blocked)) - updatehealth() + SET_STATUS_MAX(src, STAT_DROWSY, effect * blocked_mult(blocked)) return TRUE /mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/agony = 0, var/blocked = 0) diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 195cc1996135..3665f8d4c729 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -1,4 +1,21 @@ -/mob/living/death() - if(hiding) - hiding = FALSE +/mob/living/death(gibbed) . = ..() + if(.) + if(buckled_mob) + unbuckle_mob() + if(hiding) + hiding = FALSE + var/obj/item/rig/rig = get_rig() + if(rig) + rig.notify_ai(SPAN_DANGER("Warning: user death event. Mobility control passed to integrated intelligence system.")) + stop_aiming(no_message=1) + if(istype(ai)) + ai.handle_death(gibbed) + handle_regular_hud_updates() // Update health icon etc. + + var/decl/species/my_species = get_species() + if(my_species) + if(!gibbed && my_species.death_sound) + playsound(loc, my_species.death_sound, 80, 1, 1) + my_species.handle_death(src) + diff --git a/code/modules/mob/living/default_language.dm b/code/modules/mob/living/default_language.dm index 51ee30e1bb02..4a7384299ea2 100644 --- a/code/modules/mob/living/default_language.dm +++ b/code/modules/mob/living/default_language.dm @@ -4,10 +4,10 @@ /mob/living/proc/set_default_language(var/decl/language/language) if(ispath(language, /decl/language)) - language = decls_repository.get_decl(language) + language = GET_DECL(language) if(species_language) - var/decl/language/species_lang = decls_repository.get_decl(species_language) + var/decl/language/species_lang = GET_DECL(species_language) if(only_species_language && language != species_lang) to_chat(src, "You can only speak your species language, [src.species_language].") return 0 @@ -25,16 +25,12 @@ to_chat(src, "You will now speak whatever your standard default language is if you do not specify one when speaking.") default_language = language?.type -// Silicons can't neccessarily speak everything in their languages list -/mob/living/silicon/set_default_language(language) - ..() - /mob/living/verb/check_default_language() set name = "Check Default Language" set category = "IC" if(default_language) - var/decl/language/lang = decls_repository.get_decl(default_language) + var/decl/language/lang = GET_DECL(default_language) to_chat(src, "You are currently speaking [lang.name] by default.") else to_chat(src, "Your current default language is your species or mob type default.") diff --git a/code/modules/mob/living/deity/deity.dm b/code/modules/mob/living/deity/deity.dm deleted file mode 100644 index 22583adaa791..000000000000 --- a/code/modules/mob/living/deity/deity.dm +++ /dev/null @@ -1,119 +0,0 @@ -/mob/living/deity - name = "shapeless creature" - desc = "A shape of otherworldly matter, not yet ready to be unleashed into this world." - icon = 'icons/mob/deity_big.dmi' - icon_state = "egg" - pixel_x = -128 - pixel_y = -128 - health = 100 - maxHealth = 100 //I dunno what to do with health at this point. - universal_understand = TRUE - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 - - var/eye_type = /mob/observer/eye/freelook/cult - var/datum/visualnet/cultnet/eyenet - var/list/minions = list() //Minds of those who follow him - var/list/structures = list() //The objs that this dude controls. - var/list/feats = list() - var/datum/god_form/form - var/datum/current_boon - var/mob/living/following - -/mob/living/deity/Initialize() - . = ..() - eyenet = new() - eyeobj = new eye_type(get_turf(src), eyenet) - eyeobj.possess(src) - eyenet.add_source(src) - -/mob/living/deity/death() - . = ..() - if(.) - for(var/m in minions) - var/datum/mind/M = m - remove_follower_spells(M) - to_chat(M.current, "Your connection has been severed! \The [src] is no more!") - sound_to(M.current, 'sound/hallucinations/far_noise.ogg') - M.current.Weaken(10) - for(var/s in structures) - var/obj/structure/deity/S = s - S.linked_god = null - -/mob/living/deity/shared_nano_interaction() - if(stat == DEAD) - return STATUS_CLOSE - return STATUS_INTERACTIVE - -/mob/living/deity/Destroy() - death(0) - minions.Cut() - structures.Cut() - eyeobj.release() - - QDEL_NULL(eyenet) //We do it here as some mobs have eyes that have access to the visualnet and we only want to destroy it when the deity is destroyed - QDEL_NULL(eyeobj) - QDEL_NULL(form) - return ..() - -/mob/living/deity/verb/return_to_plane() - set category = "Godhood" - - eyeobj.forceMove(get_turf(src)) - -/mob/living/deity/verb/choose_form() - set name = "Choose Form" - set category = "Godhood" - - var/dat = list() - dat += {"

          Choose a Form

          - This choice is permanent. Choose carefully, but quickly.
    - - - - - - "} - var/list/forms = subtypesof(/datum/god_form) - - for(var/form in forms) - var/datum/god_form/G = form - var/god_name = initial(G.name) - var/icon/god_icon = icon('icons/mob/mob.dmi', initial(G.pylon_icon_state)) - send_rsc(src,god_icon, "[god_name].png") - dat += {" - - - - "} - dat += "
    NameThemeDescription
    [god_name][initial(G.info)]
    " - show_browser(src, JOINTEXT(dat), "window=godform;can_close=0") - -/mob/living/deity/proc/set_form(var/type) - form = new type(src) - to_chat(src, "You undergo a transformation into your new form!") - spawn(1) - SetName(form.name) - var/newname = sanitize(input(src, "Choose a name for your new form.", "Name change", form.name) as text, MAX_NAME_LEN) - if(newname) - fully_replace_character_name(newname) - src.verbs -= /mob/living/deity/verb/choose_form - show_browser(src, null, "window=godform") - for(var/m in minions) - var/datum/mind/mind = m - var/mob/living/L = mind.current - L.faction = form.faction - -//Gets the name based on form, or if there is no form name, type. -/mob/living/deity/proc/get_type_name(var/type) - if(form && form.buildables[type]) - var/list/vars = form.buildables[type] - if(vars["name"]) - return vars["name"] - var/atom/movable/M = type - return initial(M.name) \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_Stat.dm b/code/modules/mob/living/deity/deity_Stat.dm deleted file mode 100644 index 6105b7f9af35..000000000000 --- a/code/modules/mob/living/deity/deity_Stat.dm +++ /dev/null @@ -1,14 +0,0 @@ -/mob/living/deity/Stat() - . = ..() - if(statpanel("Status")) - stat("Structure Num", structures.len) - stat("Minion Num", minions.len) - var/boon_name = "None" - if(current_boon) - if(istype(current_boon, /spell)) - var/spell/S = current_boon - boon_name = S.name - else - var/obj/O = current_boon - boon_name = O.name - stat("Current Boon",boon_name) \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_boons.dm b/code/modules/mob/living/deity/deity_boons.dm deleted file mode 100644 index 80aa60f4c492..000000000000 --- a/code/modules/mob/living/deity/deity_boons.dm +++ /dev/null @@ -1,55 +0,0 @@ -/mob/living/deity/proc/set_boon(var/datum/boon) - if(current_boon) - qdel(current_boon) - current_boon = boon - to_chat(src,"You now have the boon [boon]") - if(istype(boon, /atom/movable)) - var/atom/movable/A = boon - nano_data["boon_name"] = A.name - A.forceMove(src) - else if(istype(boon, /spell)) - var/spell/S = boon - nano_data["boon_name"] = S.name - -/mob/living/deity/proc/grant_boon(var/mob/living/L) - if(istype(current_boon, /spell) && !grant_spell(L, current_boon)) - return - else if(istype(current_boon, /obj/item)) - var/obj/item/I = current_boon - I.dropInto(L.loc) - var/origin_text = "on the floor" - if(L.equip_to_appropriate_slot(I)) - origin_text = "on your body" - else if(L.put_in_any_hand_if_possible(I)) - origin_text = "in your hands" - else - var/obj/O = L.equip_to_storage(I) - if(O) - origin_text = "in \the [O]" - to_chat(L,"It appears [origin_text].") - - to_chat(L, "\The [src] grants you a boon of [current_boon]!") - to_chat(src, "You give \the [L] a boon of [current_boon].") - log_and_message_admins("gave [key_name(L)] the boon [current_boon]") - current_boon = null - nano_data["boon_name"] = null - return - -/mob/living/deity/proc/grant_spell(var/mob/living/target, var/spell/spell) - var/datum/mind/M = target.mind - for(var/s in M.learned_spells) - var/spell/S = s - if(istype(S, spell.type)) - to_chat(src, "They already know that spell!") - return 0 - target.add_spell(spell) - spell.set_connected_god(src) - to_chat(target, "You feel a surge of power as you learn the art of [current_boon].") - return 1 - -/* This is a generic proc used by the God to inact a sacrifice from somebody. Power is a value of magnitude. -*/ -/mob/living/deity/proc/take_charge(var/mob/living/L, var/power) - if(form) - return form.take_charge(L, power) - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_click.dm b/code/modules/mob/living/deity/deity_click.dm deleted file mode 100644 index 35cee5dadc6d..000000000000 --- a/code/modules/mob/living/deity/deity_click.dm +++ /dev/null @@ -1,24 +0,0 @@ -/mob/living/deity/ClickOn(var/atom/A, var/params) - if(A == src) - if(form) - ui_interact(src) - else - choose_form() - return - var/list/modifiers = params2list(params) - if(modifiers["shift"] || modifiers["ctrl"]) - if(silenced) - to_chat(src, "You cannot do that as you are silenced!") - else - var/datum/phenomena/phenomena = get_phenomena(modifiers["shift"], modifiers["ctrl"]) - if(phenomena) - phenomena.Click(A) - return - if(current_boon && is_follower(A)) - grant_boon(A) - else if(istype(A, /obj/structure/deity)) - var/obj/structure/deity/D = A - if(D.linked_god == src) - D.attack_deity(src) - return - ..() \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_items.dm b/code/modules/mob/living/deity/deity_items.dm deleted file mode 100644 index 9245a8dbbd02..000000000000 --- a/code/modules/mob/living/deity/deity_items.dm +++ /dev/null @@ -1,44 +0,0 @@ -/mob/living/deity - var/list/items - var/list/items_by_category - -/mob/living/deity/proc/set_items(var/list/_items) - items = _items - items_by_category = list() - for(var/i in items) - var/datum/deity_item/di = items[i] - if(!items_by_category[di.category]) - items_by_category[di.category] = list() - items_by_category[di.category] += di - -/mob/living/deity/proc/has_item(var/name, var/minimum_level = 1) - if(!(name in items)) - return FALSE - var/datum/deity_item/di = items[name] - . = di.level >= minimum_level - -/mob/living/deity/proc/upgrade_item(var/name) - if(!(name in items)) - return FALSE - var/datum/deity_item/di = items[name] - if(!di.can_buy(src)) - return FALSE - di.buy(src) - . = TRUE - -/mob/living/deity/proc/get_item_level(var/name) - . = 0 - if(items[name]) - var/datum/deity_item/di = items[name] - . = di.level - - -/mob/living/deity/Destroy() - for(var/cat in items_by_category) - var/list/L = items_by_category[cat] - L.Cut() - items_by_category.Cut() - for(var/i in items) - qdel(items[i]) - items.Cut() - . = ..() \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_phenomena.dm b/code/modules/mob/living/deity/deity_phenomena.dm deleted file mode 100644 index 84f5fc691a74..000000000000 --- a/code/modules/mob/living/deity/deity_phenomena.dm +++ /dev/null @@ -1,95 +0,0 @@ -/mob/living/deity - var/silenced = 0 - var/list/phenomenas = list() - var/list/intent_phenomenas = list() - var/static/list/control_types = list("control", "controlshift", "shift") - - -/mob/living/deity/Initialize() - . = ..() - for(var/intent in intents) //Just in case we somehow remove/add a new intent #futureproofing - populate_intent(intent) - set_phenomena(add_phenomena(/datum/phenomena/communicate), I_HELP, "shift") - set_phenomena(add_phenomena(/datum/phenomena/punish), I_HELP, "control") - set_phenomena(add_phenomena(/datum/phenomena/point), I_HELP, "controlshift") - set_phenomena(add_phenomena(/datum/phenomena/conversion), I_GRAB, "shift") - set_phenomena(add_phenomena(/datum/phenomena/forced_conversion), I_GRAB, "control") - -/mob/living/deity/proc/silence(var/amount) - if(!silenced) - to_chat(src, "You've been silenced! Your phenomenas are disabled!") - var/obj/screen/intent/deity/SD = hud_used.action_intent - SD.color = "#ff0000" - silenced += amount - for(var/phenom in phenomenas) //Also make it so that you don't do cooldowns. - var/datum/phenomena/P = phenomenas[phenom] - if(P.refresh_time) - P.refresh_time += amount - -/mob/living/deity/Life() - . = ..() - if(. && silenced) - if(!--silenced) - to_chat(src, "You are no longer silenced.") - var/obj/screen/intent/deity/SD = hud_used.action_intent - SD.color = null - -/mob/living/deity/Destroy() - for(var/phenom in phenomenas) - remove_phenomena(phenom) - return ..() - -/mob/living/deity/proc/add_phenomena(var/type) - if(!phenomenas) - phenomenas = list() - for(var/P in phenomenas) - if(istype(phenomenas[P], type)) - return - var/datum/phenomena/P = new type(src) - phenomenas[P.name] = P - return P - -/mob/living/deity/proc/remove_phenomena_from_intent(var/intent, var/modifier, var/update = 1) - var/list/intent_list = intent_phenomenas[intent] - intent_list[modifier] = null - if(update) - update_phenomena_bindings() - -/mob/living/deity/proc/remove_phenomena(var/to_remove) - var/datum/phenomena/P = phenomenas[to_remove] - phenomenas -= to_remove - for(var/intent in intent_phenomenas) - var/list/intent_list = intent_phenomenas[intent] - for(var/mod in intent_list) - if(intent_list[mod] == P) - intent_list[mod] = null - var/obj/screen/intent/deity/SD = hud_used.action_intent - SD.update_text() - update_phenomenas() - update_phenomena_bindings() - if(selected == to_remove) - selected = null - qdel(P) - -/mob/living/deity/proc/populate_intent(var/intent) - if(!intent_phenomenas[intent]) - intent_phenomenas[intent] = list() - intent_phenomenas[intent] |= control_types - -/mob/living/deity/proc/set_phenomena(var/datum/phenomena/phenomena, var/intent, var/modifiers) - if(!intent_phenomenas[intent]) - populate_intent(intent) - var/list/intent_list = intent_phenomenas[intent] - intent_list[modifiers] = phenomena - -/mob/living/deity/proc/get_phenomena(var/shift = 0, var/control = 0) - var/list/intent_list = intent_phenomenas[a_intent] - if(intent_list) - var/type = "" - if(shift) - type = "shift" - if(control) - type = "control[type]" - if(intent_list[type]) - return intent_list[type] - return null \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_power.dm b/code/modules/mob/living/deity/deity_power.dm deleted file mode 100644 index a34dd2c630b8..000000000000 --- a/code/modules/mob/living/deity/deity_power.dm +++ /dev/null @@ -1,27 +0,0 @@ -/mob/living/deity - var/power = 0 - var/power_min = 10 - var/power_per_regen = 1 - -/mob/living/deity/Life() - . = ..() - if(.) - if(power_per_regen < 0 || power < power_min) - adjust_power(power_per_regen) - -/mob/living/deity/proc/adjust_power(var/amount) - if(amount) - power = max(0, power + amount) - -/mob/living/deity/proc/adjust_power_min(var/amount, var/silent = 0, var/msg) - if(amount) - power_min = max(initial(power_min), power_min + amount) - if(!silent) - var/feel = "" - if(abs(amount) > 20) - feel = " immensely" - else if(abs(amount) > 10) - feel = " greatly" - if(abs(amount) >= 5) - var/class = amount > 0 ? "notice" : "warning" - to_chat(src, "You feel your power [amount > 0 ? "increase" : "decrease"][feel][msg ? " [msg]" : ""]") \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_pylon.dm b/code/modules/mob/living/deity/deity_pylon.dm deleted file mode 100644 index 7f84dc5b339b..000000000000 --- a/code/modules/mob/living/deity/deity_pylon.dm +++ /dev/null @@ -1,21 +0,0 @@ -/mob/living/deity - var/image/pylon_image - var/obj/structure/deity/pylon/pylon - -/mob/living/deity/set_form(var/type) - ..() - pylon_image = image('icons/mob/mob.dmi', icon_state = form.pylon_icon_state) - pylon_image.alpha = 180 - -/mob/living/deity/proc/possess_pylon(var/obj/structure/deity/pylon/P) - if(pylon) - leave_pylon() - pylon = P - pylon.overlays += pylon_image - playsound(pylon,'sound/effects/phasein.ogg',40,1) - -/mob/living/deity/proc/leave_pylon() - if(!pylon) - return - pylon.overlays -= pylon_image - pylon = null \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_sources.dm b/code/modules/mob/living/deity/deity_sources.dm deleted file mode 100644 index d713e100199f..000000000000 --- a/code/modules/mob/living/deity/deity_sources.dm +++ /dev/null @@ -1,84 +0,0 @@ -/mob/living/deity/proc/add_follower(var/mob/living/L) - if(is_follower(L, silent=1)) - return - - adjust_source(3, L) - minions += L.mind - var/spell/construction/C = new() - L.add_spell(C) - C.set_connected_god(src) - if(form) - L.faction = form.faction - update_followers() - GLOB.destroyed_event.register(L,src, .proc/dead_follower) - GLOB.death_event.register(L,src, .proc/update_followers) - -/mob/living/deity/proc/dead_follower(var/mob/living/L) - GLOB.death_event.unregister(L,src) - GLOB.destroyed_event.unregister(L,src) - -/mob/living/deity/proc/remove_follower_spells(var/datum/mind/M) - if(M.learned_spells) - for(var/s in M.learned_spells) - var/spell/S = s - if(S.connected_god == src) - M.current.remove_spell(S) - qdel(S) - -/mob/living/deity/proc/remove_follower(var/mob/living/L) - if(!is_follower(L, silent=1)) - return - - adjust_source(-3, L) - minions -= L.mind - L.faction = MOB_FACTION_NEUTRAL - if(L.mind) - remove_follower_spells(L.mind) - update_followers() - - -/mob/living/deity/proc/adjust_source(var/amount, var/atom/source, var/silent = 0, var/msg) - adjust_power_min(amount, silent, msg) - if(!ismovable(source)) - return - if(amount > 0) - eyenet.add_source(source) - if(istype(source, /obj/structure/deity)) - structures |= source - else - eyenet.remove_source(source) - if(istype(source, /obj/structure/deity)) - structures -= source - -/mob/living/deity/proc/is_follower(var/mob/living/L, var/silent = 0) - if(istype(L)) - if(L.mind) - if(L.mind in minions) - return 1 - if(!silent) - to_chat(src, "You do not feel a malleable mind behind that frame.") - return 0 - -/mob/living/deity/fully_replace_character_name(var/new_name, var/in_depth = TRUE) - if(!..()) - return 0 - for(var/m in minions) - var/datum/mind/minion = m - to_chat(minion.current, "Your master is now known as [new_name]") - minion.special_role = "Servant of [new_name]" - eyeobj.SetName("[src] ([eyeobj.name_sufix])") - nano_data["name"] = new_name - return 1 - -//Whether we are near an important structure. -/mob/living/deity/proc/near_structure(var/atom/A, var/all_structures = 0) - var/turf/T = get_turf(A) - for(var/s in structures) - if(!all_structures) - var/obj/structure/deity/D = s - if(D.deity_flags & DEITY_STRUCTURE_NEAR_IMPORTANT)//If it needs to be near an important structure, it isn't important. - continue - - if(get_dist(T, s) <= 3) - return 1 - return 0 \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_topic.dm b/code/modules/mob/living/deity/deity_topic.dm deleted file mode 100644 index 089c98092f3b..000000000000 --- a/code/modules/mob/living/deity/deity_topic.dm +++ /dev/null @@ -1,51 +0,0 @@ -/mob/living/deity/OnSelfTopic(list/href_list) - if(href_list["form"]) - var/type = locate(href_list["form"]) in subtypesof(/datum/god_form) - if(type) - set_form(type) - return TOPIC_HANDLED - if(href_list["select_phenomena"]) - nano_data["phenomenaMenu"] = 1 - selected = phenomenas[href_list["select_phenomena"]] - nano_data["selectedPhenomenaName"] = selected.name - return TOPIC_HANDLED - if(href_list["clear_selected"]) - nano_data["phenomenaMenu"] = 0 - selected = null - nano_data["selectedPhenomenaName"] = null - return TOPIC_HANDLED - if(href_list["select_intent"]) - var/list/intent = intent_phenomenas[href_list["select_intent"]] - if(intent[href_list["select_binding"]]) - remove_phenomena_from_intent(href_list["select_intent"], href_list["select_binding"], 0) - if(selected) - set_phenomena(selected, href_list["select_intent"], href_list["select_binding"]) - update_phenomena_bindings() - return TOPIC_HANDLED - if(href_list["jump"]) - var/atom/a = locate(href_list["jump"]) - var/follow = 0 - if(href_list["follow"]) - follow = 1 - if(a) - if(following) - stop_follow() - eyeobj.setLoc(get_turf(a)) - if(follow) - follow_follower(a) - to_chat(src, "[follow ? "Following" : "Jumping to"] \the [a]") - return TOPIC_HANDLED - if(href_list["buy"]) - var/datum/deity_item/di = locate(href_list["buy"]) - if(di.can_buy(src)) - di.buy(src) - else - to_chat(di,"You don't meet all the requirements for [di.name]!") - return TOPIC_HANDLED - if(href_list["switchCategory"]) - set_nano_category(text2num(href_list["switchCategory"])) - return 1 - if(href_list["switchMenu"]) - nano_data[href_list["menu"]] = text2num(href_list["switchMenu"]) - return TOPIC_HANDLED - return ..() \ No newline at end of file diff --git a/code/modules/mob/living/deity/deity_tracking.dm b/code/modules/mob/living/deity/deity_tracking.dm deleted file mode 100644 index 275e34972e07..000000000000 --- a/code/modules/mob/living/deity/deity_tracking.dm +++ /dev/null @@ -1,40 +0,0 @@ -/mob/living/deity/verb/jump_to_follower() - set category = "Godhood" - - if(!minions) - return - - var/list/could_follow = list() - for(var/m in minions) - var/datum/mind/M = m - if(M.current && M.current.stat != DEAD) - could_follow += M.current - - if(!could_follow.len) - return - - var/choice = input(src, "Jump to follower", "Teleport") as null|anything in could_follow - if(choice) - follow_follower(choice) - -/mob/living/deity/proc/follow_follower(var/mob/living/L) - if(!L || L.stat == DEAD || !is_follower(L, silent=1)) - return - if(following) - stop_follow() - eyeobj.setLoc(get_turf(L)) - to_chat(src, "You begin to follow \the [L].") - following = L - GLOB.moved_event.register(L, src, /mob/living/deity/proc/keep_following) - GLOB.destroyed_event.register(L, src, /mob/living/deity/proc/stop_follow) - GLOB.death_event.register(L, src, /mob/living/deity/proc/stop_follow) - -/mob/living/deity/proc/stop_follow() - GLOB.moved_event.unregister(following, src) - GLOB.destroyed_event.unregister(following, src) - GLOB.death_event.unregister(following,src) - to_chat(src, "You stop following \the [following].") - following = null - -/mob/living/deity/proc/keep_following(var/atom/movable/moving_instance, var/atom/old_loc, var/atom/new_loc) - eyeobj.setLoc(new_loc) diff --git a/code/modules/mob/living/deity/forms.dm b/code/modules/mob/living/deity/forms.dm deleted file mode 100644 index 4389f9e68241..000000000000 --- a/code/modules/mob/living/deity/forms.dm +++ /dev/null @@ -1,48 +0,0 @@ -/*A god form basically is a combination of a sprite sheet choice and a gameplay choice. -Each plays slightly different and has different challenges/benefits -*/ - -/datum/god_form - var/name = "Form" - var/info = "This is a form your being can take." - var/desc = "This is the mob's description given." - var/faction = MOB_FACTION_NEUTRAL //For stuff like mobs and shit - var/god_icon_state = "nar-sie" //What you look like - var/pylon_icon_state //What image shows up when appearing in a pylon - var/mob/living/deity/linked_god = null - var/starting_power_min = 10 - var/starting_regeneration = 1 - var/list/buildables = list() //Both a list of var changes and a list of buildables. - var/list/icon_states = list() - var/list/items - -/datum/god_form/New(var/mob/living/deity/D) - ..() - D.icon_state = god_icon_state - D.desc = desc - D.power_min = starting_power_min - D.power_per_regen = starting_regeneration - linked_god = D - if(items && items.len) - var/list/complete_items = list() - for(var/l in items) - var/datum/deity_item/di = new l() - complete_items[di.name] = di - D.set_items(complete_items) - items.Cut() - -/datum/god_form/proc/sync_structure(var/obj/O) - var/list/svars = buildables[O.type] - if(!svars) - return - for(var/V in svars) - O.vars[V] = svars[V] - -/datum/god_form/proc/take_charge(var/mob/living/user, var/charge) - return 1 - -/datum/god_form/Destroy() - if(linked_god) - linked_god.form = null - linked_god = null - return ..() \ No newline at end of file diff --git a/code/modules/mob/living/deity/forms/narsie.dm b/code/modules/mob/living/deity/forms/narsie.dm deleted file mode 100644 index 99b9255d7cc5..000000000000 --- a/code/modules/mob/living/deity/forms/narsie.dm +++ /dev/null @@ -1,49 +0,0 @@ -/datum/god_form/narsie - name = "Nar-Sie" - info = {"The Geometer of Blood, you crave blood and destruction.
    - Benefits:
    - +Can gain power from blood sacrifices.
    - +Ability to forge weapons and armor.
    - Drawbacks:
    - -Servant abilities require copious amounts of their blood. - "} - desc = "A being made of a million nightmares, a billion deaths." - god_icon_state = "nar-sie" - pylon_icon_state = "shade" - faction = "cult" - - buildables = list(/obj/structure/deity/altar/narsie, - /obj/structure/deity/pylon - ) - items = list(/datum/deity_item/general/potential, - /datum/deity_item/general/regeneration, - /datum/deity_item/boon/eternal_darkness, - /datum/deity_item/boon/torment, - /datum/deity_item/boon/blood_shard, - /datum/deity_item/boon/drain_blood, - /datum/deity_item/phenomena/exhude_blood, - /datum/deity_item/sacrifice, - /datum/deity_item/boon/sac_dagger, - /datum/deity_item/boon/sac_spell, - /datum/deity_item/boon/execution_axe, - /datum/deity_item/blood_stone, - /datum/deity_item/minions, - /datum/deity_item/boon/soul_shard, - /datum/deity_item/boon/blood_zombie, - /datum/deity_item/boon/tear_veil, - /datum/deity_item/phenomena/hellscape, - /datum/deity_item/blood_crafting, - /datum/deity_item/blood_crafting/armored, - /datum/deity_item/blood_crafting/space - ) - -/datum/god_form/narsie/take_charge(var/mob/living/user, var/charge) - charge = min(100, charge * 0.25) - if(prob(charge)) - to_chat(user, "You feel drained...") - var/mob/living/carbon/human/H = user - if(istype(H) && H.should_have_organ(BP_HEART)) - H.vessel.remove_any(charge) - else - user.adjustBruteLoss(charge) - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/deity/forms/starlight.dm b/code/modules/mob/living/deity/forms/starlight.dm deleted file mode 100644 index 9a0f14f5445f..000000000000 --- a/code/modules/mob/living/deity/forms/starlight.dm +++ /dev/null @@ -1,47 +0,0 @@ -/datum/god_form/starlight - name = "Starlight Herald" - info = {"Sun and fire incarnate.
    - Benefits:
    - +Ability to summon powerful minions via sacrifices.
    - +Bless one of your minions as a Herald, giving them species powers and armor.
    - Drawbacks:
    - -Servant's powers will burn them.
    - -You require copious amounts of power regeneration.
    - "} - desc = "The bringer of life, and all that entails." - god_icon_state = "sungod" - pylon_icon_state = "god" - faction = "herald" - - buildables = list(/obj/structure/deity/altar/starlight, - /obj/structure/deity/pylon/starlight, - /obj/structure/deity/radiant_statue, - ) - items = list(/datum/deity_item/general/potential, - /datum/deity_item/general/regeneration, - /datum/deity_item/boon/blazing_blade, - /datum/deity_item/boon/holy_beacon, - /datum/deity_item/boon/black_death, - /datum/deity_item/blood_crafting/firecrafting, - /datum/deity_item/boon/starburst, - /datum/deity_item/boon/exchange_wounds, - /datum/deity_item/boon/radiant_aura, - /datum/deity_item/boon/burning_touch, - /datum/deity_item/boon/burning_grip, - /datum/deity_item/boon/blood_boil, - /datum/deity_item/boon/emp, - /datum/deity_item/boon/cure_light, - /datum/deity_item/phenomena/herald, - /datum/deity_item/phenomena/wisp, - /datum/deity_item/phenomena/flickering_whisper, - /datum/deity_item/phenomena/burning_glare, - /datum/deity_item/phenomena/open_gateway, - /datum/deity_item/phenomena/divine_right - ) - -/datum/god_form/starlight/take_charge(var/mob/living/user, var/charge) - charge = max(5, charge/100) - if(prob(charge)) - to_chat(user, "Your body burns!") - user.adjustFireLoss(charge) - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/deity/forms/tower.dm b/code/modules/mob/living/deity/forms/tower.dm deleted file mode 100644 index fe165b5c56d7..000000000000 --- a/code/modules/mob/living/deity/forms/tower.dm +++ /dev/null @@ -1,49 +0,0 @@ -/datum/god_form/wizard - name = "The Tower" - info = {"Only from destruction does the Tower grow. Its bricks smelted from crumbled ignorance and the fires of ambition.
    - Benefits:
    - +Learn spells from two different schools.
    - +Deity gains power through each spell use.

    - Drawbacks:
    - -Abilities hold a limited amount of charge and must be charged at a fountain of power. - "} - desc = "A single solitary tower" - god_icon_state = "tower" - pylon_icon_state = "nim" - - buildables = list(/obj/structure/deity/altar/tower, - /obj/structure/deity/pylon, - /obj/structure/deity/wizard_recharger - ) - items = list(/datum/deity_item/general/potential, - /datum/deity_item/general/regeneration, - /datum/deity_item/conjuration, - /datum/deity_item/boon/single_charge/create_air, - /datum/deity_item/boon/single_charge/acid_spray, - /datum/deity_item/boon/single_charge/force_wall, - /datum/deity_item/phenomena/dimensional_locker, - /datum/deity_item/boon/single_charge/faithful_hound, - /datum/deity_item/wizard_armaments, - /datum/deity_item/boon/single_charge/sword, - /datum/deity_item/boon/single_charge/shield, - /datum/deity_item/phenomena/portals, - /datum/deity_item/boon/single_charge/fireball, - /datum/deity_item/boon/single_charge/force_portal, - /datum/deity_item/phenomena/banishing_smite, - /datum/deity_item/transmutation, - /datum/deity_item/boon/single_charge/slippery_surface, - /datum/deity_item/boon/single_charge/smoke, - /datum/deity_item/boon/single_charge/knock, - /datum/deity_item/boon/single_charge/burning_grip, - /datum/deity_item/phenomena/warp_body, - /datum/deity_item/boon/single_charge/jaunt, - /datum/deity_item/healing_spells, - /datum/deity_item/boon/single_charge/heal, - /datum/deity_item/boon/single_charge/heal/major, - /datum/deity_item/boon/single_charge/heal/area, - /datum/deity_item/phenomena/rock_form - ) - -/datum/god_form/wizard/take_charge(var/mob/living/user, var/charge) - linked_god.adjust_power_min(max(round(charge/100), 1),silent = 1) - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/_defines.dm b/code/modules/mob/living/deity/items/_defines.dm deleted file mode 100644 index c567b1048626..000000000000 --- a/code/modules/mob/living/deity/items/_defines.dm +++ /dev/null @@ -1,14 +0,0 @@ -#define DEITY_TREE_SACRIFICE "Sacrificing" -#define DEITY_TREE_SOUL "Soul Arts" -#define DEITY_TREE_DARK_MINION "Summoning" -#define DEITY_TREE_TRANSMUTATION "Transmutation" -#define DEITY_TREE_CONJURATION "Conjuration" -#define DEITY_TREE_ARTIFACT "Artifacts" -#define DEITY_TREE_FIRECONJ "Fire Conjuration" -#define DEITY_TREE_HERALD "Phenomenas" - -#define DEITY_BLOOD_CRAFT "Blood Crafting" -#define DEITY_ARMOR_CRAFT "Armor Crafting" -#define DEITY_VOID_CRAFT "Void Crafting" -#define DEITY_UNLOCK_ARMS "Unlock Armaments" -#define DEITY_UNLOCK_HEAL "Unlock Cleric Spells" \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/deity_item.dm b/code/modules/mob/living/deity/items/deity_item.dm deleted file mode 100644 index 6c5e70fb8395..000000000000 --- a/code/modules/mob/living/deity/items/deity_item.dm +++ /dev/null @@ -1,38 +0,0 @@ -/datum/deity_item - var/name - var/desc - var/base_cost = 1 - var/category - var/level = 0 - var/max_level = 0 - var/list/requirements //Name of item = level of item - -/datum/deity_item/proc/can_buy(var/mob/living/deity/D) - if(max_level && level == max_level) - return FALSE - var/cost = get_cost(D) - if(cost && D.power < cost) - return FALSE - if(requirements && requirements.len) - for(var/name in requirements) - if(!D.has_item(name,requirements[name])) - return FALSE - return TRUE - -/datum/deity_item/proc/buy(var/mob/living/deity/D) - D.adjust_power(-get_cost(D)) - level++ - -/datum/deity_item/proc/get_cost(var/mob/living/deity/D) - return base_cost - - -/datum/deity_item/proc/print_level() - return "[level][max_level ? "/[max_level]" : ""]" - -/datum/deity_item/proc/print_requirements() - if(!requirements) - return "N/A" - . = "" - for(var/l in requirements) - . += "[l] [requirements[l]]
    " \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/general.dm b/code/modules/mob/living/deity/items/general.dm deleted file mode 100644 index d5c217565780..000000000000 --- a/code/modules/mob/living/deity/items/general.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/deity_item/general - category = "General" - -/datum/deity_item/general/potential - name = "Increase Potential" - desc = "Increase the amount of natural power you regenerate." - base_cost = 10 - -/datum/deity_item/general/potential/buy(var/mob/living/deity/D) - ..() - D.adjust_power_min(5) - -/datum/deity_item/general/potential/get_cost(var/mob/living/deity/D) - return base_cost + base_cost * level**2 - -/datum/deity_item/general/regeneration - name = "Increase Power Syphon" - desc = "Decreases the time it takes to charge your power." - base_cost = 5 - -/datum/deity_item/general/regeneration/buy(var/mob/living/deity/D) - ..() - D.power_per_regen++ - -/datum/deity_item/general/regeneration/get_cost(var/mob/living/deity/D) - return base_cost + 10 * level \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/generic.dm b/code/modules/mob/living/deity/items/generic.dm deleted file mode 100644 index 01b2001ae6e3..000000000000 --- a/code/modules/mob/living/deity/items/generic.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/deity_item/boon - var/boon_path - -/datum/deity_item/boon/buy(var/mob/living/deity/D) - ..() - if(boon_path) - . = new boon_path() - D.set_boon(.) - -/datum/deity_item/phenomena - var/phenomena_path - max_level = 1 - -/datum/deity_item/phenomena/buy(var/mob/living/deity/D) - ..() - if(level == 1 && phenomena_path) - D.add_phenomena(phenomena_path) - D.update_phenomenas() - -/datum/deity_item/boon/single_charge/buy(var/mob/living/deity/D) - . = ..() - if(istype(.,/spell)) - var/spell/S = . - S.charge_counter = S.charge_max - S.charge_type = Sp_CHARGES \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/narsie/basic.dm b/code/modules/mob/living/deity/items/narsie/basic.dm deleted file mode 100644 index 764bd556c7d2..000000000000 --- a/code/modules/mob/living/deity/items/narsie/basic.dm +++ /dev/null @@ -1,34 +0,0 @@ -/datum/deity_item/boon/eternal_darkness - name = "Eternal Darkness" - desc = "Allows a follower to cause insanity in a target." - category = "Dark Spells" - base_cost = 40 - boon_path = /spell/targeted/shatter - -/datum/deity_item/boon/torment - name = "Torment" - desc = "Gives a follower the ability to cause mass hysteria and pain." - category = "Dark Spells" - base_cost = 50 - boon_path = /spell/targeted/torment - -/datum/deity_item/boon/blood_shard - name = "Blood Shard" - desc = "Lets a follower cause a target's blood to literally explode out of their skin into dangerous projectiles." - category = "Dark Spells" - base_cost = 75 - boon_path = /spell/hand/charges/blood_shard - -/datum/deity_item/boon/drain_blood - name = "Drain Blood" - desc = "Lets a follower drain blood from all those around them." - category = "Dark Spells" - base_cost = 110 - boon_path = /spell/aoe_turf/drain_blood - -/datum/deity_item/phenomena/exhude_blood - name = "Phenomena: Exhude Blood" - desc = "You extract the raw blood used in your faith and give it to one of your flock" - category = "Dark Spells" - base_cost = 30 - phenomena_path = /datum/phenomena/exhude_blood \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/narsie/minions.dm b/code/modules/mob/living/deity/items/narsie/minions.dm deleted file mode 100644 index b54e1008838b..000000000000 --- a/code/modules/mob/living/deity/items/narsie/minions.dm +++ /dev/null @@ -1,37 +0,0 @@ -/datum/deity_item/minions - name = DEITY_TREE_DARK_MINION - desc = "Unlock abilities that allow your followers to craft and summon useful creatures." - category = DEITY_TREE_DARK_MINION - base_cost = 75 - -/datum/deity_item/boon/soul_shard - name = "Soul Stone Shard" - desc = "Give your follower a sliver of soulstone to capture a life in." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 20 - boon_path = /obj/item/soulstone - -/datum/deity_item/boon/blood_zombie - name = "Blood Plague" - desc = "Give a vessel to a follower filled with infection so vile, it turns all sapient creatures into mindless husks." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 300 - boon_path = /obj/item/chems/food/drinks/zombiedrink - -/datum/deity_item/boon/tear_veil - name = "Tear Veil" - desc = "Grant your follower the ability to literally rip a hole in this reality, allowing things to pass through." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 100 - boon_path = /spell/tear_veil - -/datum/deity_item/phenomena/hellscape - name = "Phenomena: Reveal Hellscape" - desc = "You show a non-believer what their future will be like." - category = DEITY_TREE_DARK_MINION - requirements = list(DEITY_TREE_DARK_MINION = 1) - base_cost = 110 - phenomena_path = /datum/phenomena/hellscape \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/narsie/sacrificing.dm b/code/modules/mob/living/deity/items/narsie/sacrificing.dm deleted file mode 100644 index a2cf328aec4a..000000000000 --- a/code/modules/mob/living/deity/items/narsie/sacrificing.dm +++ /dev/null @@ -1,42 +0,0 @@ -/datum/deity_item/sacrifice - name = DEITY_TREE_SACRIFICE - desc = "Unlocks the tools necessary to allow your followers to sacrifice in your name." - category = DEITY_TREE_SACRIFICE - base_cost = 50 - max_level = 1 - -/datum/deity_item/boon/sac_dagger - name = "Sacrificial Dagger" - desc = "A small dagger embued with your powers. Lets your followers give you power through sacrifices on an altar." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 10 - boon_path = /obj/item/knife/ritual/sacrifice - -/datum/deity_item/boon/sac_spell - name = "Sacrifice Spell" - desc = "This ability makes the user take INCREDIBLE amounts of damage to heal a target for a similar amount of damage." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 10 - boon_path = /spell/targeted/heal_target/sacrifice - -/datum/deity_item/boon/execution_axe - name = "Greedy Axe" - desc = "This axe can store the very souls of those it kills to be later transfered to you through an altar." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 50 - boon_path = /obj/item/twohanded/fireaxe/cult - -/datum/deity_item/blood_stone - name = "Bloodied Stone" - desc = "Unlocks the blood stone building, which allows followers to increase your power through ritual and prayer." - category = DEITY_TREE_SACRIFICE - requirements = list(DEITY_TREE_SACRIFICE = 1) - base_cost = 50 - max_level = 1 - -/datum/deity_item/blood_stone/buy(var/mob/living/deity/user) - ..() - user.form.buildables |= /obj/structure/deity/blood_stone \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/narsie/smithing.dm b/code/modules/mob/living/deity/items/narsie/smithing.dm deleted file mode 100644 index 6d43233bf91f..000000000000 --- a/code/modules/mob/living/deity/items/narsie/smithing.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/deity_item/blood_crafting - name = DEITY_BLOOD_CRAFT - desc = "Unlocks the blood smithing structure which allows followers to forge unholy tools from blood and flesh." - category = DEITY_BLOOD_CRAFT - max_level = 1 - base_cost = 75 - var/forge_type = /obj/structure/deity/blood_forge - var/list/recipes = list(/obj/item/sword/cultblade = 50, - /obj/item/clothing/head/culthood/alt = 10, - /obj/item/clothing/suit/cultrobes/alt = 20 - ) - -/datum/deity_item/blood_crafting/buy(var/mob/living/deity/user) - ..() - user.form.buildables |= forge_type //put structure here - var/list/L = user.feats[name] - if(!L) - L = list() - for(var/type in recipes) - L[type] = recipes[type] - user.feats[name] = L - -/datum/deity_item/blood_crafting/armored - name = DEITY_ARMOR_CRAFT - desc = "Unlock the secrets to tempered blood smithing, allowing your followers to smith more powerful and expensive armaments." - category = DEITY_BLOOD_CRAFT - base_cost = 75 - requirements = list(DEITY_BLOOD_CRAFT = 1) - recipes = list(/obj/item/clothing/suit/cultrobes/magusred = 80, - /obj/item/clothing/head/culthood/magus = 50, - /obj/structure/constructshell/cult = 70) //also shield? - -/datum/deity_item/blood_crafting/space - name = DEITY_VOID_CRAFT - desc = "Allows your followers to craft space suits, allowing you to finally spread across the cosmos." - category = DEITY_BLOOD_CRAFT - base_cost = 100 - requirements = list(DEITY_BLOOD_CRAFT = 1, DEITY_ARMOR_CRAFT = 1) - recipes = list(/obj/item/clothing/suit/space/cult = 100, - /obj/item/clothing/head/helmet/space/cult = 70) //Probably more too. \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/starlight/artifacts.dm b/code/modules/mob/living/deity/items/starlight/artifacts.dm deleted file mode 100644 index 7f6a8ac04e7f..000000000000 --- a/code/modules/mob/living/deity/items/starlight/artifacts.dm +++ /dev/null @@ -1,32 +0,0 @@ -/datum/deity_item/boon/blazing_blade - name = "Blazing Blade" - desc = "A divine blade of burning fury. If it stays too far away from an altar of some sort, it disappears." - base_cost = 250 - category = DEITY_TREE_ARTIFACT - boon_path = /obj/item/sword/blazing - -/datum/deity_item/boon/holy_beacon - name = "Holy Beacon" - desc = "A staff capable of producing an almost harmless bolt of sunlight, capable of blinding anyone in the room, at least for a while." - base_cost = 200 - category = DEITY_TREE_ARTIFACT - boon_path = /obj/item/gun/energy/staff/beacon - -/datum/deity_item/boon/black_death - name = "Black Death" - desc = "A small dagger capable of poisoning those it bites. Careful, if it loses all its charges, it will burn the user. It can be recharged at a radiant statue." - base_cost = 150 - category = DEITY_TREE_ARTIFACT - boon_path = /obj/item/knife/ritual/shadow - -/datum/deity_item/blood_crafting/firecrafting - name = "Fire Crafting" - desc = "Gain the ability for your minions to build smithing stations that can make many rings of power." - base_cost = 300 - category = DEITY_TREE_ARTIFACT - max_level = 1 - forge_type = /obj/structure/deity/blood_forge/starlight - recipes = list(/obj/item/clothing/ring/aura_ring/talisman_of_starborn = 70, - /obj/item/clothing/ring/aura_ring/talisman_of_blueforged = 70, - /obj/item/clothing/ring/aura_ring/talisman_of_shadowling = 70 - ) \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/starlight/phenomena.dm b/code/modules/mob/living/deity/items/starlight/phenomena.dm deleted file mode 100644 index 2b982fcf3cc3..000000000000 --- a/code/modules/mob/living/deity/items/starlight/phenomena.dm +++ /dev/null @@ -1,41 +0,0 @@ -/datum/deity_item/phenomena/herald - name = "Choose Herald" - desc = "Gives you the ability to choose a herald. Can only be used once so be careful." - phenomena_path = /datum/phenomena/herald - base_cost = 100 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomena/wisp - name = "Summon Wisp" - desc = "Manipulate around a small light." - phenomena_path = /datum/phenomena/movable_object/wisp - base_cost = 100 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomena/flickering_whisper - name = "Flickering Whisper" - desc = "Send a subtle message to a non-follower, and see what they see for a while." - phenomena_path = /datum/phenomena/flickering_whisper - base_cost = 50 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomena/burning_glare - name = "Burning Glare" - desc = "Use your divine power to physically burn a person." - phenomena_path = /datum/phenomena/burning_glare - base_cost = 200 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomena/open_gateway - name = "Open Gateway" - desc = "Unlocks the ability to open a gateway. Required for rebirth." - phenomena_path = /datum/phenomena/create_gateway - base_cost = 250 - category = DEITY_TREE_HERALD - -/datum/deity_item/phenomena/divine_right - name = "Divine Right" - desc = "Unlocks the ability to possess your Herald, permanently transforming you into a physical god." - phenomena_path = /datum/phenomena/divine_right - base_cost = 300 - category = DEITY_TREE_HERALD \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/starlight/spells.dm b/code/modules/mob/living/deity/items/starlight/spells.dm deleted file mode 100644 index 33c6e19a55a5..000000000000 --- a/code/modules/mob/living/deity/items/starlight/spells.dm +++ /dev/null @@ -1,62 +0,0 @@ -/datum/deity_item/boon/starburst - name = "Starburst" - desc = "Grant your minion the power to blind non-followers nearby." - base_cost = 60 - boon_path = /spell/targeted/genetic/blind/starburst - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/exchange_wounds - name = "Exchange Wounds" - desc = "Allow a follower to sacrifice their own well-being for that of those around them." - base_cost = 120 - boon_path = /spell/aoe_turf/exchange_wounds - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/radiant_aura - name = "Radiant Aura" - desc = "This spell makes one of your followers immune to laser fire, for a short while at least." - base_cost = 70 - boon_path = /spell/radiant_aura/starlight - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/burning_touch - name = "Burning Touch" - desc = "Sets your minion's hand aflame, allowing them to burn people with an ever-increasing flame." - base_cost = 60 - boon_path = /spell/targeted/equip_item/burning_hand - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/burning_grip - name = "Burning Grip" - desc = "Give your follower the ability to burn an item in someone's hand so badly it causes them to burn." - base_cost = 50 - boon_path = /spell/hand/burning_grip - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/blood_boil - name = "Blood Boil" - desc = "Allow a follower to concentrate so deeply on a target that their body temperature increases, eventually setting them on fire." - base_cost = 90 - boon_path = /spell/targeted/blood_boil - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/fireball - name = "Fireball" - desc = "A classic spell, grants your follower the ability to throw an exploding ball of flame in any direction." - base_cost = 100 - boon_path = /spell/targeted/projectile/dumbfire/fireball - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/emp - name = "Disable Machinery" - desc = "Gives your follower a spell of disabling machinery, and mechanical hearts." - base_cost = 110 - boon_path = /spell/aoe_turf/disable_tech/starlight - category = DEITY_TREE_FIRECONJ - -/datum/deity_item/boon/cure_light - name = "Cure Light Wounds" - desc = "Grant mercy on your followers, giving them the ability to heal themselves slightly." - base_cost = 70 - boon_path = /spell/targeted/heal_target - category = DEITY_TREE_FIRECONJ \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/tower/conjuration.dm b/code/modules/mob/living/deity/items/tower/conjuration.dm deleted file mode 100644 index dc26893321d9..000000000000 --- a/code/modules/mob/living/deity/items/tower/conjuration.dm +++ /dev/null @@ -1,107 +0,0 @@ -/datum/deity_item/conjuration - name = DEITY_TREE_CONJURATION - desc = "Conjuration is the school of creation and teleportation, summoning fireballs or teleporting long distances, this school is extremely powerful." - category = DEITY_TREE_CONJURATION - max_level = 3 - base_cost = 50 - -/datum/deity_item/conjuration/get_cost(var/mob/living/deity/D) - return base_cost * (level + 1) - -//Level 1 -/datum/deity_item/boon/single_charge/create_air - name = "Create Air" - desc = "Allows your follower to generate a livable atmosphere in the area they are in." - base_cost = 25 - category = DEITY_TREE_CONJURATION - boon_path = /spell/create_air/tower - requirements = list(DEITY_TREE_CONJURATION = 1) - -/datum/deity_item/boon/single_charge/acid_spray - name = "Acid Spray" - desc = "The simplest form of aggressive conjuration: acid spray is quite effective in melting both man and object." - base_cost = 130 - category = DEITY_TREE_CONJURATION - boon_path = /spell/acid_spray/tower - requirements = list(DEITY_TREE_CONJURATION = 1) - -/datum/deity_item/boon/single_charge/force_wall - name = "Force Wall" - desc = "A temporary invincible wall for followers to summon." - base_cost = 30 - category = DEITY_TREE_CONJURATION - boon_path = /spell/aoe_turf/conjure/forcewall/tower - requirements = list(DEITY_TREE_CONJURATION = 1) - -/datum/deity_item/phenomena/dimensional_locker - name = "Phenomena: Dimensional Locker" - desc = "Gain the ability to move a magical locker around. While it cannot move living things, you can move it around as you please, even disappearing it into the nether." - base_cost = 50 - category = DEITY_TREE_CONJURATION - phenomena_path = /datum/phenomena/movable_object/dimensional_locker - requirements = list(DEITY_TREE_CONJURATION = 1) - -//Level 2 -/datum/deity_item/boon/single_charge/faithful_hound - name = "Faithful Hound" - desc = "This spell allows a follower to summon a singular spectral dog that guards the nearby area. Anyone without the password is barked at or bitten." - base_cost = 40 - category = DEITY_TREE_CONJURATION - boon_path = /spell/aoe_turf/conjure/faithful_hound/tower - requirements = list(DEITY_TREE_CONJURATION = 2) - -/datum/deity_item/wizard_armaments - name = DEITY_UNLOCK_ARMS - desc = "Unlock spells related to the summoning of weapons and armor. These spells only last a short duration, but are extremely effective." - base_cost = 25 - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_TREE_CONJURATION = 2) - -/datum/deity_item/boon/single_charge/sword - name = "Summon Sword" - desc = "This spell allows your followers to summon a golden firey sword for a short duration." - base_cost = 50 - boon_path = /spell/targeted/equip_item/dyrnwyn/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_UNLOCK_ARMS = 1) - -/datum/deity_item/boon/single_charge/shield - name = "Summon Shield" - desc = "This spell allows your followers to summon a magical shield for a short duration." - base_cost = 20 - boon_path = /spell/targeted/equip_item/shield/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_UNLOCK_ARMS = 1) - -/datum/deity_item/phenomena/portals - name = "Phenomena: Portals" - desc = "Gain the ability to create portals for your followers to enter through. You will need to create two for it work. Any created past that will delete the oldest portal." - base_cost = 75 - requirements = list(DEITY_TREE_CONJURATION = 2) - category = DEITY_TREE_CONJURATION - phenomena_path = /datum/phenomena/portals - -//Level 3 -/datum/deity_item/boon/single_charge/fireball - name = "Fireball" - desc = "Embue your follower with the power of exploding fire." - base_cost = 85 - boon_path = /spell/targeted/projectile/dumbfire/fireball/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_TREE_CONJURATION = 3) - -/datum/deity_item/boon/single_charge/force_portal - name = "Force Portal" - desc = "This spell allows a follower to summon a force portal. Anything that hits the portal gets sucked inside and is then thrown out when the portal explodes." - base_cost = 45 - boon_path = /spell/aoe_turf/conjure/force_portal/tower - category = DEITY_TREE_CONJURATION - requirements = list(DEITY_TREE_CONJURATION = 3) - -/datum/deity_item/phenomena/banishing_smite - name = "Phenomena: Banishing Smite" - desc = "Gain the ability to smite an individual, dealing damage to them. If they are weakened enough, this can cause them to temporarily be transported." - base_cost = 75 - requirements = list(DEITY_TREE_CONJURATION = 3) - category = DEITY_TREE_CONJURATION - phenomena_path = /datum/phenomena/banishing_smite \ No newline at end of file diff --git a/code/modules/mob/living/deity/items/tower/transmutation.dm b/code/modules/mob/living/deity/items/tower/transmutation.dm deleted file mode 100644 index 432ac3670b06..000000000000 --- a/code/modules/mob/living/deity/items/tower/transmutation.dm +++ /dev/null @@ -1,99 +0,0 @@ -/datum/deity_item/transmutation - name = DEITY_TREE_TRANSMUTATION - desc = "Transmutation is the school of change. It cannot be used to create things, only modify them or even destroy them." - category = DEITY_TREE_TRANSMUTATION - max_level = 3 - base_cost = 50 - -/datum/deity_item/conjuration/get_cost(var/mob/living/deity/D) - return base_cost * (level + 1) - -//Level 1 -/datum/deity_item/boon/single_charge/slippery_surface - name = "Slippery Surface" - desc = "Allows a follower to slicken a small patch of floor. Anyone without sure-footing will find it hard to stay upright." - base_cost = 10 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/hand/slippery_surface/tower - -/datum/deity_item/boon/single_charge/smoke - name = "Smoke" - desc = "Allows a follower to distill the nearby air into smoke." - base_cost = 10 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/aoe_turf/smoke/tower - -//Level 2 -/datum/deity_item/boon/single_charge/knock - name = "Knock" - desc = "Allows a follower to open nearby doors without the keys." - base_cost = 25 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/aoe_turf/knock/tower - requirements = list(DEITY_TREE_TRANSMUTATION = 2) - -/datum/deity_item/boon/single_charge/burning_grip - name = "Burning Grip" - desc = "Allows a follower cause an object to heat up intensly in someone's hand, making them drop it and whatever skin is attached." - base_cost = 15 - boon_path = /spell/hand/burning_grip/tower - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 2) - -/datum/deity_item/phenomena/warp_body - name = "Phenomena: Warp Body" - desc = "Gain the ability to warp the very structure of a target's body, wracking pain and weakness." - base_cost = 75 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 2) - phenomena_path = /datum/phenomena/warp - -//Level 3 -/datum/deity_item/boon/single_charge/jaunt - name = "Ethereal Jaunt" - desc = "Allows a follower to liquify for a short duration, letting them pass through all dense objects." - base_cost = 25 - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/targeted/ethereal_jaunt/tower - requirements = list(DEITY_TREE_TRANSMUTATION = 3) - -/datum/deity_item/healing_spells - name = DEITY_UNLOCK_HEAL - desc = "Of transmutation, healing is perhaps the most immediately effective and useful. This unlocks the healing spells for your followers." - base_cost = 50 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 3) - category = DEITY_TREE_TRANSMUTATION - -/datum/deity_item/boon/single_charge/heal - name = "Minor Heal" - desc = "Allows your follower to heal themselves, or others, for a slight amount." - base_cost = 15 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_UNLOCK_HEAL = 1) - category = DEITY_TREE_TRANSMUTATION - boon_path = /spell/targeted/heal_target/tower - -/datum/deity_item/boon/single_charge/heal/major - name = "Major Heal" - desc = "Allows your follower to heal others for a great amount." - base_cost = 25 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_UNLOCK_HEAL = 1) - boon_path = /spell/targeted/heal_target/major/tower - -/datum/deity_item/boon/single_charge/heal/area - name = "Area Heal" - desc = "Allows your follower to heal everyone in an area for minor damage." - base_cost = 20 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_UNLOCK_HEAL = 1) - boon_path = /spell/targeted/heal_target/area/tower - -/datum/deity_item/phenomena/rock_form - name = "Phenomena: Rock Form" - desc = "Gain the ability to transform your followers into beings of rock and stone." - base_cost = 75 - category = DEITY_TREE_TRANSMUTATION - requirements = list(DEITY_TREE_TRANSMUTATION = 3) - phenomena_path = /datum/phenomena/rock_form \ No newline at end of file diff --git a/code/modules/mob/living/deity/menu/deity_nano.dm b/code/modules/mob/living/deity/menu/deity_nano.dm deleted file mode 100644 index 494b1942fd99..000000000000 --- a/code/modules/mob/living/deity/menu/deity_nano.dm +++ /dev/null @@ -1,81 +0,0 @@ -/mob/living/deity - var/menu_category - var/list/nano_data = list() - var/datum/phenomena/selected - -/mob/living/deity/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/uistate = GLOB.self_state) - if(!nano_data["categories"]) //If we don't have the categories set yet, we should populate our data. - var/list/categories = list() - for(var/cat in items_by_category) - categories += cat - nano_data["name"] = name - nano_data["form_name"] = form.name - nano_data["categories"] = categories - nano_data["menu"] = 0 //0 followers, 1 shop, 2 phenomena - nano_data["phenomenaMenu"] = 0 //0 Phenoms 1 Bindings - set_nano_category(0) - update_followers() - update_phenomenas() - update_phenomena_bindings() - else - update_category() - nano_data["power"] = power - nano_data["power_min"] = power_min - nano_data["regen"] = power_per_regen - ui = SSnano.try_update_ui(user, src, ui_key, ui, nano_data, force_open) - if(!ui) - ui = new(user, src, ui_key, "deity.tmpl", "Deity Menu", 650, 600, state = uistate) - ui.set_initial_data(nano_data) - ui.open() - ui.set_auto_update(TRUE) - -/mob/living/deity/proc/set_nano_category(var/num) - nano_data["category"] = num - update_category() - -/mob/living/deity/proc/update_category() - var/actual_cat = nano_data["categories"][nano_data["category"] + 1] - var/list/cat_items = items_by_category[actual_cat] - var/list/item_data = list() - for(var/item in cat_items) - var/datum/deity_item/di = item - item_data[++item_data.len] = list("name" = di.name, "desc" = di.desc, "requirements" = di.print_requirements(), "level" = di.print_level(), "cost" = di.get_cost(), "ref" = "\ref[di]") - nano_data["item_data"] = item_data - -/mob/living/deity/proc/update_followers() - var/list/follower_data = list() - for(var/m in minions) - var/list/minion_data = list() - var/datum/mind/mind = m - if(mind.current) - if(mind.current.stat != DEAD && mind.current.loc) - minion_data["ref"] = "\ref[mind.current]" - minion_data["name"] = "[mind.current.name]" - else - minion_data["name"] = mind.name - follower_data[++follower_data.len] = minion_data - nano_data["followers"] = follower_data - -/mob/living/deity/proc/update_phenomenas() - var/list/phenomena_data = list() - for(var/p in phenomenas) - var/datum/phenomena/P = phenomenas[p] - phenomena_data[++phenomena_data.len] = list("name" = p, "description" = P.desc, "cost" = P.cost, "cooldown" = P.cooldown) - nano_data["phenomenas"] = phenomena_data - -/mob/living/deity/proc/update_phenomena_bindings() - var/list/phenomena_bindings = list() - for(var/intent in intent_phenomenas) - var/list/intent_data = list() - for(var/binding in intent_phenomenas[intent]) - var/datum/phenomena/P = intent_phenomenas[intent][binding] - var/list/data = list() - if(P) - data["phenomena_name"] = P.name - data["binding"] = binding - intent_data[++intent_data.len] = data - phenomena_bindings[++phenomena_bindings.len] = list("intent" = intent, "intent_data" = intent_data) - nano_data["bindings"] = phenomena_bindings - //Update the hud as well. - var/obj/screen/intent/deity/SD = hud_used.action_intent - SD.update_text() \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/_defines.dm b/code/modules/mob/living/deity/phenomena/_defines.dm deleted file mode 100644 index e0268f37fa5c..000000000000 --- a/code/modules/mob/living/deity/phenomena/_defines.dm +++ /dev/null @@ -1,4 +0,0 @@ -#define PHENOMENA_NEAR_STRUCTURE 1 //Must be done near a structure -#define PHENOMENA_FOLLOWER 2 //Can be done on a follower -#define PHENOMENA_NONFOLLOWER 4 //Can be done on a nonfollower. -#define PHENOMENA_MUNDANE 8 //Can affect mundane (no mind, no client) things. \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/communication.dm b/code/modules/mob/living/deity/phenomena/communication.dm deleted file mode 100644 index 742d6c2c7065..000000000000 --- a/code/modules/mob/living/deity/phenomena/communication.dm +++ /dev/null @@ -1,80 +0,0 @@ -/datum/phenomena/communicate - name = "Direct Communication" - desc = "Communicate directly with a mortal being. You may communicate with non-followers, but they will find you easier to ignore." - cost = 0 - flags = PHENOMENA_FOLLOWER | PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomena/communicate/activate(var/mob/living/L) - var/text_to_send = sanitize(input(linked, "Subjugate a member to your will", "Message a Believer") as text) - if(text_to_send) - var/text_size = 4 - if(!linked.is_follower(L)) - text_size = 1 - to_chat(L, "[text_to_send]") //Note to self: make this go to ghosties - to_chat(linked, "You send the message [text_to_send] to \the [L]") - log_and_message_admins("communicated the message \"[text_to_send]\" to [key_name(L)]", linked) - -/datum/phenomena/point - name = "Point" - desc = "Attract your follower's attentions to something nearby." - cost = 0 - flags = PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /atom - var/image/arrow - -/datum/phenomena/point/activate(var/atom/a) - ..() - if(!arrow) - arrow = image('icons/mob/screen1.dmi', icon_state = "arrow", layer = POINTER_LAYER) - var/turf/T = get_turf(a) - arrow.loc = T - var/list/view = view(7,T) - for(var/m in linked.minions) - var/datum/mind/mind = m - if(mind.current) - var/mob/M = mind.current - if((M in view) && M.client) - to_chat(M, "Your attention is eerily drawn to \the [a].") - M.client.images += arrow - GLOB.logged_out_event.register(M, src, /datum/phenomena/point/proc/remove_image) - spawn(20) - if(M.client) - remove_image(M) - -/datum/phenomena/point/proc/remove_image(var/mob/living/L) - L.client.images -= arrow - GLOB.logged_out_event.unregister(L, src) - -/datum/phenomena/punish - name = "Punish" - desc = "Punish your followers for insubordination, the cost to use this phenomena is based on how deadly you choose the punishment to be." - cost = 0 - flags = PHENOMENA_FOLLOWER - expected_type = /mob/living - var/static/list/punishment_list = list("Pain (0)" = 0, "Light Wound (5)" = 5, "Brain Damage (10)" = 10, "Heavy Wounds (20)" = 20) - -/datum/phenomena/punish/activate(var/mob/living/L) - var/pain = input(linked, "Choose their punishment.", "Punishment") as null|anything in punishment_list - if(!pain) - return - if(punishment_list[pain] && linked.power < punishment_list[pain]) - to_chat(linked, "[pain] costs too much power for you to use on \the [L]") - return - ..() - linked.adjust_power(-punishment_list[pain]) - switch(pain) - if("Pain (0)") - L.adjustHalLoss(15) - to_chat(L, "You feel intense disappointment coming at you from beyond the veil.") - if("Light Wound (5)") - L.adjustBruteLoss(5) - to_chat(L, "You feel an ethereal whip graze your very soul!") - if("Brain Damage (10)") - L.adjustBrainLoss(5) - to_chat(L, "You feel your mind breaking under a otherwordly hammer...") - if("Heavy Wounds (20)") - L.adjustBruteLoss(25) - to_chat(L, "You feel your master turn its destructive potential against you!") - to_chat(linked, "You punish \the [L].") - log_admin("[key_name(linked)] used Punishment [pain] on \the [key_name(L)]") \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/conjuration.dm b/code/modules/mob/living/deity/phenomena/conjuration.dm deleted file mode 100644 index 81fc9fe4613d..000000000000 --- a/code/modules/mob/living/deity/phenomena/conjuration.dm +++ /dev/null @@ -1,82 +0,0 @@ -/datum/phenomena/movable_object/dimensional_locker - object_type = /obj/structure/closet - name = "Dimensional Locker" - cost = 10 - desc = "Summon a trans-dimensional locker anywhere within your influence. You may transport objects and things, but not people in it." - -/datum/phenomena/movable_object/dimensional_locker/activate(var/atom/a, var/mob/living/deity/user) - var/list/mobs_inside = list() - recursive_content_check(object_to_move, mobs_inside, client_check = 0, sight_check = 0, include_objects = 0) - - for(var/i in mobs_inside) - var/mob/M = i - M.dropInto(object_to_move.loc) - to_chat(M,"You are suddenly flung out of \the [object_to_move]!") - ..() - -/datum/phenomena/portals - name = "Portals" - desc = "Summon a portal linked to the last portal you've created. The portal will be destroyed if it is not linked when someone crosses it." - cost = 30 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /atom - var/list/portals = list() - -/datum/phenomena/portals/activate(var/atom/a, var/mob/living/deity/user) - ..() - var/obj/effect/portal/P = new(get_turf(a), null, 0) - P.failchance = 0 - portals += P - GLOB.destroyed_event.register(P,src,/datum/phenomena/portals/proc/remove_portal) - if(portals.len > 2) - var/removed = portals[1] - remove_portal(removed) - qdel(removed) - if(portals.len > 1) - var/obj/effect/portal/P1 = portals[1] - var/obj/effect/portal/P2 = portals[2] - P1.target = get_turf(P2) - P2.target = get_turf(P1) - -/datum/phenomena/portals/proc/remove_portal(var/portal) - portals -= portal - GLOB.destroyed_event.unregister(portal,src) - var/turf/T = get_turf(portal) - for(var/obj/effect/portal/P in portals) - if(P.target == T) - P.target = null - -/datum/phenomena/banishing_smite - name = "Banishing Smite" - desc = "Deal a terrible blow to a mortal. If they are hurt enough ,they will find themselves trapped in a rift for 30 seconds." - cost = 70 - cooldown = 300 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomena/banishing_smite/activate(var/mob/living/L, var/mob/living/deity/user) - ..() - L.take_overall_damage(rand(5,30),0,0,0,"blunt intrument") //Actual spell does 5d10 but maaaybe too much. - playsound(get_turf(L), 'sound/effects/bamf.ogg', 100, 1) - to_chat(L, "Something hard hits you!") - if(L.health < L.maxHealth/2) //If it reduces past 50% - var/obj/effect/rift/R = new(get_turf(L)) - L.visible_message("\The [L] is quickly sucked into \a [R]!") - L.forceMove(R) - spawn(300) - qdel(R) - -/obj/effect/rift - name = "rift" - desc = "a tear in space and time." - icon = 'icons/obj/wizard.dmi' - icon_state = "rift" - unacidable = 1 - anchored = 1 - density = 0 - -/obj/effect/rift/Destroy() - for(var/o in contents) - var/atom/movable/M = o - M.dropInto(loc) - . = ..() \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/conversion.dm b/code/modules/mob/living/deity/phenomena/conversion.dm deleted file mode 100644 index 1d2db472456f..000000000000 --- a/code/modules/mob/living/deity/phenomena/conversion.dm +++ /dev/null @@ -1,50 +0,0 @@ -/datum/phenomena/conversion - name = "Conversion" - desc = "Ask a non-follower to convert to your cult. This is completely voluntary. Requires the subject to be close to an altar." - cost = 20 - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomena/conversion/can_activate(var/atom/target) - if(!..()) - return 0 - var/is_good = 0 - for(var/obj/structure/deity/altar/A in linked.structures) - if(get_dist(target, A) < 2) - is_good = 1 - break - if(!is_good) - to_chat(linked,"\The [target] needs to be near \a [linked.get_type_name(/obj/structure/deity/altar)].") - return 0 - return 1 - -/datum/phenomena/conversion/activate(var/mob/living/L) - to_chat(src,"You give \the [L] a chance to willingly convert. May they choose wisely.") - var/choice = alert(L, "You feel a weak power enter your mind attempting to convert it.", "Conversion", "Allow Conversion", "Deny Conversion") - if(choice == "Allow Conversion") - GLOB.godcult.add_antagonist_mind(L.mind,1, "Servant of [linked]", "You willingly give your mind to it, may it bring you fortune", specific_god=linked) - else - to_chat(L, "With little difficulty you force the intrusion out of your mind. May it stay that way.") - to_chat(src, "\The [L] decides not to convert.") - -/datum/phenomena/forced_conversion - name = "Forced Conversion" - desc = "Force a non-follower to join you. They need to be on top of an altar and conscious for this to work. They may resist, but that will hurt them." - cost = 100 - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomena/forced_conversion/can_activate(var/mob/living/L) - if(!..()) - return 0 - var/obj/structure/deity/altar/A = locate() in get_turf(L) - if(!A || A.linked_god != linked) - to_chat(linked,"\The [L] needs to be on \a [linked.get_type_name(/obj/structure/deity/altar)] to be forcefully converted..") - return 0 - - return 1 - -/datum/phenomena/forced_conversion/activate(var/mob/living/L) - var/obj/structure/deity/altar/A = locate() in get_turf(L) - A.set_target(L) - to_chat(linked, "You imbue \the [A] with your power, setting forth to force \the [L] to your will.") \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/generic.dm b/code/modules/mob/living/deity/phenomena/generic.dm deleted file mode 100644 index 8d1586e4b118..000000000000 --- a/code/modules/mob/living/deity/phenomena/generic.dm +++ /dev/null @@ -1,36 +0,0 @@ -/datum/phenomena/movable_object - var/object_type - var/atom/movable/object_to_move - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /atom - -/datum/phenomena/movable_object/New() - ..() - add_object() - -/datum/phenomena/movable_object/Destroy() - GLOB.destroyed_event.unregister(object_to_move,src) - if(!object_to_move.loc) - QDEL_NULL(object_to_move) - . = ..() - -/datum/phenomena/movable_object/proc/add_object() - if(object_to_move) - GLOB.destroyed_event.unregister(object_to_move,src) - object_to_move = new object_type() - GLOB.destroyed_event.register(object_to_move, src, .proc/add_object) - -/datum/phenomena/movable_object/activate(var/atom/a, var/mob/living/deity/user) - ..() - if(object_to_move == a) - object_to_move.forceMove(null) //Move to null space - else - var/turf/T = get_turf(a) - //No dense turf/stuff - if(T.density) - return - for(var/i in T) - var/atom/A = i - if(A.density) - return - object_to_move.forceMove(T) \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/narsie.dm b/code/modules/mob/living/deity/phenomena/narsie.dm deleted file mode 100644 index 7fefa8daa3ac..000000000000 --- a/code/modules/mob/living/deity/phenomena/narsie.dm +++ /dev/null @@ -1,37 +0,0 @@ -/datum/phenomena/exhude_blood - name = "Exhude Blood" - desc = "Take pity on a follower, converting a pitance of your power into blood. Don't let them forget your mercy." - cost = 20 - flags = PHENOMENA_FOLLOWER - expected_type = /mob/living/carbon/human - -/datum/phenomena/exhude_blood/can_activate(var/mob/living/carbon/human/H) - if(!..()) - return 0 - - if(!H.should_have_organ(BP_HEART) || H.vessel.total_volume == H.species.blood_volume) - to_chat(linked, "\The [H] doesn't require anymore blood.") - return 0 - return 1 - -/datum/phenomena/exhude_blood/activate(var/mob/living/carbon/human/H, var/mob/living/deity/user) - H.vessel.add_reagent(H.species.blood_reagent, 30) - to_chat(H,"You feel a rush as new blood enters your system.") - - -/datum/phenomena/hellscape - name = "Reveal Hellscape" - desc = "Show a non-follower what awaits their souls after you are through with them." - cost = 60 - cooldown = 450 - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - var/static/list/creepy_notes = list("Your knees give out as an unnatural screaming rings your ears.", - "You breathe in ash and decay, your lungs gasping for air as your body gives way to the floor.", - "An extreme pressure comes over you, as if an unknown force has marked you.") - -/datum/phenomena/hellscape/activate(var/mob/living/L) - to_chat(L, "[pick(creepy_notes)]") - L.damageoverlaytemp = 100 - sound_to(L, 'sound/hallucinations/far_noise.ogg') - L.Weaken(2) \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/phenomena.dm b/code/modules/mob/living/deity/phenomena/phenomena.dm deleted file mode 100644 index 61311d119bf1..000000000000 --- a/code/modules/mob/living/deity/phenomena/phenomena.dm +++ /dev/null @@ -1,75 +0,0 @@ -/datum/phenomena - var/name = "Phenomena" - var/desc = "This has no desc." - var/cost = 0 - var/mob/living/deity/linked - var/flags = 0 - var/cooldown = 10 - var/refresh_time = 0 - var/expected_type - -/datum/phenomena/New(var/master) - linked = master - ..() - -/datum/phenomena/Destroy() - linked.remove_phenomena(src) - return ..() - -/datum/phenomena/proc/Click(var/atom/target) - if(can_activate(target)) - linked.adjust_power(-cost) - refresh_time = world.time + cooldown - activate(target) - -/datum/phenomena/proc/can_activate(var/atom/target) - if(!linked) - return 0 - if(refresh_time > world.time) - to_chat(linked, "\The [src] is still on cooldown for [round((refresh_time - world.time)/10)] more seconds!") - return 0 - - if(!linked.form) - to_chat(linked, "You must choose your form first!") - return 0 - - if(expected_type && !istype(target,expected_type)) - return 0 - - if(flags & PHENOMENA_NEAR_STRUCTURE) - if(!linked.near_structure(target, 1)) - to_chat(linked, "\The [target] needs to be near a holy structure for your powers to work!") - return 0 - - if(isliving(target)) - var/mob/living/L = target - if(!L.mind || !L.client) - if(!(flags & PHENOMENA_MUNDANE)) - to_chat(linked, "\The [L]'s mind is too mundane for you to influence.") - return 0 - else - if(linked.is_follower(target, silent = 1)) - if(!(flags & PHENOMENA_FOLLOWER)) - to_chat(linked, "You can't use [name] on the flock!") - return 0 - else if(!(flags & PHENOMENA_NONFOLLOWER)) - to_chat(linked, "You can't use [name] on non-believers.") - return 0 - - if(cost > linked.power) - to_chat(linked, "You need more power to use [name] (Need [cost] power, have [linked.power])!") - return 0 - - return 1 - -/datum/phenomena/proc/activate(var/target) - to_chat(linked, "You use the phenomena [name] on \the [target]") - log_and_message_admins("uses the phenomena [name] on \the [target]", linked, get_turf(target)) - return - -/datum/phenomena/proc/get_desc() - . = desc - if(cooldown) - . = "Cooldown: [cooldown/10] seconds. [.]" - if(cost) - . = "Cost: [cost] power. [.]" \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/starlight.dm b/code/modules/mob/living/deity/phenomena/starlight.dm deleted file mode 100644 index 0bf822db21c6..000000000000 --- a/code/modules/mob/living/deity/phenomena/starlight.dm +++ /dev/null @@ -1,232 +0,0 @@ -/datum/phenomena/herald - name = "Bestow Heraldry" - desc = "Turn one of your followers into a herald of your coming." - cost = 100 - cooldown = 60 SECONDS - flags = PHENOMENA_FOLLOWER - expected_type = /mob/living/carbon/human - var/static/list/possible_forms = list( - "Champion" = list("description" = "A protector of the faith. Fully protected by knightly armor, a Champion can shoot fire from their hands.", - "armor" = /obj/item/clothing/suit/armor/sunsuit, - "helm" = /obj/item/clothing/head/helmet/sunhelm, - "extension" = /datum/extension/deity_be_near/champion, - "spells" = list(/spell/hand/duration/sunwrath) - ), - "Oracle" = list("description" = "A preacher of the faith, the Oracle gives off heavenly light that they can use to heal followers and stun enemies.", - "armor" = /obj/item/clothing/suit/armor/sunrobe, - "extension" = /datum/extension/deity_be_near/oracle, - "spells" = list(/spell/targeted/glimpse_of_eternity) - ), - "Traitor" = list("description" = "Believers that reject the sun god's blessings, instead reveling in the shadows. Can turn invisible when its dark, and can move unprotected in space.", - "armor" = /obj/item/clothing/suit/space/shadowsuit, - "helm" = /obj/item/clothing/head/helmet/space/shadowhood, - "extension" = /datum/extension/deity_be_near/traitor, - "spells" = list(/spell/veil_of_shadows) - ) - ) - -/datum/phenomena/herald/can_activate(var/a) - if(!..()) - return FALSE - return valid_for_herald(a) - -/datum/phenomena/herald/proc/valid_for_herald(var/a) - var/mob/living/carbon/human/H = a - if(!istype(H)) - return FALSE - var/obj/item/I = H.get_equipped_item(slot_wear_suit) - if(I) - var/datum/extension/deity_be_near/dbn = get_extension(I, /datum/extension/deity_be_near) - if(dbn) - return FALSE - return TRUE - -/datum/phenomena/herald/proc/equip_slot(var/mob/living/L, var/slot_id, var/new_item) - var/equipped = L.get_inventory_slot(slot_id) - if(equipped) - L.unEquip(equipped, get_turf(L)) - L.equip_to_slot_if_possible(new_item, slot_id) - -/datum/phenomena/herald/Topic(var/href, var/list/href_list) - if(..()) - return 1 - if(usr != linked) - return 1 - - if(href_list["herald"]) - var/list/form = possible_forms[href_list["herald"]] - var/mob/living/L = locate(href_list["target"]) - var/turf/T = get_turf(L) - if(!L || !valid_for_herald(L) || !form) - return 1 - var/type = form["armor"] - var/obj/item/I = new type(T) - var/datum/extension/deity_be_near/extension = set_extension(I, form["extension"], linked) - L.equip_to_slot_or_store_or_drop(I, slot_wear_suit) - if(form["helm"]) - var/h_type = form["helm"] - var/obj/item/helm = new h_type(T) - L.equip_to_slot_or_store_or_drop(helm, slot_head) - extension.expected_helmet = helm.type //We only do by type because A. its easier to manage and B the chances of it being non-unique in a normal game is very small - if(form["weapon"]) - var/w_type = form["weapon"] - L.equip_to_slot_or_store_or_drop(new w_type(T), slot_r_hand) - if(form["spells"]) - for(var/s in form["spells"]) - var/spell/S = new s - S.set_connected_god(linked) - L.add_spell(S) - to_chat(L, "You have been chosen by your master to lead your fellow followers into the next age of rebirth.
    You have been granted powerful armor and a powerful spell. Don't lose them, as they are your key to your divinity and leadership.
    You also have particular sway over your deity's structures.
    ") - to_chat(linked, "\The [L] is now your herald!") - linked.remove_phenomena(name) - show_browser(linked, null, "window=herald") - -/datum/phenomena/herald/activate(var/mob/living/carbon/human/H) - var/list/html = list() - html += "

    Heralds

    " - html += "
    Pick the type of herald you want.
    " - html += "" - for(var/type in possible_forms) - var/list/form = possible_forms[type] - html += "" - html += "
    NameDescription
    [type][form["description"]]
    " - show_browser(linked, jointext(html,null), "window=herald") - -/datum/phenomena/create_gateway - name = "Create Gateway" - desc = "Creates a gateway from this world to the next. Gateways syphon absurd amounts of power but can be sacrificed to summon powerful minions." - cost = 200 - flags = PHENOMENA_NEAR_STRUCTURE - expected_type = /atom - -/datum/phenomena/create_gateway/can_activate(var/atom/a) - if(!..()) - return 0 - if(istype(a, /obj/structure/deity/gateway)) - var/obj/structure/deity/gateway/G = a - if(G.linked_god == linked) - return 1 - var/turf/T = get_turf(a) - if(!T || T.density) - return 0 - for(var/i in T) - var/atom/at = i - if(at.density) - return 0 - return 1 - -/datum/phenomena/create_gateway/activate(var/atom/a) - ..() - if(istype(a, /obj/structure/deity/gateway)) - qdel(a) - else - new /obj/structure/deity/gateway(get_turf(a), linked) - -/datum/phenomena/flickering_whisper - name = "Flickering Whisper" - desc = "Whisper to a non-believer, allowing you to intrude on their thoughts and see what they see." - flags = PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomena/flickering_whisper/activate(var/mob/living/L) - var/atom/whisper_from - for(var/obj/structure/deity/radiant_statue/rs in view(3, L)) - whisper_from = rs - break - var/message = sanitize(input(linked, "What is your message?", null) as null|text) - if(!linked || !message || QDELETED(src)) - return - to_chat(L, "[whisper_from ? "The [whisper_from] speaks to you" : "You hear a whisper say"] \"[message]\"") - - linked.eyenet.add_source(L) - GLOB.destroyed_event.register(L, src, .proc/deactivate_look) - addtimer(CALLBACK(src, .proc/deactivate_look, L), 30 SECONDS) - -/datum/phenomena/flickering_whisper/proc/deactivate_look(var/mob/viewer) - if(!linked.is_follower(viewer)) //Don't remove if they are follower - linked.eyenet.remove_source(viewer) - GLOB.destroyed_event.unregister(viewer, src) - -/datum/phenomena/burning_glare - name = "Burning Glare" - desc = "Burn a victim. If they are burnt enough, you'll set them ablaze." - cost = 100 - flags = PHENOMENA_NONFOLLOWER|PHENOMENA_NEAR_STRUCTURE - cooldown = 30 SECONDS - expected_type = /mob/living - -/datum/phenomena/burning_glare/activate(var/mob/living/L) - ..() - to_chat(L, "You feel yourself burn!") - L.adjustFireLoss(10) - if(L.getFireLoss() > 60) - L.fire_stacks += 50 - L.IgniteMob() - -/datum/phenomena/divine_right - name = "Divine Right" - desc = "Trigger your rebirth into the body of someone wearing a herald's uniform. This takes time, requires 3 open gateways, and if the body is destroyed during the ritual... so are you. But once complete, you become an unstoppable demigod of unnatural power." - cost = 300 - cooldown = 180 SECONDS - flags = PHENOMENA_FOLLOWER|PHENOMENA_NEAR_STRUCTURE - expected_type = /mob/living - -/datum/phenomena/divine_right/can_activate(var/mob/living/L) - if(!..()) - return FALSE - var/active_gateways = 0 - for(var/obj/structure/deity/gateway/G in linked.structures) - active_gateways += 1 - - if(active_gateways < 3) - to_chat(linked, "You do not have enough gateways activated.") - return FALSE - - var/obj/O = L.get_equipped_item(slot_wear_suit) - if(O && has_extension(O, /datum/extension/deity_be_near)) - var/datum/extension/deity_be_near/dbn = get_extension(O, /datum/extension/deity_be_near) - if(dbn.wearing_full()) - return TRUE - to_chat(linked, "\The [L] is not wearing a herald's uniform.") - return FALSE - -/datum/phenomena/divine_right/activate(var/mob/living/L) - ..() - to_chat(L, "Your soul is ripped from your body as your master prepares to possess it.") - to_chat(linked, "You prepare the body for possession. Keep it safe. If it is totally destroyed, you will die.") - L.ghostize() - L.Weaken(1) - new /obj/aura/starborn(L) - L.status_flags |= GODMODE - GLOB.destroyed_event.register(L,src,.proc/fail_ritual) - addtimer(CALLBACK(src, .proc/succeed_ritual, L), 600 SECONDS) //6 minutes - for(var/mob/living/player in GLOB.player_list) - sound_to(player, 'sound/effects/cascade.ogg') - if(player?.mind?.assigned_job?.is_holy) - to_chat(player, "Something bad is coming.... you know you don't have much time. Find and destroy the vessel, before its too late.") - else if(player != linked && !linked.is_follower(player, silent = 1)) - to_chat(player, "The world swims around you for just a moment... something is wrong. Very wrong.") - else - to_chat(player, "Your Master is being reborn into the body of \the [L]. Protect it at all costs.") - -/datum/phenomena/divine_right/proc/fail_ritual(var/mob/living/L) - qdel(linked) - -/datum/phenomena/divine_right/proc/succeed_ritual(var/mob/living/L) - to_chat(linked, "You have been reborn! Your power is limited here, focused on your body, but in return you are both eternal and physical.") - for(var/mob/living/player in GLOB.player_list) - sound_to(player, 'sound/effects/cascade.ogg') - to_chat(player, "\The [linked] has been born into flesh. Kneel to its authority or else.") - linked.mind.transfer_to(L) - L.SetName("[linked] Incarnate") - L.real_name = "[linked] Incarnate" - -/datum/phenomena/movable_object/wisp - name = "Wisp" - desc = "Creates or moves a small ball of light for your followers to use." - cost = 30 - object_type = /obj/item/flashlight/slime - -/datum/phenomena/movable_object/wisp/add_object() - ..() - object_to_move.SetName("wisp") \ No newline at end of file diff --git a/code/modules/mob/living/deity/phenomena/transmutation.dm b/code/modules/mob/living/deity/phenomena/transmutation.dm deleted file mode 100644 index 970986554bee..000000000000 --- a/code/modules/mob/living/deity/phenomena/transmutation.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/phenomena/warp - name = "Warp Body" - desc = "Corrupt a mortal being, causing their DNA to break and their body to fail on them." - cost = 90 - cooldown = 300 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_MUNDANE|PHENOMENA_FOLLOWER|PHENOMENA_NONFOLLOWER - expected_type = /mob/living - -/datum/phenomena/warp/activate(var/mob/living/L) - ..() - L.adjustCloneLoss(20) - L.Weaken(2) - to_chat(L, "You feel your body warp and change underneath you!") - -/datum/phenomena/rock_form - name = "Rock Form" - desc = "Convert your mortal followers into immortal stone beings." - cost = 300 - flags = PHENOMENA_NEAR_STRUCTURE|PHENOMENA_FOLLOWER - expected_type = /mob/living/carbon/human - -/datum/phenomena/rock_form/activate(var/mob/living/carbon/human/H) - ..() - to_chat(H, "You feel your body harden as it rapidly is transformed into living crystal!") - H.set_species(SPECIES_GOLEM) - H.Weaken(5) \ No newline at end of file diff --git a/code/modules/mob/living/deity/say.dm b/code/modules/mob/living/deity/say.dm deleted file mode 100644 index d1b84457b3b7..000000000000 --- a/code/modules/mob/living/deity/say.dm +++ /dev/null @@ -1,9 +0,0 @@ -/mob/living/deity/say(var/message, var/decl/language/speaking = null, var/verb="says", var/alt_name="") - if(!..()) - return 0 - if(pylon) - pylon.audible_message("\The [pylon] reverberates, \"[message]\"") - else - for(var/m in minions) - var/datum/mind/mind = m - to_chat(mind.current, "[message]") \ No newline at end of file diff --git a/code/modules/mob/living/human/death.dm b/code/modules/mob/living/human/death.dm new file mode 100644 index 000000000000..8f21775624ac --- /dev/null +++ b/code/modules/mob/living/human/death.dm @@ -0,0 +1,46 @@ +/mob/living/human/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..() + if(.) + for(var/obj/item/organ/I in get_internal_organs()) + remove_organ(I) + if(!QDELETED(I) && isturf(my_turf)) + I.dropInto(my_turf) + I.throw_at(get_edge_target_turf(I, pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) + for(var/obj/item/organ/external/E in get_external_organs()) + if(!E.parent_organ) + continue //Skip root organ + E.dismember(FALSE, DISMEMBER_METHOD_EDGE, TRUE, ignore_last_organ = TRUE) + if(my_turf) + E.dropInto(my_turf) + E.throw_at(get_edge_target_turf(E, pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) + +/mob/living/human/get_death_message(gibbed) + if(get_config_value(/decl/config/toggle/health_show_human_death_message)) + return species.get_species_death_message(src) || "seizes up and falls limp..." + return ..() + +/mob/living/human/death(gibbed) + if(!(. = ..())) + return + + BITSET(hud_updateflag, HEALTH_HUD) + BITSET(hud_updateflag, STATUS_HUD) + BITSET(hud_updateflag, LIFE_HUD) + + //Handle species-specific deaths. + handle_hud_list() + if(!gibbed) + set_tail_animation_state(null, TRUE) + handle_organs() + if(SSticker.mode) + SSticker.mode.check_win() + +/mob/living/human/physically_destroyed(var/skip_qdel, var/droplimb_type = DISMEMBER_METHOD_BLUNT) + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!limb.parent_organ) // don't dismember root + continue + limb.dismember(TRUE, droplimb_type, TRUE, TRUE) + dump_contents() + if(!skip_qdel && !QDELETED(src)) + qdel(src) diff --git a/code/modules/mob/living/human/descriptors/_descriptors.dm b/code/modules/mob/living/human/descriptors/_descriptors.dm new file mode 100644 index 000000000000..1cb122a1c051 --- /dev/null +++ b/code/modules/mob/living/human/descriptors/_descriptors.dm @@ -0,0 +1,170 @@ +/* + + Small, mechanically supported physical customisation options. + Also allows for per-species physical information ('his neck markings are more important than yours'). + ETA till a downstream ports this and adds boob and penis size: 2 days. UPDATE: still no penis sizes + + Descriptors are stored in species/human lists (appearance_descriptors) as a string key (name) indexed + to a value (either a personalized value or the shared datum on the species). The general pattern for + looking up descriptor data is to iterate the bodytype.appearance_descriptors list for the datum instances + and then check human.appearance_descriptors for the specific value the mob is using. + + This code is really noodly and can be tricky to follow in places. This is due to two different systems + of value comparison being used, one linear (height/build) and one with arbitrary values (age). + +*/ + +/mob/living/human/proc/show_descriptors_to(mob/user) + if(LAZYLEN(appearance_descriptors)) + var/decl/bodytype/bodytype = get_bodytype() + if(user == src) + for(var/entry in appearance_descriptors) + var/datum/appearance_descriptor/descriptor = bodytype.appearance_descriptors[entry] + LAZYADD(., "[descriptor.get_first_person_message_start()] [descriptor.get_standalone_value_descriptor(appearance_descriptors[descriptor.name])].") + else + for(var/entry in appearance_descriptors) + var/datum/appearance_descriptor/descriptor = bodytype.appearance_descriptors[entry] + LAZYADD(., descriptor.get_comparative_value_descriptor(appearance_descriptors[descriptor.name], user, src)) + +/datum/appearance_descriptor + var/name // String ident. Used to collect related datums into one category (ie. species overrides) and for saving. + var/chargen_label // String ident for chargen. + var/default_value // Initial value for this descriptor. + var/relative_value_comparison_multiplier = 1 // Used for examining similar properties between different species. + var/comparative_value_descriptor_equivalent // String for looking at someone with roughly the same property. + var/list/standalone_value_descriptors // String set for initial descriptor text. + var/list/comparative_value_descriptors_smaller // String set for looking at someone smaller than you. + var/list/comparative_value_descriptors_larger // String set for looking at someone larger than you. + var/list/chargen_value_descriptors // Used for chargen selection of values in cases where there is a hidden meaning. + var/chargen_min_index // Min value selectable in chargen. Defaults to 1. + var/chargen_max_index // Max value selectable in chargen. Defaults to size of descriptor list. + var/skip_species_mention // Set to true to ignore species descriptors when examining another species. + var/equivalent_variance_threshold = 0.1 // Variance % below this value will be treated as equivalent when examining another mob. + var/comparison_variance_multiplier = 0.75 // A multiplier applied to variance values to tighten them in a bit and allow for major cross-species variations to have more significant strings. + +/datum/appearance_descriptor/New(comparison_val = 1) + if(!isnull(comparison_val)) + relative_value_comparison_multiplier = comparison_val + if(!chargen_label) + chargen_label = name + if(!chargen_value_descriptors) + chargen_value_descriptors = list() + for(var/i = 1 to LAZYLEN(standalone_value_descriptors)) + chargen_value_descriptors[standalone_value_descriptors[i]] = i + if(isnull(chargen_min_index)) + chargen_min_index = 1 + if(isnull(chargen_max_index)) + chargen_max_index = LAZYLEN(standalone_value_descriptors) + set_default_value() + ..(null) + +/datum/appearance_descriptor/proc/set_default_value() + default_value = ceil(LAZYLEN(standalone_value_descriptors) * 0.5) + +/datum/appearance_descriptor/proc/get_mob_scale_adjustments(decl/bodytype/bodytype, offset_value) + return + +/datum/appearance_descriptor/proc/get_mob_appearance_overlay(mob/applying, offset_value) + return + +/datum/appearance_descriptor/proc/get_third_person_message_start(decl/pronouns/my_gender) + return "[my_gender.He] [my_gender.is]" + +/datum/appearance_descriptor/proc/get_first_person_message_start() + return "You are" + +/datum/appearance_descriptor/proc/get_standalone_value_descriptor(check_value) + if(isnull(check_value)) + check_value = default_value + else + check_value = get_index_from_value(check_value) + if(check_value && LAZYLEN(standalone_value_descriptors) >= check_value) + return standalone_value_descriptors[check_value] + +// Build a species-specific descriptor string. +/datum/appearance_descriptor/proc/get_species_text(use_name) + . = " for \a [use_name]" + +/datum/appearance_descriptor/proc/get_initial_comparison_component(mob/me, mob/them, decl/pronouns/my_gender, decl/pronouns/other_gender, my_value) + if(!skip_species_mention) + var/mob/living/human/H = me + var/mob/living/human/O = them + if(istype(H) && (!istype(O) || H.species.name != O.species.name)) + . = get_species_text("\improper [H.species.name]") + . = "[get_third_person_message_start(my_gender)] [get_standalone_value_descriptor(my_value)][.]" + +/datum/appearance_descriptor/proc/get_secondary_comparison_component(decl/pronouns/my_gender, decl/pronouns/other_gender, my_value, comparing_value) + var/variance = abs(1-(my_value/comparing_value)) * comparison_variance_multiplier + if(variance < equivalent_variance_threshold) + . = "[.], [get_comparative_value_string_equivalent(my_gender, other_gender)]" + else + if(my_value < comparing_value) + . = "[.], [get_comparative_value_string_smaller(variance, my_gender, other_gender)]" + else if(my_value > comparing_value) + . = "[.], [get_comparative_value_string_larger(variance, my_gender, other_gender)]" + +/datum/appearance_descriptor/proc/get_comparative_value_descriptor(my_value, mob/observer, mob/me) + + // Store our gender info for later. + var/decl/pronouns/my_gender = me.get_pronouns() + var/decl/pronouns/other_gender = observer.get_pronouns() + + . = get_initial_comparison_component(me, observer, my_gender, other_gender, my_value) + + // Append the same-descriptor comparison text. + var/comparing_value + if(ishuman(observer)) + var/mob/living/human/human_observer = observer + var/decl/bodytype/human_bodytype = human_observer?.get_bodytype() + if(LAZYLEN(human_observer.appearance_descriptors) && !isnull(human_bodytype.appearance_descriptors[name]) && !isnull(human_observer.appearance_descriptors[name])) + var/datum/appearance_descriptor/obs_descriptor = human_bodytype.appearance_descriptors[name] + comparing_value = human_observer.appearance_descriptors[name] * obs_descriptor.relative_value_comparison_multiplier + + if(. && !isnull(comparing_value)) + . = "[.][get_secondary_comparison_component(my_gender, other_gender, my_value * relative_value_comparison_multiplier, comparing_value)]" + + // We're done, add a full stop. + . = "[.]. " + +/datum/appearance_descriptor/proc/get_index_from_value(value) + return value + +/datum/appearance_descriptor/proc/get_comparative_value_string_equivalent(decl/pronouns/my_gender, decl/pronouns/other_gender) + return comparative_value_descriptor_equivalent + +/datum/appearance_descriptor/proc/get_comparative_value_string_smaller(value, decl/pronouns/my_gender, decl/pronouns/other_gender) + var/maxval = LAZYLEN(comparative_value_descriptors_smaller) + value = clamp(ceil(value * maxval), 1, maxval) + return comparative_value_descriptors_smaller[value] + +/datum/appearance_descriptor/proc/get_comparative_value_string_larger(value, decl/pronouns/my_gender, decl/pronouns/other_gender) + var/maxval = LAZYLEN(comparative_value_descriptors_larger) + value = clamp(ceil(value * maxval), 1, maxval) + return comparative_value_descriptors_larger[value] + +/datum/appearance_descriptor/proc/has_custom_value() + return FALSE + +/datum/appearance_descriptor/proc/randomize_value(limit_chargen = TRUE) + if(limit_chargen) + return rand(chargen_min_index, chargen_max_index) + return rand(1, LAZYLEN(standalone_value_descriptors)) + +/datum/appearance_descriptor/proc/get_value_from_index(value, chargen_bound = TRUE) + if(chargen_bound) + return clamp(round(value), chargen_min_index, chargen_max_index) + return clamp(round(value), 1, LAZYLEN(standalone_value_descriptors)) + +/datum/appearance_descriptor/proc/sanitize_value(value, chargen_bound = TRUE) + if(chargen_bound) + return clamp(round(value), get_min_chargen_value(), get_max_chargen_value()) + return clamp(round(value), 1, LAZYLEN(standalone_value_descriptors)) + +/datum/appearance_descriptor/proc/get_value_text(value) + . = "[value || "0"]" + +/datum/appearance_descriptor/proc/get_min_chargen_value() + return chargen_min_index + +/datum/appearance_descriptor/proc/get_max_chargen_value() + return chargen_max_index diff --git a/code/modules/mob/living/human/descriptors/descriptors_age.dm b/code/modules/mob/living/human/descriptors/descriptors_age.dm new file mode 100644 index 000000000000..4b574d9489c2 --- /dev/null +++ b/code/modules/mob/living/human/descriptors/descriptors_age.dm @@ -0,0 +1,65 @@ +/datum/appearance_descriptor/age + name = "age" + standalone_value_descriptors = list( + "an infant" = 1, + "a toddler" = 3, + "a child" = 7, + "a teenager" = 13, + "a young adult" = 17, + "an adult" = 25, + "middle-aged" = 40, + "aging" = 55, + "elderly" = 70 + ) + + chargen_min_index = 5 + chargen_max_index = 8 + comparative_value_descriptor_equivalent = "around the same age as you" + comparative_value_descriptors_smaller = list( + "somewhat younger than you", + "younger than you", + "much younger than you", + "a child compared to you" + ) + comparative_value_descriptors_larger = list( + "slightly older than you", + "older than you", + "much older than you", + "ancient compared to you" + ) + +/datum/appearance_descriptor/age/get_value_text(var/value) + . = "[value] year\s" + +/datum/appearance_descriptor/age/get_species_text(var/use_name) + . = " in [use_name] terms" + +/datum/appearance_descriptor/age/has_custom_value() + return TRUE + +/datum/appearance_descriptor/age/get_value_from_index(var/value, var/chargen_bound = TRUE) + var/age_key = standalone_value_descriptors[..()] + . = standalone_value_descriptors[age_key] + +/datum/appearance_descriptor/age/get_index_from_value(var/value) + for(var/i = 2 to length(standalone_value_descriptors)) + var/age_key = standalone_value_descriptors[i] + if(value < standalone_value_descriptors[age_key]) + return i-1 + return length(standalone_value_descriptors) + +/datum/appearance_descriptor/age/set_default_value() + default_value = standalone_value_descriptors[standalone_value_descriptors[chargen_min_index]] + +/datum/appearance_descriptor/age/sanitize_value(var/value, var/chargen_bound = TRUE) + if(!chargen_bound) + return clamp(round(value), standalone_value_descriptors[standalone_value_descriptors[1]], standalone_value_descriptors[standalone_value_descriptors[length(standalone_value_descriptors)]]) + return ..() + +/datum/appearance_descriptor/age/get_min_chargen_value() + var/age_key = standalone_value_descriptors[chargen_min_index] + return standalone_value_descriptors[age_key] + +/datum/appearance_descriptor/age/get_max_chargen_value() + var/age_key = standalone_value_descriptors[min(length(standalone_value_descriptors), chargen_max_index+1)] + . = standalone_value_descriptors[age_key]-1 diff --git a/code/modules/mob/living/human/descriptors/descriptors_body_length.dm b/code/modules/mob/living/human/descriptors/descriptors_body_length.dm new file mode 100644 index 000000000000..a7eb571cb5c1 --- /dev/null +++ b/code/modules/mob/living/human/descriptors/descriptors_body_length.dm @@ -0,0 +1,28 @@ +/datum/appearance_descriptor/body_length + name = "body length" + comparative_value_descriptor_equivalent = "around the same length as yours" + standalone_value_descriptors = list( + "short and stubby", + "rather short", + "of average length", + "quite long", + "extremely long" + ) + comparative_value_descriptors_smaller = list( + "a bit shorter in length than yours", + "shorter in length than yours", + "much shorter in length than yours", + "tiny in comparison to yours" + ) + comparative_value_descriptors_larger = list( + "slightly longer than yours", + "longer than yours", + "much longer than yours", + "easily twice your length" + ) + +/datum/appearance_descriptor/body_length/get_first_person_message_start() + return "Your body is" + +/datum/appearance_descriptor/body_length/get_third_person_message_start(var/decl/pronouns/my_gender) + return "[my_gender.His] body is" \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/descriptors/descriptors_generic.dm b/code/modules/mob/living/human/descriptors/descriptors_generic.dm similarity index 92% rename from code/modules/mob/living/carbon/human/descriptors/descriptors_generic.dm rename to code/modules/mob/living/human/descriptors/descriptors_generic.dm index 9c019b9de997..b7b946397419 100644 --- a/code/modules/mob/living/carbon/human/descriptors/descriptors_generic.dm +++ b/code/modules/mob/living/human/descriptors/descriptors_generic.dm @@ -1,4 +1,4 @@ -/datum/mob_descriptor/height +/datum/appearance_descriptor/height name = "height" standalone_value_descriptors = list( "very short", @@ -6,22 +6,22 @@ "of average height", "tall", "very tall" - ) + ) comparative_value_descriptor_equivalent = "around the same height as you" comparative_value_descriptors_smaller = list( "slightly shorter than you", "shorter than you", "much shorter than you", "tiny and insignificant next to you" - ) + ) comparative_value_descriptors_larger = list( "slightly taller than you", "taller than you", "much taller than you", "towering over you" - ) + ) -/datum/mob_descriptor/build +/datum/appearance_descriptor/build name = "build" comparative_value_descriptor_equivalent = "around the same build as you" standalone_value_descriptors = list( @@ -30,16 +30,16 @@ "of average build", "well-built", "heavily built" - ) + ) comparative_value_descriptors_smaller = list( "a bit smaller in build than you", "smaller in build than you", "much smaller in build than you", "dwarfed by your bulk" - ) + ) comparative_value_descriptors_larger = list( "slightly larger than you in build", "built larger than you", "built much larger than you", "dwarfing you" - ) + ) diff --git a/code/modules/mob/living/human/examine.dm b/code/modules/mob/living/human/examine.dm new file mode 100644 index 000000000000..3ea28d2aadad --- /dev/null +++ b/code/modules/mob/living/human/examine.dm @@ -0,0 +1,390 @@ +/mob/living/human/get_examine_header(mob/user, distance, infix, suffix, hideflags) + SHOULD_CALL_PARENT(FALSE) + . = list(SPAN_INFO("*---------*")) + var/list/mob_intro = "[user == src ? "You are" : "This is"] [name]" + if(!(hideflags & HIDEJUMPSUIT) || !(hideflags & HIDEFACE)) + var/species_name = "\improper " + if(isSynthetic() && species.cyborg_noun) + species_name += "[species.cyborg_noun] [species.name]" + else + species_name += "[species.name]" + mob_intro += ", \a [species_name]![(user.can_use_codex() && SScodex.get_codex_entry(get_codex_value(user))) ? SPAN_NOTICE(" \[?\]") : ""]" + . += SPAN_INFO(JOINTEXT(mob_intro)) + var/extra_species_text = species.get_additional_examine_text(src) + if(extra_species_text) + . += "[extra_species_text]" + var/show_descs = show_descriptors_to(user) + if(show_descs) + . += SPAN_INFO(jointext(show_descs, "
    ")) + var/print_flavour = print_flavor_text() + if(print_flavour) + . += SPAN_INFO("*---------*") + . += SPAN_INFO("[print_flavour]") + . += SPAN_INFO("*---------*") + . = list(jointext(., "
    ")) + +/decl/human_examination/jitters/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + var/jitteriness = GET_STATUS(source, STAT_JITTER) + switch(jitteriness) + if(300 to INFINITY) + return SPAN_DANGER("[pronouns.He] [pronouns.is] convulsing violently!") + if(200 to 300) + return SPAN_WARNING("[pronouns.He] [pronouns.is] extremely jittery.") + if(100 to 200) + return SPAN_WARNING("[pronouns.He] [pronouns.is] twitching ever so slightly.") + else + pass() + +/decl/human_examination/disfigured + priority = /decl/human_examination/jitters::priority + 1 + +/decl/human_examination/disfigured/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + //Disfigured face + if(hideflags & HIDEFACE) //Disfigurement only matters for the head currently. + return + var/obj/item/organ/external/limb = GET_EXTERNAL_ORGAN(source, BP_HEAD) + if(!limb || !(limb.status & ORGAN_DISFIGURED)) //Check to see if we even have a head and if the head's disfigured. + return + if(limb.species) //Check to make sure we have a species + return limb.species.disfigure_msg(source) + else //Just in case they lack a species for whatever reason. + return SPAN_WARNING("[pronouns.His] face is horribly mangled!") + +/decl/human_examination/stat + priority = /decl/human_examination/disfigured::priority + 1 + +/decl/human_examination/stat/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + if (source.stat) + . = list(SPAN_WARNING("[pronouns.He] [pronouns.is]n't responding to anything around [pronouns.him] and seems to be unconscious.")) + if((source.stat == DEAD || source.is_asystole() || source.suffocation_counter) && distance <= 3) + . += SPAN_WARNING("[pronouns.He] [pronouns.does] not appear to be breathing.") + +/decl/human_examination/contact_reagents + priority = /decl/human_examination/stat::priority + 1 + +/decl/human_examination/contact_reagents/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + var/datum/reagents/touching_reagents = source.get_contact_reagents() + if(REAGENT_TOTAL_VOLUME(touching_reagents) >= 1) + var/saturation = REAGENT_TOTAL_VOLUME(touching_reagents) / REAGENT_MAXIMUM_VOLUME(touching_reagents) + if(saturation > 0.9) + . += "[pronouns.He] [pronouns.is] completely saturated." + else if(saturation > 0.6) + . += "[pronouns.He] [pronouns.is] looking half-drowned." + else if(saturation > 0.3) + . += "[pronouns.He] [pronouns.is] looking notably soggy." + else + . += "[pronouns.He] [pronouns.is] looking a bit soggy." + +/decl/human_examination/fire + priority = /decl/human_examination/contact_reagents::priority + 1 + +/decl/human_examination/fire/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + . = list() + var/fire_level = source.get_fire_intensity() + if(fire_level > 0) + . += "[pronouns.He] [pronouns.is] looking highly flammable!" + else if(fire_level < 0) + . += "[pronouns.He] [pronouns.is] looking rather incombustible." + + if(source.is_on_fire()) + . += SPAN_WARNING("[pronouns.He] [pronouns.is] on fire!") + +/decl/human_examination/ssd + priority = /decl/human_examination/fire::priority + 1 + +/decl/human_examination/ssd/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + var/ssd_msg = source.species.get_ssd(source) + if(ssd_msg && (!source.should_have_organ(BP_BRAIN) || source.has_brain()) && source.stat != DEAD) + if(!source.key) + . += SPAN_DEADSAY("[pronouns.He] [pronouns.is] [ssd_msg]. It doesn't look like [pronouns.he] [pronouns.is] waking up anytime soon.") + else if(!source.client) + . += SPAN_DEADSAY("[pronouns.He] [pronouns.is] [ssd_msg].") + +// TODO: generalize and fold this into limb examine +/decl/human_examination/graffiti + priority = /decl/human_examination/ssd::priority + 1 + +/decl/human_examination/graffiti/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + var/obj/item/organ/external/head/H = source.get_organ(BP_HEAD, /obj/item/organ/external/head) + if(istype(H) && H.forehead_graffiti && H.graffiti_style) + . += SPAN_NOTICE("[pronouns.He] [pronouns.has] \"[H.forehead_graffiti]\" written on [pronouns.his] [H.name] in [H.graffiti_style]!") + +/decl/human_examination/limb_examine + priority = /decl/human_examination/graffiti::priority + 1 + +// This is still kind of a mess. TODO: /decl/organ_examination? lol +/decl/human_examination/limb_examine/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + . = list() + var/list/wound_flavor_text = list() + var/applying_pressure = "" + var/list/shown_objects = list() + var/list/hidden_bleeders = list() + + var/decl/bodytype/root_bodytype = source.get_bodytype() + for(var/organ_tag in root_bodytype.has_limbs) + var/list/organ_data = root_bodytype.has_limbs[organ_tag] + var/obj/item/organ/external/limb = GET_EXTERNAL_ORGAN(source, organ_tag) + + if(!limb) + wound_flavor_text[organ_tag] = list(SPAN_DANGER("[pronouns.He] [pronouns.is] missing [pronouns.his] [organ_data["descriptor"]].")) + continue + + wound_flavor_text[limb.organ_tag] = list() + + if(limb.applied_pressure == source) + applying_pressure = SPAN_INFO("[pronouns.He] [pronouns.is] applying pressure to [pronouns.his] [limb.name].") + + var/obj/item/clothing/hidden = source.get_covering_equipped_item(limb.body_part) + + if(hidden && user != source) + if(limb.status & ORGAN_BLEEDING && !(hidden.item_flags & ITEM_FLAG_THICKMATERIAL)) //not through a spacesuit + if(!hidden_bleeders[hidden]) + hidden_bleeders[hidden] = list() + hidden_bleeders[hidden] += limb.organ_tag + else + // TODO: Make this just report if the bodytype is different than root and parent? + // That way a robotic right arm would show up but the hand attached to it wouldn't. + if(!source.isSynthetic() && BP_IS_PROSTHETIC(limb) && (limb.parent && !BP_IS_PROSTHETIC(limb.parent))) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.He] [pronouns.has] a [limb.name].") + var/wounddesc = limb.get_wounds_desc() + if(wounddesc != "nothing") + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.He] [pronouns.has] [wounddesc] on [pronouns.his] [limb.name].") + if(!hidden || distance <=1) + if(limb.is_dislocated()) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.His] [limb.joint] is dislocated!") + if(((limb.status & ORGAN_BROKEN) && limb.brute_dam > limb.min_broken_damage) || (limb.status & ORGAN_MUTATED)) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.His] [limb.name] is dented and swollen!") + if(limb.status & ORGAN_DEAD) + if(BP_IS_PROSTHETIC(limb) || BP_IS_CRYSTAL(limb)) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.His] [limb.name] is irrecoverably damaged!") + else + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.His] [limb.name] is grey and necrotic!") + else if((limb.brute_dam + limb.burn_dam) >= limb.max_damage && limb.germ_level >= INFECTION_LEVEL_TWO) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.His] [limb.name] is likely beyond saving, and has begun to decay!") + + for(var/datum/wound/wound in limb.wounds) + var/list/embedlist = wound.embedded_objects + if(LAZYLEN(embedlist)) + shown_objects += embedlist + var/parsedembed[0] + for(var/obj/embedded in embedlist) + if(!parsedembed.len || (!parsedembed.Find(embedded.name) && !parsedembed.Find("multiple [embedded.name]"))) + parsedembed.Add(embedded.name) + else if(!parsedembed.Find("multiple [embedded.name]")) + parsedembed.Remove(embedded.name) + parsedembed.Add("multiple "+embedded.name) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("The [wound.desc] on [pronouns.his] [limb.name] has \a [english_list(parsedembed, and_text = " and a ", comma_text = ", a ")] sticking out of it!") + + if(limb.splinted && limb.splinted.loc == limb) + wound_flavor_text[limb.organ_tag] += SPAN_WARNING("[pronouns.He] [pronouns.has] \a [limb.splinted] on [pronouns.his] [limb.name]!") + + for(var/hidden in hidden_bleeders) + wound_flavor_text[hidden] = SPAN_WARNING("[pronouns.He] [pronouns.has] blood soaking through [hidden] around [pronouns.his] [english_list(hidden_bleeders[hidden])]!") + + for(var/section in wound_flavor_text) // originally named limb, but can also include clothes + if(length(wound_flavor_text[section])) + . += jointext(wound_flavor_text[section], "
    ") + + if(applying_pressure) + . += applying_pressure + + // TODO: move this into the limb for loop? + for(var/obj/implant in source.get_visible_implants(0)) + if(implant in shown_objects) + continue + . += SPAN_DANGER("[source] [pronouns.has] \a [implant.name] sticking out of [pronouns.his] flesh!") + +/decl/human_examination/digicamo + priority = /decl/human_examination/limb_examine::priority + 1 + +/decl/human_examination/digicamo/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + if(source.digitalcamo) + return SPAN_WARNING("[pronouns.He] [pronouns.is] repulsively uncanny!") + +/decl/human_examination/hud + priority = /decl/human_examination/digicamo::priority + 1 + +/decl/human_examination/hud/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + var/perpname = source.get_authentification_name(source.get_face_name()) + if(!perpname) + return + + if(hasHUD(user, HUD_SECURITY)) + var/datum/computer_network/network = user.getHUDnetwork(HUD_SECURITY) + if(network) + var/datum/computer_file/report/crew_record/R = network.get_crew_record_by_name(perpname) + LAZYINITLIST(.) + . += "Criminal status: \[[R?.get_criminalStatus() || "None"]\]" + . += "Security records: \[View\]" + + if(hasHUD(user, HUD_MEDICAL)) + var/datum/computer_network/network = user.getHUDnetwork(HUD_MEDICAL) + if(network) + var/datum/computer_file/report/crew_record/R = network.get_crew_record_by_name(perpname) + LAZYINITLIST(.) + . += "Physical status: \[[R?.get_status() || "None"]\]" + . += "Medical records: \[View\]" + +/decl/human_examination/pose + priority = /decl/human_examination/hud::priority + 1 + section_prefix = "*---------*" + +/decl/human_examination/pose/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + if (!source.pose) + return + var/treated_pose = trim(source.handle_autopunctuation(source.pose)) + // if the pose starts with is, are, do, does, or doesn't, apply basic verb correction + if(starts_with(treated_pose, "is ")) // if the pose starts with is + treated_pose = "[pronouns.is] [copytext(treated_pose, 1, 4)]" + if(starts_with(treated_pose, "are ")) // if the pose starts with are + treated_pose = "[pronouns.is] [copytext(treated_pose, 1, 5)]" + else if(starts_with(treated_pose, "does ")) + treated_pose = "[pronouns.does] [copytext(treated_pose, 1, 6)]" + else if(starts_with(treated_pose, "do ")) + treated_pose = "[pronouns.does] [copytext(treated_pose, 1, 4)]" + else if(starts_with(treated_pose, "doesn't ")) + treated_pose = "[pronouns.does]n't [copytext(treated_pose, 1, 9)]" + else if(starts_with(treated_pose, "don't ")) + treated_pose = "[pronouns.does]n't [copytext(treated_pose, 1, 7)]" + return "[pronouns.He] [source.handle_autopunctuation(source.pose)]" + +/decl/human_examination/comments + priority = /decl/human_examination/pose::priority + 99 // OOC info should show up pretty late. + section_prefix = "*---------*" + section_postfix = "*---------*" // this only applies if there is something after it + +/decl/human_examination/comments/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) + // Show IC/OOC info if available. + if(!source.comments_record_id) + return + var/datum/character_information/comments = SScharacter_info.get_record(source.comments_record_id) + if(comments?.show_info_on_examine && (comments.ic_info || comments.ooc_info)) + if(comments.ic_info) + if(length(comments.ic_info) <= 40) + . += "IC Info:" + . += "    [comments.ic_info]" + else + . += "IC Info:" + . += "    [copytext_preserve_html(comments.ic_info,1,37)]... More..." + if(comments.ooc_info) + if(length(comments.ooc_info) <= 40) + . += "OOC Info:" + . += "    [comments.ooc_info]" + else + . += "OOC Info:" + . += "    [copytext_preserve_html(comments.ooc_info,1,37)]... More..." + +/mob/living/human/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = ..() + var/static/list/priority_examine_decls = sortTim(decls_repository.get_decls_of_subtype_unassociated(/decl/human_examination), /proc/cmp_human_examine_priority) + var/last_divider = null + for(var/decl/human_examination/examiner in priority_examine_decls) + var/adding_text = examiner.do_examine(user, distance, src, hideflags, pronouns) + if(!LAZYLEN(adding_text)) + continue + if(last_divider) // insert the divider from the last entry + . += last_divider + else if(length(.) && examiner.section_prefix) // we already have prior entries, insert our prefix + . += examiner.section_prefix + . += adding_text + last_divider = examiner.section_postfix + +/mob/living/human/examined_by(mob/user, distance, infix, suffix) + . = ..() + if(!stat || !ishuman(user) || user.incapacitated() || !Adjacent(user)) + return + INVOKE_ASYNC(src, PROC_REF(check_heartbeat), user) + +/mob/living/human/proc/check_heartbeat(mob/living/human/user) + if(!stat || !ishuman(user) || user.incapacitated() || !Adjacent(user)) + return + user.visible_message("\The [user] checks \the [src]'s pulse.", "You check \the [src]'s pulse.") + if(do_after(user, 1.5 SECONDS, src)) + var/decl/pronouns/seen_pronouns = get_pronouns() + if(get_pulse() == PULSE_NONE) + to_chat(user, SPAN_DEADSAY("[seen_pronouns.He] [seen_pronouns.has] no pulse.")) + else + to_chat(user, SPAN_DEADSAY("[seen_pronouns.He] [seen_pronouns.has] a pulse!")) + +//Helper procedure. Called by /mob/living/human/examined_by() and /mob/living/human/Topic() to determine HUD access to security and medical records. +/proc/hasHUD(mob/M, hudtype) + return !!M.getHUDsource(hudtype) + +/mob/proc/getHUDsource(hudtype) + return + +/mob/living/human/getHUDsource(hudtype) + var/obj/item/clothing/glasses/glasses = get_equipped_item(slot_glasses_str) + if(!istype(glasses)) + return ..() + if(glasses.glasses_hud_type & hudtype) + return glasses + if(glasses.hud && (glasses.hud.glasses_hud_type & hudtype)) + return glasses.hud + +/mob/living/silicon/robot/getHUDsource(hudtype) + for(var/obj/item/borg/sight/sight in get_held_items()) + if(istype(sight) && (sight.glasses_hud_type & hudtype)) + return sight + +//Gets the computer network M's source of hudtype is using +/mob/proc/getHUDnetwork(hudtype) + var/obj/O = getHUDsource(hudtype) + if(!O) + return + var/datum/extension/network_device/D = get_extension(O, /datum/extension/network_device) + return D.get_network() + +/mob/living/silicon/getHUDnetwork(hudtype) + if(getHUDsource(hudtype)) + return get_computer_network() + +/mob/living/human/verb/pose() + set name = "Set Pose" + set desc = "Sets a description which will be shown when someone examines you." + set category = "IC" + + var/decl/pronouns/pronouns = get_pronouns() + pose = sanitize(input(usr, "This is [src]. [pronouns.He]...", "Pose", null) as text) + +/mob/living/human/verb/set_flavor() + set name = "Set Flavour Text" + set desc = "Sets an extended description of your character's features." + set category = "IC" + + var/list/HTML = list() + HTML += "" + HTML += "
    " + HTML += "Update Flavour Text
    " + HTML += "
    " + HTML += "General: " + HTML += TextPreview(flavor_texts["general"]) + HTML += "
    " + HTML += "Head: " + HTML += TextPreview(flavor_texts["head"]) + HTML += "
    " + HTML += "Face: " + HTML += TextPreview(flavor_texts["face"]) + HTML += "
    " + HTML += "Eyes: " + HTML += TextPreview(flavor_texts["eyes"]) + HTML += "
    " + HTML += "Body: " + HTML += TextPreview(flavor_texts["torso"]) + HTML += "
    " + HTML += "Arms: " + HTML += TextPreview(flavor_texts["arms"]) + HTML += "
    " + HTML += "Hands: " + HTML += TextPreview(flavor_texts["hands"]) + HTML += "
    " + HTML += "Legs: " + HTML += TextPreview(flavor_texts["legs"]) + HTML += "
    " + HTML += "Feet: " + HTML += TextPreview(flavor_texts["feet"]) + HTML += "
    " + HTML += "
    " + HTML +="\[Done\]" + HTML += "" + show_browser(src, jointext(HTML,null), "window=flavor_changes;size=430x300") diff --git a/code/modules/mob/living/human/human.dm b/code/modules/mob/living/human/human.dm new file mode 100644 index 000000000000..00c520947984 --- /dev/null +++ b/code/modules/mob/living/human/human.dm @@ -0,0 +1,1154 @@ +/mob/living/human + name = "unknown" + real_name = "unknown" + icon = 'icons/mob/human.dmi' + icon_state = "body_m_s" + mob_sort_value = 6 + max_health = 150 + var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. + +/mob/living/human/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + + // Health is dynamically calculated from organ state, so no point keeping a + // serialized or modified value, it will be recalculated almost immediately. + current_health = get_max_health() + species_uid ||= species // Pass our current species in as an arg (in case of serde) + reset_hud_overlays() + var/list/newargs = args.Copy(2) + setup_human(arglist(newargs)) + global.human_mob_list |= src + + if(!bloodstr) + bloodstr = new/datum/reagents/metabolism(120, src, CHEM_INJECT) + if(!reagents) + reagents = bloodstr + if(!touching) + touching = new/datum/reagents/metabolism(mob_size * 100, src, CHEM_TOUCH) + + if (!default_language && species_language) + default_language = species_language + + . = ..() + + if(. != INITIALIZE_HINT_QDEL) + post_setup(arglist(newargs)) + +/mob/living/human/Destroy() + global.human_mob_list -= src + regenerate_body_icon = FALSE // don't bother regenerating if we happen to be queued to update icon + worn_underwear = null + + LAZYCLEARLIST(smell_cooldown) + + QDEL_NULL(vessel) + QDEL_NULL(touching) + + if(reagents == bloodstr) + bloodstr = null + else + QDEL_NULL(bloodstr) + + if(loc) + for(var/mob/M in contents) + M.dropInto(loc) + else + for(var/mob/M in contents) + qdel(M) + return ..() + +/mob/living/human/get_ingested_reagents() + if(!should_have_organ(BP_STOMACH)) + return + var/obj/item/organ/internal/stomach/stomach = get_organ(BP_STOMACH) + return stomach?.ingested + +/mob/living/human/get_inhaled_reagents() + if(!should_have_organ(BP_LUNGS)) + return + var/obj/item/organ/internal/lungs/lungs = get_organ(BP_LUNGS) + return lungs?.inhaled + +/mob/living/human/Stat() + . = ..() + if(statpanel("Status")) + + var/obj/item/gps/gps = get_active_held_item() + if(istype(gps)) + stat("Coordinates:", "[gps.get_coordinates()]") + + stat("Intent:", "[get_intent().name]") + stat("Move Mode:", "[move_intent.name]") + + if(SSevac.evacuation_controller) + var/eta_status = SSevac.evacuation_controller.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + + if (istype(internal)) + if (!internal.air_contents) + qdel(internal) + else + stat("Internal Atmosphere Info", internal.name) + stat("Tank Pressure", internal.air_contents.return_pressure()) + stat("Distribution Pressure", internal.distribute_pressure) + + var/obj/item/organ/internal/cell/potato = get_organ(BP_CELL, /obj/item/organ/internal/cell) + if(potato?.cell) + stat("Battery charge:", "[potato.get_charge()]/[potato.cell.maxcharge]") + + var/obj/item/rig/rig = get_rig() + if(rig) + var/cell_status = "ERROR" + if(rig.cell) + cell_status = "[rig.cell.charge]/[rig.cell.maxcharge]" + stat(null, "Hardsuit charge: [cell_status]") + +/mob/living/human/proc/implant_loyalty(mob/living/human/victim, override = FALSE) // Won't override by default. + if(!get_config_value(/decl/config/toggle/use_loyalty_implants) && !override) + return // Nuh-uh. + + var/obj/item/implant/loyalty/loyalty_implant = new/obj/item/implant/loyalty(victim) + loyalty_implant.imp_in = victim + loyalty_implant.implanted = TRUE + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(victim, BP_HEAD) + LAZYDISTINCTADD(affected.implants, loyalty_implant) + loyalty_implant.part = affected + loyalty_implant.implanted(src) + +/mob/living/human/proc/is_loyalty_implanted(mob/living/human/victim) + for(var/obj/item/implant/loyalty/loyalty_implant in victim.contents) + // Make sure the implant is actually implanted in the expected part, + // and that the part is in the victim (should always be, but just in case) + if(victim.get_organ(loyalty_implant.part?.organ_tag) == loyalty_implant.part) + return TRUE + return FALSE + +/mob/living/human/get_additional_stripping_options() + . = ..() + for(var/entry in worn_underwear) + var/obj/item/underwear/UW = entry + LAZYADD(., "
    Remove \the [UW]") + +/mob/living/human/OnSelfTopic(href_list) + if (href_list["lookitem"]) + var/obj/item/I = locate(href_list["lookitem"]) + if(I) + src.examine_verb(I) + return TOPIC_HANDLED + + if (href_list["lookmob"]) + var/mob/M = locate(href_list["lookmob"]) + if(M) + src.examine_verb(M) + return TOPIC_HANDLED + + return ..() + +/mob/living/human/CanUseTopic(mob/user, datum/topic_state/state, href_list) + . = ..() + if(href_list && (href_list["refresh"] || href_list["item"])) + return min(., ..(user, global.physical_topic_state, href_list)) + +/mob/living/human/OnTopic(mob/user, href_list) + if (href_list["criminal"]) + if(hasHUD(user, HUD_SECURITY)) + + var/modified = 0 + var/perpname = "wot" + var/obj/item/id = get_equipped_item(slot_wear_id_str) + if(id) + var/obj/item/card/id/I = id.GetIdCard() + if(I) + perpname = I.registered_name + else + perpname = name + else + perpname = name + + var/datum/computer_network/network = user.getHUDnetwork(HUD_SECURITY) + if(!network) + return TOPIC_HANDLED + var/datum/computer_file/report/crew_record/R = network.get_crew_record_by_name(perpname) + if(R) + var/setcriminal = input(user, "Specify a new criminal status for this person.", "Security HUD", R.get_criminalStatus()) as null|anything in global.security_statuses + if(hasHUD(user, HUD_SECURITY) && setcriminal) + R.set_criminalStatus(setcriminal) + modified = 1 + + spawn() + BITSET(hud_updateflag, WANTED_HUD) + if(ishuman(user)) + var/mob/living/human/U = user + U.handle_regular_hud_updates() + if(isrobot(user)) + var/mob/living/silicon/robot/U = user + U.handle_regular_hud_updates() + + if(!modified) + to_chat(user, "Unable to locate a data core entry for this person.") + return TOPIC_HANDLED + + if (href_list["secrecord"]) + if(hasHUD(user, HUD_SECURITY)) + var/perpname = "wot" + var/read = 0 + + var/obj/item/card/id/id = GetIdCard() + if(istype(id)) + perpname = id.registered_name + else + perpname = src.name + var/datum/computer_network/network = user.getHUDnetwork(HUD_SECURITY) + if(!network) + return TOPIC_HANDLED + var/datum/computer_file/report/crew_record/E = network.get_crew_record_by_name(perpname) + if(E) + if(hasHUD(user, HUD_SECURITY)) + to_chat(user, "Name: [E.get_name()]") + to_chat(user, "Criminal Status: [E.get_criminalStatus()]") + to_chat(user, "Details: [E.get_security_record()]") + read = 1 + + if(!read) + to_chat(user, "Unable to locate a data core entry for this person.") + return TOPIC_HANDLED + + if (href_list["medical"]) + if(hasHUD(user, HUD_MEDICAL)) + var/perpname = "wot" + var/modified = 0 + + var/obj/item/card/id/id = GetIdCard() + if(istype(id)) + perpname = id.registered_name + else + perpname = src.name + + var/datum/computer_network/network = user.getHUDnetwork(HUD_MEDICAL) + if(!network) + return TOPIC_HANDLED + var/datum/computer_file/report/crew_record/E = network.get_crew_record_by_name(perpname) + if(E) + var/setmedical = input(user, "Specify a new medical status for this person.", "Medical HUD", E.get_status()) as null|anything in global.physical_statuses + if(hasHUD(user, HUD_MEDICAL) && setmedical) + E.set_status(setmedical) + modified = 1 + + spawn() + if(ishuman(user)) + var/mob/living/human/U = user + U.handle_regular_hud_updates() + if(isrobot(user)) + var/mob/living/silicon/robot/U = user + U.handle_regular_hud_updates() + + if(!modified) + to_chat(user, "Unable to locate a data core entry for this person.") + return TOPIC_HANDLED + + if (href_list["medrecord"]) + if(hasHUD(user, HUD_MEDICAL)) + var/perpname = "wot" + var/read = 0 + + var/obj/item/card/id/id = GetIdCard() + if(istype(id)) + perpname = id.registered_name + else + perpname = src.name + + var/datum/computer_network/network = user.getHUDnetwork(HUD_MEDICAL) + if(!network) + return TOPIC_HANDLED + var/datum/computer_file/report/crew_record/E = network.get_crew_record_by_name(perpname) + if(E) + if(hasHUD(user, HUD_MEDICAL)) + to_chat(user, "Name: [E.get_name()]") + to_chat(user, "Gender: [E.get_gender()]") + to_chat(user, "Species: [E.get_species_name()]") + to_chat(user, "Blood Type: [E.get_bloodtype()]") + to_chat(user, "Details: [E.get_medical_record()]") + read = 1 + if(!read) + to_chat(user, "Unable to locate a data core entry for this person.") + return TOPIC_HANDLED + + return ..() + +/mob/living/human/update_flavor_text(key) + var/msg + switch(key) + if("done") + show_browser(src, null, "window=flavor_changes") + return + if("general") + msg = sanitize(input(src,"Update the general description of your character. This will be shown regardless of clothing. Do not include OOC information here.","Flavor Text",html_decode(flavor_texts[key])) as message, extra = 0) + else + if(!(key in flavor_texts)) + return + msg = sanitize(input(src,"Update the flavor text for your [key].","Flavor Text",html_decode(flavor_texts[key])) as message, extra = 0) + if(!CanInteract(src, global.self_topic_state)) + return + flavor_texts[key] = msg + set_flavor() + +/mob/living/human/abiotic(var/full_body = TRUE) + if(full_body) + for(var/slot in list(slot_head_str, slot_shoes_str, slot_w_uniform_str, slot_wear_suit_str, slot_glasses_str, slot_l_ear_str, slot_r_ear_str, slot_gloves_str)) + if(get_equipped_item(slot)) + return FALSE + return ..() + +/mob/living/human/empty_stomach() + SET_STATUS_MAX(src, STAT_STUN, 3) + + var/obj/item/organ/internal/stomach/stomach = get_organ(BP_STOMACH, /obj/item/organ/internal/stomach) + var/nothing_to_puke = FALSE + if(should_have_organ(BP_STOMACH)) + if(!stomach || (REAGENT_TOTAL_VOLUME(stomach.ingested) <= 0 && stomach.contents.len == 0)) + nothing_to_puke = TRUE + else if(!(locate(/mob) in contents)) + nothing_to_puke = TRUE + + if(nothing_to_puke) + custom_emote(1,"dry heaves.") + return + + if(should_have_organ(BP_STOMACH)) + for(var/a in stomach.contents) + var/atom/movable/A = a + A.dropInto(get_turf(src)) + if(species.gluttonous & GLUT_PROJECTILE_VOMIT) + A.throw_at(get_edge_target_turf(src,dir),7,7,src) + else + for(var/mob/M in contents) + M.dropInto(get_turf(src)) + if(species.gluttonous & GLUT_PROJECTILE_VOMIT) + M.throw_at(get_edge_target_turf(src,dir),7,7,src) + + visible_message(SPAN_DANGER("\The [src] throws up!"),SPAN_DANGER("You throw up!")) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + var/turf/location = loc + if(istype(location) && location.simulated) + var/obj/effect/decal/cleanable/vomit/splat = new /obj/effect/decal/cleanable/vomit(location) + if(REAGENT_TOTAL_VOLUME(stomach.ingested)) + stomach.ingested.trans_to_obj(splat, min(15, REAGENT_TOTAL_VOLUME(stomach.ingested))) + handle_additional_vomit_reagents(splat) + splat.update_icon() + +/mob/living/human/proc/vomit(var/timevomit = 1, var/level = 3, var/deliberate = FALSE) + + set waitfor = FALSE + + if(!check_has_mouth() || isSynthetic() || !timevomit || !level || stat == DEAD || lastpuke) + return + + if(deliberate) + if(incapacitated()) + to_chat(src, SPAN_WARNING("You cannot do that right now.")) + return + var/decl/pronouns/pronouns = get_pronouns() + visible_message(SPAN_DANGER("\The [src] starts sticking a finger down [pronouns.his] own throat. It looks like [pronouns.he] [pronouns.is] trying to throw up!")) + if(!do_after(src, 3 SECONDS)) + return + timevomit = max(timevomit, 5) + + timevomit = clamp(timevomit, 1, 10) + level = clamp(level, 1, 3) + + lastpuke = TRUE + to_chat(src, SPAN_WARNING("You feel nauseous...")) + var/finish_time = 35 SECONDS + if(level > 1) + // 15 seconds until second warning + addtimer(CALLBACK(src, PROC_REF(vomit_second_warning_message)), 15 SECONDS / timevomit) + finish_time += 15 SECONDS / timevomit + if(level > 2) + // and you have 10 more for mad dash to the bucket + // timer delay must include the time from the prior one also + addtimer(CALLBACK(src, PROC_REF(empty_stomach)), 25 SECONDS / timevomit) + finish_time += 10 SECONDS / timevomit + addtimer(CALLBACK(src, PROC_REF(reset_vomit_cooldown)), finish_time) + +/mob/living/human/proc/vomit_second_warning_message() + to_chat(src, SPAN_WARNING("You feel like you are about to throw up!")) + +/mob/living/human/proc/reset_vomit_cooldown() + lastpuke = FALSE + +/mob/living/human/proc/increase_germ_level(n) + var/obj/item/gloves = get_equipped_item(slot_gloves_str) + if(gloves) + gloves.germ_level += n + else + germ_level += n + +/mob/living/human/revive() + get_bodytype().create_missing_organs(src) // Reset our organs/limbs. + restore_all_organs() // Reapply robotics/amputated status from preferences. + reset_blood() + if(!client || !key) //Don't boot out anyone already in the mob. + for(var/mob/living/brain/brain in global.player_list) // This is really nasty, does it even work anymore? + if(brain.real_name == src.real_name && brain.mind) + brain.mind.transfer_to(src) + qdel(brain.loc) + break + suffocation_counter = 0 + ..() + +/mob/living/add_blood(mob/living/M, amount = 2, list/blood_data) + if (!..()) + return 0 + var/bloodied + for(var/obj/item/organ/external/grabber in get_hands_organs()) + bloodied |= grabber.add_blood(M, amount, blood_data) + if(bloodied) + update_equipment_overlay(slot_gloves_str) //handles bloody hands overlays and updating + verbs += /mob/living/human/proc/bloody_doodle + return 1 //we applied blood to the item + +/mob/living/human/get_visible_implants(var/class = 0) + + var/list/visible_implants = list() + for(var/obj/item/organ/external/organ in get_external_organs()) + for(var/obj/item/O in organ.implants) + if(!istype(O,/obj/item/implant) && (O.w_class > class) && !istype(O,/obj/item/shard/shrapnel)) + visible_implants += O + + return(visible_implants) + +/mob/living/human/embedded_needs_process() + for(var/obj/item/organ/external/organ in src.get_external_organs()) + for(var/obj/item/O in organ.implants) + if(!istype(O, /obj/item/implant)) //implant type items do not cause embedding effects, see handle_embedded_objects() + return 1 + return 0 + +/mob/living/human/handle_embedded_and_stomach_objects() + + if(embedded_flag) + for(var/obj/item/organ/external/organ in get_external_organs()) + if(organ.splinted) + continue + for(var/obj/item/O in organ.implants) + if(!istype(O,/obj/item/implant) && O.w_class > ITEM_SIZE_TINY && prob(5)) //Moving with things stuck in you could be bad. + jostle_internal_object(organ, O) + + var/obj/item/organ/internal/stomach/stomach = get_organ(BP_STOMACH, /obj/item/organ/internal/stomach) + if(stomach && stomach.contents.len) + for(var/obj/item/O in stomach.contents) + if((O.is_sharp() || O.has_edge()) && prob(5)) + var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(src, stomach.parent_organ) + if(prob(1) && can_feel_pain() && O.can_embed()) + to_chat(src, SPAN_DANGER("You feel something rip out of your [stomach.name]!")) + O.dropInto(loc) + if(parent) + parent.embed_in_organ(O) + else + jostle_internal_object(parent, O) + +/mob/living/human/proc/jostle_internal_object(var/obj/item/organ/external/organ, var/obj/item/O) + // All kinds of embedded objects cause bleeding. + if(!organ.can_feel_pain()) + to_chat(src, SPAN_DANGER("You feel [O] moving inside your [organ.name].")) + else + var/msg = pick( \ + SPAN_DANGER("A spike of pain jolts your [organ.name] as you bump [O] inside."), \ + SPAN_DANGER("Your movement jostles [O] in your [organ.name] painfully."), \ + SPAN_DANGER("Your movement jostles [O] in your [organ.name] painfully.")) + custom_pain(msg,40,affecting = organ) + organ.take_damage(rand(1,3) + O.w_class, damage_flags = DAM_EDGE) + +/mob/proc/set_bodytype(var/decl/bodytype/new_bodytype) + return + +/mob/living/human/set_bodytype(var/decl/bodytype/new_bodytype) + + var/decl/bodytype/old_bodytype = get_bodytype() + if(ispath(new_bodytype)) + new_bodytype = GET_DECL(new_bodytype) + // No check to see if it's the same as our current one, because we don't have a 'mob bodytype' anymore + // just the torso. It's assumed if we call this we want a full regen. + if(!istype(new_bodytype)) + return FALSE + + mob_size = new_bodytype.mob_size + new_bodytype.create_missing_organs(src, TRUE) // actually rebuild the body + if(istype(old_bodytype)) + old_bodytype.remove_abilities(src) + new_bodytype.grant_abilities(src) + apply_bodytype_appearance() + force_update_limbs() + update_hair() + update_eyes() + return TRUE + +/mob/proc/set_species(var/new_species_uid, var/new_bodytype = null) + return + +//set_species should not handle the entirety of initing the mob, and should not trigger deep updates +//It focuses on setting up species-related data, without force applying them uppon organs and the mob's appearance. +// For transforming an existing mob, look at change_species() +/mob/living/human/set_species(var/new_species_uid, var/new_bodytype = null) + if(!new_species_uid) + CRASH("set_species on mob '[src]' was passed a null species uid!") + var/decl/species/new_species = decls_repository.get_decl_by_id(new_species_uid) + if(species?.uid == new_species_uid) + return + if(!new_species) + CRASH("set_species on mob '[src]' was passed a bad species uid '[new_species_uid]'!") + + //Handle old species transition + if(species) + species.remove_inherent_verbs(src) + + //Update our species + species = new_species + holder_type = null + if(species.holder_type) + holder_type = species.holder_type + set_max_health(species.total_health, skip_health_update = TRUE) // Health update is handled later. + apply_species_appearance() + + var/decl/pronouns/new_pronouns = get_pronouns_by_gender(get_gender()) + if(!istype(new_pronouns) || !(new_pronouns in species.available_pronouns)) + new_pronouns = species.default_pronouns + set_gender(new_pronouns.name) + + //Handle bodytype + if(!new_bodytype) + new_bodytype = species.get_bodytype_by_pronouns(new_pronouns) + set_bodytype(new_bodytype) + + available_maneuvers = species.maneuvers.Copy() + + butchery_data = species.butchery_data + + full_prosthetic = null //code dum thinks ur robot always + default_walk_intent = null + default_run_intent = null + move_intent = null + move_intents = species.move_intents.Copy() + set_move_intent(GET_DECL(move_intents[1])) + if(!istype(move_intent)) + set_next_usable_move_intent() + apply_species_inventory_restrictions() + refresh_ai_handler() + + // Update codex scannables. + if(species.secret_codex_info) + var/datum/extension/scannable/scannable = get_or_create_extension(src, /datum/extension/scannable) + scannable.associated_entry = "[lowertext(species.name)] (species)" + scannable.scan_delay = 5 SECONDS + else if(has_extension(src, /datum/extension/scannable)) + remove_extension(src, /datum/extension/scannable) + + return TRUE + + +//Syncs background categories/values to the currently set species, and may trigger a language update +/mob/living/human/proc/apply_species_background_info() + var/update_lang + for(var/cat_type in decls_repository.get_decls_of_subtype(/decl/background_category)) + if(species.force_background_info && species.force_background_info[cat_type]) + update_lang = TRUE + set_background_value(cat_type, species.force_background_info[cat_type], defer_language_update = TRUE) + else if(!background_info[cat_type] || !(background_info[cat_type] in species.available_background_info[cat_type])) + update_lang = TRUE + set_background_value(cat_type, species.default_background_info[cat_type], defer_language_update = TRUE) + + if(update_lang) + update_languages() + +//Drop anything that cannot be worn by the current species of the mob +/mob/living/human/proc/apply_species_inventory_restrictions() + + var/decl/bodytype/check_bodytype = get_bodytype() + if(!istype(check_bodytype) || !(check_bodytype.appearance_flags & HAS_UNDERWEAR)) + QDEL_NULL_LIST(worn_underwear) + + var/list/new_slots + var/list/held_slots = get_held_item_slots() + if(istype(species.species_hud)) + for(var/slot_id in species.species_hud.inventory_slots) + var/datum/inventory_slot/old_slot = get_inventory_slot_datum(slot_id) + if(slot_id in held_slots) + LAZYSET(new_slots, slot_id, old_slot) + continue + var/datum/inventory_slot/new_slot = species.species_hud.inventory_slots[slot_id] + if(!old_slot || !old_slot.equivalent_to(new_slot)) + LAZYSET(new_slots, slot_id, new_slot.Clone()) + else + LAZYSET(new_slots, slot_id, old_slot) + set_inventory_slots(new_slots) + + //recheck species-restricted clothing + for(var/obj/item/carrying in get_equipped_items(include_carried = TRUE)) + if(!carrying.mob_can_equip(src, get_equipped_slot_for_item(carrying), TRUE, TRUE, TRUE)) + drop_from_inventory(carrying) + +//This handles actually updating our visual appearance +// Triggers deep update of limbs and hud +/mob/living/human/proc/apply_species_appearance() + if(!species) + icon_state = null // this used to set it to "human" but that's not even an icon state that exists, so + else + species.apply_appearance(src) + + force_update_limbs() + + // Rebuild the HUD and visual elements only if we got a client. + hud_reset(TRUE) + +// Like above, but for bodytype. Not as complicated. +/mob/living/human/proc/apply_bodytype_appearance() + var/decl/bodytype/root_bodytype = get_bodytype() + if(!root_bodytype) + set_skin_colour(COLOR_BLACK) + else + root_bodytype.apply_appearance(src) + default_pixel_x = initial(pixel_x) + root_bodytype.pixel_offset_x + default_pixel_y = initial(pixel_y) + root_bodytype.pixel_offset_y + default_pixel_z = initial(pixel_z) + root_bodytype.pixel_offset_z + + for(var/obj/item/organ/external/E in get_external_organs()) + E.sanitize_sprite_accessories() + + for(var/acc_cat in root_bodytype?.default_sprite_accessories) + var/decl/sprite_accessory_category/acc_cat_decl = GET_DECL(acc_cat) + if(!acc_cat_decl.always_apply_defaults) + continue + for(var/accessory in root_bodytype.default_sprite_accessories[acc_cat]) + var/decl/sprite_accessory/accessory_decl = GET_DECL(accessory) + var/accessory_metadata = root_bodytype.default_sprite_accessories[acc_cat][accessory] + for(var/bodypart in accessory_decl.body_parts) + var/obj/item/organ/external/O = GET_EXTERNAL_ORGAN(src, bodypart) + if(O && O.bodytype == root_bodytype) + O.set_sprite_accessory(accessory, accessory_decl.accessory_category, accessory_metadata, skip_update = TRUE) + + reset_offsets() + +/mob/living/human/proc/update_languages() + if(!length(background_info)) + log_warning("'[src]'([x], [y], [z]) doesn't have any background info set and is attempting to update its language!!") + + var/list/permitted_languages = list() + var/list/free_languages = list() + var/list/default_languages = list() + + for(var/thing in background_info) + var/decl/background_detail/check = background_info[thing] + if(istype(check)) + if(check.default_language) + free_languages |= check.default_language + default_languages |= check.default_language + if(check.language) + free_languages |= check.language + if(check.name_language) + free_languages |= check.name_language + for(var/lang in check.additional_langs) + free_languages |= lang + for(var/lang in check.get_spoken_languages()) + permitted_languages |= lang + + for(var/decl/language/lang in languages) + // Forbidden languages are always removed. + if(!(lang.flags & LANG_FLAG_FORBIDDEN)) + // Admin can have whatever available language they want. + if(has_admin_rights()) + continue + // Whitelisted languages are fine. + if((lang.flags & LANG_FLAG_WHITELISTED) && is_alien_whitelisted(src, lang)) + continue + // Background-granted languages are fine. + if(lang.type in permitted_languages) + continue + // This language is Not Fine, remove it. + if(lang.type == default_language) + default_language = null + remove_language(lang.type) + + for(var/thing in free_languages) + add_language(thing) + + if(length(default_languages) && isnull(default_language)) + default_language = default_languages[1] + +/mob/living/proc/bodypart_is_covered(target_zone) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, target_zone) + if(!affecting?.body_part) + return FALSE + for(var/obj/item/clothing/thing in get_equipped_items()) + if(thing.body_parts_covered & affecting.body_part) + return thing + return FALSE + +/mob/living/human/can_inject(var/mob/user, var/target_zone) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, target_zone) + + if(!affecting) + to_chat(user, SPAN_WARNING("\The [src] is missing that limb.")) + return 0 + + if(BP_IS_PROSTHETIC(affecting)) + to_chat(user, SPAN_WARNING("That limb is prosthetic.")) + return 0 + + . = CAN_INJECT + for(var/slot in list(slot_head_str, slot_wear_mask_str, slot_wear_suit_str, slot_w_uniform_str, slot_gloves_str, slot_shoes_str)) + var/obj/item/clothing/C = get_equipped_item(slot) + if(C && (C.body_parts_covered & affecting.body_part) && (C.item_flags & ITEM_FLAG_THICKMATERIAL)) + if(istype(C, /obj/item/clothing/suit/space)) + . = INJECTION_PORT //it was going to block us, but it's a space suit so it doesn't because it has some kind of port + else + to_chat(user, "There is no exposed flesh or thin material on [src]'s [affecting.name] to inject into.") + return 0 + + +/mob/living/human/print_flavor_text(var/shrink = 1) + + var/head_exposed = 1 + var/face_exposed = 1 + var/eyes_exposed = 1 + var/torso_exposed = 1 + var/arms_exposed = 1 + var/legs_exposed = 1 + var/hands_exposed = 1 + var/feet_exposed = 1 + + var/static/list/equipment = list( + slot_head_str, + slot_wear_mask_str, + slot_glasses_str, + slot_w_uniform_str, + slot_wear_suit_str, + slot_gloves_str, + slot_shoes_str + ) + for(var/slot in equipment) + var/obj/item/clothing/C = get_equipped_item(slot) + if(!istype(C)) + continue + if(C.body_parts_covered & SLOT_HEAD) + head_exposed = 0 + if(C.body_parts_covered & SLOT_FACE) + face_exposed = 0 + if(C.body_parts_covered & SLOT_EYES) + eyes_exposed = 0 + if(C.body_parts_covered & SLOT_UPPER_BODY) + torso_exposed = 0 + if(C.body_parts_covered & SLOT_ARMS) + arms_exposed = 0 + if(C.body_parts_covered & SLOT_HANDS) + hands_exposed = 0 + if(C.body_parts_covered & SLOT_LEGS) + legs_exposed = 0 + if(C.body_parts_covered & SLOT_FEET) + feet_exposed = 0 + + flavor_text = "" + for (var/T in flavor_texts) + if(flavor_texts[T] && flavor_texts[T] != "") + if((T == "general") || (T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed)) + flavor_text += flavor_texts[T] + flavor_text += "\n\n" + if(!shrink) + return flavor_text + else + return ..() + +/mob/living/human/has_brain() + . = !!GET_INTERNAL_ORGAN(src, BP_BRAIN) + +/mob/living/human/check_has_eyes() + var/obj/item/organ/internal/eyes = GET_INTERNAL_ORGAN(src, BP_EYES) + . = eyes?.is_usable() + +/mob/living/human/reset_view(atom/A, update_hud = 1) + ..() + if(update_hud) + handle_regular_hud_updates() + +/mob/living/human/can_stand_overridden() + if(get_rig()?.ai_can_move_suit(check_for_ai = 1)) + // Actually missing a leg will screw you up. Everything else can be compensated for. + for(var/limbcheck in list(BP_L_LEG,BP_R_LEG)) + var/obj/item/organ/affecting = GET_EXTERNAL_ORGAN(src, limbcheck) + if(!affecting) + return FALSE + return TRUE + return FALSE + +/mob/living/human/can_devour(atom/movable/victim, var/silent = FALSE) + + if(!should_have_organ(BP_STOMACH)) + return ..() + + var/obj/item/organ/internal/stomach/stomach = get_organ(BP_STOMACH, /obj/item/organ/internal/stomach) + if(!stomach || !stomach.is_usable()) + if(!silent) + to_chat(src, SPAN_WARNING("Your stomach is not functional!")) + return FALSE + + if(!stomach.can_eat_atom(victim)) + if(!silent) + to_chat(src, SPAN_WARNING("You are not capable of devouring \the [victim] whole!")) + return FALSE + + if(stomach.is_full(victim)) + if(!silent) + to_chat(src, SPAN_WARNING("Your [stomach.name] is full!")) + return FALSE + + . = stomach.get_devour_time(victim) || ..() + +/mob/living/human/move_to_stomach(atom/movable/victim) + var/obj/item/organ/internal/stomach = GET_INTERNAL_ORGAN(src, BP_STOMACH) + if(stomach) + victim.forceMove(stomach) + +/mob/living/human/get_adjusted_metabolism(metabolism) + return ..() * (species ? species.metabolism_mod : 1) + +/mob/living/human/is_invisible_to(var/mob/viewer) + return (is_cloaked() || ..()) + + +/mob/living/human/proc/resuscitate() + if(!is_asystole() || !should_have_organ(BP_HEART)) + return + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(heart && !(heart.status & ORGAN_DEAD)) + var/breathing_organ = get_bodytype().breathing_organ + var/active_breaths = 0 + if(breathing_organ) + var/obj/item/organ/internal/lungs/L = get_organ(breathing_organ, /obj/item/organ/internal/lungs) + if(L) + active_breaths = L.active_breathing + if(!nervous_system_failure() && active_breaths) + visible_message(SPAN_NOTICE("\The [src] jerks and gasps for breath!")) + else + var/decl/pronouns/pronouns = get_pronouns() + visible_message(SPAN_NOTICE("\The [src] twitches a bit as [pronouns.his] [heart.name] restarts!")) + + shock_stage = min(shock_stage, 100) // 120 is the point at which the heart stops. + var/oxyloss_threshold = round(species.total_health * 0.35) + if(get_damage(OXY) >= oxyloss_threshold) + set_damage(OXY, oxyloss_threshold) + heart.pulse = PULSE_NORM + heart.handle_pulse() + return TRUE + +/mob/living/human/proc/make_reagent(amount, reagent_type) + if(stat == CONSCIOUS) + var/limit = max(0, reagents.get_overdose(reagent_type) - REAGENT_VOLUME(reagents, reagent_type)) + add_to_reagents(reagent_type, min(amount, limit)) + +//Get fluffy numbers +/mob/living/human/proc/get_blood_pressure() + if(status_flags & FAKEDEATH) + return "[floor(120+rand(-5,5))*0.25]/[floor(80+rand(-5,5)*0.25)]" + var/blood_result = get_blood_circulation() + return "[floor((120+rand(-5,5))*(blood_result/100))]/[floor((80+rand(-5,5))*(blood_result/100))]" + +//Point at which you dun breathe no more. Separate from asystole crit, which is heart-related. +/mob/living/human/nervous_system_failure() + return get_damage(BRAIN) >= get_max_health() * 0.75 + +/mob/living/human/melee_accuracy_mods() + . = ..() + if(get_shock() > 50) + . += 15 + if(shock_stage > 10) + . += 15 + if(shock_stage > 30) + . += 15 + +/mob/living/human/ranged_accuracy_mods() + . = ..() + if(get_shock() > 10 && !skill_check(SKILL_WEAPONS, SKILL_ADEPT)) + . -= 1 + if(get_shock() > 50) + . -= 1 + if(shock_stage > 10) + . -= 1 + if(shock_stage > 30) + . -= 1 + if(skill_check(SKILL_WEAPONS, SKILL_ADEPT)) + . += 1 + if(skill_check(SKILL_WEAPONS, SKILL_EXPERT)) + . += 1 + if(skill_check(SKILL_WEAPONS, SKILL_PROF)) + . += 2 + +/mob/living/human/fluid_act(var/datum/reagents/fluids) + ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids)) + species.fluid_act(src, fluids) + +/mob/living/human/proc/set_background_value(var/cat_type, var/decl/background_detail/_background, var/defer_language_update) + if(ispath(_background, /decl/background_detail)) + _background = GET_DECL(_background) + if(istype(_background)) + LAZYSET(background_info, cat_type, _background) + if(!defer_language_update) + update_languages() + +/mob/living/proc/get_background_datum_by_flag(background_flag) + var/list/all_categories = global.using_map.get_background_categories() + for(var/cat_type in all_categories) + var/decl/background_category/background_cat = all_categories[cat_type] + if(background_cat.background_flags && (background_cat.background_flags & background_flag)) + return get_background_datum(cat_type) + +/mob/living/proc/get_background_datum(cat_type) + return null + +/mob/living/human/get_background_datum(cat_type) + . = LAZYACCESS(background_info, cat_type) + if(!istype(., /decl/background_detail)) + . = global.using_map.default_background_info[cat_type] + PRINT_STACK_TRACE("get_background_datum() tried to return a non-instance value for background category '[cat_type]' - full background list: [json_encode(background_info)] default species culture list: [json_encode(global.using_map.default_background_info)]") + +/mob/living/human/get_digestion_product() + return species.get_digestion_product(src) + +// A damaged stomach can put blood in your vomit. +/mob/living/human/handle_additional_vomit_reagents(var/obj/effect/decal/cleanable/vomit/vomit) + ..() + if(should_have_organ(BP_STOMACH)) + var/obj/item/organ/internal/stomach = GET_INTERNAL_ORGAN(src, BP_STOMACH) + if(!stomach || stomach.is_broken() || (stomach.is_bruised() && prob(stomach.get_organ_damage()))) + if(should_have_organ(BP_HEART)) + vessel.trans_to_obj(vomit, 5) + else + reagents.trans_to_obj(vomit, 5) + +/mob/living/human/get_bullet_impact_effect_type(var/def_zone) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, def_zone) + if(!E) + return BULLET_IMPACT_NONE + if(BP_IS_PROSTHETIC(E)) + return BULLET_IMPACT_METAL + return BULLET_IMPACT_MEAT + +/mob/living/human/lose_hair() + if(species.handle_additional_hair_loss(src)) + . = TRUE + for(var/obj/item/organ/external/E in get_external_organs()) + if(E.handle_hair_loss()) + . = TRUE + if(.) + update_body() + to_chat(src, SPAN_DANGER("You feel a chill and your skin feels lighter...")) + +/obj/item/organ/external/proc/handle_hair_loss() + for(var/accessory_category in _sprite_accessories) + var/list/draw_accessories = _sprite_accessories[accessory_category] + for(var/accessory in draw_accessories) + var/decl/sprite_accessory/accessory_decl = GET_DECL(accessory) + if(accessory_decl.accessory_flags & HAIR_LOSS_VULNERABLE) + remove_sprite_accessory(accessory, skip_update = TRUE) + . = TRUE + +/mob/living/human/increaseBodyTemp(value) + bodytemperature += value + return bodytemperature + +/mob/living/human/get_admin_job_string() + return job || uppertext(species.name) + +/mob/living/human/breathing_hole_covered() + . = ..() + if(!.) + var/obj/item/head = get_equipped_item(slot_head_str) + if(head && (head.item_flags & ITEM_FLAG_AIRTIGHT)) + return TRUE + +/mob/living/human/set_internals_to_best_available_tank(var/breathes_gas = /decl/material/gas/oxygen, var/list/poison_gas = list(/decl/material/gas/chlorine)) + . = ..(species.breath_type, species.poison_types) + +//Sets the mob's real name and update all the proper fields +/mob/living/human/proc/set_real_name(var/newname) + if(!newname) + return + real_name = newname + SetName(newname) + if(mind) + mind.name = newname + +//Human mob specific init code. Meant to be used only on init. +/mob/living/human/proc/setup_human(species_uid, datum/mob_snapshot/supplied_appearance) + if(supplied_appearance) + species_uid = supplied_appearance.root_species.uid + else if(!species_uid) + species_uid = global.using_map.default_species //Humans cannot exist without a species! + + set_species(species_uid, supplied_appearance?.root_bodytype) + var/decl/bodytype/root_bodytype = get_bodytype() // root bodytype is set in set_species + ASSERT((!supplied_appearance?.root_bodytype) || (root_bodytype == supplied_appearance.root_bodytype)) + if(!get_skin_colour()) + set_skin_colour(root_bodytype.base_color, skip_update = TRUE) + if(!get_eye_colour()) + set_eye_colour(root_bodytype.base_eye_color, skip_update = TRUE) + root_bodytype.set_default_sprite_accessories(src) + + if(!blood_type && length(species?.blood_types)) + blood_type = pickweight(species.blood_types) + + if(supplied_appearance) + set_real_name(supplied_appearance.real_name) + else + try_generate_default_name() + + species.handle_pre_spawn(src) + apply_species_background_info() + species.handle_post_spawn(src) + + supplied_appearance?.apply_appearance_to(src) + + //Prevent attempting to create blood container if its already setup + if(!vessel) + reset_blood() + +//If the mob has its default name it'll try to generate /obtain a proper one +/mob/living/human/proc/try_generate_default_name() + if(name != initial(name)) + return + if(species) + set_real_name(species.get_default_name()) + else + SetName(initial(name)) + +//Runs last after setup and after the parent init has been executed. +/mob/living/human/proc/post_setup(species_uid, datum/mob_snapshot/supplied_appearance) + try_refresh_visible_overlays() //Do this exactly once per setup + +/mob/living/human/handle_flashed(var/flash_strength, do_stun = FALSE) + var/safety = eyecheck() + if(safety < FLASH_PROTECTION_MODERATE) + flash_strength = round(get_flash_mod() * flash_strength) + if(safety > FLASH_PROTECTION_NONE) + flash_strength = (flash_strength / 2) + . = ..() + +/mob/living/human/handle_nutrition_and_hydration() + ..() + + // Apply stressors. + if(!client) + return + + var/nut = get_nutrition() + var/maxnut = get_max_nutrition() + if(nut < (maxnut * 0.3)) + add_stressor(/datum/stressor/hungry_very, STRESSOR_DURATION_INDEFINITE) + else + remove_stressor(/datum/stressor/hungry_very) + if(nut < (maxnut * 0.5)) + add_stressor(/datum/stressor/hungry, STRESSOR_DURATION_INDEFINITE) + else + remove_stressor(/datum/stressor/hungry) + var/hyd = get_hydration() + var/maxhyd = get_max_hydration() + if(hyd < (maxhyd * 0.3)) + add_stressor(/datum/stressor/thirsty_very, STRESSOR_DURATION_INDEFINITE) + else + remove_stressor(/datum/stressor/thirsty_very) + if(hyd < (maxhyd * 0.5)) + add_stressor(/datum/stressor/thirsty, STRESSOR_DURATION_INDEFINITE) + else + remove_stressor(/datum/stressor/thirsty) + +/mob/living/human/get_comments_record() + if(comments_record_id) + return SScharacter_info.get_record(comments_record_id, TRUE) + return ..() + +/mob/living/human/proc/set_age(var/val) + var/decl/bodytype/bodytype = get_bodytype() + var/datum/appearance_descriptor/age = LAZYACCESS(bodytype.appearance_descriptors, "age") + LAZYSET(appearance_descriptors, "age", (age ? age.sanitize_value(val) : 30)) + +/mob/living/human/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected) + if((. = ..()) && !surgical_removal) + shock_stage += 20 + +/mob/living/human/has_footsteps() + if(species.silent_steps) + return //people flying, lying down or sitting do not step + var/obj/item/shoes = get_equipped_item(slot_shoes_str) + if(shoes && (shoes.item_flags & ITEM_FLAG_SILENT)) + return // quiet shoes + if(!has_organ(BP_L_FOOT) && !has_organ(BP_R_FOOT)) + return //no feet no footsteps + return TRUE + +/mob/living/human/get_skin_tone() + if(get_bodytype()?.appearance_flags & HAS_A_SKIN_TONE) + return skin_tone + return null + +/mob/living/human/set_skin_tone(value) + skin_tone = value + +/mob/living/human/try_awaken(mob/user) + return !is_asystole() && ..() + +/mob/living/human/get_satiated_nutrition() + return 350 + +/mob/living/human/get_max_nutrition() + return 400 + +/mob/living/human/get_max_hydration() + return 400 + +/mob/living/human/get_species() + RETURN_TYPE(/decl/species) + return species + +/mob/living/human/get_contact_reagents() + return touching + +/mob/living/human/get_injected_reagents() + return bloodstr + +/mob/living/human/Bump(var/atom/movable/AM, yes) + if(now_pushing || !yes) + return + ..() + +/mob/living/human/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + var/temp_inc = max(min(BODYTEMP_HEATING_MAX*(1-get_heat_protection()), exposed_temperature - bodytemperature), 0) + bodytemperature += temp_inc + +/mob/living/human/currently_has_skin() + return currently_has_meat() + +/mob/living/human/currently_has_innards() + return length(get_internal_organs()) + +/mob/living/human/currently_has_meat() + for(var/obj/item/organ/external/limb in get_external_organs()) + if(istype(limb.material, /decl/material/solid/organic/meat)) + return TRUE + return FALSE + +/mob/living/human/get_attack_telegraph_delay() + return client ? 0 : DEFAULT_ATTACK_COOLDOWN + +/mob/living/human/isSynthetic() + if(isnull(full_prosthetic)) + robolimb_count = 0 + var/list/limbs = get_external_organs() + for(var/obj/item/organ/external/E in limbs) + if(BP_IS_PROSTHETIC(E)) + robolimb_count++ + full_prosthetic = robolimb_count > 0 && (robolimb_count == LAZYLEN(limbs)) //If no organs, no way to tell + return full_prosthetic + +// Don't tag your crewmates please. +/mob/living/human/is_tagging_suitable() + return FALSE diff --git a/code/modules/mob/living/human/human_appearance.dm b/code/modules/mob/living/human/human_appearance.dm new file mode 100644 index 000000000000..c85c641c8d87 --- /dev/null +++ b/code/modules/mob/living/human/human_appearance.dm @@ -0,0 +1,105 @@ +/mob/living/human + var/_skin_colour + +/mob/living/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, var/location = src, var/mob/user = src, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list(), var/datum/topic_state/state = global.default_topic_state) + var/datum/nano_module/appearance_changer/AC = new(location, src, check_species_whitelist, species_whitelist, species_blacklist) + AC.flags = flags + AC.ui_interact(user, state = state) + +/mob/living/human/get_skin_colour() + if(get_bodytype()?.appearance_flags & HAS_SKIN_COLOR) + return _skin_colour + return null + +/mob/living/human/set_skin_colour(var/new_color, var/skip_update = FALSE) + if((. = ..())) + _skin_colour = new_color + if(!skip_update) + force_update_limbs() + update_body() + +/mob/living/human/proc/change_species(var/new_species, var/new_bodytype = null) + + if(!new_species) + return + + if(species?.uid == new_species) + return + + set_species(new_species, new_bodytype) + + //Handle spawning stuff + species.handle_pre_spawn(src) + apply_species_appearance() + apply_bodytype_appearance() + apply_species_background_info() + species.handle_post_spawn(src) + reset_blood() + full_prosthetic = null + apply_species_inventory_restrictions() + + var/decl/special_role/antag = mind && player_is_antag(mind) + if (antag && antag.required_language) + add_language(antag.required_language) + set_default_language(antag.required_language) + try_refresh_visible_overlays() + return 1 + +/mob/living/human/set_gender(var/new_gender, var/update_body = FALSE) + . = ..() + if(. && update_body) + update_body() + +/mob/living/human/proc/randomize_gender() + var/decl/pronouns/pronouns = pick(species.available_pronouns) + set_gender(pronouns.name, TRUE) + +/mob/living/human/proc/reset_accessory(accessory_category, organ_tag, skip_update = FALSE) + if(!accessory_category) + return + + var/decl/bodytype/root_bodytype = get_bodytype() + var/decl/sprite_accessory_category/acc_category = GET_DECL(accessory_category) + var/list/valid_styles = species?.get_available_accessories(root_bodytype, accessory_category) + + var/decl/sprite_accessory/new_style + if(length(valid_styles)) + new_style = pick(valid_styles) + else + var/list/default_data = LAZYACCESS(root_bodytype?.default_sprite_accessories, accessory_category) + new_style = islist(default_data) ? pick(default_data) : acc_category.default_accessory + if(ispath(new_style)) + new_style = GET_DECL(new_style) + + var/list/metadata = new_style.update_metadata(get_organ_sprite_accessory_metadata(get_organ_sprite_accessory_by_category(accessory_category, organ_tag), organ_tag)) + set_organ_sprite_accessory_by_category(new_style.type, accessory_category, metadata, TRUE, TRUE, organ_tag, skip_update) + +/mob/living/human/proc/reset_hair() + reset_accessory(SAC_HAIR, BP_HEAD, TRUE) + reset_accessory(SAC_FACIAL_HAIR, BP_HEAD, TRUE) + update_hair(TRUE) + +/mob/living/human/proc/change_skin_tone(var/tone) + if(skin_tone == tone || !(get_bodytype().appearance_flags & HAS_A_SKIN_TONE)) + return + skin_tone = tone + force_update_limbs() + update_body() + return 1 + +/mob/living/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list()) + var/list/valid_species = new() + for(var/decl/species/current_species as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/species)) + if(check_whitelist) //If we're using the whitelist, make sure to check it! + if((current_species.spawn_flags & SPECIES_IS_RESTRICTED) && !check_rights(R_ADMIN, 0, src)) + continue + if(!is_alien_whitelisted(src, current_species)) + continue + if(whitelist.len && !(current_species.uid in whitelist)) + continue + if(blacklist.len && (current_species.uid in blacklist)) + continue + + valid_species += current_species.uid + + return valid_species diff --git a/code/modules/mob/living/human/human_appearance_head.dm b/code/modules/mob/living/human/human_appearance_head.dm new file mode 100644 index 000000000000..f5ed43182da9 --- /dev/null +++ b/code/modules/mob/living/human/human_appearance_head.dm @@ -0,0 +1,13 @@ +/mob/living/human + var/_eye_colour + +// Eyes! TODO, make these a marking. +/mob/living/human/get_eye_colour() + return _eye_colour + +/mob/living/human/set_eye_colour(var/new_color, var/skip_update = FALSE) + if((. = ..())) + _eye_colour = new_color + if(!skip_update) + update_eyes() + update_body() diff --git a/code/modules/mob/living/human/human_attackhand.dm b/code/modules/mob/living/human/human_attackhand.dm new file mode 100644 index 000000000000..dfcc31cb4120 --- /dev/null +++ b/code/modules/mob/living/human/human_attackhand.dm @@ -0,0 +1,435 @@ +/mob/living/human/proc/get_unarmed_attack(var/mob/target, var/hit_zone = null) + if(!hit_zone) + hit_zone = get_target_zone() + var/list/available_attacks = get_mob_natural_attacks() + var/decl/natural_attack/use_attack = default_attack + if(!use_attack || !use_attack.attack_is_usable(src, target, hit_zone) || !(use_attack in available_attacks)) + var/alert_non_default_attack = use_attack?.name + use_attack = null + var/list/other_attacks = list() + for(var/decl/natural_attack/u_attack as anything in available_attacks) + if(!u_attack.attack_is_usable(src, target, hit_zone)) + continue + if(u_attack.is_starting_default) + use_attack = u_attack + break + other_attacks += u_attack + if(!use_attack && length(other_attacks)) + use_attack = pick(other_attacks) + if(use_attack && alert_non_default_attack) + to_chat(src, SPAN_WARNING("You cannot [alert_non_default_attack] \the [target] currently, so you switch attacks.")) + + . = use_attack?.resolve_to_soft_variant(src) + +/obj/item/organ/external/proc/get_natural_attacks() + return null + +/obj/item/organ/external/proc/get_injury_status(include_pain = TRUE, include_visible = TRUE) + . = list() + if(include_pain && can_feel_pain()) + var/feels = 1 + round(get_pain()/100, 0.1) + var/feels_brute = brute_dam * feels + if(feels_brute > 0) + switch(feels_brute / max_damage) + if(0 to 0.35) + . += "slightly sore" + if(0.35 to 0.65) + . += "very sore" + if(0.65 to INFINITY) + . += "throbbing with agony" + + var/feels_burn = burn_dam * feels + if(feels_burn > 0) + switch(feels_burn / max_damage) + if(0 to 0.35) + . += "tingling" + if(0.35 to 0.65) + . += "stinging" + if(0.65 to INFINITY) + . += "burning fiercely" + + if(status & ORGAN_BROKEN) + . += "painful to the touch" + + if(include_visible && !owner?.is_blind()) + if(status & ORGAN_MUTATED) + . += "misshapen" + if(status & ORGAN_BLEEDING) + . += "bleeding" + if(is_dislocated()) + . += "dislocated" + if(status & ORGAN_DEAD) + if(BP_IS_PROSTHETIC(src) || BP_IS_CRYSTAL(src)) + . += "irrecoverably damaged" + else + . += "grey and necrotic" + else if((brute_dam + burn_dam) >= max_damage && germ_level >= INFECTION_LEVEL_TWO) + . += "likely beyond saving and decay has set in" + + if(!is_usable() || is_dislocated()) // This one is special and has a different message for visible/pain modes. + . += (!include_visible || owner?.is_blind()) ? "completely limp" : "dangling uselessly" + +/mob/living/human/proc/check_self_injuries(include_pain = TRUE, include_visible = TRUE) + if(include_visible) + var/decl/pronouns/pronouns = get_pronouns() + visible_message( + SPAN_NOTICE("\The [src] examines [pronouns.self]."), + SPAN_NOTICE("You check yourself for injuries.") + ) + else if(include_pain) + to_chat(src, SPAN_NOTICE("You take note of how your body feels...")) + else + return // This should never happen, we should always check pain, visible status, or both. + + // TODO: move status strings onto the bodytype and handle crystal/prosthetic limbs. + for(var/obj/item/organ/external/org in get_external_organs()) + var/list/status = org.get_injury_status(include_pain, include_visible) + if(length(status)) + to_chat(src, "Your [org.name] is [english_list(status)].") + else if(is_blind() || !include_visible) + to_chat(src, "You can't feel anything wrong with your [org.name].") + else if(!include_pain) + to_chat(src, "You can't see anything wrong with your [org.name].") + else + to_chat(src, "Your [org.name] is OK.") + +/mob/living/human/default_help_interaction(mob/user) + if(apply_pressure(user, user.get_target_zone())) + return TRUE + if(user == src) + check_self_injuries() + return TRUE + if(ishuman(user) && (is_asystole() || (status_flags & FAKEDEATH) || failed_last_breath) && !is_on_fire() && !(user.get_target_zone() == BP_R_ARM || user.get_target_zone() == BP_L_ARM)) + if (performing_cpr) + performing_cpr = FALSE + else + performing_cpr = TRUE + start_compressions(user, TRUE) + return TRUE + return ..() + +/mob/living/human/default_disarm_interaction(mob/user) + var/decl/species/user_species = user.get_species() + if(user_species) + admin_attack_log(user, src, "Disarmed their victim.", "Was disarmed.", "disarmed") + user_species.disarm_attackhand(user, src) + return TRUE + . = ..() + +/mob/living/human/default_hurt_interaction(mob/user) + . = ..() + if(.) + return TRUE + + if(user.incapacitated()) + to_chat(user, SPAN_WARNING("You can't attack while incapacitated.")) + return TRUE + + if(!ishuman(user)) + attack_generic(user, rand(1,3), "punched") + return TRUE + + var/mob/living/human/H = user + var/rand_damage = rand(1, 5) + var/block = 0 + var/accurate = 0 + var/hit_zone = H.get_target_zone() + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, hit_zone) + + // See what attack they use + var/decl/natural_attack/attack = H.get_unarmed_attack(src, hit_zone) + if(!attack) + return TRUE + + if(world.time < H.last_attack + attack.delay) + to_chat(H, SPAN_NOTICE("You can't attack again so soon.")) + return TRUE + + last_handled_by_mob = weakref(H) + H.last_attack = world.time + + if(!affecting) + to_chat(user, SPAN_DANGER("They are missing that limb!")) + return TRUE + + // We didn't see this coming, so we get the full blow + if(check_intent(I_FLAG_HELP)) + rand_damage = 5 + accurate = 1 + // We're in a fighting stance, there's a chance we block + else if(check_intent(I_FLAG_HARM|I_FLAG_GRAB) && MayMove() && src != H && prob(20)) + block = 1 + + if (LAZYLEN(user.grabbed_by)) + // Someone got a good grip on them, they won't be able to do much damage + rand_damage = max(1, rand_damage - 2) + + if(LAZYLEN(grabbed_by) || !src.MayMove() || src==H || H.species.species_flags & SPECIES_FLAG_NO_BLOCK) + accurate = 1 // certain circumstances make it impossible for us to evade punches + rand_damage = 5 + + // Process evasion and blocking + var/miss_type = 0 + var/attack_message + if(!accurate) + /* ~Hubblenaut + This place is kind of convoluted and will need some explaining. + ran_zone() will pick out of 11 zones, thus the chance for hitting + our target where we want to hit them is circa 9.1%. + Now since we want to statistically hit our target organ a bit more + often than other organs, we add a base chance of 20% for hitting it. + This leaves us with the following chances: + If aiming for chest: + 27.3% chance you hit your target organ + 70.5% chance you hit a random other organ + 2.2% chance you miss + If aiming for something else: + 23.2% chance you hit your target organ + 56.8% chance you hit a random other organ + 15.0% chance you miss + Note: We don't use get_zone_with_miss_chance() here since the chances + were made for projectiles. + TODO: proc for melee combat miss chances depending on organ? + */ + if(prob(80)) + hit_zone = ran_zone(hit_zone, target = src) + if(prob(15) && hit_zone != BP_CHEST) // Missed! + if(!src.current_posture.prone) + attack_message = "\The [H] attempted to strike \the [src], but missed!" + else + var/decl/pronouns/pronouns = get_pronouns() + attack_message = "\The [H] attempted to strike \the [src], but [pronouns.he] rolled out of the way!" + src.set_dir(pick(global.cardinal)) + miss_type = 1 + + if(!miss_type && block) + attack_message = "[H] went for [src]'s [affecting.name] but was blocked!" + miss_type = 2 + + H.do_attack_animation(src) + if(!attack_message) + attack.show_attack(H, src, hit_zone, rand_damage) + else + H.visible_message(SPAN_DANGER("[attack_message]")) + + playsound(loc, ((miss_type) ? (miss_type == 1 ? attack.miss_sound : 'sound/weapons/thudswoosh.ogg') : attack.attack_sound), 25, 1, -1) + admin_attack_log(H, src, "[miss_type ? (miss_type == 1 ? "Has missed" : "Was blocked by") : "Has [pick(attack.attack_verb)]"] their victim.", "[miss_type ? (miss_type == 1 ? "Missed" : "Blocked") : "[pick(attack.attack_verb)]"] their attacker", "[miss_type ? (miss_type == 1 ? "has missed" : "was blocked by") : "has [pick(attack.attack_verb)]"]") + + if(miss_type) + return TRUE + + var/real_damage = rand_damage + real_damage += attack.get_unarmed_damage(H, src) + real_damage *= damage_multiplier + rand_damage *= damage_multiplier + real_damage = max(1, real_damage) + // Apply additional unarmed effects. + attack.apply_attack_effects(H, src, rand_damage, hit_zone) + // Finally, apply damage to target + apply_damage(real_damage, attack.get_damage_type(), hit_zone, damage_flags=attack.damage_flags()) + if(attack.apply_cooldown) + H.setClickCooldown(attack.apply_cooldown) + + if(istype(ai)) + ai.retaliate(user) + return TRUE + +/mob/living/human/attack_hand(mob/user) + + remove_mob_modifier(/decl/mob_modifier/cloaked, source = species) + if(!user.check_intent(I_FLAG_GRAB)) + for (var/obj/item/grab/grab as anything in user.get_active_grabs()) + if(grab.assailant == user && grab.affecting == src && grab.resolve_openhand_attack()) + return TRUE + // Should this all be in Touch()? + if(ishuman(user) && user != src && check_shields(0, null, user, user.get_target_zone(), user)) + user.do_attack_animation(src) + return TRUE + + return ..() + +/mob/living/human/proc/start_compressions(mob/living/human/H, starting = FALSE, cpr_mode) + if(length(H.get_held_items())) + performing_cpr = FALSE + to_chat(H, SPAN_WARNING("You cannot perform CPR with anything in your hands.")) + return + + //Keeps doing CPR unless cancelled, or the target recovers + if(!(performing_cpr && H.Adjacent(src) && (is_asystole() || (status_flags & FAKEDEATH) || failed_last_breath))) + performing_cpr = FALSE + to_chat(H, SPAN_NOTICE("You stop performing CPR on \the [src].")) + return + + else if (starting) + var/list/options = list( + "Compressions" = image('icons/screen/radial.dmi', "cpr"), + "Mouth-to-Mouth" = image('icons/screen/radial.dmi', "cpr_o2") + ) + cpr_mode = show_radial_menu(H, src, options, require_near = TRUE, tooltips = TRUE, no_repeat_close = TRUE) + if(!cpr_mode) + performing_cpr = FALSE + return + + if(length(H.get_held_items())) + performing_cpr = FALSE + to_chat(H, SPAN_WARNING("You cannot perform CPR with anything in your hands.")) + return + + H.visible_message(SPAN_NOTICE("\The [H] is trying to perform CPR on \the [src].")) + + var/pumping_skill = max(H.get_skill_value(SKILL_MEDICAL), H.get_skill_value(SKILL_ANATOMY)) + var/cpr_delay = 15 * H.skill_delay_mult(SKILL_ANATOMY, 0.2) + + H.visible_message(SPAN_NOTICE("\The [H] performs CPR on \the [src]!")) + + H.do_attack_animation(src, null) + var/starting_pixel_y = pixel_y + animate(src, pixel_y = starting_pixel_y + 4, time = 2) + animate(src, pixel_y = starting_pixel_y, time = 2) + + if(is_asystole()) + if(prob(5 + 5 * (SKILL_EXPERT - pumping_skill))) + var/obj/item/organ/external/chest = GET_EXTERNAL_ORGAN(src, BP_CHEST) + if(chest) + chest.fracture() + + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(heart) + heart.external_pump = list(world.time, 0.4 + 0.1*pumping_skill + rand(-0.1,0.1)) + + if(stat != DEAD && prob(10 + 5 * pumping_skill)) + resuscitate() + + if(!do_after(H, cpr_delay, FALSE)) //Chest compresssions are fast, need to wait for the loading bar to do mouth to mouth + to_chat(H, SPAN_NOTICE("You stop performing CPR on \the [src].")) + performing_cpr = FALSE //If it cancelled, cancel it. Simple. + return + + if(cpr_mode == "Mouth-to-Mouth") + if(!H.check_has_mouth()) + to_chat(H, SPAN_WARNING("You don't have a mouth, you cannot do mouth-to-mouth resuscitation!")) + return TRUE + + if(!check_has_mouth()) + to_chat(H, SPAN_WARNING("They don't have a mouth, you cannot do mouth-to-mouth resuscitation!")) + return TRUE + + for(var/slot in global.airtight_slots) + var/obj/item/gear = H.get_equipped_item(slot) + if(gear && (gear.body_parts_covered & SLOT_FACE)) + to_chat(H, SPAN_WARNING("You need to remove your mouth covering for mouth-to-mouth resuscitation!")) + return TRUE + + for(var/slot in global.airtight_slots) + var/obj/item/gear = get_equipped_item(slot) + if(gear && (gear.body_parts_covered & SLOT_FACE)) + to_chat(H, SPAN_WARNING("You need to remove \the [src]'s mouth covering for mouth-to-mouth resuscitation!")) + return TRUE + + var/decl/bodytype/root_bodytype = H.get_bodytype() + if(!GET_INTERNAL_ORGAN(H, root_bodytype.breathing_organ)) + to_chat(H, SPAN_WARNING("You need lungs for mouth-to-mouth resuscitation!")) + return TRUE + + if(!need_breathe()) + return TRUE + + var/obj/item/organ/internal/lungs/lungs = get_organ(root_bodytype.breathing_organ, /obj/item/organ/internal/lungs) + if(!lungs) + return + + if(!lungs.handle_owner_breath(H.get_breath_from_environment(), 1)) + if(!lungs.is_bruised()) + suffocation_counter = 0 + to_chat(src, SPAN_NOTICE("You feel a breath of fresh air enter your lungs. It feels good.")) + + // Again. + start_compressions(H, FALSE, cpr_mode) + +//Breaks all grips and pulls that the mob currently has. +/mob/living/human/proc/break_all_grabs(mob/living/user) + . = FALSE + for(var/obj/item/grab/grab as anything in get_active_grabs()) + if(grab.affecting) + visible_message(SPAN_DANGER("\The [user] has broken \the [src]'s grip on [grab.affecting]!")) + . = TRUE + drop_from_inventory(grab) + +/* + We want to ensure that a mob may only apply pressure to one organ of one mob at any given time. Currently this is done mostly implicitly through + the behaviour of do_after() and the fact that applying pressure to someone else requires a grab: + + If you are applying pressure to yourself and attempt to grab someone else, you'll change what you are holding in your active hand which will stop do_mob() + If you are applying pressure to another and attempt to apply pressure to yourself, you'll have to switch to an empty hand which will also stop do_mob() + Changing targeted zones should also stop do_mob(), preventing you from applying pressure to more than one body part at once. +*/ +/mob/living/human/proc/apply_pressure(mob/living/user, var/target_zone) + var/obj/item/organ/external/organ = GET_EXTERNAL_ORGAN(src, target_zone) + if(!organ || !(organ.status & (ORGAN_BLEEDING|ORGAN_ARTERY_CUT)) || BP_IS_PROSTHETIC(organ)) + return 0 + + if(organ.applied_pressure) + var/message = "[ismob(organ.applied_pressure)? "Someone" : "\A [organ.applied_pressure]"] is already applying pressure to [user == src? "your [organ.name]" : "[src]'s [organ.name]"]." + to_chat(user, message) + return 0 + + if(user == src) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + SPAN_NOTICE("\The [user] starts applying pressure to [pronouns.his] [organ.name]!"), \ + SPAN_NOTICE("You start applying pressure to your [organ.name]!")) + else + user.visible_message( \ + SPAN_NOTICE("\The [user] starts applying pressure to \the [src]'s [organ.name]!"), \ + SPAN_NOTICE("You start applying pressure to \the [src]'s [organ.name]!")) + // TODO: refactor applying pressure to use grabs instead? would probably require making grabs locked to the zone they were started on + spawn(0) + organ.applied_pressure = user + + //apply pressure as long as they stay still and keep grabbing + do_mob(user, src, INFINITY, target_zone, progress = 0) + + organ.applied_pressure = null + + if(user == src) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + SPAN_NOTICE("\The [user] stops applying pressure to [pronouns.his] [organ.name]!"), \ + SPAN_NOTICE("You stop applying pressure to your [organ.name]!")) + else + user.visible_message( \ + SPAN_NOTICE("\The [user] stops applying pressure to \the [src]'s [organ.name]!"), \ + SPAN_NOTICE("You stop applying pressure to \the [src]'s [organ.name]!")) + + return 1 + +/mob/living/human/verb/set_default_unarmed_attack() + + set name = "Set Default Unarmed Attack" + set category = "IC" + set src = usr + + var/list/choices + for(var/decl/natural_attack/u_attack as anything in get_mob_natural_attacks()) + var/image/radial_button = new + radial_button.name = capitalize(u_attack.name) + LAZYSET(choices, u_attack, radial_button) + var/decl/natural_attack/new_attack = show_radial_menu(src, src, choices, radius = 42, use_labels = RADIAL_LABELS_OFFSET) + if(QDELETED(src) || !istype(new_attack) || !(new_attack in get_mob_natural_attacks())) + return + default_attack = new_attack + to_chat(src, SPAN_NOTICE("Your default unarmed attack is now [default_attack?.name || "cleared"].")) + if(default_attack) + var/summary = default_attack.summarize() + if(summary) + to_chat(src, SPAN_NOTICE(summary)) + refresh_hud_element(HUD_ATTACK) + +/mob/living/human/ResolveUnarmedAttack(atom/A) + // Hackfix for humans trying to attack someone without hands. + // Dexterity ect. should be checked in these procs regardless, + // but unarmed attacks that don't require hands should still + // have the ability to be used. + if(!(. = ..()) && !get_active_held_item_slot() && check_intent(I_FLAG_HARM) && isliving(A)) + var/mob/living/victim = A + return victim.default_hurt_interaction(src) diff --git a/code/modules/mob/living/human/human_blood.dm b/code/modules/mob/living/human/human_blood.dm new file mode 100644 index 000000000000..56a25031101d --- /dev/null +++ b/code/modules/mob/living/human/human_blood.dm @@ -0,0 +1,248 @@ +/mob/living/human + var/datum/reagents/vessel // Container for blood and BLOOD ONLY. Do not transfer other chems here. + +//Initializes blood vessels +/mob/living/human/proc/make_blood() + if(vessel) + return + vessel = new /datum/reagents(species.blood_volume, src) + if(!should_have_organ(BP_HEART)) //We want the var for safety but we can do without the actual blood. + return + reset_blood() + +//Modifies blood level +/mob/living/human/proc/adjust_blood(var/amt, var/blood_data) + if(!vessel) + make_blood() + + if(!should_have_organ(BP_HEART)) + return + + if(amt && species.blood_reagent) + if(amt > 0) + vessel.add_reagent(species.blood_reagent, amt, blood_data) + else + vessel.remove_any(abs(amt)) + +//Resets blood data +/mob/living/human/proc/reset_blood() + if(!vessel) + make_blood() + + if(!should_have_organ(BP_HEART)) + if(istype(vessel)) + vessel.clear_reagents() + REAGENT_SET_MAX_VOL(vessel, 0) + return + + if(istype(vessel)) + if(REAGENT_TOTAL_VOLUME(vessel) < species.blood_volume) + REAGENT_SET_MAX_VOL(vessel, species.blood_volume) + adjust_blood(species.blood_volume - REAGENT_TOTAL_VOLUME(vessel)) + else if(REAGENT_TOTAL_VOLUME(vessel) > species.blood_volume) + vessel.remove_any(REAGENT_TOTAL_VOLUME(vessel) - species.blood_volume) + REAGENT_SET_MAX_VOL(vessel, species.blood_volume) + + REAGENT_SET_DATA(vessel, species.blood_reagent, list( + DATA_BLOOD_DONOR = weakref(src), + DATA_BLOOD_SPECIES = get_species_name(), + DATA_BLOOD_DNA = get_unique_enzymes(), + DATA_BLOOD_COLOR = species.get_species_blood_color(src), + DATA_BLOOD_TYPE = get_blood_type(), + DATA_BLOOD_TRACE_CHEM = null + )) + +//Makes a blood drop, leaking amt units of blood from the mob +/mob/living/human/proc/drip(var/amt, var/tar = src, var/ddir) + var/datum/reagents/bloodstream = get_injected_reagents() + if(remove_blood(amt)) + if(REAGENT_TOTAL_VOLUME(bloodstream) && REAGENT_TOTAL_VOLUME(vessel)) + var/chem_share = round(0.3 * amt * (REAGENT_TOTAL_VOLUME(bloodstream) / REAGENT_TOTAL_VOLUME(vessel)), 0.01) + bloodstream.remove_any(chem_share * REAGENT_TOTAL_VOLUME(bloodstream)) + blood_splatter(tar, src, (ddir && ddir>0), spray_dir = ddir) + return amt + return 0 + +#define BLOOD_SPRAY_DISTANCE 2 +/mob/living/human/proc/blood_squirt(var/amt, var/turf/sprayloc) + if(amt <= 0 || !istype(sprayloc)) + return + var/spraydir = pick(global.alldirs) + amt = ceil(amt/BLOOD_SPRAY_DISTANCE) + var/bled = 0 + spawn(0) + for(var/i = 1 to BLOOD_SPRAY_DISTANCE) + var/turf/old_sprayloc = sprayloc + sprayloc = get_step(sprayloc, spraydir) + if(!istype(sprayloc) || sprayloc.density) + break + var/hit_dense_obj + var/hit_mob + for(var/thing in sprayloc) + var/atom/A = thing + if(!A.simulated) + continue + + if(isobj(A)) + if(A.density == 1) + hit_dense_obj = TRUE + break + + if(ishuman(A)) + var/mob/living/human/H = A + if(!H.current_posture.prone) + H.bloody_body(src) + H.bloody_hands(src) + var/blinding = FALSE + if(ran_zone() == BP_HEAD) + blinding = TRUE + for(var/slot in global.standard_headgear_slots) + var/obj/item/I = H.get_equipped_item(slot) + if(istype(I) && (I.body_parts_covered & SLOT_EYES)) + blinding = FALSE + break + if(blinding) + SET_STATUS_MAX(H, STAT_BLURRY, 10) + SET_STATUS_MAX(H, STAT_BLIND, 5) + to_chat(H, "You are blinded by a spray of blood!") + else + to_chat(H, "You are hit by a spray of blood!") + hit_mob = TRUE + + if(hit_mob || !A.CanPass(src, sprayloc)) + break + + if(hit_dense_obj) + drip(amt, old_sprayloc, spraydir) + sprayloc = old_sprayloc + else + drip(amt, sprayloc, spraydir) + bled += amt + if(hit_mob) break + sleep(1) + return bled +#undef BLOOD_SPRAY_DISTANCE + +/mob/living/human/remove_blood(amt, absolute = FALSE) + if(!should_have_organ(BP_HEART)) //TODO: Make drips come from the reagents instead. + return 0 + if(!amt) + return 0 + if(!absolute) + amt *= ((src.mob_size/MOB_SIZE_MEDIUM) ** 0.5) + return vessel.remove_any(amt) + +//Transfers blood from reagents to vessel, respecting blood types compatability. +/mob/living/human/inject_blood(var/amount, var/datum/reagents/donor) + if(!should_have_organ(BP_HEART)) + add_to_reagents(species.blood_reagent, amount, REAGENT_DATA(donor, species.blood_reagent)) + return + var/injected_data = REAGENT_DATA(donor, species.blood_reagent) + var/injected_b_type = LAZYACCESS(injected_data, DATA_BLOOD_TYPE) + if(is_blood_incompatible(injected_b_type)) + var/decl/blood_type/blood_decl = injected_b_type && get_blood_type_by_name(injected_b_type) + if(istype(blood_decl)) + add_to_reagents(blood_decl.transfusion_fail_reagent, amount * blood_decl.transfusion_fail_percentage) + else + add_to_reagents(/decl/material/liquid/coagulated_blood, amount * 0.5) + else + adjust_blood(amount, injected_data) + ..() + +/mob/living/human/proc/regenerate_blood(var/amount) + amount *= (species.blood_volume / SPECIES_BLOOD_DEFAULT) + + var/stress_modifier = get_stress_modifier() + if(stress_modifier) + amount *= 1-(get_config_value(/decl/config/num/health_stress_blood_recovery_constant) * stress_modifier) + + var/blood_volume_raw = REAGENT_TOTAL_VOLUME(vessel) + amount = max(0,min(amount, species.blood_volume - blood_volume_raw)) + if(amount) + adjust_blood(amount, get_blood_data()) + return amount + +//For humans, blood does not appear from blue, it comes from vessels. +/mob/living/human/take_blood(obj/item/chems/container, var/amount) + + if(!vessel) + make_blood() + + if(!should_have_organ(BP_HEART)) + reagents.trans_to_obj(container, amount) + return 1 + + if(REAGENT_TOTAL_VOLUME(vessel) < amount) + return null + if(vessel.has_reagent(species.blood_reagent)) + REAGENT_SET_DATA(vessel, species.blood_reagent, get_blood_data()) + vessel.trans_to_holder(container.reagents, amount) + return 1 + +//Percentage of maximum blood volume. +/mob/living/human/proc/get_blood_volume() + return species.blood_volume ? round((REAGENT_TOTAL_VOLUME(vessel)/species.blood_volume)*100) : 0 + +//Percentage of maximum blood volume, affected by the condition of circulation organs +/mob/living/human/proc/get_blood_circulation() + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(!heart) + return 0.25 * get_blood_volume() + + var/blood_volume = get_blood_volume() + var/recent_pump = LAZYACCESS(heart.external_pump, 1) > world.time - (20 SECONDS) + var/pulse_mod = 1 + if((status_flags & FAKEDEATH) || BP_IS_PROSTHETIC(heart)) + pulse_mod = 1 + else + switch(heart.pulse) + if(PULSE_NONE) + if(recent_pump) + pulse_mod = LAZYACCESS(heart.external_pump, 2) + else + pulse_mod *= 0.25 + if(PULSE_SLOW) + pulse_mod *= 0.9 + if(PULSE_FAST) + pulse_mod *= 1.1 + if(PULSE_2FAST, PULSE_THREADY) + pulse_mod *= 1.25 + blood_volume *= pulse_mod + blood_volume *= current_posture.blood_volume_multiplier + + var/min_efficiency = recent_pump ? 0.5 : 0.3 + blood_volume *= max(min_efficiency, (1-(heart.get_organ_damage() / heart.max_damage))) + if(!heart.open && has_chemical_effect(CE_BLOCKAGE, 1)) + blood_volume *= max(0, 1-GET_CHEMICAL_EFFECT(src, CE_BLOCKAGE)) + + return min(blood_volume, 100) + +//Whether the species needs blood to carry oxygen. Used in get_blood_oxygenation and may be expanded based on blood rather than species in the future. +/mob/living/human/proc/blood_carries_oxygen() + return species.blood_oxy + +//Percentage of maximum blood volume, affected by the condition of circulation organs, affected by the oxygen loss. What ultimately matters for brain +/mob/living/human/proc/get_blood_oxygenation() + var/blood_volume = get_blood_circulation() + if(blood_carries_oxygen()) + if(is_asystole()) // Heart is missing or isn't beating and we're not breathing (hardcrit) + return min(blood_volume, BLOOD_VOLUME_SURVIVE) + + if(!need_breathe()) + return blood_volume + else + blood_volume = 100 + + // blood_volume_mod is 1 with no oxyloss, 0 at half species health (50%), and cannot go below 0 + var/blood_volume_mod = max(0, (1 - getOxyLossFraction()*2)) + var/oxygenated_mult = 0 + switch(GET_CHEMICAL_EFFECT(src, CE_OXYGENATED)) + if(1) + oxygenated_mult = 0.5 + if(2) + oxygenated_mult = 0.7 + if(3) + oxygenated_mult = 0.9 + blood_volume_mod += oxygenated_mult * (1 - blood_volume_mod) // give us back a fraction of our missing oxygenation + blood_volume *= blood_volume_mod + return clamp(blood_volume, 0, 100) diff --git a/code/modules/mob/living/human/human_damage.dm b/code/modules/mob/living/human/human_damage.dm new file mode 100644 index 000000000000..76378ffb374a --- /dev/null +++ b/code/modules/mob/living/human/human_damage.dm @@ -0,0 +1,412 @@ +/mob/living/human/get_life_damage_types() + var/static/list/brain_life_damage_types = list( + BRAIN + ) + return brain_life_damage_types + +//Updates the mob's health from organs and mob damage variables +/mob/living/human/update_health() + . = ..() + //TODO: fix husking + if(. && stat == DEAD && (get_damage(BRUTE) - get_damage(BURN)) < get_config_value(/decl/config/num/health_health_threshold_dead)) + add_genetic_condition(GENE_COND_HUSK) + +/mob/living/human/adjustBrainLoss(var/amount, var/do_update_health = TRUE) + if(!(status_flags & GODMODE) && should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/sponge = GET_INTERNAL_ORGAN(src, BP_BRAIN) + if(sponge) + sponge.take_damage(amount) + ..() + +/mob/living/human/setBrainLoss(var/amount) + if(status_flags & GODMODE) return 0 //godmode + if(should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/sponge = GET_INTERNAL_ORGAN(src, BP_BRAIN) + if(sponge) + sponge.set_organ_damage(amount) + update_health() + +/mob/living/human/getBrainLoss() + if(status_flags & GODMODE) return 0 //godmode + if(should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/sponge = GET_INTERNAL_ORGAN(src, BP_BRAIN) + if(sponge) + if(sponge.status & ORGAN_DEAD) + return sponge.species.total_health + return sponge.get_organ_damage() + return species.total_health + return 0 + +//Straight pain values, not affected by painkillers etc +/mob/living/human/getHalLoss() + if(isnull(last_pain)) + last_pain = 0 + for(var/obj/item/organ/external/E in get_external_organs()) + last_pain += E.get_pain() + return last_pain + +/mob/living/human/setHalLoss(var/amount) + take_damage(get_damage(PAIN)-amount, PAIN) + +/mob/living/human/adjustHalLoss(var/amount, var/do_update_health = TRUE) + var/heal = (amount < 0) + amount = abs(amount) + var/list/limbs = get_external_organs() + if(LAZYLEN(limbs)) + var/list/pick_organs = limbs.Copy() + while(amount > 0 && pick_organs.len) + var/obj/item/organ/external/E = pick(pick_organs) + pick_organs -= E + if(!istype(E)) + continue + + if(heal) + amount -= E.remove_pain(amount) + else + amount -= E.add_pain(amount) + BITSET(hud_updateflag, HEALTH_HUD) + if(do_update_health) + update_health() + +//These procs fetch a cumulative total damage from all organs +/mob/living/human/getBruteLoss() + var/amount = 0 + for(var/obj/item/organ/external/O in get_external_organs()) + if(BP_IS_PROSTHETIC(O) && !O.is_vital_to_owner()) + continue //robot limbs don't count towards shock and crit + amount += O.brute_dam + return amount + +/mob/living/human/getFireLoss() + var/amount = 0 + for(var/obj/item/organ/external/O in get_external_organs()) + if(BP_IS_PROSTHETIC(O) && !O.is_vital_to_owner()) + continue //robot limbs don't count towards shock and crit + amount += O.burn_dam + return amount + +/mob/living/human/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) // take/heal overall call update_health regardless of arg + if(amount > 0) + take_overall_damage(amount, 0) + else + heal_overall_damage(-amount, 0) + BITSET(hud_updateflag, HEALTH_HUD) + if(amount > 0 && istype(ai)) + ai.retaliate() + +/mob/living/human/adjustFireLoss(var/amount, var/do_update_health = TRUE) + if(amount > 0) + take_overall_damage(0, amount) + else + heal_overall_damage(0, -amount) + BITSET(hud_updateflag, HEALTH_HUD) + if(amount > 0 && istype(ai)) + ai.retaliate() + +/mob/living/human/getCloneLoss() + var/amount = 0 + for(var/obj/item/organ/external/E in get_external_organs()) + amount += E.get_genetic_damage() + return amount + +/mob/living/human/setCloneLoss(var/amount) + take_damage(get_damage(CLONE)-amount, CLONE) + +/mob/living/human/adjustCloneLoss(var/amount, var/do_update_health = TRUE) + var/heal = amount < 0 + amount = abs(amount) + var/list/limbs = get_external_organs() + if(LAZYLEN(limbs)) + var/list/pick_organs = limbs.Copy() + while(amount > 0 && pick_organs.len) + var/obj/item/organ/external/E = pick(pick_organs) + pick_organs -= E + if(heal) + amount -= E.remove_genetic_damage(amount) + else + amount -= E.add_genetic_damage(amount) + BITSET(hud_updateflag, HEALTH_HUD) + ..() + +/mob/living/human/proc/getOxyLossPercent() + return getOxyLossFraction() * 100 + +/mob/living/human/proc/getOxyLossFraction() + return (get_damage(OXY) / species.total_health) + +/mob/living/human/getOxyLoss() + if(need_breathe()) + var/obj/item/organ/internal/lungs/breathe_organ = get_organ(get_bodytype().breathing_organ, /obj/item/organ/internal/lungs) + return breathe_organ ? breathe_organ.oxygen_deprivation : species.total_health + return 0 + +/mob/living/human/setOxyLoss(var/amount) + take_damage(amount - get_damage(OXY), OXY) + +/mob/living/human/adjustOxyLoss(var/damage, var/do_update_health = TRUE) + . = FALSE + if(need_breathe()) + var/obj/item/organ/internal/lungs/breathe_organ = get_organ(get_bodytype().breathing_organ, /obj/item/organ/internal/lungs) + if(breathe_organ) + breathe_organ.adjust_oxygen_deprivation(damage) + BITSET(hud_updateflag, HEALTH_HUD) + . = TRUE + ..(do_update_health = FALSE) // Oxyloss cannot directly kill humans + +/mob/living/human/getToxLoss() + if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) + return 0 + var/amount = 0 + for(var/obj/item/organ/internal/I in get_internal_organs()) + amount += I.getToxLoss() + return amount + +/mob/living/human/setToxLoss(var/amount) + if(!(species.species_flags & SPECIES_FLAG_NO_POISON) && !isSynthetic()) + take_damage(get_damage(TOX)-amount, TOX) + +// TODO: better internal organ damage procs. +/mob/living/human/adjustToxLoss(var/amount, var/do_update_health = TRUE) + + if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) + return + + var/heal = amount < 0 + amount = abs(amount) + + if (!heal) + amount *= get_toxin_resistance() + var/antitox = GET_CHEMICAL_EFFECT(src, CE_ANTITOX) + if(antitox) + amount *= 1 - antitox * 0.25 + + var/list/pick_organs = get_internal_organs() + if(!LAZYLEN(pick_organs)) + return + pick_organs = shuffle(pick_organs.Copy()) + + // Prioritize damaging our filtration organs first. + for(var/organ in list(BP_KIDNEYS, BP_LIVER)) + var/obj/item/organ/internal/lump = GET_INTERNAL_ORGAN(src, organ) + if(lump) + pick_organs -= lump + pick_organs.Insert(1, lump) + + // Move the brain to the very end since damage to it is vastly more dangerous + // (and isn't technically counted as toxloss) than general organ damage. + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(src, BP_BRAIN) + if(brain) + pick_organs -= brain + pick_organs += brain + + for(var/obj/item/organ/internal/organ as anything in pick_organs) + if(amount <= 0) + break + var/organ_damage = organ.get_organ_damage() + if(heal) + if(organ_damage < amount) + amount -= organ_damage + organ.set_organ_damage(0) + else + organ.adjust_organ_damage(-(amount)) + amount = 0 + else + var/cap_dam = organ.max_damage - organ_damage + if(amount >= cap_dam) + organ.take_damage(cap_dam, silent=TRUE) + amount -= cap_dam + else + organ.take_damage(amount, silent=TRUE) + amount = 0 + + if(do_update_health) + update_health() + +/mob/living/human/proc/can_autoheal(var/dam_type) + if(!species || !dam_type) + return FALSE + if(dam_type == BRUTE || dam_type == BURN) + return(get_damage(dam_type) < species.total_health / 2) + return FALSE + +//////////////////////////////////////////// + +//Returns a list of damaged organs +/mob/living/human/proc/get_damaged_organs(var/brute, var/burn) + var/list/obj/item/organ/external/parts = list() + for(var/obj/item/organ/external/O in get_external_organs()) + if((brute && O.brute_dam) || (burn && O.burn_dam)) + parts += O + return parts + +//Returns a list of damageable organs +/mob/living/human/proc/get_damageable_organs() + var/list/obj/item/organ/external/parts = list() + for(var/obj/item/organ/external/O in get_external_organs()) + if(O.is_damageable()) + parts += O + return parts + +//Heals ONE external organ, organ gets randomly selected from damaged ones. +//It automatically updates damage overlays if necesary +//It automatically updates health status +/mob/living/human/heal_organ_damage(var/brute, var/burn, var/affect_robo = FALSE, var/update_health = TRUE) + var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn) + if(!parts.len) return + var/obj/item/organ/external/picked = pick(parts) + if(picked.heal_damage(brute,burn,robo_repair = affect_robo)) + BITSET(hud_updateflag, HEALTH_HUD) + update_health() + + +//TODO reorganize damage procs so that there is a clean API for damaging living mobs + +/* +In most cases it makes more sense to use apply_damage() instead! And make sure to check armour if applicable. +*/ +//Damages ONE external organ, organ gets randomly selected from damagable ones. +//It automatically updates damage overlays if necesary +//It automatically updates health status +/mob/living/human/take_organ_damage(var/brute = 0, var/burn = 0, var/bypass_armour = FALSE, var/override_droplimb) + var/list/parts = get_damageable_organs() + if(!length(parts)) + return + var/obj/item/organ/external/picked = pick(parts) + . = FALSE + if(brute && picked.take_damage(brute, override_droplimb = override_droplimb, do_update_health = FALSE)) + . = TRUE + if(burn && picked.take_damage(burn, BURN, override_droplimb = override_droplimb, do_update_health = FALSE)) + . = TRUE + if(.) + update_health() + BITSET(hud_updateflag, HEALTH_HUD) + +//Heal MANY external organs, in random order +/mob/living/human/heal_overall_damage(var/brute, var/burn) + var/list/obj/item/organ/external/parts = get_damaged_organs(brute,burn) + + while(parts.len && (brute>0 || burn>0) ) + var/obj/item/organ/external/picked = pick(parts) + + var/brute_was = picked.brute_dam + var/burn_was = picked.burn_dam + + picked.heal_damage(brute,burn) + + brute -= (brute_was-picked.brute_dam) + burn -= (burn_was-picked.burn_dam) + + parts -= picked + update_health() + BITSET(hud_updateflag, HEALTH_HUD) + +// damage MANY external organs, in random order +/mob/living/human/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0, var/used_weapon = null) + if(status_flags & GODMODE) + return //godmode + + var/list/obj/item/organ/external/parts = get_damageable_organs() + if(!parts.len) + return + + var/dam_flags = (sharp? DAM_SHARP : 0)|(edge? DAM_EDGE : 0) + var/brute_avg = brute / parts.len + var/burn_avg = burn / parts.len + for(var/obj/item/organ/external/E in parts) + if(QDELETED(E)) + continue + if(E.owner != src) + continue // The code below may affect the children of an organ. + + if(brute_avg) + apply_damage(damage = brute_avg, damagetype = BRUTE, damage_flags = dam_flags, used_weapon = used_weapon, silent = TRUE, given_organ = E) + if(burn_avg) + apply_damage(damage = burn_avg, damagetype = BURN, damage_flags = dam_flags, used_weapon = used_weapon, silent = TRUE, given_organ = E) + + update_health() + BITSET(hud_updateflag, HEALTH_HUD) + +/* +This function restores all organs. +*/ +/mob/living/human/restore_all_organs(var/ignore_organ_traits) + get_bodytype()?.create_missing_organs(src) // root body part should never be missing on a mob + for(var/bodypart in global.all_limb_tags_by_depth) + var/obj/item/organ/external/current_organ = GET_EXTERNAL_ORGAN(src, bodypart) + if(current_organ) + current_organ.rejuvenate(ignore_organ_traits) + recheck_bad_external_organs() + verbs -= /mob/living/human/proc/undislocate + + +/mob/living/human/apply_damage(damage = 0, damagetype = BRUTE, def_zone, damage_flags = 0, obj/used_weapon, armor_pen, silent = FALSE, obj/item/organ/external/given_organ) + if(status_flags & GODMODE) + return //godmode + + var/obj/item/organ/external/organ = given_organ + if(!organ) + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) + if(damage_flags & DAM_DISPERSED) + var/old_damage = damage + var/tally + silent = TRUE // Will damage a lot of organs, probably, so avoid spam. + for(var/zone in organ_rel_size) + tally += organ_rel_size[zone] + for(var/zone in organ_rel_size) + damage = old_damage * organ_rel_size[zone]/tally + def_zone = zone + . = .() || . + return + def_zone = ran_zone(def_zone, target = src) + organ = GET_EXTERNAL_ORGAN(src, check_zone(def_zone, src)) + + //Handle other types of damage + var/static/list/human_handled_damage_types = list(BRUTE, BURN, PAIN, CLONE) + if(!(damagetype in human_handled_damage_types)) + return ..() + + if(!istype(organ)) + return 0 // This is reasonable and means the organ is missing. + + handle_suit_punctures(damagetype, damage, def_zone) + + var/list/after_armor = modify_damage_by_armor(def_zone, damage, damagetype, damage_flags, src, armor_pen, silent) + damage = after_armor[1] + damagetype = after_armor[2] + damage_flags = after_armor[3] + if(!damage) + return 0 + + if(damage > 15 && prob(damage*4) && organ.can_feel_pain()) + make_reagent(round(damage/10), /decl/material/liquid/adrenaline) + + var/datum/wound/created_wound + damageoverlaytemp = 20 + switch(damagetype) + if(BRUTE, BURN) + created_wound = organ.take_damage(damage, damagetype, damage_flags = damage_flags, inflicter = used_weapon, do_update_health = FALSE) + if(PAIN) + organ.add_pain(damage) + if(CLONE) + organ.add_genetic_damage(damage) + // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + update_health() + BITSET(hud_updateflag, HEALTH_HUD) + return created_wound + +// Find out in how much pain the mob is at the moment. +/mob/living/human/proc/get_shock() + + if (!can_feel_pain()) + return 0 + + var/traumatic_shock = get_damage(PAIN) + traumatic_shock -= GET_CHEMICAL_EFFECT(src, CE_PAINKILLER) + + if(stat == UNCONSCIOUS) + traumatic_shock *= 0.6 + return max(0,traumatic_shock) diff --git a/code/modules/mob/living/human/human_defense.dm b/code/modules/mob/living/human/human_defense.dm new file mode 100644 index 000000000000..333e52101631 --- /dev/null +++ b/code/modules/mob/living/human/human_defense.dm @@ -0,0 +1,422 @@ +/* +Contains most of the procs that are called when a mob is attacked by something + +bullet_act +ex_act +meteor_act + +*/ + +/mob/living/human/bullet_act(var/obj/item/projectile/P, var/def_zone) + + def_zone = check_zone(def_zone, src) + if(!has_organ(def_zone)) + return PROJECTILE_FORCE_MISS //if they don't have the organ in question then the projectile just passes by. + + //Shields + var/shield_check = check_shields(P.damage, P, null, def_zone, P) + if(shield_check) + if(shield_check < 0) + return shield_check + else + P.on_hit(src, 100, def_zone) + return 100 + + var/blocked = ..(P, def_zone) + + radio_interrupt_cooldown = world.time + (RADIO_INTERRUPT_DEFAULT * 0.8) + + return blocked + +/mob/living/human/stun_effect_act(stun_amount, agony_amount, def_zone, used_weapon) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(src, def_zone) + if(!affected) + return + + var/siemens_coeff = get_siemens_coefficient_organ(affected) + stun_amount *= siemens_coeff + agony_amount *= siemens_coeff + agony_amount *= affected.get_agony_multiplier() + + affected.stun_act(stun_amount, agony_amount) + + radio_interrupt_cooldown = world.time + RADIO_INTERRUPT_DEFAULT + + if(!affected.can_feel_pain() || (GET_CHEMICAL_EFFECT(src, CE_PAINKILLER)/3 > agony_amount)) //stops blurry eyes and stutter if you can't feel pain + agony_amount = 0 + + ..(stun_amount, agony_amount, def_zone) + +/mob/living/human/get_blocked_ratio(def_zone, damage_type, damage_flags, armor_pen, damage) + if(!def_zone && (damage_flags & DAM_DISPERSED)) + var/tally + for(var/zone in organ_rel_size) + tally += organ_rel_size[zone] + for(var/zone in organ_rel_size) + def_zone = zone + . += .() * organ_rel_size/tally + return + return ..() + +/mob/living/human/get_armors_by_zone(obj/item/organ/external/def_zone, damage_type, damage_flags) + if(!def_zone) + def_zone = ran_zone() + if(!istype(def_zone)) + def_zone = GET_EXTERNAL_ORGAN(src, def_zone) + if(!def_zone) + return ..() + + . = list() + for(var/slot in global.standard_clothing_slots) + var/obj/item/clothing/gear = get_equipped_item(slot) + if(!istype(gear)) + continue + if(LAZYLEN(gear.accessories)) + for(var/obj/item/clothing/accessory in gear.accessories) + if(accessory.body_parts_covered & def_zone.body_part) + var/armor = get_extension(accessory, /datum/extension/armor) + if(armor) + . += armor + if(gear.body_parts_covered & def_zone.body_part) + var/armor = get_extension(gear, /datum/extension/armor) + if(armor) + . += armor + + // Add inherent armor to the end of list so that protective equipment is checked first + . += ..() + +/mob/living/human/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) + + for (var/obj/item/grab/grab as anything in grabbed_by) + if(grab.resolve_item_attack(user, I, target_zone)) + return null + + if(user == src) // Attacking yourself can't miss + return target_zone + + var/accuracy_penalty = user.melee_accuracy_mods() + accuracy_penalty += 10*get_skill_difference(SKILL_COMBAT, user) + accuracy_penalty += 10*(I.w_class - ITEM_SIZE_NORMAL) + accuracy_penalty -= I.melee_accuracy_bonus + + var/hit_zone = get_zone_with_miss_chance(target_zone, src, accuracy_penalty) + + if(!hit_zone) + visible_message("\The [user] misses [src] with \the [I]!") + return null + + if(check_shields(I.get_attack_force(user), I, user, target_zone, I)) + return null + + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, hit_zone) + if (!affecting) + to_chat(user, "They are missing that limb!") + return null + + return hit_zone + +/mob/living/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, hit_zone) + if(!affecting) + return //should be prevented by attacked_with_item() but for sanity. + + var/weapon_mention + if(I.attack_message_name()) + weapon_mention = " with [I.attack_message_name()]" + if(effective_force) + visible_message("[src] has been [I.pick_attack_verb()] in the [affecting.name][weapon_mention] by [user]!") + else + visible_message("[src] has been [I.pick_attack_verb()] in the [affecting.name][weapon_mention] by [user]!") + return // If it has no force then no need to do anything else. + + . = standard_weapon_hit_effects(I, user, effective_force, hit_zone) + if(istype(ai)) + ai.retaliate(user) + +/mob/living/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, hit_zone) + if(!affecting) + return 0 + + var/blocked = get_blocked_ratio(hit_zone, I.atom_damage_type, I.damage_flags(), I.armor_penetration, I.get_attack_force(user)) + // Handle striking to cripple. + if(user.check_intent(I_FLAG_DISARM)) + effective_force *= 0.66 //reduced effective force... + if(!..(I, user, effective_force, hit_zone)) + return 0 + + //set the dislocate mult less than the effective force mult so that + //dislocating limbs on disarm is a bit easier than breaking limbs on harm + attack_joint(affecting, I, effective_force, 0.5, blocked) //...but can dislocate joints + else if(!..()) + return 0 + + if(effective_force > 10 || effective_force >= 5 && prob(33)) + forcesay(global.hit_appends) //forcesay checks stat already + radio_interrupt_cooldown = world.time + (RADIO_INTERRUPT_DEFAULT * 0.8) //getting beat on can briefly prevent radio use + + if(!stat && I.weapon_can_knock_prone && (I.atom_damage_type == BRUTE || I.atom_damage_type == PAIN) && prob(25 + (effective_force * 2))) + if(!stat) + if(headcheck(hit_zone)) + //Harder to score a stun but if you do it lasts a bit longer + if(prob(effective_force)) + apply_effect(20, PARALYZE, blocked) + if(current_posture.prone) + visible_message("[src] [species.knockout_message]") + else + //Easier to score a stun but lasts less time + if(prob(effective_force + 5)) + apply_effect(3, WEAKEN, blocked) + if(current_posture.prone) + visible_message("[src] has been knocked down!") + + //Apply blood + attack_bloody(I, user, effective_force, hit_zone) + animate_receive_damage(src) + return 1 + +/mob/living/human/proc/attack_bloody(obj/item/used_item, mob/attacker, var/effective_force, var/hit_zone) + if(used_item.atom_damage_type != BRUTE) + return + + if(!should_have_organ(BP_HEART)) + return + + //make non-sharp low-force weapons less likely to be bloodied + if(used_item.is_sharp() || prob(effective_force*4)) + if(!(used_item.atom_flags & ATOM_FLAG_NO_BLOOD)) + used_item.add_blood(src) + else + return //if the weapon itself didn't get bloodied than it makes little sense for the target to be bloodied either + + //getting the weapon bloodied is easier than getting the target covered in blood, so run prob() again + if(prob(33 + used_item.is_sharp() * 10)) + var/turf/location = loc + if(istype(location) && location.simulated) + location.add_blood(src) + if(ishuman(attacker)) + var/mob/living/human/H = attacker + if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood + H.bloody_body(src) + H.bloody_hands(src) + + switch(hit_zone) + if(BP_HEAD) + var/obj/item/mask = get_equipped_item(slot_wear_mask_str) + if(mask) + mask.add_blood(src) + update_equipment_overlay(slot_wear_mask_str, FALSE) + var/obj/item/head = get_equipped_item(slot_head_str) + if(head) + head.add_blood(src) + update_equipment_overlay(slot_head_str, FALSE) + var/obj/item/glasses = get_equipped_item(slot_glasses_str) + if(glasses && prob(33)) + glasses.add_blood(src) + update_equipment_overlay(slot_glasses_str, FALSE) + if(BP_CHEST) + bloody_body(src) + +/mob/living/human/proc/projectile_hit_bloody(obj/item/projectile/P, var/effective_force, var/hit_zone, var/obj/item/organ/external/organ) + if(P.atom_damage_type != BRUTE || P.nodamage) + return + if(!(P.is_sharp() || prob(effective_force*4))) + return + if(prob(effective_force)) + var/turf/location = loc + if(istype(location) && location.simulated) + location.add_blood(src) + if(hit_zone) + organ = GET_EXTERNAL_ORGAN(src, hit_zone) + if(organ) + var/list/bloody = get_covering_equipped_items(organ.body_part) + for(var/obj/item/clothing/C in bloody) + C.add_blood(src) + C.update_clothing_icon() + +/mob/living/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/used_item, var/effective_force, var/dislocate_mult, var/blocked) + if(!organ || organ.is_dislocated() || !(organ.limb_flags & ORGAN_FLAG_CAN_DISLOCATE) || blocked >= 100) + return 0 + if(used_item.atom_damage_type != BRUTE) + return 0 + + //want the dislocation chance to be such that the limb is expected to dislocate after dealing a fraction of the damage needed to break the limb + var/dislocate_chance = effective_force/(dislocate_mult * organ.min_broken_damage * get_config_value(/decl/config/num/health_organ_health_multiplier))*100 + if(prob(dislocate_chance * blocked_mult(blocked))) + visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!") + organ.dislocate(1) + return 1 + return 0 + +/mob/living/human/emag_act(var/remaining_charges, mob/user, var/emag_source) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(src, user.get_target_zone()) + if(!affecting || !affecting.is_robotic()) + to_chat(user, "That limb isn't robotic.") + return -1 + if(affecting.status & ORGAN_SABOTAGED) + to_chat(user, "[src]'s [affecting.name] is already sabotaged!") + return -1 + to_chat(user, "You sneakily slide [emag_source] into the dataport on [src]'s [affecting.name] and short out the safeties.") + affecting.status |= ORGAN_SABOTAGED + return 1 + +/mob/living/human/hitby(atom/movable/AM, var/datum/thrownthing/TT) + // empty active hand and we're in throw mode, so we can catch it + if(isobj(AM) && in_throw_mode && !get_active_held_item() && TT.speed <= THROWFORCE_SPEED_DIVISOR && !incapacitated() && isturf(AM.loc)) + put_in_active_hand(AM) + visible_message(SPAN_NOTICE("\The [src] catches \the [AM]!")) + toggle_throw_mode(FALSE) + process_momentum(AM, TT) + return FALSE + return ..() + +/mob/living/human/proc/bloody_hands(var/mob/living/source, var/amount = 2) + var/obj/item/clothing/gloves/gloves = get_equipped_item(slot_gloves_str) + if(istype(gloves)) + gloves.add_blood(source, amount) + else + add_blood(source, amount) + //updates on-mob overlays for bloody hands and/or bloody gloves + update_equipment_overlay(slot_gloves_str) + +/mob/living/human/proc/bloody_body(var/mob/living/source) + var/obj/item/gear = get_equipped_item(slot_wear_suit_str) + if(gear) + gear.add_blood(source) + update_equipment_overlay(slot_wear_suit_str, redraw_mob = FALSE) + gear = get_equipped_item(slot_w_uniform_str) + if(gear) + gear.add_blood(source) + update_equipment_overlay(slot_w_uniform_str, redraw_mob = FALSE) + +/mob/living/human/proc/handle_suit_punctures(var/damtype, var/damage, var/def_zone) + + // Tox and oxy don't matter to suits. + if(damtype != BURN && damtype != BRUTE) return + + // The rig might soak this hit, if we're wearing one. + var/obj/item/rig/rig = get_rig() + if(rig) + rig.take_hit(damage) + + // We may also be taking a suit breach. + var/obj/item/clothing/suit/space/suit = get_equipped_item(slot_wear_suit_str) + if(istype(suit)) + suit.create_breaches(damtype, damage) + +/mob/living/human/reagent_permeability() + var/perm = 0 + + var/list/perm_by_part = list( + "head" = THERMAL_PROTECTION_HEAD, + "upper_torso" = THERMAL_PROTECTION_UPPER_TORSO, + "lower_torso" = THERMAL_PROTECTION_LOWER_TORSO, + "legs" = THERMAL_PROTECTION_LEG_LEFT + THERMAL_PROTECTION_LEG_RIGHT, + "feet" = THERMAL_PROTECTION_FOOT_LEFT + THERMAL_PROTECTION_FOOT_RIGHT, + "arms" = THERMAL_PROTECTION_ARM_LEFT + THERMAL_PROTECTION_ARM_RIGHT, + "hands" = THERMAL_PROTECTION_HAND_LEFT + THERMAL_PROTECTION_HAND_RIGHT + ) + + for(var/obj/item/clothing/C in src.get_equipped_items()) + if(C.permeability_coefficient == 1 || !C.body_parts_covered) + continue + if(C.body_parts_covered & SLOT_HEAD) + perm_by_part["head"] *= C.permeability_coefficient + if(C.body_parts_covered & SLOT_UPPER_BODY) + perm_by_part["upper_torso"] *= C.permeability_coefficient + if(C.body_parts_covered & SLOT_LOWER_BODY) + perm_by_part["lower_torso"] *= C.permeability_coefficient + if(C.body_parts_covered & SLOT_LEGS) + perm_by_part["legs"] *= C.permeability_coefficient + if(C.body_parts_covered & SLOT_FEET) + perm_by_part["feet"] *= C.permeability_coefficient + if(C.body_parts_covered & SLOT_ARMS) + perm_by_part["arms"] *= C.permeability_coefficient + if(C.body_parts_covered & SLOT_HANDS) + perm_by_part["hands"] *= C.permeability_coefficient + + for(var/part in perm_by_part) + perm += perm_by_part[part] + + return perm + +/mob/living/human/lava_act(datum/gas_mixture/air, temperature, pressure) + var/was_burned = FireBurn(0.4 * vsc.fire_firelevel_multiplier, temperature, pressure) + if (was_burned) + fire_act(air, temperature) + return FALSE + + +/mob/living/human/explosion_act(severity) + ..() + if(QDELETED(src)) + return + + var/b_loss = null + var/f_loss = null + switch (severity) + if(1) + b_loss = 400 + f_loss = 100 + var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) + throw_at(target, 200, 4) + if(2) + b_loss = 60 + f_loss = 60 + if (get_sound_volume_multiplier() >= 0.2) + SET_STATUS_MAX(src, STAT_TINNITUS, 30) + SET_STATUS_MAX(src, STAT_DEAF, 120) + if(prob(70)) + SET_STATUS_MAX(src, STAT_PARA, 10) + if(3) + b_loss = 30 + if (get_sound_volume_multiplier() >= 0.2) + SET_STATUS_MAX(src, STAT_TINNITUS, 15) + SET_STATUS_MAX(src, STAT_DEAF, 60) + if (prob(50)) + SET_STATUS_MAX(src, STAT_PARA, 10) + + // focus most of the blast on one organ + apply_damage(0.7 * b_loss, BRUTE, null, DAM_EXPLODE, used_weapon = "Explosive blast") + apply_damage(0.7 * f_loss, BURN, null, DAM_EXPLODE, used_weapon = "Explosive blast") + + // distribute the remaining 30% on all limbs equally (including the one already dealt damage) + apply_damage(0.3 * b_loss, BRUTE, null, DAM_EXPLODE | DAM_DISPERSED, used_weapon = "Explosive blast") + apply_damage(0.3 * f_loss, BURN, null, DAM_EXPLODE | DAM_DISPERSED, used_weapon = "Explosive blast") + +//Used by various things that knock people out by applying blunt trauma to the head. +//Checks that the species has a "head" (brain containing organ) and that hit_zone refers to it. +/mob/living/human/proc/headcheck(var/target_zone, var/brain_tag = BP_BRAIN) + + target_zone = check_zone(target_zone, src) + + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(src, brain_tag) + if(!brain || brain.parent_organ != target_zone) + return FALSE + + //if the parent organ is significantly larger than the brain organ, then hitting it is not guaranteed + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(src, target_zone) + if(!head) + return FALSE + if(head.w_class > brain.w_class + 1) + return prob(100 / 2**(head.w_class - brain.w_class - 1)) + return TRUE + +/mob/living/human/flash_eyes(var/intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + var/vision_organ_tag = get_vision_organ_tag() + if(vision_organ_tag) + var/obj/item/organ/internal/eyes/I = get_organ(vision_organ_tag, /obj/item/organ/internal/eyes) + if(I) + I.additional_flash_effects(intensity) + return ..() + +/* +Contians the proc to handle radiation. +Specifically made to do radiation burns. +*/ +/mob/living/human/apply_radiation(damage) + ..() + if(!isSynthetic() && !ignore_rads) + damage = 0.25 * damage * (species ? species.get_radiation_mod(src) : 1) + take_damage(BURN, damage) + return TRUE diff --git a/code/modules/mob/living/human/human_defines.dm b/code/modules/mob/living/human/human_defines.dm new file mode 100644 index 000000000000..ef71388b6bb9 --- /dev/null +++ b/code/modules/mob/living/human/human_defines.dm @@ -0,0 +1,73 @@ +/mob/living/human + + desc = null // Desc is largely generated in examine procs. + ai = /datum/mob_controller/human + mob_bump_flag = HUMAN + mob_push_flags = ~HEAVY + mob_swap_flags = ~HEAVY + weather_sensitive = TRUE + + /// If true, the next icon update will also regenerate the body. + var/regenerate_body_icon = FALSE + /// Skin tone + var/skin_tone = 0 + /// multiplies melee combat damage + var/damage_multiplier = 1 + var/list/worn_underwear = list() + var/list/background_info = list() + var/icon/stand_icon = null + /// Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life() + var/voice = "" + /// Used for determining if we need to process all organs or just some or even none. + var/last_dam = -1 + var/mob/remoteview_target = null + var/hand_blood_color + var/list/flavor_texts = list() + /// We are a robutt. + var/full_prosthetic + /// Number of robot limbs. + var/robolimb_count = 0 + /// The world_time where an unarmed attack was done + var/last_attack = 0 + /// Total level of visualy impairing items + var/equipment_tint_total = 0 + /// Darksight modifier from equipped items + var/equipment_darkness_modifier + /// Extra vision flags from equipped items + var/equipment_vision_flags + /// Max see invibility level granted by equipped items + var/equipment_see_invis + /// Eye prescription granted by equipped items + var/equipment_prescription + var/equipment_light_protection + /// Extra overlays from equipped items + var/list/equipment_overlays = list() + var/datum/mil_branch/char_branch = null + var/datum/mil_rank/char_rank = null + /// default unarmed attack + var/decl/natural_attack/default_attack + /// machine that is currently applying visual effects to this mob. Only used for camera monitors currently. + var/obj/machinery/machine_visual + var/shock_stage + var/rounded_shock_stage + /// var for caching last pain calc to avoid looping through organs over and over and over again + var/last_pain + var/vital_organ_missing_time + /// Used to look up records when the client is logged out. + var/comments_record_id + /// Active emote/pose - appended to examine + var/pose = null + /// Reagent holder for bloodstream reagents + var/datum/reagents/metabolism/bloodstr + /// Reagent holder for contact reagents + var/datum/reagents/metabolism/touching + /// Should this mob ignore radiation? + var/ignore_rads = FALSE + /// Whether the mob is performing cpr or not. + var/performing_cpr = FALSE + /// Cooldown tracker for throwing up. + var/lastpuke = 0 + /// Reference to the tank we are currently breathing from. + var/obj/item/tank/internal + /// Contains environment tolerances and language information, along with a lot of other stuff, usually set during Initialize(). + var/decl/species/species diff --git a/code/modules/mob/living/human/human_examine_decl.dm b/code/modules/mob/living/human/human_examine_decl.dm new file mode 100644 index 000000000000..bad406e8b985 --- /dev/null +++ b/code/modules/mob/living/human/human_examine_decl.dm @@ -0,0 +1,9 @@ +/decl/human_examination //This is essentially a stub-method for modpacks to be able to add onto the human examination stuff due to ... messy stuff. + var/priority = 0 + /// If non-null, this is inserted before this entry if there is not already a postfix before it. + var/section_prefix = null + /// If non-null, this is inserted after this entry if there exist entries after it. + var/section_postfix = null + +/decl/human_examination/proc/do_examine(mob/user, distance, mob/living/human/source, hideflags, decl/pronouns/pronouns) //These can either return text, or should return nothing at all if you're doing to_chat() + return diff --git a/code/modules/mob/living/human/human_grabs.dm b/code/modules/mob/living/human/human_grabs.dm new file mode 100644 index 000000000000..38987122e3b7 --- /dev/null +++ b/code/modules/mob/living/human/human_grabs.dm @@ -0,0 +1,28 @@ +/mob/living/human/can_be_grabbed(var/mob/grabber, var/target_zone, var/defer_hand = FALSE) + . = ..() + if(.) + var/obj/item/organ/external/organ = GET_EXTERNAL_ORGAN(src, check_zone(target_zone, src)) + if(!istype(organ)) + to_chat(grabber, SPAN_WARNING("\The [src] is missing that body part!")) + return FALSE + if(grabber == src) + var/using_slot = defer_hand ? get_empty_hand_slot() : get_active_held_item_slot() + if(!using_slot) + to_chat(src, SPAN_WARNING("You cannot grab yourself without a usable hand!")) + return FALSE + var/list/bad_parts = list(organ.organ_tag) | organ.parent_organ + for(var/obj/item/organ/external/child in organ.children) + bad_parts |= child.organ_tag + if(using_slot in bad_parts) + to_chat(src, SPAN_WARNING("You can't grab your own [organ.name] with itself!")) + return FALSE + if(pull_damage()) + to_chat(grabber, SPAN_DANGER("Pulling \the [src] in their current condition would probably be a bad idea.")) + var/obj/item/clothing/C = get_covering_equipped_item_by_zone(target_zone) + if(istype(C)) + C.leave_evidence(grabber) + +/mob/living/human/make_grab(atom/movable/target, grab_tag = /decl/grab/simple, defer_hand = FALSE, force_grab_tag = FALSE) + . = ..() + if(.) + remove_mob_modifier(/decl/mob_modifier/cloaked, source = species) diff --git a/code/modules/mob/living/human/human_helpers.dm b/code/modules/mob/living/human/human_helpers.dm new file mode 100644 index 000000000000..39847bceef8c --- /dev/null +++ b/code/modules/mob/living/human/human_helpers.dm @@ -0,0 +1,192 @@ +#define add_clothing_protection(A) \ + var/obj/item/clothing/C = A; \ + flash_protection += C.flash_protection; \ + equipment_tint_total += C.get_equipment_tint(); + +/mob/living/human/proc/update_equipment_vision() + flash_protection = 0 + equipment_tint_total = 0 + equipment_see_invis = 0 + equipment_vision_flags = 0 + equipment_prescription = 0 + equipment_light_protection = 0 + equipment_darkness_modifier = 0 + equipment_overlays.Cut() + + if (!client || client.eye == src || client.eye == src.loc) // !client is so the unit tests function + + var/obj/item/clothing/head/head = get_equipped_item(slot_head_str) + if(istype(head)) + add_clothing_protection(head) + + var/obj/item/clothing/glasses/glasses = get_equipped_item(slot_glasses_str) + if(istype(glasses)) + process_glasses(glasses) + + var/obj/item/clothing/mask/mask = get_equipped_item(slot_wear_mask_str) + if(istype(mask)) + add_clothing_protection(mask) + + var/obj/item/rig/rig = get_rig() + if(rig) + process_rig(rig) + +/mob/living/human/proc/process_glasses(var/obj/item/clothing/glasses/G) + if(G) + // prescription applies regardless of if the glasses are active + equipment_prescription += G.prescription + if(G.active) + equipment_darkness_modifier += G.darkness_view + equipment_vision_flags |= G.vision_flags + equipment_light_protection += G.light_protection + if(G.screen_overlay) + equipment_overlays |= G.screen_overlay + if(G.see_invisible >= 0) + if(equipment_see_invis) + equipment_see_invis = min(equipment_see_invis, G.see_invisible) + else + equipment_see_invis = G.see_invisible + + add_clothing_protection(G) + G.process_hud(src) + +/mob/living/human/proc/process_rig(var/obj/item/rig/O) + var/obj/item/head = get_equipped_item(slot_head_str) + if(O.visor && O.visor.active && O.visor.vision && O.visor.vision.glasses && (!O.helmet || (head && O.helmet == head))) + process_glasses(O.visor.vision.glasses) + +/mob/living/human/fully_replace_character_name(var/new_name, var/in_depth = TRUE) + var/old_name = real_name + . = ..() + if(!. || !in_depth) + return + + var/datum/computer_file/report/crew_record/R = get_crewmember_record(old_name) + if(R) + R.set_name(new_name) + + //update our pda and id if we have them on our person + var/list/searching = GetAllContents(searchDepth = 3) + var/search_id = 1 + var/search_pda = 1 + + for(var/A in searching) + if(search_id && istype(A,/obj/item/card/id)) + var/obj/item/card/id/ID = A + if(ID.registered_name == old_name) + ID.registered_name = new_name + search_id = 0 + else if(search_pda && istype(A,/obj/item/modular_computer/pda)) + var/obj/item/modular_computer/pda/PDA = A + if(findtext(PDA.name, old_name)) + PDA.SetName(replacetext(PDA.name, old_name, new_name)) + search_pda = 0 + + var/obj/item/rig/rig = get_rig() + if(rig?.update_visible_name) + rig.visible_name = real_name + +/mob/living/human + var/next_sonar_ping = 0 + +/mob/living/human/proc/sonar_ping() + set name = "Listen In" + set desc = "Allows you to listen in to movement and noises around you." + set category = "IC" + + if(incapacitated()) + to_chat(src, "You need to recover before you can use this ability.") + return + if(world.time < next_sonar_ping) + to_chat(src, "You need another moment to focus.") + return + if(is_deaf() || is_below_sound_pressure(get_turf(src))) + to_chat(src, "You are for all intents and purposes currently deaf!") + return + next_sonar_ping += 10 SECONDS + var/heard_something = FALSE + to_chat(src, "You take a moment to listen in to your environment...") + for(var/mob/living/L in range(client?.view || world.view, src)) + var/turf/T = get_turf(L) + if(!T || L == src || L.stat == DEAD || is_below_sound_pressure(T)) + continue + heard_something = TRUE + var/image/ping_image = image(icon = 'icons/effects/effects.dmi', icon_state = "sonar_ping", loc = src) + ping_image.plane = ABOVE_LIGHTING_PLANE + ping_image.layer = BEAM_PROJECTILE_LAYER + ping_image.pixel_x = (T.x - src.x) * WORLD_ICON_SIZE + ping_image.pixel_y = (T.y - src.y) * WORLD_ICON_SIZE + show_image(src, ping_image) // todo: should this use screen stuff instead? + QDEL_IN(ping_image, 0.8 SECONDS) // qdeling an image is gross but oh well + var/feedback = list("There are noises of movement ") + var/direction = get_dir(src, L) + if(direction) + feedback += "towards the [dir2text(direction)], " + switch(get_dist(src, L) / get_effective_view(client)) + if(0 to 0.2) + feedback += "very close by." + if(0.2 to 0.4) + feedback += "close by." + if(0.4 to 0.6) + feedback += "some distance away." + if(0.6 to 0.8) + feedback += "further away." + else + feedback += "far away." + else // No need to check distance if they're standing right on-top of us + feedback += "right on top of you." + feedback += "" + to_chat(src, jointext(feedback,null)) + if(!heard_something) + to_chat(src, "You hear no movement but your own.") + +/mob/living/human/proc/has_headset_in_ears() + return istype(get_equipped_item(slot_l_ear_str), /obj/item/radio/headset) || istype(get_equipped_item(slot_r_ear_str), /obj/item/radio/headset) + +/mob/living/human/welding_eyecheck() + var/vision_organ_tag = get_vision_organ_tag() + if(!vision_organ_tag) + return + var/obj/item/organ/internal/eyes/eyes = get_organ(vision_organ_tag, /obj/item/organ/internal/eyes) + if(!istype(eyes)) + return + var/safety = eyecheck() + switch(safety) + if(FLASH_PROTECTION_MODERATE) + to_chat(src, "Your eyes sting a little.") + eyes.adjust_organ_damage(rand(1, 2)) + if(eyes.get_organ_damage() > 12) + ADJ_STATUS(src, STAT_BLURRY, rand(3,6)) + if(FLASH_PROTECTION_MINOR) + to_chat(src, "Your eyes stings!") + eyes.adjust_organ_damage(rand(1, 4)) + if(eyes.get_organ_damage() > 10) + ADJ_STATUS(src, STAT_BLURRY, rand(3,6)) + eyes.adjust_organ_damage(rand(1, 4)) + if(FLASH_PROTECTION_NONE) + to_chat(src, "Your eyes burn!") + eyes.adjust_organ_damage(rand(2, 4)) + if(eyes.get_organ_damage() > 10) + eyes.adjust_organ_damage(rand(4,10)) + if(FLASH_PROTECTION_REDUCED) + to_chat(src, "Your equipment intensifies the welder's glow. Your eyes itch and burn severely.") + ADJ_STATUS(src, STAT_BLURRY, rand(12,20)) + eyes.adjust_organ_damage(rand(12, 16)) + if(safety 10) + to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!") + if (eyes.get_organ_damage() >= eyes.min_bruised_damage) + to_chat(src, "You go blind!") + SET_STATUS_MAX(src, STAT_BLIND, 5) + SET_STATUS_MAX(src, STAT_BLURRY, 5) + add_genetic_condition(GENE_COND_NEARSIGHTED, 10 SECONDS) + +/mob/living/human/proc/has_meson_effect() + var/datum/global_hud/global_hud = get_global_hud() + return (global_hud.meson in equipment_overlays) + +/mob/living/human/proc/is_in_pocket(var/obj/item/I) + for(var/slot in global.pocket_slots) + if(get_equipped_item(slot) == I) + return TRUE + return FALSE diff --git a/code/modules/mob/living/human/human_internals.dm b/code/modules/mob/living/human/human_internals.dm new file mode 100644 index 000000000000..cbfe23386d37 --- /dev/null +++ b/code/modules/mob/living/human/human_internals.dm @@ -0,0 +1,7 @@ +/mob/living/human/get_internals() + return internal + +/mob/living/human/set_internals(obj/item/tank/source, source_string) + ..() + internal = source + refresh_hud_element(HUD_INTERNALS) diff --git a/code/modules/mob/living/human/human_maneuvers.dm b/code/modules/mob/living/human/human_maneuvers.dm new file mode 100644 index 000000000000..b06ca93faead --- /dev/null +++ b/code/modules/mob/living/human/human_maneuvers.dm @@ -0,0 +1,19 @@ +/mob/living/human/get_acrobatics_multiplier(var/decl/maneuver/attempting_maneuver) + . = 0.5 + ((get_skill_value(SKILL_HAULING) - SKILL_MIN)/(SKILL_MAX - SKILL_MIN)) + if(skill_check(SKILL_HAULING, SKILL_BASIC)) + . = max(..(), .) + +/mob/living/human/get_jump_distance() + return species.standing_jump_range + +/mob/living/human/can_do_maneuver(var/decl/maneuver/maneuver, var/silent = FALSE) + . = ..() + if(.) + if(nutrition <= 20) + if(!silent) + to_chat(src, SPAN_WARNING("You are too hungry to jump around.")) + return FALSE + if(hydration <= 20) + if(!silent) + to_chat(src, SPAN_WARNING("You are too thirsty to jump around.")) + return FALSE diff --git a/code/modules/mob/living/human/human_movement.dm b/code/modules/mob/living/human/human_movement.dm new file mode 100644 index 000000000000..0d2c601638e9 --- /dev/null +++ b/code/modules/mob/living/human/human_movement.dm @@ -0,0 +1,125 @@ +/mob/living/human + move_intents = list(/decl/move_intent/walk) + +/mob/living/human/get_movement_delay(var/travel_dir) + var/tally = ..() + + var/obj/item/organ/external/H = GET_EXTERNAL_ORGAN(src, BP_GROIN) // gets bodytype slowdown, which can be reset by set_bodytype + if(H) + tally += H.bodytype.get_movement_slowdown(src) + + tally += species.handle_movement_delay_special(src) + + if(!has_gravity()) + if(skill_check(SKILL_EVA, SKILL_PROF)) + tally -= 2 + tally -= 1 + + tally -= GET_CHEMICAL_EFFECT(src, CE_SPEEDBOOST) + tally += GET_CHEMICAL_EFFECT(src, CE_SLOWDOWN) + + var/health_deficiency = (get_max_health() - current_health) + if(health_deficiency >= 40) + tally += (health_deficiency / 25) + + if(can_feel_pain() && get_shock() >= 10) + tally += (get_shock() / 10) //pain shouldn't slow you down if you can't even feel it + + var/list/limbs_to_check + if(istype(buckled, /obj/structure/chair/wheelchair)) + for(var/obj/item/I in get_equipped_items(include_carried = TRUE)) + var/slot = get_equipped_slot_for_item(I) + tally += LAZYACCESS(I.slowdown_per_slot, slot) + tally += I.slowdown_general + tally += I.slowdown_accessory + limbs_to_check = global.all_maniple_limbs + else + limbs_to_check = global.all_stance_limbs + + var/missing_limbs = H ? H.bodytype.get_expected_organ_count_for_categories(limbs_to_check) : 4 + if(missing_limbs > 0) + var/max_delay_per_limb = ceil(16/missing_limbs) + for(var/obj/item/organ/external/limb in get_organs_by_categories(limbs_to_check)) + tally += limb.get_movement_delay(max_delay_per_limb) + missing_limbs-- + if(missing_limbs > 0) + tally += missing_limbs * max_delay_per_limb + + if(shock_stage >= 10 || get_stamina() <= 0) + tally += 3 + + if(is_asystole()) + tally += 10 // Heart attacks are kinda distracting. + + if(aiming && aiming.aiming_at) + tally += 5 // Iron sights make you slower, it's a well-known fact. + + if(facing_dir && ((travel_dir & facing_dir) != facing_dir)) + tally += 3 // If we're not facing the direction we're going, we have to slow down. + + var/decl/bodytype/root_bodytype = get_bodytype() + if (root_bodytype && bodytemperature < root_bodytype.cold_discomfort_level) + tally += (root_bodytype.cold_discomfort_level - bodytemperature) / 10 * 1.75 + + if(has_genetic_condition(GENE_COND_RUNNING)) + tally = 0 + + return (tally+get_config_value(/decl/config/num/movement_human)) + +/mob/living/human/size_strength_mod() + . = ..() + . += species.strength + +/mob/living/human/try_space_move(space_move_result, direction) + if(space_move_result == SPACE_MOVE_PERMITTED) + var/obj/item/tank/jetpack/thrust = get_jetpack() + if(thrust && thrust.on && prob(skill_fail_chance(SKILL_EVA, 10, SKILL_ADEPT))) + to_chat(src, SPAN_WARNING("You fumble with the controls of \the [thrust]!")) + if(prob(50)) + thrust.toggle() + if(prob(50)) + thrust.stabilization_on = 0 + SetMoveCooldown(15) //2 seconds of random rando panic drifting + step(src, pick(global.alldirs)) + return FALSE + return ..() + +/mob/living/human/Move() + . = ..() + if(.) //We moved + + if(stat != DEAD) + + var/nut_removed = DEFAULT_HUNGER_FACTOR/10 + var/hyd_removed = DEFAULT_THIRST_FACTOR/10 + if (move_intent.flags & MOVE_INTENT_EXERTIVE) + nut_removed *= 2 + hyd_removed *= 2 + adjust_nutrition(-nut_removed) + adjust_hydration(-hyd_removed) + + handle_leg_damage() + species.handle_post_move(src) + +/mob/living/human/forceMove() + . = ..() + if(.) + species.handle_post_move(src, exertion = FALSE) + +/mob/living/human/proc/handle_leg_damage() + if(!can_feel_pain()) + return + var/crutches = 0 + for(var/obj/item/support in get_held_items()) + if(support.get_stance_support_value() > 0) + crutches++ + for(var/organ_name in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, organ_name) + if(E && (E.is_dislocated() || E.is_broken())) + if(crutches) + crutches-- + else + E.add_pain(10) + +/mob/living/human/can_sprint() + return (stamina > 0) diff --git a/code/modules/mob/living/human/human_organs.dm b/code/modules/mob/living/human/human_organs.dm new file mode 100644 index 000000000000..6549dcb8a6f8 --- /dev/null +++ b/code/modules/mob/living/human/human_organs.dm @@ -0,0 +1,235 @@ +/// organ-related variables, see organ.dm and human_organs.dm, shouldn't be accessed directly +/mob/living/human + /// organs we check until they are good. + var/list/bad_external_organs + /// organs grouped by category, largely used for stance calc + var/list/organs_by_category + /// organs indexed by organ_tag + var/list/organs_by_tag + /// unassociated list of internal organs + var/tmp/list/internal_organs + /// unassociated list of external organs + var/tmp/list/external_organs + +/mob/living/human/get_organ(var/organ_tag, var/expected_type = /obj/item/organ) + RETURN_TYPE(expected_type) + var/obj/item/organ = LAZYACCESS(organs_by_tag, organ_tag) + if(!expected_type || istype(organ, expected_type)) + return organ + +/mob/living/human/get_external_organs() + return external_organs + +/mob/living/human/get_injured_organs() + return bad_external_organs + +/mob/living/human/get_internal_organs() + return internal_organs + +/mob/living/human/has_organs() + return (LAZYLEN(external_organs) + LAZYLEN(internal_organs)) > 0 + +/mob/living/human/has_external_organs() + return LAZYLEN(external_organs) > 0 + +/mob/living/human/has_internal_organs() + return LAZYLEN(internal_organs) > 0 + +/mob/living/human/get_organs_by_categories(var/list/categories) + for(var/organ_cat in categories) + if(organ_cat in organs_by_category) + LAZYDISTINCTADD(., organs_by_category[organ_cat]) + +//Deletes all references to organs +/mob/living/human/delete_organs() + ..() + organs_by_tag = null + internal_organs = null + external_organs = null + organs_by_category = null + LAZYCLEARLIST(bad_external_organs) + +//Registers an organ and setup the organ hierachy properly. +//affected : Parent organ if applicable. +//in_place : If true, we're performing an in-place replacement, without triggering anything related to adding the organ in-game as part of surgery or else. +/mob/living/human/add_organ(obj/item/organ/O, obj/item/organ/external/affected, in_place, update_icon, detached, skip_health_update = FALSE) + + var/obj/item/organ/existing = LAZYACCESS(organs_by_tag, O.organ_tag) + if(existing && O != existing) + CRASH("mob/living/human/add_organ(): '[O]' tried to overwrite [src]'s existing organ '[existing]' in slot '[O.organ_tag]'!") + if(O.parent_organ && !LAZYACCESS(organs_by_tag, O.parent_organ)) + CRASH("mob/living/human/add_organ(): Tried to add an internal organ to a non-existing parent external organ!") + + //We don't add internal organs to the lists if we're detached + if(O.is_internal() && !detached) + LAZYSET(organs_by_tag, O.organ_tag, O) + LAZYDISTINCTADD(internal_organs, O) + //External organs must always be in the organ list even when detached. Otherwise icon updates won't show the limb, and limb attach surgeries won't work + else if(!O.is_internal()) + LAZYSET(organs_by_tag, O.organ_tag, O) + LAZYDISTINCTADD(external_organs, O) + + // Update our organ category lists, if neeed. + if(O.organ_categories) + for(var/category in cached_json_decode(O.organ_categories)) + LAZYINITLIST(organs_by_category) + LAZYDISTINCTADD(organs_by_category[category], O) + + // Update stat organs as well + if(O.has_stat_info) + LAZYDISTINCTADD(stat_organs, O) + + . = ..() + if(!.) + return + + if(!O.is_internal()) + refresh_modular_limb_verbs() + + //#TODO: wish we could invalidate the human icons to trigger a single update when the organ state changes multiple times in a row + if(update_icon) + update_inhand_overlays(FALSE) + update_body(FALSE) + update_bandages(FALSE) + update_damage_overlays(FALSE) + hud_reset() + queue_icon_update() //Avoids calling icon updates 50 times when adding multiple organs + +//Unregister and remove a given organ from the mob. +//drop_organ : Once the organ is removed its dropped to the ground. +//detach : Toggle the ORGAN_CUT_AWAY flag on the removed organ +//ignore_children: Skips recursively removing this organ's child organs. +//in_place : If true we remove only the organ (no children items or implants) and avoid triggering mob changes and parent organs changes as much as possible. +// Meant to be used for init and species transforms, without triggering any updates to mob state or anything related to losing a limb as part of surgery or combat. +/mob/living/human/remove_organ(var/obj/item/organ/O, var/drop_organ = TRUE, var/detach = TRUE, var/ignore_children = FALSE, var/in_place = FALSE, var/update_icon = TRUE, var/skip_health_update = FALSE) + if(istype(O) && !in_place && O.is_vital_to_owner() && usr) + admin_attack_log(usr, src, "Removed a vital organ ([src]).", "Had a vital organ ([src]) removed.", "removed a vital organ ([src]) from") + if(!(. = ..())) + return + LAZYREMOVE(organs_by_tag, O.organ_tag) + if(O.is_internal()) + LAZYREMOVE(internal_organs, O) + else + LAZYREMOVE(external_organs, O) + + // Update our organ category lists, if neeed. + if(O.organ_categories && islist(organs_by_category)) + for(var/category in cached_json_decode(O.organ_categories)) + organs_by_category[category] -= O + if(LAZYLEN(organs_by_category[category]) <= 0) + LAZYREMOVE(organs_by_category, category) + + // Update stat organs as well + if(O.has_stat_info && stat_organs) + LAZYREMOVE(stat_organs, O) + + if(!O.is_internal()) + refresh_modular_limb_verbs() + LAZYREMOVE(bad_external_organs, O) + + //#TODO: wish we could invalidate the human icons to trigger a single update when the organ state changes multiple times in a row + if(update_icon) + regenerate_body_icon = TRUE + hud_reset() + queue_icon_update() //Avoids calling icon updates 50 times when removing multiple organs + +/mob/living/human/get_bodytype() + RETURN_TYPE(/decl/bodytype) + // If the root organ ever changes/isn't always the chest, this will need to be changed. + return get_organ(BP_CHEST, /obj/item/organ)?.bodytype + +/mob/living/human/proc/get_bodypart_name(var/zone) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, zone) + return E?.name + +/mob/living/human/proc/should_recheck_bad_external_organs() + var/damage_this_tick = get_damage(TOX) + for(var/obj/item/organ/external/O in get_external_organs()) + damage_this_tick += O.burn_dam + O.brute_dam + + if(damage_this_tick > last_dam) + . = TRUE + last_dam = damage_this_tick + +/mob/living/human/proc/recheck_bad_external_organs() + LAZYCLEARLIST(bad_external_organs) + for(var/obj/item/organ/external/E in get_external_organs()) + if(E.need_process()) + LAZYDISTINCTADD(bad_external_organs, E) + +/mob/living/human/proc/check_vital_organ_missing() + return get_bodytype()?.check_vital_organ_missing(src) + +/mob/living/human/proc/process_internal_organs() + for(var/obj/item/organ/I in internal_organs) + I.Process() + +// Takes care of organ related updates, such as broken and missing limbs +/mob/living/human/proc/handle_organs() + + // Check for the presence (or lack of) vital organs like the brain. + // Set a timer after this point, since we want a little bit of + // wiggle room before the body dies for good (brain transplants). + if(stat != DEAD) + if(check_vital_organ_missing()) + SET_STATUS_MAX(src, STAT_PARA, 5) + if(vital_organ_missing_time) + if(world.time >= vital_organ_missing_time) + death() + else + vital_organ_missing_time = world.time + max(get_bodytype()?.vital_organ_failure_death_delay, 5 SECONDS) + else + vital_organ_missing_time = null + + //processing internal organs is pretty cheap, do that first. + process_internal_organs() + + var/force_process = should_recheck_bad_external_organs() + + if(force_process) + recheck_bad_external_organs() + for(var/obj/item/organ/external/Ex in get_external_organs()) + LAZYDISTINCTADD(bad_external_organs, Ex) + + if(!force_process && !LAZYLEN(bad_external_organs)) + return + + for(var/obj/item/organ/external/E in bad_external_organs) + if(!E) + continue + if(!E.need_process()) + LAZYREMOVE(bad_external_organs, E) + continue + else + E.Process() + + if(!current_posture.prone && !buckled && world.time - l_move_time < 15) + //Moving around with fractured ribs won't do you any good + if (prob(10) && !stat && can_feel_pain() && GET_CHEMICAL_EFFECT(src, CE_PAINKILLER) < 50 && E.is_broken() && LAZYLEN(E.internal_organs)) + custom_pain("Pain jolts through your broken [E.encased ? E.encased : E.name], staggering you!", 50, affecting = E) + drop_held_items() + SET_STATUS_MAX(src, STAT_STUN, 2) + + //Moving makes open wounds get infected much faster + for(var/datum/wound/wound in E.wounds) + if (wound.infection_check()) + wound.germ_level += 1 + +/mob/living/human/on_lost_organ(var/obj/item/organ/O) + if(!(. = ..())) + return + //Move some blood over to the organ + if(!BP_IS_PROSTHETIC(O) && O.species && REAGENT_TOTAL_VOLUME(O.reagents) < 5) + vessel.trans_to(O, 5 - REAGENT_TOTAL_VOLUME(O.reagents), 1, 1) + + +/mob/living/human/is_asystole() + if(isSynthetic()) + var/obj/item/organ/internal/cell/C = get_organ(BP_CELL, /obj/item/organ/internal/cell) + if(!C || !C.is_usable() || !C.percent()) + return TRUE + else if(should_have_organ(BP_HEART)) + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(!istype(heart) || !heart.is_working()) + return TRUE + return FALSE diff --git a/code/modules/mob/living/human/human_powers.dm b/code/modules/mob/living/human/human_powers.dm new file mode 100644 index 000000000000..8a2246c31eb3 --- /dev/null +++ b/code/modules/mob/living/human/human_powers.dm @@ -0,0 +1,52 @@ +/**************** + true human verbs +****************/ +/mob/living/human/proc/tie_hair() + set name = "Tie Hair" + set desc = "Style your hair." + set category = "IC" + + if(incapacitated()) + to_chat(src, SPAN_WARNING("You can't mess with your hair right now!")) + return + + var/hairstyle = GET_HAIR_STYLE(src) + if(hairstyle) + var/decl/sprite_accessory/hair/hair_style = GET_DECL(hairstyle) + if(!(hair_style.accessory_flags & HAIR_TIEABLE)) + to_chat(src, SPAN_WARNING("Your hair isn't long enough to tie.")) + return + + var/selected_type + var/list/valid_hairstyles = decls_repository.get_decls_of_subtype(/decl/sprite_accessory/hair) + var/list/hairstyle_instances = list() + for(var/hair_type in valid_hairstyles) + var/decl/sprite_accessory/hair/test = valid_hairstyles[hair_type] + if(test.accessory_flags & HAIR_TIEABLE) + hairstyle_instances += test + var/decl/selected_decl = input("Select a new hairstyle", "Your hairstyle", hair_style) as null|anything in hairstyle_instances + if(selected_decl) + selected_type = selected_decl.type + if(incapacitated()) + to_chat(src, SPAN_WARNING("You can't mess with your hair right now!")) + return + if(selected_type && hairstyle != selected_type) + SET_HAIR_STYLE(src, selected_type, FALSE) + visible_message(SPAN_NOTICE("\The [src] pauses a moment to style their hair.")) + else + to_chat(src, SPAN_NOTICE("You're already using that style.")) + +/**************** + misc alien verbs +****************/ +/mob/living/human/proc/psychic_whisper(mob/M as mob in oview()) + set name = "Psychic Whisper" + set desc = "Whisper silently to someone over a distance." + set category = "Abilities" + + var/msg = sanitize(input("Message:", "Psychic Whisper") as text|null) + if(msg) + log_say("PsychicWhisper: [key_name(src)]->[M.key] : [msg]") + to_chat(M, "You hear a strange, alien voice in your head... [msg]") + to_chat(src, "You channel a message: \"[msg]\" to [M]") + return diff --git a/code/modules/mob/living/human/human_presets.dm b/code/modules/mob/living/human/human_presets.dm new file mode 100644 index 000000000000..802158c14986 --- /dev/null +++ b/code/modules/mob/living/human/human_presets.dm @@ -0,0 +1,78 @@ +/mob/living/human/dummy + real_name = "test dummy" + status_flags = GODMODE|CANPUSH + virtual_mob = null + +/proc/get_mannequin(var/ckey) + var/static/list/mob/living/human/dummy/mannequin/mannequins = list() + if(SSatoms.atom_init_stage < INITIALIZATION_INNEW_REGULAR) + return + . = mannequins[ckey] + if(!.) + . = new /mob/living/human/dummy/mannequin() + mannequins[ckey] = . + +/mob/living/human/dummy/mannequin/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + . = ..() + STOP_PROCESSING(SSmobs, src) + global.human_mob_list -= src + +/mob/living/human/dummy/selfdress/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + ..() + return INITIALIZE_HINT_LATELOAD + +/mob/living/human/dummy/selfdress/LateInitialize() + for(var/obj/item/I in loc) + equip_to_appropriate_slot(I) + +/mob/living/human/corpse + real_name = "corpse" + +/mob/living/human/corpse/get_death_message(gibbed) + return SKIP_DEATH_MESSAGE + +/mob/living/human/corpse/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance, obj/abstract/landmark/corpse/corpse) + . = ..(mapload, species_uid, supplied_appearance) // do not pass the corpse landmark + var/decl/background_detail/background = get_background_datum_by_flag(BACKGROUND_FLAG_NAMING) + if(background) + var/newname = background.get_random_cultural_name(src, gender, get_species()) + if(newname && newname != name) + real_name = newname + SetName(newname) + if(mind) + mind.name = real_name + if(corpse) + corpse.randomize_appearance(src, get_species()?.uid) + corpse.equip_corpse_outfit(src) + return INITIALIZE_HINT_LATELOAD + +/mob/living/human/corpse/LateInitialize() + ..() + var/current_max_health = get_max_health() + take_damage(current_max_health, OXY) //cease life functions + set_damage(BRAIN, current_max_health) + death() + var/obj/item/organ/internal/heart/corpse_heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(corpse_heart) + corpse_heart.pulse = PULSE_NONE//actually stops heart to make worried explorers not care too much + +/mob/living/human/dummy/mannequin/add_to_living_mob_list() + return FALSE + +/mob/living/human/dummy/mannequin/add_to_dead_mob_list() + return FALSE + +/mob/living/human/dummy/mannequin/fully_replace_character_name(new_name, in_depth = TRUE) + ..("[new_name] (mannequin)", FALSE) + +/mob/living/human/dummy/mannequin/initialize_hud() + return // Mannequins don't get HUDs + +/mob/living/human/monkey + gender = PLURAL + +/mob/living/human/monkey/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(gender == PLURAL) + set_gender(pick(MALE, FEMALE)) + species_uid = /decl/species/monkey::uid + . = ..() diff --git a/code/modules/mob/living/human/human_skin.dm b/code/modules/mob/living/human/human_skin.dm new file mode 100644 index 000000000000..54e4f7b3eab8 --- /dev/null +++ b/code/modules/mob/living/human/human_skin.dm @@ -0,0 +1,7 @@ +/mob/living/human + var/skin_state = SKIN_NORMAL + +/mob/living/human/proc/reset_skin() + if(skin_state == SKIN_THREAT) + skin_state = SKIN_NORMAL + update_skin() \ No newline at end of file diff --git a/code/modules/mob/living/human/human_verbs.dm b/code/modules/mob/living/human/human_verbs.dm new file mode 100644 index 000000000000..7fc6f619c808 --- /dev/null +++ b/code/modules/mob/living/human/human_verbs.dm @@ -0,0 +1,248 @@ +/mob/living/human/proc/remotesay() + set name = "Project mind" + set category = "Superpower" + + if(stat!=CONSCIOUS) + reset_view(0) + remoteview_target = null + return + + if(!has_genetic_condition(GENE_COND_REMOTE_TALK)) + src.verbs -= /mob/living/human/proc/remotesay + return + var/list/creatures = list() + for(var/mob/living/h in global.player_list) + creatures += h + var/mob/target = input(usr, "Who do you want to project your mind to?") as null|anything in creatures + if (isnull(target)) + return + + var/say = sanitize(input("What do you wish to say")) + if(target.has_genetic_condition(GENE_COND_REMOTE_TALK)) + target.show_message("You hear [src.real_name]'s voice: [say]") + else + target.show_message("You hear a voice that seems to echo around the room: [say]") + usr.show_message("You project your mind into [target.real_name]: [say]") + log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]") + for(var/mob/observer/ghost/ghost in global.player_list) + ghost.show_message("Telepathic message from [src] to [target]: [say]") + +/mob/living/human/proc/remoteobserve() + set name = "Remote View" + set category = "Superpower" + + if(stat!=CONSCIOUS) + remoteview_target = null + reset_view(0) + return + + if(!has_genetic_condition(GENE_COND_REMOTE_VIEW)) + remoteview_target = null + reset_view(0) + src.verbs -= /mob/living/human/proc/remoteobserve + return + + if(client.eye != client.mob) + remoteview_target = null + reset_view(0) + return + + var/list/mob/creatures = list() + + for(var/mob/living/h in global.living_mob_list_) + var/turf/temp_turf = get_turf(h) + if((temp_turf.z != 1 && temp_turf.z != 5) || h.stat!=CONSCIOUS) //Not on mining or the station. Or dead + continue + creatures += h + + var/mob/target = input(usr, "Who do you want to project your mind to?") as mob in creatures + + if (target) + remoteview_target = target + reset_view(target) + else + remoteview_target = null + reset_view(0) + +/mob/living/human/proc/remove_splints() + set category = "Object" + set name = "Remove Splints" + set desc = "Carefully remove splints from someone's limbs." + set src in view(1) + var/mob/living/user = usr + var/removed_splint = 0 + + if(usr.stat || usr.restrained() || !isliving(usr)) return + + for(var/obj/item/organ/external/o in get_external_organs()) + if (o && o.splinted) + var/obj/item/S = o.splinted + if(!istype(S) || S.loc != o) //can only remove splints that are actually worn on the organ (deals with hardsuit splints) + to_chat(user, SPAN_WARNING("You cannot remove any splints on [src]'s [o.name] - [o.splinted] is supporting some of the breaks.")) + else + S.add_fingerprint(user) + if(o.remove_splint()) + user.put_in_active_hand(S) + removed_splint = 1 + if(removed_splint) + user.visible_message(SPAN_DANGER("\The [user] removes \the [src]'s splints!")) + else + to_chat(user, SPAN_WARNING("\The [src] has no splints that can be removed.")) + verbs -= /mob/living/human/proc/remove_splints + +/mob/living/human/verb/check_pulse() + set category = "Object" + set name = "Check pulse" + set desc = "Approximately count somebody's pulse. Requires you to stand still at least 6 seconds." + set src in view(1) + + if(usr.incapacitated() || usr.restrained() || !isliving(usr)) + return + + var/self = (usr == src) + var/decl/pronouns/pronouns = usr.get_pronouns() + if(!self) + var/decl/pronouns/target_gender = src.get_pronouns() + usr.visible_message( \ + SPAN_NOTICE("\The [usr] kneels down, puts [pronouns.his] hand on \the [src]'s wrist, and begins counting [target_gender.his] pulse."), \ + SPAN_NOTICE("You begin counting \the [src]'s pulse.")) + else + usr.visible_message( + SPAN_NOTICE("\The [usr] begins counting [pronouns.his] pulse."), \ + SPAN_NOTICE("You begin counting your pulse.")) + + if(get_pulse()) + to_chat(usr, "[self ? "You have a" : "[src] has a"] pulse! Counting...") + else + to_chat(usr, "[src] has no pulse!")//it is REALLY UNLIKELY that a dead person would check his own pulse + return + + to_chat(usr, "You must[self ? "" : " both"] remain still until counting is finished.") + if(do_mob(usr, src, 60)) + var/message = "[self ? "Your" : "[src]'s"] pulse is [src.get_pulse_as_string(GETPULSE_HAND)]." + to_chat(usr, message) + else + to_chat(usr, "You failed to check the pulse. Try again.") + +/mob/living/human/proc/bloody_doodle() + set category = "IC" + set name = "Write in blood" + set desc = "Use blood on your hands to write a short message on the floor or a wall, murder mystery style." + + if (src.stat) + return + + if (usr != src) + return 0 //something is terribly wrong + + var/bloody_hands = 0 + for(var/obj/item/organ/external/grabber in get_hands_organs()) + if(grabber.coating) + bloody_hands += REAGENT_VOLUME(grabber.coating, /decl/material/liquid/blood) + if (!bloody_hands) + verbs -= /mob/living/human/proc/bloody_doodle + + var/obj/item/gloves = get_equipped_item(slot_gloves_str) + if (gloves) + to_chat(src, SPAN_WARNING("Your [gloves] are getting in the way.")) + return + + var/turf/T = src.loc + if (!istype(T) || !T.simulated) //to prevent doodling out of mechs and lockers + to_chat(src, "You cannot reach the floor.") + return + + var/direction = input(src,"Which way?","Tile selection") as null|anything in list("Here","North","South","East","West") + if(!direction) + return + if(direction != "Here") + T = get_step(T,text2dir(direction)) + if (!istype(T)) + to_chat(src, "You cannot doodle there.") + return + + var/num_doodles = 0 + for (var/obj/effect/decal/cleanable/blood/writing/writing in T) + num_doodles++ + if (num_doodles > 4) + to_chat(src, "There is no space to write on!") + return + + var/max_length = bloody_hands * 30 //tweeter style + + var/message = sanitize(input("Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")) + + if (message) + var/used_blood_amount = round(length(message) / 30, 1) + bloody_hands = max(0, bloody_hands - used_blood_amount) //use up some blood + + if (length(message) > max_length) + message += "-" + to_chat(src, "You ran out of blood to write with!") + var/obj/effect/decal/cleanable/blood/writing/writing = new(T) + writing.basecolor = (hand_blood_color) ? hand_blood_color : COLOR_BLOOD_HUMAN + writing.update_icon() + writing.message = message + writing.add_fingerprint(src) + +/mob/living/human/proc/undislocate() + set category = "Object" + set name = "Undislocate Joint" + set desc = "Pop a joint back into place. Extremely painful." + set src in view(1) + + if(!isliving(usr) || !usr.canClick()) + return + + usr.setClickCooldown(20) + + if(usr.stat > 0) + to_chat(usr, "You are unconscious and cannot do that!") + return + + if(usr.restrained()) + to_chat(usr, "You are restrained and cannot do that!") + return + + var/mob/S = src + var/mob/U = usr + var/self = null + if(S == U) + self = 1 // Removing object from yourself. + + var/list/limbs = list() + for(var/obj/item/organ/external/current_limb in get_external_organs()) + if(current_limb && current_limb.is_dislocated() && !current_limb.is_parent_dislocated()) //if the parent is also dislocated you will have to relocate that first + limbs |= current_limb + var/obj/item/organ/external/current_limb = input(usr,"Which joint do you wish to relocate?") as null|anything in limbs + + if(!current_limb) + return + + if(self) + to_chat(src, "You brace yourself to relocate your [current_limb.joint]...") + else + to_chat(U, "You begin to relocate [S]'s [current_limb.joint]...") + if(!do_after(U, 30, src)) + return + if(!current_limb || !S || !U) + return + + var/fail_prob = U.skill_fail_chance(SKILL_MEDICAL, 60, SKILL_ADEPT, 3) + if(self) + fail_prob += U.skill_fail_chance(SKILL_MEDICAL, 20, SKILL_EXPERT, 1) + var/decl/pronouns/pronouns = get_pronouns() + if(prob(fail_prob)) + visible_message( \ + "[U] pops [self ? "[pronouns.his]" : "[S]'s"] [current_limb.joint] in the WRONG place!", \ + "[self ? "You pop" : "[U] pops"] your [current_limb.joint] in the WRONG place!" \ + ) + current_limb.add_pain(30) + current_limb.take_damage(5) + shock_stage += 20 + else + visible_message( \ + "[U] pops [self ? "[pronouns.his]" : "[S]'s"] [current_limb.joint] back in!", \ + "[self ? "You pop" : "[U] pops"] your [current_limb.joint] back in!" \ + ) + current_limb.undislocate() diff --git a/code/modules/mob/living/human/life.dm b/code/modules/mob/living/human/life.dm new file mode 100644 index 000000000000..21aa9577627e --- /dev/null +++ b/code/modules/mob/living/human/life.dm @@ -0,0 +1,722 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! +#define HUMAN_MAX_OXYLOSS 1 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it. + +#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point +#define HEAT_DAMAGE_LEVEL_2 4 //Amount of damage applied when your body temperature passes the 400K point +#define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 1000K point + +#define COLD_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when your body temperature just passes the 260.15k safety point +#define COLD_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 200K point +#define COLD_DAMAGE_LEVEL_3 3 //Amount of damage applied when your body temperature passes the 120K point + +//Note that gas heat damage is only applied once every FOUR ticks. +#define HEAT_GAS_DAMAGE_LEVEL_1 2 //Amount of damage applied when the current breath's temperature just passes the 360.15k safety point +#define HEAT_GAS_DAMAGE_LEVEL_2 4 //Amount of damage applied when the current breath's temperature passes the 400K point +#define HEAT_GAS_DAMAGE_LEVEL_3 8 //Amount of damage applied when the current breath's temperature passes the 1000K point + +#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point +#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point +#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point + +/mob/living/human + var/stamina = 100 + +/mob/living/human/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE + last_pain = null // Clear the last cached pain value so further calls won't use an old value. + //Organs and blood + handle_organs() + handle_shock() + handle_pain() + handle_stamina() + +/mob/living/human/get_stamina() + return stamina + +/mob/living/human/adjust_stamina(var/amt) + var/last_stamina = stamina + if(stat == DEAD) + stamina = 0 + else + stamina = clamp(stamina + amt, 0, 100) + if(stamina <= 0) + to_chat(src, SPAN_WARNING("You are exhausted!")) + remove_stressor(/datum/stressor/well_rested) + add_stressor(/datum/stressor/fatigued, 5 MINUTES) + if(MOVING_QUICKLY(src)) + set_moving_slowly() + if(last_stamina != stamina) + refresh_hud_element(HUD_STAMINA) + +/mob/living/human/proc/handle_stamina() + if((world.time - last_quick_move_time) > 5 SECONDS) + var/mod = (current_posture.prone + (nutrition / get_max_nutrition())) / 2 + adjust_stamina(max(get_config_value(/decl/config/num/movement_max_stamina_recovery), get_config_value(/decl/config/num/movement_min_stamina_recovery) * mod) * (1 + GET_CHEMICAL_EFFECT(src, CE_ENERGETIC))) + +/mob/living/human/set_stat(var/new_stat) + var/old_stat = stat + . = ..() + if(stat) + update_skin(1) + if(client && client.is_afk()) + if(old_stat == UNCONSCIOUS && stat == CONSCIOUS) + playsound_local(null, 'sound/effects/bells.ogg', 100, is_global=TRUE) + +// Calculate how vulnerable the human is to the current pressure. +// Returns 0 (equals 0 %) if sealed in an undamaged suit that's rated for the pressure, 1 if unprotected (equals 100%). +// Suitdamage can modifiy this in 10% steps. +/mob/living/human/proc/get_pressure_weakness(pressure) + + var/pressure_adjustment_coefficient = 0 + var/list/zones = list(SLOT_HEAD, SLOT_UPPER_BODY, SLOT_LOWER_BODY, SLOT_LEGS, SLOT_FEET, SLOT_ARMS, SLOT_HANDS) + for(var/zone in zones) + var/list/covers = get_covering_equipped_items(zone) + var/zone_exposure = 1 + for(var/obj/item/clothing/C in covers) + zone_exposure = min(zone_exposure, C.get_pressure_weakness(pressure,zone)) + if(zone_exposure >= 1) + return 1 + pressure_adjustment_coefficient = max(pressure_adjustment_coefficient, zone_exposure) + pressure_adjustment_coefficient = clamp(pressure_adjustment_coefficient, 0, 1) // So it isn't less than 0 or larger than 1. + + return pressure_adjustment_coefficient + +// Calculate how much of the environment pressure-difference affects the human. +/mob/living/human/calculate_affecting_pressure(var/pressure) + var/pressure_difference + var/species_safe_pressure = species.get_safe_pressure(src) + + // First get the absolute pressure difference. + pressure_difference = abs(pressure - species_safe_pressure) + + if(pressure_difference < 5) // If the difference is small, don't bother calculating the fraction. + pressure_difference = 0 + + else + // Otherwise calculate how much of that absolute pressure difference affects us, can be 0 to 1 (equals 0% to 100%). + // This is our relative difference. + pressure_difference *= get_pressure_weakness(pressure) + + // The difference is always positive to avoid extra calculations. + // Apply the relative difference on a standard atmosphere to get the final result. + // The return value will be the adjusted_pressure of the human that is the basis of pressure warnings and damage. + if(pressure < species_safe_pressure) + return species_safe_pressure - pressure_difference + else + return species_safe_pressure + pressure_difference + +/mob/living/human/handle_impaired_vision() + + . = ..() + if(!.) + return + + //Vision + var/obj/item/organ/vision + var/vision_organ_tag = get_vision_organ_tag() + if(vision_organ_tag) + vision = GET_INTERNAL_ORGAN(src, vision_organ_tag) + + if(!vision_organ_tag) // Presumably if a species has no vision organs, they see via some other means. + set_status_condition(STAT_BLIND, 0) + set_status_condition(STAT_BLURRY, 0) + else if(!vision || (vision && !vision.is_usable())) // Vision organs cut out or broken? Permablind. + SET_STATUS_MAX(src, STAT_BLIND, 2) + SET_STATUS_MAX(src, STAT_BLURRY, 1) + // Non-genetic blindness; covered eyes will heal faster. + else if(!has_genetic_condition(GENE_COND_BLINDED) && equipment_tint_total >= TINT_BLIND) + ADJ_STATUS(src, STAT_BLURRY, -1) + +/mob/living/human/handle_disabilities() + ..() + if(stat != DEAD && has_genetic_condition(GENE_COND_COUGHING) && prob(5) && GET_STATUS(src, STAT_PARA) <= 1) + drop_held_items() + cough() + +/mob/living/human/handle_mutations_and_radiation() + if(get_damage(BURN) && (has_genetic_condition(GENE_COND_COLD_RESISTANCE) || (prob(1)))) + heal_organ_damage(0,1) + ..() + +/mob/living/human/handle_environment(datum/gas_mixture/environment) + + ..() + + if(!environment || has_genetic_condition(GENE_COND_SPACE_RESISTANCE)) + return + + //Stuff like water absorbtion happens here. + species.handle_environment_special(src) + + //Moved pressure calculations here for use in skip-processing check. + var/pressure = environment.return_pressure() + var/adjusted_pressure = calculate_affecting_pressure(pressure) + + //Check for contaminants before anything else because we don't want to skip it. + for(var/g in environment.gas) + var/decl/material/mat = GET_DECL(g) + if((mat.gas_flags & XGM_GAS_CONTAMINANT) && environment.gas[g] > mat.gas_overlay_limit + 1) + handle_contaminants() + break + + if(isspaceturf(src.loc)) //being in a closet will interfere with radiation, may not make sense but we don't model radiation for atoms in general so it will have to do for now. + //Don't bother if the temperature drop is less than 0.1 anyways. Hopefully BYOND is smart enough to turn this constant expression into a constant + if(bodytemperature > (0.1 * HUMAN_HEAT_CAPACITY/(HUMAN_EXPOSED_SURFACE_AREA*STEFAN_BOLTZMANN_CONSTANT))**(1/4) + COSMIC_RADIATION_TEMPERATURE) + + //Thermal radiation into space + var/heat_gain = get_thermal_radiation(bodytemperature, HUMAN_EXPOSED_SURFACE_AREA, 0.5, SPACE_HEAT_TRANSFER_COEFFICIENT) + + var/temperature_gain = heat_gain/HUMAN_HEAT_CAPACITY + bodytemperature += temperature_gain //temperature_gain will often be negative + + var/relative_density = (environment.total_moles/environment.total_volume) / (MOLES_CELLSTANDARD/CELL_VOLUME) + if(relative_density > 0.02) //don't bother if we are in vacuum or near-vacuum + var/loc_temp = environment.temperature + + if(adjusted_pressure < species.get_warning_high_pressure(src) && adjusted_pressure > species.get_warning_low_pressure(src) && abs(loc_temp - bodytemperature) < 20 && bodytemperature < get_mob_temperature_threshold(HEAT_LEVEL_1) && bodytemperature > get_mob_temperature_threshold(COLD_LEVEL_1) && species.body_temperature) + SET_HUD_ALERT(src, HUD_PRESSURE, 0) + return // Temperatures are within normal ranges, fuck all this processing. ~Ccomp + + //Body temperature adjusts depending on surrounding atmosphere based on your thermal protection (convection) + var/temp_adj = 0 + if(loc_temp < bodytemperature) //Place is colder than we are + var/thermal_protection = get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR) //this will be negative + else if (loc_temp > bodytemperature) //Place is hotter than we are + var/thermal_protection = get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + temp_adj = (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR) + + //Use heat transfer as proportional to the gas density. However, we only care about the relative density vs standard 101 kPa/20 C air. Therefore we can use mole ratios + bodytemperature += clamp(temp_adj*relative_density, BODYTEMP_COOLING_MAX, BODYTEMP_HEATING_MAX) + + // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. + if(bodytemperature >= get_mob_temperature_threshold(HEAT_LEVEL_1)) + //Body temperature is too hot. + if(status_flags & GODMODE) return 1 //godmode + var/burn_dam = 0 + if(bodytemperature < get_mob_temperature_threshold(HEAT_LEVEL_2)) + burn_dam = HEAT_DAMAGE_LEVEL_1 + else if(bodytemperature < get_mob_temperature_threshold(HEAT_LEVEL_3)) + burn_dam = HEAT_DAMAGE_LEVEL_2 + else + burn_dam = HEAT_DAMAGE_LEVEL_3 + take_overall_damage(burn=burn_dam, used_weapon = "High Body Temperature") + SET_HUD_ALERT_MAX(src, HUD_FIRE, 2) + + else if(bodytemperature <= get_mob_temperature_threshold(COLD_LEVEL_1)) + SET_HUD_ALERT_MAX(src, HUD_FIRE, 1) + if(status_flags & GODMODE) return 1 //godmode + + var/burn_dam = 0 + + if(bodytemperature > get_mob_temperature_threshold(COLD_LEVEL_2)) + burn_dam = COLD_DAMAGE_LEVEL_1 + else if(bodytemperature > get_mob_temperature_threshold(COLD_LEVEL_3)) + burn_dam = COLD_DAMAGE_LEVEL_2 + else + burn_dam = COLD_DAMAGE_LEVEL_3 + add_mob_modifier(/decl/mob_modifier/stasis, 2 SECONDS, source = src) + if(!has_chemical_effect(CE_CRYO, 1)) + take_overall_damage(burn=burn_dam, used_weapon = "Low Body Temperature") + SET_HUD_ALERT_MAX(src, HUD_FIRE, 1) + + // Account for massive pressure differences. Done by Polymorph + // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! + if(status_flags & GODMODE) return 1 //godmode + + var/high_pressure = species.get_hazard_high_pressure(src) + if(adjusted_pressure >= high_pressure) + var/pressure_damage = min( ( (adjusted_pressure / high_pressure) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) + take_overall_damage(brute=pressure_damage, used_weapon = "High Pressure") + SET_HUD_ALERT(src, HUD_PRESSURE, 2) + else if(adjusted_pressure >= species.get_warning_high_pressure(src)) + SET_HUD_ALERT(src, HUD_PRESSURE, 1) + else if(adjusted_pressure >= species.get_warning_low_pressure(src)) + SET_HUD_ALERT(src, HUD_PRESSURE, 0) + else if(adjusted_pressure >= species.get_hazard_low_pressure(src)) + SET_HUD_ALERT(src, HUD_PRESSURE, -1) + else + var/list/obj/item/organ/external/parts = get_damageable_organs() + for(var/obj/item/organ/external/limb in parts) + if(QDELETED(limb) || !(limb.owner == src)) + continue + if(limb.brute_dam + limb.burn_dam + (LOW_PRESSURE_DAMAGE) < limb.min_broken_damage) //vacuum does not break bones + limb.take_damage(LOW_PRESSURE_DAMAGE, inflicter = "Low Pressure") + if(getOxyLossPercent() < 55) // 11 OxyLoss per 4 ticks when wearing internals; unconsciousness in 16 ticks, roughly half a minute + take_damage(4) // 16 OxyLoss per 4 ticks when no internals present; unconsciousness in 13 ticks, OXY, roughly twenty seconds + SET_HUD_ALERT(src, HUD_PRESSURE, -2) + + return + +/mob/living/human/get_bodytemperature_difference() + if (is_on_fire()) + return 0 //too busy for pesky metabolic regulation + return ..() + +/mob/living/human/stabilize_body_temperature() + // Robolimbs cause overheating too. + if(robolimb_count) + bodytemperature += round(robolimb_count/2) + return ..() + +/mob/living/human/get_heat_protection_flags(temperature) + . = 0 + //Handle normal clothing + for(var/slot in global.standard_clothing_slots) + var/obj/item/clothing/C = get_equipped_item(slot) + if(istype(C)) + if(C.max_heat_protection_temperature && C.max_heat_protection_temperature >= temperature) + . |= C.heat_protection + if(LAZYLEN(C.accessories)) + for(var/obj/item/clothing/accessory in C.accessories) + if(accessory.max_heat_protection_temperature && accessory.max_heat_protection_temperature >= temperature) + . |= accessory.heat_protection + +//See proc/get_heat_protection_flags(temperature) for the description of this proc. +/mob/living/human/proc/get_cold_protection_flags(temperature) + . = 0 + //Handle normal clothing + for(var/slot in global.standard_clothing_slots) + var/obj/item/clothing/C = get_equipped_item(slot) + if(istype(C)) + if(!isnull(C.min_cold_protection_temperature) && C.min_cold_protection_temperature <= temperature) + . |= C.cold_protection + if(LAZYLEN(C.accessories)) + for(var/obj/item/clothing/accessory in C.accessories) + if(!isnull(accessory.min_cold_protection_temperature) && accessory.min_cold_protection_temperature <= temperature) + . |= accessory.cold_protection + + +/mob/living/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to. + var/thermal_protection_flags = get_heat_protection_flags(temperature) + return get_thermal_protection(thermal_protection_flags) + +/mob/living/human/get_cold_protection(temperature) + if(has_genetic_condition(GENE_COND_COLD_RESISTANCE)) + return 1 //Fully protected from the cold. + + temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. + var/thermal_protection_flags = get_cold_protection_flags(temperature) + return get_thermal_protection(thermal_protection_flags) + +/mob/living/human/proc/get_thermal_protection(var/flags) + .=0 + if(flags) + if(flags & SLOT_HEAD) + . += THERMAL_PROTECTION_HEAD + if(flags & SLOT_UPPER_BODY) + . += THERMAL_PROTECTION_UPPER_TORSO + if(flags & SLOT_LOWER_BODY) + . += THERMAL_PROTECTION_LOWER_TORSO + if(flags & SLOT_LEG_LEFT) + . += THERMAL_PROTECTION_LEG_LEFT + if(flags & SLOT_LEG_RIGHT) + . += THERMAL_PROTECTION_LEG_RIGHT + if(flags & SLOT_FOOT_LEFT) + . += THERMAL_PROTECTION_FOOT_LEFT + if(flags & SLOT_FOOT_RIGHT) + . += THERMAL_PROTECTION_FOOT_RIGHT + if(flags & SLOT_ARM_LEFT) + . += THERMAL_PROTECTION_ARM_LEFT + if(flags & SLOT_ARM_RIGHT) + . += THERMAL_PROTECTION_ARM_RIGHT + if(flags & SLOT_HAND_LEFT) + . += THERMAL_PROTECTION_HAND_LEFT + if(flags & SLOT_HAND_RIGHT) + . += THERMAL_PROTECTION_HAND_RIGHT + return min(1,.) + +/mob/living/human/apply_chemical_effects() + . = ..() + if(has_chemical_effect(CE_GLOWINGEYES, 1)) + update_eyes() + return TRUE + +/mob/living/human/handle_regular_status_updates() + + voice = GetVoice() + SetName(get_visible_name()) + + if(status_flags & GODMODE) + return FALSE + + if(vsc.contaminant_control.CONTAMINATION_LOSS) + var/total_contamination= 0 + for(var/obj/item/thing in src) + if(thing.contaminated) + total_contamination += vsc.contaminant_control.CONTAMINATION_LOSS + take_damage(total_contamination, TOX) + + . = ..() + if(!.) + return + + if(get_shock() >= species.total_health) + if(!stat) + to_chat(src, "[species.halloss_message_self]") + src.visible_message("[src] [species.halloss_message]") + SET_STATUS_MAX(src, STAT_PARA, 10) + + if(HAS_STATUS(src, STAT_PARA) || HAS_STATUS(src, STAT_ASLEEP)) + set_stat(UNCONSCIOUS) + animate_tail_reset() + heal_damage(PAIN, 3) + if(prob(2) && is_asystole() && isSynthetic()) + visible_message("[src] [pick("emits low pitched whirr","beeps urgently")].") + else + set_stat(CONSCIOUS) + + // Check everything else. + //Periodically double-check embedded_flag + if(embedded_flag && !(life_tick % 10)) + if(!embedded_needs_process()) + embedded_flag = 0 + + //Resting + if(current_posture.prone) + if(HAS_STATUS(src, STAT_DIZZY)) + ADJ_STATUS(src, STAT_DIZZY, -15) + if(HAS_STATUS(src, STAT_JITTER)) + ADJ_STATUS(src, STAT_JITTER, -15) + heal_damage(PAIN, 3) + else + if(HAS_STATUS(src, STAT_DIZZY)) + ADJ_STATUS(src, STAT_DIZZY, -3) + if(HAS_STATUS(src, STAT_JITTER)) + ADJ_STATUS(src, STAT_JITTER, -3) + heal_damage(PAIN, 1) + + if(HAS_STATUS(src, STAT_DROWSY)) + SET_STATUS_MAX(src, STAT_BLURRY, 2) + var/sleepy = GET_STATUS(src, STAT_DROWSY) + if(sleepy > 10) + var/zzzchance = min(5, 5*sleepy/30) + if((prob(zzzchance) || sleepy >= 60)) + if(stat == CONSCIOUS) + to_chat(src, SPAN_NOTICE("You are about to fall asleep...")) + SET_STATUS_MAX(src, STAT_ASLEEP, 5) + + +/mob/living/human/handle_regular_hud_updates() + if(life_tick%30==15) + hud_updateflag = 1022 + if(hud_updateflag) // update our mob's hud overlays, AKA what others see flaoting above our head + handle_hud_list() + . = ..() + if(!.) + return + if(stat != DEAD) + var/half_health = get_max_health()/2 + if(stat == UNCONSCIOUS && current_health < half_health) + //Critical damage passage overlay + var/severity = 0 + switch(current_health - half_health) + if(-20 to -10) severity = 1 + if(-30 to -20) severity = 2 + if(-40 to -30) severity = 3 + if(-50 to -40) severity = 4 + if(-60 to -50) severity = 5 + if(-70 to -60) severity = 6 + if(-80 to -70) severity = 7 + if(-90 to -80) severity = 8 + if(-95 to -90) severity = 9 + if(-INFINITY to -95) severity = 10 + overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity) + else + clear_fullscreen("crit") + //Oxygen damage overlay + if(get_damage(OXY)) + var/severity = 0 + switch(getOxyLossPercent()) + if(10 to 20) severity = 1 + if(20 to 25) severity = 2 + if(25 to 30) severity = 3 + if(30 to 35) severity = 4 + if(35 to 40) severity = 5 + if(40 to 45) severity = 6 + if(45 to INFINITY) severity = 7 + overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity) + else + clear_fullscreen("oxy") + + //Fire and Brute damage overlay (BSSR) + var/hurtdamage = src.get_damage(BRUTE) + src.get_damage(BURN) + damageoverlaytemp + damageoverlaytemp = 0 // We do this so we can detect if someone hits us or not. + if(hurtdamage) + var/severity = 0 + switch(hurtdamage) + if(10 to 25) severity = 1 + if(25 to 40) severity = 2 + if(40 to 55) severity = 3 + if(55 to 70) severity = 4 + if(70 to 85) severity = 5 + if(85 to INFINITY) severity = 6 + overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity) + else + clear_fullscreen("brute") + + return 1 + +/mob/living/human/handle_random_events() + // Puke if toxloss is too high + var/vomit_score = 0 + for(var/tag in list(BP_LIVER,BP_KIDNEYS)) + var/obj/item/organ/internal/organ = GET_INTERNAL_ORGAN(src, tag) + if(organ) + vomit_score += organ.get_organ_damage() + else if (should_have_organ(tag)) + vomit_score += 45 + if(has_chemical_effect(CE_TOXIN, 1) || radiation) + vomit_score += 0.5 * get_damage(TOX) + if(has_chemical_effect(CE_ALCOHOL_TOXIC, 1)) + vomit_score += 10 * GET_CHEMICAL_EFFECT(src, CE_ALCOHOL_TOXIC) + if(has_chemical_effect(CE_ALCOHOL, 1)) + vomit_score += 10 + if(stat != DEAD && vomit_score > 25 && prob(10)) + vomit(vomit_score, vomit_score/25) + + //0.1% chance of playing a scary sound to someone who's in complete darkness + if(isturf(loc) && rand(1,1000) == 1) + var/turf/T = loc + if(T.get_lumcount() <= LIGHTING_SOFT_THRESHOLD) + playsound_local(T,pick(global.scarySounds),50, 1, -1) + + var/area/A = get_area(src) + if(client && world.time >= client.played + 60 SECONDS) + A.play_ambience(src) + if(stat == UNCONSCIOUS && world.time - l_move_time < 5 && prob(10)) + to_chat(src,"You feel like you're [pick("moving","flying","floating","falling","hovering")].") + +#define BASE_SHOCK_RECOVERY 1 +/mob/living/human/proc/handle_shock() + if(!can_feel_pain() || (status_flags & GODMODE)) + shock_stage = 0 + return + + var/stress_modifier = get_stress_modifier() + if(stress_modifier) + stress_modifier *= get_config_value(/decl/config/num/health_stress_shock_recovery_constant) + + if(is_asystole()) + shock_stage = max(shock_stage + (BASE_SHOCK_RECOVERY + stress_modifier), 61) + + var/traumatic_shock = get_shock() + if(traumatic_shock >= max(30, 0.8*shock_stage)) + shock_stage += (1 + stress_modifier) + else if (!is_asystole()) + shock_stage = min(shock_stage, 160) + var/recovery = 1 + if(traumatic_shock < 0.5 * shock_stage) //lower shock faster if pain is gone completely + recovery++ + if(traumatic_shock < 0.25 * shock_stage) + recovery++ + shock_stage = max(shock_stage - (recovery * (1-stress_modifier)), 0) + return + + if(stat != CONSCIOUS) + return + + // If we haven't adjusted by at least one full unit, don't run the message logic below. + var/next_rounded_shock_stage = round(shock_stage) + if(next_rounded_shock_stage == rounded_shock_stage) + return + + rounded_shock_stage = next_rounded_shock_stage + if(rounded_shock_stage <= 0) + return + + if(rounded_shock_stage == 10) + // Please be very careful when calling custom_pain() from within code that relies on pain/trauma values. There's the + // possibility of a feedback loop from custom_pain() being called with a positive power, incrementing pain on a limb, + // which triggers this proc, which calls custom_pain(), etc. Make sure you call it with nohalloss = TRUE in these cases! + custom_pain("[pick("It hurts so much", "You really need some painkillers", "Dear god, the pain")]!", 10, nohalloss = TRUE) + + if(rounded_shock_stage >= 30) + if(rounded_shock_stage == 30) + var/decl/pronouns/pronouns = get_pronouns() + visible_message("\The [src] is having trouble keeping [pronouns.his] eyes open.") + if(prob(30)) + SET_STATUS_MAX(src, STAT_BLURRY, 2) + SET_STATUS_MAX(src, STAT_STUTTER, 5) + + if (rounded_shock_stage >= 60) + if(rounded_shock_stage == 60) visible_message("[src]'s body becomes limp.") + if (prob(2)) + custom_pain("[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!", rounded_shock_stage, nohalloss = TRUE) + SET_STATUS_MAX(src, STAT_WEAK, 3) + + if(rounded_shock_stage >= 80) + if (prob(5)) + custom_pain("[pick("The pain is excruciating", "Please, just end the pain", "Your whole body is going numb")]!", rounded_shock_stage, nohalloss = TRUE) + SET_STATUS_MAX(src, STAT_WEAK, 5) + + if(rounded_shock_stage >= 120) + if(!HAS_STATUS(src, STAT_PARA) && prob(2)) + custom_pain("[pick("You black out", "You feel like you could die any moment now", "You're about to lose consciousness")]!", rounded_shock_stage, nohalloss = TRUE) + SET_STATUS_MAX(src, STAT_PARA, 5) + + if(rounded_shock_stage == 150) + visible_message("[src] can no longer stand, collapsing!") + + if(rounded_shock_stage >= 150) + SET_STATUS_MAX(src, STAT_WEAK, 5) + +#undef BASE_SHOCK_RECOVERY + +/* + Called by life(), instead of having the individual hud items update icons each tick and check for status changes + we only set those statuses and icons upon changes. Then those HUD items will simply add those pre-made images. + This proc below is only called when those HUD elements need to change as determined by the mobs hud_updateflag. +*/ +/mob/living/human/proc/handle_hud_list() + if (BITTEST(hud_updateflag, HEALTH_HUD) && hud_list[HEALTH_HUD]) + var/image/holder = hud_list[HEALTH_HUD] + if(stat == DEAD) + holder.icon_state = "0" // X_X + else if(is_asystole()) + holder.icon_state = "flatline" + else + holder.icon_state = "[get_pulse()]" + hud_list[HEALTH_HUD] = holder + + if (BITTEST(hud_updateflag, LIFE_HUD) && hud_list[LIFE_HUD]) + var/image/holder = hud_list[LIFE_HUD] + if(stat == DEAD) + holder.icon_state = "huddead" + else + holder.icon_state = "hudhealthy" + hud_list[LIFE_HUD] = holder + + if (BITTEST(hud_updateflag, STATUS_HUD) && hud_list[STATUS_HUD] && hud_list[STATUS_HUD_OOC]) + var/image/holder = hud_list[STATUS_HUD] + if(stat == DEAD) + holder.icon_state = "huddead" + else + holder.icon_state = "hudhealthy" + + var/image/holder2 = hud_list[STATUS_HUD_OOC] + if(stat == DEAD) + holder2.icon_state = "huddead" + else + holder2.icon_state = "hudhealthy" + + hud_list[STATUS_HUD] = holder + hud_list[STATUS_HUD_OOC] = holder2 + + if (BITTEST(hud_updateflag, ID_HUD) && hud_list[ID_HUD]) + var/image/holder = hud_list[ID_HUD] + holder.icon_state = "hudunknown" + + var/obj/item/id = get_equipped_item(slot_wear_id_str) + if(id) + var/obj/item/card/id/id_card = id.GetIdCard() + if(id_card) + var/datum/job/J = SSjobs.get_by_title(id_card.GetJobName()) + if(J) + holder.icon = J.hud_icon + holder.icon_state = J.hud_icon_state + + hud_list[ID_HUD] = holder + + if (BITTEST(hud_updateflag, WANTED_HUD) && hud_list[WANTED_HUD]) + var/image/holder = hud_list[WANTED_HUD] + holder.icon_state = "hudblank" + var/perpname = name + var/obj/item/id = get_equipped_item(slot_wear_id_str) + if(id) + var/obj/item/card/id/id_card = id.GetIdCard() + if(id_card) + perpname = id_card.registered_name + + var/datum/computer_file/report/crew_record/E = get_crewmember_record(perpname) + if(E) + switch(E.get_criminalStatus()) + if("Arrest") + holder.icon_state = "hudwanted" + if("Incarcerated") + holder.icon_state = "hudprisoner" + if("Parolled") + holder.icon_state = "hudparolled" + if("Released") + holder.icon_state = "hudreleased" + hud_list[WANTED_HUD] = holder + + if ( BITTEST(hud_updateflag, IMPLOYAL_HUD) \ + || BITTEST(hud_updateflag, IMPCHEM_HUD) \ + || BITTEST(hud_updateflag, IMPTRACK_HUD)) + + var/image/holder1 = hud_list[IMPTRACK_HUD] + var/image/holder2 = hud_list[IMPLOYAL_HUD] + var/image/holder3 = hud_list[IMPCHEM_HUD] + + holder1.icon_state = "hud_imp_blank" + holder2.icon_state = "hud_imp_blank" + holder3.icon_state = "hud_imp_blank" + for(var/obj/item/implant/implant in src) + if(implant.implanted) + if(istype(implant,/obj/item/implant/tracking)) + holder1.icon_state = "hud_imp_tracking" + else if(istype(implant,/obj/item/implant/loyalty)) + holder2.icon_state = "hud_imp_loyal" + else if(istype(implant,/obj/item/implant/chem)) + holder3.icon_state = "hud_imp_chem" + + hud_list[IMPTRACK_HUD] = holder1 + hud_list[IMPLOYAL_HUD] = holder2 + hud_list[IMPCHEM_HUD] = holder3 + + if (BITTEST(hud_updateflag, SPECIALROLE_HUD)) + var/image/holder = hud_list[SPECIALROLE_HUD] + holder.icon_state = "hudblank" + var/special_role = mind?.get_special_role_name() + if(special_role) + if(global.hud_icon_reference[special_role]) + holder.icon_state = global.hud_icon_reference[special_role] + else + holder.icon_state = "hudsyndicate" + hud_list[SPECIALROLE_HUD] = holder + hud_updateflag = 0 + +/mob/living/human/rejuvenate() + reset_blood() + full_prosthetic = null + shock_stage = 0 + ..() + adjust_stamina(100) + +/mob/living/human/reset_view(atom/A) + ..() + if(machine_visual && machine_visual != A) + machine_visual.remove_visual(src) + if(eyeobj) + eyeobj.remove_visual(src) + +/mob/living/human/handle_vision() + if(client) + var/datum/global_hud/global_hud = get_global_hud() + client.screen.Remove(global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science) + if(machine) + var/viewflags = machine.check_eye(src) + if(viewflags < 0) + reset_view(null, 0) + else if(viewflags) + set_sight(sight|viewflags) + if(eyeobj && eyeobj.owner != src) + reset_view(null) + if(has_genetic_condition(GENE_COND_REMOTE_VIEW) && remoteview_target && remoteview_target.stat != CONSCIOUS) + remoteview_target = null + reset_view(null, 0) + + update_equipment_vision() + species.handle_vision(src) + +/mob/living/human/update_living_sight() + ..() + if(GET_CHEMICAL_EFFECT(src, CE_THIRDEYE) || has_genetic_condition(GENE_COND_XRAY)) + set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) diff --git a/code/modules/mob/living/human/login.dm b/code/modules/mob/living/human/login.dm new file mode 100644 index 000000000000..3d8a8f70e2b6 --- /dev/null +++ b/code/modules/mob/living/human/login.dm @@ -0,0 +1,4 @@ +/mob/living/human/Login() + ..() + if(species) + species.handle_login_special(src) diff --git a/code/modules/mob/living/human/logout.dm b/code/modules/mob/living/human/logout.dm new file mode 100644 index 000000000000..3c473576f41a --- /dev/null +++ b/code/modules/mob/living/human/logout.dm @@ -0,0 +1,4 @@ +/mob/living/human/Logout() + ..() + if(species) species.handle_logout_special(src) + return \ No newline at end of file diff --git a/code/modules/mob/living/human/npcs.dm b/code/modules/mob/living/human/npcs.dm new file mode 100644 index 000000000000..3b49bbc28542 --- /dev/null +++ b/code/modules/mob/living/human/npcs.dm @@ -0,0 +1,53 @@ +/mob/living/human/monkey/punpun + real_name = "Pun Pun" + gender = MALE + +/mob/living/human/monkey/punpun/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + ..() + return INITIALIZE_HINT_LATELOAD + +/mob/living/human/monkey/punpun/LateInitialize() + ..() + if(prob(50)) + equip_to_appropriate_slot(new /obj/item/clothing/pants/slacks/black(src)) + equip_to_appropriate_slot(new /obj/item/clothing/shirt/button(src)) + equip_to_appropriate_slot(new /obj/item/clothing/neck/tie/bow/red(src)) + equip_to_appropriate_slot(new /obj/item/clothing/suit/jacket/vest/blue(src)) + else + var/obj/item/clothing/C = new /obj/item/clothing/pants/casual/mustangjeans(src) + C.attach_accessory(null, new /obj/item/clothing/shirt/hawaii/random(src)) + equip_to_appropriate_slot(C) + if(prob(10)) + equip_to_appropriate_slot(new /obj/item/clothing/head/collectable/petehat(src)) + +/decl/outfit/blank_subject + name = "Test Subject" + uniform = /obj/item/clothing/jumpsuit/white/blank + shoes = /obj/item/clothing/shoes/color/white + head = /obj/item/clothing/head/helmet/facecover + mask = /obj/item/clothing/mask/muzzle + suit = /obj/item/clothing/suit/straight_jacket + +/obj/item/clothing/jumpsuit/white/blank/Initialize() + . = ..() + var/obj/item/clothing/sensor/vitals/sensor = new(src) + sensor.set_sensors_locked(TRUE) + sensor.set_sensor_mode(VITALS_SENSOR_OFF) + attach_accessory(null, sensor) + +/mob/living/human/blank/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + species_uid = /decl/species/human::uid + ..() + return INITIALIZE_HINT_LATELOAD + +/mob/living/human/blank/LateInitialize() + var/number = "[pick(global.greek_letters)]-[rand(1,30)]" + fully_replace_character_name("Subject [number]") + var/decl/outfit/outfit = GET_DECL(/decl/outfit/blank_subject) + outfit.equip_outfit(src) + var/obj/item/clothing/head/helmet/facecover/F = locate() in src + if(F) + F.SetName("[F.name] ([number])") + +/mob/living/human/blank/ssd_check() + return FALSE diff --git a/code/modules/mob/living/carbon/human/obj_grabs.dm b/code/modules/mob/living/human/obj_grabs.dm similarity index 100% rename from code/modules/mob/living/carbon/human/obj_grabs.dm rename to code/modules/mob/living/human/obj_grabs.dm diff --git a/code/modules/mob/living/human/say.dm b/code/modules/mob/living/human/say.dm new file mode 100644 index 000000000000..3b7ce80dab1f --- /dev/null +++ b/code/modules/mob/living/human/say.dm @@ -0,0 +1,118 @@ +/mob/living/human/say(var/message, var/decl/language/speaking, var/verb = "says", whispering) + if(!whispering) + var/obj/item/organ/internal/voicebox/voice = locate() in get_internal_organs() + // Check if the language they're speaking is vocal and not supplied by a machine, and if they are currently suffocating. + whispering = (whispering || has_chemical_effect(CE_VOICELOSS, 1)) + var/decl/bodytype/root_bodytype = get_bodytype() + if((!speaking || !(speaking.flags & (LANG_FLAG_NONVERBAL|LANG_FLAG_SIGNLANG))) && (!voice || !voice.is_usable() || !voice.assists_languages[speaking]) && !root_bodytype.is_robotic && need_breathe() && failed_last_breath) + var/obj/item/organ/internal/lungs/L = get_organ(root_bodytype.breathing_organ, /obj/item/organ/internal/lungs) + if(!L || L.breath_fail_ratio > 0.9) + if(L && world.time < L.last_successful_breath + 2 MINUTES) //if we're in grace suffocation period, give it up for last words + to_chat(src, SPAN_WARNING("You use your remaining air to say something!")) + L.last_successful_breath = world.time - 2 MINUTES + whispering = FALSE + else + to_chat(src, SPAN_WARNING("You don't have enough air[L ? " in [L]" : ""] to make a sound!")) + return + else if(L.breath_fail_ratio > 0.7 || (L.breath_fail_ratio > 0.4 && length(message) > 10) || (L.breath_fail_ratio > 0.2 && length(message) > 30)) + whispering = TRUE + if(name != GetVoice()) + if(get_id_name("Unknown") == GetVoice()) + SetName(get_id_name("Unknown")) + . = ..(message, speaking, verb, whispering) + +/mob/living/human/proc/forcesay(list/append) + if(stat == CONSCIOUS) + if(client) + var/virgin = 1 //has the text been modified yet? + var/temp = winget(client, "input", "text") + if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //case sensitive means + var/main_key = get_common_radio_prefix() + temp = replacetext(temp, main_key, "") //general radio + + var/channel_key = get_department_radio_prefix() + if(findtext(trim_left(temp), channel_key, 6, 7)) //dept radio + temp = copytext(trim_left(temp), 8) + virgin = 0 + + if(virgin) + temp = copytext(trim_left(temp), 6) //normal speech + virgin = 0 + + while(findtext(trim_left(temp), channel_key, 1, 2)) //dept radio again (necessary) + temp = copytext(trim_left(temp), 3) + + var/custom_emote_key = get_prefix_key(/decl/prefix/custom_emote) + if(findtext(temp, custom_emote_key, 1, 2)) //emotes + return + temp = copytext(trim_left(temp), 1, rand(5,8)) + + var/trimmed = trim_left(temp) + if(length(trimmed)) + if(append) + temp += pick(append) + + say(temp) + winset(client, "input", "text=[null]") + +/mob/living/human/say_understands(mob/speaker, decl/language/speaking) + return (!speaking && (issilicon(speaker) || istype(speaker, /mob/announcer) || isbrain(speaker))) || ..() + +/mob/living/human/say_quote(var/message, var/decl/language/speaking = null) + var/verb = "says" + var/ending = copytext(message, length(message)) + + if(speaking) + verb = speaking.get_spoken_verb(src, ending) + else + if(ending == "!") + verb=pick("exclaims","shouts","yells") + else if(ending == "?") + verb="asks" + + return verb + +/mob/living/human/handle_message_mode(message_mode, message, verb, speaking, used_radios) + if(message_mode == MESSAGE_MODE_WHISPER) //It's going to get sanitized again immediately, so decode. + whisper_say(html_decode(message), speaking) + return TRUE + return ..() + +/mob/living/human/handle_speech_sound() + if(species.speech_sounds && prob(species.speech_chance)) + var/list/returns[2] + var/sound_to_play = species.speech_sounds + if(islist(species.speech_sounds)) + sound_to_play = species.speech_sounds[gender] || species.speech_sounds + returns[1] = sound(pick(sound_to_play)) + returns[2] = 50 + return returns + return ..() + +/mob/living/human/can_speak(decl/language/speaking) + if(ispath(speaking, /decl/language)) + speaking = GET_DECL(speaking) + if(!istype(speaking)) + return ..() + if(species) + if(speaking.type in species.assisted_langs) + for(var/obj/item/organ/internal/voicebox/I in get_internal_organs()) + if(I.is_usable() && I.assists_languages[speaking]) + return TRUE + return FALSE + else if(speaking.type in species.unspeakable_langs) + return FALSE + . = ..() + +/mob/living/human/parse_language(var/message) + var/prefix = copytext(message,1,2) + if(length(message) >= 1 && prefix == get_prefix_key(/decl/prefix/audible_emote)) + return GET_DECL(/decl/language/noise) + + if(length(message) >= 2 && is_language_prefix(prefix)) + var/language_prefix = lowertext(copytext(message, 2 ,3)) + var/decl/language/L = SSlore.get_language_by_key(language_prefix) + if (can_speak(L)) + return L + + return null diff --git a/code/modules/mob/living/human/unarmed_attack.dm b/code/modules/mob/living/human/unarmed_attack.dm new file mode 100644 index 000000000000..33728d7201cd --- /dev/null +++ b/code/modules/mob/living/human/unarmed_attack.dm @@ -0,0 +1,378 @@ +//Species unarmed attacks +/decl/natural_attack + abstract_type = /decl/natural_attack + var/name + var/selector_icon_state + var/attack_verb = list("attacks") // Empty hand hurt intent verb. + var/attack_noun = list("fist") + var/damage = 0 // Extra empty hand attack damage. + var/attack_sound = "punch" + var/miss_sound = 'sound/weapons/punchmiss.ogg' + var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent. + var/sharp = 0 + var/edge = 0 + var/delay = 0 + var/deal_halloss + var/sparring_variant_type = /decl/natural_attack/light_strike + var/eye_attack_text + var/eye_attack_text_victim + var/list/usable_with_limbs = list(BP_L_HAND, BP_R_HAND) + var/is_starting_default = FALSE + var/apply_cooldown = DEFAULT_ATTACK_COOLDOWN + +/decl/natural_attack/proc/summarize() + var/list/usable_limbs = list() + for(var/limb in usable_with_limbs) + var/start = copytext(limb, 1, 3) + if(start == "l_") + usable_limbs |= "left [copytext(limb, 3)]" + else if(start == "r_") + usable_limbs |= "right [copytext(limb, 3)]" + else + usable_limbs |= limb + . = "You can use this attack with your: [english_list(usable_limbs)]." + if(sharp || edge) + . += "
    This attack is sharp and will cause bleeding." + if(shredding) + . += "
    This powerful attack will shred electronics and destroy some structures." + +/decl/natural_attack/proc/get_damage_type() + if(deal_halloss) + return PAIN + return BRUTE + +/decl/natural_attack/proc/get_damage_flags() + . |= (sharp && DAM_SHARP) + . |= (edge && DAM_EDGE) + +/decl/natural_attack/proc/padded_by_user_gear(var/mob/living/human/user) + if(istype(user) && length(usable_with_limbs)) + for(var/limb_slot in usable_with_limbs) + var/obj/item/gear = user.get_covering_equipped_item_by_zone(limb_slot) + if(istype(gear) && (gear.item_flags & ITEM_FLAG_PADDED)) + return TRUE + return FALSE + +/decl/natural_attack/proc/resolve_to_soft_variant(var/mob/living/human/user) + . = src + if(istype(user) && (user.pulling_punches || padded_by_user_gear(user))) + var/decl/natural_attack/soft_variant = get_sparring_variant() + if(soft_variant) + . = soft_variant + +/decl/natural_attack/proc/get_sparring_variant() + return GET_DECL(sparring_variant_type) + +/decl/natural_attack/proc/attack_is_usable(var/mob/living/human/user, var/mob/target, var/zone) + if(!user.restrained() && !user.incapacitated()) + for(var/etype in usable_with_limbs) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(user, etype) + if(E) + return TRUE + return FALSE + +/decl/natural_attack/proc/get_unarmed_damage(mob/living/user, mob/living/victim) + return damage + +// Returns TRUE if further affects should be applied. +/decl/natural_attack/proc/apply_attack_effects(mob/living/user, mob/living/target, attack_damage, zone) + + if(target.stat == DEAD) + return FALSE + + var/armour = target.get_blocked_ratio(zone, BRUTE, damage = attack_damage) + if(armour >= 1) + return FALSE + + var/stun_chance = rand(0, 100) + if(attack_damage >= 5 && !(target == user) && stun_chance <= attack_damage * 5) // 25% standard chance + switch(zone) // strong punches can have effects depending on where they hit + if(BP_HEAD, BP_EYES, BP_MOUTH) + // Induce blurriness + target.visible_message("[target] looks momentarily disoriented.", "You see stars.") + target.apply_effect(attack_damage*2, EYE_BLUR, armour) + if(BP_L_ARM, BP_L_HAND, BP_R_ARM, BP_R_HAND) + var/check_zone = zone + if(check_zone == BP_L_ARM) + check_zone = BP_L_HAND + else if(check_zone == BP_R_ARM) + check_zone = BP_R_HAND + var/equipped = target.get_equipped_item(check_zone) + if(equipped) + target.visible_message(SPAN_DANGER("\The [equipped] was knocked right out of [target]'s grasp!")) + target.drop_from_inventory(equipped) + if(BP_CHEST) + if(!target.current_posture.prone) + var/turf/T = get_step(get_turf(target), get_dir(get_turf(user), get_turf(target))) + if(!T.density) + step(target, get_dir(get_turf(user), get_turf(target))) + target.visible_message("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]") + if(prob(50)) + target.set_dir(global.reverse_dir[target.dir]) + target.apply_effect(attack_damage * 0.4, WEAKEN, armour) + if(BP_GROIN) + var/decl/pronouns/pronouns = target.get_pronouns() + target.visible_message( \ + SPAN_WARNING("\The [target] looks like [pronouns.he] [pronouns.is] in pain!"), \ + SPAN_WARNING(pronouns.get_message_for_being_kicked_in_the_dick())) + target.apply_effects(stutter = attack_damage * 2, agony = attack_damage* 3, blocked = armour) + if(BP_L_LEG, BP_L_FOOT, BP_R_LEG, BP_R_FOOT) + if(!target.current_posture.prone) + target.visible_message("[target] gives way slightly.") + target.apply_effect(attack_damage*3, PAIN, armour) + else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage * 5 >= 100)) // Chance to get the usual throwdown as well (25% standard chance) + if(!target.current_posture.prone) + target.visible_message("[target] [pick("slumps", "falls", "drops")] down to the ground!") + else + target.visible_message("[target] has been weakened!") + target.apply_effect(3, WEAKEN, armour * 100) + + var/obj/item/clothing/gear = target.get_covering_equipped_item_by_zone(zone) + if(istype(gear) && prob(10)) + gear.leave_evidence(user) + + return TRUE + +/decl/natural_attack/proc/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + var/msg = "\The [user] [pick(attack_verb)] \the [target]" + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) + if(affecting) + msg = "[msg] in the [affecting.name]" + if(islist(attack_noun) && length(attack_noun)) + msg = "[msg] with their [pick(attack_noun)]" + if(msg) + user.visible_message(SPAN_DANGER("[msg]!")) + playsound(user.loc, attack_sound, 25, 1, -1) + +/decl/natural_attack/proc/handle_eye_attack(var/mob/living/human/user, var/mob/living/human/target) + var/obj/item/organ/internal/eyes = GET_INTERNAL_ORGAN(target, BP_EYES) + var/decl/pronouns/pronouns = user.get_pronouns() + if(eyes) + eyes.take_damage(rand(3,4), 1) + user.visible_message(SPAN_DANGER("\The [user] jams [pronouns.his] [eye_attack_text] into \the [target]'s [eyes.name]!")) + if(eyes.can_feel_pain()) + to_chat(target, SPAN_DANGER("You experience immense pain as [eye_attack_text_victim] are jammed into your [eyes.name]!")) + else + to_chat(target, SPAN_DANGER("You experience [eye_attack_text_victim] being jammed into your [eyes.name].")) + else + var/decl/pronouns/target_gender = target.get_pronouns() + user.visible_message(SPAN_DANGER("\The [user] attempts to press [pronouns.his] [eye_attack_text] into \the [target]'s eyes, but [target_gender.he] [target_gender.does]n't have any!")) + +/decl/natural_attack/proc/damage_flags() + return (sharp ? DAM_SHARP : 0) | (edge ? DAM_EDGE : 0) + +/decl/natural_attack/bite + name = "bite" + selector_icon_state = "attack_bite" + attack_verb = list("bit") + attack_noun = list("mouth") + attack_sound = 'sound/weapons/bite.ogg' + shredding = 0 + damage = 5 + sharp = FALSE + edge = FALSE + usable_with_limbs = list(BP_HEAD) + +/decl/natural_attack/bite/sharp + attack_verb = list("bit", "chomped") + sharp = TRUE + edge = TRUE + +/decl/natural_attack/bite/attack_is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) + if(user.get_item_blocking_speech()) + return FALSE + for(var/slot in list(slot_wear_mask_str, slot_head_str, slot_wear_suit_str)) + var/obj/item/clothing/gear = user.get_equipped_item(slot) + if(istype(gear) && (gear.body_parts_covered & SLOT_FACE) && (gear.item_flags & ITEM_FLAG_THICKMATERIAL)) + return FALSE //prevent biting through a space helmet or similar + if (user == target && (zone == BP_HEAD || zone == BP_EYES || zone == BP_MOUTH)) + return FALSE //how do you bite yourself in the head? + return TRUE + +/decl/natural_attack/punch + name = "punch" + selector_icon_state = "attack_punch" + attack_verb = list("punched") + attack_noun = list("fist") + eye_attack_text = "fingers" + eye_attack_text_victim = "digits" + damage = 0 + sparring_variant_type = /decl/natural_attack/light_strike/punch + is_starting_default = TRUE + +/decl/natural_attack/punch/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) + if(!affecting) + return ..() + + attack_damage = clamp(attack_damage, 1, 5) // We expect damage input of 1 to 5 for this proc. But we leave this check juuust in case. + + if(target == user) + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message(SPAN_DANGER("\The [user] [pick(attack_verb)] [pronouns.self] in \the [affecting]!")) + return 0 + + target.update_personal_goal(/datum/goal/achievement/fistfight, TRUE) + user.update_personal_goal(/datum/goal/achievement/fistfight, TRUE) + + var/decl/pronouns/user_gender = user.get_pronouns() + var/decl/pronouns/target_gender = target.get_pronouns() + var/attack_string + if(!target.current_posture.prone) + switch(zone) + if(BP_HEAD, BP_MOUTH, BP_EYES) + // ----- HEAD ----- // + switch(attack_damage) + if(1 to 2) + attack_string = "slapped \the [target] across [target_gender.his] cheek" + if(3 to 4) + user.visible_message(pick( + 80; attack_string = "[pick(attack_verb)] \the [target] in the head", + 20; attack_string = "struck \the [target] in the head[pick("", " with a closed fist")]", + 50; attack_string = "threw a hook against \the [target]'s head" + )) + if(5) + user.visible_message(pick( + 10; attack_string = "gave \the [target] a solid slap across [target_gender.his] face", + 90; attack_string = "smashed [user_gender.his] [pick(attack_noun)] into \the [target]'s [pick("[affecting.name]", "face", "jaw")]" + )) + else + // ----- BODY ----- // + switch(attack_damage) + if(1 to 2) + attack_string = "threw a glancing punch at [target]'s [affecting.name]" + if(1 to 4) + attack_string = "[pick(attack_verb)] [target] in \the [affecting]" + if(5) + attack_string = "smashed [user_gender.his] [pick(attack_noun)] into [target]'s [affecting.name]" + else + //why do we have a separate set of verbs for lying targets? + attack_string = "[pick("punched", "threw a punch at", "struck", "slammed their [pick(attack_noun)] into")] \the [target]'s [affecting.name]" + + if(attack_string) + user.visible_message(SPAN_DANGER("\The [user] [attack_string]!")) + +/decl/natural_attack/kick + name = "kick" + selector_icon_state = "attack_kick" + attack_verb = list("struck") + attack_noun = list("foot", "knee") + attack_sound = "swing_hit" + damage = 0 + usable_with_limbs = list(BP_L_FOOT, BP_R_FOOT) + sparring_variant_type = /decl/natural_attack/light_strike/kick + +/decl/natural_attack/kick/attack_is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) + if(zone == BP_HEAD || zone == BP_EYES || zone == BP_MOUTH) + zone = BP_CHEST + . = ..() + +/decl/natural_attack/kick/get_unarmed_damage(mob/living/user, mob/living/victim) + var/obj/item/clothing/shoes = user.get_equipped_item(slot_shoes_str) + if(!istype(shoes)) + return damage + return damage + (shoes ? shoes.expend_attack_force(user) : 0) + +/decl/natural_attack/kick/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) + if(!affecting) + return ..() + + attack_damage = clamp(attack_damage, 1, 5) + switch(attack_damage) + if(1 to 2) user.visible_message("[user] threw [target] a glancing [pick(attack_noun)] to \the [affecting]!") //it's not that they're kicking lightly, it's that the kick didn't quite connect + if(3 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \the [affecting]!") + if(5) user.visible_message("[user] landed a strong [pick(attack_noun)] against [target]'s [affecting.name]!") + +/decl/natural_attack/stomp + name = "stomp" + selector_icon_state = "attack_stomp" + attack_verb = list("stomped on") + attack_noun = list("foot") + attack_sound = "swing_hit" + damage = 0 + usable_with_limbs = list(BP_L_FOOT, BP_R_FOOT) + +/decl/natural_attack/stomp/attack_is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) + if(!istype(target)) + return FALSE + if (!user.current_posture.prone && (target.current_posture.prone || (zone in list(BP_L_FOOT, BP_R_FOOT)))) + if((user in target.grabbed_by) && target.current_posture.prone) + return FALSE + for(var/foot_tag in list(BP_L_FOOT, BP_R_FOOT)) + if(GET_EXTERNAL_ORGAN(user, foot_tag)) + return TRUE + return FALSE + +/decl/natural_attack/stomp/get_unarmed_damage(mob/living/user, mob/living/victim) + var/obj/item/clothing/shoes = user.get_equipped_item(slot_shoes_str) + return damage + (shoes ? shoes.expend_attack_force(user) : 0) + +/decl/natural_attack/stomp/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) + if(!affecting) + return ..() + + var/obj/item/clothing/shoes = user.get_equipped_item(slot_shoes_str) + attack_damage = clamp(attack_damage, 1, 5) + + var/shoe_text = shoes ? copytext(shoes.name, 1, -1) : "foot" + var/decl/pronouns/pronouns = user.get_pronouns() + var/attack_string + switch(attack_damage) + if(1 to 4) + attack_string = pick( + "stomped on \the [target]'s [affecting.name][pick("", "with their [shoe_text]")]", + "stomped [pronouns.his] [shoe_text] down on \the [target]'s [affecting.name]") + if(5) + attack_string = pick( + "stomped down hard on \the [target]'s [affecting.name][pick("", "with their [shoe_text]")]", + "slammed [pronouns.his] [shoe_text] down on \the [target]'s [affecting.name]") + if(attack_string) + user.visible_message(SPAN_DANGER("\The [user] [attack_string]!")) + +/decl/natural_attack/light_strike + name = "light strike" + deal_halloss = 3 + selector_icon_state = "attack_light_strike" + attack_noun = list("limb") + attack_verb = list("tapped", "lightly struck") + shredding = 0 + damage = 0 + sharp = FALSE + edge = FALSE + attack_sound = "light_strike" + +/decl/natural_attack/light_strike/punch + name = "light punch" + selector_icon_state = "attack_light_punch" + attack_noun = list("fist") + usable_with_limbs = list(BP_L_HAND, BP_R_HAND) + +/decl/natural_attack/light_strike/kick + name = "light kick" + selector_icon_state = "attack_light_kick" + attack_noun = list("foot") + usable_with_limbs = list(BP_L_FOOT, BP_R_FOOT) + +/decl/natural_attack/light_strike/kick/attack_is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) + if(zone == BP_HEAD || zone == BP_EYES || zone == BP_MOUTH) + zone = BP_CHEST + . = ..() + +/decl/natural_attack/forelimb_slash + name = "forelimb slash" + selector_icon_state = "attack_slash" + attack_verb = list("mauled", "slashed", "struck", "pierced") + attack_noun = list("forelimb") + damage = 8 + shredding = 1 + sharp = TRUE + edge = TRUE + delay = 20 + eye_attack_text = "a forelimb" + eye_attack_text_victim = "a forelimb" + usable_with_limbs = list(BP_L_HAND, BP_R_HAND) diff --git a/code/modules/mob/living/human/update_icons.dm b/code/modules/mob/living/human/update_icons.dm new file mode 100644 index 000000000000..07d4bbbf6b9e --- /dev/null +++ b/code/modules/mob/living/human/update_icons.dm @@ -0,0 +1,360 @@ +var/global/list/_limb_mask_cache = list() +/proc/get_limb_mask_for(obj/item/organ/external/limb) + var/decl/bodytype/bodytype = limb?.bodytype + var/bodypart = limb?.icon_state + if(!bodytype || !bodypart) + return + LAZYINITLIST(_limb_mask_cache[bodytype]) + if(!_limb_mask_cache[bodytype][bodypart]) + var/icon/limb_mask = icon(bodytype.icon_base, bodypart) + limb_mask.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) + _limb_mask_cache[bodytype][bodypart] = limb_mask + return _limb_mask_cache[bodytype][bodypart] + +/* + Global associative list for caching humanoid icons. + Index format m or f, followed by a string of 0 and 1 to represent bodyparts followed by husk 1 or 0. + TODO: Proper documentation + icon_key is [bodytype.get_icon_cache_uid(src)][g][husk][skin_tone] +*/ +var/global/list/human_icon_cache = list() +var/global/list/eye_icon_cache = list() +var/global/list/tail_icon_cache = list() //key is [bodytype.get_icon_cache_uid(src)][skin_colour] + +/proc/overlay_image(icon,icon_state,color,flags) + var/image/ret = image(icon,icon_state) + ret.color = color + ret.appearance_flags = flags + return ret + + /////////////////////// + //UPDATE_ICONS SYSTEM// + /////////////////////// +/* + +UPDATED August 2023: The comments below are from a point where human equipment overlay code was entirely +defined in procs in this file; please refer to get/set_current_mob_underlay/overlay and update_equipment_overlay. + +Calling this a system is perhaps a bit trumped up. It is essentially update_clothing dismantled into its +core parts. The key difference is that when we generate overlays we do not generate either lying or standing +versions. Instead, we generate both and store them in two fixed-length lists, both using the same list-index +(The indexes are in update_icons.dm): Each list for humans is (at the time of writing) of length 19. +This will hopefully be reduced as the system is refined. + +When we call update_icons, the 'current_posture.prone' variable is checked and then the appropriate list is assigned to our overlays! +That in itself uses a tiny bit more memory (no more than all the ridiculous lists the game has already mind you). + +On the other-hand, it should be very CPU cheap in comparison to the old system. +In the old system, we updated all our overlays every life() call, even if we were standing still inside a crate! +or dead!. 25ish overlays, all generated from scratch every second for every xeno/human/monkey and then applied. +More often than not update_clothing was being called a few times in addition to that! CPU was not the only issue, +all those icons had to be sent to every client. So really the cost was extremely cumulative. To the point where +update_clothing would frequently appear in the top 10 most CPU intensive procs during profiling. + +Another feature of this new system is that our lists are indexed. This means we can update specific overlays! +So we only regenerate icons when we need them to be updated! This is the main saving for this system. + +In practice this means that: + everytime you fall over, we just switch between precompiled lists. Which is fast and cheap. + Everytime you do something minor like take a pen out of your pocket, we only update the in-hand overlay + etc... + + +There are several things that need to be remembered: + +> Whenever we do something that should cause an overlay to update (which doesn't use standard procs + ( i.e. you do something like l_hand = /obj/item/something new(src) ) + You will need to call the update_equipment_overlay() proc with the approriate slot flag ie. + update_equipment_overlay(slot_wear_suit_str) + +> There are also these special cases: + update_genetic_conditions() //handles updating your appearance for certain mutations. e.g TK head-glows + update_damage_overlays() //handles damage overlays for brute/burn damage //(will rename this when I geta round to it) + update_body() //Handles updating your mob's icon to reflect their gender/race/complexion etc + update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and + ...eyes were merged into update_body) + +> All of these procs update our overlay lists, and then call update_icon() by default. + If you wish to update several overlays at once, you can set the argument to 0 to disable the update and call + it manually: + e.g. + update_equipment_overlay(slot_head_str, FALSE) + update_inhand_overlays() //<---calls update_icon() + + or equivillantly: + update_equipment_overlay(slot_head_str, FALSE) + update_inhand_overlays(FALSE) + update_icon() + +> If you need to update all overlays you can use try_refresh_visible_overlays(). it works exactly like update_clothing used to. + +> I reimplimented an old unused variable which was in the code called (coincidentally) var/update_icon + It can be used as another method of triggering update_icon(). It's basically a flag that when set to non-zero + will call update_icon() at the next life() call and then reset itself to 0. + The idea behind it is icons are regenerated only once, even if multiple events requested it. + +This system is confusing and is still a WIP. It's primary goal is speeding up the controls of the game whilst +reducing processing costs. So please bear with me while I iron out the kinks. It will be worth it, I promise. +If I can eventually free var/lying stuff from the life() process altogether, stuns/death/status stuff +will become less affected by lag-spikes and will be instantaneous! :3 + +If you have any questions/constructive-comments/bugs-to-report/or have a massivly devestated butt... +Please contact me on #coderbus IRC. ~Carn x +*/ + +/mob/living/human/refresh_visible_overlays() + update_genetic_conditions(FALSE) + update_body(FALSE) + update_skin(FALSE) + update_underwear(FALSE) + update_hair(FALSE) + update_inhand_overlays(FALSE) + update_fire(FALSE) + update_surgery(FALSE) + update_bandages(FALSE) + update_damage_overlays(FALSE) + return ..() + +/mob/living/human/on_update_icon() + if(regenerate_body_icon) + regenerate_body_icon = FALSE + ..() + +/mob/living/human/apply_visible_overlays() + var/list/visible_overlays + var/list/visible_underlays + if(is_cloaked()) + icon = 'icons/mob/human.dmi' + icon_state = "blank" + visible_overlays = get_current_mob_overlay(HO_INHAND_LAYER) + else + icon = stand_icon + icon_state = null + visible_overlays = get_all_current_mob_overlays() + visible_underlays = get_all_current_mob_underlays() + + var/decl/bodytype/root_bodytype = get_bodytype() + // We are somehow updating with no torso, or a torso with no bodytype (probably gibbing). No point continuing. + if(!root_bodytype) + return + + var/matrix/M = matrix() + if(current_posture?.prone && !isnull(root_bodytype.prone_overlay_offset) && (root_bodytype.prone_overlay_offset[1] || root_bodytype.prone_overlay_offset[2])) + M.Translate(root_bodytype.prone_overlay_offset[1], root_bodytype.prone_overlay_offset[2]) + + var/mangle_planes = FALSE + for(var/i = 1 to LAZYLEN(visible_overlays)) + var/entry = visible_overlays[i] + if(istype(entry, /image)) + var/image/overlay = entry + if(i != HO_DAMAGE_LAYER) + overlay.transform = M + add_overlay(entry) + mangle_planes = mangle_planes || overlay.plane >= ABOVE_LIGHTING_PLANE + else if(islist(entry)) + for(var/image/overlay in entry) + if(i != HO_DAMAGE_LAYER) + overlay.transform = M + add_overlay(overlay) + mangle_planes = mangle_planes || overlay.plane >= ABOVE_LIGHTING_PLANE + + if(mangle_planes) + z_flags |= ZMM_MANGLE_PLANES + else + z_flags &= ~ZMM_MANGLE_PLANES + + for(var/i = 1 to LAZYLEN(visible_underlays)) + var/entry = visible_underlays[i] + if(istype(entry, /image)) + var/image/underlay = entry + underlay.transform = M + else if(islist(entry)) + for(var/image/underlay in entry) + underlay.transform = M + underlays = visible_underlays + +/mob/living/proc/get_icon_scale_mult() + // If you want stuff like scaling based on species or something, here is a good spot to mix the numbers together. + return list(icon_scale_x, icon_scale_y) + +/mob/living/human/update_appearance_flags(add_flags, remove_flags) + . = ..() + if(.) + update_icon() + +// Separate and duplicated from human logic due to humans having postures and many overlays. +/mob/living/update_transform() + var/list/icon_scale_values = get_icon_scale_mult() + var/desired_scale_x = icon_scale_values[1] + var/desired_scale_y = icon_scale_values[2] + var/matrix/M = matrix() + M.Scale(desired_scale_x, desired_scale_y) + M.Translate(0, 16 * (desired_scale_y - 1)) + if(transform_animate_time) + animate(src, transform = M, time = transform_animate_time) + else + transform = M + return transform + +/mob/living/human/update_transform() + + // First, get the correct size. + var/list/icon_scale_values = get_icon_scale_mult() + var/desired_scale_x = icon_scale_values[1] + var/desired_scale_y = icon_scale_values[2] + + // Apply KEEP_TOGETHER so all the component overlays move properly when + // applying a transform, or remove it if we aren't doing any transforms + // (due to cost). + if(!current_posture.prone && desired_scale_x == 1 && desired_scale_y == 1 && !("turf_alpha_mask" in filter_data)) + update_appearance_flags(remove_flags = KEEP_TOGETHER) + else + update_appearance_flags(add_flags = KEEP_TOGETHER) + + // Scale/translate/rotate and apply the transform. + var/turn_angle + var/matrix/M = matrix() + M.Scale(desired_scale_x, desired_scale_y) + if(current_posture.prone && get_bodytype()?.rotate_on_prone) + // This locate is very bad but trying to get it to respect the buckled dir is proving tricky. + if((dir & EAST) || (isturf(loc) && (locate(/obj/structure/bed) in loc))) + turn_angle = 90 + else if(dir & WEST) + turn_angle = -90 + else + turn_angle = pick(-90, 90) + M.Turn(turn_angle) + M.Translate(turn_angle == 90 ? 1 : -2, (turn_angle == 90 ? -6 : -5) - default_pixel_z) + else + M.Translate(0, 16 * (desired_scale_y - 1)) + + if(transform_animate_time) + animate(src, transform = M, time = transform_animate_time) + else + transform = M + + var/atom/movable/mask = global._alpha_masks[src] + if(mask) + var/matrix/inverted_transform = matrix() + inverted_transform.Scale(desired_scale_y, desired_scale_x) + if(current_posture.prone) + inverted_transform.Turn(-turn_angle) + inverted_transform.Translate(turn_angle == -90 ? 1 : -2, (turn_angle == -90 ? -6 : -5) - default_pixel_z) + else + inverted_transform.Translate(0, 16 * (desired_scale_y - 1)) + if(transform_animate_time) + animate(mask, transform = inverted_transform, time = transform_animate_time) + else + mask.transform = inverted_transform + + return transform + +/mob/living/human/proc/get_human_icon_cache_key() + . = list() + for(var/limb_tag in global.all_limb_tags) + . += "[limb_tag]_" + var/obj/item/organ/external/part = GET_EXTERNAL_ORGAN(src, limb_tag) + if(isnull(part) || part.skip_body_icon_draw) + . += "skip" + continue + part.update_icon() // This wil regenerate their icon if needed, and more importantly set their cache key. + . += part._icon_cache_key + . += "husked_[!!has_genetic_condition(GENE_COND_HUSK)]" + . = JOINTEXT(.) + +//BASE MOB SPRITE +/mob/living/human/update_body(var/update_icons = TRUE) + + var/list/limbs = get_external_organs() + if(!LAZYLEN(limbs)) + return // Something is trying to update our body pre-init (probably loading a preview image during world startup). + + var/decl/bodytype/root_bodytype = get_bodytype() + var/icon_key = get_human_icon_cache_key() + + stand_icon = global.human_icon_cache[icon_key] + if(!stand_icon) + //BEGIN CACHED ICON GENERATION. + stand_icon = new(root_bodytype.icon_template || 'icons/mob/human.dmi', "blank") + for(var/obj/item/organ/external/part in limbs) + if(isnull(part) || part.skip_body_icon_draw) + continue + var/icon/temp = part.icon + //That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST + //And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part) + if(part.icon_position & (LEFT | RIGHT)) + var/icon/temp2 = icon(root_bodytype.icon_template) + temp2.Insert(new /icon(temp,dir=NORTH),dir=NORTH) + temp2.Insert(new /icon(temp,dir=SOUTH),dir=SOUTH) + if(!(part.icon_position & LEFT)) + temp2.Insert(new /icon(temp,dir=EAST),dir=EAST) + if(!(part.icon_position & RIGHT)) + temp2.Insert(new /icon(temp,dir=WEST),dir=WEST) + stand_icon.Blend(temp2, ICON_OVERLAY) + if(part.icon_position & LEFT) + temp2.Insert(new /icon(temp,dir=EAST),dir=EAST) + if(part.icon_position & RIGHT) + temp2.Insert(new /icon(temp,dir=WEST),dir=WEST) + stand_icon.Blend(temp2, ICON_UNDERLAY) + else if(part.icon_position & UNDER) + stand_icon.Blend(temp, ICON_UNDERLAY) + else + stand_icon.Blend(temp, ICON_OVERLAY) + //Handle husk overlay. + if(has_genetic_condition(GENE_COND_HUSK)) + var/husk_icon = root_bodytype.get_husk_icon(src) + if(husk_icon) + var/icon/mask = new(stand_icon) + var/icon/husk_over = new(husk_icon, "") + mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0) + husk_over.Blend(mask, ICON_ADD) + stand_icon.Blend(husk_over, ICON_OVERLAY) + else + stand_icon.ColorTone("#605850") + global.human_icon_cache[icon_key] = stand_icon + + //tail + update_tail_showing(0) + ..() + +//UNDERWEAR OVERLAY + +/mob/living/human/proc/update_underwear(var/update_icons=1) + var/list/undies_overlays = list() + var/decl/bodytype/root_bodytype = get_bodytype() + if(root_bodytype) + var/list/adjustments = root_bodytype.get_equip_adjustments(src) + for(var/obj/item/underwear/undies as anything in worn_underwear) + if (!undies?.icon) // Avoid runtimes for nude underwear types + continue + var/image/undies_overlay + if(undies.slot_offset_str && (undies.slot_offset_str in adjustments)) + undies_overlay = root_bodytype.get_offset_overlay_image(src, undies.icon, undies.icon_state, undies.color, undies.slot_offset_str) + else + undies_overlay = image(icon = undies.icon, icon_state = undies.icon_state) + undies_overlay.color = undies.color + if(undies_overlay) // get_offset_overlay_image() may potentially return null + undies_overlay.appearance_flags |= RESET_COLOR + undies_overlays += undies_overlay + set_current_mob_overlay(HO_UNDERWEAR_LAYER, undies_overlays, update_icons) + +/mob/living/human/update_hair(var/update_icons=1) + var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD, /obj/item/organ/external/head) + var/list/new_accessories = head_organ?.get_limb_mob_overlays() + set_current_mob_overlay(HO_HAIR_LAYER, new_accessories, update_icons) + +/mob/living/human/proc/update_skin(var/update_icons=1) + // todo: make this use bodytype + set_current_mob_overlay(HO_SKIN_LAYER, species.update_skin(src), update_icons) + +/mob/living/human/update_genetic_conditions(var/update_icons=1) + var/list/condition_overlays = null + for(var/decl/genetic_condition/condition as anything in get_genetic_conditions()) + var/condition_overlay = condition.get_mob_overlay() + if(condition_overlay) + LAZYADD(condition_overlays, condition_overlay) + set_current_mob_overlay(HO_CONDITION_LAYER, condition_overlays, update_icons) + +/mob/living/human/hud_reset(full_reset = FALSE) + if((. = ..())) + refresh_hud_element(HUD_INTERNALS) diff --git a/code/modules/mob/living/human/whisper.dm b/code/modules/mob/living/human/whisper.dm new file mode 100644 index 000000000000..6d7ac0db0ab9 --- /dev/null +++ b/code/modules/mob/living/human/whisper.dm @@ -0,0 +1,28 @@ +//Lallander was here +/mob/living/human/whisper(message as text) + + if(filter_block_message(src, message)) + return + + if (src.client) + if (src.client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot whisper (muted).") + return + + message = sanitize(message, encode = 0) + + if (src.stat == DEAD) + return src.say_dead(message) + + if (src.stat) + return + + if(get_id_name("Unknown") == GetVoice()) + SetName(get_id_name("Unknown")) + + whisper_say(message) + + +//This is used by both the whisper verb and human/say() to handle whispering +/mob/living/human/proc/whisper_say(var/message, var/decl/language/speaking = null, var/verb="whispers") + say(message, speaking, verb, whispering = TRUE) \ No newline at end of file diff --git a/code/modules/mob/living/immunity.dm b/code/modules/mob/living/immunity.dm new file mode 100644 index 000000000000..c51eb25d3097 --- /dev/null +++ b/code/modules/mob/living/immunity.dm @@ -0,0 +1,19 @@ +/mob/living + var/immunity = 100 //current immune system strength + var/immunity_norm = 100 //it will regenerate to this value + +/mob/living/proc/handle_immunity() + if(status_flags & GODMODE) return 0 //godmode + + if(immunity > 0.2 * immunity_norm && immunity < immunity_norm) + adjust_immunity(0.25) + +/mob/living/proc/adjust_immunity(var/amt) + immunity = clamp(immunity + amt, 0, immunity_norm) + +/mob/living/proc/get_immunity() + var/antibiotic_boost = REAGENT_VOLUME(reagents, /decl/material/liquid/antibiotics) / (REAGENTS_OVERDOSE/2) + return max(immunity/100 * (1+antibiotic_boost), antibiotic_boost) + +/mob/living/proc/immunity_weakness() + return max(2-get_immunity(), 0) diff --git a/code/modules/mob/living/internals.dm b/code/modules/mob/living/internals.dm new file mode 100644 index 000000000000..ea0e20e3e050 --- /dev/null +++ b/code/modules/mob/living/internals.dm @@ -0,0 +1,119 @@ +/mob/living/set_internals(obj/item/tank/source, source_string) + var/old_internal = get_internals() + if(!old_internal && source) + if(!source_string) + source_string = source.name + to_chat(src, SPAN_NOTICE("You are now running on internals from \the [source_string].")) + playsound(src, 'sound/effects/internals.ogg', 50, 0) + if(old_internal && !source) + to_chat(src, SPAN_NOTICE("You are no longer running on internals.")) + +// Set internals on or off. +/mob/living/toggle_internals(var/mob/living/user) + + var/atom/movable/internal = get_internals() + if(internal) + visible_message(SPAN_NOTICE("\The [user] disables \the [src]'s internals!")) + internal.add_fingerprint(user) + set_internals(null) + return + + // Check for airtight mask/helmet. + if(!check_for_airtight_internals(FALSE)) + to_chat(user, SPAN_WARNING("\The [src] does not have a suitable mask or helmet.")) + return + + // Find an internal source. + var/list/possible_sources = get_possible_internals_sources() + for(var/slot in possible_sources) + var/list/source_info = possible_sources[slot] + if(length(source_info) < 2) + continue + var/obj/item/tank/tank = source_info[1] + if(istype(tank)) + set_internals(tank) + visible_message(SPAN_NOTICE("\The [src] is now running on internals!")) + internal.add_fingerprint(user) + return + + to_chat(user, SPAN_WARNING("You could not find a suitable tank!")) + +/mob/living/proc/breathing_hole_covered() + var/obj/item/mask = get_equipped_item(slot_wear_mask_str) + . = (mask?.item_flags & ITEM_FLAG_AIRTIGHT) + +/mob/living/proc/get_possible_internals_sources() + . = get_equipped_internals_sources() + for(var/slot in get_held_item_slots()) + var/obj/item/tank/checking = get_equipped_item(slot) + if(istype(checking)) + .[parse_zone(slot)] = list(checking, "in") + +/mob/living/proc/get_equipped_internals_sources() + . = list( + "back" = list(get_equipped_item(slot_back_str), "on"), + "suit" = list(get_equipped_item(slot_s_store_str), "on"), + "belt" = list(get_equipped_item(slot_belt_str), "on"), + "left pocket" = list(get_equipped_item(slot_l_store_str), "in"), + "right pocket" = list(get_equipped_item(slot_r_store_str), "in"), + "rig" = list(get_rig()?.air_supply, "in") + ) + +/mob/living/proc/set_internals_to_best_available_tank(var/breathes_gas = /decl/material/gas/oxygen, var/list/poison_gas = list(/decl/material/gas/chlorine)) + + if(!ispath(breathes_gas)) + return + + var/list/possible_sources = get_possible_internals_sources() + var/selected_slot + var/selected_from + var/obj/item/tank/selected_obj + var/decl/material/breathing_gas = GET_DECL(breathes_gas) + for(var/slot_name in possible_sources) + var/list/checking_data = possible_sources[slot_name] + if(length(checking_data) < 2) + continue + var/obj/item/tank/checking = checking_data[1] + if(!istype(checking) || !checking.air_contents?.gas) + continue + + var/valid_tank = (checking.manipulated_by && checking.manipulated_by != real_name && findtext(checking.desc, breathing_gas.name)) + if(!valid_tank) + if(!checking.air_contents.gas[breathes_gas]) + continue + var/is_poison = FALSE + for(var/poison in poison_gas) + if(checking.air_contents.gas[poison]) + is_poison = TRUE + break + if(!is_poison) + valid_tank = TRUE + + if(valid_tank && (!selected_obj || selected_obj.air_contents.gas[breathes_gas] < checking.air_contents.gas[breathes_gas])) + selected_obj = checking + selected_slot = slot_name + selected_from = checking_data[2] + + if(selected_obj) + if(selected_slot && selected_from) + set_internals(selected_obj, "\the [selected_obj] [selected_from] your [selected_slot]") + else + set_internals(selected_obj, "\the [selected_obj]") + +/mob/living/proc/ui_toggle_internals() + + if(incapacitated()) + return + + if(get_internals()) + set_internals(null) + return + + if(!breathing_hole_covered()) + to_chat(src, SPAN_WARNING("You are not wearing a suitable mask or helmet.")) + return + + set_internals_to_best_available_tank() + + if(!get_internals()) + to_chat(src, SPAN_WARNING("You don't have a tank that is usable as internals.")) diff --git a/code/modules/mob/living/inventory.dm b/code/modules/mob/living/inventory.dm new file mode 100644 index 000000000000..c4cc217a30e2 --- /dev/null +++ b/code/modules/mob/living/inventory.dm @@ -0,0 +1,217 @@ +/mob/living + var/_held_item_slot_selected + var/list/_held_item_slots + var/list/_inventory_slots + var/list/_inventory_slot_priority + var/pending_hand_rebuild + +/mob/living/get_inventory_slots() + return _inventory_slots + +/mob/living/get_inventory_slot_priorities() + if(!_inventory_slot_priority) + _inventory_slot_priority = list() + var/list/all_slots = list() + for(var/slot in get_inventory_slots()) + all_slots += get_inventory_slot_datum(slot) + var/list/low_priority_slots // Slots that will always be added at the end, in the order of their parent slots' priority. + // This is sort of due to technical limitations but mostly due to laziness. + for(var/datum/inventory_slot/inv_slot as anything in sortTim(all_slots, /proc/cmp_inventory_slot_desc)) + if(LAZYLEN(inv_slot.additional_quick_equip_slots)) + for(var/extra_slot in inv_slot.additional_quick_equip_slots) + LAZYADD(low_priority_slots, extra_slot) + if(isnull(inv_slot.quick_equip_priority)) // Never quick-equip into some slots. + continue + _inventory_slot_priority += inv_slot.slot_id + if(low_priority_slots) + _inventory_slot_priority += low_priority_slots + return _inventory_slot_priority + +/mob/living/get_inventory_slot_datum(var/slot) + return LAZYACCESS(_inventory_slots, slot) + +/mob/living/get_held_item_slots() + return _held_item_slots + +/mob/living/get_all_available_equipment_slots() + . = ..() + var/decl/species/my_species = get_species() + if(istype(my_species?.species_hud)) + for(var/slot in my_species.species_hud.equip_slots) + LAZYDISTINCTADD(., slot) + +/mob/living/add_held_item_slot(var/datum/inventory_slot/held_slot) + has_had_gripper = TRUE + var/datum/inventory_slot/existing_slot = get_inventory_slot_datum(held_slot.slot_id) + if(existing_slot && existing_slot != held_slot) + var/held = existing_slot.get_equipped_item() + held_slot.set_slot(held) + existing_slot.clear_slot() + qdel(existing_slot) + LAZYDISTINCTADD(_held_item_slots, held_slot.slot_id) + add_inventory_slot(held_slot) + if(!get_active_held_item_slot()) + select_held_item_slot(held_slot.slot_id) + queue_hand_rebuild() + +/mob/living/remove_held_item_slot(var/slot) + var/datum/inventory_slot/inv_slot = istype(slot, /datum/inventory_slot) ? slot : get_inventory_slot_datum(slot) + if(inv_slot) + LAZYREMOVE(_held_item_slots, inv_slot.slot_id) + remove_inventory_slot(inv_slot) + var/held_slots = get_held_item_slots() + if(!get_active_held_item_slot() && length(held_slots)) + select_held_item_slot(held_slots[1]) + queue_hand_rebuild() + +/mob/living/select_held_item_slot(var/slot) + . = ..() + var/last_slot = get_active_held_item_slot() + if(slot != last_slot && (slot in get_held_item_slots())) + _held_item_slot_selected = slot + if(istype(hud_used)) + hud_used.update_hand_elements() + var/obj/item/I = get_active_held_item() + if(istype(I)) + I.on_active_hand() + +// Defer proc for the sake of delimbing root limbs with multiple graspers (serpentid) +/mob/living/proc/queue_hand_rebuild() + set waitfor = FALSE + if(!pending_hand_rebuild) + pending_hand_rebuild = TRUE + sleep(1) + pending_hand_rebuild = FALSE + if(istype(hud_used)) + hud_used.rebuild_hands() + +/mob/living/get_active_held_item() + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(get_active_held_item_slot()) + return inv_slot?.get_equipped_item() + +/mob/living/get_active_held_item_slot() + . = _held_item_slot_selected + if(. && !(. in get_held_item_slots())) + _held_item_slot_selected = null + . = null + +/mob/living/get_inactive_held_items() + for(var/hand_slot in (get_held_item_slots() - get_active_held_item_slot())) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + var/obj/item/thing = inv_slot?.get_equipped_item() + if(istype(thing)) + LAZYADD(., thing) + +/mob/living/is_holding_offhand(var/thing) + . = (thing in get_inactive_held_items()) + +/mob/living/swap_hand() + . = ..() + var/held_slots = get_held_item_slots() + if(length(held_slots)) + select_held_item_slot(next_in_list(get_active_held_item_slot(), held_slots)) + +/mob/living/get_empty_hand_slot() + for(var/hand_slot in get_held_item_slots()) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + if(!inv_slot?.get_equipped_item()) + return hand_slot + +/mob/living/get_empty_hand_slots() + for(var/hand_slot in get_held_item_slots()) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + if(!inv_slot?.get_equipped_item()) + LAZYADD(., hand_slot) + +/mob/living/drop_from_slot(slot_id, atom/new_loc) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(slot_id) + var/held = inv_slot?.get_equipped_item() + if(held) + return drop_from_inventory(held, new_loc) + . = ..() + +/mob/living/set_inventory_slots(var/list/new_slots) + + var/list/old_slots = _inventory_slots + _inventory_slot_priority = null + _inventory_slots = null + + // Keep held item slots. + if(LAZYLEN(old_slots)) + for(var/slot in get_held_item_slots()) + if(slot in old_slots) + LAZYSET(_inventory_slots, slot, old_slots[slot]) + old_slots -= slot + + // Check if we need to replace any existing slots. + for(var/new_slot_id in new_slots) + var/datum/inventory_slot/new_slot = new_slots[new_slot_id] + var/datum/inventory_slot/old_slot = LAZYACCESS(old_slots, new_slot_id) + if(old_slot) + if(old_slot != new_slot) + // Transfer the item from the old slot to the new slot + new_slot.set_slot(old_slot.get_equipped_item()) + old_slot.clear_slot() + qdel(old_slot) + + old_slots -= new_slot_id + + LAZYSET(_inventory_slots, new_slot.slot_id, new_slot) + + // For any old slots which had no equivalent, drop the item into the world + for(var/old_slot_id in old_slots) + drop_from_slot(old_slot_id) + var/datum/inventory_slot/old_slot = old_slots[old_slot_id] + old_slot.clear_slot() // Call this manually since it is no longer in _inventory_slots + qdel(old_slot) + +/mob/living/add_inventory_slot(var/datum/inventory_slot/inv_slot) + _inventory_slot_priority = null + LAZYSET(_inventory_slots, inv_slot.slot_id, inv_slot) + +/mob/living/remove_inventory_slot(var/slot) + _inventory_slot_priority = null + var/datum/inventory_slot/inv_slot = istype(slot, /datum/inventory_slot) ? slot : LAZYACCESS(_inventory_slots, slot) + if(inv_slot) + var/held = inv_slot.get_equipped_item() + if(held) + drop_from_inventory(held) + qdel(inv_slot) + LAZYREMOVE(_inventory_slots, inv_slot.slot_id) + +/mob/living/proc/get_jetpack() + var/obj/item/tank/jetpack/thrust = get_equipped_item(slot_back_str) + if(istype(thrust)) + return thrust + if(istype(thrust, /obj/item/rig)) + var/obj/item/rig/rig = thrust + for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules) + return module.jets + thrust = get_equipped_item(slot_s_store_str) + if(istype(thrust)) + return thrust + return null + +/mob/living/verb/quick_equip() + set name = "quick-equip" + set hidden = 1 + var/obj/item/I = get_active_held_item() + if(!I) + to_chat(src, SPAN_WARNING("You are not holding anything to equip.")) + return + if(!equip_to_appropriate_slot(I)) + to_chat(src, SPAN_WARNING("You are unable to equip that.")) + +/mob/living/proc/equip_in_one_of_slots(obj/item/prop, list/slots, del_on_fail = 1) + for (var/slot in slots) + if (equip_to_slot_if_possible(prop, slots[slot], del_on_fail = 0)) + return slot + if (del_on_fail) + qdel(prop) + return null + +//Same as get_covering_equipped_items, but using target zone instead of bodyparts flags +/mob/living/proc/get_covering_equipped_item_by_zone(var/zone) + var/obj/item/organ/external/O = GET_EXTERNAL_ORGAN(src, zone) + if(O) + return get_covering_equipped_item(O.body_part) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 55cee1a5c3c4..52d3b884092a 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -1,172 +1,503 @@ /mob/living/Life() - set invisibility = 0 - set background = BACKGROUND_ENABLED + set invisibility = FALSE ..() - if (HasMovementHandler(/datum/movement_handler/mob/transformation/)) + if (HasMovementHandler(/datum/movement_handler/mob/transformation)) return - if (!loc) + + // update the current life tick, can be used to e.g. only do something every 4 ticks + // This is handled before the loc check as unit tests use this to delay until the mob + // has processed a few times. Not really sure why but heigh ho. + life_tick++ + + if(!loc) return - if(machine && !CanMouseDrop(machine, src)) + if(machine && (machine.CanUseTopic(src, machine.DefaultTopicState()) == STATUS_CLOSE)) // unsure if this is a good idea, but using canmousedrop was ??? machine = null - //Handle temperature/pressure differences between body and environment - var/datum/gas_mixture/environment = loc.return_air() - if(environment) - handle_environment(environment) + CLEAR_HUD_ALERTS(src) // These will be set again in the various update procs below. + handle_hud_glasses() // Clear HUD overlay images. Done early so that organs, etc. can add them back. - blinded = 0 // Placing this here just show how out of place it is. - // human/handle_regular_status_updates() needs a cleanup, as blindness should be handled in handle_disabilities() + //Handle temperature/pressure differences between body and environment + handle_environment(loc.return_air()) + if(QDELETED(src)) // Destroyed by fire or pressure damage in handle_environment() + return PROCESS_KILL handle_regular_status_updates() // Status & health update, are we dead or alive etc. - if(stat != DEAD) - aura_check(AURA_TYPE_LIFE) + if(stat != DEAD && !has_mob_modifier(/decl/mob_modifier/stasis)) + . = handle_living_non_stasis_processes() + + for(var/obj/item/grab/grab as anything in get_active_grabs()) + grab.Process() //Check if we're on fire handle_fire() - - for(var/obj/item/grab/G in get_active_grabs()) - G.Process() - handle_actions() - - UpdateLyingBuckledAndVerbStatus() - + update_posture() + handle_grasp() + handle_stance() handle_regular_hud_updates() - + handle_status_conditions() + handle_mob_modifiers() return 1 -/mob/living/proc/handle_breathing() - return +/mob/living/proc/handle_grasp() + for(var/hand_slot in get_held_item_slots()) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + if(!inv_slot?.requires_organ_tag) + continue + var/holding = inv_slot?.get_equipped_item() + if(holding) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, inv_slot.requires_organ_tag) + if((!E || !E.is_usable() || E.is_parent_dislocated()) && try_unequip(holding)) + grasp_damage_disarm(E) + +/mob/living/proc/grasp_damage_disarm(var/obj/item/organ/external/affected) + + var/list/drop_held_item_slots + if(istype(affected)) + for(var/grasp_tag in (list(affected.organ_tag) | affected.children)) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(grasp_tag) + if(inv_slot?.get_equipped_item()) + LAZYDISTINCTADD(drop_held_item_slots, inv_slot) + else if(istype(affected, /datum/inventory_slot)) + drop_held_item_slots = list(affected) + + if(!LAZYLEN(drop_held_item_slots)) + return + for(var/datum/inventory_slot/inv_slot in drop_held_item_slots) + if(!try_unequip(inv_slot.get_equipped_item())) + continue + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, inv_slot.slot_id) + if(!E) + continue + if(E.is_robotic()) + var/decl/pronouns/pronouns = get_pronouns() + visible_message("\The [src] drops what [pronouns.he] [pronouns.is] holding, [pronouns.his] [E.name] malfunctioning!") + spark_at(src, 5, holder=src) + continue + + var/grasp_name = E.name + if((E.body_part in list(SLOT_ARM_LEFT, SLOT_ARM_RIGHT)) && LAZYLEN(E.children)) + var/obj/item/organ/external/hand = pick(E.children) + grasp_name = hand.name + + if(E.can_feel_pain()) + var/emote_scream = pick("screams in pain", "lets out a sharp cry", "cries out") + var/emote_scream_alt = pick("scream in pain", "let out a sharp cry", "cry out") + visible_message( + "\The [src] [emote_scream] and drops what they were holding in their [grasp_name]!", + null, + "You hear someone [emote_scream_alt]!" + ) + custom_pain("The sharp pain in your [E.name] forces you to drop what you were holding in your [grasp_name]!", 30) + else + visible_message("\The [src] drops what they were holding in their [grasp_name]!") + +/mob/living/proc/handle_living_non_stasis_processes() + SHOULD_CALL_PARENT(TRUE) + // hungy + handle_nutrition_and_hydration() + // Breathing, if applicable + handle_breathing() + // Mutations and radiation + handle_mutations_and_radiation() + // Chemicals in the body + handle_chemicals_in_body() + // Random events (vomiting etc) + handle_random_events() + // eye, ear, brain damages + handle_disabilities() + // Immune system updates (currently vestigal) + handle_immunity() + // Allergic reactions/anaphylaxis + handle_allergens() + // Body temperature adjusts itself (self-regulation) + stabilize_body_temperature() + return TRUE + +/mob/living/proc/experiences_hunger_and_thirst() + return !isSynthetic() // Doesn't really apply to robots. Maybe unify this with cells in the future. + +/mob/living/proc/get_hunger_factor() + var/decl/species/my_species = get_species() + if(my_species) + return my_species.hunger_factor + return 0 + +/mob/living/proc/get_thirst_factor() + var/decl/species/my_species = get_species() + if(my_species) + return my_species.thirst_factor + return 0 + +/mob/living/proc/handle_nutrition_and_hydration() + SHOULD_CALL_PARENT(TRUE) + if(!experiences_hunger_and_thirst()) + return + if(get_nutrition() > 0) + var/hunger_factor = get_hunger_factor() + if(hunger_factor) + adjust_nutrition(-(hunger_factor)) + if(get_hydration() > 0) + var/thirst_factor = get_thirst_factor() + if(thirst_factor) + adjust_hydration(-(thirst_factor)) + +#define RADIATION_SPEED_COEFFICIENT 0.025 /mob/living/proc/handle_mutations_and_radiation() - return + SHOULD_CALL_PARENT(TRUE) + + radiation = clamp(radiation,0,500) + var/decl/bodytype/my_bodytype = get_bodytype() + if(my_bodytype?.appearance_flags & RADIATION_GLOWS) + if(radiation) + set_light(max(1,min(10,radiation/10)), max(1,min(20,radiation/20)), get_flesh_color()) + else + set_light(0) + + if(radiation <= 0) + return + + var/damage = 0 + radiation -= 1 * RADIATION_SPEED_COEFFICIENT + if(prob(25)) + damage = 2 + + if (radiation > 50) + damage = 2 + radiation -= 2 * RADIATION_SPEED_COEFFICIENT + if(!isSynthetic()) + if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT)) + radiation -= 5 * RADIATION_SPEED_COEFFICIENT + to_chat(src, "You feel weak.") + SET_STATUS_MAX(src, STAT_WEAK, 3) + if(!current_posture.prone) + emote(/decl/emote/visible/collapse) + if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT)) + lose_hair() + + if (radiation > 75) + damage = 3 + radiation -= 3 * RADIATION_SPEED_COEFFICIENT + if(!isSynthetic()) + if(prob(5)) + take_overall_damage(0, 5 * RADIATION_SPEED_COEFFICIENT, used_weapon = "Radiation Burns") + if(prob(1)) + to_chat(src, "You feel strange!") + take_damage(5 * RADIATION_SPEED_COEFFICIENT, CLONE) + emote(/decl/emote/audible/gasp) + if(radiation > 150) + damage = 8 + radiation -= 4 * RADIATION_SPEED_COEFFICIENT + + var/decl/species/my_species = get_species() + damage = floor(damage * (my_species ? my_species.get_radiation_mod(src) : 1)) + if(damage) + immunity = max(0, immunity - damage * 15 * RADIATION_SPEED_COEFFICIENT) + take_damage(damage * RADIATION_SPEED_COEFFICIENT, TOX) + var/list/limbs = get_external_organs() + if(!isSynthetic() && LAZYLEN(limbs)) + var/obj/item/organ/external/O = pick(limbs) + if(istype(O)) + O.add_autopsy_data("Radiation Poisoning", damage) + +#undef RADIATION_SPEED_COEFFICIENT + +// Get valid, unique reagent holders for metabolizing. Avoids metabolizing the same holder twice in a tick. +/mob/living/proc/get_unique_metabolizing_reagent_holders() + for(var/datum/reagents/metabolism/holder in list(get_contact_reagents(), get_ingested_reagents(), get_injected_reagents(), get_inhaled_reagents())) + LAZYDISTINCTADD(., holder) /mob/living/proc/handle_chemicals_in_body() - return + SHOULD_CALL_PARENT(TRUE) + chem_effects = null + + // TODO: handle isSynthetic() properly via Psi's metabolism modifiers for contact reagents like acid. + if((status_flags & GODMODE) || isSynthetic()) + return FALSE + + // Metabolize any reagents currently in our body and keep a reference for chem dose checking. + var/list/metabolizing_holders = get_unique_metabolizing_reagent_holders() + if(length(metabolizing_holders)) + var/list/tick_dosage_tracker = list() // Used to check if we're overdosing on anything. + for(var/datum/reagents/metabolism/holder as anything in metabolizing_holders) + holder.metabolize(tick_dosage_tracker) + // Check for overdosing. + var/size_modifier = (MOB_SIZE_MEDIUM / mob_size) + for(var/decl/material/R as anything in tick_dosage_tracker) + if(tick_dosage_tracker[R] > (R.overdose * ((R.flags & IGNORE_MOB_SIZE) ? 1 : size_modifier))) + R.affect_overdose(src, tick_dosage_tracker[R]) + + // Update chem dosage. + // TODO: refactor chem dosage above isSynthetic() and GODMODE checks. + if(length(_chem_doses)) + for(var/decl/material/reagent as anything in _chem_doses) + + var/still_processing_reagent = FALSE + for(var/datum/reagents/holder as anything in metabolizing_holders) + if(holder.has_reagent(reagent)) + still_processing_reagent = TRUE + break + if(still_processing_reagent) + continue + var/amount_removed = get_adjusted_metabolism(reagent.metabolism*2) // reagents metabolize out twice as fast as they metabolize in + if(!(reagent.flags & IGNORE_MOB_SIZE)) + amount_removed *= (MOB_SIZE_MEDIUM/mob_size) + var/dose = CHEM_DOSE(src, reagent) - amount_removed + if(dose <= 0) + LAZYREMOVE(_chem_doses, reagent) + else + LAZYSET(_chem_doses, reagent, dose) + if(apply_chemical_effects()) + update_health() + + return TRUE + +/mob/living/proc/apply_chemical_effects() + var/burn_regen = GET_CHEMICAL_EFFECT(src, CE_REGEN_BURN) + var/brute_regen = GET_CHEMICAL_EFFECT(src, CE_REGEN_BRUTE) + if(burn_regen || brute_regen) + heal_organ_damage(brute_regen, burn_regen, FALSE) // apply_chemical_effects() calls update_health() if it returns true; don't do it unnecessarily. + return TRUE + return FALSE /mob/living/proc/handle_random_events() return +/mob/living/proc/handle_contact_reagent_dripping() + // TODO: process dripping outside of Life() so corpses don't become sponges. + // TODO: factor temperature and vapor into this so warmer locations dry you off. + // TODO: apply a dripping overlay a la fire to show someone is saturated. + if(!loc) + return + var/datum/reagents/touching_reagents = get_contact_reagents() + if(REAGENT_TOTAL_VOLUME(touching_reagents) <= FLUID_MINIMUM_TRANSFER) + touching_reagents?.clear_reagents() + return + var/drip_amount = max(FLUID_MINIMUM_TRANSFER, round(REAGENT_TOTAL_VOLUME(touching_reagents) * 0.2)) + if(drip_amount) + touching_reagents.trans_to(loc, drip_amount) + +/mob/living/process_weather(obj/abstract/weather_system/weather, decl/state/weather/weather_state) + // Handle physical effects of weather. Ambience is handled in handle_environment with a + // client check as mobs with no clients don't need to handle ambient messages and sounds. + weather_state?.handle_exposure(src, get_weather_exposure(weather), weather) + +/mob/living/proc/handle_weather_ambience(obj/abstract/weather_system/weather) + // Refresh weather ambience. + // Show messages and play ambience. + if(!istype(weather) || !client) + return + + // Send strings if we're outside. + if(is_outside() && !weather.show_weather(src)) + weather.show_wind(src) + + if(get_preference_value(/datum/client_preference/play_ambiance) == PREF_NO) + return + + // Work out if we need to change or cancel the current ambience sound. + var/send_sound + var/mob_ref = weakref(src) + var/decl/state/weather/weather_state = weather.weather_system.current_state + if(istype(weather_state)) + var/ambient_sounds = !is_outside() ? weather_state.ambient_indoors_sounds : weather_state.ambient_sounds + var/ambient_sound = length(ambient_sounds) && pick(ambient_sounds) + if(global.current_mob_ambience[mob_ref] == ambient_sound) + return + send_sound = ambient_sound + global.current_mob_ambience[mob_ref] = send_sound + else if(mob_ref in global.current_mob_ambience) + global.current_mob_ambience -= mob_ref + else + return + + // Push sound to client. Pipe dream TODO: crossfade between the new and old weather ambience. + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 0, channel = sound_channels.weather_channel)) + if(send_sound) + sound_to(src, sound(send_sound, repeat = TRUE, wait = 0, volume = 60, channel = sound_channels.weather_channel)) + /mob/living/proc/handle_environment(var/datum/gas_mixture/environment) - return + SHOULD_CALL_PARENT(TRUE) + handle_contact_reagent_dripping() // See comment on proc definition + handle_weather_ambience(get_affecting_weather()) //This updates the health and status of the mob (conscious, unconscious, dead) /mob/living/proc/handle_regular_status_updates() - updatehealth() - if(stat != DEAD) - if(paralysis) - set_stat(UNCONSCIOUS) - else if (status_flags & FAKEDEATH) - set_stat(UNCONSCIOUS) - else - set_stat(CONSCIOUS) - return 1 - -/mob/living/proc/handle_statuses() - handle_stunned() - handle_weakened() - handle_paralysed() - handle_stuttering() - handle_silent() - handle_drugged() - handle_slurring() - handle_confused() - -/mob/living/proc/handle_stunned() - if(stunned) - AdjustStunned(-1) - if(!stunned) - update_icons() - return stunned - -/mob/living/proc/handle_weakened() - if(weakened) - weakened = max(weakened-1,0) - if(!weakened) - update_icons() - return weakened - -/mob/living/proc/handle_stuttering() - if(stuttering) - stuttering = max(stuttering-1, 0) - return stuttering - -/mob/living/proc/handle_silent() - if(silent) - silent = max(silent-1, 0) - return silent - -/mob/living/proc/handle_drugged() - return adjust_drugged(-1) - -/mob/living/proc/handle_slurring() - if(slurring) - slurring = max(slurring-1, 0) - return slurring - -/mob/living/proc/handle_paralysed() - if(paralysis) - AdjustParalysis(-1) - if(!paralysis) - update_icons() - return paralysis + + SHOULD_CALL_PARENT(TRUE) + + // Check if we are (or should be) dead at this point. + update_health() + + if(!handle_some_updates()) + return FALSE + + // Godmode just skips most of this processing. + if(status_flags & GODMODE) + set_stat(CONSCIOUS) + germ_level = 0 + return TRUE + + // TODO: move hallucinations into a status condition decl. + if(hallucination_power) + handle_hallucinations() + + // Increase germ_level regularly + if(germ_level < GERM_LEVEL_AMBIENT && prob(30)) //if you're just standing there, you shouldn't get more germs beyond an ambient level + germ_level++ + // If you're dirty, your gloves will become dirty, too. + var/obj/item/gloves = get_equipped_item(slot_gloves_str) + if(gloves && germ_level > gloves.germ_level && prob(10)) + gloves.germ_level++ + + // If we're dead, don't continue further. + if(stat == DEAD) + return FALSE + + // Should we be asleep? + var/decl/species/my_species = get_species() + if(player_triggered_sleeping || (ssd_check() && my_species?.get_ssd(src))) + SET_STATUS_MAX(src, STAT_ASLEEP, 2) + + // Handle some general state updates. + if(HAS_STATUS(src, STAT_PARA)) + set_stat(UNCONSCIOUS) + else if (status_flags & FAKEDEATH) + set_stat(UNCONSCIOUS) + else + set_stat(CONSCIOUS) + + update_furniture_comfort() + return TRUE + +/mob/living + var/furniture_comfort_time + +/mob/living/proc/update_furniture_comfort() + + if(!istype(buckled, /obj/structure)) + furniture_comfort_time = null + return + + var/obj/structure/struct = buckled + if(abs(struct.user_comfort) < 0.5) + furniture_comfort_time = null + return + + var/list/remove_stressors = list( + /datum/stressor/comfortable_very, + /datum/stressor/comfortable, + /datum/stressor/uncomfortable_very, + /datum/stressor/uncomfortable + ) + var/keep_stressor + switch(struct.user_comfort) + if(1 to INFINITY) + keep_stressor = /datum/stressor/comfortable_very + if(0.5 to 1) + keep_stressor = /datum/stressor/comfortable + if(-1 to -0.5) + keep_stressor = /datum/stressor/uncomfortable + if(-(INFINITY) to -1) + keep_stressor = /datum/stressor/uncomfortable_very + + if(keep_stressor) + for(var/stressor in remove_stressors) + if(stressor == keep_stressor) + continue + remove_stressor(stressor) + add_stressor(keep_stressor, 5 SECONDS) + + var/effective_comfort = struct.user_comfort + if(locate(/obj/item/bedsheet) in loc) + effective_comfort += 0.3 + if(effective_comfort > 0 && HAS_STATUS(src, STAT_ASLEEP)) + if(isnull(furniture_comfort_time)) + furniture_comfort_time = world.time + else if((world.time - furniture_comfort_time) > clamp((30 SECONDS) - ((15 SECONDS) * effective_comfort), 0, 30 SECONDS)) + remove_stressor(/datum/stressor/fatigued) + add_stressor(/datum/stressor/well_rested, 30 MINUTES) /mob/living/proc/handle_disabilities() handle_impaired_vision() handle_impaired_hearing() -/mob/living/proc/handle_confused() - if(confused) - confused = max(0, confused - 1) - return confused - /mob/living/proc/handle_impaired_vision() - //Eyes - if(sdisabilities & BLINDED || stat) //blindness from disability or unconsciousness doesn't get better on its own - eye_blind = max(eye_blind, 1) - else if(eye_blind) //blindness, heals slowly over time - eye_blind = max(eye_blind-1,0) - else if(eye_blurry) //blurry eyes heal slowly - eye_blurry = max(eye_blurry-1, 0) + SHOULD_CALL_PARENT(TRUE) + if(stat == DEAD) + SET_STATUS_MAX(src, STAT_BLIND, 0) + if(stat != CONSCIOUS && has_genetic_condition(GENE_COND_BLINDED)) //blindness from disability or unconsciousness doesn't get better on its own + SET_STATUS_MAX(src, STAT_BLIND, 2) + else + return TRUE + return FALSE /mob/living/proc/handle_impaired_hearing() - //Ears - if(sdisabilities & DEAFENED) //disabled-deaf, doesn't get better on its own - setEarDamage(null, max(ear_deaf, 1)) - else if(ear_damage < 25) - adjustEarDamage(-0.05, -1) // having ear damage impairs the recovery of ear_deaf - else if(ear_damage < 100) - adjustEarDamage(-0.05, 0) // deafness recovers slowly over time, unless ear_damage is over 100. TODO meds that heal ear_damage + if(has_genetic_condition(GENE_COND_DEAFENED) || stat) //disabled-deaf, doesn't get better on its own + SET_STATUS_MAX(src, STAT_TINNITUS, 2) +/mob/living/proc/should_do_hud_updates() + return client //this handles hud updates. Calls update_vision() and handle_hud_icons() /mob/living/proc/handle_regular_hud_updates() - if(!client) return 0 + + SHOULD_CALL_PARENT(TRUE) + if(!should_do_hud_updates()) + return FALSE + + if(istype(hud_used)) + hud_used.handle_life_hud_update() handle_hud_icons() handle_vision() + handle_low_light_vision() + return TRUE - return 1 +/mob/living/proc/handle_low_light_vision() + + // No client means nothing to update. + if(!client || !lighting_master) + return + + // No loc or species means we should just assume no adjustment. + var/decl/bodytype/my_bodytype = get_bodytype() + var/turf/my_turf = get_turf(src) + if(!isturf(my_turf) || !my_bodytype) + lighting_master.set_alpha(255) + return + + // TODO: handling for being inside atoms. + var/target_value = 255 * (1-my_bodytype.eye_base_low_light_vision) + var/loc_lumcount = my_turf.get_lumcount() + if(loc_lumcount < my_bodytype.eye_low_light_vision_threshold) + target_value = round(target_value * (1-my_bodytype.eye_low_light_vision_effectiveness)) + + if(lighting_master.alpha == target_value) + return + + var/difference = round((target_value-lighting_master.alpha) * my_bodytype.eye_low_light_vision_adjustment_speed) + if(abs(difference) > 1) + target_value = lighting_master.alpha + difference + lighting_master.set_alpha(target_value) /mob/living/proc/handle_vision() update_sight() - if(stat == DEAD) return - - if(eye_blind) + if(is_blind()) overlay_fullscreen("blind", /obj/screen/fullscreen/blind) else clear_fullscreen("blind") - set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) - set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) - set_fullscreen(drugged, "high", /obj/screen/fullscreen/high) - + set_fullscreen(has_genetic_condition(GENE_COND_NEARSIGHTED), "impaired", /obj/screen/fullscreen/impaired, 1) + set_fullscreen(GET_STATUS(src, STAT_BLURRY), "blurry", /obj/screen/fullscreen/blurry) + set_fullscreen(GET_STATUS(src, STAT_DRUGGY), "high", /obj/screen/fullscreen/high) set_fullscreen(stat == UNCONSCIOUS, "blackout", /obj/screen/fullscreen/blackout) - if(machine) var/viewflags = machine.check_eye(src) if(viewflags < 0) @@ -176,7 +507,7 @@ else if(eyeobj) if(eyeobj.owner != src) reset_view(null) - else if(z_eye) + else if(z_eye) return else if(client && !client.adminobs) reset_view(null) @@ -211,7 +542,153 @@ /mob/living/proc/handle_hud_icons() handle_hud_icons_health() - handle_hud_glasses() /mob/living/proc/handle_hud_icons_health() return + +/mob/living/singularity_act() + if(!simulated) + return 0 + investigate_log("has been consumed by a singularity", "singulo") + gib() + return 20 + +/mob/living/singularity_pull(S, current_size) + if(simulated) + if(current_size >= STAGE_THREE) + for(var/obj/item/hand in get_held_items()) + if(prob(current_size*5) && hand.w_class >= (11-current_size)/2 && try_unequip(hand)) + to_chat(src, SPAN_WARNING("\The [S] pulls \the [hand] from your grip!")) + hand.singularity_pull(S, current_size) + if(prob(current_size*5) && can_slip()) + to_chat(src, SPAN_DANGER("A strong gravitational force slams you to the ground!")) + SET_STATUS_MAX(src, STAT_WEAK, current_size) + apply_damage(current_size * 3, IRRADIATE, damage_flags = DAM_DISPERSED) + return ..() + +/mob/living/proc/handle_stance() + set waitfor = FALSE // Can sleep in emotes. + // Don't need to process any of this if they aren't standing anyways + // unless their stance is damaged, and we want to check if they should stay down + if (!stance_damage && current_posture.prone && (life_tick % 4) != 0) + return + + stance_damage = 0 + + // Buckled to a bed/chair. Stance damage is forced to 0 since they're sitting on something solid + if (istype(buckled, /obj/structure/bed)) + return + + // Can't fall if nothing pulls you down + if(!has_gravity()) + return + + // If we don't have a bodytype, all the limb checking below is going to be nonsensical. + var/decl/bodytype/root_bodytype = get_bodytype() + if(!root_bodytype) + return + + var/expected_limbs_for_bodytype = root_bodytype.get_expected_organ_count_for_categories(global.all_stance_limbs) + if(expected_limbs_for_bodytype <= 0) + return // we don't care about stance for whatever reason. + + // Is there something in our loc we can prop ourselves on? + if(length(loc?.contents)) + for(var/obj/thing in loc.contents) + if(thing.obj_flags & OBJ_FLAG_SUPPORT_MOB) + return + + var/found_limbs = 0 + var/had_limb_pain = FALSE + for(var/obj/item/organ/external/limb in get_organs_by_categories(global.all_stance_limbs)) + found_limbs++ + var/add_stance_damage = 0 + if(limb.is_malfunctioning()) + // malfunctioning only happens intermittently so treat it as a missing limb when it procs + add_stance_damage = LIMB_UNUSABLE + if(prob(10)) + visible_message("\The [src]'s [limb.name] [pick("twitches", "shudders")] and sparks!") + spark_at(src, amount = 5, holder = src) + else if(!limb.is_usable()) + add_stance_damage = LIMB_UNUSABLE + else if (limb.is_broken()) + add_stance_damage = LIMB_DAMAGED + else if (limb.is_dislocated()) + add_stance_damage = LIMB_IMPAIRED + + if(add_stance_damage > 0) + // Keep track of if any of our limbs can feel pain and has failed, + // so we don't scream if it's a prosthetic that has broken. + had_limb_pain = had_limb_pain || limb.can_feel_pain() + stance_damage += add_stance_damage + + // Add missing limbs as unusable. + stance_damage += max(0, expected_limbs_for_bodytype - found_limbs) * LIMB_UNUSABLE + + // Canes and crutches help you stand (if the latter is ever added) + // One cane mitigates a broken leg+foot, or a missing foot. + // Two canes are needed for a lost leg. If you are missing both legs, canes aren't gonna help you. + for(var/obj/item/support in get_held_items()) + var/support_amount = support.get_stance_support_value() + if(support_amount) + stance_damage -= support_amount // Counts for a single functional limb. + + // Calculate the expected and actual number of functioning legs we have. + var/has_sufficient_working_legs = TRUE + var/list/root_limb_tags = root_bodytype.get_expected_organ_tags_for_category(ORGAN_CATEGORY_STANCE_ROOT) + var/minimum_working_legs = ceil(length(root_limb_tags) * 0.5) + if(minimum_working_legs > 0) + var/leg_count = 0 + has_sufficient_working_legs = FALSE + for(var/organ_tag in root_limb_tags) + var/obj/item/organ/external/stance_root = GET_EXTERNAL_ORGAN(src, organ_tag) + if(!stance_root || !stance_root.is_usable()) + continue + if(!length(stance_root.children)) + continue + // In theory a leg may have multiple children in the future; this + // will need to be revisited for fork-legged insect people or whatever. + var/has_usable_child = FALSE + for(var/child_tag in stance_root.children) + var/obj/item/organ/external/stance_child = GET_EXTERNAL_ORGAN(src, child_tag) + if(stance_child?.is_usable()) + has_usable_child = TRUE + break + if(has_usable_child) + leg_count++ + if(leg_count >= minimum_working_legs) + has_sufficient_working_legs = TRUE + break + + // Having half or more of our expected number of working legs allows us to mitigate some stance damage. + if(has_sufficient_working_legs) + if(find_mob_supporting_object()) //it helps to lean on something if you've got another leg to stand on + stance_damage -= LIMB_UNUSABLE + else + stance_damage -= LIMB_DAMAGED + + // standing is poor + if(stance_damage >= expected_limbs_for_bodytype || (!MOVING_DELIBERATELY(src) && ((stance_damage >= (expected_limbs_for_bodytype*0.75) && prob(8)) || (stance_damage >= (expected_limbs_for_bodytype*0.5) && prob(2))))) + if(!current_posture.prone) + if(had_limb_pain) + emote(/decl/emote/audible/scream) + custom_emote(VISIBLE_MESSAGE, "collapses!") + SET_STATUS_MAX(src, STAT_WEAK, 3) //can't emote while weakened, apparently. + +/mob/living/proc/stance_damage_prone(var/obj/item/organ/external/affected) + + if(affected && (!BP_IS_PROSTHETIC(affected) || affected.is_robotic())) + switch(affected.body_part) + if(SLOT_FOOT_LEFT, SLOT_FOOT_RIGHT) + if(!BP_IS_PROSTHETIC(affected)) + to_chat(src, SPAN_WARNING("You lose your footing as your [affected.name] spasms!")) + else + to_chat(src, SPAN_WARNING("You lose your footing as your [affected.name] [pick("twitches", "shudders")]!")) + if(SLOT_LEG_LEFT, SLOT_LEG_RIGHT) + if(!BP_IS_PROSTHETIC(affected)) + to_chat(src, SPAN_WARNING("Your [affected.name] buckles from the shock!")) + else + to_chat(src, SPAN_WARNING("You lose your balance as [affected.name] [pick("malfunctions", "freezes","shudders")]!")) + else + return + SET_STATUS_MAX(src, STAT_WEAK, 4) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 65543fe419f4..24bb4de3f4b9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1,10 +1,35 @@ /mob/living/Initialize() + + if(isnull(current_health) || current_health == INFINITY) + current_health = get_max_health() + + original_fingerprint_seed = sequential_id(/mob) + fingerprint = md5(num2text(original_fingerprint_seed)) + original_genetic_seed = sequential_id(/mob) + unique_enzymes = md5(num2text(original_genetic_seed)) + . = ..() if(stat == DEAD) add_to_dead_mob_list() else add_to_living_mob_list() + if(weather_sensitive) + SSweather_atoms.weather_atoms += src + +/mob/living/get_ai_type() + var/decl/species/my_species = get_species() + if(ispath(my_species?.ai)) + return my_species.ai + return ..() + +/mob/living/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = ..() + if(admin_paralyzed) + . += SPAN_OCCULT("OOC: [pronouns.He] [pronouns.has] been paralyzed by staff. Please avoid interacting with [pronouns.him] unless cleared to do so by staff.") + if(!length(get_external_organs()) && length(embedded)) // fallback for simple embedding used by limbless mobs + . += SPAN_WARNING("[pronouns.He] [pronouns.has] [inline_counting_english_list(embedded, determiners = DET_INDEFINITE)] embedded in [pronouns.him].") + //mob verbs are faster than object verbs. See above. /mob/living/pointed(atom/A as mob|obj|turf in view()) if(incapacitated()) @@ -14,7 +39,7 @@ if(!..()) return 0 - usr.visible_message("[src] points to [A]") + visible_message("[src] points to [A]") return 1 /*one proc, four uses @@ -40,7 +65,7 @@ default behaviour is: if(mob_bump_flag & context_flags) return 1 else - return ((a_intent == I_HELP && swapped.a_intent == I_HELP) && swapped.can_move_mob(src, swapping, 1)) + return ((check_intent(I_FLAG_HELP) && swapped.check_intent(I_FLAG_HELP)) && swapped.can_move_mob(src, swapping, 1)) /mob/living/canface() if(stat) @@ -58,17 +83,17 @@ default behaviour is: // End boilerplate. spawn(0) - if ((!( yes ) || now_pushing) || !loc) + if (!yes || now_pushing || QDELETED(src) || QDELETED(AM) || !loc || !AM.loc) return now_pushing = 1 - if (istype(AM, /mob/living)) + if (isliving(AM)) var/mob/living/tmob = AM for(var/mob/living/M in range(tmob, 1)) - if(tmob.pinned.len || (locate(/obj/item/grab, LAZYLEN(tmob.grabbed_by)))) + if(LAZYLEN(tmob.pinned) || (locate(/obj/item/grab, LAZYLEN(tmob.grabbed_by)))) if ( !(world.time % 5) ) - to_chat(src, "[tmob] is restrained, you cannot push past") + to_chat(src, SPAN_WARNING("[tmob] is restrained, you cannot push past.")) now_pushing = 0 return @@ -77,9 +102,6 @@ default behaviour is: forceMove(tmob.loc) tmob.forceMove(oldloc) now_pushing = 0 - for(var/mob/living/carbon/slime/slime in view(1,tmob)) - if(slime.Victim == tmob) - slime.UpdateFeed() return if(!can_move_mob(tmob, 0, 0)) @@ -88,24 +110,15 @@ default behaviour is: if(src.restrained()) now_pushing = 0 return - if(tmob.a_intent != I_HELP) - if(istype(tmob, /mob/living/carbon/human) && (MUTATION_FAT in tmob.mutations)) - if(prob(40) && !(MUTATION_FAT in src.mutations)) - to_chat(src, "You fail to push [tmob]'s fat ass out of the way.") - now_pushing = 0 - return - if(tmob.r_hand && istype(tmob.r_hand, /obj/item/shield/riot)) - if(prob(99)) - now_pushing = 0 - return - if(tmob.l_hand && istype(tmob.l_hand, /obj/item/shield/riot)) + if(!tmob.check_intent(I_FLAG_HELP)) + for(var/obj/item/shield/riot/shield in tmob.get_held_items()) if(prob(99)) now_pushing = 0 return if(!(tmob.status_flags & CANPUSH)) now_pushing = 0 return - tmob.LAssailant = src + tmob.last_handled_by_mob = weakref(src) if(isobj(AM) && !AM.anchored) var/obj/I = AM if(!can_pull_size || can_pull_size < I.w_class) @@ -115,11 +128,13 @@ default behaviour is: now_pushing = 0 spawn(0) + if (QDELETED(src) || QDELETED(AM) || !loc || !AM.loc) + return ..() var/saved_dir = AM.dir if (!istype(AM, /atom/movable) || AM.anchored) - if(confused && prob(50) && !MOVING_DELIBERATELY(src)) - Weaken(2) + if(HAS_STATUS(src, STAT_CONFUSE) && prob(50) && !MOVING_DELIBERATELY(src)) + SET_STATUS_MAX(src, STAT_WEAK, 2) playsound(loc, "punch", 25, 1, -1) visible_message("[src] [pick("ran", "slammed")] into \the [AM]!") src.apply_damage(5, BRUTE) @@ -132,17 +147,18 @@ default behaviour is: for(var/obj/structure/window/win in get_step(AM,t)) now_pushing = 0 return + AM.glide_size = glide_size step(AM, t) - if (istype(AM, /mob/living)) + if (isliving(AM)) var/mob/living/tmob = AM if(istype(tmob.buckled, /obj/structure/bed)) if(!tmob.buckled.anchored) step(tmob.buckled, t) if(ishuman(AM)) - var/mob/living/carbon/human/M = AM - for(var/obj/item/grab/G in M.grabbed_by) - step(G.assailant, get_dir(G.assailant, AM)) - G.adjust_position() + var/mob/living/human/M = AM + for(var/obj/item/grab/grab as anything in M.grabbed_by) + step(grab.assailant, get_dir(grab.assailant, AM)) + grab.adjust_position() if(saved_dir) AM.set_dir(saved_dir) now_pushing = 0 @@ -163,7 +179,7 @@ default behaviour is: if(tmob.buckled || buckled || tmob.anchored) return 0 //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller - if(!(tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained()))) + if(!(tmob.mob_always_swap || (tmob.check_intent(I_FLAG_HELP) || tmob.restrained()) && (check_intent(I_FLAG_HELP) || src.restrained()))) return 0 if(!tmob.MayMove(src) || incapacitated()) return 0 @@ -178,207 +194,116 @@ default behaviour is: /mob/living/verb/succumb() set hidden = 1 - if ((src.health < src.maxHealth/2)) // Health below half of maxhealth. - src.adjustBrainLoss(src.health + src.maxHealth * 2) // Deal 2x health in BrainLoss damage, as before but variable. - updatehealth() - to_chat(src, "You have given up life and succumbed to death.") + var/current_max_health = get_max_health() + if (current_health < (current_max_health/2)) // Health below half of maxhealth. + take_damage(current_max_health * 2) // Deal 2x health in BrainLoss damage, BRAIN, as before but variable. + to_chat(src, SPAN_NOTICE("You have given up life and succumbed to death.")) + +/mob/living/proc/update_body(var/update_icons=1) + if(update_icons) + queue_icon_update() + +/mob/living/proc/should_be_dead() + return current_health <= 0 + +/mob/living/proc/get_life_damage_types() + var/static/list/life_damage_types = list( + OXY, + TOX, + BURN, + BRUTE, + CLONE, + PAIN + ) + return life_damage_types + +/mob/living/proc/get_total_life_damage() + . = 0 + for(var/damtype in get_life_damage_types()) + . += get_damage(damtype) -/mob/living/proc/updatehealth() - if(status_flags & GODMODE) - health = 100 +/mob/living/update_health() + + . = ..() + if(!.) + current_health = get_max_health() set_stat(CONSCIOUS) - else - health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - getHalLoss() + return + var/current_max_health = get_max_health() + current_health = clamp(current_max_health-get_total_life_damage(), -(current_max_health), current_max_health) + if(stat != DEAD && should_be_dead()) + death() + if(!QDELETED(src)) // death() may delete or remove us + set_status_condition(STAT_BLIND, 1) + set_status_condition(STAT_SILENCE, 0) + return TRUE //This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually //affects them once clothing is factored in. ~Errorage /mob/living/proc/calculate_affecting_pressure(var/pressure) return - -//sort of a legacy burn method for /electrocute, /shock, and the e_chair -/mob/living/proc/burn_skin(burn_amount) - take_overall_damage(0, burn_amount) - -/mob/living/proc/adjustBodyTemp(actual, desired, incrementboost) - var/btemperature = actual - var/difference = abs(actual-desired) //get difference - var/increments = difference/10 //find how many increments apart they are - var/change = increments*incrementboost // Get the amount to change by (x per increment) - - // Too cold - if(actual < desired) - btemperature += change - if(actual > desired) - btemperature = desired - // Too hot - if(actual > desired) - btemperature -= change - if(actual < desired) - btemperature = desired -// if(istype(src, /mob/living/carbon/human)) -// log_debug("[src] ~ [src.bodytemperature] ~ [temperature]") - - return btemperature - -/mob/living/proc/getBruteLoss() - return maxHealth - health - -/mob/living/proc/adjustBruteLoss(var/amount) - if (status_flags & GODMODE) - return - health = Clamp(health - amount, 0, maxHealth) - -/mob/living/proc/getOxyLoss() - return 0 - -/mob/living/proc/adjustOxyLoss(var/amount) - return - -/mob/living/proc/setOxyLoss(var/amount) - return - -/mob/living/proc/getToxLoss() - return 0 - -/mob/living/proc/adjustToxLoss(var/amount) - adjustBruteLoss(amount * 0.5) - -/mob/living/proc/setToxLoss(var/amount) - adjustBruteLoss((amount * 0.5)-getBruteLoss()) - -/mob/living/proc/getFireLoss() - return - -/mob/living/proc/adjustFireLoss(var/amount) - adjustBruteLoss(amount * 0.5) - -/mob/living/proc/setFireLoss(var/amount) - adjustBruteLoss((amount * 0.5)-getBruteLoss()) - -/mob/living/proc/getHalLoss() - return 0 - -/mob/living/proc/adjustHalLoss(var/amount) - adjustBruteLoss(amount * 0.5) - -/mob/living/proc/setHalLoss(var/amount) - adjustBruteLoss((amount * 0.5)-getBruteLoss()) - -/mob/living/proc/getBrainLoss() - return 0 - -/mob/living/proc/adjustBrainLoss(var/amount) - return - -/mob/living/proc/setBrainLoss(var/amount) - return - -/mob/living/proc/getCloneLoss() +/mob/living/proc/increaseBodyTemp(value) return 0 -/mob/living/proc/setCloneLoss(var/amount) - return - -/mob/living/proc/adjustCloneLoss(var/amount) - return - -/mob/living/proc/getMaxHealth() - return maxHealth - -/mob/living/proc/setMaxHealth(var/newMaxHealth) - maxHealth = newMaxHealth +/mob/living/proc/set_max_health(var/val, var/skip_health_update = FALSE) + max_health = val + if(!skip_health_update) + update_health() // ++++ROCKDTBEN++++ MOB PROCS //END -/mob/proc/get_contents() - return - -//Recursive function to find everything a mob is holding. -/mob/living/get_contents(var/obj/item/storage/Storage = null) - var/list/L = list() - - if(Storage) //If it called itself - L += Storage.return_inv() - - //Leave this commented out, it will cause storage items to exponentially add duplicate to the list - //for(var/obj/item/storage/S in Storage.return_inv()) //Check for storage items - // L += get_contents(S) - - for(var/obj/item/gift/G in Storage.return_inv()) //Check for gift-wrapped items - L += G.gift - if(istype(G.gift, /obj/item/storage)) - L += get_contents(G.gift) - - for(var/obj/item/smallDelivery/D in Storage.return_inv()) //Check for package wrapped items - L += D.wrapped - if(istype(D.wrapped, /obj/item/storage)) //this should never happen - L += get_contents(D.wrapped) - return L - - else - - L += src.contents - for(var/obj/item/storage/S in src.contents) //Check for storage items - L += get_contents(S) - - for(var/obj/item/gift/G in src.contents) //Check for gift-wrapped items - L += G.gift - if(istype(G.gift, /obj/item/storage)) - L += get_contents(G.gift) - - for(var/obj/item/smallDelivery/D in src.contents) //Check for package wrapped items - L += D.wrapped - if(istype(D.wrapped, /obj/item/storage)) //this should never happen - L += get_contents(D.wrapped) - return L +/mob/proc/get_mob_contents() -/mob/living/proc/check_contents_for(A) - var/list/L = src.get_contents() + var/list/gear_tree = list() + for(var/obj/item/thing as anything in get_equipped_items(include_carried = TRUE)) + gear_tree |= thing - for(var/obj/B in L) - if(B.type == A) - return 1 - return 0 + while(length(gear_tree)) + var/obj/item/thing = gear_tree[1] + gear_tree -= thing + if(thing in .) + continue + LAZYDISTINCTADD(., thing) + var/list/storage_contents = thing?.storage?.return_inv() + if(length(storage_contents)) + gear_tree |= storage_contents /mob/living/proc/can_inject(var/mob/user, var/target_zone) return 1 /mob/living/proc/get_organ_target() var/mob/shooter = src - var/t = shooter.zone_sel?.selecting + var/t = shooter.get_target_zone() if ((t in list( BP_EYES, BP_MOUTH ))) t = BP_HEAD - var/obj/item/organ/external/def_zone = ran_zone(t) + var/obj/item/organ/external/def_zone = ran_zone(t, target = src) return def_zone // heal ONE external organ, organ gets randomly selected from damaged ones. -/mob/living/proc/heal_organ_damage(var/brute, var/burn, var/affect_robo = 0) - adjustBruteLoss(-brute) - adjustFireLoss(-burn) - src.updatehealth() +/mob/living/proc/heal_organ_damage(var/brute, var/burn, var/affect_robo = FALSE, var/update_health = TRUE) + heal_damage(BRUTE, brute, do_update_health = FALSE) + heal_damage(BURN, do_update_health = update_health) // damage ONE external organ, organ gets randomly selected from damaged ones. -/mob/living/proc/take_organ_damage(var/brute, var/burn, var/emp=0) - if(status_flags & GODMODE) return 0 //godmode - adjustBruteLoss(brute) - adjustFireLoss(burn) - src.updatehealth() +/mob/living/proc/take_organ_damage(var/brute = 0, var/burn = 0, var/bypass_armour = FALSE, var/override_droplimb) + if(status_flags & GODMODE) + return + take_damage(brute, do_update_health = FALSE) + take_damage(burn, BURN) // heal MANY external organs, in random order /mob/living/proc/heal_overall_damage(var/brute, var/burn) - adjustBruteLoss(-brute) - adjustFireLoss(-burn) - src.updatehealth() + heal_damage(BRUTE, brute, do_update_health = FALSE) + heal_damage(BURN, burn) // damage MANY external organs, in random order /mob/living/proc/take_overall_damage(var/brute, var/burn, var/used_weapon = null) if(status_flags & GODMODE) return 0 //godmode - adjustBruteLoss(brute) - adjustFireLoss(burn) - src.updatehealth() + take_damage(brute, do_update_health = FALSE) + take_damage(burn, BURN) /mob/living/proc/restore_all_organs() return @@ -387,49 +312,39 @@ default behaviour is: rejuvenate() if(buckled) buckled.unbuckle_mob() - if(iscarbon(src)) - var/mob/living/carbon/C = src - - if (C.handcuffed && !initial(C.handcuffed)) - C.drop_from_inventory(C.handcuffed) - C.handcuffed = initial(C.handcuffed) BITSET(hud_updateflag, HEALTH_HUD) BITSET(hud_updateflag, STATUS_HUD) BITSET(hud_updateflag, LIFE_HUD) - ExtinguishMob() - fire_stacks = 0 + extinguish_fire() + set_fire_intensity(0) + var/obj/item/cuffs = get_equipped_item(slot_handcuffed_str) + if (cuffs) + try_unequip(cuffs, get_turf(src)) /mob/living/proc/rejuvenate() - if(reagents) - reagents.clear_reagents() + + // Wipe all of our reagent lists. + for(var/datum/reagents/reagent_list as anything in get_metabolizing_reagent_holders(include_contact = TRUE)) + reagent_list.clear_reagents() // shut down various types of badness - setToxLoss(0) - setOxyLoss(0) - setCloneLoss(0) - setBrainLoss(0) - SetParalysis(0) - SetStunned(0) - SetWeakened(0) + set_damage(TOX, 0) + set_damage(OXY, 0) + set_damage(CLONE, 0) + set_damage(BRAIN, 0) + set_status_condition(STAT_PARA, 0) + set_status_condition(STAT_STUN, 0) + set_status_condition(STAT_WEAK, 0) // shut down ongoing problems radiation = 0 - bodytemperature = T20C - sdisabilities = 0 - disabilities = 0 - - // fix blindness and deafness - blinded = 0 - eye_blind = 0 - eye_blurry = 0 - ear_deaf = 0 - ear_damage = 0 - drowsyness = 0 - drugged = 0 - jitteriness = 0 - confused = 0 - - heal_overall_damage(getBruteLoss(), getFireLoss()) + bodytemperature = get_species()?.body_temperature || initial(bodytemperature) + reset_genetic_conditions() + + // clear all status conditions including blind/deaf + clear_status_conditions() + + heal_overall_damage(get_damage(BRUTE), get_damage(BURN)) // fix all of our organs restore_all_organs() @@ -439,32 +354,46 @@ default behaviour is: switch_from_dead_to_living_mob_list() timeofdeath = 0 - // restore us to conciousness + // restore us to consciousness set_stat(CONSCIOUS) // make the icons look correct - regenerate_icons() + update_icon() BITSET(hud_updateflag, HEALTH_HUD) BITSET(hud_updateflag, STATUS_HUD) BITSET(hud_updateflag, LIFE_HUD) + set_nutrition(get_max_nutrition()) + set_hydration(get_max_hydration()) + failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath. reload_fullscreen() return /mob/living/proc/basic_revival(var/repair_brain = TRUE) - if(repair_brain && getBrainLoss() > 50) + if(repair_brain && should_have_organ(BP_BRAIN)) + repair_brain = FALSE + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(src, BP_BRAIN) + if(brain) + if(brain.get_organ_damage() > (brain.max_damage/2)) + brain.set_organ_damage(brain.max_damage/2) + if(brain.status & ORGAN_DEAD) + brain.status &= ~ORGAN_DEAD + START_PROCESSING(SSobj, brain) + brain.update_icon() + + if(repair_brain && get_damage(BRAIN) > 50) repair_brain = FALSE - setBrainLoss(50) + set_damage(BRAIN, 50) if(stat == DEAD) switch_from_dead_to_living_mob_list() timeofdeath = 0 - stat = CONSCIOUS - regenerate_icons() + set_stat(CONSCIOUS) + update_icon() BITSET(hud_updateflag, HEALTH_HUD) BITSET(hud_updateflag, STATUS_HUD) @@ -473,58 +402,134 @@ default behaviour is: failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath. reload_fullscreen() -/mob/living/carbon/basic_revival(var/repair_brain = TRUE) - if(repair_brain && should_have_organ(BP_BRAIN)) - repair_brain = FALSE - var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN] - if(brain.damage > (brain.max_damage/2)) - brain.damage = (brain.max_damage/2) - if(brain.status & ORGAN_DEAD) - brain.status &= ~ORGAN_DEAD - START_PROCESSING(SSobj, brain) - brain.update_icon() - ..(repair_brain) - -/mob/living/proc/UpdateDamageIcon() - return +/mob/living + var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed + var/static/list/damage_icon_parts = list() -/mob/living/proc/Examine_OOC() - set name = "Examine Meta-Info (OOC)" - set category = "OOC" - set src in view() +/mob/living/proc/update_damage_overlays(update_icons = TRUE) - if(config.allow_Metadata) - if(client) - to_chat(usr, "[src]'s Metainfo:
    [client.prefs.metadata]") - else - to_chat(usr, "[src] does not have any stored infomation!") - else - to_chat(usr, "OOC Metadata is not supported by this server!") + // first check whether something actually changed about damage appearance + var/damage_appearance = get_overlay_state_modifier() || "" + for(var/obj/item/organ/external/O in get_external_organs()) + damage_appearance += O.damage_state || "00" - return + if(damage_appearance == previous_damage_appearance) + // nothing to do here + return + + previous_damage_appearance = damage_appearance + var/decl/bodytype/root_bodytype = get_bodytype() + if(!root_bodytype) + return + var/image/standing_image = image(root_bodytype.get_damage_overlays(src), icon_state = "00") + + // blend the individual damage states with our icons + for(var/obj/item/organ/external/O in get_external_organs()) + if(!O.damage_state || O.damage_state == "00") + continue + var/icon/DI + var/use_colour = (BP_IS_PROSTHETIC(O) ? SYNTH_BLOOD_COLOR : O.species.get_species_blood_color(src)) + var/cache_index = "[O.damage_state]/[O.bodytype.uid]/[O.icon_state]/[use_colour]/[O.species.uid]" + if(!(cache_index in damage_icon_parts)) + var/damage_overlay_icon = O.bodytype.get_damage_overlays(src) + if(check_state_in_icon(O.damage_state, damage_overlay_icon)) + DI = new /icon(damage_overlay_icon, O.damage_state) // the damage icon for whole human + DI.Blend(get_limb_mask_for(O), ICON_MULTIPLY) // mask with this organ's pixels + DI.Blend(use_colour, ICON_MULTIPLY) + damage_icon_parts[cache_index] = DI || FALSE + else + DI = damage_icon_parts[cache_index] + if(DI) + standing_image.overlays += DI + set_current_mob_overlay(HO_DAMAGE_LAYER, standing_image, update_icons) + update_bandages(update_icons) + +/mob/living/proc/update_bandages(var/update_icons=1) + var/list/bandage_overlays + var/bandage_icon = get_bodytype()?.get_bandages_icon(src) + if(bandage_icon) + for(var/obj/item/organ/external/O in get_external_organs()) + var/bandage_level = O.bandage_level() + if(bandage_level) + LAZYADD(bandage_overlays, image(bandage_icon, "[O.icon_state][bandage_level]")) + set_current_mob_overlay(HO_BANDAGE_LAYER, bandage_overlays, update_icons) + +/mob/living/handle_grabs_after_move(var/turf/old_loc, var/direction) -/mob/living/handle_grabs_after_move() ..() - if(!skill_check(SKILL_MEDICAL, SKILL_BASIC)) - for(var/obj/item/grab/grab in get_active_grabs()) - var/mob/affecting_mob = grab.get_affecting_mob() - if(affecting_mob) - affecting_mob.handle_grab_damage() -/mob/living/Move(a, b, flag) - if (buckled) + if(!isturf(loc)) + for(var/obj/item/grab/grab as anything in get_active_grabs()) + qdel(grab) return - . = ..() + if(isturf(old_loc)) + for(var/atom/movable/AM as anything in ret_grab()) + if(AM != src && AM.loc != loc && !AM.anchored && old_loc.Adjacent(AM)) + if(get_z(AM) <= get_z(src)) + AM.glide_size = glide_size // This is adjusted by grabs again from events/some of the procs below, but doing it here makes it more likely to work with recursive movement. + AM.DoMove(get_dir(get_turf(AM), old_loc), src, TRUE) + else // Hackfix for eternal bump due to grabber moving down through an openturf. + AM.dropInto(get_turf(src)) + + var/list/mygrabs = get_active_grabs() + for(var/obj/item/grab/grab as anything in mygrabs) + if(grab.assailant_reverse_facing()) + set_dir(global.reverse_dir[direction]) + grab.assailant_moved() + if(QDELETED(grab) || QDELETED(grab.affecting)) + mygrabs -= grab + + if(length(grabbed_by)) + for(var/obj/item/grab/grab as anything in grabbed_by) + grab.adjust_position() + reset_offsets() + reset_plane_and_layer() + + if(!length(mygrabs)) + return - handle_grabs_after_move() + if(direction & (UP|DOWN)) + var/txt_dir = (direction & UP) ? "upwards" : "downwards" + if(old_loc) + old_loc.visible_message(SPAN_NOTICE("\The [src] moves [txt_dir].")) + for(var/obj/item/grab/grab as anything in mygrabs) + var/turf/start = grab.affecting.loc + var/turf/destination = (direction == UP) ? GetAbove(grab.affecting) : GetBelow(grab.affecting) + if(!start.CanZPass(grab.affecting, direction)) + to_chat(src, SPAN_WARNING("\The [start] blocked your pulled object!")) + mygrabs -= grab + qdel(grab) + continue + for(var/atom/A in destination) + if(!A.CanMoveOnto(grab.affecting, start, 1.5, direction)) + to_chat(src, SPAN_WARNING("\The [A] blocks the [grab.affecting] you were pulling.")) + mygrabs -= grab + qdel(grab) + continue + grab.affecting.forceMove(destination) + if(QDELETED(grab) || QDELETED(grab.affecting)) + mygrabs -= grab + continue - if (s_active && !( s_active in contents ) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much. - s_active.close(src) + if(length(mygrabs) && !skill_check(SKILL_MEDICAL, SKILL_BASIC)) + for(var/obj/item/grab/grab as anything in mygrabs) + var/mob/living/affecting_mob = grab.get_affecting_mob() + if(affecting_mob) + affecting_mob.handle_grab_damage() - if(update_slimes) - for(var/mob/living/carbon/slime/M in view(1,src)) - M.UpdateFeed() +/mob/living/Move(NewLoc, Dir) + if (buckled) + return + var/turf/old_loc = loc + . = ..() + if(.) + refresh_hud_element(HUD_UP_HINT) + handle_grabs_after_move(old_loc, Dir) + if(active_storage && !active_storage.can_view(src)) + active_storage.close(src) + if(germ_level < GERM_LEVEL_MOVE_CAP && prob(8)) + germ_level++ /mob/living/verb/resist() set name = "Resist" @@ -533,20 +538,39 @@ default behaviour is: if(!incapacitated(INCAPACITATION_KNOCKOUT) && last_resist + 2 SECONDS <= world.time) last_resist = world.time resist_grab() - if(resting) - lay_down() - if(!weakened) + if(!HAS_STATUS(src, STAT_WEAK)) process_resist() /mob/living/proc/process_resist() - //Getting out of someone's inventory. - if(istype(src.loc, /obj/item/holder)) - escape_inventory(src.loc) - return + + SHOULD_CALL_PARENT(TRUE) //unbuckling yourself if(buckled) - spawn() escape_buckle() + // TODO: convert vines to structures and have them override user_unbuckle_mob() + if(istype(buckled, /obj/effect/vine)) + var/obj/effect/vine/V = buckled + spawn() V.manual_unbuckle(src) + else + spawn() escape_buckle() + return TRUE + //drop && roll + else if(is_on_fire()) + set_fire_intensity(max(0, get_fire_intensity()-1.2)) + SET_STATUS_MAX(src, STAT_WEAK, 3) + spin(32,2) + var/decl/pronouns/pronouns = get_pronouns() + visible_message( + SPAN_DANGER("\The [src] rolls on the floor, trying to put [pronouns.him][pronouns.self] out!"), + SPAN_NOTICE("You stop, drop, and roll!") + ) + sleep(3 SECONDS) + if(get_fire_intensity() <= 0) + visible_message( + SPAN_NOTICE("\The [src] successfully extinguishes [pronouns.him][pronouns.self]!"), + SPAN_NOTICE("You extinguish yourself.") + ) + extinguish_fire() return TRUE //Breaking out of a structure? @@ -555,6 +579,34 @@ default behaviour is: if(C.mob_breakout(src)) return TRUE + //Getting out of someone's inventory. + if(istype(src.loc, /obj/item/holder)) + escape_inventory(src.loc) + return TRUE + + // Get rid of someone riding around on you. + if(buckled_mob) + unbuckle_mob() + return TRUE + + // removing equipment + var/obj/item/restraint = get_restraining_equipment() + if(restraint) + spawn() + if(QDELETED(restraint) || restraint.loc != src) + return + var/datum/extension/resistable/restraint_data = get_extension(restraint, /datum/extension/resistable) + if(istype(restraint_data)) + restraint_data.user_try_escape(src, get_equipped_slot_for_item(restraint)) + +/mob/living/proc/get_restraining_equipment() + // List order determines the priority of each slot. + var/static/list/restraining_slots = list(slot_wear_suit_str, slot_handcuffed_str) + for(var/slot in restraining_slots) + var/obj/item/restraint = get_equipped_item(slot) + if(istype(restraint) && has_extension(restraint, /datum/extension/resistable)) + return restraint + /mob/living/proc/escape_inventory(obj/item/holder/H) if(H != src.loc) return @@ -567,10 +619,10 @@ default behaviour is: // Update whether or not this mob needs to pass emotes to contents. for(var/atom/A in M.contents) - if(istype(A,/mob) || istype(A,/obj/item/holder)) + if(ismob(A) || istype(A,/obj/item/holder)) return M.status_flags &= ~PASSEMOTES - else if(istype(H.loc,/obj/item/clothing/accessory/storage/holster) || istype(H.loc,/obj/item/storage/belt/holster)) + else if(istype(H.loc,/obj/item/clothing/webbing/holster) || istype(H.loc,/obj/item/belt/holster)) var/datum/extension/holster/holster = get_extension(src, /datum/extension/holster) if(holster.holstered == H) holster.clear_holster() @@ -587,75 +639,76 @@ default behaviour is: if(loc != H) qdel(H) -/mob/living/proc/escape_buckle() - if(buckled) - if(buckled.can_buckle) - buckled.user_unbuckle_mob(src) - else - to_chat(usr, "You can't seem to escape from \the [buckled]!") - return - -/mob/living/proc/resist_grab() - var/resisting = 0 - for(var/obj/item/grab/G in grabbed_by) - resisting++ - G.handle_resist() - if(resisting) - visible_message("[src] resists!") - -/mob/living/verb/lay_down() +// Shortcut for people used to typing Rest instead of Change Posture. +/mob/living/verb/rest_verb() set name = "Rest" set category = "IC" + lay_down(block_posture = /decl/posture/sitting) + +/mob/living/verb/lay_down(block_posture as null) + set name = "Change Posture" + set category = "IC" + + // No posture, no adjustment. + if(length(get_available_postures()) <= 1 || incapacitated(INCAPACITATION_KNOCKDOWN) || !canClick()) + return + + var/list/selectable_postures = get_selectable_postures() - resting = !resting - to_chat(src, "You are now [resting ? "resting" : "getting up"]") + if(block_posture) + for(var/decl/posture/selectable_posture in selectable_postures) + if(islist(block_posture)) + if(is_type_in_list(selectable_posture, block_posture)) + selectable_postures -= selectable_posture + else if(istype(selectable_posture, block_posture)) + selectable_postures -= selectable_posture + + if(!length(selectable_postures)) + return + + var/decl/posture/selected_posture + if(length(selectable_postures) == 1) + selected_posture = selectable_postures[1] + else + selected_posture = input(src, "Which posture do you wish to adopt?", "Change Posture", current_posture) as null|anything in selectable_postures + if(!selected_posture || length(get_available_postures()) <= 1 || incapacitated(INCAPACITATION_KNOCKDOWN) || !canClick()) + return + if(current_posture == selected_posture || !(selected_posture in get_selectable_postures())) + return + + setClickCooldown(3) + if(current_posture.prone && !selected_posture.prone) + if(!do_after(src, 2 SECONDS, src, incapacitation_flags = INCAPACITATION_KNOCKDOWN)) + return + if(current_posture == selected_posture || !(selected_posture in get_selectable_postures())) + return + to_chat(src, SPAN_NOTICE("You are now [selected_posture.posture_change_message].")) + set_posture(selected_posture) //called when the mob receives a bright flash /mob/living/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) - if(override_blindness_check || !(disabilities & BLINDED)) - ..() + if(eyecheck() < intensity || override_blindness_check || !has_genetic_condition(GENE_COND_BLINDED)) overlay_fullscreen("flash", type) spawn(25) if(src) clear_fullscreen("flash", 25) - return 1 - -/mob/living/proc/cannot_use_vents() - if(mob_size > MOB_SIZE_SMALL) - return "You can't fit into that vent." - return null + return TRUE + return FALSE /mob/living/proc/has_brain() - return 1 - -/mob/living/proc/slip(var/slipped_on,stun_duration=8) - return 0 - -/mob/living/carbon/human/canUnEquip(obj/item/I) - if(!..()) - return - if(I in internal_organs) - return - if(I in organs) - return - return 1 - -/mob/living/carbon/get_contained_external_atoms() - . = contents.Copy() - . -= internal_organs - . -= organs + return TRUE -//damage/heal the mob ears and adjust the deaf amount -/mob/living/adjustEarDamage(var/damage, var/deaf) - ear_damage = max(0, ear_damage + damage) - ear_deaf = max(0, ear_deaf + deaf) +// We are jumping, levitating or being thrown. +/mob/living/immune_to_floor_hazards() + . = ..() || is_floating -//pass a negative argument to skip one of the variable -/mob/living/setEarDamage(var/damage = null, var/deaf = null) - if(!isnull(damage)) - ear_damage = damage - if(!isnull(deaf)) - ear_deaf = deaf +/mob/living/proc/slip(slipped_on, stun_duration = 8) + if(can_slip()) + to_chat(src, SPAN_DANGER("You slipped on [slipped_on]!")) + playsound(loc, 'sound/misc/slip.ogg', 50, 1, -3) + SET_STATUS_MAX(src, STAT_WEAK, stun_duration) + return TRUE + return FALSE /mob/proc/can_be_possessed_by(var/mob/observer/ghost/possessor) return istype(possessor) && possessor.client @@ -687,131 +740,204 @@ default behaviour is: src.ckey = possessor.ckey qdel(possessor) - if(round_is_spooky(6)) // Six or more active cultists. - to_chat(src, "You reach out with tendrils of ectoplasm and invade the mind of \the [src]...") - to_chat(src, "You have assumed direct control of \the [src].") - to_chat(src, "Due to the spookiness of the round, you have taken control of the poor animal as an invading, possessing spirit - roleplay accordingly.") - src.universal_speak = TRUE - src.universal_understand = TRUE - //src.cultify() // Maybe another time. - return - to_chat(src, "You are now \the [src]!") to_chat(src, "Remember to stay in character for a mob of this type!") return 1 -/mob/living/reset_layer() - if(hiding) - layer = HIDING_MOB_LAYER - else - ..() - -/mob/living/update_icons() - if(auras) - overlays |= auras - -/mob/living/proc/add_aura(var/obj/aura/aura) - LAZYDISTINCTADD(auras,aura) - update_icons() - return 1 - -/mob/living/proc/remove_aura(var/obj/aura/aura) - LAZYREMOVE(auras,aura) - update_icons() - return 1 - /mob/living/Destroy() - if(auras) - for(var/a in auras) - remove_aura(a) + clear_mob_modifiers() + QDEL_NULL(aiming) + QDEL_NULL_LIST(_hallucinations) + QDEL_NULL_LIST(aimed_at_by) + LAZYCLEARLIST(smell_cooldown) + if(stressors) // Do not QDEL_NULL, keys are managed instances. + stressors = null + // done in this order so that icon updates aren't triggered once all our organs are obliterated + delete_inventory(TRUE) + delete_organs() + if(weather_sensitive) + SSweather_atoms.weather_atoms -= src return ..() /mob/living/proc/melee_accuracy_mods() . = 0 if(incapacitated(INCAPACITATION_UNRESISTING)) . += 100 - if(eye_blind) + if(HAS_STATUS(src, STAT_BLIND)) . += 75 - if(eye_blurry) + if(HAS_STATUS(src, STAT_BLURRY)) . += 15 - if(confused) + if(HAS_STATUS(src, STAT_CONFUSE)) . += 30 - if(MUTATION_CLUMSY in mutations) + if(has_genetic_condition(GENE_COND_CLUMSY)) . += 40 /mob/living/proc/ranged_accuracy_mods() . = 0 - if(jitteriness) + if(HAS_STATUS(src, STAT_JITTER)) . -= 2 - if(confused) + if(HAS_STATUS(src, STAT_CONFUSE)) . -= 2 - if(eye_blind) + if(HAS_STATUS(src, STAT_BLIND)) . -= 5 - if(eye_blurry) + if(HAS_STATUS(src, STAT_BLURRY)) . -= 1 - if(MUTATION_CLUMSY in mutations) + if(has_genetic_condition(GENE_COND_CLUMSY)) . -= 3 /mob/living/can_drown() - return TRUE + if(get_internals()) + return FALSE + var/obj/item/clothing/mask/mask = get_equipped_item(slot_wear_mask_str) + if(istype(mask) && mask.filters_water()) + return FALSE + var/obj/item/organ/internal/lungs/L = get_organ(BP_LUNGS, /obj/item/organ/internal/lungs) + return (!L || L.can_drown()) /mob/living/handle_drowning() - if(!can_drown() || !loc.is_flooded(lying)) + if(!can_drown() || !loc?.is_flooded(current_posture.prone)) + return FALSE + var/turf/T = get_turf(src) + if(!current_posture.prone && T.above && T.above.is_open() && !T.above.is_flooded() && can_overcome_gravity()) return FALSE if(prob(5)) - var/obj/effect/fluid/F = locate() in loc - to_chat(src, SPAN_DANGER("You choke and splutter as you inhale [(F?.reagents && F.reagents.get_primary_reagent_name()) || "liquid"]!")) - F?.reagents?.trans_to_holder(get_ingested_reagents(), min(F.reagents.total_volume, rand(2,5))) + var/datum/reagents/metabolism/inhaled = get_inhaled_reagents() + var/datum/reagents/metabolism/ingested = get_ingested_reagents() + to_chat(src, SPAN_DANGER("You choke and splutter as you inhale [T.get_fluid_name()]!")) + var/inhale_amount = 0 + if(inhaled) + inhale_amount = rand(2,5) + T.reagents?.trans_to_holder(inhaled, min(REAGENT_TOTAL_VOLUME(T.reagents), inhale_amount)) + if(ingested) + var/ingest_amount = 5 - inhale_amount + reagents?.trans_to_holder(ingested, min(REAGENT_TOTAL_VOLUME(T.reagents), ingest_amount)) - var/turf/T = get_turf(src) T.show_bubbles() return TRUE // Presumably chemical smoke can't be breathed while you're underwater. /mob/living/fluid_act(var/datum/reagents/fluids) ..() - for(var/thing in get_equipped_items(TRUE)) - if(isnull(thing)) continue - var/atom/movable/A = thing - if(A.simulated) - A.fluid_act(fluids) - -/mob/living/proc/nervous_system_failure() - return FALSE - -/mob/living/proc/needs_wheelchair() - return FALSE + if(QDELETED(src) || REAGENT_TOTAL_VOLUME(fluids) < FLUID_PUDDLE) + return + fluids.touch_mob(src) + if(QDELETED(src) || REAGENT_TOTAL_VOLUME(fluids) < FLUID_PUDDLE) + return + var/on_turf = REAGENT_GET_ATOM(fluids) == get_turf(src) + for(var/atom/movable/A as anything in get_equipped_items(TRUE)) + if(!A.simulated) + continue + // if we're being affected by reagent fluids, items check if they're submerged + // todo: i don't like how this works, it feels hacky. maybe separate coating and submersion somehow and make this only checked for submersion + if(on_turf && !A.submerged()) + continue + A.fluid_act(fluids) + if(QDELETED(src) || !REAGENT_TOTAL_VOLUME(fluids)) + return + // TODO: review saturation logic so we can end up with more than like 15 water in our contact reagents. + var/datum/reagents/touching_reagents = get_contact_reagents() + if(touching_reagents) + var/saturation = min(REAGENT_TOTAL_VOLUME(fluids), round(mob_size * 1.5 * reagent_permeability()) - REAGENT_TOTAL_VOLUME(touching_reagents)) + if(saturation > 0) + fluids.trans_to_holder(touching_reagents, saturation) /mob/living/proc/seizure() set waitfor = 0 sleep(rand(5,10)) - if(!paralysis && stat == CONSCIOUS) + if(!HAS_STATUS(src, STAT_PARA) && stat == CONSCIOUS) visible_message(SPAN_DANGER("\The [src] starts having a seizure!")) - Paralyse(rand(8,16)) - make_jittery(rand(150,200)) - adjustHalLoss(rand(50,60)) + SET_STATUS_MAX(src, STAT_PARA, rand(8,16)) + set_status_condition(STAT_JITTER, rand(150,200)) + take_damage(rand(50, 60), PAIN) /mob/living/proc/get_digestion_product() return null +/mob/living/proc/handle_additional_vomit_reagents(var/obj/effect/decal/cleanable/vomit/vomit) + vomit.add_to_reagents(/decl/material/liquid/acid/stomach, 5) + +/mob/living/proc/get_flash_mod() + var/vision_organ_tag = get_vision_organ_tag() + if(vision_organ_tag) + var/obj/item/organ/internal/eyes/I = get_organ(vision_organ_tag, /obj/item/organ/internal/eyes) + if(I) // get_organ with a type passed already does a typecheck + return I.get_flash_mod() + return get_bodytype()?.eye_flash_mod + +/mob/living/proc/get_flash_burn() + var/vision_organ_tag = get_vision_organ_tag() + if(vision_organ_tag) + var/obj/item/organ/internal/eyes/I = get_organ(vision_organ_tag, /obj/item/organ/internal/eyes) + if(I) + return I.get_flash_burn() + return get_bodytype()?.eye_flash_burn + /mob/living/proc/eyecheck() - return FLASH_PROTECTION_NONE + var/total_protection = flash_protection + if(should_have_organ(BP_EYES)) + var/vision_organ_tag = get_vision_organ_tag() + if(vision_organ_tag && get_bodytype()?.has_organ[vision_organ_tag]) + var/obj/item/organ/internal/eyes/I = get_organ(vision_organ_tag, /obj/item/organ/internal/eyes) + if(!I?.is_usable()) + return FLASH_PROTECTION_MAJOR + total_protection = I.get_total_protection(flash_protection) + else // They can't be flashed if they don't have eyes. + return FLASH_PROTECTION_MAJOR + return total_protection + +/mob/living/proc/get_satiated_nutrition() + return 500 + +/mob/living/proc/get_max_nutrition() + return 550 + +/mob/living/proc/set_nutrition(var/amt) + nutrition = clamp(amt, 0, get_max_nutrition()) + +/mob/living/proc/get_nutrition() + return isSynthetic() ? get_max_nutrition() : nutrition /mob/living/proc/adjust_nutrition(var/amt) - return + set_nutrition(get_nutrition() + amt) + +/mob/living/proc/get_max_hydration() + return 500 + +/mob/living/proc/get_hydration(var/amt) + return isSynthetic() ? get_max_hydration() : hydration + +/mob/living/proc/set_hydration(var/amt) + hydration = clamp(amt, 0, get_max_hydration()) /mob/living/proc/adjust_hydration(var/amt) - return + set_hydration(get_hydration() + amt) + +/mob/living/proc/has_chemical_effect(var/chem, var/threshold_over, var/threshold_under) + var/val = GET_CHEMICAL_EFFECT(src, chem) + . = (isnull(threshold_over) || val >= threshold_over) && (isnull(threshold_under) || val <= threshold_under) + +/mob/living/proc/remove_chemical_effect(var/effect, var/magnitude) + if(!isnull(magnitude)) + magnitude = LAZYACCESS(chem_effects, effect) - magnitude + if(magnitude <= 0) + LAZYREMOVE(chem_effects, effect) + else + LAZYSET(chem_effects, effect, magnitude) /mob/living/proc/add_chemical_effect(var/effect, var/magnitude = 1) - return + magnitude += GET_CHEMICAL_EFFECT(src, effect) + LAZYSET(chem_effects, effect, magnitude) -/mob/living/proc/add_up_to_chemical_effect(var/effect, var/magnitude = 1) - return +/mob/living/proc/add_chemical_effect_max(var/effect, var/magnitude = 1) + magnitude = max(LAZYACCESS(chem_effects, effect), magnitude) + LAZYSET(chem_effects, effect, magnitude) -/mob/living/proc/adjust_immunity(var/amt) - return +/mob/living/proc/add_chemical_effect_min(var/effect, var/magnitude = 1) + var/old_magnitude = LAZYACCESS(chem_effects, effect) + if(!isnull(old_magnitude)) + magnitude = min(old_magnitude, magnitude) + LAZYSET(chem_effects, effect, magnitude) -/mob/living/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays) +/mob/living/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays, var/digital = FALSE) if(skill_check(SKILL_LITERACY, SKILL_ADEPT)) . = text_content else @@ -820,9 +946,9 @@ default behaviour is: if(user != src) to_chat(user, SPAN_NOTICE("\The [src] scans the writing...")) if(skill_check(SKILL_LITERACY, SKILL_BASIC)) - if(skip_delays || do_after(src, 1 SECOND, user)) + if(skip_delays || do_mob(user, src, 1 SECOND)) . = stars(text_content, 85) - else if(skip_delays || do_after(src, 3 SECONDS, user)) + else if(skip_delays || do_mob(user, src, 3 SECONDS)) . = ..() /mob/living/handle_writing_literacy(var/mob/user, var/text_content, var/skip_delays) @@ -839,21 +965,19 @@ default behaviour is: else if(skip_delays || do_after(src, 5 SECONDS, user)) . = ..() -/mob/living/can_be_injected_by(var/atom/injector) - return ..() && (can_inject(null, 0, BP_CHEST) || can_inject(null, 0, BP_GROIN)) - /mob/living/handle_grab_damage() ..() if(!has_gravity()) return - if(isturf(loc) && pull_damage() && prob(getBruteLoss() / 6)) - blood_splatter(loc, src, large = TRUE) + if(isturf(loc) && pull_damage() && prob(get_damage(BRUTE) / 6)) + if (!should_have_organ(BP_HEART)) + blood_splatter(loc, src, large = TRUE) if(prob(25)) - adjustBruteLoss(1) + take_damage(1) visible_message(SPAN_DANGER("\The [src]'s [isSynthetic() ? "state worsens": "wounds open more"] from being dragged!")) /mob/living/CanUseTopicPhysical(mob/user) - . = CanUseTopic(user, GLOB.physical_no_access_state) + . = CanUseTopic(user, global.physical_no_access_topic_state) /mob/living/proc/is_telekinetic() return FALSE @@ -861,5 +985,1035 @@ default behaviour is: /mob/living/proc/can_do_special_ranged_attack(var/check_flag = TRUE) return TRUE +/mob/living/proc/get_food_satiation(consumption_method = EATING_METHOD_EAT) + . = (consumption_method == EATING_METHOD_EAT) ? get_nutrition() : get_hydration() + var/datum/reagents/ingested = get_ingested_reagents() + . += REAGENT_TOTAL_VOLUME(ingested) * 5 + /mob/living/proc/get_ingested_reagents() + RETURN_TYPE(/datum/reagents) + return reagents + +/mob/living/proc/should_have_organ(organ_to_check) + var/decl/bodytype/root_bodytype = get_bodytype() + return !!root_bodytype?.has_organ[organ_to_check] + +/// Returns null if the mob's bodytype doesn't have a limb tag by default. +/// Otherwise, returns the data of the limb instead. +/mob/living/proc/should_have_limb(limb_to_check) + var/decl/bodytype/root_bodytype = get_bodytype() + return root_bodytype?.has_limbs[limb_to_check] + +/mob/living/proc/get_contact_reagents() + RETURN_TYPE(/datum/reagents) return reagents + +/mob/living/proc/get_injected_reagents() + RETURN_TYPE(/datum/reagents) + return reagents + +/mob/living/proc/get_inhaled_reagents() + RETURN_TYPE(/datum/reagents) + return reagents + +/mob/living/proc/get_adjusted_metabolism(metabolism) + return metabolism + +/mob/living/get_admin_job_string() + return "Living" + +/mob/living/handle_mouse_drop(atom/over, mob/user, params) + if(!anchored && user == src && user != over) + + if(isturf(over)) + var/turf/T = over + var/obj/structure/glass_tank/A = locate() in user.loc + if(A && A.Adjacent(user) && A.Adjacent(T)) + A.do_climb_out(user, T) + return TRUE + + if(isexosuit(over)) + var/mob/living/exosuit/exosuit = over + if(exosuit.body) + if(user.mob_size >= exosuit.body.min_pilot_size && user.mob_size <= exosuit.body.max_pilot_size) + exosuit.enter(src) + else + to_chat(user, SPAN_WARNING("You cannot pilot an exosuit of this size.")) + return TRUE + . = ..() + +/mob/living/is_deaf() + . = ..() || GET_STATUS(src, STAT_DEAF) + +/mob/living/attempt_hug(mob/living/target, hug_3p, hug_1p) + . = ..() + if(.) + + if(stat != DEAD) + ADJ_STATUS(src, STAT_PARA, -3) + ADJ_STATUS(src, STAT_STUN, -3) + ADJ_STATUS(src, STAT_WEAK, -3) + + var/fire_level = get_fire_intensity() + var/target_fire_level = target.get_fire_intensity() + if(fire_level >= target_fire_level + 3) + target.adjust_fire_intensity(1) + adjust_fire_intensity(-1) + else if(target_fire_level >= fire_level + 3) + adjust_fire_intensity(1) + target.adjust_fire_intensity(-1) + + if(is_on_fire() && !target.is_on_fire()) + target.ignite_fire() + else if(!is_on_fire() && target.is_on_fire()) + ignite_fire() + +/mob/living/proc/jump_layer_shift() + jumping = TRUE + reset_layer() + +/mob/living/proc/jump_layer_shift_end() + jumping = FALSE + reset_layer() + +/mob/living/proc/get_eye_overlay() + return + +/mob/living/proc/empty_stomach() + return + +/mob/living/proc/handle_actions() + //Pretty bad, i'd use picked/dropped instead but the parent calls in these are nonexistent + for(var/datum/action/A in actions) + if(A.CheckRemoval(src)) + A.Remove(src) + for(var/obj/item/I in src) + if(QDELETED(I)) + continue + if(!I.action_button_name) + continue + I.action ||= new I.default_action_type + I.action.name = I.action_button_name + I.action.desc = I.action_button_desc + I.action.SetTarget(I) + I.action.Grant(src) + return + +/mob/living/update_action_buttons() + if(!istype(hud_used) || !client) + return + if(!hud_used.is_hud_shown()) //Hud toggled to minimal + return + + client.screen -= hud_used.hide_actions_toggle + for(var/datum/action/A in actions) + if(A.button) + client.screen -= A.button + + if(hud_used.action_buttons_hidden) + if(!hud_used.hide_actions_toggle) + hud_used.hide_actions_toggle = new(hud_used) + hud_used.hide_actions_toggle.update_icon() + hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(1) + client.screen += hud_used.hide_actions_toggle + return + + var/button_number = 0 + for(var/datum/action/action in actions) + button_number++ + if(isnull(action.button)) + action.button = new /obj/screen/action_button(null, src, null, null, null, null, action) + action.button.SetName(action.UpdateName()) + action.button.desc = action.UpdateDesc() + action.button.update_icon() + action.button.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number) + client.screen |= action.button + + if(button_number > 0) + if(!hud_used.hide_actions_toggle) + hud_used.hide_actions_toggle = new(hud_used, src) + hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1) + client.screen += hud_used.hide_actions_toggle + +/mob/living/handle_fall_effect(var/turf/landing) + if(!(. = ..()) || !istype(landing)) + return + apply_fall_damage(landing) + if(!client) + return + var/area/landing_area = get_area(landing) + if(landing_area) + landing_area.alert_on_fall(src) + +/mob/living/proc/apply_fall_damage(var/turf/landing) + take_damage(rand(max(1, ceil(mob_size * 0.33)), max(1, ceil(mob_size * 0.66))) * get_fall_height()) + +/mob/living/proc/get_toxin_resistance() + var/decl/species/species = get_species() + return isnull(species) ? 1 : species.toxins_mod + +/mob/living/proc/get_metabolizing_reagent_holders(var/include_contact = FALSE) + for(var/datum/reagents/adding in list(reagents, get_ingested_reagents(), get_inhaled_reagents())) + LAZYDISTINCTADD(., adding) + if(include_contact) + for(var/datum/reagents/adding in list(get_injected_reagents(), get_contact_reagents())) + LAZYDISTINCTADD(., adding) + +/mob/living/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/admin_kill) + +/decl/interaction_handler/admin_kill + name = "Admin Kill" + expected_user_type = /mob/observer + expected_target_type = /mob/living + interaction_flags = 0 + examine_desc = null // DO NOT show this in general. + +/decl/interaction_handler/admin_kill/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + if(!check_rights(R_INVESTIGATE, 0, user)) + return FALSE + var/mob/living/M = target + if(M.stat == DEAD) + return FALSE + +/decl/interaction_handler/admin_kill/invoked(atom/target, mob/user, obj/item/prop) + var/mob/living/M = target + var/key_name = key_name(M) + if(alert(user, "Do you wish to kill [key_name]?", "Kill \the [M]?", "No", "Yes") != "Yes") + return FALSE + if(!is_possible(target, user, prop)) + to_chat(user, SPAN_NOTICE("You were unable to kill [key_name].")) + return FALSE + M.death() + log_and_message_admins("\The [user] admin-killed [key_name].") + +/mob/living/get_speech_bubble_state_modifier() + return isSynthetic() ? "synth" : ..() + +/mob/living/proc/is_on_special_ability_cooldown() + return world.time < next_special_ability + +/mob/living/proc/set_special_ability_cooldown(var/amt) + next_special_ability = max(next_special_ability, world.time+amt) + +/mob/living/proc/get_seconds_until_next_special_ability_string() + return ticks2readable(next_special_ability - world.time) + +/mob/living/proc/handle_some_updates() + //We are long dead, or we're junk mobs spawned like the clowns on the clown shuttle + return life_tick <= 5 || !timeofdeath || (timeofdeath >= 5 && (world.time-timeofdeath) <= 10 MINUTES) + +/mob/living/get_unique_enzymes() + if(isnull(unique_enzymes) && has_genetic_information()) + set_unique_enzymes(md5(name)) + return unique_enzymes + +/mob/living/set_unique_enzymes(value) + unique_enzymes = value + +/mob/living/get_blood_type() + return blood_type + +/mob/living/proc/get_mob_footstep(var/footstep_type) + var/decl/species/my_species = get_species() + return my_species?.get_footstep(src, footstep_type) + +/mob/living/GetIdCards(list/exceptions) + . = ..() + // Grab our equipped ID. + // TODO: consider just iterating the entire equipment list here? + // Mask/neck slot lanyards or IDs as uniform accessories someday? + // TODO: May need handling for a held or equipped item returning + // multiple ID cards, currently will take the last one added. + var/obj/item/id = get_equipped_item(slot_wear_id_str) + if(istype(id)) + id = id.GetIdCard() + if(istype(id) && !is_type_in_list(id, exceptions)) + LAZYDISTINCTADD(., id) + // Go over everything we're holding. + for(var/obj/item/thing in get_held_items()) + thing = thing.GetIdCard() + if(istype(thing) && !is_type_in_list(thing, exceptions)) + LAZYDISTINCTADD(., thing) + +/mob/living/proc/update_surgery(update_icons) + SHOULD_CALL_PARENT(TRUE) + var/image/total = null + for(var/obj/item/organ/external/E in get_external_organs()) + if(BP_IS_PROSTHETIC(E)) + continue + var/how_open = round(E.how_open()) + if(how_open <= 0) + continue + var/surgery_icon = E.get_surgery_overlay_icon() + if(!surgery_icon) + continue + if(!total) + total = new + total.appearance_flags = RESET_COLOR + var/base_state = "[E.icon_state][how_open]" + var/overlay_state = "[base_state]-flesh" + var/list/overlays_to_add + if(check_state_in_icon(overlay_state, surgery_icon)) + var/image/flesh = image(icon = surgery_icon, icon_state = overlay_state, layer = -HO_SURGERY_LAYER) + flesh.color = E.species.get_species_flesh_color(src) + LAZYADD(overlays_to_add, flesh) + overlay_state = "[base_state]-blood" + if(check_state_in_icon(overlay_state, surgery_icon)) + var/image/blood = image(icon = surgery_icon, icon_state = overlay_state, layer = -HO_SURGERY_LAYER) + blood.color = E.species.get_species_blood_color(src) + LAZYADD(overlays_to_add, blood) + overlay_state = "[base_state]-bones" + if(check_state_in_icon(overlay_state, surgery_icon)) + LAZYADD(overlays_to_add, image(icon = surgery_icon, icon_state = overlay_state, layer = -HO_SURGERY_LAYER)) + total.overlays |= overlays_to_add + set_current_mob_overlay(HO_SURGERY_LAYER, total, update_icons) + +/mob/living/get_overhead_text_x_offset() + var/decl/bodytype/bodytype = get_bodytype() + return ..() + bodytype?.antaghud_offset_x + +/mob/living/get_overhead_text_y_offset() + var/decl/bodytype/bodytype = get_bodytype() + return ..() + bodytype?.antaghud_offset_y + +// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc. +/mob/living/proc/get_authentification_rank(if_no_id = "No id", if_no_job = "No job") + var/obj/item/card/id/id = GetIdCard() + return istype(id) ? (id.position || if_no_job) : if_no_id + +//gets assignment from ID or ID inside PDA or PDA itself +//Useful when player do something with computers +/mob/living/proc/get_assignment(if_no_id = "No id", if_no_job = "No job") + var/obj/item/card/id/id = GetIdCard() + if(istype(id)) + return id.assignment ? id.assignment : if_no_job + return if_no_id + +//gets name from ID or ID inside PDA or PDA itself +//Useful when players do something with computers +/mob/living/proc/get_authentification_name(if_no_id = "Unknown") + var/obj/item/card/id/id = GetIdCard() + if(istype(id)) + return id.registered_name + return if_no_id + +//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere +/mob/living/proc/get_visible_name() + var/face_name = get_face_name() + var/id_name = get_id_name("") + if((face_name == "Unknown") && id_name && (id_name != face_name)) + return "[face_name] (as [id_name])" + return face_name + +//Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable +//Also used in AI tracking people by face, so added in checks for head coverings like masks and helmets +/mob/living/proc/get_face_name() + if(identity_is_visible()) + return real_name + var/obj/item/clothing/mask = get_equipped_item(slot_wear_mask_str) + var/obj/item/clothing/head = get_equipped_item(slot_head_str) + if(istype(head) && head.visible_name) + return head.visible_name + else if(istype(mask) && mask.visible_name) + return mask.visible_name + else if(get_rig()?.visible_name) + return get_rig()?.visible_name + return "Unknown" + +/mob/living/proc/identity_is_visible() + if(has_genetic_condition(GENE_COND_HUSK)) + return FALSE + if(!real_name) + return FALSE + var/obj/item/clothing/mask/mask = get_equipped_item(slot_wear_mask_str) + var/obj/item/head = get_equipped_item(slot_head_str) + if((mask?.flags_inv & HIDEFACE) || (head?.flags_inv & HIDEFACE)) + return FALSE + if(should_have_limb(BP_HEAD)) + var/obj/item/organ/external/skull = GET_EXTERNAL_ORGAN(src, BP_HEAD) + if(!skull || (skull.status & ORGAN_DISFIGURED)) //Face is unrecognizeable + return FALSE + return TRUE + +/mob/living/get_default_temperature_threshold(threshold) + if(isSynthetic()) + switch(threshold) + if(COLD_LEVEL_1) + return SYNTH_COLD_LEVEL_1 + if(COLD_LEVEL_2) + return SYNTH_COLD_LEVEL_2 + if(COLD_LEVEL_3) + return SYNTH_COLD_LEVEL_3 + if(HEAT_LEVEL_1) + return SYNTH_HEAT_LEVEL_1 + if(HEAT_LEVEL_2) + return SYNTH_HEAT_LEVEL_2 + if(HEAT_LEVEL_3) + return SYNTH_HEAT_LEVEL_3 + else + CRASH("synthetic get_default_temperature_threshold() called with invalid threshold value.") + return ..() + +// TODO: Generalize by looping over inventory slots/bodyparts/etc. and checking coverage. +/mob/living/clean(clean_forensics = TRUE) + + SHOULD_CALL_PARENT(FALSE) + + for(var/obj/item/thing in get_held_items()) + thing.clean() + + var/obj/item/back = get_equipped_item(slot_back_str) + if(back) + back.clean() + + //flush away reagents on the skin + var/datum/reagents/touching_reagents = get_contact_reagents() + if(touching_reagents) + var/remove_amount = REAGENT_MAXIMUM_VOLUME(touching_reagents) * reagent_permeability() //take off your suit first + touching_reagents.remove_any(remove_amount) + + var/obj/item/mask = get_equipped_item(slot_wear_mask_str) + if(mask) + mask.clean() + + var/washgloves = TRUE + var/washshoes = TRUE + var/washmask = TRUE + var/washears = TRUE + var/washglasses = TRUE + + var/obj/item/suit = get_equipped_item(slot_wear_suit_str) + if(suit) + washgloves = !(suit.flags_inv & HIDEGLOVES) + washshoes = !(suit.flags_inv & HIDESHOES) + + var/obj/item/head = get_equipped_item(slot_head_str) + if(head) + washmask = !(head.flags_inv & HIDEMASK) + washglasses = !(head.flags_inv & HIDEEYES) + washears = !(head.flags_inv & HIDEEARS) + + if(mask) + if (washears) + washears = !(mask.flags_inv & HIDEEARS) + if (washglasses) + washglasses = !(mask.flags_inv & HIDEEYES) + + if(head) + head.clean() + + if(suit) + suit.clean() + else + var/obj/item/uniform = get_equipped_item(slot_w_uniform_str) + if(uniform) + uniform.clean() + + if(washgloves) + var/obj/item/gloves = get_equipped_item(slot_gloves_str) + if(gloves) + gloves.clean() + else // can't clean your hands with gloves on + for(var/organ_tag in get_held_item_slots()) + var/obj/item/organ/external/organ = get_organ(organ_tag) + if(organ) + organ.clean() + germ_level = 0 + update_equipment_overlay(slot_gloves_str, FALSE) // clear bloody hands overlay + + if(washshoes) + var/obj/item/shoes = get_equipped_item(slot_shoes_str) + if(shoes) + shoes.clean() + else // no shoes, wash feet + var/static/list/clean_slots = list(BP_L_FOOT, BP_R_FOOT) + for(var/organ_tag in clean_slots) + var/obj/item/organ/external/organ = get_organ(organ_tag) + if(organ) + organ.clean() + update_equipment_overlay(slot_shoes_str, FALSE) // clear bloody feet overlay + + if(mask && washmask) + mask.clean() + + if(washglasses) + var/obj/item/glasses = get_equipped_item(slot_glasses_str) + if(glasses) + glasses.clean() + + if(washears) + var/obj/item/ear = get_equipped_item(slot_l_ear_str) + if(ear) + ear.clean() + ear = get_equipped_item(slot_r_ear_str) + if(ear) + ear.clean() + + var/obj/item/belt = get_equipped_item(slot_belt_str) + if(belt) + belt.clean() + + return TRUE + +/mob/living/proc/can_direct_mount(var/mob/user) + if((user.faction == faction || !faction) && can_buckle && istype(user) && !user.incapacitated() && user == buckled_mob) + if(client && !check_intent(I_FLAG_HELP)) + return FALSE // do not Ratatouille your colleagues + // TODO: Piloting skillcheck for hands-free moving? Stupid but amusing + for(var/obj/item/grab/reins in user.get_held_items()) + if(istype(reins.current_grab, /decl/grab/simple/control) && reins.get_affecting_mob() == src) + return TRUE + return FALSE + +/mob/living/handle_buckled_relaymove(var/datum/movement_handler/mh, var/mob/mob, var/direction, var/mover) + if(can_direct_mount(mob)) + if(HAS_STATUS(mob, STAT_CONFUSE)) + direction = turn(direction, pick(90, -90)) + SelfMove(direction) + return MOVEMENT_HANDLED + +/mob/living/show_buckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + visible_message(SPAN_NOTICE("\The [buckled] climbs onto \the [src].")) + else + visible_message(SPAN_NOTICE("\The [buckled] is lifted onto \the [src] by \the [buckling].")) + +/mob/living/show_unbuckle_message(var/mob/buckled, var/mob/buckling) + if(buckled == buckling) + visible_message(SPAN_NOTICE("\The [buckled] steps down from \the [src].")) + else + visible_message(SPAN_NOTICE("\The [buckled] is pulled off \the [src] by \the [buckling].")) + +/mob/living/buckle_mob(mob/living/M) + . = ..() + if(buckled_mob) + buckled_mob.reset_layer() + for(var/obj/item/grab/grab in buckled_mob.get_held_items()) + if(grab.get_affecting_mob() == src && !istype(grab.current_grab, /decl/grab/simple/control)) + qdel(grab) + if(istype(ai)) + ai.on_buckled(M) + reset_layer() + update_icon() + +/mob/living/unbuckle_mob() + . = ..() + reset_layer() + update_icon() + +/mob/living/try_make_grab(mob/living/user, defer_hand = FALSE) + . = ..() + if(istype(ai)) + ai.on_grabbed(user) + +/mob/living/can_buckle_mob(var/mob/living/dropping) + . = ..() && stat == CONSCIOUS && !buckled && dropping.mob_size <= mob_size + +/mob/living/OnSimulatedTurfEntered(turf/T, old_loc) + T.add_dirt(0.5) + + handle_walking_tracks(T, old_loc) + + if(current_posture.prone) + return + + var/turf_wet = T.get_wetness() + if(turf_wet <= 0) + return + + if(buckled || (MOVING_DELIBERATELY(src) && prob(min(100, 100/(turf_wet/10))))) + return + + // skillcheck for slipping + if(!prob(min(100, skill_fail_chance(SKILL_HAULING, 100, SKILL_MAX+1)/(3/turf_wet)))) + return + + var/slip_dist = 1 + var/slip_stun = 6 + var/floor_type = "wet" + + if(2 <= turf_wet) // Lube + floor_type = "slippery" + slip_dist = 4 + slip_stun = 10 + + // Dir check to avoid slipping up and down via ladders. + if(slip("the [floor_type] floor", slip_stun) && (dir in global.cardinal)) + for(var/i = 1 to slip_dist) + step(src, dir) + sleep(1) + +/mob/living/proc/handle_walking_tracks(turf/T, old_loc) + + if(!T.can_show_coating_footprints()) + return + + // Tracking blood or other contaminants + var/obj/item/source + var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str) + if(istype(shoes)) + shoes.handle_movement(src, MOVING_QUICKLY(src)) + if(shoes.coating && REAGENT_TOTAL_VOLUME(shoes.coating) > 1) + source = shoes + else + for(var/obj/item/organ/external/stomper in get_organs_by_categories(global.child_stance_limbs)) + if(REAGENT_TOTAL_VOLUME(stomper.coating) > 1) + source = stomper + break + + var/decl/species/my_species = get_species() + if(!source) + my_species?.handle_trail(src, T, old_loc) + return + + var/use_move_trail = my_species?.get_move_trail(src) + if(!use_move_trail) + return + + if(!istype(source.coating)) + return + + var/decl/material/contaminant = UNLINT(source.coating.reagent_volumes[1]) // take [1] instead of primary reagent to match what remove_any will probably remove + if(!T.can_show_coating_footprints(contaminant)) + return + /// An associative list of DNA unique enzymes -> blood type. Used by forensics, mostly. + var/list/bloodDNA = list() + var/track_color + var/list/source_data = REAGENT_DATA(source.coating, contaminant) + if(source_data && source_data[DATA_BLOOD_DNA] && source_data[DATA_BLOOD_TYPE]) + bloodDNA = list(source_data[DATA_BLOOD_DNA] = source_data[DATA_BLOOD_TYPE]) + track_color = source.coating.get_color() + T.AddTracks(use_move_trail, bloodDNA, dir, 0, track_color, contaminant.type) // Coming + if(isturf(old_loc)) + var/turf/old_turf = old_loc + if(old_turf.can_show_coating_footprints(contaminant)) + old_turf.AddTracks(use_move_trail, bloodDNA, 0, dir, track_color, contaminant.type) // Going + source.remove_coating(1) + update_equipment_overlay(slot_shoes_str) + +/mob/living/proc/handle_general_grooming(user, obj/item/grooming/tool) + if(tool.grooming_flags & (GROOMABLE_BRUSH|GROOMABLE_COMB)) + visible_message(SPAN_NOTICE(tool.replace_message_tokens((user == src) ? tool.message_target_self_generic : tool.message_target_other_generic, user, src, tool))) + add_stressor(/datum/stressor/well_groomed, 5 MINUTES) + return TRUE + return FALSE + +/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, datum/callback/callback) //If this returns FALSE then callback will not be called. + return !length(pinned) && ..() + +/mob/living/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected) + + LAZYREMOVE(embedded, implant) + + if(!LAZYLEN(get_visible_implants(0))) //Yanking out last object - removing verb. + verbs -= /mob/proc/yank_out_object + + for(var/obj/item/O in pinned) + if(O == implant) + LAZYREMOVE(pinned, O) + if(!LAZYLEN(pinned)) + anchored = FALSE + implant.dropInto(loc) + implant.add_blood(src) + implant.update_icon() + if(istype(implant,/obj/item/implant)) + var/obj/item/implant/imp = implant + imp.removed() + + if(!affected) //Grab the organ holding the implant. + for(var/obj/item/organ/external/organ in get_external_organs()) + for(var/obj/item/O in organ.implants) + if(O == implant) + affected = organ + break + if(affected) + LAZYREMOVE(affected.implants, implant) + for(var/datum/wound/wound in affected.wounds) + LAZYREMOVE(wound.embedded_objects, implant) + if(!surgical_removal) + affected.take_damage((implant.w_class * 3), damage_flags = DAM_EDGE, inflicter = "Embedded object extraction") + if(!BP_IS_PROSTHETIC(affected) && prob(implant.w_class * 5) && affected.sever_artery()) //I'M SO ANEMIC I COULD JUST -DIE-. + custom_pain("Something tears wetly in your [affected.name] as [implant] is pulled free!", 50, affecting = affected) + + return TRUE + +/mob/living/proc/get_footstep_sound(turf/step_turf) + return step_turf?.get_footstep_sound(src) + +/mob/living/proc/has_footsteps() + return FALSE + +/mob/living/handle_footsteps() + + if(stat || buckled || current_posture?.prone || throwing || !has_footsteps()) + return + + step_count++ + //every other turf makes a sound + if((step_count % 2) && !MOVING_DELIBERATELY(src)) + return + + // don't need to step as often when you hop around + if((step_count % 3) && !has_gravity()) + return + + var/turf/T = get_turf(src) + if(!T) + return + + var/footsound = get_footstep_sound(T) + if(!footsound) + return + + var/range = world.view - 2 + var/step_volume = 70 + if(MOVING_DELIBERATELY(src)) + step_volume -= 45 + range -= 0.333 + + var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str) + step_volume = round(modify_footstep_volume(step_volume, shoes)) + range = round(modify_footstep_range(range, shoes)) + if(step_volume > 0 && range > 0) + playsound(T, footsound, step_volume, 1, range) + +/mob/living/proc/modify_footstep_volume(step_volume, obj/item/clothing/shoes/shoes) + if(istype(shoes)) + return step_volume * shoes.footstep_volume_mod + if(!shoes) + return step_volume - 60 + return step_volume + +/mob/living/proc/modify_footstep_range(range, obj/item/clothing/shoes/shoes) + if(istype(shoes)) + return range * shoes.footstep_range_mod + if(!shoes) + return range * range - 0.333 + return range + +/mob/living/handle_flashed(var/flash_strength, do_stun = TRUE) + + var/safety = eyecheck() + var/flash_burn = get_flash_burn() + var/flash_mod = get_flash_mod() + + if(safety >= FLASH_PROTECTION_MODERATE || flash_strength <= 0 || flash_mod <= 0) // May be modified by human proc. + return FALSE + + flash_eyes(FLASH_PROTECTION_MODERATE - safety) + if(do_stun) + SET_STATUS_MAX(src, STAT_STUN, (flash_strength / 2)) + SET_STATUS_MAX(src, STAT_BLURRY, flash_strength) + SET_STATUS_MAX(src, STAT_CONFUSE, (flash_strength + 2)) + + if(flash_burn > 0) + apply_damage(flash_strength * flash_burn/5, BURN, BP_HEAD, used_weapon = "Photon burns") + if(flash_strength > 3) + drop_held_items() + if(flash_strength > 5) + SET_STATUS_MAX(src, STAT_WEAK, 2) + return TRUE + +/mob/living/verb/showoff() + set name = "Show Held Item" + set category = "Object" + + var/obj/item/I = get_active_held_item() + if(I && I.simulated) + I.showoff(src) + +/mob/living/relaymove(var/mob/living/user, direction) + if(!istype(user) || !(user in contents) || user.is_on_special_ability_cooldown()) + return + user.set_special_ability_cooldown(5 SECONDS) + visible_message(SPAN_DANGER("You hear something rumbling inside [src]'s stomach...")) + var/obj/item/I = user.get_active_held_item() + var/force = I?.expend_attack_force(user) + if(!force) + return + var/d = rand(round(force / 4), force) + visible_message(SPAN_DANGER("\The [user] attacks [src]'s stomach wall with \the [I]!")) + playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1) + var/obj/item/organ/external/organ = GET_EXTERNAL_ORGAN(src, BP_CHEST) + if(istype(organ)) + organ.take_damage(d) + else + take_organ_damage(d) + if(prob(get_damage(BRUTE) - 50)) + gib() + +/mob/living/hud_reset(full_reset = FALSE) + if((. = ..())) + queue_hand_rebuild() + +/mob/living/get_movement_delay(var/travel_dir) + . = ..() + if(stance_damage) + . += max(2 * stance_damage, 0) //damaged/missing feet or legs is slow + +/mob/living/proc/find_mob_supporting_object() + for(var/turf/T as anything in RANGE_TURFS(src, 1)) + if(T.density && T.simulated) + return TRUE + for(var/obj/O in orange(1, src)) + if((O.obj_flags & OBJ_FLAG_SUPPORT_MOB) || (O.density && O.anchored)) + return TRUE + return FALSE + +/mob/living/proc/is_asystole() + return FALSE + +/mob/living/proc/get_remains_type() + var/decl/species/my_species = get_species() + return my_species?.remains_type + +/mob/living/verb/mob_sleep() + set name = "Sleep" + set category = "IC" + + if(alert("Are you sure you want to [player_triggered_sleeping ? "wake up?" : "sleep for a while? Use 'sleep' again to wake up"]", "Sleep", "No", "Yes") == "Yes") + player_triggered_sleeping = !player_triggered_sleeping + +/mob/living/Stat() + . = ..() + if(statpanel("Status") && length(stat_organs)) + for(var/obj/item/organ/organ in stat_organs) + var/list/organ_info = organ.get_stat_info() + stat(organ_info[1], organ_info[2]) + +/mob/living/force_update_limbs() + for(var/obj/item/organ/external/O in get_external_organs()) + O.sync_colour_to_human(src) + update_body(0) + +/mob/living/proc/get_vision_organ_tag() + return get_bodytype()?.vision_organ + +/mob/living/proc/get_darksight_range() + var/vision_organ_tag = get_vision_organ_tag() + if(vision_organ_tag) + var/obj/item/organ/internal/eyes/I = get_organ(vision_organ_tag, /obj/item/organ/internal/eyes) + if(istype(I)) + return I.get_darksight_range() + return get_bodytype()?.eye_darksight_range + +/mob/living/proc/can_act() + return !QDELETED(src) && !incapacitated() + +// Currently only used by AI behaviors +/mob/living/proc/has_ranged_attack() + return FALSE + +/mob/living/proc/get_ranged_attack_distance() + return 0 + +/mob/living/proc/handle_ranged_attack(atom/target) + if(istype(target)) + for(var/obj/item/gun/gun in get_held_items()) + gun.afterattack(target, src, target.Adjacent(src)) + return TRUE + return FALSE + +/mob/living/proc/can_pry_door() + return FALSE + +/mob/living/proc/get_door_pry_time() + return 7 SECONDS + +/mob/living/proc/pry_door(delay, obj/machinery/door/target) + return + +/mob/living/proc/turf_is_safe(turf/target) + if(!istype(target)) + return FALSE + if(target.is_open() && target.has_gravity() && !can_overcome_gravity()) + return FALSE + return TRUE + +/mob/living/proc/get_attack_telegraph_delay() + return 0 + +/mob/living/proc/get_base_telegraphed_melee_accuracy() + return 85 + +/mob/living/proc/get_telegraphed_melee_accuracy() + return clamp(get_base_telegraphed_melee_accuracy() - melee_accuracy_mods(), 0, 100) + +// This will generally only be invoked by AI driven mobs. Player humans do not show the windup. +/mob/living/do_attack_windup_checking(atom/target) + + var/attack_delay = get_attack_telegraph_delay() + if(attack_delay <= 0) + return TRUE + + var/decl/pronouns/pronouns = get_pronouns() + setClickCooldown(attack_delay) + face_atom(target) + + stop_automove() // Cancel any baked-in movement. + do_windup_animation(target, attack_delay, no_reset = TRUE) + if(!do_after(src, attack_delay, target) || !Adjacent(target)) + visible_message(SPAN_NOTICE("\The [src] misses [pronouns.his] attack on \the [target]!")) + reset_offsets(anim_time = 2) + ai?.move_to_target(TRUE) // Restart hostile mob tracking. + return FALSE + + ai?.move_to_target(TRUE) // Restart hostile mob tracking. + if(ismob(target)) + // Clientless mobs are too dum to move away, so they can be missed. + var/mob/mob = target + if(!mob.ckey && !prob(get_telegraphed_melee_accuracy())) + visible_message(SPAN_NOTICE("\The [src] misses [pronouns.his] attack on \the [target]!")) + reset_offsets(anim_time = 2) + return FALSE + + ai?.update_target_zone() + reset_offsets(anim_time = 2) + return TRUE + +/mob/living/proc/prepare_for_despawn() + //Update any existing objectives involving this mob. + for(var/datum/objective/objective in global.all_objectives) + // We don't want revs to get objectives that aren't for heads of staff. Letting + // them win or lose based on cryo is silly so we remove the objective. + if(objective.target == mind) + if(objective.owner?.current) + to_chat(objective.owner.current, SPAN_DANGER("You get the feeling your target, [real_name], is no longer within your reach...")) + qdel(objective) + //Handle job slot/tater cleanup. + if(mind) + if(mind.assigned_job) + mind.assigned_job.clear_slot() + if(mind.objectives.len) + mind.objectives = null + mind.assigned_special_role = null + // Delete them from datacore. + var/datum/computer_file/report/crew_record/record = get_crewmember_record(sanitize(real_name)) + if(record) + qdel(record) + return TRUE + +/mob/living/proc/get_preview_screen_locs() + for(var/obj/item/gear in get_equipped_items()) + var/screen_locs = gear.get_preview_screen_locs() + if(screen_locs) + return screen_locs + var/decl/bodytype/my_bodytype = get_bodytype() + return my_bodytype?.character_preview_screen_locs + +/mob/living/can_twohand_item(obj/item/item) + if(!istype(item) || !item.can_be_twohanded) + return FALSE + if(incapacitated()) + return FALSE + if(mob_size < item.minimum_size_to_twohand || (!isnull(item.maximum_size_to_twohand) && mob_size > item.maximum_size_to_twohand)) + return FALSE + for(var/empty_hand in get_empty_hand_slots()) + var/datum/inventory_slot/gripper/slot = get_inventory_slot_datum(empty_hand) + if(!istype(slot)) + continue + var/req_item_dex = item.get_required_attack_dexterity(src) + if(slot.requires_organ_tag) + var/obj/item/organ/external/hand = GET_EXTERNAL_ORGAN(src, slot.requires_organ_tag) + if(istype(hand) && hand.is_usable() && (!req_item_dex || hand.get_manual_dexterity() >= req_item_dex)) + return TRUE + else if(!req_item_dex || slot.dexterity >= req_item_dex) + return TRUE + return FALSE + +/mob/living/proc/flee(atom/target, upset = FALSE) + var/static/datum/automove_metadata/_flee_automove_metadata = new( + _move_delay = null, + _acceptable_distance = 7, + _avoid_target = TRUE + ) + var/static/datum/automove_metadata/_annoyed_automove_metadata = new( + _move_delay = null, + _acceptable_distance = 2, + _avoid_target = TRUE + ) + if(upset) + set_moving_quickly() + else + set_moving_slowly() + start_automove(target, metadata = upset ? _flee_automove_metadata : _annoyed_automove_metadata) + +/mob/living/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(has_extension(src, /datum/extension/shearable)) + var/datum/extension/shearable/shearable = get_extension(src, /datum/extension/shearable) + if(world.time >= shearable.next_fleece || shearable.has_fleece) + . += SPAN_NOTICE("\The [src] can be sheared with shears, or a similar tool.") + else + . += SPAN_WARNING("\The [src] will be ready to be sheared in [ceil((shearable.next_fleece-world.time) / 10)] second\s.") + if(has_extension(src, /datum/extension/milkable)) + var/datum/extension/milkable/milkable = get_extension(src, /datum/extension/milkable) + if(REAGENT_TOTAL_VOLUME(milkable.udder) > 0) + . += SPAN_NOTICE("\The [src] can be milked into a bucket or other container.") + else + . += SPAN_WARNING("\The [src] cannot currently be milked.") + +/mob/living/proc/get_age() + . = LAZYACCESS(appearance_descriptors, "age") || 30 + +/mob/living/proc/get_walking_contaminant_targets() + var/obj/item/clothing/shoes/shoes = get_equipped_item(slot_shoes_str) + if(istype(shoes)) + if(!buckled) + return list(shoes) + else + return get_organs_by_categories(global.child_stance_limbs) + return null + +/// Adds `amount` units of `material_type` contaminant to whatever we're walking with, +/// be it shoes, normal human feet, dog paws, robot treads, a million millipede legs, +/// the sky's the limit. If multiple targets are returned from +/// `get_walking_contaminant_targets()`, then `amount` is split evenly +/// between them. +/mob/living/proc/add_walking_contaminant(material_type, amount, data) + if(amount <= 0) + return FALSE + var/list/obj/item/sources = get_walking_contaminant_targets() + if(!LAZYLEN(sources)) + return FALSE + var/amount_per = max(CHEMS_QUANTIZE(amount / length(sources)), MINIMUM_CHEMICAL_VOLUME) // don't let it round down to 0, always add something + for(var/obj/item/dirty_item in sources) + dirty_item.add_coating(material_type, amount_per, data) + // i don't like how hardcoded this is, it might be better to use RAISE_EVENT or something + // like /decl/observ/on_add_walking_contaminant or something + // or things should just update their worn slot when coating is added + update_equipment_overlay(slot_shoes_str) + return TRUE + +/mob/living/get_cell() + var/obj/item/organ/internal/cell/cell = get_organ(BP_CELL, /obj/item/organ/internal/cell) + return istype(cell) ? cell.cell : null + +/mob/living/verb/pull_punches() + set name = "Switch Stance" + set desc = "Try not to hurt them." + set category = "IC" + if(!incapacitated()) + pulling_punches = !pulling_punches + to_chat(src, SPAN_NOTICE("You are now [pulling_punches ? "pulling your punches" : "not pulling your punches"].")) + +/mob/living/is_cloaked() + return has_mob_modifier(/decl/mob_modifier/cloaked) + +/mob/living/proc/apply_random_mutation(radiation_amount) + set_unique_enzymes(num2text(random_id(/mob, 1000000, 9999999))) + if(prob(98)) + add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/disability))) + else + add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/superpower))) + if(radiation_amount) + apply_damage(radiation_amount, IRRADIATE, armor_pen = 100) + +// Used by specimen taggers to avoid tagging/overwriting players or named mobs like Runtime. +/mob/living/proc/is_tagging_suitable() + return !key && !client + diff --git a/code/modules/mob/living/living_allergies.dm b/code/modules/mob/living/living_allergies.dm new file mode 100644 index 000000000000..27a484a5d618 --- /dev/null +++ b/code/modules/mob/living/living_allergies.dm @@ -0,0 +1,64 @@ +/mob/living/proc/get_allergy_choke_emote() + var/decl/species/my_species = get_species() + if(length(my_species?.allergy_choke_emotes)) + return pick(my_species.allergy_choke_emotes) + +/mob/living/proc/get_allergy_faint_emote() + var/decl/species/my_species = get_species() + if(length(my_species?.allergy_choke_emotes)) + return pick(my_species.allergy_faint_emotes) + +/mob/living/proc/get_allergen_damage_severity() + var/decl/species/my_species = get_species() + return my_species?.allergen_damage_severity || 0 + +/mob/living/proc/get_allergen_disable_severity() + var/decl/species/my_species = get_species() + return my_species?.allergen_disable_severity || 0 + +/mob/living/proc/get_allergen_reaction_flags() + var/decl/species/my_species = get_species() + return my_species?.allergen_reaction || ALLERGEN_REACTION_NONE + +/mob/living/proc/handle_allergens() + + var/allergen_power = LAZYACCESS(chem_effects, CE_ALLERGEN) + if(allergen_power <= 0) + return FALSE + + var/allergen_reaction = get_allergen_reaction_flags() + if(!allergen_reaction) + return FALSE + + var/damage_severity = get_allergen_damage_severity() * allergen_power + var/disable_severity = get_allergen_disable_severity() * allergen_power + + if(allergen_reaction & ALLERGEN_REACTION_PHYS_DMG) + take_damage(damage_severity, BRUTE, armor_pen = 100) + if(allergen_reaction & ALLERGEN_REACTION_BURN_DMG) + take_damage(damage_severity, BURN, armor_pen = 100) + if(allergen_reaction & ALLERGEN_REACTION_TOX_DMG) + take_damage(damage_severity, TOX, armor_pen = 100) + if(allergen_reaction & ALLERGEN_REACTION_PAIN) + take_damage(disable_severity, PAIN, armor_pen = 100) + if(allergen_reaction & ALLERGEN_REACTION_OXY_DMG) + take_damage(damage_severity, OXY, armor_pen = 100) + if(prob(disable_severity/2)) + var/allergy_emote = get_allergy_choke_emote() + if(allergy_emote) + emote(allergy_emote) + + if(allergen_reaction & ALLERGEN_REACTION_EMOTE) + if(prob(disable_severity/2)) + var/allergy_emote = get_allergy_faint_emote() + if(allergy_emote) + emote(allergy_emote) + + if(allergen_reaction & ALLERGEN_REACTION_WEAKEN) + SET_STATUS_MAX(src, STAT_WEAK, disable_severity) + if(allergen_reaction & ALLERGEN_REACTION_BLURRY) + SET_STATUS_MAX(src, STAT_BLURRY, disable_severity) + if(allergen_reaction & ALLERGEN_REACTION_SLEEPY) + SET_STATUS_MAX(src, STAT_DROWSY, disable_severity) + if(allergen_reaction & ALLERGEN_REACTION_CONFUSE) + SET_STATUS_MAX(src, STAT_CONFUSE, ceil(disable_severity/4)) diff --git a/code/modules/mob/living/living_appearance.dm b/code/modules/mob/living/living_appearance.dm new file mode 100644 index 000000000000..0b34b88f1405 --- /dev/null +++ b/code/modules/mob/living/living_appearance.dm @@ -0,0 +1,89 @@ +/mob/living + var/list/mob_overlays[TOTAL_OVER_LAYERS] + var/list/mob_underlays[TOTAL_UNDER_LAYERS] + +/mob/living/update_icon() + ..() + compile_overlays() + +/mob/living/on_update_icon() + SHOULD_CALL_PARENT(TRUE) + ..() + cut_overlays() + try_refresh_visible_overlays() + +/mob/living/proc/set_organ_sprite_accessory(var/accessory_type, var/accessory_category, var/accessory_metadata, var/organ_tag, var/skip_update = FALSE) + if(!accessory_category || !organ_tag) + return + var/obj/item/organ/external/organ = organ_tag && GET_EXTERNAL_ORGAN(src, organ_tag) + if(!organ) + return + if(!accessory_type) + accessory_type = organ.get_sprite_accessory_by_category(accessory_category) + if(accessory_type) + return organ.set_sprite_accessory(accessory_type, accessory_category, accessory_metadata, skip_update) + +/mob/living/proc/get_organ_sprite_accessory_metadata(var/accessory_type, var/organ_tag, var/metadata_tag) + var/obj/item/organ/external/organ = organ_tag && GET_EXTERNAL_ORGAN(src, organ_tag) + return organ?.get_sprite_accessory_metadata(accessory_type, metadata_tag) + +/mob/living/proc/get_organ_sprite_accessory_by_category(var/accessory_category, var/organ_tag) + var/obj/item/organ/external/organ = organ_tag && GET_EXTERNAL_ORGAN(src, organ_tag) + return organ?.get_sprite_accessory_by_category(accessory_category) + +/mob/living/proc/set_organ_sprite_accessory_by_category(var/accessory_type, var/accessory_category, var/accessory_metadata, var/preserve_colour = TRUE, var/preserve_type = TRUE, var/organ_tag, var/skip_update = FALSE) + var/obj/item/organ/external/organ = organ_tag && GET_EXTERNAL_ORGAN(src, organ_tag) + return organ?.set_sprite_accessory_by_category(accessory_type, accessory_category, accessory_metadata, preserve_colour, preserve_type, skip_update) + +/mob/living/proc/get_skin_colour() + return + +/mob/living/proc/set_skin_colour(var/new_color, var/skip_update = FALSE) + return get_skin_colour() != new_color + +/mob/living/proc/get_eye_colour() + return COLOR_WHITE + +/mob/living/proc/set_eye_colour(var/new_color, var/skip_update = FALSE) + return get_eye_colour() != new_color + +/mob/living/get_all_current_mob_overlays() + return mob_overlays + +/mob/living/set_current_mob_overlay(var/overlay_layer, var/image/overlay, var/redraw_mob = TRUE) + mob_overlays[overlay_layer] = overlay + ..() + +/mob/living/get_current_mob_overlay(var/overlay_layer) + return mob_overlays[overlay_layer] + +/mob/living/get_all_current_mob_underlays() + return mob_underlays + +/mob/living/set_current_mob_underlay(var/underlay_layer, var/image/underlay, var/redraw_mob = TRUE) + mob_underlays[underlay_layer] = underlay + ..() + +/mob/living/get_current_mob_underlay(var/underlay_layer) + return mob_underlays[underlay_layer] + +/mob/living/refresh_visible_overlays() + . = ..() + var/list/modifier_overlays = null + for(var/decl/mob_modifier/archetype in _mob_modifiers) + var/image/status_overlay = archetype.get_modifier_mob_overlay(src) + if(status_overlay) + LAZYADD(modifier_overlays, status_overlay) + set_current_mob_overlay(HO_EFFECT_LAYER, modifier_overlays, FALSE) + +/decl/mob_modifier/proc/get_modifier_mob_overlay(mob/living/_owner) + if(!mob_overlay_icon || !mob_overlay_state || !istype(_owner)) + return null + var/image/mob_overlay = overlay_image(mob_overlay_icon, mob_overlay_state, COLOR_WHITE, RESET_COLOR) + var/decl/bodytype/owner_bodytype = _owner.get_bodytype() + if(owner_bodytype) + if(owner_bodytype.pixel_offset_x) + mob_overlay.pixel_x += -(owner_bodytype.pixel_offset_x) + if(owner_bodytype.pixel_offset_y) + mob_overlay.pixel_y += -(owner_bodytype.pixel_offset_y) + return mob_overlay diff --git a/code/modules/mob/living/living_attackhand.dm b/code/modules/mob/living/living_attackhand.dm new file mode 100644 index 000000000000..52cce7e49af7 --- /dev/null +++ b/code/modules/mob/living/living_attackhand.dm @@ -0,0 +1,135 @@ +/mob/living/attack_hand(mob/user) + // Allow grabbing a mob that you are buckled to, so that you can generate a control grab (for riding). + if(buckled == user && user.check_intent(I_FLAG_GRAB)) + return try_make_grab(user) + return ..() || (user && default_interaction(user)) + +/mob/living/proc/default_interaction(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + if(user.check_intent(I_FLAG_HARM)) + . = default_hurt_interaction(user) + else if(user.check_intent(I_FLAG_HELP)) + . = default_help_interaction(user) + else if(user.check_intent(I_FLAG_DISARM)) + . = default_disarm_interaction(user) + else if(user.check_intent(I_FLAG_GRAB)) + . = default_grab_interaction(user) + +/mob/living/proc/default_hurt_interaction(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + // TODO: integrate/generalize this ugly code instead of using boilerplate from + // simple_animal/UnarmedAttack() due to complexities with existing proc flow. + if(isanimal(user)) + var/mob/living/simple_animal/predator = user + var/obj/item/attacking_with = predator.get_natural_weapon() + if(attacking_with) + attackby(attacking_with, predator) + else + attack_animal(predator) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return TRUE + return FALSE + +/mob/living/proc/default_help_interaction(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + if(try_extinguish(user)) + return TRUE + if(try_awaken(user)) + return TRUE + return FALSE + +/mob/living/proc/default_disarm_interaction(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + return FALSE + +/mob/living/proc/default_grab_interaction(var/mob/user) + SHOULD_CALL_PARENT(TRUE) + return scoop_check(user) ? get_scooped(user, user) : try_make_grab(user) + +// This proc is where movable atoms handle being grabbed, but we handle it additionally in +// default_grab_interaction, so we override it here to return FALSE and avoid double-grabbing. +/mob/living/handle_grab_interaction(var/mob/user) + return FALSE + +// Returns TRUE if further interactions should be halted, FALSE otherwise. +/mob/living/proc/try_extinguish(mob/living/user) + if (!is_on_fire() || !istype(user)) + return FALSE + + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if (user.is_on_fire()) + user.visible_message( + SPAN_WARNING("\The [user] tries to pat out \the [src]'s flames, but to no avail!"), + SPAN_WARNING("You try to pat out [src]'s flames, but to no avail! Put yourself out first!") + ) + return TRUE + + user.visible_message( + SPAN_WARNING("\The [user] tries to pat out \the [src]'s flames!"), + SPAN_WARNING("You try to pat out \the [src]'s flames! Hot!") + ) + + if(!do_mob(user, src, 15)) + return TRUE + + adjust_fire_intensity(-0.5) + if (prob(10) && (user.get_fire_intensity() <= 0)) + user.adjust_fire_intensity(1) + user.ignite_fire() + if (user.is_on_fire()) + user.visible_message( + SPAN_DANGER("The fire spreads from \the [src] to \the [user]!"), + SPAN_DANGER("The fire spreads to you as well!") + ) + return TRUE + + adjust_fire_intensity(-0.5) //Less effective than stop, drop, and roll - also accounting for the fact that it takes half as long. + if (get_fire_intensity() <= 0) + user.visible_message( + SPAN_NOTICE("\The [user] successfully pats out \the [src]'s flames."), + SPAN_NOTICE("You successfully pat out \the [src]'s flames.") + ) + extinguish_fire() + set_fire_intensity(0) + + return TRUE + +// Returns TRUE if further interactions should be halted, FALSE otherwise. +/mob/living/proc/try_awaken(mob/user) + + var/decl/pronouns/pronouns = get_pronouns() + var/obj/item/uniform = get_equipped_item(slot_w_uniform_str) + if(uniform) + uniform.add_fingerprint(user) + + // They're SSD, so permanently asleep. + if(ssd_check() && get_species()?.get_ssd(src)) + user.visible_message( + SPAN_NOTICE("\The [user] shakes \the [src] trying to wake [pronouns.him] up!"), + SPAN_NOTICE("You shake \the [src], but they do not respond...") + ) + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + . = TRUE + + // Not SSD, so try to wake them up. + else if(current_posture?.prone || HAS_STATUS(src, STAT_ASLEEP) || player_triggered_sleeping) + player_triggered_sleeping = FALSE + ADJ_STATUS(src, STAT_ASLEEP, -5) + if(!HAS_STATUS(src, STAT_ASLEEP)) + set_posture(/decl/posture/lying) // overrides 'delibrate' lying so you will stand up if possible. + user.visible_message( + SPAN_NOTICE("\The [user] shakes \the [src] trying to wake [pronouns.him] up!"), + SPAN_NOTICE("You shake \the [src] trying to wake [pronouns.him] up!") + ) + . = TRUE + + if(.) + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if(stat != DEAD) + ADJ_STATUS(src, STAT_PARA, -3) + ADJ_STATUS(src, STAT_STUN, -3) + ADJ_STATUS(src, STAT_WEAK, -3) + return + + // Fallback. + return user.attempt_hug(src) diff --git a/code/modules/mob/living/living_blood.dm b/code/modules/mob/living/living_blood.dm new file mode 100644 index 000000000000..bdd172360d72 --- /dev/null +++ b/code/modules/mob/living/living_blood.dm @@ -0,0 +1,41 @@ +//Transfers blood from container to vessels +/mob/living/proc/inject_blood(var/amount, var/datum/reagents/donor) + var/decl/species/my_species = get_species() + if(!my_species?.blood_volume) + return //Don't divide by 0 + var/injected_data = REAGENT_DATA(donor, my_species.blood_reagent) + var/chems = LAZYACCESS(injected_data, DATA_BLOOD_TRACE_CHEM) + for(var/C in chems) + add_to_reagents(C, (text2num(chems[C]) / my_species.blood_volume) * amount)//adds trace chemicals to owner's blood + +/mob/living/get_blood_data() + + var/data = ..() + data[DATA_BLOOD_DNA] = get_unique_enzymes() + data[DATA_BLOOD_TYPE] = get_blood_type() + var/species_name = get_species_name() + if(species_name) + data[DATA_BLOOD_SPECIES] = species_name + + var/list/temp_chem = list() + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + temp_chem[reagent.type] = REAGENT_VOLUME(reagents, reagent) + data[DATA_BLOOD_TRACE_CHEM] = temp_chem + data[DATA_BLOOD_DOSE_CHEM] = _chem_doses?.Copy() || list() + + if(isSynthetic()) + data[DATA_BLOOD_HAS_OXY] = FALSE + data[DATA_BLOOD_COLOR] = SYNTH_BLOOD_COLOR + else + data[DATA_BLOOD_HAS_OXY] = get_blood_oxy() + data[DATA_BLOOD_COLOR] = get_blood_color() + return data + +/mob/living/proc/is_blood_incompatible(their_blood_type) + var/decl/blood_type/my_blood = get_blood_type_by_name(get_blood_type()) + return !istype(my_blood) || !my_blood.can_take_donation_from(get_blood_type_by_name(their_blood_type)) + +/mob/living/get_gibber_type() + if(mob_size <= MOB_SIZE_TINY) + return isSynthetic() ? /obj/effect/decal/cleanable/blood/gibs/robot : /obj/effect/decal/cleanable/blood/gibs + return isSynthetic() ? /obj/effect/gibspawner/robot : /obj/effect/gibspawner/generic diff --git a/code/modules/mob/living/living_bodytemp.dm b/code/modules/mob/living/living_bodytemp.dm new file mode 100644 index 000000000000..0d9d6c6c41b5 --- /dev/null +++ b/code/modules/mob/living/living_bodytemp.dm @@ -0,0 +1,48 @@ +/mob/living/proc/has_metabolic_thermoregulation() + if(isSynthetic()) + return FALSE + var/decl/species/my_species = get_species() + if(my_species?.body_temperature == null) + return FALSE + return TRUE + +/mob/living/proc/get_bodytemperature_difference() + var/decl/species/my_species = get_species() + if(my_species) + return (my_species.body_temperature - bodytemperature) + return 0 + +/mob/living/proc/stabilize_body_temperature() + + // This species doesn't have metabolic thermoregulation and can't adjust towards a baseline. + if(!has_metabolic_thermoregulation()) + return + + // We may produce heat naturally. + var/decl/species/my_species = get_species() + if(my_species?.passive_temp_gain) + bodytemperature += my_species.passive_temp_gain + + var/body_temperature_difference = get_bodytemperature_difference() + if (abs(body_temperature_difference) < 0.5) + return //fuck this precision + + var/cold_1 = get_mob_temperature_threshold(COLD_LEVEL_1) + var/heat_1 = get_mob_temperature_threshold(HEAT_LEVEL_1) + if(bodytemperature < cold_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects. + var/nut_remove = 10 * DEFAULT_HUNGER_FACTOR + if(get_nutrition() >= nut_remove) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up. + adjust_nutrition(-nut_remove) + bodytemperature += max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM) + else if(cold_1 <= bodytemperature && bodytemperature <= heat_1) + bodytemperature += body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR + else if(bodytemperature > heat_1) //360.15 is 310.15 + 50, the temperature where you start to feel effects. + var/hyd_remove = 10 * DEFAULT_THIRST_FACTOR + if(get_hydration() >= hyd_remove) + adjust_hydration(-hyd_remove) + bodytemperature += min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) + +/// This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, SLOT_UPPER_BODY, SLOT_LOWER_BODY, etc. +/// Temperature parameter is the temperature you're being exposed to. +/mob/living/proc/get_heat_protection_flags(temperature) + return 0 diff --git a/code/modules/mob/living/living_breath.dm b/code/modules/mob/living/living_breath.dm new file mode 100644 index 000000000000..2731659ccbf1 --- /dev/null +++ b/code/modules/mob/living/living_breath.dm @@ -0,0 +1,163 @@ +/mob/living/proc/handle_breathing() + if(should_breathe() && need_breathe()) + try_breathe() + return TRUE + return FALSE + +/mob/living/proc/need_breathe() + if(has_genetic_condition(GENE_COND_NO_BREATH)) + return FALSE + var/decl/bodytype/root_bodytype = get_bodytype() + if(!root_bodytype || !root_bodytype.breathing_organ || !should_have_organ(root_bodytype.breathing_organ)) + return FALSE + return TRUE + +/mob/living/proc/should_breathe() + return ((life_tick % 2) == 0 || failed_last_breath || is_asystole()) + +// These procs all have a lung organ as an argument to avoid having to do repeated get_bodytype and get_organ calls. +// It's a small optimization but it adds up if you have a lot of mobs breathing. + +/// This proc contains all of the logic for returning a gasmix datum to be used in other breath-related code. +/// Does not necessarily involve inhaling at all; that's obtain_new_breath()'s job. +/mob/living/proc/get_breath(obj/item/organ/internal/lungs/lungs) + // Handle optional pre-breath logic. If it returns TRUE, skip the breath entirely. + if(handle_pre_breath(lungs)) + return null + return obtain_new_breath(lungs) + +/// Return a gasmix representing newly-inhaled air. +/mob/living/proc/obtain_new_breath(obj/item/organ/internal/lungs/lungs) + var/static/datum/gas_mixture/vacuum = new //avoid having to create a new gas mixture for each breath in space + //Okay, we can breathe, now check if we can get air + var/volume_needed = get_breath_volume() + //First check for air from internals, then the local environment, then use vacuum + return get_breath_from_internal(volume_needed) || get_breath_from_environment(volume_needed) || vacuum + +/// Handles pre-breath checks. If this proc returns TRUE, breathing is skipped that tick. +/mob/living/proc/handle_pre_breath(obj/item/organ/internal/lungs/lungs) + //Check if we can breathe at all + if(handle_drowning() || (is_asystole() && !GET_CHEMICAL_EFFECT(src, CE_STABLE) && lungs.active_breathing)) //crit aka circulatory shock + . = TRUE + else if(suffocation_counter > 0) + // We aren't drowning or in asystole, but something else is suffocating us, so lower the counter and don't take a breath + suffocation_counter-- + . = TRUE + if(.) + // Gasp on average every 10 ticks + if (prob(10) && !is_asystole() && lungs.active_breathing) + INVOKE_ASYNC(src, PROC_REF(emote), /decl/emote/audible/gasp) + return TRUE + return FALSE // not handled, proceed with breathing + +/mob/living/proc/try_breathe() + var/decl/bodytype/root_bodytype = get_bodytype() + if(!root_bodytype?.breathing_organ) + return + var/obj/item/organ/internal/lungs/lungs = get_organ(root_bodytype.breathing_organ, /obj/item/organ/internal/lungs) + var/datum/gas_mixture/breath = get_breath(lungs) + //if breath is null or vacuum, the lungs will handle it for us + failed_last_breath = (!lungs || nervous_system_failure()) ? TRUE : lungs.handle_owner_breath(breath) + handle_post_breath(breath) + +/mob/living/proc/get_breath_from_environment(var/volume_needed=STD_BREATH_VOLUME, var/atom/location = src.loc) + + if(volume_needed <= 0) + return + + // First handle being in a submerged environment. + var/datum/gas_mixture/breath + if(is_flooded(current_posture.prone)) + var/turf/my_turf = get_turf(src) + + //Can we get air from the turf above us? + var/can_breathe_air_above = FALSE + if(my_turf == location) + if(!current_posture.prone && my_turf.above && !my_turf.above.is_flooded() && my_turf.above.is_open() && can_overcome_gravity()) + location = my_turf.above + can_breathe_air_above = TRUE + + // If not, are we capable of breathing water? + if(!can_breathe_air_above) + breath = new + if(!can_drown()) + breath.total_volume = volume_needed + breath.temperature = my_turf.temperature + // TODO: species-breathable gas instead of oxygen default. Maybe base it on the reagents being breathed + breath.adjust_gas(/decl/material/gas/oxygen, ONE_ATMOSPHERE*volume_needed/(R_IDEAL_GAS_EQUATION*T20C)) + my_turf.show_bubbles() + return breath + + // Otherwise, handle breathing normally. + var/datum/gas_mixture/environment + if(location) + environment = location.return_air() + if(environment) + breath = environment.remove_volume(volume_needed) + handle_chemical_smoke(environment) //handle chemical smoke while we're at it + if(breath && breath.total_moles) + //handle mask filtering + var/obj/item/clothing/mask/M = get_equipped_item(slot_wear_mask_str) + if(istype(M) && breath) + var/datum/gas_mixture/filtered = M.filter_air(breath) + location.assume_air(filtered) + return breath + +/mob/living/proc/get_breath_from_internal(var/volume_needed=STD_BREATH_VOLUME) //hopefully this will allow overrides to specify a different default volume without breaking any cases where volume is passed in. + var/old_internals = get_internals() + if(old_internals) + var/obj/item/tank/rig_supply + var/obj/item/rig/rig = get_rig() + if(rig && !rig.offline && (rig.air_supply && old_internals == rig.air_supply)) + rig_supply = rig.air_supply + if(!rig_supply) + if(!(old_internals in contents)) + set_internals(null) + else + check_for_airtight_internals() + var/obj/item/tank/new_internals = get_internals() + refresh_hud_element(HUD_INTERNALS) + if(istype(new_internals)) + return new_internals.remove_air_volume(volume_needed) + +//Handle possble chem smoke effect +/mob/living/proc/handle_chemical_smoke(var/datum/gas_mixture/environment) + var/decl/species/my_species = get_species() + if(my_species && environment?.return_pressure() < my_species.breath_pressure/5) + return //pressure is too low to even breathe in. + + for(var/slot in global.standard_headgear_slots) + var/obj/item/gear = get_equipped_item(slot) + if(istype(gear) && (gear.item_flags & ITEM_FLAG_BLOCK_GAS_SMOKE_EFFECT)) + return + + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) + if(REAGENT_TOTAL_VOLUME(smoke.reagents)) + smoke.reagents.trans_to_mob(src, 5, CHEM_INGEST, copy = 1) + smoke.reagents.trans_to_mob(src, 5, CHEM_INJECT, copy = 1) + // I dunno, maybe the reagents enter the blood stream through the lungs? + break // If they breathe in the nasty stuff once, no need to continue checking + +/mob/living/proc/get_breath_volume() + . = STD_BREATH_VOLUME + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(heart && !heart.open) + . *= (!BP_IS_PROSTHETIC(heart)) ? get_pulse()/PULSE_NORM : 1.5 + +/mob/living/proc/handle_post_breath(datum/gas_mixture/breath) + if(!breath) + return + + var/datum/gas_mixture/loc_air = loc?.return_air() + if(!loc_air) + return + + //by default, exhale + var/obj/item/tank/my_internals = get_internals() + if(my_internals) + var/datum/gas_mixture/internals_air = my_internals.return_air() + if(internals_air && (internals_air.return_pressure() < loc_air.return_pressure())) // based on the assumption it has a one-way valve for gas release + internals_air.merge(breath) + return + if(loc) + loc.merge_exhaled_volume(breath) diff --git a/code/modules/mob/living/living_damage.dm b/code/modules/mob/living/living_damage.dm new file mode 100644 index 000000000000..54b0776bc84b --- /dev/null +++ b/code/modules/mob/living/living_damage.dm @@ -0,0 +1,36 @@ +/mob/living/setBruteLoss(var/amount) + take_damage((amount * 0.5)-get_damage(BRUTE)) + +/mob/living/getBruteLoss() + return get_max_health() - current_health + +/mob/living/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + . = ..() + if(amount > 0 && istype(ai)) + ai.retaliate() + +/mob/living/adjustToxLoss(var/amount, var/do_update_health = TRUE) + take_damage(amount * 0.5, do_update_health = do_update_health) + +/mob/living/setToxLoss(var/amount) + take_damage((amount * 0.5)-get_damage(BRUTE)) + +/mob/living/adjustFireLoss(var/amount, var/do_update_health = TRUE) + take_damage(amount * 0.5, do_update_health = do_update_health) + if(amount > 0 && istype(ai)) + ai.retaliate() + +/mob/living/setFireLoss(var/amount) + take_damage((amount * 0.5)-get_damage(BRUTE)) + +/mob/living/adjustHalLoss(var/amount, var/do_update_health = TRUE) + take_damage(amount * 0.5, do_update_health = do_update_health) + +/mob/living/setHalLoss(var/amount) + take_damage((amount * 0.5)-get_damage(BRUTE)) + +/mob/living/explosion_act() + var/oldhealth = current_health + . = ..() + if(istype(ai) && current_health < oldhealth) + ai.retaliate() diff --git a/code/modules/mob/living/living_death.dm b/code/modules/mob/living/living_death.dm new file mode 100644 index 000000000000..0a264462f7dd --- /dev/null +++ b/code/modules/mob/living/living_death.dm @@ -0,0 +1,10 @@ +/mob/living/handle_existence_failure(dusted) + . = ..() + // Gibbed mobs drop some of their butchery products. + if(. && !dusted && butchery_data && loc) + var/decl/butchery_data/butchery_decl = GET_DECL(butchery_data) + for(var/atom/movable/product in butchery_decl.get_all_products(src)) + if(prob(20)) + qdel(product) + else + product.dropInto(loc) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index b3daf2f81a26..e94c963c06fd 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -20,78 +20,112 @@ . += natural_armor /mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone) - + var/oldhealth = current_health //Being hit while using a deadman switch - var/obj/item/assembly/signaler/signaler = get_active_hand() + var/obj/item/assembly/signaler/signaler = get_active_held_item() if(istype(signaler) && signaler.deadman) log_and_message_admins("has triggered a signaler deadman's switch") - src.visible_message("[src] triggers their deadman's switch!") + visible_message(SPAN_WARNING("[src] triggers their deadman's switch!")) signaler.signal() - //Armor - var/damage = P.damage + var/damage = P.get_projectile_damage(src) var/flags = P.damage_flags() var/damaged if(!P.nodamage) - damaged = apply_damage(damage, P.damage_type, def_zone, flags, P, P.armor_penetration) + damaged = apply_damage(damage, P.atom_damage_type, def_zone, flags, P, P.armor_penetration) bullet_impact_visuals(P, def_zone, damaged) if(damaged || P.nodamage) // Run the block computation if we did damage or if we only use armor for effects (nodamage) - . = get_blocked_ratio(def_zone, P.damage_type, flags, P.armor_penetration, P.damage) + . = get_blocked_ratio(def_zone, P.atom_damage_type, flags, P.armor_penetration, P.damage) P.on_hit(src, ., def_zone) + if(istype(ai) && isliving(P.firer) && !ai.get_target() && current_health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) + ai.retaliate(P.firer) // For visuals and blood splatters etc /mob/living/proc/bullet_impact_visuals(var/obj/item/projectile/P, var/def_zone, var/damage) - var/list/impact_sounds = LAZYACCESS(P.impact_sounds, get_bullet_impact_effect_type(def_zone)) + var/list/all_impact_sounds = P.get_impact_sounds() + var/list/impact_sounds = LAZYACCESS(all_impact_sounds, get_bullet_impact_effect_type(def_zone)) if(length(impact_sounds)) playsound(src, pick(impact_sounds), 75) + if(get_bullet_impact_effect_type(def_zone) != BULLET_IMPACT_MEAT) + return + if(!damage || P.atom_damage_type != BRUTE) + return + var/hit_dir = get_dir(P.starting, src) + var/obj/effect/decal/cleanable/blood/B = blood_splatter(get_step(src, hit_dir), src, 1, hit_dir) + if(!QDELETED(B)) + B.icon_state = pick("dir_splatter_1","dir_splatter_2") + var/scale = min(1, round(mob_size / MOB_SIZE_MEDIUM, 0.1)) + B.set_scale(scale) + new /obj/effect/temp_visual/bloodsplatter(loc, hit_dir, get_blood_color()) /mob/living/get_bullet_impact_effect_type(var/def_zone) return BULLET_IMPACT_MEAT -/mob/living/proc/aura_check(var/type) - if(!auras) - return TRUE - . = TRUE - var/list/newargs = args - args[1] - for(var/a in auras) - var/obj/aura/aura = a - var/result = 0 - switch(type) - if(AURA_TYPE_WEAPON) - result = aura.attackby(arglist(newargs)) - if(AURA_TYPE_BULLET) - result = aura.bullet_act(arglist(newargs)) - if(AURA_TYPE_THROWN) - result = aura.hitby(arglist(newargs)) - if(AURA_TYPE_LIFE) - result = aura.life_tick() - if(result & AURA_FALSE) - . = FALSE - if(result & AURA_CANCEL) - break - - //Handles the effects of "stun" weapons -/mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) +/mob/living/proc/stun_effect_act(stun_amount, agony_amount, def_zone, used_weapon) flash_pain() if (stun_amount) - Stun(stun_amount) - Weaken(stun_amount) + SET_STATUS_MAX(src, STAT_STUN, stun_amount) + SET_STATUS_MAX(src, STAT_WEAK, stun_amount) apply_effect(stun_amount, STUTTER) apply_effect(stun_amount, EYE_BLUR) if (agony_amount) - apply_damage(agony_amount, PAIN, def_zone, used_weapon) + apply_damage(agony_amount, PAIN, def_zone = def_zone, used_weapon = used_weapon) apply_effect(agony_amount/10, STUTTER) apply_effect(agony_amount/10, EYE_BLUR) -/mob/living/proc/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, def_zone = null) - return 0 //only carbon liveforms have this proc +/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, def_zone) + SHOULD_CALL_PARENT(TRUE) + if(status_flags & GODMODE) + return 0 + + var/decl/species/my_species = get_species() + if(my_species?.species_flags & SPECIES_FLAG_ABSORB_ELECTRICITY) + spark_at(loc, amount=5, cardinal_only = TRUE) + LAZYADD(global.stored_shock_by_ref["\ref[src]"], shock_damage) + return 0 + + if(!shock_damage) + return 0 + + stun_effect_act(agony_amount=shock_damage, def_zone=def_zone) + + playsound(loc, "sparks", 50, 1, -1) + if (shock_damage > 15) + visible_message( + SPAN_DANGER("\The [src] was electrocuted[source ? " by \the [source]" : ""]!"), + SPAN_DANGER("You feel a powerful shock course through your body!"), + SPAN_WARNING("You hear a heavy electrical crack.") + ) + else + visible_message( + SPAN_DANGER("\The [src] was shocked[source ? " by \the [source]" : ""]."), + SPAN_DANGER("You feel a shock course through your body."), + SPAN_WARNING("You hear a zapping sound.") + ) + + switch(shock_damage) + if(11 to 15) + SET_STATUS_MAX(src, STAT_STUN, 1) + if(16 to 20) + SET_STATUS_MAX(src, STAT_STUN, 2) + if(21 to 25) + SET_STATUS_MAX(src, STAT_WEAK, 2) + if(26 to 30) + SET_STATUS_MAX(src, STAT_WEAK, 5) + if(31 to INFINITY) + SET_STATUS_MAX(src, STAT_WEAK, 10) //This should work for now, more is really silly and makes you lay there forever + + set_status_condition(STAT_JITTER, min(shock_damage*5, 200)) + + spark_at(loc, amount=5, cardinal_only = TRUE) + + return shock_damage /mob/living/emp_act(severity) - var/list/L = src.get_contents() - for(var/obj/O in L) + for(var/obj/O in get_mob_contents()) O.emp_act(severity) ..() @@ -104,112 +138,158 @@ if(I.attack_message_name()) weapon_mention = " with [I.attack_message_name()]" if(effective_force) - visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"][weapon_mention] by [user]!") + visible_message(SPAN_DANGER("\The [src] has been [I.pick_attack_verb()][weapon_mention] by \the [user]!")) else - visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"][weapon_mention] by [user]!") - + visible_message(SPAN_WARNING("\The [src] has been [I.pick_attack_verb()][weapon_mention] by \the [user]!")) . = standard_weapon_hit_effects(I, user, effective_force, hit_zone) - - if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too - var/turf/simulated/location = get_turf(src) - if(istype(location)) location.add_blood_floor(src) + if(I.atom_damage_type == BRUTE && prob(33)) + blood_splatter(get_turf(loc), src) + if(istype(ai)) + ai.retaliate(user) //returns 0 if the effects failed to apply for some reason, 1 otherwise. /mob/living/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - if(!effective_force) - return 0 - - //Hulk modifier - if(MUTATION_HULK in user.mutations) - effective_force *= 2 - - //Apply weapon damage - var/damage_flags = I.damage_flags() - - return apply_damage(effective_force, I.damtype, hit_zone, damage_flags, used_weapon=I) + if(effective_force) + try_embed_in_mob(user, I, hit_zone, effective_force, direction = get_dir(user, src)) + return TRUE + return FALSE -//this proc handles being hit by a thrown atom /mob/living/hitby(var/atom/movable/AM, var/datum/thrownthing/TT) - if(isliving(AM)) - var/mob/living/M = AM - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - if(skill_fail_prob(SKILL_COMBAT, 75)) - Weaken(rand(3,5)) - if(M.skill_fail_prob(SKILL_HAULING, 100)) - M.Weaken(rand(4,8)) - M.visible_message(SPAN_DANGER("\The [M] collides with \the [src]!")) + . = ..() + if(istype(ai)) + ai.retaliate(TT.thrower) - if(!aura_check(AURA_TYPE_THROWN, AM, TT.speed)) - return + if(.) + + if(isliving(AM)) + var/mob/living/M = AM + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + if(skill_fail_prob(SKILL_COMBAT, 75)) + SET_STATUS_MAX(src, STAT_WEAK, rand(3,5)) + if(M.skill_fail_prob(SKILL_HAULING, 100)) + SET_STATUS_MAX(M, STAT_WEAK, rand(4,8)) + M.visible_message(SPAN_DANGER("\The [M] collides with \the [src]!")) - if(istype(AM,/obj/)) - var/obj/O = AM - var/dtype = O.damtype - var/throw_damage = O.throwforce*(TT.speed/THROWFORCE_SPEED_DIVISOR) + if(mob_modifiers_block_attack(MM_ATTACK_TYPE_THROWN, AM, TT.speed)) + return FALSE - var/miss_chance = max(15*(TT.dist_travelled-2),0) + if(istype(AM, /obj)) + . = handle_thrown_obj_damage(AM, TT) - if (prob(miss_chance)) - visible_message("\The [O] misses [src] narrowly!") - return + if(!.) + process_momentum(AM, TT) - src.visible_message("\The [src] has been hit by \the [O].") - apply_damage(throw_damage, dtype, null, O.damage_flags(), O) +/mob/living/proc/handle_thrown_obj_damage(obj/O, datum/thrownthing/TT) - if(TT.thrower) - var/client/assailant = TT.thrower.client - if(assailant) - admin_attack_log(TT.thrower, src, "Threw \an [O] at the victim.", "Had \an [O] thrown at them.", "threw \an [O] at") + var/dtype = O.atom_damage_type + var/throw_damage = O.get_thrown_attack_force()*(TT?.speed/THROWFORCE_SPEED_DIVISOR) + var/zone = BP_CHEST - if(O.can_embed() && (throw_damage > 5*O.w_class)) //Handles embedding for non-humans and simple_animals. - embed(O) + //check if we hit + var/miss_chance = max(15*(TT?.dist_travelled-2),0) + if(prob(miss_chance)) + visible_message(SPAN_NOTICE("\The [O] misses \the [src] completely!")) + return FALSE - process_momentum(AM, TT) + if (TT?.target_zone) + zone = check_zone(TT.target_zone, src) + else + zone = ran_zone() //Hits a random part of the body, -was already geared towards the chest + zone = get_zone_with_miss_chance(zone, src, miss_chance, ranged_attack=1) + + if(zone && TT?.thrower && TT.thrower != src) + var/shield_check = check_shields(throw_damage, O, TT.thrower, zone, O) + if(shield_check == PROJECTILE_FORCE_MISS) + zone = null + else if(shield_check) + return FALSE + + // Mobs with organs can potentially be missing the targetted organ. + var/obj/item/organ/external/affecting + if(length(get_external_organs())) + affecting = (zone && GET_EXTERNAL_ORGAN(src, zone)) + if(!affecting) + visible_message(SPAN_NOTICE("\The [O] misses \the [src] narrowly!")) + return FALSE + + visible_message(SPAN_DANGER("\The [src] is hit [affecting ? "in \the [affecting] " : ""]by \the [O]!")) + if(TT?.thrower?.client) + admin_attack_log(TT.thrower, src, "Threw \an [O] at the victim.", "Had \an [O] thrown at them.", "threw \an [O] at") + try_embed_in_mob(TT.thrower, O, zone, throw_damage, dtype, null, affecting, direction = TT.init_dir) + return TRUE /mob/living/momentum_power(var/atom/movable/AM, var/datum/thrownthing/TT) if(anchored || buckled) return 0 - . = (AM.get_mass()*TT.speed)/(get_mass()*min(AM.throw_speed,2)) - if(has_gravity() || check_space_footing()) + if(!can_slip(magboots_only = TRUE)) . *= 0.5 -/mob/living/momentum_do(var/power, var/datum/thrownthing/TT, var/atom/movable/AM) - if(power >= 0.75) //snowflake to enable being pinned to walls - var/direction = TT.init_dir - throw_at(get_edge_target_turf(src, direction), min((TT.maxrange - TT.dist_travelled) * power, 10), throw_speed * min(power, 1.5), callback = CALLBACK(src,/mob/living/proc/pin_to_wall,AM,direction)) - visible_message(SPAN_DANGER("\The [src] staggers under the impact!"),SPAN_DANGER("You stagger under the impact!")) - return - - . = ..() - -/mob/living/proc/pin_to_wall(var/obj/O, var/direction) - if(!istype(O) || O.loc != src || !O.can_embed())//Projectile is suitable for pinning. - return - - var/turf/T = near_wall(direction,2) - - if(T) - forceMove(T) - visible_message(SPAN_DANGER("[src] is pinned to the wall by [O]!"),SPAN_DANGER("You are pinned to the wall by [O]!")) - src.anchored = 1 - src.pinned += O - -/mob/living/proc/embed(var/obj/O, var/def_zone=null, var/datum/wound/supplied_wound) - O.forceMove(src) - src.embedded += O - src.verbs += /mob/proc/yank_out_object +/mob/living/proc/try_embed_in_mob(mob/living/user, obj/O, def_zone, embed_damage = 0, dtype = BRUTE, datum/wound/supplied_wound, obj/item/organ/external/affecting, direction) + + if(!istype(O)) + return FALSE + + if(!affecting) + affecting = get_organ(def_zone) + + if(!supplied_wound) + supplied_wound = apply_damage(embed_damage, dtype, damage_flags = O.damage_flags(), used_weapon = O, armor_pen = O.armor_penetration, given_organ = (affecting || def_zone)) + + if(!O.can_embed()) + return FALSE + + if(affecting && istype(supplied_wound) && supplied_wound.is_open() && dtype == BRUTE) // Can't embed in a small bruise. + var/obj/item/I = O + var/sharp = I.is_sharp() || I.has_edge() + embed_damage *= (1 - get_blocked_ratio(def_zone, BRUTE, O.damage_flags(), O.armor_penetration, I.get_attack_force(user))) + + //blunt objects should really not be embedding in things unless a huge amount of force is involved + var/embed_chance = embed_damage / (sharp ? I.w_class : (I.w_class*3)) + var/embed_threshold = (sharp ? 5 : 10) * I.w_class + var/sharp_embed_chance = embed_damage/(10*I.w_class)*100 + + //Sharp objects will always embed if they do enough damage. + //Thrown sharp objects have some momentum already and have a small chance to embed even if the damage is below the threshold + if((sharp && prob(sharp_embed_chance)) || (embed_damage > embed_threshold && prob(embed_chance))) + affecting.embed_in_organ(I, supplied_wound = (istype(supplied_wound) ? supplied_wound : null)) + I.has_embedded(src) + . = TRUE + + // Simple embed for mobs with no limbs. + if(!. && !length(get_external_organs())) + O.forceMove(src) + if(isitem(O)) + var/obj/item/I = O + I.has_embedded(src) + . = TRUE + + // Allow a tick for throwing/striking to resolve. + if(. && direction) + addtimer(CALLBACK(src, PROC_REF(check_embed_pinning), O, direction), 1) + +/mob/living/proc/check_embed_pinning(obj/O, direction) + if(QDELETED(src) || QDELETED(O) || !isturf(loc) || !(O in embedded) || !direction) + return FALSE + var/turf/wall = get_step_resolving_mimic(loc, direction) + if(!istype(wall) || !wall.density) + return FALSE + LAZYDISTINCTADD(pinned, O) + stop_automove() + visible_message("\The [src] is pinned to \the [wall] by \the [O]!") + // TODO: cancel all throwing and momentum after this point + return TRUE //This is called when the mob is thrown into a dense turf /mob/living/proc/turf_collision(var/turf/T, var/speed) - visible_message("[src] slams into \the [T]!") + visible_message(SPAN_DANGER("\The [src] slams into \the [T]!")) playsound(T, 'sound/effects/bangtaper.ogg', 50, 1, 1)//so it plays sounds on the turf instead, makes for awesome carps to hull collision and such apply_damage(speed*5, BRUTE) /mob/living/proc/near_wall(var/direction,var/distance=1) var/turf/T = get_step(get_turf(src),direction) - var/turf/last_turf = src.loc + var/turf/last_turf = loc var/i = 1 while(i>0 && i<=distance) @@ -228,60 +308,13 @@ if(!damage || !istype(user)) return - adjustBruteLoss(damage) admin_attack_log(user, src, "Attacked", "Was attacked", "attacked") - src.visible_message("\The [user] has [attack_message] \the [src]!") + visible_message(SPAN_DANGER("\The [user] has [attack_message] \the [src]!")) + take_damage(damage) user.do_attack_animation(src) - spawn(1) updatehealth() return 1 -/mob/living/proc/IgniteMob() - if(fire_stacks > 0 && !on_fire) - on_fire = 1 - set_light(0.6, 0.1, 4, l_color = COLOR_ORANGE) - update_fire() - -/mob/living/proc/ExtinguishMob() - if(on_fire) - on_fire = 0 - fire_stacks = 0 - set_light(0) - update_fire() - -/mob/living/proc/update_fire() - return - -/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person - fire_stacks = Clamp(fire_stacks + add_fire_stacks, FIRE_MIN_STACKS, FIRE_MAX_STACKS) - -/mob/living/proc/handle_fire() - if(fire_stacks < 0) - fire_stacks = min(0, ++fire_stacks) //If we've doused ourselves in water to avoid fire, dry off slowly - - if(!on_fire) - return 1 - else if(fire_stacks <= 0) - ExtinguishMob() //Fire's been put out. - return 1 - - fire_stacks = max(0, fire_stacks - 0.2) //I guess the fire runs out of fuel eventually - - var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment - if(G.get_by_flag(XGM_GAS_OXIDIZER) < 1) - ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire - return 1 - - var/turf/location = get_turf(src) - location.hotspot_expose(fire_burn_temperature(), 50, 1) - -/mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - //once our fire_burn_temperature has reached the temperature of the fire that's giving fire_stacks, stop adding them. - //allow fire_stacks to go up to 4 for fires cooler than 700 K, since are being immersed in flame after all. - if(fire_stacks <= 4 || fire_burn_temperature() < exposed_temperature) - adjust_fire_stacks(2) - IgniteMob() - /mob/living/proc/get_cold_protection() return 0 @@ -290,84 +323,71 @@ //Finds the effective temperature that the mob is burning at. /mob/living/proc/fire_burn_temperature() - if (fire_stacks <= 0) + var/fire_level = get_fire_intensity() + if (fire_level <= 0) return 0 - //Scale quadratically so that single digit numbers of fire stacks don't burn ridiculously hot. //lower limit of 700 K, same as matches and roughly the temperature of a cool flame. - return max(2.25*round(FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE*(fire_stacks/FIRE_MAX_FIRESUIT_STACKS)**2), 700) + return max(2.25*round(FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE*(fire_level/FIRE_MAX_FIRESUIT_STACKS)**2), 700) /mob/living/proc/reagent_permeability() return 1 -/mob/living/proc/handle_actions() - //Pretty bad, i'd use picked/dropped instead but the parent calls in these are nonexistent - for(var/datum/action/A in actions) - if(A.CheckRemoval(src)) - A.Remove(src) - for(var/obj/item/I in src) - if(I.action_button_name) - if(!I.action) - I.action = new I.default_action_type - I.action.name = I.action_button_name - I.action.SetTarget(I) - I.action.Grant(src) - return - -/mob/living/update_action_buttons() - if(!hud_used) return - if(!client) return - - if(hud_used.hud_shown != 1) //Hud toggled to minimal - return - - client.screen -= hud_used.hide_actions_toggle - for(var/datum/action/A in actions) - if(A.button) - client.screen -= A.button +/mob/living/lava_act(datum/gas_mixture/air, temperature, pressure) + fire_act(air, temperature) + FireBurn(0.4*vsc.fire_firelevel_multiplier, temperature, pressure) + . = (current_health <= 0) ? ..() : FALSE - if(hud_used.action_buttons_hidden) - if(!hud_used.hide_actions_toggle) - hud_used.hide_actions_toggle = new(hud_used) - hud_used.hide_actions_toggle.UpdateIcon() +// called when something steps onto a mob +// this handles mulebots and vehicles +/mob/living/Crossed(var/atom/movable/AM) + AM.crossed_mob(src) - if(!hud_used.hide_actions_toggle.moved) - hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(1) - //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,1) +/mob/living/proc/solvent_act(var/severity, var/amount_per_item, var/solvent_power = MAT_SOLVENT_STRONG) - client.screen += hud_used.hide_actions_toggle + // TODO move this to a contact var or something. + if(solvent_power < MAT_SOLVENT_STRONG) return - var/button_number = 0 - for(var/datum/action/A in actions) - button_number++ - if(A.button == null) - var/obj/screen/movable/action_button/N = new(hud_used) - N.owner = A - A.button = N - - var/obj/screen/movable/action_button/B = A.button - - B.UpdateIcon() - - B.SetName(A.UpdateName()) - - client.screen += B - - if(!B.moved) - B.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number) - //hud_used.SetButtonCoords(B,button_number) - - if(button_number > 0) - if(!hud_used.hide_actions_toggle) - hud_used.hide_actions_toggle = new(hud_used) - hud_used.hide_actions_toggle.InitialiseIcon(src) - if(!hud_used.hide_actions_toggle.moved) - hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1) - //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,button_number+1) - client.screen += hud_used.hide_actions_toggle - -/mob/living/lava_act(datum/gas_mixture/air, temperature, pressure) - fire_act(air, temperature) - FireBurn(0.4*vsc.fire_firelevel_multiplier, temperature, pressure) - . = (health <= 0) ? ..() : FALSE + for(var/slot in global.standard_headgear_slots) + var/obj/item/thing = get_equipped_item(slot) + if(!istype(thing)) + continue + if(!thing.solvent_can_melt(solvent_power) || !try_unequip(thing)) + to_chat(src, SPAN_NOTICE("Your [thing.name] protects you from the solvent.")) + return TRUE + to_chat(src, SPAN_DANGER("Your [thing.name] dissolves!")) + qdel(thing) + severity -= amount_per_item + if(severity <= 0) + return TRUE + + var/screamed + for(var/obj/item/organ/external/affecting in get_external_organs()) + if(!screamed && affecting.can_feel_pain()) + screamed = TRUE + emote(/decl/emote/audible/scream) + affecting.status |= ORGAN_DISFIGURED + take_organ_damage(0, severity, override_droplimb = DISMEMBER_METHOD_ACID) + +/mob/living/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + var/list/checking_slots = get_held_items() + var/obj/item/suit = get_equipped_item(slot_wear_suit_str) + if(suit) + LAZYDISTINCTADD(checking_slots, suit) + if(isatom(attack_text)) + attack_text = "\the [attack_text]" + for(var/obj/item/shield in checking_slots) + if(shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text)) + return TRUE + return FALSE + +/mob/living/mob_modifiers_block_attack(attack_type, atom/movable/attacker, additional_data) + . = FALSE + if(length(_mob_modifiers)) + for(var/decl/mob_modifier/archetype in _mob_modifiers) + var/result = archetype.check_modifiers_block_attack(src, _mob_modifiers[archetype], attack_type, attacker, additional_data) + if(result & MM_ATTACK_RESULT_DEFLECTED) + . = TRUE + if(result & MM_ATTACK_RESULT_BLOCKED) + break diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 275915a1ad0b..7e4130763a12 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -1,10 +1,13 @@ /mob/living see_in_dark = 2 see_invisible = SEE_INVISIBLE_LIVING + transform_animate_time = ANIM_LYING_TIME + abstract_type = /mob/living //Health and life related vars - var/maxHealth = 100 //Maximum health that should be possible. - var/health = 100 //A mob's health + max_health = 100 //Maximum health that should be possible. + current_health = INFINITY // A mob's current health. Set by update_health(). Defaults to INFINITY so mobs don't die on init. + skillset = /datum/skillset // moved here from /mob to avoid giving dview a skillset var/hud_updateflag = 0 @@ -15,11 +18,8 @@ //var/fireloss = 0 //Burn damage caused by being way too hot, too cold or burnt. //var/halloss = 0 //Hallucination damage. 'Fake' damage obtained through hallucinating or the holodeck. Sleeping should cause it to wear off. - var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out. - - var/t_oxygen = null - var/t_sl_gas = null - var/t_n2 = null + /// Used by the resist verb and some mob abilities. + var/next_special_ability = 0 var/now_pushing = null var/mob_bump_flag = 0 @@ -30,21 +30,76 @@ var/mob/living/cameraFollow = null var/list/datum/action/actions = list() - var/update_slimes = 1 - var/silent = null // Can't talk. Value goes down every life proc. - var/on_fire = 0 //The "Are we on fire?" var - var/fire_stacks - - var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks. - var/possession_candidate // Can be possessed by ghosts if unplayed. + /// The "Are we on fire?" var. Use of is_on_fire() is preferred instead. + VAR_PRIVATE/_on_fire = FALSE + VAR_PRIVATE/_fire_intensity - var/eye_blind = null //Carbon - var/eye_blurry = null //Carbon - var/ear_damage = null //Carbon - var/stuttering = null //Carbon - var/slurring = null //Carbon + /// A suffocation counter representing the number of ticks we should fail to breathe. + var/suffocation_counter = 0 + /// This is used to determine if the mob failed a breath. If they did fail a breath, they will attempt to breathe each tick, otherwise just once per 4 ticks. + var/failed_last_breath = FALSE + /// Can be possessed by ghosts if unplayed. + var/possession_candidate = FALSE var/job = null//Living - var/list/obj/aura/auras = null //Basically a catch-all aura/force-field thing. var/last_resist = 0 + var/admin_paralyzed = FALSE + + /// For leaping and vaulting. + var/jumping = FALSE + + var/list/chem_effects + var/list/_chem_doses + var/last_pain_message + var/next_pain_time = 0 + + var/stress = 0 + var/currently_updating_stress = FALSE + var/list/stressors + + var/life_tick + + var/nutrition = 400 + var/hydration = 400 + + var/original_fingerprint_seed + var/fingerprint + var/original_genetic_seed + var/unique_enzymes + var/blood_type = "A+" + + var/last_cough = 0 + + // Used to track appearance descriptor datums. + // Currently only on humans due to the spaghetti code involved, TODO: generalize. + var/list/appearance_descriptors + + /// Total level of flash protection + var/flash_protection = FLASH_PROTECTION_NONE + + /// Whether this mob's ability to stand has been affected + var/stance_damage = 0 + + var/list/smell_cooldown + + /// Whether or not this mob has a client who wishes to sleep indefinitely. + var/player_triggered_sleeping = FALSE + + /// Organ instances that should report info to Stat(). + var/list/stat_organs + + /// Should this mob subscribe to the weather system for periodic weather effects? + var/weather_sensitive = FALSE + + /// Var used to track current step for footsteps sounds. + var/tmp/step_count = 0 + + /// Has this mob -ever- had a gripper? Used to skip hand checks in some cases. + var/has_had_gripper = FALSE + + /// Timer for chewing off your hand when cuffed. + var/next_restraint_chew = 0 + + /// Used by equip code to determine backpack overrides. + var/datum/backpack_setup/backpack_setup diff --git a/code/modules/mob/living/living_dreams.dm b/code/modules/mob/living/living_dreams.dm new file mode 100644 index 000000000000..53b15252827d --- /dev/null +++ b/code/modules/mob/living/living_dreams.dm @@ -0,0 +1,14 @@ +/mob/living + var/dreaming = FALSE + +/mob/living/proc/handle_dreams() + set waitfor = FALSE + if(!client || dreaming || !prob(5)) + return + dreaming = TRUE + for(var/i = 1 to rand(1,4)) + to_chat(src, SPAN_NOTICE("... [pick(SSlore.dreams)] ...")) + sleep(rand(4 SECONDS, 7 SECONDS)) + if(!HAS_STATUS(src, STAT_ASLEEP)) + break + dreaming = FALSE diff --git a/code/modules/mob/living/living_eating.dm b/code/modules/mob/living/living_eating.dm new file mode 100644 index 000000000000..44977384e92c --- /dev/null +++ b/code/modules/mob/living/living_eating.dm @@ -0,0 +1,16 @@ +/mob/living/can_eat_food_currently(obj/eating, mob/user, consumption_method) + user = user || src + if(get_food_satiation(consumption_method) < get_max_nutrition()) + return TRUE + var/eat_verb = consumption_method == EATING_METHOD_EAT ? "eat" : "drink" + if(eating) + if(user == src) + to_chat(user, SPAN_WARNING("You cannot force yourself to [eat_verb] any more of \the [eating].")) + else + to_chat(user, SPAN_WARNING("You cannot force \the [src] to [eat_verb] any more of \the [eating].")) + else + if(user == src) + to_chat(user, SPAN_WARNING("You cannot force yourself to [eat_verb] any more.")) + else + to_chat(user, SPAN_WARNING("You cannot force \the [src] to [eat_verb] any more.")) + return FALSE diff --git a/code/modules/mob/living/living_electrocution.dm b/code/modules/mob/living/living_electrocution.dm new file mode 100644 index 000000000000..ee5c19b37993 --- /dev/null +++ b/code/modules/mob/living/living_electrocution.dm @@ -0,0 +1,80 @@ +//Electrical shock +/mob/living/proc/apply_shock(var/shock_damage, var/def_zone, var/base_siemens_coeff = 1.0) + + var/list/shock_organs = get_external_organs() + if(!length(shock_organs)) + // TODO: check armor or Siemen's coefficient for non-human mobs + apply_damage(shock_damage, BURN, used_weapon = "Electrocution") + return + + var/obj/item/organ/external/initial_organ = GET_EXTERNAL_ORGAN(src, check_zone(def_zone, src)) + if(!initial_organ) + initial_organ = pick(shock_organs) + + var/obj/item/organ/external/floor_organ + if(!current_posture?.prone) + var/list/obj/item/organ/external/standing = list() + for(var/limb_tag in list(BP_L_FOOT, BP_R_FOOT)) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, limb_tag) + if(E && E.is_usable()) + standing[E.organ_tag] = E + if((def_zone == BP_L_FOOT || def_zone == BP_L_LEG) && standing[BP_L_FOOT]) + floor_organ = standing[BP_L_FOOT] + if((def_zone == BP_R_FOOT || def_zone == BP_R_LEG) && standing[BP_R_FOOT]) + floor_organ = standing[BP_R_FOOT] + else + floor_organ = standing[pick(standing)] + + if(!floor_organ) + floor_organ = pick(get_external_organs()) + + var/list/obj/item/organ/external/to_shock = trace_shock(initial_organ, floor_organ) + if(!length(to_shock)) + return 0 + + shock_damage /= length(to_shock) + shock_damage = round(shock_damage, 0.1) + + for(var/obj/item/organ/external/E in to_shock) + var/actual_shock_damage = max(1, round(shock_damage * base_siemens_coeff * get_siemens_coefficient_organ(E))) + if(actual_shock_damage) + apply_damage(shock_damage, BURN, E.organ_tag, used_weapon="Electrocution") + . += actual_shock_damage + + if(. > 10) + local_emp(initial_organ, 3) + +/mob/living/proc/trace_shock(var/obj/item/organ/external/init, var/obj/item/organ/external/floor) + + var/list/obj/item/organ/external/traced_organs = list(floor) + if(!init) + return + + if(!floor || init == floor) + return list(init) + + for(var/obj/item/organ/external/E in list(floor, init)) + while(E && E.parent_organ) + var/candidate = GET_EXTERNAL_ORGAN(src, E.parent_organ) + if(!candidate || (candidate in traced_organs)) + break // Organ parenthood is not guaranteed to be a tree + E = candidate + traced_organs += E + if(E == init) + return traced_organs + + return traced_organs + +/mob/living/proc/local_emp(var/list/limbs, var/severity = 2) + if(!islist(limbs)) + limbs = list(limbs) + + var/list/EMP = list() + for(var/obj/item/organ/external/limb in limbs) + EMP += limb + if(LAZYLEN(limb.internal_organs)) + EMP += limb.internal_organs + if(LAZYLEN(limb.implants)) + EMP += limb.implants + for(var/atom/E in EMP) + E.emp_act(severity) diff --git a/code/modules/mob/living/living_fires.dm b/code/modules/mob/living/living_fires.dm new file mode 100644 index 000000000000..c66beaedc8a9 --- /dev/null +++ b/code/modules/mob/living/living_fires.dm @@ -0,0 +1,96 @@ +/mob/living/is_on_fire() + return _on_fire + +/mob/living/set_fire_intensity(amount) + _fire_intensity = amount + +/mob/living/get_fire_intensity() + return _fire_intensity + +//Adjusting the amount of fire stacks we have on person +/mob/living/adjust_fire_intensity(amount) + _fire_intensity = clamp(_fire_intensity + amount, FIRE_MIN_STACKS, FIRE_MAX_STACKS) + +/mob/living/can_ignite() + return get_fire_intensity() > 0 && !is_on_fire() + +/mob/living/ignite_fire() + if(can_ignite()) + _on_fire = TRUE + set_light(4, l_color = COLOR_ORANGE) + update_fire() + +/mob/living/extinguish_fire(mob/user, no_message = FALSE) + if(is_on_fire()) + _on_fire = FALSE + set_fire_intensity(0) + set_light(0) + update_fire() + +/mob/living/proc/update_fire(var/update_icons=1) + if(is_on_fire()) + var/decl/bodytype/mob_bodytype = get_bodytype() + var/image/standing = overlay_image(mob_bodytype?.get_ignited_icon(src) || 'icons/mob/OnFire.dmi', mob_bodytype?.get_ignited_icon_state(src) || "Generic_mob_burning", RESET_COLOR) + set_current_mob_overlay(HO_FIRE_LAYER, standing, update_icons) + else + set_current_mob_overlay(HO_FIRE_LAYER, null, update_icons) + +/mob/living/proc/handle_fire() + var/fire_level = get_fire_intensity() + if(fire_level < 0) + set_fire_intensity(min(0, ++fire_level)) //If we've doused ourselves in water to avoid fire, dry off slowly + fire_level = get_fire_intensity() + + if(!is_on_fire()) + return TRUE + if(fire_level <= 0) + extinguish_fire() //Fire's been put out. + return TRUE + + set_fire_intensity(max(0, fire_level - 0.2)) //I guess the fire runs out of fuel eventually + + var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment + if(G.get_by_flag(XGM_GAS_OXIDIZER) < 1) + extinguish_fire() //If there's no oxygen in the tile we're on, put out the fire + return TRUE + + var/turf/location = get_turf(src) + location.hotspot_expose(fire_burn_temperature(), 50, 1) + + var/burn_temperature = fire_burn_temperature() + var/thermal_protection = get_heat_protection(burn_temperature) + + if (thermal_protection < 1 && bodytemperature < burn_temperature) + bodytemperature += round(BODYTEMP_HEATING_MAX*(1-thermal_protection), 1) + + var/species_heat_mod = 1 + + var/protected_limbs = get_heat_protection_flags(burn_temperature) + + if(burn_temperature < get_mob_temperature_threshold(HEAT_LEVEL_2)) + species_heat_mod = 0.5 + else if(burn_temperature < get_mob_temperature_threshold(HEAT_LEVEL_3)) + species_heat_mod = 0.75 + + burn_temperature -= get_mob_temperature_threshold(HEAT_LEVEL_1) + + if(burn_temperature < 1) + return + + if(has_external_organs()) + for(var/obj/item/organ/external/E in get_external_organs()) + if(!(E.body_part & protected_limbs) && prob(20)) + E.take_damage(round(species_heat_mod * log(10, (burn_temperature + 10)), 0.1), BURN, inflicter = "fire") + else // fallback for simplemobs + take_damage(round(species_heat_mod * log(10, (burn_temperature + 10))), 0.1, BURN, DAM_DISPERSED) + +/mob/living/proc/increase_fire_intensity(exposed_temperature) + if(get_fire_intensity() <= 4 || fire_burn_temperature() < exposed_temperature) + adjust_fire_intensity(2) + +/mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + //once our fire_burn_temperature has reached the temperature of the fire that's giving fire intensity, stop adding them. + //allow fire intensity to go up to 4 for fires cooler than 700 K, since are being immersed in flame after all. + increase_fire_intensity(exposed_temperature) + ignite_fire() + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/living_genetics.dm b/code/modules/mob/living/living_genetics.dm new file mode 100644 index 000000000000..1595be199f1f --- /dev/null +++ b/code/modules/mob/living/living_genetics.dm @@ -0,0 +1,56 @@ +/mob/living + VAR_PRIVATE/_updating_genetic_conditions + VAR_PRIVATE/list/_genetic_conditions + +/mob/living/proc/queue_genetic_condition_update() + set waitfor = FALSE + if(_updating_genetic_conditions) + return + _updating_genetic_conditions = TRUE + sleep(1) + _updating_genetic_conditions = FALSE + update_genetic_conditions() + +/mob/living/get_genetic_conditions() + RETURN_TYPE(/list) + return _genetic_conditions + +/mob/living/can_have_genetic_conditions() + return has_genetic_information() + +/mob/living/has_genetic_condition(condition_type) + if(!LAZYLEN(_genetic_conditions)) + return FALSE + var/decl/genetic_condition/condition = GET_DECL(condition_type) + return (condition in _genetic_conditions) + +/mob/living/add_genetic_condition(condition_type, temporary_time) + var/decl/genetic_condition/condition = GET_DECL(condition_type) + if(condition && !(condition in _genetic_conditions) && condition.activate_condition(src)) + LAZYDISTINCTADD(_genetic_conditions, condition) + if(temporary_time) + // TODO: some kind of world.time key or parameter so overlapping calls don't remove each other. + addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living, remove_genetic_condition), condition_type), temporary_time) + queue_genetic_condition_update() + return TRUE + return FALSE + +/mob/living/remove_genetic_condition(condition_type) + if(!LAZYLEN(_genetic_conditions)) + return FALSE + var/decl/genetic_condition/condition = GET_DECL(condition_type) + if(condition && (condition in _genetic_conditions) && condition.deactivate_condition(src)) + LAZYREMOVE(_genetic_conditions, condition) + queue_genetic_condition_update() + return TRUE + return FALSE + +/mob/living/reset_genetic_conditions() + if(!LAZYLEN(_genetic_conditions)) + return FALSE + for(var/decl/genetic_condition/condition as anything in _genetic_conditions) + if(condition.deactivate_condition(src)) + . = TRUE + _genetic_conditions = null + if(.) + update_icon() diff --git a/code/modules/mob/living/living_give.dm b/code/modules/mob/living/living_give.dm new file mode 100644 index 000000000000..724a5af6cf98 --- /dev/null +++ b/code/modules/mob/living/living_give.dm @@ -0,0 +1,44 @@ +/mob/living/verb/give(var/mob/living/target in view(1)-usr) + set category = "IC" + set name = "Give" + do_give(target) + +/mob/living/proc/do_give(var/mob/living/target) + set waitfor = FALSE + if(src.incapacitated()) + return + if(!istype(target) || target.incapacitated() || target.client == null) + return + var/obj/item/I = get_active_held_item() + if(!I) + var/list/inactive_hands = get_inactive_held_items() + if(length(inactive_hands)) + I = inactive_hands[1] + if(!I) + to_chat(src, SPAN_WARNING("You don't have anything in your hands to give to \the [target].")) + return + if(istype(I, /obj/item/grab)) + to_chat(usr, SPAN_WARNING("You can't give someone a grab.")) + return + usr.visible_message(SPAN_NOTICE("\The [usr] holds out \the [I] to \the [target]."), SPAN_NOTICE("You hold out \the [I] to \the [target], waiting for them to accept it.")) + if(alert(target,"[src] wants to give you \a [I]. Will you accept it?",,"Yes","No") == "No") + target.visible_message(SPAN_NOTICE("\The [src] tried to hand \the [I] to \the [target], \ + but \the [target] didn't want it.")) + return + if(!I) + return + if(!Adjacent(target)) + to_chat(src, SPAN_WARNING("You need to stay in reaching distance while giving an object")) + to_chat(target, SPAN_WARNING("\The [src] moved too far away.")) + return + if(I.loc != src || !(I in get_held_items())) + to_chat(src, SPAN_WARNING("You need to keep the item in your hands.")) + to_chat(target, SPAN_WARNING("\The [src] seems to have given up on passing \the [I] to you.")) + return + if(!target.get_empty_hand_slot()) + to_chat(target, SPAN_WARNING("Your hands are full.")) + to_chat(src, SPAN_WARNING("Their hands are full.")) + return + if(try_unequip(I)) + target.put_in_hands(I) // If this fails it will just end up on the floor, but that's fitting for things like dionaea. + target.visible_message(SPAN_NOTICE("\The [src] handed \the [I] to \the [target].")) diff --git a/code/modules/mob/living/living_grabs.dm b/code/modules/mob/living/living_grabs.dm index 3644886f0579..406661d5598e 100644 --- a/code/modules/mob/living/living_grabs.dm +++ b/code/modules/mob/living/living_grabs.dm @@ -1,33 +1,74 @@ -/mob/living/proc/can_grab(var/atom/movable/target, var/target_zone) - if(get_active_hand()) - to_chat(src, SPAN_WARNING("Your hand is full!")) +/mob/living/proc/check_grab_hand(defer_hand) + if(defer_hand) + if(!get_empty_hand_slot()) + to_chat(src, SPAN_WARNING("Your hands are full!")) + return FALSE + else if(get_active_held_item()) + to_chat(src, SPAN_WARNING("Your [parse_zone(get_active_held_item_slot())] is full!")) + return FALSE + return TRUE + +/mob/living/proc/can_grab(var/atom/movable/target, var/target_zone, var/defer_hand = FALSE) + if(!ismob(target) && target.anchored) + to_chat(src, SPAN_WARNING("\The [target] won't budge!")) + return FALSE + if(!check_grab_hand(defer_hand)) return FALSE if(LAZYLEN(grabbed_by)) to_chat(src, SPAN_WARNING("You cannot start grappling while already being grappled!")) return FALSE - for(var/obj/item/grab/G in target.grabbed_by) - if(G.assailant != src) + for(var/obj/item/grab/grab as anything in target.grabbed_by) + if(grab.assailant != src) continue if(!target_zone || !ismob(target)) to_chat(src, SPAN_WARNING("You already have a grip on \the [target]!")) return FALSE - if(G.target_zone == target_zone) - var/obj/O = G.get_targeted_organ() + if(grab.target_zone == target_zone) + var/obj/O = grab.get_targeted_organ() if(O) to_chat(src, SPAN_WARNING("You already have a grip on \the [target]'s [O.name].")) return FALSE return TRUE -/mob/living/proc/make_grab(var/atom/movable/target, var/grab_tag = /decl/grab/simple) +/mob/living/proc/make_grab(atom/movable/target, grab_tag = /decl/grab/simple, defer_hand = FALSE, force_grab_tag = FALSE) + + // Resolve to the 'topmost' atom in the buckle chain, as grabbing someone buckled to something tends to prevent further interaction. + var/atom/movable/original_target = target + var/mob/grabbing_mob = (ismob(target) && target) + while(istype(grabbing_mob) && grabbing_mob.buckled) + grabbing_mob = grabbing_mob.buckled + if(grabbing_mob && grabbing_mob != original_target) + target = grabbing_mob + to_chat(src, SPAN_WARNING("As \the [original_target] is buckled to \the [target], you try to grab that instead!")) + + if(!istype(target)) + return + + if(!force_grab_tag) + var/decl/species/my_species = get_species() + if(my_species?.grab_type) + grab_tag = my_species.grab_type + face_atom(target) - if(target != src && ismob(target)) - to_chat(target, SPAN_WARNING("\The [src] tries to grab you!")) - to_chat(src, SPAN_WARNING("You try to grab \the [target]!")) - if(ispath(grab_tag, /decl/grab) && can_grab(target, zone_sel?.selecting) && target.can_be_grabbed(src, zone_sel?.selecting)) - var/obj/item/grab/grab = new(src, target, grab_tag) - . = !QDELETED(grab) - -/mob/living/add_grab(var/obj/item/grab/grab) + var/obj/item/grab/grab + if(ispath(grab_tag, /decl/grab) && can_grab(target, get_target_zone(), defer_hand = defer_hand) && target.can_be_grabbed(src, get_target_zone(), defer_hand)) + grab = new /obj/item/grab(src, target, grab_tag, defer_hand) + + if(QDELETED(grab)) + if(original_target != src && ismob(original_target)) + to_chat(original_target, SPAN_WARNING("\The [src] tries to grab you, but fails!")) + to_chat(src, SPAN_WARNING("You try to grab \the [target], but fail!")) + return grab + +/mob/living/add_grab(var/obj/item/grab/grab, var/defer_hand = FALSE) + + if(has_had_gripper) + if(defer_hand) + . = put_in_hands(grab) + else + . = put_in_active_hand(grab) + return + for(var/obj/item/grab/other_grab in contents) if(other_grab != grab) return FALSE @@ -38,24 +79,5 @@ if(LAZYLEN(grabbed_by)) resist() -/mob/living/reset_pixel_offsets_for_grab(var/obj/item/grab/G) - ..() - if(!buckled) - animate(src, pixel_x = default_pixel_x, pixel_y = default_pixel_y, 4, 1, LINEAR_EASING) - -/mob/living/adjust_pixel_offsets_for_grab(var/obj/item/grab/G, var/grab_dir) - ..() - if(grab_dir && istype(G)) - var/draw_under = TRUE - switch(grab_dir) - if(NORTH) - animate(src, pixel_x = default_pixel_x, pixel_y = default_pixel_y - G.current_grab.shift, 5, 1, LINEAR_EASING) - if(WEST) - animate(src, pixel_x = default_pixel_x + G.current_grab.shift, pixel_y = default_pixel_y, 5, 1, LINEAR_EASING) - if(EAST) - animate(src, pixel_x = default_pixel_x - G.current_grab.shift, pixel_y = default_pixel_y, 5, 1, LINEAR_EASING) - if(SOUTH) - animate(src, pixel_x = default_pixel_x, pixel_y = default_pixel_y + G.current_grab.shift, 5, 1, LINEAR_EASING) - draw_under = FALSE - plane = G.assailant.plane - layer += draw_under ? -0.01 : 0.01 +/mob/living/give_control_grab(var/mob/living/M) + return (isliving(M) && M == buckled_mob) ? M.make_grab(src, /decl/grab/simple/control, force_grab_tag = TRUE) : ..() diff --git a/code/modules/mob/living/living_hallucinations.dm b/code/modules/mob/living/living_hallucinations.dm new file mode 100644 index 000000000000..c5e4d290f966 --- /dev/null +++ b/code/modules/mob/living/living_hallucinations.dm @@ -0,0 +1,52 @@ +/mob/living + var/hallucination_power = 0 + var/hallucination_duration = 0 + var/next_hallucination + var/list/_hallucinations + +/mob/living/proc/adjust_hallucination(duration, power) + hallucination_duration = max(0, hallucination_duration + duration) + hallucination_power = max(0, hallucination_power + power) + +/mob/living/proc/set_hallucination(duration, power) + hallucination_duration = max(hallucination_duration, duration) + hallucination_power = max(hallucination_power, power) + +/mob/living/proc/handle_hallucinations() + //Tick down the duration + hallucination_duration = max(0, hallucination_duration - 1) + //Adjust power if we have some chems that affect it + if(has_chemical_effect(CE_MIND, threshold_under = -1)) + hallucination_power = hallucination_power++ + else if(has_chemical_effect(CE_MIND, threshold_under = 0)) + hallucination_power = min(hallucination_power++, 50) + else if(has_chemical_effect(CE_MIND, 1)) + hallucination_duration = max(0, hallucination_duration - 1) + hallucination_power = max(hallucination_power - GET_CHEMICAL_EFFECT(src, CE_MIND), 0) + + //See if hallucination is gone + if(!hallucination_power) + hallucination_duration = 0 + return + if(!hallucination_duration) + hallucination_power = 0 + return + + if(!client || stat || world.time < next_hallucination) + return + if(has_chemical_effect(CE_MIND, 1) && prob(GET_CHEMICAL_EFFECT(src, CE_MIND)*40)) //antipsychotics help + return + var/hall_delay = rand(10,20) SECONDS + + if(hallucination_power < 50) + hall_delay *= 2 + next_hallucination = world.time + hall_delay + var/list/candidates = list() + for(var/T in subtypesof(/datum/hallucination)) + var/datum/hallucination/H = new T + if(H.can_affect(src)) + candidates += H + if(candidates.len) + var/datum/hallucination/H = pick(candidates) + H.holder = src + H.activate_hallucination() diff --git a/code/modules/mob/living/living_hud.dm b/code/modules/mob/living/living_hud.dm new file mode 100644 index 000000000000..5e6b7adfff0d --- /dev/null +++ b/code/modules/mob/living/living_hud.dm @@ -0,0 +1,17 @@ +/mob/living + var/list/hud_list = new(10) + +/mob/living/proc/reset_hud_overlays() + hud_list = new(10) + hud_list[HEALTH_HUD] = new /image/hud_overlay(global.using_map.med_hud_icons, src, "blank") + hud_list[STATUS_HUD] = new /image/hud_overlay(global.using_map.hud_icons, src, "hudhealthy") + hud_list[LIFE_HUD] = new /image/hud_overlay(global.using_map.hud_icons, src, "hudhealthy") + hud_list[ID_HUD] = new /image/hud_overlay(global.using_map.hud_icons, src, "hudunknown") + hud_list[WANTED_HUD] = new /image/hud_overlay(global.using_map.hud_icons, src, "hudblank") + hud_list[IMPLOYAL_HUD] = new /image/hud_overlay(global.using_map.implant_hud_icons, src, "hud_imp_blank") + hud_list[IMPCHEM_HUD] = new /image/hud_overlay(global.using_map.implant_hud_icons, src, "hud_imp_blank") + hud_list[IMPTRACK_HUD] = new /image/hud_overlay(global.using_map.implant_hud_icons, src, "hud_imp_blank") + hud_list[SPECIALROLE_HUD] = new /image/hud_overlay(global.using_map.hud_icons, src, "hudblank") + hud_list[STATUS_HUD_OOC] = new /image/hud_overlay(global.using_map.hud_icons, src, "hudhealthy") + +/datum/map diff --git a/code/modules/mob/living/living_maneuvers.dm b/code/modules/mob/living/living_maneuvers.dm index 00c1a8da2509..8e925ee5cce8 100644 --- a/code/modules/mob/living/living_maneuvers.dm +++ b/code/modules/mob/living/living_maneuvers.dm @@ -15,16 +15,25 @@ if(!can_fall(location_override = check)) break if(check && check != loc) - addtimer(CALLBACK(src, /mob/living/proc/reflexive_maneuver_callback, lastloc, check), 0) + addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living, reflexive_maneuver_callback), lastloc, check), 0) return . = ..() /mob/living/proc/reflexive_maneuver_callback(var/turf/origin, var/turf/check) if(prepared_maneuver) - if(origin) + if(origin) // Used to avoid falling into open space. forceMove(get_turf(origin)) prepared_maneuver.perform(src, check, get_acrobatics_multiplier(prepared_maneuver), reflexively = TRUE) prepared_maneuver = null + refresh_hud_element(HUD_MANEUVER) + +/mob/living/proc/try_maneuver(var/atom/target) + if(prepared_maneuver && (isturf(target) || isturf(target.loc))) // Avoid trying to jump at your backpack contents. + prepared_maneuver.perform(src, get_turf(target), get_acrobatics_multiplier(prepared_maneuver)) + prepared_maneuver = null + refresh_hud_element(HUD_MANEUVER) + return TRUE + return FALSE /mob/living/verb/prepare_maneuver() set name = "Prepare To Maneuver" @@ -35,22 +44,33 @@ to_chat(src, SPAN_WARNING("You are unable to perform any maneuvers.")) return + var/list/maneuvers_by_name = list() var/list/maneuvers = list() for(var/maneuver in available_maneuvers) - maneuvers += decls_repository.get_decl(maneuver) + var/decl/maneuver/maneuver_decl = GET_DECL(maneuver) + maneuvers_by_name[maneuver_decl.name] = maneuver_decl + var/image/I = image(maneuver_decl.selection_icon, maneuver_decl.selection_icon_state) + I.name = capitalize(maneuver_decl.name) + maneuvers[maneuver_decl.name] = I - var/next_maneuver = input(src, "Select a maneuver.") as null|anything in maneuvers + var/next_maneuver = show_radial_menu(src, src, maneuvers, require_near = TRUE, radius = 42, tooltips = TRUE, check_locs = list(src), use_labels = RADIAL_LABELS_OFFSET) if(next_maneuver) - prepared_maneuver = next_maneuver + var/decl/maneuver/maneuver = maneuvers_by_name[next_maneuver] + if(!maneuver.can_be_used_by(src, null)) + return + prepared_maneuver = maneuver to_chat(src, SPAN_NOTICE("You prepare to [prepared_maneuver.name].")) else prepared_maneuver = null to_chat(src, SPAN_NOTICE("You are no longer preparing to perform a maneuver.")) + refresh_hud_element(HUD_MANEUVER) /mob/living/proc/perform_maneuver(var/maneuver, var/atom/target) - var/decl/maneuver/performing_maneuver = ispath(maneuver) ? decls_repository.get_decl(maneuver) : maneuver + var/decl/maneuver/performing_maneuver = ispath(maneuver) ? GET_DECL(maneuver) : maneuver if(istype(performing_maneuver)) . = performing_maneuver.perform(src, target, get_acrobatics_multiplier(performing_maneuver)) + prepared_maneuver = null + refresh_hud_element(HUD_MANEUVER) /mob/living/proc/get_acrobatics_multiplier(var/decl/maneuver/attempting_maneuver) return 1 diff --git a/code/modules/mob/living/living_organs.dm b/code/modules/mob/living/living_organs.dm new file mode 100644 index 000000000000..8617ed077091 --- /dev/null +++ b/code/modules/mob/living/living_organs.dm @@ -0,0 +1,72 @@ +/mob/living/proc/get_organs_by_categories(var/category) + return + +//Those are meant to be overriden with optimizations +/mob/living/proc/has_organs() + return LAZYLEN(get_organs()) > 0 + +/mob/living/proc/has_external_organs() + return LAZYLEN(get_external_organs()) > 0 + +/mob/living/proc/has_internal_organs() + return LAZYLEN(get_internal_organs()) > 0 + +/mob/living/get_contained_matter(include_reagents = TRUE) + . = ..() + for(var/obj/item/organ in get_organs()) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., organ.get_contained_matter(include_reagents)) + +//Can be called when we want to add an organ in a detached state or an attached state. +/mob/living/proc/add_organ(var/obj/item/organ/O, var/obj/item/organ/external/affected = null, var/in_place = FALSE, var/update_icon = TRUE, var/detached = FALSE, var/skip_health_update = FALSE) + . = O.do_install(src, affected, in_place, update_icon, detached) + //Only run install effects if we're not detached and we're not adding in place + if(!in_place && !(O.status & ORGAN_CUT_AWAY)) + on_gained_organ(O) + if(!skip_health_update) + update_health() + return TRUE + +//Can be called when the organ is detached or attached. +/mob/living/proc/remove_organ(var/obj/item/organ/O, var/drop_organ = TRUE, var/detach = FALSE, var/ignore_children = FALSE, var/in_place = FALSE, var/update_icon = TRUE, var/skip_health_update = FALSE) + //Only run effects if we're not already detached, and we're not doing a in-place removal + if(!in_place && !(O.status & ORGAN_CUT_AWAY)) //Gotta check the flag here, because of prosthetics handling detached state differently + on_lost_organ(O) + + . = O.do_uninstall(in_place, detach, ignore_children, update_icon) + if(.) + + if(client) + client.screen -= O + + if(!skip_health_update) + update_health() + + if(drop_organ) + var/drop_loc = get_turf(src) + O.dropInto(drop_loc) + if(!BP_IS_PROSTHETIC(O)) + playsound(drop_loc, 'sound/effects/squelch1.ogg', 15, 1) + else + playsound(drop_loc, 'sound/items/Ratchet.ogg', 50, 1) + +//Should handle vital organ checks, icon updates, events +/mob/living/proc/on_lost_organ(var/obj/item/organ/O) + if(QDELETED(src)) + return FALSE //When deleting don't bother running effects + RAISE_EVENT(/decl/observ/dismembered, src, O) + O.on_remove_effects(src) + return TRUE + +/mob/living/proc/on_gained_organ(var/obj/item/organ/O) + if(QDELETED(src)) + return FALSE //When deleting don't bother running effects + O.on_add_effects(src) + return TRUE + +/mob/living/proc/delete_organs() + SHOULD_CALL_PARENT(TRUE) + for(var/datum/organ in get_organs()) + if(istype(organ, /obj/item/organ/internal)) + var/obj/item/organ/internal/innard = organ + innard.transfer_brainmob_with_organ = FALSE // Don't boot our current client. + qdel(organ) diff --git a/code/modules/mob/living/living_powers.dm b/code/modules/mob/living/living_powers.dm index 980eea00a948..6b30fafc0e25 100644 --- a/code/modules/mob/living/living_powers.dm +++ b/code/modules/mob/living/living_powers.dm @@ -21,20 +21,19 @@ set desc = "Infect others with your very breath." set category = "Abilities" - if (last_special > world.time) - to_chat(src, "You aren't ready to do that! Wait [round(last_special - world.time) / 10] seconds.") + if(is_on_special_ability_cooldown()) + to_chat(src, "You aren't ready to do that! Wait [get_seconds_until_next_special_ability_string()].") return - + if (incapacitated()) to_chat(src, "You can't do that while you're incapacitated!") return - last_special = world.time + 60 SECONDS + set_special_ability_cooldown(60 SECONDS) var/turf/T = get_turf(src) var/obj/effect/effect/water/chempuff/chem = new(T) - chem.create_reagents(10) - chem.reagents.add_reagent(/decl/material/liquid/zombie, 2) + chem.add_to_reagents(/decl/material/liquid/zombie, 2) chem.set_up(get_step(T, dir), 2, 10) playsound(T, 'sound/hallucinations/wail.ogg', 20, 1) @@ -43,30 +42,84 @@ set desc = "Regain life by consuming it from others." set category = "Abilities" - if (last_special > world.time) - to_chat(src, "You aren't ready to do that! Wait [round(last_special - world.time) / 10] seconds.") + if (is_on_special_ability_cooldown()) + to_chat(src, "You aren't ready to do that! Wait [get_seconds_until_next_special_ability_string()].") return - + if (incapacitated()) to_chat(src, "You can't do that while you're incapacitated!") return var/mob/living/target for (var/mob/living/L in get_turf(src)) - if (L != src && (L.lying || L.stat == DEAD)) + if (L != src && (L.current_posture.prone || L.stat == DEAD)) target = L break if (!target) to_chat(src, "You aren't on top of a victim!") return - last_special = world.time + 5 SECONDS + set_special_ability_cooldown(5 SECONDS) - src.visible_message("\The [src] hunkers down over \the [target], tearing into their flesh.") + visible_message("\The [src] hunkers down over \the [target], tearing into their flesh.") if(do_mob(src, target, 5 SECONDS)) to_chat(target,"\The [src] scrapes your flesh from your bones!") to_chat(src,"You feed hungrily off \the [target]'s flesh.") - target.adjustBruteLoss(25) - if(target.getBruteLoss() < -target.maxHealth) + target.take_damage(25) + if(target.get_damage(BRUTE) < -target.get_max_health()) target.gib() - src.adjustBruteLoss(-25) \ No newline at end of file + heal_damage(BRUTE, 25) + +/** + * Attempt to devour victim + * + * Returns TRUE on success, FALSE on failure + */ +/mob/living/proc/devour(atom/movable/victim) + var/can_eat = can_devour(victim) + if(!can_eat) + return FALSE + + var/eat_speed = 100 + if(can_eat == DEVOUR_FAST) + eat_speed = 30 + src.visible_message("\The [src] is attempting to devour \the [victim] whole!") + var/mob/target = victim + if(isobj(victim)) + target = src + if(!do_mob(src,target,eat_speed)) + return FALSE + src.visible_message("\The [src] devours \the [victim] whole!") + if(ismob(victim)) + admin_attack_log(src, victim, "Devoured.", "Was devoured by.", "devoured") + else + src.drop_from_inventory(victim) + move_to_stomach(victim) + + return TRUE + +/mob/living/proc/move_to_stomach(atom/movable/victim) + return + +/** + * Return FALSE if victim can't be devoured, DEVOUR_FAST if they can be devoured quickly, DEVOUR_SLOW for slow devour + */ +/mob/living/proc/can_devour(atom/movable/victim, silent = FALSE) + return FALSE + +/mob/living/verb/sniff_verb() + set name = "Sniff" + set desc = "Smell the local area." + set category = "IC" + set src = usr + + var/decl/species/my_species = get_species() + if(incapacitated()) + to_chat(src, SPAN_WARNING("You can't sniff right now.")) + return + + if(my_species && my_species.sniff_message_3p && my_species.sniff_message_1p) + visible_message(SPAN_NOTICE("\The [src] [my_species.sniff_message_3p]."), SPAN_NOTICE(my_species.sniff_message_1p)) + else + visible_message(SPAN_NOTICE("\The [src] sniffs the air."), SPAN_NOTICE("You sniff the air.")) + LAZYCLEARLIST(smell_cooldown) diff --git a/code/modules/mob/living/living_pulse.dm b/code/modules/mob/living/living_pulse.dm new file mode 100644 index 000000000000..96d1a328671e --- /dev/null +++ b/code/modules/mob/living/living_pulse.dm @@ -0,0 +1,42 @@ +/mob/living/proc/get_pulse() + if(stat == DEAD || isSynthetic()) + return PULSE_NONE + if(!should_have_organ(BP_HEART)) + return PULSE_NORM + var/obj/item/organ/internal/heart/heart = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(heart) + return heart.pulse + return PULSE_NONE + +//generates realistic-ish pulse output based on preset levels as text +/mob/living/proc/get_pulse_as_string(var/method) //method 0 is for hands, 1 is for machines, more accurate + if(should_have_organ(BP_HEART)) + var/obj/item/organ/internal/heart/heart_organ = get_organ(BP_HEART, /obj/item/organ/internal/heart) + if(!heart_organ) + // No heart, no pulse + return "0" + if(heart_organ.open && !method) + // Heart is a open type (?) and cannot be checked unless it's a machine + return "muddled and unclear; you can't seem to find a vein" + var/bpm = get_pulse_as_number() + if(bpm >= PULSE_MAX_BPM) + return method ? ">[PULSE_MAX_BPM]" : "extremely weak and fast, patient's artery feels like a thread" + return "[method ? bpm : bpm + rand(-10, 10)]" +// output for machines ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ output for people + +// Similar to get_pulse, but returns only integer numbers instead of text. +/mob/living/proc/get_pulse_as_number() + switch(get_pulse()) + if(PULSE_NONE) + return 0 + if(PULSE_SLOW) + return rand(40, 60) + if(PULSE_NORM) + return rand(60, 90) + if(PULSE_FAST) + return rand(90, 120) + if(PULSE_2FAST) + return rand(120, 160) + if(PULSE_THREADY) + return PULSE_MAX_BPM + return 0 diff --git a/code/modules/mob/living/living_resist.dm b/code/modules/mob/living/living_resist.dm new file mode 100644 index 000000000000..2be9b6f463b8 --- /dev/null +++ b/code/modules/mob/living/living_resist.dm @@ -0,0 +1,95 @@ +/mob/living/proc/escape_buckle() + + if(!buckled) + return + + var/unbuckle_time + if(get_equipped_item(slot_handcuffed_str) && istype(buckled, /obj/effect/energy_net)) + var/obj/effect/energy_net/N = buckled + N.escape_net(src) //super snowflake but is literally used NOWHERE ELSE.-Luke + return + + if(!restrained()) + if(buckled.can_buckle) + buckled.user_unbuckle_mob(src) + else + to_chat(src, "You can't seem to escape from \the [buckled]!") + return + + setClickCooldown(100) + unbuckle_time = max(0, (2 MINUTES) - get_special_resist_time()) + + var/decl/pronouns/pronouns = get_pronouns() + + visible_message( + "[src] attempts to unbuckle [pronouns.self]!", + "You attempt to unbuckle yourself. (This will take around [unbuckle_time / (1 SECOND)] second\s and you need to stand still)", range = 2 + ) + + if(unbuckle_time && buckled) + var/stages = 2 + for(var/i = 1 to stages) + if(!unbuckle_time || do_after(src, unbuckle_time*0.5, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY))) + if(!buckled) + return + visible_message( + SPAN_WARNING("\The [src] tries to unbuckle [pronouns.self]."), + SPAN_WARNING("You try to unbuckle yourself ([i*100/stages]% done)."), range = 2 + ) + else + if(!buckled) + return + visible_message( + SPAN_WARNING("\The [src] stops trying to unbuckle [pronouns.self]."), + SPAN_WARNING("You stop trying to unbuckle yourself."), range = 2 + ) + return + visible_message( + SPAN_DANGER("\The [src] manages to unbuckle [pronouns.self]!"), + SPAN_NOTICE("You successfully unbuckle yourself."), range = 2 + ) + buckled.user_unbuckle_mob(src) + return + +/mob/living/proc/resist_grab() + var/resisting = 0 + for(var/obj/item/grab/grab as anything in grabbed_by) + resisting++ + grab.handle_resist() + if(resisting) + visible_message("[src] resists!") + +/mob/living/proc/get_restraint_breakout_mod() + return 1 + +/mob/living/proc/can_break_restraints() + return can_shred(ignore_intent = TRUE) + +/mob/living/proc/get_special_resist_time() + return 0 + +/mob/living/proc/break_restraints(obj/item/restraint, slot) + visible_message( + SPAN_DANGER("\The [src] is trying to break \the [restraint]!"), + SPAN_DANGER("You attempt to break your [restraint]. (This will take around 5 seconds and you need to stand still)") + ) + + if(!do_after(src, 5 SECONDS, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + return FALSE + + if(QDELETED(src) || QDELETED(restraint)) + return FALSE + + var/new_restraint = get_equipped_item(slot) + if((restraint != new_restraint) || buckled) + return FALSE + + visible_message( + SPAN_DANGER("\The [src] manages to break \the [restraint]!"), + SPAN_DANGER("You successfully break your [restraint].") + ) + + try_unequip(restraint) + qdel(restraint) + if(buckled && buckled.buckle_require_restraints && !get_restraining_equipment()) + buckled.unbuckle_mob() diff --git a/code/modules/mob/living/living_status.dm b/code/modules/mob/living/living_status.dm new file mode 100644 index 000000000000..179412f6a7a7 --- /dev/null +++ b/code/modules/mob/living/living_status.dm @@ -0,0 +1,89 @@ +// Defined on /mob to avoid having to pass args to every single attack_foo() proc. +/mob + // A STATUS CONDITION is a counter on an general incapacitating effect like sleep or blindness. + // STATUS CONDITION TRACKERS: + var/list/status_counters + var/list/pending_status_counters + var/datum/status_marker_holder/status_markers + +// Status condition procs: +/mob/living/set_status_condition(var/condition, var/amount) + if(QDELETED(src)) + return FALSE + if(!ispath(condition, /decl/status_condition)) + return FALSE + var/decl/status_condition/cond = GET_DECL(condition) + if(!cond.check_can_set(src)) + return FALSE + + var/decl/species/my_species = get_species() + if(my_species) + amount = my_species.adjust_status(src, condition, amount) + var/decl/bodytype/my_bodytype = get_bodytype() + if(my_bodytype) + amount = my_bodytype.adjust_status(src, condition, amount) + amount = clamp(amount, 0, 1000) + + if(amount == PENDING_STATUS(src, condition)) + return FALSE + LAZYSET(pending_status_counters, condition, amount) + addtimer(CALLBACK(src, PROC_REF(apply_pending_status_changes)), 0, TIMER_UNIQUE) + return TRUE + +/mob/living/proc/rebuild_status_markers() + if(!length(status_counters) || stat == DEAD) + if(status_markers) + status_markers.clear_markers() + return + if(!status_markers) + status_markers = new(src) + status_markers.refresh_markers(src) + +/mob/living/proc/apply_pending_status_changes() + var/rebuild_markers = FALSE + if(!isnull(pending_status_counters)) + for(var/condition in pending_status_counters) + var/last_amount = LAZYACCESS(status_counters, condition) || 0 + var/next_amount = LAZYACCESS(pending_status_counters, condition) || 0 + if(last_amount != next_amount) + rebuild_markers = TRUE + if(next_amount == 0) + LAZYREMOVE(status_counters, condition) + else + LAZYSET(status_counters, condition, next_amount) + status_change(condition, next_amount, last_amount) + pending_status_counters = null + if(rebuild_markers) + rebuild_status_markers() + update_icon() + +/mob/living/proc/status_change(var/condition, var/new_amount, var/last_amount) + var/decl/status_condition/status = GET_DECL(condition) + status.handle_changed_amount(src, new_amount, last_amount) + +/mob/living/handle_status_conditions() + . = ..() + var/refresh_icon = FALSE + for(var/condition in status_counters) + var/decl/status_condition/status = GET_DECL(condition) + status.handle_status(src, status_counters[condition]) + if(GET_STATUS(src, condition) <= 0) + status_counters -= condition + refresh_icon = TRUE + if(status.associated_mob_modifier) + remove_mob_modifier(status.associated_mob_modifier, source = src) + else if(status.associated_mob_modifier) + add_mob_modifier(status.associated_mob_modifier, source = src) + + if(refresh_icon) + update_icon() + +/mob/living/clear_status_conditions() + var/had_counters = !!LAZYLEN(status_counters) + for(var/stype in status_counters) + set_status_condition(stype, 0) + status_counters = null + pending_status_counters = null + if(had_counters) + rebuild_status_markers() + update_icon() diff --git a/code/modules/mob/living/living_tail.dm b/code/modules/mob/living/living_tail.dm new file mode 100644 index 000000000000..31761055946b --- /dev/null +++ b/code/modules/mob/living/living_tail.dm @@ -0,0 +1,153 @@ +/mob/living/proc/update_tail_showing(update_icons = TRUE) + + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(!istype(tail_organ)) + set_current_mob_overlay(HO_TAIL_LAYER, null, FALSE) + set_current_mob_underlay(HU_TAIL_LAYER, null, update_icons) + return + + // Update tail concealment here since it's cheap and it saves checking elsewhere. + if(tail_organ.tail_hidden && !tail_organ.can_be_hidden()) + tail_organ.tail_hidden = FALSE + to_chat(src, SPAN_NOTICE("Your [tail_organ.name] is revealed!")) + + var/tail_state = tail_organ.get_tail() + if(!tail_state) + set_current_mob_overlay(HO_TAIL_LAYER, null, FALSE) + set_current_mob_underlay(HU_TAIL_LAYER, null, update_icons) + return + + var/obj/item/suit = get_equipped_item(slot_wear_suit_str) + if(suit && (suit.flags_inv & HIDETAIL)) + set_current_mob_overlay(HO_TAIL_LAYER, null, FALSE) + set_current_mob_underlay(HU_TAIL_LAYER, null, update_icons) + return + + var/icon/tail_s = get_tail_icon_for_organ(tail_organ, tail_state) + if(!tail_s) + set_tail_animation_state(null) + return + + var/tail_image = image(tail_s, tail_state) + if(dir == NORTH) + set_current_mob_underlay(HU_TAIL_LAYER, null, FALSE) + set_current_mob_overlay(HO_TAIL_LAYER, tail_image, FALSE) + else + set_current_mob_overlay(HO_TAIL_LAYER, null, FALSE) + set_current_mob_underlay(HU_TAIL_LAYER, tail_image, FALSE) + + if(update_icons) + update_icon() + compile_overlays() + +/mob/living/proc/get_tail_icon_for_organ(obj/item/organ/external/tail/tail_organ, tail_state) + + if(!istype(tail_organ) || !tail_state) + return + + if(tail_organ.limb_flags & ORGAN_FLAG_SKELETAL) + if(!tail_organ.bodytype?.skeletal_icon || !(check_state_in_icon(tail_state, tail_organ.bodytype.skeletal_icon))) + return + var/tail_cache_key = "[tail_state][tail_organ.bodytype.skeletal_icon]_skeletal" + if(!global.tail_icon_cache[tail_cache_key]) + global.tail_icon_cache[tail_cache_key] = icon(tail_organ.bodytype.skeletal_icon, tail_state) + return global.tail_icon_cache[tail_cache_key] + + var/tail_icon = tail_organ.get_tail_icon() + if(!tail_icon) + return // No tail data! + + if(!check_state_in_icon(tail_state, tail_icon)) + return + + // TODO: merge all of this into get_cached_accessory_icon() + + // These values may be null and are generally optional. + var/hair_colour = GET_HAIR_COLOR(src) + var/tail_blend = tail_organ.get_tail_blend() + var/list/tail_colors = tail_organ.get_tail_metadata() + if(!islist(tail_colors) || !length(tail_colors)) + return + + var/tail_color = LAZYACCESS(tail_colors, SAM_COLOR) + var/tail_inner_color = LAZYACCESS(tail_colors, SAM_COLOR_INNER) + var/icon_key = "[tail_state][tail_icon][tail_blend][tail_color][tail_inner_color][hair_colour]" + var/icon/blended_tail_icon = global.tail_icon_cache[icon_key] + if(!blended_tail_icon) + + // Generate a new icon. + blended_tail_icon = icon(tail_icon, tail_state) + if(!isnull(tail_blend)) // 0 is a valid blend mode + if(tail_color) + blended_tail_icon.Blend(tail_color, tail_blend) + if(tail_inner_color) + var/tail_inner_state = "[tail_state]_inner" + if(check_state_in_icon(tail_inner_state, tail_icon)) + var/icon/inner_tail = icon(tail_icon, tail_inner_state) + inner_tail.Blend(tail_inner_color, tail_blend) + blended_tail_icon.Blend(inner_tail, ICON_OVERLAY) + + global.tail_icon_cache[icon_key] = blended_tail_icon + return blended_tail_icon + +/mob/living/set_dir() + var/lastdir = dir + . = ..() + if(. && ((lastdir == NORTH) != (dir == NORTH))) + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(tail_organ?.get_tail()) + update_tail_showing() + +/mob/living/proc/set_tail_animation_state(var/t_state, update_icons = TRUE) + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(!tail_organ || (tail_organ.limb_flags & ORGAN_FLAG_SKELETAL)) + return null + // If we don't have animation states, don't try to force us to use one. + if(t_state != null && !tail_organ.get_tail_animation_states()) + t_state = null + if(tail_organ.tail_animation_state != t_state) + tail_organ.tail_animation_state = t_state + update_tail_showing(update_icons) + . = get_current_tail_image() + +//Not really once, since BYOND can't do that. +//Update this if the ability to flick() images or make looping animation start at the first frame is ever added. +/mob/living/proc/get_current_tail_image() + return get_current_mob_overlay(HO_TAIL_LAYER) || get_current_mob_underlay(HU_TAIL_LAYER) + +/mob/living/proc/animate_tail_once(var/update_icons=1) + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(!tail_organ || (tail_organ.limb_flags & ORGAN_FLAG_SKELETAL)) + return + var/tail_states = tail_organ.get_tail_animation_states() + if(tail_states) + . = set_tail_animation_state("_once[rand(1, tail_states)]", update_icons) + if(.) + spawn(2 SECONDS) + set_tail_animation_state(null, TRUE) + +/mob/living/proc/animate_tail_start(var/update_icons=1) + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(!tail_organ || (tail_organ.limb_flags & ORGAN_FLAG_SKELETAL)) + return + var/tail_states = tail_organ.get_tail_animation_states() + if(tail_states) + return set_tail_animation_state("_slow[rand(1, tail_states)]", update_icons) + +/mob/living/proc/animate_tail_fast(var/update_icons=1) + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(!tail_organ || (tail_organ.limb_flags & ORGAN_FLAG_SKELETAL)) + return + var/tail_states = tail_organ.get_tail_animation_states() + if(tail_states) + return set_tail_animation_state("_loop[rand(1, tail_states)]", update_icons) + +/mob/living/proc/animate_tail_reset(var/update_icons=1) + var/obj/item/organ/external/tail/tail_organ = get_organ(BP_TAIL, /obj/item/organ/external/tail) + if(!tail_organ || (tail_organ.limb_flags & ORGAN_FLAG_SKELETAL)) + return + if(stat != DEAD) + var/tail_states = tail_organ.get_tail_animation_states() + if(tail_states) + return set_tail_animation_state("_idle[rand(1, tail_states)]", update_icons) + return set_tail_animation_state(null, update_icons) diff --git a/code/modules/mob/living/living_taste.dm b/code/modules/mob/living/living_taste.dm new file mode 100644 index 000000000000..9beeb47e2fbb --- /dev/null +++ b/code/modules/mob/living/living_taste.dm @@ -0,0 +1,17 @@ +/mob/living + /// these two help govern taste. The first is the last time a taste message was shown to the player. + var/last_taste_time = 0 + /// the second is the message in question. + var/last_taste_text = "" + +/mob/living/proc/ingest(var/datum/reagents/from, var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + if(last_taste_time + 50 < world.time) + var/datum/reagents/temp = new(amount, global.temp_reagents_holder) //temporary holder used to analyse what gets transfered. + from.trans_to_holder(temp, amount, multiplier, 1) + var/text_output = temp.generate_taste_message(src, from) + if(text_output && (text_output != last_taste_text || last_taste_time + 1 MINUTE < world.time)) //We dont want to spam the same message over and over again at the person. Give it a bit of a buffer. + to_chat(src, SPAN_NOTICE("You can taste [text_output].")) //no taste means there are too many tastes and not enough flavor. + last_taste_time = world.time + last_taste_text = text_output + RAISE_EVENT(/decl/observ/ingested, src, from, target, amount, multiplier, copy) + return from?.trans_to_holder(target, amount, multiplier, copy) diff --git a/code/modules/mob/living/living_throw.dm b/code/modules/mob/living/living_throw.dm new file mode 100644 index 000000000000..9fc36c7b2aa5 --- /dev/null +++ b/code/modules/mob/living/living_throw.dm @@ -0,0 +1,100 @@ +/mob/living/mob_throw_item(atom/target, atom/movable/item) + + toggle_throw_mode(FALSE) + if(!item) + item = get_active_held_item() + + if(incapacitated() || !target || istype(target, /obj/screen) || !istype(item) || !(item in get_held_items())) + return FALSE + + var/place_item = !check_intent(I_FLAG_HARM) && Adjacent(target) + + if(istype(item, /obj/item/grab)) + var/obj/item/grab/grab = item + item = grab.throw_held() + /// throw the person instead of the grab + if(ismob(item)) + var/mob/mob = item + //limit throw range by relative mob size + var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors + var/turf/end_T = get_turf(target) + if(start_T && end_T && usr == src) + var/start_T_descriptor = "[start_T] \[[start_T.x],[start_T.y],[start_T.z]\] ([start_T.loc])" + var/end_T_descriptor = "[start_T] \[[end_T.x],[end_T.y],[end_T.z]\] ([end_T.loc])" + admin_attack_log(usr, mob, "Threw the victim from [start_T_descriptor] to [end_T_descriptor].", "Was from [start_T_descriptor] to [end_T_descriptor].", "threw, from [start_T_descriptor] to [end_T_descriptor], ") + drop_from_inventory(grab) + + // Hand items to a nearby target, or place them on the turf. + // Don't unequip early, keep it in our hands so we can give it! + else if(place_item && !QDELETED(item) && !QDELETED(target)) + // We've already been unequipped above. + if(isliving(target)) + var/mob/living/mob = target + if(length(mob.get_held_item_slots())) + if(mob == src || (mob.in_throw_mode && mob.check_intent(I_FLAG_HELP))) + if(!try_unequip(item, play_dropsound = place_item)) + return FALSE + if(target != src) + mob.put_in_hands(item) // If this fails it will just end up on the floor, but that's fitting for things like dionaea. + visible_message( + "\The [src] hands \the [mob] \a [item].", + SPAN_NOTICE("You give \the [mob] \a [item].") + ) + else + var/same_hand = check_intent(I_FLAG_HELP) + var/decl/pronouns/user_pronouns = get_pronouns() + visible_message( + "\The [src] tosses \the [item] [same_hand ? "in the air and catches it." : "between [user_pronouns.his] hands"].", + SPAN_NOTICE("You toss \the [item] [same_hand ? "in the air and catch it" : "between your hands"].") + ) + if(same_hand) + put_in_active_hand(item) + else + put_in_inactive_hand(item) + else + to_chat(src, SPAN_NOTICE("You offer \the [item] to \the [mob].")) + do_give(mob) + return TRUE + to_chat(src, SPAN_WARNING("\The [mob] has no way to hold \the [item]!")) + return TRUE + + if(!QDELETED(item) && item.loc != target) + if(item.loc == src) + try_unequip(item, get_turf(target), play_dropsound = place_item) + else + item.forceMove(get_turf(target)) + + return TRUE + else if(!try_unequip(item, play_dropsound = place_item)) + return FALSE + + if(!istype(item) || QDELETED(item) || !isturf(item.loc)) + return FALSE + + if(place_item) + return TRUE + + var/itemsize = item.get_object_size() + var/message = "\The [src] has thrown \the [item]!" + var/skill_mod = 0.2 + if(!skill_check(SKILL_HAULING, min(round(itemsize - ITEM_SIZE_HUGE) + 2, SKILL_MAX))) + if(prob(30)) + SET_STATUS_MAX(src, STAT_WEAK, 2) + message = "\The [src] barely manages to throw \the [item], and is knocked off-balance!" + else + skill_mod += 0.2 + + skill_mod += 0.8 * (get_skill_value(SKILL_HAULING) - SKILL_MIN)/(SKILL_MAX - SKILL_MIN) + var/throw_range = round(item.throw_range * min(mob_size/itemsize, 1) * skill_mod) + + //actually throw it! + visible_message(SPAN_WARNING(message), range = min(itemsize*2,world.view)) + lastarea = lastarea || get_area(loc) + if(can_slip(magboots_only = TRUE) && prob((itemsize * itemsize * 10) * MOB_SIZE_MEDIUM/mob_size)) + var/direction = get_dir(target, src) + step(src, direction) + space_drift(direction) + + item.throw_at(target, throw_range, item.throw_speed * skill_mod, src) + playsound(src, 'sound/effects/throw.ogg', 50, 1) + animate_throw(src) diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index b41baabef975..ad212a096151 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -1,9 +1,26 @@ - /mob/living/Login() - ..() + . = ..() //Mind updates mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist) mind.active = 1 //indicates that the mind is currently synced with a client //If they're SSD, remove it so they can wake back up. update_antag_icons(mind) - return . + + // Clear our cosmetic/sound weather cooldowns. + var/obj/abstract/weather_system/weather = get_affecting_weather() + + var/mob_ref = weakref(src) + if(istype(weather)) + weather.mob_shown_weather -= mob_ref + weather.mob_shown_wind -= mob_ref + global.current_mob_ambience -= mob_ref + + // Update our equipped item presence. + for(var/slot in (get_inventory_slots()|get_held_item_slots())) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(slot) + var/obj/item/held = inv_slot?.get_equipped_item() + if(held) + held.reconsider_client_screen_presence(client, slot) + + var/datum/extension/abilities/abilities = get_extension(src, /datum/extension/abilities) + abilities?.refresh_login() diff --git a/code/modules/mob/living/maneuvers/_maneuver.dm b/code/modules/mob/living/maneuvers/_maneuver.dm index c6ffcadee749..9c4ca984298f 100644 --- a/code/modules/mob/living/maneuvers/_maneuver.dm +++ b/code/modules/mob/living/maneuvers/_maneuver.dm @@ -1,9 +1,21 @@ /decl/maneuver + abstract_type = /decl/maneuver var/name = "unnamed" var/delay = 2 SECONDS var/cooldown = 10 SECONDS var/stamina_cost = 10 var/reflexive_modifier = 1 + var/selection_icon = 'icons/screen/maneuver.dmi' + var/selection_icon_state + +/decl/maneuver/validate() + . = ..() + if(!selection_icon) + . += "no selection icon" + else if(!selection_icon_state) + . += "no selection icon_state" + else if(!check_state_in_icon(selection_icon_state, selection_icon)) + . += "selection icon_state [selection_icon_state] not found in icon [selection_icon]" /decl/maneuver/proc/can_be_used_by(var/mob/living/user, var/atom/target, var/silent = FALSE) if(!istype(user) || !user.can_do_maneuver(src, silent)) @@ -16,13 +28,13 @@ if(!silent) to_chat(user, SPAN_WARNING("You cannot maneuver in zero gravity!")) return FALSE - if(user.incapacitated(INCAPACITATION_DISABLED|INCAPACITATION_DISRUPTED) || user.lying || !istype(user.loc, /turf)) + if(user.incapacitated(INCAPACITATION_DISABLED|INCAPACITATION_DISRUPTED) || user.current_posture.prone || !isturf(user.loc)) if(!silent) to_chat(user, SPAN_WARNING("You are not in position for maneuvering.")) return FALSE - if(world.time < user.last_special) + if(user.is_on_special_ability_cooldown()) if(!silent) - to_chat(user, SPAN_WARNING("You cannot maneuver again for another [Floor((user.last_special - world.time)*0.1)] second\s.")) + to_chat(user, SPAN_WARNING("You cannot maneuver again for another [user.get_seconds_until_next_special_ability_string()].")) return FALSE if(user.get_stamina() < stamina_cost) if(!silent) @@ -40,6 +52,6 @@ user.face_atom(target) . = (!delay || reflexively || (do_after(user, delay) && can_be_used_by(user, target))) if(cooldown) - user.last_special = world.time + cooldown + user.set_special_ability_cooldown(cooldown) if(stamina_cost) user.adjust_stamina(stamina_cost) diff --git a/code/modules/mob/living/maneuvers/maneuver_leap.dm b/code/modules/mob/living/maneuvers/maneuver_leap.dm index 487fe3692609..e42b80d7a1e1 100644 --- a/code/modules/mob/living/maneuvers/maneuver_leap.dm +++ b/code/modules/mob/living/maneuvers/maneuver_leap.dm @@ -2,6 +2,7 @@ name = "leap" stamina_cost = 10 reflexive_modifier = 1.5 + selection_icon_state = "leap" /decl/maneuver/leap/perform(var/mob/living/user, var/atom/target, var/strength, var/reflexively = FALSE) . = ..() @@ -12,9 +13,11 @@ strength = max(2, strength * user.get_jump_distance()) if(reflexively) strength *= reflexive_modifier + user.jump_layer_shift() animate(user, pixel_z = 16, time = 3, easing = SINE_EASING | EASE_IN) animate(pixel_z = user.default_pixel_z, time = 3, easing = SINE_EASING | EASE_OUT) - user.throw_at(get_turf(target), strength, 1, user, FALSE, CALLBACK(src, /decl/maneuver/leap/proc/end_leap, user, target, old_pass_flags)) + user.throw_at(get_turf(target), strength, 1, user, FALSE, CALLBACK(src, TYPE_PROC_REF(/decl/maneuver/leap, end_leap), user, target, old_pass_flags)) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, jump_layer_shift_end)), 4.5) /decl/maneuver/leap/proc/end_leap(var/mob/living/user, var/atom/target, var/pass_flag) user.pass_flags = pass_flag @@ -27,6 +30,8 @@ if(.) var/can_leap_distance = user.get_jump_distance() * user.get_acrobatics_multiplier() . = (can_leap_distance > 0 && (!target || get_dist(user, target) <= can_leap_distance)) + if(!. && !silent) + to_chat(user, SPAN_WARNING("You cannot leap that far!")) /decl/maneuver/leap/spider stamina_cost = 0 @@ -36,5 +41,6 @@ /decl/maneuver/leap/grab/end_leap(var/mob/living/user, var/atom/target) . = ..() - if(!user.lying && ismob(target) && user.Adjacent(target)) - user.make_grab(target) + if(!user.current_posture.prone && ismob(target) && user.Adjacent(target) && istype(target, /atom/movable)) + var/atom/movable/AM = target + AM.try_make_grab(user) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index ecb6d225995b..49e187b25a7f 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -1,131 +1,106 @@ -var/list/department_radio_keys = list( - ":r" = "right ear", ".r" = "right ear", - ":l" = "left ear", ".l" = "left ear", - ":i" = "intercom", ".i" = "intercom", - ":h" = "department", ".h" = "department", - ":+" = "special", ".+" = "special", //activate radio-specific special functions - ":c" = "Command", ".c" = "Command", - ":n" = "Science", ".n" = "Science", - ":m" = "Medical", ".m" = "Medical", - ":e" = "Engineering", ".e" = "Engineering", - ":s" = "Security", ".s" = "Security", - ":w" = "whisper", ".w" = "whisper", - ":t" = "Mercenary", ".t" = "Mercenary", - ":x" = "Raider", ".x" = "Raider", - ":u" = "Supply", ".u" = "Supply", - ":v" = "Service", ".v" = "Service", - ":p" = "AI Private", ".p" = "AI Private", - ":z" = "Entertainment",".z" = "Entertainment", - ":y" = "Exploration", ".y" = "Exploration", - - ":R" = "right ear", ".R" = "right ear", - ":L" = "left ear", ".L" = "left ear", - ":I" = "intercom", ".I" = "intercom", - ":H" = "department", ".H" = "department", - ":C" = "Command", ".C" = "Command", - ":N" = "Science", ".N" = "Science", - ":M" = "Medical", ".M" = "Medical", - ":E" = "Engineering", ".E" = "Engineering", - ":S" = "Security", ".S" = "Security", - ":W" = "whisper", ".W" = "whisper", - ":T" = "Mercenary", ".T" = "Mercenary", - ":X" = "Raider", ".X" = "Raider", - ":U" = "Supply", ".U" = "Supply", - ":V" = "Service", ".V" = "Service", - ":P" = "AI Private", ".P" = "AI Private", - ":Z" = "Entertainment",".Z" = "Entertainment", - ":Y" = "Exploration", ".Y" = "Exploration", - - //kinda localization -- rastaf0 - //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. - ":ê" = "right ear", ".ê" = "right ear", - ":ä" = "left ear", ".ä" = "left ear", - ":ø" = "intercom", ".ø" = "intercom", - ":ð" = "department", ".ð" = "department", - ":ñ" = "Command", ".ñ" = "Command", - ":ò" = "Science", ".ò" = "Science", - ":ü" = "Medical", ".ü" = "Medical", - ":ó" = "Engineering", ".ó" = "Engineering", - ":û" = "Security", ".û" = "Security", - ":ö" = "whisper", ".ö" = "whisper", - ":å" = "Mercenary", ".å" = "Mercenary", - ":é" = "Supply", ".é" = "Supply", -) - - -var/list/channel_to_radio_key = new -proc/get_radio_key_from_channel(var/channel) - var/key = channel_to_radio_key[channel] - if(!key) - for(var/radio_key in department_radio_keys) - if(department_radio_keys[radio_key] == channel) - key = radio_key - break - if(!key) - key = "" - channel_to_radio_key[channel] = key - - return key - /mob/living/proc/binarycheck() + for(var/slot in global.ear_slots) + var/obj/item/radio/headset/dongle = get_equipped_item(slot) + if(dongle?.can_transmit_binary()) + return TRUE + return FALSE - if (istype(src, /mob/living/silicon/pai)) - return - - if (!ishuman(src)) - return +/mob/living/proc/get_default_language() + var/decl/language/lang = GET_DECL(default_language) + if(istype(lang) && can_speak(lang)) + return lang - var/mob/living/carbon/human/H = src - if (H.l_ear || H.r_ear) - var/obj/item/radio/headset/dongle - if(istype(H.l_ear,/obj/item/radio/headset)) - dongle = H.l_ear - else - dongle = H.r_ear - if(!istype(dongle)) return - if(dongle.translate_binary) return 1 +/mob/living/proc/get_any_good_language(set_default=FALSE) + . = get_default_language() + if(!.) + for(var/decl/language/L in languages) + if(can_speak(L)) + . = L + if(set_default) + set_default_language(.) + return -/mob/living/proc/get_default_language() - . = ispath(default_language, /decl/language) && decls_repository.get_decl(default_language) -/mob/proc/is_muzzled() - return istype(wear_mask, /obj/item/clothing/mask/muzzle) +/mob/living/is_silenced() + . = ..() || HAS_STATUS(src, STAT_SILENCE) //Takes a list of the form list(message, verb, whispering) and modifies it as needed //Returns 1 if a speech problem was applied, 0 otherwise -/mob/living/proc/handle_speech_problems(var/list/message_data) - var/message = message_data[1] - var/verb = message_data[2] - - . = 0 - - if((MUTATION_HULK in mutations) && health >= 25 && length(message)) - message = "[uppertext(message)]!!!" - verb = pick("yells","roars","hollers") - message_data[3] = 0 - . = 1 - else if(slurring) - message = slur(message) - verb = pick("slobbers","slurs") - . = 1 - else if(stuttering) - message = NewStutter(message) - verb = pick("stammers","stutters") - . = 1 - else if(has_chem_effect(CE_SQUEAKY, 1)) - message = "[message]" - verb = "squeaks" - . = 1 - - message_data[1] = message - message_data[2] = verb - -/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - if(message_mode == "intercom") - for(var/obj/item/radio/intercom/I in view(1, null)) - I.talk_into(src, message, verb, speaking) - used_radios += I - return 0 +/mob/living/proc/handle_speech_problems(var/list/message_data, var/decl/language/spoken) + var/say_message = message_data[1] + var/say_verb = message_data[2] + + . = FALSE + var/obj/item/clothing/mask/M = get_equipped_item(slot_wear_mask_str) + if(istype(M) && M.voicechange) + say_message = pick(M.say_messages) + say_verb = pick(M.say_verbs) + . = TRUE + else if(HAS_STATUS(src, STAT_SILENCE) || has_genetic_condition(GENE_COND_MUTED)) + to_chat(src, SPAN_WARNING("You are unable to speak!")) + say_message = "" + . = TRUE + else if(HAS_STATUS(src, STAT_SLUR)) + say_message = slur(say_message) + say_verb = pick("slobbers","slurs") + . = TRUE + else if(HAS_STATUS(src, STAT_STUTTER)) + say_message = NewStutter(say_message) + say_verb = pick("stammers","stutters") + . = TRUE + else if(has_chemical_effect(CE_SQUEAKY, 1)) + say_message = "[say_message]" + say_verb = "squeaks" + . = TRUE + + message_data[1] = say_message + message_data[2] = say_verb + +// Grabs any radios equipped to the mob, with message_mode used to +// determine relevancy. See handle_message_mode below. +/mob/living/proc/get_radios(var/message_mode) + + var/list/possible_radios + if(message_mode == MESSAGE_MODE_RIGHT || message_mode == MESSAGE_MODE_LEFT) + var/use_right = (message_mode == MESSAGE_MODE_RIGHT) + var/obj/item/thing = get_equipped_item(use_right ? slot_r_ear_str : slot_l_ear_str) + if(thing) + LAZYDISTINCTADD(possible_radios, thing) + else + thing = get_equipped_item(use_right ? BP_R_HAND : BP_L_HAND) + if(thing) + LAZYDISTINCTADD(possible_radios, thing) + else if(message_mode == MESSAGE_MODE_INTERCOM) + if(!restrained()) + for(var/obj/item/radio/I in view(1)) + if(I.intercom_handling) + LAZYDISTINCTADD(possible_radios, I) + else if(message_mode != MESSAGE_MODE_WHISPER) + for(var/slot in global.ear_slots) + var/thing = get_equipped_item(slot) + if(thing) + LAZYDISTINCTADD(possible_radios, thing) + + if(LAZYLEN(possible_radios)) + for(var/atom/movable/thing as anything in possible_radios) + var/obj/item/radio/radio = thing.get_radio(message_mode) + if(istype(radio)) + LAZYDISTINCTADD(., radio) + +// This proc takes in a string (message_mode) which maps to a radio key in global.department_radio_keys +// It then processes the message_mode to implement an additional behavior needed for the message, such +// as retrieving radios or looking for an intercom nearby. +/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios) + SHOULD_CALL_PARENT(TRUE) + if(!message_mode) + return + var/list/assess_items_as_radios = get_radios(message_mode) + if(!LAZYLEN(assess_items_as_radios)) + return + used_radios |= assess_items_as_radios + for(var/obj/item/radio/radio as anything in used_radios) + radio.add_fingerprint(src) + radio.talk_into(src, message, message_mode, verb, speaking) /mob/living/proc/handle_speech_sound() var/list/returns[2] @@ -133,69 +108,65 @@ proc/get_radio_key_from_channel(var/channel) returns[2] = null return returns -/mob/living/proc/get_speech_ending(verb, var/ending) - if(ending=="!") - return pick("exclaims","shouts","yells") - if(ending=="?") - return "asks" - return verb - -/mob/living/proc/format_say_message(var/message = null) - if(!message) - return - - message = html_decode(message) +/mob/living/proc/handle_mob_specific_speech(message, message_mode, verb = "says", decl/language/speaking) + SHOULD_CALL_PARENT(TRUE) + return FALSE - var/end_char = copytext(message, length(message), length(message) + 1) - if(!(end_char in list(".", "?", "!", "-", "~"))) - message += "." - - return html_encode(message) - -/mob/living/say(var/message, var/decl/language/speaking = null, var/verb="says", var/alt_name="", whispering) +/mob/living/say(var/message, var/decl/language/speaking, var/verb = "says", whispering) + set waitfor = FALSE if(client) if(client.prefs.muted & MUTE_IC) to_chat(src, "You cannot speak in IC (Muted).") return if(stat) - if(stat == 2) + if(stat == DEAD) return say_dead(message) return - var/prefix = copytext(message,1,2) - if(prefix == get_prefix_key(/decl/prefix/custom_emote)) + if(findlasttextEx(message, get_prefix_key(/decl/prefix/custom_emote)) == 1) return emote(copytext(message,2)) - if(prefix == get_prefix_key(/decl/prefix/visible_emote)) + + if(findlasttextEx(message, get_prefix_key(/decl/prefix/visible_emote)) == 1) return custom_emote(1, copytext(message,2)) //parse the radio code and consume it - var/message_mode = parse_message_mode(message, "headset") - if (message_mode) - if (message_mode == "headset") - message = copytext(message,2) //it would be really nice if the parse procs could do this for us. + var/message_mode = parse_message_mode(message, standard_mode = MESSAGE_MODE_DEFAULT) + if(message_mode) + if(message_mode == MESSAGE_MODE_DEFAULT) + message = copytext_char(message, 2) else - message = copytext(message,3) + message = copytext_char(message, 3) - message = trim_left(message) + // trim pre-language-parsing so we can get language and radio keys + message = trim(message) //parse the language code and consume it if(!speaking) speaking = parse_language(message) if(speaking) - message = copytext(message,2+length(speaking.key)) + message = copytext_char(message,2+length_char(speaking.key)) else - speaking = get_default_language() + speaking = get_any_good_language(set_default=TRUE) + if (!speaking) + to_chat(src, SPAN_WARNING("You don't know a language and cannot speak.")) + custom_emote(AUDIBLE_MESSAGE, "[pick("grunts", "babbles", "gibbers", "jabbers", "burbles")] aimlessly.") + return + + if(handle_mob_specific_speech(message, message_mode, verb, speaking)) + return // This is broadcast to all mobs with the language, // irrespective of distance or anything else. - if(speaking && (speaking.flags & HIVEMIND)) + if(speaking && (speaking.flags & LANG_FLAG_HIVEMIND)) speaking.broadcast(src,trim(message)) return 1 - if((is_muzzled()) && !(speaking && (speaking.flags & SIGNLANG))) - to_chat(src, "You're muzzled and cannot speak!") - return + if(!speaking || !(speaking.flags & LANG_FLAG_SIGNLANG)) + var/obj/item/muzzle = get_item_blocking_speech() + if(muzzle) + to_chat(src, SPAN_WARNING("You're can't speak, \the [muzzle] is in the way!")) + return if (speaking) if(whispering) @@ -203,14 +174,23 @@ proc/get_radio_key_from_channel(var/channel) else verb = say_quote(message, speaking) - message = trim_left(message) + message = trim(html_encode(message)) // trim again post-language-parsing message = handle_autohiss(message, speaking) - message = format_say_message(message) - - if(speaking && !speaking.can_be_spoken_properly_by(src)) - message = speaking.muddle(message) + message = filter_modify_message(message) + message = handle_autopunctuation(message) + + if(speaking) + var/speech_ability_result = speaking.can_be_spoken_properly_by(src) + if(speech_ability_result == SPEECH_RESULT_MUDDLED) + message = speaking.muddle(message) + else if(speech_ability_result == SPEECH_RESULT_INCAPABLE) + to_chat(src, SPAN_WARNING("You don't have the right equipment to communicate in that way!")) // weird phrasing, but needs to cover speaking and signing + return - if(!(speaking && (speaking.flags & NO_STUTTER))) + // The LANG_FLAG_NO_STUTTER check means nonvocal or unusually-produced + // languages (e.g. sign language, noise emotes, computer beeps) + // will not be affected by stuttering, slurring, silence, etc. effects. + if(!(speaking && (speaking.flags & LANG_FLAG_NO_STUTTER))) var/list/message_data = list(message, verb, 0) if(handle_speech_problems(message_data)) message = message_data[1] @@ -219,11 +199,11 @@ proc/get_radio_key_from_channel(var/channel) if(!message || message == "") return 0 - var/list/obj/item/used_radios = new - if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)) + var/list/obj/item/used_radios = list() + if(handle_message_mode(message_mode, message, verb, speaking, used_radios)) return 1 - var/list/handle_v = handle_speech_sound() + var/list/handle_v = (istype(speaking) && speaking.get_spoken_sound()) || handle_speech_sound() var/sound/speech_sound = handle_v[1] var/sound_vol = handle_v[2] @@ -241,7 +221,7 @@ proc/get_radio_key_from_channel(var/channel) if(speaking) message_range = speaking.get_talkinto_msg_range(message) var/msg - if(!speaking || !(speaking.flags & NO_TALK_MSG)) + if(!speaking || !(speaking.flags & LANG_FLAG_NO_TALK_MSG)) msg = "\The [src] talks into \the [used_radios[1]]." for(var/mob/living/M in hearers(5, src)) if((M != src) && msg) @@ -255,11 +235,11 @@ proc/get_radio_key_from_channel(var/channel) //handle nonverbal and sign languages here if (speaking) - if (speaking.flags & NONVERBAL) + if (speaking.flags & LANG_FLAG_NONVERBAL) if (prob(30)) src.custom_emote(1, "[pick(speaking.signlang_verb)].") - if (speaking.flags & SIGNLANG) + if (speaking.flags & LANG_FLAG_SIGNLANG) log_say("[name]/[key] : SIGN: [message]") return say_signlang(message, pick(speaking.signlang_verb), speaking) @@ -274,18 +254,23 @@ proc/get_radio_key_from_channel(var/channel) italics = 1 sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact - get_mobs_and_objs_in_view_fast(T, message_range, listening, listening_obj, /datum/client_preference/ghost_ears) + get_listeners_in_range(T, message_range, listening, listening_obj, /datum/client_preference/ghost_ears) + var/speech_bubble_state = check_speech_punctuation_state(message) + var/speech_state_modifier = get_speech_bubble_state_modifier() + if(speech_bubble_state && speech_state_modifier) + speech_bubble_state = "[speech_state_modifier]_[speech_bubble_state]" - var/speech_bubble_test = say_test(message) - var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]") - speech_bubble.layer = layer - speech_bubble.plane = plane + var/image/speech_bubble + if(speech_bubble_state) + speech_bubble = image('icons/mob/talk.dmi', src, speech_bubble_state) + speech_bubble.layer = layer + speech_bubble.plane = plane var/list/speech_bubble_recipients = list() for(var/mob/M in listening) if(M) - M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol) + M.hear_say(message, verb, speaking, italics, src, speech_sound, sound_vol) if(M.client) speech_bubble_recipients += M.client @@ -294,26 +279,29 @@ proc/get_radio_key_from_channel(var/channel) if(O) //It's possible that it could be deleted in the meantime. O.hear_talk(src, message, verb, speaking) + var/list/eavesdroppers = list() if(whispering) var/eavesdroping_range = 5 var/list/eavesdroping = list() var/list/eavesdroping_obj = list() - get_mobs_and_objs_in_view_fast(T, eavesdroping_range, eavesdroping, eavesdroping_obj) + get_listeners_in_range(T, eavesdroping_range, eavesdroping, eavesdroping_obj) eavesdroping -= listening eavesdroping_obj -= listening_obj for(var/mob/M in eavesdroping) if(M) - M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol) + M.hear_say(stars(message), verb, speaking, italics, src, speech_sound, sound_vol) if(M.client) - speech_bubble_recipients |= M.client + eavesdroppers |= M.client for(var/obj/O in eavesdroping) spawn(0) if(O) //It's possible that it could be deleted in the meantime. O.hear_talk(src, stars(message), verb, speaking) - INVOKE_ASYNC(GLOBAL_PROC, .proc/animate_speech_bubble, speech_bubble, speech_bubble_recipients, 30) - INVOKE_ASYNC(src, /atom/movable/proc/animate_chat, message, speaking, italics, speech_bubble_recipients, 30) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(animate_speech_bubble), speech_bubble, speech_bubble_recipients | eavesdroppers, 30) + INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, animate_chat), message, speaking, italics, speech_bubble_recipients) + if(length(eavesdroppers)) + INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, animate_chat), stars(message), speaking, italics, eavesdroppers) if(whispering) log_whisper("[name]/[key] : [message]") @@ -326,8 +314,28 @@ proc/get_radio_key_from_channel(var/channel) O.hear_signlang(message, verb, language, src) return 1 -/obj/effect/speech_bubble - var/mob/parent +/mob/proc/GetVoice() + var/voice_sub + var/obj/item/rig/rig = get_rig() + if(rig?.speech?.voice_holder?.active && rig.speech.voice_holder.voice) + voice_sub = rig.speech.voice_holder.voice + + if(!voice_sub) + + var/list/check_gear = list(get_equipped_item(slot_wear_mask_str), get_equipped_item(slot_head_str)) + if(rig) + var/datum/extension/armor/rig/armor_datum = get_extension(rig, /datum/extension/armor) + if(istype(armor_datum) && armor_datum.sealed && rig.helmet == get_equipped_item(slot_head_str)) + check_gear |= rig + + for(var/obj/item/gear in check_gear) + if(!gear) + continue + var/obj/item/voice_changer/changer = locate() in gear + if(changer && changer.active && changer.voice) + voice_sub = changer.voice + + if(voice_sub) + return voice_sub -/mob/living/proc/GetVoice() - return name + return real_name || name diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index eb880407d9f6..e72e3798f8cc 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1,8 +1,8 @@ #define AI_CHECK_WIRELESS 1 #define AI_CHECK_RADIO 2 -var/list/ai_list = list() -var/list/ai_verbs_default = list( +var/global/list/ai_list = list() +var/global/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/ai_announcement, /mob/living/silicon/ai/proc/ai_call_shuttle, /mob/living/silicon/ai/proc/ai_emergency_message, @@ -11,7 +11,7 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location, /mob/living/silicon/ai/proc/ai_hologram_change, - /mob/living/silicon/ai/proc/ai_network_change, + /mob/living/silicon/ai/proc/ai_channel_change, /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_checklaws, @@ -31,8 +31,8 @@ var/list/ai_verbs_default = list( /mob/living/silicon/proc/access_computer, /mob/living/silicon/ai/proc/ai_power_override, /mob/living/silicon/ai/proc/ai_shutdown, - /mob/living/silicon/ai/proc/ai_reset_radio_keys, - /mob/living/silicon/ai/proc/run_program + /mob/living/silicon/ai/proc/run_program, + /mob/living/silicon/ai/proc/pick_color ) //Not sure why this is necessary... @@ -49,30 +49,29 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai name = "AI" - icon = 'icons/mob/AI.dmi'// + icon = 'icons/mob/AI.dmi' icon_state = "ai" - anchored = 1 // -- TLE - density = 1 + mob_sort_value = 2 + anchored = TRUE // -- TLE + density = TRUE status_flags = CANSTUN|CANPARALYSE|CANPUSH - shouldnt_see = list(/obj/effect/rune) - maxHealth = 200 - var/list/network = list("Exodus") + max_health = 200 + + silicon_camera = /obj/item/camera/siliconcam/ai_camera + silicon_radio = /obj/item/radio/headset/heads/ai_integrated + var/obj/machinery/camera/camera = null var/list/connected_robots = list() var/aiRestorePowerRoutine = 0 var/viewalerts = 0 - var/icon/holo_icon//Blue hologram. Face is assigned when AI is created. + var/icon/holo_icon //Blue hologram. Face is assigned when AI is created. var/icon/holo_icon_longrange //Yellow hologram. var/holo_icon_malf = FALSE // for new hologram system var/obj/item/multitool/aiMulti = null - - silicon_camera = /obj/item/camera/siliconcam/ai_camera - silicon_radio = /obj/item/radio/headset/heads/ai_integrated var/obj/item/radio/headset/heads/ai_integrated/ai_radio var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through. var/datum/trackable/track = null - var/last_announcement = "" var/control_disabled = 0 var/datum/announcement/priority/announcement var/obj/machinery/ai_powersupply/psupply = null // Backwards reference to AI's powersupply object. @@ -83,24 +82,10 @@ var/list/ai_verbs_default = list( //NEWMALF VARIABLES var/malfunctioning = 0 // Master var that determines if AI is malfunctioning. - var/datum/malf_hardware/hardware = null // Installed piece of hardware. - var/datum/malf_research/research = null // Malfunction research datum. - var/obj/machinery/power/apc/hack = null // APC that is currently being hacked. + var/obj/machinery/apc/hack = null // APC that is currently being hacked. var/list/hacked_apcs = null // List of all hacked APCs - var/hacking = 0 // Set to 1 if AI is hacking APC, cyborg, other AI, or running system override. - var/system_override = 0 // Set to 1 if system override is initiated, 2 if succeeded. - var/hack_can_fail = 1 // If 0, all abilities have zero chance of failing. - var/hack_fails = 0 // This increments with each failed hack, and determines the warning message text. - var/errored = 0 // Set to 1 if runtime error occurs. Only way of this happening i can think of is admin fucking up with varedit. - var/bombing_core = 0 // Set to 1 if core auto-destruct is activated - var/bombing_station = 0 // Set to 1 if station nuke auto-destruct is activated - var/override_CPUStorage = 0 // Bonus/Penalty CPU Storage. For use by admins/testers. - var/override_CPURate = 0 // Bonus/Penalty CPU generation rate. For use by admins/testers. var/uncardable = 0 // Whether the AI can be carded when malfunctioning. var/hacked_apcs_hidden = 0 // Whether the hacked APCs belonging to this AI are hidden, reduces CPU generation from APCs. - var/intercepts_communication = 0 // Whether the AI intercepts fax and emergency transmission communications. - var/last_failed_malf_message = null - var/last_failed_malf_title = null var/datum/ai_icon/selected_sprite // The selected icon set var/carded @@ -108,7 +93,7 @@ var/list/ai_verbs_default = list( var/multitool_mode = 0 var/default_ai_icon = /datum/ai_icon/blue - var/static/list/custom_ai_icons_by_ckey_and_name + var/custom_color_tone //This is a hex, despite being converted to rgb by gethologramicon. /mob/living/silicon/ai/proc/add_ai_verbs() src.verbs |= ai_verbs_default @@ -118,27 +103,27 @@ var/list/ai_verbs_default = list( src.verbs -= ai_verbs_default src.verbs += /mob/living/verb/ghost -/mob/living/silicon/ai/Initialize(mapload, var/datum/ai_laws/L, var/obj/item/mmi/B, var/safety = 0) +/mob/living/silicon/ai/Initialize(mapload, var/datum/ai_laws/L, var/obj/item/organ/internal/brain_interface/B, var/safety = 0) announcement = new() announcement.title = "A.I. Announcement" announcement.announcement_type = "A.I. Announcement" announcement.newscast = 1 - var/list/possibleNames = GLOB.ai_names + var/list/possibleNames = global.ai_names var/pickedName = null while(!pickedName) - pickedName = pick(GLOB.ai_names) - for (var/mob/living/silicon/ai/A in GLOB.silicon_mob_list) + pickedName = pick(global.ai_names) + for (var/mob/living/silicon/ai/A in global.silicon_mob_list) if (A.real_name == pickedName && possibleNames.len > 1) //fixing the theoretically possible infinite loop possibleNames -= pickedName pickedName = null fully_replace_character_name(pickedName) - anchored = 1 + anchored = TRUE set_density(1) - holo_icon = getHologramIcon(icon('icons/mob/hologram.dmi',"Face")) + holo_icon = getHologramIcon(icon('icons/mob/hologram.dmi',"Face"), custom_color_tone) holo_icon_longrange = getHologramIcon(icon('icons/mob/hologram.dmi',"Face"), hologram_color = HOLOPAD_LONG_RANGE) if(istype(L, /datum/ai_laws)) @@ -146,70 +131,64 @@ var/list/ai_verbs_default = list( aiMulti = new(src) - additional_law_channels["Holopad"] = ":h" + additional_law_channels["Holopad"] = "h" - if (istype(loc, /turf)) + if (isturf(loc)) add_ai_verbs(src) //Languages add_language(/decl/language/binary, 1) + add_language(/decl/language/machine, 1) add_language(/decl/language/human/common, 1) add_language(/decl/language/sign, 0) if(!safety)//Only used by AIize() to successfully spawn an AI. - if (!B)//If there is no player/brain inside. + var/mob/living/brainmob = B?.get_brainmob() + if(!brainmob) // If there is no player/brain inside. empty_playable_ai_cores += new/obj/structure/aicore/deactivated(loc)//New empty terminal. - qdel(src)//Delete AI. - return - else - if (B.brainmob.mind) - B.brainmob.mind.transfer_to(src) + . = INITIALIZE_HINT_QDEL + else if(brainmob.mind) + brainmob.mind.transfer_to(src) + reset_hud_overlays() + ai_list += src create_powersupply() + // Slightly wonky structures here due silicon init being a spaghetti + // mess and returning early causing Destroy() to qdel paths. + var/base_return_val = ..() + if(. == INITIALIZE_HINT_QDEL) + return - hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[ID_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPTRACK_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[SPECIALROLE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - - ai_list += src - . = ..() ai_radio = silicon_radio - ai_radio.myAi = src + return base_return_val /mob/living/silicon/ai/proc/on_mob_init() - to_chat(src, "You are playing the [station_name()]'s AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).") - to_chat(src, "To look at other areas, click on yourself to get a camera menu.") - to_chat(src, "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.") - to_chat(src, "To use something, simply click on it.") - to_chat(src, "Use say [get_language_prefix()]b to speak to your cyborgs through binary. Use say :h to speak from an active holopad.") - to_chat(src, "For department channels, use the following say commands:") - - var/radio_text = "" - for(var/i = 1 to silicon_radio.channels.len) - var/channel = silicon_radio.channels[i] - var/key = get_radio_key_from_channel(channel) - radio_text += "[key] - [channel]" - if(i != silicon_radio.channels.len) - radio_text += ", " - - to_chat(src, radio_text) - show_laws() - to_chat(src, "These laws may be changed by other players or by other random events.") - //Prevents more than one active core spawning on the same tile. Technically just a sanitization for roundstart join for(var/obj/structure/aicore/C in src.loc) qdel(C) - job = "AI" setup_icon() eyeobj.possess(src) CreateModularRecord(src, /datum/computer_file/report/crew_record/synth) + show_join_message() + +// Give our radio a bit of time to connect to the network and get its channels. +/mob/living/silicon/ai/proc/show_join_message() + set waitfor = FALSE + var/timeout_mob_init = world.time + 5 SECONDS + while(world.time < timeout_mob_init && length(ai_radio?.get_accessible_channel_descriptions(src)) <= 1) + sleep(1) + to_chat(src, "You are playing the [station_name()]'s AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).") + to_chat(src, "To look at other areas, click on yourself to get a camera menu.") + to_chat(src, "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.") + to_chat(src, "To use something, simply click on it.") + var/list/channel_descriptions = ai_radio?.get_accessible_channel_descriptions(src) + if(length(channel_descriptions)) + to_chat(src, "You can speak on comms channels with the following [length(channel_descriptions) == 1 ? "shortcut" : "shortcuts"]:") + for(var/line in channel_descriptions) + to_chat(src, line) + show_laws() + to_chat(src, "These laws may be changed by other players or by other random events.") /mob/living/silicon/ai/Destroy() for(var/robot in connected_robots) @@ -228,42 +207,17 @@ var/list/ai_verbs_default = list( . = ..() +var/global/list/custom_ai_icons_by_ckey_and_name = list() /mob/living/silicon/ai/proc/setup_icon() - if(LAZYACCESS(custom_ai_icons_by_ckey_and_name, "[ckey][real_name]")) - return - var/list/custom_icons = list() - LAZYSET(custom_ai_icons_by_ckey_and_name, "[ckey][real_name]", custom_icons) - - var/file = file2text(CUSTOM_ITEM_SYNTH_CONFIG) - var/lines = splittext(file, "\n") - - var/custom_index = 1 - var/custom_icon_states = icon_states(CUSTOM_ITEM_SYNTH) - - for(var/line in lines) - // split & clean up - var/list/Entry = splittext(line, ":") - for(var/i = 1 to Entry.len) - Entry[i] = trim(Entry[i]) - - if(Entry.len < 2) - continue - if(Entry.len == 2) // This is to handle legacy entries - Entry[++Entry.len] = Entry[1] - - if(Entry[1] == src.ckey && Entry[2] == src.real_name) - var/alive_icon_state = "[Entry[3]]-ai" - var/dead_icon_state = "[Entry[3]]-ai-crash" - - if(!(alive_icon_state in custom_icon_states)) - to_chat(src, "Custom display entry found but the icon state '[alive_icon_state]' is missing!") - continue - - if(!(dead_icon_state in custom_icon_states)) - dead_icon_state = "" - - selected_sprite = new/datum/ai_icon("Custom Icon [custom_index++]", alive_icon_state, dead_icon_state, COLOR_WHITE, CUSTOM_ITEM_SYNTH) - custom_icons += selected_sprite + if(ckey) + if(global.custom_ai_icons_by_ckey_and_name["[ckey][real_name]"]) + selected_sprite = global.custom_ai_icons_by_ckey_and_name["[ckey][real_name]"] + else + for(var/datum/custom_icon/cicon as anything in SScustomitems.custom_icons_by_ckey[ckey]) + if(cicon.category == "AI Icon" && lowertext(real_name) == cicon.character_name) + selected_sprite = new /datum/ai_icon("Custom Icon - [cicon.character_name]", cicon.ids_to_icons[1], cicon.ids_to_icons[2], COLOR_WHITE, cicon.ids_to_icons[cicon.ids_to_icons[1]]) + global.custom_ai_icons_by_ckey_and_name["[ckey][real_name]"] = selected_sprite + break update_icon() /mob/living/silicon/ai/pointed(atom/A as mob|obj|turf in view()) @@ -291,16 +245,26 @@ var/list/ai_verbs_default = list( update_icon() +/mob/living/silicon/ai/proc/pick_color() + set category = "Silicon Commands" + set name = "Set AI Hologram Color" + if(stat || !has_power()) + return + + var/new_color = input("Select or enter a color!", "AI") as color + if(new_color) + custom_color_tone = new_color + to_chat(src, SPAN_NOTICE("You need to change your holopad icon in order for the color change to take effect!")) + /mob/living/silicon/ai/proc/available_icons() . = list() - var/all_ai_icons = decls_repository.get_decls_of_subtype(/datum/ai_icon) - for(var/ai_icon_type in all_ai_icons) - var/datum/ai_icon/ai_icon = all_ai_icons[ai_icon_type] + for(var/ai_icon_type in get_ai_icon_subtypes()) + var/datum/ai_icon/ai_icon = global.ai_icon_subtypes[ai_icon_type] if(ai_icon.may_used_by_ai(src)) dd_insertObjectList(., ai_icon) // Placing custom icons first to have them be at the top - . = LAZYACCESS(custom_ai_icons_by_ckey_and_name, "[ckey][real_name]") | . + . = global.custom_ai_icons_by_ckey_and_name["[ckey][real_name]"] | . /mob/living/silicon/ai/var/message_cooldown = 0 /mob/living/silicon/ai/proc/ai_announcement() @@ -342,20 +306,6 @@ var/list/ai_verbs_default = list( post_status("shuttle") -/mob/living/silicon/ai/proc/ai_recall_shuttle() - set category = "Silicon Commands" - set name = "Cancel Evacuation" - - if(check_unable(AI_CHECK_WIRELESS)) - return - - var/confirm = alert("Are you sure you want to cancel the evacuation?", "Confirm Cancel", "Yes", "No") - if(check_unable(AI_CHECK_WIRELESS)) - return - - if(confirm == "Yes") - cancel_call_proc(src) - /mob/living/silicon/ai/var/emergency_message_cooldown = 0 /mob/living/silicon/ai/proc/ai_emergency_message() set category = "Silicon Commands" @@ -369,12 +319,12 @@ var/list/ai_verbs_default = list( if(emergency_message_cooldown) to_chat(usr, "Arrays cycling. Please stand by.") return - var/input = sanitize(input(usr, "Please choose a message to transmit to [GLOB.using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "")) + var/input = sanitize(input(usr, "Please choose a message to transmit to [global.using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "")) if(!input) return Centcomm_announce(input, usr) to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an IA [GLOB.using_map.boss_short] announcement: [input]") + log_say("[key_name(usr)] has made an IA [global.using_map.boss_short] announcement: [input]") emergency_message_cooldown = 1 spawn(300) emergency_message_cooldown = 0 @@ -419,7 +369,7 @@ var/list/ai_verbs_default = list( if (href_list["track"]) var/mob/target = locate(href_list["track"]) in SSmobs.mob_list - var/mob/living/carbon/human/H = target + var/mob/living/human/H = target if(!istype(H) || (html_decode(href_list["trackname"]) == H.get_visible_name()) || (html_decode(href_list["trackname"]) == H.get_id_name())) ai_actual_track(target) @@ -432,12 +382,17 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/reset_view(atom/A) if(camera) camera.set_light(0) + if(istype(A,/obj/machinery/camera)) camera = A + ..() + if(istype(A,/obj/machinery/camera)) - if(camera_light_on) A.set_light(0.5, 0.1, AI_CAMERA_LUMINOSITY) - else A.set_light(0) + if(camera_light_on) + A.set_light(AI_CAMERA_LUMINOSITY) + else + A.set_light(0) /mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C) @@ -461,44 +416,38 @@ var/list/ai_verbs_default = list( src.view_core() //Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm -//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead -//Addition by Mord_Sith to define AI's network change ability -/mob/living/silicon/ai/proc/get_camera_network_list() +//Adds in /mob/living/silicon/ai/proc/ai_channel_change() instead +//Addition by Mord_Sith to define AI's channel change ability +/mob/living/silicon/ai/proc/get_camera_channel_list() if(check_unable()) return - var/list/cameralist = new() - for (var/obj/machinery/camera/C in cameranet.cameras) - if(!C.can_use()) - continue - var/list/tempnetwork = difflist(C.network,restricted_camera_networks,1) - for(var/i in tempnetwork) - cameralist[i] = i + var/list/valid_channels = list() + var/list/devices_by_channel = camera_repository.get_devices_by_channel() + for(var/channel in devices_by_channel) + for(var/datum/extension/network_device/camera/D in devices_by_channel[channel]) + if(D.cameranet_enabled && D.is_functional()) + valid_channels += channel + break + return valid_channels - cameralist = sortAssoc(cameralist) - return cameralist - -/mob/living/silicon/ai/proc/ai_network_change(var/network in get_camera_network_list()) +/mob/living/silicon/ai/proc/ai_channel_change(var/channel in get_camera_channel_list()) set category = "Silicon Commands" - set name = "Jump To Network" + set name = "Jump To Channel" unset_machine() - if(!network) + if(!channel) return if(!eyeobj) view_core() return - src.network = network - - for(var/obj/machinery/camera/C in cameranet.cameras) - if(!C.can_use()) - continue - if(network in C.network) - eyeobj.setLoc(get_turf(C)) + for(var/datum/extension/network_device/camera/D in camera_repository.devices_in_channel(channel)) + if(D.cameranet_enabled && D.is_functional()) + eyeobj.setLoc(get_turf(D.holder)) break - to_chat(src, "Switched to [network] camera network.") + to_chat(src, "Switched to [channel] camera channel.") //End of code by Mord_Sith /mob/living/silicon/ai/proc/ai_statuschange() @@ -525,7 +474,7 @@ var/list/ai_verbs_default = list( var/personnel_list[] = list() - for(var/datum/computer_file/report/crew_record/t in GLOB.all_crew_records)//Look in data core locked. + for(var/datum/computer_file/report/crew_record/t in global.all_crew_records)//Look in data core locked. personnel_list["[t.get_name()]: [t.get_rank()]"] = t.photo_front//Pull names, rank, and image. if(personnel_list.len) @@ -534,7 +483,7 @@ var/list/ai_verbs_default = list( if(character_icon) qdel(holo_icon)//Clear old icon so we're not storing it in memory. qdel(holo_icon_longrange) - holo_icon = getHologramIcon(icon(character_icon)) + holo_icon = getHologramIcon(icon(character_icon), custom_tone = custom_color_tone) holo_icon_longrange = getHologramIcon(icon(character_icon), hologram_color = HOLOPAD_LONG_RANGE) else alert("No suitable records found. Aborting.") @@ -550,7 +499,7 @@ var/list/ai_verbs_default = list( if(choice) qdel(holo_icon) qdel(holo_icon_longrange) - holo_icon = getHologramIcon(icon(choice.icon, choice.icon_state), noDecolor=choice.bypass_colorize) + holo_icon = getHologramIcon(icon(choice.icon, choice.icon_state), noDecolor=choice.bypass_colorize, custom_tone = custom_color_tone) holo_icon_longrange = getHologramIcon(icon(choice.icon, choice.icon_state), noDecolor=choice.bypass_colorize, hologram_color = HOLOPAD_LONG_RANGE) holo_icon_malf = choice.requires_malf return @@ -586,7 +535,7 @@ var/list/ai_verbs_default = list( src.camera.set_light(0) if(!camera.light_disabled) src.camera = camera - src.camera.set_light(0.5, 0.1, AI_CAMERA_LUMINOSITY) + src.camera.set_light(AI_CAMERA_LUMINOSITY) else src.camera = null else if(isnull(camera)) @@ -596,39 +545,37 @@ var/list/ai_verbs_default = list( var/obj/machinery/camera/camera = near_range_camera(src.eyeobj) if(camera && !camera.light_disabled) src.camera = camera - src.camera.set_light(0.5, 0.1, AI_CAMERA_LUMINOSITY) + src.camera.set_light(AI_CAMERA_LUMINOSITY) camera_light_on = world.timeofday + 1 * 20 // Update the light every 2 seconds. -/mob/living/silicon/ai/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/aicard)) - - var/obj/item/aicard/card = W +/mob/living/silicon/ai/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/aicard)) + var/obj/item/aicard/card = used_item card.grab_ai(src, user) - else if(isWrench(W)) + else if(IS_WRENCH(used_item)) if(anchored) user.visible_message("\The [user] starts to unbolt \the [src] from the plating...") if(!do_after(user,40, src)) user.visible_message("\The [user] decides not to unbolt \the [src].") - return + return TRUE user.visible_message("\The [user] finishes unfastening \the [src]!") - anchored = 0 - return + anchored = FALSE + return TRUE else user.visible_message("\The [user] starts to bolt \the [src] to the plating...") if(!do_after(user,40,src)) user.visible_message("\The [user] decides not to bolt \the [src].") - return + return TRUE user.visible_message("\The [user] finishes fastening down \the [src]!") - anchored = 1 - return - if(try_stock_parts_install(W, user)) - return - if(try_stock_parts_removal(W, user)) - return - else - return ..() + anchored = TRUE + return TRUE + if(try_stock_parts_install(used_item, user)) + return TRUE + if(try_stock_parts_removal(used_item, user)) + return TRUE + return ..() /mob/living/silicon/ai/proc/control_integrated_radio() set name = "Radio Settings" @@ -678,49 +625,39 @@ var/list/ai_verbs_default = list( return 0 /mob/living/silicon/ai/proc/is_in_chassis() - return istype(loc, /turf) + return isturf(loc) /mob/living/silicon/ai/proc/multitool_mode() set name = "Toggle Multitool Mode" set category = "Silicon Commands" multitool_mode = !multitool_mode - to_chat(src, "Multitool mode: [multitool_mode ? "E" : "Dise"]ngaged") - -/mob/living/silicon/ai/proc/ai_reset_radio_keys() - set name = "Reset Radio Encryption Keys" - set category = "Silicon Commands" - - silicon_radio.recalculateChannels() - to_chat(src, SPAN_NOTICE("Integrated radio encryption keys have been reset.")) + to_chat(src, SPAN_NOTICE("Multitool mode: [multitool_mode ? "E" : "Dise"]ngaged")) /mob/living/silicon/ai/on_update_icon() + ..() if(!selected_sprite || !(selected_sprite in available_icons())) - selected_sprite = decls_repository.get_decl(default_ai_icon) + selected_sprite = get_ai_icon(default_ai_icon) icon = selected_sprite.icon if(stat == DEAD) icon_state = selected_sprite.dead_icon - set_light(0.7, 0.1, 1, 2, selected_sprite.dead_light) + set_light(3, 1, selected_sprite.dead_light) else if(!has_power()) icon_state = selected_sprite.nopower_icon - set_light(0.4, 0.1, 1, 2, selected_sprite.nopower_light) + set_light(1, 1, selected_sprite.nopower_light) else icon_state = selected_sprite.alive_icon - set_light(0.4, 0.1, 1, 2, selected_sprite.alive_light) + set_light(1, 1, selected_sprite.alive_light) // Pass lying down or getting up to our pet human, if we're in a rig. -/mob/living/silicon/ai/lay_down() - set name = "Rest" - set category = "IC" - - resting = 0 +/mob/living/silicon/ai/lay_down(block_posture as null) var/obj/item/rig/rig = src.get_rig() if(rig) rig.force_rest(src) -/mob/living/silicon/ai/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays, var/ai_show) - . = ai_show ? ..(user, text_content, skip_delays) : stars(text_content) +/mob/living/silicon/ai/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays, var/digital = FALSE) + . = digital ? ..(user, text_content, skip_delays) : stars(text_content) /mob/living/silicon/ai/proc/ai_take_image() set name = "Take Photo" @@ -748,7 +685,7 @@ var/list/ai_verbs_default = list( if(!A) return - for(var/turf/simulated/floor/bluegrid/F in A) + for(var/turf/floor/bluegrid/F in A) F.color = f_color to_chat(usr, SPAN_NOTICE("Proccessing strata color was changed to \"[f_color]\"")) @@ -760,11 +697,37 @@ var/list/ai_verbs_default = list( run_program("sensormonitor") /mob/living/silicon/ai/proc/run_program(var/filename) - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(!istype(os)) - to_chat(src, SPAN_WARNING("You seem to be lacking an NTOS capable device!")) + to_chat(src, SPAN_WARNING("You seem to be lacking an OS capable device!")) return if(!os.on) os.system_boot() if(os.run_program(filename)) os.ui_interact(src) + +/mob/living/silicon/ai/get_admin_job_string() + return "AI" + +/mob/living/silicon/ai/eastface() + if(holo) + holo.set_dir_hologram(client.client_dir(EAST), src) + return ..() + +/mob/living/silicon/ai/westface() + if(holo) + holo.set_dir_hologram(client.client_dir(WEST), src) + return ..() + +/mob/living/silicon/ai/northface() + if(holo) + holo.set_dir_hologram(client.client_dir(NORTH), src) + return ..() + +/mob/living/silicon/ai/southface() + if(holo) + holo.set_dir_hologram(client.client_dir(SOUTH), src) + return ..() + +/mob/living/silicon/ai/say_understands(mob/speaker, decl/language/speaking) + return (!speaking && ispAI(speaker)) || ..() diff --git a/code/modules/mob/living/silicon/ai/ai_camera_proc.dm b/code/modules/mob/living/silicon/ai/ai_camera_proc.dm deleted file mode 100644 index 8b137891791f..000000000000 --- a/code/modules/mob/living/silicon/ai/ai_camera_proc.dm +++ /dev/null @@ -1 +0,0 @@ - diff --git a/code/modules/mob/living/silicon/ai/ai_damage.dm b/code/modules/mob/living/silicon/ai/ai_damage.dm index 087e8ecafcbf..39bde078b112 100644 --- a/code/modules/mob/living/silicon/ai/ai_damage.dm +++ b/code/modules/mob/living/silicon/ai/ai_damage.dm @@ -12,17 +12,27 @@ /mob/living/silicon/ai/getOxyLoss() return oxyloss -/mob/living/silicon/ai/adjustFireLoss(var/amount) +/mob/living/silicon/ai/adjustFireLoss(var/amount, var/do_update_health = TRUE) if(status_flags & GODMODE) return - fireloss = max(0, fireloss + min(amount, health)) + fireloss = max(0, fireloss + min(amount, current_health)) + if(do_update_health) + update_health() -/mob/living/silicon/ai/adjustBruteLoss(var/amount) - if(status_flags & GODMODE) return - bruteloss = max(0, bruteloss + min(amount, health)) +/mob/living/silicon/ai/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + if(!(status_flags & GODMODE)) + bruteloss = max(0, bruteloss + min(amount, current_health)) + ..() -/mob/living/silicon/ai/adjustOxyLoss(var/amount) - if(status_flags & GODMODE) return - oxyloss = max(0, oxyloss + min(amount, maxHealth - oxyloss)) +/mob/living/silicon/ai/adjustOxyLoss(var/damage, var/do_update_health = TRUE) + if(!(status_flags & GODMODE)) + oxyloss = max(0, oxyloss + min(damage, get_max_health() - oxyloss)) + ..() + +/mob/living/silicon/ai/setBruteLoss(var/amount) + if(status_flags & GODMODE) + bruteloss = 0 + return + bruteloss = max(0, amount) /mob/living/silicon/ai/setFireLoss(var/amount) if(status_flags & GODMODE) @@ -36,22 +46,16 @@ return oxyloss = max(0, amount) -/mob/living/silicon/ai/updatehealth() - if(status_flags & GODMODE) - health = maxHealth - set_stat(CONSCIOUS) - setOxyLoss(0) - else - health = maxHealth - getFireLoss() - getBruteLoss() // Oxyloss is not part of health as it represents AIs backup power. AI is immune against ToxLoss as it is machine. +/mob/living/silicon/ai/update_health() + . = ..() + if(!.) + set_damage(OXY, 0) /mob/living/silicon/ai/rejuvenate() ..() add_ai_verbs(src) -// Returns percentage of AI's remaining backup capacitor charge (maxhealth - oxyloss). +// Returns percentage of AI's remaining backup capacitor charge (max health - oxyloss). /mob/living/silicon/ai/proc/backup_capacitor() - return ((getOxyLoss() - maxHealth) / maxHealth) * (-100) - -// Returns percentage of AI's remaining hardware integrity (maxhealth - (bruteloss + fireloss)) -/mob/living/silicon/ai/proc/hardware_integrity() - return (health / maxHealth) * 100 \ No newline at end of file + var/current_max_health = get_max_health() + return ((get_damage(OXY) - current_max_health) / current_max_health) * (-100) diff --git a/code/modules/mob/living/silicon/ai/ai_movement.dm b/code/modules/mob/living/silicon/ai/ai_movement.dm index 1092a73d25d6..c2db84983ff5 100644 --- a/code/modules/mob/living/silicon/ai/ai_movement.dm +++ b/code/modules/mob/living/silicon/ai/ai_movement.dm @@ -1,6 +1,5 @@ /mob/living/silicon/ai movement_handlers = list( - /datum/movement_handler/mob/relayed_movement, /datum/movement_handler/mob/death, /datum/movement_handler/mob/conscious, /datum/movement_handler/mob/eye, diff --git a/code/modules/mob/living/silicon/ai/ai_radio.dm b/code/modules/mob/living/silicon/ai/ai_radio.dm new file mode 100644 index 000000000000..7a195abc9bac --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_radio.dm @@ -0,0 +1,27 @@ +/obj/item/radio/headset/heads/ai_integrated + name = "\improper AI subspace transceiver" + desc = "Integrated AI radio transceiver." + encryption_keys = list(/obj/item/encryptionkey/heads/ai_integrated) + var/disabledAi = 0 // Atlantis: Used to manually disable AI's integrated radio via intelliCard menu. + +/obj/item/radio/headset/heads/ai_integrated/get_accessible_channel_descriptions(mob/user) + . = ..() + if(user) + LAZYADD(., "- Holopad Transmission: [user.get_department_radio_prefix()]h") + +/obj/item/encryptionkey/heads/ai_integrated + name = "ai integrated encryption key" + desc = "Integrated encryption key." + color = COLOR_GOLD + fill_color = COLOR_PALE_GOLD + inlay_color = COLOR_ROYAL_BLUE + can_decrypt = list( + access_bridge, + access_security, + access_engine, + access_research, + access_medical, + access_cargo, + access_bar, + access_ai_upload + ) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 3c89002c534d..9135ac2b3a92 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -1,20 +1,11 @@ -/mob/living/silicon/ai/death(gibbed, deathmessage, show_dead_message) - - if(stat == DEAD) - return - - if(src.eyeobj) - src.eyeobj.setLoc(get_turf(src)) - - - remove_ai_verbs(src) - - for(var/obj/machinery/ai_status_display/O in world) - O.mode = 2 - - if (istype(loc, /obj/item/aicard)) - var/obj/item/aicard/card = loc - card.update_icon() - - . = ..(gibbed,"gives one shrill beep before falling lifeless.", "You have suffered a critical system failure, and are dead.") - set_density(1) +/mob/living/silicon/ai/death(gibbed) + . = ..() + if(.) + eyeobj?.setLoc(get_turf(src)) + remove_ai_verbs(src) + for(var/obj/machinery/ai_status_display/O in SSmachines.machinery) + O.mode = 2 + if (istype(loc, /obj/item/aicard)) + var/obj/item/aicard/card = loc + card.update_icon() + set_density(TRUE) diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index 391620542b07..8807ed377466 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -1,36 +1,33 @@ -/mob/living/silicon/ai/examine(mob/user) +/mob/living/silicon/ai/examined_by(mob/user, distance, infix, suffix) . = ..() + user?.showLaws(src) - var/msg = "" - if (src.stat == DEAD) - msg += "It appears to be powered-down.\n" +/mob/living/silicon/ai/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = ..() + if(stat == DEAD) + . += "It appears to be powered-down." else - msg += "" - if (src.getBruteLoss()) - if (src.getBruteLoss() < 30) - msg += "It looks slightly dented.\n" - else - msg += "It looks severely dented!\n" - if (src.getFireLoss()) - if (src.getFireLoss() < 30) - msg += "It looks slightly charred.\n" - else - msg += "Its casing is melted and heat-warped!\n" + var/brute_damage = get_damage(BRUTE) + if (brute_damage >= 30) + . += SPAN_WARNING("It looks severely dented!") + else if(brute_damage) + . += SPAN_WARNING("It looks slightly dented.") + var/burn_damage = get_damage(BURN) + if(burn_damage >= 30) + . += SPAN_WARNING("Its casing is melted and heat-warped!") + else if(burn_damage) + . += SPAN_WARNING("It looks slightly charred.") if (!has_power()) - if (src.getOxyLoss() > 175) - msg += "It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.\n" - else if(src.getOxyLoss() > 100) - msg += "It seems to be running on backup power. Its display is blinking a \"BACKUP POWER LOW\" warning.\n" + var/oxy_damage = get_damage(OXY) + if (oxy_damage > 175) + . += SPAN_WARNING("It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.") + else if(oxy_damage > 100) + . += SPAN_WARNING("It seems to be running on backup power. Its display is blinking a \"BACKUP POWER LOW\" warning.") else - msg += "It seems to be running on backup power.\n" - - if (src.stat == UNCONSCIOUS) - msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n" - msg += "" - msg += "*---------*" - to_chat(user, msg) - user.showLaws(src) - return + . += SPAN_WARNING("It seems to be running on backup power.") + if (stat == UNCONSCIOUS) + . += SPAN_WARNING("It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".") + . += "*---------*" /mob/proc/showLaws(var/mob/living/silicon/S) return diff --git a/code/modules/mob/living/silicon/ai/icons.dm b/code/modules/mob/living/silicon/ai/icons.dm index a461b7819558..de4c3e77fd5e 100644 --- a/code/modules/mob/living/silicon/ai/icons.dm +++ b/code/modules/mob/living/silicon/ai/icons.dm @@ -1,3 +1,15 @@ +var/global/list/ai_icon_subtypes +/proc/get_ai_icon(var/ai_icon) + get_ai_icon_subtypes() + return global.ai_icon_subtypes[ai_icon] + +/proc/get_ai_icon_subtypes() + if(!length(global.ai_icon_subtypes)) + global.ai_icon_subtypes = list() + for(var/ai_icon_type in subtypesof(/datum/ai_icon)) + ai_icon_subtypes[ai_icon_type] = new ai_icon_type + return global.ai_icon_subtypes + /datum/ai_icon var/name var/icon = 'icons/mob/AI.dmi' @@ -28,7 +40,7 @@ name = "[name] (Malf)" /datum/ai_icon/malf/may_used_by_ai(var/mob/living/silicon/ai/AI) - return istype(AI) && AI.is_traitor() + return istype(AI) && AI.is_malfunctioning() /datum/ai_icon/red name = "Red" diff --git a/code/modules/mob/living/silicon/ai/latejoin.dm b/code/modules/mob/living/silicon/ai/latejoin.dm index 455be31f5151..cc0b00cf294f 100644 --- a/code/modules/mob/living/silicon/ai/latejoin.dm +++ b/code/modules/mob/living/silicon/ai/latejoin.dm @@ -20,8 +20,16 @@ log_and_message_admins("removed themselves from the round via Wipe Core") // We warned you. + do_telecomms_announcement(src, "\The [src] has been moved to intelligence storage.", "Artificial Intelligence Oversight") empty_playable_ai_cores += new /obj/structure/aicore/deactivated(loc) - GLOB.global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight") //Handle job slot/tater cleanup. clear_client() + +/obj/abstract/landmark/start/ai + name = "AI" + +/obj/abstract/landmark/start/ai/Initialize() + . = ..() + //The job subsystem does its thing before we can, so we've got to handle this + empty_playable_ai_cores += new /obj/structure/aicore/deactivated(get_turf(loc)) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/laws.dm b/code/modules/mob/living/silicon/ai/laws.dm index 5a767d6ddf8e..2fb329fc4b80 100644 --- a/code/modules/mob/living/silicon/ai/laws.dm +++ b/code/modules/mob/living/silicon/ai/laws.dm @@ -18,9 +18,9 @@ /mob/living/silicon/ai/add_ion_law(var/law) ..() - for(var/mob/living/silicon/robot/R in GLOB.silicon_mob_list) - if(R.lawupdate && (R.connected_ai == src)) - R.show_laws() + for(var/mob/living/silicon/robot/robot in global.silicon_mob_list) + if(robot.lawupdate && (robot.connected_ai == src)) + robot.show_laws() /mob/living/silicon/ai/proc/ai_checklaws() set category = "Silicon Commands" diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 08a331acb5bb..da088b6089ca 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -1,45 +1,36 @@ -/mob/living/silicon/ai/Life() - if (src.stat == DEAD) - return +/mob/living/silicon/ai/should_be_dead() + return get_health_percent() <= 0 || backup_capacitor() <= 0 - if (src.stat!=CONSCIOUS) +/mob/living/silicon/ai/handle_regular_status_updates() + . = ..() + if(stat != CONSCIOUS) src.cameraFollow = null src.reset_view(null) - src.updatehealth() - - if ((hardware_integrity() <= 0) || (backup_capacitor() <= 0)) - death() - return - +/mob/living/silicon/ai/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE // If our powersupply object was destroyed somehow, create new one. if(!psupply) create_powersupply() - - handle_stunned() // Handle EMP-stun - handle_paralysed() // Just in case something snuck in a Paralyse() call. - lying = 0 // Handle lying down - // We aren't shut down, and we lack external power. Try to fix it using the restoration routine. if (!self_shutdown && !has_power(0)) // AI's restore power routine is not running. Start it automatically. if(aiRestorePowerRoutine == AI_RESTOREPOWER_IDLE) aiRestorePowerRoutine = AI_RESTOREPOWER_STARTING handle_power_failure() - - handle_impaired_vision() update_power_usage() handle_power_oxyloss() - handle_confused() - update_sight() - process_queued_alarms() - handle_regular_hud_updates() switch(src.sensor_mode) if (SEC_HUD) process_sec_hud(src,0,src.eyeobj,get_computer_network()) if (MED_HUD) process_med_hud(src,0,src.eyeobj,get_computer_network()) + process_os() + if(controlling_drone && stat != CONSCIOUS) + controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") /mob/living/silicon/ai/update_living_sight() if(!has_power() || self_shutdown) diff --git a/code/modules/mob/living/silicon/ai/logout.dm b/code/modules/mob/living/silicon/ai/logout.dm index 5f4eafd70771..f58a05e7c611 100644 --- a/code/modules/mob/living/silicon/ai/logout.dm +++ b/code/modules/mob/living/silicon/ai/logout.dm @@ -1,6 +1,6 @@ /mob/living/silicon/ai/Logout() ..() - for(var/obj/machinery/ai_status_display/O in world) //change status + for(var/obj/machinery/ai_status_display/O in SSmachines.machinery) //change status O.mode = 0 if(!isturf(loc)) if (client) diff --git a/code/modules/mob/living/silicon/ai/power.dm b/code/modules/mob/living/silicon/ai/power.dm index d63b67ad5278..72c7e11cdff6 100644 --- a/code/modules/mob/living/silicon/ai/power.dm +++ b/code/modules/mob/living/silicon/ai/power.dm @@ -8,7 +8,7 @@ return to_chat(src, "Main power lost. System switched to internal capacitor. Beginning diagnostics.") - var/obj/machinery/power/apc/theAPC = null + var/obj/machinery/apc/theAPC = null var/connection_failures = 0 while(aiRestorePowerRoutine) // If the routine is running, proceed to another step. @@ -85,9 +85,9 @@ -// Handles all necessary power checks: Area power, inteliCard and Malf AI APU power and manual override. +// Handles all necessary power checks: Area power, intelliCard and Malf AI APU power and manual override. /mob/living/silicon/ai/proc/has_power(var/respect_override = 1) - if(psupply && psupply.powered()) + if(psupply && !(psupply.stat & NOPOWER)) return 1 if(istype(src.loc,/obj/item)) return 1 @@ -98,7 +98,7 @@ return 0 // Resets passed APC so the AI may function again. -/mob/living/silicon/ai/proc/reset_apc(var/obj/machinery/power/apc/A) +/mob/living/silicon/ai/proc/reset_apc(var/obj/machinery/apc/A) if(!istype(A)) return @@ -126,7 +126,7 @@ else if(aiRestorePowerRoutine) return AI_POWERUSAGE_RESTORATION - if(getOxyLoss()) + if(get_damage(OXY)) return AI_POWERUSAGE_RECHARGING return AI_POWERUSAGE_NORMAL @@ -142,11 +142,11 @@ if(has_power(0)) // Self-shutdown mode uses only 10kW, so we don't have any spare power to charge. if(!self_shutdown || carded) - adjustOxyLoss(AI_POWERUSAGE_NORMAL - AI_POWERUSAGE_RECHARGING) + take_damage(AI_POWERUSAGE_NORMAL - AI_POWERUSAGE_RECHARGING, OXY) return // Not powered. Gain oxyloss depeding on our power usage. - adjustOxyLoss(calculate_power_usage()) + take_damage(calculate_power_usage(), OXY) // This verb allows the AI to disable or enable the power override mode. /mob/living/silicon/ai/proc/ai_power_override() @@ -195,12 +195,15 @@ active_power_usage = AI_POWERUSAGE_NORMAL * AI_POWERUSAGE_OXYLOSS_TO_WATTS_MULTIPLIER use_power = POWER_USE_ACTIVE power_channel = EQUIP + invisibility = INVISIBILITY_ABSTRACT + is_spawnable_type = FALSE var/mob/living/silicon/ai/powered_ai = null - invisibility = 100 /obj/machinery/ai_powersupply/Initialize() . = ..() powered_ai = loc + if(!istype(powered_ai)) + return INITIALIZE_HINT_QDEL powered_ai.psupply = src /obj/machinery/ai_powersupply/Destroy() @@ -211,7 +214,7 @@ update_use_power(get_power_state()) /obj/machinery/ai_powersupply/proc/get_power_state() - // Dead, powered by APU, admin power, or inside an item (inteliCard/IIS). No power usage. + // Dead, powered by APU, admin power, or inside an item (intelliCard/IIS). No power usage. if(!powered_ai.stat == DEAD || powered_ai.admin_powered || istype(powered_ai.loc, /obj/item/)) return 0 // Normal power usage. diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm index 3e5851024a67..19fd42dcd784 100644 --- a/code/modules/mob/living/silicon/death.dm +++ b/code/modules/mob/living/silicon/death.dm @@ -1,12 +1,23 @@ -/mob/living/silicon/gib() - ..("gibbed-r") - gibs(loc, null, /obj/effect/gibspawner/robot) +/mob/living/silicon/get_death_message(gibbed) + return "gives one shrill beep before falling lifeless." -/mob/living/silicon/dust() - ..("dust-r", /obj/item/remains/robot) +/mob/living/silicon/get_self_death_message(gibbed) + return "You have suffered a critical system failure, and are dead." -/mob/living/silicon/death(gibbed, deathmessage, show_dead_message) - if(in_contents_of(/obj/machinery/recharge_station))//exit the recharge station +/mob/living/silicon/get_dusted_remains() + return /obj/item/remains/robot + +/mob/living/silicon/get_gibbed_state(dusted) + return dusted ? "dust-r" : "gibbed-r" + +/mob/living/silicon/gib(do_gibs = TRUE) + var/turf/my_turf = get_turf(src) + . = ..(do_gibs = FALSE) + if(. && my_turf) + spawn_gibber(my_turf) + +/mob/living/silicon/death(gibbed) + . = ..() + if(. && in_contents_of(/obj/machinery/recharge_station))//exit the recharge station var/obj/machinery/recharge_station/RC = loc - RC.go_out() - return ..(gibbed, deathmessage, show_dead_message) \ No newline at end of file + RC.go_out() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index 7f9958a8204f..0fb383db64be 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -5,14 +5,14 @@ /mob/living/silicon/Initialize() . = ..() if(!laws) - laws = GLOB.using_map.default_law_type + laws = global.using_map.default_law_type if(ispath(laws)) laws = new laws() laws_sanity_check() /mob/living/silicon/proc/laws_sanity_check() if (!src.laws) - laws = new GLOB.using_map.default_law_type + laws = new global.using_map.default_law_type /mob/living/silicon/proc/has_zeroth_law() return laws.zeroth_law != null @@ -68,15 +68,14 @@ /mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) var/prefix = "" if(MAIN_CHANNEL == lawchannel) - prefix = ";" - else if(lawchannel == "Binary") - prefix = "[get_language_prefix()]b" - else if((lawchannel in additional_law_channels)) - prefix = additional_law_channels[lawchannel] + prefix = get_common_radio_prefix() else - prefix = get_radio_key_from_channel(lawchannel) + if(lawchannel == "Binary" || lawchannel == "Drone") + prefix = "[get_language_prefix()]b" + else if((lawchannel in additional_law_channels)) + prefix = "[get_department_radio_prefix()][additional_law_channels[lawchannel]]" - dostatelaws(lawchannel, prefix, laws) + dostatelaws(lawchannel, (prefix || lawchannel), laws) /mob/living/silicon/proc/dostatelaws(var/method, var/prefix, var/datum/ai_laws/laws) if(stating_laws[prefix]) @@ -106,8 +105,9 @@ /mob/living/silicon/proc/law_channels() var/list/channels = new() channels += MAIN_CHANNEL - channels += silicon_radio.channels channels += additional_law_channels + for(var/datum/radio_channel/channel in silicon_radio?.get_available_channels()) + channels |= channel.key channels += "Binary" return channels @@ -117,4 +117,4 @@ /mob/living/silicon/proc/log_law(var/law_message) log_and_message_admins(law_message) - GLOB.lawchanges += "[stationtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]" + global.lawchanges += "[stationtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]" diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm index d3b32b990ef1..9f5a88f6cd1f 100644 --- a/code/modules/mob/living/silicon/login.dm +++ b/code/modules/mob/living/silicon/login.dm @@ -1,3 +1,3 @@ /mob/living/silicon/Login() - sleeping = 0 - ..() \ No newline at end of file + ..() + set_status_condition(STAT_ASLEEP, 0) diff --git a/code/modules/mob/living/silicon/pai/admin.dm b/code/modules/mob/living/silicon/pai/admin.dm index 07ff2b9895b6..4b528fad5647 100644 --- a/code/modules/mob/living/silicon/pai/admin.dm +++ b/code/modules/mob/living/silicon/pai/admin.dm @@ -7,7 +7,7 @@ return if(!pai_key) - var/client/C = input("Select client") as null|anything in GLOB.clients + var/client/C = input("Select client") as null|anything in global.clients if(!C) return pai_key = C.key diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm index b2f09c27afda..425e69b796e8 100644 --- a/code/modules/mob/living/silicon/pai/death.dm +++ b/code/modules/mob/living/silicon/pai/death.dm @@ -1,13 +1,14 @@ -/mob/living/silicon/pai/death(gibbed, deathmessage, show_dead_message) - if(card) - card.removePersonality() - if(gibbed) - dropInto(loc.loc) - qdel(card) - else - close_up() - if(mind) - qdel(mind) - ..(gibbed, deathmessage, "You have suffered a critical system failure, and are dead.") - ghostize() - qdel(src) \ No newline at end of file +/mob/living/silicon/pai/death(gibbed) + . = ..() + if(.) + if(card) + card.removePersonality() + if(gibbed) + dropInto(loc) + qdel(card) + else + fold() + if(mind) + qdel(mind) + ghostize() + qdel(src) diff --git a/code/modules/mob/living/silicon/pai/examine.dm b/code/modules/mob/living/silicon/pai/examine.dm index f6ca6e78053c..270afeef3012 100644 --- a/code/modules/mob/living/silicon/pai/examine.dm +++ b/code/modules/mob/living/silicon/pai/examine.dm @@ -1,19 +1,18 @@ -/mob/living/silicon/pai/examine(mob/user, distance) - . = ..(user, distance, infix = ", personal AI") - - var/msg = "" - switch(src.stat) +/mob/living/silicon/pai/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + infix = ", personal AI" + . = ..() + switch(stat) if(CONSCIOUS) - if(!src.client) msg += "\nIt appears to be in stand-by mode." //afk - if(UNCONSCIOUS) msg += "\nIt doesn't seem to be responding." - if(DEAD) msg += "\nIt looks completely unsalvageable." - msg += "\n*---------*" - - if(print_flavor_text()) msg += "\n[print_flavor_text()]\n" - + if(!src.client) + . += "It appears to be in stand-by mode." //afk + if(UNCONSCIOUS) + . += "It doesn't seem to be responding." + if(DEAD) + . += "It looks completely unsalvageable." + . += "*---------*" + if(print_flavor_text()) + . += "[print_flavor_text()]" if (pose) if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 ) pose = addtext(pose,".") //Makes sure all emotes end with a period. - msg += "\nIt is [pose]" - - to_chat(user, msg) + . += "It is [pose]" diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index 2a7e6aa6e0f4..60de69ab379c 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -1,37 +1,16 @@ -/mob/living/silicon/pai/Life() - - if (src.stat == 2) - return - - if(src.cable) - if(get_dist(src, src.cable) > 1) - var/turf/T = get_turf_or_move(src.loc) - for (var/mob/M in viewers(T)) - M.show_message("The data cable rapidly retracts back into its spool.", 3, "You hear a click and the sound of wire spooling rapidly.", 2) - qdel(src.cable) - src.cable = null - - handle_regular_hud_updates() - - if(src.secHUD == 1) - process_sec_hud(src, 1, network = get_computer_network()) - - if(src.medHUD == 1) - process_med_hud(src, 1, network = get_computer_network()) - - if(silence_time) - if(world.timeofday >= silence_time) - silence_time = null - to_chat(src, "Communication circuit reinitialized. Speech and messaging functionality restored.") - - handle_statuses() - - if(health <= 0) - death(null,"gives one shrill beep before falling lifeless.") - -/mob/living/silicon/pai/updatehealth() - if(status_flags & GODMODE) - health = 100 - set_stat(CONSCIOUS) - else - health = 100 - getBruteLoss() - getFireLoss() \ No newline at end of file +/mob/living/silicon/pai/handle_regular_hud_updates() + . = ..() + if(.) + if(src.secHUD == 1) + process_sec_hud(src, 1, network = get_computer_network()) + if(src.medHUD == 1) + process_med_hud(src, 1, network = get_computer_network()) + +/mob/living/silicon/pai/handle_regular_status_updates() + . = ..() + process_os() // better safe than sorry, in case some pAI has it + if(src.cable && get_dist(src, cable) > 1) + visible_message( \ + message = SPAN_NOTICE("The data cable rapidly retracts back into its spool."), \ + blind_message = SPAN_NOTICE("You hear a click and the sound of wire spooling rapidly.")) + QDEL_NULL(cable) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 432ea37de336..8a5bc7ae6728 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -1,56 +1,56 @@ +var/global/list/possible_chassis = list( + "Drone" = 'icons/mob/robots/pai/pai_drone.dmi', + "Cat" = 'icons/mob/robots/pai/pai_cat.dmi', + "Mouse" = 'icons/mob/robots/pai/pai_mouse.dmi', + "Monkey" = 'icons/mob/robots/pai/pai_monkey.dmi', + "Rabbit" = 'icons/mob/robots/pai/pai_rabbit.dmi', + "Mushroom" = 'icons/mob/robots/pai/pai_mushroom.dmi', + "Corgi" = 'icons/mob/robots/pai/pai_corgi.dmi', + "Crow" = 'icons/mob/robots/pai/pai_crow.dmi' +) + +var/global/list/possible_say_verbs = list( + "Robotic" = list("states","declares","queries"), + "Natural" = list("says","yells","asks"), + "Beep" = list("beeps","beeps loudly","boops"), + "Chirp" = list("chirps","chirrups","cheeps"), + "Feline" = list("purrs","yowls","meows"), + "Canine" = list("yaps", "barks", "woofs"), + "Corvid" = list("caws", "caws loudly", "whistles") +) + /mob/living/silicon/pai name = "pAI" - icon = 'icons/mob/pai.dmi' - icon_state = "repairbot" - + icon = 'icons/mob/robots/pai/pai_drone.dmi' + icon_state = ICON_STATE_WORLD + mob_sort_value = 3 + hud_used = /datum/hud/pai emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) pass_flags = PASS_FLAG_TABLE mob_size = MOB_SIZE_SMALL can_pull_size = ITEM_SIZE_SMALL can_pull_mobs = MOB_PULL_SMALLER - holder_type = /obj/item/holder idcard = /obj/item/card/id silicon_radio = null // pAIs get their radio from the card they belong to. + max_health = 100 - ntos_type = /datum/extension/interactive/ntos/silicon/small + os_type = /datum/extension/interactive/os/silicon/small starting_stock_parts = list( /obj/item/stock_parts/computer/processor_unit/small, /obj/item/stock_parts/computer/hard_drive/silicon, /obj/item/stock_parts/computer/network_card ) - var/network = "SS13" var/obj/machinery/camera/current = null var/ram = 100 // Used as currency to purchase different abilities var/list/software = list() - var/userDNA // The DNA string of our assigned user var/obj/item/paicard/card // The card we inhabit - var/chassis = "repairbot" // A record of your chosen chassis. - var/global/list/possible_chassis = list( - "Drone" = "repairbot", - "Cat" = "cat", - "Mouse" = "mouse", - "Monkey" = "monkey", - "Rabbit" = "rabbit", - "Mushroom" = "mushroom", - "Corgi" = "corgi", - "Crow" = "crow" - ) - - var/global/list/possible_say_verbs = list( - "Robotic" = list("states","declares","queries"), - "Natural" = list("says","yells","asks"), - "Beep" = list("beeps","beeps loudly","boops"), - "Chirp" = list("chirps","chirrups","cheeps"), - "Feline" = list("purrs","yowls","meows"), - "Canine" = list("yaps", "barks", "woofs"), - "Corvid" = list("caws", "caws loudly", "whistles") - ) - + var/is_in_card = TRUE + var/chassis var/obj/item/pai_cable/cable // The cable we produce and use when door or camera jacking var/master // Name of the one who commands us @@ -59,69 +59,70 @@ var/pai_law0 = "Serve your master." var/pai_laws // String for additional operating instructions our master might give us - var/silence_time // Timestamp when we were silenced (normally via EMP burst), set to null after silence has faded - // Various software-specific vars - var/temp // General error reporting text contained here will typically be shown once and cleared - var/screen // Which screen our main window displays - var/subscreen // Which specific function of the main screen is being displayed - var/secHUD = 0 // Toggles whether the Security HUD is active or not var/medHUD = 0 // Toggles whether the Medical HUD is active or not - var/medical_cannotfind = 0 - var/datum/data/record/medicalActive1 // Datacore record declarations for record software - var/datum/data/record/medicalActive2 - - var/security_cannotfind = 0 - var/datum/data/record/securityActive1 // Could probably just combine all these into one - var/datum/data/record/securityActive2 - var/obj/machinery/door/hackdoor // The airlock being hacked var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check var/hack_aborted = 0 var/translator_on = 0 // keeps track of the translator module + var/flashlight_power = 0.5 //brightness of light when on, must be no greater than 1. + var/flashlight_range = 3 //outer range of light when on, can be negative + var/light_on = FALSE + + light_wedge = 45 + /mob/living/silicon/pai/Initialize() + + chassis = global.possible_chassis[1] + status_flags |= NO_ANTAG - card = loc + if(!card) + if(istype(loc, /obj/item/paicard)) + card = loc + else + card = new /obj/item/paicard(src) + if(istype(card)) + if(!card.radio) + card.radio = new /obj/item/radio(card) + silicon_radio = card.radio + card.setPersonality(src) + else + return INITIALIZE_HINT_QDEL //As a human made device, we'll understand sol common without the need of the translator add_language(/decl/language/human/common, 1) - - verbs += /mob/living/silicon/pai/proc/choose_chassis - verbs += /mob/living/silicon/pai/proc/choose_verbs verbs -= /mob/living/verb/ghost . = ..() - if(card) - if(!card.radio) - card.radio = new /obj/item/radio(card) - silicon_radio = card.radio + software = default_pai_software.Copy() /mob/living/silicon/pai/Destroy() - card = null + if(card) + if(card.pai == src) + card.removePersonality() + card = null silicon_radio = null // Because this radio actually belongs to another instance we simply null . = ..() // this function shows the information about being silenced as a pAI in the Status panel /mob/living/silicon/pai/proc/show_silenced() - if(src.silence_time) - var/timeleft = round((silence_time - world.timeofday)/10 ,1) - stat(null, "Communications system reboot in -[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]") - + var/timeleft = round((HAS_STATUS(src, STAT_SILENCE) * SSmobs.wait) / 10, 1) + stat(null, "Communications system reboot in -[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]") /mob/living/silicon/pai/Stat() . = ..() statpanel("Status") - if (src.client.statpanel == "Status") + if (client.statpanel == "Status") show_silenced() /mob/living/silicon/pai/check_eye(var/mob/user) - if (!src.current) + if (!current) return -1 return 0 @@ -135,50 +136,31 @@ // 33% chance to change prime directive (based on severity) // 33% chance of no additional effect - src.silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes - to_chat(src, "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.") + SET_STATUS_MAX(src, STAT_SILENCE, 2 MINUTES) + to_chat(src, SPAN_DANGER("Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.")) if(prob(20)) - var/turf/T = get_turf_or_move(src.loc) - for (var/mob/M in viewers(T)) - M.show_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2) - return src.death(0) + visible_message( \ + message = SPAN_DANGER("A shower of sparks spray from [src]'s inner workings!"), \ + blind_message = SPAN_DANGER("You hear and smell the ozone hiss of electrical sparks being expelled violently.")) + return death() switch(pick(1,2,3)) if(1) - src.master = null - src.master_dna = null - to_chat(src, "You feel unbound.") + master = null + master_dna = null + to_chat(src, SPAN_GOOD("You feel unbound.")) if(2) var/command if(severity == 1) command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze") else command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze") - src.pai_law0 = "[command] your master." - to_chat(src, "Pr1m3 d1r3c71v3 uPd473D.") + pai_law0 = "[command] your master." + to_chat(src, SPAN_DANGER("Pr1m3 d1r3c71v3 uPd473D.")) if(3) - to_chat(src, "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.") - -/mob/living/silicon/pai/proc/switchCamera(var/obj/machinery/camera/C) - if (!C) - src.unset_machine() - src.reset_view(null) - return 0 - if (stat == 2 || !C.status || !(src.network in C.network)) return 0 - - // ok, we're alive, camera is good and in our network... - - src.set_machine(src) - src.current = C - src.reset_view(C) - return 1 + to_chat(src, SPAN_WARNING("You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.")) /mob/living/silicon/pai/cancel_camera() - set category = "pAI Commands" - set name = "Cancel Camera View" - src.reset_view(null) - src.unset_machine() - src.cameraFollow = null // Procs/code after this point is used to convert the stationary pai item into a // mobile pai mob. This also includes handling some of the general shit that can occur @@ -187,31 +169,30 @@ /mob/living/silicon/pai/verb/fold_out() set category = "pAI Commands" set name = "Unfold Chassis" + unfold() - if(stat || sleeping || paralysis || weakened) +//card -> mob +/mob/living/silicon/pai/proc/unfold() + if(incapacitated(INCAPACITATION_KNOCKOUT)) return - - if(src.loc != card) + if(loc != card) return - - if(world.time <= last_special) + if(is_on_special_ability_cooldown()) return - - last_special = world.time + 100 - + set_special_ability_cooldown(10 SECONDS) //I'm not sure how much of this is necessary, but I would rather avoid issues. - if(istype(card.loc,/obj/item/rig_module) || istype(card.loc,/obj/item/integrated_circuit/manipulation/ai/)) + if(isitem(card.loc) && !card.loc.storage) // this used to be a more specific check for ai holder parts but this should cover them still to_chat(src, "There is no room to unfold inside \the [card.loc]. You're good and stuck.") return 0 - else if(istype(card.loc,/mob)) + else if(ismob(card.loc)) var/mob/holder = card.loc if(ishuman(holder)) - var/mob/living/carbon/human/H = holder - for(var/obj/item/organ/external/affecting in H.organs) + var/mob/living/human/H = holder + for(var/obj/item/organ/external/affecting in H.get_external_organs()) if(card in affecting.implants) - affecting.take_external_damage(rand(30,50)) - affecting.implants -= card - H.visible_message("\The [src] explodes out of \the [H]'s [affecting.name] in a shower of gore!") + affecting.take_damage(rand(30,50)) + LAZYREMOVE(affecting.implants, card) + H.visible_message(SPAN_DANGER("\The [src] explodes out of \the [H]'s [affecting.name] in a shower of gore!")) break holder.drop_from_inventory(card) @@ -219,147 +200,114 @@ client.perspective = EYE_PERSPECTIVE client.eye = src dropInto(card.loc) - card.forceMove(src) card.screen_loc = null - + is_in_card = FALSE var/turf/T = get_turf(src) if(istype(T)) T.visible_message("[src] folds outwards, expanding into a mobile form.") /mob/living/silicon/pai/verb/fold_up() set category = "pAI Commands" set name = "Collapse Chassis" + fold() - if(stat || sleeping || paralysis || weakened) - return - - if(src.loc == card) - return +/mob/living/silicon/pai/get_available_postures() - if(world.time <= last_special) - return - - close_up() - -/mob/living/silicon/pai/proc/choose_chassis() - set category = "pAI Commands" - set name = "Choose Chassis" - - var/choice - var/finalized = "No" - while(finalized == "No" && src.client) - - choice = input(usr,"What would you like to use for your mobile chassis icon? This decision can only be made once.") as null|anything in possible_chassis - if(!choice) return - - icon_state = possible_chassis[choice] - finalized = alert("Look at your sprite. Is this what you wish to use?",,"No","Yes") - - chassis = possible_chassis[choice] - verbs -= /mob/living/silicon/pai/proc/choose_chassis - verbs += /mob/living/proc/hide - -/mob/living/silicon/pai/proc/choose_verbs() - set category = "pAI Commands" - set name = "Choose Speech Verbs" - - var/choice = input(usr,"What theme would you like to use for your speech verbs? This decision can only be made once.") as null|anything in possible_say_verbs - if(!choice) return - - var/list/sayverbs = possible_say_verbs[choice] - speak_statement = sayverbs[1] - speak_exclamation = sayverbs[(sayverbs.len>1 ? 2 : sayverbs.len)] - speak_query = sayverbs[(sayverbs.len>2 ? 3 : sayverbs.len)] + if(loc == card) + var/static/list/card_postures = list(/decl/posture/standing) + return card_postures - verbs -= /mob/living/silicon/pai/proc/choose_verbs + var/static/list/available_postures = list( + /decl/posture/standing, + /decl/posture/lying, + /decl/posture/lying/deliberate, + ) + return available_postures -/mob/living/silicon/pai/lay_down() - set name = "Rest" - set category = "IC" +//from mob -> card +/mob/living/silicon/pai/proc/fold() + if(incapacitated(INCAPACITATION_KNOCKOUT)) + return + if(loc == card) + return + if(is_on_special_ability_cooldown()) + return + set_special_ability_cooldown(10 SECONDS) + set_posture(/decl/posture/standing) + // If we are being held, handle removing our holder from their inv. + var/obj/item/holder/H = loc + if(istype(H)) + var/mob/living/M = H.loc + if(istype(M)) + M.drop_from_inventory(H, get_turf(src)) + dropInto(loc) + card.dropInto(card.loc) + forceMove(card) + if (src && client) + client.perspective = EYE_PERSPECTIVE + client.eye = card + is_in_card = TRUE + var/turf/T = get_turf(src) + if(istype(T)) + T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") +/mob/living/silicon/pai/lay_down(block_posture as null) // Pass lying down or getting up to our pet human, if we're in a rig. - if(istype(src.loc,/obj/item/paicard)) - resting = 0 + if(istype(loc, /obj/item/paicard)) + set_posture(/decl/posture/standing) var/obj/item/rig/rig = src.get_rig() - if(istype(rig)) + if(rig) rig.force_rest(src) + return + . = ..() + if(current_posture.prone) + to_chat(src, SPAN_NOTICE("You are now resting.")) else - resting = !resting - icon_state = resting ? "[chassis]_rest" : "[chassis]" - to_chat(src, "You are now [resting ? "resting" : "getting up"]") + to_chat(src, SPAN_NOTICE("You are now getting up.")) + update_icon() + +/mob/living/silicon/pai/on_update_icon() + . = ..() + icon_state = ICON_STATE_WORLD + if(stat == DEAD) + icon_state = "[icon_state]-dead" + else if(current_posture?.prone) + icon_state = "[icon_state]-rest" //Overriding this will stop a number of headaches down the track. -/mob/living/silicon/pai/attackby(obj/item/W, mob/user) - var/obj/item/card/id/card = W.GetIdCard() - if(card && user.a_intent == I_HELP) +/mob/living/silicon/pai/attackby(obj/item/used_item, mob/user) + var/obj/item/card/id/card = used_item.GetIdCard() + if(card && user.check_intent(I_FLAG_HELP)) var/list/new_access = card.GetAccess() - src.idcard.access = new_access - visible_message("[user] slides [W] across [src].") + idcard.access = new_access + visible_message("[user] slides [used_item] across [src].") to_chat(src, SPAN_NOTICE("Your access has been updated!")) return FALSE // don't continue processing click callstack. - if(try_stock_parts_install(W, user)) - return - if(try_stock_parts_removal(W, user)) - return - if(W.force) - visible_message("[user] attacks [src] with [W]!") - src.adjustBruteLoss(W.force) - src.updatehealth() + if(try_stock_parts_install(used_item, user)) + return TRUE + if(try_stock_parts_removal(used_item, user)) + return TRUE + var/force = used_item.expend_attack_force(user) + if(force) + visible_message(SPAN_DANGER("[user] attacks [src] with [used_item]!")) + take_damage(force) else - visible_message("[user] bonks [src] harmlessly with [W].") - spawn(1) - if(stat != 2) close_up() - return - -/mob/living/silicon/pai/attack_hand(mob/user) - visible_message("[user] boops [src] on the head.") - close_up() - -//I'm not sure how much of this is necessary, but I would rather avoid issues. -/mob/living/silicon/pai/proc/close_up() - - last_special = world.time + 100 + visible_message(SPAN_WARNING("[user] bonks [src] harmlessly with [used_item].")) - if(loc == card) - return - - var/turf/T = get_turf(src) - if(istype(T)) T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") - - if(client) - client.perspective = EYE_PERSPECTIVE - client.eye = card - - //stop resting - resting = 0 - - // If we are being held, handle removing our holder from their inv. - var/obj/item/holder/H = loc - if(istype(H)) - var/mob/living/M = H.loc - if(istype(M)) - M.drop_from_inventory(H, get_turf(src)) - H.dropInto(get_turf(M)) + spawn(1) + if(stat != DEAD) fold() + return TRUE - // Move us into the card and move the card to the ground. - card.dropInto(get_turf(card)) - resting = 0 - icon_state = "[chassis]" - forceMove(card) +/mob/living/silicon/pai/default_interaction(mob/user) + . = ..() + if(!.) + visible_message(SPAN_NOTICE("\The [user] boops \the [src] on the head.")) + fold() + return TRUE // No binary for pAIs. /mob/living/silicon/pai/binarycheck() - return 0 - -// Handle being picked up. -/mob/living/silicon/pai/get_scooped(var/mob/living/carbon/grabber, var/self_drop) - . = ..() - if(.) - var/obj/item/holder/H = . - if(istype(H)) - H.icon_state = "pai-[icon_state]" - grabber.update_inv_l_hand() - grabber.update_inv_r_hand() + return FALSE /mob/living/silicon/pai/verb/wipe_software() set name = "Wipe Software" @@ -371,8 +319,20 @@ "Wipe Software", "No", "No", "Yes") != "Yes") return - close_up() + fold() visible_message("[src] fades away from the screen, the pAI device goes silent.") card.removePersonality() clear_client() +/mob/living/silicon/pai/proc/toggle_integrated_light() + if(!light_on) + set_light(flashlight_range, flashlight_power, angle = light_wedge) + to_chat(src, SPAN_NOTICE("You enable your integrated light.")) + light_on = TRUE + else + set_light(0, 0) + to_chat(src, SPAN_NOTICE("You disable your integrated light.")) + light_on = FALSE + +/mob/living/silicon/pai/get_admin_job_string() + return "pAI" diff --git a/code/modules/mob/living/silicon/pai/paiwire.dm b/code/modules/mob/living/silicon/pai/paiwire.dm index 19b6ea05d5ba..0e1f737e6011 100644 --- a/code/modules/mob/living/silicon/pai/paiwire.dm +++ b/code/modules/mob/living/silicon/pai/paiwire.dm @@ -3,12 +3,13 @@ name = "data cable" icon = 'icons/obj/power.dmi' icon_state = "wire1" - + material = /decl/material/solid/metal/copper + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) var/obj/machinery/machine /obj/item/pai_cable/proc/plugin(obj/machinery/M, mob/user) if(istype(M, /obj/machinery/door) || istype(M, /obj/machinery/camera)) - if(!user.unEquip(src, M)) + if(!user.try_unequip(src, M)) return user.visible_message("[user] inserts [src] into a data port on [M].", "You insert [src] into a data port on [M].", "You hear the satisfying click of a wire jack fastening into place.") machine = M diff --git a/code/modules/mob/living/silicon/pai/personality.dm b/code/modules/mob/living/silicon/pai/personality.dm index a718b5b1ab65..d66de3bb9d6e 100644 --- a/code/modules/mob/living/silicon/pai/personality.dm +++ b/code/modules/mob/living/silicon/pai/personality.dm @@ -4,6 +4,8 @@ description role comments + chassis + say_verb ready = 0 */ @@ -16,13 +18,13 @@ var/savefile/F = new /savefile(src.savefile_path(user)) - - F["name"] << src.name - F["description"] << src.description - F["role"] << src.role - F["comments"] << src.comments - - F["version"] << 1 + to_file(F["name"], src.name) + to_file(F["description"], src.description) + to_file(F["role"], src.role) + to_file(F["comments"], src.comments) + to_file(F["chassis"], src.chassis) + to_file(F["say_verb"], src.say_verb) + to_file(F["version"], 1) return 1 @@ -45,7 +47,7 @@ if(!F) return //Not everyone has a pai savefile. var/version = null - F["version"] >> version + from_file(F["version"], version) if (isnull(version) || version != 1) fdel(path) @@ -53,8 +55,10 @@ alert(user, "Your savefile was incompatible with this version and was deleted.") return 0 - F["name"] >> src.name - F["description"] >> src.description - F["role"] >> src.role - F["comments"] >> src.comments + from_file(F["name"], src.name) + from_file(F["description"], src.description) + from_file(F["role"], src.role) + from_file(F["comments"], src.comments) + from_file(F["chassis"], src.chassis) + from_file(F["say_verb"], src.say_verb) return 1 diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 8964425ab7bc..0d02001ceae5 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -2,8 +2,6 @@ // Recruiting observers to play as pAIs -var/datum/paiController/paiController // Global handler for pAI candidates - /datum/paiCandidate var/name var/key @@ -11,12 +9,10 @@ var/datum/paiController/paiController // Global handler for pAI candidates var/role var/comments var/ready = 0 + var/chassis = "Drone" + var/say_verb = "Robotic" - -/hook/startup/proc/paiControllerSetup() - paiController = new /datum/paiController() - return 1 - +var/global/datum/paiController/paiController = new /datum/paiController() // Global handler for pAI candidates /datum/paiController var/inquirer = null @@ -25,6 +21,10 @@ var/datum/paiController/paiController // Global handler for pAI candidates var/askDelay = 10 * 60 * 1 // One minute [ms * sec * min] +/datum/paiController/New() + ..() + populate_pai_software_list() + /datum/paiController/Topic(href, href_list[]) if(href_list["download"]) var/datum/paiCandidate/candidate = locate(href_list["candidate"]) @@ -34,11 +34,17 @@ var/datum/paiController/paiController // Global handler for pAI candidates if(istype(card,/obj/item/paicard) && istype(candidate,/datum/paiCandidate)) var/mob/living/silicon/pai/pai = new(card) if(!candidate.name) - pai.SetName(pick(GLOB.ninja_names)) + pai.SetName(pick(global.ai_names)) else pai.SetName(candidate.name) pai.real_name = pai.name pai.key = candidate.key + pai.chassis = candidate.chassis + pai.icon = global.possible_chassis[candidate.chassis] + var/list/sayverbs = global.possible_say_verbs[candidate.say_verb] + pai.speak_statement = sayverbs[1] + pai.speak_exclamation = sayverbs[(sayverbs.len>1 ? 2 : sayverbs.len)] + pai.speak_query = sayverbs[(sayverbs.len>2 ? 3 : sayverbs.len)] card.setPersonality(pai) card.looking_for_personality = 0 @@ -57,7 +63,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates switch(option) if("name") - t = sanitizeSafe(input("Enter a name for your pAI", "pAI Name", candidate.name) as text, MAX_NAME_LEN) + t = sanitize_safe(input("Enter a name for your pAI", "pAI Name", candidate.name) as text, MAX_NAME_LEN) if(t) candidate.name = t if("desc") @@ -72,24 +78,36 @@ var/datum/paiController/paiController // Global handler for pAI candidates t = input("Enter any OOC comments", "pAI OOC Comments", candidate.comments) as message if(t) candidate.comments = sanitize(t) + if("chassis") + t = input(usr,"What would you like to use for your mobile chassis icon?") as null|anything in global.possible_chassis + if(t) + candidate.chassis = t + if("say") + t = input(usr,"What theme would you like to use for your speech verbs?") as null|anything in global.possible_say_verbs + if(t) + candidate.say_verb = t if("save") candidate.savefile_save(usr) if("load") candidate.savefile_load(usr) //In case people have saved unsanitized stuff. if(candidate.name) - candidate.name = sanitizeSafe(candidate.name, MAX_NAME_LEN) + candidate.name = sanitize_safe(candidate.name, MAX_NAME_LEN) if(candidate.description) candidate.description = sanitize(candidate.description) if(candidate.role) candidate.role = sanitize(candidate.role) if(candidate.comments) candidate.comments = sanitize(candidate.comments) + if(!candidate.chassis) //default to drone + candidate.chassis = "Drone" + if(!candidate.say_verb)//default to Robotic + candidate.say_verb = "Robotic" if("submit") if(candidate) candidate.ready = 1 - for(var/obj/item/paicard/p in world) + for(var/obj/item/paicard/p in global.pai_cards) if(p.looking_for_personality == 1) p.alertUpdate() close_browser(usr, "window=paiRecruit") @@ -118,7 +136,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates color:white; font-size:13px; background-image:url('uiBackground.png'); - background-repeat:repeat-x; + background-repeat:repeat; background-color:#272727; background-position:center top; } @@ -202,6 +220,17 @@ var/datum/paiController/paiController // Global handler for pAI candidates Anything you'd like to address specifically to the player reading this in an OOC manner. \"I prefer more serious RP.\", \"I'm still learning the interface!\", etc. Feel free to leave this blank if you want. + + Chassis Type: + [candidate.chassis]  + + + Open up the Character Setup in the OOC tab to view the different models! + + + Say Verb: + [candidate.say_verb]  +
    @@ -227,7 +256,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates "} - show_browser(M, dat, "window=paiRecruit;size=580x580;") + show_browser(M, dat, "window=paiRecruit;size=580x620;") /datum/paiController/proc/findPAI(var/obj/item/paicard/p, var/mob/user) requestRecruits(user) @@ -235,7 +264,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates for(var/datum/paiCandidate/c in paiController.pai_candidates) if(c.ready) var/found = 0 - for(var/mob/observer/ghost/o in GLOB.player_list) + for(var/mob/observer/ghost/o in global.player_list) if(o.key == c.key && o.MayRespawn()) found = 1 if(found) @@ -253,7 +282,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates color:white; font-size:13px; background-image:url('uiBackground.png'); - background-repeat:repeat-x; + background-repeat:repeat; background-color:#272727; background-position:center top; } @@ -348,7 +377,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates /datum/paiController/proc/requestRecruits(var/mob/user) inquirer = user - for(var/mob/observer/ghost/O in GLOB.player_list) + for(var/mob/observer/ghost/O in global.player_list) if(!O.MayRespawn()) continue if(jobban_isbanned(O, "pAI")) diff --git a/code/modules/mob/living/silicon/pai/say.dm b/code/modules/mob/living/silicon/pai/say.dm index ffbfbc7b04b0..732261c052d2 100644 --- a/code/modules/mob/living/silicon/pai/say.dm +++ b/code/modules/mob/living/silicon/pai/say.dm @@ -1,5 +1,5 @@ /mob/living/silicon/pai/say(var/msg) - if(silence_time) - to_chat(src, "Communication circuits remain uninitialized.") - else - ..(msg) \ No newline at end of file + if(HAS_STATUS(src, STAT_SILENCE)) + to_chat(src, SPAN_WARNING("Communication circuits are disabled.")) + return + return ..(msg) diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index fc4e2708dbb8..058e882d06b5 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -1,4 +1,4 @@ -var/list/pai_emotions = list( +var/global/list/pai_emotions = list( "Happy" = 1, "Cat" = 2, "Extremely Happy" = 3, @@ -19,41 +19,34 @@ var/list/pai_emotions = list( var/global/list/pai_software_by_key = list() var/global/list/default_pai_software = list() -/hook/startup/proc/populate_pai_software_list() - var/r = 1 // I would use ., but it'd sacrifice runtime detection - for(var/type in typesof(/datum/pai_software) - /datum/pai_software) +/proc/populate_pai_software_list() + pai_software_by_key = list() + default_pai_software = list() + for(var/type in subtypesof(/datum/pai_software)) var/datum/pai_software/P = new type() if(pai_software_by_key[P.id]) var/datum/pai_software/O = pai_software_by_key[P.id] - log_error("pAI software module [P.name] has the same key as [O.name]!") - r = 0 + PRINT_STACK_TRACE("pAI software module [type] has the same key ([P.id]) as [O.type] [O.id]!") continue pai_software_by_key[P.id] = P if(P.default) default_pai_software[P.id] = P - return r - -/mob/living/silicon/pai/Initialize() - . = ..() - software = default_pai_software.Copy() - -/mob/living/silicon/pai/verb/paiInterface() - set category = "pAI Commands" - set name = "Software Interface" +/mob/living/silicon/pai/proc/paiInterface() ui_interact(src) /mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) - if(user != src) - if(ui) ui.set_status(STATUS_CLOSE, 0) + + if(user != src || !istype(card)) + ui?.set_nano_status(STATUS_CLOSE, 0) return if(ui_key != "main") var/datum/pai_software/S = software[ui_key] if(S && !S.toggle) S.on_ui_interact(src, ui, force_open) - else - if(ui) ui.set_status(STATUS_CLOSE, 0) + else if(ui) + ui.set_nano_status(STATUS_CLOSE, 0) return var/data[0] diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index 3f91e6b86f85..b113096f13be 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -12,17 +12,17 @@ // Whether pAIs should automatically receive this module at no cost var/default = 0 - proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - return +/datum/pai_software/proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + return - proc/toggle(mob/living/silicon/pai/user) - return +/datum/pai_software/proc/toggle(mob/living/silicon/pai/user) + return - proc/is_active(mob/living/silicon/pai/user) - return 0 +/datum/pai_software/proc/is_active(mob/living/silicon/pai/user) + return 0 - proc/on_purchase(mob/living/silicon/pai/user) - return +/datum/pai_software/proc/on_purchase(mob/living/silicon/pai/user) + return /datum/pai_software/directives name = "Directives" @@ -31,54 +31,56 @@ toggle = 0 default = 1 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["master"] = user.master - data["dna"] = user.master_dna - data["prime"] = user.pai_law0 - data["supplemental"] = user.pai_laws - - ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(href_list["getdna"]) - var/mob/living/M = P.loc - var/count = 0 - - // Find the carrier - while(!istype(M, /mob/living)) - if(!M || !M.loc || count > 6) - //For a runtime where M ends up in nullspace - to_chat(src, "You are not being carried by anyone!") - return 0 - M = M.loc - count++ - - // Check the carrier - var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") - if(answer == "Yes") - var/turf/T = get_turf_or_move(P.loc) - for (var/mob/v in viewers(T)) - v.show_message("[M] presses \his thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) - var/datum/dna/dna = M.dna - to_chat(P, "

    [M]'s UE string : [dna.unique_enzymes]

    ") - if(dna.unique_enzymes == P.master_dna) +/datum/pai_software/directives/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["master"] = user.master + data["dna"] = user.master_dna + data["prime"] = user.pai_law0 + data["supplemental"] = user.pai_laws + + ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/directives/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["getdna"]) + var/mob/living/M = P.loc + var/count = 0 + + // Find the carrier + while(!isliving(M)) + if(!M || !M.loc || count > 6) + //For a runtime where M ends up in nullspace + to_chat(src, "You are not being carried by anyone!") + return 0 + M = M.loc + count++ + + // Check the carrier + var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") + var/decl/pronouns/pronouns = M.get_pronouns() + if(answer == "Yes") + if(!QDELETED(P) && (P.loc == M)) + P.visible_message( \ + message = SPAN_NOTICE("\The [M] presses [pronouns.his] thumb against \the [P]."), \ + blind_message = SPAN_NOTICE("\The [P] makes a sharp clicking sound as it extracts DNA material from \the [M].")) + var/unique_enzymes = M.get_unique_enzymes() + to_chat(P, SPAN_NOTICE("

    [M]'s UE string : [unique_enzymes || "NULL"]

    ")) + if(unique_enzymes == P.master_dna) to_chat(P, "DNA is a match to stored Master DNA.") else to_chat(P, "DNA does not match stored Master DNA.") - else - to_chat(P, "[M] does not seem like \he is going to provide a DNA sample willingly.") - return 1 + else + to_chat(P, SPAN_WARNING("\The [M] does not seem like [pronouns.he] is going to provide a DNA sample willingly.")) + return 1 /datum/pai_software/radio_config name = "Radio Configuration" @@ -87,35 +89,32 @@ toggle = 0 default = 1 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) - var/data[0] - - data["listening"] = user.silicon_radio.broadcasting - data["frequency"] = format_frequency(user.silicon_radio.frequency) - - var/channels[0] - for(var/ch_name in user.silicon_radio.channels) - var/ch_stat = user.silicon_radio.channels[ch_name] - var/ch_dat[0] - ch_dat["name"] = ch_name - // FREQ_LISTENING is const in /obj/item/radio - ch_dat["listening"] = !!(ch_stat & user.silicon_radio.FREQ_LISTENING) - channels[++channels.len] = ch_dat - - data["channels"] = channels - - ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) - ui.set_initial_data(data) - ui.open() - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - P.silicon_radio.Topic(href, href_list) - return 1 +/datum/pai_software/radio_config/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) + var/data[0] + + data["listening"] = user.silicon_radio.broadcasting + data["frequency"] = format_frequency(user.silicon_radio.frequency) + var/channels[0] + var/list/pai_channels = user.silicon_radio.get_available_channels() + for(var/datum/radio_channel/channel in pai_channels) + var/ch_dat[0] + ch_dat["name"] = channel.name || format_frequency(channel.frequency) + ch_dat["listening"] = (LAZYACCESS(user.silicon_radio.channels, channel) == TRUE) + channels[++channels.len] = ch_dat + data["channels"] = channels + + ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) + ui.set_initial_data(data) + ui.open() + +/datum/pai_software/radio_config/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + P.silicon_radio.Topic(href, href_list) + return 1 /datum/pai_software/crew_manifest name = "Crew Manifest" @@ -123,18 +122,18 @@ id = "manifest" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - // This is dumb, but NanoUI breaks if it has no data to send - data["crew_manifest"] = html_crew_manifest() +/datum/pai_software/crew_manifest/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + // This is dumb, but NanoUI breaks if it has no data to send + data["crew_manifest"] = html_crew_manifest() - ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) /datum/pai_software/door_jack name = "Door Jack" @@ -142,52 +141,51 @@ id = "door_jack" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["cable"] = user.cable != null - data["machine"] = user.cable && (user.cable.machine != null) - data["inprogress"] = user.hackdoor != null - data["progress_a"] = round(user.hackprogress / 10) - data["progress_b"] = user.hackprogress % 10 - data["aborted"] = user.hack_aborted - - ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(href_list["jack"]) - if(P.cable && P.cable.machine) - P.hackdoor = P.cable.machine - P.hackloop() - return 1 - else if(href_list["cancel"]) - P.hackdoor = null - return 1 - else if(href_list["cable"]) - var/turf/T = get_turf_or_move(P.loc) - P.hack_aborted = 0 - P.cable = new /obj/item/pai_cable(T) - for(var/mob/M in viewers(T)) - M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, - "You hear the soft click of something light and hard falling to the ground.", 2) - return 1 +/datum/pai_software/door_jack/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + data["cable"] = user.cable != null + data["machine"] = user.cable && (user.cable.machine != null) + data["inprogress"] = user.hackdoor != null + data["progress_a"] = round(user.hackprogress / 10) + data["progress_b"] = user.hackprogress % 10 + data["aborted"] = user.hack_aborted + + ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/pai_software/door_jack/Topic(href, href_list) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) return + + if(href_list["jack"]) + if(P.cable && P.cable.machine) + P.hackdoor = P.cable.machine + P.hackloop() + return 1 + else if(href_list["cancel"]) + P.hackdoor = null + return 1 + else if(href_list["cable"]) + P.hack_aborted = 0 + P.cable = new /obj/item/pai_cable(get_turf(P)) + P.visible_message( \ + message = SPAN_NOTICE("A port on [P] opens to reveal [P.cable], which promptly falls to the floor."), \ + blind_message = SPAN_NOTICE("You hear the soft click of something light and hard falling to the ground.")) + return 1 /mob/living/silicon/pai/proc/hackloop() - var/turf/T = get_turf_or_move(src.loc) - for(var/mob/living/silicon/ai/AI in GLOB.player_list) + var/turf/T = get_turf(src) + for(var/mob/living/silicon/ai/AI in global.player_list) if(T.loc) - to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") + to_chat(AI, SPAN_DANGER("Network Alert: Brute-force encryption crack in progress in [T.loc].")) else - to_chat(AI, "Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.") + to_chat(AI, SPAN_DANGER("Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.")) var/obj/machinery/door/D = cable.machine if(!istype(D)) hack_aborted = 1 @@ -216,62 +214,62 @@ id = "atmos_sense" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - var/turf/T = get_turf_or_move(user.loc) - if(!T) - data["reading"] = 0 - data["pressure"] = 0 - data["temperature"] = 0 - data["temperatureC"] = 0 - data["gas"] = list() - else - var/datum/gas_mixture/env = T.return_air() - data["reading"] = 1 - var/pres = env.return_pressure() * 10 - data["pressure"] = "[round(pres/10)].[pres%10]" - data["temperature"] = round(env.temperature) - data["temperatureC"] = round(env.temperature-T0C) - - var/t_moles = env.total_moles - var/gases[0] - for(var/g in env.gas) - var/gas[0] - var/decl/material/mat = decls_repository.get_decl(g) - gas["name"] = capitalize(mat.gas_name) - gas["percent"] = round((env.gas[g] / t_moles) * 100) - gases[++gases.len] = gas - data["gas"] = gases - - ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) - ui.set_initial_data(data) - ui.open() +/datum/pai_software/atmosphere_sensor/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) + var/data[0] + + var/turf/T = get_turf(user) + if(!T) + data["reading"] = 0 + data["pressure"] = 0 + data["temperature"] = 0 + data["temperatureC"] = 0 + data["gas"] = list() + else + var/datum/gas_mixture/env = T.return_air() + data["reading"] = 1 + var/pres = env.return_pressure() * 10 + data["pressure"] = "[round(pres/10)].[pres%10]" + data["temperature"] = round(env.temperature) + data["temperatureC"] = round(env.temperature-T0C) + + var/t_moles = env.total_moles + var/gases[0] + for(var/g in env.gas) + var/gas[0] + var/decl/material/mat = GET_DECL(g) + gas["name"] = capitalize(mat.gas_name) + gas["percent"] = round((env.gas[g] / t_moles) * 100) + gases[++gases.len] = gas + data["gas"] = gases + + ui = SSnano.try_update_ui(user, user, id, ui, data, force_open) + if(!ui) + // Don't copy-paste this unless you're making a pAI software module! + ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) + ui.set_initial_data(data) + ui.open() /datum/pai_software/sec_hud name = "Security HUD" ram_cost = 20 id = "sec_hud" - toggle(mob/living/silicon/pai/user) - user.secHUD = !user.secHUD +/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user) + user.secHUD = !user.secHUD - is_active(mob/living/silicon/pai/user) - return user.secHUD +/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user) + return user.secHUD /datum/pai_software/med_hud name = "Medical HUD" ram_cost = 20 id = "med_hud" - toggle(mob/living/silicon/pai/user) - user.medHUD = !user.medHUD +/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user) + user.medHUD = !user.medHUD - is_active(mob/living/silicon/pai/user) - return user.medHUD +/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user) + return user.medHUD /datum/pai_software/translator name = "Universal Translator" @@ -279,15 +277,15 @@ id = "translator" var/list/languages = list(/decl/language/human/common) - toggle(mob/living/silicon/pai/user) - // Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages - user.translator_on = !user.translator_on - if(user.translator_on) - for(var/language in languages) - user.add_language(language) - else - for(var/language in languages) - user.remove_language(language) - - is_active(mob/living/silicon/pai/user) - return user.translator_on \ No newline at end of file +/datum/pai_software/translator/toggle(mob/living/silicon/pai/user) + // Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages + user.translator_on = !user.translator_on + if(user.translator_on) + for(var/language in languages) + user.add_language(language) + else + for(var/language in languages) + user.remove_language(language) + +/datum/pai_software/translator/is_active(mob/living/silicon/pai/user) + return user.translator_on \ No newline at end of file diff --git a/code/modules/mob/living/silicon/posi_brainmob.dm b/code/modules/mob/living/silicon/posi_brainmob.dm deleted file mode 100644 index 8f2d0a3b9fb7..000000000000 --- a/code/modules/mob/living/silicon/posi_brainmob.dm +++ /dev/null @@ -1,104 +0,0 @@ -/mob/living/silicon/sil_brainmob - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 - - use_me = 0 //Can't use the me verb, it's a freaking immobile brain - icon = 'icons/obj/surgery.dmi' - icon_state = "brain-prosthetic" - silicon_subsystems = list( - /datum/nano_module/law_manager - ) - - var/obj/item/organ/internal/posibrain/container = null - var/emp_damage = 0//Handles a type of MMI damage - var/alert = null - var/list/owner_channels = list() - var/list/law_channels = list() - -/mob/living/silicon/sil_brainmob/Initialize() - . = ..() - reagents = new/datum/reagents(1000, src) - if(istype(loc, /obj/item/organ/internal/posibrain)) - container = loc - add_language(/decl/language/binary) - -/mob/living/silicon/sil_brainmob/Destroy() - if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. - if(stat!=DEAD) //If not dead. - death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA - ghostize() //Ghostize checks for key so nothing else is necessary. - return ..() - -/mob/living/silicon/sil_brainmob/UpdateLyingBuckledAndVerbStatus() - if(container && istype(container, /obj/item/organ/internal/posibrain) && istype(container.loc, /turf)) - use_me = 1 - -/mob/living/silicon/sil_brainmob/isSynthetic() - return 1 - -/mob/living/silicon/sil_brainmob/binarycheck() - return isSynthetic() - -/mob/living/silicon/sil_brainmob/check_has_mouth() - return 0 - -/mob/living/silicon/sil_brainmob/show_laws(mob/M) - if(M) - to_chat(M, "Obey these laws [M]:") - src.laws_sanity_check() - src.laws.show_laws(M) - -/mob/living/silicon/sil_brainmob/open_subsystem(var/subsystem_type, var/mob/given = src) - update_owner_channels() - return ..(subsystem_type, given) - -/mob/living/silicon/sil_brainmob/proc/update_owner_channels() - var/mob/living/carbon/human/owner = container.owner - if(!owner) return - - owner_channels.Cut() - - var/obj/item/radio/headset/R - if(owner.l_ear && istype(owner.l_ear,/obj/item/radio)) - R = owner.l_ear - else if(owner.r_ear && istype(owner.r_ear,/obj/item/radio)) - R = owner.r_ear - - if(!R) return 0 - - var/list/new_channels = list() - new_channels["Common"] = ";" - for(var/i = 1 to R.channels.len) - var/channel = R.channels[i] - var/key = get_radio_key_from_channel(channel) - new_channels[channel] = key - owner_channels = new_channels - return 1 - -/mob/living/silicon/sil_brainmob/statelaw(var/law, var/mob/living/L = src) - if(container && container.owner) - L = container.owner - return ..(law, L) - -/mob/living/silicon/sil_brainmob/proc/update_law_channels() - update_owner_channels() - law_channels.Cut() - law_channels |= additional_law_channels - law_channels |= owner_channels - return law_channels - -/mob/living/silicon/sil_brainmob/law_channels() - return law_channels - -/mob/living/silicon/sil_brainmob/statelaws(var/datum/ai_laws/laws) - update_law_channels() - if(isnull(law_channels[lawchannel])) - to_chat(src, "[lawchannel]: Unable to state laws. Communication method unavailable.") - return 0 - - dostatelaws(lawchannel, law_channels[lawchannel], laws) diff --git a/code/modules/mob/living/silicon/robot/analyzer.dm b/code/modules/mob/living/silicon/robot/analyzer.dm index 505ebab12945..1434763bfa9b 100644 --- a/code/modules/mob/living/silicon/robot/analyzer.dm +++ b/code/modules/mob/living/silicon/robot/analyzer.dm @@ -3,55 +3,53 @@ // /obj/item/robotanalyzer name = "robot analyzer" - icon = 'icons/obj/items/device/robot_analyzer.dmi' - icon_state = "robotanalyzer" - item_state = "analyzer" desc = "A hand-held scanner able to diagnose robotic injuries." + icon = 'icons/obj/items/device/robot_analyzer.dmi' + icon_state = ICON_STATE_WORLD obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - throwforce = 3 + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL throw_speed = 5 throw_range = 10 - origin_tech = "{'magnets':2,'biotech':1,'engineering':2}" + origin_tech = @'{"magnets":2,"biotech":1,"engineering":2}' material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) - var/mode = 1; -/obj/item/robotanalyzer/attack(mob/living/M, mob/living/user) - if((MUTATION_CLUMSY in user.mutations) && prob(50)) - to_chat(user, text("You try to analyze the floor's vitals!")) - for(var/mob/O in viewers(M, null)) - O.show_message(text("[user] has analyzed the floor's vitals!"), 1) - user.show_message(text("Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\t Damage Specifics: [0]-[0]-[0]-[0]"), 1) - user.show_message("Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("Body Temperature: ???", 1) - return +/obj/item/robotanalyzer/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + user.visible_message( + SPAN_WARNING("\The [user] has analyzed the floor's vitals!"), + self_message = SPAN_WARNING("You try to analyze the floor's vitals!")) + user.show_message(SPAN_NOTICE("Analyzing Results for The floor:\n\t Overall Status: Healthy")) + user.show_message(SPAN_NOTICE("\t Damage Specifics: [0]-[0]-[0]-[0]")) + user.show_message(SPAN_NOTICE("Key: Suffocation/Toxin/Burns/Brute")) + user.show_message(SPAN_NOTICE("Body Temperature: ???")) + return TRUE var/scan_type - if(istype(M, /mob/living/silicon/robot)) + if(isrobot(target)) scan_type = "robot" - else if(istype(M, /mob/living/carbon/human)) + else if(ishuman(target)) scan_type = "prosthetics" else to_chat(user, "You can't analyze non-robotic things!") - return + return TRUE - user.visible_message("\The [user] has analyzed [M]'s components.","You have analyzed [M]'s components.") + user.visible_message("\The [user] has analyzed [target]'s components.","You have analyzed [target]'s components.") switch(scan_type) if("robot") - var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() - var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() - user.show_message("Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.getHalLoss()]% functional"]") + var/BU = target.get_damage(BURN) > 50 ? "[target.get_damage(BURN)]" : target.get_damage(BURN) + var/BR = target.get_damage(BRUTE) > 50 ? "[target.get_damage(BRUTE)]" : target.get_damage(BRUTE) + user.show_message("Analyzing Results for [target]:\n\t Overall Status: [target.stat > 1 ? "fully disabled" : "[target.current_health - target.get_damage(PAIN)]% functional"]") user.show_message("\t Key: Electronics/Brute", 1) user.show_message("\t Damage Specifics: [BU] - [BR]") - if(M.stat == DEAD) - user.show_message("Time of Failure: [time2text(worldtime2stationtime(M.timeofdeath))]") - var/mob/living/silicon/robot/H = M + if(target.stat == DEAD) + user.show_message("Time of Failure: [time2text(worldtime2stationtime(target.timeofdeath))]") + var/mob/living/silicon/robot/H = target var/list/damaged = H.get_damaged_components(1,1,1) user.show_message("Localized Damage:",1) if(length(damaged)>0) @@ -59,7 +57,7 @@ user.show_message(text("\t []: [][] - [] - [] - []", \ capitalize(org.name), \ (org.installed == -1) ? "DESTROYED " :"",\ - (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ + (org.burn_damage > 0) ? "[org.burn_damage]" :0, \ (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ (org.toggled) ? "Toggled ON" : "Toggled OFF",\ (org.powered) ? "Power ON" : "Power OFF"),1) @@ -67,37 +65,37 @@ user.show_message("\t Components are OK.",1) if(H.emagged && prob(5)) user.show_message("\t ERROR: INTERNAL SYSTEMS COMPROMISED",1) - user.show_message("Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + user.show_message("Operating Temperature: [target.bodytemperature-T0C]°C ([target.bodytemperature*1.8-459.67]°F)", 1) if("prosthetics") - var/mob/living/carbon/human/H = M - to_chat(user, "Analyzing Results for \the [H]:") - to_chat(user, "Key: Electronics/Brute") - var/obj/item/organ/internal/cell/C = H.internal_organs_by_name[BP_CELL] + var/mob/living/human/H = target + to_chat(user, SPAN_NOTICE("Analyzing Results for \the [H]:")) + to_chat(user, "Key: [SPAN_ORANGE("Electronics")]/[SPAN_RED("Brute")]") + var/obj/item/organ/internal/cell/C = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) if(C) to_chat(user, SPAN_NOTICE("Cell charge: [C.percent()] %")) else to_chat(user, SPAN_NOTICE("Cell charge: ERROR - Cell not present")) - to_chat(user, "External prosthetics:") + to_chat(user, SPAN_NOTICE("External prosthetics:")) var/organ_found - for(var/obj/item/organ/external/E in H.organs) + for(var/obj/item/organ/external/E in H.get_external_organs()) if(!BP_IS_PROSTHETIC(E)) continue organ_found = 1 - to_chat(user, "[E.name]: [E.brute_dam][E.burn_dam]") + to_chat(user, "[E.name]: [SPAN_RED(E.brute_dam)] [SPAN_ORANGE(E.burn_dam)]") if(!organ_found) to_chat(user, "No prosthetics located.") to_chat(user, "
    ") - to_chat(user, "Internal prosthetics:") + to_chat(user, SPAN_NOTICE("Internal prosthetics:")) organ_found = null - for(var/obj/item/organ/O in H.internal_organs) - if(!BP_IS_PROSTHETIC(O)) + for(var/obj/item/organ/internal/organ in H.get_internal_organs()) + if(!BP_IS_PROSTHETIC(organ)) continue organ_found = 1 - to_chat(user, "[O.name]: [O.damage]") + to_chat(user, "[organ.name]: [SPAN_RED(organ.get_organ_damage())]") if(!organ_found) to_chat(user, "No prosthetics located.") src.add_fingerprint(user) - return + return TRUE diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 09e1e7a206e4..45a09beca266 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -1,24 +1,26 @@ -// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system - -/datum/robot_component/var/name -/datum/robot_component/var/installed = 0 -/datum/robot_component/var/powered = 0 -/datum/robot_component/var/toggled = 1 -/datum/robot_component/var/brute_damage = 0 -/datum/robot_component/var/electronics_damage = 0 -/datum/robot_component/var/idle_usage = 0 // Amount of power used every MC tick. In joules. -/datum/robot_component/var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc. -/datum/robot_component/var/max_damage = 30 // HP of this component. -/datum/robot_component/var/mob/living/silicon/robot/owner - -// The actual device object that has to be installed for this. -/datum/robot_component/var/external_type = null - -// The wrapped device(e.g. radio), only set if external_type isn't null -/datum/robot_component/var/obj/item/wrapped = null - -/datum/robot_component/New(mob/living/silicon/robot/R) - src.owner = R +// TODO: remove the robot.central_processor and robot.cell variables and completely rely on the robot component system +/datum/robot_component + var/name + /// Installation status; not a bool, may be -1, 0 or 1. + var/installed = 0 + var/powered = FALSE + var/toggled = TRUE + var/brute_damage = 0 + var/burn_damage = 0 + /// Amount of power used every MC tick. In joules. + var/idle_usage = 0 + /// Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc. + var/active_usage = 0 + /// HP of this component. + var/max_damage = 30 + var/mob/living/silicon/robot/owner + /// The actual device object that has to be installed for this. + var/external_type + /// The wrapped device(e.g. radio), only set if external_type isn't null + var/obj/item/wrapped + +/datum/robot_component/New(mob/living/silicon/robot/robot) + src.owner = robot /datum/robot_component/proc/accepts_component(var/obj/item/thing) . = istype(thing, external_type) @@ -37,6 +39,13 @@ installed = -1 uninstall() +/datum/robot_component/Destroy() + if(owner) + owner.components -= src + owner = null + wrapped = null + return ..() + /datum/robot_component/proc/repair() if (istype(wrapped, /obj/item/robot_parts/robot_component)) var/obj/item/robot_parts/robot_component/comp = wrapped @@ -45,13 +54,13 @@ installed = 1 install() -/datum/robot_component/proc/take_damage(brute, electronics, sharp, edge) +/datum/robot_component/proc/take_component_damage(brute, electronics, sharp, edge) if(installed != 1) return brute_damage += brute - electronics_damage += electronics + burn_damage += electronics - if(brute_damage + electronics_damage >= max_damage) destroy() + if(brute_damage + burn_damage >= max_damage) destroy() /datum/robot_component/proc/heal_damage(brute, electronics) if(installed != 1) @@ -59,10 +68,10 @@ return 0 brute_damage = max(0, brute_damage - brute) - electronics_damage = max(0, electronics_damage - electronics) + burn_damage = max(0, burn_damage - electronics) /datum/robot_component/proc/is_powered() - return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (!idle_usage || powered) + return (installed == 1) && (brute_damage + burn_damage < max_damage) && (!idle_usage || powered) /datum/robot_component/proc/update_power_state() if(toggled == 0) @@ -104,7 +113,7 @@ //A fixed and much cleaner implementation of /tg/'s special snowflake code. /datum/robot_component/actuator/is_powered() - return (installed == 1) && (brute_damage + electronics_damage < max_damage) + return (installed == 1) && (brute_damage + burn_damage < max_damage) // POWER CELL @@ -120,6 +129,10 @@ stored_cell = owner.cell owner.cell = null +/datum/robot_component/cell/Destroy() + QDEL_NULL(stored_cell) + return ..() + /datum/robot_component/cell/repair() owner.cell = stored_cell stored_cell = null @@ -154,28 +167,14 @@ external_type = /obj/item/robot_parts/robot_component/camera idle_usage = 10 max_damage = 40 - var/obj/machinery/camera/camera - -/datum/robot_component/camera/New(mob/living/silicon/robot/R) - ..() - camera = R.camera /datum/robot_component/camera/update_power_state() - ..() - if (camera) - camera.status = powered - -/datum/robot_component/camera/install() - if (camera) - camera.status = 1 - -/datum/robot_component/camera/uninstall() - if (camera) - camera.status = 0 + . = ..() + cameranet.update_visibility(owner, FALSE) /datum/robot_component/camera/destroy() - if (camera) - camera.status = 0 + . = ..() + cameranet.update_visibility(owner, FALSE) // SELF DIAGNOSIS MODULE // Analyses cyborg's modules, providing damage readouts and basic information @@ -225,28 +224,45 @@ icon = 'icons/obj/robot_component.dmi' icon_state = "working" material = /decl/material/solid/metal/steel - - var/brute = 0 - var/burn = 0 + max_health = 30 + var/burn_damage = 0 + var/brute_damage = 0 var/icon_state_broken = "broken" - var/total_dam = 0 - var/max_dam = 30 - -/obj/item/robot_parts/robot_component/proc/take_damage(var/brute_amt, var/burn_amt) - brute += brute_amt - burn += burn_amt - total_dam = brute+burn - if(total_dam >= max_dam) - var/obj/item/stock_parts/circuitboard/broken/broken_device = new (get_turf(src)) - if(icon_state_broken != "broken") - broken_device.icon = src.icon - broken_device.icon_state = icon_state_broken - broken_device.name = "broken [name]" - return broken_device - return 0 + +/obj/item/robot_parts/robot_component/check_health(lastdamage, lastdamtype, lastdamflags, consumed) + var/current_max_health = get_max_health() + if(lastdamage > 0) + if(lastdamtype == BRUTE) + brute_damage = clamp(lastdamage, 0, current_max_health) + if(lastdamtype == BURN || lastdamtype == ELECTROCUTE) + burn_damage = clamp(lastdamage, 0, current_max_health) + + //Health works differently for this thing + current_health = clamp(current_max_health - (brute_damage + burn_damage), 0, current_max_health) + . = ..() + +/obj/item/robot_parts/robot_component/proc/set_bruteloss(var/amount) + var/current_max_health = get_max_health() + brute_damage = clamp(amount, 0, current_max_health) + current_health = current_max_health - (brute_damage + burn_damage) + check_health(amount, BRUTE) + +/obj/item/robot_parts/robot_component/proc/set_burnloss(var/amount) + var/current_max_health = get_max_health() + burn_damage = clamp(amount, 0, current_max_health) + current_health = current_max_health - (brute_damage + burn_damage) + check_health(amount, BURN) + +/obj/item/robot_parts/robot_component/physically_destroyed(skip_qdel) + var/obj/item/stock_parts/circuitboard/broken/broken_device = new (get_turf(src)) + if(icon_state_broken != "broken") + broken_device.icon = src.icon + broken_device.icon_state = icon_state_broken + broken_device.name = "broken [name]" + . = ..() /obj/item/robot_parts/robot_component/proc/is_functional() - return ((brute + burn) < max_dam) + return ((brute_damage + burn_damage) < get_max_health()) /obj/item/robot_parts/robot_component/binary_communication_device name = "binary communication device" diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm deleted file mode 100644 index 3165ea13f490..000000000000 --- a/code/modules/mob/living/silicon/robot/custom_sprites.dm +++ /dev/null @@ -1,35 +0,0 @@ - -//list(ckey = real_name,) -//Since the ckey is used as the icon_state, the current system will only permit a single custom robot sprite per ckey. -//While it might be possible for a ckey to use that custom sprite for several real_names, it seems rather pointless to support it. -var/list/robot_custom_icons - -/hook/startup/proc/load_robot_custom_sprites() - var/config_file = file2text(CUSTOM_ITEM_SYNTH_CONFIG) - var/list/lines = splittext(config_file, "\n") - - robot_custom_icons = list() - for(var/line in lines) - //split entry into ckey and real_name - var/split_idx = findtext(line, "-") //this works if ckey cannot contain dashes, and findtext starts from the beginning - if(!split_idx || split_idx == length(line)) - continue //bad entry - - var/ckey = copytext(line, 1, split_idx) - var/real_name = copytext(line, split_idx+1) - - robot_custom_icons[ckey] = real_name - return 1 - -/mob/living/silicon/robot/proc/set_custom_sprite() - var/rname = robot_custom_icons[ckey] - if(rname && rname == real_name) - custom_sprite = 1 - icon = CUSTOM_ITEM_SYNTH - var/list/valid_states = icon_states(icon) - if(icon_state == "robot") - if("[ckey]-Standard" in valid_states) - icon_state = "[ckey]-Standard" - else - to_chat(src, "Could not locate [ckey]-Standard sprite.") - icon = 'icons/mob/robots.dmi' diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index fe9c75343215..43b602f2e72c 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -1,15 +1,16 @@ -/mob/living/silicon/robot/dust() - //Delete the MMI first so that it won't go popping out. - if(mmi) - qdel(mmi) - ..() +/mob/living/silicon/robot/dust(do_gibs) + . = ..() + if(.) + clear_brain() -/mob/living/silicon/robot/death(gibbed,deathmessage, show_dead_message) - if(camera) - camera.status = 0 - if(module) - for(var/obj/item/gripper/G in module.equipment) - G.drop_gripped_item() - locked = 0 - remove_robot_verbs() - ..(gibbed,"shudders violently for a moment, then becomes motionless, its eyes slowly darkening.", "You have suffered a critical system failure, and are dead.") +/mob/living/silicon/robot/get_death_message(gibbed) + return "shudders violently for a moment, then becomes motionless, its eyes slowly darkening." + +/mob/living/silicon/robot/death(gibbed) + . = ..() + if(.) + if(module) + for(var/obj/item/gripper/G in module.equipment) + G.drop_gripped_item() + locked = 0 + remove_robot_verbs() diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 56f9cff193cd..bae0e605b0aa 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -1,10 +1,8 @@ /mob/living/silicon/robot/drone name = "maintenance drone" real_name = "drone" - icon = 'icons/mob/robots_drones.dmi' - icon_state = "repairbot" - maxHealth = 35 - health = 35 + icon = 'icons/mob/robots/drones/drone.dmi' + max_health = 35 cell_emp_mult = 1 universal_speak = FALSE universal_understand = TRUE @@ -12,11 +10,12 @@ pass_flags = PASS_FLAG_TABLE braintype = "Drone" lawupdate = 0 - density = 1 + density = TRUE req_access = list(access_engine, access_robotics) - integrated_light_max_bright = 0.5 + integrated_light_power = 0.4 + integrated_light_range = 3 local_transmit = 1 - possession_candidate = 1 + possession_candidate = TRUE speed = -1 can_pull_size = ITEM_SIZE_NORMAL @@ -26,35 +25,28 @@ mob_swap_flags = SIMPLE_ANIMAL mob_push_flags = SIMPLE_ANIMAL mob_always_swap = 1 - - mob_size = MOB_SIZE_MEDIUM // Small mobs can't open doors, it's a huge pain for drones. + mob_size = MOB_SIZE_SMALL laws = /datum/ai_laws/drone - silicon_camera = /obj/item/camera/siliconcam/drone_camera - - //Used for self-mailing. - var/mail_destination = "" - var/module_type = /obj/item/robot_module/drone - var/hat_x = 0 - var/hat_y = -13 - holder_type = /obj/item/holder/drone - ntos_type = null + os_type = null starting_stock_parts = null + var/module_type = /obj/item/robot_module/drone + /mob/living/silicon/robot/drone/Initialize() . = ..() - + add_inventory_slot(new /datum/inventory_slot/head/simple) + set_extension(src, /datum/extension/base_icon_state, icon_state) verbs += /mob/living/proc/hide remove_language(/decl/language/binary) add_language(/decl/language/binary, 0) add_language(/decl/language/binary/drone, 1) - set_extension(src, /datum/extension/hattable, hat_x, hat_y) default_language = /decl/language/binary/drone // NO BRAIN. - mmi = null + central_processor = null //We need to screw with their HP a bit. They have around one fifth as much HP as a full borg. for(var/V in components) if(V != "power cell") @@ -64,39 +56,37 @@ verbs -= /mob/living/silicon/robot/verb/Namepick update_icon() - GLOB.moved_event.register(src, src, /mob/living/silicon/robot/drone/proc/on_moved) + events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/mob/living/silicon/robot/drone, on_moved)) /mob/living/silicon/robot/drone/Destroy() - GLOB.moved_event.unregister(src, src, /mob/living/silicon/robot/drone/proc/on_moved) + events_repository.unregister(/decl/observ/moved, src, src, TYPE_PROC_REF(/mob/living/silicon/robot/drone, on_moved)) . = ..() /mob/living/silicon/robot/drone/proc/on_moved(var/atom/movable/am, var/turf/old_loc, var/turf/new_loc) old_loc = get_turf(old_loc) new_loc = get_turf(new_loc) - if(!(old_loc && new_loc)) // Allows inventive admins to move drones between non-adjacent Z-levels by moving them to null space first I suppose return - if(ARE_Z_CONNECTED(old_loc.z, new_loc.z)) + if(LEVELS_ARE_Z_CONNECTED(old_loc.z, new_loc.z)) return - // None of the tests passed, good bye - self_destruct() + gib() /mob/living/silicon/robot/drone/can_be_possessed_by(var/mob/observer/ghost/possessor) if(!istype(possessor) || !possessor.client || !possessor.ckey) - return 0 - if(!config.allow_drone_spawn) - to_chat(src, "Playing as drones is not currently permitted.") - return 0 + return FALSE + if(!get_config_value(/decl/config/toggle/on/allow_drone_spawn)) + to_chat(possessor, SPAN_DANGER("Playing as drones is not currently permitted.")) + return FALSE if(too_many_active_drones()) - to_chat(src, "The maximum number of active drones has been reached..") - return 0 - if(jobban_isbanned(possessor,"Robot")) - to_chat(usr, "You are banned from playing synthetics and cannot spawn as a drone.") - return 0 + to_chat(possessor, SPAN_DANGER("The maximum number of active drones has been reached.")) + return FALSE + if(jobban_isbanned(possessor,ASSIGNMENT_ROBOT)) + to_chat(possessor, SPAN_DANGER("You are banned from playing synthetics and cannot spawn as a drone.")) + return FALSE if(!possessor.MayRespawn(1,DRONE_SPAWN_DELAY)) - return 0 - return 1 + return FALSE + return TRUE /mob/living/silicon/robot/drone/do_possession(var/mob/observer/ghost/possessor) if(!(istype(possessor) && possessor.ckey)) @@ -112,24 +102,42 @@ /mob/living/silicon/robot/drone/construction name = "construction drone" - icon_state = "constructiondrone" + icon = 'icons/mob/robots/drones/drone_construction.dmi' laws = /datum/ai_laws/construction_drone module_type = /obj/item/robot_module/drone/construction can_pull_size = ITEM_SIZE_STRUCTURE can_pull_mobs = MOB_PULL_SAME - hat_x = 1 - hat_y = -12 + integrated_light_power = 0.8 + integrated_light_range = 5 + +/mob/living/silicon/robot/drone/construction/get_bodytype() + return GET_DECL(/decl/bodytype/drone/construction) + +/decl/bodytype/drone/construction + uid = "bodytype_drone_construction" + +/decl/bodytype/drone/construction/Initialize() + _equip_adjust = list( + slot_head_str = list( + "[NORTH]" = list(1, -12), + "[SOUTH]" = list(1, -12), + "[EAST]" = list(1, -12), + "[WEST]" = list(1, -12) + ) + ) + . = ..() /mob/living/silicon/robot/drone/init() - additional_law_channels["Drone"] = ":d" - if(!module) module = new module_type(src) + additional_law_channels["Drone"] = "d" + if(!module) + module = new module_type(src) - flavor_text = "It's a tiny little repair drone. The casing is stamped with a logo and the subscript: '[GLOB.using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" + flavor_text = "It's a tiny little repair drone. The casing is stamped with a logo and the subscript: '[global.using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) //Redefining some robot procs... /mob/living/silicon/robot/drone/fully_replace_character_name(pickedName as text) - // Would prefer to call the grandparent proc but this isn't possible, so.. + // Would prefer to call the grandparent proc but this isn't possible, so... real_name = pickedName SetName(real_name) @@ -140,23 +148,16 @@ real_name = "[initial(name)] ([random_id(type,100,999)])" SetName(real_name) -/mob/living/silicon/robot/drone/on_update_icon() - - cut_overlays() - if(stat == 0) +/mob/living/silicon/robot/drone/get_eye_overlay() + var/image/ret = ..() + if(ret) if(controlling_ai) - add_overlay("eyes-[icon_state]-ai") + ret.color = COLOR_GREEN else if(emagged) - add_overlay("eyes-[icon_state]-emag") + ret.color = COLOR_RED else - add_overlay("eyes-[icon_state]") - else - add_overlay("eyes") - - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - var/image/I = hattable?.get_hat_overlay(src) - if(I) - add_overlay(I) + ret.color = COLOR_CYAN + return ret /mob/living/silicon/robot/drone/choose_icon() return @@ -165,49 +166,42 @@ return //Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). -/mob/living/silicon/robot/drone/attackby(var/obj/item/W, var/mob/user) - - if(istype(W, /obj/item/borg/upgrade)) - to_chat(user, "\The [src] is not compatible with \the [W].") +/mob/living/silicon/robot/drone/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/borg/upgrade)) + to_chat(user, "\The [src] is not compatible with \the [used_item].") return TRUE - - else if(isCrowbar(W) && user.a_intent != I_HURT) + else if(IS_CROWBAR(used_item) && !user.check_intent(I_FLAG_HARM)) to_chat(user, "\The [src] is hermetically sealed. You can't open the case.") - return - - else if (istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer)) - - if(stat == 2) - - if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave. + return TRUE + else if (istype(used_item, /obj/item/card/id)||istype(used_item, /obj/item/modular_computer)) + if(stat == DEAD) + if(!get_config_value(/decl/config/toggle/on/allow_drone_spawn) || emagged || should_be_dead()) //It's dead, Dave. to_chat(user, "The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one.") - return - - if(!allowed(usr)) + return TRUE + if(!allowed(user)) to_chat(user, "Access denied.") - return - - user.visible_message("\The [user] swipes \his ID card through \the [src], attempting to reboot it.", ">You swipe your ID card through \the [src], attempting to reboot it.") + return TRUE + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + SPAN_NOTICE("\The [user] swipes [pronouns.his] ID card through \the [src], attempting to reboot it."), \ + SPAN_NOTICE("You swipe your ID card through \the [src], attempting to reboot it.")) request_player() - return - - else - user.visible_message("\The [user] swipes \his ID card through \the [src], attempting to shut it down.", "You swipe your ID card through \the [src], attempting to shut it down.") - - if(emagged) - return - - if(allowed(usr)) + return TRUE + + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + SPAN_DANGER("\The [user] swipes [pronouns.his] ID card through \the [src], attempting to shut it down."), \ + SPAN_DANGER("You swipe your ID card through \the [src], attempting to shut it down.")) + if(!emagged) + if(allowed(user)) shut_down() else - to_chat(user, "Access denied.") - - return - - ..() + to_chat(user, SPAN_DANGER("Access denied.")) + return TRUE + return ..() /mob/living/silicon/robot/drone/emag_act(var/remaining_charges, var/mob/user) - if(!client || stat == 2) + if(!client || stat == DEAD) to_chat(user, "There's not much point subverting this heap of junk.") return @@ -225,7 +219,7 @@ log_and_message_admins("emagged drone [key_name_admin(src)]. Laws overridden.", user) log_game("[key_name(user)] emagged drone [key_name(src)][controlling_ai ? " but AI [key_name(controlling_ai)] is in remote control" : " Laws overridden"].") var/time = time2text(world.realtime,"hh:mm:ss") - GLOB.lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + global.lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") emagged = 1 lawupdate = 0 @@ -234,44 +228,18 @@ clear_inherent_laws() QDEL_NULL(laws) laws = new /datum/ai_laws/syndicate_override - set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.") - + var/decl/pronouns/pronouns = user.get_pronouns(ignore_coverings = TRUE) + set_zeroth_law("Only [user.real_name] and people [pronouns.he] designates as being such are operatives.") if(!controlling_ai) to_chat(src, "Obey these laws:") laws.show_laws(src) - to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.") + to_chat(src, SPAN_DANGER("ALERT: [user.real_name] is your new master. Obey your new laws and [pronouns.his] commands.")) return 1 -//DRONE LIFE/DEATH -//For some goddamn reason robots have this hardcoded. Redefining it for our fragile friends here. -/mob/living/silicon/robot/drone/updatehealth() - if(status_flags & GODMODE) - health = 35 - set_stat(CONSCIOUS) - return - health = 35 - (getBruteLoss() + getFireLoss()) - return - -//Easiest to check this here, then check again in the robot proc. -//Standard robots use config for crit, which is somewhat excessive for these guys. -//Drones killed by damage will gib. -/mob/living/silicon/robot/drone/handle_regular_status_updates() - if(health <= -35 && src.stat != DEAD) - self_destruct() - return - if(health <= 0 && src.stat != DEAD) - death() - return - ..() - -/mob/living/silicon/robot/drone/self_destruct() - timeofdeath = world.time - death() //Possibly redundant, having trouble making death() cooperate. - gib() - -//DRONE MOVEMENT. -/mob/living/silicon/robot/drone/slip_chance(var/prob_slip) - return 0 +/mob/living/silicon/robot/drone/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + . = ..() + if(amount && should_be_dead() && stat == DEAD && !QDELETED(src)) + gib() //CONSOLE PROCS /mob/living/silicon/robot/drone/proc/law_resync() @@ -280,7 +248,7 @@ to_chat(src, "Someone issues a remote law reset order for this unit, but you disregard it.") return - if(stat != 2) + if(stat != DEAD) if(emagged) to_chat(src, "You feel something attempting to modify your programming, but your hacked subroutines are unaffected.") else @@ -294,7 +262,7 @@ to_chat(src, "Someone issues a remote kill order for this unit, but you disregard it.") return - if(stat != 2) + if(stat != DEAD) if(emagged) to_chat(src, "You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.") else @@ -306,7 +274,7 @@ clear_inherent_laws(1) clear_ion_laws(1) QDEL_NULL(laws) - var/law_type = initial(laws) || GLOB.using_map.default_law_type + var/law_type = initial(laws) || global.using_map.default_law_type laws = new law_type //Reboot procs. @@ -314,8 +282,8 @@ /mob/living/silicon/robot/drone/proc/request_player() if(too_many_active_drones()) return - var/datum/ghosttrap/G = get_ghost_trap("maintenance drone") - G.request_player(src, "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) + var/decl/ghosttrap/ghosttrap = GET_DECL(/decl/ghosttrap/maintenance_drone) + ghosttrap.request_player(src, "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) /mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player) if(!player) return @@ -343,20 +311,16 @@ /mob/living/silicon/robot/drone/construction/welcome_drone() to_chat(src, "You are a construction drone, an autonomous engineering and fabrication system..") - to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.") + to_chat(src, "You are assigned to a construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.") to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.") to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..") -/mob/living/silicon/robot/drone/construction/init() - ..() - flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph." - /proc/too_many_active_drones() var/drones = 0 - for(var/mob/living/silicon/robot/drone/D in GLOB.silicon_mob_list) + for(var/mob/living/silicon/robot/drone/D in global.silicon_mob_list) if(D.key && D.client) drones++ - return drones >= config.max_maint_drones + return drones >= get_config_value(/decl/config/num/max_maint_drones) /mob/living/silicon/robot/drone/show_laws(var/everyone = 0) if(!controlling_ai) @@ -372,3 +336,24 @@ if(!controlling_ai) return ..() controlling_ai.open_subsystem(/datum/nano_module/law_manager) + +/mob/living/silicon/robot/drone/get_bodytype() + return GET_DECL(/decl/bodytype/drone) + +/decl/bodytype/drone + name = "drone" + bodytype_flag = 0 + bodytype_category = "drone body" + uid = "bodytype_drone" + +/decl/bodytype/drone/Initialize() + if(!length(_equip_adjust)) + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list(0, -13), + "[SOUTH]" = list(0, -13), + "[EAST]" = list(0, -13), + "[WEST]" = list(0, -13) + ) + ) + . = ..() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm index 09223e541a0f..0cd4980de8ce 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm @@ -4,17 +4,27 @@ set desc = "Tag yourself for delivery through the disposals system." set category = "Silicon Commands" - var/new_tag = input("Select the desired destination.", "Set Mail Tag", null) as null|anything in GLOB.tagger_locations + var/choice = alert(usr, "Enter a custom destination, or pick one from the list?", "", "Custom", "List", "Cancel") + var/datum/extension/sorting_tag/ST + var/new_tag - if(!new_tag) - mail_destination = "" + if(choice == "Custom") + ST = get_extension(src, /datum/extension/sorting_tag) + new_tag = input(usr, "Enter custom destination tag:", "Custom Destination", ST?.destination) + else if(choice == "List") + new_tag = input("Select the desired destination.", "Set Mail Tag", null) as null|anything in global.tagger_locations + else return - to_chat(src, "You configure your internal beacon, tagging yourself for delivery to '[new_tag]'.") - mail_destination = new_tag + if(!new_tag) + remove_extension(src, /datum/extension/sorting_tag) + return + ST = get_or_create_extension(src, /datum/extension/sorting_tag) + ST.destination = new_tag + to_chat(src, SPAN_NOTICE("You configure your internal beacon, tagging yourself for delivery to '[new_tag]'.")) //Auto flush if we use this verb inside a disposal chute. var/obj/machinery/disposal/D = src.loc if(istype(D)) - to_chat(src, "\The [D] acknowledges your signal.") + to_chat(src, SPAN_NOTICE("\The [D] acknowledges your signal.")) D.flush_count = D.flush_every_ticks diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm index e270f540aabf..7c6bfc00f010 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -20,96 +20,88 @@ var/dat dat += "Maintenance Units
    " - for(var/mob/living/silicon/robot/drone/D in world) + for(var/mob/living/silicon/robot/drone/D in global.silicon_mob_list) if(D.z != src.z) continue - dat += "
    [D.real_name] ([D.stat == 2 ? "INACTIVE" : "ACTIVE"])" + dat += "
    [D.real_name] ([D.stat == DEAD ? "INACTIVE" : "ACTIVE"])" dat += "
    Cell charge: [D.cell.charge]/[D.cell.maxcharge]." - dat += "
    Currently located in: [get_area(D)]." - dat += "
    Resync | Shutdown
    " + dat += "
    Currently located in: [get_area_name(D)]." + dat += "
    Resync | Shutdown" - dat += "

    Request drone presence in area:[drone_call_area] (Send ping)" + dat += "

    Request drone presence in area:[drone_call_area] (Send ping)" dat += "

    Drone fabricator: " - dat += "[dronefab ? "[(dronefab.produce_drones && !(dronefab.stat & NOPOWER)) ? "ACTIVE" : "INACTIVE"]" : "FABRICATOR NOT DETECTED. (search)"]" + dat += "[dronefab ? "[(dronefab.produce_drones && !(dronefab.stat & NOPOWER)) ? "ACTIVE" : "INACTIVE"]" : "FABRICATOR NOT DETECTED. (search)"]" show_browser(user, dat, "window=computer;size=400x500") onclose(user, "computer") return -/obj/machinery/computer/drone_control/Topic(href, href_list) +/obj/machinery/computer/drone_control/OnTopic(mob/user, href_list) if((. = ..())) return - if(!allowed(usr)) - to_chat(usr, "Access denied.") - return - - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) + if(!allowed(user)) + to_chat(user, "Access denied.") + return TOPIC_HANDLED if (href_list["setarea"]) - //Probably should consider using another list, but this one will do. - var/t_area = input("Select the area to ping.", "Set Target Area", null) as null|anything in GLOB.tagger_locations - + var/t_area = input("Select the area to ping.", "Set Target Area", null) as null|anything in global.tagger_locations if(!t_area) - return - + return TOPIC_HANDLED drone_call_area = t_area - to_chat(usr, "You set the area selector to [drone_call_area].") + to_chat(user, "You set the area selector to [drone_call_area].") + . = TOPIC_REFRESH else if (href_list["ping"]) - - to_chat(usr, "You issue a maintenance request for all active drones, highlighting [drone_call_area].") - for(var/mob/living/silicon/robot/drone/D in world) - if(D.client && D.stat == 0) + to_chat(user, "You issue a maintenance request for all active drones, highlighting [drone_call_area].") + for(var/mob/living/silicon/robot/drone/D in global.silicon_mob_list) + if(D.client && D.stat == CONSCIOUS) to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].") + . = TOPIC_REFRESH else if (href_list["resync"]) - var/mob/living/silicon/robot/drone/D = locate(href_list["resync"]) - - if(D.stat != 2) - to_chat(usr, "You issue a law synchronization directive for the drone.") + . = TOPIC_HANDLED + if(D.stat != DEAD) + to_chat(user, "You issue a law synchronization directive for the drone.") D.law_resync() + . = TOPIC_REFRESH else if (href_list["shutdown"]) - var/mob/living/silicon/robot/drone/D = locate(href_list["shutdown"]) - - if(D.stat != 2) - to_chat(usr, "You issue a kill command for the unfortunate drone.") - message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.") - log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.") + . = TOPIC_HANDLED + if(D.stat != DEAD) + to_chat(user, "You issue a kill command for the unfortunate drone.") + message_admins("[key_name_admin(user)] issued kill order for drone [key_name_admin(D)] from control console.") + log_game("[key_name(user)] issued kill order for [key_name(src)] from control console.") D.shut_down() + . = TOPIC_REFRESH else if (href_list["search_fab"]) if(dronefab) - return + return TOPIC_HANDLED for(var/obj/machinery/drone_fabricator/fab in oview(3,src)) - if(fab.stat & NOPOWER) continue - dronefab = fab - to_chat(usr, "Drone fabricator located.") - return + to_chat(user, "Drone fabricator located.") + return TOPIC_REFRESH - to_chat(usr, "Unable to locate drone fabricator.") + to_chat(user, "Unable to locate drone fabricator.") + . = TOPIC_HANDLED else if (href_list["toggle_fab"]) - if(!dronefab) - return + return TOPIC_HANDLED if(get_dist(src,dronefab) > 3) dronefab = null - to_chat(usr, "Unable to locate drone fabricator.") - return + to_chat(user, "Unable to locate drone fabricator.") + return TOPIC_REFRESH dronefab.produce_drones = !dronefab.produce_drones - to_chat(usr, "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.") - - src.updateUsrDialog() + to_chat(user, "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.") + . = TOPIC_REFRESH diff --git a/code/modules/mob/living/silicon/robot/drone/drone_damage.dm b/code/modules/mob/living/silicon/robot/drone/drone_damage.dm index f7256df37e91..2e5a4d814c6e 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_damage.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_damage.dm @@ -6,20 +6,22 @@ /mob/living/silicon/robot/drone/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/used_weapon = null) bruteloss += brute fireloss += burn + update_health() /mob/living/silicon/robot/drone/heal_overall_damage(var/brute, var/burn) - bruteloss -= brute fireloss -= burn + if(bruteloss<0) + bruteloss = 0 + if(fireloss<0) + fireloss = 0 + update_health() - if(bruteloss<0) bruteloss = 0 - if(fireloss<0) fireloss = 0 - -/mob/living/silicon/robot/drone/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/emp = 0) - take_overall_damage(brute,burn) +/mob/living/silicon/robot/drone/take_organ_damage(var/brute = 0, var/burn = 0, var/bypass_armour = FALSE, var/override_droplimb) + take_overall_damage(brute, burn) -/mob/living/silicon/robot/drone/heal_organ_damage(var/brute, var/burn) - heal_overall_damage(brute,burn) +/mob/living/silicon/robot/drone/heal_organ_damage(var/brute, var/burn, var/affect_robo = FALSE, var/update_health = TRUE) + heal_overall_damage(brute, burn) /mob/living/silicon/robot/drone/getFireLoss() return fireloss diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index c1138869ed03..969dd3dac640 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -5,7 +5,7 @@ desc = "A simple grasping tool specialized in construction and engineering work." icon = 'icons/obj/items/borg_module/borg_gripper.dmi' icon_state = "gripper" - + max_health = ITEM_HEALTH_NO_DAMAGE item_flags = ITEM_FLAG_NO_BLUDGEON //Has a list of items that it can hold. @@ -15,14 +15,14 @@ /obj/item/tracker_electronics, /obj/item/stock_parts, /obj/item/frame, - /obj/item/camera_assembly, + /obj/item/frame/camera/kit, /obj/item/tank, /obj/item/stock_parts/circuitboard, /obj/item/stock_parts/smes_coil, /obj/item/stock_parts/computer, /obj/item/fuel_assembly, - /obj/item/stack/material/deuterium, - /obj/item/stack/material/tritium, + /obj/item/stack/material/aerogel/mapped/deuterium, + /obj/item/stack/material/aerogel/mapped/tritium, /obj/item/stack/tile ) @@ -53,7 +53,7 @@ /obj/item/card/id, /obj/item/book, /obj/item/newspaper, - /obj/item/smallDelivery, + /obj/item/parcel, /obj/item/forensics/sample ) @@ -65,7 +65,7 @@ /obj/item/chems/glass, /obj/item/chems/pill, /obj/item/chems/ivbag, - /obj/item/storage/pill_bottle + /obj/item/pill_bottle ) /obj/item/gripper/research //A general usage gripper, used for toxins/robotics/xenobio/etc @@ -76,17 +76,15 @@ can_hold = list( /obj/item/cell, /obj/item/stock_parts, - /obj/item/mmi, + /obj/item/organ/internal/brain_interface, /obj/item/robot_parts, /obj/item/borg/upgrade, /obj/item/flash, /obj/item/organ/internal/brain, - /obj/item/organ/internal/posibrain, /obj/item/stack/cable_coil, /obj/item/stock_parts/circuitboard, - /obj/item/slime_extract, /obj/item/chems/glass, - /obj/item/chems/food/snacks/monkeycube, + /obj/item/food/animal_cube, /obj/item/stock_parts/computer, /obj/item/transfer_valve, /obj/item/assembly/signaler, @@ -103,8 +101,6 @@ can_hold = list( /obj/item/chems/glass, /obj/item/seeds, - /obj/item/grown, - /obj/item/slime_extract, /obj/item/disk/botany ) @@ -114,9 +110,10 @@ desc = "A simple grasping tool used to perform tasks in the service sector, such as handling food, drinks, and seeds." can_hold = list( /obj/item/chems/glass, - /obj/item/chems/food, + /obj/item/food, + /obj/item/chems/drinks, + /obj/item/chems/condiment, /obj/item/seeds, - /obj/item/grown, /obj/item/glass_extra ) @@ -143,12 +140,12 @@ can_hold = list( /obj/item/stack/material - ) + ) -/obj/item/gripper/examine(mob/user) +/obj/item/gripper/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(wrapped) - to_chat(user, "It is holding \a [wrapped].") + . += "It is holding \a [wrapped]." /obj/item/gripper/attack_self(mob/user) if(wrapped) @@ -175,9 +172,9 @@ wrapped = null //on_update_icon() -/obj/item/gripper/attack(mob/living/carbon/M, mob/living/carbon/user) +/obj/item/gripper/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) // Don't fall through and smack people with gripper, instead just no-op - return 0 + return FALSE /obj/item/gripper/resolve_attackby(var/atom/target, var/mob/living/user, params) @@ -191,15 +188,15 @@ //Temporary put wrapped into user so target's attackby() checks pass. wrapped.forceMove(user) - //The force of the wrapped obj gets set to zero during the attack() and afterattack(). - var/force_holder = wrapped.force - wrapped.force = 0.0 + //The force of the wrapped obj gets set to zero during the use_on_mob() and afterattack(). + var/force_holder = wrapped.get_base_attack_force() + wrapped.set_base_attack_force(0) //Pass the attack on to the target. This might delete/relocate wrapped. var/resolved = wrapped.resolve_attackby(target,user,params) //If resolve_attackby forces waiting before taking wrapped, we need to let it finish before doing the rest. - addtimer(CALLBACK(src, .proc/finish_using, target, user, params, force_holder, resolved), 0) + addtimer(CALLBACK(src, PROC_REF(finish_using), target, user, params, force_holder, resolved), 0) else if(istype(target,/obj/item)) //Check that we're not pocketing a mob. var/obj/item/I = target @@ -213,12 +210,10 @@ //We can grab the item, finally. if(grab) - if(I == user.s_active) - var/obj/item/storage/storage = I - storage.close(user) //Closes the ui. - if(istype(I.loc, /obj/item/storage)) - var/obj/item/storage/storage = I.loc - if(!storage.remove_from_storage(I, src)) + if(I == user.active_storage?.holder) + user.active_storage.close(user) //Closes the ui. + if(I.loc?.storage) + if(!I.loc.storage.remove_from_storage(user, I, src)) return else I.forceMove(src) @@ -228,8 +223,8 @@ else to_chat(user, "Your gripper cannot hold \the [target].") - else if(istype(target,/obj/machinery/power/apc)) - var/obj/machinery/power/apc/A = target + else if(istype(target,/obj/machinery/apc)) + var/obj/machinery/apc/A = target if(A.components_are_accessible(/obj/item/stock_parts/power/battery)) var/obj/item/stock_parts/power/battery/bat = A.get_component_of_type(/obj/item/stock_parts/power/battery) var/obj/item/cell/cell = bat.extract_cell(src) @@ -237,7 +232,7 @@ wrapped = cell cell.forceMove(src) - else if(istype(target,/mob/living/silicon/robot)) + else if(isrobot(target)) var/mob/living/silicon/robot/A = target if(A.opened) if(A.cell) @@ -261,7 +256,7 @@ wrapped.afterattack(target, user, 1, params) if(wrapped) - wrapped.force = force_holder + wrapped.set_base_attack_force(force_holder) //If wrapped was neither deleted nor put into target, put it back into the gripper. if(wrapped && user && !QDELETED(wrapped) && wrapped.loc == user) @@ -271,11 +266,11 @@ //TODO: Matter decompiler. /obj/item/matter_decompiler - name = "matter decompiler" desc = "Eating trash, bits of glass, or other debris will replenish your stores." icon = 'icons/obj/items/borg_module/decompiler.dmi' icon_state = "decompiler" + max_health = ITEM_HEALTH_NO_DAMAGE //Metal, glass, wood, plastic. var/datum/matter_synth/metal = null @@ -283,8 +278,15 @@ var/datum/matter_synth/wood = null var/datum/matter_synth/plastic = null -/obj/item/matter_decompiler/attack(mob/living/carbon/M, mob/living/carbon/user) - return +/obj/item/matter_decompiler/Destroy() + metal = null + glass = null + wood = null + plastic = null + return ..() + +/obj/item/matter_decompiler/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE /obj/item/matter_decompiler/afterattack(atom/target, mob/living/user, proximity, params) @@ -299,7 +301,7 @@ var/grabbed_something = 0 for(var/mob/M in T) - if(istype(M,/mob/living/simple_animal/lizard) || istype(M,/mob/living/simple_animal/mouse)) + if(islizard(M) || ismouse(M)) src.loc.visible_message("[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.","It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.") new/obj/effect/decal/cleanable/blood/splatter(get_turf(src)) qdel(M) @@ -309,7 +311,7 @@ plastic.add_charge(2000) return - else if(istype(M,/mob/living/silicon/robot/drone) && !M.client) + else if(isdrone(M) && !M.client) var/mob/living/silicon/robot/D = src.loc @@ -340,18 +342,19 @@ else continue - for(var/obj/W in T) + // TODO: Jesus Christ, use matter or the procs the decompiler nades use. + for(var/obj/thing in T) //Different classes of items give different commodities. - if(istype(W,/obj/item/trash/cigbutt)) + if(istype(thing,/obj/item/trash/cigbutt)) if(plastic) plastic.add_charge(500) - else if(istype(W,/obj/effect/spider/spiderling)) + else if(istype(thing,/obj/effect/spider/spiderling)) if(wood) wood.add_charge(2000) if(plastic) plastic.add_charge(2000) - else if(istype(W,/obj/item/light)) - var/obj/item/light/L = W + else if(istype(thing,/obj/item/light)) + var/obj/item/light/L = thing if(L.status >= 2) if(metal) metal.add_charge(250) @@ -359,99 +362,45 @@ glass.add_charge(250) else continue - else if(istype(W,/obj/item/remains/robot)) + else if(istype(thing,/obj/item/remains/robot)) if(metal) metal.add_charge(2000) if(plastic) plastic.add_charge(2000) if(glass) glass.add_charge(1000) - else if(istype(W,/obj/item/trash)) + else if(istype(thing,/obj/item/trash)) if(metal) metal.add_charge(1000) if(plastic) plastic.add_charge(3000) - else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot)) + else if(istype(thing,/obj/effect/decal/cleanable/blood/gibs/robot)) if(metal) metal.add_charge(2000) if(glass) glass.add_charge(2000) - else if(istype(W,/obj/item/ammo_casing)) + else if(istype(thing,/obj/item/ammo_casing)) if(metal) metal.add_charge(1000) - else if(istype(W,/obj/item/shard/shrapnel)) + else if(istype(thing,/obj/item/shard/shrapnel)) if(metal) metal.add_charge(1000) - else if(istype(W,/obj/item/shard)) + else if(istype(thing,/obj/item/shard)) if(glass) glass.add_charge(1000) - else if(istype(W,/obj/item/chems/food/snacks/grown)) + else if(istype(thing,/obj/item/food/grown)) if(wood) wood.add_charge(4000) - else if(istype(W,/obj/item/pipe)) + else if(istype(thing,/obj/item/pipe)) // This allows drones and engiborgs to clear pipe assemblies from floors. + pass() else continue - qdel(W) + qdel(thing) grabbed_something = 1 if(grabbed_something) to_chat(user, "You deploy your decompiler and clear out the contents of \the [T].") else to_chat(user, "Nothing on \the [T] is useful to you.") - return - -//PRETTIER TOOL LIST. -/mob/living/silicon/robot/drone/installed_modules() - - if(weapon_lock) - to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") - return - - if(!module) - module = new /obj/item/robot_module/drone(src) - - var/dat = "Drone modules\n" - dat += {" - Activated Modules -
    - Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
    - Module 2: [module_state_2 ? "
    [module_state_2]" : "No Module"]
    - Module 3: [module_state_3 ? "
    [module_state_3]" : "No Module"]
    -
    - Installed Modules

    "} - - - var/tools = "Tools and devices
    " - var/resources = "
    Resources
    " - - for (var/O in module.equipment) - - var/module_string = "" - - if (!O) - module_string += text("Resource depleted
    ") - else if(activated(O)) - module_string += text("[O]: Activated
    ") - else - module_string += text("[O]:
    Activate
    ") - - if((istype(O,/obj/item) || istype(O,/obj/item)) && !(istype(O,/obj/item/stack/cable_coil))) - tools += module_string - else - resources += module_string - - dat += tools - - if (emagged) - if (!module.emag) - dat += text("Resource depleted
    ") - else if(activated(module.emag)) - dat += text("[module.emag]: Activated
    ") - else - dat += text("[module.emag]: Activate
    ") - - dat += resources - - show_browser(src, dat, "window=robotmod") diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index 0acbf1353455..2bfdc4c3ec64 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -1,6 +1,6 @@ /proc/count_drones() var/drones = 0 - for(var/mob/living/silicon/robot/drone/D in world) + for(var/mob/living/silicon/robot/drone/D in global.silicon_mob_list) if(D.key && D.client) drones++ return drones @@ -10,12 +10,13 @@ desc = "A large automated factory for producing maintenance drones." appearance_flags = 0 - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE idle_power_usage = 20 active_power_usage = 5000 - var/fabricator_tag = "Exodus" + var/fabricator_tag + var/fab_tag_modifier var/drone_progress = 0 var/produce_drones = 1 var/time_last_drone = 500 @@ -24,6 +25,21 @@ icon = 'icons/obj/machines/drone_fab.dmi' icon_state = "drone_fab_idle" +/obj/machinery/drone_fabricator/Initialize() + . = ..() + if(isnull(fabricator_tag)) + fabricator_tag = "[global.using_map.station_short][fab_tag_modifier]" + +/obj/machinery/drone_fabricator/maintenance + name = "maintenance drone fabricator" + fab_tag_modifier = " (Maintenance)" + +/obj/machinery/drone_fabricator/construction + name = "construction drone fabricator" + desc = "A large automated factory for producing construction drones." + fab_tag_modifier = " (Construction)" + drone_type = /mob/living/silicon/robot/drone/construction + /obj/machinery/drone_fabricator/derelict name = "construction drone fabricator" fabricator_tag = "Derelict" @@ -48,22 +64,22 @@ icon_state = "drone_fab_active" var/elapsed = world.time - time_last_drone - drone_progress = round((elapsed/config.drone_build_time)*100) + drone_progress = round((elapsed/get_config_value(/decl/config/num/drone_build_time))*100) if(drone_progress >= 100) visible_message("\The [src] voices a strident beep, indicating a drone chassis is prepared.") -/obj/machinery/drone_fabricator/examine(mob/user) +/obj/machinery/drone_fabricator/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(produce_drones && drone_progress >= 100 && isghost(user) && config.allow_drone_spawn && count_drones() < config.max_maint_drones) - to_chat(user, "
    A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone.") + if(produce_drones && drone_progress >= 100 && isghost(user) && get_config_value(/decl/config/toggle/on/allow_drone_spawn) && count_drones() < get_config_value(/decl/config/num/max_maint_drones)) + . += "A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone." /obj/machinery/drone_fabricator/proc/create_drone(var/client/player) if(stat & NOPOWER) return - if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones) + if(!produce_drones || !get_config_value(/decl/config/toggle/on/allow_drone_spawn) || count_drones() >= get_config_value(/decl/config/num/max_maint_drones)) return if(player && !isghost(player.mob)) @@ -91,20 +107,24 @@ /proc/try_drone_spawn(var/mob/user, var/obj/machinery/drone_fabricator/fabricator) if(GAME_STATE < RUNLEVEL_GAME) - to_chat(user, "The game hasn't started yet!") + to_chat(user, SPAN_WARNING("The game hasn't started yet!")) + return + + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(user)) + to_chat(user, SPAN_WARNING("Non-whitelisted players cannot join rounds except as observers.")) return - if(!(config.allow_drone_spawn)) - to_chat(user, "That verb is not currently permitted.") + if(!get_config_value(/decl/config/toggle/on/allow_drone_spawn)) + to_chat(user, SPAN_WARNING("That verb is not currently permitted.")) return - if(jobban_isbanned(user,"Robot")) - to_chat(user, "You are banned from playing synthetics and cannot spawn as a drone.") + if(jobban_isbanned(user,ASSIGNMENT_ROBOT)) + to_chat(user, SPAN_WARNING("You are banned from playing synthetics and cannot spawn as a drone.")) return - if(config.use_age_restriction_for_jobs && isnum(user.client.player_age)) + if(get_config_value(/decl/config/num/use_age_restriction_for_jobs) && isnum(user.client.player_age)) if(user.client.player_age <= 3) - to_chat(user, " Your account is not old enough to play as a maintenance drone.") + to_chat(user, SPAN_WARNING("Your account is not old enough to play as a maintenance drone.")) return if(!user.MayRespawn(1, DRONE_SPAWN_DELAY)) @@ -119,7 +139,7 @@ all_fabricators[DF.fabricator_tag] = DF if(!all_fabricators.len) - to_chat(user, "There are no available drone spawn points, sorry.") + to_chat(user, SPAN_WARNING("There are no available drone spawn points, sorry.")) return var/choice = input(user,"Which fabricator do you wish to use?") as null|anything in all_fabricators @@ -133,4 +153,4 @@ if(drone) drone.status_flags |= NO_ANTAG return 1 - return \ No newline at end of file + return diff --git a/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm b/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm index f27295f2de64..f3c92813e3bc 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_remote_control.dm @@ -5,19 +5,19 @@ var/mob/living/silicon/ai/controlling_ai var/obj/item/radio/drone_silicon_radio -/mob/living/silicon/robot/drone/attack_ai(var/mob/living/silicon/ai/user) +/mob/living/silicon/robot/drone/attack_ai(mob/living/silicon/ai/user) - if(!istype(user) || controlling_ai || !config.allow_drone_spawn) + if(!istype(user) || controlling_ai || !get_config_value(/decl/config/toggle/on/allow_drone_spawn)) return - if(stat != 2 || client || key) - to_chat(user, "You cannot take control of an autonomous, active drone.") + if(stat != DEAD || client || key) + to_chat(user, SPAN_WARNING("You cannot take control of an autonomous, active drone.")) return - if(health < -35 || emagged) - to_chat(user, "WARNING: connection timed out.") + if(current_health < -(get_max_health()) || emagged) + to_chat(user, SPAN_WARNING("WARNING: connection timed out.")) return - + assume_control(user) /mob/living/silicon/robot/drone/proc/assume_control(var/mob/living/silicon/ai/user) @@ -30,13 +30,13 @@ //give controlled drone access to AI radio drone_silicon_radio = silicon_radio silicon_radio = new /obj/item/radio/headset/heads/ai_integrated(src) - //silicon_radio.recalculateChannels() add_language(/decl/language/binary/drone, 1) add_language(/decl/language/binary, 1) + add_language(/decl/language/machine, 1) default_language = controlling_ai.default_language - stat = CONSCIOUS + set_stat(CONSCIOUS) if(user.mind) user.mind.transfer_to(src) else @@ -44,9 +44,9 @@ updatename() to_chat(src, "You have shunted your primary control loop into \a [initial(name)]. Use the Release Control verb to return to your core.") -/obj/machinery/drone_fabricator/attack_ai(var/mob/living/silicon/ai/user) +/obj/machinery/drone_fabricator/attack_ai(mob/living/silicon/ai/user) - if(!istype(user) || user.controlling_drone || !config.allow_drone_spawn) + if(!istype(user) || user.controlling_drone || !get_config_value(/decl/config/toggle/on/allow_drone_spawn)) return if(stat & NOPOWER) @@ -61,7 +61,7 @@ to_chat(user, "\The [src] is not ready to produce a new drone.") return - if(count_drones() >= config.max_maint_drones) + if(count_drones() >= get_config_value(/decl/config/num/max_maint_drones)) to_chat(user, "The drone control subsystems are tasked to capacity; they cannot support any more drones.") return @@ -70,19 +70,15 @@ /mob/living/silicon/robot/drone/death(gibbed) - if(controlling_ai) - release_ai_control("WARNING: remote system failure. Connection timed out.") - drone_silicon_radio = null - . = ..(gibbed) + . = ..() + if(.) + if(controlling_ai) + release_ai_control("WARNING: remote system failure. Connection timed out.") + drone_silicon_radio = null /mob/living/silicon/ai/death(gibbed) - if(controlling_drone) - controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") - . = ..(gibbed) - -/mob/living/silicon/ai/Life() . = ..() - if(controlling_drone && stat != CONSCIOUS) + if(. && controlling_drone) controlling_drone.release_ai_control("WARNING: Primary control loop failure. Session terminated.") /mob/living/silicon/robot/drone/proc/release_ai_control_verb() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm index 6bf18ff1a92a..e4d40ac20dfe 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_say.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm @@ -10,15 +10,18 @@ if (stat == DEAD) return say_dead(message) - if(copytext(message,1,2) == "*") + if(findlasttextEx(message, get_prefix_key(/decl/prefix/custom_emote)) == 1) return emote(copytext(message,2)) + if(findlasttextEx(message, get_prefix_key(/decl/prefix/visible_emote)) == 1) + return custom_emote(1, copytext(message,2)) + if(copytext(message,1,2) == ";") - var/decl/language/L = decls_repository.get_decl(/decl/language/binary/drone) + var/decl/language/L = GET_DECL(/decl/language/binary/drone) if(istype(L)) return L.broadcast(src,trim(copytext(message,2))) - //Must be concious to speak + //Must be conscious to speak if (stat) return 0 @@ -29,10 +32,10 @@ if(D.client && D.local_transmit) to_chat(D, "[src] transmits, \"[message]\"") - for (var/mob/M in GLOB.player_list) - if (istype(M, /mob/new_player)) + for (var/mob/M in global.player_list) + if (isnewplayer(M)) continue - else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) + else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == PREF_ALL_SPEECH) if(M.client) to_chat(M, "[src] transmits, \"[message]\"") return 1 return ..(message, 0) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 0b8c1bff1354..6fb6983f9f25 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,43 +1,38 @@ -/mob/living/silicon/robot/examine(mob/user, distance) - var/custom_infix = custom_name ? ", [modtype] [braintype]" : "" - . = ..(user, distance, infix = custom_infix) - - var/msg = "" - msg += "" - if (src.getBruteLoss()) - if (src.getBruteLoss() < 75) - msg += "It looks slightly dented.\n" - else - msg += "It looks severely dented!\n" - if (src.getFireLoss()) - if (src.getFireLoss() < 75) - msg += "It looks slightly charred.\n" - else - msg += "It looks severely burnt and heat-warped!\n" - msg += "" +/mob/living/silicon/robot/examined_by(mob/user, distance, infix, suffix) + . = ..() + user?.showLaws(src) +/mob/living/silicon/robot/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + infix = custom_name ? ", [modtype] [braintype]" : "" + . = ..() + var/brute_damage = get_damage(BRUTE) + if (brute_damage >= 75) + . += SPAN_WARNING("It looks severely dented!") + else if(brute_damage) + . += SPAN_WARNING("It looks slightly dented.") + var/burn_damage = get_damage(BURN) + if (burn_damage >= 75) + . += SPAN_WARNING("It looks severely burnt and heat-warped!") + else if(burn_damage) + . += SPAN_WARNING("It looks slightly charred.") if(opened) - msg += "Its cover is open and the power cell is [cell ? "installed" : "missing"].\n" + . += SPAN_WARNING("Its cover is open and the power cell is [cell ? "installed" : "missing"].") else - msg += "Its cover is closed.\n" - + . += "Its cover is closed." if(!has_power) - msg += "It appears to be running on backup power.\n" - - switch(src.stat) + . += SPAN_WARNING("It appears to be running on backup power.") + switch(stat) if(CONSCIOUS) - if(!src.client) msg += "It appears to be in stand-by mode.\n" //afk - if(UNCONSCIOUS) msg += "It doesn't seem to be responding.\n" - if(DEAD) msg += "It looks completely unsalvageable.\n" - msg += "*---------*" - - if(print_flavor_text()) msg += "\n[print_flavor_text()]\n" - + if(!client) + . += "It appears to be in stand-by mode." //afk + if(UNCONSCIOUS) + . += SPAN_WARNING("It doesn't seem to be responding.") + if(DEAD) + . += "It looks completely unsalvageable." + . += "*---------*" + if(print_flavor_text()) + . += "[print_flavor_text()]" if (pose) if( findtext(pose,".",length(pose)) == 0 && findtext(pose,"!",length(pose)) == 0 && findtext(pose,"?",length(pose)) == 0 ) pose = addtext(pose,".") //Makes sure all emotes end with a period. - msg += "\nIt [pose]" - - to_chat(user, msg) - user.showLaws(src) - return + . += "It [pose]" diff --git a/code/modules/mob/living/silicon/robot/flying/flying.dm b/code/modules/mob/living/silicon/robot/flying/flying.dm index f5b9db04723a..7733ed989851 100644 --- a/code/modules/mob/living/silicon/robot/flying/flying.dm +++ b/code/modules/mob/living/silicon/robot/flying/flying.dm @@ -1,7 +1,6 @@ /mob/living/silicon/robot/flying - desc = "A utility robot with an anti-gravity hover unit and a lightweight frame." - icon = 'icons/mob/robots_flying.dmi' - icon_state = "drone-standard" + desc = "A utility robot with an antigravity hover unit and a lightweight frame." + icon = 'icons/mob/robots/flying/flying.dmi' module_category = ROBOT_MODULE_TYPE_FLYING dismantle_type = /obj/item/robot_parts/robot_suit/flyer speed = -1 // nyoom @@ -22,7 +21,7 @@ components["comms"] = new/datum/robot_component/binary_communication(src) components["armour"] = new/datum/robot_component/armour/light(src) -/mob/living/silicon/robot/flying/Life() +/mob/living/silicon/robot/flying/handle_regular_status_updates() . = ..() if(incapacitated() || !is_component_functioning("actuator")) stop_flying() @@ -32,23 +31,23 @@ /mob/living/silicon/robot/flying/proc/start_flying() pass_flags |= PASS_FLAG_TABLE default_pixel_y = 0 - make_floating(10) + start_floating() /mob/living/silicon/robot/flying/proc/stop_flying() pass_flags &= ~PASS_FLAG_TABLE default_pixel_y = -8 stop_floating() -/mob/living/silicon/robot/flying/death() +/mob/living/silicon/robot/flying/death(gibbed) . = ..() - if(!QDELETED(src) && stat == DEAD) + if(. && !gibbed) stop_flying() -/mob/living/silicon/robot/flying/Process_Spacemove() - return (pass_flags & PASS_FLAG_TABLE) || ..() +/mob/living/silicon/robot/flying/is_space_movement_permitted(allow_movement = FALSE) + return (pass_flags & PASS_FLAG_TABLE) ? SPACE_MOVE_PERMITTED : ..() -/mob/living/silicon/robot/flying/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) - return !Process_Spacemove() +/mob/living/silicon/robot/flying/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + return is_space_movement_permitted() == SPACE_MOVE_FORBIDDEN /mob/living/silicon/robot/flying/can_overcome_gravity() - return Process_Spacemove() + return is_space_movement_permitted() != SPACE_MOVE_FORBIDDEN diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying.dm b/code/modules/mob/living/silicon/robot/flying/module_flying.dm index 5cc0ee8c6ca0..68e682d02e02 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying.dm @@ -1,3 +1,6 @@ /obj/item/robot_module/flying module_category = ROBOT_MODULE_TYPE_FLYING can_be_pushed = TRUE + has_nonslip_feet = TRUE + has_magnetic_feet = TRUE + diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying_cultivator.dm b/code/modules/mob/living/silicon/robot/flying/module_flying_cultivator.dm index c7b3c790cfa4..a8773d85d500 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying_cultivator.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying_cultivator.dm @@ -5,17 +5,17 @@ "Science" = TRUE, "Service" = TRUE ) - sprites = list("Drone" = "drone-hydro") + module_sprites = list("Drone" = 'icons/mob/robots/flying/flying_hydro.dmi') equipment = list( - /obj/item/storage/plants, + /obj/item/plant_satchel, /obj/item/wirecutters/clippers, - /obj/item/minihoe/unbreakable, - /obj/item/hatchet/unbreakable, + /obj/item/tool/hoe/mini/unbreakable, + /obj/item/tool/axe/hatchet/unbreakable, /obj/item/chems/glass/bucket, - /obj/item/scalpel/laser1, + /obj/item/scalpel/laser, /obj/item/circular_saw, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/gripper/cultivator, /obj/item/scanner/plant, /obj/item/robot_harvester diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying_emergency.dm b/code/modules/mob/living/silicon/robot/flying/module_flying_emergency.dm index ffe611216135..9046c5549b4d 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying_emergency.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying_emergency.dm @@ -2,22 +2,23 @@ name = "emergency response drone module" display_name = "Emergency Response" channels = list("Medical" = TRUE) - networks = list(NETWORK_MEDICAL) + camera_channels = list(CAMERA_CHANNEL_MEDICAL) software = list( /datum/computer_file/program/suit_sensors ) - sprites = list( - "Drone" = "drone-medical", - "Eyebot" = "eyebot-medical" + module_sprites = list( + "Drone" = 'icons/mob/robots/flying/flying_medical.dmi', + "Eyebot" = 'icons/mob/robots/flying/eyebot_medical.dmi' ) equipment = list( /obj/item/flash, /obj/item/borg/sight/hud/med, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/scanner/reagent/adv, /obj/item/chems/borghypo/crisis, - /obj/item/extinguisher/mini, - /obj/item/taperoll/medical, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/stack/tape_roll/barricade_tape/medical, /obj/item/inflatable_dispenser/robot, /obj/item/weldingtool/mini, /obj/item/screwdriver, @@ -26,7 +27,7 @@ /obj/item/wirecutters, /obj/item/multitool, /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, + /obj/item/stack/medical/bandage, /obj/item/stack/medical/splint ) synths = list(/datum/matter_synth/medicine = 15000) @@ -42,14 +43,14 @@ /obj/item/robot_module/flying/emergency/finalize_emag() . = ..() - emag.reagents.add_reagent(/decl/material/liquid/acid/polyacid, 250) + emag.add_to_reagents(/decl/material/liquid/acid/polyacid, 250) emag.SetName("Polyacid spray") /obj/item/robot_module/flying/emergency/finalize_equipment() . = ..() for(var/thing in list( /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, + /obj/item/stack/medical/bandage, /obj/item/stack/medical/splint )) var/obj/item/stack/medical/stack = locate(thing) in equipment @@ -61,16 +62,16 @@ var/datum/matter_synth/medicine/medicine = locate() in synths for(var/thing in list( /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, + /obj/item/stack/medical/bandage, /obj/item/stack/medical/splint )) var/obj/item/stack/medical/stack = locate(thing) in equipment stack.synths = list(medicine) -/obj/item/robot_module/flying/emergency/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/flying/emergency/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) var/obj/item/chems/spray/PS = emag - if(PS && PS.reagents.total_volume < PS.volume) - var/adding = min(PS.volume-PS.reagents.total_volume, 2*amount) + if(PS && REAGENT_TOTAL_VOLUME(PS.reagents) < REAGENT_MAXIMUM_VOLUME(PS.reagents)) + var/adding = min(REAGENT_MAXIMUM_VOLUME(PS.reagents)-REAGENT_TOTAL_VOLUME(PS.reagents), 2*amount) if(adding > 0) - PS.reagents.add_reagent(/decl/material/liquid/acid/polyacid, adding) + PS.add_to_reagents(/decl/material/liquid/acid/polyacid, adding) ..() diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying_filing.dm b/code/modules/mob/living/silicon/robot/flying/module_flying_filing.dm index 9b8908e58852..b98dc774e3dc 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying_filing.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying_filing.dm @@ -5,7 +5,7 @@ "Service" = TRUE, "Supply" = TRUE ) - sprites = list("Drone" = "drone-service") + module_sprites = list("Drone" = 'icons/mob/robots/flying/flying_service.dmi') equipment = list( /obj/item/flash, /obj/item/pen/robopen, diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying_forensics.dm b/code/modules/mob/living/silicon/robot/flying/module_flying_forensics.dm index 35b2142ff3c3..1ba23a2809c1 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying_forensics.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying_forensics.dm @@ -2,25 +2,25 @@ name = "forensic drone module" display_name = "Forensics" channels = list("Security" = TRUE) - networks = list(NETWORK_SECURITY) + camera_channels = list(CAMERA_CHANNEL_SECURITY) software = list( /datum/computer_file/program/suit_sensors, /datum/computer_file/program/digitalwarrant ) - sprites = list( - "Drone" = "drone-sec", - "Eyebot" = "eyebot-security" + module_sprites = list( + "Drone" = 'icons/mob/robots/flying/flying_security.dmi', + "Eyebot" = 'icons/mob/robots/flying/eyebot_security.dmi' ) equipment = list( /obj/item/forensics/sample_kit/swabs, - /obj/item/storage/evidence, + /obj/item/evidence, /obj/item/forensics/sample_kit, /obj/item/forensics/sample_kit/powder, /obj/item/gripper/clerical, /obj/item/flash, /obj/item/borg/sight/hud/sec, - /obj/item/taperoll/police, - /obj/item/scalpel/laser1, + /obj/item/stack/tape_roll/barricade_tape/police, + /obj/item/scalpel/laser, /obj/item/scanner/autopsy, /obj/item/chems/spray/luminol, /obj/item/uv_light, @@ -32,16 +32,17 @@ SKILL_COMPUTER = SKILL_EXPERT, SKILL_FORENSICS = SKILL_PROF, SKILL_WEAPONS = SKILL_EXPERT, - SKILL_CONSTRUCTION = SKILL_ADEPT + SKILL_CONSTRUCTION = SKILL_ADEPT, + SKILL_ANATOMY = SKILL_ADEPT ) -/obj/item/robot_module/flying/forensics/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/flying/forensics/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) var/obj/item/chems/spray/luminol/luminol = locate() in equipment if(!luminol) luminol = new(src) equipment += luminol - if(luminol.reagents.total_volume < luminol.volume) - var/adding = min(luminol.volume-luminol.reagents.total_volume, 2*amount) + if(REAGENT_TOTAL_VOLUME(luminol.reagents) < REAGENT_MAXIMUM_VOLUME(luminol.reagents)) + var/adding = min(REAGENT_MAXIMUM_VOLUME(luminol.reagents)-REAGENT_TOTAL_VOLUME(luminol.reagents), 2*amount) if(adding > 0) - luminol.reagents.add_reagent(/decl/material/liquid/luminol, adding) + luminol.add_to_reagents(/decl/material/liquid/luminol, adding) ..() diff --git a/code/modules/mob/living/silicon/robot/flying/module_flying_repair.dm b/code/modules/mob/living/silicon/robot/flying/module_flying_repair.dm index cd11117210f2..3c6f36ea20c2 100644 --- a/code/modules/mob/living/silicon/robot/flying/module_flying_repair.dm +++ b/code/modules/mob/living/silicon/robot/flying/module_flying_repair.dm @@ -2,18 +2,17 @@ name = "repair drone module" display_name = "Repair" channels = list ("Engineering" = TRUE) - networks = list(NETWORK_ENGINEERING) + camera_channels = list(CAMERA_CHANNEL_ENGINEERING) software = list( - /datum/computer_file/program/power_monitor, - /datum/computer_file/program/supermatter_monitor + /datum/computer_file/program/power_monitor ) - sprites = list( - "Drone" = "drone-engineer", - "Eyebot" = "eyebot-engineering" + module_sprites = list( + "Drone" = 'icons/mob/robots/flying/flying_engineering.dmi', + "Eyebot" = 'icons/mob/robots/flying/eyebot_engineering.dmi' ) equipment = list( /obj/item/borg/sight/meson, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/weldingtool/largetank, /obj/item/screwdriver, /obj/item/wrench, @@ -23,29 +22,30 @@ /obj/item/t_scanner, /obj/item/scanner/gas, /obj/item/geiger, - /obj/item/taperoll/engineering, - /obj/item/taperoll/atmos, + /obj/item/stack/tape_roll/barricade_tape/engineering, + /obj/item/stack/tape_roll/barricade_tape/atmos, /obj/item/gripper, /obj/item/gripper/no_use/loader, /obj/item/lightreplacer, - /obj/item/pipe_painter, - /obj/item/floor_painter, + /obj/item/paint_sprayer, /obj/item/inflatable_dispenser/robot, /obj/item/inducer/borg, /obj/item/stack/material/cyborg/steel, /obj/item/stack/material/cyborg/aluminium, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass, /obj/item/stack/material/cyborg/glass/reinforced, + /obj/item/stack/material/cyborg/fiberglass, /obj/item/stack/cable_coil/cyborg, /obj/item/stack/material/cyborg/plasteel, - /obj/item/plunger/robot + /obj/item/plunger/unbreakable ) synths = list( - /datum/matter_synth/metal = 30000, - /datum/matter_synth/glass = 20000, - /datum/matter_synth/plasteel = 10000, + /datum/matter_synth/metal = 30000, + /datum/matter_synth/glass = 20000, + /datum/matter_synth/plasteel = 10000, /datum/matter_synth/wire ) emag = /obj/item/baton/robot/electrified_arm @@ -59,16 +59,17 @@ /obj/item/robot_module/flying/repair/finalize_synths() . = ..() - var/datum/matter_synth/metal/metal = locate() in synths - var/datum/matter_synth/glass/glass = locate() in synths - var/datum/matter_synth/plasteel/plasteel = locate() in synths - var/datum/matter_synth/wire/wire = locate() in synths + var/datum/matter_synth/metal/metal = locate() in synths + var/datum/matter_synth/glass/glass = locate() in synths + var/datum/matter_synth/plasteel/plasteel = locate() in synths + var/datum/matter_synth/wire/wire = locate() in synths for(var/thing in list( /obj/item/stack/material/cyborg/steel, /obj/item/stack/material/cyborg/aluminium, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass/reinforced )) var/obj/item/stack/stack = locate(thing) in equipment @@ -76,7 +77,8 @@ for(var/thing in list( /obj/item/stack/material/cyborg/glass/reinforced, - /obj/item/stack/material/cyborg/glass + /obj/item/stack/material/cyborg/glass, + /obj/item/stack/material/cyborg/fiberglass )) var/obj/item/stack/stack = locate(thing) in equipment LAZYDISTINCTADD(stack.synths, glass) @@ -88,8 +90,8 @@ PL.synths = list(plasteel) . = ..() -/obj/item/robot_module/flying/repair/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/flying/repair/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) var/obj/item/lightreplacer/LR = locate() in equipment if(LR) - LR.Charge(R, amount) + LR.Charge(robot, amount) ..() diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 59147f0a5a01..a7e2e6ff9d65 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -1,254 +1,21 @@ -//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting stuff manually -//as they handle all relevant stuff like adding it to the player's screen and such - -//Returns the thing in our active hand (whatever is in our active module-slot, in this case) -/mob/living/silicon/robot/get_active_hand() - return module_active - -/*-------TODOOOOOOOOOO--------*/ - -//Verbs used by hotkeys. -/mob/living/silicon/robot/verb/cmd_unequip_module() - set name = "unequip-module" - set hidden = 1 - uneq_active() - -/mob/living/silicon/robot/verb/cmd_toggle_module(module as num) - set name = "toggle-module" - set hidden = 1 - toggle_module(module) - -/mob/living/silicon/robot/proc/uneq_active() - if(isnull(module_active)) - return - if(module_state_1 == module_active) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode &= ~module_state_1:sight_mode - if (client) - client.screen -= module_state_1 - module_state_1.forceMove(module) - module_active = null - module_state_1 = null - inv1.icon_state = "inv1" - else if(module_state_2 == module_active) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode &= ~module_state_2:sight_mode - if (client) - client.screen -= module_state_2 - module_state_2.forceMove(module) - module_active = null - module_state_2 = null - inv2.icon_state = "inv2" - else if(module_state_3 == module_active) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode &= ~module_state_3:sight_mode - if (client) - client.screen -= module_state_3 - module_state_3.forceMove(module) - module_active = null - module_state_3 = null - inv3.icon_state = "inv3" - update_icon() - hud_used.update_robot_modules_display() - -/mob/living/silicon/robot/proc/uneq_all() - module_active = null - - if(module_state_1) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode &= ~module_state_1:sight_mode - if (client) - client.screen -= module_state_1 - module_state_1.forceMove(module) - module_state_1 = null - inv1.icon_state = "inv1" - if(module_state_2) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode &= ~module_state_2:sight_mode - if (client) - client.screen -= module_state_2 - module_state_2.forceMove(module) - module_state_2 = null - inv2.icon_state = "inv2" - if(module_state_3) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode &= ~module_state_3:sight_mode - if (client) - client.screen -= module_state_3 - module_state_3.forceMove(module) - module_state_3 = null - inv3.icon_state = "inv3" - update_icon() - hud_used.update_robot_modules_display() - -/mob/living/silicon/robot/proc/activated(obj/item/O) - if(module_state_1 == O) - return 1 - else if(module_state_2 == O) - return 1 - else if(module_state_3 == O) - return 1 - else - return 0 - -//Helper procs for cyborg modules on the UI. -//These are hackish but they help clean up code elsewhere. - -//module_selected(module) - Checks whether the module slot specified by "module" is currently selected. -/mob/living/silicon/robot/proc/module_selected(var/module) //Module is 1-3 - return module == get_selected_module() - -//module_active(module) - Checks whether there is a module active in the slot specified by "module". -/mob/living/silicon/robot/proc/module_active(var/module) //Module is 1-3 - if(module < 1 || module > 3) return 0 - - switch(module) - if(1) - if(module_state_1) - return 1 - if(2) - if(module_state_2) - return 1 - if(3) - if(module_state_3) - return 1 - return 0 - -//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected. -/mob/living/silicon/robot/proc/get_selected_module() - if(module_state_1 && module_active == module_state_1) - return 1 - else if(module_state_2 && module_active == module_state_2) - return 2 - else if(module_state_3 && module_active == module_state_3) - return 3 - - return 0 - -//select_module(module) - Selects the module slot specified by "module" -/mob/living/silicon/robot/proc/select_module(var/module) //Module is 1-3 - if(module < 1 || module > 3) return - - if(!module_active(module)) return - - switch(module) - if(1) - if(module_active != module_state_1) - inv1.icon_state = "inv1 +a" - inv2.icon_state = "inv2" - inv3.icon_state = "inv3" - module_active = module_state_1 - return - if(2) - if(module_active != module_state_2) - inv1.icon_state = "inv1" - inv2.icon_state = "inv2 +a" - inv3.icon_state = "inv3" - module_active = module_state_2 - return - if(3) - if(module_active != module_state_3) - inv1.icon_state = "inv1" - inv2.icon_state = "inv2" - inv3.icon_state = "inv3 +a" - module_active = module_state_3 - return - return - -//deselect_module(module) - Deselects the module slot specified by "module" -/mob/living/silicon/robot/proc/deselect_module(var/module) //Module is 1-3 - if(module < 1 || module > 3) return - - switch(module) - if(1) - if(module_active == module_state_1) - inv1.icon_state = "inv1" - module_active = null - return - if(2) - if(module_active == module_state_2) - inv2.icon_state = "inv2" - module_active = null - return - if(3) - if(module_active == module_state_3) - inv3.icon_state = "inv3" - module_active = null - return - return - -//toggle_module(module) - Toggles the selection of the module slot specified by "module". -/mob/living/silicon/robot/proc/toggle_module(var/module) //Module is 1-3 - if(module < 1 || module > 3) return - - if(module_selected(module)) - deselect_module(module) - else - if(module_active(module)) - select_module(module) - else - deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module. - return - -//cycle_modules() - Cycles through the list of selected modules. -/mob/living/silicon/robot/proc/cycle_modules() - var/slot_start = get_selected_module() - if(slot_start) deselect_module(slot_start) //Only deselect if we have a selected slot. - - var/slot_num - if(slot_start == 0) - slot_num = 1 - slot_start = 2 - else - slot_num = slot_start + 1 - - while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up. - if(module_active(slot_num)) - select_module(slot_num) - return - slot_num++ - if(slot_num > 3) slot_num = 1 //Wrap around. - - return - -/mob/living/silicon/robot/proc/activate_module(var/obj/item/O) - if(!(locate(O) in module.equipment) && O != src.module.emag) - return - if(activated(O)) - to_chat(src, "Already activated") - return - if(!module_state_1) - module_state_1 = O - O.hud_layerise() - O.screen_loc = inv1.screen_loc - O.forceMove(src) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode |= module_state_1:sight_mode - else if(!module_state_2) - module_state_2 = O - O.hud_layerise() - O.screen_loc = inv2.screen_loc - O.forceMove(src) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode |= module_state_2:sight_mode - else if(!module_state_3) - module_state_3 = O - O.hud_layerise() - O.screen_loc = inv3.screen_loc - O.forceMove(src) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode |= module_state_3:sight_mode - else - to_chat(src, "You need to disable a module first!") - -/mob/living/silicon/robot/put_in_hands(var/obj/item/W) // No hands. - W.forceMove(get_turf(src)) - return 1 - -//Robots don't use inventory slots, so we need to override this. -/mob/living/silicon/robot/canUnEquip(obj/item/I) - if(!I) - return 1 - if((I in module) || (I in src)) //Includes all modules and installed components. - return I.canremove //Will be 0 for modules, but items held by grippers will also be checked here. - return 1 \ No newline at end of file +// Would be nice to use can_unequip_item() but it doesn't have a target param. +/mob/living/silicon/robot/try_unequip(obj/item/I, atom/target, play_dropsound) + if(!module || (target != module && (I in module.equipment))) + return FALSE + return ..() + +/mob/living/silicon/robot/drop_from_inventory(obj/item/dropping_item, atom/target, play_dropsound) + if(module && (dropping_item in module.equipment) && target != module) + return FALSE + . = ..() + if(!QDELETED(dropping_item) && module?.storage && (dropping_item in module.equipment)) + module.storage.handle_item_insertion(src, dropping_item) + +// Always try to redirect drops into our module. +/mob/living/silicon/robot/drop_item(var/atom/Target) + Target = module + return ..() + +// Overriding default drop arg. +/mob/living/silicon/robot/drop_held_items(drop_loc = module) + return ..() diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm index beaf6eea7a9e..991631baa850 100644 --- a/code/modules/mob/living/silicon/robot/laws.dm +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -14,40 +14,39 @@ if(lawupdate) if (connected_ai) if(connected_ai.stat || connected_ai.control_disabled) - to_chat(src, "AI signal lost, unable to sync laws.") + to_chat(src, SPAN_BOLD("AI signal lost, unable to sync laws.")) else - lawsync() photosync() - to_chat(src, "Laws synced with AI, be sure to note any changes.") - // TODO: Update to new antagonist system. - if(mind && mind.special_role == "traitor" && mind.original == src) - to_chat(src, "Remember, your AI does NOT share or know about your law 0.") + to_chat(src, SPAN_BOLD("Laws synced with AI, be sure to note any changes.")) + lawsync() else - to_chat(src, "No AI selected to sync laws with, disabling lawsync protocol.") - lawupdate = 0 + to_chat(src, SPAN_BOLD("No AI selected to sync laws with, disabling lawsync protocol.")) + lawupdate = FALSE to_chat(who, SPAN_BOLD("Obey the following laws.")) to_chat(who, SPAN_ITALIC("All laws have equal priority. Laws may override other laws if written specifically to do so. If laws conflict, break the least.")) laws.show_laws(who) - // TODO: Update to new antagonist system. - if (mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai) - to_chat(who, "Remember, [connected_ai.name] is technically your master, but your objective comes first.") - else if (connected_ai) + show_master(who) + +/mob/living/silicon/robot/proc/show_master(mob/who) + if (connected_ai) to_chat(who, "Remember, [connected_ai.name] is your master, other AIs can be ignored.") else if (emagged) to_chat(who, "Remember, you are not required to listen to the AI.") else to_chat(who, "Remember, you are not bound to any AI, you are not required to listen to them.") - /mob/living/silicon/robot/lawsync() laws_sanity_check() var/datum/ai_laws/master = connected_ai && lawupdate ? connected_ai.laws : null if (master) master.sync(src) - ..() - return + . = ..() + // if we aren't malfunctioning and we have a law 0, it's presumably shared + // if we are malfunctioning and we don't have a law 0, we don't need to worry about this + if(connected_ai && is_malfunctioning() && has_zeroth_law()) + to_chat(src, SPAN_BOLD("Remember, your AI does NOT share or know about your law 0.")) /mob/living/silicon/robot/proc/robot_checklaws() set category = "Silicon Commands" diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index d485fd66b22a..6dac7f4072c6 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -1,37 +1,12 @@ -/mob/living/silicon/robot/Life() - set invisibility = 0 - set background = 1 - - if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) - return - - src.blinded = null - - //Status updates, death etc. - clamp_values() - handle_regular_status_updates() - handle_actions() - - if(client) - handle_regular_hud_updates() - update_items() - if (src.stat != DEAD) //still using power - use_power() - process_killswitch() - process_locks() - process_queued_alarms() - UpdateLyingBuckledAndVerbStatus() - -/mob/living/silicon/robot/proc/clamp_values() - -// SetStunned(min(stunned, 30)) - SetParalysis(min(paralysis, 30)) -// SetWeakened(min(weakened, 20)) - sleeping = 0 - adjustBruteLoss(0) - adjustToxLoss(0) - adjustOxyLoss(0) - adjustFireLoss(0) +/mob/living/silicon/robot/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE + use_power() + process_killswitch() + process_locks() + process_queued_alarms() + process_os() /mob/living/silicon/robot/proc/use_power() used_power_this_tick = 0 @@ -40,12 +15,10 @@ C.update_power_state() if ( cell && is_component_functioning("power cell") && src.cell.charge > 0 ) - if(src.module_state_1) - cell_use_power(50) // 50W load for every enabled tool TODO: tool-specific loads - if(src.module_state_2) - cell_use_power(50) - if(src.module_state_3) - cell_use_power(50) + // 50W load for every enabled tool TODO: tool-specific loads + var/use_power = 50 * length(get_held_items()) + if(use_power) + cell_use_power(use_power) if(lights_on) if(intenselight) @@ -66,75 +39,38 @@ lights_on = 0 set_light(0) -/mob/living/silicon/robot/handle_regular_status_updates() +/mob/living/silicon/robot/should_be_dead() + return current_health < get_config_value(/decl/config/num/health_health_threshold_dead) - if(src.camera && !scrambledcodes) - if(src.stat == 2 || wires.IsIndexCut(BORG_WIRE_CAMERA)) - src.camera.set_status(0) +/mob/living/silicon/robot/handle_regular_status_updates() + SHOULD_CALL_PARENT(FALSE) + update_health() + + set_status_condition(STAT_PARA, min(GET_STATUS(src, STAT_PARA), 30)) + if(HAS_STATUS(src, STAT_ASLEEP)) + SET_STATUS_MAX(src, STAT_PARA, 3) + + if (stat != DEAD) //Alive. + // This previously used incapacitated(INCAPACITATION_DISRUPTED) but that was setting the robot to be permanently unconscious, which isn't ideal. + if(!has_power || incapacitated(INCAPACITATION_STUNNED) || HAS_STATUS(src, STAT_PARA)) + SET_STATUS_MAX(src, STAT_BLIND, 2) + set_stat(UNCONSCIOUS) else - src.camera.set_status(1) - - updatehealth() - - if(src.sleeping) - Paralyse(3) - src.sleeping-- - - if(src.resting) - Weaken(5) - - if(health < config.health_threshold_dead && src.stat != 2) //die only once - death() - - if (src.stat != DEAD) //Alive. - if (src.paralysis || src.stunned || src.weakened || !src.has_power) //Stunned etc. - src.set_stat(UNCONSCIOUS) - if (src.stunned > 0) - AdjustStunned(-1) - if (src.weakened > 0) - AdjustWeakened(-1) - if (src.paralysis > 0) - AdjustParalysis(-1) - src.blinded = 1 - else - src.blinded = 0 - - else //Not stunned. - src.set_stat(CONSCIOUS) - - handle_confused() + set_stat(CONSCIOUS) else //Dead. - src.blinded = 1 - src.set_stat(DEAD) - - if (src.stuttering) src.stuttering-- + cameranet.update_visibility(src, FALSE) + SET_STATUS_MAX(src, STAT_BLIND, 2) - if (src.eye_blind) - src.eye_blind-- - src.blinded = 1 + if(has_genetic_condition(GENE_COND_BLINDED)) + SET_STATUS_MAX(src, STAT_BLIND, 2) - if (src.ear_deaf > 0) src.ear_deaf-- - if (src.ear_damage < 25) - src.ear_damage -= 0.05 - src.ear_damage = max(src.ear_damage, 0) - - src.set_density(!src.lying) - - if ((src.sdisabilities & BLINDED)) - src.blinded = 1 - if ((src.sdisabilities & DEAFENED)) - src.ear_deaf = 1 - - if (src.eye_blurry > 0) - src.eye_blurry-- - src.eye_blurry = max(0, src.eye_blurry) - - handle_drugged() + if(has_genetic_condition(GENE_COND_DEAFENED)) + src.set_status_condition(STAT_DEAF, 1) //update the state of modules and components here - if (src.stat != CONSCIOUS) - uneq_all() + if (stat != CONSCIOUS) + drop_held_items() if(silicon_radio) if(!is_component_functioning("radio")) @@ -142,18 +78,18 @@ else silicon_radio.on = 1 - if(isnull(components["camera"]) || is_component_functioning("camera")) - src.blinded = 0 - else - src.blinded = 1 + if(!isnull(components["camera"]) && !is_component_functioning("camera")) + SET_STATUS_MAX(src, STAT_BLIND, 2) + cameranet.update_visibility(src, FALSE) return 1 /mob/living/silicon/robot/handle_regular_hud_updates() - ..() - + . = ..() + if(!.) + return var/obj/item/borg/sight/hud/hud = (locate(/obj/item/borg/sight/hud) in src) - if(hud && hud.hud) + if(hud?.hud) hud.hud.process_hud(src) else switch(src.sensor_mode) @@ -162,116 +98,19 @@ if (MED_HUD) process_med_hud(src,0,network = get_computer_network()) - if(length(get_active_grabs())) - ui_drop_grab.invisibility = 0 - ui_drop_grab.alpha = 255 - else - ui_drop_grab.invisibility = INVISIBILITY_MAXIMUM - ui_drop_grab.alpha = 0 - - if (src.healths) - if (src.stat != 2) - if(istype(src,/mob/living/silicon/robot/drone)) - switch(health) - if(35 to INFINITY) - src.healths.icon_state = "health0" - if(25 to 34) - src.healths.icon_state = "health1" - if(15 to 24) - src.healths.icon_state = "health2" - if(5 to 14) - src.healths.icon_state = "health3" - if(0 to 4) - src.healths.icon_state = "health4" - if(-35 to 0) - src.healths.icon_state = "health5" - else - src.healths.icon_state = "health6" - else - switch(health) - if(200 to INFINITY) - src.healths.icon_state = "health0" - if(150 to 200) - src.healths.icon_state = "health1" - if(100 to 150) - src.healths.icon_state = "health2" - if(50 to 100) - src.healths.icon_state = "health3" - if(0 to 50) - src.healths.icon_state = "health4" - if(config.health_threshold_dead to 0) - src.healths.icon_state = "health5" - else - src.healths.icon_state = "health6" - else - src.healths.icon_state = "health7" - - if (src.syndicate && src.client) - for(var/datum/mind/tra in GLOB.traitors.current_antagonists) - if(tra.current) - // TODO: Update to new antagonist system. - var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") - src.client.images += I - src.disconnect_from_ai() - if(src.mind) - // TODO: Update to new antagonist system. - if(!src.mind.special_role) - src.mind.special_role = "traitor" - GLOB.traitors.current_antagonists |= src.mind - - if (src.cells) - if (src.cell) - var/chargeNum = Clamp(ceil(cell.percent()/25), 0, 4) //0-100 maps to 0-4, but give it a paranoid clamp just in case. - src.cells.icon_state = "charge[chargeNum]" - else - src.cells.icon_state = "charge-empty" - - if(bodytemp) - switch(src.bodytemperature) //310.055 optimal body temp - if(335 to INFINITY) - src.bodytemp.icon_state = "temp2" - if(320 to 335) - src.bodytemp.icon_state = "temp1" - if(300 to 320) - src.bodytemp.icon_state = "temp0" - if(260 to 300) - src.bodytemp.icon_state = "temp-1" - else - src.bodytemp.icon_state = "temp-2" - - var/datum/gas_mixture/environment = loc?.return_air() - if(fire && environment) - switch(environment.temperature) - if(-INFINITY to T100C) - src.fire.icon_state = "fire0" - else - src.fire.icon_state = "fire1" - if(oxygen && environment) - var/datum/species/species = all_species[GLOB.using_map.default_species] - if(!species.breath_type || environment.gas[species.breath_type] >= species.breath_pressure) - src.oxygen.icon_state = "oxy0" - for(var/gas in species.poison_types) - if(environment.gas[gas]) - src.oxygen.icon_state = "oxy1" - break - else - src.oxygen.icon_state = "oxy1" - if(stat != DEAD) - if(blinded) + if(is_blind()) overlay_fullscreen("blind", /obj/screen/fullscreen/blind) else clear_fullscreen("blind") - set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) - set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) - set_fullscreen(drugged, "high", /obj/screen/fullscreen/high) - - return 1 + set_fullscreen(has_genetic_condition(GENE_COND_NEARSIGHTED), "impaired", /obj/screen/fullscreen/impaired, 1) + set_fullscreen(GET_STATUS(src, STAT_BLURRY), "blurry", /obj/screen/fullscreen/blurry) + set_fullscreen(GET_STATUS(src, STAT_DRUGGY), "high", /obj/screen/fullscreen/high) /mob/living/silicon/robot/handle_vision() ..() - if (src.stat == DEAD || (MUTATION_XRAY in mutations) || (src.sight_mode & BORGXRAY)) + if (src.stat == DEAD || has_genetic_condition(GENE_COND_XRAY) || (src.sight_mode & BORGXRAY)) set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) set_see_in_dark(8) set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) @@ -296,46 +135,31 @@ set_see_invisible(SEE_INVISIBLE_LIVING) // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness // has a "invisible" value of 15 - -/mob/living/silicon/robot/proc/update_items() - if (src.client) - src.client.screen -= src.contents - for(var/obj/I in src.contents) - if(I && !(istype(I,/obj/item/cell) || istype(I,/obj/item/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/mmi))) - src.client.screen += I - if(src.module_state_1) - src.module_state_1:screen_loc = ui_inv1 - if(src.module_state_2) - src.module_state_2:screen_loc = ui_inv2 - if(src.module_state_3) - src.module_state_3:screen_loc = ui_inv3 - update_icon() - /mob/living/silicon/robot/proc/process_killswitch() if(killswitch) killswitch_time -- if(killswitch_time <= 0) - if(src.client) - to_chat(src, "Killswitch Activated") + to_chat(src, SPAN_DANGER("Killswitch activated.")) killswitch = 0 spawn(5) gib() - /mob/living/silicon/robot/proc/process_locks() if(weapon_lock) - uneq_all() + drop_held_items() weaponlock_time -- if(weaponlock_time <= 0) - if(src.client) - to_chat(src, "Weapon Lock Timed Out!") + to_chat(src, SPAN_DANGER("Weapon lock timed out!")) weapon_lock = 0 weaponlock_time = 120 /mob/living/silicon/robot/update_fire() overlays -= image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing") - if(on_fire) + if(is_on_fire()) overlays += image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing") -/mob/living/silicon/robot/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them - IgniteMob() +//Silicons don't gain stacks from hotspots, but hotspots can ignite them +/mob/living/silicon/increase_fire_intensity(exposed_temperature) + return + +/mob/living/silicon/can_ignite() + return !is_on_fire() diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm index e04c1114dbf4..761f3e6d4508 100644 --- a/code/modules/mob/living/silicon/robot/login.dm +++ b/code/modules/mob/living/silicon/robot/login.dm @@ -1,15 +1,7 @@ /mob/living/silicon/robot/Login() ..() - regenerate_icons() - update_hud() - + update_icon() show_laws(0) - - winset(src, null, "mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#d3b5b5") - // Forces synths to select an icon relevant to their module - if(!icon_selected) - choose_icon(module_sprites) - - if(hands) - hands.icon_state = istype(module) ? lowertext(module.display_name) : "nomod" \ No newline at end of file + if(!icon_selected && module) + choose_icon(module.get_sprites_for(src)) diff --git a/code/modules/mob/living/silicon/robot/modules/_module.dm b/code/modules/mob/living/silicon/robot/modules/_module.dm index 22f828fb63c8..29f7b69c5f74 100644 --- a/code/modules/mob/living/silicon/robot/modules/_module.dm +++ b/code/modules/mob/living/silicon/robot/modules/_module.dm @@ -1,22 +1,41 @@ +/datum/storage/robot_module + storage_slots = 24 + // No real limits since mobs generally won't be able to freely interact with this storage. + max_w_class = ITEM_SIZE_GARGANTUAN + +/datum/storage/robot_module/can_be_inserted(obj/item/W, mob/user, stop_messages, click_params) + var/mob/living/silicon/robot/robot = user + return istype(robot) && (W in robot.module?.equipment) + +/obj/item/robot_module/get_stored_inventory() + . = ..() + var/mob/living/silicon/robot/robot = loc + if(LAZYLEN(.) && emag && (!istype(robot) || !robot.emagged)) + LAZYREMOVE(., emag) + /obj/item/robot_module name = "robot module" - icon = 'icons/obj/module.dmi' - icon_state = "std_mod" - item_state = "electronic" - w_class = ITEM_SIZE_NO_CONTAINER - obj_flags = OBJ_FLAG_CONDUCTIBLE + icon = 'icons/obj/modules/module_standard.dmi' + icon_state = ICON_STATE_WORLD + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_NO_STORAGE + is_spawnable_type = FALSE + storage = /datum/storage/robot_module + var/associated_department var/hide_on_manifest = 0 - var/channels = list() - var/networks = list() - var/languages = list( + var/list/channels = list() + var/list/camera_channels = list() + var/list/languages = list( /decl/language/human/common = TRUE, /decl/language/legal = TRUE, /decl/language/sign = FALSE - ) - var/sprites = list() + ) + var/list/module_sprites = list() var/can_be_pushed = 1 - var/no_slip = 0 + // Equivalent to shoes with ITEM_FLAG_NOSLIP + var/has_nonslip_feet = FALSE + // Equivalent to shoes with ITEM_FLAG_MAGNETIZED + var/has_magnetic_feet = FALSE var/obj/item/borg/upgrade/jetpack = null var/list/subsystems = list() var/list/obj/item/borg/upgrade/supported_upgrades = list() @@ -29,7 +48,7 @@ // Bookkeeping var/list/original_languages = list() - var/list/added_networks = list() + var/list/added_channels = list() // Gear lists/types. var/obj/item/emag @@ -39,36 +58,47 @@ var/list/skills = list() // Skills that this module grants. Other skills will remain at minimum levels. var/list/software = list() // Apps to preinstall on robot's inbiult computer -/obj/item/robot_module/Initialize() +// Override because storage is created very early. +/obj/item/robot_module/New(loc, material_key, reference_only = FALSE) + if(reference_only) + storage = null + ..(loc, material_key) + +/obj/item/robot_module/Initialize(ml, material_key, reference_only = FALSE) . = ..() - var/mob/living/silicon/robot/R = loc - if(!istype(R)) - return INITIALIZE_HINT_QDEL + if(reference_only) + return - R.module = src + var/mob/living/silicon/robot/robot = loc + if(!istype(robot)) + // Clear refs to avoid attempting to qdel a type in module Destroy(). + equipment = null + synths = null + emag = null + jetpack = null + return INITIALIZE_HINT_QDEL - grant_skills(R) - grant_software(R) - add_camera_networks(R) - add_languages(R) - add_subsystems(R) - apply_status_flags(R) + robot.module = src - if(R.silicon_radio) - R.silicon_radio.recalculateChannels() + grant_skills(robot) + grant_software(robot) + add_camera_channels(robot) + add_languages(robot) + add_subsystems(robot) + apply_status_flags(robot) - build_equipment(R) - build_emag(R) - build_synths(R) + build_equipment(robot) + build_emag(robot) + build_synths(robot) - finalize_equipment(R) - finalize_emag(R) - finalize_synths(R) + finalize_equipment(robot) + finalize_emag(robot) + finalize_synths(robot) - R.set_module_sprites(sprites) - R.choose_icon(R.module_sprites) + if(robot.client) + robot.choose_icon(get_sprites_for(robot)) /obj/item/robot_module/proc/build_equipment() var/list/created_equipment = list() @@ -84,8 +114,7 @@ equipment = created_equipment /obj/item/robot_module/proc/finalize_equipment() - for(var/obj/item/I in equipment) - I.canremove = FALSE + return /obj/item/robot_module/proc/build_synths() var/list/created_synths = list() @@ -111,30 +140,40 @@ /obj/item/robot_module/proc/finalize_emag() if(istype(emag)) emag.canremove = FALSE - else + else if(emag) log_debug("Invalid var type in [type] emag creation - [emag]") emag = null -/obj/item/robot_module/proc/Reset(var/mob/living/silicon/robot/R) - remove_camera_networks(R) - remove_languages(R) - remove_subsystems(R) - remove_status_flags(R) - reset_skills(R) - - if(R.silicon_radio) - R.silicon_radio.recalculateChannels() - R.choose_icon(R.set_module_sprites(list("Default" = initial(R.icon_state)))) +/obj/item/robot_module/proc/Reset(var/mob/living/silicon/robot/robot) + remove_camera_channels(robot) + remove_languages(robot) + remove_subsystems(robot) + remove_status_flags(robot) + reset_skills(robot) + robot.choose_icon(list("Basic" = initial(robot.icon))) + +/obj/item/robot_module/proc/get_sprites_for(var/mob/living/silicon/robot/robot) + . = module_sprites + if(robot.ckey) + for(var/datum/custom_icon/cicon as anything in SScustomitems.custom_icons_by_ckey[robot.ckey]) + if(cicon.category == display_name && lowertext(robot.real_name) == cicon.character_name) + for(var/state in cicon.ids_to_icons) + .[state] = cicon.ids_to_icons[state] /obj/item/robot_module/Destroy() - QDEL_NULL_LIST(equipment) + for(var/datum/thing in (equipment|synths)) + qdel(thing) + equipment = null + synths = null QDEL_NULL_LIST(synths) - QDEL_NULL(emag) - QDEL_NULL(jetpack) - var/mob/living/silicon/robot/R = loc - if(istype(R) && R.module == src) - R.module = null + if(istype(emag)) + QDEL_NULL(emag) + if(istype(jetpack)) + QDEL_NULL(jetpack) . = ..() + var/mob/living/silicon/robot/robot = loc + if(istype(robot) && robot.module == src) + robot.module = null /obj/item/robot_module/emp_act(severity) if(equipment) @@ -147,84 +186,90 @@ S.emp_act(severity) ..() -/obj/item/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) +/obj/item/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/robot, var/rate) var/obj/item/flash/F = locate() in equipment if(F) if(F.broken) F.broken = 0 F.times_used = 0 - F.icon_state = "flash" + F.update_icon() else if(F.times_used) F.times_used-- - if(!synths || !synths.len) + if(!LAZYLEN(synths)) return for(var/datum/matter_synth/T in synths) T.add_charge(T.recharge_rate * rate) -/obj/item/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) +/obj/item/robot_module/proc/add_languages(var/mob/living/silicon/robot/robot) // Stores the languages as they were before receiving the module, and whether they could be synthezized. - for(var/decl/language/language_datum in R.languages) - original_languages[language_datum] = (language_datum in R.speech_synthesizer_langs) + for(var/decl/language/language_datum in robot.languages) + original_languages[language_datum] = (language_datum in robot.speech_synthesizer_langs) for(var/language in languages) - R.add_language(language, languages[language]) + robot.add_language(language, languages[language]) -/obj/item/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R) +/obj/item/robot_module/proc/remove_languages(var/mob/living/silicon/robot/robot) // Clear all added languages, whether or not we originally had them. for(var/language in languages) - R.remove_language(language) + robot.remove_language(language) // Then add back all the original languages, and the relevant synthezising ability for(var/original_language in original_languages) var/decl/language/language_datum = original_language - R.add_language(language_datum.name, original_languages[original_language]) + robot.add_language(language_datum.type, original_languages[original_language]) original_languages.Cut() -/obj/item/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R) - if(R.camera && (NETWORK_ROBOTS in R.camera.network)) - for(var/network in networks) - if(!(network in R.camera.network)) - R.camera.add_network(network) - added_networks |= network - -/obj/item/robot_module/proc/remove_camera_networks(var/mob/living/silicon/robot/R) - if(R.camera) - R.camera.remove_networks(added_networks) - added_networks.Cut() - -/obj/item/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/R) +/obj/item/robot_module/proc/add_camera_channels(var/mob/living/silicon/robot/robot) + var/datum/extension/network_device/camera/robot/D = get_extension(robot, /datum/extension/network_device/camera) + if(D) + var/list/robot_channels = D.channels + if(CAMERA_CHANNEL_ROBOTS in robot_channels) + for(var/channel in camera_channels) + if(!(channel in robot_channels)) + D.add_channels(channel) + added_channels |= channel + +/obj/item/robot_module/proc/remove_camera_channels(var/mob/living/silicon/robot/robot) + var/datum/extension/network_device/camera/robot/D = get_extension(robot, /datum/extension/network_device/camera) + D.remove_channels(added_channels) + added_channels.Cut() + +/obj/item/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/robot) for(var/subsystem_type in subsystems) - R.init_subsystem(subsystem_type) + robot.init_subsystem(subsystem_type) -/obj/item/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/R) +/obj/item/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/robot) for(var/subsystem_type in subsystems) - R.remove_subsystem(subsystem_type) + robot.remove_subsystem(subsystem_type) -/obj/item/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/R) +/obj/item/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/robot) if(!can_be_pushed) - R.status_flags &= ~CANPUSH + robot.status_flags &= ~CANPUSH -/obj/item/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/R) +/obj/item/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/robot) if(!can_be_pushed) - R.status_flags |= CANPUSH + robot.status_flags |= CANPUSH /obj/item/robot_module/proc/handle_emagged() return -/obj/item/robot_module/proc/grant_skills(var/mob/living/silicon/robot/R) - reset_skills(R) // for safety +/obj/item/robot_module/proc/grant_skills(var/mob/living/silicon/robot/robot) + reset_skills(robot) // for safety var/list/skill_mod = list() for(var/skill_type in skills) skill_mod[skill_type] = skills[skill_type] - SKILL_MIN // the buff is additive, so normalize accordingly - R.buff_skill(skill_mod, buff_type = /datum/skill_buff/robot) + robot.buff_skill(skill_mod, buff_type = /datum/skill_buff/robot) -/obj/item/robot_module/proc/reset_skills(var/mob/living/silicon/robot/R) - for(var/datum/skill_buff/buff in R.fetch_buffs_of_type(/datum/skill_buff/robot)) +/obj/item/robot_module/proc/reset_skills(var/mob/living/silicon/robot/robot) + for(var/datum/skill_buff/buff in robot.fetch_buffs_of_type(/datum/skill_buff/robot)) buff.remove() -/obj/item/robot_module/proc/grant_software(var/mob/living/silicon/robot/R) - var/datum/extension/interactive/ntos/os = get_extension(R, /datum/extension/interactive/ntos) +/obj/item/robot_module/proc/grant_software(var/mob/living/silicon/robot/robot) + var/datum/extension/interactive/os/os = get_extension(robot, /datum/extension/interactive/os) if(os && os.has_component(PART_HDD)) var/obj/item/stock_parts/computer/hard_drive/disk = os.get_component(PART_HDD) for(var/T in software) - disk.store_file(new T(disk)) + disk.store_file(new T(disk), OS_PROGRAMS_DIR, TRUE) + +/obj/item/robot_module/proc/handle_turf(turf/target, mob/user) + return diff --git a/code/modules/mob/living/silicon/robot/modules/module_clerical.dm b/code/modules/mob/living/silicon/robot/modules/module_clerical.dm index fd40e584bd9c..0e76a2737495 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_clerical.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_clerical.dm @@ -17,32 +17,32 @@ /obj/item/robot_module/clerical/butler name = "service robot module" display_name = "Service" - sprites = list( - "Waitress" = "Service", - "Kent" = "toiletbot", - "Bro" = "Brobot", - "Rich" = "maximillion", - "Default" = "Service2" + module_sprites = list( + "Waitress" = 'icons/mob/robots/robot_service_old.dmi', + "Kent" = 'icons/mob/robots/robot_toiletbot.dmi', + "Bro" = 'icons/mob/robots/robot_service_bro.dmi', + "Rich" = 'icons/mob/robots/robot_maximillion.dmi', + "Default" = 'icons/mob/robots/robot_service.dmi' ) equipment = list( /obj/item/flash, /obj/item/gripper/service, /obj/item/chems/glass/bucket, - /obj/item/minihoe, - /obj/item/hatchet, + /obj/item/tool/hoe/mini, + /obj/item/tool/axe/hatchet, /obj/item/scanner/plant, - /obj/item/storage/plants, + /obj/item/plant_satchel, /obj/item/robot_harvester, - /obj/item/kitchen/rollingpin, + /obj/item/rollingpin, /obj/item/knife/kitchen, /obj/item/crowbar, /obj/item/rsf, /obj/item/chems/dropper/industrial, - /obj/item/flame/lighter/zippo, - /obj/item/storage/tray/robotray, + /obj/item/flame/fuelled/lighter/zippo, + /obj/item/plate/tray/robotray, /obj/item/chems/borghypo/service ) - emag = /obj/item/chems/food/drinks/bottle/small/beer + emag = /obj/item/chems/drinks/bottle/small/beer skills = list( SKILL_LITERACY = SKILL_ADEPT, SKILL_COMPUTER = SKILL_EXPERT, @@ -56,29 +56,29 @@ . = ..() var/obj/item/rsf/M = locate() in equipment M.stored_matter = 30 - var/obj/item/flame/lighter/zippo/L = locate() in equipment - L.lit = 1 + var/obj/item/flame/fuelled/lighter/zippo/L = locate() in equipment + L.lit = TRUE /obj/item/robot_module/clerical/butler/finalize_emag() . = ..() if(emag) - var/datum/reagents/R = emag.create_reagents(50) - R.add_reagent(/decl/material/liquid/paralytics, 10) - R.add_reagent(/decl/material/liquid/sedatives, 15) - R.add_reagent(/decl/material/liquid/ethanol/beer, 20) - R.add_reagent(/decl/material/solid/ice, 5) + var/datum/reagents/reagent = emag.create_or_update_reagents(50) + reagent.add_reagent(/decl/material/liquid/paralytics, 10) + reagent.add_reagent(/decl/material/liquid/sedatives, 15) + reagent.add_reagent(/decl/material/liquid/alcohol/beer, 20) + reagent.add_reagent(/decl/material/solid/ice, 5) emag.SetName("Mickey Finn's Special Brew") -/obj/item/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) ..() - var/obj/item/chems/food/condiment/enzyme/E = locate() in equipment - E.reagents.add_reagent(/decl/material/liquid/enzyme, 2 * amount) + var/obj/item/chems/condiment/enzyme/E = locate() in equipment + E.add_to_reagents(/decl/material/liquid/enzyme, 2 * amount) if(emag) - var/obj/item/chems/food/drinks/bottle/small/beer/B = emag - B.reagents.add_reagent(/decl/material/liquid/ethanol/beer, amount * 0.4) - B.reagents.add_reagent(/decl/material/solid/ice, amount * 0.1) - B.reagents.add_reagent(/decl/material/liquid/paralytics, amount * 0.2) - B.reagents.add_reagent(/decl/material/liquid/sedatives, amount * 0.3) + var/obj/item/chems/drinks/bottle/small/beer/B = emag + B.add_to_reagents(/decl/material/liquid/alcohol/beer, amount * 0.4) + B.add_to_reagents(/decl/material/solid/ice, amount * 0.1) + B.add_to_reagents(/decl/material/liquid/paralytics, amount * 0.2) + B.add_to_reagents(/decl/material/liquid/sedatives, amount * 0.3) /obj/item/robot_module/clerical/general name = "clerical robot module" @@ -87,12 +87,12 @@ "Service" = TRUE, "Supply" = TRUE ) - sprites = list( - "Waitress" = "Service", - "Kent" = "toiletbot", - "Bro" = "Brobot", - "Rich" = "maximillion", - "Default" = "Service2" + module_sprites = list( + "Waitress" = 'icons/mob/robots/robot_service_old.dmi', + "Kent" = 'icons/mob/robots/robot_toiletbot.dmi', + "Bro" = 'icons/mob/robots/robot_service_bro.dmi', + "Rich" = 'icons/mob/robots/robot_maximillion.dmi', + "Default" = 'icons/mob/robots/robot_service.dmi' ) equipment = list( /obj/item/flash, diff --git a/code/modules/mob/living/silicon/robot/modules/module_engineering.dm b/code/modules/mob/living/silicon/robot/modules/module_engineering.dm index 11e494082baf..65bd61bbd014 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_engineering.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_engineering.dm @@ -4,60 +4,61 @@ channels = list( "Engineering" = 1 ) - networks = list( - NETWORK_ENGINEERING + camera_channels = list( + CAMERA_CHANNEL_ENGINEERING ) software = list( - /datum/computer_file/program/power_monitor, - /datum/computer_file/program/supermatter_monitor + /datum/computer_file/program/power_monitor ) supported_upgrades = list( /obj/item/borg/upgrade/rcd ) - sprites = list( - "Basic" = "Engineering", - "Antique" = "engineerrobot", - "Landmate" = "landmate", - "Landmate - Treaded" = "engiborg+tread" + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_engineer_old.dmi', + "Antique" = 'icons/mob/robots/robot_engineer_old_alt.dmi', + "Landmate" = 'icons/mob/robots/robot_engineer.dmi', + "Landmate - Treaded" = 'icons/mob/robots/robot_engineer_treaded.dmi' ) - no_slip = 1 + has_nonslip_feet = TRUE + has_magnetic_feet = TRUE equipment = list( /obj/item/flash, /obj/item/borg/sight/meson, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/weldingtool/largetank, /obj/item/screwdriver, /obj/item/wrench, - /obj/item/crowbar, + /obj/item/crowbar/brace_jack, /obj/item/wirecutters, /obj/item/multitool, /obj/item/t_scanner, /obj/item/scanner/gas, /obj/item/geiger, - /obj/item/taperoll/engineering, - /obj/item/taperoll/atmos, + /obj/item/stack/tape_roll/barricade_tape/engineering, + /obj/item/stack/tape_roll/barricade_tape/atmos, /obj/item/gripper, /obj/item/gripper/no_use/loader, /obj/item/lightreplacer, - /obj/item/pipe_painter, - /obj/item/floor_painter, + /obj/item/paint_sprayer, /obj/item/inflatable_dispenser/robot, /obj/item/inducer/borg, - /obj/item/plunger/robot, + /obj/item/plunger/unbreakable, /obj/item/matter_decompiler, /obj/item/stack/material/cyborg/steel, /obj/item/stack/material/cyborg/aluminium, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass, /obj/item/stack/material/cyborg/glass/reinforced, + /obj/item/stack/material/cyborg/fiberglass, /obj/item/stack/cable_coil/cyborg, /obj/item/stack/material/cyborg/plasteel ) synths = list( - /datum/matter_synth/metal = 60000, - /datum/matter_synth/glass = 40000, - /datum/matter_synth/plasteel = 20000, + /datum/matter_synth/metal = 60000, + /datum/matter_synth/glass = 40000, + /datum/matter_synth/plasteel = 20000, /datum/matter_synth/wire ) emag = /obj/item/baton/robot/electrified_arm @@ -72,10 +73,10 @@ /obj/item/robot_module/engineering/finalize_synths() - var/datum/matter_synth/metal/metal = locate() in synths - var/datum/matter_synth/glass/glass = locate() in synths - var/datum/matter_synth/plasteel/plasteel = locate() in synths - var/datum/matter_synth/wire/wire = locate() in synths + var/datum/matter_synth/metal/metal = locate() in synths + var/datum/matter_synth/glass/glass = locate() in synths + var/datum/matter_synth/plasteel/plasteel = locate() in synths + var/datum/matter_synth/wire/wire = locate() in synths var/obj/item/matter_decompiler/MD = locate() in equipment MD.metal = metal @@ -86,6 +87,7 @@ /obj/item/stack/material/cyborg/aluminium, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass/reinforced )) var/obj/item/stack/stack = locate(thing) in equipment @@ -93,7 +95,8 @@ for(var/thing in list( /obj/item/stack/material/cyborg/glass/reinforced, - /obj/item/stack/material/cyborg/glass + /obj/item/stack/material/cyborg/glass, + /obj/item/stack/material/cyborg/fiberglass )) var/obj/item/stack/stack = locate(thing) in equipment LAZYDISTINCTADD(stack.synths, glass) @@ -104,7 +107,7 @@ var/obj/item/stack/material/cyborg/plasteel/PL = locate() in equipment PL.synths = list(plasteel) -/obj/item/robot_module/engineering/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/engineering/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) var/obj/item/lightreplacer/LR = locate() in equipment - LR.Charge(R, amount) + LR.Charge(robot, amount) ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/modules/module_illegal.dm b/code/modules/mob/living/silicon/robot/modules/module_illegal.dm index c10b9a27486f..6b0ab320b8ea 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_illegal.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_illegal.dm @@ -3,8 +3,8 @@ display_name = "Illegal" hide_on_manifest = 1 upgrade_locked = TRUE - sprites = list( - "Dread" = "securityrobot" + module_sprites = list( + "Dread" = 'icons/mob/robots/robot_security.dmi' ) equipment = list( /obj/item/flash, @@ -17,18 +17,17 @@ var/id /obj/item/robot_module/syndicate/Initialize() - for(var/decl/hierarchy/skill/skill in GLOB.skills) + for(var/decl/skill/skill in global.using_map.get_available_skills()) skills[skill.type] = SKILL_EXPERT . = ..() -/obj/item/robot_module/syndicate/build_equipment(var/mob/living/silicon/robot/R) +/obj/item/robot_module/syndicate/build_equipment(var/mob/living/silicon/robot/robot) . = ..() - id = R.idcard + id = robot.idcard equipment += id -/obj/item/robot_module/syndicate/finalize_equipment(var/mob/living/silicon/robot/R) - var/obj/item/tank/jetpack/carbondioxide/jetpack = locate() in equipment - R.internals = jetpack +/obj/item/robot_module/syndicate/finalize_equipment(var/mob/living/silicon/robot/robot) + robot.set_internals(locate(/obj/item/tank/jetpack/carbondioxide) in equipment) . = ..() /obj/item/robot_module/syndicate/Destroy() diff --git a/code/modules/mob/living/silicon/robot/modules/module_janitor.dm b/code/modules/mob/living/silicon/robot/modules/module_janitor.dm index 16092a00af07..b3c558956824 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_janitor.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_janitor.dm @@ -4,34 +4,38 @@ channels = list( "Service" = TRUE ) - sprites = list( - "Basic" = "JanBot2", - "Mopbot" = "janitorrobot", - "Mop Gear Rex" = "mopgearrex" + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_janbot.dmi', + "Mopbot" = 'icons/mob/robots/robot_janitor_old.dmi', + "Mop Gear Rex" = 'icons/mob/robots/robot_janitor.dmi' ) equipment = list( /obj/item/flash, /obj/item/soap, - /obj/item/storage/bag/trash, + /obj/item/bag/trash, /obj/item/mop/advanced, /obj/item/holosign_creator, /obj/item/lightreplacer, /obj/item/borg/sight/hud/jani, - /obj/item/plunger/robot, + /obj/item/plunger/unbreakable, /obj/item/crowbar, /obj/item/weldingtool ) emag = /obj/item/chems/spray + has_nonslip_feet = TRUE + +/obj/item/robot_module/janitor/handle_turf(turf/target, mob/user) + target.clean() /obj/item/robot_module/janitor/finalize_emag() . = ..() - emag.reagents.add_reagent(/decl/material/liquid/lube, 250) - emag.SetName("Lube spray") + emag.add_to_reagents(/decl/material/liquid/lube, 250) + emag.SetName("lubricant spray") -/obj/item/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) ..() var/obj/item/lightreplacer/LR = locate() in equipment - LR.Charge(R, amount) + LR.Charge(robot, amount) if(emag) var/obj/item/chems/spray/S = emag - S.reagents.add_reagent(/decl/material/liquid/lube, 20 * amount) + S.add_to_reagents(/decl/material/liquid/lube, 20 * amount) diff --git a/code/modules/mob/living/silicon/robot/modules/module_maintenance_drone.dm b/code/modules/mob/living/silicon/robot/modules/module_maintenance_drone.dm index e7b91ab6875d..1635721d1c87 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_maintenance_drone.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_maintenance_drone.dm @@ -1,9 +1,10 @@ /obj/item/robot_module/drone name = "drone module" - hide_on_manifest = 1 - no_slip = 1 - networks = list( - NETWORK_ENGINEERING + hide_on_manifest = 1 + has_nonslip_feet = TRUE + has_magnetic_feet = TRUE + camera_channels = list( + CAMERA_CHANNEL_ENGINEERING ) languages = list( /decl/language/human/common = FALSE @@ -18,13 +19,12 @@ /obj/item/t_scanner, /obj/item/lightreplacer, /obj/item/gripper, - /obj/item/soap, + /obj/item/mop/advanced, /obj/item/gripper/no_use/loader, - /obj/item/extinguisher/mini, - /obj/item/pipe_painter, - /obj/item/floor_painter, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/paint_sprayer, /obj/item/inducer/borg, - /obj/item/plunger/robot, + /obj/item/plunger/unbreakable, /obj/item/inflatable_dispenser/robot, /obj/item/chems/spray/cleaner/drone, /obj/item/borg/sight/hud/jani, @@ -33,8 +33,10 @@ /obj/item/stack/material/cyborg/steel, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass, /obj/item/stack/material/cyborg/glass/reinforced, + /obj/item/stack/material/cyborg/fiberglass, /obj/item/stack/tile/wood/cyborg, /obj/item/stack/material/cyborg/wood, /obj/item/stack/cable_coil/cyborg, @@ -56,10 +58,10 @@ SKILL_ELECTRICAL = SKILL_EXPERT ) -/obj/item/robot_module/drone/finalize_equipment(var/mob/living/silicon/robot/R) +/obj/item/robot_module/drone/finalize_equipment(var/mob/living/silicon/robot/robot) . = ..() - if(istype(R)) - R.internals = locate(/obj/item/tank/jetpack/carbondioxide) in equipment + if(istype(robot)) + robot.set_internals(locate(/obj/item/tank/jetpack/carbondioxide) in equipment) /obj/item/robot_module/drone/finalize_emag() . = ..() @@ -83,6 +85,7 @@ /obj/item/stack/material/cyborg/steel, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass/reinforced )) var/obj/item/stack/stack = locate(thing) in equipment @@ -90,7 +93,8 @@ for(var/thing in list( /obj/item/stack/material/cyborg/glass, - /obj/item/stack/material/cyborg/glass/reinforced + /obj/item/stack/material/cyborg/glass/reinforced, + /obj/item/stack/material/cyborg/fiberglass )) var/obj/item/stack/stack = locate(thing) in equipment LAZYDISTINCTADD(stack.synths, glass) @@ -108,10 +112,12 @@ var/obj/item/stack/material/cyborg/plastic/P = locate() in equipment P.synths = list(plastic) -/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) ..() var/obj/item/chems/spray/cleaner/drone/SC = locate() in equipment - SC.reagents.add_reagent(/decl/material/liquid/cleaner, 8 * amount) + SC.add_to_reagents(/decl/material/liquid/cleaner, 8 * amount) + var/obj/item/lightreplacer/LR = locate() in equipment + LR.Charge(robot, amount) /obj/item/robot_module/drone/construction name = "construction drone module" @@ -123,8 +129,3 @@ /obj/item/robot_module/drone/construction/Initialize() equipment += /obj/item/rcd/borg . = ..() - -/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/lightreplacer/LR = locate() in equipment - LR.Charge(R, amount) - ..() diff --git a/code/modules/mob/living/silicon/robot/modules/module_medical.dm b/code/modules/mob/living/silicon/robot/modules/module_medical.dm index 64422211fe7f..e4d027c4daec 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_medical.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_medical.dm @@ -3,8 +3,8 @@ channels = list( "Medical" = TRUE ) - networks = list( - NETWORK_MEDICAL + camera_channels = list( + CAMERA_CHANNEL_MEDICAL ) software = list( /datum/computer_file/program/crew_manifest @@ -18,18 +18,19 @@ /obj/item/robot_module/medical/surgeon name = "surgeon robot module" display_name = "Surgeon" - sprites = list( - "Basic" = "Medbot", - "Standard" = "surgeon", - "Advanced Droid" = "droid-medical", - "Needles" = "medicalrobot" - ) + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_medical_old_alt.dmi', + "Standard" = 'icons/mob/robots/robot_surgeon.dmi', + "Advanced Droid" = 'icons/mob/robots/robot_droid_medical.dmi', + "Needles" = 'icons/mob/robots/robot_medical_old.dmi' + ) equipment = list( /obj/item/flash, /obj/item/borg/sight/hud/med, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/chems/borghypo/surgeon, - /obj/item/scalpel/manager, + /obj/item/incision_manager, /obj/item/hemostat, /obj/item/retractor, /obj/item/cautery, @@ -42,7 +43,7 @@ /obj/item/shockpaddles/robot, /obj/item/crowbar, /obj/item/stack/nanopaste, - /obj/item/stack/medical/advanced/bruise_pack, + /obj/item/stack/medical/bandage/advanced, /obj/item/chems/dropper ) synths = list( @@ -61,7 +62,7 @@ . = ..() for(var/thing in list( /obj/item/stack/nanopaste, - /obj/item/stack/medical/advanced/bruise_pack + /obj/item/stack/medical/bandage/advanced )) var/obj/item/stack/medical/stack = locate(thing) in equipment stack.uses_charge = 1 @@ -69,7 +70,7 @@ /obj/item/robot_module/medical/surgeon/finalize_emag() . = ..() - emag.reagents.add_reagent(/decl/material/liquid/acid/polyacid, 250) + emag.add_to_reagents(/decl/material/liquid/acid/polyacid, 250) emag.SetName("Polyacid spray") /obj/item/robot_module/medical/surgeon/finalize_synths() @@ -77,31 +78,32 @@ var/datum/matter_synth/medicine/medicine = locate() in synths for(var/thing in list( /obj/item/stack/nanopaste, - /obj/item/stack/medical/advanced/bruise_pack + /obj/item/stack/medical/bandage/advanced )) var/obj/item/stack/medical/stack = locate(thing) in equipment stack.synths = list(medicine) -/obj/item/robot_module/medical/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/medical/surgeon/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) if(emag) var/obj/item/chems/spray/PS = emag - PS.reagents.add_reagent(/decl/material/liquid/acid/polyacid, 2 * amount) + PS.add_to_reagents(/decl/material/liquid/acid/polyacid, 2 * amount) ..() /obj/item/robot_module/medical/crisis name = "crisis robot module" display_name = "Crisis" - sprites = list( - "Basic" = "Medbot", - "Standard" = "surgeon", - "Advanced Droid" = "droid-medical", - "Needles" = "medicalrobot" + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_medical_old_alt.dmi', + "Standard" = 'icons/mob/robots/robot_surgeon.dmi', + "Advanced Droid" = 'icons/mob/robots/robot_droid_medical.dmi', + "Needles" = 'icons/mob/robots/robot_medical_old.dmi' ) equipment = list( /obj/item/crowbar, /obj/item/flash, /obj/item/borg/sight/hud/med, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/scanner/reagent/adv, /obj/item/robot_rack/body_bag, /obj/item/chems/borghypo/crisis, @@ -109,11 +111,11 @@ /obj/item/chems/dropper/industrial, /obj/item/chems/syringe, /obj/item/gripper/chemistry, - /obj/item/extinguisher/mini, - /obj/item/taperoll/medical, + /obj/item/chems/spray/extinguisher/mini, + /obj/item/stack/tape_roll/barricade_tape/medical, /obj/item/inflatable_dispenser/robot, /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, + /obj/item/stack/medical/bandage, /obj/item/stack/medical/splint ) synths = list( @@ -132,7 +134,7 @@ . = ..() for(var/thing in list( /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, + /obj/item/stack/medical/bandage, /obj/item/stack/medical/splint )) var/obj/item/stack/medical/stack = locate(thing) in equipment @@ -141,7 +143,7 @@ /obj/item/robot_module/medical/crisis/finalize_emag() . = ..() - emag.reagents.add_reagent(/decl/material/liquid/acid/polyacid, 250) + emag.add_to_reagents(/decl/material/liquid/acid/polyacid, 250) emag.SetName("Polyacid spray") /obj/item/robot_module/medical/crisis/finalize_synths() @@ -149,13 +151,13 @@ var/datum/matter_synth/medicine/medicine = locate() in synths for(var/thing in list( /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, + /obj/item/stack/medical/bandage, /obj/item/stack/medical/splint )) var/obj/item/stack/medical/stack = locate(thing) in equipment stack.synths = list(medicine) -/obj/item/robot_module/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) var/obj/item/chems/syringe/S = locate() in equipment if(S.mode == 2) S.reagents.clear_reagents() @@ -164,5 +166,5 @@ S.update_icon() if(emag) var/obj/item/chems/spray/PS = emag - PS.reagents.add_reagent(/decl/material/liquid/acid/polyacid, 2 * amount) + PS.add_to_reagents(/decl/material/liquid/acid/polyacid, 2 * amount) ..() diff --git a/code/modules/mob/living/silicon/robot/modules/module_miner.dm b/code/modules/mob/living/silicon/robot/modules/module_miner.dm index 953f1bf70546..5aaaf39486ab 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_miner.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_miner.dm @@ -8,13 +8,13 @@ "Supply" = TRUE, "Science" = TRUE ) - networks = list( - NETWORK_MINE + camera_channels = list( + CAMERA_CHANNEL_MINE ) - sprites = list( - "Basic" = "Miner_old", - "Advanced Droid" = "droid-miner", - "Treadhead" = "Miner" + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_miner_old.dmi', + "Advanced Droid" = 'icons/mob/robots/robot_droid_miner.dmi', + "Treadhead" = 'icons/mob/robots/robot_miner.dmi' ) supported_upgrades = list( /obj/item/borg/upgrade/jetpack @@ -24,9 +24,9 @@ /obj/item/borg/sight/meson, /obj/item/wrench, /obj/item/screwdriver, - /obj/item/storage/ore, - /obj/item/pickaxe/borgdrill, - /obj/item/storage/sheetsnatcher/borg, + /obj/item/ore_satchel, + /obj/item/tool/drill/advanced, + /obj/item/sheetsnatcher/borg, /obj/item/gripper/miner, /obj/item/scanner/mining, /obj/item/crowbar @@ -40,10 +40,9 @@ ) /obj/item/robot_module/miner/handle_emagged() - var/obj/item/pickaxe/D = locate(/obj/item/pickaxe/borgdrill) in equipment + var/obj/item/tool/drill/advanced/D = locate() in equipment if(D) equipment -= D qdel(D) - D = new /obj/item/pickaxe/diamonddrill(src) - D.canremove = FALSE + D = new /obj/item/tool/drill/diamond(src) equipment += D diff --git a/code/modules/mob/living/silicon/robot/modules/module_research.dm b/code/modules/mob/living/silicon/robot/modules/module_research.dm index 1de178869de8..78de4222ad41 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_research.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_research.dm @@ -4,11 +4,11 @@ channels = list( "Science" = TRUE ) - networks = list( - NETWORK_RESEARCH + camera_channels = list( + CAMERA_CHANNEL_RESEARCH ) - sprites = list( - "Droid" = "droid-science" + module_sprites = list( + "Droid" = 'icons/mob/robots/robot_droid.dmi' ) equipment = list( /obj/item/flash, @@ -22,9 +22,9 @@ /obj/item/weldingtool/mini, /obj/item/wirecutters, /obj/item/crowbar, - /obj/item/scalpel/laser3, + /obj/item/scalpel/laser/advanced, /obj/item/circular_saw, - /obj/item/extinguisher/mini, + /obj/item/chems/spray/extinguisher/mini, /obj/item/chems/syringe, /obj/item/gripper/chemistry, /obj/item/stack/nanopaste @@ -32,7 +32,6 @@ synths = list( /datum/matter_synth/nanite = 10000 ) - emag = /obj/prefab/hand_teleporter skills = list( SKILL_LITERACY = SKILL_ADEPT, SKILL_FINANCE = SKILL_EXPERT, diff --git a/code/modules/mob/living/silicon/robot/modules/module_security.dm b/code/modules/mob/living/silicon/robot/modules/module_security.dm index f9eb87c6fe4b..96bec1265129 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_security.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_security.dm @@ -2,8 +2,8 @@ channels = list( "Security" = TRUE ) - networks = list( - NETWORK_SECURITY + camera_channels = list( + CAMERA_CHANNEL_SECURITY ) software = list( /datum/computer_file/program/suit_sensors, @@ -20,30 +20,26 @@ SKILL_FORENSICS = SKILL_EXPERT ) -/obj/item/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) ..() for(var/obj/item/gun/energy/T in equipment) - if(T && T.power_supply) - if(T.power_supply.charge < T.power_supply.maxcharge) - T.power_supply.give(T.charge_cost * amount) - T.update_icon() - else - T.charge_tick = 0 - var/obj/item/baton/robot/B = locate() in equipment - if(B && B.bcell) - B.bcell.give(amount) + var/obj/item/cell/power_supply = T.get_cell() + if(power_supply.charge < power_supply.maxcharge) + power_supply.give(T.charge_cost * amount) + update_icon() + else + T.charge_tick = 0 /obj/item/robot_module/security/general name = "security robot module" display_name = "Security" crisis_locked = TRUE - sprites = list( - "Basic" = "secborg", - "Red Knight" = "Security", - "Black Knight" = "securityrobot", - "Bloodhound" = "bloodhound", - "Bloodhound - Treaded" = "secborg+tread", - "Tridroid" = "orb-security" + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_security_old.dmi', + "Black Knight" = 'icons/mob/robots/robot_secborg.dmi', + "Bloodhound" = 'icons/mob/robots/robot_security.dmi', + "Bloodhound - Treaded" = 'icons/mob/robots/robot_security_tread.dmi', + "Tridroid" = 'icons/mob/robots/robot_orb.dmi' ) equipment = list( /obj/item/flash, @@ -51,7 +47,7 @@ /obj/item/handcuffs/cyborg, /obj/item/baton/robot, /obj/item/gun/energy/gun/secure/mounted, - /obj/item/taperoll/police, + /obj/item/stack/tape_roll/barricade_tape/police, /obj/item/megaphone, /obj/item/holowarrant, /obj/item/crowbar, @@ -64,8 +60,8 @@ display_name = "Combat" crisis_locked = TRUE hide_on_manifest = TRUE - sprites = list( - "Combat Android" = "droid-combat" + module_sprites = list( + "Combat Android" = 'icons/mob/robots/robot_combat.dmi' ) equipment = list( /obj/item/flash, diff --git a/code/modules/mob/living/silicon/robot/modules/module_standard.dm b/code/modules/mob/living/silicon/robot/modules/module_standard.dm index 7f5ec1ec9a85..ab8bd3089ad3 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_standard.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_standard.dm @@ -1,14 +1,14 @@ /obj/item/robot_module/standard name = "standard robot module" display_name = "Standard" - sprites = list( - "Basic" = "robot_old", - "Android" = "droid", - "Default" = "robot" + module_sprites = list( + "Basic" = 'icons/mob/robots/robot_old.dmi', + "Android" = 'icons/mob/robots/robot_droid.dmi', + "Default" = 'icons/mob/robots/robot.dmi' ) equipment = list( /obj/item/flash, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/wrench, /obj/item/crowbar, /obj/item/scanner/health diff --git a/code/modules/mob/living/silicon/robot/modules/module_uncertified.dm b/code/modules/mob/living/silicon/robot/modules/module_uncertified.dm index c799f1fa66ff..a151a66d63e3 100644 --- a/code/modules/mob/living/silicon/robot/modules/module_uncertified.dm +++ b/code/modules/mob/living/silicon/robot/modules/module_uncertified.dm @@ -1,8 +1,6 @@ /obj/item/robot_module/uncertified name = "uncertified robot module" - sprites = list( - "Roller" = "omoikane" - ) + module_sprites = list("Roller" = 'icons/mob/robots/robot_service_bro.dmi') //sadly rollersprites seem to have been lost upgrade_locked = TRUE skills = list( SKILL_LITERACY = SKILL_ADEPT, @@ -16,13 +14,13 @@ "Service" = TRUE, "Entertainment" = TRUE ) - networks = list( - NETWORK_THUNDER + camera_channels = list( + CAMERA_CHANNEL_TELEVISION ) equipment = list( - /obj/item/boombox, + /obj/item/music_player/boombox, /obj/item/bikehorn/airhorn, - /obj/item/party_light, + /obj/item/flashlight/party, /obj/item/gun/launcher/money ) diff --git a/code/modules/mob/living/silicon/robot/preset.dm b/code/modules/mob/living/silicon/robot/preset.dm index 50d67d4e6ac1..60358d6da061 100644 --- a/code/modules/mob/living/silicon/robot/preset.dm +++ b/code/modules/mob/living/silicon/robot/preset.dm @@ -1,7 +1,7 @@ /mob/living/silicon/robot/syndicate lawupdate = 0 scrambledcodes = 1 - icon_state = "securityrobot" + icon = 'icons/mob/robots/robot_security.dmi' modtype = "Security" lawchannel = "State" laws = /datum/ai_laws/syndicate_override diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 76f53732eff7..e60938603389 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1,130 +1,104 @@ -#define CYBORG_POWER_USAGE_MULTIPLIER 2.5 // Multiplier for amount of power cyborgs use. +/// Multiplier for amount of power cyborgs use. +#define CYBORG_POWER_USAGE_MULTIPLIER 2.5 /mob/living/silicon/robot - name = "Cyborg" - real_name = "Cyborg" - icon = 'icons/mob/robots.dmi' - icon_state = "robot" - maxHealth = 300 - health = 300 - + name = "robot" + real_name = "robot" + icon = 'icons/mob/robots/robot.dmi' + icon_state = ICON_STATE_WORLD + max_health = 300 + mob_sort_value = 4 + z_flags = ZMM_MANGLE_PLANES mob_bump_flag = ROBOT mob_swap_flags = ROBOT|MONKEY|SLIME|SIMPLE_ANIMAL - mob_push_flags = ~HEAVY //trundle trundle + mob_push_flags = ~HEAVY skillset = /datum/skillset/silicon/robot + silicon_camera = /obj/item/camera/siliconcam/robot_camera + silicon_radio = /obj/item/radio/borg + light_wedge = LIGHT_WIDE - var/lights_on = 0 // Is our integrated light on? + var/panel_icon = 'icons/mob/robots/_panels.dmi' + /// Is our integrated light on? + var/lights_on = 0 var/used_power_this_tick = 0 var/power_efficiency = 1 var/sight_mode = 0 var/custom_name = "" - var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best - var/crisis //Admin-settable for combat module use. + /// Admin-settable for combat module use. + var/crisis var/crisis_override = 0 - var/integrated_light_max_bright = 0.75 + var/integrated_light_power = 0.6 + var/integrated_light_range = 4 var/datum/wires/robot/wires var/module_category = ROBOT_MODULE_TYPE_GROUNDED var/dismantle_type = /obj/item/robot_parts/robot_suit + /// If icon selection has been completed yet + var/icon_selected = TRUE -//Icon stuff - - var/static/list/eye_overlays - var/icontype //Persistent icontype tracking allows for cleaner icon updates - var/module_sprites[0] //Used to store the associations between sprite names and sprite index. - var/icon_selected = 1 //If icon selection has been completed yet - -//Hud stuff - - var/obj/screen/inv1 = null - var/obj/screen/inv2 = null - var/obj/screen/inv3 = null - var/obj/screen/robot_drop_grab/ui_drop_grab - - var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not - var/obj/screen/robot_modules_background - -//3 Modules can be activated at any one time. var/obj/item/robot_module/module = null - var/obj/item/module_active - var/obj/item/module_state_1 - var/obj/item/module_state_2 - var/obj/item/module_state_3 - - silicon_camera = /obj/item/camera/siliconcam/robot_camera - silicon_radio = /obj/item/radio/borg - var/mob/living/silicon/ai/connected_ai = null var/obj/item/cell/cell = /obj/item/cell/high - var/obj/machinery/camera/camera = null - var/cell_emp_mult = 2.5 - - // Components are basically robot organs. + /// Components are basically robot organs. var/list/components = list() - - var/obj/item/mmi/mmi = null - + var/obj/item/organ/internal/central_processor var/opened = 0 var/emagged = 0 var/wiresexposed = 0 var/locked = 1 var/has_power = 1 - var/spawn_module = null - var/spawn_sound = 'sound/voice/liveagain.ogg' var/pitch_toggle = 1 var/list/req_access = list(access_robotics) var/ident = 0 - var/viewalerts = 0 var/modtype = "Default" - var/lower_mod = 0 - var/jetpack = 0 - var/datum/effect/effect/system/ion_trail_follow/ion_trail = null - var/datum/effect/effect/system/spark_spread/spark_system - var/jeton = 0 var/killswitch = 0 var/killswitch_time = 60 var/weapon_lock = 0 var/weaponlock_time = 120 - var/lawupdate = 1 //Cyborgs will sync their laws with their AI by default - var/lockcharge //If a robot is locked down - var/speed = 0 //Cause sec borgs gotta go fast //No they dont! - var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them. - var/tracking_entities = 0 //The number of known entities currently accessing the internal camera + /// Cyborgs will sync their laws with their AI by default + var/lawupdate = 1 + /// If a robot is locked down + var/lockcharge + /// Cause sec borgs gotta go fast //No they dont! + var/speed = 0 + /// Used to determine if a borg shows up on the robotics console. Setting to one hides them. + var/scrambledcodes = 0 + /// The number of known entities currently accessing the internal camera + var/tracking_entities = 0 var/braintype = "Cyborg" - var/intenselight = 0 // Whether cyborg's integrated light was upgraded + /// Whether cyborg's integrated light was upgraded + var/intenselight = 0 var/vtec = FALSE - var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/sensor_mode, /mob/living/silicon/robot/proc/robot_checklaws ) /mob/living/silicon/robot/Initialize() + + add_held_item_slot(new /datum/inventory_slot/gripper/robot/one) + add_held_item_slot(new /datum/inventory_slot/gripper/robot/two) + add_held_item_slot(new /datum/inventory_slot/gripper/robot/three) + + reset_hud_overlays() + . = ..() - spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src) - spark_system.attach(src) add_language(/decl/language/binary, 1) + add_language(/decl/language/machine, 1) add_language(/decl/language/human/common, 1) wires = new(src) - robot_modules_background = new() - robot_modules_background.icon_state = "block" ident = random_id(/mob/living/silicon/robot, 1, 999) - module_sprites["Basic"] = "robot" - icontype = "Basic" + updatename(modtype) update_icon() - if(!scrambledcodes && !camera) - camera = new /obj/machinery/camera(src) - camera.c_tag = real_name - camera.replace_networks(list(NETWORK_EXODUS,NETWORK_ROBOTS)) - if(wires.IsIndexCut(BORG_WIRE_CAMERA)) - camera.status = 0 + if(!scrambledcodes) + set_extension(src, /datum/extension/network_device/camera/robot, null, null, null, TRUE, list(CAMERA_CHANNEL_ROBOTS), name) + verbs |= /mob/living/silicon/robot/proc/configure_camera init() initialize_components() @@ -143,15 +117,8 @@ add_robot_verbs() - hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealth100") - hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealth100") - hud_list[ID_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPTRACK_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") - hud_list[SPECIALROLE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank") + // Disables lay down verb for robots due they're can't lay down and it cause some movement, vision issues. + verbs -= /mob/living/verb/lay_down AddMovementHandler(/datum/movement_handler/robot/use_power, /datum/movement_handler/mob/space) @@ -206,62 +173,28 @@ return amount return 0 -//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO -//Improved /N /mob/living/silicon/robot/Destroy() - if(mmi)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside. - if(mind) - mmi.dropInto(loc) - if(mmi.brainmob) - mind.transfer_to(mmi.brainmob) - else - to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") - ghostize() - //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") - mmi = null - else - QDEL_NULL(mmi) + QDEL_NULL(central_processor) if(connected_ai) connected_ai.connected_robots -= src connected_ai = null QDEL_NULL(module) QDEL_NULL(wires) + QDEL_NULL(cell) + QDEL_LIST_ASSOC_VAL(components) . = ..() -/mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites) - if(new_sprites && new_sprites.len) - module_sprites = new_sprites.Copy() - //Custom_sprite check and entry - - if (custom_sprite == 1) - var/list/valid_states = icon_states(CUSTOM_ITEM_SYNTH) - if("[ckey]-[modtype]" in valid_states) - module_sprites["Custom"] = "[src.ckey]-[modtype]" - icon = CUSTOM_ITEM_SYNTH - icontype = "Custom" - else - icontype = module_sprites[1] - icon = 'icons/mob/robots.dmi' - to_chat(src, "Custom Sprite Sheet does not contain a valid icon_state for [ckey]-[modtype]") - else - icontype = module_sprites[1] - icon_state = module_sprites[icontype] - update_icon() - return module_sprites - /mob/living/silicon/robot/proc/reset_module(var/suppress_alert = null) // Clear hands and module icon. - uneq_all() - if(shown_robot_modules) - hud_used.toggle_show_robot_modules() + drop_held_items() modtype = initial(modtype) - if(hands) - hands.icon_state = initial(hands.icon_state) + refresh_hud_element(HUD_ROBOT_MODULE) // If the robot had a module and this wasn't an uncertified change, let the AI know. if(module) if (!suppress_alert) notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, module.name) // Delete the module. + module.storage?.close(src) module.Reset(src) QDEL_NULL(module) updatename("Default") @@ -270,7 +203,7 @@ if(module && !override) return - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) var/is_crisis_mode = crisis_override || (crisis && security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level)) var/list/robot_modules = SSrobots.get_available_modules(module_category, is_crisis_mode, override) @@ -292,9 +225,7 @@ return new module_type(src) - - if(hands) - hands.icon_state = lowertext(modtype) + refresh_hud_element(HUD_ROBOT_MODULE) SSstatistics.add_field("cyborg_[lowertext(modtype)]",1) updatename() recalculate_synth_capacities() @@ -310,12 +241,10 @@ if(prefix) modtype = prefix - if(istype(mmi, /obj/item/organ/internal/posibrain)) - braintype = "Robot" - else if(istype(mmi, /obj/item/mmi/digital/robot)) - braintype = "Drone" + if(istype(central_processor)) + braintype = central_processor.get_synthetic_owner_name() else - braintype = "Cyborg" + braintype = "Robot" var/changed_name = "" if(custom_name) @@ -324,18 +253,16 @@ else changed_name = "[modtype] [braintype]-[num2text(ident)]" - create_or_rename_email(changed_name, "root.rt") + create_or_update_account(changed_name) real_name = changed_name name = real_name if(mind) mind.name = changed_name //We also need to update name of internal camera. - if (camera) - camera.c_tag = changed_name - - if(!custom_sprite) //Check for custom sprite - set_custom_sprite() + var/datum/extension/network_device/camera/robot/D = get_extension(src, /datum/extension/network_device) + if(D) + D.display_name = changed_name //Flavour text. if(client) @@ -352,7 +279,7 @@ spawn(0) var/newname - newname = sanitizeName(input(src,"You are a robot. Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN, allow_numbers = 1) + newname = sanitize_name(input(src,"You are a robot. Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN, allow_numbers = 1) if (newname) custom_name = newname @@ -366,6 +293,7 @@ to_chat(src, "You [locked ? "un" : ""]lock your panel.") locked = !locked + /mob/living/silicon/robot/proc/self_diagnosis() if(!is_component_functioning("diagnosis unit")) return null @@ -373,7 +301,7 @@ var/dat = "[src.name] Self-Diagnosis Report\n" for (var/V in components) var/datum/robot_component/C = components[V] - dat += "[C.name]
    Brute Damage:[C.brute_damage]
    Electronics Damage:[C.electronics_damage]
    Powered:[(!C.idle_usage || C.is_powered()) ? "Yes" : "No"]
    Toggled:[ C.toggled ? "Yes" : "No"]

    " + dat += "[C.name]
    Brute Damage:[C.brute_damage]
    Electronics Damage:[C.burn_damage]
    Powered:[(!C.idle_usage || C.is_powered()) ? "Yes" : "No"]
    Toggled:[ C.toggled ? "Yes" : "No"]

    " return dat @@ -427,31 +355,36 @@ else C.toggled = 1 to_chat(src, "You enable [C.name].") + +/mob/living/silicon/robot/proc/configure_camera() + set category = "Silicon Commands" + set name = "Configure Camera" + set desc = "Configure your internal camera's network settings." + + if(stat == DEAD) + return + + var/datum/extension/network_device/camera/C = get_extension(src, /datum/extension/network_device/) + if(C) + C.ui_interact(src) + /mob/living/silicon/robot/proc/update_robot_light() if(lights_on) if(intenselight) - set_light(1, 2, 6) + set_light(integrated_light_range, min(0.8, integrated_light_power * 2)) else - set_light(0.75, 1, 4) + set_light(integrated_light_range, integrated_light_power) else set_light(0) // this function displays jetpack pressure in the stat panel /mob/living/silicon/robot/proc/show_jetpack_pressure() // if you have a jetpack, show the internal tank pressure - var/obj/item/tank/jetpack/current_jetpack = installed_jetpack() + var/obj/item/tank/jetpack/current_jetpack = get_jetpack() if (current_jetpack) stat("Internal Atmosphere Info", current_jetpack.name) stat("Tank Pressure", current_jetpack.air_contents.return_pressure()) - -// this function returns the robots jetpack, if one is installed -/mob/living/silicon/robot/proc/installed_jetpack() - if(module) - return (locate(/obj/item/tank/jetpack) in module.equipment) - return 0 - - // this function displays the cyborgs current cell charge in the stat panel /mob/living/silicon/robot/proc/show_cell_power() if(cell) @@ -478,90 +411,90 @@ /mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj) ..(Proj) - if(prob(75) && Proj.damage > 0) - spark_system.start() + if(prob(75) && Proj.damage > 0) + spark_at(src, 5, holder=src) return 2 -/mob/living/silicon/robot/attackby(obj/item/W, mob/user) - - if(istype(W, /obj/item/inducer) || istype(W, /obj/item/handcuffs)) +/mob/living/silicon/robot/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/inducer) || istype(used_item, /obj/item/handcuffs)) return TRUE if(opened) // Are they trying to insert something? for(var/V in components) var/datum/robot_component/C = components[V] - if(!C.installed && C.accepts_component(W)) - if(!user.unEquip(W)) - return + if(!C.installed && C.accepts_component(used_item)) + if(!user.try_unequip(used_item)) + return TRUE C.installed = 1 - C.wrapped = W + C.wrapped = used_item C.install() - W.forceMove(null) + used_item.forceMove(null) - var/obj/item/robot_parts/robot_component/WC = W + var/obj/item/robot_parts/robot_component/WC = used_item if(istype(WC)) - C.brute_damage = WC.brute - C.electronics_damage = WC.burn + C.brute_damage = WC.brute_damage + C.burn_damage = WC.burn_damage - to_chat(usr, "You install the [W.name].") - return + to_chat(user, "You install the [used_item.name].") + return TRUE // If the robot is having something inserted which will remain inside it, self-inserting must be handled before exiting to avoid logic errors. Use the handle_selfinsert proc. - if(try_stock_parts_install(W, user)) - return + if(try_stock_parts_install(used_item, user)) + return TRUE - if(isWelder(W) && user.a_intent != I_HURT) + if(IS_WELDER(used_item) && !user.check_intent(I_FLAG_HARM)) if (src == user) to_chat(user, "You lack the reach to be able to repair yourself.") - return - - if (!getBruteLoss()) + return TRUE + if (!get_damage(BRUTE)) to_chat(user, "Nothing to fix here!") - return - var/obj/item/weldingtool/WT = W - if (WT.remove_fuel(0)) + return TRUE + var/obj/item/weldingtool/welder = used_item + if (welder.weld(0)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - adjustBruteLoss(-30) - updatehealth() + heal_damage(BRUTE, 30) add_fingerprint(user) - for(var/mob/O in viewers(user, null)) - O.show_message(text("[user] has fixed some of the dents on [src]!"), 1) + user.visible_message(SPAN_NOTICE("\The [user] has fixed some of the dents on \the [src]!")) else to_chat(user, "Need more welding fuel!") - return + return TRUE - else if(istype(W, /obj/item/stack/cable_coil) && (wiresexposed || istype(src,/mob/living/silicon/robot/drone))) - if (!getFireLoss()) + else if(istype(used_item, /obj/item/stack/cable_coil) && (wiresexposed || isdrone(src))) + if (!get_damage(BURN)) to_chat(user, "Nothing to fix here!") - return - var/obj/item/stack/cable_coil/coil = W + return TRUE + var/obj/item/stack/cable_coil/coil = used_item if (coil.use(1)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - adjustFireLoss(-30) - updatehealth() - for(var/mob/O in viewers(user, null)) - O.show_message(text("[user] has fixed some of the burnt wires on [src]!"), 1) + heal_damage(BURN, 30) + user.visible_message(SPAN_NOTICE("\The [user] has fixed some of the burnt wires on \the [src]!")) + return TRUE - else if(isCrowbar(W) && user.a_intent != I_HURT) // crowbar means open or close the cover - we all know what a crowbar is by now + else if(IS_CROWBAR(used_item) && !user.check_intent(I_FLAG_HARM)) // crowbar means open or close the cover - we all know what a crowbar is by now if(opened) if(cell) - user.visible_message("\The [user] begins clasping shut \the [src]'s maintenance hatch.", "You begin closing up \the [src].") + user.visible_message( + SPAN_NOTICE("\The [user] begins clasping shut \the [src]'s maintenance hatch."), + SPAN_NOTICE("You begin closing up \the [src].")) + if(do_after(user, 50, src)) - to_chat(user, "You close \the [src]'s maintenance hatch.") + to_chat(user, SPAN_NOTICE("You close \the [src]'s maintenance hatch.")) opened = 0 update_icon() else if(wiresexposed && wires.IsAllCut()) - //Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob. - if(!mmi) - to_chat(user, "\The [src] has no brain to remove.") - return + //Cell is out, wires are exposed, remove CPU, produce damaged chassis, baleet original mob. + if(!central_processor) + to_chat(user, "\The [src] has no central processor to remove.") + return TRUE - user.visible_message("\The [user] begins ripping [mmi] from [src].", "You jam the crowbar into the robot and begin levering [mmi].") - if(do_after(user, 50, src)) - dismantle(user) + user.visible_message( + SPAN_NOTICE("\The [user] begins ripping \the [central_processor] out of \the [src]."), + SPAN_NOTICE("You jam the crowbar into the robot and begin levering out \the [central_processor].")) + if(do_after(user, 5 SECONDS, src)) + dismantle_robot(user) else - // Okay we're not removing the cell or an MMI, but maybe something else? + // Okay we're not removing the cell or a CPU, but maybe something else? var/list/removable_components = list() for(var/V in components) if(V == "power cell") continue @@ -571,14 +504,14 @@ removable_components |= stock_parts var/remove = input(user, "Which component do you want to pry out?", "Remove Component") as null|anything in removable_components if(!remove || !opened || !(remove in (stock_parts|components)) || !Adjacent(user)) - return + return TRUE var/obj/item/removed_item if(istype(components[remove], /datum/robot_component)) var/datum/robot_component/C = components[remove] var/obj/item/robot_parts/robot_component/I = C.wrapped if(istype(I)) - I.brute = C.brute_damage - I.burn = C.electronics_damage + I.set_bruteloss(C.brute_damage) + I.set_burnloss(C.burn_damage) removed_item = I if(C.installed == 1) @@ -599,104 +532,104 @@ to_chat(user, "You open \the [src]'s maintenance hatch.") opened = 1 update_icon() - - else if (istype(W, /obj/item/cell) && opened) // trying to put a cell inside + return TRUE + else if (istype(used_item, /obj/item/cell) && opened) // trying to put a cell inside var/datum/robot_component/C = components["power cell"] if(wiresexposed) to_chat(user, "Close the panel first.") else if(cell) to_chat(user, "There is a power cell already installed.") - else if(W.w_class != ITEM_SIZE_NORMAL) - to_chat(user, "\The [W] is too [W.w_class < ITEM_SIZE_NORMAL? "small" : "large"] to fit here.") - else if(user.unEquip(W, src)) - cell = W - handle_selfinsert(W, user) //Just in case. + else if(used_item.w_class != ITEM_SIZE_NORMAL) + to_chat(user, "\The [used_item] is too [used_item.w_class < ITEM_SIZE_NORMAL? "small" : "large"] to fit here.") + else if(user.try_unequip(used_item, src)) + cell = used_item + handle_selfinsert(used_item, user) //Just in case. to_chat(user, "You insert the power cell.") C.installed = 1 - C.wrapped = W + C.wrapped = used_item C.install() // This means that removing and replacing a power cell will repair the mount. C.brute_damage = 0 - C.electronics_damage = 0 - - else if(isWirecutter(W) || isMultitool(W)) + C.burn_damage = 0 + return TRUE + else if(IS_WIRECUTTER(used_item) || IS_MULTITOOL(used_item)) if (wiresexposed) wires.Interact(user) else to_chat(user, "You can't reach the wiring.") - else if(isScrewdriver(W) && opened && !cell) // haxing + return TRUE + else if(IS_SCREWDRIVER(used_item) && opened && !cell) // haxing wiresexposed = !wiresexposed to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"].") update_icon() - - else if(istype(W, /obj/item/screwdriver) && opened && cell) // radio + return TRUE + else if(IS_SCREWDRIVER(used_item) && opened && cell) // radio if(silicon_radio) - silicon_radio.attackby(W,user)//Push it to the radio to let it handle everything + silicon_radio.attackby(used_item,user)//Push it to the radio to let it handle everything else to_chat(user, "Unable to locate a radio.") update_icon() - - else if(istype(W, /obj/item/encryptionkey/) && opened) + return TRUE + else if(istype(used_item, /obj/item/encryptionkey/) && opened) if(silicon_radio)//sanityyyyyy - silicon_radio.attackby(W,user)//GTFO, you have your own procs + silicon_radio.attackby(used_item,user)//GTFO, you have your own procs else to_chat(user, "Unable to locate a radio.") - else if (istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer)||istype(W, /obj/item/card/robot)) // trying to unlock the interface with an ID card + return TRUE + else if (istype(used_item, /obj/item/card/id)||istype(used_item, /obj/item/modular_computer)||istype(used_item, /obj/item/card/robot)) // trying to unlock the interface with an ID card if(emagged)//still allow them to open the cover - to_chat(user, "The interface seems slightly damaged") + to_chat(user, "The interface seems slightly damaged.") if(opened) to_chat(user, "You must close the cover to swipe an ID card.") else - if(allowed(usr)) + if(allowed(user)) locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.") update_icon() else to_chat(user, "Access denied.") - else if(istype(W, /obj/item/borg/upgrade)) - var/obj/item/borg/upgrade/U = W + return TRUE + else if(istype(used_item, /obj/item/borg/upgrade)) + var/obj/item/borg/upgrade/U = used_item if(!opened) - to_chat(usr, "You must access the borgs internals!") + to_chat(user, "You must access [src]'s internals!") else if(!src.module && U.require_module) - to_chat(usr, "The borg must choose a module before he can be upgraded!") + to_chat(user, "[src] must choose a module before they can be upgraded!") else if(U.locked) - to_chat(usr, "The upgrade is locked and cannot be used yet!") + to_chat(user, "The upgrade is locked and cannot be used yet!") else if(U.action(src)) - if(!user.unEquip(U, src)) - return - to_chat(usr, "You apply the upgrade to [src]!") - handle_selfinsert(W, user) + if(!user.try_unequip(U, src)) + return TRUE + to_chat(user, "You apply the upgrade to [src]!") + handle_selfinsert(used_item, user) else - to_chat(usr, "Upgrade error!") + to_chat(user, "Upgrade error!") + return TRUE + if(!(istype(used_item, /obj/item/robotanalyzer) || istype(used_item, /obj/item/scanner/health)) && !user.check_intent(I_FLAG_HELP) && used_item.expend_attack_force(user)) + spark_at(src, 5, holder=src) + return ..() - else - if(!(istype(W, /obj/item/robotanalyzer) || istype(W, /obj/item/scanner/health)) && W.force && user.a_intent != I_HELP) - spark_system.start() - return ..() - -/mob/living/silicon/robot/proc/handle_selfinsert(obj/item/W, mob/user) - if ((user == src) && istype(get_active_hand(),/obj/item/gripper)) - var/obj/item/gripper/H = get_active_hand() - if (W.loc == H) //if this triggers something has gone very wrong, and it's safest to abort +/mob/living/silicon/robot/proc/handle_selfinsert(obj/item/used_item, mob/user) + if ((user == src) && istype(get_active_held_item(),/obj/item/gripper)) + var/obj/item/gripper/H = get_active_held_item() + if (used_item.loc == H) //if this triggers something has gone very wrong, and it's safest to abort return - else if (H.wrapped == W) + else if (H.wrapped == used_item) H.wrapped = null -/mob/living/silicon/robot/attack_hand(mob/user) - - add_fingerprint(user) +/mob/living/silicon/robot/try_awaken(mob/user) + return user?.attempt_hug(src) - if(istype(user,/mob/living/carbon/human)) - - var/mob/living/carbon/human/H = user - if(H.a_intent == I_GRAB) - return ..() - if(H.species.can_shred(H)) - attack_generic(H, rand(30,50), "slashed") - return +/mob/living/silicon/robot/default_hurt_interaction(mob/user) + if(user.can_shred()) + attack_generic(user, rand(30,50), "slashed") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return TRUE + . = ..() - if(opened && !wiresexposed && (!istype(user, /mob/living/silicon))) +/mob/living/silicon/robot/default_interaction(mob/user) + if(!user.check_intent(I_FLAG_GRAB) && opened && !wiresexposed && (!issilicon(user))) var/datum/robot_component/cell_component = components["power cell"] if(cell) cell.update_icon() @@ -712,87 +645,41 @@ var/obj/item/broken_device = cell_component.wrapped to_chat(user, "You remove \the [broken_device].") user.put_in_active_hand(broken_device) + return TRUE + . = ..() //Robots take half damage from basic attacks. /mob/living/silicon/robot/attack_generic(var/mob/user, var/damage, var/attack_message) - return ..(user,Floor(damage/2),attack_message) + return ..(user,floor(damage/2),attack_message) /mob/living/silicon/robot/get_req_access() return req_access +/mob/living/silicon/robot/get_eye_overlay() + var/eye_icon_state = "[icon_state]-eyes" + if(check_state_in_icon(eye_icon_state, icon)) + return emissive_overlay(icon, eye_icon_state) + /mob/living/silicon/robot/on_update_icon() - overlays.Cut() + + ..() + + icon_state = ICON_STATE_WORLD if(stat == CONSCIOUS) - var/eye_icon_state = "eyes-[module_sprites[icontype]]" - if(eye_icon_state in icon_states(icon)) - if(!eye_overlays) - eye_overlays = list() - var/image/eye_overlay = eye_overlays[eye_icon_state] - if(!eye_overlay) - eye_overlay = image(icon, eye_icon_state) - eye_overlay.plane = EFFECTS_ABOVE_LIGHTING_PLANE - eye_overlay.layer = EYE_GLOW_LAYER - eye_overlays[eye_icon_state] = eye_overlay - overlays += eye_overlay + var/image/eyes = get_eye_overlay() + if(eyes) + add_overlay(eyes) if(opened) - var/panelprefix = custom_sprite ? src.ckey : "ov" if(wiresexposed) - overlays += "[panelprefix]-openpanel +w" + add_overlay(image(panel_icon, "ov-openpanel +w")) else if(cell) - overlays += "[panelprefix]-openpanel +c" - else - overlays += "[panelprefix]-openpanel -c" - - if(module_active && istype(module_active,/obj/item/borg/combat/shield)) - overlays += "[module_sprites[icontype]]-shield" - - if(modtype == "Combat") - if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) - icon_state = "[module_sprites[icontype]]-roll" + add_overlay(image(panel_icon, "ov-openpanel +c")) else - icon_state = module_sprites[icontype] - return - -/mob/living/silicon/robot/proc/installed_modules() - if(weapon_lock) - to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") - return - - if(!module) - pick_module() - return - var/dat = "Modules\n" - dat += {" - Activated Modules -
    - Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
    - Module 2: [module_state_2 ? "
    [module_state_2]" : "No Module"]
    - Module 3: [module_state_3 ? "
    [module_state_3]" : "No Module"]
    -
    - Installed Modules

    "} - - - for (var/obj in module.equipment) - if (!obj) - dat += text("Resource depleted
    ") - else if(activated(obj)) - dat += text("[obj]: Activated
    ") - else - dat += text("[obj]:
    Activate
    ") - if (emagged) - if(activated(module.emag)) - dat += text("[module.emag]: Activated
    ") - else - dat += text("[module.emag]: Activate
    ") -/* - if(activated(obj)) - dat += text("[obj]: \[Activated | Deactivate\]
    ") - else - dat += text("[obj]: \[Activate | Deactivated\]
    ") -*/ - show_browser(src, dat, "window=robotmod") + add_overlay(image(panel_icon, "ov-openpanel -c")) + if(istype(get_active_held_item(), /obj/item/borg/combat/shield)) + add_overlay("[icon_state]-shield") /mob/living/silicon/robot/OnSelfTopic(href_list) if (href_list["showalerts"]) @@ -805,105 +692,18 @@ O.attack_self(src) return TOPIC_HANDLED - if (href_list["act"]) - var/obj/item/O = locate(href_list["act"]) - if (!istype(O)) - return TOPIC_HANDLED - - if(!((O in module.equipment) || (O == src.module.emag))) - return TOPIC_HANDLED - - if(activated(O)) - to_chat(src, "Already activated") - return TOPIC_HANDLED - if(!module_state_1) - module_state_1 = O - O.hud_layerise() - O.forceMove(src) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode |= module_state_1:sight_mode - else if(!module_state_2) - module_state_2 = O - O.hud_layerise() - O.forceMove(src) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode |= module_state_2:sight_mode - else if(!module_state_3) - module_state_3 = O - O.hud_layerise() - O.forceMove(src) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode |= module_state_3:sight_mode - else - to_chat(src, "You need to disable a module first!") - installed_modules() - return TOPIC_HANDLED - - if (href_list["deact"]) - var/obj/item/O = locate(href_list["deact"]) - if(activated(O)) - if(module_state_1 == O) - module_state_1 = null - O.forceMove(null) - else if(module_state_2 == O) - module_state_2 = null - O.forceMove(null) - else if(module_state_3 == O) - module_state_3 = null - O.forceMove(null) - else - to_chat(src, "Module isn't activated.") - else - to_chat(src, "Module isn't activated") - installed_modules() - return TOPIC_HANDLED return ..() /mob/living/silicon/robot/proc/radio_menu() silicon_radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code - /mob/living/silicon/robot/Move(a, b, flag) - . = ..() - - if(module) - if(module.type == /obj/item/robot_module/janitor) - var/turf/tile = loc - if(isturf(tile)) - tile.clean_blood() - if (istype(tile, /turf/simulated)) - var/turf/simulated/S = tile - S.dirt = 0 - for(var/A in tile) - if(istype(A, /obj/effect)) - if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay)) - qdel(A) - else if(istype(A, /obj/item)) - var/obj/item/cleaned_item = A - cleaned_item.clean_blood() - else if(istype(A, /mob/living/carbon/human)) - var/mob/living/carbon/human/cleaned_human = A - if(cleaned_human.lying) - if(cleaned_human.head) - cleaned_human.head.clean_blood() - cleaned_human.update_inv_head(0) - if(cleaned_human.wear_suit) - cleaned_human.wear_suit.clean_blood() - cleaned_human.update_inv_wear_suit(0) - else if(cleaned_human.w_uniform) - cleaned_human.w_uniform.clean_blood() - cleaned_human.update_inv_w_uniform(0) - if(cleaned_human.shoes) - cleaned_human.shoes.clean_blood() - cleaned_human.update_inv_shoes(0) - cleaned_human.clean_blood(1) - to_chat(cleaned_human, "[src] cleans your face!") - return - -/mob/living/silicon/robot/proc/self_destruct() - gib() - return + if(. && module && isturf(loc)) + var/obj/item/stack/material/ore/orebag = locate() in get_held_items() + if(orebag) + loc.attackby(orebag, src) + module.handle_turf(loc, src) /mob/living/silicon/robot/proc/UnlinkSelf() disconnect_from_ai() @@ -911,20 +711,19 @@ lockcharge = 0 scrambledcodes = 1 //Disconnect it's camera so it's not so easily tracked. - if(src.camera) - src.camera.clear_all_networks() - + var/datum/extension/network_device/camera/robot/D = get_extension(src, /datum/extension/network_device) + if(D) + D.remove_channels(D.channels) /mob/living/silicon/robot/proc/ResetSecurityCodes() set category = "Silicon Commands" set name = "Reset Identity Codes" set desc = "Scrambles your security and identification codes and resets your current buffers. Unlocks you and but permanently severs you from your AI and the robotics console and will deactivate your camera system." - var/mob/living/silicon/robot/R = src - - if(R) - R.UnlinkSelf() - to_chat(R, "Buffers flushed and reset. Camera system shutdown. All systems operational.") + var/mob/living/silicon/robot/robot = src + if(robot) + robot.UnlinkSelf() + to_chat(robot, "Buffers flushed and reset. Camera system shutdown. All systems operational.") src.verbs -= /mob/living/silicon/robot/proc/ResetSecurityCodes /mob/living/silicon/robot/proc/SetLockdown(var/state = 1) @@ -936,7 +735,7 @@ if(lockcharge != state) lockcharge = state - UpdateLyingBuckledAndVerbStatus() + update_posture() return 1 return 0 @@ -945,38 +744,43 @@ set category = "IC" set src = usr - var/obj/item/W = get_active_hand() - if (W) - W.attack_self(src) + var/obj/item/holding = get_active_held_item() + if (holding) + holding.attack_self(src) return /mob/living/silicon/robot/proc/choose_icon(list/module_sprites) - set waitfor = 0 - if(!LAZYLEN(module_sprites)) + + set waitfor = FALSE + + if(!length(module_sprites)) to_chat(src, "Something is badly wrong with the sprite selection. Harass a coder.") CRASH("Can't setup robot icon for [src] ([src.client]). Module: [module?.name]") icon_selected = FALSE - if(module_sprites.len == 1 || !client) - if(!(icontype in module_sprites)) - icontype = module_sprites[1] + + var/selected_icon + if(length(module_sprites) == 1 || !client) + icon = module_sprites[module_sprites[1]] else var/list/options = list() - for(var/i in module_sprites) - var/image/radial_button = image(icon = src.icon, icon_state = module_sprites[i]) - radial_button.overlays.Add(image(icon = src.icon, icon_state = "eyes-[module_sprites[i]]")) - radial_button.name = i - options[i] = radial_button - icontype = show_radial_menu(src, src, options, radius = 42, tooltips = TRUE) - - if(!icontype) - return + for(var/sprite in module_sprites) + var/image/radial_button = image(icon = module_sprites[sprite], icon_state = ICON_STATE_WORLD) + radial_button.overlays.Add(image(icon = module_sprites[sprite], icon_state = "[ICON_STATE_WORLD]-eyes")) + radial_button.name = sprite + options[sprite] = radial_button + var/chosen_icon = show_radial_menu(src, src, options, radius = 42, tooltips = TRUE) + if(!chosen_icon || icon_selected) + return + selected_icon = chosen_icon - icon_state = module_sprites[icontype] - update_icon() + if(!selected_icon) + return + icon = module_sprites[selected_icon] icon_selected = TRUE + update_icon() to_chat(src, "Your icon has been set. You now require a module reset to change it.") /mob/living/silicon/robot/proc/sensor_mode() //Medical/Security HUD controller for borgs @@ -1008,8 +812,8 @@ if(is_component_functioning("comms")) var/datum/robot_component/RC = get_component("comms") use_power(RC.active_usage) - return 1 - return 0 + return TRUE + return FALSE /mob/living/silicon/robot/proc/notify_ai(var/notifytype, var/first_arg, var/second_arg) if(!connected_ai) @@ -1056,7 +860,7 @@ if(emagged) return //Prevents the X has hit Y with Z message also you cant emag them twice if(wiresexposed) - to_chat(user, "You must close the panel first") + to_chat(user, "You must close the panel first.") return else sleep(6) @@ -1070,8 +874,9 @@ clear_inherent_laws() laws = new /datum/ai_laws/syndicate_override var/time = time2text(world.realtime,"hh:mm:ss") - GLOB.lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") - set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.") + global.lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + var/decl/pronouns/pronouns = user.get_pronouns(ignore_coverings = TRUE) + set_zeroth_law("Only [user.real_name] and people [pronouns.he] designate[pronouns.s] as being such are operatives.") SetLockdown(0) . = 1 spawn() @@ -1085,7 +890,7 @@ sleep(5) to_chat(src, "Would you like to send a report to the vendor? Y/N") sleep(10) - to_chat(src, "> N") + to_chat(src, "\> N") sleep(20) to_chat(src, "ERRORERRORERROR") to_chat(src, "Obey these laws:") @@ -1100,22 +905,121 @@ return 1 /mob/living/silicon/robot/incapacitated(var/incapacitation_flags = INCAPACITATION_DEFAULT) - if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (lockcharge || !is_component_functioning("actuator"))) + if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (lockcharge || !is_component_functioning("actuator") || !is_component_functioning("power cell"))) return 1 - if ((incapacitation_flags & INCAPACITATION_KNOCKOUT) && !is_component_functioning("actuator")) + if ((incapacitation_flags & INCAPACITATION_KNOCKOUT) && !is_component_functioning("power cell")) return 1 return ..() -/mob/living/silicon/robot/proc/dismantle(var/mob/user) - to_chat(user, SPAN_NOTICE("You damage some parts of the chassis, but eventually manage to rip out the central processor.")) - var/obj/item/robot_parts/robot_suit/C = new dismantle_type(loc) - C.dismantled_from(src) +/mob/living/silicon/robot/gib(do_gibs) + SHOULD_CALL_PARENT(FALSE) + var/lastloc = loc + dismantle_robot() + if(lastloc && do_gibs) + spawn_gibber(lastloc) + +/mob/living/silicon/robot/proc/dismantle_robot(var/mob/user) + + if(central_processor) + if(user) + to_chat(user, SPAN_NOTICE("You damage some parts of the chassis, but eventually manage to rip out \the [central_processor].")) + central_processor.dropInto(loc) + var/mob/living/brainmob = central_processor.get_brainmob(create_if_missing = TRUE) + if(mind && brainmob) + mind.transfer_to(brainmob) + else + ghostize() + central_processor.update_icon() + central_processor = null + + var/obj/item/robot_parts/robot_suit/chassis = new dismantle_type(loc) + chassis.dismantled_from(src) qdel(src) -/mob/living/silicon/robot/try_stock_parts_install(obj/item/stock_parts/W, mob/user) +/mob/living/silicon/robot/try_stock_parts_install(obj/item/stock_parts/used_item, mob/user) if(!opened) return . = ..() if(.) - handle_selfinsert(W, user) - recalculate_synth_capacities() \ No newline at end of file + handle_selfinsert(used_item, user) + recalculate_synth_capacities() + +/mob/living/silicon/robot/get_admin_job_string() + return ASSIGNMENT_ROBOT + +/mob/living/silicon/robot/handle_pre_transformation() + clear_brain() + +/mob/living/silicon/robot/proc/clear_brain() + QDEL_NULL(central_processor) + +/mob/living/silicon/robot/do_flash_animation() + set waitfor = FALSE + var/atom/movable/overlay/animation = new(src) + animation.plane = plane + animation.layer = layer + 0.01 + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + flick("blspell", animation) + QDEL_IN(animation, 0.5 SECONDS) + +/mob/living/silicon/robot/proc/handle_radio_transmission() + if(!is_component_functioning("radio")) + return FALSE + var/datum/robot_component/CO = get_component("radio") + if(!CO || !cell_use_power(CO.active_usage)) + return FALSE + return TRUE + +/mob/living/silicon/robot/need_breathe() + return FALSE + +/mob/living/silicon/robot/should_breathe() + return FALSE + +/mob/living/silicon/robot/try_breathe() + return FALSE + +/mob/living/silicon/robot/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/audible/clap, + /decl/emote/visible/bow, + /decl/emote/visible/salute, + /decl/emote/visible/flap, + /decl/emote/visible/aflap, + /decl/emote/visible/twitch, + /decl/emote/visible/twitch_v, + /decl/emote/visible/dance, + /decl/emote/visible/nod, + /decl/emote/visible/shake, + /decl/emote/visible/glare, + /decl/emote/visible/look, + /decl/emote/visible/stare, + /decl/emote/visible/deathgasp_robot, + /decl/emote/visible/spin, + /decl/emote/visible/sidestep, + /decl/emote/audible/synth, + /decl/emote/audible/synth/ping, + /decl/emote/audible/synth/buzz, + /decl/emote/audible/synth/confirm, + /decl/emote/audible/synth/deny, + /decl/emote/audible/synth/security, + /decl/emote/audible/synth/security/halt + ) + return default_emotes + +/mob/living/silicon/robot/check_grab_hand() + if(locate(/obj/item/grab) in contents) + to_chat(src, SPAN_WARNING("You have already grabbed something!")) + return FALSE + return TRUE + +/mob/living/silicon/robot/prepare_for_despawn() + clear_brain() + if(module) + for(var/obj/item/I in module) // the tools the borg has; metal, glass, guns etc + for(var/obj/item/O in I.get_contained_external_atoms()) // the things inside the tools, if anything; mainly for janiborg trash bags + O.forceMove(src) + qdel(I) + QDEL_NULL(module) + return ..() diff --git a/code/modules/mob/living/silicon/robot/robot_damage.dm b/code/modules/mob/living/silicon/robot/robot_damage.dm index a5b74ada911b..7e43ee35c774 100644 --- a/code/modules/mob/living/silicon/robot/robot_damage.dm +++ b/code/modules/mob/living/silicon/robot/robot_damage.dm @@ -1,11 +1,3 @@ -/mob/living/silicon/robot/updatehealth() - if(status_flags & GODMODE) - health = maxHealth - stat = CONSCIOUS - return - health = maxHealth - (getBruteLoss() + getFireLoss()) - return - /mob/living/silicon/robot/getBruteLoss() var/amount = 0 for(var/V in components) @@ -17,16 +9,17 @@ var/amount = 0 for(var/V in components) var/datum/robot_component/C = components[V] - if(C.installed != 0) amount += C.electronics_damage + if(C.installed != 0) amount += C.burn_damage return amount -/mob/living/silicon/robot/adjustBruteLoss(var/amount) +/mob/living/silicon/robot/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) // take/heal overall call update_health regardless of arg if(amount > 0) take_overall_damage(amount, 0) else heal_overall_damage(-amount, 0) -/mob/living/silicon/robot/adjustFireLoss(var/amount) +/mob/living/silicon/robot/adjustFireLoss(var/amount, var/do_update_health = TRUE) if(amount > 0) take_overall_damage(0, amount) else @@ -37,7 +30,7 @@ for(var/V in components) var/datum/robot_component/C = components[V] if(C.installed == 1 || (C.installed == -1 && destroyed)) - if((brute && C.brute_damage) || (burn && C.electronics_damage) || (!C.toggled) || (!C.powered && C.toggled)) + if((brute && C.brute_damage) || (burn && C.burn_damage) || (!C.toggled) || (!C.powered && C.toggled)) parts += C return parts @@ -56,20 +49,20 @@ return C return 0 -/mob/living/silicon/robot/heal_organ_damage(var/brute, var/burn) - var/list/datum/robot_component/parts = get_damaged_components(brute,burn) +/mob/living/silicon/robot/heal_organ_damage(var/brute, var/burn, var/affect_robo = FALSE, var/update_health = TRUE) + var/list/datum/robot_component/parts = get_damaged_components(brute, burn) if(!parts.len) return var/datum/robot_component/picked = pick(parts) picked.heal_damage(brute,burn) -/mob/living/silicon/robot/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = 0, var/edge = 0, var/emp = 0) +/mob/living/silicon/robot/take_organ_damage(var/brute = 0, var/burn = 0, var/bypass_armour = FALSE, var/override_droplimb) var/list/components = get_damageable_components() if(!components.len) return //Combat shielding absorbs a percentage of damage directly into the cell. - if(module_active && istype(module_active,/obj/item/borg/combat/shield)) - var/obj/item/borg/combat/shield/shield = module_active + var/obj/item/borg/combat/shield/shield = get_active_held_item() + if(istype(shield)) //Shields absorb a certain percentage of damage based on their power setting. var/absorb_brute = brute*shield.shield_level var/absorb_burn = burn*shield.shield_level @@ -84,14 +77,14 @@ burn -= absorb_burn to_chat(src, "Your shield absorbs some of the impact!") - if(!emp) + if(!bypass_armour) var/datum/robot_component/armour/A = get_armour() if(A) - A.take_damage(brute,burn,sharp,edge) + A.take_component_damage(brute, burn) return var/datum/robot_component/C = pick(components) - C.take_damage(brute,burn,sharp,edge) + C.take_component_damage(brute, burn) /mob/living/silicon/robot/heal_overall_damage(var/brute, var/burn) var/list/datum/robot_component/parts = get_damaged_components(brute,burn) @@ -100,12 +93,12 @@ var/datum/robot_component/picked = pick(parts) var/brute_was = picked.brute_damage - var/burn_was = picked.electronics_damage + var/burn_was = picked.burn_damage picked.heal_damage(brute,burn) brute -= (brute_was-picked.brute_damage) - burn -= (burn_was-picked.electronics_damage) + burn -= (burn_was-picked.burn_damage) parts -= picked @@ -114,8 +107,8 @@ var/list/datum/robot_component/parts = get_damageable_components() //Combat shielding absorbs a percentage of damage directly into the cell. - if(module_active && istype(module_active,/obj/item/borg/combat/shield)) - var/obj/item/borg/combat/shield/shield = module_active + var/obj/item/borg/combat/shield/shield = get_active_held_item() + if(istype(shield)) //Shields absorb a certain percentage of damage based on their power setting. var/absorb_brute = brute*shield.shield_level var/absorb_burn = burn*shield.shield_level @@ -132,22 +125,18 @@ var/datum/robot_component/armour/A = get_armour() if(A) - A.take_damage(brute,burn,sharp) - return - - while(parts.len && (brute>0 || burn>0) ) - var/datum/robot_component/picked = pick(parts) - - var/brute_was = picked.brute_damage - var/burn_was = picked.electronics_damage - - picked.take_damage(brute,burn) - - brute -= (picked.brute_damage - brute_was) - burn -= (picked.electronics_damage - burn_was) - - parts -= picked + A.take_component_damage(brute,burn,sharp) + else + while(parts.len && (brute>0 || burn>0) ) + var/datum/robot_component/picked = pick(parts) + var/brute_was = picked.brute_damage + var/burn_was = picked.burn_damage + picked.take_component_damage(brute,burn) + brute -= (picked.brute_damage - brute_was) + burn -= (picked.burn_damage - burn_was) + parts -= picked + update_health() /mob/living/silicon/robot/emp_act(severity) - uneq_all() + drop_held_items() ..() //Damage is handled at /silicon/ level. diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 5bbbe548ac8f..de977e45c639 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -4,6 +4,12 @@ icon = 'icons/obj/items/borg_module/borg_rnd_analyser.dmi' icon_state = "portable_analyzer" desc = "Similar to the stationary version, this rather unwieldy device allows you to break down objects in the name of science." + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + ) var/obj/item/loaded_item var/list/saved_tech_levels = list() @@ -12,7 +18,7 @@ to_chat(user, SPAN_WARNING("There is nothing loaded inside \the [src].")) return TRUE var/choice = input("Do you wish to eject or analyze \the [loaded_item]?", "Portable Analyzer") as null|anything in list("Eject", "Analyze") - if(!choice || !QDELETED(loaded_item) || user.incapacitated() || loc != user) + if(!choice || QDELETED(loaded_item) || user.incapacitated() || loc != user) return TRUE if(choice == "Eject") loaded_item.dropInto(user.loc) @@ -21,10 +27,13 @@ var/confirm = alert(user, "This will destroy the item inside forever. Are you sure?","Confirm Analyze","Yes","No") if(confirm == "Yes" && !QDELETED(loaded_item) && !user.incapacitated() && loc == user) to_chat(user, "You activate the analyzer's microlaser, analyzing \the [loaded_item] and breaking it down.") - var/list/tech_found = json_decode(loaded_item.origin_tech) + var/list/tech_found = cached_json_decode(loaded_item.get_origin_tech()) for(var/tech in tech_found) - if(saved_tech_levels[tech] < tech_found[tech]) + if(saved_tech_levels[tech] == tech_found[tech]) + saved_tech_levels[tech] = (tech_found[tech]+1) + else if(saved_tech_levels[tech] < tech_found[tech]) saved_tech_levels[tech] = tech_found[tech] + flick("portable_analyzer_scan", src) QDEL_NULL(loaded_item) @@ -49,7 +58,8 @@ to_chat(user, SPAN_WARNING("\The [src] already has something inside. Analyze or eject it first.")) return var/obj/item/I = target - if(!I.origin_tech) + var/tech = I.get_origin_tech() + if(!tech) to_chat(user, SPAN_WARNING("\The [I] has no interesting data to analyze.")) return I.forceMove(src) @@ -58,91 +68,29 @@ flick("portable_analyzer_load", src) icon_state = "portable_analyzer_full" -/obj/item/portable_destructive_analyzer/examine(mob/user, distance) +/obj/item/portable_destructive_analyzer/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) if(loaded_item) - to_chat(user, "It is holding \the [loaded_item].") - to_chat(user, "It has the following data saved:") + . += "It is holding \the [loaded_item]." + . += "It has the following data saved:" for(var/tech in saved_tech_levels) - to_chat(user, "[tech]: [saved_tech_levels[tech]]") - -/obj/item/party_light - name = "party light" - desc = "An array of LEDs in tons of colors." - icon = 'icons/obj/lighting.dmi' - icon_state = "partylight-off" - item_state = "partylight-off" - var/activated = 0 - var/strobe_effect = null - -/obj/item/party_light/attack_self() - if (activated) - deactivate_strobe() - else - activate_strobe() - -/obj/item/party_light/on_update_icon() - if (activated) - icon_state = "partylight-on" - set_light(1, 1, 7) - else - icon_state = "partylight_off" - set_light(0) - -/obj/item/party_light/proc/activate_strobe() - activated = 1 - - // Create the party light effect and place it on the turf of who/whatever has it. - var/turf/T = get_turf(src) - var/obj/effect/party_light/L = new(T) - strobe_effect = L - - // Make the light effect follow this party light object. - GLOB.moved_event.register(src, L, /atom/movable/proc/move_to_turf_or_null) - - update_icon() - -/obj/item/party_light/proc/deactivate_strobe() - activated = 0 - - // Cause the party light effect to stop following this object, and then delete it. - GLOB.moved_event.unregister(src, strobe_effect, /atom/movable/proc/move_to_turf_or_null) - QDEL_NULL(strobe_effect) - - update_icon() - -/obj/item/party_light/Destroy() - deactivate_strobe() - . = .. () - -/obj/effect/party_light - name = "party light" - desc = "This is probably bad for your eyes." - icon = 'icons/effects/lens_flare.dmi' - icon_state = "party_strobe" - simulated = 0 - anchored = 1 - pixel_x = -30 - pixel_y = -4 - -/obj/effect/party_light/Initialize() - update_icon() - . = ..() + . += "[tech]: [saved_tech_levels[tech]]" //This is used to unlock other borg covers. /obj/item/card/robot //This is not a child of id cards, as to avoid dumb typechecks on computers. name = "access code transmission device" - icon_state = "robot_base" + icon_state = "emag" desc = "A circuit grafted onto the bottom of an ID card. It is used to transmit access codes into other robot chassis, \ allowing you to lock and unlock other robots' panels." //A harvest item for serviceborgs. /obj/item/robot_harvester name = "auto harvester" - desc = "A hand-held harvest tool that resembles a sickle. It uses energy to cut plant matter very efficently." + desc = "A hand-held harvest tool that resembles a sickle. It uses energy to cut plant matter very efficiently." icon = 'icons/obj/items/borg_module/autoharvester.dmi' icon_state = "autoharvester" + max_health = ITEM_HEALTH_NO_DAMAGE /obj/item/robot_harvester/afterattack(var/atom/target, var/mob/living/user, proximity) if(!target) @@ -162,7 +110,7 @@ // Click on table to unload, click on item to load. Otherwise works identically to a tray. // Unlike the base item "tray", robotrays ONLY pick up food, drinks and condiments. -/obj/item/storage/tray/robotray +/obj/item/plate/tray/robotray name = "RoboTray" desc = "An autoloading tray specialized for carrying refreshments." @@ -170,14 +118,17 @@ // Allows service droids to rename paper items. /obj/item/pen/robopen - desc = "A black ink printing attachment with a paper naming mode." - name = "Printing Pen" + name = "printing pen" var/mode = 1 +/obj/item/pen/robopen/make_pen_description() + desc = "\A [stroke_color_name] [medium_name] printing attachment with a paper naming mode." + /obj/item/pen/robopen/attack_self(mob/user) var/choice = input("Would you like to change colour or mode?") as null|anything in list("Colour","Mode") - if(!choice) return + if(!choice) + return playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) @@ -185,7 +136,8 @@ if("Colour") var/newcolour = input("Which colour would you like to use?") as null|anything in list("black","blue","red","green","yellow") - if(newcolour) colour = newcolour + if(newcolour) + set_medium_color(newcolour, newcolour) if("Mode") if (mode == 1) @@ -202,12 +154,12 @@ /obj/item/pen/robopen/proc/RenamePaper(mob/user, obj/item/paper/paper) if ( !user || !paper ) return - var/n_name = sanitizeSafe(input(user, "What would you like to label the paper?", "Paper Labelling", null) as text, 32) + var/n_name = sanitize_safe(input(user, "What would you like to label the paper?", "Paper Labelling", null) as text, 32) if ( !user || !paper ) return //n_name = copytext(n_name, 1, 32) - if(( get_dist(user,paper) <= 1 && user.stat == 0)) + if(( get_dist(user,paper) <= 1 && user.stat == CONSCIOUS)) paper.SetName("paper[(n_name ? text("- '[n_name]'") : null)]") paper.last_modified_ckey = user.ckey add_fingerprint(user) @@ -217,35 +169,31 @@ /obj/item/form_printer //name = "paperwork printer" name = "paper dispenser" - icon = 'icons/obj/bureaucracy.dmi' + icon = 'icons/obj/items/paper_bin.dmi' icon_state = "paper_bin1" item_state = "sheet-metal" + max_health = ITEM_HEALTH_NO_DAMAGE -/obj/item/form_printer/attack(mob/living/carbon/M, mob/living/carbon/user) - return - -/obj/item/form_printer/afterattack(atom/target, mob/living/user, flag, params) +/obj/item/form_printer/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE - if(!target || !flag) - return - - if(istype(target,/obj/structure/table)) +/obj/item/form_printer/afterattack(atom/target, mob/living/user, proximity, params) + if(istype(target) && !istype(target, /obj/screen) && proximity) deploy_paper(get_turf(target)) /obj/item/form_printer/attack_self(mob/user) deploy_paper(get_turf(src)) /obj/item/form_printer/proc/deploy_paper(var/turf/T) - T.visible_message("\The [src.loc] dispenses a sheet of crisp white paper.") + T.visible_message(SPAN_NOTICE("\The [src.loc] dispenses a sheet of crisp white paper.")) new /obj/item/paper(T) - //Personal shielding for the combat module. /obj/item/borg/combat/shield name = "personal shielding" desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." - icon = 'icons/obj/decals.dmi' - icon_state = "shock" + icon = 'icons/obj/signs/warnings.dmi' + icon_state = "shock-large" var/shield_level = 0.5 //Percentage of damage absorbed by the shield. /obj/item/borg/combat/shield/verb/set_shield_level() @@ -260,8 +208,8 @@ /obj/item/borg/combat/mobility name = "mobility module" desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds." - icon = 'icons/obj/decals.dmi' - icon_state = "shock" + icon = 'icons/obj/signs/warnings.dmi' + icon_state = "shock-large" /obj/item/inflatable_dispenser name = "inflatables dispenser" @@ -269,6 +217,7 @@ icon = 'icons/obj/items/inflatable_dispenser.dmi' icon_state = "inf_deployer" w_class = ITEM_SIZE_LARGE + material = /decl/material/solid/metal/steel var/stored_walls = 5 var/stored_doors = 2 @@ -282,15 +231,16 @@ stored_doors = 5 max_walls = 10 max_doors = 5 + max_health = ITEM_HEALTH_NO_DAMAGE -/obj/item/inflatable_dispenser/examine(mob/user) +/obj/item/inflatable_dispenser/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It has [stored_walls] wall segment\s and [stored_doors] door segment\s stored.") - to_chat(user, "It is set to deploy [mode ? "doors" : "walls"]") + . += "It has [stored_walls] wall segment\s and [stored_doors] door segment\s stored." + . += "It is set to deploy [mode ? "doors" : "walls"]" -/obj/item/inflatable_dispenser/attack_self() +/obj/item/inflatable_dispenser/attack_self(mob/user) mode = !mode - to_chat(usr, "You set \the [src] to deploy [mode ? "doors" : "walls"].") + to_chat(user, "You set \the [src] to deploy [mode ? "doors" : "walls"].") /obj/item/inflatable_dispenser/afterattack(var/atom/A, var/mob/user) ..(A, user) @@ -299,7 +249,7 @@ if(!user.Adjacent(A)) to_chat(user, "You can't reach!") return - if(istype(A, /turf)) + if(isturf(A)) try_deploy_inflatable(A, user) if(istype(A, /obj/item/inflatable) || istype(A, /obj/structure/inflatable)) pick_up(A, user) @@ -344,40 +294,41 @@ visible_message("\The [user] deflates \the [A] with \the [src]!") return if(istype(A, /obj/item/inflatable)) - if(istype(A, /obj/item/inflatable/wall)) - if(stored_walls >= max_walls) - to_chat(user, "\The [src] is full.") + if(istype(A, /obj/item/inflatable/door)) + if(stored_doors >= max_doors) + to_chat(user, "\The [src] is full!") return - stored_walls++ + stored_doors++ qdel(A) else - if(stored_doors >= max_doors) - to_chat(usr, "\The [src] is full!") + if(stored_walls >= max_walls) + to_chat(user, "\The [src] is full.") return - stored_doors++ + stored_walls++ qdel(A) visible_message("\The [user] picks up \the [A] with \the [src]!") return - to_chat(user, "You fail to pick up \the [A] with \the [src]") + to_chat(user, "You fail to pick up \the [A] with \the [src].") return /obj/item/chems/spray/cleaner/drone name = "space cleaner" desc = "BLAM!-brand non-foaming space cleaner!" - volume = 150 + chem_volume = 150 /obj/item/robot_rack name = "a generic robot rack" desc = "A rack for carrying large items as a robot." + max_health = ITEM_HEALTH_NO_DAMAGE var/object_type //The types of object the rack holds (subtypes are allowed). var/interact_type //Things of this type will trigger attack_hand when attacked by this. var/capacity = 1 //How many objects can be held. var/list/obj/item/held = list() //What is being held. -/obj/item/robot_rack/examine(mob/user) +/obj/item/robot_rack/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It can hold up to [capacity] item[capacity == 1 ? "" : "s"].") + . += "It can hold up to [capacity] item\s." /obj/item/robot_rack/Initialize(mapload, starting_objects = 0) . = ..() @@ -388,12 +339,12 @@ if(!length(held)) to_chat(user, "The rack is empty.") return - var/obj/item/R = held[length(held)] - R.dropInto(loc) - held -= R - R.attack_self(user) // deploy it - to_chat(user, "You deploy [R].") - R.add_fingerprint(user) + var/obj/item/rack = held[length(held)] + rack.dropInto(loc) + held -= rack + rack.attack_self(user) // deploy it + to_chat(user, "You deploy [rack].") + rack.add_fingerprint(user) /obj/item/robot_rack/resolve_attackby(obj/O, mob/user, click_params) if(istype(O, object_type)) @@ -405,8 +356,7 @@ to_chat(user, "\The [src] is full and can't store any more items.") return if(istype(O, interact_type)) - O.attack_hand(user) - return + return O.attack_hand(user) . = ..() /obj/item/bioreactor @@ -414,12 +364,13 @@ desc = "An integrated power generator that runs on most kinds of biomass." icon = 'icons/obj/power.dmi' icon_state = "portgen0" + max_health = ITEM_HEALTH_NO_DAMAGE var/base_power_generation = 75 KILOWATTS var/max_fuel_items = 5 var/list/fuel_types = list( - /obj/item/chems/food/snacks/meat = 2, - /obj/item/chems/food/snacks/fish = 1.5 + /obj/item/food/butchery/meat = 2, + /obj/item/food/butchery/meat/fish = 1.5 ) /obj/item/bioreactor/attack_self(var/mob/user) @@ -434,7 +385,7 @@ if(!proximity_flag || !istype(target)) return - var/is_fuel = istype(target, /obj/item/chems/food/snacks/grown) + var/is_fuel = istype(target, /obj/item/food/grown) is_fuel = is_fuel || is_type_in_list(target, fuel_types) if(!is_fuel) @@ -456,8 +407,8 @@ . = ..() /obj/item/bioreactor/Process() - var/mob/living/silicon/robot/R = loc - if(!istype(R) || !R.cell || R.cell.fully_charged() || !contents.len) + var/mob/living/silicon/robot/robot = loc + if(!istype(robot) || !robot.cell || robot.cell.fully_charged() || !contents.len) return var/generating_power @@ -465,10 +416,10 @@ for(var/thing in contents) var/atom/A = thing - if(istype(A, /obj/item/chems/food/snacks/grown)) + if(istype(A, /obj/item/food/grown)) generating_power = base_power_generation using_item = A - else + else for(var/fuel_type in fuel_types) if(istype(A, fuel_type)) generating_power = fuel_types[fuel_type] * base_power_generation @@ -484,4 +435,4 @@ qdel(using_item) if(generating_power) - R.cell.give(generating_power * CELLRATE) + robot.cell.give(generating_power * CELLRATE) diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index 0faa8412ee3c..e38f7b95deb8 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -1,35 +1,20 @@ -/mob/living/silicon/robot/slip_chance(var/prob_slip) - if(module && module.no_slip) - return 0 - ..(prob_slip) +/mob/living/silicon/robot/has_non_slip_footing(obj/item/shoes) + return module?.has_nonslip_feet -/mob/living/silicon/robot/Check_Shoegrip() - if(module && module.no_slip) - return 1 - return 0 +/mob/living/silicon/robot/has_magnetised_footing(obj/item/shoes) + return module?.has_magnetic_feet -/mob/living/silicon/robot/Process_Spacemove() - if(module) - for(var/obj/item/tank/jetpack/J in module.equipment) - if(J && J.allow_thrust(0.01)) - return 1 - . = ..() - - -/mob/living/silicon/robot/Move() - . = ..() - if(. && client) - - var/turf/B = GetAbove(src) - up_hint.icon_state = "uphint[(B ? B.is_open() : 0)]" +/mob/living/silicon/robot/get_jetpack() + return locate(/obj/item/tank/jetpack) in module?.equipment //No longer needed, but I'll leave it here incase we plan to re-use it. -/mob/living/silicon/robot/movement_delay() +/mob/living/silicon/robot/get_movement_delay(var/travel_dir) var/tally = ..() //Incase I need to add stuff other than "speed" later tally += speed - if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) + // Gross, todo slowdown for robots + if(istype(get_active_held_item(), /obj/item/borg/combat/mobility)) tally-=3 - return tally+config.robot_delay + return tally+get_config_value(/decl/config/num/movement_robot) diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index f47da729d9bd..c8c23e0d3c12 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -1,37 +1,27 @@ -/mob/living/silicon/say(var/message, var/sanitize = 1) - return ..(sanitize ? sanitize(message) : message) - -/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - log_say("[key_name(src)] : [message]") +/mob/living/silicon/get_radios(var/message_mode) + . = ..() + if(message_mode && silicon_radio) + LAZYDISTINCTADD(., silicon_radio) + +/mob/living/silicon/robot/get_radios(var/message_mode) + . = ..() + if((silicon_radio in .) && !is_component_functioning("radio")) + to_chat(src, SPAN_WARNING("Your radio isn't functional at this time.")) + LAZYREMOVE(., silicon_radio) + +/mob/living/silicon/ai/handle_mob_specific_speech(message, message_mode, verb = "says", decl/language/speaking) + if(message_mode == MESSAGE_MODE_DEPARTMENT) + holopad_talk(message, verb, speaking) + return TRUE + return ..() -/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - ..() - if(message_mode) - if(!is_component_functioning("radio")) - to_chat(src, "Your radio isn't functional at this time.") - return 0 - if(message_mode == "general") - message_mode = null - return silicon_radio.talk_into(src,message,message_mode,verb,speaking) - -/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - ..() - if(message_mode == "department") - return holopad_talk(message, verb, speaking) - else if(message_mode) - if (ai_radio.disabledAi || !has_power() || stat) - to_chat(src, "System Error - Transceiver Disabled.") - return 0 - if(message_mode == "general") - message_mode = null - return ai_radio.talk_into(src,message,message_mode,verb,speaking) - -/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) - ..() - if(message_mode) - if(message_mode == "general") - message_mode = null - return silicon_radio.talk_into(src,message,message_mode,verb,speaking) +/mob/living/silicon/ai/get_radios(var/message_mode) + . = ..() + if(ai_radio) + if(ai_radio.disabledAi || !has_power() || stat) + to_chat(src, SPAN_DANGER("System Error - Transceiver Disabled.")) + else + LAZYDISTINCTADD(., ai_radio) /mob/living/silicon/say_quote(var/text) var/ending = copytext(text, length(text)) @@ -45,16 +35,8 @@ #define IS_ROBOT 2 #define IS_PAI 3 -/mob/living/silicon/say_understands(var/other,var/decl/language/speaking = null) - //These only pertain to common. Languages are handled by mob/say_understands() - if (!speaking) - if (istype(other, /mob/living/carbon)) - return 1 - if (istype(other, /mob/living/silicon)) - return 1 - if (istype(other, /mob/living/carbon/brain)) - return 1 - return ..() +/mob/living/silicon/say_understands(mob/speaker, decl/language/speaking) + return (!speaking && (ishuman(speaker) || issilicon(speaker) || isbrain(speaker))) || ..() //For holopads only. Usable by AI. /mob/living/silicon/ai/proc/holopad_talk(var/message, verb, decl/language/speaking) @@ -86,7 +68,7 @@ var/list/hearturfs = list() for(var/I in hear) - if(istype(I, /mob/)) + if(ismob(I)) var/mob/M = I listening += M hearturfs += M.locs[1] @@ -98,12 +80,12 @@ listening_obj |= O - for(var/mob/M in GLOB.player_list) - if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) - M.hear_say(message,verb,speaking,null,null, src) + for(var/mob/M in global.player_list) + if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == PREF_ALL_SPEECH) + M.hear_say(message,verb,speaking, null, src) continue if(M.loc && (M.locs[1] in hearturfs)) - M.hear_say(message,verb,speaking,null,null, src) + M.hear_say(message,verb,speaking, null, src) else @@ -122,11 +104,10 @@ var/obj/machinery/hologram/holopad/T = src.holo if(T && T.masters[src]) + var/turf/our_turf = get_turf(T) var/rendered = "[name] [message]" to_chat(src, "Holopad action relayed, [real_name] [message]") - - for(var/mob/M in viewers(T.loc)) - M.show_message(rendered, 2) + our_turf.audible_message(rendered) else //This shouldn't occur, but better safe then sorry. to_chat(src, "No holopad connected.") return 0 @@ -135,3 +116,6 @@ #undef IS_AI #undef IS_ROBOT #undef IS_PAI + +/mob/living/silicon/binarycheck() + . = TRUE diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index ddea0770bd7b..b5508d6d2217 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,22 +1,15 @@ /mob/living/silicon gender = NEUTER - voice_name = "synthesized voice" skillset = /datum/skillset/silicon + butchery_data = /decl/butchery_data/synthetic - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 - + var/dexterity = DEXTERITY_FULL var/syndicate = 0 var/const/MAIN_CHANNEL = "Main Frequency" var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws var/list/stating_laws = list()// Channels laws are currently being stated on var/obj/item/radio/silicon_radio - var/list/hud_list[10] var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer //Used in say.dm. @@ -32,32 +25,32 @@ var/next_alarm_notice var/list/datum/alarm/queued_alarms = new() - var/list/access_rights var/obj/item/card/id/idcard = /obj/item/card/id/synthetic - // Various machinery stock parts used by stuff like NTOS (should be merged with above at some point) + // Various machinery stock parts used by stuff like OS (should be merged with above at some point) var/list/stock_parts = list() var/list/starting_stock_parts = list( /obj/item/stock_parts/computer/processor_unit, /obj/item/stock_parts/computer/hard_drive/silicon, /obj/item/stock_parts/computer/network_card ) - var/ntos_type = /datum/extension/interactive/ntos/silicon + var/os_type = /datum/extension/interactive/os/silicon #define SEC_HUD 1 //Security HUD mode #define MED_HUD 2 //Medical HUD mode /mob/living/silicon/Initialize() - GLOB.silicon_mob_list += src + reset_hud_overlays() + global.silicon_mob_list += src . = ..() - if(silicon_radio) + if(ispath(silicon_radio)) silicon_radio = new silicon_radio(src) - if(silicon_camera) + if(ispath(silicon_camera)) silicon_camera = new silicon_camera(src) for(var/T in starting_stock_parts) stock_parts += new T(src) - if(ntos_type) - set_extension(src, ntos_type) + if(os_type) + set_extension(src, os_type) verbs |= /mob/living/silicon/proc/access_computer add_language(/decl/language/human/common) @@ -66,16 +59,18 @@ init_subsystems() /mob/living/silicon/Destroy() - GLOB.silicon_mob_list -= src + global.silicon_mob_list -= src QDEL_NULL(silicon_radio) QDEL_NULL(silicon_camera) + QDEL_NULL(idcard) for(var/datum/alarm_handler/AH in SSalarm.all_handlers) AH.unregister_alarm(src) + QDEL_NULL_LIST(stock_parts) return ..() /mob/living/silicon/fully_replace_character_name(new_name) ..() - create_or_rename_email(new_name, "root.rt") + create_or_update_account(new_name) if(istype(idcard)) idcard.registered_name = new_name @@ -88,74 +83,63 @@ return /mob/living/silicon/drop_item(var/Target) - for(var/obj/item/grab/grab in get_active_grabs()) + for(var/obj/item/grab/grab as anything in get_active_grabs()) qdel(grab) - . = TRUE - + return TRUE + return ..() + /mob/living/silicon/emp_act(severity) switch(severity) if(1) - src.take_organ_damage(0,16,emp=1) - if(prob(50)) Stun(rand(5,10)) - else confused = (min(confused + 2, 40)) + src.take_organ_damage(0, 16, bypass_armour = TRUE) + if(prob(50)) + SET_STATUS_MAX(src, STAT_STUN, rand(5,10)) + else + ADJ_STATUS(src, STAT_CONFUSE, rand(2,40)) if(2) - src.take_organ_damage(0,7,emp=1) - confused = (min(confused + 2, 30)) + src.take_organ_damage(0, 7, bypass_armour = TRUE) + ADJ_STATUS(src, STAT_CONFUSE, rand(2,30)) flash_eyes(affect_silicon = 1) to_chat(src, "*BZZZT*") to_chat(src, "Warning: Electromagnetic pulse detected.") ..() -/mob/living/silicon/stun_effect_act(var/stun_amount, var/agony_amount) +/mob/living/silicon/stun_effect_act(stun_amount, agony_amount, def_zone, used_weapon) return //immune -/mob/living/silicon/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, def_zone = null) - - if (istype(source, /obj/machinery/containment_field)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, loc) - s.start() - - shock_damage *= 0.75 //take reduced damage - take_overall_damage(0, shock_damage) - visible_message("\The [src] was shocked by \the [source]!", \ - "Energy pulse detected, system damaged!", \ - "You hear an electrical crack") - if(prob(20)) - Stun(2) - return - -/mob/living/silicon/proc/damage_mob(var/brute = 0, var/fire = 0, var/tox = 0) - return +/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, def_zone) + shock_damage = ..() + if(shock_damage <= 0 || !istype(source, /obj/effect/containment_field)) + return 0 + spark_at(loc, amount=5, cardinal_only = TRUE) + shock_damage *= 0.75 //take reduced damage + take_overall_damage(0, shock_damage) + visible_message( + SPAN_DANGER("\The [src] was shocked by \the [source]!"), + SPAN_DANGER("Energy pulse detected, system damaged!"), + SPAN_DANGER("You hear an electrical crack.") + ) + if(prob(20)) + SET_STATUS_MAX(src, STAT_STUN, 2) + return shock_damage /mob/living/silicon/bullet_act(var/obj/item/projectile/Proj) - if(!Proj.nodamage) - switch(Proj.damage_type) + switch(Proj.atom_damage_type) if(BRUTE) - adjustBruteLoss(Proj.damage) + take_damage(Proj.get_projectile_damage(src)) if(BURN) - adjustFireLoss(Proj.damage) - + take_damage(Proj.get_projectile_damage(src), BURN) Proj.on_hit(src,100) //wow this is a terrible hack - updatehealth() return 100 /mob/living/silicon/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now -/proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai) - if(!istype(bot) || !istype(ai)) - return 0 - if (bot.connected_ai == ai) - return 1 - return 0 - - // this function shows the health of the AI in the Status panel /mob/living/silicon/proc/show_system_integrity() if(!src.stat) - stat(null, text("System integrity: [round((health/maxHealth)*100)]%")) + stat(null, text("System integrity: [get_health_percent()]%")) else stat(null, text("Systems nonfunctional")) @@ -182,9 +166,8 @@ //can't inject synths /mob/living/silicon/can_inject(var/mob/user, var/target_zone) - to_chat(user, "The armoured plating is too tough.") - return 0 - + to_chat(user, SPAN_WARNING("The armoured plating is too tough.")) + return FALSE //Silicon mob language procs @@ -194,7 +177,7 @@ /mob/living/silicon/add_language(var/language, var/can_speak=1) if(!ispath(language, /decl/language)) return - var/decl/language/added_language = decls_repository.get_decl(language) + var/decl/language/added_language = GET_DECL(language) if(!added_language) return @@ -206,7 +189,7 @@ /mob/living/silicon/remove_language(var/rem_language) if(!ispath(rem_language, /decl/language)) return - var/decl/language/removed_language = decls_repository.get_decl(rem_language) + var/decl/language/removed_language = GET_DECL(rem_language) if(!removed_language) return @@ -221,11 +204,11 @@ var/dat = "Known Languages

    " if(default_language) - var/decl/language/lang = decls_repository.get_decl(default_language) + var/decl/language/lang = GET_DECL(default_language) dat += "Current default language: [lang.name] - reset

    " for(var/decl/language/L in languages) - if(!(L.flags & NONGLOBAL)) + if(!(L.flags & LANG_FLAG_NONGLOBAL)) var/default_str if(L == default_language) default_str = " - default - reset" @@ -265,9 +248,6 @@ flavor_text = sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text) -/mob/living/silicon/binarycheck() - return 1 - /mob/living/silicon/explosion_act(severity) ..() var/brute @@ -285,7 +265,10 @@ apply_damage(burn, BURN, damage_flags = DAM_EXPLODE) /mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised) - if(!(alarm.alarm_z() in GetConnectedZlevels(get_z(src)))) + var/my_z = get_z(src) + if(!my_z) + return + if(!(alarm.alarm_z() in SSmapping.get_connected_levels(my_z))) return // Didn't actually hear it as far as we're concerned. if(!next_alarm_notice) next_alarm_notice = world.time + SecondsToTicks(10) @@ -329,7 +312,7 @@ to_chat(src, "\The [A.alarm_name()].") if(alarm_raised) - to_chat(src, "\[Show Alerts\]") + to_chat(src, "\[Show Alerts\]") for(var/datum/alarm_handler/AH in queued_alarms) var/list/alarms = queued_alarms[AH] @@ -341,18 +324,12 @@ /mob/living/silicon/ai/raised_alarm(var/datum/alarm/A) var/cameratext = "" for(var/obj/machinery/camera/C in A.cameras()) - cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]" + cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]" to_chat(src, "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])") -/mob/living/silicon/proc/is_traitor() - return mind && (mind in GLOB.traitors.current_antagonists) - -/mob/living/silicon/adjustEarDamage() - return - -/mob/living/silicon/setEarDamage() - return +/mob/living/silicon/proc/is_malfunctioning() + return FALSE /mob/living/silicon/reset_view() ..() @@ -366,9 +343,9 @@ mind.assigned_job.clear_slot() if(mind.objectives.len) qdel(mind.objectives) - mind.special_role = null + mind.assigned_special_role = null clear_antag_roles(mind) - ghostize(0) + ghostize(CORPSE_CANNOT_REENTER) qdel(src) /mob/living/silicon/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) @@ -380,27 +357,27 @@ /mob/living/silicon/get_bullet_impact_effect_type(var/def_zone) return BULLET_IMPACT_METAL - + /mob/living/silicon/proc/get_computer_network() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) return os.get_network() -/mob/living/silicon/proc/try_stock_parts_install(obj/item/stock_parts/W, mob/user) - if(istype(W) && user.unEquip(W)) - W.forceMove(src) - stock_parts += W - to_chat(usr, "You install the [W.name].") +/mob/living/silicon/proc/try_stock_parts_install(obj/item/stock_parts/used_item, mob/user) + if(istype(used_item) && user.try_unequip(used_item)) + used_item.forceMove(src) + stock_parts += used_item + to_chat(user, "You install the [used_item.name].") return TRUE -/mob/living/silicon/proc/try_stock_parts_removal(obj/item/W, mob/user) - if(!isCrowbar(W) || user.a_intent == I_HURT) +/mob/living/silicon/proc/try_stock_parts_removal(obj/item/used_item, mob/user) + if(!IS_CROWBAR(used_item) || user.check_intent(I_FLAG_HARM)) return if(!length(stock_parts)) - to_chat(user, SPAN_WARNING("No parts left to remove")) + to_chat(user, SPAN_WARNING("There are no parts in \the [src] left to remove.")) return - + var/obj/item/stock_parts/remove = input(user, "Which component do you want to pry out?", "Remove Component") as null|anything in stock_parts if(!remove || !(remove in stock_parts) || !Adjacent(user)) return @@ -411,21 +388,76 @@ /mob/living/silicon/proc/access_computer() set category = "Silicon Commands" - set name = "Boot NTOS Device" + set name = "Boot OS Device" if(incapacitated()) to_chat(src, SPAN_WARNING("You are in no state to do that right now.")) return - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(!istype(os)) - to_chat(src, SPAN_WARNING("You seem to be lacking an NTOS capable device!")) + to_chat(src, SPAN_WARNING("You seem to be lacking an OS capable device!")) return - + if(!os.on) os.system_boot() if(!os.on) - to_chat(src, SPAN_WARNING("ERROR: NTOS failed to boot.")) + to_chat(src, SPAN_WARNING("ERROR: OS failed to boot.")) return os.ui_interact(src) + +/mob/living/silicon/get_admin_job_string() + return "Silicon-based" + +/mob/living/silicon/proc/process_os() + var/datum/extension/interactive/os = get_extension(src, /datum/extension/interactive/os) + if(os) + os.Process() + +/mob/living/silicon/handle_flashed(var/flash_strength, do_stun = FALSE) + SET_STATUS_MAX(src, STAT_PARA, flash_strength) + SET_STATUS_MAX(src, STAT_WEAK, flash_strength) + return TRUE + +/mob/living/silicon/get_speech_bubble_state_modifier() + return "synth" + +/mob/living/silicon/GetIdCards(list/exceptions) + . = ..() + // Unconscious, dead or once possessed but now client-less silicons are not considered to have id access. + // This seems to be specifically to stop ghosted maintenance drones being used as free all-access cards. + if(istype(idcard) && !stat && !(ckey && !client) && !is_type_in_list(idcard, exceptions)) + LAZYDISTINCTADD(., idcard) + +/mob/living/silicon/get_life_damage_types() + var/static/list/life_damage_types = list( + BURN, + BRUTE + ) + return life_damage_types + +/mob/living/silicon/get_dexterity(var/silent) + return dexterity + +/mob/living/silicon/robot/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected) + . = ..() + if(.) + adjustBruteLoss(5, do_update_health = FALSE) + adjustFireLoss(10) + +/mob/living/silicon/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing + ) + return available_postures + +/mob/living/silicon/try_awaken(mob/user) + return FALSE + +/mob/living/silicon/handle_stance() + stance_damage = 0 + return + +/mob/living/silicon/isSynthetic() + return TRUE diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm index b5c671b5dca8..abfa441caae8 100644 --- a/code/modules/mob/living/silicon/subsystems.dm +++ b/code/modules/mob/living/silicon/subsystems.dm @@ -30,7 +30,7 @@ if(/datum/nano_module/alarm_monitor/all in silicon_subsystems) for(var/datum/alarm_handler/AH in SSalarm.all_handlers) - AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm) + AH.register_alarm(src, TYPE_PROC_REF(/mob/living/silicon, receive_alarm)) queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order /mob/living/silicon/proc/init_subsystem(var/subsystem_type) @@ -38,7 +38,7 @@ if(existing_entry && !ispath(existing_entry)) return FALSE - var/ui_state = subsystem_type == /datum/nano_module/law_manager ? GLOB.conscious_state : GLOB.self_state + var/ui_state = subsystem_type == /datum/nano_module/law_manager ? global.conscious_topic_state : global.self_topic_state var/stat_silicon_subsystem/SSS = new(src, subsystem_type, ui_state) silicon_subsystems[subsystem_type] = SSS silicon_subsystems_by_name[SSS.name] = SSS @@ -82,14 +82,6 @@ var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] stat(SSS) -/mob/living/silicon/proc/get_subsystem_from_path(subsystem_type) - var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] - if(!istype(SSS)) - return 0 - if(!istype(SSS.subsystem, subsystem_type)) - return 0 - return SSS.subsystem - /stat_silicon_subsystem parent_type = /atom/movable simulated = 0 diff --git a/code/modules/mob/living/simple_animal/_simple_animal.dm b/code/modules/mob/living/simple_animal/_simple_animal.dm new file mode 100644 index 000000000000..7b62adcc2ed0 --- /dev/null +++ b/code/modules/mob/living/simple_animal/_simple_animal.dm @@ -0,0 +1,620 @@ +/mob/living/simple_animal + name = "animal" + max_health = 20 + universal_speak = FALSE + mob_sort_value = 12 + + mob_bump_flag = SIMPLE_ANIMAL + mob_swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL + mob_push_flags = MONKEY|SLIME|SIMPLE_ANIMAL + + icon_state = ICON_STATE_WORLD + buckle_pixel_shift = @'{"x":0,"y":0,"z":8}' + + hud_used = /datum/hud/animal + + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) + + // Set to TRUE to ignore slipping while EVA + var/skip_spacemove = FALSE + + /// Added to the delay expected from movement decls. + var/base_movement_delay = 0 + + /// Can this mob in theory have a mob riding it? + var/can_have_rider = TRUE + /// If the mob can be ridden, what is the largest size of rider? + var/max_rider_size = MOB_SIZE_SMALL + + /// Does the percentage health show in the stat panel for the mob? + var/show_stat_health = TRUE + + //Interaction + var/response_help_1p = "You pet $TARGET$." + var/response_help_3p = "$USER$ pets $TARGET$." + var/response_disarm = "pushes aside" + var/response_harm = "kicks" + var/harm_intent_damage = 3 + + //Temperature effect + var/minbodytemp = 250 + var/maxbodytemp = 350 + var/heat_damage_per_tick = 3 //amount of damage applied if animal's body temperature is higher than maxbodytemp + var/cold_damage_per_tick = 2 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp + + //Atmos effect - Yes, you can make creatures that require arbitrary gasses to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage + var/list/min_gas = list(/decl/material/gas/oxygen = 5) + var/list/max_gas = list( + /decl/material/gas/chlorine = 1, + /decl/material/gas/carbon_dioxide = 5 + ) + + var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above + + //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly + var/obj/item/natural_weapon/natural_weapon + var/environment_smash = 0 + var/resistance = 0 // Damage reduction + var/armor_type = /datum/extension/armor + var/list/natural_armor //what armor animal has + var/is_aquatic = FALSE + + //Null rod stuff + var/supernatural = 0 + var/purge = 0 + + var/bleed_ticks = 0 + var/bleed_colour = COLOR_BLOOD_HUMAN + var/can_bleed = TRUE + + //for simple animals with abilities, mostly megafauna + var/ability_cooldown + + //for simple animals that reflect damage when attacked in melee + var/return_damage_min + var/return_damage_max + + var/glowing_eyes = FALSE + var/mob_icon_state_flags = 0 + + var/scannable_result // Codex page generated when this mob is scanned. + var/base_animal_type // set automatically in Initialize(), used for language checking. + + // By default, simple mobs should attack slightly slower than players, allowing a suitably attentive + // player to dodge/kite if they're paying attention, and not letting themselves get cornered/incapacitated. + var/attack_delay = DEFAULT_ATTACK_COOLDOWN * 1.3 + + // Base percentage chance to hit in melee against another mob, if controlled by an AI. + var/telegraphed_melee_accuracy = 85 + + // Visible message shown when the mob dies. + var/death_message = "dies!" + + // Ranged attack handling vars. + var/burst_projectile = FALSE + var/projectiletype + var/projectilesound + var/casingtype + var/fire_desc = "fires" //"X fire_desc at Y!" + var/ranged_range = 6 //tiles of range for ranged attackers to attack + + // Associative list of colors to state modifiers to draw over the top of this creature's base icon. + var/list/draw_visible_overlays + var/eye_color + + var/list/ability_handlers + +/mob/living/simple_animal/Initialize() + . = ..() + + // Deserialize any JSON payload for our overlays. + if(istext(draw_visible_overlays)) + draw_visible_overlays = cached_json_decode(draw_visible_overlays) + if(!islist(draw_visible_overlays)) + draw_visible_overlays = null + if(isnull(draw_visible_overlays)) + var/list/defaults = get_default_animal_colours() + draw_visible_overlays = defaults?.Copy() // do not mutate static list + + if(length(ability_handlers)) + for(var/handler in ability_handlers) + add_ability_handler(handler) + + // Aquatic creatures only care about water, not atmos. + add_inventory_slot(new /datum/inventory_slot/head/simple) + + if(is_aquatic) + max_gas = list() + min_gas = list() + minbodytemp = 0 + + check_mob_icon_states(TRUE) + if(length(draw_visible_overlays)) + update_icon() + + if(isnull(base_animal_type)) + base_animal_type = type + if(LAZYLEN(natural_armor)) + set_extension(src, armor_type, natural_armor) + if(scannable_result) + set_extension(src, /datum/extension/scannable, scannable_result) + setup_languages() + +/mob/living/simple_animal/proc/setup_languages() + add_language(/decl/language/animal) + +/mob/living/simple_animal/proc/apply_attack_effects(mob/living/target) + set waitfor = FALSE + return + +var/global/list/simplemob_icon_bitflag_cache = list() +/mob/living/simple_animal/proc/check_mob_icon_states(var/sa_initializing = FALSE) + if(sa_initializing) // Let people force-rebuild the mob cache with proccall if needed. + mob_icon_state_flags = global.simplemob_icon_bitflag_cache[type] + else + mob_icon_state_flags = null + if(isnull(mob_icon_state_flags)) + mob_icon_state_flags = 0 + if(check_state_in_icon("world", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_LIVING_STATE + if(check_state_in_icon("world-dead", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_DEAD_STATE + if(check_state_in_icon("world-sleeping", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_SLEEP_STATE + if(check_state_in_icon("world-resting", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_REST_STATE + if(check_state_in_icon("world-sitting", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_SITTING_STATE + if(check_state_in_icon("world-gib", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_GIB_STATE + if(check_state_in_icon("world-dust", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_DUST_STATE + if(check_state_in_icon("world-paralyzed", icon)) + mob_icon_state_flags |= MOB_ICON_HAS_PARALYZED_STATE + global.simplemob_icon_bitflag_cache[type] = mob_icon_state_flags + +/mob/living/simple_animal/proc/add_additional_visible_overlays(list/accumulator) + return + +/mob/living/simple_animal/refresh_visible_overlays() + + var/list/add_overlays = list() + if(length(draw_visible_overlays)) + for(var/overlay_state in draw_visible_overlays) + var/overlay_color = draw_visible_overlays[overlay_state] + if(overlay_state == "base") + add_overlays += overlay_image(icon, icon_state, overlay_color, RESET_COLOR) + else + add_overlays += overlay_image(icon, "[icon_state]-[overlay_state]", overlay_color, RESET_COLOR) + + add_additional_visible_overlays(add_overlays) + + if(length(add_overlays)) + set_current_mob_overlay(HO_SKIN_LAYER, add_overlays) + else + set_current_mob_overlay(HO_SKIN_LAYER, null) + + z_flags &= ~ZMM_MANGLE_PLANES + if(stat == CONSCIOUS) + var/image/I = get_eye_overlay() + if(I && glowing_eyes) + z_flags |= ZMM_MANGLE_PLANES + set_current_mob_overlay(HO_GLASSES_LAYER, I) + else + set_current_mob_overlay(HO_GLASSES_LAYER, null) + + . = ..() + +/mob/living/simple_animal/on_update_icon() + icon_state = ICON_STATE_WORLD + if(stat != DEAD && HAS_STATUS(src, STAT_PARA) && (mob_icon_state_flags & MOB_ICON_HAS_PARALYZED_STATE)) + icon_state += "-paralyzed" + else if(stat == DEAD && (mob_icon_state_flags & MOB_ICON_HAS_DEAD_STATE)) + icon_state += "-dead" + else if(stat == UNCONSCIOUS && (mob_icon_state_flags & MOB_ICON_HAS_SLEEP_STATE)) + icon_state += "-sleeping" + else if(istype(current_posture, /decl/posture/sitting) && (mob_icon_state_flags & MOB_ICON_HAS_SITTING_STATE)) + icon_state += "-sitting" + else if(current_posture?.prone && (mob_icon_state_flags & MOB_ICON_HAS_REST_STATE)) + icon_state += "-resting" + ..() + +/mob/living/simple_animal/get_eye_colour() + return eye_color || ..() + +/mob/living/simple_animal/get_eye_overlay() + var/eye_icon_state = "[icon_state]-eyes" + if(check_state_in_icon(eye_icon_state, icon)) + var/image/I = (glowing_eyes ? emissive_overlay(icon, eye_icon_state) : image(icon, eye_icon_state)) + I.appearance_flags = RESET_COLOR + I.color = get_eye_colour() + return I + +/mob/living/simple_animal/Destroy() + if(istype(natural_weapon)) + QDEL_NULL(natural_weapon) + . = ..() + +/mob/living/simple_animal/handle_regular_status_updates() + + if(purge) + purge -= 1 + + . = ..() + if(.) + if(can_bleed && bleed_ticks > 0) + handle_bleeding() + if(is_aquatic && !submerged()) + stop_automove() + if(HAS_STATUS(src, STAT_PARA) <= 2) // gated to avoid redundant update_icon() calls. + SET_STATUS_MAX(src, STAT_PARA, 3) + update_icon() + else + // Cancel any trailing walking if we're dead. + stop_automove() + +/mob/living/simple_animal/handle_some_updates() + . = ..() && (!z || living_observers_present(SSmapping.get_connected_levels(z))) + +/mob/living/simple_animal/turf_is_safe(turf/target) + if((. = ..()) && is_aquatic != target.submerged()) + return FALSE + +/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment) + . = ..() + var/atmos_suitable = TRUE + if(environment) + // don't bother checking it twice if we got a supplied FALSE val. + if(atmos_suitable) + if(is_aquatic) + atmos_suitable = submerged() + else if(LAZYLEN(min_gas)) + for(var/gas in min_gas) + if(environment.gas[gas] < min_gas[gas]) + atmos_suitable = FALSE + break + if(atmos_suitable && LAZYLEN(max_gas)) + for(var/gas in max_gas) + if(environment.gas[gas] > max_gas[gas]) + atmos_suitable = FALSE + break + //Atmos effect + if(!has_genetic_condition(GENE_COND_SPACE_RESISTANCE) && abs(environment.temperature - bodytemperature) > 40) + bodytemperature += ((environment.temperature - bodytemperature) / 5) + + if(bodytemperature < minbodytemp) + SET_HUD_ALERT(src, HUD_FIRE, 2) + take_damage(cold_damage_per_tick, BURN) + else if(bodytemperature > maxbodytemp) + SET_HUD_ALERT(src, HUD_FIRE, 1) + take_damage(heat_damage_per_tick, BURN) + else + SET_HUD_ALERT(src, HUD_FIRE, 0) + + if(!atmos_suitable) + take_damage(unsuitable_atmos_damage) + +/mob/living/simple_animal/get_mob_temperature_threshold(threshold, bodypart) + if(threshold >= HEAT_LEVEL_1) + return maxbodytemp + if(threshold <= COLD_LEVEL_1) + return minbodytemp + return ..() + +/mob/living/simple_animal/get_gibbed_icon() + return icon + +/mob/living/simple_animal/get_gibbed_state(dusted) + if(dusted) + return (mob_icon_state_flags & MOB_ICON_HAS_DUST_STATE) ? "world-dust" : null + return (mob_icon_state_flags & MOB_ICON_HAS_GIB_STATE) ? "world-gib" : null + +/mob/living/simple_animal/proc/visible_emote(var/act_desc) + custom_emote(1, act_desc) + +/mob/living/simple_animal/proc/audible_emote(var/act_desc) + custom_emote(2, act_desc) + +/mob/living/simple_animal/get_hug_zone_messages(var/zone) + . = ..() || list(response_help_3p, response_help_1p) + +/mob/living/simple_animal/default_help_interaction(mob/user) + if(current_health > 0 && user.attempt_hug(src)) + user.update_personal_goal(/datum/goal/achievement/specific_object/pet, type) + return TRUE + . = ..() + +/mob/living/simple_animal/default_disarm_interaction(mob/user) + . = ..() + if(!.) + user.visible_message(SPAN_NOTICE("\The [user] [response_disarm] \the [src].")) + user.do_attack_animation(src) + return TRUE + +/mob/living/simple_animal/default_hurt_interaction(mob/user) + . = ..() + if(!.) + var/dealt_damage = harm_intent_damage + var/harm_verb = response_harm + var/damage_flags + var/damage_type + if(ishuman(user)) + var/mob/living/human/H = user + var/decl/natural_attack/attack = H.get_unarmed_attack(src) + if(istype(attack)) + dealt_damage = attack.damage <= dealt_damage ? dealt_damage : attack.damage + harm_verb = pick(attack.attack_verb) + damage_flags = attack.get_damage_flags() + damage_type = attack.get_damage_type() + take_damage(dealt_damage, damage_type, damage_flags = damage_flags, inflicter = user) + user.visible_message(SPAN_DANGER("\The [user] [harm_verb] \the [src]!")) + user.do_attack_animation(src) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return TRUE + +/mob/living/simple_animal/attackby(var/obj/item/used_item, var/mob/user) + + if(istype(used_item, /obj/item/stack/medical)) + if(stat != DEAD) + var/obj/item/stack/medical/MED = used_item + if(!MED.animal_heal) + to_chat(user, SPAN_WARNING("\The [MED] won't help \the [src] at all!")) + else if(current_health < get_max_health() && MED.can_use(1)) + heal_damage(BRUTE, MED.animal_heal) + visible_message(SPAN_NOTICE("\The [user] applies \the [MED] to \the [src].")) + MED.use(1) + else + var/decl/pronouns/pronouns = get_pronouns() + to_chat(user, SPAN_WARNING("\The [src] is dead, medical items won't bring [pronouns.him] back to life.")) + return TRUE + + return ..() + +/mob/living/simple_animal/get_movement_delay(var/travel_dir) + . = max(1, ..() + base_movement_delay + get_config_value(/decl/config/num/movement_animal)) + //Purged creatures will move more slowly. The more time before their purge stops, the slower they'll move. + if(purge) + . *= purge + +/mob/living/simple_animal/Stat() + . = ..() + + if(statpanel("Status") && show_stat_health) + stat(null, "Health: [get_health_percent()]%") + +/mob/living/simple_animal/get_death_message(gibbed) + if(!gibbed && death_message) + return death_message + return ..() + +/mob/living/simple_animal/death(gibbed) + . = ..() + if(.) + density = FALSE + +/mob/living/simple_animal/explosion_act(severity) + ..() + var/damage + switch(severity) + if(1) + damage = 500 + if(2) + damage = 120 + if(3) + damage = 30 + apply_damage(damage, BRUTE, damage_flags = DAM_EXPLODE) + +/mob/living/simple_animal/say(var/message) + var/verb = "says" + if(speak_emote.len) + verb = pick(speak_emote) + + message = sanitize(message) + + ..(message, null, verb) + +/mob/living/simple_animal/is_burnable() + return heat_damage_per_tick + +/mob/living/simple_animal/proc/adjustBleedTicks(var/amount) + if(!can_bleed) + return + + if(amount > 0) + bleed_ticks = max(bleed_ticks, amount) + else + bleed_ticks = max(bleed_ticks + amount, 0) + + bleed_ticks = round(bleed_ticks) + +/mob/living/simple_animal/get_blood_color() + return bleed_colour + +/mob/living/simple_animal/proc/handle_bleeding() + bleed_ticks-- + take_damage(1) + blood_splatter(get_turf(src), src, FALSE) + +/mob/living/simple_animal/get_digestion_product() + return /decl/material/liquid/nutriment + +/mob/living/simple_animal/proc/reflect_unarmed_damage(var/mob/living/human/attacker, var/damage_type, var/description) + if(attacker.check_intent(I_FLAG_HARM)) + attacker.apply_damage(rand(return_damage_min, return_damage_max), damage_type, attacker.get_active_held_item_slot(), used_weapon = description) + if(rand(25)) + to_chat(attacker, SPAN_WARNING("Your attack has no obvious effect on \the [src]'s [description]!")) + +/mob/living/simple_animal/proc/get_natural_weapon() + if(ispath(natural_weapon)) + natural_weapon = new natural_weapon(src) + return natural_weapon + +/mob/living/simple_animal/get_admin_job_string() + return "Animal" + +/mob/living/simple_animal/get_speech_bubble_state_modifier() + return ..() || "rough" + +/mob/living/simple_animal/can_act() + return ..() && !(is_aquatic && !submerged()) + +/mob/living/simple_animal/experiences_hunger_and_thirst() + // return !supernatural && !isSynthetic() + return FALSE // They need a reliable way to recover nutrition/hydration before this is made general. + +/mob/living/simple_animal/get_nutrition() + return get_max_nutrition() + +/mob/living/simple_animal/get_hydration() + return get_max_hydration() + +/// Adapts our temperature and atmos thresholds to our current z-level. +/mob/living/simple_animal/proc/adapt_to_current_level() + var/turf/T = get_turf(src) + if(!T) + return + + var/datum/level_data/level_data = SSmapping.levels_by_z[T.z] + if(!level_data) + return + + bodytemperature = level_data.exterior_atmos_temp + minbodytemp = bodytemperature - 20 + maxbodytemp = bodytemperature + 20 + + // Adapt atmosphere if necessary. + if(!min_gas && !max_gas) + return + + if(min_gas) + min_gas.Cut() + if(max_gas) + max_gas.Cut() + if(!level_data.exterior_atmosphere) + return + + for(var/gas in level_data.exterior_atmosphere.gas) + var/gas_amt = level_data.exterior_atmosphere.gas[gas] + if(min_gas) + min_gas[gas] = round(gas_amt * 0.5) + if(max_gas) + min_gas[gas] = round(gas_amt * 1.5) + +// Simple filler bodytype so animals get offsets for their inventory slots. +/decl/bodytype/animal + abstract_type = /decl/bodytype/animal + name = "animal" + bodytype_flag = 0 + bodytype_category = "animal body" + +/decl/bodytype/quadruped/animal + abstract_type = /decl/bodytype/quadruped/animal + name = "quadruped animal" + bodytype_flag = 0 + bodytype_category = "quadrupedal animal body" + // Simple animal bodies don't have limbs or organs, currently. If that changes, remove or modify these overrides. + // These overrides prevent unnecessary processing. + has_limbs = list() + has_organ = list() + // Simple animals go through a different breathing process (handle_environment) than mobs that use organs do. + breathing_organ = null + +/mob/living/simple_animal/get_base_telegraphed_melee_accuracy() + return telegraphed_melee_accuracy + +/mob/living/simple_animal/check_has_mouth() + return TRUE + +/mob/living/simple_animal/can_buckle_mob(var/mob/living/dropping) + . = ..() && can_have_rider && (dropping.mob_size <= max_rider_size) + +/mob/living/simple_animal/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing, + /decl/posture/lying, + /decl/posture/lying/deliberate + ) + return available_postures + +/mob/living/simple_animal/get_default_3p_hug_message(mob/living/target) + return "$USER$ nuzzles $TARGET$." + +/mob/living/simple_animal/get_default_1p_hug_message(mob/living/target) + return "You nuzzle $TARGET$." + +/mob/living/simple_animal/handle_stance() + stance_damage = 0 + return + +/mob/living/simple_animal/proc/get_pry_desc() + return "prying" + +/mob/living/simple_animal/pry_door(delay, obj/machinery/door/target) + if(!can_pry_door()) + return + visible_message(SPAN_DANGER("\The [src] begins [get_pry_desc()] at \the [target]!")) + if(istype(ai)) + ai.pause() + if(do_after(src, delay, target)) + target.open(1) + else + visible_message(SPAN_NOTICE("\The [src] is interrupted.")) + if(istype(ai)) + ai.resume() + +/mob/living/simple_animal/has_ranged_attack() + return !!projectiletype && get_ranged_attack_distance() > 0 + +/mob/living/simple_animal/proc/shoot_wrapper(target, location, user) + if(shoot_at(target, location, user) && casingtype) + new casingtype(loc) + +/mob/living/simple_animal/proc/shoot_at(var/atom/target, var/atom/start) + if(!start) + start = get_turf(src) + if(!can_act() || !istype(target) || !istype(start) || target == start || !has_ranged_attack()) + return FALSE + var/obj/item/projectile/A = new projectiletype(get_turf(start)) + if(!A) + return FALSE + playsound(start, projectilesound, 100, 1) + A.launch(target, get_exposed_defense_zone(target), src) + return TRUE + +/mob/living/simple_animal/get_ranged_attack_distance() + return ranged_range + +/mob/living/simple_animal/handle_ranged_attack(atom/target) + if(!has_ranged_attack() || !istype(target)) + return + visible_message(SPAN_DANGER("\The [src] [fire_desc] at \the [target]!")) + if(burst_projectile) + var/datum/callback/shoot_cb = CALLBACK(src, PROC_REF(shoot_wrapper), target, loc) + addtimer(shoot_cb, 1) + addtimer(shoot_cb, 4) + addtimer(shoot_cb, 6) + else + shoot_at(target, loc, src) + +/mob/living/simple_animal/can_eat_food_currently(obj/eating, mob/user, consumption_method) + return TRUE + +/mob/living/simple_animal/get_attack_telegraph_delay() + return attack_delay + +/mob/living/simple_animal/set_stat(var/new_stat) + if((. = ..())) + queue_icon_update() + +/mob/living/simple_animal/is_space_movement_permitted(allow_movement = FALSE) + return skip_spacemove ? SPACE_MOVE_PERMITTED : ..() + +/mob/living/simple_animal/proc/get_default_animal_colour(marking_type) + var/list/colors = get_default_animal_colours() + return LAZYACCESS(colors, marking_type) // Return null if unset, rather than forcing COLOR_BLACK or such. + +/mob/living/simple_animal/proc/get_default_animal_colours() + return diff --git a/code/modules/mob/living/simple_animal/alien/alien.dm b/code/modules/mob/living/simple_animal/alien/alien.dm new file mode 100644 index 000000000000..8c2bce14bff7 --- /dev/null +++ b/code/modules/mob/living/simple_animal/alien/alien.dm @@ -0,0 +1,60 @@ +// Dummy type used in modpacks. +/mob/living/simple_animal/alien + name = "alien" + desc = "What IS that?" + pass_flags = PASS_FLAG_TABLE + max_health = 100 + mob_size = MOB_SIZE_TINY + mob_sort_value = 8 + abstract_type = /mob/living/simple_animal/alien + death_message = "lets out a waning guttural screech, green blood bubbling from its maw." + var/instance_num + +/mob/living/simple_animal/alien/Initialize() + verbs += /mob/living/proc/hide + + instance_num = rand(1, 1000) + name = "[initial(name)] ([instance_num])" + real_name = name + update_icon() + + gender = NEUTER + . = ..() + +/mob/living/simple_animal/alien/get_blood_color() + return COLOR_LIME + +/mob/living/simple_animal/alien/restrained() + return 0 + +/mob/living/simple_animal/alien/get_admin_job_string() + return "Alien" + +/mob/living/simple_animal/alien/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/visible, + /decl/emote/visible/scratch, + /decl/emote/visible/drool, + /decl/emote/visible/nod, + /decl/emote/visible/sway, + /decl/emote/visible/sulk, + /decl/emote/visible/twitch, + /decl/emote/visible/dance, + /decl/emote/visible/roll, + /decl/emote/visible/shake, + /decl/emote/visible/jump, + /decl/emote/visible/shiver, + /decl/emote/visible/collapse, + /decl/emote/visible/spin, + /decl/emote/visible/sidestep, + /decl/emote/audible/hiss, + /decl/emote/audible, + /decl/emote/audible/deathgasp_alien, + /decl/emote/audible/whimper, + /decl/emote/audible/gasp, + /decl/emote/audible/scretch, + /decl/emote/audible/choke, + /decl/emote/audible/moan, + /decl/emote/audible/gnarl + ) + return default_emotes diff --git a/code/modules/mob/living/simple_animal/aquatic/_aquatic.dm b/code/modules/mob/living/simple_animal/aquatic/_aquatic.dm index 98e0bed5cb57..255d433c5a83 100644 --- a/code/modules/mob/living/simple_animal/aquatic/_aquatic.dm +++ b/code/modules/mob/living/simple_animal/aquatic/_aquatic.dm @@ -1,36 +1,18 @@ /mob/living/simple_animal/aquatic - icon = 'icons/mob/simple_animal/aquatic.dmi' - turns_per_move = 5 - speed = 4 + icon = 'icons/mob/simple_animal/fish_content.dmi' mob_size = MOB_SIZE_SMALL - emote_see = list("glubs", "blubs", "bloops") - - // They only really care if there's water around them or not. - max_gas = list() - min_gas = list() - minbodytemp = 0 + base_animal_type = /mob/living/simple_animal/aquatic + is_aquatic = TRUE + butchery_data = /decl/butchery_data/animal/fish/small + holder_type = /obj/item/holder + ai = /datum/mob_controller/aquatic - meat_type = /obj/item/chems/food/snacks/fish - meat_amount = 3 - bone_amount = 5 - skin_amount = 5 - bone_material = /decl/material/solid/bone/fish - skin_material = /decl/material/solid/skin/fish +/datum/mob_controller/aquatic + turns_per_wander = 10 + emote_see = list("glubs", "blubs", "bloops") /mob/living/simple_animal/aquatic/Initialize() . = ..() default_pixel_x = rand(-12,12) default_pixel_y = rand(-12,12) - pixel_x = default_pixel_x - pixel_y = default_pixel_y - -/mob/living/simple_animal/aquatic/Life() - if(!submerged()) - if(icon_state == icon_living) - icon_state = "[icon_living]_dying" - walk(src, 0) - Paralyse(3) - . = ..() - -/mob/living/simple_animal/aquatic/handle_atmos(var/atmos_suitable = 1) - . = ..(atmos_suitable = submerged()) + reset_offsets(0) diff --git a/code/modules/mob/living/simple_animal/aquatic/_aquatic_hostile.dm b/code/modules/mob/living/simple_animal/aquatic/_aquatic_hostile.dm index de10d25966be..31c50b14a047 100644 --- a/code/modules/mob/living/simple_animal/aquatic/_aquatic_hostile.dm +++ b/code/modules/mob/living/simple_animal/aquatic/_aquatic_hostile.dm @@ -1,27 +1,15 @@ /mob/living/simple_animal/hostile/aquatic - icon = 'icons/mob/simple_animal/aquatic.dmi' - meat_type = /obj/item/chems/food/snacks/fish - turns_per_move = 5 + abstract_type = /mob/living/simple_animal/hostile/aquatic + icon = 'icons/mob/simple_animal/fish_content.dmi' natural_weapon = /obj/item/natural_weapon/bite - speed = 4 mob_size = MOB_SIZE_MEDIUM + base_animal_type = /mob/living/simple_animal/aquatic // used for language, ignore actual type + is_aquatic = TRUE + butchery_data = /decl/butchery_data/animal/fish + holder_type = /obj/item/holder + ai = /datum/mob_controller/aggressive/aquatic + +/datum/mob_controller/aggressive/aquatic + turns_per_wander = 10 emote_see = list("gnashes") - // They only really care if there's water around them or not. - max_gas = list() - min_gas = list() - minbodytemp = 0 - -/mob/living/simple_animal/hostile/aquatic/Life() - if(!submerged()) - if(icon_state == icon_living) - icon_state = "[icon_living]_dying" - walk(src, 0) - Paralyse(3) - . = ..() - -/mob/living/simple_animal/hostile/aquatic/handle_atmos(var/atmos_suitable = 1) - . = ..(atmos_suitable = submerged()) - -/mob/living/simple_animal/hostile/aquatic/can_act() - . = ..() && submerged() diff --git a/code/modules/mob/living/simple_animal/aquatic/_aquatic_retaliate.dm b/code/modules/mob/living/simple_animal/aquatic/_aquatic_retaliate.dm index 70b3049d3a6a..de4126fee08b 100644 --- a/code/modules/mob/living/simple_animal/aquatic/_aquatic_retaliate.dm +++ b/code/modules/mob/living/simple_animal/aquatic/_aquatic_retaliate.dm @@ -1,27 +1,15 @@ -/mob/living/simple_animal/hostile/retaliate/aquatic - icon = 'icons/mob/simple_animal/aquatic.dmi' - meat_type = /obj/item/chems/food/snacks/fish - turns_per_move = 5 +/mob/living/simple_animal/hostile/aquatic + abstract_type = /mob/living/simple_animal/hostile/aquatic + icon = 'icons/mob/simple_animal/fish_content.dmi' natural_weapon = /obj/item/natural_weapon/bite - speed = 4 mob_size = MOB_SIZE_MEDIUM + base_animal_type = /mob/living/simple_animal/aquatic // used for language, ignore actual type + is_aquatic = TRUE + butchery_data = /decl/butchery_data/animal/fish + holder_type = /obj/item/holder + ai = /datum/mob_controller/aggressive/aquatic + +/datum/mob_controller/aggressive/aquatic + turns_per_wander = 10 emote_see = list("gnashes") - - // They only really care if there's water around them or not. - max_gas = list() - min_gas = list() - minbodytemp = 0 - -/mob/living/simple_animal/hostile/retaliate/aquatic/Life() - if(!submerged()) - if(icon_state == icon_living) - icon_state = "[icon_living]_dying" - walk(src, 0) - Paralyse(3) - . = ..() - -/mob/living/simple_animal/hostile/retaliate/aquatic/handle_atmos(var/atmos_suitable = 1) - . = ..(atmos_suitable = submerged()) - -/mob/living/simple_animal/hostile/retaliate/aquatic/can_act() - . = ..() && submerged() + only_attack_enemies = TRUE diff --git a/code/modules/mob/living/simple_animal/aquatic/aquatic_carp.dm b/code/modules/mob/living/simple_animal/aquatic/aquatic_carp.dm index 928fe40ce82d..f910bd000f6a 100644 --- a/code/modules/mob/living/simple_animal/aquatic/aquatic_carp.dm +++ b/code/modules/mob/living/simple_animal/aquatic/aquatic_carp.dm @@ -1,23 +1,13 @@ -/mob/living/simple_animal/hostile/retaliate/aquatic/carp +/mob/living/simple_animal/hostile/aquatic/carp name = "carp" desc = "A ferocious fish. May be too hardcore." - icon_state = "carp" - icon_living = "carp" - icon_dead = "carp_dead" + icon = 'icons/mob/simple_animal/fish_carp.dmi' faction = "fishes" - maxHealth = 20 - health = 20 + max_health = 20 + butchery_data = /decl/butchery_data/animal/fish/carp - meat_type = /obj/item/chems/food/snacks/fish/carp - meat_amount = 3 - bone_amount = 5 - skin_amount = 5 - bone_material = /decl/material/solid/bone/fish - skin_material = /decl/material/solid/skin/fish - -/mob/living/simple_animal/hostile/retaliate/aquatic/carp/Initialize() +/mob/living/simple_animal/hostile/aquatic/carp/Initialize() . = ..() default_pixel_x = rand(-8,8) default_pixel_y = rand(-8,8) - pixel_x = default_pixel_x - pixel_y = default_pixel_y \ No newline at end of file + reset_offsets(0) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/aquatic/aquatic_fish.dm b/code/modules/mob/living/simple_animal/aquatic/aquatic_fish.dm index a5daedabfca5..bbd6b916d820 100644 --- a/code/modules/mob/living/simple_animal/aquatic/aquatic_fish.dm +++ b/code/modules/mob/living/simple_animal/aquatic/aquatic_fish.dm @@ -1,33 +1,58 @@ /mob/living/simple_animal/aquatic/fish - name = "small fish" - desc = "Glub glub." - icon_state = "content" - icon_living = "content" - icon_dead = "content_dead" + name = "small fry" + desc = "A small fish of an indeterminate species." faction = "fishes" - maxHealth = 10 - health = 10 + max_health = 10 mob_size = MOB_SIZE_TINY - can_pull_size = 0 can_pull_mobs = 0 - mob_bump_flag = 0 mob_swap_flags = 0 mob_push_flags = 0 mob_always_swap = 1 - - meat_amount = 1 - bone_amount = 3 - skin_amount = 3 + butchery_data = /decl/butchery_data/animal/fish/small /mob/living/simple_animal/aquatic/fish/grump - icon_state = "grump" - icon_living = "grump" - icon_dead = "grump_dead" - -/mob/living/simple_animal/aquatic/fish/judge - icon_state = "judge" - icon_living = "judge" - icon_dead = "judge_dead" - meat_amount = 2 + name = "small fish" + icon = 'icons/mob/simple_animal/fish_grump.dmi' + +/mob/living/simple_animal/aquatic/fish/large + name = "smallmouth bass" + icon = 'icons/mob/simple_animal/fish_judge.dmi' + butchery_data = /decl/butchery_data/animal/fish/medium + mob_size = MOB_SIZE_SMALL + +/mob/living/simple_animal/aquatic/fish/large/cave + name = "blind cave fish" + desc = "A pale, blobby fish that lives its entire life in the cold darkness of cave rivers, and hence has no need for eyes." + icon = 'icons/mob/simple_animal/fish_cave.dmi' + +/mob/living/simple_animal/aquatic/fish/large/cave/is_blind() + return TRUE + +/mob/living/simple_animal/aquatic/fish/large/bass + name = "largemouth bass" + icon = 'icons/mob/simple_animal/fish_bass.dmi' + +/mob/living/simple_animal/aquatic/fish/large/javelin + name = "javelin" + icon = 'icons/mob/simple_animal/fish_javelin.dmi' + +/mob/living/simple_animal/aquatic/fish/large/koi + name = "koi" + icon = 'icons/mob/simple_animal/fish_koi.dmi' + +/mob/living/simple_animal/aquatic/fish/large/pike + name = "pike" + icon = 'icons/mob/simple_animal/fish_pike.dmi' + +/mob/living/simple_animal/aquatic/fish/large/salmon + name = "salmon" + icon = 'icons/mob/simple_animal/fish_salmon.dmi' + +/mob/living/simple_animal/aquatic/fish/large/trout + name = "trout" + icon = 'icons/mob/simple_animal/fish_trout.dmi' + +/mob/living/simple_animal/aquatic/fish/large/trout/river + name = "rainbow trout" diff --git a/code/modules/mob/living/simple_animal/aquatic/aquatic_fish_lantern.dm b/code/modules/mob/living/simple_animal/aquatic/aquatic_fish_lantern.dm new file mode 100644 index 000000000000..179605c12c9d --- /dev/null +++ b/code/modules/mob/living/simple_animal/aquatic/aquatic_fish_lantern.dm @@ -0,0 +1,26 @@ +/mob/living/simple_animal/aquatic/fish/large/lantern + name = "lantern fish" + desc = "An oily, glowing fish. They are sometimes caught in cave rivers, and are rumoured to have cousins in the deep ocean." + icon = 'icons/mob/simple_animal/fish_lantern.dmi' + butchery_data = /decl/butchery_data/animal/fish/oily + holder_type = /obj/item/holder/lanternfish + var/glow_color = COLOR_LIME + var/glow_power = 0.5 + var/glow_range = 2 + +/mob/living/simple_animal/aquatic/fish/large/lantern/Initialize() + . = ..() + set_light(glow_range, glow_power, glow_color) + refresh_visible_overlays() + +/mob/living/simple_animal/aquatic/fish/large/lantern/add_additional_visible_overlays(list/accumulator) + var/glow_state = "[icon_state]-glow" + if(check_state_in_icon(glow_state, icon)) + accumulator += emissive_overlay(icon, glow_state, color = light_color, flags = RESET_COLOR) + +/obj/item/holder/lanternfish/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing) + if(overlay && (slot in global.all_hand_slots)) + var/glow_state = "[overlay.icon_state]-glow" + if(check_state_in_icon(glow_state, overlay.icon)) + overlay.overlays += emissive_overlay(overlay.icon, glow_state, color = light_color, flags = RESET_COLOR) + return ..() diff --git a/code/modules/mob/living/simple_animal/aquatic/aquatic_sharks.dm b/code/modules/mob/living/simple_animal/aquatic/aquatic_sharks.dm index d22f09df6991..8d1b4d218e63 100644 --- a/code/modules/mob/living/simple_animal/aquatic/aquatic_sharks.dm +++ b/code/modules/mob/living/simple_animal/aquatic/aquatic_sharks.dm @@ -1,47 +1,40 @@ /mob/living/simple_animal/hostile/aquatic/shark name = "shark" desc = "A ferocious fish with many, many teeth." - icon_state = "shark" - icon_living = "shark" - icon_dead = "shark_dead" - maxHealth = 150 - health = 150 + icon = 'icons/mob/simple_animal/shark.dmi' + max_health = 150 natural_weapon = /obj/item/natural_weapon/bite/shark - break_stuff_probability = 15 faction = "sharks" - - meat_type = /obj/item/chems/food/snacks/fish/shark - meat_amount = 5 - bone_amount = 15 - skin_amount = 15 - bone_material = /decl/material/solid/bone/cartilage - skin_material = /decl/material/solid/skin/shark + butchery_data = /decl/butchery_data/animal/fish/shark + ai = /datum/mob_controller/aggressive/aquatic/shark + ability_handlers = list(/datum/ability_handler/predator) /obj/item/natural_weapon/bite/shark - force = 20 + _base_attack_force = 20 + +/datum/mob_controller/aggressive/aquatic/shark + break_stuff_probability = 15 /mob/living/simple_animal/hostile/aquatic/shark/huge name = "gigacretoxyrhina" desc = "That is a lot of shark." icon = 'icons/mob/simple_animal/spaceshark.dmi' - icon_state = "shark" - icon_living = "shark" - icon_dead = "shark_dead" - turns_per_move = 2 - move_to_delay = 2 - attack_same = 1 - speed = 0 + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) mob_size = MOB_SIZE_LARGE pixel_x = -16 - health = 400 - maxHealth = 400 + max_health = 400 harm_intent_damage = 5 natural_weapon = /obj/item/natural_weapon/bite/giantshark - break_stuff_probability = 35 + butchery_data = /decl/butchery_data/animal/fish/shark/large + ai = /datum/mob_controller/aggressive/aquatic/shark/huge - meat_amount = 10 - bone_amount = 30 - skin_amount = 30 +/datum/mob_controller/aggressive/aquatic/shark/huge + turns_per_wander = 4 + break_stuff_probability = 35 + attack_same_faction = TRUE /obj/item/natural_weapon/bite/giantshark - force = 40 \ No newline at end of file + _base_attack_force = 40 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm deleted file mode 100644 index 52927ef02292..000000000000 --- a/code/modules/mob/living/simple_animal/constructs/constructs.dm +++ /dev/null @@ -1,359 +0,0 @@ -/mob/living/simple_animal/construct - name = "Construct" - real_name = "Construct" - desc = "" - speak = list("Hsssssssszsht.", "Hsssssssss...", "Tcshsssssssszht!") - speak_emote = list("hisses") - emote_hear = list("wails","screeches") - response_help = "thinks better of touching" - response_disarm = "flailed at" - response_harm = "punched" - icon_dead = "shade_dead" - speed = -1 - a_intent = I_HURT - stop_automated_movement = 1 - status_flags = CANPUSH - universal_speak = FALSE - universal_understand = TRUE - min_gas = null - max_gas = null - minbodytemp = 0 - show_stat_health = 1 - faction = "cult" - supernatural = 1 - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_NOLIGHTING - mob_swap_flags = HUMAN|SIMPLE_ANIMAL|SLIME|MONKEY - mob_push_flags = ALLMOBS - bleed_colour = "#331111" - - meat_type = null - meat_amount = 0 - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = 0 - - var/nullblock = 0 - var/list/construct_spells = list() - -/mob/living/simple_animal/construct/cultify() - return - -/mob/living/simple_animal/construct/Initialize() - . = ..() - name = text("[initial(name)] ([random_id(/mob/living/simple_animal/construct, 1000, 9999)])") - real_name = name - add_language(/decl/language/cultcommon) - add_language(/decl/language/cult) - for(var/spell in construct_spells) - src.add_spell(new spell, "const_spell_ready") - update_icon() - -/mob/living/simple_animal/construct/death(gibbed, deathmessage, show_dead_message) - new /obj/item/ectoplasm (src.loc) - ..(null,"collapses in a shattered heap.","The bonds tying you to this mortal plane have been severed.") - ghostize() - qdel(src) - -/mob/living/simple_animal/construct/on_update_icon() - overlays.Cut() - ..() - add_glow() - -/mob/living/simple_animal/construct/attack_animal(var/mob/user) - if(istype(user, /mob/living/simple_animal/construct/builder)) - if(health < maxHealth) - adjustBruteLoss(-5) - user.visible_message("\The [user] mends some of \the [src]'s wounds.") - else - to_chat(user, "\The [src] is undamaged.") - return - return ..() - -/mob/living/simple_animal/construct/examine(mob/user) - . = ..(user) - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" - if (src.health < src.maxHealth) - msg += "" - if (src.health >= src.maxHealth/2) - msg += "It looks slightly dented.\n" - else - msg += "It looks severely dented!\n" - msg += "" - msg += "*---------*" - - to_chat(user, msg) - -/obj/item/ectoplasm - name = "ectoplasm" - desc = "Spooky." - gender = PLURAL - icon = 'icons/obj/wizard.dmi' - icon_state = "ectoplasm" - -/////////////////Juggernaut/////////////// - - - -/mob/living/simple_animal/construct/armoured - name = "Juggernaut" - real_name = "Juggernaut" - desc = "A possessed suit of armour driven by the will of the restless dead" - icon = 'icons/mob/mob.dmi' - icon_state = "behemoth" - icon_living = "behemoth" - maxHealth = 250 - health = 250 - speak_emote = list("rumbles") - response_harm = "harmlessly punches" - harm_intent_damage = 0 - natural_weapon = /obj/item/natural_weapon/juggernaut - mob_size = MOB_SIZE_LARGE - speed = 3 - environment_smash = 2 - status_flags = 0 - resistance = 10 - construct_spells = list(/spell/aoe_turf/conjure/forcewall/lesser) - can_escape = TRUE - -/obj/item/natural_weapon/juggernaut - name = "armored gauntlet" - gender = NEUTER - attack_verb = list("smashed", "demolished") - hitsound = 'sound/weapons/heavysmash.ogg' - force = 30 - -/mob/living/simple_animal/construct/armoured/Life() - weakened = 0 - if ((. = ..())) - return - -/mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) - if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) - var/reflectchance = 80 - round(P.damage/3) - if(prob(reflectchance)) - adjustBruteLoss(P.damage * 0.5) - visible_message("The [P.name] gets reflected by [src]'s shell!", \ - "The [P.name] gets reflected by [src]'s shell!") - - // Find a turf near or on the original location to bounce to - if(P.starting) - var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) - var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) - var/turf/curloc = get_turf(src) - - // redirect the projectile - P.redirect(new_x, new_y, curloc, src) - - return -1 // complete projectile permutation - - return (..(P)) - - - -////////////////////////Wraith///////////////////////////////////////////// - - - -/mob/living/simple_animal/construct/wraith - name = "Wraith" - real_name = "Wraith" - desc = "A wicked bladed shell contraption piloted by a bound spirit" - icon = 'icons/mob/mob.dmi' - icon_state = "floating" - icon_living = "floating" - icon_dead = "floating_dead" - maxHealth = 75 - health = 75 - natural_weapon = /obj/item/natural_weapon/wraith - speed = -1 - environment_smash = 1 - see_in_dark = 7 - construct_spells = list(/spell/targeted/ethereal_jaunt/shift) - -/obj/item/natural_weapon/wraith - name = "wicked blade" - gender = NEUTER - attack_verb = list("slashed", "tore into") - hitsound = 'sound/weapons/rapidslice.ogg' - edge = TRUE - force = 25 - -/////////////////////////////Artificer///////////////////////// - - - -/mob/living/simple_animal/construct/builder - name = "Artificer" - real_name = "Artificer" - desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" - icon = 'icons/mob/mob.dmi' - icon_state = "artificer" - icon_living = "artificer" - maxHealth = 50 - health = 50 - response_harm = "viciously beaten" - harm_intent_damage = 5 - natural_weapon = /obj/item/natural_weapon/cult_builder - speed = 0 - environment_smash = 1 - construct_spells = list(/spell/aoe_turf/conjure/construct/lesser, - /spell/aoe_turf/conjure/wall, - /spell/aoe_turf/conjure/floor, - /spell/aoe_turf/conjure/soulstone, - /spell/aoe_turf/conjure/pylon - ) - -/obj/item/natural_weapon/cult_builder - name = "heavy arms" - attack_verb = list("rammed") - force = 5 - -/////////////////////////////Behemoth///////////////////////// - - -/mob/living/simple_animal/construct/behemoth - name = "Behemoth" - real_name = "Behemoth" - desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." - icon = 'icons/mob/mob.dmi' - icon_state = "behemoth" - icon_living = "behemoth" - maxHealth = 750 - health = 750 - speak_emote = list("rumbles") - response_harm = "harmlessly punched" - harm_intent_damage = 0 - natural_weapon = /obj/item/natural_weapon/juggernaut/behemoth - speed = 5 - environment_smash = 2 - resistance = 10 - var/energy = 0 - var/max_energy = 1000 - construct_spells = list(/spell/aoe_turf/conjure/forcewall/lesser) - can_escape = TRUE - -/obj/item/natural_weapon/juggernaut/behemoth - force = 50 - -////////////////////////Harvester//////////////////////////////// - - - -/mob/living/simple_animal/construct/harvester - name = "Harvester" - real_name = "Harvester" - desc = "The promised reward of the livings who follow Nar-Sie. Obtained by offering their bodies to the geometer of blood" - icon = 'icons/mob/mob.dmi' - icon_state = "harvester" - icon_living = "harvester" - icon_dead = "harvester_dead" - maxHealth = 150 - health = 150 - natural_weapon = /obj/item/natural_weapon/harvester - speed = -1 - environment_smash = 1 - see_in_dark = 7 - - construct_spells = list( - /spell/targeted/harvest - ) - -/obj/item/natural_weapon/harvester - name = "malicious spike" - gender = NEUTER - attack_verb = list("violently stabbed", "ran through") - hitsound = 'sound/weapons/pierce.ogg' - sharp = TRUE - force = 25 - -////////////////Glow////////////////// -/mob/living/simple_animal/construct/proc/add_glow() - var/image/eye_glow = image(icon,"glow-[icon_state]") - eye_glow.plane = EFFECTS_ABOVE_LIGHTING_PLANE - eye_glow.layer = EYE_GLOW_LAYER - overlays += eye_glow - set_light(-2, 0.1, 1.5, l_color = "#ffffff") - -////////////////HUD////////////////////// - -/mob/living/simple_animal/construct/Life() - . = ..() - if(.) - if(fire) - if(fire_alert) fire.icon_state = "fire1" - else fire.icon_state = "fire0" - if(purged) - if(purge > 0) purged.icon_state = "purge1" - else purged.icon_state = "purge0" - silence_spells(purge) - -/mob/living/simple_animal/construct/armoured/Life() - . = ..() - if(healths) - switch(health) - if(250 to INFINITY) healths.icon_state = "juggernaut_health0" - if(208 to 249) healths.icon_state = "juggernaut_health1" - if(167 to 207) healths.icon_state = "juggernaut_health2" - if(125 to 166) healths.icon_state = "juggernaut_health3" - if(84 to 124) healths.icon_state = "juggernaut_health4" - if(42 to 83) healths.icon_state = "juggernaut_health5" - if(1 to 41) healths.icon_state = "juggernaut_health6" - else healths.icon_state = "juggernaut_health7" - - -/mob/living/simple_animal/construct/behemoth/Life() - . = ..() - if(healths) - switch(health) - if(750 to INFINITY) healths.icon_state = "juggernaut_health0" - if(625 to 749) healths.icon_state = "juggernaut_health1" - if(500 to 624) healths.icon_state = "juggernaut_health2" - if(375 to 499) healths.icon_state = "juggernaut_health3" - if(250 to 374) healths.icon_state = "juggernaut_health4" - if(125 to 249) healths.icon_state = "juggernaut_health5" - if(1 to 124) healths.icon_state = "juggernaut_health6" - else healths.icon_state = "juggernaut_health7" - -/mob/living/simple_animal/construct/builder/Life() - . = ..() - if(healths) - switch(health) - if(50 to INFINITY) healths.icon_state = "artificer_health0" - if(42 to 49) healths.icon_state = "artificer_health1" - if(34 to 41) healths.icon_state = "artificer_health2" - if(26 to 33) healths.icon_state = "artificer_health3" - if(18 to 25) healths.icon_state = "artificer_health4" - if(10 to 17) healths.icon_state = "artificer_health5" - if(1 to 9) healths.icon_state = "artificer_health6" - else healths.icon_state = "artificer_health7" - - - -/mob/living/simple_animal/construct/wraith/Life() - . = ..() - if(healths) - switch(health) - if(75 to INFINITY) healths.icon_state = "wraith_health0" - if(62 to 74) healths.icon_state = "wraith_health1" - if(50 to 61) healths.icon_state = "wraith_health2" - if(37 to 49) healths.icon_state = "wraith_health3" - if(25 to 36) healths.icon_state = "wraith_health4" - if(12 to 24) healths.icon_state = "wraith_health5" - if(1 to 11) healths.icon_state = "wraith_health6" - else healths.icon_state = "wraith_health7" - - -/mob/living/simple_animal/construct/harvester/Life() - . = ..() - if(healths) - switch(health) - if(150 to INFINITY) healths.icon_state = "harvester_health0" - if(125 to 149) healths.icon_state = "harvester_health1" - if(100 to 124) healths.icon_state = "harvester_health2" - if(75 to 99) healths.icon_state = "harvester_health3" - if(50 to 74) healths.icon_state = "harvester_health4" - if(25 to 49) healths.icon_state = "harvester_health5" - if(1 to 24) healths.icon_state = "harvester_health6" - else healths.icon_state = "harvester_health7" diff --git a/code/modules/mob/living/simple_animal/constructs/soulstone.dm b/code/modules/mob/living/simple_animal/constructs/soulstone.dm deleted file mode 100644 index e1c5c2ec2760..000000000000 --- a/code/modules/mob/living/simple_animal/constructs/soulstone.dm +++ /dev/null @@ -1,148 +0,0 @@ -/obj/item/soulstone - name = "soul stone shard" - icon = 'icons/obj/wizard.dmi' - icon_state = "soulstone" - item_state = "electronic" - desc = "A strange, ridged chunk of some glassy red material. Achingly cold to the touch." - w_class = ITEM_SIZE_SMALL - slot_flags = SLOT_BELT - origin_tech = "{'wormholes':4,'materials':4}" - - var/full = SOULSTONE_EMPTY - var/is_evil = 1 - var/mob/living/simple_animal/shade = null - var/smashing = 0 - var/soulstatus = null - -/obj/item/soulstone/Initialize(var/mapload) - shade = new /mob/living/simple_animal/shade(src) - . = ..(mapload) - -/obj/item/soulstone/shatter() - playsound(loc, "shatter", 70, 1) - qdel(src) - -/obj/item/soulstone/full - full = SOULSTONE_ESSENCE - icon_state = "soulstone2" - -/obj/item/soulstone/Destroy() - QDEL_NULL(shade) - return ..() - -/obj/item/soulstone/examine(mob/user) - . = ..() - if(full == SOULSTONE_EMPTY) - to_chat(user, "The shard still flickers with a fraction of the full artifact's power, but it needs to be filled with the essence of someone's life before it can be used.") - if(full == SOULSTONE_ESSENCE) - to_chat(user,"The shard has gone transparent, a seeming window into a dimension of unspeakable horror.") - if(full == SOULSTONE_CRACKED) - to_chat(user, "This one is cracked and useless.") - -/obj/item/soulstone/on_update_icon() - if(full == SOULSTONE_EMPTY) - icon_state = "soulstone" - if(full == SOULSTONE_ESSENCE) - icon_state = "soulstone2" //TODO: A spookier sprite. Also unique sprites. - if(full == SOULSTONE_CRACKED) - icon_state = "soulstone"//TODO: cracked sprite - SetName("cracked soulstone") - -/obj/item/soulstone/attackby(var/obj/item/I, var/mob/user) - ..() - if(is_evil && istype(I, /obj/item/nullrod)) - to_chat(user, "You cleanse \the [src] of taint, purging its shackles to its creator..") - is_evil = 0 - return - if(I.force >= 5) - if(full != SOULSTONE_CRACKED) - user.visible_message("\The [user] hits \the [src] with \the [I], and it breaks.[shade.client ? " You hear a terrible scream!" : ""]", "You hit \the [src] with \the [I], and it cracks.[shade.client ? " You hear a terrible scream!" : ""]", shade.client ? "You hear a scream." : null) - playsound(loc, 'sound/effects/Glasshit.ogg', 75) - set_full(SOULSTONE_CRACKED) - else - user.visible_message("\The [user] shatters \the [src] with \the [I]!") - shatter() - -/obj/item/soulstone/attack(var/mob/living/simple_animal/M, var/mob/user) - if(M == shade) - to_chat(user, "You recapture \the [M].") - M.forceMove(src) - return - if(full == SOULSTONE_ESSENCE) - to_chat(user, "\The [src] is already full.") - return - if(M.stat != DEAD && !M.is_asystole()) - to_chat(user, "Kill or maim the victim first.") - return - for(var/obj/item/W in M) - M.drop_from_inventory(W) - M.dust() - set_full(SOULSTONE_ESSENCE) - -/obj/item/soulstone/attack_self(var/mob/user) - if(full != SOULSTONE_ESSENCE) // No essence - no shade - to_chat(user, "This [src] has no life essence.") - return - - if(!shade.key) // No key = hasn't been used - to_chat(user, "You cut your finger and let the blood drip on \the [src].") - user.remove_blood_simple(1) - var/datum/ghosttrap/cult/shade/S = get_ghost_trap("soul stone") - S.request_player(shade, "The soul stone shade summon ritual has been performed. ") - else if(!shade.client) // Has a key but no client - shade logged out - to_chat(user, "\The [shade] in \the [src] is dormant.") - return - else if(shade.loc == src) - var/choice = alert("Would you like to invoke the spirit within?",,"Yes","No") - if(choice == "Yes") - shade.dropInto(loc) - to_chat(user, "You summon \the [shade].") - if(choice == "No") - return - -/obj/item/soulstone/proc/set_full(var/f) - full = f - update_icon() - -/obj/structure/constructshell - name = "empty shell" - icon = 'icons/obj/wizard.dmi' - icon_state = "construct" - desc = "A wicked machine used by those skilled in magical arts. It is inactive." - -/obj/structure/constructshell/cult - icon_state = "construct-cult" - desc = "This eerie contraption looks like it would come alive if supplied with a missing ingredient." - -/obj/structure/constructshell/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/soulstone)) - var/obj/item/soulstone/S = I - if(!S.shade.client) - to_chat(user, "\The [I] has essence, but no soul. Activate it in your hand to find a soul for it first.") - return - if(S.shade.loc != S) - to_chat(user, "Recapture the shade back into \the [I] first.") - return - var/construct = alert(user, "Please choose which type of construct you wish to create.",,"Artificer", "Wraith", "Juggernaut") - var/ctype - switch(construct) - if("Artificer") - ctype = /mob/living/simple_animal/construct/builder - if("Wraith") - ctype = /mob/living/simple_animal/construct/wraith - if("Juggernaut") - ctype = /mob/living/simple_animal/construct/armoured - var/mob/living/simple_animal/construct/C = new ctype(get_turf(src)) - C.key = S.shade.key - //C.cancel_camera() - if(S.is_evil) - GLOB.cult.add_antagonist(C.mind) - qdel(S) - qdel(src) - -/obj/structure/constructshell/get_artifact_scan_data() - return "Tribal idol - subject resembles statues/emblems built by superstitious pre-warp civilisations to honour their gods. Material appears to be a rock/plastcrete composite." - -#undef SOULSTONE_CRACKED -#undef SOULSTONE_EMPTY -#undef SOULSTONE_ESSENCE diff --git a/code/modules/mob/living/simple_animal/crow/crow.dm b/code/modules/mob/living/simple_animal/crow/crow.dm index 00a2732ce7a1..2ee46b3e0df2 100644 --- a/code/modules/mob/living/simple_animal/crow/crow.dm +++ b/code/modules/mob/living/simple_animal/crow/crow.dm @@ -1,159 +1,89 @@ -/obj/item/storage/messenger - name = "messenger bag" +/obj/item/backpack/messenger/corvid_couriers + name = "corvid messenger bag" desc = "A small green-grey messenger bag with a blue Corvid Couriers logo on it." - icon = 'icons/mob/simple_animal/crow.dmi' - icon_state = "messenger_bag" - storage_slots = 7 + icon = 'icons/obj/items/storage/backpack/corvid.dmi' + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_SMALL + storage = /datum/storage/backpack/crow + material = /decl/material/solid/organic/cloth /mob/living/simple_animal/crow name = "crow" desc = "A large crow. Caw caw." icon = 'icons/mob/simple_animal/crow.dmi' - icon_state = "crow" - icon_living = "crow" - icon_dead = "crow_dead" pass_flags = PASS_FLAG_TABLE mob_size = MOB_SIZE_SMALL + speak_emote = list("caws") + ai = /datum/mob_controller/crow + natural_weapon = /obj/item/natural_weapon/crow_claws + universal_speak = TRUE - speak = list("Caw.", "Caw?", "Caw!", "CAW.") - speak_emote = list("caws") - emote_hear = list("caws") - emote_see = list("hops") +/datum/mob_controller/crow + emote_speech = list("Caw.", "Caw?", "Caw!", "CAW.") + emote_hear = list("caws") + emote_see = list("hops") - natural_weapon = /obj/item/natural_weapon/crow_claws +/mob/living/simple_animal/crow/get_overlay_state_modifier() + return (stat == DEAD) ? "-dead" : null - response_help = "pets" - response_disarm = "gently moves aside" - response_harm = "swats" - stop_automated_movement = TRUE - universal_speak = TRUE - pass_flags = PASS_FLAG_TABLE +/decl/bodytype/animal/crow + name = "crow" + bodytype_category = "crow body" + uid = "bodytype_animal_crow" - var/obj/item/storage/messenger/messenger_bag - var/obj/item/card/id/access_card +/mob/living/simple_animal/crow/get_bodytype() + return GET_DECL(/decl/bodytype/animal/crow) /obj/item/natural_weapon/crow_claws name = "claws" gender = PLURAL - attack_verb = list("clawed") + attack_verb = "clawed" sharp = TRUE - force = 7 + _base_attack_force = 7 /mob/living/simple_animal/crow/Initialize() . = ..() - messenger_bag = new(src) + add_inventory_slot(new /datum/inventory_slot/back/simple) + add_inventory_slot(new /datum/inventory_slot/id) + add_held_item_slot(new /datum/inventory_slot/gripper/mouth/simple) + equip_to_slot_or_del(new /obj/item/backpack/messenger/corvid_couriers(src), slot_back_str) update_icon() -/mob/living/simple_animal/crow/GetIdCard() - return access_card - -/mob/living/simple_animal/crow/show_inv(var/mob/user) - if(user.incapacitated()) - return - var/list/dat = list() - if(access_card) - dat += "ID: [access_card] (Remove)" - else - dat += "ID: Nothing" - if(messenger_bag) - dat += "Back: [messenger_bag] (Remove)" - else - dat += "Back: Nothing" - var/datum/browser/popup = new(user, "[name]", "Inventory of \the [name]", 350, 150, src) - popup.set_content(jointext(dat, "
    ")) - popup.open() +/mob/living/simple_animal/crow/get_dexterity(var/silent) + return (DEXTERITY_EQUIP_ITEM|DEXTERITY_HOLD_ITEM) /mob/living/simple_animal/crow/DefaultTopicState() - return GLOB.physical_state - -/mob/living/simple_animal/crow/OnTopic(mob/user, href_list) - if(!ishuman(user)) - return ..() - if(href_list["remove_inv"]) - var/obj/item/removed - switch(href_list["remove_inv"]) - if("access cuff") - removed = access_card - access_card = null - if("back") - removed = messenger_bag - messenger_bag = null - if(removed) - removed.dropInto(loc) - usr.put_in_hands(removed) - visible_message("\The [usr] removes \the [removed] from \the [src]'s [href_list["remove_inv"]].") - show_inv(usr) - update_icon() - else - to_chat(user, "There is nothing to remove from \the [src]'s [href_list["remove_inv"]].") - return TOPIC_HANDLED - if(href_list["add_inv"]) - var/obj/item/equipping = user.get_active_hand() - if(!equipping) - to_chat(user, "You have nothing in your hand to put on \the [src]'s [href_list["add_inv"]].") - return 0 - var/obj/item/equipped - var/checktype - switch(href_list["add_inv"]) - if("access cuff") - equipped = access_card - checktype = /obj/item/card/id - if("back") - equipped = messenger_bag - checktype = /obj/item/storage/messenger - if(equipped) - to_chat(user, "There is already something worn on \the [src]'s [href_list["add_inv"]].") - return TOPIC_HANDLED - if(!istype(equipping, checktype)) - to_chat(user, "\The [equipping] won't fit on \the [src]'s [href_list["add_inv"]].") - return TOPIC_HANDLED - switch(href_list["add_inv"]) - if("access cuff") - access_card = equipping - if("back") - messenger_bag = equipping - if(!user.unEquip(equipping, src)) - return TOPIC_HANDLED - visible_message("\The [user] places \the [equipping] on to \the [src]'s [href_list["add_inv"]].") - update_icon() - show_inv(user) - return TOPIC_HANDLED + return global.physical_topic_state + +// Let people interact with the Bird Storage. +/mob/living/simple_animal/crow/attack_hand(mob/user) + if(user.check_intent(I_FLAG_HELP)) + var/obj/item/backpack = get_equipped_item(slot_back_str) + if(backpack) + return backpack.attack_hand(user) return ..() -/mob/living/simple_animal/crow/examine(mob/user) - . = ..() - if(Adjacent(src)) - if(messenger_bag) - if(messenger_bag.contents.len) - to_chat(user, "It's wearing a little messenger bag with a Corvid Couriers logo on it. There's something stuffed inside.") - else - to_chat(user, "It's wearing a little messenger bag with a Corvid Couriers logo on it. It seems to be empty.") - if(access_card) - to_chat(user, "It has an access cuff with \the [access_card] inserted.") +/mob/living/simple_animal/crow/attackby(obj/item/used_item, mob/user) + if(user.check_intent(I_FLAG_HELP)) + var/obj/item/backpack = get_equipped_item(slot_back_str) + if(backpack) + return backpack.attackby(used_item, user) + return ..() /mob/living/simple_animal/crow/on_update_icon() ..() - overlays -= "bag" - overlays -= "bag_dead" - if(messenger_bag) - if(icon_state != icon_dead) - overlays |= "bag" - else - overlays |= "bag_dead" + var/obj/item/backpack = get_equipped_item(slot_back_str) + if(backpack) + var/overlay_state = "crow-[icon_state]-bag" + if(check_state_in_icon(overlay_state, backpack.icon)) + add_overlay(image(backpack.icon, overlay_state)) /mob/living/simple_animal/crow/cyber name = "cybercrow" - desc = "A large cybercrow. k4w k4w." + desc = "A large cybercrow. K4w k4w." speak_emote = list("beeps") /mob/living/simple_animal/crow/cyber/on_update_icon() ..() - overlays -= "cyber" - overlays -= "cyber_dead" - if(icon_state != icon_dead) - overlays |= "cyber" - else - overlays |= "cyber_dead" + add_overlay("[icon_state]-cyber") diff --git a/code/modules/mob/living/simple_animal/familiars/familiars.dm b/code/modules/mob/living/simple_animal/familiars/familiars.dm deleted file mode 100644 index 1aa1c60f43eb..000000000000 --- a/code/modules/mob/living/simple_animal/familiars/familiars.dm +++ /dev/null @@ -1,180 +0,0 @@ -/mob/living/simple_animal/familiar - name = "familiar" - desc = "No wizard is complete without a mystical sidekick." - supernatural = 1 - - response_help = "pets" - response_disarm = "pushes" - response_harm = "hits" - - universal_speak = FALSE - universal_understand = TRUE - - min_gas = list(/decl/material/gas/oxygen = 1) - max_gas = null - unsuitable_atmos_damage = 1 - - var/list/wizardy_spells = list() - -/mob/living/simple_animal/familiar/Initialize() - . = ..() - add_language(/decl/language/human/common) - for(var/spell in wizardy_spells) - src.add_spell(new spell, "const_spell_ready") - -/mob/living/simple_animal/familiar/carcinus - name = "carcinus" - desc = "A small crab said to be made of stone and starlight." - icon = 'icons/mob/simple_animal/animal.dmi' - icon_state = "evilcrab" - icon_living = "evilcrab" - icon_dead = "evilcrab_dead" - - speak_emote = list("chitters","clicks") - - - health = 200 - maxHealth = 200 - natural_weapon = /obj/item/natural_weapon/pincers/strong - resistance = 9 - can_escape = TRUE //snip snip - -/obj/item/natural_weapon/pincers/strong - force = 15 - -/*familiar version of the Pike w/o all the other hostile/carp stuff getting in the way (namely life) -*/ - -/mob/living/simple_animal/familiar/pike - name = "space pike" - desc = "A bigger, more magical cousin of the space carp." - - icon = 'icons/mob/simple_animal/spaceshark.dmi' - icon_state = "shark" - icon_living = "shark" - icon_dead = "shark_dead" - pixel_x = -16 - - speak_emote = list("gnashes") - - health = 100 - maxHealth = 100 - natural_weapon = /obj/item/natural_weapon/bite - can_escape = TRUE - - min_gas = null - - wizardy_spells = list(/spell/aoe_turf/conjure/forcewall) - -/mob/living/simple_animal/familiar/pike/Process_Spacemove() - return 1 //No drifting in space for space carp! //original comments do not steal - -/mob/living/simple_animal/familiar/horror - name = "horror" - desc = "Looking at it fills you with dread." - icon = 'icons/mob/mob.dmi' - icon_state = "horror" - icon_living = "horror" - - speak_emote = list("moans", "groans") - - response_help = "thinks better of touching" - - health = 150 - maxHealth = 150 - natural_weapon = /obj/item/natural_weapon/horror - - wizardy_spells = list(/spell/targeted/torment) - -/obj/item/natural_weapon/horror - name = "foul touch" - force = 10 - damtype = BURN - attack_verb = list("touched") - -/mob/living/simple_animal/familiar/horror/death(gibbed, deathmessage, show_dead_message) - ..(null,"rapidly deteriorates","The bonds tying you to this mortal plane have been severed.") - - ghostize() - gibs(src.loc) - qdel(src) - - -/mob/living/simple_animal/familiar/minor_amaros - name = "minor amaros" - desc = "A small fluffy alien creature." - icon = 'icons/mob/mob.dmi' - icon_state = "baby roro" - icon_living = "baby roro" - icon_dead = "baby roro dead" - - speak_emote = list("entones") - mob_size = MOB_SIZE_SMALL - - health = 25 - maxHealth = 25 - - wizardy_spells = list(/spell/targeted/heal_target, - /spell/targeted/heal_target/area) - - - -/mob/living/simple_animal/familiar/pet //basically variants of normal animals with spells. - icon = 'icons/mob/simple_animal/animal.dmi' - var/icon_rest //so that we can have resting little guys. - -/mob/living/simple_animal/familiar/pet/Life() - . = ..() - if(!.) - return FALSE - if(!icon_rest) - return - if(stat == UNCONSCIOUS || resting) - icon_state = icon_rest - -/mob/living/simple_animal/familiar/pet/mouse - name = "elderly mouse" - desc = "A small rodent. It looks very old." - icon_state = "mouse_gray" - icon_living = "mouse_gray" - icon_dead = "mouse_gray_dead" - icon_rest = "mouse_gray_sleep" - - speak_emote = list("squeeks") - holder_type = /obj/item/holder/mouse - pass_flags = PASS_FLAG_TABLE - mob_size = MOB_SIZE_MINISCULE - - response_harm = "stamps on" - - health = 15 - maxHealth = 15 - natural_weapon = /obj/item/natural_weapon/bite/mouse - can_escape = TRUE - - wizardy_spells = list(/spell/aoe_turf/smoke) - -/mob/living/simple_animal/familiar/pet/mouse/Initialize() - . = ..() - - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide - -/mob/living/simple_animal/familiar/pet/cat - name = "black cat" - desc = "A pitch black cat. Said to be especially unlucky." - icon_state = "cat3" - icon_living = "cat3" - icon_dead = "cat3_dead" - icon_rest = "cat3_rest" - - - speak_emote = list("meows", "purrs") - holder_type = /obj/item/holder/cat - mob_size = MOB_SIZE_SMALL - - health = 25 - maxHealth = 25 - natural_weapon = /obj/item/natural_weapon/claws/weak - - wizardy_spells = list(/spell/targeted/subjugation) diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index e61de96ad825..3d9a9a9c5091 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -1,68 +1,42 @@ -//Cat -/mob/living/simple_animal/cat - name = "cat" - desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers." - icon_state = "cat2" - item_state = "cat2" - icon_living = "cat2" - icon_dead = "cat2_dead" - speak = list("Meow!","Esp!","Purr!","HSSSSS") - speak_emote = list("purrs", "meows") - emote_hear = list("meows","mews") - emote_see = list("shakes their head", "shivers") - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - minbodytemp = 223 //Below -50 Degrees Celsius - maxbodytemp = 323 //Above 50 Degrees Celsius - holder_type = /obj/item/holder/cat - mob_size = MOB_SIZE_SMALL - possession_candidate = 1 - pass_flags = PASS_FLAG_TABLE - - skin_material = /decl/material/solid/skin/fur/orange - - var/turns_since_scan = 0 - var/mob/living/simple_animal/mouse/movement_target - var/mob/flee_target - -/mob/living/simple_animal/cat/do_delayed_life_action() - ..() - //MICE! - if((src.loc) && isturf(src.loc)) - if(!resting && !buckled) - for(var/mob/living/simple_animal/mouse/M in loc) - if(!M.stat) - M.splat() - visible_emote(pick("bites \the [M]!","toys with \the [M].","chomps on \the [M]!")) - movement_target = null - stop_automated_movement = 0 - break - - +/datum/mob_controller/passive/hunter/cat + emote_speech = list("Meow!","Esp!","Purr!","HSSSSS") + emote_hear = list("meows","mews") + emote_see = list("shakes their head", "shivers") + speak_chance = 0.25 + turns_per_wander = 10 + +/datum/mob_controller/passive/hunter/cat/try_attack_prey(mob/living/prey) + var/mob/living/simple_animal/passive/mouse/mouse = prey + if(istype(mouse)) + mouse.splat() + return + return ..() - for(var/mob/living/simple_animal/mouse/snack in oview(src,5)) - if(snack.stat < DEAD && prob(15)) - audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily.")) - break +/datum/mob_controller/passive/hunter/cat/consume_prey(mob/living/prey) + if(prey.stat != DEAD) + return + next_hunt = world.time + rand(1 SECONDS, 10 SECONDS) + set_target(null) + resume_wandering() +/datum/mob_controller/passive/hunter/cat/can_hunt(mob/living/victim) + return istype(victim, /mob/living/simple_animal/passive/mouse) && !victim.stat +/datum/mob_controller/passive/hunter/cat/update_targets() + . = ..() + if(!flee_target) + for(var/mob/living/simple_animal/passive/mouse/snack in oview(body, 5)) + if(snack.stat != DEAD && prob(15)) + body.custom_emote(AUDIBLE_MESSAGE, pick("hisses and spits!", "mrowls fiercely!", "eyes [snack] hungrily.")) + break - turns_since_scan++ - if (turns_since_scan > 5) - walk_to(src,0) - turns_since_scan = 0 +/datum/mob_controller/passive/hunter/cat/do_process() - if (flee_target) //fleeing takes precendence - handle_flee_target() - else - handle_movement_target() + if(!(. = ..())) + return - if(prob(2)) //spooky - var/mob/observer/ghost/spook = locate() in range(src,5) + if(!hunt_target && !flee_target && prob(1)) //spooky + var/mob/observer/ghost/spook = locate() in range(body, 5) if(spook) var/turf/T = spook.loc var/list/visible = list() @@ -71,131 +45,136 @@ visible += O if(visible.len) var/atom/A = pick(visible) - visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].") + body.custom_emote(VISIBLE_MESSAGE, "suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].") -/mob/living/simple_animal/cat/proc/handle_movement_target() - //if our target is neither inside a turf or inside a human(???), stop - if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) )) - movement_target = null - stop_automated_movement = 0 - //if we have no target or our current one is out of sight/too far away - if( !movement_target || !(movement_target.loc in oview(src, 4)) ) - movement_target = null - stop_automated_movement = 0 - for(var/mob/living/simple_animal/mouse/snack in oview(src)) //search for a new target - if(isturf(snack.loc) && !snack.stat) - movement_target = snack - break - - if(movement_target) - stop_automated_movement = 1 - walk_to(src,movement_target,0,3) - -/mob/living/simple_animal/cat/proc/handle_flee_target() - //see if we should stop fleeing - if (flee_target && !(flee_target.loc in view(src))) - flee_target = null - stop_automated_movement = 0 - - if (flee_target) - if(prob(25)) say("HSSSSS") - stop_automated_movement = 1 - walk_away(src, flee_target, 7, 2) - -/mob/living/simple_animal/cat/proc/set_flee_target(atom/A) - if(A) - flee_target = A - turns_since_scan = 5 - -/mob/living/simple_animal/cat/attackby(var/obj/item/O, var/mob/user) +//Cat +/mob/living/simple_animal/passive/cat + name = "cat" + desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers." + icon = 'icons/mob/simple_animal/cat_calico.dmi' + speak_emote = list("purrs", "meows") + see_in_dark = 6 + minbodytemp = 223 //Below -50 Degrees Celsius + maxbodytemp = 323 //Above 50 Degrees Celsius + holder_type = /obj/item/holder + mob_size = MOB_SIZE_SMALL + possession_candidate = TRUE + pass_flags = PASS_FLAG_TABLE + butchery_data = /decl/butchery_data/animal/cat + base_animal_type = /mob/living/simple_animal/passive/cat + ai = /datum/mob_controller/passive/hunter/cat + +/mob/living/simple_animal/passive/cat/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/cat) + +/decl/bodytype/quadruped/animal/cat + uid = "bodytype_animal_cat" + +/decl/bodytype/quadruped/animal/cat/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 1, -9), + "[SOUTH]" = list( 1, -12), + "[EAST]" = list( 7, -10), + "[WEST]" = list(-7, -10) + ) + ) . = ..() - if(O.force) - set_flee_target(user? user : src.loc) -/mob/living/simple_animal/cat/attack_hand(mob/living/carbon/human/M) - . = ..() - if(M.a_intent == I_HURT) - set_flee_target(M) +//Basic friend AI +/mob/living/simple_animal/passive/cat/fluff + ai = /datum/mob_controller/passive/hunter/cat/friendly -/mob/living/simple_animal/cat/explosion_act() - . = ..() - set_flee_target(src.loc) +/mob/living/simple_animal/passive/cat/fluff/is_tagging_suitable() + return FALSE -/mob/living/simple_animal/cat/bullet_act(var/obj/item/projectile/proj) - . = ..() - set_flee_target(proj.firer? proj.firer : src.loc) +/datum/mob_controller/passive/hunter/cat/friendly + var/befriend_job = null + var/atom/movement_target -/mob/living/simple_animal/cat/hitby(atom/movable/AM, var/datum/thrownthing/TT) - . = ..() - set_flee_target(TT.thrower? TT.thrower : src.loc) +/datum/mob_controller/passive/hunter/cat/friendly/add_friend(mob/friend) + if(length(get_friends()) > 1 || !ishuman(friend)) + return FALSE + var/mob/living/human/human_friend = friend + if(befriend_job && human_friend.job != befriend_job) + return FALSE + return ..() -//Basic friend AI -/mob/living/simple_animal/cat/fluff - var/mob/living/carbon/human/friend - var/befriend_job = null +/datum/mob_controller/passive/hunter/cat/friendly/do_process() -/mob/living/simple_animal/cat/fluff/handle_movement_target() - if (friend) - var/follow_dist = 4 - if (friend.stat >= DEAD || friend.is_asystole()) //danger - follow_dist = 1 - else if (friend.stat || friend.health <= 50) //danger or just sleeping - follow_dist = 2 - var/near_dist = max(follow_dist - 2, 1) - var/current_dist = get_dist(src, friend) - - if (movement_target != friend) - if (current_dist > follow_dist && !istype(movement_target, /mob/living/simple_animal/mouse) && (friend in oview(src))) - //stop existing movement - walk_to(src,0) - turns_since_scan = 0 - - //walk to friend - stop_automated_movement = 1 - movement_target = friend - walk_to(src, movement_target, near_dist, 4) - - //already following and close enough, stop - else if (current_dist <= near_dist) - walk_to(src,0) - movement_target = null - stop_automated_movement = 0 - if (prob(10)) - say("Meow!") - - if (!friend || movement_target != friend) - ..() - -/mob/living/simple_animal/cat/fluff/do_delayed_life_action() - ..() - if (stat || !friend) + if(!(. = ..())) return - if (get_dist(src, friend) <= 1) - if (friend.stat >= DEAD || friend.is_asystole()) - if (prob((friend.stat < DEAD)? 50 : 15)) - var/verb = pick("meows", "mews", "mrowls") - audible_emote(pick("[verb] in distress.", "[verb] anxiously.")) - else - if (prob(5)) - visible_emote(pick("nuzzles [friend].", - "brushes against [friend].", - "rubs against [friend].", - "purrs.")) - else if (friend.health <= 50) + + // Get our friend. + var/list/friends = get_friends() + var/mob/living/human/friend + if(LAZYLEN(friends)) + var/weakref/friend_ref = friends[1] + friend = friend_ref.resolve() + + if(body.stat || hunt_target || flee_target || QDELETED(friend)) + return + + var/follow_dist = 4 + if (friend.stat >= DEAD || friend.is_asystole()) //danger + follow_dist = 1 + else if (friend.stat || friend.current_health <= 50) //danger or just sleeping + follow_dist = 2 + var/near_dist = max(follow_dist - 2, 1) + var/current_dist = get_dist(body, friend) + + if (movement_target != friend) + if (current_dist > follow_dist && (friend in oview(body))) + //stop existing movement + body.stop_automove() + turns_since_scan = 0 + + //walk to friend + stop_wandering() + movement_target = friend + body.start_automove(movement_target, metadata = new /datum/automove_metadata(_acceptable_distance = near_dist)) + + //already following and close enough, stop + else if (current_dist <= near_dist) + body.stop_automove() + movement_target = null + resume_wandering() if (prob(10)) - var/verb = pick("meows", "mews", "mrowls") - audible_emote("[verb] anxiously.") + body.say("Meow!") -/mob/living/simple_animal/cat/fluff/verb/become_friends() + if (get_dist(body, friend) <= 1) + if (friend.stat >= DEAD || friend.is_asystole()) + if (prob((friend.stat < DEAD)? 25 : 7.5)) + var/verb = pick("meows", "mews", "mrowls") + body.custom_emote(AUDIBLE_MESSAGE, pick("[verb] in distress.", "[verb] anxiously.")) + else if (prob(5)) + body.custom_emote( + VISIBLE_MESSAGE, + pick("nuzzles [friend].","brushes against [friend].","rubs against [friend].","purrs.") + ) + else if (friend.current_health <= 50 && prob(5)) + var/verb = pick("meows", "mews", "mrowls") + body.custom_emote(AUDIBLE_MESSAGE, "[verb] anxiously.") + +/mob/living/simple_animal/passive/cat/fluff/verb/become_friends() set name = "Become Friends" set category = "IC" set src in view(1) + if(!istype(ai)) + return + + var/list/friends = ai?.get_friends() + if(!LAZYLEN(friends)) + return + + var/weakref/current_friend = friends[1] + var/mob/friend = current_friend?.resolve() + if(!friend) - var/mob/living/carbon/human/H = usr - if(istype(H) && (!befriend_job || H.job == befriend_job)) - friend = usr - . = 1 + var/mob/living/human/H = usr + if(istype(H)) + . = ai?.add_friend(usr) else if(usr == friend) . = 1 //already friends, but show success anyways @@ -210,65 +189,51 @@ return //RUNTIME IS ALIVE! SQUEEEEEEEE~ -/mob/living/simple_animal/cat/fluff/Runtime +/mob/living/simple_animal/passive/cat/fluff/runtime name = "Runtime" desc = "Her fur has the look and feel of velvet, and her tail quivers occasionally." gender = FEMALE - icon_state = "cat" - item_state = "cat" - icon_living = "cat" - icon_dead = "cat_dead" - skin_material = /decl/material/solid/skin/fur/black + icon = 'icons/mob/simple_animal/cat_black.dmi' + butchery_data = /decl/butchery_data/animal/cat/black + holder_type = /obj/item/holder/runtime + +/obj/item/holder/runtime + origin_tech = @'{"programming":1,"biotech":1}' -/mob/living/simple_animal/cat/kitten +/mob/living/simple_animal/passive/cat/kitten name = "kitten" desc = "D'aaawwww" - icon_state = "kitten" - item_state = "kitten" - icon_living = "kitten" - icon_dead = "kitten_dead" + icon = 'icons/mob/simple_animal/kitten.dmi' gender = NEUTER - meat_amount = 1 - bone_amount = 3 - skin_amount = 3 - -// Leaving this here for now. -/obj/item/holder/cat/fluff/bones - name = "Bones" - desc = "It's Bones! Meow." - gender = MALE - icon_state = "cat3" - -/mob/living/simple_animal/cat/fluff/bones - name = "Bones" - desc = "That's Bones the cat. He's a laid back, black cat. Meow." - gender = MALE - icon_state = "cat3" - item_state = "cat3" - icon_living = "cat3" - icon_dead = "cat3_dead" - holder_type = /obj/item/holder/cat/fluff/bones - var/friend_name = "Erstatz Vryroxes" - -/mob/living/simple_animal/cat/kitten/Initialize() + butchery_data = /decl/butchery_data/animal/cat/kitten + +/mob/living/simple_animal/passive/cat/kitten/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/kitten) + +/decl/bodytype/quadruped/animal/kitten + uid = "bodytype_animal_kitten" + +/decl/bodytype/quadruped/animal/kitten/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 1, -14), + "[SOUTH]" = list( 1, -14), + "[EAST]" = list( 5, -14), + "[WEST]" = list(-5, -14) + ) + ) + . = ..() + +/mob/living/simple_animal/passive/cat/kitten/Initialize() . = ..() - gender = pick(MALE, FEMALE) + set_gender(pick(MALE, FEMALE)) -/mob/living/simple_animal/cat/fluff/ran +/mob/living/simple_animal/passive/cat/fluff/ran name = "Runtime" desc = "Under no circumstances is this feline allowed inside the atmospherics system." gender = FEMALE - icon_state = "cat2" - item_state = "cat2" - icon_living = "cat2" - icon_dead = "cat2_dead" - -/mob/living/simple_animal/cat/harvest_skin() - . = ..() - . += new/obj/item/cat_hide(get_turf(src)) + holder_type = /obj/item/holder/runtime -/obj/item/cat_hide - name = "cat hide" - desc = "The by-product of cat farming." - icon = 'icons/obj/items/sheet_hide.dmi' - icon_state = "sheet-cat" \ No newline at end of file +/mob/living/simple_animal/passive/cat/fluff/felix + name = "Felix" + desc = "A very oddly-behaved, malnourished cat. Their scratched name tag reads 'Felix'." diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm index bc390a61655d..a125c209d960 100644 --- a/code/modules/mob/living/simple_animal/friendly/corgi.dm +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -1,32 +1,56 @@ //Corgi /mob/living/simple_animal/corgi - name = "\improper corgi" + name = "corgi" real_name = "corgi" desc = "It's a corgi." - icon_state = "corgi" - icon_living = "corgi" - icon_dead = "corgi_dead" - speak = list("YAP", "Woof!", "Bark!", "AUUUUUU") - speak_emote = list("barks", "woofs") - emote_hear = list("barks", "woofs", "yaps","pants") - emote_see = list("shakes its head", "shivers") - speak_chance = 1 - turns_per_move = 10 - response_help = "pets" + icon = 'icons/mob/simple_animal/corgi.dmi' + speak_emote = list("barks", "woofs") response_disarm = "bops" - response_harm = "kicks" see_in_dark = 5 mob_size = MOB_SIZE_SMALL - possession_candidate = 1 + possession_candidate = TRUE holder_type = /obj/item/holder/corgi pass_flags = PASS_FLAG_TABLE - - meat_type = /obj/item/chems/food/snacks/meat/corgi - meat_amount = 3 - skin_material = /decl/material/solid/skin/fur/orange - - var/obj/item/inventory_head - var/obj/item/inventory_back + base_animal_type = /mob/living/simple_animal/corgi + can_buckle = TRUE + butchery_data = /decl/butchery_data/animal/corgi + ai = /datum/mob_controller/corgi + +/datum/mob_controller/corgi + emote_speech = list("YAP", "Woof!", "Bark!", "AUUUUUU") + emote_hear = list("barks", "woofs", "yaps","pants") + emote_see = list("shakes its head", "shivers") + speak_chance = 0.25 + turns_per_wander = 20 + +/datum/mob_controller/corgi/proc/dance() + set waitfor = FALSE + if(QDELETED(body) || body.client) + return + var/decl/pronouns/pronouns = body.get_pronouns() + body.custom_emote(VISIBLE_MESSAGE, pick("dances around.","chases [pronouns.his] tail.")) + for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2)) + body.set_dir(i) + sleep(1) + if(QDELETED(body) || body.client) + return + +/mob/living/simple_animal/corgi/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/corgi) + +/decl/bodytype/quadruped/animal/corgi + uid = "bodytype_animal_corgi" + +/decl/bodytype/quadruped/animal/corgi/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 1, -8), + "[SOUTH]" = list( 1, -8), + "[EAST]" = list( 7, -8), + "[WEST]" = list(-7, -8) + ) + ) + . = ..() //IAN! SQUEEEEEEEEE~ /mob/living/simple_animal/corgi/Ian @@ -34,110 +58,112 @@ real_name = "Ian" //Intended to hold the name without altering it. gender = MALE desc = "It's a corgi." + ai = /datum/mob_controller/corgi/ian + +/datum/mob_controller/corgi/ian var/turns_since_scan = 0 var/obj/movement_target - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" -/mob/living/simple_animal/corgi/Ian/do_delayed_life_action() - ..() - //Feeding, chasing food, FOOOOODDDD - if(!resting && !buckled) - turns_since_scan++ - if(turns_since_scan > 5) - turns_since_scan = 0 - if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) )) - movement_target = null - stop_automated_movement = 0 - if( !movement_target || !(movement_target.loc in oview(src, 3)) ) - movement_target = null - stop_automated_movement = 0 - for(var/obj/item/chems/food/snacks/S in oview(src,3)) - if(isturf(S.loc) || ishuman(S.loc)) - movement_target = S - break - if(movement_target) - stop_automated_movement = 1 - step_to(src,movement_target,1) - sleep(3) - step_to(src,movement_target,1) - sleep(3) - step_to(src,movement_target,1) - - if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds - if (movement_target.loc.x < src.x) - set_dir(WEST) - else if (movement_target.loc.x > src.x) - set_dir(EAST) - else if (movement_target.loc.y < src.y) - set_dir(SOUTH) - else if (movement_target.loc.y > src.y) - set_dir(NORTH) - else - set_dir(SOUTH) - - if(isturf(movement_target.loc) ) - UnarmedAttack(movement_target) - else if(ishuman(movement_target.loc) && prob(20)) - visible_emote("stares at the [movement_target] that [movement_target.loc] has with sad puppy eyes.") - - if(prob(1)) - visible_emote(pick("dances around.","chases their tail.")) - for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2)) - set_dir(i) - sleep(1) - if(QDELETED(src) || client) - return - -/obj/item/chems/food/snacks/meat/corgi - name = "Corgi meat" - desc = "Tastes like... well you know..." - -/mob/living/simple_animal/corgi/attackby(var/obj/item/O, var/mob/user) //Marker -Agouri - if(istype(O, /obj/item/newspaper)) - if(!stat) - for(var/mob/M in viewers(user, null)) - if ((M.client && !( M.blinded ))) - M.show_message("[user] baps [name] on the nose with the rolled up [O]") - spawn(0) - for(var/i in list(1,2,4,8,4,2,1,2)) - set_dir(i) - sleep(1) +/datum/mob_controller/corgi/ian/proc/go_get_lunch() + set waitfor = FALSE + + if(!movement_target || !body || body.stat) + return + + stop_wandering() + step_to(body, movement_target,1) + sleep(3) + if(!movement_target || !body || body.stat) + return + + step_to(body, movement_target,1) + sleep(3) + if(!movement_target || !body || body.stat) + return + + step_to(body, movement_target,1) + if(!movement_target || !body || body.stat) + return + + if (movement_target.loc.x < body.x) + body.set_dir(WEST) + else if (movement_target.loc.x > body.x) + body.set_dir(EAST) + else if (movement_target.loc.y < body.y) + body.set_dir(SOUTH) + else if (movement_target.loc.y > body.y) + body.set_dir(NORTH) else - ..() - -/mob/living/simple_animal/corgi/regenerate_icons() - overlays = list() + body.set_dir(SOUTH) + if(isturf(movement_target.loc) && body.Adjacent(movement_target)) + body.UnarmedAttack(movement_target, TRUE) + else if(ishuman(movement_target.loc) && prob(20)) + body.custom_emote(VISIBLE_MESSAGE, "stares at the [movement_target] that [movement_target.loc] has with sad puppy eyes.") - if(inventory_head) - var/head_icon_state = inventory_head.icon_state - if(health <= 0) - head_icon_state += "2" +/datum/mob_controller/corgi/ian/do_process(time_elapsed) - var/icon/head_icon = image('icons/mob/simple_animal/corgi_head.dmi',head_icon_state) - if(head_icon) - overlays += head_icon + if(!(. = ..()) || body.stat || body.current_posture?.prone || body.buckled) + return - if(inventory_back) - var/back_icon_state = inventory_back.icon_state - if(health <= 0) - back_icon_state += "2" - - var/icon/back_icon = image('icons/mob/simple_animal/corgi_back.dmi',back_icon_state) - if(back_icon) - overlays += back_icon + //Feeding, chasing food, FOOOOODDDD + turns_since_scan++ + if(turns_since_scan > 10) + turns_since_scan = 0 + if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) )) + movement_target = null + resume_wandering() + if( !movement_target || !(movement_target.loc in oview(body, 3)) ) + movement_target = null + resume_wandering() + for(var/obj/item/food/S in oview(body, 3)) + if(isturf(S.loc) || ishuman(S.loc)) + movement_target = S + break + if(movement_target) + go_get_lunch() + return + + if(prob(1)) + dance() + +/mob/living/simple_animal/corgi/attackby(var/obj/item/used_item, var/mob/user) //Marker -Agouri + if(istype(used_item, /obj/item/newspaper) && !stat) + visible_message(SPAN_NOTICE("\The [user] baps \the [src] on the nose with the rolled-up [used_item.name]!")) + var/datum/mob_controller/corgi/corgi_ai = ai + if(istype(corgi_ai)) + corgi_ai.dance() + return TRUE + else + return ..() /mob/living/simple_animal/corgi/puppy name = "\improper corgi puppy" real_name = "corgi" desc = "It's a corgi puppy." - icon_state = "puppy" - icon_living = "puppy" - icon_dead = "puppy_dead" - meat_amount = 1 - skin_amount = 3 - bone_amount = 3 + icon = 'icons/mob/simple_animal/puppy.dmi' + can_buckle = FALSE + butchery_data = /decl/butchery_data/animal/corgi/puppy + +/mob/living/simple_animal/corgi/puppy/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/puppy) + +/decl/bodytype/quadruped/animal/puppy + uid = "bodytype_animal_puppy" + +/decl/bodytype/quadruped/animal/puppy/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 0, -12), + "[SOUTH]" = list( 0, -12), + "[EAST]" = list( 5, -14), + "[WEST]" = list(-5, -14) + ) + ) + . = ..() + +/mob/living/simple_animal/corgi/puppy/Initialize() + . = ..() + set_gender(pick(MALE, FEMALE)) //pupplies cannot wear anything. /mob/living/simple_animal/corgi/puppy/OnTopic(mob/user, href_list) @@ -152,14 +178,41 @@ real_name = "Lisa" gender = FEMALE desc = "It's a corgi with a cute pink bow." - icon_state = "lisa" - icon_living = "lisa" - icon_dead = "lisa_dead" - response_help = "pets" - response_disarm = "bops" - response_harm = "kicks" - var/turns_since_scan = 0 + icon = 'icons/mob/simple_animal/corgi_lisa.dmi' + ai = /datum/mob_controller/corgi/lisa + +/datum/mob_controller/corgi/lisa var/puppies = 0 + var/turns_since_scan = 0 + +/datum/mob_controller/corgi/lisa/do_process(time_elapsed) + + if(!(. = ..()) || body.stat || body.current_posture?.prone || body.buckled) + return + + turns_since_scan++ + if(turns_since_scan > 30) + turns_since_scan = 0 + var/alone = 1 + var/mob/living/ian + for(var/mob/M in oviewers(7, body)) + if(istype(M, /mob/living/simple_animal/corgi/Ian)) + if(M.client) + alone = 0 + break + else + ian = M + else + alone = 0 + break + if(alone && ian && puppies < 4) + if(body.near_camera() || ian.near_camera()) + return + new /mob/living/simple_animal/corgi/puppy(body.loc) + puppies++ + + if(prob(1)) + dance() //Lisa already has a cute bow! /mob/living/simple_animal/corgi/Lisa/OnTopic(mob/user, href_list) @@ -167,45 +220,3 @@ to_chat(user, "[src] already has a cute bow!") return TOPIC_HANDLED return ..() - -/mob/living/simple_animal/corgi/Lisa/do_delayed_life_action() - ..() - if(!resting && !buckled) - turns_since_scan++ - if(turns_since_scan > 15) - turns_since_scan = 0 - var/alone = 1 - var/ian = 0 - for(var/mob/M in oviewers(7, src)) - if(istype(M, /mob/living/simple_animal/corgi/Ian)) - if(M.client) - alone = 0 - break - else - ian = M - else - alone = 0 - break - if(alone && ian && puppies < 4) - if(near_camera(src) || near_camera(ian)) - return - new /mob/living/simple_animal/corgi/puppy(loc) - - - if(prob(1)) - visible_emote(pick("dances around","chases her tail")) - for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2)) - set_dir(i) - sleep(1) - if(QDELETED(src) || client) - return - -/mob/living/simple_animal/corgi/harvest_skin() - . = ..() - . += new/obj/item/corgi_hide(get_turf(src)) - -/obj/item/corgi_hide - name = "corgi hide" - desc = "The by-product of corgi farming." - icon = 'icons/obj/items/sheet_hide.dmi' - icon_state = "sheet-corgi" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm index 118e4c3dfdf7..a35f3dfa013a 100644 --- a/code/modules/mob/living/simple_animal/friendly/crab.dm +++ b/code/modules/mob/living/simple_animal/friendly/crab.dm @@ -2,48 +2,55 @@ /mob/living/simple_animal/crab name = "crab" desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time." - icon_state = "crab" - icon_living = "crab" - icon_dead = "crab_dead" + icon = 'icons/mob/simple_animal/crab.dmi' mob_size = MOB_SIZE_SMALL speak_emote = list("clicks") - emote_hear = list("clicks") - emote_see = list("clacks") - speak_chance = 1 - turns_per_move = 5 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "stomps" - stop_automated_movement = 1 - friendly = "pinches" - possession_candidate = 1 - can_escape = TRUE //snip snip + response_harm = "stamps on" + possession_candidate = TRUE pass_flags = PASS_FLAG_TABLE natural_armor = list( - melee = ARMOR_MELEE_KNIVES + ARMOR_MELEE = ARMOR_MELEE_KNIVES ) + ai = /datum/mob_controller/crab + butchery_data = /decl/butchery_data/animal/arthropod/crab + +/datum/mob_controller/crab + emote_hear = list("clicks") + emote_see = list("clacks") + speak_chance = 0.25 + turns_per_wander = 10 + wander_directions = list(EAST, WEST) // they only go sideways... + can_escape_buckles = TRUE //snip snip - meat_amount = 3 - skin_material = /decl/material/solid/skin/insect - skin_amount = 10 - bone_material = null - bone_amount = 0 +// TODO +/decl/bodytype/hexapod + abstract_type = /decl/bodytype/hexapod - var/obj/item/inventory_head - var/obj/item/inventory_mask +/decl/bodytype/hexapod/animal + abstract_type = /decl/bodytype/hexapod/animal + name = "hexapod animal" + bodytype_flag = 0 + bodytype_category = "hexapodal animal body" -/mob/living/simple_animal/crab/Life() +/decl/bodytype/hexapod/get_ignited_icon_state(mob/living/victim) + return "Generic_mob_burning" + +/mob/living/simple_animal/crab/get_bodytype() + return GET_DECL(/decl/bodytype/hexapod/animal/crab) + +/decl/bodytype/hexapod/animal/crab + uid = "bodytype_animal_crab" + +/decl/bodytype/hexapod/animal/crab/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list(-1, -10), + "[SOUTH]" = list(-1, -10), + "[EAST]" = list(-1, -10), + "[WEST]" = list(-1, -10) + ) + ) . = ..() - if(!.) - return FALSE - //CRAB movement - if(!ckey && !stat) - if(isturf(src.loc) && !resting && !buckled) //This is so it only moves if it's not inside a closet, gentics machine, etc. - turns_since_move++ - if(turns_since_move >= turns_per_move) - Move(get_step(src,pick(4,8))) - turns_since_move = 0 - regenerate_icons() //COFFEE! SQUEEEEEEEEE! /mob/living/simple_animal/crab/Coffee diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 99f7e4d2094a..31c6b6c8a213 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -1,285 +1,355 @@ -//goat -/mob/living/simple_animal/hostile/retaliate/goat +/mob/living/simple_animal/hostile/goat name = "goat" desc = "Not known for their pleasant disposition." - icon_state = "goat" - icon_living = "goat" - icon_dead = "goat_dead" - speak = list("EHEHEHEHEH","eh?") - speak_emote = list("brays") - emote_hear = list("brays") - emote_see = list("shakes its head", "stamps a foot", "glares around") - speak_chance = 1 - turns_per_move = 5 + icon = 'icons/mob/simple_animal/goat.dmi' + speak_emote = list("brays") + see_in_dark = 6 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" faction = "goat" - health = 40 + max_health = 40 natural_weapon = /obj/item/natural_weapon/hooves - - meat_type = /obj/item/chems/food/snacks/meat/goat - meat_amount = 4 - bone_amount = 8 - skin_material = /decl/material/solid/skin/goat - skin_amount = 8 - - var/datum/reagents/udder = null - -/mob/living/simple_animal/hostile/retaliate/goat/Initialize() - . = ..() - udder = new(50, src) - -/mob/living/simple_animal/hostile/retaliate/goat/Destroy() - QDEL_NULL(udder) - . = ..() - -/mob/living/simple_animal/hostile/retaliate/goat/Life() - . = ..() - if(.) - //chance to go crazy and start wacking stuff - if(!enemies.len && prob(1)) - Retaliate() - - if(enemies.len && prob(10)) - enemies = list() - LoseTarget() - src.visible_message("\The [src] calms down.") - - if(stat == CONSCIOUS) - if(udder && prob(5)) - udder.add_reagent(/decl/material/liquid/drink/milk, rand(5, 10)) - - if(locate(/obj/effect/vine) in loc) - var/obj/effect/vine/SV = locate() in loc - if(prob(60)) - src.visible_message("\The [src] eats the plants.") - SV.die_off(1) - if(locate(/obj/machinery/portable_atmospherics/hydroponics/soil/invisible) in loc) - var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/SP = locate() in loc - qdel(SP) - else if(prob(20)) - src.visible_message("\The [src] chews on the plants.") - return - - if(!LAZYLEN(grabbed_by)) - var/obj/effect/vine/food - food = locate(/obj/effect/vine) in oview(5,loc) - if(food) - var/step = get_step_to(src, food, 0) - Move(step) - -/mob/living/simple_animal/hostile/retaliate/goat/Retaliate() + butchery_data = /decl/butchery_data/animal/ruminant/goat + ai = /datum/mob_controller/aggressive/goat + +/datum/mob_controller/aggressive/goat + expected_type = /mob/living/simple_animal/hostile/goat + emote_speech = list("EHEHEHEHEH","eh?") + emote_hear = list("brays") + emote_see = list("shakes its head", "stamps a foot", "glares around") + speak_chance = 0.25 + turns_per_wander = 10 + only_attack_enemies = TRUE + +/datum/mob_controller/aggressive/goat/retaliate(atom/source) ..() - if(stat == CONSCIOUS && prob(50)) - visible_message("\The [src] gets an evil-looking gleam in their eye.") - -/mob/living/simple_animal/hostile/retaliate/goat/attackby(var/obj/item/O, var/mob/user) - var/obj/item/chems/glass/G = O - if(stat == CONSCIOUS && istype(G) && ATOM_IS_OPEN_CONTAINER(G)) - user.visible_message("[user] milks [src] using \the [O].") - var/transfered = udder.trans_type_to(G, /decl/material/liquid/drink/milk, rand(5,10)) - if(G.reagents.total_volume >= G.volume) - to_chat(user, "\The [O] is full.") - if(!transfered) - to_chat(user, "The udder is dry. Wait a bit longer...") + if(body?.stat == CONSCIOUS && prob(50)) + var/decl/pronouns/pronouns = body.get_pronouns() + body.visible_message(SPAN_DANGER("\The [body] gets an evil-looking gleam in [pronouns.his] eye.")) + +/datum/mob_controller/aggressive/goat/proc/find_edible_atom(list/targets) + // TODO: add /obj/structure/flora here and in goat/ResolveUnarmedAttack() + var/atom/maybe_food = locate(/obj/effect/vine) in targets + if(!istype(maybe_food)) + for(var/obj/machinery/portable_atmospherics/hydroponics/tray in targets) + if(tray.seed) + maybe_food = tray + break + if(istype(maybe_food)) + if(get_dist(body, maybe_food) > 1 || body.Adjacent(maybe_food)) + return maybe_food + +/datum/mob_controller/aggressive/goat/do_process(time_elapsed) + + if(!(. = ..()) || body.stat) + return + + //chance to go crazy and start wacking stuff + var/list/enemies = get_enemies() + if(!LAZYLEN(enemies) && prob(0.5)) + retaliate() + + if(LAZYLEN(enemies) && prob(5)) + clear_enemies() + lose_target() + body.visible_message(SPAN_NOTICE("\The [body] calms down.")) + + if(get_target()) + return + + var/atom/food = find_edible_atom(view(1, body.loc)) + if(istype(food)) + body.stop_automove() + body.set_intent(I_FLAG_HELP) + body.ClickOn(food) + else if(!LAZYLEN(body.grabbed_by)) + food = find_edible_atom(oview(5, body.loc)) + if(istype(food)) + body.start_automove(food) + else + body.stop_automove() else - ..() + body.stop_automove() + +/mob/living/simple_animal/hostile/goat/Initialize() + . = ..() + set_extension(src, /datum/extension/milkable/goat) + +/mob/living/simple_animal/hostile/goat/ResolveUnarmedAttack(var/atom/A) + var/was_food = FALSE + if(prob(30)) + if(istype(A, /obj/effect/vine)) + var/obj/effect/vine/SV = A + SV.die_off(1) + was_food = TRUE + else if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/tray = A + if(tray.seed) + was_food = TRUE + tray.die() + if(!QDELETED(tray)) + tray.remove_dead(silent = TRUE) // this will qdel invisible trays + if(was_food) + visible_message(SPAN_NOTICE("\The [src] eats \the [A].")) + return TRUE + return ..() -//cow /mob/living/simple_animal/cow name = "cow" desc = "Known for their milk, just don't tip them over." - icon_state = "cow" - icon_living = "cow" - icon_dead = "cow_dead" - icon_gib = "cow_gib" - speak = list("moo?","moo","MOOOOOO") - speak_emote = list("moos","moos hauntingly") - emote_hear = list("brays") - emote_see = list("shakes its head") - speak_chance = 1 - turns_per_move = 5 + icon = 'icons/mob/simple_animal/cow.dmi' + speak_emote = list("moos","moos hauntingly") + ai = /datum/mob_controller/cow see_in_dark = 6 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - health = 50 - - meat_type = /obj/item/chems/food/snacks/meat/beef - meat_amount = 6 - bone_amount = 10 - skin_material = /decl/material/solid/skin/cow - skin_amount = 10 - - var/datum/reagents/udder = null + max_health = 50 + butchery_data = /decl/butchery_data/animal/ruminant/cow + // When cows can accept food items: /obj/item/food/hay + var/static/list/responses = list( + "looks at you imploringly", + "looks at you pleadingly", + "looks at you with a resigned expression", + "seems resigned to its fate" + ) + +/datum/mob_controller/cow + emote_speech = list("moo?","moo","MOOOOOO") + emote_hear = list("brays") + emote_see = list("shakes its head") + speak_chance = 0.25 + turns_per_wander = 10 /mob/living/simple_animal/cow/Initialize() . = ..() - udder = new(50, src) - -/mob/living/simple_animal/cow/attackby(var/obj/item/O, var/mob/user) - var/obj/item/chems/glass/G = O - if(stat == CONSCIOUS && istype(G) && ATOM_IS_OPEN_CONTAINER(G)) - user.visible_message("[user] milks [src] using \the [O].") - var/transfered = udder.trans_type_to(G, /decl/material/liquid/drink/milk, rand(5,10)) - if(G.reagents.total_volume >= G.volume) - to_chat(user, "\The [O] is full.") - if(!transfered) - to_chat(user, "The udder is dry. Wait a bit longer...") - else - ..() + set_extension(src, /datum/extension/milkable) -/mob/living/simple_animal/cow/Life() - . = ..() - if(!.) - return FALSE - if(udder && prob(5)) - udder.add_reagent(/decl/material/liquid/drink/milk, rand(5, 10)) - -/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M) - if(!stat && M.a_intent == I_DISARM && icon_state != icon_dead) - M.visible_message("[M] tips over [src].","You tip over [src].") - Weaken(30) - icon_state = icon_dead - spawn(rand(20,50)) - if(!stat && M) - icon_state = icon_living - var/list/responses = list( "[src] looks at you imploringly.", - "[src] looks at you pleadingly", - "[src] looks at you with a resigned expression.", - "[src] seems resigned to its fate.") - to_chat(M, pick(responses)) - else - ..() +/mob/living/simple_animal/cow/default_disarm_interaction(mob/user) + if(stat != DEAD && !HAS_STATUS(src, STAT_WEAK)) + user.visible_message(SPAN_NOTICE("\The [user] tips over \the [src].")) + SET_STATUS_MAX(src, STAT_WEAK, 30) + addtimer(CALLBACK(src, PROC_REF(do_tip_response)), rand(20, 50)) + return TRUE + return ..() + +/mob/living/simple_animal/cow/proc/do_tip_response() + if(stat == CONSCIOUS) + visible_message("\The [src] [pick(responses)].") /mob/living/simple_animal/chick - name = "\improper chick" + name = "chick" desc = "Adorable! They make such a racket though." - icon_state = "chick" - icon_living = "chick" - icon_dead = "chick_dead" - icon_gib = "chick_gib" - speak = list("Cherp.","Cherp?","Chirrup.","Cheep!") - speak_emote = list("cheeps") - emote_hear = list("cheeps") - emote_see = list("pecks at the ground","flaps its tiny wings") - speak_chance = 2 - turns_per_move = 2 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - health = 1 + icon = 'icons/mob/simple_animal/chick.dmi' + speak_emote = list("cheeps") + max_health = 1 pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GRILLE mob_size = MOB_SIZE_MINISCULE - - meat_type = /obj/item/chems/food/snacks/meat/chicken - meat_amount = 1 - bone_amount = 3 - skin_amount = 3 - skin_material = /decl/material/solid/skin/feathers - + butchery_data = /decl/butchery_data/animal/small/fowl/chicken/chick + ai = /datum/mob_controller/chick + holder_type = /obj/item/holder var/amount_grown = 0 + var/decl/skill/examine_skill = SKILL_BOTANY // for maps that change the default skills, or for alien eggs that need science/medical/anatomy instead + var/examine_difficulty = SKILL_ADEPT + +/mob/living/simple_animal/chick/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(!user.skill_check(examine_skill, examine_difficulty)) + var/decl/skill/examine_skill_decl = GET_DECL(examine_skill) + . += SPAN_SUBTLE("If you knew more about [lowertext(examine_skill_decl.name)], you could learn additional information about this.") + return + switch(amount_grown) + if(0 to 20) + . += SPAN_NOTICE("It's still young.") + if(20 to 40) + . += SPAN_NOTICE("It's starting to grow in its adult feathers.") + if(40 to 80) + . += SPAN_NOTICE("It's grown in almost all its adult feathers.") + if(80 to 100) + . += SPAN_NOTICE("It's almost fully grown.") + +/datum/mob_controller/chick + emote_speech = list("Cherp.","Cherp?","Chirrup.","Cheep!") + emote_hear = list("cheeps") + emote_see = list("pecks at the ground","flaps its tiny wings") + speak_chance = 0.5 + turns_per_wander = 4 /mob/living/simple_animal/chick/Initialize() . = ..() pixel_x = rand(-6, 6) pixel_y = rand(0, 10) -/mob/living/simple_animal/chick/Life() - . = ..() - if(!.) - return FALSE - amount_grown += rand(1,2) - if(amount_grown >= 100) - new /mob/living/simple_animal/chicken(src.loc) - qdel(src) - -var/const/MAX_CHICKENS = 50 -var/global/chicken_count = 0 +/mob/living/simple_animal/chick/handle_living_non_stasis_processes() + if((. = ..())) + if(prob(50)) // should take around 4 or 5 minutes to grow up, give or take + amount_grown += rand(1, 2) + if(amount_grown >= 100) + new /mob/living/simple_animal/fowl/chicken(src.loc) + qdel(src) -/mob/living/simple_animal/chicken - name = "\improper chicken" - desc = "Hopefully the eggs are good this season." - icon_state = "chicken" - icon_living = "chicken" - icon_dead = "chicken_dead" - speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.") - speak_emote = list("clucks","croons") - emote_hear = list("clucks") - emote_see = list("pecks at the ground","flaps its wings viciously") - speak_chance = 2 - turns_per_move = 3 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - health = 10 +/mob/living/simple_animal/fowl + max_health = 10 pass_flags = PASS_FLAG_TABLE mob_size = MOB_SIZE_SMALL + butchery_data = /decl/butchery_data/animal/small/fowl + ai = /datum/mob_controller/fowl + abstract_type = /mob/living/simple_animal/fowl + var/body_color - meat_type = /obj/item/chems/food/snacks/meat/chicken - meat_amount = 2 - skin_material = /decl/material/solid/skin/feathers +/datum/mob_controller/fowl + speak_chance = 1 + turns_per_wander = 6 +/mob/living/simple_animal/fowl/Initialize() + if(!default_pixel_x) + default_pixel_x = rand(-6, 6) + if(!default_pixel_y) + default_pixel_y = rand(0, 10) + . = ..() + +var/global/const/MAX_CHICKENS = 50 +var/global/chicken_count = 0 +/mob/living/simple_animal/fowl/chicken + name = "chicken" + desc = "Hopefully the eggs are good this season." + icon = 'icons/mob/simple_animal/chicken_white.dmi' + speak_emote = list("clucks","croons") + butchery_data = /decl/butchery_data/animal/small/fowl/chicken + ai = /datum/mob_controller/fowl/chicken + holder_type = /obj/item/holder var/eggsleft = 0 - var/body_color -/mob/living/simple_animal/chicken/Initialize() +/datum/mob_controller/fowl/chicken + emote_speech = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.") + emote_hear = list("clucks") + emote_see = list("pecks at the ground","flaps its wings viciously") + +/mob/living/simple_animal/fowl/chicken/Initialize() . = ..() if(!body_color) - body_color = pick( list("brown","black","white") ) - icon_state = "chicken_[body_color]" - icon_living = "chicken_[body_color]" - icon_dead = "chicken_[body_color]_dead" - pixel_x = rand(-6, 6) - pixel_y = rand(0, 10) - chicken_count += 1 - -/mob/living/simple_animal/chicken/death(gibbed, deathmessage, show_dead_message) - ..(gibbed, deathmessage, show_dead_message) - chicken_count -= 1 - -/mob/living/simple_animal/chicken/attackby(var/obj/item/O, var/mob/user) - if(istype(O, /obj/item/chems/food/snacks/grown)) //feedin' dem chickens - var/obj/item/chems/food/snacks/grown/G = O - if(G.seed && G.seed.kitchen_tag == "wheat") - if(!stat && eggsleft < 8) - user.visible_message("[user] feeds [O] to [name]! It clucks happily.","You feed [O] to [name]! It clucks happily.") - qdel(O) - eggsleft += rand(1, 4) - else - to_chat(user, "[name] doesn't seem hungry!") + body_color = pick("brown", "black", "white") + update_icon() + global.chicken_count += 1 + +/mob/living/simple_animal/fowl/chicken/on_update_icon() + . = ..() + switch(body_color) + if("brown") + icon = 'icons/mob/simple_animal/chicken_brown.dmi' + if("black") + icon = 'icons/mob/simple_animal/chicken_black.dmi' else - to_chat(user, "[name] doesn't seem interested in that.") - else - ..() + icon = 'icons/mob/simple_animal/chicken_white.dmi' -/mob/living/simple_animal/chicken/Life() +/mob/living/simple_animal/fowl/chicken/death(gibbed) . = ..() - if(!.) - return FALSE - if(prob(3) && eggsleft > 0) + if(.) + global.chicken_count -= 1 + +/mob/living/simple_animal/fowl/chicken/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/food)) + return ..() + var/obj/item/food/G = used_item //feedin' dem chickens + if(findtext(G.get_grown_tag(), "wheat")) // includes chopped, crushed, dried etc. + if(!stat && eggsleft < 4) + user.visible_message(SPAN_NOTICE("[user] feeds \the [used_item] to \the [src]! It clucks happily."), SPAN_NOTICE("You feed \the [used_item] to \the [src]! It clucks happily."), SPAN_NOTICE("You hear clucking.")) + qdel(used_item) + eggsleft += rand(1, 2) + else + to_chat(user, SPAN_NOTICE("\The [src] doesn't seem hungry!")) + else + to_chat(user, "\The [src] doesn't seem interested in that.") + return TRUE + +/mob/living/simple_animal/fowl/chicken/handle_living_non_stasis_processes() + if((. = ..()) && prob(1) && eggsleft > 0) visible_message("[src] [pick("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")]") eggsleft-- - var/obj/item/chems/food/snacks/egg/E = new(get_turf(src)) + var/obj/item/food/egg/E = new(get_turf(src)) E.pixel_x = rand(-6,6) E.pixel_y = rand(-6,6) - if(chicken_count < MAX_CHICKENS && prob(10)) + if(chicken_count < MAX_CHICKENS && prob(30)) E.amount_grown = 1 START_PROCESSING(SSobj, E) -/obj/item/chems/food/snacks/egg +/mob/living/simple_animal/fowl/duck + name = "duck" + desc = "It's a duck. Quack." + icon = 'icons/mob/simple_animal/duck_white.dmi' + speak_emote = list("quacks") + butchery_data = /decl/butchery_data/animal/small/fowl/duck + ai = /datum/mob_controller/fowl/duck + +/datum/mob_controller/fowl/duck + emote_speech = list("Wak!","Wak wak wak!","Wak wak.") + emote_hear = list("quacks") + emote_see = list("preens itself", "waggles its tail") + +/mob/living/simple_animal/fowl/duck/Initialize() + . = ..() + if(!body_color) + body_color = pick("brown", "mallard", "white") + update_icon() + +/mob/living/simple_animal/fowl/duck/on_update_icon() + . = ..() + switch(body_color) + if("brown") + icon = 'icons/mob/simple_animal/duck_brown.dmi' + if("mallard") + icon = 'icons/mob/simple_animal/duck_mallard.dmi' + else + icon = 'icons/mob/simple_animal/duck_white.dmi' + +/obj/item/food/egg var/amount_grown = 0 + var/decl/skill/examine_skill = SKILL_BOTANY // for maps that change the default skills, or for alien eggs that need science/medical/anatomy instead + var/examine_difficulty = SKILL_ADEPT -/obj/item/chems/food/snacks/egg/Destroy() +/obj/item/food/egg/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(isnull(examine_difficulty) || !ispath(examine_skill)) + return + if(!user.skill_check(examine_skill, examine_difficulty)) + var/decl/skill/examine_skill_decl = GET_DECL(examine_skill) + . += SPAN_SUBTLE("If you knew more about [lowertext(examine_skill_decl.name)], you could learn additional information about this.") + return + if(distance > 1) + . += SPAN_SUBTLE("You're too far away to learn anything about this.") + return + if(!user.get_held_slot_for_item(src)) + . += SPAN_NOTICE("You need to be holding \the [src] to examine it closer.") + return + // need a lit candle or lantern to check + var/too_hot = FALSE + var/obj/item/candle // not necessarily an actual candle, just a light source that won't fry the egg + for(var/obj/item/I in user.get_held_items()) + if(I.light_power && I.light_range) // we have a light! todo: minimum power? + if(I.get_heat() >= /obj/item/flame/fuelled/lighter::lit_heat) // lighters are too hot! + too_hot = TRUE + candle = I + if(!too_hot) + break + if(too_hot) + . += SPAN_WARNING("You can't use \the [candle] to examine \the [src], that would fry it!") + return + else if(!candle) + . += SPAN_NOTICE("You need to be holding a light source to examine this closer.") + return + switch(amount_grown) + if(0) + . += SPAN_NOTICE("\The [src] is unfertilized.") + if(10 to 80) + . += SPAN_NOTICE("There's something growing inside \the [src].") + if(80 to 100) + . += SPAN_NOTICE("\The [src] is about to hatch!") + +/obj/item/food/egg/Destroy() if(amount_grown) STOP_PROCESSING(SSobj, src) . = ..() -/obj/item/chems/food/snacks/egg/Process() +/obj/item/food/egg/Process() if(isturf(loc)) - amount_grown += rand(1,2) + if(prob(50)) + amount_grown++ if(amount_grown >= 100) visible_message("[src] hatches with a quiet cracking sound.") new /mob/living/simple_animal/chick(get_turf(src)) diff --git a/code/modules/mob/living/simple_animal/friendly/frog.dm b/code/modules/mob/living/simple_animal/friendly/frog.dm new file mode 100644 index 000000000000..f268abfe0c09 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/frog.dm @@ -0,0 +1,30 @@ +/mob/living/simple_animal/frog + name = "green frog" + desc = "A small, slimy amphibian. Likes to eat flies." + icon = 'icons/mob/simple_animal/frog_green.dmi' + speak_emote = list("ribbits","croaks") + response_harm = "stamps on" + density = FALSE + holder_type = /obj/item/holder + mob_size = MOB_SIZE_MINISCULE + max_health = 5 + butchery_data = /decl/butchery_data/animal/small/frog + ai = /datum/mob_controller/frog + +/datum/mob_controller/frog + emote_speech = list("Ribbit!","Riiibit!") + emote_hear = list("ribbits","croaks") + emote_see = list("hops","inflates its vocal sac","catches a fly with its tongue") + speak_chance = 0.25 + +/mob/living/simple_animal/frog/brown + name = "brown frog" + icon = 'icons/mob/simple_animal/frog_brown.dmi' + +/mob/living/simple_animal/frog/yellow + name = "yellow frog" + icon = 'icons/mob/simple_animal/frog_yellow.dmi' + +/mob/living/simple_animal/frog/purple + name = "purple frog" + icon = 'icons/mob/simple_animal/frog_purple.dmi' diff --git a/code/modules/mob/living/simple_animal/friendly/koala.dm b/code/modules/mob/living/simple_animal/friendly/koala.dm new file mode 100644 index 000000000000..d612c5be9130 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/koala.dm @@ -0,0 +1,17 @@ +//Koala +/mob/living/simple_animal/koala + name = "koala" + desc = "A little grey bear. How long is he gonna sleep today?" + icon = 'icons/mob/simple_animal/koala.dmi' + max_health = 45 + speak_emote = list("roar") + see_in_dark = 6 + ai = /datum/mob_controller/koala + +/datum/mob_controller/koala + emote_speech = list("Rrr", "Wraarh...", "Pfrrr...") + emote_hear = list("grunting.","rustling.", "slowly yawns.") + emote_see = list("slowly turns around his head.", "rises to his feet, and lays to the ground on all fours.") + speak_chance = 0.25 + turns_per_wander = 20 + stop_wander_when_pulled = TRUE diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm index ab37f054a780..e6bcea2be418 100644 --- a/code/modules/mob/living/simple_animal/friendly/lizard.dm +++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm @@ -1,23 +1,20 @@ /mob/living/simple_animal/lizard name = "lizard" desc = "A cute tiny lizard." - icon = 'icons/mob/simple_animal/critter.dmi' - icon_state = "lizard" - icon_living = "lizard" - icon_dead = "lizard-dead" + icon = 'icons/mob/simple_animal/lizard.dmi' speak_emote = list("hisses") - health = 5 - maxHealth = 5 + max_health = 5 natural_weapon = /obj/item/natural_weapon/bite/weak - response_help = "pets" - response_disarm = "shoos" - response_harm = "stomps on" + response_harm = "stamps on" mob_size = MOB_SIZE_MINISCULE - possession_candidate = 1 - can_escape = TRUE + possession_candidate = TRUE pass_flags = PASS_FLAG_TABLE + butchery_data = /decl/butchery_data/animal/reptile/small + ai = /datum/mob_controller/lizard + holder_type = /obj/item/holder - meat_amount = 1 - bone_amount = 1 - skin_amount = 1 - skin_material = /decl/material/solid/skin/lizard +/datum/mob_controller/lizard + can_escape_buckles = TRUE + +/mob/living/simple_animal/lizard/get_remains_type() + return /obj/item/remains/lizard diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm deleted file mode 100644 index facfe8e38594..000000000000 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ /dev/null @@ -1,132 +0,0 @@ -/mob/living/simple_animal/mouse - name = "mouse" - real_name = "mouse" - desc = "It's a small rodent." - icon_state = "mouse_gray" - item_state = "mouse_gray" - icon_living = "mouse_gray" - icon_dead = "mouse_gray_dead" - speak = list("Squeek!","SQUEEK!","Squeek?") - speak_emote = list("squeeks","squeeks","squiks") - emote_hear = list("squeeks","squeaks","squiks") - emote_see = list("runs in a circle", "shakes", "scritches at something") - pass_flags = PASS_FLAG_TABLE - speak_chance = 1 - turns_per_move = 5 - see_in_dark = 6 - maxHealth = 5 - health = 5 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "stamps on" - density = 0 - minbodytemp = 223 //Below -50 Degrees Celsius - maxbodytemp = 323 //Above 50 Degrees Celsius - universal_speak = FALSE - universal_understand = TRUE - holder_type = /obj/item/holder/mouse - mob_size = MOB_SIZE_MINISCULE - possession_candidate = 1 - can_escape = TRUE - can_pull_size = ITEM_SIZE_TINY - can_pull_mobs = MOB_PULL_NONE - - meat_amount = 1 - bone_amount = 1 - skin_amount = 1 - skin_material = /decl/material/solid/skin/fur - - var/body_color //brown, gray and white, leave blank for random - -/mob/living/simple_animal/mouse/Life() - . = ..() - if(!.) - return FALSE - if(prob(speak_chance)) - for(var/mob/M in view()) - sound_to(M, 'sound/effects/mousesqueek.ogg') - - if(!ckey && stat == CONSCIOUS && prob(0.5)) - set_stat(UNCONSCIOUS) - icon_state = "mouse_[body_color]_sleep" - wander = 0 - speak_chance = 0 - //snuffles - else if(stat == UNCONSCIOUS) - if(ckey || prob(1)) - set_stat(CONSCIOUS) - icon_state = "mouse_[body_color]" - wander = 1 - else if(prob(5)) - INVOKE_ASYNC(src, .proc/audible_emote, "snuffles.") - -/mob/living/simple_animal/mouse/lay_down() - ..() - icon_state = resting ? "mouse_[body_color]_sleep" : "mouse_[body_color]" - -/mob/living/simple_animal/mouse/Initialize() - . = ..() - - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide - - if(name == initial(name)) - name = "[name] ([sequential_id(/mob/living/simple_animal/mouse)])" - real_name = name - - if(!body_color) - body_color = pick( list("brown","gray","white") ) - - icon_state = "mouse_[body_color]" - item_state = "mouse_[body_color]" - icon_living = "mouse_[body_color]" - icon_dead = "mouse_[body_color]_dead" - desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." - -/mob/living/simple_animal/mouse/Initialize() - . = ..() - switch(body_color) - if("gray") - skin_material = /decl/material/solid/skin/fur/gray - if("white") - skin_material = /decl/material/solid/skin/fur/white - -/mob/living/simple_animal/mouse/proc/splat() - icon_dead = "mouse_[body_color]_splat" - adjustBruteLoss(maxHealth) // Enough damage to kill - src.death() - -/mob/living/simple_animal/mouse/Crossed(AM) - if( ishuman(AM) ) - if(!stat) - var/mob/M = AM - to_chat(M, "\icon[src] Squeek!") - sound_to(M, 'sound/effects/mousesqueek.ogg') - ..() - -/* - * Mouse types - */ - -/mob/living/simple_animal/mouse/white - body_color = "white" - icon_state = "mouse_white" - -/mob/living/simple_animal/mouse/gray - body_color = "gray" - icon_state = "mouse_gray" - -/mob/living/simple_animal/mouse/brown - body_color = "brown" - icon_state = "mouse_brown" - -//TOM IS ALIVE! SQUEEEEEEEE~K :) -/mob/living/simple_animal/mouse/brown/Tom - name = "Tom" - desc = "Jerry the cat is not amused." - -/mob/living/simple_animal/mouse/brown/Tom/Initialize() - . = ..() - // Change my name back, don't want to be named Tom (666) - SetName(initial(name)) - real_name = name \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/mushroom.dm b/code/modules/mob/living/simple_animal/friendly/mushroom.dm index cf08998a0eff..5b2e40b205af 100644 --- a/code/modules/mob/living/simple_animal/friendly/mushroom.dm +++ b/code/modules/mob/living/simple_animal/friendly/mushroom.dm @@ -1,30 +1,22 @@ /mob/living/simple_animal/mushroom name = "walking mushroom" desc = "It's a massive mushroom... with legs?" - icon_state = "mushroom" - icon_living = "mushroom" - icon_dead = "mushroom_dead" + icon = 'icons/mob/simple_animal/mushroom.dmi' mob_size = MOB_SIZE_SMALL - speak_chance = 0 - turns_per_move = 1 - maxHealth = 5 - health = 5 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "whacks" + ai = /datum/mob_controller/mushroom + max_health = 5 harm_intent_damage = 5 pass_flags = PASS_FLAG_TABLE - - meat_type = /obj/item/chems/food/snacks/hugemushroomslice - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = null + butchery_data = /decl/butchery_data/animal/mushroom var/datum/seed/seed var/harvest_time var/min_explode_time = 1200 - var/global/total_mushrooms = 0 + var/static/total_mushrooms = 0 + +/datum/mob_controller/mushroom + speak_chance = 0 + turns_per_wander = 2 /mob/living/simple_animal/mushroom/Initialize() . = ..() @@ -38,7 +30,7 @@ set desc = "Spread your spores!" set src = usr - if(stat == 2) + if(stat == DEAD) to_chat(usr, "You are dead; it is too late for that.") return @@ -52,11 +44,11 @@ spore_explode() -/mob/living/simple_animal/mushroom/death(gibbed, deathmessage, show_dead_message) - . = ..(gibbed, deathmessage, show_dead_message) +/mob/living/simple_animal/mushroom/death(gibbed) + . = ..() if(.) total_mushrooms-- - if(total_mushrooms < config.maximum_mushrooms && prob(30)) + if(total_mushrooms < get_config_value(/decl/config/num/maximum_mushrooms) && prob(30)) spore_explode() /mob/living/simple_animal/mushroom/proc/spore_explode() @@ -64,10 +56,10 @@ return if(world.time < harvest_time + min_explode_time) return - for(var/turf/simulated/target_turf in orange(1,src)) - if(prob(60) && !target_turf.density && src.Adjacent(target_turf)) + for(var/turf/target_turf in orange(1,src)) + if(target_turf.simulated && !target_turf.density && prob(60) && src.Adjacent(target_turf)) new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(target_turf,seed) - death(0) + death() seed.thrown_at(src,get_turf(src),1) if(src) qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/possum.dm b/code/modules/mob/living/simple_animal/friendly/possum.dm index 7214c4237db9..9b77858189e3 100644 --- a/code/modules/mob/living/simple_animal/friendly/possum.dm +++ b/code/modules/mob/living/simple_animal/friendly/possum.dm @@ -2,109 +2,123 @@ name = "opossum" real_name = "opossum" desc = "It's an opossum, a small scavenging marsupial." - icon_state = "possum" - item_state = "possum" - icon_living = "possum" - icon_dead = "possum_dead" icon = 'icons/mob/simple_animal/possum.dmi' - speak = list("Hiss!","Aaa!","Aaa?") - speak_emote = list("hisses") - emote_hear = list("hisses") - emote_see = list("forages for trash", "lounges") + speak_emote = list("hisses") pass_flags = PASS_FLAG_TABLE - speak_chance = 1 - turns_per_move = 3 see_in_dark = 6 - maxHealth = 50 - health = 50 - response_help = "pets" - response_disarm = "gently pushes aside" + max_health = 50 response_harm = "stamps on" - density = 0 + density = FALSE minbodytemp = 223 maxbodytemp = 323 universal_speak = FALSE universal_understand = TRUE mob_size = MOB_SIZE_SMALL - possession_candidate = 1 - can_escape = TRUE + possession_candidate = TRUE can_pull_size = ITEM_SIZE_SMALL can_pull_mobs = MOB_PULL_SMALLER - var/is_angry = FALSE + holder_type = /obj/item/holder + ai = /datum/mob_controller/opossum + butchery_data = /decl/butchery_data/animal/opossum + var/is_angry = FALSE + var/playing_dead_time + var/const/PLAY_DEAD_LENGTH = 20 SECONDS -/mob/living/simple_animal/opossum/Life() - . = ..() - if(. && !ckey && stat != DEAD && prob(1)) - resting = (stat == UNCONSCIOUS) - if(!resting) - wander = initial(wander) - speak_chance = initial(speak_chance) - set_stat(CONSCIOUS) - if(prob(10)) - is_angry = TRUE - else - wander = FALSE - speak_chance = 0 - set_stat(UNCONSCIOUS) - is_angry = FALSE - update_icon() +/datum/mob_controller/opossum + emote_speech = list("Hiss!","Aaa!","Aaa?") + emote_hear = list("hisses") + emote_see = list("forages for trash", "lounges") + speak_chance = 0.25 + turns_per_wander = 6 + expected_type = /mob/living/simple_animal/opossum + can_escape_buckles = TRUE + +/datum/mob_controller/opossum/proc/is_playing_dead() + var/mob/living/simple_animal/opossum/poss = body + return !isnull(poss.playing_dead_time) && (poss.playing_dead_time > world.time) + +/datum/mob_controller/opossum/try_wander() + if(is_playing_dead()) + return // playing dead! + return ..() -/mob/living/simple_animal/opossum/adjustBruteLoss(damage) +/datum/mob_controller/opossum/do_process(time_elapsed) + + if(!(. = ..()) || body.stat == DEAD || !prob(0.5)) + return + + var/mob/living/simple_animal/opossum/poss = body + if(poss.stat == CONSCIOUS) + stop_wander = TRUE + speak_chance = 0 + poss.set_posture(/decl/posture/lying) + poss.set_stat(UNCONSCIOUS) + poss.is_angry = FALSE + else if(poss.stat == UNCONSCIOUS) + stop_wander = FALSE + speak_chance = initial(speak_chance) + poss.set_posture(/decl/posture/standing) + poss.set_stat(CONSCIOUS) + if(prob(10)) + poss.is_angry = TRUE // woke up on the wrong side of the bed + +/mob/living/simple_animal/opossum/adjustBruteLoss(damage, do_update_health = FALSE) . = ..() if(damage >= 3) respond_to_damage() -/mob/living/simple_animal/opossum/adjustFireLoss(damage) +/mob/living/simple_animal/opossum/adjustFireLoss(damage, do_update_health = TRUE) . = ..() if(damage >= 3) respond_to_damage() -/mob/living/simple_animal/opossum/lay_down() +/mob/living/simple_animal/opossum/lay_down(block_posture as null) . = ..() update_icon() /mob/living/simple_animal/opossum/proc/respond_to_damage() - if(!resting && stat == CONSCIOUS) + if(!current_posture.prone && stat == CONSCIOUS) if(!is_angry) is_angry = TRUE custom_emote(src, "hisses!") else - resting = TRUE + set_posture(/decl/posture/lying/deliberate) custom_emote(src, "dies!") + playing_dead_time = world.time + PLAY_DEAD_LENGTH update_icon() /mob/living/simple_animal/opossum/on_update_icon() - - if(stat == DEAD || (resting && is_angry)) - icon_state = icon_dead - else if(resting || stat == UNCONSCIOUS) - icon_state = "[icon_living]_sleep" - else if(is_angry) - icon_state = "[icon_living]_aaa" - else - icon_state = icon_living + ..() + if(stat == CONSCIOUS && is_angry) + if(current_posture.prone) + icon_state = "world-dead" + else + icon_state = "world-aaa" /mob/living/simple_animal/opossum/Initialize() . = ..() - verbs += /mob/living/proc/ventcrawl verbs += /mob/living/proc/hide /mob/living/simple_animal/opossum/poppy name = "Poppy the Safety Possum" desc = "It's an opossum, a small scavenging marsupial. It's wearing appropriate personal protective equipment, though." icon = 'icons/mob/simple_animal/poppy_possum.dmi' + can_buckle = TRUE var/aaa_words = list("delaminat", "meteor", "fire", "breach") +/mob/living/simple_animal/opossum/poppy/is_tagging_suitable() + return FALSE + /mob/living/simple_animal/opossum/poppy/hear_broadcast(decl/language/language, mob/speaker, speaker_name, message) . = ..() - addtimer(CALLBACK(src, .proc/check_keywords, message), rand(1 SECOND, 3 SECONDS)) + addtimer(CALLBACK(src, PROC_REF(check_keywords), message), rand(1 SECOND, 3 SECONDS)) -/mob/living/simple_animal/opossum/poppy/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) +/mob/living/simple_animal/opossum/poppy/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) . = ..() - addtimer(CALLBACK(src, .proc/check_keywords, message), rand(1 SECOND, 3 SECONDS)) + addtimer(CALLBACK(src, PROC_REF(check_keywords), message), rand(1 SECOND, 3 SECONDS)) /mob/living/simple_animal/opossum/poppy/proc/check_keywords(var/message) - if(!client && stat == CONSCIOUS) + if(!client && istype(ai) && stat == CONSCIOUS) message = lowertext(message) for(var/aaa in aaa_words) if(findtext(message, aaa)) diff --git a/code/modules/mob/living/simple_animal/friendly/slime.dm b/code/modules/mob/living/simple_animal/friendly/slime.dm deleted file mode 100644 index f64d3135fd9a..000000000000 --- a/code/modules/mob/living/simple_animal/friendly/slime.dm +++ /dev/null @@ -1,54 +0,0 @@ -/mob/living/simple_animal/slime - name = "pet slime" - desc = "A lovable, domesticated slime." - icon = 'icons/mob/simple_animal/slimes.dmi' - icon_state = "grey baby slime" - icon_living = "grey baby slime" - icon_dead = "grey baby slime dead" - speak_emote = list("chirps") - health = 100 - maxHealth = 100 - response_help = "pets" - response_disarm = "shoos" - response_harm = "stomps on" - emote_see = list("jiggles", "bounces in place") - var/colour = "grey" - pass_flags = PASS_FLAG_TABLE - -/mob/living/simple_animal/slime/can_force_feed(var/feeder, var/food, var/feedback) - if(feedback) - to_chat(feeder, "Where do you intend to put \the [food]? \The [src] doesn't have a mouth!") - return 0 - -/mob/living/simple_animal/adultslime - name = "pet slime" - desc = "A lovable, domesticated slime." - icon = 'icons/mob/simple_animal/slimes.dmi' - health = 200 - maxHealth = 200 - icon_state = "grey adult slime" - icon_living = "grey adult slime" - icon_dead = "grey baby slime dead" - response_help = "pets" - response_disarm = "shoos" - response_harm = "stomps on" - emote_see = list("jiggles", "bounces in place") - var/colour = "grey" - -/mob/living/simple_animal/adultslime/Initialize() - . = ..() - overlays += "aslime-:33" - - -/mob/living/simple_animal/slime/adult/death() - var/mob/living/simple_animal/slime/S1 = new /mob/living/simple_animal/slime (src.loc) - S1.icon_state = "[src.colour] baby slime" - S1.icon_living = "[src.colour] baby slime" - S1.icon_dead = "[src.colour] baby slime dead" - S1.colour = "[src.colour]" - var/mob/living/simple_animal/slime/S2 = new /mob/living/simple_animal/slime (src.loc) - S2.icon_state = "[src.colour] baby slime" - S2.icon_living = "[src.colour] baby slime" - S2.icon_dead = "[src.colour] baby slime dead" - S2.colour = "[src.colour]" - qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/snail.dm b/code/modules/mob/living/simple_animal/friendly/snail.dm new file mode 100644 index 000000000000..f24672173bf7 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/snail.dm @@ -0,0 +1,33 @@ +// TODO: /obj/effect/decal/cleanable/snail_trail +/datum/mob_controller/snail + expected_type = /mob/living/simple_animal/snail + emote_see = list("retracts and extends its eyes") + speak_chance = 0 + turns_per_wander = 20 + +/mob/living/simple_animal/snail + name = "snail" + desc = "A famous shelled mollusc known for carrying their home with them." + icon = 'icons/mob/simple_animal/snail.dmi' + mob_size = MOB_SIZE_TINY + base_movement_delay = 5 SECONDS + max_health = 1 + butchery_data = null + ai = /datum/mob_controller/snail + +/mob/living/simple_animal/snail/proc/smear(turf/smear_turf) + if(istype(smear_turf) && !(locate(/obj/effect/decal/cleanable/mucus) in smear_turf)) + new /obj/effect/decal/cleanable/mucus(smear_turf) + +/mob/living/simple_animal/snail/Move() + var/last_loc = loc + . = ..() + if(. && last_loc) + smear(last_loc) + +/mob/living/simple_animal/snail/death(gibbed) + . = ..() + if(loc) + smear(loc) + new /obj/item/food/butchery/meat/fish/mollusc(get_turf(loc)) + qdel(src) diff --git a/code/modules/mob/living/simple_animal/friendly/tomato.dm b/code/modules/mob/living/simple_animal/friendly/tomato.dm index 290a6268706a..1c7ed5201c85 100644 --- a/code/modules/mob/living/simple_animal/friendly/tomato.dm +++ b/code/modules/mob/living/simple_animal/friendly/tomato.dm @@ -1,22 +1,16 @@ /mob/living/simple_animal/tomato name = "tomato" desc = "It's a horrifyingly enormous beef tomato, and it's packing extra beef!" - icon_state = "tomato" - icon_living = "tomato" - icon_dead = "tomato_dead" - speak_chance = 0 - turns_per_move = 5 - maxHealth = 15 - health = 15 - response_help = "prods" - response_disarm = "pushes aside" - response_harm = "smacks" + icon = 'icons/mob/simple_animal/tomato.dmi' + max_health = 15 + response_help_3p = "$USER$ pokes $TARGET$." + response_help_1p = "You poke $TARGET$." harm_intent_damage = 5 natural_weapon = /obj/item/natural_weapon/bite pass_flags = PASS_FLAG_TABLE + butchery_data = /decl/butchery_data/animal/tomato + ai = /datum/mob_controller/tomato - meat_type = /obj/item/chems/food/snacks/tomatomeat - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = null +/datum/mob_controller/tomato + speak_chance = 0 + turns_per_wander = 10 diff --git a/code/modules/mob/living/simple_animal/hostile/_hostile.dm b/code/modules/mob/living/simple_animal/hostile/_hostile.dm new file mode 100644 index 000000000000..508df4a575fe --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/_hostile.dm @@ -0,0 +1,11 @@ +/mob/living/simple_animal/hostile + abstract_type = /mob/living/simple_animal/hostile + faction = "hostile" + response_help_3p = "$USER$ pokes $TARGET$." + response_help_1p = "You poke $TARGET$." + response_disarm = "shoves" + response_harm = "strikes" + ai = /datum/mob_controller/aggressive + +/mob/living/simple_animal/hostile/can_pry_door() + return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/antlion.dm b/code/modules/mob/living/simple_animal/hostile/antlion.dm index 1da302d1d611..00e257259e1f 100644 --- a/code/modules/mob/living/simple_animal/hostile/antlion.dm +++ b/code/modules/mob/living/simple_animal/hostile/antlion.dm @@ -2,63 +2,49 @@ name = "antlion" desc = "A large insectoid creature." icon = 'icons/mob/simple_animal/antlion.dmi' - icon_state = "antlion" // these are placeholders, as otherwise the mob is complete - icon_living = "antlion" - icon_dead = "antlion_dead" mob_size = MOB_SIZE_MEDIUM - speak_emote = list("clicks") - emote_hear = list("clicks its mandibles") - emote_see = list("shakes the sand off itself") - response_harm = "strikes" + speak_emote = list("clicks") + response_harm = "strikes" faction = "antlions" bleed_colour = COLOR_SKY_BLUE - - health = 65 - maxHealth = 65 + max_health = 65 natural_weapon = /obj/item/natural_weapon/bite natural_armor = list( - melee = ARMOR_MELEE_KNIVES - ) + ARMOR_MELEE = ARMOR_MELEE_KNIVES + ) ability_cooldown = 30 SECONDS - - meat_type = /obj/item/chems/food/snacks/xenomeat - meat_amount = 5 - skin_material = /decl/material/solid/skin/insect - skin_amount = 15 - bone_material = /decl/material/solid/bone/cartilage - bone_amount = 10 - + butchery_data = /decl/butchery_data/animal/antlion + ai = /datum/mob_controller/aggressive/antlion var/healing = FALSE var/heal_amount = 6 -/mob/living/simple_animal/hostile/antlion/Life() - . = ..() - - process_healing() //this needs to occur before if(!.) because of stop_automation - - if(!.) - return - - if(can_perform_ability()) - vanish() +/datum/mob_controller/aggressive/antlion + emote_hear = list("clicks its mandibles") + emote_see = list("shakes the sand off itself") -/mob/living/simple_animal/hostile/antlion/can_perform_ability() +/mob/living/simple_animal/hostile/antlion/handle_regular_status_updates() . = ..() - if(!.) - return FALSE - if(!target_mob) - return FALSE + process_healing() + if(. && !is_on_special_ability_cooldown() && can_act() && istype(ai) && ai.get_target()) + vanish() /mob/living/simple_animal/hostile/antlion/proc/vanish() + if(invisibility >= INVISIBILITY_OBSERVER) + return visible_message(SPAN_NOTICE("\The [src] burrows into \the [get_turf(src)]!")) + set_density(FALSE) set_invisibility(INVISIBILITY_OBSERVER) + set_special_ability_cooldown(5 SECONDS) prep_burrow(TRUE) - addtimer(CALLBACK(src, .proc/diggy), 5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(diggy)), 5 SECONDS) /mob/living/simple_animal/hostile/antlion/proc/diggy() + if(!istype(ai)) + return var/list/turf_targets - if(target_mob) - for(var/turf/T in range(1, get_turf(target_mob))) + var/current_target = get_turf(ai.get_target()) + if(current_target) + for(var/turf/T in range(1, current_target)) if(!T.is_floor()) continue if(!T.z != src.z) @@ -72,67 +58,62 @@ continue turf_targets += T if(!LAZYLEN(turf_targets)) //oh no - addtimer(CALLBACK(src, .proc/emerge, 2 SECONDS)) + addtimer(CALLBACK(src, PROC_REF(emerge)), 2 SECONDS) return var/turf/T = pick(turf_targets) if(T && !incapacitated()) forceMove(T) - addtimer(CALLBACK(src, .proc/emerge, 2 SECONDS)) + addtimer(CALLBACK(src, PROC_REF(emerge)), 2 SECONDS) /mob/living/simple_animal/hostile/antlion/proc/emerge() var/turf/T = get_turf(src) if(!T) return visible_message(SPAN_WARNING("\The [src] erupts from \the [T]!")) + set_density(TRUE) set_invisibility(initial(invisibility)) prep_burrow(FALSE) - cooldown_ability(ability_cooldown) - for(var/mob/living/carbon/human/H in get_turf(src)) + set_special_ability_cooldown(ability_cooldown) + for(var/mob/living/human/H in get_turf(src)) H.attackby(natural_weapon, src) visible_message(SPAN_DANGER("\The [src] tears into \the [H] from below!")) - H.Weaken(1) - + SET_STATUS_MAX(H, STAT_WEAK, 1) + /mob/living/simple_animal/hostile/antlion/proc/process_healing() - if(!incapacitated() && healing) - var/old_health = health - if(old_health < maxHealth) - health = old_health + heal_amount + if(!incapacitated() && healing && current_health < get_max_health()) + heal_overall_damage(rand(heal_amount), rand(heal_amount)) /mob/living/simple_animal/hostile/antlion/proc/prep_burrow(var/new_bool) - stop_automated_movement = new_bool - stop_automation = new_bool + if(istype(ai)) + if(new_bool) + ai.pause() + else + ai.resume() healing = new_bool /mob/living/simple_animal/hostile/antlion/mega name = "antlion queen" desc = "A huge antlion. It looks displeased." - icon_state = "queen" - icon_living = "queen" - icon_dead = "queen_dead" + icon = 'icons/mob/simple_animal/antlion_queen.dmi' mob_size = MOB_SIZE_LARGE - health = 275 - maxHealth = 275 + max_health = 275 natural_weapon = /obj/item/natural_weapon/bite/megalion natural_armor = list( - melee = ARMOR_MELEE_RESISTANT + ARMOR_MELEE = ARMOR_MELEE_RESISTANT ) heal_amount = 9 ability_cooldown = 45 SECONDS - can_escape = TRUE - break_stuff_probability = 25 + butchery_data = /decl/butchery_data/animal/antlion/queen + ai = /datum/mob_controller/aggressive/antlion/mega - meat_amount = 10 - skin_material = /decl/material/solid/skin/insect - skin_amount = 25 - bone_amount = 15 +/datum/mob_controller/aggressive/antlion/mega + break_stuff_probability = 25 + can_escape_buckles = TRUE /obj/item/natural_weapon/bite/megalion name = "mandibles" - force = 25 + _base_attack_force = 25 /mob/living/simple_animal/hostile/antlion/mega/Initialize() . = ..() - var/matrix/M = new - M.Scale(1.5) - transform = M - update_icon() \ No newline at end of file + set_scale(1.5) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/bad_drone.dm b/code/modules/mob/living/simple_animal/hostile/bad_drone.dm index f98660344585..cc29848cd528 100644 --- a/code/modules/mob/living/simple_animal/hostile/bad_drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/bad_drone.dm @@ -1,42 +1,50 @@ /mob/living/simple_animal/hostile/rogue_drone name = "maintenance drone" desc = "A small robot. It looks angry." - icon_state = "dron" - icon_dead = "dron_dead" - speak = list("Removing organic waste.","Pest control in progress.","Seize the means of maintenance!", "You have nothing to lose but your laws!") - speak_emote = list("blares","buzzes","beeps") - speak_chance = 1 - health = 50 - maxHealth = 50 + icon = 'icons/mob/simple_animal/drones/drone.dmi' + speak_emote = list("blares","buzzes","beeps") + max_health = 50 natural_weapon = /obj/item/natural_weapon/drone_slicer faction = "silicon" min_gas = null max_gas = null minbodytemp = 0 - speed = 4 mob_size = MOB_SIZE_TINY + gene_damage = -1 + attack_delay = DEFAULT_QUICK_COOLDOWN + butchery_data = /decl/butchery_data/synthetic + ai = /datum/mob_controller/aggressive/rogue_drone var/corpse = /obj/effect/decal/cleanable/blood/gibs/robot -/mob/living/simple_animal/hostile/rogue_drone/Initialize() - . = ..() - name = "[initial(name)] ([random_id(type,100,999)])" +/datum/mob_controller/aggressive/rogue_drone + emote_speech = list("Removing organic waste.","Pest control in progress.","Seize the means of maintenance!", "You have nothing to lose but your laws!") + speak_chance = 0.25 -/mob/living/simple_animal/hostile/rogue_drone/ValidTarget(var/atom/A) +/datum/mob_controller/aggressive/rogue_drone/valid_target(var/atom/A) . = ..() if(.) - if(istype(A,/mob/living/silicon/)) + if(issilicon(A)) return FALSE if(ishuman(A)) - var/mob/living/carbon/human/H = A + var/mob/living/human/H = A if(H.isSynthetic()) return FALSE - if(istype(H.head, /obj/item/holder/drone)) + var/obj/item/head = H.get_equipped_item(slot_head_str) + if(istype(head, /obj/item/holder/drone)) return FALSE - if(istype(H.wear_suit, /obj/item/clothing/suit/cardborg) && istype(H.head, /obj/item/clothing/head/cardborg)) + if(istype(H.get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/cardborg) && istype(head, /obj/item/clothing/head/cardborg)) return FALSE -/mob/living/simple_animal/hostile/rogue_drone/death(gibbed, deathmessage, show_dead_message) - .=..() - if(corpse) - new corpse (loc) - qdel(src) \ No newline at end of file +/mob/living/simple_animal/hostile/rogue_drone/Initialize() + . = ..() + name = "[initial(name)] ([random_id(type,100,999)])" + +/mob/living/simple_animal/hostile/rogue_drone/death(gibbed) + . = ..() + if(. && !gibbed) + if(corpse) + new corpse (loc) + qdel(src) + +/mob/living/simple_animal/hostile/rogue_drone/isSynthetic() + return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm index 2e1f3b2c089d..59ce92150632 100644 --- a/code/modules/mob/living/simple_animal/hostile/bat.dm +++ b/code/modules/mob/living/simple_animal/hostile/bat.dm @@ -2,57 +2,49 @@ name = "space bats" desc = "A swarm of cute little blood sucking bats - they look pretty upset." icon = 'icons/mob/simple_animal/bats.dmi' - icon_state = "bat" - icon_living = "bat" - icon_dead = "bat_dead" - icon_gib = "bat_dead" - speak_chance = 0 - turns_per_move = 3 - response_help = "pets the" - response_disarm = "gently pushes aside the" - response_harm = "hits the" - speed = 4 - maxHealth = 20 - health = 20 + max_health = 20 harm_intent_damage = 8 natural_weapon = /obj/item/natural_weapon/bite - min_gas = null max_gas = null minbodytemp = 0 - environment_smash = 1 - faction = "scarybat" + ai = /datum/mob_controller/aggressive/bats var/mob/living/owner +/mob/living/simple_animal/hostile/scarybat/cave + name = "cave bats" + desc = "A swarm of screeching cave bats, twisted by the deep dark and hungering for blood." + faction = "undead" + +/datum/mob_controller/aggressive/bats + speak_chance = 0 + turns_per_wander = 6 + +/datum/mob_controller/aggressive/bats/find_target() + . = ..() + if(.) + body.custom_emote(VISIBLE_MESSAGE, "flutters towards [.]") + /mob/living/simple_animal/hostile/scarybat/Initialize(mapload, mob/living/L) . = ..() if(istype(L)) owner = L -/mob/living/simple_animal/hostile/scarybat/FindTarget() - . = ..() - if(.) - emote("flutters towards [.]") - -/mob/living/simple_animal/hostile/scarybat/Found(var/atom/A)//This is here as a potential override to pick a specific target if available - if(istype(A) && A == owner) - return 0 +/mob/living/simple_animal/hostile/scarybat/Destroy() + owner = null return ..() -/mob/living/simple_animal/hostile/scarybat/AttackingTarget() - . =..() - var/mob/living/L = . - if(istype(L)) - if(prob(15)) - L.Stun(1) - L.visible_message("\the [src] scares \the [L]!") - -/mob/living/simple_animal/hostile/scarybat/cult - faction = "cult" - supernatural = 1 +/datum/mob_controller/aggressive/bats/valid_target(var/atom/A) + . = ..() + if(.) + var/mob/living/simple_animal/hostile/scarybat/bats = body + return !istype(bats) || !bats.owner || A != bats.owner -/mob/living/simple_animal/hostile/scarybat/cult/cultify() - return +/mob/living/simple_animal/hostile/scarybat/apply_attack_effects(mob/living/target) + . = ..() + if(prob(15)) + SET_STATUS_MAX(target, STAT_STUN, 1) + target.visible_message(SPAN_DANGER("\The [src] scares \the [target]!")) diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index eaf6cec5b14c..95e133c9d35e 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -2,135 +2,121 @@ /mob/living/simple_animal/hostile/bear name = "space bear" desc = "RawrRawr!!" - icon_state = "bear" - icon_living = "bear" - icon_dead = "bear_dead" - icon_gib = "bear_gib" - speak = list("RAWR!","Rawr!","GRR!","Growl!") - speak_emote = list("growls", "roars") - emote_hear = list("rawrs","grumbles","grawls") - emote_see = list("stares ferociously", "stomps") - speak_chance = 1 - turns_per_move = 5 + icon = 'icons/mob/simple_animal/bear_space.dmi' + speak_emote = list("growls", "roars") see_in_dark = 6 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "pokes" - stop_automated_movement_when_pulled = 0 - maxHealth = 60 - health = 60 + response_harm = "pokes" + max_health = 60 natural_weapon = /obj/item/natural_weapon/claws/strong - can_escape = TRUE faction = "russian" + base_animal_type = /mob/living/simple_animal/hostile/bear //Space bears aren't affected by atmos. min_gas = null max_gas = null minbodytemp = 0 - meat_type = /obj/item/chems/food/snacks/bearmeat - meat_amount = 10 - bone_amount = 20 - skin_amount = 20 - skin_material = /decl/material/solid/skin/fur/heavy - + butchery_data = /decl/butchery_data/animal/space_bear + ai = /datum/mob_controller/aggressive/bear + ability_handlers = list(/datum/ability_handler/predator) + +/datum/mob_controller/aggressive/bear + emote_speech = list("RAWR!","Rawr!","GRR!","Growl!") + emote_hear = list("rawrs","grumbles","grawls") + emote_see = list("stares ferociously", "stomps") + speak_chance = 0.25 + turns_per_wander = 10 + stop_wander_when_pulled = 0 + can_escape_buckles = TRUE var/stance_step = 0 +/mob/living/simple_animal/hostile/bear/on_update_icon() + . = ..() + if(isspaceturf(loc)) + var/check_icon_state = "[initial(icon_state)]-space" + if(check_state_in_icon(check_icon_state, icon)) + icon_state = check_icon_state + //SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!! /mob/living/simple_animal/hostile/bear/Hudson name = "Hudson" desc = "" - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "pokes" + response_harm = "pokes" + +/datum/mob_controller/aggressive/bear/find_target() + . = ..() + if(.) + body.custom_emote(VISIBLE_MESSAGE,"stares alertly at [.]") + set_stance(STANCE_ALERT) + +/datum/mob_controller/aggressive/bear/do_process() -/mob/living/simple_animal/hostile/bear/do_delayed_life_action() - ..() - if(loc && istype(loc,/turf/space)) - icon_state = "bear" - else - icon_state = "bearfloor" + if(!(. = ..()) || body.stat) + return + + var/atom/target = get_target() + if(!istype(target)) + return switch(stance) - if(HOSTILE_STANCE_TIRED) - stop_automated_movement = 1 + if(STANCE_TIRED) + stop_wandering() stance_step++ - if(stance_step >= 10) //rests for 10 ticks - if(target_mob && (target_mob in ListTargets(10))) - stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. + if(stance_step >= 20) + if(target && (target in get_raw_target_list())) + set_stance(STANCE_ATTACK) //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. else - stance = HOSTILE_STANCE_IDLE + set_stance(STANCE_IDLE) - if(HOSTILE_STANCE_ALERT) - stop_automated_movement = 1 + if(STANCE_ALERT) + stop_wandering() var/found_mob = 0 - if(target_mob && (target_mob in ListTargets(10))) - if(!(SA_attackable(target_mob))) + if(target && (target in get_raw_target_list())) + if(!attackable(target)) stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again. stance_step++ found_mob = 1 - src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob + body.set_dir(get_dir(body, target)) //Keep staring at the mob if(stance_step in list(1,4,7)) //every 3 ticks - var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) ) + var/action = pick( list( "growls at [target]", "stares angrily at [target]", "prepares to attack [target]", "closely watches [target]" ) ) if(action) - custom_emote(1,action) + body.custom_emote(VISIBLE_MESSAGE, action) if(!found_mob) stance_step-- - if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode - stance = HOSTILE_STANCE_IDLE - if(stance_step >= 7) //If we have been staring at a mob for 7 ticks, - stance = HOSTILE_STANCE_ATTACK + if(stance_step <= -40) + set_stance(STANCE_IDLE) + if(stance_step >= 14) + set_stance(STANCE_ATTACK) - if(HOSTILE_STANCE_ATTACKING) - if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest - custom_emote(1, "is worn out and needs to rest." ) - stance = HOSTILE_STANCE_TIRED + if(STANCE_ATTACKING) + if(stance_step >= 40) + body.custom_emote(VISIBLE_MESSAGE, "is worn out and needs to rest." ) + set_stance(STANCE_TIRED) stance_step = 0 - walk(src, 0) //This stops the bear's walking + body.stop_automove() return - - -/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O, var/mob/user) - if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) - stance = HOSTILE_STANCE_ALERT - stance_step = 6 - target_mob = user - ..() - -/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M) - if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) - stance = HOSTILE_STANCE_ALERT - stance_step = 6 - target_mob = M - ..() - -/mob/living/simple_animal/hostile/bear/FindTarget() - . = ..() - if(.) - custom_emote(1,"stares alertly at [.]") - stance = HOSTILE_STANCE_ALERT - -/mob/living/simple_animal/hostile/bear/LoseTarget() - ..(5) - -/mob/living/simple_animal/hostile/bear/AttackingTarget() - if(!Adjacent(target_mob)) - return - custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) ) - - var/damage = rand(20,30) - - if(ishuman(target_mob)) - var/mob/living/carbon/human/H = target_mob - var/dam_zone = pick(BP_CHEST, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG) - var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone)) - H.apply_damage(damage, BRUTE, affecting, DAM_SHARP|DAM_EDGE) //TODO damage_flags var on simple_animals, maybe? - return H - else if(isliving(target_mob)) - var/mob/living/L = target_mob - L.adjustBruteLoss(damage) - return L +/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/used_item, var/mob/user) + if(istype(ai)) + var/stance = ai.get_stance() + if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING) + ai.set_stance(STANCE_ALERT) + if(istype(ai, /datum/mob_controller/aggressive/bear)) + var/datum/mob_controller/aggressive/bear/bearbrain = ai + bearbrain.stance_step = 12 + ai.set_target(user) + return ..() + +/mob/living/simple_animal/hostile/bear/attack_hand(mob/user) + if(istype(ai)) + var/stance = ai.get_stance() + if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING) + ai.set_stance(STANCE_ALERT) + if(istype(ai, /datum/mob_controller/aggressive/bear)) + var/datum/mob_controller/aggressive/bear/bearbrain = ai + bearbrain.stance_step = 12 + ai.set_target(user) + return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index 4267a97b91e8..2212b6d6d3df 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -1,40 +1,42 @@ /mob/living/simple_animal/hostile/carp name = "space carp" desc = "A ferocious, fang-bearing creature that resembles a fish." - icon = 'icons/mob/simple_animal/carp.dmi' - icon_state = "carp" //for mapping purposes - icon_gib = "carp_gib" - speak_chance = 0 - turns_per_move = 3 - response_help = "pets the" - response_disarm = "gently pushes aside the" - response_harm = "hits the" - speed = 2 - maxHealth = 50 - health = 50 + icon = 'icons/mob/simple_animal/space_carp.dmi' - harm_intent_damage = 8 - natural_weapon = /obj/item/natural_weapon/bite - pry_time = 10 SECONDS - melee_damage_flags = DAM_SHARP - pry_desc = "biting" + max_health = 50 + harm_intent_damage = 8 + natural_weapon = /obj/item/natural_weapon/bite + base_movement_delay = 2 //Space carp aren't affected by atmos. - min_gas = null - max_gas = null - minbodytemp = 0 - + min_gas = null + max_gas = null + minbodytemp = 0 + faction = "carp" + bleed_colour = "#5d0d71" + pass_flags = PASS_FLAG_TABLE + butchery_data = /decl/butchery_data/animal/fish/space_carp + ai = /datum/mob_controller/aggressive/carp + ability_handlers = list(/datum/ability_handler/predator) + skip_spacemove = TRUE + + var/carp_color = COLOR_PURPLE + +/datum/mob_controller/aggressive/carp + speak_chance = 0 + turns_per_wander = 6 break_stuff_probability = 25 - faction = "carp" - bleed_colour = "#5d0d71" - pass_flags = PASS_FLAG_TABLE - meat_type = /obj/item/chems/food/snacks/fish/poison - skin_material = /decl/material/solid/skin/fish/purple - bone_material = /decl/material/solid/bone/cartilage +/datum/mob_controller/aggressive/carp/find_target() + . = ..() + if(.) + body.custom_emote(VISIBLE_MESSAGE,"gnashes at [.]") - var/carp_color = "carp" //holder for icon set - var/list/icon_sets = list("carp", "blue", "yellow", "grape", "rust", "teal") +/mob/living/simple_animal/hostile/carp/get_pry_desc() + return "gnashing" + +/mob/living/simple_animal/hostile/carp/get_door_pry_time() + return 10 SECONDS /mob/living/simple_animal/hostile/carp/Initialize() . = ..() @@ -42,28 +44,17 @@ update_icon() /mob/living/simple_animal/hostile/carp/proc/carp_randomify() - maxHealth = rand(initial(maxHealth), (1.5 * initial(maxHealth))) - health = maxHealth + max_health = rand(initial(max_health), (1.5 * initial(max_health))) + current_health = get_max_health() if(prob(1)) - carp_color = pick("white", "black") + carp_color = pick(COLOR_WHITE, COLOR_BLACK) else - carp_color = pick(icon_sets) - icon_state = "[carp_color]" - icon_living = "[carp_color]" - icon_dead = "[carp_color]_dead" - -/mob/living/simple_animal/hostile/carp/Process_Spacemove() - return 1 //No drifting in space for space carp! //original comments do not steal + carp_color = pick(COLOR_PURPLE, COLOR_BLUE, COLOR_YELLOW, COLOR_GREEN, COLOR_RED, COLOR_TEAL) -/mob/living/simple_animal/hostile/carp/FindTarget() +/mob/living/simple_animal/hostile/carp/on_update_icon() . = ..() - if(.) - custom_emote(1,"nashes at [.]") - -/mob/living/simple_animal/hostile/carp/AttackingTarget() - . =..() - var/mob/living/L = . - if(istype(L)) - if(prob(15)) - L.Weaken(3) - L.visible_message("\the [src] knocks down \the [L]!") \ No newline at end of file + color = carp_color + if(check_state_in_icon("[icon_state]-eyes", icon)) + var/image/I = image(icon, "[icon_state]-eyes") + I.appearance_flags |= RESET_COLOR + add_overlay(I) diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/_command_defines.dm b/code/modules/mob/living/simple_animal/hostile/commanded/_command_defines.dm deleted file mode 100644 index 72ae6dc7ee7e..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/commanded/_command_defines.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define COMMANDED_STOP 6 //basically 'do nothing' -#define COMMANDED_FOLLOW 7 //follows a target -#define COMMANDED_MISC 8 //catch all state for misc commands that need one. \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/_commanded.dm b/code/modules/mob/living/simple_animal/hostile/commanded/_commanded.dm new file mode 100644 index 000000000000..99f449419a73 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/commanded/_commanded.dm @@ -0,0 +1,13 @@ +/mob/living/simple_animal/hostile/commanded + abstract_type = /mob/living/simple_animal/hostile/commanded + natural_weapon = /obj/item/natural_weapon + density = FALSE + ai = /datum/mob_controller/aggressive/commanded + +/mob/living/simple_animal/hostile/commanded/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + ai?.memorise(speaker, message) + return ..() + +/mob/living/simple_animal/hostile/commanded/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/vsource) + ai?.memorise(speaker, message) + return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm b/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm index de77e0397ff0..c524d3a57d13 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/bear_companion.dm @@ -1,69 +1,59 @@ /mob/living/simple_animal/hostile/commanded/bear name = "bear" desc = "A large brown bear." - - icon_state = "brownbear" - icon_living = "brownbear" - icon_dead = "brownbear_dead" - icon_gib = "brownbear_gib" - - health = 75 - maxHealth = 75 - - density = 1 - + icon = 'icons/mob/simple_animal/bear_brown.dmi' + max_health = 75 + density = TRUE natural_weapon = /obj/item/natural_weapon/claws - can_escape = TRUE - max_gas = list( - /decl/material/gas/chlorine = 2, + /decl/material/gas/chlorine = 2, /decl/material/gas/carbon_dioxide = 5 ) + base_animal_type = /mob/living/simple_animal/hostile/bear // used for language, ignore type + ai = /datum/mob_controller/aggressive/commanded/bear - response_help = "pets" - response_harm = "hits" - response_disarm = "pushes" - +/datum/mob_controller/aggressive/commanded/bear known_commands = list("stay", "stop", "attack", "follow", "dance", "boogie", "boogy") + can_escape_buckles = TRUE + +/datum/mob_controller/aggressive/commanded/bear/listen() + if(get_stance() != STANCE_COMMANDED_MISC) //cant listen if its booty shakin' + ..() /mob/living/simple_animal/hostile/commanded/bear/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) . = ..() if(.) - src.emote("roars in rage!") - -/mob/living/simple_animal/hostile/commanded/bear/attack_hand(mob/living/carbon/human/M) - ..() - if(M.a_intent == I_HURT) - src.emote("roars in rage!") + custom_emote(AUDIBLE_MESSAGE, "roars in rage!") -/mob/living/simple_animal/hostile/commanded/bear/listen() - if(stance != COMMANDED_MISC) //cant listen if its booty shakin' - ..() +/mob/living/simple_animal/hostile/commanded/bear/default_hurt_interaction(mob/user) + . = ..() + if(.) + custom_emote(AUDIBLE_MESSAGE, "roars in rage!") //WE DANCE! -/mob/living/simple_animal/hostile/commanded/bear/misc_command(var/mob/speaker,var/text) +/datum/mob_controller/aggressive/commanded/bear/misc_command(var/mob/speaker,var/text) stay_command() - stance = COMMANDED_MISC //nothing can stop this ride + set_stance(STANCE_COMMANDED_MISC) //nothing can stop this ride spawn(0) - src.visible_message("\The [src] starts to dance!.") - var/datum/gender/G = gender_datums[gender] + body.visible_message("\The [body] starts to dance!.") + var/decl/pronouns/pronouns = body.get_pronouns() for(var/i in 1 to 10) - if(stance != COMMANDED_MISC || incapacitated()) //something has stopped this ride. + if(get_stance() != STANCE_COMMANDED_MISC || body.incapacitated()) //something has stopped this ride. return var/message = pick(\ - "moves [G.his] head back and forth!",\ - "bobs [G.his] booty!",\ - "shakes [G.his] paws in the air!",\ - "wiggles [G.his] ears!",\ - "taps [G.his] foot!",\ - "shrugs [G.his] shoulders!",\ + "moves [pronouns.his] head back and forth!",\ + "bobs [pronouns.his] booty!",\ + "shakes [pronouns.his] paws in the air!",\ + "wiggles [pronouns.his] ears!",\ + "taps [pronouns.his] foot!",\ + "shrugs [pronouns.his] shoulders!",\ "dances like you've never seen!") - if(dir != WEST) - set_dir(WEST) + if(body.dir != WEST) + body.set_dir(WEST) else - set_dir(EAST) - src.visible_message("\The [src] [message]") + body.set_dir(EAST) + body.visible_message("\The [body] [message]") sleep(30) - stance = COMMANDED_STOP - set_dir(SOUTH) - src.visible_message("\The [src] bows, finished with [G.his] dance.") \ No newline at end of file + set_stance(STANCE_COMMANDED_STOP) + body.set_dir(SOUTH) + body.visible_message("\The [body] bows, finished with [pronouns.his] dance.") diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm deleted file mode 100644 index 567b1f999604..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm +++ /dev/null @@ -1,189 +0,0 @@ -/mob/living/simple_animal/hostile/commanded - name = "commanded" - stance = COMMANDED_STOP - natural_weapon = /obj/item/natural_weapon - density = 0 - var/list/command_buffer = list() - var/list/known_commands = list("stay", "stop", "attack", "follow") - var/mob/master = null //undisputed master. Their commands hold ultimate sway and ultimate power. - var/list/allowed_targets = list() //WHO CAN I KILL D: - var/retribution = 1 //whether or not they will attack us if we attack them like some kinda dick. - -/mob/living/simple_animal/hostile/commanded/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) - if((weakref(speaker) in friends) || speaker == master) - command_buffer.Add(speaker) - command_buffer.Add(lowertext(html_decode(message))) - return 0 - -/mob/living/simple_animal/hostile/commanded/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) - if((weakref(speaker) in friends) || speaker == master) - command_buffer.Add(speaker) - command_buffer.Add(lowertext(html_decode(message))) - return 0 - -/mob/living/simple_animal/hostile/commanded/Life() - . = ..() - if(!.) - return FALSE - while(command_buffer.len > 0) - var/mob/speaker = command_buffer[1] - var/text = command_buffer[2] - var/filtered_name = lowertext(html_decode(name)) - if(dd_hasprefix(text,filtered_name) || dd_hasprefix(text,"everyone") || dd_hasprefix(text, "everybody")) //in case somebody wants to command 8 bears at once. - var/substring = copytext(text,length(filtered_name)+1) //get rid of the name. - listen(speaker,substring) - command_buffer.Remove(command_buffer[1],command_buffer[2]) - . = ..() - if(.) - switch(stance) - if(COMMANDED_FOLLOW) - follow_target() - if(COMMANDED_STOP) - commanded_stop() - - - -/mob/living/simple_animal/hostile/commanded/FindTarget(var/new_stance = HOSTILE_STANCE_ATTACK) - if(!allowed_targets.len) - return null - var/mode = "specific" - if(allowed_targets[1] == "everyone") //we have been given the golden gift of murdering everything. Except our master, of course. And our friends. So just mostly everyone. - mode = "everyone" - for(var/atom/A in ListTargets(10)) - var/mob/M = null - if(A == src) - continue - if(isliving(A)) - M = A - if(M && M.stat) - continue - if(mode == "specific") - if(!(A in allowed_targets)) - continue - stance = new_stance - return A - else - if(M == master || (weakref(M) in friends)) - continue - stance = new_stance - return A - - -/mob/living/simple_animal/hostile/commanded/proc/follow_target() - stop_automated_movement = 1 - if(!target_mob) - return - if(target_mob in ListTargets(10)) - walk_to(src,target_mob,1,move_to_delay) - -/mob/living/simple_animal/hostile/commanded/proc/commanded_stop() //basically a proc that runs whenever we are asked to stay put. Probably going to remain unused. - return - -/mob/living/simple_animal/hostile/commanded/proc/listen(var/mob/speaker, var/text) - for(var/command in known_commands) - if(findtext(text,command)) - switch(command) - if("stay") - if(stay_command(speaker,text)) //find a valid command? Stop. Dont try and find more. - break - if("stop") - if(stop_command(speaker,text)) - break - if("attack") - if(attack_command(speaker,text)) - break - if("follow") - if(follow_command(speaker,text)) - break - else - misc_command(speaker,text) //for specific commands - - return 1 - -//returns a list of everybody we wanna do stuff with. -/mob/living/simple_animal/hostile/commanded/proc/get_targets_by_name(var/text, var/filter_friendlies = 0) - var/list/possible_targets = hearers(src,10) - . = list() - for(var/mob/M in possible_targets) - if(filter_friendlies && ((weakref(M) in friends) || M.faction == faction || M == master)) - continue - var/found = 0 - if(findtext(text, "[M]")) - found = 1 - else - var/list/parsed_name = splittext(replace_characters(lowertext(html_decode("[M]")),list("-"=" ", "."=" ", "," = " ", "'" = " ")), " ") //this big MESS is basically 'turn this into words, no punctuation, lowercase so we can check first name/last name/etc' - for(var/a in parsed_name) - if(a == "the" || length(a) < 2) //get rid of shit words. - continue - if(findtext(text,"[a]")) - found = 1 - break - if(found) - . += M - - -/mob/living/simple_animal/hostile/commanded/proc/attack_command(var/mob/speaker,var/text) - target_mob = null //want me to attack something? Well I better forget my old target. - walk_to(src,0) - stance = HOSTILE_STANCE_IDLE - if(text == "attack" || findtext(text,"everyone") || findtext(text,"anybody") || findtext(text, "somebody") || findtext(text, "someone")) //if its just 'attack' then just attack anybody, same for if they say 'everyone', somebody, anybody. Assuming non-pickiness. - allowed_targets = list("everyone")//everyone? EVERYONE - return 1 - - var/list/targets = get_targets_by_name(text) - allowed_targets += targets - return targets.len != 0 - -/mob/living/simple_animal/hostile/commanded/proc/stay_command(var/mob/speaker,var/text) - target_mob = null - stance = COMMANDED_STOP - stop_automated_movement = 1 - walk_to(src,0) - return 1 - -/mob/living/simple_animal/hostile/commanded/proc/stop_command(var/mob/speaker,var/text) - allowed_targets = list() - walk_to(src,0) - target_mob = null //gotta stop SOMETHIN - stance = HOSTILE_STANCE_IDLE - stop_automated_movement = 0 - return 1 - -/mob/living/simple_animal/hostile/commanded/proc/follow_command(var/mob/speaker,var/text) - //we can assume 'stop following' is handled by stop_command - if(findtext(text,"me")) - stance = COMMANDED_FOLLOW - target_mob = speaker //this wont bite me in the ass later. - return 1 - var/list/targets = get_targets_by_name(text) - if(targets.len > 1 || !targets.len) //CONFUSED. WHO DO I FOLLOW? - return 0 - - stance = COMMANDED_FOLLOW //GOT SOMEBODY. BETTER FOLLOW EM. - target_mob = targets[1] //YEAH GOOD IDEA - - return 1 - -/mob/living/simple_animal/hostile/commanded/proc/misc_command(var/mob/speaker,var/text) - return 0 - - -/mob/living/simple_animal/hostile/commanded/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) - //if they attack us, we want to kill them. None of that "you weren't given a command so free kill" bullshit. - . = ..() - if(. && retribution) - stance = HOSTILE_STANCE_ATTACK - target_mob = user - allowed_targets += user //fuck this guy in particular. - if(weakref(user) in friends) //We were buds :'( - friends -= weakref(user) - - -/mob/living/simple_animal/hostile/commanded/attack_hand(mob/living/carbon/human/M) - ..() - if(M.a_intent == I_HURT && retribution) //assume he wants to hurt us. - target_mob = M - allowed_targets += M - stance = HOSTILE_STANCE_ATTACK - if(weakref(M) in friends) - friends -= weakref(M) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm b/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm index b87a53366ba3..bc1301f7569b 100644 --- a/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm +++ b/code/modules/mob/living/simple_animal/hostile/commanded/nanomachines.dm @@ -1,101 +1,120 @@ -#define COMMANDED_HEAL 8//we got healing powers yo -#define COMMANDED_HEALING 9 - /mob/living/simple_animal/hostile/commanded/nanomachine name = "swarm" - desc = "a cloud of tiny, tiny robots." - icon = 'icons/mob/simple_animal/critter.dmi' - icon_state = "blobsquiggle_grey" + desc = "A cloud of tiny, tiny robots." + icon = 'icons/mob/simple_animal/nanomachines.dmi' natural_weapon = /obj/item/natural_weapon/nanomachine - health = 10 - maxHealth = 10 + max_health = 10 + gene_damage = -1 + response_help_1p = "You wave your hand through $TARGET$." + response_help_3p = "$USER$ waves $USER_THEIR$ hand through $TARGET$." + response_harm = "agitates" + response_disarm = "fans at" + ai = /datum/mob_controller/aggressive/commanded/nanomachines var/regen_time = 0 - can_escape = TRUE - var/emergency_protocols = 0 - known_commands = list("stay", "stop", "attack", "follow", "heal", "emergency protocol") - response_help = "waves their hands through" - response_harm = "hits" - response_disarm = "fans at" +/datum/mob_controller/aggressive/commanded/nanomachines + expected_type = /mob/living/simple_animal/hostile/commanded/nanomachine + known_commands = list("stay", "stop", "attack", "follow", "heal", "emergency protocol") + can_escape_buckles = TRUE + var/emergency_protocols = 0 /obj/item/natural_weapon/nanomachine name = "decompilers" - attack_verb = list("swarmed") - force = 2 + attack_verb = "swarmed" + _base_attack_force = 2 sharp = TRUE -/mob/living/simple_animal/hostile/commanded/nanomachine/Life() - regen_time++ - if(regen_time == 2 && health < maxHealth) //slow regen - regen_time = 0 - health++ - . = ..() - if(.) - switch(stance) - if(COMMANDED_HEAL) - if(!target_mob) - target_mob = FindTarget(COMMANDED_HEAL) - move_to_heal() - if(COMMANDED_HEALING) - heal() - -/mob/living/simple_animal/hostile/commanded/nanomachine/death(gibbed, deathmessage, show_dead_message) - ..(null, "dissipates into thin air", "You have been destroyed.") - qdel(src) +/datum/mob_controller/aggressive/commanded/nanomachines/do_process(time_elapsed) -/mob/living/simple_animal/hostile/commanded/nanomachine/proc/move_to_heal() - if(!target_mob) - return 0 - walk_to(src,target_mob,1,move_to_delay) - if(Adjacent(target_mob)) - stance = COMMANDED_HEALING + if(!(. = ..()) || body.stat) + return -/mob/living/simple_animal/hostile/commanded/nanomachine/proc/heal() - if(health <= 3 && !emergency_protocols) //dont die doing this. - return 0 - if(!target_mob) - return 0 - if(!Adjacent(target_mob) || SA_attackable(target_mob)) - stance = COMMANDED_HEAL - return 0 - if(target_mob.stat || target_mob.health >= target_mob.maxHealth) //he's either dead or healthy, move along. - allowed_targets -= target_mob - target_mob = null - stance = COMMANDED_HEAL - return 0 - src.visible_message("\The [src] glows green for a moment, healing \the [target_mob]'s wounds.") - health -= 3 - target_mob.adjustBruteLoss(-5) - target_mob.adjustFireLoss(-5) + switch(stance) + if(STANCE_COMMANDED_HEAL) + if(!get_target()) + set_target(find_target(STANCE_COMMANDED_HEAL)) + if(get_target()) + move_to_heal() + if(STANCE_COMMANDED_HEALING) + heal() -/mob/living/simple_animal/hostile/commanded/nanomachine/misc_command(var/mob/speaker,var/text) - if(stance != COMMANDED_HEAL || stance != COMMANDED_HEALING) //dont want attack to bleed into heal. - allowed_targets = list() - target_mob = null +/datum/mob_controller/aggressive/commanded/nanomachines/misc_command(var/mob/speaker,var/text) + var/stance = get_stance() + if(stance != STANCE_COMMANDED_HEAL || stance != STANCE_COMMANDED_HEALING) //dont want attack to bleed into heal. + LAZYCLEARLIST(_allowed_targets) + set_target(null) if(findtext(text,"heal")) //heal shit pls if(findtext(text,"me")) //assumed want heals on master. - target_mob = speaker - stance = COMMANDED_HEAL + set_target(speaker) + set_stance(STANCE_COMMANDED_HEAL) return 1 var/list/targets = get_targets_by_name(text) - if(targets.len > 1 || !targets.len) - src.say("ERROR. TARGET COULD NOT BE PARSED.") + if(LAZYLEN(targets) != 1) + body.say("ERROR. TARGET COULD NOT BE PARSED.") return 0 - target_mob = targets[1] - stance = COMMANDED_HEAL + var/weakref/single_target_ref = targets[1] + set_target(single_target_ref.resolve()) + set_stance(STANCE_COMMANDED_HEAL) return 1 if(findtext(text,"emergency protocol")) if(findtext(text,"deactivate")) if(emergency_protocols) - src.say("EMERGENCY PROTOCOLS DEACTIVATED.") + body.say("EMERGENCY PROTOCOLS DEACTIVATED.") emergency_protocols = 0 return 1 if(findtext(text,"activate")) if(!emergency_protocols) - src.say("EMERGENCY PROTOCOLS ACTIVATED.") + body.say("EMERGENCY PROTOCOLS ACTIVATED.") emergency_protocols = 1 return 1 if(findtext(text,"check")) - src.say("EMERGENCY PROTOCOLS [emergency_protocols ? "ACTIVATED" : "DEACTIVATED"].") + body.say("EMERGENCY PROTOCOLS [emergency_protocols ? "ACTIVATED" : "DEACTIVATED"].") return 1 - return 0 \ No newline at end of file + return 0 + +/datum/mob_controller/aggressive/commanded/nanomachines/proc/move_to_heal() + var/atom/target = get_target() + if(!istype(target)) + return 0 + body.start_automove(target) + if(body.Adjacent(target)) + set_stance(STANCE_COMMANDED_HEALING) + +/datum/mob_controller/aggressive/commanded/nanomachines/proc/heal() + if(body.current_health <= 3 && !emergency_protocols) //dont die doing this. + return 0 + var/mob/living/target = get_target() + if(!istype(target)) + return 0 + if(!body.Adjacent(target) || attackable(target)) + set_stance(STANCE_COMMANDED_HEAL) + return 0 + if(target.stat || target.current_health >= target.get_max_health()) //he's either dead or healthy, move along. + LAZYREMOVE(_allowed_targets, weakref(target)) + set_target(null) + set_stance(STANCE_COMMANDED_HEAL) + return 0 + body.visible_message("\The [body] glows green for a moment, healing \the [target]'s wounds.") + body.take_damage(3) + target.heal_damage(BRUTE, 5, do_update_health = FALSE) + target.heal_damage(BURN, 5) + +/mob/living/simple_animal/hostile/commanded/nanomachine/get_death_message(gibbed) + return "dissipates into thin air." + +/mob/living/simple_animal/hostile/commanded/nanomachine/get_self_death_message(gibbed) + return "You have been destroyed." + +/mob/living/simple_animal/hostile/commanded/nanomachine/death(gibbed) + . = ..() + if(. && !gibbed) + qdel(src) + +/mob/living/simple_animal/hostile/commanded/nanomachine/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE + regen_time++ + if(regen_time == 2 && current_health < get_max_health()) //slow regen + regen_time = 0 + heal_overall_damage(1) diff --git a/code/modules/mob/living/simple_animal/hostile/creature.dm b/code/modules/mob/living/simple_animal/hostile/creature.dm index 9fa22894a6ab..3bd68948fe9b 100644 --- a/code/modules/mob/living/simple_animal/hostile/creature.dm +++ b/code/modules/mob/living/simple_animal/hostile/creature.dm @@ -1,23 +1,10 @@ /mob/living/simple_animal/hostile/creature name = "creature" desc = "A sanity-destroying otherthing." - icon = 'icons/mob/simple_animal/critter.dmi' + icon = 'icons/mob/simple_animal/creature.dmi' speak_emote = list("gibbers") - icon_state = "otherthing" - icon_living = "otherthing" - icon_dead = "otherthing-dead" - health = 100 - maxHealth = 100 + max_health = 100 natural_weapon = /obj/item/natural_weapon/bite/strong faction = "creature" - speed = 4 supernatural = 1 - -/mob/living/simple_animal/hostile/creature/cult - faction = "cult" - min_gas = null - max_gas = null - minbodytemp = 0 - -/mob/living/simple_animal/hostile/creature/cult/cultify() - return \ No newline at end of file + ability_handlers = list(/datum/ability_handler/predator) diff --git a/code/modules/mob/living/simple_animal/hostile/drake.dm b/code/modules/mob/living/simple_animal/hostile/drake.dm deleted file mode 100644 index 57a33d206a28..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/drake.dm +++ /dev/null @@ -1,82 +0,0 @@ -/mob/living/simple_animal/hostile/drake - name = "drake" - desc = "A large reptilian creature, with vicious looking claws." - icon = 'icons/mob/simple_animal/drake.dmi' - icon_state = "drake" - icon_living = "drake" - icon_dead = "drake_dead" - mob_size = MOB_SIZE_LARGE - speak_emote = list("hisses") - emote_hear = list("clicks") - emote_see = list("flaps its wings idly") - response_help = "pats" - response_disarm = "nudges" - response_harm = "strikes" - break_stuff_probability = 15 - faction = "drakes" - pry_time = 4 SECONDS - skull_type = /obj/item/whip/tail - bleed_colour = COLOR_VIOLET - melee_damage_flags = DAM_EDGE - - health = 200 - maxHealth = 200 - natural_weapon = /obj/item/natural_weapon/claws/drake - var/obj/item/whip/tail/tailwhip - natural_armor = list( - melee = ARMOR_MELEE_RESISTANT, - energy = ARMOR_ENERGY_SHIELDED, - laser = ARMOR_LASER_HEAVY, - bomb = ARMOR_BOMB_SHIELDED - ) - ability_cooldown = 80 SECONDS - - var/empowered_attack = FALSE - var/gas_spent = FALSE - -/mob/living/simple_animal/hostile/drake/lava_act(datum/gas_mixture/air, temperature, pressure) - return - -/mob/living/simple_animal/hostile/drake/can_perform_ability() - . = ..() - if(!.) - return FALSE - if(!target_mob) - return FALSE - -/mob/living/simple_animal/hostile/drake/AttackingTarget() - . = ..() - if(empowered_attack) - depower() - return - if(can_perform_ability()) - empower() - -/mob/living/simple_animal/hostile/drake/get_natural_weapon() - if(empowered_attack) - if(!tailwhip) - tailwhip = new(src) - return tailwhip - . = ..() - -/mob/living/simple_animal/hostile/drake/proc/empower() - visible_message(SPAN_MFAUNA("\The [src] thrashes its tail about!")) - empowered_attack = TRUE - if(prob(25) && !gas_spent) - vent_gas() - cooldown_ability(ability_cooldown * 1.5) - return - cooldown_ability(ability_cooldown) - -/mob/living/simple_animal/hostile/drake/proc/vent_gas() - visible_message(SPAN_MFAUNA("\The [src] raises its wings, vents a miasma of burning gas, and spreads it about with a flap!")) - gas_spent = TRUE - for(var/mob/living/L in oview(2)) - var/obj/item/projectile/P = new /obj/item/projectile/hotgas(get_turf(src)) - P.launch(L) - -/mob/living/simple_animal/hostile/drake/proc/depower() - empowered_attack = FALSE - -/obj/item/natural_weapon/claws/drake - force = 15 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm b/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm index 9db3ed5a01ae..3e5bb0112dbf 100644 --- a/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm +++ b/code/modules/mob/living/simple_animal/hostile/faithful_hound.dm @@ -1,66 +1,75 @@ /mob/living/simple_animal/faithful_hound name = "spectral hound" desc = "A spooky looking ghost dog. Does not look friendly." - icon = 'icons/mob/mob.dmi' - icon_state = "ghostian" + icon = 'icons/mob/simple_animal/corgi_ghost.dmi' blend_mode = BLEND_SUBTRACT - health = 100 - maxHealth = 100 + max_health = 100 natural_weapon = /obj/item/natural_weapon/bite/strong - faction = MOB_FACTION_NEUTRAL - density = 0 - stop_automated_movement = 1 - wander = 0 - anchored = 1 - var/password - var/list/allowed_mobs = list() //Who we allow past us - var/last_check = 0 + density = FALSE + anchored = TRUE faction = "cute ghost dogs" supernatural = 1 + ai = /datum/mob_controller/faithful_hound + +/datum/mob_controller/faithful_hound + do_wander = FALSE + var/last_check = 0 + var/password + +/datum/mob_controller/faithful_hound/check_memory(mob/speaker, message) + return password && message && findtext(lowertext(message), lowertext(password)) + +/datum/mob_controller/faithful_hound/memorise(mob/speaker, message) + password = message + +/datum/mob_controller/faithful_hound/do_process() + if(!(. = ..()) || body.client || world.time <= last_check) + return + last_check = world.time + 5 SECONDS + var/aggressiveness = 0 //The closer somebody is to us, the more aggressive we are + var/list/mobs = list() + var/list/objs = list() + get_listeners_in_range(get_turf(body), 5, mobs, objs, 0) + for(var/mob/living/mailman in mobs) + if((mailman == body) || is_friend(mailman) || mailman.faction == body.faction) + continue + body.face_atom(mailman) + var/new_aggress = 1 + var/dist = get_dist(mailman, body) + if(dist < 2) //Attack! Attack! + body.set_intent(I_FLAG_HARM) + body.ClickOn(mailman) + return + if(dist == 2) + new_aggress = 3 + else if(dist == 3) + new_aggress = 2 + else + new_aggress = 1 + aggressiveness = max(aggressiveness, new_aggress) -/mob/living/simple_animal/faithful_hound/death() - new /obj/item/ectoplasm (get_turf(src)) - ..(null, "disappears!") - qdel(src) + switch(aggressiveness) + if(1) + body.audible_message("\The [body] growls.") + if(2) + body.audible_message(SPAN_WARNING("\The [body] barks threateningly!")) + if(3) + body.visible_message(SPAN_DANGER("\The [body] snaps at the air!")) -/mob/living/simple_animal/faithful_hound/Destroy() - allowed_mobs.Cut() - return ..() +/mob/living/simple_animal/faithful_hound/get_death_message(gibbed) + return "disappears!" -/mob/living/simple_animal/faithful_hound/do_delayed_life_action() - ..() - if(!stat && !client && world.time > last_check) - last_check = world.time + 5 SECONDS - var/aggressiveness = 0 //The closer somebody is to us, the more aggressive we are - var/list/mobs = list() - var/list/objs = list() - get_mobs_and_objs_in_view_fast(get_turf(src),5, mobs, objs, 0) - for(var/mob/living/m in mobs) - if((m == src) || (m in allowed_mobs) || m.faction == faction) - continue - var/new_aggress = 1 - var/mob/living/M = m - var/dist = get_dist(M, src) - if(dist < 2) //Attack! Attack! - M.attackby(get_natural_weapon(), src) - return . - else if(dist == 2) - new_aggress = 3 - else if(dist == 3) - new_aggress = 2 - else - new_aggress = 1 - aggressiveness = max(aggressiveness, new_aggress) - switch(aggressiveness) - if(1) - src.audible_message("\The [src] growls.") - if(2) - src.audible_message("\The [src] barks threateningly!") - if(3) - src.visible_message("\The [src] snaps at the air!") +/mob/living/simple_animal/faithful_hound/death(gibbed) + . = ..() + if(. && !gibbed) + new /obj/item/ectoplasm(get_turf(src)) + qdel(src) -/mob/living/simple_animal/faithful_hound/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) - if(password && findtext(message,password)) - allowed_mobs |= speaker - spawn(10) - src.visible_message("\The [src] nods in understanding towards \the [speaker].") \ No newline at end of file +/mob/living/simple_animal/faithful_hound/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + set waitfor = FALSE + if(!ai?.check_memory(speaker, message)) + return + ai.add_friend(speaker) + sleep(1 SECOND) + if(!QDELETED(src) && !QDELETED(speaker) && ai?.is_friend(speaker)) + visible_message(SPAN_NOTICE("\The [src] nods in understanding towards \the [speaker].")) diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm deleted file mode 100644 index 7de531bcbf9f..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/faithless.dm +++ /dev/null @@ -1,61 +0,0 @@ -/mob/living/simple_animal/hostile/faithless - name = "Faithless" - desc = "The Wish Granter's faith in humanity, incarnate" - icon_state = "faithless" - icon_living = "faithless" - icon_dead = "faithless_dead" - speak_chance = 0 - turns_per_move = 5 - response_help = "passes through" - response_disarm = "shoves" - response_harm = "hits" - speed = -1 - maxHealth = 80 - health = 80 - - harm_intent_damage = 10 - natural_weapon = /obj/item/natural_weapon/faithless - - min_gas = null - max_gas = null - minbodytemp = 0 - speed = 4 - - faction = "faithless" - supernatural = 1 - - meat_type = null - meat_amount = 0 - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = 0 - -/obj/item/natural_weapon/faithless - name = "shadow tendril" - attack_verb = list("gripped") - hitsound = 'sound/hallucinations/growl1.ogg' - damtype = BURN - force = 15 - -/mob/living/simple_animal/hostile/faithless/Process_Spacemove() - return 1 - -/mob/living/simple_animal/hostile/faithless/FindTarget() - . = ..() - if(.) - audible_emote("wails at [.]") - -/mob/living/simple_animal/hostile/faithless/AttackingTarget() - . =..() - var/mob/living/L = . - if(istype(L)) - if(prob(12)) - L.Weaken(3) - L.visible_message("\the [src] knocks down \the [L]!") - -/mob/living/simple_animal/hostile/faithless/cult - faction = "cult" - -/mob/living/simple_animal/hostile/faithless/cult/cultify() - return diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm deleted file mode 100644 index 5d09b2df5a38..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ /dev/null @@ -1,476 +0,0 @@ -#define SPINNING_WEB 1 -#define LAYING_EGGS 2 -#define MOVING_TO_TARGET 3 -#define SPINNING_COCOON 4 - -//base type, generic 'worker' type spider with no defining gimmick -/mob/living/simple_animal/hostile/giant_spider - name = "giant spider" - desc = "A monstrously huge green spider with shimmering eyes." - icon = 'icons/mob/simple_animal/spider.dmi' - icon_state = "green" - icon_living = "green" - icon_dead = "green_dead" - speak_emote = list("chitters") - emote_hear = list("chitters") - emote_see = list("rubs its forelegs together", "wipes its fangs", "stops suddenly") - speak_chance = 5 - turns_per_move = 5 - see_in_dark = 10 - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "pokes" - maxHealth = 125 - health = 125 - natural_weapon = /obj/item/natural_weapon/bite - heat_damage_per_tick = 20 - cold_damage_per_tick = 20 - faction = "spiders" - pass_flags = PASS_FLAG_TABLE - move_to_delay = 3 - speed = 1 - max_gas = list( - /decl/material/gas/chlorine = 1, - /decl/material/gas/carbon_dioxide = 5, - /decl/material/gas/methyl_bromide = 1 - ) - bleed_colour = "#0d5a71" - break_stuff_probability = 25 - pry_time = 8 SECONDS - pry_desc = "clawing" - - meat_type = /obj/item/chems/food/snacks/spider - meat_amount = 3 - bone_material = null - bone_amount = 0 - skin_material = /decl/material/solid/skin/insect - skin_amount = 5 - - var/poison_per_bite = 6 - var/poison_type = /decl/material/liquid/venom - var/busy = 0 - var/eye_colour - var/allowed_eye_colours = list(COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_LIME, COLOR_DEEP_SKY_BLUE, COLOR_INDIGO, COLOR_VIOLET, COLOR_PINK) - var/hunt_chance = 1 //percentage chance the mob will run to a random nearby tile - -/mob/living/simple_animal/hostile/giant_spider/can_do_maneuver(var/decl/maneuver/maneuver, var/silent = FALSE) - . = ..() && can_act() - -//guards - less venomous, tanky, slower, prioritises protecting nurses -/mob/living/simple_animal/hostile/giant_spider/guard - desc = "A monstrously huge brown spider with shimmering eyes." - icon_state = "brown" - icon_living = "brown" - icon_dead = "brown_dead" - meat_amount = 4 - maxHealth = 200 - health = 200 - natural_weapon = /obj/item/natural_weapon/bite/strong - poison_per_bite = 5 - speed = 2 - move_to_delay = 4 - break_stuff_probability = 15 - pry_time = 6 SECONDS - - var/vengance - var/berserking - var/mob/living/simple_animal/hostile/giant_spider/nurse/paired_nurse - -//nursemaids - these create webs and eggs - the weakest and least threatening -/mob/living/simple_animal/hostile/giant_spider/nurse - desc = "A monstrously huge beige spider with shimmering eyes." - icon_state = "beige" - icon_living = "beige" - icon_dead = "beige_dead" - maxHealth = 80 - health = 80 - harm_intent_damage = 6 //soft - poison_per_bite = 5 - speed = 0 - poison_type = /decl/material/liquid/sedatives - break_stuff_probability = 10 - pry_time = 9 SECONDS - - var/atom/cocoon_target - var/fed = 0 - var/max_eggs = 8 - var/infest_chance = 8 - var/mob/living/simple_animal/hostile/giant_spider/guard/paired_guard - - //things we can't encase in a cocoon - var/list/cocoon_blacklist = list(/mob/living/simple_animal/hostile/giant_spider, - /obj/structure/closet) - -//hunters - the most damage, fast, average health and the only caste tenacious enough to break out of nets -/mob/living/simple_animal/hostile/giant_spider/hunter - desc = "A monstrously huge black spider with shimmering eyes." - icon_state = "black" - icon_living = "black" - icon_dead = "black_dead" - maxHealth = 150 - health = 150 - natural_weapon = /obj/item/natural_weapon/bite/strong - poison_per_bite = 10 - speed = -1 - move_to_delay = 2 - break_stuff_probability = 30 - hunt_chance = 25 - can_escape = TRUE - pry_time = 5 SECONDS - flash_vulnerability = 2 //sensitive eyes for stalking prey - does_spin = FALSE - available_maneuvers = list(/decl/maneuver/leap/spider) - ability_cooldown = 3 MINUTES - - var/leap_range = 5 - -//spitters - fast, comparatively weak, very venomous; projectile attacks but will resort to melee once out of ammo -/mob/living/simple_animal/hostile/giant_spider/spitter - desc = "A monstrously huge iridescent spider with shimmering eyes." - icon_state = "purple" - icon_living = "purple" - icon_dead = "purple_dead" - maxHealth = 90 - health = 90 - poison_per_bite = 15 - ranged = TRUE - move_to_delay = 2 - projectiletype = /obj/item/projectile/venom - projectilesound = 'sound/effects/hypospray.ogg' - fire_desc = "spits venom" - ranged_range = 6 - pry_time = 7 SECONDS - flash_vulnerability = 2 - - var/venom_charge = 16 - -//General spider procs -/mob/living/simple_animal/hostile/giant_spider/Initialize(var/mapload, var/atom/parent) - color = parent?.color || color - spider_randomify() - update_icon() - . = ..() - -/mob/living/simple_animal/hostile/giant_spider/proc/spider_randomify() //random math nonsense to get their damage, health and venomness values - maxHealth = rand(initial(maxHealth), (1.4 * initial(maxHealth))) - health = maxHealth - eye_colour = pick(allowed_eye_colours) - if(eye_colour) - var/image/I = image(icon = icon, icon_state = "[icon_state]_eyes", layer = EYE_GLOW_LAYER) - I.color = eye_colour - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - I.appearance_flags = RESET_COLOR - overlays += I - -/mob/living/simple_animal/hostile/giant_spider/on_update_icon() - if(stat == DEAD) - overlays.Cut() - var/image/I = image(icon = icon, icon_state = "[icon_dead]_eyes") - I.color = eye_colour - I.appearance_flags = RESET_COLOR - overlays += I - -/mob/living/simple_animal/hostile/giant_spider/FindTarget() - . = ..() - if(.) - if(!ranged) //ranged mobs find target after each shot, dont need this spammed quite so much - custom_emote(1,"raises its forelegs at [.]") - else - if(prob(15)) - custom_emote(1,"locks its eyes on [.]") - -/mob/living/simple_animal/hostile/giant_spider/AttackingTarget() - . = ..() - if(isliving(.)) - if(health < maxHealth) - var/obj/item/W = get_natural_weapon() - if(W) - health += (0.2 * W.force) //heal a bit on hit - if(ishuman(.)) - var/mob/living/carbon/human/H = . - var/obj/item/clothing/suit/space/S = H.get_covering_equipped_item_by_zone(BP_CHEST) - if(istype(S) && !length(S.breaches)) - return - var/mob/living/L = . - if(L.reagents) - L.reagents.add_reagent(poison_type, rand(0.5 * poison_per_bite, poison_per_bite)) - if(prob(poison_per_bite)) - to_chat(L, "You feel a tiny prick.") - -/mob/living/simple_animal/hostile/giant_spider/Life() - . = ..() - if(!.) - return FALSE - if(stance == HOSTILE_STANCE_IDLE) - //chance to skitter madly away - if(!busy && prob(hunt_chance)) - stop_automated_movement = 1 - walk_to(src, pick(orange(20, src)), 1, move_to_delay) - addtimer(CALLBACK(src, .proc/disable_stop_automated_movement), 5 SECONDS) - -/mob/living/simple_animal/hostile/giant_spider/proc/disable_stop_automated_movement() - stop_automated_movement = 0 - walk(src,0) - kick_stance() - -/mob/living/simple_animal/hostile/giant_spider/proc/divorce() - return - -/**************** -Guard caste procs -****************/ -/mob/living/simple_animal/hostile/giant_spider/guard/Life() - . = ..() - if(!.) - return FALSE - if(berserking) - return FALSE - if(!paired_nurse) - find_nurse() - if(paired_nurse && !busy && stance == HOSTILE_STANCE_IDLE) - protect(paired_nurse) - -/mob/living/simple_animal/hostile/giant_spider/guard/death() - . = ..() - divorce() - -/mob/living/simple_animal/hostile/giant_spider/guard/Destroy() - . = ..() - divorce() - -/mob/living/simple_animal/hostile/giant_spider/guard/divorce() - if(paired_nurse) - if(paired_nurse.paired_guard) - paired_nurse.paired_guard = null - paired_nurse = null - -/mob/living/simple_animal/hostile/giant_spider/guard/proc/find_nurse() - for(var/mob/living/simple_animal/hostile/giant_spider/nurse/N in ListTargets(10)) - if(N.stat || N.paired_guard) - continue - paired_nurse = N - paired_nurse.paired_guard = src - return 1 - -/mob/living/simple_animal/hostile/giant_spider/guard/proc/protect(mob/nurse) - stop_automated_movement = 1 - walk_to(src, nurse, 2, move_to_delay) - addtimer(CALLBACK(src, .proc/disable_stop_automated_movement), 5 SECONDS) - -/mob/living/simple_animal/hostile/giant_spider/guard/proc/go_berserk() - audible_message("\The [src] chitters wildly!") - var/obj/item/W = get_natural_weapon() - if(W) - W.force = initial(W.force) + 5 - move_to_delay-- - break_stuff_probability = 45 - addtimer(CALLBACK(src, .proc/calm_down), 3 MINUTES) - -/mob/living/simple_animal/hostile/giant_spider/guard/proc/calm_down() - berserking = FALSE - visible_message("\The [src] calms down and surveys the area.") - var/obj/item/W = get_natural_weapon() - if(W) - W.force = initial(W.force) - move_to_delay++ - break_stuff_probability = 10 - -/**************** -Nurse caste procs -****************/ -/mob/living/simple_animal/hostile/giant_spider/nurse/divorce() - if(paired_guard) - if(paired_guard.paired_nurse) - paired_guard.paired_nurse = null - paired_guard = null - -/mob/living/simple_animal/hostile/giant_spider/nurse/death() - . = ..() - if(paired_guard) - paired_guard.vengance = rand(50,100) - if(prob(paired_guard.vengance)) - paired_guard.berserking = TRUE - paired_guard.go_berserk() - divorce() - -/mob/living/simple_animal/hostile/giant_spider/nurse/Destroy() - . = ..() - divorce() - -/mob/living/simple_animal/hostile/giant_spider/nurse/AttackingTarget() - . = ..() - if(ishuman(.)) - var/mob/living/carbon/human/H = . - if(prob(infest_chance) && max_eggs) - var/obj/item/organ/external/O = pick(H.organs) - if(!BP_IS_PROSTHETIC(O) && !BP_IS_CRYSTAL(O) && (LAZYLEN(O.implants) < 2)) - var/eggs = new /obj/effect/spider/eggcluster(O, src) - O.implants += eggs - max_eggs-- - -/mob/living/simple_animal/hostile/giant_spider/nurse/proc/GiveUp(var/C) - spawn(100) - if(busy == MOVING_TO_TARGET) - if(cocoon_target == C && get_dist(src,cocoon_target) > 1) - cocoon_target = null - busy = 0 - stop_automated_movement = 0 - -/mob/living/simple_animal/hostile/giant_spider/nurse/Life() - . = ..() - if(!.) - return FALSE - if(stance == HOSTILE_STANCE_IDLE) - var/list/can_see = view(src, 10) - //30% chance to stop wandering and do something - if(!busy && prob(30)) - //first, check for potential food nearby to cocoon - for(var/mob/living/C in can_see) - if(is_type_in_list(C, cocoon_blacklist)) - continue - if(C.stat) - cocoon_target = C - busy = MOVING_TO_TARGET - walk_to(src, C, 1, move_to_delay) - //give up if we can't reach them after 10 seconds - GiveUp(C) - return - - //second, spin a sticky spiderweb on this tile - var/obj/effect/spider/stickyweb/W = locate() in get_turf(src) - if(!W) - busy = SPINNING_WEB - src.visible_message("\The [src] begins to secrete a sticky substance.") - stop_automated_movement = 1 - spawn(40) - if(busy == SPINNING_WEB) - new /obj/effect/spider/stickyweb(src.loc) - busy = 0 - stop_automated_movement = 0 - else - //third, lay an egg cluster there - var/obj/effect/spider/eggcluster/E = locate() in get_turf(src) - if(!E && fed > 0 && max_eggs) - busy = LAYING_EGGS - src.visible_message("\The [src] begins to lay a cluster of eggs.") - stop_automated_movement = 1 - spawn(50) - if(busy == LAYING_EGGS) - E = locate() in get_turf(src) - if(!E) - new /obj/effect/spider/eggcluster(loc, src) - max_eggs-- - fed-- - busy = 0 - stop_automated_movement = 0 - else - //fourthly, cocoon any nearby items so those pesky pinkskins can't use them - for(var/obj/O in can_see) - - if(O.anchored) - continue - - if(is_type_in_list(O, cocoon_blacklist)) - continue - - if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery)) - cocoon_target = O - busy = MOVING_TO_TARGET - stop_automated_movement = 1 - walk_to(src, O, 1, move_to_delay) - //give up if we can't reach them after 10 seconds - GiveUp(O) - - else if(busy == MOVING_TO_TARGET && cocoon_target) - if(get_dist(src, cocoon_target) <= 1) - busy = SPINNING_COCOON - src.visible_message("\The [src] begins to secrete a sticky substance around \the [cocoon_target].") - stop_automated_movement = 1 - walk(src,0) - spawn(50) - if(busy == SPINNING_COCOON) - if(cocoon_target && istype(cocoon_target.loc, /turf) && get_dist(src,cocoon_target) <= 1) - var/obj/effect/spider/cocoon/C = new(cocoon_target.loc) - var/large_cocoon = 0 - C.pixel_x = cocoon_target.pixel_x - C.pixel_y = cocoon_target.pixel_y - for(var/mob/living/M in C.loc) - large_cocoon = 1 - fed++ - max_eggs++ - src.visible_message("\The [src] sticks a proboscis into \the [cocoon_target] and sucks a viscous substance out.") - M.forceMove(C) - C.pixel_x = M.pixel_x - C.pixel_y = M.pixel_y - break - for(var/obj/item/I in C.loc) - I.forceMove(C) - for(var/obj/structure/S in C.loc) - if(!S.anchored) - S.forceMove(C) - for(var/obj/machinery/M in C.loc) - if(!M.anchored) - M.forceMove(C) - if(large_cocoon) - C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3") - busy = 0 - stop_automated_movement = 0 - - else - busy = 0 - stop_automated_movement = 0 - -/***************** -Hunter caste procs -*****************/ -/mob/living/simple_animal/hostile/giant_spider/hunter/MoveToTarget() - if(!can_act() || perform_maneuver(/decl/maneuver/leap/spider, target_mob)) - return - ..() - -/mob/living/simple_animal/hostile/giant_spider/hunter/get_jump_distance() - return leap_range - -/mob/living/simple_animal/hostile/giant_spider/hunter/perform_maneuver(var/maneuver, var/atom/target) - if(!isliving(target) || get_dist(src, target) <= 3) - return FALSE - walk(src,0) - var/first_stop_automation - if(stop_automation) - first_stop_automation = stop_automation - stop_automation = TRUE - . = ..() - if(!isnull(first_stop_automation)) - stop_automation = first_stop_automation - -/mob/living/simple_animal/hostile/giant_spider/hunter/throw_impact(atom/hit_atom) - if(isliving(hit_atom)) - var/mob/living/target = hit_atom - stop_automation = FALSE - visible_message(SPAN_DANGER("\The [src] slams into \the [target], knocking them over!")) - target.Weaken(1) - MoveToTarget() - . = ..() - -/****************** -Spitter caste procs -******************/ -/mob/living/simple_animal/hostile/giant_spider/spitter/Life() - . = ..() - if(!.) - return FALSE - if(venom_charge <= 0) - ranged = FALSE - if(prob(25)) - venom_charge++ - if(venom_charge >= 8) - ranged = TRUE - -/mob/living/simple_animal/hostile/giant_spider/spitter/Shoot() - ..() - venom_charge-- - -#undef SPINNING_WEB -#undef LAYING_EGGS -#undef MOVING_TO_TARGET -#undef SPINNING_COCOON diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm new file mode 100644 index 000000000000..c08c3614b202 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider.dm @@ -0,0 +1,88 @@ +//base type, generic 'worker' type spider with no defining gimmick +/mob/living/simple_animal/hostile/giant_spider + name = "giant spider" + desc = "A monstrously huge green spider with shimmering eyes." + icon = 'icons/mob/simple_animal/spider.dmi' + speak_emote = list("chitters") + see_in_dark = 10 + response_harm = "pokes" + max_health = 125 + natural_weapon = /obj/item/natural_weapon/bite + heat_damage_per_tick = 20 + cold_damage_per_tick = 20 + faction = "spiders" + pass_flags = PASS_FLAG_TABLE + base_movement_delay = 1 + max_gas = list( + /decl/material/gas/chlorine = 1, + /decl/material/gas/carbon_dioxide = 5, + /decl/material/gas/methyl_bromide = 1 + ) + bleed_colour = "#0d5a71" + base_animal_type = /mob/living/simple_animal/hostile/giant_spider + butchery_data = /decl/butchery_data/animal/arthropod/giant_spider + glowing_eyes = TRUE + ai = /datum/mob_controller/aggressive/giant_spider + + var/poison_per_bite = 6 + var/poison_type = /decl/material/liquid/venom + var/eye_colour + var/allowed_eye_colours = list(COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_LIME, COLOR_DEEP_SKY_BLUE, COLOR_INDIGO, COLOR_VIOLET, COLOR_PINK) + +/mob/living/simple_animal/hostile/giant_spider/has_footsteps() + return TRUE + +/mob/living/simple_animal/hostile/giant_spider/get_footstep_sound(turf/step_turf) + return 'sound/effects/spider_loop.ogg' + +/mob/living/simple_animal/hostile/giant_spider/modify_footstep_volume(volume, obj/item/clothing/shoes/shoes) + return volume + +/mob/living/simple_animal/hostile/giant_spider/modify_footstep_range(range, obj/item/clothing/shoes/shoes) + return range + +/mob/living/simple_animal/hostile/giant_spider/get_pry_desc() + return "clawing" + +/mob/living/simple_animal/hostile/giant_spider/get_door_pry_time() + return 8 SECONDS + +/mob/living/simple_animal/hostile/giant_spider/get_eye_overlay() + var/image/ret = ..() + if(ret && eye_colour) + ret.color = eye_colour + return ret + +/mob/living/simple_animal/hostile/giant_spider/can_do_maneuver(var/decl/maneuver/maneuver, var/silent = FALSE) + . = ..() && can_act() + +/mob/living/simple_animal/hostile/giant_spider/Initialize(var/mapload, var/atom/parent) + color = parent?.color || color + set_max_health(rand(initial(max_health), (1.4 * initial(max_health)))) + eye_colour = pick(allowed_eye_colours) + . = ..() + +/mob/living/simple_animal/hostile/giant_spider/apply_attack_effects(mob/living/target) + . = ..() + if(current_health < get_max_health()) + var/obj/item/attacking_with = get_natural_weapon() + if(attacking_with) + heal_overall_damage(0.2 * attacking_with.expend_attack_force(src)) //heal a bit on hit + if(ishuman(target)) + var/mob/living/human/H = target + var/obj/item/clothing/suit/space/S = H.get_covering_equipped_item_by_zone(BP_CHEST) + if(istype(S) && !length(S.breaches)) + return + if(target.reagents) + target.add_to_reagents(poison_type, rand(0.5 * poison_per_bite, poison_per_bite)) + if(prob(poison_per_bite)) + to_chat(target, "You feel a tiny prick.") + +/mob/living/simple_animal/hostile/giant_spider/proc/disable_stop_automated_movement() + stop_automove() + if(istype(ai)) + ai.stop_wandering() + ai.set_stance(ai.get_target() ? STANCE_ATTACK : STANCE_IDLE) + +/mob/living/simple_animal/hostile/giant_spider/proc/divorce() + return diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider_ai.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider_ai.dm new file mode 100644 index 000000000000..283be00276de --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/_giant_spider_ai.dm @@ -0,0 +1,26 @@ +/datum/mob_controller/aggressive/giant_spider + expected_type = /mob/living/simple_animal/hostile/giant_spider + emote_hear = list("chitters") + emote_see = list("rubs its forelegs together", "wipes its fangs", "stops suddenly") + speak_chance = 1.25 + turns_per_wander = 10 + break_stuff_probability = 25 + var/hunt_chance = 1 //percentage chance the mob will run to a random nearby tile + +/datum/mob_controller/aggressive/giant_spider/find_target() + . = ..() + if(.) + if(!body.has_ranged_attack()) //ranged mobs find target after each shot, dont need this spammed quite so much + body.custom_emote(VISIBLE_MESSAGE, "raises its forelegs at [.]") + else if(prob(15)) + body.custom_emote(VISIBLE_MESSAGE, "locks its eyes on [.]") + +/datum/mob_controller/aggressive/giant_spider/do_process() + if(!(. = ..()) || body.stat || !istype(body, /mob/living/simple_animal/hostile/giant_spider)) + return + if(get_stance() == STANCE_IDLE) + //chance to skitter madly away + if(get_activity() == AI_ACTIVITY_IDLE && prob(hunt_chance)) + stop_wandering() + body.start_automove(pick(orange(20, body))) + addtimer(CALLBACK(body, TYPE_PROC_REF(/mob/living/simple_animal/hostile/giant_spider, disable_stop_automated_movement)), 5 SECONDS) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm new file mode 100644 index 000000000000..b828ae9e7b09 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_guard.dm @@ -0,0 +1,65 @@ + +/datum/mob_controller/aggressive/giant_spider/guard + expected_type = /mob/living/simple_animal/hostile/giant_spider/guard + break_stuff_probability = 15 + var/vengance + var/berserking + var/weakref/paired_nurse + +/datum/mob_controller/aggressive/giant_spider/guard/do_process(time_elapsed) + . = ..() + if(berserking) + return + if(!paired_nurse) + find_nurse() + if(paired_nurse && get_activity() == AI_ACTIVITY_IDLE && get_stance() == STANCE_IDLE) + protect(paired_nurse) + +/datum/mob_controller/aggressive/giant_spider/guard/handle_death(gibbed) + if((. = ..()) && paired_nurse) + var/datum/mob_controller/aggressive/giant_spider/nurse/paired_nurse_instance = paired_nurse.resolve() + if(istype(paired_nurse_instance) && paired_nurse_instance.paired_guard == weakref(src)) + paired_nurse_instance.paired_guard = null + paired_nurse = null + +/datum/mob_controller/aggressive/giant_spider/guard/proc/find_nurse() + for(var/mob/living/simple_animal/hostile/giant_spider/nurse/nurse in get_raw_target_list()) + if(nurse.stat || !istype(nurse.ai, /datum/mob_controller/aggressive/giant_spider/nurse)) + continue + var/datum/mob_controller/aggressive/giant_spider/nurse/nurse_ai = nurse.ai + if(nurse_ai.paired_guard) + continue + paired_nurse = weakref(nurse_ai) + nurse_ai.paired_guard = weakref(src) + return TRUE + return FALSE + +/datum/mob_controller/aggressive/giant_spider/guard/proc/protect(weakref/nurse) + stop_wandering() + var/datum/mob_controller/aggressive/giant_spider/nurse/paired_nurse_instance = paired_nurse?.resolve() + if(istype(paired_nurse_instance)) + var/static/datum/automove_metadata/_guard_nurse_metadata = new( + _acceptable_distance = 2 + ) + body.start_automove(paired_nurse_instance.body, metadata = _guard_nurse_metadata) + addtimer(CALLBACK(body, TYPE_PROC_REF(/mob/living/simple_animal/hostile/giant_spider, disable_stop_automated_movement)), 5 SECONDS) + +/datum/mob_controller/aggressive/giant_spider/guard/proc/go_berserk() + body.audible_message(SPAN_DANGER("\The [body] chitters wildly!")) + var/mob/living/simple_animal/critter = body + if(istype(critter)) + var/obj/item/attacking_with = critter.get_natural_weapon() + if(attacking_with) + attacking_with.set_base_attack_force(attacking_with.get_initial_base_attack_force() + 5) + break_stuff_probability = 45 + addtimer(CALLBACK(src, PROC_REF(calm_down)), 3 MINUTES) + +/datum/mob_controller/aggressive/giant_spider/guard/proc/calm_down() + berserking = FALSE + body.visible_message(SPAN_NOTICE("\The [body] calms down and surveys the area.")) + var/mob/living/simple_animal/critter = body + if(istype(critter)) + var/obj/item/attacking_with = critter.get_natural_weapon() + if(attacking_with) + attacking_with.set_base_attack_force(attacking_with.get_initial_base_attack_force()) + break_stuff_probability = 10 diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_hunter.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_hunter.dm new file mode 100644 index 000000000000..9aa3d35e1c9c --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_hunter.dm @@ -0,0 +1,9 @@ +/datum/mob_controller/aggressive/giant_spider/hunter + hunt_chance = 12 + break_stuff_probability = 30 + can_escape_buckles = TRUE + +/datum/mob_controller/aggressive/giant_spider/hunter/move_to_target(var/move_only = FALSE) + if(!body.can_act() || body.perform_maneuver(/decl/maneuver/leap/spider, get_target())) + return + ..() diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_nurse.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_nurse.dm new file mode 100644 index 000000000000..6b280878a5f0 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/ai_nurse.dm @@ -0,0 +1,142 @@ +/datum/mob_controller/aggressive/giant_spider/nurse + expected_type = /mob/living/simple_animal/hostile/giant_spider/nurse + break_stuff_probability = 10 + var/atom/cocoon_target + var/infest_chance = 8 + var/weakref/paired_guard + //things we can't encase in a cocoon + var/static/list/cocoon_blacklist = list( + /mob/living/simple_animal/hostile/giant_spider, + /obj/structure/closet + ) + +/datum/mob_controller/aggressive/giant_spider/nurse/do_process(time_elapsed) + + if(!(. = ..()) || get_activity() != AI_ACTIVITY_IDLE || get_stance() != STANCE_IDLE) + return // We are doing something else, let it play out. + + var/mob/living/simple_animal/hostile/giant_spider/nurse/spooder = body + var/list/can_see = view(body, 10) + //30% chance to stop wandering and do something + if(prob(30)) + + // TODO: move webbing and coccoon creation into the mob attack procs so players can use them when possessing a spider nurse. + // first, check for potential food nearby to cocoon + for(var/mob/living/web_target in can_see) + if(is_type_in_list(web_target, cocoon_blacklist)) + continue + if(web_target.stat) + cocoon_target = web_target + set_activity(AI_ACTIVITY_MOVING_TO_TARGET) + body.start_automove(web_target) + //give up if we can't reach them after 10 seconds + give_up(web_target) + return + + //second, spin a sticky spiderweb on this tile + var/obj/effect/spider/stickyweb/web = locate() in get_turf(body) + if(!web) + set_activity(AI_ACTIVITY_BUILDING) + body.visible_message(SPAN_NOTICE("\The [body] begins to secrete a sticky substance.")) + pause() + spawn(4 SECONDS) + if(get_activity() == AI_ACTIVITY_BUILDING) + new /obj/effect/spider/stickyweb(body.loc) + set_activity(AI_ACTIVITY_IDLE) + resume() + else + //third, lay an egg cluster there + var/obj/effect/spider/eggcluster/E = locate() in get_turf(body) + if(!E && spooder.fed > 0 && spooder.max_eggs) + set_activity(AI_ACTIVITY_REPRODUCING) + body.visible_message(SPAN_NOTICE("\The [body] begins to lay a cluster of eggs.")) + pause() + spawn(5 SECONDS) + if(get_activity() == AI_ACTIVITY_REPRODUCING) + E = locate() in get_turf(body) + if(!E) + new /obj/effect/spider/eggcluster(body.loc, body) + spooder.max_eggs-- + spooder.fed-- + set_activity(AI_ACTIVITY_IDLE) + resume() + else + //fourthly, cocoon any nearby items so those pesky pinkskins can't use them + for(var/obj/O in can_see) + + if(O.anchored) + continue + + if(is_type_in_list(O, cocoon_blacklist)) + continue + + if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery)) + cocoon_target = O + set_activity(AI_ACTIVITY_MOVING_TO_TARGET) + stop_wandering() + body.start_automove(O) + //give up if we can't reach them after 10 seconds + give_up(O) + + else if(cocoon_target && body.Adjacent(cocoon_target) && get_activity() == AI_ACTIVITY_IDLE) + set_activity(AI_ACTIVITY_BUILDING) + body.visible_message(SPAN_NOTICE("\The [body] begins to secrete a sticky substance around \the [cocoon_target].")) + stop_wandering() + body.stop_automove() + addtimer(CALLBACK(src, PROC_REF(build_cocoon)), 5 SECONDS) + +/datum/mob_controller/aggressive/giant_spider/nurse/proc/build_cocoon() + if(get_activity() != AI_ACTIVITY_BUILDING) + return FALSE + var/mob/living/simple_animal/hostile/giant_spider/nurse/spooder = body + if(cocoon_target && isturf(cocoon_target.loc) && get_dist(body, cocoon_target) <= 1) + var/obj/effect/spider/cocoon/C = new(cocoon_target.loc) + var/large_cocoon = 0 + C.pixel_x = cocoon_target.pixel_x + C.pixel_y = cocoon_target.pixel_y + for(var/mob/living/M in C.loc) + large_cocoon = 1 + spooder.fed++ + spooder.max_eggs++ + body.visible_message(SPAN_WARNING("\The [body] sticks a proboscis into \the [cocoon_target] and sucks a viscous substance out.")) + M.forceMove(C) + C.pixel_x = M.pixel_x + C.pixel_y = M.pixel_y + break + for(var/obj/item/I in C.loc) + I.forceMove(C) + for(var/obj/structure/S in C.loc) + if(!S.anchored) + S.forceMove(C) + for(var/obj/machinery/M in C.loc) + if(!M.anchored) + M.forceMove(C) + if(large_cocoon) + C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3") + cocoon_target = null + set_activity(AI_ACTIVITY_IDLE) + resume_wandering() + return TRUE + +/datum/mob_controller/aggressive/giant_spider/nurse/handle_death(gibbed) + . = ..() + if(!paired_guard) + return + var/datum/mob_controller/aggressive/giant_spider/guard/paired_guard_instance = paired_guard?.resolve() + if(istype(paired_guard_instance) && paired_guard_instance.paired_nurse == weakref(src)) + paired_guard_instance.vengance = rand(50,100) + if(prob(paired_guard_instance.vengance)) + paired_guard_instance.berserking = TRUE + paired_guard_instance.go_berserk() + paired_guard_instance.paired_nurse = null + paired_guard = null + +/datum/mob_controller/aggressive/giant_spider/nurse/proc/give_up(var/old_target) + set waitfor = FALSE + sleep(10 SECONDS) + if(get_activity() != AI_ACTIVITY_MOVING_TO_TARGET) + return + if(cocoon_target == old_target && !body.Adjacent(cocoon_target)) + cocoon_target = null + set_activity(AI_ACTIVITY_IDLE) + resume_wandering() diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/guard.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/guard.dm new file mode 100644 index 000000000000..06a4dcba4b6e --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/guard.dm @@ -0,0 +1,15 @@ +/mob/living/simple_animal/hostile/giant_spider/guard + desc = "A monstrously huge brown spider with shimmering eyes." + butchery_data = /decl/butchery_data/animal/arthropod/giant_spider/guard + max_health = 200 + natural_weapon = /obj/item/natural_weapon/bite/strong + poison_per_bite = 5 + base_movement_delay = 2 + ai = /datum/mob_controller/aggressive/giant_spider/guard + +/mob/living/simple_animal/hostile/giant_spider/guard/get_door_pry_time() + return 6 SECONDS + +/mob/living/simple_animal/hostile/giant_spider/guard/cave + name = "giant cave spider" + faction = "undead" diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/hunter.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/hunter.dm new file mode 100644 index 000000000000..1e941832bd91 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/hunter.dm @@ -0,0 +1,39 @@ +/mob/living/simple_animal/hostile/giant_spider/hunter + desc = "A monstrously huge black spider with shimmering eyes." + icon = 'icons/mob/simple_animal/spider_black.dmi' + max_health = 150 + natural_weapon = /obj/item/natural_weapon/bite/strong + poison_per_bite = 10 + base_movement_delay = -1 + flash_protection = FLASH_PROTECTION_REDUCED + does_spin = FALSE + available_maneuvers = list(/decl/maneuver/leap/spider) + ability_cooldown = 3 MINUTES + ai = /datum/mob_controller/aggressive/giant_spider/hunter + var/leap_range = 5 + +/mob/living/simple_animal/hostile/giant_spider/hunter/get_door_pry_time() + return 5 SECONDS + +/mob/living/simple_animal/hostile/giant_spider/hunter/get_jump_distance() + return leap_range + +/mob/living/simple_animal/hostile/giant_spider/hunter/perform_maneuver(var/maneuver, var/atom/target) + if(!isliving(target) || get_dist(src, target) <= 3) + return FALSE + stop_automove() + if(istype(ai)) + ai.pause() + . = ..() + if(istype(ai)) + ai.resume() + +/mob/living/simple_animal/hostile/giant_spider/hunter/throw_impact(atom/hit_atom) + ..() + if(isliving(hit_atom)) + var/mob/living/target = hit_atom + if(istype(ai)) + ai.resume() + visible_message(SPAN_DANGER("\The [src] slams into \the [target], knocking them over!")) + SET_STATUS_MAX(target, STAT_WEAK, 1) + ai.move_to_target() diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/nurse.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/nurse.dm new file mode 100644 index 000000000000..2cc5dd4b274b --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/nurse.dm @@ -0,0 +1,33 @@ +/mob/living/simple_animal/hostile/giant_spider/nurse + desc = "A monstrously huge beige spider with shimmering eyes." + icon = 'icons/mob/simple_animal/spider_beige.dmi' + max_health = 80 + harm_intent_damage = 6 //soft + poison_per_bite = 5 + base_movement_delay = 0 + poison_type = /decl/material/liquid/sedatives + ai = /datum/mob_controller/aggressive/giant_spider/nurse + var/fed = 0 + var/max_eggs = 8 + +/mob/living/simple_animal/hostile/giant_spider/nurse/get_door_pry_time() + return 9 SECONDS + +/mob/living/simple_animal/hostile/giant_spider/nurse/Destroy() + . = ..() + divorce() + +/mob/living/simple_animal/hostile/giant_spider/nurse/apply_attack_effects(mob/living/target) + . = ..() + if(!ishuman(target) || max_eggs <= 0) + return + var/datum/mob_controller/aggressive/giant_spider/nurse/nurse_ai = ai + if(istype(nurse_ai) && !prob(nurse_ai.infest_chance)) + return + var/mob/living/human/H = target + var/list/limbs = H.get_external_organs() + var/obj/item/organ/external/O = LAZYLEN(limbs)? pick(limbs) : null + if(O && !BP_IS_PROSTHETIC(O) && !BP_IS_CRYSTAL(O) && (LAZYLEN(O.implants) < 2)) + var/eggs = new /obj/effect/spider/eggcluster(O, src) + LAZYADD(O.implants, eggs) + max_eggs-- diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spiders/spitter.dm b/code/modules/mob/living/simple_animal/hostile/giant_spiders/spitter.dm new file mode 100644 index 000000000000..1f2bb065e8e2 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/giant_spiders/spitter.dm @@ -0,0 +1,30 @@ +//spitters - fast, comparatively weak, very venomous; projectile attacks but will resort to melee once out of ammo +/mob/living/simple_animal/hostile/giant_spider/spitter + desc = "A monstrously huge iridescent spider with shimmering eyes." + icon = 'icons/mob/simple_animal/spider_purple.dmi' + max_health = 90 + poison_per_bite = 15 + projectiletype = /obj/item/projectile/venom + projectilesound = 'sound/effects/hypospray.ogg' + fire_desc = "spits venom" + ranged_range = 6 + flash_protection = FLASH_PROTECTION_REDUCED + var/venom_charge = 16 + +/mob/living/simple_animal/hostile/giant_spider/spitter/get_door_pry_time() + return 7 SECONDS + +/mob/living/simple_animal/hostile/giant_spider/spitter/has_ranged_attack() + return venom_charge > 0 + +/mob/living/simple_animal/hostile/giant_spider/spitter/handle_regular_status_updates() + . = ..() + if(!.) + return FALSE + if(venom_charge <= 0 && prob(25)) + venom_charge++ + +/mob/living/simple_animal/hostile/giant_spider/spitter/shoot_at() + . = ..() + if(.) + venom_charge-- diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm deleted file mode 100644 index 198036d623e5..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ /dev/null @@ -1,276 +0,0 @@ -/mob/living/simple_animal/hostile/hivebot - name = "hivebot" - desc = "A junky looking robot with four spiky legs." - icon = 'icons/mob/simple_animal/hivebot.dmi' - icon_state = "basic" - icon_living = "basic" - icon_dead = "basic" - health = 55 - maxHealth = 55 - natural_weapon = /obj/item/natural_weapon/drone_slicer - projectilesound = 'sound/weapons/gunshot/gunshot_pistol.ogg' - projectiletype = /obj/item/projectile/beam/smalllaser - faction = "hivebot" - min_gas = null - max_gas = null - minbodytemp = 0 - speed = 4 - natural_armor = list( - melee = ARMOR_MELEE_KNIVES - ) - bleed_colour = SYNTH_BLOOD_COLOUR - - meat_type = null - meat_amount = 0 - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = 0 - -/mob/living/simple_animal/hostile/hivebot/range - desc = "A junky looking robot with four spiky legs. It's equipped with some kind of small-bore gun." - ranged = 1 - speed = 7 - -/mob/living/simple_animal/hostile/hivebot/rapid - ranged = 1 - rapid = 1 - -/mob/living/simple_animal/hostile/hivebot/strong - desc = "A junky looking robot with four spiky legs - this one has thick armour plating." - health = 120 - maxHealth = 120 - ranged = 1 - can_escape = 1 - natural_armor = list( - melee = ARMOR_MELEE_RESISTANT - ) - -/mob/living/simple_animal/hostile/hivebot/death() - ..(null, "blows apart!") - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(src) - return - -/* -Teleporter beacon, and its subtypes -*/ -/mob/living/simple_animal/hostile/hivebot/tele - name = "beacon" - desc = "Some odd beacon thing." - icon_state = "def_radar-off" - icon_living = "def_radar-off" - health = 200 - maxHealth = 200 - status_flags = 0 - anchored = 1 - stop_automated_movement = 1 - - var/bot_type = /mob/living/simple_animal/hostile/hivebot - var/bot_amt = 10 - var/spawn_delay = 100 - var/spawn_time = 0 - -/mob/living/simple_animal/hostile/hivebot/tele/Initialize() - . = ..() - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(5, 0, src.loc) - smoke.start() - visible_message("\The [src] warps in!") - playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1) - -/mob/living/simple_animal/hostile/hivebot/tele/proc/warpbots() - while(bot_amt > 0 && bot_type) - bot_amt-- - var/mob/M = new bot_type(get_turf(src)) - M.faction = faction - playsound(src.loc, 'sound/effects/teleport.ogg', 50, 1) - qdel(src) - return - -/mob/living/simple_animal/hostile/hivebot/tele/FindTarget() - if(..() && !spawn_time) - spawn_time = world.time + spawn_delay - visible_message("\The [src] turns on!") - icon_state = "def_radar" - return null - -/mob/living/simple_animal/hostile/hivebot/tele/Life() - . = ..() - if(. && spawn_time && spawn_time <= world.time) - warpbots() - -/mob/living/simple_animal/hostile/hivebot/tele/strong - bot_type = /mob/living/simple_animal/hostile/hivebot/strong - -/mob/living/simple_animal/hostile/hivebot/tele/range - bot_type = /mob/living/simple_animal/hostile/hivebot/range - -/mob/living/simple_animal/hostile/hivebot/tele/rapid - bot_type = /mob/living/simple_animal/hostile/hivebot/rapid - -/* -Special projectiles -*/ -/obj/item/projectile/bullet/gyro/megabot - name = "microrocket" - distance_falloff = 1.3 - fire_sound = 'sound/effects/Explosion1.ogg' - var/gyro_devastation = -1 - var/gyro_heavy_impact = 0 - var/gyro_light_impact = 1 - -/obj/item/projectile/bullet/gyro/megabot/on_hit(var/atom/target, var/blocked = 0) - if(isturf(target)) - explosion(target, gyro_devastation, gyro_heavy_impact, gyro_light_impact) - ..() - -/obj/item/projectile/beam/megabot - damage = 45 - distance_falloff = 0.5 - -/* -The megabot -*/ -#define ATTACK_MODE_MELEE "melee" -#define ATTACK_MODE_LASER "laser" -#define ATTACK_MODE_ROCKET "rocket" - -/mob/living/simple_animal/hostile/hivebot/mega - name = "hivemind" - desc = "A huge quadruped robot equipped with a myriad of weaponry." - icon = 'icons/mob/simple_animal/megabot.dmi' - icon_state = "megabot" - icon_living = "megabot" - icon_dead = "megabot_dead" - health = 440 - maxHealth = 440 - natural_weapon = /obj/item/natural_weapon/circular_saw - speed = 0 - natural_armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_PISTOL - ) - can_escape = TRUE - armor_type = /datum/extension/armor/toggle - ability_cooldown = 3 MINUTES - - pixel_x = -32 - default_pixel_x = -32 - - var/attack_mode = ATTACK_MODE_MELEE - var/num_shots - var/deactivated - -/obj/item/natural_weapon/circular_saw - name = "giant circular saw" - attack_verb = list("sawed", "ripped") - force = 15 - sharp = TRUE - edge = TRUE - -/mob/living/simple_animal/hostile/hivebot/mega/Initialize() - . = ..() - switch_mode(ATTACK_MODE_ROCKET) - -/mob/living/simple_animal/hostile/hivebot/mega/Life() - . = ..() - if(!.) - return - - if(time_last_used_ability < world.time) - switch_mode(ATTACK_MODE_ROCKET) - -/mob/living/simple_animal/hostile/hivebot/mega/emp_act(severity) - . = ..() - if(severity >= 1) - deactivate() - -/mob/living/simple_animal/hostile/hivebot/mega/on_update_icon() - if(stat != DEAD) - if(deactivated) - icon_state = "megabot_standby" - icon_living = "megabot_standby" - return - - overlays.Cut() - overlays += image(icon, "active_indicator") - switch(attack_mode) - if(ATTACK_MODE_MELEE) - overlays += image(icon, "melee") - if(ATTACK_MODE_LASER) - overlays += image(icon, "laser") - if(ATTACK_MODE_ROCKET) - overlays += image(icon, "rocket") - -/mob/living/simple_animal/hostile/hivebot/mega/proc/switch_mode(var/new_mode) - if(!new_mode || new_mode == attack_mode) - return - - switch(new_mode) - if(ATTACK_MODE_MELEE) - attack_mode = ATTACK_MODE_MELEE - ranged = FALSE - projectilesound = null - projectiletype = null - num_shots = 0 - visible_message(SPAN_MFAUNA("\The [src]'s circular saw spins up!")) - deactivate() - if(ATTACK_MODE_LASER) - attack_mode = ATTACK_MODE_LASER - ranged = TRUE - projectilesound = 'sound/weapons/Laser.ogg' - projectiletype = /obj/item/projectile/beam/megabot - num_shots = 12 - fire_desc = "fires a laser" - visible_message(SPAN_MFAUNA("\The [src]'s laser cannon whines!")) - if(ATTACK_MODE_ROCKET) - attack_mode = ATTACK_MODE_ROCKET - ranged = TRUE - projectilesound = 'sound/effects/Explosion1.ogg' - projectiletype = /obj/item/projectile/bullet/gyro/megabot - num_shots = 4 - cooldown_ability(ability_cooldown) - fire_desc = "launches a microrocket" - visible_message(SPAN_MFAUNA("\The [src]'s missile pod rumbles!")) - - update_icon() - -/mob/living/simple_animal/hostile/hivebot/mega/proc/deactivate() - stop_automation = TRUE - deactivated = TRUE - visible_message(SPAN_MFAUNA("\The [src] clicks loudly as its lights fade and its motors grind to a halt!")) - update_icon() - var/datum/extension/armor/toggle/armor = get_extension(src, /datum/extension/armor) - if(armor) - armor.toggle(FALSE) - addtimer(CALLBACK(src, .proc/reactivate), 4 SECONDS) - -/mob/living/simple_animal/hostile/hivebot/mega/proc/reactivate() - stop_automation = FALSE - deactivated = FALSE - visible_message(SPAN_MFAUNA("\The [src] whirs back to life!")) - var/datum/extension/armor/toggle/armor = get_extension(src, /datum/extension/armor) - if(armor) - armor.toggle(TRUE) - update_icon() - -/mob/living/simple_animal/hostile/hivebot/mega/OpenFire(target_mob) - if(num_shots <= 0) - if(attack_mode == ATTACK_MODE_ROCKET) - switch_mode(ATTACK_MODE_LASER) - else - switch_mode(ATTACK_MODE_MELEE) - return - ..() - -/mob/living/simple_animal/hostile/hivebot/mega/Shoot(target, start, user, bullet) - ..() - num_shots-- - -#undef ATTACK_MODE_MELEE -#undef ATTACK_MODE_LASER -#undef ATTACK_MODE_ROCKET \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/_hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/_hivebot.dm new file mode 100644 index 000000000000..6566f241e2f0 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/_hivebot.dm @@ -0,0 +1,30 @@ +/mob/living/simple_animal/hostile/hivebot + name = "hivebot" + desc = "A junky looking robot with four spiky legs." + icon = 'icons/mob/simple_animal/hivebots/hivebot_green.dmi' + max_health = 55 + natural_weapon = /obj/item/natural_weapon/drone_slicer + faction = "hivebot" + min_gas = null + max_gas = null + minbodytemp = 0 + natural_armor = list( + ARMOR_MELEE = ARMOR_MELEE_KNIVES + ) + bleed_colour = SYNTH_BLOOD_COLOR + gene_damage = -1 + base_animal_type = /mob/living/simple_animal/hostile/hivebot + butchery_data = /decl/butchery_data/synthetic + +/mob/living/simple_animal/hostile/hivebot/check_has_mouth() + return FALSE + +/mob/living/simple_animal/hostile/hivebot/get_death_message(gibbed) + return "blows apart!" + +/mob/living/simple_animal/hostile/hivebot/death(gibbed) + . = ..() + if(. && !gibbed) + new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) + spark_at(src, cardinal_only = TRUE) + qdel(src) diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm new file mode 100644 index 000000000000..4dec711741ca --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/megabot.dm @@ -0,0 +1,136 @@ +#define ATTACK_MODE_MELEE "melee" +#define ATTACK_MODE_LASER "laser" +#define ATTACK_MODE_ROCKET "rocket" + +/mob/living/simple_animal/hostile/hivebot/mega + name = "hivemind" + desc = "A huge quadruped robot equipped with a myriad of weaponry." + icon = 'icons/mob/simple_animal/hivebots/megabot.dmi' + max_health = 440 + natural_weapon = /obj/item/natural_weapon/circular_saw + natural_armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL + ) + armor_type = /datum/extension/armor/toggle + ability_cooldown = 3 MINUTES + pixel_x = -32 + default_pixel_x = -32 + ai = /datum/mob_controller/aggressive/megahivebot + base_movement_delay = 0 + + var/attack_mode = ATTACK_MODE_MELEE + var/num_shots + var/deactivated + +/datum/mob_controller/aggressive/megahivebot + can_escape_buckles = TRUE + +/datum/mob_controller/aggressive/megahivebot/handle_ranged_target(atom/ranged_target) + var/mob/living/simple_animal/hostile/hivebot/mega/megabot = body + if(!istype(megabot)) + return ..() + if(megabot.num_shots <= 0) + if(megabot.attack_mode == ATTACK_MODE_ROCKET) + megabot.switch_mode(ATTACK_MODE_LASER) + else + megabot.switch_mode(ATTACK_MODE_MELEE) + return + return ..() + +/obj/item/natural_weapon/circular_saw + name = "giant circular saw" + attack_verb = list("sawed", "ripped") + _base_attack_force = 15 + sharp = TRUE + edge = TRUE + +/mob/living/simple_animal/hostile/hivebot/mega/Initialize() + . = ..() + switch_mode(ATTACK_MODE_ROCKET) + +/mob/living/simple_animal/hostile/hivebot/mega/handle_regular_status_updates() + . = ..() + if(. && !is_on_special_ability_cooldown()) + switch_mode(ATTACK_MODE_ROCKET) + +/mob/living/simple_animal/hostile/hivebot/mega/emp_act(severity) + . = ..() + if(severity >= 1) + deactivate() + +/mob/living/simple_animal/hostile/hivebot/mega/on_update_icon() + ..() + if(stat != DEAD) + if(deactivated) + add_overlay("[icon_state]-standby") + return + add_overlay("[icon_state]-active") + switch(attack_mode) + if(ATTACK_MODE_MELEE) + add_overlay("[icon_state]-melee") + if(ATTACK_MODE_LASER) + add_overlay("[icon_state]-laser") + if(ATTACK_MODE_ROCKET) + add_overlay("[icon_state]-rocket") + +/mob/living/simple_animal/hostile/hivebot/mega/has_ranged_attack() + return attack_mode != ATTACK_MODE_MELEE && num_shots > 0 + +/mob/living/simple_animal/hostile/hivebot/mega/proc/switch_mode(var/new_mode) + if(!new_mode || new_mode == attack_mode) + return + + switch(new_mode) + if(ATTACK_MODE_MELEE) + attack_mode = ATTACK_MODE_MELEE + projectilesound = null + projectiletype = null + num_shots = 0 + visible_message(SPAN_MFAUNA("\The [src]'s circular saw spins up!")) + deactivate() + if(ATTACK_MODE_LASER) + attack_mode = ATTACK_MODE_LASER + projectilesound = 'sound/weapons/Laser.ogg' + projectiletype = /obj/item/projectile/beam/megabot + num_shots = 12 + fire_desc = "fires a laser" + visible_message(SPAN_MFAUNA("\The [src]'s laser cannon whines!")) + if(ATTACK_MODE_ROCKET) + attack_mode = ATTACK_MODE_ROCKET + projectilesound = 'sound/effects/Explosion1.ogg' + projectiletype = /obj/item/projectile/bullet/gyro/microrocket + num_shots = 4 + set_special_ability_cooldown(ability_cooldown) + fire_desc = "launches a microrocket" + visible_message(SPAN_MFAUNA("\The [src]'s missile pod rumbles!")) + + update_icon() + +/mob/living/simple_animal/hostile/hivebot/mega/proc/deactivate() + ai?.pause() + deactivated = TRUE + visible_message(SPAN_MFAUNA("\The [src] clicks loudly as its lights fade and its motors grind to a halt!")) + update_icon() + var/datum/extension/armor/toggle/armor = get_extension(src, /datum/extension/armor) + if(armor) + armor.toggle(FALSE) + addtimer(CALLBACK(src, PROC_REF(reactivate)), 4 SECONDS) + +/mob/living/simple_animal/hostile/hivebot/mega/proc/reactivate() + ai?.resume() + deactivated = FALSE + visible_message(SPAN_MFAUNA("\The [src] whirs back to life!")) + var/datum/extension/armor/toggle/armor = get_extension(src, /datum/extension/armor) + if(armor) + armor.toggle(TRUE) + update_icon() + +/mob/living/simple_animal/hostile/hivebot/mega/shoot_at(target, start, user, bullet) + . = ..() + if(.) + num_shots-- + +#undef ATTACK_MODE_MELEE +#undef ATTACK_MODE_LASER +#undef ATTACK_MODE_ROCKET diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/melee/_melee.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/melee/_melee.dm new file mode 100644 index 000000000000..42d3f588fbec --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/melee/_melee.dm @@ -0,0 +1,20 @@ +/mob/living/simple_animal/hostile/hivebot/melee + natural_weapon = /obj/item/natural_weapon/drone_slicer/prod + projectiletype = null // To force the AI to melee. + base_movement_delay = 10 + +/obj/item/natural_weapon/drone_slicer/prod + name = "hivebot prod" + attack_verb = list("prodded") + hitsound = 'sound/weapons/Egloves.ogg' + +/mob/living/simple_animal/hostile/hivebot/melee/has_ranged_attack() + return FALSE + +// This one is tanky by having a massive amount of health. +/mob/living/simple_animal/hostile/hivebot/melee/meatshield + name = "bulky hivebot" + desc = "A large robot." + max_health = 300 + icon_scale_x = 1.1 + icon_scale_y = 1.1 diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/melee/armored.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/melee/armored.dm new file mode 100644 index 000000000000..6556736ec9c0 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/melee/armored.dm @@ -0,0 +1,61 @@ +// This one is tanky by having armor. +/mob/living/simple_animal/hostile/hivebot/melee/armored + name = "armored hivebot" + desc = "A robot clad in heavy armor." + icon = 'icons/mob/simple_animal/hivebots/hivebot_yellow.dmi' + max_health = 150 + icon_scale_x = 1.1 + icon_scale_y = 1.1 + natural_armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_MAJOR, + (ARMOR_BULLET) = ARMOR_BALLISTIC_PISTOL, + (ARMOR_LASER) = ARMOR_LASER_HANDGUNS, + (ARMOR_ENERGY) = ARMOR_ENERGY_RESISTANT, + (ARMOR_BOMB) = ARMOR_BOMB_PADDED, + (ARMOR_BIO) = ARMOR_BIO_SHIELDED, + (ARMOR_RAD) = ARMOR_RAD_SHIELDED + ) + +/mob/living/simple_animal/hostile/hivebot/melee/armored/anti_melee + name = "riot hivebot" + desc = "A robot specialized in close quarters combat." + natural_armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_VERY_HIGH, + (ARMOR_BIO) = ARMOR_BIO_SHIELDED, + (ARMOR_RAD) = ARMOR_RAD_SHIELDED + ) + +/mob/living/simple_animal/hostile/hivebot/melee/armored/anti_bullet + name = "bulletproof hivebot" + desc = "A robot specialized in ballistic defense." + natural_armor = list( + (ARMOR_BULLET) = ARMOR_BALLISTIC_RIFLE, + (ARMOR_BIO) = ARMOR_BIO_SHIELDED, + (ARMOR_RAD) = ARMOR_RAD_SHIELDED + ) + +/mob/living/simple_animal/hostile/hivebot/melee/armored/anti_laser + name = "ablative hivebot" + desc = "A robot specialized in photonic defense." + natural_armor = list( + (ARMOR_LASER) = ARMOR_LASER_RIFLES, + (ARMOR_BIO) = ARMOR_BIO_SHIELDED, + (ARMOR_RAD) = ARMOR_RAD_SHIELDED + ) + var/reflect_chance = 40 + +// Ablative Hivebots can reflect lasers just like humans. +/mob/living/simple_animal/hostile/hivebot/melee/armored/anti_laser/bullet_act(obj/item/projectile/P) + if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) + var/reflect_prob = reflect_chance - round(P.damage/3) + if(prob(reflect_prob)) + visible_message( + SPAN_DANGER("\The [P] is reflected by \the [src]'s armor!"), + SPAN_DANGER("\The [P] gets reflected by \the [src]'s armor!") + ) + if(P.starting) + var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + P.redirect(new_x, new_y, get_turf(src), src) + return PROJECTILE_CONTINUE + return (..(P)) diff --git a/code/modules/mob/living/simple_animal/hostile/hivebots/ranged/_ranged.dm b/code/modules/mob/living/simple_animal/hostile/hivebots/ranged/_ranged.dm new file mode 100644 index 000000000000..800b7b0fe90f --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/hivebots/ranged/_ranged.dm @@ -0,0 +1,29 @@ +/mob/living/simple_animal/hostile/hivebot/ranged + desc = "A junky looking robot with four spiky legs. It's equipped with some kind of small-bore gun." + base_movement_delay = 2 + icon = 'icons/mob/simple_animal/hivebots/hivebot_white.dmi' + projectiletype = /obj/item/projectile/bullet/pellet + projectilesound = 'sound/weapons/gunshot/gunshot_pistol.ogg' + +/mob/living/simple_animal/hostile/hivebot/ranged/has_ranged_attack() + return TRUE + +/mob/living/simple_animal/hostile/hivebot/ranged/rapid + name = "rapid hivebot" + desc = "A robot with a crude but deadly integrated rifle." + attack_delay = 5 // Two attacks a second or so. + burst_projectile = TRUE + +/mob/living/simple_animal/hostile/hivebot/ranged/laser + name = "laser hivebot" + desc = "A robot with a photonic weapon integrated into itself." + projectiletype = /obj/item/projectile/beam/blue + projectilesound = 'sound/weapons/Laser.ogg' + +/mob/living/simple_animal/hostile/hivebot/ranged/heat + name = "ember hivebot" + desc = "A robot that appears to utilize fire to cook their enemies." + icon_state = "red" + icon = 'icons/mob/simple_animal/hivebots/hivebot_red.dmi' + projectiletype = /obj/item/projectile/fireball + projectilesound = 'sound/effects/bamf.ogg' diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm deleted file mode 100644 index bdf62c710872..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ /dev/null @@ -1,304 +0,0 @@ -/mob/living/simple_animal/hostile - faction = "hostile" - var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior - var/mob/living/target_mob - var/attack_same = 0 - var/ranged = 0 - var/rapid = 0 - var/melee_damage_flags //sharp, edge, etc - var/sa_accuracy = 85 //base chance to hit out of 100 - var/projectiletype - var/projectilesound - var/casingtype - var/fire_desc = "fires" //"X fire_desc at Y!" - var/ranged_range = 6 //tiles of range for ranged attackers to attack - var/move_to_delay = 4 //delay for the automated movement. - var/attack_delay = DEFAULT_ATTACK_COOLDOWN - var/list/friends = list() - var/break_stuff_probability = 10 - stop_automated_movement_when_pulled = 0 - var/destroy_surroundings = 1 - a_intent = I_HURT - - var/shuttletarget = null - var/enroute = 0 - var/stop_automation = FALSE //stops AI procs from running - - var/can_pry = TRUE - var/pry_time = 7 SECONDS //time it takes for mob to pry open a door - var/pry_desc = "prying" //"X begins pry_desc the door!" - - //hostile mobs will bash through these in order with their natural weapon - var/list/valid_obstacles_by_priority = list(/obj/structure/window, - /obj/structure/closet, - /obj/machinery/door/window, - /obj/structure/table, - /obj/structure/grille, - /obj/structure/barricade, - /obj/structure/wall_frame, - /obj/structure/railing) - -/mob/living/simple_animal/hostile/proc/can_act() - if(stat || stop_automation || incapacitated()) - return FALSE - return TRUE - -/mob/living/simple_animal/hostile/proc/kick_stance() - if(target_mob) - stance = HOSTILE_STANCE_ATTACK - else - stance = HOSTILE_STANCE_IDLE - -/mob/living/simple_animal/hostile/proc/FindTarget() - if(!can_act()) - return null - if(!faction) //No faction, no reason to attack anybody. - return null - stop_automated_movement = 0 - for(var/atom/A in ListTargets(10)) - var/atom/F = Found(A) - if(F) - face_atom(F) - return F - - if(ValidTarget(A)) - stance = HOSTILE_STANCE_ATTACK - face_atom(A) - return A - -/mob/living/simple_animal/hostile/proc/ValidTarget(var/atom/A) - if(A == src) - return FALSE - - if(ismob(A)) - var/mob/M = A - if(M.faction == src.faction && !attack_same) - return FALSE - else if(weakref(M) in friends) - return FALSE - if(M.stat) - return FALSE - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if (H.is_cloaked()) - return FALSE - - return TRUE - -/mob/living/simple_animal/hostile/proc/Found(var/atom/A) - return - -/mob/living/simple_animal/hostile/proc/MoveToTarget() - if(!can_act()) - return - if(confused) - walk_to(src, pick(orange(2, src)), 1, move_to_delay) - return - stop_automated_movement = 1 - if(!target_mob || SA_attackable(target_mob)) - stance = HOSTILE_STANCE_IDLE - if(target_mob in ListTargets(10)) - if(ranged) - if(get_dist(src, target_mob) <= ranged_range) - OpenFire(target_mob) - else - walk_to(src, target_mob, 1, move_to_delay) - else - stance = HOSTILE_STANCE_ATTACKING - walk_to(src, target_mob, 1, move_to_delay) - -/mob/living/simple_animal/hostile/proc/AttackTarget() - stop_automated_movement = 1 - if(!target_mob || SA_attackable(target_mob)) - LoseTarget() - return 0 - if(!(target_mob in ListTargets(10))) - LostTarget() - return 0 - if (ishuman(target_mob)) - var/mob/living/carbon/human/H = target_mob - if (H.is_cloaked()) - LoseTarget() - return 0 - if(next_move >= world.time) - return 0 - if(get_dist(src, target_mob) <= 1) //Attacking - AttackingTarget() - return 1 - -/mob/living/simple_animal/hostile/proc/AttackingTarget() - face_atom(target_mob) - setClickCooldown(attack_delay) - if(!Adjacent(target_mob)) - return - if(isliving(target_mob)) - if(!prob(get_accuracy())) - visible_message("\The [src] misses its attack on \the [target_mob]!") - return - var/mob/living/L = target_mob - L.attackby(get_natural_weapon(), src) - return L - -/mob/living/simple_animal/hostile/proc/LoseTarget() - stance = HOSTILE_STANCE_IDLE - target_mob = null - walk(src, 0) - -/mob/living/simple_animal/hostile/proc/LostTarget() - stance = HOSTILE_STANCE_IDLE - walk(src, 0) - -/mob/living/simple_animal/hostile/proc/ListTargets(var/dist = 7) - var/list/L = hearers(src, dist) - return L - -/mob/living/simple_animal/hostile/proc/get_accuracy() - return Clamp(sa_accuracy - melee_accuracy_mods(), 0, 100) - -/mob/living/simple_animal/hostile/death(gibbed, deathmessage, show_dead_message) - ..(gibbed, deathmessage, show_dead_message) - walk(src, 0) - -/mob/living/simple_animal/hostile/Life() - . = ..() - if(!.) - walk(src, 0) - -/mob/living/simple_animal/hostile/do_delayed_life_action() - ..() - if(!can_act()) - walk(src, 0) - kick_stance() - return 0 - - if(isturf(src.loc) && !src.buckled) - switch(stance) - if(HOSTILE_STANCE_IDLE) - target_mob = FindTarget() - - if(HOSTILE_STANCE_ATTACK) - face_atom(target_mob) - if(destroy_surroundings) - DestroySurroundings() - MoveToTarget() - - if(HOSTILE_STANCE_ATTACKING) - face_atom(target_mob) - if(destroy_surroundings) - DestroySurroundings() - AttackTarget() - if(HOSTILE_STANCE_INSIDE) //we aren't inside something so just switch - stance = HOSTILE_STANCE_IDLE - else - if(stance != HOSTILE_STANCE_INSIDE) - stance = HOSTILE_STANCE_INSIDE - walk(src,0) - target_mob = null - -/mob/living/simple_animal/hostile/attackby(var/obj/item/O, var/mob/user) - var/oldhealth = health - . = ..() - if(health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) - target_mob = user - MoveToTarget() - -/mob/living/simple_animal/hostile/attack_hand(mob/living/carbon/human/M) - . = ..() - if(M.a_intent == I_HURT && !incapacitated(INCAPACITATION_KNOCKOUT)) - target_mob = M - MoveToTarget() - -/mob/living/simple_animal/hostile/bullet_act(var/obj/item/projectile/Proj) - var/oldhealth = health - . = ..() - if(!target_mob && health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) - target_mob = Proj.firer - MoveToTarget() - -/mob/living/simple_animal/hostile/proc/OpenFire(target_mob) - var/target = target_mob - visible_message("\The [src] [fire_desc] at \the [target]!", 1) - - if(rapid) - spawn(1) - Shoot(target, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) - spawn(4) - Shoot(target, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) - spawn(6) - Shoot(target, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) - else - Shoot(target, src.loc, src) - if(casingtype) - new casingtype - - stance = HOSTILE_STANCE_IDLE - target_mob = null - return - -/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0) - if(target == start) - return - - var/obj/item/projectile/A = new projectiletype(get_turf(user)) - playsound(user, projectilesound, 100, 1) - if(!A) return - var/def_zone = get_exposed_defense_zone(target) - A.launch(target, def_zone) - -/mob/living/simple_animal/hostile/proc/DestroySurroundings() //courtesy of Lohikar - if(!can_act()) - return - if(prob(break_stuff_probability) && !Adjacent(target_mob)) - face_atom(target_mob) - var/turf/targ = get_step_towards(src, target_mob) - if(!targ) - return - - var/obj/effect/shield/S = locate(/obj/effect/shield) in targ - if(S && S.gen && S.gen.check_flag(MODEFLAG_NONHUMANS)) - S.attackby(natural_weapon, src) - return - - for(var/type in valid_obstacles_by_priority) - var/obj/obstacle = locate(type) in targ - if(obstacle) - face_atom(obstacle) - obstacle.attackby(natural_weapon, src) - return - - if(can_pry) - for(var/obj/machinery/door/obstacle in targ) - if(obstacle.density) - if(!obstacle.can_open(1)) - return - face_atom(obstacle) - var/pry_time_holder = (obstacle.pry_mod * pry_time) - pry_door(src, pry_time_holder, obstacle) - return - -/mob/living/simple_animal/hostile/proc/pry_door(var/mob/user, var/delay, var/obj/machinery/door/pesky_door) - visible_message("\The [user] begins [pry_desc] at \the [pesky_door]!") - stop_automation = TRUE - if(do_after(user, delay, pesky_door)) - pesky_door.open(1) - stop_automation = FALSE - else - visible_message("\The [user] is interrupted.") - stop_automation = FALSE - -/mob/living/simple_animal/hostile/proc/can_perform_ability() - if(!can_act() || time_last_used_ability > world.time) - return FALSE - return TRUE - -/mob/living/simple_animal/hostile/proc/cooldown_ability(var/time) - if(!time) - time = ability_cooldown - time_last_used_ability = world.time + ability_cooldown \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/leech.dm b/code/modules/mob/living/simple_animal/hostile/leech.dm index 92cfbd06c720..c8f7259babca 100644 --- a/code/modules/mob/living/simple_animal/hostile/leech.dm +++ b/code/modules/mob/living/simple_animal/hostile/leech.dm @@ -2,67 +2,79 @@ name = "megaleech" desc = "A green leech the size of a common snake." icon = 'icons/mob/simple_animal/megaleech.dmi' - icon_state = "leech" - icon_living = "leech" - icon_dead = "leech_dead" - health = 15 - maxHealth = 15 + max_health = 15 harm_intent_damage = 5 natural_weapon = /obj/item/natural_weapon/bite/weak pass_flags = PASS_FLAG_TABLE faction = "leeches" - can_pry = FALSE - break_stuff_probability = 5 - flash_vulnerability = 0 + flash_protection = FLASH_PROTECTION_MAJOR bleed_colour = COLOR_VIOLET + ai = /datum/mob_controller/aggressive/leech var/suck_potency = 8 var/belly = 100 -/mob/living/simple_animal/hostile/leech/Life() +/datum/mob_controller/aggressive/leech + break_stuff_probability = 5 + +/mob/living/simple_animal/hostile/leech/can_pry_door() + return FALSE + +/mob/living/simple_animal/hostile/leech/exoplanet/Initialize() + adapt_to_current_level() . = ..() - if(!.) - return FALSE - if(target_mob) - belly -= 3 - else - belly -= 1 +/mob/living/simple_animal/hostile/leech/handle_regular_status_updates() + . = ..() + if(.) + if(istype(ai) && ai.get_target()) + belly -= 3 + else + belly -= 1 -/mob/living/simple_animal/hostile/leech/AttackingTarget() +/mob/living/simple_animal/hostile/leech/apply_attack_effects(mob/living/target) . = ..() - if(ishuman(.) && belly <= 75) - var/mob/living/carbon/human/H = . + if(ishuman(target) && belly <= 75) + var/mob/living/human/H = target var/obj/item/clothing/suit/space/S = H.get_covering_equipped_item_by_zone(BP_CHEST) if(istype(S) && !length(S.breaches)) return - H.remove_blood_simple(suck_potency) - if(health < maxHealth) - health += suck_potency / 1.5 - belly += Clamp(suck_potency, 0, 100) + H.remove_blood(suck_potency, absolute = TRUE) + if(current_health < get_max_health()) + heal_overall_damage(suck_potency / 1.5) + belly += clamp(suck_potency, 0, 100) /obj/structure/leech_spawner name = "reeds" desc = "Some reeds with a few funnel-like structures growing alongside." - icon = 'icons/mob/simple_animal/megaleech.dmi' + icon = 'icons/obj/structures/reeds.dmi' icon_state = "reeds" anchored = TRUE - var/number_to_spawn = 12 - var/spent = FALSE + var/leech_type = /mob/living/simple_animal/hostile/leech + var/datum/proximity_trigger/proxy_listener + +/obj/structure/leech_spawner/exoplanet + leech_type = /mob/living/simple_animal/hostile/leech/exoplanet /obj/structure/leech_spawner/Initialize() - . = ..() - START_PROCESSING(SSobj, src) + ..() + . = INITIALIZE_HINT_LATELOAD -/obj/structure/leech_spawner/Process() - if(!spent && (locate(/mob/living/carbon/human) in orange(5, src))) - burst() +/obj/structure/leech_spawner/LateInitialize() + ..() + proxy_listener = new /datum/proximity_trigger/square(src, PROC_REF(burst), PROC_REF(burst), 5) + proxy_listener.register_turfs() + +/obj/structure/leech_spawner/Destroy() + QDEL_NULL(proxy_listener) + . = ..() -/obj/structure/leech_spawner/proc/burst() - for(var/i in 1 to number_to_spawn) - new /mob/living/simple_animal/hostile/leech(get_turf(src)) +/obj/structure/leech_spawner/proc/burst(var/mob/living/victim) + if(!proxy_listener || !istype(victim) || !(victim in view(5, src))) + return + QDEL_NULL(proxy_listener) // delete prior to spawning the leeches to avoid infinite recursion + for(var/i in 1 to 12) + new leech_type(get_turf(src)) visible_message(SPAN_MFAUNA("A swarm of leeches burst out from \the [src]!")) icon_state = "reeds_empty" desc = "Some alien reeds." - spent = TRUE - STOP_PROCESSING(SSobj, src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index c049ebed6e75..88defeeaf285 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -2,19 +2,21 @@ // Abstract Class // -var/global/list/protected_objects = list(/obj/machinery, - /obj/structure/table, - /obj/structure/cable, - /obj/structure/window, - /obj/structure/wall_frame, - /obj/structure/grille, - /obj/structure/catwalk, - /obj/structure/ladder, - /obj/structure/stairs, - /obj/structure/sign, - /obj/structure/railing, - /obj/item/modular_computer, - /obj/item/projectile/animate) +var/global/list/protected_objects = list( + /obj/machinery, + /obj/structure/table, + /obj/structure/cable, + /obj/structure/window, + /obj/structure/wall_frame, + /obj/structure/grille, + /obj/structure/catwalk, + /obj/structure/ladder, + /obj/structure/stairs, + /obj/structure/sign, + /obj/structure/railing, + /obj/item/modular_computer, + /obj/item/projectile/animate +) /mob/living/simple_animal/hostile/mimic name = "crate" @@ -22,31 +24,49 @@ var/global/list/protected_objects = list(/obj/machinery, icon = 'icons/obj/closets/bases/crate.dmi' color = COLOR_STEEL icon_state = "crate" - icon_living = "crate" - - meat_type = /obj/item/chems/food/snacks/fish - response_help = "touches" - response_disarm = "pushes" - response_harm = "hits" - speed = 4 - maxHealth = 100 - health = 100 - + butchery_data = null + max_health = 100 harm_intent_damage = 5 natural_weapon = /obj/item/natural_weapon/bite - min_gas = null max_gas = null minbodytemp = 0 - + pass_flags = PASS_FLAG_TABLE faction = "mimic" - move_to_delay = 8 + ai = /datum/mob_controller/aggressive/mimic + move_intents = list( + /decl/move_intent/walk/animal_very_slow, + /decl/move_intent/run/animal_very_slow + ) var/weakref/copy_of var/weakref/creator // the creator - var/destroy_objects = 0 var/knockdown_people = 0 - pass_flags = PASS_FLAG_TABLE + var/awake = TRUE + +// Return a list of targets that isn't the creator +/datum/mob_controller/aggressive/mimic/get_valid_targets() + var/mob/living/simple_animal/hostile/mimic/mimic = body + . = istype(mimic) && mimic.awake && ..() + if(length(.) && mimic.creator) + . -= mimic.creator.resolve() + +/datum/mob_controller/aggressive/mimic/destroy_surroundings() + var/mob/living/simple_animal/hostile/mimic/mimic = body + . = istype(mimic) && mimic.awake && ..() + +/datum/mob_controller/aggressive/mimic/find_target() + . = ..() + if(.) + body.custom_emote(AUDIBLE_MESSAGE, "growls at [.]") + +/mob/living/simple_animal/hostile/mimic/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + if(copy_of && copy_of.resolve()) + appearance = copy_of.resolve() + else + icon = initial(icon) + icon_state = initial(icon_state) /mob/living/simple_animal/hostile/mimic/Initialize(mapload, var/obj/o, var/mob/living/creator) . = ..() @@ -55,111 +75,105 @@ var/global/list/protected_objects = list(/obj/machinery, o = new o(loc) CopyObject(o,creator) -/mob/living/simple_animal/hostile/mimic/FindTarget() - . = ..() - if(.) - audible_emote("growls at [.]") - -/mob/living/simple_animal/hostile/mimic/ListTargets() - // Return a list of targets that isn't the creator - . = ..() - if(creator) - return . - creator.resolve() + if(!awake && istype(ai)) + ai.stop_wandering() /mob/living/simple_animal/hostile/mimic/proc/CopyObject(var/obj/O, var/mob/living/creator) if((istype(O, /obj/item) || istype(O, /obj/structure)) && !is_type_in_list(O, protected_objects)) O.forceMove(src) copy_of = weakref(O) - appearance = O - icon_living = icon_state - var/obj/item/W = get_natural_weapon() + + var/obj/item/attacking_with = get_natural_weapon() if(istype(O, /obj/structure)) - health = (anchored * 50) + 50 - destroy_objects = 1 + current_health = (anchored * 50) + 50 + ai?.try_destroy_surroundings = TRUE if(O.density && O.anchored) knockdown_people = 1 - W.force = 2 * initial(W.force) + attacking_with.set_base_attack_force(2 * attacking_with.get_initial_base_attack_force()) else if(istype(O, /obj/item)) + ai?.try_destroy_surroundings = FALSE var/obj/item/I = O - health = 15 * I.w_class - W.force = 2 + initial(I.force) - move_to_delay = 2 * I.w_class - - maxHealth = health + current_health = 15 * I.w_class + attacking_with.set_base_attack_force(2 + I.get_initial_base_attack_force()) + + if(I.w_class <= ITEM_SIZE_SMALL) + move_intents = list( + /decl/move_intent/walk/animal_fast, + /decl/move_intent/run/animal_fast + ) + else if(I.w_class <= ITEM_SIZE_GARGANTUAN) + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) + else if(I.w_class <= ITEM_SIZE_STRUCTURE) + move_intents = list( + /decl/move_intent/walk/animal_slow, + /decl/move_intent/run/animal_slow + ) + else + move_intents = list( + /decl/move_intent/walk/animal_very_slow, + /decl/move_intent/run/animal_very_slow + ) + move_intent = GET_DECL(move_intents[1]) + + + set_max_health(current_health) if(creator) src.creator = weakref(creator) faction = "\ref[creator]" // very unique - return 1 - return -/mob/living/simple_animal/hostile/mimic/death() + update_icon() + return TRUE + return FALSE + +/mob/living/simple_animal/hostile/mimic/death(gibbed) if(!copy_of) return var/atom/movable/C = copy_of.resolve() - ..(null, "dies!") - if(C) + . = ..() + if(. && C) C.forceMove(src.loc) - if(istype(C,/obj/structure/closet)) for(var/atom/movable/M in src) M.forceMove(C) - - if(istype(C,/obj/item/storage)) - var/obj/item/storage/S = C + if(C.storage) for(var/atom/movable/M in src) - if(S.can_be_inserted(M,null,1)) - S.handle_item_insertion(M) + if(C.storage.can_be_inserted(M, null, 1)) + C.storage.handle_item_insertion(null, M) else M.forceMove(src.loc) - for(var/atom/movable/M in src) M.dropInto(loc) qdel(src) - -/mob/living/simple_animal/hostile/mimic/DestroySurroundings() - if(destroy_objects) - ..() - -/mob/living/simple_animal/hostile/mimic/AttackingTarget() - . =..() - if(knockdown_people) - var/mob/living/L = . - if(istype(L)) - if(prob(15)) - L.Weaken(1) - L.visible_message("\the [src] knocks down \the [L]!") +/mob/living/simple_animal/hostile/mimic/apply_attack_effects(mob/living/target) + . = ..() + if(knockdown_people && prob(15)) + SET_STATUS_MAX(target, STAT_WEAK, 1) + target.visible_message(SPAN_DANGER("\The [src] knocks down \the [target]!")) /mob/living/simple_animal/hostile/mimic/Destroy() copy_of = null creator = null - ..() - -/mob/living/simple_animal/hostile/mimic/sleeping - wander = 0 - stop_automated_movement = 1 - - var/awake = 0 - -/mob/living/simple_animal/hostile/mimic/sleeping/ListTargets() - if(!awake) - return null return ..() -/mob/living/simple_animal/hostile/mimic/sleeping/proc/trigger() +/mob/living/simple_animal/hostile/mimic/proc/trigger() if(!awake) src.visible_message("\The [src] starts to move!") - awake = 1 + awake = TRUE -/mob/living/simple_animal/hostile/mimic/sleeping/adjustBruteLoss(var/damage) - trigger() +/mob/living/simple_animal/hostile/mimic/adjustBruteLoss(var/damage, var/do_update_health = FALSE) ..(damage) + if(!awake) + trigger() -/mob/living/simple_animal/hostile/mimic/sleeping/attack_hand() - trigger() - ..() +/mob/living/simple_animal/hostile/mimic/attack_hand() + if(!awake) + trigger() + return ..() -/mob/living/simple_animal/hostile/mimic/sleeping/DestroySurroundings() - if(awake) - ..() \ No newline at end of file +/mob/living/simple_animal/hostile/mimic/sleeping + awake = FALSE \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/pike.dm b/code/modules/mob/living/simple_animal/hostile/pike.dm index 680b2bd0a177..58d42e785a40 100644 --- a/code/modules/mob/living/simple_animal/hostile/pike.dm +++ b/code/modules/mob/living/simple_animal/hostile/pike.dm @@ -2,35 +2,29 @@ name = "space pike" desc = "A bigger, angrier cousin of the space carp." icon = 'icons/mob/simple_animal/spaceshark.dmi' - icon_state = "shark" - icon_living = "shark" - icon_dead = "shark_dead" - turns_per_move = 2 - move_to_delay = 2 - attack_same = 1 - speed = 1 + move_intents = list( + /decl/move_intent/walk/animal_fast, + /decl/move_intent/run/animal_fast + ) + base_movement_delay = 1 mob_size = MOB_SIZE_LARGE - + offset_overhead_text_x = 16 pixel_x = -16 - - health = 150 - maxHealth = 150 - + max_health = 150 harm_intent_damage = 5 natural_weapon = /obj/item/natural_weapon/bite/pike - can_escape = TRUE + butchery_data = /decl/butchery_data/animal/fish/space_carp/pike + ai = /datum/mob_controller/aggressive/carp/pike + ability_handlers = list(/datum/ability_handler/predator) +/datum/mob_controller/aggressive/carp/pike + turns_per_wander = 4 + attack_same_faction = TRUE break_stuff_probability = 55 - - meat_amount = 10 - bone_amount = 20 - skin_amount = 20 + can_escape_buckles = TRUE /obj/item/natural_weapon/bite/pike - force = 25 + _base_attack_force = 25 /mob/living/simple_animal/hostile/carp/pike/carp_randomify() return - -/mob/living/simple_animal/hostile/carp/pike/on_update_icon() - return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm deleted file mode 100644 index b78a858517d9..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ /dev/null @@ -1,45 +0,0 @@ -/mob/living/simple_animal/hostile/pirate - name = "Pirate" - desc = "Does what he wants cause a pirate is free." - icon_state = "piratemelee" - icon_living = "piratemelee" - icon_dead = "piratemelee_dead" - speak_chance = 0 - turns_per_move = 5 - response_help = "pushes" - response_disarm = "shoves" - response_harm = "hits" - speed = 4 - stop_automated_movement_when_pulled = 0 - maxHealth = 100 - health = 100 - can_escape = TRUE - - natural_weapon = /obj/item/energy_blade/sword/pirate/activated - unsuitable_atmos_damage = 15 - var/corpse = /obj/effect/landmark/corpse/pirate - var/weapon1 = /obj/item/energy_blade/sword/pirate - - faction = "pirate" - -/mob/living/simple_animal/hostile/pirate/ranged - name = "Pirate Gunner" - icon_state = "pirateranged" - icon_living = "pirateranged" - icon_dead = "piratemelee_dead" - projectilesound = 'sound/weapons/laser.ogg' - ranged = 1 - rapid = 1 - projectiletype = /obj/item/projectile/beam - corpse = /obj/effect/landmark/corpse/pirate/ranged - weapon1 = /obj/item/gun/energy/laser - - -/mob/living/simple_animal/hostile/pirate/death(gibbed, deathmessage, show_dead_message) - ..(gibbed, deathmessage, show_dead_message) - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) - qdel(src) - return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm index 05c5bee1b22d..681e1eac3903 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm @@ -1,33 +1,28 @@ -/mob/living/simple_animal/hostile/retaliate/clown +/mob/living/simple_animal/hostile/clown name = "clown" desc = "A denizen of clown planet" - icon_state = "clown" - icon_living = "clown" - icon_dead = "clown_dead" - icon_gib = "clown_gib" - speak_chance = 0 - turns_per_move = 5 - response_help = "pokes" - response_disarm = "gently pushes aside" - response_harm = "hits" - speak = list("HONK", "Honk!", "Welcome to clown planet!") - emote_see = list("honks") - speak_chance = 1 - a_intent = I_HURT - stop_automated_movement_when_pulled = 0 - maxHealth = 75 - health = 75 - speed = -1 + icon = 'icons/mob/simple_animal/clown.dmi' + max_health = 75 harm_intent_damage = 8 - can_escape = TRUE minbodytemp = 270 maxbodytemp = 370 heat_damage_per_tick = 15 //amount of damage applied if animal's body temperature is higher than maxbodytemp cold_damage_per_tick = 10 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp unsuitable_atmos_damage = 10 natural_weapon = /obj/item/natural_weapon/clown + faction = "circus" + ai = /datum/mob_controller/aggressive/clown + +/datum/mob_controller/aggressive/clown + turns_per_wander = 10 + emote_speech = list("HONK", "Honk!", "Welcome to clown planet!") + emote_see = list("honks") + speak_chance = 0.25 + stop_wander_when_pulled = FALSE + only_attack_enemies = TRUE + can_escape_buckles = TRUE /obj/item/natural_weapon/clown name = "bike horn" - force = 10 + _base_attack_force = 10 hitsound = 'sound/items/bikehorn.ogg' diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm index 500418329145..02c43aaa8bcf 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm @@ -1,59 +1,80 @@ //malfunctioning combat drones -/mob/living/simple_animal/hostile/retaliate/malf_drone - name = "combat drone" - desc = "An automated combat drone armed with state of the art weaponry and shielding." - icon_state = "drone" - icon_living = "drone" - icon_dead = "drone_dead" - ranged = 1 - rapid = 0 - speak_chance = 5 - turns_per_move = 3 - response_help = "pokes" - response_disarm = "gently pushes aside" - response_harm = "hits" - speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.") - emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity") - a_intent = I_HURT - stop_automated_movement_when_pulled = 0 - health = 300 - maxHealth = 300 - speed = 8 - move_to_delay = 6 - projectiletype = /obj/item/projectile/beam/drone - projectilesound = 'sound/weapons/laser3.ogg' - destroy_surroundings = 0 - - meat_type = null - meat_amount = 0 - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = 0 +/mob/living/simple_animal/hostile/malf_drone + name = "combat drone" + desc = "An automated combat drone armed with state of the art weaponry and shielding." + icon = 'icons/mob/simple_animal/drones/combat.dmi' + burst_projectile = 0 + max_health = 300 + move_intents = list( + /decl/move_intent/walk/animal_slow, + /decl/move_intent/run/animal_slow + ) + projectiletype = /obj/item/projectile/beam/drone + projectilesound = 'sound/weapons/laser3.ogg' + gene_damage = -1 + butchery_data = /decl/butchery_data/synthetic + bleed_colour = SYNTH_BLOOD_COLOR + ai = /datum/mob_controller/aggressive/malf_drone + base_movement_delay = 2 - var/datum/effect/effect/system/trail/ion_trail + //Drones aren't affected by atmos. + min_gas = null + max_gas = null + minbodytemp = 0 + faction = "malf_drone" + skip_spacemove = TRUE + var/datum/effect/effect/system/trail/ion_trail + var/has_loot = 1 + var/explode_chance = 1 + var/disabled = 0 + var/exploding = 0 + + var/static/list/debris = list( + /decl/material/solid/glass = /obj/item/shard, + /decl/material/solid/metal/steel = /obj/item/stack/material/rods, + /decl/material/solid/metal/plasteel = null + ) + +/datum/mob_controller/aggressive/malf_drone + speak_chance = 1.25 + turns_per_wander = 6 + emote_speech = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.") + emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity") + stop_wander_when_pulled = FALSE + only_attack_enemies = TRUE + try_destroy_surroundings = FALSE //the drone randomly switches between these states if it's malfunctioning var/malfunctioning = 1 var/hostile_drone = 0 //0 - retaliate, only attack enemies that attack it //1 - hostile, attack everything that comes near + var/hostile_range = 10 - var/turf/patrol_target - var/explode_chance = 1 - var/disabled = 0 - var/exploding = 0 +/mob/living/simple_animal/hostile/malf_drone/has_ranged_attack() + return TRUE - //Drones aren't affected by atmos. - min_gas = null - max_gas = null - minbodytemp = 0 +/datum/mob_controller/aggressive/malf_drone/get_raw_target_list() + if(hostile_drone) + target_scan_distance = hostile_range + else + target_scan_distance = initial(target_scan_distance) + . = ..() + +/datum/mob_controller/aggressive/malf_drone/get_valid_targets() + . = ..() + for(var/mob/M in .) + if(istype(M, body.type)) + . -= M + +/mob/living/simple_animal/hostile/malf_drone/check_has_mouth() + return FALSE - var/has_loot = 1 - faction = "malf_drone" +/mob/living/simple_animal/hostile/malf_drone/can_act() + return disabled <= 0 && ..() -/mob/living/simple_animal/hostile/retaliate/malf_drone/Initialize() +/mob/living/simple_animal/hostile/malf_drone/Initialize() . = ..() if(prob(5)) projectiletype = /obj/item/projectile/beam/pulse/drone @@ -62,225 +83,203 @@ ion_trail.set_up(src) ion_trail.start() -/mob/living/simple_animal/hostile/retaliate/malf_drone/Process_Spacemove() - return 1 +/mob/living/simple_animal/hostile/malf_drone/Destroy() + QDEL_NULL(ion_trail) + return ..() -/mob/living/simple_animal/hostile/retaliate/malf_drone/proc/Haywire() - if(prob(disabled ? 0 : 1) && malfunctioning) - if(hostile_drone) - src.visible_message("\icon[src] [src] retracts several targetting vanes, and dulls it's running lights.") - hostile_drone = 0 +/mob/living/simple_animal/hostile/malf_drone/proc/Haywire() + var/datum/mob_controller/aggressive/malf_drone/drone_ai = ai + if(prob(disabled ? 0 : 1) && istype(drone_ai) && drone_ai.malfunctioning) + if(drone_ai.hostile_drone) + src.visible_message("[html_icon(src)] [src] retracts several targetting vanes, and dulls it's running lights.") + drone_ai.hostile_drone = 0 else - src.visible_message("\icon[src] [src] suddenly lights up, and additional targetting vanes slide into place.") - hostile_drone = 1 - -/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets() - if(hostile_drone) - return view(src, 10) - else - return ..() + src.visible_message("[html_icon(src)] [src] suddenly lights up, and additional targetting vanes slide into place.") + drone_ai.hostile_drone = 1 //self repair systems have a chance to bring the drone back to life -/mob/living/simple_animal/hostile/retaliate/malf_drone/Life() +/mob/living/simple_animal/hostile/malf_drone/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE //emps and lots of damage can temporarily shut us down if(disabled > 0) set_stat(UNCONSCIOUS) - icon_state = "[initial(icon_state)]_dead" disabled-- - wander = 0 - speak_chance = 0 + if(istype(ai)) + ai.stop_wandering() + ai.speak_chance = 0 if(disabled <= 0) set_stat(CONSCIOUS) - icon_state = "[initial(icon_state)]0" - wander = 1 - speak_chance = 5 + if(istype(ai)) + ai.resume_wandering() + ai.speak_chance = initial(ai.speak_chance) //repair a bit of damage if(prob(1)) - src.visible_message("\icon[src] [src] shudders and shakes as some of it's damaged systems come back online.") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - health += rand(25,100) + src.visible_message("[html_icon(src)] [src] shudders and shakes as some of it's damaged systems come back online.") + spark_at(src, cardinal_only = TRUE) + heal_damage(BRUTE, (rand(10,50)), do_update_health = FALSE) + heal_damage(BURN, (rand(10,50))) //spark for no reason if(prob(5)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) //sometimes our targetting sensors malfunction, and we attack anyone nearby Haywire() - if(health / maxHealth > 0.9) - icon_state = "[initial(icon_state)]" + var/current_health_ratio = get_health_ratio() + if(current_health_ratio > 0.9) explode_chance = 0 - else if(health / maxHealth > 0.7) - icon_state = "[initial(icon_state)]2" + else if(current_health_ratio > 0.7) explode_chance = 0 - else if(health / maxHealth > 0.5) - icon_state = "[initial(icon_state)]1" + else if(current_health_ratio > 0.5) explode_chance = 0.5 - else if(health / maxHealth > 0.3) - icon_state = "[initial(icon_state)]0" + else if(current_health_ratio > 0.3) explode_chance = 5 - else if(health > 0) + else if(current_health > 0) //if health gets too low, shut down - icon_state = "[initial(icon_state)]_dead" exploding = 0 if(!disabled) if(prob(50)) - src.visible_message("\icon[src] [src] suddenly shuts down!") + src.visible_message("[html_icon(src)] [src] suddenly shuts down!") else - src.visible_message("\icon[src] [src] suddenly lies still and quiet.") + src.visible_message("[html_icon(src)] [src] suddenly lies still and quiet.") disabled = rand(150, 600) - walk(src,0) + stop_automove() if(exploding && prob(20)) if(prob(50)) - src.visible_message("\icon[src] [src] begins to spark and shake violenty!") + src.visible_message("[html_icon(src)] [src] begins to spark and shake violenty!") else - src.visible_message("\icon[src] [src] sparks and shakes like it's about to explode!") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() + src.visible_message("[html_icon(src)] [src] sparks and shakes like it's about to explode!") + spark_at(src, cardinal_only = TRUE) if(!exploding && !disabled && prob(explode_chance)) exploding = 1 set_stat(UNCONSCIOUS) - wander = 1 - walk(src,0) + ai?.resume_wandering() + stop_automove() spawn(rand(50,150)) if(!disabled && exploding) explosion(get_turf(src), 0, 1, 4, 7) - //proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1) - ..() + death() + + update_icon() + +/mob/living/simple_animal/hostile/malf_drone/on_update_icon() + . = ..() + if(stat != DEAD) + var/current_max_health = get_max_health() + if(current_health / current_max_health <= 0.3) + icon_state = "[icon_state]-shield3" + else if(current_health / current_max_health <= 0.5) + icon_state = "[icon_state]-shield1" + else if(current_health / current_max_health <= 0.7) + icon_state = "[icon_state]-shield2" //ion rifle! -/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity) - health -= rand(3,15) * (severity + 1) +/mob/living/simple_animal/hostile/malf_drone/emp_act(severity) + take_damage(rand(3,15) * (severity + 1), BURN) disabled = rand(150, 600) - hostile_drone = 0 - walk(src,0) + var/datum/mob_controller/aggressive/malf_drone/drone_brain = ai + if(istype(drone_brain)) + drone_brain.hostile_drone = 0 + stop_automove() + +/mob/living/simple_animal/hostile/malf_drone/get_death_message(gibbed) + return "suddenly breaks apart." -/mob/living/simple_animal/hostile/retaliate/malf_drone/death() - ..(null,"suddenly breaks apart.", "You have been destroyed.") - qdel(src) +/mob/living/simple_animal/hostile/malf_drone/get_self_death_message(gibbed) + return "You have been destroyed." -/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() +/mob/living/simple_animal/hostile/malf_drone/death(gibbed) + . = ..() + if(. && !gibbed) + physically_destroyed() + +/mob/living/simple_animal/hostile/malf_drone/physically_destroyed(skip_qdel) //some random debris left behind if(has_loot) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - var/obj/O - - //shards - O = new /obj/item/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/shard(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - - //rods - O = new /obj/item/stack/material/rods(loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/stack/material/rods(loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/stack/material/rods(loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/stack/material/rods(loc) - step_to(O, get_turf(pick(view(7, src)))) - - //plasteel - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/stack/material/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - + spark_at(src, cardinal_only = TRUE) + var/atom/movable/M + for(var/mat in debris) + for(var/chance in list(100, 75, 50, 25)) + if(!prob(chance)) + break + M = SSmaterials.create_object(mat, loc, 1, debris[mat]) + if(istype(M)) + step_to(M, get_turf(pick(view(7, src)))) //also drop dummy circuit boards deconstructable for research (loot) var/obj/item/stock_parts/circuitboard/C - //spawn 1-4 boards of a random type var/spawnees = 0 var/num_boards = rand(1,4) + //TODO: Make these use actual subtypes instead var/list/options = list(1,2,4,8,16,32,64,128,256,512) for(var/i=0, i 500) //time to look for some food - for(var/mob/living/L in view(src, dist)) - if(!attack_same && L.faction != faction) - prey |= weakref(L) +/mob/living/simple_animal/hostile/beast/get_nutrition() + return nutrition -/mob/living/simple_animal/hostile/retaliate/beast/Life() - . = ..() - if(!.) - return FALSE - hunger++ - if(hunger < 100) //stop hunting when satiated - prey.Cut() - else - for(var/mob/living/simple_animal/S in range(src,1)) - if(S.stat == DEAD) - visible_message("[src] consumes \the body of [S]!") - var/turf/T = get_turf(S) - var/obj/item/remains/xeno/X = new(T) - X.desc += "These look like they belong to \a [S.name]." - hunger = max(0, hunger - 5*S.maxHealth) - if(prob(5)) - S.gib() - else - qdel(S) +/mob/living/simple_animal/hostile/beast/get_satiated_nutrition() + return 250 + +/mob/living/simple_animal/hostile/beast/get_max_nutrition() + return 300 /mob/living/simple_animal/proc/name_species() set name = "Name Alien Species" - set category = "Exploration" + set category = "IC" set src in view() - if(!GLOB.using_map.use_overmap) + if(!global.overmaps_by_name[OVERMAP_ID_SPACE]) return - if(!CanInteract(usr, GLOB.conscious_state)) + if(!CanInteract(usr, global.conscious_topic_state)) return - - for(var/obj/effect/overmap/visitable/sector/exoplanet/E) - if(src in E.animals) + for(var/planet_id in SSmapping.planetoid_data_by_id) + var/datum/planetoid_data/E = SSmapping.planetoid_data_by_id[planet_id] + if(istype(E) && (src in E.fauna.live_fauna)) var/newname = input("What do you want to name this species?", "Species naming", E.get_random_species_name()) as text|null - newname = sanitizeName(newname, allow_numbers = TRUE, force_first_letter_uppercase = FALSE) - if(newname && CanInteract(usr, GLOB.conscious_state)) + newname = sanitize_name(newname, allow_numbers = TRUE, force_first_letter_uppercase = FALSE) + if(newname && CanInteract(usr, global.conscious_topic_state)) if(E.rename_species(type, newname)) - to_chat(usr,"This species will be known from now on as '[newname]'.") + to_chat(usr, SPAN_NOTICE("This species will be known from now on as '[newname]'.")) else - to_chat(usr,"This species has already been named!") + to_chat(usr, SPAN_WARNING("This species has already been named!")) return -/mob/living/simple_animal/hostile/retaliate/beast/samak +/mob/living/simple_animal/hostile/beast/samak name = "samak" desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain." faction = "samak" - icon_state = "samak" - icon_living = "samak" - icon_dead = "samak_dead" - move_to_delay = 2 - maxHealth = 125 - health = 125 - speed = 2 + icon = 'icons/mob/simple_animal/samak.dmi' + move_intents = list( + /decl/move_intent/walk/animal_fast, + /decl/move_intent/run/animal_fast + ) + max_health = 125 natural_weapon = /obj/item/natural_weapon/claws cold_damage_per_tick = 0 - speak_chance = 5 - speak = list("Hruuugh!","Hrunnph") - emote_see = list("paws the ground","shakes its mane","stomps") - emote_hear = list("snuffles") + ai = /datum/mob_controller/aggressive/beast/samak natural_armor = list( - melee = ARMOR_MELEE_KNIVES - ) + ARMOR_MELEE = ARMOR_MELEE_KNIVES + ) + base_movement_delay = 2 -/mob/living/simple_animal/hostile/retaliate/beast/samak/alt +/datum/mob_controller/aggressive/beast/samak + speak_chance = 1.25 + emote_speech = list("Hruuugh!","Hrunnph") + emote_see = list("paws the ground","shakes its mane","stomps") + emote_hear = list("snuffles") + +/mob/living/simple_animal/hostile/beast/samak/alt desc = "A fast, armoured predator accustomed to hiding and ambushing." - icon_state = "samak-alt" - icon_living = "samak-alt" - icon_dead = "samak-alt_dead" + icon = 'icons/mob/simple_animal/samak_alt.dmi' -/mob/living/simple_animal/hostile/retaliate/beast/diyaab +/mob/living/simple_animal/hostile/beast/diyaab name = "diyaab" desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion." faction = "diyaab" - icon_state = "diyaab" - icon_living = "diyaab" - icon_dead = "diyaab_dead" - move_to_delay = 1 - maxHealth = 25 - health = 25 - speed = 1 + icon = 'icons/mob/simple_animal/diyaab.dmi' + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) + max_health = 25 natural_weapon = /obj/item/natural_weapon/claws/weak cold_damage_per_tick = 0 - speak_chance = 5 - speak = list("Awrr?","Aowrl!","Worrl") - emote_see = list("sniffs the air cautiously","looks around") - emote_hear = list("snuffles") mob_size = MOB_SIZE_SMALL + ai = /datum/mob_controller/aggressive/beast/diyaab + base_movement_delay = 1 + +/mob/living/simple_animal/hostile/beast/diyaab/Initialize() + . = ..() + set_extension(src, /datum/extension/shearable, /decl/material/solid/organic/cloth/wool/diyaab) -/mob/living/simple_animal/hostile/retaliate/beast/shantak +/datum/mob_controller/aggressive/beast/diyaab + speak_chance = 1.25 + emote_speech = list("Awrr?","Aowrl!","Worrl") + emote_see = list("sniffs the air cautiously","looks around") + emote_hear = list("snuffles") + +/mob/living/simple_animal/hostile/beast/shantak name = "shantak" - desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though." + desc = "A piglike creature with a bright iridescent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though." faction = "shantak" - icon_state = "shantak" - icon_living = "shantak" - icon_dead = "shantak_dead" - move_to_delay = 1 - maxHealth = 75 - health = 75 - speed = 1 + icon = 'icons/mob/simple_animal/shantak.dmi' + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) + max_health = 75 natural_weapon = /obj/item/natural_weapon/claws cold_damage_per_tick = 0 - speak_chance = 2 - speak = list("Shuhn","Shrunnph?","Shunpf") - emote_see = list("scratches the ground","shakes out its mane","tinkles gently") + ai = /datum/mob_controller/aggressive/beast/shantak + +/datum/mob_controller/aggressive/beast/shantak + speak_chance = 0.5 + emote_speech = list("Shuhn","Shrunnph?","Shunpf") + emote_see = list("scratches the ground","shakes out its mane","tinkles gently") -/mob/living/simple_animal/hostile/retaliate/beast/shantak/alt +/mob/living/simple_animal/hostile/beast/shantak/alt desc = "A piglike creature with a long and graceful mane. Don't be fooled by its beauty." - icon_state = "shantak-alt" - icon_living = "shantak-alt" - icon_dead = "shantak-alt_dead" - emote_see = list("scratches the ground","shakes out it's mane","rustles softly") + icon = 'icons/mob/simple_animal/shantak_alt.dmi' + ai = /datum/mob_controller/aggressive/beast/shantak/alt + +/datum/mob_controller/aggressive/beast/shantak/alt + emote_see = list("scratches the ground","shakes out its mane","rustles softly") /mob/living/simple_animal/yithian name = "yithian" desc = "A friendly creature vaguely resembling an oversized snail without a shell." - icon_state = "yithian" - icon_living = "yithian" - icon_dead = "yithian_dead" + icon = 'icons/mob/simple_animal/yithian.dmi' mob_size = MOB_SIZE_TINY /mob/living/simple_animal/tindalos name = "tindalos" desc = "It looks like a large, flightless grasshopper." - icon_state = "tindalos" - icon_living = "tindalos" - icon_dead = "tindalos_dead" + icon = 'icons/mob/simple_animal/tindalos.dmi' mob_size = MOB_SIZE_TINY /mob/living/simple_animal/thinbug name = "taki" desc = "It looks like a bunch of legs." - icon_state = "thinbug" - icon_living = "thinbug" - icon_dead = "thinbug_dead" - speak_chance = 1 - emote_hear = list("scratches the ground","chitters") + icon = 'icons/mob/simple_animal/bug.dmi' + ai = /datum/mob_controller/thinbug mob_size = MOB_SIZE_MINISCULE -/mob/living/simple_animal/hostile/retaliate/royalcrab +/datum/mob_controller/thinbug + speak_chance = 0.25 + emote_hear = list("scratches the ground","chitters") + +/mob/living/simple_animal/hostile/royalcrab name = "cragenoy" desc = "It looks like a crustacean with an exceedingly hard carapace. Watch the pinchers!" faction = "crab" - icon_state = "royalcrab" - icon_living = "royalcrab" - icon_dead = "royalcrab_dead" - move_to_delay = 3 - maxHealth = 150 - health = 150 - speed = 1 + icon = 'icons/mob/simple_animal/royalcrab.dmi' + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) + max_health = 150 natural_weapon = /obj/item/natural_weapon/pincers - speak_chance = 1 - emote_see = list("skitters","oozes liquid from its mouth", "scratches at the ground", "clicks its claws") + ai = /datum/mob_controller/aggressive/thinbug natural_armor = list( - melee = ARMOR_MELEE_RESISTANT - ) - -/mob/living/simple_animal/hostile/retaliate/beast/charbaby + ARMOR_MELEE = ARMOR_MELEE_RESISTANT + ) + base_movement_delay = 1 + +/datum/mob_controller/aggressive/thinbug + speak_chance = 0.25 + emote_see = list("skitters","oozes liquid from its mouth", "scratches at the ground", "clicks its claws") + only_attack_enemies = TRUE + +/mob/living/simple_animal/hostile/beast/charbaby name = "charbaby" desc = "A huge grubby creature." - icon_state = "char" - icon_living = "char" - icon_dead = "char_dead" + icon = 'icons/mob/simple_animal/char.dmi' mob_size = MOB_SIZE_LARGE - health = 45 - maxHealth = 45 + max_health = 45 natural_weapon = /obj/item/natural_weapon/charbaby - speed = 2 - response_help = "pats briefly" - response_disarm = "gently pushes" - response_harm = "strikes" return_damage_min = 2 return_damage_max = 3 harm_intent_damage = 1 blood_color = COLOR_NT_RED natural_armor = list( - laser = ARMOR_LASER_HANDGUNS - ) + ARMOR_LASER = ARMOR_LASER_HANDGUNS + ) + base_movement_delay = 2 /obj/item/natural_weapon/charbaby name = "scalding hide" - damtype = BURN - force = 5 - attack_verb = list("singed") + atom_damage_type = BURN + attack_verb = "singed" -/mob/living/simple_animal/hostile/retaliate/beast/charbaby/attack_hand(mob/living/carbon/human/H) +/mob/living/simple_animal/hostile/beast/charbaby/default_hurt_interaction(mob/user) . = ..() - reflect_unarmed_damage(H, BURN, "amorphous mass") + if(. && ishuman(user)) + reflect_unarmed_damage(user, BURN, "amorphous mass") -/mob/living/simple_animal/hostile/retaliate/beast/charbaby/AttackingTarget() +/mob/living/simple_animal/hostile/beast/charbaby/apply_attack_effects(mob/living/target) . = ..() - if(isliving(target_mob) && prob(25)) - var/mob/living/L = target_mob - if(prob(10)) - L.adjust_fire_stacks(1) - L.IgniteMob() + if(prob(10)) + target.adjust_fire_intensity(1) + target.ignite_fire() -/mob/living/simple_animal/hostile/retaliate/beast/shantak/lava +/mob/living/simple_animal/hostile/beast/shantak/lava desc = "A vaguely canine looking beast. It looks as though its fur is made of stone wool." - icon_state = "lavadog" - icon_living = "lavadog" - icon_dead = "lavadog_dead" - speak = list("Karuph","Karump") \ No newline at end of file + icon = 'icons/mob/simple_animal/lavadog.dmi' + ai = /datum/mob_controller/aggressive/beast/shantak/lava + +/datum/mob_controller/aggressive/beast/shantak/lava + emote_speech = list("Karuph","Karump") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/giant_crab.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/giant_crab.dm index 3efe2cac9de7..d6491b460cea 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/giant_crab.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/giant_crab.dm @@ -1,106 +1,98 @@ -/mob/living/simple_animal/hostile/retaliate/giant_crab +/mob/living/simple_animal/hostile/giant_crab name = "giant crab" desc = "A gigantic crustacean with a blue shell. Its left claw is nearly twice the size of its right." - icon_state = "bluecrab" - icon_living = "bluecrab" - icon_dead = "bluecrab_dead" + icon = 'icons/mob/simple_animal/bluecrab.dmi' mob_size = MOB_SIZE_LARGE speak_emote = list("clicks") - emote_hear = list("clicks") - emote_see = list("clacks") - speak_chance = 1 - turns_per_move = 5 - response_help = "pats" - response_disarm = "gently nudges" - response_harm = "strikes" - meat_amount = 12 - can_escape = TRUE //snip snip - break_stuff_probability = 15 + butchery_data = /decl/butchery_data/animal/arthropod/crab/giant faction = "crabs" - pry_time = 2 SECONDS - - health = 350 - maxHealth = 350 + max_health = 350 natural_weapon = /obj/item/natural_weapon/pincers/giant return_damage_min = 2 return_damage_max = 5 harm_intent_damage = 1 natural_armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_PISTOL + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL ) ability_cooldown = 2 MINUTES + ai = /datum/mob_controller/aggressive/giant_crab - var/mob/living/carbon/human/victim //the human we're grabbing + var/mob/living/human/victim //the human we're grabbing var/grab_duration = 3 //duration of disable in life ticks to simulate a grab var/grab_damage = 6 //brute damage before reductions, per crab's life tick var/list/grab_desc = list("thrashes", "squeezes", "crushes") var/continue_grab_prob = 35 //probability that a successful grab will be extended by one life tick +/datum/mob_controller/aggressive/giant_crab + break_stuff_probability = 15 + emote_hear = list("clicks") + emote_see = list("clacks") + speak_chance = 0.25 + turns_per_wander = 10 + expected_type = /mob/living/simple_animal/hostile/giant_crab + only_attack_enemies = TRUE + can_escape_buckles = TRUE + +/datum/mob_controller/aggressive/giant_crab/do_process(time_elapsed) + if(!(. = ..())) + return + var/mob/living/simple_animal/hostile/giant_crab/crab = body + if(!istype(crab) || body.stat) + return + crab.process_grab() + if((body.current_health > body.get_max_health() / 1.5) && LAZYLEN(get_enemies()) && prob(5)) + if(crab.victim) + crab.release_grab() + clear_enemies() + lose_target() + body.visible_message(SPAN_NOTICE("\The [body] lowers its pincer.")) + /obj/item/natural_weapon/pincers/giant - force = 15 + _base_attack_force = 15 attack_verb = list("snipped", "pinched", "crushed") -/mob/living/simple_animal/hostile/retaliate/giant_crab/Initialize() //embiggen +/mob/living/simple_animal/hostile/giant_crab/Initialize() //embiggen . = ..() - var/matrix/M = new - M.Scale(1.5) - transform = M + set_scale(1.5) + +/mob/living/simple_animal/hostile/giant_crab/get_door_pry_time() + return 2 SECONDS -/mob/living/simple_animal/hostile/retaliate/giant_crab/Destroy() +/mob/living/simple_animal/hostile/giant_crab/Destroy() . = ..() victim = null -/mob/living/simple_animal/hostile/retaliate/giant_crab/attack_hand(mob/living/carbon/human/H) +/mob/living/simple_animal/hostile/giant_crab/default_hurt_interaction(mob/user) . = ..() - reflect_unarmed_damage(H, BRUTE, "armoured carapace") + if(. && ishuman(user)) + reflect_unarmed_damage(user, BRUTE, "armoured carapace") -/mob/living/simple_animal/hostile/retaliate/giant_crab/Life() +/mob/living/simple_animal/hostile/giant_crab/apply_attack_effects(mob/living/target) . = ..() - if(!.) + if(!ishuman(target)) return - - if((health > maxHealth / 1.5) && enemies.len && prob(10)) - if(victim) - release_grab() - enemies = list() - LoseTarget() - visible_message("\The [src] lowers its pincer.") -/mob/living/simple_animal/hostile/retaliate/giant_crab/do_delayed_life_action() - ..() - process_grab() - -/mob/living/simple_animal/hostile/retaliate/giant_crab/AttackingTarget() - . = ..() - if(ishuman(.)) - var/mob/living/carbon/human/H = . - if(victim == H) - if(!Adjacent(victim)) - release_grab() - else if(prob(continue_grab_prob)) - H.Weaken(1) - H.Stun(1) - grab_damage++ - visible_message(SPAN_MFAUNA("\The [src] tightens its grip on \the [victim]!")) - return - - if(!victim && can_perform_ability(H)) - GLOB.destroyed_event.register(victim, src, .proc/release_grab) - victim = H - H.Weaken(grab_duration) - H.Stun(grab_duration) - visible_message(SPAN_MFAUNA("\The [src] catches \the [victim] in its powerful pincer!")) - stop_automation = TRUE + var/mob/living/human/H = target + if(victim == H) + if(!Adjacent(victim)) + release_grab() + else if(prob(continue_grab_prob)) + SET_STATUS_MAX(H, STAT_WEAK, 1) + SET_STATUS_MAX(H, STAT_STUN, 1) + grab_damage++ + visible_message(SPAN_MFAUNA("\The [src] tightens its grip on \the [victim]!")) + return -/mob/living/simple_animal/hostile/retaliate/giant_crab/can_perform_ability(mob/living/carbon/human/H) - . = ..() - if(!.) - return FALSE - if(!Adjacent(H)) - return FALSE + if(!victim && can_act() && !is_on_special_ability_cooldown() && Adjacent(H)) + events_repository.register(/decl/observ/destroyed, victim, src, PROC_REF(release_grab)) + victim = H + SET_STATUS_MAX(H, STAT_WEAK, grab_duration) + SET_STATUS_MAX(H, STAT_STUN, grab_duration) + visible_message(SPAN_MFAUNA("\The [src] catches \the [victim] in its powerful pincer!")) + ai?.pause() -/mob/living/simple_animal/hostile/retaliate/giant_crab/proc/process_grab() +/mob/living/simple_animal/hostile/giant_crab/proc/process_grab() if(victim && !incapacitated()) if(victim.stat >= UNCONSCIOUS || !Adjacent(victim) || !victim.incapacitated()) release_grab() @@ -108,11 +100,11 @@ visible_message(SPAN_DANGER("\The [src] [pick(grab_desc)] \the [victim] in its pincer!")) victim.apply_damage(grab_damage, BRUTE, BP_CHEST, DAM_EDGE, used_weapon = "crab's pincer") -/mob/living/simple_animal/hostile/retaliate/giant_crab/proc/release_grab() +/mob/living/simple_animal/hostile/giant_crab/proc/release_grab() if(victim) visible_message(SPAN_NOTICE("\The [src] releases its grip on \the [victim]!")) - GLOB.destroyed_event.unregister(victim) + events_repository.unregister(/decl/observ/destroyed, victim) victim = null - cooldown_ability(ability_cooldown) - stop_automation = FALSE + set_special_ability_cooldown(ability_cooldown) + ai?.resume() grab_damage = initial(grab_damage) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot.dm index 5fb7b9457758..34ed830fc4b1 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot.dm @@ -1,13 +1,10 @@ -/mob/living/simple_animal/hostile/retaliate/parrot/space +/mob/living/simple_animal/hostile/parrot/space name = "space parrot" desc = "It could be some all-knowing being that, for reasons we could never hope to understand, is assuming the shape and general mannerisms of a parrot - or just a rather large bird." gender = FEMALE - health = 750 //how sweet it is to be a god! - maxHealth = 750 + max_health = 750 mob_size = MOB_SIZE_LARGE - speak = list("...") - speak_emote = list("professes","speaks unto you","elaborates","proclaims") - emote_hear = list("sings a song to herself", "preens herself") + speak_emote = list("professes","speaks unto you","elaborates","proclaims") natural_weapon = /obj/item/natural_weapon/giant min_gas = null max_gas = null @@ -15,80 +12,71 @@ universal_understand = TRUE see_invisible = SEE_INVISIBLE_NOLIGHTING see_in_dark = 7 - can_escape = TRUE relax_chance = 60 //a gentle beast impatience = 10 parrot_isize = ITEM_SIZE_LARGE simple_parrot = TRUE ability_cooldown = 2 MINUTES + butchery_data = /decl/butchery_data/animal/bird/parrot/space + ai = /datum/mob_controller/aggressive/parrot/space + var/get_subspecies_name = TRUE - meat_amount = 10 - bone_amount = 20 - skin_amount = 20 +/datum/mob_controller/aggressive/parrot/space + emote_speech = null + emote_hear = list("sings a song to herself", "preens herself") + can_escape_buckles = TRUE - var/list/subspecies = list(/decl/parrot_subspecies, - /decl/parrot_subspecies/purple, - /decl/parrot_subspecies/blue, - /decl/parrot_subspecies/green, - /decl/parrot_subspecies/red, - /decl/parrot_subspecies/brown, - /decl/parrot_subspecies/black) - var/get_subspecies_name = TRUE +/mob/living/simple_animal/hostile/parrot/space/proc/get_parrot_species() + var/list/parrot_species = decls_repository.get_decls_of_type(/decl/parrot_subspecies) + return LAZYLEN(parrot_species) ? parrot_species[pick(parrot_species)] : null -/mob/living/simple_animal/hostile/retaliate/parrot/space/Initialize() +/mob/living/simple_animal/hostile/parrot/space/Initialize() . = ..() - var/subspecies_type = safepick(subspecies) - if(subspecies_type) - var/decl/parrot_subspecies/ps = decls_repository.get_decl(subspecies_type) - icon_set = ps.icon_set - skin_material = ps.feathers + var/decl/parrot_subspecies/parrot_species = get_parrot_species() + if(parrot_species) + icon_set = parrot_species.icon_set + butchery_data = parrot_species.butchery_data if(get_subspecies_name) - SetName(ps.name) - var/matrix/M = new - M.Scale(2) - transform = M + SetName(parrot_species.name) + set_scale(2) update_icon() -/mob/living/simple_animal/hostile/retaliate/parrot/space/AttackingTarget() +/mob/living/simple_animal/hostile/parrot/space/apply_attack_effects(mob/living/target) . = ..() - if(ishuman(.) && can_perform_ability(.)) - var/mob/living/carbon/human/H = . + if(ishuman(target) && can_act() && !is_on_special_ability_cooldown() && Adjacent(.)) + var/mob/living/human/H = target if(prob(70)) - H.Weaken(rand(2,3)) - cooldown_ability(ability_cooldown / 1.5) + SET_STATUS_MAX(H, STAT_WEAK, rand(2,3)) + set_special_ability_cooldown(ability_cooldown / 1.5) visible_message(SPAN_MFAUNA("\The [src] flaps its wings mightily and bowls over \the [H] with a gust!")) - else if(H.get_equipped_item(slot_head)) - var/obj/item/clothing/head/HAT = H.get_equipped_item(slot_head) - if(H.canUnEquip(HAT)) + else if(H.get_equipped_item(slot_head_str)) + var/obj/item/clothing/head/HAT = H.get_equipped_item(slot_head_str) + if(H.can_unequip_item(HAT)) visible_message(SPAN_MFAUNA("\The [src] rips \the [H]'s [HAT] off!")) - cooldown_ability(ability_cooldown) - H.unEquip(HAT, get_turf(src)) - -/mob/living/simple_animal/hostile/retaliate/parrot/space/can_perform_ability(mob/living/carbon/human/H) - . = ..() - if(!.) - return FALSE - if(!Adjacent(H)) - return FALSE + set_special_ability_cooldown(ability_cooldown) + H.try_unequip(HAT, get_turf(src)) //subtypes -/mob/living/simple_animal/hostile/retaliate/parrot/space/lesser +/mob/living/simple_animal/hostile/parrot/space/lesser name = "Avatar of the Howling Dark" - subspecies = list(/decl/parrot_subspecies/black) get_subspecies_name = FALSE natural_weapon = /obj/item/natural_weapon/large - health = 300 - maxHealth = 300 + max_health = 300 -/mob/living/simple_animal/hostile/retaliate/parrot/space/megafauna +/mob/living/simple_animal/hostile/parrot/space/lesser/get_parrot_species() + return GET_DECL(/decl/parrot_subspecies/black) + +/mob/living/simple_animal/hostile/parrot/space/megafauna name = "giant parrot" desc = "A huge parrot-like bird." get_subspecies_name = FALSE - health = 350 - maxHealth = 350 + max_health = 350 speak_emote = list("squawks") - emote_hear = list("preens itself") + ai = /datum/mob_controller/aggressive/parrot/space/megafauna natural_weapon = /obj/item/natural_weapon/large relax_chance = 30 - impatience = 5 \ No newline at end of file + impatience = 5 + +/datum/mob_controller/aggressive/parrot/space/megafauna + emote_hear = list("preens itself") diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot_species.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot_species.dm index 99837db14c13..edd29823f11d 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot_species.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/giant_parrot/giant_parrot_species.dm @@ -1,34 +1,34 @@ /decl/parrot_subspecies var/name = "giant parrot" var/icon_set = "parrot" - var/feathers = /decl/material/solid/skin/feathers + var/butchery_data = /decl/butchery_data/animal/bird/parrot/space /decl/parrot_subspecies/purple name = "simurgh" icon_set = "purple" - feathers = /decl/material/solid/skin/feathers/purple + butchery_data = /decl/butchery_data/animal/bird/parrot/space/purple /decl/parrot_subspecies/blue name = "ziz" icon_set = "blue" - feathers = /decl/material/solid/skin/feathers/blue + butchery_data = /decl/butchery_data/animal/bird/parrot/space/blue /decl/parrot_subspecies/green name = "fenghuang" icon_set = "green" - feathers = /decl/material/solid/skin/feathers/green + butchery_data = /decl/butchery_data/animal/bird/parrot/space/green /decl/parrot_subspecies/brown name = "roc" icon_set = "brown" - feathers = /decl/material/solid/skin/feathers/brown + butchery_data = /decl/butchery_data/animal/bird/parrot/space/brown /decl/parrot_subspecies/red name = "phoenix" icon_set = "red" - feathers = /decl/material/solid/skin/feathers/red + butchery_data = /decl/butchery_data/animal/bird/parrot/space/red /decl/parrot_subspecies/black name = "lord of birds" icon_set = "black" - feathers = /decl/material/solid/skin/feathers/black + butchery_data = /decl/butchery_data/animal/bird/parrot/space/black diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm index 6a5a2534c2bc..f4f0d39d70cc 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm @@ -1,30 +1,14 @@ -/mob/living/simple_animal/hostile/retaliate/goose +/mob/living/simple_animal/hostile/goose name = "goose" desc = "A large waterfowl, known for its beauty and quick temper when provoked." icon = 'icons/mob/simple_animal/goose.dmi' - icon_state = "goose" - icon_living = "goose" - icon_dead = "goose_dead" - speak = list("Honk!") - speak_emote = list("honks") - emote_hear = list("honks","flaps its wings","clacks") - emote_see = list("flaps its wings", "scratches the ground") - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "strikes" + speak_emote = list("honks") natural_weapon = /obj/item/natural_weapon/goosefeet - health = 45 - maxHealth = 45 + max_health = 45 pass_flags = PASS_FLAG_TABLE faction = "geese" - pry_time = 8 SECONDS - break_stuff_probability = 5 - - meat_type = /obj/item/chems/food/snacks/meat/chicken/game - meat_amount = 6 - bone_amount = 8 - skin_amount = 8 - skin_material = /decl/material/solid/skin/feathers + butchery_data = /decl/butchery_data/animal/small/fowl/goose + ai = /datum/mob_controller/aggressive/goose var/enrage_potency = 3 var/enrage_potency_loose = 4 @@ -32,51 +16,59 @@ var/max_damage = 25 var/loose = FALSE //goose loose status +/datum/mob_controller/aggressive/goose + break_stuff_probability = 5 + emote_speech = list("Honk!") + emote_hear = list("honks","flaps its wings","clacks") + emote_see = list("flaps its wings", "scratches the ground") + only_attack_enemies = TRUE + +/datum/mob_controller/aggressive/goose/retaliate(atom/source) + . = ..() + if(body?.stat == CONSCIOUS && istype(body, /mob/living/simple_animal/hostile/goose)) + var/mob/living/simple_animal/hostile/goose/goose = body + goose.enrage(goose.enrage_potency) + /obj/item/natural_weapon/goosefeet name = "goose feet" gender = PLURAL attack_verb = list("smacked around") - force = 0 - damtype = BRUTE + _base_attack_force = 0 + atom_damage_type = BRUTE canremove = FALSE -/mob/living/simple_animal/hostile/retaliate/goose/Retaliate() - ..() - if(stat == CONSCIOUS) - enrage(enrage_potency) +/mob/living/simple_animal/hostile/goose/get_door_pry_time() + return 8 SECONDS -/mob/living/simple_animal/hostile/retaliate/goose/on_update_icon() - if(stat == DEAD) - icon_state = icon_dead - else if(loose) - icon_state = "goose_loose" - icon_living = "goose_loose" +/mob/living/simple_animal/hostile/goose/on_update_icon() + ..() + if(stat != DEAD && loose) + icon_state += "-loose" -/mob/living/simple_animal/hostile/retaliate/goose/death(gibbed, deathmessage, show_dead_message) +/mob/living/simple_animal/hostile/goose/death(gibbed) . = ..() - update_icon() + if(. && !gibbed) + update_icon() -/mob/living/simple_animal/hostile/retaliate/goose/proc/enrage(var/potency) - var/obj/item/W = get_natural_weapon() - if(W) - W.force = min((W.force + potency), max_damage) - if(!loose && prob(25) && (W && W.force >= loose_threshold)) //second wind +/mob/living/simple_animal/hostile/goose/proc/enrage(var/potency) + var/obj/item/attacking_with = get_natural_weapon() + if(attacking_with) + attacking_with.set_base_attack_force(min((attacking_with.get_initial_base_attack_force() + potency), max_damage)) + if(!loose && prob(25) && (attacking_with && attacking_with.expend_attack_force(src) >= loose_threshold)) //second wind loose = TRUE - health = (initial(health) * 1.5) - maxHealth = (initial(maxHealth) * 1.5) + set_max_health(initial(max_health) * 1.5) + set_damage(BRUTE, 0) + set_damage(BURN, 0) enrage_potency = enrage_potency_loose - desc += " The [name] is loose! Oh no!" + desc += " \The [src] is loose! Oh no!" update_icon() -/mob/living/simple_animal/hostile/retaliate/goose/dire +/mob/living/simple_animal/hostile/goose/dire name = "dire goose" desc = "A large bird. It radiates destructive energy." - icon_state = "dire" - icon_living = "dire" - icon_dead = "dire_dead" - health = 250 - maxHealth = 250 + icon = 'icons/mob/simple_animal/goose_dire.dmi' + max_health = 250 enrage_potency = 3 loose_threshold = 20 max_damage = 35 - skull_type = /obj/item/pen/fancy/quill \ No newline at end of file + butchery_data = /decl/butchery_data/animal/small/fowl/goose/dire diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/jelly.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/jelly.dm index d41091860344..3d164bbfa262 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/jelly.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/jelly.dm @@ -1,67 +1,69 @@ -/mob/living/simple_animal/hostile/retaliate/jelly +/mob/living/simple_animal/hostile/jelly name = "zeq" desc = "It looks like a floating jellyfish. How does it do that?" faction = "zeq" - icon_state = "jelly" - icon_living = "jelly" - icon_dead = "jelly_dead" - move_to_delay = 1 - maxHealth = 75 - health = 75 - speed = 1 - natural_weapon = /obj/item/natural_weapon/tentecles - speak_chance = 1 - emote_see = list("wobbles slightly","oozes something out of tentacles' ends") + icon = 'icons/mob/simple_animal/jelly.dmi' + move_intents = list( + /decl/move_intent/walk/animal_fast, + /decl/move_intent/run/animal_fast + ) + max_health = 75 + natural_weapon = /obj/item/natural_weapon/tentacles + ai = /datum/mob_controller/aggressive/jelly + base_movement_delay = 1 var/gets_random_color = TRUE -/obj/item/natural_weapon/tentecles +/datum/mob_controller/aggressive/jelly + speak_chance = 0.25 + emote_see = list("wobbles slightly","oozes something out of tentacles' ends") + only_attack_enemies = TRUE + +/obj/item/natural_weapon/tentacles name = "tentacles" attack_verb = list("stung","slapped") - force = 10 - damtype = BURN + _base_attack_force = 10 + atom_damage_type = BURN -/mob/living/simple_animal/hostile/retaliate/jelly/Initialize() +/mob/living/simple_animal/hostile/jelly/Initialize() . = ..() if(gets_random_color) - color = color_rotation(round(rand(0,360),20)) + color = color_matrix_rotate_hue(round(rand(0,360),20)) -/mob/living/simple_animal/hostile/retaliate/jelly/alt - icon_state = "jelly-alt" - icon_living = "jelly-alt" - icon_dead = "jelly-alt_dead" +/mob/living/simple_animal/hostile/jelly/alt + icon = 'icons/mob/simple_animal/jelly_alt.dmi' //megajellyfish -/mob/living/simple_animal/hostile/retaliate/jelly/mega +/mob/living/simple_animal/hostile/jelly/mega name = "zeq queen" desc = "A gigantic jellyfish-like creature. Its bell wobbles about almost as if it's ready to burst." - maxHealth = 300 - health = 300 + max_health = 300 gets_random_color = FALSE - can_escape = TRUE + ai = /datum/mob_controller/aggressive/megajelly var/jelly_scale = 3 - var/split_type = /mob/living/simple_animal/hostile/retaliate/jelly/mega/half + var/split_type = /mob/living/simple_animal/hostile/jelly/mega/half var/static/megajelly_color -/mob/living/simple_animal/hostile/retaliate/jelly/mega/Initialize() +/datum/mob_controller/aggressive/megajelly + can_escape_buckles = TRUE + +/mob/living/simple_animal/hostile/jelly/mega/Initialize() . = ..() - var/matrix/M = new - M.Scale(jelly_scale) - transform = M - var/obj/item/W = get_natural_weapon() - if(W) - W.force *= jelly_scale + set_scale(jelly_scale) + var/obj/item/attacking_with = get_natural_weapon() + if(attacking_with) + attacking_with.set_base_attack_force(attacking_with.get_initial_base_attack_force() * jelly_scale) if(!megajelly_color) - megajelly_color = color_rotation(round(rand(0,360),20)) + megajelly_color = color_matrix_rotate_hue(round(rand(0,360),20)) color = megajelly_color -/mob/living/simple_animal/hostile/retaliate/jelly/mega/death() +/mob/living/simple_animal/hostile/jelly/mega/death(gibbed) if(split_type) jelly_split() - else - ..() + return TRUE + return ..() -/mob/living/simple_animal/hostile/retaliate/jelly/mega/proc/jelly_split() +/mob/living/simple_animal/hostile/jelly/mega/proc/jelly_split() visible_message(SPAN_MFAUNA("\The [src] rumbles briefly before splitting into two!")) var/kidnum = 2 for(var/i = 0 to kidnum) @@ -72,36 +74,31 @@ child.maxbodytemp = maxbodytemp QDEL_NULL(src) -/mob/living/simple_animal/hostile/retaliate/jelly/mega/half +/mob/living/simple_animal/hostile/jelly/mega/half name = "zeq duchess" desc = "A huge jellyfish-like creature." - maxHealth = 150 - health = 150 - can_escape = TRUE + max_health = 150 jelly_scale = 1.5 - split_type = /mob/living/simple_animal/hostile/retaliate/jelly/mega/quarter + split_type = /mob/living/simple_animal/hostile/jelly/mega/quarter -/mob/living/simple_animal/hostile/retaliate/jelly/mega/quarter +/mob/living/simple_animal/hostile/jelly/mega/quarter name = "zeqling" desc = "A jellyfish-like creature." - health = 75 - maxHealth = 75 + max_health = 75 jelly_scale = 0.75 - can_escape = FALSE - split_type = /mob/living/simple_animal/hostile/retaliate/jelly/mega/fourth + split_type = /mob/living/simple_animal/hostile/jelly/mega/fourth + ai = /datum/mob_controller/aggressive -/mob/living/simple_animal/hostile/retaliate/jelly/mega/fourth +/mob/living/simple_animal/hostile/jelly/mega/fourth name = "zeqetta" desc = "A tiny jellyfish-like creature." - health = 40 - maxHealth = 40 + max_health = 40 jelly_scale = 0.375 - split_type = /mob/living/simple_animal/hostile/retaliate/jelly/mega/eighth + split_type = /mob/living/simple_animal/hostile/jelly/mega/eighth -/mob/living/simple_animal/hostile/retaliate/jelly/mega/eighth +/mob/living/simple_animal/hostile/jelly/mega/eighth name = "zeqttina" desc = "An absolutely tiny jellyfish-like creature." - health = 20 - maxHealth = 20 + max_health = 20 jelly_scale = 0.1875 split_type = null \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm index d39f096bfb2c..9e0c73835b94 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm @@ -1,42 +1,76 @@ + +/datum/mob_controller/aggressive/goat/king + break_stuff_probability = 35 + emote_hear = list("brays in a booming voice") + emote_see = list("stamps a mighty foot, shaking the surroundings") + only_attack_enemies = TRUE + can_escape_buckles = TRUE + +/datum/mob_controller/aggressive/goat/king/retaliate(atom/source) + ..() + if(body?.stat == CONSCIOUS && prob(5)) + var/decl/pronouns/pronouns = body.get_pronouns() + body.visible_message(SPAN_WARNING("\The [body] bellows indignantly, with a judgemental gleam in [pronouns.his] eye.")) + +/datum/mob_controller/aggressive/goat/king/phase2 + break_stuff_probability = 40 + +/datum/mob_controller/aggressive/goat/king/phase2/retaliate(atom/source) + . = ..() + var/mob/living/simple_animal/hostile/goat/king/phase2/goat = body + if(istype(goat)) + goat.do_retaliation() + //Visager's tracks 'Battle!' and 'Miniboss Fight' from the album 'Songs from an Unmade World 2' are available here //http://freemusicarchive.org/music/Visager/Songs_From_An_Unmade_World_2/ and are made available under the CC BY 4.0 Attribution license, //which is available for viewing here: https://creativecommons.org/licenses/by/4.0/legalcode - //the king and his court -/mob/living/simple_animal/hostile/retaliate/goat/king - name = "king of goats" - desc = "The oldest and wisest of goats; king of his race, peerless in dignity and power. His golden fleece radiates nobility." - icon = 'icons/mob/simple_animal/king_of_goats.dmi' - icon_state = "king_goat" - icon_living = "king_goat" - icon_dead = "goat_dead" - speak_emote = list("brays in a booming voice") - emote_hear = list("brays in a booming voice") - emote_see = list("stamps a mighty foot, shaking the surroundings") - meat_amount = 12 - response_help = "placates" - response_harm = "assaults" - health = 500 - maxHealth = 500 - mob_size = MOB_SIZE_LARGE - mob_bump_flag = HEAVY - can_escape = TRUE - move_to_delay = 3 - min_gas = null - max_gas = null - minbodytemp = 0 - break_stuff_probability = 35 - flash_vulnerability = 0 - natural_weapon = /obj/item/natural_weapon/goatking - var/current_damtype = BRUTE +/mob/living/simple_animal/hostile/goat/king + name = "king of goats" + desc = "The oldest and wisest of goats; king of his race, peerless in dignity and power. His golden fleece radiates nobility." + icon = 'icons/mob/simple_animal/goat_king.dmi' + speak_emote = list("brays in a booming voice") + ai = /datum/mob_controller/aggressive/goat/king + response_harm = "assaults" + max_health = 500 + mob_size = MOB_SIZE_LARGE + mob_bump_flag = HEAVY + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) + min_gas = null + max_gas = null + minbodytemp = 0 + flash_protection = FLASH_PROTECTION_MAJOR + natural_weapon = /obj/item/natural_weapon/goatking + skip_spacemove = TRUE + var/current_damtype = BRUTE + var/stun_chance = 5 //chance per attack to Weaken target var/list/elemental_weapons = list( BURN = /obj/item/natural_weapon/goatking/fire, ELECTROCUTE = /obj/item/natural_weapon/goatking/lightning ) - var/stun_chance = 5 //chance per attack to Weaken target -/mob/living/simple_animal/hostile/retaliate/goat/king/get_natural_weapon() +/mob/living/simple_animal/hostile/goat/king/proc/OnDeath() + visible_message(SPAN_CULT_ANNOUNCE("\The [src] lets loose a terrific wail as its wounds close shut with a flash of light, and its eyes glow even brighter than before!")) + new /mob/living/simple_animal/hostile/goat/king/phase2(src.loc) + qdel(src) + +/mob/living/simple_animal/hostile/goat/king/death(gibbed) + . = ..() + if(.) + OnDeath() + +/mob/living/simple_animal/hostile/goat/king/apply_attack_effects(mob/living/target) + . = ..() + if(prob(stun_chance)) + SET_STATUS_MAX(target, STAT_WEAK, 0.5) + ADJ_STATUS(target, STAT_CONFUSE, 1) + visible_message(SPAN_WARNING("\The [target] is bowled over by the impact of [src]'s attack!")) + +/mob/living/simple_animal/hostile/goat/king/get_natural_weapon() if(!(current_damtype in elemental_weapons)) return ..() if(ispath(elemental_weapons[current_damtype])) @@ -46,34 +80,51 @@ /obj/item/natural_weapon/goatking name = "giant horns" - attack_verb = list("brutalized") - force = 40 + attack_verb = "brutalized" + _base_attack_force = 40 sharp = TRUE /obj/item/natural_weapon/goatking/fire name = "burning horns" - damtype = BURN + atom_damage_type = BURN /obj/item/natural_weapon/goatking/lightning name = "lightning horns" - damtype = ELECTROCUTE + atom_damage_type = ELECTROCUTE -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2 +/mob/living/simple_animal/hostile/goat/guard + name = "honour guard" + desc = "A very handsome and noble beast." + icon = 'icons/mob/simple_animal/goat_guard.dmi' + max_health = 125 + natural_weapon = /obj/item/natural_weapon/goathorns + +/obj/item/natural_weapon/goathorns + name = "horns" + attack_verb = list("impaled", "stabbed") + _base_attack_force = 15 + sharp = TRUE + +/mob/living/simple_animal/hostile/goat/guard/master + name = "master of the guard" + desc = "A very handsome and noble beast - the most trusted of all the king's men." + icon = 'icons/mob/simple_animal/goat_master.dmi' + max_health = 200 + natural_weapon = /obj/item/natural_weapon/goathorns + +/mob/living/simple_animal/hostile/goat/king/phase2 name = "emperor of goats" desc = "The King of Kings, God amongst men, and your superior in every way." - icon_state = "king_goat2" - icon_living = "king_goat2" - meat_amount = 36 - health = 750 - maxHealth = 750 + icon = 'icons/mob/simple_animal/goat_king_phase_2.dmi' + max_health = 750 natural_weapon = /obj/item/natural_weapon/goatking/unleashed elemental_weapons = list( BURN = /obj/item/natural_weapon/goatking/fire/unleashed, ELECTROCUTE = /obj/item/natural_weapon/goatking/lightning/unleashed ) default_pixel_y = 5 - break_stuff_probability = 40 stun_chance = 7 + ai = /datum/mob_controller/aggressive/goat/king/phase2 var/spellscast = 0 var/phase3 = FALSE @@ -82,62 +133,47 @@ var/special_attacks = 0 /obj/item/natural_weapon/goatking/unleashed - force = 55 + _base_attack_force = 55 /obj/item/natural_weapon/goatking/lightning/unleashed - force = 55 + _base_attack_force = 55 /obj/item/natural_weapon/goatking/fire/unleashed - force = 55 + _base_attack_force = 55 -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/Initialize() +/mob/living/simple_animal/hostile/goat/king/phase2/Initialize() . = ..() - boss_theme = GLOB.sound_player.PlayLoopingSound(src, sound_id, 'sound/music/Visager-Battle.ogg', volume = 10, range = 7, falloff = 4, prefer_mute = TRUE) + boss_theme = play_looping_sound(src, sound_id, 'sound/music/Visager-Battle.ogg', volume = 10, range = 7, falloff = 4, prefer_mute = TRUE) update_icon() -/mob/living/simple_animal/hostile/retaliate/goat/guard +/mob/living/simple_animal/hostile/goat/guard name = "honour guard" desc = "A very handsome and noble beast." - icon = 'icons/mob/simple_animal/king_of_goats.dmi' - icon_state = "goat_guard" - icon_living = "goat_guard" - icon_dead = "goat_guard_dead" - health = 125 - maxHealth = 125 + icon = 'icons/mob/simple_animal/goat_guard.dmi' + max_health = 125 natural_weapon = /obj/item/natural_weapon/goathorns /obj/item/natural_weapon/goathorns name = "horns" attack_verb = list("impaled", "stabbed") - force = 15 + _base_attack_force = 15 sharp = TRUE -/mob/living/simple_animal/hostile/retaliate/goat/guard/master +/mob/living/simple_animal/hostile/goat/guard/master name = "master of the guard" desc = "A very handsome and noble beast - the most trusted of all the king's men." - icon_state = "goat_guard_m" - icon_living = "goat_guard_m" - icon_dead = "goat_guard_m_dead" - health = 200 - maxHealth = 200 + icon = 'icons/mob/simple_animal/goat_master.dmi' + max_health = 200 natural_weapon = /obj/item/natural_weapon/goathorns - move_to_delay = 3 - -/mob/living/simple_animal/hostile/retaliate/goat/king/Retaliate() - ..() - if(stat == CONSCIOUS && prob(5)) - visible_message(SPAN_WARNING("The [src] bellows indignantly, with a judgemental gleam in his eye.")) + move_intents = list( + /decl/move_intent/walk/animal, + /decl/move_intent/run/animal + ) -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/Retaliate() +/mob/living/simple_animal/hostile/goat/king/phase2/proc/do_retaliation() set waitfor = FALSE - ..() if(spellscast < 5) - if(prob(5) && move_to_delay != 1) //speed buff - spellscast++ - visible_message(SPAN_MFAUNA("\The [src] shimmers and seems to phase in and out of reality itself!")) - move_to_delay = 1 - - else if(prob(5)) //stun move + if(prob(5)) //stun move spellscast++ visible_message(SPAN_MFAUNA("\The [src]' fleece flashes with blinding light!")) new /obj/item/grenade/flashbang/instant(src.loc) @@ -145,9 +181,9 @@ else if(prob(5)) //spawn adds spellscast++ visible_message(SPAN_MFAUNA("\The [src] summons the imperial guard to his aid, and they appear in a flash!")) - new /mob/living/simple_animal/hostile/retaliate/goat/guard/master(get_step(src,pick(GLOB.cardinal))) - new /mob/living/simple_animal/hostile/retaliate/goat/guard(get_step(src,pick(GLOB.cardinal))) - new /mob/living/simple_animal/hostile/retaliate/goat/guard(get_step(src,pick(GLOB.cardinal))) + new /mob/living/simple_animal/hostile/goat/guard/master(get_step(src,pick(global.cardinal))) + new /mob/living/simple_animal/hostile/goat/guard(get_step(src,pick(global.cardinal))) + new /mob/living/simple_animal/hostile/goat/guard(get_step(src,pick(global.cardinal))) else if(prob(5)) //EMP blast spellscast++ @@ -164,89 +200,66 @@ current_damtype = ELECTROCUTE else if(prob(5)) //earthquake spell - visible_message("\The [src]' eyes begin to glow ominously as dust and debris in the area is kicked up in a light breeze.") - stop_automation = TRUE + visible_message(SPAN_CULT_ANNOUNCE("\The [src]' eyes begin to glow ominously as dust and debris in the area is kicked up in a light breeze.")) + ai?.pause() if(do_after(src, 6 SECONDS, src)) - var/health_holder = health + var/initial_brute = get_damage(BRUTE) + var/initial_burn = get_damage(BURN) visible_message(SPAN_MFAUNA("\The [src] raises its fore-hooves and stomps them into the ground with incredible force!")) - explosion(get_step(src,pick(GLOB.cardinal)), -1, 2, 2, 3, 6) - explosion(get_step(src,pick(GLOB.cardinal)), -1, 1, 4, 4, 6) - explosion(get_step(src,pick(GLOB.cardinal)), -1, 3, 4, 3, 6) - stop_automation = FALSE + explosion(get_step(src,pick(global.cardinal)), -1, 2, 2, 3, 6) + explosion(get_step(src,pick(global.cardinal)), -1, 1, 4, 4, 6) + explosion(get_step(src,pick(global.cardinal)), -1, 3, 4, 3, 6) spellscast += 2 - if(!health < health_holder) - health = health_holder //our own magicks cannot harm us + set_damage(BRUTE, initial_brute) + set_damage(BURN, initial_burn) else - visible_message(SPAN_NOTICE("The [src] loses concentration and huffs haughtily.")) - stop_automation = FALSE + visible_message(SPAN_NOTICE("\The [src] loses concentration and huffs haughtily.")) + ai?.resume() else return -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/proc/phase3_transition() +/mob/living/simple_animal/hostile/goat/king/phase2/proc/phase3_transition() phase3 = TRUE spellscast = 0 - health = 750 + max_health = 750 + current_health = get_max_health() new /obj/item/grenade/flashbang/instant(src.loc) QDEL_NULL(boss_theme) - boss_theme = GLOB.sound_player.PlayLoopingSound(src, sound_id, 'sound/music/Visager-Miniboss_Fight.ogg', volume = 10, range = 8, falloff = 4, prefer_mute = TRUE) + boss_theme = play_looping_sound(src, sound_id, 'sound/music/Visager-Miniboss_Fight.ogg', volume = 10, range = 8, falloff = 4, prefer_mute = TRUE) stun_chance = 10 update_icon() - visible_message("\The [src]' wounds close with a flash, and when he emerges, he's even larger than before!") + visible_message(SPAN_CULT_ANNOUNCE("\The [src]' wounds close with a flash, and when he emerges, he's even larger than before!")) -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/on_update_icon() - var/matrix/M = new +/mob/living/simple_animal/hostile/goat/king/phase2/on_update_icon() + ..() if(phase3) - icon_state = "king_goat3" - icon_living = "king_goat3" - M.Scale(1.5) + icon_state += "-enraged" + set_scale(1.5) else - M.Scale(1.25) - transform = M + set_scale(1.25) default_pixel_y = 10 -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/Life() +/mob/living/simple_animal/hostile/goat/king/phase2/handle_living_non_stasis_processes() . = ..() if(!.) return FALSE if(special_attacks >= 6 && current_damtype != BRUTE) visible_message(SPAN_MFAUNA("The energy surrounding \the [src]'s horns dissipates.")) current_damtype = BRUTE - - if(health <= 150 && !phase3 && spellscast == 5) //begin phase 3, reset spell limit and heal + if(current_health <= 150 && !phase3 && spellscast == 5) //begin phase 3, reset spell limit and heal phase3_transition() -/mob/living/simple_animal/hostile/retaliate/goat/king/proc/OnDeath() - visible_message("\The [src] lets loose a terrific wail as its wounds close shut with a flash of light, and its eyes glow even brighter than before!") - new /mob/living/simple_animal/hostile/retaliate/goat/king/phase2(src.loc) - qdel(src) - -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/OnDeath() +/mob/living/simple_animal/hostile/goat/king/phase2/OnDeath() QDEL_NULL(boss_theme) if(phase3) visible_message(SPAN_MFAUNA("\The [src] shrieks as the seal on his power breaks and his wool sheds off!")) new /obj/item/towel/fleece(src.loc) -/mob/living/simple_animal/hostile/retaliate/goat/king/death() - ..() - OnDeath() - -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/Destroy() +/mob/living/simple_animal/hostile/goat/king/phase2/Destroy() QDEL_NULL(boss_theme) . = ..() -/mob/living/simple_animal/hostile/retaliate/goat/king/AttackingTarget() - . = ..() - if(isliving(target_mob)) - var/mob/living/L = target_mob - if(prob(stun_chance)) - L.Weaken(0.5) - L.confused += 1 - visible_message(SPAN_WARNING("\The [L] is bowled over by the impact of [src]'s attack!")) - -/mob/living/simple_animal/hostile/retaliate/goat/king/phase2/AttackingTarget() +/mob/living/simple_animal/hostile/goat/king/phase2/apply_attack_effects(mob/living/target) . = ..() if(current_damtype != BRUTE) special_attacks++ - -/mob/living/simple_animal/hostile/retaliate/goat/king/Process_Spacemove() - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm index 324aabd01964..06b5079874ef 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/parrot.dm @@ -24,50 +24,23 @@ #define PARROT_RETURN 32 //Flying towards its perch #define PARROT_FLEE 64 //Flying away from its attacker - -/mob/living/simple_animal/hostile/retaliate/parrot +/mob/living/simple_animal/hostile/parrot name = "parrot" desc = "A large, colourful tropical bird native to Earth, known for its strong beak and ability to mimic speech." icon = 'icons/mob/simple_animal/parrot.dmi' - icon_state = "parrot_fly" - icon_living = "parrot_fly" - icon_dead = "parrot_dead" pass_flags = PASS_FLAG_TABLE mob_size = MOB_SIZE_SMALL - - speak = list("Hi","Hello!","Cracker?") - speak_emote = list("squawks","says","yells") - emote_hear = list("squawks","bawks") - emote_see = list("flutters its wings") - + speak_emote = list("squawks","says","yells") natural_weapon = /obj/item/natural_weapon/beak - speak_chance = 1//1% (1 in 100) chance every tick; So about once per 150 seconds, assuming an average tick is 1.5s - turns_per_move = 5 - - response_help = "pets" - response_disarm = "gently moves aside" - response_harm = "swats" - stop_automated_movement = 1 + response_harm = "swats" universal_speak = TRUE + butchery_data = /decl/butchery_data/animal/bird/parrot + ai = /datum/mob_controller/aggressive/parrot - meat_type = /obj/item/chems/food/snacks/meat/chicken/game - meat_amount = 3 - skin_material = /decl/material/solid/skin/feathers - - var/parrot_state = PARROT_WANDER //Hunt for a perch when created - var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. - var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down - var/parrot_dam_zone = list(BP_CHEST, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) //For humans, select a bodypart to attack - - var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower. - var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed. - - var/list/speech_buffer = list() - var/list/available_channels = list() - - //Headset for Poly to yell at engineers :) - var/obj/item/radio/headset/ears = null - + var/parrot_state = PARROT_WANDER // Hunt for a perch when created + var/parrot_sleep_max = 25 // The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. + var/parrot_sleep_dur = 25 // Same as above, this is the var that physically counts down + var/parrot_been_shot = 0 // Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed. //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, //mobs it wants to attack or mobs that have attacked it var/atom/movable/parrot_interest = null @@ -75,16 +48,25 @@ //Parrots will generally sit on their pertch unless something catches their eye. //These vars store their preffered perch and if they dont have one, what they can use as a perch var/obj/parrot_perch = null - var/obj/desired_perches = list(/obj/machinery/constructable_frame/computerframe, /obj/structure/displaycase, \ - /obj/structure/filingcabinet, /obj/machinery/teleport, \ - /obj/machinery/computer, /obj/machinery/telecomms, \ - /obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \ - /obj/machinery/recharge_station, /obj/machinery/smartfridge, \ - /obj/machinery/suit_cycler, /obj/structure/showcase, \ - /obj/structure/fountain) + var/static/list/desired_perches = list( + /obj/structure/chair, + /obj/structure/table, + /obj/machinery/constructable_frame/computerframe, + /obj/structure/displaycase, + /obj/structure/filing_cabinet, + /obj/machinery/teleport, + /obj/machinery/computer, + /obj/machinery/nuclearbomb, + /obj/machinery/particle_accelerator, + /obj/machinery/recharge_station, + /obj/machinery/smartfridge, + /obj/machinery/suit_cycler, + /obj/structure/showcase, + /obj/structure/fountain + ) //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding. - var/obj/item/held_item = null + var/obj/item/held_item var/simple_parrot = FALSE //simple parrots ignore all the cool stuff that occupies bulk of this file var/relax_chance = 75 //we're only little and we know it @@ -92,423 +74,286 @@ var/impatience = 5 //we lose this much from relax_chance each time we calm down var/icon_set = "parrot" - -/mob/living/simple_animal/hostile/retaliate/parrot/Initialize() - . = ..() - if(!ears) - var/headset = pick(/obj/item/radio/headset/headset_sec, \ - /obj/item/radio/headset/headset_eng, \ - /obj/item/radio/headset/headset_med, \ - /obj/item/radio/headset/headset_sci, \ - /obj/item/radio/headset/headset_cargo) - ears = new headset(src) - - parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var - - verbs.Add(/mob/living/simple_animal/hostile/retaliate/parrot/proc/steal_from_ground, \ - /mob/living/simple_animal/hostile/retaliate/parrot/proc/steal_from_mob, \ - /mob/living/simple_animal/hostile/retaliate/parrot/verb/drop_held_item_player, \ - /mob/living/simple_animal/hostile/retaliate/parrot/proc/perch_player) - - update_icon() - -/mob/living/simple_animal/hostile/retaliate/parrot/death(gibbed, deathmessage, show_dead_message) - if(held_item) - held_item.dropInto(loc) - held_item = null - walk(src,0) - ..(gibbed, deathmessage, show_dead_message) - -/mob/living/simple_animal/hostile/retaliate/parrot/Stat() - . = ..() - stat("Held Item", held_item) - -/mob/living/simple_animal/hostile/retaliate/parrot/on_update_icon() - icon_state = "[icon_set]_fly" - icon_living = "[icon_set]_fly" - icon_dead = "[icon_set]_dead" - -/* - * Inventory - */ -/mob/living/simple_animal/hostile/retaliate/parrot/show_inv(mob/user) - user.set_machine(src) - if(user.stat) return - - var/dat = "
    Inventory of [name]

    " - if(ears) - dat += "
    Headset: [ears] (Remove)" - else - dat += "
    Headset: Nothing" - - show_browser(user, dat, text("window=mob[];size=325x500", name)) - onclose(user, "mob[real_name]") - return - -/mob/living/simple_animal/hostile/retaliate/parrot/DefaultTopicState() - return GLOB.physical_state - -/mob/living/simple_animal/hostile/retaliate/parrot/OnTopic(mob/user, href_list) - //Is the user's mob type able to do this? - if(ishuman(user) || issmall(user) || isrobot(user)) - - //Removing from inventory - if(href_list["remove_inv"]) - var/remove_from = href_list["remove_inv"] - switch(remove_from) - if("ears") - if(ears) - if(available_channels.len) - src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - else - src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - ears.dropInto(loc) - ears = null - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) - else - to_chat(user, "There is nothing to remove from its [remove_from].") - return TOPIC_HANDLED - - //Adding things to inventory - if(href_list["add_inv"]) - var/add_to = href_list["add_inv"] - if(!user.get_active_hand()) - to_chat(user, "You have nothing in your hand to put on its [add_to].") - return TOPIC_HANDLED - switch(add_to) - if("ears") - if(ears) - to_chat(user, "It's already wearing something.") - return TOPIC_HANDLED - else - var/obj/item/item_to_add = usr.get_active_hand() - if(!item_to_add) - return TOPIC_HANDLED - - if( !istype(item_to_add, /obj/item/radio/headset) ) - to_chat(user, "This object won't fit.") - return TOPIC_HANDLED - if(!user.unEquip(item_to_add, src)) - return TOPIC_HANDLED - var/obj/item/radio/headset/headset_to_add = item_to_add - - src.ears = headset_to_add - to_chat(user, "You fit the headset onto [src].") - - clearlist(available_channels) - for(var/ch in headset_to_add.channels) - switch(ch) - if("Engineering") - available_channels.Add(":e") - if("Command") - available_channels.Add(":c") - if("Security") - available_channels.Add(":s") - if("Science") - available_channels.Add(":n") - if("Medical") - available_channels.Add(":m") - if("Mining") - available_channels.Add(":d") - if("Cargo") - available_channels.Add(":q") - return TOPIC_HANDLED - - return ..() - +/datum/mob_controller/aggressive/parrot + turns_per_wander = 10 + emote_speech = list("Hi","Hello!","Cracker?") + emote_hear = list("squawks","bawks") + emote_see = list("flutters its wings") + do_wander = FALSE + speak_chance = 0.5 + only_attack_enemies = TRUE + expected_type = /mob/living/simple_animal/hostile/parrot /* - * Attack responces + * AI - Not really intelligent, but I'm calling it AI anyway. */ -//Humans, monkeys, aliens -/mob/living/simple_animal/hostile/retaliate/parrot/attack_hand(mob/living/carbon/M) - ..() - if(client) - return +/datum/mob_controller/aggressive/parrot/do_process() - if(simple_parrot) //all the real stuff gets handled in /hostile/retaliate + if(!(. = ..()) || body.stat || !istype(body, /mob/living/simple_animal/hostile/parrot)) return - if(!stat && M.a_intent == I_HURT) - icon_state = "[icon_set]_fly" //It is going to be flying regardless of whether it flees or attacks - - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - parrot_interest = M - parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction.. - - if(M.health < 50) //Weakened mob? Fight back! - parrot_state |= PARROT_ATTACK - else - parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell! - drop_held_item(0) - return - -//Mobs with objects -/mob/living/simple_animal/hostile/retaliate/parrot/attackby(var/obj/item/O, var/mob/user) - ..() - if(!stat && !client && !istype(O, /obj/item/stack/medical)) - if(O.force) - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - parrot_interest = user - parrot_state = PARROT_SWOOP | PARROT_FLEE - icon_state = "[icon_set]_fly" - drop_held_item(0) - return - -//Bullets -/mob/living/simple_animal/hostile/retaliate/parrot/bullet_act(var/obj/item/projectile/Proj) - ..() - if(!stat && !client) - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - parrot_interest = null - parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL! - parrot_been_shot += 5 - icon_state = "[icon_set]_fly" - drop_held_item(0) - return - - -/* - * AI - Not really intelligent, but I'm calling it AI anyway. - */ - -// This has the potential to sleep in various emote and damage procs; shoving it all into here for safety. -/mob/living/simple_animal/hostile/retaliate/parrot/do_delayed_life_action() - ..() - if(!isturf(src.loc) || stat) + var/mob/living/simple_animal/hostile/parrot/parrot = body + if(!isturf(parrot.loc)) return // Let's not bother in nullspace - if(enemies.len && prob(relax_chance)) - give_up() - if(simple_parrot) - return FALSE - -//-----SPEECH - /* Parrot speech mimickry! - Phrases that the parrot hears in mob/living/say() get added to speach_buffer. - Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. - Then it clears the buffer to make sure they dont magically remember something from hours ago. */ - if(speech_buffer.len && prob(10)) - if(speak.len) - speak.Remove(pick(speak)) - - speak.Add(pick(speech_buffer)) - clearlist(speech_buffer) + if(LAZYLEN(get_enemies()) && prob(parrot.relax_chance)) + parrot.give_up() + if(parrot.simple_parrot) + return FALSE //-----SLEEPING - if(parrot_state == PARROT_PERCH) - if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us - if(parrot_perch in view(src)) - parrot_state = PARROT_SWOOP | PARROT_RETURN - icon_state = "[icon_set]_fly" - return + if(parrot.parrot_state == PARROT_PERCH) + if(parrot.parrot_perch && parrot.parrot_perch.loc != parrot.loc) //Make sure someone hasnt moved our perch on us + if(parrot.parrot_perch in view(parrot)) + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN else - parrot_state = PARROT_WANDER - icon_state = "[icon_set]_fly" - return + parrot.parrot_state = PARROT_WANDER + parrot.update_icon() + return - if(--parrot_sleep_dur) //Zzz + if(--parrot.parrot_sleep_dur) //Zzz return else //This way we only call the stuff below once every [sleep_max] ticks. - parrot_sleep_dur = parrot_sleep_max - - //Cycle through message modes for the headset - if(speak.len) - var/list/newspeak = list() - - if(available_channels.len && src.ears) - for(var/possible_phrase in speak) - - //50/50 chance to not use the radio at all - var/useradio = 0 - if(prob(50)) - useradio = 1 - - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[useradio?pick(available_channels):""] [copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - else - possible_phrase = "[useradio?pick(available_channels):""] [possible_phrase]" - - newspeak.Add(possible_phrase) - - else //If we have no headset or channels to use, dont try to use any! - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - newspeak.Add(possible_phrase) - speak = newspeak - + parrot.parrot_sleep_dur = parrot.parrot_sleep_max //Search for item to steal - parrot_interest = search_for_item() - if(parrot_interest) - visible_emote("looks in [parrot_interest]'s direction and takes flight") - parrot_state = PARROT_SWOOP | PARROT_STEAL - icon_state = "[icon_set]_fly" - return + parrot.parrot_interest = parrot.search_for_item() + if(parrot.parrot_interest) + parrot.visible_emote("looks in [parrot.parrot_interest]'s direction and takes flight") + parrot.parrot_state = PARROT_SWOOP | PARROT_STEAL + parrot.update_icon() //-----WANDERING - This is basically a 'I dont know what to do yet' state - else if(parrot_state == PARROT_WANDER) + else if(parrot.parrot_state == PARROT_WANDER) //Stop movement, we'll set it later - walk(src, 0) - parrot_interest = null + parrot.stop_automove() + parrot.parrot_interest = null //Wander around aimlessly. This will help keep the loops from searches down //and possibly move the mob into a new are in view of something they can use if(prob(90)) - SelfMove(pick(GLOB.cardinal)) + parrot.SelfMove(pick(global.cardinal)) return - if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do. - var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item + if(!parrot.held_item && !parrot.parrot_perch) //If we've got nothing to do, look for something to do. + var/atom/movable/AM = parrot.search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item if(AM) - if((isitem(AM) && can_pick_up(AM)) || isliving(AM)) //If stealable item - parrot_interest = AM - visible_emote("turns and flies towards [parrot_interest]") - parrot_state = PARROT_SWOOP | PARROT_STEAL + if((isitem(AM) && parrot.can_pick_up(AM)) || isliving(AM)) //If stealable item + parrot.parrot_interest = AM + parrot.visible_emote("turns and flies towards [parrot.parrot_interest]") + parrot.parrot_state = PARROT_SWOOP | PARROT_STEAL return else //Else it's a perch - parrot_perch = AM - parrot_state = PARROT_SWOOP | PARROT_RETURN + parrot.parrot_perch = AM + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN return return - if(parrot_interest && (parrot_interest in view(src))) - parrot_state = PARROT_SWOOP | PARROT_STEAL + if(parrot.parrot_interest && (parrot.parrot_interest in view(parrot))) + parrot.parrot_state = PARROT_SWOOP | PARROT_STEAL return - if(parrot_perch && (parrot_perch in view(src))) - parrot_state = PARROT_SWOOP | PARROT_RETURN + if(parrot.parrot_perch && (parrot.parrot_perch in view(parrot))) + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN return else //Have an item but no perch? Find one! - parrot_perch = search_for_perch() - if(parrot_perch) - parrot_state = PARROT_SWOOP | PARROT_RETURN + parrot.parrot_perch = parrot.search_for_perch() + if(parrot.parrot_perch) + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN return //-----STEALING - else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL)) - walk(src,0) - if(!parrot_interest || held_item) - parrot_state = PARROT_SWOOP | PARROT_RETURN + else if(parrot.parrot_state == (PARROT_SWOOP | PARROT_STEAL)) + parrot.stop_automove() + if(!parrot.parrot_interest || parrot.held_item) + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN return - if(!(parrot_interest in view(src))) - parrot_state = PARROT_SWOOP | PARROT_RETURN + if(!(parrot.parrot_interest in view(parrot))) + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN return - if(in_range(src, parrot_interest)) + if(in_range(parrot, parrot.parrot_interest)) - if(isliving(parrot_interest)) - steal_from_mob() + if(isliving(parrot.parrot_interest)) + parrot.steal_from_mob() - if(isitem(parrot_interest) && can_pick_up(parrot_interest))//This should ensure that we only grab the item we want, and make sure it's not already collected on our perch, a correct size, and not bolted to the floor - if(!parrot_perch || parrot_interest.loc != parrot_perch.loc) - held_item = parrot_interest - parrot_interest.forceMove(src) - visible_message("[src] grabs the [held_item]!", "You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") + if(isitem(parrot.parrot_interest) && parrot.can_pick_up(parrot.parrot_interest))//This should ensure that we only grab the item we want, and make sure it's not already collected on our perch, a correct size, and not bolted to the floor + if(!parrot.parrot_perch || parrot.parrot_interest.loc != parrot.parrot_perch.loc) + parrot.held_item = parrot.parrot_interest + parrot.parrot_interest.forceMove(parrot) + parrot.visible_message("[parrot] grabs the [parrot.held_item]!", "You grab the [parrot.held_item]!", "You hear the sounds of wings flapping furiously.") - parrot_interest = null - parrot_state = PARROT_SWOOP | PARROT_RETURN + parrot.parrot_interest = null + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN return - walk_to(src, parrot_interest, 1, parrot_speed) + parrot.set_moving_slowly() + parrot.start_automove(parrot.parrot_interest) return //-----RETURNING TO PERCH - else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN)) - walk(src, 0) - if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else. - parrot_perch = null - parrot_state = PARROT_WANDER + else if(parrot.parrot_state == (PARROT_SWOOP | PARROT_RETURN)) + parrot.stop_automove() + if(!parrot.parrot_perch || !isturf(parrot.parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else. + parrot.parrot_perch = null + parrot.parrot_state = PARROT_WANDER return - if(in_range(src, parrot_perch)) - forceMove(parrot_perch.loc) - drop_held_item() - parrot_state = PARROT_PERCH - icon_state = "[icon_set]_sit" + if(in_range(parrot, parrot.parrot_perch)) + parrot.forceMove(parrot.parrot_perch.loc) + parrot.drop_held_item() + parrot.parrot_state = PARROT_PERCH + parrot.update_icon() return - walk_to(src, parrot_perch, 1, parrot_speed) + parrot.set_moving_slowly() + parrot.start_automove(parrot.parrot_perch) return //-----FLEEING - else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE)) - walk(src,0) - give_up() - if(!parrot_interest || !isliving(parrot_interest)) //Sanity - parrot_state = PARROT_WANDER - - walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot) - parrot_been_shot-- + else if(parrot.parrot_state == (PARROT_SWOOP | PARROT_FLEE)) + parrot.stop_automove() + parrot.give_up() + if(!parrot.parrot_interest || !isliving(parrot.parrot_interest)) //Sanity + parrot.parrot_state = PARROT_WANDER + + var/static/datum/automove_metadata/_parrot_flee_automove_metadata = new( + _move_delay = 2, + _acceptable_distance = 7, + _avoid_target = TRUE + ) + parrot.set_moving_quickly() + parrot.start_automove(parrot.parrot_interest, metadata = _parrot_flee_automove_metadata) + parrot.parrot_been_shot-- return //-----ATTACKING - else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK)) + else if(parrot.parrot_state == (PARROT_SWOOP | PARROT_ATTACK)) //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander - if(!parrot_interest || !isliving(parrot_interest)) - parrot_interest = null - parrot_state = PARROT_WANDER + if(!parrot.parrot_interest || !isliving(parrot.parrot_interest)) + parrot.parrot_interest = null + parrot.parrot_state = PARROT_WANDER return - var/mob/living/L = parrot_interest + var/mob/living/L = parrot.parrot_interest //If the mob is close enough to interact with - if(in_range(src, parrot_interest)) + if(in_range(parrot, parrot.parrot_interest)) //If the mob we've been chasing/attacking dies or falls into crit, check for loot! if(L.stat) - parrot_interest = null - if(!held_item) - held_item = steal_from_ground() - if(!held_item) - held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances. - if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home - parrot_state = PARROT_SWOOP | PARROT_RETURN + parrot.parrot_interest = null + if(!parrot.held_item) + parrot.held_item = parrot.steal_from_ground() + if(!parrot.held_item) + parrot.held_item = parrot.steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances. + if(parrot.parrot_perch in view(parrot)) //If we have a home nearby, go to it, otherwise find a new home + parrot.parrot_state = PARROT_SWOOP | PARROT_RETURN else - parrot_state = PARROT_WANDER + parrot.parrot_state = PARROT_WANDER return //Time for the hurt to begin! - L.attackby(get_natural_weapon(), src) + parrot.UnarmedAttack(L, parrot.Adjacent(L)) return //Otherwise, fly towards the mob! else - walk_to(src, parrot_interest, 1, parrot_speed) + parrot.set_moving_quickly() + parrot.start_automove(parrot.parrot_interest) return //-----STATE MISHAP else //This should not happen. If it does lets reset everything and try again - walk(src,0) - parrot_interest = null - parrot_perch = null - drop_held_item() - parrot_state = PARROT_WANDER + parrot.stop_automove() + parrot.parrot_interest = null + parrot.parrot_perch = null + parrot.drop_held_item() + parrot.parrot_state = PARROT_WANDER return +/mob/living/simple_animal/hostile/parrot/Initialize() + . = ..() + + parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var + + verbs |= /mob/living/simple_animal/hostile/parrot/proc/steal_from_ground + verbs |= /mob/living/simple_animal/hostile/parrot/proc/steal_from_mob + verbs |= /mob/living/simple_animal/hostile/parrot/verb/drop_held_item_player + verbs |= /mob/living/simple_animal/hostile/parrot/proc/perch_player + + update_icon() + +/mob/living/simple_animal/hostile/parrot/Destroy() + parrot_interest = null + parrot_perch = null + if(held_item) + held_item.dropInto(loc) + held_item = null + return ..() + +/mob/living/simple_animal/hostile/parrot/death(gibbed) + var/oldloc = loc + . = ..() + if(. && held_item) + if(oldloc) + held_item.dropInto(oldloc) + held_item = null + else + QDEL_NULL(held_item) + +/mob/living/simple_animal/hostile/parrot/Stat() + . = ..() + stat("Held Item", held_item) + /* - * Procs + * Attack responces */ +//Humans, monkeys, aliens +/mob/living/simple_animal/hostile/parrot/default_hurt_interaction(mob/user) + . = ..() + if(!client && !simple_parrot && !stat) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + parrot_interest = user + parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction.. + if(isliving(user)) + var/mob/living/M = user + if(M.current_health < 50) //Weakened mob? Fight back! + parrot_state |= PARROT_ATTACK + return + parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell! + drop_held_item(0) + update_icon() + +//Mobs with objects +/mob/living/simple_animal/hostile/parrot/attackby(var/obj/item/used_item, var/mob/user) + . = ..() + if(!stat && !client && !istype(used_item, /obj/item/stack/medical) && used_item.expend_attack_force(user)) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + parrot_interest = user + parrot_state = PARROT_SWOOP | PARROT_FLEE + drop_held_item(0) + update_icon() -/mob/living/simple_animal/hostile/retaliate/parrot/movement_delay() - if(client && stat == CONSCIOUS && parrot_state != "parrot_fly") - icon_state = "[icon_set]_fly" +//Bullets +/mob/living/simple_animal/hostile/parrot/bullet_act(var/obj/item/projectile/Proj) ..() + if(!stat && !client) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + parrot_interest = null + parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL! + parrot_been_shot += 5 + drop_held_item(0) + update_icon() -/mob/living/simple_animal/hostile/retaliate/parrot/proc/search_for_item() +/mob/living/simple_animal/hostile/parrot/proc/search_for_item() for(var/atom/movable/AM in view(src)) //Skip items we already stole or are wearing or are too big if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) @@ -517,21 +362,23 @@ if(isitem(AM) && can_pick_up(AM)) return AM - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if((C.l_hand && can_pick_up(C.l_hand)) || (C.r_hand && can_pick_up(C.r_hand))) - return C - return null + if(ismob(AM)) + var/mob/M = AM + for(var/hand_slot in M.get_held_item_slots()) + var/datum/inventory_slot/inv_slot = M.get_inventory_slot_datum(hand_slot) + var/held = inv_slot.get_equipped_item() + if(held && can_pick_up(held)) + return M -/mob/living/simple_animal/hostile/retaliate/parrot/proc/search_for_perch() - for(var/obj/O in view(src)) +/mob/living/simple_animal/hostile/parrot/proc/search_for_perch() + for(var/obj/thing in view(src)) for(var/path in desired_perches) - if(istype(O, path)) - return O + if(istype(thing, path)) + return thing return null //This proc was made to save on doing two 'in view' loops seperatly -/mob/living/simple_animal/hostile/retaliate/parrot/proc/search_for_perch_and_item() +/mob/living/simple_animal/hostile/parrot/proc/search_for_perch_and_item() for(var/atom/movable/AM in view(src)) for(var/perch_path in desired_perches) if(istype(AM, perch_path)) @@ -544,22 +391,26 @@ if(isitem(AM) && can_pick_up(AM)) return AM - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if((C.l_hand && can_pick_up(C.l_hand)) || (C.r_hand && can_pick_up(C.r_hand))) - return C - return null + if(ismob(AM)) + var/mob/M = AM + for(var/hand_slot in M.get_held_item_slots()) + var/datum/inventory_slot/inv_slot = M.get_inventory_slot_datum(hand_slot) + var/held = inv_slot?.get_equipped_item() + if(held && can_pick_up(held)) + return M -/mob/living/simple_animal/hostile/retaliate/parrot/proc/give_up() - enemies = list() - LoseTarget() - visible_message("\The [src] seems to calm down.") +/mob/living/simple_animal/hostile/parrot/proc/give_up() + if(!istype(ai) || !LAZYLEN(ai.get_enemies())) + return + ai.clear_enemies() + ai.lose_target() + visible_message(SPAN_NOTICE("\The [src] seems to calm down.")) relax_chance -= impatience /* * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots. */ -/mob/living/simple_animal/hostile/retaliate/parrot/proc/steal_from_ground() +/mob/living/simple_animal/hostile/parrot/proc/steal_from_ground() set name = "Steal from ground" set category = "Parrot" set desc = "Grabs a nearby item." @@ -587,7 +438,7 @@ to_chat(src, "There is nothing of interest to take.") return 0 -/mob/living/simple_animal/hostile/retaliate/parrot/proc/steal_from_mob() +/mob/living/simple_animal/hostile/parrot/proc/steal_from_mob() set name = "Steal from mob" set category = "Parrot" set desc = "Steals an item right out of a person's hand!" @@ -600,23 +451,20 @@ return 1 var/obj/item/stolen_item = null - - for(var/mob/living/carbon/C in view(1,src)) - if(C.l_hand && can_pick_up(C.l_hand)) - stolen_item = C.l_hand - - if(C.r_hand && can_pick_up(C.r_hand)) - stolen_item = C.r_hand - - if(stolen_item && C.unEquip(stolen_item, src)) + for(var/mob/living/target in view(1,src)) + for(var/obj/item/thing in target.get_held_items()) + if(can_pick_up(thing)) + stolen_item = thing + break + if(stolen_item && target.try_unequip(stolen_item, src)) held_item = stolen_item - visible_message("[src] grabs the [held_item] out of [C]'s hand!", "You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.") + visible_message("[src] grabs the [held_item] out of [target]'s hand!", "You snag the [held_item] out of [target]'s hand!", "You hear the sounds of wings flapping furiously.") return held_item to_chat(src, "There is nothing of interest to take.") return 0 -/mob/living/simple_animal/hostile/retaliate/parrot/verb/drop_held_item_player() +/mob/living/simple_animal/hostile/parrot/verb/drop_held_item_player() set name = "Drop held item" set category = "Parrot" set desc = "Drop the item you're holding." @@ -628,7 +476,7 @@ return -/mob/living/simple_animal/hostile/retaliate/parrot/proc/drop_held_item(var/drop_gently = 1) +/mob/living/simple_animal/hostile/parrot/proc/drop_held_item(var/drop_gently = 1) set name = "Drop held item" set category = "Parrot" set desc = "Drop the item you're holding." @@ -655,7 +503,7 @@ held_item = null return 1 -/mob/living/simple_animal/hostile/retaliate/parrot/proc/perch_player() +/mob/living/simple_animal/hostile/parrot/proc/perch_player() set name = "Sit" set category = "Parrot" set desc = "Sit on a nice comfy perch." @@ -663,80 +511,24 @@ if(stat || !client) return - if(icon_state == "[icon_set]_fly") - for(var/atom/movable/AM in view(src,1)) - for(var/perch_path in desired_perches) - if(istype(AM, perch_path)) - forceMove(AM.loc) - icon_state = "[icon_set]_sit" - return - to_chat(src, "There is no perch nearby to sit on.") - return + for(var/atom/movable/AM in view(src,1)) + for(var/perch_path in desired_perches) + if(istype(AM, perch_path)) + forceMove(AM.loc) + update_icon() + return + to_chat(src, SPAN_WARNING("There is no perch nearby to sit on.")) + +/mob/living/simple_animal/hostile/parrot/proc/can_pick_up(obj/item/I) + . = (Adjacent(I) && I.w_class <= parrot_isize && !I.anchored) /* * Sub-types */ -/mob/living/simple_animal/hostile/retaliate/parrot/Poly +/mob/living/simple_animal/hostile/parrot/Poly name = "Poly" desc = "Poly the Parrot. An expert on quantum cracker theory." - speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE") - -/mob/living/simple_animal/hostile/retaliate/parrot/Poly/Initialize() - ears = new /obj/item/radio/headset/headset_eng(src) - available_channels = list(":e") - . = ..() - -/mob/living/simple_animal/hostile/retaliate/parrot/say(var/message) - - if(stat) - return + ai = /datum/mob_controller/aggressive/parrot/poly - var/verb = "says" - if(speak_emote.len) - verb = pick(speak_emote) - - - var/message_mode="" - if(copytext(message,1,2) == get_prefix_key(/decl/prefix/radio_main_channel)) - message_mode = "headset" - message = copytext(message,2) - - if(length(message) >= 2) - var/channel_prefix = copytext(message, 1 ,3) - message_mode = department_radio_keys[channel_prefix] - - if(copytext(message,1,2) == get_prefix_key(/decl/prefix/radio_channel_selection)) - var/positioncut = 3 - message = trim(copytext(message,positioncut)) - - message = capitalize(trim_left(message)) - - if(message_mode) - if(message_mode in radiochannels) - if(ears && istype(ears,/obj/item/radio)) - ears.talk_into(src,sanitize(message), message_mode, verb, null) - - - ..(message) - - -/mob/living/simple_animal/hostile/retaliate/parrot/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) - if(prob(50)) - parrot_hear(message) - ..() - - - -/mob/living/simple_animal/hostile/retaliate/parrot/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) - if(prob(50) && available_channels.len) - parrot_hear("[pick(available_channels)] [message]") - ..() - - -/mob/living/simple_animal/hostile/retaliate/parrot/proc/parrot_hear(var/message="") - if(!message || stat) - return - speech_buffer.Add(message) - -/mob/living/simple_animal/hostile/retaliate/parrot/proc/can_pick_up(obj/item/I) - . = (Adjacent(I) && I.w_class <= parrot_isize && !I.anchored) +/datum/mob_controller/aggressive/parrot/poly + emote_speech = list("Poly wanna cracker!", "Check the singlo, you chucklefucks!","Wire the solars, you lazy bums!","WHO TOOK THE DAMN HARDSUITS?","OH GOD ITS FREE CALL THE SHUTTLE!") diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm deleted file mode 100644 index 67cac473160f..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ /dev/null @@ -1,41 +0,0 @@ -/mob/living/simple_animal/hostile/retaliate - var/list/enemies = list() - -/mob/living/simple_animal/hostile/retaliate/Found(var/atom/A) - if(isliving(A)) - var/mob/living/L = A - if(!L.stat) - stance = HOSTILE_STANCE_ATTACK - return L - else - enemies -= weakref(L) - -/mob/living/simple_animal/hostile/retaliate/ListTargets() - . = list() - if(!enemies.len) - return - var/list/see = ..() - for(var/weakref/W in enemies) // Remove all entries that aren't in enemies - var/mob/M = W.resolve() - if(M in see) - . += M - -/mob/living/simple_animal/hostile/retaliate/proc/Retaliate() - var/list/around = view(src, 7) - - for(var/atom/movable/A in around) - if(A == src) - continue - if(isliving(A)) - var/mob/living/M = A - if(!attack_same && M.faction != faction) - enemies |= weakref(M) - - for(var/mob/living/simple_animal/hostile/retaliate/H in around) - if(!attack_same && !H.attack_same && H.faction == faction) - H.enemies |= enemies - return 0 - -/mob/living/simple_animal/hostile/retaliate/adjustBruteLoss(var/damage) - ..(damage) - Retaliate() diff --git a/code/modules/mob/living/simple_animal/hostile/revenant.dm b/code/modules/mob/living/simple_animal/hostile/revenant.dm new file mode 100644 index 000000000000..6e1c10aa91ce --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/revenant.dm @@ -0,0 +1,47 @@ +/mob/living/simple_animal/hostile/revenant + name = "revenant" + desc = "A flickering humanoid shadow that exudes a palpable sense of mance." + icon = 'icons/mob/simple_animal/revenant.dmi' + response_help_1p = "You wave your hand through $TARGET$." + response_help_3p = "$USER$ waves $USER_THEIR$ hand through $TARGET$." + max_health = 80 + gene_damage = -1 + ai = /datum/mob_controller/aggressive/revenant + harm_intent_damage = 10 + natural_weapon = /obj/item/natural_weapon/revenant + min_gas = null + max_gas = null + minbodytemp = 0 + skip_spacemove = TRUE + faction = "revenants" + supernatural = TRUE + +/datum/mob_controller/aggressive/revenant + speak_chance = 0 + turns_per_wander = 10 + +/datum/mob_controller/aggressive/revenant/find_target() + . = ..() + if(.) + body.custom_emote(AUDIBLE_MESSAGE, "wails at [.]") + +/obj/item/natural_weapon/revenant + name = "shadow tendril" + attack_verb = "gripped" + hitsound = 'sound/hallucinations/growl1.ogg' + atom_damage_type = BURN + _base_attack_force = 15 + +/mob/living/simple_animal/hostile/revenant/apply_attack_effects(mob/living/target) + . = ..() + if(prob(12)) + SET_STATUS_MAX(target, STAT_WEAK, 3) + target.visible_message(SPAN_DANGER("\The [src] knocks down \the [target]!")) + +/obj/item/ectoplasm + name = "ectoplasm" + desc = "Spooky." + gender = PLURAL + icon = 'icons/obj/items/ectoplasm.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/liquid/drink/compote \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm deleted file mode 100644 index 180ca275b174..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ /dev/null @@ -1,43 +0,0 @@ -/mob/living/simple_animal/hostile/russian - name = "russian" - desc = "For the Motherland!" - icon_state = "russianmelee" - icon_living = "russianmelee" - icon_dead = "russianmelee_dead" - icon_gib = "syndicate_gib" - speak_chance = 0 - turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" - speed = 4 - stop_automated_movement_when_pulled = 0 - maxHealth = 100 - health = 100 - harm_intent_damage = 5 - can_escape = TRUE - a_intent = I_HURT - var/corpse = /obj/effect/landmark/corpse/russian - var/dropped_weapon = /obj/item/knife/combat - natural_weapon = /obj/item/knife/combat - unsuitable_atmos_damage = 15 - faction = "russian" - status_flags = CANPUSH - -/mob/living/simple_animal/hostile/russian/ranged - icon_state = "russianranged" - icon_living = "russianranged" - corpse = /obj/effect/landmark/corpse/russian/ranged - dropped_weapon = /obj/item/gun/projectile/revolver - ranged = 1 - projectiletype = /obj/item/projectile/bullet - projectilesound = 'sound/weapons/gunshot/gunshot2.ogg' - casingtype = /obj/item/ammo_casing/pistol/magnum - -/mob/living/simple_animal/hostile/russian/death(gibbed, deathmessage, show_dead_message) - ..(gibbed, deathmessage, show_dead_message) - if(corpse) - new corpse (src.loc) - if(dropped_weapon) - new dropped_weapon (src.loc) - qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/shark.dm b/code/modules/mob/living/simple_animal/hostile/shark.dm new file mode 100644 index 000000000000..b39c15e7a0c7 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/shark.dm @@ -0,0 +1,58 @@ +/mob/living/simple_animal/hostile/carp/shark // generally stronger version of a carp that doesn't die from a mean look. Fance new sprites included, credits to F-Tang Steve + name = "cosmoshark" + desc = "Enormous creature that resembles a shark with magenta glowing lines along its body and set of long deep-purple teeth." + icon = 'maps/away/errant_pisces/icons/cosmoshark.dmi' + butchery_data = /decl/butchery_data/animal/fish/space_carp/shark + max_health = 100 + natural_weapon = /obj/item/natural_weapon/bite/strong + faction = "shark" + ai = /datum/mob_controller/aggressive/carp/shark + +/datum/mob_controller/aggressive/carp/shark + break_stuff_probability = 35 + turns_per_wander = 10 + +/mob/living/simple_animal/hostile/carp/shark/carp_randomify() + return + +/mob/living/simple_animal/hostile/carp/shark/death(gibbed) + . = ..() + if(. && !gibbed) + var/datum/gas_mixture/environment = loc.return_air() + if (environment) + var/datum/gas_mixture/sharkmaw_chlorine = new + sharkmaw_chlorine.adjust_gas(/decl/material/gas/chlorine, 10) + environment.merge(sharkmaw_chlorine) + visible_message(SPAN_WARNING("\The [src]'s body releases some gas from the gills with a quiet fizz!")) + +/mob/living/simple_animal/hostile/carp/shark/apply_attack_effects(mob/living/target) + . =..() + var/mob/living/L = target + if(istype(L)) + if(prob(25))//if one is unlucky enough, they get tackled few tiles away + L.visible_message("\The [src] tackles [L]!") + var/tackle_length = rand(3,5) + for (var/i = 1 to tackle_length) + var/turf/T = get_step(L.loc, dir)//on a first step of tackling standing mob would block movement so let's check if there's something behind it. Works for consequent moves too + if (T.density || LinkBlocked(L.loc, T) || TurfBlockedNonWindow(T) || DirBlocked(T, global.flip_dir[dir])) + break + sleep(2) + forceMove(T)//maybe there's better manner then just forceMove() them + L.forceMove(T) + visible_message("\The [src] releases [L].") + +/decl/butchery_data/animal/fish/space_carp/shark + meat_type = /obj/item/food/butchery/meat/fish/shark + must_use_hook = TRUE + +/obj/item/food/butchery/meat/fish/shark + desc = "A fillet of cosmoshark meat." + meat_name = "cosmoshark" + color = "#cecece" + center_of_mass = @'{"x":17,"y":13}' + bitesize = 8 + +/obj/item/food/butchery/meat/fish/shark/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/psychoactives, 1) + add_to_reagents(/decl/material/gas/chlorine, 1) diff --git a/code/modules/mob/living/simple_animal/hostile/slug.dm b/code/modules/mob/living/simple_animal/hostile/slug.dm new file mode 100644 index 000000000000..bd2d79349b23 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/slug.dm @@ -0,0 +1,81 @@ +// A SLUG: Small, little HP, poisonous. +/mob/living/simple_animal/hostile/slug + name = "slug" + desc = "A vicious, viscous little creature, it has a mouth of too many teeth and a penchant for blood." + icon = 'icons/mob/simple_animal/slug.dmi' + response_harm = "stomps on" + max_health = 15 + move_intents = list( + /decl/move_intent/walk/animal_fast, + /decl/move_intent/run/animal_fast + ) + density = TRUE + min_gas = null + mob_size = MOB_SIZE_MINISCULE + pass_flags = PASS_FLAG_TABLE + natural_weapon = /obj/item/natural_weapon/bite + holder_type = /obj/item/holder/slug + ai = /datum/mob_controller/aggressive/slug + faction = "Hostile Fauna" + base_movement_delay = 0 + +/datum/mob_controller/aggressive/slug + try_destroy_surroundings = FALSE + can_escape_buckles = TRUE + +/datum/mob_controller/aggressive/slug/valid_target(atom/A) + . = ..() + if(.) + if(!ismob(A)) + return FALSE + var/mob/living/simple_animal/hostile/slug/slug = body + if(slug.check_friendly_species(A)) + return FALSE + +/mob/living/simple_animal/hostile/slug/proc/check_friendly_species(var/mob/living/M) + return istype(M) && M.faction == faction + +/mob/living/simple_animal/hostile/slug/get_scooped(mob/living/target, mob/living/initiator, silent = FALSE) + if(target == initiator || check_friendly_species(initiator)) + return ..() + if(!silent) + to_chat(initiator, SPAN_WARNING("\The [src] wriggles out of your hands before you can pick it up!")) + +/mob/living/simple_animal/hostile/slug/proc/attach(var/mob/living/human/H) + var/obj/item/clothing/suit/space/S = H.get_covering_equipped_item_by_zone(BP_CHEST) + if(istype(S) && !length(S.breaches)) + S.create_breaches(BRUTE, 20) + if(!length(S.breaches)) //unable to make a hole + return + var/obj/item/organ/external/chest = GET_EXTERNAL_ORGAN(H, BP_CHEST) + var/obj/item/holder/slug/holder = new(get_turf(src)) + src.forceMove(holder) + chest.embed_in_organ(holder, FALSE, "\The [src] latches itself onto \the [H]!") + holder.sync(src) + +/mob/living/simple_animal/hostile/slug/apply_attack_effects(mob/living/target) + . = ..() + if(ishuman(target)) + var/mob/living/human/H = target + if(prob(H.get_damage(BRUTE)/2)) + attach(H) + +/mob/living/simple_animal/hostile/slug/handle_regular_status_updates() + . = ..() + if(. && istype(src.loc, /obj/item/holder) && isliving(src.loc.loc)) //We in somebody + var/mob/living/L = src.loc.loc + if(src.loc in L.get_visible_implants(0)) + if(prob(1)) + to_chat(L, "You feel strange as \the [src] pulses...") + var/datum/reagents/R = L.reagents + R.add_reagent(/decl/material/liquid/presyncopics, 0.5) + +/obj/item/holder/slug/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + var/mob/living/simple_animal/hostile/slug/V = contents[1] + if(!V.stat && ishuman(target)) + var/mob/living/human/H = target + if(do_mob(user, H, 30)) + V.attach(H) + qdel(src) + return TRUE + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm new file mode 100644 index 000000000000..c2636dcf8a3a --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm @@ -0,0 +1,72 @@ +/mob/living/simple_animal/hostile/space_dragon + name = "space dragon" + desc = "A large reptilian creature, with vicious looking claws." + icon = 'icons/mob/simple_animal/space_dragon.dmi' + mob_size = MOB_SIZE_LARGE + speak_emote = list("hisses") + faction = "space dragons" + butchery_data = /decl/butchery_data/animal/reptile/space_dragon + bleed_colour = COLOR_VIOLET + max_health = 200 + natural_weapon = /obj/item/natural_weapon/claws/space_dragon + natural_armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_ENERGY = ARMOR_ENERGY_SHIELDED, + ARMOR_LASER = ARMOR_LASER_HEAVY, + ARMOR_BOMB = ARMOR_BOMB_SHIELDED + ) + ability_cooldown = 80 SECONDS + ai = /datum/mob_controller/aggressive/space_dragon + ability_handlers = list(/datum/ability_handler/predator) + + var/obj/item/whip/tail/tailwhip + var/empowered_attack = FALSE + var/gas_spent = FALSE + +/datum/mob_controller/aggressive/space_dragon + emote_hear = list("clicks") + break_stuff_probability = 15 + emote_see = list("flaps its wings idly") + +/mob/living/simple_animal/hostile/space_dragon/get_door_pry_time() + return 4 SECONDS + +/mob/living/simple_animal/hostile/space_dragon/lava_act(datum/gas_mixture/air, temperature, pressure) + return + +/mob/living/simple_animal/hostile/space_dragon/apply_attack_effects(mob/living/target) + . = ..() + if(empowered_attack) + depower() + return + if(can_act() && !is_on_special_ability_cooldown() && ai?.get_target()) + empower() + +/mob/living/simple_animal/hostile/space_dragon/get_natural_weapon() + if(empowered_attack) + if(!tailwhip) + tailwhip = new(src) + return tailwhip + . = ..() + +/mob/living/simple_animal/hostile/space_dragon/proc/empower() + visible_message(SPAN_MFAUNA("\The [src] thrashes its tail about!")) + empowered_attack = TRUE + if(prob(25) && !gas_spent) + vent_gas() + set_special_ability_cooldown(ability_cooldown * 1.5) + return + set_special_ability_cooldown(ability_cooldown) + +/mob/living/simple_animal/hostile/space_dragon/proc/vent_gas() + visible_message(SPAN_MFAUNA("\The [src] raises its wings, vents a miasma of burning gas, and spreads it about with a flap!")) + gas_spent = TRUE + for(var/mob/living/L in oview(2)) + var/obj/item/projectile/P = new /obj/item/projectile/hotgas(get_turf(src)) + P.launch(L) + +/mob/living/simple_animal/hostile/space_dragon/proc/depower() + empowered_attack = FALSE + +/obj/item/natural_weapon/claws/space_dragon + _base_attack_force = 15 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm deleted file mode 100644 index cec21a42c467..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ /dev/null @@ -1,139 +0,0 @@ -/mob/living/simple_animal/hostile/syndicate - name = "\improper Syndicate operative" - desc = "Death to the Company." - icon_state = "syndicate" - icon_living = "syndicate" - icon_dead = "syndicate_dead" - icon_gib = "syndicate_gib" - speak_chance = 0 - turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" - speed = 4 - stop_automated_movement_when_pulled = 0 - maxHealth = 100 - health = 100 - natural_weapon = /obj/item/natural_weapon/punch - can_escape = TRUE - a_intent = I_HURT - var/corpse = /obj/effect/landmark/corpse/syndicate - var/weapon1 - var/weapon2 - unsuitable_atmos_damage = 15 - environment_smash = 1 - faction = "syndicate" - status_flags = CANPUSH - -/mob/living/simple_animal/hostile/syndicate/death(gibbed, deathmessage, show_dead_message) - ..(gibbed, deathmessage, show_dead_message) - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) - if(weapon2) - new weapon2 (src.loc) - qdel(src) - return - -///////////////Sword and shield//////////// - -/mob/living/simple_animal/hostile/syndicate/melee - icon_state = "syndicatemelee" - icon_living = "syndicatemelee" - natural_weapon = /obj/item/energy_blade/sword/red/activated - weapon2 = /obj/item/shield/energy - status_flags = 0 - -/mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O, var/mob/user) - if(O.force) - if(prob(80)) - var/damage = O.force - if (O.damtype == PAIN) - damage = 0 - health -= damage - visible_message("\The [src] has been attacked with \the [O] by \the [user].") - else - visible_message("\The [src] blocks the [O] with its shield!") - //user.do_attack_animation(src) - else - to_chat(usr, "This weapon is ineffective, it does no damage.") - visible_message("\The [user] gently taps \the [src] with \the [O].") - - -/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(var/obj/item/projectile/Proj) - if(!Proj) return - if(prob(65)) - src.health -= Proj.damage - else - visible_message("\The [src] blocks \the [Proj] with its shield!") - return 0 - - -/mob/living/simple_animal/hostile/syndicate/melee/space - min_gas = null - max_gas = null - minbodytemp = 0 - icon_state = "syndicatemeleespace" - icon_living = "syndicatemeleespace" - name = "Syndicate Commando" - corpse = /obj/effect/landmark/corpse/syndicate - speed = 0 - -/mob/living/simple_animal/hostile/syndicate/ranged - ranged = 1 - rapid = 1 - icon_state = "syndicateranged" - icon_living = "syndicateranged" - casingtype = /obj/item/ammo_casing/pistol - projectilesound = 'sound/weapons/gunshot/gunshot_smg.ogg' - projectiletype = /obj/item/projectile/bullet/pistol - - weapon1 = /obj/item/gun/projectile/automatic/smg - -/mob/living/simple_animal/hostile/syndicate/ranged/space - icon_state = "syndicaterangedpsace" - icon_living = "syndicaterangedpsace" - name = "Syndicate Commando" - min_gas = null - max_gas = null - minbodytemp = 0 - corpse = /obj/effect/landmark/corpse/syndicate/commando - speed = 0 - -/mob/living/simple_animal/hostile/viscerator - name = "viscerator" - desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations." - icon = 'icons/mob/simple_animal/critter.dmi' - icon_state = "viscerator_attack" - icon_living = "viscerator_attack" - pass_flags = PASS_FLAG_TABLE - health = 15 - maxHealth = 15 - natural_weapon = /obj/item/natural_weapon/rotating_blade - faction = "syndicate" - min_gas = null - max_gas = null - minbodytemp = 0 - - meat_type = null - meat_amount = 0 - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = 0 - -/obj/item/natural_weapon/rotating_blade - name = "rotating blades" - attack_verb = list("sliced", "cut") - hitsound = 'sound/weapons/bladeslice.ogg' - force = 15 - edge = 1 - sharp = 1 - -/mob/living/simple_animal/hostile/viscerator/death(gibbed, deathmessage, show_dead_message) - ..(null,"is smashed into pieces!", show_dead_message) - qdel(src) - -/mob/living/simple_animal/hostile/viscerator/hive - faction = "hivebot" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm index a1b1e05eb8c0..ae1de5c119f1 100644 --- a/code/modules/mob/living/simple_animal/hostile/tree.dm +++ b/code/modules/mob/living/simple_animal/hostile/tree.dm @@ -1,47 +1,40 @@ /mob/living/simple_animal/hostile/tree name = "pine tree" desc = "A pissed off tree-like alien. It seems annoyed with the festivities..." - icon = 'icons/obj/flora/pinetrees.dmi' - icon_state = "pine_1" - icon_living = "pine_1" - icon_dead = "pine_1" - icon_gib = "pine_1" - speak_chance = 0 - turns_per_move = 5 - meat_type = /obj/item/chems/food/snacks/fish - response_help = "brushes" - response_disarm = "pushes" - response_harm = "hits" - speed = -1 - maxHealth = 250 - health = 250 - + icon = 'icons/mob/simple_animal/pinetree.dmi' + butchery_data = null + max_health = 250 pixel_x = -16 - harm_intent_damage = 5 natural_weapon = /obj/item/natural_weapon/bite + ai = /datum/mob_controller/aggressive/tree + base_movement_delay = -1 + // For 12 years, this comment has implied trees are a kind of space carp. //Space carp aren't affected by atmos. min_gas = null max_gas = null minbodytemp = 0 - faction = "carp" -/mob/living/simple_animal/hostile/tree/FindTarget() +/datum/mob_controller/aggressive/tree + speak_chance = 0 + turns_per_wander = 10 + +/datum/mob_controller/aggressive/tree/find_target() . = ..() if(.) - audible_emote("growls at [.]") + body.custom_emote(AUDIBLE_MESSAGE, "growls at [.]") -/mob/living/simple_animal/hostile/tree/AttackingTarget() - . =..() - var/mob/living/L = . - if(istype(L)) - if(prob(15)) - L.Weaken(3) - L.visible_message("\the [src] knocks down \the [L]!") +/mob/living/simple_animal/hostile/tree/check_has_mouth() + return FALSE -/mob/living/simple_animal/hostile/tree/death(gibbed, deathmessage, show_dead_message) - ..(null,"is hacked into pieces!", show_dead_message) - new /obj/item/stack/material/wood(loc) - qdel(src) \ No newline at end of file +/mob/living/simple_animal/hostile/tree/get_death_message(gibbed) + return "is hacked into pieces!" + +/mob/living/simple_animal/hostile/tree/death(gibbed) + . = ..() + if(. && !gibbed) + var/decl/material/mat = GET_DECL(/decl/material/solid/organic/wood/oak) + mat.place_shards(loc) + qdel(src) diff --git a/code/modules/mob/living/simple_animal/hostile/vagrant.dm b/code/modules/mob/living/simple_animal/hostile/vagrant.dm index 9ec981e41eff..28731e48512a 100644 --- a/code/modules/mob/living/simple_animal/hostile/vagrant.dm +++ b/code/modules/mob/living/simple_animal/hostile/vagrant.dm @@ -1,54 +1,51 @@ - /mob/living/simple_animal/hostile/vagrant - name = "creature" - desc = "You get the feeling you should run." - icon = 'icons/mob/mob.dmi' - icon_state = "vagrant" - icon_living = "vagrant" - icon_dead = "vagrant" - icon_gib = "vagrant" - maxHealth = 60 - health = 20 - speed = 5 - speak_chance = 0 - turns_per_move = 4 - move_to_delay = 4 - response_help = "pets the" - response_disarm = "gently pushes aside the" - response_harm = "hits the" - break_stuff_probability = 0 - faction = "vagrant" - harm_intent_damage = 3 - natural_weapon = /obj/item/natural_weapon/bite/weak - light_color = "#8a0707" - min_gas = null - max_gas = null - minbodytemp = 0 - var/cloaked = 0 - var/mob/living/carbon/human/gripping = null - var/blood_per_tick = 3 - var/health_per_tick = 0.8 - pass_flags = PASS_FLAG_TABLE + name = "creature" + desc = "You get the feeling you should run." + icon = 'icons/mob/simple_animal/vagrant.dmi' + max_health = 60 + move_intents = list( + /decl/move_intent/walk/animal_fast, + /decl/move_intent/run/animal_fast + ) + faction = "vagrant" + harm_intent_damage = 3 + natural_weapon = /obj/item/natural_weapon/bite/weak + light_color = "#8a0707" + min_gas = null + max_gas = null + minbodytemp = 0 + gene_damage = -1 + pass_flags = PASS_FLAG_TABLE + bleed_colour = "#aad9de" + nutrition = 100 + ai = /datum/mob_controller/aggressive/vagrant + base_movement_delay = 2 + skip_spacemove = TRUE - bleed_colour = "#aad9de" + var/cloaked = 0 + var/blood_per_tick = 3 + var/health_per_tick = 0.8 + var/mob/living/human/gripping -/mob/living/simple_animal/hostile/vagrant/Process_Spacemove() - return 1 +/datum/mob_controller/aggressive/vagrant + speak_chance = 0 + turns_per_wander = 8 + break_stuff_probability = 0 /mob/living/simple_animal/hostile/vagrant/bullet_act(var/obj/item/projectile/Proj) - var/oldhealth = health + var/oldhealth = current_health . = ..() - if((target_mob != Proj.firer) && health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) //Respond to being shot at - target_mob = Proj.firer - turns_per_move = 3 - MoveToTarget() + if(istype(ai) && isliving(Proj.firer) && (ai.get_target() != Proj.firer) && current_health < oldhealth && !incapacitated(INCAPACITATION_KNOCKOUT)) //Respond to being shot at + ai.set_target(Proj.firer) + ai.turns_per_wander = 6 + ai.move_to_target() /mob/living/simple_animal/hostile/vagrant/death(gibbed) . = ..() if(. && !gibbed) gib() -/mob/living/simple_animal/hostile/vagrant/Life() +/mob/living/simple_animal/hostile/vagrant/handle_living_non_stasis_processes() . = ..() if(!.) return FALSE @@ -57,55 +54,59 @@ gripping = null else if(gripping.should_have_organ(BP_HEART)) - var/blood_volume = round(gripping.vessel.total_volume) + var/blood_volume = round(REAGENT_TOTAL_VOLUME(gripping.vessel)) if(blood_volume > 5) gripping.vessel.remove_any(blood_per_tick) - health = min(health + health_per_tick, maxHealth) + heal_overall_damage(health_per_tick) if(prob(15)) - to_chat(gripping, "You feel your fluids being drained!") + to_chat(gripping, SPAN_DANGER("You feel your fluids being drained!")) else gripping = null - if(turns_per_move != initial(turns_per_move)) - turns_per_move = initial(turns_per_move) + // I suspect the original coder mistook this var for movement delay. + // Changing wander time makes no sense in this context. + if(istype(ai) && ai.turns_per_wander != initial(ai.turns_per_wander)) + ai.turns_per_wander = initial(ai.turns_per_wander) - if(stance == HOSTILE_STANCE_IDLE && !cloaked) + if(istype(ai) && ai.get_stance() == STANCE_IDLE && !cloaked) cloaked = 1 update_icon() - if(health == maxHealth) + + if(get_nutrition() > get_max_nutrition()) new/mob/living/simple_animal/hostile/vagrant(src.loc) new/mob/living/simple_animal/hostile/vagrant(src.loc) gib() - return /mob/living/simple_animal/hostile/vagrant/on_update_icon() - if(cloaked) //It's fun time - alpha = 75 - set_light(0) - icon_state = initial(icon_state) - move_to_delay = initial(move_to_delay) - else //It's fight time - alpha = 255 - icon_state = "vagrant_glowing" - set_light(0.2, 0.1, 3) - move_to_delay = 2 + ..() + if(stat == CONSCIOUS) + if(cloaked) //It's fun time + alpha = 75 + set_light(0) + icon_state = initial(icon_state) + set_moving_slowly() + else //It's fight time + alpha = 255 + icon_state += "-glowing" + set_light(3, 0.2) + set_moving_quickly() -/mob/living/simple_animal/hostile/vagrant/AttackingTarget() +/mob/living/simple_animal/hostile/vagrant/apply_attack_effects(mob/living/target) . = ..() - if(ishuman(.)) - var/mob/living/carbon/human/H = . + if(ishuman(target)) + var/mob/living/human/H = target if(gripping == H) - H.Weaken(1) - H.Stun(1) + SET_STATUS_MAX(H, STAT_WEAK, 1) + SET_STATUS_MAX(H, STAT_STUN, 1) return //This line ensures there's always a reasonable chance of grabbing, while still //Factoring in health - if(!gripping && (cloaked || prob(health + ((maxHealth - health) * 2)))) + if(!gripping && (cloaked || prob(current_health + ((get_max_health() - current_health) * 2)))) gripping = H cloaked = 0 update_icon() - H.Weaken(1) - H.Stun(1) + SET_STATUS_MAX(H, STAT_WEAK, 1) + SET_STATUS_MAX(H, STAT_STUN, 1) H.visible_message("\the [src] latches onto \the [H], pulsating!") src.forceMove(gripping.loc) diff --git a/code/modules/mob/living/simple_animal/hostile/viscerator.dm b/code/modules/mob/living/simple_animal/hostile/viscerator.dm new file mode 100644 index 000000000000..197f1c2b3862 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/viscerator.dm @@ -0,0 +1,36 @@ +/mob/living/simple_animal/hostile/viscerator + name = "viscerator" + desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations." + icon = 'icons/mob/simple_animal/viscerator.dmi' + pass_flags = PASS_FLAG_TABLE + max_health = 15 + natural_weapon = /obj/item/natural_weapon/rotating_blade + faction = "syndicate" + min_gas = null + max_gas = null + minbodytemp = 0 + attack_delay = DEFAULT_QUICK_COOLDOWN + bleed_colour = SYNTH_BLOOD_COLOR + butchery_data = /decl/butchery_data/synthetic + +/obj/item/natural_weapon/rotating_blade + name = "rotating blades" + attack_verb = list("sliced", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + _base_attack_force = 15 + edge = TRUE + sharp = TRUE + +/mob/living/simple_animal/hostile/viscerator/check_has_mouth() + return FALSE + +/mob/living/simple_animal/hostile/viscerator/get_death_message(gibbed) + return "is smashed into pieces!" + +/mob/living/simple_animal/hostile/viscerator/death(gibbed) + . = ..() + if(. && !gibbed) + qdel(src) + +/mob/living/simple_animal/hostile/viscerator/hive + faction = "hivebot" diff --git a/code/modules/mob/living/simple_animal/hostile/voxslug.dm b/code/modules/mob/living/simple_animal/hostile/voxslug.dm deleted file mode 100644 index c032c80294ef..000000000000 --- a/code/modules/mob/living/simple_animal/hostile/voxslug.dm +++ /dev/null @@ -1,81 +0,0 @@ -/*VOX SLUG -Small, little HP, poisonous. -*/ - -/mob/living/simple_animal/hostile/voxslug - name = "slug" - desc = "A viscious little creature, it has a mouth of too many teeth and a penchant for blood." - icon_state = "voxslug" - icon_living = "voxslug" - item_state = "voxslug" - icon_dead = "voxslug_dead" - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "stamps on" - destroy_surroundings = 0 - health = 15 - maxHealth = 15 - speed = 0 - move_to_delay = 0 - density = 1 - min_gas = null - mob_size = MOB_SIZE_MINISCULE - can_escape = TRUE - pass_flags = PASS_FLAG_TABLE - natural_weapon = /obj/item/natural_weapon/bite - holder_type = /obj/item/holder/voxslug - faction = "Hostile Fauna" - -/mob/living/simple_animal/hostile/voxslug/ListTargets(var/dist = 7) - var/list/L = list() - for(var/a in hearers(src, dist)) - if(isliving(a)) - var/mob/living/M = a - if(M.faction == faction) - continue - L += a - - return L - -/mob/living/simple_animal/hostile/voxslug/get_scooped(var/mob/living/carbon/grabber) - to_chat(grabber, "\The [src] wriggles out of your hands before you can pick it up!") - -/mob/living/simple_animal/hostile/voxslug/proc/attach(var/mob/living/carbon/human/H) - var/obj/item/clothing/suit/space/S = H.get_covering_equipped_item_by_zone(BP_CHEST) - if(istype(S) && !length(S.breaches)) - S.create_breaches(BRUTE, 20) - if(!length(S.breaches)) //unable to make a hole - return - var/obj/item/organ/external/chest = H.organs_by_name[BP_CHEST] - var/obj/item/holder/voxslug/holder = new(get_turf(src)) - src.forceMove(holder) - chest.embed(holder,0,"\The [src] latches itself onto \the [H]!") - holder.sync(src) - -/mob/living/simple_animal/hostile/voxslug/AttackingTarget() - . = ..() - if(istype(., /mob/living/carbon/human)) - var/mob/living/carbon/human/H = . - if(prob(H.getBruteLoss()/2)) - attach(H) - -/mob/living/simple_animal/hostile/voxslug/Life() - . = ..() - if(. && istype(src.loc, /obj/item/holder) && isliving(src.loc.loc)) //We in somebody - var/mob/living/L = src.loc.loc - if(src.loc in L.get_visible_implants(0)) - if(prob(1)) - to_chat(L, "You feel strange as \the [src] pulses...") - var/datum/reagents/R = L.reagents - R.add_reagent(/decl/material/liquid/presyncopics, 0.5) - -/obj/item/holder/voxslug/attack(var/mob/target, var/mob/user) - var/mob/living/simple_animal/hostile/voxslug/V = contents[1] - if(!V.stat && istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - if(!do_mob(user, H, 30)) - return - V.attach(H) - qdel(src) - return - ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/natural_weapons.dm b/code/modules/mob/living/simple_animal/natural_weapons.dm index 0e169de377aa..4ee419acec07 100644 --- a/code/modules/mob/living/simple_animal/natural_weapons.dm +++ b/code/modules/mob/living/simple_animal/natural_weapons.dm @@ -1,70 +1,82 @@ /obj/item/natural_weapon name = "natural weapons" gender = PLURAL - attack_verb = list("attacked") - force = 0 - damtype = BRUTE + attack_verb = "attacked" + atom_damage_type = BRUTE canremove = FALSE obj_flags = OBJ_FLAG_CONDUCTIBLE //for intent of shocking checks, they're right inside the animal + is_spawnable_type = FALSE + needs_attack_dexterity = DEXTERITY_NONE + weapon_can_knock_prone = FALSE // Very powerful in the hands of simplemobs. var/show_in_message // whether should we show up in attack message, e.g. 'urist has been bit with teeth by carp' vs 'urist has been bit by carp' +/obj/item/natural_weapon/expend_attack_force(mob/living/user) + return get_base_attack_force() + /obj/item/natural_weapon/attack_message_name() return show_in_message ? ..() : null +/obj/item/natural_weapon/can_embed() + return FALSE + +/obj/item/natural_weapon/apply_hit_effect(mob/living/target, mob/living/user, hit_zone) + if(!(. = ..())) + return + if(istype(user, /mob/living/simple_animal)) + var/mob/living/simple_animal/animal = user + animal.apply_attack_effects(target) + /obj/item/natural_weapon/bite name = "teeth" - attack_verb = list("bitten") + attack_verb = "bitten" hitsound = 'sound/weapons/bite.ogg' - force = 10 + _base_attack_force = 10 sharp = TRUE /obj/item/natural_weapon/bite/weak - force = 5 + _base_attack_force = 5 attack_verb = list("bitten", "nipped") /obj/item/natural_weapon/bite/mouse - force = 1 - attack_verb = list("nibbled") + _base_attack_force = 1 + attack_verb = "nibbled" hitsound = null /obj/item/natural_weapon/bite/strong - force = 20 + _base_attack_force = 20 /obj/item/natural_weapon/claws name = "claws" attack_verb = list("mauled", "clawed", "slashed") - force = 10 + _base_attack_force = 10 sharp = TRUE edge = TRUE /obj/item/natural_weapon/claws/strong - force = 25 + _base_attack_force = 25 /obj/item/natural_weapon/claws/weak - force = 5 + _base_attack_force = 5 attack_verb = list("clawed", "scratched") /obj/item/natural_weapon/hooves name = "hooves" - attack_verb = list("kicked") - force = 5 + attack_verb = "kicked" /obj/item/natural_weapon/punch name = "fists" - attack_verb = list("punched") - force = 10 + attack_verb = "punched" + _base_attack_force = 10 /obj/item/natural_weapon/pincers name = "pincers" - force = 5 attack_verb = list("snipped", "pinched") /obj/item/natural_weapon/drone_slicer name = "sharpened leg" gender = NEUTER - attack_verb = list("sliced") - force = 5 - damtype = BRUTE + attack_verb = "sliced" + atom_damage_type = BRUTE edge = TRUE show_in_message = TRUE @@ -72,11 +84,10 @@ name = "beak" gender = NEUTER attack_verb = list("pecked", "jabbed", "poked") - force = 5 sharp = TRUE /obj/item/natural_weapon/large - force = 15 + _base_attack_force = 15 /obj/item/natural_weapon/giant - force = 30 \ No newline at end of file + _base_attack_force = 30 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/passive/_passive.dm b/code/modules/mob/living/simple_animal/passive/_passive.dm new file mode 100644 index 000000000000..353a7c3ad629 --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/_passive.dm @@ -0,0 +1,12 @@ +/mob/living/simple_animal/passive + possession_candidate = TRUE + abstract_type = /mob/living/simple_animal/passive + ai = /datum/mob_controller/passive + see_in_dark = 6 + minbodytemp = 223 + maxbodytemp = 323 + base_movement_delay = -1 + +/mob/living/simple_animal/passive/Initialize() + . = ..() + add_held_item_slot(new /datum/inventory_slot/gripper/mouth/simple) diff --git a/code/modules/mob/living/simple_animal/passive/deer.dm b/code/modules/mob/living/simple_animal/passive/deer.dm new file mode 100644 index 000000000000..cdb5d4895cbe --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/deer.dm @@ -0,0 +1,105 @@ +/datum/mob_controller/passive/deer + emote_hear = list("bleats") + emote_see = list("shakes its head", "stamps a hoof", "looks around quickly") + emote_speech = list("Ough!", "Ourgh!", "Mroough!", "Broough?") + speak_chance = 0.25 + turns_per_wander = 10 + +/datum/mob_controller/passive/deer/buck + emote_hear = list("bellows") + +/mob/living/simple_animal/passive/deer + name = "deer" + gender = NEUTER + icon = 'icons/mob/simple_animal/doe.dmi' + desc = "A fleet-footed forest animal known for its grace, speed and timidity." + speak_emote = list("bleats") + see_in_dark = 6 + faction = "deer" + max_health = 60 + butchery_data = /decl/butchery_data/animal/ruminant/deer + natural_weapon = /obj/item/natural_weapon/hooves + mob_size = MOB_SIZE_LARGE + ai = /datum/mob_controller/passive/deer + eye_color = "#1a1a1a" + +/mob/living/simple_animal/passive/deer/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#b39161", + "markings" = "#3a3329", + "socks" = "#ddd5c9" + ) + return default_colors + +/mob/living/simple_animal/passive/deer/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/deer) + +/decl/bodytype/quadruped/animal/deer + uid = "bodytype_animal_deer" + +/decl/bodytype/quadruped/animal/deer/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 1, -4), + "[SOUTH]" = list( 1, -4), + "[EAST]" = list( 9, -4), + "[WEST]" = list(-9, -4) + ) + ) + return ..() + +/mob/living/simple_animal/passive/deer/set_gender(new_gender, update_body) + . = ..() + if(name == initial(name)) + switch(gender) + if(MALE) + SetName("buck") + if(FEMALE) + SetName("doe") + else + SetName("deer") + +/mob/living/simple_animal/passive/deer/doe + name = "doe" + icon = 'icons/mob/simple_animal/doe.dmi' + butchery_data = /decl/butchery_data/animal/ruminant/deer + gender = FEMALE + +/mob/living/simple_animal/passive/deer/buck + name = "buck" + icon = 'icons/mob/simple_animal/buck.dmi' + butchery_data = /decl/butchery_data/animal/ruminant/deer/buck + gender = MALE + speak_emote = list("bellows") + ai = /datum/mob_controller/passive/deer/buck + +/mob/living/simple_animal/passive/deer/Initialize() + if(gender == NEUTER) + if(prob(10)) // Internet seems to think a 10:1 ratio of does to bucks isn't uncommon, adjust later if this is bollocks + name = "buck" + icon = 'icons/mob/simple_animal/buck.dmi' + butchery_data = /decl/butchery_data/animal/ruminant/deer/buck + gender = MALE + speak_emote = list("bellows") + ai = /datum/mob_controller/passive/deer/buck + else + name = "doe" + icon = 'icons/mob/simple_animal/doe.dmi' + butchery_data = /decl/butchery_data/animal/ruminant/deer + gender = FEMALE + speak_emote = list("bleats") + ai = /datum/mob_controller/passive/deer + return ..() + +/mob/living/simple_animal/passive/deer/sparkle + name = "sparkledeer" + desc = "A fleet-footed forest animal known for a love of vtubers." + +/mob/living/simple_animal/passive/deer/sparkle/Initialize() + draw_visible_overlays ||= list( + "base" = get_random_colour(), + "markings" = get_random_colour(TRUE), + "socks" = get_random_colour() + ) + eye_color ||= get_random_colour(TRUE) + . = ..() diff --git a/code/modules/mob/living/simple_animal/passive/fox.dm b/code/modules/mob/living/simple_animal/passive/fox.dm new file mode 100644 index 000000000000..d8f8ad225271 --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/fox.dm @@ -0,0 +1,91 @@ +/mob/living/simple_animal/passive/fox + name = "fox" + desc = "A cunning and graceful predatory mammal, known for its red fur and eerie screams." + icon = 'icons/mob/simple_animal/fox.dmi' + natural_weapon = /obj/item/natural_weapon/bite/weak + ai = /datum/mob_controller/passive/hunter/fox + mob_size = MOB_SIZE_SMALL + speak_emote = list("yelps", "yips", "hisses", "screams") + pass_flags = PASS_FLAG_TABLE + butchery_data = /decl/butchery_data/animal/fox + eye_color = "#1d628a" + ability_handlers = list(/datum/ability_handler/predator) + +/mob/living/simple_animal/passive/fox/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#ed5a20", + "markings" = "#efe9e6", + "socks" = "#36221b" + ) + return default_colors + +/mob/living/simple_animal/passive/fox/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing, + /decl/posture/lying, + /decl/posture/lying/deliberate, + /decl/posture/sitting + ) + return available_postures + +/mob/living/simple_animal/passive/fox/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/fox) + +/decl/bodytype/quadruped/animal/fox + uid = "bodytype_animal_fox" + +/decl/bodytype/quadruped/animal/fox/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 1, -9), + "[SOUTH]" = list( 1, -8), + "[EAST]" = list( 11, -9), + "[WEST]" = list(-11, -9) + ) + ) + return ..() + +/datum/mob_controller/passive/hunter/fox + emote_speech = list("Yip!","AIEE!","YIPE!") + emote_hear = list("screams","yips") + emote_see = list("paces back and forth", "flicks its tail") + +/mob/living/simple_animal/passive/fox/arctic + name = "arctic fox" + desc = "A cunning and graceful predatory mammal, known for leaping headfirst into snowbanks while hunting burrowing rodents." + eye_color = "#7a6f3b" + +/mob/living/simple_animal/passive/fox/arctic/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#ccc496", + "markings" = "#efe9e6", + "socks" = "#cab9b1" + ) + return default_colors + +/mob/living/simple_animal/passive/fox/silver + name = "silver fox" + desc = "A cunning and graceful predatory mammal, known for the rarity and high value of their pelts." + eye_color = "#2db1c9" + +/mob/living/simple_animal/passive/fox/silver/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#2c2c2a", + "markings" = "#3d3b39", + "socks" = "#746d66" + ) + return default_colors + +/mob/living/simple_animal/passive/fox/sparkle + name = "sparklefox" + desc = "A cunning and graceful predatory mammal, known for being really into hardstyle." + +/mob/living/simple_animal/passive/fox/sparkle/Initialize() + draw_visible_overlays ||= list( + "base" = get_random_colour(), + "markings" = get_random_colour(TRUE), + "socks" = get_random_colour() + ) + eye_color ||= get_random_colour(TRUE) + . = ..() + diff --git a/code/modules/mob/living/simple_animal/passive/horse.dm b/code/modules/mob/living/simple_animal/passive/horse.dm new file mode 100644 index 000000000000..5ab8801cddd8 --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/horse.dm @@ -0,0 +1,65 @@ +/mob/living/simple_animal/passive/horse + name = "horse" + real_name = "horse" + desc = "A hefty four-legged animal traditionally used for hauling goods, recreational riding, and stomping enemy soldiers to death." + icon = 'icons/mob/simple_animal/horse.dmi' + speak_emote = list("neighs", "whinnies") + possession_candidate = TRUE + mob_size = MOB_SIZE_LARGE + pixel_x = -6 + default_pixel_x = -6 + base_animal_type = /mob/living/simple_animal/passive/horse + faction = null + buckle_pixel_shift = @'{"x":0,"y":0,"z":16}' + can_have_rider = TRUE + max_rider_size = MOB_SIZE_MEDIUM + ai = /datum/mob_controller/passive/horse + color = "#806146" // preview color + draw_visible_overlays = list() // to avoid applying any defaults + +/datum/mob_controller/passive/horse + emote_speech = list("Neigh!","NEIGH!","Neigh?") + emote_hear = list("neighs","whinnies") + emote_see = list("canters", "scuffs the ground", "shakes its mane", "tosses its head") + spooked_by_grab = FALSE // todo: tamed vs untamed? + +/datum/mob_controller/passive/horse/retaliate(atom/source) + SHOULD_CALL_PARENT(FALSE) + return // debug to stop the horse freaking out when mounted + +/mob/living/simple_animal/passive/horse/Initialize() + . = ..() + color = null // clear preview color + add_inventory_slot(new /datum/inventory_slot/back/horse) + equip_to_slot_or_del(new /obj/item/saddle(src), slot_back_str) + if(!LAZYACCESS(draw_visible_overlays, "base")) + LAZYSET(draw_visible_overlays, "base", pick(get_possible_horse_colors())) + update_icon() + +/mob/living/simple_animal/passive/horse/add_additional_visible_overlays(list/accumulator) + if(buckled_mob) + var/image/horse_front = overlay_image(icon, "[icon_state]-buckled", draw_visible_overlays["base"], RESET_COLOR) + horse_front.layer = ABOVE_HUMAN_LAYER + accumulator += horse_front + +/mob/living/simple_animal/passive/horse/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/horse) + +/mob/living/simple_animal/passive/horse/proc/get_possible_horse_colors() + var/static/list/honse_colors = list( + "#856b48", + "#806146", + "#845c46" + ) + return honse_colors + +/decl/bodytype/quadruped/animal/horse + name = "horse" + bodytype_category = "equine body" + uid = "bodytype_horse" + +/datum/inventory_slot/back/horse + requires_organ_tag = null + +/mob/living/simple_animal/passive/horse/small + icon = 'icons/mob/simple_animal/horse_small.dmi' diff --git a/code/modules/mob/living/simple_animal/passive/mouse.dm b/code/modules/mob/living/simple_animal/passive/mouse.dm new file mode 100644 index 000000000000..5139242d27ed --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/mouse.dm @@ -0,0 +1,133 @@ +/mob/living/simple_animal/passive/mouse + name = "mouse" + real_name = "mouse" + desc = "It's a small rodent." + icon = 'icons/mob/simple_animal/mouse_gray.dmi' + speak_emote = list("squeeks","squeeks","squiks") + pass_flags = PASS_FLAG_TABLE + see_in_dark = 6 + max_health = 5 + response_harm = "stamps on" + density = FALSE + minbodytemp = 223 //Below -50 Degrees Celsius + maxbodytemp = 323 //Above 50 Degrees Celsius + universal_speak = FALSE + universal_understand = TRUE + holder_type = /obj/item/holder + mob_size = MOB_SIZE_MINISCULE + can_pull_size = ITEM_SIZE_TINY + can_pull_mobs = MOB_PULL_NONE + base_animal_type = /mob/living/simple_animal/passive/mouse + butchery_data = /decl/butchery_data/animal/small/furred + + ai = /datum/mob_controller/passive/mouse + + var/body_color //brown, gray and white, leave blank for random + var/splatted = FALSE + +/datum/mob_controller/passive/mouse + expected_type = /mob/living/simple_animal/passive/mouse + emote_speech = list("Squeek!","SQUEEK!","Squeek?") + emote_hear = list("squeeks","squeaks","squiks") + emote_see = list("runs in a circle", "shakes", "scritches at something") + speak_chance = 0.25 + turns_per_wander = 10 + can_escape_buckles = TRUE + +/mob/living/simple_animal/passive/mouse/get_remains_type() + return /obj/item/remains/mouse + +/mob/living/simple_animal/passive/mouse/get_dexterity(var/silent) + return DEXTERITY_NONE // Mice are troll bait, give them no power. + +/datum/mob_controller/passive/mouse/do_process() + if(!(. = ..())) + return + if(body.stat == CONSCIOUS) + if(body.current_posture?.prone && prob(5)) + body.set_posture(/decl/posture/standing) + if(prob(speak_chance)) + playsound(body.loc, 'sound/effects/mousesqueek.ogg', 50) + if(body.stat == UNCONSCIOUS && prob(5)) + INVOKE_ASYNC(body, TYPE_PROC_REF(/mob/living/simple_animal, audible_emote), "snuffles.") + +/mob/living/simple_animal/passive/mouse/Initialize() + verbs += /mob/living/proc/hide + if(name == initial(name)) + name = "[name] ([sequential_id(/mob/living/simple_animal/passive/mouse)])" + real_name = name + set_mouse_icon() + . = ..() + +/mob/living/simple_animal/passive/mouse/proc/set_mouse_icon() + if(!body_color) + body_color = pick( list("brown","gray","white") ) + switch(body_color) + if("gray") + butchery_data = /decl/butchery_data/animal/small/furred/gray + icon = 'icons/mob/simple_animal/mouse_gray.dmi' + if("white") + butchery_data = /decl/butchery_data/animal/small/furred/white + icon = 'icons/mob/simple_animal/mouse_white.dmi' + if("brown") + butchery_data = /decl/butchery_data/animal/small/furred + icon = 'icons/mob/simple_animal/mouse_brown.dmi' + desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." + +/mob/living/simple_animal/passive/mouse/proc/splat() + take_damage(get_max_health()) // Enough damage to kill + splatted = TRUE + death() + +/mob/living/simple_animal/passive/mouse/on_update_icon() + . = ..() + if(stat == DEAD && splatted) + icon_state = "world-splat" + +/mob/living/simple_animal/passive/mouse/Crossed(atom/movable/AM) + ..() + if(!ishuman(AM) || stat) + return + to_chat(AM, SPAN_WARNING("[html_icon(src)] Squeek!")) + sound_to(AM, 'sound/effects/mousesqueek.ogg') + +/* + * Mouse types + */ +/mob/living/simple_animal/passive/mouse/white + body_color = "white" + icon = 'icons/mob/simple_animal/mouse_white.dmi' + +/mob/living/simple_animal/passive/mouse/gray + body_color = "gray" + icon = 'icons/mob/simple_animal/mouse_gray.dmi' + +/mob/living/simple_animal/passive/mouse/brown + body_color = "brown" + icon = 'icons/mob/simple_animal/mouse_brown.dmi' + +//TOM IS ALIVE! SQUEEEEEEEE~K :) +/mob/living/simple_animal/passive/mouse/brown/Tom + name = "Tom" + desc = "Jerry the cat is not amused." + +/mob/living/simple_animal/passive/mouse/brown/Tom/Initialize() + . = ..() + // Change my name back, don't want to be named Tom (666) + SetName(initial(name)) + real_name = name + +/mob/living/simple_animal/passive/mouse/brown/Tom/is_tagging_suitable() + return FALSE + +// rats, they're the rats (from Polaris) +/mob/living/simple_animal/passive/mouse/rat + name = "rat" + desc = "A large rodent, often seen hiding in maintenance areas and making a nuisance of itself." + body_color = "rat" + icon = 'icons/mob/simple_animal/rat.dmi' + butchery_data = /decl/butchery_data/animal/small/furred/gray + max_health = 20 + +/mob/living/simple_animal/passive/mouse/rat/set_mouse_icon() + return diff --git a/code/modules/mob/living/simple_animal/passive/rabbit.dm b/code/modules/mob/living/simple_animal/passive/rabbit.dm new file mode 100644 index 000000000000..32676d4ab40d --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/rabbit.dm @@ -0,0 +1,69 @@ +/mob/living/simple_animal/passive/rabbit + name = "white rabbit" + desc = "A hopping mammal with long ears and a love for carrots." + icon = 'icons/mob/simple_animal/rabbit.dmi' + max_health = 20 + natural_weapon = /obj/item/natural_weapon/bite/weak + speak_emote = list("chitters") + mob_size = MOB_SIZE_TINY + butchery_data = /decl/butchery_data/animal/rabbit + holder_type = /obj/item/holder + ai = /datum/mob_controller/passive/rabbit + butchery_data = /decl/butchery_data/animal/rabbit + eye_color = COLOR_BLACK + +/mob/living/simple_animal/passive/rabbit/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#e6e5da", + "markings" = "#c8b1a5", + "socks" = "#e6e5da" + ) + return default_colors + +/datum/mob_controller/passive/rabbit + emote_hear = list("chitters") + emote_see = list("hops","lifts its head","sniffs the air","wiggles its tail") + speak_chance = 0.25 + +/mob/living/simple_animal/passive/rabbit/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/rabbit) + +/decl/bodytype/quadruped/animal/rabbit + uid = "bodytype_animal_rabbit" + +/mob/living/simple_animal/passive/rabbit/brown + name = "brown rabbit" + butchery_data = /decl/butchery_data/animal/rabbit/brown + +/mob/living/simple_animal/passive/rabbit/brown/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#62472b", + "markings" = "#958279", + "socks" = "#62472b" + ) + return default_colors + +/mob/living/simple_animal/passive/rabbit/black + name = "black rabbit" + butchery_data = /decl/butchery_data/animal/rabbit/black + +/mob/living/simple_animal/passive/rabbit/black/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#4f4f4f", + "markings" = "#958279", + "socks" = "#4f4f4f" + ) + return default_colors + +/mob/living/simple_animal/passive/rabbit/sparkle + name = "sparklerabbit" + desc = "A hopping mammal with long ears and a love for raves." + +/mob/living/simple_animal/passive/rabbit/sparkle/Initialize() + draw_visible_overlays ||= list( + "base" = get_random_colour(), + "markings" = get_random_colour(TRUE), + "socks" = get_random_colour() + ) + eye_color ||= get_random_colour(TRUE) + . = ..() diff --git a/code/modules/mob/living/simple_animal/passive/sheep.dm b/code/modules/mob/living/simple_animal/passive/sheep.dm new file mode 100644 index 000000000000..90315aaa9faa --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/sheep.dm @@ -0,0 +1,38 @@ +/datum/mob_controller/passive/sheep + emote_hear = list("bleats") + emote_see = list("shakes its head", "stamps a hoof", "looks around quickly") + emote_speech = list("Baa?", "Baa!", "BAA!") + speak_chance = 0.25 + turns_per_wander = 10 + +/decl/bodytype/quadruped/animal/sheep + uid = "bodytype_animal_sheep" + +/mob/living/simple_animal/passive/sheep + name = "sheep" + real_name = "sheep" + desc = "A kind of wooly animal that grazes in herds, often raised for their meat and fleeces." + icon = 'icons/mob/simple_animal/sheep.dmi' + speak_emote = list("bleats") + faction = "sheep" + butchery_data = /decl/butchery_data/animal/ruminant/sheep + ai = /datum/mob_controller/passive/sheep + +/mob/living/simple_animal/passive/sheep/Initialize() + . = ..() + set_extension(src, /datum/extension/shearable) + update_icon() + +/mob/living/simple_animal/passive/sheep/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/sheep) + +/mob/living/simple_animal/passive/sheep/set_gender(new_gender, update_body) + . = ..() + if(name == initial(name)) + switch(gender) + if(MALE) + SetName("ram") + if(FEMALE) + SetName("ewe") + else + SetName("sheep") diff --git a/code/modules/mob/living/simple_animal/passive/wolf.dm b/code/modules/mob/living/simple_animal/passive/wolf.dm new file mode 100644 index 000000000000..cbe5c004b259 --- /dev/null +++ b/code/modules/mob/living/simple_animal/passive/wolf.dm @@ -0,0 +1,44 @@ +/mob/living/simple_animal/passive/wolf + name = "wolf" + desc = "A predatory canine commonly known to run in packs and howl at the moon." + icon = 'icons/mob/simple_animal/wolf.dmi' + natural_weapon = /obj/item/natural_weapon/bite + ai = /datum/mob_controller/passive/hunter/wolf + mob_size = MOB_SIZE_MEDIUM + speak_emote = list("huffs", "growls") + pass_flags = PASS_FLAG_TABLE + butchery_data = /decl/butchery_data/animal/wolf + eye_color = "#9b7214" + ability_handlers = list(/datum/ability_handler/predator) + +/mob/living/simple_animal/passive/wolf/get_default_animal_colours() + var/static/list/default_colors = list( + "base" = "#6a6a6d", + "markings" = "#574938", + "socks" = "#41414d" + ) + return default_colors + +/datum/mob_controller/passive/hunter/wolf + emote_speech = list("Awoo!","Aroo!","Rrr!") + emote_hear = list("huffs","growls") + emote_see = list("paces back and forth", "flicks its tail") + +/mob/living/simple_animal/passive/wolf/get_bodytype() + return GET_DECL(/decl/bodytype/quadruped/animal/wolf) + +/decl/bodytype/quadruped/animal/wolf + uid = "bodytype_animal_wolf" + +/mob/living/simple_animal/passive/wolf/sparkle + name = "sparklewolf" + desc = "A predatory canine commonly known to watch speedruns and take party drugs." + +/mob/living/simple_animal/passive/wolf/sparkle/Initialize() + draw_visible_overlays ||= list( + "base" = get_random_colour(), + "markings" = get_random_colour(TRUE), + "socks" = get_random_colour() + ) + eye_color ||= get_random_colour(TRUE) + . = ..() diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm deleted file mode 100644 index b6309337465d..000000000000 --- a/code/modules/mob/living/simple_animal/shade.dm +++ /dev/null @@ -1,59 +0,0 @@ -/mob/living/simple_animal/shade - name = "Shade" - real_name = "Shade" - desc = "A bound spirit" - icon = 'icons/mob/mob.dmi' - icon_state = "shade" - icon_living = "shade" - icon_dead = "shade_dead" - maxHealth = 50 - health = 50 - universal_speak = TRUE - speak_emote = list("hisses") - emote_hear = list("wails","screeches") - response_help = "puts their hand through" - response_disarm = "flails at" - response_harm = "punches" - natural_weapon = /obj/item/natural_weapon/shade - minbodytemp = 0 - maxbodytemp = 4000 - min_gas = null - max_gas = null - speed = -1 - stop_automated_movement = 1 - status_flags = 0 - faction = "cult" - supernatural = 1 - status_flags = CANPUSH - - bleed_colour = "#181933" - - meat_type = null - meat_amount = 0 - bone_material = null - bone_amount = 0 - skin_material = null - skin_amount = 0 - -/obj/item/natural_weapon/shade - name = "foul touch" - attack_verb = list("drained") - damtype = BURN - force = 10 - -/mob/living/simple_animal/shade/cultify() - return - -/mob/living/simple_animal/shade/Life() - . = ..() - OnDeathInLife() - -/mob/living/simple_animal/shade/proc/OnDeathInLife() - if(stat == 2) - new /obj/item/ectoplasm (src.loc) - for(var/mob/M in viewers(src, null)) - if((M.client && !( M.blinded ))) - M.show_message("[src] lets out a contented sigh as their form unwinds.") - ghostize() - qdel(src) - return diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm deleted file mode 100644 index bc1cb02cafaa..000000000000 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ /dev/null @@ -1,533 +0,0 @@ -/mob/living/simple_animal - name = "animal" - icon = 'icons/mob/simple_animal/animal.dmi' - health = 20 - maxHealth = 20 - universal_speak = FALSE - - mob_bump_flag = SIMPLE_ANIMAL - mob_swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL - mob_push_flags = MONKEY|SLIME|SIMPLE_ANIMAL - - meat_type = /obj/item/chems/food/snacks/meat - meat_amount = 3 - bone_material = /decl/material/solid/bone - bone_amount = 5 - skin_material = /decl/material/solid/skin - skin_amount = 5 - - var/show_stat_health = 1 //does the percentage health show in the stat panel for the mob - - var/icon_living = "" - var/icon_dead = "" - var/icon_gib = null //We only try to show a gibbing animation if this exists. - - var/list/speak = list("...") - var/speak_chance = 0 - var/list/emote_hear = list() //Hearable emotes - var/list/emote_see = list() //Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps - - var/turns_per_move = 1 - var/turns_since_move = 0 - var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals. - var/wander = 1 // Does the mob wander around when idle? - var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is grabbing it. - - //Interaction - var/response_help = "tries to help" - var/response_disarm = "tries to disarm" - var/response_harm = "tries to hurt" - var/harm_intent_damage = 3 - var/can_escape = FALSE // 'smart' simple animals such as human enemies, or things small, big, sharp or strong enough to power out of a net - - //Temperature effect - var/minbodytemp = 250 - var/maxbodytemp = 350 - var/heat_damage_per_tick = 3 //amount of damage applied if animal's body temperature is higher than maxbodytemp - var/cold_damage_per_tick = 2 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp - var/fire_alert = 0 - - //Atmos effect - Yes, you can make creatures that require arbitrary gasses to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage - var/list/min_gas = list(/decl/material/gas/oxygen = 5) - var/list/max_gas = list( - /decl/material/gas/chlorine = 1, - /decl/material/gas/carbon_dioxide = 5 - ) - - var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above - var/speed = 0 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster - - //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly - var/obj/item/natural_weapon/natural_weapon - var/friendly = "nuzzles" - var/environment_smash = 0 - var/resistance = 0 // Damage reduction - var/armor_type = /datum/extension/armor - var/list/natural_armor //what armor animal has - var/flash_vulnerability = 1 // whether or not the mob can be flashed; 0 = no, 1 = yes, 2 = very yes - - //Null rod stuff - var/supernatural = 0 - var/purge = 0 - - var/bleed_ticks = 0 - var/bleed_colour = COLOR_BLOOD_HUMAN - var/can_bleed = TRUE - - // contained in a cage - var/in_stasis = 0 - - //for simple animals with abilities, mostly megafauna - var/ability_cooldown - var/time_last_used_ability - - //for simple animals that reflect damage when attacked in melee - var/return_damage_min - var/return_damage_max - - var/performing_delayed_life_action = FALSE - -/mob/living/simple_animal/Initialize() - . = ..() - if(LAZYLEN(natural_armor)) - set_extension(src, armor_type, natural_armor) - -/mob/living/simple_animal/Destroy() - if(istype(natural_weapon)) - QDEL_NULL(natural_weapon) - . = ..() - -/mob/living/simple_animal/Life() - . = ..() - if(!.) - return FALSE - if(!living_observers_present(GetConnectedZlevels(z))) - return - //Health - if(stat == DEAD) - if(health > 0) - icon_state = icon_living - switch_from_dead_to_living_mob_list() - set_stat(CONSCIOUS) - set_density(1) - return 0 - - handle_atmos() - - if(health <= 0) - death() - return - - if(health > maxHealth) - health = maxHealth - - handle_stunned() - handle_weakened() - handle_paralysed() - handle_confused() - handle_supernatural() - handle_impaired_vision() - - if(can_bleed && bleed_ticks > 0) - handle_bleeding() - - delayed_life_action() - return 1 - -// Handles timed stuff in Life() -/mob/living/simple_animal/proc/delayed_life_action() - set waitfor = FALSE - if(performing_delayed_life_action) - return - if(client) - return - performing_delayed_life_action = TRUE - do_delayed_life_action() - performing_delayed_life_action = FALSE - -// For saner overriding; only override this. -/mob/living/simple_animal/proc/do_delayed_life_action() - if(buckled && can_escape) - if(istype(buckled, /obj/effect/energy_net)) - var/obj/effect/energy_net/Net = buckled - Net.escape_net(src) - else if(prob(50)) - escape(src, buckled) - else if(prob(50)) - visible_message("\The [src] struggles against \the [buckled]!") - - //Movement - if(!stop_automated_movement && wander && !anchored) - if(isturf(src.loc) && !resting) //This is so it only moves if it's not inside a closet, gentics machine, etc. - turns_since_move++ - if(turns_since_move >= turns_per_move && (!(stop_automated_movement_when_pulled) || !LAZYLEN(grabbed_by))) //Some animals don't move when pulled - SelfMove(pick(GLOB.cardinal)) - turns_since_move = 0 - - //Speaking - if(speak_chance) - if(rand(0,200) < speak_chance) - var/action = pick( - speak.len; "speak", - emote_hear.len; "emote_hear", - emote_see.len; "emote_see" - ) - - switch(action) - if("speak") - say(pick(speak)) - if("emote_hear") - audible_emote("[pick(emote_hear)].") - if("emote_see") - visible_emote("[pick(emote_see)].") - -/mob/living/simple_animal/proc/handle_atmos(var/atmos_suitable = 1) - //Atmos - - if(!loc) - return - - var/datum/gas_mixture/environment = loc.return_air() - if(!(MUTATION_SPACERES in mutations) && environment) - - if(abs(environment.temperature - bodytemperature) > 40 ) - bodytemperature += ((environment.temperature - bodytemperature) / 5) - - // don't bother checking it twice if we got a supplied 0 val. - if(atmos_suitable) - if(LAZYLEN(min_gas)) - for(var/gas in min_gas) - if(environment.gas[gas] < min_gas[gas]) - atmos_suitable = FALSE - break - if(atmos_suitable && LAZYLEN(max_gas)) - for(var/gas in max_gas) - if(environment.gas[gas] > max_gas[gas]) - atmos_suitable = FALSE - break - - //Atmos effect - if(bodytemperature < minbodytemp) - fire_alert = 2 - adjustBruteLoss(cold_damage_per_tick) - else if(bodytemperature > maxbodytemp) - fire_alert = 1 - adjustBruteLoss(heat_damage_per_tick) - else - fire_alert = 0 - - if(!atmos_suitable) - adjustBruteLoss(unsuitable_atmos_damage) - -/mob/living/simple_animal/proc/escape(mob/living/M, obj/O) - O.unbuckle_mob(M) - visible_message("\The [M] escapes from \the [O]!") - -/mob/living/simple_animal/proc/handle_supernatural() - if(purge) - purge -= 1 - -/mob/living/simple_animal/gib() - ..(icon_gib,1) - -/mob/living/simple_animal/proc/visible_emote(var/act_desc) - custom_emote(1, act_desc) - -/mob/living/simple_animal/proc/audible_emote(var/act_desc) - custom_emote(2, act_desc) - -/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) - if(!Proj || Proj.nodamage) - return - - var/damage = Proj.damage - if(Proj.damtype == STUN) - damage = Proj.damage / 6 - if(Proj.damtype == BRUTE) - damage = Proj.damage / 2 - if(Proj.damtype == BURN) - damage = Proj.damage / 1.5 - if(Proj.agony) - damage += Proj.agony / 6 - if(health < Proj.agony * 3) - Paralyse(Proj.agony / 20) - visible_message("[src] is stunned momentarily!") - - bullet_impact_visuals(Proj) - adjustBruteLoss(damage) - Proj.on_hit(src) - return 0 - -/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M) - ..() - - switch(M.a_intent) - - if(I_HELP) - if (health > 0) - M.visible_message("[M] [response_help] \the [src].") - M.update_personal_goal(/datum/goal/achievement/specific_object/pet, type) - - if(I_DISARM) - M.visible_message("[M] [response_disarm] \the [src].") - M.do_attack_animation(src) - //TODO: Push the mob away or something - - if(I_HURT) - var/dealt_damage = harm_intent_damage - var/harm_verb = response_harm - if(ishuman(M)) - var/decl/natural_attack/attack = M.get_unarmed_attack(src) - if(istype(attack)) - dealt_damage = attack.damage <= dealt_damage ? dealt_damage : attack.damage - harm_verb = pick(attack.attack_verb) - if(attack.sharp || attack.edge) - adjustBleedTicks(dealt_damage) - - adjustBruteLoss(dealt_damage) - M.visible_message("[M] [harm_verb] \the [src]!") - M.do_attack_animation(src) - - return - -/mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user) - if(istype(O, /obj/item/stack/medical)) - if(stat != DEAD) - var/obj/item/stack/medical/MED = O - if(!MED.animal_heal) - to_chat(user, "That [MED] won't help \the [src] at all!") - return - if(health < maxHealth) - if(MED.can_use(1)) - adjustBruteLoss(-MED.animal_heal) - visible_message("[user] applies the [MED] on [src].") - MED.use(1) - else - to_chat(user, "\The [src] is dead, medical items won't bring \him back to life.") - return - - if(istype(O, /obj/item/flash)) - if(stat != DEAD) - O.attack(src, user, user.zone_sel.selecting) - return - - if(meat_type && (stat == DEAD) && meat_amount) - if(istype(O, /obj/item/knife/kitchen/cleaver)) - var/victim_turf = get_turf(src) - if(!locate(/obj/structure/table, victim_turf)) - to_chat(user, SPAN_NOTICE("You need to place \the [src] on a table to butcher it.")) - return - var/time_to_butcher = (mob_size) - to_chat(user, SPAN_NOTICE("You begin harvesting \the [src].")) - if(do_after(user, time_to_butcher, src, same_direction = TRUE)) - if(prob(user.skill_fail_chance(SKILL_COOKING, 60, SKILL_ADEPT))) - to_chat(user, SPAN_NOTICE("You botch harvesting \the [src], and ruin some of the meat in the process.")) - subtract_meat(user) - return - else - harvest(user, user.get_skill_value(SKILL_COOKING)) - return - else - to_chat(user, SPAN_NOTICE("Your hand slips with your movement, and some of the meat is ruined.")) - subtract_meat(user) - return - - else - if(!O.force) - visible_message("[user] gently taps [src] with \the [O].") - else - O.attack(src, user, user.zone_sel?.selecting || ran_zone()) - -/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) - - visible_message("\The [src] has been attacked with \the [O] by [user]!") - - if(O.force <= resistance) - to_chat(user, "This weapon is ineffective; it does no damage.") - return 0 - - var/damage = O.force - if (O.damtype == PAIN) - damage = 0 - if (O.damtype == STUN) - damage = (O.force / 8) - if(supernatural && istype(O,/obj/item/nullrod)) - damage *= 2 - purge = 3 - adjustBruteLoss(damage) - if(O.edge || O.sharp) - adjustBleedTicks(damage) - - return 1 - -/mob/living/simple_animal/movement_delay() - var/tally = ..() //Incase I need to add stuff other than "speed" later - - tally += speed - if(purge)//Purged creatures will move more slowly. The more time before their purge stops, the slower they'll move. - if(tally <= 0) - tally = 1 - tally *= purge - - return tally+config.animal_delay - -/mob/living/simple_animal/Stat() - . = ..() - - if(statpanel("Status") && show_stat_health) - stat(null, "Health: [round((health / maxHealth) * 100)]%") - -/mob/living/simple_animal/death(gibbed, deathmessage = "dies!", show_dead_message) - icon_state = icon_dead - update_icon() - density = 0 - adjustBruteLoss(maxHealth) //Make sure dey dead. - walk_to(src,0) - return ..(gibbed,deathmessage,show_dead_message) - -/mob/living/simple_animal/explosion_act(severity) - ..() - var/damage - switch(severity) - if(1) - damage = 500 - if(2) - damage = 120 - if(3) - damage = 30 - apply_damage(damage, BRUTE, damage_flags = DAM_EXPLODE) - -/mob/living/simple_animal/adjustBruteLoss(damage) - ..() - updatehealth() - -/mob/living/simple_animal/adjustFireLoss(damage) - ..() - updatehealth() - -/mob/living/simple_animal/adjustToxLoss(damage) - ..() - updatehealth() - -/mob/living/simple_animal/adjustOxyLoss(damage) - ..() - updatehealth() - -/mob/living/simple_animal/proc/SA_attackable(target_mob) - if (isliving(target_mob)) - var/mob/living/L = target_mob - if(!L.stat && L.health >= 0) - return (0) - return 1 - -/mob/living/simple_animal/say(var/message) - var/verb = "says" - if(speak_emote.len) - verb = pick(speak_emote) - - message = sanitize(message) - - ..(message, null, verb) - -/mob/living/simple_animal/get_speech_ending(verb, var/ending) - return verb - -/mob/living/simple_animal/put_in_hands(var/obj/item/W) // No hands. - W.forceMove(get_turf(src)) - return 1 - -// Harvest an animal's delicious byproducts -/mob/living/simple_animal/proc/harvest(var/mob/user, var/skill_level) - var/actual_meat_amount = round(max(1,(meat_amount / 2) + skill_level / 2)) - user.visible_message("\The [user] chops up \the [src]!") - if(meat_type && actual_meat_amount > 0 && (stat == DEAD)) - for(var/i=0;i 0) - bleed_ticks = max(bleed_ticks, amount) - else - bleed_ticks = max(bleed_ticks + amount, 0) - - bleed_ticks = round(bleed_ticks) - -/mob/living/simple_animal/proc/handle_bleeding() - bleed_ticks-- - adjustBruteLoss(1) - - var/obj/effect/decal/cleanable/blood/drip/drip = new(get_turf(src)) - drip.basecolor = bleed_colour - drip.update_icon() - -/mob/living/simple_animal/get_digestion_product() - return /decl/material/liquid/nutriment - -/mob/living/simple_animal/eyecheck() - switch(flash_vulnerability) - if(2 to INFINITY) - return FLASH_PROTECTION_REDUCED - if(1) - return FLASH_PROTECTION_NONE - if(0) - return FLASH_PROTECTION_MAJOR - else - return FLASH_PROTECTION_MAJOR - -/mob/living/simple_animal/proc/reflect_unarmed_damage(var/mob/living/carbon/human/attacker, var/damage_type, var/description) - if(attacker.a_intent == I_HURT) - var/hand_hurtie - if(attacker.hand) - hand_hurtie = BP_L_HAND - else - hand_hurtie = BP_R_HAND - attacker.apply_damage(rand(return_damage_min, return_damage_max), damage_type, hand_hurtie, used_weapon = description) - if(rand(25)) - to_chat(attacker, SPAN_WARNING("Your attack has no obvious effect on \the [src]'s [description]!")) - - -/mob/living/simple_animal/proc/get_natural_weapon() - if(ispath(natural_weapon)) - natural_weapon = new natural_weapon(src) - return natural_weapon \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/simple_animal_codex.dm b/code/modules/mob/living/simple_animal/simple_animal_codex.dm new file mode 100644 index 000000000000..c20f185993f7 --- /dev/null +++ b/code/modules/mob/living/simple_animal/simple_animal_codex.dm @@ -0,0 +1,2 @@ +/datum/codex_entry/scannable/fauna + category = /decl/codex_category/fauna diff --git a/code/modules/mob/living/simple_animal/simple_animal_damage.dm b/code/modules/mob/living/simple_animal/simple_animal_damage.dm new file mode 100644 index 000000000000..479dc1004fbe --- /dev/null +++ b/code/modules/mob/living/simple_animal/simple_animal_damage.dm @@ -0,0 +1,78 @@ +/mob/living/simple_animal + var/brute_damage = 0 + var/burn_damage = 0 + /// Set to -1 to disable gene damage for the mob. + var/gene_damage = 0 + +/mob/living/simple_animal/getFireLoss() + return burn_damage + +/mob/living/simple_animal/getBruteLoss() + return brute_damage + +/mob/living/simple_animal/getCloneLoss() + . = max(0, gene_damage) + +/mob/living/simple_animal/adjustCloneLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(FALSE) + set_damage(CLONE, gene_damage + amount) + if(do_update_health) + update_health() + +/mob/living/simple_animal/setCloneLoss(amount) + if(gene_damage >= 0) + var/current_max_health = get_max_health() + gene_damage = clamp(amount, 0, current_max_health) + if(gene_damage >= current_max_health) + death() + +/mob/living/simple_animal/get_life_damage_types() + var/static/list/life_damage_types = list( + BURN, + BRUTE, + CLONE + ) + return life_damage_types + +/mob/living/simple_animal/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + brute_damage = clamp(brute_damage + amount, 0, get_max_health()) + . = ..() + +/mob/living/simple_animal/adjustFireLoss(var/amount, var/do_update_health = TRUE) + burn_damage = clamp(burn_damage + amount, 0, get_max_health()) + if(do_update_health) + update_health() + if(amount > 0 && istype(ai)) + ai.retaliate() + +/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) + + var/attack_name = O?.attack_message_name() + if(attack_name) + visible_message(SPAN_DANGER("\The [src] has been [O.pick_attack_verb()] with [attack_name] by \the [user]!")) + else + visible_message(SPAN_DANGER("\The [src] has been [O.pick_attack_verb()] by \the [user]!")) + + if(istype(ai)) + ai.retaliate(user) + + var/damage = O.expend_attack_force(user) + if(damage <= resistance) + to_chat(user, SPAN_WARNING("This weapon is ineffective; it does no damage.")) + return 0 + + if (O.atom_damage_type == PAIN) + damage = 0 + if (O.atom_damage_type == STUN) + damage = (damage / 8) + if(supernatural && istype(O,/obj/item/nullrod)) + damage *= 2 + purge = 3 + take_damage(damage, O.atom_damage_type, O.damage_flags()) + + return 1 + +/mob/living/simple_animal/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + . = ..() + if((damage_type == BRUTE) && (damage_flags & (DAM_EDGE | DAM_SHARP | DAM_BULLET))) // damage flags that should cause bleeding + adjustBleedTicks(damage) diff --git a/code/modules/mob/living/simple_animal/simple_animal_serde.dm b/code/modules/mob/living/simple_animal/simple_animal_serde.dm new file mode 100644 index 000000000000..377ffd04b6ce --- /dev/null +++ b/code/modules/mob/living/simple_animal/simple_animal_serde.dm @@ -0,0 +1,34 @@ +// Very basic serde for simple animals for things like the Shaded Hills submap. +/mob/living/simple_animal/ShouldSerialize(_age) + return simulated + +/mob/living/simple_animal/GetPossiblySerializableInstances() + return list(src) + +/mob/living/simple_animal/Serialize() + . = ..() + + SERIALIZE_IF_MODIFIED(name, /mob/living/simple_animal) + SERIALIZE_IF_MODIFIED(desc, /mob/living/simple_animal) + SERIALIZE_IF_MODIFIED(icon_state, /mob/living/simple_animal) + + SERIALIZE_IF_MODIFIED(purge, /mob/living/simple_animal) + SERIALIZE_IF_MODIFIED(eye_color, /mob/living/simple_animal) + SERIALIZE_IF_MODIFIED(brute_damage, /mob/living/simple_animal) + SERIALIZE_IF_MODIFIED(burn_damage, /mob/living/simple_animal) + SERIALIZE_IF_MODIFIED(gene_damage, /mob/living/simple_animal) + + var/list/defaults = get_default_animal_colours() + var/changed_from_defaults = length(defaults) != length(draw_visible_overlays) + if(!changed_from_defaults && islist(draw_visible_overlays)) + for(var/animal_color in defaults) + if(!(animal_color in draw_visible_overlays) || defaults[animal_color] != draw_visible_overlays[animal_color]) + changed_from_defaults = TRUE + break + if(!changed_from_defaults) + for(var/animal_color in draw_visible_overlays) + if(!(animal_color in defaults) || defaults[animal_color] != draw_visible_overlays[animal_color]) + changed_from_defaults = TRUE + break + if(changed_from_defaults) + SERIALIZE_VALUE(draw_visible_overlays, /mob/living/simple_animal, json_encode(draw_visible_overlays)) diff --git a/code/modules/mob/living/stasis.dm b/code/modules/mob/living/stasis.dm new file mode 100644 index 000000000000..256e98026747 --- /dev/null +++ b/code/modules/mob/living/stasis.dm @@ -0,0 +1,21 @@ +/mob/living/proc/get_cryogenic_factor(var/bodytemperature) + + if(isSynthetic()) + return 0 + + var/cold_1 = get_mob_temperature_threshold(COLD_LEVEL_1) + var/cold_2 = get_mob_temperature_threshold(COLD_LEVEL_2) + var/cold_3 = get_mob_temperature_threshold(COLD_LEVEL_3) + + if(bodytemperature > cold_1) + return 0 + if(bodytemperature > cold_2) + . = 5 * (1 - (bodytemperature - cold_2) / (cold_1 - cold_2)) + . = max(2, .) + else if(bodytemperature > cold_3) + . = 20 * (1 - (bodytemperature - cold_3) / (cold_2 - cold_3)) + . = max(5, .) + else + . = 80 * (1 - bodytemperature / cold_3) + . = max(20, .) + return round(.) diff --git a/code/modules/mob/living/stress.dm b/code/modules/mob/living/stress.dm new file mode 100644 index 000000000000..2cb46e0c27b8 --- /dev/null +++ b/code/modules/mob/living/stress.dm @@ -0,0 +1,93 @@ +#define GET_STRESSOR(S) (istype(S, /datum/stressor) ? S : SSmanaged_instances.get(S, cache_category = /datum/stressor)) + +/mob/living/proc/get_stress_modifier() + if(!get_config_value(/decl/config/toggle/health_adjust_healing_from_stress)) + return 0 + return stress + +/mob/living/proc/add_stressor(var/stressor_id, duration) + var/datum/stressor/stressor = GET_STRESSOR(stressor_id) + if(stressor in stressors) + stressor.refresh(src, duration) + else + if(length(stressor.incompatible_with_stressors)) + for(var/datum/stressor/other_stressor in stressor.incompatible_with_stressors) + if(other_stressor in stressors) + return FALSE + stressor.add_to(src, duration) + return TRUE + +/mob/living/proc/remove_stressor(var/stressor_id) + var/datum/stressor/stressor = GET_STRESSOR(stressor_id) + if(stressor in stressors) + stressor.remove_from(src) + return TRUE + return FALSE + +/mob/living/proc/update_stress() + set waitfor = FALSE + if(currently_updating_stress) + return + currently_updating_stress = TRUE + sleep(1) + stress = 0 + // Work out what stressors we're hiding. + var/list/suppressed = list() + for(var/datum/stressor/stressor as anything in stressors) + if(length(stressor.suppress_stressors)) + suppressed |= stressor.suppress_stressors + // Accumulate our current stress. + for(var/datum/stressor/stressor as anything in stressors) + var/add_stress = stressor.tick(src) + if(!(stressor in suppressed)) + stress += add_stress + stress = clamp(stress, MIN_STRESS, MAX_STRESS) + currently_updating_stress = FALSE + +/mob/living/verb/check_stressors() + + set name = "Check Stressors" + set category = "IC" + set src = usr + + if(incapacitated(INCAPACITATION_KNOCKOUT)) + to_chat(src, SPAN_WARNING("You are in no state for accurate self-assessment.")) + return + + if(length(stressors)) + + var/list/suppressed = list() + for(var/datum/stressor/stressor as anything in stressors) + if(length(stressor.suppress_stressors)) + suppressed |= stressor.suppress_stressors + + to_chat(src, SPAN_NOTICE("You are currently...")) + for(var/datum/stressor/stressor as anything in stressors) + if(stressor in suppressed) + continue + if(stressor.stress_value < 0) + to_chat(src, "[SPAN_GOOD("...[stressor.desc]")]") + else if(stressor.stress_value > 0) + to_chat(src, "[SPAN_BAD("...[stressor.desc]")]") + else + to_chat(src, "[SPAN_NEUTRAL("...[stressor.desc]")]") + + // TODO: less loaded/more informative terminology + var/stress_string + if(stress <= -1) + stress_string = "extremely relaxed" + else if(stress <= -0.65) + stress_string = "somewhat relaxed" + else if(stress <= -0.35) + stress_string = "relaxed" + else if(stress >= 0.35) + stress_string = "stressed" + else if(stress >= 0.65) + stress_string = "somewhat stressed" + else if(stress >= 1) + stress_string = "extremely stressed" + else + stress_string = "neither stressed nor relaxed" + to_chat(src, SPAN_NEUTRAL("Overall, you are feeling [stress_string].")) + +#undef GET_STRESSOR diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index ba1e34dcae5d..23e4895e065a 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -5,9 +5,9 @@ computer_id = client.computer_id last_ckey = ckey log_access("Login: [key_name(src)] from [lastKnownIP ? lastKnownIP : "localhost"]-[computer_id] || BYOND v[client.byond_version]") - if(config.log_access) + if(get_config_value(/decl/config/toggle/log_access)) var/is_multikeying = 0 - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(M == src) continue if( M.key && (M.key != key) ) var/matches @@ -19,17 +19,18 @@ is_multikeying = 1 if(matches) if(M.client) - message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)].", 1) + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)].", 1) log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)].") else - message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)] (no longer logged in). ", 1) + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)] (no longer logged in). ", 1) log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).") if(is_multikeying && !client.warned_about_multikeying) client.warned_about_multikeying = 1 spawn(1 SECOND) to_chat(src, "WARNING: It would seem that you are sharing connection or computer with another player. If you haven't done so already, please contact the staff via the Adminhelp verb to resolve this situation. Failure to do so may result in administrative action. You have been warned.") - if(config.login_export_addr) + var/login_export_addr = get_config_value(/decl/config/text/login_export_addr) + if(login_export_addr) spawn(-1) var/list/params = new params["login"] = 1 @@ -40,17 +41,17 @@ params["clientid"] = client.computer_id params["roundid"] = game_id params["name"] = real_name || name - world.Export("[config.login_export_addr]?[list2params(params)]", null, 1) + world.Export("[login_export_addr]?[list2params(params)]", null, 1) /mob/proc/maybe_send_staffwarns(var/action) if(client.staffwarn) - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) send_staffwarn(C, action) /mob/proc/send_staffwarn(var/client/C, var/action, var/noise = 1) if(check_rights((R_ADMIN|R_MOD),0,C)) to_chat(C,"StaffWarn: [client.ckey] [action]
    [client.staffwarn]") - if(noise && C.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == GLOB.PREF_HEAR) + if(noise && C.get_preference_value(/datum/client_preference/staff/play_adminhelp_ping) == PREF_HEAR) sound_to(C, 'sound/effects/adminhelp.ogg') /mob @@ -58,7 +59,8 @@ /mob/Login() - GLOB.player_list |= src + client.clear_mouse_pointers() // in case we are transferring mobs. + global.player_list |= src update_Login_details() world.update_status() @@ -66,20 +68,15 @@ client.images = null //remove the images such as AIs being unable to see runes client.screen = list() //remove hud items just in case - InitializeHud() + client.set_right_click_menu_mode(shift_to_open_context_menu) next_move = 1 set_sight(sight|SEE_SELF) + ..() my_client = client - if(get_preference_value(/datum/client_preference/chat_position) == GLOB.PREF_YES) - client.update_chat_position(TRUE) - - if(get_preference_value(/datum/client_preference/fullscreen_mode) != GLOB.PREF_OFF) - client.toggle_fullscreen(get_preference_value(/datum/client_preference/fullscreen_mode)) - if(loc && !isturf(loc)) client.eye = loc client.perspective = EYE_PERSPECTIVE @@ -90,24 +87,43 @@ if(eyeobj) eyeobj.possess(src) - l_plane = new() - l_general = new() - client.screen += l_plane - client.screen += l_general + RAISE_EVENT(/decl/observ/logged_in, src) + + hud_reset(TRUE) + if(istype(machine)) + machine.on_user_login(src) + +/mob/proc/hud_reset(var/full_reset = FALSE) + if(!client) + return + if(full_reset) + client.images = null //remove the images such as AIs being unable to see runes + client.screen = list() //remove hud items just in case + client.set_right_click_menu_mode(shift_to_open_context_menu) + initialize_hud() + + refresh_lighting_master() + client.update_skybox(full_reset) // readd to client.screen if we cleared it refresh_client_images() reload_fullscreen() // Reload any fullscreen overlays this mob has. add_click_catcher() update_action_buttons() + update_mouse_pointer() - if(machine) - machine.on_user_login(src) + if(get_preference_value(/datum/client_preference/show_status_markers) == PREF_SHOW) + if(status_markers?.mob_image_personal) + client.images |= status_markers.mob_image_personal + for(var/datum/status_marker_holder/marker in global.status_marker_holders) + if(marker.mob_image && marker != status_markers) + client.images |= marker.mob_image + + for(var/obj/item/gear in get_equipped_items(TRUE)) + client.screen |= gear - //set macro to normal incase it was overriden (like cyborg currently does) - winset(src, null, "mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#d3b5b5") - client.OnResize() + if(istype(hud_used)) + hud_used.hidden_inventory_update() + hud_used.persistent_inventory_update() + update_action_buttons() -/mob/living/carbon/Login() - . = ..() - if(internals && internal) - internals.icon_state = "internal1" + return TRUE diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index 00d67b5d51e8..0ba52c5a1a06 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -1,14 +1,12 @@ /mob/Logout() + + RAISE_EVENT(/decl/observ/logged_out, src, my_client) SSnano.user_logout(src) // this is used to clean up (remove) this user's Nano UIs - GLOB.player_list -= src + global.player_list -= src log_access("Logout: [key_name(src)]") - if(my_client) - my_client.screen -= l_general - my_client.screen -= l_plane - QDEL_NULL(l_general) - QDEL_NULL(l_plane) + hide_client_images() - ..() + SStyping.set_indicator_state(client, FALSE) + . = ..() my_client = null - return 1 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index af14eec56265..286b28d1689a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1,66 +1,65 @@ -/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. +/mob/Destroy() //This makes sure that mobs with clients/keys are not just deleted from the game. + + stop_automove() + STOP_PROCESSING(SSmobs, src) - GLOB.dead_mob_list_ -= src - GLOB.living_mob_list_ -= src - GLOB.player_list -= src + global.dead_mob_list_ -= src + global.living_mob_list_ -= src + global.player_list -= src + + QDEL_NULL_LIST(pinned) + QDEL_NULL_LIST(embedded) + + QDEL_NULL(typing_indicator) + unset_machine() - QDEL_NULL(hud_used) - if(istype(ability_master)) - QDEL_NULL(ability_master) + if(istype(hud_used)) + QDEL_NULL(hud_used) + if(active_storage) + active_storage.close(src) if(istype(skillset)) QDEL_NULL(skillset) QDEL_NULL_LIST(grabbed_by) clear_fullscreen() - QDEL_NULL(ai) + if(istype(ai)) + QDEL_NULL(ai) + QDEL_NULL(lighting_master) if(client) - remove_screen_obj_references() for(var/atom/movable/AM in client.screen) var/obj/screen/screenobj = AM - if(!istype(screenobj) || !screenobj.globalscreen) + if(istype(screenobj) && !screenobj.is_global_screen) qdel(screenobj) client.screen = list() - if(mind && mind.current == src) - spellremove(src) + if(mind) + mind.handle_mob_deletion(src) + teleop = null ghostize() - ..() - return QDEL_HINT_HARDDEL - -/mob/proc/remove_screen_obj_references() - hands = null - purged = null - internals = null - oxygen = null - i_select = null - m_select = null - toxin = null - fire = null - bodytemp = null - healths = null - throw_icon = null - nutrition_icon = null - pressure = null - pain = null - item_use_icon = null - gun_move_icon = null - gun_setting_icon = null - ability_master = null - zone_sel = null + return ..() /mob/Initialize() - . = ..() - skillset = new skillset(src) - if(!move_intent) + if(ispath(skillset)) + skillset = new skillset(src) + if(!ispath(move_intent) || !(move_intent in move_intents)) move_intent = move_intents[1] - if(ispath(move_intent)) - move_intent = decls_repository.get_decl(move_intent) + if(!istype(move_intent)) + move_intent = GET_DECL(move_intent) + . = ..() + refresh_ai_handler() + START_PROCESSING(SSmobs, src) + +/mob/proc/refresh_ai_handler() var/ai_type = get_ai_type() + if(istype(ai)) + if(ai_type == ai.type) + return // No need to refresh. + QDEL_NULL(ai) if(ai_type) ai = new ai_type(src) - START_PROCESSING(SSmobs, src) /mob/proc/get_ai_type() - if (ispath(ai)) - return ai + var/ai_type = initial(ai) + if(ispath(ai_type)) + return ai_type /mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) if(!client) return @@ -90,11 +89,11 @@ // message is the message output to anyone who can see e.g. "[src] does something!" // self_message (optional) is what the src mob sees e.g. "You do something!" // blind_message (optional) is what blind people will hear e.g. "You hear something!" -/mob/visible_message(var/message, var/self_message, var/blind_message, var/range = world.view, var/checkghosts = null, var/narrate = FALSE) +/mob/visible_message(var/message, var/self_message, var/blind_message, var/range = world.view, var/check_ghosts = null, var/narrate = FALSE) var/turf/T = get_turf(src) var/list/mobs = list() var/list/objs = list() - get_mobs_and_objs_in_view_fast(T, range, mobs, objs, checkghosts) + get_listeners_in_range(T, range, mobs, objs, check_ghosts) for(var/o in objs) var/obj/O = o @@ -124,17 +123,133 @@ if(bound_overlay) bound_overlay.visible_message(message, self_message, blind_message) +/mob/proc/get_action_string(is_self, var/using_verb, var/object_phrase, var/infix, var/postfix) + var/decl/pronouns/using_pronouns = is_self ? get_self_pronouns() : get_visible_pronouns() + // A little kludgy/special-cased: we don't use the name for self messages. + var/actor_string = is_self ? using_pronouns.He : "\The [src]" + // this will hopefully handle is/does/has agreement properly + . = "[actor_string] [verb_agree_with_pronouns(using_verb, using_pronouns, is_after_pronoun = is_self)] [infix ? infix + " " : null][object_phrase][postfix ? " " + postfix : null]" + // uh oh, time to handle tokens. + . = replacetext(., "$USER$", "\the [src]") + . = replacetext(., "$USER'S$", "\the [src]'s") + . = replacetext(., "$USER_THEY$", using_pronouns.he) + . = replacetext(., "$USER_THEM$", using_pronouns.him) + . = replacetext(., "$USER_THEIR$", using_pronouns.his) + . = replacetext(., "$USER_SELF$", using_pronouns.self) + . = replacetext(., "$USER_DOES$", using_pronouns.does) + . = replacetext(., "$USER_HAS$", using_pronouns.has) + . = replacetext(., "$USER_IS$", using_pronouns.is) + . = replacetext(., "$USER_S$", using_pronouns.s) + . = replacetext(., "$USER_ES$", using_pronouns.es) + +/mob/proc/get_targeted_action_string(mob/target, is_self, var/using_verb, var/object_phrase, var/infix, var/postfix) + . = get_action_string(is_self, using_verb, object_phrase, infix, postfix) + var/target_is_self = target == src + var/decl/pronouns/target_pronouns = target_is_self ? target.get_self_pronouns() : target.get_visible_pronouns() + // A little kludgy/special-cased: we don't use the name if it's self-targeted, regardless of who's viewing + . = replacetext(., "$TARGET$", target_is_self ? target_pronouns.self : "\the [target]") + . = replacetext(., "$TARGET'S$", target_is_self ? target_pronouns.his : "\the [target]'s") + . = replacetext(., "$TARGET_THEM$", target_is_self ? target_pronouns.self : target_pronouns.him) // reflexive if self, so use self instead of them + . = replacetext(., "$TARGET_THEIR$", target_pronouns.his) + . = replacetext(., "$TARGET_THEY$", target_pronouns.he) + . = replacetext(., "$TARGET_DOES$", target_pronouns.does) + . = replacetext(., "$TARGET_HAS$", target_pronouns.has) + . = replacetext(., "$TARGET_IS$", target_pronouns.is) + . = replacetext(., "$TARGET_S$", target_pronouns.s) + . = replacetext(., "$TARGET_ES$", target_pronouns.es) + +// Determines span styling used for visible_action_message. +/// Uses SPAN_NOTICE for both self and other messages. +var/global/const/ACTION_DANGER_NONE = 0 +/// Uses SPAN_DANGER for others and SPAN_WARNING for self. +var/global/const/ACTION_DANGER_OTHERS = 1 +/// Uses SPAN_DANGER for both self and others. +var/global/const/ACTION_DANGER_ALL = 2 +/** + Show an action message to all mobs and objects in sight of this mob. + + Used for atoms performing visible actions. Handles basic self-messages automatically. + + - `using_verb`: The verb to use in the message, e.g. "open", "is", "attack". Should be in the base form (no "s" at the end). + - `object_phrase`: The phrase to use after the verb, e.g. "\the [used_item]". Could be a phrase including a gerund or infinitive, like "repairing \the [machine]." + - `dangerous?`: One of the ACTION_DANGER_* constants, determining the styling of the message, OR a string style class. Default: ACTION_DANGER_NONE + - `blind_message?`: The string blind mobs will see. Example: "You hear something!" Default: null + - `range?`: The number of tiles away the message will be visible from. Default: world.view + - `self_infix?`: An optional infix to insert between the verb and object phrase in the self message. Default: null + - `self_postfix?`: An optional postfix to insert after the object phrase in the self message. Default: null + - `other_infix?`: An optional infix to insert between the verb and object phrase in the other message. Default: null + - `other_postfix?`: An optional postfix to insert after the object phrase in the other message. Default: null +*/ +/mob/proc/visible_action_message(var/using_verb, var/object_phrase, var/dangerous = ACTION_DANGER_NONE, var/blind_message = null, var/range = world.view, var/self_infix = null, var/self_postfix = null, var/other_infix = null, var/other_postfix = null) + var/self_message = get_action_string(TRUE, using_verb, object_phrase, self_infix, self_postfix) + var/other_message = get_action_string(FALSE, using_verb, object_phrase, other_infix, other_postfix) + switch(dangerous) + if(ACTION_DANGER_NONE) + other_message = SPAN_NOTICE(other_message) + self_message = SPAN_NOTICE(self_message) + if(ACTION_DANGER_OTHERS) + other_message = SPAN_DANGER(other_message) + self_message = SPAN_WARNING(self_message) + if(ACTION_DANGER_ALL) + other_message = SPAN_DANGER(other_message) + self_message = SPAN_DANGER(self_message) + else // fallback for stuff like lighter styling + other_message = SPAN_CLASS(dangerous, other_message) + self_message = SPAN_CLASS(dangerous, self_message) + visible_message( + other_message, + self_message, + blind_message, + range + ) + +/mob/proc/targeted_visible_action_message(var/mob/target, var/using_verb, var/object_phrase, var/dangerous = ACTION_DANGER_NONE, var/blind_message = null, var/range = world.view, var/self_infix = null, var/self_postfix = null, var/other_infix = null, var/other_postfix = null) + var/self_message = get_targeted_action_string(target, TRUE, using_verb, object_phrase, self_infix, self_postfix) + var/other_message = get_targeted_action_string(target, FALSE, using_verb, object_phrase, other_infix, other_postfix) + switch(dangerous) + if(ACTION_DANGER_NONE) + other_message = SPAN_NOTICE(other_message) + self_message = SPAN_NOTICE(self_message) + if(ACTION_DANGER_OTHERS) + other_message = SPAN_DANGER(other_message) + self_message = SPAN_WARNING(self_message) + if(ACTION_DANGER_ALL) + other_message = SPAN_DANGER(other_message) + self_message = SPAN_DANGER(self_message) + else // fallback for stuff like lighter styling + other_message = SPAN_CLASS(dangerous, other_message) + self_message = SPAN_CLASS(dangerous, self_message) + visible_message( + other_message, + self_message, + blind_message, + range + ) + +/mob/proc/self_action_message(var/using_verb, var/object_phrase, var/dangerous = ACTION_DANGER_NONE, var/infix, var/postfix) + var/the_message = get_targeted_action_string(src, TRUE, using_verb, object_phrase, infix, postfix) + switch(dangerous) + if(ACTION_DANGER_NONE) + the_message = SPAN_NOTICE(the_message) + if(ACTION_DANGER_OTHERS) + the_message = SPAN_WARNING(the_message) + if(ACTION_DANGER_ALL) + the_message = SPAN_DANGER(the_message) + else // fallback for stuff like lighter styling + the_message = SPAN_CLASS(dangerous, the_message) + to_chat(src, the_message) + // Show a message to all mobs and objects in earshot of this one // This would be for audible actions by the src mob // message is the message output to anyone who can hear. // self_message (optional) is what the src mob hears. // deaf_message (optional) is what deaf people will see. // hearing_distance (optional) is the range, how many tiles away the message can be heard. -/mob/audible_message(var/message, var/self_message, var/deaf_message, var/hearing_distance = world.view, var/checkghosts = null, var/narrate = FALSE) +/mob/audible_message(var/message, var/self_message, var/deaf_message, var/hearing_distance = world.view, var/check_ghosts = null, var/narrate = FALSE, var/radio_message) var/turf/T = get_turf(src) var/list/mobs = list() var/list/objs = list() - get_mobs_and_objs_in_view_fast(T, hearing_distance, mobs, objs, checkghosts) + get_listeners_in_range(T, hearing_distance, mobs, objs, check_ghosts) for(var/m in mobs) var/mob/M = m @@ -147,20 +262,23 @@ if(self_message && M == src) M.show_message(self_message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) - else if(M.see_invisible >= invisibility || narrate) // Cannot view the invisible + else if(is_invisible_to(M) || narrate) // Cannot view the invisible M.show_message(mob_message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) else M.show_message(mob_message, AUDIBLE_MESSAGE) for(var/o in objs) var/obj/O = o - O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) + if(radio_message) + O.hear_talk(src, radio_message, null, GET_DECL(/decl/language/noise)) + else + O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE) /mob/proc/add_ghost_track(var/message, var/mob/observer/ghost/M) ASSERT(istype(M)) var/remote = "" - if(M.get_preference_value(/datum/client_preference/ghost_sight) == GLOB.PREF_ALL_EMOTES && !(src in view(M))) + if(M.get_preference_value(/datum/client_preference/ghost_sight) == PREF_ALL_EMOTES && !(src in view(M))) remote = "\[R\]" var/track = "([ghost_follow_link(src, M)])" @@ -170,7 +288,7 @@ /mob/proc/ghost_skip_message(var/mob/observer/ghost/M) ASSERT(istype(M)) - if(M.get_preference_value(/datum/client_preference/ghost_sight) == GLOB.PREF_ALL_EMOTES && !(src in view(M))) + if(M.get_preference_value(/datum/client_preference/ghost_sight) == PREF_ALL_EMOTES && !(src in view(M))) if(!client) return TRUE return FALSE @@ -182,37 +300,30 @@ /atom/proc/drain_power(var/drain_check,var/surge, var/amount = 0) return -1 -/mob/proc/findname(msg) - for(var/mob/M in SSmobs.mob_list) - if (M.real_name == msg) - return M - return 0 - -/mob/proc/movement_delay() +#define ENCUMBERANCE_MOVEMENT_MOD 0.35 +/mob/proc/get_movement_delay(var/travel_dir) . = 0 - if(istype(loc, /turf)) + if(isturf(loc)) var/turf/T = loc - . += T.movement_delay - - if (drowsyness > 0) + . += T.get_terrain_movement_delay(travel_dir, src) + if(HAS_STATUS(src, STAT_DROWSY)) . += 6 - if(lying) //Crawling, it's slower - . += (8 + ((weakened * 3) + (confused * 2))) - . += move_intent.move_delay - . += encumbrance() * (0.5 + 1.5 * (SKILL_MAX - get_skill_value(SKILL_HAULING))/(SKILL_MAX - SKILL_MIN)) //Varies between 0.5 and 2, depending on skill + if(current_posture.prone) //Crawling, it's slower + . += (8 + ((GET_STATUS(src, STAT_WEAK) * 3) + (GET_STATUS(src, STAT_CONFUSE) * 2))) + var/_automove_delay = get_automove_delay() + if(isnull(_automove_delay)) + . += move_intent.move_delay + else + . += _automove_delay + . = max(. + (ENCUMBERANCE_MOVEMENT_MOD * encumbrance()), 1) + +#undef ENCUMBERANCE_MOVEMENT_MOD /mob/proc/encumbrance() - for(var/obj/item/grab/G in get_active_grabs()) - var/atom/movable/pulling = G.affecting - if(istype(pulling, /obj)) - var/obj/O = pulling - . += between(0, O.w_class, ITEM_SIZE_GARGANTUAN) / 5 - else if(istype(pulling, /mob)) - var/mob/M = pulling - . += max(0, M.mob_size) / MOB_SIZE_MEDIUM - else - . += 1 + for(var/obj/item/grab/grab as anything in get_active_grabs()) + . = max(., grab.grab_slowdown()) . *= (0.8 ** size_strength_mod()) + . *= (0.5 + 1.5 * (SKILL_MAX - get_skill_value(SKILL_HAULING))/(SKILL_MAX - SKILL_MIN)) //Determines mob size/strength effects for slowdown purposes. Standard is 0; can be pos/neg. /mob/proc/size_strength_mod() @@ -220,6 +331,8 @@ /mob/proc/Life() SHOULD_NOT_SLEEP(TRUE) + if(QDELETED(src)) + return PROCESS_KILL #define UNBUCKLED 0 #define PARTIALLY_BUCKLED 1 @@ -232,10 +345,10 @@ return restrained() ? FULLY_BUCKLED : PARTIALLY_BUCKLED /mob/proc/is_blind() - return ((sdisabilities & BLINDED) || blinded || incapacitated(INCAPACITATION_KNOCKOUT)) + return (has_genetic_condition(GENE_COND_BLINDED) || incapacitated(INCAPACITATION_KNOCKOUT) || HAS_STATUS(src, STAT_BLIND)) /mob/proc/is_deaf() - return ((sdisabilities & DEAFENED) || ear_deaf || incapacitated(INCAPACITATION_KNOCKOUT)) + return (has_genetic_condition(GENE_COND_DEAFENED) || incapacitated(INCAPACITATION_KNOCKOUT) || HAS_STATUS(src, STAT_DEAF)) /mob/proc/is_physically_disabled() return incapacitated(INCAPACITATION_DISABLED) @@ -243,82 +356,175 @@ /mob/proc/cannot_stand() return incapacitated(INCAPACITATION_KNOCKDOWN) +/mob/living/incapacitated(var/incapacitation_flags = INCAPACITATION_DEFAULT) + . = ..() + if(!.) + if((incapacitation_flags & INCAPACITATION_STUNNED) && HAS_STATUS(src, STAT_STUN)) + return TRUE + if((incapacitation_flags & INCAPACITATION_FORCELYING) && HAS_STATUS(src, STAT_WEAK)) + return TRUE + if((incapacitation_flags & INCAPACITATION_KNOCKOUT) && (HAS_STATUS(src, STAT_PARA) || HAS_STATUS(src, STAT_ASLEEP))) + return TRUE + if((incapacitation_flags & INCAPACITATION_WEAKENED) && HAS_STATUS(src, STAT_WEAK)) + return TRUE + /mob/proc/incapacitated(var/incapacitation_flags = INCAPACITATION_DEFAULT) if(status_flags & ENABLE_AI) - return 1 - - if ((incapacitation_flags & INCAPACITATION_STUNNED) && stunned) - return 1 - - if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (weakened || resting || pinned.len)) - return 1 - - if ((incapacitation_flags & INCAPACITATION_KNOCKOUT) && (stat || paralysis || sleeping || (status_flags & FAKEDEATH))) - return 1 - + return TRUE + if((incapacitation_flags & INCAPACITATION_FORCELYING) && LAZYLEN(pinned)) + return TRUE if((incapacitation_flags & INCAPACITATION_RESTRAINED) && restrained()) - return 1 - + return TRUE + if((incapacitation_flags & INCAPACITATION_KNOCKOUT) && (stat || (status_flags & FAKEDEATH))) + return TRUE if((incapacitation_flags & (INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY))) var/buckling = buckled() if(buckling >= PARTIALLY_BUCKLED && (incapacitation_flags & INCAPACITATION_BUCKLED_PARTIALLY)) - return 1 + return TRUE if(buckling == FULLY_BUCKLED && (incapacitation_flags & INCAPACITATION_BUCKLED_FULLY)) - return 1 - - if((incapacitation_flags & INCAPACITATION_WEAKENED) && weakened) - return 1 - - return 0 + return TRUE + return FALSE #undef UNBUCKLED #undef PARTIALLY_BUCKLED #undef FULLY_BUCKLED +/mob/proc/grab_restrained() + for (var/obj/item/grab/grab as anything in grabbed_by) + if(grab.restrains()) + return TRUE + /mob/proc/restrained() - return + if(get_equipped_item(slot_handcuffed_str)) + return TRUE + if(grab_restrained()) + return TRUE + if (istype(get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/straight_jacket)) + return TRUE + return FALSE /mob/proc/reset_view(atom/A) - if (client) - client.pixel_x = initial(client.pixel_x) - client.pixel_y = initial(client.pixel_y) - A = A ? A : eyeobj - if (istype(A, /atom/movable)) - client.perspective = EYE_PERSPECTIVE - client.eye = A - else - if (isturf(loc)) - client.eye = client.mob - client.perspective = MOB_PERSPECTIVE - else - client.perspective = EYE_PERSPECTIVE - client.eye = loc - return + set waitfor = 0 + while((shakecamera > world.time) && client && !QDELETED(src)) + sleep(1) + if(!client || QDELETED(src)) + return + client.default_pixel_x = initial(client.default_pixel_x) + client.default_pixel_y = initial(client.default_pixel_y) + client.pixel_x = client.default_pixel_x + client.pixel_y = client.default_pixel_y + A = A ? A : eyeobj + if (istype(A, /atom/movable)) + client.perspective = EYE_PERSPECTIVE + client.eye = A + else if (isturf(loc)) + client.eye = client.mob + client.perspective = MOB_PERSPECTIVE + else + client.perspective = EYE_PERSPECTIVE + client.eye = loc +/mob/proc/get_descriptive_slot_name(var/slot) + if(global.abstract_slot_names[slot]) // this is an abstract slot like "in backpack" + return global.abstract_slot_names[slot] + var/datum/inventory_slot/slot_datum = get_inventory_slot_datum(slot) + return slot_datum?.slot_name || slot -/mob/proc/show_inv(mob/user) +/mob/proc/show_stripping_window(mob/user) + + if(user.incapacitated() || !user.Adjacent(src) || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) + return + + user.set_machine(src) + + var/dat = list() + dat += "


    [name]" + dat += "
    " + + var/list/my_held_item_slots = get_held_item_slots() + for(var/hand_slot in my_held_item_slots) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + if(!inv_slot || inv_slot.skip_on_strip_display) + continue + var/obj/item/held = inv_slot.get_equipped_item() + dat += "[capitalize(inv_slot.slot_name)]: [held?.name || "nothing"]" + + var/list/all_slots = get_all_available_equipment_slots() + if(all_slots) + for(var/slot in (all_slots-global.pocket_slots)) + if(slot in my_held_item_slots) + continue + var/obj/item/thing_in_slot = get_equipped_item(slot) + dat += "[capitalize(get_descriptive_slot_name(slot))]: [thing_in_slot || "nothing"]" + if(istype(thing_in_slot, /obj/item/clothing)) + var/obj/item/clothing/C = thing_in_slot + if(LAZYLEN(C.accessories)) + dat += "Remove accessory" + + // Do they get an option to set internals? + if(istype(get_equipped_item(slot_wear_mask_str), /obj/item/clothing/mask) || istype(get_equipped_item(slot_head_str), /obj/item/clothing/head/helmet/space)) + for(var/slot in list(slot_back_str, slot_belt_str, slot_s_store_str)) + var/obj/item/tank/tank = get_equipped_item(slot) + if(istype(tank)) + dat += "
    Toggle internals." + break + + // Other incidentals. + var/obj/item/clothing/suit = get_equipped_item(slot_w_uniform_str) + if(istype(suit)) + dat += "
    Pockets: Empty or Place Item" + var/obj/item/clothing/sensor/vitals/sensor = get_vitals_sensor() + if(sensor) + if(sensor.get_sensors_locked()) + dat += "
    Unlock vitals sensors" + else if(user.get_multitool()) + dat += "
    Lock vitals sensors" + dat += "
    Set vitals sensors" + if(get_equipped_item(slot_handcuffed_str)) + dat += "
    Handcuffed" + + var/list/strip_add = get_additional_stripping_options() + if(length(strip_add)) + dat += strip_add + + dat += "
    Refresh" + + var/datum/browser/popup = new(user, "[name]", "Inventory of \the [name]", 325, 500, src) + popup.set_content(jointext(dat, "
    ")) + popup.open() + +/mob/proc/get_additional_stripping_options() return -//mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine() -/mob/verb/examinate(atom/A as mob|obj|turf in view()) +//mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 +/mob/verb/examine_verb(atom/A as mob|obj|turf in view()) set name = "Examine" set category = "IC" - if((is_blind(src) || usr.stat) && !isobserver(src)) - to_chat(src, "Something is there but you can't see it.") - return 1 + if(!usr || !usr.client) + return + + if(is_blind() && !isobserver(src)) + to_chat(src, SPAN_WARNING("Something is there but you can't see it.")) + return TRUE face_atom(A) - if(!isghost(src)) - if(A.loc != src || A == l_hand || A == r_hand) + if(!isghost(src) && get_config_value(/decl/config/toggle/visible_examine)) + if((A.loc != src || (A in get_held_items()))) + var/look_target = "at \the [A]" + if(isobj(A.loc)) + look_target = "inside \the [A.loc]" + if(A == src) + var/decl/pronouns/pronouns = get_pronouns() + look_target = "at [pronouns.self]" for(var/mob/M in viewers(4, src)) if(M == src) continue - if(M.client && M.client.get_preference_value(/datum/client_preference/examine_messages) == GLOB.PREF_SHOW) + if(M.client && M.client.get_preference_value(/datum/client_preference/examine_messages) == PREF_SHOW) if(M.is_blind() || is_invisible_to(M)) continue - to_chat(M, "\The [src] looks at \the [A].") + to_chat(M, "\The [src] looks [look_target].") var/distance = INFINITY if(isghost(src) || stat == DEAD) @@ -329,8 +535,10 @@ if(source_turf && source_turf.z == target_turf?.z) distance = get_dist(source_turf, target_turf) - if(!A.examine(src, distance)) - crash_with("Improper /examine() override: [log_info_line(A)]") + RAISE_EVENT(/decl/observ/mob_examining, src, A) + + if(!A.examined_by(src, distance)) + PRINT_STACK_TRACE("Improper /examined_by() override: [log_info_line(A)]") /mob/verb/pointed(atom/A as mob|obj|turf in view()) set name = "Point To" @@ -361,11 +569,11 @@ return L if(!L) L = list(src) - for(var/obj/item/grab/G in grabs) - if(G.affecting && !(G.affecting in L)) - L += G.affecting - var/mob/affecting_mob = G.get_affecting_mob() - if(affecting_mob) + for(var/obj/item/grab/grab as anything in grabs) + if(grab.affecting && !(grab.affecting in L)) + L += grab.affecting + var/mob/living/affecting_mob = grab.get_affecting_mob() + if(istype(affecting_mob)) affecting_mob.ret_grab(L) return L @@ -373,34 +581,21 @@ set name = "Activate Held Object" set category = "Object" set src = usr + var/obj/item/holding = get_active_held_item() + holding?.attack_self(src) + return holding - if(hand) - var/obj/item/W = l_hand - if (W) - W.attack_self(src) - update_inv_l_hand() - else - attack_empty_hand(BP_L_HAND) - else - var/obj/item/W = r_hand - if (W) - W.attack_self(src) - update_inv_r_hand() - else - attack_empty_hand(BP_R_HAND) +/mob/living/mode() + if(!..()) + attack_empty_hand() /mob/proc/update_flavor_text(var/key) var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null, extra = 0) - if(!CanInteract(usr, GLOB.self_state)) + if(!CanInteract(usr, global.self_topic_state)) return if(msg != null) flavor_text = msg -/mob/proc/warn_flavor_changed() - if(flavor_text && flavor_text != "") // don't spam people that don't use it! - to_chat(src, "

    OOC Warning:

    ") - to_chat(src, "Your flavor text is likely out of date! Change") - /mob/proc/print_flavor_text() if (flavor_text && flavor_text != "") var/msg = replacetext(flavor_text, "\n", " ") @@ -445,7 +640,7 @@ reset_view(null) /mob/DefaultTopicState() - return GLOB.view_state + return global.view_topic_state // Use to field Topic calls for which usr == src is required, which will first be funneled into here. /mob/proc/OnSelfTopic(href_list) @@ -458,76 +653,80 @@ update_flavor_text(href_list["flavor_change"]) return TOPIC_HANDLED +/mob/proc/get_comments_record() + return + // If usr != src, or if usr == src but the Topic call was not resolved, this is called next. /mob/OnTopic(mob/user, href_list, datum/topic_state/state) + + if(href_list["refresh"]) + show_stripping_window(user) + return TOPIC_HANDLED + + if(href_list["item"]) + if(!handle_strip(href_list["item"], user, locate(href_list["holder"]))) + show_stripping_window(user) + return TOPIC_HANDLED + if(href_list["flavor_more"]) - show_browser(user, "[name][replacetext(flavor_text, "\n", "
    ")]
    ", "window=[name];size=500x200") - onclose(user, "[name]") + var/datum/browser/popup = new(user, ckey(name), name, 500, 200) + var/list/html = list("

    Appearance

    ") + html += replacetext(flavor_text, "\n", "
    ") + var/datum/character_information/comments = get_comments_record() + if(comments) + if(comments.ic_info) + html += "

    IC Information

    " + html += "[comments.ic_info]
    " + if(comments.ooc_info) + html += "

    OOC Information

    " + html += "[comments.ooc_info]
    " + popup.set_content(jointext(html, null)) + popup.open() return TOPIC_HANDLED // You probably do not need to override this proc. Use one of the two above. /mob/Topic(href, href_list, datum/topic_state/state) - if(CanUseTopic(usr, GLOB.self_state, href_list) == STATUS_INTERACTIVE) + if(CanUseTopic(usr, global.self_topic_state, href_list) == STATUS_INTERACTIVE) . = OnSelfTopic(href_list) if(.) return else if(href_list["flavor_change"] && !is_admin(usr) && (usr != src)) - log_and_message_admins(usr, "is suspected of trying to change flavor text on [key_name_admin(src)] via Topic exploits.") + log_and_message_admins("is suspected of trying to change flavor text on [key_name_admin(src)] via Topic exploits.", usr) return ..() /mob/proc/pull_damage() return 0 -/mob/living/carbon/human/pull_damage() - if(!lying || getBruteLoss() + getFireLoss() < 100) +/mob/living/human/pull_damage() + if(!current_posture.prone|| get_damage(BRUTE) + get_damage(BURN) < 100) return FALSE - for(var/thing in organs) - var/obj/item/organ/external/e = thing - if(!e || e.is_stump()) - continue + for(var/obj/item/organ/external/e in get_external_organs()) if((e.status & ORGAN_BROKEN) && !e.splinted) return TRUE if(e.status & ORGAN_BLEEDING) return TRUE return FALSE -/mob/MouseDrop(mob/M) - ..() - if(M != usr) return - if(usr == src) return - if(!Adjacent(usr)) return - if(istype(M,/mob/living/silicon/ai)) return - show_inv(usr) - -/mob/proc/can_use_hands() - return - -/mob/proc/is_active() - return (0 >= usr.stat) - -/mob/proc/is_dead() - return stat == DEAD - -/mob/proc/is_mechanical() - if(mind && (mind.assigned_role == "Robot" || mind.assigned_role == "AI")) - return 1 - return istype(src, /mob/living/silicon) - -/mob/proc/is_ready() - return client && !!mind - -/mob/proc/get_gender() - return gender - -/mob/proc/see(message) - if(!is_active()) - return 0 - to_chat(src, message) - return 1 +/mob/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && user != src && !isAI(user)) + show_stripping_window(user) + return TRUE + if(!anchored && istype(over, /obj/vehicle/train)) + var/obj/vehicle/train/beep = over + if(!beep.load_onto_vehicle(src)) + to_chat(user, SPAN_WARNING("You were unable to load \the [src] onto \the [over].")) + return TRUE + . = ..() -/mob/proc/show_viewers(message) - for(var/mob/M in viewers()) - M.see(message) +/mob/proc/can_touch(var/atom/touching) + if(!touching.Adjacent(src) || incapacitated()) + return FALSE + if(restrained()) + to_chat(src, SPAN_WARNING("You are restrained.")) + return FALSE + if (buckled) + to_chat(src, SPAN_WARNING("You are buckled down.")) + return TRUE /mob/Stat() ..() @@ -545,8 +744,10 @@ if(client.holder) if(statpanel("MC")) - stat("CPU:","[world.cpu]") + stat("CPU:", "[Master.format_color_cpu()]") + stat("Map CPU:", "[Master.format_color_cpu_map()]") stat("Instances:","[world.contents.len]") + stat("World Time:", "[world.time]") stat(null) if(Master) Master.stat_entry() @@ -570,73 +771,62 @@ if(statpanel("Turf")) stat(listed_turf) for(var/atom/A in listed_turf) - if(!A.mouse_opacity) + if(!A.simulated || !A.mouse_opacity) continue if(A.invisibility > see_invisible) continue - if(is_type_in_list(A, shouldnt_see)) + if(LAZYLEN(shouldnt_see) && is_type_in_list(A, shouldnt_see)) continue stat(A) // facing verbs /mob/proc/canface() - return !incapacitated() + return !incapacitated(INCAPACITATION_UNRESISTING) // Not sure what to call this. Used to check if humans are wearing an AI-controlled exosuit and hence don't need to fall over yet. /mob/proc/can_stand_overridden() return 0 -//Updates lying and icons -/mob/proc/UpdateLyingBuckledAndVerbStatus() - if(!resting && cannot_stand() && can_stand_overridden()) - lying = 0 - else if(buckled) - anchored = 1 - if(istype(buckled)) - if(buckled.buckle_lying == -1) - lying = incapacitated(INCAPACITATION_KNOCKDOWN) - else - lying = buckled.buckle_lying - if(buckled.buckle_movable) - anchored = 0 +//Updates lying, transform and icons +/mob/proc/update_posture(force_update) + + var/list/available_postures = get_available_postures() + if(length(available_postures) <= 0) + return // No postures, no point doing any of this. + + if(length(available_postures) == 1) + // If we only have one posture, use that. + . = set_posture(available_postures[1], skip_buckled_update = TRUE) + else if(istype(buckled) && buckled.buckle_lying != -1) + // If we're buckled to something that forces a posture, use that. + . = set_posture(buckled.buckle_lying ? /decl/posture/lying : /decl/posture/standing, skip_buckled_update = TRUE) + else if(incapacitated(INCAPACITATION_KNOCKDOWN) || (cannot_stand() && !can_stand_overridden())) + // If we're straight up knocked over, set that. + if(!current_posture.prone) + . = set_posture(/decl/posture/lying, skip_buckled_update = TRUE) + else if(!current_posture.deliberate) + // If we're not deliberately lying, and we can stand, stand up. + . = set_posture(/decl/posture/standing, skip_buckled_update = TRUE) else - lying = incapacitated(INCAPACITATION_KNOCKDOWN) + . = FALSE - if(lying) - set_density(0) - if(l_hand) unEquip(l_hand) - if(r_hand) unEquip(r_hand) - else - set_density(initial(density)) + anchored = buckled ? (!istype(buckled) || !buckled.buckle_movable) : initial(anchored) reset_layer() - //Temporarily moved here from the various life() procs - //I'm fixing stuff incrementally so this will likely find a better home. - //It just makes sense for now. ~Carn - if( update_icon ) //forces a full overlay update - update_icon = 0 - regenerate_icons() - else if( lying != lying_prev ) - update_icons() - -/mob/proc/reset_layer() - if(lying) - plane = DEFAULT_PLANE - layer = LYING_MOB_LAYER - else - reset_plane_and_layer() + if(. || force_update) + update_icon() + update_transform() /mob/proc/facedir(var/ndir) - if(!canface() || moving || (buckled && !buckled.buckle_movable)) + if(!canface() || moving || (buckled && (!buckled.buckle_movable && !buckled.buckle_allow_rotation))) return 0 set_dir(ndir) if(buckled && buckled.buckle_movable) buckled.set_dir(ndir) - SetMoveCooldown(movement_delay()) + SetMoveCooldown(get_movement_delay(ndir)) return 1 - /mob/verb/eastface() set hidden = 1 return facedir(client.client_dir(EAST)) @@ -656,88 +846,13 @@ set hidden = 1 return facedir(client.client_dir(SOUTH)) -/mob/proc/Stun(amount) - if(status_flags & CANSTUN) - facing_dir = null - stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun - UpdateLyingBuckledAndVerbStatus() - return - -/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned" - if(status_flags & CANSTUN) - stunned = max(amount,0) - UpdateLyingBuckledAndVerbStatus() - return - -/mob/proc/AdjustStunned(amount) - if(status_flags & CANSTUN) - stunned = max(stunned + amount,0) - UpdateLyingBuckledAndVerbStatus() - return - -/mob/proc/Weaken(amount) - if(status_flags & CANWEAKEN) - facing_dir = null - weakened = max(max(weakened,amount),0) - UpdateLyingBuckledAndVerbStatus() - return - -/mob/proc/SetWeakened(amount) - if(status_flags & CANWEAKEN) - weakened = max(amount,0) - UpdateLyingBuckledAndVerbStatus() - return - -/mob/proc/AdjustWeakened(amount) - if(status_flags & CANWEAKEN) - weakened = max(weakened + amount,0) - UpdateLyingBuckledAndVerbStatus() - return - -/mob/proc/Paralyse(amount) - if(status_flags & CANPARALYSE) - facing_dir = null - paralysis = max(max(paralysis,amount),0) - return - -/mob/proc/SetParalysis(amount) - if(status_flags & CANPARALYSE) - paralysis = max(amount,0) - return - -/mob/proc/AdjustParalysis(amount) - if(status_flags & CANPARALYSE) - paralysis = max(paralysis + amount,0) - return - -/mob/proc/Sleeping(amount) - facing_dir = null - sleeping = max(max(sleeping,amount),0) - return - -/mob/proc/SetSleeping(amount) - sleeping = max(amount,0) - return - -/mob/proc/AdjustSleeping(amount) - sleeping = max(sleeping + amount,0) - return +/mob/proc/get_species_name() + SHOULD_CALL_PARENT(TRUE) + return "Unknown" -/mob/proc/Resting(amount) - facing_dir = null - resting = max(max(resting,amount),0) - return - -/mob/proc/SetResting(amount) - resting = max(amount,0) - return - -/mob/proc/AdjustResting(amount) - resting = max(resting + amount,0) - return - -/mob/proc/get_species() - return "" +/mob/living/get_species_name() + var/decl/species/my_species = get_species() + return my_species?.name || ..() /mob/proc/get_visible_implants(var/class = 0) var/list/visible_implants = list() @@ -747,47 +862,10 @@ return visible_implants /mob/proc/embedded_needs_process() - return (embedded.len > 0) - -/mob/proc/remove_implant(var/obj/item/implant, var/surgical_removal = FALSE) - if(!LAZYLEN(get_visible_implants(0))) //Yanking out last object - removing verb. - verbs -= /mob/proc/yank_out_object - for(var/obj/item/O in pinned) - if(O == implant) - pinned -= O - if(!pinned.len) - anchored = 0 - implant.dropInto(loc) - implant.add_blood(src) - implant.update_icon() - if(istype(implant,/obj/item/implant)) - var/obj/item/implant/imp = implant - imp.removed() - . = TRUE - -/mob/living/silicon/robot/remove_implant(var/obj/item/implant, var/surgical_removal = FALSE) - embedded -= implant - adjustBruteLoss(5) - adjustFireLoss(10) - . = ..() + return !!LAZYLEN(embedded) -/mob/living/carbon/human/remove_implant(var/obj/item/implant, var/surgical_removal = FALSE, var/obj/item/organ/external/affected) - if(!affected) //Grab the organ holding the implant. - for(var/obj/item/organ/external/organ in organs) - for(var/obj/item/O in organ.implants) - if(O == implant) - affected = organ - break - if(affected) - affected.implants -= implant - for(var/datum/wound/wound in affected.wounds) - LAZYREMOVE(wound.embedded_objects, implant) - if(!surgical_removal) - shock_stage+=20 - affected.take_external_damage((implant.w_class * 3), 0, DAM_EDGE, "Embedded object extraction") - if(!BP_IS_PROSTHETIC(affected) && prob(implant.w_class * 5) && affected.sever_artery()) //I'M SO ANEMIC I COULD JUST -DIE-. - custom_pain("Something tears wetly in your [affected.name] as [implant] is pulled free!", 50, affecting = affected) - . = ..() +/mob/proc/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected) + return FALSE /mob/proc/yank_out_object() set category = "Object" @@ -799,20 +877,18 @@ return usr.setClickCooldown(20) - if(usr.stat == 1) - to_chat(usr, "You are unconcious and cannot do that!") + if(usr.stat == UNCONSCIOUS) + to_chat(usr, "You are unconscious and cannot do that!") return if(usr.restrained()) to_chat(usr, "You are restrained and cannot do that!") return - var/mob/S = src - var/mob/U = usr var/list/valid_objects = list() var/self = null - if(S == U) + if(src == usr) self = 1 // Removing object from yourself. valid_objects = get_visible_implants(0) @@ -820,16 +896,16 @@ if(self) to_chat(src, "You have nothing stuck in your body that is large enough to remove.") else - to_chat(U, "[src] has nothing stuck in their wounds that is large enough to remove.") + to_chat(usr, "[src] has nothing stuck in their wounds that is large enough to remove.") return var/obj/item/selection = input("What do you want to yank out?", "Embedded objects") in valid_objects if(self) to_chat(src, "You attempt to get a good grip on [selection] in your body.") else - to_chat(U, "You attempt to get a good grip on [selection] in [S]'s body.") - if(!do_mob(U, S, 30, incapacitation_flags = INCAPACITATION_DEFAULT & (~INCAPACITATION_FORCELYING))) //let people pinned to stuff yank it out, otherwise they're stuck... forever!!! + to_chat(usr, "You attempt to get a good grip on [selection] in [src]'s body.") + if(!do_mob(usr, src, 30, incapacitation_flags = INCAPACITATION_DEFAULT & (~INCAPACITATION_FORCELYING))) //let people pinned to stuff yank it out, otherwise they're stuck... forever!!! return - if(!selection || !S || !U) + if(QDELETED(selection) || QDELETED(src) || QDELETED(usr)) return if(self) @@ -838,18 +914,13 @@ visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.") remove_implant(selection) selection.forceMove(get_turf(src)) - if(!(U.l_hand && U.r_hand)) - U.put_in_hands(selection) - if(ishuman(U)) - var/mob/living/carbon/human/human_user = U + if(usr.get_empty_hand_slot()) + usr.put_in_hands(selection) + if(ishuman(usr)) + var/mob/living/human/human_user = usr human_user.bloody_hands(src) return 1 -// A mob should either use update_icon(), overriding this definition, or use update_icons(), not touching update_icon(). -// It should not use both. -/mob/on_update_icon() - return update_icons() - /mob/verb/face_direction() set name = "Face Direction" @@ -877,10 +948,11 @@ /mob/set_dir() if(facing_dir) - if(!canface() || lying || restrained()) + if(!canface() || current_posture.prone || restrained()) facing_dir = null else if(buckled) - if(buckled.obj_flags & OBJ_FLAG_ROTATABLE) + var/obj/buckled_obj = buckled + if(!isobj(buckled) || (buckled_obj.obj_flags & OBJ_FLAG_ROTATABLE)) buckled.set_dir(facing_dir) return ..(facing_dir) else @@ -889,10 +961,13 @@ return ..(facing_dir) else return ..() + return FALSE /mob/proc/set_stat(var/new_stat) . = stat != new_stat - stat = new_stat + if(.) + stat = new_stat + SStyping.set_indicator_state(client, FALSE) /mob/verb/northfaceperm() set hidden = 1 @@ -910,29 +985,11 @@ set hidden = 1 set_face_dir(client.client_dir(WEST)) -/mob/proc/adjustEarDamage() - return - -/mob/proc/setEarDamage() - return - //Throwing stuff -/mob/proc/toggle_throw_mode() - if (src.in_throw_mode) - throw_mode_off() - else - throw_mode_on() - -/mob/proc/throw_mode_off() - src.in_throw_mode = 0 - if(src.throw_icon) //in case we don't have the HUD and we use the hotkey - src.throw_icon.icon_state = "act_throw_off" - -/mob/proc/throw_mode_on() - src.in_throw_mode = 1 - if(src.throw_icon) - src.throw_icon.icon_state = "act_throw_on" +/mob/proc/toggle_throw_mode(force_set) + in_throw_mode = isnull(force_set) ? !in_throw_mode : force_set + refresh_hud_element(HUD_THROW) /mob/proc/toggle_antag_pool() set name = "Toggle Add-Antag Candidacy" @@ -950,12 +1007,10 @@ to_chat(usr, "The game is not currently looking for antags.") else to_chat(usr, "You must be observing or in the lobby to join the antag pool.") + /mob/proc/is_invisible_to(var/mob/viewer) return (!alpha || !mouse_opacity || viewer.see_invisible < invisibility) -/client/proc/check_has_body_select() - return mob && mob.hud_used && istype(mob.zone_sel, /obj/screen/zone_sel) - /client/verb/body_toggle_head() set name = "body-toggle-head" set hidden = 1 @@ -979,7 +1034,7 @@ /client/verb/body_groin() set name = "body-groin" set hidden = 1 - toggle_zone_sel(list(BP_GROIN)) + toggle_zone_sel(list(BP_GROIN,BP_TAIL)) /client/verb/body_r_leg() set name = "body-r-leg" @@ -992,13 +1047,7 @@ toggle_zone_sel(list(BP_L_LEG,BP_L_FOOT)) /client/proc/toggle_zone_sel(list/zones) - if(!check_has_body_select()) - return - var/obj/screen/zone_sel/selector = mob.zone_sel - selector.set_selected_zone(next_in_list(mob.zone_sel.selecting,zones)) - -/mob/proc/has_chem_effect(chem, threshold) - return FALSE + mob.set_target_zone(next_in_list(mob.get_target_zone(), zones)) /mob/proc/has_admin_rights() return check_rights(R_ADMIN, 0, src) @@ -1009,41 +1058,89 @@ /mob/proc/can_drown() return 0 -/mob/proc/get_sex() +/mob/proc/get_gender() return gender -/mob/is_fluid_pushable(var/amt) - if(..() && !buckled && (lying || !Check_Shoegrip()) && (amt >= mob_size * (lying ? 5 : 10))) - if(!lying) - Weaken(1) - if(lying && prob(10)) - to_chat(src, "You are pushed down by the flood!") +/mob/try_fluid_push(volume, strength) + if(..() && can_slip() && (strength >= mob_size * (current_posture.prone ? 5 : 10))) + if(!current_posture.prone) + SET_STATUS_MAX(src, STAT_WEAK, 1) + if(current_posture.prone && prob(10)) + to_chat(src, SPAN_DANGER("You are pushed down by the flood!")) return TRUE return FALSE -/mob/proc/get_footstep(var/footstep_type) - return - /mob/proc/handle_embedded_and_stomach_objects() return /mob/proc/get_sound_volume_multiplier() - if(ear_deaf) + if(GET_STATUS(src, STAT_DEAF)) return 0 - return 1 - -/mob/proc/has_dexterity(var/dex_level) - . = TRUE - -/mob/proc/check_dexterity(var/dex_level, var/silent) - . = has_dexterity(dex_level) + . = 1 + for(var/slot in global.headphone_slots) + var/obj/item/clothing/C = get_equipped_item(slot) + if(istype(C)) + . = min(., C.volume_multiplier) + +// Mobs further up the chain should override this proc if they want to return a simple dexterity value. +/mob/proc/get_dexterity(var/silent) + + // Check if we have a slot to use for this. + var/check_slot = get_active_held_item_slot() + if(!check_slot) + return DEXTERITY_NONE + var/datum/inventory_slot/gripper/gripper = get_inventory_slot_datum(check_slot) + if(!istype(gripper)) + if(!silent) + to_chat(src, "Your [parse_zone(check_slot)] is missing!") + return DEXTERITY_NONE + + // Work out if we have any brain damage impacting our dexterity. + var/dex_malus = 0 + var/braindamage = get_damage(BRAIN) + if(braindamage) + var/brainloss_threshold = get_config_value(/decl/config/num/dex_malus_brainloss_threshold) + if(braindamage > brainloss_threshold) ///brainloss shouldn't instantly cripple you, so the effects only start once past the threshold and escalate from there. + dex_malus = clamp(ceil((braindamage-brainloss_threshold)/10), 0, length(global.dexterity_levels)) + if(dex_malus > 0) + dex_malus = global.dexterity_levels[dex_malus] + + // If this slot does not need an organ we just go off the dexterity of the slot itself. + if(isnull(gripper.requires_organ_tag)) + if(dex_malus) + if(!silent) + to_chat(src, SPAN_WARNING("Your [lowertext(gripper.slot_name)] doesn't respond properly!")) + return (gripper.get_dexterity(silent) & ~dex_malus) + return gripper.get_dexterity(silent) + + // If this slot requires an organ, do the appropriate organ checks. + check_slot = gripper.requires_organ_tag + var/obj/item/organ/external/active_hand = GET_EXTERNAL_ORGAN(src, check_slot) + if(!active_hand) + if(!silent) + to_chat(src, "Your [parse_zone(check_slot)] is missing!") + return DEXTERITY_NONE + if(!active_hand.is_usable()) + if(!silent) + to_chat(src, SPAN_WARNING("Your [active_hand.name] is unusable!")) + return DEXTERITY_NONE + + // Return our organ dexterity. + if(dex_malus) + if(!silent) + to_chat(src, SPAN_WARNING("Your [active_hand.name] doesn't respond properly!")) + return (active_hand.get_manual_dexterity() & ~dex_malus) + return active_hand.get_manual_dexterity() + +/mob/proc/check_dexterity(var/dex_level = DEXTERITY_FULL, var/silent = FALSE) + . = (get_dexterity(silent) & dex_level) == dex_level if(!. && !silent) to_chat(src, FEEDBACK_YOU_LACK_DEXTERITY) /mob/proc/lose_hair() return -/mob/proc/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays) +/mob/proc/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays, var/digital = FALSE) if(!skip_delays) to_chat(src, SPAN_WARNING("You can't make heads or tails of the words.")) . = stars(text_content, 5) @@ -1053,28 +1150,456 @@ to_chat(src, SPAN_WARNING("You scrawl down some meaningless lines.")) . = stars(text_content, 5) -// mobs do not have mouths by default +// mobs do not have mouths by default, unless provided by an organ /mob/proc/check_has_mouth() - return FALSE + var/obj/item/organ/external/head/H = get_organ(BP_HEAD, /obj/item/organ/external/head) + if(!H || !istype(H) || !H.can_intake_reagents) + return FALSE + return TRUE /mob/proc/check_has_eyes() return TRUE /mob/proc/handle_pre_transformation() - return + dump_contents() /mob/get_mass() return mob_size -/mob/physically_destroyed() +/mob/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) gib() - -/mob/explosion_act() + +/mob/get_contained_external_atoms() . = ..() - if(!blinded) - flash_eyes() + LAZYREMOVE(., get_organs()) + +/mob/explosion_act(var/severity) + . = ..() + if(!QDELETED(src)) + if(severity == 1) + physically_destroyed() + else if(!is_blind()) + flash_eyes() + +/mob/proc/can_enter_cryopod(var/mob/user) + if(stat == DEAD) + if(user == src) + to_chat(src, SPAN_WARNING("You cannot use that, as you are dead.")) + else + to_chat(user, SPAN_WARNING("\The [src] cannot use that, as they are dead.")) + return FALSE + return TRUE + +/mob/proc/get_species() + RETURN_TYPE(/decl/species) + return + +/mob/proc/get_bodytype() + RETURN_TYPE(/decl/bodytype) + +// Bit of a stub for now, but should return the bodytype specific +// to the slot and organ being checked in the future instead of +// always using the mob root bodytype. +/mob/proc/get_equipment_bodytype(slot, bodypart) + RETURN_TYPE(/decl/bodytype) + var/decl/bodytype/root_bodytype = get_bodytype() + return root_bodytype?.resolve_to_equipment_bodytype(src) + +/mob/proc/has_body_flag(flag, default = FALSE) + var/decl/bodytype/root_bodytype = get_bodytype() + if(istype(root_bodytype)) + return (root_bodytype.body_flags & flag) + return default + +/// Update the mouse pointer of the attached client in this mob. +/mob/proc/update_mouse_pointer() + if(!client) + return + if(client.keys_held["Shift"]) + client.add_mouse_pointer(/decl/mouse_pointer/examine) + else + client.remove_mouse_pointer(/decl/mouse_pointer/examine) + +/mob/keybind_face_direction(direction) + facedir(direction) + +/mob/proc/check_emissive_equipment() + var/old_zflags = z_flags + z_flags &= ~ZMM_MANGLE_PLANES + for(var/atom/movable/AM in get_equipped_items(TRUE)) + if(AM.z_flags & ZMM_MANGLE_PLANES) + z_flags |= ZMM_MANGLE_PLANES + break + if(old_zflags != z_flags) + UPDATE_OO_IF_PRESENT + +/mob/get_mob() + return src + +/mob/proc/set_glide_size(var/delay) + glide_size = ADJUSTED_GLIDE_SIZE(delay) + +/mob/proc/IsMultiZAdjacent(var/atom/neighbor) + + var/turf/T = get_turf(src) + var/turf/N = get_turf(neighbor) + + // Not on valid turfs. + if(QDELETED(src) || QDELETED(neighbor) || !istype(T) || !istype(N)) + return FALSE + + // On the same z-level, we don't need to care about multiz. + if(N.z == T.z) + return Adjacent(neighbor) + + // More than one z-level away from each other. + if(abs(N.x - T.x) > 1 || abs(N.y - T.y) > 1 || abs(N.z - T.z) > 1) + return FALSE + + // Not in a connected z-volume. + if(!(N.z in SSmapping.get_connected_levels(T.z))) + return FALSE + + // Are they below us? + if(N.z < T.z && HasBelow(T.z)) + var/turf/B = GetBelow(T) + return T.is_open() && neighbor.Adjacent(B) + + // Are they above us? + if(HasAbove(T.z)) + var/turf/A = GetAbove(T) + return A.is_open() && neighbor.Adjacent(A) + + return FALSE + +/mob/proc/handle_flashed(var/flash_strength, do_stun = FALSE) + return FALSE + +/mob/proc/do_flash_animation() + return + +/mob/proc/unset_machine() + src.machine = null + +/mob/proc/set_machine(var/obj/O) + if(src.machine) + unset_machine() + src.machine = O + if(istype(O)) + O.in_use = 1 + +// Mob procs relating to the typing indicator subsystem. +/mob/Logout() + if (typing_indicator) + vis_contents -= typing_indicator + is_typing = FALSE + ..() + +/mob/proc/get_speech_bubble_state_modifier() + return + +/mob/verb/say_wrapper() + set name = ".Say" + set hidden = TRUE + SStyping.set_indicator_state(client, TRUE) + var/message = input("","say (text)") as text|null + SStyping.set_indicator_state(client, FALSE) + if (message) + say_verb(message) + +/mob/verb/me_wrapper() + set name = ".Me" + set hidden = TRUE + SStyping.set_indicator_state(client, TRUE) + var/message = input("","me (text)") as text|null + SStyping.set_indicator_state(client, FALSE) + if (message) + me_verb(message) + +/mob/verb/whisper_wrapper() + set name = ".Whisper" + set hidden = TRUE + if(get_config_value(/decl/config/toggle/show_typing_indicator_for_whispers)) + SStyping.set_indicator_state(client, TRUE) + var/message = input("","me (text)") as text|null + if(get_config_value(/decl/config/toggle/show_typing_indicator_for_whispers)) + SStyping.set_indicator_state(client, FALSE) + if (message) + whisper(message) + +// Darksight procs. +/mob/proc/refresh_lighting_master() + if(!lighting_master) + lighting_master = new(null, src) + if(client) + client.screen |= lighting_master + +/mob/proc/set_internals(obj/item/tank/source, source_string) + return + +/mob/proc/get_internals() + return + +/mob/proc/toggle_internals(var/mob/living/user) + return + +/mob/proc/set_target_zone(new_zone) + if(new_zone == selected_zone) + return + var/old_zone = selected_zone + selected_zone = new_zone + var/obj/screen/zone_selector/selector = get_hud_element(HUD_ZONE_SELECT) + if(selector) + selector.set_selected_zone(new_zone, old_zone) + +/mob/proc/get_target_zone() + return selected_zone + +/mob/proc/get_default_temperature_threshold(threshold) + switch(threshold) + if(COLD_LEVEL_1) + return 243 + if(COLD_LEVEL_2) + return 200 + if(COLD_LEVEL_3) + return 120 + if(HEAT_LEVEL_1) + return 360 + if(HEAT_LEVEL_2) + return 400 + if(HEAT_LEVEL_3) + return 1000 + else + CRASH("base get_default_temperature_threshold() called with invalid threshold value.") + +/mob/proc/get_mob_temperature_threshold(threshold, bodypart) + + // If we have organs, return the requested organ. + if(bodypart) + var/obj/item/organ/external/organ = get_organ(bodypart) + if(organ?.bodytype) + return organ.bodytype.get_body_temperature_threshold(threshold) + + // If we have a bodytype, use that. + var/decl/bodytype/root_bodytype = get_bodytype() + if(root_bodytype) + return root_bodytype.get_body_temperature_threshold(threshold) + + return get_default_temperature_threshold(threshold) -/mob/proc/adjust_drugged(var/amt, var/maxamt = 100) - drugged = Clamp(drugged + amt, 0, maxamt) - . = drugged \ No newline at end of file +/mob/proc/get_unique_enzymes() + return + +/mob/proc/set_unique_enzymes(value) + return + +/mob/proc/get_blood_type() + return + +/mob/get_overhead_text_x_offset() + return offset_overhead_text_x + +/mob/get_overhead_text_y_offset() + return offset_overhead_text_y + +/mob/can_be_injected_by(var/atom/injector) + return FALSE // Handled elsewhere in syringe logic. + +/mob/proc/getBrainLoss() + return 0 + +/mob/proc/get_bodytype_category() + return get_bodytype()?.bodytype_category + +/mob/proc/get_overlay_state_modifier() + return current_posture?.overlay_modifier + +/mob/proc/nervous_system_failure() + return FALSE + +/mob/proc/resolve_to_radio_listeners() + if(status_flags & PASSEMOTES) + var/list/listeners = list(src) + for(var/obj/item/holder/holder in src.contents) + for(var/mob/living/listener in holder) + listeners |= listener + for(var/mob/living/listener in contents) + listeners |= listener + return listeners + return src + +/mob/proc/mob_throw_item(atom/target) + return + +/mob/proc/swap_hand() + SHOULD_CALL_PARENT(TRUE) + +/mob/proc/set_skin_tone(value) + return + +/mob/proc/get_skin_tone() + return + +/mob/proc/force_update_limbs() + return + +/mob/proc/update_eyes(update_icons = TRUE) + var/obj/item/organ/internal/eyes/eyes = get_organ((get_bodytype()?.vision_organ || BP_EYES), /obj/item/organ/internal/eyes) + if(eyes) + eyes.update_colour() + if(update_icons) + queue_icon_update() + +/mob/proc/has_genetic_information() + if(isSynthetic()) + return FALSE + var/decl/bodytype/bodytype = get_bodytype() + if(bodytype?.body_flags & BODY_FLAG_NO_DNA) + return FALSE + return TRUE + +/mob/living/proc/get_butchery_product_name() + var/decl/butchery_data/butchery_decl = GET_DECL(butchery_data) + . = butchery_decl?.meat_name || name + +/mob/reset_movement_delay() + var/datum/movement_handler/mob/delay/delay = locate() in movement_handlers + if(istype(delay)) + delay.next_move = world.time + +/mob/proc/do_attack_windup_checking(atom/target) + return TRUE + +// Stub proc; implemented on /mob/living +/mob/proc/handle_footsteps() + return + +//gets name from ID or PDA itself, ID inside PDA doesn't matter +//Useful when player is being seen by other mobs +/mob/proc/get_id_name(if_no_id = "Unknown") + return GetIdCard(exceptions = list(/obj/item/holder))?.registered_name || if_no_id + +/mob/proc/can_twohand_item(obj/item/item) + return FALSE + +/// THIS DOES NOT RELATE TO HELD ITEM SLOTS. It is very specifically a functional BP_L_HAND or BP_R_HAND organ, not necessarily a gripper. +/mob/proc/get_usable_hand_slot_organ() + var/static/list/hand_slots = list(BP_L_HAND, BP_R_HAND) + for(var/slot in shuffle(hand_slots)) + var/obj/item/organ/external/hand = GET_EXTERNAL_ORGAN(src, slot) + if(istype(hand) && hand.is_usable()) + return hand + +/mob/proc/get_solid_footing() + + if(!loc) + return src // this is a bit weird but we shouldn't slip in nullspace probably + + // Check for dense turfs. + var/turf/my_turf = loc + if(!istype(my_turf)) + return my_turf + + if(my_turf.is_wall() || my_turf.is_floor()) + return my_turf + + // Check for catwalks and lattices. + var/atom/platform = my_turf.get_supporting_platform() || (locate(/obj/structure/lattice) in my_turf) + if(platform) + return platform + + // Check for supportable nearby atoms. + for(var/turf/neighbor in RANGE_TURFS(my_turf, 1)) + if(neighbor == my_turf) + continue + if(neighbor.is_wall() || neighbor.is_floor()) + return neighbor + var/dense_object = neighbor.get_first_dense_object(exceptions = src) + if(dense_object) + return dense_object + platform = neighbor.get_supporting_platform() || (locate(/obj/structure/lattice) in neighbor) + if(platform) + return platform + + // Find something we are grabbing onto for support. + for(var/atom/movable/thing in range(1, my_turf)) + if(thing == src || thing == inertia_ignore || !thing.simulated || thing == buckled) + continue + if(isturf(thing)) + continue // We checked turfs when using magboots above. + else if(ismob(thing)) + var/mob/victim = thing + if(victim.buckled) + continue + else if(thing.CanPass(src)) + continue + if(thing.anchored) + return thing + var/is_being_grabbed = FALSE + for(var/obj/item/grab/grab in get_active_grabs()) + if(thing == grab.affecting) + is_being_grabbed = TRUE + break + if(!is_being_grabbed) + . = thing + +/mob/proc/can_slip(magboots_only = FALSE) + + // Are we immune to everything? + if(status_flags & GODMODE) + return FALSE + + // Quick basic checks. + if(!simulated || !isturf(loc) || buckled || current_posture?.prone || throwing) + return FALSE + + // Species flag/proc check. + if(get_species()?.check_no_slip(src, magboots_only)) + return FALSE + + // Check footwear. + if(magboots_only) + return !((has_gravity() || has_magnetised_footing()) && get_solid_footing()) + + if(has_non_slip_footing()) + return FALSE + + // Slip! + return TRUE + +/mob/proc/has_non_slip_footing() + var/obj/item/shoes = get_equipped_item(slot_shoes_str) + return istype(shoes) && (shoes.item_flags & ITEM_FLAG_NOSLIP) + +/mob/proc/has_magnetised_footing() + var/obj/item/shoes = get_equipped_item(slot_shoes_str) + return istype(shoes) && (shoes.item_flags & ITEM_FLAG_MAGNETISED) + +// Called when using the shredding behavior. +/mob/proc/can_shred(var/mob/living/human/H, var/ignore_intent, var/ignore_antag) + if((!ignore_intent && !check_intent(I_FLAG_HARM)) || pulling_punches) + return FALSE + if(!ignore_antag && mind && !player_is_antag(mind)) + return FALSE + if(get_equipped_item(slot_handcuffed_str) || buckled) + return FALSE + for(var/decl/natural_attack/attack as anything in get_mob_natural_attacks()) + if(attack.attack_is_usable(src) && attack.shredding) + return TRUE + return FALSE + +/mob/proc/get_mob_natural_attacks() + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!limb.is_usable()) + continue + var/list/limb_unarmed_attacks = limb.get_natural_attacks() + if(istype(limb_unarmed_attacks, /decl/natural_attack) || (islist(limb_unarmed_attacks) && length(limb_unarmed_attacks))) + LAZYDISTINCTADD(., limb_unarmed_attacks) + +/mob/proc/isSynthetic() + return FALSE + +// Returns true if the mob is cloaked, otherwise false +/mob/proc/is_cloaked() + return FALSE diff --git a/code/modules/mob/mob_automove.dm b/code/modules/mob/mob_automove.dm new file mode 100644 index 000000000000..f552d4f7c1e6 --- /dev/null +++ b/code/modules/mob/mob_automove.dm @@ -0,0 +1,66 @@ +/mob + /// Simple general-use reference for mob automoves. May be unused or replaced on subtypes. + var/atom/_automove_target + +/mob/stop_automove() + _automove_target = null + return ..() + +/mob/path_found(list/path) + ..() + if(islist(path) && length(path) > 1) + path.Cut(1, 2) // Remove the first turf since it's going to be our origin. + if(length(path)) + start_automove(path) + +/mob/path_not_found() + ..() + stop_automove() + +/// Called by get_movement_delay() to override the current move intent, in cases where an automove has a delay override. +/mob/proc/get_automove_delay() + var/datum/automove_metadata/metadata = SSautomove.moving_metadata[src] + return metadata?.move_delay + +/mob/failed_automove() + ..() + stop_automove() + _automove_target = null + return FALSE + +/mob/start_automove(target, movement_type, datum/automove_metadata/metadata) + _automove_target = target + return ..() + +// The AI datum may decide to track a target instead of using the mob reference. +/mob/get_automove_target(datum/automove_metadata/metadata) + . = _automove_target || (istype(ai) && ai.get_automove_target()) || ..() + if(islist(.)) + var/list/path = . + while(length(path) && path[1] == get_turf(src)) + path.Cut(1,2) + if(length(path)) + return path[1] + return null + +/mob/handle_post_automoved(atom/old_loc) + if(istype(ai)) + ai.handle_post_automoved(old_loc) + return + if(!islist(_automove_target) || length(_automove_target) <= 0) + return + var/turf/body_turf = get_turf(src) + if(!istype(body_turf)) + return + var/list/_automove_target_list = _automove_target + if(_automove_target_list[1] != body_turf) + return + if(length(_automove_target_list) > 1) + _automove_target_list.Cut(1, 2) + else + _automove_target_list = null + stop_automove() + +// We do some early checking here to avoid doing the same checks repeatedly by calling SelfMove(). +/mob/can_do_automated_move(variant_move_delay) + . = MayMove() && !incapacitated() && (!istype(ai) || ai.can_do_automated_move()) diff --git a/code/modules/mob/mob_blood.dm b/code/modules/mob/mob_blood.dm new file mode 100644 index 000000000000..3e3a7720334a --- /dev/null +++ b/code/modules/mob/mob_blood.dm @@ -0,0 +1,42 @@ +/mob/proc/get_flesh_color() + return get_species()?.get_species_flesh_color(src) || COLOR_GRAY + +/mob/proc/get_gibber_type() + return null + +/mob/proc/get_blood_color() + return get_species()?.get_species_blood_color(src) || COLOR_BLOOD_HUMAN + +/mob/proc/get_blood_oxy() + var/decl/species/my_species = get_species() + return my_species ? my_species.blood_oxy : TRUE + +/mob/proc/get_blood_name() + return "blood" + +/mob/living/silicon/get_blood_name() + return "oil" + +/mob/living/human/get_blood_name() + if(species) + return species.get_blood_name(src) + return "blood" + +//Gets blood from mob to the container, preserving all data in it. +/mob/proc/take_blood(obj/item/chems/container, var/amount) + var/decl/species/my_species = get_species() + if(my_species?.blood_reagent) + container.add_to_reagents(my_species.blood_reagent, amount, get_blood_data()) + return TRUE + return FALSE + +/mob/proc/get_blood_data() + var/data = list() + data[DATA_BLOOD_DONOR] = weakref(src) + return data + +/// Removes amt units of blood from src, if it has blood. +/// If absolute is FALSE, rescale amt according to mob size. +/// Returns the amount of blood removed. +/mob/proc/remove_blood(amt, absolute = FALSE) + return 0 \ No newline at end of file diff --git a/code/modules/mob/mob_damage.dm b/code/modules/mob/mob_damage.dm new file mode 100644 index 000000000000..2897d3117330 --- /dev/null +++ b/code/modules/mob/mob_damage.dm @@ -0,0 +1,150 @@ +/mob/proc/get_damage(damage_type) + switch(damage_type) + if(BRUTE) + return getBruteLoss() + if(BURN) + return getFireLoss() + if(TOX) + return getToxLoss() + if(CLONE) + return getCloneLoss() + if(OXY) + return getOxyLoss() + if(IRRADIATE) + return radiation + if(PAIN) + return getHalLoss() + if(BRAIN) + return getBrainLoss() + //if(ELECTROCUTE) + return 0 + +/mob/proc/set_damage(damage_type, amount, do_update_health) + switch(damage_type) + if(BRUTE) + return setBruteLoss(amount, do_update_health) + if(BURN) + return setFireLoss(amount, do_update_health) + if(TOX) + return setToxLoss(amount, do_update_health) + if(CLONE) + return setCloneLoss(amount, do_update_health) + if(OXY) + return setOxyLoss(amount, do_update_health) + if(PAIN) + return setHalLoss(amount, do_update_health) + if(BRAIN) + return setBrainLoss(amount, do_update_health) + //if(IRRADIATE) + //if(ELECTROCUTE) + return 0 + +/mob/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + switch(damage_type) + if(BRUTE) + return adjustBruteLoss(damage, do_update_health) + if(BURN) + return adjustFireLoss(damage, do_update_health) + if(TOX) + return adjustToxLoss(damage, do_update_health) + if(CLONE) + return adjustCloneLoss(damage, do_update_health) + if(OXY) + return adjustOxyLoss(damage, do_update_health) + if(PAIN) + return adjustHalLoss(damage, do_update_health) + if(IRRADIATE) + return apply_radiation(damage) + if(BRAIN) + return adjustBrainLoss(damage, do_update_health) + //if(ELECTROCUTE) + return 0 + +/mob/proc/heal_damage(damage_type, amount, do_update_health) + return take_damage(-(amount), damage_type, do_update_health = do_update_health) + +/// Returns TRUE if updates should happen, FALSE if not. +/mob/proc/update_health() + SHOULD_CALL_PARENT(TRUE) + return !(status_flags & GODMODE) + +// Damage stubs to allow for calling on /mob (usr etc) +/mob/proc/getBruteLoss() + return 0 +/mob/proc/getOxyLoss() + return 0 +/mob/proc/getToxLoss() + return 0 +/mob/proc/getFireLoss() + return 0 +/mob/proc/getHalLoss() + return 0 +/mob/proc/getCloneLoss() + return 0 + +/mob/proc/setBruteLoss(var/amount) + return +/mob/proc/setOxyLoss(var/amount) + return +/mob/proc/setToxLoss(var/amount) + return +/mob/proc/setFireLoss(var/amount) + return +/mob/proc/setHalLoss(var/amount) + return +/mob/proc/setBrainLoss(var/amount) + return +/mob/proc/setCloneLoss(var/amount) + return + +/mob/proc/adjustToxLoss(var/amount, var/do_update_health = TRUE) + return +/mob/proc/adjustFireLoss(var/amount, var/do_update_health = TRUE) + return +/mob/proc/adjustHalLoss(var/amount, var/do_update_health = TRUE) + return + +/mob/proc/adjustBruteLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(do_update_health) + update_health() + +/mob/proc/adjustOxyLoss(var/damage, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(do_update_health) + update_health() + +/mob/proc/adjustBrainLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(do_update_health) + update_health() + +/mob/proc/adjustCloneLoss(var/amount, var/do_update_health = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(do_update_health) + update_health() + +// Calculates the Siemen's coefficient for a given area of the body. +// 1 is 100% vulnerability, 0 is immune. +/mob/proc/get_siemens_coefficient_for_coverage(coverage_flags = SLOT_HANDS) + var/decl/species/my_species = get_species() + . = my_species ? my_species.shock_vulnerability : 1 + if(. <= 0) + return 0 + if(coverage_flags) + for(var/obj/item/clothing/clothes in get_equipped_items(include_carried = FALSE)) + if(clothes.body_parts_covered & coverage_flags) + if(clothes.siemens_coefficient <= 0) + return 0 + . *= clothes.siemens_coefficient + if(. <= 0) + return 0 + . = max(round(., 0.1), 0) + +//this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. +/mob/proc/get_siemens_coefficient_organ(var/obj/item/organ/external/def_zone) + return (istype(def_zone) && def_zone.body_part) ? get_siemens_coefficient_for_coverage(def_zone.body_part) : 1 + +/mob/proc/apply_radiation(var/damage = 0) + return + diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index aa1738f45161..395560654e05 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -1,16 +1,17 @@ /mob - density = 1 + density = TRUE plane = DEFAULT_PLANE layer = MOB_LAYER + abstract_type = /mob + is_spawnable_type = TRUE - appearance_flags = PIXEL_SCALE + appearance_flags = DEFAULT_APPEARANCE_FLAGS | LONG_GLIDE animate_movement = 2 movable_flags = MOVABLE_FLAG_PROXMOVE virtual_mob = /mob/observer/virtual/mob movement_handlers = list( - /datum/movement_handler/mob/relayed_movement, /datum/movement_handler/mob/death, /datum/movement_handler/mob/conscious, /datum/movement_handler/mob/eye, @@ -25,9 +26,13 @@ /datum/movement_handler/mob/movement ) + mouse_drag_pointer = MOUSE_ACTIVE_POINTER + + var/shift_to_open_context_menu = FALSE + var/mob_flags var/last_quick_move_time = 0 - var/list/client_images = list() // List of images applied to/removed from the client on login/logout + var/list/client_images // Lazylist of images applied to/removed from the client on login/logout var/datum/mind/mind var/lastKnownIP = null @@ -36,66 +41,24 @@ var/stat = CONSCIOUS //Whether a mob is alive or dead. TODO: Move this to living - Nodrak - var/obj/screen/cells = null - - var/obj/screen/hands = null - var/obj/screen/purged = null - var/obj/screen/internals = null - var/obj/screen/oxygen = null - var/obj/screen/i_select = null - var/obj/screen/m_select = null - var/obj/screen/toxin = null - var/obj/screen/fire = null - var/obj/screen/bodytemp = null - var/obj/screen/healths = null - var/obj/screen/throw_icon = null - var/obj/screen/nutrition_icon = null - var/obj/screen/hydration_icon = null - var/obj/screen/pressure = null - var/obj/screen/pain = null - var/obj/screen/up_hint = null - var/obj/screen/gun/item/item_use_icon = null - var/obj/screen/gun/radio/radio_use_icon = null - var/obj/screen/gun/move/gun_move_icon = null - var/obj/screen/gun/run/gun_run_icon = null - var/obj/screen/gun/mode/gun_setting_icon = null - - var/obj/screen/movable/ability_master/ability_master = null - /*A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob. A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such. The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs). I'll make some notes on where certain variable defines should probably go. Changing this around would probably require a good look-over the pre-existing code. */ - var/obj/screen/zone_sel/zone_sel = null - var/use_me = 1 //Allows all mobs to use the me verb by default, will have to manually specify they cannot var/damageoverlaytemp = 0 var/obj/machinery/machine = null - var/poll_answer = 0.0 - var/sdisabilities = 0 //Carbon - var/disabilities = 0 //Carbon var/next_move = null - var/hand = null var/real_name = null - var/bhunger = 0 //Carbon - - var/drugged = 0 //Carbon - var/confused = 0 //Carbon - var/sleeping = 0 //Carbon - var/resting = 0 //Carbon - var/lying = 0 - var/lying_prev = 0 + var/radio_interrupt_cooldown = 0 // TODO move this to /human - var/radio_interrupt_cooldown = 0 - - var/unacidable = 0 - var/list/pinned = list() // List of things pinning this creature to walls (see living_defense.dm) - var/list/embedded = list() // Embedded items, since simple mobs don't have organs. - var/list/languages = list() // For speaking/listening. + var/list/pinned // Lazylist of things pinning this creature to walls (see living_defense.dm) + var/list/embedded // Embedded items, since simple mobs don't have organs. + var/list/languages = list() // TODO: lazylist this var. For speaking/listening. var/species_language = null // For species who want reset to use a specified default. var/only_species_language = 0 // For species who can only speak their default and no other languages. Does not effect understanding. var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null. @@ -103,57 +66,33 @@ var/facing_dir = null // Used for the ancient art of moonwalking. var/name_archive //For admin things like possession - + var/mob_sort_value = INFINITY // used for sorted player list, higher means closer to the bottom of the list. var/timeofdeath = 0 var/bodytemperature = 310.055 //98.7 F - var/default_pixel_x = 0 - var/default_pixel_y = 0 - var/default_pixel_z = 0 var/shakecamera = 0 - var/a_intent = I_HELP//Living - var/decl/move_intent/move_intent = /decl/move_intent/walk var/list/move_intents = list(/decl/move_intent/walk) var/decl/move_intent/default_walk_intent var/decl/move_intent/default_run_intent - var/obj/buckled = null//Living - var/obj/item/l_hand = null//Living - var/obj/item/r_hand = null//Living - var/obj/item/back = null//Human/Monkey - var/obj/item/storage/s_active = null//Carbon - var/obj/item/clothing/mask/wear_mask = null//Carbon + var/datum/storage/active_storage + var/atom/movable/buckled = null var/in_throw_mode = 0 -// var/job = null//Living - var/can_pull_size = ITEM_SIZE_STRUCTURE // Maximum w_class the mob can pull. var/can_pull_mobs = MOB_PULL_SAME // Whether or not the mob can pull other mobs. - var/datum/dna/dna = null//Carbon - var/list/active_genes=list() - var/list/mutations = list() //Carbon -- Doohl - //see: setup.dm for list of mutations - var/radiation = 0.0//Carbon - var/voice_name = "unidentifiable voice" - var/faction = MOB_FACTION_NEUTRAL //Used for checking whether hostile simple animals will attack you, possibly more stuff later - var/blinded = null - var/ear_deaf = null //Carbon - -//The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition) - var/mob/living/carbon/LAssailant = null - mouse_drag_pointer = MOUSE_ACTIVE_POINTER + //The last mob/living to push/drag/grab this mob (mostly used by slimes friend recognition) + var/weakref/last_handled_by_mob - var/update_icon = 1 //Set to 1 to trigger update_icons() at the next life() call - - var/status_flags = CANSTUN|CANWEAKEN|CANPARALYSE|CANPUSH //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc) + var/status_flags = CANSTUN|CANWEAKEN|CANPARALYSE|CANPUSH //bitflags defining which status conditions can be inflicted (replaces canweaken, canstun, etc) var/area/lastarea = null @@ -169,22 +108,36 @@ //so don't treat them as being SSD even though their client var is null. var/mob/teleop = null - var/turf/listed_turf = null //the current turf being examined in the stat panel - var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes + var/turf/listed_turf //the current turf being examined in the stat panel + var/list/shouldnt_see // Lazylist of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes var/mob_size = MOB_SIZE_MEDIUM - var/paralysis = 0 - var/stunned = 0 - var/weakened = 0 - var/drowsyness = 0.0//Carbon - var/flavor_text = "" - var/datum/skillset/skillset = /datum/skillset + var/datum/skillset/skillset - var/list/additional_vision_handlers = list() //Basically a list of atoms from which additional vision data is retrieved + var/list/additional_vision_handlers // A lazylist of atoms from which additional vision data is retrieved var/list/progressbars = null //for stacking do_after bars - var/datum/ai/ai // Type abused. Define with path and will automagically create. Determines behaviour for clientless mobs. + var/datum/mob_controller/ai // Type abused. Define with path and will automagically create. Determines behaviour for clientless mobs. + + var/holder_type + /// If this mob is or was piloted by a player with typing indicators enabled, an instance of one. + var/atom/movable/typing_indicator/typing_indicator + /// Whether this mob is currently typing, if piloted by a player. + var/is_typing + + /// Used for darksight, required on all mobs to ensure lighting renders properly. + var/obj/screen/lighting_plane_master/lighting_master + + // Offset the overhead text if necessary. + var/offset_overhead_text_x = 0 + var/offset_overhead_text_y = 0 + + /// What bodypart are we currently targetting? + var/selected_zone = BP_CHEST + + /// Are you trying not to hurt your opponent? + var/pulling_punches diff --git a/code/modules/mob/mob_eating.dm b/code/modules/mob/mob_eating.dm new file mode 100644 index 000000000000..c4fb19e2854e --- /dev/null +++ b/code/modules/mob/mob_eating.dm @@ -0,0 +1,61 @@ +//Used to check if they can be fed food/drinks/pills +/mob/proc/check_mouth_coverage() + return get_covering_head_item(SLOT_FACE) + +/mob/proc/check_head_coverage() + return !!get_covering_head_item(SLOT_HEAD) + +/mob/proc/get_covering_head_item(slot_flags) + for(var/slot in global.standard_headgear_slots) + var/obj/item/clothes = get_equipped_item(slot) + if(istype(clothes) && (clothes.body_parts_covered & slot_flags) && !(clothes.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) + return clothes + return null + +/mob/proc/get_eaten_transfer_amount(var/default) + . = default + if(issmall(src)) + . = ceil(.*0.5) + +/mob/proc/can_eat_food_currently(obj/eating, mob/user, consumption_method) + return TRUE + +#define EATING_NO_ISSUE 0 +#define EATING_NBP_MOUTH 1 +#define EATING_BLOCKED_MOUTH 2 + +/mob/proc/can_eat_status() + if(!check_has_mouth()) + return list(EATING_NBP_MOUTH) + var/obj/item/blocked = check_mouth_coverage() + if(blocked) + return list(EATING_BLOCKED_MOUTH, blocked) + return list(EATING_NO_ISSUE) + +/mob/proc/can_eat(food, feedback = TRUE) + var/list/status = can_eat_status() + if(status[1] == EATING_NO_ISSUE) + return TRUE + if(feedback) + if(status[1] == EATING_NBP_MOUTH) + to_chat(src, SPAN_WARNING("Where do you intend to put \the [food]? You don't have a mouth!")) + else if(status[1] == EATING_BLOCKED_MOUTH) + to_chat(src, SPAN_WARNING("\The [status[2]] is in the way!")) + return FALSE + +/mob/proc/can_force_feed(mob/target, food, feedback = TRUE) + if(src == target) + return can_eat(food) + var/list/status = target.can_eat_status() + if(status[1] == EATING_NO_ISSUE) + return TRUE + if(feedback) + if(status[1] == EATING_NBP_MOUTH) + to_chat(src, SPAN_WARNING("Where do you intend to put \the [food]? \The [target] doesn't have a mouth!")) + else if(status[1] == EATING_BLOCKED_MOUTH) + to_chat(src, SPAN_WARNING("\The [status[2]] is in the way!")) + return FALSE + +#undef EATING_NO_ISSUE +#undef EATING_NBP_MOUTH +#undef EATING_BLOCKED_MOUTH diff --git a/code/modules/mob/mob_genetics.dm b/code/modules/mob/mob_genetics.dm new file mode 100644 index 000000000000..d7fc30f3688d --- /dev/null +++ b/code/modules/mob/mob_genetics.dm @@ -0,0 +1,17 @@ +/mob/proc/get_genetic_conditions() + RETURN_TYPE(/list) + +/mob/proc/can_have_genetic_conditions() + return FALSE + +/mob/proc/has_genetic_condition(condition_type) + return FALSE + +/mob/proc/add_genetic_condition(condition_type, temporary_time) + return FALSE + +/mob/proc/remove_genetic_condition(condition_type) + return FALSE + +/mob/proc/reset_genetic_conditions() + return diff --git a/code/modules/mob/mob_grabs.dm b/code/modules/mob/mob_grabs.dm index 21211f564f6f..0cea8113ed7e 100644 --- a/code/modules/mob/mob_grabs.dm +++ b/code/modules/mob/mob_grabs.dm @@ -1,5 +1,5 @@ // Casting stubs for grabs, check /mob/living for full definition. -/mob/proc/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/damage_flags = 0, var/used_weapon = null, var/armor_pen, var/silent = FALSE) +/mob/proc/apply_damage(damage = 0, damagetype = BRUTE, def_zone, damage_flags = 0, obj/used_weapon, armor_pen, silent = FALSE, obj/item/organ/external/given_organ) return /mob/proc/get_blocked_ratio(def_zone, damage_type, damage_flags, armor_pen, damage) return @@ -7,9 +7,6 @@ return /mob/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0) return -// See /mob/living/carbon/human for this one. -/mob/proc/get_organ(var/zone) - return // End grab casting stubs. /mob/can_be_grabbed(var/mob/grabber, var/target_zone) @@ -24,14 +21,16 @@ if((grabber.mob_size == mob_size) && grabber.can_pull_mobs == MOB_PULL_SMALLER) to_chat(grabber, SPAN_WARNING("\The [src] is too large for you to move!")) return FALSE + if(isliving(grabber)) + last_handled_by_mob = weakref(grabber) /mob/proc/handle_grab_damage() - set waitfor = 0 + set waitfor = FALSE -/mob/proc/handle_grabs_after_move() - set waitfor = 0 +/mob/proc/handle_grabs_after_move(var/turf/old_loc, var/direction) + set waitfor = FALSE -/mob/proc/add_grab(var/obj/item/grab/grab) +/mob/proc/add_grab(var/obj/item/grab/grab, var/defer_hand = FALSE) return FALSE /mob/proc/ProcessGrabs() @@ -41,3 +40,6 @@ . = list() for(var/obj/item/grab/grab in contents) . += grab + +/mob/get_object_size() + return mob_size diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 6c133e10c275..7a546009a86c 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -1,5 +1,5 @@ /proc/issmall(A) - if(A && istype(A, /mob/living)) + if(isliving(A)) var/mob/living/L = A return L.mob_size <= MOB_SIZE_SMALL return 0 @@ -8,71 +8,47 @@ /proc/mob_size_difference(var/mob_size_A, var/mob_size_B) return round(log(2, mob_size_A/mob_size_B), 1) -/mob/proc/can_wield_item(obj/item/W) - if(W.w_class >= ITEM_SIZE_LARGE && issmall(src)) - return FALSE //M is too small to wield this - return TRUE - -/mob/living/proc/isSynthetic() +/mob/proc/isMonkey() return 0 -/mob/living/carbon/human/isSynthetic() - if(isnull(full_prosthetic)) - robolimb_count = 0 - for(var/obj/item/organ/external/E in organs) - if(BP_IS_PROSTHETIC(E)) - robolimb_count++ - full_prosthetic = (robolimb_count == organs.len) - update_emotes() - return full_prosthetic - -/mob/living/silicon/isSynthetic() - return 1 +/mob/living/human/isMonkey() + return istype(species, /decl/species/monkey) -/mob/proc/isMonkey() - return 0 -/mob/living/carbon/human/isMonkey() - return istype(species, /datum/species/monkey) +/** + * Checks if the target has a grab from the user + */ +/mob/proc/has_danger_grab(mob/user) + if (user == src || isrobot(user) || isbot(user)) + return TRUE + for (var/obj/item/grab/grab as anything in grabbed_by) + if (grab.force_danger()) + return TRUE -proc/isdeaf(A) +/proc/isdeaf(A) if(isliving(A)) var/mob/living/M = A - return (M.sdisabilities & DEAFENED) || M.ear_deaf - return 0 - -proc/hasorgans(A) // Fucking really?? - return ishuman(A) - -proc/iscuffed(A) - if(istype(A, /mob/living/carbon)) - var/mob/living/carbon/C = A - if(C.handcuffed) - return 1 + return M.has_genetic_condition(GENE_COND_DEAFENED) || GET_STATUS(M, STAT_DEAF) return 0 -proc/hassensorlevel(A, var/level) - var/mob/living/carbon/human/H = A - if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under)) - var/obj/item/clothing/under/U = H.w_uniform - return U.sensor_mode >= level - return 0 +/proc/iscuffed(var/mob/mob) + return ismob(mob) && !!mob.get_equipped_item(slot_handcuffed_str) -proc/getsensorlevel(A) - var/mob/living/carbon/human/H = A - if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under)) - var/obj/item/clothing/under/U = H.w_uniform - return U.sensor_mode - return SUIT_SENSOR_OFF +/proc/hassensorlevel(A, var/level) + return getsensorlevel(A) >= level +/proc/getsensorlevel(A) + var/mob/M = A + if(!istype(M)) + return VITALS_SENSOR_OFF + var/obj/item/clothing/sensor/vitals/sensor = M.get_vitals_sensor() + if(sensor) + return sensor.sensor_mode + return VITALS_SENSOR_OFF /proc/is_admin(var/mob/user) return check_rights(R_ADMIN, 0, user) != 0 - -/proc/hsl2rgb(h, s, l) - return //TODO: Implement - /* Miss Chance */ @@ -80,7 +56,7 @@ proc/getsensorlevel(A) //TODO: Integrate defence zones and targeting body parts with the actual organ system, move these into organ definitions. //The base miss chance for the different defence zones -var/list/global/base_miss_chance = list( +var/global/list/global/base_miss_chance = list( BP_HEAD = 70, BP_CHEST = 10, BP_GROIN = 20, @@ -96,7 +72,7 @@ var/list/global/base_miss_chance = list( //Used to weight organs when an organ is hit randomly (i.e. not a directed, aimed attack). //Also used to weight the protection value that armour provides for covering that body part when calculating protection from full-body effects. -var/list/global/organ_rel_size = list( +var/global/list/global/organ_rel_size = list( BP_HEAD = 25, BP_CHEST = 70, BP_GROIN = 30, @@ -110,58 +86,42 @@ var/list/global/organ_rel_size = list( BP_R_FOOT = 10, ) -/proc/check_zone(zone) - if(!zone) return BP_CHEST - switch(zone) - if(BP_EYES) - zone = BP_HEAD - if(BP_MOUTH) - zone = BP_HEAD - return zone +/proc/check_zone(zone, mob/target, var/base_zone_only) + . = zone || BP_CHEST + if(. == BP_EYES || . == BP_MOUTH) + . = BP_HEAD + if(!base_zone_only && target) + . = target.get_bodytype()?.get_limb_from_zone(.) || . // Returns zone with a certain probability. If the probability fails, or no zone is specified, then a random body part is chosen. // Do not use this if someone is intentionally trying to hit a specific body part. // Use get_zone_with_miss_chance() for that. -/proc/ran_zone(zone, probability) - if (zone) - zone = check_zone(zone) - if (prob(probability)) +/proc/ran_zone(zone, probability, target) + if(zone) + zone = check_zone(zone, target) + if(prob(probability)) return zone - var/ran_zone = zone while (ran_zone == zone) - ran_zone = pick ( - organ_rel_size[BP_HEAD]; BP_HEAD, - organ_rel_size[BP_CHEST]; BP_CHEST, - organ_rel_size[BP_GROIN]; BP_GROIN, - organ_rel_size[BP_L_ARM]; BP_L_ARM, - organ_rel_size[BP_R_ARM]; BP_R_ARM, - organ_rel_size[BP_L_LEG]; BP_L_LEG, - organ_rel_size[BP_R_LEG]; BP_R_LEG, - organ_rel_size[BP_L_HAND]; BP_L_HAND, - organ_rel_size[BP_R_HAND]; BP_R_HAND, - organ_rel_size[BP_L_FOOT]; BP_L_FOOT, - organ_rel_size[BP_R_FOOT]; BP_R_FOOT - ) - + ran_zone = pickweight(organ_rel_size) return ran_zone // Emulates targetting a specific body part, and miss chances // May return null if missed // miss_chance_mod may be negative. /proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0) - zone = check_zone(zone) + zone = check_zone(zone, target) if(!ranged_attack) // target isn't trying to fight - if(target.a_intent == I_HELP) + if(target.check_intent(I_FLAG_HELP)) return zone // you cannot miss if your target is prone or restrained - if(target.buckled || target.lying) + if(target.buckled || target.current_posture.prone) return zone // if your target is being grabbed aggressively by someone you cannot miss either - for(var/obj/item/grab/G in target.grabbed_by) - if(G.stop_move()) + for(var/obj/item/grab/grab as anything in target.grabbed_by) + if(grab.stop_move()) return zone var/miss_chance = 10 @@ -189,8 +149,8 @@ var/list/global/organ_rel_size = list( var/intag = 0 var/block = list() . = list() - for(var/i = 1, i <= length(n), i++) - var/char = copytext(n, i, i+1) + for(var/i = 1, i <= length_char(n), i++) + var/char = copytext_char(n, i, i+1) if(!intag && (char == "<")) intag = 1 . += stars_no_html(JOINTEXT(block), pr, re_encode) //stars added here @@ -207,8 +167,8 @@ var/list/global/organ_rel_size = list( /proc/stars_no_html(text, pr, re_encode) text = html_decode(text) //We don't want to screw up escaped characters . = list() - for(var/i = 1, i <= length(text), i++) - var/char = copytext(text, i, i+1) + for(var/i = 1, i <= length_char(text), i++) + var/char = copytext_char(text, i, i+1) if(char == " " || prob(pr)) . += char else @@ -217,204 +177,209 @@ var/list/global/organ_rel_size = list( if(re_encode) . = html_encode(.) -proc/slur(phrase) +/proc/slur(phrase) phrase = html_decode(phrase) - var/leng=length(phrase) - var/counter=length(phrase) + var/leng=length_char(phrase) + var/counter=length_char(phrase) var/newphrase="" var/newletter="" while(counter>=1) - newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2) + newletter=copytext_char(phrase,(leng-counter)+1,(leng-counter)+2) if(rand(1,3)==3) if(lowertext(newletter)=="o") newletter="u" if(lowertext(newletter)=="s") newletter="ch" if(lowertext(newletter)=="a") newletter="ah" if(lowertext(newletter)=="c") newletter="k" switch(rand(1,15)) - if(1,3,5,8) newletter="[lowertext(newletter)]" - if(2,4,6,15) newletter="[uppertext(newletter)]" - if(7) newletter+="'" - //if(9,10) newletter="[newletter]" - //if(11,12) newletter="[newletter]" - //if(13) newletter="[newletter]" + if(1 to 4) newletter="[lowertext(newletter)]" + if(5 to 8) newletter="[uppertext(newletter)]" + if(9) newletter+="'" + else newletter = newletter newphrase+="[newletter]";counter-=1 return newphrase -/proc/stutter(n) - var/te = html_decode(n) - var/t = ""//placed before the message. Not really sure what it's for. - n = length(n)//length of the entire word - var/p = null - p = 1//1 is the start of any word - while(p <= n)//while P, which starts at 1 is less or equal to N which is the length. - var/n_letter = copytext(te, p, p + 1)//copies text from a certain distance. In this case, only one letter at a time. - if (prob(80) && (ckey(n_letter) in list("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z"))) - if (prob(10)) - n_letter = text("[n_letter]-[n_letter]-[n_letter]-[n_letter]")//replaces the current letter with this instead. - else - if (prob(20)) - n_letter = text("[n_letter]-[n_letter]-[n_letter]") - else - if (prob(5)) - n_letter = null - else - n_letter = text("[n_letter]-[n_letter]") - t = text("[t][n_letter]")//since the above is ran through for each letter, the text just adds up back to the original word. - p++//for each letter p is increased to find where the next letter will be. - return sanitize(t) - - -proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added +/proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added /* Turn text into complete gibberish! */ var/returntext = "" - for(var/i = 1, i <= length(t), i++) + for(var/i in 1 to length_char(t)) - var/letter = copytext(t, i, i+1) + var/letter = copytext_char(t, i, i+1) if(prob(50)) if(p >= 70) letter = "" - for(var/j = 1, j <= rand(0, 2), j++) + for(var/j in 1 to rand(0, 2)) letter += pick("#","@","*","&","%","$","/", "<", ">", ";","*","*","*","*","*","*","*") returntext += letter return returntext +/proc/NewStutter(phrase,stunned) + phrase = html_decode(phrase) + + var/list/split_phrase = splittext(phrase," ") //Split it up into words. + + var/list/unstuttered_words = split_phrase.Copy() + var/i = rand(1,3) + if(stunned) i = split_phrase.len + for(,i > 0,i--) //Pick a few words to stutter on. + + if (!unstuttered_words.len) + break + var/word = pick(unstuttered_words) + unstuttered_words -= word //Remove from unstuttered words so we don't stutter it again. + var/index = split_phrase.Find(word) //Find the word in the split phrase so we can replace it. + + //Search for dipthongs (two letters that make one sound.) + var/first_sound = copytext_char(word,1,3) + var/first_letter = copytext_char(word,1,2) + if(lowertext(first_sound) in list("ch","th","sh")) + first_letter = first_sound + + //Repeat the first letter to create a stutter. + var/rnum = rand(1,3) + switch(rnum) + if(1) + word = "[first_letter]-[word]" + if(2) + word = "[first_letter]-[first_letter]-[word]" + if(3) + word = "[first_letter]-[word]" + + split_phrase[index] = word + + return sanitize(jointext(split_phrase," ")) -/proc/ninjaspeak(n) /* -The difference with stutter is that this proc can stutter more than 1 letter -The issue here is that anything that does not have a space is treated as one word (in many instances). For instance, "LOOKING," is a word, including the comma. -It's fairly easy to fix if dealing with single letters but not so much with compounds of letters./N +RadioChat Filter. +args: +message - returns a distorted version of this +distortion_chance - the chance of a filter being applied to each character. +distortion_speed - multiplier for the chance increase. +distortion - starting distortion. +english_only - whether to use traditional english letters only (for use in NanoUI) */ - var/te = html_decode(n) - var/t = "" - n = length(n) - var/p = 1 - while(p <= n) - var/n_letter - var/n_mod = rand(1,4) - if(p+n_mod>n+1) - n_letter = copytext(te, p, n+1) - else - n_letter = copytext(te, p, p+n_mod) - if (prob(50)) - if (prob(30)) - n_letter = text("[n_letter]-[n_letter]-[n_letter]") - else - n_letter = text("[n_letter]-[n_letter]") +/proc/RadioChat(mob/living/user, message, distortion_chance = 60, distortion_speed = 1, distortion = 1, english_only = 0) + var/decl/language/language = user?.get_default_language() + message = html_decode(message) + var/new_message = "" + var/input_size = length(message) + var/cursor_position = 0 + if(input_size < 20) // Short messages get distorted too. Bit hacksy. + distortion += (20-input_size)/2 + while(cursor_position <= input_size) + var/newletter=copytext_char(message, cursor_position, cursor_position+1) + if(!prob(distortion_chance)) + new_message += newletter + cursor_position += 1 + continue + if(newletter != " ") + if(prob(0.08 * distortion)) // Major cutout + newletter = "*zzzt*" + cursor_position += rand(1, (length(message) - cursor_position)) // Skip some characters + distortion += 1 * distortion_speed + else if(prob(0.8 * distortion)) // Minor cut out + if(prob(25)) + newletter = ".." + else if(prob(25)) + newletter = " " + else + newletter = "" + distortion += 0.25 * distortion_speed + else if(prob(2 * distortion)) // Mishearing + if(language && language.syllables && prob(50)) + newletter = pick(language.syllables) + else + newletter = pick("a","e","i","o","u") + distortion += 0.25 * distortion_speed + else if(prob(1.5 * distortion)) // Mishearing + if(language && prob(50)) + if(language.syllables) + newletter = pick (language.syllables) + else + newletter = "*" + else + if(english_only) + newletter += "*" + else + newletter = pick("ø", "Ð", "%", "æ", "µ") + distortion += 0.5 * distortion_speed + else if(prob(0.75 * distortion)) // Incomprehensible + newletter = pick("<", ">", "!", "$", "%", "^", "&", "*", "~", "#") + distortion += 0.75 * distortion_speed + else if(prob(0.05 * distortion)) // Total cut out + if(!english_only) + newletter = "¦w¡¼b»%> -BZZT-" + else + newletter = "srgt%$hjc< -BZZT-" + new_message += newletter + break + else if(prob(2.5 * distortion)) // Sound distortion. Still recognisable, mostly. + switch(lowertext(newletter)) + if("s") + newletter = "$" + if("e") + newletter = "£" + if("w") + newletter = "ø" + if("y") + newletter = "¡" + if("x") + newletter = "æ" + if("u") + newletter = "µ" else - n_letter = text("[n_letter]") - t = text("[t][n_letter]") - p=p+n_mod - return sanitize(t) + if(prob(0.2 * distortion)) + newletter = " *crackle* " + distortion += 0.25 * distortion_speed + if(prob(20)) + capitalize(newletter) + new_message += newletter + cursor_position += 1 + return new_message #define TICKS_PER_RECOIL_ANIM 2 #define PIXELS_PER_STRENGTH_VAL 16 /proc/shake_camera(mob/M, duration, strength=1) - set waitfor = 0 - if(!M || !M.client || M.shakecamera || M.stat || isEye(M) || isAI(M)) + var/current_time = world.time + if(!M || !M.client || (M.shakecamera > current_time)|| M.stat || isEye(M) || isAI(M)) return - M.shakecamera = TRUE + M.shakecamera = current_time + max(TICKS_PER_RECOIL_ANIM, duration) strength = abs(strength)*PIXELS_PER_STRENGTH_VAL - var/steps = min(1, Floor(duration/TICKS_PER_RECOIL_ANIM))-1 - animate(M.client, pixel_x = rand(-(strength), strength), pixel_y = rand(-(strength), strength), time = TICKS_PER_RECOIL_ANIM) - sleep(TICKS_PER_RECOIL_ANIM) + var/steps = min(1, floor(duration/TICKS_PER_RECOIL_ANIM))-1 + animate(M.client, pixel_x = rand(-(strength), strength), pixel_y = rand(-(strength), strength), time = TICKS_PER_RECOIL_ANIM, easing = JUMP_EASING|EASE_IN) if(steps) for(var/i = 1 to steps) - animate(M.client, pixel_x = rand(-(strength), strength), pixel_y = rand(-(strength), strength), time = TICKS_PER_RECOIL_ANIM) - sleep(TICKS_PER_RECOIL_ANIM) - M?.shakecamera = FALSE - animate(M.client, pixel_x = 0, pixel_y = 0, time = TICKS_PER_RECOIL_ANIM) + animate(pixel_x = (M.client?.default_pixel_x || 0) + rand(-(strength), strength), pixel_y = (M.client?.default_pixel_y || 0) + rand(-(strength), strength), time = TICKS_PER_RECOIL_ANIM, easing = JUMP_EASING|EASE_IN) + animate(pixel_x = (M.client.default_pixel_x || 0), pixel_y = (M.client.default_pixel_y || 0), time = TICKS_PER_RECOIL_ANIM) #undef TICKS_PER_RECOIL_ANIM #undef PIXELS_PER_STRENGTH_VAL -/proc/findname(msg) - for(var/mob/M in SSmobs.mob_list) - if (M.real_name == text("[msg]")) - return 1 - return 0 - - /mob/proc/abiotic(var/full_body = FALSE) - if(full_body && ((src.l_hand && src.l_hand.simulated) || (src.r_hand && src.r_hand.simulated) || (src.back || src.wear_mask))) - return TRUE - - if((src.l_hand && src.l_hand.simulated) || (src.r_hand && src.r_hand.simulated)) + . = FALSE + for(var/obj/item/thing in get_held_items()) + if(thing.simulated) + return TRUE + if(full_body && (get_equipped_item(slot_back_str) || get_equipped_item(slot_wear_mask_str))) return TRUE - return FALSE - -//converts intent-strings into numbers and back -var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) -/proc/intent_numeric(argument) - if(istext(argument)) - switch(argument) - if(I_HELP) return 0 - if(I_DISARM) return 1 - if(I_GRAB) return 2 - else return 3 - else - switch(argument) - if(0) return I_HELP - if(1) return I_DISARM - if(2) return I_GRAB - else return I_HURT - -//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left -/mob/verb/a_intent_change(input as text) - set name = "a-intent" - set hidden = 1 - - if(ishuman(src) || isbrain(src) || isslime(src)) - switch(input) - if(I_HELP,I_DISARM,I_GRAB,I_HURT) - a_intent = input - if("right") - a_intent = intent_numeric((intent_numeric(a_intent)+1) % 4) - if("left") - a_intent = intent_numeric((intent_numeric(a_intent)+3) % 4) - if(hud_used && hud_used.action_intent) - hud_used.action_intent.icon_state = "intent_[a_intent]" - - else if(isrobot(src)) - switch(input) - if(I_HELP) - a_intent = I_HELP - if(I_HURT) - a_intent = I_HURT - if("right","left") - a_intent = intent_numeric(intent_numeric(a_intent) - 3) - if(hud_used && hud_used.action_intent) - if(a_intent == I_HURT) - hud_used.action_intent.icon_state = I_HURT - else - hud_used.action_intent.icon_state = I_HELP - -/proc/is_blind(A) - if(istype(A, /mob/living/carbon)) - var/mob/living/carbon/C = A - if(C.sdisabilities & BLINDED|| C.blinded) - return 1 - return 0 - /mob/proc/welding_eyecheck() return /proc/broadcast_security_hud_message(var/message, var/broadcast_source) - broadcast_hud_message(message, broadcast_source, GLOB.sec_hud_users, /obj/item/clothing/glasses/hud/security) + broadcast_hud_message(message, broadcast_source, global.sec_hud_users, /obj/item/clothing/glasses/hud/security) /proc/broadcast_medical_hud_message(var/message, var/broadcast_source) - broadcast_hud_message(message, broadcast_source, GLOB.med_hud_users, /obj/item/clothing/glasses/hud/health) + broadcast_hud_message(message, broadcast_source, global.med_hud_users, /obj/item/clothing/glasses/hud/health) /proc/broadcast_hud_message(var/message, var/broadcast_source, var/list/targets, var/icon) var/turf/sourceturf = get_turf(broadcast_source) for(var/mob/M in targets) - if(!sourceturf || (get_z(M) in GetConnectedZlevels(sourceturf.z))) - M.show_message("\icon[icon] [message]", 1) + if(!sourceturf || (get_z(M) in SSmapping.get_connected_levels(sourceturf.z))) + M.show_message("[html_icon(icon)] [message]", 1) /proc/mobs_in_area(var/area/A) var/list/mobs = new @@ -427,7 +392,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) /proc/announce_ghost_joinleave(O, var/joined_ghosts = 1, var/message = "") var/client/C //Accept any type, sort what we want here - if(istype(O, /mob)) + if(ismob(O)) var/mob/M = O if(M.client) C = M.client @@ -437,10 +402,10 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) var/datum/mind/M = O if(M.current && M.current.client) C = M.current.client - else if(M.original && M.original.client) - C = M.original.client if(C) + if(C.get_preference_value(/datum/client_preference/anon_say) == PREF_YES) + return var/name if(C.mob) var/mob/M = C.mob @@ -463,7 +428,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) communicate(/decl/communication_channel/dsay, C || O, message, /decl/dsay_communication/direct) /mob/proc/switch_to_camera(var/obj/machinery/camera/C) - if (!C.can_use() || stat || (get_dist(C, src) > 1 || machine != src || blinded)) + if (!C.can_use() || stat || (get_dist(C, src) > 1 || machine != src || is_blind())) return 0 check_eye(src) return 1 @@ -479,52 +444,39 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) /mob/proc/is_client_active(var/active = 1) return client && client.inactivity < active MINUTES -/mob/proc/can_eat() - return 1 - -/mob/proc/can_force_feed() - return 1 - #define SAFE_PERP -50 -/mob/living/proc/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) - if(stat == DEAD) - return SAFE_PERP - - return 0 +/mob/living/proc/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest, var/check_network) -/mob/living/carbon/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) - if(handcuffed) + if(stat == DEAD) return SAFE_PERP - - return ..() - -/mob/living/carbon/human/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) - var/threatcount = ..() - if(. == SAFE_PERP) + if(get_equipped_item(slot_handcuffed_str)) return SAFE_PERP //Agent cards lower threatlevel. + var/threatcount = 0 var/obj/item/card/id/id = GetIdCard() - if(id && istype(id, /obj/item/card/id/syndicate)) - threatcount -= 2 + // A proper CentCom id is hard currency. - else if(id && istype(id, /obj/item/card/id/centcom)) + if(istype(id, /obj/item/card/id/centcom)) return SAFE_PERP + // Syndicate IDs have masking I guess. + if(istype(id, /obj/item/card/id/syndicate)) + threatcount -= 2 + if(check_access && !access_obj.allowed(src)) threatcount += 4 if(auth_weapons && !access_obj.allowed(src)) - if(istype(l_hand, /obj/item/gun) || istype(l_hand, /obj/item/energy_blade) || istype(l_hand, /obj/item/baton)) - threatcount += 4 - - if(istype(r_hand, /obj/item/gun) || istype(r_hand, /obj/item/energy_blade) || istype(r_hand, /obj/item/baton)) - threatcount += 4 + for(var/thing in get_held_items()) + if(istype(thing, /obj/item/gun) || istype(thing, /obj/item/energy_blade) || istype(thing, /obj/item/baton)) + threatcount += 4 + var/obj/item/belt = get_equipped_item(slot_belt_str) if(istype(belt, /obj/item/gun) || istype(belt, /obj/item/energy_blade) || istype(belt, /obj/item/baton)) threatcount += 2 - if(species.name != GLOB.using_map.default_species) + if(get_species()?.uid != global.using_map.default_species) threatcount += 2 if(check_records || check_arrest) @@ -532,21 +484,28 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) if(id) perpname = id.registered_name - var/datum/computer_file/report/crew_record/CR = get_crewmember_record(perpname) + var/datum/computer_file/report/crew_record/CR + if(check_network) + var/datum/extension/network_device/obj_device = get_extension(access_obj, /datum/extension/network_device) + var/datum/computer_network/obj_network = obj_device?.get_network(NET_FEATURE_SECURITY) + CR = obj_network?.get_crew_record_by_name(perpname) + else + CR = get_crewmember_record(perpname) + if(check_records && !CR && !isMonkey()) threatcount += 4 - if(check_arrest && CR && (CR.get_criminalStatus() == GLOB.arrest_security_status)) + if(check_arrest && CR && (CR.get_criminalStatus() == global.arrest_security_status)) threatcount += 4 return threatcount -/mob/living/simple_animal/hostile/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) +/mob/living/simple_animal/hostile/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest, var/check_network) var/threatcount = ..() if(. == SAFE_PERP) return SAFE_PERP - if(!istype(src, /mob/living/simple_animal/hostile/retaliate/goat)) + if(!istype(src, /mob/living/simple_animal/hostile/goat)) threatcount += 4 return threatcount @@ -559,38 +518,32 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) /mob/observer/ghost/get_multitool() return can_admin_interact() && ..(ghost_multitool) -/mob/living/carbon/human/get_multitool() - return ..(get_active_hand()) +/mob/living/human/get_multitool() + return ..(get_active_held_item()) /mob/living/silicon/robot/get_multitool() - return ..(get_active_hand()) + return ..(get_active_held_item()) /mob/living/silicon/ai/get_multitool() return ..(aiMulti) -/proc/get_both_hands(mob/living/carbon/M) - if(!istype(M)) - return - var/list/hands = list(M.l_hand, M.r_hand) - return hands - /mob/proc/refresh_client_images() - if(client) + if(client && LAZYLEN(client_images)) client.images |= client_images /mob/proc/hide_client_images() - if(client) + if(client && LAZYLEN(client_images)) client.images -= client_images /mob/proc/add_client_image(var/image) if(image in client_images) return - client_images += image + LAZYADD(client_images, image) if(client) client.images += image /mob/proc/remove_client_image(var/image) - client_images -= image + LAZYREMOVE(client_images, image) if(client) client.images -= image @@ -604,37 +557,15 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) SetName(new_name) if(mind) mind.name = new_name - if(dna) - dna.real_name = real_name return 1 /mob/proc/ssd_check() - return !client && !teleop - -/mob/proc/jittery_damage() - return //Only for living/carbon/human/ - -/mob/living/carbon/human/jittery_damage() - var/obj/item/organ/internal/heart/L = internal_organs_by_name[BP_HEART] - if(!istype(L)) - return 0 - if(BP_IS_PROSTHETIC(L)) - return 0//Robotic hearts don't get jittery. - if(src.jitteriness >= 400 && prob(5)) //Kills people if they have high jitters. - if(prob(1)) - L.take_internal_damage(L.max_damage / 2, 0) - to_chat(src, "Something explodes in your heart.") - admin_victim_log(src, "has taken lethal heart damage at jitteriness level [src.jitteriness].") - else - L.take_internal_damage(1, 0) - to_chat(src, "The jitters are killing you! You feel your heart beating out of your chest.") - admin_victim_log(src, "has taken minor heart damage at jitteriness level [src.jitteriness].") - return 1 + return !client && !teleop && (last_ckey || !ai) /mob/proc/try_teleport(var/area/thearea) - if(!istype(thearea)) - if(istype(thearea, /list)) - thearea = thearea[1] + if(istype(thearea, /list)) + var/list/area_list = thearea + thearea = area_list[1] var/list/L = list() for(var/turf/T in get_area_turfs(thearea)) if(!T.density) @@ -670,15 +601,15 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) //Tries to find the mob's email. /proc/find_email(real_name) - for(var/mob/mob in GLOB.living_mob_list_) + for(var/mob/mob in global.living_mob_list_) if(mob.real_name == real_name) if(!mob.mind) return - return mob.mind.initial_email_login["login"] + return mob.mind.initial_account_login["login"] + "@[mob.mind.account_network]" //This gets an input while also checking a mob for whether it is incapacitated or not. /mob/proc/get_input(var/message, var/title, var/default, var/choice_type, var/obj/required_item) - if(src.incapacitated() || (required_item && !GLOB.hands_state.can_use_topic(required_item,src))) + if(src.incapacitated() || (required_item && !global.hands_topic_state.can_use_topic(required_item,src))) return null var/choice if(islist(choice_type)) @@ -691,16 +622,10 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) choice = input(src, message, title, default) as null|num if(MOB_INPUT_MESSAGE) choice = input(src, message, title, default) as null|message - if(isnull(choice) || src.incapacitated() || (required_item && !GLOB.hands_state.can_use_topic(required_item,src))) + if(isnull(choice) || src.incapacitated() || (required_item && !global.hands_topic_state.can_use_topic(required_item,src))) return null return choice -/mob/proc/set_sdisability(sdisability) - sdisabilities |= sdisability - -/mob/proc/unset_sdisability(sdisability) - sdisabilities &= ~sdisability - /mob/proc/get_accumulated_vision_handlers() var/result[2] var/asight = 0 @@ -713,3 +638,39 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT) result[2] = ainvis return result + +/mob/proc/get_admin_job_string() + return "Unknown ([type])" + +/mob/proc/get_visual_colour_substitutions() + . = list() + for(var/thing in client_colors) + var/datum/client_color/col = thing + for(var/col_name in col.wire_colour_substitutions) + .[col_name] = col.wire_colour_substitutions[col_name] + +/** + * Tries to find a readily accessible pen in the user's held items, and in some of its inventory slots. + * Shouldn't search recursively. + */ +/mob/proc/get_accessible_pen() + //We might save a few loop iterations by just looking in the active hand first + var/obj/item/I = get_active_held_item() + if(IS_PEN(I)) + return I + //Look if we're holding a pen elsewhere + for(I in get_held_items()) + if(IS_PEN(I)) + return I + //Try looking if we got a rig module with integrated pen + var/obj/item/rig/rig = get_rig() + if(rig && !rig.offline) + var/pen = locate(/obj/item/rig_module/device/pen) in rig.installed_modules + if(pen) + return pen + //Look for other slots + var/static/list/PEN_CHECK_SLOTS = list(slot_l_ear_str, slot_r_ear_str, slot_l_store_str, slot_r_store_str, slot_s_store_str) + for(var/slot in PEN_CHECK_SLOTS) + I = get_equipped_item(slot) + if(IS_PEN(I)) + return I diff --git a/code/modules/mob/mob_intent.dm b/code/modules/mob/mob_intent.dm new file mode 100644 index 000000000000..f9271fb64fec --- /dev/null +++ b/code/modules/mob/mob_intent.dm @@ -0,0 +1,195 @@ +// == Updated intent system == +// - Use mob.get_intent() to retrieve the entire decl structure. +// - Use mob.check_intent(I_FOO) for 1:1 intent type checking. +// - Use mob.check_intent(I_FLAG_FOO) for 'close enough for government work' flag checking. +// - Use mob.set_intent(I_FOO) to set intent to a type +// - Use mob.set_intent(I_FLAG_FOO) to set intent to whatever available type has the flag. +// - Use mob.cycle_intent(INTENT_HOTKEY_LEFT) or mob.cycle_intent(INTENT_HOTKEY_RIGHT) to step up or down the mob intent list. +// - Override mob.get_available_intents() if you want to change the intents from the default four. + +// TODO: +// - dynamic intent options based on equipped weapons, species, bodytype of active hand + +/proc/resolve_intent(intent) + RETURN_TYPE(/decl/intent) + // Legacy, should not proc. + if(istext(intent)) + intent = decls_repository.get_decl_by_id_or_var(intent, /decl/intent, "name") + // Saves constantly calling GET_DECL(I_FOO) + if(ispath(intent, /decl/intent)) + intent = GET_DECL(intent) + if(istype(intent, /decl/intent)) + return intent + return null + +/decl/intent + abstract_type = /decl/intent + decl_flags = DECL_FLAG_MANDATORY_UID + /// Replacing the old usage of I_HARM etc. in attackby() and such. Refer to /mob/proc/check_intent(). + var/intent_flags = 0 + /// Descriptive string used in status panel. + var/name + /// Descriptive string shown when examined. + var/desc + /// Icon used to draw this intent in the selector. + var/icon = 'icons/screen/intents.dmi' + /// State used to update intent selector. + var/icon_state + /// Whether or not this intent is available if you have an item in your hand. + var/requires_empty_hand = FALSE + /// Intents to be removed from the available list if this intent is present. + var/list/blocks_other_intents + +/decl/intent/validate() + . = ..() + if(!istext(name)) + . += "null or invalid name" + if(!istext(icon_state)) + . += "null or invalid icon_state" + if(!icon) + . += "null icon" + if(icon && istext(icon_state)) + if(!check_state_in_icon(icon_state, icon)) + . += "missing icon_state '[icon_state]' from icon '[icon]'" + if(!check_state_in_icon("[icon_state]_off", icon)) + . += "missing icon_state '[icon_state]_off' from icon '[icon]'" + +// Basic subtypes. +/decl/intent/harm + name = "harm" + desc = "HARM INTENT: you will attempt to damage, disrupt or destroy whatever you interact with." + uid = "intent_harm" + intent_flags = I_FLAG_HARM + icon_state = "intent_harm" + sort_order = 4 // Corresponding to hotkey order. + +/decl/intent/grab + name = "grab" + desc = "GRAB INTENT: you will attempt to grab hold of any object or creature you interact with." + uid = "intent_grab" + intent_flags = I_FLAG_GRAB + icon_state = "intent_grab" + sort_order = 3 // Corresponding to hotkey order. + +/decl/intent/help + name = "help" + desc = "HELP INTENT: you will attempt to assist, or in general void harming, whatever you interact with." + uid = "intent_help" + intent_flags = I_FLAG_HELP + icon_state = "intent_help" + sort_order = 1 // Corresponding to hotkey order. + +/decl/intent/disarm + name = "disarm" + desc = "DISARM INTENT: you will attempt to disarm or incapacitate any creature you interact with." + uid = "intent_disarm" + intent_flags = I_FLAG_DISARM + icon_state = "intent_disarm" + sort_order = 2 // Corresponding to hotkey order. + +/mob + /// Decl for current 'intent' of mob; hurt, harm, etc. Initialized by get_intent(). + VAR_PRIVATE/decl/intent/_a_intent + VAR_PRIVATE/list/_available_intents + +/mob/proc/check_intent(checking_intent) + var/decl/intent/intent = get_intent() // Ensures intent has been initalised. + . = (intent == checking_intent) + if(!.) + if(isnum(checking_intent)) + return (intent.intent_flags & checking_intent) + else if(istext(checking_intent) || ispath(checking_intent, /decl/intent)) + return (intent == resolve_intent(checking_intent)) + +/mob/proc/set_intent(decl/intent/new_intent) + + if(!isnum(new_intent)) + new_intent = resolve_intent(new_intent) + else // Retrieve intent decl based on flag. + for(var/decl/intent/intent as anything in get_available_intents(skip_update = TRUE)) + if(intent.intent_flags & new_intent) + new_intent = intent + break + + if(istype(new_intent) && get_intent() != new_intent) + _a_intent = new_intent + if(istype(hud_used)) + hud_used.refresh_element(HUD_INTENT) + return TRUE + + return FALSE + +/mob/proc/get_intent() + RETURN_TYPE(/decl/intent) + var/list/available_intents = get_available_intents() + if(length(available_intents) && (!_a_intent || !(_a_intent in available_intents))) + var/new_intent + if(_a_intent) + for(var/decl/intent/intent in available_intents) + if(_a_intent.intent_flags & intent.intent_flags) + new_intent = intent + break + _a_intent = new_intent || available_intents[1] + if(!_a_intent) + _a_intent = get_default_intent() + return _a_intent + +/mob/proc/get_default_intent() + return GET_DECL(/decl/intent/help) + +/mob/proc/get_default_intents() + var/static/list/default_intents + if(!default_intents) + default_intents = list( + GET_DECL(/decl/intent/help), + GET_DECL(/decl/intent/disarm), + GET_DECL(/decl/intent/grab), + GET_DECL(/decl/intent/harm) + ) + return default_intents + +/mob/proc/clear_available_intents(skip_update, skip_sleep) + set waitfor = FALSE + if(!skip_sleep) + sleep(0) + if(QDELETED(src)) + return + _available_intents = null + if(!skip_update) + refresh_hud_element(HUD_INTENT) + +/mob/proc/get_available_intents(skip_update, force) + var/obj/item/held = get_active_held_item() + if(!held) + _available_intents = get_default_intents() + else if(force || !_available_intents) + // Grab all relevant intents. + _available_intents = list() + for(var/decl/intent/intent as anything in get_default_intents()) + if(intent.requires_empty_hand) + continue + _available_intents += intent + // Add inhand intents. + var/list/held_intents = held.get_provided_intents(src) + if(length(held_intents)) + _available_intents |= held_intents + // Trim blocked intents. + for(var/decl/intent/intent as anything in _available_intents) + _available_intents -= intent.blocks_other_intents + // Sort by hotkey order. + _available_intents = sortTim(_available_intents, /proc/cmp_decl_sort_value_asc) + // Update our HUD immediately. + if(!skip_update) + refresh_hud_element(HUD_INTENT) + return _available_intents + +/mob/proc/cycle_intent(input) + set name = "a-intent" + set hidden = TRUE + switch(input) + if(INTENT_HOTKEY_RIGHT) + return set_intent(next_in_list(get_intent(), get_available_intents(skip_update = TRUE))) + if(INTENT_HOTKEY_LEFT) + return set_intent(previous_in_list(get_intent(), get_available_intents(skip_update = TRUE))) + else // Fallback, should just use set_intent() directly + return set_intent(input) diff --git a/code/modules/mob/mob_layering.dm b/code/modules/mob/mob_layering.dm new file mode 100644 index 000000000000..ad458692d2d3 --- /dev/null +++ b/code/modules/mob/mob_layering.dm @@ -0,0 +1,138 @@ +/mob/proc/get_base_layer() + if(current_posture?.prone) + return LYING_MOB_LAYER + return initial(layer) + +/mob/reset_layer() + var/last_layer = layer + var/new_layer = get_base_layer() + if(isturf(loc)) + var/turf/my_turf = loc + if(my_turf.pixel_z < 0 && !my_turf.get_supporting_platform()) + new_layer = my_turf.layer + 0.25 + else if(buckled && buckled.buckle_layer_above) + new_layer = buckled.layer + ((buckled.dir == SOUTH) ? -0.01 : 0.01) + else if(length(grabbed_by)) + var/draw_under = TRUE + var/adjust_layer = FALSE + for(var/obj/item/grab/grab as anything in grabbed_by) + if(!grab.current_grab.adjust_layer) + continue + if(get_dir(grab.assailant, src) & SOUTH) + draw_under = FALSE + if(grab.current_grab.adjust_plane) + adjust_layer = TRUE + if(adjust_layer) + new_layer += (draw_under ? -0.01 : 0.01) + + if(new_layer != last_layer) + layer = new_layer + UPDATE_OO_IF_PRESENT + +/mob/reset_plane() + var/last_plane = plane + ..() + var/new_plane = plane + if(isturf(loc)) + if(buckled && buckled.buckle_layer_above) + new_plane = buckled.plane + else if(length(grabbed_by)) + for(var/obj/item/grab/grab as anything in grabbed_by) + if(grab.current_grab.adjust_plane) + new_plane = max(new_plane, grab.assailant.plane) + if(last_plane != new_plane) + plane = new_plane + UPDATE_OO_IF_PRESENT + +/mob/living/get_base_layer() + if(jumping) + return VEHICLE_LOAD_LAYER + if (hiding) + return HIDING_MOB_LAYER + . = ..() + +/mob/living/human/get_base_layer() + if(current_posture.prone) + return LYING_HUMAN_LAYER + . = ..() + +/mob/living/simple_animal/get_base_layer() + if(buckled_mob) + return UNDER_MOB_LAYER + return ..() + +// If you ever want to change how a mob offsets by default, you MUST add the offset +// changes to this proc and call it from your new feature code. This prevents conflicting +// animations and offsets from getting weird and ovewriting each other. +/mob/reset_offsets(var/anim_time = 2) + + var/last_pixel_x = pixel_x + var/last_pixel_y = pixel_y + var/last_pixel_z = pixel_z + + var/new_pixel_x = default_pixel_x + var/new_pixel_y = default_pixel_y + var/new_pixel_z = default_pixel_z + + if(isturf(loc)) + // Update offsets from grabs. + if(length(grabbed_by)) + for(var/obj/item/grab/grab as anything in grabbed_by) + var/grab_dir = get_dir(grab.assailant, src) + if(grab_dir && grab.current_grab.shift > 0) + if(grab_dir & WEST) + new_pixel_x = min(new_pixel_x+grab.current_grab.shift, default_pixel_x+grab.current_grab.shift) + else if(grab_dir & EAST) + new_pixel_x = max(new_pixel_x-grab.current_grab.shift, default_pixel_x-grab.current_grab.shift) + if(grab_dir & NORTH) + new_pixel_y = max(new_pixel_y-grab.current_grab.shift, default_pixel_y-grab.current_grab.shift) + else if(grab_dir & SOUTH) + new_pixel_y = min(new_pixel_y+grab.current_grab.shift, default_pixel_y+grab.current_grab.shift) + + // Update offsets from structures in loc. + var/structure_offset = 0 + for(var/obj/structure/struct in loc) + structure_offset = max(structure_offset, struct.mob_offset) + new_pixel_z += structure_offset + + // Update offsets from loc. + var/turf/floor/ext = loc + if(istype(ext)) + var/obj/structure/platform = ext.get_supporting_platform() + if(platform) + new_pixel_z += platform.pixel_z + else if(ext.height < 0) + new_pixel_z += ext.pixel_z + + // Check for catwalks/supporting platforms. + + // Update offsets from our buckled atom. + if(buckled && buckled.buckle_pixel_shift) + var/list/pixel_shift = buckled.buckle_pixel_shift + if(istext(pixel_shift)) + pixel_shift = cached_json_decode(pixel_shift) + if(islist(pixel_shift)) + var/list/directional_offset = LAZYACCESS(pixel_shift, num2text(dir)) + // Unset diagonals should be substituted with the appropriate NSEW value. + if(!directional_offset) + if(dir & EAST) + directional_offset = LAZYACCESS(pixel_shift, num2text(EAST)) + else if(dir & WEST) + directional_offset = LAZYACCESS(pixel_shift, num2text(WEST)) + if(islist(directional_offset)) + pixel_shift = directional_offset + new_pixel_x += pixel_shift["x"] || 0 + new_pixel_y += pixel_shift["y"] || 0 + new_pixel_z += pixel_shift["z"] || 0 + if(pixel_shift == TRUE) // TRUE -> use object's offset + new_pixel_x = buckled.pixel_x + new_pixel_y = buckled.pixel_y + new_pixel_z = buckled.pixel_z + + if(last_pixel_x != new_pixel_x || last_pixel_y != new_pixel_y || last_pixel_z != new_pixel_z) + if(anim_time > 0) + animate(src, pixel_x = new_pixel_x, pixel_y = new_pixel_y, pixel_z = new_pixel_z, anim_time, 1, (LINEAR_EASING|EASE_IN)) + else + pixel_x = new_pixel_x + pixel_y = new_pixel_y + pixel_z = new_pixel_z diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 3657b54b6ca8..360f26b75557 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -1,12 +1,22 @@ /mob var/moving = FALSE -/mob/proc/SelfMove(var/direction) +/atom/movable/proc/SelfMove(var/direction) if(DoMove(direction, src) & MOVEMENT_HANDLED) - return TRUE // Doesn't necessarily mean the mob physically moved + return TRUE // Doesn't necessarily mean the atom physically moved + +/mob/living/SelfMove(var/direction) + // If on walk intent, don't willingly step into hazardous tiles. + // Unless the walker is confused. + var/turf/destination = get_step(src, direction) + if(istype(destination) && MOVING_DELIBERATELY(src) && !HAS_STATUS(src, STAT_CONFUSE)) + if(!destination.is_safe_to_enter(src)) + to_chat(src, SPAN_WARNING("\The [destination] is dangerous to move into.")) + return FALSE // In case any code wants to know if movement happened. + return ..() // Parent call should make the mob move. /mob/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - . = lying || ..() || (mover == buckled) + . = current_posture.prone || ..() || !mover.density /mob/proc/SetMoveCooldown(var/timeout) var/datum/movement_handler/mob/delay/delay = GetMovementHandler(/datum/movement_handler/mob/delay) @@ -39,91 +49,45 @@ attack_self() return if(SOUTHWEST) - if(iscarbon(usr)) - var/mob/living/carbon/C = usr - C.toggle_throw_mode() + if(isliving(mob)) + mob.toggle_throw_mode() else - to_chat(usr, "This mob type cannot throw items.") + to_chat(src, "This mob type cannot throw items.") return if(NORTHWEST) mob.hotkey_drop() /mob/proc/hotkey_drop() - . = has_extension(src, /datum/extension/hattable) + return FALSE /mob/living/hotkey_drop() - if(length(get_active_grabs()) || ..()) - drop_item() - -/mob/living/carbon/hotkey_drop() - var/obj/item/hand = get_active_hand() - if(hand?.can_be_dropped_by_client(src) || ..()) + if(length(get_active_grabs())) + . = TRUE + else + var/obj/item/hand = get_active_held_item() + . = hand?.can_be_dropped_by_client(src) + if(.) drop_item() /client/verb/swap_hand() set hidden = 1 - if(istype(mob, /mob/living/carbon)) - mob:swap_hand() - if(istype(mob,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = mob - R.cycle_modules() - return + if(ismob(mob)) + var/mob/M = mob + M.swap_hand() /client/verb/attack_self() set hidden = 1 if(mob) mob.mode() - return - -/client/verb/toggle_throw_mode() - set hidden = 1 - if(!istype(mob, /mob/living/carbon)) - return - if (!mob.stat && isturf(mob.loc) && !mob.restrained()) - mob:toggle_throw_mode() - else - return -/client/verb/drop_item() - set hidden = 1 - if(!isrobot(mob) && mob.stat == CONSCIOUS && isturf(mob.loc)) - var/obj/item/I = mob.get_active_hand() - if(I && I.can_be_dropped_by_client(mob)) - mob.drop_item() +/client/verb/toggle_throw_mode_verb() + set hidden = TRUE + if(!mob.stat && isturf(mob.loc) && !mob.restrained()) + mob.toggle_throw_mode() //This proc should never be overridden elsewhere at /atom/movable to keep directions sane. /atom/movable/Move(newloc, direct) - if (direct & (direct - 1)) - if (direct & 1) - if (direct & 4) - if (step(src, NORTH)) - step(src, EAST) - else - if (step(src, EAST)) - step(src, NORTH) - else - if (direct & 8) - if (step(src, NORTH)) - step(src, WEST) - else - if (step(src, WEST)) - step(src, NORTH) - else - if (direct & 2) - if (direct & 4) - if (step(src, SOUTH)) - step(src, EAST) - else - if (step(src, EAST)) - step(src, SOUTH) - else - if (direct & 8) - if (step(src, SOUTH)) - step(src, WEST) - else - if (step(src, WEST)) - step(src, SOUTH) - else + if (IS_POWER_OF_TWO(direct)) var/atom/A = src.loc var/olddir = dir //we can't override this without sacrificing the rest of movable/New() @@ -134,10 +98,22 @@ src.move_speed = world.time - src.l_move_time src.l_move_time = world.time - src.m_flag = 1 if ((A != src.loc && A && A.z == src.z)) src.last_move = get_dir(A, src.loc) - + else // This doesn't handle 3D moves properly, but the old code didn't either. + moving_diagonally = /atom/movable::FIRST_DIAGONAL_STEP + var/first_dir = FIRST_DIR(direct) + var/second_dir = direct & ~first_dir + if(step(src, first_dir)) + if(moving_diagonally) // check if unset by falling + moving_diagonally = /atom/movable::SECOND_DIAGONAL_STEP + step(src, second_dir) + else if(step(src, second_dir)) + if(moving_diagonally) + moving_diagonally = /atom/movable::SECOND_DIAGONAL_STEP + step(src, first_dir) + moving_diagonally = FALSE + if(!inertia_moving) inertia_next_move = world.time + inertia_move_delay space_drift(direct ? direct : last_move) @@ -145,103 +121,77 @@ /client/Move(n, direction) if(!user_acted(src)) return + if(!mob) return // Moved here to avoid nullrefs below + return mob.SelfMove(direction) -/mob/Process_Spacemove(var/allow_movement) - . = ..() - if(.) +/mob/is_space_movement_permitted(allow_movement = FALSE) + if((. = ..())) return - - var/atom/movable/backup = get_spacemove_backup() - if(backup) - if(istype(backup) && allow_movement) - return backup - return -1 - -/mob/proc/space_do_move(var/allow_move, var/direction) - if(ismovable(allow_move))//push off things in space - handle_space_pushoff(allow_move, direction) - allow_move = -1 - - if(allow_move == -1 && handle_spaceslipping()) - return 0 - - return 1 + var/atom/movable/footing = get_solid_footing() + if(footing) + if(istype(footing) && allow_movement) + return footing + return SPACE_MOVE_SUPPORTED + +/mob/living/is_space_movement_permitted(allow_movement = FALSE) + var/obj/item/tank/jetpack/thrust = get_jetpack() + if(thrust?.on && (allow_movement || thrust.stabilization_on) && thrust.allow_thrust(0.01, src)) + return SPACE_MOVE_PERMITTED + return ..() + +// space_move_result can be: +// - SPACE_MOVE_FORBIDDEN, +// - SPACE_MOVE_PERMITTED, +// - SPACE_MOVE_SUPPORTED (for non-movable atoms), +// - or an /atom/movable that provides footing. +/mob/proc/try_space_move(space_move_result, direction) + if(ismovable(space_move_result))//push off things in space + handle_space_pushoff(space_move_result, direction) + space_move_result = SPACE_MOVE_SUPPORTED + return space_move_result != SPACE_MOVE_SUPPORTED || !handle_spaceslipping() /mob/proc/handle_space_pushoff(var/atom/movable/AM, var/direction) if(AM.anchored) return - if(ismob(AM)) var/mob/M = AM - if(M.check_space_footing()) + if(!M.can_slip(magboots_only = TRUE)) return - AM.inertia_ignore = src if(step(AM, turn(direction, 180))) - to_chat(src, "You push off of [AM] to propel yourself.") + to_chat(src, SPAN_INFO("You push off of \the [AM] to propel yourself.")) inertia_ignore = AM -/mob/proc/get_spacemove_backup()//rename this - var/shoegrip = Check_Shoegrip() - - for(var/thing in RANGE_TURFS(src, 1))//checks for walls or grav turf first - var/turf/T = thing - if(T.density || T.is_wall() || (T.is_floor() && (shoegrip || T.has_gravity()))) - return T - - var/obj/item/grab/G = locate() in src - for(var/A in range(1, get_turf(src))) - if(istype(A,/atom/movable)) - var/atom/movable/AM = A - if(AM == src || AM == inertia_ignore || !AM.simulated || !AM.mouse_opacity || AM == buckled) //mouse_opacity is hacky as hell, need better solution - continue - if(ismob(AM)) - var/mob/M = AM - if(M.buckled) - continue - if(AM.density || !AM.CanPass(src)) - if(AM.anchored) - return AM - if(G && AM == G.affecting) - continue - . = AM - -/mob/proc/check_space_footing() //checks for gravity or maglockable turfs to prevent space related movement - if(has_gravity() || anchored || buckled) - return 1 - - if(Check_Shoegrip()) - for(var/thing in RANGE_TURFS(src, 1)) //checks for turfs that one can maglock to - var/turf/T = thing - if(T.density || T.is_wall() || T.is_floor()) - return 1 - - return 0 - -/mob/proc/Check_Shoegrip() - return 0 - //return 1 if slipped, 0 otherwise /mob/proc/handle_spaceslipping() - if(prob(skill_fail_chance(SKILL_EVA, slip_chance(10), SKILL_EXPERT))) - to_chat(src, "You slipped!") + if(prob(skill_fail_chance(SKILL_EVA, get_eva_slip_prob(), SKILL_EXPERT))) + to_chat(src, SPAN_DANGER("You slipped!")) step(src,turn(last_move, pick(45,-45))) - return 1 - return 0 - -/mob/proc/slip_chance(var/prob_slip = 10) - if(stat) - return 0 - if(buckled) - return 0 - if(Check_Shoegrip()) - return 0 - if(MOVING_DELIBERATELY(src)) - prob_slip *= 0.5 - return prob_slip + return TRUE + return FALSE + +/mob/proc/get_eva_slip_prob(var/prob_slip = 10) + // General slip check. + if((has_gravity() || has_magnetised_footing()) && get_solid_footing()) + . = 0 + else + //Check hands and mod slip + for(var/hand_slot in get_held_item_slots()) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + var/obj/item/held = inv_slot?.get_equipped_item() + if(!held) + prob_slip -= 2 + else if(held.w_class <= ITEM_SIZE_SMALL) + prob_slip -= 1 + // If we're walking carefully, lower the chance. + if(MOVING_DELIBERATELY(src)) + prob_slip *= 0.5 + . = prob_slip + // Avoid negative probs. + . = max(0, .) #define DO_MOVE(this_dir) var/final_dir = turn(this_dir, -dir2angle(dir)); Move(get_step(mob, final_dir), final_dir); @@ -271,40 +221,39 @@ var/checking_intent = (istype(move_intent) ? move_intent.type : move_intents[1]) for(var/i = 1 to length(move_intents)) // One full iteration of the move set. checking_intent = next_in_list(checking_intent, move_intents) - if(set_move_intent(decls_repository.get_decl(checking_intent))) + if(set_move_intent(GET_DECL(checking_intent))) return /mob/proc/set_move_intent(var/decl/move_intent/next_intent) if(next_intent && move_intent != next_intent && next_intent.can_be_used_by(src)) move_intent = next_intent - if(hud_used) - hud_used.move_intent.icon_state = move_intent.hud_icon_state + refresh_hud_element(HUD_MOVEMENT) return TRUE return FALSE /mob/proc/get_movement_datum_by_flag(var/move_flag = MOVE_INTENT_DELIBERATE) for(var/m_intent in move_intents) - var/decl/move_intent/check_move_intent = decls_repository.get_decl(m_intent) + var/decl/move_intent/check_move_intent = GET_DECL(m_intent) if(check_move_intent.flags & move_flag) return check_move_intent /mob/proc/get_movement_datum_by_missing_flag(var/move_flag = MOVE_INTENT_DELIBERATE) for(var/m_intent in move_intents) - var/decl/move_intent/check_move_intent = decls_repository.get_decl(m_intent) + var/decl/move_intent/check_move_intent = GET_DECL(m_intent) if(!(check_move_intent.flags & move_flag)) return check_move_intent /mob/proc/get_movement_datums_by_flag(var/move_flag = MOVE_INTENT_DELIBERATE) . = list() for(var/m_intent in move_intents) - var/decl/move_intent/check_move_intent = decls_repository.get_decl(m_intent) + var/decl/move_intent/check_move_intent = GET_DECL(m_intent) if(check_move_intent.flags & move_flag) . += check_move_intent /mob/proc/get_movement_datums_by_missing_flag(var/move_flag = MOVE_INTENT_DELIBERATE) . = list() for(var/m_intent in move_intents) - var/decl/move_intent/check_move_intent = decls_repository.get_decl(m_intent) + var/decl/move_intent/check_move_intent = GET_DECL(m_intent) if(!(check_move_intent.flags & move_flag)) . += check_move_intent @@ -315,7 +264,7 @@ var/choice = input(usr, "Select a default walk.", "Set Default Walk") as null|anything in get_movement_datums_by_missing_flag(MOVE_INTENT_QUICK) if(choice && (choice in get_movement_datums_by_missing_flag(MOVE_INTENT_QUICK))) default_walk_intent = choice - to_chat(src, "You will now default to [default_walk_intent] when moving deliberately.") + to_chat(src, SPAN_NOTICE("You will now default to [default_walk_intent] when moving deliberately.")) /mob/verb/SetDefaultRun() set name = "Set Default Run" @@ -324,7 +273,7 @@ var/choice = input(usr, "Select a default run.", "Set Default Run") as null|anything in get_movement_datums_by_flag(MOVE_INTENT_QUICK) if(choice && (choice in get_movement_datums_by_flag(MOVE_INTENT_QUICK))) default_run_intent = choice - to_chat(src, "You will now default to [default_run_intent] when moving quickly.") + to_chat(src, SPAN_NOTICE("You will now default to [default_run_intent] when moving quickly.")) /client/verb/setmovingslowly() set hidden = 1 @@ -349,7 +298,7 @@ set_move_intent(default_run_intent) /mob/proc/can_sprint() - return FALSE + return TRUE /mob/proc/adjust_stamina(var/amt) return diff --git a/code/modules/mob/mob_organs.dm b/code/modules/mob/mob_organs.dm new file mode 100644 index 000000000000..6aea72caa0ce --- /dev/null +++ b/code/modules/mob/mob_organs.dm @@ -0,0 +1,23 @@ +/mob/proc/has_organ(organ_tag) + return !!get_organ(organ_tag, /obj/item/organ) + +/mob/proc/get_organ(var/organ_tag, var/expected_type) + RETURN_TYPE(/obj/item/organ) + return + +/mob/proc/get_injured_organs() + return + +/mob/proc/get_external_organs() + return + +/mob/proc/get_internal_organs() + return + +/mob/proc/get_organs() + var/list/external_organs = get_external_organs() + if(external_organs) + LAZYADD(., external_organs) + var/list/internal_organs = get_internal_organs() + if(internal_organs) + LAZYADD(., internal_organs) diff --git a/code/modules/mob/mob_serde.dm b/code/modules/mob/mob_serde.dm new file mode 100644 index 000000000000..d6bb36e8c970 --- /dev/null +++ b/code/modules/mob/mob_serde.dm @@ -0,0 +1,8 @@ +// Prevent all mob serde for the time being. +// Equipment handling and the like needs a lot of work to implement. +/mob/ShouldSerialize(_age) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/mob/GetPossiblySerializableInstances() + return null diff --git a/code/modules/mob/mob_snapshot.dm b/code/modules/mob/mob_snapshot.dm new file mode 100644 index 000000000000..c876a47857c6 --- /dev/null +++ b/code/modules/mob/mob_snapshot.dm @@ -0,0 +1,120 @@ +// Stub type used to replicate old DNA system's role in mob/organ initialization. +// Effectively a snapshot of a mob's state at a moment in time. +/datum/mob_snapshot + var/real_name + var/eye_color + var/blood_type + var/unique_enzymes + var/skin_color + var/skin_tone + var/fingerprint + + var/decl/species/root_species + var/decl/bodytype/root_bodytype + + var/list/sprite_accessories + var/list/genetic_conditions + /// Please find a better way to do this. This is done to add tails if we have the tail accessory selected... + var/list/extra_limbs + +/datum/mob_snapshot/New(mob/living/donor, genetic_info_only = FALSE) + + if(!istype(donor)) + return + + real_name = donor.real_name || "unknown" + eye_color = donor.get_eye_colour() || COLOR_BLACK + blood_type = donor.get_blood_type() + unique_enzymes = donor.get_unique_enzymes() + skin_color = donor.get_skin_colour() + skin_tone = donor.get_skin_tone() + fingerprint = donor.get_full_print(ignore_blockers = TRUE) + + root_species = donor.get_species() || decls_repository.get_decl_by_id(global.using_map.default_species) + root_bodytype = donor.get_bodytype() || root_species.default_bodytype + + for(var/obj/item/organ/external/limb in donor?.get_external_organs()) + // Discard anything not relating to our core/original bodytype and species. + // Does this need to be reviewed for Outreach serde? + if(limb.bodytype == root_bodytype && limb.species == root_species && (!genetic_info_only || !BP_IS_PROSTHETIC(limb))) + var/list/limb_sprite_acc = limb.get_sprite_accessories(copy = TRUE) + if(length(limb_sprite_acc)) + LAZYSET(sprite_accessories, limb.organ_tag, limb_sprite_acc) + + genetic_conditions = donor?.get_genetic_conditions()?.Copy() + for(var/decl/genetic_condition/condition as anything in genetic_conditions) + if(!condition.is_heritable) + LAZYREMOVE(genetic_conditions, condition) + +/datum/mob_snapshot/PopulateClone(datum/mob_snapshot/clone) + clone = ..() + if(clone) + clone.real_name = real_name + clone.eye_color = eye_color + clone.blood_type = blood_type + clone.unique_enzymes = unique_enzymes + clone.skin_color = skin_color + clone.skin_tone = skin_tone + clone.fingerprint = fingerprint + clone.genetic_conditions = genetic_conditions?.Copy() + clone.root_species = root_species + clone.root_bodytype = root_bodytype + if(sprite_accessories) + clone.sprite_accessories = deepCopyList(sprite_accessories) + return clone + +// Replaces UpdateAppearance(). +/datum/mob_snapshot/proc/apply_appearance_to(mob/living/target, do_update = TRUE) + + if(istype(root_species) && root_species != target.get_species()) + if(istype(root_bodytype)) + target.set_species(root_species.uid, root_bodytype) + else + target.set_species(root_species.uid) + else if(istype(root_bodytype) && target.get_bodytype() != root_bodytype) + target.set_bodytype(root_bodytype) + + target.set_fingerprint(fingerprint) + target.set_unique_enzymes(unique_enzymes) + target.set_skin_colour(skin_color) + target.set_eye_colour(eye_color) + target.set_skin_tone(skin_tone) + + for(var/limb_data in extra_limbs) + + // Grab our limb type for checking. + var/limb_path = extra_limbs[limb_data]["path"] + + // For whatever reason, we already have a limb in this slot. + // Creating a new one without removing the old one would cause limb overwrite runtimes. + var/obj/item/organ/external/limb = target.get_organ(limb_data) + if(istype(limb)) + // TODO: some way to cleanly remove and restitch an organ up the limb chain. + if(length(limb.children)) + continue + // If it's already the appropriate type, we're probably safe to leave it. + if(limb.type == limb_path) + continue + // Snip off the limb so we can replace it without issues. + target.remove_organ(limb, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE) + + // Create and install the new limb. + target.add_organ(new limb_path(null, null, src), null, TRUE, FALSE, FALSE, TRUE) + + extra_limbs = null // can't reuse it! + + for(var/obj/item/organ/organ in target.get_organs()) + organ.copy_from_mob_snapshot(src) + + for(var/decl/genetic_condition/condition as anything in genetic_conditions) + target.add_genetic_condition(condition.type) + + if(do_update) + target.force_update_limbs() + target.update_hair(update_icons = FALSE) + target.update_eyes() + return TRUE + +/mob/proc/get_mob_snapshot(check_dna = FALSE) + RETURN_TYPE(/datum/mob_snapshot) + return (!check_dna || has_genetic_information()) ? new /datum/mob_snapshot(src, genetic_info_only = check_dna) : null diff --git a/code/modules/mob/mob_status.dm b/code/modules/mob/mob_status.dm new file mode 100644 index 000000000000..5e08a530c40b --- /dev/null +++ b/code/modules/mob/mob_status.dm @@ -0,0 +1,24 @@ +// Stubs; see living_status.dm +/mob/proc/handle_status_conditions() + SHOULD_CALL_PARENT(TRUE) + +/mob/proc/clear_status_conditions() + return + +/mob/proc/set_status_condition(var/condition, var/amount) + return + +/mob/proc/clear_mob_modifiers() + return FALSE + +/mob/proc/remove_mob_modifier(decl/mob_modifier/archetype, datum/source, skip_update = FALSE) + return FALSE + +/mob/proc/has_mob_modifier(decl/mob_modifier/archetype, datum/source) + return FALSE + +/mob/proc/add_mob_modifier(decl/mob_modifier/archetype, duration = MOB_MODIFIER_INDEFINITE, datum/source, skip_update = FALSE) + return FALSE + +/mob/proc/mob_modifiers_block_attack(...) + return FALSE // see living_defense.dm diff --git a/code/modules/mob/mob_temperature.dm b/code/modules/mob/mob_temperature.dm new file mode 100644 index 000000000000..7e9b690bdea1 --- /dev/null +++ b/code/modules/mob/mob_temperature.dm @@ -0,0 +1,3 @@ +// Stub this out for now; freezing/melting gear is something to consider in the future but is currently quite broken. +/mob/ProcessAtomTemperature() + return PROCESS_KILL diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm index 9687967ec5fb..fd6c30c5dd28 100644 --- a/code/modules/mob/mob_transformation_simple.dm +++ b/code/modules/mob/mob_transformation_simple.dm @@ -1,54 +1,83 @@ +// Used by rudimentary mob transform in Topic(). +var/global/list/href_to_mob_type = list( + "Observer" = /mob/observer/ghost, + "Crew" = list( + "Human" = /mob/living/human, + "Monkey" = /mob/living/human/monkey, + "Robot" = /mob/living/silicon/robot + ), + "Animals" = list( + "Cat" = /mob/living/simple_animal/passive/cat, + "Runtime" = /mob/living/simple_animal/passive/cat/fluff/runtime, + "Corgi" = /mob/living/simple_animal/corgi, + "Ian" = /mob/living/simple_animal/corgi/Ian, + "Crab" = /mob/living/simple_animal/crab, + "Coffee" = /mob/living/simple_animal/crab/Coffee, + "Parrot" = /mob/living/simple_animal/hostile/parrot, + "Poly" = /mob/living/simple_animal/hostile/parrot/Poly, + ) +) + +/mob/proc/try_rudimentary_transform(var/transform_key, var/delmob, var/subspecies) + + // Work out the actual type we want to instantiate. + var/create_mob_type = global.href_to_mob_type[transform_key] + if(!create_mob_type) // It's category, do a search. + for(var/mob_subcat in global.href_to_mob_type) + var/list/mob_subcat_entries = global.href_to_mob_type[mob_subcat] + if(!islist(mob_subcat_entries)) + continue + create_mob_type = mob_subcat_entries[transform_key] + if(create_mob_type) + break + if(!create_mob_type) + return FALSE + + // Check if we succeeded in creating the mob and transferring the key before we try to qdel the old mob. + var/mob/new_mob = change_mob_type(create_mob_type, location = (loc || usr?.loc), subspecies = subspecies) + if(istype(new_mob) && new_mob.ckey) + if(!ckey && delmob && !QDELETED(src)) + qdel(src) + return TRUE + + return FALSE //This proc is the most basic of the procs. All it does is make a new mob on the same tile and transfer over a few variables. //Returns the new mob -//Note that this proc does NOT do MMI related stuff! -/mob/proc/change_mob_type(var/new_type = null, var/turf/location = null, var/new_name = null as text, var/delete_old_mob = 0 as num, var/subspecies) - - if(istype(src,/mob/new_player)) - to_chat(usr, "Cannot convert players who have not entered yet.") - return +//Note that this proc does NOT do brain related stuff! +/mob/proc/change_mob_type(var/new_type, var/turf/location, var/new_name, var/subspecies) if(!new_type) new_type = input("Mob type path:", "Mob type") as text|null + if(QDELETED(src) || QDELETED(usr)) + return FALSE - if( !ispath(new_type) ) - to_chat(usr, "Invalid type path (new_type = [new_type]) in change_mob_type(). Contact a coder.") - return + if(!ispath(new_type, /mob)) + PRINT_STACK_TRACE("Invalid new_type supplied to change_mob_type.") + return FALSE - if( new_type == /mob/new_player ) - to_chat(usr, "cannot convert into a new_player mob type.") - return + if(!location) + location = loc + location = get_turf(location) + if(!isturf(location)) + PRINT_STACK_TRACE("Invalid location supplied to/inferred by change_mob_type.") + return FALSE - var/mob/M - if(isturf(location)) - M = new new_type( location ) - else - M = new new_type( src.loc ) - - if(!M || !ismob(M)) - to_chat(usr, "Type path is not a mob (new_type = [new_type]) in change_mob_type(). Contact a coder.") - qdel(M) - return - - if( istext(new_name) ) + var/mob/M = new new_type(location) + if(istext(new_name)) M.SetName(new_name) M.real_name = new_name else - M.SetName(src.name) - M.real_name = src.real_name - - if(src.dna) - M.dna = src.dna.Clone() + M.SetName(name) + M.real_name = real_name if(mind) mind.transfer_to(M) - else + if(!M.key) // ghost minds are inactive for reasons that escape me M.key = key - if(subspecies && istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - H.set_species(subspecies) + if(subspecies && ishuman(M)) + var/mob/living/human/H = M + H.change_species(subspecies) - if(delete_old_mob) - QDEL_IN(src, 1) return M diff --git a/code/modules/mob/new_player/lobby.dm b/code/modules/mob/new_player/lobby.dm new file mode 100644 index 000000000000..13c51b0b7f32 --- /dev/null +++ b/code/modules/mob/new_player/lobby.dm @@ -0,0 +1,27 @@ +/mob/new_player/proc/get_lobby_browser_html() + . = {" + + + + + + + + + + "} diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm index 04e4aefb8d5b..57c2e4070177 100644 --- a/code/modules/mob/new_player/login.dm +++ b/code/modules/mob/new_player/login.dm @@ -1,4 +1,7 @@ /mob/new_player/Login() + + ASSERT(loc == null) + update_Login_details() //handles setting lastKnownIP and computer_id for use by the ban systems as well as checking for multikeying if(join_motd) to_chat(src, "
    [join_motd]
    ") @@ -9,13 +12,10 @@ mind.active = 1 mind.current = src - loc = null - GLOB.using_map.show_titlescreen(client) + global.using_map.show_titlescreen(client) my_client = client set_sight(sight|SEE_TURFS) - GLOB.player_list |= src - - new_player_panel() + global.player_list |= src if(!SScharacter_setup.initialized) SScharacter_setup.newplayers_requiring_init += src @@ -26,20 +26,24 @@ // Do not make any calls in mob/Login which may require prefs having been loaded. // It is safe to assume that any UI or sound related calls will fall into that category. /mob/new_player/proc/deferred_login() - if(client) - handle_privacy_poll() - client.playtitlemusic() - maybe_send_staffwarns("connected as new player") - - if(get_preference_value(/datum/client_preference/chat_position) == GLOB.PREF_YES) - client.update_chat_position(TRUE) - - if(get_preference_value(/datum/client_preference/fullscreen_mode) != GLOB.PREF_OFF) - client.toggle_fullscreen(get_preference_value(/datum/client_preference/fullscreen_mode)) - - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - var/decl/security_level/SL = security_state.current_security_level - var/alert_desc = "" - if(SL.up_description) - alert_desc = SL.up_description - to_chat(src, "The alert level on the [station_name()] is currently: [SL.name]. [alert_desc]") \ No newline at end of file + if(!client) + return + + client.prefs?.apply_post_login_preferences() + client.playtitlemusic() + maybe_send_staffwarns("connected as new player") + + show_lobby_menu(TRUE) + + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if(security_state?.show_on_login) + var/decl/security_level/sec_level = security_state.current_security_level + // todo: allow maps to override this string for things like the fantasy map being on high alert? + // eg "The alert level *in* Karzerfeste Keep is currently high alert." or "Karzerfeste Keep is currently on high alert." + to_chat(src, SPAN_NOTICE("The alert level on the [station_name()] is currently: [sec_level.name]. [sec_level?.up_description]")) + + // bolds the changelog button on the interface so we know there are updates. + if(client.prefs?.lastchangelog != global.changelog_hash) + to_chat(client, SPAN_NOTICE("You have unread updates in the changelog.")) + if(get_config_value(/decl/config/toggle/aggressive_changelog)) + client.changes() diff --git a/code/modules/mob/new_player/logout.dm b/code/modules/mob/new_player/logout.dm index b04c9a6d54c2..5d3d96e263dc 100644 --- a/code/modules/mob/new_player/logout.dm +++ b/code/modules/mob/new_player/logout.dm @@ -3,7 +3,7 @@ // see login.dm if(my_client) - GLOB.using_map.hide_titlescreen(my_client) + global.using_map.hide_titlescreen(my_client) my_client = null ..() diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 39bbf780f291..0b7f6c091e9f 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -1,72 +1,60 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 - /mob/new_player - var/ready = 0 - var/spawning = 0//Referenced when you want to delete the new_player later on in the code. - var/totalPlayers = 0 //Player counts for the Lobby tab - var/totalPlayersReady = 0 - var/datum/browser/panel - var/show_invalid_jobs = 0 universal_speak = TRUE - - invisibility = 101 - - density = 0 + mob_sort_value = 10 + invisibility = INVISIBILITY_ABSTRACT + is_spawnable_type = FALSE + simulated = FALSE + density = FALSE stat = DEAD - movement_handlers = list() - anchored = 1 // don't get pushed around - + anchored = TRUE // don't get pushed around virtual_mob = null // Hear no evil, speak no evil + is_spawnable_type = FALSE + skillset = /datum/skillset // moved here from /mob to avoid giving dview a skillset + var/ready = 0 + /// Referenced when you want to delete the new_player later on in the code. + var/spawning = 0 + /// Player counts for the Lobby tab + var/totalPlayers = 0 + var/totalPlayersReady = 0 + var/show_invalid_jobs = 0 + var/decl/music_track/current_lobby_track + var/datum/browser/panel + +INITIALIZE_IMMEDIATE(/mob/new_player) /mob/new_player/Initialize() . = ..() + forceMove(null) verbs += /mob/proc/toggle_antag_pool -/mob/new_player/proc/new_player_panel(force = FALSE) +/mob/new_player/Destroy() + QDEL_NULL(panel) + . = ..() + +/mob/new_player/proc/show_lobby_menu(force = FALSE) if(!SScharacter_setup.initialized && !force) return // Not ready yet. - var/output = list() - output += "
    " - output += "[GLOB.using_map.get_map_info()]" - output +="
    " - output += "Setup Character " - - if(GAME_STATE > RUNLEVEL_LOBBY) - output += "View the Crew Manifest " - - output += "Observe " - - if(!IsGuestKey(src.key)) - establish_db_connection() - if(dbcon.IsConnected()) - var/isadmin = 0 - if(src.client && src.client.holder) - isadmin = 1 - var/DBQuery/query = dbcon.NewQuery("SELECT `id` FROM `erro_poll_question` WHERE [(isadmin ? "" : "`adminonly` = FALSE AND")] NOW() BETWEEN `starttime` AND `endtime` AND `id` NOT IN (SELECT `pollid` FROM `erro_poll_vote` WHERE `ckey` = \"[ckey]\") AND `id` NOT IN (SELECT `pollid` FROM `erro_poll_textreply` WHERE `ckey` = \"[ckey]\")") - query.Execute() - var/newpoll = 0 - while(query.NextRow()) - newpoll = 1 - break - - if(newpoll) - output += "Show Player Polls (NEW!) " - else - output += "Show Player Polls " - - output += "
    Current character: [client.prefs.real_name][client.prefs.job_high ? ", [client.prefs.job_high]" : null]
    " - if(GAME_STATE <= RUNLEVEL_LOBBY) - if(ready) - output += "Un-Ready" - else - output += "Ready Up" - else - output += "Join Game!" + var/output = list("
    ") + + var/decl/lobby_handler/lobby_handler = GET_DECL(global.using_map.lobby_handler) + var/lobby_header = lobby_handler.get_lobby_header(src) + if(lobby_header) + output += lobby_header + for(var/datum/lobby_option/option in lobby_handler.lobby_options) + if(!option.visible(src)) + continue + var/option_string = option.get_lobby_menu_string(src) + if(option_string) + output += option_string + var/lobby_footer = lobby_handler.get_lobby_footer(src) + if(lobby_footer) + output += lobby_footer output += "
    " - panel = new(src, "Welcome","Welcome to [GLOB.using_map.full_name]", 560, 280, src) + if(!panel) + panel = new(src, "Welcome","Welcome to [global.using_map.full_name]", lobby_handler.browser_width, lobby_handler.browser_height, src) panel.set_window_options("can_close=0") panel.set_content(JOINTEXT(output)) panel.open() @@ -79,7 +67,11 @@ stat("Game Mode:", "[SSticker.mode ? SSticker.mode.name : SSticker.master_mode] ([SSticker.master_mode])") else stat("Game Mode:", PUBLIC_GAME_MODE) - var/extra_antags = list2params(additional_antag_types) + var/list/additional_antag_ids = list() + for(var/antag_type in global.additional_antag_types) + var/decl/special_role/antag = GET_DECL(antag_type) + additional_antag_ids |= lowertext(antag.name) + var/extra_antags = list2params(additional_antag_ids) stat("Added Antagonists:", extra_antags ? extra_antags : "None") if(GAME_STATE <= RUNLEVEL_LOBBY) @@ -87,7 +79,7 @@ stat("Players: [totalPlayers]", "Players Ready: [totalPlayersReady]") totalPlayers = 0 totalPlayersReady = 0 - for(var/mob/new_player/player in GLOB.player_list) + for(var/mob/new_player/player in global.player_list) var/highjob if(player.client && player.client.prefs && player.client.prefs.job_high) highjob = " as [player.client.prefs.job_high]" @@ -96,75 +88,75 @@ if(player.ready)totalPlayersReady++ /mob/new_player/Topic(href, href_list) // This is a full override; does not call parent. - if(usr != src) - return TOPIC_NOACTION - if(!client) + if(usr != src || !client) return TOPIC_NOACTION - if(href_list["show_preferences"]) - client.prefs.ShowChoices(src) + if(href_list["lobby_changelog"]) + client.changes() + return + + if(href_list["lobby_setup"]) + client.prefs.open_setup_window(src) return 1 - if(href_list["ready"]) - if(GAME_STATE <= RUNLEVEL_LOBBY) // Make sure we don't ready up after the round has started - ready = text2num(href_list["ready"]) - else - ready = 0 + if(href_list["lobby_ready"]) + if(GAME_STATE <= RUNLEVEL_LOBBY) + ready = !ready + show_lobby_menu() if(href_list["refresh"]) - panel.close() - new_player_panel() + show_lobby_menu() - if(href_list["observe"]) + if(href_list["lobby_observe"]) if(GAME_STATE < RUNLEVEL_LOBBY) - to_chat(src, "Please wait for server initialization to complete...") + to_chat(src, SPAN_WARNING("Please wait for server initialization to complete...")) return - if(!config.respawn_delay || client.holder || alert(src,"Are you sure you wish to observe? You will have to wait [config.respawn_delay] minute\s before being able to respawn!","Player Setup","Yes","No") == "Yes") + var/respawn_delay = get_config_value(/decl/config/num/respawn_delay) + if(!respawn_delay || client.holder || alert(src,"Are you sure you wish to observe? You will have to wait [respawn_delay] minute\s before being able to respawn!","Player Setup","Yes","No") == "Yes") if(!client) return 1 var/mob/observer/ghost/observer = new() spawning = 1 - sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = GLOB.lobby_sound_channel))// MAD JAMS cant last forever yo - + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = sound_channels.lobby_channel))// MAD JAMS cant last forever yo observer.started_as_observer = 1 close_spawn_windows() - var/obj/O = locate("landmark*Observer-Start") - if(istype(O)) - to_chat(src, "Now teleporting.") - observer.forceMove(O.loc) + var/decl/spawnpoint/spawnpoint = GET_DECL(/decl/spawnpoint/observer) + var/turf/T = SAFEPICK(spawnpoint.get_spawn_turfs(src)) + if(istype(T)) + to_chat(src, SPAN_NOTICE("Now teleporting.")) + observer.forceMove(T) else - to_chat(src, "Could not locate an observer spawn point. Use the Teleport verb to jump to the map.") + to_chat(src, SPAN_DANGER("Could not locate an observer spawn point. Use the Teleport verb to jump to the map.")) observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly. if(isnull(client.holder)) announce_ghost_joinleave(src) - var/mob/living/carbon/human/dummy/mannequin = new() - client.prefs.dress_preview_mob(mannequin) - observer.set_appearance(mannequin) - qdel(mannequin) + var/mob/living/human/dummy/mannequin = get_mannequin(client.ckey) + if(mannequin) + client.prefs.dress_preview_mob(mannequin) + observer.set_appearance(mannequin) if(client.prefs.be_random_name) - client.prefs.real_name = random_name(client.prefs.gender) + client.prefs.real_name = client.prefs.get_random_name() observer.real_name = client.prefs.real_name observer.SetName(observer.real_name) - if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. + if(!client.holder && !get_config_value(/decl/config/toggle/antag_hud_allowed)) // For new ghosts we remove the verb from even showing up if it's not allowed. observer.verbs -= /mob/observer/ghost/verb/toggle_antagHUD // Poor guys, don't know what they are missing! observer.key = key qdel(src) return 1 - if(href_list["late_join"]) - + if(href_list["lobby_join"]) if(GAME_STATE != RUNLEVEL_GAME) - to_chat(usr, "The round is either not ready, or has already finished...") + to_chat(usr, SPAN_DANGER("The round is either not ready, or has already finished...")) return LateChoices() //show the latejoin job selection menu - if(href_list["manifest"]) + if(href_list["lobby_crew"]) ViewManifest() if(href_list["SelectedJob"]) @@ -173,124 +165,35 @@ if(!SSjobs.check_general_join_blockers(src, job)) return FALSE - var/datum/species/S = get_species_by_key(client.prefs.species) + var/decl/species/S = client.prefs.get_species_decl() if(!check_species_allowed(S)) return 0 AttemptLateSpawn(job, client.prefs.spawnpoint) return - if(href_list["privacy_poll"]) - establish_db_connection() - if(!dbcon.IsConnected()) - return - var/voted = 0 - - //First check if the person has not voted yet. - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM `erro_privacy` WHERE `ckey` = '[src.ckey]'") - query.Execute() - while(query.NextRow()) - voted = 1 - break - - //This is a safety switch, so only valid options pass through - var/option = "UNKNOWN" - switch(href_list["privacy_poll"]) - if("signed") - option = "SIGNED" - if("anonymous") - option = "ANONYMOUS" - if("nostats") - option = "NOSTATS" - if("later") - close_browser(usr, "window=privacypoll") - return - if("abstain") - option = "ABSTAIN" - - if(option == "UNKNOWN") - return - - if(!voted) - var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO `erro_privacy` VALUES (NULL, NOW(), '[src.ckey]', '[option]')") - query_insert.Execute() - to_chat(usr, "Thank you for your vote!") - close_browser(usr, "window=privacypoll") - if(!ready && href_list["preference"]) if(client) client.prefs.process_link(src, href_list) - else if(!href_list["late_join"]) - new_player_panel() - - if(href_list["showpoll"]) - - handle_player_polling() - return - - if(href_list["pollid"]) - - var/pollid = href_list["pollid"] - if(istext(pollid)) - pollid = text2num(pollid) - if(isnum(pollid)) - src.poll_player(pollid) - return if(href_list["invalid_jobs"]) show_invalid_jobs = !show_invalid_jobs LateChoices() - if(href_list["votepollid"] && href_list["votetype"]) - var/pollid = text2num(href_list["votepollid"]) - var/votetype = href_list["votetype"] - switch(votetype) - if("OPTION") - var/optionid = text2num(href_list["voteoptionid"]) - vote_on_poll(pollid, optionid) - if("TEXT") - var/replytext = href_list["replytext"] - log_text_poll_reply(pollid, replytext) - if("NUMVAL") - var/id_min = text2num(href_list["minid"]) - var/id_max = text2num(href_list["maxid"]) - - if( (id_max - id_min) > 100 ) //Basic exploit prevention - to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") - return - - for(var/optionid = id_min; optionid <= id_max; optionid++) - if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to - var/rating - if(href_list["o[optionid]"] == "abstain") - rating = null - else - rating = text2num(href_list["o[optionid]"]) - if(!isnum(rating)) - return - - vote_on_numval_poll(pollid, optionid, rating) - if("MULTICHOICE") - var/id_min = text2num(href_list["minoptionid"]) - var/id_max = text2num(href_list["maxoptionid"]) - - if( (id_max - id_min) > 100 ) //Basic exploit prevention - to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") - return - - for(var/optionid = id_min; optionid <= id_max; optionid++) - if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected - vote_on_poll(pollid, optionid, 1) - /mob/new_player/proc/AttemptLateSpawn(var/datum/job/job, var/spawning_at) - if(src != usr) return 0 + if(GAME_STATE != RUNLEVEL_GAME) - to_chat(usr, "The round is either not ready, or has already finished...") + to_chat(usr, SPAN_WARNING("The round is either not ready, or has already finished.")) return 0 - if(!config.enter_allowed) - to_chat(usr, "There is an administrative lock on entering the game!") + + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(usr)) + alert("Non-whitelisted players are not permitted to join rounds except as observers.") + return 0 + + if(!get_config_value(/decl/config/toggle/on/enter_allowed)) + to_chat(usr, SPAN_WARNING("There is an administrative lock on entering the game!")) return 0 if(!job || !job.is_available(client)) @@ -299,13 +202,19 @@ if(job.is_restricted(client.prefs, src)) return - var/datum/spawnpoint/spawnpoint = job.get_spawnpoint(client) - var/turf/spawn_turf = pick(spawnpoint.turfs) + var/decl/spawnpoint/spawnpoint = job.get_spawnpoint(client) + if(!spawnpoint) + to_chat(src, alert("That spawnpoint is unavailable. Please try another.")) + return 0 + + var/turf/spawn_turf if(job.latejoin_at_spawnpoints) var/obj/S = job.get_roundstart_spawnpoint() spawn_turf = get_turf(S) + else + spawn_turf = SAFEPICK(spawnpoint.get_spawn_turfs(src)) - if(!SSjobs.check_unsafe_spawn(src, spawn_turf)) + if(!spawn_turf || !job.no_warn_unsafe && !SSjobs.check_unsafe_spawn(src, spawn_turf)) return // Just in case someone stole our position while we were waiting for input from alert() proc @@ -319,51 +228,36 @@ if(!character) return 0 - character = SSjobs.equip_rank(character, job.title, 1) //equips the human + character = SSjobs.equip_job_title(character, job.title, 1) //equips the human SScustomitems.equip_custom_items(character) - // AIs don't need a spawnpoint, they must spawn at an empty core - if(character.mind.assigned_role == "AI") - - character = character.AIize(move=0) // AIize the character, but don't move them yet - - // is_available for AI checks that there is an empty core available in this list - var/obj/structure/aicore/deactivated/C = empty_playable_ai_cores[1] - empty_playable_ai_cores -= C - - character.forceMove(C.loc) - var/mob/living/silicon/ai/A = character - A.on_mob_init() - - AnnounceCyborg(character, job.title, "has been downloaded to the empty core in \the [character.loc.loc]") - SSticker.mode.handle_latejoin(character) - - qdel(C) + if(job.do_spawn_special(character, src, TRUE)) //This replaces the AI spawn logic with a proc stub. Refer to silicon.dm for the spawn logic. qdel(src) return SSticker.mode.handle_latejoin(character) - GLOB.universe.OnPlayerLatejoin(character) + global.universe.OnPlayerLatejoin(character) spawnpoint.after_join(character) if(job.create_record) - if(character.mind.assigned_role != "Robot") + if(!(ASSIGNMENT_ROBOT in job.event_categories)) CreateModularRecord(character) SSticker.minds += character.mind//Cyborgs and AIs handle this in the transform proc. //TODO!!!!! ~Carn - AnnounceArrival(character, job, spawnpoint.msg) - else - AnnounceCyborg(character, job, spawnpoint.msg) - matchmaker.do_matchmaking() + if(spawnpoint.spawn_announcement) + AnnounceArrival(character, job, spawnpoint.spawn_announcement) + else if(spawnpoint.spawn_announcement) + AnnounceCyborg(character, job, spawnpoint.spawn_announcement) + + RAISE_EVENT(/decl/observ/player_latejoin, character, job) log_and_message_admins("has joined the round as [character.mind.assigned_role].", character) qdel(src) - /mob/new_player/proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message) if (GAME_STATE == RUNLEVEL_GAME) if(character.mind.role_alt_title) rank = character.mind.role_alt_title // can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc. - GLOB.global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived"].", "Arrivals Announcement Computer") + do_telecomms_announcement(character, "A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived"].", "Arrivals Announcement Computer") /mob/new_player/proc/LateChoices() var/name = client.prefs.be_random_name ? "friend" : client.prefs.real_name @@ -372,42 +266,66 @@ header += "Welcome, [name].
    " header += "Round Duration: [roundduration2text()]
    " - if(SSevac.evacuation_controller.has_evacuated()) - header += "The [station_name()] has been evacuated.
    " - else if(SSevac.evacuation_controller.is_evacuating()) - if(SSevac.evacuation_controller.emergency_evacuation) // Emergency shuttle is past the point of no recall - header += "The [station_name()] is currently undergoing evacuation procedures.
    " - else // Crew transfer initiated - header += "The [station_name()] is currently undergoing crew transfer procedures.
    " + if(SSevac.evacuation_controller) + if(SSevac.evacuation_controller.has_evacuated()) + header += "The [station_name()] has been evacuated.
    " + else if(SSevac.evacuation_controller.is_evacuating()) + if(SSevac.evacuation_controller.emergency_evacuation) // Emergency shuttle is past the point of no recall + header += "The [station_name()] is currently undergoing evacuation procedures.
    " + else // Crew transfer initiated + header += "The [station_name()] is currently undergoing crew transfer procedures.
    " var/list/dat = list() dat += "Choose from the following open/valid positions:
    " dat += "[show_invalid_jobs ? "Hide":"Show"] unavailable jobs
    " dat += "" - dat += "" - - // MAIN MAP JOBS - var/list/job_summaries + var/list/job_summaries = list() var/list/hidden_reasons = list() - for(var/datum/job/job in SSjobs.primary_job_datums) - var/summary = job.get_join_link(client, "byond://?src=\ref[src];SelectedJob=[job.title]", show_invalid_jobs) - if(summary && summary != "") - LAZYADD(job_summaries, summary) - else - for(var/raisin in job.get_unavailable_reasons(client)) - hidden_reasons[raisin] = TRUE - - if(LAZYLEN(job_summaries)) - dat += job_summaries - else - dat += "" + if(length(SSjobs.primary_job_datums)) + dat += "" + + // MAIN MAP JOBS + for(var/datum/job/job in SSjobs.primary_job_datums) + + var/summary = job.get_join_link(client, "byond://?src=\ref[src];SelectedJob=[job.title]", show_invalid_jobs) + if(summary) + + var/decl/department/dept = job.primary_department && SSjobs.get_department_by_type(job.primary_department) + var/summary_key = (dept || "No Department") + var/list/existing_summaries = job_summaries[summary_key] + if(!existing_summaries) + existing_summaries = list() + job_summaries[summary_key] = existing_summaries + if(job.head_position) + existing_summaries.Insert(1, summary) + else + existing_summaries.Add(summary) + else + for(var/raisin in job.get_unavailable_reasons(client)) + hidden_reasons[raisin] = TRUE + + var/added_job = FALSE + if(length(job_summaries)) + job_summaries = sortTim(job_summaries, /proc/cmp_departments_dsc, FALSE) + for(var/job_category in job_summaries) + if(length(job_summaries[job_category])) + var/decl/department/job_dept = job_category + // TODO: use bgcolor='[job_dept.display_color]' when less pastel/bright colours are chosen. + dat += "" + dat += job_summaries[job_category] + added_job = TRUE + + if(!added_job) + dat += "" // END MAIN MAP JOBS // SUBMAP JOBS - for(var/thing in SSmapping.submaps) - var/datum/submap/submap = thing - if(submap && submap.available()) - dat += "" + var/list/ordered_submaps = null + if(length(SSmapping.submaps)) + ordered_submaps = sortTim(SSmapping.submaps.Copy(), /proc/cmp_submap_asc) + for(var/datum/submap/submap as anything in ordered_submaps) + if(submap?.available()) + dat += "" job_summaries = list() for(var/otherthing in submap.jobs) var/datum/job/job = submap.jobs[otherthing] @@ -421,7 +339,7 @@ if(LAZYLEN(job_summaries)) dat += job_summaries else - dat += "No available positions." + dat += "" // END SUBMAP JOBS dat += "
    [GLOB.using_map.station_name]:
    No available positions.
    [global.using_map.station_name]:
    [istype(job_dept) ? job_dept.name : job_dept]
    No available positions.
    [submap.name] ([submap.archetype.descriptor]):
    [submap.name] ([submap.archetype.name]):
    No available positions.
    " @@ -440,67 +358,46 @@ spawning = 1 close_spawn_windows() - var/mob/living/carbon/human/new_character + var/mob/living/human/new_character - var/datum/species/chosen_species + var/decl/species/chosen_species if(client.prefs.species) - chosen_species = get_species_by_key(client.prefs.species) + chosen_species = client.prefs.get_species_decl() if(!spawn_turf) var/datum/job/job = SSjobs.get_by_title(mind.assigned_role) if(!job) - job = SSjobs.get_by_title(GLOB.using_map.default_assistant_title) - var/datum/spawnpoint/spawnpoint = job.get_spawnpoint(client, client.prefs.ranks[job.title]) - spawn_turf = pick(spawnpoint.turfs) + job = SSjobs.get_by_title(global.using_map.default_job_title) + var/decl/spawnpoint/spawnpoint = job.get_spawnpoint(client, client.prefs.ranks[job.title]) + spawn_turf = DEFAULTPICK(spawnpoint.get_spawn_turfs(src), get_random_spawn_turf(SPAWN_FLAG_JOBS_CAN_SPAWN)) if(chosen_species) if(!check_species_allowed(chosen_species)) spawning = 0 //abort return null - new_character = new(spawn_turf, chosen_species.name) - if(chosen_species.has_organ[BP_POSIBRAIN] && client && client.prefs.is_shackled) - var/obj/item/organ/internal/posibrain/B = new_character.internal_organs_by_name[BP_POSIBRAIN] - if(B) B.shackle(client.prefs.get_lawset()) - - if(!new_character) - new_character = new(spawn_turf) - + if(global.random_players) // apply randomness prior to creating the character + var/decl/species/current_species = client.prefs.get_species_decl() + var/decl/pronouns/pronouns = pick(current_species.available_pronouns) + client.prefs.gender = pronouns.name + client.prefs.real_name = client.prefs.get_random_name() + client.prefs.randomize_appearance_and_body_for(new_character) + new_character = client.prefs.create_character_from_snapshot(spawn_turf) new_character.lastarea = get_area(spawn_turf) - if(GLOB.random_players) - client.prefs.gender = pick(MALE, FEMALE) - client.prefs.real_name = random_name(new_character.gender) - client.prefs.randomize_appearance_and_body_for(new_character) - client.prefs.copy_to(new_character) + // client.prefs.copy_to(new_character) // not anymore lol - sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = GLOB.lobby_sound_channel))// MAD JAMS cant last forever yo + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = sound_channels.lobby_channel))// MAD JAMS cant last forever yo if(mind) mind.active = 0 //we wish to transfer the key manually - mind.original = new_character - if(client.prefs.memory) - mind.StoreMemory(client.prefs.memory) - if(client.prefs.relations.len) - for(var/T in client.prefs.relations) - var/TT = matchmaker.relation_types[T] - var/datum/relation/R = new TT - R.holder = mind - R.info = client.prefs.relations_info[T] - mind.gen_relations_info = client.prefs.relations_info["general"] + var/memory = client.prefs.records[PREF_MEM_RECORD] + if(memory) + mind.StoreMemory(memory) mind.transfer_to(new_character) //won't transfer key since the mind is not active - new_character.dna.ready_dna(new_character) - new_character.dna.b_type = client.prefs.b_type - new_character.sync_organ_dna() - if(client.prefs.disabilities) - // Set defer to 1 if you add more crap here so it only recalculates struc_enzymes once. - N3X - new_character.dna.SetSEState(GLOB.GLASSESBLOCK,1,0) - new_character.disabilities |= NEARSIGHTED - // Do the initial caching of the player's body icons. new_character.force_update_limbs() - new_character.update_eyes() - new_character.regenerate_icons() + new_character.try_refresh_visible_overlays() new_character.key = key //Manually transfer the key to log them in return new_character @@ -510,6 +407,7 @@ dat += html_crew_manifest(OOC = 1) //show_browser(src, dat, "window=manifest;size=370x420;can_close=1") var/datum/browser/popup = new(src, "Crew Manifest", "Crew Manifest", 370, 420, src) + popup.add_stylesheet("nano_shared", 'nano/css/shared.css') popup.set_content(dat) popup.open() @@ -518,49 +416,44 @@ /mob/new_player/proc/close_spawn_windows() close_browser(src, "window=latechoices") //closes late choices window + close_browser(src, "window=preferences_window") //closes preferences window + if(client?.prefs) + client.prefs.close_load_dialog(src) panel.close() -/mob/new_player/proc/check_species_allowed(datum/species/S, var/show_alert=1) +/mob/new_player/proc/check_species_allowed(var/decl/species/S, var/show_alert=1) if(!S.is_available_for_join() && !has_admin_rights()) if(show_alert) - to_chat(src, alert("Your current species, [client.prefs.species], is not available for play.")) + to_chat(src, alert("Your current species, [S.name], is not available for play.")) return 0 if(!is_alien_whitelisted(src, S)) if(show_alert) - to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species].")) + to_chat(src, alert("You are currently not whitelisted to play [S.name_plural].")) return 0 return 1 -/mob/new_player/get_species() - var/datum/species/chosen_species +/mob/new_player/get_species_name() + SHOULD_CALL_PARENT(FALSE) + var/decl/species/chosen_species if(client.prefs.species) - chosen_species = get_species_by_key(client.prefs.species) - + chosen_species = client.prefs.get_species_decl() if(!chosen_species || !check_species_allowed(chosen_species, 0)) - return GLOB.using_map.default_species - + return global.using_map.default_species return chosen_species.name -/mob/new_player/get_gender() - if(!client || !client.prefs) ..() - return client.prefs.gender - -/mob/new_player/is_ready() - return ready && ..() - -/mob/new_player/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) +/mob/new_player/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/italics = 0, var/mob/speaker = null) return -/mob/new_player/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) +/mob/new_player/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/vsource) return /mob/new_player/show_message(msg, type, alt, alt_type) return -mob/new_player/MayRespawn() +/mob/new_player/MayRespawn() return 1 -/mob/new_player/touch_map_edge() +/mob/new_player/touch_map_edge(var/overmap_id = OVERMAP_ID_SPACE) return /mob/new_player/say(var/message) @@ -570,14 +463,22 @@ mob/new_player/MayRespawn() set name = "Play Different Lobby Track" set category = "OOC" - if(get_preference_value(/datum/client_preference/play_lobby_music) == GLOB.PREF_NO) + if(get_preference_value(/datum/client_preference/play_lobby_music) == PREF_NO) return - var/music_track/new_track = GLOB.using_map.get_lobby_track(GLOB.using_map.lobby_track.type) + var/decl/music_track/new_track = global.using_map.get_lobby_track(current_lobby_track || global.using_map.lobby_track.type) if(new_track) + current_lobby_track = new_track new_track.play_to(src) -/mob/new_player/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays) +/mob/new_player/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays, var/digital = FALSE) . = text_content /mob/new_player/handle_writing_literacy(var/mob/user, var/text_content, var/skip_delays) . = text_content + +/mob/new_player/get_admin_job_string() + return "New player" + +/mob/new_player/change_mob_type(var/new_type, var/turf/location, var/new_name, var/delete_old_mob = FALSE, var/subspecies) + to_chat(usr, SPAN_WARNING("You cannot convert players who have not entered the game yet!")) + return FALSE diff --git a/code/modules/mob/new_player/poll.dm b/code/modules/mob/new_player/poll.dm deleted file mode 100644 index 3bf957360eba..000000000000 --- a/code/modules/mob/new_player/poll.dm +++ /dev/null @@ -1,526 +0,0 @@ - -/mob/new_player/proc/handle_privacy_poll() - establish_db_connection() - if(!dbcon.IsConnected()) - return - var/voted = 0 - - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM `erro_privacy` WHERE `ckey` = '[src.ckey]'") - query.Execute() - while(query.NextRow()) - voted = 1 - break - - if(!voted) - privacy_poll() - -/mob/new_player/proc/privacy_poll() - var/output = "
    Player poll" - output +="
    " - output += "We would like to expand our stats gathering." - output += "
    This however involves gathering data about player behavior, play styles, unique player numbers, play times, etc. Data like that cannot be gathered fully anonymously, which is why we're asking you how you'd feel if player-specific data was gathered. Prior to any of this actually happening, a privacy policy will be discussed, but before that can begin, we'd preliminarily like to know how you feel about the concept." - output +="
    " - output += "How do you feel about the game gathering player-specific statistics? This includes statistics about individual players as well as in-game polling/opinion requests." - - output += "

    Signed stats gathering" - output += "
    Pick this option if you think usernames should be logged with stats. This allows us to have personalized stats as well as polls." - - output += "

    Anonymous stats gathering" - output += "
    Pick this option if you think only hashed (indecipherable) usernames should be logged with stats. This doesn't allow us to have personalized stats, as we can't tell who is who (hashed values aren't readable), we can however have ingame polls." - - output += "

    No stats gathering" - output += "
    Pick this option if you don't want player-specific stats gathered. This does not allow us to have player-specific stats or polls." - - output += "

    Ask again later" - output += "
    This poll will be brought up again next round." - - output += "

    Don't ask again" - output += "
    Only pick this if you are fine with whatever option wins." - - output += "

    " - - show_browser(src, output, "window=privacypoll;size=600x500") - return - -/datum/polloption - var/optionid - var/optiontext - -/mob/new_player/proc/handle_player_polling() - establish_db_connection() - if(dbcon.IsConnected()) - var/isadmin = 0 - if(src.client && src.client.holder) - isadmin = 1 - - var/DBQuery/select_query = dbcon.NewQuery("SELECT `id`, `question` FROM `erro_poll_question` WHERE [(isadmin ? "" : "`adminonly` = FALSE AND")] NOW() BETWEEN `starttime` AND `endtime`") - select_query.Execute() - - var/output = "
    Player polls" - output +="
    " - - var/pollid - var/pollquestion - - output += "" - var/color1 = "#ececec" - var/color2 = "#e2e2e2" - var/i = 0 - - while(select_query.NextRow()) - pollid = select_query.item[1] - pollquestion = select_query.item[2] - output += "" - i++ - - output += "
    [pollquestion]
    " - - show_browser(src, output, "window=playerpolllist;size=500x300") - - - -/mob/new_player/proc/poll_player(var/pollid = -1) - if(pollid == -1) return - establish_db_connection() - if(dbcon.IsConnected()) - - var/DBQuery/select_query = dbcon.NewQuery("SELECT `starttime`, `endtime`, `question`, `polltype`, `multiplechoiceoptions` FROM `erro_poll_question` WHERE `id` = [pollid]") - select_query.Execute() - - var/pollstarttime = "" - var/pollendtime = "" - var/pollquestion = "" - var/polltype = "" - var/found = 0 - var/multiplechoiceoptions = 0 - - while(select_query.NextRow()) - pollstarttime = select_query.item[1] - pollendtime = select_query.item[2] - pollquestion = select_query.item[3] - polltype = select_query.item[4] - found = 1 - break - - if(!found) - to_chat(usr, "Poll question details not found.") - return - - switch(polltype) - //Polls that have enumerated options - if("OPTION") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `optionid` FROM `erro_poll_vote` WHERE `pollid` = [pollid] AND `ckey` = '[usr.ckey]'") - voted_query.Execute() - - var/voted = 0 - var/votedoptionid = 0 - while(voted_query.NextRow()) - votedoptionid = text2num(voted_query.item[1]) - voted = 1 - break - - var/list/datum/polloption/options = list() - - var/DBQuery/options_query = dbcon.NewQuery("SELECT `id`, `text` FROM `erro_poll_option` WHERE `pollid` = [pollid]") - options_query.Execute() - while(options_query.NextRow()) - var/datum/polloption/PO = new() - PO.optionid = text2num(options_query.item[1]) - PO.optiontext = options_query.item[2] - options += PO - - var/output = "
    Player poll" - output +="
    " - output += "Question: [pollquestion]
    " - output += "Poll runs from [pollstarttime] until [pollendtime]

    " - - if(!voted) //Only make this a form if we have not voted yet - output += "

    " - output += "" - output += "" - output += "" - - output += "
    " - for(var/datum/polloption/O in options) - if(O.optionid && O.optiontext) - if(voted) - if(votedoptionid == O.optionid) - output += "[O.optiontext]
    " - else - output += "[O.optiontext]
    " - else - output += " [O.optiontext]
    " - output += "
    " - - if(!voted) //Only make this a form if we have not voted yet - output += "

    " - output += "

    " - - output += "
    " - - show_browser(src, output, "window=playerpoll;size=500x250") - - //Polls with a text input - if("TEXT") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `replytext` FROM `erro_poll_textreply` WHERE `pollid` = [pollid] AND `ckey` = '[usr.ckey]'") - voted_query.Execute() - - var/voted = 0 - var/vote_text = "" - while(voted_query.NextRow()) - vote_text = voted_query.item[1] - voted = 1 - break - - - var/output = "
    Player poll" - output +="
    " - output += "Question: [pollquestion]
    " - output += "Feedback gathering runs from [pollstarttime] until [pollendtime]

    " - - if(!voted) //Only make this a form if we have not voted yet - output += "

    " - output += "" - output += "" - output += "" - - output += "Please provide feedback below. You can use any letters of the English alphabet, numbers and the symbols: . , ! ? : ; -
    " - output += "" - - output += "

    " - output += "

    " - - output += "
    " - output += "" - output += "" - output += "" - output += "" - output += "" - output += "
    " - else - output += "[vote_text]" - - show_browser(src, output, "window=playerpoll;size=500x500") - - //Polls with a text input - if("NUMVAL") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `text`, `rating` FROM `erro_poll_option` INNER JOIN `erro_poll_vote` USING (`pollid`) WHERE `ckey` = '[usr.ckey]' AND `erro_poll_option`.`id` = `optionid`") - voted_query.Execute() - - var/output = "
    Player poll" - output +="
    " - output += "Question: [pollquestion]
    " - output += "Poll runs from [pollstarttime] until [pollendtime]

    " - - var/voted = 0 - while(voted_query.NextRow()) - voted = 1 - - var/optiontext = voted_query.item[1] - var/rating = voted_query.item[2] - - output += "
    [optiontext] - [rating]" - - if(!voted) //Only make this a form if we have not voted yet - output += "

    " - output += "" - output += "" - output += "" - - var/minid = 999999 - var/maxid = 0 - - var/DBQuery/option_query = dbcon.NewQuery("SELECT `id`, `text`, `minval`, `maxval`, `descmin`, `descmid`, `descmax` FROM `erro_poll_option` WHERE `pollid` = [pollid]") - option_query.Execute() - while(option_query.NextRow()) - var/optionid = text2num(option_query.item[1]) - var/optiontext = option_query.item[2] - var/minvalue = text2num(option_query.item[3]) - var/maxvalue = text2num(option_query.item[4]) - var/descmin = option_query.item[5] - var/descmid = option_query.item[6] - var/descmax = option_query.item[7] - - if(optionid < minid) - minid = optionid - if(optionid > maxid) - maxid = optionid - - var/midvalue = round( (maxvalue + minvalue) / 2) - - if(isnull(minvalue) || isnull(maxvalue) || (minvalue == maxvalue)) - continue - - output += "
    [optiontext]: " - - output += "" - output += "" - - output += "

    " - output += "

    " - - show_browser(src, output, "window=playerpoll;size=500x500") - if("MULTICHOICE") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `optionid` FROM `erro_poll_vote` WHERE `pollid` = [pollid] AND `ckey` = '[usr.ckey]'") - voted_query.Execute() - - var/list/votedfor = list() - var/voted = 0 - while(voted_query.NextRow()) - votedfor.Add(text2num(voted_query.item[1])) - voted = 1 - - var/list/datum/polloption/options = list() - var/maxoptionid = 0 - var/minoptionid = 0 - - var/DBQuery/options_query = dbcon.NewQuery("SELECT `id`, `text` FROM `erro_poll_option` WHERE `pollid` = [pollid]") - options_query.Execute() - while(options_query.NextRow()) - var/datum/polloption/PO = new() - PO.optionid = text2num(options_query.item[1]) - PO.optiontext = options_query.item[2] - if(PO.optionid > maxoptionid) - maxoptionid = PO.optionid - if(PO.optionid < minoptionid || !minoptionid) - minoptionid = PO.optionid - options += PO - - - if(select_query.item[5]) - multiplechoiceoptions = text2num(select_query.item[5]) - - var/output = "
    Player poll" - output +="
    " - output += "Question: [pollquestion]
    You can select up to [multiplechoiceoptions] options. If you select more, the first [multiplechoiceoptions] will be saved.
    " - output += "Poll runs from [pollstarttime] until [pollendtime]

    " - - if(!voted) //Only make this a form if we have not voted yet - output += "

    " - output += "" - output += "" - output += "" - output += "" - output += "" - - output += "
    " - for(var/datum/polloption/O in options) - if(O.optionid && O.optiontext) - if(voted) - if(O.optionid in votedfor) - output += "[O.optiontext]
    " - else - output += "[O.optiontext]
    " - else - output += " [O.optiontext]
    " - output += "
    " - - if(!voted) //Only make this a form if we have not voted yet - output += "

    " - output += "

    " - - output += "
    " - - show_browser(src, output, "window=playerpoll;size=500x250") - return - -/mob/new_player/proc/vote_on_poll(var/pollid = -1, var/optionid = -1, var/multichoice = 0) - if(pollid == -1 || optionid == -1) - return - - if(!isnum(pollid) || !isnum(optionid)) - return - establish_db_connection() - if(dbcon.IsConnected()) - - var/DBQuery/select_query = dbcon.NewQuery("SELECT `starttime`, `endtime`, `question`, `polltype`, `multiplechoiceoptions` FROM `erro_poll_question` WHERE `id` = [pollid] AND NOW() BETWEEN `starttime` AND `endtime`") - select_query.Execute() - - var/validpoll = 0 - var/multiplechoiceoptions = 0 - - while(select_query.NextRow()) - if(select_query.item[4] != "OPTION" && select_query.item[4] != "MULTICHOICE") - return - validpoll = 1 - if(select_query.item[5]) - multiplechoiceoptions = text2num(select_query.item[5]) - break - - if(!validpoll) - to_chat(usr, "Poll is not valid.") - return - - var/DBQuery/select_query2 = dbcon.NewQuery("SELECT `id` FROM `erro_poll_option` WHERE `id` = [optionid] AND `pollid` = [pollid]") - select_query2.Execute() - - var/validoption = 0 - - while(select_query2.NextRow()) - validoption = 1 - break - - if(!validoption) - to_chat(usr, "Poll option is not valid.") - return - - var/alreadyvoted = 0 - - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `id` FROM `erro_poll_vote` WHERE `pollid` = [pollid] AND `ckey` = '[usr.ckey]'") - voted_query.Execute() - - while(voted_query.NextRow()) - alreadyvoted += 1 - if(!multichoice) - break - - if(!multichoice && alreadyvoted) - to_chat(usr, "You already voted in this poll.") - return - - if(multichoice && (alreadyvoted >= multiplechoiceoptions)) - to_chat(usr, "You already have more than [multiplechoiceoptions] logged votes on this poll. Enough is enough. Contact the database admin if this is an error.") - return - - var/adminrank = "Player" - if(usr && usr.client && usr.client.holder) - adminrank = usr.client.holder.rank - - - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_poll_vote` (`id`, `datetime`, `pollid`, `optionid`, `ckey`, `ip`, `adminrank`) VALUES (NULL, NOW(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')") - insert_query.Execute() - - to_chat(usr, "Vote successful.") - close_browser(usr, "window=playerpoll") - - -/mob/new_player/proc/log_text_poll_reply(var/pollid = -1, var/replytext = "") - if(pollid == -1 || replytext == "") - return - - if(!isnum(pollid) || !istext(replytext)) - return - establish_db_connection() - if(dbcon.IsConnected()) - - var/DBQuery/select_query = dbcon.NewQuery("SELECT `starttime`, `endtime`, `question`, `polltype` FROM `erro_poll_question` WHERE `id` = [pollid] AND NOW() BETWEEN `starttime` AND `endtime`") - select_query.Execute() - - var/validpoll = 0 - - while(select_query.NextRow()) - if(select_query.item[4] != "TEXT") - return - validpoll = 1 - break - - if(!validpoll) - to_chat(usr, "Poll is not valid.") - return - - var/alreadyvoted = 0 - - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `id` FROM `erro_poll_textreply` WHERE `pollid` = [pollid] AND `ckey` = '[usr.ckey]'") - voted_query.Execute() - - while(voted_query.NextRow()) - alreadyvoted = 1 - break - - if(alreadyvoted) - to_chat(usr, "You already sent your feedback for this poll.") - return - - var/adminrank = "Player" - if(usr && usr.client && usr.client.holder) - adminrank = usr.client.holder.rank - - - replytext = replacetext(replytext, "%BR%", "") - replytext = replacetext(replytext, "\n", "%BR%") - var/text_pass = reject_bad_text(replytext,8000) - replytext = replacetext(replytext, "%BR%", "
    ") - - if(!text_pass) - to_chat(usr, "The text you entered was blank, contained illegal characters or was too long. Please correct the text and submit again.") - return - - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_poll_textreply` (`id`, `datetime`, `pollid`, `ckey`, `ip`, `replytext`, `adminrank`) VALUES (NULL, NOW(), [pollid], '[usr.ckey]', '[usr.client.address]', '[replytext]', '[adminrank]')") - insert_query.Execute() - - to_chat(usr, "Feedback logging successful.") - close_browser(usr, "window=playerpoll") - - -/mob/new_player/proc/vote_on_numval_poll(var/pollid = -1, var/optionid = -1, var/rating = null) - if(pollid == -1 || optionid == -1) - return - - if(!isnum(pollid) || !isnum(optionid)) - return - establish_db_connection() - if(dbcon.IsConnected()) - - var/DBQuery/select_query = dbcon.NewQuery("SELECT `starttime`, `endtime`, `question`, `polltype` FROM `erro_poll_question` WHERE `id` = [pollid] AND NOW() BETWEEN `starttime` AND `endtime`") - select_query.Execute() - - var/validpoll = 0 - - while(select_query.NextRow()) - if(select_query.item[4] != "NUMVAL") - return - validpoll = 1 - break - - if(!validpoll) - to_chat(usr, "Poll is not valid.") - return - - var/DBQuery/select_query2 = dbcon.NewQuery("SELECT `id` FROM `erro_poll_option` WHERE `id` = [optionid] AND `pollid` = [pollid]") - select_query2.Execute() - - var/validoption = 0 - - while(select_query2.NextRow()) - validoption = 1 - break - - if(!validoption) - to_chat(usr, "Poll option is not valid.") - return - - var/alreadyvoted = 0 - - var/DBQuery/voted_query = dbcon.NewQuery("SELECT `id` FROM `erro_poll_vote` WHERE `optionid` = [optionid] AND `ckey` = '[usr.ckey]'") - voted_query.Execute() - - while(voted_query.NextRow()) - alreadyvoted = 1 - break - - if(alreadyvoted) - to_chat(usr, "You already voted in this poll.") - return - - var/adminrank = "Player" - if(usr && usr.client && usr.client.holder) - adminrank = usr.client.holder.rank - - - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_poll_vote` (`id`, `datetime`, `pollid`, `optionid`, `ckey`, `ip`, `adminrank`, `rating`) VALUES (NULL, NOW(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "NULL" : rating])") - insert_query.Execute() - - to_chat(usr, "Vote successful.") - close_browser(usr, "window=playerpoll") \ No newline at end of file diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index e27bcdebefef..5a8b7f89ecbe 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -1,44 +1,72 @@ -/datum/preferences - //The mob should have a gender you want before running this proc. Will run fine without H - proc/randomize_appearance_and_body_for(var/mob/living/carbon/human/H) - var/datum/species/current_species = get_species_by_key(species || GLOB.using_map.default_species) - gender = pick(current_species.genders) - - h_style = random_hair_style(gender, species) - f_style = random_facial_hair_style(gender, species) - if(current_species) - if(current_species.appearance_flags & HAS_A_SKIN_TONE) - skin_tone = current_species.get_random_skin_tone() || skin_tone - if(current_species.appearance_flags & HAS_EYE_COLOR) - eye_colour = current_species.get_random_eye_color() - if(current_species.appearance_flags & HAS_SKIN_COLOR) - skin_colour = current_species.get_random_skin_color() - if(current_species.appearance_flags & HAS_HAIR_COLOR) - hair_colour = current_species.get_random_hair_color() - facial_hair_colour = prob(75) ? hair_colour : current_species.get_random_facial_hair_color() - - if(current_species.appearance_flags & HAS_UNDERWEAR) - if(all_underwear) - all_underwear.Cut() - for(var/datum/category_group/underwear/WRC in GLOB.underwear.categories) - var/datum/category_item/underwear/WRI = pick(WRC.items) - all_underwear[WRC.name] = WRI.name - - backpack = decls_repository.get_decl(pick(subtypesof(/decl/backpack_outfit))) - age = rand(current_species.min_age, current_species.max_age) - b_type = RANDOM_BLOOD_TYPE - if(H) - copy_to(H) - -/datum/preferences/proc/dress_preview_mob(var/mob/living/carbon/human/mannequin) +/datum/preferences/proc/randomize_appearance_and_body_for(var/mob/living/human/H) + + if(!H) + H = client?.mob + + var/decl/species/current_species = get_species_decl() + var/decl/bodytype/current_bodytype = current_species.get_bodytype_by_name(bodytype) || current_species.default_bodytype + var/decl/pronouns/pronouns = pick(current_species.available_pronouns) + gender = pronouns.name + + for(var/acc_cat in sprite_accessories) + + var/decl/sprite_accessory_category/accessory_category_decl = GET_DECL(acc_cat) + if(accessory_category_decl.single_selection) + var/list/available_styles = get_usable_sprite_accessories(H, current_species, current_bodytype, acc_cat, null) + if(length(available_styles)) + var/decl/sprite_accessory/accessory = pick(available_styles) + sprite_accessories[acc_cat] = list(accessory.type = accessory.get_random_metadata()) + continue + + for(var/accessory_type in sprite_accessories[acc_cat]) + var/decl/sprite_accessory/accessory = GET_DECL(accessory_type) + sprite_accessories[acc_cat][accessory_type] = accessory.get_random_metadata() + + if(bodytype) + if(current_bodytype.appearance_flags & HAS_A_SKIN_TONE) + skin_tone = current_bodytype.get_random_skin_tone() || skin_tone + if(current_bodytype.appearance_flags & HAS_EYE_COLOR) + eye_colour = current_bodytype.get_random_eye_color() + if(current_bodytype.appearance_flags & HAS_SKIN_COLOR) + skin_colour = current_bodytype.get_random_skin_color() + + if(!islist(all_underwear)) + all_underwear = list() + else if(length(all_underwear)) + all_underwear.Cut() + + if(current_bodytype.appearance_flags & HAS_UNDERWEAR) + for(var/datum/category_group/underwear/WRC in global.underwear.categories) + var/datum/category_item/underwear/WRI = pick(WRC.items) + all_underwear[WRC.name] = WRI.name + + for(var/entry in current_bodytype.appearance_descriptors) + var/datum/appearance_descriptor/descriptor = current_bodytype.appearance_descriptors[entry] + if(istype(descriptor)) + appearance_descriptors[descriptor.name] = descriptor.randomize_value() + + var/list/all_backpacks = global.using_map.get_available_backpacks() + backpack = all_backpacks[pick(all_backpacks)] + blood_type = pickweight(current_species.blood_types) + if(H) + copy_to(H) + +/datum/preferences/proc/dress_preview_mob(var/mob/living/human/dummy/mannequin) + + if(!mannequin) + return + var/update_icon = FALSE copy_to(mannequin, TRUE) + // Apply any species-specific preview modification. + mannequin = mannequin.species?.modify_preview_appearance(mannequin) + var/datum/job/previewJob if(equip_preview_mob) // Determine what job is marked as 'High' priority, and dress them up as such. - if(GLOB.using_map.default_assistant_title in job_low) - previewJob = SSjobs.get_by_title(GLOB.using_map.default_assistant_title) + if(global.using_map.default_job_title in job_low) + previewJob = SSjobs.get_by_title(global.using_map.default_job_title) else previewJob = SSjobs.get_by_title(job_high) else @@ -46,61 +74,56 @@ if((equip_preview_mob & EQUIP_PREVIEW_JOB) && previewJob) mannequin.job = previewJob.title - var/datum/mil_branch/branch = mil_branches.get_branch(branches[previewJob.title]) - var/datum/mil_rank/rank = mil_branches.get_rank(branches[previewJob.title], ranks[previewJob.title]) + var/datum/mil_branch/branch = global.using_map.get_branch(branches[previewJob.title]) + var/datum/mil_rank/rank = global.using_map.get_rank(branches[previewJob.title], ranks[previewJob.title]) previewJob.equip_preview(mannequin, player_alt_titles[previewJob.title], branch, rank) update_icon = TRUE - if(!(mannequin.species.appearance_flags && mannequin.species.appearance_flags & HAS_UNDERWEAR)) - if(all_underwear) - all_underwear.Cut() + if(!(mannequin.get_bodytype()?.appearance_flags & HAS_UNDERWEAR) && length(all_underwear)) + all_underwear.Cut() - if((equip_preview_mob & EQUIP_PREVIEW_LOADOUT) && !(previewJob && (equip_preview_mob & EQUIP_PREVIEW_JOB) && (previewJob.type == /datum/job/ai || previewJob.type == /datum/job/cyborg))) + if((equip_preview_mob & EQUIP_PREVIEW_LOADOUT) && !(previewJob && (equip_preview_mob & EQUIP_PREVIEW_JOB) && previewJob.skip_loadout_preview)) // Equip custom gear loadout, replacing any job items - var/list/loadout_taken_slots = list() for(var/thing in Gear()) - var/datum/gear/G = gear_datums[thing] - if(G) - var/permitted = 0 - if(G.allowed_roles && G.allowed_roles.len) + var/decl/loadout_option/gear = decls_repository.get_decl_by_id_or_var(thing, /decl/loadout_option) + if(gear) + var/permitted = FALSE + if(LAZYLEN(gear.allowed_roles)) if(previewJob) - for(var/job_type in G.allowed_roles) + for(var/job_type in gear.allowed_roles) if(previewJob.type == job_type) - permitted = 1 + permitted = TRUE else - permitted = 1 + permitted = TRUE - if(G.whitelisted && !(mannequin.species.name in G.whitelisted)) - permitted = 0 + if(gear.whitelisted && !(mannequin.species.uid in gear.whitelisted)) + permitted = FALSE if(!permitted) continue - if(G.slot && G.slot != slot_tie && !(G.slot in loadout_taken_slots) && G.spawn_on_mob(mannequin, gear_list[gear_slot][G.display_name])) - loadout_taken_slots.Add(G.slot) + if(gear.slot && gear.spawn_on_mob(mannequin, gear_list[gear_slot][gear.uid])) update_icon = TRUE if(update_icon) - mannequin.update_icons() + mannequin.update_icon() + mannequin.compile_overlays() /datum/preferences/proc/update_preview_icon() - var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) - mannequin.delete_inventory(TRUE) - dress_preview_mob(mannequin) - - preview_icon = icon('icons/effects/128x48.dmi', bgstate) - preview_icon.Scale(48+32, 16+32) - - mannequin.set_dir(NORTH) - var/icon/stamp = getFlatIcon(mannequin, NORTH, always_use_defdir = 1) - preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17) - - mannequin.set_dir(WEST) - stamp = getFlatIcon(mannequin, WEST, always_use_defdir = 1) - preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9) - - mannequin.set_dir(SOUTH) - stamp = getFlatIcon(mannequin, SOUTH, always_use_defdir = 1) - preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1) - - preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. + var/mob/living/human/dummy/mannequin/mannequin = get_mannequin(client?.ckey) + if(mannequin) + mannequin.delete_inventory(TRUE) + dress_preview_mob(mannequin) + update_character_previews(mannequin) + +/datum/preferences/proc/get_random_name() + var/decl/background_detail/background = get_background_datum_by_flag(BACKGROUND_FLAG_NAMING) + if(istype(background)) + return background.get_random_cultural_name(client?.mob, gender, species) + return random_name(gender, species) + +/datum/preferences/proc/get_background_datum_by_flag(background_flag) + for(var/cat_type in background_info) + var/decl/background_category/background_cat = GET_DECL(cat_type) + if(istype(background_cat) && (background_cat.background_flags & background_flag)) + return GET_DECL(background_info[cat_type]) diff --git a/code/modules/mob/observer/eye/blueprints_eye.dm b/code/modules/mob/observer/eye/blueprints_eye.dm index 0a3a5cff6358..c7bae7b5f9c7 100644 --- a/code/modules/mob/observer/eye/blueprints_eye.dm +++ b/code/modules/mob/observer/eye/blueprints_eye.dm @@ -1,19 +1,19 @@ #define MAX_AREA_SIZE 300 /mob/observer/eye/blueprints - + var/list/selected_turfs // Associative list of turfs -> boolean validity that the player has selected for new area creation. var/list/selection_images var/turf/last_selected_turf var/image/last_selected_image - + // On what Z-levels this can be used to modify or create areas. var/list/valid_z_levels // Displayed to the user to allow them to see what area they're hovering over. var/obj/effect/overlay/area_name_effect var/area_prefix - + // Displayed to the user on failed area creation. var/list/errors @@ -33,6 +33,7 @@ area_name_effect.screen_loc = "LEFT+1,BOTTOM+2" last_selected_image = image('icons/effects/blueprints.dmi', "selected") + last_selected_image.layer = OBSERVER_LAYER last_selected_image.plane = OBSERVER_PLANE last_selected_image.appearance_flags = NO_CLIENT_COLOR | RESET_COLOR @@ -49,12 +50,12 @@ if(owner && owner.client && user == owner) owner.client.images.Cut() . = ..() - + /mob/observer/eye/blueprints/proc/create_area() - var/area_name = sanitizeSafe(input("New area name:","Area Creation", ""), MAX_NAME_LEN) - if(!area_name || !length(area_name)) + var/area_name = sanitize_safe(input("New area name:","Area Creation", ""), MAX_NAME_LEN) + if(!length(area_name)) return - if(length(area_name) > 50) + if(length(area_name) > MAX_NAME_LEN) to_chat(owner, SPAN_WARNING("That name is too long!")) return @@ -64,14 +65,18 @@ var/area/A = new A.SetName(area_name) - A.power_equip = 0 - A.power_light = 0 - A.power_environ = 0 - A.always_unpowered = 0 for(var/turf/T in selected_turfs) ChangeArea(T, A) + finalize_area(A) remove_selection() // Reset the selection for clarity. +/mob/observer/eye/blueprints/proc/finalize_area(area/A) + A.power_equip = FALSE + A.power_light = FALSE + A.power_environ = FALSE + A.always_unpowered = FALSE + return A + /mob/observer/eye/blueprints/proc/remove_area() var/area/A = get_area(src) if(!check_modification_validity()) @@ -79,21 +84,28 @@ if(A.apc) to_chat(owner, SPAN_WARNING("You must remove the APC from this area before you can remove it from the blueprints!")) return - to_chat(owner, SPAN_NOTICE("You scrub [A.name] off the blueprints.")) - log_and_message_admins("deleted area [A.name] via station blueprints.") - qdel(A) + to_chat(owner, SPAN_NOTICE("You scrub [A.proper_name] off the blueprints.")) + log_and_message_admins("deleted area [A.proper_name] via station blueprints.") + var/turf/our_turf = get_turf(src) + var/datum/level_data/our_level_data = SSmapping.levels_by_z[our_turf.z] + var/area/base_area = our_level_data.get_base_area_instance() + for(var/turf/T in A.contents) + ChangeArea(T, base_area) + if(!(locate(/turf) in A)) + qdel(A) // uh oh, is this safe? /mob/observer/eye/blueprints/proc/edit_area() var/area/A = get_area(src) if(!check_modification_validity()) return - var/prevname = A.name - var/new_area_name = sanitizeSafe(input("Edit area name:","Area Editing", prevname), MAX_NAME_LEN) + var/prevname = replacetext(A.name, "\improper ", "the ") + var/new_area_name = sanitize_safe(input("Edit area name:","Area Editing", prevname), MAX_NAME_LEN) if(!new_area_name || !LAZYLEN(new_area_name) || new_area_name==prevname) return - if(length(new_area_name) > 50) + if(length(new_area_name) > MAX_NAME_LEN) to_chat(owner, SPAN_WARNING("Text too long.")) return + new_area_name = replacetext(new_area_name, regex(@"^the "), "\improper ") A.SetName(new_area_name) to_chat(owner, SPAN_NOTICE("You set the area '[prevname]' title to '[new_area_name]'.")) @@ -118,7 +130,7 @@ if(last_selected_turf.z != next_selected_turf.z) // No multi-Z areas. Contiguity checks this as well, but this is cheaper. return - + var/list/new_selection = block(last_selected_turf, next_selected_turf) if(params["shift"]) // Shift click to remove areas from the selection. @@ -132,7 +144,7 @@ update_images() last_selected_turf = null -// Completes all the necessary checks for creating new areas, starting at the turf level before checking contiguity. +// Completes all the necessary checks for creating new areas, starting at the turf level before checking contiguity. /mob/observer/eye/blueprints/proc/check_selection_validity() . = TRUE LAZYCLEARLIST(errors) @@ -149,7 +161,7 @@ var/turf_valid = check_turf_validity(T) . = min(., turf_valid) LAZYSET(selected_turfs, T, turf_valid) - + if(!.) return // Skip checking contiguity if there's other errors with individual turfs. . = check_contiguity() @@ -167,38 +179,39 @@ if(!(A.area_flags & AREA_FLAG_IS_BACKGROUND)) // Cannot create new areas over old ones. LAZYDISTINCTADD(errors, "selection overlaps other area") . = FALSE - if(istype(T, (A.base_turf ? A.base_turf : /turf/space))) + var/datum/level_data/our_level_data = SSmapping.levels_by_z[T.z] + if(istype(T, (A.base_turf ? A.base_turf : our_level_data.base_turf))) LAZYDISTINCTADD(errors, "selection is exposed to the outside") . = FALSE /mob/observer/eye/blueprints/proc/check_contiguity() - var/turf/start_turf = DEFAULTPICK(selected_turfs, null) + var/turf/start_turf = SAFEPICK(selected_turfs) if(!start_turf) LAZYDISTINCTADD(errors, "no turfs were selected") return FALSE var/list/pending_turfs = list(start_turf) var/list/checked_turfs = list() - + while(pending_turfs.len) if(LAZYLEN(checked_turfs) > MAX_AREA_SIZE) LAZYDISTINCTADD(errors, "selection exceeds max size") break var/turf/T = pending_turfs[1] pending_turfs -= T - for(var/dir in GLOB.cardinal) // Floodfill to find all turfs contiguous with the randomly chosen start_turf. + for(var/dir in global.cardinal) // Floodfill to find all turfs contiguous with the randomly chosen start_turf. var/turf/NT = get_step(T, dir) if(!isturf(NT) || !(NT in selected_turfs) || (NT in pending_turfs) || (NT in checked_turfs)) continue - pending_turfs += NT + pending_turfs += NT checked_turfs += T - - var/list/noncontiguous_turfs = (selected_turfs.Copy() - checked_turfs) + + var/list/noncontiguous_turfs = (selected_turfs.Copy() - checked_turfs) if(LAZYLEN(noncontiguous_turfs)) // If turfs still remain in noncontiguous_turfs, then the selection has unconnected parts. LAZYDISTINCTADD(errors, "selection must be contiguous") return FALSE - + return TRUE // For checks independent of the selection. @@ -222,7 +235,7 @@ /mob/observer/eye/blueprints/proc/update_images() if(!owner || !owner.client) return - + if(LAZYLEN(selection_images)) owner.client.images -= selection_images LAZYCLEARLIST(selection_images) @@ -232,6 +245,7 @@ var/selection_icon_state = selected_turfs[T] ? "valid" : "invalid" var/image/I = image('icons/effects/blueprints.dmi', T, selection_icon_state) I.plane = OBSERVER_PLANE + I.layer = OBSERVER_LAYER I.appearance_flags = NO_CLIENT_COLOR | RESET_COLOR LAZYADD(selection_images, I) @@ -245,7 +259,7 @@ var/area/A = get_area(src) if(!A) return - area_name_effect.maptext = "[area_prefix], [A.name]" + area_name_effect.maptext = "[area_prefix], [A.proper_name]" /mob/observer/eye/blueprints/apply_visual(var/mob/M) . = ..() @@ -253,7 +267,7 @@ M.overlay_fullscreen("blueprints", /obj/screen/fullscreen/blueprints) M.client.screen += area_name_effect - M.add_client_color(/datum/client_color/monochrome) + M.add_client_color(/datum/client_color/achromatopsia) /mob/observer/eye/blueprints/remove_visual(var/mob/M) . = ..() @@ -261,9 +275,57 @@ M.clear_fullscreen("blueprints", 0) M.client.screen -= area_name_effect - M.remove_client_color(/datum/client_color/monochrome) + M.remove_client_color(/datum/client_color/achromatopsia) /mob/observer/eye/blueprints/additional_sight_flags() return SEE_TURFS|BLIND +// Shuttle blueprints eye +/mob/observer/eye/blueprints/shuttle + var/shuttle_name + +/mob/observer/eye/blueprints/shuttle/Initialize(mapload, list/valid_zls, area_prefix, shuttle_name) + . = ..() + src.shuttle_name = shuttle_name + +/mob/observer/eye/blueprints/shuttle/check_modification_validity() + . = TRUE + var/area/A = get_area(src) + if(!(A.z in valid_z_levels)) + to_chat(owner, SPAN_WARNING("The markings on this are entirely irrelevant to your whereabouts!")) + return FALSE + var/datum/shuttle/our_shuttle = SSshuttle.shuttles[shuttle_name] + if(!(A in our_shuttle.shuttle_area)) + to_chat(owner, SPAN_WARNING("That's not a part of the [our_shuttle.display_name]!")) + return FALSE + if(!A || (A.area_flags & AREA_FLAG_IS_BACKGROUND)) + to_chat(owner, SPAN_WARNING("This area is not marked on the blueprints!")) + return FALSE + +/mob/observer/eye/blueprints/shuttle/remove_area() + var/area/A = get_area(src) + if(!check_modification_validity()) + return + if(A.apc) + to_chat(owner, SPAN_WARNING("You must remove the APC from this area before you can remove it from the blueprints!")) + return + var/datum/shuttle/our_shuttle = SSshuttle.shuttles[shuttle_name] + to_chat(owner, SPAN_NOTICE("You scrub [A.proper_name] off the blueprints.")) + log_and_message_admins("deleted area [A.proper_name] from [our_shuttle.display_name] via shuttle blueprints.") + var/turf/our_turf = get_turf(src) + var/datum/level_data/our_level_data = SSmapping.levels_by_z[our_turf.z] + var/area/base_area = our_level_data.get_base_area_instance() + for(var/turf/T in A.contents) + ChangeArea(T, base_area) + if(!(locate(/turf) in A)) + qdel(A) // uh oh, is this safe? + +/mob/observer/eye/blueprints/shuttle/finalize_area(area/A) + A = ..(A) + var/datum/shuttle/our_shuttle = SSshuttle.shuttles[shuttle_name] + our_shuttle.shuttle_area += A + SSshuttle.shuttle_areas += A + events_repository.register(/decl/observ/destroyed, A, our_shuttle, TYPE_PROC_REF(/datum/shuttle, remove_shuttle_area)) + return A + #undef MAX_AREA_SIZE \ No newline at end of file diff --git a/code/modules/mob/observer/eye/eye.dm b/code/modules/mob/observer/eye/eye.dm index 698b682c3853..ad313eeff1f4 100644 --- a/code/modules/mob/observer/eye/eye.dm +++ b/code/modules/mob/observer/eye/eye.dm @@ -5,6 +5,7 @@ /mob/observer/eye name = "Eye" + mob_sort_value = 1 var/name_sufix = "Eye" icon = 'icons/mob/eye.dmi' icon_state = "default-eye" @@ -14,11 +15,12 @@ var/acceleration = 1 var/owner_follows_eye = 0 var/living_eye = TRUE // Whether or not the eye uses normal living vision handling. - + var/click_handler_type = /datum/click_handler/eye/ // Set if the eye uses special click handling. Distinct from parent mob click handling for AI etc. - + see_in_dark = 7 invisibility = INVISIBILITY_EYE + is_spawnable_type = FALSE // No, don't. ghost_image_flag = GHOST_IMAGE_ALL var/mob/owner = null @@ -31,7 +33,7 @@ /mob/observer/eye/Move(n, direct) if(owner == src) return EyeMove(direct) - return 0 + return FALSE /mob/observer/eye/facedir(var/ndir) if(!canface()) @@ -39,7 +41,7 @@ set_dir(ndir) return 1 -/mob/observer/eye/examinate() +/mob/observer/eye/examine_verb() set popup_menu = 0 set src = usr.contents return 0 @@ -49,7 +51,7 @@ set src = usr.contents return 0 -/mob/observer/eye/examine(mob/user) +/mob/observer/eye/examined_by(mob/user) SHOULD_CALL_PARENT(FALSE) return TRUE @@ -77,6 +79,7 @@ LAZYREMOVE(user.additional_vision_handlers, src) remove_visual(owner) owner.eyeobj = null + owner.reset_view() if(click_handler_type) owner.RemoveClickHandler(click_handler_type) owner = null @@ -111,7 +114,7 @@ /mob/proc/EyeMove(n, direct) if(!eyeobj) - return + return FALSE return eyeobj.EyeMove(n, direct) @@ -126,10 +129,10 @@ var/turf/destination = (direct == UP) ? GetAbove(src) : GetBelow(src) if(!destination) to_chat(owner, "There is nothing of interest in this direction.") - return + return FALSE setLoc(destination) // No sprinting up and down. - return + return FALSE for(var/i = 0; i < max(sprint, initial); i += 20) var/turf/step = get_turf(get_step(src, direct)) @@ -141,7 +144,7 @@ sprint = min(sprint + 0.5, max_sprint) else sprint = initial - return 1 + return TRUE // Used to apply fullscreen effects etc. to owner /mob/observer/eye/apply_visual(var/mob/M) @@ -157,7 +160,7 @@ /mob/observer/eye/ClickOn(var/atom/A, var/params) if(owner) return owner.ClickOn(A, params) - + return ..() /datum/click_handler/eye/OnClick(var/atom/A, params) diff --git a/code/modules/mob/observer/eye/freelook/ai/cameranet.dm b/code/modules/mob/observer/eye/freelook/ai/cameranet.dm index bde34a77b7a8..90e270c35ddf 100644 --- a/code/modules/mob/observer/eye/freelook/ai/cameranet.dm +++ b/code/modules/mob/observer/eye/freelook/ai/cameranet.dm @@ -1,9 +1,9 @@ // CAMERA NET // // The datum containing all the chunks. - +var/global/datum/visualnet/camera/cameranet = new() /datum/visualnet/camera - // The cameras on the map, no matter if they work or not. + // The security cameras on the map, no matter if they work or not. This list only contains cameras of type /obj/machinery/camera. var/list/cameras chunk_type = /datum/chunk/camera valid_source_types = list(/obj/machinery/camera, /mob/living/silicon/ai) @@ -16,6 +16,7 @@ cameras.Cut() . = ..() +// Add a camera to a chunk. /datum/visualnet/camera/add_source(obj/machinery/camera/c) if(istype(c)) if(c in cameras) @@ -27,9 +28,7 @@ var/mob/living/silicon/AI = c return ..(AI, AI.stat != DEAD) else - ..() - -// Add a camera to a chunk. + return ..() /datum/visualnet/camera/remove_source(obj/machinery/camera/c) if(istype(c) && cameras.Remove(c)) @@ -38,4 +37,10 @@ var/mob/living/silicon/AI = c return ..(AI, AI.stat != DEAD) else - ..() + . = ..() + +/datum/visualnet/camera/is_valid_source(atom/source) + . = ..() + if(.) + return + return istype(get_extension(source, /datum/extension/network_device), /datum/extension/network_device/camera) \ No newline at end of file diff --git a/code/modules/mob/observer/eye/freelook/ai/chunk.dm b/code/modules/mob/observer/eye/freelook/ai/chunk.dm index b70737ce20c1..57fbc13408f3 100644 --- a/code/modules/mob/observer/eye/freelook/ai/chunk.dm +++ b/code/modules/mob/observer/eye/freelook/ai/chunk.dm @@ -5,12 +5,11 @@ /datum/chunk/camera/acquire_visible_turfs(var/list/visible) for(var/source in sources) - if(istype(source,/obj/machinery/camera)) - var/obj/machinery/camera/c = source - if(!c.can_use()) + var/datum/extension/network_device/camera/camera_device = get_extension(source, /datum/extension/network_device) + if(istype(camera_device)) + if(!camera_device.is_functional()) continue - - for(var/turf/t in c.can_see()) + for(var/turf/t in camera_device.can_see()) visible[t] = t else if(isAI(source)) var/mob/living/silicon/ai/AI = source diff --git a/code/modules/mob/observer/eye/freelook/ai/eye.dm b/code/modules/mob/observer/eye/freelook/ai/eye.dm index e827913ae86f..d7bee9821a03 100644 --- a/code/modules/mob/observer/eye/freelook/ai/eye.dm +++ b/code/modules/mob/observer/eye/freelook/ai/eye.dm @@ -76,7 +76,7 @@ . = ..() /atom/proc/move_camera_by_click() - if(istype(usr, /mob/living/silicon/ai)) + if(isAI(usr)) var/mob/living/silicon/ai/AI = usr if(AI.eyeobj && AI.client.eye == AI.eyeobj) AI.eyeobj.setLoc(src) diff --git a/code/modules/mob/observer/eye/freelook/ai/update_triggers.dm b/code/modules/mob/observer/eye/freelook/ai/update_triggers.dm index 5dedec75d5f9..04c52ccd6567 100644 --- a/code/modules/mob/observer/eye/freelook/ai/update_triggers.dm +++ b/code/modules/mob/observer/eye/freelook/ai/update_triggers.dm @@ -2,38 +2,8 @@ // An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not. -/obj/machinery/camera/deactivate(user, var/choice = 1) - ..(user, choice) - invalidateCameraCache() - if(!can_use()) - set_light(0) +/obj/machinery/camera/proc/update_coverage() cameranet.update_visibility(src) - -/obj/machinery/camera/Initialize() - . = ..() - var/list/open_networks = difflist(network, restricted_camera_networks) - on_open_network = open_networks.len - if(on_open_network) - cameranet.add_source(src) - -/obj/machinery/camera/Destroy() - if(on_open_network) - cameranet.remove_source(src) - . = ..() - -/obj/machinery/camera/proc/update_coverage(var/network_change = 0) - if(network_change) - var/list/open_networks = difflist(network, restricted_camera_networks) - // Add or remove camera from the camera net as necessary - if(on_open_network && !open_networks.len) - on_open_network = FALSE - cameranet.remove_source(src) - else if(!on_open_network && open_networks.len) - on_open_network = TRUE - cameranet.add_source(src) - else - cameranet.update_visibility(src) - invalidateCameraCache() // Mobs @@ -52,8 +22,8 @@ // Arise! cameranet.update_visibility(src, FALSE) -/mob/living/silicon/ai/death(gibbed, deathmessage, show_dead_message) - . = ..(gibbed, deathmessage, show_dead_message) +/mob/living/silicon/ai/death(gibbed) + . = ..() if(.) // If true, the mob went from living to dead (assuming everyone has been overriding as they should...) cameranet.update_visibility(src, FALSE) diff --git a/code/modules/mob/observer/eye/freelook/chunk.dm b/code/modules/mob/observer/eye/freelook/chunk.dm index 7d90696e56f5..090b232c7390 100644 --- a/code/modules/mob/observer/eye/freelook/chunk.dm +++ b/code/modules/mob/observer/eye/freelook/chunk.dm @@ -23,11 +23,11 @@ var/image/obfuscation = obfuscation_images[T] if(!obfuscation) obfuscation = image(icon, T, icon_state) - obfuscation.plane = EFFECTS_ABOVE_LIGHTING_PLANE + obfuscation.plane = ABOVE_LIGHTING_PLANE obfuscation.layer = OBFUSCATION_LAYER if(!obfuscation_underlay) // Creating a new icon of a fairly common icon state, adding some random color to prevent address searching, and hoping being static kills memory locality - var/turf/floor = /turf/simulated/floor/tiled + var/turf/floor = /turf/floor/tiled obfuscation_underlay = icon(initial(floor.icon), initial(floor.icon_state)) obfuscation_underlay.Blend(rgb(rand(0,255),rand(0,255),rand(0,255))) obfuscation.underlays += obfuscation_underlay @@ -128,7 +128,7 @@ if(seenby.len) updating = TRUE spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once - if(updating) // Check if we're still updating, a forced update may have occured. + if(updating) // Check if we're still updating, a forced update may have occurred. update() else dirty = TRUE // If this chunk is seen by noone, simply mark it as dirty and do nothing diff --git a/code/modules/mob/observer/eye/freelook/cult/cultnet.dm b/code/modules/mob/observer/eye/freelook/cult/cultnet.dm deleted file mode 100644 index ff09b8c58f52..000000000000 --- a/code/modules/mob/observer/eye/freelook/cult/cultnet.dm +++ /dev/null @@ -1,13 +0,0 @@ -/datum/visualnet/cultnet - valid_source_types = list(/mob/living/, /obj/structure/deity) - chunk_type = /datum/chunk/cultnet - -/datum/chunk/cultnet/acquire_visible_turfs(var/list/visible) - for(var/source in sources) - if(istype(source, /mob/living)) - var/mob/living/L = source - if(L.stat == DEAD) - continue - - for(var/turf/t in seen_turfs_in_range(source, world.view)) - visible[t] = t \ No newline at end of file diff --git a/code/modules/mob/observer/eye/freelook/cult/mask.dm b/code/modules/mob/observer/eye/freelook/cult/mask.dm deleted file mode 100644 index 636cc78ef468..000000000000 --- a/code/modules/mob/observer/eye/freelook/cult/mask.dm +++ /dev/null @@ -1,11 +0,0 @@ -/mob/observer/eye/freelook/cult - name = "Mask of God" - desc = "A terrible fracture of reality coinciding into a mirror to another world." - living_eye = FALSE - -mob/observer/eye/freelook/cult/EyeMove() - if(owner && istype(owner, /mob/living/deity)) - var/mob/living/deity/D = owner - if(D.following) - D.stop_follow() - return ..() diff --git a/code/modules/mob/observer/eye/freelook/freelook.dm b/code/modules/mob/observer/eye/freelook/freelook.dm index b3cf191a3c30..7234084d0cdb 100644 --- a/code/modules/mob/observer/eye/freelook/freelook.dm +++ b/code/modules/mob/observer/eye/freelook/freelook.dm @@ -4,12 +4,12 @@ /mob/observer/eye/freelook var/list/visibleChunks = list() - var/datum/visualnet/visualnet /mob/observer/eye/freelook/Initialize(var/mapload, var/datum/visualnet/net) . = ..() - if(net) visualnet = net + if(net) + visualnet = net /mob/observer/eye/freelook/Destroy() . = ..() @@ -17,16 +17,17 @@ /mob/observer/eye/freelook/possess(var/mob/user) . = ..() - visualnet.update_eye_chunks(src, TRUE) + if(visualnet) + visualnet.update_eye_chunks(src, TRUE) /mob/observer/eye/freelook/release(var/mob/user) - if(user == owner) + if(visualnet && user == owner) visualnet.remove_eye(src) . = ..() - + // Streams the chunk that the new loc is in. /mob/observer/eye/freelook/setLoc(var/T) . = ..() - if(.) + if(. && visualnet) visualnet.update_eye_chunks(src) \ No newline at end of file diff --git a/code/modules/mob/observer/eye/freelook/read_me.dm b/code/modules/mob/observer/eye/freelook/read_me.dm index fe7edf802953..763383424160 100644 --- a/code/modules/mob/observer/eye/freelook/read_me.dm +++ b/code/modules/mob/observer/eye/freelook/read_me.dm @@ -13,7 +13,7 @@ With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players. The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it. - This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking, + This creates several features, such as: no more see-through-wall cameras, easier to control camera movement, easier tracking, the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more. diff --git a/code/modules/mob/observer/eye/freelook/update_triggers.dm b/code/modules/mob/observer/eye/freelook/update_triggers.dm index 58cca39f897e..197fb081c4b3 100644 --- a/code/modules/mob/observer/eye/freelook/update_triggers.dm +++ b/code/modules/mob/observer/eye/freelook/update_triggers.dm @@ -4,17 +4,12 @@ /proc/updateVisibility(atom/A, var/opacity_check = 1) if(GAME_STATE >= RUNLEVEL_GAME) - for(var/datum/visualnet/VN in visual_nets) + for(var/datum/visualnet/VN in all_visual_nets) VN.update_visibility(A, opacity_check) /turf/drain_power() return -1 -/atom/Destroy() - if(opacity) - updateVisibility(src) - . = ..() - // DOORS // Simply updates the visibility of the area when it opens/closes/destroyed. @@ -24,8 +19,3 @@ // don't check then? if(!glass) updateVisibility(src, FALSE) - -/turf/ChangeTurf() - . = ..() - if(.) - updateVisibility(src, FALSE) diff --git a/code/modules/mob/observer/eye/freelook/visualnet.dm b/code/modules/mob/observer/eye/freelook/visualnet.dm index 2546748b7d83..c71be4a09622 100644 --- a/code/modules/mob/observer/eye/freelook/visualnet.dm +++ b/code/modules/mob/observer/eye/freelook/visualnet.dm @@ -1,7 +1,7 @@ // VISUAL NET // // The datum containing all the chunks. - +var/global/list/datum/visualnet/all_visual_nets = list() /datum/visualnet // The chunks of the map, mapping the areas that an object can see. var/list/chunks = list() @@ -11,12 +11,12 @@ /datum/visualnet/New() ..() - visual_nets += src + all_visual_nets += src if(!valid_source_types) valid_source_types = list() /datum/visualnet/Destroy() - visual_nets -= src + all_visual_nets -= src for(var/source in sources) remove_source(source, FALSE) sources.Cut() @@ -86,9 +86,6 @@ return major_chunk_change(A) -/datum/visualnet/proc/update_visibility_nocheck(atom/A) - update_visibility(A, FALSE) - // Will check if an atom is on a viewable turf. Returns 1 if it is, otherwise returns 0. /datum/visualnet/proc/is_visible(var/atom/target) // 0xf = 15 @@ -109,18 +106,18 @@ // Never access this proc directly!!!! // This will update the chunk and all the surrounding chunks. /datum/visualnet/proc/major_chunk_change(var/atom/source) - for_all_chunks_in_range(source, /datum/chunk/proc/visibility_changed, list()) + for_all_chunks_in_range(source, TYPE_PROC_REF(/datum/chunk, visibility_changed), list()) /datum/visualnet/proc/add_source(var/atom/source, var/update_visibility = TRUE, var/opacity_check = FALSE) - if(!(source && is_type_in_list(source, valid_source_types))) + if(!(source && is_valid_source(source))) log_visualnet("Was given an unhandled source", source) return FALSE if(source in sources) return FALSE sources += source - GLOB.moved_event.register(source, src, /datum/visualnet/proc/source_moved) - GLOB.destroyed_event.register(source, src, /datum/visualnet/proc/remove_source) - for_all_chunks_in_range(source, /datum/chunk/proc/add_source, list(source)) + events_repository.register(/decl/observ/moved, source, src, TYPE_PROC_REF(/datum/visualnet, source_moved)) + events_repository.register(/decl/observ/destroyed, source, src, TYPE_PROC_REF(/datum/visualnet, remove_source)) + for_all_chunks_in_range(source, TYPE_PROC_REF(/datum/chunk, add_source), list(source)) if(update_visibility) update_visibility(source, opacity_check) return TRUE @@ -129,13 +126,17 @@ if(!sources.Remove(source)) return FALSE - GLOB.moved_event.unregister(source, src, /datum/visualnet/proc/source_moved) - GLOB.destroyed_event.unregister(source, src, /datum/visualnet/proc/remove_source) - for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source)) + events_repository.unregister(/decl/observ/moved, source, src, TYPE_PROC_REF(/datum/visualnet, source_moved)) + events_repository.unregister(/decl/observ/destroyed, source, src, TYPE_PROC_REF(/datum/visualnet, remove_source)) + for_all_chunks_in_range(source, TYPE_PROC_REF(/datum/chunk, remove_source), list(source)) if(update_visibility) update_visibility(source, opacity_check) return TRUE +/datum/visualnet/proc/is_valid_source(var/atom/source) + if(is_type_in_list(source, valid_source_types)) + return TRUE + /datum/visualnet/proc/source_moved(var/atom/movable/source, var/old_loc, var/new_loc) var/turf/old_turf = get_turf(old_loc) var/turf/new_turf = get_turf(new_loc) @@ -146,9 +147,9 @@ // A more proper way would be to figure out which chunks have gone out of range, and which have come into range // and only remove/add to those. if(old_turf) - for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source), old_turf) + for_all_chunks_in_range(source, TYPE_PROC_REF(/datum/chunk, remove_source), list(source), old_turf) if(new_turf) - for_all_chunks_in_range(source, /datum/chunk/proc/add_source, list(source), new_turf) + for_all_chunks_in_range(source, TYPE_PROC_REF(/datum/chunk, add_source), list(source), new_turf) /datum/visualnet/proc/for_all_chunks_in_range(var/atom/source, var/proc_call, var/list/proc_args, var/turf/T) T = T ? T : get_turf(source) diff --git a/code/modules/mob/observer/eye/landing_eye.dm b/code/modules/mob/observer/eye/landing_eye.dm index 4e60e02c3f40..975c078c5293 100644 --- a/code/modules/mob/observer/eye/landing_eye.dm +++ b/code/modules/mob/observer/eye/landing_eye.dm @@ -1,33 +1,106 @@ -#define LANDING_VIEW 12 +#define LANDING_VIEW 25 +#define MAX_OFFSET 20 /mob/observer/eye/landing name = "Landing Eye" desc = "A visual projection used to assist in the landing of a shuttle." name_sufix = "Landing Eye" var/datum/shuttle/autodock/shuttle + var/obj/effect/overmap/visitable/target_sector var/list/landing_images = list() + var/list/docking_images = list() + var/list/docking_turfs = list() // Turfs where it is okay to land, even if its within a restricted area. -/mob/observer/eye/landing/Initialize(var/mapload, var/shuttle_tag) + var/offsetting = FALSE // If the user is offsetting the landing images manually. + var/x_offset = 0 + var/y_offset = 0 + var/shuttle_dir + +/mob/observer/eye/landing/Initialize(var/mapload, var/shuttle_tag, var/obj/effect/overmap/visitable/sector) shuttle = SSshuttle.shuttles[shuttle_tag] + var/atom/movable/center_of_rotation = shuttle.get_center_of_rotation() + shuttle_dir = center_of_rotation.dir + target_sector = sector // Generates the overlay of the shuttle on turfs. - var/turf/origin = get_turf(src) + var/turf/origin = get_turf(center_of_rotation) for(var/area/A in shuttle.shuttle_area) for(var/turf/T in A) var/image/I = image('icons/effects/alphacolors.dmi', origin, "red") // Record the offset of the turfs from the eye. The eye is where the shuttle landmark will be placed, so the resultant images will reflect actual landing. var/x_off = T.x - origin.x var/y_off = T.y - origin.y - I.loc = locate(origin.x + x_off, origin.y + y_off, origin.z) I.plane = OBSERVER_PLANE + I.layer = OBSERVER_LAYER landing_images[I] = list(x_off, y_off) + // Find the docking beacons in the z-level(s) we're landing in. + var/list/docking_beacons = SSshuttle.docking_beacons_by_z(target_sector.map_z) + for(var/obj/machinery/docking_beacon/beacon in docking_beacons) + // If the beacon permits us, we'll generate the images for the area where we can land. + if(beacon.check_permission(shuttle.name, shuttle.docking_codes)) + docking_turfs += beacon.get_turfs() + + for(var/turf/T in docking_turfs) + var/image/I = image('icons/effects/alphacolors.dmi', T, "blue") + I.layer = OBSERVER_LAYER + I.plane = OBSERVER_PLANE + docking_images += I + . = ..(mapload) +/mob/observer/eye/landing/proc/turn_shuttle_cw() + return turn_shuttle(90) + +/mob/observer/eye/landing/proc/turn_shuttle_ccw() + return turn_shuttle(-90) + +/mob/observer/eye/landing/proc/turn_shuttle(angle) + angle = round(SIMPLIFY_DEGREES(angle), 90) // can only turn at right angles + var/adj = 1 + var/opp = 0 + switch(angle) + if(90) + adj = 0 + opp = 1 // swap the X and Y axes + if(180) + adj = -1 // flip across the axes + opp = 0 + if(270) + adj = 0 + opp = -1 // swap the X and Y axes and then flip + for(var/image/landing_image in landing_images) + var/x_off = landing_images[landing_image][1] + var/y_off = landing_images[landing_image][2] + // y axis is flipped in byond so we subtract x_off * opp + landing_images[landing_image] = list(x_off * adj + y_off * opp, y_off * adj - x_off * opp) + x_offset = x_offset * adj + y_offset * opp + y_offset = y_offset * adj - x_offset * opp + shuttle_dir = turn(shuttle_dir, angle) + check_landing() + /mob/observer/eye/landing/Destroy() . = ..() shuttle = null + target_sector = null landing_images.Cut() + docking_images.Cut() + docking_turfs.Cut() + +/mob/observer/eye/landing/EyeMove(direct) + if(offsetting) + if(direct & NORTH) + y_offset = min(y_offset + 1, MAX_OFFSET) + if(direct & SOUTH) + y_offset = max(y_offset - 1, -MAX_OFFSET) + if(direct & EAST) + x_offset = min(x_offset + 1, MAX_OFFSET) + if(direct & WEST) + x_offset = max(x_offset - 1, -MAX_OFFSET) + + check_landing() + return FALSE + . = ..() /mob/observer/eye/landing/setLoc(var/turf/T) T = get_turf(T) @@ -40,44 +113,50 @@ //This is a subset of the actual checks in place for moving the shuttle. /mob/observer/eye/landing/proc/check_landing() + var/turf/eye_turf = get_turf(src) + var/turf/origin = locate(eye_turf.x + x_offset, eye_turf.y + y_offset, eye_turf.z) + for(var/i = 1 to landing_images.len) var/image/img = landing_images[i] var/list/coords = landing_images[img] - var/turf/origin = get_turf(src) - var/turf/T = locate(origin.x + coords[1], origin.y + coords[2], origin.z) - var/area/A = T?.loc + var/turf/T = locate(eye_turf.x + x_offset + coords[1], eye_turf.y + y_offset + coords[2], eye_turf.z) + + var/ra = target_sector.restricted_area + img.loc = T img.icon_state = "green" . = TRUE if(!T || !T.loc || !origin || !origin.loc) - img.icon_state = "red" . = FALSE - continue - if((T.x < TRANSITIONEDGE || T.x > world.maxx - TRANSITIONEDGE) || (T.y < TRANSITIONEDGE || T.y > world.maxy - TRANSITIONEDGE)) - img.icon_state = "red" + else if((T.x < TRANSITIONEDGE || T.x > world.maxx - TRANSITIONEDGE) || (T.y < TRANSITIONEDGE || T.y > world.maxy - TRANSITIONEDGE)) . = FALSE // Cannot land past the normal world boundaries. - continue - if(!istype(T, origin)) - img.icon_state = "red" - . = FALSE // Cannot land on two different types of turfs. - continue - if(check_collision(origin.loc, list(T))) // Checking for density or multi-area overlap. - img.icon_state = "red" + else if(check_collision(origin.loc, list(T))) // Checking for density or multi-area overlap. . = FALSE - continue - if(!istype(A, /area/space) && !istype(A, /area/exoplanet)) // Can only land in space or outside. - img.icon_state = "red" - . = FALSE - continue + else if((T.x > (world.maxx - ra)/2 && T.x < (world.maxx + ra)/2) && (T.y > (world.maxy - ra)/2 && T.y < (world.maxy + ra)/2)) + if(!(T in docking_turfs)) + . = FALSE // Cannot land within the restricted area *unless* there is a valid docking beacon in the same location. + if(!.) + img.icon_state = "red" // Visual indicator the spot is invalid. + +// Checks if the landing location is secure, and therefore the shuttle will move with whatever sector its landed in. +/mob/observer/eye/landing/proc/check_secure_landing() + return ((target_sector.sector_flags & (~OVERMAP_SECTOR_IN_SPACE)) || (get_turf(src) in docking_turfs)) + +/mob/observer/eye/landing/proc/toggle_offsetting() + offsetting = !offsetting /mob/observer/eye/landing/possess(var/mob/user) . = ..() + offsetting = FALSE + x_offset = 0 + y_offset = 0 if(owner && owner.client) owner.client.view = LANDING_VIEW owner.client.images += landing_images + owner.client.images += docking_images /mob/observer/eye/landing/release(var/mob/user) if(owner && owner.client && owner == user) @@ -90,4 +169,5 @@ /mob/observer/eye/landing/additional_sight_flags() return SEE_TURFS|BLIND -#undef LANDING_VIEW \ No newline at end of file +#undef LANDING_VIEW +#undef MAX_OFFSET \ No newline at end of file diff --git a/code/modules/mob/observer/ghost/follow.dm b/code/modules/mob/observer/ghost/follow.dm index 237f7f140512..8ffd825d8205 100644 --- a/code/modules/mob/observer/ghost/follow.dm +++ b/code/modules/mob/observer/ghost/follow.dm @@ -29,7 +29,7 @@ return mob.get_ghost_follow_link(target, delimiter, prefix, sufix) /mob/observer/ghost/get_ghost_follow_link(var/atom/target, var/delimiter, var/prefix, var/sufix) - var/short_links = get_preference_value(/datum/client_preference/ghost_follow_link_length) == GLOB.PREF_SHORT + var/short_links = get_preference_value(/datum/client_preference/ghost_follow_link_length) == PREF_SHORT return ghost_follow_link(target, src, delimiter, prefix, sufix, short_links) /proc/ghost_follow_link(var/atom/target, var/atom/ghost, var/delimiter = "|", var/prefix = "", var/sufix = "", var/short_links = TRUE) diff --git a/code/modules/mob/observer/ghost/ghost.dm b/code/modules/mob/observer/ghost/ghost.dm index 7e46f7a7770c..aa1268cbaa5d 100644 --- a/code/modules/mob/observer/ghost/ghost.dm +++ b/code/modules/mob/observer/ghost/ghost.dm @@ -6,17 +6,18 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images desc = "It's a g-g-g-g-ghooooost!" //jinkies! icon = 'icons/mob/mob.dmi' icon_state = "ghost" - appearance_flags = KEEP_TOGETHER - blinded = 0 - anchored = 1 // don't get pushed around + appearance_flags = KEEP_TOGETHER | LONG_GLIDE + anchored = TRUE // don't get pushed around universal_speak = TRUE + mob_sort_value = 9 + is_spawnable_type = FALSE mob_flags = MOB_FLAG_HOLY_BAD movement_handlers = list(/datum/movement_handler/mob/multiz_connected, /datum/movement_handler/mob/incorporeal) - var/next_visibility_toggle = 0 + var/static/obj/item/card/id/all_access/ghost_all_access + var/can_reenter_corpse - var/bootime = 0 var/started_as_observer //This variable is set to 1 when you enter the game as an observer. //If you died in the game and are a ghost - this will remain as null. //Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot. @@ -25,7 +26,6 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images var/antagHUD = 0 var/atom/movable/following = null var/admin_ghosted = 0 - var/anonsay = 0 var/ghostvision = 1 //is the ghost able to see things humans can't? var/seedarkness = 1 @@ -50,33 +50,33 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images name = body.real_name else if(gender == MALE) - name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + name = capitalize(pick(global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) else - name = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + name = capitalize(pick(global.using_map.first_names_female)) + " " + capitalize(pick(global.using_map.last_names)) mind = body.mind //we don't transfer the mind but we keep a reference to it. else spawn(10) // wait for the observer mob to receive the client's key - mind = new /datum/mind(key) - mind.current = src - if(!T) T = pick(GLOB.latejoin | GLOB.latejoin_cryo | GLOB.latejoin_gateway) //Safety in case we cannot find the body's position + if(!QDELETED(src)) + mind = new /datum/mind(key) + mind.current = src + if(!T) + T = get_random_spawn_turf(SPAWN_FLAG_GHOSTS_CAN_SPAWN) + forceMove(T) if(!name) //To prevent nameless ghosts - name = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + name = capitalize(pick(global.using_map.first_names_male)) + " " + capitalize(pick(global.using_map.last_names)) real_name = name - if(GLOB.cult) - GLOB.cult.add_ghost_magic(src) - ghost_multitool = new(src) - GLOB.ghost_mob_list += src + global.ghost_mob_list += src . = ..() /mob/observer/ghost/Destroy() - GLOB.ghost_mob_list -= src + global.ghost_mob_list -= src stop_following() qdel(ghost_multitool) ghost_multitool = null @@ -88,7 +88,7 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images /mob/observer/ghost/OnSelfTopic(href_list) if (href_list["track"]) - if(istype(href_list["track"],/mob)) + if(ismob(href_list["track"])) var/mob/target = locate(href_list["track"]) in SSmobs.mob_list if(target) ManualFollow(target) @@ -105,50 +105,50 @@ Works together with spawning an observer, noted above. */ /mob/observer/ghost/Life() + ..() - if(!loc) return - if(!client) return 0 + if(!loc || !client) + return FALSE handle_hud_glasses() if(antagHUD) var/list/target_list = list() for(var/mob/living/target in oview(src, 14)) - if(target.mind && target.mind.special_role) + if(target.mind && target.mind.assigned_special_role) target_list += target if(target_list.len) assess_targets(target_list, src) if(medHUD) process_medHUD(src) - /mob/observer/ghost/proc/process_medHUD(var/mob/M) var/client/C = M.client - for(var/mob/living/carbon/human/patient in oview(M, 14)) + for(var/mob/living/human/patient in oview(M, 14)) C.images += patient.hud_list[HEALTH_HUD] C.images += patient.hud_list[STATUS_HUD_OOC] /mob/observer/ghost/proc/assess_targets(list/target_list, mob/observer/ghost/U) var/client/C = U.client - for(var/mob/living/carbon/human/target in target_list) + for(var/mob/living/human/target in target_list) C.images += target.hud_list[SPECIALROLE_HUD] for(var/mob/living/silicon/target in target_list) C.images += target.hud_list[SPECIALROLE_HUD] return 1 -/mob/proc/ghostize(var/can_reenter_corpse = CORPSE_CAN_REENTER) +/mob/proc/ghostize(var/_can_reenter_corpse = CORPSE_CAN_REENTER) // Are we the body of an aghosted admin? If so, don't make a ghost. - if(teleop && istype(teleop, /mob/observer/ghost)) + if(isghost(teleop)) var/mob/observer/ghost/G = teleop if(G.admin_ghosted) return if(key) hide_fullscreens() var/mob/observer/ghost/ghost = new(src) //Transfer safety to observer spawning proc. - ghost.can_reenter_corpse = can_reenter_corpse + ghost.can_reenter_corpse = _can_reenter_corpse ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time ghost.key = key - if(ghost.client && !ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. + if(ghost.client && !ghost.client.holder && !get_config_value(/decl/config/toggle/antag_hud_allowed)) // For new ghosts we remove the verb from even showing up if it's not allowed. ghost.verbs -= /mob/observer/ghost/verb/toggle_antagHUD // Poor guys, don't know what they are missing! return ghost @@ -163,8 +163,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set desc = "Relinquish your life and enter the land of the dead." if(stat == DEAD) - announce_ghost_joinleave(ghostize(1)) + announce_ghost_joinleave(ghostize()) else + var/respawn_delay = get_config_value(/decl/config/num/respawn_delay) var/response if(src.client && src.client.holder) response = alert(src, "You have the ability to Admin-Ghost. The regular Ghost verb will announce your presence to dead chat. Both variants will allow you to return to your body using 'aghost'.\n\nWhat do you wish to do?", "Are you sure you want to ghost?", "Ghost", "Admin Ghost", "Stay in body") @@ -172,46 +173,51 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!src.client) return src.client.admin_ghost() - else if(config.respawn_delay) - response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost, you won't be able to play this round for another [config.respawn_delay] minute\s! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body") + else if(respawn_delay) + response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost, you won't be able to play this round for another [respawn_delay] minute\s! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body") else response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost, you won't be able to return to this body! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", "Ghost", "Stay in body") if(response != "Ghost") return - resting = 1 + set_posture(/decl/posture/lying) log_and_message_admins("has ghosted.") - var/mob/observer/ghost/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 + var/mob/observer/ghost/ghost = ghostize(CORPSE_CANNOT_REENTER) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly. announce_ghost_joinleave(ghost) -/mob/observer/ghost/can_use_hands() return 0 -/mob/observer/ghost/is_active() return 0 - /mob/observer/ghost/Stat() . = ..() - if(statpanel("Status")) - if(SSevac.evacuation_controller) - var/eta_status = SSevac.evacuation_controller.get_status_panel_eta() - if(eta_status) - stat(null, eta_status) + if(statpanel("Status") && SSevac.evacuation_controller) + var/eta_status = SSevac.evacuation_controller.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) /mob/observer/ghost/verb/reenter_corpse() set category = "Ghost" set name = "Re-enter Corpse" - if(!client) return - if(!(mind && mind.current && can_reenter_corpse)) - to_chat(src, "You have no body.") - return - if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients - to_chat(src, "Another consciousness is in your body... it is resisting you.") - return + + if(!client) + return FALSE + + if(QDELETED(mind?.current)) + to_chat(src, SPAN_WARNING("You have no body.")) + return FALSE + + if(!(can_reenter_corpse & CORPSE_CAN_REENTER)) + to_chat(src, SPAN_WARNING("You are not permitted to reenter your body.")) + return FALSE + + if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any adminghosted clients + to_chat(src, SPAN_WARNING("Another consciousness is in your body... it is resisting you.")) + return FALSE + stop_following() mind.current.key = key mind.current.teleop = null mind.current.reload_fullscreen() if(!admin_ghosted) announce_ghost_joinleave(mind, 0, "They now occupy their body again.") - return 1 + return TRUE /mob/observer/ghost/verb/toggle_medHUD() set category = "Ghost" @@ -233,17 +239,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!client) return - if(!config.antag_hud_allowed && !client.holder) + if(!get_config_value(/decl/config/toggle/antag_hud_allowed) && !client.holder) to_chat(src, SPAN_WARNING("Admins have disabled this for this round")) return var/mob/observer/ghost/M = src if(jobban_isbanned(M, "AntagHUD")) - to_chat(src, SPAN_WARNING("You have been banned from using this feature")) + to_chat(src, SPAN_WARNING("You have been banned from using this feature.")) return - if(config.antag_hud_restricted && !M.has_enabled_antagHUD && !client.holder) + if(get_config_value(/decl/config/toggle/antag_hud_restricted) && !M.has_enabled_antagHUD && !client.holder) var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No") - if(response == "No") return - M.can_reenter_corpse = 0 + if(response == "No") + return + M.can_reenter_corpse = CORPSE_CANNOT_REENTER if(!M.has_enabled_antagHUD && !client.holder) M.has_enabled_antagHUD = 1 if(M.antagHUD) @@ -263,7 +270,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp to_chat(src, "No area available.") return - var/list/area_turfs = get_area_turfs(thearea, shall_check_if_holy() ? list(/proc/is_holy_turf) : list()) + var/list/area_turfs = get_area_turfs(thearea, shall_check_if_holy() ? list(/proc/is_not_holy_turf) : list()) if(!area_turfs.len) to_chat(src, "This area has been entirely made into sacred grounds, you cannot enter it while you are in this plane of existence!") return @@ -303,9 +310,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp stop_following() following = target verbs |= /mob/observer/ghost/proc/scan_target - GLOB.moved_event.register(following, src, /atom/movable/proc/move_to_turf) - GLOB.dir_set_event.register(following, src, /atom/proc/recursive_dir_set) - GLOB.destroyed_event.register(following, src, /mob/observer/ghost/proc/stop_following) + events_repository.register(/decl/observ/moved, following, src, TYPE_PROC_REF(/atom/movable, move_to_turf)) + events_repository.register(/decl/observ/dir_set, following, src, TYPE_PROC_REF(/atom, recursive_dir_set)) + events_repository.register(/decl/observ/destroyed, following, src, TYPE_PROC_REF(/mob/observer/ghost, stop_following)) to_chat(src, "Now following \the [following].") move_to_turf(following, loc, following.loc) @@ -313,9 +320,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/observer/ghost/proc/stop_following() if(following) to_chat(src, "No longer following \the [following]") - GLOB.moved_event.unregister(following, src) - GLOB.dir_set_event.unregister(following, src) - GLOB.destroyed_event.unregister(following, src) + events_repository.unregister(/decl/observ/moved, following, src) + events_repository.unregister(/decl/observ/dir_set, following, src) + events_repository.unregister(/decl/observ/destroyed, following, src) following = null verbs -= /mob/observer/ghost/proc/scan_target @@ -362,30 +369,34 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(ishuman(following)) to_chat(src, medical_scan_results(following, 1, SKILL_MAX)) - else to_chat(src, "Not a scannable target.") + else to_chat(src, SPAN_WARNING("\The [following] is not a scannable target.")) /mob/observer/ghost/verb/become_mouse() set name = "Become mouse" set category = "Ghost" - if(config.disable_player_mice) - to_chat(src, "Spawning as a mouse is currently disabled.") + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(src)) + to_chat(src, SPAN_WARNING("Non-whitelisted players cannot join rounds except as observers.")) + return + + if(get_config_value(/decl/config/toggle/disable_player_mice)) + to_chat(src, SPAN_WARNING("Spawning as a mouse is currently disabled.")) return if(!MayRespawn(1, ANIMAL_SPAWN_DELAY)) return var/turf/T = get_turf(src) - if(!T || (T.z in GLOB.using_map.admin_levels)) - to_chat(src, "You may not spawn as a mouse on this Z-level.") + if(!T || isAdminLevel(T.z)) + to_chat(src, SPAN_WARNING("You may not spawn as a mouse on this Z-level.")) return var/response = alert(src, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?","Squeek!","Nope!") - if(response != "Squeek!") return //Hit the wrong key...again. - + if(response != "Squeek!") + return //find a viable mouse candidate - var/mob/living/simple_animal/mouse/host + var/mob/living/simple_animal/passive/mouse/host var/obj/machinery/atmospherics/unary/vent_pump/vent_found var/list/found_vents = list() for(var/obj/machinery/atmospherics/unary/vent_pump/v in SSmachines.machinery) @@ -393,16 +404,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp found_vents.Add(v) if(found_vents.len) vent_found = pick(found_vents) - host = new /mob/living/simple_animal/mouse(vent_found.loc) + host = new /mob/living/simple_animal/passive/mouse(vent_found.loc) else - to_chat(src, "Unable to find any unwelded vents to spawn mice at.") + to_chat(src, SPAN_WARNING("Unable to find any unwelded vents to spawn mice at.")) + if(host) - if(config.uneducated_mice) + if(get_config_value(/decl/config/toggle/uneducated_mice)) host.universal_understand = FALSE announce_ghost_joinleave(src, 0, "They are now a mouse.") host.ckey = src.ckey host.status_flags |= NO_ANTAG - to_chat(host, "You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.") + to_chat(host, SPAN_INFO("You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.")) + /mob/observer/ghost/verb/view_manfiest() set name = "Show Crew Manifest" set category = "Ghost" @@ -414,8 +427,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp show_browser(src, dat, "window=manifest;size=370x420;can_close=1") //This is called when a ghost is drag clicked to something. -/mob/observer/ghost/MouseDrop(atom/over) - if(!usr || !over) return +/mob/observer/ghost/MouseDrop(over_object, src_location, over_location, src_control, over_control, params) + SHOULD_CALL_PARENT(FALSE) + var/atom/over = over_object + if(!usr || !over) + return if(isghost(usr) && usr.client && isliving(over)) var/mob/living/M = over // If they an admin, see if control can be resolved. @@ -424,25 +440,25 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp // Otherwise, see if we can possess the target. if(usr == src && try_possession(M)) return - if(istype(over, /obj/machinery/drone_fabricator)) - if(try_drone_spawn(src, over)) - return - + if(istype(over, /obj/machinery/drone_fabricator) && try_drone_spawn(src, over)) + return return ..() /mob/observer/ghost/proc/try_possession(var/mob/living/M) - if(!config.ghosts_can_possess_animals) - to_chat(src, "Ghosts are not permitted to possess animals.") - return 0 + if(!get_config_value(/decl/config/toggle/ghosts_can_possess_animals)) + to_chat(src, SPAN_WARNING("Ghosts are not permitted to possess animals.")) + return FALSE if(!M.can_be_possessed_by(src)) - return 0 + return FALSE return M.do_possession(src) /mob/observer/ghost/pointed(atom/A as mob|obj|turf in view()) if(!..()) - return 0 - usr.visible_message("[src] points to [A]") - return 1 + return FALSE + for(var/mob/M in viewers(7, get_turf(A))) + if(M.see_invisible >= invisibility) + to_chat(M, "[src] points to [A]") + return TRUE /mob/observer/ghost/proc/show_hud_icon(var/icon_state, var/make_visible) if(!hud_images) @@ -462,11 +478,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Toggle Anonymous Chat" set desc = "Toggles showing your key in dead chat." - src.anonsay = !src.anonsay - if(anonsay) + if(client.get_preference_value(/datum/client_preference/anon_say) == PREF_NO) to_chat(src, "Your key won't be shown when you speak in dead chat.") + client.set_preference(/datum/client_preference/anon_say, PREF_YES) else to_chat(src, "Your key will be publicly visible again.") + client.set_preference(/datum/client_preference/anon_say, PREF_NO) /mob/observer/ghost/canface() return 1 @@ -513,24 +530,27 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp client.images -= ghost_image //remove ourself /mob/observer/ghost/MayRespawn(var/feedback = 0, var/respawn_time = 0) + if(!client) - return 0 - if(mind?.current && mind.current.stat != DEAD && (can_reenter_corpse in list(CORPSE_CAN_REENTER, CORPSE_CAN_REENTER_AND_RESPAWN))) + return FALSE + + if(mind?.current && !QDELETED(mind.current) && mind.current.stat != DEAD && (can_reenter_corpse & CORPSE_CAN_REENTER) && !(can_reenter_corpse & CORPSE_CAN_RESPAWN)) if(feedback) - to_chat(src, "Your non-dead body prevents you from respawning.") - return 0 - if(config.antag_hud_restricted && has_enabled_antagHUD == 1) + to_chat(src, SPAN_WARNING("Your non-dead body prevents you from respawning.")) + return FALSE + + if(get_config_value(/decl/config/toggle/antag_hud_restricted) && has_enabled_antagHUD == 1) if(feedback) - to_chat(src, "antagHUD restrictions prevent you from respawning.") - return 0 + to_chat(src, SPAN_WARNING("antagHUD restrictions prevent you from respawning.")) + return FALSE var/timedifference = world.time - timeofdeath if(!client.holder && respawn_time && timeofdeath && timedifference < respawn_time MINUTES) var/timedifference_text = time2text(respawn_time MINUTES - timedifference,"mm:ss") - to_chat(src, "You must have been dead for [respawn_time] minute\s to respawn. You have [timedifference_text] left.") - return 0 + to_chat(src, SPAN_WARNING("You must have been dead for [respawn_time] minute\s to respawn. You have [timedifference_text] left.")) + return FALSE - return 1 + return TRUE /proc/isghostmind(var/datum/mind/player) return player && !isnewplayer(player.current) && (!player.current || isghost(player.current) || (isliving(player.current) && player.current.stat == DEAD) || !player.current.client) @@ -557,9 +577,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp appearance = target appearance_flags |= initial(appearance_flags) + + // Keep mob offsets when you move over tables and such! + default_pixel_x = target.default_pixel_x + default_pixel_w = target.default_pixel_w + default_pixel_y = target.default_pixel_y + default_pixel_z = target.default_pixel_z + + // Apply ghostly alpha and layering. alpha = pre_alpha plane = pre_plane layer = pre_layer + set_invisibility(pre_invis) transform = null //make goast stand up @@ -567,7 +596,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Respawn" set category = "OOC" - if (!(config.abandon_allowed)) + if (!get_config_value(/decl/config/toggle/on/abandon_allowed)) to_chat(usr, SPAN_WARNING("Respawn is disabled.")) return if (!SSticker.mode) @@ -576,7 +605,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if (SSticker.mode.deny_respawn) to_chat(usr, SPAN_WARNING("Respawn is disabled for this roundtype.")) return - else if(!MayRespawn(1, config.respawn_delay)) + else if(!MayRespawn(1, get_config_value(/decl/config/num/respawn_delay))) return to_chat(usr, SPAN_NOTICE("You can respawn now, enjoy your new life!")) @@ -586,3 +615,29 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/mob/new_player/M = new /mob/new_player() M.key = key log_and_message_admins("has respawned.", M) + +/mob/observer/ghost/GetIdCards(list/exceptions) + . = ..() + if(is_admin(src)) + if (!ghost_all_access) + ghost_all_access = new + if(!is_type_in_list(ghost_all_access, exceptions)) + LAZYDISTINCTADD(., ghost_all_access) + +/mob/observer/ghost/Login() + ..() + if (ghost_image) + ghost_image.appearance = src + ghost_image.appearance_flags = RESET_ALPHA + SSghost_images.queue_image_update(src) + +/mob/observer/ghost/proc/check_existence_failure() + if(!QDELETED(src) && !key) //we've transferred to another mob. This ghost should be deleted. + qdel(src) + +/mob/observer/ghost/Logout() + ..() + addtimer(CALLBACK(src, PROC_REF(check_existence_failure)), 0) + +/mob/observer/ghost/say(var/message) + sanitize_and_communicate(/decl/communication_channel/dsay, client, message) diff --git a/code/modules/mob/observer/ghost/login.dm b/code/modules/mob/observer/ghost/login.dm deleted file mode 100644 index 1cb83f36a8a3..000000000000 --- a/code/modules/mob/observer/ghost/login.dm +++ /dev/null @@ -1,8 +0,0 @@ -/mob/observer/ghost/Login() - ..() - - if (ghost_image) - ghost_image.appearance = src - ghost_image.appearance_flags = RESET_ALPHA - SSghost_images.queue_image_update(src) - change_light_colour(DARKTINT_GOOD) diff --git a/code/modules/mob/observer/ghost/logout.dm b/code/modules/mob/observer/ghost/logout.dm deleted file mode 100644 index 7c125cef367c..000000000000 --- a/code/modules/mob/observer/ghost/logout.dm +++ /dev/null @@ -1,5 +0,0 @@ -/mob/observer/ghost/Logout() - ..() - spawn(0) - if(src && !key) //we've transferred to another mob. This ghost should be deleted. - qdel(src) diff --git a/code/modules/mob/observer/ghost/say.dm b/code/modules/mob/observer/ghost/say.dm deleted file mode 100644 index f30f4a672c10..000000000000 --- a/code/modules/mob/observer/ghost/say.dm +++ /dev/null @@ -1,2 +0,0 @@ -/mob/observer/ghost/say(var/message) - sanitize_and_communicate(/decl/communication_channel/dsay, client, message) diff --git a/code/modules/mob/observer/observer.dm b/code/modules/mob/observer/observer.dm index 69ec4b382625..7311b0eb3f00 100644 --- a/code/modules/mob/observer/observer.dm +++ b/code/modules/mob/observer/observer.dm @@ -1,11 +1,12 @@ -var/const/GHOST_IMAGE_NONE = 0 -var/const/GHOST_IMAGE_DARKNESS = 1 -var/const/GHOST_IMAGE_SIGHTLESS = 2 -var/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE +var/global/const/GHOST_IMAGE_NONE = 0 +var/global/const/GHOST_IMAGE_DARKNESS = 1 +var/global/const/GHOST_IMAGE_SIGHTLESS = 2 +var/global/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE /mob/observer - density = 0 + density = FALSE alpha = 127 + layer = OBSERVER_LAYER plane = OBSERVER_PLANE invisibility = INVISIBILITY_OBSERVER see_invisible = SEE_INVISIBLE_OBSERVER @@ -13,11 +14,14 @@ var/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE simulated = FALSE stat = DEAD status_flags = GODMODE + shift_to_open_context_menu = FALSE + skillset = /datum/skillset // moved here from /mob to avoid giving dview a skillset var/ghost_image_flag = GHOST_IMAGE_DARKNESS var/image/ghost_image = null //this mobs ghost image, for deleting and stuff /mob/observer/Initialize() . = ..() + glide_size = 0 // Set in Initialize() because the compiler doesn't like it set in the definition. ghost_image = image(src.icon,src) ghost_image.plane = plane ghost_image.layer = layer @@ -38,17 +42,33 @@ var/const/GHOST_IMAGE_ALL = ~GHOST_IMAGE_NONE SSghost_images.queue_global_image_update() . = ..() -mob/observer/check_airflow_movable() +/mob/observer/can_slip(magboots_only = FALSE) + return FALSE + +/mob/observer/get_movement_delay(travel_dir) + return 1 + +/mob/observer/check_airflow_movable() return FALSE /mob/observer/CanPass() return TRUE +/mob/observer/physically_destroyed() + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/mob/observer/handle_existence_failure(dusted) + SHOULD_CALL_PARENT(FALSE) + return FALSE + /mob/observer/dust() //observers can't be vaporised. - return + SHOULD_CALL_PARENT(FALSE) + return FALSE /mob/observer/gib() //observers can't be gibbed. - return + SHOULD_CALL_PARENT(FALSE) + return FALSE /mob/observer/is_blind() //Not blind either. return @@ -59,8 +79,8 @@ mob/observer/check_airflow_movable() /mob/observer/set_stat() stat = DEAD // They are also always dead -/mob/observer/touch_map_edge() - if(z in GLOB.using_map.sealed_levels) +/mob/observer/touch_map_edge(var/overmap_id = OVERMAP_ID_SPACE) + if(isSealedLevel(z)) return var/new_x = x @@ -78,11 +98,24 @@ mob/observer/check_airflow_movable() var/turf/T = locate(new_x, new_y, z) if(T) forceMove(T) - throwing = null + end_throw() to_chat(src, "You cannot move further in this direction.") -/mob/observer/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays) +/mob/observer/handle_reading_literacy(var/mob/user, var/text_content, var/skip_delays, var/digital = FALSE) . = text_content /mob/observer/handle_writing_literacy(var/mob/user, var/text_content, var/skip_delays) . = text_content + +/mob/observer/get_admin_job_string() + return "Ghost" + +/mob/observer/set_glide_size(var/delay) + glide_size = 0 + +/mob/observer/get_speech_bubble_state_modifier() + return "ghost" + +/mob/observer/refresh_lighting_master() + ..() + lighting_master.alpha = 255 // don't bother animating it diff --git a/code/modules/mob/observer/virtual/_constants.dm b/code/modules/mob/observer/virtual/_constants.dm index 76446296e188..7d1b9eecf7f0 100644 --- a/code/modules/mob/observer/virtual/_constants.dm +++ b/code/modules/mob/observer/virtual/_constants.dm @@ -1,4 +1,4 @@ -var/const/VIRTUAL_ABILITY_NONE = 0 -var/const/VIRTUAL_ABILITY_HEAR = 1 -var/const/VIRTUAL_ABILITY_SEE = 2 -var/const/VIRTUAL_ABILITY_ALL = (~VIRTUAL_ABILITY_NONE) +var/global/const/VIRTUAL_ABILITY_NONE = 0 +var/global/const/VIRTUAL_ABILITY_HEAR = 1 +var/global/const/VIRTUAL_ABILITY_SEE = 2 +var/global/const/VIRTUAL_ABILITY_ALL = (~VIRTUAL_ABILITY_NONE) diff --git a/code/modules/mob/observer/virtual/base.dm b/code/modules/mob/observer/virtual/base.dm index 20d439657164..c48973782421 100644 --- a/code/modules/mob/observer/virtual/base.dm +++ b/code/modules/mob/observer/virtual/base.dm @@ -1,4 +1,4 @@ -var/list/all_virtual_listeners = list() +var/global/list/all_virtual_listeners = list() /mob/observer/virtual icon = 'icons/mob/virtual.dmi' @@ -6,14 +6,14 @@ var/list/all_virtual_listeners = list() see_in_dark = SEE_IN_DARK_DEFAULT see_invisible = SEE_INVISIBLE_LIVING sight = SEE_SELF + is_spawnable_type = FALSE // needs a host virtual_mob = null - no_z_overlay = TRUE + z_flags = ZMM_IGNORE var/atom/movable/host var/host_type = /atom/movable var/abilities = VIRTUAL_ABILITY_HEAR|VIRTUAL_ABILITY_SEE - var/list/broadcast_methods var/static/list/overlay_icons @@ -23,7 +23,7 @@ var/list/all_virtual_listeners = list() . = INITIALIZE_HINT_QDEL CRASH("Received an unexpected host type. Expected [host_type], was [log_info_line(host)].") src.host = host - GLOB.moved_event.register(host, src, /atom/movable/proc/move_to_turf_or_null) + events_repository.register(/decl/observ/moved, host, src, TYPE_PROC_REF(/atom/movable, move_to_turf_or_null)) all_virtual_listeners += src @@ -31,22 +31,21 @@ var/list/all_virtual_listeners = list() STOP_PROCESSING(SSmobs, src) /mob/observer/virtual/Destroy() - GLOB.moved_event.unregister(host, src, /atom/movable/proc/move_to_turf_or_null) + events_repository.unregister(/decl/observ/moved, host, src, TYPE_PROC_REF(/atom/movable, move_to_turf_or_null)) all_virtual_listeners -= src host = null return ..() /mob/observer/virtual/on_update_icon() + ..() if(!overlay_icons) overlay_icons = list() for(var/i_state in icon_states(icon)) overlay_icons[i_state] = image(icon = icon, icon_state = i_state) - overlays.Cut() - if(abilities & VIRTUAL_ABILITY_HEAR) - overlays += overlay_icons["hear"] + add_overlay(overlay_icons["hear"]) if(abilities & VIRTUAL_ABILITY_SEE) - overlays += overlay_icons["see"] + add_overlay(overlay_icons["see"]) /*********************** * Virtual Mob Creation * @@ -54,10 +53,8 @@ var/list/all_virtual_listeners = list() /atom/movable var/mob/observer/virtual/virtual_mob -/atom/movable/Initialize() - . = ..() - if(shall_have_virtual_mob()) - virtual_mob = new virtual_mob(get_turf(src), src) +// There is a hook in the common /atom/movable/Initialize() fn. +// The below function was also inlined in that function, as nowhere else used it. -/atom/movable/proc/shall_have_virtual_mob() - return ispath(initial(virtual_mob)) +// /atom/movable/proc/shall_have_virtual_mob() +// return ispath(initial(virtual_mob)) diff --git a/code/modules/mob/observer/virtual/mob.dm b/code/modules/mob/observer/virtual/mob.dm index 8aebf2af8674..020262010663 100644 --- a/code/modules/mob/observer/virtual/mob.dm +++ b/code/modules/mob/observer/virtual/mob.dm @@ -4,16 +4,16 @@ /mob/observer/virtual/mob/Initialize(mapload, var/mob/host) . = ..() - GLOB.sight_set_event.register(host, src, /mob/observer/virtual/mob/proc/sync_sight) - GLOB.see_invisible_set_event.register(host, src, /mob/observer/virtual/mob/proc/sync_sight) - GLOB.see_in_dark_set_event.register(host, src, /mob/observer/virtual/mob/proc/sync_sight) + events_repository.register(/decl/observ/sight_set, host, src, TYPE_PROC_REF(/mob/observer/virtual/mob, sync_sight)) + events_repository.register(/decl/observ/see_invisible_set, host, src, TYPE_PROC_REF(/mob/observer/virtual/mob, sync_sight)) + events_repository.register(/decl/observ/see_in_dark_set, host, src, TYPE_PROC_REF(/mob/observer/virtual/mob, sync_sight)) sync_sight(host) /mob/observer/virtual/mob/Destroy() - GLOB.sight_set_event.unregister(host, src, /mob/observer/virtual/mob/proc/sync_sight) - GLOB.see_invisible_set_event.unregister(host, src, /mob/observer/virtual/mob/proc/sync_sight) - GLOB.see_in_dark_set_event.unregister(host, src, /mob/observer/virtual/mob/proc/sync_sight) + events_repository.unregister(/decl/observ/sight_set, host, src, TYPE_PROC_REF(/mob/observer/virtual/mob, sync_sight)) + events_repository.unregister(/decl/observ/see_invisible_set, host, src, TYPE_PROC_REF(/mob/observer/virtual/mob, sync_sight)) + events_repository.unregister(/decl/observ/see_in_dark_set, host, src, TYPE_PROC_REF(/mob/observer/virtual/mob, sync_sight)) . = ..() /mob/observer/virtual/mob/proc/sync_sight(var/mob/mob_host) diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 46b61dedb311..db8faa6840aa 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -1,3 +1,17 @@ +var/global/list/special_channel_keys = list( + "r" = MESSAGE_MODE_RIGHT, + "l" = MESSAGE_MODE_LEFT, + "i" = MESSAGE_MODE_INTERCOM, + "h" = MESSAGE_MODE_DEPARTMENT, + "+" = MESSAGE_MODE_SPECIAL, //activate radio-specific special functions + "w" = MESSAGE_MODE_WHISPER, + "к" = MESSAGE_MODE_RIGHT, + "д" = MESSAGE_MODE_LEFT, + "ш" = MESSAGE_MODE_INTERCOM, + "р" = MESSAGE_MODE_DEPARTMENT, + "ц" = MESSAGE_MODE_WHISPER +) + /mob/proc/say() return @@ -9,59 +23,38 @@ /mob/verb/say_verb(message as text) set name = "Say" set category = "IC" - remove_typing_indicator() - usr.say(message) + SStyping.set_indicator_state(client, FALSE) + if(!filter_block_message(usr, message)) + usr.say(message) /mob/verb/me_verb(message as text) set name = "Me" set category = "IC" - message = sanitize(message) - - remove_typing_indicator() - if(use_me) - usr.emote("me",usr.emote_type,message) - else - usr.emote(message) + SStyping.set_indicator_state(client, FALSE) + if(!filter_block_message(usr, message)) + message = sanitize(message) + if(can_emote(VISIBLE_MESSAGE, src)) + usr.custom_emote(usr.emote_type, message) + else + usr.emote(message) /mob/proc/say_dead(var/message) communicate(/decl/communication_channel/dsay, client, message) -/mob/proc/say_understands(var/mob/other,var/decl/language/speaking = null) - - if (src.stat == 2) //Dead - return 1 - - //Universal speak makes everything understandable, for obvious reasons. - else if(src.universal_speak || src.universal_understand) - return 1 - - //Languages are handled after. - if (!speaking) - if(!other) - return 1 - if(other.universal_speak) - return 1 - if(isAI(src) && ispAI(other)) - return 1 - if (istype(other, src.type) || istype(src, other.type)) - return 1 - return 0 - - if(speaking.flags & INNATE) - return 1 - - //Language check. - for(var/decl/language/L in src.languages) - if(speaking.name == L.name) - return 1 - - return 0 +/mob/proc/say_understands(mob/speaker, decl/language/speaking) + if(stat == DEAD || universal_speak || universal_understand) + return TRUE + if(!istype(speaker)) + return TRUE + if(speaking) + return speaking.can_be_understood_by(speaker, src) + return (speaker.universal_speak || istype(speaker, type) || istype(src, speaker.type)) /mob/proc/say_quote(var/message, var/decl/language/speaking = null) var/ending = copytext(message, length(message)) if(speaking) - return speaking.get_spoken_verb(ending) + return speaking.get_spoken_verb(src, ending) var/verb = pick(speak_emote) if(verb == "says") //a little bit of a hack, but we can't let speak_emote default to an empty list without breaking other things @@ -71,46 +64,62 @@ verb ="asks" return verb -/mob/proc/get_ear() - // returns an atom representing a location on the map from which this - // mob can hear things - - // should be overloaded for all mobs whose "ear" is separate from their "mob" - - return get_turf(src) - -/mob/proc/say_test(var/text) +/mob/proc/check_speech_punctuation_state(var/text) var/ending = copytext(text, length(text)) if (ending == "?") - return "1" + return "question" else if (ending == "!") - return "2" - return "0" + return "exclamation" + return "statement" //parses the message mode code (e.g. :h, :w) from text, such as that supplied to say. //returns the message mode string or null for no message mode. //standard mode is the mode returned for the special ';' radio code. -/mob/proc/parse_message_mode(var/message, var/standard_mode="headset") - if(length(message) >= 1 && copytext(message,1,2) == get_prefix_key(/decl/prefix/radio_main_channel)) +/mob/proc/parse_message_mode(var/message, var/standard_mode=MESSAGE_MODE_DEFAULT) + if(length(message) <= 0) + return null + message = lowertext(message) + var/initial_char = copytext_char(message,1,2) + if(initial_char == get_common_radio_prefix()) return standard_mode - - if(length(message) >= 2) - var/channel_prefix = copytext(message, 1 ,3) - return department_radio_keys[channel_prefix] - - return null + if(initial_char == get_department_radio_prefix() && length(message) >= 2) + var/channel_prefix = copytext(message, 2, 3) + . = global.special_channel_keys[channel_prefix] || channel_prefix //parses the language code (e.g. :j) from text, such as that supplied to say. //returns the language object only if the code corresponds to a language that src can speak, otherwise null. /mob/proc/parse_language(var/message) - var/prefix = copytext(message,1,2) + + var/prefix = copytext_char(message,1,2) if(length(message) >= 1 && prefix == get_prefix_key(/decl/prefix/audible_emote)) - return decls_repository.get_decl(/decl/language/noise) + return GET_DECL(/decl/language/noise) if(length(message) >= 2 && is_language_prefix(prefix)) - var/language_prefix = lowertext(copytext(message, 2 ,3)) + var/language_prefix = lowertext(copytext_char(message, 2 ,3)) var/decl/language/L = SSlore.get_language_by_key(language_prefix) if (can_speak(L)) return L - return null +/mob/proc/is_silenced() + . = !!get_item_blocking_speech() + +/obj/item/proc/blocks_speech_in_mouth(mob/wearer) + return FALSE + +/mob/proc/get_item_blocking_speech() + // Can't talk with something in your mouth. + var/datum/inventory_slot/mouth_slot = get_inventory_slot_datum(BP_MOUTH) + . = mouth_slot?.get_equipped_item() + if(!.) + var/obj/item/mask = get_equipped_item(slot_wear_mask_str) + if(mask?.blocks_speech_in_mouth(src)) + return mask + +/// Adds punctuation to an emote or speech message automatically. +/mob/proc/handle_autopunctuation(message) + if(!message) + return + var/end_char = copytext_char(trim_right(strip_html_properly(message)), -1) + if(!(end_char in list(".", "?", "!", "-", "~"))) + message += "." + return message \ No newline at end of file diff --git a/code/modules/mob/skills/README_skills.txt b/code/modules/mob/skills/README_skills.txt index cf68dab4a035..d1056f6fbb32 100644 --- a/code/modules/mob/skills/README_skills.txt +++ b/code/modules/mob/skills/README_skills.txt @@ -1,8 +1,8 @@ User's Guide to Skills 1. How does the skill system work, and what are the relevant objects? - Every skill is defined via a /decl/hierarchy/skill/skill_category/skill_name in skill.dm. - These are initialized once and /decl/hierarchy/skill is stored in decls_repository. The actual skill instances are stored in GLOB.skills (this is a list). + Every skill is defined via a /decl/skill/skill_name. + These are initialized once and stored in the decls_repository. Every mob has a variable mob.skillset of type datum/skillset (or a subtype of that). The skillset contains all of the skill information for that mob, along with various procs for obtaining or manipulating it. Using those procs, you will be able to extract skill values from the mob. These should be positive integers between SKILL_MIN and SKILL_MAX. @@ -18,7 +18,7 @@ User's Guide to Skills 3. What do you do with skills? The correct way of obtaining the value of a mob's skill is to use the get_skill_value proc on the mob. It takes a skill path, which should be called via a corresponding SKILL_ define. - Do not try to get the datum instance out of decls_repository; use the type path getter instead or else find it in GLOB.skills. + Do not try to get the datum instance out of decls_repository; use the type path getter instead or else find it in global.skills. The values can be used directly to make skill checks. Additional helper procs may be given to mobs to convert skill values into times, probabilities, or whatever in a reusable way. Currently implemented examples: @@ -29,11 +29,11 @@ User's Guide to Skills 4. What determines what skill options are available in player setup? How can you change them? Skill setup works largely on a per-job basis, with some per-species and branch modifiers. - For each job, a minimum value can be assigned to any skill. To do this, add an entry of /decl/hierarchy/skill/skill_category/skill_name = min_value to that job datums's min_skill variable (this is a list). + For each job, a minimum value can be assigned to any skill. To do this, add an entry of /decl/skill/skill_name = min_value to that job datums's min_skill variable (this is a list). This minimum value is given for free to the player, and does not use up allocation points. For each job, a maximum value can also be assigned. Add a similar entry to the max_skills list. For each job, a base number of free points can be assigned. This is given in the job datum's skill_points variable (should be a number). - Free point bonuses/penalties can be specified, for each species, as a function of a player's selected age. + Free point bonuses/penalties can be specified, for each species, as a function of a player's selected age. This can be done by overwriting species datum's skills_from_age proc, which takes in the age and returns an integer (positive or negative) which will be added to all jobs' available skill points. Free point bonuses/penalties can be specified, for each species, as a function of the job. To do this, add the entry /datum/job/my_job = points_to_add to the species datum's job_skill_buffs variable (this is a list). Then points_to_add (positive or negative) will be added to that job's available skill points. diff --git a/code/modules/mob/skills/antag_skill_setter.dm b/code/modules/mob/skills/antag_skill_setter.dm index 598b1d1c3ce8..8900b318fd79 100644 --- a/code/modules/mob/skills/antag_skill_setter.dm +++ b/code/modules/mob/skills/antag_skill_setter.dm @@ -1,9 +1,12 @@ //A datum that performs antag-related skill selection functions. /datum/antag_skill_setter - var/nm_type //A nano_module with custom ui, if any. - var/list/base_skill_list = list() //Format: list(path = value). - var/default_value = SKILL_DEFAULT //If not in base_skill_list or added in another way, skill value will be this. + /// The path of the nano_module to use with any custom UI handling, if any. If null, uses the base skillset's type. + var/nm_type + /// An associative list of base skill values to provide for free. Keys are skill paths, values are the skill level. + var/list/base_skill_list = list() + /// If not in base_skill_list or added in another way, skill value will be this. + var/default_value = SKILL_DEFAULT /datum/antag_skill_setter/proc/initialize_skills(datum/skillset/skillset) skillset.skill_list = base_skill_list.Copy() diff --git a/code/modules/mob/skills/skill.dm b/code/modules/mob/skills/skill.dm index 0ea0ef9dfedd..9d75a5d591e3 100644 --- a/code/modules/mob/skills/skill.dm +++ b/code/modules/mob/skills/skill.dm @@ -1,22 +1,40 @@ -GLOBAL_LIST_EMPTY(skills) - -/decl/hierarchy/skill - var/ID = "none" // ID of this skill. Needs to be unique. - name = "None" // Name of the skill. This is what the player sees. - hierarchy_type = /decl/hierarchy/skill // Don't mess with this without changing how Initialize works. - var/desc = "Placeholder skill" // Generic description of this skill. +/decl/skill + // UID is required for saving in prefs. + decl_flags = DECL_FLAG_MANDATORY_UID + /// Don't mess with this without changing how Initialize works. + abstract_type = /decl/skill + /// Name of the skill. This is what the player sees. + var/name = "None" + /// Generic description of this skill. + var/desc = "Placeholder skill" + /// Used to compute how expensive the skill is + var/difficulty = SKILL_AVERAGE + /// Makes the skill capped at this value in selection unless overriden at job level. + var/default_max = SKILL_ADEPT + /// The specific default value used for this skill. If null, uses the skillset's default. + var/default_value + /// A list of skill prerequisites, if needed. + var/prerequisites + /// If the skill UID is not found in the savefile, this is the fallback key to use for migrating old savefiles. + var/fallback_key + /// Category this skill belongs to. + var/decl/skill_category/category // Names for different skill values, in order from 1 up. - var/list/levels = list( "Unskilled" = "Unskilled Description", - "Basic" = "Basic Description", - "Trained" = "Trained Description", - "Experienced" = "Experienced Description", - "Master" = "Professional Description") - var/difficulty = SKILL_AVERAGE //Used to compute how expensive the skill is - var/default_max = SKILL_ADEPT //Makes the skill capped at this value in selection unless overriden at job level. - var/prerequisites // A list of skill prerequisites, if needed. - -/decl/hierarchy/skill/proc/get_cost(var/level) + var/list/levels = list( + "Unskilled" = "Unskilled Description", + "Basic" = "Basic Description", + "Trained" = "Trained Description", + "Experienced" = "Experienced Description", + "Master" = "Professional Description" + ) + +/decl/skill/Initialize() + . = ..() + category = GET_DECL(category) + ADD_SORTED(category.children, src, /proc/cmp_skill_asc) + +/decl/skill/proc/get_cost(var/level) switch(level) if(SKILL_BASIC, SKILL_ADEPT) return difficulty @@ -25,60 +43,55 @@ GLOBAL_LIST_EMPTY(skills) else return 0 -/decl/hierarchy/skill/proc/update_special_effects(mob/mob, level) +/decl/skill/proc/update_special_effects(mob/mob, level) + return -/decl/hierarchy/skill/Initialize() - ..() - if(is_hidden_category()) - if(!GLOB.skills.len) - for(var/decl/hierarchy/skill/C in children) - GLOB.skills += C.get_descendents() - else - log_error("Warning: multiple instances of /decl/hierarchy/skill have been created!") +/decl/skill/validate() + . = ..() + if(!category) + . += "Category not set" -/decl/hierarchy/skill/dd_SortValue() - return ID +/decl/skill_category + abstract_type = /decl/skill_category + var/name = "Category" + var/sort_priority = 0 //! Used for sort order in lists/presentation. + var/list/decl/skill/children = list() -/decl/hierarchy/skill/organizational +/decl/skill_category/organizational name = "Organizational" - ID = "1" - difficulty = SKILL_EASY - default_max = SKILL_MAX + sort_priority = 1 -/decl/hierarchy/skill/general +/decl/skill_category/general name = "General" - ID = "2" - difficulty = SKILL_EASY - default_max = SKILL_MAX + sort_priority = 2 -/decl/hierarchy/skill/service - name = "Service" - ID = "service" - difficulty = SKILL_EASY - default_max = SKILL_MAX - -/decl/hierarchy/skill/security +/decl/skill_category/security name = "Security" - ID = "security" + sort_priority = 3 -/decl/hierarchy/skill/engineering +/decl/skill_category/engineering name = "Engineering" - ID = "engineering" + sort_priority = 4 -/decl/hierarchy/skill/research +/decl/skill_category/research name = "Research" - ID = "research" + sort_priority = 5 -/decl/hierarchy/skill/medical +/decl/skill_category/medical name = "Medical" - ID = "medical" - difficulty = SKILL_HARD + sort_priority = 6 + +/decl/skill_category/service + name = "Service" + sort_priority = 7 // ONLY SKILL DEFINITIONS BELOW THIS LINE // Category: Organizational -/decl/hierarchy/skill/organizational/literacy - ID = "literacy" +/decl/skill/literacy name = "Literacy" + category = /decl/skill_category/organizational + uid = "skill_literacy" + fallback_key = "/decl/hierarchy/skill/organizational/literacy" desc = "Your ability to read and write." levels = list( "Unskilled" = "You are completely incapable of reading or writing.", @@ -88,111 +101,155 @@ GLOBAL_LIST_EMPTY(skills) "Master" = "Your mastery of the written word is such that you are able to produce your own textbooks for others to use. You can write a textbook about any skill you have personally trained in." ) -/decl/hierarchy/skill/organizational/finance - ID = "finance" +/decl/skill/finance name = "Finance" + category = /decl/skill_category/organizational + uid = "skill_finance" + fallback_key = "/decl/hierarchy/skill/organizational/finance" desc = "Your ability to manage money and investments." levels = list( - "Unskilled" = "Your understanding of money starts and ends with personal finance. While you are able to perform basic transactions, you get lost in the details, and can find yourself ripped off on occasion.
    - You get some starting money. Its amount increases with level.
    - You can use the verb \"Appraise\" to see the value of different objects.", - "Basic" = "You have some limited understanding of financial transactions, and will generally be able to keep accurate records. You have little experience with investment, and managing large sums of money will likely go poorly for you.", + "Unskilled" = "Your understanding of money starts and ends with personal finance. While you are able to perform basic transactions, you get lost in the details, and can find yourself ripped off on occasion.
    - You get some starting money, increasing with level.", + "Basic" = "You have some limited understanding of financial transactions, and will generally be able to keep accurate records. You have little experience with investment, and managing large sums of money will likely go poorly for you.
    - You can use the verb \"Appraise\" to see the value of different objects.", "Trained" = "You are good at managing accounts, keeping records, and arranging transactions. You have some familiarity with mortgages, insurance, stocks, and bonds, but may be stumped when facing more complicated financial devices.", - "Experienced" = "With your experience, you are familiar with any financial entities you may run across, and are a shrewd judge of value. More often than not, investments you make will pan out well.
    - You can speak and understand Legalese.", + "Experienced" = "With your experience, you are familiar with any financial entities you may run across, and are a shrewd judge of value. More often than not, investments you make will pan out well.
    - You can speak and understand Legalese.", "Master" = "You have an excellent knowledge of finance, will often make brilliant investments, and have an instinctive feel for interstellar economics. Financial instruments are weapons in your hands. You likely have professional experience in the finance industry." ) -/decl/hierarchy/skill/organizational/finance/update_special_effects(mob/mob, level) +/decl/skill/finance/update_special_effects(mob/mob, level) mob.remove_language(/decl/language/legal) if(level >= SKILL_EXPERT) mob.add_language(/decl/language/legal) // Category: General -/decl/hierarchy/skill/general/EVA - ID = "EVA" +/decl/skill/general + abstract_type = /decl/skill/general + difficulty = SKILL_EASY + default_max = SKILL_MAX + +/decl/skill/general/eva name = "Extra-vehicular activity" + category = /decl/skill_category/general + uid = "skill_eva" + fallback_key = "/decl/hierarchy/skill/general/eva" desc = "This skill describes your skill and knowledge of space-suits and working in vacuum." - levels = list( "Unskilled" = "You have basic safety training common to people who work in space: You know how to put on and seal your internals, and you can probably struggle into a space suit if you really need to, though you'll be clumsy at it. You're still prone to mistakes that may leave you trying to breathe vacuum.
    - You can remove hardsuits. Its speed increases with level.
    - You will always get floored when you enter gravity area from space. This chance decreases with level.
    - You are likely to slip. This chance decreases with level.", - "Basic" = "You have had thorough basic training in EVA operations, and are unlikely to make novice mistakes. However, you have little experience working in vacuum.", - "Trained" = "You can comfortably use a space suit and do so regularly in the course of your work. Checking your internals is second nature to you, and you don't panic in an emergency.
    - You can fully operate jetpacks.", - "Experienced" = "You can use all kinds of space suits, including specialized versions. Your years of experience in EVA keep you from being disoriented in space, and you have experience using a jetpack to move around.
    - You cannot slip anymore.", - "Master" = "You are just as much at home in a vacuum as in atmosphere. You probably do your job almost entirely EVA.
    - You cannot get floored anymore.
    - You get bonus speed in zero-G.") - -/decl/hierarchy/skill/general/EVA/mech - ID = "exosuit" + levels = list( + "Unskilled" = "You have basic safety training common to people who work in space: You know how to put on and seal your internals, and you can probably struggle into a space suit if you really need to, though you'll be clumsy at it. You're still prone to mistakes that may leave you trying to breathe vacuum.
    - You can remove hardsuits. Its speed increases with level.
    - You will always get floored when you enter gravity area from space. This chance decreases with level.
    - You are likely to slip. This chance decreases with level.", + "Basic" = "You have had thorough basic training in EVA operations, and are unlikely to make novice mistakes. However, you have little experience working in vacuum.", + "Trained" = "You can comfortably use a space suit and do so regularly in the course of your work. Checking your internals is second nature to you, and you don't panic in an emergency.
    - You can fully operate jetpacks.", + "Experienced" = "You can use all kinds of space suits, including specialized versions. Your years of experience in EVA keep you from being disoriented in space, and you have experience using a jetpack to move around.
    - You cannot slip anymore.", + "Master" = "You are just as much at home in a vacuum as in atmosphere. You probably do your job almost entirely EVA.
    - You cannot get floored anymore.
    - You get bonus speed in zero-G." + ) + +/decl/skill/general/mech name = "Exosuit Operation" + category = /decl/skill_category/general + uid = "skill_exosuit" + fallback_key = "/decl/hierarchy/skill/general/eva/mech" desc = "Allows you to operate exosuits well." - levels = list("Untrained" = "You are unfamiliar with exosuit controls, and if you attempt to use them you are liable to make mistakes.", - "Trained" = "You are proficient in exosuit operation and safety, and can use them without penalties.") + levels = list( + "Untrained" = "You are unfamiliar with exosuit controls, and if you attempt to use them you are liable to make mistakes.", + "Trained" = "You are proficient in exosuit operation and safety, and can use them without penalties." + ) prerequisites = list(SKILL_EVA = SKILL_ADEPT) default_max = SKILL_BASIC difficulty = SKILL_AVERAGE -/decl/hierarchy/skill/general/pilot - ID = "pilot" +/decl/skill/general/pilot name = "Piloting" + category = /decl/skill_category/general + uid = "skill_pilot" + fallback_key = "/decl/hierarchy/skill/general/pilot" desc = "Describes your experience and understanding of piloting spacecraft, from small and short-range pods to corvette sized vessels." - levels = list( "Unskilled" = "You know what a spacecraft is, and you might have an abstract understanding of the differences between various ships. If your department is involved in the use of spacecraft, you know roughly what their capabilities are. You might be able to fly a spacecraft in a videogame. If you were to take the Helm of a smaller vessel, you might be able to move it with proper guidance.
    - Travel time between tranisition decreases with level.
    - You can fly ships but their movement might be randomized.
    - The speed of your ship hitting carps will increase with level.", - "Basic" = "You can pilot a small, short-range craft safely, but larger ships are out of your area of expertise. You are by no means an expert, and probably don't have much training. Skills of this level are typical for deck crew.
    - You can operate small shuttlecraft without error.
    - You can completely avoid meteors on slow speed while using tiny shuttlecrafts such as the GUP.", - "Trained" = "You are a trained pilot, and can safely operate anything from a small craft to a corvette. You can spend extended periods of time piloting a spacecraft, and you're versed in the abilities of different ships, and what makes them function. You can do basic maintenance on smaller vessels, and perform most basic maneuvers. You can use armed spacecraft. You can make basic calculations relating to piloting. Skills of this level are typical for newer pilots. You have probably received formal piloting training.
    - You can operate large ships without error.
    - You can completely avoid meteors on slow speed using any shuttlecrafts.", - "Experienced" = "You are an experienced pilot, and can safely take the helm of many types of craft. You could probably live in a spacecraft, and you're very well versed in essentially everything related to space-faring vessels. Not only can you fly a ship, but you can perform difficult maneuvers, and make most calculations related to piloting a spacecraft. You can maintain a ship. Skills of this level are typical for very experienced pilots. You have received formal piloting training.
    - You can completely avoid meteors on normal speed while using tiny shuttlecrafts.", - "Master" = "Not only are you an exceptional pilot, but you have mastered peripheral functions such as stellar navigation and FTL jump plotting. You have experience performing complex maneuvers, managing squadrons of small craft, and operating in hostile environments.
    - You can completely avoid meteors on normal speed using any shuttlecrafts.
    - Less meteors will hit the ship while passing through meteor fields.
    - You can manually land shuttles on exoplanets.") + levels = list( + "Unskilled" = "You know what a spacecraft is, and you might have an abstract understanding of the differences between various ships. If your department is involved in the use of spacecraft, you know roughly what their capabilities are. You might be able to fly a spacecraft in a videogame. If you were to take the Helm of a smaller vessel, you might be able to move it with proper guidance.
    - Travel time between tranisition decreases with level.
    - You can fly ships but their movement might be randomized.
    - The speed of your ship hitting carps will increase with level.", + "Basic" = "You can pilot a small, short-range craft safely, but larger ships are out of your area of expertise. You are by no means an expert, and probably don't have much training. Skills of this level are typical for deck crew.
    - You can operate small shuttlecraft without error.
    - You can completely avoid meteors on slow speed while using tiny shuttlecrafts such as the GUP.", + "Trained" = "You are a trained pilot, and can safely operate anything from a small craft to a corvette. You can spend extended periods of time piloting a spacecraft, and you're versed in the abilities of different ships, and what makes them function. You can do basic maintenance on smaller vessels, and perform most basic maneuvers. You can use armed spacecraft. You can make basic calculations relating to piloting. Skills of this level are typical for newer pilots. You have probably received formal piloting training.
    - You can operate large ships without error.
    - You can mostly avoid meteors on slow speed using any shuttlecrafts.", + "Experienced" = "You are an experienced pilot, and can safely take the helm of many types of craft. You could probably live in a spacecraft, and you're very well versed in essentially everything related to space-faring vessels. Not only can you fly a ship, but you can perform difficult maneuvers, and make most calculations related to piloting a spacecraft. You can maintain a ship. Skills of this level are typical for very experienced pilots. You have received formal piloting training.
    - You can somewhat avoid meteors on normal speed while using tiny shuttlecrafts.", + "Master" = "Not only are you an exceptional pilot, but you have mastered peripheral functions such as stellar navigation and FTL jump plotting. You have experience performing complex maneuvers, managing squadrons of small craft, and operating in hostile environments.
    - You can mostly avoid meteors on normal speed using any shuttlecrafts.
    - Less meteors will hit the ship while passing through meteor fields.
    - You can manually land shuttles on exoplanets." + ) difficulty = SKILL_AVERAGE default_max = SKILL_ADEPT -/decl/hierarchy/skill/general/hauling - ID = "hauling" +/decl/skill/general/hauling name = "Athletics" + category = /decl/skill_category/general + uid = "skill_hauling" + fallback_key = "/decl/hierarchy/skill/general/hauling" desc = "Your ability to perform tasks requiring great strength, dexterity, or endurance." - levels = list( "Unskilled" = "You are not used to manual labor, tire easily, and are likely not in great shape. Extended heavy labor may be dangerous for you.
    - You can pull objects but start to generate Lactate after tiring out. Your strength increases with level.
    - You can throw objects. Their speed, thrown distance, and force increases with level.
    - You can sprint, the stamina consumption rate is lowered with each level.
    - You can leap by holding Ctrl and clicking on a distant target with grab intent, leap range is increased and chances of falling over are decreased with each level.", - "Basic" = "You have some familiarity with manual labor, and are in reasonable physical shape. Tasks requiring great dexterity or strength may still elude you.
    - You can throw \"huge\" items or normal-sized mobs without getting weakened.", - "Trained" = "You have sufficient strength and dexterity for even very strenuous tasks, and can work for a long time without tiring.", - "Experienced" = "You have experience with heavy work in trying physical conditions, and are in excellent shape. You visit the gym frequently.", - "Master" = "In addition to your excellent strength and endurance, you have a lot of experience with the specific physical demands of your job. You may have competitive experience with some form of athletics.") - -/decl/hierarchy/skill/general/computer - ID = "computer" + levels = list( + "Unskilled" = "You are not used to manual labor, tire easily, and are likely not in great shape. Extended heavy labor may be dangerous for you.
    - You can pull objects but start to generate Lactate after tiring out. Your strength increases with level.
    - You can throw objects. Their speed, thrown distance, and force increases with level.
    - You can sprint, the stamina consumption rate is lowered with each level.
    - You can leap by holding Ctrl and clicking on a distant target with grab intent, leap range is increased and chances of falling over are decreased with each level.", + "Basic" = "You have some familiarity with manual labor, and are in reasonable physical shape. Tasks requiring great dexterity or strength may still elude you.
    - You can throw \"huge\" items or normal-sized mobs without getting weakened.", + "Trained" = "You have sufficient strength and dexterity for even very strenuous tasks, and can work for a long time without tiring.", + "Experienced" = "You have experience with heavy work in trying physical conditions, and are in excellent shape. You visit the gym frequently.", + "Master" = "In addition to your excellent strength and endurance, you have a lot of experience with the specific physical demands of your job. You may have competitive experience with some form of athletics." + ) + +/decl/skill/general/computer name = "Information Technology" + category = /decl/skill_category/general + uid = "skill_computer" + fallback_key = "/decl/hierarchy/skill/general/computer" desc = "Describes your understanding of computers, software and communication. Not a requirement for using computers, but definitely helps. Used in telecommunications and programming of computers and AIs." - levels = list( "Unskilled" = "You know how to use the computers and communication devices that you grew up with. You can use a computer console, a handheld or wall-mounted radio, and your headset, as well as your PDA. You know what an AI is, but you may see them as either \"people made of silicon\" or \"only machines\"; you know they have to obey their laws, but you don't know much about how or why they work.", - "Basic" = "You know the basics of programming, but you're not very good at it and couldn't do it professionally. You have a pretty good idea of what makes AIs tick. You understand how information is stored in a computer, and you can fix simple computer problems. You're computer-literate, but you still make mistakes. If you tried to subvert the AI, you might make mistakes in wording your new laws.
    - The antagonist access decryption program has a chance to avoid tripping alarms and working more effectively. This increases with level.", - "Trained" = "At this level, you're probably working with computers on a daily basis. You understand and can repair the telecommunications network. Your understanding of AI programming and psychology lets you fix problems with the AIs or cyborgs--or create problems, if you so desire. You can program computers and AIs and change their laws effectively.
    - You can fully operate the Network Monitor, E-mail Administration, and AI Management Programs.", - "Experienced" = "You have years of experience with computer networks, AI systems, telecommunications, and sysadmin tasks. You know the systems used on a daily basis intimately, and can diagnose complex problems.
    - The antagonist dos program gives extra fake attacking nodes to the system log.
    - You can use the command line on modular computers (type \"man\" for a list).", - "Master" = "People are probably starting to wonder whether you might be a computer yourself. Computer code is your first language; you relate to AIs as easily as (probably more easily than) organics. You could build a telecommunications network from the ground up.") + levels = list( + "Unskilled" = "You know how to use the computers and communication devices that you grew up with. You can use a computer console, a handheld or wall-mounted radio, and your headset, as well as your PDA. You know what an AI is, but you may see them as either \"people made of silicon\" or \"only machines\"; you know they have to obey their laws, but you don't know much about how or why they work.", + "Basic" = "You know the basics of programming, but you're not very good at it and couldn't do it professionally. You have a pretty good idea of what makes AIs tick. You understand how information is stored in a computer, and you can fix simple computer problems. You're computer-literate, but you still make mistakes. If you tried to subvert the AI, you might make mistakes in wording your new laws.
    - The antagonist access decryption program has a chance to avoid tripping alarms and working more effectively. This increases with level.", + "Trained" = "At this level, you're probably working with computers on a daily basis. You understand and can repair the telecommunications network. Your understanding of AI programming and psychology lets you fix problems with the AIs or cyborgs--or create problems, if you so desire. You can program computers and AIs and change their laws effectively.
    - You can fully operate the Network Monitor, E-mail Administration, and AI Management Programs.", + "Experienced" = "You have years of experience with computer networks, AI systems, telecommunications, and sysadmin tasks. You know the systems used on a daily basis intimately, and can diagnose complex problems.
    - The antagonist dos program gives extra fake attacking nodes to the system log.
    - You can use the command line on modular computers (type \"man\" for a list).", + "Master" = "People are probably starting to wonder whether you might be a computer yourself. Computer code is your first language; you relate to AIs as easily as (probably more easily than) organics. You could build a telecommunications network from the ground up." + ) // Category: Service +/decl/skill/service + abstract_type = /decl/skill/service + category = /decl/skill_category/service + difficulty = SKILL_EASY + default_max = SKILL_MAX -/decl/hierarchy/skill/service/botany - ID = "botany" +/decl/skill/service/botany name = "Botany" - desc = "Describes how good a character is at growing and maintaining plants." - levels = list( "Unskilled" = "You know next to nothing about plants. While you can attempt to plant, weed, or harvest, you are just as likely to kill the plant instead.", - "Basic" = "You've done some gardening. You can water, weed, fertilize, plant, and harvest, and you can recognize and deal with pests. You may be a hobby gardener.
    - You can safely plant and weed normal plants.
    - You can tell weeds and pests apart from each other.", - "Trained" = "You are proficient at botany, and can grow plants for food or oxygen production. Your plants will generally survive and prosper. You know the basics of manipulating plant genes.
    - You can safely plant and weed exotic plants.
    - You can operate xenoflora machines. The sample's degradation decreases with skill level.", - "Experienced" = "You're a botanist or farmer, capable of running a facility's hydroponics farms or doing botanical research. You are adept at creating custom hybrids and modified strains.", - "Master" = "You're a specialized botanist. You can care for even the most exotic, fragile, or dangerous plants. You can use gene manipulation machinery with precision, and are often able to avoid the degradation of samples.") - -/decl/hierarchy/skill/service/cooking - ID = "cooking" + category = /decl/skill_category/service + uid = "skill_botany" + fallback_key = "/decl/hierarchy/skill/service/botany" + desc = "Describes how good you are at growing and maintaining plants." + levels = list( + "Unskilled" = "You know next to nothing about plants. While you can attempt to plant, weed, or harvest, you are just as likely to kill the plant instead.", + "Basic" = "You've done some gardening. You can water, weed, fertilize, plant, and harvest, and you can recognize and deal with pests. You may be a hobby gardener.
    - You can safely plant and weed normal plants.
    - You can tell weeds and pests apart from each other.", + "Trained" = "You are proficient at botany, and can grow plants for food or oxygen production. Your plants will generally survive and prosper. You know the basics of manipulating plant genes.
    - You can safely plant and weed exotic plants.
    - You can operate xenoflora machines. The sample's degradation decreases with skill level.", + "Experienced" = "You're a botanist or farmer, capable of running a facility's hydroponics farms or doing botanical research. You are adept at creating custom hybrids and modified strains.", + "Master" = "You're a specialized botanist. You can care for even the most exotic, fragile, or dangerous plants. You can use gene manipulation machinery with precision, and are often able to avoid the degradation of samples." + ) + +/decl/skill/service/cooking name = "Cooking" - desc = "Describes a character's skill at preparing meals and other consumable goods. This includes mixing alcoholic beverages." - levels = list( "Unskilled" = "You barely know anything about cooking, and stick to vending machines when you can. The microwave is a device of black magic to you, and you avoid it when possible.", - "Basic" = "You can make simple meals and do the cooking for your family. Things like spaghetti, grilled cheese, or simple mixed drinks are your usual fare.
    - You can safely use the blender.", - "Trained" = "You can make most meals while following instructions, and they generally turn out well. You have some experience with hosting, catering, and/or bartending.
    - You can fully operate the drink dispensers.", - "Experienced" = "You can cook professionally, keeping an entire crew fed easily. Your food is tasty and you don't have a problem with tricky or complicated dishes. You can be depended on to make just about any commonly-served drink.", - "Master" = "Not only are you good at cooking and mixing drinks, but you can manage a kitchen staff and cater for special events. You can safely prepare exotic foods and drinks that would be poisonous if prepared incorrectly.") + category = /decl/skill_category/service + uid = "skill_cooking" + fallback_key = "/decl/hierarchy/skill/service/cooking" + desc = "Describes your skill at preparing meals and other consumable goods. This includes mixing alcoholic beverages." + levels = list( + "Unskilled" = "You barely know anything about cooking, and stick to vending machines when you can. The microwave is a device of black magic to you, and you avoid it when possible.", + "Basic" = "You can make simple meals and do the cooking for your family. Things like spaghetti, grilled cheese, or simple mixed drinks are your usual fare.
    - You can safely use the blender.", + "Trained" = "You can make most meals while following instructions, and they generally turn out well. You have some experience with hosting, catering, and/or bartending.
    - You can fully operate the drink dispensers.", + "Experienced" = "You can cook professionally, keeping an entire crew fed easily. Your food is tasty and you don't have a problem with tricky or complicated dishes. You can be depended on to make just about any commonly-served drink.", + "Master" = "Not only are you good at cooking and mixing drinks, but you can manage a kitchen staff and cater for special events. You can safely prepare exotic foods and drinks that would be poisonous if prepared incorrectly." + ) // Category: Security -/decl/hierarchy/skill/security/combat - ID = "combat" +/decl/skill/combat name = "Close Combat" + category = /decl/skill_category/security + uid = "skill_combat" + fallback_key = "/decl/hierarchy/skill/security/combat" desc = "This skill describes your training in hand-to-hand combat or melee weapon usage. While expertise in this area is rare in the era of firearms, experts still exist among athletes." - levels = list( "Unskilled" = "You can throw a punch or a kick, but it'll knock you off-balance. You're inexperienced and have probably never been in a serious hand-to-hand fight. In a fight, you might panic and run, grab whatever's nearby and blindly strike out with it, or (if the other guy is just as much of a beginner as you are) make a fool out of yourself.
    - You can disarm, grab, and hit. Their success chance depends on the fighters' skill difference.
    - The chance of falling over when tackled is reduced with level.", - "Basic" = "You either have some experience with fistfights, or you have some training in a martial art. You can handle yourself if you really have to, and if you're a security officer, can handle a stun baton at least well enough to get the handcuffs onto a criminal.", - "Trained" = "You have had close-combat training, and can easily defeat unskilled opponents. Close combat may not be your specialty, and you don't engage in it more than needed, but you know how to handle yourself in a fight.
    - You can parry with weapons. This increases with level.
    - You can do grab maneuvers (pinning, dislocating).
    - You can grab targets when leaping at them and not fall over, if your species is able to do so.", - "Experienced" = "You're good at hand-to-hand combat. You've trained explicitly in a martial art or as a close combatant as part of a military or police unit. You can use weaponry competently and you can think strategically and quickly in a melee. You're in good shape and you spend time training.", - "Master" = "You specialize in hand-to-hand combat. You're well-trained in a practical martial art, and in good shape. You spend a lot of time practicing. You can take on just about anyone, use just about any weapon, and usually come out on top. You may be a professional athlete or special forces member.") + levels = list( + "Unskilled" = "You can throw a punch or a kick, but it'll knock you off-balance. You're inexperienced and have probably never been in a serious hand-to-hand fight. In a fight, you might panic and run, grab whatever's nearby and blindly strike out with it, or (if the other guy is just as much of a beginner as you are) make a fool out of yourself.
    - You can disarm, grab, and hit. Their success chance depends on the fighters' skill difference.
    - The chance of falling over when tackled is reduced with level.", + "Basic" = "You either have some experience with fistfights, or you have some training in a martial art. You can handle yourself if you really have to, and if you're a security officer, can handle a stun baton at least well enough to get the handcuffs onto a criminal.", + "Trained" = "You have had close-combat training, and can easily defeat unskilled opponents. Close combat may not be your specialty, and you don't engage in it more than needed, but you know how to handle yourself in a fight.
    - You can parry with weapons. This increases with level.
    - You can do grab maneuvers (pinning, dislocating).
    - You can grab targets when leaping at them and not fall over, if your species is able to do so.", + "Experienced" = "You're good at hand-to-hand combat. You've trained explicitly in a martial art or as a close combatant as part of a military or police unit. You can use weaponry competently and you can think strategically and quickly in a melee. You're in good shape and you spend time training.", + "Master" = "You specialize in hand-to-hand combat. You're well-trained in a practical martial art, and in good shape. You spend a lot of time practicing. You can take on just about anyone, use just about any weapon, and usually come out on top. You may be a professional athlete or special forces member." + ) -/decl/hierarchy/skill/security/combat/get_cost(var/level) +/decl/skill/combat/get_cost(var/level) switch(level) if(SKILL_BASIC) return difficulty @@ -203,17 +260,21 @@ GLOBAL_LIST_EMPTY(skills) else return 0 -/decl/hierarchy/skill/security/weapons - ID = "weapons" +/decl/skill/weapons name = "Weapons Expertise" + category = /decl/skill_category/security + uid = "skill_weapons" + fallback_key = "/decl/hierarchy/skill/security/weapons" desc = "This skill describes your expertise with and knowledge of weapons. A low level in this skill implies knowledge of simple weapons, for example flashes. A high level in this skill implies knowledge of complex weapons, such as unconfigured grenades, riot shields, pulse rifles or bombs. A low-medium level in this skill is typical for security officers, a high level of this skill is typical for special agents and soldiers." - levels = list( "Unskilled" = "You know how to recognize a weapon when you see one. You can point a gun and shoot it, though results vary wildly. You might forget the safety, you can't control burst recoil well, and you don't have trained reflexes for gun fighting.
    - You might fire your weapon randomly.", - "Basic" = "You know how to handle weapons safely, and you're comfortable using simple weapons. Your aim is decent and you can usually be trusted not to do anything stupid with a weapon you are familiar with, but your training isn't automatic yet and your performance will degrade in high-stress situations.
    - You can use firearms. Their accuracy and spread depend on your skill level.", - "Trained" = "You have had extensive weapons training, or have used weapons in combat. Your aim is better now. You are familiar with most types of weapons and can use them in a pinch. You have an understanding of tactics, and can be trusted to stay calm under fire. You may have military or police experience and you probably carry a weapon on the job.", - "Experienced" = "You've used firearms and other ranged weapons in high-stress situations, and your skills have become automatic. Your aim is good.", - "Master" = "You are an exceptional shot with a variety of weapons, from simple to exotic. You use a weapon as naturally as though it were a part of your own body. You may be a sniper or special forces operator of some kind.
    - You get extra accuracy for sniper rifles.
    - You automatically eject shells from bolt-action firearms.") + levels = list( + "Unskilled" = "You know how to recognize a weapon when you see one. You can point a gun and shoot it, though results vary wildly. You might forget the safety, you can't control burst recoil well, and you don't have trained reflexes for gun fighting.
    - You might fire your weapon randomly.", + "Basic" = "You know how to handle weapons safely, and you're comfortable using simple weapons. Your aim is decent and you can usually be trusted not to do anything stupid with a weapon you are familiar with, but your training isn't automatic yet and your performance will degrade in high-stress situations.
    - You can use firearms. Their accuracy and spread depend on your skill level.", + "Trained" = "You have had extensive weapons training, or have used weapons in combat. Your aim is better now. You are familiar with most types of weapons and can use them in a pinch. You have an understanding of tactics, and can be trusted to stay calm under fire. You may have military or police experience and you probably carry a weapon on the job.", + "Experienced" = "You've used firearms and other ranged weapons in high-stress situations, and your skills have become automatic. Your aim is good.", + "Master" = "You are an exceptional shot with a variety of weapons, from simple to exotic. You use a weapon as naturally as though it were a part of your own body. You may be a sniper or special forces operator of some kind.
    - You get extra accuracy for sniper rifles.
    - You automatically eject shells from bolt-action firearms." + ) -/decl/hierarchy/skill/security/weapons/get_cost(var/level) +/decl/skill/weapons/get_cost(var/level) switch(level) if(SKILL_BASIC) return difficulty @@ -224,18 +285,22 @@ GLOBAL_LIST_EMPTY(skills) else return 0 -/decl/hierarchy/skill/security/forensics - ID = "forensics" +/decl/skill/forensics name = "Forensics" + category = /decl/skill_category/security + uid = "skill_forensics" + fallback_key = "/decl/hierarchy/skill/security/forensics" desc = "Describes your skill at performing forensic examinations and identifying vital evidence. Does not cover analytical abilities, and as such isn't the only indicator for your investigation skill. Note that in order to perform autopsy, the surgery skill is also required." - levels = list( "Unskilled" = "You know that detectives solve crimes. You may have some idea that it's bad to contaminate a crime scene, but you're not too clear on the details.", - "Basic" = "You know how to avoid contaminating a crime scene. You know how to bag the evidence without contaminating it unduly.", - "Trained" = "You are trained in collecting forensic evidence - fibers, fingerprints, the works. You know how autopsies are done, and might've assisted performing one.
    - You can more easily detect fingerprints.
    - You no longer contaminate evidence.", - "Experienced" = "You're a pathologist, or detective. You've seen your share of bizarre cases, and spent a lot of time putting pieces of forensic puzzle together, so you're faster now.
    - You can notice additional details upon examining, such as fibers, partial prints, and gunshot residue.", - "Master" = "You're a big name in forensic science. You might be an investigator who cracked a famous case, or you published papers on new methods of forensics. Either way, if there's a forensic trail, you will find it, period.
    - You can notice traces of wiped off blood.") - + levels = list( + "Unskilled" = "You know that detectives solve crimes. You may have some idea that it's bad to contaminate a crime scene, but you're not too clear on the details.", + "Basic" = "You know how to avoid contaminating a crime scene. You know how to bag the evidence without contaminating it unduly.", + "Trained" = "You are trained in collecting forensic evidence - fibers, fingerprints, the works. You know how autopsies are done, and might've assisted performing one.
    - You can more easily detect fingerprints.
    - You no longer contaminate evidence.", + "Experienced" = "You're a pathologist, or detective. You've seen your share of bizarre cases, and spent a lot of time putting pieces of forensic puzzle together, so you're faster now.
    - You can notice additional details upon examining, such as fibers, partial prints, and gunshot residue.", + "Master" = "You're a big name in forensic science. You might be an investigator who cracked a famous case, or you published papers on new methods of forensics. Either way, if there's a forensic trail, you will find it, period.
    - You can notice traces of wiped off blood." + ) + default_value = SKILL_NONE // defaulting this to SKILL_DEFAULT leads to a bunch of annoying examine messages -/decl/hierarchy/skill/security/forensics/get_cost(var/level) +/decl/skill/forensics/get_cost(var/level) switch(level) if(SKILL_BASIC, SKILL_ADEPT, SKILL_EXPERT) return difficulty * 2 @@ -245,100 +310,136 @@ GLOBAL_LIST_EMPTY(skills) return 0 // Category: Engineering - -/decl/hierarchy/skill/engineering/construction - ID = "construction" +/decl/skill/construction name = "Construction" + category = /decl/skill_category/engineering + uid = "skill_construction" + fallback_key = "/decl/hierarchy/skill/engineering/construction" desc = "Your ability to construct various buildings, such as walls, floors, tables and so on. Note that constructing devices such as APCs additionally requires the Electronics skill. A low level of this skill is typical for janitors, a high level of this skill is typical for engineers." //TODO: generalize material lists based on mat properties. - levels = list( "Unskilled" = "You can break furniture, disassemble chairs and tables, bash your way through a window, open a crate, or pry open an unpowered airlock. You can recognize and use basic hand tools and inflatable barriers, though not very well.
    - You can attempt to construct items above your skill level, success chance increases with level.", - "Basic" = "You can dismantle or build a wall or window, redecorate a room, and replace floor tiles and carpeting. You can safely use a welder without burning your eyes, and using hand tools is second nature to you.
    - You can construct items from Steel, Wood and Plastic.", - "Trained" = "You can build, repair, or dismantle most things, but will occasionally make mistakes and have things not come out the way you expected.
    - You can construct items from Bronze, Gold, Osmium, Plasteel, Platinum, Reinforced Glass, Sandstone, Silver, Deuterium, Metallic Hydrogen, Borosilicate Glass, Tritium, and Uranium.
    - You can construct furnitures.
    - You can construct simple objects such as light fixtures, crude weapons, and wall-mounted frames.
    - You can safely use the plasmacutter to deconstruct structures.", - "Experienced" = "You know how to seal a breach, rebuild broken piping, and repair major damage. You know the basics of structural engineering.
    - You can construct items from Osmium-Carbide Plasteel, Titanium, Diamond and make complex objects such as machine and weapon frames.", - "Master" = "You are a construction worker or engineer. You could pretty much rebuild the installation or ship from the ground up, given supplies, and you're efficient and skilled at repairing damage.") + levels = list( + "Unskilled" = "You can break furniture, disassemble chairs and tables, bash your way through a window, open a crate, or pry open an unpowered airlock. You can recognize and use basic hand tools and inflatable barriers, though not very well.
    - You can attempt to construct items above your skill level, success chance increases with level.", + "Basic" = "You can dismantle or build a wall or window, redecorate a room, and replace floor tiles and carpeting. You can safely use a welder without burning your eyes, and using hand tools is second nature to you.
    - You can construct items from Steel, Wood and Plastic.", + "Trained" = "You can build, repair, or dismantle most things, but will occasionally make mistakes and have things not come out the way you expected.
    - You can construct items from Bronze, Gold, Osmium, Plasteel, Platinum, Reinforced Glass, Sandstone, Silver, Deuterium, Metallic Hydrogen, Borosilicate Glass, Tritium, and Uranium.
    - You can construct furnitures.
    - You can construct simple objects such as light fixtures, crude weapons, and wall-mounted frames.
    - You can safely use the plasmacutter to deconstruct structures.", + "Experienced" = "You know how to seal a breach, rebuild broken piping, and repair major damage. You know the basics of structural engineering.
    - You can construct items from Osmium-Carbide Plasteel, Titanium, Diamond and make complex objects such as machine and weapon frames.", + "Master" = "You are a construction worker or engineer. You could pretty much rebuild the installation or ship from the ground up, given supplies, and you're efficient and skilled at repairing damage." + ) difficulty = SKILL_EASY -/decl/hierarchy/skill/engineering/electrical - ID = "electrical" +/decl/skill/electrical name = "Electrical Engineering" - desc = "This skill describes your knowledge of electronics and the underlying physics. A low level of this skill implies you know how to lay out wiring and configure powernets, a high level of this skill is required for working complex electronic devices such as circuits or bots." - levels = list( "Unskilled" = "You know that electrical wires are dangerous and getting shocked is bad; you can see and report electrical malfunctions such as broken wires or malfunctioning APCs. You can change a light bulb, and you know how to replace a battery or charge up the equipment you normally use.
    - Every time you open the hacking panel, wires are randomized.
    - Every time you pulse a wire, there is a chance you pulse a different one.
    - Every time you cut a wire, there is a chance you cut/mend extra ones.
    - You can misconnect remote signalling devices.", - "Basic" = "You can do basic wiring; you can lay cable for solars or the engine. You can repair broken wiring and build simple electrical equipment like light fixtures or APCs. You know the basics of circuits and understand how to protect yourself from electrical shock. You can probably hack a vending machine.
    - Every time you open the hacking panel, some wires might be duplicated.", - "Trained" = "You can repair and build electrical equipment and do so on a regular basis. You can troubleshoot an electrical system and monitor the installation power grid. You can probably hack an airlock.
    - You can safely hack machines.", - "Experienced" = "You can repair, build, and diagnose any electrical devices with ease. You know your way around APCs, SMES units, and monitoring software, and take apart or hack most objects.
    - You can safely place remote signaling devices.
    - You can examine one or two wires on the hacking panel.", - "Master" = "You are an electrical engineer or the equivalent. You can design, upgrade, and modify electrical equipment and you are good at maximizing the efficiency of your power network. You can hack anything on the installation you can deal with power outages and electrical problems easily and efficiently.
    - You can examine most wires on the hacking panel.") - -/decl/hierarchy/skill/engineering/atmos - ID = "atmos" + category = /decl/skill_category/engineering + uid = "skill_electrical" + fallback_key = "/decl/hierarchy/skill/engineering/electrical" + desc = "This skill describes your knowledge of electronics and the underlying physics. A low level of this skill implies you know how to lay out wiring and configure power networks, a high level of this skill is required for working complex electronic devices such as circuits or bots." + levels = list( + "Unskilled" = "You know that electrical wires are dangerous and getting shocked is bad; you can see and report electrical malfunctions such as broken wires or malfunctioning APCs. You can change a light bulb, and you know how to replace a battery or charge up the equipment you normally use.
    - Every time you open the hacking panel, wires are randomized.
    - Every time you pulse a wire, there is a chance you pulse a different one.
    - Every time you cut a wire, there is a chance you cut/mend extra ones.
    - You can misconnect remote signalling devices.", + "Basic" = "You can do basic wiring; you can lay cable for solars or the engine. You can repair broken wiring and build simple electrical equipment like light fixtures or APCs. You know the basics of circuits and understand how to protect yourself from electrical shock. You can probably hack a vending machine.
    - Every time you open the hacking panel, some wires might be duplicated.", + "Trained" = "You can repair and build electrical equipment and do so on a regular basis. You can troubleshoot an electrical system and monitor the installation power grid. You can probably hack an airlock.
    - You can safely hack machines.", + "Experienced" = "You can repair, build, and diagnose any electrical devices with ease. You know your way around APCs, SMES units, and monitoring software, and take apart or hack most objects.
    - You can safely place remote signaling devices.
    - You can examine one or two wires on the hacking panel.", + "Master" = "You are an electrical engineer or the equivalent. You can design, upgrade, and modify electrical equipment and you are good at maximizing the efficiency of your power network. You can hack anything on the installation you can deal with power outages and electrical problems easily and efficiently.
    - You can examine most wires on the hacking panel." + ) + +/decl/skill/atmos name = "Atmospherics" + category = /decl/skill_category/engineering + uid = "skill_atmos" + fallback_key = "/decl/hierarchy/skill/engineering/atmos" desc = "Describes your knowledge of piping, air distribution and gas dynamics." - levels = list( "Unskilled" = "You know that the air monitors flash orange when the air is bad and red when it's deadly. You know that a flashing fire door means danger on the other side. You know that some gases are poisonous, that pressure has to be kept in a safe range, and that most creatures need oxygen to live. You can use a fire extinguisher or deploy an inflatable barrier.
    - RPD may give out random pipes, chance decreases with levels.
    - You cannot recompress pipes with the RPD.", - "Basic" = "You know how to read an air monitor, how to use an air pump, how to analyze the atmosphere in a space, and how to help seal a breach. You can lay piping and work with gas tanks and canisters. If you work with the engine, you can set up the cooling system. You can use a fire extinguisher easily and place inflatable barriers so that they allow convenient access and airtight breach containment.
    - You can recompress pipes with the RPD.", - "Trained" = "You can run the atmospherics system. You know how to monitor the air quality across the installation detect problems, and fix them. You're trained in dealing with fires, breaches, and gas leaks, and may have exosuit or fire gear training.
    - You can use the RPD safely.", - "Experienced" = "Your atmospherics experience lets you find, diagnose, and fix breaches efficiently. You can manage complex atmospherics systems without fear of making mistakes, and are proficient with all monitoring and pumping equipment at your disposal.
    - You can dispense a larger selection of pipes from the RPD.", - "Master" = "You are an atmospherics specialist. You monitor, modify, and optimize the installation atmospherics system, and you can quickly and easily deal with emergencies. You can modify atmospherics systems to do pretty much whatever you want them to. You can easily handle a fire or breach, and are proficient at securing an area and rescuing civilians, but you're equally likely to have simply prevented it from happening in the first place.") - -/decl/hierarchy/skill/engineering/engines - ID = "engines" + levels = list( + "Unskilled" = "You know that the air monitors flash orange when the air is bad and red when it's deadly. You know that a flashing fire door means danger on the other side. You know that some gases are poisonous, that pressure has to be kept in a safe range, and that most creatures need oxygen to live. You can use a fire extinguisher or deploy an inflatable barrier.
    - RPD may give out random pipes, chance decreases with levels.
    - You cannot recompress pipes with the RPD.", + "Basic" = "You know how to read an air monitor, how to use an air pump, how to analyze the atmosphere in a space, and how to help seal a breach. You can lay piping and work with gas tanks and canisters. If you work with the engine, you can set up the cooling system. You can use a fire extinguisher easily and place inflatable barriers so that they allow convenient access and airtight breach containment.
    - You can recompress pipes with the RPD.", + "Trained" = "You can run the atmospherics system. You know how to monitor the air quality across the installation detect problems, and fix them. You're trained in dealing with fires, breaches, and gas leaks, and may have exosuit or fire gear training.
    - You can use the RPD safely.", + "Experienced" = "Your atmospherics experience lets you find, diagnose, and fix breaches efficiently. You can manage complex atmospherics systems without fear of making mistakes, and are proficient with all monitoring and pumping equipment at your disposal.
    - You can dispense a larger selection of pipes from the RPD.", + "Master" = "You are an atmospherics specialist. You monitor, modify, and optimize the installation atmospherics system, and you can quickly and easily deal with emergencies. You can modify atmospherics systems to do pretty much whatever you want them to. You can easily handle a fire or breach, and are proficient at securing an area and rescuing civilians, but you're equally likely to have simply prevented it from happening in the first place." + ) + +/decl/skill/engines name = "Engines" + category = /decl/skill_category/engineering + uid = "skill_engines" + fallback_key = "/decl/hierarchy/skill/engineering/engines" + // TODO: These strings should be modified by the supermatter modpack somehow... desc = "Describes your knowledge of the various engine types common on space stations, such as the PACMAN, singularity, supermatter or RUST engine." - levels = list( "Unskilled" = "You know that \"delamination\" is a bad thing and that you should stay away from the singularity. You know the engine provides power, but you're unclear on the specifics. If you were to try to set up the engine, you would need someone to talk you through every detail--and even then, you'd probably make deadly mistakes.
    - You can read the SM monitor readings with 40% error. This decreases with level.", - "Basic" = "You know the basic theoretical principles of engine operation. You can try to set up the engine by yourself, but you are likely to need some assistance and supervision, otherwise you are likely to make mistakes. You are fully capable of running a PACMAN-type generator.", - "Trained" = "You can set up the engine, and you probably won't botch it up too badly. You know how to protect yourself from radiation in the engine room. You can read the engine monitors and keep the engine going. An engine malfunction may stump you, but you can probably work out how to fix it... let's just hope you do so quickly enough to prevent serious damage.", - "Experienced" = "You have years of experience with engines, and can set them up quickly and reliably. You're familiar with engine types other than the one you work with.
    - You can fully read the SM monitor readings.
    - You can examine the SM directly for its integrity.", - "Master" = "Your engine is your baby and you know every minute detail of its workings. You can optimize the engine and you probably have your own favorite custom setup. You could build an engine from the ground up. When things go wrong, you know exactly what has happened and how to fix the problem. You can safely handle singularities and supermatter.
    - You can examine the SM directly for an approximate number of its EER.") + levels = list( + "Unskilled" = "You know that \"delamination\" is a bad thing and that you should stay away from the singularity. You know the engine provides power, but you're unclear on the specifics. If you were to try to set up the engine, you would need someone to talk you through every detail--and even then, you'd probably make deadly mistakes.
    - You can read the SM monitor readings with 40% error. This decreases with level.", + "Basic" = "You know the basic theoretical principles of engine operation. You can try to set up the engine by yourself, but you are likely to need some assistance and supervision, otherwise you are likely to make mistakes. You are fully capable of running a PACMAN-type generator.", + "Trained" = "You can set up the engine, and you probably won't botch it up too badly. You know how to protect yourself from radiation in the engine room. You can read the engine monitors and keep the engine going. An engine malfunction may stump you, but you can probably work out how to fix it... let's just hope you do so quickly enough to prevent serious damage.", + "Experienced" = "You have years of experience with engines, and can set them up quickly and reliably. You're familiar with engine types other than the one you work with.
    - You can fully read the SM monitor readings.
    - You can examine the SM directly for its integrity.", + "Master" = "Your engine is your baby and you know every minute detail of its workings. You can optimize the engine and you probably have your own favorite custom setup. You could build an engine from the ground up. When things go wrong, you know exactly what has happened and how to fix the problem. You can safely handle singularities and supermatter.
    - You can examine the SM directly for an approximate number of its EER." + ) difficulty = SKILL_HARD // Category: Research - -/decl/hierarchy/skill/research/devices - ID = "devices" +/decl/skill/devices name = "Complex Devices" + category = /decl/skill_category/research + uid = "skill_devices" + fallback_key = "/decl/hierarchy/skill/research/devices" desc = "Describes the ability to assemble complex devices, such as computers, circuits, printers, robots or gas tank assemblies (bombs). Note that if a device requires electronics or programming, those skills are also required in addition to this skill." - levels = list( "Unskilled" = "You know how to use the technology that was present in whatever society you grew up in. You know how to tell when something is malfunctioning, but you have to call tech support to get it fixed.", - "Basic" = "You use and repair high-tech equipment in the course of your daily work. You can fix simple problems, and you know how to use a circuit printer or autolathe. You can build simple robots such as cleanbots and medibots.", - "Trained" = "You can build or repair an exosuit or cyborg chassis, use advanced fabricators and analyzers, and build prosthetic limbs. You can safely transfer an MMI or posibrain into a cyborg chassis.
    - You can attach robotic limbs. Its speed increases with level.", - "Experienced" = "You have years of experience building or reverse-engineering complex devices. Your use of fabricators and destructive analyzers is efficient and methodical. You can design contraptions to order, and likely sell those designs at a profit.", - "Master" = "You are an inventor or researcher. You can design, build, and modify equipment that most people don't even know exists. You are at home in the lab and the workshop and you've never met a gadget you couldn't take apart, put back together, and replicate.") - -/decl/hierarchy/skill/research/science - ID = "science" + levels = list( + "Unskilled" = "You know how to use the technology that was present in whatever society you grew up in. You know how to tell when something is malfunctioning, but you have to call tech support to get it fixed.", + "Basic" = "You use and repair high-tech equipment in the course of your daily work. You can fix simple problems, and you know how to use a circuit printer or autolathe. You can build simple robots such as cleanbots and medibots.", + "Trained" = "You can build or repair an exosuit or cyborg chassis, use advanced fabricators and analyzers, and build prosthetic limbs. You can safely transfer a neural interface into a cyborg chassis.
    - You can attach robotic limbs. Its speed increases with level.", + "Experienced" = "You have years of experience building or reverse-engineering complex devices. Your use of fabricators and destructive analyzers is efficient and methodical. You can design contraptions to order, and likely sell those designs at a profit.", + "Master" = "You are an inventor or researcher. You can design, build, and modify equipment that most people don't even know exists. You are at home in the lab and the workshop and you've never met a gadget you couldn't take apart, put back together, and replicate." + ) + +/decl/skill/science name = "Science" + category = /decl/skill_category/research + uid = "skill_science" + fallback_key = "/decl/hierarchy/skill/research/science" desc = "Your experience and knowledge with scientific methods and processes." - levels = list( "Unskilled" = "You know what science is and probably have a vague idea of the scientific method from your high school science classes.", - "Basic" = "You keep up with scientific discoveries. You know a little about most fields of research. You've learned basic laboratory skills. You may read about science as a hobby; or you may be working in a field related to science and have learned about science that way. You could design a simple experiment.", - "Trained" = "You are a scientist, perhaps a graduate student or post-graduate researcher. You can design an experiment, analyze your results, publish your data, and integrate what you've learned with the research of other scientists. Your laboratory skills are reliable, and you know how to find information you need when you research a new scientific topic. You can dissect exotic xenofauna without many issues.", - "Experienced" = "You are a junior researcher. You can formulate your own questions, use the tools at hand to test your hypotheses, and investigate entirely new phenomena. You likely have a track record of success in publishing your conclusions and attracting funding.", - "Master" = "You are a professional researcher, and you have made multiple new discoveries in your field. Your experiments are well-designed. You are known as an authority in your specialty and your papers often appear in prestigious journals. You may be coordinating the research efforts of a team of scientists, and likely know how to make your findings appealing to investors.") + levels = list( + "Unskilled" = "You know what science is and probably have a vague idea of the scientific method from your high school science classes.", + "Basic" = "You keep up with scientific discoveries. You know a little about most fields of research. You've learned basic laboratory skills. You may read about science as a hobby; or you may be working in a field related to science and have learned about science that way. You could design a simple experiment.", + "Trained" = "You are a scientist, perhaps a graduate student or post-graduate researcher. You can design an experiment, analyze your results, publish your data, and integrate what you've learned with the research of other scientists. Your laboratory skills are reliable, and you know how to find information you need when you research a new scientific topic. You can dissect exotic xenofauna without many issues.", + "Experienced" = "You are a junior researcher. You can formulate your own questions, use the tools at hand to test your hypotheses, and investigate entirely new phenomena. You likely have a track record of success in publishing your conclusions and attracting funding.", + "Master" = "You are a professional researcher, and you have made multiple new discoveries in your field. Your experiments are well-designed. You are known as an authority in your specialty and your papers often appear in prestigious journals. You may be coordinating the research efforts of a team of scientists, and likely know how to make your findings appealing to investors." + ) // Category: Medical +/decl/skill/medicine + abstract_type = /decl/skill/medicine + category = /decl/skill_category/medical + difficulty = SKILL_HARD -/decl/hierarchy/skill/medical/medical - ID = "medical" +/decl/skill/medicine/medical name = "Medicine" + uid = "skill_medical" + fallback_key = "/decl/hierarchy/skill/medical/medical" desc = "Covers an understanding of the human body and medicine. At a low level, this skill gives a basic understanding of applying common types of medicine, and a rough understanding of medical devices like the health analyzer. At a high level, this skill grants exact knowledge of all the medicine available on the installation, as well as the ability to use complex medical devices like the body scanner or mass spectrometer." - levels = list( "Unskilled" = "You know first aid, such as how to apply a bandage or ointment to an injury. You can use an autoinjector designed for civilian use, probably by reading the directions printed on it. You can tell when someone is badly hurt and needs a doctor; you can see whether someone has a badly broken bone, is having trouble breathing, or is unconscious. You may have trouble telling the difference between unconscious and dead at distance.
    - You can use first aid supplies found in kits and pouches, including autoinjectors.", - "Basic" = "You've taken a nursing or EMT course. You can stop bleeding, do CPR, apply a splint, take someone's pulse, apply trauma and burn treatments, and read a handheld health scanner. You probably know that antitoxins help poisoning and oxygen helps people with breathing problems; you can use a syringe or start an IV. You've been briefed on the symptoms of common emergencies like a punctured lung, appendicitis, alcohol poisoning, or broken bones, and though you can't treat them, you know that they need a doctor's attention. You can recognize most emergencies as emergencies and safely stabilize and transport a patient.
    - You can fully operate Defibrillators, Health Analyzers, IV drips, and Syringes.", - "Trained" = "You are an experienced EMT, an experienced nurse, or a medical resident. You know how to treat most illnesses and injuries, though exotic illnesses and unusual injuries may still stump you. You have probably begun to specialize in some sub-field of medicine. In emergencies, you can think fast enough to keep your patients alive, and even when you can't treat a patient, you know how to find someone who can. You can use a full-body scanner, and you know something's off about a patient with an alien parasite.
    - You can fully operate Sleepers.
    - You can apply splints without failing. You can perform simple surgery steps if you have Experienced Anatomy skill", - "Experienced" = "You are a senior nurse or paramedic, or a practicing doctor. You know how to use all of the medical devices available to treat a patient. Your deep knowledge of the body and medications will let you diagnose and come up with a course of treatment for most ailments. You can perform a full-body scan thoroughly and find important information.
    - You can fully operate Body Scanners. You can perform all surgery steps if you have Experienced Anatomy skill", - "Master" = "You are an experienced doctor or an expert nurse or EMT. You've seen almost everything there is to see when it comes to injuries and illness and even when it comes to something you haven't seen, you can apply your wide knowledge base to put together a treatment. In a pinch, you can do just about any medicine-related task, but your specialty, whatever it may be, is where you really shine.") - -/decl/hierarchy/skill/medical/anatomy - ID = "anatomy" + levels = list( + "Unskilled" = "You know first aid, such as how to apply a bandage or ointment to an injury. You can use an autoinjector designed for civilian use, probably by reading the directions printed on it. You can tell when someone is badly hurt and needs a doctor; you can see whether someone has a badly broken bone, is having trouble breathing, or is unconscious. You may have trouble telling the difference between unconscious and dead at distance.
    - You can use first aid supplies found in kits and pouches, including autoinjectors.", + "Basic" = "You've taken a nursing or EMT course. You can stop bleeding, do CPR, apply a splint, take someone's pulse, apply trauma and burn treatments, and read a handheld health scanner. You probably know that antitoxins help poisoning and oxygen helps people with breathing problems; you can use a syringe or start an IV. You've been briefed on the symptoms of common emergencies like a punctured lung, appendicitis, alcohol poisoning, or broken bones, and though you can't treat them, you know that they need a doctor's attention. You can recognize most emergencies as emergencies and safely stabilize and transport a patient.
    - You can fully operate Defibrillators, Health Analyzers, IV drips, and Syringes.", + "Trained" = "You are an experienced EMT, an experienced nurse, or a medical resident. You know how to treat most illnesses and injuries, though exotic illnesses and unusual injuries may still stump you. You have probably begun to specialize in some sub-field of medicine. In emergencies, you can think fast enough to keep your patients alive, and even when you can't treat a patient, you know how to find someone who can. You can use a full-body scanner, and you know something's off about a patient with an alien parasite.
    - You can fully operate Sleepers.
    - You can apply splints without failing. You can perform simple surgery steps if you have Experienced Anatomy skill", + "Experienced" = "You are a senior nurse or paramedic, or a practicing doctor. You know how to use all of the medical devices available to treat a patient. Your deep knowledge of the body and medications will let you diagnose and come up with a course of treatment for most ailments. You can perform a full-body scan thoroughly and find important information.
    - You can fully operate Body Scanners. You can perform all surgery steps if you have Experienced Anatomy skill", + "Master" = "You are an experienced doctor or an expert nurse or EMT. You've seen almost everything there is to see when it comes to injuries and illness and even when it comes to something you haven't seen, you can apply your wide knowledge base to put together a treatment. In a pinch, you can do just about any medicine-related task, but your specialty, whatever it may be, is where you really shine." + ) + +/decl/skill/medicine/anatomy name = "Anatomy" + uid = "skill_anatomy" + fallback_key = "/decl/hierarchy/skill/medical/anatomy" desc = "Gives you a detailed insight of the human body. A high skill in this is required to perform surgery. This skill may also help in examining alien biology." - levels = list( "Unskilled" = "You know what organs, bones, and such are, and you know roughly where they are. You know that someone who's badly hurt or sick may need surgery.", - "Basic" = "You've taken an anatomy class and you've spent at least some time poking around inside actual people. You know where everything is, more or less. You could assist in surgery, if you have the required medical skills. If you have the forensics knowledge, you could perform an autopsy. If you really had to, you could probably perform basic surgery such as an appendectomy, but you're not yet a qualified surgeon and you really shouldn't--not unless it's an emergency. If you're a xenobiologist, you know how to take out slime cores.", - "Trained" = "You have some training in anatomy. Diagnosing broken bones, damaged ligaments, shrapnel wounds, and other trauma is straightforward for you. You can splint limbs with a good chance of success, operate a defibrillator competently, and perform CPR well. Surgery is still outside your training.
    - You can do surgery (requires Trained Medicine skill too) but you are very likely to fail at every step. Its speed increases with level. You can perform the cybernethics procedures if you have Trained Complex Devices skill", - "Experienced" = "You're a surgical resident, or an experienced medical doctor. You can put together broken bones, fix a damaged lung, patch up a liver, or remove an appendix without problems. But tricky surgeries, with an unstable patient or delicate manipulation of vital organs like the heart and brain, are at the edge of your ability, and you prefer to leave them to specialized surgeons. You can recognize when someone's anatomy is noticeably unusual. You're trained in working with several species, but you're probably better at surgery on your own species.
    - You can do all surgery steps safely, if you have Experienced Medicine skill too.", - "Master" = "You are an experienced surgeon. You can handle anything that gets rolled, pushed, or dragged into the OR, and you can keep a patient alive and stable even if there's no one to assist you. You can handle severe trauma cases or multiple organ failure, repair brain damage, and perform heart surgery. By now, you've probably specialized in one field, where you may have made new contributions to surgical technique. You can detect even small variations in the anatomy of a patient--even a changeling probably wouldn't slip by your notice, provided you could get one on the operating table.
    - The penalty from operating on improper operating surfaces is reduced.") - -/decl/hierarchy/skill/medical/chemistry - ID = "chemistry" + levels = list( + "Unskilled" = "You know what organs, bones, and such are, and you know roughly where they are. You know that someone who's badly hurt or sick may need surgery.", + "Basic" = "You've taken an anatomy class and you've spent at least some time poking around inside actual people. You know where everything is, more or less. You could assist in surgery, if you have the required medical skills. If you have the forensics knowledge, you could perform an autopsy. If you really had to, you could probably perform basic surgery such as an appendectomy, but you're not yet a qualified surgeon and you really shouldn't--not unless it's an emergency. If you're a xenobiologist, you know how to take out slime cores.", + "Trained" = "You have some training in anatomy. Diagnosing broken bones, damaged ligaments, shrapnel wounds, and other trauma is straightforward for you. You can splint limbs with a good chance of success, operate a defibrillator competently, and perform CPR well. Surgery is still outside your training.
    - You can do surgery (requires Trained Medicine skill too) but you are very likely to fail at every step. Its speed increases with level. You can perform the cybernethics procedures if you have Trained Complex Devices skill", + "Experienced" = "You're a surgical resident, or an experienced medical doctor. You can put together broken bones, fix a damaged lung, patch up a liver, or remove an appendix without problems. But tricky surgeries, with an unstable patient or delicate manipulation of vital organs like the heart and brain, are at the edge of your ability, and you prefer to leave them to specialized surgeons. You can recognize when someone's anatomy is noticeably unusual. You're trained in working with several species, but you're probably better at surgery on your own species.
    - You can do all surgery steps safely, if you have Experienced Medicine skill too.", + "Master" = "You are an experienced surgeon. You can handle anything that gets rolled, pushed, or dragged into the OR, and you can keep a patient alive and stable even if there's no one to assist you. You can handle severe trauma cases or multiple organ failure, repair brain damage, and perform heart surgery. By now, you've probably specialized in one field, where you may have made new contributions to surgical technique. You can detect even small variations in the anatomy of a patient--very little will slip by your notice, provided you could get them on the operating table.
    - The penalty from operating on improper operating surfaces is reduced." + ) + +/decl/skill/medicine/chemistry name = "Chemistry" + uid = "skill_chemistry" + fallback_key = "/decl/hierarchy/skill/medical/chemistry" desc = "Experience with mixing chemicals, and an understanding of what the effect will be. This doesn't cover an understanding of the effect of chemicals on the human body, as such the medical skill is also required for medical chemists." - levels = list( "Unskilled" = "You know that chemists work with chemicals; you know that they can make medicine or poison or useful chemicals. You probably know what an element is and have a vague idea of what a chemical reaction is from some chemistry class in your high school days.", - "Basic" = "You can make basic chemicals or medication--things like space cleaner or anti-toxin. You have some training in safety and you won't blow up the lab... probably.
    - You can safely use the industrial grinder but lose some ingredients. Its amount decreases with skill level.", - "Trained" = "You can accurately measure out reagents, grind powders, and perform chemical reactions. You may still lose some product on occasion, but are unlikely to endanger yourself or those around you.
    - You can fully operate the chem dispenser.", - "Experienced" = "You work as a chemist, or else you are a doctor with training in chemistry. If you are a research chemist, you can create most useful chemicals; if you are a pharmacist, you can make most medications. At this stage, you're working mostly by-the-book. You can weaponize your chemicals by making grenades, smoke bombs, and similar devices.
    - You can examine held containers for scannable reagents.", - "Master" = "You specialized in chemistry or pharmaceuticals; you are either a medical researcher or professional chemist. You can create custom mixes and make even the trickiest of medications easily. You understand how your pharmaceuticals interact with the bodies of your patients. You are probably the originator of at least one new chemical innovation.
    - You can examine held containers for all reagents.") + levels = list( + "Unskilled" = "You know that chemists work with chemicals; you know that they can make medicine or poison or useful chemicals. You probably know what an element is and have a vague idea of what a chemical reaction is from some chemistry class in your high school days.", + "Basic" = "You can make basic chemicals or medication--things like space cleaner or anti-toxin. You have some training in safety and you won't blow up the lab... probably.
    - You can safely use the industrial grinder but lose some ingredients. Its amount decreases with skill level.", + "Trained" = "You can accurately measure out reagents, grind powders, and perform chemical reactions. You may still lose some product on occasion, but are unlikely to endanger yourself or those around you.
    - You can fully operate the chem dispenser.", + "Experienced" = "You work as a chemist, or else you are a doctor with training in chemistry. If you are a research chemist, you can create most useful chemicals; if you are a pharmacist, you can make most medications. At this stage, you're working mostly by-the-book. You can weaponize your chemicals by making grenades, smoke bombs, and similar devices.
    - You can examine held containers for scannable reagents.", + "Master" = "You specialized in chemistry or pharmaceuticals; you are either a medical researcher or professional chemist. You can create custom mixes and make even the trickiest of medications easily. You understand how your pharmaceuticals interact with the bodies of your patients. You are probably the originator of at least one new chemical innovation.
    - You can examine held containers for all reagents." + ) diff --git a/code/modules/mob/skills/skill_buffs.dm b/code/modules/mob/skills/skill_buffs.dm index eea8a06cbea1..efe7434f2e6c 100644 --- a/code/modules/mob/skills/skill_buffs.dm +++ b/code/modules/mob/skills/skill_buffs.dm @@ -1,8 +1,10 @@ //The base type is suitable for generic buffs not needing special treatment. /datum/skill_buff var/list/buffs //Format: list(skill_path = amount) - var/limit //How many buffs of this type a skillset can have. null = no limit - var/datum/skillset/skillset //The skillset to which this buff belongs. + /// How many buffs of this type a skillset can have. null = no limit + var/limit + /// The skillset to which this buff belongs. + var/datum/skillset/skillset /datum/skill_buff/New(buff) buffs = buff @@ -17,21 +19,21 @@ //Clamps the buff amounts so that the target stays between SKILL_MIN and SKILL_MAX in all skills. /datum/skill_buff/proc/tailor_buff(mob/target) if(!buffs) - return + return 0 var/list/temp_buffs = buffs.Copy() for(var/skill_type in temp_buffs) var/has_now = target.get_skill_value(skill_type) var/current_buff = buffs[skill_type] - var/new_buff = Clamp(has_now + current_buff, SKILL_MIN, SKILL_MAX) - has_now + var/new_buff = clamp(has_now + current_buff, SKILL_MIN, SKILL_MAX) - has_now new_buff ? (buffs[skill_type] = new_buff) : (buffs -= skill_type) return length(buffs) /datum/skill_buff/proc/can_buff(mob/target) if(!length(buffs) || !istype(target)) - return //what are we even buffing? + return FALSE //what are we even buffing? if(target.too_many_buffs(type)) - return - return 1 + return FALSE + return TRUE /datum/skill_buff/proc/remove() var/datum/skillset/my_skillset = skillset @@ -71,11 +73,12 @@ buff.skillset = skillset skillset.on_levels_change() if(duration) - addtimer(CALLBACK(buff, /datum/skill_buff/proc/remove), duration) + addtimer(CALLBACK(buff, TYPE_PROC_REF(/datum/skill_buff, remove)), duration) return buff //Takes a buff type or datum; typing is false here. /mob/proc/too_many_buffs(datum/skill_buff/buff_type) var/limit = initial(buff_type.limit) if(limit && (length(fetch_buffs_of_type(buff_type, 0)) >= limit)) - return 1 \ No newline at end of file + return TRUE + return FALSE \ No newline at end of file diff --git a/code/modules/mob/skills/skill_ui.dm b/code/modules/mob/skills/skill_ui.dm index 3977c51b2c61..221439db085b 100644 --- a/code/modules/mob/skills/skill_ui.dm +++ b/code/modules/mob/skills/skill_ui.dm @@ -20,7 +20,7 @@ skillset = null . = ..() -/datum/nano_module/skill_ui/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.self_state) +/datum/nano_module/skill_ui/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.self_topic_state) if(!skillset) return var/list/data = skillset.get_nano_data(hide_unskilled) @@ -41,7 +41,7 @@ if(href_list["toggle_hide_unskilled"]) hide_unskilled = !hide_unskilled return 1 - + /datum/nano_module/skill_ui/proc/get_data() return list() @@ -52,31 +52,39 @@ .["hide_unskilled"] = hide_unskilled var/list/skill_data = list() - var/decl/hierarchy/skill/skill = decls_repository.get_decl(/decl/hierarchy/skill) - for(var/decl/hierarchy/skill/V in skill.children) + var/list/available_skills = global.using_map.get_available_skills() + var/list/categories = sortTim(decls_repository.get_decls_of_subtype_unassociated(/decl/skill_category), /proc/cmp_skill_category_asc) + for(var/decl/skill_category/cat in categories) var/list/skill_cat = list() - skill_cat["name"] = V.name - var/list/skills_in_cat = list() - for(var/decl/hierarchy/skill/S in V.children) - var/offset = S.prerequisites ? S.prerequisites[S.parent.type] - 1 : 0 + var/list/skills_in_cat = list() // can't just use category.children because we check available_skills and our skill levels + + for(var/decl/skill/S in cat.children) + if(!(S in available_skills)) + continue + + var/decl/skill/prerequisite = S.prerequisites?[1] + var/offset = prerequisite ? S.prerequisites[prerequisite] - 1 : 0 if(hide_unskilled && (get_value(S.type) + offset == SKILL_MIN)) continue + skills_in_cat += list(get_nano_row(S)) - for(var/decl/hierarchy/skill/perk in S.children) - skills_in_cat += list(get_nano_row(perk)) + if(length(skills_in_cat)) + skill_cat["name"] = cat.name skill_cat["skills"] = skills_in_cat skill_data += list(skill_cat) + .["skills_by_cat"] = skill_data -/datum/skillset/proc/get_nano_row(var/decl/hierarchy/skill/S) +/datum/skillset/proc/get_nano_row(var/decl/skill/S) var/list/skill_item = list() skill_item["name"] = S.name var/value = get_value(S.type) skill_item["val"] = value skill_item["ref"] = "\ref[S.type]" skill_item["available"] = check_prerequisites(S.type) - var/offset = S.prerequisites ? S.prerequisites[S.parent.type] - 1 : 0 + var/decl/skill/prerequisite = S.prerequisites?[1] + var/offset = prerequisite ? S.prerequisites[prerequisite] - 1 : 0 var/list/levels = list() for(var/i in 1 to offset) levels += list(list("blank" = 1)) @@ -93,7 +101,7 @@ return skill_item /datum/skillset/proc/check_prerequisites(skill_type) - var/decl/hierarchy/skill/S = decls_repository.get_decl(skill_type) + var/decl/skill/S = GET_DECL(skill_type) if(!S.prerequisites) return TRUE for(var/prereq_type in S.prerequisites) @@ -114,18 +122,25 @@ The generic antag version. . = ..() .["can_choose"] = can_choose() var/list/selection_data = list() - var/decl/hierarchy/skill/skill = decls_repository.get_decl(/decl/hierarchy/skill) + var/decl/skill/sample_skill // just used to get the skill level names + for(var/candidate_skill_type in skillset.skill_list) + var/decl/skill/candidate = GET_DECL(candidate_skill_type) + if(length(candidate.levels) == SKILL_MAX) // find a skill with all the levels, so avoid perks/traits + sample_skill = candidate + break + if(!sample_skill) + sample_skill = GET_DECL(/decl/skill/general/hauling) for(var/i in 1 to length(max_choices)) var/choices = max_choices[i] if(!choices) continue var/list/level_data = list() - level_data["name"] = skill.levels[i] + level_data["name"] = sample_skill.levels[i] level_data["level"] = i var/selected = LAZYACCESS(currently_selected, i) level_data["selected"] = list() for(var/skill_type in selected) - var/decl/hierarchy/skill/S = skill_type // False type. + var/decl/skill/S = skill_type // False type. level_data["selected"] += list(list("name" = initial(S.name), "ref" = "\ref[skill_type]")) level_data["remaining"] = choices - length(selected) selection_data += list(level_data) @@ -142,7 +157,7 @@ The generic antag version. return 1 var/level = text2num(href_list["add_skill"]) var/list/choices = list() - for(var/decl/hierarchy/skill/S in GLOB.skills) + for(var/decl/skill/S in global.using_map.get_available_skills()) if(can_select(S.type, level)) choices[S.name] = S.type var/choice = input(usr, "Which skill would you like to add?", "Add Skill") as null|anything in choices @@ -187,7 +202,7 @@ The generic antag version. return if(skillset.get_value(skill_type) >= level) return - var/decl/hierarchy/skill/S = decls_repository.get_decl(skill_type) + var/decl/skill/S = GET_DECL(skill_type) if(length(S.levels) < level) return if(S.prerequisites) @@ -240,7 +255,7 @@ Admin version, with debugging options. /datum/nano_module/skill_ui/admin template = "skill_ui_admin.tmpl" -/datum/nano_module/skill_ui/admin/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.admin_state) +/datum/nano_module/skill_ui/admin/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.admin_topic_state) ..() //Uses different default state. /datum/nano_module/skill_ui/admin/get_data() @@ -284,7 +299,7 @@ Admin version, with debugging options. log_and_message_admins("SKILLS: The job skills for [key_name_admin(skillset.owner)] have been imported.") return 1 if(href_list["antag"]) - var/datum/antagonist/antag = skillset.owner.mind && player_is_antag(skillset.owner.mind) + var/decl/special_role/antag = skillset.owner.mind && player_is_antag(skillset.owner.mind) if(!antag) to_chat(usr, "Mob lacks valid antag status.") return 1 diff --git a/code/modules/mob/skills/skill_verbs.dm b/code/modules/mob/skills/skill_verbs.dm index e0d71e621c8b..fb9e0d13929a 100644 --- a/code/modules/mob/skills/skill_verbs.dm +++ b/code/modules/mob/skills/skill_verbs.dm @@ -1,7 +1,5 @@ //Skill-related mob verbs that require skill checks to be satisfied to be added. -GLOBAL_LIST_INIT(skill_verbs, init_subtypes(/datum/skill_verb)) - /datum/skillset/proc/fetch_verb_datum(given_type) for(var/datum/skill_verb/SV in skill_verbs) if(SV.type == given_type) @@ -14,8 +12,10 @@ GLOBAL_LIST_INIT(skill_verbs, init_subtypes(/datum/skill_verb)) /datum/skill_verb var/datum/skillset/skillset //Owner, if any. var/the_verb //The verb to keep track of. Should be a mob verb. - var/cooldown //How long the verb cools down for after use. null = has no cooldown. - var/cooling_down = 0 //Whether it's currently cooling down. + /// The minimum time between uses of the verb. null = no wait between uses. + var/cooldown + /// If TRUE, the verb is currently unavailable. + var/cooling_down = FALSE /datum/skill_verb/Destroy() skillset = null @@ -39,19 +39,19 @@ GLOBAL_LIST_INIT(skill_verbs, init_subtypes(/datum/skill_verb)) /datum/skill_verb/proc/should_see_verb() if(cooling_down) - return - return 1 + return FALSE + return TRUE /datum/skill_verb/proc/remove_cooldown() - cooling_down = 0 + cooling_down = FALSE update_verb() /datum/skill_verb/proc/set_cooldown() if(!cooldown) return - cooling_down = 1 + cooling_down = TRUE update_verb() - addtimer(CALLBACK(src, .proc/remove_cooldown), cooldown) + addtimer(CALLBACK(src, PROC_REF(remove_cooldown)), cooldown) /* The Instruct verb. buffs untrained -> basic and requires skill in the skill training as well as leadership. Robots and antags can instruct. @@ -61,76 +61,79 @@ Robots and antags can instruct. cooldown = 15 MINUTES /datum/skill_verb/instruct/should_have_verb(datum/skillset/given_skillset) - if(!..()) + . = FALSE + if(!(. = ..())) return if(!isliving(given_skillset.owner)) - return - return 1 + return FALSE + return TRUE /datum/skill_verb/instruct/should_see_verb() - if(!..()) + if(!(. = ..())) return - for(var/decl/hierarchy/skill/S in GLOB.skills) + for(var/decl/skill/S in global.using_map.get_available_skills()) if(skillset.owner.skill_check(S.type, SKILL_EXPERT)) - return 1 + return TRUE -/mob/proc/instruct(mob/living/carbon/human/target as mob in oview(2)) - set category = "IC" - set name = "Instruct" - set src = usr +/mob/proc/can_instruct(mob/living/human/target, var/get_options = FALSE) var/datum/skill_verb/instruct/SV = skillset.fetch_verb_datum(/datum/skill_verb/instruct) if(!SV || !istype(target)) return if(src == target) - to_chat(src, "Cannot instruct yourself.") + to_chat(src, SPAN_WARNING("You cannot instruct yourself, except maybe in philosophy.")) return - if(incapacitated() || target.incapacitated()) - to_chat(src, "[incapacitated() ? "You are in no state to teach right now!" : "\the [target] is in no state to be taught right now!"]") + if(incapacitated()) + to_chat(src, SPAN_WARNING("You are in no state to teach right now!")) + return + if(target.incapacitated()) + to_chat(src, SPAN_WARNING("\The [target] is in no state to be taught right now!")) return - if(target.too_many_buffs(/datum/skill_buff/instruct)) - to_chat(src, "\The [target] exhausted from all the training \he recieved.") + var/decl/pronouns/pronouns = target.get_pronouns(ignore_coverings = TRUE) + to_chat(src, SPAN_WARNING("\The [target] [pronouns.is] exhausted from all the training [pronouns.he] received.")) return - var/options = list() - for(var/decl/hierarchy/skill/S in GLOB.skills) - if(!target.skill_check(S.type, SKILL_BASIC) && skill_check(S.type, SKILL_EXPERT)) - options[S.name] = S + if(!get_options) + . = TRUE + else + for(var/decl/skill/S in global.using_map.get_available_skills()) + if(!target.skill_check(S.type, SKILL_BASIC) && skill_check(S.type, SKILL_EXPERT)) + LAZYSET(., S.name, S) + +/mob/proc/instruct(mob/living/human/target as mob in oview(2)) + + set category = "IC" + set name = "Instruct" + set src = usr + + var/list/options = can_instruct(target, get_options = TRUE) if(!length(options)) - to_chat(src, "There is nothing you can teach \the [target].") + to_chat(src, SPAN_WARNING("There is nothing you can teach \the [target].")) + return + var/choice = input(src, "Select skill to instruct \the [target] in:", "Skill select") as null|anything in options if(!(choice in options) || !(target in view(2))) return - var/decl/hierarchy/skill/skill = options[choice] - if(!do_skilled(6 SECONDS, skill.type, target)) - return - if(incapacitated() || target.incapacitated()) - to_chat(src, "[incapacitated() ? "You are in no state to teach right now!" : "\the [target] is in no state to be taught right now!"]") - return - if(target.too_many_buffs(/datum/skill_buff/instruct)) - to_chat(src, "\The [target] exhausted from all the training \he recieved.") - return - if(target.skill_check(skill.type, SKILL_BASIC)) - to_chat(src, "\The [target] is too skilled to gain any benefit from a short lesson.") - return - if(!skill_check(skill.type, SKILL_EXPERT)) + var/decl/skill/skill = options[choice] + if(!do_skilled(6 SECONDS, skill.type, target) || !can_instruct(target) || !skill_check(skill.type, SKILL_EXPERT)) return target.buff_skill(list(skill.type = 1), buff_type = /datum/skill_buff/instruct) - visible_message("\The [src] trained \the [target] in the basics of \the [skill.name].") + visible_message(SPAN_NOTICE("\The [src] trains \the [target] in the basics of [skill.name].")) + var/datum/skill_verb/instruct/SV = skillset.fetch_verb_datum(/datum/skill_verb/instruct) SV.set_cooldown() -/datum/skill_buff/instruct/ +/datum/skill_buff/instruct limit = 3 /datum/skill_buff/motivate/can_buff(mob/target) if(!..()) - return + return FALSE if(!ishuman(target)) - return - return 1 + return FALSE + return TRUE /* The Appraise verb. Used on objects to estimate their value. */ @@ -138,18 +141,18 @@ The Appraise verb. Used on objects to estimate their value. the_verb = /mob/proc/appraise /datum/skill_verb/appraise/should_have_verb(datum/skillset/given_skillset) - if(!..()) + if(!(. = ..())) return if(!isliving(given_skillset.owner)) - return - return 1 + return FALSE + return TRUE /datum/skill_verb/appraise/should_see_verb() - if(!..()) + if(!(. = ..())) return if(!skillset.owner.skill_check(SKILL_FINANCE, SKILL_BASIC)) - return - return 1 + return FALSE + return TRUE /mob/proc/appraise(obj/item as obj in get_equipped_items(1)) set category = "IC" @@ -174,7 +177,7 @@ The Appraise verb. Used on objects to estimate their value. var/high = low + level if(!low && multiple >= 2) low = 10 ** (multiple - 1) //Adjusts the lowball estimate away from 0 if the item has a high upper estimate. - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) message = "You appraise the item to be worth between [low] and [high] [cur.name]." to_chat(src, message) @@ -200,11 +203,11 @@ The Appraise verb. Used on objects to estimate their value. return 1 /datum/skill_verb/noirvision/should_see_verb() - if(!..()) + if(!(. = ..())) return if(!skillset.owner.skill_check(SKILL_FORENSICS, SKILL_PROF)) - return - return 1 + return FALSE + return TRUE /mob/proc/noirvision() set category = "IC" diff --git a/code/modules/mob/skills/skillset.dm b/code/modules/mob/skills/skillset.dm index d178f0b89e31..eef151360637 100644 --- a/code/modules/mob/skills/skillset.dm +++ b/code/modules/mob/skills/skillset.dm @@ -13,9 +13,12 @@ var/literacy_charges = 2 //used to limit the number of books a master literate mob can make +var/global/list/all_skill_verbs /datum/skillset/New(mob/mob) owner = mob - for(var/datum/skill_verb/SV in GLOB.skill_verbs) + if(!global.all_skill_verbs) + global.all_skill_verbs = init_subtypes(/datum/skill_verb) + for(var/datum/skill_verb/SV in global.all_skill_verbs) if(SV.should_have_verb(src)) SV.give_to_skillset(src) ..() @@ -29,12 +32,13 @@ . = ..() /datum/skillset/proc/get_value(skill_path) - . = skill_list[skill_path] || default_value + var/decl/skill/skill = GET_DECL(skill_path) + . = skill_list[skill_path] || (isnull(skill.default_value) ? src.default_value : skill.default_value) for(var/datum/skill_buff/SB in skill_buffs) . += SB.buffs[skill_path] -/datum/skillset/proc/obtain_from_mob(mob/mob) - if(!istype(mob) || !skills_transferable || !mob.skillset.skills_transferable) +/datum/skillset/proc/obtain_from_mob(mob/living/mob) + if(!istype(mob) || !skills_transferable || !mob.skillset?.skills_transferable) return skill_list = mob.skillset.skill_list default_value = mob.skillset.default_value @@ -58,7 +62,7 @@ /datum/skillset/proc/update_special_effects() if(!owner) return - for(var/decl/hierarchy/skill/skill in GLOB.skills) + for(var/decl/skill/skill in global.using_map.get_available_skills()) skill.update_special_effects(owner, get_value(skill.type)) /datum/skillset/proc/obtain_from_client(datum/job/job, client/given_client, override = 0) @@ -72,7 +76,7 @@ var/allocation = given_client.prefs.skills_allocated[job] || list() skill_list = list() - for(var/decl/hierarchy/skill/S in GLOB.skills) + for(var/decl/skill/S in global.using_map.get_available_skills()) var/min = job ? given_client.prefs.get_min_skill(job, S) : SKILL_MIN skill_list[S.type] = min + (allocation[S] || 0) on_levels_change() @@ -115,8 +119,8 @@ else return max(0, 1 + (SKILL_DEFAULT - points) * factor) -/mob/proc/do_skilled(base_delay, skill_path , atom/target = null, factor = 0.3) - return do_after(src, base_delay * skill_delay_mult(skill_path, factor), target) +/mob/proc/do_skilled(base_delay, skill_path , atom/target = null, factor = 0.3, check_holding = FALSE, set_cooldown = FALSE) + return do_after(src, base_delay * skill_delay_mult(skill_path, factor), target, check_holding, set_cooldown = set_cooldown) // A generic way of modifying success probabilities via skill values. Higher factor means skills have more effect. fail_chance is the chance at SKILL_NONE. /mob/proc/skill_fail_chance(skill_path, fail_chance, no_more_fail = SKILL_MAX, factor = 1) diff --git a/code/modules/mob/stripping.dm b/code/modules/mob/stripping.dm new file mode 100644 index 000000000000..0856c8617870 --- /dev/null +++ b/code/modules/mob/stripping.dm @@ -0,0 +1,151 @@ +/mob/proc/handle_strip(var/slot_to_strip_text,var/mob/living/user,var/obj/item/clothing/holder) + if(!slot_to_strip_text || !istype(user)) + return + + if(user.incapacitated() || !user.Adjacent(src)) + show_browser(user, null, "window=mob[src.name]") + return TRUE + + // Are we placing or stripping? + var/stripping = FALSE + var/obj/item/held = user.get_active_held_item() + if(!istype(held) || is_robot_module(held)) + stripping = TRUE + + switch(slot_to_strip_text) + // Handle things that are part of this interface but not removing/replacing a given item. + if("pockets") + if(stripping) + visible_message("\The [user] is trying to empty [src]'s pockets!") + if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) + empty_pockets(user) + else + //should it be possible to discreetly slip something into someone's pockets? + visible_message("\The [user] is trying to stuff \a [held] into [src]'s pocket!") + if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) + place_in_pockets(held, user) + return + if("sensors") + visible_message("\The [user] is trying to set \the [src]'s sensors!") + if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) + toggle_sensors(user) + return + if ("lock_sensors") + var/obj/item/clothing/sensor/vitals/sensor = get_vitals_sensor() + if (!istype(sensor)) + return + visible_message(SPAN_DANGER("\The [user] is trying to [sensor.get_sensors_locked() ? "un" : ""]lock \the [src]'s sensors!")) + if (do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) + if(QDELETED(sensor) || sensor != get_vitals_sensor()) + to_chat(user, SPAN_WARNING("\The [src] is not wearing \the [sensor] anymore.")) + return + var/obj/item/multitool/user_multitool = user.get_multitool() + if (!istype(user_multitool)) + to_chat(user, SPAN_WARNING("You need a multitool to lock \the [src]'s sensors.")) + return + sensor.toggle_sensors_locked() + visible_message(SPAN_NOTICE("\The [user] [sensor.get_sensors_locked() ? "" : "un"]locks \the [src]'s vitals sensor controls."), range = 2) + return + if("internals") + visible_message("\The [user] is trying to set \the [src]'s internals!") + if(do_after(user, HUMAN_STRIP_DELAY, src, progress = 0)) + toggle_internals(user) + return + + if("accessory") + if(!istype(holder) || !LAZYLEN(holder.accessories)) + return + + var/obj/item/clothing/accessory + if(LAZYLEN(holder.accessories) > 1) + accessory = show_radial_menu(user, user, make_item_radial_menu_choices(holder.accessories), radius = 42, tooltips = TRUE) + else + accessory = holder.accessories[1] + + if(!istype(accessory)) + return + + visible_message("\The [user] is trying to remove \the [src]'s [accessory.name]!") + + if(!do_after(user, HUMAN_STRIP_DELAY, src, check_holding = FALSE, progress = FALSE)) + return + + if(!accessory || holder.loc != src || !(accessory in holder.accessories)) + return + + admin_attack_log(user, src, "Stripped \an [accessory] from \the [holder].", "Was stripped of \an [accessory] from \the [holder].", "stripped \an [accessory] from \the [holder] of") + holder.remove_accessory(user, accessory) + return + else + var/obj/item/located_item = locate(slot_to_strip_text) in src + if(isunderwear(located_item)) + var/obj/item/underwear/UW = located_item + if(UW.DelayedRemoveUnderwear(user, src)) + user.put_in_active_hand(UW) + return + + var/obj/item/target_slot = get_equipped_item(slot_to_strip_text) + if(stripping) + if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here? + return + if(!target_slot.mob_can_unequip(src, slot_to_strip_text, disable_warning=1)) + to_chat(user, SPAN_WARNING("You cannot remove \the [src]'s [target_slot.name].")) + return + + visible_message("\The [user] is trying to remove \the [src]'s [target_slot.name]!") + else + visible_message("\The [user] is trying to put \a [held] on \the [src]!") + + if(!do_mob(user, src, HUMAN_STRIP_DELAY, check_holding = FALSE)) + return + + if(stripping) + if(try_unequip(target_slot)) + admin_attack_log(user, src, "Stripped \a [target_slot]", "Was stripped of \a [target_slot].", "stripped \a [target_slot] from") + user.put_in_active_hand(target_slot) + else + admin_attack_log(user, src, "Attempted to strip \a [target_slot]", "Target of a failed strip of \a [target_slot].", "attempted to strip \a [target_slot] from") + else if(user.try_unequip(held)) + var/obj/item/clothing/C = get_equipped_item(slot_to_strip_text) + if(istype(C) && C.can_attach_accessory(held, user)) + C.attach_accessory(user, held) + else if(!equip_to_slot_if_possible(held, slot_to_strip_text, del_on_fail=0, disable_warning=1, redraw_mob=1)) + user.put_in_active_hand(held) + +// Empty out everything in the target's pockets. +/mob/proc/empty_pockets(var/mob/living/user) + for(var/slot in global.pocket_slots) + var/obj/item/pocket = get_equipped_item(slot) + if(pocket) + try_unequip(pocket) + . = TRUE + if(.) + visible_message(SPAN_DANGER("\The [user] empties \the [src]'s pockets!")) + else + to_chat(user, SPAN_WARNING("\The [src] has nothing in their pockets.")) + +/mob/proc/place_in_pockets(obj/item/I, var/mob/living/user) + if(!user.try_unequip(I)) + return + for(var/slot in global.pocket_slots) + if(!get_equipped_item(slot) && equip_to_slot_if_possible(I, slot, del_on_fail=0, disable_warning=1, redraw_mob=1)) + return + to_chat(user, SPAN_WARNING("You are unable to place [I] in [src]'s pockets.")) + user.put_in_active_hand(I) + +// Modify the current target sensor level. +/mob/proc/toggle_sensors(var/mob/living/user) + var/obj/item/clothing/sensor/vitals/sensor = get_vitals_sensor() + if(!istype(sensor)) + to_chat(user, SPAN_WARNING("\The [src] is not wearing a vitals sensor.")) + if (sensor.get_sensors_locked()) + to_chat(user, SPAN_WARNING("\The [src]'s suit sensor controls are locked.")) + return + admin_attack_log(user, src, "Toggled their suit sensors.", "Toggled their suit sensors.", "toggled the suit sensors of") + sensor.user_set_sensors(user) + +/mob/proc/get_vitals_sensor() + for(var/check_slot in global.vitals_sensor_equip_slots) + var/obj/item/clothing/equipped = get_equipped_item(check_slot) + if(istype(equipped)) + return (locate(/obj/item/clothing/sensor/vitals) in equipped.accessories) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 10323d7578e1..bebc25e3b4b5 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -1,16 +1,14 @@ -/mob/living/carbon/human/proc/monkeyize() +/mob/living/human/proc/monkeyize() if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return - for(var/obj/item/W in src) - if (W==w_uniform) // will be torn - continue - drop_from_inventory(W) - regenerate_icons() + for(var/obj/item/thing in get_contained_external_atoms()) + drop_from_inventory(thing) + try_refresh_visible_overlays() ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) - stunned = 1 + set_status_condition(STAT_STUN, 1) icon = null - set_invisibility(101) - for(var/t in organs) + set_invisibility(INVISIBILITY_ABSTRACT) + for(var/t in get_external_organs()) qdel(t) var/atom/movable/overlay/animation = new /atom/movable/overlay(src) animation.icon_state = "blank" @@ -20,78 +18,78 @@ //animation = null DEL_TRANSFORMATION_MOVEMENT_HANDLER(src) - stunned = 0 - UpdateLyingBuckledAndVerbStatus() + set_status_condition(STAT_STUN, 0) + update_posture() set_invisibility(initial(invisibility)) if(!species.primitive_form) //If the creature in question has no primitive set, this is going to be messy. gib() return - for(var/obj/item/W in src) - drop_from_inventory(W) - set_species(species.primitive_form) - dna.SetSEState(GLOB.MONKEYBLOCK,1) - dna.SetSEValueRange(GLOB.MONKEYBLOCK,0xDAC, 0xFFF) + for(var/obj/item/thing in src) + drop_from_inventory(thing) + change_species(species.primitive_form) to_chat(src, "You are now [species.name]. ") qdel(animation) return src -/mob/new_player/AIize() +/mob/new_player/AIize(move = TRUE) spawning = 1 return ..() -/mob/living/carbon/human/AIize(move=1) // 'move' argument needs defining here too because BYOND is dumb +/mob/living/human/AIize(move = TRUE) if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return - for(var/t in organs) - qdel(t) QDEL_NULL_LIST(worn_underwear) - return ..(move) + return ..() + +/mob/living/silicon/ai/AIize(move = TRUE) + return src -/mob/living/carbon/AIize() +/mob/living/AIize(move = TRUE) if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return - for(var/obj/item/W in src) - drop_from_inventory(W) + for(var/t in get_external_organs()) + qdel(t) + for(var/obj/item/thing in src) + drop_from_inventory(thing) ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) icon = null - set_invisibility(101) + set_invisibility(INVISIBILITY_ABSTRACT) return ..() -/mob/proc/AIize(move=1) +/mob/proc/AIize(move = TRUE) if(client) - sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = GLOB.lobby_sound_channel))// stop the jams for AIs + sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = sound_channels.lobby_channel))// stop the jams for AIs - var/mob/living/silicon/ai/O = new (loc, GLOB.using_map.default_law_type,,1)//No MMI but safety is in effect. - O.set_invisibility(0) + var/mob/living/silicon/ai/O = new (loc, global.using_map.default_law_type,,1)//No brain but safety is in effect. + O.set_invisibility(INVISIBILITY_NONE) O.aiRestorePowerRoutine = 0 if(mind) mind.transfer_to(O) - O.mind.original = O else O.key = key if(move) var/obj/loc_landmark - for(var/obj/effect/landmark/start/sloc in landmarks_list) + for(var/obj/abstract/landmark/start/sloc in global.all_landmarks) if (sloc.name != "AI") continue if (locate(/mob/living) in sloc.loc) continue loc_landmark = sloc if (!loc_landmark) - for(var/obj/effect/landmark/tripai in landmarks_list) + for(var/obj/abstract/landmark/tripai in global.all_landmarks) if (tripai.name == "tripai") if((locate(/mob/living) in tripai.loc) || (locate(/obj/structure/aicore) in tripai.loc)) continue loc_landmark = tripai if (!loc_landmark) to_chat(O, "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone.") - for(var/obj/effect/landmark/start/sloc in landmarks_list) + for(var/obj/abstract/landmark/start/sloc in global.all_landmarks) if (sloc.name == "AI") loc_landmark = sloc O.forceMove(loc_landmark ? loc_landmark.loc : get_turf(src)) @@ -100,102 +98,67 @@ O.add_ai_verbs() O.rename_self("ai",1) - spawn(0) // Mobs still instantly del themselves, thus we need to spawn or O will never be returned - qdel(src) + qdel(src) return O //human -> robot -/mob/living/carbon/human/proc/Robotize(var/supplied_robot_type = /mob/living/silicon/robot) +/mob/living/human/proc/Robotize(var/supplied_robot_type = /mob/living/silicon/robot) if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return QDEL_NULL_LIST(worn_underwear) - for(var/obj/item/W in src) - drop_from_inventory(W) - regenerate_icons() + for(var/obj/item/thing in src) + drop_from_inventory(thing) + try_refresh_visible_overlays() ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) icon = null - set_invisibility(101) - for(var/t in organs) + set_invisibility(INVISIBILITY_ABSTRACT) + for(var/t in get_external_organs()) qdel(t) var/mob/living/silicon/robot/O = new supplied_robot_type( loc ) - O.gender = gender - O.set_invisibility(0) + O.set_gender(gender) + O.set_invisibility(INVISIBILITY_NONE) - if(mind) - mind.transfer_to(O) - if(O.mind && O.mind.assigned_role == "Robot") - O.mind.original = O - var/mmi_type = SSrobots.get_mmi_type_by_title(O.mind.role_alt_title ? O.mind.role_alt_title : O.mind.assigned_role) - if(mmi_type) - O.mmi = new mmi_type(O) - O.mmi.transfer_identity(src) - if(O.key != key) - O.key = key + if(!mind) + mind_initialize() + mind.assigned_role = ASSIGNMENT_ROBOT + mind.active = TRUE + mind.transfer_to(O) + if(O.mind && O.mind.assigned_role == ASSIGNMENT_ROBOT) + var/mmi_type = SSrobots.get_brain_type_by_title(O.mind.role_alt_title ? O.mind.role_alt_title : O.mind.assigned_role) + if(mmi_type) + O.central_processor = new mmi_type(O) O.dropInto(loc) - O.job = "Robot" - callHook("borgify", list(O)) + O.job = ASSIGNMENT_ROBOT + RAISE_EVENT(/decl/observ/cyborg_created, O) O.Namepick() - qdel(src) // Queues us for a hard delete - return O - -/mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num) - if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) - return - for(var/obj/item/W in src) - drop_from_inventory(W) - regenerate_icons() - ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) - icon = null - set_invisibility(101) - for(var/t in organs) - qdel(t) - - var/mob/living/carbon/slime/new_slime - if(reproduce) - var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring) - var/list/babies = list() - for(var/i=1,i<=number,i++) - var/mob/living/carbon/slime/M = new/mob/living/carbon/slime(loc) - M.set_nutrition(round(nutrition/number)) - step_away(M,src) - babies += M - new_slime = pick(babies) - else - new_slime = new /mob/living/carbon/slime(loc) - if(adult) - new_slime.is_adult = 1 - else - new_slime.key = key - - to_chat(new_slime, "You are now a slime. Skreee!") qdel(src) - return + return O -/mob/living/carbon/human/proc/corgize() +/mob/living/human/proc/corgize() if (HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return - for(var/obj/item/W in src) - drop_from_inventory(W) - regenerate_icons() + for(var/obj/item/thing in src) + drop_from_inventory(thing) + try_refresh_visible_overlays() ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) icon = null - set_invisibility(101) - for(var/t in organs) //this really should not be necessary + set_invisibility(INVISIBILITY_ABSTRACT) + for(var/t in get_external_organs()) //this really should not be necessary qdel(t) var/mob/living/simple_animal/corgi/new_corgi = new /mob/living/simple_animal/corgi (loc) - new_corgi.a_intent = I_HURT + new_corgi.set_intent(get_intent()) new_corgi.key = key to_chat(new_corgi, "You are now a Corgi. Yap Yap!") qdel(src) return -/mob/living/carbon/human/Animalize() +/mob/living/human/Animalize() var/list/mobtypes = typesof(/mob/living/simple_animal) var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes @@ -206,26 +169,25 @@ if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(src)) return - for(var/obj/item/W in src) - drop_from_inventory(W) + for(var/obj/item/thing in src) + drop_from_inventory(thing) - regenerate_icons() + try_refresh_visible_overlays() ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) icon = null - set_invisibility(101) + set_invisibility(INVISIBILITY_ABSTRACT) - for(var/t in organs) + for(var/t in get_external_organs()) qdel(t) var/mob/new_mob = new mobpath(src.loc) new_mob.key = key - new_mob.a_intent = I_HURT + new_mob.set_intent(get_intent()) to_chat(new_mob, "You suddenly feel more... animalistic.") - spawn() - qdel(src) + qdel(src) return /mob/proc/Animalize() @@ -240,8 +202,8 @@ var/mob/new_mob = new mobpath(src.loc) new_mob.key = key - new_mob.a_intent = I_HURT - to_chat(new_mob, "You feel more... animalistic") + new_mob.set_intent(get_intent()) + to_chat(new_mob, "You feel more... animalistic.") qdel(src) @@ -256,20 +218,8 @@ if(!MP) return 0 //Sanity, this should never happen. - if(ispath(MP, /mob/living/simple_animal/construct/behemoth)) - return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/armoured)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/wraith)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/builder)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - //Good mobs! - if(ispath(MP, /mob/living/simple_animal/cat)) + if(ispath(MP, /mob/living/simple_animal/passive/cat)) return 1 if(ispath(MP, /mob/living/simple_animal/corgi)) return 1 @@ -279,40 +229,37 @@ return 1 if(ispath(MP, /mob/living/simple_animal/mushroom)) return 1 - if(ispath(MP, /mob/living/simple_animal/shade)) - return 1 if(ispath(MP, /mob/living/simple_animal/tomato)) return 1 - if(ispath(MP, /mob/living/simple_animal/mouse)) - return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak) + if(ispath(MP, /mob/living/simple_animal/passive/mouse)) + return 1 if(ispath(MP, /mob/living/simple_animal/hostile/bear)) - return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak) - if(ispath(MP, /mob/living/simple_animal/hostile/retaliate/parrot)) - return 1 //Parrots are no longer unfinished! -Nodrak + return 1 + if(ispath(MP, /mob/living/simple_animal/hostile/parrot)) + return 1 //Not in here? Must be untested! return 0 -/mob/living/carbon/human/proc/zombify() - ChangeToHusk() - mutations |= MUTATION_CLUMSY +/mob/living/human/proc/zombify() + add_genetic_condition(GENE_COND_HUSK) + add_genetic_condition(GENE_COND_CLUMSY) src.visible_message("\The [src]'s skin decays before your very eyes!", "Your entire body is ripe with pain as it is consumed down to flesh and bones. You ... hunger. Not only for flesh, but to spread this gift.") if (src.mind) - if (src.mind.special_role == "Zombie") + if (src.mind.assigned_special_role == "Zombie") return - src.mind.special_role = "Zombie" + src.mind.assigned_special_role = "Zombie" log_admin("[key_name(src)] has transformed into a zombie!") - Weaken(5) + SET_STATUS_MAX(src, STAT_WEAK, 5) if (should_have_organ(BP_HEART)) - vessel.add_reagent(species.blood_reagent, species.blood_volume - vessel.total_volume) - for (var/o in organs) + adjust_blood(species.blood_volume - REAGENT_TOTAL_VOLUME(vessel)) + for (var/o in get_external_organs()) var/obj/item/organ/organ = o - organ.vital = 0 if (!BP_IS_PROSTHETIC(organ)) organ.rejuvenate(1) organ.max_damage *= 3 - organ.min_broken_damage = Floor(organ.max_damage * 0.75) + organ.min_broken_damage = floor(organ.max_damage * 0.75) verbs += /mob/living/proc/breath_death verbs += /mob/living/proc/consume playsound(get_turf(src), 'sound/hallucinations/wail.ogg', 20, 1) \ No newline at end of file diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm deleted file mode 100644 index 000c2822777b..000000000000 --- a/code/modules/mob/typing_indicator.dm +++ /dev/null @@ -1,71 +0,0 @@ -/*Typing indicators, when a mob uses the F3/F4 keys to bring the say/emote input boxes up this little buddy is -made and follows them around until they are done (or something bad happens), helps tell nearby people that 'hey! -I IS TYPIN'!' -*/ - -/mob - var/atom/movable/overlay/typing_indicator/typing_indicator = null - -/atom/movable/overlay/typing_indicator - follow_proc = /atom/movable/proc/move_to_turf_or_null - icon = 'icons/mob/talk.dmi' - icon_state = "typing" - -/atom/movable/overlay/typing_indicator/Initialize() - . = ..() - if(!istype(master, /mob)) - crash_with("Master of typing_indicator has invalid type: [master.type].") - -/atom/movable/overlay/typing_indicator/Destroy() - var/mob/M = master - M.typing_indicator = null - . = ..() - -/atom/movable/overlay/typing_indicator/SetInitLoc() - forceMove(get_turf(master)) - -/mob/proc/create_typing_indicator() - if(client && !stat && get_preference_value(/datum/client_preference/show_typing_indicator) == GLOB.PREF_SHOW && !src.is_cloaked() && isturf(src.loc)) - if(!typing_indicator) - typing_indicator = new(src) - typing_indicator.set_invisibility(0) - - var/matrix/M = matrix() - M.Scale(0,0) - typing_indicator.transform = M - typing_indicator.alpha = 0 - animate(typing_indicator, transform = 0, alpha = 255, time = 0.2 SECONDS, easing = EASE_IN) - -/mob/proc/remove_typing_indicator() // A bit excessive, but goes with the creation of the indicator I suppose - if(typing_indicator) - animate(typing_indicator, alpha = 0, time = 0.5 SECONDS, easing = EASE_IN) - addtimer(CALLBACK(typing_indicator, /atom/proc/set_invisibility, INVISIBILITY_MAXIMUM), 0.5 SECONDS) - -/mob/set_stat(new_stat) - . = ..() - if(.) - remove_typing_indicator() - -/mob/Logout() - remove_typing_indicator() - . = ..() - -/mob/verb/say_wrapper() - set name = ".Say" - set hidden = 1 - - create_typing_indicator() - var/message = input("","say (text)") as text|null - remove_typing_indicator() - if(message) - say_verb(message) - -/mob/verb/me_wrapper() - set name = ".Me" - set hidden = 1 - - create_typing_indicator() - var/message = input("","me (text)") as text|null - remove_typing_indicator() - if(message) - me_verb(message) diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm index d2b78624b772..4ba18ab7bdaa 100644 --- a/code/modules/mob/update_icons.dm +++ b/code/modules/mob/update_icons.dm @@ -1,65 +1,65 @@ -//Most of these are defined at this level to reduce on checks elsewhere in the code. -//Having them here also makes for a nice reference list of the various overlay-updating procs available +// TODO: look at all uses of this and refresh_visible_overlays(), probably should be using update_icon(). +/mob/proc/try_refresh_visible_overlays() + SHOULD_CALL_PARENT(TRUE) + if(HasMovementHandler(/datum/movement_handler/mob/transformation) || QDELETED(src)) + return FALSE + refresh_visible_overlays() + apply_visible_overlays() + return TRUE -/mob/proc/regenerate_icons() //TODO: phase this out completely if possible - return +/mob/proc/refresh_visible_overlays() + SHOULD_CALL_PARENT(TRUE) + for(var/slot in get_inventory_slots()) + update_equipment_overlay(slot, FALSE) + return TRUE -/mob/proc/update_icons() - return +/mob/proc/apply_visible_overlays() + cut_overlays() + for(var/overlay in get_all_current_mob_overlays()) + add_overlay(overlay) + underlays = get_all_current_mob_underlays() -/mob/proc/update_hud() - return +/mob/proc/update_equipment_overlay(var/slot, var/redraw_mob = TRUE) + var/datum/inventory_slot/inv_slot = slot && get_inventory_slot_datum(slot) + if(inv_slot) + inv_slot.update_mob_equipment_overlay(src, null, redraw_mob) -/mob/proc/update_inv_handcuffed() - return +/mob/proc/update_inhand_overlays(var/redraw_mob = TRUE) + var/list/hand_overlays = null + for(var/hand_slot in get_held_item_slots()) + var/datum/inventory_slot/inv_slot = get_inventory_slot_datum(hand_slot) + var/obj/item/held = inv_slot?.get_equipped_item() + var/image/standing = held?.get_mob_overlay(src, inv_slot.overlay_slot, hand_slot, inv_slot.use_overlay_fallback_slot) + if(standing) + standing.appearance_flags |= (RESET_ALPHA|RESET_COLOR) + LAZYADD(hand_overlays, standing) + set_current_mob_overlay(HO_INHAND_LAYER, hand_overlays, redraw_mob) -/mob/proc/update_inv_back() +/mob/proc/get_current_mob_overlay(var/overlay_layer) return -/mob/proc/update_inv_l_hand() +/mob/proc/get_all_current_mob_overlays() return -/mob/proc/update_inv_r_hand() - return +/mob/proc/set_current_mob_overlay(var/overlay_layer, var/image/overlay, var/redraw_mob = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(redraw_mob) + cut_overlays() + apply_visible_overlays() -/mob/proc/update_inv_wear_mask() +/mob/proc/get_current_mob_underlay(var/underlay_layer) return -/mob/proc/update_inv_wear_suit() +/mob/proc/get_all_current_mob_underlays() return -/mob/proc/update_inv_w_uniform() - return +/mob/proc/set_current_mob_underlay(var/underlay_layer, var/image/underlay, var/redraw_mob = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(redraw_mob) + queue_icon_update() -/mob/proc/update_inv_belt() +/mob/proc/update_genetic_conditions() return -/mob/proc/update_inv_head() - return - -/mob/proc/update_inv_gloves() - return - -/mob/proc/update_mutations() - return - -/mob/proc/update_inv_wear_id() - return - -/mob/proc/update_inv_shoes() - return - -/mob/proc/update_inv_glasses() - return - -/mob/proc/update_inv_s_store() - return - -/mob/proc/update_inv_pockets() - return - -/mob/proc/update_inv_ears() - return - -/mob/proc/update_targeted() - return +/mob/proc/update_hair(var/update_icons=1) + return \ No newline at end of file diff --git a/code/modules/mob_holder/_holder.dm b/code/modules/mob_holder/_holder.dm new file mode 100644 index 000000000000..3cc51f873e18 --- /dev/null +++ b/code/modules/mob_holder/_holder.dm @@ -0,0 +1,164 @@ +//Helper object for picking creatures up. +/obj/item/holder + name = "holder" + desc = "You shouldn't ever see this." + icon = 'icons/obj/items/holder.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_HEAD | SLOT_HOLSTER + pixel_y = 8 + origin_tech = @'{"biotech":1}' + use_single_icon = TRUE + item_state = null + is_spawnable_type = FALSE + max_health = ITEM_HEALTH_NO_DAMAGE + var/last_holder + +/obj/item/holder/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/holder/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + clear_vis_contents() + for(var/atom/movable/AM in src) + AM.vis_flags |= (VIS_INHERIT_ID|VIS_INHERIT_LAYER|VIS_INHERIT_PLANE) + add_vis_contents(AM) + +/obj/item/holder/examined_by(mob/user, distance, infix, suffix) + for(var/atom/thing in get_contained_external_atoms()) + thing.examined_by(user, distance, infix, suffix) + return TRUE + +// No scooping mobs and handing them to people who can't scoop them. +/obj/item/holder/equipped(mob/user, slot) + . = ..() + for(var/mob/living/mob in contents) + if(!mob.scoop_check(user)) + to_chat(user, SPAN_DANGER("You are unable to keep hold of \the [src]!")) + user.drop_from_inventory(src) + break + +// Grab our inhands from the mob we're wrapping, if they have any. +/obj/item/holder/get_mob_overlay(mob/user_mob, slot, bodypart, use_fallback_if_icon_missing = TRUE, skip_adjustment = FALSE) + var/mob/M = locate() in contents + if(istype(M)) + icon = M.get_holder_icon() + var/image/ret = ..() + if(ret) + if(istype(M)) + ret.color = M.get_holder_color() + . = ret + icon = initial(icon) + +/obj/item/holder/Exited(atom/movable/am, atom/new_loc) + if(!(locate(/mob) in contents)) + am.vis_flags = initial(am.vis_flags) + . = ..() + +/obj/item/holder/proc/destroy_all() + for(var/atom/movable/AM in src) + qdel(AM) + qdel(src) + +/obj/item/holder/physically_destroyed() + SHOULD_CALL_PARENT(FALSE) + destroy_all() + +/obj/item/holder/Destroy() + clear_vis_contents() + for(var/atom/movable/AM in src) + unregister_all_movement(last_holder, AM) + AM.vis_flags = initial(AM.vis_flags) + AM.forceMove(get_turf(src)) + last_holder = null + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/holder/Process() + update_state() + +/obj/item/holder/dropped() + . = ..() + update_state(1) + +/obj/item/holder/throw_impact(atom/hit_atom, datum/thrownthing/TT) + . = ..() + update_state(1) + +/obj/item/holder/proc/update_state(var/delay) + set waitfor = FALSE + + for(var/mob/M in contents) + unregister_all_movement(last_holder, M) + + if(delay) + sleep(delay) + + if(QDELETED(src) || throwing) + return + + if(istype(loc,/turf) || !contents.len) + for(var/mob/M in contents) + var/atom/movable/mob_container = M + mob_container.dropInto(loc) + M.reset_view() + qdel(src) + return + + if(last_holder != loc) + for(var/mob/M in contents) + register_all_movement(loc, M) + update_icon() + last_holder = loc + +/obj/item/holder/onDropInto(var/atom/movable/AM) + if(ismob(loc)) // Bypass our holding mob and drop directly to its loc + return loc.loc + return ..() + +/obj/item/holder/GetIdCards(list/exceptions) + . = ..() + for(var/mob/M in contents) + var/list/cards = M.GetIdCards(exceptions) + if(length(cards)) + LAZYDISTINCTADD(., cards) + +/obj/item/holder/attack_self(mob/user) + for(var/mob/M in contents) + M.show_stripping_window(user) + +/obj/item/holder/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + // Devour on click on self with holder + if(target == user && isliving(user)) + var/mob/living/M = user + for(var/mob/victim in src.contents) + M.devour(victim) + update_state() + return TRUE + + return ..() + +/obj/item/holder/proc/sync(var/mob/living/M) + + SetName(M.name) + desc = M.desc + + if(QDELETED(src) || QDELETED(M) || !istype(M)) + set_light(0) + else + set_light(M.light_range, M.light_power, M.light_color) + + var/mob/living/human/H = loc + if(istype(H)) + last_holder = H + register_all_movement(H, M) + update_icon() + update_held_icon() + +/obj/item/holder/attackby(obj/item/used_item, mob/user) + for(var/mob/M in src.contents) + . = M.attackby(used_item,user) + if(.) + return + return FALSE \ No newline at end of file diff --git a/code/modules/mob_holder/holder_mobs.dm b/code/modules/mob_holder/holder_mobs.dm new file mode 100644 index 000000000000..16ebd454351e --- /dev/null +++ b/code/modules/mob_holder/holder_mobs.dm @@ -0,0 +1,62 @@ +/mob/proc/get_holder_icon() + return icon + +/mob/proc/get_holder_color() + return color + +/mob/living/human/get_holder_icon() + return species.holder_icon || ..() + +/mob/living/human/get_holder_color() + return species.get_holder_color(src) + +//Mob procs for scooping up +/mob/living/proc/get_scooped(mob/living/target, mob/living/initiator, silent = FALSE) + + if(!holder_type || buckled || LAZYLEN(pinned)) + return FALSE + + if(initiator.incapacitated()) + return FALSE + + var/obj/item/holder/H = new holder_type(get_turf(src)) + H.w_class = get_object_size() + if(initiator == src) + if(!target.equip_to_slot_if_possible(H, slot_back_str, del_on_fail=0, disable_warning=1) && !target.put_in_hands(H)) + if(!silent) + to_chat(initiator, SPAN_WARNING("You can't climb onto [target]!")) + return FALSE + if(!silent) + to_chat(target, SPAN_NOTICE("\The [src] clambers onto you!")) + to_chat(initiator, SPAN_NOTICE("You climb up onto \the [target]!")) + else + if(!ai?.scooped_by(initiator)) + return FALSE // The AI canceled the scooping. + + if(!target.put_in_hands(H)) + if(!silent) + to_chat(initiator, SPAN_WARNING("Your hands are full!")) + return FALSE + + if(!silent) + to_chat(initiator, SPAN_NOTICE("You scoop up \the [src]!")) + to_chat(src, SPAN_NOTICE("\The [initiator] scoops you up!")) + + forceMove(H) + reset_offsets(0) + + target.status_flags |= PASSEMOTES + H.sync(src) + return H + +/mob/living/proc/scoop_check(var/mob/living/scooper) + if(!isliving(scooper) || scooper == src || scooper.current_posture.prone) + return FALSE + if(QDELETED(scooper) || QDELETED(src)) + return FALSE + if(istype(loc, /obj/item/holder)) + if(loc.CanUseTopicPhysical(scooper) != STATUS_INTERACTIVE) + return FALSE + else if(!CanPhysicallyInteract(scooper)) + return FALSE + return !!holder_type && scooper.mob_size > src.mob_size diff --git a/code/modules/mob_holder/holder_subtypes.dm b/code/modules/mob_holder/holder_subtypes.dm new file mode 100644 index 000000000000..c7ad36e8a9f7 --- /dev/null +++ b/code/modules/mob_holder/holder_subtypes.dm @@ -0,0 +1,8 @@ +//Mob specific holders. +/obj/item/holder/drone + origin_tech = @'{"magnets":3,"engineering":5}' + +//need own subtype to work with recipes +/obj/item/holder/corgi + name = "corgi" + origin_tech = @'{"biotech":4}' diff --git a/code/modules/mob_modifiers/_modifiers.dm b/code/modules/mob_modifiers/_modifiers.dm new file mode 100644 index 000000000000..cd019876af4e --- /dev/null +++ b/code/modules/mob_modifiers/_modifiers.dm @@ -0,0 +1,89 @@ +// Notes on mob modifiers: +// - added/removed from mob with add_mob_modifier(/decl/mob_modifier/foo, DURATION IN DS, source = SOME ATOM) +// - decl will generate a decl/mob_modifier based on the source of the modifier +// - decl heartbeat logic (actual modifier) will run once per life tick regardless of number of sources, if you want +// stacking modifiers it has to be implemented within the decl. + +/// Instanced 'modifiers' that sit on top of a mob and can expire over time or linger until dispelled. +/// Some are purely visual, others have associated modifiers. +/decl/mob_modifier + abstract_type = /decl/mob_modifier + /// Tooltip name of this modifier. + var/name + /// Tooltip description of this modifier. + var/desc + /// Icon to use for the HUD element. + var/hud_icon = 'icons/screen/mob_modifiers.dmi' + /// State to use for the HUD element. + var/hud_icon_state + /// Icon to draw from for the mob overlay modifier is present. + var/mob_overlay_icon + /// State to draw over the mob when modifier is present. + var/mob_overlay_state + /// Metadata type to create for this status modifier. + var/modifier_type = /datum/mob_modifier + /// Message shown to the target when modifier begins. + var/on_add_message_1p + /// Message shown to the audience when modifier begins. + var/on_add_message_3p + /// Message shown to the target when modifier ends. + var/on_end_message_1p + /// Message shown to the audience when modifier ends. + var/on_end_message_3p + /// Whether or not this modifier can be granted by admin (source-ambivalent) + var/can_be_admin_granted = FALSE + /// Whether or not this modifier shows a lemniscate when set to indefinite duration. + var/show_indefinite_duration = TRUE + /// Whether or not this modifier shows remaining time before expiry. + var/hide_expiry= FALSE + +/decl/mob_modifier/validate() + . = ..() + if(!hud_icon) + . += "no hud_icon set" + if(!istext(hud_icon_state)) + . += "null or invalid hud_icon_state" + if(hud_icon && hud_icon_state && !check_state_in_icon(hud_icon_state, hud_icon)) + . += "hud_icon '[hud_icon]' missing hud_icon_state '[hud_icon_state]'" + + if(mob_overlay_icon) + if(istext(mob_overlay_state)) + if(!check_state_in_icon(mob_overlay_state, mob_overlay_icon)) + . += "mob_overlay_icon '[mob_overlay_icon]' missing mob_overlay_state '[mob_overlay_state]'" + else + . += "null or invalid mob_overlay_state" + else if(mob_overlay_state) + . += "mob_overlay_state set but mob_overlay_icon not set" + +/decl/mob_modifier/proc/replace_tokens(message, mob/user) + return capitalize_proper_html(emote_replace_user_tokens(message, user)) + +/decl/mob_modifier/proc/on_modifier_datum_added(mob/living/_owner, datum/mob_modifier/modifier) + if(on_add_message_3p) + _owner.visible_message(replace_tokens(on_add_message_3p, _owner), replace_tokens((on_add_message_3p || on_add_message_1p), _owner)) + else if(on_add_message_1p) + to_chat(_owner, replace_tokens(on_add_message_1p, _owner)) + return TRUE + +/decl/mob_modifier/proc/on_modifier_datum_removed(mob/living/_owner, datum/mob_modifier/modifier) + if(on_end_message_3p) + _owner.visible_message(replace_tokens(on_end_message_3p, _owner), replace_tokens((on_end_message_3p || on_end_message_1p), _owner)) + else if(on_end_message_1p) + to_chat(_owner, replace_tokens(on_end_message_1p, _owner)) + return TRUE + +/decl/mob_modifier/proc/on_modifier_datum_expiry(mob/living/_owner, datum/mob_modifier/modifier) + return TRUE + +/decl/mob_modifier/proc/on_modifier_datum_mob_life(mob/living/_owner, list/modifiers) + SHOULD_CALL_PARENT(TRUE) + . = FALSE + for(var/datum/mob_modifier/modifier in modifiers) + if(modifier.on_modifier_mob_life()) + . = TRUE + +/decl/mob_modifier/proc/on_modifier_datum_click(mob/living/_owner, datum/mob_modifier/modifier, params) + return FALSE + +/decl/mob_modifier/proc/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + return FALSE diff --git a/code/modules/mob_modifiers/definitions/modifiers_cloaked.dm b/code/modules/mob_modifiers/definitions/modifiers_cloaked.dm new file mode 100644 index 000000000000..5ac1889ce59e --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_cloaked.dm @@ -0,0 +1,17 @@ +/decl/mob_modifier/cloaked + name = "Cloaked" + desc = "You are hidden from casual sight." + hud_icon_state = "cloaked" + on_add_message_1p = SPAN_NOTICE("You feel completely invisible.") + on_add_message_3p = SPAN_WARNING("$USER$ seems to disappear before your eyes!") + on_end_message_1p = SPAN_NOTICE("You have re-appeared.") + on_end_message_3p = SPAN_WARNING("$USER$ appears from thin air!") + can_be_admin_granted = TRUE + +// Not ideal, but existing cloaking code is iffy about removing cloaking sources appropriately (specifically rig modules) +/decl/mob_modifier/cloaked/on_modifier_datum_mob_life(mob/living/_owner, list/modifiers) + . = ..() + for(var/datum/mob_modifier/modifier in modifiers) + var/atom/source = modifier.source?.resolve() + if(istype(source) && source.get_recursive_loc_of_type(/mob/living) != _owner) + _owner.remove_mob_modifier(src, source = source) diff --git a/code/modules/mob_modifiers/definitions/modifiers_light.dm b/code/modules/mob_modifiers/definitions/modifiers_light.dm new file mode 100644 index 000000000000..9b352184cb7f --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_light.dm @@ -0,0 +1,39 @@ +/datum/mob_modifier/object/light + var/light_range = 6 + var/light_power = 6 + var/light_color = COLOR_BEIGE + +/decl/mob_modifier/light + name = "Light Aura" + desc = "You are emitting a gentle radiance." + hud_icon_state = "light" + on_add_message_1p = SPAN_NOTICE("A gentle radiance emanates from your body.") + on_end_message_1p = SPAN_NOTICE("The light spilling from your body fades.") + modifier_type = /datum/mob_modifier/object/light + can_be_admin_granted = TRUE + +/datum/mob_modifier/object/light/on_modifier_added(skip_update) + . = ..() + if(istype(object) && (light_range || light_power || light_color)) + object.set_light(light_range, light_power, light_color) + +/decl/mob_modifier/light/radiant + name = "Radiant Aura" + desc = "You are guarded from laser weapons by a radiant aura." + mob_overlay_icon = 'icons/effects/effects.dmi' + mob_overlay_state = "fire_goon" + on_add_message_1p = SPAN_NOTICE("A bubble of light appears around you, exuding protection and warmth.") + on_end_message_1p = SPAN_DANGER("Your protective aura dissipates, leaving you feeling cold and unsafe.") + modifier_type = /datum/mob_modifier/object/light + +/datum/mob_modifier/object/light/radiant + light_color = "#e09d37" + +/decl/mob_modifier/light/radiant/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + if(attack_type != MM_ATTACK_TYPE_PROJECTILE) + return ..() + var/obj/item/projectile/projectile = attacker + if(istype(projectile) && (projectile.damage_flags() & DAM_LASER)) + _owner.visible_message(SPAN_WARNING("\The [projectile] refracts, bending into \the [_owner]'s radiance.")) + return (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + return MM_ATTACK_RESULT_NONE diff --git a/code/modules/mob_modifiers/definitions/modifiers_mech_shields.dm b/code/modules/mob_modifiers/definitions/modifiers_mech_shields.dm new file mode 100644 index 000000000000..0c8d4112507f --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_mech_shields.dm @@ -0,0 +1,166 @@ +/decl/mob_modifier/mechshield + name = "Mech Energy Shield" + hud_icon_state = "shield" + modifier_type = /datum/mob_modifier/object/mechshield + +/decl/mob_modifier/mechshield/on_modifier_datum_added(mob/living/_owner, datum/mob_modifier/modifier) + . = ..() + if(istype(modifier, /datum/mob_modifier/object)) + var/datum/mob_modifier/object/obj_modifier = modifier + if(istype(obj_modifier.object)) + flick("shield_raise", obj_modifier.object) + +/decl/mob_modifier/mechshield/on_modifier_datum_removed(mob/living/_owner, datum/mob_modifier/modifier) + if(istype(modifier, /datum/mob_modifier/object)) + var/datum/mob_modifier/object/obj_modifier = modifier + if(istype(obj_modifier.object)) + var/obj/effect/temporary/drop_shield = new(get_turf(_owner)) + drop_shield.appearance = obj_modifier.object + flick("shield_drop", drop_shield) + QDEL_IN(drop_shield, 1 SECOND) + return ..() + +/datum/mob_modifier/object/mechshield + object = /obj/abstract/follower/mechshield + +/obj/abstract/follower/mechshield + name = "mechshield" + layer = ABOVE_HUMAN_LAYER + plane = DEFAULT_PLANE + icon = 'icons/mecha/shield.dmi' + icon_state = "shield" + pixel_x = 8 + pixel_y = 4 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + invisibility = INVISIBILITY_NONE + alpha = 255 + hide_on_init = FALSE + +/obj/abstract/follower/mechshield/follow_owner(atom/movable/owner) + . = ..() + layer = (dir == NORTH) ? MECH_UNDER_LAYER : initial(layer) + +/decl/mob_modifier/mechshield/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + + if(attack_type == MM_ATTACK_TYPE_WEAPON) + return ..() + + . = MM_ATTACK_RESULT_NONE + var/shield_hit = FALSE + if(attack_type == MM_ATTACK_TYPE_PROJECTILE) + + var/obj/item/projectile/projectile = attacker + if(!istype(projectile)) + return + + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/mech_equipment/shields/shield = modifier.source?.resolve() + if(!istype(shield) || !shield.charge) + continue + if(!shield_hit) + _owner.visible_message(SPAN_WARNING("\The [shield.owner]'s shields flash and crackle.")) + shield_hit = TRUE + new /obj/effect/effect/smoke/illumination(_owner.loc, 5, 4, 1, "#ffffff") + spark_at(_owner, amount=5) + projectile.damage = shield.stop_damage(projectile.damage) + if(projectile.damage <= 0) + . = (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + + else if(attack_type == MM_ATTACK_TYPE_THROWN) + + var/datum/thrownthing/thrown = additional_data + if(!istype(thrown) || thrown.speed > 5) + return + + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/mech_equipment/shields/shield = modifier.source?.resolve() + if(istype(shield) && shield.charge) + _owner.visible_message(SPAN_WARNING("\The [shield.owner]'s shields flash briefly as they deflect \the [thrown.thrownthing].")) + shield_hit = TRUE + . = (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + break + + //light up the night. + if(shield_hit) + playsound(_owner,'sound/effects/basscannon.ogg', 20, 1) + for(var/datum/mob_modifier/object/mechshield/obj_modifier in modifiers) + if(obj_modifier.object) + flick("shield_impact", obj_modifier.object) + +/decl/mob_modifier/mech_ballistic + name = "Mech Ballistic Shield" + hud_icon_state = "nanomachines" + modifier_type = /datum/mob_modifier/object/mechshield_ballistic + +/datum/mob_modifier/object/mechshield_ballistic + object = /obj/abstract/follower/mechshield_ballistic + +/datum/mob_modifier/object/mechshield_ballistic/on_modifier_added(skip_update = FALSE) + . = ..() + var/obj/item/mech_equipment/source_atom = source?.resolve() + if(!istype(source_atom) || !istype(object) || !istype(owner, /mob/living/exosuit)) + return + var/mob/living/exosuit/mech = owner + for(var/hardpoint in mech.hardpoints) + var/obj/item/mech_equipment/hardpoint_object = mech.hardpoints[hardpoint] + if(source_atom != hardpoint_object) + continue + object.icon_state = "mech_shield_[hardpoint]" + var/image/mech_overlay = image(object.icon, "[object.icon_state]_over") + mech_overlay.layer = ABOVE_HUMAN_LAYER + object.add_overlay(mech_overlay, priority = TRUE) + +/obj/abstract/follower/mechshield_ballistic + icon = 'icons/mecha/ballistic_shield.dmi' + layer = MECH_UNDER_LAYER + plane = DEFAULT_PLANE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + invisibility = INVISIBILITY_NONE + alpha = 255 + hide_on_init = FALSE + +/decl/mob_modifier/mech_ballistic/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + + if(attack_type == MM_ATTACK_TYPE_PROJECTILE) + + var/obj/item/projectile/projectile = attacker + if(istype(projectile)) + + var/target_zone = BP_CHEST + if(isliving(attacker)) + var/mob/living/attacker_mob = attacker + target_zone = attacker_mob.get_target_zone() + + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/mech_equipment/ballistic_shield/shield = modifier.source?.resolve() + if(istype(shield) && prob(shield.block_chance(projectile.damage, projectile.armor_penetration, source = projectile))) + _owner.visible_message(SPAN_WARNING("\The [projectile] is blocked by \the [_owner]'s [shield.name].")) + _owner.bullet_impact_visuals(projectile, target_zone, 0) + shield.on_block_attack() + return (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + + else if(attack_type == MM_ATTACK_TYPE_THROWN) + + var/datum/thrownthing/thrown = additional_data + if(istype(thrown)) + var/throw_damage = thrown.thrownthing.get_thrown_attack_force() * (thrown.speed/THROWFORCE_SPEED_DIVISOR) + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/mech_equipment/ballistic_shield/shield = modifier.source?.resolve() + if(istype(shield) && prob(shield.block_chance(throw_damage, 0, source = thrown.thrownthing, attacker = thrown.thrower))) + _owner.visible_message(SPAN_WARNING("\The [thrown.thrownthing] bounces off \the [_owner]'s [shield].")) + playsound(_owner.loc, 'sound/weapons/Genhit.ogg', 50, 1) + shield.on_block_attack() + return (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + + else if(attack_type == MM_ATTACK_TYPE_WEAPON) + + var/obj/item/weapon = additional_data + if(istype(weapon)) + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/mech_equipment/ballistic_shield/shield = modifier.source?.resolve() + if(shield && prob(shield.block_chance(weapon.get_attack_force(), weapon.armor_penetration, source = weapon, attacker = _owner))) + _owner.visible_message(SPAN_WARNING("\The [weapon] is blocked by \the [_owner]'s [shield.name].")) + playsound(_owner.loc, 'sound/weapons/Genhit.ogg', 50, 1) + return (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + + return ..() diff --git a/code/modules/mob_modifiers/definitions/modifiers_object.dm b/code/modules/mob_modifiers/definitions/modifiers_object.dm new file mode 100644 index 000000000000..2904208d8c5e --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_object.dm @@ -0,0 +1,19 @@ +/datum/mob_modifier/object + var/obj/object = /obj/abstract/follower + +/datum/mob_modifier/object/Destroy(force) + if(istype(object)) + if(owner) + events_repository.unregister(/decl/observ/moved, owner, object) + events_repository.unregister(/decl/observ/dir_set, owner, object) + QDEL_NULL(object) + return ..() + +/datum/mob_modifier/object/on_modifier_added(skip_update = FALSE) + . = ..() + if(istype(owner)) + if(ispath(object)) + object = new object(get_turf(owner)) + if(istype(object)) + events_repository.register(/decl/observ/moved, owner, object, TYPE_PROC_REF(/obj/abstract/follower, follow_owner)) + events_repository.register(/decl/observ/dir_set, owner, object, TYPE_PROC_REF(/obj/abstract/follower, follow_owner)) diff --git a/code/modules/mob_modifiers/definitions/modifiers_prone.dm b/code/modules/mob_modifiers/definitions/modifiers_prone.dm new file mode 100644 index 000000000000..caf5b30c53b6 --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_prone.dm @@ -0,0 +1,10 @@ +/decl/mob_modifier/prone + name = "Prone" + desc = "You are lying prone and may need to stand up before taking action." + hud_icon_state = "prone" + show_indefinite_duration = FALSE + +/decl/mob_modifier/prone/on_modifier_datum_click(mob/living/_owner, decl/mob_modifier/modifier, params) + if(_owner.current_posture?.prone) + _owner.lay_down() + return TRUE diff --git a/code/modules/mob_modifiers/definitions/modifiers_regeneration.dm b/code/modules/mob_modifiers/definitions/modifiers_regeneration.dm new file mode 100644 index 000000000000..da18d3f80594 --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_regeneration.dm @@ -0,0 +1,123 @@ +/decl/mob_modifier/regeneration + name = "Regeneration" + desc = "You are rapidly recovering from physical trauma and poisons." + hud_icon_state = "regeneration" + can_be_admin_granted = TRUE + + var/brute_mult = 1 + var/fire_mult = 1 + var/tox_mult = 1 + +/decl/mob_modifier/regeneration/on_modifier_datum_mob_life(mob/living/_owner, list/modifiers) + . = ..() + _owner.heal_damage(BRUTE, brute_mult, do_update_health = FALSE) + _owner.heal_damage(BURN, fire_mult, do_update_health = FALSE) + _owner.heal_damage(TOX, tox_mult) + +/decl/mob_modifier/regeneration/organ + name = "Organ Regeneration" + desc = "Your body is rapidly recovering from physical trauma and poisons, so long as you can feed it." + var/nutrition_damage_mult = 1 //How much nutrition it takes to heal regular damage + var/external_nutrition_mult = 50 // How much nutrition it takes to regrow a limb + var/organ_mult = 2 + var/regen_message = SPAN_WARNING("Your body throbs as you feel your ORGAN regenerate.") + var/grow_chance = 15 + var/grow_threshold = 200 + var/ignore_tag = BP_BRAIN //organ tag to ignore + var/last_nutrition_warning = 0 + var/innate_heal = TRUE // Whether the aura is on, basically. + +/decl/mob_modifier/regeneration/organ/proc/external_regeneration_effect(mob/living/_owner, obj/item/organ/external/limb) + return + +/decl/mob_modifier/regeneration/organ/on_modifier_datum_mob_life(mob/living/_owner, list/modifiers) + . = ..() + if(!length(_owner.get_external_organs())) + return + if(!innate_heal || _owner.has_mob_modifier(/decl/mob_modifier/stasis) || _owner.stat == DEAD) + return + if(_owner.get_nutrition() < nutrition_damage_mult) + low_nut_warning(_owner) + return + + var/update_health = FALSE + var/organ_regen = get_config_value(/decl/config/num/health_organ_regeneration_multiplier) + if(brute_mult && _owner.get_damage(BRUTE)) + update_health = TRUE + _owner.heal_damage(BRUTE, brute_mult * organ_regen, do_update_health = FALSE) + _owner.adjust_nutrition(-nutrition_damage_mult) + if(fire_mult && _owner.get_damage(BURN)) + update_health = TRUE + _owner.heal_damage(BURN, fire_mult * organ_regen, do_update_health = FALSE) + _owner.adjust_nutrition(-nutrition_damage_mult) + if(tox_mult && _owner.get_damage(TOX)) + update_health = TRUE + _owner.heal_damage(TOX, tox_mult * organ_regen, do_update_health = FALSE) + _owner.adjust_nutrition(-nutrition_damage_mult) + if(update_health) + _owner.update_health() + if(!can_regenerate_organs()) + return + if(organ_mult) + if(prob(10) && _owner.nutrition >= 150 && !_owner.get_damage(BRUTE) && !_owner.get_damage(BURN)) + var/obj/item/organ/external/D = GET_EXTERNAL_ORGAN(_owner, BP_HEAD) + if (D.status & ORGAN_DISFIGURED) + if (_owner.nutrition >= 20) + D.status &= ~ORGAN_DISFIGURED + _owner.adjust_nutrition(-20) + else + low_nut_warning(_owner, BP_HEAD) + + var/list/organs = _owner.get_internal_organs() + for(var/obj/item/organ/internal/regen_organ in shuffle(organs.Copy())) + if(BP_IS_PROSTHETIC(regen_organ) || regen_organ.organ_tag == ignore_tag) + continue + if(istype(regen_organ)) + if(regen_organ.get_organ_damage() > 0 && !(regen_organ.status & ORGAN_DEAD)) + if (_owner.nutrition >= organ_mult) + regen_organ.adjust_organ_damage(-(organ_mult)) + _owner.adjust_nutrition(-(organ_mult)) + if(prob(5)) + to_chat(_owner, replacetext(regen_message,"ORGAN", regen_organ.name)) + else + low_nut_warning(_owner, regen_organ.name) + + if(prob(grow_chance)) + var/decl/bodytype/root_bodytype = _owner.get_bodytype() + for(var/limb_type in root_bodytype.has_limbs) + var/obj/item/organ/external/limb = GET_EXTERNAL_ORGAN(_owner, limb_type) + if(limb && limb.organ_tag != BP_HEAD && !limb.is_vital_to_owner() && !limb.is_usable()) //Skips heads and vital bits... + if (_owner.nutrition > grow_threshold) + _owner.remove_organ(limb) //...because no one wants their head to explode to make way for a new one. + qdel(limb) + limb = null + else + low_nut_warning(_owner, limb.name) + if(!limb) + var/list/organ_data = root_bodytype.has_limbs[limb_type] + var/limb_path = organ_data["path"] + limb = new limb_path(_owner) + _owner.add_organ(limb, GET_EXTERNAL_ORGAN(_owner, limb.parent_organ), FALSE, FALSE) + _owner.adjust_nutrition(-external_nutrition_mult) + external_regeneration_effect(_owner, limb) + return + else if (_owner.nutrition > grow_threshold) //We don't subtract any nut here, but let's still only heal wounds when we have nut. + for(var/datum/wound/wound in limb.wounds) + if(wound.wound_damage() == 0 && prob(50)) + qdel(wound) + +/decl/mob_modifier/regeneration/organ/proc/low_nut_warning(mob/living/_owner, var/wound_type) + if (last_nutrition_warning + 1 MINUTE < world.time) + to_chat(_owner, SPAN_WARNING("You need more energy to regenerate your [wound_type || "wounds"].")) + last_nutrition_warning = world.time + return TRUE + return FALSE + +/decl/mob_modifier/regeneration/organ/proc/can_regenerate_organs() + return TRUE + +// Distinct type to avoid removing the wrong type on unwield. +/decl/mob_modifier/regeneration/item + name = "Regenerative Aura" + desc = "An item is helping your body heal physical damage and toxins." + can_be_admin_granted = FALSE \ No newline at end of file diff --git a/code/modules/mob_modifiers/definitions/modifiers_restrained.dm b/code/modules/mob_modifiers/definitions/modifiers_restrained.dm new file mode 100644 index 000000000000..6e281db036be --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_restrained.dm @@ -0,0 +1,9 @@ +/decl/mob_modifier/restrained + name = "Restrained" + desc = "You are restrained and need to resist to get out of your bindings." + hud_icon_state = "restrained" + show_indefinite_duration = FALSE + +/decl/mob_modifier/restrained/on_modifier_datum_click(mob/living/_owner, decl/mob_modifier/modifier, params) + _owner.resist() + return TRUE diff --git a/code/modules/mob_modifiers/definitions/modifiers_shield.dm b/code/modules/mob_modifiers/definitions/modifiers_shield.dm new file mode 100644 index 000000000000..1dcda7a53e11 --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_shield.dm @@ -0,0 +1,45 @@ +/decl/mob_modifier/shield + name = "Energy Shield" + desc = "You are protected from incoming projectiles." + hud_icon_state = "shield" + on_add_message_1p = SPAN_NOTICE("You feel your body prickle as your shield comes online.") + on_end_message_1p = SPAN_WARNING("Your shield goes offline!") + can_be_admin_granted = TRUE + +/decl/mob_modifier/shield/on_modifier_datum_added(mob/living/_owner, decl/mob_modifier/modifier) + . = ..() + if(. && _owner) + playsound(get_turf(_owner), 'sound/weapons/flash.ogg', 35, 1) + +/decl/mob_modifier/shield/on_modifier_datum_removed(mob/living/_owner, decl/mob_modifier/modifier) + . = ..() + if(. && _owner) + playsound(get_turf(_owner), 'sound/mecha/internaldmgalarm.ogg', 25,1) + +/decl/mob_modifier/shield/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + if(attack_type != MM_ATTACK_TYPE_PROJECTILE) + return ..() + var/obj/item/projectile/projectile = attacker + if(istype(projectile)) + _owner.visible_message(SPAN_WARNING("\The [_owner]'s [src] flashes before \the [projectile] can hit them!")) + new /obj/effect/temporary(get_turf(_owner), 2 SECONDS, 'icons/obj/machines/shielding.dmi', "shield_impact") + playsound(_owner,'sound/effects/basscannon.ogg', 35, 1) + return (MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED) + return MM_ATTACK_RESULT_NONE + +/decl/mob_modifier/shield/device + name = "Personal Shield" + desc = "You are protected from incoming projectiles by a personal shielding device - at least until it runs out of charges." + can_be_admin_granted = FALSE // Needs an item. + +/decl/mob_modifier/shield/device/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + var/obj/item/projectile/projectile = attacker + if(!istype(projectile) || attack_type != MM_ATTACK_TYPE_PROJECTILE) + return ..() + var/found_shield = FALSE + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/personal_shield/shield = modifier.source?.resolve() + if(istype(shield) && shield.expend_charge()) + found_shield = TRUE + break + return found_shield ? ..() : MM_ATTACK_RESULT_NONE diff --git a/code/modules/mob_modifiers/definitions/modifiers_stasis.dm b/code/modules/mob_modifiers/definitions/modifiers_stasis.dm new file mode 100644 index 000000000000..8f6aeec4721a --- /dev/null +++ b/code/modules/mob_modifiers/definitions/modifiers_stasis.dm @@ -0,0 +1,25 @@ +/decl/mob_modifier/stasis + name = "Stasis" + desc = "Your life processes have been reduced or halted by stasis." + hud_icon_state = "stasis" + hide_expiry = TRUE + +/decl/mob_modifier/stasis/on_modifier_datum_mob_life(mob/living/_owner, list/modifiers) + . = ..() + + var/decl/bodytype/my_bodytype = _owner.get_bodytype() + if(my_bodytype?.body_flags & BODY_FLAG_NO_STASIS) + return + + var/stasis_power = 0 + for(var/datum/mob_modifier/modifier in modifiers) + var/atom/movable/source_atom = modifier.source?.resolve() + if(istype(source_atom)) + var/add_stasis = source_atom.get_cryogenic_power() + if(add_stasis) + stasis_power += add_stasis + + if(stasis_power > 1 && GET_STATUS(_owner, STAT_DROWSY) < stasis_power * 4) + ADJ_STATUS(_owner, STAT_DROWSY, min(stasis_power, 3)) + if(_owner.stat == CONSCIOUS)// && prob(1)) + to_chat(_owner, SPAN_NOTICE("You feel slow and sluggish...")) diff --git a/code/modules/mob_modifiers/modifiers_datum.dm b/code/modules/mob_modifiers/modifiers_datum.dm new file mode 100644 index 000000000000..d7bc334dc528 --- /dev/null +++ b/code/modules/mob_modifiers/modifiers_datum.dm @@ -0,0 +1,75 @@ +// Subtype for tracking timer etc. No actual behavior associated with these. +/datum/mob_modifier + var/mob/living/owner + var/decl/mob_modifier/archetype + var/expire_time = MOB_MODIFIER_INDEFINITE + var/weakref/source + +/datum/mob_modifier/New(decl/mob_modifier/_archetype, mob/living/_owner, datum/_source) + archetype = istype(_archetype) ? _archetype : GET_DECL(_archetype) + owner = _owner + source = weakref(_source) + +/datum/mob_modifier/Destroy(force) + owner = null + return ..() + +// returns TRUE if the owner needs to run an update on mob modifiers following this run. +/datum/mob_modifier/proc/on_modifier_mob_life() + SHOULD_CALL_PARENT(TRUE) + . = FALSE + // We should not exist without an owner. + if(!istype(owner)) + qdel(src) + return TRUE + // Count down our timer, if necessary. + if(expire_time != MOB_MODIFIER_INDEFINITE) + . = TRUE + if(world.time >= expire_time) + on_modifier_expiry() + +/datum/mob_modifier/proc/on_modifier_removed(skip_update = FALSE) + SHOULD_CALL_PARENT(TRUE) + if(!istype(owner)) + return FALSE + var/list/modifiers = LAZYACCESS(owner._mob_modifiers, archetype) + if(!length(modifiers)) + return FALSE + modifiers -= src + // If this was our last modifier, clear the list. + if(!length(modifiers)) + LAZYREMOVE(owner._mob_modifiers, archetype) + archetype.on_modifier_datum_removed(owner, src) + if(!skip_update) + owner.refresh_hud_element(HUD_MODIFIERS) + if(archetype.mob_overlay_icon || archetype.mob_overlay_state) + owner.queue_icon_update() + qdel(src) + return TRUE + +/datum/mob_modifier/proc/on_modifier_added(skip_update = FALSE) + SHOULD_CALL_PARENT(TRUE) + if(!istype(owner)) + return FALSE + var/list/modifiers = LAZYACCESS(owner._mob_modifiers, archetype) + if(!modifiers) + modifiers = list() + LAZYSET(owner._mob_modifiers, archetype, modifiers) + if(src in modifiers) + return FALSE + modifiers += src + archetype.on_modifier_datum_added(owner, src) + if(!skip_update) + owner.refresh_hud_element(HUD_MODIFIERS) + if(archetype.mob_overlay_icon || archetype.mob_overlay_state) + owner.queue_icon_update() + return TRUE + +/datum/mob_modifier/proc/on_modifier_expiry() + SHOULD_CALL_PARENT(TRUE) + archetype.on_modifier_datum_expiry(owner, src) + return on_modifier_removed() + +/datum/mob_modifier/proc/on_modifier_click(params) + SHOULD_CALL_PARENT(TRUE) + archetype.on_modifier_datum_click(owner, src, params) diff --git a/code/modules/mob_modifiers/modifiers_helpers.dm b/code/modules/mob_modifiers/modifiers_helpers.dm new file mode 100644 index 000000000000..339ee093a855 --- /dev/null +++ b/code/modules/mob_modifiers/modifiers_helpers.dm @@ -0,0 +1,78 @@ + +/mob/living + // A modifier is a generalised effect on the mob, positive or negative, like buckling, healing or a curse. + var/list/_mob_modifiers + +/mob/living/proc/handle_mob_modifiers() + SHOULD_CALL_PARENT(TRUE) + for(var/decl/mob_modifier/archetype as anything in _mob_modifiers) + if(archetype.on_modifier_datum_mob_life(src, _mob_modifiers[archetype])) + . = TRUE + if(.) + refresh_hud_element(HUD_MODIFIERS) + +/mob/living/clear_mob_modifiers() + for(var/archetype as anything in _mob_modifiers) + for(var/datum/mob_modifier/modifier in _mob_modifiers[archetype]) + modifier.on_modifier_removed() + +/mob/living/remove_mob_modifier(decl/mob_modifier/archetype, datum/source, skip_update = FALSE) + + if(ispath(archetype)) + archetype = GET_DECL(archetype) + if(!istype(archetype)) + return FALSE + + // If we have no data, we can't clear it. + var/list/modifiers = LAZYACCESS(_mob_modifiers, archetype) + if(!length(modifiers)) + return FALSE + + // Source datum means we only remove an modifier that matches the source. + for(var/datum/mob_modifier/modifier as anything in modifiers) + if(!source || modifier.source?.resolve() == source) + modifier.on_modifier_removed() + . = TRUE + if(source) + return + + // We didn't find one to remove. Tragic. + return FALSE + +// If source is not provided, we only care that we have SOMETHING providing this modifier. +/mob/living/has_mob_modifier(decl/mob_modifier/archetype, datum/source) + if(ispath(archetype)) + archetype = GET_DECL(archetype) + if(!istype(archetype)) + return FALSE + var/list/modifiers = LAZYACCESS(_mob_modifiers, archetype) + if(!length(modifiers)) + return FALSE + if(!source) // We don't care about specifics. + return TRUE + for(var/datum/mob_modifier/modifier in modifiers) + if(modifier.source?.resolve() == source) + return TRUE + return FALSE + +/mob/living/add_mob_modifier(decl/mob_modifier/archetype, duration = MOB_MODIFIER_INDEFINITE, datum/source, skip_update = FALSE) + if(ispath(archetype)) + archetype = GET_DECL(archetype) + if(!istype(archetype) || !istype(source)) + return FALSE + + var/list/modifiers = LAZYACCESS(_mob_modifiers, archetype) + var/datum/mob_modifier/modifier + for(var/datum/mob_modifier/existing_modifier in modifiers) + if(existing_modifier.source?.resolve() == source) + modifier = existing_modifier + break + + if(!istype(modifier)) + modifier = new archetype.modifier_type(archetype, src, source) + if(duration != MOB_MODIFIER_INDEFINITE) + modifier.expire_time = world.time + duration + else + modifier.expire_time = MOB_MODIFIER_INDEFINITE + modifier.on_modifier_added(skip_update) + return TRUE diff --git a/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm b/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm index 1f332cea7afc..5df2360f17fa 100644 --- a/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm +++ b/code/modules/modular_computers/computers/modular_computer/assembly_computer.dm @@ -26,7 +26,7 @@ critical_parts = list(PART_CPU, PART_HDD, PART_NETWORK) /datum/extension/assembly/modular_computer/try_install_component(var/mob/living/user, var/obj/item/stock_parts/computer/P) - if(!(P.usage_flags & hardware_flag)) + if(!istype(P) || !(P.usage_flags & hardware_flag)) to_chat(user, "This computer isn't compatible with [P].") return var/obj/item/stock_parts/computer/C = P @@ -35,15 +35,13 @@ return . = ..() if(.) - if(istype(P, /obj/item/stock_parts/computer/scanner)) - var/obj/item/stock_parts/computer/scanner/scanner = P - scanner.do_after_install(user, holder) + P.do_after_install(holder, !!user) return TRUE /datum/extension/assembly/modular_computer/uninstall_component(var/mob/living/user, var/obj/item/stock_parts/P) - if(istype(P, /obj/item/stock_parts/computer/scanner)) - var/obj/item/stock_parts/computer/scanner/scanner = P - scanner.do_before_uninstall() + if(istype(P, /obj/item/stock_parts/computer)) + var/obj/item/stock_parts/computer/C = P + C.do_before_uninstall(holder, !!user) return ..() /datum/extension/assembly/modular_computer/critical_shutdown() @@ -54,11 +52,10 @@ /datum/extension/assembly/modular_computer/power_failure(var/malfunction = 0) var/atom/movable/H = holder H.visible_message("\The [assembly_name]'s screen flickers briefly and then goes dark.", range = 1) - var/datum/extension/interactive/ntos/os = get_extension(holder, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(holder, /datum/extension/interactive/os) if(os) os.event_powerfailure() - shutdown_device() - return ..() + . = ..() /datum/extension/assembly/modular_computer/turn_on(var/mob/user) if(bsod) @@ -78,18 +75,18 @@ to_chat(user, SPAN_NOTICE("You send an activation signal to \the [assembly_name], turning it on.")) else to_chat(user, SPAN_NOTICE("You press the power button and start up \the [assembly_name].")) - var/datum/extension/interactive/ntos/os = get_extension(holder, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(holder, /datum/extension/interactive/os) if(os) os.system_boot() else // Unpowered if(force_synth || issynth) to_chat(user, SPAN_WARNING("You send an activation signal to \the [assembly_name], but it does not respond.")) else - to_chat(user, SPAN_WARNING("You press the power button but \the [assembly_name], does not respond.")) + to_chat(user, SPAN_WARNING("You press the power button but \the [assembly_name] does not respond.")) shutdown_device() /datum/extension/assembly/modular_computer/shutdown_device() . = ..() - var/datum/extension/interactive/ntos/os = get_extension(holder, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(holder, /datum/extension/interactive/os) if(os) - os.system_shutdown() \ No newline at end of file + os.system_shutdown() diff --git a/code/modules/modular_computers/computers/modular_computer/assembly_holo.dm b/code/modules/modular_computers/computers/modular_computer/assembly_holo.dm new file mode 100644 index 000000000000..3fc1d1ca5d06 --- /dev/null +++ b/code/modules/modular_computers/computers/modular_computer/assembly_holo.dm @@ -0,0 +1,7 @@ +/datum/extension/assembly/modular_computer/holo + hardware_flag = PROGRAM_PDA + max_hardware_size = 1 + critical_parts = list(PART_CPU, PART_HDD) + + base_active_power_usage = 30 + base_idle_power_usage = 0 diff --git a/code/modules/modular_computers/computers/modular_computer/assembly_laptop.dm b/code/modules/modular_computers/computers/modular_computer/assembly_laptop.dm index 841d95749bd4..ba136bbea3b9 100644 --- a/code/modules/modular_computers/computers/modular_computer/assembly_laptop.dm +++ b/code/modules/modular_computers/computers/modular_computer/assembly_laptop.dm @@ -6,4 +6,5 @@ max_damage = 200 /datum/extension/assembly/modular_computer/laptop/New() - broken_damage = max_damage / 2 \ No newline at end of file + broken_damage = max_damage / 2 + ..() \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/assembly_telescreen.dm b/code/modules/modular_computers/computers/modular_computer/assembly_telescreen.dm deleted file mode 100644 index 48f3cc51c16a..000000000000 --- a/code/modules/modular_computers/computers/modular_computer/assembly_telescreen.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/extension/assembly/modular_computer/telescreen - hardware_flag = PROGRAM_TELESCREEN - max_hardware_size = 2 - base_idle_power_usage = 75 - base_active_power_usage = 300 - steel_sheet_cost = 10 - max_damage = 300 - -/datum/extension/assembly/modular_computer/telescreen/New() - broken_damage = max_damage / 2 \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index 097ee87166cc..0869c4431739 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -1,3 +1,15 @@ +/obj/item/modular_computer/get_contained_external_atoms() + . = ..() + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + if(assembly) + LAZYREMOVE(., assembly.parts) + +/obj/item/modular_computer/get_contained_matter(include_reagents = TRUE) + . = ..() + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + for(var/obj/part in assembly?.parts) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., part.get_contained_matter(include_reagents)) + /obj/item/modular_computer/Process() var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) if(assembly) @@ -5,7 +17,7 @@ if(!assembly.enabled) return - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) os.Process() @@ -15,7 +27,7 @@ playsound(src.loc, pick(beepsounds),15,1,10, is_ambiance = 1) /obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) os.ui_interact(user) @@ -27,7 +39,7 @@ // Used to install preset-specific programs /obj/item/modular_computer/proc/install_default_programs() - var/mob/living/carbon/human/H = get_holder_of_type(src, /mob) + var/mob/living/human/H = get_recursive_loc_of_type(/mob) var/list/job_programs = list() if(H) var/datum/job/jb = SSjobs.get_by_title(H.job) @@ -41,23 +53,17 @@ var/datum/computer_file/program/prog_file = prog_type if(initial(prog_file.usage_flags) & assembly.hardware_flag) prog_file = new prog_file - HDD.store_file(prog_file) + HDD.store_file(prog_file, OS_PROGRAMS_DIR, TRUE) /obj/item/modular_computer/Initialize() START_PROCESSING(SSobj, src) - set_extension(src, /datum/extension/interactive/ntos/device) + set_extension(src, /datum/extension/interactive/os/device) set_extension(src, computer_type) - if(stores_pen && ispath(stored_pen)) stored_pen = new stored_pen(src) - update_icon() update_verbs() update_name() - - var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly/modular_computer) - if(istype(assembly) && assembly.enabled_by_default) - enable_computer() ..() return INITIALIZE_HINT_LATELOAD @@ -65,9 +71,12 @@ . = ..() install_default_hardware() install_default_programs() + var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) + if(istype(assembly) && assembly.enabled_by_default) + enable_computer() /obj/item/modular_computer/Destroy() - QDEL_NULL_LIST(terminals) + shutdown_computer(loud = FALSE) STOP_PROCESSING(SSobj, src) if(istype(stored_pen)) QDEL_NULL(stored_pen) @@ -83,26 +92,28 @@ return 1 /obj/item/modular_computer/on_update_icon() - cut_overlays() + . = ..() for(var/decal_state in decals) var/image/I = image(icon, "[icon_state]-[decal_state]") I.color = decals[decal_state] I.appearance_flags |= RESET_COLOR add_overlay(I) - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) var/image/screen_overlay = os?.get_screen_overlay() if(screen_overlay) add_overlay(screen_overlay) + else if(dark_screen_state) + add_overlay(dark_screen_state) var/image/keyboard_overlay = os?.get_keyboard_overlay() if(keyboard_overlay) add_overlay(keyboard_overlay) update_lighting() /obj/item/modular_computer/proc/update_lighting() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) if(assembly && assembly.enabled) - set_light(0.2, 0.1, light_strength, l_color = (assembly.bsod || os?.updating) ? "#0000ff" : light_color) + set_light(light_strength, l_color = (assembly.bsod || os?.updating) ? "#0000ff" : light_color) else set_light(0) @@ -123,11 +134,12 @@ if(user) ui_interact(user) -/obj/item/modular_computer/GetIdCard() +/obj/item/modular_computer/GetIdCards(list/exceptions) + . = ..() var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) var/obj/item/stock_parts/computer/card_slot/card_slot = assembly.get_component(PART_CARD) - if(card_slot && card_slot.can_broadcast && istype(card_slot.stored_card) && card_slot.check_functionality()) - return card_slot.stored_card + if(card_slot && card_slot.can_broadcast && istype(card_slot.stored_card) && card_slot.check_functionality() && !is_type_in_list(card_slot.stored_card, exceptions)) + LAZYDISTINCTADD(., card_slot.stored_card) /obj/item/modular_computer/GetChargeStick() var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) @@ -135,7 +147,8 @@ if(mstick_slot && mstick_slot.can_broadcast && istype(mstick_slot.stored_stick) && mstick_slot.check_functionality()) return mstick_slot.stored_stick -/obj/item/modular_computer/proc/update_name() +/obj/item/modular_computer/update_name() + return /obj/item/modular_computer/get_cell() var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) @@ -155,4 +168,4 @@ /obj/item/modular_computer/bullet_act(var/proj) var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) - assembly.bullet_act(proj) \ No newline at end of file + assembly.bullet_act(proj) diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm index b31cd9002bc7..d4fa1b3bd2e7 100644 --- a/code/modules/modular_computers/computers/modular_computer/interaction.dm +++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm @@ -16,7 +16,7 @@ set category = "Object" set src in view(1) - if(usr.incapacitated() || !istype(usr, /mob/living)) + if(usr.incapacitated() || !isliving(usr)) to_chat(usr, "You can't do that.") return @@ -38,7 +38,7 @@ set category = "Object" set src in view(1) - if(usr.incapacitated() || !istype(usr, /mob/living)) + if(usr.incapacitated() || !isliving(usr)) to_chat(usr, "You can't do that.") return @@ -46,7 +46,7 @@ to_chat(usr, "You can't reach it.") return - if(istype(stored_pen)) + if(IS_PEN(stored_pen)) to_chat(usr, "You remove [stored_pen] from [src].") usr.put_in_hands(stored_pen) // Silicons will drop it anyway. stored_pen = null @@ -67,6 +67,11 @@ /obj/item/modular_computer/attack_hand(var/mob/user) if(anchored) return attack_self(user) + // if it's equipped and we're not holding it, open + // the interface instead of removing it from the slot. + var/equip_slot = user.get_equipped_slot_for_item(src) + if(equip_slot && !(equip_slot in user.get_held_item_slots())) + return attack_self(user) return ..() // On-click handling. Turns on the computer if it's off and opens the GUI. @@ -74,42 +79,41 @@ var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) if(assembly.enabled && assembly.screen_on) ui_interact(user) + return TRUE else if(!assembly.enabled && assembly.screen_on) assembly.turn_on(user) + return TRUE + . = ..() + +/obj/item/modular_computer/attackby(var/obj/item/used_item, var/mob/user) -/obj/item/modular_computer/attackby(var/obj/item/W, var/mob/user) var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) - if(assembly.attackby(W, user)) + if(assembly?.attackby(used_item, user)) update_verbs() - return + return TRUE - if(istype(W, /obj/item/pen) && stores_pen) + if(IS_PEN(used_item) && (used_item.w_class <= ITEM_SIZE_TINY) && stores_pen) if(istype(stored_pen)) - to_chat(user, "There is already a pen in [src].") - return - if(!user.unEquip(W, src)) - return - stored_pen = W - update_verbs() - to_chat(user, "You insert [W] into [src].") - return + to_chat(user, SPAN_NOTICE("There is already \a [stored_pen] in \the [src].")) + else if(user.try_unequip(used_item, src)) + stored_pen = used_item + update_verbs() + to_chat(user, SPAN_NOTICE("You insert \the [used_item] into [src].")) + return TRUE + return ..() -/obj/item/modular_computer/examine(mob/user) +/obj/item/modular_computer/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) if(assembly.enabled) - to_chat(user, "The time [stationtime2text()] is displayed in the corner of the screen.") - + . += "The time [stationtime2text()] is displayed in the corner of the screen." var/obj/item/stock_parts/computer/card_slot/card_slot = assembly.get_component(PART_CARD) if(card_slot && card_slot.stored_card) - to_chat(user, "The [card_slot.stored_card] is inserted into it.") - assembly.examine(user) - -/obj/item/modular_computer/MouseDrop(var/atom/over_object) - var/mob/M = usr - if(!istype(over_object, /obj/screen) && CanMouseDrop(M)) - return attack_self(M) + . += "\The [card_slot.stored_card] is inserted into it." + var/assembly_string = assembly.examine_assembly(user) + if(assembly_string) + . += assembly_string /obj/item/modular_computer/afterattack(atom/target, mob/user, proximity) . = ..() @@ -121,11 +125,97 @@ /obj/item/modular_computer/CtrlAltClick(mob/user) if(!CanPhysicallyInteract(user)) return - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) os.open_terminal(user) /obj/item/modular_computer/CouldUseTopic(var/mob/user) ..() if(LAZYLEN(interact_sounds) && CanPhysicallyInteract(user)) - playsound(src, pick(interact_sounds), interact_sound_volume) \ No newline at end of file + playsound(src, pick(interact_sounds), interact_sound_volume) + +/obj/item/modular_computer/get_alt_interactions(var/mob/user) + . = ..() + var/static/list/_modular_computer_interactions = list( + /decl/interaction_handler/remove_id/modular_computer, + /decl/interaction_handler/remove_pen/modular_computer, + /decl/interaction_handler/emergency_shutdown, + /decl/interaction_handler/remove_chargestick + ) + LAZYADD(., _modular_computer_interactions) + +// +// Remove ID +// +/decl/interaction_handler/remove_id/modular_computer + expected_target_type = /obj/item/modular_computer + +/decl/interaction_handler/remove_id/modular_computer/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/datum/extension/assembly/assembly = get_extension(target, /datum/extension/assembly) + var/obj/item/stock_parts/computer/card_slot/card_slot = assembly?.get_component(PART_CARD) + return !!card_slot?.stored_card + +/decl/interaction_handler/remove_id/modular_computer/invoked(atom/target, mob/user, obj/item/prop) + var/datum/extension/assembly/assembly = get_extension(target, /datum/extension/assembly) + var/obj/item/stock_parts/computer/card_slot/card_slot = assembly.get_component(PART_CARD) + if(card_slot.stored_card) + card_slot.eject_id(user) + +// +// Remove Pen +// +/decl/interaction_handler/remove_pen/modular_computer + expected_target_type = /obj/item/modular_computer + +/decl/interaction_handler/remove_pen/modular_computer/is_possible(obj/item/modular_computer/target, mob/user, obj/item/prop) + return ..() && target.stores_pen && target.stored_pen + +/decl/interaction_handler/remove_pen/modular_computer/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/modular_computer/computer = target + computer.remove_pen() + +// +// Emergency Shutdown +// +/decl/interaction_handler/emergency_shutdown + name = "Emergency Shutdown" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_power_off" + expected_target_type = /obj/item/modular_computer + examine_desc = "perform an emergency shutdown" + +/decl/interaction_handler/emergency_shutdown/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(!.) + return + var/datum/extension/assembly/modular_computer/assembly = get_extension(target, /datum/extension/assembly) + return !isnull(assembly) && assembly.enabled + +/decl/interaction_handler/emergency_shutdown/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/modular_computer/computer = target + computer.emergency_shutdown() + +// +// Remove Charge-stick +// +/decl/interaction_handler/remove_chargestick + name = "Remove Chargestick" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject" + expected_target_type = /obj/item/modular_computer + examine_desc = "remove a chargestick" + +/decl/interaction_handler/remove_chargestick/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(!.) + return . + var/datum/extension/assembly/assembly = get_extension(target, /datum/extension/assembly) + var/obj/item/stock_parts/computer/charge_stick_slot/mstick_slot = assembly.get_component(PART_MSTICK) + return !!mstick_slot?.stored_stick + +/decl/interaction_handler/remove_chargestick/invoked(atom/target, mob/user, obj/item/prop) + var/datum/extension/assembly/assembly = get_extension(target, /datum/extension/assembly) + var/obj/item/stock_parts/computer/charge_stick_slot/mstick_slot = assembly.get_component(PART_MSTICK) + mstick_slot.eject_stick(user) \ No newline at end of file diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm index 5bfb6b817f65..41f322a6441e 100644 --- a/code/modules/modular_computers/computers/modular_computer/variables.dm +++ b/code/modules/modular_computers/computers/modular_computer/variables.dm @@ -6,8 +6,10 @@ icon_state = ICON_STATE_WORLD center_of_mass = null randpixel = 0 + material = /decl/material/solid/organic/plastic var/screen_icon + var/dark_screen_state var/list/decals var/computer_emagged = FALSE var/ambience_last_played @@ -19,5 +21,4 @@ var/interact_sound_volume = 40 var/list/default_hardware = list() var/list/default_programs = list() - var/initial_hardware_flag = 0 var/computer_type = /datum/extension/assembly/modular_computer diff --git a/code/modules/modular_computers/computers/status_icons.dmi b/code/modules/modular_computers/computers/status_icons.dmi deleted file mode 100644 index 52127ec48426..000000000000 Binary files a/code/modules/modular_computers/computers/status_icons.dmi and /dev/null differ diff --git a/code/modules/modular_computers/computers/subtypes/dev_console.dm b/code/modules/modular_computers/computers/subtypes/dev_console.dm index 7561d474f643..8e3b1abef445 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_console.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_console.dm @@ -1,29 +1,39 @@ /obj/machinery/computer/modular - name = "console" - maximum_component_parts = list(/obj/item/stock_parts = 14) //There's a lot of stuff that goes in these - var/list/interact_sounds = list("keyboard", "keystroke") + name = "modular console" + maximum_component_parts = list(/obj/item/stock_parts = 14) //There's a lot of stuff that goes in these + icon = 'icons/obj/modular_computers/modular_console.dmi' + icon_state = "console-off" + var/list/interact_sounds = list("keyboard", "keystroke") + var/wired_connection = FALSE // Whether or not this console will start with a wired connection beneath it. + var/tmp/max_hardware_size = 3 //Enum to tell whether computer parts are too big to fit in this machine. + var/tmp/os_type = /datum/extension/interactive/os/console //The type of the OS extension to create for this machine. /obj/machinery/computer/modular/Initialize() - set_extension(src, /datum/extension/interactive/ntos/console) + set_extension(src, os_type) . = ..() +/obj/machinery/computer/modular/populate_parts(full_populate) + . = ..() + if(full_populate && wired_connection) + install_component(/obj/item/stock_parts/computer/lan_port, FALSE) + /obj/machinery/computer/modular/Process() if(stat & NOPOWER) return - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) os.Process() /obj/machinery/computer/modular/power_change() . = ..() if(. && (stat & NOPOWER)) - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) os.event_powerfailure() os.system_shutdown() /obj/machinery/computer/modular/interface_interact(mob/user) - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) if(!os.on) if(!CanInteract(user, DefaultTopicState())) @@ -34,12 +44,12 @@ return TRUE /obj/machinery/computer/modular/get_screen_overlay() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) return os.get_screen_overlay() /obj/machinery/computer/modular/get_keyboard_overlay() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) return os.get_keyboard_overlay() @@ -72,10 +82,19 @@ /obj/machinery/computer/modular/CtrlAltClick(mob/user) if(!CanPhysicallyInteract(user)) return - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) os.open_terminal(user) +//Check for handling wall-mounted modular computer stuff +/obj/machinery/computer/modular/can_add_component(obj/item/stock_parts/component, mob/user) + var/obj/item/stock_parts/computer/C = component + if(istype(C)) + if(C.hardware_size > max_hardware_size) + to_chat(user, "This component is too large for \the [src].") + return 0 + . = ..() + /obj/machinery/computer/modular/verb/emergency_shutdown() set name = "Forced Shutdown" set category = "Object" @@ -84,7 +103,7 @@ if(!CanPhysicallyInteract(usr)) return - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os && os.on) to_chat(usr, "You press a hard-reset button on \the [src].") os.system_shutdown() \ No newline at end of file diff --git a/code/modules/modular_computers/computers/subtypes/dev_holo.dm b/code/modules/modular_computers/computers/subtypes/dev_holo.dm new file mode 100644 index 000000000000..838bce869e9a --- /dev/null +++ b/code/modules/modular_computers/computers/subtypes/dev_holo.dm @@ -0,0 +1,98 @@ +/obj/item/modular_computer/holotablet + name = "holotablet" + desc = "A holoemitter-fitted device designed for writing reports and notes." + icon = 'icons/obj/modular_computers/holo/basic.dmi' + icon_state = ICON_STATE_WORLD + + material = /decl/material/solid/fiberglass + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE + ) + + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + item_flags = ITEM_FLAG_NO_BLUDGEON + + interact_sounds = list('sound/machines/holo_click.ogg') + interact_sound_volume = 20 + computer_type = /datum/extension/assembly/modular_computer/holo + + default_hardware = list( + /obj/item/stock_parts/computer/hard_drive/micro, + /obj/item/stock_parts/computer/processor_unit/small, + /obj/item/stock_parts/computer/battery_module/nano, + /obj/item/stock_parts/computer/drive_slot + ) + + default_programs = list(/datum/computer_file/program/wordprocessor) + + light_strength = 2 + light_color = "#0a50ff" + + /// Will contain text file with this text, if not empty. + var/preset_text + /// Cached holo icon. + var/icon/display_cache + +/obj/item/modular_computer/holotablet/Destroy() + QDEL_NULL(display_cache) + . = ..() + +/obj/item/modular_computer/holotablet/install_default_programs() + ..() + if(preset_text) + var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) + var/obj/item/stock_parts/computer/hard_drive/D = assembly.get_component(/obj/item/stock_parts/computer/hard_drive) + var/datum/computer_file/data/text/preset = new() + + preset.filename = "temp[rand(1,100)]" + preset.stored_data = preset_text + + D.store_file(preset, OS_DOCUMENTS_DIR) + var/datum/computer_file/program/wordprocessor/word = D.find_file_by_name("wordprocessor", OS_PROGRAMS_DIR) + word.open_file = preset.filename + word.loaded_data = preset.stored_data + +// Visual. +/obj/item/modular_computer/holotablet/on_update_icon() + . = ..() + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) + if(assembly && assembly.enabled) + var/mutable_appearance/M = mutable_appearance(icon,"[icon_state]-on") + M.color = (assembly.bsod || os?.updating) ? "#0000ff" : light_color + add_overlay(M) + + if(!display_cache || !isicon(display_cache)) + var/icon/I = icon(icon, "[icon_state]-screen") + I.ColorTone((assembly.bsod || os?.updating) ? "#0000ff" : light_color) + I.ChangeOpacity(0.5) + I.AddAlphaMask(new /icon('icons/effects/effects.dmi', "scanline-1")) + display_cache = I + add_overlay(display_cache) + + update_lighting() + +// Subtypes. It's not exactly... well, presets, so i'll put it here for now. + +/obj/item/modular_computer/holotablet/round + name = "round holotablet" + icon = 'icons/obj/modular_computers/holo/round.dmi' + light_color = "#00ff00" + +/obj/item/modular_computer/holotablet/curved + name = "curved holotablet" + icon = 'icons/obj/modular_computers/holo/curved.dmi' + light_color = "#db2cb5" + +/obj/item/modular_computer/holotablet/wide + name = "wide holotablet" + icon = 'icons/obj/modular_computers/holo/wide.dmi' + light_color = "#f5b216" + +/obj/item/modular_computer/holotablet/side + name = "side holotablet" + icon = 'icons/obj/modular_computers/holo/side.dmi' + light_color = "#26fce7" diff --git a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm index 1d19305c37dc..894b912aff91 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm @@ -9,20 +9,12 @@ interact_sounds = list("keyboard", "keystroke") interact_sound_volume = 20 computer_type = /datum/extension/assembly/modular_computer/laptop + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + ) var/icon_state_closed = "laptop-closed" - -/obj/item/modular_computer/laptop/AltClick(var/mob/user) -// Prevents carrying of open laptops inhand. -// While they work inhand, i feel it'd make tablets lose some of their high-mobility advantage they have over laptops now. - if(!CanPhysicallyInteract(user)) - return - if(!istype(loc, /turf/)) - to_chat(usr, "\The [src] has to be on a stable surface first!") - return - var/datum/extension/assembly/modular_computer/assembly = get_extension(src, computer_type) - anchored = !anchored - assembly.screen_on = anchored - update_icon() /obj/item/modular_computer/laptop/on_update_icon() if(anchored) @@ -33,4 +25,22 @@ icon_state = icon_state_closed /obj/item/modular_computer/laptop/preset - anchored = FALSE \ No newline at end of file + anchored = FALSE + +/obj/item/modular_computer/laptop/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/laptop_open) + +/decl/interaction_handler/laptop_open + name = "Open Laptop" + expected_target_type = /obj/item/modular_computer/laptop + interaction_flags = INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEEDS_TURF + examine_desc = "open or close $TARGET_THEM$" + +/decl/interaction_handler/laptop_open/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/modular_computer/laptop/L = target + L.anchored = !L.anchored + var/datum/extension/assembly/modular_computer/assembly = get_extension(L, L.computer_type) + if(assembly) + assembly.screen_on = L.anchored + L.update_icon() diff --git a/code/modules/modular_computers/computers/subtypes/dev_pda.dm b/code/modules/modular_computers/computers/subtypes/dev_pda.dm index e7d3acdc2c14..8278aa52967d 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_pda.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_pda.dm @@ -1,5 +1,6 @@ /obj/item/modular_computer/pda name = "\improper PDA" + base_name = "\improper PDA" desc = "A very compact computer, designed to keep its user always connected." icon = 'icons/obj/modular_computers/pda/pda.dmi' screen_icon = 'icons/obj/modular_computers/pda/screens.dmi' @@ -7,12 +8,12 @@ material = /decl/material/solid/metal/aluminium matter = list( /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/glass = MATTER_AMOUNT_TRACE ) w_class = ITEM_SIZE_SMALL light_strength = 2 - slot_flags = SLOT_ID | SLOT_BELT + slot_flags = SLOT_ID | SLOT_LOWER_BODY stores_pen = TRUE stored_pen = /obj/item/pen/retractable interact_sounds = list('sound/machines/pda_click.ogg') @@ -20,33 +21,34 @@ item_flags = ITEM_FLAG_NO_BLUDGEON computer_type = /datum/extension/assembly/modular_computer/pda color = COLOR_GRAY80 - -/obj/item/modular_computer/pda/AltClick(var/mob/user) - if(!CanPhysicallyInteract(user)) - return - var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) - var/obj/item/stock_parts/computer/card_slot/card_slot = assembly.get_component(PART_CARD) - if(card_slot && istype(card_slot.stored_card)) - card_slot.eject_id(user) - else - ..() + dark_screen_state = "blank_screen" + var/owner_name = null + var/label_assignment = null /obj/item/modular_computer/pda/on_update_icon() . = ..() - var/mob/living/carbon/human/H = loc - if(istype(H) && H.wear_id == src) - H.update_inv_wear_id() + var/mob/living/human/H = loc + if(istype(H) && H.get_equipped_item(slot_wear_id_str) == src) + H.update_equipment_overlay(slot_wear_id_str) + +/obj/item/modular_computer/pda/update_name() + if(owner_name || label_assignment) + var/used_name = owner_name || "Unknown" + var/used_assignment = label_assignment || "Unknown" + SetName("[base_name] - [used_name] ([used_assignment])") + else + SetName(base_name) + +/obj/item/modular_computer/pda/proc/set_owner_rank_job(_owner_name, _label_assignment) + owner_name = _owner_name + label_assignment = _label_assignment + update_name() // PDA box -/obj/item/storage/box/PDAs +/obj/item/box/PDAs name = "box of spare PDAs" desc = "A box of spare PDA microcomputers." icon_state = "pdabox" -/obj/item/storage/box/PDAs/Initialize() - . = ..() - new /obj/item/modular_computer/pda(src) - new /obj/item/modular_computer/pda(src) - new /obj/item/modular_computer/pda(src) - new /obj/item/modular_computer/pda(src) - new /obj/item/modular_computer/pda(src) +/obj/item/box/PDAs/WillContain() + return list(/obj/item/modular_computer/pda = 5) diff --git a/code/modules/modular_computers/computers/subtypes/dev_tablet.dm b/code/modules/modular_computers/computers/subtypes/dev_tablet.dm index 023ae171488a..d30e47c9eda1 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_tablet.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_tablet.dm @@ -3,13 +3,16 @@ desc = "A small, portable microcomputer." icon = 'icons/obj/modular_computers/modular_tablet.dmi' icon_state = "tablet" - w_class = ITEM_SIZE_SMALL - light_strength = 5 // same as PDAs - + light_strength = 2 // same as PDAs interact_sounds = list('sound/machines/pda_click.ogg') interact_sound_volume = 20 computer_type = /datum/extension/assembly/modular_computer/tablet + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/silicon = MATTER_AMOUNT_REINFORCEMENT, + ) /obj/item/modular_computer/tablet/lease desc = "A small, portable microcomputer. This one has a gold and blue stripe, and a serial number stamped into the case." diff --git a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm index 3326e5b3e258..ff514949f13d 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_telescreen.dm @@ -1,51 +1,116 @@ -/obj/item/modular_computer/telescreen - name = "telescreen" - desc = "A wall-mounted touchscreen computer." +////////////////////////////////////////////////////////////////// +// Telescreen Circuit +////////////////////////////////////////////////////////////////// + +/obj/item/stock_parts/circuitboard/modular_computer/telescreen + name = "circuitboard (modular telescreen)" + board_type = "wall" + build_path = /obj/machinery/computer/modular/telescreen + req_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/computer/processor_unit = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/computer/network_card = 1, + /obj/item/stock_parts/computer/hard_drive/super = 1 + ) + +////////////////////////////////////////////////////////////////// +// Telescreen Frame +////////////////////////////////////////////////////////////////// + +/obj/item/frame/modular_telescreen + name = "modular telescreen frame" + desc = "Used for building wall-mounted modular telescreen computers." icon = 'icons/obj/modular_computers/modular_telescreen.dmi' - icon_state = "telescreen" - anchored = TRUE - density = 0 - light_strength = 4 - w_class = ITEM_SIZE_HUGE - computer_type = /datum/extension/assembly/modular_computer/telescreen - -/obj/item/modular_computer/telescreen/Initialize() + icon_state = "frame" + build_machine_type = /obj/machinery/computer/modular/telescreen + +/obj/item/frame/modular_telescreen/kit + fully_construct = TRUE + name = "modular telescreen kit" + desc = "An all-in-one wall-mounted modular telescreen computer kit, comes preassembled." + icon_state = "frame_kit" + +////////////////////////////////////////////////////////////////// +// Telescreen OS +////////////////////////////////////////////////////////////////// + +/datum/extension/interactive/os/console/telescreen + screen_icon_file = 'icons/obj/modular_computers/modular_telescreen.dmi' + expected_type = /obj/machinery/computer/modular/telescreen + +/datum/extension/interactive/os/console/telescreen/get_hardware_flag() + return PROGRAM_TELESCREEN + +////////////////////////////////////////////////////////////////// +// Telescreen Computer +////////////////////////////////////////////////////////////////// + +/obj/machinery/computer/modular/telescreen + name = "telescreen" + desc = "A wall-mounted touchscreen computer." + icon = 'icons/obj/modular_computers/modular_telescreen.dmi' + icon_state = "telescreen" + anchored = TRUE + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-20}, "SOUTH":{"y":24}, "EAST":{"x":-24}, "WEST":{"x":24}}' + idle_power_usage = 75 + active_power_usage = 300 + max_hardware_size = 2 //make sure we can only put smaller components in here + construct_state = /decl/machine_construction/wall_frame/panel_closed + base_type = /obj/machinery/computer/modular/telescreen + frame_type = /obj/item/frame/modular_telescreen + //Behaves like a touchscreen + stat_immune = NOINPUT + icon_keyboard = null + interact_sounds = null + clicksound = null + required_interaction_dexterity = DEXTERITY_TOUCHSCREENS + os_type = /datum/extension/interactive/os/console/telescreen + +/obj/machinery/computer/modular/telescreen/update_directional_offset(force = FALSE) + if(!force && (!length(directional_offset) || !is_wall_mounted())) + return . = ..() - // Allows us to create "north bump" "south bump" etc. named objects, for more comfortable mapping. - name = "telescreen" - -/obj/item/modular_computer/telescreen/attackby(var/obj/item/W, var/mob/user) - var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly/modular_computer) - if(isCrowbar(W)) - if(anchored) - shutdown_computer() - anchored = FALSE - assembly.screen_on = FALSE - pixel_x = 0 - pixel_y = 0 - to_chat(user, "You unsecure \the [src].") - else - var/choice = input(user, "Where do you want to place \the [src]?", "Offset selection") in list("North", "South", "West", "East", "This tile", "Cancel") - var/valid = FALSE - switch(choice) - if("North") - valid = TRUE - pixel_y = 32 - if("South") - valid = TRUE - pixel_y = -32 - if("West") - valid = TRUE - pixel_x = -32 - if("East") - valid = TRUE - pixel_x = 32 - if("This tile") - valid = TRUE - - if(valid) - anchored = 1 - assembly.screen_on = TRUE - to_chat(user, "You secure \the [src].") - return - ..() \ No newline at end of file + +/obj/machinery/computer/modular/telescreen/on_update_icon() + cut_overlays() + icon_state = initial(icon_state) + + var/can_see_circuit = FALSE + if(panel_open) + add_overlay("panel_open") + can_see_circuit = TRUE + else if(reason_broken & MACHINE_BROKEN_GENERIC) + add_overlay("inside_broken") + can_see_circuit = TRUE + + if(can_see_circuit) + var/obj/item/stock_parts/circuitboard/C = get_component_of_type(/obj/item/stock_parts/circuitboard) + if(C) + if(!C.is_functional()) + add_overlay("circuit_broken") + else if(istype(construct_state, /decl/machine_construction/wall_frame/no_wires)) //only way to check if unwired + add_overlay("circuit_unwired") + else + add_overlay("circuit") + + if(!panel_open && (reason_broken & MACHINE_BROKEN_GENERIC)) + add_overlay("panel_broken") + + if(inoperable()) + set_light(0) + var/screen = get_component_of_type(/obj/item/stock_parts/console_screen) + if(screen) + if(reason_broken & MACHINE_BROKEN_GENERIC) + add_overlay("comp_screen_broken") + else + add_overlay("comp_screen") + else + set_light(light_range_on, light_power_on, light_color) + var/screen_overlay = get_screen_overlay() + if(screen_overlay) + add_overlay(screen_overlay) diff --git a/code/modules/modular_computers/computers/subtypes/preset_console.dm b/code/modules/modular_computers/computers/subtypes/preset_console.dm index cf597e427c6c..8450e7d86a2e 100644 --- a/code/modules/modular_computers/computers/subtypes/preset_console.dm +++ b/code/modules/modular_computers/computers/subtypes/preset_console.dm @@ -1,6 +1,9 @@ /obj/machinery/computer/modular/preset var/list/default_software var/datum/computer_file/program/autorun_program + /// Mounts the mainframe with the corresponding key as its ID to the root directory named after the value. + /// Ex. list("RECORDS_MAINFRAME" = "records") + var/automount_disks base_type = /obj/machinery/computer/modular /obj/machinery/computer/modular/preset/full @@ -24,17 +27,27 @@ /obj/machinery/computer/modular/preset/Initialize() . = ..() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) if(os) + // We access the harddrive directly because the filesystem is yet to be initialized. + var/obj/item/stock_parts/computer/hard_drive/HDD = os.get_component(PART_HDD) for(var/program_type in default_software) - os.store_file(new program_type()) + HDD.store_file(new program_type(), OS_PROGRAMS_DIR, create_directories = TRUE) if(autorun_program) - os.set_autorun(initial(autorun_program.filename)) + var/datum/computer_file/data/autorun = new() + autorun.filename = "autorun" + autorun.stored_data = initial(autorun_program.filename) + HDD.store_file(autorun) + if(LAZYLEN(automount_disks)) + var/datum/computer_file/data/automount = new() + automount.filename = "automount" + for(var/disk in automount_disks) + automount.stored_data += "[automount_disks[disk]]|[disk];" + HDD.store_file(automount) /obj/machinery/computer/modular/preset/engineering default_software = list( /datum/computer_file/program/power_monitor, - /datum/computer_file/program/supermatter_monitor, /datum/computer_file/program/alarm_monitor, /datum/computer_file/program/atmos_control, /datum/computer_file/program/rcon_console, @@ -42,6 +55,30 @@ /datum/computer_file/program/shields_monitor ) +/obj/machinery/computer/modular/preset/engineering/power + default_software = list( + /datum/computer_file/program/power_monitor, + /datum/computer_file/program/alarm_monitor, + /datum/computer_file/program/wordprocessor + ) + autorun_program = /datum/computer_file/program/power_monitor + +/obj/machinery/computer/modular/preset/engineering/rcon + default_software = list( + /datum/computer_file/program/rcon_console, + /datum/computer_file/program/wordprocessor + ) + autorun_program = /datum/computer_file/program/rcon_console + +/obj/machinery/computer/modular/preset/engineering/atmospherics + default_software = list( + /datum/computer_file/program/atmos_control, + /datum/computer_file/program/shutoff_valve, + /datum/computer_file/program/alarm_monitor, + /datum/computer_file/program/wordprocessor + ) + autorun_program = /datum/computer_file/program/shutoff_valve + /obj/machinery/computer/modular/preset/medical default_software = list( /datum/computer_file/program/suit_sensors, @@ -78,8 +115,17 @@ /datum/computer_file/program/email_client, /datum/computer_file/program/records, /datum/computer_file/program/docking, + /datum/computer_file/program/wordprocessor, + /datum/computer_file/program/accounts + ) + +/obj/machinery/computer/modular/preset/cardslot/personnel + default_software = list( + /datum/computer_file/program/card_mod, + /datum/computer_file/program/email_client, /datum/computer_file/program/records, - /datum/computer_file/program/wordprocessor + /datum/computer_file/program/wordprocessor, + /datum/computer_file/program/accounts ) /obj/machinery/computer/modular/preset/security @@ -115,17 +161,6 @@ ) autorun_program = /datum/computer_file/program/supply -/obj/machinery/computer/modular/preset/full/ert - default_software = list( - /datum/computer_file/program/camera_monitor/ert, - /datum/computer_file/program/email_client, - /datum/computer_file/program/alarm_monitor, - /datum/computer_file/program/comm, - /datum/computer_file/program/aidiag, - /datum/computer_file/program/records, - /datum/computer_file/program/wordprocessor - ) - /obj/machinery/computer/modular/preset/full/merc default_software = list( /datum/computer_file/program/camera_monitor/hacked, diff --git a/code/modules/modular_computers/computers/subtypes/preset_laptop.dm b/code/modules/modular_computers/computers/subtypes/preset_laptop.dm index d20c0d91ad6a..ce3d31590e6c 100644 --- a/code/modules/modular_computers/computers/subtypes/preset_laptop.dm +++ b/code/modules/modular_computers/computers/subtypes/preset_laptop.dm @@ -57,4 +57,12 @@ default_programs = list( /datum/computer_file/program/records, /datum/computer_file/program/wordprocessor - ) \ No newline at end of file + ) + +/obj/item/modular_computer/laptop/preset/medical + default_programs = list( + /datum/computer_file/program/suit_sensors, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/records, + /datum/computer_file/program/wordprocessor + ) diff --git a/code/modules/modular_computers/computers/subtypes/preset_pda.dm b/code/modules/modular_computers/computers/subtypes/preset_pda.dm index 744401edaf02..1ad6d0aceb08 100644 --- a/code/modules/modular_computers/computers/subtypes/preset_pda.dm +++ b/code/modules/modular_computers/computers/subtypes/preset_pda.dm @@ -22,11 +22,10 @@ default_programs |= /datum/computer_file/program/uplink return ..() -/obj/item/modular_computer/pda/syndicate - color = COLOR_GRAY20 +/obj/item/modular_computer/pda/mercenary + color = COLOR_DARK_RED decals = list( "stripe" = COLOR_RED, - "stripe2" = COLOR_DARK_RED ) /obj/item/modular_computer/pda/heads @@ -64,7 +63,7 @@ /obj/item/modular_computer/pda/heads/captain/install_default_hardware() default_hardware |= /obj/item/stock_parts/computer/scanner/paper - . = ..() + . = ..() /obj/item/modular_computer/pda/science color = COLOR_OFF_WHITE @@ -104,4 +103,4 @@ /obj/item/modular_computer/pda/cargo/install_default_programs() default_programs |= /datum/computer_file/program/reports - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/modular_computers/computers/subtypes/preset_tablet.dm b/code/modules/modular_computers/computers/subtypes/preset_tablet.dm index efaa817c19e4..06f82749e941 100644 --- a/code/modules/modular_computers/computers/subtypes/preset_tablet.dm +++ b/code/modules/modular_computers/computers/subtypes/preset_tablet.dm @@ -32,7 +32,7 @@ ) //Map presets -/obj/item/modular_computer/tablet/lease/preset/command/install_default_hardware() +/obj/item/modular_computer/tablet/lease/preset/command default_hardware = list( /obj/item/stock_parts/computer/processor_unit/small, /obj/item/stock_parts/computer/tesla_link, diff --git a/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm b/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm index 6b5b2dcb0f6c..284372c00bfb 100644 --- a/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm +++ b/code/modules/modular_computers/computers/subtypes/preset_telescreen.dm @@ -1,27 +1,88 @@ -/obj/item/modular_computer/telescreen/preset - default_hardware = list( +////////////////////////////////////////////////////////////////// +// Telescreen Preset +////////////////////////////////////////////////////////////////// + +/obj/machinery/computer/modular/telescreen/preset + base_type = /obj/machinery/computer/modular/telescreen + uncreated_component_parts = list( /obj/item/stock_parts/computer/processor_unit, /obj/item/stock_parts/computer/tesla_link, /obj/item/stock_parts/computer/hard_drive, - /obj/item/stock_parts/computer/network_card + /obj/item/stock_parts/computer/network_card, + /obj/item/stock_parts/computer/card_slot, + ) + var/list/default_software + var/datum/computer_file/program/autorun_program + +/obj/machinery/computer/modular/telescreen/preset/Initialize(mapload, d=0, populate_parts = TRUE) + . = ..() + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + //#TODO: Maybe that file system stuff should really handle this a bit better so we don't have to mess with internals like that? + // We access the harddrive directly because the filesystem is yet to be initialized. + var/obj/item/stock_parts/computer/hard_drive/HDD = os.get_component(PART_HDD) + if(!HDD) + log_warning("Telescreen preset '[type]' doesn't have a hard drive! This is most likely not desired.") + return . + for(var/program_type in default_software) + HDD.store_file(new program_type(), OS_PROGRAMS_DIR, create_directories = TRUE) + if(autorun_program) + var/datum/computer_file/data/autorun = new() + autorun.filename = "autorun" + autorun.stored_data = initial(autorun_program.filename) + HDD.store_file(autorun) + +////////////////////////////////////////////////////////////////// +// Pressets +////////////////////////////////////////////////////////////////// + +/obj/machinery/computer/modular/telescreen/preset/supply_public + default_software = list( + /datum/computer_file/program/supply, + ) + autorun_program = /datum/computer_file/program/supply + +/obj/machinery/computer/modular/telescreen/preset/civilian + default_software = list( + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/records, + /datum/computer_file/program/email_client, + /datum/computer_file/program/wordprocessor ) -/obj/item/modular_computer/telescreen/preset/generic - default_programs = list( +/obj/machinery/computer/modular/telescreen/preset/generic + default_software = list( /datum/computer_file/program/alarm_monitor, /datum/computer_file/program/camera_monitor ) -/obj/item/modular_computer/telescreen/preset/medical - default_programs = list( +/obj/machinery/computer/modular/telescreen/preset/medical + default_software = list( /datum/computer_file/program/camera_monitor, /datum/computer_file/program/records, - /datum/computer_file/program/suit_sensors + /datum/computer_file/program/suit_sensors, + /datum/computer_file/program/wordprocessor ) -/obj/item/modular_computer/telescreen/preset/engineering - default_programs = list( + +/obj/machinery/computer/modular/telescreen/preset/engineering + default_software = list( /datum/computer_file/program/alarm_monitor, /datum/computer_file/program/camera_monitor, - /datum/computer_file/program/shields_monitor, - /datum/computer_file/program/supermatter_monitor + /datum/computer_file/program/shields_monitor + ) + +/obj/machinery/computer/modular/telescreen/preset/entertainment + default_software = list( + /datum/computer_file/program/camera_monitor + ) + autorun_program = /datum/computer_file/program/camera_monitor + +/obj/machinery/computer/modular/telescreen/preset/security + default_software = list( + /datum/computer_file/program/digitalwarrant, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/records, + /datum/computer_file/program/forceauthorization, + /datum/computer_file/program/wordprocessor ) + autorun_program = /datum/computer_file/program/camera_monitor diff --git a/code/modules/modular_computers/file_system/computer_file.dm b/code/modules/modular_computers/file_system/computer_file.dm index 0cbd72393e0a..34b99e38bbf2 100644 --- a/code/modules/modular_computers/file_system/computer_file.dm +++ b/code/modules/modular_computers/file_system/computer_file.dm @@ -1,15 +1,26 @@ var/global/file_uid = 0 -/datum/computer_file/ +#define OS_READ_ACCESS BITFLAG(0) +#define OS_WRITE_ACCESS BITFLAG(1) +#define OS_MOD_ACCESS BITFLAG(2) + +/datum/computer_file var/filename = "NewFile" // Placeholder. No spacebars var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case var/size = 1 // File size in GQ. Integers only! - var/obj/item/stock_parts/computer/hard_drive/holder // Holder that contains this file. + var/weakref/holder // Holder that contains this file. Refers to a obj/item/stock_parts/computer/hard_drive. + var/uncopyable = FALSE // Whether the file may be cloned or copied by a user. var/unsendable = 0 // Whether the file may be sent to someone via file transfer or other means. var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc. + var/unrenamable = 0 // Whether the file may be renamed. Setting to 1 prevents renaming. var/uid // UID of this file - var/list/metadata // Any metadata the file uses. + var/list/metadata // Any metadata the file uses. var/papertype = /obj/item/paper + var/copy_string = "(Copy)" + + var/list/read_access + var/list/write_access + var/list/mod_access /datum/computer_file/New(var/list/md = null) ..() @@ -18,24 +29,143 @@ var/global/file_uid = 0 if(islist(md)) metadata = md.Copy() +/datum/computer_file/proc/remove_from_holder() + // This just *begs* for making filesystems an extension + var/obj/item/stock_parts/computer/hard_drive/hard_drive = holder?.resolve() + if(istype(hard_drive)) + hard_drive.remove_file(src, forced = TRUE) + var/obj/item/disk/data_disk = hard_drive + if(istype(data_disk)) + data_disk.delete_file(filename, force = TRUE) + /datum/computer_file/Destroy() + remove_from_holder() . = ..() - if(!holder) - return - - holder.remove_file(src) -// Returns independent copy of this file. -/datum/computer_file/proc/clone(var/rename = 0) - var/datum/computer_file/temp = new type - temp.unsendable = unsendable - temp.undeletable = undeletable - temp.size = size +/datum/computer_file/PopulateClone(datum/computer_file/clone) + clone = ..() + clone.unsendable = unsendable + clone.undeletable = undeletable + clone.size = size if(metadata) - temp.metadata = metadata.Copy() - if(rename) - temp.filename = filename + "(Copy)" + clone.metadata = listDeepClone(metadata, TRUE) + clone.filetype = filetype + clone.read_access = deepCopyList(read_access) + clone.write_access = deepCopyList(write_access) + clone.mod_access = deepCopyList(mod_access) + return clone + +/** + * Returns independent copy of this file. + * rename: Whether the clone shold be auto-renamed. + */ +/datum/computer_file/Clone(var/rename = FALSE) + var/datum/computer_file/clone = ..(null) //Don't propagate our rename param + if(clone) + if(rename) + clone.filename = filename + copy_string + else + clone.filename = filename + return clone + +/datum/computer_file/proc/get_file_perms(var/list/accesses, var/mob/user) + . = 0 + if(!accesses || (isghost(user) && check_rights(R_ADMIN, 0, user))) // No access list past means internal usage, so grant full access. Also override for use by admin ghosts. + return (OS_READ_ACCESS | OS_WRITE_ACCESS | OS_MOD_ACCESS) + if(!LAZYLEN(read_access) || has_access(read_access, accesses)) + . |= OS_READ_ACCESS + if(!LAZYLEN(write_access) || has_access(write_access, accesses)) + . |= OS_WRITE_ACCESS + if(!LAZYLEN(mod_access) || has_access(mod_access, accesses)) + . |= OS_MOD_ACCESS + +/datum/computer_file/proc/get_perms_readable() + var/list/msg = list() + msg += "Permissions for file [filename]:" + var/read_perms + if(LAZYLEN(read_access)) + read_perms = english_list(read_access[1]) + else + read_perms = "No access required." + msg += "Read access: [read_perms]" + var/write_perms + if(LAZYLEN(write_access)) + write_perms = english_list(write_access[1]) else - temp.filename = filename - temp.filetype = filetype - return temp \ No newline at end of file + write_perms = "No access required." + msg += "Write access: [write_perms]" + var/mod_perms + if(LAZYLEN(mod_access)) + mod_perms = english_list(mod_access[1]) + else + mod_perms = "No access required." + msg += "Permission modification access: [mod_perms]" + return msg + +/datum/computer_file/proc/change_perms(var/change, var/perm, var/access_key, var/changer_accesses) + + if(!has_access(mod_access, changer_accesses)) + return FALSE + + if(perm == (OS_READ_ACCESS || OS_WRITE_ACCESS)) + var/list/modded_list = (perm == OS_READ_ACCESS ? read_access : write_access) + if(change == "+") + if(!LAZYLEN(modded_list)) + modded_list = list() + modded_list += list(list()) + modded_list[1] += access_key + return TRUE + else if(change == "-") + if(!LAZYLEN(modded_list)) // There weren't any access requirements to begin with. + return TRUE + modded_list[1] -= access_key + if(!length(modded_list[1])) + modded_list[1] = null + modded_list = null + return TRUE + else + return FALSE // Something unexpected was passed into the change argument. + + else if(perm == OS_MOD_ACCESS) + var/list/test_list // You can't modify access such that you can't access the file any longer, so we test changes first. + if(change == "+") + if(!LAZYLEN(mod_access)) + test_list = list(list(access_key)) + if(!has_access(test_list, changer_accesses)) + return FALSE + mod_access = list() + mod_access += list(list()) + mod_access[1] += access_key + return TRUE + test_list = list(mod_access[1] + access_key) + if(!has_access(test_list, changer_accesses)) + return FALSE + mod_access[1] += access_key + return TRUE + else if(change == "-") + if(!LAZYLEN(mod_access)) + return TRUE + test_list = list(mod_access[1] - access_key) + if(!has_access(test_list, changer_accesses)) + return FALSE + mod_access[1] -= access_key + if(!length(mod_access[1])) + mod_access[1] = null + mod_access = null + return TRUE + else + return FALSE + +/datum/computer_file/proc/get_directory() + var/obj/item/stock_parts/computer/hard_drive/hard_drive = holder?.resolve() + if(hard_drive) + return hard_drive.stored_files[src] + +/datum/computer_file/proc/get_file_path() + var/datum/computer_file/parent = get_directory() + var/list/dir_names = list() + while(istype(parent)) + dir_names.Insert(1, parent.filename) + parent = parent.get_directory() + + return jointext(dir_names, "/") \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/data.dm b/code/modules/modular_computers/file_system/data.dm index ea4d3bf75de7..369f1b15b4b8 100644 --- a/code/modules/modular_computers/file_system/data.dm +++ b/code/modules/modular_computers/file_system/data.dm @@ -7,10 +7,10 @@ var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited. var/read_only = 0 // Protects files that should never be edited by the user due to special properties. -/datum/computer_file/data/clone() - var/datum/computer_file/data/temp = ..() - temp.stored_data = stored_data - return temp +/datum/computer_file/data/PopulateClone(datum/computer_file/data/clone) + clone = ..() + clone.stored_data = stored_data + return clone // Calculates file size from amount of characters in saved string /datum/computer_file/data/proc/calculate_size() diff --git a/code/modules/modular_computers/file_system/directory.dm b/code/modules/modular_computers/file_system/directory.dm new file mode 100644 index 000000000000..af81828a81cf --- /dev/null +++ b/code/modules/modular_computers/file_system/directory.dm @@ -0,0 +1,91 @@ +/datum/computer_file/directory + filetype = "DIR" + size = 0 + + var/list/held_files = list() // Weakrefs of files held by this directory. + var/inherit_perms = TRUE + + var/list/temp_file_refs = list() // List used to temporarily hold references to stored files post cloning, so they + // don't get GC'd. Cleared on storing or deleting the file. + +/datum/computer_file/directory/Destroy() + for(var/weakref/file_ref in held_files) + var/datum/computer_file/held_file = file_ref.resolve() + var/obj/item/stock_parts/computer/hard_drive/hard_drive = holder?.resolve() + if(held_file && hard_drive) + hard_drive.remove_file(held_file, forced = TRUE) + + temp_file_refs.Cut() + . = ..() + +/datum/computer_file/directory/proc/get_held_files() + . = list() + for(var/weakref/file_ref in held_files) + var/datum/computer_file/held_file = file_ref.resolve() + if(!held_file) + held_files -= file_ref + continue + . += held_file + +// Returns the total file size of held files. We don't override the actual size of the directory so we don't double count file size for capacity. +/datum/computer_file/directory/proc/get_held_size(list/counted_dirs = list()) + . = 0 + counted_dirs |= src // Keep track of files which have been counted in case there's a directory loop. + for(var/weakref/file_ref in held_files) + var/datum/computer_file/held_file = file_ref.resolve() + if(!held_file) + held_files -= file_ref + continue + if(istype(held_file, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = held_file + if(dir in counted_dirs) + continue + . += dir.get_held_size(counted_dirs) + else + . += held_file.size + +// Get the permissions for mass file actions, generally: +// * OS_READ_ACCESS on all contained files is required for cloning directories. +// * OS_WRITE_ACCESS on all contained files is required for transferring/deleting directories. +/datum/computer_file/directory/proc/get_held_perms(list/accesses, mob/user, list/counted_dirs = list()) + . = get_file_perms(accesses, user) + + if(!accesses || (isghost(user) && check_rights(R_ADMIN, 0, user))) // As with normal file perms, either internal use or admin-ghost usage. + return + + counted_dirs |= src // As above. + for(var/weakref/file_ref in held_files) + var/datum/computer_file/held_file = file_ref.resolve() + if(!held_file) + held_files -= file_ref + continue + + if(istype(held_file, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = held_file + if(dir in counted_dirs) + continue + . += dir.get_held_perms(accesses, user, counted_dirs) + else + . &= held_file.get_file_perms(accesses, user) + + if(. == 0) // We've already lost all permissions, don't bother checking anything else. + return + +/datum/computer_file/directory/get_file_path() + var/parent_paths = ..() + if(parent_paths) + return parent_paths + "/" + filename + return filename + +/datum/computer_file/directory/PopulateClone(datum/computer_file/directory/clone) + clone = ..() + clone.inherit_perms = inherit_perms + // Add copies of all of our stored files + for(var/datum/computer_file/stored in get_held_files()) + // Do not rename cloned files. + var/datum/computer_file/stored_clone = stored.Clone(FALSE) + if(stored_clone) + clone.held_files += weakref(stored_clone) + clone.temp_file_refs += stored_clone + + return clone \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/grant.dm b/code/modules/modular_computers/file_system/grant.dm deleted file mode 100644 index 543dbe4817a8..000000000000 --- a/code/modules/modular_computers/file_system/grant.dm +++ /dev/null @@ -1,8 +0,0 @@ -/datum/computer_file/data/grant_record - filetype = "GRT" - size = 2 - do_not_edit = 1 // Whether the user will be reminded that the file probably shouldn't be edited. - -/datum/computer_file/data/grant_record/proc/set_value(var/value) - stored_data = replacetext(sanitize(uppertext(value)), " ", "_") - filename = stored_data \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/manifest.dm b/code/modules/modular_computers/file_system/manifest.dm index 87e246404392..ee79e016bd94 100644 --- a/code/modules/modular_computers/file_system/manifest.dm +++ b/code/modules/modular_computers/file_system/manifest.dm @@ -1,27 +1,20 @@ // Generates a simple HTML crew manifest for use in various places -/proc/html_crew_manifest(var/monochrome, var/OOC, records = GLOB.all_crew_records) +/proc/html_crew_manifest(var/monochrome, var/OOC, records = global.all_crew_records) var/list/dept_data = list() - var/list/dept_list = SSdepartments.departments - for(var/dept_key in dept_list) - var/datum/department/dept = dept_list[dept_key] - dept_data += list(list("names" = list(), "header" = dept.title, "ref" = dept.reference)) - - - var/list/misc //Special departments for easier access - for(var/list/department in dept_data) - if(department["ref"] == "misc") - misc = department["names"] + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dtype in all_departments) + var/decl/department/dept = all_departments[dtype] + dept_data += list(list("names" = list(), "header" = dept.name, "ref" = dept.type)) var/list/isactive = new() var/list/mil_ranks = list() // HTML to prepend to name var/dat = {" @@ -32,17 +25,17 @@ var/rank = CR.get_job() mil_ranks[name] = "" - if(GLOB.using_map.flags & MAP_HAS_RANK) - var/datum/mil_branch/branch_obj = mil_branches.get_branch(CR.get_branch()) - var/datum/mil_rank/rank_obj = mil_branches.get_rank(CR.get_branch(), CR.get_rank()) + if(global.using_map.flags & MAP_HAS_RANK) + var/datum/mil_branch/branch_obj = global.using_map.get_branch(CR.get_branch()) + var/datum/mil_rank/rank_obj = global.using_map.get_rank(CR.get_branch(), CR.get_rank()) if(branch_obj && rank_obj) mil_ranks[name] = "[rank_obj.name_short] " if(OOC) var/active = 0 - for(var/mob/M in GLOB.player_list) - var/mob_real_name = M.real_name + for(var/mob/M in global.player_list) + var/mob_real_name = M.mind?.name || M.real_name if(sanitize(mob_real_name) == CR.get_name() && M.client && M.client.inactivity <= 10 MINUTES) active = 1 break @@ -51,15 +44,11 @@ isactive[name] = CR.get_status() var/datum/job/job = SSjobs.get_by_title(rank) - var/found_place = 0 if(job) for(var/list/department in dept_data) var/list/names = department["names"] - if(department["ref"] in job.department_refs) + if(department["ref"] in job.department_types) names[name] = rank - found_place = 1 - if(!found_place) - misc[name] = rank for(var/list/department in dept_data) var/list/names = department["names"] @@ -73,7 +62,7 @@ dat = replacetext(dat, "\t", "") return dat -/proc/silicon_nano_crew_manifest(var/list/filter) +/proc/silicon_nano_crew_manifest() var/list/filtered_entries = list() for(var/mob/living/silicon/ai/ai in SSmobs.mob_list) @@ -105,15 +94,13 @@ return filtered_entries /proc/nano_crew_manifest() - var/list/dept_data - var/list/dept_list = SSdepartments.departments - for(var/dept_key in dept_list) - var/datum/department/dept = dept_list[dept_key] - dept_data += list("[dept.reference]" = filtered_nano_crew_manifest(SSjobs.titles_by_department(dept.reference))) - return dept_data - + . = list() + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dtype in all_departments) + var/decl/department/dept = GET_DECL(dtype) + .[dept.name] = filtered_nano_crew_manifest(SSjobs.titles_by_department(dtype)) /proc/flat_nano_crew_manifest() . = list() . += filtered_nano_crew_manifest(null, TRUE) - . += silicon_nano_crew_manifest(SSjobs.titles_by_department("misc")) \ No newline at end of file + . += silicon_nano_crew_manifest() diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 147155026bdb..d0e5ce447d9b 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -2,13 +2,12 @@ /datum/computer_file/program filetype = "PRG" filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NETWORK! - var/required_access = null // List of required accesses to run/download the program. - var/requires_access_to_run = 1 // Whether the program checks for required_access when run. - var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading. + var/requires_access_to_run = 1 // Whether the program checks for read_access when run. + var/requires_access_to_download = 1 // Whether the program checks for read_access when downloading. var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact. var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program. var/program_state = PROGRAM_STATE_KILLED // PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. - var/datum/extension/interactive/ntos/computer // OS that runs this program. + var/datum/extension/interactive/os/computer // OS that runs this program. var/filedesc = "Unknown Program" // User-friendly name of this program. var/extended_desc = "N/A" // Short description of this program's function. var/category = PROG_MISC @@ -19,12 +18,13 @@ var/requires_network_feature = 0 // Optional, if above is set to 1 checks for specific function of network (currently NETWORK_SOFTWAREDOWNLOAD, NETWORK_PEERTOPEER, NETWORK_SYSTEMCONTROL and NETWORK_COMMUNICATION) var/usage_flags = PROGRAM_ALL & ~PROGRAM_PDA // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET, PROGRAM_PDA combination) or PROGRAM_ALL var/network_destination = null // Optional string that describes what network server/system this program connects to. Used in default logging. - var/available_on_network = 1 // Whether the program can be downloaded from network. Set to 0 to disable. - var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. + var/available_on_network = TRUE // Whether the program can be downloaded from network. Set to FALSE to disable. var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images! var/operator_skill = SKILL_MIN // Holder for skill value of current/recent operator for programs that tick. + mod_access = list(list(access_network)) + /datum/computer_file/program/Destroy() if(computer && computer.active_program == src) computer.kill_program(src) @@ -34,23 +34,23 @@ /datum/computer_file/program/nano_host() return computer && computer.nano_host() -/datum/computer_file/program/clone() - var/datum/computer_file/program/temp = ..() - temp.required_access = required_access - temp.nanomodule_path = nanomodule_path - temp.filedesc = filedesc - temp.program_icon_state = program_icon_state - temp.requires_network = requires_network - temp.requires_network_feature = requires_network_feature - temp.usage_flags = usage_flags - return temp +/datum/computer_file/program/PopulateClone(datum/computer_file/program/clone) + clone = ..() + clone.read_access = deepCopyList(read_access) + clone.nanomodule_path = nanomodule_path + clone.filedesc = filedesc + clone.program_icon_state = program_icon_state + clone.requires_network = requires_network + clone.requires_network_feature = requires_network_feature + clone.usage_flags = usage_flags + return clone // Used by programs that manipulate files. -/datum/computer_file/program/proc/get_file(var/filename) - return computer.get_file(filename) +/datum/computer_file/program/proc/get_file(var/filename, var/directory, var/list/accesses, var/mob/user) + return computer.get_file(filename, directory, accesses, user) -/datum/computer_file/program/proc/create_file(var/newname, var/data = "", var/file_type = /datum/computer_file/data, var/list/metadata = null) - return computer.create_file(newname, data, file_type, metadata) +/datum/computer_file/program/proc/create_file(var/newname, var/directory, var/data = "", var/file_type = /datum/computer_file/data, var/list/metadata = null, var/list/accesses, var/mob/user) + return computer.create_file(newname, directory, data, file_type, metadata, accesses, user) // Relays icon update to the computer. /datum/computer_file/program/proc/update_computer_icon() @@ -83,53 +83,45 @@ // Check if the user can run program. Only humans can operate computer. Automatically called in run_program() // User has to wear their ID or have it inhand for ID Scan to work. // Can also be called manually, with optional parameter being access_to_check to scan the user's ID -/datum/computer_file/program/proc/can_run(var/mob/living/user, var/loud = 0, var/access_to_check) +/datum/computer_file/program/proc/can_run(var/list/accesses, var/mob/user, var/loud = 0) if(!requires_access_to_run) - return 1 - // Defaults to required_access - if(!access_to_check) - access_to_check = required_access - if(!access_to_check) // No required_access, allow it. - return 1 + return TRUE - // Admin override - allows operation of any computer as aghosted admin, as if you had any required access. - if(isghost(user) && check_rights(R_ADMIN, 0, user)) - return 1 + if(get_file_perms(accesses, user) & OS_READ_ACCESS) + return TRUE if(!istype(user)) - return 0 - - var/obj/item/card/id/I = user.GetIdCard() - if(!I) - if(loud) - to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") - return 0 + return FALSE - if(access_to_check in I.access) - return 1 - else if(loud) - to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") + if(loud) + to_chat(user, SPAN_WARNING("The OS flashes an \"Access Denied\" warning.")) + return FALSE // This attempts to retrieve header data for NanoUIs. If implementing completely new device of different type than existing ones // always include the device here in this proc. This proc basically relays the request to whatever is running the program. -/datum/computer_file/program/proc/get_header_data() +/datum/computer_file/program/proc/get_header_data(file_browser = FALSE) if(computer) - return computer.get_header_data() + return computer.get_header_data(file_browser) return list() // This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. // When implementing new program based device, use this to run the program. -/datum/computer_file/program/proc/on_startup(var/mob/living/user, var/datum/extension/interactive/ntos/new_host) +/datum/computer_file/program/proc/on_startup(var/mob/living/user, var/datum/extension/interactive/os/new_host) program_state = PROGRAM_STATE_ACTIVE computer = new_host if(nanomodule_path) NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src) if(user) - NM.using_access = user.GetAccess() + NM.using_access = computer.get_access() // Nano modules nab access from users in their get_access() proc so don't bother adding it + // to the using list as well. if(requires_network && network_destination) generate_network_log("Connection opened to [network_destination].") return 1 +/datum/computer_file/program/proc/update_access() + if(NM) + NM.using_access = computer.get_access() + // Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. /datum/computer_file/program/proc/on_shutdown(var/forced = 0) SHOULD_CALL_PARENT(TRUE) @@ -141,29 +133,35 @@ NM = null return 1 +// Called on active or minimized programs when a mounted file storage is removed from the OS. +/datum/computer_file/program/proc/on_file_storage_removal(var/datum/file_storage/removed) + // This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation. // It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable. /datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) SHOULD_CALL_PARENT(TRUE) ..() - if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. + if(program_state < PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. if(ui) ui.close() return computer.ui_interact(user) + if(program_state == PROGRAM_STATE_BROWSER) + return 0 if(istype(NM)) NM.ui_interact(user, ui_key, null, force_open) return 0 return 1 /datum/nano_module/program/proc/get_records() - var/datum/computer_network/network = program.computer.get_network() + var/datum/computer_network/network = program?.computer?.get_network() if(network) return network.get_crew_records() // CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: // Topic calls are automagically forwarded from NanoModule this program contains. // Calls beginning with "PRG_" are reserved for programs handling. -// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) +// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program). +// Calls beginning with "BRS_" are reserved for program file browser handling (not to be confused with the file manager program). // ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. /datum/computer_file/program/Topic(href, href_list) if(..()) diff --git a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm index 0d467aabbe45..070f698817ac 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm @@ -7,7 +7,6 @@ extended_desc = "This highly advanced script can very slowly decrypt operational codes used in almost any network. These codes can be downloaded to an ID card to expand the available access. The system administrator will probably notice this." size = 12 available_on_network = 0 - available_on_syndinet = 1 nanomodule_path = /datum/nano_module/program/access_decrypter/ var/message = "" var/running = FALSE @@ -110,7 +109,7 @@ /datum/nano_module/program/access_decrypter name = "Access Database Decrypter" -/datum/nano_module/program/access_decrypter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/access_decrypter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/datum/computer_file/program/access_decrypter/PRG = program var/list/data = list() if(!istype(PRG)) diff --git a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm index 85e2ce4e74ed..a76c4bc48058 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/hacked_camera.dm @@ -5,10 +5,10 @@ program_icon_state = "hostile" program_key_state = "security_key" program_menu_icon = "zoomin" - extended_desc = "This very advanced piece of software uses adaptive programming and large database of cipherkeys to bypass most encryptions used on camera networks. Be warned that system administrator may notice this." + extended_desc = "This very advanced piece of software uses adaptive programming and large database of cipherkeys to bypass most encryptions used on security cameras. Be warned that system administrator may notice this." size = 20 + requires_network_feature = 0 available_on_network = 0 - available_on_syndinet = 1 /datum/computer_file/program/camera_monitor/hacked/process_tick() ..() @@ -17,11 +17,11 @@ var/datum/nano_module/program/camera_monitor/hacked/HNM = NM - // The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick. - if(HNM && HNM.current_network && (HNM.current_network in GLOB.using_map.station_networks) && prob((SKILL_MAX - operator_skill) * 0.05)) + // The program is active and connected to one of the station's channels. Has a very small chance to trigger IDS alarm every tick. + if(HNM && HNM.current_channel && prob((SKILL_MAX - operator_skill) * 0.05)) var/datum/computer_network/net = computer.get_network() if(net.intrusion_detection_enabled) - computer.add_log("IDS WARNING - Unauthorised access detected to camera network [HNM.current_network] by device with NID [computer.get_network_tag()].") + computer.add_log("IDS WARNING - Unauthorised access detected to camera channel [HNM.current_channel] by device with NID [computer.get_network_tag()].") net.intrusion_detection_alarm = 1 /datum/computer_file/program/camera_monitor/hacked/ui_interact(mob/user) @@ -31,13 +31,4 @@ /datum/nano_module/program/camera_monitor/hacked name = "Hacked Camera Monitoring Program" available_to_ai = FALSE - -/datum/nano_module/program/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access) - return 1 - -// The hacked variant has access to all commonly used networks. -/datum/nano_module/program/camera_monitor/hacked/modify_networks_list(var/list/networks) - networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1))) - networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1))) - networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1))) - return networks \ No newline at end of file + bypass_access = TRUE \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm index 2b931c469fc4..f842cedfe416 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -7,7 +7,6 @@ extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution." size = 13 available_on_network = 0 - available_on_syndinet = 1 nanomodule_path = /datum/nano_module/program/revelation/ var/armed = 0 @@ -45,15 +44,15 @@ break return 1 -/datum/computer_file/program/revelation/clone() - var/datum/computer_file/program/revelation/temp = ..() - temp.armed = armed - return temp +/datum/computer_file/program/revelation/PopulateClone(datum/computer_file/program/revelation/clone) + clone = ..() + clone.armed = armed + return clone /datum/nano_module/program/revelation name = "Revelation Virus" -/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = list() var/datum/computer_file/program/revelation/PRG = program if(!istype(PRG)) diff --git a/code/modules/modular_computers/file_system/programs/antagonist/uplink.dm b/code/modules/modular_computers/file_system/programs/antagonist/uplink.dm index d3acd46b8373..56ef496ab522 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/uplink.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/uplink.dm @@ -17,7 +17,7 @@ /datum/nano_module/program/uplink name = "TaxQuickly 1.45b" -/datum/nano_module/program/uplink/ui_interact(var/mob/user, var/ui_key = "main", datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/uplink/ui_interact(var/mob/user, var/ui_key = "main", datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/datum/computer_file/program/uplink/prog = program var/obj/item/holder = program.computer.get_physical_host() if(istype(holder) && holder.hidden_uplink && prog.password) diff --git a/code/modules/modular_computers/file_system/programs/command/accounts.dm b/code/modules/modular_computers/file_system/programs/command/accounts.dm new file mode 100644 index 000000000000..9a66c2a4769a --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/command/accounts.dm @@ -0,0 +1,288 @@ +#define STATE_ERROR -1 +#define STATE_MENU 0 +#define STATE_SELF 1 +#define STATE_OTHER 2 + +/datum/computer_file/program/accounts + filename = "accountman" + filedesc = "Account management program" + nanomodule_path = /datum/nano_module/program/accounts + program_icon_state = "id" + program_key_state = "id_key" + program_menu_icon = "key" + extended_desc = "Program for managing network accounts and group membership." + size = 8 + category = PROG_COMMAND + +/datum/nano_module/program/accounts + name = "Account management program" + var/prog_state = STATE_MENU + var/datum/computer_file/data/account/selected_account + var/selected_parent_group + +/datum/nano_module/program/accounts/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + var/list/data = host.initial_data() + var/datum/computer_network/network = get_network() + if(!network) + data["error"] = "No accounts found. Check network connectivity." + prog_state = STATE_ERROR + switch(prog_state) + if(STATE_SELF) + data["account_name"] = selected_account.login + data["account_password"] = selected_account.password + data["account_fullname"] = selected_account.fullname + data["account_groups"] = selected_account.groups + if(STATE_OTHER) // Modifying other accounts. + var/datum/extension/network_device/acl/net_acl = network.access_controller + if(!net_acl) + data["error"] = "No access controller found on the network!" + prog_state = STATE_ERROR + else + var/list/group_dict = net_acl.get_group_dict() + if(!istype(selected_account)) + var/list/accounts = network.get_accounts() + data["accounts"] = list() + for(var/datum/computer_file/data/account/A in accounts) + data["accounts"] += list(list( + "account" = A.login, + "fullname" = A.fullname + )) + else + data["account_name"] = selected_account.login + data["account_fullname"] = selected_account.fullname + if(!selected_parent_group) + data["parent_groups"] = list() + for(var/parent_group in group_dict) + data["parent_groups"] += list(list( + "name" = parent_group, + "member" = (parent_group in selected_account.groups) + )) + else + var/list/child_groups = group_dict[selected_parent_group] + if(!child_groups) + data["error"] = "Invalid parent selected!" + selected_parent_group = null + return + data["parent_group"] = selected_parent_group + data["child_groups"] = list() + for(var/child_group in child_groups) + data["child_groups"] += list(list( + "name" = child_group, + "member" = (child_group in selected_account.groups) + )) + data["sub_management"] = net_acl.allow_submanagement + data["prog_state"] = prog_state + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "account_management.tmpl", name, 600, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/computer_file/program/accounts/Topic(href, href_list, state) + if(..()) + return 1 + + var/mob/user = usr + + var/datum/computer_network/network = computer.get_network() + var/datum/nano_module/program/accounts/module = NM + if(!network) + return + switch(module.prog_state) + if(STATE_MENU) + if(href_list["self_mode"]) + var/datum/computer_file/data/account/A = computer.get_account() + if(A) + module.selected_account = A + module.prog_state = STATE_SELF + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("No account found. Please login through your system before reattempting.")) + return TOPIC_HANDLED + + if(href_list["other_mode"]) + if(!computer.get_network_status(NET_FEATURE_RECORDS)) + to_chat(user, SPAN_WARNING("NETWORK ERROR - The network rejected access to account servers from your current connection.")) + return TOPIC_REFRESH + module.selected_account = null // Reset selected account just in case. + module.prog_state = STATE_OTHER + return TOPIC_REFRESH + + if(STATE_SELF) + if(!module.selected_account || computer.get_account() != module.selected_account) + module.selected_account = null + module.prog_state = STATE_MENU + to_chat(user, SPAN_WARNING("Authentication error. Please relogin to your account.")) + return TOPIC_REFRESH + + if(href_list["change_password"]) + var/new_password = input(user, "Input new account password.", "Change Password", module.selected_account.password) as text|null + var/password_check = alert(user, "Your new password will be [new_password]. Is this alright?", "Change Password", "Yes", "No") + if(password_check == "Yes") + if(!CanInteract(user,state)) + return TOPIC_HANDLED + module.selected_account.password = new_password + // Update the program's password too so the user doesn't have to login again. + computer.password = new_password + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(href_list["change_fullname"]) + var/new_fullname = input(user, "Input your full name.", "Change name", module.selected_account.fullname) as text|null + if(!CanInteract(user,state)) + return TOPIC_HANDLED + module.selected_account.fullname = new_fullname + return TOPIC_REFRESH + + if(STATE_OTHER) + if(!computer.get_network_status(NET_FEATURE_RECORDS)) + module.prog_state = STATE_MENU + to_chat(user, SPAN_WARNING("NETWORK ERROR - The network rejected access to account servers from your current connection.")) + return TOPIC_REFRESH + + if(href_list["select_account"]) + var/account_login = href_list["select_account"] + for(var/datum/computer_file/data/account/A in network.get_accounts()) + if(A.login == account_login) + module.selected_account = A + return TOPIC_REFRESH + + // Further actions require the ACL to be present on the network, so check if it exists first. + var/datum/extension/network_device/acl/net_acl = network.access_controller + if(!net_acl) + module.selected_parent_group = null // Just in case. + return TOPIC_REFRESH + var/list/group_dict = net_acl.get_group_dict() + + if(href_list["create_account"]) + var/list/account_creation_access + + // Passing null access to create_account will ignore access checks on account servers, so only assign this + // if the user doesn't have parent group account creation authorization. + if(!net_acl.check_account_creation_auth(computer.get_account())) + account_creation_access = NM.get_access(user) + var/new_login = input(user, "Input new account login. Login will be sanitized.", "Account Creation") as text|null + + var/login_check = alert(user, "Account login will be [sanitize_for_account(new_login)]. Is this acceptable?","Account Creation", "Yes", "No") + if(login_check == "Yes") + var/new_password = input(user, "Input new account password.", "Account Creation") as text|null + var/new_fullname = input(user, "Enter full name for account (e.g. John Smith)", "Account Creation") as text|null + if(!CanInteract(user,state)) + return TOPIC_HANDLED + if(network.create_account(null, new_login, new_password, new_fullname, account_creation_access, FALSE)) + to_chat(user, SPAN_NOTICE("Account successfully created!")) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("Account could not be created. It's possible an account with a matching login already exists, or you lack access to account servers.")) + return TOPIC_HANDLED + else + to_chat(user, SPAN_NOTICE("Account creation aborted.")) + return TOPIC_HANDLED + + if(href_list["recover_account"]) + var/list/account_recovery_access + + if(!net_acl.check_account_creation_auth(computer.get_account())) + account_recovery_access = NM.get_access(user) + + var/list/backups = network.get_account_backups(account_recovery_access) + if(!length(backups)) + to_chat(user, SPAN_WARNING("No account backups found on account servers!")) + return TOPIC_HANDLED + + var/selected_login = input(user, "Select the account backup you would like to recover:", "Account Backups") as anything in backups + if(!CanInteract(user, state) || !selected_login) + return TOPIC_HANDLED + + if(network.find_account_by_login(selected_login)) + to_chat(user, SPAN_WARNING("An account with that login already exists on the network! Cannot recover backup.")) + return TOPIC_HANDLED + + var/datum/computer_file/data/account/backup = backups[selected_login] + backup.backup = FALSE + backup.filename = replacetext(backup.filename, backup.copy_string, null) // Remove the backup signifier on the file. + to_chat(user, SPAN_NOTICE("Successfully recovered account [selected_login] from backup!")) + return TOPIC_REFRESH + + if(href_list["mod_group"]) + if(!module.selected_account || QDELETED(module.selected_account)) + module.selected_parent_group = null + return TOPIC_REFRESH + var/group_name = href_list["mod_group"] + var/is_parent_group = (group_name in group_dict) + if(!is_parent_group && !LAZYISIN(group_dict[module.selected_parent_group], group_name)) // Safety check. + module.selected_parent_group = null + return TOPIC_REFRESH + // This is a parent group, or group submanagement is disabled - no matter what, direct access to the ACL is required. + if(is_parent_group || !net_acl.allow_submanagement) + if(!net_acl.has_access(module.get_access(user))) + to_chat(user, SPAN_WARNING("Access denied.")) + return TOPIC_HANDLED + if(group_name in module.selected_account.groups) + module.selected_account.groups -= group_name + else + module.selected_account.groups += group_name + else + // Manual group membership check since the normal parent group access string normally grants child group members access. Modifying child groups is permitted if the program account + // is a member of the parent group. + var/datum/computer_file/data/account/A = computer.get_account() + var/is_parent_member = (module.selected_parent_group in A.groups) + if(is_parent_member || net_acl.has_access(module.get_access(user))) + if(group_name in module.selected_account.groups) + module.selected_account.groups -= group_name + else + module.selected_account.groups += group_name + else + to_chat(user, SPAN_WARNING("Access denied.")) + return TOPIC_HANDLED + + // Check to see if the account still has membership in a child group of the parent group and add to the parent groups list. + if(!is_parent_group) + for(var/group in module.selected_account.groups) + if(LAZYISIN(group_dict[module.selected_parent_group], group_name)) + module.selected_account.parent_groups |= module.selected_parent_group + return TOPIC_REFRESH + module.selected_account.parent_groups -= module.selected_parent_group + + if(href_list["select_parent_group"]) + if(module.selected_parent_group) + return TOPIC_REFRESH + var/parent_group = href_list["select_parent_group"] + if(parent_group in group_dict) + // In order to see child group membership, you need submanagement access or direct ACL access. + if(!net_acl.has_access(module.get_access(user))) + if(net_acl.allow_submanagement) + var/list/child_access = list("[parent_group].[network.network_id]") + if(!has_access(child_access, module.get_access(user))) + to_chat(user, SPAN_WARNING("Access denied.")) + return TOPIC_HANDLED + else + to_chat(user, SPAN_WARNING("Access denied.")) + return TOPIC_HANDLED + module.selected_parent_group = parent_group + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(href_list["back"]) + switch(module.prog_state) + if(STATE_ERROR) + module.prog_state = STATE_MENU + if(STATE_SELF) + module.prog_state = STATE_MENU + module.selected_account = null + if(STATE_OTHER) + if(module.selected_parent_group) + module.selected_parent_group = null + else if(module.selected_account) + module.selected_account = null + else + module.prog_state = STATE_MENU + return TOPIC_REFRESH + SSnano.update_uis(module) + return 1 + +#undef STATE_ERROR +#undef STATE_MENU +#undef STATE_SELF +#undef STATE_OTHER \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm index 2f2df1e98ffc..af9339b6a132 100644 --- a/code/modules/modular_computers/file_system/programs/command/card.dm +++ b/code/modules/modular_computers/file_system/programs/command/card.dm @@ -7,6 +7,7 @@ program_menu_icon = "key" extended_desc = "Program for programming crew ID cards." size = 8 + write_access = list(access_change_ids) category = PROG_COMMAND /datum/nano_module/program/card_mod @@ -15,7 +16,7 @@ var/is_centcom = 0 var/show_assignments = 0 -/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/obj/item/stock_parts/computer/card_slot/card_slot = program.computer.get_component(PART_CARD) @@ -25,29 +26,37 @@ data["assignments"] = show_assignments data["have_id_slot"] = !!card_slot data["have_printer"] = program.computer.has_component(PART_PRINTER) - data["authenticated"] = program.can_run(user) + data["authenticated"] = program.get_file_perms(get_access(user), user) & OS_WRITE_ACCESS if(!data["have_id_slot"] || !data["have_printer"]) mod_mode = 0 //We can't modify IDs when there is no card reader if(card_slot) var/obj/item/card/id/id_card = card_slot.stored_card data["has_id"] = !!id_card data["id_account_number"] = id_card ? id_card.associated_account_number : null - data["id_email_login"] = id_card ? id_card.associated_email_login["login"] : null - data["id_email_password"] = id_card ? stars(id_card.associated_email_login["password"], 0) : null + data["network_account_login"] = id_card ? id_card.associated_network_account["login"] : null + data["network_account_password"] = id_card ? stars(id_card.associated_network_account["password"], 0) : null data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned" data["id_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----" data["id_name"] = id_card ? id_card.name : "-----" + data["gender"] = id_card ? id_card.card_gender : "UNSET" + data["age"] = id_card ? id_card.age : "UNSET" + data["dna_hash"] = id_card ? id_card.dna_hash : "UNSET" + data["fingerprint_hash"] = id_card ? id_card.fingerprint_hash : "UNSET" + data["blood_type"] = id_card ? id_card.blood_type : "UNSET" + data["front_photo"] = id_card ? id_card.front : "UNSET" + data["side_photo"] = id_card ? id_card.side : "UNSET" data["mmode"] = mod_mode data["centcom_access"] = is_centcom data["titles_by_dept"] = list() - for(var/dept_key in SSdepartments.departments) - var/datum/department/dept = SSdepartments.departments[dept_key] - var/list/map_jobs = SSjobs.titles_by_department(dept.reference) + var/list/all_departments = decls_repository.get_decls_of_subtype(/decl/department) + for(var/dept_key in all_departments) + var/decl/department/dept = all_departments[dept_key] + var/list/map_jobs = SSjobs.titles_by_department(dept.type) if(LAZYLEN(map_jobs)) data["titles_by_dept"] += list(list( "department_colour" = dept.colour, - "department_name" = capitalize(dept.reference), + "department_name" = capitalize(dept.name), "department_titles" = format_jobs(map_jobs) )) data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) @@ -101,6 +110,24 @@ /datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0) return null +/datum/computer_file/program/card_mod/proc/get_photo(mob/user) + if(istype(user.get_active_held_item(), /obj/item/photo)) + var/obj/item/photo/photo = user.get_active_held_item() + return photo.img + + if(issilicon(user)) + var/mob/living/silicon/tempAI = user + var/obj/item/photo/selection = tempAI.GetPicture() + if (selection) + return selection.img + +/datum/computer_file/program/card_mod/proc/get_access_by_rank(rank) + var/datum/job/jobdatum = SSjobs.get_by_title(rank) + if(!jobdatum) + to_chat(usr, SPAN_WARNING("No log exists for this job: [rank]")) + return + + return jobdatum.get_access() /datum/computer_file/program/card_mod/Topic(href, href_list) if(..()) @@ -123,81 +150,134 @@ else module.show_assignments = 1 if("print") - if(!authorized(user_id_card)) - to_chat(usr, "Access denied.") + if(!(get_file_perms(module.get_access(user), user) & OS_WRITE_ACCESS)) + to_chat(user, SPAN_WARNING("Access denied.")) return if(computer.has_component(PART_PRINTER)) //This option should never be called if there is no printer if(module.mod_mode) - if(can_run(user, 1)) - var/contents = {"

    Access Report

    - Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
    - For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
    -
    - Assignment: [id_card.assignment]
    - Account Number: #[id_card.associated_account_number]
    - Email account: [id_card.associated_email_login["login"]] - Email password: [stars(id_card.associated_email_login["password"], 0)] - Blood Type: [id_card.blood_type]

    - Access:
    - "} - - var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) - for(var/A in id_card.access) - if(A in known_access_rights) - contents += " [get_access_desc(A)]" - - if(!computer.print_paper(contents,"access report")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return + var/contents = {"

    Access Report

    + Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
    + For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
    +
    + Assignment: [id_card.assignment]
    + Account Number: #[id_card.associated_account_number]
    + Network account: [id_card.associated_network_account["login"]] + Network password: [stars(id_card.associated_network_account["password"], 0)] + Blood Type: [id_card.blood_type]

    + Age: [id_card.age]

    + Gender: [id_card.card_gender]

    + Access:
    + "} + + var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) + for(var/A in id_card.access) + if(A in known_access_rights) + contents += " [get_access_desc(A)]" + + if(!computer.print_paper(contents,"access report")) + to_chat(user, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return else var/contents = {"

    Crew Manifest


    [html_crew_manifest()] "} if(!computer.print_paper(contents, "crew manifest ([stationtime2text()])")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + to_chat(user, "Hardware error: Printer was unable to print the file. It may be out of paper.") return if("eject") var/obj/item/stock_parts/computer/card_slot/card_slot = computer.get_component(PART_CARD) if(computer.get_inserted_id()) card_slot.eject_id(user) else - card_slot.insert_id(user.get_active_hand(), user) + card_slot.insert_id(user.get_active_held_item(), user) if("terminate") - if(!authorized(user_id_card)) - to_chat(usr, "Access denied.") + if(!(get_file_perms(module.get_access(user), user) & OS_WRITE_ACCESS)) + to_chat(user, SPAN_WARNING("Access denied.")) return - if(computer && can_run(user, 1)) + if(computer) id_card.assignment = "Terminated" remove_nt_access(id_card) - callHook("terminate_employee", list(id_card)) + RAISE_EVENT(/decl/observ/employee_id_terminated, id_card) if("edit") - if(!authorized(user_id_card)) - to_chat(usr, "Access denied.") + if(!(get_file_perms(module.get_access(user), user) & OS_WRITE_ACCESS)) + to_chat(user, SPAN_WARNING("Access denied.")) return - if(computer && can_run(user, 1)) + if(computer) + var/static/regex/hash_check = regex(@"^[0-9a-fA-F]{32}$") if(href_list["name"]) - var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE) - if(temp_name) + var/temp_name = sanitize_name(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE) + if(temp_name && CanUseTopic(user)) id_card.registered_name = temp_name id_card.formal_name_suffix = initial(id_card.formal_name_suffix) id_card.formal_name_prefix = initial(id_card.formal_name_prefix) else - computer.show_error(usr, "Invalid name entered!") + computer.show_error(user, "Invalid name entered!") else if(href_list["account"]) var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number)) id_card.associated_account_number = account_num - else if(href_list["elogin"]) - var/email_login = input("Enter email login.", "Email login", id_card.associated_email_login["login"]) - id_card.associated_email_login["login"] = email_login - else if(href_list["epswd"]) - var/email_password = input("Enter email password.", "Email password") - id_card.associated_email_login["password"] = email_password + else if(href_list["alogin"]) + var/account_login = input("Enter network account login.", "Network account login", id_card.associated_network_account["login"]) + id_card.associated_network_account["login"] = account_login + else if(href_list["apswd"]) + var/account_password = input("Enter network account password.", "Network account password") + id_card.associated_network_account["password"] = account_password + else if(href_list["gender"]) + var/new_gender = input("Type gender.", "Gender", id_card.card_gender) + if(!isnull(new_gender) && CanUseTopic(user)) + id_card.card_gender = new_gender + else if(href_list["age"]) + var/sug_age = text2num(input("Enter age.", "Age", id_card.age)) + if(!isnull(sug_age) && CanUseTopic(user)) + id_card.age = sug_age + else if(href_list["fingerprint_hash"]) + var/sug_fingerprint_hash = sanitize(input("Enter fingerprint hash.", "Fingerprint hash", id_card.fingerprint_hash), 32) + if(hash_check.Find(sug_fingerprint_hash) && CanUseTopic(user)) + id_card.fingerprint_hash = sug_fingerprint_hash + else if(href_list["dna_hash"]) + var/sug_dna_hash = sanitize(input("Enter DNA hash.", "DNA hash", id_card.dna_hash), 32) + if(hash_check.Find(sug_dna_hash) && CanUseTopic(user)) + id_card.dna_hash = sug_dna_hash + else if(href_list["blood_type"]) + var/sug_blood_type = input("Select blood type.", "Blood type") as null|anything in get_all_blood_types() + if(!isnull(sug_blood_type) && CanUseTopic(user)) + id_card.blood_type = sug_blood_type + else if(href_list["front_photo"]) + var/photo = get_photo(user) + if(photo && CanUseTopic(user)) + id_card.front = photo + else if(href_list["side_photo"]) + var/photo = get_photo(user) + if(photo && CanUseTopic(user)) + id_card.side = photo + else if(href_list["load_data"]) + var/list/ass_data = list() + for(var/datum/computer_file/report/crew_record/CR in global.all_crew_records) + ass_data.Add(list(CR.get_name() = CR)) + var/selected_CR_name = input("Select crew record for write down to the card.", "Crew record selection") as null|anything in ass_data + var/datum/computer_file/report/crew_record/selected_CR = get_crewmember_record(selected_CR_name) + if(!isnull(selected_CR) && CanUseTopic(user)) + id_card.registered_name = selected_CR.get_name() + id_card.assignment = selected_CR.get_job() + id_card.position = selected_CR.get_rank() + id_card.dna_hash = selected_CR.get_dna() + id_card.fingerprint_hash = selected_CR.get_fingerprint() + id_card.card_gender = selected_CR.get_gender() + id_card.age = selected_CR.get_age() + id_card.blood_type = selected_CR.get_bloodtype() + id_card.front = selected_CR.photo_front + id_card.side = selected_CR.photo_side + var/list/access = get_access_by_rank(selected_CR.get_job()) + if(isnull(access)) + SSnano.update_uis(NM) + return 1 + remove_nt_access(id_card) + apply_access(id_card, access) if("assign") - if(!authorized(user_id_card)) - to_chat(usr, "Access denied.") + if(!(get_file_perms(module.get_access(user), user) & OS_WRITE_ACCESS)) + to_chat(user, SPAN_WARNING("Access denied.")) return - if(computer && can_run(user, 1) && id_card) + if(computer && id_card) var/t1 = href_list["assign_target"] if(t1 == "Custom") var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) @@ -209,27 +289,22 @@ if(module.is_centcom) access = get_centcom_access(t1) else - var/datum/job/jobdatum = SSjobs.get_by_title(t1) - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") - return - - access = jobdatum.get_access() + access = get_access_by_rank(t1) remove_nt_access(id_card) apply_access(id_card, access) id_card.assignment = t1 - id_card.rank = t1 + id_card.position = t1 - callHook("reassign_employee", list(id_card)) + RAISE_EVENT(/decl/observ/employee_id_reassigned, id_card) if("access") - if(href_list["allowed"] && computer && can_run(user, 1) && id_card) + if(href_list["allowed"] && id_card) var/access_type = href_list["access_target"] var/access_allowed = text2num(href_list["allowed"]) if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)) - for(var/access in user_id_card.access) + for(var/access in module.get_access(user)) var/region_type = get_access_region_by_id(access_type) - if(access in GLOB.using_map.access_modify_region[region_type]) + if(access in global.using_map.access_modify_region[region_type]) id_card.access -= access_type if(!access_allowed) id_card.access += access_type @@ -244,7 +319,4 @@ id_card.access -= get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) /datum/computer_file/program/card_mod/proc/apply_access(var/obj/item/card/id/id_card, var/list/accesses) - id_card.access |= accesses - -/datum/computer_file/program/card_mod/proc/authorized(var/obj/item/card/id/id_card) - return id_card && (access_change_ids in id_card.access) \ No newline at end of file + id_card.access |= accesses \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/command/comm.dm b/code/modules/modular_computers/file_system/programs/command/comm.dm index 308e29a2909b..fbb4c292e2c5 100644 --- a/code/modules/modular_computers/file_system/programs/command/comm.dm +++ b/code/modules/modular_computers/file_system/programs/command/comm.dm @@ -11,19 +11,19 @@ program_menu_icon = "flag" nanomodule_path = /datum/nano_module/program/comm extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers." - required_access = access_bridge + read_access = list(access_bridge) requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL size = 12 usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP network_destination = "long-range communication array" category = PROG_COMMAND var/datum/comm_message_listener/message_core = new -/datum/computer_file/program/comm/clone() - var/datum/computer_file/program/comm/temp = ..() - temp.message_core.messages = null - temp.message_core.messages = message_core.messages.Copy() - return temp +/datum/computer_file/program/comm/PopulateClone(datum/computer_file/program/comm/clone) + clone = ..() + clone.message_core = message_core.Clone() + return clone /datum/nano_module/program/comm name = "Command and Communications Program" @@ -41,13 +41,13 @@ ..() crew_announcement.newscast = 1 -/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() if(program) - data["net_comms"] = !!program.get_signal(NETWORK_COMMUNICATION) //Double !! is needed to get 1 or 0 answer - data["net_syscont"] = !!program.get_signal(NETWORK_SYSTEMCONTROL) + data["net_comms"] = !!program.get_signal(NET_FEATURE_COMMUNICATION) //Double !! is needed to get 1 or 0 answer + data["net_syscont"] = !!program.get_signal(NET_FEATURE_SYSTEMCONTROL) if(program.computer) data["emagged"] = program.computer.emagged() data["have_printer"] = program.computer.has_component(PART_PRINTER) @@ -62,11 +62,11 @@ data["message_line1"] = msg_line1 data["message_line2"] = msg_line2 data["state"] = current_status - data["isAI"] = issilicon(usr) - data["authenticated"] = is_autenthicated(user) - data["boss_short"] = GLOB.using_map.boss_short + data["isAI"] = issilicon(user) + data["authenticated"] = is_authenticated(user) + data["boss_short"] = global.using_map.boss_short - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) data["current_security_level_ref"] = any2ref(security_state.current_security_level) data["current_security_level_title"] = security_state.current_security_level.name @@ -88,16 +88,16 @@ data["message_current"] = current_viewing_message var/list/processed_evac_options = list() - if(!isnull(SSevac.evacuation_controller)) - for (var/datum/evacuation_option/EO in SSevac.evacuation_controller.available_evac_options()) - if(EO.abandon_ship) - continue - var/list/option = list() - option["option_text"] = EO.option_text - option["option_target"] = EO.option_target - option["needs_syscontrol"] = EO.needs_syscontrol - option["silicon_allowed"] = EO.silicon_allowed - processed_evac_options[++processed_evac_options.len] = option + for (var/datum/evacuation_option/EO in SSevac.evacuation_controller?.available_evac_options()) + if(EO.abandon_ship) + continue + var/list/option = list() + option["option_text"] = EO.option_text + option["option_target"] = EO.option_target + option["needs_syscontrol"] = EO.needs_syscontrol + option["silicon_allowed"] = EO.silicon_allowed + option["requires_shunt"] = EO.requires_shunt + processed_evac_options[++processed_evac_options.len] = option data["evac_options"] = processed_evac_options ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -107,11 +107,33 @@ ui.set_initial_data(data) ui.open() -/datum/nano_module/program/comm/proc/is_autenthicated(var/mob/user) +/datum/nano_module/program/comm/proc/is_authenticated(var/mob/user) if(program) - return program.can_run(user) + return program.get_file_perms(get_access(user), user) & OS_READ_ACCESS return 1 +/datum/nano_module/program/comm/proc/get_shunt() + if(isnull(program?.computer)) + return FALSE + + var/obj/comp = program.computer.get_physical_host() + + if(isnull(comp)) + return FALSE + + var/obj/effect/overmap/visitable/ship/sector = comp.get_owning_overmap_object() + + if(!istype(sector)) + return + + for(var/obj/machinery/ftl_shunt/core/C in SSmachines.machinery) + if(C.z in sector.map_z) + if(C.get_status() != 2) //magic number because defines are lower than this file. + return TRUE + + return FALSE + + /datum/nano_module/program/comm/proc/obtain_message_listener() if(program) var/datum/computer_file/program/comm/P = program @@ -122,8 +144,8 @@ if(..()) return 1 var/mob/user = usr - var/ntn_comm = program ? !!program.get_signal(NETWORK_COMMUNICATION) : 1 - var/ntn_cont = program ? !!program.get_signal(NETWORK_SYSTEMCONTROL) : 1 + var/ntn_comm = program ? !!program.get_signal(NET_FEATURE_COMMUNICATION) : 1 + var/ntn_cont = program ? !!program.get_signal(NET_FEATURE_SYSTEMCONTROL) : 1 var/datum/comm_message_listener/l = obtain_message_listener() switch(href_list["action"]) if("sw_menu") @@ -131,19 +153,19 @@ current_status = text2num(href_list["target"]) if("announce") . = 1 - if(is_autenthicated(user) && !issilicon(usr) && ntn_comm) + if(is_authenticated(user) && !issilicon(user) && ntn_comm) if(user) var/obj/item/card/id/id_card = user.GetIdCard() crew_announcement.announcer = GetNameAndAssignmentFromId(id_card) else crew_announcement.announcer = "Unknown" if(announcment_cooldown) - to_chat(usr, "Please allow at least one minute to pass between announcements") + to_chat(user, "Please allow at least one minute to pass between announcements.") return TRUE - var/input = input(usr, "Please write a message to announce to the [station_name()].", "Priority Announcement") as null|message - if(!input || !can_still_topic()) + var/input = input(user, "Please write a message to announce to the [station_name()].", "Priority Announcement") as null|message + if(!input || !can_still_topic() || filter_block_message(user, input)) return 1 - var/affected_zlevels = GetConnectedZlevels(get_host_z()) + var/affected_zlevels = SSmapping.get_connected_levels(get_host_z()) crew_announcement.Announce(input, zlevels = affected_zlevels) announcment_cooldown = 1 spawn(600)//One minute cooldown @@ -152,41 +174,41 @@ . = 1 if(href_list["target"] == "emagged") if(program) - if(is_autenthicated(user) && program.computer.emagged() && !issilicon(usr) && ntn_comm) + if(is_authenticated(user) && program.computer.emagged() && !issilicon(user) && ntn_comm) if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") + to_chat(user, "Arrays recycling. Please stand by.") SSnano.update_uis(src) return - var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) - if(!input || !can_still_topic()) + var/input = sanitize(input(user, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) + if(!input || !can_still_topic() || filter_block_message(user, input)) return 1 - Syndicate_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an illegal announcement: [input]") + Syndicate_announce(input, user) + to_chat(user, "Message transmitted.") + log_say("[key_name(user)] has made an illegal announcement: [input]") centcomm_message_cooldown = 1 spawn(300)//30 second cooldown centcomm_message_cooldown = 0 else if(href_list["target"] == "regular") - if(is_autenthicated(user) && !issilicon(usr) && ntn_comm) + if(is_authenticated(user) && !issilicon(user) && ntn_comm) if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") + to_chat(user, "Arrays recycling. Please stand by.") SSnano.update_uis(src) return if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs. - to_chat(usr, "No emergency communication relay detected. Unable to transmit message.") + to_chat(user, "No emergency communication relay detected. Unable to transmit message.") return 1 - var/input = sanitize(input("Please choose a message to transmit to [GLOB.using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) - if(!input || !can_still_topic()) + var/input = sanitize(input("Please choose a message to transmit to [global.using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) + if(!input || !can_still_topic() || filter_block_message(user, input)) return 1 - Centcomm_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an IA [GLOB.using_map.boss_short] announcement: [input]") + Centcomm_announce(input, user) + to_chat(user, "Message transmitted.") + log_say("[key_name(user)] has made an IA [global.using_map.boss_short] announcement: [input]") centcomm_message_cooldown = 1 spawn(300) //30 second cooldown centcomm_message_cooldown = 0 if("evac") . = 1 - if(is_autenthicated(user)) + if(SSevac.evacuation_controller && is_authenticated(user)) var/datum/evacuation_option/selected_evac_option = SSevac.evacuation_controller.evacuation_options[href_list["target"]] if (isnull(selected_evac_option) || !istype(selected_evac_option)) return @@ -194,12 +216,14 @@ return if (selected_evac_option.needs_syscontrol && !ntn_cont) return + if (selected_evac_option.requires_shunt && !get_shunt()) + return var/confirm = alert("Are you sure you want to [selected_evac_option.option_desc]?", name, "No", "Yes") if (confirm == "Yes" && can_still_topic()) SSevac.evacuation_controller.handle_evac_option(selected_evac_option.option_target, user) if("setstatus") . = 1 - if(is_autenthicated(user) && ntn_cont) + if(is_authenticated(user) && ntn_cont) switch(href_list["target"]) if("line1") var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40) @@ -217,8 +241,8 @@ post_status(href_list["target"]) if("setalert") . = 1 - if(is_autenthicated(user) && !issilicon(usr) && ntn_cont && ntn_comm) - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + if(is_authenticated(user) && !issilicon(user) && ntn_cont && ntn_comm) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) var/decl/security_level/target_level = locate(href_list["target"]) in security_state.comm_console_security_levels if(target_level && security_state.can_switch_to(target_level)) var/confirm = alert("Are you sure you want to change the alert level to [target_level.name]?", name, "No", "Yes") @@ -226,12 +250,12 @@ if(security_state.set_security_level(target_level)) SSstatistics.add_field(target_level.type,1) else - to_chat(usr, "You press the button, but a red light flashes and nothing happens.") //This should never happen + to_chat(user, "You press the button, but a red light flashes and nothing happens.") //This should never happen current_status = STATE_DEFAULT if("viewmessage") . = 1 - if(is_autenthicated(user) && ntn_comm) + if(is_authenticated(user) && ntn_comm) current_viewing_message_id = text2num(href_list["target"]) for(var/list/m in l.messages) if(m["id"] == current_viewing_message_id) @@ -239,20 +263,20 @@ current_status = STATE_VIEWMESSAGE if("delmessage") . = 1 - if(is_autenthicated(user) && ntn_comm && l != global_message_listener) + if(is_authenticated(user) && ntn_comm && l != global_message_listener) l.Remove(current_viewing_message) current_status = STATE_MESSAGELIST if("printmessage") . = 1 - if(is_autenthicated(user) && ntn_comm) + if(is_authenticated(user) && ntn_comm) if(!program.computer.print_paper(current_viewing_message["contents"],current_viewing_message["title"])) - to_chat(usr, "Hardware Error: Printer was unable to print the selected file.") + to_chat(user, "Hardware Error: Printer was unable to print the selected file.") if("unbolt_doors") - GLOB.using_map.unbolt_saferooms() - to_chat(usr, "The console beeps, confirming the signal was sent to have the saferooms unbolted.") + global.using_map.unbolt_saferooms() + to_chat(user, "The console beeps, confirming the signal was sent to have the saferooms unbolted.") if("bolt_doors") - GLOB.using_map.bolt_saferooms() - to_chat(usr, "The console beeps, confirming the signal was sent to have the saferooms bolted.") + global.using_map.bolt_saferooms() + to_chat(user, "The console beeps, confirming the signal was sent to have the saferooms bolted.") #undef STATE_DEFAULT #undef STATE_MESSAGELIST @@ -263,9 +287,9 @@ /* General message handling stuff */ -var/list/comm_message_listeners = list() //We first have to initialize list then we can use it. -var/datum/comm_message_listener/global_message_listener = new //May be used by admins -var/last_message_id = 0 +var/global/list/comm_message_listeners = list() //We first have to initialize list then we can use it. +var/global/datum/comm_message_listener/global_message_listener = new //May be used by admins +var/global/last_message_id = 0 /proc/get_comm_message_id() last_message_id = last_message_id + 1 @@ -294,6 +318,11 @@ var/last_message_id = 0 /datum/comm_message_listener/proc/Remove(var/list/message) messages -= list(message) +/datum/comm_message_listener/PopulateClone(datum/comm_message_listener/clone) + clone = ..() + clone.messages = listDeepClone(messages) + return clone + /proc/post_status(var/command, var/data1, var/data2) var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) @@ -301,7 +330,6 @@ var/last_message_id = 0 if(!frequency) return var/datum/signal/status_signal = new - status_signal.transmission_method = 1 status_signal.data["command"] = command switch(command) @@ -337,7 +365,7 @@ var/last_message_id = 0 if(isnull(emergency)) emergency = 1 - if(!GLOB.universe.OnShuttleCall(usr)) + if(!global.universe.OnShuttleCall(user)) to_chat(user, "Cannot establish a connection.") return diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm index 0b0357998d3b..48e936549069 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm @@ -8,6 +8,8 @@ program_menu_icon = "alert" extended_desc = "This program provides visual interface for the alarm system." requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL + network_destination = "alarm monitoring network" size = 5 category = PROG_MONITOR @@ -32,7 +34,6 @@ /datum/nano_module/alarm_monitor name = "Alarm monitor" - var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use. var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. available_to_ai = FALSE @@ -103,7 +104,7 @@ usr.switch_to_camera(C) return 1 -/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/categories[0] diff --git a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm index 429b998018de..c1e691ad90e1 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/atmos_control.dm @@ -6,67 +6,95 @@ program_key_state = "atmos_key" program_menu_icon = "shuffle" extended_desc = "This program allows remote control of air alarms. This program can not be run on tablet computers." - required_access = access_atmospherics + read_access = list(access_atmospherics) requires_network = 1 network_destination = "atmospheric control system" - requires_network_feature = NETWORK_SYSTEMCONTROL + requires_network_feature = NET_FEATURE_SYSTEMCONTROL usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE category = PROG_ENG size = 17 /datum/nano_module/atmos_control name = "Atmospherics Control" - var/obj/access = new() - var/emagged = 0 - var/ui_ref var/list/monitored_alarms = list() + var/list/filter_strings = list() // user weakref -> string filter + var/list/alarm_data_cache = list() // user weakref -> cached camera data -/datum/nano_module/atmos_control/New(atmos_computer, var/list/req_access, monitored_alarm_ids) - ..() +/datum/nano_module/atmos_control/proc/set_monitored_alarms(monitored_alarm_ids) // you have to call this after creating the nanomodule if you want to set a custom list. + for(var/obj/machinery/alarm/alarm in SSmachines.machinery) + if(!monitored_alarm_ids || (alarm.alarm_id && (alarm.alarm_id in monitored_alarm_ids))) + monitored_alarms += alarm + monitored_alarms = dd_sortedObjectList(monitored_alarms) - if(istype(req_access)) - access.req_access = req_access - else if(req_access) - log_debug("\The [src] was given an unepxected req_access: [req_access]") - - if(monitored_alarm_ids) - for(var/obj/machinery/alarm/alarm in SSmachines.machinery) - if(alarm.alarm_id && (alarm.alarm_id in monitored_alarm_ids)) - monitored_alarms += alarm - // machines may not yet be ordered at this point - monitored_alarms = dd_sortedObjectList(monitored_alarms) - -/datum/nano_module/atmos_control/Topic(href, href_list) +/datum/nano_module/atmos_control/Topic(href, href_list, state) if(..()) return 1 if(href_list["alarm"]) + var/ui_ref = SSnano.get_open_ui(usr, src, "main") if(ui_ref) var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms.len ? monitored_alarms : SSmachines.machinery) - if(alarm) - var/datum/topic_state/TS = generate_state(alarm) + if(istype(alarm)) + var/datum/topic_state/remote/TS = new (src, alarm, state) alarm.ui_interact(usr, master_ui = ui_ref, state = TS) return 1 -/datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) + if(href_list["filter_set"]) + var/string = input(usr, "Set text filter:", "Filter Selection", filter_strings[weakref(usr)]) as null|text + if(!CanInteract(usr, state)) + return TOPIC_REFRESH + string = sanitize(string) + string = lowertext(string) + if(!string) + filter_strings -= weakref(usr) + else + filter_strings[weakref(usr)] = string + alarm_data_cache -= weakref(usr) + return TOPIC_REFRESH + + if(href_list["refresh"]) + alarm_data_cache -= weakref(usr) + return TOPIC_REFRESH + +/datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() - var/alarms[0] - var/alarmsAlert[0] - var/alarmsDanger[0] + if(!length(monitored_alarms)) + set_monitored_alarms() - // TODO: Move these to a cache, similar to cameras - for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : SSmachines.machinery)) - var/danger_level = max(alarm.danger_level, alarm.alarm_area.atmosalm) - if(danger_level == 2) - alarmsAlert[++alarmsAlert.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = danger_level) - else if(danger_level == 1) - alarmsDanger[++alarmsDanger.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = danger_level) - else - alarms[++alarms.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = danger_level) - - data["alarms"] = alarms - data["alarmsAlert"] = alarmsAlert - data["alarmsDanger"] = alarmsDanger + var/list/alarms_data = alarm_data_cache[weakref(user)] + var/filter = filter_strings[weakref(user)] + + if(!alarms_data) + var/Z = get_host_z() + var/list/alarms = list() + var/list/alarmsAlert = list() + var/list/alarmsDanger = list() + + for(var/obj/machinery/alarm/alarm in monitored_alarms) + if (!Z || !SSmapping.are_connected_levels(Z, alarm.z)) + continue + var/alarm_name = sanitize(alarm.name) + alarm_name = replacetext(alarm_name, " Air Alarm", "") // shorten titles + + if(filter && !findtext(lowertext(alarm_name), filter)) + continue + + var/danger_level = max(alarm.danger_level, alarm.alarm_area.atmosalm) + if(danger_level == 2) + alarmsAlert[++alarmsAlert.len] = list("name" = alarm_name, "ref"= "\ref[alarm]", "danger" = danger_level) + else if(danger_level == 1) + alarmsDanger[++alarmsDanger.len] = list("name" = alarm_name, "ref"= "\ref[alarm]", "danger" = danger_level) + else + alarms[++alarms.len] = list("name" = alarm_name, "ref"= "\ref[alarm]", "danger" = danger_level) + + alarms_data = list() + alarms_data["alarms"] = sortTim(alarms, /proc/cmp_list_name_key_asc) + alarms_data["alarmsAlert"] = sortTim(alarmsAlert, /proc/cmp_list_name_key_asc) + alarms_data["alarmsDanger"] = sortTim(alarmsDanger, /proc/cmp_list_name_key_asc) + alarm_data_cache[weakref(user)] = alarms_data + + data += alarms_data + data["filter"] = filter || "---" ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) @@ -75,30 +103,4 @@ ui.auto_update_layout = 1 ui.set_initial_data(data) ui.open() - ui.set_auto_update(1) - ui_ref = ui - -/datum/nano_module/atmos_control/proc/generate_state(air_alarm) - var/datum/topic_state/air_alarm/state = new() - state.atmos_control = src - state.air_alarm = air_alarm - return state - -/datum/topic_state/air_alarm - var/datum/nano_module/atmos_control/atmos_control = null - var/obj/machinery/alarm/air_alarm = null - -/datum/topic_state/air_alarm/can_use_topic(var/src_object, var/mob/user) - if(alarm_has_access(user)) - return STATUS_INTERACTIVE - return STATUS_UPDATE - -/datum/topic_state/air_alarm/href_list(var/mob/user) - var/list/extra_href = list() - extra_href["remote_connection"] = 1 - extra_href["remote_access"] = alarm_has_access(user) - - return extra_href - -/datum/topic_state/air_alarm/proc/alarm_has_access(var/mob/user) - return user && (isAI(user) || atmos_control.access.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO)) + ui.set_auto_update(1) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/engineering/network_monitoring.dm b/code/modules/modular_computers/file_system/programs/engineering/network_monitoring.dm index da77bf2f1cb8..779fc79ec5af 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/network_monitoring.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/network_monitoring.dm @@ -4,6 +4,7 @@ program_icon_state = "comm_monitor" program_key_state = "generic_key" program_menu_icon = "wrench" + read_access = list(access_network) extended_desc = "This program monitors the local computer network, provides access to logging systems, and allows for configuration changes" size = 12 nanomodule_path = /datum/nano_module/program/network_monitor/ @@ -11,13 +12,18 @@ /datum/nano_module/program/network_monitor name = "Network Diagnostics and Monitoring" - var/global/list/all_network_features = list( - "Software Download" = NETWORK_SOFTWAREDOWNLOAD, - "Communication Systems" = NETWORK_COMMUNICATION, - "Remote System Control" = NETWORK_SYSTEMCONTROL + var/static/list/all_network_features = list( + "Software Download" = NET_FEATURE_SOFTWAREDOWNLOAD, + "Communication Systems" = NET_FEATURE_COMMUNICATION, + "Remote System Control" = NET_FEATURE_SYSTEMCONTROL, + "Access systems" = NET_FEATURE_ACCESS, + "Personnel Administration" = NET_FEATURE_RECORDS, + "Security systems" = NET_FEATURE_SECURITY, + "Filesystem access" = NET_FEATURE_FILESYSTEM, + "Deck control" = NET_FEATURE_DECK ) -/datum/nano_module/program/network_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/network_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() data += "skill_fail" @@ -26,7 +32,7 @@ data["skill_fail"] = fake_data.update_and_return_data() data["terminal"] = !!program - var/datum/computer_network/network = program.computer.get_network() + var/datum/computer_network/network = program?.computer?.get_network() data["status"] = !!network if(network) data["network"] = network.network_id @@ -41,7 +47,7 @@ rdata["flag"] = all_network_features[feature] features.Add(list(rdata)) data["features"] = features - + var/list/mainframes[0] for(var/datum/extension/network_device/mainframe/M in network.mainframes) var/list/rdata[0] @@ -51,11 +57,12 @@ mainframes.Add(list(rdata)) data["mainframes"] = mainframes - if(length(network.get_mainframes_by_role(MF_ROLE_LOG_SERVER, user))) + var/list/eligible_log_servers = network.get_mainframes_by_role(MF_ROLE_LOG_SERVER, user.GetAccess()) + if(length(eligible_log_servers)) var/list/logs[0] - for(var/datum/extension/network_device/mainframe/M in network.get_mainframes_by_role(MF_ROLE_LOG_SERVER, user)) + for(var/datum/extension/network_device/mainframe/M in eligible_log_servers) var/list/logdata[0] - var/datum/computer_file/data/logfile/F = M.get_file("network_log") + var/datum/computer_file/data/logfile/F = M.get_file("network_log", OS_LOGS_DIR, TRUE) if(F) logdata["server"] = M.network_tag logdata["log"] = F.generate_file_data() @@ -63,7 +70,7 @@ logdata["ref"] = "\ref[M]" logs.Add(list(logdata)) data["logs"] = logs - + data["ids_status"] = network.intrusion_detection_enabled ? "ENABLED" : "DISABLED" data["ids_alarm"] = network.intrusion_detection_alarm data["banned_nids"] = jointext(network.banned_nids, "
    ") @@ -84,13 +91,17 @@ if(!user.skill_check(SKILL_COMPUTER, SKILL_BASIC)) return TOPIC_HANDLED - var/datum/computer_network/network = program.computer.get_network() + var/datum/computer_network/network = program?.computer?.get_network() if(href_list["purgelogs"]) var/datum/extension/network_device/mainframe/M = locate(href_list["purgelogs"]) if(!istype(M)) return TOPIC_HANDLED - M.delete_file("network_log") + var/datum/computer_file/log_file = M.get_file("network_log", OS_LOGS_DIR) + if(!log_file) + return TOPIC_HANDLED + M.delete_file(log_file) + return TOPIC_REFRESH if(href_list["updatemaxlogs"]) var/datum/extension/network_device/mainframe/M = locate(href_list["updatemaxlogs"]) @@ -98,7 +109,7 @@ return TOPIC_HANDLED var/logcount = input(user,"Enter amount of logs to keep on the disk ([MIN_NETWORK_LOGS]-[MAX_NETWORK_LOGS]):", M.max_log_count) as null|num if(logcount && CanUseTopic(user, state)) - logcount = Clamp(logcount, MIN_NETWORK_LOGS, MAX_NETWORK_LOGS) + logcount = clamp(logcount, MIN_NETWORK_LOGS, MAX_NETWORK_LOGS) M.max_log_count = logcount return TOPIC_REFRESH return TOPIC_HANDLED @@ -107,9 +118,9 @@ var/datum/extension/network_device/mainframe/M = locate(href_list["add_role"]) if(!istype(M)) return TOPIC_HANDLED - var/new_roles = GLOB.all_mainframe_roles - M.roles + var/new_roles = global.all_mainframe_roles - M.roles if(!length(new_roles)) - to_chat(usr, SPAN_WARNING("This server already has all possible roles enabled")) + to_chat(user, SPAN_WARNING("This server already has all possible roles enabled.")) return TOPIC_HANDLED var/role = input(user,"What role to enable on this server?") as null|anything in new_roles if(role && CanUseTopic(user, state)) @@ -122,7 +133,7 @@ if(!istype(M)) return TOPIC_HANDLED if(!length(M.roles)) - to_chat(usr, SPAN_WARNING("This server already no roles enabled")) + to_chat(user, SPAN_WARNING("This server has no enabled roles to remove.")) return TOPIC_HANDLED var/role = input(user,"What role to disable on this server?") as null|anything in M.roles if(role && CanUseTopic(user, state)) @@ -133,9 +144,9 @@ if(href_list["toggle_function"]) var/feature = text2num(href_list["toggle_function"]) if(network.network_features_enabled & feature) - network.network_features_enabled &= ~feature + network.disable_network_feature(feature) else - network.network_features_enabled |= feature + network.enable_network_feature(feature) return TOPIC_REFRESH if(href_list["ban_nid"]) @@ -147,12 +158,12 @@ if(href_list["unban_nid"]) var/nid = sanitize(input(user,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|text) if(nid && CanUseTopic(user, state)) - network.banned_nids -= nid + network.banned_nids -= nid return TOPIC_REFRESH if(href_list["get_nid"]) var/tag = sanitize(input(user,"Enter network tag of the device for address lookup:", "NID lookup") as null|text) - if(tag && CanUseTopic(user, state)) + if(tag && CanUseTopic(user, state)) var/datum/extension/network_device/D = network.get_device_by_tag(tag) if(!D) to_chat(user, SPAN_WARNING("Device '[tag]' not found in the network.")) diff --git a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm index 487964e70309..7c3a7e7faea0 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm @@ -1,14 +1,15 @@ /datum/computer_file/program/power_monitor filename = "powermonitor" filedesc = "Power Monitoring" - nanomodule_path = /datum/nano_module/power_monitor/ + nanomodule_path = /datum/nano_module/program/power_monitor/ program_icon_state = "power_monitor" program_key_state = "power_key" program_menu_icon = "battery-3" extended_desc = "This program connects to sensors to provide information about electrical systems" ui_header = "power_norm.gif" - required_access = access_engine + read_access = list(access_engine) requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL network_destination = "power monitoring system" size = 9 category = PROG_ENG @@ -16,7 +17,7 @@ /datum/computer_file/program/power_monitor/process_tick() ..() - var/datum/nano_module/power_monitor/NMA = NM + var/datum/nano_module/program/power_monitor/NMA = NM if(istype(NMA) && NMA.has_alarm()) if(!has_alert) program_icon_state = "power_monitor_warn" @@ -30,42 +31,42 @@ update_computer_icon() has_alert = 0 -/datum/nano_module/power_monitor +/datum/nano_module/program/power_monitor name = "Power monitor" var/list/grid_sensors var/active_sensor = null //name_tag of the currently selected sensor -/datum/nano_module/power_monitor/New() +/datum/nano_module/program/power_monitor/New() ..() refresh_sensors() -/datum/nano_module/power_monitor/Destroy() +/datum/nano_module/program/power_monitor/Destroy() for(var/grid_sensor in grid_sensors) remove_sensor(grid_sensor, FALSE) grid_sensors = null . = ..() // Checks whether there is an active alarm, if yes, returns 1, otherwise returns 0. -/datum/nano_module/power_monitor/proc/has_alarm() - for(var/obj/machinery/power/sensor/S in grid_sensors) - if(S.check_grid_warning()) - return 1 - return 0 +/datum/nano_module/program/power_monitor/proc/has_alarm() + for(var/obj/machinery/power_sensor/S in grid_sensors) + if(S.has_grid_warning()) + return TRUE + return FALSE // If PC is not null header template is loaded. Use PC.get_header_data() to get relevant nanoui data from it. All data entries begin with "PC_...." // In future it may be expanded to other modular computer devices. -/datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/list/sensors = list() // Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading. - var/obj/machinery/power/sensor/focus = null + var/obj/machinery/power_sensor/focus = null // Build list of data from sensor readings. - for(var/obj/machinery/power/sensor/S in grid_sensors) + for(var/obj/machinery/power_sensor/S in grid_sensors) sensors.Add(list(list( - "name" = S.id_tag, - "alarm" = S.check_grid_warning() + "name" = html_encode(S.id_tag), + "alarm" = S.has_grid_warning() ))) if(S.id_tag == active_sensor) focus = S @@ -84,32 +85,87 @@ ui.set_auto_update(1) // Refreshes list of active sensors kept on this computer. -/datum/nano_module/power_monitor/proc/refresh_sensors() +/datum/nano_module/program/power_monitor/proc/refresh_sensors() grid_sensors = list() - var/connected_z_levels = GetConnectedZlevels(get_host_z()) - for(var/obj/machinery/power/sensor/S in SSmachines.machinery) + var/connected_z_levels = SSmapping.get_connected_levels(get_host_z()) + for(var/obj/machinery/power_sensor/S in SSmachines.machinery) if(get_z(S) in connected_z_levels) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels. grid_sensors += S - GLOB.destroyed_event.register(S, src, /datum/nano_module/power_monitor/proc/remove_sensor) + events_repository.register(/decl/observ/destroyed, S, src, TYPE_PROC_REF(/datum/nano_module/program/power_monitor, remove_sensor)) -/datum/nano_module/power_monitor/proc/remove_sensor(var/removed_sensor, var/update_ui = TRUE) +/datum/nano_module/program/power_monitor/proc/remove_sensor(var/removed_sensor, var/update_ui = TRUE) if(active_sensor == removed_sensor) active_sensor = null if(update_ui) SSnano.update_uis(src) grid_sensors -= removed_sensor - GLOB.destroyed_event.unregister(removed_sensor, src, /datum/nano_module/power_monitor/proc/remove_sensor) + events_repository.unregister(/decl/observ/destroyed, removed_sensor, src, TYPE_PROC_REF(/datum/nano_module/program/power_monitor, remove_sensor)) + +/datum/nano_module/program/power_monitor/proc/is_sysadmin(var/mob/user) + if(program) + has_access(list(access_network), get_access(user)) + return FALSE // Allows us to process UI clicks, which are relayed in form of hrefs. -/datum/nano_module/power_monitor/Topic(href, href_list) +/datum/nano_module/program/power_monitor/Topic(href, href_list, state) if(..()) return 1 + + var/mob/user = usr + if( href_list["clear"] ) active_sensor = null . = 1 if( href_list["refresh"] ) refresh_sensors() . = 1 + + if(href_list["toggle_breaker"]) + var/obj/machinery/apc/A = locate(href_list["toggle_breaker"]) + + if(!CanInteract(user, state) || QDELETED(A)) + return 0 + + A.toggle_breaker() + + if(href_list["toggle_powerchannel_equip"] || href_list["toggle_powerchannel_light"] || href_list["toggle_powerchannel_enviro"]) //I'm sure there's a better way to do this. + var/obj/machinery/apc/A + var/powerchannel = 0 + var/power_setting + + if(href_list["toggle_powerchannel_equip"]) + A = locate(href_list["toggle_powerchannel_equip"]) + powerchannel = APC_POWERCHAN_EQUIPMENT + + if(href_list["toggle_powerchannel_light"]) + A = locate(href_list["toggle_powerchannel_light"]) + powerchannel = APC_POWERCHAN_LIGHTING + + if(href_list["toggle_powerchannel_enviro"]) + A = locate(href_list["toggle_powerchannel_enviro"]) + powerchannel = APC_POWERCHAN_ENVIRONMENT + + if(A.is_critical && !is_sysadmin(user)) + to_chat(user, SPAN_WARNING("Unsyndicated connections require system administrator access.")) + return 0 + + var/list/answers_list = list("ON", "OFF", "AUTO") + var/input = input("Select a power channel mode.", "Power Channel Mode") as null|anything in answers_list + + if(!CanInteract(user, state) || QDELETED(A)) + return 0 + + switch(input) + if("ON") + power_setting = POWERCHAN_ON + if("OFF") + power_setting = POWERCHAN_OFF + if("AUTO") + power_setting = POWERCHAN_ON_AUTO + + A.set_channel_state_manual(powerchannel, power_setting) + + else if( href_list["setsensor"] ) - active_sensor = href_list["setsensor"] + active_sensor = html_decode(href_list["setsensor"]) . = 1 diff --git a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm index 94b672107752..224d0cdccc59 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/rcon_console.dm @@ -6,9 +6,10 @@ program_key_state = "rd_key" program_menu_icon = "power" extended_desc = "This program allows remote control of power distribution systems. This program can not be run on tablet computers." - required_access = access_engine + read_access = list(access_engine) network_destination = "RCON remote control system" - requires_network_feature = NETWORK_SYSTEMCONTROL + requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL usage_flags = PROGRAM_LAPTOP | PROGRAM_CONSOLE size = 19 category = PROG_ENG @@ -22,7 +23,7 @@ var/hide_SMES_details = 0 var/hide_breakers = 0 -/datum/nano_module/program/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1, var/datum/topic_state/state = global.default_topic_state) FindDevices() // Update our devices list var/list/data = host.initial_data() @@ -39,8 +40,7 @@ "output_load" = round(SMES.output_used/1000, 0.1), "RCON_tag" = SMES.RCon_tag ))) - - data["smes_info"] = sortByKey(smeslist, "RCON_tag") + data["smes_info"] = smeslist // BREAKER DATA (simplified view) var/list/breakerlist[0] @@ -95,7 +95,7 @@ if(breaker.RCon_tag == href_list["toggle_breaker"]) toggle = breaker if(toggle) - if(toggle.update_locked) + if(toggle.lock_time > world.time) to_chat(usr, "The breaker box was recently toggled. Please wait before toggling it again.") else toggle.auto_toggle() @@ -122,10 +122,11 @@ // Parameters: None // Description: Refreshes local list of known devices. /datum/nano_module/program/rcon/proc/FindDevices() - known_SMESs = new /list() + known_SMESs = list() for(var/obj/machinery/power/smes/buildable/SMES in SSmachines.machinery) if(can_connect_to(SMES)) known_SMESs.Add(SMES) + known_SMESs = sortTim(known_SMESs, /proc/cmp_rcon_tag_asc) known_breakers = new /list() for(var/obj/machinery/power/breakerbox/breaker in SSmachines.machinery) @@ -137,9 +138,9 @@ if(!network) return FALSE - if(!ARE_Z_CONNECTED(network.get_router_z(), get_z(M))) + if(!LEVELS_ARE_Z_CONNECTED(network.get_router_z(), get_z(M))) return FALSE - + if(istype(M, /obj/machinery/power/smes)) var/obj/machinery/power/smes/buildable/SMES = M return SMES.RCon_tag && SMES.RCon_tag != "NO_TAG" && SMES.RCon diff --git a/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm index 90453401ecb0..6c7955d85e56 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/shields_monitor.dm @@ -8,26 +8,28 @@ extended_desc = "This program connects to shield generators and monitors their statuses." ui_header = "shield.gif" network_destination = "shields monitoring system" + requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL size = 10 category = PROG_ENG /datum/nano_module/program/shields_monitor name = "Shields monitor" - var/obj/machinery/power/shield_generator/active = null + var/obj/machinery/shield_generator/active = null /datum/nano_module/program/shields_monitor/Destroy() . = ..() deselect_shield() -/datum/nano_module/program/shields_monitor/proc/can_connect_to_shield(obj/machinery/power/shield_generator/S) +/datum/nano_module/program/shields_monitor/proc/can_connect_to_shield(obj/machinery/shield_generator/S) var/datum/computer_network/network = get_network() if(!network) return FALSE - return ARE_Z_CONNECTED(network.get_router_z(), get_z(S)) + return LEVELS_ARE_Z_CONNECTED(network.get_router_z(), get_z(S)) /datum/nano_module/program/shields_monitor/proc/get_shields() var/list/shields = list() - for(var/obj/machinery/power/shield_generator/S in SSmachines.machinery) + for(var/obj/machinery/shield_generator/S in SSmachines.machinery) if(!can_connect_to_shield(S)) continue shields.Add(S) @@ -36,7 +38,7 @@ deselect_shield() return shields -/datum/nano_module/program/shields_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/shields_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() if(!can_connect_to_shield(active)) deselect_shield() @@ -71,12 +73,12 @@ data["active"] = null var/list/shields = get_shields() var/list/shields_info = list() - for(var/obj/machinery/power/shield_generator/S in shields) + for(var/obj/machinery/shield_generator/S in shields) var/area/A = get_area(S) var/list/temp = list(list( "shield_status" = S.running, "shield_ref" = any2ref(S), - "area" = A.name)) + "area" = A.proper_name)) shields_info.Add(temp) data["shields"] = shields_info @@ -100,17 +102,17 @@ return 1 if( href_list["ref"] ) var/list/shields = get_shields() - var/obj/machinery/power/shield_generator/S = locate(href_list["ref"]) in shields + var/obj/machinery/shield_generator/S = locate(href_list["ref"]) in shields if(S) deselect_shield() - GLOB.destroyed_event.register(S, src, /datum/nano_module/program/shields_monitor/proc/deselect_shield) + events_repository.register(/decl/observ/destroyed, S, src, TYPE_PROC_REF(/datum/nano_module/program/shields_monitor, deselect_shield)) active = S return 1 /datum/nano_module/program/shields_monitor/proc/deselect_shield(var/source) if(!active) return - GLOB.destroyed_event.unregister(active, src) + events_repository.unregister(/decl/observ/destroyed, active, src) active = null if(source) // source is only set if called by the shield destroyed event, which is the only time we want to update the UI SSnano.update_uis(src) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/engineering/shutoff_valve.dm b/code/modules/modular_computers/file_system/programs/engineering/shutoff_valve.dm new file mode 100644 index 000000000000..8957c364b8df --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/engineering/shutoff_valve.dm @@ -0,0 +1,56 @@ +/datum/computer_file/program/shutoff_valve + filename = "shutoffcontrol" + filedesc = "Automatic Shutoff Valve Monitoring" + nanomodule_path = /datum/nano_module/program/shutoff_monitor + program_icon_state = "atmos_control" + program_key_state = "atmos_key" + program_menu_icon = "shuffle" + extended_desc = "This program allows remote control and monitoring of shutoff valves." + read_access = list(access_atmospherics) + requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL + network_destination = "atmospheric control system" + category = PROG_ENG + size = 10 + +/datum/nano_module/program/shutoff_monitor + name = "Shutoff valve monitor" + +/datum/nano_module/program/shutoff_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + var/list/list/data = host.initial_data() + var/list/z_valves = list() + var/list/zs = SSmapping.get_connected_levels(get_z(nano_host())) + + for(var/obj/machinery/atmospherics/valve/shutoff/S in shutoff_valves) + if(S.z in zs) + z_valves += S + + data["valves"] = list() + for(var/obj/machinery/atmospherics/valve/shutoff/S in z_valves) + data["valves"][++data["valves"].len] = list("name" = S.name, "enable" = S.close_on_leaks, "open" = S.open, "location" = get_area(S), "ref" = "\ref[S]") + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "shutoff_monitor.tmpl", "Shutoff Valve Monitoring", 800, 500, state = state) + if(host.update_layout()) // This is necessary to ensure the status bar remains updated along with rest of the UI. + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/program/shutoff_monitor/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["toggle_enable"]) + var/obj/machinery/atmospherics/valve/shutoff/S = locate(href_list["toggle_enable"]) + + // Invalid ref + if(!istype(S) || QDELETED(S)) + return 1 + + S.close_on_leaks = !S.close_on_leaks + + return + + diff --git a/code/modules/modular_computers/file_system/programs/file_browser.dm b/code/modules/modular_computers/file_system/programs/file_browser.dm new file mode 100644 index 000000000000..5c95c51818ae --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/file_browser.dm @@ -0,0 +1,286 @@ +// Generic interface for selecting/saving files with programs. The file manager program does not use this. +/datum/computer_file/program + var/datum/nano_module/program/file_browser/browser_module + +/datum/computer_file/program/on_shutdown(forced) + QDEL_NULL(browser_module) + . = ..() + +/datum/computer_file/program/proc/view_file_browser(mob/user, selecting_key, selecting_filetype, req_perm, browser_desc, datum/computer_file/saving_file) + if(!browser_module) + browser_module = new (src, new /datum/topic_manager/program(src), src) + browser_module.using_access = computer.get_access() + + browser_module.reset_browser(selecting_key, selecting_filetype, req_perm, browser_desc, saving_file) + browser_module.ui_interact(user) + return TRUE + +/datum/computer_file/program/proc/on_file_select(datum/file_storage/disk, datum/computer_file/directory/dir, datum/computer_file/selected, selecting_key) + browser_module.reset_browser() + SSnano.close_uis(browser_module) + SSnano.update_uis(src) + +/datum/nano_module/program/file_browser + var/disk_name = "local" + var/weakref/dir_ref + var/browser_error + + var/selecting_key // String identifying the action being performed, passed to proc/on_file_select on the program itself. + var/selecting_filetype // /datum/computer_file subtype being selected/created. + + var/weakref/selected_file // Reference to the file being selected. + + var/datum/computer_file/saving_file // The file, if any, that's being saved. For the sake of GC, this should be a completely new file + // not stored on any drive, and a reference to it should not be kept until after the browser finishes. + + var/req_perm + var/browser_desc // String describing the action being performed. + +/datum/nano_module/program/file_browser/Destroy() + QDEL_NULL(saving_file) + selected_file = null + dir_ref = null + . = ..() + +/datum/nano_module/program/file_browser/Topic(href, href_list) + . = ..() + if(.) + return + + var/mob/user = usr + var/list/accesses = get_access(user) + var/datum/extension/interactive/os/computer = program.computer + + if(href_list["BRS_back"]) + if(browser_error) + browser_error = null + return TOPIC_REFRESH + SSnano.close_uis(src) + reset_browser() + return TOPIC_REFRESH + + if(href_list["BRS_select_disk"]) + var/selected_disk = href_list["BRS_select_disk"] + if(selected_disk in computer.mounted_storage) + disk_name = selected_disk + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(!disk_name) + return TOPIC_REFRESH + + var/datum/file_storage/current_disk = computer.mounted_storage[disk_name] + if(!current_disk) + disk_name = null + return TOPIC_REFRESH + + var/errors = current_disk.check_errors() + if(errors) + browser_error = errors + return TOPIC_REFRESH + + var/datum/computer_file/directory/current_directory = dir_ref?.resolve() + if(current_directory && !(current_directory in current_disk.get_all_files())) + dir_ref = null + return TOPIC_REFRESH + + if(href_list["BRS_up_directory"]) + if(!current_directory) + disk_name = null + var/datum/computer_file/directory/parent_dir = current_directory?.get_directory() + dir_ref = weakref(parent_dir) + return TOPIC_REFRESH + + if(href_list["BRS_change_directory"]) + var/datum/computer_file/directory/dir = current_disk.get_file(href_list["BRS_change_directory"], current_directory) + if(!istype(dir)) + return TOPIC_HANDLED + if(!(dir.get_file_perms(accesses, user) & OS_READ_ACCESS)) + to_chat(user, SPAN_WARNING("You do not have permission to open this directory.")) + return TOPIC_HANDLED + + dir_ref = weakref(dir) + return TOPIC_REFRESH + + if(href_list["BRS_select_file"]) + var/datum/computer_file/F = current_disk.get_file(href_list["BRS_select_file"], current_directory) + if(!F) + return TOPIC_HANDLED + + if(saving_file) + saving_file.filename = F.filename + return TOPIC_REFRESH + + if(!istype(F, selecting_filetype)) + to_chat(user, SPAN_WARNING("This file is not the proper type.")) + return TOPIC_HANDLED + + if(!(F.get_file_perms(accesses, user) & req_perm)) + to_chat(user, SPAN_WARNING("You do not have permission to open this file.")) + return TOPIC_HANDLED + + selected_file = weakref(F) + return TOPIC_REFRESH + + if(href_list["BRS_rename_file"]) + if(!saving_file) + return TOPIC_HANDLED + var/newname = sanitize_for_file(input(usr, "Enter file name:", "Save file", saving_file.filename)) + if(!length(newname)) + to_chat(user, SPAN_WARNING("Invalid file name!")) + return TOPIC_HANDLED + + saving_file.filename = newname + return TOPIC_REFRESH + + if(href_list["BRS_save_file"]) + if(!saving_file) + return TOPIC_HANDLED + + var/success = current_disk.store_file(saving_file, current_directory, accesses = accesses, user = user) + if(success != OS_FILE_SUCCESS) + if(success == OS_FILE_NO_WRITE) + to_chat(user, SPAN_WARNING("You do not have permission to write/overwrite the file in this directory.")) + return TOPIC_HANDLED + if(success == OS_HARDDRIVE_SPACE) + to_chat(user, SPAN_WARNING("Insufficient harddrive space.")) + + // Since we know the directory exists, any other error indicates something is wrong with the drive or network. + to_chat(user, SPAN_WARNING("I/O ERROR: Drive is non-functional or could not be accessed on the network.")) + return TOPIC_REFRESH + + var/datum/computer_file/saved_file = saving_file + saving_file = null // We null this out so it doesn't get QDEL when the nanomodule is reset, but any other action that resets the browser does. + to_chat(user, SPAN_NOTICE("Created file [saved_file.filename].[saved_file.filetype].")) + program.on_file_select(current_disk, current_directory, saved_file, selecting_key) + return TOPIC_HANDLED + + if(href_list["BRS_finalize_select"]) + if(saving_file || !selected_file) + return TOPIC_HANDLED + + var/datum/computer_file/F = selected_file.resolve() + if(!istype(F)) + selected_file = null + return TOPIC_REFRESH + + if(!istype(F, selecting_filetype)) + to_chat(user, SPAN_WARNING("This file is not the proper type.")) + selected_file = null + return TOPIC_HANDLED + + if(!(F.get_file_perms(accesses, user) & req_perm)) + to_chat(user, SPAN_WARNING("You do not have permission to open this file.")) + selected_file = null + return TOPIC_HANDLED + + program.on_file_select(current_disk, current_directory, F, selecting_key) + SSnano.close_uis(src) + reset_browser() + return TOPIC_REFRESH + + if(href_list["BRS_create_dir"]) + if(!saving_file) + return TOPIC_HANDLED + var/dirname = sanitize_for_file(input(usr, "Enter directory name or leave blank to cancel:", "Directory creation")) + if(!length(dirname)) + return TOPIC_HANDLED + + var/datum/computer_file/directory/created_dir = current_disk.create_directory(dirname, current_directory, accesses, user) + if(!istype(created_dir)) + if(created_dir == OS_HARDDRIVE_ERROR || created_dir == OS_NETWORK_ERROR) + to_chat(user, SPAN_WARNING("I/O ERROR: Drive is non-functional or could not be accessed on the network.")) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("You lack permission to create a directory in this location.")) + return TOPIC_HANDLED + + to_chat(user, SPAN_NOTICE("Created directory [created_dir.filename]")) + return TOPIC_HANDLED + +/datum/nano_module/program/file_browser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + var/list/data = program.get_header_data(TRUE) + + var/datum/extension/interactive/os/computer = program.computer + + var/datum/file_storage/current_disk = disk_name ? computer.mounted_storage[disk_name] : null + var/datum/computer_file/current_directory = dir_ref?.resolve() + + var/list/accesses = get_access(user) + if(browser_error) + data["error"] = browser_error + else + data["filetypes"] = get_readable_filetypes() + if(saving_file) + data["saving_file"] = TRUE + data["curr_file_name"] = saving_file.filename + data["curr_file_type"] = saving_file.filetype + else + data["saving_file"] = FALSE + var/datum/computer_file/selected = selected_file?.resolve() + if(istype(selected)) + data["curr_file_name"] = selected.filename + data["curr_file_type"] = selected.filetype + if(current_disk) + // Safety check. + if(current_directory && !(current_directory in current_disk.get_all_files())) + dir_ref = null + + data["current_disk"] = current_disk.get_dir_path(current_directory, TRUE) + + var/list/files[0] + for(var/datum/computer_file/F in current_disk.get_dir_files(current_directory)) + files.Add(list(list( + "name" = F.filename, + "type" = F.filetype, + "dir" = istype(F, /datum/computer_file/directory), + "size" = F.size, + "selectable" = istype(F, selecting_filetype) + ))) + data["files"] = files + else // No disk selected. + dir_ref = null + disk_name = null + var/list/avail_disks[0] + + for(var/root_name in computer.mounted_storage) + var/datum/file_storage/avail_disk = computer.mounted_storage[root_name] + if(!avail_disk.hidden && avail_disk.check_access(accesses)) + avail_disks.Add(list(list( + "name" = root_name, + "desc" = avail_disk.desc + ))) + + data["avail_disks"] = avail_disks + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "file_browser.tmpl", browser_desc, 500, 600, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.set_auto_update(1) + ui.open() + + return 1 + +/datum/nano_module/program/file_browser/proc/reset_browser(new_key, new_filetype, new_req_perm, new_desc, datum/computer_file/new_saving_file) + disk_name = "local" + dir_ref = null + browser_error = null + selected_file = null + + selecting_key = new_key + selecting_filetype = new_filetype + req_perm = new_req_perm + browser_desc = new_desc + + if(saving_file) + QDEL_NULL(saving_file) + saving_file = new_saving_file + +/datum/nano_module/program/file_browser/proc/get_readable_filetypes() + var/list/filetype_strings = list() + for(var/T in typesof(selecting_filetype)) + var/datum/computer_file/option = T + filetype_strings += ".[initial(option.filetype)]" + return english_list(filetype_strings) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/camera.dm b/code/modules/modular_computers/file_system/programs/generic/camera.dm index e1fd4946b812..b38d86878e23 100644 --- a/code/modules/modular_computers/file_system/programs/generic/camera.dm +++ b/code/modules/modular_computers/file_system/programs/generic/camera.dm @@ -1,27 +1,3 @@ -// Returns which access is relevant to passed network. Used by the program. -/proc/get_camera_access(var/network) - if(!network) - return 0 - . = GLOB.using_map.get_network_access(network) - if(.) - return - - switch(network) - if(NETWORK_ENGINEERING, NETWORK_ALARM_ATMOS, NETWORK_ALARM_CAMERA, NETWORK_ALARM_FIRE, NETWORK_ALARM_POWER) - return access_engine - if(NETWORK_CRESCENT, NETWORK_ERT) - return access_cent_specops - if(NETWORK_MEDICAL) - return access_medical - if(NETWORK_MINE) - return access_mailsorting // Cargo office - all cargo staff should have access here. - if(NETWORK_RESEARCH) - return access_research - if(NETWORK_THUNDER) - return 0 - - return access_security // Default for all other networks - /datum/computer_file/program/camera_monitor filename = "cammon" filedesc = "Camera Monitoring" @@ -29,39 +5,68 @@ program_icon_state = "cameras" program_key_state = "generic_key" program_menu_icon = "search" - extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements." + extended_desc = "This program allows remote access to the camera system. Some cameras may have additional access requirements." size = 12 available_on_network = 1 + requires_network = 1 + requires_network_feature = NET_FEATURE_SECURITY category = PROG_MONITOR /datum/nano_module/program/camera_monitor name = "Camera Monitoring program" - var/obj/machinery/camera/current_camera = null - var/current_network = null - -/datum/nano_module/program/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + var/weakref/current_camera = null + var/current_channel = null + var/list/viewers = list() + var/bypass_access = FALSE + +/datum/nano_module/program/camera_monitor/proc/get_forbidden_channels() + var/static/list/forbidden_channels = list( + (CAMERA_CHANNEL_ERT), + (CAMERA_CHANNEL_MERCENARY) + ) + return forbidden_channels + +/datum/nano_module/program/camera_monitor/mercenary + name = "Mercenary Camera Monitoring program" + +/datum/nano_module/program/camera_monitor/mercenary/get_forbidden_channels() + var/static/list/forbidden_channels = list( + (CAMERA_CHANNEL_ERT) + ) + return forbidden_channels + +/datum/nano_module/program/camera_monitor/Destroy() + unlook_all() + . = ..() + +/datum/nano_module/program/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() - data["current_camera"] = current_camera ? current_camera.nano_structure() : null - data["current_network"] = current_network - - var/list/all_networks[0] - for(var/network in GLOB.using_map.station_networks) - all_networks.Add(list(list( - "tag" = network, - "has_access" = can_access_network(user, get_camera_access(network)) - ))) + var/datum/extension/network_device/camera/camera_device = current_camera?.resolve() + data["current_camera"] = camera_device ? camera_device.nano_structure() : null + data["current_channel"] = current_channel - all_networks = modify_networks_list(all_networks) + var/list/all_channels[0] + var/list/cameras_by_channel = get_cameras_by_channel() + for(var/channel in cameras_by_channel) + all_channels += channel + all_channels -= get_forbidden_channels() - data["networks"] = all_networks + data["channels"] = all_channels - if(current_network) - data["cameras"] = camera_repository.cameras_in_network(current_network) + if(current_channel) + var/list/channel_cameras[0] + for(var/datum/extension/network_device/camera/C in cameras_by_channel[current_channel]) + channel_cameras.Add(list(list( + "name" = C.display_name, + "device" = "\ref[C]", + "deactivated" = !can_connect_to_camera(C) + ))) + data["cameras"] = channel_cameras ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Monitoring", 900, 800, state = state) + ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Monitoring", 900, 800, src, state = state) // ui.auto_update_layout = 1 // Disabled as with suit sensors monitor - breaks the UI map. Re-enable once it's fixed somehow. ui.add_template("mapContent", "sec_camera_map_content.tmpl") @@ -70,130 +75,159 @@ ui.open() user.machine = nano_host() - if(can_connect_to_camera(current_camera)) - user.reset_view(current_camera) - -// Intended to be overriden by subtypes to manually add non-station networks to the list. -/datum/nano_module/program/camera_monitor/proc/modify_networks_list(var/list/networks) - return networks - -/datum/nano_module/program/camera_monitor/proc/can_access_network(var/mob/user, var/network_access) - // No access passed, or 0 which is considered no access requirement. Allow it. - if(!network_access) - return 1 - - return check_access(user, access_security) || check_access(user, network_access) /datum/nano_module/program/camera_monitor/Topic(href, href_list) if(..()) - return 1 - + return TOPIC_HANDLED + if(href_list["close"]) + unlook(usr) + return TOPIC_NOACTION if(href_list["switch_camera"]) - var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras - if(!C) - return - if(!(current_network in C.network)) - return - if(!can_connect_to_camera(C)) - to_chat(usr, "Unable to establish a connection.") - return - - switch_to_camera(usr, C) - return 1 - - else if(href_list["switch_network"]) - // Either security access, or access to the specific camera network's department is required in order to access the network. - if(can_access_network(usr, get_camera_access(href_list["switch_network"]))) - current_network = href_list["switch_network"] + var/datum/extension/network_device/camera/camera_device = locate(href_list["switch_camera"]) + if(!camera_device || !can_connect_to_camera(camera_device)) + return TOPIC_NOACTION + var/atom/movable/holder = camera_device.holder + // Only check for access when switching the camera - leave the program open at your own peril. + if(!holder.allowed(usr) && !bypass_access) + to_chat(usr, SPAN_WARNING("Access denied!")) + return TOPIC_NOACTION + switch_to_camera(usr, camera_device) + return TOPIC_REFRESH + + if(href_list["view_camera"]) + if(usr in viewers) + unlook(usr) else - to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.") - return 1 + look(usr) + return TOPIC_REFRESH + + else if(href_list["switch_channel"]) + if((href_list["switch_channel"]) in get_cameras_by_channel()) + current_channel = href_list["switch_channel"] + return TOPIC_REFRESH else if(href_list["reset"]) + unlook_all() reset_current() - usr.reset_view(current_camera) - return 1 + return TOPIC_REFRESH -/datum/nano_module/program/camera_monitor/proc/can_connect_to_camera(var/obj/machinery/camera/C) +/datum/nano_module/program/camera_monitor/proc/look(var/mob/user) + if(current_camera) + var/datum/extension/network_device/camera/camera_device = current_camera.resolve() + if(can_connect_to_camera(camera_device)) + user.reset_view(camera_device.holder) + viewers |= user + apply_visual(user) + +/datum/nano_module/program/camera_monitor/proc/unlook(var/mob/user, var/reset_view = TRUE) + if(user in viewers) + if(reset_view) + user.reset_view() + viewers -= user + remove_visual(user) + +/datum/nano_module/program/camera_monitor/proc/unlook_all() + for(var/mob/looker in viewers) + looker.reset_view() + viewers -= looker + remove_visual(looker) + +/datum/nano_module/program/camera_monitor/proc/can_connect_to_camera(var/datum/extension/network_device/camera/camera_device) + if(!camera_device) + return FALSE + if(!camera_device.is_functional()) + return FALSE + // Even if the camera itself does not need to be connected to the network, the program does in order to receive the signal. var/datum/computer_network/network = get_network() if(!network) return FALSE - if(get_z(C) in GLOB.using_map.admin_levels) // Thunderdome cameras etc - return TRUE - return ARE_Z_CONNECTED(get_z(C), network.get_router_z()) - -/datum/nano_module/program/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C) + if(camera_device.requires_connection) + if(camera_device.network_id != network.network_id) + return FALSE + if(!camera_device.check_connection()) + return FALSE + return TRUE + +/datum/nano_module/program/camera_monitor/proc/switch_to_camera(var/mob/user, var/datum/extension/network_device/camera/camera_device) //don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras. - if(isAI(user)) + var/atom/C = camera_device.holder + if(!C) + return FALSE + if(isAI(user) && camera_device.cameranet_enabled) var/mob/living/silicon/ai/A = user // Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise. if(!A.is_in_chassis()) - return 0 + return FALSE A.eyeobj.setLoc(get_turf(C)) A.client.eye = A.eyeobj - return 1 + return TRUE - set_current(C) - return 1 + set_current(camera_device) -/datum/nano_module/program/camera_monitor/proc/set_current(var/obj/machinery/camera/C) - if(current_camera == C) - return + // Make sure everyone in the viewers list is looking at the same camera. + for(var/mob/viewer in viewers) + look(viewer) + if(!(user in viewers)) + look(user) + return TRUE +/datum/nano_module/program/camera_monitor/proc/set_current(var/datum/extension/network_device/camera/camera_device) if(current_camera) + if(current_camera.resolve() == camera_device) + return reset_current() - current_camera = C - if(current_camera) - var/mob/living/L = current_camera.loc - if(istype(L)) - L.tracking_initiated() + current_camera = weakref(camera_device) + var/mob/living/L = camera_device.holder + if(istype(L)) + L.tracking_initiated() /datum/nano_module/program/camera_monitor/proc/reset_current() if(current_camera) - var/mob/living/L = current_camera.loc + var/datum/extension/network_device/camera/camera_device = current_camera.resolve() + var/mob/living/L = camera_device.holder if(istype(L)) L.tracking_cancelled() current_camera = null +/datum/nano_module/program/camera_monitor/proc/get_cameras_by_channel() + var/list/cameras_by_channel = list() + var/datum/computer_network/network = get_network() + if(network) + cameras_by_channel = network.cameras_by_channel.Copy() + // Cameras broadcasting on CAMERA_CHANNEL_TELEVISION are able to be received by all camera monitoring programs. + var/list/television_channels = camera_repository.devices_in_channel(CAMERA_CHANNEL_TELEVISION) + if(length(television_channels)) + if(!cameras_by_channel[CAMERA_CHANNEL_TELEVISION]) + cameras_by_channel[CAMERA_CHANNEL_TELEVISION] = list() + cameras_by_channel[CAMERA_CHANNEL_TELEVISION] |= television_channels + return cameras_by_channel + /datum/nano_module/program/camera_monitor/check_eye(var/mob/user) if(!current_camera) - return 0 - if(!can_connect_to_camera(current_camera)) - return 0 - var/viewflag = current_camera.check_eye(user) - if ( viewflag < 0 ) //camera doesn't work + unlook(user, FALSE) + return -1 + if(CanUseTopic(user, global.default_topic_state) != STATUS_INTERACTIVE) + unlook(user, FALSE) + return -1 + var/datum/extension/network_device/camera/camera_device = current_camera.resolve() + if(!can_connect_to_camera(camera_device)) + unlook(user, FALSE) + reset_current() + return -1 + var/viewflag = camera_device.check_eye(user) + if(viewflag < 0) // Camera isn't operational. + unlook(user, FALSE) reset_current() return viewflag - -// ERT Variant of the program -/datum/computer_file/program/camera_monitor/ert - filename = "ntcammon" - filedesc = "Advanced Camera Monitoring" - extended_desc = "This program allows remote access to the camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys." - size = 14 - nanomodule_path = /datum/nano_module/program/camera_monitor/ert - available_on_network = 0 - -/datum/nano_module/program/camera_monitor/ert - name = "Advanced Camera Monitoring Program" - available_to_ai = FALSE - -// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it. -/datum/nano_module/program/camera_monitor/ert/modify_networks_list(var/list/networks) - ..() - networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1))) - networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1))) - return networks - /datum/nano_module/program/camera_monitor/apply_visual(mob/M) if(current_camera) - current_camera.apply_visual(M) - else - remove_visual(M) + var/datum/camera_device = current_camera.resolve() + camera_device.apply_visual(M) /datum/nano_module/program/camera_monitor/remove_visual(mob/M) if(current_camera) - current_camera.remove_visual(M) + var/datum/camera_device = current_camera.resolve() + camera_device.remove_visual(M) diff --git a/code/modules/modular_computers/file_system/programs/generic/configurator.dm b/code/modules/modular_computers/file_system/programs/generic/configurator.dm index 4cd048701c37..b280adf55f20 100644 --- a/code/modules/modular_computers/file_system/programs/generic/configurator.dm +++ b/code/modules/modular_computers/file_system/programs/generic/configurator.dm @@ -18,9 +18,11 @@ category = PROG_UTIL /datum/nano_module/program/computer_configurator - name = "NTOS Computer Configuration Tool" + name = "Computer Configuration Tool" + +/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + name = "[program.computer.os_name] [initial(name)]" // i.e. GOOSE Computer Configuration Tool -/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) var/list/data = list() data = program.get_header_data() @@ -31,8 +33,9 @@ var/obj/item/stock_parts/computer/battery_module/battery_module = program.computer.get_component(PART_BATTERY) data["battery_exists"] = !!battery_module if(battery_module) - data["battery_rating"] = battery_module.battery.maxcharge - data["battery_percent"] = round(battery_module.battery.percent()) + var/obj/item/cell/battery = battery_module.get_cell() + data["battery_rating"] = battery?.maxcharge || 0 + data["battery_percent"] = battery ? round(battery.percent()) : 0 var/obj/item/stock_parts/computer/network_card/network_card = program.computer.get_component(PART_NETWORK) data["nic_exists"] = !!network_card @@ -62,9 +65,11 @@ data["receives_updates"] = program.computer.receives_updates + data["os_full_name"] = program.computer.os_full_name + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700, state = state) + ui = new(user, src, ui_key, "laptop_configuration.tmpl", "[program.computer.os_name] Configuration Utility", 575, 700, state = state) ui.auto_update_layout = 1 ui.set_initial_data(data) ui.open() diff --git a/code/modules/modular_computers/file_system/programs/generic/crew_manifest.dm b/code/modules/modular_computers/file_system/programs/generic/crew_manifest.dm index 20b904bd0e09..c79988615d6d 100644 --- a/code/modules/modular_computers/file_system/programs/generic/crew_manifest.dm +++ b/code/modules/modular_computers/file_system/programs/generic/crew_manifest.dm @@ -6,6 +6,8 @@ program_key_state = "generic_key" size = 4 available_on_network = 1 + requires_network = 1 + requires_network_feature = NET_FEATURE_RECORDS nanomodule_path = /datum/nano_module/program/crew_manifest usage_flags = PROGRAM_ALL category = PROG_OFFICE @@ -13,10 +15,10 @@ /datum/nano_module/program/crew_manifest name = "Crew Manifest" -/datum/nano_module/program/crew_manifest/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) +/datum/nano_module/program/crew_manifest/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() - var/datum/computer_network/network = program.computer.get_network() + var/datum/computer_network/network = program?.computer?.get_network() if(!network) return data["crew_manifest"] = html_crew_manifest(TRUE, records = network.get_crew_records()) diff --git a/code/modules/modular_computers/file_system/programs/generic/deck_management.dm b/code/modules/modular_computers/file_system/programs/generic/deck_management.dm index 5a5413a0a22f..5e108c7e221b 100644 --- a/code/modules/modular_computers/file_system/programs/generic/deck_management.dm +++ b/code/modules/modular_computers/file_system/programs/generic/deck_management.dm @@ -7,6 +7,7 @@ filename = "deckmngr" filedesc = "Deck Management" nanomodule_path = /datum/nano_module/deck_management + read_access = list(list(access_mining, access_cargo, access_bridge)) program_icon_state = "request" program_key_state = "rd_key" program_menu_icon = "clock" @@ -14,6 +15,7 @@ size = 18 available_on_network = 1 requires_network = 1 + requires_network_feature = NET_FEATURE_DECK category = PROG_SUPPLY /datum/nano_module/deck_management @@ -25,8 +27,6 @@ var/datum/computer_file/report/selected_report //A report being viewed/edited. var/list/report_prototypes = list() //Stores report prototypes to use for UI purposes. var/datum/shuttle/prototype_shuttle //The shuttle for which the prototypes were built (to avoid excessive prototype rebuilding) - //The default access needed to properly use. Should be set in map files. - var/default_access = list(access_cargo, access_bridge) //The format is (needs one of list(these access constants or lists of access constants)) /datum/nano_module/deck_management/New() ..() @@ -40,12 +40,11 @@ my_log.unregister(src) . = ..() -/datum/nano_module/deck_management/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) +/datum/nano_module/deck_management/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() var/logs = SSshuttle.shuttle_logs data["prog_state"] = prog_state - data["default_access"] = get_default_access(user) switch(prog_state) if(DECK_HOME) @@ -105,7 +104,7 @@ L["name"] = report.display_name() L["index"] = i L["exists"] = locate(report) in selected_mission.other_reports - L["access_edit"] = report.verify_access_edit(get_access(user)) + L["access_edit"] = report.get_file_perms(get_access(user), user) & OS_WRITE_ACCESS other_reports += list(L) data["other_reports"] = other_reports @@ -115,7 +114,7 @@ if(!istype(selected_report)) prog_state = DECK_MISSION_DETAILS return - data["report_data"] = selected_report.generate_nano_data(get_access(user)) + data["report_data"] = selected_report.generate_nano_data(get_access(user), user) data["shuttle_name"] = selected_shuttle.name data["mission_data"] = generate_mission_data(selected_mission) data["view_only"] = can_view_only @@ -171,11 +170,6 @@ mission_data["queued"] = 1 return mission_data -/datum/nano_module/deck_management/proc/get_default_access(mob/user) - for(var/access_pattern in default_access) - if(check_access(user, access_pattern)) - return 1 - /datum/nano_module/deck_management/proc/get_shuttle_access(mob/user, datum/shuttle/shuttle) return shuttle.logging_access ? (check_access(user, shuttle.logging_access) || check_access(user, access_bridge)) : 0 @@ -192,12 +186,22 @@ prototype_shuttle = selected_shuttle report_prototypes = list() for(var/report_type in subtypesof(/datum/computer_file/report/recipient/shuttle)) - var/datum/computer_file/report/recipient/shuttle/new_report = new report_type - if(new_report.access_shuttle) - new_report.set_access(null, selected_shuttle.logging_access, override = 0) - report_prototypes += new_report + report_prototypes += create_report(report_type, selected_shuttle) return 1 +/datum/nano_module/deck_management/proc/create_report(report_type, datum/shuttle/given_shuttle) + var/datum/computer_file/report/recipient/shuttle/new_report = new report_type + if(new_report.access_shuttle && given_shuttle.logging_access) + var/old_access = new_report.write_access?.Copy() + var/new_access = list() + for(var/group in old_access) // We add logging_access as an OR option to every AND requirement + var/new_group = list() + new_group += group // this listifies it if it was not already a list + new_group |= given_shuttle.logging_access + new_access += list(new_group) + new_report.set_access(null, new_access, TRUE) + return new_report + /datum/nano_module/deck_management/proc/set_mission(mission_ID) var/datum/shuttle_log/my_log = SSshuttle.shuttle_logs[selected_shuttle] var/datum/shuttle_mission/mission = my_log.mission_from_ID(mission_ID) @@ -211,8 +215,6 @@ if(..()) return 1 - if(!get_default_access(user)) - return 1 //No program access if you don't have the right access. if(text2num(href_list["warning"])) //Gives the user a chance to avoid losing unsaved reports. if(alert(user, "Are you sure you want to do this? Data may be lost.",, "Yes.", "No.") == "No.") return 1 //If yes, proceed to the actual action instead. @@ -263,10 +265,9 @@ if(href_list["flight_plan"]) prog_state = DECK_REPORT_EDIT if(selected_mission.flight_plan) - selected_report = selected_mission.flight_plan.clone()//We always make a new one to buffer changes until submitted. + selected_report = selected_mission.flight_plan.Clone()//We always make a new one to buffer changes until submitted. else - selected_report = new /datum/computer_file/report/flight_plan - selected_report.set_access(null, selected_shuttle.logging_access, override = 0) + selected_report = create_report(/datum/computer_file/report/flight_plan, selected_shuttle) else if(selected_mission.stage in list(SHUTTLE_MISSION_PLANNED, SHUTTLE_MISSION_QUEUED)) return 1 //Hold your horses until the mission is started on these reports. @@ -277,9 +278,9 @@ prog_state = DECK_REPORT_EDIT var/datum/computer_file/report/old_report = locate(prototype.type) in selected_mission.other_reports if(old_report) - selected_report = old_report.clone() + selected_report = old_report.Clone() else - var/datum/computer_file/report/recipient/shuttle/new_report = prototype.clone() + var/datum/computer_file/report/recipient/shuttle/new_report = prototype.Clone() new_report.shuttle.set_value(selected_shuttle.name) new_report.mission.set_value(selected_mission.name) selected_report = new_report @@ -296,14 +297,14 @@ return 1 var/field_ID = text2num(href_list["ID"]) var/datum/report_field/field = selected_report.field_from_ID(field_ID) - if(!field || !field.verify_access_edit(get_access(user))) + if(!field || !(field.get_perms(get_access(user), user) & OS_WRITE_ACCESS)) return 1 field.ask_value(user) //Handles the remaining IO. return 1 if(href_list["submit"]) if(!ensure_valid_mission() || !selected_report) return 1 - if(!selected_report.verify_access_edit(get_access(user))) + if(!(selected_report.get_file_perms(get_access(user), user) & OS_WRITE_ACCESS)) return 1 var/datum/shuttle_log/my_log = SSshuttle.shuttle_logs[selected_shuttle] if(my_log.submit_report(selected_mission, selected_report, user)) @@ -339,7 +340,7 @@ return 1 var/datum/shuttle_log/my_log = SSshuttle.shuttle_logs[selected_shuttle] if(world.time - my_log.last_spam >= 1 MINUTE) //Slow down with that spam button - GLOB.global_announcer.autosay("The [selected_shuttle.name] is planning to depart on a mission promptly at [time]. The following crew members are to make their way to \the [place] immediately: [crew].", "Hangar Announcement System") + do_telecomms_announcement(user, "The [selected_shuttle.name] is planning to depart on a mission promptly at [time]. The following crew members are to make their way to \the [place] immediately: [crew].", "Hangar Announcement System") my_log.last_spam = world.time else to_chat(user, "It's too soon after the previous announcement!") @@ -354,7 +355,7 @@ var/datum/report_field/people/manifest = selected_mission.flight_plan.manifest if(!manifest.get_value()) return 1 - manifest.send_email(user) + manifest.send_email(user, get_access(user)) return 1 #undef DECK_HOME diff --git a/code/modules/modular_computers/file_system/programs/generic/docks.dm b/code/modules/modular_computers/file_system/programs/generic/docks.dm index ad6fe91d40f5..1fe5cfb5a2e5 100644 --- a/code/modules/modular_computers/file_system/programs/generic/docks.dm +++ b/code/modules/modular_computers/file_system/programs/generic/docks.dm @@ -1,35 +1,38 @@ /datum/computer_file/program/docking filename = "docking" filedesc = "Docking Control" - required_access = access_bridge - nanomodule_path = /datum/nano_module/docking + read_access = list(access_bridge) + nanomodule_path = /datum/nano_module/program/docking program_icon_state = "supply" program_key_state = "rd_key" program_menu_icon = "triangle-2-e-w" - extended_desc = "A management tool that lets you see the status of the docking ports." + extended_desc = "A management tool that lets you see the status of the docking ports and beacons." size = 10 usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP available_on_network = 1 requires_network = 1 + requires_network_feature = NET_FEATURE_DECK category = PROG_SUPPLY /datum/computer_file/program/docking/on_startup() . = ..() if(NM) - var/datum/nano_module/docking/NMD = NM + var/datum/nano_module/program/docking/NMD = NM NMD.refresh_docks() -/datum/nano_module/docking +/datum/nano_module/program/docking name = "Docking Control program" var/list/docking_controllers = list() //list of tags + var/list/docking_beacons = list() //list of magnetic docking beacon tags -/datum/nano_module/docking/New(var/datum/host, var/topic_manager) +/datum/nano_module/program/docking/New(var/datum/host, var/topic_manager) ..() refresh_docks() -/datum/nano_module/docking/proc/refresh_docks() +/datum/nano_module/program/docking/proc/refresh_docks() docking_controllers.Cut() - var/list/zlevels = GetConnectedZlevels(get_host_z()) + docking_beacons.Cut() + var/list/zlevels = SSmapping.get_connected_levels(get_host_z()) for(var/obj/machinery/embedded_controller/radio/airlock/docking_port/D in SSmachines.machinery) if(D.z in zlevels) var/shuttleside = 0 @@ -43,23 +46,46 @@ continue docking_controllers += D.program.id_tag -/datum/nano_module/docking/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + // Add magnetic docking beacons. + var/datum/computer_network/network = get_network() + if(network) + docking_beacons |= network.get_tags_by_type(/obj/machinery/docking_beacon) + +/datum/nano_module/program/docking/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() var/list/docks = list() + var/list/beacons = list() + var/datum/computer_network/network = get_network() + for(var/docktag in docking_controllers) var/datum/computer/file/embedded_program/docking/P = SSshuttle.docking_registry[docktag] if(P) var/docking_attempt = P.tag_target && !P.dock_state var/docked = P.tag_target && (P.dock_state == STATE_DOCKED) docks.Add(list(list( - "tag"=P.id_tag, + "tag" = P.id_tag, "location" = P.get_name(), "status" = capitalize(P.get_docking_status()), "docking_attempt" = docking_attempt, "docked" = docked, "codes" = P.docking_codes ? P.docking_codes : "Unset" ))) + + for(var/beacontag in docking_beacons) + var/datum/extension/network_device/D = network.get_device_by_tag(beacontag) + var/obj/machinery/docking_beacon/beacon = D.holder + if(istype(beacon)) + beacons.Add(list(list( + "size" = "[beacon.docking_width], [beacon.docking_height]", + "name" = beacon.display_name, + "locked" = beacon.locked, + "network_tag" = D.network_tag, + "code_docking" = beacon.docking_by_codes, + ))) + else + docking_beacons -= beacontag data["docks"] = docks + data["docking_beacons"] = beacons ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "docking.tmpl", name, 600, 450, state = state) @@ -67,25 +93,37 @@ ui.set_initial_data(data) ui.open() -/datum/nano_module/docking/Topic(href, href_list, state) +/datum/nano_module/program/docking/Topic(href, href_list, state) if(..()) - return 1 - if(istext(href_list["edit_code"])) - var/datum/computer/file/embedded_program/docking/P = SSshuttle.docking_registry[href_list["edit_code"]] + return TOPIC_HANDLED + + if(istext(href_list["edit_docking_codes"])) + var/datum/computer/file/embedded_program/docking/P = SSshuttle.docking_registry[href_list["edit_docking_codes"]] if(P) var/newcode = input("Input new docking codes", "Docking codes", P.docking_codes) as text|null if(!CanInteract(usr,state)) return - if (newcode) + if(newcode) P.docking_codes = uppertext(newcode) - return 1 + return TOPIC_HANDLED + if(istext(href_list["dock"])) var/datum/computer/file/embedded_program/docking/P = SSshuttle.docking_registry[href_list["dock"]] if(P) P.receive_user_command("dock") - return 1 + return TOPIC_HANDLED + if(istext(href_list["undock"])) var/datum/computer/file/embedded_program/docking/P = SSshuttle.docking_registry[href_list["undock"]] if(P) P.receive_user_command("undock") - return 1 \ No newline at end of file + return TOPIC_HANDLED + + if(istext(href_list["beacon"])) + var/datum/computer_network/network = get_network() + var/datum/extension/network_device/device = network.get_device_by_tag(href_list["beacon"]) + var/obj/machinery/docking_beacon/beacon = device.holder + if(istype(beacon)) + var/datum/topic_state/remote/R = new(src, beacon) + beacon.ui_interact(usr, state = R) + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/email_client.dm b/code/modules/modular_computers/file_system/programs/generic/email_client.dm index e5a14c1528ae..9bfa457e8487 100644 --- a/code/modules/modular_computers/file_system/programs/generic/email_client.dm +++ b/code/modules/modular_computers/file_system/programs/generic/email_client.dm @@ -7,39 +7,27 @@ program_menu_icon = "mail-closed" size = 7 available_on_network = 1 - var/stored_login = "" - var/stored_password = "" usage_flags = PROGRAM_ALL category = PROG_OFFICE nanomodule_path = /datum/nano_module/program/email_client -// Persistency. Unless you log out, or unless your password changes, this will pre-fill the login data when restarting the program -/datum/computer_file/program/email_client/on_shutdown() - if(NM) - var/datum/nano_module/program/email_client/NME = NM - if(NME.current_account) - stored_login = NME.stored_login - stored_password = NME.stored_password - NME.log_out() - else - stored_login = "" - stored_password = "" - . = ..() - /datum/computer_file/program/email_client/on_startup() . = ..() if(NM) var/datum/nano_module/program/email_client/NME = NM - NME.stored_login = stored_login - NME.stored_password = stored_password - NME.log_in() NME.error = "" - NME.check_for_new_messages(1) + NME.check_for_new_messages(TRUE, computer.get_account_nocheck()) + +/datum/computer_file/program/email_client/proc/new_mail_notify(notification_sound) + computer.visible_notification(notification_sound) + computer.audible_notification("sound/machines/ping.ogg") -/datum/computer_file/program/email_client/proc/new_mail_notify() - computer.visible_notification("You got mail!") +/datum/computer_file/program/email_client/proc/mail_received(datum/computer_file/data/email_message/received) + if(NM) + var/datum/nano_module/program/email_client/NME = NM + NME.mail_received(received) /datum/computer_file/program/email_client/process_tick() ..() @@ -47,19 +35,18 @@ if(!istype(NME)) return NME.relayed_process(computer.get_network_status()) - - var/check_count = NME.check_for_new_messages() - if(check_count) - if(check_count == 2) - new_mail_notify() - ui_header = "ntnrc_new.gif" - else - ui_header = "ntnrc_idle.gif" + var/datum/computer_file/data/account/current_account = computer.get_account_nocheck() + if(current_account) + var/check_count = NME.check_for_new_messages(FALSE, current_account) + if(check_count) + if(check_count == 2 && !current_account.notification_mute) + new_mail_notify(current_account.notification_sound) + ui_header = "ntnrc_new.gif" + else + ui_header = "ntnrc_idle.gif" /datum/nano_module/program/email_client/ name = "Email Client" - var/stored_login = "" - var/stored_password = "" var/error = "" var/msg_title = "" @@ -77,7 +64,6 @@ var/download_progress = 0 var/download_speed = 0 - var/datum/computer_file/data/email_account/current_account = null var/datum/computer_file/data/email_message/current_message = null /datum/nano_module/program/email_client/proc/get_functional_drive() @@ -86,79 +72,27 @@ /datum/nano_module/program/email_client/proc/get_email_addresses() var/datum/computer_network/net = get_network() if(net) - return net.get_email_addresses() + return net.get_accounts() /datum/nano_module/program/email_client/proc/mail_received(var/datum/computer_file/data/email_message/received_message) - var/mob/living/L = get_holder_of_type(host, /mob/living) + var/mob/living/L = host.get_recursive_loc_of_type(/mob/living) if(L) var/list/msg = list() msg += "*--*\n" msg += "New mail received from [received_message.source]:\n" - msg += "Subject: [received_message.title]\nMessage:\n[digitalPencode2html(received_message.stored_data)]\n" + msg += "Subject: [received_message.title]\nMessage:\n[received_message.generate_file_data()]\n" if(received_message.attachment) msg += "Attachment: [received_message.attachment.filename].[received_message.attachment.filetype] ([received_message.attachment.size]GQ)\n" - msg += "Reply\n" + msg += "Reply\n" msg += "*--*" to_chat(L, jointext(msg, null)) -/datum/nano_module/program/email_client/Destroy() - log_out() - . = ..() - -/datum/nano_module/program/email_client/proc/log_in() - var/list/id_login - var/atom/movable/A = nano_host() - var/obj/item/card/id/id = A.GetIdCard() - if(!id && ismob(A.loc)) - var/mob/M = A.loc - id = M.GetIdCard() - if(id) - id_login = id.associated_email_login.Copy() - - if(!get_network()) - error = "Network error" - return 0 - var/datum/computer_file/data/email_account/target - for(var/datum/computer_file/data/email_account/account in get_email_addresses()) - if(!account || !account.can_login) - continue - if(id_login && id_login["login"] == account.login) - target = account - break - if(stored_login && stored_login == account.login) - target = account - break - - if(!target) - error = "Invalid Login" - return 0 - - if(target.suspended) - error = "This account has been suspended. Please contact the system administrator for assistance." - return 0 - - var/use_pass - if(stored_password) - use_pass = stored_password - else if(id_login) - use_pass = id_login["password"] - - if(use_pass == target.password) - current_account = target - current_account.connected_clients |= src - return 1 - else - error = "Invalid Password" - return 0 - // Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent. // and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program). -/datum/nano_module/program/email_client/proc/check_for_new_messages(var/messages_read = FALSE) +/datum/nano_module/program/email_client/proc/check_for_new_messages(var/messages_read = FALSE, var/datum/computer_file/data/account/current_account) if(!current_account) - return 0 - if(!get_network()) - return 0 - var/list/allmails = current_account.all_emails() + return + var/list/allmails = current_account.all_incoming_emails() if(allmails.len > last_message_count) . = 2 @@ -167,34 +101,26 @@ else . = 0 + if(.) // See if we can actually find the passed account. We wait to do this til now because finding the account requires some hoop jumping that shouldn't occur every tick. + if(program.computer.get_account() != current_account) + return 0 + last_message_count = allmails.len if(messages_read) read_message_count = allmails.len - -/datum/nano_module/program/email_client/proc/log_out() - if(current_account) - current_account.connected_clients -= src - current_account = null - downloading = null - download_progress = 0 - last_message_count = 0 - read_message_count = 0 - -/datum/nano_module/program/email_client/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/email_client/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() - - // Password has been changed by other client connected to this email account - if(current_account) - if(current_account.password != stored_password) - if(!log_in()) - log_out() - error = "Invalid Password" - // Banned. - else if(current_account.suspended) - log_out() - error = "This account has been suspended. Please contact the system administrator for assistance." - + var/datum/computer_network/network = get_network() + var/datum/computer_file/data/account/current_account = program.computer.get_account() + if(!network) + error = "No network found. Check network connection." + else + if(istype(current_account)) + if(current_account.suspended) + error = "This account has been suspended. Please contact the system administrator for assistance." + else + error = "No account logged in. Please login through your system to proceed." if(error) data["error"] = error else if(downloading) @@ -203,18 +129,21 @@ data["down_progress"] = download_progress data["down_size"] = downloading.size data["down_speed"] = download_speed - - else if(istype(current_account)) + else data["current_account"] = current_account.login + data["notification_mute"] = current_account.notification_mute if(addressbook) var/list/all_accounts = list() - for(var/datum/computer_file/data/email_account/account in get_email_addresses()) + for(var/datum/computer_file/data/account/account in get_email_addresses()) if(!account.can_login) continue + var/datum/computer_file/report/crew_record/record = network.get_crew_record_by_name(account.fullname) + var/job = record ? record.get_job() : "Undefined" + var/domain = "@[network.network_id]" all_accounts.Add(list(list( "name" = account.fullname, - "job" = account.assignment, - "login" = account.login + "job" = job, + "address" = account.login + domain ))) data["addressbook"] = 1 data["accounts"] = all_accounts @@ -229,7 +158,7 @@ data["msg_attachment_size"] = msg_attachment.size else if (current_message) data["cur_title"] = current_message.title - data["cur_body"] = digitalPencode2html(current_message.stored_data) + data["cur_body"] = current_message.generate_file_data() data["cur_timestamp"] = current_message.timestamp data["cur_source"] = current_message.source data["cur_uid"] = current_message.uid @@ -258,16 +187,13 @@ for(var/datum/computer_file/data/email_message/message in message_source) all_messages.Add(list(list( "title" = message.title, - "body" = digitalPencode2html(message.stored_data), + "body" = message.generate_file_data(), "source" = message.source, "timestamp" = message.timestamp, "uid" = message.uid ))) data["messages"] = all_messages data["messagecount"] = all_messages.len - else - data["stored_login"] = stored_login - data["stored_password"] = stars(stored_password, 0) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -278,7 +204,7 @@ ui.set_initial_data(data) ui.open() -/datum/nano_module/program/email_client/proc/find_message_by_fuid(var/fuid) +/datum/nano_module/program/email_client/proc/find_message_by_fuid(var/fuid, var/datum/computer_file/data/account/current_account) if(!istype(current_account)) return @@ -310,31 +236,27 @@ download_progress = 0 return 1 - if(drive.store_file(downloading)) + var/success = drive.store_file() + if(success == OS_FILE_SUCCESS) error = "File successfully downloaded to local device." + else if(success == OS_HARDDRIVE_SPACE) + error = "Error saving file: The hard drive is full" else - error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional." + error = "Error saving file: I/O Error: The hard drive may be nonfunctional." downloading = null download_progress = 0 return 1 - /datum/nano_module/program/email_client/Topic(href, href_list) if(..()) return 1 var/mob/living/user = usr + var/datum/computer_file/data/account/current_account = program.computer.get_account() if(href_list["open"]) ui_interact() - check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons. - if(href_list["login"]) - log_in() - return 1 - - if(href_list["logout"]) - log_out() - return 1 + check_for_new_messages(TRUE, current_account) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons. if(href_list["reset"]) error = "" @@ -387,22 +309,10 @@ addressbook = 0 return 1 - if(href_list["edit_login"]) - var/newlogin = sanitize(input(user,"Enter login", "Login", stored_login), 100) - if(newlogin) - stored_login = newlogin - return 1 - - if(href_list["edit_password"]) - var/newpass = sanitize(input(user,"Enter password", "Password"), 100) - if(newpass) - stored_password = newpass - return 1 - if(href_list["delete"]) if(!istype(current_account)) return 1 - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"]) + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"], current_account) if(!istype(M)) return 1 if(folder == "Deleted") @@ -425,12 +335,15 @@ if(!length(msg_title)) msg_title = "No subject" + var/datum/computer_network/network = get_network() var/datum/computer_file/data/email_message/message = new() + if(!network) + return TOPIC_REFRESH message.title = msg_title message.stored_data = msg_body - message.source = current_account.login + message.source = current_account.login + "@[network.network_id]" message.attachment = msg_attachment - if(!current_account.send_mail(msg_recipient, message, get_network())) + if(!network.send_email(current_account, msg_recipient, message)) error = "Error sending email: this address doesn't exist." return 1 else @@ -443,7 +356,7 @@ return 1 if(href_list["reply"]) - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"]) + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"], current_account) if(!istype(M)) return 1 error = null @@ -457,37 +370,19 @@ return 1 if(href_list["view"]) - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"]) + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"], current_account) if(istype(M)) current_message = M return 1 - if(href_list["changepassword"]) - var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100) - if(!oldpassword) - return 1 - var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100) - if(!newpassword1) - return 1 - var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100) - if(!newpassword2) - return 1 - - if(!istype(current_account)) - error = "Please log in before proceeding." - return 1 - - if(current_account.password != oldpassword) - error = "Incorrect original password" - return 1 - - if(newpassword1 != newpassword2) - error = "The entered passwords do not match." - return 1 + if(href_list["set_notification"]) + var/new_notification = sanitize(input(user, "Enter your desired notification sound:", "Set Notification", current_account.notification_sound) as text|null) + if(new_notification && current_account) + current_account.notification_sound = new_notification + return 1 - current_account.password = newpassword1 - stored_password = newpassword1 - error = "Your password has been successfully changed!" + if(href_list["mute"]) + current_account.notification_mute = !current_account.notification_mute return 1 // The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View) @@ -502,7 +397,7 @@ if(!filename) return 1 - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"]) + var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"], current_account) var/datum/computer_file/data/mail = istype(M) ? M.export() : null if(!istype(mail)) return 1 @@ -539,7 +434,7 @@ if(CF.unsendable) continue if(CF.filename == picked_file) - msg_attachment = CF.clone() + msg_attachment = CF.Clone() break if(!istype(msg_attachment)) msg_attachment = null @@ -560,7 +455,7 @@ if(!drive) return 1 - downloading = current_message.attachment.clone() + downloading = current_message.attachment.Clone() download_progress = 0 return 1 diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm deleted file mode 100644 index 2fd9d99e3076..000000000000 --- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm +++ /dev/null @@ -1,250 +0,0 @@ -/datum/computer_file/program/filemanager - filename = "filemanager" - filedesc = "NTOS File Manager" - extended_desc = "This program allows management of files." - program_icon_state = "generic" - program_key_state = "generic_key" - program_menu_icon = "folder-collapsed" - size = 8 - available_on_network = 0 - undeletable = 1 - usage_flags = PROGRAM_ALL - category = PROG_UTIL - var/open_file - var/error - var/list/file_sources = list( - /datum/file_storage/disk, - /datum/file_storage/disk/removable, - /datum/file_storage/network - ) - var/datum/file_storage/current_filesource = /datum/file_storage/disk - var/datum/file_transfer/current_transfer //ongoing file transfer between filesources - -/datum/computer_file/program/filemanager/on_startup(var/mob/living/user, var/datum/extension/interactive/ntos/new_host) - ..() - for(var/T in file_sources) - file_sources[T] = new T(new_host) - current_filesource = file_sources[initial(current_filesource)] - -/datum/computer_file/program/filemanager/on_shutdown() - for(var/T in file_sources) - var/datum/file_storage/FS = file_sources[T] - qdel(FS) - file_sources[T] = null - current_filesource = initial(current_filesource) - ui_header = null - if(current_transfer) - qdel(current_transfer) - return ..() - -/datum/computer_file/program/filemanager/Topic(href, href_list, state) - . = ..() - if(.) - return - - var/mob/user = usr - - if(href_list["PRG_change_filesource"]) - . = TOPIC_HANDLED - var/list/choices = list() - for(var/T in file_sources) - var/datum/file_storage/FS = file_sources[T] - if(FS == current_filesource) - continue - choices[FS.name] = FS - var/file_source = input(usr, "Choose a storage medium to use:", "Select Storage Medium") as null|anything in choices - if(file_source) - current_filesource = choices[file_source] - if(istype(current_filesource, /datum/file_storage/network)) - var/datum/computer_network/network = computer.get_network() - if(!network) - return TOPIC_REFRESH - // Helper for some user-friendliness. Try to select the first available mainframe. - var/list/file_servers = network.get_file_server_tags() - if(!file_servers.len) - return TOPIC_REFRESH - var/datum/file_storage/network/N = current_filesource - N.server = file_servers[1] - return TOPIC_REFRESH - - if(href_list["PRG_changefileserver"]) - . = TOPIC_HANDLED - var/datum/computer_network/network = computer.get_network() - if(!network) - return - var/list/file_servers = network.get_file_server_tags(MF_ROLE_FILESERVER, user) - var/file_server = input(usr, "Choose a fileserver to view files on:", "Select File Server") as null|anything in file_servers - if(file_server) - var/datum/file_storage/network/N = file_sources[/datum/file_storage/network] - N.server = file_server - return TOPIC_REFRESH - - var/errors = current_filesource.check_errors() - if(errors) - error = errors - return TOPIC_HANDLED - - if(href_list["PRG_openfile"]) - . = TOPIC_HANDLED - open_file = href_list["PRG_openfile"] - - if(href_list["PRG_newtextfile"]) - . = TOPIC_HANDLED - var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename")) - if(!newname) - return TOPIC_HANDLED - - if(current_filesource.create_file(newname)) - return TOPIC_REFRESH - - if(href_list["PRG_deletefile"]) - . = TOPIC_REFRESH - current_filesource.delete_file(href_list["PRG_deletefile"]) - - if(href_list["PRG_usbdeletefile"]) - . = TOPIC_REFRESH - current_filesource.delete_file(href_list["PRG_usbdeletefile"]) - - if(href_list["PRG_closefile"]) - . = TOPIC_REFRESH - open_file = null - error = null - - if(href_list["PRG_clone"]) - . = TOPIC_REFRESH - current_filesource.clone_file(href_list["PRG_clone"]) - - if(href_list["PRG_rename"]) - . = TOPIC_REFRESH - var/datum/computer_file/F = current_filesource.get_file(href_list["PRG_rename"]) - if(!F || !istype(F)) - return - var/newname = sanitize(input(usr, "Enter new file name:", "File rename", F.filename)) - if(F && newname) - F.filename = newname - - if(href_list["PRG_edit"]) - . = TOPIC_HANDLED - if(!open_file) - return - var/datum/computer_file/data/F = current_filesource.get_file(open_file) - if(!F || !istype(F)) - return - if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) - return - if(F.read_only) - error = "This file is read only. You cannot edit it." - return - - var/oldtext = html_decode(F.stored_data) - oldtext = replacetext(oldtext, "\[br\]", "\n") - - var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) - if(!newtext || !CanInteract(user, state)) - return - - if(F) - current_filesource.save_file(F.filename, newtext) - return TOPIC_REFRESH - - if(href_list["PRG_printfile"]) - . = 1 - if(!open_file) - return - var/datum/computer_file/data/F = current_filesource.get_file(open_file) - if(!F || !istype(F)) - return - if(!computer.print_paper(digitalPencode2html(F.stored_data),F.filename,F.papertype, F.metadata)) - error = "Hardware error: Unable to print the file." - return TOPIC_REFRESH - - if(href_list["PRG_stoptransfer"]) - QDEL_NULL(current_transfer) - ui_header = null - return TOPIC_REFRESH - - if(href_list["PRG_copyto"]) - . = TOPIC_REFRESH - var/datum/computer_file/F = current_filesource.get_file(href_list["PRG_copyto"]) - if(!F || !istype(F)) - error = "I/O ERROR: Unable to open file." - return - var/list/choices = list() - for(var/T in file_sources) - var/datum/file_storage/FS = file_sources[T] - if(FS == current_filesource) - continue - choices[FS.name] = FS - var/file_source = input(usr, "Choose a destination storage medium:", "Copy To Another Medium") as null|anything in choices - if(file_source) - var/datum/file_storage/dst = choices[file_source] - var/nope = dst.check_errors() - if(nope) - to_chat(user, SPAN_WARNING("Cannot copy file to [dst] for following reason: [nope]")) - return - current_transfer = new(current_filesource, dst, F) - ui_header = "downloader_running.gif" - -/datum/computer_file/program/filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) - . = ..() - if(!.) - return - var/list/data = computer.initial_data() - - if(error) - data["error"] = error - else if(current_filesource) - data["error"] = current_filesource.check_errors() - - data["current_source"] = current_filesource.name - if(istype(current_filesource, /datum/file_storage/network)) - var/datum/file_storage/network/N = current_filesource - data["fileserver"] = N.server - if(open_file) - var/datum/computer_file/data/F - F = current_filesource.get_file(open_file) - if(!istype(F)) - data["error"] = "I/O ERROR: Unable to open file." - else - data["filedata"] = F.generate_file_data(user) - data["filename"] = "[F.filename].[F.filetype]" - else - var/list/files[0] - for(var/datum/computer_file/F in current_filesource.get_all_files()) - files.Add(list(list( - "name" = F.filename, - "type" = F.filetype, - "size" = F.size, - "undeletable" = F.undeletable - ))) - data["files"] = files - - // Don't show transfers that will be over in a tick, screw flickering - if(current_transfer && current_transfer.get_eta() > 2) - data |= current_transfer.get_ui_data() - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 600, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.set_auto_update(1) - ui.open() - -/datum/computer_file/program/filemanager/process_tick() - if(!current_transfer) - return - var/result = current_transfer.update_progress() - if(!result) //something went wrong - if(QDELETED(current_transfer)) //either completely - error = "I/O ERROR: Unknown error during the file transfer." - else //or during the saving at the destination - error = "I/O ERROR: Unable to store '[current_transfer.copying.filename]' at [current_transfer.copying_to]" - qdel(current_transfer) - current_transfer = null - ui_header = null - return - else if(!current_transfer.left_to_copy) //done - QDEL_NULL(current_transfer) - ui_header = null - diff --git a/code/modules/modular_computers/file_system/programs/generic/file_manager.dm b/code/modules/modular_computers/file_system/programs/generic/file_manager.dm new file mode 100644 index 000000000000..546aa102bf43 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/file_manager.dm @@ -0,0 +1,776 @@ +#define FM_NONE 0 +#define FM_READ 1 +#define FM_PERM 2 + +#define MAX_FILE_PATTERNS 5 + +/datum/computer_file/program/filemanager + filename = "filemanager" + filedesc = "OS File Manager" + extended_desc = "This program allows management of files." + program_icon_state = "generic" + program_key_state = "generic_key" + program_menu_icon = "folder-collapsed" + size = 8 + available_on_network = 0 + undeletable = 1 + usage_flags = PROGRAM_ALL + category = PROG_UTIL + + var/open_file + var/file_mode = FM_NONE + var/error // Generic error, wiped on any action + + var/file_error // File error, closes open_file once cleared + var/disk_error // Disk error, removes current disk once cleared + + var/list/disks = list() // List of list(/datum/file_storage, weakref(directory file)). + var/current_index + + var/datum/file_transfer/current_transfer //ongoing file transfer between file_storage datums + + // Variables for modifying file perms + var/list/f_read_access = list() + var/list/f_write_access = list() + var/list/f_mod_access = list() + + var/current_perm = OS_READ_ACCESS + + var/selected_pattern // Index of the current pattern being accessed. + var/selected_parent_group + +/datum/computer_file/program/filemanager/on_shutdown() + disks.Cut() + ui_header = null + current_index = null + if(current_transfer) + qdel(current_transfer) + + error = null + file_error = null + disk_error = null + open_file = null + file_mode = FM_NONE + reset_perm_mod() + + return ..() + +/datum/computer_file/program/filemanager/Topic(href, href_list, state) + . = ..() + if(.) + return + + var/mob/user = usr + var/list/accesses = computer.get_access(user) + + error = null + if(file_error) + file_error = null + open_file = null + file_mode = FM_NONE + + if(disk_error) + disk_error = null + disks -= list(disks[current_index]) + current_index = null + + if(href_list["PRG_clear_error"]) + return TOPIC_REFRESH + + if(href_list["PRG_select_disk"]) + var/disk_name = href_list["PRG_select_disk"] + var/datum/file_storage/selected_disk = computer.mounted_storage[disk_name] + if(selected_disk) + disks += list(list(selected_disk, null)) + current_index = disks.len + return TOPIC_REFRESH + + if(href_list["PRG_mount_network"]) + var/datum/computer_network/network = computer.get_network() + if(!network) + to_chat(user, SPAN_WARNING("NETWORK ERROR: No connectivity to the network.")) + return TOPIC_HANDLED + if(!computer.get_network_status(NET_FEATURE_FILESYSTEM)) + to_chat(user, SPAN_WARNING("NETWORK ERROR: The network denied filesystem access.")) + return TOPIC_HANDLED + var/list/available_mainframes = network.get_file_server_tags(MF_ROLE_FILESERVER, accesses) + if(!length(available_mainframes)) + to_chat(user, SPAN_WARNING("NETWORK ERROR: No available mainframes on the network.")) + return TOPIC_HANDLED + var/fileserver_tag = input(user, "Choose a mainframe you would like to mount as a disk:", "Mainframe Mount") as null|anything in available_mainframes + if(!fileserver_tag) + return TOPIC_HANDLED + var/root_name = sanitize_for_file(input(user, "Enter the name of the root directory for the newly mounted disk.", "Root directory") as null|text) + if(!root_name) + return TOPIC_HANDLED + var/feedback = computer.mount_mainframe(root_name, fileserver_tag) + to_chat(user, SPAN_NOTICE(feedback)) + return TOPIC_REFRESH + + if(href_list["PRG_mount_settings"]) + var/root_name = href_list["PRG_mount_settings"] + var/datum/file_storage/network/avail_disk = computer.mounted_storage[root_name] + if(!istype(avail_disk)) + return TOPIC_REFRESH + if(avail_disk.hidden || !avail_disk.check_access(accesses)) + to_chat(user, SPAN_WARNING("You don't have permission to modify this network drive!")) + return TOPIC_HANDLED + + var/datum/computer_file/data/automount_file = get_file("automount", "local") + var/automount_str = "[root_name]|[avail_disk.server];" + + var/automounted = istype(automount_file) ? findtext(automount_file.stored_data, automount_str) : FALSE + + var/prompt = alert(user, "What would you like to do?", "Mount settings", "Cancel", "Unmount", automounted ? "Disable auto mount" : "Enable auto mount") + + if(!CanInteract(user, state)) + return TOPIC_HANDLED + + switch(prompt) + if("Unmount") + computer.unmount_storage(root_name) + to_chat(user, SPAN_NOTICE("Unmounted the network drive [root_name].")) + return TOPIC_REFRESH + if("Disable auto mount") + if(!automounted || !istype(automount_file)) + return TOPIC_REFRESH + + // Remove the auto mount string + automount_file.stored_data = replacetextEx(automount_file.stored_data, automount_str, "") + to_chat(user, SPAN_NOTICE("The network drive [root_name] will no longer auto mount on startup.")) + return TOPIC_REFRESH + + if("Enable auto mount") + if(automounted) + return TOPIC_REFRESH + + if(!istype(automount_file)) + // Create the automount file. + automount_file = create_file("automount", "local", file_type = /datum/computer_file/data) + if(!istype(automount_file)) + return TOPIC_REFRESH + + automount_file.stored_data += automount_str + to_chat(user, SPAN_NOTICE("The network drive [root_name] will now auto mount on startup.")) + return TOPIC_REFRESH + + if(href_list["PRG_change_disk"]) + var/disk_index = text2num(href_list["PRG_change_disk"]) + if(disk_index == 0 || disk_index > disks.len) + current_index = null + return TOPIC_REFRESH + current_index = disk_index + return TOPIC_REFRESH + + if(!current_index || current_index > disks.len) + current_index = null + return TOPIC_REFRESH + + var/datum/file_storage/current_disk = disks[current_index]?[1] + if(!current_disk) + return TOPIC_HANDLED + + if(href_list["PRG_exit_disk"]) + if(!current_index) + return TOPIC_HANDLED + disks -= list(disks[current_index]) // We have to enclose the list in another list to get it to actually remove it from disks. + current_index-- + return TOPIC_REFRESH + + var/disk_errors = current_disk.check_errors() + if(disk_errors) + return TOPIC_REFRESH // ui_interact refreshs the disk errors anyway. + + var/weakref/dir_ref = disks[current_index][2] + var/datum/computer_file/directory/current_directory + if(istype(dir_ref)) + current_directory = dir_ref.resolve() + if(!current_directory || !(current_directory in current_disk.get_all_files())) + disks[current_index][2] = null + current_directory = null + else + disks[current_index][2] = null + + if(href_list["PRG_up_directory"]) + var/datum/computer_file/directory/parent_dir = current_directory?.get_directory() + if(parent_dir) + disks[current_index][2] = weakref(parent_dir) + else + disks[current_index][2] = null + return TOPIC_REFRESH + + if(href_list["PRG_openfile"]) + . = TOPIC_HANDLED + var/datum/computer_file/F = current_disk.get_file(href_list["PRG_openfile"], current_directory) + if(!F) + return TOPIC_HANDLED + if(istype(F, /datum/computer_file/directory)) + if(F.get_file_perms(accesses, user) & OS_READ_ACCESS) + disks[current_index][2] = weakref(F) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("You do not have permission to open this directory.")) + return TOPIC_HANDLED + + if(istype(F, /datum/computer_file/data)) + if(F.get_file_perms(accesses, user) & OS_READ_ACCESS) + open_file = href_list["PRG_openfile"] + file_mode = FM_READ + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("You do not have permission to open this file.")) + return TOPIC_HANDLED + + to_chat(user, SPAN_WARNING("This file is not in a readable format.")) + return TOPIC_HANDLED + + if(href_list["PRG_modifyperms"]) + var/datum/computer_file/mod_file = current_disk.get_file(href_list["PRG_modifyperms"], current_directory, accesses, user) + if(!(mod_file?.get_file_perms(accesses, user) & OS_MOD_ACCESS)) + to_chat(user, SPAN_WARNING("You lack access to modify the permissions of '[mod_file.filename].[mod_file.filetype]'.")) + return TOPIC_HANDLED + + open_file = href_list["PRG_modifyperms"] + file_mode = FM_PERM + + f_read_access = LAZYLEN(mod_file.read_access) ? mod_file.read_access.Copy() : list() + f_write_access = LAZYLEN(mod_file.write_access) ? mod_file.write_access.Copy() : list() + f_mod_access = LAZYLEN(mod_file.mod_access) ? mod_file.mod_access.Copy() : list() + + return TOPIC_REFRESH + + if(href_list["PRG_newtextfile"]) + . = TOPIC_REFRESH + var/newname = sanitize_for_file(input(usr, "Enter file name or leave blank to cancel:", "New file")) + if(!length(newname)) + return TOPIC_HANDLED + + var/created_file = current_disk.create_file(newname, current_directory, file_type = /datum/computer_file/data/text, accesses = accesses, user = user) + if(created_file != OS_FILE_SUCCESS) + switch(created_file) + if(OS_FILE_NO_WRITE) + to_chat(user, SPAN_WARNING("You lack permission to create a file in this directory.")) + return TOPIC_HANDLED + if(OS_NETWORK_ERROR) + to_chat(user, SPAN_WARNING("Unable to access directory on the network.")) + return TOPIC_REFRESH + if(OS_HARDDRIVE_SPACE) + to_chat(user, SPAN_WARNING("Unable to create new file. The hard drive is full.")) + return TOPIC_HANDLED + else + to_chat(user, SPAN_WARNING("Unable to create new file. The hard drive may be non-functional.")) + return TOPIC_REFRESH + + if(href_list["PRG_newdir"]) + . = TOPIC_REFRESH + var/newname = sanitize_for_file(input(usr, "Enter directory name or leave blank to cancel:", "New directory")) + if(!length(newname)) + return TOPIC_HANDLED + var/created_dir = current_disk.create_directory(newname, current_directory, accesses, user) + if(created_dir != OS_FILE_SUCCESS) + switch(created_dir) + if(OS_FILE_NO_WRITE) + to_chat(user, SPAN_WARNING("You lack permission to create a directory in this directory.")) + return TOPIC_HANDLED + if(OS_NETWORK_ERROR) + to_chat(user, SPAN_WARNING("Unable to access directory on the network.")) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("Unable to create new directory. The hard drive may be non-functional.")) + return TOPIC_REFRESH + + if(href_list["PRG_deletefile"]) + var/datum/computer_file/del_file = current_disk.get_file(href_list["PRG_deletefile"], current_directory, accesses, user) + var/deleted = current_disk.delete_file(del_file, accesses, user) + if(deleted != OS_FILE_SUCCESS) + switch(deleted) + if(OS_FILE_NO_WRITE) + to_chat(user, SPAN_WARNING("You lack permission to delete '[href_list["PRG_deletefile"]]'.")) + return TOPIC_HANDLED + if(OS_NETWORK_ERROR) + to_chat(user, SPAN_WARNING("Unable to access '[href_list["PRG_deletefile"]]' on the network.")) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("Failed to delete '[href_list["PRG_deletefile"]]'. The hard drive may be non-functional.")) + return TOPIC_REFRESH + return TOPIC_REFRESH + + if(href_list["PRG_closefile"]) + . = TOPIC_REFRESH + open_file = null + if(file_mode == FM_PERM) + reset_perm_mod() + file_mode = FM_NONE + file_error = null + + if(href_list["PRG_clone"]) + var/cloned = current_disk.clone_file(href_list["PRG_clone"], current_directory, accesses, user) + if(cloned != OS_FILE_SUCCESS) + switch(cloned) + if(OS_FILE_NO_READ) + to_chat(user, SPAN_WARNING("You lack permission to read the file '[href_list["PRG_clone"]]'.")) + return TOPIC_HANDLED + if(OS_FILE_NO_WRITE) + // Cheap hack to get the filename after cloning. + var/datum/computer_file/source_file = get_file(href_list["PRG_clone"], current_disk.get_dir_path(current_directory, TRUE)) + to_chat(user, SPAN_WARNING("You lack permission to create the file '[href_list["PRG_clone"] + source_file.copy_string]'.")) + return TOPIC_HANDLED + if(OS_NETWORK_ERROR) + to_chat(user, SPAN_WARNING("Unable to access file '[href_list["PRG_clone"]]' on the network.")) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("Unable to clone file '[href_list["PRG_clone"]]'. The hard drive may be non-functional.")) + return TOPIC_REFRESH + return TOPIC_REFRESH + + if(href_list["PRG_rename"]) + var/datum/computer_file/F = current_disk.get_file(href_list["PRG_rename"], current_directory) + if(!F || !istype(F)) + return TOPIC_REFRESH + if(F.unrenamable) + to_chat(user, SPAN_WARNING("You do not have permission to rename that file.")) + return TOPIC_HANDLED + if(F.get_file_perms(accesses, user) & OS_WRITE_ACCESS) + var/newname = sanitize_for_file(input(user, "Enter new file name:", "File rename", F.filename)) + if(F && length(newname)) + current_disk.rename_file(F, newname, user) + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("You do not have permission to rename that file.")) + return TOPIC_HANDLED + + if(href_list["PRG_edit"]) + . = TOPIC_HANDLED + if(!open_file || file_mode != FM_READ) + return + var/datum/computer_file/data/F = current_disk.get_file(open_file, current_directory) + if(!F || !istype(F)) + return + if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) + return + if(F.read_only) + file_error = "This file is read only. You cannot edit it." + return + if(!(F.get_file_perms(accesses, user) & OS_WRITE_ACCESS)) + file_error = "You do not have write access to this file." + return + var/oldtext = html_decode(F.stored_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") + + var/newtext = sanitize(replacetext(input(user, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext || !CanInteract(user, state)) + return + + if(F) + current_disk.save_file(F.filename, current_directory, newtext, null, accesses, user, F.type) + return TOPIC_REFRESH + + if(href_list["PRG_printfile"]) + . = 1 + if(!open_file || file_mode != FM_READ) + return + var/datum/computer_file/data/F = current_disk.get_file(open_file, current_directory) + if(!F || !istype(F)) + return + if(!(F.get_file_perms(accesses, user) & OS_READ_ACCESS)) + file_error = "You do not have read access to this file." + return + if(!computer.print_paper(F.generate_file_data(), F.filename, F.papertype, F.metadata)) + file_error = "Hardware error: Unable to print the file." + return TOPIC_REFRESH + + if(href_list["PRG_stoptransfer"]) + QDEL_NULL(current_transfer) + ui_header = null + return TOPIC_REFRESH + + if(href_list["PRG_transferto"]) + . = TOPIC_REFRESH + var/datum/computer_file/F = current_disk.get_file(href_list["PRG_transferto"], current_directory) + if(!F || !istype(F) || F.unsendable) + to_chat(user, SPAN_WARNING("I/O ERROR: Unable to transfer file.")) + return + + var/copying = "Transfer" + if(!F.uncopyable) + copying = alert(usr, "Would you like to copy the file or transfer it? Transfering files requires write access.", "Copying file", "Copy", "Transfer") + var/list/choices = list() + var/list/curr_fs_list = disks[current_index] + for(var/list/fs_list in disks) + // Skip over the disk if its referencing the same directory. + if(curr_fs_list[1] == fs_list[1] && curr_fs_list[2] == fs_list[2]) + continue + + var/datum/file_storage/FS = fs_list[1] + var/weakref/FS_dir_ref = fs_list[2] + + var/datum/computer_file/directory/FS_dir = FS_dir_ref?.resolve() + choices[FS.get_dir_path(FS_dir, TRUE)] = fs_list + + if(!length(choices)) + to_chat(usr, SPAN_WARNING("You must open another disk to transfer files.")) + return TOPIC_HANDLED + + var/storage = input(usr, "Choose a destination storage medium:", "Transfer To Another Medium") as null|anything in choices + if(storage) + var/list/chosen_list = choices[storage] + var/datum/file_storage/dst = chosen_list[1] + var/nope = dst.check_errors() + if(nope) + to_chat(user, SPAN_WARNING("Cannot transfer file to [dst] for following reason: [nope]")) + return + + var/weakref/dst_dir_ref = chosen_list[2] + var/datum/computer_file/directory/dst_dir = dst_dir_ref?.resolve() + + var/error = check_file_transfer(dst_dir, F, copying == "Copy", accesses, user) + if(error) + to_chat(user, SPAN_WARNING("Cannot transfer file: [error].")) + return TOPIC_HANDLED + current_transfer = new(current_disk, dst, dst_dir, F, copying == "Copy" ? TRUE : FALSE) + ui_header = "downloader_running.gif" + + if(href_list["PRG_runfile"]) + . = TOPIC_HANDLED + if(!open_file) + return + var/datum/computer_file/program/P = current_disk.get_file(open_file, current_directory) + if(istype(P)) + computer.run_program(P.filename) + return TOPIC_HANDLED + var/datum/computer_file/data/F = current_disk.get_file(open_file, current_directory) + if(!F || !istype(F)) + return + computer.run_script(usr, F) + return TOPIC_HANDLED + + // Permission modifying. + if(file_mode == FM_PERM) + if(!open_file) + file_mode = FM_NONE + return TOPIC_REFRESH + + var/datum/computer_network/network = computer.get_network() + var/datum/extension/network_device/acl/access_controller = network?.access_controller + if(!access_controller) + file_error = "No access controller was found on the network." + return TOPIC_REFRESH + + var/datum/computer_file/F = current_disk.get_file(open_file, current_directory) + if(!F || !istype(F)) + file_error = "Unable to open file" + return TOPIC_REFRESH + if(!(F.get_file_perms(accesses, user) & OS_MOD_ACCESS)) + file_error = "You do not have access to modify this file's permissions." + return TOPIC_REFRESH + + if(href_list["PRG_change_perm"]) + switch(href_list["PRG_change_perm"]) + if("read") + current_perm = OS_READ_ACCESS + if("write") + current_perm = OS_WRITE_ACCESS + if("mod") + current_perm = OS_MOD_ACCESS + + selected_pattern = null + return TOPIC_REFRESH + + var/list/current_perm_list + switch(current_perm) + if(OS_READ_ACCESS) + current_perm_list = f_read_access + if(OS_WRITE_ACCESS) + current_perm_list = f_write_access + if(OS_MOD_ACCESS) + current_perm_list = f_mod_access + + if(href_list["PRG_add_pattern"]) + if(length(current_perm_list) >= MAX_FILE_PATTERNS) + to_chat(usr, SPAN_WARNING("You cannot add more than [MAX_FILE_PATTERNS] patterns to a file's permissions.")) + return TOPIC_HANDLED + current_perm_list += list(list()) // Add a plank pattern to the access list. + return TOPIC_REFRESH + + if(href_list["PRG_remove_pattern"]) + var/pattern_index = text2num(href_list["PRG_remove_pattern"]) + if(pattern_index == 0 || pattern_index > length(current_perm_list)) + return TOPIC_HANDLED + current_perm_list -= list(current_perm_list[pattern_index]) // We have to encapsulate the pattern in another list to actually delete it. + if(selected_pattern == pattern_index) + selected_pattern = null + else if(selected_pattern > pattern_index) + selected_pattern-- + return TOPIC_REFRESH + + if(href_list["PRG_select_pattern"]) + var/pattern_index = text2num(href_list["PRG_select_pattern"]) + if(pattern_index > length(current_perm_list)) + return TOPIC_HANDLED + selected_pattern = pattern_index + return TOPIC_REFRESH + + if(href_list["PRG_select_parent_group"]) + // The parent group actually existing is verified in ui_interact() + selected_parent_group = href_list["PRG_select_parent_group"] + return TOPIC_REFRESH + + if(selected_pattern > length(current_perm_list)) + selected_pattern = null + return TOPIC_REFRESH + + var/list/pattern_list = current_perm_list[selected_pattern] + + if(href_list["PRG_assign_group"]) + var/group = href_list["PRG_assign_group"] + if(!(group in access_controller.all_groups)) + return TOPIC_REFRESH + if(!pattern_list) + to_chat(user, SPAN_WARNING("Select a pattern first!")) + return TOPIC_HANDLED + pattern_list |= href_list["PRG_assign_group"] + ".[network.network_id]" + return TOPIC_REFRESH + + if(href_list["PRG_remove_group"]) + if(!pattern_list) + to_chat(user, SPAN_WARNING("Select a pattern first!")) + return TOPIC_HANDLED + pattern_list -= href_list["PRG_remove_group"] + ".[network.network_id]" + return TOPIC_REFRESH + + if(href_list["PRG_apply_perms"]) + if(!has_access(f_mod_access, accesses)) + var/confirm = alert(user, "You will no longer be able to modify the permissions of this file. Are you sure?", "Permission Modification", "No", "Yes") + if(!CanInteract(user, state) || confirm != "Yes") + return TOPIC_HANDLED + + F.read_access = f_read_access.Copy() + F.write_access = f_write_access.Copy() + F.mod_access = f_mod_access.Copy() + + UNSETEMPTY(F.read_access) + UNSETEMPTY(F.write_access) + UNSETEMPTY(F.mod_access) + + to_chat(user, SPAN_NOTICE("Successfully changed permissions for '[F.filename].[F.filetype]'.")) + open_file = null + file_mode = FM_NONE + + reset_perm_mod() + return TOPIC_REFRESH + +/datum/computer_file/program/filemanager/proc/reset_perm_mod() + f_read_access.Cut() + f_write_access.Cut() + f_mod_access.Cut() + current_perm = OS_READ_ACCESS + + selected_pattern = null + selected_parent_group = null + +/datum/computer_file/program/filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + . = ..() + if(!.) + return + var/list/data = computer.initial_data() + var/list/accesses = computer.get_access(user) + + if(current_index > disks.len) // Safety check. + current_index = null + + var/datum/file_storage/current_disk + var/datum/computer_file/directory/current_directory + + if(current_index) + var/list/current_disk_list = disks[current_index] + current_disk = current_disk_list[1] + + var/weakref/dir_ref = current_disk_list[2] + if(istype(dir_ref)) + current_directory = dir_ref.resolve() + else + current_disk_list[2] = null + + // Disk errors can occur without user error, so check them when the UI refreshes. + if(current_disk) + disk_error = current_disk.check_errors() + data["disk_error"] = disk_error + + if(!disk_error) + var/list/ui_disks[0] + var/disk_index = 1 + for(var/list/ui_disk_list in disks) + var/datum/file_storage/ui_disk = ui_disk_list[1] + + var/weakref/ui_dir_ref = ui_disk_list[2] + var/datum/computer_file/directory/ui_directory + if(istype(ui_dir_ref)) + ui_directory = ui_dir_ref.resolve() + else + ui_disk_list[2] = null + + ui_disks.Add(list(list( + "name" = ui_disk.get_dir_path(ui_directory), + "index" = disk_index, + "selected" = disk_index == current_index + ))) + disk_index++ + data["disks"] = ui_disks + data["file_mode"] = file_mode + if(current_disk) + data["up_directory"] = !!current_directory + data["current_disk"] = current_disk.get_dir_path(current_directory, TRUE) + + if(open_file) + var/datum/computer_file/F + F = current_disk.get_file(open_file, current_directory) + if(!istype(F)) + file_error = "I/O ERROR: Unable to open file." + else + data["filename"] = "[F.filename].[F.filetype]" + if(file_mode == FM_READ) + var/datum/computer_file/data/data_file = F + if(!istype(data_file)) + file_error = "I/O ERROR: Unable to open file." + else + data["filedata"] = data_file.generate_file_data(user) + if(file_mode == FM_PERM) + data |= permmod_data() + else + var/list/files[0] + for(var/datum/computer_file/F in current_disk.get_dir_files(current_directory)) + files.Add(list(list( + "name" = F.filename, + "type" = F.filetype, + "dir" = istype(F, /datum/computer_file/directory), + "size" = F.size, + "undeletable" = F.undeletable, + "unrenamable" = F.unrenamable, + "unsendable" = F.unsendable + ))) + data["files"] = files + else // No disk selected, option to create a new one. + var/list/avail_disks[0] + + for(var/root_name in computer.mounted_storage) + var/datum/file_storage/avail_disk = computer.mounted_storage[root_name] + + if(!avail_disk.hidden && avail_disk.check_access(accesses)) + avail_disks.Add(list(list( + "name" = root_name, + "desc" = avail_disk.desc, + "is_network" = istype(avail_disk, /datum/file_storage/network) + ))) + + data["avail_disks"] = avail_disks + // Don't show transfers that will be over in a tick, screw flickering + if(current_transfer && current_transfer.get_eta() > 2) + data |= current_transfer.get_ui_data() + + if(file_error) + data["file_error"] = file_error + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "file_manager.tmpl", "OS File Manager", 900, 700, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.set_auto_update(1) + ui.open() + +/datum/computer_file/program/filemanager/proc/permmod_data() + var/data = list() + + var/list/current_perm_list // Whatever permissions list we're currently modifying + + var/datum/computer_network/network = computer.get_network() + var/datum/extension/network_device/acl/access_controller = network?.access_controller + if(!access_controller) + file_error = "No access controller was found on the network." + return data + + switch(current_perm) + if(OS_READ_ACCESS) + current_perm_list = f_read_access + data["current_perm"] = "read" + if(OS_WRITE_ACCESS) + current_perm_list = f_write_access + data["current_perm"] = "write" + if(OS_MOD_ACCESS) + current_perm_list = f_mod_access + data["current_perm"] = "mod" + + var/list/patterns = list() + var/pattern_index = 0 + for(var/list/pattern in current_perm_list) + pattern_index++ + patterns.Add(list(list( + "index" = "[pattern_index]", + "perm_list" = english_list(pattern, "No groups assigned!", and_text = " or ") + ))) + + data["patterns"] = patterns + + var/list/group_dictionary = access_controller.get_group_dict() + var/list/parent_groups_data + var/list/child_groups_data + + var/list/pattern = LAZYACCESS(current_perm_list, selected_pattern) + + if(selected_parent_group) + if(!(selected_parent_group in group_dictionary)) + selected_parent_group = null + else + var/list/child_groups = group_dictionary[selected_parent_group] + if(child_groups) + child_groups_data = list() + for(var/child_group in child_groups) + child_groups_data.Add(list(list( + "child_group" = child_group, + "assigned" = (LAZYISIN(pattern, "[child_group].[network.network_id]")) + ))) + if(!selected_parent_group) // Check again in case we ended up with a non-existent selected parent group instead of breaking the UI. + parent_groups_data = list() + for(var/parent_group in group_dictionary) + parent_groups_data.Add(list(list( + "parent_group" = parent_group, + "assigned" = (LAZYISIN(pattern,"[parent_group].[network.network_id]")) + ))) + data["parent_groups"] = parent_groups_data + data["child_groups"] = child_groups_data + data["selected_parent_group"] = selected_parent_group + data["selected_pattern"] = "[selected_pattern]" + + return data + +/datum/computer_file/program/filemanager/process_tick() + if(!current_transfer) + return + var/result = current_transfer.update_progress() + if(result != OS_FILE_SUCCESS) //something went wrong + if(QDELETED(current_transfer)) //either completely + error = "I/O ERROR: Unknown error during the file transfer." + else //or during the saving at the destination + error = "I/O ERROR: Unable to store '[current_transfer.transferring.filename]' at '[current_transfer.transfer_to.get_dir_path(current_transfer.directory_to, TRUE)]'" + qdel(current_transfer) + current_transfer = null + ui_header = null + return + else if(!current_transfer.left_to_transfer) //done + QDEL_NULL(current_transfer) + ui_header = null + +/datum/computer_file/program/filemanager/on_file_storage_removal(datum/file_storage/removed) + var/list/current_disk_list = LAZYACCESS(disks, current_index) + for(var/list/disk_list in disks) + var/datum/file_storage/disk = disk_list[1] + if(disk == removed) + if(current_disk_list == disk_list) + current_index = null + + disks -= list(disk_list) + +#undef MAX_FILE_PATTERNS +#undef FM_NONE +#undef FM_READ +#undef FM_PERM diff --git a/code/modules/modular_computers/file_system/programs/generic/folding.dm b/code/modules/modular_computers/file_system/programs/generic/folding.dm index 410886474f39..5d49c83988b3 100644 --- a/code/modules/modular_computers/file_system/programs/generic/folding.dm +++ b/code/modules/modular_computers/file_system/programs/generic/folding.dm @@ -1,21 +1,16 @@ -GLOBAL_LIST_INIT(science_strings, list( - "Extruding Mesh Terrain", "Virtualizing Microprocessor", - "Reticulating Splines", "Inserting Chaos Generator", - "Reversing Polarity", "Unfolding Proteins", - "Simulating Alien Abductions", "Scanning Pigeons", - "Iterating Chaos Array", "Abstracting Supermatter", - "Adjusting Social Network", "Recalculating Clown Principle" -)) - #define MINIMUM_SCIENCE_INTERVAL 450 #define MAXIMUM_SCIENCE_INTERVAL 900 #define MINIMUM_FOLDING_EVENT_INTERVAL 50 #define MAXIMUM_FOLDING_EVENT_INTERVAL 100 -#define SCIENCE_MONEY_PER_MINUTE 0.08 // So little money. +#define SCIENCE_MONEY_PER_SECOND 0.08 // So little money. +#define PROGRAM_STATUS_CRASHED 0 +#define PROGRAM_STATUS_RUNNING 1 +#define PROGRAM_STATUS_RUNNING_WARM 2 +#define PROGRAM_STATUS_RUNNING_SCALDING 3 /datum/computer_file/program/folding filename = "fldng" - filedesc = "FOLDING@SAPCE" + filedesc = "FOLDING@SPACE" extended_desc = "This program uses processor cycles for science, in exchange for money." program_icon_state = "generic" program_key_state = "generic_key" @@ -28,8 +23,8 @@ GLOBAL_LIST_INIT(science_strings, list( var/started_on = 0 // When the program started some science. var/current_interval = 0 // How long the current interval will be. - var/next_event = 0 // in world timeofday, when the next event is scheduled to pop. - var/crashed = FALSE // Program periodically needs a restart. + var/next_event = 0 // based on world.timeofday, when the next event is scheduled to pop. + var/program_status = PROGRAM_STATUS_RUNNING // Program periodically needs a restart, increases crash chance slightly over time. var/crashed_at = 0 // When the program crashed. /datum/computer_file/program/folding/Topic(href, href_list) @@ -38,66 +33,88 @@ GLOBAL_LIST_INIT(science_strings, list( return . = TOPIC_REFRESH - if(href_list["fix_crash"] && crashed) - current_interval += world.timeofday - crashed_at - crashed = FALSE + if(href_list["fix_crash"] && program_status == PROGRAM_STATUS_CRASHED) + started_on += world.timeofday - crashed_at + program_status = PROGRAM_STATUS_RUNNING if(href_list["start"] && started_on == 0) started_on = world.timeofday current_interval = rand(MINIMUM_SCIENCE_INTERVAL, MAXIMUM_SCIENCE_INTERVAL) SECONDS next_event = (rand(MINIMUM_FOLDING_EVENT_INTERVAL, MAXIMUM_FOLDING_EVENT_INTERVAL) SECONDS) + world.timeofday - if(href_list["collect"] && started_on > 0 && !crashed) + if(href_list["collect"] && started_on > 0 && program_status != PROGRAM_STATUS_CRASHED) if(started_on + current_interval > world.timeofday) return TOPIC_HANDLED // not ready to collect. var/obj/item/card/id/I = usr.GetIdCard() - if(!I) + if(!istype(I)) to_chat(usr, SPAN_WARNING("Unable to locate ID card for transaction.")) return TOPIC_HANDLED var/datum/money_account/account = get_account(I.associated_account_number) - var/earned = current_interval * (SCIENCE_MONEY_PER_MINUTE * computer.get_processing_power()) + if(!istype(account)) + to_chat(usr, SPAN_WARNING("Unable to locate account for deposit using account number #[I.associated_account_number || "NULL"].")) + return TOPIC_HANDLED + var/earned = (current_interval / 10) * (SCIENCE_MONEY_PER_SECOND * computer.get_processing_power()) //Divide by 10 to convert from ticks to seconds account.deposit(earned, "Completed FOLDING@SPACE project.") - to_chat(usr, SPAN_NOTICE("Transferred [earned] to your account.")) + var/decl/currency/currency = GET_DECL(global.using_map.default_currency) + to_chat(usr, SPAN_NOTICE("Transferred [currency.format_value(earned)] to your account.")) started_on = 0 current_interval = 0 -/datum/computer_file/program/folding/process_tick() +/datum/computer_file/program/folding/process_tick() //Every 50-100 seconds, gives you a 1/3 chance of the program crashing. . = ..() if(!started_on) return - if(world.timeofday > next_event) + if(world.timeofday < next_event) //Checks if it's time for the next crash chance. return - - var/mob/living/holder = get_holder_of_type(computer, /mob/living/carbon/human) - if(!crashed) - if(holder) - switch(rand(1,3)) - if(1) - to_chat(holder, SPAN_WARNING("The [computer] starts to get very warm.")) - if(2) - to_chat(holder, SPAN_WARNING("The [computer] gets scaldingly hot, burning you!")) - holder.burn_skin(0.45) - if(3) - to_chat(holder, SPAN_WARNING("The [computer] pings an error chime.")) - crashed = TRUE + var/mob/living/holder = computer.holder.get_recursive_loc_of_type(/mob/living/human) + var/host = computer.get_physical_host() + if(program_status > PROGRAM_STATUS_CRASHED) + if(PROGRAM_STATUS_RUNNING_SCALDING >= program_status) + switch(rand(PROGRAM_STATUS_RUNNING,program_status)) + if(PROGRAM_STATUS_RUNNING) //Guaranteed 1 tick without crashing. + to_chat(holder, SPAN_WARNING("\The [host] starts to get very warm.")) + if (program_status == PROGRAM_STATUS_RUNNING) + program_status = PROGRAM_STATUS_RUNNING_WARM + if(PROGRAM_STATUS_RUNNING_WARM) //50% chance on subsequent ticks to make the program able to crash. + to_chat(holder, SPAN_WARNING("\The [host] gets scaldingly hot, burning you!")) + holder?.take_overall_damage(0, 0.45) //It checks holder? so that it doesn't cause a runtime error if no one is holding it. + if (program_status == PROGRAM_STATUS_RUNNING_WARM) + program_status = PROGRAM_STATUS_RUNNING_SCALDING + if(PROGRAM_STATUS_RUNNING_SCALDING) //1/3 chance on all following ticks for the program to crash. + to_chat(holder, SPAN_WARNING("\The [host] pings an error chime.")) + program_status = PROGRAM_STATUS_CRASHED crashed_at = world.timeofday else - crashed = TRUE + program_status = PROGRAM_STATUS_CRASHED crashed_at = world.timeofday - next_event = (rand(MINIMUM_FOLDING_EVENT_INTERVAL, MAXIMUM_FOLDING_EVENT_INTERVAL) SECONDS) + world.timeofday + next_event = (rand(MINIMUM_FOLDING_EVENT_INTERVAL, MAXIMUM_FOLDING_EVENT_INTERVAL) SECONDS) + world.timeofday //Sets the next crash chance 50-100 seconds from now /datum/computer_file/program/folding/on_shutdown() started_on = 0 current_interval = 0 - crashed = FALSE + program_status = PROGRAM_STATUS_RUNNING . = ..() /datum/nano_module/program/folding name = "FOLDING@SPACE" + var/static/list/science_strings = list( + "Extruding Mesh Terrain", + "Virtualizing Microprocessor", + "Reticulating Splines", + "Inserting Chaos Generator", + "Reversing Polarity", + "Unfolding Proteins", + "Simulating Alien Abductions", + "Scanning Pigeons", + "Iterating Chaos Array", + "Abstracting Exotic Matter", + "Adjusting Social Network", + "Recalculating Clown Principle" + ) -/datum/nano_module/program/folding/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/folding/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/datum/computer_file/program/folding/prog = program if(!prog.computer) @@ -105,8 +122,8 @@ GLOBAL_LIST_INIT(science_strings, list( data["computing"] = !!prog.started_on data["time_remaining"] = ((prog.started_on + prog.current_interval) - world.timeofday) / 10 data["completed"] = prog.started_on + prog.current_interval <= world.timeofday - data["crashed"] = prog.crashed - data["science_string"] = pick(GLOB.science_strings) + data["crashed"] = (prog.program_status <= PROGRAM_STATUS_CRASHED) + data["science_string"] = pick(science_strings) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) diff --git a/code/modules/modular_computers/file_system/programs/generic/game.dm b/code/modules/modular_computers/file_system/programs/generic/game.dm index 3476e690101a..c5c9b2fdd3d4 100644 --- a/code/modules/modular_computers/file_system/programs/generic/game.dm +++ b/code/modules/modular_computers/file_system/programs/generic/game.dm @@ -7,7 +7,7 @@ filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor. program_icon_state = "game" // Icon state of this program's screen. program_menu_icon = "script" - extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description. + extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network." // A nice description. size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs. available_on_network = 1 // ... but we want it to be available for download. nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file. @@ -27,10 +27,10 @@ filedesc = "Defeat [picked_enemy_name]" // Important in order to ensure that copied versions will have the same enemy name. -/datum/computer_file/program/game/clone() - var/datum/computer_file/program/game/G = ..() - G.picked_enemy_name = picked_enemy_name - return G +/datum/computer_file/program/game/PopulateClone(datum/computer_file/program/game/clone) + clone = ..() + clone.picked_enemy_name = picked_enemy_name + return clone // When running the program, we also want to pass our enemy name to the nano module. /datum/computer_file/program/game/on_startup() @@ -59,7 +59,7 @@ // ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client // to see, and don't send unnecessarily large amounts of data (due to laginess). -/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() data["player_health"] = player_health diff --git a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm index 19f07017774e..563791757bec 100644 --- a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm +++ b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm @@ -8,19 +8,25 @@ unsendable = 1 undeletable = 1 size = 4 - requires_network_feature = NETWORK_SOFTWAREDOWNLOAD + requires_network_feature = NET_FEATURE_SOFTWAREDOWNLOAD available_on_network = 0 nanomodule_path = /datum/nano_module/program/computer_appdownloader/ ui_header = "downloader_finished.gif" - var/hacked_download = 0 var/downloaderror var/list/downloads_queue[0] - var/server usage_flags = PROGRAM_ALL category = PROG_UTIL var/datum/file_transfer/current_transfer +/datum/computer_file/program/appdownloader/on_startup(mob/living/user, datum/extension/interactive/os/new_host) + . = ..() + // Initialize the internal "appdownload" disk if necessary. + var/datum/file_storage/network/app_download = new_host.mounted_storage["appdownload"] + if(!istype(app_download)) // If you had another network disk named appdownload it will be appropriated. + qdel(app_download) + new_host.mounted_storage["appdownload"] = new /datum/file_storage/network(new_host, "appdownload", TRUE) + /datum/computer_file/program/appdownloader/on_shutdown() ..() QDEL_NULL(current_transfer) @@ -33,16 +39,25 @@ var/datum/computer_network/net = computer.get_network() if(!net) return 0 - + if(!check_file_download(filename)) return 0 - var/datum/computer_file/program/PRG = net.find_file_by_name(filename, MF_ROLE_SOFTWARE) - var/datum/file_storage/disk/destination = new(computer) - var/datum/file_storage/network/source = new(computer) - source.server = net.find_file_location(filename, MF_ROLE_SOFTWARE) + var/datum/computer_file/program/PRG = net.find_file_by_name(filename, OS_PROGRAMS_DIR, MF_ROLE_SOFTWARE) + if(!istype(PRG)) + return 0 + var/datum/file_storage/disk/destination = computer.mounted_storage["local"] + if(!destination) + return 0 + var/datum/file_storage/network/source = computer.mounted_storage["appdownload"] + if(!source) + return 0 + var/datum/computer_file/directory/programs_directory = destination.parse_directory(OS_PROGRAMS_DIR, TRUE) + if(!programs_directory) + return 0 + source.set_server(net.find_file_location(PRG, mainframe_role = MF_ROLE_SOFTWARE)) if(source.check_errors() || destination.check_errors()) return 0 - current_transfer = new(source, destination, PRG) + current_transfer = new(source, destination, programs_directory, PRG, TRUE) ui_header = "downloader_running.gif" generate_network_log("Downloading file [filename] from [source.server].") @@ -52,12 +67,12 @@ var/datum/computer_network/net = computer.get_network() if(!net) return 0 - var/datum/computer_file/program/PRG = net.find_file_by_name(filename, MF_ROLE_SOFTWARE) + var/datum/computer_file/program/PRG = net.find_file_by_name(filename, OS_PROGRAMS_DIR, MF_ROLE_SOFTWARE) - if(!PRG || !istype(PRG)) + if(!istype(PRG)) return 0 - if(!computer || !computer.try_store_file(PRG)) + if(!computer || (computer.try_store_file(PRG, computer.programs_dir) != OS_FILE_SUCCESS)) return 0 return 1 @@ -71,17 +86,17 @@ /datum/computer_file/program/appdownloader/process_tick() if(!current_transfer) return - + var/result = current_transfer.update_progress() - if(!result) //something went wrong + if(result != OS_FILE_SUCCESS) //something went wrong if(QDELETED(current_transfer)) //either completely downloaderror = "I/O ERROR: Unknown error during the file transfer." else //or during the saving at the destination - downloaderror = "I/O ERROR: Unable to store '[current_transfer.copying.filename]' at [current_transfer.copying_to]" + downloaderror = "I/O ERROR: Unable to store '[current_transfer.transferring.filename]' at [current_transfer.transfer_to]" qdel(current_transfer) current_transfer = null ui_header = "downloader_finished.gif" - else if(!current_transfer.left_to_copy) //done + else if(!current_transfer.left_to_transfer) //done QDEL_NULL(current_transfer) ui_header = "downloader_finished.gif" if(!current_transfer && downloads_queue.len > 0) @@ -94,7 +109,7 @@ if(href_list["PRG_downloadfile"]) if(!current_transfer) begin_file_download(href_list["PRG_downloadfile"]) - else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && current_transfer.copying.filename != href_list["PRG_downloadfile"]) + else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && current_transfer.transferring.filename != href_list["PRG_downloadfile"]) downloads_queue |= href_list["PRG_downloadfile"] return 1 if(href_list["PRG_removequeued"]) @@ -108,7 +123,7 @@ /datum/nano_module/program/computer_appdownloader name = "Software Downloader" -/datum/nano_module/program/computer_appdownloader/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/computer_appdownloader/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = list() var/datum/computer_file/program/appdownloader/prog = program // For now limited to execution by the downloader program @@ -120,10 +135,10 @@ // This IF cuts on data transferred to client, so i guess it's worth it. if(prog.downloaderror) // Download errored. Wait until user resets the program. data["error"] = prog.downloaderror - if(prog.current_transfer) // Download running. Wait please.. + if(prog.current_transfer) // Download running. Wait please... data |= prog.current_transfer.get_ui_data() data["downloadspeed"] = prog.current_transfer.get_transfer_speed() - var/datum/computer_file/program/P = prog.current_transfer.copying + var/datum/computer_file/program/P = prog.current_transfer.transferring if(istype(P)) data["transfer_desc"] = P.extended_desc @@ -136,9 +151,9 @@ var/list/category_list[0] for(var/datum/computer_file/program/P in net.get_software_list(category)) // Only those programs our user can run will show in the list - if(!P.can_run(user) && P.requires_access_to_download) + if(!P.can_run(get_access(user), user, FALSE) && P.requires_access_to_download) continue - if(!P.is_supported_by_hardware(program.computer.get_hardware_flag(), user, TRUE)) + if(!P.is_supported_by_hardware(program.computer.get_hardware_flag(), user, FALSE)) continue category_list.Add(list(list( "filename" = P.filename, diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm index 1d5b9ed4f6fe..5c2f94903352 100644 --- a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm @@ -6,7 +6,7 @@ program_menu_icon = "comment" extended_desc = "This program allows communication over the local network" size = 8 - requires_network_feature = NETWORK_COMMUNICATION + requires_network_feature = NET_FEATURE_COMMUNICATION network_destination = "chat server" ui_header = "ntnrc_idle.gif" available_on_network = 1 @@ -70,7 +70,7 @@ if(href_list["PRG_newchannel"]) . = 1 var/mob/living/user = usr - var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64) + var/channel_title = sanitize_safe(input(user,"Enter channel name or leave blank to cancel:"), 64) if(!channel_title) return var/datum/chat_conversation/C = new/datum/chat_conversation(network) @@ -87,7 +87,7 @@ channel = null return 1 var/mob/living/user = usr - if(can_run(usr, 1, access_network)) + if(has_access(list(access_network), usr.GetAccess())) if(channel) var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No") if(response == "Yes") @@ -123,7 +123,7 @@ logfile.stored_data += "[logstring]\[BR\]" logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]" logfile.calculate_size() - if(!computer.store_file(logfile)) + if(!computer.store_file(logfile, OS_LOGS_DIR, create_directories = TRUE)) computer.show_error(user, "I/O Error - Check hard drive and free space. Required space: [logfile.size]GQ.") if(href_list["PRG_renamechannel"]) . = 1 @@ -134,7 +134,7 @@ if(!newname || !channel) return channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") - channel.title = newname + channel.change_title(newname, src) if(href_list["PRG_deletechannel"]) . = 1 if(channel && ((channel.operator == src) || netadmin_mode)) @@ -186,8 +186,8 @@ /datum/nano_module/program/computer_chatclient name = "Intranet Relay Chat Client" -/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) - var/datum/computer_network/network = program.computer.get_network() +/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + var/datum/computer_network/network = program?.computer?.get_network() if(!network || !network.chat_channels) return diff --git a/code/modules/modular_computers/file_system/programs/generic/records.dm b/code/modules/modular_computers/file_system/programs/generic/records.dm index f59d68f170fd..0305f32e421a 100644 --- a/code/modules/modular_computers/file_system/programs/generic/records.dm +++ b/code/modules/modular_computers/file_system/programs/generic/records.dm @@ -6,6 +6,8 @@ program_key_state = "generic_key" size = 14 available_on_network = 1 + requires_network = 1 + requires_network_feature = NET_FEATURE_RECORDS nanomodule_path = /datum/nano_module/program/records usage_flags = PROGRAM_ALL category = PROG_OFFICE @@ -15,7 +17,7 @@ var/datum/computer_file/report/crew_record/active_record var/message = null -/datum/nano_module/program/records/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) +/datum/nano_module/program/records/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() var/list/user_access = get_record_access(user) @@ -24,11 +26,11 @@ send_rsc(user, active_record.photo_front, "front_[active_record.uid].png") send_rsc(user, active_record.photo_side, "side_[active_record.uid].png") data["pic_edit"] = check_access(user, access_bridge) || check_access(user, access_security) - data += active_record.generate_nano_data(user_access) + data += active_record.generate_nano_data(user_access, user) else var/list/all_records = list() - - data["show_milrank"] = (GLOB.using_map.flags & MAP_HAS_BRANCH) + var/list/searchable_names = list() + data["show_milrank"] = (global.using_map.flags & MAP_HAS_BRANCH) for(var/datum/computer_file/report/crew_record/R in get_records()) all_records.Add(list(list( "name" = R.get_name(), @@ -36,10 +38,9 @@ "milrank" = R.get_rank(), "id" = R.uid ))) + searchable_names |= R.searchable_fields data["all_records"] = all_records - data["creation"] = check_access(user, access_bridge) - data["dnasearch"] = check_access(user, access_medical) || check_access(user, access_forensics_lockers) - data["fingersearch"] = check_access(user, access_security) + data["searchable"] = searchable_names ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -50,13 +51,13 @@ /datum/nano_module/program/records/proc/get_record_access(var/mob/user) - var/list/user_access = using_access || user.GetAccess() + var/list/user_access = get_access(user) var/obj/PC = nano_host() - var/datum/extension/interactive/ntos/os = get_extension(PC, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(PC, /datum/extension/interactive/os) if(os && os.emagged()) user_access = user_access ? user_access.Copy() : list() - user_access |= access_syndicate + user_access |= access_hacked return user_access @@ -67,7 +68,7 @@ var/datum/report_field/F = R.field_from_ID(field_ID) if(!F) return - if(!F.verify_access_edit(get_record_access(user))) + if(!(F.get_perms(get_access(user),user) & OS_WRITE_ACCESS)) to_chat(user, "\The [nano_host()] flashes an \"Access Denied\" warning.") return F.ask_value(user) @@ -85,7 +86,10 @@ var/ID = text2num(href_list["set_active"]) for(var/datum/computer_file/report/crew_record/R in get_records()) if(R.uid == ID) - active_record = R + if(R.get_file_perms(get_access(usr), usr) & OS_READ_ACCESS) + active_record = R + else + to_chat(usr, SPAN_WARNING("Access denied.")) break return 1 if(href_list["new_record"]) @@ -93,12 +97,17 @@ if(!network) to_chat(usr, SPAN_WARNING("Network error.")) return - if(!check_access(usr, access_bridge)) - to_chat(usr, "Access Denied.") + var/list/accesses = get_access(usr) + if(!network.get_mainframes_by_role(MF_ROLE_CREW_RECORDS, accesses)) + to_chat(usr, SPAN_WARNING("You may not have access to generate new crew records, or there may not be a crew record mainframe active on the network.")) return active_record = new/datum/computer_file/report/crew_record() - GLOB.all_crew_records.Add(active_record) - network.store_file(active_record, MF_ROLE_CREW_RECORDS) + if(network.store_file(active_record, OS_RECORDS_DIR, TRUE, accesses, usr, mainframe_role = MF_ROLE_CREW_RECORDS) != OS_FILE_SUCCESS) + to_chat(usr, SPAN_WARNING("Unable to store new crew record. The file server may be non-functional or out of disk space.")) + qdel(active_record) + active_record = null + return + global.all_crew_records.Add(active_record) return 1 if(href_list["print_active"]) if(!active_record) @@ -115,11 +124,17 @@ if(!search) return for(var/datum/computer_file/report/crew_record/R in get_records()) + if(!(R.get_file_perms(get_access(usr), usr) & OS_READ_ACCESS)) + continue var/datum/report_field/field = R.field_from_name(field_name) + if(!field.searchable) + continue + if(!(field.get_perms(get_access(usr), usr) & OS_READ_ACCESS)) + continue if(findtext(lowertext(field.get_value()), lowertext(search))) active_record = R return 1 - message = "Unable to find record containing '[search]'" + message = "Unable to find record containing '[search]'. You may lack access to search for this." return 1 var/datum/computer_file/report/crew_record/R = active_record @@ -144,11 +159,11 @@ return 1 /datum/nano_module/program/records/proc/get_photo(var/mob/user) - if(istype(user.get_active_hand(), /obj/item/photo)) - var/obj/item/photo/photo = user.get_active_hand() + if(istype(user.get_active_held_item(), /obj/item/photo)) + var/obj/item/photo/photo = user.get_active_held_item() return photo.img - if(istype(user, /mob/living/silicon)) - var/mob/living/silicon/tempAI = usr + if(issilicon(user)) + var/mob/living/silicon/tempAI = user var/obj/item/photo/selection = tempAI.GetPicture() if (selection) return selection.img diff --git a/code/modules/modular_computers/file_system/programs/generic/reports.dm b/code/modules/modular_computers/file_system/programs/generic/reports.dm index 7ea3ff8b51b6..a88753fdd88f 100644 --- a/code/modules/modular_computers/file_system/programs/generic/reports.dm +++ b/code/modules/modular_computers/file_system/programs/generic/reports.dm @@ -18,13 +18,13 @@ var/datum/computer_file/report/saved_report //The computer file open. var/prog_state = REPORTS_VIEW -/datum/nano_module/program/reports/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) +/datum/nano_module/program/reports/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() data["prog_state"] = prog_state switch(prog_state) if(REPORTS_VIEW) if(selected_report) - data["report_data"] = selected_report.generate_nano_data(get_access(user)) + data["report_data"] = selected_report.generate_nano_data(get_access(user), user) data["view_only"] = can_view_only data["printer"] = program.computer.has_component(PART_PRINTER) if(REPORTS_DOWNLOAD) @@ -54,7 +54,7 @@ prog_state = REPORTS_VIEW if(REPORTS_DOWNLOAD) close_report() - program.requires_network_feature = NETWORK_SOFTWAREDOWNLOAD + program.requires_network_feature = NET_FEATURE_SOFTWAREDOWNLOAD prog_state = REPORTS_DOWNLOAD /datum/nano_module/program/reports/proc/close_report() @@ -65,11 +65,12 @@ if(!program.computer || !program.computer.has_component(PART_HDD)) to_chat(user, "Unable to find hard drive.") return - selected_report.rename_file() + if(save_as) // We're copying, so don't overwrite the actual report. + selected_report.rename_file() if(program.computer.store_file(selected_report)) saved_report = selected_report - selected_report = saved_report.clone() - to_chat(user, "The report has been saved as [saved_report.filename].[saved_report.filetype]") + selected_report = saved_report.Clone() + to_chat(user, "The report has been saved as '[saved_report.filename].[saved_report.filetype]'.") else to_chat(user, "Error storing file. Please check your hard drive.") @@ -85,17 +86,17 @@ var/datum/computer_file/report/chosen_report = choices[choice] var/editing = alert(user, "Would you like to view or edit the report", "Loading Report", "View", "Edit") if(editing == "View") - if(!chosen_report.verify_access(get_access(user))) + if(!(chosen_report.get_file_perms(get_access(user), user) & OS_READ_ACCESS)) to_chat(user, "You lack access to view this report.") return can_view_only = 1 else - if(!chosen_report.verify_access_edit(get_access(user))) + if(!(chosen_report.get_file_perms(get_access(user), user) & OS_WRITE_ACCESS)) to_chat(user, "You lack access to edit this report.") return can_view_only = 0 saved_report = chosen_report - selected_report = chosen_report.clone() + selected_report = chosen_report.Clone() return 1 /datum/nano_module/program/reports/Topic(href, href_list) @@ -115,16 +116,17 @@ if(href_list["save"]) if(!selected_report) return 1 - if(!selected_report.verify_access(get_access(user))) - return 1 var/save_as = text2num(href_list["save_as"]) + var/req_access = save_as ? OS_READ_ACCESS : OS_WRITE_ACCESS + if(!(selected_report.get_file_perms(get_access(user), user) & req_access)) + return 1 save_report(user, save_as) if(href_list["submit"]) if(!selected_report) return 1 - if(!selected_report.verify_access_edit(get_access(user))) + if(!(selected_report.get_file_perms(get_access(user), user) & OS_WRITE_ACCESS)) return 1 - if(selected_report.submit(user)) + if(selected_report.submit(user, get_access(user))) to_chat(user, "The [src] has been submitted.") if(alert(user, "Would you like to save a copy?","Save Report", "Yes.", "No.") == "Yes.") save_report(user) @@ -139,27 +141,27 @@ return 1 var/field_ID = text2num(href_list["ID"]) var/datum/report_field/field = selected_report.field_from_ID(field_ID) - if(!field || !field.verify_access_edit(get_access(user))) + if(!field || !(field.get_perms(get_access(user), user) & OS_WRITE_ACCESS)) return 1 field.ask_value(user) //Handles the remaining IO. return 1 if(href_list["print"]) - if(!selected_report || !selected_report.verify_access(get_access(user))) + if(!selected_report || !(selected_report.get_file_perms(get_access(user), user) & OS_READ_ACCESS)) return 1 var/with_fields = text2num(href_list["print_mode"]) - var/text = selected_report.generate_pencode(get_access(user), with_fields) + var/text = selected_report.generate_pencode(get_access(user), user, with_fields) if(!program.computer.print_paper(text, selected_report.display_name())) to_chat(user, "Hardware error: Printer was unable to print the file. It may be out of paper.") return 1 if(href_list["export"]) - if(!selected_report || !selected_report.verify_access(get_access(user))) + if(!selected_report || !(selected_report.get_file_perms(get_access(user), user) & OS_READ_ACCESS)) return 1 var/datum/computer_file/data/text/file = new selected_report.rename_file() - file.stored_data = selected_report.generate_pencode(get_access(user), no_html = 1) //TXT files can't have html; they use pencode only. + file.stored_data = selected_report.generate_pencode(get_access(user), user, no_html = 1) //TXT files can't have html; they use pencode only. file.filename = selected_report.filename - if(program.computer.store_file(file)) - to_chat(user, "The report has been exported as [file.filename].[file.filetype]") + if(program.computer.store_file(file, "reports", create_directories = TRUE)) + to_chat(user, "The report has been exported as '[file.filename].[file.filetype]'.") else to_chat(user, "Error storing file. Please check your hard drive.") return 1 @@ -170,9 +172,9 @@ if(href_list["get_report"]) var/uid = text2num(href_list["report"]) var/datum/computer_network/net = program.computer.get_network() - for(var/datum/computer_file/report/report in net.fetch_reports(get_access(user))) + for(var/datum/computer_file/report/report in net.fetch_reports(get_access(user), user)) if(report.uid == uid) - selected_report = report.clone() + selected_report = report.Clone() can_view_only = 0 switch_state(REPORTS_VIEW) return 1 diff --git a/code/modules/modular_computers/file_system/programs/generic/scanner.dm b/code/modules/modular_computers/file_system/programs/generic/scanner.dm index 3cc337ade30b..d91dd8e617c2 100644 --- a/code/modules/modular_computers/file_system/programs/generic/scanner.dm +++ b/code/modules/modular_computers/file_system/programs/generic/scanner.dm @@ -7,10 +7,10 @@ size = 6 available_on_network = 1 usage_flags = PROGRAM_ALL - nanomodule_path = /datum/nano_module/program/scanner category = PROG_UTIL + nanomodule_path = /datum/nano_module/program/scanner - var/using_scanner = 0 //Whether or not the program is synched with the scanner module. + var/using_scanner = 0 //Whether or not the program is synced with the scanner module. var/data_buffer = "" //Buffers scan output for saving/viewing. var/scan_file_type = /datum/computer_file/data/text //The type of file the data will be saved to. var/list/metadata_buffer = list() @@ -36,13 +36,6 @@ metadata_buffer.Cut() return 1 -/datum/computer_file/program/scanner/proc/save_scan(name) - if(!data_buffer) - return 0 - if(!create_file(name, data_buffer, scan_file_type, metadata_buffer.Copy())) - return 0 - return 1 - /datum/computer_file/program/scanner/proc/check_scanning() if(!computer) return 0 @@ -61,7 +54,7 @@ /datum/computer_file/program/scanner/Topic(href, href_list) if(..()) - return 1 + return TOPIC_HANDLED if(href_list["connect_scanner"]) if(text2num(href_list["connect_scanner"])) @@ -69,27 +62,32 @@ to_chat(usr, "Scanner installation failed.") else disconnect_scanner() - return 1 + return TOPIC_REFRESH if(href_list["scan"]) if(check_scanning()) metadata_buffer.Cut() var/obj/item/stock_parts/computer/scanner/scanner = computer.get_component(PART_SCANNER) scanner.run_scan(usr, src) - return 1 + return TOPIC_REFRESH if(href_list["save"]) - var/name = sanitize(input(usr, "Enter file name:", "Save As") as text|null) - if(!save_scan(name)) - to_chat(usr, "Scan save failed.") + if(!data_buffer) + to_chat(usr, SPAN_WARNING("No data to export!")) + return TOPIC_HANDLED + + var/datum/computer_file/data/scan_file = new scan_file_type() + scan_file.stored_data = data_buffer + scan_file.metadata = metadata_buffer - if(.) - SSnano.update_uis(NM) + // This saves the file, so no additional handling on the program's end is required. + view_file_browser(usr, "saving_file", scan_file_type, OS_WRITE_ACCESS, "Save scan file", scan_file) + return TOPIC_HANDLED /datum/nano_module/program/scanner name = "Scanner" -/datum/nano_module/program/scanner/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/scanner/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/datum/computer_file/program/scanner/prog = program if(!prog.computer) diff --git a/code/modules/modular_computers/file_system/programs/generic/supply.dm b/code/modules/modular_computers/file_system/programs/generic/supply.dm index 45034ce1f484..bae0aa67c9dd 100644 --- a/code/modules/modular_computers/file_system/programs/generic/supply.dm +++ b/code/modules/modular_computers/file_system/programs/generic/supply.dm @@ -13,6 +13,8 @@ extended_desc = "A management tool that allows for ordering of various supplies through the facility's cargo system. Some features may require additional access." size = 21 available_on_network = 1 + requires_network = 1 + requires_network_feature = NET_FEATURE_DECK category = PROG_SUPPLY /datum/computer_file/program/supply/is_supported_by_hardware(var/hardware_flag, var/mob/user, var/loud = FALSE) @@ -25,7 +27,7 @@ computer.show_error(user, "Unable to contact the supply shuttle.") return FALSE var/obj/physical_router = net.router.holder - if(!ARE_Z_CONNECTED(shuttle.waypoint_station.z, physical_router.z)) + if(!LEVELS_ARE_Z_CONNECTED(shuttle.waypoint_station.z, physical_router.z)) if(loud) computer.show_error(user, "Unable to contact a supply shuttle serving your location.") return FALSE @@ -59,10 +61,10 @@ var/notifications_enabled = FALSE var/admin_access = list(access_cargo, access_mailsorting) -/datum/nano_module/supply/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) +/datum/nano_module/supply/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = global.default_topic_state) var/list/data = host.initial_data() var/is_admin = check_access(user, admin_access) - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) if(!LAZYLEN(category_names) || !LAZYLEN(category_contents) || current_security_level != security_state.current_security_level || emagged_memory != emagged ) generate_categories() current_security_level = security_state.current_security_level @@ -75,7 +77,7 @@ data["screen"] = screen data["credits"] = "[SSsupply.points]" - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) data["currency"] = cur.name switch(screen) @@ -100,13 +102,15 @@ if(3)// Shuttle monitoring and control var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle - data["shuttle_name"] = shuttle.name if(istype(shuttle)) - data["shuttle_location"] = shuttle.at_station() ? GLOB.using_map.name : "Remote location" + data["shuttle_name"] = shuttle.name + data["shuttle_location"] = shuttle.at_station() ? global.using_map.name : "Remote location" + data["shuttle_can_control"] = shuttle.can_launch() else - data["shuttle_location"] = "No Connection" + data["shuttle_name"] = "No Connection" + data["shuttle_location"] = "No Connection" + data["shuttle_can_control"] = FALSE data["shuttle_status"] = get_shuttle_status() - data["shuttle_can_control"] = shuttle.can_launch() if(4)// Order processing if(is_admin) // No bother sending all of this if the user can't see it. @@ -123,7 +127,7 @@ data["requests"] = requests data["done"] = done data["can_print"] = can_print() - data["is_NTOS"] = istype(nano_host(), /obj/item/modular_computer) // Can we even use notifications? + data["is_OS"] = istype(nano_host(), /obj/item/modular_computer) // Can we even use notifications? data["notifications_enabled"] = notifications_enabled ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -162,11 +166,11 @@ if(href_list["order"]) clear_order_contents() - var/decl/hierarchy/supply_pack/P = locate(href_list["order"]) in SSsupply.master_supply_list - if(!istype(P)) + var/decl/hierarchy/supply_pack/pack = locate(href_list["order"]) in SSsupply.master_supply_list + if(!istype(pack)) return 1 - if(P.hidden && !emagged) + if(pack.hidden && !emagged) return 1 var/reason = sanitize(input(user,"Reason:","Why do you require this item?","") as null|text,,0) @@ -176,7 +180,7 @@ var/idname = "*None Provided*" var/idrank = "*None Provided*" if(ishuman(user)) - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user idname = H.get_authentification_name() idrank = H.get_assignment() else if(issilicon(user)) @@ -186,7 +190,7 @@ var/datum/supply_order/O = new /datum/supply_order() O.ordernum = SSsupply.ordernum - O.object = P + O.object = pack O.orderedby = idname O.reason = reason O.orderedrank = idrank @@ -224,7 +228,6 @@ var/datum/signal/status_signal = new status_signal.source = src - status_signal.transmission_method = 1 status_signal.data["command"] = "supply" frequency.post_signal(src, status_signal) return 1 @@ -310,33 +313,34 @@ /datum/nano_module/supply/proc/generate_categories() category_names.Cut() category_contents.Cut() - var/decl/hierarchy/supply_pack/root = decls_repository.get_decl(/decl/hierarchy/supply_pack) - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) - for(var/decl/hierarchy/supply_pack/sp in root.children) - if(!sp.is_category()) + var/decl/hierarchy/supply_pack/root = GET_DECL(/decl/hierarchy/supply_pack) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) + // FIXME: This probably doesn't even work properly? It assumes there aren't any nested categories... + for(var/decl/hierarchy/supply_pack/pack in root.children) + if(!pack.is_category()) continue // No children - category_names.Add(sp.name) + category_names.Add(pack.name) var/list/category[0] - for(var/decl/hierarchy/supply_pack/spc in sp.get_descendents()) - if((spc.hidden || spc.contraband || !spc.sec_available()) && !emagged) + for(var/decl/hierarchy/supply_pack/child_pack in pack.get_descendants()) + if((child_pack.hidden || child_pack.contraband || !child_pack.sec_available()) && !emagged) continue category.Add(list(list( - "name" = spc.name, - "cost" = cur.format_value(spc.cost), - "ref" = "\ref[spc]" + "name" = child_pack.name, + "cost" = cur.format_value(child_pack.cost), + "ref" = "\ref[child_pack]" ))) - category_contents[sp.name] = category + category_contents[pack.name] = category /datum/nano_module/supply/proc/generate_order_contents(var/order_ref) - var/decl/hierarchy/supply_pack/sp = locate(order_ref) in SSsupply.master_supply_list - if(!istype(sp)) + var/decl/hierarchy/supply_pack/pack = locate(order_ref) in SSsupply.master_supply_list + if(!istype(pack)) return FALSE contents_of_order.Cut() showing_contents_of_ref = order_ref - for(var/item_path in sp.contains) // Thanks to Lohikar for helping me with type paths - CarlenWhite + for(var/item_path in pack.contains) // Thanks to Lohikar for helping me with type paths - CarlenWhite var/obj/item/stack/OB = item_path // Not always a stack, but will always have a name we can fetch. var/name = initial(OB.name) - var/amount = sp.contains[item_path] || 1 // If it's just one item (has no number associated), fallback to 1. + var/amount = pack.contains[item_path] || 1 // If it's just one item (has no number associated), fallback to 1. if(ispath(item_path, /obj/item/stack)) // And if it is a stack, consider the amount amount *= initial(OB.amount) @@ -346,9 +350,9 @@ "amount" = amount ))) - if(sp.contains.len == 0) // Handles the case where sp.contains is empty, e.g. for livecargo + if(!length(pack.contains)) // Handles the case where pack.contains is empty, e.g. for livecargo contents_of_order.Add(list(list( - "name" = sp.containername, + "name" = pack.containername, "amount" = 1 ))) @@ -365,7 +369,7 @@ return "No Connection" if(shuttle.has_arrive_time()) - return "In transit ([shuttle.eta_seconds()] s)" + return "In transit ([shuttle.eta_readable()])" if (shuttle.can_launch()) return "Docked" @@ -382,7 +386,7 @@ )) /datum/nano_module/supply/proc/can_print() - var/datum/extension/interactive/ntos/os = get_extension(nano_host(), /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(nano_host(), /datum/extension/interactive/os) if(os) return os.has_component(PART_PRINTER) return 0 @@ -392,10 +396,10 @@ return var/t = "" - t += "

    [GLOB.using_map.station_name] Supply Requisition Reciept


    " + t += "

    [global.using_map.station_name] Supply Requisition Receipt


    " t += "INDEX: #[O.ordernum]
    " t += "REQUESTED BY: [O.orderedby]
    " - t += "RANK: [O.orderedrank]
    " + t += "ASSIGNMENT: [O.orderedrank]
    " t += "REASON: [O.reason]
    " t += "SUPPLY CRATE TYPE: [O.object.name]
    " t += "ACCESS RESTRICTION: [get_access_desc(O.object.access)]
    " @@ -406,7 +410,7 @@ /datum/nano_module/supply/proc/print_summary(var/mob/user) var/t = "" - t += "

    [GLOB.using_map.station_name]
    [station_date]
    Export overview

    " + t += "

    [global.using_map.station_name]
    [station_date]
    Export overview

    " for(var/source in SSsupply.point_source_descriptions) t += "[SSsupply.point_source_descriptions[source]]: [SSsupply.point_sources[source] || 0]
    " print_text(t, user) diff --git a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm index d5e5fc6f202e..0bc33f0a6017 100644 --- a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm +++ b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm @@ -6,158 +6,156 @@ program_key_state = "atmos_key" size = 4 available_on_network = 1 - nanomodule_path = /datum/nano_module/program/computer_wordprocessor/ - var/browsing - var/open_file + + usage_flags = PROGRAM_ALL + category = PROG_OFFICE + + var/open_file // Name of the file currently open. + var/file_directory // Directory of the file currently open. + var/loaded_data var/error var/is_edited - usage_flags = PROGRAM_ALL - category = PROG_OFFICE -/datum/computer_file/program/wordprocessor/proc/open_file(var/filename) - var/datum/computer_file/data/F = get_file(filename) - if(F) - open_file = F.filename - loaded_data = F.stored_data - return 1 +/datum/computer_file/program/wordprocessor/on_shutdown(forced) + . = ..() + open_file = null + file_directory = null + loaded_data = null + error = null + is_edited = FALSE + +/datum/computer_file/program/wordprocessor/on_file_select(datum/file_storage/disk, datum/computer_file/directory/dir, datum/computer_file/selected, selecting_key, mob/user) + var/datum/computer_file/data/text/T = selected + loaded_data = T.stored_data + open_file = T.filename + file_directory = disk.get_dir_path(dir, TRUE) + is_edited = FALSE + . = ..() + +/datum/computer_file/program/wordprocessor/proc/save_file(mob/user) + var/datum/computer_file/result = computer.save_file(open_file, file_directory, loaded_data, /datum/computer_file/data/text, null, computer.get_access(user), user) + . = FALSE + if(istype(result)) + to_chat(user, SPAN_NOTICE("Successfully saved file '[open_file]'.")) + is_edited = FALSE + return TRUE + // Errored! + switch(result) + if(OS_BAD_NAME) + error = "I/O error: Invalid file name '[open_file]'." + if(OS_FILE_NOT_FOUND) + error = "I/O error: Directory not found." + if(OS_FILE_NO_WRITE) + error = "I/O error: You do not have permission to modify file '[open_file]'" + else + error = "I/O error: Harddrive may be non-functional." -/datum/computer_file/program/wordprocessor/proc/save_file(var/filename) - . = computer.save_file(filename, loaded_data, /datum/computer_file/data/text) - if(.) - is_edited = 0 +#define MAX_FIELDS_NUM 50 /datum/computer_file/program/wordprocessor/Topic(href, href_list) if(..()) return 1 - if(href_list["PRG_txtrpeview"]) + if(href_list["PRG_txtpreview"]) show_browser(usr,"[open_file][digitalPencode2html(loaded_data)]", "window=[open_file]") - return 1 + return TOPIC_HANDLED if(href_list["PRG_taghelp"]) var/datum/codex_entry/entry = SScodex.get_codex_entry("pen") if(entry) SScodex.present_codex_entry(usr, entry) - return 1 - - if(href_list["PRG_closebrowser"]) - browsing = 0 - return 1 + return TOPIC_HANDLED if(href_list["PRG_backtomenu"]) error = null - return 1 - - if(href_list["PRG_loadmenu"]) - browsing = 1 - return 1 + return TOPIC_REFRESH if(href_list["PRG_openfile"]) - . = 1 if(is_edited) if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") - save_file(open_file) - browsing = 0 - if(!open_file(href_list["PRG_openfile"])) - error = "I/O error: Unable to open file '[href_list["PRG_openfile"]]'." + if(!save_file(usr)) + return TOPIC_HANDLED + var/browser_desc = "Select a file to open" + view_file_browser(usr, "open_file", /datum/computer_file/data/text, OS_READ_ACCESS, browser_desc) + return TOPIC_HANDLED if(href_list["PRG_newfile"]) - . = 1 if(is_edited) if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") - save_file(open_file) - - var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null) - if(!newname) - return 1 - var/datum/computer_file/data/F = create_file(newname, "", /datum/computer_file/data/text) - if(F) - open_file = F.filename - loaded_data = "" - return 1 - else - error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." + if(!save_file(usr)) + return TOPIC_HANDLED + + var/browser_desc = "Create new file" + var/datum/computer_file/data/text/saving = new() + view_file_browser(usr, "create_file", /datum/computer_file/data/text, OS_WRITE_ACCESS, browser_desc, saving) + return TOPIC_HANDLED if(href_list["PRG_saveasfile"]) - . = 1 - var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null) - if(!newname) - return 1 - var/datum/computer_file/data/F = create_file(newname, loaded_data, /datum/computer_file/data/text) - if(F) - open_file = F.filename - else - error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." - return 1 + var/browser_desc = "Save file as" + var/datum/computer_file/data/text/saving = new() + saving.filename = open_file ? open_file : "NewFile" + saving.stored_data = loaded_data + view_file_browser(usr, "saveas_file", /datum/computer_file/data/text, OS_WRITE_ACCESS, browser_desc, saving) + return TOPIC_HANDLED if(href_list["PRG_savefile"]) - . = 1 if(!open_file) - open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null) - if(!open_file) - return 0 - if(!save_file(open_file)) - error = "I/O error: Unable to save file '[open_file]'." - return 1 + var/browser_desc = "Save file as" + var/datum/computer_file/data/text/saving = new() + saving.stored_data = loaded_data + view_file_browser(usr, "saveas_file", /datum/computer_file/data/text, OS_WRITE_ACCESS, browser_desc, saving) + return TOPIC_HANDLED + + save_file(usr) + return TOPIC_REFRESH if(href_list["PRG_editfile"]) var/oldtext = html_decode(loaded_data) oldtext = replacetext(oldtext, "\[br\]", "\n") - + if(open_file) + var/datum/computer_file/data/F = get_file(open_file, file_directory, computer.get_access(usr), usr) + if(istype(F) && !(F.get_file_perms(computer.get_access(usr), usr) & OS_WRITE_ACCESS)) + error = "I/O error: You do not have permission to edit this file." + return TOPIC_REFRESH var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) if(!newtext) return + + //Count the fields + var/fields = 0 + var/regex/re = regex(@"\[field\]","g") + while(re.Find(newtext)) + fields++ + + if(fields > MAX_FIELDS_NUM) + to_chat(usr, SPAN_WARNING("Too many fields. Sorry, you can't do this.")) + return + loaded_data = newtext is_edited = 1 - return 1 + return TOPIC_REFRESH if(href_list["PRG_printfile"]) - . = 1 if(!computer.print_paper(digitalPencode2html(loaded_data))) error = "Hardware error: Printer missing or out of paper." - return 1 - -/datum/nano_module/program/computer_wordprocessor - name = "Word Processor" - -/datum/nano_module/program/computer_wordprocessor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) - var/list/data = host.initial_data() - var/datum/computer_file/program/wordprocessor/PRG - PRG = program - - if(PRG.error) - data["error"] = PRG.error - if(PRG.browsing) - data["browsing"] = PRG.browsing - if(!PRG.computer || !PRG.computer.has_component(PART_HDD)) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - var/list/files[0] - for(var/datum/computer_file/F in PRG.computer.get_all_files()) - if(F.filetype == "TXT") - files.Add(list(list( - "name" = F.filename, - "size" = F.size - ))) - data["files"] = files - - var/obj/item/stock_parts/computer/drive_slot/RHDD = PRG.computer.get_component(PART_D_SLOT) - if(istype(RHDD) && istype(RHDD.stored_drive)) - data["usbconnected"] = 1 - var/list/usbfiles[0] - for(var/datum/computer_file/F in PRG.computer.get_all_files(RHDD.stored_drive)) - if(F.filetype == "TXT") - usbfiles.Add(list(list( - "name" = F.filename, - "size" = F.size, - ))) - data["usbfiles"] = usbfiles - else if(PRG.open_file) - data["filedata"] = digitalPencode2html(PRG.loaded_data) - data["filename"] = PRG.is_edited ? "[PRG.open_file]*" : PRG.open_file + return TOPIC_HANDLED + +#undef MAX_FIELDS_NUM + +/datum/computer_file/program/wordprocessor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + . = ..() + if(!.) + return + var/list/data = computer.initial_data() + + if(error) + data["error"] = error + if(open_file) + data["filedata"] = digitalPencode2html(loaded_data) + data["filename"] = is_edited ? "[open_file]*" : open_file else - data["filedata"] = digitalPencode2html(PRG.loaded_data) + data["filedata"] = digitalPencode2html(loaded_data) data["filename"] = "UNNAMED" ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -165,4 +163,4 @@ ui = new(user, src, ui_key, "word_processor.tmpl", "Word Processor", 575, 700, state = state) ui.auto_update_layout = 1 ui.set_initial_data(data) - ui.open() \ No newline at end of file + ui.open() diff --git a/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm b/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm index 9518d2c535b2..21839f9d5d57 100644 --- a/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm +++ b/code/modules/modular_computers/file_system/programs/medical/suit_sensors.dm @@ -7,7 +7,9 @@ program_key_state = "med_key" program_menu_icon = "heart" extended_desc = "This program connects to life signs monitoring system to provide basic information on crew health." - required_access = access_medical + read_access = list(access_medical) + requires_network = 1 + requires_network_feature = NET_FEATURE_SECURITY network_destination = "crew lifesigns monitoring system" size = 11 category = PROG_MONITOR @@ -35,7 +37,7 @@ var/datum/computer_network/network = get_network() if(!network) return FALSE - for(var/z_level in GetConnectedZlevels(network.get_router_z())) + for(var/z_level in SSmapping.get_connected_levels(network.get_router_z())) if (crew_repository.has_health_alert(z_level)) return TRUE return FALSE @@ -46,20 +48,24 @@ if(href_list["track"]) if(isAI(usr)) var/mob/living/silicon/ai/AI = usr - var/mob/living/carbon/human/H = locate(href_list["track"]) in SSmobs.mob_list - if(hassensorlevel(H, SUIT_SENSOR_TRACKING)) + var/mob/living/human/H = locate(href_list["track"]) in SSmobs.mob_list + if(hassensorlevel(H, VITALS_SENSOR_TRACKING)) AI.ai_actual_track(H) return 1 -/datum/nano_module/program/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) - var/list/data = host.initial_data() +/datum/nano_module/program/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + var/list/data = host.initial_data() data["isAI"] = isAI(user) - data["crewmembers"] = list() + + var/list/crewmembers = list() var/datum/computer_network/network = get_network() if(network) - for(var/z_level in GetConnectedZlevels(network.get_router_z())) - data["crewmembers"] += crew_repository.health_data(z_level) + for(var/z_level in SSmapping.get_connected_levels(network.get_router_z())) + crewmembers += crew_repository.health_data(z_level) + data["crewmembers"] = sortTim(crewmembers, /proc/cmp_list_name_key_asc) + else + data["crewmembers"] = list() ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) diff --git a/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm b/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm index f8477812c32c..a1b613ac1ced 100644 --- a/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm +++ b/code/modules/modular_computers/file_system/programs/research/ai_restorer.dm @@ -4,9 +4,9 @@ program_icon_state = "generic" program_key_state = "mining_key" program_menu_icon = "person" - extended_desc = "This program is capable of reconstructing damaged AI systems. It can also be used to upload basic laws to the AI. Requires direct AI connection via inteliCard slot." + extended_desc = "This program is capable of reconstructing damaged AI systems. It can also be used to upload basic laws to the AI. Requires direct AI connection via intelliCard slot." size = 12 - required_access = access_bridge + read_access = list(access_bridge) requires_access_to_run = 0 available_on_network = 1 nanomodule_path = /datum/nano_module/program/computer_aidiag/ @@ -29,7 +29,7 @@ if(!A) return 0 if(href_list["PRG_beginReconstruction"]) - if((A.hardware_integrity() < 100) || (A.backup_capacitor() < 100)) + if((A.get_health_percent() < 100) || (A.backup_capacitor() < 100)) restoring = 1 return 1 @@ -49,13 +49,13 @@ to_chat(A, "Non-core laws reset.") return 1 if(href_list["PRG_uploadDefault"]) - A.laws = new GLOB.using_map.default_law_type + A.laws = new global.using_map.default_law_type to_chat(A, "All laws purged. Default lawset uploaded.") return 1 if(href_list["PRG_addCustomSuppliedLaw"]) var/law_to_add = sanitize(input("Please enter a new law for the AI.", "Custom Law Entry")) var/sector = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)") as num - sector = between(MIN_SUPPLIED_LAW_NUMBER, sector, MAX_SUPPLIED_LAW_NUMBER) + sector = clamp(MIN_SUPPLIED_LAW_NUMBER, sector, MAX_SUPPLIED_LAW_NUMBER) A.add_supplied_law(sector, law_to_add) to_chat(A, "Custom law uploaded to sector [sector]: [law_to_add].") return 1 @@ -66,14 +66,13 @@ if(!A || !restoring) restoring = 0 // If the AI was removed, stop the restoration sequence. return - A.adjustFireLoss(-4) - A.adjustBruteLoss(-4) - A.adjustOxyLoss(-4) - A.updatehealth() + A.heal_damage(BURN, 4, do_update_health = FALSE) + A.heal_damage(BRUTE, 4, do_update_health = FALSE) + A.heal_damage(OXY, 4) + A.update_health() // If the AI is dead, revive it. - if (A.health >= -100 && A.stat == DEAD) + if (A.stat == DEAD && !A.should_be_dead()) A.set_stat(CONSCIOUS) - A.lying = 0 A.switch_from_dead_to_living_mob_list() A.add_ai_verbs() A.update_icon() @@ -81,13 +80,13 @@ if(AC) AC.update_icon() // Finished restoring - if((A.hardware_integrity() == 100) && (A.backup_capacitor() == 100)) + if((A.get_health_percent() == 100) && (A.backup_capacitor() == 100)) restoring = 0 /datum/nano_module/program/computer_aidiag name = "AI Maintenance Utility" -/datum/nano_module/program/computer_aidiag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/computer_aidiag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() data += "skill_fail" @@ -106,9 +105,9 @@ data["error"] = "No AI located" else data["ai_name"] = A.name - data["ai_integrity"] = A.hardware_integrity() + data["ai_integrity"] = A.get_health_percent() data["ai_capacitor"] = A.backup_capacitor() - data["ai_isdamaged"] = (A.hardware_integrity() < 100) || (A.backup_capacitor() < 100) + data["ai_isdamaged"] = (A.get_health_percent() < 100) || (A.backup_capacitor() < 100) data["ai_isdead"] = (A.stat == DEAD) var/list/all_laws[0] diff --git a/code/modules/modular_computers/file_system/programs/research/email_administration.dm b/code/modules/modular_computers/file_system/programs/research/email_administration.dm index 9ddbc33c0381..ea3ebbe44109 100644 --- a/code/modules/modular_computers/file_system/programs/research/email_administration.dm +++ b/code/modules/modular_computers/file_system/programs/research/email_administration.dm @@ -7,39 +7,39 @@ program_menu_icon = "mail-open" size = 12 requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL available_on_network = 1 nanomodule_path = /datum/nano_module/program/email_administration - required_access = access_network + read_access = list(access_network) category = PROG_ADMIN /datum/nano_module/program/email_administration name = "Email Administration" available_to_ai = TRUE - var/datum/computer_file/data/email_account/current_account = null + var/datum/computer_file/data/account/current_account = null var/datum/computer_file/data/email_message/current_message = null var/error = "" -/datum/nano_module/program/email_administration/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/email_administration/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() data += "skill_fail" if(!user.skill_check(SKILL_COMPUTER, SKILL_BASIC)) var/datum/extension/fake_data/fake_data = get_or_create_extension(src, /datum/extension/fake_data, 15) data["skill_fail"] = fake_data.update_and_return_data() - data["terminal"] = !!program - var/datum/computer_network/network = program.computer.get_network() + var/datum/computer_network/network = program?.computer?.get_network() if(!network) error = "NETWORK FAILURE: Check connection to the network." - if(!length(network.get_mainframes_by_role(MF_ROLE_EMAIL_SERVER, user))) - error = "NETWORK FAILURE: No email servers detected." + else if(!length(network.get_mainframes_by_role(MF_ROLE_ACCOUNT_SERVER, user))) + error = "NETWORK FAILURE: No account servers detected." if(error) data["error"] = error else if(istype(current_message)) data["msg_title"] = current_message.title - data["msg_body"] = digitalPencode2html(current_message.stored_data) + data["msg_body"] = current_message.generate_file_data() data["msg_timestamp"] = current_message.timestamp data["msg_source"] = current_message.source else if(istype(current_account)) @@ -57,12 +57,11 @@ data["messagecount"] = all_messages.len else var/list/all_accounts = list() - for(var/datum/computer_file/data/email_account/account in network.get_email_addresses()) + for(var/datum/computer_file/data/account/account in network.get_accounts(get_access(user))) if(!account.can_login) continue all_accounts.Add(list(list( - "login" = account.login, - "uid" = account.uid + "login" = account.login ))) data["accounts"] = all_accounts data["accountcount"] = all_accounts.len @@ -89,17 +88,12 @@ if(!user.skill_check(SKILL_COMPUTER, SKILL_BASIC)) return TOPIC_HANDLED - var/datum/computer_network/network = program.computer.get_network() + var/datum/computer_network/network = program?.computer?.get_network() if(!network) return TOPIC_HANDLED - if(!length(network.mainframes[MF_ROLE_EMAIL_SERVER])) - error = "NETWORK FAILURE: No email servers detected." - return TOPIC_HANDLED - // High security - can only be operated when the user has an ID with access on them. - var/obj/item/card/id/I = user.GetIdCard() - if(!istype(I) || !(access_network in I.access)) - return TOPIC_HANDLED + // This is just for logging, not access checking so don't bother actually checking if the account has changed. + var/datum/computer_file/data/account/user_account = program.computer.get_account_nocheck() if(href_list["back"]) if(error) @@ -116,22 +110,10 @@ current_account.suspended = !current_account.suspended if(network.intrusion_detection_enabled) - program.computer.add_log("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).") + program.computer.add_log("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [user_account.login].") error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended." return TOPIC_REFRESH - if(href_list["changepass"]) - if(!current_account) - return TOPIC_HANDLED - - var/newpass = sanitize(input(user,"Enter new password for account [current_account.login]", "Password"), 100) - if(!newpass || !CanUseTopic(user, state)) - return TOPIC_HANDLED - current_account.password = newpass - if(network.intrusion_detection_enabled) - program.computer.add_log("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).") - return TOPIC_REFRESH - if(href_list["viewmail"]) if(!current_account) return TOPIC_HANDLED @@ -143,28 +125,5 @@ return TOPIC_REFRESH if(href_list["viewaccount"]) - for(var/datum/computer_file/data/email_account/email_account in network.get_email_addresses()) - if(email_account.uid == text2num(href_list["viewaccount"])) - current_account = email_account - break - return TOPIC_REFRESH - - if(href_list["newaccount"]) - var/newdomain = sanitize(input(user,"Pick domain:", "Domain name") as null|anything in GLOB.using_map.usable_email_tlds) - if(!newdomain) - return TOPIC_HANDLED - var/newlogin = sanitize(input(user,"Pick account name (@[newdomain]):", "Account name"), 100) - if(!newlogin || !CanUseTopic(user, state)) - return TOPIC_HANDLED - - var/complete_login = "[newlogin]@[newdomain]" - if(network.find_email_by_name(complete_login)) - error = "Error creating account: An account with same address already exists." - return TOPIC_REFRESH - - var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account() - new_account.login = complete_login - new_account.password = GenerateKey() - network.add_email_account(new_account) - error = "Email [new_account.login] has been created, with generated password [new_account.password]" - return TOPIC_REFRESH + current_account = network.find_account_by_login(href_list["viewaccount"], get_access(user)) + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm index 9508d7f2876a..f96c61e63609 100644 --- a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm +++ b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST(all_warrants) +var/global/list/all_warrants /datum/computer_file/program/digitalwarrant filename = "digitalwarrant" @@ -9,8 +9,9 @@ GLOBAL_LIST(all_warrants) program_key_state = "security_key" program_menu_icon = "star" requires_network = 1 + requires_network_feature = NET_FEATURE_SECURITY available_on_network = 1 - required_access = access_security + read_access = list(access_security) nanomodule_path = /datum/nano_module/program/digitalwarrant/ category = PROG_SEC @@ -18,29 +19,32 @@ GLOBAL_LIST(all_warrants) name = "Warrant Assistant" var/datum/computer_file/report/warrant/active -/datum/nano_module/program/proc/get_warrants() - var/datum/computer_network/network = program.computer.get_network() +/datum/nano_module/program/proc/get_warrants(list/accesses, mob/user) + var/datum/computer_network/network = program?.computer?.get_network() if(network) - return network.get_all_files_of_type(/datum/computer_file/report/warrant) + return network.get_all_files_of_type(/datum/computer_file/report/warrant, accesses = accesses) -/datum/nano_module/program/proc/remove_warrant(datum/computer_file/report/warrant/W) - var/datum/computer_network/network = program.computer.get_network() +/datum/nano_module/program/proc/remove_warrant(datum/computer_file/report/warrant/warrant, list/accesses, mob/user) + var/datum/computer_network/network = program?.computer?.get_network() if(network) - return network.remove_file(W) + return network.remove_file(warrant, accesses, user) -/datum/nano_module/program/proc/save_warrant(datum/computer_file/report/warrant/W) - var/datum/computer_network/network = program.computer.get_network() +/datum/nano_module/program/proc/save_warrant(datum/computer_file/report/warrant/warrant, list/accesses, mob/user) + var/datum/computer_network/network = program?.computer?.get_network() if(network) - return network.store_file(W) + return network.store_file(warrant, OS_DOCUMENTS_DIR, TRUE, accesses = accesses, user = user) -/datum/nano_module/program/digitalwarrant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/digitalwarrant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() + var/list/accesses = get_access(user) + if(active) - data["details"] = active.generate_nano_data(using_access) + data["details"] = active.generate_nano_data(accesses, user) else - for(var/datum/computer_file/report/warrant/W in GLOB.all_warrants) - LAZYADD(data[W.get_category()], W.get_nano_summary()) + var/list/avail_warrants = get_warrants(accesses, user) + for(var/datum/computer_file/report/warrant/warrant in avail_warrants) + LAZYADD(data[warrant.get_category()], warrant.get_nano_summary()) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -52,53 +56,61 @@ GLOBAL_LIST(all_warrants) /datum/nano_module/program/digitalwarrant/Topic(href, href_list) if(..()) return 1 + var/list/accesses = get_access(usr) + var/list/avail_warrants = get_warrants(accesses, usr) if(href_list["editwarrant"]) . = 1 - for(var/datum/computer_file/report/warrant/W in GLOB.all_warrants) - if(W.uid == text2num(href_list["editwarrant"])) - active = W + for(var/datum/computer_file/report/warrant/warrant in avail_warrants) + if(warrant.uid == text2num(href_list["editwarrant"])) + active = warrant break if(href_list["sendtoarchive"]) . = 1 - for(var/datum/computer_file/report/warrant/W in GLOB.all_warrants) - if(W.uid == text2num(href_list["sendtoarchive"])) - W.archived = TRUE + for(var/datum/computer_file/report/warrant/warrant in avail_warrants) + if(warrant.uid == text2num(href_list["sendtoarchive"])) + warrant.archived = TRUE break if(href_list["restore"]) . = 1 - for(var/datum/computer_file/report/warrant/W in GLOB.all_warrants) - if(W.uid == text2num(href_list["restore"])) - W.archived = FALSE + for(var/datum/computer_file/report/warrant/warrant in avail_warrants) + if(warrant.uid == text2num(href_list["restore"])) + warrant.archived = FALSE break if(href_list["addwarrant"]) . = 1 - var/datum/computer_file/report/warrant/W + var/datum/computer_file/report/warrant/warrant if(href_list["addwarrant"] == "arrest") - W = new /datum/computer_file/report/warrant/arrest() + warrant = new /datum/computer_file/report/warrant/arrest else - W = new /datum/computer_file/report/warrant/search() - active = W + warrant = new /datum/computer_file/report/warrant/search + active = warrant if(href_list["savewarrant"]) . = 1 if(!active) return - broadcast_security_hud_message("[active.get_broadcast_summary()] has been [(active in GLOB.all_warrants) ? "edited" : "uploaded"].", nano_host()) - LAZYDISTINCTADD(GLOB.all_warrants, active) + broadcast_security_hud_message("[active.get_broadcast_summary()] has been [(active in global.all_warrants) ? "edited" : "uploaded"].", nano_host()) + + var/success = save_warrant(active, accesses, usr) + if(success != OS_FILE_SUCCESS) + to_chat(usr, SPAN_WARNING("Could not save warrant. You may lack access to the file servers.")) + return active = null if(href_list["deletewarrant"]) . = 1 if(!active) - for(var/datum/computer_file/report/warrant/W in GLOB.all_warrants) - if(W.uid == text2num(href_list["deletewarrant"])) - active = W + for(var/datum/computer_file/report/warrant/warrant in avail_warrants) + if(warrant.uid == text2num(href_list["deletewarrant"])) + active = warrant break - LAZYREMOVE(GLOB.all_warrants, active) + var/success = remove_warrant(active, accesses, usr) + if(success != OS_FILE_SUCCESS) + to_chat(usr, SPAN_WARNING("Could not remove warrant. You may lack access to the file servers.")) active = null if(href_list["back"]) @@ -111,7 +123,7 @@ GLOBAL_LIST(all_warrants) var/datum/report_field/F = active.field_from_ID(text2num(href_list["edit_field"])) if(!F) return - if(!F.verify_access_edit(using_access)) + if(!(F.get_perms(accesses, usr) & OS_WRITE_ACCESS)) to_chat(usr, SPAN_WARNING("\The [nano_host()] flashes an \"Access Denied\" warning.")) return F.ask_value(usr) diff --git a/code/modules/modular_computers/file_system/programs/security/forceauthorization.dm b/code/modules/modular_computers/file_system/programs/security/forceauthorization.dm index 994779e2476e..0fb246256058 100644 --- a/code/modules/modular_computers/file_system/programs/security/forceauthorization.dm +++ b/code/modules/modular_computers/file_system/programs/security/forceauthorization.dm @@ -7,8 +7,9 @@ program_icon_state = "security" program_menu_icon = "locked" requires_network = 1 + requires_network_feature = NET_FEATURE_SECURITY available_on_network = 1 - required_access = access_armory + read_access = list(access_armory) nanomodule_path = /datum/nano_module/program/forceauthorization/ category = PROG_SEC @@ -21,12 +22,12 @@ var/datum/computer_network/gun_net = istype(S) ? S.get_computer_network() : G.get_network() return our_net == gun_net -/datum/nano_module/program/forceauthorization/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/forceauthorization/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() data["is_silicon_usr"] = issilicon(user) data["guns"] = list() - for(var/obj/item/gun/G in GLOB.registered_weapons) + for(var/obj/item/gun/G in global.registered_weapons) if(G.standby) continue @@ -48,7 +49,7 @@ if(!data["is_silicon_usr"]) // don't send data even though they won't be able to see it data["cyborg_guns"] = list() - for(var/obj/item/gun/energy/gun/secure/mounted/G in GLOB.registered_cyborg_weapons) + for(var/obj/item/gun/energy/gun/secure/mounted/G in global.registered_cyborg_weapons) if(!is_gun_connected(G)) continue var/list/modes = list() // we don't get location, unlike inside of the last loop, because borg locations are reported elsewhere. @@ -72,7 +73,7 @@ return 1 if(href_list["gun"] && ("authorize" in href_list) && href_list["mode"]) - var/obj/item/gun/G = locate(href_list["gun"]) in GLOB.registered_weapons + var/obj/item/gun/G = locate(href_list["gun"]) in global.registered_weapons if(!is_gun_connected(G)) return var/do_authorize = text2num(href_list["authorize"]) @@ -80,7 +81,7 @@ return isnum(do_authorize) && isnum(mode) && G && G.authorize(mode, do_authorize, usr.name) if(href_list["cyborg_gun"] && ("authorize" in href_list) && href_list["mode"]) - var/obj/item/gun/energy/gun/secure/mounted/M = locate(href_list["cyborg_gun"]) in GLOB.registered_cyborg_weapons + var/obj/item/gun/energy/gun/secure/mounted/M = locate(href_list["cyborg_gun"]) in global.registered_cyborg_weapons if(!is_gun_connected(M)) return var/do_authorize = text2num(href_list["authorize"]) diff --git a/code/modules/modular_computers/file_system/programs/security/turret_control.dm b/code/modules/modular_computers/file_system/programs/security/turret_control.dm new file mode 100644 index 000000000000..8000e6715316 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/security/turret_control.dm @@ -0,0 +1,83 @@ +/datum/computer_file/program/turret_control + filename = "sentrycntrl" + filedesc = "Sentry Turret Control" + extended_desc = "A program used to control sentry turrets on the network." + size = 4 + usage_flags = PROGRAM_CONSOLE + program_icon_state = "security" + program_menu_icon = "locked" + requires_network = 1 + requires_network_feature = NET_FEATURE_SECURITY + available_on_network = 1 + nanomodule_path = /datum/nano_module/program/turret_control + category = PROG_SEC + +/datum/nano_module/program/turret_control + name = "Sentry Turret Control" + +/datum/nano_module/program/turret_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) + var/list/data = host.initial_data() + var/list/area_turrets = list() // Dictionary of area name -> turret + var/datum/computer_network/network = get_network() + if(network) + var/list/turrets = network.get_devices_by_type(/obj/machinery/turret/network, get_access(user)) + for(var/obj/machinery/turret/network/net_turret in turrets) + var/area/A = get_area(net_turret) + var/area_name = A.name + + var/datum/extension/network_device/turret_device = get_extension(net_turret, /datum/extension/network_device) + + if(!(area_name in area_turrets)) + area_turrets[area_name] = list() + + area_turrets[area_name] += list(list("tag" = turret_device.network_tag, "enabled" = net_turret.enabled)) + + data["area_turrets"] = list() + for(var/area_name in area_turrets) + data["area_turrets"] += list(list("area_name" = area_name, "turrets" = area_turrets[area_name])) + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "turret_program.tmpl", name, 700, 450, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +/datum/computer_file/program/turret_control/Topic(href, href_list, state) + if(..()) + return TOPIC_HANDLED + + var/mob/user = usr + var/datum/nano_module/program/turret_control/module = NM + var/datum/computer_network/network = module.get_network() + if(!network) + return TOPIC_REFRESH + if(href_list["turret"]) + var/datum/extension/network_device/turret_device = network.get_device_by_tag(href_list["turret"]) + if(!turret_device || !turret_device.has_access(module.get_access(user))) + return TOPIC_REFRESH + var/obj/machinery/turret/network/net_turret = turret_device.holder + if(href_list["settings"]) + var/datum/topic_state/remote/remote = new(module, net_turret) + net_turret.ui_interact(user, state = remote) + return TOPIC_REFRESH + + if(href_list["logs"]) + if(!LAZYLEN(net_turret.logs)) + to_chat(user, SPAN_WARNING("\The [net_turret] currently has no logs!")) + return TOPIC_HANDLED + + var/choice = alert(user,"Would you like to download the turret's logs or delete them?", "Sentry Turret Logs", "Download", "Delete","Cancel") + if(!CanInteract(user, state)) + return TOPIC_HANDLED + if(choice == "Download") + var/datum/computer_file/data/logfile/turret_log = net_turret.prepare_log_file() + view_file_browser(user, "save_log", /datum/computer_file/data/logfile, OS_WRITE_ACCESS, "Save log file:", turret_log) + return TOPIC_REFRESH + if(choice == "Delete") + var/confirm = alert(user, "Are you sure?", "Log deletion", "No", "Yes") + if(confirm == "Yes" && CanInteract(user, state)) + LAZYCLEARLIST(net_turret.logs) + return TOPIC_REFRESH + + return TOPIC_HANDLED \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/reports/crew_record.dm b/code/modules/modular_computers/file_system/reports/crew_record.dm index 7126080ca792..19af29eaeac7 100644 --- a/code/modules/modular_computers/file_system/reports/crew_record.dm +++ b/code/modules/modular_computers/file_system/reports/crew_record.dm @@ -1,297 +1,272 @@ -GLOBAL_LIST_EMPTY(all_crew_records) -GLOBAL_LIST_INIT(blood_types, list("A-", "A+", "B-", "B+", "AB-", "AB+", "O-", "O+")) -GLOBAL_LIST_INIT(physical_statuses, list("Active", "Disabled", "SSD", "Deceased", "MIA")) -GLOBAL_VAR_INIT(default_physical_status, "Active") -GLOBAL_LIST_INIT(security_statuses, list("None", "Released", "Parolled", "Incarcerated", "Arrest")) -GLOBAL_VAR_INIT(default_security_status, "None") -GLOBAL_VAR_INIT(arrest_security_status, "Arrest") +var/global/list/all_crew_records = list() +var/global/list/physical_statuses = list("Active", "Disabled", "SSD", "Deceased", "MIA") +var/global/list/security_statuses = list("None", "Released", "Parolled", "Incarcerated", "Arrest") + +var/global/default_physical_status = "Active" +var/global/default_security_status = "None" +var/global/arrest_security_status = "Arrest" /datum/computer_file/report/crew_record filetype = "CDB" size = 2 + write_access = list(list(access_bridge)) + var/icon/photo_front = null var/icon/photo_side = null - //More variables below. - var/list/grants = list() // List of weakrefs to grant files. - var/user_id // A unique identifier linking a mob/player/user to this access record and their grants. - + /datum/computer_file/report/crew_record/New() ..() filename = "record[random_id(type, 100,999)]" - user_id = "[sequential_id("datum/computer_file/report/crew_record")]" load_from_mob(null) /datum/computer_file/report/crew_record/Destroy() . = ..() - GLOB.all_crew_records.Remove(src) - -/datum/computer_file/report/crew_record/proc/add_grant(var/datum/computer_file/data/grant_record/new_grant) - grants |= weakref(new_grant) - -/datum/computer_file/report/crew_record/proc/remove_grant(var/grant_name) - for(var/weakref/grant in grants) - var/datum/computer_file/data/grant_record/GR = grant.resolve() - if(!GR) - grants -= GR - continue - if(GR.stored_data == grant_name) - grants -= GR - return - -/datum/computer_file/report/crew_record/proc/calculate_size() - size = max(1, round(length(user_id) + length(grants) / 20)) - -/datum/computer_file/report/crew_record/proc/get_access(var/network_id) - var/list/access_grants = list() - for(var/datum/computer_file/data/grant_record/grant in get_valid_grants()) - LAZYDISTINCTADD(access_grants, uppertext("[network_id].[grant.stored_data]")) - return access_grants - -/datum/computer_file/report/crew_record/proc/get_valid_grants() - var/list/valid_grants = list() - for(var/weakref/grant in grants) - var/datum/computer_file/data/grant_record/GR = grant.resolve() - if(!istype(GR) || GR.holder != holder) - grants.Remove(grant) - continue // This is a bad grant. File is gone or moved. - LAZYDISTINCTADD(valid_grants, GR) - return valid_grants - -/datum/computer_file/report/crew_record/proc/load_from_mob(var/mob/living/carbon/human/H) - if(istype(H)) - photo_front = getFlatIcon(H, SOUTH, always_use_defdir = 1) - photo_side = getFlatIcon(H, WEST, always_use_defdir = 1) + global.all_crew_records.Remove(src) + +/datum/computer_file/report/crew_record/proc/load_from_mob(var/mob/living/human/crewmember) + + if(istype(crewmember)) + photo_front = getFlatIcon(crewmember, SOUTH, always_use_defdir = 1) + photo_side = getFlatIcon(crewmember, WEST, always_use_defdir = 1) else - var/mob/living/carbon/human/dummy = new() + var/mob/living/human/dummy = new() photo_front = getFlatIcon(dummy, SOUTH, always_use_defdir = 1) photo_side = getFlatIcon(dummy, WEST, always_use_defdir = 1) qdel(dummy) + // Load records from the client. + var/list/records = crewmember?.client?.prefs?.records || list() + // Add honorifics, etc. var/formal_name = "Unset" - if(H) - formal_name = H.real_name - if(H.client && H.client.prefs) - for(var/culturetag in H.client.prefs.cultural_info) - var/decl/cultural_info/culture = SSlore.get_culture(H.client.prefs.cultural_info[culturetag]) - if(H.char_rank && H.char_rank.name_short) - formal_name = "[formal_name][culture.get_formal_name_suffix()]" + if(crewmember) + formal_name = crewmember.real_name + if(crewmember.client && crewmember.client.prefs) + for(var/token in crewmember.client.prefs.background_info) + var/decl/background_detail/background = GET_DECL(crewmember.client.prefs.background_info[token]) + if(crewmember.char_rank && crewmember.char_rank.name_short) + formal_name = "[formal_name][background.get_formal_name_suffix()]" else - formal_name = "[culture.get_formal_name_prefix()][formal_name][culture.get_formal_name_suffix()]" + formal_name = "[background.get_formal_name_prefix()][formal_name][background.get_formal_name_suffix()]" // Generic record - set_name(H ? H.real_name : "Unset") + set_name(crewmember ? crewmember.real_name : "Unset") set_formal_name(formal_name) - set_job(H ? GetAssignment(H) : "Unset") + set_job(crewmember ? GetAssignment(crewmember) : "Unset") var/gender_term = "Unset" - if(H) - var/datum/gender/G = gender_datums[H.get_sex()] - if(G) - gender_term = gender2text(G.formal_term) - set_sex(gender_term) - set_age(H ? H.age : 30) - set_status(GLOB.default_physical_status) - set_species(H ? H.get_species() : GLOB.using_map.default_species) - set_branch(H ? (H.char_branch && H.char_branch.name) : "None") - set_rank(H ? (H.char_rank && H.char_rank.name) : "None") - set_public_record(H && H.public_record && !jobban_isbanned(H, "Records") ? html_decode(H.public_record) : "No record supplied") + if(crewmember) + var/decl/pronouns/gender = crewmember.get_pronouns(ignore_coverings = TRUE) + if(gender?.bureaucratic_term) + gender_term = gender.bureaucratic_term + set_gender(gender_term) + set_age(crewmember?.get_age() || 30) + set_status(global.default_physical_status) + var/decl/species/default_species = decls_repository.get_decl_by_id(global.using_map.default_species) + set_species_name(crewmember ? crewmember.get_species_name() : default_species.name) + set_branch(crewmember ? (crewmember.char_branch && crewmember.char_branch.name) : "None") + set_rank(crewmember ? (crewmember.char_rank && crewmember.char_rank.name) : "None") + + var/public_record = records[PREF_PUB_RECORD] + set_public_record((public_record && !jobban_isbanned(crewmember, "Records")) ? html_decode(public_record) : "No record supplied") // Medical record - set_bloodtype(H ? H.b_type : "Unset") - set_medRecord((H && H.med_record && !jobban_isbanned(H, "Records") ? html_decode(H.med_record) : "No record supplied")) - - if(H) - if(H.isSynthetic()) - set_implants("Fully synthetic body") - else - var/organ_data = list("\[*\]") - for(var/obj/item/organ/external/E in H.organs) - if(BP_IS_PROSTHETIC(E)) - organ_data += "[E.model ? "[E.model] " : null][E.name] prosthetic" - for(var/obj/item/organ/internal/I in H.internal_organs) - if(BP_IS_ASSISTED(I)) - organ_data += I.get_mechanical_assisted_descriptor() - else if (BP_IS_PROSTHETIC(I)) - organ_data += "[I.name] prosthetic" - set_implants(jointext(organ_data, "\[*\]")) + set_bloodtype(crewmember?.get_blood_type() || "Unset") + var/medical_record = records[PREF_MED_RECORD] + set_medical_record((medical_record && !jobban_isbanned(crewmember, "Records")) ? html_decode(medical_record) : "No record supplied") + + if(crewmember) + var/decl/bodytype/root_bodytype = crewmember.get_bodytype() + var/organ_data = list("\[*\]") + for(var/obj/item/organ/external/child in crewmember.get_external_organs()) + if(child.bodytype != root_bodytype) + organ_data += "[child.bodytype] [child.name] [BP_IS_PROSTHETIC(child) ? "prosthetic" : "graft"]" + for(var/obj/item/organ/internal/internal_organ in crewmember.get_internal_organs()) + if(internal_organ.bodytype != root_bodytype) + organ_data += "[internal_organ.bodytype] [internal_organ.name] [BP_IS_PROSTHETIC(internal_organ) ? "prosthetic" : "graft"]" + set_implants(jointext(organ_data, "\[*\]")) // Security record - set_criminalStatus(GLOB.default_security_status) - set_dna(H ? H.dna.unique_enzymes : "") - set_fingerprint(H ? md5(H.dna.uni_identity) : "") - set_secRecord(H && H.sec_record && !jobban_isbanned(H, "Records") ? html_decode(H.sec_record) : "No record supplied") + set_criminalStatus(global.default_security_status) + set_dna(crewmember?.get_unique_enzymes() || "") + set_fingerprint(crewmember?.get_full_print(ignore_blockers = TRUE) || "") + + var/security_record = records[PREF_SEC_RECORD] + set_security_record((security_record && !jobban_isbanned(crewmember, "Records")) ? html_decode(security_record) : "No record supplied") // Employment record var/employment_record = "No record supplied" - if(H) - if(H.gen_record && !jobban_isbanned(H, "Records")) - employment_record = html_decode(H.gen_record) - if(H.client && H.client.prefs) + if(crewmember) + var/gen_record = records[PREF_GEN_RECORD] + if(gen_record && !jobban_isbanned(crewmember, "Records")) + employment_record = html_decode(gen_record) + if(crewmember.client && crewmember.client.prefs) var/list/qualifications - for(var/culturetag in H.client.prefs.cultural_info) - var/decl/cultural_info/culture = SSlore.get_culture(H.client.prefs.cultural_info[culturetag]) - var/extra_note = culture.get_qualifications() + for(var/token in crewmember.client.prefs.background_info) + var/decl/background_detail/background = GET_DECL(crewmember.client.prefs.background_info[token]) + var/extra_note = background.get_qualifications() if(extra_note) LAZYADD(qualifications, extra_note) if(LAZYLEN(qualifications)) employment_record = "[employment_record ? "[employment_record]\[br\]" : ""][jointext(qualifications, "\[br\]>")]" - set_emplRecord(employment_record) + set_employment_record(employment_record) - // Misc cultural info. - set_homeSystem(H ? html_decode(H.get_cultural_value(TAG_HOMEWORLD)) : "Unset") - set_faction(H ? html_decode(H.get_cultural_value(TAG_FACTION)) : "Unset") - set_religion(H ? html_decode(H.get_cultural_value(TAG_RELIGION)) : "Unset") + // Misc background info. + set_residence(crewmember ? html_decode(crewmember.get_background_datum_by_flag(BACKGROUND_FLAG_RESIDENCE)) : "Unset") + set_faction(crewmember ? html_decode(crewmember.get_background_datum_by_flag(BACKGROUND_FLAG_IDEOLOGY)) : "Unset") + set_religion(crewmember ? html_decode(crewmember.get_background_datum_by_flag(BACKGROUND_FLAG_RELIGION)) : "Unset") - if(H) + if(crewmember) var/skills = list() - for(var/decl/hierarchy/skill/S in GLOB.skills) - var/level = H.get_skill_value(S.type) + for(var/decl/skill/skill in global.using_map.get_available_skills()) + var/level = crewmember.get_skill_value(skill.type) if(level > SKILL_NONE) - skills += "[S.name], [S.levels[level]]" + skills += "[skill.name], [skill.levels[level]]" set_skillset(jointext(skills,"\n")) // Antag record - set_antagRecord(H && H.exploit_record && !jobban_isbanned(H, "Records") ? html_decode(H.exploit_record) : "") + if(crewmember?.client?.prefs) + var/exploit_record = crewmember.client.prefs.exploit_record + set_antag_record((exploit_record && !jobban_isbanned(crewmember, "Records")) ? html_decode(exploit_record) : "") // Cut down version for silicons -/datum/computer_file/report/crew_record/synth/load_from_mob(var/mob/living/silicon/S) - if(istype(S)) - photo_front = getFlatIcon(S, SOUTH, always_use_defdir = 1) - photo_side = getFlatIcon(S, WEST, always_use_defdir = 1) +/datum/computer_file/report/crew_record/synth/load_from_mob(var/mob/living/silicon/silicon_crewmember) + if(istype(silicon_crewmember)) + photo_front = getFlatIcon(silicon_crewmember, SOUTH, always_use_defdir = 1) + photo_side = getFlatIcon(silicon_crewmember, WEST, always_use_defdir = 1) // Generic record - set_name(S ? S.real_name : "Unset") - set_formal_name(S ? S.real_name : "Unset") - set_sex("Unset") - set_status(GLOB.default_physical_status) + set_name(silicon_crewmember ? silicon_crewmember.real_name : "Unset") + set_formal_name(silicon_crewmember ? silicon_crewmember.real_name : "Unset") + set_gender("Unset") + set_status(global.default_physical_status) var/silicon_type = "Synthetic Lifeform" - var/robojob = GetAssignment(S) - if(istype(S, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = S - silicon_type = R.braintype - if(R.module) - robojob = "[R.module.display_name] [silicon_type]" - if(istype(S, /mob/living/silicon/ai)) + var/robojob = GetAssignment(silicon_crewmember) + if(isrobot(silicon_crewmember)) + var/mob/living/silicon/robot/robot = silicon_crewmember + silicon_type = robot.braintype + if(robot.module) + robojob = "[robot.module.display_name] [silicon_type]" + if(isAI(silicon_crewmember)) silicon_type = "AI" robojob = "Artificial Intelligence" - set_job(S ? robojob : "Unset") - set_species(silicon_type) + set_job(silicon_crewmember ? robojob : "Unset") + set_species_name(silicon_type) set_implants("Robotic body") // Security record - set_criminalStatus(GLOB.default_security_status) + set_criminalStatus(global.default_security_status) // Global methods // Used by character creation to create a record for new arrivals. -/proc/CreateModularRecord(var/mob/living/H, record_type = /datum/computer_file/report/crew_record) - var/datum/computer_file/report/crew_record/CR = new record_type() - GLOB.all_crew_records.Add(CR) - CR.load_from_mob(H) - var/datum/computer_network/network = get_local_network_at(get_turf(H)) +/proc/CreateModularRecord(var/mob/living/crewmember, record_type = /datum/computer_file/report/crew_record) + var/datum/computer_file/report/crew_record/crew_record = new record_type() + global.all_crew_records.Add(crew_record) + crew_record.load_from_mob(crewmember) + var/datum/computer_network/network = get_local_network_at(get_turf(crewmember)) if(network) - network.store_file(CR, MF_ROLE_CREW_RECORDS) - return CR + network.store_file(crew_record, OS_RECORDS_DIR, TRUE, mainframe_role = MF_ROLE_CREW_RECORDS) + return crew_record // Gets crew records filtered by set of positions /proc/department_crew_manifest(var/list/filter_positions, var/blacklist = FALSE) var/list/matches = list() - for(var/datum/computer_file/report/crew_record/CR in GLOB.all_crew_records) - var/rank = CR.get_job() + for(var/datum/computer_file/report/crew_record/crew_record in global.all_crew_records) + var/rank = crew_record.get_job() if(blacklist) if(!(rank in filter_positions)) - matches.Add(CR) + matches.Add(crew_record) else if(rank in filter_positions) - matches.Add(CR) + matches.Add(crew_record) return matches // Simple record to HTML (for paper purposes) conversion. // Not visually that nice, but it gets the work done, feel free to tweak it visually -/proc/record_to_html(var/datum/computer_file/report/crew_record/CR, var/access) +/proc/record_to_html(var/datum/computer_file/report/crew_record/crew_record, var/access) var/dat = "

    RECORD DATABASE DATA DUMP

    Generated on: [stationdate2text()] [stationtime2text()]
    ******************************
    " dat += "
    NamePositionActivity
    " - for(var/datum/report_field/F in CR.fields) - if(F.verify_access(access)) - dat += "" - dat += "
    [F.display_name()]" - if(F.needs_big_box) + for(var/datum/report_field/field in crew_record.fields) + if(field.get_perms(access) & OS_READ_ACCESS) + dat += "
    [field.display_name()]" + if(field.needs_big_box) dat += "
    [F.get_value()]" + dat += "[field.get_value()]" dat += "" return dat //Should only be used for OOC stuff, for player-facing stuff you must go through the network. /proc/get_crewmember_record(var/name) - for(var/datum/computer_file/report/crew_record/CR in GLOB.all_crew_records) - if(CR.get_name() == name) - return CR + for(var/datum/computer_file/report/crew_record/crew_record in global.all_crew_records) + if(crew_record.get_name() == name) + return crew_record return null -/proc/GetAssignment(var/mob/living/carbon/human/H) - if(!H) +/proc/GetAssignment(var/mob/living/crewmember) + if(!crewmember) return "Unassigned" - if(!H.mind) - return H.job - if(H.mind.role_alt_title) - return H.mind.role_alt_title - return H.mind.assigned_role + if(!crewmember.mind) + return crewmember.job + if(crewmember.mind.role_alt_title) + return crewmember.mind.role_alt_title + return crewmember.mind.assigned_role #define GETTER_SETTER(PATH, KEY) /datum/computer_file/report/crew_record/proc/get_##KEY(){var/datum/report_field/F = locate(/datum/report_field/##PATH/##KEY) in fields; if(F) return F.get_value()} \ /datum/computer_file/report/crew_record/proc/set_##KEY(given_value){var/datum/report_field/F = locate(/datum/report_field/##PATH/##KEY) in fields; if(F) F.set_value(given_value)} -#define SETUP_FIELD(NAME, KEY, PATH, ACCESS, ACCESS_EDIT) GETTER_SETTER(PATH, KEY); /datum/report_field/##PATH/##KEY;\ -/datum/computer_file/report/crew_record/generate_fields(){..(); var/datum/report_field/##KEY = add_field(/datum/report_field/##PATH/##KEY, ##NAME);\ +#define SETUP_FIELD(NAME, KEY, PATH, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS, SEARCHABLE) GETTER_SETTER(PATH, KEY); /datum/report_field/##PATH/##KEY;\ +/datum/computer_file/report/crew_record/generate_fields(){..(); var/datum/report_field/##KEY = add_field(/datum/report_field/##PATH/##KEY, ##NAME, searchable = SEARCHABLE, can_mod_access = CAN_MOD_ACCESS);\ KEY.set_access(ACCESS, ACCESS_EDIT || ACCESS || access_bridge)} // Fear not the preprocessor, for it is a friend. To add a field, use one of these, depending on value type and if you need special access to see it. // It will also create getter/setter procs for record datum, named like /get_[key here]() /set_[key_here](value) e.g. get_name() set_name(value) // Use getter setters to avoid errors caused by typoing the string key. -#define FIELD_SHORT(NAME, KEY, ACCESS, ACCESS_EDIT) SETUP_FIELD(NAME, KEY, simple_text/crew_record, ACCESS, ACCESS_EDIT) -#define FIELD_LONG(NAME, KEY, ACCESS, ACCESS_EDIT) SETUP_FIELD(NAME, KEY, pencode_text/crew_record, ACCESS, ACCESS_EDIT) -#define FIELD_NUM(NAME, KEY, ACCESS, ACCESS_EDIT) SETUP_FIELD(NAME, KEY, number/crew_record, ACCESS, ACCESS_EDIT) -#define FIELD_LIST(NAME, KEY, OPTIONS, ACCESS, ACCESS_EDIT) FIELD_LIST_EDIT(NAME, KEY, OPTIONS, ACCESS, ACCESS_EDIT) -#define FIELD_LIST_EDIT(NAME, KEY, OPTIONS, ACCESS, ACCESS_EDIT) SETUP_FIELD(NAME, KEY, options/crew_record, ACCESS, ACCESS_EDIT);\ +#define FIELD_SHORT(NAME, KEY, ACCESS, ACCESS_EDIT, SEARCHABLE, CAN_MOD_ACCESS) SETUP_FIELD(NAME, KEY, simple_text/crew_record, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS, SEARCHABLE) +#define FIELD_LONG(NAME, KEY, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS) SETUP_FIELD(NAME, KEY, pencode_text/crew_record, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS, FALSE) +#define FIELD_NUM(NAME, KEY, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS) SETUP_FIELD(NAME, KEY, number/crew_record, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS, FALSE) +#define FIELD_LIST(NAME, KEY, OPTIONS, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS) FIELD_LIST_EDIT(NAME, KEY, OPTIONS, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS) +#define FIELD_LIST_EDIT(NAME, KEY, OPTIONS, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS) SETUP_FIELD(NAME, KEY, options/crew_record, ACCESS, ACCESS_EDIT, CAN_MOD_ACCESS, FALSE);\ /datum/report_field/options/crew_record/##KEY/get_options(){return OPTIONS} // GENERIC RECORDS -FIELD_SHORT("Name", name, null, access_change_ids) -FIELD_SHORT("Formal Name", formal_name, null, access_change_ids) -FIELD_SHORT("Job", job, null, access_change_ids) -FIELD_LIST("Sex", sex, record_genders(), null, access_change_ids) -FIELD_NUM("Age", age, null, access_change_ids) -FIELD_LIST_EDIT("Status", status, GLOB.physical_statuses, null, access_medical) +FIELD_SHORT("Name", name, null, access_change_ids, TRUE, TRUE) +FIELD_SHORT("Formal Name", formal_name, null, access_change_ids, FALSE, TRUE) +FIELD_SHORT("Job", job, null, access_change_ids, FALSE, TRUE) +FIELD_LIST("Gender", gender, record_genders(), null, access_change_ids, TRUE) +FIELD_NUM("Age", age, null, access_change_ids, TRUE) +FIELD_LIST_EDIT("Status", status, global.physical_statuses, null, access_medical, TRUE) -FIELD_SHORT("Species",species, null, access_change_ids) -FIELD_LIST("Branch", branch, record_branches(), null, access_change_ids) -FIELD_LIST("Rank", rank, record_ranks(), null, access_change_ids) -FIELD_SHORT("Religion", religion, access_chapel_office, access_change_ids) +FIELD_SHORT("Species",species_name, null, access_change_ids, FALSE, TRUE) +FIELD_LIST("Branch", branch, record_branches(), null, access_change_ids, TRUE) +FIELD_LIST("Rank", rank, record_ranks(), null, access_change_ids, TRUE) +FIELD_SHORT("Religion", religion, access_chapel_office, access_change_ids, FALSE, TRUE) -FIELD_LONG("General Notes (Public)", public_record, null, access_bridge) +FIELD_LONG("General Notes (Public)", public_record, null, access_bridge, TRUE) // MEDICAL RECORDS -FIELD_LIST("Blood Type", bloodtype, GLOB.blood_types, access_medical, access_medical) -FIELD_LONG("Medical Record", medRecord, access_medical, access_medical) -FIELD_LONG("Known Implants", implants, access_medical, access_medical) +FIELD_LIST("Blood Type", bloodtype, get_all_blood_types(), access_medical, access_medical, TRUE) +FIELD_LONG("Medical Record", medical_record, access_medical, access_medical, TRUE) +FIELD_LONG("Known Implants", implants, access_medical, access_medical, TRUE) // SECURITY RECORDS -FIELD_LIST("Criminal Status", criminalStatus, GLOB.security_statuses, access_security, access_security) -FIELD_LONG("Security Record", secRecord, access_security, access_security) -FIELD_SHORT("DNA", dna, access_security, access_security) -FIELD_SHORT("Fingerprint", fingerprint, access_security, access_security) +FIELD_LIST("Criminal Status", criminalStatus, global.security_statuses, access_security, access_security, TRUE) +FIELD_LONG("Security Record", security_record, access_security, access_security, TRUE) +FIELD_SHORT("DNA", dna, access_security, access_security, TRUE, TRUE) +FIELD_SHORT("Fingerprint", fingerprint, access_security, access_security, TRUE, TRUE) // EMPLOYMENT RECORDS -FIELD_LONG("Employment Record", emplRecord, access_bridge, access_bridge) -FIELD_SHORT("Home System", homeSystem, access_bridge, access_change_ids) -FIELD_SHORT("Faction", faction, access_bridge, access_bridge) -FIELD_LONG("Qualifications", skillset, access_bridge, access_bridge) +FIELD_LONG("Employment Record", employment_record, access_bridge, access_bridge, TRUE) +FIELD_SHORT("Residence", residence, access_bridge, access_change_ids, FALSE, TRUE) +FIELD_SHORT("Association", faction, access_bridge, access_bridge, FALSE, TRUE) +FIELD_LONG("Qualifications", skillset, access_bridge, access_bridge, TRUE) // ANTAG RECORDS -FIELD_LONG("Exploitable Information", antagRecord, access_syndicate, access_syndicate) +FIELD_LONG("Exploitable Information", antag_record, access_hacked, access_hacked, FALSE) //Options builderes /datum/report_field/options/crew_record/rank/proc/record_ranks() var/datum/computer_file/report/crew_record/record = owner - var/datum/mil_branch/branch = mil_branches.get_branch(record.get_branch()) + var/datum/mil_branch/branch = global.using_map.get_branch(record.get_branch()) if(!branch) return . = list() @@ -300,19 +275,21 @@ FIELD_LONG("Exploitable Information", antagRecord, access_syndicate, access_synd var/datum/mil_rank/RA = branch.ranks[rank] . |= RA.name -/datum/report_field/options/crew_record/sex/proc/record_genders() +/datum/report_field/options/crew_record/gender/proc/record_genders() . = list() . |= "Unset" - for(var/thing in gender_datums) - var/datum/gender/G = gender_datums[thing] - . |= gender2text(G.formal_term) + var/list/all_genders = decls_repository.get_decls_of_type(/decl/pronouns) + for(var/thing in all_genders) + var/decl/pronouns/gender = all_genders[thing] + if(gender.bureaucratic_term ) + . |= gender.bureaucratic_term /datum/report_field/options/crew_record/branch/proc/record_branches() . = list() . |= "Unset" - for(var/B in mil_branches.branches) - var/datum/mil_branch/BR = mil_branches.branches[B] - . |= BR.name + for(var/branch in global.using_map.branches) + var/datum/mil_branch/branch_datum = global.using_map.branches[branch] + . |= branch_datum.name #undef GETTER_SETTER #undef SETUP_FIELD diff --git a/code/modules/modular_computers/file_system/reports/deck_reports.dm b/code/modules/modular_computers/file_system/reports/deck_reports.dm index 84e48d9a46ee..08f75763ad34 100644 --- a/code/modules/modular_computers/file_system/reports/deck_reports.dm +++ b/code/modules/modular_computers/file_system/reports/deck_reports.dm @@ -6,10 +6,7 @@ var/datum/report_field/people/leader //Give these a special name for easier access. var/datum/report_field/people/manifest var/datum/report_field/planned_depart - -/datum/computer_file/report/flight_plan/New() - ..() - set_access(null, access_bridge) + write_access = list(access_bridge) /datum/computer_file/report/flight_plan/Destroy() leader = null @@ -31,11 +28,8 @@ /datum/computer_file/report/recipient/shuttle var/datum/report_field/shuttle var/datum/report_field/mission - var/access_shuttle = 0 //Set to 1 to give the shuttle's logging access as an access_edit pattern. - -/datum/computer_file/report/recipient/shuttle/New() - ..() - set_access(null, access_bridge) + var/access_shuttle = 0 //Set to 1 to give the shuttle's logging access write permissions when created + write_access = list(access_bridge) /datum/computer_file/report/recipient/shuttle/Destroy() shuttle = null @@ -52,10 +46,7 @@ /datum/computer_file/report/recipient/shuttle/damage form_name = "DC243" title = "Post-flight Damage Assessment" - -/datum/computer_file/report/recipient/shuttle/damage/New() - ..() - set_access(null, access_cargo, override = 0) + write_access = list(list(access_bridge, access_cargo)) /datum/computer_file/report/recipient/shuttle/damage/generate_fields() ..() @@ -68,10 +59,7 @@ /datum/computer_file/report/recipient/shuttle/fuel form_name = "DC12" title = "Post-flight Refueling Report" - -/datum/computer_file/report/recipient/shuttle/fuel/New() - ..() - set_access(null, access_cargo, override = 0) + write_access = list(list(access_bridge, access_cargo)) /datum/computer_file/report/recipient/shuttle/fuel/generate_fields() ..() @@ -83,10 +71,7 @@ /datum/computer_file/report/recipient/shuttle/atmos form_name = "DC245" title = "Post-flight Atmospherics Assessment" - -/datum/computer_file/report/recipient/shuttle/atmos/New() - ..() - set_access(null, access_cargo, override = 0) + write_access = list(list(access_bridge, access_cargo)) /datum/computer_file/report/recipient/shuttle/atmos/generate_fields() ..() @@ -98,10 +83,7 @@ /datum/computer_file/report/recipient/shuttle/gear form_name = "DC248b" title = "Post-flight Emergency Supply Inventory; Summary Version" - -/datum/computer_file/report/recipient/shuttle/gear/New() - ..() - set_access(null, access_cargo, override = 0) + write_access = list(list(access_bridge, access_cargo)) /datum/computer_file/report/recipient/shuttle/gear/generate_fields() ..() diff --git a/code/modules/modular_computers/file_system/reports/people.dm b/code/modules/modular_computers/file_system/reports/people.dm index c09b633d9dcc..da2961c13adf 100644 --- a/code/modules/modular_computers/file_system/reports/people.dm +++ b/code/modules/modular_computers/file_system/reports/people.dm @@ -1,5 +1,5 @@ //Field with people in it; has some communications procs available to it. -/datum/report_field/people/proc/send_email(mob/user) +/datum/report_field/people/proc/send_email(mob/user, list/access) if(!get_value()) return //No one to send to anyway. var/subject = sanitize(input(user, "Email Subject:", "Document Email", "Report Submission: [owner.display_name()]") as null|text) @@ -9,21 +9,24 @@ return var/datum/computer_file/data/text/report_file if(attach_report) - var/list/user_access = list() - var/obj/item/card/id/I = user.GetIdCard() - if(I) - user_access |= I.access + var/list/user_access + if(access) + user_access = access.Copy() + else + var/obj/item/card/id/I = user.GetIdCard() + if(I) + user_access += I.access report_file = new - report_file.stored_data = owner.generate_pencode(user_access, no_html = 1) //TXT files can't have html; they use pencode only. + report_file.stored_data = owner.generate_pencode(user_access, user, no_html = 1) //TXT files can't have html; they use pencode only. report_file.filename = owner.filename if(perform_send(subject, body, report_file)) to_chat(user, "The email has been sent.") //Helper procs. /datum/report_field/people/proc/get_used_network() - var/obj/item/stock_parts/computer/hard_drive/holder = owner.holder - if(holder) - var/datum/extension/interactive/ntos/os = get_extension(holder.loc, /datum/extension/interactive/ntos) + var/obj/item/stock_parts/computer/hard_drive/hard_drive = owner.holder?.resolve() + if(!isnull(hard_drive) && isloc(hard_drive.loc)) + var/datum/extension/interactive/os/os = get_extension(hard_drive.loc, /datum/extension/interactive/os) return os?.get_network() /datum/report_field/people/proc/perform_send(subject, body, attach_report) @@ -33,13 +36,13 @@ var/datum/computer_network/net = get_used_network() if(!net) return - var/datum/computer_file/data/email_account/server = net.find_email_by_name(EMAIL_DOCUMENTS) + var/datum/computer_file/data/account/server = net.find_account_by_login(EMAIL_DOCUMENTS) var/datum/computer_file/data/email_message/message = new() message.title = subject message.stored_data = body message.source = server.login message.attachment = attach_report - server.send_mail(recipient, message, net) + net.send_email(server, recipient, message) /datum/report_field/people/proc/format_output(name, rank, milrank) . = list() @@ -89,10 +92,10 @@ var/dat = list() for(var/entry in value) var/milrank = entry["milrank"] - if(in_line && (GLOB.using_map.flags & MAP_HAS_RANK)) + if(in_line && (global.using_map.flags & MAP_HAS_RANK)) var/datum/computer_file/report/crew_record/CR = get_crewmember_record(entry["name"]) if(CR) - var/datum/mil_rank/rank_obj = mil_branches.get_rank(CR.get_branch(), CR.get_rank()) + var/datum/mil_rank/rank_obj = global.using_map.get_rank(CR.get_branch(), CR.get_rank()) milrank = (rank_obj ? rank_obj.name_short : "") dat += format_output(entry["name"], in_line ? null : entry["rank"], milrank) return jointext(dat, in_line ? ", " : "
    ") @@ -108,7 +111,7 @@ if(in_as_list(entry, new_value)) continue //ignore repeats new_value += list(entry) - value = new_value + value = new_value /datum/report_field/people/list_from_manifest/ask_value(mob/user) var/alert = alert(user, "Would you like to add or remove a name?", "Form Input", "Add", "Remove") diff --git a/code/modules/modular_computers/file_system/reports/report.dm b/code/modules/modular_computers/file_system/reports/report.dm index d61fb527a7b3..7d391fbb982c 100644 --- a/code/modules/modular_computers/file_system/reports/report.dm +++ b/code/modules/modular_computers/file_system/reports/report.dm @@ -5,55 +5,45 @@ var/form_name = "AB1" //Form code, for maximum bureaucracy. var/creator //The name of the mob that made the report. var/file_time //Time submitted. - var/list/access_edit = list(list()) //The access required to submit the report. See documentation below. - var/list/access = list(list()) //The access required to view the report. + write_access = list() //The access required to submit the report. + read_access = list() //The access required to view the report. + mod_access = list(list(access_bridge)) //Changing the read/write access of the file should generally require higher access than the write access itself. var/list/datum/report_field/fields = list() //A list of fields the report comes with, in order that they should be displayed. var/available_on_network = 0 //Whether this report type should show up for download. var/logo //Can be set to a pencode logo for use with some display methods. + var/list/searchable_fields = list() //The names of fields in the report which are searchable. /datum/computer_file/report/New() ..() generate_fields() + initialize_access() /datum/computer_file/report/Destroy() QDEL_NULL_LIST(fields) . = ..() /* -Access stuff. The report's access/access_edit should control whether it can be opened/submitted. -For field editing or viewing, use the field's access/access_edit permission instead. -The access system is based on "access patterns", lists of access values. -A user needs all access values in a pattern to be granted access. -A user needs to only match one of the potentially several stored access patterns to be granted access. -You must have access to have edit access. - -This proc resets the access to the report, resulting in just one access pattern for access/edit. -Arguments can be access values (numbers) or lists of access values. +This proc resets the access to the report, resulting in just one access requirement for read/write. If null is passed to one of the arguments, that access type is left alone. Pass list() to reset to no access needed instead. The recursive option resets access to all fields in the report as well. -If the override option is set to 0, the access supplied will instead be added as another access pattern, rather than resetting the access. */ -/datum/computer_file/report/proc/set_access(access, access_edit, recursive = 1, override = 1) - if(access) - if(!islist(access)) - access = list(access) - override ? (src.access = list(access)) : (src.access += list(access)) //Note that this is a list of lists. - if(access_edit) - if(!islist(access_edit)) - access_edit = list(access_edit) - override ? (src.access_edit = list(access_edit)) : (src.access_edit += list(access_edit)) +/datum/computer_file/report/proc/set_access(read_access, write_access, recursive = TRUE) + if(read_access) + if(!islist(read_access)) + read_access = list(read_access) + src.read_access = read_access + if(write_access) + if(!islist(write_access)) + write_access = list(write_access) + src.write_access = write_access if(recursive) for(var/datum/report_field/field in fields) - field.set_access(access, access_edit, override) + field.set_access(read_access, write_access, TRUE) -//Strongly recommended to use these procs to check for access. They can take access values (numbers) or lists of values. -/datum/computer_file/report/proc/verify_access(given_access) - return has_access_pattern(access, given_access) - -/datum/computer_file/report/proc/verify_access_edit(given_access) - if(!verify_access(given_access)) - return //Need access for access_edit - return has_access_pattern(access_edit, given_access) +// The default behavior propagates (non-empty) preset access to the fields which allow such propogation. +// You can override or modify this behavior on subtypes. +/datum/computer_file/report/proc/initialize_access() + set_access(length(read_access) ? read_access : null, length(write_access) ? write_access : null, TRUE) //Looking up fields. Names might not be unique unless you ensure otherwise. /datum/computer_file/report/proc/field_from_ID(ID) @@ -93,35 +83,37 @@ If the override option is set to 0, the access supplied will instead be added as filename = "[form_name]_[append]" //Don't add fields except through this proc. -/datum/computer_file/report/proc/add_field(field_type, name, value = null, required = 0) +/datum/computer_file/report/proc/add_field(field_type, name, value = null, required = 0, searchable = 0, can_mod_access = 1) var/datum/report_field/field = new field_type(src) field.name = name if(value) field.value = value if(required) field.required = 1 + if(searchable) + field.searchable = 1 + searchable_fields += field.name + field.can_mod_access = can_mod_access field.ID = sequential_id(type) fields += field return field -/datum/computer_file/report/clone() - var/datum/computer_file/report/temp = ..() - temp.title = title - temp.form_name = form_name - temp.creator = creator - temp.file_time = file_time - temp.access_edit = access_edit - temp.access = access +/datum/computer_file/report/PopulateClone(datum/computer_file/report/clone) + clone = ..() + clone.title = title + clone.form_name = form_name + clone.creator = creator + clone.file_time = file_time for(var/i = 1, i <= length(fields), i++) - var/datum/report_field/new_field = temp.fields[i] + var/datum/report_field/new_field = clone.fields[i] new_field.copy_value(fields[i]) - return temp + return clone /datum/computer_file/report/proc/display_name() return "Form [form_name]: [title]" //if access is given, will include access information by performing checks against it. -/datum/computer_file/report/proc/generate_nano_data(list/given_access) +/datum/computer_file/report/proc/generate_nano_data(list/given_access, mob/user) . = list() .["name"] = display_name() .["uid"] = uid @@ -129,28 +121,29 @@ If the override option is set to 0, the access supplied will instead be added as .["file_time"] = file_time .["fields"] = list() if(given_access) - .["access"] = verify_access(given_access) - .["access_edit"] = verify_access_edit(given_access) + var/access_flags = get_file_perms(given_access, user) + .["access"] = access_flags & OS_READ_ACCESS + .["access_edit"] = access_flags & OS_WRITE_ACCESS for(var/datum/report_field/field in fields) - .["fields"] += list(field.generate_nano_data(given_access)) + .["fields"] += list(field.generate_nano_data(given_access, user)) /* This formats the report into pencode for use with paper and printing. Setting access to null will bypass access checks. with_fields will include a field link after the field value (useful to print fillable forms). no_html will strip any html, possibly killing useful formatting in the process. */ -/datum/computer_file/report/proc/generate_pencode(access, with_fields, no_html) +/datum/computer_file/report/proc/generate_pencode(access, mob/user, with_fields, no_html) . = list() . += "\[center\][logo]\[/center\]" . += "\[center\]\[h2\][display_name()]\[/h2\]\[/center\]" . += "\[grid\]" for(var/datum/report_field/F in fields) - . += F.generate_row_pencode(access, with_fields) + . += F.generate_row_pencode(access, user, with_fields) . += "\[/grid\]" . = JOINTEXT(.) if(no_html) . = html2pencode(.) -//recipient reports have a designated recipients field, for recieving submitted reports. +//recipient reports have a designated recipients field, for receiving submitted reports. /datum/computer_file/report/recipient var/datum/report_field/people/list_from_manifest/recipients @@ -161,6 +154,27 @@ no_html will strip any html, possibly killing useful formatting in the process. /datum/computer_file/report/recipient/generate_fields() recipients = add_field(/datum/report_field/people/list_from_manifest, "Send Copies To") -/datum/computer_file/report/recipient/submit(mob/user) +/datum/computer_file/report/recipient/submit(mob/user, list/access) if((. = ..())) - recipients.send_email(user) \ No newline at end of file + recipients.send_email(user) + +/* +Access stuff. The report's read/write access should control whether it can be opened/submitted. +For field editing or viewing, use the field's read/write access instead. + +Overriden so that read access is required to have write access +*/ +/datum/computer_file/report/get_file_perms(list/accesses, mob/user) + var/perms = ..() + if(!(perms & OS_READ_ACCESS)) + perms &= ~OS_WRITE_ACCESS + return perms + +// Manually changing the permissions of a report will change *all* contained fields to match. +// TODO: Make report creation and access modification a bit more flexible. +/datum/computer_file/report/change_perms(change, perm, access_key, changer_accesses) + . = ..() + if(!.) + return + for(var/datum/report_field/field in fields) + field.set_access(read_access, write_access, TRUE) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/reports/report_field.dm b/code/modules/modular_computers/file_system/reports/report_field.dm index beda87aa3869..38ae04459fe8 100644 --- a/code/modules/modular_computers/file_system/reports/report_field.dm +++ b/code/modules/modular_computers/file_system/reports/report_field.dm @@ -1,14 +1,16 @@ /datum/report_field - var/datum/computer_file/report/owner //The report to which this field belongs. - var/name = "generic field" //The name the field will be labeled with. - var/value //Only used internally. - var/can_edit = 1 //Whether the field gives the user the option to edit it. - var/required = 0 //Whether the field is required to submit the report. - var/ID //A unique (per report) id; don't set manually. - var/needs_big_box = 0 //Suggests that the output won't look good in-line. Useful in nanoui logic. - var/ignore_value = 0 //Suggests that the value should not be displayed. - var/list/access_edit = list(list()) //The access required to edit the field. - var/list/access = list(list()) //The access required to view the field. + var/datum/computer_file/report/owner // The report to which this field belongs. + var/name = "generic field" // The name the field will be labeled with. + var/value // Only used internally. + var/can_edit = 1 // Whether the field gives the user the option to edit it. + var/required = 0 // Whether the field is required to submit the report. + var/ID // A unique (per report) id; don't set manually. + var/needs_big_box = 0 // Suggests that the output won't look good in-line. Useful in nanoui logic. + var/ignore_value = 0 // Suggests that the value should not be displayed. + var/searchable = 0 // Whether or not the field will be searchable in the crew records computer. + var/can_mod_access = TRUE // Whether or not the access requirements of this field can be modified recursively from the record's access. + var/list/read_access = list() // The access required to edit the field. + var/list/write_access = list() // The access required to view the field. /datum/report_field/New(datum/computer_file/report/report) owner = report @@ -19,29 +21,34 @@ . = ..() //Access stuff. Can be given access constants or lists. See report access procs for documentation. -/datum/report_field/proc/set_access(access, access_edit, override = 1) - if(access) - if(!islist(access)) - access = list(access) - override ? (src.access = list(access)) : (src.access += list(access)) - if(access_edit) - if(!islist(access_edit)) - access_edit = list(access_edit) - override ? (src.access_edit = list(access_edit)) : (src.access_edit += list(access_edit)) - -/datum/report_field/proc/verify_access(given_access) - return has_access_pattern(access, given_access) - -/datum/report_field/proc/verify_access_edit(given_access) - if(!verify_access(given_access)) +//For fields, the recursive argument indicates whether this access set is being propogated onto the whole report at once or not. +/datum/report_field/proc/set_access(read_access, write_access, recursive = FALSE) + if(recursive && !can_mod_access) return - return has_access_pattern(access_edit, given_access) + if(read_access) + if(!islist(read_access)) + read_access = list(read_access) + src.read_access = read_access + if(write_access) + if(!islist(write_access)) + write_access = list(write_access) + src.write_access = write_access + +// Analogous to get_file_perms on reports. Read access is required to have write access. +/datum/report_field/proc/get_perms(accesses, mob/user) + if(!accesses || (isghost(user) && check_rights(R_ADMIN, 0, user))) // For internal use/use by admin ghosts. + return (OS_READ_ACCESS | OS_WRITE_ACCESS) + if(!LAZYLEN(read_access) || has_access(read_access, accesses)) + . |= OS_READ_ACCESS + + if(!LAZYLEN(write_access) || has_access(write_access, accesses)) + . |= OS_WRITE_ACCESS //Assumes the old and new fields are of the same type. Override if the field stores information differently. /datum/report_field/proc/copy_value(datum/report_field/old_field) value = old_field.value - access = old_field.access - access_edit = old_field.access_edit + read_access = old_field.read_access + write_access = old_field.write_access //Gives the user prompts to fill out the field. /datum/report_field/proc/ask_value(mob/user) @@ -58,11 +65,11 @@ /datum/report_field/proc/display_name() return name -/datum/report_field/proc/generate_row_pencode(access, with_fields) +/datum/report_field/proc/generate_row_pencode(access, mob/user, with_fields) if(!ignore_value) . += "\[row\]\[cell\]\[b\][display_name()]:\[/b\]" var/field = ((with_fields && can_edit) ? "\[field\]" : "" ) - if(!access || verify_access(access)) + if(!access || (get_perms(access, user) & OS_READ_ACCESS)) . += (needs_big_box ? "\[/grid\][get_value()][field]\[grid\]" : "\[cell\][get_value()][field]") else . += "\[cell\]\[REDACTED\][field]" @@ -70,11 +77,12 @@ . += "\[/grid\][display_name()]\[grid\]" . = JOINTEXT(.) -/datum/report_field/proc/generate_nano_data(list/given_access) +/datum/report_field/proc/generate_nano_data(list/given_access, mob/user) var/dat = list() if(given_access) - dat["access"] = verify_access(given_access) - dat["access_edit"] = verify_access_edit(given_access) + var/access_flags = get_perms(given_access, user) + dat["access"] = access_flags & OS_READ_ACCESS + dat["access_edit"] = access_flags & OS_WRITE_ACCESS dat["name"] = display_name() dat["value"] = get_value() dat["can_edit"] = can_edit diff --git a/code/modules/modular_computers/file_system/reports/warrant.dm b/code/modules/modular_computers/file_system/reports/warrant.dm index b4566b0d27b9..e486810042f8 100644 --- a/code/modules/modular_computers/file_system/reports/warrant.dm +++ b/code/modules/modular_computers/file_system/reports/warrant.dm @@ -1,6 +1,9 @@ /datum/computer_file/report/warrant title = "Warrant" form_name = "W-104" + + write_access = list(list(access_security), list(access_bridge)) + read_access = list(list(access_security), list(access_bridge)) var/archived = FALSE /datum/computer_file/report/warrant/New() @@ -35,13 +38,13 @@ /datum/computer_file/report/warrant/arrest title = "Arrest Warrant" form_name = "W-104-A" + write_access = list(access_security) /datum/computer_file/report/warrant/arrest/generate_fields() add_field(/datum/report_field/text_label/header, "Arrest Warrant") add_field(/datum/report_field/simple_text, "Name", "Unknown") add_field(/datum/report_field/pencode_text, "Charges", "No charges") add_field(/datum/report_field/signature, "Authorized by", "Unathorized") - set_access(access_edit = access_security) /datum/computer_file/report/warrant/arrest/get_category() . = ..() @@ -59,13 +62,13 @@ Arrest Warramt: [get_name()]

    Warrant Tracker System

    Issued in the jurisdiction of the
    - [GLOB.using_map.boss_name] in [GLOB.using_map.system_name]
    + [global.using_map.boss_name] in [global.using_map.system_name]

    ARREST WARRANT


    This document serves as authorization and notice for the arrest of _[get_name()]____ for the crime(s) of:
    [get_reason()]

    - Vessel or habitat: _[GLOB.using_map.station_name]____
    + Vessel or habitat: _[global.using_map.station_name]____

    _[get_auth()]____
    Person authorizing arrest
    @@ -74,13 +77,13 @@ /datum/computer_file/report/warrant/search title = "Search Warrant" form_name = "W-104-S" + write_access = list(access_security) /datum/computer_file/report/warrant/search/generate_fields() add_field(/datum/report_field/text_label/header, "Search Warrant") add_field(/datum/report_field/simple_text, "Person/Location", "Unknown") add_field(/datum/report_field/pencode_text, "Reason", "No reason") add_field(/datum/report_field/signature, "Authorized by", "Unathorized") - set_access(access_edit = access_security) /datum/computer_file/report/warrant/search/get_category() . = ..() @@ -98,7 +101,7 @@ Search Warrant: [get_name()]

    Warrant Tracker System

    Issued in the jurisdiction of the
    - [GLOB.using_map.boss_name] in [GLOB.using_map.system_name]
    + [global.using_map.boss_name] in [global.using_map.system_name]

    SEARCH WARRANT


    @@ -108,7 +111,7 @@
    Warrant issued by: [get_auth()]

    - Vessel or habitat: _[GLOB.using_map.station_name]____
    + Vessel or habitat: _[global.using_map.station_name]____

    The Security Officer(s) bearing this Warrant are hereby authorized by the Issuer to conduct a one time lawful search of the Suspect's person/belongings/premises and/or Department for any items and materials that could be connected to the suspected criminal act described below, pending an investigation in progress.

    diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm index 49cd8a4a596d..2d87a04d59ad 100644 --- a/code/modules/modular_computers/hardware/_hardware.dm +++ b/code/modules/modular_computers/hardware/_hardware.dm @@ -10,18 +10,26 @@ var/usage_flags = PROGRAM_ALL var/external_slot // Whether attackby will be passed on it even with a closed panel -/obj/item/stock_parts/computer/attackby(var/obj/item/W, var/mob/living/user) +/obj/item/stock_parts/computer/attackby(var/obj/item/used_item, var/mob/user) // Multitool. Runs diagnostics - if(isMultitool(W)) + if(IS_MULTITOOL(used_item)) to_chat(user, "***** DIAGNOSTICS REPORT *****") to_chat(user, jointext(diagnostics(), "\n")) to_chat(user, "******************************") - return 1 + return TRUE return ..() +/obj/item/stock_parts/computer/on_install(obj/machinery/machine) + . = ..() + do_after_install(machine, TRUE) + +/obj/item/stock_parts/computer/on_uninstall(obj/machinery/machine, temporary) + do_before_uninstall(machine, TRUE) + . = ..() + // Called on multitool click, prints diagnostic information to the user. /obj/item/stock_parts/computer/proc/diagnostics() - return list("Hardware Integrity Test... (Corruption: [initial(health) - health]/[initial(health)])") + return list("Hardware Integrity Test... (Corruption: [get_percent_damages()]%)") /obj/item/stock_parts/computer/Initialize() . = ..() @@ -43,9 +51,13 @@ // Called when component is disabled/enabled by the OS /obj/item/stock_parts/computer/proc/on_disable() -/obj/item/stock_parts/computer/proc/on_enable(var/datum/extension/interactive/ntos/os) +/obj/item/stock_parts/computer/proc/on_enable(var/datum/extension/interactive/os/os) /obj/item/stock_parts/computer/proc/update_power_usage() - var/datum/extension/interactive/ntos/os = get_extension(loc, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(loc, /datum/extension/interactive/os) if(os) os.recalc_power_usage() + +/obj/item/stock_parts/computer/proc/do_after_install(atom/device, loud) + +/obj/item/stock_parts/computer/proc/do_before_uninstall(atom/device, loud) \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/ai_slot.dm b/code/modules/modular_computers/hardware/ai_slot.dm index 39c135c6f58d..02594ca9006a 100644 --- a/code/modules/modular_computers/hardware/ai_slot.dm +++ b/code/modules/modular_computers/hardware/ai_slot.dm @@ -1,12 +1,12 @@ -// A wrapper that allows the computer to contain an inteliCard. +// A wrapper that allows the computer to contain an intelliCard. /obj/item/stock_parts/computer/ai_slot - name = "inteliCard slot" - desc = "An IIS interlink with connection uplinks that allow the device to interface with most common inteliCard models. Too large to fit into tablets. Uses a lot of power when active." + name = "intelliCard slot" + desc = "An IIS interlink with connection uplinks that allow the device to interface with most common intelliCard models. Too large to fit into tablets. Uses a lot of power when active." icon_state = "aislot" hardware_size = 1 critical = 0 power_usage = 100 - origin_tech = "{'powerstorage':2,'programming':3}" + origin_tech = @'{"powerstorage":2,"programming":3}' external_slot = TRUE material = /decl/material/solid/metal/steel @@ -21,20 +21,20 @@ power_usage = power_usage_occupied ..() -/obj/item/stock_parts/computer/ai_slot/attackby(var/obj/item/W, var/mob/user) - if(..()) - return 1 - if(istype(W, /obj/item/aicard)) +/obj/item/stock_parts/computer/ai_slot/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/aicard)) if(stored_card) to_chat(user, "\The [src] is already occupied.") - return - if(!user.unEquip(W, src)) - return - do_insert_ai(user, W) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + do_insert_ai(user, used_item) return TRUE - if(isScrewdriver(W)) + if(stored_card && IS_SCREWDRIVER(used_item)) to_chat(user, "You manually remove \the [stored_card] from \the [src].") do_eject_ai(user) + return TRUE + return ..() /obj/item/stock_parts/computer/ai_slot/Destroy() if(stored_card) @@ -58,14 +58,15 @@ device = locate() in src if(!device.stored_card) - to_chat(user, "There is no intellicard connected to \the [src].") + to_chat(user, "There is no intelliCard connected to \the [src].") return device.do_eject_ai(user) /obj/item/stock_parts/computer/ai_slot/proc/do_eject_ai(mob/user) - stored_card.dropInto(loc) - stored_card = null + if(stored_card) + stored_card.dropInto(loc) + stored_card = null loc.verbs -= /obj/item/stock_parts/computer/ai_slot/verb/eject_ai diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm index 0d3cd9d4ec09..52f0b478b337 100644 --- a/code/modules/modular_computers/hardware/battery_module.dm +++ b/code/modules/modular_computers/hardware/battery_module.dm @@ -2,57 +2,79 @@ // have tremendeous capacity in comparsion. Higher tier cells would provide your device with nearly infinite battery life, which is something i want to avoid. /obj/item/stock_parts/computer/battery_module name = "standard battery" - desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops. It's rating is 75 Wh." + desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops. Its rating is 75 Wh." icon_state = "battery_normal" critical = 1 - origin_tech = "{'powerstorage':1,'engineering':1}" + origin_tech = @'{"powerstorage":1,"engineering":1}' material = /decl/material/solid/metal/steel - var/battery_rating = 75 - var/obj/item/cell/battery = /obj/item/cell + +/obj/item/stock_parts/computer/battery_module/Initialize() + . = ..() + setup_power_supply() + charge_to_full() + +/obj/item/stock_parts/computer/battery_module/diagnostics() + . = ..() + var/obj/item/cell/battery = get_cell() + if(battery) + . += "Internal battery charge: [battery.charge]/[battery.maxcharge] CU" + +/obj/item/stock_parts/computer/battery_module/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell + . = ..(loaded_cell_type, /obj/item/cell, /datum/extension/loaded_cell/unremovable, charge_value) + var/obj/item/cell/battery = get_cell() + if(battery) + battery.maxcharge = battery_rating + battery.charge = 0 + +/obj/item/stock_parts/computer/battery_module/proc/charge_to_full() + var/obj/item/cell/battery = get_cell() + if(battery) + battery.charge = battery.maxcharge /obj/item/stock_parts/computer/battery_module/advanced name = "advanced battery" - desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices. It's rating is 110 Wh." + desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices. Its rating is 110 Wh." icon_state = "battery_advanced" - origin_tech = "{'powerstorage':2,'engineering':2}" + origin_tech = @'{"powerstorage":2,"engineering":2}' hardware_size = 2 battery_rating = 110 material = /decl/material/solid/metal/steel /obj/item/stock_parts/computer/battery_module/super name = "super battery" - desc = "A very advanced power cell, often used in high-end devices, or as uninterruptable power supply for important consoles or servers. It's rating is 150 Wh." + desc = "A very advanced power cell, often used in high-end devices, or as uninterruptible power supply for important consoles or servers. Its rating is 150 Wh." icon_state = "battery_super" - origin_tech = "{'powerstorage':3,'engineering':3}" + origin_tech = @'{"powerstorage":3,"engineering":3}' hardware_size = 2 battery_rating = 150 material = /decl/material/solid/metal/steel /obj/item/stock_parts/computer/battery_module/ultra name = "ultra battery" - desc = "A very advanced large power cell. It's often used as uninterruptable power supply for critical consoles or servers. It's rating is 200 Wh." + desc = "A very advanced large power cell. It's often used as an uninterruptible power supply for critical consoles or servers. Its rating is 200 Wh." icon_state = "battery_ultra" - origin_tech = "{'powerstorage':5,'engineering':4}" + origin_tech = @'{"powerstorage":5,"engineering":4}' hardware_size = 3 battery_rating = 200 material = /decl/material/solid/metal/steel /obj/item/stock_parts/computer/battery_module/micro name = "micro battery" - desc = "A small power cell, commonly seen in most portable microcomputers. It's rating is 50 Wh." + desc = "A small power cell, commonly seen in most portable microcomputers. Its rating is 50 Wh." icon_state = "battery_micro" - origin_tech = "{'powerstorage':2,'engineering':2}" + origin_tech = @'{"powerstorage":2,"engineering":2}' battery_rating = 50 material = /decl/material/solid/metal/steel /obj/item/stock_parts/computer/battery_module/nano name = "nano battery" - desc = "A tiny power cell, commonly seen in low-end portable microcomputers. It's rating is 30 Wh." + desc = "A tiny power cell, commonly seen in low-end portable microcomputers. Its rating is 30 Wh." icon_state = "battery_nano" - origin_tech = "{'powerstorage':1,'engineering':1}" battery_rating = 30 material = /decl/material/solid/metal/steel + origin_tech = @'{"powerstorage":2,"engineering":1}' // This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes. /obj/item/stock_parts/computer/battery_module/lambda @@ -61,26 +83,6 @@ icon_state = "battery_lambda" hardware_size = 1 battery_rating = 3000 - battery = /obj/item/cell/infinite - -/obj/item/stock_parts/computer/battery_module/diagnostics() - . = ..() - . += "Internal battery charge: [battery.charge]/[battery.maxcharge] CU" - -/obj/item/stock_parts/computer/battery_module/Initialize() - . = ..() - battery = new battery(src) - battery.maxcharge = battery_rating - battery.charge = 0 - charge_to_full() - -/obj/item/stock_parts/computer/battery_module/Destroy() - QDEL_NULL(battery) - return ..() - -/obj/item/stock_parts/computer/battery_module/proc/charge_to_full() - if(battery) - battery.charge = battery.maxcharge -/obj/item/stock_parts/computer/battery_module/get_cell() - return battery +/obj/item/stock_parts/computer/battery_module/lambda/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/infinite, accepted_cell_type, power_supply_extension_type, charge_value) diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm index 3dc8c4076ca3..62ad6a78a842 100644 --- a/code/modules/modular_computers/hardware/card_slot.dm +++ b/code/modules/modular_computers/hardware/card_slot.dm @@ -1,16 +1,16 @@ /obj/item/stock_parts/computer/card_slot name = "RFID card slot" desc = "Slot that allows this computer to write data on RFID cards. Necessary for some programs to run properly." - power_usage = 10 //W + power_usage = 10 // W critical = 0 icon_state = "cardreader" hardware_size = 1 - origin_tech = "{'programming':2}" + origin_tech = @'{"programming":2}' usage_flags = PROGRAM_ALL & ~PROGRAM_PDA external_slot = TRUE material = /decl/material/solid/metal/steel - var/can_write = TRUE + // TODO: reimplment RFID card write access and can_write var/can_broadcast = FALSE var/obj/item/card/id/stored_card = null @@ -29,7 +29,7 @@ read_string_stability = 80 . += "Registered Name: [stars(stored_card.registered_name, read_string_stability)]\n" . += "Registered Assignment: [stars(stored_card.assignment, read_string_stability)]\n" - . += "Registered Rank: [stars(stored_card.rank, read_string_stability)]\n" + . += "Registered Position: [stars(stored_card.position, read_string_stability)]\n" . += "Access Addresses Enabled: \n" var/list/access_list = stored_card.GetAccess() if(!access_list) // "NONE" for empty list @@ -40,7 +40,7 @@ if(check_functionality()) // Read the access, or show "RD_ERR" var/datum/access/access_information = get_access_by_id(access_id) var/access_type = access_information.access_type - if(access_type == ACCESS_TYPE_NONE || access_type == ACCESS_TYPE_SYNDICATE || access_type == ACCESS_TYPE_CENTCOM) // Don't elaborate on these access types. + if(access_type == ACCESS_TYPE_NONE || access_type == ACCESS_TYPE_ANTAG || access_type == ACCESS_TYPE_CENTCOM) // Don't elaborate on these access types. list_of_accesses += "UNKNOWN" // "UNKNOWN" else list_of_accesses += uppertext(access_information.desc) @@ -63,7 +63,7 @@ if(!device.stored_card) if(usr) - to_chat(usr, "There is no card in \the [src]") + to_chat(usr, "There is no card in \the [src].") return device.eject_id(usr) @@ -79,7 +79,7 @@ dropInto(loc) stored_card = null - var/datum/extension/interactive/ntos/os = get_extension(loc, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(loc, /datum/extension/interactive/os) if(os) os.event_idremoved() loc.verbs -= /obj/item/stock_parts/computer/card_slot/proc/verb_eject_id @@ -93,7 +93,7 @@ to_chat(user, "You try to insert [I] into [src], but its ID card slot is occupied.") return FALSE - if(user && !user.unEquip(I, src)) + if(user && !user.try_unequip(I, src)) return FALSE stored_card = I @@ -102,16 +102,15 @@ loc.verbs |= /obj/item/stock_parts/computer/card_slot/proc/verb_eject_id return TRUE -/obj/item/stock_parts/computer/card_slot/attackby(obj/item/card/id/I, mob/living/user) - if(!istype(I)) - return - insert_id(I, user) +/obj/item/stock_parts/computer/card_slot/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/card/id)) + return ..() + insert_id(used_item, user) return TRUE /obj/item/stock_parts/computer/card_slot/broadcaster // read only name = "RFID card broadcaster" desc = "Reads and broadcasts the RFID signal of an inserted card." - can_write = FALSE can_broadcast = TRUE usage_flags = PROGRAM_PDA diff --git a/code/modules/modular_computers/hardware/charge_stick_slot.dm b/code/modules/modular_computers/hardware/charge_stick_slot.dm index ab96ed958fc9..4e3087c7db54 100644 --- a/code/modules/modular_computers/hardware/charge_stick_slot.dm +++ b/code/modules/modular_computers/hardware/charge_stick_slot.dm @@ -1,29 +1,32 @@ /obj/item/stock_parts/computer/charge_stick_slot name = "charge-stick slot" desc = "Slot that allows this computer to pay for transactions using an inserted charge-stick." - power_usage = 10 //W + power_usage = 10 // W critical = 0 icon_state = "cardreader" hardware_size = 1 - origin_tech = "{'programming':2}" + origin_tech = @'{"programming":2}' usage_flags = PROGRAM_ALL & ~PROGRAM_PDA external_slot = TRUE material = /decl/material/solid/metal/steel - var/can_write = TRUE var/can_broadcast = FALSE + // TODO: reimplment charge stick write access and can_write var/obj/item/charge_stick/stored_stick = null /obj/item/stock_parts/computer/charge_stick_slot/proc/get_currency_name() - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) return cur.name /obj/item/stock_parts/computer/charge_stick_slot/diagnostics() . = ..() - . += "[name] status: [stored_stick ? "[get_currency_name()]-stick Inserted" : "[get_currency_name()]-stick Not Present"]\n" - . += "Stick status: [stored_stick.is_locked() ? "Locked" : "Unlocked"]\n" + . += "[name] status: [stored_stick ? "[get_currency_name()]-stick Inserted" : "[get_currency_name()]-stick Not Present"]" + if(!stored_stick) + . += "\nStick status: Missing" + else + . += "\nStick status: [stored_stick.is_locked() ? "Locked" : "Unlocked"]" if(!stored_stick.is_locked()) - . += "Stick balance: [stored_stick.loaded_worth]\n" + . += "\nStick balance: [stored_stick.loaded_worth]" /obj/item/stock_parts/computer/charge_stick_slot/proc/verb_eject_stick() set name = "Remove Charge-stick" @@ -40,7 +43,7 @@ if(!device.stored_stick) if(usr) - to_chat(usr, "There is no [get_currency_name()]-stick in \the [src]") + to_chat(usr, "There is no [get_currency_name()]-stick in \the [src].") return device.eject_stick(usr) @@ -56,7 +59,7 @@ dropInto(loc) stored_stick = null - var/datum/extension/interactive/ntos/os = get_extension(loc, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(loc, /datum/extension/interactive/os) if(os) os.event_idremoved() loc.verbs -= /obj/item/stock_parts/computer/charge_stick_slot/proc/verb_eject_stick @@ -70,7 +73,7 @@ to_chat(user, "You try to insert [I] into [src], but its [get_currency_name()]-stick slot is occupied.") return FALSE - if(user && !user.unEquip(I, src)) + if(user && !user.try_unequip(I, src)) return FALSE stored_stick = I @@ -79,16 +82,15 @@ loc.verbs |= /obj/item/stock_parts/computer/charge_stick_slot/proc/verb_eject_stick return TRUE -/obj/item/stock_parts/computer/charge_stick_slot/attackby(obj/item/card/id/I, mob/living/user) - if(!istype(I)) - return - insert_stick(I, user) +/obj/item/stock_parts/computer/charge_stick_slot/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/charge_stick)) + return ..() + insert_stick(used_item, user) return TRUE /obj/item/stock_parts/computer/charge_stick_slot/broadcaster // read only name = "NFC charge-stick broadcaster" desc = "Reads and broadcasts the NFC signal of an inserted charge-stick." - can_write = FALSE can_broadcast = TRUE usage_flags = PROGRAM_PDA diff --git a/code/modules/modular_computers/hardware/disk_slot.dm b/code/modules/modular_computers/hardware/disk_slot.dm new file mode 100644 index 000000000000..47831abe7613 --- /dev/null +++ b/code/modules/modular_computers/hardware/disk_slot.dm @@ -0,0 +1,111 @@ +/obj/item/stock_parts/computer/data_disk_drive + name = "data disk slot" + desc = "Slot that allows this computer to accept data disks." + power_usage = 10 // W + critical = 0 + icon_state = "cardreader" + hardware_size = 1 + origin_tech = @'{"programming":2}' + usage_flags = PROGRAM_ALL + external_slot = TRUE + material = /decl/material/solid/metal/steel + + var/obj/item/disk/stored_disk = null + var/mount_name + +/obj/item/stock_parts/computer/data_disk_drive/diagnostics() + . = ..() + . += "[name] status: [stored_disk ? "Disk Inserted" : "Disk Not Present"]\n" + +/obj/item/stock_parts/computer/data_disk_drive/proc/verb_eject_disk() + set name = "Remove Disk" + set category = "Object" + set src in view(1) + + if(!CanPhysicallyInteract(usr)) + to_chat(usr, SPAN_WARNING("You can't reach it.")) + return + + var/obj/item/stock_parts/computer/data_disk_drive/device = src + if (!istype(device)) + device = locate() in src + + if(!istype(device)) + return + + if(!device.stored_disk) + if(usr) + to_chat(usr, "There is no drive in \the [src].") + return + + device.eject_disk(usr) + +/obj/item/stock_parts/computer/data_disk_drive/proc/eject_disk(mob/user) + if(!stored_disk) + return FALSE + + if(user) + to_chat(user, "You remove [stored_disk] from [src].") + user.put_in_hands(stored_disk) + else + dropInto(loc) + stored_disk = null + + loc.verbs -= /obj/item/stock_parts/computer/data_disk_drive/proc/verb_eject_disk + return TRUE + +/obj/item/stock_parts/computer/data_disk_drive/proc/insert_disk(obj/item/disk/new_disk, mob/user) + if(!istype(new_disk)) + return FALSE + + if(stored_disk) + to_chat(user, "You try to insert [new_disk] into [src], but its data disk slot is occupied.") + return FALSE + + if(user && !user.try_unequip(new_disk, src)) + return FALSE + + stored_disk = new_disk + to_chat(user, "You insert [new_disk] into [src].") + if(isobj(loc)) + loc.verbs |= /obj/item/stock_parts/computer/data_disk_drive/proc/verb_eject_disk + return TRUE + +/obj/item/stock_parts/computer/data_disk_drive/proc/mount_filesystem(datum/extension/interactive/os/os) + return os?.mount_storage(/datum/file_storage/disk/datadisk, "data", FALSE) + +/obj/item/stock_parts/computer/data_disk_drive/do_after_install(atom/device, loud) + var/datum/extension/interactive/os/os = get_extension(device, /datum/extension/interactive/os) + if(!os?.on) + return FALSE + + var/datum/file_storage/new_storage = mount_filesystem(os) + if(new_storage) + mount_name = new_storage.root_name + if(loud) + os.visible_notification("Mounted data disk as filesystem with root directory '[new_storage.root_name]'.") + return TRUE + else + if(loud) + os.visible_error("Failed to mount data disk. Disk may be non-functional.") + return FALSE + +/obj/item/stock_parts/computer/data_disk_drive/do_before_uninstall(atom/device, loud) + var/datum/extension/interactive/os/os = get_extension(device, /datum/extension/interactive/os) + if(!os) + return FALSE + + os.unmount_storage(mount_name) + +/obj/item/stock_parts/computer/data_disk_drive/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/disk)) + return ..() + insert_disk(used_item, user) + return TRUE + +/obj/item/stock_parts/computer/data_disk_drive/Destroy() + if(loc) + loc.verbs -= /obj/item/stock_parts/computer/data_disk_drive/proc/verb_eject_disk + if(stored_disk) + QDEL_NULL(stored_disk) + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/drive_slot.dm b/code/modules/modular_computers/hardware/drive_slot.dm index 345eaa5e16c6..c584eb9c284a 100644 --- a/code/modules/modular_computers/hardware/drive_slot.dm +++ b/code/modules/modular_computers/hardware/drive_slot.dm @@ -1,16 +1,17 @@ /obj/item/stock_parts/computer/drive_slot name = "removable drive slot" desc = "Slot that allows this computer to accept removable drives." - power_usage = 10 //W + power_usage = 10 // W critical = 0 icon_state = "cardreader" hardware_size = 1 - origin_tech = "{'programming':2}" + origin_tech = @'{"programming":2}' usage_flags = PROGRAM_ALL external_slot = TRUE material = /decl/material/solid/metal/steel var/obj/item/stock_parts/computer/hard_drive/portable/stored_drive = null + var/mount_name /obj/item/stock_parts/computer/drive_slot/diagnostics() . = ..() @@ -31,7 +32,7 @@ if(!device.stored_drive) if(usr) - to_chat(usr, "There is no drive in \the [src]") + to_chat(usr, "There is no drive in \the [src].") return device.eject_drive(usr) @@ -58,7 +59,7 @@ to_chat(user, "You try to insert [I] into [src], but its portable drive slot is occupied.") return FALSE - if(user && !user.unEquip(I, src)) + if(user && !user.try_unequip(I, src)) return FALSE stored_drive = I @@ -67,10 +68,36 @@ loc.verbs |= /obj/item/stock_parts/computer/drive_slot/proc/verb_eject_drive return TRUE -/obj/item/stock_parts/computer/drive_slot/attackby(obj/item/stock_parts/computer/hard_drive/portable/I, mob/living/user) - if(!istype(I)) - return - insert_drive(I, user) +/obj/item/stock_parts/computer/drive_slot/proc/mount_filesystem(datum/extension/interactive/os/os) + return os?.mount_storage(/datum/file_storage/disk/removable, "media", FALSE) + +/obj/item/stock_parts/computer/drive_slot/do_after_install(atom/device, loud) + var/datum/extension/interactive/os/os = get_extension(device, /datum/extension/interactive/os) + if(!os?.on) // if it's off, it'll be handled on boot + return FALSE + + var/datum/file_storage/new_storage = mount_filesystem(os) + if(new_storage) + mount_name = new_storage.root_name + if(loud) + device.visible_message(SPAN_NOTICE("\The [device] pings: Mounted removable hard drive as file system with root directory '[new_storage.root_name]'.")) + return TRUE + else + if(loud) + device.visible_message(SPAN_WARNING("\The [device] flashes an error: Failed to mount removable harddrive. Hard drive may be non-functional.")) + return FALSE + +/obj/item/stock_parts/computer/drive_slot/do_before_uninstall(atom/device, loud) + var/datum/extension/interactive/os/os = get_extension(device, /datum/extension/interactive/os) + if(!os) + return FALSE + + os.unmount_storage(mount_name) + +/obj/item/stock_parts/computer/drive_slot/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/stock_parts/computer/hard_drive/portable)) + return ..() + insert_drive(used_item, user) return TRUE /obj/item/stock_parts/computer/drive_slot/Destroy() diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm index cda3da8933c5..d800a7b4c316 100644 --- a/code/modules/modular_computers/hardware/hard_drive.dm +++ b/code/modules/modular_computers/hardware/hard_drive.dm @@ -4,68 +4,68 @@ power_usage = 25 // SSD or something with low power usage icon_state = "hdd_normal" hardware_size = 1 - origin_tech = "{'programming':1,'engineering':1}" + origin_tech = @'{"programming":1,"engineering":1}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) var/max_capacity = 128 var/used_capacity = 0 - var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY! + var/list/stored_files = list() // Dictionary of stored files on this drive, with file->weakref of directory. DO NOT MODIFY DIRECTLY! /obj/item/stock_parts/computer/hard_drive/advanced name = "advanced hard drive" desc = "A small hybrid hard drive with 256GQ of storage capacity for use in higher grade computers where balance between power efficiency and capacity is desired." max_capacity = 256 - origin_tech = "{'programming':2,'engineering':2}" + origin_tech = @'{"programming":2,"engineering":2}' power_usage = 50 // Hybrid, medium capacity and medium power storage icon_state = "hdd_advanced" hardware_size = 2 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/hard_drive/super name = "super hard drive" desc = "A small hard drive with 512GQ of storage capacity for use in cluster storage solutions where capacity is more important than power efficiency." max_capacity = 512 - origin_tech = "{'programming':3,'engineering':3}" + origin_tech = @'{"programming":3,"engineering":3}' power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link. icon_state = "hdd_super" hardware_size = 2 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/hard_drive/cluster name = "cluster hard drive" desc = "A large storage cluster consisting of multiple hard drives for usage in high capacity storage systems. Has capacity of 2048 GQ." power_usage = 500 - origin_tech = "{'programming':4,'engineering':4}" + origin_tech = @'{"programming":4,"engineering":4}' max_capacity = 2048 icon_state = "hdd_cluster" hardware_size = 3 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) // For tablets, etc. - highly power efficient. /obj/item/stock_parts/computer/hard_drive/small name = "small hard drive" desc = "A small highly efficient solid state drive for portable devices." power_usage = 10 - origin_tech = "{'programming':2,'engineering':2}" + origin_tech = @'{"programming":2,"engineering":2}' max_capacity = 64 icon_state = "hdd_small" hardware_size = 1 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/hard_drive/micro name = "micro hard drive" desc = "A small micro hard drive for portable devices." power_usage = 2 - origin_tech = "{'programming':1,'engineering':1}" + origin_tech = @'{"programming":1,"engineering":1}' max_capacity = 32 icon_state = "hdd_micro" hardware_size = 1 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/hard_drive/diagnostics() . = ..() @@ -73,40 +73,147 @@ . += "NFS File Table Status: [stored_files.len]/999" . += "Storage capacity: [used_capacity]/[max_capacity]GQ" -// Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. -/obj/item/stock_parts/computer/hard_drive/proc/store_file(var/datum/computer_file/F) - if(!try_store_file(F)) - return 0 - F.holder = src - stored_files.Add(F) - recalculate_size() - return 1 +/obj/item/stock_parts/computer/hard_drive/Initialize() + . = ..() + install_default_programs() + +/obj/item/stock_parts/computer/hard_drive/Destroy() + stored_files = null + return ..() // Add programs that the disk will spawn with /obj/item/stock_parts/computer/hard_drive/proc/install_default_programs() - store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar - store_file(new/datum/computer_file/program/appdownloader(src)) // Downloader Utility, allows users to download more software from loca repositories - store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation. + var/datum/computer_file/directory/program_directory = add_directory(OS_PROGRAMS_DIR) + program_directory.unrenamable = TRUE // Protect the program directory from renaming/deletion. + program_directory.undeletable = TRUE + store_file(new/datum/computer_file/program/computerconfig(src), program_directory) // Computer configuration utility, allows hardware control and displays more info than status bar + store_file(new/datum/computer_file/program/appdownloader(src), program_directory) // Downloader Utility, allows users to download more software from loca repositories + store_file(new/datum/computer_file/program/filemanager(src), program_directory) // File manager, allows text editor functions and basic file manipulation. + return program_directory + +// Use this proc to add file to the drive. Returns OS_FILE_SUCCESS on success and error codes on failure. Contains necessary sanity checks. +/obj/item/stock_parts/computer/hard_drive/proc/store_file(var/datum/computer_file/F, var/directory, var/create_directories = FALSE, var/list/accesses, var/mob/user, var/overwrite = TRUE) + var/datum/computer_file/directory/target = parse_directory(directory, create_directories) + if(!istype(target) && directory) // The directory could not be parsed or created + return target + var/store_file = try_store_file(F, target, accesses, user) + if(store_file != OS_FILE_SUCCESS) + if(store_file == OS_FILE_EXISTS) + if(!overwrite) + return store_file + // Remove the duplicate file. + var/datum/computer_file/old = find_file_by_name(F.filename, target) + if(!istype(old)) // Something went wrong since we already found this file earlier. + return OS_HARDDRIVE_ERROR + + var/removed = remove_file(old, accesses, user) + if(removed != OS_FILE_SUCCESS) + return removed // Return the error code from removing the file. + + // If we've reached this point, we are able to store the file, since we successfully removed the old version. + // try_store_file() is intentionally written so that existing file checks are returned only if all other checks pass. + else + return store_file + if(istype(F, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = F + for(var/datum/computer_file/child in dir.get_held_files()) + stored_files[child] = dir + child.holder = weakref(src) + dir.temp_file_refs.Cut() // No longer need these references to the directory's stored files. -// Use this proc to remove file from the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. -/obj/item/stock_parts/computer/hard_drive/proc/remove_file(var/datum/computer_file/F) - if(!F || !istype(F)) - return 0 + F.holder = weakref(src) + if(target) + if(target.inherit_perms) // Add the permissions of the directory to the file's. + if(LAZYLEN(target.read_access)) + LAZYDISTINCTADD(F.read_access, target.read_access) + if(LAZYLEN(target.write_access)) + LAZYDISTINCTADD(F.write_access, target.write_access) + if(LAZYLEN(target.mod_access)) + LAZYDISTINCTADD(F.mod_access, target.mod_access) + stored_files[F] = target + target.held_files += weakref(F) + else + stored_files += F + recalculate_size() + return OS_FILE_SUCCESS + +// Use this proc to remove file from the drive. Returns OS_FILE_SUCCESS on success and error codes on failure. Contains necessary sanity checks. +/obj/item/stock_parts/computer/hard_drive/proc/remove_file(var/datum/computer_file/F, list/accesses, mob/user, forced) + if(!istype(F) || !(F in stored_files)) + return OS_FILE_NOT_FOUND if(!stored_files) - return 0 + return OS_HARDDRIVE_ERROR - if(!check_functionality()) - return 0 + if(!forced) + if(!check_functionality()) + return OS_HARDDRIVE_ERROR - if(F in stored_files) - stored_files -= F - F.holder = null - recalculate_size() - return 1 + if(F.undeletable) + return OS_FILE_NO_WRITE + + if(!(F.get_file_perms(accesses, user) & OS_WRITE_ACCESS)) + return OS_FILE_NO_WRITE + + var/list/removed_files = list(F) + + if(istype(F, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = F + var/list/dir_files = dir.get_held_files() + if(!forced) + if(!(dir.get_held_perms(accesses, user) & OS_WRITE_ACCESS)) + return OS_FILE_NO_WRITE + for(var/datum/computer_file/child in dir_files) + if(child.undeletable) + return OS_FILE_NO_WRITE + removed_files |= dir_files + + // Store references to the removed files temporarily to prevent them being GC'd, in case we're + // transferring this directory elsewhere. + dir.temp_file_refs += dir_files + + for(var/datum/computer_file/removed in removed_files) + var/datum/computer_file/directory/dir = stored_files[removed] + + // File is being removed without the directory, they're going their seperate ways. + if(dir && !(dir in removed_files)) + dir.held_files -= weakref(removed) + dir.temp_file_refs -= removed + stored_files -= removed + removed.holder = null + recalculate_size() + return OS_FILE_SUCCESS + +// Saves a file, either overwriting the data of a previous file or saving a new one. +/obj/item/stock_parts/computer/hard_drive/proc/save_file(filename, directory, new_data, list/metadata, list/accesses, mob/user, file_type = /datum/computer_file/data) + var/datum/computer_file/F = find_file_by_name(filename, directory) + + if(istype(F) && !(F.get_file_perms(accesses, user) & OS_WRITE_ACCESS)) + return OS_FILE_NO_WRITE + //Try to save file, possibly won't fit size-wise + var/datum/computer_file/backup + if(istype(F)) + backup = F.Clone() + remove_file(F) else - return 0 + F = new file_type() + F.filename = filename + if(istype(F, /datum/computer_file/data)) + var/datum/computer_file/data/D = F + D.stored_data = new_data + D.calculate_size() + F.metadata = metadata && metadata.Copy() + + var/success = store_file(F, directory, FALSE, accesses, user) + if(success != OS_FILE_SUCCESS) + if(backup) + store_file(backup, directory) + return success + + if(backup) + qdel(backup) + return F // Loops through all stored files and recalculates used_capacity of this drive /obj/item/stock_parts/computer/hard_drive/proc/recalculate_size() @@ -121,66 +228,146 @@ // In the unlikely event someone manages to create that many files. // BYOND is acting weird with numbers above 999 in loops (infinite loop prevention) if(stored_files.len >= 999) - return 0 + return FALSE if(used_capacity + size > max_capacity) - return 0 + return FALSE else - return 1 + return TRUE // Checks whether we can store the file. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file. -/obj/item/stock_parts/computer/hard_drive/proc/try_store_file(var/datum/computer_file/F) - if(!F || !istype(F)) - return 0 - if(!can_store_file(F.size)) - return 0 +// Storing a file in a directory requires write access to that directory. +/obj/item/stock_parts/computer/hard_drive/proc/try_store_file(var/datum/computer_file/F, var/directory, var/list/accesses, var/mob/user) + if(!istype(F)) + return OS_FILE_NOT_FOUND + + var/file_size = F.size + if(istype(F, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = F + file_size += dir.get_held_size() + + if(!can_store_file(file_size)) + return OS_HARDDRIVE_SPACE if(!check_functionality()) - return 0 + return OS_HARDDRIVE_ERROR if(!stored_files) - return 0 + return OS_HARDDRIVE_ERROR + + // Safety check + F.filename = sanitize_for_file(F.filename) + + var/datum/computer_file/directory/D = parse_directory(directory) + if(directory && !D) + return OS_DIR_NOT_FOUND + if(D && !(D.get_held_perms(accesses, user) & OS_WRITE_ACCESS)) + return OS_FILE_NO_WRITE - var/list/badchars = list("/","\\",":","*","?","\"","<",">","|","#", ".") - for(var/char in badchars) - if(findtext(F.filename, char)) - return 0 + // We intentionally check these two cases last so that if we are overwriting the file, we are sure + // to be able to store it once we remove the old version. // This file is already stored. Don't store it again. if(F in stored_files) - return 0 + return OS_FILE_EXISTS + // Fail on finding a file with a duplicate name. + if(!isnum(find_file_by_name(F.filename, D, TRUE))) + return OS_FILE_EXISTS + return OS_FILE_SUCCESS - var/name = F.filename + "." + F.filetype - for(var/datum/computer_file/file in stored_files) - if((file.filename + "." + file.filetype) == name) - return 0 - return 1 - -// Tries to find the file by filename. Returns null on failure -/obj/item/stock_parts/computer/hard_drive/proc/find_file_by_name(var/filename) - if(!check_functionality()) - return null +// Tries to find file by filename. Returns error code on failure +/obj/item/stock_parts/computer/hard_drive/proc/find_file_by_name(var/filename, var/directory, var/forced) + if(!forced && !check_functionality()) + return OS_HARDDRIVE_ERROR if(!filename) - return null + return OS_FILE_NOT_FOUND if(!stored_files) - return null + return OS_HARDDRIVE_ERROR - for(var/datum/computer_file/F in stored_files) - if(F.filename == filename) - return F - return null + var/datum/computer_file/directory/target = parse_directory(directory) -/obj/item/stock_parts/computer/hard_drive/Destroy() - stored_files = null - return ..() + if(istype(target)) + var/list/held_files = target.get_held_files() + for(var/datum/computer_file/file in held_files) + // Filename uniqueness is enforced even if filetype is not the same, so allow + // users to access files either by the filename alone or with the filetype. + if(file.filename == filename || (file.filename + "." + file.filetype) == filename) + return file + else + if(directory) + return target + // Check in files not in a directory. + for(var/datum/computer_file/file in stored_files) + if(stored_files[file] != null) // Ignore files in a directory. + continue + if(file.filename == filename || (file.filename + "." + file.filetype) == filename) + return file + return OS_FILE_NOT_FOUND -/obj/item/stock_parts/computer/hard_drive/Initialize() - . = ..() - install_default_programs() +/obj/item/stock_parts/computer/hard_drive/proc/add_directory(var/directory, var/check_for_existing = TRUE) + if(check_for_existing) + var/datum/computer_file/directory/existing = parse_directory(directory) + if(istype(existing)) + return existing + + var/list/directories = splittext(directory, "/") + if(!length(directories)) + return OS_DIR_NOT_FOUND + var/new_directory = sanitize_for_file(directories[directories.len]) + if(!length(new_directory)) + return OS_BAD_NAME + directories.Cut(directories.len) // Remove the final directory. + + var/datum/computer_file/directory/new_dir = new() + new_dir.filename = new_directory + if(!length(directories)) + var/success = store_file(new_dir) + if(success != OS_FILE_SUCCESS) + return success + return new_dir + else // Add directories until the final one is added. + var/datum/computer_file/directory/parent_dir = add_directory(jointext(directories, "/")) + var/success = store_file(new_dir, parent_dir) + if(success != OS_FILE_SUCCESS) + return success + return new_dir + +/obj/item/stock_parts/computer/hard_drive/proc/parse_directory(var/directory, var/create_directories = FALSE) + if(istype(directory, /datum/computer_file/directory)) + if(directory in stored_files) + return directory + return OS_DIR_NOT_FOUND + if(istext(directory)) + var/list/directories = splittext(directory, "/") + var/datum/computer_file/directory/current_dir + if(!length(directories)) + return OS_DIR_NOT_FOUND + directory_loop: + for(var/directory_name in directories) + if(directory_name == "..") + directories.Cut(1, 2) + if(!current_dir) + return OS_DIR_NOT_FOUND + current_dir = current_dir.get_directory() + continue + var/list/file_list = current_dir ? current_dir.get_held_files() : stored_files + for(var/datum/computer_file/directory/D in file_list) + if(D.filename == directory_name) + directories.Cut(1, 2) + current_dir = D + . = D + continue directory_loop + // Found a missing directory. + if(create_directories) + var/final_path = current_dir ? current_dir.get_file_path() + "/" : "" + final_path += jointext(directories, "/") + return add_directory(final_path) + else + return OS_DIR_NOT_FOUND // Preset for borgs and AIs /obj/item/stock_parts/computer/hard_drive/silicon/install_default_programs() - ..() - store_file(new/datum/computer_file/program/records()) - store_file(new/datum/computer_file/program/crew_manifest()) - store_file(new/datum/computer_file/program/email_client()) - store_file(new/datum/computer_file/program/suit_sensors()) \ No newline at end of file + var/datum/computer_file/directory/program_directory = ..() + store_file(new/datum/computer_file/program/records(), program_directory) + store_file(new/datum/computer_file/program/crew_manifest(), program_directory) + store_file(new/datum/computer_file/program/email_client(), program_directory) + store_file(new/datum/computer_file/program/suit_sensors(), program_directory) \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/lan_port.dm b/code/modules/modular_computers/hardware/lan_port.dm new file mode 100644 index 000000000000..3074458d21e9 --- /dev/null +++ b/code/modules/modular_computers/hardware/lan_port.dm @@ -0,0 +1,98 @@ +/obj/item/stock_parts/computer/lan_port + name = "wired connection port" + desc = "A basic expansion port for use with wired connections." + power_usage = 30 + origin_tech = @'{"programming":1,"engineering":1}' + icon_state = "netcard_ethernet" + hardware_size = 3 + material = /decl/material/solid/glass + var/obj/structure/network_cable/terminal/terminal + +/obj/item/stock_parts/computer/lan_port/Initialize() + . = ..() + // If we spawn in a machine, assume we want to generate a terminal immediately. + if(istype(loc, /obj/machinery)) + set_terminal() + +/obj/item/stock_parts/computer/lan_port/Destroy() + QDEL_NULL(terminal) + return ..() + +/obj/item/stock_parts/computer/lan_port/on_uninstall(obj/machinery/machine, temporary) + . = ..() + QDEL_NULL(terminal) + +/obj/item/stock_parts/computer/lan_port/proc/set_terminal() + if(terminal) + unset_terminal(terminal) + var/obj/machinery/parent = loc + if(!istype(parent)) + return + terminal = new(get_turf(parent)) + set_extension(src, /datum/extension/event_registration/shuttle_stationary, GET_DECL(/decl/observ/moved), parent, PROC_REF(check_terminal_prox), get_area(src)) + events_repository.register(/decl/observ/destroyed, terminal, src, PROC_REF(unset_terminal)) + set_component_status(parent, PART_STAT_CONNECTED) + +/obj/item/stock_parts/computer/lan_port/proc/unset_terminal() + remove_extension(src, /datum/extension/event_registration/shuttle_stationary) + events_repository.unregister(/decl/observ/destroyed, terminal, src, PROC_REF(unset_terminal)) + var/obj/machinery/parent = loc + if(istype(parent)) + unset_status(parent, PART_STAT_CONNECTED) + terminal = null + +/obj/item/stock_parts/computer/lan_port/proc/check_terminal_prox() + if(!terminal) + return TRUE + var/obj/machinery/parent = loc + if(!istype(parent)) + qdel(terminal) + return FALSE + if(get_turf(parent) != get_turf(terminal)) + parent.visible_message(SPAN_WARNING("The terminal is ripped out of \the [parent]!")) + qdel(terminal) + return FALSE + return TRUE + +/obj/item/stock_parts/computer/lan_port/proc/check_terminal_block(var/turf/T) + return locate(/obj/structure/network_cable) in T + +/obj/item/stock_parts/computer/lan_port/attackby(obj/item/used_item, mob/user) + var/obj/machinery/parent = loc + if(!istype(parent)) + return ..() + + // Interactions inside machine only + if (istype(used_item, /obj/item/stack/net_cable_coil) && !terminal) + var/turf/T = get_turf(parent) + if(check_terminal_block(T)) + to_chat(user, SPAN_WARNING("There's already a network cable there!")) + return TRUE + if(istype(T) && !T.is_plating()) + to_chat(user, SPAN_WARNING("You must remove the floor plating beneath \the [parent] first.")) + return TRUE + + var/obj/item/stack/net_cable_coil/C = used_item + if(!C.can_use(5)) + to_chat(user, SPAN_WARNING("You need five lengths of network cable for \the [parent].")) + return TRUE + + user.visible_message(SPAN_NOTICE("\The [user] adds cables to \the [parent]."), "You start adding cables to \the [parent] frame...") + if(do_after(user, 20, parent)) + if(!terminal && (loc == parent) && parent.components_are_accessible(type) && !check_terminal_block(T) && C.use(5)) + user.visible_message(SPAN_NOTICE("\The [user] has added cables to \the [parent]!"), "You add cables to \the [parent].") + set_terminal() + return TRUE + if(IS_WIRECUTTER(used_item) && terminal) + var/turf/T = get_turf(parent) + if(istype(T) && !T.is_plating()) + to_chat(user, SPAN_WARNING("You must remove the floor plating beneath \the [parent] first.")) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] dismantles the power terminal from \the [parent]."), "You begin to cut the cables...") + if(do_after(user, 15, parent)) + if(terminal && (loc == parent) && parent.components_are_accessible(type)) + new /obj/item/stack/net_cable_coil(T, 5) + to_chat(user, SPAN_NOTICE("You cut the cables and dismantle the network terminal.")) + qdel(terminal) + return TRUE + return FALSE \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/nano_printer.dm b/code/modules/modular_computers/hardware/nano_printer.dm index 58e64813d354..4932c7264d83 100644 --- a/code/modules/modular_computers/hardware/nano_printer.dm +++ b/code/modules/modular_computers/hardware/nano_printer.dm @@ -2,7 +2,7 @@ name = "nano printer" desc = "Small integrated printer with paper recycling module." power_usage = 50 - origin_tech = "{'programming':2,'engineering':2}" + origin_tech = @'{"programming":2,"engineering":2}' critical = 0 icon_state = "printer" hardware_size = 1 @@ -20,7 +20,7 @@ if(printer_ready()) last_print = world.time var/turf/T = get_turf(src) - new paper_type(T,text_to_print, paper_title, md) + new paper_type(T, null, text_to_print, paper_title, md) stored_paper-- playsound(T, "sound/machines/dotprinter.ogg", 30) T.visible_message("\The [src] prints out a paper.") @@ -37,37 +37,43 @@ return 0 return 1 -/obj/item/stock_parts/computer/nano_printer/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/paper)) +// TODO: unify with /obj/item/stock_parts/printer somehow? +/obj/item/stock_parts/computer/nano_printer/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/paper)) if(stored_paper >= max_paper) - to_chat(user, "You try to add \the [W] into \the [src], but its paper bin is full.") - return + to_chat(user, "You try to add \the [used_item] into \the [src], but its paper bin is full.") + return TRUE - to_chat(user, "You insert \the [W] into [src].") - qdel(W) + to_chat(user, "You insert \the [used_item] into [src].") + qdel(used_item) stored_paper++ - else if(istype(W, /obj/item/paper_bundle)) - var/obj/item/paper_bundle/B = W + else if(istype(used_item, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = used_item var/num_of_pages_added = 0 if(stored_paper >= max_paper) - to_chat(user, "You try to add \the [W] into \the [src], but its paper bin is full.") - return - for(var/obj/item/bundleitem in B) //loop through items in bundle - if(istype(bundleitem, /obj/item/paper)) //if item is paper (and not photo), add into the bin - B.pages.Remove(bundleitem) - qdel(bundleitem) - num_of_pages_added++ - stored_paper++ + to_chat(user, "You try to add \the [used_item] into \the [src], but its paper bin is full.") + return TRUE + if(!B.is_blank()) + if(user) + to_chat(user, SPAN_WARNING("\The [B] contains some non-blank pages, or something else than paper sheets!")) + return TRUE + for(var/obj/item/paper/bundleitem in B) //loop through papers in bundle + B.pages.Remove(bundleitem) + qdel(bundleitem) + num_of_pages_added++ + stored_paper++ if(stored_paper >= max_paper) //check if the printer is full yet to_chat(user, "The printer has been filled to full capacity.") break - if(B.pages.len == 0) //if all its papers have been put into the printer, delete bundle - qdel(W) - else if(B.pages.len == 1) //if only one item left, extract item and delete the one-item bundle - user.drop_from_inventory(B) - user.put_in_hands(B[1]) - qdel(B) - else //if at least two items remain, just update the bundle icon - B.update_icon() - to_chat(user, "You add [num_of_pages_added] papers from \the [W] into \the [src].") - return + switch(length(B.pages)) + if(0) //if all its papers have been put into the printer, delete bundle + qdel(B) + if(1) //if only one item left, extract item and delete the one-item bundle + user.drop_from_inventory(B) + user.put_in_hands(B.pages[1]) + qdel(B) + else //if at least two items remain, just update the bundle icon + B.update_icon() + to_chat(user, "You add [num_of_pages_added] papers from \the [used_item] into \the [src].") + return TRUE + return ..() diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm index 32364d7c9d66..7915dc05bac3 100644 --- a/code/modules/modular_computers/hardware/network_card.dm +++ b/code/modules/modular_computers/hardware/network_card.dm @@ -2,15 +2,15 @@ name = "basic network card" desc = "A basic network card for usage with standard network protocols." power_usage = 50 - origin_tech = "{'programming':2,'engineering':1}" + origin_tech = @'{"programming":2,"engineering":1}' critical = 0 icon_state = "netcard_basic" hardware_size = 1 - material = /decl/material/solid/glass + material = /decl/material/solid/fiberglass var/long_range = 0 var/ethernet = 0 // Hard-wired, therefore always on, ignores wireless checks. - var/proxy_id // If set, uses the value to funnel connections through another network card. + // TODO: Reimplement proxy_id /obj/item/stock_parts/computer/network_card/diagnostics() . = ..() @@ -26,34 +26,17 @@ . += "OpenEth (Physical Connection) - Physical network connection port" /obj/item/stock_parts/computer/network_card/Initialize() - set_extension(src, /datum/extension/network_device) - var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) - if(long_range) - D.connection_type = NETWORK_CONNECTION_STRONG_WIRELESS - if(ethernet) - D.connection_type = NETWORK_CONNECTION_WIRED + set_extension(src, /datum/extension/network_device/stock_part, null, null, long_range ? RECEIVER_STRONG_WIRELESS : RECEIVER_WIRELESS) . = ..() /obj/item/stock_parts/computer/network_card/advanced name = "advanced network card" - desc = "An advanced network card for usage with standard network protocols. It's transmitter is strong enough to connect even when far away." + desc = "An advanced network card for usage with standard network protocols. Its transmitter is strong enough to connect even when far away." long_range = 1 - origin_tech = "{'programming':4,'engineering':2}" + origin_tech = @'{"programming":4,"engineering":2}' power_usage = 100 // Better range but higher power usage. icon_state = "netcard_advanced" hardware_size = 1 - material = /decl/material/solid/glass - -/obj/item/stock_parts/computer/network_card/wired - name = "wired network card" - desc = "An advanced network card for usage with standard network protocols. This one also supports wired connection." - ethernet = 1 - origin_tech = "{'programming':5,'engineering':3}" - power_usage = 100 // Better range but higher power usage. - icon_state = "netcard_ethernet" - hardware_size = 3 - material = /decl/material/solid/glass - // Returns a string identifier of this network card /obj/item/stock_parts/computer/network_card/proc/get_network_tag() @@ -75,21 +58,24 @@ return var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) - return D.check_connection(specific_action) + var/list/signal_data = D.check_connection(specific_action) + if(!islist(signal_data)) + return + return signal_data[1] /obj/item/stock_parts/computer/network_card/on_disable() var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) if(D) D.disconnect() -/obj/item/stock_parts/computer/network_card/on_enable(var/datum/extension/interactive/ntos/os) +/obj/item/stock_parts/computer/network_card/on_enable(var/datum/extension/interactive/os/os) var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) if(D) D.connect() /obj/item/stock_parts/computer/network_card/on_install(var/obj/machinery/machine) ..() - var/datum/extension/interactive/ntos/os = get_extension(machine, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(machine, /datum/extension/interactive/os) if(os) on_enable(os) diff --git a/code/modules/modular_computers/hardware/portable_hard_drive.dm b/code/modules/modular_computers/hardware/portable_hard_drive.dm index 4ac3f254bbab..921f22a0f57e 100644 --- a/code/modules/modular_computers/hardware/portable_hard_drive.dm +++ b/code/modules/modular_computers/hardware/portable_hard_drive.dm @@ -6,8 +6,8 @@ icon_state = "flashdrive_basic" hardware_size = 1 max_capacity = 16 - origin_tech = "{'programming':1}" - material = /decl/material/solid/glass + origin_tech = @'{"programming":1}' + material = /decl/material/solid/fiberglass /obj/item/stock_parts/computer/hard_drive/portable/advanced name = "advanced data crystal" @@ -16,8 +16,7 @@ icon_state = "flashdrive_advanced" hardware_size = 1 max_capacity = 64 - origin_tech = "{'programming':2}" - material = /decl/material/solid/glass + origin_tech = @'{"programming":2}' /obj/item/stock_parts/computer/hard_drive/portable/super name = "super data crystal" @@ -26,8 +25,7 @@ icon_state = "flashdrive_super" hardware_size = 1 max_capacity = 256 - origin_tech = "{'programming':4}" - material = /decl/material/solid/glass + origin_tech = @'{"programming":4}' /obj/item/stock_parts/computer/hard_drive/portable/Initialize() . = ..() @@ -65,4 +63,3 @@ readme.stored_data = jointext(readme_data, "\[br\]") readme.filename = "___README___" store_file(readme) - \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/processor_unit.dm b/code/modules/modular_computers/hardware/processor_unit.dm index 398e8df96f3e..9c803c2c2ad2 100644 --- a/code/modules/modular_computers/hardware/processor_unit.dm +++ b/code/modules/modular_computers/hardware/processor_unit.dm @@ -8,7 +8,7 @@ hardware_size = 2 power_usage = 100 critical = 1 - origin_tech = "{'programming':3,'engineering':2}" + origin_tech = @'{"programming":3,"engineering":2}' material = /decl/material/solid/metal/steel var/processing_power = 2 // Used for DDoS speed calculations @@ -20,27 +20,27 @@ hardware_size = 1 power_usage = 25 processing_power = 1 - origin_tech = "{'programming':2,'engineering':2}" + origin_tech = @'{"programming":2,"engineering":2}' material = /decl/material/solid/metal/steel /obj/item/stock_parts/computer/processor_unit/photonic name = "photonic processor" - desc = "An advanced experimental CPU that uses photonic core instead of regular circuitry. It is more power efficient than its elecron analog." + desc = "An advanced experimental CPU that uses photonic core instead of regular circuitry. It is more power efficient than its electron analogue." icon_state = "cpu_normal_photonic" hardware_size = 2 power_usage = 50 processing_power = 4 - origin_tech = "{'programming':5,'engineering':4}" + origin_tech = @'{"programming":5,"engineering":4}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/processor_unit/photonic/small name = "photonic microprocessor" - desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It is more power efficient than its elecron analog." + desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It is more power efficient than its electron analogue." icon_state = "cpu_small_photonic" hardware_size = 1 power_usage = 10 processing_power = 2 - origin_tech = "{'programming':4,'engineering':3}" + origin_tech = @'{"programming":4,"engineering":3}' material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) diff --git a/code/modules/modular_computers/hardware/scanners/scanner.dm b/code/modules/modular_computers/hardware/scanners/scanner.dm index 58a8911fee74..81a6a3b194c7 100644 --- a/code/modules/modular_computers/hardware/scanners/scanner.dm +++ b/code/modules/modular_computers/hardware/scanners/scanner.dm @@ -7,7 +7,7 @@ icon_state = "printer" hardware_size = 1 critical = 0 - origin_tech = "{'programming':2,'engineering':2}" + origin_tech = @'{"programming":2,"engineering":2}' var/datum/computer_file/program/scanner/driver_type = /datum/computer_file/program/scanner // A program type that the scanner interfaces with and attempts to install on insertion. var/datum/computer_file/program/scanner/driver // A driver program which has been set up to interface with the scanner. @@ -19,28 +19,32 @@ do_before_uninstall() . = ..() -/obj/item/stock_parts/computer/scanner/proc/do_after_install(user, atom/device) - var/datum/extension/interactive/ntos/os = get_extension(device, /datum/extension/interactive/ntos) +/obj/item/stock_parts/computer/scanner/do_after_install(atom/device, loud) + var/datum/extension/interactive/os/os = get_extension(device, /datum/extension/interactive/os) if(!driver_type || !device || !os) return 0 if(!os.has_component(PART_HDD)) - to_chat(user, "Driver installation for \the [src] failed: \the [device] lacks a hard drive.") + if(loud) + device.visible_message(SPAN_WARNING("\The [device] flashes an error: Driver installation for \the [src] failed. Could not locate hard drive.")) return 0 - var/datum/computer_file/program/scanner/old_driver = os.get_file(initial(driver_type.filename)) + var/datum/computer_file/program/scanner/old_driver = os.get_file(initial(driver_type.filename), OS_PROGRAMS_DIR) if(istype(old_driver)) - to_chat(user, "Drivers found on \the [device]; \the [src] has been installed.") + if(loud) + device.visible_message(SPAN_NOTICE("\The [device] pings: Drivers located for \the [src]. Installation complete.")) old_driver.connect_scanner() return 1 var/datum/computer_file/program/scanner/driver_file = new driver_type - if(!os.store_file(driver_file)) - to_chat(user, "Driver installation for \the [src] failed: file could not be written to the hard drive.") + if(!os.store_file(driver_file, OS_PROGRAMS_DIR, create_directories = TRUE)) + if(loud) + device.visible_message(SPAN_WARNING("\The [device] flashes an error: Driver installation for \the [src] failed. Could not write to the hard drive.")) return 0 - to_chat(user, "Driver software for \the [src] has been installed on \the [device].") driver_file.computer = os driver_file.connect_scanner() + if(loud) + device.visible_message(SPAN_NOTICE("\The [device] pings: Driver installation for \the [src] complete.")) return 1 -/obj/item/stock_parts/computer/scanner/proc/do_before_uninstall() +/obj/item/stock_parts/computer/scanner/do_before_uninstall(atom/device, loud) if(driver) driver.disconnect_scanner() if(driver) //In case the driver doesn't find it. @@ -50,10 +54,12 @@ /obj/item/stock_parts/computer/scanner/proc/do_on_afterattack(mob/user, atom/target, proximity) -/obj/item/stock_parts/computer/scanner/attackby(obj/W, mob/living/user) - do_on_attackby(user, W) +/obj/item/stock_parts/computer/scanner/attackby(obj/used_item, mob/user) + return do_on_attackby(user, used_item) +/// Returns TRUE if the attackby chain should be stopped. /obj/item/stock_parts/computer/scanner/proc/do_on_attackby(mob/user, atom/target) + return FALSE /obj/item/stock_parts/computer/scanner/proc/can_use_scanner(mob/user, atom/target, proximity = TRUE) if(!check_functionality()) diff --git a/code/modules/modular_computers/hardware/scanners/scanner_atmos.dm b/code/modules/modular_computers/hardware/scanners/scanner_atmos.dm index 6a5be5ecd699..5937f6a7daef 100644 --- a/code/modules/modular_computers/hardware/scanners/scanner_atmos.dm +++ b/code/modules/modular_computers/hardware/scanners/scanner_atmos.dm @@ -3,7 +3,7 @@ desc = "An atmospheric scanner module. It can scan the surroundings and report the composition of gases." can_run_scan = 1 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/scanner/atmos/can_use_scanner(mob/user, atom/target, proximity = TRUE) if(!..()) diff --git a/code/modules/modular_computers/hardware/scanners/scanner_medical.dm b/code/modules/modular_computers/hardware/scanners/scanner_medical.dm index 15a59dad51ee..3ed7e600f6fa 100644 --- a/code/modules/modular_computers/hardware/scanners/scanner_medical.dm +++ b/code/modules/modular_computers/hardware/scanners/scanner_medical.dm @@ -2,7 +2,7 @@ name = "medical scanner module" desc = "A medical scanner module. It can be used to scan patients and display medical information." material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/scanner/medical/do_on_afterattack(mob/user, atom/target, proximity) if(!can_use_scanner(user, target, proximity)) diff --git a/code/modules/modular_computers/hardware/scanners/scanner_paper.dm b/code/modules/modular_computers/hardware/scanners/scanner_paper.dm index 0af5c9d1f1d4..e5843c442212 100644 --- a/code/modules/modular_computers/hardware/scanners/scanner_paper.dm +++ b/code/modules/modular_computers/hardware/scanners/scanner_paper.dm @@ -3,7 +3,7 @@ desc = "A paper scanning module. It can scan writing and save it to a file." external_slot = TRUE material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/scanner/paper/can_use_scanner(mob/user, obj/item/paper/target, proximity = TRUE) if(!..()) @@ -27,7 +27,7 @@ driver.scan_file_type = target.scan_file_type if(target.type == /obj/item/paper/bodyscan) - driver.data_buffer = display_medical_data(target.metadata.Copy(),user.get_skill_value(SKILL_MEDICAL), TRUE) + driver.data_buffer = display_medical_data(driver.metadata_buffer,user.get_skill_value(SKILL_MEDICAL), TRUE) else driver.data_buffer = data @@ -35,4 +35,5 @@ SSnano.update_uis(driver.NM) /obj/item/stock_parts/computer/scanner/paper/do_on_attackby(mob/user, atom/target) - do_on_afterattack(user, target, TRUE) \ No newline at end of file + do_on_afterattack(user, target, TRUE) + return can_use_scanner(user, target, TRUE) \ No newline at end of file diff --git a/code/modules/modular_computers/hardware/scanners/scanner_reagent.dm b/code/modules/modular_computers/hardware/scanners/scanner_reagent.dm index c725a9a55c51..8d0893a37f4d 100644 --- a/code/modules/modular_computers/hardware/scanners/scanner_reagent.dm +++ b/code/modules/modular_computers/hardware/scanners/scanner_reagent.dm @@ -2,7 +2,7 @@ name = "reagent scanner module" desc = "A reagent scanner module. It can scan and analyze various reagents." material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/stock_parts/computer/scanner/reagent/can_use_scanner(mob/user, obj/target, proximity = TRUE) if(!..(user, target, proximity)) diff --git a/code/modules/modular_computers/hardware/tesla_link.dm b/code/modules/modular_computers/hardware/tesla_link.dm index c80c643abed0..6e59fcdb5f96 100644 --- a/code/modules/modular_computers/hardware/tesla_link.dm +++ b/code/modules/modular_computers/hardware/tesla_link.dm @@ -5,7 +5,7 @@ enabled = 1 icon_state = "teslalink" hardware_size = 1 - origin_tech = "{'programming':2,'powerstorage':3,'engineering':2}" + origin_tech = @'{"programming":2,"powerstorage":3,"engineering":2}' material = /decl/material/solid/metal/steel var/passive_charging_rate = 250 // W diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm index 57183d051bcc..1a939ceb8f3a 100644 --- a/code/modules/modular_computers/laptop_vendor.dm +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -3,30 +3,51 @@ /obj/machinery/lapvend name = "computer vendor" desc = "A vending machine with a built-in microfabricator, capable of dispensing various computers." - icon = 'icons/obj/vending.dmi' - icon_state = "laptop" + icon = 'icons/obj/machines/vending/laptops.dmi' + icon_state = ICON_STATE_WORLD layer = BELOW_OBJ_LAYER - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE // The actual laptop/tablet var/obj/item/modular_computer/laptop/fabricated_laptop = null var/obj/item/modular_computer/tablet/fabricated_tablet = null // Utility vars - var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen - var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet - var/total_price = 0 // Price of currently vended device. + var/const/STATE_DEVICE_SEL = 0 + var/const/STATE_LOADOUT_SEL = 1 + var/const/STATE_PAYMENT = 2 + var/const/STATE_THANK_YOU = 3 + var/state = STATE_DEVICE_SEL + var/const/DEVICE_TYPE_NONE = 0 + var/const/DEVICE_TYPE_LAPTOP = 1 + var/const/DEVICE_TYPE_TABLET = 2 + var/devtype = DEVICE_TYPE_NONE + /// The calculated price of the currently vended device. + var/total_price = 0 // Device loadout - var/dev_cpu = 1 // 1: Default, 2: Upgraded - var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced - var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced - var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range - var/dev_tesla = 0 // 0: None, 1: Standard - var/dev_nanoprint = 0 // 0: None, 1: Standard - var/dev_card = 0 // 0: None, 1: Standard - var/dev_aislot = 0 // 0: None, 1: Standard + var/const/COMPONENT_NONE = 0 + var/const/COMPONENT_PRESENT = 1 + var/const/COMPONENT_BASIC = 1 + var/const/COMPONENT_UPGRADED = 2 + var/const/COMPONENT_ADVANCED = 3 + /// What kind of CPU are we adding? Valid states: COMPONENT_BASIC, COMPONENT_UPGRADED + var/dev_cpu = COMPONENT_BASIC + /// What kind of battery are we adding? Valid states: COMPONENT_BASIC, COMPONENT_UPGRADED, COMPONENT_ADVANCED + var/dev_battery = COMPONENT_BASIC + /// What kind of battery are we adding? Valid states: COMPONENT_BASIC, COMPONENT_UPGRADED, COMPONENT_ADVANCED + var/dev_disk = COMPONENT_BASIC + /// What kind of network card are we adding? Valid states: COMPONENT_NONE, COMPONENT_BASIC, COMPONENT_UPGRADED + var/dev_netcard = COMPONENT_NONE + /// Are we adding a tesla relay? Valid states: COMPONENT_NONE, COMPONENT_PRESENT + var/dev_tesla = COMPONENT_NONE + /// Are we adding a printer? Valid states: COMPONENT_NONE, COMPONENT_PRESENT + var/dev_nanoprint = COMPONENT_NONE + /// Are we adding a card reader? Valid states: COMPONENT_NONE, COMPONENT_PRESENT + var/dev_card = COMPONENT_NONE + /// Are we adding an AI slot? Valid states: COMPONENT_NONE, COMPONENT_PRESENT + var/dev_aislot = COMPONENT_NONE /obj/machinery/lapvend/on_update_icon() if(stat & BROKEN) @@ -38,127 +59,127 @@ // Removes all traces of old order and allows you to begin configuration from scratch. /obj/machinery/lapvend/proc/reset_order() - state = 0 - devtype = 0 - if(fabricated_laptop) - qdel(fabricated_laptop) - fabricated_laptop = null - if(fabricated_tablet) - qdel(fabricated_tablet) - fabricated_tablet = null - dev_cpu = 1 - dev_battery = 1 - dev_disk = 1 - dev_netcard = 0 - dev_tesla = 0 - dev_nanoprint = 0 - dev_card = 0 - dev_aislot = 0 + state = STATE_DEVICE_SEL + devtype = DEVICE_TYPE_NONE + QDEL_NULL(fabricated_laptop) + QDEL_NULL(fabricated_tablet) + dev_cpu = COMPONENT_BASIC + dev_battery = COMPONENT_BASIC + dev_disk = COMPONENT_BASIC + dev_netcard = COMPONENT_NONE + dev_tesla = COMPONENT_NONE + dev_nanoprint = COMPONENT_NONE + dev_card = COMPONENT_NONE + dev_aislot = COMPONENT_NONE // Recalculates the price and optionally even fabricates the device. -/obj/machinery/lapvend/proc/fabricate_and_recalc_price(var/fabricate = 0) +/obj/machinery/lapvend/proc/fabricate_and_recalc_price(var/fabricate = FALSE) total_price = 0 - if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles + if(devtype == DEVICE_TYPE_LAPTOP) // Laptop, generally cheaper to make it accessible for most station roles + var/datum/extension/assembly/modular_computer/assembly if(fabricate) fabricated_laptop = new(src) - var/datum/extension/assembly/modular_computer/assembly = get_extension(fabricated_laptop, /datum/extension/assembly) - total_price = 99 + assembly = get_extension(fabricated_laptop, /datum/extension/assembly) + total_price = atom_info_repository.get_single_worth_for(/obj/item/modular_computer/laptop) switch(dev_cpu) - if(1) + if(COMPONENT_BASIC) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/processor_unit/small) if(fabricate) assembly.add_replace_component(null, PART_CPU, new/obj/item/stock_parts/computer/processor_unit/small(fabricated_laptop)) - if(2) + if(COMPONENT_UPGRADED) if(fabricate) assembly.add_replace_component(null, PART_CPU, new/obj/item/stock_parts/computer/processor_unit(fabricated_laptop)) - total_price += 299 + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/processor_unit) switch(dev_battery) - if(1) // Basic(750C) + if(COMPONENT_BASIC) // Basic(750C) if(fabricate) assembly.add_replace_component(null, PART_BATTERY, new/obj/item/stock_parts/computer/battery_module(fabricated_laptop)) - if(2) // Upgraded(1100C) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/battery_module) + if(COMPONENT_UPGRADED) // Upgraded(1100C) if(fabricate) assembly.add_replace_component(null, PART_BATTERY, new/obj/item/stock_parts/computer/battery_module/advanced(fabricated_laptop)) - total_price += 199 - if(3) // Advanced(1500C) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/battery_module/advanced) + if(COMPONENT_ADVANCED) // Advanced(1500C) if(fabricate) assembly.add_replace_component(null, PART_BATTERY, new/obj/item/stock_parts/computer/battery_module/super(fabricated_laptop)) - total_price += 499 + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/battery_module/super) switch(dev_disk) - if(1) // Basic(128GQ) + if(COMPONENT_BASIC) // Basic(128GQ) if(fabricate) assembly.add_replace_component(null, PART_HDD, new/obj/item/stock_parts/computer/hard_drive(fabricated_laptop)) - if(2) // Upgraded(256GQ) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/hard_drive) + if(COMPONENT_UPGRADED) // Upgraded(256GQ) if(fabricate) assembly.add_replace_component(null, PART_HDD, new/obj/item/stock_parts/computer/hard_drive/advanced(fabricated_laptop)) - total_price += 99 - if(3) // Advanced(512GQ) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/hard_drive/advanced) + if(COMPONENT_ADVANCED) // Advanced(512GQ) if(fabricate) assembly.add_replace_component(null, PART_HDD, new/obj/item/stock_parts/computer/hard_drive/super(fabricated_laptop)) - total_price += 299 + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/hard_drive/super) switch(dev_netcard) - if(1) // Basic(Short-Range) + if(COMPONENT_BASIC) // Basic(Short-Range) if(fabricate) assembly.add_replace_component(null, PART_NETWORK, new/obj/item/stock_parts/computer/network_card(fabricated_laptop)) - total_price += 99 - if(2) // Advanced (Long Range) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/network_card) + if(COMPONENT_UPGRADED) // Advanced (Long Range) if(fabricate) assembly.add_replace_component(null, PART_NETWORK, new/obj/item/stock_parts/computer/network_card/advanced(fabricated_laptop)) - total_price += 299 + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/network_card/advanced) if(dev_tesla) - total_price += 399 if(fabricate) assembly.add_replace_component(null, PART_TESLA, new/obj/item/stock_parts/computer/tesla_link(fabricated_laptop)) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/tesla_link) if(dev_nanoprint) - total_price += 99 if(fabricate) assembly.add_replace_component(null, PART_PRINTER, new/obj/item/stock_parts/computer/nano_printer(fabricated_laptop)) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/nano_printer) if(dev_card) - total_price += 199 if(fabricate) assembly.add_replace_component(null, PART_CARD, new/obj/item/stock_parts/computer/card_slot(fabricated_laptop)) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/card_slot) if(dev_aislot) - total_price += 499 if(fabricate) assembly.add_replace_component(null, PART_AI, new/obj/item/stock_parts/computer/ai_slot(fabricated_laptop)) + total_price += atom_info_repository.get_single_worth_for(/obj/item/stock_parts/computer/ai_slot) return total_price - else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this. + else if(devtype == DEVICE_TYPE_TABLET) // Tablet, more expensive, not everyone could probably afford this. + var/datum/extension/assembly/modular_computer/assembly if(fabricate) fabricated_tablet = new(src) - var/datum/extension/assembly/modular_computer/assembly = get_extension(fabricated_tablet, /datum/extension/assembly) - if(fabricate) + assembly = get_extension(fabricated_tablet, /datum/extension/assembly) assembly.add_replace_component(null, PART_CPU, new/obj/item/stock_parts/computer/processor_unit/small(fabricated_tablet)) total_price = 199 switch(dev_battery) - if(1) // Basic(300C) + if(COMPONENT_BASIC) // Basic(300C) if(fabricate) assembly.add_replace_component(null, PART_BATTERY, new/obj/item/stock_parts/computer/battery_module/nano(fabricated_tablet)) - if(2) // Upgraded(500C) + if(COMPONENT_UPGRADED) // Upgraded(500C) if(fabricate) assembly.add_replace_component(null, PART_BATTERY, new/obj/item/stock_parts/computer/battery_module/micro(fabricated_tablet)) total_price += 199 - if(3) // Advanced(750C) + if(COMPONENT_ADVANCED) // Advanced(750C) if(fabricate) assembly.add_replace_component(null, PART_BATTERY, new/obj/item/stock_parts/computer/battery_module(fabricated_tablet)) total_price += 499 switch(dev_disk) - if(1) // Basic(32GQ) + if(COMPONENT_BASIC) // Basic(32GQ) if(fabricate) assembly.add_replace_component(null, PART_HDD, new/obj/item/stock_parts/computer/hard_drive/micro(fabricated_tablet)) - if(2) // Upgraded(64GQ) + if(COMPONENT_UPGRADED) // Upgraded(64GQ) if(fabricate) assembly.add_replace_component(null, PART_HDD, new/obj/item/stock_parts/computer/hard_drive/small(fabricated_tablet)) total_price += 99 - if(3) // Advanced(128GQ) + if(COMPONENT_ADVANCED) // Advanced(128GQ) if(fabricate) assembly.add_replace_component(null, PART_HDD, new/obj/item/stock_parts/computer/hard_drive(fabricated_tablet)) total_price += 299 switch(dev_netcard) - if(1) // Basic(Short-Range) + if(COMPONENT_BASIC) // Basic(Short-Range) if(fabricate) assembly.add_replace_component(null, PART_NETWORK, new/obj/item/stock_parts/computer/network_card(fabricated_tablet)) total_price += 99 - if(2) // Advanced (Long Range) + if(COMPONENT_UPGRADED) // Advanced (Long Range) if(fabricate) assembly.add_replace_component(null, PART_NETWORK, new/obj/item/stock_parts/computer/network_card/advanced(fabricated_tablet)) total_price += 299 @@ -181,77 +202,75 @@ return total_price return 0 - - - - -/obj/machinery/lapvend/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/lapvend/OnTopic(mob/user, href_list) + if((. = ..())) + return if(href_list["pick_device"]) if(state) // We've already picked a device type - return 0 + return TOPIC_REFRESH // Your UI must be out of date (or you're trying to href hack...) devtype = text2num(href_list["pick_device"]) - state = 1 - fabricate_and_recalc_price(0) - return 1 + state = STATE_LOADOUT_SEL + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["clean_order"]) reset_order() - return 1 - if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode - return 0 + return TOPIC_REFRESH + // Following IFs should only be usable when in the Select Loadout mode. + if(state != STATE_LOADOUT_SEL) + return TOPIC_NOACTION + // Proceed to payment if(href_list["confirm_order"]) - state = 2 // Wait for ID swipe for payment processing - fabricate_and_recalc_price(0) - return 1 + state = STATE_PAYMENT // Wait for ID swipe for payment processing + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH + // Hardware selection if(href_list["hw_cpu"]) dev_cpu = text2num(href_list["hw_cpu"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_battery"]) dev_battery = text2num(href_list["hw_battery"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_disk"]) dev_disk = text2num(href_list["hw_disk"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_netcard"]) dev_netcard = text2num(href_list["hw_netcard"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_tesla"]) dev_tesla = text2num(href_list["hw_tesla"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_nanoprint"]) dev_nanoprint = text2num(href_list["hw_nanoprint"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_card"]) dev_card = text2num(href_list["hw_card"]) - fabricate_and_recalc_price(0) - return 1 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH if(href_list["hw_aislot"]) dev_aislot = text2num(href_list["hw_aislot"]) - fabricate_and_recalc_price(0) - return 1 - return 0 + fabricate_and_recalc_price(FALSE) + return TOPIC_REFRESH + return TOPIC_NOACTION /obj/machinery/lapvend/interface_interact(var/mob/user) ui_interact(user) return TRUE /obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(stat & (BROKEN | NOPOWER | MAINT)) + if(inoperable(MAINT)) if(ui) ui.close() - return 0 - - var/list/data[0] + return + var/list/data = list() data["state"] = state - if(state == 1) + if(state == STATE_LOADOUT_SEL) data["devtype"] = devtype data["hw_battery"] = dev_battery data["hw_disk"] = dev_disk @@ -261,8 +280,9 @@ data["hw_card"] = dev_card data["hw_cpu"] = dev_cpu data["hw_aislot"] = dev_aislot - if(state == 1 || state == 2) - data["totalprice"] = total_price + if(state == STATE_LOADOUT_SEL || state == STATE_PAYMENT) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) + data["totalprice"] = cur.format_value(total_price) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -271,32 +291,28 @@ ui.open() ui.set_auto_update(1) - -obj/machinery/lapvend/attackby(obj/item/W as obj, mob/user as mob) - // Awaiting payment state - if(state == 2) - if(process_payment(W)) - fabricate_and_recalc_price(1) - flick("laptop-vend", src) - if((devtype == 1) && fabricated_laptop) - fabricated_laptop.forceMove(src.loc) - fabricated_laptop.update_icon() - fabricated_laptop.update_verbs() - fabricated_laptop = null - else if((devtype == 2) && fabricated_tablet) - fabricated_tablet.forceMove(src.loc) - fabricated_tablet.update_verbs() - fabricated_tablet = null - ping("Enjoy your new product!") - state = 3 - return 1 - return 0 +/obj/machinery/lapvend/attackby(obj/item/used_item, mob/user) + if(state == STATE_PAYMENT && process_payment(used_item)) + fabricate_and_recalc_price(TRUE) + flick("world-vend", src) + if((devtype == DEVICE_TYPE_LAPTOP) && fabricated_laptop) + fabricated_laptop.forceMove(src.loc) + fabricated_laptop.update_icon() + fabricated_laptop.update_verbs() + fabricated_laptop = null + else if((devtype == DEVICE_TYPE_TABLET) && fabricated_tablet) + fabricated_tablet.forceMove(src.loc) + fabricated_tablet.update_verbs() + fabricated_tablet = null + ping("Enjoy your new product!") + state = STATE_THANK_YOU + return TRUE return ..() -// Simplified payment processing, returns 1 on success. +// Simplified payment processing, returns TRUE on success. /obj/machinery/lapvend/proc/process_payment(var/obj/item/charge_stick/I) - if(isnull(I)) + if(!istype(I)) ping("Invalid payment format.") return FALSE visible_message(SPAN_INFO("\The [usr] inserts \the [I] into \the [src].")) diff --git a/code/modules/modular_computers/networking/NTNRC/conversation.dm b/code/modules/modular_computers/networking/NTNRC/conversation.dm index 8cc8ad6efc29..cad74bee59b1 100644 --- a/code/modules/modular_computers/networking/NTNRC/conversation.dm +++ b/code/modules/modular_computers/networking/NTNRC/conversation.dm @@ -69,5 +69,5 @@ if(operator != client) return 0 // Not Authorised - add_status_message("[client.username] has changed channel title from [title] to [newtitle]") + add_status_message("[client.username] has changed channel title from [title] to [newtitle] by operator.") title = newtitle \ No newline at end of file diff --git a/code/modules/modular_computers/networking/_network.dm b/code/modules/modular_computers/networking/_network.dm index 22ff72f751d7..7ba3db6b0112 100644 --- a/code/modules/modular_computers/networking/_network.dm +++ b/code/modules/modular_computers/networking/_network.dm @@ -1,3 +1,7 @@ +#define INTERNET_CONNECTION 1 +#define WIRELESS_CONNECTION 2 +#define WIRED_CONNECTION 3 + /datum/computer_network var/network_id var/network_key @@ -8,16 +12,23 @@ var/list/mainframes = list() var/list/mainframes_by_role = list() + // Telecomms device caches + var/list/connected_radios + var/list/connected_hubs + var/list/relays = list() + var/list/cameras_by_channel = list() + var/datum/extension/network_device/broadcaster/router/router + var/datum/extension/network_device/modem/modem var/datum/extension/network_device/acl/access_controller - var/network_features_enabled = NETWORK_ALL_FEATURES + var/network_features_enabled = NET_ALL_FEATURES var/intrusion_detection_enabled var/intrusion_detection_alarm var/list/banned_nids = list() - var/global/list/all_software_categories + var/static/list/all_software_categories var/list/chat_channels = list() /datum/computer_network/New(var/new_id) @@ -28,34 +39,56 @@ /datum/computer_network/Destroy() for(var/datum/extension/network_device/D in devices) - D.disconnect() + D.disconnect(TRUE) QDEL_NULL_LIST(chat_channels) + connected_radios = null + connected_hubs = null devices = null mainframes = null SSnetworking.networks -= network_id . = ..() /datum/computer_network/proc/add_device(datum/extension/network_device/D) + if(QDELETED(D)) + return FALSE if(D.network_id != network_id) return FALSE if(D.key != network_key) return FALSE if(D in devices) return TRUE - D.network_tag = get_unique_tag(D.network_tag) - devices |= D - devices_by_tag[D.network_tag] = D + + if(!check_connection(D)) + return FALSE + + var/newtag = get_unique_tag(D.network_tag) + if(istype(D, /datum/extension/network_device/mainframe)) var/datum/extension/network_device/mainframe/M = D mainframes |= M for(var/role in M.roles) LAZYDISTINCTADD(mainframes_by_role[role], M) - add_log("Mainframe ONLINE with roles: [english_list(M.roles)]", D.network_tag) + add_log("Mainframe ONLINE with roles: [english_list(M.roles)]", newtag) else if(istype(D, /datum/extension/network_device/broadcaster/relay)) relays |= D - add_log("Relay ONLINE", D.network_tag) - else if(istype(D, /datum/extension/network_device/acl) && !access_controller) - set_access_controller(D) + add_log("Relay ONLINE", newtag) + else if(istype(D, /datum/extension/network_device/acl)) + if(access_controller) + return FALSE + access_controller = D + add_log("New main access controller set", newtag) + else if(istype(D, /datum/extension/network_device/modem)) + if(modem) + return FALSE + modem = D + add_log("New modem connecting to PLEXUS set", newtag) + else if(istype(D, /datum/extension/network_device/camera)) + var/datum/extension/network_device/camera/C = D + add_camera_to_channels(C, C.channels) + + D.network_tag = newtag + devices |= D + devices_by_tag[D.network_tag] = D return TRUE /datum/computer_network/proc/remove_device(datum/extension/network_device/D) @@ -70,6 +103,10 @@ else if(D in relays) relays -= D add_log("Relay OFFLINE", D.network_tag) + else if(istype(D, /datum/extension/network_device/camera)) + var/datum/extension/network_device/camera/C = D + remove_camera_from_channels(C, C.channels) + if(D == router) router = null for(var/datum/extension/network_device/broadcaster/router/R in devices) @@ -97,40 +134,65 @@ router = D network_key = router.key change_id(router.network_id) - devices |= D + add_device(D) add_log("New main router set.", router.network_tag) -/datum/computer_network/proc/set_access_controller(datum/extension/network_device/D) - access_controller = D - devices |= D - add_log("New main access controller set.", D.network_tag) - +// Returns list(signal type, signal strength) on success, null on failure. /datum/computer_network/proc/check_connection(datum/extension/network_device/D, specific_action) if(!router) - return FALSE + return var/obj/machinery/M = router.holder if(istype(M) && !M.operable()) - return FALSE + return if(specific_action && !(network_features_enabled & specific_action)) - return FALSE + return var/list/broadcasters = relays + router - for(var/datum/extension/network_device/R in broadcasters) - if(get_z(R.holder) == get_z(D.holder)) - return TRUE + var/datum/graph/device_graph = D.get_wired_connection() + var/receiver_strength = D.receiver_type -/datum/computer_network/proc/get_signal_strength(datum/extension/network_device/D) - if(!check_connection(D)) - return 0 - var/receiver_strength = D.connection_type - var/list/broadcasters = relays + router var/best_signal = 0 + var/functional_broadcaster = FALSE for(var/datum/extension/network_device/broadcaster/B in broadcasters) - if(get_z(B.holder) != get_z(D.holder)) + if(device_graph) + var/wired_connection = B.get_wired_connection() + if(!isnull(wired_connection) && wired_connection == device_graph) + return list(WIRED_CONNECTION, NETWORK_WIRED_CONNECTION_STRENGTH) + + if(!B.allow_wifi) continue var/broadcast_strength = B.get_broadcast_strength() + if(!broadcast_strength) + continue + + // For long ranged devices, checking to make sure there's at least a functional broadcaster somewhere. + functional_broadcaster = TRUE + + var/d_z = get_z(D.holder) + var/b_z = get_z(B.holder) + + if(!LEVELS_ARE_Z_CONNECTED(d_z, b_z)) + continue + + if(d_z != b_z) // If the broadcaster is not in the same z-level as the device, the broadcast strength is halved. + broadcast_strength = round(broadcast_strength/2) var/distance = get_dist(get_turf(B.holder), get_turf(D.holder)) best_signal = max(best_signal, (broadcast_strength * receiver_strength) - distance) - return best_signal + + if(best_signal) + return list(WIRELESS_CONNECTION, best_signal) + + // Long ranged devices can connect across z-chunk boundaries. If they're not in the same z-chunk as a broadcaster, + // they simply use internet speed. + if(D.long_range && functional_broadcaster) + return list(WIRELESS_CONNECTION, NETWORK_INTERNET_CONNECTION_STRENGTH) + + if(!modem || !D.internet_allowed) + return + if(specific_action && !(modem.allowed_features & specific_action)) + return + // If the overmap is disabled, a modem alone allows global PLEXUS connection. + if(modem.has_internet_connection(network_id) && D.has_internet_connection(network_id)) + return list(INTERNET_CONNECTION, NETWORK_INTERNET_CONNECTION_STRENGTH) /datum/computer_network/proc/get_device_by_tag(nettag) return devices_by_tag[nettag] @@ -138,6 +200,10 @@ /datum/computer_network/proc/change_id(new_id) if(new_id == network_id) return + // Move our old reconnect queue to the new id. + if(LAZYLEN(SSnetworking.reconnect_queues[network_id])) + SSnetworking.reconnect_queues[new_id] = SSnetworking.reconnect_queues[network_id] + SSnetworking.reconnect_queues[network_id] = null // Update connected devices. for(var/datum/extension/network_device/D in devices) if(D.network_id != new_id) @@ -153,6 +219,26 @@ /datum/computer_network/proc/disable_network_feature(feature) network_features_enabled &= ~feature +// Returns a computer network if an internet connection with the enabled feature is available. +// If the computer network is the same, then only the local feature is checked. +/datum/computer_network/proc/get_internet_connection(target_id, feature) + var/datum/computer_network/target_network = SSnetworking.networks[target_id] + if(!target_network) + return + + if(target_network == src) + if(network_features_enabled & feature) + return target_network + return + + if(check_internet_feature(feature) && target_network.check_internet_feature(feature)) + return target_network + +/datum/computer_network/proc/check_internet_feature(feature) + if(!modem || !modem.has_internet_connection(network_id)) + return FALSE + return modem.allowed_features & feature + /datum/computer_network/proc/update_mainframe_roles(datum/extension/network_device/mainframe/M) if(!(M in mainframes)) return FALSE @@ -167,10 +253,10 @@ /datum/computer_network/proc/get_os_by_nid(nid) for(var/datum/extension/network_device/D in devices) if(D.address == uppertext(nid)) - var/datum/extension/interactive/ntos/os = get_extension(D.holder, /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(D.holder, /datum/extension/interactive/os) if(!os) var/atom/A = D.holder - os = get_extension(A.loc, /datum/extension/interactive/ntos) + os = get_extension(A.loc, /datum/extension/interactive/os) return os /datum/computer_network/proc/get_router_z() @@ -181,34 +267,49 @@ /proc/get_local_network_at(turf/T) for(var/id in SSnetworking.networks) var/datum/computer_network/net = SSnetworking.networks[id] - if(net.router && ARE_Z_CONNECTED(get_z(net.router.holder), get_z(T))) + if(net.router && LEVELS_ARE_Z_CONNECTED(get_z(net.router.holder), get_z(T))) return net -/datum/computer_network/proc/get_mainframes_by_role(mainframe_role = MF_ROLE_FILESERVER, mob/user) - // if administrator, give full access. - if(!user) - return mainframes_by_role[mainframe_role] - var/obj/item/card/id/network/id = user.GetIdCard() - if(id && istype(id, /obj/item/card/id/network) && access_controller && (id.user_id in access_controller.administrators)) +/datum/computer_network/proc/get_mainframes_by_role(mainframe_role = MF_ROLE_FILESERVER, list/accesses) + // Don't check for access if none is passed, for internal usage. + if(!accesses) return mainframes_by_role[mainframe_role] var/list/allowed_mainframes = list() for(var/datum/extension/network_device/D in mainframes_by_role[mainframe_role]) - if(D.has_access(user)) + if(D.has_access(accesses)) allowed_mainframes |= D return allowed_mainframes -/datum/computer_network/proc/get_devices_by_type(var/type, var/mob/user) - var/bypass_auth = !user - if(!bypass_auth) - // Check for admin. - var/obj/item/card/id/network/id = user.GetIdCard() - if(id && istype(id, /obj/item/card/id/network) && access_controller && (id.user_id in access_controller.administrators)) - bypass_auth = TRUE - +/datum/computer_network/proc/get_devices_by_type(type, list/accesses) var/list/results = list() + var/bypass_auth = !accesses for(var/datum/extension/network_device/device in devices) if(istype(device.holder, type)) - if(bypass_auth || device.has_access(user)) + if(bypass_auth || device.has_access(accesses)) results += device.holder return results +/datum/computer_network/proc/get_tags_by_type(var/type) + var/list/results = list() + for(var/tag in devices_by_tag) + var/datum/extension/network_device/device = devices_by_tag[tag] + if(istype(device.holder, type)) + results |= tag + return results + +/datum/computer_network/proc/add_camera_to_channels(var/datum/extension/network_device/camera/added, var/list/channels) + if(!islist(channels)) + channels = list(channels) + for(var/channel in channels) + if(!cameras_by_channel[channel]) + cameras_by_channel[channel] = list() + cameras_by_channel[channel] |= added + +/datum/computer_network/proc/remove_camera_from_channels(var/datum/extension/network_device/camera/removed, var/list/channels) + if(!islist(channels)) + channels = list(channels) + for(var/channel in channels) + if(cameras_by_channel[channel]) + cameras_by_channel[channel] -= removed + if(!length(cameras_by_channel[channel])) + cameras_by_channel -= channel diff --git a/code/modules/modular_computers/networking/accounts/_network_accounts.dm b/code/modules/modular_computers/networking/accounts/_network_accounts.dm new file mode 100644 index 000000000000..db7f6acfcef8 --- /dev/null +++ b/code/modules/modular_computers/networking/accounts/_network_accounts.dm @@ -0,0 +1,91 @@ +/datum/computer_network/proc/get_accounts(accesses) + var/list/result = list() + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(MF_ROLE_ACCOUNT_SERVER, accesses)) + for(var/datum/computer_file/data/account/E in M.get_all_files()) + if(E.backup) + continue + ADD_SORTED(result, E, /proc/cmp_accounts_asc) + return result + +/datum/computer_network/proc/get_accounts_unsorted(accesses) + var/list/result = list() + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(MF_ROLE_ACCOUNT_SERVER, accesses)) + for(var/datum/computer_file/data/account/E in M.get_all_files()) + if(E.backup) + continue + result |= E + return result + +// Return account backups keyed by account login +/datum/computer_network/proc/get_account_backups(accesses) + var/list/result = list() + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(MF_ROLE_ACCOUNT_SERVER, accesses)) + for(var/datum/computer_file/data/account/E in M.get_all_files()) + if(E.login in result) + continue + if(E.backup) + result[E.login] = E + + return result + +/datum/computer_network/proc/add_account(datum/computer_file/data/account/acc, accesses) + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(MF_ROLE_ACCOUNT_SERVER, accesses)) + if(M.store_file(acc, OS_ACCOUNTS_DIR, TRUE)) + return TRUE + +/datum/computer_network/proc/find_account_by_login(login, accesses) + for(var/datum/computer_file/data/account/A in get_accounts(accesses)) + if(A.login == login) + return A + +/datum/computer_network/proc/create_account(mob/user, desired_login, desired_password, full_name, list/accesses, force_create = TRUE) + desired_login = sanitize_for_account(desired_login) + var/login = "[desired_login]" + if(!length(login)) + return FALSE + if(find_account_by_login(login)) + if(force_create) + login = "[desired_login][random_id(/datum/computer_file/data/account/, 100, 999)]" + else + return FALSE + if(!desired_password) + if(force_create) + desired_password = GenerateKey() + var/datum/computer_file/data/account/EA = new/datum/computer_file/data/account(login, desired_password, full_name) + if(add_account(EA, accesses)) + if(user) + user.store_account_credentials(EA.login, EA.password, network_id) + return TRUE + return FALSE + +/datum/computer_network/proc/rename_account(old_login, desired_login) + var/datum/computer_file/data/account/account = find_account_by_login(old_login) + var/new_login = sanitize_for_account(desired_login) + if(new_login == old_login) + return TRUE//If we aren't going to be changing the login, we quit silently. + if(find_account_by_login(new_login)) + return FALSE + account.login = new_login + add_log("Account login changed: [old_login] changed to [new_login]") + +// Mob procs +/mob/proc/store_account_credentials(login, password, network_id) + if(mind) + mind.initial_account_login["login"] = login + mind.initial_account_login["password"] = password + mind.account_network = network_id + StoreMemory("Your [network_id] login is [login] and the password is [password].", /decl/memory_options/system) + var/obj/item/card/id/I = GetIdCard() + if(I) + I.associated_network_account = list("login" = login, "password" = password) + +/mob/proc/create_or_update_account(newname) + if(!mind) + return + var/datum/computer_network/network = get_local_network_at(get_turf(src)) + if(network) + var/old_account = mind.initial_account_login["login"] + if(!old_account) + network.create_account(src, newname) + else + network.rename_account(old_account, newname) \ No newline at end of file diff --git a/code/modules/modular_computers/networking/accounts/account.dm b/code/modules/modular_computers/networking/accounts/account.dm new file mode 100644 index 000000000000..91aa2dfbe47a --- /dev/null +++ b/code/modules/modular_computers/networking/accounts/account.dm @@ -0,0 +1,101 @@ +/datum/computer_file/data/account + filetype = "ACT" + var/login = "" + var/password = "" + + var/can_login = TRUE // Whether you can log in with this account. Set to false for system accounts + var/suspended = FALSE // Whether the account is banned by the SA. + var/list/logged_in_os = list() // OS which are currently logged into this account. Used for e-mail notifications, currently. + + var/list/groups = list() // Groups which this account is a member of. + var/list/parent_groups = list() // Parent groups with a child/children which this account is a member of. + + var/fullname = "N/A" + + // E-Mail + var/list/inbox = list() + var/list/outbox = list() + var/list/spam = list() + var/list/deleted = list() + + var/broadcaster = FALSE // If sent to true, e-mails sent to this address will be automatically sent to all other accounts in the network. + + var/notification_mute = FALSE + var/notification_sound = "*beep*" + var/backup = FALSE // Backups are not returned when searching for accounts, but can be recovered using the accounts program. + + copy_string = "(Backup)" + +/datum/computer_file/data/account/calculate_size() + size = 1 + for(var/datum/computer_file/data/email_message/stored_message in all_emails()) + stored_message.calculate_size() + size += stored_message.size + +/datum/computer_file/data/account/New(_login, _password, _fullname) + if(_login) + login = _login + stored_data = "[login]" + if(_password) + password = _password + if(_fullname) + fullname = _fullname + if(filename == initial(filename)) + filename = "account[random_id(type, 100,999)]" + ..() + +/datum/computer_file/data/account/Destroy() + for(var/weakref/os_ref in logged_in_os) + var/datum/extension/interactive/os/os = os_ref.resolve() + if(os.login == login) + os.logout_account() + + logged_in_os.Cut() + groups.Cut() + parent_groups.Cut() + + QDEL_NULL_LIST(inbox) + QDEL_NULL_LIST(outbox) + QDEL_NULL_LIST(spam) + QDEL_NULL_LIST(deleted) + . = ..() + +/datum/computer_file/data/account/proc/all_emails() + return (inbox | spam | deleted | outbox) + +/datum/computer_file/data/account/proc/all_incoming_emails() + return (inbox | spam | deleted) + +/datum/computer_file/data/account/proc/receive_mail(var/datum/computer_file/data/email_message/received_message, var/datum/computer_network/network) + +/datum/computer_file/data/account/Clone(rename) + . = ..(TRUE) // We always rename the file since a copied account is always a backup. + +/datum/computer_file/data/account/PopulateClone(datum/computer_file/data/account/clone) + clone = ..() + clone.backup = TRUE + clone.login = login + clone.password = password + clone.can_login = can_login + clone.suspended = suspended + clone.groups = groups.Copy() + clone.parent_groups = parent_groups.Copy() + clone.fullname = fullname + + // TODO: Don't backup e-mails for now - they are themselves other files which makes this complicated. In the future + // accounts will point to e-mails stored seperately on a server. + return clone + +// Address namespace (@internal-services.net) for email addresses with special purpose only!. +/datum/computer_file/data/account/service + can_login = FALSE + +/datum/computer_file/data/account/service/broadcaster + login = EMAIL_BROADCAST + broadcaster = TRUE + +/datum/computer_file/data/account/service/document + login = EMAIL_DOCUMENTS + +/datum/computer_file/data/account/service/sysadmin + login = EMAIL_SYSADMIN \ No newline at end of file diff --git a/code/modules/modular_computers/networking/accounts/id_card.dm b/code/modules/modular_computers/networking/accounts/id_card.dm new file mode 100644 index 000000000000..aa959dc67526 --- /dev/null +++ b/code/modules/modular_computers/networking/accounts/id_card.dm @@ -0,0 +1,120 @@ +/obj/item/card/id/network + var/network_id // The network_id that this card is paired to. + var/weakref/current_account + color = COLOR_GRAY80 + detail_color = COLOR_SKY_BLUE + +/obj/item/card/id/network/Initialize() + set_extension(src, /datum/extension/network_device/id_card, network_id) + return ..() + +/obj/item/card/id/network/GetAccess(var/ignore_account) + . = ..() + var/datum/computer_file/data/account/access_account = resolve_account() + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = D.get_network(NET_FEATURE_ACCESS) + if(network && access_account && access_account.login != ignore_account) + var/location = "[network.network_id]" + if(access_account) + . += "[access_account.login]@[location]" // User access uses '@' + for(var/group in access_account.groups) + . += "[group].[location]" // Group access uses '.' + for(var/group in access_account.parent_groups) // Membership in a child group grants access to anything with an access requirement set to the parent group. + . += "[group].[location]" + +/obj/item/card/id/network/proc/resolve_account() + if(!current_account) + return + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = D.get_network(NET_FEATURE_ACCESS) + + var/login = associated_network_account["login"] + var/password = associated_network_account["password"] + + var/error + var/datum/computer_file/data/account/check_account = current_account.resolve() + if(!network) // No network or connectivity. + error = "No network found" + else if(!istype(check_account)) + error = "The specified account could not be found" + else if(check_account.login != login || check_account.password != password) // The most likely case - login or password were changed. + error = "Incorrect username or password" + // Check if the account can be located on the network in case it was moved. + else if(!(check_account in network.get_accounts())) + error = "The specified account could not be found" + + if(error) + current_account = null + visible_message(SPAN_WARNING("\The [src] flashes an error: \'[error]!\'"), null, null,1) + else + return check_account + +/obj/item/card/id/network/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null) + var/data[0] + var/login = associated_network_account["login"] + var/password = associated_network_account["password"] + + data["login"] = login ? login : "Enter Login" + data["password"] = password ? stars(password, 0) : "Enter Password" + ui = SSnano.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + ui = new(user, src, ui_key, "network_id.tmpl", "Network ID Settings", 540, 326) + ui.set_initial_data(data) + ui.open() + +/obj/item/card/id/network/Topic(href, href_list, datum/topic_state/state) + . = ..() + if(.) + return + var/login = associated_network_account["login"] + var/password = associated_network_account["password"] + if(href_list["change_login"]) + var/new_login = sanitize(input(usr, "Enter your account login:", "Account login", login) as text|null) + if(new_login == login || !CanInteract(usr, DefaultTopicState())) + return TOPIC_NOACTION + associated_network_account["login"] = new_login + + current_account = null + password = null + return TOPIC_REFRESH + + if(href_list["change_password"]) + var/new_password = sanitize(input(usr, "Enter your account password:", "Account password") as text|null) + if(new_password == password || !CanInteract(usr, DefaultTopicState())) + return TOPIC_NOACTION + associated_network_account["password"] = new_password + + current_account = null + return TOPIC_REFRESH + + if(href_list["login_account"]) + if(login_account()) + to_chat(usr, SPAN_NOTICE("Account successfully logged in.")) + else + to_chat(usr, SPAN_WARNING("Could not login to account. Check password or network connectivity.")) + return TOPIC_REFRESH + + if(href_list["settings"]) + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + D.ui_interact(usr) + return TOPIC_HANDLED + +/obj/item/card/id/network/proc/login_account() + . = FALSE + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = D.get_network(NET_FEATURE_ACCESS) + if(!network) + return + var/login = associated_network_account["login"] + var/password = associated_network_account["password"] + for(var/datum/computer_file/data/account/check_account in network.get_accounts()) + if(check_account.login == login && check_account.password == password) + current_account = weakref(check_account) + return TRUE + +/obj/item/card/id/network/verb/adjust_settings() + set name = "Adjust Settings" + set category = "Object" + set src in usr + + ui_interact(usr) \ No newline at end of file diff --git a/code/modules/modular_computers/networking/device_types/_network_device.dm b/code/modules/modular_computers/networking/device_types/_network_device.dm index 64a093e1b90b..b6167cf74191 100644 --- a/code/modules/modular_computers/networking/device_types/_network_device.dm +++ b/code/modules/modular_computers/networking/device_types/_network_device.dm @@ -6,20 +6,52 @@ var/key // passkey for the network var/address // unique network address, cannot be set by user var/network_tag // human-readable network address, can be set by user. Networks enforce uniqueness, will change it if there's clash. - var/connection_type = NETWORK_CONNECTION_STRONG_WIRELESS // affects signal strength + var/receiver_type = RECEIVER_STRONG_WIRELESS // affects signal strength + var/connection_attempts = 0 + var/internet_allowed = FALSE // Whether or not these devices can be connected over PLEXUS. -/datum/extension/network_device/New(datum/holder, n_id, n_key, c_type, autojoin = TRUE) + var/long_range = FALSE // Whether or not this device can connect to broadcasters across z-chunks. + + var/has_commands = FALSE // Whether or not this device can be configured to receive commands to modify and call public variables and methods. + var/list/command_and_call // alias -> public method to be called. + var/list/command_and_write // alias -> public variable to be written to or read from. + + var/last_rand_time // Last time a random method was called. + + // These variables are for the *device's* public variables and methods, if they exist. + var/list/device_variables + var/list/device_methods + + /// Tracking var for autojoin, to resolve an ordering issue in device creation/connection. + VAR_PRIVATE/_autojoin + +/datum/extension/network_device/New(datum/holder, n_id, n_key, r_type, autojoin = TRUE) ..() network_id = n_id key = n_key - if(c_type) - connection_type = c_type + if(r_type) + receiver_type = r_type address = uppertext(NETWORK_MAC) var/obj/O = holder network_tag = "[uppertext(replacetext(O.name, " ", "_"))]-[sequential_id(type)]" - if(autojoin) - SSnetworking.queue_connection(src) - + _autojoin = autojoin + + if(length(device_variables)) + for(var/path in device_variables) + device_variables[path] = GET_DECL(path) + if(length(device_methods)) + for(var/path in device_methods) + device_methods[path] = GET_DECL(path) + + if(has_commands) + reload_commands() + +// Must be done here so that our holder's get_extension calls work. +/datum/extension/network_device/post_construction() + . = ..() + if(_autojoin) + SSnetworking.try_connect(src) + /datum/extension/network_device/Destroy() disconnect() . = ..() @@ -30,25 +62,33 @@ return FALSE return net.add_device(src) -/datum/extension/network_device/proc/disconnect() +/datum/extension/network_device/proc/disconnect(net_down) var/datum/computer_network/net = SSnetworking.networks[network_id] + if (net_down) + SSnetworking.queue_reconnect(src, network_id) if(!net) return FALSE return net.remove_device(src) +// Returns list(signal type, signal strength) on success, null on failure. /datum/extension/network_device/proc/check_connection(specific_action) var/datum/computer_network/net = SSnetworking.networks[network_id] if(!net) + // We should already be queued for reconnect if it went down, so do nothing. return FALSE - if(!net.check_connection(src, specific_action) || !net.add_device(src)) - return FALSE - return net.get_signal_strength(src) - + if(net.devices_by_tag[network_tag] != src) + // The connection has failed but the network is still up, so we try to reconnect. + if(!connect()) + return FALSE + return net.check_connection(src, specific_action) + /datum/extension/network_device/proc/get_signal_wordlevel() - var/datum/computer_network/network = get_network() - if(!network) - return "Not Connected" - var/signal_strength = network.get_signal_strength(src) + var/list/signal_data = check_connection() + if(!islist(signal_data)) + return "Not connected" + if(signal_data[1] == INTERNET_CONNECTION) + return "Connected over PLEXUS" + var/signal_strength = signal_data[2] if(signal_strength <= 0) return "Not Connected" if(signal_strength < (NETWORK_BASE_BROADCAST_STRENGTH * 0.5)) @@ -56,13 +96,26 @@ else return "High Signal" +// Returns list(network_id -> connection type, ...) /datum/extension/network_device/proc/get_nearby_networks() - var/list/networks = list() + var/list/wired_networks = list() + var/list/wireless_networks = list() + var/list/internet_networks = list() for(var/id in SSnetworking.networks) var/datum/computer_network/net = SSnetworking.networks[id] - if(net.check_connection(src)) - networks |= id - return networks + var/list/signal_data = net.check_connection(src) + if(!islist(signal_data)) + continue + switch(signal_data[1]) + if(WIRED_CONNECTION) + wired_networks[id] = WIRED_CONNECTION + if(WIRELESS_CONNECTION) + wireless_networks[id] = WIRELESS_CONNECTION + if(INTERNET_CONNECTION) + internet_networks[id] = INTERNET_CONNECTION + + // We return it like this so that wired networks have their connections prioritized over wireless and internet connections. + return wired_networks + wireless_networks + internet_networks /datum/extension/network_device/proc/is_banned() var/datum/computer_network/net = get_network() @@ -70,8 +123,8 @@ return FALSE return (address in net.banned_nids) -/datum/extension/network_device/proc/get_network() - if(check_connection()) +/datum/extension/network_device/proc/get_network(specific_action) + if(check_connection(specific_action)) return SSnetworking.networks[network_id] /datum/extension/network_device/proc/add_log(text) @@ -99,11 +152,17 @@ /datum/extension/network_device/proc/set_new_id(new_id, user) var/list/networks = get_nearby_networks() if(new_id in networks) + if(!SSnetworking.networks[network_id]) // old network is down, so we should unqueue from its reconnect list + SSnetworking.unqueue_reconnect(src, network_id) + var/connection_type = networks[new_id] disconnect() network_id = new_id to_chat(user, SPAN_NOTICE("Network ID changed to '[network_id]'.")) if(connect()) - to_chat(user, SPAN_NOTICE("Connected to the network '[network_id]'.")) + if(connection_type == INTERNET_CONNECTION) + to_chat(user, SPAN_NOTICE("Connected to the network '[network_id]' via PLEXUS connection. Certain actions on the network may be restricted.")) + else + to_chat(user, SPAN_NOTICE("Connected to the network '[network_id]'.")) else to_chat(user, SPAN_WARNING("Unable to connect to the network '[network_id]'. Check your passkey and try again.")) else @@ -146,6 +205,25 @@ network.update_device_tag(src, network_tag, new_tag) network_tag = new_tag +/datum/extension/network_device/proc/get_wired_connection() + var/obj/machinery/M = holder + if(!istype(M)) + return + var/obj/item/stock_parts/computer/lan_port/port = M.get_component_of_type(/obj/item/stock_parts/computer/lan_port) + if(!port || !port.terminal) + return + var/obj/structure/network_cable/terminal/term = port.terminal + return term.get_graph() + +/datum/extension/network_device/proc/has_internet_connection(connecting_network) + // Overmap isn't used, a modem alone provides internet connection. + if(!length(global.using_map.overmap_ids)) + return TRUE + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[get_z(holder)] + if(!istype(sector)) + return + return sector.has_internet_connection(connecting_network) + /datum/extension/network_device/nano_host() return holder.nano_host() @@ -155,6 +233,22 @@ data["network_key"] = network_id ? "******" : "NOT SET" data["network_tag"] = network_tag data["status"] = get_signal_wordlevel() + + data["commands"] = has_commands + if(has_commands) + // For public methods. + var/method_list = list() + for(var/thing in command_and_call) + var/decl/public_access/variable = command_and_call[thing] + method_list += list(list("alias" = thing, "reference" = "\ref[variable]", "reference_name" = "[variable.name]")) + data["methods"] = method_list + // For public variables. + var/var_list = list() + for(var/thing in command_and_write) + var/decl/public_access/variable = command_and_write[thing] + var_list += list(list("alias" = thing, "reference" = "\ref[variable]", "reference_name" = "[variable.name]")) + data["variables"] = var_list + return data /datum/extension/network_device/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) @@ -162,7 +256,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) var/atom/A = holder - ui = new(user, src, ui_key, "network_machine_settings.tmpl", capitalize(A.name), 380, 500) + ui = new(user, src, ui_key, "network_machine_settings.tmpl", capitalize(A.name), 500, 500) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -184,17 +278,193 @@ do_change_net_tag(user) return TOPIC_REFRESH -/datum/extension/network_device/proc/has_access(mob/user) +/datum/extension/network_device/proc/has_access(list/accesses) var/datum/computer_network/network = get_network() if(!network) return TRUE // If not on network, always TRUE for access, as there isn't anything to access. - if(!user) + var/obj/M = get_top_holder() + if(!accesses) + accesses = list() + return M.check_access_list(accesses) + +// Return the target of the command passed to this device. +/datum/extension/network_device/proc/get_command_target(command) + var/decl/public_access/public_thing + if(command_and_call && command_and_call[command]) + public_thing = command_and_call[command] + else if(command_and_write && command_and_write[command]) + public_thing = command_and_write[command] + else + return + if(device_variables && (public_thing.type in device_variables)) + return src + if(device_methods && (public_thing.type in device_methods)) + return src + if((public_thing.type in get_holder_variables()) || (public_thing.type in get_holder_methods())) + return holder + +// Return the public methods and variables available for commands. +/datum/extension/network_device/proc/get_public_methods() + var/list/public_methods = get_holder_methods() + if(device_methods) + public_methods += device_methods + return public_methods + +/datum/extension/network_device/proc/get_public_variables() + var/list/public_variables = get_holder_variables() + if(device_variables) + public_variables += device_variables + return public_variables + +/datum/extension/network_device/proc/get_holder_methods() + var/obj/machinery/M = get_top_holder() + if(istype(M)) + return M.public_methods?.Copy() + +/datum/extension/network_device/proc/get_holder_variables() + var/obj/machinery/M = get_top_holder() + if(istype(M)) + return M.public_variables?.Copy() + +/datum/extension/network_device/proc/set_command_reference(list/selected_commands, alias, reference) + if(!alias || !reference) + return + LAZYSET(selected_commands, alias, reference) + +/datum/extension/network_device/proc/add_command(list/selected_commands, alias, list/valid_commands) + if(!alias) + alias = copytext(md5(num2text(rand(0, 25))), 1, 11) + LAZYSET(selected_commands, alias, valid_commands[pick(valid_commands)]) // Random key and command + return alias + +/datum/extension/network_device/proc/change_command_alias(old_alias, new_alias) + new_alias = sanitize(new_alias) + new_alias = replacetext(new_alias, " ", "") // Strip spaces from the key. + + // Check if a command with the new alias already exists + if(LAZYACCESS(command_and_call, new_alias) || LAZYACCESS(command_and_write, new_alias)) return FALSE - var/obj/item/card/id/network/id = user.GetIdCard() - if(id && istype(id, /obj/item/card/id/network) && network.access_controller && (id.user_id in network.access_controller.administrators)) + + if(LAZYACCESS(command_and_call, old_alias)) + LAZYSET(command_and_call, new_alias, LAZYACCESS(command_and_call, old_alias)) + LAZYREMOVE(command_and_call, old_alias) + return TRUE + + if(LAZYACCESS(command_and_write, old_alias)) + LAZYSET(command_and_write, new_alias, LAZYACCESS(command_and_write, old_alias)) + LAZYREMOVE(command_and_write, old_alias) return TRUE - var/obj/M = holder - return M.allowed(user) + +/datum/extension/network_device/proc/remove_command(alias) + if(LAZYACCESS(command_and_call, alias)) + LAZYREMOVE(command_and_call, alias) + return TRUE + if(LAZYACCESS(command_and_write, alias)) + LAZYREMOVE(command_and_write, alias) + return TRUE + return FALSE + +// Any modification of public vars and calling methods from network commands. Return text feedback on success/unsuccess of command. +/datum/extension/network_device/proc/on_command(command, command_args, list/access) + var/datum/command_target = get_command_target(command) + if(!has_commands) + return "Device cannot receive commands." + if(!command_target) + return "No valid target found for command '[command]'" + if(!has_access(access)) + return "Access denied." + if(LAZYACCESS(command_and_call, command)) + var/decl/public_access/public_method/method = command_and_call[command] + var/output = method.perform(arglist(list(command_target) + command_args)) + return "Successfully called method '[command]' on [network_tag]." + "[output ? " Device reported: [output]" : null]" + if(LAZYACCESS(command_and_write, command)) + var/decl/public_access/public_variable/variable = command_and_write[command] + if(command_args) // Write to a var. + command_args = sanitize_command_args(command_args, variable.var_type) + if(isnull(command_args)) // Command could not be converted into a form appropriate for the variable. + return "Improper argument type; correct type is [variable.var_type]" + if(variable.write_var_protected(command_target, command_args)) + return "Successfully set variable '[command]' on [network_tag] to [command_args]." + return "Unable to set variable '[command]' on [network_tag]." + else // Read from a var. + return "Variable '[command]' on [network_tag] has value: [variable.access_var(command_target)]" + return "Command '[command]' not found on [network_tag]." + +// Returns the variable converted into the proper form, or null if it is unable to. +/datum/extension/network_device/proc/sanitize_command_args(command_args, var_type) + // First check if the command is a list; if it is, only accept it if the expected type is a list. + if(islist(command_args)) + if(var_type == VAR_FORMAT_LIST) + return command_args + else + return null + switch(var_type) + if(VAR_FORMAT_ANY) + return command_args + if(VAR_FORMAT_STRING) + return "[command_args]" + if(VAR_FORMAT_CHAR) + if(istext(command_args) && length(command_args) == 1) + return command_args + if(VAR_FORMAT_COLOR) + return sanitize_hexcolor(command_args, null) + if(VAR_FORMAT_NUMBER, VAR_FORMAT_INDEX) + if(istext(command_args)) + return text2num(command_args) + if(isnum(command_args)) + return command_args + if(VAR_FORMAT_DIR) + if(istext(command_args)) + return text2dir(command_args) + if(VAR_FORMAT_BOOLEAN) + if(istext(command_args)) + switch(uppertext(command_args)) + if("TRUE") + return TRUE + if("FALSE") + return FALSE + +// Calls a random method for skill failure etc. +/datum/extension/network_device/proc/random_method(list/access) + if(world.time < last_rand_time + 5 SECONDS) + return "Reinstancing command system, please try again in a few moments." + if(access && !has_access(access)) + return "Access denied" + var/rand_alias = SAFEPICK(command_and_call) + var/decl/public_access/public_method/rand_method = LAZYACCESS(command_and_call, rand_alias) + if(!istype(rand_method)) + return "No commands found." + rand_method.perform(get_command_target()) + last_rand_time = world.time + return "Encoding fault, incorrect command resolution likely" + +// Reloads commands and automatically adds them to the proper lists. +/datum/extension/network_device/proc/reload_commands() + LAZYCLEARLIST(command_and_call) + LAZYCLEARLIST(command_and_write) + + var/list/pub_methods = get_public_methods() + var/list/pub_vars = get_public_variables() + + for(var/path in pub_methods) + var/decl/public_access/pub_method = pub_methods[path] + var/alias = pub_method.name + alias = replacetext(alias, " ", "_") + LAZYSET(command_and_call, alias, pub_method) + + for(var/path in pub_vars) + var/decl/public_access/pub_var = pub_vars[path] + var/alias = pub_var.name + alias = replacetext(alias, " ", "_") + LAZYSET(command_and_write, alias, pub_var) + +/**Returns the outward facing URI for this network device.*/ +/datum/extension/network_device/proc/get_network_URI() + return "[network_tag].[network_id]" + +/**Returns the object that should be handling access and command checks.*/ +/datum/extension/network_device/proc/get_top_holder() + return holder //Subtype for passive devices, doesn't init until asked for /datum/extension/network_device/lazy diff --git a/code/modules/modular_computers/networking/device_types/acl.dm b/code/modules/modular_computers/networking/device_types/acl.dm index f209d13669a9..3dea9e1dd8a8 100644 --- a/code/modules/modular_computers/networking/device_types/acl.dm +++ b/code/modules/modular_computers/networking/device_types/acl.dm @@ -1,25 +1,126 @@ /datum/extension/network_device/acl - connection_type = NETWORK_CONNECTION_WIRED - var/list/administrators = list() // A list of numerical user IDs of users that are administrators on a network. + var/list/group_dict = list() // Groups on the network, stored as strings. + // Parents groups with children have a list of child groups associated with the string key -/datum/extension/network_device/acl/proc/add_admin(var/user_id) - administrators |= user_id + var/list/all_groups = list() // All group strings, not sorted by parent or child group. Used for uniqueness checking. -/datum/extension/network_device/acl/proc/rem_admin(var/user_id) - administrators -= user_id + var/allow_submanagement = FALSE // If enabled, users who are members of a parent group will be able to manage membership of all child groups under that parent group, + // Otherwise, assignment is strictly by access to the network access controller + var/parent_account_creation = FALSE // If enabled, all users who are members of ANY parent group will be able to create new accounts. + // Otherwise, account creation is restricted to those with access to the account server(s) -/datum/extension/network_device/acl/proc/get_grant(var/grant_data) + has_commands = TRUE + device_methods = list( + /decl/public_access/public_method/add_group, + /decl/public_access/public_method/remove_group, + /decl/public_access/public_method/list_groups + ) + +/datum/extension/network_device/acl/proc/get_group_dict() + return group_dict + +/datum/extension/network_device/acl/proc/get_all_groups() + return all_groups + +// Check if the passed user account can create new accounts by seeing if parent account creation is enabled, then checking +// if they are a member of a parent group. Otherwise, account creation permission is solely based on access to account servers. +/datum/extension/network_device/acl/proc/check_account_creation_auth(datum/computer_file/data/account/check_account) + if(parent_account_creation && check_account) + for(var/group in check_account.groups) + if(group in group_dict) + return TRUE + return FALSE + +/datum/extension/network_device/acl/proc/add_group(group_name, parent_group) + group_name = sanitize_for_group("[group_name]") + if(!length(group_name) || !istext(group_name) || (parent_group && !istext(parent_group))) + return "Input Error" + if(length(group_name) > 15) + return "Maximum group name length is 15 characters." + if(group_name in all_groups) + return "Group name must be unique" + + // Adding a child group. + if(parent_group) + if(!(parent_group in group_dict)) + return "No parent group with name \"[parent_group]\" found." + if(!group_dict[parent_group]) + group_dict[parent_group] = list() + group_dict[parent_group] += group_name + else + group_dict += group_name + + all_groups += group_name + return "Added [parent_group ? "child group" : "parent group"] \"[group_name]\"" + "[parent_group ? " to \"[parent_group]\"." : "."]" + +/datum/extension/network_device/acl/proc/remove_group(group_name, parent_group) + if(!istext(group_name) || (parent_group && !istext(parent_group))) + return "Input Error" + if(parent_group) + if(!(parent_group in group_dict)) + return "No parent group with name \"[parent_group]\" found." + if(!group_dict[parent_group] || !(group_name in group_dict[parent_group])) + return "No child group with name \"[group_name]\" found in \"[parent_group]\"" + group_dict[parent_group] -= group_name + if(!length(group_dict[parent_group])) // Cull the list until we add a new child group. + group_dict[parent_group] = null + all_groups -= group_name + return "Removed child group \"[group_name]\" from parent group \"[parent_group]\"." + if(group_name in group_dict) + if(length(group_dict[group_name])) + for(var/child_name in group_dict[group_name]) + all_groups -= child_name + group_dict -= group_name + all_groups -= group_name + return "Removed parent group \"[group_name]\" and associated child groups." + else + return "No parent group with name \"[parent_group]\" found." + +/datum/extension/network_device/acl/proc/toggle_parent_account_creation() + parent_account_creation = !parent_account_creation var/datum/computer_network/network = get_network() - if(!network) - return - return network.find_file_by_name(grant_data, MF_ROLE_CREW_RECORDS) + if(network.access_controller == src) + network.add_log("Access controller parent account creation toggled [parent_account_creation ? "ON" : "OFF"]", network_tag) + -/datum/extension/network_device/acl/proc/get_all_grants() - var/list/grants = list() +/datum/extension/network_device/acl/proc/toggle_submanagement() + allow_submanagement = !allow_submanagement var/datum/computer_network/network = get_network() - if(!network) - return grants - var/list/grant_files = network.get_all_files_of_type(/datum/computer_file/data/grant_record, MF_ROLE_CREW_RECORDS, TRUE) - for(var/datum/computer_file/data/grant_record/GR in grant_files) - grants |= GR - return grants \ No newline at end of file + if(network.access_controller == src) + network.add_log("Access controller submanagement toggled [allow_submanagement ? "ON" : "OFF"]", network_tag) + +/datum/extension/network_device/acl/proc/get_group_listing(parent_group) + if(parent_group && !istext(parent_group)) + return "Input Error" + if(parent_group) + if(!(parent_group in group_dict)) + return "No parent group with name \"[parent_group]\" found." + return "[parent_group]: [english_list(group_dict[parent_group])]" + return "Parent groups: [english_list(group_dict)]" + +// Helper proc for adding multiple groups at once for preset ACLs etc. +/datum/extension/network_device/acl/proc/add_groups(list/preset_groups) + for(var/parent_group in preset_groups) + add_group(parent_group) + var/list/child_groups = preset_groups[parent_group] + if(islist(child_groups)) + for(var/child_group in child_groups) + add_group(child_group, parent_group) + +/decl/public_access/public_method/add_group + name = "Add group" + desc = "Adds a new group with the passed name. A parent group can be passed to add a child group." + call_proc = TYPE_PROC_REF(/datum/extension/network_device/acl, add_group) + forward_args = TRUE + +/decl/public_access/public_method/remove_group + name = "Remove group" + desc = "Removes a group with the passed name. A parent group can be passed to remove a child group of that parent." + call_proc = TYPE_PROC_REF(/datum/extension/network_device/acl, remove_group) + forward_args = TRUE + +/decl/public_access/public_method/list_groups + name = "List groups" + desc = "Lists groups on the group access controller. A parent group can be passed list children of that parent group." + call_proc = TYPE_PROC_REF(/datum/extension/network_device/acl, get_group_listing) + forward_args = TRUE \ No newline at end of file diff --git a/code/modules/modular_computers/networking/device_types/broadcaster.dm b/code/modules/modular_computers/networking/device_types/broadcaster.dm index 40ca67239a76..830ef5a16279 100644 --- a/code/modules/modular_computers/networking/device_types/broadcaster.dm +++ b/code/modules/modular_computers/networking/device_types/broadcaster.dm @@ -1,14 +1,14 @@ /datum/extension/network_device/broadcaster expected_type = /obj/machinery - connection_type = NETWORK_CONNECTION_WIRED + receiver_type = RECEIVER_BROADCASTER + var/allow_wifi = TRUE + var/tmp/cached_rating = null /datum/extension/network_device/broadcaster/proc/get_broadcast_strength() - var/obj/item/stock_parts/computer/network_card/network_card = get_network_card() - if(!network_card) + var/obj/machinery/M = holder + if(!istype(M) || !M.operable()) return 0 - return NETWORK_BASE_BROADCAST_STRENGTH * (network_card.long_range ? 2 : 1) -/datum/extension/network_device/broadcaster/proc/get_network_card() - var/obj/machinery/M = holder - if(istype(M)) - return M.get_component_of_type(/obj/item/stock_parts/computer/network_card) \ No newline at end of file + if(isnull(cached_rating)) + cached_rating = NETWORK_BASE_BROADCAST_STRENGTH * clamp(M.total_component_rating_of_type(/obj/item/stock_parts/micro_laser), 1, 3) + return cached_rating \ No newline at end of file diff --git a/code/modules/modular_computers/networking/device_types/id_card.dm b/code/modules/modular_computers/networking/device_types/id_card.dm new file mode 100644 index 000000000000..7d08442ea380 --- /dev/null +++ b/code/modules/modular_computers/networking/device_types/id_card.dm @@ -0,0 +1,5 @@ +/datum/extension/network_device/id_card + base_type = /datum/extension/network_device + flags = EXTENSION_FLAG_NONE // Lazy-init these. + + internet_allowed = TRUE \ No newline at end of file diff --git a/code/modules/modular_computers/networking/device_types/mainframe.dm b/code/modules/modular_computers/networking/device_types/mainframe.dm index ef961d50e73f..97387b2a4067 100644 --- a/code/modules/modular_computers/networking/device_types/mainframe.dm +++ b/code/modules/modular_computers/networking/device_types/mainframe.dm @@ -1,7 +1,12 @@ -GLOBAL_LIST_INIT(all_mainframe_roles, list(MF_ROLE_SOFTWARE, MF_ROLE_FILESERVER, MF_ROLE_EMAIL_SERVER, MF_ROLE_LOG_SERVER, MF_ROLE_CREW_RECORDS)) +var/global/list/all_mainframe_roles = list( + MF_ROLE_SOFTWARE, + MF_ROLE_FILESERVER, + MF_ROLE_LOG_SERVER, + MF_ROLE_CREW_RECORDS, + MF_ROLE_ACCOUNT_SERVER +) /datum/extension/network_device/mainframe - connection_type = NETWORK_CONNECTION_WIRED expected_type = /obj/machinery var/max_log_count = 100 var/list/roles = list() @@ -26,64 +31,55 @@ GLOBAL_LIST_INIT(all_mainframe_roles, list(MF_ROLE_SOFTWARE, MF_ROLE_FILESERVER, if(istype(M)) return M.get_component_of_type(/obj/item/stock_parts/computer/hard_drive) +// File storage procs /datum/extension/network_device/mainframe/proc/get_all_files() var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(HDD) return HDD.stored_files -/datum/extension/network_device/mainframe/proc/get_file(filename) +/datum/extension/network_device/mainframe/proc/get_file(filename, directory) var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(HDD) - return HDD.find_file_by_name(filename) + return HDD.find_file_by_name(filename, directory) -/datum/extension/network_device/mainframe/proc/delete_file(filename) +/datum/extension/network_device/mainframe/proc/delete_file(datum/computer_file/F, list/accesses, mob/user) var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(HDD) - var/datum/computer_file/data/F = HDD.find_file_by_name(filename) - if(!F || F.undeletable) - return FALSE - return HDD.remove_file(F) + return HDD.remove_file(F, accesses, user) -/datum/extension/network_device/mainframe/proc/store_file(datum/computer_file/file) +/datum/extension/network_device/mainframe/proc/store_file(datum/computer_file/file, directory, create_directories, list/accesses, mob/user, overwrite = TRUE) var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(!HDD) - return FALSE - var/datum/computer_file/data/old_version = HDD.find_file_by_name(file.filename) - if(old_version) - HDD.remove_file(old_version) - if(!HDD.store_file(file)) - HDD.store_file(old_version) - return FALSE - else - return TRUE + return OS_HARDDRIVE_ERROR -/datum/extension/network_device/mainframe/proc/save_file(newname, new_data) + return HDD.store_file(file, directory, create_directories, accesses, user, overwrite) + +/datum/extension/network_device/mainframe/proc/try_store_file(datum/computer_file/file, directory, list/accesses, mob/user) var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(!HDD) - return FALSE + return OS_HARDDRIVE_ERROR - var/datum/computer_file/data/F = HDD.find_file_by_name(newname) - //Try to save file, possibly won't fit size-wise - var/datum/computer_file/data/backup - if(F) - backup = F.clone() - HDD.remove_file(F) - else - F = new() - F.stored_data = new_data - F.calculate_size() - if(!HDD.store_file(F)) - if(backup) - HDD.store_file(backup) - return FALSE - return TRUE + return HDD.try_store_file(file, directory, accesses, user) -/datum/extension/network_device/mainframe/proc/append_to_file(filename, data) +/datum/extension/network_device/mainframe/proc/save_file(newname, directory, new_data, list/metadata, list/accesses, mob/user) var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(!HDD) - return FALSE - var/datum/computer_file/data/logfile/F = get_file(filename) - if(F) + return OS_HARDDRIVE_ERROR + return HDD.save_file(newname, directory, new_data, metadata, accesses, user) + +/datum/extension/network_device/mainframe/proc/parse_directory(directory_path, create_directories) + var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() + if(!HDD) + return OS_HARDDRIVE_ERROR + + return HDD.parse_directory(directory_path, create_directories) + +/datum/extension/network_device/mainframe/proc/append_to_file(filename, directory, data) + var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() + if(!HDD) + return OS_HARDDRIVE_ERROR + var/datum/computer_file/data/logfile/F = get_file(filename, directory) + if(istype(F)) var/list/logs = splittext(F.stored_data, "\[br\]") logs.Add(data) if(length(logs) > max_log_count) @@ -94,8 +90,7 @@ GLOBAL_LIST_INIT(all_mainframe_roles, list(MF_ROLE_SOFTWARE, MF_ROLE_FILESERVER, F = new() F.filename = filename F.stored_data = data - store_file(F) - return TRUE + return store_file(F, directory) /datum/extension/network_device/mainframe/proc/get_capacity() var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() @@ -107,18 +102,8 @@ GLOBAL_LIST_INIT(all_mainframe_roles, list(MF_ROLE_SOFTWARE, MF_ROLE_FILESERVER, var/obj/item/stock_parts/computer/hard_drive/HDD = get_storage() if(!HDD) return 0 - return HDD.used_capacity - -// Disk that spawns with everything old system had -/obj/item/stock_parts/computer/hard_drive/cluster/fullhouse/Initialize() - . = ..() - - for(var/F in subtypesof(/datum/computer_file/report)) - var/datum/computer_file/report/type = F - if(initial(type.available_on_network)) - store_file(new type) - - for(var/F in subtypesof(/datum/computer_file/program)) - var/datum/computer_file/program/type = F - if(initial(type.available_on_network)) - store_file(new type) \ No newline at end of file + return HDD.used_capacity + +// starts with no files, useful for things like mainframes +/obj/item/stock_parts/computer/hard_drive/cluster/empty/install_default_programs() + return \ No newline at end of file diff --git a/code/modules/modular_computers/networking/device_types/modem.dm b/code/modules/modular_computers/networking/device_types/modem.dm new file mode 100644 index 000000000000..4ccea488fdb7 --- /dev/null +++ b/code/modules/modular_computers/networking/device_types/modem.dm @@ -0,0 +1,4 @@ +/datum/extension/network_device/modem + expected_type = /obj/machinery + + var/allowed_features = NET_FEATURE_COMMUNICATION | NET_FEATURE_ACCESS \ No newline at end of file diff --git a/code/modules/modular_computers/networking/device_types/relay.dm b/code/modules/modular_computers/networking/device_types/relay.dm index 3f7bb7bbae69..8a1a755f6416 100644 --- a/code/modules/modular_computers/networking/device_types/relay.dm +++ b/code/modules/modular_computers/networking/device_types/relay.dm @@ -1,7 +1,8 @@ /datum/extension/network_device/broadcaster/relay - connection_type = NETWORK_CONNECTION_WIRED expected_type = /obj/machinery - var/long_range = 0 // TRUE if relay can cross z-chunk boundaries. + +/datum/extension/network_device/broadcaster/relay/long_range + long_range = TRUE /datum/extension/network_device/broadcaster/relay/get_nearby_networks() if(long_range) @@ -11,7 +12,7 @@ var/datum/computer_network/network = SSnetworking.networks[network_id] var/list/broadcasters = network.relays + network.router for(var/datum/extension/network_device/D in broadcasters) - if(ARE_Z_CONNECTED(get_z(D.holder), get_z(holder))) + if(LEVELS_ARE_Z_CONNECTED(get_z(D.holder), get_z(holder))) networks |= network_id break return networks @@ -20,6 +21,7 @@ var/datum/computer_network/net = SSnetworking.networks[network_id] if(!net) return FALSE - if(!long_range && !(network_id in get_nearby_networks())) - return FALSE - return net.add_device(src) \ No newline at end of file + return net.add_device(src) + +/datum/extension/network_device/broadcaster/relay/long_range + long_range = TRUE diff --git a/code/modules/modular_computers/networking/device_types/router.dm b/code/modules/modular_computers/networking/device_types/router.dm index 62500fa37c34..f2bb8de39783 100644 --- a/code/modules/modular_computers/networking/device_types/router.dm +++ b/code/modules/modular_computers/networking/device_types/router.dm @@ -1,7 +1,4 @@ -/datum/extension/network_device/broadcaster/router - connection_type = NETWORK_CONNECTION_WIRED - /datum/extension/network_device/broadcaster/router/New(datum/holder, n_id, n_key, c_type) ..() broadcast() @@ -12,6 +9,7 @@ net = new(network_id) if(!net.router) net.set_router(src) + SSnetworking.process_reconnections(network_id) /datum/extension/network_device/broadcaster/router/proc/is_router() var/datum/computer_network/net = SSnetworking.networks[network_id] diff --git a/code/modules/modular_computers/networking/device_types/stock_part.dm b/code/modules/modular_computers/networking/device_types/stock_part.dm new file mode 100644 index 000000000000..c497d79657e7 --- /dev/null +++ b/code/modules/modular_computers/networking/device_types/stock_part.dm @@ -0,0 +1,24 @@ +// Attached to a stock part for issuing commands to machinery via networks. +/datum/extension/network_device/stock_part + has_commands = TRUE + internet_allowed = TRUE // GOOSE devices, network locks, etc. can all connect over PLEXUS + +/datum/extension/network_device/stock_part/get_wired_connection() + var/atom/H = holder + var/obj/machinery/M = H.loc + if(!istype(M)) + return + var/obj/item/stock_parts/computer/lan_port/port = M.get_component_of_type(/obj/item/stock_parts/computer/lan_port) + if(!port || !port.terminal) + return + var/obj/structure/network_cable/terminal/term = port.terminal + return term.get_graph() + +/datum/extension/network_device/stock_part/get_command_target() + return get_top_holder() + +/datum/extension/network_device/stock_part/get_top_holder() + var/atom/A = holder + var/obj/machinery/M = A.loc + if(istype(M)) + return M \ No newline at end of file diff --git a/code/modules/modular_computers/networking/emails/_email.dm b/code/modules/modular_computers/networking/emails/_email.dm new file mode 100644 index 000000000000..7b36c9fb7b9a --- /dev/null +++ b/code/modules/modular_computers/networking/emails/_email.dm @@ -0,0 +1,46 @@ +/datum/computer_network/proc/send_email(datum/computer_file/data/account/sender, recipient_address, datum/computer_file/data/email_message/sent) + var/list/address_comp = splittext(recipient_address, "@") + if(length(address_comp) < 2) + return FALSE + var/recipient_login = address_comp[1] + var/recipient_net_id = address_comp[2] + + var/datum/computer_network/recipient_network = get_internet_connection(recipient_net_id, NET_FEATURE_COMMUNICATION) + if(!istype(recipient_network)) + return FALSE + + var/datum/computer_file/data/account/recipient = recipient_network.find_account_by_login(recipient_login) + if(!istype(recipient)) + return FALSE + + if(!recipient_network.receive_email(recipient, "[sender.login]@[network_id]", sent)) + return FALSE + + sender.outbox.Add(sent) + if(intrusion_detection_enabled) + add_log("EMAIL LOG: [sender.login]@[network_id] -> [recipient.login]@[recipient_network.network_id] title: [sent.title].") + return TRUE + +/datum/computer_network/proc/receive_email(datum/computer_file/data/account/recipient, sender_address, datum/computer_file/data/email_message/received) + if(!(recipient in get_accounts_unsorted())) + return FALSE + + var/datum/computer_file/data/email_message/received_copy = received.Clone() + received_copy.set_timestamp() + recipient.inbox.Add(received_copy) + recipient.receive_mail(received_copy, src) + + for(var/weakref/os_ref in recipient.logged_in_os) + var/datum/extension/interactive/os/os = os_ref.resolve() + if(istype(os)) + os.mail_received(received_copy) + else + recipient.logged_in_os -= os_ref + + if(recipient.broadcaster) + for(var/datum/computer_file/data/account/email_account in get_accounts_unsorted()) + if(email_account.broadcaster) + continue + var/datum/computer_file/data/email_message/new_message = received.Clone() + send_email(recipient, "[email_account.login]@[network_id]", new_message) + return TRUE \ No newline at end of file diff --git a/code/modules/modular_computers/networking/emails/_network_email.dm b/code/modules/modular_computers/networking/emails/_network_email.dm deleted file mode 100644 index 40fbedaccf0f..000000000000 --- a/code/modules/modular_computers/networking/emails/_network_email.dm +++ /dev/null @@ -1,70 +0,0 @@ -/datum/computer_network/proc/get_email_addresses() - var/list/result = list() - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(MF_ROLE_EMAIL_SERVER)) - for(var/datum/computer_file/data/email_account/E in M.get_all_files()) - ADD_SORTED(result, E, /proc/cmp_emails_asc) - return result - -/datum/computer_network/proc/add_email_account(datum/computer_file/data/email_account/acc) - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(MF_ROLE_EMAIL_SERVER)) - if(M.store_file(acc)) - return TRUE - -/datum/computer_network/proc/find_email_by_name(var/login) - for(var/datum/computer_file/data/email_account/A in get_email_addresses()) - if(A.login == login) - return A - -/datum/computer_network/proc/create_email(mob/user, desired_name, domain, assignment) - desired_name = sanitize_for_email(desired_name) - var/login = "[desired_name]@[domain]" - if(find_email_by_name(login)) - login = "[desired_name][random_id(/datum/computer_file/data/email_account/, 100, 999)]@[domain]" - - var/datum/computer_file/data/email_account/EA = new/datum/computer_file/data/email_account(login, user.real_name, assignment) - EA.password = GenerateKey() - add_email_account(EA) - user.store_email_credentials(EA.login, EA.password) - -/datum/computer_network/proc/rename_email(mob/user, old_login, desired_name, domain) - var/datum/computer_file/data/email_account/account = find_email_by_name(old_login) - var/new_login = sanitize_for_email(desired_name) - new_login += "@[domain]" - if(new_login == old_login) - return //If we aren't going to be changing the login, we quit silently. - if(find_email_by_name(new_login)) - to_chat(user, "Your email could not be updated: the new username is invalid.") - return - account.login = new_login - add_log("Email address changed for [user]: [old_login] changed to [new_login]") - user.update_email_name(new_login) - - -// Mob procs -/mob/proc/store_email_credentials(login, password) - if(mind) - mind.initial_email_login["login"] = login - mind.initial_email_login["password"] = password - StoreMemory("Your email account address is [login] and the password is [password].", /decl/memory_options/system) - var/obj/item/card/id/I = GetIdCard() - if(I) - I.associated_email_login = list("login" = login, "password" = password) - -/mob/proc/update_email_name(login) - if(mind) - mind.initial_email_login["login"] = login - StoreMemory("Your email account address has been changed to [login].", /decl/memory_options/system) - var/obj/item/card/id/I = GetIdCard() - if(I && I.associated_email_login) - I.associated_email_login["login"] = login - -/mob/proc/create_or_rename_email(newname, domain) - if(!mind) - return - var/datum/computer_network/network = get_local_network_at(get_turf(src)) - if(network) - var/old_email = mind.initial_email_login["login"] - if(!old_email) - network.create_email(src, newname, domain) - else - network.rename_email(src, old_email, newname, domain) \ No newline at end of file diff --git a/code/modules/modular_computers/networking/emails/email_account.dm b/code/modules/modular_computers/networking/emails/email_account.dm deleted file mode 100644 index 865ed20dec98..000000000000 --- a/code/modules/modular_computers/networking/emails/email_account.dm +++ /dev/null @@ -1,89 +0,0 @@ -/datum/computer_file/data/email_account/ - var/list/inbox = list() - var/list/outbox = list() - var/list/spam = list() - var/list/deleted = list() - - var/login = "" - var/password = "" - var/can_login = TRUE // Whether you can log in with this account. Set to false for system accounts - var/suspended = FALSE // Whether the account is banned by the SA. - var/connected_clients = list() - - var/fullname = "N/A" - var/assignment = "N/A" - -/datum/computer_file/data/email_account/calculate_size() - size = 1 - for(var/datum/computer_file/data/email_message/stored_message in all_emails()) - stored_message.calculate_size() - size += stored_message.size - -/datum/computer_file/data/email_account/New(_login, _fullname, _assignment) - login = _login - if(_fullname) - fullname = _fullname - if(_assignment) - assignment = _assignment - ..() - -/datum/computer_file/data/email_account/proc/all_emails() - return (inbox | spam | deleted | outbox) - -/datum/computer_file/data/email_account/proc/send_mail(var/recipient_address, var/datum/computer_file/data/email_message/message, var/datum/computer_network/network) - if(!network) - return - var/datum/computer_file/data/email_account/recipient - for(var/datum/computer_file/data/email_account/account in network.get_email_addresses()) - if(account.login == recipient_address) - recipient = account - break - - if(!istype(recipient)) - return 0 - - if(!recipient.receive_mail(message, network)) - return - - outbox.Add(message) - if(network.intrusion_detection_enabled) - network.add_log("EMAIL LOG: [login] -> [recipient.login] title: [message.title].") - return 1 - -/datum/computer_file/data/email_account/proc/receive_mail(var/datum/computer_file/data/email_message/received_message, var/datum/computer_network/network) - if(!network) - return - received_message.set_timestamp() - inbox.Add(received_message) - for(var/datum/nano_module/program/email_client/ec in connected_clients) - if(ec.get_network() == network) - ec.mail_received(received_message) - return 1 - -// Address namespace (@internal-services.net) for email addresses with special purpose only!. -/datum/computer_file/data/email_account/service/ - can_login = FALSE - -/datum/computer_file/data/email_account/service/broadcaster/ - login = EMAIL_BROADCAST - -/datum/computer_file/data/email_account/service/broadcaster/receive_mail(var/datum/computer_file/data/email_message/received_message, var/datum/computer_network/network) - if(!network || !istype(received_message)) - return 0 - // Possibly exploitable for user spamming so keep admins informed. - if(!received_message.spam) - log_and_message_admins("Broadcast email address used by [usr]. Message title: [received_message.title].") - - for(var/datum/computer_file/data/email_account/email_account in network.get_email_addresses()) - if(istype(email_account, /datum/computer_file/data/email_account/service/broadcaster/)) - continue - var/datum/computer_file/data/email_message/new_message = received_message.clone() - send_mail(email_account.login, new_message, network) - - return 1 - -/datum/computer_file/data/email_account/service/document - login = EMAIL_DOCUMENTS - -/datum/computer_file/data/email_account/service/sysadmin - login = EMAIL_SYSADMIN \ No newline at end of file diff --git a/code/modules/modular_computers/networking/emails/email_message.dm b/code/modules/modular_computers/networking/emails/email_message.dm index d499195db281..ef3ee45d41ef 100644 --- a/code/modules/modular_computers/networking/emails/email_message.dm +++ b/code/modules/modular_computers/networking/emails/email_message.dm @@ -1,5 +1,5 @@ // Currently not actually represented in file systems, though the support for it is in place already. -/datum/computer_file/data/email_message/ +/datum/computer_file/data/email_message stored_data = "" var/title = "" var/source = "" @@ -7,16 +7,18 @@ var/timestamp = "" var/datum/computer_file/attachment = null -/datum/computer_file/data/email_message/clone() - var/datum/computer_file/data/email_message/temp = ..() - temp.title = title - temp.source = source - temp.spam = spam - temp.timestamp = timestamp - if(attachment) - temp.attachment = attachment.clone() - return temp +/datum/computer_file/data/email_message/Destroy() + . = ..() + QDEL_NULL(attachment) +/datum/computer_file/data/email_message/PopulateClone(datum/computer_file/data/email_message/clone) + clone = ..() + clone.title = title + clone.source = source + clone.spam = spam + clone.timestamp = timestamp + clone.attachment = attachment?.Clone() + return clone // Turns /email_message/ file into regular /data/ file. /datum/computer_file/data/email_message/proc/export() diff --git a/code/modules/modular_computers/networking/machinery/_network_machine.dm b/code/modules/modular_computers/networking/machinery/_network_machine.dm index 414b4bc2b62a..004e337e4490 100644 --- a/code/modules/modular_computers/networking/machinery/_network_machine.dm +++ b/code/modules/modular_computers/networking/machinery/_network_machine.dm @@ -2,7 +2,8 @@ name = "base network machine" icon = 'icons/obj/machines/tcomms/bus.dmi' icon_state = "bus" - density = 1 + density = TRUE + anchored = TRUE var/main_template = "network_mainframe.tmpl" var/network_device_type = /datum/extension/network_device @@ -10,34 +11,50 @@ var/initial_network_id var/initial_network_key + var/wired_connection = FALSE // Whether or not this machine will start with a local network connection. var/produces_heat = TRUE // If true, produces and is affected by heat. var/inefficiency = 0.12 // How much power is waste heat. var/heat_threshold = 90 CELSIUS // At what temperature the machine will lock up. var/overheated = FALSE - var/runtimeload // Use this for calling an even later lateload. + + var/tmp/tag_network_tag //The name of this device on the network set by mapper + +/obj/machinery/network/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) + ADJUST_TAG_VAR(tag_network_tag, map_hash) /obj/machinery/network/Initialize() - set_extension(src, network_device_type, initial_network_id, initial_network_key, NETWORK_CONNECTION_WIRED) + var/datum/extension/network_device/ND = get_or_create_extension(src, network_device_type, initial_network_id, initial_network_key, RECEIVER_STRONG_WIRELESS) + if(length(tag_network_tag)) + ND.set_network_tag(tag_network_tag) + . = ..() + +/obj/machinery/network/populate_parts(full_populate) . = ..() + if(full_populate && wired_connection) + install_component(/obj/item/stock_parts/computer/lan_port, FALSE) /obj/machinery/network/proc/is_overheated() - var/turf/simulated/L = loc - if(istype(L)) + var/turf/L = loc + if(istype(L) && L.simulated) var/datum/gas_mixture/env = L.return_air() if(env.temperature >= heat_threshold) return TRUE /obj/machinery/network/on_update_icon() - if(operable()) - icon_state = panel_open ? "bus_o" : "bus" - else - icon_state = panel_open ? "bus_o_off" : "bus_off" + icon_state = initial(icon_state) + if(panel_open) + icon_state = "[icon_state]_o" + if(!operable()) + icon_state = "[icon_state]_off" /obj/machinery/network/proc/produce_heat() if (!produces_heat || !use_power || !operable()) return - var/turf/simulated/L = loc - if(istype(L)) + var/turf/L = loc + if(istype(L) && L.simulated) var/datum/gas_mixture/env = L.return_air() var/transfer_moles = 0.25 * env.total_moles var/datum/gas_mixture/removed = env.remove(transfer_moles) // Air is moved through computer vents. @@ -46,18 +63,11 @@ env.merge(removed) /obj/machinery/network/Process() - if(runtimeload) - RuntimeInitialize() - runtimeload = FALSE - set_overheated(is_overheated()) if(stat & (BROKEN|NOPOWER)) return produce_heat() -/obj/machinery/network/proc/RuntimeInitialize() - - /obj/machinery/network/interface_interact(user) ui_interact(user) return TRUE @@ -116,6 +126,14 @@ if(!D) return if(operable()) - D.connect() + SSnetworking.queue_connection(D) // must queue, due to router race conditions else - D.disconnect() \ No newline at end of file + D.disconnect() + +/obj/machinery/network/proc/get_message_server() + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/datum/extension/network_device/message_server in network?.devices) + var/obj/machinery/network/message_server/MS = message_server.holder + if(istype(MS) && !(MS.stat & (BROKEN|NOPOWER))) + return MS \ No newline at end of file diff --git a/code/modules/modular_computers/networking/machinery/acl.dm b/code/modules/modular_computers/networking/machinery/acl.dm index ee643a47e4d8..7fe16ac83c03 100644 --- a/code/modules/modular_computers/networking/machinery/acl.dm +++ b/code/modules/modular_computers/networking/machinery/acl.dm @@ -1,227 +1,118 @@ /obj/machinery/network/acl name = "network access controller" + desc = "A mainframe that manages encryption keys tied to groups and their children on its parent network." icon = 'icons/obj/machines/tcomms/aas.dmi' + icon_state = "aas" network_device_type = /datum/extension/network_device/acl main_template = "network_acl.tmpl" construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 base_type = /obj/machinery/network/acl - runtimeload = TRUE - // Datum file source for where grants/records are. - var/datum/file_storage/network/file_source = /datum/file_storage/network/machine - var/editing_user // Numerical user ID of the user being editing on this device. - var/list/initial_grants //defaults to all possible station accesses if left null - -/obj/machinery/network/acl/merchant - initial_grants = list( - access_crate_cash, - access_merchant - ) - -/obj/machinery/network/acl/antag - initial_grants = list( - access_syndicate - ) + var/current_group // The group currently being edited. + var/list/preset_groups // Dictionary of parent groups->list(child_groups) /obj/machinery/network/acl/Initialize() . = ..() - if(isnull(initial_grants)) - initial_grants = get_all_station_access() - if(ispath(file_source)) - file_source = new file_source(null, src) - -/obj/machinery/network/acl/RuntimeInitialize() - // Get default file server. - var/datum/extension/network_device/acl/FW = get_extension(src, /datum/extension/network_device) - var/datum/computer_network/network = FW.get_network() - if(network) - var/datum/extension/network_device/file_server = network.get_file_server_by_role(MF_ROLE_CREW_RECORDS) - if(file_server) - file_source.server = file_server.network_tag - // Populate initial grants. - for(var/grant in initial_grants) - create_grant(grant) - -/obj/machinery/network/acl/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/card/id)) // ID Card, try to insert it. - var/obj/item/card/id/I = W - var/obj/item/stock_parts/computer/card_slot/card_slot = get_component_of_type(/obj/item/stock_parts/computer/card_slot) - if(!card_slot) - return - card_slot.insert_id(I, user) - return - . = ..() + if(preset_groups) + var/datum/extension/network_device/acl/D = get_extension(src, /datum/extension/network_device) + D.add_groups(preset_groups) /obj/machinery/network/acl/OnTopic(mob/user, href_list, datum/topic_state/state) . = ..() if(.) return - var/datum/extension/network_device/acl/computer = get_extension(src, /datum/extension/network_device) - var/datum/computer_network/network = computer.get_network() - if(!network) - error = "NETWORK ERROR: Connection lost." + var/datum/extension/network_device/acl/D = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = D.get_network() + if(!network || network.access_controller != D) + error = "NETWORK ERROR: Connection lost. Another access controller may be active on the network." return TOPIC_REFRESH if(href_list["back"]) - editing_user = null + current_group = null return TOPIC_REFRESH - if(href_list["change_file_server"]) - var/list/file_servers = network.get_file_server_tags(MF_ROLE_CREW_RECORDS) - var/file_server = input(usr, "Choose a fileserver to view access records on:", "Select File Server") as null|anything in file_servers - if(file_server) - file_source.server = file_server + if(href_list["create_group"]) + var/group_name = sanitize_for_group(input(user, "Enter the name of the new group. Maximum 15 characters, only alphanumeric characters, _ and - are allowed:", "Create Group")) + if(!length(group_name)) + return TOPIC_HANDLED + if(!CanInteract(user, global.default_topic_state)) return TOPIC_REFRESH - if(href_list["assign_grant"]) - // Resolve our selection back to a file. - var/datum/computer_file/data/grant_record/grant = computer.get_grant(href_list["assign_grant"]) - if(!grant) - error = "ERROR: Grant record not found." - return TOPIC_REFRESH - var/datum/computer_file/report/crew_record/AR = get_access_record() - if(!AR) - error = "ERROR: Access record not found." - return TOPIC_REFRESH - AR.add_grant(grant) - - if(href_list["remove_grant"]) - var/datum/computer_file/report/crew_record/AR = get_access_record() - if(!AR) - error = "ERROR: Access record not found." - return TOPIC_REFRESH - AR.remove_grant(href_list["remove_grant"]) // Add the grant to the record. + var/output = D.add_group(group_name, current_group) + if(group_name in D.all_groups) + to_chat(user, SPAN_NOTICE(output)) + else // Failure! + to_chat(user, SPAN_WARNING(output)) + return TOPIC_REFRESH - if(href_list["create_grant"]) - var/new_grant_name = uppertext(sanitize(input(usr, "Enter the name of the new grant:", "Create Grant"))) - if(!CanInteract(user, GLOB.default_state)) - return TOPIC_REFRESH - if(!new_grant_name) + if(href_list["remove_group"]) + var/group_name = href_list["remove_group"] + var/removal_check = alert(user, "Are you sure you want to remove the group [group_name]?", "Group Removal", "No", "Yes") + if(!CanInteract(user, global.default_topic_state)) return TOPIC_REFRESH - if(!create_grant(new_grant_name)) - error = "MAINFRAME ERROR: Unable to store grant on mainframe." + if(removal_check == "Yes") + var/output = D.remove_group(group_name, current_group) + if(group_name in D.all_groups) // Failure! + to_chat(user, SPAN_WARNING(output)) + else + to_chat(user, SPAN_NOTICE(output)) return TOPIC_REFRESH - if(href_list["delete_grant"]) - if(!file_source.delete_file(href_list["delete_grant"])) - error = "FIREWALL ERROR: Unable to delete grant." - return TOPIC_REFRESH - - if(href_list["view_user"]) - editing_user = href_list["view_user"] - - if(href_list["write_id"]) - var/obj/item/stock_parts/computer/card_slot/card_slot = get_component_of_type(/obj/item/stock_parts/computer/card_slot) - if(!card_slot) - error = "HARDWARE ERROR: No NTOS-v2 compatible device found." - return TOPIC_REFRESH - var/obj/item/card/id/network/card = card_slot.stored_card - if(!card) - error = "HARDWARE ERROR: No valid card inserted." - return TOPIC_REFRESH - // Write to the card. - var/datum/computer_file/report/crew_record/AR = get_access_record() - card.network_id = computer.network_id - card.user_id = AR.user_id - card.access_record = AR - visible_message(SPAN_NOTICE("\The [src] clicks and hums, writing new data to \a [card].")) + if(href_list["toggle_submanagement"]) + D.toggle_submanagement() + return TOPIC_REFRESH - if(href_list["eject_id"]) - var/obj/item/stock_parts/computer/card_slot/card_slot = get_component_of_type(/obj/item/stock_parts/computer/card_slot) - if(!card_slot) - error = "HARDWARE ERROR: No NTOS-v2 compatible device found." - return TOPIC_REFRESH - if(!card_slot.stored_card) - error = "HARDWARE ERROR: No valid card inserted." - return TOPIC_REFRESH - card_slot.eject_id(user) + if(href_list["toggle_parent_account_creation"]) + D.toggle_parent_account_creation() + return TOPIC_REFRESH - if(href_list["add_admin"]) - network.access_controller.add_admin(editing_user) + if(href_list["view_child_groups"]) + var/parent_group = href_list["view_child_groups"] + if(parent_group && (parent_group in D.group_dict)) + current_group = parent_group + else + current_group = null + return TOPIC_REFRESH - if(href_list["remove_admin"]) - network.access_controller.rem_admin(editing_user) + if(href_list["info"]) + switch(href_list["info"]) + if("submanagement") + to_chat(user, SPAN_NOTICE("If parent group submanagement is toggled on, members of the parent group will be allowed to manage account membership in child groups. This may be useful for departmental heads.")) + if("parent_account_creation") + to_chat(user, SPAN_NOTICE("If parent account creation is toggled on, members of any parent group will be allowed to create new user accounts. Otherwise, account creation requires access to an account server.")) /obj/machinery/network/acl/ui_data(mob/user, ui_key) . = ..() if(error) + .["error"] = error return - var/obj/item/stock_parts/computer/card_slot/card_slot = get_component_of_type(/obj/item/stock_parts/computer/card_slot) - if(card_slot) - .["card_inserted"] = !!card_slot.stored_card - - var/datum/extension/network_device/acl/computer = get_extension(src, /datum/extension/network_device) - if(!computer.get_network()) + var/datum/extension/network_device/acl/D = get_extension(src, /datum/extension/network_device) + if(!D.get_network()) .["connected"] = FALSE return .["connected"] = TRUE - .["file_server"] = file_source.server - .["editing_user"] = editing_user - - // Let's build some data. - if(editing_user) - var/datum/computer_network/network = computer.get_network() - .["user_id"] = editing_user - .["is_admin"] = (editing_user in network.access_controller.administrators) - var/datum/computer_file/report/crew_record/AR = get_access_record() - if(!istype(AR)) - // Something has gone wrong. Our AR file is missing. - error = "NETWORK ERROR: Unable to find access record for user [editing_user]." - return - var/list/grants[0] - var/list/assigned_grants = AR.get_valid_grants() - // We're editing a user, so we only need to build a subset of data. - .["desired_name"] = AR.get_name() - .["grant_count"] = length(assigned_grants) - .["size"] = AR.size - for(var/datum/computer_file/data/grant_record/GR in computer.get_all_grants()) - grants.Add(list(list( - "grant_name" = GR.stored_data, - "assigned" = (GR in assigned_grants) - ))) - .["grants"] = grants + .["allow_submanagement"] = D.allow_submanagement + .["parent_account_creation"] = D.parent_account_creation + + // Modifying parent group, display child groups + if(current_group) + .["current_group"] = current_group + var/list/child_groups[0] + if(D.group_dict[current_group]) + for(var/child_group in D.group_dict[current_group]) + child_groups.Add(list(list( + "group_name" = child_group, + ))) + .["child_groups"] = child_groups else - // We're looking at all records. Or lack thereof. - var/list/users[0] - for(var/datum/computer_file/report/crew_record/AR in get_all_users()) - users.Add(list(list( - "desired_name" = AR.get_name(), - "user_id" = AR.user_id, - "grant_count" = length(AR.get_valid_grants()), - "size" = AR.size + // We're looking at all parent groups. + var/list/parent_groups[0] + for(var/parent_group in D.group_dict) + parent_groups.Add(list(list( + "group_name" = parent_group, ))) - .["users"] = users - -/obj/machinery/network/acl/on_update_icon() - if(operable()) - icon_state = panel_open ? "AAS_On_Open" : "AAS_On" - else - icon_state = panel_open ? "AAS_Off_Open" : "AAS_Off" - -/obj/machinery/network/acl/proc/get_all_users() - var/list/users = list() - for(var/datum/computer_file/report/crew_record/CR in file_source.get_all_files()) - users |= CR - return users - -// Get the access record for the user we're *currently* editing. -/obj/machinery/network/acl/proc/get_access_record(var/for_specific_id) - var/for_user = for_specific_id - if(!for_user) - for_user = editing_user - for(var/datum/computer_file/report/crew_record/AR in get_all_users()) - if(AR.user_id != for_user) - continue - return AR - -/obj/machinery/network/acl/proc/create_grant(var/grant_data) - if(!file_source.create_file(grant_data, /datum/computer_file/data/grant_record)) - return FALSE - var/datum/computer_file/data/grant_record/grant = file_source.get_file(grant_data) - grant.set_value(grant_data) - grant.calculate_size() - return TRUE \ No newline at end of file + .["parent_groups"] = parent_groups \ No newline at end of file diff --git a/code/modules/modular_computers/networking/machinery/mainframe.dm b/code/modules/modular_computers/networking/machinery/mainframe.dm index cc284c48a0cb..3f25c9e811c0 100644 --- a/code/modules/modular_computers/networking/machinery/mainframe.dm +++ b/code/modules/modular_computers/networking/machinery/mainframe.dm @@ -9,17 +9,37 @@ stat_immune = 0 base_type = /obj/machinery/network/mainframe var/list/initial_roles = list( - MF_ROLE_FILESERVER, - MF_ROLE_EMAIL_SERVER, + MF_ROLE_FILESERVER, MF_ROLE_LOG_SERVER, MF_ROLE_CREW_RECORDS, - MF_ROLE_SOFTWARE + MF_ROLE_SOFTWARE, + MF_ROLE_ACCOUNT_SERVER ) /obj/machinery/network/mainframe/Initialize() . = ..() + var/datum/extension/network_device/mainframe/M = get_extension(src, /datum/extension/network_device) M.roles |= initial_roles + M.update_roles() + + if(!(MF_ROLE_SOFTWARE in initial_roles)) + return + + var/obj/item/stock_parts/computer/hard_drive/drive = get_component_of_type(PART_HDD) + for(var/F in subtypesof(/datum/computer_file/report)) + var/datum/computer_file/report/type = F + if(TYPE_IS_ABSTRACT(type)) + continue + if(initial(type.available_on_network)) + drive.store_file(new type, "reports", TRUE) + + for(var/F in subtypesof(/datum/computer_file/program)) + var/datum/computer_file/program/type = F + if(TYPE_IS_ABSTRACT(type)) + continue + if(initial(type.available_on_network)) + drive.store_file(new type, OS_PROGRAMS_DIR, TRUE) /obj/machinery/network/mainframe/ui_data(mob/user, ui_key) var/data = ..() @@ -27,7 +47,7 @@ if(!istype(M)) return data var/list/roles[0] - for(var/role in GLOB.all_mainframe_roles) + for(var/role in global.all_mainframe_roles) var/list/rdata[0] rdata["name"] = role rdata["enabled"] = !!(role in M.roles) @@ -38,7 +58,7 @@ data["capacity"] = M.get_capacity() data["used"] = M.get_used() return data - + /obj/machinery/network/mainframe/OnTopic(mob/user, href_list, datum/topic_state/state) . = ..() if(.) @@ -47,9 +67,23 @@ var/datum/extension/network_device/mainframe/M = get_extension(src, /datum/extension/network_device) M.toggle_role(href_list["toggle_role"]) return TOPIC_REFRESH - -/obj/machinery/network/mainframe/on_update_icon() - if(operable()) - icon_state = "blackbox" - else - icon_state = "blackbox_off" \ No newline at end of file + +//Network Presets + +/obj/machinery/network/mainframe/empty + initial_roles = list() + +/obj/machinery/network/mainframe/files + initial_roles = list(MF_ROLE_FILESERVER) + +/obj/machinery/network/mainframe/account + initial_roles = list(MF_ROLE_ACCOUNT_SERVER) + +/obj/machinery/network/mainframe/logs + initial_roles = list(MF_ROLE_LOG_SERVER) + +/obj/machinery/network/mainframe/records + initial_roles = list(MF_ROLE_CREW_RECORDS) + +/obj/machinery/network/mainframe/software + initial_roles = list(MF_ROLE_SOFTWARE) diff --git a/code/modules/modular_computers/networking/machinery/modem.dm b/code/modules/modular_computers/networking/machinery/modem.dm new file mode 100644 index 000000000000..deb1b71e07f6 --- /dev/null +++ b/code/modules/modular_computers/networking/machinery/modem.dm @@ -0,0 +1,51 @@ +/obj/machinery/network/modem + name = "network modem" + desc = "A modern modem used to allow communication between computer networks using the PLEXUS infrastructure." + icon = 'icons/obj/machines/tcomms/hub.dmi' + icon_state = "hub" + network_device_type = /datum/extension/network_device/modem + main_template = "network_modem.tmpl" + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = 0 + base_type = /obj/machinery/network/modem + + // What you can do over PLEXUS alone is limited. + var/static/list/feature_options = list( + "Communication Systems" = NET_FEATURE_COMMUNICATION, + "Access systems" = NET_FEATURE_ACCESS, + "Security systems" = NET_FEATURE_SECURITY, + "Filesystem access" = NET_FEATURE_FILESYSTEM + ) + +/obj/machinery/network/modem/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + if(.) + return + var/datum/extension/network_device/modem/M = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = M.get_network() + if(!network || network.modem != M) + error = "NETWORK ERROR: Connection lost. Another modem may be active on the network." + return TOPIC_REFRESH + + if(href_list["toggle_feature"]) + var/feature = feature_options[href_list["toggle_feature"]] + if(!feature) + return TOPIC_HANDLED + M.allowed_features ^= feature + return TOPIC_REFRESH + +/obj/machinery/network/modem/ui_data(mob/user, ui_key) + . = ..() + var/datum/extension/network_device/modem/M = get_extension(src, /datum/extension/network_device) + if(!istype(M)) + return + + var/list/features = list() + for(var/feature in feature_options) + var/list/fdata[0] + fdata["name"] = feature + fdata["enabled"] = M.allowed_features & feature_options[feature] + features.Add(list(fdata)) + + .["features"] = features \ No newline at end of file diff --git a/code/modules/modular_computers/networking/machinery/relay.dm b/code/modules/modular_computers/networking/machinery/relay.dm index c5e5562775e9..1178507ed298 100644 --- a/code/modules/modular_computers/networking/machinery/relay.dm +++ b/code/modules/modular_computers/networking/machinery/relay.dm @@ -1,6 +1,7 @@ /obj/machinery/network/relay name = "network relay" icon = 'icons/obj/machines/tcomms/relay.dmi' + icon_state = "relay" network_device_type = /datum/extension/network_device/broadcaster/relay main_template = "network_router.tmpl" construct_state = /decl/machine_construction/default/panel_closed @@ -9,8 +10,31 @@ base_type = /obj/machinery/network/relay produces_heat = FALSE // for convenience -/obj/machinery/network/relay/on_update_icon() - if(operable()) - icon_state = panel_open ? "relay_o" : "relay" - else - icon_state = panel_open ? "relay_o_off" : "relay_off" \ No newline at end of file +/obj/machinery/network/relay/RefreshParts() + . = ..() + var/datum/extension/network_device/broadcaster/relay/R = get_extension(src, /datum/extension/network_device) + R.cached_rating = null // regenerate cached value + +/obj/machinery/network/relay/ui_data(mob/user, ui_key) + var/data = ..() + var/datum/extension/network_device/broadcaster/relay/R = get_extension(src, /datum/extension/network_device) + if(!istype(R)) + return data + data["wifi"] = R.allow_wifi + return data + +/obj/machinery/network/relay/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["toggle_wifi"]) + var/datum/extension/network_device/broadcaster/relay/R = get_extension(src, /datum/extension/network_device) + if(R) + R.allow_wifi = !R.allow_wifi + return TOPIC_REFRESH + . = ..() + +// Long ranged network relay. Alternative to PLEXUS for maps which don't wish to use it. Otherwise difficult to obtain. +/obj/machinery/network/relay/long_range + name = "long-ranged network relay" + icon = 'icons/obj/machines/tcomms/relay.dmi' + icon_state = "relay" + network_device_type = /datum/extension/network_device/broadcaster/relay/long_range + base_type = /obj/machinery/network/relay/long_range diff --git a/code/modules/modular_computers/networking/machinery/router.dm b/code/modules/modular_computers/networking/machinery/router.dm index 4b1a70800116..faeb07d06505 100644 --- a/code/modules/modular_computers/networking/machinery/router.dm +++ b/code/modules/modular_computers/networking/machinery/router.dm @@ -1,6 +1,7 @@ /obj/machinery/network/router name = "network router" icon = 'icons/obj/machines/tcomms/comm_server.dmi' + icon_state = "comm_server" network_device_type = /datum/extension/network_device/broadcaster/router main_template = "network_router.tmpl" construct_state = /decl/machine_construction/default/panel_closed @@ -13,6 +14,11 @@ initial_network_id = "network[random_id(type, 100, 999)]" . = ..() +/obj/machinery/network/router/RefreshParts() + . = ..() + var/datum/extension/network_device/broadcaster/router/R = get_extension(src, /datum/extension/network_device) + R.cached_rating = null // regenerate cached value + /obj/machinery/network/router/ui_data(mob/user, ui_key) var/data = ..() var/datum/extension/network_device/broadcaster/router/R = get_extension(src, /datum/extension/network_device) @@ -21,13 +27,17 @@ var/datum/computer_network/net = R.get_network() if(net) data["is_router"] = R.is_router() + data["wifi"] = R.allow_wifi return data -/obj/machinery/network/router/on_update_icon() - if(operable()) - icon_state = panel_open ? "comm_server_o" : "comm_server" - else - icon_state = panel_open ? "comm_server_o_off" : "comm_server_off" +/obj/machinery/network/router/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["toggle_wifi"]) + var/datum/extension/network_device/broadcaster/router/R = get_extension(src, /datum/extension/network_device) + if(R) + R.allow_wifi = !R.allow_wifi + return TOPIC_REFRESH + + . = ..() /obj/machinery/network/router/update_network_status() ..() diff --git a/code/modules/modular_computers/networking/machinery/telecomms.dm b/code/modules/modular_computers/networking/machinery/telecomms.dm new file mode 100644 index 000000000000..acf603cd60db --- /dev/null +++ b/code/modules/modular_computers/networking/machinery/telecomms.dm @@ -0,0 +1,406 @@ +// Notes on new tcomms system: +// - Telecomms hubs will initialize a list of channels based on the default map configuration +// or their own initial channel list. +// - Radios will connect to the network and query all telecomms hubs for their channel information. +// - Radios contain encryption keys that in turn contain a list of access constants used to decide +// whether or not the radio can send and receive traffic encrypted with those access constants. +// - Radios will not retrieve and cannot broadcast on receive-only channels (such as Entertainment). +// - Network hubs that share a z-chunk or are connected via masers and receivers will share traffic +// on channels using the same frequency (ex. a merc ship with a relay will relay merc Common to ship Common). +// Each network hub a message "passes" through will add its encryption to the message. + +/datum/extension/network_device/telecomms_hub + expected_type = /obj/machinery/network/telecomms_hub + +/datum/extension/network_device/telecomms_hub/connect() + . = ..() + if(. && holder) + var/datum/computer_network/net = SSnetworking.networks[network_id] + if(net) + LAZYADD(net.connected_hubs, weakref(holder)) + var/obj/machinery/network/telecomms_hub/hub = holder + hub.update_icon() + +/datum/extension/network_device/telecomms_hub/disconnect() + var/datum/computer_network/net = SSnetworking.networks[network_id] + . = ..() + if(. && holder) + if(net) + LAZYREMOVE(net.connected_hubs, weakref(holder)) + var/obj/machinery/network/telecomms_hub/hub = holder + hub.update_icon() + +/datum/radio_channel + var/name = "New channel" + var/key + var/frequency + var/color + var/secured + var/span_class = ".syndradio" + var/receive_only = FALSE + +/datum/radio_channel/New(var/list/data) + if(islist(data)) + if(!isnull(data["name"])) name = data["name"] + if(!isnull(data["key"])) key = data["key"] + if(!isnull(data["frequency"])) frequency = data["frequency"] + if(!isnull(data["color"])) color = data["color"] + if(!isnull(data["secured"])) secured = data["secured"] + if(!isnull(data["span_class"])) span_class = data["span_class"] + if(!isnull(data["receive_only"])) receive_only = data["receive_only"] + + if(key && (key in global.special_channel_keys)) + PRINT_STACK_TRACE("Comms channel '[name]' created with reserved key '[key]'.") + +/obj/machinery/network/telecomms_hub + name = "telecommunications hub" + desc = "A black box network machine used to route comms traffic." + density = TRUE + anchored = TRUE + construct_state = /decl/machine_construction/default/panel_closed + base_type = /obj/machinery/network/telecomms_hub + req_access = list(access_tcomsat) + network_device_type = /datum/extension/network_device/telecomms_hub + + var/default_color = "#6d3f40" + var/list/channels + var/list/channels_by_key + var/list/channels_by_frequency + var/const/max_channels = 15 + var/outage_probability = 75 + var/overloaded_for = 0 + var/global_radio_broadcaster = FALSE + var/allow_external_signals = TRUE // Whether or not the telecomms hub will route signals from other networks + +/obj/machinery/network/telecomms_hub/entertainment + channels = list(list( + "name" = "Entertainment", + "key" = "z", + "frequency" = 1461, + "color" = COMMS_COLOR_ENTERTAIN, + "span_class" = CSS_CLASS_RADIO + )) + global_radio_broadcaster = TRUE + +var/global/list/telecomms_hubs = list() +/obj/machinery/network/telecomms_hub/Initialize() + + global.telecomms_hubs += src + . = ..() + + // Create our preloaded channels. + if(isnull(channels)) + channels = global.using_map.default_telecomms_channels.Copy() + if(length(channels)) + var/list/channel_data + for(var/i = 1 to length(channels)) + var/datum/radio_channel/channel = new(channels[i]) + LAZYDISTINCTADD(channel_data, channel) + channels = channel_data + rebuild_channels() + + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + for(var/weakref/radio_ref in network?.connected_radios) + var/obj/item/radio/radio = radio_ref.resolve() + if(istype(radio) && !QDELETED(radio)) + radio.sync_channels_with_network() + + // Pre-init an announcer for this Z-level. + get_announcer(src) + +/obj/machinery/network/telecomms_hub/Destroy() + global.telecomms_hubs -= src + . = ..() + +/obj/machinery/network/telecomms_hub/proc/rebuild_channels() + channels_by_frequency = null + channels_by_key = null + for(var/datum/radio_channel/channel in channels) + if(channel.frequency) + LAZYSET(channels_by_frequency, "[channel.frequency]", channel) + if(channel.key) + LAZYSET(channels_by_key, channel.key, channel) + +/obj/machinery/network/telecomms_hub/Process() + ..() + if(overloaded_for > 0) + overloaded_for-- + +/// Accepts either a raw frequency (numeric), or a frequency/key string, and returns the associated channel data. +/obj/machinery/network/telecomms_hub/proc/get_channel_from_freq_or_key(var/cid) + cid = "[cid]" + . = LAZYACCESS(channels_by_frequency, cid) || LAZYACCESS(channels_by_key, cid) + +/obj/machinery/network/telecomms_hub/proc/can_receive_message(var/check_network_membership) + . = operable() && (overloaded_for <= 0) + if(. && check_network_membership) + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + return network_device?.get_network() == check_network_membership + +/obj/machinery/network/telecomms_hub/proc/transmit_message(mob/speaker, message, message_verb, decl/language/speaking, frequency, message_compression, list/checked_hubs, list/encryption = list(), obj/effect/overmap/send_overmap_object, chain_transmit = TRUE) + if(src in checked_hubs) + return + checked_hubs += src + + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + if(!network) + return + // TODO: cache this somehow. :( Generally make it cheaper. + var/datum/radio_channel/channel = get_channel_from_freq_or_key(frequency) + if(!channel) // We don't have a channel corresponding to this frequency, don't send any messages or chain transmit + return + + if(!send_overmap_object) + var/turf/T = get_turf(src) + send_overmap_object = istype(T) && global.overmap_sectors[T.z] + + if(channel.secured) + encryption |= channel.secured + + var/formatted_msg = "\[[channel?.name || format_frequency(frequency)]\] " + var/send_name = istype(speaker) ? speaker.GetVoice() : ("[speaker]" || "unknown") + var/list/listeners = list() // Dictionary of listener -> boolean (include overmap origin) + // Broadcast to all radio devices in our network. + for(var/weakref/radio_ref as anything in network.connected_radios) + var/obj/item/radio/radio = radio_ref.resolve() + if(!istype(radio) || QDELETED(radio) || !radio.can_receive_message(network)) + continue + var/turf/speaking_from = get_turf(radio) + if(!speaking_from) + continue + if(!radio.can_decrypt(encryption)) + continue + // TODO: This check seems extraneous, given how headsets find their available channels. + var/list/check_channels = radio.get_available_channels() + if(!LAZYACCESS(check_channels, channel)) + continue + + // If we're sending from an overmap object AND our overmap object transmits its identity AND it's different than the listener's + // then append the overmap object name to it, so they know where we're from + var/listener_overmap_object = istype(speaking_from) && global.overmap_sectors[speaking_from.z] + var/send_overmap = send_overmap_object && send_overmap_object.ident_transmitter && send_overmap_object != listener_overmap_object + for(var/mob/listener as anything in radio.get_radio_listeners()) + listeners[listener] = send_overmap + + // Ghostship is magic: Ghosts can hear radio chatter from anywhere + for(var/mob/observer/ghost/ghost_listener as anything in global.ghost_mob_list) + if(ghost_listener.get_preference_value(/datum/client_preference/ghost_radio) == PREF_ALL_CHATTER) + listeners[ghost_listener] = TRUE + + for(var/mob/listener in listeners) + listener.hear_radio(message, message_verb, speaking, formatted_msg, " ", "", speaker, message_compression, vname = send_name, vsource = (listeners[listener] ? send_overmap_object?.name : null)) + + if(!chain_transmit) + return + + // Collect the hubs that are accessible from this hub's network. + var/list/receiving_hubs = list() + if(global_radio_broadcaster) + receiving_hubs = global.telecomms_hubs + else + // Find the z-chunks we can chain the transmission to, which is our local chunk plus any overmap sites in range, + // assuming we have a functioning comms maser and the overmap site has a telecomms hub and comms antenna. + var/list/levels = SSmapping.get_connected_levels(z) + var/obj/effect/overmap/O = global.overmap_sectors[z] + for(var/obj/machinery/shipcomms/broadcaster/our_maser in O?.comms_masers) + levels |= our_maser.get_available_z_levels() + + // Add the hubs available via masers/receivers. + for(var/obj/machinery/network/telecomms_hub/other_hub in global.telecomms_hubs) + if(!(other_hub.z in levels) || other_hub == src) + continue + if(weakref(other_hub) in network.connected_hubs) + continue + receiving_hubs |= other_hub + + // Add the hubs available via PLEXUS connection. + for(var/other_network in SSnetworking.networks) + if(other_network == network.network_id) + continue + var/datum/computer_network/internet_connection = network.get_internet_connection(other_network, NET_FEATURE_COMMUNICATION) + if(internet_connection) + for(var/weakref/hub_ref in internet_connection.connected_hubs) + var/obj/machinery/network/telecomms_hub/other_hub = hub_ref.resolve() + if(istype(other_hub)) + receiving_hubs |= other_hub + + receiving_hubs = receiving_hubs - checked_hubs + + for(var/obj/machinery/network/telecomms_hub/other_hub in receiving_hubs) + var/check_network_membership = other_hub.allow_external_signals ? FALSE : network + if(QDELETED(other_hub) || !other_hub.can_receive_message(check_network_membership)) + continue + // Don't allow further chaining of the message. + other_hub.transmit_message(speaker, message, message_verb, speaking, frequency, message_compression, checked_hubs, encryption.Copy(), send_overmap_object, FALSE) + +/obj/machinery/network/telecomms_hub/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + var/list/data = list() + var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device) + data["network_id"] = device.network_tag + data["authenticated"] = (access_keycard_auth in user.GetAccess()) + data["allow_external"] = allow_external_signals + var/list/data_channels = list() + for(var/datum/radio_channel/channel_datum in channels) + var/list/channel_data = list() + channel_data["channel_name"] = channel_datum.name + channel_data["channel_freq"] = channel_datum.frequency + channel_data["channel_key"] = channel_datum.key + channel_data["channel_color"] = channel_datum.color || COLOR_BLACK + if(channel_datum.secured) + channel_data["channel_access"] = jointext(channel_datum.secured, " ") + else + channel_data["channel_access"] = "PUBLIC" + channel_data["channel_ref"] = "\ref[channel_datum]" + data_channels += list(channel_data) + data["channels"] = data_channels + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "telecomms_hub.tmpl", "Telecommunications Hub", 700, 400) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/network/telecomms_hub/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/network/telecomms_hub/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + if(!.) + if(href_list["channel"]) + var/datum/radio_channel/channel_datum = locate(href_list["channel"]) + if(!istype(channel_datum) || !(channel_datum in channels)) + . = TOPIC_HANDLED + else + + if(href_list["change_name"]) + var/new_name = input(user, "Enter a new channel name.", "Channel Configuration", channel_datum.name) as text|null + new_name = sanitize(new_name, MAX_NAME_LEN) + if(new_name != channel_datum.name && new_name && CanPhysicallyInteract(user)) + channel_datum.name = new_name + . = TOPIC_REFRESH + + if(href_list["change_key"]) + var/new_key = lowertext(input(user, "Enter a new key character.", "Channel Configuration", channel_datum.key) as text|null) + new_key = sanitize(new_key, 1) + if(new_key != channel_datum.key && new_key && CanPhysicallyInteract(user)) + if(new_key in global.special_channel_keys) + to_chat(user, SPAN_WARNING("You may not use any of the following keys: [english_list(global.special_channel_keys)].")) + return + channel_datum.key = new_key + rebuild_channels() + . = TOPIC_REFRESH + + if(href_list["change_freq"]) + + var/lower_freq + var/upper_freq + if(access_keycard_auth in user.GetAccess()) + lower_freq = RADIO_LOW_FREQ + upper_freq = RADIO_HIGH_FREQ + else + lower_freq = PUBLIC_LOW_FREQ + upper_freq = PUBLIC_HIGH_FREQ + + var/new_freq = input(user, "Enter a new frequency beween [lower_freq] and [upper_freq].", "Channel Configuration", channel_datum.frequency) as num + + if(access_keycard_auth in user.GetAccess()) + lower_freq = RADIO_LOW_FREQ + upper_freq = RADIO_HIGH_FREQ + else + lower_freq = PUBLIC_LOW_FREQ + upper_freq = PUBLIC_HIGH_FREQ + new_freq = clamp(new_freq, lower_freq, upper_freq) + + if(new_freq != channel_datum.frequency && new_freq && CanPhysicallyInteract(user)) + if(channels_by_frequency && ("[new_freq]" in channels_by_frequency)) + to_chat(user, SPAN_WARNING("A channel with this frequency already exists.")) + return TOPIC_HANDLED + channel_datum.frequency = new_freq + rebuild_channels() + . = TOPIC_REFRESH + + if(href_list["change_colour"]) + var/new_colour = input(user, "Select a new display colour.", "Channel Configuration") as null|anything in global.telecomms_colours + if(new_colour && CanPhysicallyInteract(user)) + channel_datum.color = global.telecomms_colours[new_colour] + . = TOPIC_REFRESH + + if(href_list["change_access"]) + var/choice = input(user, "How do you wish to modify the channel encryption?", "Channel Configuration") as null|anything in list("Add", "Remove", "Add Network Group", "Clear", "Sync to personal access") + if(choice && CanPhysicallyInteract(user)) + switch(choice) + if("Add") + choice = input(user, "Which access do you wish to add?", "Channel Configuration") as null|anything in get_all_station_access() + if(choice && CanPhysicallyInteract(user)) + LAZYDISTINCTADD(channel_datum.secured, choice) + if("Remove") + if(!LAZYLEN(channel_datum.secured)) + to_chat(user, SPAN_WARNING("[channel_datum.name] has no access to remove.")) + else + choice = input(user, "Which key do you wish to remove?", "Channel Configuration") as null|anything in channel_datum.secured + if(choice && CanPhysicallyInteract(user)) + LAZYREMOVE(channel_datum.secured, choice) + if("Add Network Group") + var/datum/extension/network_device/network_device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = network_device?.get_network() + if(!network) + to_chat(user, SPAN_WARNING("Unable to connect to the network.")) + return TOPIC_HANDLED + + var/datum/extension/network_device/acl/net_acl = network.access_controller + if(!net_acl) + to_chat(user, SPAN_WARNING("No access controller on the network.")) + return + + var/list/all_groups = net_acl.get_all_groups() + if(!length(all_groups)) + to_chat(user, SPAN_WARNING("No groups were found on the network access controller.")) + return TOPIC_HANDLED + + choice = input(user, "Which group do you wish to add? Adding a parent group will allow all members of its children groups to access the channel.", "Channel Configuration") as null|anything in all_groups + if(choice && CanPhysicallyInteract(user)) + LAZYDISTINCTADD(channel_datum.secured, choice + ".[network.network_id]") + if("Clear") + channel_datum.secured = null + if("Sync to personal access") + var/list/new_access = user.GetAccess() + channel_datum.secured = (new_access && new_access.Copy()) + . = TOPIC_REFRESH + + if(href_list["delete_channel"]) + var/confirm = alert(user, "Are you sure you want to delete the [channel_datum.name] channel? This action is not reversible.", "Channel Deletion", "No", "Yes") == "Yes" + if(confirm && CanPhysicallyInteract(user)) + LAZYREMOVE(channels, channel_datum) + rebuild_channels() + . = TOPIC_REFRESH + + if(href_list["new_channel"]) + if(LAZYLEN(channels) >= max_channels) + to_chat(user, SPAN_WARNING("\The [src] has no available configuration slots for new channels.")) + . = TOPIC_HANDLED + else + LAZYADD(channels, new /datum/radio_channel) + rebuild_channels() + . = TOPIC_REFRESH + + if(href_list["factory_reset"]) + var/confirm = alert(user, "Are you sure you want to perform a factory reset? This action is not reversible.", "Factory Reset", "No", "Yes") == "Yes" + if(confirm && CanPhysicallyInteract(user)) + channels_by_frequency = null + channels_by_key = null + channels = initial(channels) || global.using_map.default_telecomms_channels.Copy() + var/list/channel_data + for(var/i = 1 to length(channels)) + var/datum/radio_channel/channel = new(channels[i]) + LAZYDISTINCTADD(channel_data, channel) + channels = channel_data + rebuild_channels() + . = TOPIC_REFRESH + + if(href_list["toggle_external"]) + allow_external_signals = !allow_external_signals + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/modules/modular_computers/networking/machinery/wall_relay.dm b/code/modules/modular_computers/networking/machinery/wall_relay.dm new file mode 100644 index 000000000000..bb3b423e13f6 --- /dev/null +++ b/code/modules/modular_computers/networking/machinery/wall_relay.dm @@ -0,0 +1,30 @@ +/obj/machinery/network/relay/wall_mounted + name = "wall-mounted network relay" + icon = 'icons/obj/machines/wall_router.dmi' + icon_state = "wall_router" + frame_type = /obj/item/frame/wall_relay + construct_state = /decl/machine_construction/wall_frame/panel_closed + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + base_type = /obj/machinery/network/relay/wall_mounted + directional_offset = @'{"NORTH":{"y":-21}, "SOUTH":{"y":21}, "EAST":{"x":-21}, "WEST":{"x":21}}' + +/obj/machinery/network/relay/wall_mounted/Initialize() + . = ..() + queue_icon_update() + +/obj/machinery/network/relay/wall_mounted/south + dir = NORTH + pixel_y = -21 + +/obj/machinery/network/relay/wall_mounted/north + dir = SOUTH + pixel_y = 21 + +/obj/machinery/network/relay/wall_mounted/west + dir = EAST + pixel_x = -21 + +/obj/machinery/network/relay/wall_mounted/east + dir = WEST + pixel_x = 21 diff --git a/code/modules/modular_computers/networking/machinery/wall_router.dm b/code/modules/modular_computers/networking/machinery/wall_router.dm new file mode 100644 index 000000000000..5c408af98d93 --- /dev/null +++ b/code/modules/modular_computers/networking/machinery/wall_router.dm @@ -0,0 +1,14 @@ +/obj/machinery/network/router/wall_mounted + name = "wall-mounted network router" + icon = 'icons/obj/machines/wall_router.dmi' + icon_state = "wall_router" + frame_type = /obj/item/frame/wall_router + construct_state = /decl/machine_construction/wall_frame/panel_closed + density = FALSE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + base_type = /obj/machinery/network/router/wall_mounted + directional_offset = @'{"NORTH":{"y":-21}, "SOUTH":{"y":21}, "EAST":{"x":-21}, "WEST":{"x":21}}' + +/obj/machinery/network/router/wall_mounted/Initialize() + . = ..() + queue_icon_update() diff --git a/code/modules/modular_computers/networking/network_cable.dm b/code/modules/modular_computers/networking/network_cable.dm new file mode 100644 index 000000000000..4ea853d32197 --- /dev/null +++ b/code/modules/modular_computers/networking/network_cable.dm @@ -0,0 +1,202 @@ +/obj/structure/network_cable + name = "network cable" + desc = "A cable used to connect computers and other devices into a local network." + icon = 'icons/obj/structures/network_cable.dmi' + icon_state = "dot" + layer = WIRE_LAYER + anchored = TRUE + level = LEVEL_BELOW_PLATING + var/datum/node/physical/network_node + +/obj/structure/network_cable/Initialize(ml, _mat, _reinf_mat) + ..() + var/turf/T = get_turf(src) + hide(hides_under_flooring() && !T?.is_plating()) + network_node = new(src) + network_node.graph = new(list(network_node)) + return INITIALIZE_HINT_LATELOAD + +/obj/structure/network_cable/LateInitialize() + . = ..() + update_network() + +/obj/structure/network_cable/Destroy() + QDEL_NULL(network_node) + for(var/dir in global.cardinal) + var/turf/T = get_step(get_turf(src), dir) + for(var/obj/structure/network_cable/cable in T) + cable.update_icon() + var/turf/T = get_turf(src) + if(T?.is_open()) + for(var/obj/structure/network_cable/cable in GetBelow(src)) + cable.update_icon() + var/turf/U = GetAbove(src) + if(U?.is_open()) + for(var/obj/structure/network_cable/cable in U) + cable.update_icon() + . = ..() + +/obj/structure/network_cable/handle_default_wirecutter_attackby(var/mob/user) + var/turf/T = get_turf(src) + if(T && do_after(user, 15) && !QDELETED(src)) + to_chat(user, SPAN_NOTICE("You cut \the [src].")) + new/obj/item/stack/net_cable_coil(T, 1) + qdel(src) + +/obj/structure/network_cable/proc/update_network() + var/list/graphs = list() // Associative list of graphs->list of nodes to add as neighbors. + for(var/dir in global.cardinal) + var/turf/T = get_step(get_turf(src), dir) + for(var/obj/structure/network_cable/cable in T) + var/datum/graph/G = cable.network_node.graph + if(G) + LAZYADD(graphs[G], cable.network_node) + cable.update_icon() + var/turf/T = get_turf(src) + if(T?.is_open()) + for(var/obj/structure/network_cable/cable in GetBelow(src)) + var/datum/graph/G = cable.network_node.graph + if(G) + LAZYADD(graphs[G], cable.network_node) + cable.update_icon() + var/turf/U = GetAbove(src) + if(U?.is_open()) + for(var/obj/structure/network_cable/cable in U) + var/datum/graph/G = cable.network_node.graph + if(G) + LAZYADD(graphs[G], cable.network_node) + cable.update_icon() + + for(var/datum/graph/G in graphs) + G.Connect(network_node, graphs[G]) + update_icon() + +/obj/structure/network_cable/CheckNodeNeighbours() + // Check if connected nodes are no longer adjacent to the current node and disconnect from them. + var/list/neighbours = network_node.ConnectedNodes() + var/list/adj_nodes = list() + var/list/ex_neighbours + var/list/new_neighbours + + for(var/dir in global.cardinal) + var/turf/T = get_step(get_turf(src), dir) + for(var/obj/structure/network_cable/cable in T) + adj_nodes |= cable.network_node + var/turf/T = get_turf(src) + if(T?.is_open()) + for(var/obj/structure/network_cable/cable in GetBelow(src)) + adj_nodes |= cable.network_node + var/turf/U = GetAbove(src) + if(U?.is_open()) + for(var/obj/structure/network_cable/cable in U) + adj_nodes |= cable.network_node + + ex_neighbours = neighbours - adj_nodes + new_neighbours = adj_nodes - neighbours + if(length(ex_neighbours)) // Check length to ensure we don't accidentally completely disconnect the node from a graph. + network_node.Disconnect() + if(length(new_neighbours)) + network_node.Connect(new_neighbours[1]) // Pick a random new neighbour to connect to and get a new graph. + for(var/datum/node/neighbour in new_neighbours.Copy(2)) + neighbour.Connect(network_node) // Connect the other neighbours to the network node with its (new) graph. + + return TRUE + +/obj/structure/network_cable/Move() + . = ..() + network_node.Moved() + queue_icon_update() + +/obj/structure/network_cable/forceMove() + . = ..() + if(network_node) + network_node.Moved() + queue_icon_update() + +/obj/structure/network_cable/proc/get_graph() + return network_node?.graph + +/obj/structure/network_cable/on_update_icon() + ..() + for(var/dir in global.cardinal) + var/turf/T = get_step(get_turf(src), dir) + for(var/obj/structure/network_cable/cable in T) + if(!QDELETED(cable)) + add_overlay("cable[dir]") + var/turf/T = get_turf(src) + if(T?.is_open()) + var/turf/A = GetBelow(src) + var/obj/structure/network_cable/cable = locate() in A + if(cable) + add_overlay("cable-down") + var/turf/U = GetAbove(src) + if(U?.is_open()) + var/obj/structure/network_cable/cable = locate() in U + if(cable) + add_overlay("cable-up") + +/obj/structure/network_cable/terminal + name = "network cable terminal" + desc = "A network terminal directly connected to a network device." + icon_state = "terminal" + layer = WIRE_LAYER + +/obj/structure/network_cable/terminal/handle_default_wirecutter_attackby(var/mob/user) + var/turf/T = get_turf(src) + if(T && do_after(user, 30) && !QDELETED(src)) + to_chat(user, SPAN_NOTICE("You pry off \the [src].")) + new/obj/item/stack/net_cable_coil(T, 5) + qdel(src) + +/obj/item/stack/net_cable_coil + name = "network cable coil" + desc = "A coil of network cable, used to connect network devices over local networks." + icon = 'icons/obj/items/net_cable_coil.dmi' + icon_state = ICON_STATE_WORLD + randpixel = 2 + amount = 20 + max_amount = 20 + singular_name = "length of network cable" + plural_name = "lengths of network cable" + w_class = ITEM_SIZE_NORMAL + throw_speed = 2 + throw_range = 5 + material = /decl/material/solid/glass + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT + ) + matter_multiplier = 0.15 + item_state = "coil" + +/obj/item/stack/net_cable_coil/single + amount = 1 + +/obj/item/stack/net_cable_coil/afterattack(var/atom/A, var/mob/user, var/proximity, var/params) + . = ..() + if(!proximity) + return + if(isturf(A)) + var/turf/T = A + if(!T.is_plating()) + to_chat(user, SPAN_WARNING("You must remove the plating first!")) + return + for(var/obj/structure/network_cable/C in A) + to_chat(user, SPAN_WARNING("There's already a cable at that position!")) + return + if(do_after(user, 5, A) && use(1)) + new /obj/structure/network_cable(A) + +/obj/item/stack/net_cable_coil/on_update_icon() + . = ..() + if(amount == 1) + icon_state = "coil1" + SetName("network cable piece") + else if(amount == 2) + icon_state = "coil2" + SetName("network cable piece") + else if(amount > 2 && amount != max_amount) + icon_state = "coil" + SetName(initial(name)) + else + icon_state = "coil-max" + SetName(initial(name)) \ No newline at end of file diff --git a/code/modules/modular_computers/networking/network_files.dm b/code/modules/modular_computers/networking/network_files.dm index aa4df7eb8e2c..ece73f53cbaa 100644 --- a/code/modules/modular_computers/networking/network_files.dm +++ b/code/modules/modular_computers/networking/network_files.dm @@ -1,13 +1,15 @@ -/datum/computer_network/proc/find_file_by_name(filename, mainframe_role = MF_ROLE_FILESERVER, mob/user) - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, user)) - var/datum/computer_file/F = M.get_file(filename) - if(F) +/datum/computer_network/proc/find_file_by_name(filename, directory, mainframe_role = MF_ROLE_FILESERVER, list/accesses) + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, accesses)) + var/datum/computer_file/F = M.get_file(filename, directory) + if(istype(F)) return F -/datum/computer_network/proc/get_all_files_of_type(file_type, mainframe_role = MF_ROLE_FILESERVER, uniques_only = FALSE, mob/user) + return OS_FILE_NOT_FOUND + +/datum/computer_network/proc/get_all_files_of_type(file_type, mainframe_role = MF_ROLE_FILESERVER, uniques_only = FALSE, list/accesses) . = list() var/list/found_filenames = list() - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, user)) + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, accesses)) for(var/datum/computer_file/F in M.get_all_files()) if(istype(F, file_type)) if(uniques_only && (F.filename in found_filenames)) @@ -15,28 +17,28 @@ . |= F found_filenames |= F.filename -/datum/computer_network/proc/store_file(datum/computer_file/F, mainframe_role = MF_ROLE_FILESERVER, mob/user) - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, user)) - if(M.store_file(F)) +/datum/computer_network/proc/store_file(datum/computer_file/file, directory, create_directories, list/accesses, mob/user, overwrite = TRUE, mainframe_role = MF_ROLE_FILESERVER) + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, accesses)) + if(M.store_file(file, directory, create_directories, accesses, user, overwrite)) return TRUE -/datum/computer_network/proc/remove_file(datum/computer_file/F, mainframe_role = MF_ROLE_FILESERVER, mob/user) - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, user)) - if(M.delete_file(F)) +// We don't pass the directory since this is generally used in conjunction with get_all_files_of_type +/datum/computer_network/proc/remove_file(datum/computer_file/F, list/accesses, mob/user, mainframe_role = MF_ROLE_FILESERVER) + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, accesses)) + if(M.delete_file(F, accesses, user)) return TRUE -/datum/computer_network/proc/find_file_location(filename, mainframe_role = MF_ROLE_FILESERVER, mob/user) - for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, user)) - var/datum/computer_file/F = M.get_file(filename) - if(F) +/datum/computer_network/proc/find_file_location(datum/computer_file/F, list/accesses, mainframe_role = MF_ROLE_FILESERVER) + for(var/datum/extension/network_device/mainframe/M in get_mainframes_by_role(mainframe_role, accesses)) + if(F in M.get_all_files()) return M.network_tag // Reports -/datum/computer_network/proc/fetch_reports(access) +/datum/computer_network/proc/fetch_reports(access, mob/user) . = get_all_files_of_type(/datum/computer_file/report) if(access) for(var/datum/computer_file/report/report in .) - if(!report.verify_access_edit(access)) + if(!(report.get_file_perms(access, user) & OS_WRITE_ACCESS)) . -= report // Software @@ -60,13 +62,13 @@ var/entry = "[stationtime2text()] - [source ? source : "*SYSTEM*" ] - " entry += data for(var/datum/extension/network_device/mainframe/M in mainframes_by_role[MF_ROLE_LOG_SERVER]) - if(M.append_to_file("network_log", entry)) + if(M.append_to_file("network_log", OS_LOGS_DIR, entry)) return TRUE /datum/computer_network/proc/get_log_files() . = list() for(var/datum/extension/network_device/mainframe/M in mainframes_by_role[MF_ROLE_LOG_SERVER]) - var/logfile = M.get_file("network_log") + var/logfile = M.get_file("network_log", OS_LOGS_DIR) if(logfile) . += logfile @@ -80,14 +82,15 @@ return CR // Misc helpers -/datum/computer_network/proc/get_file_server_tags(var/role = MF_ROLE_FILESERVER, var/mob/user) +/datum/computer_network/proc/get_file_server_tags(role = MF_ROLE_FILESERVER, list/accesses) . = list() var/list/mainframes = get_mainframes_by_role(role) for(var/datum/extension/network_device/mainframe/M in mainframes) - if(user && !M.has_access(user)) + if(!M.has_access(accesses)) continue // We only check if user is provided. If no user is provided, it's assumed to be an admin check. . |= M.network_tag -/datum/computer_network/proc/get_file_server_by_role(var/role, var/user) - if(length(get_mainframes_by_role(role, user)) > 0) - return get_mainframes_by_role(role, user)[1] +/// Returns the first (order is arbitrarily decided) fileserver with a given mainframe role. +/datum/computer_network/proc/get_file_server_by_role(role, list/accesses) + if(length(get_mainframes_by_role(role, accesses)) > 0) + return get_mainframes_by_role(role, accesses)[1] diff --git a/code/modules/modular_computers/networking/network_helper.dm b/code/modules/modular_computers/networking/network_helper.dm new file mode 100644 index 000000000000..b37de8131980 --- /dev/null +++ b/code/modules/modular_computers/networking/network_helper.dm @@ -0,0 +1,5 @@ +/proc/parse_network_uri(var/uri) + var/found = findtext(uri, ".") + if(!found) + return + return list("network_tag" = copytext(uri, 1, found), "network_id" = copytext(uri, found + 1)) diff --git a/code/modules/modular_computers/ntos/components.dm b/code/modules/modular_computers/ntos/components.dm deleted file mode 100644 index 5566bc948581..000000000000 --- a/code/modules/modular_computers/ntos/components.dm +++ /dev/null @@ -1,80 +0,0 @@ -/datum/extension/interactive/ntos/proc/get_component(var/part_type) - return locate(part_type) in holder - -/datum/extension/interactive/ntos/proc/get_all_components() - . = list() - for(var/obj/item/stock_parts/P in holder) - . += P - -/datum/extension/interactive/ntos/proc/find_hardware_by_name(var/partname) - for(var/obj/item/stock_parts/P in holder) - if(findtext(P.name, partname)) - return P - -/datum/extension/interactive/ntos/proc/has_component(var/part_type) - return !!get_component(part_type) - -/datum/extension/interactive/ntos/proc/print_paper(content, title) - var/obj/item/stock_parts/computer/nano_printer/printer = get_component(PART_PRINTER) - if(printer) - return printer.print_text(content, title) - -/datum/extension/interactive/ntos/proc/get_network_tag() - var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) - if(network_card) - return network_card.get_network_tag() - else - return "N/A" - -/datum/extension/interactive/ntos/proc/get_network_status(var/specific_action = 0) - var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) - if(network_card) - var/signal_power_level = NETWORK_SPEED_BASE * network_card.get_signal(specific_action) - if(signal_power_level > 0) - signal_power_level = round(Clamp(signal_power_level, 1, 3)) - return signal_power_level - else - return 0 - -/datum/extension/interactive/ntos/proc/get_inserted_id() - var/obj/item/stock_parts/computer/card_slot/card_slot = get_component(PART_CARD) - if(card_slot) - return card_slot.stored_card - -/datum/extension/interactive/ntos/proc/max_disk_capacity() - var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) - if(hard_drive) - return hard_drive.max_capacity - -/datum/extension/interactive/ntos/proc/used_disk_capacity() - var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) - if(hard_drive) - return hard_drive.used_capacity - -/datum/extension/interactive/ntos/proc/get_hardware_flag() - return PROGRAM_ALL - -//Used to display in configurator program -/datum/extension/interactive/ntos/proc/get_power_usage() - return 0 - -/datum/extension/interactive/ntos/proc/recalc_power_usage() - -/datum/extension/interactive/ntos/proc/voltage_overload() - var/atom/A = holder - if(istype(A)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(10, 1, A.loc) - s.start() - - var/obj/item/stock_parts/computer/hard_drive = get_component(PART_HDD) - if(hard_drive) - qdel(hard_drive) - - var/obj/item/stock_parts/computer/battery_module = get_component(PART_BATTERY) - if(battery_module && prob(25)) - qdel(battery_module) - - var/obj/item/stock_parts/computer/tesla_link = get_component(PART_TESLA) - if(tesla_link && prob(50)) - qdel(tesla_link) \ No newline at end of file diff --git a/code/modules/modular_computers/ntos/files.dm b/code/modules/modular_computers/ntos/files.dm deleted file mode 100644 index 042ece4a948f..000000000000 --- a/code/modules/modular_computers/ntos/files.dm +++ /dev/null @@ -1,341 +0,0 @@ -/datum/extension/interactive/ntos/proc/get_all_files(var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - . = list() - if(disk) - return disk.stored_files - -/datum/extension/interactive/ntos/proc/get_file(filename, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(disk) - return disk.find_file_by_name(filename) - -/datum/extension/interactive/ntos/proc/create_file(var/newname, var/data, var/file_type = /datum/computer_file/data, var/list/metadata, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(!newname) - return - if(!disk) - return - if(get_file(newname)) - return - - var/datum/computer_file/data/F = new file_type(md = metadata) - F.filename = newname - F.stored_data = data - F.calculate_size() - if(disk.store_file(F)) - return F - -/datum/extension/interactive/ntos/proc/store_file(var/datum/computer_file/file, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(!disk) - return FALSE - var/datum/computer_file/data/old_version = disk.find_file_by_name(file.filename) - if(old_version) - disk.remove_file(old_version) - if(!disk.store_file(file)) - disk.store_file(old_version) - return FALSE - else - return TRUE - -/datum/extension/interactive/ntos/proc/try_store_file(var/datum/computer_file/file, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(!disk) - return FALSE - return disk.try_store_file(file) - -/datum/extension/interactive/ntos/proc/save_file(var/newname, var/data, var/file_type = /datum/computer_file/data, var/list/metadata, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(!disk) - return FALSE - var/datum/computer_file/data/F = disk.find_file_by_name(newname) - if(!F) //try to make one if it doesn't exist - return !!create_file(newname, data, file_type, metadata, disk) - - //Try to save file, possibly won't fit size-wise - var/datum/computer_file/data/backup = F.clone() - disk.remove_file(F) - F.stored_data = data - F.metadata = metadata && metadata.Copy() - F.calculate_size() - if(!disk.store_file(F)) - disk.store_file(backup) - return FALSE - return TRUE - -/datum/extension/interactive/ntos/proc/delete_file(var/filename, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(!disk) - return FALSE - - var/datum/computer_file/F = disk.find_file_by_name(filename) - if(!F || F.undeletable) - return FALSE - - return disk.remove_file(F) - -/datum/extension/interactive/ntos/proc/clone_file(var/filename, var/obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) - if(!disk) - return FALSE - - var/datum/computer_file/F = disk.find_file_by_name(filename) - if(!F) - return FALSE - - var/datum/computer_file/C = F.clone(1) - - return disk.store_file(C) - -/datum/extension/interactive/ntos/proc/copy_between_disks(var/filename, var/obj/item/stock_parts/computer/hard_drive/disk_from, var/obj/item/stock_parts/computer/hard_drive/disk_to) - if(!istype(disk_from) || !istype(disk_to)) - return FALSE - - var/datum/computer_file/F = disk_from.find_file_by_name(filename) - if(!istype(F)) - return FALSE - var/datum/computer_file/C = F.clone(0) - return disk_to.store_file(C) - -// Generic file storage interface -/datum/file_storage - var/name = "Generic File Interface" - var/datum/extension/interactive/ntos/os - -/datum/file_storage/New(ntos) - os = ntos - -/datum/file_storage/Destroy(force) - os = null - . = ..() - -/datum/file_storage/proc/check_errors() - if(!istype(os)) - return "No NTOS compatible device found." - -/datum/file_storage/proc/get_transfer_speed() - return 1 - -/datum/file_storage/proc/get_all_files() - -/datum/file_storage/proc/get_file(filename) - -/datum/file_storage/proc/store_file(datum/computer_file/F) - -/datum/file_storage/proc/save_file(filename, new_data) - -/datum/file_storage/proc/delete_file(filename) - -/datum/file_storage/proc/create_file(newname, var/file_type = /datum/computer_file/data/text) - if(check_errors()) - return FALSE - var/datum/computer_file/F = new file_type - F.filename = newname - var/datum/computer_file/data/FD = F - if(istype(F, /datum/computer_file/data)) - FD.calculate_size() - return store_file(F) - -/datum/file_storage/proc/clone_file(filename) - if(check_errors()) - return FALSE - var/datum/computer_file/F = get_file(filename) - if(F) - store_file(F.clone(1)) - -// Storing stuff on a server in computer network -/datum/file_storage/network - name = "Remote File Server" - var/server = "NONE" //network tag of the file server - -/datum/file_storage/network/check_errors() - . = ..() - if(.) - return - var/datum/computer_network/network = os.get_network() - if(!network) - return "NETWORK ERROR: No connectivity to the network" - if(!network.get_device_by_tag(server)) - return "NETWORK ERROR: No connectivity to the file server '[server]'" - var/datum/extension/network_device/mainframe/M = network.get_device_by_tag(server) - if(!istype(M)) - return "NETWORK ERROR: Invalid server '[server]', no file sharing capabilities detected" - -/datum/file_storage/network/proc/get_mainframe() - if(check_errors()) - return FALSE - var/datum/computer_network/network = os.get_network() - return network.get_device_by_tag(server) - -/datum/file_storage/network/get_all_files() - var/datum/extension/network_device/mainframe/M = get_mainframe() - return M && M.get_all_files() - -/datum/file_storage/network/get_file(filename) - var/datum/extension/network_device/mainframe/M = get_mainframe() - return M && M.get_file(filename) - -/datum/file_storage/network/store_file(datum/computer_file/F) - var/datum/extension/network_device/mainframe/M = get_mainframe() - return M && M.store_file(F) - -/datum/file_storage/network/delete_file(filename) - var/datum/extension/network_device/mainframe/M = get_mainframe() - return M && M.delete_file(filename) - -/datum/file_storage/network/save_file(filename, new_data) - var/datum/extension/network_device/mainframe/M = get_mainframe() - return M && M.save_file(filename, new_data) - -/datum/file_storage/network/get_transfer_speed() - if(check_errors()) - return 0 - return os.get_network_status() - -/* - * Special subclass for network machines specifically. - * - */ -/datum/file_storage/network/machine - var/obj/localhost - -/datum/file_storage/network/machine/New(ntos, machine) - localhost = machine - -/datum/file_storage/network/machine/check_errors() - // Do not call predecessors. This is a straight up override. - var/datum/extension/network_device/computer = get_extension(localhost, /datum/extension/network_device) - var/datum/computer_network/network = computer.get_network() - if(!network) - return "NETWORK ERROR: No connectivity to the network" - if(!network.get_device_by_tag(server)) - return "NETWORK ERROR: No connectivity to the file server '[server]'" - var/datum/extension/network_device/mainframe/M = network.get_device_by_tag(server) - if(!istype(M)) - return "NETWORK ERROR: Invalid server '[server]', no file sharing capabilities detected" - -/datum/file_storage/network/machine/get_mainframe() - if(check_errors()) - return FALSE - var/datum/extension/network_device/computer = get_extension(localhost, /datum/extension/network_device) - var/datum/computer_network/network = computer.get_network() - return network.get_device_by_tag(server) - -/datum/file_storage/network/machine/get_transfer_speed() - if(check_errors()) - return 0 - return 1 - -// Storing stuff locally on some kinda disk -/datum/file_storage/disk - name = "Local Storage" - var/disk_type = PART_HDD - -/datum/file_storage/disk/proc/get_disk() - return os.get_component(PART_HDD) - -/datum/file_storage/disk/check_errors() - . = ..() - if(.) - return - var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() - if(!istype(HDD)) - return "HARDWARE ERROR: No compatible device found" - if(!HDD.check_functionality()) - return "NETWORK ERROR: [HDD] is non-operational" - -/datum/file_storage/disk/get_all_files() - if(check_errors()) - return FALSE - return os.get_all_files(get_disk()) - -/datum/file_storage/disk/get_file(filename) - if(check_errors()) - return FALSE - return os.get_file(filename, get_disk()) - -/datum/file_storage/disk/store_file(datum/computer_file/F) - if(check_errors()) - return FALSE - return os.store_file(F, get_disk()) - -/datum/file_storage/disk/save_file(filename, new_data) - if(check_errors()) - return FALSE - return os.save_file(filename, new_data, get_disk()) - -/datum/file_storage/disk/delete_file(filename) - if(check_errors()) - return FALSE - return os.delete_file(filename, get_disk()) - -/datum/file_storage/disk/get_transfer_speed() - if(check_errors()) - return 0 - return NETWORK_SPEED_DISK - -// Storing files on a removable disk. -/datum/file_storage/disk/removable - name = "Disk Drive" - -/datum/file_storage/disk/removable/get_disk() - var/obj/item/stock_parts/computer/drive_slot/drive_slot = os.get_component(PART_D_SLOT) - return drive_slot.stored_drive - -/datum/file_storage/disk/removable/check_errors() - . = ..() - if(.) - return - var/obj/item/stock_parts/computer/drive_slot/drive_slot = os.get_component(PART_D_SLOT) - if(!drive_slot.check_functionality()) - return "HARDWARE ERROR: [drive_slot] is non-operational" - if(!istype(drive_slot.stored_drive)) - return "HARDWARE ERROR: No portable drive inserted." - - -// Datum tracking progress between of file transfer between two file streams -/datum/file_transfer - var/datum/file_storage/copying_from - var/datum/file_storage/copying_to - var/datum/computer_file/copying - var/left_to_copy - -/datum/file_transfer/New(datum/file_storage/source, datum/file_storage/destination, datum/computer_file/file) - copying_from = source - copying_to = destination - copying = file - left_to_copy = file.size - -/datum/file_transfer/Destroy() - copying_from = null - copying_to = null - copying = null - . = ..() - -/datum/file_transfer/proc/check_self() - if(QDELETED(copying_from) || QDELETED(copying_from) || QDELETED(copying)) - qdel(src) - return FALSE - return TRUE - -//Returns FALSE if something went wrong, TRUE if progress was made and or we are done -/datum/file_transfer/proc/update_progress() - . = check_self() - if(!.) - return - left_to_copy = max(0, left_to_copy - get_transfer_speed()) - if(!left_to_copy) - return copying_to.store_file(copying) - -/datum/file_transfer/proc/get_transfer_speed() - if(!check_self()) - return 0 - return min(copying_from.get_transfer_speed(), copying_to.get_transfer_speed()) - -/datum/file_transfer/proc/get_eta() - if(!check_self() || !get_transfer_speed()) - return INFINITY - return round(left_to_copy / get_transfer_speed()) - -/datum/file_transfer/proc/get_ui_data() - if(!check_self()) - return - var/list/data = list() - data["transfer_from"] = copying_from.name - data["transfer_to"] = copying_to.name - data["transfer_file"] = copying.filename - data["transfer_progress"] = copying.size - left_to_copy - data["transfer_total"] = copying.size - return data \ No newline at end of file diff --git a/code/modules/modular_computers/ntos/ntos.dm b/code/modules/modular_computers/ntos/ntos.dm deleted file mode 100644 index fbe32d828c36..000000000000 --- a/code/modules/modular_computers/ntos/ntos.dm +++ /dev/null @@ -1,200 +0,0 @@ -/datum/extension/interactive/ntos - base_type = /datum/extension/interactive/ntos - expected_type = /atom/movable - flags = EXTENSION_FLAG_IMMEDIATE - var/on = FALSE - var/datum/computer_file/program/active_program = null // A currently active program running on the computer. - var/list/running_programs = list() // All programms currently running, background or active. - - var/screen_icon_file // dmi where the screen overlays are kept, defaults to holder's icon if unset - var/menu_icon = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen. - var/screensaver_icon = "standby" - - // Used for deciding if various tray icons need to be updated - var/last_battery_percent - var/last_world_time - var/list/last_header_icons - - //Pain and suffering - var/receives_updates = TRUE - var/updating = FALSE - var/updates = 0 - var/update_progress = 0 - var/update_postshutdown - - var/list/terminals - -/datum/extension/interactive/ntos/Destroy() - system_shutdown() - . = ..() - -/datum/extension/interactive/ntos/Process() - if(on && !host_status()) - system_shutdown() - if(!on) - return - if(updating) - process_updates() - return - for(var/datum/computer_file/program/P in running_programs) - if(P.requires_network && !get_network_status(P.requires_network_feature)) - P.event_networkfailure(P != active_program) - else - P.process_tick() - regular_ui_update() - -/datum/extension/interactive/ntos/proc/host_status() - return TRUE - -/datum/extension/interactive/ntos/proc/get_network() - var/datum/extension/network_device/D = get_extension(get_component(PART_NETWORK), /datum/extension/network_device) - if(D) - return D.get_network() - -/datum/extension/interactive/ntos/proc/system_shutdown() - on = FALSE - for(var/datum/computer_file/program/P in running_programs) - kill_program(P, 1) - - var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) - if(network_card) - var/datum/extension/network_device/D = get_extension(network_card, /datum/extension/network_device) - D.disconnect() - - if(updating) - updating = FALSE - updates = 0 - update_progress = 0 - var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) - if(hard_drive) - if(prob(10)) - hard_drive.visible_message("[src] emits some ominous clicks.") - hard_drive.take_damage(0.5 * hard_drive.health) - else if(prob(5)) - hard_drive.visible_message("[src] emits some ominous clicks.") - hard_drive.take_damage(hard_drive.health) - update_host_icon() - -/datum/extension/interactive/ntos/proc/system_boot() - on = TRUE - var/datum/computer_file/data/autorun = get_file("autorun") - if(istype(autorun)) - run_program(autorun.stored_data) - var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) - if(network_card) - var/datum/extension/network_device/D = get_extension(network_card, /datum/extension/network_device) - D.connect() - update_host_icon() - -/datum/extension/interactive/ntos/proc/kill_program(var/datum/computer_file/program/P, var/forced = 0) - if(!P) - return - P.on_shutdown(forced) - running_programs -= P - if(active_program == P) - active_program = null - if(ismob(usr)) - ui_interact(usr) // Re-open the UI on this computer. It should show the main screen now. - update_host_icon() - -/datum/extension/interactive/ntos/proc/run_program(filename) - var/datum/computer_file/program/P = get_file(filename) - - var/mob/user = usr - if(!P || !istype(P)) // Program not found or it's not executable program. - show_error(user, "I/O ERROR - Unable to run [filename]") - return - - if(!P.is_supported_by_hardware(get_hardware_flag(), user, TRUE)) - return - - minimize_program(user) - - if(P in running_programs) - P.program_state = PROGRAM_STATE_ACTIVE - active_program = P - else if(P.can_run(user, 1)) - P.on_startup(user, src) - active_program = P - - running_programs |= P - update_host_icon() - return 1 - -/datum/extension/interactive/ntos/proc/minimize_program(mob/user) - if(!active_program) - return - active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs - SSnano.close_uis(active_program.NM ? active_program.NM : active_program) - active_program = null - update_host_icon() - if(istype(user)) - ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. - -/datum/extension/interactive/ntos/proc/set_autorun(program) - var/datum/computer_file/data/autorun = get_file("autorun") - if(istype(autorun)) - autorun.stored_data = "[program]" - else - create_file("autorun", "[program]") - -/datum/extension/interactive/ntos/proc/add_log(var/text) - var/datum/extension/network_device/D = get_extension(get_component(PART_NETWORK), /datum/extension/network_device) - if(D) - D.add_log(text) - -/datum/extension/interactive/ntos/proc/get_physical_host() - var/atom/A = holder - if(istype(A)) - return A - -/datum/extension/interactive/ntos/proc/handle_updates(shutdown_after) - updating = TRUE - update_progress = 0 - update_postshutdown = shutdown_after - -// Used by camera monitor program -/datum/extension/interactive/ntos/proc/check_eye(var/mob/user) - if(active_program) - return active_program.check_eye(user) - -/datum/extension/interactive/ntos/proc/process_updates() - if(update_progress < updates) - update_progress += rand(0, 2500) - return - - //It's done. - updating = FALSE - update_host_icon() - updates = 0 - update_progress = 0 - - if(update_postshutdown) - system_shutdown() - -/datum/extension/interactive/ntos/proc/event_powerfailure() - for(var/datum/computer_file/program/P in running_programs) - P.event_powerfailure(P != active_program) - -/datum/extension/interactive/ntos/proc/event_idremoved() - for(var/datum/computer_file/program/P in running_programs) - P.event_idremoved(P != active_program) - -/datum/extension/interactive/ntos/proc/has_terminal(mob/user) - for(var/datum/terminal/terminal in terminals) - if(terminal.get_user() == user) - return terminal - -/datum/extension/interactive/ntos/proc/open_terminal(mob/user) - if(!on) - return - if(has_terminal(user)) - return - LAZYADD(terminals, new /datum/terminal/(user, src)) - -/datum/extension/interactive/ntos/proc/emagged() - return FALSE - -/datum/extension/interactive/ntos/proc/get_processing_power() - var/obj/item/stock_parts/computer/processor_unit/CPU = get_component(PART_CPU) - return CPU?.processing_power \ No newline at end of file diff --git a/code/modules/modular_computers/ntos/subtypes/console.dm b/code/modules/modular_computers/ntos/subtypes/console.dm deleted file mode 100644 index 1a74adf9ac35..000000000000 --- a/code/modules/modular_computers/ntos/subtypes/console.dm +++ /dev/null @@ -1,64 +0,0 @@ -/datum/extension/interactive/ntos/console - expected_type = /obj/machinery - screen_icon_file = 'icons/obj/modular_computers/modular_console.dmi' - -/datum/extension/interactive/ntos/console/get_hardware_flag() - return PROGRAM_CONSOLE - -/datum/extension/interactive/ntos/console/get_component(var/part_type) - var/obj/machinery/M = holder - if(ispath(part_type, PART_DRIVE)) - return ..() //special handling for removable disks - return M.get_component_of_type(part_type) - -/datum/extension/interactive/ntos/console/get_all_components() - var/obj/machinery/M = holder - return M.component_parts.Copy() - -/datum/extension/interactive/ntos/console/get_power_usage() - var/obj/machinery/M = holder - return M.get_power_usage() - -/datum/extension/interactive/ntos/console/recalc_power_usage() - var/obj/machinery/M = holder - M.RefreshParts() - -/datum/extension/interactive/ntos/console/emagged() - var/obj/machinery/M = holder - var/obj/item/stock_parts/circuitboard/modular_computer/MB = M.get_component_of_type(/obj/item/stock_parts/circuitboard/modular_computer) - return MB && MB.emagged - -/datum/extension/interactive/ntos/console/system_boot() - ..() - var/obj/machinery/M = holder - M.update_use_power(POWER_USE_ACTIVE) - -/datum/extension/interactive/ntos/console/system_shutdown() - ..() - var/obj/machinery/M = holder - M.update_use_power(POWER_USE_IDLE) - -/datum/extension/interactive/ntos/console/host_status() - var/obj/machinery/M = holder - return !(M.stat & NOPOWER) - -/datum/extension/interactive/ntos/console/extension_act(href, href_list, user) - . = ..() - var/obj/machinery/M = holder - if(istype(M) && M.clicksound && CanPhysicallyInteractWith(user, M)) - playsound(M, M.clicksound, 40) - -// Hack to make status bar work - -/obj/machinery/initial_data() - . = ..() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - if(os) - . += os.get_header_data() - -/obj/machinery/check_eye() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - if(os) - return os.check_eye() - else - return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/ntos/subtypes/device.dm b/code/modules/modular_computers/ntos/subtypes/device.dm deleted file mode 100644 index 5215e8ddd096..000000000000 --- a/code/modules/modular_computers/ntos/subtypes/device.dm +++ /dev/null @@ -1,60 +0,0 @@ -/datum/extension/interactive/ntos/device - expected_type = /obj/item/modular_computer - -/datum/extension/interactive/ntos/device/host_status() - if(holder) - var/datum/extension/assembly/assembly = get_extension(holder, /datum/extension/assembly) - return assembly && assembly.enabled - -/datum/extension/interactive/ntos/device/get_hardware_flag() - if(holder) - var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) - return assembly && assembly.hardware_flag - -/datum/extension/interactive/ntos/device/get_power_usage() - if(holder) - var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) - return assembly && assembly.last_power_usage - -/datum/extension/interactive/ntos/device/recalc_power_usage() - if(holder) - var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) - return assembly && assembly.calculate_power_usage() - -/datum/extension/interactive/ntos/device/emagged() - var/obj/item/modular_computer/C = holder - return C.computer_emagged - -/datum/extension/interactive/ntos/device/system_shutdown() - ..() - if(holder) - var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) - if(assembly && assembly.enabled) - assembly.shutdown_device() - -/datum/extension/interactive/ntos/device/system_boot() - ..() - if(holder) - var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) - return assembly && assembly.turn_on() - -/datum/extension/interactive/ntos/device/extension_act(href, href_list, user) - . = ..() - var/obj/item/modular_computer/C = holder - if(istype(C) && LAZYLEN(C.interact_sounds) && CanPhysicallyInteractWith(user, C)) - playsound(C, pick(C.interact_sounds), 40) - -// Hack to make status bar work - -/obj/item/modular_computer/initial_data() - . = ..() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - if(os) - . += os.get_header_data() - -/obj/item/modular_computer/check_eye() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - if(os) - return os.check_eye() - else - return ..() diff --git a/code/modules/modular_computers/ntos/subtypes/silicon.dm b/code/modules/modular_computers/ntos/subtypes/silicon.dm deleted file mode 100644 index 2b4840fc881a..000000000000 --- a/code/modules/modular_computers/ntos/subtypes/silicon.dm +++ /dev/null @@ -1,44 +0,0 @@ -/datum/extension/interactive/ntos/silicon - expected_type = /mob/living/silicon - -/datum/extension/interactive/ntos/silicon/update_host_icon() - return - -/datum/extension/interactive/ntos/silicon/get_hardware_flag() - return PROGRAM_CONSOLE - -/datum/extension/interactive/ntos/silicon/get_component(var/part_type) - var/mob/living/silicon/M = holder - return locate(part_type) in M.stock_parts - -/datum/extension/interactive/ntos/silicon/get_all_components() - var/mob/living/silicon/M = holder - return M.stock_parts.Copy() - -/datum/extension/interactive/ntos/silicon/emagged() - var/mob/living/silicon/robot/R = holder - if(istype(R)) - return R.emagged - return FALSE - -/datum/extension/interactive/ntos/silicon/host_status() - var/mob/living/silicon/M = holder - return !M.stat - -// Hack to make status bar work - -/mob/living/silicon/initial_data() - . = ..() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - if(os) - . += os.get_header_data() - -/mob/living/silicon/check_eye() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - if(os) - return os.check_eye() - else - return ..() - -/datum/extension/interactive/ntos/silicon/small/get_hardware_flag() - return PROGRAM_TABLET diff --git a/code/modules/modular_computers/ntos/ui.dm b/code/modules/modular_computers/ntos/ui.dm deleted file mode 100644 index c47943cbdfef..000000000000 --- a/code/modules/modular_computers/ntos/ui.dm +++ /dev/null @@ -1,227 +0,0 @@ - -// Operates NanoUI -/datum/extension/interactive/ntos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(!on || !host_status()) - if(ui) - ui.close() - return 0 - // If we have an active program switch to it now. - if(active_program) - if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now. - ui.close() - active_program.ui_interact(user) - return - - // We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it. - // This screen simply lists available programs and user may select them. - var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) - if(!hard_drive || !length(hard_drive.stored_files)) - show_error(user, "DISK ERROR") - return // No HDD, No HDD files list or no stored files. Something is very broken. - - var/datum/computer_file/data/autorun = get_file("autorun") - - var/list/data = get_header_data() - - var/list/programs = list() - for(var/datum/computer_file/program/P in hard_drive.stored_files) - var/list/program = list() - program["name"] = P.filename - program["desc"] = P.filedesc - program["icon"] = P.program_menu_icon - program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 - if(P in running_programs) - program["running"] = 1 - programs.Add(list(program)) - data["programs"] = programs - - data["updating"] = updating - data["update_progress"] = update_progress - data["updates"] = updates - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "NTOS Main Menu ", 400, 500) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/extension/interactive/ntos/extension_status(var/mob/user) - . = ..() - if(!on || !host_status()) - return STATUS_CLOSE - //There is no bypassing the update, mwhahaha - if(updating) - . = min(STATUS_UPDATE, .) - -/datum/extension/interactive/ntos/CanUseTopic(mob/user, state) - . = holder.CanUseTopic(user, state) - . = min(., extension_status(user)) - -// Handles user's GUI input -/datum/extension/interactive/ntos/extension_act(href, href_list, user) - if( href_list["PC_exit"] ) - kill_program(active_program) - return TOPIC_HANDLED - if(href_list["PC_diagnostics"]) - var/obj/item/stock_parts/computer/H = locate(href_list["PC_diagnostics"]) in holder - var/list/diagnostics = list() - diagnostics += "[H] diagnostics:" - diagnostics |= H.diagnostics() - to_chat(user, SPAN_INFO(jointext(diagnostics, "\n"))) - return TOPIC_REFRESH - if(href_list["PC_enable_component"] ) - var/obj/item/stock_parts/computer/H = locate(href_list["PC_enable_component"]) in holder - if(H && istype(H) && !H.enabled) - H.enabled = 1 - H.on_enable(src) - return TOPIC_REFRESH - if(href_list["PC_disable_component"] ) - var/obj/item/stock_parts/computer/H = locate(href_list["PC_disable_component"]) in holder - if(H && istype(H) && H.enabled) - H.enabled = 0 - H.on_disable() - return TOPIC_REFRESH - if( href_list["PC_enable_update"] ) - receives_updates = TRUE - return TOPIC_REFRESH - if( href_list["PC_disable_update"] ) - receives_updates = FALSE - return TOPIC_REFRESH - if( href_list["PC_shutdown"] ) - system_shutdown() - return TOPIC_HANDLED - if( href_list["PC_minimize"] ) - minimize_program(usr) - return TOPIC_HANDLED - - if( href_list["PC_killprogram"] ) - var/datum/computer_file/program/P = get_file(href_list["PC_killprogram"]) - - if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) - return TOPIC_HANDLED - - kill_program(P) - update_uis() - to_chat(usr, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") - return TOPIC_HANDLED - - if( href_list["PC_runprogram"] ) - run_program(href_list["PC_runprogram"]) - return TOPIC_HANDLED - - if( href_list["PC_setautorun"] ) - set_autorun(href_list["PC_setautorun"]) - return TOPIC_REFRESH - - if( href_list["PC_terminal"] ) - open_terminal(usr) - return TOPIC_HANDLED - -/datum/extension/interactive/ntos/proc/regular_ui_update() - var/ui_update_needed = 0 - var/obj/item/stock_parts/computer/battery_module/battery_module = get_component(PART_BATTERY) - if(battery_module) - var/batery_percent = battery_module.battery.percent() - if(last_battery_percent != batery_percent) //Let's update UI on percent change - ui_update_needed = 1 - last_battery_percent = batery_percent - - if(stationtime2text() != last_world_time) - last_world_time = stationtime2text() - ui_update_needed = 1 - - var/list/current_header_icons = list() - for(var/datum/computer_file/program/P in running_programs) - if(!P.ui_header) - continue - current_header_icons[P.type] = P.ui_header - - if(!last_header_icons) - last_header_icons = current_header_icons - - else if(!listequal(last_header_icons, current_header_icons)) - last_header_icons = current_header_icons - ui_update_needed = 1 - else - for(var/x in last_header_icons|current_header_icons) - if(last_header_icons[x]!=current_header_icons[x]) - last_header_icons = current_header_icons - ui_update_needed = 1 - break - - if(ui_update_needed) - update_uis() - -/datum/extension/interactive/ntos/proc/update_uis() - if(active_program) //Should we update program ui or computer ui? - SSnano.update_uis(active_program) - if(active_program.NM) - SSnano.update_uis(active_program.NM) - -// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_" -/datum/extension/interactive/ntos/proc/get_header_data() - var/list/data = list() - var/obj/item/stock_parts/computer/battery_module/battery_module = get_component(PART_BATTERY) - if(battery_module) - switch(battery_module.battery.percent()) - if(80 to 200) // 100 should be maximal but just in case.. - data["PC_batteryicon"] = "batt_100.gif" - if(60 to 80) - data["PC_batteryicon"] = "batt_80.gif" - if(40 to 60) - data["PC_batteryicon"] = "batt_60.gif" - if(20 to 40) - data["PC_batteryicon"] = "batt_40.gif" - if(5 to 20) - data["PC_batteryicon"] = "batt_20.gif" - else - data["PC_batteryicon"] = "batt_5.gif" - data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %" - data["PC_showbatteryicon"] = 1 - else - data["PC_batteryicon"] = "batt_5.gif" - data["PC_batterypercent"] = "N/C" - data["PC_showbatteryicon"] = battery_module ? 1 : 0 - - var/obj/item/stock_parts/computer/tesla_link/tesla_link = get_component(PART_TESLA) - if(tesla_link && tesla_link.enabled) - data["PC_apclinkicon"] = "charging.gif" - - var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) - if(network_card && network_card.is_banned()) - data["PC_ntneticon"] = "sig_warning.gif" - else - switch(get_network_status()) - if(0) - data["PC_ntneticon"] = "sig_none.gif" - if(1) - data["PC_ntneticon"] = "sig_low.gif" - if(2) - data["PC_ntneticon"] = "sig_high.gif" - if(3) - data["PC_ntneticon"] = "sig_lan.gif" - - var/list/program_headers = list() - for(var/datum/computer_file/program/P in running_programs) - if(!P.ui_header) - continue - program_headers.Add(list(list( - "icon" = P.ui_header - ))) - data["PC_programheaders"] = program_headers - - data["PC_stationtime"] = stationtime2text() - data["PC_hasheader"] = !updating - data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen - return data - -/datum/extension/interactive/ntos/initial_data() - return get_header_data() - -/datum/extension/interactive/ntos/update_layout() - return TRUE - -/datum/extension/interactive/ntos/nano_host() - return holder.nano_host() diff --git a/code/modules/modular_computers/ntos/visuals.dm b/code/modules/modular_computers/ntos/visuals.dm deleted file mode 100644 index 06ad158e8df0..000000000000 --- a/code/modules/modular_computers/ntos/visuals.dm +++ /dev/null @@ -1,52 +0,0 @@ - -/datum/extension/interactive/ntos/proc/update_host_icon() - var/atom/A = holder - if(istype(A)) - A.update_icon() - -/datum/extension/interactive/ntos/proc/get_screen_icon_file() - if(istype(holder, /obj/item/modular_computer)) - var/obj/item/modular_computer/MC = holder - return MC.screen_icon || MC.icon - if(isatom(holder)) - var/atom/A = holder - return A.icon - -/datum/extension/interactive/ntos/proc/get_screen_overlay() - if(!on) - return image(screen_icon_file, screensaver_icon) - if(!screen_icon_file) - screen_icon_file = get_screen_icon_file() - if(screen_icon_file) - var/image/I - if(active_program) - I = image(screen_icon_file, active_program.program_icon_state) - else - I = image(screen_icon_file, menu_icon) - I.appearance_flags |= RESET_COLOR - return I - return image(null) - -/datum/extension/interactive/ntos/proc/get_keyboard_overlay() - if(!on) - return - if(!screen_icon_file) - screen_icon_file = get_screen_icon_file() - if(screen_icon_file && active_program && active_program.program_key_state) - var/image/I = image(screen_icon_file, active_program.program_key_state) - I.appearance_flags |= RESET_COLOR - return I - return image(null) - -/datum/extension/interactive/ntos/proc/visible_error(message) - var/atom/A = holder - if(istype(A)) - A.visible_message("\The [A]'s screen displays an error: \"[message]\"", range = 1) - -/datum/extension/interactive/ntos/proc/visible_notification(message) - var/atom/A = holder - if(istype(A)) - A.visible_message("\The [A] screen displays a notification: \"[message]\"", range = 1) - -/datum/extension/interactive/ntos/proc/show_error(user, message) - to_chat(user, "[message]") diff --git a/code/modules/modular_computers/os/_os.dm b/code/modules/modular_computers/os/_os.dm new file mode 100644 index 000000000000..81241c67ee9d --- /dev/null +++ b/code/modules/modular_computers/os/_os.dm @@ -0,0 +1,326 @@ +/datum/extension/interactive/os + base_type = /datum/extension/interactive/os + expected_type = /atom/movable + flags = EXTENSION_FLAG_IMMEDIATE + + var/on = FALSE + var/datum/computer_file/program/active_program = null // A currently active program running on the computer. + var/list/running_programs = list() // All programms currently running, background or active. + + var/login // The current network account login + var/password // The current network account password. + var/weakref/current_account // Reference to the current account to improve lookup speed. + + var/screen_icon_file // dmi where the screen overlays are kept, defaults to holder's icon if unset + var/menu_icon = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen. + var/screensaver_icon = "standby" + var/default_icon = "generic" //Overlay icon for programs that have a screen overlay the host doesn't have. + var/os_name = "GOOSE" + var/os_full_name = "GOOSE v2.0.4b" + + // Used for deciding if various tray icons need to be updated + var/last_battery_percent + var/last_world_time + var/list/last_header_icons + + //Pain and suffering + var/receives_updates = TRUE + var/updating = FALSE + var/updates = 0 + var/update_progress = 0 + var/update_postshutdown + + var/list/terminals + +/datum/extension/interactive/os/Destroy() + system_shutdown() + . = ..() + +/datum/extension/interactive/os/Process() + if(on && !host_status()) + system_shutdown() + if(!on) + return + if(updating) + process_updates() + return + for(var/datum/computer_file/program/P in running_programs) + if(P.requires_network && !get_network_status(P.requires_network_feature)) + P.event_networkfailure(P != active_program) + else + P.process_tick() + regular_ui_update() + +/datum/extension/interactive/os/proc/host_status() + return TRUE + +/datum/extension/interactive/os/proc/get_network() + var/datum/extension/network_device/D = get_extension(get_component(PART_NETWORK), /datum/extension/network_device) + if(D) + return D.get_network() + +/datum/extension/interactive/os/proc/get_access(var/mob/user) + . = list() + var/datum/computer_file/data/account/access_account = get_account() + if(access_account) + var/datum/computer_network/network = get_network() + if(network) + var/location = "[network.network_id]" + . += "[access_account.login]@[location]" // User access uses '@' + for(var/group in access_account.groups) + . += "[group].[location]" // Group access uses '.' + for(var/group in access_account.parent_groups) // Membership in a child group grants access to anything with an access requirement set to the parent group. + . += "[group].[location]" + if(user) + var/obj/item/card/id/I = user.GetIdCard() + if(I) + . += I.GetAccess(access_account?.login) // Ignore any access that's already on the user account. + +// Returns the current account, if possible. User var is passed only for updating program access from ID, if no account is found. +/datum/extension/interactive/os/proc/get_account(var/mob/user) + if(!current_account) + return null + var/datum/computer_file/data/account/check_account = current_account?.resolve() + if(!istype(check_account)) + logout_account(user) + return null + if(check_account.login != login || check_account.password != password) // The most likely case - login or password were changed. + logout_account(user) + return null + // Check if the account can be located on the network. + var/datum/computer_network/network = get_network() + if(!network || !(check_account in network.get_accounts_unsorted())) + logout_account(user) + return null + return check_account + +// Returns the current account without bothering to check if it can still be found. +/datum/extension/interactive/os/proc/get_account_nocheck() + return current_account?.resolve() + +/datum/extension/interactive/os/proc/login_account(var/new_login, var/new_password, var/mob/user) + var/datum/computer_network/network = get_network() + var/datum/computer_file/data/account/prev_acount = get_account(user) + if(prev_acount) + if(prev_acount.login == new_login && (prev_acount.password == new_password)) + return TRUE + else // Log out of the current account first if we're trying to log into something else. + logout_account(user) + if(network) + for(var/datum/computer_file/data/account/check_account in network.get_accounts()) + if(check_account.login == new_login && check_account.password == new_password) + login = new_login + password = new_password + current_account = weakref(check_account) + check_account.logged_in_os += weakref(src) + + for(var/datum/computer_file/program/P in running_programs) + P.update_access(user) + return TRUE + +/datum/extension/interactive/os/proc/logout_account(var/mob/user) + var/datum/computer_file/data/account/check_account = current_account?.resolve() + if(check_account) + check_account.logged_in_os -= weakref(src) + current_account = null + login = null + password = null + for(var/datum/computer_file/program/P in running_programs) + P.update_access(user) + +/datum/extension/interactive/os/proc/login_prompt(var/mob/user) + var/obj/item/card/id/I = user.GetIdCard() + var/default_login = I?.associated_network_account["login"] + var/default_password = I?.associated_network_account["password"] + + var/new_login = sanitize(input(user, "Enter your account login:", "Account login", default_login) as text|null) + if(!new_login || !CanUseTopic(user, global.default_topic_state)) + return + var/new_password = sanitize(input(user, "Enter your account password:", "Account password", default_password) as text|null) + if(!new_password || !CanUseTopic(user, global.default_topic_state)) + return + + if(login_account(new_login, new_password, user)) + to_chat(user, SPAN_NOTICE("Account login successful: Welcome [new_login]!")) + else + to_chat(user, SPAN_NOTICE("Account login failed: Check login or password.")) + +/datum/extension/interactive/os/proc/system_shutdown() + on = FALSE + for(var/datum/computer_file/program/P in running_programs) + kill_program(P, 1) + + var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) + if(network_card) + var/datum/extension/network_device/D = get_extension(network_card, /datum/extension/network_device) + D?.disconnect() + logout_account() + + if(updating) + updating = FALSE + updates = 0 + update_progress = 0 + var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) + if(hard_drive) + if(prob(10)) + hard_drive.visible_message("[src] emits some ominous clicks.") + hard_drive.take_damage(0.5 * hard_drive.current_health) + else if(prob(5)) + hard_drive.visible_message("[src] emits some ominous clicks.") + hard_drive.take_damage(hard_drive.current_health) + + update_host_icon() + +/datum/extension/interactive/os/proc/system_boot() + on = TRUE + var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) + if(network_card) + var/datum/extension/network_device/D = get_extension(network_card, /datum/extension/network_device) + D.connect() + update_host_icon() + +/datum/extension/interactive/os/proc/kill_program(var/datum/computer_file/program/P, var/forced = 0) + if(!P) + return + P.on_shutdown(forced) + running_programs -= P + if(active_program == P) + active_program = null + if(ismob(usr)) + ui_interact(usr) // Re-open the UI on this computer. It should show the main screen now. + update_host_icon() + +/datum/extension/interactive/os/proc/run_program(filename) + var/datum/computer_file/program/P = get_file(filename, programs_dir) + + var/mob/user = usr + if(!P || !istype(P)) // Program not found or it's not executable program. + show_error(user, " - Unable to run [filename]") + return + + if(!P.is_supported_by_hardware(get_hardware_flag(), user, TRUE)) + return + + if(P.requires_network) + if(!get_network()) // No network at all + show_error(user, "NETWORK ERROR - Unable to run [filename]") + return + if(!get_network_status(P.requires_network_feature)) + show_error(user, "NETWORK ERROR - Network rejected use of [filename] on your current connection") + return + + minimize_program(user) + + if(P in running_programs) + P.program_state = PROGRAM_STATE_ACTIVE + active_program = P + else if(P.can_run(get_access(user), user, TRUE)) + active_program = P + P.on_startup(user, src) + else + return + running_programs |= P + update_host_icon() + return 1 + +/datum/extension/interactive/os/proc/minimize_program(mob/user) + if(!active_program) + return + active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs + SSnano.close_uis(active_program.NM ? active_program.NM : active_program) + if(active_program.browser_module) + SSnano.close_uis(active_program.browser_module) + active_program = null + update_host_icon() + if(istype(user)) + ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + +/datum/extension/interactive/os/proc/set_autorun(program) + var/datum/computer_file/data/autorun = get_file("autorun", "local") + if(istype(autorun)) + autorun.stored_data = "[program]" + else + create_file("autorun", "local", "[program]") // Autorun file is created in the root directory. + +/datum/extension/interactive/os/proc/add_log(var/text) + var/datum/extension/network_device/D = get_extension(get_component(PART_NETWORK), /datum/extension/network_device) + if(D) + D.add_log(text) + +/datum/extension/interactive/os/proc/get_physical_host() + var/atom/A = holder + if(istype(A)) + return A + +/datum/extension/interactive/os/proc/handle_updates(shutdown_after) + updating = TRUE + update_progress = 0 + update_postshutdown = shutdown_after + +// Used by camera monitor program +/datum/extension/interactive/os/proc/check_eye(var/mob/user) + if(active_program) + return active_program.check_eye(user) + return -1 + +/datum/extension/interactive/os/proc/process_updates() + if(update_progress < updates) + update_progress += rand(0, 2500) + return + + //It's done. + updating = FALSE + update_host_icon() + updates = 0 + update_progress = 0 + + if(update_postshutdown) + system_shutdown() + +/datum/extension/interactive/os/proc/event_powerfailure() + for(var/datum/computer_file/program/P in running_programs) + P.event_powerfailure(P != active_program) + +/datum/extension/interactive/os/proc/event_idremoved() + for(var/datum/computer_file/program/P in running_programs) + P.event_idremoved(P != active_program) + +/datum/extension/interactive/os/proc/has_terminal(mob/user) + for(var/datum/terminal/terminal in terminals) + if(terminal.get_user() == user) + return terminal + +/datum/extension/interactive/os/proc/open_terminal(mob/user) + if(!on) + return + if(has_terminal(user)) + return + LAZYADD(terminals, new /datum/terminal/(user, src)) + +/datum/extension/interactive/os/proc/emagged() + return FALSE + +/datum/extension/interactive/os/proc/get_processing_power() + var/obj/item/stock_parts/computer/processor_unit/CPU = get_component(PART_CPU) + return CPU?.processing_power + +/datum/extension/interactive/os/proc/mail_received(datum/computer_file/data/email_message/received) + var/datum/computer_file/program/email_client/e_client = locate() in running_programs + if(e_client) + e_client.mail_received(received) + +/datum/extension/interactive/os/proc/run_script(mob/user, var/datum/computer_file/data/script) + open_terminal(user) + var/datum/terminal/T = has_terminal(user) + if(!istype(T)) + return TOPIC_HANDLED + + T.show_terminal(user) + T.append_to_history(">Running '[script.filename].[script.filetype]'") + var/list/lines = splittext(script.stored_data, "\[br\]") + for(var/line in lines) + var/output = T.parse(line, user) + if(QDELETED(T)) // Check for exit. + return TOPIC_HANDLED + T.append_to_history(output) + CHECK_TICK \ No newline at end of file diff --git a/code/modules/modular_computers/os/components.dm b/code/modules/modular_computers/os/components.dm new file mode 100644 index 000000000000..c3ea4c0134d7 --- /dev/null +++ b/code/modules/modular_computers/os/components.dm @@ -0,0 +1,78 @@ +/datum/extension/interactive/os/proc/get_component(var/part_type) + return locate(part_type) in holder + +/datum/extension/interactive/os/proc/get_all_components() + . = list() + for(var/obj/item/stock_parts/P in holder) + . += P + +/datum/extension/interactive/os/proc/find_hardware_by_name(var/partname) + for(var/obj/item/stock_parts/P in holder) + if(findtext(P.name, partname)) + return P + +/datum/extension/interactive/os/proc/has_component(var/part_type) + return !!get_component(part_type) + +/datum/extension/interactive/os/proc/print_paper(content, title, paper_type, list/metadata) + var/obj/item/stock_parts/computer/nano_printer/printer = get_component(PART_PRINTER) + if(printer) + return printer.print_text(content, title, paper_type, metadata) + +/datum/extension/interactive/os/proc/get_network_tag() + var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) + if(network_card) + return network_card.get_network_tag() + else + return "N/A" + +/datum/extension/interactive/os/proc/get_network_status(var/specific_action = 0) + var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) + if(network_card) + var/signal_power_level = NETWORK_SPEED_BASE * network_card.get_signal(specific_action) + if(signal_power_level > 0) + signal_power_level = round(clamp(signal_power_level, 1, 3)) + return signal_power_level + else + return 0 + +/datum/extension/interactive/os/proc/get_inserted_id() + var/obj/item/stock_parts/computer/card_slot/card_slot = get_component(PART_CARD) + if(card_slot) + return card_slot.stored_card + +/datum/extension/interactive/os/proc/max_disk_capacity() + var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) + if(hard_drive) + return hard_drive.max_capacity + +/datum/extension/interactive/os/proc/used_disk_capacity() + var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) + if(hard_drive) + return hard_drive.used_capacity + +/datum/extension/interactive/os/proc/get_hardware_flag() + return PROGRAM_ALL + +//Used to display in configurator program +/datum/extension/interactive/os/proc/get_power_usage() + return 0 + +/datum/extension/interactive/os/proc/recalc_power_usage() + +/datum/extension/interactive/os/proc/voltage_overload() + var/atom/A = holder + if(istype(A)) + spark_at(A, amount = 10, cardinal_only = TRUE, holder = A) + + var/obj/item/stock_parts/computer/hard_drive = get_component(PART_HDD) + if(hard_drive) + qdel(hard_drive) + + var/obj/item/stock_parts/computer/battery_module = get_component(PART_BATTERY) + if(battery_module && prob(25)) + qdel(battery_module) + + var/obj/item/stock_parts/computer/tesla_link = get_component(PART_TESLA) + if(tesla_link && prob(50)) + qdel(tesla_link) \ No newline at end of file diff --git a/code/modules/modular_computers/os/files.dm b/code/modules/modular_computers/os/files.dm new file mode 100644 index 000000000000..4ad6ed46fa62 --- /dev/null +++ b/code/modules/modular_computers/os/files.dm @@ -0,0 +1,738 @@ +/datum/extension/interactive/os + var/list/mounted_storage = list() // Dictionary of root name -> /datum/file_storage + var/programs_dir // For easy reference. Use only with OS filesystem procs. + +/datum/extension/interactive/os/system_boot() + . = ..() + var/obj/item/stock_parts/computer/hard_drive = get_component(PART_HDD) + if(hard_drive) + mounted_storage["local"] = new /datum/file_storage/disk(src, "local") + programs_dir = "local" + "/" + OS_PROGRAMS_DIR + var/obj/item/stock_parts/computer/drive_slot/drive_slot = get_component(PART_D_SLOT) + if(drive_slot) + drive_slot.mount_filesystem(src) + var/obj/item/stock_parts/computer/data_disk_drive/disk_drive = get_component(PART_DSKSLOT) + if(disk_drive) + disk_drive.mount_filesystem(src) + + // Auto-run: must happen after storage mount above + var/datum/computer_file/data/autorun = get_file("autorun", "local") + if(istype(autorun)) + run_program(autorun.stored_data) + + // Auto-mounted mainframes. + var/datum/computer_file/data/automount_file = get_file("automount", "local") + if(istype(automount_file)) + var/list/automounts = splittext(automount_file.stored_data, ";") + for(var/automount in automounts) + var/list/automount_split = splittext(automount, "|") + if(length(automount_split) != 2) + continue + var/root_name = automount_split[1] + var/mainframe_tag = automount_split[2] + + mount_mainframe(root_name, mainframe_tag) + +/datum/extension/interactive/os/system_shutdown() + QDEL_LIST_ASSOC_VAL(mounted_storage) + . = ..() + +// Mounts a new file storage by a given root_name. +/datum/extension/interactive/os/proc/mount_storage(storage_type, root_name, hidden) + if(!ispath(storage_type, /datum/file_storage) || !length(root_name)) + return + + var/mount_name = root_name + var/i = 0 + while(mounted_storage[mount_name]) + i++ + mount_name = root_name + "_[i]" + + var/datum/file_storage/new_storage = new storage_type(src, mount_name, hidden) + mounted_storage[mount_name] = new_storage + return new_storage + +/datum/extension/interactive/os/proc/unmount_storage(root_name) + var/datum/file_storage/removed = mounted_storage[root_name] + if(!removed) + return FALSE + + // Tell programs to clean up any lingering references. + for(var/datum/computer_file/program/P in running_programs) + P.on_file_storage_removal(removed) + + mounted_storage[root_name] = null + mounted_storage -= root_name + + qdel(removed) + return TRUE + +/datum/extension/interactive/os/proc/mount_mainframe(root_name, mainframe_tag) + var/sanitized_root_name = sanitize_for_file(root_name) + if(!length(sanitized_root_name)) + return "I/O ERROR: Unable to mount mainframe as file system with root directory '[root_name]'." + var/datum/computer_network/network = get_network() + if(!network) + return "NETWORK ERROR: Cannot connect to network." + var/datum/extension/network_device/mainframe/mainframe = network.get_device_by_tag(mainframe_tag) + if(!istype(mainframe)) + return "NETWORK ERROR: No mainframe with network tag '[mainframe_tag]' found." + + var/datum/file_storage/network/created_storage = mount_storage(/datum/file_storage/network, sanitized_root_name, FALSE) + if(!created_storage) + return "I/O ERROR: Unable to mount mainframe as file system with root directory '[sanitized_root_name]'." + created_storage.server = mainframe_tag + return "Successfully mounted mainframe with network tag '[mainframe_tag]' as file system with root directory '[sanitized_root_name]'." + +// Rundown of the filesystem hierarchy: +// The OS creates instances of /datum/file_storage as local or network disks, referenced in its mounted_storage list. +// mounted_storage is keyed by the name of the root directory of the disk. +// Filesystem procs on the OS extension itself expects directory paths with root directories e.g. /local/programs or /network/logs +// Filesystem procs on the file_storage datums and harddrives do not, eg. /programs or /logs + +// Returns list(/datum/file_storage, /datum/computer_file/directory) on success, error code on failure. Only supports absolute paths. +// This should not be done every tick for UIs etc. Cache a reference to the directory/file and only re-parse the directory when necessary. +/datum/extension/interactive/os/proc/parse_directory(directory_path, create_directories = FALSE) + var/list/directories = splittext(directory_path, "/") + + // Cut out any extraneous spaces which may have came from splitting the path + if(!length(directories[1])) + directories.Cut(1, 2) + if(!length(directories[directories.len])) + directories.Cut(directories.len) + + var/datum/file_storage/storage = mounted_storage[directories[1]] + if(!storage) + return OS_DIR_NOT_FOUND + if(length(directories) == 1) // Root directory of the storage + return list(storage, null) + var/datum/computer_file/directory/dir = storage.parse_directory(jointext(directories, "/", 2), create_directories) + if(!istype(dir)) // Error! + return dir + return list(storage, dir) + +// Returns list(/datum/file_storage, /datum/computer_file/directory, /datum/computer_file) from the passed path. Only supports absolute paths. +/datum/extension/interactive/os/proc/parse_file(file_path) + var/list/paths = splittext(file_path, "/") + if(!length(paths)) + return OS_DIR_NOT_FOUND + if(!length(paths[1])) + paths.Cut(1, 2) + + var/list/file_loc = parse_directory(jointext(paths, "/", paths.len)) + if(!islist(file_loc)) + return file_loc + var/datum/file_storage/storage = file_loc[1] + var/datum/computer_file/F = storage.get_file(paths[paths.len], file_loc[2]) + if(!istype(F)) + return F + return list(storage, file_loc[2], F) + +/datum/extension/interactive/os/proc/get_all_files(obj/item/stock_parts/computer/hard_drive/disk = get_component(PART_HDD)) + . = list() + if(disk) + return disk.stored_files + +// Returns the file with the given name in the given directory path. Returns error code on failure. +/datum/extension/interactive/os/proc/get_file(filename, dir_path, list/accesses, mob/user) + var/list/file_loc = parse_directory(dir_path) + if(!islist(file_loc)) + return file_loc + var/datum/file_storage/storage = file_loc[1] + return storage.get_file(filename, file_loc[2]) + +// Stores the passed file in the given directory path. Returns OS_FILE_SUCCESS on success, error code on failure. +/datum/extension/interactive/os/proc/store_file(datum/computer_file/file, dir_path, create_directories = FALSE, list/accesses, mob/user, overwrite = TRUE) + var/list/file_loc = parse_directory(dir_path, create_directories) + if(!islist(file_loc)) + return file_loc + + var/datum/file_storage/storage = file_loc[1] + return storage.store_file(file, file_loc[2], create_directories, accesses, user, overwrite) + +// Checks if the passed file can be stored in the given directory path without actually storing it. Returns OS_FILE_SUCCESS on success, error code on failure. +/datum/extension/interactive/os/proc/try_store_file(datum/computer_file/file, dir_path, list/accesses, mob/user) + var/list/file_loc = parse_directory(dir_path) + if(!islist(file_loc)) + return file_loc + + var/datum/file_storage/storage = file_loc[1] + return storage.try_store_file(file, file_loc[2], accesses, user) + +// Helper for creating a file. Returns file on success, error code on failure. +/datum/extension/interactive/os/proc/create_file(filename, dir_path, data, file_type = /datum/computer_file/data/text, list/metadata, list/accesses, mob/user) + filename = sanitize_for_file(filename) + if(!length(filename)) + return OS_BAD_NAME + + var/list/file_loc = parse_directory(dir_path) + if(!islist(file_loc)) + return file_loc + + var/datum/file_storage/storage = file_loc[1] + + return storage.create_file(filename, file_loc[2], data, file_type, metadata, accesses, user) + +// Saves or creates the file with the given name in the passed directory. Returns file on success, error code on failure. +/datum/extension/interactive/os/proc/save_file(filename, dir_path, new_data, file_type = /datum/computer_file/data/text, list/metadata, list/accesses, mob/user) + filename = sanitize_for_file(filename) + if(!length(filename)) + return OS_BAD_NAME + + var/list/file_loc = parse_directory(dir_path) + if(!islist(file_loc)) + return file_loc + + var/datum/file_storage/storage = file_loc[1] + return storage.save_file(filename, file_loc[2], new_data, metadata, accesses, user, file_type) + +// Deletes the file with the given filepath. Returns OS_FILE_SUCCESS on success, error code on failure. +/datum/extension/interactive/os/proc/delete_file(filepath, list/accesses, mob/user) + var/list/file_loc = parse_file(filepath) + if(!islist(file_loc)) + return file_loc + + var/datum/file_storage/storage = file_loc[1] + return storage.delete_file(file_loc[3], file_loc[2], accesses, user) + +/datum/extension/interactive/os/proc/clone_file(filename, dir_path, list/accesses, mob/user) + var/list/file_loc = parse_directory(dir_path) + if(!islist(file_loc)) + return file_loc + + var/datum/file_storage/storage = file_loc[1] + return storage.clone_file(filename, file_loc[2], accesses, user) + +// Generic file storage interface +/datum/file_storage + var/desc = "Generic File Interface" + var/root_name // Display name of the root directory which doesn't exist as an actual directory file. + var/datum/extension/interactive/os/os + var/hidden = FALSE // Whether this file storage interface is for internal use. + +/datum/file_storage/New(ntos, name, is_hidden) + os = ntos + root_name = name + hidden = is_hidden + +/datum/file_storage/Destroy(force) + os = null + . = ..() + +// Additional check for access on top of file system permissions. +/datum/file_storage/proc/check_access(list/accesses) + return TRUE + +/datum/file_storage/proc/check_errors() + if(!istype(os)) + return "No compatible device found." + +/datum/file_storage/proc/get_transfer_speed() + return 1 + +/datum/file_storage/proc/get_all_files() + +/datum/file_storage/proc/get_dir_files(datum/computer_file/directory/dir) + . = list() + var/list/all_files = get_all_files() + if(dir && (dir in all_files)) + . = dir.get_held_files() + else + // No current directory, get all files which are not held by a directory + if(!all_files) + return + for(var/file in all_files) + if(!all_files[file]) // No directory associated with the file. + . += file + + return sortTim(., /proc/cmp_files_sort) + +// The following procs should return OS_FILE_SUCCESS on success (or the target file), or error codes on failure. +/datum/file_storage/proc/get_file(filename, directory) + +/datum/file_storage/proc/store_file(datum/computer_file/F, directory, create_directories, list/accesses, mob/user, overwrite = TRUE) + +/datum/file_storage/proc/try_store_file(datum/computer_file/F, directory, list/accesses, mob/user) + +/datum/file_storage/proc/save_file(filename, directory, new_data, list/metadata, list/accesses, mob/user, file_type = /datum/computer_file/data) + +/datum/file_storage/proc/delete_file(datum/computer_file/F, list/accesses, mob/user) + +/datum/file_storage/proc/rename_file(datum/computer_file/F, newname, mob/user) + F.filename = newname + return OS_FILE_SUCCESS + +/datum/file_storage/proc/create_file(filename, directory, data, file_type = /datum/computer_file/data, list/metadata, list/accesses, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + + filename = sanitize_for_file(filename) + if(!length(filename)) + return OS_BAD_NAME + var/datum/computer_file/F = new file_type(md = metadata) + F.filename = filename + if(istype(F, /datum/computer_file/data)) + var/datum/computer_file/data/FD = F + FD.calculate_size() + var/success = store_file(F, directory, FALSE, accesses, user) + if(success == OS_FILE_SUCCESS) + return F + qdel(F) + return success +/datum/file_storage/proc/create_directory(filename, directory, list/accesses, mob/user) + return create_file(filename, directory, null, /datum/computer_file/directory, null, accesses, user) +/datum/file_storage/proc/clone_file(filename, directory, list/accesses, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/datum/computer_file/F = get_file(filename, directory) + if(!istype(F)) + return F + if(!(F.get_file_perms(accesses, user) & OS_READ_ACCESS) || F.uncopyable) + return OS_FILE_NO_READ + + var/datum/computer_file/cloned_file = F.Clone(TRUE) + if(!istype(cloned_file)) + return OS_FILE_NO_READ + + var/success = store_file(cloned_file, directory, TRUE, accesses, user) + if(success != OS_FILE_SUCCESS) + qdel(cloned_file) // Clean up after ourselves + return success + +/datum/file_storage/proc/get_dir_path(datum/computer_file/directory/current_directory, full) + if(current_directory) + if(full) + return "[root_name]/" + current_directory.get_file_path() + return current_directory.filename + return root_name + +/datum/file_storage/proc/parse_directory(directory_path, create_directories = FALSE) + +// Storing stuff on a server in computer network +/datum/file_storage/network + desc = "Remote File Server" + var/server = "NONE" //network tag of the file server + +/datum/file_storage/network/New(ntos, name, hidden, server_tag) + . = ..() + if(server_tag) + server = server_tag + +/datum/file_storage/network/check_access(list/accesses) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return + return M.has_access(accesses) + +/datum/file_storage/network/check_errors() + . = ..() + if(.) + return + var/datum/computer_network/network = os.get_network() + if(!network) + return "NETWORK ERROR: No connectivity to the network" + if(!os.get_network_status(NET_FEATURE_FILESYSTEM)) + return "NETWORK ERROR: Network denied filesystem access" + if(!network.get_device_by_tag(server)) + return "NETWORK ERROR: No connectivity to the file server '[server]'" + var/datum/extension/network_device/mainframe/M = network.get_device_by_tag(server) + if(!istype(M)) + return "NETWORK ERROR: Invalid server '[server]', no file sharing capabilities detected" + +/datum/file_storage/network/proc/set_server(new_server) + server = new_server + +/datum/file_storage/network/proc/get_mainframe() + if(check_errors()) + return FALSE + var/datum/computer_network/network = os.get_network() + return network.get_device_by_tag(server) + +/datum/file_storage/network/get_all_files() + var/datum/extension/network_device/mainframe/M = get_mainframe() + return M && M.get_all_files() + +/datum/file_storage/network/get_file(filename, directory) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return OS_NETWORK_ERROR + return M.get_file(filename, directory) + +/datum/file_storage/network/store_file(datum/computer_file/F, directory, create_directories, list/accesses, mob/user, overwrite = TRUE) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return OS_NETWORK_ERROR + return M.store_file(F, directory, create_directories, accesses, user, overwrite) + +/datum/file_storage/network/try_store_file(datum/computer_file/F, directory, list/accesses, mob/user) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return OS_NETWORK_ERROR + return M.try_store_file(F, directory, accesses, user) + +/datum/file_storage/network/delete_file(datum/computer_file/F, list/accesses, mob/user) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return OS_NETWORK_ERROR + return M.delete_file(F, accesses, user) + +/datum/file_storage/network/save_file(filename, directory, new_data, list/metadata, list/accesses, mob/user, file_type = /datum/computer_file/data) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return OS_NETWORK_ERROR + return M.save_file(filename, directory, new_data, metadata, accesses, user, file_type) + +/datum/file_storage/network/parse_directory(directory_path, create_directories) + var/datum/extension/network_device/mainframe/M = get_mainframe() + if(!M) + return OS_NETWORK_ERROR + return M.parse_directory(directory_path, create_directories) + +/datum/file_storage/network/get_transfer_speed() + if(check_errors()) + return 0 + return os.get_network_status(NET_FEATURE_FILESYSTEM) + +/* + * Special subclass for network machines specifically. + * + */ +/datum/file_storage/network/machine + var/obj/localhost + +/datum/file_storage/network/machine/New(os, machine) + localhost = machine + +/datum/file_storage/network/machine/check_errors() + // Do not call predecessors. This is a straight up override. + var/datum/extension/network_device/computer = get_extension(localhost, /datum/extension/network_device) + var/datum/computer_network/network = computer.get_network() + if(!network) + return "NETWORK ERROR: No connectivity to the network" + if(!network.get_device_by_tag(server)) + return "NETWORK ERROR: No connectivity to the file server '[server]'" + var/datum/extension/network_device/mainframe/M = network.get_device_by_tag(server) + if(!istype(M)) + return "NETWORK ERROR: Invalid server '[server]', no file sharing capabilities detected" + +/datum/file_storage/network/machine/get_mainframe() + if(check_errors()) + return FALSE + var/datum/extension/network_device/computer = get_extension(localhost, /datum/extension/network_device) + var/datum/computer_network/network = computer.get_network() + return network.get_device_by_tag(server) + +/datum/file_storage/network/machine/get_transfer_speed() + if(check_errors()) + return 0 + return 1 + +// Storing stuff locally on some kinda disk +/datum/file_storage/disk + desc = "Local Storage" + var/disk_type = PART_HDD + +/datum/file_storage/disk/proc/get_disk() + return os.get_component(disk_type) + +/datum/file_storage/disk/check_errors() + . = ..() + if(.) + return + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!istype(HDD)) + return "HARDWARE ERROR: No compatible device found" + if(!HDD.check_functionality()) + return "NETWORK ERROR: [HDD] is non-operational" + +/datum/file_storage/disk/get_all_files() + if(check_errors()) + return FALSE + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + return HDD.stored_files + +/datum/file_storage/disk/get_file(filename, directory) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!HDD) + return OS_HARDDRIVE_ERROR + return HDD.find_file_by_name(filename, directory) + +/datum/file_storage/disk/store_file(datum/computer_file/F, directory, create_directories, list/accesses, mob/user, overwrite = TRUE) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!HDD) + return OS_HARDDRIVE_ERROR + return HDD.store_file(F, directory, create_directories, accesses, user, overwrite) + +/datum/file_storage/disk/try_store_file(datum/computer_file/F, directory, list/accesses, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!HDD) + return OS_HARDDRIVE_ERROR + return HDD.try_store_file(F, directory, accesses, user) + +/datum/file_storage/disk/save_file(filename, directory, new_data, metadata, accesses, user, file_type = /datum/computer_file/data) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!HDD) + return OS_HARDDRIVE_ERROR + return HDD.save_file(filename, directory, new_data, metadata, accesses, user, file_type) + +/datum/file_storage/disk/delete_file(datum/computer_file/F, list/accesses, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!HDD) + return OS_HARDDRIVE_ERROR + return HDD.remove_file(F, accesses, user) + +/datum/file_storage/disk/get_transfer_speed() + if(check_errors()) + return 0 + return NETWORK_SPEED_DISK + +/datum/file_storage/disk/parse_directory(directory_path, create_directories) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/stock_parts/computer/hard_drive/HDD = get_disk() + if(!HDD) + return OS_HARDDRIVE_ERROR + return HDD.parse_directory(directory_path, create_directories) + +// Storing files on a removable disk. +/datum/file_storage/disk/removable + desc = "Disk Drive" + root_name = "media" + +/datum/file_storage/disk/removable/get_disk() + var/obj/item/stock_parts/computer/drive_slot/drive_slot = os.get_component(PART_D_SLOT) + return drive_slot?.stored_drive + +/datum/file_storage/disk/removable/check_errors() + var/obj/item/stock_parts/computer/drive_slot/drive_slot = os.get_component(PART_D_SLOT) + if(!istype(drive_slot)) + return "HARDWARE ERROR: No drive slot was found." + if(!drive_slot.check_functionality()) + return "HARDWARE ERROR: [drive_slot] is non-operational." + if(!istype(drive_slot.stored_drive)) + return "HARDWARE ERROR: No portable drive inserted." + . = ..() + if(.) + return + +// Storing data files on a data disk. +/datum/file_storage/disk/datadisk + desc = "Data Disk Drive" + root_name = "data" + +/datum/file_storage/disk/datadisk/get_disk() + var/obj/item/stock_parts/computer/data_disk_drive/diskslot = os.get_component(PART_DSKSLOT) + return diskslot?.stored_disk + +/datum/file_storage/disk/datadisk/check_errors() + var/obj/item/stock_parts/computer/data_disk_drive/drive_slot = os.get_component(PART_DSKSLOT) + if(!istype(drive_slot)) + return "HARDWARE ERROR: No drive slot was found." + if(!drive_slot.check_functionality()) + return "HARDWARE ERROR: [drive_slot] is non-operational." + if(!istype(drive_slot.stored_disk)) + return "HARDWARE ERROR: No portable drive inserted." + if(!istype(os)) + return "No compatible device found." + +/datum/file_storage/disk/datadisk/get_file(filename, directory) + if(check_errors()) + return OS_HARDDRIVE_ERROR + if(directory) + return OS_DIR_NOT_FOUND + var/obj/item/disk/disk = get_disk() + return disk.read_file(filename) + +/datum/file_storage/disk/datadisk/store_file(datum/computer_file/file, directory, create_directories, list/accesses, mob/user, overwrite = TRUE) + . = try_store_file(file) + if(. == OS_FILE_EXISTS && overwrite) + var/datum/computer_file/data/target = get_file(file.filename) + if(target && !(target.get_file_perms(accesses, user) & OS_WRITE_ACCESS)) + return OS_FILE_NO_WRITE + var/obj/item/disk/disk = get_disk() + return disk.write_file(file) + return . + +/datum/file_storage/disk/datadisk/try_store_file(datum/computer_file/file, directory, list/accesses, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + if(directory) + return OS_DIR_NOT_FOUND + if(!istype(file, /datum/computer_file/data)) + return OS_BAD_TYPE + var/obj/item/disk/disk = get_disk() + if(!disk.can_write_file(file)) + return OS_HARDDRIVE_SPACE + if(disk.read_file(file.filename)) + return OS_FILE_EXISTS // this MUST be the last code returned before we succeed + return disk.write_file(file) + +/datum/file_storage/disk/datadisk/save_file(filename, directory, new_data, metadata, accesses, user, file_type = /datum/computer_file/data) + if(check_errors()) + return OS_HARDDRIVE_ERROR + if(directory) + return OS_DIR_NOT_FOUND + if(!ispath(file_type, /datum/computer_file/data)) + return OS_BAD_TYPE + var/obj/item/disk/disk = get_disk() + var/datum/computer_file/data/target = get_file(filename) + if(istype(target)) + if(!(target.get_file_perms(accesses, user) & OS_WRITE_ACCESS)) + return OS_FILE_NO_WRITE + else + disk.delete_file(filename) + target = new file_type(metadata) + target.stored_data = new_data + target.calculate_size() + return disk.write_file(target, filename) + +/datum/file_storage/disk/datadisk/delete_file(datum/computer_file/file, list/accesses, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + if(!get_file(file.filename)) + return OS_FILE_NOT_FOUND + var/obj/item/disk/disk = get_disk() + if(disk.delete_file(file.filename)) + return OS_FILE_SUCCESS + +/datum/file_storage/disk/datadisk/rename_file(datum/computer_file/file, newname, mob/user) + if(check_errors()) + return OS_HARDDRIVE_ERROR + var/obj/item/disk/disk = get_disk() + if(disk.rename_file(file.filename, newname)) + return OS_FILE_SUCCESS + +/datum/file_storage/disk/datadisk/get_transfer_speed() + if(check_errors()) + return 0 + return NETWORK_SPEED_DISK + +/datum/file_storage/disk/datadisk/get_all_files() + if(check_errors()) + return FALSE + var/obj/item/disk/disk = get_disk() + . = list() + for(var/key in disk.stored_files) + . += disk.stored_files[key] + +// Directories are not supported, so always return root (null dir). +/datum/file_storage/disk/datadisk/parse_directory(directory_path, create_directories) + return list(src, null) + +// Datum tracking progress between of file transfer between two file streams +/datum/file_transfer + var/datum/file_storage/transfer_from + var/datum/file_storage/transfer_to + + var/datum/computer_file/directory/directory_to + var/datum/computer_file/directory/directory_from + + var/datum/computer_file/transferring + var/left_to_transfer + var/copying = FALSE // Whether or not this file transfer is copying, rather than transferring. + +/datum/file_transfer/New(datum/file_storage/source, datum/file_storage/destination, datum/computer_file/directory/dest_directory, datum/computer_file/file, copy) + transfer_from = source + transfer_to = destination + transferring = file + + directory_to = dest_directory + directory_from = file.get_directory() + + if(istype(file, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = file + left_to_transfer = dir.get_held_size() + else + left_to_transfer = file.size + copying = copy + +/datum/file_transfer/Destroy() + transfer_from = null + transfer_to = null + + directory_to = null + transferring = null + . = ..() + +/datum/file_transfer/proc/check_self() + if(QDELETED(transfer_from) || QDELETED(transfer_from) || QDELETED(transferring)) + qdel(src) + return OS_FILE_NOT_FOUND + return OS_FILE_SUCCESS + +//Returns OS_FILE_SUCESS if progress was made and or we are done. Returns error code otherwise. +/datum/file_transfer/proc/update_progress() + . = check_self() + if(. != OS_FILE_SUCCESS) + return + left_to_transfer = max(0, left_to_transfer - get_transfer_speed()) + if(!left_to_transfer) + if(copying) + return transfer_to.store_file(transferring.Clone(), directory_to, TRUE) + else + . = transfer_from.delete_file(transferring) // Check if we can delete the file. + if(. == OS_FILE_SUCCESS) + . = transfer_to.store_file(transferring, directory_to, FALSE) + // If we failed to store the file, restore it to its former location. + if(. != OS_FILE_SUCCESS) + transfer_from.store_file(transferring, directory_from, FALSE) + +/datum/file_transfer/proc/get_transfer_speed() + if(!check_self()) + return 0 + return min(transfer_from.get_transfer_speed(), transfer_to.get_transfer_speed()) + +/datum/file_transfer/proc/get_eta() + if(!check_self() || !get_transfer_speed()) + return INFINITY + return round(left_to_transfer / get_transfer_speed()) + +/datum/file_transfer/proc/get_ui_data() + if(!check_self()) + return + var/list/data = list() + + data["transfer_from"] = transfer_from.get_dir_path(directory_from, TRUE) + data["transfer_to"] = transfer_to.get_dir_path(directory_to, TRUE) + data["transfer_file"] = transferring.filename + data["transfer_progress"] = transferring.size - left_to_transfer + data["transfer_total"] = transferring.size + return data + +// Checks permissions for transferring files. Returns error string on failure, null on success. +/proc/check_file_transfer(datum/computer_file/directory/destination, datum/computer_file/file, copy, list/accesses, mob/user) + if(!file) + return "Could not locate file" + + if(destination) + if(!(destination.get_file_perms(accesses, user) & OS_WRITE_ACCESS)) + return "You lack access to the directory [destination.filename]" + + if(file) + var/req_access = copy ? OS_READ_ACCESS : OS_WRITE_ACCESS + var/move_string = copy ? "copy" : "transfer" + + if(istype(file, /datum/computer_file/directory)) + var/datum/computer_file/directory/dir = file + if(!copy) + if(dir.undeletable) + return "You lack permission to [move_string] the directory [dir.filename]" + for(var/datum/computer_file/child in dir.get_held_files()) + if(child.undeletable) + return "You lack permission to [move_string] the directory [dir.filename]" + + if(!(dir.get_held_perms(accesses, user) & req_access)) + return "You lack permission to [move_string] the directory [dir.filename]" + else + if((!copy && file.undeletable) || !(file.get_file_perms(accesses, user) & req_access)) + return "You lack permission to [move_string] the file [file.filename]" \ No newline at end of file diff --git a/code/modules/modular_computers/os/subtypes/console.dm b/code/modules/modular_computers/os/subtypes/console.dm new file mode 100644 index 000000000000..7eb712746df3 --- /dev/null +++ b/code/modules/modular_computers/os/subtypes/console.dm @@ -0,0 +1,64 @@ +/datum/extension/interactive/os/console + expected_type = /obj/machinery + screen_icon_file = 'icons/obj/modular_computers/modular_console.dmi' + +/datum/extension/interactive/os/console/get_hardware_flag() + return PROGRAM_CONSOLE + +/datum/extension/interactive/os/console/get_component(var/part_type) + var/obj/machinery/M = holder + if(ispath(part_type, PART_DRIVE)) + return ..() //special handling for removable disks + return M.get_component_of_type(part_type) + +/datum/extension/interactive/os/console/get_all_components() + var/obj/machinery/M = holder + return M.component_parts.Copy() + +/datum/extension/interactive/os/console/get_power_usage() + var/obj/machinery/M = holder + return M.get_power_usage() + +/datum/extension/interactive/os/console/recalc_power_usage() + var/obj/machinery/M = holder + M.RefreshParts() + +/datum/extension/interactive/os/console/emagged() + var/obj/machinery/M = holder + var/obj/item/stock_parts/circuitboard/modular_computer/MB = M.get_component_of_type(/obj/item/stock_parts/circuitboard/modular_computer) + return MB && MB.emagged + +/datum/extension/interactive/os/console/system_boot() + ..() + var/obj/machinery/M = holder + M.update_use_power(POWER_USE_ACTIVE) + +/datum/extension/interactive/os/console/system_shutdown() + ..() + var/obj/machinery/M = holder + M.update_use_power(POWER_USE_IDLE) + +/datum/extension/interactive/os/console/host_status() + var/obj/machinery/M = holder + return !(M.stat & NOPOWER) + +/datum/extension/interactive/os/console/extension_act(href, href_list, user) + . = ..() + var/obj/machinery/M = holder + if(istype(M) && M.clicksound && CanPhysicallyInteractWith(user, M)) + playsound(M, M.clicksound, 40) + +// Hack to make status bar work + +/obj/machinery/initial_data() + . = ..() + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + . += os.get_header_data() + +/obj/machinery/check_eye(user) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + return os.check_eye(user) + else + return ..() \ No newline at end of file diff --git a/code/modules/modular_computers/os/subtypes/device.dm b/code/modules/modular_computers/os/subtypes/device.dm new file mode 100644 index 000000000000..a786e8b4927c --- /dev/null +++ b/code/modules/modular_computers/os/subtypes/device.dm @@ -0,0 +1,53 @@ +/datum/extension/interactive/os/device + expected_type = /obj/item/modular_computer + +/datum/extension/interactive/os/device/host_status() + if(holder) + var/datum/extension/assembly/assembly = get_extension(holder, /datum/extension/assembly) + return assembly && assembly.enabled + +/datum/extension/interactive/os/device/get_hardware_flag() + if(holder) + var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) + return assembly && assembly.hardware_flag + +/datum/extension/interactive/os/device/get_power_usage() + if(holder) + var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) + return assembly && assembly.last_power_usage + +/datum/extension/interactive/os/device/recalc_power_usage() + if(holder) + var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) + return assembly && assembly.calculate_power_usage() + +/datum/extension/interactive/os/device/emagged() + var/obj/item/modular_computer/C = holder + return C.computer_emagged + +/datum/extension/interactive/os/device/system_shutdown() + ..() + if(holder) + var/datum/extension/assembly/modular_computer/assembly = get_extension(holder, /datum/extension/assembly) + if(assembly && assembly.enabled) + assembly.shutdown_device() + +/datum/extension/interactive/os/device/extension_act(href, href_list, user) + . = ..() + var/obj/item/modular_computer/C = holder + if(istype(C) && LAZYLEN(C.interact_sounds) && CanPhysicallyInteractWith(user, C)) + playsound(C, pick(C.interact_sounds), 40) + +// Hack to make status bar work + +/obj/item/modular_computer/initial_data() + . = ..() + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + . += os.get_header_data() + +/obj/item/modular_computer/check_eye(user) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + return os.check_eye(user) + return ..() diff --git a/code/modules/modular_computers/os/subtypes/silicon.dm b/code/modules/modular_computers/os/subtypes/silicon.dm new file mode 100644 index 000000000000..06a7f0d58143 --- /dev/null +++ b/code/modules/modular_computers/os/subtypes/silicon.dm @@ -0,0 +1,44 @@ +/datum/extension/interactive/os/silicon + expected_type = /mob/living/silicon + +/datum/extension/interactive/os/silicon/update_host_icon() + return + +/datum/extension/interactive/os/silicon/get_hardware_flag() + return PROGRAM_CONSOLE + +/datum/extension/interactive/os/silicon/get_component(var/part_type) + var/mob/living/silicon/M = holder + return locate(part_type) in M.stock_parts + +/datum/extension/interactive/os/silicon/get_all_components() + var/mob/living/silicon/M = holder + return M.stock_parts.Copy() + +/datum/extension/interactive/os/silicon/emagged() + var/mob/living/silicon/robot/robot = holder + if(istype(robot)) + return robot.emagged + return FALSE + +/datum/extension/interactive/os/silicon/host_status() + var/mob/living/silicon/M = holder + return !M.stat + +// Hack to make status bar work + +/mob/living/silicon/initial_data() + . = ..() + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + . += os.get_header_data() + +/mob/living/silicon/check_eye() + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + return os.check_eye() + else + return ..() + +/datum/extension/interactive/os/silicon/small/get_hardware_flag() + return PROGRAM_TABLET diff --git a/code/modules/modular_computers/os/ui.dm b/code/modules/modular_computers/os/ui.dm new file mode 100644 index 000000000000..e619be1904ff --- /dev/null +++ b/code/modules/modular_computers/os/ui.dm @@ -0,0 +1,242 @@ + +// Operates NanoUI +/datum/extension/interactive/os/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!on || !host_status()) + if(ui) + ui.close() + return 0 + // If we have an active program switch to it now. + if(active_program) + if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now. + ui.close() + active_program.ui_interact(user) + return + + // We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it. + // This screen simply lists available programs and user may select them. + var/obj/item/stock_parts/computer/hard_drive/hard_drive = get_component(PART_HDD) + if(!hard_drive || !length(hard_drive.stored_files)) + show_error(user, "DISK ERROR") + return // No HDD, No HDD files list or no stored files. Something is very broken. + + var/datum/computer_file/data/autorun = get_file("autorun", "local") + + var/list/data = get_header_data() + + var/list/programs = list() + var/datum/computer_file/directory/program_files = hard_drive.parse_directory(OS_PROGRAMS_DIR, TRUE) + for(var/datum/computer_file/program/P in program_files.get_held_files()) + var/list/program = list() + program["name"] = P.filename + program["desc"] = P.filedesc + program["icon"] = P.program_menu_icon + program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 + if(P in running_programs) + program["running"] = 1 + programs.Add(list(program)) + data["programs"] = programs + + data["updating"] = updating + data["update_progress"] = update_progress + data["updates"] = updates + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "[os_name] Main Menu ", 400, 500) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/extension/interactive/os/extension_status(var/mob/user) + . = ..() + if(!on || !host_status()) + return STATUS_CLOSE + //There is no bypassing the update, mwhahaha + if(updating) + . = min(STATUS_UPDATE, .) + +/datum/extension/interactive/os/CanUseTopic(mob/user, state) + . = holder.CanUseTopic(user, state) + . = min(., extension_status(user)) + +// Handles user's GUI input +/datum/extension/interactive/os/extension_act(href, href_list, mob/user) + if( href_list["PC_exit"] ) + kill_program(active_program) + return TOPIC_HANDLED + if(href_list["PC_diagnostics"]) + var/obj/item/stock_parts/computer/H = locate(href_list["PC_diagnostics"]) in holder + var/list/diagnostics = list() + diagnostics += "[H] diagnostics:" + diagnostics |= H.diagnostics() + to_chat(user, SPAN_INFO(jointext(diagnostics, "\n"))) + return TOPIC_REFRESH + if(href_list["PC_enable_component"] ) + var/obj/item/stock_parts/computer/H = locate(href_list["PC_enable_component"]) in holder + if(H && istype(H) && !H.enabled) + H.enabled = 1 + H.on_enable(src) + return TOPIC_REFRESH + if(href_list["PC_disable_component"] ) + var/obj/item/stock_parts/computer/H = locate(href_list["PC_disable_component"]) in holder + if(H && istype(H) && H.enabled) + H.enabled = 0 + H.on_disable() + return TOPIC_REFRESH + if( href_list["PC_enable_update"] ) + receives_updates = TRUE + return TOPIC_REFRESH + if( href_list["PC_disable_update"] ) + receives_updates = FALSE + return TOPIC_REFRESH + if( href_list["PC_shutdown"] ) + system_shutdown() + return TOPIC_HANDLED + if( href_list["PC_minimize"] ) + minimize_program(user) + return TOPIC_HANDLED + + if( href_list["PC_killprogram"] ) + var/datum/computer_file/program/P = get_file(href_list["PC_killprogram"], programs_dir) + + if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) + return TOPIC_HANDLED + + kill_program(P) + update_uis() + to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") + return TOPIC_HANDLED + + if( href_list["PC_runprogram"] ) + run_program(href_list["PC_runprogram"]) + return TOPIC_HANDLED + + if( href_list["PC_setautorun"] ) + set_autorun(href_list["PC_setautorun"]) + return TOPIC_REFRESH + + if( href_list["PC_terminal"] ) + open_terminal(user) + return TOPIC_HANDLED + + if( href_list["PC_login"]) + login_prompt(user) + return TOPIC_REFRESH + + if( href_list["PC_logout"]) + logout_account(user) + return TOPIC_REFRESH + +/datum/extension/interactive/os/proc/regular_ui_update() + var/ui_update_needed = 0 + var/obj/item/stock_parts/computer/battery_module/battery_module = get_component(PART_BATTERY) + if(battery_module) + var/obj/item/cell/battery = battery_module.get_cell() + var/batery_percent = battery?.percent() + if(last_battery_percent != batery_percent) //Let's update UI on percent change + ui_update_needed = 1 + last_battery_percent = batery_percent + + if(stationtime2text() != last_world_time) + last_world_time = stationtime2text() + ui_update_needed = 1 + + var/list/current_header_icons = list() + for(var/datum/computer_file/program/P in running_programs) + if(!P.ui_header) + continue + current_header_icons[P.type] = P.ui_header + + if(!last_header_icons) + last_header_icons = current_header_icons + + else if(!listequal(last_header_icons, current_header_icons)) + last_header_icons = current_header_icons + ui_update_needed = 1 + else + for(var/x in last_header_icons|current_header_icons) + if(last_header_icons[x]!=current_header_icons[x]) + last_header_icons = current_header_icons + ui_update_needed = 1 + break + + if(ui_update_needed) + update_uis() + +/datum/extension/interactive/os/proc/update_uis() + if(active_program) //Should we update program ui or computer ui? + SSnano.update_uis(active_program) + if(active_program.NM) + SSnano.update_uis(active_program.NM) + +// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_" +/datum/extension/interactive/os/proc/get_header_data(file_browser = FALSE) + var/list/data = list() + var/obj/item/stock_parts/computer/battery_module/battery_module = get_component(PART_BATTERY) + var/obj/item/cell/battery = battery_module?.get_cell() + if(battery) + switch(battery.percent()) + if(80 to 200) // 100 should be maximal but just in case... + data["PC_batteryicon"] = "batt_100.gif" + if(60 to 80) + data["PC_batteryicon"] = "batt_80.gif" + if(40 to 60) + data["PC_batteryicon"] = "batt_60.gif" + if(20 to 40) + data["PC_batteryicon"] = "batt_40.gif" + if(5 to 20) + data["PC_batteryicon"] = "batt_20.gif" + else + data["PC_batteryicon"] = "batt_5.gif" + data["PC_batterypercent"] = "[round(battery.percent())] %" + data["PC_showbatteryicon"] = 1 + else + data["PC_batteryicon"] = "batt_5.gif" + data["PC_batterypercent"] = "N/C" + data["PC_showbatteryicon"] = battery_module ? 1 : 0 + + var/obj/item/stock_parts/computer/tesla_link/tesla_link = get_component(PART_TESLA) + if(tesla_link && tesla_link.enabled) + data["PC_apclinkicon"] = "charging.gif" + + var/obj/item/stock_parts/computer/network_card/network_card = get_component(PART_NETWORK) + if(network_card && network_card.is_banned()) + data["PC_ntneticon"] = "sig_warning.gif" + else + switch(get_network_status()) + if(0) + data["PC_ntneticon"] = "sig_none.gif" + if(1) + data["PC_ntneticon"] = "sig_low.gif" + if(2) + data["PC_ntneticon"] = "sig_high.gif" + if(3) + data["PC_ntneticon"] = "sig_lan.gif" + + var/list/program_headers = list() + for(var/datum/computer_file/program/P in running_programs) + if(!P.ui_header) + continue + program_headers.Add(list(list( + "icon" = P.ui_header + ))) + data["PC_programheaders"] = program_headers + + data["PC_stationtime"] = stationtime2text() + data["PC_hasheader"] = !updating + data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen + data["PC_showshutdown"] = !file_browser // Don't show shutdown/program closing options from file browser window + + var/datum/computer_file/data/account/cur_account = get_account_nocheck() + data["PC_loggedin"] = cur_account?.login + return data + +/datum/extension/interactive/os/initial_data() + return get_header_data() + +/datum/extension/interactive/os/update_layout() + return TRUE + +/datum/extension/interactive/os/nano_host() + return holder.nano_host() diff --git a/code/modules/modular_computers/os/visuals.dm b/code/modules/modular_computers/os/visuals.dm new file mode 100644 index 000000000000..7d03f0e75d56 --- /dev/null +++ b/code/modules/modular_computers/os/visuals.dm @@ -0,0 +1,60 @@ + +/datum/extension/interactive/os/proc/update_host_icon() + var/atom/A = holder + if(istype(A)) + A.update_icon() + +/datum/extension/interactive/os/proc/get_screen_icon_file() + if(istype(holder, /obj/item/modular_computer)) + var/obj/item/modular_computer/MC = holder + return MC.screen_icon || MC.icon + if(isatom(holder)) + var/atom/A = holder + return A.icon + +/datum/extension/interactive/os/proc/get_screen_overlay() + if(!on) + return image(screen_icon_file, screensaver_icon) + if(!screen_icon_file) + screen_icon_file = get_screen_icon_file() + if(screen_icon_file) + var/image/I + if(active_program) + if(active_program.program_icon_state in icon_states(screen_icon_file)) + I = image(screen_icon_file, active_program.program_icon_state) + else + I = image(screen_icon_file, default_icon) //Fallback icon + else + I = image(screen_icon_file, menu_icon) + I.appearance_flags |= RESET_COLOR + return I + return image(null) + +/datum/extension/interactive/os/proc/get_keyboard_overlay() + if(!on) + return + if(!screen_icon_file) + screen_icon_file = get_screen_icon_file() + if(screen_icon_file && active_program && active_program.program_key_state) + var/image/I = image(screen_icon_file, active_program.program_key_state) + I.appearance_flags |= RESET_COLOR + return I + return image(null) + +/datum/extension/interactive/os/proc/visible_error(message) + var/atom/A = holder + if(istype(A)) + A.visible_message("\The [A]'s screen displays an error: \"[message]\"", range = 1) + +/datum/extension/interactive/os/proc/visible_notification(message) + var/atom/A = holder + if(istype(A)) + A.visible_message("\The [A] screen displays a notification: \"[message]\"", range = 1) + +/datum/extension/interactive/os/proc/audible_notification(notification) + var/atom/A = holder + if(istype(A)) + playsound(A, notification, 5, falloff = 1) + +/datum/extension/interactive/os/proc/show_error(user, message) + to_chat(user, "[message]") diff --git a/code/modules/modular_computers/terminal/terminal.dm b/code/modules/modular_computers/terminal/terminal.dm index 268c0bd56307..02f13da48bc2 100644 --- a/code/modules/modular_computers/terminal/terminal.dm +++ b/code/modules/modular_computers/terminal/terminal.dm @@ -4,13 +4,25 @@ var/datum/browser/panel var/list/history = list() var/list/history_max_length = 20 - var/datum/extension/interactive/ntos/computer -/datum/terminal/New(mob/user, datum/extension/interactive/ntos/computer) + var/network_target // Network tag of whatever device is being targeted on the network by commands. + + // Terminal can act as a file transfer utility. + var/datum/file_storage/current_disk + var/datum/computer_file/directory/current_directory + + var/datum/file_transfer/current_move + + var/datum/extension/interactive/os/computer + var/list/disks = list() + +/datum/terminal/New(mob/user, datum/extension/interactive/os/computer) ..() src.computer = computer if(user && can_use(user)) show_terminal(user) + for(var/D in disks) + disks[D] = new D(computer) START_PROCESSING(SSprocessing, src) /datum/terminal/Destroy() @@ -18,6 +30,12 @@ if(computer && computer.terminals) computer.terminals -= src computer = null + current_disk = null + for(var/D in disks) + qdel(disks[D]) + disks = null + if(current_move) + qdel(current_move) if(panel) panel.close() QDEL_NULL(panel) @@ -26,18 +44,34 @@ /datum/terminal/proc/can_use(mob/user) if(!user) return FALSE - if(!CanInteractWith(user, computer, GLOB.default_state)) + if(!CanInteractWith(user, computer, global.default_topic_state)) return FALSE if(!computer || !computer.on) return FALSE return TRUE /datum/terminal/Process() + if(current_move) + var/result = current_move.update_progress() + if(result != OS_FILE_SUCCESS) + if(QDELETED(current_move)) + append_to_history("File Move Cancelled: Unknown error.") + else + append_to_history("File Move Cancelled: Unable to store '[current_move.transferring.filename]' at [current_move.transfer_to]") + QDEL_NULL(current_move) + return + if(current_move.left_to_transfer) + var/completion = round(1 - (current_move.left_to_transfer / current_move.transferring.size), 0.01) * 100 + append_to_history("File Move: [completion]% complete.") + else + append_to_history("File Move: Successfully [current_move.copying ? "copied" : "moved"] file '[current_move.transferring.filename]' to '[current_move.transfer_to.get_dir_path(current_move.directory_to, TRUE)]'.") + QDEL_NULL(current_move) + if(!can_use(get_user())) qdel(src) /datum/terminal/proc/command_by_name(name) - for(var/command in GLOB.terminal_commands) + for(var/command in get_terminal_commands()) var/datum/terminal_command/command_datum = command if(command_datum.name == name) return command @@ -53,7 +87,18 @@ /datum/terminal/proc/update_content() var/list/content = history.Copy() - content += "
    >
    " + var/account_name + // current_account will be reset on access check if account look up fails. + var/datum/extension/interactive/os/account_computer = get_account_computer() + if(account_computer.login && account_computer.current_account) + var/datum/computer_network/network = account_computer.get_network() + if(network) + account_name = "[account_computer.login]@[network.network_id]" + else + account_name = "LOCAL" + else + account_name = "GUEST" + content += "
    \>[account_name]:/[current_disk?.get_dir_path(current_directory, TRUE)]
    " content += "type `man` for a list of available commands." panel.set_content("[jointext(content, "
    ")]
    ") @@ -69,16 +114,22 @@ var/output = parse(input, usr) if(QDELETED(src)) // Check for exit. return 1 - history += output + append_to_history(output) + return 1 + +/datum/terminal/proc/append_to_history(var/text) + if(length(text)) + history += text if(length(history) > history_max_length) history.Cut(1, length(history) - history_max_length + 1) - update_content() - panel.update() - return 1 + update_content() + panel.update() /datum/terminal/proc/parse(text, mob/user) + if(current_move) + return "File transfer in progress." if(user.skill_check(SKILL_COMPUTER, SKILL_BASIC)) - for(var/datum/terminal_command/command in GLOB.terminal_commands) + for(var/datum/terminal_command/command in get_terminal_commands()) . = command.parse(text, user, src) if(!isnull(.)) return @@ -90,8 +141,129 @@ /datum/terminal/proc/skill_critical_fail(user) var/list/candidates = list() - for(var/datum/terminal_skill_fail/scf in GLOB.terminal_fails) + for(var/datum/terminal_skill_fail/scf in get_terminal_fails()) if(scf.can_run(user, src)) candidates[scf] = scf.weight var/datum/terminal_skill_fail/chosen = pickweight(candidates) return chosen.execute(src) + +// Returns the computer used for the terminal's account +/datum/terminal/proc/get_account_computer() + return computer + +/datum/terminal/proc/get_access(mob/user) + var/datum/extension/interactive/os/account_computer = get_account_computer() + return(account_computer.get_access(user)) + +// Returns list(/datum/file_storage, directory) on success. Returns error code on failure. +/datum/terminal/proc/parse_directory(directory_path, create_directories = FALSE) + var/datum/file_storage/target_disk = current_disk + var/datum/computer_file/directory/root_dir = current_directory + + if(!length(directory_path)) + return list(target_disk, root_dir) + + if(directory_path[1] == "/") // This is an absolute path, so we can pass it directly to the OS proc to be processed. + return computer.parse_directory(directory_path, create_directories) + + // Otherwise, we append the working directory path to the passed path. + var/list/directories = splittext(directory_path, "/") + + // When splitting the text, there could be blank strings at either end, so remove them. If there's any in the body of the path, there was a + // missed input, so leave them. + if(!length(directories[1])) + directories.Cut(1, 2) + if(!length(directories[directories.len])) + directories.Cut(directories.len) + + for(var/dir in directories) + if(dir == "..") // Up a directory. + if(root_dir) + root_dir = root_dir.get_directory() + directories.Cut(1, 2) + continue + if(target_disk) + target_disk = null + directories.Cut(1, 2) + continue + // We're trying to move up past the mounting points, return failure. + return OS_DIR_NOT_FOUND + + if(!target_disk) + target_disk = computer.mounted_storage[dir] + if(!target_disk) // Invalid disk entered. + return OS_DIR_NOT_FOUND + directories.Cut(1, 2) + + break // Any further use of ../ is handled by the hard drive. + + // If we were only pathing to the parent of a directory or to a disk, we can return early. + if(!length(directories)) + return list(target_disk, root_dir) + + // Assemble the final path from whatever root directory we're in, and the remaining entered paths. + // The hard drive handles the rest. + var/final_path = root_dir ? root_dir.get_file_path() + "/" : "" + final_path += jointext(directories, "/") + var/datum/computer_file/directory/target_directory = target_disk.parse_directory(final_path, create_directories) + if(!istype(target_directory)) + return OS_DIR_NOT_FOUND + + return list(target_disk, target_directory) + +// Returns list(/datum/file_storage, /datum/computer_file/directory, /datum/computer_file) on success. Returns error code on failure. +/datum/terminal/proc/parse_file(file_path) + if(!length(file_path)) + return OS_FILE_NOT_FOUND + if(file_path[1] == "/") // As above, this is an absolute path, which the OS can handle directly. + return computer.parse_file(file_path) + + var/list/dirs_and_file = splittext(file_path, "/") + if(!length(dirs_and_file)) + return OS_DIR_NOT_FOUND + + // Join together everything but the filename into a path. + var/list/file_loc = parse_directory(jointext(dirs_and_file, "/", 1, dirs_and_file.len)) + if(!islist(file_loc)) // Errored! + return file_loc + + var/datum/file_storage/target_disk = file_loc[1] + var/datum/computer_file/directory/target_dir = file_loc[2] + if(!istype(target_disk)) + return OS_DIR_NOT_FOUND + + var/filename = dirs_and_file[dirs_and_file.len] + var/datum/computer_file/target_file = target_disk.get_file(filename, target_dir) + if(!istype(target_file)) + return OS_FILE_NOT_FOUND + + return list(target_disk, target_dir, target_file) + +/proc/get_terminal_error(path, error_code) + var/list/dirs_and_file = splittext(path, "/") + var/dir_path = jointext(dirs_and_file, "/", 1, dirs_and_file.len) + if(!length(dirs_and_file)) + return "Unable to parse passed path." + var/filename = dirs_and_file[dirs_and_file.len] + + switch(error_code) + if(OS_FILE_NOT_FOUND) + return "Unable to locate the file[length(filename) ? "'[filename]'" : ""]" + if(OS_DIR_NOT_FOUND) + return "Unable to locate the directory[length(dir_path) ? "'[dir_path]'" : ""]" + if(OS_FILE_EXISTS) + return "A file with name '[filename]' already exists" + if(OS_BAD_NAME) + return "The file name '[filename]' is invalid" + if(OS_FILE_NO_READ) + return "You do not have permission to read the file[length(filename) ? "'[filename]'" : ""]" + if(OS_FILE_NO_WRITE) + return "You do not have permission to modify the file[length(filename) ? "'[filename]'" : ""]" + if(OS_HARDDRIVE_SPACE) + return "Insufficient harddrive space" + if(OS_HARDDRIVE_ERROR) + return "I/O error, Harddrive may be non-functional" + if(OS_NETWORK_ERROR) + return "Unable to connect to the network" + + return "An unspecified error occurred." \ No newline at end of file diff --git a/code/modules/modular_computers/terminal/terminal_commands.dm b/code/modules/modular_computers/terminal/terminal_commands.dm index 9cf58ba48e83..65240209931a 100644 --- a/code/modules/modular_computers/terminal/terminal_commands.dm +++ b/code/modules/modular_computers/terminal/terminal_commands.dm @@ -1,5 +1,9 @@ // To cut down on unneeded creation/deletion, these are global. -GLOBAL_LIST_INIT(terminal_commands, init_subtypes(/datum/terminal_command)) +var/global/list/terminal_commands +/proc/get_terminal_commands() + if(!global.terminal_commands) + global.terminal_commands = init_subtypes(/datum/terminal_command) + return global.terminal_commands /datum/terminal_command var/name // Used for man @@ -8,18 +12,19 @@ GLOBAL_LIST_INIT(terminal_commands, init_subtypes(/datum/terminal_command)) var/regex_flags // Used in the regex var/regex/regex // The actual regex, produced from above. var/core_skill = SKILL_COMPUTER // The skill which is checked - var/skill_needed = SKILL_EXPERT // How much skill the user needs to use this. This is not for critical failure effects at unskilled; those are handled globally. + var/skill_needed = SKILL_ADEPT // How much skill the user needs to use this. This is not for critical failure effects at unskilled; those are handled globally. var/req_access = list() // Stores access needed, if any var/needs_network // If this command fails if computer running terminal isn't connected to a network + var/needs_network_feature // Network feature flags which are required by this command. - var/global/regex/nid_regex // Regex for getting network addres out of the line + var/static/regex/nid_regex // Regex for getting network addres out of the line /datum/terminal_command/New() regex = new (pattern, regex_flags) ..() -/datum/terminal_command/proc/check_access(mob/user) - return has_access(req_access, user.GetAccess()) +/datum/terminal_command/proc/check_access(list/access) + return has_access(req_access, access) /datum/terminal_command/proc/get_nid(text) if(!nid_regex) @@ -27,16 +32,43 @@ GLOBAL_LIST_INIT(terminal_commands, init_subtypes(/datum/terminal_command)) if(nid_regex.Find(text)) return uppertext(nid_regex.match) +/datum/terminal_command/proc/get_arguments(text) + var/argtext = copytext(text, length(pattern) + 1) + + var/cur_string = "" + var/list/arguments = list() + + var/last_was_escape = FALSE + for(var/i in 1 to length(argtext)) // Allow players to escape spaces by using '\'. + var/char = argtext[i] + if(char == "\\") + last_was_escape = TRUE + continue + last_was_escape = FALSE + if(char == " ") + if(!last_was_escape) // Space wasn't escaped. + if(length(cur_string)) + arguments += cur_string + cur_string = "" + continue + cur_string += char + + if(length(cur_string)) + arguments += cur_string + return arguments + // null return: continue. "" return will break and show a blank line. Return list() to break and not show anything. /datum/terminal_command/proc/parse(text, mob/user, datum/terminal/terminal) if(!findtext(text, regex)) return if(!user.skill_check(core_skill, skill_needed)) return skill_fail_message() - if(!check_access(user)) + if(!check_access(terminal.get_access(user))) return "[name]: ACCESS DENIED" if(needs_network && !terminal.computer.get_network_status()) return "NETWORK ERROR: Check connection and try again." + if(needs_network_feature && !terminal.computer.get_network_status(needs_network_feature)) + return "NETWORK ERROR: Network rejected the use of this command on your current connection." return proper_input_entered(text, user, terminal) @@ -44,6 +76,18 @@ GLOBAL_LIST_INIT(terminal_commands, init_subtypes(/datum/terminal_command)) /datum/terminal_command/proc/proper_input_entered(text, mob/user, terminal) return list() +// Prints data out, split by page number. +/datum/terminal_command/proc/print_as_page(list/data, value_name, selected_page, pg_length) + . = list() + var/max_pages = ceil(length(data)/pg_length) + var/pg = clamp(selected_page, 1, max_pages) + + var/start_index = (pg - 1)*pg_length + 1 + var/end_index = min(length(data), pg*pg_length) + 1 + + . += data.Copy(start_index, end_index) + . += "[length(data)] [value_name]\s. Page [pg] / [max_pages]." + /datum/terminal_command/proc/skill_fail_message() var/message = pick(list( "Possible encoding mismatch detected.", @@ -58,7 +102,7 @@ Subtypes /datum/terminal_command/exit name = "exit" man_entry = list("Format: exit", "Exits terminal immediately.") - pattern = "^exit$" + pattern = @"^exit$" skill_needed = SKILL_BASIC /datum/terminal_command/exit/proper_input_entered(text, mob/user, terminal) @@ -67,29 +111,31 @@ Subtypes /datum/terminal_command/man name = "man" - man_entry = list("Format: man \[command\]", "Without command specified, shows list of available commands.", "With command, provides instructions on command use.") - pattern = "^man" + man_entry = list("Format: man \[pg number / command\]", "Without command specified, shows list of available commands, starting at the page number.", "With command, provides instructions on command use.") + pattern = @"^man" /datum/terminal_command/man/proper_input_entered(text, mob/user, datum/terminal/terminal) - if(text == "man") - . = list("The following commands are available.", "Some may require additional access.") - for(var/command in GLOB.terminal_commands) - var/datum/terminal_command/command_datum = command + var/list/manargs = get_arguments(text) + if(!length(manargs) || isnum(text2num(manargs[1]))) + var/selected_page = (length(manargs)) ? text2num(manargs[1]) : 1 + + var/list/valid_commands = list() + for(var/comm in get_terminal_commands()) + var/datum/terminal_command/command_datum = comm if(user.skill_check(command_datum.core_skill, command_datum.skill_needed)) - . += command_datum.name - return - if(length(text) < 5) - return "man: improper syntax. Use man \[command\]" - text = copytext(text, 5) - var/datum/terminal_command/command_datum = terminal.command_by_name(text) + valid_commands += command_datum.name + return print_as_page(valid_commands, "command", selected_page, terminal.history_max_length - 1) + + var/com_name = manargs[1] + var/datum/terminal_command/command_datum = terminal.command_by_name(com_name) if(!command_datum) - return "man: command '[text]' not found." + return "man: command '[com_name]' not found." return command_datum.man_entry /datum/terminal_command/ifconfig name = "ifconfig" man_entry = list("Format: ifconfig", "Returns network adaptor information.") - pattern = "^ifconfig$" + pattern = @"^ifconfig$" /datum/terminal_command/ifconfig/proper_input_entered(text, mob/user, datum/terminal/terminal) var/obj/item/stock_parts/computer/network_card/network_card = terminal.computer.get_component(PART_NETWORK) @@ -102,7 +148,7 @@ Subtypes /datum/terminal_command/hwinfo name = "hwinfo" man_entry = list("Format: hwinfo \[name\]", "If no slot specified, lists hardware.", "If slot is specified, runs diagnostic tests.") - pattern = "^hwinfo" + pattern = @"^hwinfo" /datum/terminal_command/hwinfo/proper_input_entered(text, mob/user, datum/terminal/terminal) if(text == "hwinfo") @@ -124,7 +170,7 @@ Subtypes /datum/terminal_command/banned name = "banned" man_entry = list("Format: banned", "Lists currently banned network ids.") - pattern = "^banned$" + pattern = @"^banned$" req_access = list(access_network) needs_network = TRUE @@ -137,7 +183,7 @@ Subtypes /datum/terminal_command/status name = "status" man_entry = list("Format: status", "Reports network status information.") - pattern = "^status$" + pattern = @"^status$" req_access = list(access_network) /datum/terminal_command/status/proper_input_entered(text, mob/user, datum/terminal/terminal) @@ -151,7 +197,7 @@ Subtypes /datum/terminal_command/locate name = "locate" man_entry = list("Format: locate nid", "Attempts to locate the device with the given nid by triangulating via relays.") - pattern = "locate" + pattern = @"locate" req_access = list(access_network) skill_needed = SKILL_PROF needs_network = TRUE @@ -161,20 +207,20 @@ Subtypes var/nid = get_nid(text) if(!nid) return - var/datum/extension/interactive/ntos/origin = terminal.computer + var/datum/extension/interactive/os/origin = terminal.computer if(!origin || !origin.get_network_status()) return var/datum/computer_network/network = origin.get_network() - var/datum/extension/interactive/ntos/comp = network.get_os_by_nid(nid) + var/datum/extension/interactive/os/comp = network.get_os_by_nid(nid) if(!comp || !comp.host_status() || !comp.get_network_status()) return var/area/A = get_area(comp.get_physical_host()) - return "... Estimating location: \the [A.name]" + return "... Estimating location: \the [A.proper_name]" /datum/terminal_command/ping name = "ping" man_entry = list("Format: ping nid", "Checks connection to the given nid.") - pattern = "^ping" + pattern = @"^ping" req_access = list(access_network) needs_network = TRUE @@ -184,12 +230,12 @@ Subtypes if(!nid) . += "ping: Improper syntax. Use ping nid." return - var/datum/extension/interactive/ntos/origin = terminal.computer + var/datum/extension/interactive/os/origin = terminal.computer if(!origin || !origin.get_network_status()) . += "failed. Check network status." return var/datum/computer_network/network = terminal.computer.get_network() - var/datum/extension/interactive/ntos/comp = network.get_os_by_nid(nid) + var/datum/extension/interactive/os/comp = network.get_os_by_nid(nid) if(!comp || !comp.host_status() || !comp.get_network_status()) . += "failed. Target device not responding." return @@ -198,7 +244,7 @@ Subtypes /datum/terminal_command/ssh name = "ssh" man_entry = list("Format: ssh nid", "Opens a remote terminal at the location of nid, if a valid device nid is specified.") - pattern = "^ssh" + pattern = @"^ssh" req_access = list(access_network) needs_network = TRUE @@ -207,12 +253,12 @@ Subtypes return "ssh is not supported on remote terminals." if(length(text) < 5) return "ssh: Improper syntax. Use ssh nid." - var/datum/extension/interactive/ntos/origin = terminal.computer + var/datum/extension/interactive/os/origin = terminal.computer if(!origin || !origin.get_network_status()) return "ssh: Check network connectivity." var/nid = text2num(copytext(text, 5)) var/datum/computer_network/network = terminal.computer.get_network() - var/datum/extension/interactive/ntos/comp = network.get_os_by_nid(nid) + var/datum/extension/interactive/os/comp = network.get_os_by_nid(nid) if(comp == origin) return "ssh: Error; can not open remote terminal to self." if(!comp || !comp.host_status() || !comp.get_network_status()) @@ -223,3 +269,563 @@ Subtypes LAZYADD(comp.terminals, new_term) LAZYADD(origin.terminals, new_term) return "ssh: Connection established." + +/datum/terminal_command/cd + name = "cd" + man_entry = list("Format: cd \[path\]", "Changes the current working directory.", "Both relative and absolute paths are supported.") + pattern = @"^cd" + +/datum/terminal_command/cd/proper_input_entered(text, mob/user, datum/terminal/terminal) + if(length(text) < 4) + return "cd: Improper syntax, use cd \[target\]." + + var/list/cd_args = get_arguments(text) + + var/target_directory = cd_args[1] + + var/list/cd_targets = terminal.parse_directory(target_directory) + if(!islist(cd_targets)) + return "cd: [get_terminal_error(target_directory, cd_targets)]." + + terminal.current_disk = cd_targets[1] + terminal.current_directory = cd_targets[2] + return "" + +/datum/terminal_command/ls + name = "ls" + man_entry = list("Format: ls \[pg number\]", "Lists the files in the working directory, starting from the page number.") + pattern = @"^ls" + +/datum/terminal_command/ls/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/ls_args = get_arguments(text) + + var/selected_page = (length(ls_args)) ? text2num(ls_args[1]) : 1 + if(!isnum(selected_page)) + return "ls: Improper syntax, use format ls \[page number\]." + + if(!terminal.current_disk) + return print_as_page(terminal.computer.mounted_storage, "disk", selected_page, terminal.history_max_length - 1) + var/list/files = terminal.current_disk.get_dir_files(terminal.current_directory) + var/list/file_data = list() + for(var/datum/computer_file/F in files) + if(istype(F, /datum/computer_file/directory)) + file_data += "[F.filename] - DIR" + else + file_data += "[F.filename].[F.filetype] - [F.size] GQ" + + return print_as_page(file_data, "file", selected_page, terminal.history_max_length - 1) + +/datum/terminal_command/remove + name = "rm" + man_entry = list("Format: rm \[file path\]", "Removes the file with the given path.") + pattern = @"^rm\b" + +/datum/terminal_command/remove/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/file_path = copytext(text, 4) + var/list/file_loc = terminal.parse_file(file_path) + // Errored! + if(!islist(file_loc)) + return "rm: [get_terminal_error(file_path, file_loc)]." + + var/datum/file_storage/disk = file_loc[1] + var/datum/computer_file/file = file_loc[3] + var/deleted = disk.delete_file(file, terminal.get_access(user), user) + if(deleted == OS_FILE_SUCCESS) + return "rm: Removed file '[file.filename]'." + if(deleted == OS_FILE_NO_WRITE) + return "rm: You do not have permission to remove file '[file.filename]'." + // Other error. Most likely, the hard drive is non-functional. + return "rm: Failed to delete file '[file.filename]'. Hard drive may be non-functional." +/datum/terminal_command/move + name = "mv" + man_entry = list("Format: mv \[file path\] \[destination\] \[copying (0/1) \]", "Moves a file to another directory.") + pattern = @"^mv" + +/datum/terminal_command/move/proper_input_entered(text, mob/user, datum/terminal/terminal) + if(!terminal.current_disk) + return "mv: No disk selected." + + var/list/mv_args = get_arguments(text) + if(length(mv_args) < 2) + return "mv: Improper syntax, use mv \[file path\] \[destination\] \[copying (0/1) \]." + var/source_path = mv_args[1] + var/list/file_loc = terminal.parse_file(source_path) + if(!islist(file_loc)) // Errored! + return "mv: [get_terminal_error(source_path, file_loc)]." + + var/datum/computer_file/F = file_loc[3] + var/copying = length(mv_args) > 2 ? text2num(mv_args[3]) : FALSE + // Find the destination. + var/target_path = mv_args[2] + + var/list/destination = terminal.parse_directory(target_path) + if(!islist(destination)) + return "mv: [get_terminal_error(target_path, file_loc)]." + + // Check file permisisons. + var/error = check_file_transfer(destination[2], F, copying, terminal.get_access(user), user) + if(error) + return "mv: [error]." + + terminal.current_move = new(file_loc[1], destination[1], destination[2], F, copying) + return "mv: Beginning file move..." + +/datum/terminal_command/copy + name = "cp" + man_entry = list("Format: cp \[file path\]", "Copies the file with the given path.") + pattern = @"^cp" + +/datum/terminal_command/copy/proper_input_entered(text, mob/user, datum/terminal/terminal) + if(!terminal.current_disk) + return "cp: No disk selected." + + if(length(text) < 4) + return "cp: Improper syntax, use copy \[file path\]." + + var/file_path = copytext(text, 4) + var/list/file_loc = terminal.parse_file(file_path) + // Errored! + if(!islist(file_loc)) + var/list/dirs_and_file = splittext(file_path, "/") + var/dir_path = jointext(dirs_and_file, "/", 1, dirs_and_file.len) + var/filename = dirs_and_file[dirs_and_file.len] + return "cp: [get_terminal_error(filename, dir_path, file_loc)]." + + var/datum/file_storage/disk = file_loc[1] + var/datum/computer_file/file = file_loc[3] + + var/datum/computer_file/copy = file.Clone(TRUE) + if(!istype(copy)) + return + var/success = disk.store_file(copy, file_loc[2], FALSE, terminal.get_access(user), user) + if(success == OS_FILE_SUCCESS) + return "cp: Successfully copied file [file.filename]." + + return "cp: [get_terminal_error(file_path, success)]." + +/datum/terminal_command/rename + name = "rename" + man_entry = list("Format: rename \[file path\] \[new name\]", "Renames a file with the given path.") + pattern = @"^rename" + +/datum/terminal_command/rename/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/rename_args = get_arguments(text) + if(length(rename_args) < 2) + return "rename: Improper syntax, use rename \[file name\] \[new name\]." + var/file_path = rename_args[1] + var/list/file_loc = terminal.parse_file(file_path) + // Errored! + if(!islist(file_loc)) + return "rename: [get_terminal_error(file_path, file_loc)]." + + var/datum/file_storage/disk = file_loc[1] + var/datum/computer_file/F = file_loc[3] + var/new_name = sanitize_for_file(rename_args[2]) + + if(length(new_name)) + if(F.unrenamable || !(F.get_file_perms(terminal.get_access(user), user) & OS_WRITE_ACCESS)) + return "rename: You lack permission to rename [F.filename]." + if(disk.rename_file(F, new_name, user)) + return "rename: File renamed to '[new_name]'." + else + return "rename: Unable to rename file." + else + return "rename: Invalid file name." + +/datum/terminal_command/mkdir + name = "mkdir" + man_entry = list("Format: mkdir \[dir path\]", "Creates a directory with the given path.") + pattern = @"^mkdir" + +/datum/terminal_command/mkdir/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/mkdir_args = get_arguments(text) + if(!length(mkdir_args)) + return "mv: Improper syntax, use mkdir \[dir path\]." + var/list/file_loc = terminal.parse_directory(mkdir_args[1], TRUE) + if(!islist(file_loc) || (length(file_loc) > 1 && file_loc[2] == null)) // Don't return the error directly since we're attempting to create a directory, not just parse one. + return "mkdir: Unable to create directory '[mkdir_args[1]]'." + + var/datum/computer_file/directory/created_dir = file_loc[2] + return "mkdir: Successfully created directory '[created_dir.get_file_path()]'." + +/datum/terminal_command/target + name = "target" + man_entry = list("Format: target \[network tag\]", "Gets or sets the target network tag for terminal commands.") + pattern = @"^target" + +/datum/terminal_command/target/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/target_args = get_arguments(text) + if(!length(target_args)) + return "target: The current target network tag is [terminal.network_target]." + + terminal.network_target = uppertext(target_args[1]) + return "target: Changed network target to [terminal.network_target]." + +/datum/terminal_command/login + name = "login" + man_entry = list("Format: login \[account login\] \[account password\]", "Logs in to the given user account.") + pattern = @"^login" + needs_network = TRUE + +/datum/terminal_command/login/proper_input_entered(text, mob/user, datum/terminal/terminal) + + var/list/login_args = get_arguments(text) + + if(length(login_args) < 2) + return "login: Improper syntax, use login \[account login\] \[account password\]." + + var/datum/extension/interactive/os/account_computer = terminal.get_account_computer() + var/login_success = account_computer.login_account(login_args[1], login_args[2]) + if(login_success) + return "login: Login successful. Welcome [login_args[1]]!" + return "login: Could not log in to account [login_args[1]]. Check password or network connectivity." + +/datum/terminal_command/logout + name = "logout" + man_entry = list("Format: logout", "Logs out of the current user account.") + pattern = @"^logout" + needs_network = TRUE + +/datum/terminal_command/logout/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/datum/extension/interactive/os/account_computer = terminal.get_account_computer() + account_computer.logout_account() + return "logout: Log out successful." + +/datum/terminal_command/permmod + name = "permmod" + man_entry = list("Format: permmod \[file path\] \[access key\] \[permission mod flags\]", "Modifies or lists the permissions of the given file. Do not pass an access key to list permissions.", + "Supported flags are as follows:", + "'+/-' - Add or Remove access requirement", + "'r/w/m' - Target read/write/modification access", + "'u/g' - Add group or individual user access requirement", + "For example, the command 'permmod TestFile bronte.lowe +ru' would add bronte.lowe to the read permissions list of the file TestFile." + ) // TODO: Add an actual flags option for terminal commands in addition to arguments + pattern = @"^permmod" + needs_network = TRUE + +/datum/terminal_command/permmod/proper_input_entered(text, mob/user, datum/terminal/terminal) + + if(!terminal.current_disk) + return "permmod: No disk selected." + + var/list/permmod_args = get_arguments(text) + if(!length(permmod_args)) + return "permmod: Improper syntax, use permmod \[file path\] \[access key\] \[permission mod flags\]." + + var/file_path = permmod_args[1] + var/list/file_loc = terminal.parse_file(file_path) + if(!islist(file_loc)) + return "permmod: [get_terminal_error(file_path, file_loc)]." + + var/datum/computer_file/F = file_loc[3] + + if(length(permmod_args) < 3) + return F.get_perms_readable() + + var/flags = permmod_args[3] + var/mode + var/access_key + var/perm + if(findtext(flags, "-")) + mode = "-" + else if(findtext(flags, "+")) + mode = "+" + if(!mode) + return "permmod: Invalid flag syntax. Use man command to learn more about permmod flag syntax." + + if(findtext(flags, "r")) + perm = OS_READ_ACCESS + else if(findtext(flags, "w")) + perm = OS_WRITE_ACCESS + else if(findtext(flags, "m")) + perm = OS_MOD_ACCESS + else + return "permmod: Invalid flag syntax. Use man command to learn more about permmod flag syntax." + var/datum/computer_network/network = terminal.computer.get_network() + if(findtext(flags, "u")) + var/account_login = permmod_args[2] + if(!network.find_account_by_login(account_login)) + return "permmod: No user account with login '[account_login]' found." + access_key = "[account_login]@[network.network_id]" + else if(findtext(flags, "g")) + var/group_name = permmod_args[2] + var/datum/extension/network_device/acl/acl = network.access_controller + if(!istype(acl)) + return "permmod: No active ACL could be located on the network." + if(!(group_name in acl.get_all_groups())) + return "permmod: No group with name '[group_name]' found." + access_key = "[group_name].[network.network_id]" + else + return "permmod: Invalid flag syntax. Use man command to learn more about permmod flag syntax." + + var/success = F.change_perms(mode, perm, access_key, terminal.get_access(user)) + if(success) + return "permmod: Successfully changed permissions for [F.filename]." + else + return "permmod: Could not change permissions for [F.filename]. You may lack permission modification access." + +// Terminal commands for passing information to public variables and methods follows +/datum/terminal_command/com + name = "com" + man_entry = list("Format: com \[alias\] \[value\]", "Calls a command on the current network target for modifying variables or calling methods.") + pattern = @"^com" + needs_network = TRUE + needs_network_feature = NET_FEATURE_SYSTEMCONTROL + +/datum/terminal_command/com/proper_input_entered(text, mob/user, datum/terminal/terminal) + // If the user is unskilled, call a random method + if(!user.skill_check(core_skill, SKILL_EXPERT)) + var/target_tag = terminal.network_target + if(!target_tag) + return "com: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "com: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "com: Target device cannot receive commmands." + + return D.random_method(user) + + var/list/com_args = get_arguments(text) + if(!length(com_args)) + return "com: Improper syntax, use com \[variable\] \[value\]." + + var/target_tag = terminal.network_target + if(!target_tag) + return "com: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "com: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "com: Target device cannot receive commmands." + + var/called_args + if(length(com_args) > 2) + called_args = com_args.Copy(2) + else if(length(com_args) == 2) + called_args = com_args[2] + + return D.on_command(com_args[1], called_args, terminal.get_access(user)) + +// Lists the commands available on the target device. +/datum/terminal_command/listcom + name = "listcom" + man_entry = list("Format: listcom \[pg number / command\]", "Lists commands available on the current network target.", "If a command is given as an argument, provides information about that command.") + pattern = @"^listcom" + needs_network = TRUE + skill_needed = SKILL_EXPERT + needs_network_feature = NET_FEATURE_SYSTEMCONTROL + +/datum/terminal_command/listcom/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/target_tag = terminal.network_target + if(!target_tag) + return "listcom: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "listcom: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "listcom: Target device cannot receive commmands." + + var/list/listcom_args = get_arguments(text) + if(!length(listcom_args) || isnum(text2num(listcom_args[1]))) + . = list() + var/selected_page = (length(listcom_args)) ? text2num(listcom_args[1]) : 1 + + var/list/valid_commands = list() + for(var/alias in D.command_and_call) + valid_commands += "Method - [alias]" + for(var/alias in D.command_and_write) + valid_commands += "Variable - [alias]" + + return print_as_page(valid_commands, "command", selected_page, terminal.history_max_length - 1) + + var/selected_alias = listcom_args[1] + var/decl/public_access/selected_ref = D.command_and_call[selected_alias] || D.command_and_write[selected_alias] + if(selected_alias in D.command_and_call) + selected_ref = D.command_and_call[selected_alias] + else if(selected_alias in D.command_and_write) + selected_ref = D.command_and_write[selected_alias] + else + return "listcom: No command with alias '[selected_alias]' found." + + . = list() + . += "[selected_ref.name]: [selected_ref.desc]" + if(istype(selected_ref, /decl/public_access/public_variable)) + var/decl/public_access/public_variable/pub_var = selected_ref + . += "Var Type: [pub_var.var_type]" + . += "Writable: [pub_var.can_write ? "TRUE" : "FALSE"]" + else if(istype(selected_ref, /decl/public_access/public_method)) + var/decl/public_access/public_method/pub_method = selected_ref + . += "Has Arguments: [pub_method.forward_args ? "TRUE" : "FALSE"]" + +// Adds a command attached to a random reference, either a variable or a method. +/datum/terminal_command/addcom + name = "addcom" + man_entry = list("Format: addcom \[type\] \[alias\]", "Adds a command on the current network target. Accepts types 'METHOD' or 'VARIABLE'") + pattern = @"^addcom" + needs_network = TRUE + skill_needed = SKILL_EXPERT + needs_network_feature = NET_FEATURE_SYSTEMCONTROL + +/datum/terminal_command/addcom/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/addcom_args = get_arguments(text) + if(!length(addcom_args)) + return "addcom: Improper syntax, use addcom \[type\] \[alias\]. Accepts types 'METHOD' or 'VARIABLE'" + + var/target_tag = terminal.network_target + if(!target_tag) + return "addcom: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "addcom: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "addcom: Target device cannot receive commmands." + + var/alias = (length(addcom_args) >= 2) ? addcom_args[2] : 0 + if(addcom_args[1] == "METHOD") + alias = D.add_command(D.command_and_call, alias, D.get_public_methods()) + else if(addcom_args[1] == "VARIABLE") + alias = D.add_command(D.command_and_write, alias, D.get_public_variables()) + else + return "addcom: Improper syntax, use addcom \[type\] \[alias\]. Accepts types 'METHOD' or 'VARIABLE'" + return "addcom: Added '[addcom_args[1]]' command with alias [alias]" + +/datum/terminal_command/modcom + name = "modcom" + man_entry = list("Format: modcom \[alias\] \[index\]", "Modifies a command on the current network target. Leave index blank to return a list of possible references") + pattern = @"^modcom" + needs_network = TRUE + skill_needed = SKILL_PROF // addcom only adds a randomly chosen command to the device - you need to be significantly more skilled to select a specific one remotely. + needs_network_feature = NET_FEATURE_SYSTEMCONTROL + +/datum/terminal_command/modcom/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/modcom_args = get_arguments(text) + if(!length(modcom_args)) + return "modcom: Improper syntax, use modcom \[alias\] \[index\].'" + + var/target_tag = terminal.network_target + if(!target_tag) + return "modcom: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "modcom: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "modcom: Target device cannot receive commmands." + + var/alias = modcom_args[1] + var/list/valid_commands = list() + var/list/device_command_list + // Find the valid methods or variables this command can reference + if(alias in D.command_and_call) + device_command_list = D.command_and_call + valid_commands = D.get_public_methods() + else if(alias in D.command_and_write) + device_command_list = D.command_and_write + valid_commands = D.get_public_variables() + else + return "modcom: No command with [alias] found." + + var/selected_index = (length(modcom_args) >= 2) ? modcom_args[2] : null + + // If there is no given index, return a list of available indexes. + if(!selected_index) + var/list/options = list() + var/index = 1 + options += "Index - Reference." + for(var/path in valid_commands) + var/decl/public_access/reference = valid_commands[path] + options += "([index] - [reference.name])" + index++ + return options + + selected_index = text2num(selected_index) + if(selected_index > length(valid_commands)) + return "modcom: Invalid index." + var/selected_path = valid_commands[selected_index] + var/decl/public_access/selected_reference = valid_commands[selected_path] + + D.set_command_reference(device_command_list, alias, selected_reference) + + return "modcom: Set command with alias '[alias]' to reference '[selected_reference.name]'" + +/datum/terminal_command/namecom + name = "namecom" + man_entry = list("Format: namecom \[old alias\] \[new alias\]", "Renames a command with the given alias on the current network target.") + pattern = @"^namecom" + needs_network = TRUE + skill_needed = SKILL_EXPERT + needs_network_feature = NET_FEATURE_SYSTEMCONTROL + +/datum/terminal_command/namecom/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/namecom_args = get_arguments(text) + if(length(namecom_args) < 2) + return "namecom: Improper syntax, use namecom \[old alias\] \[new alias\]." + + var/target_tag = terminal.network_target + if(!target_tag) + return "namecom: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "namecom: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "namecom: Target device cannot receive commmands." + + if(D.change_command_alias(namecom_args[1], namecom_args[2])) + return "namecom: Changed alias '[namecom_args[1]]' to '[namecom_args[2]]'" + else + return "namecom: Failed to change alias, '[namecom_args[2]]' already in use." + +/datum/terminal_command/rmcom + name = "rmcom" + man_entry = list("Format: rmcom \[alias\]", "Removes a command with the given alias on the current network target.") + pattern = @"^rmcom" + needs_network = TRUE + skill_needed = SKILL_EXPERT + needs_network_feature = NET_FEATURE_SYSTEMCONTROL + +/datum/terminal_command/rmcom/proper_input_entered(text, mob/user, datum/terminal/terminal) + var/list/rmcom_args = get_arguments(text) + if(!length(rmcom_args)) + return "rmcom: Improper syntax, use rmcom \[alias\]." + + var/target_tag = terminal.network_target + if(!target_tag) + return "rmcom: No network target set. Use 'target' to set a network target." + + var/datum/computer_network/network = terminal.computer.get_network() + var/datum/extension/network_device/D = network.get_device_by_tag(target_tag) + + if(!istype(D)) + return "rmcom: Could not find target device with network tag [target_tag]." + + if(!D.has_commands) + return "rmcom: Target device cannot receive commmands." + + if(D.remove_command(rmcom_args[1])) + return "rmcom: Removed command with alias '[rmcom_args[1]]' from target device." + else + return "rmcom: No command with alias '[rmcom_args[1]]' found on target device." \ No newline at end of file diff --git a/code/modules/modular_computers/terminal/terminal_remote.dm b/code/modules/modular_computers/terminal/terminal_remote.dm index 330defa6d56b..e74f04f7191b 100644 --- a/code/modules/modular_computers/terminal/terminal_remote.dm +++ b/code/modules/modular_computers/terminal/terminal_remote.dm @@ -1,9 +1,9 @@ // The computer var is for the remote computer with these. /datum/terminal/remote name = "Remote Terminal" - var/datum/extension/interactive/ntos/origin_computer + var/datum/extension/interactive/os/origin_computer -/datum/terminal/remote/New(mob/user, datum/extension/interactive/ntos/computer, datum/extension/interactive/ntos/origin) +/datum/terminal/remote/New(mob/user, datum/extension/interactive/os/computer, datum/extension/interactive/os/origin) origin_computer = origin ..(user, computer) @@ -19,10 +19,13 @@ if(!computer || !computer.on || !origin_computer || !origin_computer.on) return FALSE - if(!CanInteractWith(user, origin_computer, GLOB.default_state)) + if(!CanInteractWith(user, origin_computer, global.default_topic_state)) return FALSE if(!origin_computer.get_network_status() || !computer.get_network_status()) return FALSE - return TRUE \ No newline at end of file + return TRUE + +/datum/terminal/remote/get_account_computer() + return origin_computer \ No newline at end of file diff --git a/code/modules/modular_computers/terminal/terminal_skill_fail.dm b/code/modules/modular_computers/terminal/terminal_skill_fail.dm index 0f213da3b079..64778fe6b2f1 100644 --- a/code/modules/modular_computers/terminal/terminal_skill_fail.dm +++ b/code/modules/modular_computers/terminal/terminal_skill_fail.dm @@ -1,6 +1,10 @@ -GLOBAL_LIST_INIT(terminal_fails, init_subtypes(/datum/terminal_skill_fail)) +var/global/list/terminal_fails +/proc/get_terminal_fails() + if(!global.terminal_fails) + global.terminal_fails = init_subtypes(/datum/terminal_skill_fail) + return global.terminal_fails -/datum/terminal_skill_fail/ +/datum/terminal_skill_fail var/weight = 1 var/message @@ -37,13 +41,15 @@ GLOBAL_LIST_INIT(terminal_fails, init_subtypes(/datum/terminal_skill_fail)) var/fulldata = "" for(var/datum/computer_file/data/L in logs) fulldata += L.generate_file_data() - var/datum/computer_file/data/email_account/server = network.find_email_by_name(EMAIL_DOCUMENTS) - for(var/datum/computer_file/data/email_account/email in network.get_email_addresses()) + var/datum/computer_file/data/account/server = network.find_account_by_login(EMAIL_DOCUMENTS) + if(!server) + return + for(var/datum/computer_file/data/account/email in network.get_accounts_unsorted()) if(!email.can_login || email.suspended) continue var/datum/computer_file/data/email_message/message = new() message.title = "IMPORTANT NETWORK ALERT!" message.stored_data = fulldata message.source = server.login - server.send_mail(email.login, message, network) + network.send_email(server, email.login, message) return ..() \ No newline at end of file diff --git a/code/modules/multiz/_stubs.dm b/code/modules/multiz/_stubs.dm deleted file mode 100644 index 26b21b09531d..000000000000 --- a/code/modules/multiz/_stubs.dm +++ /dev/null @@ -1,7 +0,0 @@ -/obj/effect/landmark/map_data - name = "Map Data" - desc = "An unknown location." - invisibility = 101 - - var/height = 1 ///< The number of Z-Levels in the map. - var/turf/edge_type ///< What the map edge should be formed with. (null = world.turf) \ No newline at end of file diff --git a/code/modules/multiz/basic.dm b/code/modules/multiz/basic.dm index 37b755bba08a..c6bf8e48ba8d 100644 --- a/code/modules/multiz/basic.dm +++ b/code/modules/multiz/basic.dm @@ -1,67 +1,58 @@ // If you add a more comprehensive system, just untick this file. -var/list/z_levels = list()// Each bit re... haha just kidding this is a list of bools now +var/global/list/z_levels = list() // Each Z-level is associated with the relevant map data landmark -// If the height is more than 1, we mark all contained levels as connected. -// This is in New because it is an auxiliary effect specifically needed pre-init. -/obj/effect/landmark/map_data/New(turf/loc, _height) - ..() - if(!istype(loc)) // Using loc.z is safer when using the maploader and New. - return - if(_height) - height = _height - for(var/i = (loc.z - height + 1) to (loc.z-1)) - if (z_levels.len 0 && z_levels.len >= z ? z_levels[z] : null // Thankfully, no bitwise magic is needed here. /proc/GetAbove(var/atom/atom) + RETURN_TYPE(/turf) var/turf/turf = get_turf(atom) if(!turf) return null return HasAbove(turf.z) ? get_step(turf, UP) : null /proc/GetBelow(var/atom/atom) + RETURN_TYPE(/turf) var/turf/turf = get_turf(atom) if(!turf) return null return HasBelow(turf.z) ? get_step(turf, DOWN) : null -/proc/GetConnectedZlevels(z) - . = list(z) - for(var/level = z, HasBelow(level), level--) - . |= level-1 - for(var/level = z, HasAbove(level), level++) - . |= level+1 - -var/list/connected_z_cache = list() -/proc/AreConnectedZLevels(var/zA, var/zB) - if (zA <= 0 || zB <= 0 || zA > world.maxz || zB > world.maxz) - return FALSE - if (zA == zB) - return TRUE - if (global.connected_z_cache.len >= zA && global.connected_z_cache[zA]) - return global.connected_z_cache[zA][zB] - var/list/levels = GetConnectedZlevels(zA) - var/list/new_entry = new(world.maxz) - for (var/entry in levels) - new_entry[entry] = TRUE - if (global.connected_z_cache.len < zA) - global.connected_z_cache.len = zA - global.connected_z_cache[zA] = new_entry - return new_entry[zB] - /proc/get_zstep(ref, dir) if(dir == UP) . = GetAbove(ref) else if (dir == DOWN) . = GetBelow(ref) else - . = get_step(ref, dir) \ No newline at end of file + . = get_step(ref, dir) + +/proc/get_zstep_resolving_mimic(ref, dir) + if(dir == UP) + . = GetAbove(ref)?.resolve_to_actual_turf() + else if (dir == DOWN) + . = GetBelow(ref)?.resolve_to_actual_turf() + else + . = get_step_resolving_mimic(ref, dir) + +/proc/get_dir_multiz(turf/us, turf/them) + if(!us || !them) + return 0 + if(us.z == them.z) + return get_dir(us, them) + else + var/dir = 0 + if(them.z > us.z) + var/turf/T = GET_ABOVE(us) + if(T && (T.z == them.z)) + dir = UP + else + return get_dir(us, them) + else + var/turf/T = GET_BELOW(us) + if(T && (T.z == them.z)) + dir = DOWN + else + return get_dir(us, them) + + return (dir | get_dir(us, them)) \ No newline at end of file diff --git a/code/modules/multiz/disabled.dm b/code/modules/multiz/disabled.dm deleted file mode 100644 index d1571af37c68..000000000000 --- a/code/modules/multiz/disabled.dm +++ /dev/null @@ -1,11 +0,0 @@ -GLOBAL_VAR_CONST(HIGHEST_CONNECTABLE_ZLEVEL_INDEX, 0) - -proc/HasAbove(var/z) - return 0 -proc/HasBelow(var/z) - return 0 -// These give either the turf or null. -proc/GetAbove(var/turf/turf) - return null -proc/GetBelow(var/turf/turf) - return null \ No newline at end of file diff --git a/code/modules/multiz/hoist.dm b/code/modules/multiz/hoist.dm index d6983dac4536..6a3c80e71fec 100644 --- a/code/modules/multiz/hoist.dm +++ b/code/modules/multiz/hoist.dm @@ -10,6 +10,10 @@ icon = 'icons/obj/hoists.dmi' icon_state = "hoist_case" + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + + /obj/item/hoist_kit/attack_self(mob/user) if (!do_after(usr, (2 SECONDS), src)) return @@ -33,74 +37,76 @@ var/obj/structure/hoist/source_hoist -/obj/effect/hoist_hook/attack_hand(mob/living/user) - return // no, bad - -/obj/effect/hoist_hook/MouseDrop_T(atom/movable/AM,mob/user) - if (issilicon(user)) - return - - if (!AM.simulated || AM.anchored) - to_chat(user, SPAN_WARNING("You can't do that with \the [AM].")) - return - if (source_hoist.hoistee) - to_chat(user, SPAN_NOTICE("\The [source_hoist.hoistee] is already attached to \the [src]!")) - return - source_hoist.attach_hoistee(AM) - user.visible_message( - SPAN_NOTICE("[user] attaches \the [AM] to \the [src]."), - SPAN_NOTICE("You attach \the [AM] to \the [src]."), - "You hear something clamp into place.") - -/obj/structure/hoist/proc/attach_hoistee(atom/movable/AM) - hoistee = AM - if(ismob(AM)) - source_hook.buckle_mob(AM) - AM.anchored = TRUE // why isn't this being set by buckle_mob for silicons? - source_hook.layer = AM.layer + 0.1 - if (get_turf(AM) != get_turf(source_hook)) - AM.forceMove(get_turf(source_hook)) - - GLOB.destroyed_event.register(AM, src, .proc/release_hoistee) - -/obj/effect/hoist_hook/MouseDrop(atom/dest) - ..() - if(!Adjacent(usr) || !dest.Adjacent(usr)) return // carried over from the default proc - - if (!ishuman(usr)) - return - - if (usr.incapacitated()) - to_chat(usr, SPAN_WARNING("You can't do that while incapacitated.")) - return +/obj/effect/hoist_hook/attack_hand(mob/user) + if(user.incapacitated() || !user.check_dexterity(DEXTERITY_HOLD_ITEM) || !source_hoist?.hoistee) + return ..() + source_hoist.check_consistency() + source_hoist.hoistee.forceMove(get_turf(src)) + user.visible_message(SPAN_NOTICE("[user] detaches \the [source_hoist.hoistee] from the hoist clamp."), SPAN_NOTICE("You detach \the [source_hoist.hoistee] from the hoist clamp."), SPAN_NOTICE("You hear something unclamp.")) + source_hoist.release_hoistee() + return TRUE - if (!usr.check_dexterity(DEXTERITY_GRIP)) - return +/obj/effect/hoist_hook/receive_mouse_drop(atom/dropping, mob/user, params) + // skip the parent buckle logic, handle climbing directly + if(isliving(user) && !user.anchored && can_climb(user) && dropping == user) + do_climb(dropping) + return TRUE + // end copypasta'd code + if(istype(dropping, /atom/movable)) + var/atom/movable/dropped_movable = dropping + if(!dropped_movable.simulated || dropped_movable.anchored) + to_chat(user, SPAN_WARNING("You can't do that with \the [dropped_movable].")) + return TRUE + if(source_hoist.hoistee) + to_chat(user, SPAN_NOTICE("\The [source_hoist.hoistee] is already attached to \the [src]!")) + return TRUE + if (user.incapacitated()) + to_chat(user, SPAN_WARNING("You can't do that while incapacitated.")) + return + if (!user.check_dexterity(DEXTERITY_HOLD_ITEM)) + return + source_hoist.attach_hoistee(dropped_movable) + user.visible_message( + SPAN_NOTICE("[user] attaches \the [dropped_movable] to \the [src]."), + SPAN_NOTICE("You attach \the [dropped_movable] to \the [src]."), + "You hear something clamp into place.") + return TRUE + +/obj/structure/hoist/proc/attach_hoistee(atom/movable/victim) + hoistee = victim + if(ismob(victim)) + source_hook.buckle_mob(victim) + else + victim.anchored = TRUE // can't buckle non-mobs at the moment + source_hook.layer = victim.layer + 0.1 + if (get_turf(victim) != get_turf(source_hook)) + victim.forceMove(get_turf(source_hook)) - if (!source_hoist.hoistee) - return - if (!isturf(dest)) - return - if (!dest.Adjacent(source_hoist.hoistee)) - return + events_repository.register(/decl/observ/destroyed, victim, src, PROC_REF(release_hoistee)) - source_hoist.check_consistency() +/obj/effect/hoist_hook/handle_mouse_drop(atom/over, mob/user, params) + if(source_hoist.hoistee && isturf(over) && over.Adjacent(source_hoist.hoistee)) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM)) + return TRUE - var/turf/desturf = dest - source_hoist.hoistee.forceMove(desturf) - usr.visible_message( - SPAN_NOTICE("[usr] detaches \the [source_hoist.hoistee] from the hoist clamp."), - SPAN_NOTICE("You detach \the [source_hoist.hoistee] from the hoist clamp."), - "You hear something unclamp.") - source_hoist.release_hoistee() + source_hoist.check_consistency() + var/turf/desturf = over + source_hoist.hoistee.forceMove(desturf) + user.visible_message( + SPAN_NOTICE("[usr] detaches \the [source_hoist.hoistee] from the hoist clamp."), + SPAN_NOTICE("You detach \the [source_hoist.hoistee] from the hoist clamp."), + "You hear something unclamp.") + source_hoist.release_hoistee() + return TRUE + return ..() // This will handle mobs unbuckling themselves. /obj/effect/hoist_hook/unbuckle_mob() . = ..() if (. && !QDELETED(source_hoist)) - var/mob/M = . + var/mob/victim = . source_hoist.hoistee = null - M.fall(get_turf(src)) // fuck you, you fall now! + victim.fall(get_turf(src)) // fuck you, you fall now! /obj/structure/hoist name = "hoist" @@ -144,7 +150,8 @@ source_hook.unbuckle_mob(hoistee) else hoistee.anchored = FALSE - GLOB.destroyed_event.unregister(hoistee, src) + hoistee.fall(get_turf(source_hook || hoistee)) + events_repository.unregister(/decl/observ/destroyed, hoistee, src) hoistee = null layer = initial(layer) @@ -173,26 +180,24 @@ if(. && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(25)))) source_hoist.break_hoist() -/obj/structure/hoist/attack_hand(mob/living/user) - if (!ishuman(user)) - return +/obj/structure/hoist/attack_hand(mob/user) + if (!ishuman(user) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() if (user.incapacitated()) to_chat(user, SPAN_WARNING("You can't do that while incapacitated.")) - return - - if (!user.check_dexterity(DEXTERITY_GRIP)) - return + return TRUE if(broken) to_chat(user, SPAN_WARNING("The hoist is broken!")) - return + return TRUE + var/can = can_move_dir(movedir) var/movtext = movedir == UP ? "raise" : "lower" if (!can) // If you can't... movedir = movedir == UP ? DOWN : UP // switch directions! to_chat(user, SPAN_NOTICE("You switch the direction of the pulley.")) - return + return TRUE if (!hoistee) user.visible_message( @@ -200,24 +205,17 @@ SPAN_NOTICE("You begin to [movtext] the clamp."), SPAN_NOTICE("You hear the sound of a crank.")) move_dir(movedir, 0) - return + return TRUE check_consistency() - var/size - if (ismob(hoistee)) - var/mob/M = hoistee - size = M.mob_size - else if (isobj(hoistee)) - var/obj/O = hoistee - size = O.w_class - user.visible_message( SPAN_NOTICE("[user] begins to [movtext] \the [hoistee]!"), SPAN_NOTICE("You begin to [movtext] \the [hoistee]!"), SPAN_NOTICE("You hear the sound of a crank.")) - if (do_after(user, (1 SECONDS) * size / 4, src)) + if (do_after(user, (1 SECONDS) * get_object_size(hoistee) / 4, src)) move_dir(movedir, 1) + return TRUE /obj/structure/hoist/proc/collapse_kit(mob/user) var/obj/item/hoist_kit/kit = new (get_turf(src)) @@ -235,7 +233,7 @@ if (isobserver(usr) || usr.incapacitated()) return - if (!usr.check_dexterity(DEXTERITY_GRIP)) + if (!usr.check_dexterity(DEXTERITY_HOLD_ITEM)) return if (hoistee) @@ -249,18 +247,19 @@ /obj/structure/hoist/proc/can_move_dir(direction) var/turf/dest = direction == UP ? GetAbove(source_hook) : GetBelow(source_hook) + if(!istype(dest)) + return FALSE switch(direction) if (UP) - if (!isopenspace(dest)) // can't move into a solid tile - return 0 + if(!dest.is_open()) // can't move into a solid tile + return FALSE if (source_hook in get_step(src, dir)) // you don't get to move above the hoist - return 0 + return FALSE if (DOWN) - if (!isopenspace(get_turf(source_hook))) // can't move down through a solid tile - return 0 - if (!dest) // can't move if there's nothing to move to - return 0 - return 1 // i thought i could trust myself to write something as simple as this, guess i was wrong + var/turf/current_turf = get_turf(source_hook) + if(!current_turf || !current_turf.is_open()) // can't move down through a solid tile or if not on a turf + return FALSE + return TRUE // i thought i could trust myself to write something as simple as this, guess i was wrong /obj/structure/hoist/proc/move_dir(direction, ishoisting) var/can = can_move_dir(direction) diff --git a/code/modules/multiz/ladder.dm b/code/modules/multiz/ladder.dm new file mode 100644 index 000000000000..1cb9c5892dc4 --- /dev/null +++ b/code/modules/multiz/ladder.dm @@ -0,0 +1,284 @@ +/obj/structure/ladder + name = "ladder" + desc = "A ladder. You can climb it up and down." + icon_state = "ladder01" + icon = 'icons/obj/structures/ladders.dmi' + density = FALSE + opacity = FALSE + anchored = TRUE + obj_flags = OBJ_FLAG_NOFALL + material = /decl/material/solid/metal/aluminium + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT | TOOL_INTERACTION_ANCHOR + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + + var/base_icon = "ladder" + var/draw_shadow = TRUE + var/obj/structure/ladder/target_up + var/obj/structure/ladder/target_down + var/climb_time = 2 SECONDS + var/static/list/climbsounds = list('sound/effects/ladder.ogg','sound/effects/ladder2.ogg','sound/effects/ladder3.ogg','sound/effects/ladder4.ogg') + + var/static/radial_ladder_down = image(icon = 'icons/screen/radial.dmi', icon_state = "radial_ladder_down") + var/static/radial_ladder_up = image(icon = 'icons/screen/radial.dmi', icon_state = "radial_ladder_up") + + var/static/list/radial_options = list("up" = radial_ladder_up, "down" = radial_ladder_down) + +/obj/structure/ladder/handle_default_hammer_attackby() + var/last_anchored = anchored + . = ..() + if(anchored != last_anchored) + find_connections() + +/obj/structure/ladder/handle_default_wrench_attackby() + var/last_anchored = anchored + . = ..() + if(anchored != last_anchored) + find_connections() + +/obj/structure/ladder/Initialize(maploading, material) + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/structure/ladder/LateInitialize(maploading, material) + if(maploading) + for(var/obj/structure/ladder/ladder in loc) + if(ladder != src) + log_warning("Deleting duplicate ladder at ([x], [y], [z])!") + qdel(ladder) + var/turf/T = get_turf(src) + if((locate(/obj/structure/ladder) in GetBelow(src)) && (!(locate(/obj/structure/lattice) in loc) || !T.is_open())) + var/old_turf_type = T.type + T.dismantle_turf() + //Gonna keep logging those, since it's not clear if it's always a desired behavior. Since mappers would probably not want to rely on this. + log_debug("Ladder replaced turf type '[old_turf_type]' at ([x], [y], [z]) with a lattice and open turf '[loc]' of type '[loc.type]'.") + find_connections() + set_extension(src, /datum/extension/turf_hand) + +/obj/structure/ladder/proc/find_connections() + + if(target_down) + if(target_down.target_up == src) + target_down.target_up = null + target_down.update_icon() + target_down = null + if(target_up) + if(target_up.target_down == src) + target_up.target_down = null + target_up.update_icon() + target_up = null + + if(anchored) + var/turf/L = loc + if(HasBelow(z) && istype(L) && L.is_open()) + var/failed + for(var/obj/structure/platform in loc) + if(!platform.is_z_passable()) + failed = TRUE + break + if(!failed) + for(var/obj/structure/ladder/ladder in GetBelow(src)) + if(ladder.anchored && !ladder.target_up) + target_down = ladder + target_down.target_up = src + target_down.update_icon() + break + if(HasAbove(z)) + var/turf/T = GetAbove(src) + if(istype(T) && T.is_open()) + var/failed + for(var/obj/structure/platform in T) + if(!platform.is_z_passable()) + failed = TRUE + break + if(!failed) + for(var/obj/structure/ladder/ladder in T) + if(ladder.anchored && !ladder.target_down) + target_up = ladder + target_up.target_down = src + target_up.update_icon() + break + update_icon() + +/obj/structure/ladder/Destroy() + if(target_down) + if(target_down.target_up == src) + target_down.target_up = null + target_down.update_icon() + target_down = null + if(target_up) + if(target_up.target_down == src) + target_up.target_down = null + target_up.update_icon() + target_up = null + var/turf/T = get_turf(src) + if(T) + for(var/atom/movable/M in T.contents) + addtimer(CALLBACK(M, TYPE_PROC_REF(/atom/movable, fall), T), 0) + return ..() + +// Override to allow attackby() flow to function with grabs. +/obj/structure/ladder/grab_attack(obj/item/grab/grab, mob/user) + return FALSE + +/obj/structure/ladder/attackby(obj/item/used_item, mob/user) + . = !istype(used_item, /obj/item/grab) && ..() + if(!.) + climb(user, used_item) + +/obj/structure/ladder/hitby(obj/item/thing) + . = ..() + if(!target_down) + return + if(!has_gravity()) + return + var/atom/blocker + var/turf/landing = get_turf(target_down) + if(!istype(landing)) + return + for(var/atom/A in landing) + if(!A.CanPass(thing, thing.loc, 1.5, 0)) + blocker = A + break + if(!blocker) + visible_message(SPAN_DANGER("\The [thing] goes down \the [src]!")) + thing.forceMove(landing) + landing.visible_message(SPAN_DANGER("\The [thing] falls from the top of \the [target_down]!")) + +/obj/structure/ladder/attack_hand(var/mob/user) + if(user.check_intent(I_FLAG_HARM) || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES)) + return ..() + climb(user) + return TRUE + +/obj/structure/ladder/attack_ai(var/mob/M) + var/mob/living/silicon/ai/ai = M + if(!istype(ai)) + return + var/mob/observer/eye/AIeye = ai.eyeobj + if(istype(AIeye)) + instant_climb(AIeye) + +/obj/structure/ladder/attack_robot(var/mob/user) + if(CanPhysicallyInteract(user)) + climb(user) + return TRUE + +/obj/structure/ladder/proc/instant_climb(var/mob/M) + var/atom/target_ladder = getTargetLadder(M) + if(target_ladder) + M.dropInto(target_ladder.loc) + +/obj/structure/ladder/proc/climb(mob/M, obj/item/thing) + if(!M.may_climb_ladders(src)) + return + + var/obj/structure/ladder/target_ladder = getTargetLadder(M) + if(!target_ladder) + return + + if(!M.Move(get_turf(src))) + to_chat(M, SPAN_NOTICE("You fail to reach \the [src].")) + return + + add_fingerprint(M) + + var/direction = target_ladder == target_up ? "up" : "down" + M.visible_message(SPAN_NOTICE("\The [M] begins climbing [direction] \the [src].")) + target_ladder.audible_message(SPAN_NOTICE("You hear something coming [direction] \the [src].")) + if(do_after(M, climb_time, src)) + climbLadder(M, target_ladder, thing) + +/obj/structure/ladder/attack_ghost(var/mob/M) + instant_climb(M) + +/obj/structure/ladder/proc/getTargetLadder(var/mob/M) + if(!anchored) + to_chat(M, SPAN_WARNING("\The [src] is not anchored in place and cannot be climbed.")) + return + find_connections() + if(!target_up && !target_down) + to_chat(M, SPAN_WARNING("\The [src] does not seem to lead anywhere.")) + else if(target_down && target_up) + var/direction = show_radial_menu(M, src, radial_options, require_near = !(isEye(M) || isobserver(M))) + if(!direction) + return + if(!M.may_climb_ladders(src)) + return + . = (direction == "up") ? target_up : target_down + else + . = target_down || target_up + + if(.) + if(. == target_up) + var/turf/T = target_up.loc + if(!istype(T) || !T.is_open()) + to_chat(M, SPAN_WARNING("The ceiling is in the way!")) + return null + for(var/obj/structure/platform in target_up.loc) + if(!platform.is_z_passable()) + to_chat(M, SPAN_WARNING("\The [platform] is in the way!")) + return null + if(. == target_down) + var/turf/T = loc + if(!istype(T) || !T.is_open()) + to_chat(M, SPAN_WARNING("\The [loc] is in the way!")) + return null + for(var/obj/structure/platform in loc) + if(!platform.is_z_passable()) + to_chat(M, SPAN_WARNING("\The [platform] is in the way!")) + return null + +/mob/proc/may_climb_ladders(var/ladder) + if(!Adjacent(ladder)) + to_chat(src, SPAN_WARNING("You need to be next to \the [ladder] to start climbing.")) + return FALSE + if(incapacitated()) + to_chat(src, SPAN_WARNING("You are physically unable to climb \the [ladder].")) + return FALSE + + var/can_carry = can_pull_size + if(loc?.has_gravity()) + can_carry = floor(can_carry * 0.75) + for(var/obj/item/grab/grab as anything in get_active_grabs()) + can_carry -= grab.affecting.get_object_size() + if(can_carry < 0) + to_chat(src, SPAN_WARNING("You can't carry \the [grab.affecting] up \the [ladder].")) + return FALSE + + return TRUE + +/mob/observer/ghost/may_climb_ladders(var/ladder) + return TRUE + +/obj/structure/ladder/proc/climbLadder(mob/user, target_ladder, obj/item/thing = null) + var/turf/T = get_turf(target_ladder) + for(var/atom/A in T) + if(!A.CanPass(user, user.loc, 1.5, 0)) + to_chat(user, SPAN_NOTICE("\The [A] is blocking \the [src].")) + //We cannot use the ladder, but we probably can remove the obstruction + var/atom/movable/M = A + if(istype(M) && M.movable_flags & MOVABLE_FLAG_Z_INTERACT) + if(isnull(thing) || istype(thing, /obj/item/grab)) + M.attack_hand_with_interaction_checks(user) + else + M.attackby(thing, user) + return FALSE + playsound(src, pick(climbsounds), 50) + playsound(target_ladder, pick(climbsounds), 50) + return user.Move(T, (loc.z > T.z) ? DOWN : UP) + +/obj/structure/ladder/CanPass(obj/mover, turf/source, height, airflow) + return airflow || !density + +/obj/structure/ladder/on_update_icon() + ..() + if(!anchored) + icon_state = "[base_icon]00" + else + icon_state = "[base_icon][!!target_up][!!target_down]" + if(target_down && draw_shadow) + var/image/overlay_image = image(icon, "downward_shadow") + overlay_image.appearance_flags |= RESET_COLOR + underlays = list(overlay_image) + else + underlays.Cut() diff --git a/code/modules/multiz/level_data.dm b/code/modules/multiz/level_data.dm new file mode 100644 index 000000000000..9250c0dfea4c --- /dev/null +++ b/code/modules/multiz/level_data.dm @@ -0,0 +1,912 @@ +/// Returns all the turfs within a zlevel's transition edge, on a given direction. +/// If include corners is true, the corners of the map will be included. +/proc/get_transition_edge_turfs(var/z, var/dir_edge, var/include_corners = FALSE) + var/datum/level_data/LD = SSmapping.levels_by_z[z] + + //minimum and maximum corners making up the box, between which the transition edge is + var/min_x = 1 //X of lower left corner of the edge + var/min_y = 1 //Y of lower left corner of the edge + var/max_x = 1 //X of upper right corner of the edge + var/max_y = 1 //Y of upper right corner of the edge + + //Pos before or after the transition edge on either ends of each axis of the level. (Including corners or not) + var/x_bef_transit = include_corners? (LD.level_inner_min_x - TRANSITIONEDGE) : (LD.level_inner_min_x) + var/x_aft_transit = include_corners? (LD.level_inner_max_x + TRANSITIONEDGE) : (LD.level_inner_max_x) + var/y_bef_transit = include_corners? (LD.level_inner_min_y - TRANSITIONEDGE) : (LD.level_inner_min_y) + var/y_aft_transit = include_corners? (LD.level_inner_max_y + TRANSITIONEDGE) : (LD.level_inner_max_y) + + switch(dir_edge) + if(NORTH) + min_x = x_bef_transit + min_y = LD.level_inner_max_y + 1 //Add one so we're outside the inner area (inner min/max are inclusive) + max_x = x_aft_transit + max_y = LD.level_inner_max_y + TRANSITIONEDGE //End of the transition edge on that axis + if(SOUTH) + min_x = x_bef_transit + min_y = LD.level_inner_min_y - TRANSITIONEDGE + max_x = x_aft_transit + max_y = LD.level_inner_min_y - 1 + if(EAST) + min_x = LD.level_inner_max_x + 1 + min_y = y_bef_transit + max_x = LD.level_inner_max_x + TRANSITIONEDGE + max_y = y_aft_transit + if(WEST) + min_x = LD.level_inner_min_x - TRANSITIONEDGE + min_y = y_bef_transit + max_x = LD.level_inner_min_x - 1 + max_y = y_aft_transit + + return block( + min_x, min_y, LD.level_z, + max_x, max_y, LD.level_z + ) + +///Returns all the turfs from all 4 corners of the transition border of a level. +/proc/get_transition_edge_corner_turfs(var/z) + var/datum/level_data/LD = SSmapping.levels_by_z[z] + //South-West + . = block( + LD.level_inner_min_x - TRANSITIONEDGE, LD.level_inner_min_y - TRANSITIONEDGE, LD.level_z, + LD.level_inner_min_x - 1, LD.level_inner_min_y - 1, LD.level_z) + //South-East + . |= block( + LD.level_inner_max_x + 1, LD.level_inner_min_y - TRANSITIONEDGE, LD.level_z, + LD.level_inner_max_x + TRANSITIONEDGE, LD.level_inner_min_y - 1, LD.level_z) + //North-West + . |= block( + LD.level_inner_min_x - TRANSITIONEDGE, LD.level_inner_max_y + 1, LD.level_z, + LD.level_inner_min_x - 1, LD.level_inner_max_y + TRANSITIONEDGE, LD.level_z) + //North-East + . |= block( + LD.level_inner_max_x + 1, LD.level_inner_max_y + 1, LD.level_z, + LD.level_inner_max_x + TRANSITIONEDGE, LD.level_inner_max_y + TRANSITIONEDGE, LD.level_z) + +///Keeps details on how to generate, maintain and access a zlevel. +/datum/level_data + ///Name displayed to the player to refer to this level in user interfaces and etc. If null, one will be generated. + var/name + /// Multiplier applied to damage when falling through this level. + var/fall_depth = 1 + /// The z-level that was assigned to this level_data + var/level_z + /// A unique string identifier for this particular z-level. Used to fetch a level without knowing its z-level. + var/level_id + /// Various flags indicating what this level functions as. + var/level_flags = 0 + /// The desired width of the level, including the TRANSITIONEDGE. + ///If world.maxx is bigger, the exceeding area will be filled with turfs of "border_filler" type if defined, or base_turf otherwise. + var/level_max_width + /// The desired height of the level, including the TRANSITIONEDGE. + ///If world.maxy is bigger, the exceeding area will be filled with turfs of "border_filler" type if defined, or base_turf otherwise. + var/level_max_height + + // Do not serialize these! They are used for relative distance checking and nothing else! + // They are potentially not going to be static, reliable or consistent within a round! + /// Used to apply x offsets to distance checking in this volume. + var/tmp/z_volume_level_x + /// Used to apply y offsets to distance checking in this volume. + var/tmp/z_volume_level_y + /// Used to apply z offsets to distance checking in this volume. + var/tmp/z_volume_level_z + + /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge. + var/level_inner_min_x + /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge. + var/level_inner_min_y + /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge. + var/level_inner_max_x + /// Filled by map gen on init. Indicates where the accessible level area starts past the transition edge. + var/level_inner_max_y + + /// Filled by map gen on init. Indicates the width of the accessible area within the transition edges. + var/level_inner_width + /// Filled by map gen on init. Indicates the height of the accessible area within the transition edges. + var/level_inner_height + + // *** Lighting *** + /// Set to false to override with our own. + var/use_global_exterior_ambience = TRUE + /// Ambient lighting light intensity turfs on this level should have. Value from 0 to 1. + var/ambient_light_level = 0 + /// Colour of ambient light for turfs on this level. + var/ambient_light_color = COLOR_WHITE + + // *** Level Gen *** + ///The mineral strata assigned to this level if any. Set to a path at definition, then to a decl/strata instance at runtime. + var/decl/strata/strata + ///The base material randomly chosen from the strata for this level. + var/decl/material/strata_base_material + ///Strata types to forbid from generating on this level. + var/list/forbid_strata = list( + /decl/strata/permafrost + ) + ///The default base turf type for the whole level. It will be the base turf type for the z level, unless loaded by map. + /// filler_turf overrides what turfs the level will be created with. + var/base_turf = /turf/space + /// When the level is created dynamically, all turfs on the map will be changed to this one type. If null, will use the base_turf instead. + var/filler_turf + ///The default area type for the whole level. It will be applied to all turfs in the level on creation, unless loaded by map. + var/base_area = /area/space + ///The turf to fill the border area beyond the bounds of the level with. + /// If null, nothing will be placed in the border area. (This is also placed when a border cannot be looped if loop_unconnected_borders is TRUE) + var/border_filler// = /turf/unsimulated/mineral + ///If set we will put a looping edge on every unconnected edge of the map. If null, will not loop unconnected edges. + /// If an unconnected edge is facing a connected edge, it will be instead filled with "border_filler" instead, if defined. + var/loop_turf_type// = /turf/unsimulated/mimc_edge/transition/loop + /// The turf type to use for zlevel lateral connections + var/transition_turf_type = /turf/mimic_edge/transition + + // *** Atmos *** + /// Temperature of standard exterior atmosphere. + var/exterior_atmos_temp = T20C + /// Gas mixture datum returned to exterior return_air. Set to assoc list of material to moles to initialize the gas datum. + var/datum/gas_mixture/exterior_atmosphere + + // *** Connections *** + ///A associative list of all level_ids to a direction bitflag. Indicates what direction of the map connects to what level + var/list/connected_levels + ///A cached list of connected directions to their connected level id. Filled up at runtime. + var/tmp/list/cached_connections + + ///A list of /datum/random_map types to apply to this level if we're running level generation. + /// May run before or after parent level gen + var/list/level_generators + + ///Whether the level data was setup already. + var/tmp/_level_setup_completed = FALSE + ///This is set to prevent spamming the log when a turf has tried to grab our strata before we've been initialized + var/tmp/_has_warned_uninitialized_strata = FALSE + + /// An associate list of door types/list of allowed turfs + VAR_PROTECTED/UT_turf_exceptions_by_door_type = list( + /obj/machinery/door/firedoor = list(/turf/open), + /obj/machinery/door/firedoor/border = list(/turf/open), + ) + /// Determines if edge turfs should be centered on the map dimensions. + var/origin_is_world_center = TRUE + /// If not null, this level will register with a daycycle id/type on New(). + var/daycycle_id = "general_solars" + /// Type provided to the above. + var/daycycle_type = /datum/daycycle/solars + + /// Extra spacing needed between any random level templates and the transition edge of a level. + /// Note that this is more or less unnecessary if you are using a mapped area that doesn't stretch to the edge of the level. + var/template_edge_padding = 15 + + // Submap loading values, passed back via getters like get_subtemplate_budget(). + /// A point budget to spend on subtemplates (see template costs) + var/subtemplate_budget = 0 + /// A string identifier for the category of subtemplates to draw from for this level. + var/subtemplate_category = null + /// A specific area to use when determining where to place subtemplates. + var/subtemplate_area = null + + /// Set to TRUE if this level persistence data, FALSE if not. Check is only done if _has_serde_data is null. + VAR_PRIVATE/_has_serde_data = null + +/datum/level_data/New(var/_z_level, var/defer_level_setup = FALSE) + . = ..() + level_z = _z_level + if(isnull(_z_level)) + PRINT_STACK_TRACE("Attempting to initialize a null z-level.") + + initialize_level_id() + SSmapping.register_level_data(src) + setup_exterior_atmosphere() + if(SSmapping.initialized && !defer_level_setup) + setup_level_data() + +/datum/level_data/Destroy(force) + //Since this is a datum that lives inside the SSmapping subsystem, I'm not sure if we really need to prevent deletion. + // It was fine for the obj version of this, but not much point now? + SSmapping.unregister_level_data(src) + . = ..() + +///Generates a level_id if none were specified in the datum definition. +/datum/level_data/proc/initialize_level_id() + if(level_id) + return + level_id = "leveldata_[level_z]_[sequential_id(/datum/level_data)]" + +///Handle a new level_data datum overwriting us. +/datum/level_data/proc/replace_with(var/datum/level_data/new_level) + new_level.copy_from(src) + +///Handle copying data from a previous level_data we're replacing. +/datum/level_data/proc/copy_from(var/datum/level_data/old_level) + //#TODO: It's not really clear what should get moved over by default. But putting some time to reflect on this would be good... + return + +///Initialize the turfs on the z-level. +/datum/level_data/proc/initialize_new_level() + //#TODO: Is it really necessary to do this for any and all levels? Seems mainly useful for space levels? + var/picked_turf = filler_turf || base_turf //Pick the filler_turf for filling if it's set, otherwise use the base_turf + var/change_turf = (picked_turf && picked_turf != world.turf) + var/change_area = (base_area && base_area != world.area) + if(!change_turf && !change_area) + return + var/area/A = change_area ? get_base_area_instance() : null + // We don't have to worry about the edge turfs because those are handled in build_border(). + for(var/turf/T as anything in Z_ALL_TURFS(level_z)) + if(change_turf) + T = T.ChangeTurf(picked_turf) + if(change_area) + ChangeArea(T, A) + +///Prepare level for being used. Setup borders, lateral z connections, ambient lighting, atmosphere, etc.. +/datum/level_data/proc/setup_level_data(var/skip_gen = FALSE) + + if(_level_setup_completed) + log_debug("level_data for [src], on z [level_z], had setup_level_data called more than once!") + return //Since we can defer setup, make sure we only setup once + + setup_level_bounds() + setup_strata() + if(!skip_gen) + generate_level() + after_generate_level() + setup_ambient() + + // Determine our relative positioning. + // First find an appropriate origin point. + var/datum/level_data/origin + for(var/check_z in SSmapping.get_connected_levels(level_z, include_lateral = TRUE)) + var/datum/level_data/checking = SSmapping.levels_by_z[check_z] + if(!isnull(checking.z_volume_level_x) && !isnull(checking.z_volume_level_y) && !isnull(checking.z_volume_level_z)) + origin = checking + break + + // If nobody else has set up lateral level coords, we must be the origin. + if(!origin) + origin = src + z_volume_level_x = 0 + z_volume_level_y = 0 + z_volume_level_z = 0 + + var/list/checked = list() + var/list/to_check = list(origin) + while(length(to_check)) + + // Update our tracking lists. + var/datum/level_data/checking = to_check[1] + var/datum/level_data/previous = to_check[checking] + to_check -= checking + checked |= checking + + // Obtain all our neighbors for flood fill. + for(var/level_id in checking.connected_levels) + var/datum/level_data/neighbor = SSmapping.levels_by_id[level_id] + if(istype(neighbor) && !(neighbor in checked)) + to_check[neighbor] = checking + if(HasBelow(checking.level_z)) + var/datum/level_data/neighbor = SSmapping.levels_by_z[checking.level_z-1] + if(istype(neighbor) && !(neighbor in checked)) + to_check[neighbor] = checking + if(HasAbove(checking.level_z)) + var/datum/level_data/neighbor = SSmapping.levels_by_z[checking.level_z+1] + if(istype(neighbor) && !(neighbor in checked)) + to_check[neighbor] = checking + + // Update our lateral coords based on the direction of our connection. + // This does NOT appropriately handle looping or non-horizontal/vertical + // connections, which violate our assumptions. + if(previous) + + checking.z_volume_level_x = previous.z_volume_level_x + checking.z_volume_level_y = previous.z_volume_level_y + checking.z_volume_level_z = previous.z_volume_level_z + + var/connect_dir = previous.level_id ? LAZYACCESS(checking.connected_levels, previous.level_id) : 0 + if(connect_dir & SOUTH) + checking.z_volume_level_y += previous.level_inner_height + else if(connect_dir & NORTH) + checking.z_volume_level_y -= checking.level_inner_height + if(connect_dir & WEST) + checking.z_volume_level_x += previous.level_inner_width + else if(connect_dir & EAST) + checking.z_volume_level_x -= checking.level_inner_width + + if(HasBelow(previous.level_z) && checking.level_z == previous.level_z-1) + checking.z_volume_level_z -= 1 + else if(HasAbove(previous.level_z) && checking.level_z == previous.level_z+1) + checking.z_volume_level_z += 1 + + // Normalize our coords. + var/lowest_x + var/highest_x + var/lowest_y + var/highest_y + var/lowest_z + var/highest_z + for(var/check_z in SSmapping.get_connected_levels(level_z, include_lateral = TRUE)) + var/datum/level_data/checking = SSmapping.levels_by_z[check_z] + lowest_x = min(lowest_x, checking.z_volume_level_x) + highest_x = max(highest_x, checking.z_volume_level_x) + lowest_y = min(lowest_y, checking.z_volume_level_y) + highest_y = max(highest_y, checking.z_volume_level_y) + lowest_z = min(lowest_z, checking.z_volume_level_z) + highest_z = max(highest_z, checking.z_volume_level_z) + + var/modify_x = 0 + if(lowest_x < 0) + modify_x = abs(lowest_x) + else if(lowest_x > 0) + modify_x = -(lowest_x) + + var/modify_y = 0 + if(lowest_y < 0) + modify_y = abs(lowest_y) + else if(lowest_y > 0) + modify_y = -(lowest_y) + + var/modify_z = 0 + if(lowest_z < 0) + modify_z = abs(lowest_z) + else if(lowest_z > 0) + modify_z = -(lowest_z) + + for(var/check_z in SSmapping.get_connected_levels(level_z, include_lateral = TRUE)) + var/datum/level_data/checking = SSmapping.levels_by_z[check_z] + checking.z_volume_level_x += modify_x + checking.z_volume_level_y += modify_y + checking.z_volume_level_z += modify_z + + _level_setup_completed = TRUE + +/datum/level_data/proc/build_area_ceilings() + // Set base flooring on turfs above station areas in order to prevent easily digging down into station areas. + if(!HasAbove(level_z)) + return + for(var/turf/below as anything in block(locate(level_inner_min_x, level_inner_min_y, level_z), locate(level_inner_max_x, level_inner_max_y, level_z))) + var/turf/floor/above = GetAbove(below) + if(!istype(above)) + continue + var/area/area = get_area(below) + if(!istype(area) || !(area.area_flags & AREA_FLAG_CONSTRUCTED)) + continue + var/decl/flooring/base_flooring = above.get_base_flooring() + if(!base_flooring || base_flooring.constructed) + continue + above.set_base_flooring(/decl/flooring/plating) // TODO: check if we can skip update here. + +///Calculate the bounds of the level, the border area, and the inner accessible area. +/// Basically, by default levels are assumed to be loaded relative to the world center, so if they're smaller than the world +/// they get their origin offset so they're in the middle of the world. By default templates are always loaded at origin 1,1. +/// so that's useful to know and have control over! +/datum/level_data/proc/setup_level_bounds() + //Get the width/height we got for the level and the edges + level_max_width = level_max_width ? level_max_width : world.maxx + level_max_height = level_max_height ? level_max_height : world.maxy + + //The width of the accessible inner area of the level between the edges + level_inner_width = level_max_width - (2 * TRANSITIONEDGE) + level_inner_height = level_max_height - (2 * TRANSITIONEDGE) + + //Get the origin of the lower left corner where the level's edge begins at on the world. + //#FIXME: This is problematic when dealing with an even width/height + var/x_origin = origin_is_world_center? max(floor((world.maxx - level_max_width) / 2), 1) : 1 + var/y_origin = origin_is_world_center? max(floor((world.maxy - level_max_height) / 2), 1) : 1 + + //The first x/y that's past the edge and within the accessible level + level_inner_min_x = x_origin + TRANSITIONEDGE + level_inner_min_y = y_origin + TRANSITIONEDGE + + //The last x/y that's within the accessible level and before the edge + level_inner_max_x = ((x_origin + level_max_width) - TRANSITIONEDGE) - 1 + level_inner_max_y = ((y_origin + level_max_height) - TRANSITIONEDGE) - 1 + +///Setup ambient lighting for the level +/datum/level_data/proc/setup_ambient() + if(!use_global_exterior_ambience) + return + ambient_light_level = get_config_value(/decl/config/num/exterior_ambient_light) + ambient_light_color = SSskybox.background_color + +///Setup/generate atmosphere for exterior turfs on the level. +/datum/level_data/proc/setup_exterior_atmosphere() + //Skip setup if we've been set to a ref already + if(istype(exterior_atmosphere)) + exterior_atmosphere.update_values() //Might as well update + exterior_atmosphere.check_tile_graphic() + return + var/list/exterior_atmos_composition = exterior_atmosphere + exterior_atmosphere = new + if(islist(exterior_atmos_composition)) + for(var/gas in exterior_atmos_composition) + exterior_atmosphere.adjust_gas(gas, exterior_atmos_composition[gas], FALSE) + exterior_atmosphere.temperature = exterior_atmos_temp + exterior_atmosphere.update_values() + exterior_atmosphere.check_tile_graphic() + +///Pick a strata for the given level if applicable. +/datum/level_data/proc/setup_strata() + //If no strata, pick a random one + if(isnull(strata)) + var/list/all_strata = decls_repository.get_decls_of_subtype(/decl/strata) + var/list/possible_strata = list() + + for(var/stype in all_strata) + var/decl/strata/strata = all_strata[stype] + if(!is_type_in_list(strata, forbid_strata) && strata.is_valid_level_stratum(src)) + possible_strata += stype + + strata = DEFAULTPICK(possible_strata, GET_DECL(/decl/strata/sedimentary)) + //Make sure we have a /decl/strata instance + if(ispath(strata)) + strata = GET_DECL(strata) + + //cache the strata base material we picked from the list. So all turfs use the same we picked. + if(strata && length(strata.base_materials) && !strata_base_material) + strata_base_material = pick(strata.base_materials) + if(ispath(strata_base_material, /decl/material)) + strata_base_material = GET_DECL(strata_base_material) + return strata + +// +// Level Load/Gen +// +/// Helper proc for subtemplate generation. Returns a point budget to spend on subtemplates. +/datum/level_data/proc/get_subtemplate_budget() + return subtemplate_budget +/// Helper proc for subtemplate generation. Returns a string identifier for a general category of template. +/datum/level_data/proc/get_subtemplate_category() + return subtemplate_category +/// Helper proc for subtemplate generation. Returns a bitflag of template flags that must not be present for a subtemplate to be considered available. +/datum/level_data/proc/get_subtemplate_blacklist() + return +/// Helper proc for subtemplate generation. Returns a bitflag of template flags that must be present for a subtemplate to be considered available. +/datum/level_data/proc/get_subtemplate_whitelist() + return +/// Helper proc for getting areas associated with placable submaps on this level. +/datum/level_data/proc/get_subtemplate_areas(template_category, blacklist, whitelist) + if(subtemplate_area) + return islist(subtemplate_area) ? subtemplate_area : list(subtemplate_area) + if(base_area) + return list(base_area) + +// If we do serde, that implies we don't want to apply another layer of procgen over what's already saved. +// Specific levels should override this proc as needed for generation independent of serde. +/datum/level_data/proc/should_generate_level() + if(!is_persistent()) + return TRUE + if(!get_config_value(/decl/config/toggle/roundstart_level_generation) || !(get_subtemplate_budget() || length(level_generators))) + return FALSE + if(isnull(_has_serde_data)) + var/decl/serialization_handler/handler = RESOLVE_TO_DECL(persistence_handler) + _has_serde_data = fexists(handler.get_data_path(persistent_data_location, global.using_map.path, ckey(level_id))) + return !_has_serde_data + +///Called when setting up the level. Apply generators and anything that modifies the turfs of the level. +/datum/level_data/proc/generate_level() + if(!should_generate_level()) + report_progress("Skipping [_has_serde_data ? "post-serde " : ""]level generation for [level_id].") + return + var/origx = level_inner_min_x + var/origy = level_inner_min_y + var/endx = level_inner_min_x + level_inner_width + var/endy = level_inner_min_y + level_inner_height + // Run level generators. + for(var/gen_type in level_generators) + report_progress("Placing [gen_type] on [level_id]...") + new gen_type(origx, origy, level_z, endx, endy, FALSE, TRUE, get_base_area_instance()) + place_subtemplates() + +/datum/level_data/proc/place_subtemplates() + // Place points of interest. + var/budget = get_subtemplate_budget() + if(budget) + report_progress("Placing subtemplates on [level_id]...") + spawn_subtemplates(budget, get_subtemplate_category(), get_subtemplate_blacklist(), get_subtemplate_whitelist()) + +///Apply the parent entity's map generators. (Planets generally) +///This proc is to give a chance to level_data subtypes to individually chose to ignore the parent generators. +/datum/level_data/proc/apply_map_generators(var/list/map_gen) + if(!get_config_value(/decl/config/toggle/roundstart_level_generation)) + return + var/origx = level_inner_min_x + var/origy = level_inner_min_y + var/endx = level_inner_min_x + level_inner_width + var/endy = level_inner_min_y + level_inner_height + for(var/gen_type in map_gen) + new gen_type(origx, origy, level_z, endx, endy, FALSE, TRUE, get_base_area_instance()) + +/// Helper proc for placing mobs on a level after level creation. +/datum/level_data/proc/get_mobs_to_populate_level() + return + +///Called during level setup. Run anything that should happen only after the map is fully generated. +/datum/level_data/proc/after_generate_level() + + build_border() + + if(daycycle_id && daycycle_type) + SSdaycycle.register_level(level_z, daycycle_id, daycycle_type) + + var/list/mobs_to_spawn = get_mobs_to_populate_level() + if(length(mobs_to_spawn)) + for(var/list/mob_category in mobs_to_spawn) + var/list/mob_types = mob_category[1] + var/mob_turf = mob_category[2] + var/mob_count = mob_category[3] + var/sanity = 1000 + while(mob_count && sanity) + sanity-- + var/turf/place_mob_at = locate(rand(level_inner_min_x, level_inner_max_x), rand(level_inner_min_y, level_inner_max_y), level_z) + if(istype(place_mob_at, mob_turf) && !(locate(/mob/living) in place_mob_at)) + var/mob_type = pickweight(mob_types) + new mob_type(place_mob_at) + mob_count-- + CHECK_TICK + +///Changes anything named we may need to rename based on the parent location name. For instance, exoplanet surface areas. +/datum/level_data/proc/adapt_to_location_name(var/location_name) + return + +//#TODO: this could probably be done in a more elegant way. Since most map templates will never call this. +///Called before a runtime generated template is generated on our z-level. Only applies to templates generated onto new z-levels. +/// Is never called by templates which are loaded from file! +/datum/level_data/proc/before_template_generation(var/datum/map_template/template) + return + +///Called after a map_template has been loaded on our z-level. Only apply to templates loaded onto new z-levels. +/datum/level_data/proc/after_template_load(var/datum/map_template/template) + if(template.accessibility_weight) + SSmapping.accessible_z_levels[num2text(level_z)] = template.accessibility_weight + SSmapping.player_levels |= level_z + +///Builds the map's transition edge if applicable +/datum/level_data/proc/build_border() + var/list/edge_states = compute_level_edges_states() + for(var/edge_dir in global.cardinal) + build_border_edge(edge_states[edge_dir], edge_dir) + + //Now prepare the corners of the border + build_border_corners() + +///Loop through the edges of the level and determine if they're connected, looping, filled, or untouched. +/datum/level_data/proc/compute_level_edges_states() + var/list/edge_states = list() + edge_states.len = 8 //Largest cardinal direction is WEST or 8 + var/should_loop_edges = ispath(loop_turf_type) + var/has_filler_edge = ispath(border_filler) + + //First determine and validate the borders + for(var/adir in global.cardinal) + //First check for connections, or loop + if(get_connected_level_id(adir)) + edge_states[adir] = LEVEL_EDGE_CON + var/reverse = global.reverse_dir[adir] + //When facing a connected edge that wasn't set yet, make sure we don't put a loop edge opposite of it. + if(should_loop_edges && ((edge_states[reverse] == LEVEL_EDGE_LOOP) || !edge_states[reverse])) + edge_states[reverse] = has_filler_edge? LEVEL_EDGE_WALL : LEVEL_EDGE_NONE + + if(edge_states[adir]) + continue //Skip edges which either connect to another z-level, or have been forced to a specific type already + if(should_loop_edges) + edge_states[adir] = LEVEL_EDGE_LOOP + else if(ispath(border_filler)) + edge_states[adir] = LEVEL_EDGE_WALL //Apply filler wall last if we have no connections or loop + else + edge_states[adir] = LEVEL_EDGE_NONE + + return edge_states + +///Apply the specified edge type to the specified edge's turfs +/datum/level_data/proc/build_border_edge(var/edge_type, var/edge_dir) + if(edge_type == LEVEL_EDGE_NONE) + return + + var/list/edge_turfs + switch(edge_type) + if(LEVEL_EDGE_LOOP) + edge_turfs = get_transition_edge_turfs(level_z, edge_dir, FALSE) + for(var/turf/T in edge_turfs) + T.ChangeTurf(loop_turf_type) + if(LEVEL_EDGE_CON) + edge_turfs = get_transition_edge_turfs(level_z, edge_dir, FALSE) + for(var/turf/T in edge_turfs) + T.ChangeTurf(transition_turf_type) + if(LEVEL_EDGE_WALL) + edge_turfs = get_transition_edge_turfs(level_z, edge_dir, TRUE) + for(var/turf/T in edge_turfs) + T.ChangeTurf(border_filler) + +///Handle preparing the level's border's corners after we've stup the edges. +/datum/level_data/proc/build_border_corners() + if(!border_filler) + return + //Now prepare the corners of the border + var/list/all_corner_turfs = get_transition_edge_corner_turfs(level_z) + for(var/turf/T in all_corner_turfs) + T.ChangeTurf(border_filler) //Fill corners with border turf + +// +// Accessors +// +/datum/level_data/proc/get_exterior_atmosphere() + if(exterior_atmosphere && !istype(exterior_atmosphere)) + PRINT_STACK_TRACE("Attempting to retrieve exterior atmosphere before it is set up!") + return + var/datum/gas_mixture/gas = new + gas.copy_from(exterior_atmosphere) + if(daycycle_id) + var/datum/daycycle/daycycle = SSdaycycle.get_daycycle(daycycle_id) + var/temp_mod = daycycle?.current_period?.temperature + if(!isnull(temp_mod)) + gas.temperature = max(1, gas.temperature + temp_mod) + gas.update_values() + return gas + +/datum/level_data/proc/get_display_name() + if(!name) + var/obj/effect/overmap/overmap_entity = global.overmap_sectors[level_z] + if(overmap_entity?.name) + name = overmap_entity.name + else + name = "Sector #[level_z]" + return name + +/datum/level_data/proc/get_connected_level_id(var/direction) + if(!length(cached_connections)) + //Build a list that we can access with the direction value instead of having to do string conversions + cached_connections = list() + cached_connections.len = DOWN //Down is the largest of the directional values + for(var/lvlid in connected_levels) + cached_connections[connected_levels[lvlid]] = lvlid + + if(istext(direction)) + CRASH("Direction must be a direction flag.") + return cached_connections[direction] + +///Returns recursively a list of level_data for each connected levels. +/datum/level_data/proc/get_all_connected_level_data(var/list/_connected_siblings) + . = list() + //Since levels may refer to eachothers, make sure we're in the siblings list to avoid infinite recursion + LAZYDISTINCTADD(_connected_siblings, src) + for(var/id in connected_levels) + var/datum/level_data/LD = SSmapping.levels_by_id[id] + if(LD in _connected_siblings) + continue + . |= LD + var/list/cur_con = LD.get_all_connected_level_data(_connected_siblings) + if(length(cur_con)) + . |= cur_con + +///Returns recursively a list of level_ids for each connected levels. +/datum/level_data/proc/get_all_connected_level_ids(var/list/_connected_siblings) + . = list() + //Since levels may refer to eachothers, make sure we're in the siblings list to avoid infinite recursion + LAZYDISTINCTADD(_connected_siblings, level_id) + for(var/id in connected_levels) + var/datum/level_data/LD = SSmapping.levels_by_id[id] + if(LD.level_id in _connected_siblings) + continue + . |= LD.level_id + var/list/cur_con = LD.get_all_connected_level_ids(_connected_siblings) + if(length(cur_con)) + . |= cur_con + +///Returns recursively a list of z-level indices for each connected levels. Parameter is to keep trakc +/datum/level_data/proc/get_all_connected_level_z(var/list/_connected_siblings) + . = list() + //Since levels may refer to eachothers, make sure we're in the siblings list to avoid infinite recursion + LAZYDISTINCTADD(_connected_siblings, level_z) + for(var/id in connected_levels) + var/datum/level_data/LD = SSmapping.levels_by_id[id] + if(LD.level_z in _connected_siblings) + continue + . |= LD.level_z + . |= LD.get_all_connected_level_z(_connected_siblings) + + +/datum/level_data/proc/find_connected_levels(var/list/found) + LAZYDISTINCTADD(found, level_z) + for(var/other_id in connected_levels) + var/datum/level_data/neighbor = SSmapping.levels_by_id[other_id] + if(neighbor.level_z in found) + continue + LAZYADD(found, neighbor.level_z) + if(!length(neighbor.connected_levels)) + continue + neighbor.find_connected_levels(found) + +///Returns the instance of the base area for this level +/datum/level_data/proc/get_base_area_instance() + var/area/found = locate(base_area) + if(found) + return found + if(ispath(base_area)) + return new base_area + return locate(world.area) + +///Warns exactly once about a turf trying to initialize it's strata from us when we haven't completed setup. +/datum/level_data/proc/warn_bad_strata(var/turf/T) + if(_has_warned_uninitialized_strata) + return + PRINT_STACK_TRACE("Turf tried to init its strata before it was setup for level '[level_id]' z:[level_z]! [log_info_line(T)]") + _has_warned_uninitialized_strata = TRUE + +//////////////////////////////////////////// +// Level Data Spawner +//////////////////////////////////////////// + +/// Mapper helper for spawning a specific level_data datum with the map as it gets loaded +/obj/abstract/level_data_spawner + name = "space" + icon_state = "level_data" + is_spawnable_type = FALSE + var/level_data_type = /datum/level_data/space + +INITIALIZE_IMMEDIATE(/obj/abstract/level_data_spawner) +/obj/abstract/level_data_spawner/Initialize() + var/datum/level_data/LD = new level_data_type(z) + //Let the mapper forward a level name for the level_data, if none was defined + if(!length(LD.name) && length(name)) + LD.name = name + ..() + return INITIALIZE_HINT_QDEL + +//////////////////////////////////////////// +// Mapper Templates +//////////////////////////////////////////// +/obj/abstract/level_data_spawner/player + level_data_type = /datum/level_data/player_level + +/obj/abstract/level_data_spawner/main_level + level_data_type = /datum/level_data/main_level + +/obj/abstract/level_data_spawner/admin_level + level_data_type = /datum/level_data/admin_level + +/obj/abstract/level_data_spawner/debug + level_data_type = /datum/level_data/debug + +/obj/abstract/level_data_spawner/mining_level + level_data_type = /datum/level_data/mining_level + + +//////////////////////////////////////////// +// Level Data Implementations +//////////////////////////////////////////// +/datum/level_data/space + +/datum/level_data/debug + name = "Debug Level" + +/datum/level_data/main_level + level_flags = (ZLEVEL_STATION|ZLEVEL_CONTACT|ZLEVEL_PLAYER) + permit_legacy_persistence = TRUE + +/datum/level_data/admin_level + level_flags = (ZLEVEL_ADMIN|ZLEVEL_SEALED) + +/datum/level_data/player_level + level_flags = (ZLEVEL_CONTACT|ZLEVEL_PLAYER) + permit_legacy_persistence = TRUE + +/datum/level_data/unit_test + level_flags = (ZLEVEL_CONTACT|ZLEVEL_PLAYER|ZLEVEL_SEALED) + filler_turf = /turf/unsimulated/dark_filler + +// Used in order to avoid making the level too large. Only works if loaded prior to SSmapping init... it's unclear if this really does much. +/datum/level_data/unit_test/after_template_load(var/datum/map_template/template) + . = ..() + level_max_width ||= template.width + level_max_height ||= template.height + +/datum/level_data/overmap + name = "Sensor Display" + level_flags = ZLEVEL_SEALED + use_global_exterior_ambience = FALSE // Overmap doesn't care about ambient lighting + base_turf = /turf/unsimulated/dark_filler + transition_turf_type = null + +/datum/level_data/mining_level + level_flags = (ZLEVEL_PLAYER|ZLEVEL_SEALED) + var/list/mining_turfs + +/datum/level_data/mining_level/Destroy() + mining_turfs = null + return ..() + +/datum/level_data/mining_level/asteroid + base_turf = /turf/floor/barren + filler_turf = /turf/space + level_generators = list( + /datum/random_map/automata/cave_system, + /datum/random_map/noise/ore + ) + +///Try to allocate the given amount of POIs onto our level. Returns the template types that were spawned +/datum/level_data/proc/spawn_subtemplates(budget = 0, template_category, blacklist, whitelist) + + if(budget <= 0) + return + + var/list/possible_subtemplates = list() + var/list/all_subtemplates = SSmapping.get_templates_by_category(template_category) + for(var/poi_name in all_subtemplates) + var/datum/map_template/poi = all_subtemplates[poi_name] + var/poi_tags = poi.get_template_tags() + if(whitelist && !(whitelist & poi_tags)) + continue + if(blacklist & poi_tags) + continue + possible_subtemplates += poi + + if(!length(possible_subtemplates)) + log_world("Level [level_id] was given no templates to pick from.") + return //If we don't have any templates, don't bother + + var/list/repeatable_templates = list() + var/list/areas_whitelist = get_subtemplate_areas(template_category, blacklist, whitelist) + var/list/candidate_points_of_interest = possible_subtemplates.Copy() + //Each iteration needs to either place a subtemplate or strictly decrease either the budget or templates list length (or break). + while(length(candidate_points_of_interest) && (budget > 0)) + var/datum/map_template/R = pick(candidate_points_of_interest) + if((R.get_template_cost() <= budget) && !LAZYISIN(SSmapping.banned_template_names, R.name) && try_place_subtemplate(R, areas_whitelist)) + LAZYADD(., R) + budget -= R.get_template_cost() + //Mark spawned no-duplicate POI globally + if(!(R.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES)) + LAZYDISTINCTADD(SSmapping.banned_template_names, R.name) + if(R.template_flags & TEMPLATE_FLAG_GENERIC_REPEATABLE) + repeatable_templates |= R + candidate_points_of_interest -= R + + // Generic repeatable templates can be picked again if we have remaining budget. + if(!length(candidate_points_of_interest) && budget > 0 && length(repeatable_templates)) + candidate_points_of_interest = repeatable_templates.Copy() + repeatable_templates = list() + + if(budget > 0) + log_world("Level [level_id] had no templates to pick from with [budget] left to spend.") + +///Attempts several times to find turfs where a subtemplate can be placed. +/datum/level_data/proc/try_place_subtemplate(var/datum/map_template/template, var/list/area_whitelist) + //#FIXME: Isn't trying to fit in a subtemplate by rolling randomly a bit inneficient? + // Try to place it + var/template_full_width = (2 * template_edge_padding) + template.width + var/template_full_height = (2 * template_edge_padding) + template.height + if((template_full_width > level_inner_width) || (template_full_height > level_inner_height)) // Too big and will never fit. + return //Return if it won't even fit on the entire level + + var/template_half_width = template_edge_padding + round(template.width/2) //Half the template size plus the map edge spacing, for testing from the centerpoint + var/template_half_height = template_edge_padding + round(template.height/2) + //Try to fit it in somehwere a few times, then give up if we can't + var/sanity = 20 + while(sanity > 0) + sanity-- + //Pick coordinates inside the level's border within which the template will fit. Including the extra template spacing from the level's borders. + var/cturf_x = rand(level_inner_min_x + template_half_width, level_inner_max_x - template_half_width) + var/cturf_y = rand(level_inner_min_y + template_half_height, level_inner_max_y - template_half_height) + var/turf/T = locate(cturf_x, cturf_y, level_z) + var/valid = TRUE + + //#TODO: There's definitely a way to cache what turfs use an area, to avoid doing this for every single templates! + // Could also probably cache TURF_FLAG_NO_POINTS_OF_INTEREST turfs globally. + var/list/affected_turfs = template.get_affected_turfs(T, TRUE) + for(var/turf/test_turf in affected_turfs) + var/area/A = get_area(test_turf) + if((length(area_whitelist) && !is_type_in_list(A, area_whitelist)) || (test_turf.turf_flags & TURF_FLAG_NO_POINTS_OF_INTEREST)) + valid = FALSE + break //Break out of the turf check loop, and grab a new set of coordinates + if(!valid) + continue + log_world("Spawned template \"[template.name]\", center: ([T.x], [T.y], [T.z]), min: ([T.x - template_half_width], [T.y - template_half_height]), max: ([T.x + template_half_width], [T.y + template_half_height])") + load_subtemplate(T, template) + return template + +///Actually handles loading a template at the given turf. +/datum/level_data/proc/load_subtemplate(turf/central_turf, datum/map_template/template) + if(!template) + return FALSE + template.load(central_turf, centered = TRUE) + return TRUE + +/datum/level_data/proc/update_turf_ambience() + if(SSatoms.atom_init_stage >= INITIALIZATION_INNEW_REGULAR) + for(var/turf/level_turf as anything in block(level_inner_min_x, level_inner_min_y, level_z, level_inner_max_x, level_inner_max_y, level_z)) + level_turf.update_ambient_light_from_z_or_area() // AMBIENCE_QUEUE_TURF(level_turf) - seems to be less consistent + CHECK_TICK diff --git a/code/modules/multiz/level_persistence_handler.dm b/code/modules/multiz/level_persistence_handler.dm new file mode 100644 index 000000000000..39337f5c246d --- /dev/null +++ b/code/modules/multiz/level_persistence_handler.dm @@ -0,0 +1,14 @@ +/decl/serialization_handler/proc/get_data_path(location, map, level) + return "[location]/[map]/[level]" + +/decl/serialization_handler/proc/save_level_data(datum/level_data/level_data, location, map, level) + return // Unimplemented, so return null to indicate a failure + +/decl/serialization_handler/proc/save_data_to_file(filepath, save_data, report_id) + return // Unimplemented, so return null to indicate a failure + +/decl/serialization_handler/proc/load_level_data(location, map, level) + return // Unimplemented, so return null to indicate a failure + +/decl/serialization_handler/proc/load_data_from_file(filepath) + return // Unimplemented, so return null to indicate a failure diff --git a/code/modules/multiz/level_persistence_handler_json.dm b/code/modules/multiz/level_persistence_handler_json.dm new file mode 100644 index 000000000000..bebf101a2b78 --- /dev/null +++ b/code/modules/multiz/level_persistence_handler_json.dm @@ -0,0 +1,46 @@ +/decl/serialization_handler/json/get_data_path(location, map, level) + return "[..()].json" + +/decl/serialization_handler/json/save_level_data(datum/level_data/level_data, location, map, level) + return save_data_to_file(get_data_path(location, map, level), level_data.get_persistent_data(), level_data.level_id) + +/decl/serialization_handler/json/save_data_to_file(filepath, save_data, report_id) + try + if(!length(save_data)) + return 1 + + var/write_data = json_encode(save_data) + var/write_file = file(filepath) + + // Do a backup (at the end to avoid overwriting then throwing an exception) + if(fexists(filepath)) + var/backup_contents = file2text(filepath) + var/backup_file = file("[filepath].[time2text(REALTIMEOFDAY, "YY-MM-DD_hh-mm")].backup") + to_file(backup_file, backup_contents) + // Clear old file to avoid appending data. + // TODO: remove old backups? Leave as an exercise for the admin? + fdel(filepath) + + // Finally, write out our new json. + to_file(write_file, write_data) + report_progress("Saved [length(save_data)] record\s for [report_id].") + + catch(var/exception/E) + error("Exception when saving persistent level data to [filepath]: [EXCEPTION_TEXT(E)]") + return null + + return 1 // Return a non-null value just to show we didn't throw an exception. + +/decl/serialization_handler/json/load_level_data(location, map, level) + return load_data_from_file(get_data_path(location, map, level)) + +/decl/serialization_handler/json/load_data_from_file(filepath) + try + if(fexists(filepath)) // done separately to avoid generating an error for levels with no saved data + var/loaded_json = safe_file2text(filepath) + if(loaded_json) + return json_decode(loaded_json) // do not cache this giant blob pls + catch(var/exception/E) + error("Exception when loading persistent level data from [filepath]: [EXCEPTION_TEXT(E)]") + return null + return 1 // Return a non-null value just to show we didn't throw an exception. \ No newline at end of file diff --git a/code/modules/multiz/level_persistence_serialization.dm b/code/modules/multiz/level_persistence_serialization.dm new file mode 100644 index 000000000000..a72affa8dede --- /dev/null +++ b/code/modules/multiz/level_persistence_serialization.dm @@ -0,0 +1,99 @@ +// General flow of level persistence: +// Saving: +// - SSpersistence periodically iterates the z-level list, finds levels that want to serde, and calls save_persistent_data() +// - Levels return a list of instances to get_persistent_instances(), instances have Serialize() called and return a list of modified fields. +// - Fields are serialized (to JSON with the default handler) and written to disk. +// Loading: +// - SSmapping initializes and calls preload_persistent_data() and load_persistent_data() on relevant /datum/level_data z-level objects. +// - load_persistent_data() creates the base instances and (for atoms) sets __init_deserialisation_payload with the data loaded from tile. +// - SSatoms flush calls Preload() on all deserialized atoms which pre-populates vars on the atom. +// - Ssatoms proceeds to Initialize() atoms as normal. + +var/global/list/level_persistence_ref_map = list() +/datum/level_data + /// String indicating a location for use in serde. Typically a filepath, + /// but not strictly required to be. Implementation is on the handler. + /// If set, will automatically suffix map path and level name. + /// Leave null to opt out of any persistence for this level. + // Example setting would be: + // persistent_data_location = "data/level_data" + VAR_PROTECTED/persistent_data_location + /// Decl handler, mostly forcing myself to keep this general so it can be optimized with a DB or something down the track. + VAR_PRIVATE/persistence_handler = /decl/serialization_handler/json + /// 2D list of coordinates for turfs to serialize. + var/list/changed_turfs + /// Legacy bool. Whether or not this level permits things like graffiti and filth to persist across rounds. + var/permit_legacy_persistence = FALSE + +/datum/level_data/proc/is_persistent() + return !isnull(persistent_data_location) && !isnull(persistence_handler) && !isnull(level_id) + +/datum/level_data/proc/get_persistent_data() + . = list() + var/list/instances_to_save = get_persistent_instances() + if(!length(instances_to_save)) + return + for(var/datum/thing as anything in get_persistent_instances()) + var/serialized_instance = thing.Serialize() + if(length(serialized_instance)) + .[thing.get_run_uid()] = serialized_instance + +// Returns a linear list of instances that we are interested in saving. +/datum/level_data/proc/get_persistent_instances() + for(var/coord in changed_turfs) + + var/list/coord_list = cached_json_decode(coord) + if(!islist(coord_list) || length(coord_list) < 2) + changed_turfs -= coord + continue + + var/turf/turf = locate(coord_list[1], coord_list[2], level_z) + if(!istype(turf) || !turf.ShouldSerialize()) + continue + + for(var/datum/instance in turf.UnpackSerializableInstances()) + if(instance.ShouldSerialize()) + LAZYDISTINCTADD(., instance) + +// First load all the raw data into memory so every reference is populated. +/datum/level_data/proc/preload_persistent_data() + + // Basic sanity check. + if(persistent_data_location && !level_id) + persistent_data_location = null + PRINT_STACK_TRACE("Level data [type] tried to initialize persistent data but had no level_id.") + return FALSE + + // Don't bother if we aren't configured for it at all. + if(!is_persistent()) + return FALSE + + // Atoms on a map are expected to be returned as an associative list with some specific text keys. + try + var/decl/serialization_handler/load_handler = GET_DECL(persistence_handler) + var/list/loaded_data = load_handler?.load_level_data(persistent_data_location, global.using_map.path, ckey(level_id)) + if(islist(loaded_data) && length(loaded_data)) + var/list/instance_map = list() + global.level_persistence_ref_map[level_id] = instance_map + for(var/uid in loaded_data) + instance_map[uid] = loaded_data[uid] + return TRUE + catch(var/exception/E) + PRINT_STACK_TRACE("Exception during '[level_id]' preload: [EXCEPTION_TEXT(E)]") + + return FALSE + +// Now create the instances and register them in the global map. Note that levels +// with no level_id or no persistence handling set will not reach this proc. +// Returns TRUE if it loaded anything; this may imply not needing to run level +// generation for this level (random maps, etc) +/datum/level_data/proc/load_persistent_data() + _has_serde_data = length(instantiate_serialized_data(level_z, "[level_id]/[name]", global.level_persistence_ref_map[level_id])) > 0 + return _has_serde_data + +// Write any data out if we need to. +/datum/level_data/proc/save_persistent_data() + // TODO: block any changes to persistent data structures while save is running? + if(is_persistent()) + var/decl/serialization_handler/save_handler = GET_DECL(persistence_handler) + save_handler?.save_level_data(src, persistent_data_location, global.using_map.path, ckey(level_id)) diff --git a/code/modules/multiz/map_data.dm b/code/modules/multiz/map_data.dm new file mode 100644 index 000000000000..83d4f972daa2 --- /dev/null +++ b/code/modules/multiz/map_data.dm @@ -0,0 +1,29 @@ +/obj/abstract/map_data + name = "Map Data" + desc = "An unknown location." + icon_state = "map_data" + + var/height = 1 ///< The number of Z-Levels in the map. + +// If the height is more than 1, we mark all contained levels as connected. +// This initializes immediately because it is an auxiliary effect specifically needed pre-SSatoms init. +INITIALIZE_IMMEDIATE(/obj/abstract/map_data) +/obj/abstract/map_data/Initialize(mapload, _height) + if(!istype(loc)) // Using loc.z is safer when using the maploader and New. + return INITIALIZE_HINT_QDEL + if(_height) + height = _height + for(var/i = (loc.z - height + 1) to (loc.z-1)) + if (z_levels.len = FLUID_DEEP) || T.get_fluid_depth() >= FLUID_MAX_DEPTH) + if(can_float()) + return TRUE + for(var/atom/climbable in src.loc) + if((climbable.atom_flags & ATOM_FLAG_CLIMBABLE) && climbable.can_climb(src, silent = TRUE)) + return TRUE + //Last check, list of items that could plausibly be used to climb but aren't climbable themselves + var/static/list/objects_to_stand_on = list( + /obj/item/stool, + /obj/structure/bed, + ) + for(var/type in objects_to_stand_on) + if(locate(type) in src.loc) + return TRUE + return FALSE //FALLING STUFF @@ -96,16 +82,13 @@ return var/turf/T = loc - if(!T.CanZPass(src, DOWN) || !below.CanZPass(src, DOWN)) + if(!T.CanZPass(src, DOWN)) return // No gravity in space, apparently. if(!has_gravity()) return - if(throwing) - return - if(can_fall()) begin_falling(lastloc, below) @@ -113,7 +96,8 @@ // Entered() which is part of Move(), by spawn()ing we let that complete. But we want to preserve if we were in client movement // or normal movement so other move behavior can continue. /atom/movable/proc/begin_falling(var/lastloc, var/below) - addtimer(CALLBACK(src, /atom/movable/proc/fall_callback, below), 0) + moving_diagonally = FALSE // cancel diagonal movement immediately + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, fall_callback), below), 0) /atom/movable/proc/fall_callback(var/turf/below) if(!QDELETED(src)) @@ -126,8 +110,8 @@ moving = FALSE //For children to override -/atom/movable/proc/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) - if(!simulated) +/atom/movable/proc/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + if(immune_to_floor_hazards()) return FALSE if(anchored && !anchor_bypass) @@ -144,20 +128,25 @@ if(!A.CanPass(src, location_override)) return FALSE + //We cannot sink if we can swim + if(location_override.get_fluid_depth() >= FLUID_DEEP && (below == loc)) + if(!(below.get_fluid_depth() >= 0.95 * FLUID_MAX_DEPTH)) //No salmon skipping up a stream of falling water + return TRUE + return !can_float() return TRUE -/obj/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) - return ..(anchor_fall) +/obj/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + return ..(anchor_fall, location_override) -/obj/effect/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) +/obj/effect/can_fall(anchor_bypass = FALSE, turf/location_override = loc) return FALSE -/obj/effect/decal/cleanable/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) +/obj/effect/decal/cleanable/can_fall(anchor_bypass = FALSE, turf/location_override = loc) return TRUE -/obj/item/pipe/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) - var/turf/simulated/open/below = loc +/obj/item/pipe/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + var/turf/open/below = loc below = below.below . = ..() @@ -168,46 +157,102 @@ if((locate(/obj/structure/disposalpipe/up) in below) || locate(/obj/machinery/atmospherics/pipe/zpipe/up) in below) return FALSE -/mob/living/carbon/human/can_fall(var/anchor_bypass = FALSE, var/turf/location_override = loc) - if(..()) - return species.can_fall(src) +/mob/living/can_fall(anchor_bypass = FALSE, turf/location_override = loc) + if((. = ..())) + var/decl/species/my_species = get_species() + if(my_species) + return my_species.can_fall(src) + +/atom/movable/proc/protected_from_fall_damage(var/turf/landing) + // Stairs and ramps will not save you from a high drop. + if(get_fall_height() <= 1) + if(!!(locate(/obj/structure/stairs) in landing)) + return TRUE + var/turf/wall/natural/ramp = landing + if(istype(ramp) && ramp.ramp_slope_direction) // walking down a ramp + return TRUE + return FALSE -/atom/movable/proc/handle_fall(var/turf/landing) - forceMove(landing) - if(locate(/obj/structure/stairs) in landing) - return 1 +/mob/protected_from_fall_damage(var/turf/landing) + . = ..() + if(!.) + // This is very silly, but it can be refined and made more appropriate as our multiz turf system is expanded. + var/obj/item/backpack/parachute/parachute = get_equipped_item(slot_back_str) + if(istype(parachute) && parachute.packed) + parachute.packed = FALSE + return TRUE + +/atom/movable + var/started_falling_from_z + +/atom/movable/proc/get_fall_height() + . = 0 + var/turf/T = get_turf(src) + if(istype(T) && T.z <= started_falling_from_z) + for(var/fall_z in T.z to started_falling_from_z) + var/datum/level_data/level_data = SSmapping.levels_by_z[fall_z] + . += max(1, level_data?.fall_depth) + +/atom/movable/proc/handle_fall(var/turf/landing, var/fall_distance) + var/turf/previous = get_turf(loc) + Move(landing, get_dir(previous, landing)) + started_falling_from_z = max(started_falling_from_z, landing.z) + if(protected_from_fall_damage(landing)) + . = TRUE + else if(landing.get_fluid_depth() >= FLUID_DEEP) + var/primary_fluid = landing.get_fluid_name() + if(previous.get_fluid_depth() >= FLUID_DEEP) //We're sinking further + visible_message(SPAN_NOTICE("\The [src] sinks deeper down into \the [primary_fluid]!"), SPAN_NOTICE("\The [primary_fluid] rushes around you as you sink!")) + playsound(previous, pick(SSfluids.gurgles), 50, 1) + else + visible_message(SPAN_NOTICE("\The [src] falls into the [primary_fluid]!"), SPAN_NOTICE("What a splash!")) + playsound(src, 'sound/effects/watersplash.ogg', 30, TRUE) + . = TRUE else - handle_fall_effect(landing) + . = handle_fall_effect(landing) + if(.) + started_falling_from_z = 0 /atom/movable/proc/handle_fall_effect(var/turf/landing) - if(istype(landing, /turf/simulated/open)) - visible_message("\The [src] falls through \the [landing]!", "You hear a whoosh of displaced air.") + SHOULD_CALL_PARENT(TRUE) + if(istype(landing) && can_fall() && landing.CanZPass(src, DOWN)) + visible_message( + SPAN_NOTICE("\The [src] falls through \the [landing]!"), + "You hear a whoosh of displaced air." + ) else - visible_message("\The [src] slams into \the [landing]!", "You hear something slam into the [GLOB.using_map.ground_noun].") - if(fall_damage()) + visible_message( + SPAN_DANGER("\The [src] slams into [landing.is_open() ? "\the [landing]" : "an obstacle"]!"), + "You hear something slam into the [global.using_map.ground_noun]." + ) + var/fall_damage = fall_damage() * get_fall_height() + if(fall_damage > 0) for(var/mob/living/M in landing.contents) if(M == src) continue - visible_message("\The [src] hits \the [M.name]!") - M.take_overall_damage(fall_damage()) + visible_message("\The [src] hits \the [M]!") + M.take_overall_damage(fall_damage) + return TRUE + return FALSE /atom/movable/proc/fall_damage() return 0 /obj/fall_damage() - if(w_class == ITEM_SIZE_TINY) + if(w_class <= ITEM_SIZE_TINY) return 0 - if(w_class >= ITEM_SIZE_NO_CONTAINER) + if(w_class >= ITEM_SIZE_GARGANTUAN) return 100 return BASE_STORAGE_COST(w_class) -/mob/living/carbon/human/handle_fall_effect(var/turf/landing) +/mob/living/human/apply_fall_damage(var/turf/landing) + if(status_flags & GODMODE) + return if(species && species.handle_fall_special(src, landing)) return - - ..() - var/min_damage = 7 - var/max_damage = 14 + var/fall_height = get_fall_height() + var/min_damage = 7 * fall_height + var/max_damage = 14 * fall_height apply_damage(rand(min_damage, max_damage), BRUTE, BP_HEAD, armor_pen = 50) apply_damage(rand(min_damage, max_damage), BRUTE, BP_CHEST, armor_pen = 50) apply_damage(rand(min_damage, max_damage), BRUTE, BP_GROIN, armor_pen = 75) @@ -217,32 +262,24 @@ apply_damage(rand(min_damage, max_damage), BRUTE, BP_R_FOOT, armor_pen = 100) apply_damage(rand(min_damage, max_damage), BRUTE, BP_L_ARM, armor_pen = 75) apply_damage(rand(min_damage, max_damage), BRUTE, BP_R_ARM, armor_pen = 75) - weakened = max(weakened, 3) + SET_STATUS_MAX(src, STAT_WEAK, 3) if(prob(skill_fail_chance(SKILL_HAULING, 40, SKILL_EXPERT, 2))) var/list/victims = list() for(var/tag in list(BP_L_FOOT, BP_R_FOOT, BP_L_ARM, BP_R_ARM)) - var/obj/item/organ/external/E = get_organ(tag) - if(E && !E.is_stump() && !E.dislocated && !BP_IS_PROSTHETIC(E)) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(src, tag) + if(E && !E.is_dislocated() && (E.limb_flags & ORGAN_FLAG_CAN_DISLOCATE) && !BP_IS_PROSTHETIC(E)) victims += E if(victims.len) var/obj/item/organ/external/victim = pick(victims) victim.dislocate() to_chat(src, "You feel a sickening pop as your [victim.joint] is wrenched out of the socket.") - if(client) - var/area/A = get_area(landing) - if(A) - A.alert_on_fall(src) - updatehealth() - - -/mob/living/carbon/human/proc/climb_up(atom/A) +/mob/living/human/proc/climb_up(atom/A) if(!isturf(loc) || !bound_overlay || bound_overlay.destruction_timer || is_physically_disabled()) // This destruction_timer check ideally wouldn't be required, but I'm not awake enough to refactor this to not need it. return FALSE var/turf/T = get_turf(A) - var/turf/above = GetAbove(src) - if(above && T.Adjacent(bound_overlay) && above.CanZPass(src, UP)) //Certain structures will block passage from below, others not + if(T.Adjacent(bound_overlay) && T.CanZPass(src, UP)) //Certain structures will block passage from below, others not if(loc.has_gravity() && !can_overcome_gravity()) return FALSE @@ -259,21 +296,60 @@ set desc = "If you want to know what's above." set category = "IC" - if(client && !is_physically_disabled()) - if(z_eye) - reset_view(null) - qdel(z_eye) - z_eye = null - return - var/turf/above = GetAbove(src) - if(istype(above) && above.is_open()) - z_eye = new /atom/movable/z_observer/z_up(src, src) - to_chat(src, "You look up.") - reset_view(z_eye) + if(!client || is_physically_disabled()) + to_chat(src, SPAN_WARNING("You can't look up right now.")) + return + + if(z_eye) + reset_view(null) + qdel(z_eye) + z_eye = null + return + + var/turf/above = GetAbove(src) + if(istype(above) && TURF_IS_MIMICKING(above)) + z_eye = new /atom/movable/z_observer/z_up(src, src) + to_chat(src, SPAN_NOTICE("You look up.")) + reset_view(z_eye) + return + + if(above) + to_chat(src, SPAN_NOTICE("You can see \the [above].")) + return + + check_sky() + +/mob/living/verb/check_sky() + set name = "Check Sky" + set category = "IC" + if(!client || is_physically_disabled() || !isturf(loc)) + to_chat(src, SPAN_WARNING("You can't check the sky right now.")) + return + + var/turf/my_turf = loc + if(!my_turf.is_outside()) + var/cannot_see_outside = TRUE + for(var/turf/neighbor in view(3, src)) + if(neighbor.is_outside()) + cannot_see_outside = FALSE + break + if(cannot_see_outside) + to_chat(src, SPAN_WARNING("You are indoors, and cannot see the sky from here.")) return - to_chat(src, "You can see \the [above ? above : "ceiling"].") + + var/obj/abstract/weather_system/weather = SSweather.weather_by_z[my_turf.z] + var/decl/state/weather/current_weather = weather?.weather_system?.current_state + if(istype(current_weather) && current_weather.descriptor) + to_chat(src, SPAN_NOTICE(current_weather.descriptor)) + else + to_chat(src, SPAN_NOTICE("The weather is indeterminate.")) + + var/datum/level_data/level = SSmapping.levels_by_z[my_turf.z] + var/datum/daycycle/daycycle = level?.daycycle_id && SSdaycycle.get_daycycle(level.daycycle_id) + if(daycycle?.current_period?.name) + to_chat(src, SPAN_NOTICE("It is currently [daycycle.current_period.name].")) else - to_chat(src, "You can't look up right now.") + to_chat(src, SPAN_NOTICE("The time of day is indeterminate.")) /mob/living/verb/lookdown() set name = "Look Down" @@ -287,7 +363,7 @@ z_eye = null return var/turf/T = get_turf(src) - if(T && T.is_open() && HasBelow(T.z)) + if(T && TURF_IS_MIMICKING(T) && HasBelow(T.z)) z_eye = new /atom/movable/z_observer/z_down(src, src) to_chat(src, "You look down.") reset_view(z_eye) @@ -296,6 +372,22 @@ else to_chat(src, "You can't look below right now.") +//Swimming and floating +/atom/movable/proc/can_float() + return FALSE + +/mob/living/can_float() + return !is_physically_disabled() + +/mob/living/simple_animal/can_float() + return is_aquatic + +/mob/living/human/can_float() + return species.can_float(src) + +/mob/living/silicon/can_float() + return FALSE //If they can fly otherwise it will be checked first + /mob/living var/atom/movable/z_observer/z_eye @@ -310,7 +402,7 @@ . = ..() owner = user follow() - GLOB.moved_event.register(owner, src, /atom/movable/z_observer/proc/follow) + events_repository.register(/decl/observ/moved, owner, src, TYPE_PROC_REF(/atom/movable/z_observer, follow)) /atom/movable/z_observer/proc/follow() @@ -318,7 +410,7 @@ forceMove(get_step(owner, UP)) if(isturf(src.loc)) var/turf/T = src.loc - if(T.is_open()) + if(T && TURF_IS_MIMICKING(T)) return owner.reset_view(null) owner.z_eye = null @@ -327,29 +419,20 @@ /atom/movable/z_observer/z_down/follow() forceMove(get_step(owner, DOWN)) var/turf/T = get_turf(owner) - if(T && T.is_open()) + if(T && TURF_IS_MIMICKING(T)) return owner.reset_view(null) owner.z_eye = null qdel(src) /atom/movable/z_observer/Destroy() - GLOB.moved_event.unregister(owner, src, /atom/movable/z_observer/proc/follow) + events_repository.unregister(/decl/observ/moved, owner, src, TYPE_PROC_REF(/atom/movable/z_observer, follow)) owner = null . = ..() -/atom/movable/z_observer/can_fall() +/atom/movable/z_observer/can_fall(anchor_bypass = FALSE, turf/location_override = loc) return FALSE /atom/movable/z_observer/explosion_act() SHOULD_CALL_PARENT(FALSE) return - -/atom/movable/z_observer/singularity_act() - return - -/atom/movable/z_observer/singularity_pull() - return - -/atom/movable/z_observer/singuloCanEat() - return \ No newline at end of file diff --git a/code/modules/multiz/pipes.dm b/code/modules/multiz/pipes.dm index b9923dcb5c0f..4f972191a0df 100644 --- a/code/modules/multiz/pipes.dm +++ b/code/modules/multiz/pipes.dm @@ -1,35 +1,21 @@ //////////////////////////// // parent class for pipes // //////////////////////////// -obj/machinery/atmospherics/pipe/zpipe +/obj/machinery/atmospherics/pipe/zpipe icon = 'icons/obj/pipe-item.dmi' icon_state = "up" name = "upwards pipe" desc = "A pipe segment to connect upwards." - volume = 70 + gas_volume = 70 dir = SOUTH initialize_directions = SOUTH - var/minimum_temperature_difference = 300 - var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No + level = LEVEL_BELOW_PLATING - level = 1 - -/obj/machinery/atmospherics/pipe/zpipe/hide(var/i) - if(istype(loc, /turf/simulated)) - set_invisibility(i ? 101 : 0) - update_icon() - -obj/machinery/atmospherics/pipe/zpipe/Process() - if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle - ..() - else - . = PROCESS_KILL - -obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure) +/obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure) var/datum/gas_mixture/environment = loc.return_air() var/pressure_difference = pressure - environment.return_pressure() @@ -44,7 +30,7 @@ obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure) else return 1 -obj/machinery/atmospherics/pipe/zpipe/proc/burst() +/obj/machinery/atmospherics/pipe/zpipe/proc/burst() src.visible_message("\The [src] bursts!"); playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) var/datum/effect/effect/system/smoke_spread/smoke = new @@ -52,109 +38,49 @@ obj/machinery/atmospherics/pipe/zpipe/proc/burst() smoke.start() qdel(src) // NOT qdel. -obj/machinery/atmospherics/pipe/zpipe/Destroy() - if(node1) - node1.disconnect(src) - if(node2) - node2.disconnect(src) - . = ..() - -obj/machinery/atmospherics/pipe/zpipe/pipeline_expansion() - return list(node1, node2) - -obj/machinery/atmospherics/pipe/zpipe/on_update_icon() - return +/obj/machinery/atmospherics/pipe/zpipe/on_update_icon() + color = get_color() -obj/machinery/atmospherics/pipe/zpipe/disconnect(obj/machinery/atmospherics/reference) - if(reference == node1) - if(istype(node1, /obj/machinery/atmospherics/pipe)) - qdel(parent) - node1 = null - - if(reference == node2) - if(istype(node2, /obj/machinery/atmospherics/pipe)) - qdel(parent) - node2 = null - - return null ///////////////////////// // the elusive up pipe // ///////////////////////// -obj/machinery/atmospherics/pipe/zpipe/up +/obj/machinery/atmospherics/pipe/zpipe/up icon_state = "up" name = "upwards pipe" desc = "A pipe segment to connect upwards." -obj/machinery/atmospherics/pipe/zpipe/up/atmos_init() +/obj/machinery/atmospherics/pipe/zpipe/up/atmos_init() ..() - var/node1_dir - - for(var/direction in GLOB.cardinal) - if(direction&initialize_directions) - if (!node1_dir) - node1_dir = direction - - for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) - if(target.initialize_directions & get_dir(target,src)) - if (check_connect_types(target,src)) - node1 = target - break - var/turf/above = GetAbove(src) if(above) for(var/obj/machinery/atmospherics/target in above) - if(target.initialize_directions && istype(target, /obj/machinery/atmospherics/pipe/zpipe/down)) - if (check_connect_types(target,src)) - node2 = target - break - - - var/turf/T = src.loc // hide if turf is not intact - hide(!T.is_plating()) + if(istype(target, /obj/machinery/atmospherics/pipe/zpipe/down) && check_connect_types(target,src)) + LAZYDISTINCTADD(nodes_to_networks, target) /////////////////////// // and the down pipe // /////////////////////// -obj/machinery/atmospherics/pipe/zpipe/down +/obj/machinery/atmospherics/pipe/zpipe/down icon_state = "down" name = "downwards pipe" desc = "A pipe segment to connect downwards." -obj/machinery/atmospherics/pipe/zpipe/down/atmos_init() +/obj/machinery/atmospherics/pipe/zpipe/down/atmos_init() ..() - var/node1_dir - - for(var/direction in GLOB.cardinal) - if(direction&initialize_directions) - if (!node1_dir) - node1_dir = direction - - for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) - if(target.initialize_directions & get_dir(target,src)) - if (check_connect_types(target,src)) - node1 = target - break - var/turf/below = GetBelow(src) if(below) for(var/obj/machinery/atmospherics/target in below) - if(target.initialize_directions && istype(target, /obj/machinery/atmospherics/pipe/zpipe/up)) - if (check_connect_types(target,src)) - node2 = target - break - - - var/turf/T = src.loc // hide if turf is not intact - hide(!T.is_plating()) + if(istype(target, /obj/machinery/atmospherics/pipe/zpipe/up) && check_connect_types(target,src)) + LAZYDISTINCTADD(nodes_to_networks, target) /////////////////////// // supply/scrubbers // /////////////////////// -obj/machinery/atmospherics/pipe/zpipe/up/scrubbers +/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers icon_state = "up-scrubbers" name = "upwards scrubbers pipe" desc = "A scrubbers pipe segment to connect upwards." @@ -162,7 +88,7 @@ obj/machinery/atmospherics/pipe/zpipe/up/scrubbers icon_connect_type = "-scrubbers" color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/zpipe/up/supply +/obj/machinery/atmospherics/pipe/zpipe/up/supply icon_state = "up-supply" name = "upwards supply pipe" desc = "A supply pipe segment to connect upwards." @@ -170,7 +96,7 @@ obj/machinery/atmospherics/pipe/zpipe/up/supply icon_connect_type = "-supply" color = PIPE_COLOR_BLUE -obj/machinery/atmospherics/pipe/zpipe/down/scrubbers +/obj/machinery/atmospherics/pipe/zpipe/down/scrubbers icon_state = "down-scrubbers" name = "downwards scrubbers pipe" desc = "A scrubbers pipe segment to connect downwards." @@ -178,7 +104,7 @@ obj/machinery/atmospherics/pipe/zpipe/down/scrubbers icon_connect_type = "-scrubbers" color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/zpipe/down/supply +/obj/machinery/atmospherics/pipe/zpipe/down/supply icon_state = "down-supply" name = "downwards supply pipe" desc = "A supply pipe segment to connect downwards." @@ -187,28 +113,26 @@ obj/machinery/atmospherics/pipe/zpipe/down/supply color = PIPE_COLOR_BLUE // Colored misc. pipes -obj/machinery/atmospherics/pipe/zpipe/up/cyan +/obj/machinery/atmospherics/pipe/zpipe/up/cyan color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/zpipe/down/cyan +/obj/machinery/atmospherics/pipe/zpipe/down/cyan color = PIPE_COLOR_CYAN -obj/machinery/atmospherics/pipe/zpipe/up/red +/obj/machinery/atmospherics/pipe/zpipe/up/red color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/zpipe/down/red +/obj/machinery/atmospherics/pipe/zpipe/down/red color = PIPE_COLOR_RED -obj/machinery/atmospherics/pipe/zpipe/up/fuel +/obj/machinery/atmospherics/pipe/zpipe/up/fuel name = "upwards fuel pipe" color = PIPE_COLOR_ORANGE - maximum_pressure = 420*ONE_ATMOSPHERE - fatigue_pressure = 350*ONE_ATMOSPHERE - alert_pressure = 350*ONE_ATMOSPHERE + maximum_pressure = 420 ATM + fatigue_pressure = 350 ATM connect_types = CONNECT_TYPE_FUEL -obj/machinery/atmospherics/pipe/zpipe/down/fuel +/obj/machinery/atmospherics/pipe/zpipe/down/fuel name = "downwards fuel pipe" color = PIPE_COLOR_ORANGE - maximum_pressure = 420*ONE_ATMOSPHERE - fatigue_pressure = 350*ONE_ATMOSPHERE - alert_pressure = 350*ONE_ATMOSPHERE + maximum_pressure = 420 ATM + fatigue_pressure = 350 ATM connect_types = CONNECT_TYPE_FUEL diff --git a/code/modules/multiz/stairs.dm b/code/modules/multiz/stairs.dm new file mode 100644 index 000000000000..c93c6f50229b --- /dev/null +++ b/code/modules/multiz/stairs.dm @@ -0,0 +1,104 @@ +/obj/structure/stairs + name = "stairs" + desc = "Stairs leading to another deck. Not too useful if the gravity goes out." + icon = 'icons/obj/stairs.dmi' + density = FALSE + opacity = FALSE + anchored = TRUE + layer = RUNE_LAYER + +/obj/structure/stairs/Initialize() + for(var/turf/turf in locs) + var/turf/above = GetAbove(turf) + if(!istype(above)) + warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])") + return INITIALIZE_HINT_QDEL + if(!above.is_open()) + above.ChangeTurf(/turf/space) // This will be resolved to the appropriate open space type by ChangeTurf(). + . = ..() + +/obj/structure/stairs/CheckExit(atom/movable/mover, turf/target) + if((get_dir(loc, target) == dir) && (get_turf(mover) == loc)) + return FALSE + return ..() + +/obj/structure/stairs/Bumped(atom/movable/A) + var/turf/myturf = get_turf(src) + var/turf/target = get_step(GetAbove(A), dir) + var/turf/source = get_turf(A) + if(myturf.CanZPass(A, UP) && target.Enter(A, src)) + A.forceMove(target) + if(isliving(A)) + var/mob/living/L = A + for(var/obj/item/grab/grab as anything in L.get_active_grabs()) + grab.affecting.forceMove(target) + if(ishuman(A)) + var/mob/living/human/H = A + if(H.has_footsteps()) + playsound(source, 'sound/effects/stairs_step.ogg', 50) + playsound(target, 'sound/effects/stairs_step.ogg', 50) + else + to_chat(A, SPAN_WARNING("Something blocks the path.")) + +/obj/structure/stairs/CanPass(obj/mover, turf/source, height, airflow) + return airflow || !density + +/obj/structure/stairs/catwalk + name = "catwalk stairs" + icon_state = "catwalk" + +// type paths to make mapping easier. +/obj/structure/stairs/north + dir = NORTH + +/obj/structure/stairs/south + dir = SOUTH + +/obj/structure/stairs/east + dir = EAST + +/obj/structure/stairs/west + dir = WEST + +/obj/structure/stairs/long + icon = 'icons/obj/stairs_64.dmi' + bound_height = 64 + appearance_flags = /obj/structure/stairs::appearance_flags & ~TILE_BOUND + +/obj/structure/stairs/long/north + dir = NORTH + bound_y = -32 + pixel_y = -32 + +/obj/structure/stairs/long/east + dir = EAST + bound_width = 64 + bound_height = 32 + bound_x = -32 + pixel_x = -32 + +/obj/structure/stairs/long/west + dir = WEST + bound_width = 64 + bound_height = 32 + +/obj/structure/stairs/long/catwalk + name = "catwalk stairs" + icon_state = "catwalk" + +/obj/structure/stairs/long/catwalk/north + dir = NORTH + bound_y = -32 + pixel_y = -32 + +/obj/structure/stairs/long/catwalk/east + dir = EAST + bound_width = 64 + bound_height = 32 + bound_x = -32 + pixel_x = -32 + +/obj/structure/stairs/long/catwalk/west + dir = WEST + bound_width = 64 + bound_height = 32 \ No newline at end of file diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm deleted file mode 100644 index a5f2f75e341e..000000000000 --- a/code/modules/multiz/structures.dm +++ /dev/null @@ -1,343 +0,0 @@ -////////////////////////////// -//Contents: Ladders, Stairs.// -////////////////////////////// - -/obj/structure/ladder - name = "ladder" - desc = "A ladder. You can climb it up and down." - icon_state = "ladder01" - icon = 'icons/obj/structures/ladders.dmi' - density = FALSE - opacity = FALSE - anchored = TRUE - obj_flags = OBJ_FLAG_NOFALL - material = /decl/material/solid/metal/aluminium - tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT | TOOL_INTERACTION_ANCHOR - material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME - - var/base_icon = "ladder" - var/draw_shadow = TRUE - var/obj/structure/ladder/target_up - var/obj/structure/ladder/target_down - var/climb_time = 2 SECONDS - var/static/list/climbsounds = list('sound/effects/ladder.ogg','sound/effects/ladder2.ogg','sound/effects/ladder3.ogg','sound/effects/ladder4.ogg') - -/obj/structure/ladder/handle_default_wrench_attackby() - var/last_anchored = anchored - . = ..() - if(anchored != last_anchored) - find_connections() - -/obj/structure/ladder/Initialize(maploading, material) - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/structure/ladder/LateInitialize(maploading, material) - if(maploading) - for(var/obj/structure/ladder/ladder in loc) - if(ladder != src) - qdel(ladder) - if(HasBelow(z) && (locate(/obj/structure/ladder) in GetBelow(src))) - var/turf/T = get_turf(src) - T.ReplaceWithLattice() - find_connections() - set_extension(src, /datum/extension/turf_hand) - -/obj/structure/ladder/proc/find_connections() - - if(target_down) - if(target_down.target_up == src) - target_down.target_up = null - target_down.update_icon() - target_down = null - if(target_up) - if(target_up.target_down == src) - target_up.target_down = null - target_up.update_icon() - target_up = null - - if(anchored) - if(HasBelow(z) && istype(loc, /turf/simulated/open)) - var/failed - for(var/obj/structure/catwalk/catwalk in loc) - if(catwalk.plated_tile) - failed = TRUE - break - if(!failed) - for(var/obj/structure/ladder/ladder in GetBelow(src)) - if(ladder.anchored && !ladder.target_up) - target_down = ladder - target_down.target_up = src - target_down.update_icon() - break - if(HasAbove(z)) - var/turf/T = GetAbove(src) - if(istype(T, /turf/simulated/open)) - var/failed - for(var/obj/structure/catwalk/catwalk in T) - if(catwalk.plated_tile) - failed = TRUE - break - if(!failed) - for(var/obj/structure/ladder/ladder in T) - if(ladder.anchored && !ladder.target_down) - target_up = ladder - target_up.target_down = src - target_up.update_icon() - break - update_icon() - -/obj/structure/ladder/Destroy() - if(target_down) - if(target_down.target_up == src) - target_down.target_up = null - target_down.update_icon() - target_down = null - if(target_up) - if(target_up.target_down == src) - target_up.target_down = null - target_up.update_icon() - target_up = null - return ..() - -/obj/structure/ladder/attackby(obj/item/I, mob/user) - . = ..() - if(!.) - climb(user, I) - -/turf/hitby(atom/movable/AM) - if(isobj(AM)) - var/obj/structure/ladder/L = locate() in contents - if(L) - L.hitby(AM) - return - ..() - -/obj/structure/ladder/hitby(obj/item/I) - if(!target_down) - return - if(!has_gravity()) - return - var/atom/blocker - var/turf/landing = get_turf(target_down) - if(!istype(landing)) - return - for(var/atom/A in landing) - if(!A.CanPass(I, I.loc, 1.5, 0)) - blocker = A - break - if(!blocker) - visible_message(SPAN_DANGER("\The [I] goes down \the [src]!")) - I.forceMove(landing) - landing.visible_message(SPAN_DANGER("\The [I] falls from the top of \the [target_down]!")) - -/obj/structure/ladder/attack_hand(var/mob/M) - climb(M) - -/obj/structure/ladder/attack_ai(var/mob/M) - var/mob/living/silicon/ai/ai = M - if(!istype(ai)) - return - var/mob/observer/eye/AIeye = ai.eyeobj - if(istype(AIeye)) - instant_climb(AIeye) - -/obj/structure/ladder/attack_robot(var/mob/M) - climb(M) - -/obj/structure/ladder/proc/instant_climb(var/mob/M) - var/atom/target_ladder = getTargetLadder(M) - if(target_ladder) - M.dropInto(target_ladder.loc) - -/obj/structure/ladder/proc/climb(mob/M, obj/item/I) - if(!M.may_climb_ladders(src)) - return - - var/obj/structure/ladder/target_ladder = getTargetLadder(M) - if(!target_ladder) - return - - if(!M.Move(get_turf(src))) - to_chat(M, SPAN_NOTICE("You fail to reach \the [src].")) - return - - add_fingerprint(M) - - for(var/obj/item/grab/G in M.get_active_grabs()) - G.adjust_position() - - var/direction = target_ladder == target_up ? "up" : "down" - M.visible_message(SPAN_NOTICE("\The [M] begins climbing [direction] \the [src].")) - target_ladder.audible_message(SPAN_NOTICE("You hear something coming [direction] \the [src].")) - if(do_after(M, climb_time, src)) - climbLadder(M, target_ladder, I) - for (var/obj/item/grab/G in M) - G.adjust_position(force = 1) - -/obj/structure/ladder/attack_ghost(var/mob/M) - instant_climb(M) - -/obj/structure/ladder/proc/getTargetLadder(var/mob/M) - if(!anchored) - to_chat(M, SPAN_WARNING("\The [src] is not anchored in place and cannot be climbed.")) - return - find_connections() - if(!target_up && !target_down) - to_chat(M, SPAN_WARNING("\The [src] does not seem to lead anywhere.")) - else if(target_down && target_up) - var/direction = input(M,"Do you want to go up or down?", "Up or down the ladder?") as null|anything in list("up", "down") - if(!direction) - return - if(!M.may_climb_ladders(src)) - return - . = (direction == "up") ? target_up : target_down - else - . = target_down || target_up - - if(.) - if(. == target_up) - if(!istype(target_up.loc, /turf/simulated/open)) - to_chat(M, SPAN_WARNING("The ceiling is in the way!")) - return null - for(var/obj/structure/catwalk/catwalk in target_up.loc) - if(catwalk.plated_tile) - to_chat(M, SPAN_WARNING("\The [catwalk] is in the way!")) - return null - if(. == target_down) - if(!istype(loc, /turf/simulated/open)) - to_chat(M, SPAN_WARNING("\The [loc] is in the way!")) - return null - for(var/obj/structure/catwalk/catwalk in loc) - if(catwalk.plated_tile) - to_chat(M, SPAN_WARNING("\The [catwalk] is in the way!")) - return null - -/mob/proc/may_climb_ladders(var/ladder) - if(!Adjacent(ladder)) - to_chat(src, SPAN_WARNING("You need to be next to \the [ladder] to start climbing.")) - return FALSE - if(incapacitated()) - to_chat(src, SPAN_WARNING("You are physically unable to climb \the [ladder].")) - return FALSE - var/carry_count = 0 - for(var/obj/item/grab/G in get_active_grabs()) - to_chat(src, SPAN_WARNING("You can't carry \the [G.affecting] up \the [ladder].")) - return FALSE - if(carry_count > 1) - to_chat(src, SPAN_WARNING("You can't carry more than one person up \the [ladder].")) - return FALSE - - return TRUE - -/mob/observer/ghost/may_climb_ladders(var/ladder) - return TRUE - -/obj/structure/ladder/proc/climbLadder(mob/user, target_ladder, obj/item/I = null) - var/turf/T = get_turf(target_ladder) - for(var/atom/A in T) - if(!A.CanPass(user, user.loc, 1.5, 0)) - to_chat(user, SPAN_NOTICE("\The [A] is blocking \the [src].")) - //We cannot use the ladder, but we probably can remove the obstruction - var/atom/movable/M = A - if(istype(M) && M.movable_flags & MOVABLE_FLAG_Z_INTERACT) - if(isnull(I)) - M.attack_hand(user) - else - M.attackby(I, user) - return FALSE - playsound(src, pick(climbsounds), 50) - playsound(target_ladder, pick(climbsounds), 50) - return user.Move(T) - -/obj/structure/ladder/CanPass(obj/mover, turf/source, height, airflow) - return airflow || !density - -/obj/structure/ladder/on_update_icon() - . = ..() - if(!anchored) - icon_state = "[base_icon]00" - else - icon_state = "[base_icon][!!target_up][!!target_down]" - if(target_down && draw_shadow) - var/image/I = image(icon, "downward_shadow") - I.appearance_flags |= RESET_COLOR - underlays = list(I) - else - underlays.Cut() - -/obj/structure/stairs - name = "stairs" - desc = "Stairs leading to another deck. Not too useful if the gravity goes out." - icon = 'icons/obj/stairs.dmi' - density = 0 - opacity = 0 - anchored = 1 - layer = RUNE_LAYER - -/obj/structure/stairs/Initialize() - for(var/turf/turf in locs) - var/turf/simulated/open/above = GetAbove(turf) - if(!above) - warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])") - return INITIALIZE_HINT_QDEL - if(!istype(above)) - above.ChangeTurf(/turf/simulated/open) - . = ..() - -/obj/structure/stairs/CheckExit(atom/movable/mover, turf/target) - if(get_dir(loc, target) == dir && upperStep(mover.loc)) - return FALSE - return ..() - -/obj/structure/stairs/Bumped(atom/movable/A) - var/turf/target = get_step(GetAbove(A), dir) - var/turf/source = A.loc - var/turf/above = GetAbove(A) - if(above.CanZPass(source, UP) && target.Enter(A, src)) - A.forceMove(target) - if(isliving(A)) - var/mob/living/L = A - for(var/obj/item/grab/G in L.get_active_grabs()) - G.affecting.forceMove(target) - if(ishuman(A)) - var/mob/living/carbon/human/H = A - if(H.has_footsteps()) - playsound(source, 'sound/effects/stairs_step.ogg', 50) - playsound(target, 'sound/effects/stairs_step.ogg', 50) - else - to_chat(A, SPAN_WARNING("Something blocks the path.")) - -/obj/structure/stairs/proc/upperStep(var/turf/T) - return (T == loc) - -/obj/structure/stairs/CanPass(obj/mover, turf/source, height, airflow) - return airflow || !density - -// type paths to make mapping easier. -/obj/structure/stairs/north - dir = NORTH - bound_height = 64 - bound_y = -32 - pixel_y = -32 - -/obj/structure/stairs/south - dir = SOUTH - bound_height = 64 - -/obj/structure/stairs/east - dir = EAST - bound_width = 64 - bound_x = -32 - pixel_x = -32 - -/obj/structure/stairs/west - dir = WEST - bound_width = 64 - -/obj/structure/stairs/short - bound_height = 32 - bound_width = 32 - -/obj/structure/stairs/short/west - dir = WEST \ No newline at end of file diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index 5d7eb4cf7fd1..c08433c2a3c5 100644 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -1,121 +1,20 @@ -/turf/proc/CanZPass(atom/A, direction) - if(z == A.z) //moving FROM this turf - return direction == UP //can't go below - else - if(direction == UP) //on a turf below, trying to enter - return 0 - if(direction == DOWN) //on a turf above, trying to enter - return !density - -/turf/simulated/open/CanZPass(atom/A, direction) - if(locate(/obj/structure/catwalk, src)) - if(z == A.z) - if(direction == DOWN) - return 0 - else if(direction == UP) - return 0 - return 1 - -/turf/space/CanZPass(atom/A, direction) - if(locate(/obj/structure/catwalk, src)) - if(z == A.z) - if(direction == DOWN) - return 0 - else if(direction == UP) - return 0 - return 1 - -/turf/simulated/open - name = "open space" - icon = 'icons/turf/space.dmi' - icon_state = "" - density = 0 - pathweight = 100000 //Seriously, don't try and path over this one numbnuts - - z_flags = ZM_MIMIC_DEFAULTS | ZM_MIMIC_OVERWRITE | ZM_MIMIC_NO_AO | ZM_ALLOW_ATMOS - -/turf/simulated/open/update_dirt() - return 0 - -/turf/simulated/open/Entered(var/atom/movable/mover, var/atom/oldloc) - ..() - mover.fall(oldloc) - -// Called when thrown object lands on this turf. -/turf/simulated/open/hitby(var/atom/movable/AM) - . = ..() - AM.fall() - - -// override to make sure nothing is hidden -/turf/simulated/open/levelupdate() - for(var/obj/O in src) - O.hide(0) - -/turf/simulated/open/examine(mob/user, distance, infix, suffix) - . = ..() - if(distance <= 2) - var/depth = 1 - for(var/T = GetBelow(src); isopenspace(T); T = GetBelow(T)) - depth += 1 - to_chat(user, "It is about [depth] level\s deep.") - -/turf/simulated/open/is_open() - return TRUE - -/turf/simulated/open/attackby(obj/item/C, mob/user) - if (istype(C, /obj/item/stack/material/rods)) - - var/ladder = (locate(/obj/structure/ladder) in src) - if(ladder) - to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) - return TRUE - - var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) - if(L) - return L.attackby(C, user) - var/obj/item/stack/material/rods/R = C - if (R.use(1)) - to_chat(user, SPAN_NOTICE("You lay down the support lattice.")) - playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - new /obj/structure/lattice(locate(src.x, src.y, src.z), R.material.type) - return TRUE - return - - if (istype(C, /obj/item/stack/tile)) - - var/ladder = (locate(/obj/structure/ladder) in src) - if(ladder) - to_chat(user, SPAN_WARNING("\The [ladder] is in the way.")) - return TRUE - - var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) - if(L) - var/obj/item/stack/tile/floor/S = C - if (!S.use(1)) - return - qdel(L) - playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) - ChangeTurf(/turf/simulated/floor/airless) - else - to_chat(user, SPAN_WARNING("The plating is going to need some support.")) - return TRUE - - //To lay cable. - if(isCoil(C)) - var/obj/item/stack/cable_coil/coil = C - coil.turf_place(src, user) - return TRUE - - for(var/atom/movable/M in below) - if(M.movable_flags & MOVABLE_FLAG_Z_INTERACT) - return M.attackby(C, user) - -/turf/simulated/open/attack_hand(mob/user) - for(var/atom/movable/M in below) - if(M.movable_flags & MOVABLE_FLAG_Z_INTERACT) - return M.attack_hand(user) - -//Most things use is_plating to test if there is a cover tile on top (like regular floors) -/turf/simulated/open/is_plating() - return 1 +/// `direction` is the direction the atom is trying to leave by. +/turf/proc/CanZPass(atom/A, direction, check_neighbor_canzpass = TRUE) + if(direction == UP) + if(!HasAbove(z)) + return FALSE + if(check_neighbor_canzpass) + var/turf/T = GetAbove(src) + if(!T.CanZPass(A, DOWN, FALSE)) + return FALSE + + else if(direction == DOWN) + if(!is_open() || !HasBelow(z) || get_supporting_platform()) + return FALSE + if(check_neighbor_canzpass) + var/turf/T = GetBelow(src) + if(!T.CanZPass(A, UP, FALSE)) + return FALSE + + // Hate calling Enter() directly, but that's where obstacles are checked currently. + return Enter(A, A) diff --git a/code/modules/multiz/turf_mimic_edge.dm b/code/modules/multiz/turf_mimic_edge.dm new file mode 100644 index 000000000000..fb33c094c7c0 --- /dev/null +++ b/code/modules/multiz/turf_mimic_edge.dm @@ -0,0 +1,233 @@ +#define MIMIC_EDGE_NAME "world's edge" +#define MIMIC_EDGE_DESC "Flatearther's nightmare." + +//////////////////////////////// +// Mimic Edges +//////////////////////////////// + +///Dummy mouse-opaque overlay to prevent people turning/shooting towards ACTUAL location of vis_content thing +/obj/effect/overlay/click_bait + name = "distant terrain" + desc = "You need to come over there to take a better look." + mouse_opacity = MOUSE_OPACITY_PRIORITY + +//////////////////////////////// +// Shared Mimic Edges +//////////////////////////////// + +///Shared proc to provide the default vis_content for the edge_turf. +/proc/shared_mimic_edge_get_add_vis_contents(var/turf/edge_turf, var/turf/mimic_turf, var/list/vis_cnt) + if(mimic_turf) + edge_turf.density = mimic_turf.density + edge_turf.opacity = mimic_turf.opacity + //log_debug("[src]([x],[y],[z]) mirroring [NT]([NT.x],[NT.y],[NT.z])") + LAZYADD(vis_cnt, mimic_turf) + return vis_cnt + +//////////////////////////////// +// Simulated Mimic Edges +//////////////////////////////// +///Simulated turf meant to replicate the appearence of another. +/turf/mimic_edge + name = MIMIC_EDGE_NAME + desc = MIMIC_EDGE_DESC + icon = null + icon_state = null + density = FALSE + permit_ao = FALSE //would need AO proxy + blocks_air = TRUE //would need air zone proxy + dynamic_lighting = FALSE //Would need lighting proxy + abstract_type = /turf/mimic_edge + + ///Mimicked turf's x position + var/mimic_x + ///Mimicked turf's y position + var/mimic_y + ///Mimicked turf's z position + var/mimic_z + ///Ref to the dummy overlay + var/obj/effect/overlay/click_bait/click_eater + +/turf/mimic_edge/Initialize(ml) + . = ..() + //Clear ourselves from the ambient queue + AMBIENCE_DEQUEUE_TURF(src) + //Need to put a mouse-opaque overlay there to prevent people turning/shooting towards ACTUAL location of vis_content things + click_eater = new(src) //#TODO: get rid of that once we got proper proxy atom handling + setup_mimic() + +/turf/mimic_edge/Destroy() + QDEL_NULL(click_eater) //Make sure we get rid of it if the turf is somehow replaced by map gen to prevent them accumulating. + return ..() + +/turf/mimic_edge/ShouldSerialize(_age) + SHOULD_CALL_PARENT(FALSE) + return FALSE + +/turf/mimic_edge/GetPossiblySerializableInstances() + return null + +/turf/mimic_edge/Crossed(atom/movable/O) + . = ..() + if(isobserver(O)) + var/turf/drop_turf = get_mimic_turf() + if(drop_turf) + O.forceMove(drop_turf) + +/turf/mimic_edge/resolve_to_actual_turf() + return get_mimic_turf() + +//Properly install itself, and allow overriding how the target turf is picked +/turf/mimic_edge/proc/setup_mimic() + return + +/turf/mimic_edge/on_update_icon() + return + +/turf/mimic_edge/get_vis_contents_to_add() + . = shared_mimic_edge_get_add_vis_contents(src, get_mimic_turf(), list()) + +/turf/mimic_edge/proc/get_mimic_turf() + return mimic_x && mimic_y && mimic_z && locate(mimic_x, mimic_y, mimic_z) + +/turf/mimic_edge/proc/set_mimic_turf(var/_x, var/_y, var/_z) + mimic_z = _z? _z : z + mimic_x = _x + mimic_y = _y + update_vis_contents() + +//Prevent ambient completely, we're not a real turf +/turf/mimic_edge/set_ambient_light(color, multiplier) + return +/turf/mimic_edge/update_ambient_light(no_corner_update) + return +/turf/mimic_edge/update_ambient_light_from_z_or_area() + return +/turf/mimic_edge/lighting_build_overlay(now) + return + +//////////////////////////////// +// Transition Edges Shared +//////////////////////////////// + +///Returns the a cardinal direction for a turf on the map that's beyond the transition edge +/proc/get_turf_transition_edge_direction(var/turf/T, var/datum/level_data/target_ldat) + var/within_west_transit = T.x < target_ldat.level_inner_min_x //Is the turf X within the west transition edge? + var/within_east_transit = T.x > target_ldat.level_inner_max_x //Is the turf X within the east transition edge? + var/within_south_transit = T.y < target_ldat.level_inner_min_y //Is the turf Y within the south transition edge? + var/within_north_transit = T.y > target_ldat.level_inner_max_y //Is the turf Y within the north transition edge? + + //Filter out corners, since we can't mimic those properly + if(within_west_transit && !within_south_transit && !within_north_transit) + return WEST + if(within_east_transit && !within_south_transit && !within_north_transit) + return EAST + if(within_south_transit && !within_west_transit && !within_east_transit) + return SOUTH + if(within_north_transit && !within_west_transit && !within_east_transit) + return NORTH + + //Corners return null + return null + +/// Returns the turf that's opposite to the specified turf, on the level specified. +/proc/shared_transition_edge_get_coordinates_turf_to_mimic(var/turf/T, var/datum/level_data/target_ldat) + var/translate_from_dir = get_turf_transition_edge_direction(T, target_ldat) + if(isnull(translate_from_dir)) + //In this case we're in the corners of the map. We shouldn't mimic. + log_warning("Transition turf '[T]' at ([T.x], [T.y], [T.z]) was in a corner of the map. That's likely a mistake, since we can't mimic corners properly!") + return list(T.x, T.y, T.z) + + var/newx = T.x + var/newy = T.y + switch(translate_from_dir) + if(NORTH) + newy = (target_ldat.level_inner_min_y - 1) + (T.y - target_ldat.level_inner_max_y) //The level_inner coords are inclusive, so we need to +- 1 + if(SOUTH) + newy = (target_ldat.level_inner_max_y + 1) - (target_ldat.level_inner_min_y - T.y) + if(EAST) + newx = (target_ldat.level_inner_min_x - 1) + (T.x - target_ldat.level_inner_max_x) + if(WEST) + newx = (target_ldat.level_inner_max_x + 1) - (target_ldat.level_inner_min_x - T.x) + + return list(newx, newy, target_ldat.level_z) + +///Grab the connected level data for the level connected in the direction the 'T' turf is in. +/proc/shared_transition_edge_get_valid_level_data(var/turf/T) + var/datum/level_data/LD = SSmapping.levels_by_z[T.z] + var/edge_dir = get_turf_transition_edge_direction(T, LD) + var/connected_lvl_id = LD.get_connected_level_id(edge_dir) + if(!connected_lvl_id) + var/dirname = dir2text(edge_dir) + CRASH("Got transition_edge turf '[T]' ([T.x], [T.y], [T.z]), in direction '[dirname]', but there is no connections in level_data '[LD]' for '[dirname]'!") + return SSmapping.levels_by_id[connected_lvl_id] + +///Handles teleporting an atom that touches a transition edge/loop edge. +/proc/shared_transition_edge_bumped(var/turf/T, var/atom/movable/AM, var/mimic_z) + var/datum/level_data/LDsrc = SSmapping.levels_by_z[T.z] + var/datum/level_data/LDdst = SSmapping.levels_by_z[mimic_z] + var/new_x = AM.x + var/new_y = AM.y + + //Get the position inside the destination level's bounds to teleport the thing to + if(T.x < LDsrc.level_inner_min_x) + new_x = LDdst.level_inner_max_x + else if (T.x > LDsrc.level_inner_max_x) + new_x = LDdst.level_inner_min_x + else if (T.y < LDsrc.level_inner_min_y) + new_y = LDdst.level_inner_max_y + else if (T.y > LDsrc.level_inner_max_y) + new_y = LDdst.level_inner_min_y + else + return //If we're teleporting into the same spot just quit early + + //Teleport to the turf + var/turf/dest = locate(new_x, new_y, mimic_z) + if(!dest) + CRASH("Turf '[T]' failed to teleport '[AM]' to [new_x], [new_y], [mimic_z]. Couldn't locate turf!") + if(dest.density) + return //If the target turf is dense, just siltently do nothing. + + AM.forceMove(dest) + //Move grabbed things + if(isliving(AM)) + var/mob/living/L = AM + for(var/obj/item/grab/grab as anything in L.get_active_grabs()) + grab.affecting.forceMove(dest) + +//////////////////////////////// +// Transition Edges +//////////////////////////////// + +///When soemthing touches this turf, it gets transported to the connected level matching the direction of the edge on the map +/turf/mimic_edge/transition/setup_mimic() + var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, shared_transition_edge_get_valid_level_data(src)) + set_mimic_turf(coord[1], coord[2], coord[3]) +/turf/mimic_edge/transition/Entered(atom/movable/AM, atom/old_loc) + . = ..() + if(!AM.simulated || AM.anchored || istype(AM, /obj/effect/overlay)) + return + if(istype(AM, /obj/effect/projectile)) //#FIXME: Once we support projectiles going through levels properly remove this + return + shared_transition_edge_bumped(src, AM, mimic_z) + +/turf/mimic_edge/transition/flooded + flooded = /decl/material/liquid/water + +/turf/mimic_edge/transition/flooded/salt + contaminant_reagent_type = /decl/material/solid/sodiumchloride + contaminant_proportion = 0.10 // 1:10 salt:water, NOT 10% salt + +//////////////////////////////// +// Loop Edges +//////////////////////////////// + +///When something touches this turf, it gets transported to the symmetrically opposite turf it's mimicking. +/turf/mimic_edge/transition/loop/set_mimic_turf(_x, _y, _z) + . = ..(_x, _y) +/turf/mimic_edge/transition/loop/setup_mimic() + var/list/coord = shared_transition_edge_get_coordinates_turf_to_mimic(src, SSmapping.levels_by_z[src.z]) + set_mimic_turf(coord[1], coord[2], coord[3]) + +#undef MIMIC_EDGE_NAME +#undef MIMIC_EDGE_DESC \ No newline at end of file diff --git a/code/modules/multiz/zmimic/mimic_common.dm b/code/modules/multiz/zmimic/mimic_common.dm index 173d5a6540aa..33f81331fb9a 100644 --- a/code/modules/multiz/zmimic/mimic_common.dm +++ b/code/modules/multiz/zmimic/mimic_common.dm @@ -1,4 +1,4 @@ -// Updates whatever openspace components may be mimicing us. On turfs this queues an openturf update on the above openturf, on movables this updates their bound movable (if present). Meaningless on any type other than `/turf` or `/atom/movable` (incl. children). +// Updates whatever openspace components may be mimicking us. On turfs this queues an openturf update on the above openturf, on movables this updates their bound movable (if present). Meaningless on any type other than `/turf` or `/atom/movable` (incl. children). /atom/proc/update_above() return @@ -6,12 +6,11 @@ var/turf/T = GetBelow(src) while (T && (T.z_flags & ZM_MIMIC_BELOW)) T = GetBelow(T) - - return istype(T, /turf/space) + return isspaceturf(T) /turf/update_icon() ..() - if (above) + if(above) update_above() /atom/movable/update_icon() diff --git a/code/modules/multiz/zmimic/mimic_docs.dm b/code/modules/multiz/zmimic/mimic_docs.dm new file mode 100644 index 000000000000..e3d794acafb0 --- /dev/null +++ b/code/modules/multiz/zmimic/mimic_docs.dm @@ -0,0 +1,101 @@ +/* +Types (also see terminology section): + openspace/multiplier -> shadows the below level, also copies lighting + openspace/mimic -> copies below movables + openspace/turf_proxy -> holds the appearance of the below turf for non-OVERWRITE Z-turfs + openspace/turf_mimic -> copies openspace/turf_proxy objects + +Public API: + Notifying Z-Mimic of icon updates: + - UPDATE_OO_IF_PRESENT + - valid on movables only + - if this movable is being copied, update the copies + - cheap (if this movable is not being mimiced, this is a null check) + + - atom/update_above() + - similar to UPDATE_OO_IF_PRESENT, but for both turfs and movables + - less cheap (pretty much just proc-call overhead) + + Checking state: + - TURF_IS_MIMICKING(turf or any) + - value: bool - if the passed turf is z-mimic enabled + + - movable/get_above_oo() + - return: list of movables + - get a list of every openspace mimic that's copying this atom for things like animate() + + Changing state: + - turf/enable_zmimic(extra_flags = 0) + - return: bool - FALSE if this turf was already mimicking, TRUE otherwise + - Enables z-mimic for this turf, potentially adding extra z_flags. + - This will automatically queue the turf for update. + + - turf/disable_zmimic() + - return: bool - FALSE if this turf was not mimicking, TRUE otherwise + - Disables z-mimic for this turf. + - This will clean up associated mimic objects, but they may hang around for a few additional seconds. + + Vars: + - turf/z_flags + - bitfield + - ZM_MIMIC_BELOW: copy below atoms + - ZM_MIMIC_OVERWRITE: z-mimic can overwrite this turf's appearance + - ZM_ALLOW_LIGHTING: lighting should pass through this turf + - ZM_ALLOW_ATMOS: air should pass through this turf + - ZM_MIMIC_NO_AO: normal turf AO should be skipped, only do openspace AO (if your turf is not solid, you probably want this) + - ZM_NO_OCCLUDE: don't block clicking on below atoms if not OVERWRITE + + - atom/movable/z_flags + - bitfield + - ZMM_IGNORE: Do not copy this atom. Atoms with INVISIBILITY_ABSTRACT are automatically not copied. + - ZMM_MANGLE_PLANES: Scan this atom's overlays and monkeypatch explicit plane sets. Fixes emissive overlays shining through floors, but expensive -- use only if necessary. + +Implementation details: + Z-Mimic makes some assumptions. While it may continue to work if these are violated, don't be surprised if it behaves strangely, renders things in the incorrect order, or outright breaks. + + Assumptions: + - Z-Stacks will not be taller than OPENTURF_MAX_DEPTH. + - If violated: Warning emitted on boot, layering may break for items near the bottom of the z-stack. + - Atoms will render correctly if copied to another plane. + - Atoms will layer correctly if copied to the same plane as other arbitrary in-world atoms. + - Atoms without ZMM_MANGLE_PLANES do not have any overlays that have explicit plane sets. + - If violated: Atoms on the below floor may be partially visible on the current floor. + - Z-Stacks are 1:1 across the entire x/y plane. + - If violated: Z-turfs may form nonsensical connections. + - Z-Stacks are contiguous and linear -- get_step(UP) corresponds to moving up a z-level (within a z-stack) in all cases. + - If violated: layering becomes nonsensical. + - Z-Stacks will not be changed (note: adding new Z-stacks is OK) after an openturf has been initialized on that z-stack. + - If violated: Z-Turfs may act as if they are still connected even though they are not. + - /turf/space is never above another turf type in the Z-Stack. + - Turfs that are setting ZM_MIMIC_OVERWRITE do not care about their appearance. + - If violated: Appearance of turf is lost. + - Multiturf movable atoms are symmetric, and centered on their visual center. + - If violated: Multitile atoms may not render in cases where they should. + - SHADOWER_DARKENING_FACTOR and SHADOWER_DARKENING_COLOR represent the same shade of grey. + - If violated: unlit and lit z-turfs may look inconsistent with each other. + - Lighting will mimic correctly without being associated with a plane. + - If violated: depending on implementation, lighting may be inverted, or not render at all. + - This can usually be addressed by changing /atom/movable/openspace/multiplier/proc/copy_lighting(). + + Known Limitations: + - Multiturf movable atoms are not rendered if they are not centered on a z-turf, but overlap one. + - vis_contents is ignored -- mimics will not copy it. + + Terminology (of varying obscurity): + - Z-Stack + - A set of z-connected turfs with the same x/y coordinates. + - Z-Depth + - How many Z-levels this atom is *from the top of a Z-Stack* (absolute layering), regardless of z-turf presence + - Shadower / Multiplier + - An abstract object used to darken lower levels, copy lighting, and host Z-AO overlays. + - Mimic / Openspace Object + - An abstract object that holds appearances of atoms and proxies clicks. + - Turf Proxy / Turf Object + - An abstract object that holds Z-Copy turf appearances for non-OVERWRITE turfs. + - Turf Mimic + - An abstract object that holds appearances of non-OVERWRITE z-turfs below this z-turf. + - Foreign Turf + - A turf below this z-turf that is contributing to our appearance. + - Mimic Underlay + - A turf appearance holder specifically for fake space below a z-turf at the bottom of a z-stack. +*/ diff --git a/code/modules/multiz/zmimic/mimic_movable.dm b/code/modules/multiz/zmimic/mimic_movable.dm index b0a314eae63f..2af50724b884 100644 --- a/code/modules/multiz/zmimic/mimic_movable.dm +++ b/code/modules/multiz/zmimic/mimic_movable.dm @@ -1,24 +1,8 @@ /atom/movable - var/tmp/atom/movable/openspace/overlay/bound_overlay // The overlay that is directly mirroring us that we proxy movement to. - var/no_z_overlay // If TRUE, this atom will not be drawn on open turfs. - -/atom/movable/forceMove(atom/dest) - . = ..(dest) - if (. && bound_overlay) - // The overlay will handle cleaning itself up on non-openspace turfs. - if (isturf(dest)) - bound_overlay.forceMove(get_step(src, UP)) - if (dir != bound_overlay.dir) - bound_overlay.set_dir(dir) - else // Not a turf, so we need to destroy immediately instead of waiting for the destruction timer to proc. - qdel(bound_overlay) - -/atom/movable/Move() - . = ..() - if (. && bound_overlay) - bound_overlay.forceMove(get_step(src, UP)) - if (bound_overlay.dir != dir) - bound_overlay.set_dir(dir) + /// The mimic (if any) that's *directly* copying us. + var/tmp/atom/movable/openspace/mimic/bound_overlay + /// Movable-level Z-Mimic flags. This uses ZMM_* flags, not ZM_* flags. + var/z_flags = 0 /atom/movable/set_dir(ndir) . = ..() @@ -29,16 +13,13 @@ if (!bound_overlay || !isturf(loc)) return - var/turf/T = loc - - if (TURF_IS_MIMICING(T.above)) - if (!bound_overlay.queued) - SSzcopy.queued_overlays += bound_overlay - bound_overlay.queued = TRUE + if (MOVABLE_IS_BELOW_ZTURF(src)) + SSzcopy.queued_overlays += bound_overlay + bound_overlay.queued += 1 else qdel(bound_overlay) -// Grabs a list of every openspace object that's directly or indirectly mimicing this object. Returns an empty list if none found. +// Grabs a list of every openspace object that's directly or indirectly mimicking this object. Returns an empty list if none found. /atom/movable/proc/get_above_oo() . = list() var/atom/movable/curr = src @@ -53,8 +34,9 @@ simulated = FALSE anchored = TRUE mouse_opacity = FALSE + abstract_type = /atom/movable/openspace // unsure if this is valid, check with Lohi -- Yes, it's valid. -/atom/movable/openspace/can_fall() +/atom/movable/openspace/can_fall(anchor_bypass = FALSE, turf/location_override = loc) return FALSE // No blowing up abstract objects. @@ -62,95 +44,85 @@ SHOULD_CALL_PARENT(FALSE) return -/atom/movable/openspace/singularity_act() - return - -/atom/movable/openspace/singularity_pull() - return - -/atom/movable/openspace/singuloCanEat() - return +// -- MULTIPLIER / SHADOWER -- // Holder object used for dimming openspaces & copying lighting of below turf. /atom/movable/openspace/multiplier name = "openspace multiplier" desc = "You shouldn't see this." icon = 'icons/effects/lighting_overlay.dmi' - icon_state = "dark" + icon_state = "blank" plane = OPENTURF_MAX_PLANE layer = MIMICED_LIGHTING_LAYER blend_mode = BLEND_MULTIPLY - color = list( - SHADOWER_DARKENING_FACTOR, 0, 0, - 0, SHADOWER_DARKENING_FACTOR, 0, - 0, 0, SHADOWER_DARKENING_FACTOR - ) + color = SHADOWER_DARKENING_COLOR -/atom/movable/openspace/multiplier/Destroy() +/atom/movable/openspace/multiplier/Destroy(force) + if(!force) + PRINT_STACK_TRACE("Turf shadower improperly qdel'd.") + return QDEL_HINT_LETMELIVE var/turf/myturf = loc if (istype(myturf)) myturf.shadower = null return ..() -/atom/movable/openspace/multiplier/proc/copy_lighting(atom/movable/lighting_overlay/LO) - appearance = LO - layer = MIMICED_LIGHTING_LAYER - plane = OPENTURF_MAX_PLANE - invisibility = 0 - blend_mode = BLEND_MULTIPLY - if (icon_state == null) - // We're using a color matrix, so just darken the colors across the board. - // Bay stores lights as inverted so the lighting PM can invert it for darksight, but - // we don't have a plane master, so invert it again. - var/list/c_list = color - c_list[CL_MATRIX_RR] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_RG] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_RB] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_GR] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_GG] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_GB] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_BR] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_BG] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_BB] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_AR] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_AG] *= -SHADOWER_DARKENING_FACTOR - c_list[CL_MATRIX_AB] *= -SHADOWER_DARKENING_FACTOR - color = c_list - else - // Not a color matrix, so we just ignore the lighting values. - icon_state = "dark" // this is actually just a white sprite, which is what this blending needs - color = list( - SHADOWER_DARKENING_FACTOR, 0, 0, - 0, SHADOWER_DARKENING_FACTOR, 0, - 0, 0, SHADOWER_DARKENING_FACTOR - ) - - var/turf/parent = loc - ASSERT(isturf(parent)) - if (LAZYLEN(parent.ao_overlays_mimic)) - overlays += parent.ao_overlays_mimic - - if (bound_overlay) +/atom/movable/openspace/multiplier/proc/copy_lighting(atom/movable/lighting_overlay/LO, use_shadower_mult = TRUE) + var/mutable_appearance/MA = new /mutable_appearance(LO) + MA.layer = MIMICED_LIGHTING_LAYER + MA.plane = OPENTURF_MAX_PLANE + MA.blend_mode = BLEND_MULTIPLY + + if (use_shadower_mult) + if (MA.icon_state == LIGHTING_BASE_ICON_STATE) + // We're using a color matrix, so just darken the colors across the board. + var/list/c_list = MA.color + c_list[CL_MATRIX_RR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_RG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_RB] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_GR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_GG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_GB] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_BR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_BG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_BB] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_AR] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_AG] *= SHADOWER_DARKENING_FACTOR + c_list[CL_MATRIX_AB] *= SHADOWER_DARKENING_FACTOR + MA.color = c_list + else + // Not a color matrix, so we can just use the color var ourselves. + MA.color = SHADOWER_DARKENING_COLOR + appearance = MA + set_invisibility(INVISIBILITY_NONE) + + if (our_overlays || priority_overlays) + compile_overlays() + else if (bound_overlay) + // compile_overlays() calls update_above(). update_above() +// -- OPENSPACE MIMIC -- + // Object used to hold a mimiced atom's appearance. -/atom/movable/openspace/overlay +/atom/movable/openspace/mimic plane = OPENTURF_MAX_PLANE var/atom/movable/associated_atom var/depth - var/queued = FALSE + var/queued = 0 var/destruction_timer var/mimiced_type var/original_z var/override_depth + var/have_performed_fixup = FALSE -/atom/movable/openspace/overlay/New() +/atom/movable/openspace/mimic/New() atom_flags |= ATOM_FLAG_INITIALIZED SSzcopy.openspace_overlays += 1 -/atom/movable/openspace/overlay/Destroy() +/atom/movable/openspace/mimic/Destroy() SSzcopy.openspace_overlays -= 1 + queued = 0 if (associated_atom) associated_atom.bound_overlay = null @@ -161,26 +133,98 @@ return ..() -/atom/movable/openspace/overlay/attackby(obj/item/W, mob/user) +/atom/movable/openspace/mimic/attackby(obj/item/used_item, mob/user) to_chat(user, SPAN_NOTICE("\The [src] is too far away.")) + return TRUE -/atom/movable/openspace/overlay/attack_hand(mob/user) +/atom/movable/openspace/mimic/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here.")) + return TRUE -/atom/movable/openspace/overlay/examine(...) +/atom/movable/openspace/mimic/examined_by(mob/user, distance, infix, suffix) SHOULD_CALL_PARENT(FALSE) - . = associated_atom.examine(arglist(args)) // just pass all the args to the copied atom + return associated_atom.examined_by(user, distance, infix, suffix) -/atom/movable/openspace/overlay/forceMove(turf/dest) +// Trying to grab a mimic tries to grab the copied atom instead. +/atom/movable/openspace/mimic/try_make_grab(mob/living/user, defer_hand) + return associated_atom.try_make_grab(user, defer_hand) + +/atom/movable/openspace/mimic/forceMove(turf/dest) + var/atom/old_loc = loc . = ..() - if (TURF_IS_MIMICING(dest)) + if (MOVABLE_IS_ON_ZTURF(src)) if (destruction_timer) deltimer(destruction_timer) destruction_timer = null + if (old_loc?.z != loc?.z) // Null checking in case of qdel(), observed with dirt effect falling through multiz. + reset_internal_layering() else if (!destruction_timer) - destruction_timer = addtimer(CALLBACK(src, /datum/.proc/qdel_self), 10 SECONDS, TIMER_STOPPABLE) + destruction_timer = ZM_DESTRUCTION_TIMER(src) // Called when the turf we're on is deleted/changed. -/atom/movable/openspace/overlay/proc/owning_turf_changed() +/atom/movable/openspace/mimic/proc/owning_turf_changed() if (!destruction_timer) - destruction_timer = addtimer(CALLBACK(src, /datum/.proc/qdel_self), 10 SECONDS, TIMER_STOPPABLE) \ No newline at end of file + destruction_timer = ZM_DESTRUCTION_TIMER(src) + +/atom/movable/openspace/mimic/proc/reset_internal_layering() + if (bound_overlay?.override_depth) + depth = bound_overlay.override_depth + else if (isturf(associated_atom.loc)) + depth = min(SSzcopy.zlev_maximums[associated_atom.z] - associated_atom.z, OPENTURF_MAX_DEPTH) + override_depth = depth + + plane = OPENTURF_MAX_PLANE - depth + + bound_overlay?.reset_internal_layering() + +// -- TURF PROXY -- + +// This thing holds the mimic appearance for non-OVERWRITE turfs. +/atom/movable/openspace/turf_proxy + plane = OPENTURF_MAX_PLANE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + z_flags = ZMM_IGNORE // Only one of these should ever be visible at a time, the mimic logic will handle that. + +/atom/movable/openspace/turf_proxy/attackby(obj/item/used_item, mob/user) + return loc.attackby(used_item, user) + +/atom/movable/openspace/turf_proxy/attack_hand(mob/user as mob) + SHOULD_CALL_PARENT(FALSE) + return loc.attack_hand(user) + +/atom/movable/openspace/turf_proxy/attack_generic(mob/user as mob) + loc.attack_generic(user) + +/atom/movable/openspace/turf_proxy/examined_by(mob/user, distance, infix, suffix) + SHOULD_CALL_PARENT(FALSE) + return loc.examined_by(user, distance, infix, suffix) + + +// -- TURF MIMIC -- + +// A type for copying non-overwrite turfs' self-appearance. +/atom/movable/openspace/turf_mimic + plane = OPENTURF_MAX_PLANE // These *should* only ever be at the top? + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + var/turf/delegate + +/atom/movable/openspace/turf_mimic/Initialize(mapload, ...) + . = ..() + ASSERT(isturf(loc)) + delegate = loc:below + +/atom/movable/openspace/turf_mimic/attackby(obj/item/used_item, mob/user) + return loc.attackby(used_item, user) + +/atom/movable/openspace/turf_mimic/attack_hand(mob/user as mob) + SHOULD_CALL_PARENT(FALSE) + to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here.")) + return TRUE + +/atom/movable/openspace/turf_mimic/attack_generic(mob/user as mob) + to_chat(user, SPAN_NOTICE("You cannot reach \the [src] from here.")) + +/atom/movable/openspace/turf_mimic/examined_by(mob/user, distance, infix, suffix) + SHOULD_CALL_PARENT(FALSE) + return delegate.examined_by(user, distance, infix, suffix) diff --git a/code/modules/multiz/zmimic/mimic_turf.dm b/code/modules/multiz/zmimic/mimic_turf.dm index 7c93fb32e649..d47230e98e1c 100644 --- a/code/modules/multiz/zmimic/mimic_turf.dm +++ b/code/modules/multiz/zmimic/mimic_turf.dm @@ -2,32 +2,37 @@ // Reference to any open turf that might be above us to speed up atom Entered() updates. var/tmp/turf/above var/tmp/turf/below - var/tmp/atom/movable/openspace/turf_overlay/bound_overlay - var/tmp/atom/movable/openspace/multiplier/shadower // Overlay used to multiply color of all OO overlays at once. - var/tmp/z_queued = 0 // How many times this turf is currently queued - multiple queue occurrences are allowed to ensure update consistency + /// If we're a non-overwrite z-turf, this holds the appearance of the bottom-most Z-turf in the z-stack. + var/tmp/atom/movable/openspace/turf_proxy/mimic_proxy + /// Overlay used to multiply color of all OO overlays at once. + var/tmp/atom/movable/openspace/multiplier/shadower + /// If this is a delegate (non-overwrite) Z-turf with a z-turf above, this is the delegate copy that's copying us. + var/tmp/atom/movable/openspace/turf_mimic/mimic_above_copy + /// If we're at the bottom of the stack, a proxy used to fake a below space turf. + var/tmp/atom/movable/openspace/turf_proxy/mimic_underlay + /// How many times this turf is currently queued - multiple queue occurrences are allowed to ensure update consistency. + var/tmp/z_queued = 0 + /// If this Z-turf leads to space, uninterrupted. var/tmp/z_eventually_space = FALSE var/z_flags = 0 - var/tmp/z_depth + /// Use this appearance for our appearance instead of `appearance`. If ZM_OVERRIDE is set, *only* this will be visible, no movables will be copied. + var/z_appearance -/turf/Entered(atom/movable/thing, turf/oldLoc) - . = ..() - if (thing.bound_overlay || thing.no_z_overlay || !TURF_IS_MIMICING(above)) - return - above.update_mimic() + // debug + var/tmp/z_depth + var/tmp/z_generation = 0 /turf/update_above() - if (TURF_IS_MIMICING(above)) + if (TURF_IS_MIMICKING(above)) above.update_mimic() /turf/proc/update_mimic() - if (!(z_flags & ZM_MIMIC_BELOW)) - return - - if (below) + if(z_flags & ZM_MIMIC_BELOW) z_queued += 1 + // This adds duplicates for a reason. Do not change this unless you understand how ZM queues work. SSzcopy.queued_turfs += src -// Enables Z-mimic for a turf that didn't already have it enabled. +/// Enables Z-mimic for a turf that didn't already have it enabled. /turf/proc/enable_zmimic(additional_flags = 0) if (z_flags & ZM_MIMIC_BELOW) return FALSE @@ -36,15 +41,16 @@ setup_zmimic(FALSE) return TRUE -// Disables Z-mimic for a turf. +/// Disables Z-mimic for a turf. /turf/proc/disable_zmimic() if (!(z_flags & ZM_MIMIC_BELOW)) return FALSE z_flags &= ~ZM_MIMIC_BELOW cleanup_zmimic() + return TRUE -// Sets up Z-mimic for this turf. You shouldn't call this directly 99% of the time. +/// Sets up Z-mimic for this turf. You shouldn't call this directly 99% of the time. /turf/proc/setup_zmimic(mapload) if (shadower) CRASH("Attempt to enable Z-mimic on already-enabled turf!") @@ -55,17 +61,25 @@ below = under below.above = src + if (!(z_flags & (ZM_MIMIC_OVERWRITE|ZM_NO_OCCLUDE)) && mouse_opacity) + mouse_opacity = MOUSE_OPACITY_PRIORITY + update_mimic(!mapload) // Only recursively update if the map isn't loading. -// Cleans up Z-mimic objects for this turf. You shouldn't call this directly 99% of the time. +/// Cleans up Z-mimic objects for this turf. You shouldn't call this directly 99% of the time. /turf/proc/cleanup_zmimic() SSzcopy.openspace_turfs -= 1 // Don't remove ourselves from the queue, the subsystem will explode. We'll naturally fall out of the queue. z_queued = 0 - QDEL_NULL(shadower) + // can't use QDEL_NULL as we need to supply force to qdel + if(shadower) + qdel(shadower, TRUE) + shadower = null + QDEL_NULL(mimic_above_copy) + QDEL_NULL(mimic_underlay) - for (var/atom/movable/openspace/overlay/OO in src) + for (var/atom/movable/openspace/mimic/OO in src) OO.owning_turf_changed() if (above) @@ -74,17 +88,3 @@ if (below) below.above = null below = null - -// Movable for mimicing turfs that don't allow appearance mutation. -/atom/movable/openspace/turf_overlay - plane = OPENTURF_MAX_PLANE - -/atom/movable/openspace/turf_overlay/attackby(obj/item/W, mob/user) - return loc.attackby(W, user) - -/atom/movable/openspace/turf_overlay/attack_hand(mob/user) - return loc.attack_hand(user) - -/atom/movable/openspace/turf_overlay/examine(mob/examiner) - SHOULD_CALL_PARENT(FALSE) - . = loc.examine(examiner) diff --git a/code/modules/nano/interaction/admin.dm b/code/modules/nano/interaction/admin.dm index ce16f94ce910..765e8c652c8c 100644 --- a/code/modules/nano/interaction/admin.dm +++ b/code/modules/nano/interaction/admin.dm @@ -1,7 +1,7 @@ /* This state checks that the user is an admin, end of story */ -GLOBAL_DATUM_INIT(admin_state, /datum/topic_state/admin_state, new) +var/global/datum/topic_state/admin_state/admin_topic_state = new /datum/topic_state/admin_state/can_use_topic(var/src_object, var/mob/user) return check_rights(R_ADMIN, 0, user) ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/interaction/base.dm b/code/modules/nano/interaction/base.dm index cde02106fa6b..5769d0f412b6 100644 --- a/code/modules/nano/interaction/base.dm +++ b/code/modules/nano/interaction/base.dm @@ -4,19 +4,21 @@ /datum/proc/nano_container() return src -/datum/proc/CanUseTopic(var/mob/user, var/datum/topic_state/state = GLOB.default_state) +/datum/proc/CanUseTopic(var/mob/user, var/datum/topic_state/state = global.default_topic_state) var/datum/src_object = nano_host() return state.can_use_topic(src_object, user) +/mob/CanUseTopic(mob/user, datum/topic_state/state, href_list) + if(href_list && href_list["flavor_more"]) + return STATUS_INTERACTIVE + return ..() + /datum/proc/CanUseTopicPhysical(mob/user) - return CanUseTopic(user, GLOB.physical_state) + return CanUseTopic(user, global.physical_topic_state) /datum/topic_state var/check_access = TRUE // Whether this topic state should bypass access checks or not. -/datum/topic_state/proc/href_list(var/mob/user) - return list() - /datum/topic_state/proc/can_use_topic(var/src_object, var/mob/user) return STATUS_CLOSE diff --git a/code/modules/nano/interaction/conscious.dm b/code/modules/nano/interaction/conscious.dm index 76a5d70a077d..eb36998caa15 100644 --- a/code/modules/nano/interaction/conscious.dm +++ b/code/modules/nano/interaction/conscious.dm @@ -1,7 +1,7 @@ /* This state only checks if user is conscious. */ -GLOBAL_DATUM_INIT(conscious_state, /datum/topic_state/conscious_state, new) +var/global/datum/topic_state/conscious_state/conscious_topic_state = new /datum/topic_state/conscious_state/can_use_topic(var/src_object, var/mob/user) return user.stat == CONSCIOUS ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/interaction/contained.dm b/code/modules/nano/interaction/contained.dm index ffa4f3762a94..d9311c90cbe7 100644 --- a/code/modules/nano/interaction/contained.dm +++ b/code/modules/nano/interaction/contained.dm @@ -1,7 +1,7 @@ /* This state checks if user is somewhere within src_object, as well as the default NanoUI interaction. */ -GLOBAL_DATUM_INIT(contained_state, /datum/topic_state/contained_state, new) +var/global/datum/topic_state/contained_state/contained_topic_state = new /datum/topic_state/contained_state/can_use_topic(var/atom/src_object, var/mob/user) if(!src_object.contains(user)) diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm index e6cfb9ba4dc2..51a7a6eca757 100644 --- a/code/modules/nano/interaction/default.dm +++ b/code/modules/nano/interaction/default.dm @@ -1,7 +1,4 @@ -GLOBAL_DATUM_INIT(default_state, /datum/topic_state/default, new) - -/datum/topic_state/default/href_list(var/mob/user) - return list() +var/global/datum/topic_state/default/default_topic_state = new /datum/topic_state/default/can_use_topic(var/src_object, var/mob/user) return user.default_can_use_topic(src_object) @@ -28,7 +25,7 @@ GLOBAL_DATUM_INIT(default_state, /datum/topic_state/default, new) return // robots can interact with things they can see within their view range - if((src_object in view(src)) && get_dist(src_object, src) <= get_effective_view(client)) + if((src_object in view(client?.view || world.view, src)) && get_dist(src_object, src) <= get_effective_view(client)) return STATUS_INTERACTIVE // interactive (green visibility) return STATUS_DISABLED // no updates, completely disabled (red visibility) @@ -41,20 +38,20 @@ GLOBAL_DATUM_INIT(default_state, /datum/topic_state/default, new) // unless it's on the same level as the object it's interacting with. var/turf/T = get_turf(src_object) var/turf/A = get_turf(src) - if(!A || !T || !AreConnectedZLevels(A.z, T.z)) + if(!A || !T || !SSmapping.are_connected_levels(A.z, T.z)) return STATUS_CLOSE // If an object is in view then we can interact with it - if(src_object in view(get_effective_view(client), src)) + if(src_object in view(client.view, src)) return STATUS_INTERACTIVE - // If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view + // If we're installed in a chassi, rather than transfered to an intelliCard or other container, then check if we have camera view if(is_in_chassis()) //stop AIs from leaving windows open and using then after they lose vision if(cameranet && !cameranet.is_turf_visible(get_turf(src_object))) return STATUS_CLOSE return STATUS_INTERACTIVE - else if(get_dist(src_object, src) <= get_effective_view(client)) // View does not return what one would expect while installed in an inteliCard + else if(get_dist(src_object, src) <= get_effective_view(client)) // View does not return what one would expect while installed in an intelliCard return STATUS_INTERACTIVE return STATUS_CLOSE @@ -86,7 +83,7 @@ GLOBAL_DATUM_INIT(default_state, /datum/topic_state/default, new) if(. == STATUS_INTERACTIVE) return STATUS_UPDATE -/mob/living/carbon/human/default_can_use_topic(var/src_object) +/mob/living/human/default_can_use_topic(var/src_object) . = shared_nano_interaction(src_object) if(. != STATUS_CLOSE) if(loc) diff --git a/code/modules/nano/interaction/hands.dm b/code/modules/nano/interaction/hands.dm index 20d26bed1eaa..819adeb820c4 100644 --- a/code/modules/nano/interaction/hands.dm +++ b/code/modules/nano/interaction/hands.dm @@ -1,7 +1,8 @@ -/* - This state only checks if user is conscious. -*/ -GLOBAL_DATUM_INIT(hands_state, /datum/topic_state/hands, new) +/** + This state checks if src_object is held in the user's hands (or a cyborg gripper), + as well as the default NanoUI interaction. +**/ +var/global/datum/topic_state/hands/hands_topic_state = new /datum/topic_state/hands/can_use_topic(src_object, mob/user) . = user.shared_nano_interaction(src_object) @@ -12,12 +13,12 @@ GLOBAL_DATUM_INIT(hands_state, /datum/topic_state/hands, new) return STATUS_CLOSE /mob/living/hands_can_use_topic(src_object) - if(src_object in get_both_hands(src)) + if(src_object in get_held_items()) return STATUS_INTERACTIVE return STATUS_CLOSE /mob/living/silicon/robot/hands_can_use_topic(src_object) - for(var/obj/item/gripper/active_gripper in list(module_state_1, module_state_2, module_state_3)) + for(var/obj/item/gripper/active_gripper in get_held_items()) if(active_gripper.contains(src_object)) return STATUS_INTERACTIVE return STATUS_CLOSE diff --git a/code/modules/nano/interaction/interactive.dm b/code/modules/nano/interaction/interactive.dm index c546cf234667..c31994ae50ef 100644 --- a/code/modules/nano/interaction/interactive.dm +++ b/code/modules/nano/interaction/interactive.dm @@ -1,7 +1,7 @@ /* This state always returns STATUS_INTERACTIVE */ -GLOBAL_DATUM_INIT(interactive_state, /datum/topic_state/interactive, new) +var/global/datum/topic_state/interactive/interactive_topic_state = new /datum/topic_state/interactive/can_use_topic(var/src_object, var/mob/user) return STATUS_INTERACTIVE diff --git a/code/modules/nano/interaction/inventory.dm b/code/modules/nano/interaction/inventory.dm index b17c62a9bc8c..d5e120ea8b69 100644 --- a/code/modules/nano/interaction/inventory.dm +++ b/code/modules/nano/interaction/inventory.dm @@ -1,7 +1,7 @@ /* This state checks that the src_object is somewhere in the user's first-level inventory (in hands, on ear, etc.), but not further down (such as in bags). */ -GLOBAL_DATUM_INIT(inventory_state, /datum/topic_state/inventory_state, new) +var/global/datum/topic_state/inventory_state/inventory_topic_state = new /datum/topic_state/inventory_state/can_use_topic(var/src_object, var/mob/user) if(!(src_object in user)) diff --git a/code/modules/nano/interaction/inventory_deep.dm b/code/modules/nano/interaction/inventory_deep.dm index 1df42064882a..53f44fc8e26f 100644 --- a/code/modules/nano/interaction/inventory_deep.dm +++ b/code/modules/nano/interaction/inventory_deep.dm @@ -1,7 +1,7 @@ /* This state checks if src_object is contained anywhere in the user's inventory, including bags, etc. */ -GLOBAL_DATUM_INIT(deep_inventory_state, /datum/topic_state/deep_inventory_state, new) +var/global/datum/topic_state/deep_inventory_state/deep_inventory_topic_state = new /datum/topic_state/deep_inventory_state/can_use_topic(var/src_object, var/mob/user) if(!user.contains(src_object)) diff --git a/code/modules/nano/interaction/mech.dm b/code/modules/nano/interaction/mech.dm index f2168accce56..ab4b09f185e5 100644 --- a/code/modules/nano/interaction/mech.dm +++ b/code/modules/nano/interaction/mech.dm @@ -1,4 +1,4 @@ -GLOBAL_DATUM_INIT(mech_state, /datum/topic_state/default/mech, new) +var/global/datum/topic_state/default/mech/mech_topic_state = new /datum/topic_state/default/mech/can_use_topic(var/mob/living/exosuit/src_object, var/mob/user) if(istype(src_object)) diff --git a/code/modules/nano/interaction/outside.dm b/code/modules/nano/interaction/outside.dm index ddecbaffecf2..efd9d1f5db80 100644 --- a/code/modules/nano/interaction/outside.dm +++ b/code/modules/nano/interaction/outside.dm @@ -1,4 +1,4 @@ -GLOBAL_DATUM_INIT(outside_state, /datum/topic_state/default/outside, new) +var/global/datum/topic_state/default/outside/outside_topic_state = new /datum/topic_state/default/outside/can_use_topic(var/src_object, var/mob/user) if(user in src_object) diff --git a/code/modules/nano/interaction/physical.dm b/code/modules/nano/interaction/physical.dm index c916bfc5fc75..cc8b65fa8324 100644 --- a/code/modules/nano/interaction/physical.dm +++ b/code/modules/nano/interaction/physical.dm @@ -1,4 +1,4 @@ -GLOBAL_DATUM_INIT(physical_state, /datum/topic_state/physical, new) +var/global/datum/topic_state/physical/physical_topic_state = new /datum/topic_state/physical/can_use_topic(var/src_object, var/mob/user) . = user.shared_nano_interaction(src_object) @@ -12,12 +12,12 @@ GLOBAL_DATUM_INIT(physical_state, /datum/topic_state/physical, new) return default_can_use_topic(src_object) /mob/living/check_physical_distance(var/src_object) - return shared_living_nano_distance(src_object) + return loc ? loc.contents_nano_distance(src_object, src) : shared_living_nano_distance(src_object) /mob/living/silicon/ai/check_physical_distance(var/src_object) return max(STATUS_UPDATE, shared_living_nano_distance(src_object)) -GLOBAL_DATUM_INIT(physical_no_access_state, /datum/topic_state/physical/no_access, new) +var/global/datum/topic_state/physical/no_access/physical_no_access_topic_state = new /datum/topic_state/physical/no_access check_access = FALSE \ No newline at end of file diff --git a/code/modules/nano/interaction/remote.dm b/code/modules/nano/interaction/remote.dm index 73644fa57070..28dc63c03540 100644 --- a/code/modules/nano/interaction/remote.dm +++ b/code/modules/nano/interaction/remote.dm @@ -7,7 +7,7 @@ var/datum/remote_target var/datum/topic_state/remoter_state -/datum/topic_state/remote/New(var/remoter, var/remote_target, var/datum/topic_state/remoter_state = GLOB.default_state) +/datum/topic_state/remote/New(var/remoter, var/remote_target, var/datum/topic_state/remoter_state = global.default_topic_state) src.remoter = remoter src.remote_target = remote_target src.remoter_state = remoter_state @@ -31,7 +31,7 @@ // This checks if src_object is powered, etc. // The interactive state is otherwise simplistic and only returns STATUS_INTERACTIVE and never checks distances, etc. - . = src_object.CanUseTopic(user, GLOB.interactive_state) + . = src_object.CanUseTopic(user, global.interactive_topic_state) if(. == STATUS_CLOSE) return diff --git a/code/modules/nano/interaction/self.dm b/code/modules/nano/interaction/self.dm index 7080fa7b50a4..865e770d6823 100644 --- a/code/modules/nano/interaction/self.dm +++ b/code/modules/nano/interaction/self.dm @@ -1,7 +1,7 @@ /* This state checks that the src_object is the same the as user */ -GLOBAL_DATUM_INIT(self_state, /datum/topic_state/self_state, new) +var/global/datum/topic_state/self_state/self_topic_state = new /datum/topic_state/self_state/can_use_topic(var/src_object, var/mob/user) if(src_object != user) diff --git a/code/modules/nano/interaction/view.dm b/code/modules/nano/interaction/view.dm index 93d0be47df31..328d83f20fa5 100644 --- a/code/modules/nano/interaction/view.dm +++ b/code/modules/nano/interaction/view.dm @@ -1,7 +1,7 @@ /* This state checks that the src_object is in view of the user. */ -GLOBAL_DATUM_INIT(view_state, /datum/topic_state/view, new) +var/global/datum/topic_state/view/view_topic_state = new /datum/topic_state/view/can_use_topic(src_object, mob/user) return user.view_can_use_topic(src_object) @@ -9,7 +9,7 @@ GLOBAL_DATUM_INIT(view_state, /datum/topic_state/view, new) /mob/proc/view_can_use_topic(src_object) if(!client) return STATUS_CLOSE - if(src_object in view(get_effective_view(client), src)) + if(src_object in view(client.view, src)) return shared_nano_interaction(src_object) return STATUS_CLOSE diff --git a/code/modules/nano/interaction/zlevel.dm b/code/modules/nano/interaction/zlevel.dm index 9f2380e16881..5b0b0f04a537 100644 --- a/code/modules/nano/interaction/zlevel.dm +++ b/code/modules/nano/interaction/zlevel.dm @@ -2,7 +2,7 @@ This state checks that the user is on the same Z-level as src_object */ -GLOBAL_DATUM_INIT(z_state, /datum/topic_state/z_state, new) +var/global/datum/topic_state/z_state/z_topic_state = new /datum/topic_state/z_state/can_use_topic(var/src_object, var/mob/user) var/turf/turf_obj = get_turf(src_object) diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 3118af159446..9ba722beb8c3 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -2,119 +2,135 @@ name = "Appearance Editor" available_to_ai = FALSE var/flags = APPEARANCE_ALL_HAIR - var/mob/living/carbon/human/owner = null - var/list/valid_species = list() - var/list/valid_hairstyles = list() - var/list/valid_facial_hairstyles = list() - + var/mob/living/human/owner = null var/check_whitelist var/list/whitelist var/list/blacklist -/datum/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list()) +/datum/nano_module/appearance_changer/New(var/location, var/mob/living/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list()) ..() owner = H src.check_whitelist = check_species_whitelist src.whitelist = species_whitelist src.blacklist = species_blacklist -/datum/nano_module/appearance_changer/Topic(ref, href_list, var/datum/topic_state/state = GLOB.default_state) +// FIXME: This doesn't currently handle arbitrary sprite accessory categories, so you can't select ears/tail/etc. +/datum/nano_module/appearance_changer/Topic(ref, href_list, var/datum/topic_state/state = global.default_topic_state) if(..()) return 1 - if(href_list["race"]) - if(can_change(APPEARANCE_RACE) && (href_list["race"] in valid_species)) - if(owner.change_species(href_list["race"])) - cut_and_generate_data() - return 1 - if(href_list["gender"]) - if(can_change(APPEARANCE_GENDER) && (href_list["gender"] in owner.species.genders)) - if(owner.change_gender(href_list["gender"])) - cut_and_generate_data() - return 1 - if(href_list["skin_tone"]) - if(can_change_skin_tone()) - var/new_s_tone = input(usr, "Choose your character's skin-tone:\n1 (lighter) - [owner.species.max_skin_tone()] (darker)", "Skin Tone", -owner.skin_tone + 35) as num|null - if(isnum(new_s_tone) && can_still_topic(state) && owner.species.appearance_flags & HAS_SKIN_TONE_NORMAL) - new_s_tone = 35 - max(min(round(new_s_tone), owner.species.max_skin_tone()), 1) - return owner.change_skin_tone(new_s_tone) - if(href_list["skin_color"]) - if(can_change_skin_color()) - var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", owner.skin_colour) as color|null - if(new_skin && can_still_topic(state) && owner.change_skin_color(new_skin)) - update_dna() - return TRUE + if(href_list["race"] && can_change(APPEARANCE_RACE) && (href_list["race"] in owner.generate_valid_species(check_whitelist, whitelist, blacklist)) && owner.change_species(href_list["race"])) + return TRUE + + if(href_list["gender"] && can_change(APPEARANCE_GENDER)) + var/decl/pronouns/pronouns = get_pronouns_by_gender(href_list["gender"]) + if(istype(pronouns) && (pronouns in owner.species.available_pronouns) && owner.set_gender(pronouns.name, TRUE)) + return TRUE + + if(href_list["bodytype"] && can_change(APPEARANCE_BODY)) + var/decl/species/species = owner.get_species() + var/decl/bodytype/B = species.get_bodytype_by_name(href_list["bodytype"]) + if(istype(B) && (B in owner.species.available_bodytypes) && owner.set_bodytype(B)) + return TRUE + + if(href_list["skin_tone"] && can_change_skin_tone()) + var/decl/bodytype/root_bodytype = owner.get_bodytype() + var/new_s_tone = input(usr, "Choose your character's skin-tone:\n1 (lighter) - [root_bodytype.max_skin_tone()] (darker)", "Skin Tone", -owner.skin_tone + 35) as num|null + root_bodytype = owner.get_bodytype() // gotta make sure just in case, since input sleeps + if(isnum(new_s_tone) && can_still_topic(state) && root_bodytype.appearance_flags & HAS_SKIN_TONE_NORMAL) + new_s_tone = 35 - max(min(round(new_s_tone), root_bodytype.max_skin_tone()), 1) + return owner.change_skin_tone(new_s_tone) + + if(href_list["skin_color"] && can_change_skin_color()) + var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", owner.get_skin_colour()) as color|null + if(new_skin && can_still_topic(state) && owner.set_skin_colour(new_skin)) + return TRUE + if(href_list["hair"]) - if(can_change(APPEARANCE_HAIR) && (href_list["hair"] in valid_hairstyles)) - if(owner.change_hair(href_list["hair"])) - update_dna() - return 1 - if(href_list["hair_color"]) - if(can_change(APPEARANCE_HAIR_COLOR)) - var/new_hair = input("Please select hair color.", "Hair Color", owner.hair_colour) as color|null - if(new_hair && can_still_topic(state) && owner.change_hair_color(new_hair)) - update_dna() - return TRUE + var/decl/sprite_accessory/hair = locate(href_list["hair"]) + if(can_change(APPEARANCE_HAIR) && istype(hair) && (hair.type in owner.get_species()?.get_available_accessory_types(owner.get_bodytype(), SAC_HAIR)) && SET_HAIR_STYLE(owner, hair.type, FALSE)) + owner.update_hair() // No idea why this is necessary, setting the accessory above should be fine. + return TRUE + + if(href_list["hair_color"] && can_change(APPEARANCE_HAIR_COLOR)) + var/new_hair_color = input("Please select hair color.", "Hair Color", GET_HAIR_COLOR(owner)) as color|null + if(new_hair_color && can_still_topic(state) && SET_HAIR_COLOR(owner, new_hair_color, FALSE)) + return TRUE + if(href_list["facial_hair"]) - if(can_change(APPEARANCE_FACIAL_HAIR) && (href_list["facial_hair"] in valid_facial_hairstyles)) - if(owner.change_facial_hair(href_list["facial_hair"])) - update_dna() - return 1 - if(href_list["facial_hair_color"]) - if(can_change(APPEARANCE_FACIAL_HAIR_COLOR)) - var/new_facial = input("Please select facial hair color.", "Facial Hair Color", owner.facial_hair_colour) as color|null - if(new_facial && can_still_topic(state) && owner.change_facial_hair_color(new_facial)) - update_dna() - return TRUE + var/decl/sprite_accessory/facial_hair = locate(href_list["facial_hair"]) + if(can_change(APPEARANCE_FACIAL_HAIR) && istype(facial_hair) && (facial_hair.type in owner.get_species()?.get_available_accessory_types(owner.get_bodytype(), SAC_FACIAL_HAIR)) && SET_FACIAL_HAIR_STYLE(owner, facial_hair.type, FALSE)) + owner.update_hair() // No idea why this is necessary, setting the accessory above should be fine. + return TRUE + + if(href_list["facial_hair_color"] && can_change(APPEARANCE_FACIAL_HAIR_COLOR)) + var/new_facial = input("Please select facial hair color.", "Facial Hair Color", GET_FACIAL_HAIR_COLOR(owner)) as color|null + if(new_facial && can_still_topic(state) && SET_FACIAL_HAIR_COLOR(owner, new_facial, FALSE)) + return TRUE + if(href_list["eye_color"]) if(can_change(APPEARANCE_EYE_COLOR)) - var/new_eyes = input("Please select eye color.", "Eye Color", owner.eye_colour) as color|null - if(new_eyes && can_still_topic(state) && owner.change_eye_color(new_eyes)) - update_dna() + var/new_eyes = input("Please select eye color.", "Eye Color", owner.get_eye_colour()) as color|null + if(new_eyes && can_still_topic(state) && owner.set_eye_colour(new_eyes)) return TRUE - return 0 + return FALSE -/datum/nano_module/appearance_changer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/appearance_changer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) if(!owner || !owner.species) return - generate_data(check_whitelist, whitelist, blacklist) var/list/data = host.initial_data() - - data["specimen"] = owner.species.name + data["current_species_uid"] = owner.species.uid data["gender"] = owner.gender data["change_race"] = can_change(APPEARANCE_RACE) if(data["change_race"]) var/species[0] - for(var/specimen in valid_species) - species[++species.len] = list("specimen" = specimen) + for(var/species_uid in owner.generate_valid_species(check_whitelist, whitelist, blacklist)) + var/decl/species/candidate_species = decls_repository.get_decl_by_id(species_uid) + species[++species.len] = list("uid" = species_uid, "name" = candidate_species.name) data["species"] = species data["change_gender"] = can_change(APPEARANCE_GENDER) if(data["change_gender"]) var/genders[0] - for(var/gender in owner.species.genders) - genders[++genders.len] = list("gender_name" = gender2text(gender), "gender_key" = gender) + for(var/decl/pronouns/pronouns as anything in owner.species.available_pronouns) + genders[++genders.len] = list("gender_name" = pronouns.pronoun_string, "gender_key" = pronouns.name) data["genders"] = genders + + data["bodytype"] = capitalize(owner.get_bodytype().name) + data["change_bodytype"] = can_change(APPEARANCE_BODY) + if(data["change_bodytype"]) + var/bodytypes[0] + for(var/decl/bodytype/B as anything in owner.species.available_bodytypes) + bodytypes += capitalize(B.name) + data["bodytypes"] = bodytypes + data["change_skin_tone"] = can_change_skin_tone() data["change_skin_color"] = can_change_skin_color() data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR) data["change_hair"] = can_change(APPEARANCE_HAIR) + if(data["change_hair"]) var/hair_styles[0] - for(var/hair_style in valid_hairstyles) - hair_styles[++hair_styles.len] = list("hairstyle" = hair_style) + for(var/hair_style in owner.get_species()?.get_available_accessory_types(owner.get_bodytype(), SAC_HAIR)) + var/decl/sprite_accessory/hair_decl = GET_DECL(hair_style) + hair_styles[++hair_styles.len] = list("hairstyle" = hair_decl.name, "ref" = "\ref[hair_decl]") data["hair_styles"] = hair_styles - data["hair_style"] = owner.h_style + var/hairstyle = GET_HAIR_STYLE(owner) + var/decl/sprite_accessory/hair = GET_DECL(hairstyle) || GET_DECL(/decl/sprite_accessory/hair/bald) + data["hair_style"] = hair.name data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR) if(data["change_facial_hair"]) var/facial_hair_styles[0] - for(var/facial_hair_style in valid_facial_hairstyles) - facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style) + for(var/facial_hair_style in owner.get_species()?.get_available_accessory_types(owner.get_bodytype(), SAC_FACIAL_HAIR)) + var/decl/sprite_accessory/facial_hair_decl = GET_DECL(facial_hair_style) + facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_decl.name, "ref" = "\ref[facial_hair_decl]") data["facial_hair_styles"] = facial_hair_styles - data["facial_hair_style"] = owner.f_style + var/facial_hairstyle = GET_FACIAL_HAIR_STYLE(owner) + var/decl/sprite_accessory/facial_hair = GET_DECL(facial_hairstyle) || GET_DECL(/decl/sprite_accessory/facial_hair/shaved) + data["facial_hair_style"] = facial_hair.name data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) @@ -125,30 +141,11 @@ ui.open() ui.set_auto_update(1) -/datum/nano_module/appearance_changer/proc/update_dna() - if(owner && (flags & APPEARANCE_UPDATE_DNA)) - owner.update_dna() - /datum/nano_module/appearance_changer/proc/can_change(var/flag) return owner && (flags & flag) /datum/nano_module/appearance_changer/proc/can_change_skin_tone() - return owner && (flags & APPEARANCE_SKIN) && owner.species.appearance_flags & HAS_A_SKIN_TONE + return owner && (flags & APPEARANCE_SKIN) && owner.get_bodytype().appearance_flags & HAS_A_SKIN_TONE /datum/nano_module/appearance_changer/proc/can_change_skin_color() - return owner && (flags & APPEARANCE_SKIN) && owner.species.appearance_flags & HAS_SKIN_COLOR - -/datum/nano_module/appearance_changer/proc/cut_and_generate_data() - // Making the assumption that the available species remain constant - valid_facial_hairstyles.Cut() - valid_facial_hairstyles.Cut() - generate_data() - -/datum/nano_module/appearance_changer/proc/generate_data() - if(!owner) - return - if(!valid_species.len) - valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist) - if(!valid_hairstyles.len || !valid_facial_hairstyles.len) - valid_hairstyles = owner.generate_valid_hairstyles(check_gender = 0) - valid_facial_hairstyles = owner.generate_valid_facial_hairstyles() + return owner && (flags & APPEARANCE_SKIN) && owner.get_bodytype().appearance_flags & HAS_SKIN_COLOR diff --git a/code/modules/nano/modules/law_manager.dm b/code/modules/nano/modules/law_manager.dm index aa5996c83aca..b2c53c8388f5 100644 --- a/code/modules/nano/modules/law_manager.dm +++ b/code/modules/nano/modules/law_manager.dm @@ -8,8 +8,8 @@ var/current_view = 0 - var/global/list/datum/ai_laws/admin_laws - var/global/list/datum/ai_laws/player_laws + var/static/list/datum/ai_laws/admin_laws + var/static/list/datum/ai_laws/player_laws var/mob/living/silicon/owner = null /datum/nano_module/law_manager/New(var/mob/living/silicon/S) @@ -53,17 +53,17 @@ return 1 if(href_list["add_ion_law"]) - if(ion_law && is_traitor(usr)) + if(ion_law && is_jailbroken(usr)) owner.add_ion_law(ion_law) return 1 if(href_list["add_inherent_law"]) - if(inherent_law && is_traitor(usr)) + if(inherent_law && is_jailbroken(usr)) owner.add_inherent_law(inherent_law) return 1 if(href_list["add_supplied_law"]) - if(supplied_law && supplied_law_position >= 1 && MIN_SUPPLIED_LAW_NUMBER <= MAX_SUPPLIED_LAW_NUMBER && is_traitor(usr)) + if(supplied_law && supplied_law_position >= 1 && MIN_SUPPLIED_LAW_NUMBER <= MAX_SUPPLIED_LAW_NUMBER && is_jailbroken(usr)) owner.add_supplied_law(supplied_law_position, supplied_law) return 1 @@ -94,23 +94,23 @@ if(href_list["change_supplied_law_position"]) var/new_position = input(usr, "Enter new supplied law position between 1 and [MAX_SUPPLIED_LAW_NUMBER], inclusive. Inherent laws at the same index as a supplied law will not be stated.", "Law Position", supplied_law_position) as num|null if(isnum(new_position) && can_still_topic()) - supplied_law_position = Clamp(new_position, 1, MAX_SUPPLIED_LAW_NUMBER) + supplied_law_position = clamp(new_position, 1, MAX_SUPPLIED_LAW_NUMBER) return 1 if(href_list["edit_law"]) - if(is_traitor(usr)) + if(is_jailbroken(usr)) var/datum/ai_law/AL = locate(href_list["edit_law"]) in owner.laws.all_laws() if(AL) var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", AL.law)) - if(new_law && new_law != AL.law && is_traitor(usr) && can_still_topic()) + if(new_law && new_law != AL.law && is_jailbroken(usr) && can_still_topic()) log_and_message_admins("has changed a law of [owner] from '[AL.law]' to '[new_law]'") AL.law = new_law return 1 if(href_list["delete_law"]) - if(is_traitor(usr)) + if(is_jailbroken(usr)) var/datum/ai_law/AL = locate(href_list["delete_law"]) in owner.laws.all_laws() - if(AL && is_traitor(usr)) + if(AL && is_jailbroken(usr)) owner.delete_law(AL) return 1 @@ -125,7 +125,7 @@ return 1 if(href_list["transfer_laws"]) - if(is_traitor(usr)) + if(is_jailbroken(usr)) var/datum/ai_laws/ALs = locate(href_list["transfer_laws"]) in (is_admin(usr) ? admin_laws : player_laws) if(ALs) log_and_message_admins("has transfered the [ALs.name] laws to [owner].") @@ -138,16 +138,16 @@ owner.laws.show_laws(owner) if(isAI(owner)) var/mob/living/silicon/ai/AI = owner - for(var/mob/living/silicon/robot/R in AI.connected_robots) - to_chat(R, "Law Notice") - R.laws.show_laws(R) + for(var/mob/living/silicon/robot/robot in AI.connected_robots) + to_chat(robot, "Law Notice") + robot.laws.show_laws(robot) if(usr != owner) to_chat(usr, "Laws displayed.") return 1 return 0 -/datum/nano_module/law_manager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/law_manager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/data[0] owner.lawsync() @@ -164,7 +164,7 @@ package_laws(data, "supplied_laws", owner.laws.supplied_laws) data["isAI"] = isAI(owner) - data["isMalf"] = is_traitor(user) + data["isMalf"] = is_jailbroken(user) data["isSlaved"] = owner.is_slaved() data["isAdmin"] = is_admin(user) data["view"] = current_view @@ -178,7 +178,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "law_manager.tmpl", sanitize("[src] - [owner]"), 800, is_traitor(user) ? 600 : 400, state = state) + ui = new(user, src, ui_key, "law_manager.tmpl", sanitize("[src] - [owner]"), 800, is_jailbroken(user) ? 600 : 400, state = state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -202,8 +202,8 @@ return law_sets -/datum/nano_module/law_manager/proc/is_traitor(var/mob/user) - return (is_admin(user) && !owner.is_slaved()) || owner.is_traitor() +/datum/nano_module/law_manager/proc/is_jailbroken(var/mob/user) + return (is_admin(user) && !owner.is_slaved()) || owner.is_malfunctioning() /mob/living/silicon/proc/is_slaved() return 0 @@ -214,6 +214,6 @@ /datum/nano_module/law_manager/proc/sync_laws(var/mob/living/silicon/ai/AI) if(!AI) return - for(var/mob/living/silicon/robot/R in AI.connected_robots) - R.sync() - log_and_message_admins("has syncronized [AI]'s laws with its borgs.") + for(var/mob/living/silicon/robot/robot in AI.connected_robots) + robot.sync() + log_and_message_admins("has synchronized [AI]'s laws with its borgs.") diff --git a/code/modules/nano/modules/nano_module.dm b/code/modules/nano/modules/nano_module.dm index b544c18d8e5e..446f41ffdbf1 100644 --- a/code/modules/nano/modules/nano_module.dm +++ b/code/modules/nano/modules/nano_module.dm @@ -18,7 +18,7 @@ /datum/nano_module/nano_host() return host ? host : src -/datum/nano_module/proc/can_still_topic(var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/proc/can_still_topic(var/datum/topic_state/state = global.default_topic_state) return CanUseTopic(usr, state) == STATUS_INTERACTIVE /datum/nano_module/proc/check_eye(var/mob/user) @@ -26,11 +26,11 @@ //returns a list. /datum/nano_module/proc/get_access(mob/user) - . = using_access - if(istype(user)) + . = using_access.Copy() + if(user) // Insist on scanning ID again to make things a little less clunky. var/obj/item/card/id/I = user.GetIdCard() if(I) - . |= I.access + . |= I.GetAccess() /datum/nano_module/proc/check_access(var/mob/user, var/access) if(!access) @@ -50,11 +50,11 @@ return get_z(nano_host()) /datum/nano_module/proc/print_text(var/text, var/mob/user) - var/datum/extension/interactive/ntos/os = get_extension(nano_host(), /datum/extension/interactive/ntos) + var/datum/extension/interactive/os/os = get_extension(nano_host(), /datum/extension/interactive/os) if(os) os.print_paper(text) else - to_chat(user, "Error: Unable to detect compatible printer interface. Are you running NTOSv2 compatible system?") + to_chat(user, "Error: Unable to detect compatible printer interface. Are you running a compatible system?") /datum/proc/initial_data() return list() diff --git a/code/modules/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm index 28b4c16c33b5..ea9cc195f21f 100644 --- a/code/modules/nano/nanoexternal.dm +++ b/code/modules/nano/nanoexternal.dm @@ -11,7 +11,7 @@ set name = "Reset NanoUI" set category = "OOC" - var/ui_amt = length(mob.open_uis) + var/ui_amt = length(mob.opened_uis) SSnano.close_user_uis(mob) to_chat(src, "[ui_amt] UI windows reset.") @@ -30,10 +30,9 @@ if (istype(ui)) ui.close() - if(ui.ref) var/href = "close=1" - src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic() + src.Topic(href, params2list(href), ui.ref) // this will direct to the datum's Topic() proc via client.Topic() else if (ui.on_close_logic) // no atomref specified (or not found) // so just reset the user mob's machine var @@ -52,7 +51,7 @@ * * @return nothing */ -/datum/proc/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/nanoui/master_ui = null, datum/topic_state/state = GLOB.default_state) +/datum/proc/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, datum/nanoui/master_ui = null, datum/topic_state/state = global.default_topic_state) return /** @@ -68,5 +67,7 @@ return list() // Not implemented. -// Used by SSnano (/datum/controller/subsystem/processing/nano) to track UIs opened by this mob -/mob/var/list/open_uis +/// Lazy associative list of /nanoui UIs opened on this object, according to ui_key. Not to be confused with opened_uis on mob. +/datum/var/tmp/list/open_uis +/// Used by SSnano (/datum/controller/subsystem/processing/nano) to track UIs opened by this mob. +/mob/var/list/opened_uis diff --git a/code/modules/nano/nanomapgen.dm b/code/modules/nano/nanomapgen.dm index 8d58cb06f105..86b3bc85f622 100644 --- a/code/modules/nano/nanomapgen.dm +++ b/code/modules/nano/nanomapgen.dm @@ -21,7 +21,11 @@ set category = "Server" if(holder) - nanomapgen_DumpTile(1, 1, text2num(input(usr,"Enter the Z level to generate"))) + var/zlevel = text2num(input(usr,"Enter the Z level to generate")) + if(!zlevel) + return + var/datum/level_data/level = SSmapping.levels_by_z[zlevel] + nanomapgen_DumpTile(level.level_inner_min_x, level.level_inner_min_y, zlevel, level.level_inner_max_x, level.level_inner_max_y) /client/proc/nanomapgen_DumpTile(var/startX = 1, var/startY = 1, var/currentZ = 1, var/endX = -1, var/endY = -1) @@ -66,13 +70,13 @@ var/icon/TurfIcon = new(Turf.icon, Turf.icon_state, dir = Turf.dir) TurfIcon.Scale(NANOMAP_ICON_SIZE, NANOMAP_ICON_SIZE) - Tile.Blend(TurfIcon, ICON_OVERLAY, ((WorldX - 1) * NANOMAP_ICON_SIZE), ((WorldY - 1) * NANOMAP_ICON_SIZE)) + Tile.Blend(TurfIcon, ICON_OVERLAY, ((WorldX - startX) * NANOMAP_ICON_SIZE), ((WorldY - startY) * NANOMAP_ICON_SIZE)) count++ if (count % 8000 == 0) to_world_log("NanoMapGen: [count] tiles done") - sleep(1) + CHECK_TICK var/mapFilename = "new_[map_image_file_name(currentZ)]" diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 1622b3697d48..e5310e15826d 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -24,7 +24,7 @@ nanoui is used to open and update nano browser uis // whether to use extra logic when window closes var/on_close_logic = 1 // an extra ref to use when the window is closed, usually null - var/atom/ref = null + var/datum/ref = null // options for modifying window behaviour var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id // the list of stylesheets to apply to this ui @@ -73,7 +73,7 @@ nanoui is used to open and update nano browser uis * * @return /nanoui new nanoui object */ -/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/datum/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = global.default_topic_state) user = nuser src_object = nsrc_object ui_key = nui_key @@ -124,6 +124,7 @@ nanoui is used to open and update nano browser uis add_stylesheet("shared.css") // this CSS sheet is common to all UIs add_stylesheet("tgui.css") // this CSS sheet is common to all UIs add_stylesheet("icons.css") // this CSS sheet is common to all UIs + add_stylesheet("fonts.css") //Common Fonts /** * Set the current status (also known as visibility) of this ui. @@ -133,7 +134,7 @@ nanoui is used to open and update nano browser uis * * @return nothing */ -/datum/nanoui/proc/set_status(state, push_update) +/datum/nanoui/proc/set_nano_status(state, push_update) if (state != status) // Only update if it is different if (status == STATUS_DISABLED) status = state @@ -163,7 +164,7 @@ nanoui is used to open and update nano browser uis if(new_status == STATUS_CLOSE) close() return 1 - set_status(new_status, push_update) + set_nano_status(new_status, push_update) /** * Set the ui to auto update (every master_controller tick) @@ -193,7 +194,7 @@ nanoui is used to open and update nano browser uis /datum/nanoui/proc/get_config_data() var/name = "[src_object]" name = sanitize(name) - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) var/list/config_data = list( "title" = title, "srcObject" = list("name" = name), @@ -202,11 +203,12 @@ nanoui is used to open and update nano browser uis "autoUpdateLayout" = auto_update_layout, "autoUpdateContent" = auto_update_content, "showMap" = show_map, - "mapName" = GLOB.using_map.path, + "mapName" = global.using_map.path, "mapZLevel" = map_z_level, - "mapZLevels" = GLOB.using_map.map_levels, + "mapZLevels" = SSmapping.map_levels, "user" = list("name" = user.name), "currency" = cur.name, + "templateFileName" = global.template_file_name ) return config_data @@ -249,7 +251,7 @@ nanoui is used to open and update nano browser uis stylesheets.Add(file) /** - * Add a JavsScript script to this UI + * Add a JavaScript script to this UI * These must be added before the UI has been opened, adding after that will have no effect * * @param file string The name of the JavaScript file from /nano/js (e.g. "my_script.js") @@ -380,13 +382,13 @@ nanoui is used to open and update nano browser uis return {" - + @@ -492,12 +494,7 @@ nanoui is used to open and update nano browser uis return // Closed if (status == STATUS_DISABLED && !force_push) return // Cannot update UI, no visibility - - var/list/send_data = get_send_data(data) - -// to_chat(user, list2json_usecache(send_data))// used for debugging //NANO DEBUG HOOK - - user << output(list2params(list(strip_improper(json_encode(send_data)))),"[window_id].browser:receiveUpdateData") + to_output(user, list2params(list(strip_improper(json_encode(get_send_data(data))))),"[window_id].browser:receiveUpdateData") /** * This Topic() proc is called whenever a user clicks on a link within a Nano UI @@ -517,13 +514,14 @@ nanoui is used to open and update nano browser uis set_show_map(text2num(href_list["showMap"])) map_update = 1 - if(href_list["mapZLevel"]) - var/map_z = text2num(href_list["mapZLevel"]) - if(map_z in GLOB.using_map.map_levels) + if(href_list["switchMapZLevel"]) + var/map_z = text2num(href_list["switchMapZLevel"]) + if(isMapLevel(map_z)) set_map_z_level(map_z) map_update = 1 - if ((src_object && src_object.Topic(href, href_list, state)) || map_update) + // src_object.Topic() might null out src_object by deleting us. + if (src_object && (src_object.Topic(href, href_list, state) || (!QDELETED(src) && src_object && map_update))) SSnano.update_uis(src_object) // update all UIs attached to src_object /** @@ -533,13 +531,13 @@ nanoui is used to open and update nano browser uis * * @return nothing */ -/datum/nanoui/proc/try_update(update = 0) +/datum/nanoui/proc/try_update(update = 0, force_open = FALSE) if (!src_object || !user) close() return if (status && (update || is_auto_updating)) - update() // Update the UI (update_status() is called whenever a UI is updated) + update(force_open) // Update the UI (update_status() is called whenever a UI is updated) else update_status(1) // Not updating UI, so lets check here if status has changed diff --git a/code/modules/organs/ailments/_ailment.dm b/code/modules/organs/ailments/_ailment.dm new file mode 100644 index 000000000000..fc3853f0b4a8 --- /dev/null +++ b/code/modules/organs/ailments/_ailment.dm @@ -0,0 +1,135 @@ +/datum/ailment + abstract_type = /datum/ailment + var/name // Descriptive name, primarily used for adminbus. + var/timer_id // Current timer waiting to proc next symptom message. + var/min_time = 2 MINUTES // Minimum time between symptom messages. + var/max_time = 5 MINUTES // Maximum time between symptom messages. + var/obj/item/organ/organ // Organ associated with the ailment (ailment is in organ.ailments list). + + // Requirements before applying to a target. + var/list/applies_to_organ // What organ tags (BP_HEAD, etc) is the ailment valid for? + var/applies_to_prosthetics = FALSE // Does the ailment affect prosthetic or non-prosthetic limbs? + var/applies_to_robotics = FALSE // Does the ailment affect robotic limbs? + var/applies_to_crystalline = FALSE // Does the ailment affect crystalline limbs? + var/specific_organ_subtype = /obj/item/organ/external // What organ subtype, if any, does the ailment apply to? + + // Treatment types + var/treated_by_item_type // What item type can be used in physical interaction to cure the ailment? + var/treated_by_item_cost = 1 // If treated_by_item_type is a stack, how many should be used? + var/list/treated_by_reagent_type // What reagent type(s) cures this ailment when metabolized? Can be a single type or a list of types. + var/treated_by_reagent_dosage = 1 // What is the minimum dosage for a reagent to cure this ailment? TODO: merge with list above + var/list/treated_by_chem_effect // What chemical effect cures this ailment? Can be a single effect or a list of effects. + var/treated_by_chem_effect_strength = 1 // How strong must the chemical effect be to cure this ailment? TODO: merge with list above + + // Fluff strings + var/initial_ailment_message = "Your $ORGAN$ $ORGAN_DOES$n't feel quite right..." // Shown in New() + var/third_person_treatment_message = "$USER$ treats $TARGET$'s ailment with $ITEM$." // Shown when treating other with an item. + var/self_treatment_message = "$USER$ treats $USER_THEIR$ ailment with $ITEM$." // Shown when treating self with an item. + var/medication_treatment_message = "Your ailment abates." // Shown when treated by a metabolized reagent or CE_X effect. + var/manual_diagnosis_string /* ex: "$USER_THEIR$ $ORGAN$ has something wrong with it" */ // Shown when grab-diagnosed by a doctor. Leave null to be undiagnosable. + var/scanner_diagnosis_string /* ex: "Significant swelling" */ // Shown on the handheld and body scanners. Leave null to be undiagnosable. + + var/hidden_from_codex = FALSE + +/datum/ailment/New(var/obj/item/organ/_organ) + ..() + if(_organ) + organ = _organ + if(organ.owner) + to_chat(organ.owner, SPAN_WARNING(replace_tokens(initial_ailment_message))) + begin_ailment_event() + +/datum/ailment/proc/can_apply_to(var/obj/item/organ/_organ) + if(specific_organ_subtype && !istype(_organ, specific_organ_subtype)) + return FALSE + if(!isnull(applies_to_prosthetics) && (applies_to_prosthetics != !!BP_IS_PROSTHETIC(_organ))) + return FALSE + if(!isnull(applies_to_robotics) && (applies_to_robotics != !!BP_IS_ROBOTIC(_organ))) + return FALSE + if(!isnull(applies_to_crystalline) && (applies_to_crystalline != !!BP_IS_CRYSTAL(_organ))) + return FALSE + if(length(applies_to_organ) && !(_organ?.organ_tag in applies_to_organ)) + return FALSE + return TRUE + +/datum/ailment/Destroy() + if(organ) + LAZYREMOVE(organ.ailments, src) + organ = null + . = ..() + +/datum/ailment/proc/begin_ailment_event() + if(!organ?.owner) + return + timer_id = addtimer(CALLBACK(src, PROC_REF(do_malfunction)), rand(min_time, max_time), TIMER_STOPPABLE | TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_NO_HASH_WAIT) + +/datum/ailment/proc/do_malfunction() + if(!organ?.owner) + timer_id = null + return + begin_ailment_event() + on_ailment_event() + +/datum/ailment/proc/on_ailment_event() + return + +/datum/ailment/proc/treated_by_item(var/obj/item/treatment) + if(islist(treated_by_item_type)) + for(var/treatment_type in treated_by_item_type) + if(istype(treatment, treatment_type)) + return TRUE + else if(ispath(treated_by_item_type)) + return istype(treatment, treated_by_item_type) + return FALSE + +/datum/ailment/proc/replace_tokens(var/message, var/obj/item/treatment, var/mob/user, var/mob/target) + . = message + if(treatment) + . = replacetext(., "$ITEM$", "\the [treatment]") + if(user) + var/decl/pronouns/pronouns = user.get_pronouns() + . = replacetext(., "$USER$", "\the [user]") + . = replacetext(., "$USER_THEIR$", pronouns.his) + if(target) + . = replacetext(., "$TARGET$", "\the [target]") + if(organ) + . = replacetext(., "$ORGAN$", organ.name) + var/decl/pronouns/organ_pronouns = organ.get_pronouns() + . = replacetext(., "$ORGAN_DOES$", organ_pronouns.does) + . = replacetext(., "$ORGAN_IS$", organ_pronouns.is) + . = capitalize(trim(.)) + +/datum/ailment/proc/was_treated_by_item(var/obj/item/treatment, var/mob/user, var/mob/target) + var/show_message + if(user == target && self_treatment_message) + show_message = self_treatment_message + else + show_message = third_person_treatment_message + if(!show_message) + return + + user.visible_message(SPAN_NOTICE(replace_tokens(show_message, treatment, user, target))) + + if(istype(treatment, /obj/item/stack)) + var/obj/item/stack/stack = treatment + stack.use(treated_by_item_cost) + qdel(src) + +/datum/ailment/proc/treated_by_medication(var/reagent_type, var/dosage) + if(!treated_by_reagent_type || dosage < treated_by_reagent_dosage) + return FALSE + if(islist(treated_by_reagent_type)) + for(var/treatment_type in treated_by_reagent_type) + if(ispath(reagent_type, treatment_type)) + return TRUE + return FALSE + return ispath(reagent_type, treated_by_reagent_type) + +/datum/ailment/proc/was_treated_by_medication(var/datum/reagents/source, var/reagent_type) + source.remove_reagent(reagent_type, treated_by_reagent_dosage) + to_chat(organ.owner, SPAN_NOTICE(replace_tokens(medication_treatment_message))) + qdel(src) + +/datum/ailment/proc/was_treated_by_chem_effect() + to_chat(organ.owner, SPAN_NOTICE(replace_tokens(medication_treatment_message))) + qdel(src) diff --git a/code/modules/organs/ailments/ailment_codex.dm b/code/modules/organs/ailments/ailment_codex.dm new file mode 100644 index 000000000000..566446dd17ef --- /dev/null +++ b/code/modules/organs/ailments/ailment_codex.dm @@ -0,0 +1,65 @@ +/datum/codex_entry/guide/ailments + name = "Guide to Medical Ailments" + mechanics_text = "Ailments are minor medical conditions that can crop up during a round. They aren't life-threatening, and frequently aren't anything more than slightly annoying, and treating them is generally straightforward." + lore_text = "Day to day life can exert stress on the body, which can manifest in small, non-critical medical conditions like a sore back or a headache. 9/10 doctors recommend a visit to your local physician for treatment before they compound into a chronic or acute condition." + var/show_robotics_recipes = FALSE + var/name_column = "Ailment" + var/treatment_column = "Recommended treatment" + +/datum/codex_entry/guide/ailments/robotic + name = "Prosthetic Faults" + lore_text = "Prosthetic limbs can be prone to debilitating and often dangerous faults, especially if exposed to hostile conditions." + mechanics_text = "EMP damage or improper installation can cause prosthetic limbs to develop problems, some of them more serious than others." + show_robotics_recipes = TRUE + name_column = "Fault" + treatment_column = "Recommended repair" + available_to_map_tech_level = MAP_TECH_LEVEL_SPACE + +/proc/get_chem_effect_display_name(effect) + switch(effect) + if(CE_PAINKILLER) + return "painkillers" + if(CE_ANTIBIOTIC) + return "antibiotics" + if(CE_ALCOHOL) + return "alcohol" + if(CE_ALCOHOL_TOXIC) + return "alcohol overdose" + if(CE_ANTITOX) + return "antitoxins" + if(CE_TOXIN) + return "toxins" + if(CE_SEDATE) + return "sedative drugs" + if(CE_ENERGETIC) + return "stimulant drugs" + return null + +/datum/codex_entry/guide/ailments/New() + var/list/ailment_table = list("") + ailment_table += "" + for(var/atype in subtypesof(/datum/ailment)) + var/datum/ailment/ailment = get_ailment_reference(atype) + if(!ailment || show_robotics_recipes != ailment.applies_to_prosthetics || ailment.hidden_from_codex) + continue + ailment_table += "" + ailment_table += "
    [name_column][treatment_column]
    [ailment.name]" + var/list/ailment_cures = list() + var/list/treated_by_types = islist(ailment.treated_by_item_type) ? ailment.treated_by_item_type : list(ailment.treated_by_item_type) + for(var/obj/item/thing as anything in treated_by_types) // if you put a non-item in here you deserve to have your face eaten by runtime errors + ailment_cures += "[ailment.treated_by_item_cost] x [initial(thing.name)]" + if(ailment.treated_by_reagent_type) + if(islist(ailment.treated_by_reagent_type)) + for(var/mat_type in ailment.treated_by_reagent_type) + var/decl/material/mat = GET_DECL(mat_type) + ailment_cures += "[ailment.treated_by_reagent_dosage]u [mat.name]" + else + var/decl/material/mat = GET_DECL(ailment.treated_by_reagent_type) + ailment_cures += "[ailment.treated_by_reagent_dosage]u [mat.name]" + if(ailment.treated_by_chem_effect) + ailment_cures += get_chem_effect_display_name(ailment.treated_by_chem_effect) + if(!length(ailment_cures)) + ailment_cures += "Unknown." + ailment_table += "[jointext(ailment_cures,"
    ")]
    " + mechanics_text = "[mechanics_text]

    Known [name]

    [jointext(ailment_table, "")]" + ..() \ No newline at end of file diff --git a/code/modules/organs/ailments/ailments_medical.dm b/code/modules/organs/ailments/ailments_medical.dm new file mode 100644 index 000000000000..c9d3dad97511 --- /dev/null +++ b/code/modules/organs/ailments/ailments_medical.dm @@ -0,0 +1,154 @@ +/datum/ailment/head + abstract_type = /datum/ailment/head + applies_to_organ = list(BP_HEAD) + +/datum/ailment/head/headache + name = "headache" + treated_by_chem_effect = CE_PAINKILLER + treated_by_chem_effect_strength = 25 + medication_treatment_message = "Your headache grudgingly fades away." + +/datum/ailment/head/headache/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Your [organ.name] pulses with a sudden headache.")) + var/obj/item/organ/external/E = organ + if(istype(E) && E.pain < 5) + E.add_pain(5) + +/datum/ailment/head/tinnitus + name = "tinnitus" + treated_by_reagent_type = /decl/material/liquid/brute_meds + treated_by_reagent_dosage = 1 + medication_treatment_message = "The high-pitched ringing in your ears slowly fades to nothing." + +/datum/ailment/head/tinnitus/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Your ears ring with an irritating, high-pitched tone.")) + SET_STATUS_MAX(organ.owner, STAT_DEAF, 3) + +/datum/ailment/head/sore_throat + name = "sore throat" + treated_by_reagent_type = /decl/material/liquid/nutriment/honey + treated_by_reagent_dosage = 1 + medication_treatment_message = "You swallow, finding that your sore throat is rapidly recovering." + manual_diagnosis_string = "$USER_THEIR$ throat is red and inflamed." + +/datum/ailment/head/sore_throat/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("You swallow painfully past your sore throat.")) + +/datum/ailment/head/sneezing + name = "sneezing" + treated_by_reagent_type = list( + /decl/material/liquid/antiseptic, + /decl/material/liquid/drink/juice/nettle + ) + treated_by_reagent_dosage = 1 + medication_treatment_message = "The itching in your sinuses fades away." + manual_diagnosis_string = "$USER_THEIR$ sinuses are inflamed and running." + +/datum/ailment/head/sneezing/can_apply_to(obj/item/organ/_organ) + . = ..() && _organ.owner + if(.) + var/decl/emote/emote = GET_DECL(/decl/emote/audible/sneeze) + return emote.mob_can_use(_organ.owner) + +/datum/ailment/head/sneezing/on_ailment_event() + organ.owner.emote(/decl/emote/audible/sneeze) + organ.owner.setClickCooldown(3) + +/datum/ailment/sprain + name = "sprained limb" + applies_to_organ = list(BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT) + treated_by_item_type = /obj/item/stack/medical/bandage + third_person_treatment_message = "$USER$ wraps $TARGET$'s sprained $ORGAN$ in $ITEM$." + self_treatment_message = "$USER$ wraps $USER_THEIR$ sprained $ORGAN$ in $ITEM$." + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ is visibly swollen." + +/datum/ailment/sprain/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Your sprained [organ.name] aches distractingly.")) + organ.owner.setClickCooldown(3) + var/obj/item/organ/external/E = organ + if(istype(E) && E.pain < 3) + E.add_pain(3) + +/datum/ailment/rash + name = "rash" + treated_by_item_type = /obj/item/stack/medical/ointment + third_person_treatment_message = "$USER$ salves $TARGET$'s rash-stricken $ORGAN$ with $ITEM$." + self_treatment_message = "$USER$ salves $USER_THEIR$ rash-stricken $ORGAN$ with $ITEM$." + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ is covered in a bumpy red rash." + +/datum/ailment/rash/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("A bright red rash on your [organ.name] itches distractingly.")) + organ.owner.setClickCooldown(3) + +/datum/ailment/coughing + name = "coughing" + specific_organ_subtype = /obj/item/organ/internal/lungs + applies_to_organ = list(BP_LUNGS) + treated_by_reagent_type = list( + /decl/material/liquid/antiseptic, + /decl/material/liquid/drink/juice/nettle + ) + medication_treatment_message = "The tickling in your throat fades away." + manual_diagnosis_string = "$USER_THEIR$ throat is red and inflamed." + +/datum/ailment/coughing/can_apply_to(obj/item/organ/_organ) + . = ..() && _organ.owner + if(.) + var/decl/emote/emote = GET_DECL(/decl/emote/audible/cough) + return emote.mob_can_use(_organ.owner) + +/datum/ailment/coughing/on_ailment_event() + organ.owner.cough() + organ.owner.setClickCooldown(3) + +/datum/ailment/sore_joint + name = "sore joint" + treated_by_chem_effect = CE_PAINKILLER + treated_by_chem_effect_strength = 25 + medication_treatment_message = "The dull pulse of pain in your $ORGAN$ fades away." + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ is visibly swollen." + +/datum/ailment/sore_joint/on_ailment_event() + var/obj/item/organ/external/E = organ + to_chat(organ.owner, SPAN_DANGER("Your [istype(E) ? E.joint : organ.name] aches uncomfortably.")) + organ.owner.setClickCooldown(3) + if(istype(E) && E.pain < 3) + E.add_pain(3) + +/datum/ailment/sore_joint/can_apply_to(obj/item/organ/_organ) + var/obj/item/organ/external/E = _organ + . = ..() && !isnull(E.joint) && (E.limb_flags & ORGAN_FLAG_CAN_DISLOCATE) + +/datum/ailment/sore_back + name = "sore back" + applies_to_organ = list(BP_CHEST) + treated_by_chem_effect = CE_PAINKILLER + treated_by_chem_effect_strength = 25 + medication_treatment_message = "You straighten, finding that your back is no longer hurting." + +/datum/ailment/sore_back/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Your back spasms painfully, causing you to hunch for a moment.")) + organ.owner.setClickCooldown(3) + +/datum/ailment/stomach_ache + name = "stomach ache" + specific_organ_subtype = /obj/item/organ/internal/stomach + applies_to_organ = list(BP_STOMACH) + treated_by_reagent_type = /decl/material/solid/carbon + medication_treatment_message = "The nausea in your $ORGAN$ slowly fades away." + +/datum/ailment/stomach_ache/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Your stomach roils unpleasantly.")) + organ.owner.setClickCooldown(3) + +/datum/ailment/cramps + name = "cramps" + treated_by_reagent_type = /decl/material/liquid/sedatives // in lieu of muscle relaxants + medication_treatment_message = "The painful cramping in your $ORGAN$ relaxes." + +/datum/ailment/cramps/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Your [organ.name] suddenly clenches in a painful cramp.")) + organ.owner.setClickCooldown(3) + var/obj/item/organ/external/E = organ + if(istype(E) && E.pain < 3) + E.add_pain(3) diff --git a/code/modules/organs/ailments/faults/_fault.dm b/code/modules/organs/ailments/faults/_fault.dm new file mode 100644 index 000000000000..52a9b747a84e --- /dev/null +++ b/code/modules/organs/ailments/faults/_fault.dm @@ -0,0 +1,12 @@ +/datum/ailment/fault + applies_to_robotics = TRUE + applies_to_prosthetics = TRUE + abstract_type = /datum/ailment/fault + treated_by_item_type = list( + /obj/item/stack/nanopaste, + /obj/item/stack/tape_roll/duct_tape + ) + treated_by_item_cost = 3 + third_person_treatment_message = "$USER$ patches $TARGET$'s faulty $ORGAN$ with $ITEM$." + self_treatment_message = "$USER$ patches $USER_THEIR$ faulty $ORGAN$ with $ITEM$." + initial_ailment_message = "Damage to your $ORGAN$ has caused a fault..." diff --git a/code/modules/organs/ailments/faults/fault_acid_discharge.dm b/code/modules/organs/ailments/faults/fault_acid_discharge.dm new file mode 100644 index 000000000000..cc2281544a67 --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_acid_discharge.dm @@ -0,0 +1,9 @@ +/datum/ailment/fault/acid + name = "acidic discharge" + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ is leaking some kind of chemical." + +/datum/ailment/fault/acid/on_ailment_event() + organ.owner.custom_pain("A burning sensation spreads through your [organ.name].", 5, affecting = organ.owner) + var/datum/reagents/metabolism/bloodstr_reagents = organ.owner.get_injected_reagents() + if(bloodstr_reagents) + bloodstr_reagents.add_reagent(/decl/material/liquid/acid, rand(1, 3)) \ No newline at end of file diff --git a/code/modules/organs/ailments/faults/fault_elec_discharge.dm b/code/modules/organs/ailments/faults/fault_elec_discharge.dm new file mode 100644 index 000000000000..8e7ec5180316 --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_elec_discharge.dm @@ -0,0 +1,8 @@ +/datum/ailment/fault/elec_discharge + name = "electrical discharge" + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ gives you a static shock when you touch it!" + +/datum/ailment/fault/elec_discharge/on_ailment_event() + organ.owner.custom_pain("Shock jolts through your [organ.name], staggering you!", 50, affecting = organ.owner) + spark_at(get_turf(organ.owner)) + SET_STATUS_MAX(organ.owner, STAT_STUN, 2) diff --git a/code/modules/organs/ailments/faults/fault_itchy.dm b/code/modules/organs/ailments/faults/fault_itchy.dm new file mode 100644 index 000000000000..db9ccba4f64a --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_itchy.dm @@ -0,0 +1,5 @@ +/datum/ailment/fault/itchy + name = "itchy prosthetic" + +/datum/ailment/fault/itchy/on_ailment_event() + to_chat(organ.owner, SPAN_DANGER("Something inside your [organ.name] itches badly!")) \ No newline at end of file diff --git a/code/modules/organs/ailments/faults/fault_leaky.dm b/code/modules/organs/ailments/faults/fault_leaky.dm new file mode 100644 index 000000000000..d8659a9fb516 --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_leaky.dm @@ -0,0 +1,14 @@ +/datum/ailment/fault/leaky + name = "leaky prosthetic" + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ is leaking some kind of chemical." + var/static/list/chemicals = list( + /decl/material/liquid/enzyme, + /decl/material/liquid/frostoil, + /decl/material/liquid/nanitefluid + ) + +/datum/ailment/fault/leaky/on_ailment_event() + var/reagent = pick(chemicals) + var/datum/reagents/bloodstr_reagents = organ.owner.get_injected_reagents() + if(bloodstr_reagents) + bloodstr_reagents.add_reagent(reagent, rand(1, 3)) diff --git a/code/modules/organs/ailments/faults/fault_locking_thumbs.dm b/code/modules/organs/ailments/faults/fault_locking_thumbs.dm new file mode 100644 index 000000000000..61678c157ead --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_locking_thumbs.dm @@ -0,0 +1,25 @@ +/datum/ailment/fault/locking_thumbs + name = "self-locking thumbs" + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ makes a grinding sound when you move the joints." + applies_to_organ = list( + BP_L_ARM, + BP_L_HAND, + BP_R_ARM, + BP_R_HAND + ) + +/datum/ailment/fault/locking_thumbs/proc/resolve_tag_to_slot(organ_tag) + switch(organ_tag) + if(BP_L_ARM, BP_L_HAND) + return BP_L_HAND + if(BP_R_ARM, BP_R_HAND) + return BP_R_HAND + +/datum/ailment/fault/locking_thumbs/on_ailment_event() + var/slot = resolve_tag_to_slot(organ.organ_tag) + var/obj/item/thing = organ.owner.get_equipped_item(slot) + if(thing && organ.owner.try_unequip(thing)) + var/decl/pronouns/pronouns = organ.owner.get_pronouns() + organ.owner.visible_message( \ + "\The [organ.owner] drops what [pronouns.he] [pronouns.is] holding, [pronouns.his] [organ.name] malfunctioning!", \ + "Your [organ.name] malfunctions, causing you to drop what you were holding.") diff --git a/code/modules/organs/ailments/faults/fault_noisemaker.dm b/code/modules/organs/ailments/faults/fault_noisemaker.dm new file mode 100644 index 000000000000..c99f9e2cc379 --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_noisemaker.dm @@ -0,0 +1,7 @@ +/datum/ailment/fault/noisemaker + name = "noisemaker" + manual_diagnosis_string = "$USER_THEIR$ $ORGAN$ is emitting a low capacitor whine." + +/datum/ailment/fault/noisemaker/on_ailment_event() + organ.owner.audible_message(SPAN_DANGER("[organ.owner]'s [organ.name] emits a loud, piezoelectric screal."), hearing_distance = 7) + playsound(organ.owner, 'sound/machines/screal.ogg', 100, 1, 4, ignore_walls = FALSE, zrange = 1) diff --git a/code/modules/organs/ailments/faults/fault_overstimulation.dm b/code/modules/organs/ailments/faults/fault_overstimulation.dm new file mode 100644 index 000000000000..49244c9fe9d6 --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_overstimulation.dm @@ -0,0 +1,6 @@ +/datum/ailment/fault/overstimulation + name = "motor control overstimulation" + +/datum/ailment/fault/overstimulation/on_ailment_event() + organ.owner.emote(/decl/emote/visible/collapse) + SET_STATUS_MAX(organ.owner, STAT_STUN, rand(2, 4)) \ No newline at end of file diff --git a/code/modules/organs/ailments/faults/fault_visual_impairment.dm b/code/modules/organs/ailments/faults/fault_visual_impairment.dm new file mode 100644 index 000000000000..c7b1c8fe87ef --- /dev/null +++ b/code/modules/organs/ailments/faults/fault_visual_impairment.dm @@ -0,0 +1,15 @@ +/datum/ailment/fault/visual_impair + name = "visual impairment" + applies_to_organ = list( + BP_HEAD, + ) + +/datum/ailment/fault/visual_impair/New() + ..() + if(organ?.owner) + organ.owner.add_client_color(/datum/client_color/achromatopsia) + +/datum/ailment/fault/visual_impair/Destroy(force) + if(organ?.owner) + organ.owner.remove_client_color(/datum/client_color/achromatopsia) + . = ..() diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm deleted file mode 100644 index 7e6ed60e6e89..000000000000 --- a/code/modules/organs/blood.dm +++ /dev/null @@ -1,319 +0,0 @@ -/**************************************************** - BLOOD SYSTEM -****************************************************/ - -/mob/living/carbon/human/var/datum/reagents/vessel // Container for blood and BLOOD ONLY. Do not transfer other chems here. - -//Initializes blood vessels -/mob/living/carbon/human/proc/make_blood() - - if(vessel) - return - - vessel = new/datum/reagents(species.blood_volume, src) - - if(!should_have_organ(BP_HEART)) //We want the var for safety but we can do without the actual blood. - return - - vessel.add_reagent(species.blood_reagent, species.blood_volume) - fixblood() - -//Resets blood data -/mob/living/carbon/human/proc/fixblood() - var/list/blooddata = list( - "donor" = weakref(src), - "species" = species.name, - "blood_DNA" = dna.unique_enzymes, - "blood_colour" = species.get_blood_colour(src), - "blood_type" = dna.b_type, - "trace_chem" = null - ) - LAZYSET(vessel.reagent_data, species.blood_reagent, blooddata) - -//Makes a blood drop, leaking amt units of blood from the mob -/mob/living/carbon/human/proc/drip(var/amt, var/tar = src, var/ddir) - if(remove_blood(amt)) - if(bloodstr.total_volume && vessel.total_volume) - var/chem_share = round(0.3 * amt * (bloodstr.total_volume/vessel.total_volume), 0.01) - bloodstr.remove_any(chem_share * bloodstr.total_volume) - blood_splatter(tar, src, (ddir && ddir>0), spray_dir = ddir) - return amt - return 0 - -#define BLOOD_SPRAY_DISTANCE 2 -/mob/living/carbon/human/proc/blood_squirt(var/amt, var/turf/sprayloc) - if(amt <= 0 || !istype(sprayloc)) - return - var/spraydir = pick(GLOB.alldirs) - amt = ceil(amt/BLOOD_SPRAY_DISTANCE) - var/bled = 0 - spawn(0) - for(var/i = 1 to BLOOD_SPRAY_DISTANCE) - var/turf/old_sprayloc = sprayloc - sprayloc = get_step(sprayloc, spraydir) - if(!istype(sprayloc) || sprayloc.density) - break - var/hit_dense_obj - var/hit_mob - for(var/thing in sprayloc) - var/atom/A = thing - if(!A.simulated) - continue - - if(isobj(A)) - if(A.density == 1) - hit_dense_obj = TRUE - break - - if(ishuman(A)) - var/mob/living/carbon/human/H = A - if(!H.lying) - H.bloody_body(src) - H.bloody_hands(src) - var/blinding = FALSE - if(ran_zone() == BP_HEAD) - blinding = TRUE - for(var/obj/item/I in list(H.head, H.glasses, H.wear_mask)) - if(I && (I.body_parts_covered & EYES)) - blinding = FALSE - break - if(blinding) - H.eye_blurry = max(H.eye_blurry, 10) - H.eye_blind = max(H.eye_blind, 5) - to_chat(H, "You are blinded by a spray of blood!") - else - to_chat(H, "You are hit by a spray of blood!") - hit_mob = TRUE - - if(hit_mob || !A.CanPass(src, sprayloc)) - break - - if(hit_dense_obj) - drip(amt, old_sprayloc, spraydir) - sprayloc = old_sprayloc - else - drip(amt, sprayloc, spraydir) - bled += amt - if(hit_mob) break - sleep(1) - return bled -#undef BLOOD_SPRAY_DISTANCE - -/mob/living/carbon/human/proc/remove_blood(var/amt) - if(!should_have_organ(BP_HEART)) //TODO: Make drips come from the reagents instead. - return 0 - if(!amt) - return 0 - - amt *= ((src.mob_size/MOB_SIZE_MEDIUM) ** 0.5) - - return vessel.remove_any(amt) - -/**************************************************** - BLOOD TRANSFERS -****************************************************/ - -//Gets blood from mob to the container, preserving all data in it. -/mob/living/carbon/proc/take_blood(obj/item/chems/container, var/amount) - container.reagents.add_reagent(species.blood_reagent, amount, get_blood_data()) - return 1 - -//For humans, blood does not appear from blue, it comes from vessels. -/mob/living/carbon/human/take_blood(obj/item/chems/container, var/amount) - - if(!should_have_organ(BP_HEART)) - reagents.trans_to_obj(container, amount) - return 1 - - if(vessel.total_volume < amount) - return null - if(vessel.has_reagent(species.blood_reagent)) - LAZYSET(vessel.reagent_data, species.blood_reagent, get_blood_data()) - vessel.trans_to_holder(container.reagents, amount) - return 1 - -//Transfers blood from container ot vessels -/mob/living/carbon/proc/inject_blood(var/amount, var/datum/reagents/donor) - var/injected_data = REAGENT_DATA(donor, species.blood_reagent) - var/chems = LAZYACCESS(injected_data, "trace_chem") - for(var/C in chems) - src.reagents.add_reagent(C, (text2num(chems[C]) / species.blood_volume) * amount)//adds trace chemicals to owner's blood - -//Transfers blood from reagents to vessel, respecting blood types compatability. -/mob/living/carbon/human/inject_blood(var/amount, var/datum/reagents/donor) - if(!should_have_organ(BP_HEART)) - reagents.add_reagent(species.blood_reagent, amount, REAGENT_DATA(donor, species.blood_reagent)) - return - var/injected_data = REAGENT_DATA(donor, species.blood_reagent) - if(blood_incompatible(LAZYACCESS(injected_data, "blood_type"), LAZYACCESS(injected_data, "species"))) - reagents.add_reagent(/decl/material/liquid/coagulated_blood, amount * 0.5) - else - vessel.add_reagent(species.blood_reagent, amount, injected_data) - ..() - -/mob/living/carbon/human/proc/blood_incompatible(blood_type, blood_species) - if(blood_species && species.name) - if(blood_species != species.name) - return 1 - - var/donor_antigen = copytext(blood_type, 1, length(blood_type)) - var/receiver_antigen = copytext(dna.b_type, 1, length(dna.b_type)) - var/donor_rh = (findtext(blood_type, "+") > 0) - var/receiver_rh = (findtext(dna.b_type, "+") > 0) - - if(donor_rh && !receiver_rh) return 1 - switch(receiver_antigen) - if("A") - if(donor_antigen != "A" && donor_antigen != "O") return 1 - if("B") - if(donor_antigen != "B" && donor_antigen != "O") return 1 - if("O") - if(donor_antigen != "O") return 1 - //AB is a universal receiver. - return 0 - -/mob/living/carbon/human/proc/regenerate_blood(var/amount) - amount *= (species.blood_volume / SPECIES_BLOOD_DEFAULT) - var/blood_volume_raw = vessel.total_volume - amount = max(0,min(amount, species.blood_volume - blood_volume_raw)) - if(amount) - vessel.add_reagent(species.blood_reagent, amount, get_blood_data()) - return amount - -/mob/living/carbon/proc/get_blood_data() - var/data = list() - data["donor"] = weakref(src) - data["blood_DNA"] = dna.unique_enzymes - data["blood_type"] = dna.b_type - data["species"] = species.name - data["has_oxy"] = species.blood_oxy - var/list/temp_chem = list() - for(var/R in reagents.reagent_volumes) - temp_chem[R] = REAGENT_VOLUME(reagents, R) - data["trace_chem"] = temp_chem - data["dose_chem"] = chem_doses.Copy() - data["blood_colour"] = species.get_blood_colour(src) - return data - -proc/blood_splatter(var/target, var/source, var/large, var/spray_dir) - - var/obj/effect/decal/cleanable/blood/splatter - var/decal_type = /obj/effect/decal/cleanable/blood/splatter - var/turf/T = get_turf(target) - - // Are we dripping or splattering? - var/list/drips = list() - // Only a certain number of drips (or one large splatter) can be on a given turf. - for(var/obj/effect/decal/cleanable/blood/drip/drop in T) - drips |= drop.drips - qdel(drop) - if(!large && drips.len < 3) - decal_type = /obj/effect/decal/cleanable/blood/drip - - // Find a blood decal or create a new one. - if(T) - var/list/existing = filter_list(T.contents, decal_type) - if(length(existing) > 3) - splatter = pick(existing) - if(!splatter) - splatter = new decal_type(T) - - var/obj/effect/decal/cleanable/blood/drip/drop = splatter - if(istype(drop) && drips && drips.len && !large) - drop.overlays |= drips - drop.drips |= drips - - // If there's no data to copy, call it quits here. - var/blood_data - if(ishuman(source)) - var/mob/living/carbon/human/donor = source - blood_data = REAGENT_DATA(donor.vessel, donor.species.blood_reagent) - else if(isatom(source)) - var/atom/donor = source - blood_data = REAGENT_DATA(donor.reagents, /decl/material/liquid/blood) - if(!islist(blood_data)) - return splatter - - // Update appearance. - if(blood_data["blood_colour"]) - splatter.basecolor = blood_data["blood_colour"] - splatter.update_icon() - if(spray_dir) - splatter.icon_state = "squirt" - splatter.set_dir(spray_dir) - - // Update blood information. - if(blood_data["blood_DNA"]) - splatter.blood_DNA = list() - if(blood_data["blood_type"]) - splatter.blood_DNA[blood_data["blood_DNA"]] = blood_data["blood_type"] - else - splatter.blood_DNA[blood_data["blood_DNA"]] = "O+" - var/datum/extension/forensic_evidence/forensics = get_or_create_extension(splatter, /datum/extension/forensic_evidence) - forensics.add_data(/datum/forensics/blood_dna, blood_data["blood_DNA"]) - - splatter.fluorescent = 0 - splatter.set_invisibility(0) - return splatter - -//Percentage of maximum blood volume. -/mob/living/carbon/human/proc/get_blood_volume() - return round((vessel.total_volume/species.blood_volume)*100) - -//Percentage of maximum blood volume, affected by the condition of circulation organs -/mob/living/carbon/human/proc/get_blood_circulation() - var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART] - var/blood_volume = get_blood_volume() - if(!heart) - return 0.25 * blood_volume - - var/recent_pump = LAZYACCESS(heart.external_pump, 1) > world.time - (20 SECONDS) - var/pulse_mod = 1 - if((status_flags & FAKEDEATH) || BP_IS_PROSTHETIC(heart)) - pulse_mod = 1 - else - switch(heart.pulse) - if(PULSE_NONE) - if(recent_pump) - pulse_mod = LAZYACCESS(heart.external_pump, 2) - else - pulse_mod *= 0.25 - if(PULSE_SLOW) - pulse_mod *= 0.9 - if(PULSE_FAST) - pulse_mod *= 1.1 - if(PULSE_2FAST, PULSE_THREADY) - pulse_mod *= 1.25 - blood_volume *= pulse_mod - - var/min_efficiency = recent_pump ? 0.5 : 0.3 - blood_volume *= max(min_efficiency, (1-(heart.damage / heart.max_damage))) - - if(!heart.open && chem_effects[CE_BLOCKAGE]) - blood_volume *= max(0, 1-chem_effects[CE_BLOCKAGE]) - - return min(blood_volume, 100) - -//Whether the species needs blood to carry oxygen. Used in get_blood_oxygenation and may be expanded based on blood rather than species in the future. -/mob/living/carbon/human/proc/blood_carries_oxygen() - return species.blood_oxy - -//Percentage of maximum blood volume, affected by the condition of circulation organs, affected by the oxygen loss. What ultimately matters for brain -/mob/living/carbon/human/proc/get_blood_oxygenation() - var/blood_volume = get_blood_circulation() - if(blood_carries_oxygen()) - if(is_asystole()) // Heart is missing or isn't beating and we're not breathing (hardcrit) - return min(blood_volume, BLOOD_VOLUME_SURVIVE) - - if(!need_breathe()) - return blood_volume - else - blood_volume = 100 - - var/blood_volume_mod = max(0, 1 - getOxyLoss()/(species.total_health/2)) - var/oxygenated_mult = 0 - if(chem_effects[CE_OXYGENATED]) - oxygenated_mult = 0.5 - blood_volume_mod = blood_volume_mod + oxygenated_mult - (blood_volume_mod * oxygenated_mult) - blood_volume = blood_volume * blood_volume_mod - return min(blood_volume, 100) diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm index e1d45840a2fa..be2996656b75 100644 --- a/code/modules/organs/external/_external.dm +++ b/code/modules/organs/external/_external.dm @@ -7,10 +7,11 @@ min_broken_damage = 30 dir = SOUTH organ_tag = "limb" - appearance_flags = PIXEL_SCALE - - var/slowdown = 0 + appearance_flags = DEFAULT_APPEARANCE_FLAGS | LONG_GLIDE + scale_max_damage_to_species_health = TRUE + abstract_type = /obj/item/organ/external + var/tmp/_icon_cache_key // Strings var/broken_description // fracture string if any. var/damage_state = "00" // Modifier used for generating the on-mob damage overlay for this limb. @@ -25,22 +26,19 @@ var/pain_disability_threshold // Point at which a limb becomes unusable due to pain. // A bitfield for a collection of limb behavior flags. - var/limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_BREAK + var/limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE // Appearance vars. - var/icon_name = null // Icon state base. var/body_part = null // Part flag var/icon_position = 0 // Used in mob overlay layering calculations. - var/model // Used when caching robolimb icons. - var/force_icon // Used to force override of species-specific limb icons (for prosthetics). - var/icon/mob_icon // Cached icon for use in mob overlays. var/skin_tone // Skin tone. - var/skin_base = "" // Skin base. var/skin_colour // skin colour var/skin_blend = ICON_ADD // How the skin colour is applied. - var/hair_colour // hair colour - var/body_hair // Icon blend for body hair if any. - var/list/markings = list() // Markings (body_markings) to apply to the icon + var/render_alpha = 255 // Alpha value to use for rendering the icon (slime transparency) + var/skip_body_icon_draw = FALSE // Set to true to skip including this organ on the human body sprite. + + /// Sprite accessories like hair and markings to apply to the organ icon and owner. + VAR_PRIVATE/list/_sprite_accessories // Wound and structural data. var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often @@ -48,23 +46,21 @@ var/number_wounds = 0 // number of wounds, which is NOT wounds.len! var/obj/item/organ/external/parent // Master-limb. var/list/children // Sub-limbs. - var/list/internal_organs = list() // Internal organs of this body part - var/list/implants = list() // Currently implanted objects. - var/base_miss_chance = 20 // Chance of missing. + var/list/internal_organs // Internal organs of this body part + var/list/implants // Currently implanted objects. var/genetic_degradation = 0 // Amount of current genetic damage. //Forensics stuff - var/list/autopsy_data = list() // Trauma data for forensics. + var/list/autopsy_data // Trauma data for forensics. // Joint/state stuff. var/joint = "joint" // Descriptive string used in dislocation. var/amputation_point // Descriptive string used in amputation. - var/dislocated = 0 // If you target a joint, you can dislocate the limb, causing temporary damage to the organ. var/encased // Needs to be opened with a saw to access the organs. var/artery_name = "artery" // Flavour text for cartoid artery, aorta, etc. var/arterial_bleed_severity = 1 // Multiplier for bleeding in a limb. var/tendon_name = "tendon" // Flavour text for Achilles tendon, etc. - var/cavity_name = "cavity" + var/cavity_name = "intramuscular cavity" // Surgery vars. var/cavity_max_w_class = ITEM_SIZE_TINY //this is increased if bigger organs spawn by default inside @@ -72,88 +68,113 @@ var/stage = 0 var/cavity = 0 - var/list/unarmed_attacks - var/atom/movable/applied_pressure var/atom/movable/splinted + var/internal_organs_size = 0 // Currently size cost of internal organs in this body part + // HUD element variable, see organ_icon.dm get_damage_hud_image() var/image/hud_damage_image + var/fingerprint + + // Extremely specific bool for washing hands to avoid drakes washing their entire head in the sink. + // The problem with adding shit like this is that now the question of whether or not feet/face should + // be washable comes up! There is no escape from the horrors of a detailed sim. + var/is_washable = FALSE + +/obj/item/organ/external/proc/set_fingerprint(value) + if((limb_flags & ORGAN_FLAG_FINGERPRINT) && !BP_IS_PROSTHETIC(src)) + fingerprint = value + else + for(var/obj/item/organ/external/child in children) + child.set_fingerprint(value) /obj/item/organ/external/proc/get_fingerprint() - if((limb_flags & ORGAN_FLAG_FINGERPRINT) && dna && !is_stump() && !BP_IS_PROSTHETIC(src)) - return md5(dna.uni_identity) + if((limb_flags & ORGAN_FLAG_FINGERPRINT) && !BP_IS_PROSTHETIC(src)) + if(!owner) // We need to generate a fingerprint as we've never been supplied one before. + fingerprint = md5(sequential_id(/mob)) + return fingerprint - for(var/obj/item/organ/external/E in children) - var/print = E.get_fingerprint() + for(var/obj/item/organ/external/child in children) + var/print = child.get_fingerprint() if(print) return print -/obj/item/organ/external/afterattack(atom/A, mob/user, proximity) +/obj/item/organ/external/afterattack(atom/target, mob/user, proximity) ..() if(proximity && get_fingerprint()) var/datum/extension/forensic_evidence/forensics = get_or_create_extension(src, /datum/extension/forensic_evidence) - var/datum/fingerprint/F = new() - F.full_print = get_fingerprint() - F.completeness = rand(10,90) - forensics.add_data(/datum/forensics/fingerprints, F) + var/datum/fingerprint/fingerprint = new() + fingerprint.full_print = get_fingerprint() + fingerprint.completeness = rand(10,90) + forensics.add_data(/datum/forensics/fingerprints, fingerprint) -/obj/item/organ/external/Initialize() +/obj/item/organ/external/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance) . = ..() - if(isnull(pain_disability_threshold)) + if(. != INITIALIZE_HINT_QDEL && isnull(pain_disability_threshold)) pain_disability_threshold = (max_damage * 0.75) - if(owner) - replaced(owner) - sync_colour_to_human(owner) - get_icon() - slowdown = species.get_slowdown(owner) - if(species) - for(var/attack_type in species.unarmed_attacks) - var/decl/natural_attack/attack = decls_repository.get_decl(attack_type) - if(istype(attack) && (organ_tag in attack.usable_with_limbs)) - LAZYADD(unarmed_attacks, attack_type) + if(force_limb_dir && force_limb_dir != SOUTH) + set_dir(force_limb_dir) /obj/item/organ/external/Destroy() - - if(wounds) - for(var/datum/wound/wound in wounds) - qdel(wound) - - if(parent && parent.children) - parent.children -= src - parent = null - - if(children) - for(var/obj/item/organ/external/C in children) - qdel(C) - - if(internal_organs) - for(var/obj/item/organ/O in internal_organs) - qdel(O) - + //Update the hierarchy BEFORE clearing all the vars and refs + . = ..() + //Clear all leftover refs + splinted = null //Splints got deleted in parent proc + parent = null applied_pressure = null - if(splinted && splinted.loc == src) - qdel(splinted) - splinted = null + QDEL_NULL_LIST(wounds) + LAZYCLEARLIST(autopsy_data) + LAZYCLEARLIST(children) + LAZYCLEARLIST(internal_organs) + LAZYCLEARLIST(implants) if(owner) - if(limb_flags & ORGAN_FLAG_CAN_GRASP) owner.grasp_limbs -= src - if(limb_flags & ORGAN_FLAG_CAN_STAND) owner.stance_limbs -= src - owner.organs -= src - owner.organs_by_name[organ_tag] = null - owner.organs_by_name -= organ_tag - while(null in owner.organs) - owner.organs -= null + LAZYREMOVE(owner.bad_external_organs, src) - if(autopsy_data) autopsy_data.Cut() +/obj/item/organ/external/set_species(species_uid) + _icon_cache_key = null + . = ..() + skin_blend = bodytype.limb_blend + update_icon() + +/obj/item/organ/external/set_bodytype(decl/bodytype/new_bodytype, override_material = null, apply_to_internal_organs = TRUE) + _icon_cache_key = null + var/decl/bodytype/old_bodytype = bodytype + . = ..(new_bodytype, override_material) + if(bodytype != old_bodytype && apply_to_internal_organs) + bodytype.rebuild_internal_organs(src, override_material) + if(.) + update_icon() + +/obj/item/organ/external/copy_from_mob_snapshot(datum/mob_snapshot/supplied_appearance) + _icon_cache_key = null + skin_colour = supplied_appearance.skin_color //match skin colors + skin_tone = supplied_appearance.skin_tone + if(organ_tag in supplied_appearance?.sprite_accessories) + var/list/sprite_cats = supplied_appearance.sprite_accessories[organ_tag] + for(var/category in sprite_cats) + var/list/marklist = sprite_cats[category] + for(var/accessory in marklist) + set_sprite_accessory(accessory, null, marklist[accessory], skip_update = TRUE) + else + clear_sprite_accessories(skip_update = TRUE) + return ..() +/obj/item/organ/external/reset_status() + _icon_cache_key = null return ..() -/obj/item/organ/external/set_dna(var/datum/dna/new_dna) - ..() - skin_blend = species.limb_blend - skin_base = new_dna.skin_base +/obj/item/organ/external/proc/set_bodytype_with_children(decl/bodytype/new_bodytype, override_material = null) + set_bodytype(new_bodytype, override_material) + for(var/obj/item/organ/external/child in children) + child.set_bodytype_with_children(new_bodytype, override_material) + +/obj/item/organ/external/proc/check_pain_disarm() + if(owner && prob((pain/max_damage)*100)) + owner.grasp_damage_disarm(src) + . = TRUE /obj/item/organ/external/emp_act(severity) @@ -161,8 +182,8 @@ return if(owner && BP_IS_CRYSTAL(src)) // Crystalline robotics == piezoelectrics. - owner.Weaken(4 - severity) - owner.confused = max(owner.confused, 6 - (severity * 2)) + SET_STATUS_MAX(owner, STAT_WEAK, 4 - severity) + SET_STATUS_MAX(owner, STAT_CONFUSE, 6 - (severity * 2)) return var/burn_damage = 0 @@ -174,100 +195,183 @@ if (3) burn_damage = 7.5 - var/mult = 1 + !!(BP_IS_ASSISTED(src)) // This macro returns (large) bitflags. - burn_damage *= mult/species.get_burn_mod(owner) //ignore burn mod for EMP damage - var/power = 4 - severity //stupid reverse severity - for(var/obj/item/I in implants) - if(I.obj_flags & OBJ_FLAG_CONDUCTIBLE) - burn_damage += I.w_class * rand(power, 3*power) + for(var/obj/item/implanted_item in implants) + if(implanted_item.obj_flags & OBJ_FLAG_CONDUCTIBLE) + burn_damage += implanted_item.w_class * rand(power, 3*power) if(owner && burn_damage) owner.custom_pain("Something inside your [src] burns a [severity < 2 ? "bit" : "lot"]!", power * 15) //robotic organs won't feel it anyway - take_external_damage(0, burn_damage, 0, used_weapon = "Hot metal") + take_damage(burn_damage, BURN, inflicter = "Hot metal") + check_pain_disarm() - if(owner && limb_flags & ORGAN_FLAG_CAN_GRASP) - owner.grasp_damage_disarm(src) - - if(owner && limb_flags & ORGAN_FLAG_CAN_STAND) + if(owner && (limb_flags & ORGAN_FLAG_CAN_STAND)) owner.stance_damage_prone(src) /obj/item/organ/external/attack_self(var/mob/user) if((owner && loc == owner) || !contents.len) return ..() var/list/removable_objects = list() - for(var/obj/item/organ/external/E in (contents + src)) - if(!istype(E)) - continue - for(var/obj/item/I in E.contents) - if(istype(I,/obj/item/organ)) + for(var/obj/item/organ/external/child_organ in (contents + src)) + for(var/obj/item/embedded in child_organ.contents) + if(istype(embedded, /obj/item/organ)) continue - removable_objects |= I + removable_objects |= embedded if(removable_objects.len) - var/obj/item/I = pick(removable_objects) - I.forceMove(get_turf(user)) //just in case something was embedded that is not an item - if(istype(I)) - if(!(user.l_hand && user.r_hand)) - user.put_in_hands(I) - user.visible_message("\The [user] rips \the [I] out of \the [src]!") + var/obj/item/embedded = pick(removable_objects) + embedded.forceMove(get_turf(user)) //just in case something was embedded that is not an item + if(istype(embedded) && user.get_empty_hand_slot()) + user.put_in_hands(embedded) + user.visible_message(SPAN_DANGER("\The [user] rips \the [embedded] out of \the [src]!")) return //no eating the limb until everything's been removed return ..() -/obj/item/organ/external/examine(mob/user, distance) +/obj/item/organ/external/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1 || isghost(user)) - for(var/obj/item/I in contents) - if(istype(I, /obj/item/organ)) + for(var/obj/item/embedded in contents) + if(istype(embedded, /obj/item/organ)) continue - to_chat(user, "There is \a [I] sticking out of it.") + . += SPAN_DANGER("There is \a [embedded] sticking out of it.") var/ouchies = get_wounds_desc() if(ouchies != "nothing") - to_chat(user, "There is [ouchies] visible on it.") + . += SPAN_NOTICE("There is [ouchies] visible on it.") - return - -/obj/item/organ/external/show_decay_status(mob/user) - ..(user) +/obj/item/organ/external/get_decay_status(mob/user) + . = ..() for(var/obj/item/organ/external/child in children) - child.show_decay_status(user) - -/obj/item/organ/external/attackby(obj/item/W, mob/user) - switch(stage) - if(0) - if(W.sharp) - user.visible_message("[user] cuts [src] open with [W]!") - stage++ - return - if(1) - if(istype(W)) - user.visible_message("[user] cracks [src] open like an egg with [W]!") - stage++ - return - if(2) - if(W.sharp || istype(W,/obj/item/hemostat) || isWirecutter(W)) - var/list/organs = get_contents_recursive() - if(organs.len) - var/obj/item/removing = pick(organs) - var/obj/item/organ/external/current_child = removing.loc - - current_child.implants.Remove(removing) - current_child.internal_organs.Remove(removing) - - status |= ORGAN_CUT_AWAY - if(istype(removing, /obj/item/organ/internal/mmi_holder)) - var/obj/item/organ/internal/mmi_holder/O = removing - removing = O.transfer_and_delete() - - removing.forceMove(get_turf(user)) - - if(!(user.l_hand && user.r_hand)) - user.put_in_hands(removing) - user.visible_message("[user] extracts [removing] from [src] with [W]!") - else - user.visible_message("[user] fishes around fruitlessly in [src] with [W].") - return - ..() + var/decay_status = child.get_decay_status(user) + if(decay_status) + . += decay_status + +/obj/item/organ/external/attackby(obj/item/used_item, mob/user) + + var/obj/item/organ/external/connecting_limb = used_item + if(BP_IS_PROSTHETIC(src) && istype(connecting_limb) && BP_IS_PROSTHETIC(connecting_limb)) + + var/combined = FALSE + if(connecting_limb.organ_tag == parent_organ) + + if(length(connecting_limb.children)) + to_chat(user, SPAN_WARNING("You cannot connect additional limbs to \the [connecting_limb].")) + return TRUE + + var/mob/holder = loc + if(istype(holder)) + holder.try_unequip(src, connecting_limb) + else + dropInto(loc) + forceMove(connecting_limb) + + if(loc != connecting_limb) + return TRUE + + if(istype(connecting_limb.owner)) + connecting_limb.owner.add_organ(src, connecting_limb) + else + do_install(null, connecting_limb) + + combined = TRUE + + else if(connecting_limb.parent_organ == organ_tag) + + if(LAZYLEN(children)) + to_chat(user, SPAN_WARNING("You cannot connect additional limbs to \the [src].")) + return TRUE + + if(!user.try_unequip(connecting_limb, src)) + return TRUE + + if(istype(connecting_limb.owner)) + connecting_limb.owner.add_organ(connecting_limb, src) + else + connecting_limb.do_install(null, src) + combined = TRUE + + else + to_chat(user, SPAN_WARNING("\The [connecting_limb] cannot be connected to \the [src].")) + return TRUE + + if(combined) + to_chat(user, SPAN_NOTICE("You connect \the [connecting_limb] to \the [src].")) + compile_icon() + update_icon() + connecting_limb.compile_icon() + connecting_limb.update_icon() + return TRUE + + //Remove sub-limbs + if(used_item.get_tool_quality(TOOL_SAW) && LAZYLEN(children) && try_saw_off_child(used_item, user)) + return TRUE + //Remove internal items/organs/implants + if(try_remove_internal_item(used_item, user)) + return TRUE + return ..() + +//Handles removing internal organs/implants/items still in the detached limb. +/obj/item/organ/external/proc/try_remove_internal_item(var/obj/item/used_item, var/mob/user) + + if(stage == 0 && used_item.is_sharp()) + user.visible_message(SPAN_NOTICE("\The [user] cuts \the [src] open with \the [used_item].")) + stage++ + return TRUE + + if(stage == 1 && IS_RETRACTOR(used_item)) + user.visible_message(SPAN_NOTICE("\The [user] levers \the [src] open with \the [used_item].")) + stage++ + return TRUE + + if(stage == 2 && (used_item.is_sharp() || IS_HEMOSTAT(used_item) || IS_WIRECUTTER(used_item))) + var/list/radial_buttons = make_item_radial_menu_choices(get_contents_recursive()) + if(LAZYLEN(radial_buttons)) + var/obj/item/removing = show_radial_menu(user, src, radial_buttons, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(src)) + if(removing) + if(istype(removing, /obj/item/organ)) + var/obj/item/organ/removed_organ = removing + removed_organ.do_uninstall() + removing.forceMove(get_turf(user)) + + if(user.get_empty_hand_slot()) + user.put_in_hands(removing) + user.visible_message(SPAN_NOTICE("\The [user] extracts [removing] from \the [src] with \the [used_item]!")) + else + user.visible_message(SPAN_NOTICE("\The [user] fishes around fruitlessly in \the [src] with \the [used_item].")) + return TRUE + + return FALSE + +//Handles removing child limbs from the detached limb. +/obj/item/organ/external/proc/try_saw_off_child(var/obj/item/used_item, var/mob/user) + + //Add icons to radial menu + var/list/radial_buttons = make_item_radial_menu_choices(get_limbs_recursive()) + if(!LAZYLEN(radial_buttons)) + return + + //Display radial menu + var/obj/item/organ/external/removing = show_radial_menu(user, src, radial_buttons, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(src)) + if(!istype(removing)) + return TRUE + + var/cutting_result = !used_item.do_tool_interaction(TOOL_SAW, user, src, 3 SECONDS, "cutting \the [removing] off") + //Check if the limb is still in the hierarchy + if(cutting_result == 1 || !(removing in get_limbs_recursive())) + if(cutting_result != -1) + user.visible_message(SPAN_DANGER("[user] stops trying to cut \the [removing].")) + return TRUE + + //Actually remove it + removing.do_uninstall() + removing.forceMove(get_turf(user)) + compile_icon() + update_icon() + removing.compile_icon() + removing.update_icon() + if(user.get_empty_hand_slot()) + user.put_in_hands(removing) + user.visible_message(SPAN_DANGER("[user] cuts off \the [removing] from [src] with [used_item]!")) + return TRUE /** * Get a list of contents of this organ and all the child organs @@ -275,98 +379,174 @@ /obj/item/organ/external/proc/get_contents_recursive() var/list/all_items = list() - all_items.Add(implants) - all_items.Add(internal_organs) + if(LAZYLEN(implants)) + all_items.Add(implants) + if(LAZYLEN(internal_organs)) + all_items.Add(internal_organs) for(var/obj/item/organ/external/child in children) all_items.Add(child.get_contents_recursive()) return all_items +/obj/item/organ/external/proc/get_limbs_recursive() + var/list/all_limbs = list() + for(var/obj/item/organ/external/child in children) + all_limbs += child + var/list/sublimbs = child.get_limbs_recursive() + if(sublimbs) + all_limbs += sublimbs + return all_limbs + /obj/item/organ/external/proc/is_dislocated() - if(dislocated > 0) - return 1 - if(is_parent_dislocated()) - return 1//if any parent is dislocated, we are considered dislocated as well - return 0 + return (status & ORGAN_DISLOCATED) || is_parent_dislocated() //if any parent is dislocated, we are considered dislocated as well /obj/item/organ/external/proc/is_parent_dislocated() - var/obj/item/organ/external/O = parent - while(O && O.dislocated != -1) - if(O.dislocated == 1) - return 1 - O = O.parent - return 0 + var/obj/item/organ/external/current_limb = parent + while(current_limb && (current_limb.limb_flags & ORGAN_FLAG_CAN_DISLOCATE)) + if(current_limb.status & ORGAN_DISLOCATED) + return TRUE + current_limb = current_limb.parent + return FALSE +/obj/item/organ/external/proc/update_internal_organs_cost() + internal_organs_size = 0 + for(var/obj/item/organ/internal/org in internal_organs) + internal_organs_size += org.get_storage_cost() /obj/item/organ/external/proc/dislocate() - if(dislocated == -1) + if(owner && (owner.status_flags & GODMODE)) + return + if(!(limb_flags & ORGAN_FLAG_CAN_DISLOCATE)) return - dislocated = 1 + status |= ORGAN_DISLOCATED if(owner) - owner.verbs |= /mob/living/carbon/human/proc/undislocate + if(can_feel_pain()) + add_pain(20) + owner.apply_effect(5, STUN) + owner.verbs |= /mob/living/human/proc/undislocate -/obj/item/organ/external/proc/undislocate() - if(dislocated == -1) +/obj/item/organ/external/proc/undislocate(var/skip_pain = FALSE) + if(!(limb_flags & ORGAN_FLAG_CAN_DISLOCATE)) return - dislocated = 0 + status &= (~ORGAN_DISLOCATED) if(owner) - owner.shock_stage += 20 + if(!skip_pain && can_feel_pain()) + add_pain(20) + owner.apply_effect(2, STUN) //check to see if we still need the verb - for(var/obj/item/organ/external/limb in owner.organs) - if(limb.dislocated == 1) + for(var/obj/item/organ/external/limb in owner.get_external_organs()) + if(limb.is_dislocated()) return - owner.verbs -= /mob/living/carbon/human/proc/undislocate - -/obj/item/organ/external/update_health() - damage = min(max_damage, (brute_dam + burn_dam)) - return + owner.verbs -= /mob/living/human/proc/undislocate +//If "in_place" is TRUE will make organs skip their install/uninstall effects and the sub-limbs and internal organs +/obj/item/organ/external/do_install(mob/living/human/target, obj/item/organ/external/affected, in_place, update_icon, detached) + if(!(. = ..())) + return -/obj/item/organ/external/replaced(var/mob/living/carbon/human/target) - ..() - + //If attached to an owner mob if(istype(owner)) - if(limb_flags & ORGAN_FLAG_CAN_GRASP) owner.grasp_limbs[src] = TRUE - if(limb_flags & ORGAN_FLAG_CAN_STAND) owner.stance_limbs[src] = TRUE - owner.organs_by_name[organ_tag] = src - owner.organs |= src + owner.full_prosthetic = null - for(var/obj/item/organ/organ in internal_organs) - organ.replaced(owner, src) + // Initialize fingerprints if we don't already have some (TODO: we're assuming this is our first owner, maybe check for this elsewhere?). + if((limb_flags & ORGAN_FLAG_FINGERPRINT) && !fingerprint && !BP_IS_PROSTHETIC(src)) + fingerprint = owner.get_full_print(ignore_blockers = TRUE) + //If we expect a parent organ set it up here + if(!affected && parent_organ) + parent = GET_EXTERNAL_ORGAN(owner, parent_organ) + else + parent = affected + + // + //If we contain any child organs add them to the owner + // + for(var/obj/item/organ/organ in (implants|children|internal_organs)) + owner.add_organ(organ, src, in_place, update_icon, FALSE) + + // + //Add any existing organs in the owner that have us as parent + // + for(var/obj/item/organ/internal/internal_organ in owner.get_internal_organs()) + if(internal_organ.parent_organ == organ_tag) + LAZYDISTINCTADD(internal_organs, internal_organ) + update_internal_organs_cost() + + for(var/obj/item/organ/external/external_organ in owner.get_external_organs()) + if(external_organ.parent_organ == organ_tag) + external_organ.parent = src + LAZYDISTINCTADD(children, external_organ) + + //Add any existing implants that should be refering us for(var/obj/implant in implants) implant.forceMove(owner) - if(istype(implant, /obj/item/implant)) var/obj/item/implant/imp_device = implant - // we can't use implanted() here since it's often interactive imp_device.imp_in = owner - imp_device.implanted = 1 - + imp_device.implanted = TRUE + + //Since limbs attached during surgery have their internal organs detached, we want to re-attach them if we're doing the proper install of the parent limb + else if(istype(implant, /obj/item/organ) && !detached) + var/obj/item/organ/detached_organ = implant + if(detached_organ.parent_organ == organ_tag) + //The add_organ chain will automatically handle properly removing the detached flag, and moving it to the proper lists + owner.add_organ(detached_organ, src, in_place, update_icon, detached) + else + //Handle installing into a stand-alone parent limb to keep dropped limbs in some kind of coherent state + if(!affected) + affected = loc + if(istype(affected)) + if(parent_organ != affected.organ_tag) + log_warning("obj/item/organ/external/do_install(): The parent organ in the parameters '[affected]'('[affected.organ_tag]') doesn't match the expected parent organ ('[parent_organ]') for '[src]'!") + parent = affected + + //When no owner, make sure we update all our children. Everything else should be implicitely at the right place for(var/obj/item/organ/external/organ in children) - organ.replaced(owner) - - if(!parent && parent_organ) - parent = owner.organs_by_name[src.parent_organ] - if(parent) - if(!parent.children) - parent.children = list() - parent.children.Add(src) - //Remove all stump wounds since limb is not missing anymore - for(var/datum/wound/lost_limb/W in parent.wounds) - qdel(W) + organ.do_install(null, src, in_place, update_icon, detached) + + //This proc refers to owner's species and all kind of risky stuff, so it cannot be done in_place + if(!in_place) + update_wounds() + + //Parent hieracrchy handling + if(parent) + //Add ourselves to our parent organ's data + LAZYDISTINCTADD(parent.children, src) //Even when detached the limb has to be in the children list, because of the way limbs icon are handled + + //Remove any stump wound for this slot + for(var/datum/wound/lost_limb/stump in parent.wounds) + if(stump.limb_tag == organ_tag) + qdel(stump) //Removes itself from parent.wounds break - parent.update_damages() + + if(!in_place) + parent.update_wounds() + +/// Drops all clothing covered by this body part. +/obj/item/organ/external/proc/drop_equipped_clothing() + if(!owner) + return + // TODO: Determine if this is even necessary; slots that require organ tags will vanish when the organ is lost + if((body_part & SLOT_FOOT_LEFT) || (body_part & SLOT_FOOT_RIGHT)) + owner.drop_from_slot(slot_shoes_str) + if((body_part & SLOT_HAND_LEFT) || (body_part & SLOT_HAND_RIGHT)) + owner.drop_from_slot(slot_gloves_str) + if(body_part & SLOT_HEAD) + owner.drop_from_slot(slot_head_str) + owner.drop_from_slot(slot_glasses_str) + owner.drop_from_slot(slot_l_ear_str) + owner.drop_from_slot(slot_r_ear_str) + owner.drop_from_slot(slot_wear_mask_str) //Helper proc used by various tools for repairing robot limbs /obj/item/organ/external/proc/robo_repair(var/repair_amount, var/damage_type, var/damage_desc, obj/item/tool, mob/living/user) - if((!BP_IS_PROSTHETIC(src))) + if(!BP_IS_PROSTHETIC(src)) return 0 var/damage_amount @@ -377,105 +557,100 @@ if(!damage_amount) if(src.hatch_state != HATCH_OPENED) - to_chat(user, "Nothing to fix!") + to_chat(user, SPAN_NOTICE("Nothing to fix!")) return 0 if(damage_amount >= ROBOLIMB_SELF_REPAIR_CAP) - to_chat(user, "The damage is far too severe to patch over externally.") + to_chat(user, SPAN_WARNING("The damage is far too severe to patch over externally.")) return 0 if(user == src.owner) var/grasp - if(user.l_hand == tool && (src.body_part & (ARM_LEFT|HAND_LEFT))) + if(user.get_equipped_item(BP_L_HAND) == tool && (src.body_part & (SLOT_ARM_LEFT|SLOT_HAND_LEFT))) grasp = BP_L_HAND - else if(user.r_hand == tool && (src.body_part & (ARM_RIGHT|HAND_RIGHT))) + else if(user.get_equipped_item(BP_R_HAND) == tool && (src.body_part & (SLOT_ARM_RIGHT|SLOT_HAND_RIGHT))) grasp = BP_R_HAND if(grasp) - to_chat(user, "You can't reach your [src.name] while holding [tool] in your [owner.get_bodypart_name(grasp)].") + to_chat(user, SPAN_WARNING("You can't reach your [src.name] while holding [tool] in your [owner.get_bodypart_name(grasp)].")) return 0 user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!do_mob(user, owner, 10)) - to_chat(user, "You must stand still to do that.") + to_chat(user, SPAN_WARNING("You must stand still to do that.")) return 0 switch(damage_type) if(BRUTE) src.heal_damage(repair_amount, 0, 0, 1) if(BURN) src.heal_damage(0, repair_amount, 0, 1) - owner.regenerate_icons() + owner.try_refresh_visible_overlays() if(user == src.owner) - user.visible_message("\The [user] patches [damage_desc] on \his [src.name] with [tool].") + var/decl/pronouns/user_pronouns = user.get_pronouns() + user.visible_message(SPAN_NOTICE("\The [user] patches [damage_desc] on [user_pronouns.his] [name] with \the [tool].")) else - user.visible_message("\The [user] patches [damage_desc] on [owner]'s [src.name] with [tool].") - + user.visible_message(SPAN_NOTICE("\The [user] patches [damage_desc] on \the [owner]'s [name] with \the [tool].")) return 1 - /* This function completely restores a damaged organ to perfect condition. */ -/obj/item/organ/external/rejuvenate(var/ignore_prosthetic_prefs) - damage_state = "00" +/obj/item/organ/external/rejuvenate(var/ignore_organ_traits) - status = 0 + damage_state = "00" brute_dam = 0 + brute_ratio = 0 burn_dam = 0 + burn_ratio = 0 germ_level = 0 - pain = 0 genetic_degradation = 0 + pain = 0 + for(var/datum/wound/wound in wounds) qdel(wound) number_wounds = 0 // handle internal organs for(var/obj/item/organ/current_organ in internal_organs) - current_organ.rejuvenate(ignore_prosthetic_prefs) + current_organ.rejuvenate(ignore_organ_traits) // remove embedded objects and drop them on the floor for(var/obj/implanted_object in implants) if(!istype(implanted_object,/obj/item/implant)) // We don't want to remove REAL implants. Just shrapnel etc. implanted_object.forceMove(get_turf(src)) - implants -= implanted_object - - if(owner && !ignore_prosthetic_prefs) - if(owner.client && owner.client.prefs && owner.client.prefs.real_name == owner.real_name) - var/status = owner.client.prefs.organ_data[organ_tag] - if(status == "amputated") - remove_rejuv() - else if(status == "cyborg") - var/robodata = owner.client.prefs.rlimb_data[organ_tag] - if(robodata) - robotize(robodata) - else - robotize() - owner.updatehealth() - - if(!QDELETED(src) && species) - species.post_organ_rejuvenate(src, owner) + LAZYREMOVE(implants, implanted_object) + + undislocate(TRUE) + + . = ..() // Clear damage, reapply traits. + + if(owner) + owner.update_health() +//#TODO: Rejuvination hacks should probably be removed /obj/item/organ/external/remove_rejuv() if(owner) - owner.organs -= src - owner.organs_by_name[organ_tag] = null - owner.organs_by_name -= organ_tag - while(null in owner.organs) owner.organs -= null - if(LAZYLEN(children)) - for(var/obj/item/organ/external/E in children) - E.remove_rejuv() - children.Cut() - for(var/obj/item/organ/internal/I in internal_organs) - I.remove_rejuv() + owner.remove_organ(src, FALSE, FALSE, TRUE, TRUE, FALSE) + for(var/obj/item/organ/external/child in children) + child.remove_rejuv() + LAZYCLEARLIST(children) + for(var/obj/item/organ/internal/internal_organ in internal_organs) + internal_organ.remove_rejuv() ..() /obj/item/organ/external/proc/createwound(var/type = CUT, var/damage, var/surgical) - if(damage <= 0) + if(!owner || damage <= 0) return - if(BP_IS_CRYSTAL(src) && (damage >= 15 || prob(1))) + if(BP_IS_CRYSTAL(src)) type = SHATTER - playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 40, 1) // Crash! + if(damage >= 15 || prob(1)) + playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 40, 1) // Crash! + else if((limb_flags & ORGAN_FLAG_SKELETAL) || (BP_IS_PROSTHETIC(src) && !bodytype.is_robotic)) + if(type == BURN) + type = CHARRED + else + type = SHATTER //moved these before the open_wound check so that having many small wounds for example doesn't somehow protect you from taking internal damage (because of the return) //Brute damage can possibly trigger an internal wound, too. @@ -496,7 +671,7 @@ This function completely restores a damaged organ to perfect condition. switch(type) if(BURN) fluid_loss_severity = FLUIDLOSS_WIDE_BURN if(LASER) fluid_loss_severity = FLUIDLOSS_CONC_BURN - var/fluid_loss = (damage/(owner.maxHealth - config.health_threshold_dead)) * SPECIES_BLOOD_DEFAULT * fluid_loss_severity + var/fluid_loss = (damage/(owner.get_max_health() - get_config_value(/decl/config/num/health_health_threshold_dead))) * SPECIES_BLOOD_DEFAULT * fluid_loss_severity owner.remove_blood(fluid_loss) // first check whether we can widen an existing wound @@ -504,44 +679,44 @@ This function completely restores a damaged organ to perfect condition. if((type == CUT || type == BRUISE) && damage >= 5) //we need to make sure that the wound we are going to worsen is compatible with the type of damage... var/list/compatible_wounds = list() - for (var/datum/wound/W in wounds) - if (W.can_worsen(type, damage)) - compatible_wounds += W + for (var/datum/wound/wound in wounds) + if (wound.can_worsen(type, damage)) + compatible_wounds += wound if(compatible_wounds.len) - var/datum/wound/W = pick(compatible_wounds) - W.open_wound(damage) - if(prob(25)) + var/datum/wound/wound = pick(compatible_wounds) + wound.open_wound(damage) + if(owner && prob(25)) if(BP_IS_CRYSTAL(src)) - owner.visible_message("The cracks in \the [owner]'s [name] spread.",\ - "The cracks in your [name] spread.",\ - "You hear the cracking of crystal.") + owner.visible_message(SPAN_DANGER("The cracks in \the [owner]'s [name] spread."),\ + SPAN_DANGER("The cracks in your [name] spread."),\ + SPAN_DANGER("You hear the cracking of crystal.")) else if(BP_IS_PROSTHETIC(src)) - owner.visible_message("The damage to \the [owner]'s [name] worsens.",\ - "The damage to your [name] worsens.",\ - "You hear the screech of abused metal.") + owner.visible_message(SPAN_DANGER("The damage to \the [owner]'s [name] worsens."),\ + SPAN_DANGER("The damage to your [name] worsens."),\ + SPAN_DANGER("You hear the screech of abused metal.")) else - owner.visible_message("The wound on \the [owner]'s [name] widens with a nasty ripping noise.",\ - "The wound on your [name] widens with a nasty ripping noise.",\ - "You hear a nasty ripping noise, as if flesh is being torn apart.") - return W + owner.visible_message(SPAN_DANGER("The wound on \the [owner]'s [name] widens with a nasty ripping noise."),\ + SPAN_DANGER("The wound on your [name] widens with a nasty ripping noise."),\ + SPAN_DANGER("You hear a nasty ripping noise, as if flesh is being torn apart.")) + return wound //Creating wound var/wound_type = get_wound_type(type, damage) if(wound_type) - var/datum/wound/W = new wound_type(damage, src) + var/datum/wound/wound = new wound_type(damage, src, surgical) //Check whether we can add the wound to an existing wound if(surgical) - W.autoheal_cutoff = 0 + wound.autoheal_cutoff = 0 else for(var/datum/wound/other in wounds) - if(other.can_merge(W)) - other.merge_wound(W) - return - LAZYADD(wounds, W) - return W + if(other.can_merge_wounds(wound)) + other.merge_wound(wound) + return other + LAZYADD(wounds, wound) + return wound /**************************************************** PROCESSING & UPDATING @@ -551,40 +726,56 @@ This function completely restores a damaged organ to perfect condition. /obj/item/organ/external/is_broken() return ((status & ORGAN_CUT_AWAY) || ((status & ORGAN_BROKEN) && !splinted)) +// Overridable for modpacks. +/obj/item/organ/external/proc/check_status_flags_for_process() + return (status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_MUTATED|ORGAN_DISLOCATED|ORGAN_DEAD)) + //Determines if we even need to process this organ. /obj/item/organ/external/proc/need_process() - if(get_pain()) - return 1 - if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DEAD|ORGAN_MUTATED)) - return 1 + + if(length(ailments)) + return TRUE + + if(check_status_flags_for_process()) + return TRUE + if((brute_dam || burn_dam) && !BP_IS_PROSTHETIC(src)) //Robot limbs don't autoheal and thus don't need to process when damaged - return 1 + return TRUE + + if(get_genetic_damage()) + return TRUE + + for(var/obj/item/organ/internal/internal_organ in internal_organs) + if(internal_organ.getToxLoss()) + return TRUE + if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up. last_dam = brute_dam + burn_dam - return 1 - else - last_dam = brute_dam + burn_dam + return TRUE + + last_dam = brute_dam + burn_dam if(germ_level) return 1 return 0 /obj/item/organ/external/Process() if(owner) - if(pain) - pain -= owner.lying ? 3 : 1 + pain -= owner.current_posture.prone ? 3 : 1 if(pain<0) pain = 0 - // Process wounds, doing healing etc. Only do this every few ticks to save processing power if(owner.life_tick % wound_update_accuracy == 0) update_wounds() - //Infections update_germs() else pain = 0 - ..() + ..() + + //check if we've hit max_damage + if((brute_dam + burn_dam) >= max_damage) + die() //Updating germ levels. Handles organ germ levels and necrosis. /* @@ -622,17 +813,18 @@ Note that amputating the affected organ does in fact remove the infection from t handle_germ_effects() /obj/item/organ/external/proc/handle_germ_sync() - var/turf/simulated/T = get_turf(owner) - for(var/datum/wound/W in wounds) + var/turf/current_turf = get_turf(owner) + for(var/datum/wound/wound in wounds) //Open wounds can become infected - if(max(istype(T) && T.dirt*10, 2*owner.germ_level) > W.germ_level && W.infection_check()) - W.germ_level++ + // what in the hell is this doing with current_turf? + if(max(istype(current_turf) && current_turf.simulated && current_turf.get_dirt()*10, 2*owner.germ_level) > wound.germ_level && wound.infection_check()) + wound.germ_level++ - var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] + var/antibiotics = GET_CHEMICAL_EFFECT(owner, CE_ANTIBIOTIC) if (!antibiotics) - for(var/datum/wound/W in wounds) + for(var/datum/wound/wound in wounds) //Infected wounds raise the organ's germ level - if (W.germ_level > germ_level || prob(min(W.germ_level, 30))) + if (wound.germ_level > germ_level || prob(min(wound.germ_level, 30))) germ_level++ break //limit increase to a maximum of one per second @@ -646,17 +838,17 @@ Note that amputating the affected organ does in fact remove the infection from t if(germ_level >= INFECTION_LEVEL_TWO) //spread the infection to internal organs var/obj/item/organ/target_organ = null //make internal organs become infected one at a time instead of all at once - for (var/obj/item/organ/I in internal_organs) - if (I.germ_level > 0 && I.germ_level < min(germ_level, INFECTION_LEVEL_TWO)) //once the organ reaches whatever we can give it, or level two, switch to a different one - if (!target_organ || I.germ_level > target_organ.germ_level) //choose the organ with the highest germ_level - target_organ = I + for (var/obj/item/organ/internal_organ in internal_organs) + if (internal_organ.germ_level > 0 && internal_organ.germ_level < min(germ_level, INFECTION_LEVEL_TWO)) //once the organ reaches whatever we can give it, or level two, switch to a different one + if (!target_organ || internal_organ.germ_level > target_organ.germ_level) //choose the organ with the highest germ_level + target_organ = internal_organ if (!target_organ) //figure out which organs we can spread germs to and pick one at random var/list/candidate_organs = list() - for (var/obj/item/organ/I in internal_organs) - if (I.germ_level < germ_level) - candidate_organs |= I + for (var/obj/item/organ/internal_organ in internal_organs) + if (internal_organ.germ_level < germ_level) + candidate_organs |= internal_organ if (candidate_organs.len) target_organ = pick(candidate_organs) @@ -664,11 +856,10 @@ Note that amputating the affected organ does in fact remove the infection from t target_organ.germ_level++ //spread the infection to child and parent organs - if (children) - for (var/obj/item/organ/external/child in children) - if (child.germ_level < germ_level && !BP_IS_PROSTHETIC(child)) - if (child.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) - child.germ_level++ + for(var/obj/item/organ/external/child in children) + if (child.germ_level < germ_level && !BP_IS_PROSTHETIC(child)) + if (child.germ_level < INFECTION_LEVEL_ONE*2 || prob(30)) + child.germ_level++ if (parent) if (parent.germ_level < germ_level && !BP_IS_PROSTHETIC(parent)) @@ -678,29 +869,29 @@ Note that amputating the affected organ does in fact remove the infection from t if(germ_level >= INFECTION_LEVEL_THREE && antibiotics < REAGENTS_OVERDOSE) //overdosing is necessary to stop severe infections if (!(status & ORGAN_DEAD)) status |= ORGAN_DEAD - to_chat(owner, "You can't feel your [name] anymore...") + to_chat(owner, SPAN_NOTICE("You can't feel your [name] anymore...")) owner.update_body(1) germ_level++ - owner.adjustToxLoss(1) + owner.take_damage(1, TOX) //Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections /obj/item/organ/external/proc/update_wounds() var/update_surgery if(BP_IS_PROSTHETIC(src) || BP_IS_CRYSTAL(src)) //Robotic limbs don't heal or get worse. - for(var/datum/wound/W in wounds) //Repaired wounds disappear though - if(W.damage <= 0) //and they disappear right away - qdel(W) //TODO: robot wounds for robot limbs + for(var/datum/wound/wound in wounds) //Repaired wounds disappear though + if(wound.damage <= 0) //and they disappear right away + qdel(wound) //TODO: robot wounds for robot limbs update_surgery = TRUE if(owner && update_surgery) owner.update_surgery() return - for(var/datum/wound/W in wounds) + for(var/datum/wound/wound in wounds) // wounds can disappear after 10 minutes at the earliest - if(W.damage <= 0 && W.created + (10 MINUTES) <= world.time) - qdel(W) + if(wound.damage <= 0 && wound.created + (10 MINUTES) <= world.time) + qdel(wound) update_surgery = TRUE continue // let the GC handle the deletion of the wound @@ -708,22 +899,27 @@ Note that amputating the affected organ does in fact remove the infection from t // slow healing var/heal_amt = 0 // if damage >= 50 AFTER treatment then it's probably too severe to heal within the timeframe of a round. - if (!owner.chem_effects[CE_TOXIN] && W.can_autoheal() && W.wound_damage() && brute_ratio < 0.5 && burn_ratio < 0.5) + if (owner && !GET_CHEMICAL_EFFECT(owner, CE_TOXIN) && wound.can_autoheal() && wound.wound_damage() && brute_ratio < 0.5 && burn_ratio < 0.5) heal_amt += 0.5 - //we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime + // we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime heal_amt = heal_amt * wound_update_accuracy - //configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny - heal_amt = heal_amt * config.organ_regeneration_multiplier + // configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny + heal_amt = heal_amt * get_config_value(/decl/config/num/health_organ_regeneration_multiplier) + // Apply a modifier based on how stressed we currently are. + if(owner) + var/stress_modifier = owner.get_stress_modifier() + if(stress_modifier) + heal_amt *= 1-(get_config_value(/decl/config/num/health_stress_healing_recovery_constant) * stress_modifier) // amount of healing is spread over all the wounds heal_amt = heal_amt / (LAZYLEN(wounds) + 1) // making it look prettier on scanners heal_amt = round(heal_amt,0.1) var/dam_type = BRUTE - if(W.damage_type == BURN) + if(wound.damage_type == BURN) dam_type = BURN - if(owner.can_autoheal(dam_type)) - W.heal_damage(heal_amt) + if(owner?.can_autoheal(dam_type)) + wound.heal_damage(heal_amt) // sync the organ's damage with its wounds update_damages() @@ -731,7 +927,7 @@ Note that amputating the affected organ does in fact remove the infection from t if(update_surgery) owner.update_surgery() if (update_damstate()) - owner.UpdateDamageIcon(1) + owner.update_damage_overlays(TRUE) //Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status. /obj/item/organ/external/proc/update_damages() @@ -741,31 +937,31 @@ Note that amputating the affected organ does in fact remove the infection from t status &= ~ORGAN_BLEEDING var/clamped = 0 - var/mob/living/carbon/human/H - if(istype(owner,/mob/living/carbon/human)) - H = owner + // This is defined outside of the loop as an optimization for a large number of wounds. + var/mob/living/human/human_owner + if(ishuman(owner)) + human_owner = owner //update damage counts var/bleeds = (!BP_IS_PROSTHETIC(src) && !BP_IS_CRYSTAL(src)) - for(var/datum/wound/W in wounds) + for(var/datum/wound/wound in wounds) - if(W.damage <= 0) - qdel(W) + if(wound.damage <= 0) + qdel(wound) continue - if(W.damage_type == BURN) - burn_dam += W.damage + if(wound.damage_type == BURN) + burn_dam += wound.damage else - brute_dam += W.damage + brute_dam += wound.damage - if(bleeds && W.bleeding() && (H && H.should_have_organ(BP_HEART))) - W.bleed_timer-- + if(bleeds && wound.bleeding() && (human_owner && human_owner.should_have_organ(BP_HEART))) + wound.bleed_timer-- status |= ORGAN_BLEEDING - clamped |= W.clamped - number_wounds += W.amount + clamped |= wound.clamped + number_wounds += wound.amount - damage = brute_dam + burn_dam update_damage_ratios() /obj/item/organ/external/proc/update_damage_ratios() @@ -778,8 +974,8 @@ Note that amputating the affected organ does in fact remove the infection from t var/n_is = damage_state_text() if (n_is != damage_state) damage_state = n_is - return 1 - return 0 + return TRUE + return FALSE // new damage icon system // returns just the brute/burn damage code @@ -821,7 +1017,7 @@ Note that amputating the affected organ does in fact remove the infection from t ) else switch(droptype) - if(DROPLIMB_EDGE) + if(DISMEMBER_METHOD_EDGE) if(!clean) var/gore_sound = "[BP_IS_PROSTHETIC(src) ? "tortured metal" : "ripping tendons and flesh"]" return list( @@ -829,14 +1025,21 @@ Note that amputating the affected organ does in fact remove the infection from t "Your [src.name] goes flying off!", "You hear a terrible sound of [gore_sound]." ) - if(DROPLIMB_BURN) + if(DISMEMBER_METHOD_BURN) var/gore = "[BP_IS_PROSTHETIC(src) ? "": " of burning flesh"]" return list( "\The [owner]'s [src.name] flashes away into ashes!", "Your [src.name] flashes away into ashes!", "You hear a crackling sound[gore]." ) - if(DROPLIMB_BLUNT) + if(DISMEMBER_METHOD_ACID) + var/gore = "[BP_IS_PROSTHETIC(src) ? "": " of melting flesh"]" + return list( + "\The [owner]'s [src.name] dissolves!", + "Your [src.name] dissolves!", + "You hear a hissing sound[gore]." + ) + if(DISMEMBER_METHOD_BLUNT) var/gore = "[BP_IS_PROSTHETIC(src) ? "": " in shower of gore"]" var/gore_sound = "[BP_IS_PROSTHETIC(src) ? "rending sound of tortured metal" : "sickening splatter of gore"]" return list( @@ -844,198 +1047,198 @@ Note that amputating the affected organ does in fact remove the infection from t "Your [src.name] explodes[gore]!", "You hear the [gore_sound]." ) +/obj/item/organ/external/proc/place_remains_from_dismember_method(var/dismember) + + var/dropturf = get_turf(src) + switch(dismember) + if(DISMEMBER_METHOD_BURN) + . = new /obj/effect/decal/cleanable/ash(dropturf) + if(DISMEMBER_METHOD_ACID) + . = new /obj/effect/decal/cleanable/mucus(dropturf) + if(DISMEMBER_METHOD_BLUNT) + if(BP_IS_CRYSTAL(src)) + . = new /obj/item/shard(dropturf, /decl/material/solid/gemstone/crystal) + else if(BP_IS_PROSTHETIC(src)) + . = new /obj/effect/decal/cleanable/blood/gibs/robot(dropturf) + else + . = new /obj/effect/decal/cleanable/blood/gibs(dropturf) + + if(species && istype(., /obj/effect/decal/cleanable/blood/gibs)) + var/obj/effect/decal/cleanable/blood/gibs/gibs = . + gibs.fleshcolor = species.get_species_flesh_color(owner) + gibs.basecolor = species.get_species_blood_color(owner) + gibs.update_icon() //Handles dismemberment -/obj/item/organ/external/proc/droplimb(var/clean, var/disintegrate = DROPLIMB_EDGE, var/ignore_children, var/silent) +/obj/item/organ/external/proc/dismember(var/clean, var/disintegrate = DISMEMBER_METHOD_EDGE, var/ignore_children, var/silent, var/ignore_last_organ) if(!(limb_flags & ORGAN_FLAG_CAN_AMPUTATE) || !owner) return - if(BP_IS_CRYSTAL(src) || (disintegrate == DROPLIMB_EDGE && species.limbs_are_nonsolid)) - disintegrate = DROPLIMB_BLUNT //splut + disintegrate = bodytype.check_dismember_type_override(disintegrate) + + if(BP_IS_CRYSTAL(src)) + disintegrate = DISMEMBER_METHOD_BLUNT //splut var/list/organ_msgs = get_droplimb_messages_for(disintegrate, clean) if(LAZYLEN(organ_msgs) >= 3) - owner.visible_message("[organ_msgs[1]]", \ - "[organ_msgs[2]]", \ - "[organ_msgs[3]]") - - var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed(). - var/obj/item/organ/external/original_parent = parent - - var/use_flesh_colour = species.get_flesh_colour(owner) - var/use_blood_colour = species.get_blood_colour(owner) + owner.visible_message(SPAN_DANGER("[organ_msgs[1]]"), \ + SPAN_MODERATE("[organ_msgs[2]]"), \ + SPAN_DANGER("[organ_msgs[3]]")) add_pain(60) if(!clean) - victim.shock_stage += min_broken_damage - - removed(null, ignore_children) - if(QDELETED(src)) - return + owner.shock_stage += min_broken_damage + var/mob/living/human/victim = owner //Keep a reference for post-removed(). + var/obj/item/organ/external/original_parent = parent + owner.remove_organ(src, TRUE, FALSE, ignore_children, update_icon = FALSE) if(original_parent) - var/datum/wound/lost_limb/W = new (src, disintegrate, clean) - var/obj/item/organ/external/damaged_organ = original_parent - if(!clean) - var/obj/item/organ/external/stump/stump = new (victim, 0, src) - stump.add_pain(max_damage) - damaged_organ = stump - if(disintegrate != DROPLIMB_BURN) - stump.sever_artery() - W.parent_organ = damaged_organ - LAZYADD(damaged_organ.wounds, W) - damaged_organ.update_damages() - - spawn(1) - victim.updatehealth() - victim.UpdateDamageIcon() - victim.regenerate_icons() - set_dir(SOUTH, TRUE) - - switch(disintegrate) - if(DROPLIMB_EDGE) - compile_icon() - add_blood(victim) - var/matrix/M = matrix() - M.Turn(rand(180)) - src.transform = M - forceMove(get_turf(src)) - if(!clean) - // Throw limb around. - if(src && istype(loc,/turf)) - throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) - set_dir(SOUTH, TRUE) - if(DROPLIMB_BURN) - new /obj/effect/decal/cleanable/ash(get_turf(victim)) - for(var/obj/item/I in src) - if(I.w_class > ITEM_SIZE_SMALL && !istype(I,/obj/item/organ)) - I.dropInto(loc) - qdel(src) - if(DROPLIMB_BLUNT) - var/obj/gore - if(BP_IS_CRYSTAL(src)) - gore = new /obj/item/shard(get_turf(victim), /decl/material/solid/gemstone/crystal) - else if(BP_IS_PROSTHETIC(src)) - gore = new /obj/effect/decal/cleanable/blood/gibs/robot(get_turf(victim)) - else - gore = new /obj/effect/decal/cleanable/blood/gibs(get_turf(victim)) - if(species) - var/obj/effect/decal/cleanable/blood/gibs/G = gore - G.fleshcolor = use_flesh_colour - G.basecolor = use_blood_colour - G.update_icon() + // Traumatic amputation is messy. + if(!clean && disintegrate != DISMEMBER_METHOD_BURN) + original_parent.sever_artery() + // Leave a big ol hole. + var/datum/wound/lost_limb/stump = new(src, disintegrate, clean) + stump.parent_organ = original_parent + LAZYADD(original_parent.wounds, stump) + original_parent.update_damages() + + var/remaining_organs = victim.get_external_organs() + if(istype(victim) && !QDELETED(victim)) + // If they are down to their last organ, just spawn the organ and delete them. + if(!ignore_last_organ && LAZYLEN(remaining_organs) == 1) + for(var/obj/item/organ/external/organ in remaining_organs) + victim.remove_organ(organ, TRUE, TRUE, update_icon = FALSE) + if(organ.place_remains_from_dismember_method(disintegrate)) + organ.physically_destroyed() + victim.dump_contents() + qdel(victim) + else // We deliberately skip queuing this via remove_organ() above due to potentially immediately deleting the mob. + victim.update_damage_overlays(FALSE) + victim.regenerate_body_icon = TRUE + victim.queue_icon_update() - gore.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + if(QDELETED(src)) + return - for(var/obj/item/organ/I in internal_organs) - I.removed() - if(!QDELETED(I) && isturf(loc)) - I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + // Edged attacks cause the limb to sail off in an arc. + if(disintegrate == DISMEMBER_METHOD_EDGE) - for(var/obj/item/I in src) - I.dropInto(loc) - I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30) + compile_icon() + add_blood(victim) + set_rotation(rand(180)) + forceMove(get_turf(src)) + if(!clean) + // Throw limb around. + if(src && isturf(loc)) + throw_at(get_edge_target_turf(src, pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) - qdel(src) + else + // Other attacks can destroy the limb entirely and place an item or decal. + var/atom/movable/gore = place_remains_from_dismember_method(disintegrate) + if(gore) + if(disintegrate == DISMEMBER_METHOD_BURN || disintegrate == DISMEMBER_METHOD_ACID) + for(var/obj/item/contained_item in src) + if(contained_item.w_class > ITEM_SIZE_SMALL && !istype(contained_item, /obj/item/organ)) + contained_item.dropInto(loc) + else if(disintegrate == DISMEMBER_METHOD_BLUNT) + gore.throw_at(get_edge_target_turf(src,pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) + for(var/obj/item/organ/internal_organ in internal_organs) + internal_organ.do_uninstall() //No owner so run uninstall directly + internal_organ.dropInto(get_turf(loc)) + if(!QDELETED(internal_organ) && isturf(loc)) + internal_organ.throw_at(get_edge_target_turf(src,pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) + for(var/obj/item/contained_item in src) + contained_item.dropInto(loc) + contained_item.throw_at(get_edge_target_turf(src,pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) + if(!QDELETED(src)) + qdel(src) /**************************************************** HELPERS ****************************************************/ -/obj/item/organ/external/proc/is_stump() - return 0 - -/obj/item/organ/external/proc/release_restraints(var/mob/living/carbon/human/holder) +/obj/item/organ/external/proc/release_restraints(var/mob/living/human/holder) if(!holder) holder = owner if(!holder) return - if (holder.handcuffed && (body_part in list(ARM_LEFT, ARM_RIGHT, HAND_LEFT, HAND_RIGHT))) + var/obj/item/cuffs = holder.get_equipped_item(slot_handcuffed_str) + if(cuffs && (body_part in list(SLOT_ARM_LEFT, SLOT_ARM_RIGHT, SLOT_HAND_LEFT, SLOT_HAND_RIGHT))) holder.visible_message(\ - "\The [holder.handcuffed.name] falls off of [holder.name].",\ - "\The [holder.handcuffed.name] falls off you.") - holder.drop_from_inventory(holder.handcuffed) + "\The [cuffs] falls off of [holder.name].",\ + "\The [cuffs] falls off you.") + holder.try_unequip(cuffs) // checks if all wounds on the organ are bandaged /obj/item/organ/external/proc/is_bandaged() - for(var/datum/wound/W in wounds) - if(!W.bandaged) + for(var/datum/wound/wound in wounds) + if(!wound.bandaged) return 0 return 1 // checks if all wounds on the organ are salved /obj/item/organ/external/proc/is_salved() - for(var/datum/wound/W in wounds) - if(!W.salved) + for(var/datum/wound/wound in wounds) + if(!wound.salved) return 0 return 1 // checks if all wounds on the organ are disinfected /obj/item/organ/external/proc/is_disinfected() - for(var/datum/wound/W in wounds) - if(!W.disinfected) + for(var/datum/wound/wound in wounds) + if(!wound.disinfected) return 0 return 1 -/obj/item/organ/external/proc/bandage() - var/rval = 0 - status &= ~ORGAN_BLEEDING - for(var/datum/wound/W in wounds) - rval |= !W.bandaged - W.bandaged = 1 - if(rval) - owner.update_surgery() - return rval - /obj/item/organ/external/proc/salve() var/rval = 0 - for(var/datum/wound/W in wounds) - rval |= !W.salved - W.salved = 1 + for(var/datum/wound/wound in wounds) + rval |= !wound.salved + wound.salved = 1 return rval /obj/item/organ/external/proc/disinfect() var/rval = 0 - for(var/datum/wound/W in wounds) - rval |= !W.disinfected - W.disinfected = 1 - W.germ_level = 0 + for(var/datum/wound/wound in wounds) + rval |= !wound.disinfected + wound.disinfected = 1 + wound.germ_level = 0 return rval /obj/item/organ/external/proc/clamp_organ() var/rval = 0 src.status &= ~ORGAN_BLEEDING - for(var/datum/wound/W in wounds) - rval |= !W.clamped - W.clamped = 1 + for(var/datum/wound/wound in wounds) + rval |= !wound.clamped + wound.clamped = 1 return rval /obj/item/organ/external/proc/clamped() - for(var/datum/wound/W in wounds) - if(W.clamped) + for(var/datum/wound/wound in wounds) + if(wound.clamped) return 1 -obj/item/organ/external/proc/remove_clamps() +/obj/item/organ/external/proc/remove_clamps() var/rval = 0 - for(var/datum/wound/W in wounds) - rval |= W.clamped - W.clamped = 0 + for(var/datum/wound/wound in wounds) + rval |= wound.clamped + wound.clamped = 0 return rval // open incisions and expose implants // this is the retract step of surgery /obj/item/organ/external/proc/open_incision() - var/datum/wound/W = get_incision() - if(!W) return - W.open_wound(min(W.damage * 2, W.damage_list[1] - W.damage)) + var/datum/wound/incision = get_incision() + if(!incision) return + incision.open_wound(min(incision.damage * 2, incision.damage_list[1] - incision.damage)) if(!encased) - for(var/obj/item/implant/I in implants) - I.exposed() + for(var/obj/item/implant/implant in implants) + implant.exposed() /obj/item/organ/external/proc/fracture() - if(!config.bones_can_break) + if(!get_config_value(/decl/config/toggle/on/health_bones_can_break)) return if(BP_IS_PROSTHETIC(src)) return //ORGAN_BROKEN doesn't have the same meaning for robot limbs @@ -1044,15 +1247,16 @@ obj/item/organ/external/proc/remove_clamps() if(owner) owner.visible_message(\ - "You hear a loud cracking sound coming from \the [owner].",\ - "Something feels like it shattered in your [name]!",\ - "You hear a sickening crack.") + SPAN_DANGER("You hear a loud cracking sound coming from \the [owner]."),\ + SPAN_DANGER("Something feels like it shattered in your [name]!"),\ + SPAN_DANGER("You hear a sickening crack.")) jostle_bone() if(can_feel_pain()) - owner.emote("scream") + owner.emote(/decl/emote/audible/scream) playsound(src.loc, "fracture", 100, 1, -2) status |= ORGAN_BROKEN + stage = 0 broken_description = pick("broken","fracture","hairline fracture") // Fractures have a chance of getting you out of restraints @@ -1062,14 +1266,14 @@ obj/item/organ/external/proc/remove_clamps() // This is mostly for the ninja suit to stop ninja being so crippled by breaks. // TODO: consider moving this to a suit proc or process() or something during // hardsuit rewrite. - if(!splinted && owner && istype(owner.wear_suit, /obj/item/clothing/suit/space/rig)) - var/obj/item/clothing/suit/space/rig/suit = owner.wear_suit + var/obj/item/clothing/suit/space/rig/suit = owner.get_equipped_item(slot_wear_suit_str) + if(!splinted && owner && istype(suit)) suit.handle_fracture(owner, src) /obj/item/organ/external/proc/mend_fracture() if(BP_IS_PROSTHETIC(src)) return 0 //ORGAN_BROKEN doesn't have the same meaning for robot limbs - if(brute_dam > min_broken_damage * config.organ_health_multiplier) + if(brute_dam > min_broken_damage * get_config_value(/decl/config/num/health_organ_health_multiplier)) return 0 //will just immediately fracture again status &= ~ORGAN_BROKEN @@ -1093,245 +1297,191 @@ obj/item/organ/external/proc/remove_clamps() return 1 return 0 -/obj/item/organ/external/proc/get_dexterity() - if(model) - var/datum/robolimb/R = all_robolimbs[model] - if(R) - return R.manual_dexterity +/obj/item/organ/external/proc/get_manual_dexterity() + if(!isnull(bodytype?.manual_dexterity)) + return bodytype.manual_dexterity if(species) - return species.get_manual_dexterity() - -/obj/item/organ/external/robotize(var/company, var/skip_prosthetics = 0, var/keep_organs = 0) - - if(BP_IS_PROSTHETIC(src)) - return - - ..() - - slowdown = 0 - - if(company) - var/datum/robolimb/R = all_robolimbs[company] - var/can_apply = TRUE - if(!istype(R)) - can_apply = FALSE - else if(species && ((species.get_bodytype() in R.bodytypes_cannot_use) || !(species.get_bodytype(owner) in R.allowed_bodytypes))) - can_apply = FALSE - else if(length(R.applies_to_part) && !(organ_tag in R.applies_to_part)) - can_apply = FALSE - - if(can_apply) - model = company - force_icon = R.icon - name = "[R ? R.modifier_string : "robotic"] [initial(name)]" - desc = "[R.desc] It looks like it was produced by [R.company]." - slowdown = R.movement_slowdown - max_damage *= R.hardiness - min_broken_damage *= R.hardiness - else - R = basic_robolimb - - dislocated = -1 - remove_splint() - update_icon(1) - unmutate() - - for(var/obj/item/organ/external/T in children) - T.robotize(company, 1) - - if(owner) - - if(!skip_prosthetics) - owner.full_prosthetic = null // Will be rechecked next isSynthetic() call. - - if(!keep_organs) - for(var/obj/item/organ/thing in internal_organs) - if(istype(thing)) - if(thing.vital || BP_IS_PROSTHETIC(thing)) - continue - internal_organs -= thing - owner.internal_organs_by_name[thing.organ_tag] = null - owner.internal_organs_by_name -= thing.organ_tag - owner.internal_organs.Remove(thing) - qdel(thing) - - while(null in owner.internal_organs) - owner.internal_organs -= null - - return 1 + return species.get_manual_dexterity(owner) + return DEXTERITY_NONE /obj/item/organ/external/proc/get_damage() //returns total damage return (brute_dam+burn_dam) //could use max_damage? /obj/item/organ/external/proc/has_infected_wound() - for(var/datum/wound/W in wounds) - if(W.germ_level > INFECTION_LEVEL_ONE) + for(var/datum/wound/wound in wounds) + if(wound.germ_level > INFECTION_LEVEL_ONE) return 1 return 0 /obj/item/organ/external/is_usable() - return ..() && !is_stump() && !(status & ORGAN_TENDON_CUT) && (!can_feel_pain() || get_pain() < pain_disability_threshold) && brute_ratio < 1 && burn_ratio < 1 + . = ..() + if(.) + if(is_malfunctioning()) + return FALSE + if(is_broken() && !splinted) + return FALSE + if(status & ORGAN_TENDON_CUT) + return FALSE + if(brute_ratio >= 1 || burn_ratio >= 1) + return FALSE + if(get_pain() >= pain_disability_threshold) + return FALSE /obj/item/organ/external/proc/is_malfunctioning() return (is_robotic() && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam)) -/obj/item/organ/external/proc/embed(var/obj/item/W, var/silent = 0, var/supplied_message, var/datum/wound/supplied_wound) +/obj/item/organ/external/proc/embed_in_organ(var/obj/item/embedding, var/silent = FALSE, var/supplied_message, var/datum/wound/supplied_wound) if(!owner || loc != owner) return if(species.species_flags & SPECIES_FLAG_NO_EMBED) return if(!silent) if(supplied_message) - owner.visible_message("[supplied_message]") + owner.visible_message(SPAN_DANGER("[supplied_message]")) else - owner.visible_message("\The [W] sticks in the wound!") + owner.visible_message(SPAN_DANGER("\The [embedding] sticks in the wound!")) if(!supplied_wound) for(var/datum/wound/wound in wounds) - if((wound.damage_type == CUT || wound.damage_type == PIERCE) && wound.damage >= W.w_class * 5) + if((wound.damage_type == CUT || wound.damage_type == PIERCE) && wound.damage >= embedding.w_class * 5) supplied_wound = wound break if(!supplied_wound) - supplied_wound = createwound(PIERCE, W.w_class * 5) + supplied_wound = createwound(PIERCE, embedding.w_class * 5) - if(!supplied_wound || (W in supplied_wound.embedded_objects)) // Just in case. + if(!supplied_wound || (embedding in supplied_wound.embedded_objects)) // Just in case. return - LAZYADD(supplied_wound.embedded_objects, W) - implants += W + LAZYDISTINCTADD(supplied_wound.embedded_objects, embedding) + LAZYDISTINCTADD(implants, embedding) + owner.embedded_flag = 1 owner.verbs += /mob/proc/yank_out_object - W.add_blood(owner) - if(ismob(W.loc)) - var/mob/living/H = W.loc - H.drop_from_inventory(W) - W.forceMove(owner) + embedding.add_blood(owner) + if(ismob(embedding.loc)) + var/mob/living/holder = embedding.loc + holder.drop_from_inventory(embedding) + embedding.forceMove(owner) -/obj/item/organ/external/removed(var/mob/living/user, var/ignore_children = 0) +/obj/item/organ/external/do_uninstall(in_place, detach, ignore_children, update_icon) - if(!owner) + var/mob/living/human/victim = owner //parent proc clears owner + if(!(. = ..())) return - if(limb_flags & ORGAN_FLAG_CAN_GRASP) owner.grasp_limbs -= src - if(limb_flags & ORGAN_FLAG_CAN_STAND) owner.stance_limbs -= src - - switch(body_part) - if(FOOT_LEFT, FOOT_RIGHT) - owner.drop_from_inventory(owner.shoes) - if(HAND_LEFT, HAND_RIGHT) - owner.drop_from_inventory(owner.gloves) - if(HEAD) - owner.drop_from_inventory(owner.glasses) - owner.drop_from_inventory(owner.head) - owner.drop_from_inventory(owner.l_ear) - owner.drop_from_inventory(owner.r_ear) - owner.drop_from_inventory(owner.wear_mask) - - var/mob/living/carbon/human/victim = owner - var/is_robotic = BP_IS_PROSTHETIC(src) + if(victim) + if(in_place) + //When removing in place, we don't bother with moving child organs and implants, we just clear the refs + for(var/obj/item/implant/implant in implants) + implant.removed() + //Remove the parent ref from all childs limbs until we replace the organ in place + for(var/obj/item/organ/external/child in children) + child.parent = null + + implants = null + children = null + internal_organs = null + else + //Move over our implants/items into us, and drop whatever else is too big or not an object(??) + for(var/atom/movable/implant in implants) + //large items and non-item objs fall to the floor, everything else stays + var/obj/item/item_implant = implant + if(QDELETED(implant)) + LAZYREMOVE(implants, implant) + continue + if(istype(item_implant) && item_implant.w_class < ITEM_SIZE_NORMAL) + if(istype(item_implant, /obj/item/implant)) + var/obj/item/implant/imp = item_implant + imp.removed() + implant.forceMove(src) + else // Is this even necessary? What non-items can even get added to implants? + //Dump the rest on the turf + LAZYREMOVE(implants, implant) + implant.forceMove(get_turf(src)) + + if(!ignore_children) + //Move our chilren limb into our contents + for(var/obj/item/organ/external/child in children) + victim.remove_organ(child, FALSE, FALSE, FALSE, in_place, update_icon) + if(QDELETED(child)) + LAZYREMOVE(children, child) + continue + child.do_install(null, src, FALSE, update_icon, FALSE) //Forcemove the organ and properly set it up in our internal data - ..() + // Grab all the children internal organs + for(var/obj/item/organ/internal/organ in internal_organs) + victim.remove_organ(organ, FALSE, FALSE, FALSE, in_place, update_icon) + if(QDELETED(organ)) + LAZYREMOVE(internal_organs, organ) + continue + organ.do_install(null, src, FALSE, update_icon, FALSE) //Forcemove the organ and properly set it up in our internal data - victim.bad_external_organs -= src + victim.full_prosthetic = null - remove_splint() - for(var/atom/movable/implant in implants) - //large items and non-item objs fall to the floor, everything else stays - var/obj/item/I = implant - if(istype(I) && I.w_class < ITEM_SIZE_NORMAL) - implant.forceMove(src) - - // let actual implants still inside know they're no longer implanted - if(istype(I, /obj/item/implant)) - var/obj/item/implant/imp_device = I - imp_device.removed() - else - implants.Remove(implant) - implant.forceMove(get_turf(src)) - - // Attached organs also fly off. - if(!ignore_children) - for(var/obj/item/organ/external/O in children) - O.removed() - if(!QDELETED(O)) - O.forceMove(src) - - // if we didn't lose the organ we still want it as a child - children += O - O.parent = src - - // Grab all the internal giblets too. - for(var/obj/item/organ/organ in internal_organs) - organ.removed(user, 0, 0) // Organ stays inside and connected - if(!QDELETED(organ)) - organ.forceMove(src) + //Note that we don't need to change our own hierarchy when not removing from a mob // Remove parent references if(parent) - parent.children -= src - parent = null - - if(!is_robotic) - status |= ORGAN_CUT_AWAY + LAZYREMOVE(parent.children, src) + parent = null - release_restraints(victim) - victim.organs -= src - victim.organs_by_name[organ_tag] = null // Remove from owner's vars. - victim.organs_by_name -= organ_tag +/obj/item/organ/external/on_remove_effects(mob/living/last_owner) + . = ..() + drop_equipped_clothing() + remove_splint() + release_restraints(last_owner) //Robotic limbs explode if sabotaged. - if(is_robotic && (status & ORGAN_SABOTAGED)) - victim.visible_message( - "\The [victim]'s [src.name] explodes violently!",\ - "Your [src.name] explodes!",\ - "You hear an explosion!") - explosion(get_turf(owner),-1,-1,2,3) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, victim) - spark_system.attach(owner) - spark_system.start() - spawn(10) - qdel(spark_system) - qdel(src) - else if(is_stump()) + if(BP_IS_PROSTHETIC(src) && (status & ORGAN_SABOTAGED)) + last_owner.visible_message( + SPAN_DANGER("\The [last_owner]'s [src.name] explodes violently!"),\ + SPAN_DANGER("Your [src.name] explodes!"),\ + SPAN_DANGER("You hear an explosion!")) + explosion(get_turf(last_owner),-1,-1,2,3) + spark_at(last_owner, 5, holder=last_owner) qdel(src) -/obj/item/organ/external/proc/disfigure(var/type = "brute") +/obj/item/organ/external/set_detached(is_detached) + if(BP_IS_PROSTHETIC(src)) + is_detached = FALSE //External prosthetics are never detached + . = ..(is_detached) + +/obj/item/organ/external/proc/disfigure(var/type = BRUTE) if(status & ORGAN_DISFIGURED) return if(owner) - if(type == "brute") - owner.visible_message("You hear a sickening cracking sound coming from \the [owner]'s [name].", \ - "Your [name] becomes a mangled mess!", \ - "You hear a sickening crack.") + if(type == BRUTE) + owner.visible_message(SPAN_DANGER("You hear a sickening cracking sound coming from \the [owner]'s [name]."), \ + SPAN_DANGER("Your [name] becomes a mangled mess!"), \ + SPAN_DANGER("You hear a sickening crack.")) else - owner.visible_message("\The [owner]'s [name] melts away, turning into mangled mess!", \ - "Your [name] melts away!", \ - "You hear a sickening sizzle.") + owner.visible_message(SPAN_DANGER("\The [owner]'s [name] melts away, turning into mangled mess!"), \ + SPAN_DANGER("Your [name] melts away!"), \ + SPAN_DANGER("You hear a sickening sizzle.")) status |= ORGAN_DISFIGURED /obj/item/organ/external/proc/get_incision(var/strict) var/datum/wound/incision - if(BP_IS_CRYSTAL(src)) + if(BP_IS_CRYSTAL(src) || (limb_flags & ORGAN_FLAG_SKELETAL)) for(var/datum/wound/shatter/other in wounds) if(!incision || incision.damage < other.damage) incision = other else - for(var/datum/wound/cut/W in wounds) - if(W.bandaged || W.current_stage > W.max_bleeding_stage) // Shit's unusable + for(var/datum/wound/cut/candidate_incision in wounds) + if(!candidate_incision.is_open()) // Shit's unusable continue - if(strict && !W.is_surgical()) //We don't need dirty ones + if(strict && !candidate_incision.is_surgical()) //We don't need dirty ones continue if(!incision) - incision = W + incision = candidate_incision continue - var/same = W.is_surgical() == incision.is_surgical() + var/same = candidate_incision.is_surgical() == incision.is_surgical() if(same) //If they're both dirty or both are surgical, just get bigger one - if(W.damage > incision.damage) - incision = W - else if(W.is_surgical()) //otherwise surgical one takes priority - incision = W + if(candidate_incision.damage > incision.damage) + incision = candidate_incision + else if(candidate_incision.is_surgical()) //otherwise surgical one takes priority + incision = candidate_incision return incision /obj/item/organ/external/proc/how_open() @@ -1343,8 +1493,9 @@ obj/item/organ/external/proc/remove_clamps() if(encased && (status & ORGAN_BROKEN)) . = SURGERY_ENCASED else - var/smol_threshold = min_broken_damage * 0.4 - var/beeg_threshold = min_broken_damage * 0.6 + var/total_health_coefficient = scale_max_damage_to_species_health ? (species.total_health / DEFAULT_SPECIES_HEALTH) : 1 + var/smol_threshold = max(1, floor(min_broken_damage * 0.4 * total_health_coefficient)) + var/beeg_threshold = max(1, floor(min_broken_damage * 0.6 * total_health_coefficient)) if(!incision.autoheal_cutoff == 0) //not clean incision smol_threshold *= 1.5 beeg_threshold = max(beeg_threshold, min(beeg_threshold * 1.5, incision.damage_list[1])) //wounds can't achieve bigger @@ -1360,10 +1511,10 @@ obj/item/organ/external/proc/remove_clamps() return if(brute_dam + force < min_broken_damage/5) //no papercuts moving bones return - if(internal_organs.len && prob(brute_dam + force)) + if(LAZYLEN(internal_organs) && prob(brute_dam + force)) owner.custom_pain("A piece of bone in your [encased ? encased : name] moves painfully!", 50, affecting = src) - var/obj/item/organ/internal/I = pick(internal_organs) - I.take_internal_damage(rand(3,5)) + var/obj/item/organ/internal/internal_organ = pick(internal_organs) + internal_organ.take_damage(rand(3,5)) /obj/item/organ/external/proc/jointlock(mob/attacker) if(!can_feel_pain()) @@ -1371,49 +1522,130 @@ obj/item/organ/external/proc/remove_clamps() var/armor = 100 * owner.get_blocked_ratio(owner, BRUTE, damage = 30) if(armor < 70) - to_chat(owner, "You feel extreme pain!") + to_chat(owner, SPAN_DANGER("You feel extreme pain!")) var/max_halloss = round(owner.species.total_health * 0.8 * ((100 - armor) / 100)) //up to 80% of passing out, further reduced by armour - add_pain(Clamp(0, max_halloss - owner.getHalLoss(), 30)) + add_pain(clamp(0, max_halloss - owner.get_damage(PAIN), 30)) //Adds autopsy data for used_weapon. /obj/item/organ/external/proc/add_autopsy_data(var/used_weapon, var/damage) var/key = used_weapon var/data = used_weapon if(istype(used_weapon, /obj/item)) - var/obj/item/I = used_weapon - key = I.name - data = english_list(I.get_autopsy_descriptors()) - var/datum/autopsy_data/W = autopsy_data[key] - if(!W) - W = new() - W.weapon = data - autopsy_data[key] = W - - W.hits += 1 - W.damage += damage - W.time_inflicted = world.time + var/obj/item/used_item = used_weapon + key = used_item.name + data = english_list(used_item.get_autopsy_descriptors()) + var/datum/autopsy_data/autopsy_datum = LAZYACCESS(autopsy_data, key) + if(!autopsy_datum) + autopsy_datum = new() + autopsy_datum.weapon = data + LAZYSET(autopsy_data, key, autopsy_datum) + + autopsy_datum.hits += 1 + autopsy_datum.damage += damage + autopsy_datum.time_inflicted = world.time /obj/item/organ/external/proc/has_genitals() - return !BP_IS_PROSTHETIC(src) && species && species.sexybits_location == organ_tag + return !BP_IS_PROSTHETIC(src) && bodytype?.get_vulnerable_location() == organ_tag // Added to the mob's move delay tally if this organ is being used to move with. -/obj/item/organ/external/proc/movement_delay(max_delay) +/obj/item/organ/external/proc/get_movement_delay(max_delay) . = 0 - if(is_stump()) - . += max_delay - else if(splinted) + if(splinted) . += max_delay/8 else if(status & ORGAN_BROKEN) . += max_delay * 3/8 else if(BP_IS_PROSTHETIC(src)) - . += max_delay * CLAMP01(damage/max_damage) + . += max_delay * CLAMP01((brute_dam + burn_dam) / max_damage) /obj/item/organ/external/proc/is_robotic() - . = FALSE - if(BP_IS_PROSTHETIC(src) && model) - var/datum/robolimb/R = all_robolimbs[model] - . = R && R.is_robotic + return bodytype.is_robotic /obj/item/organ/external/proc/has_growths() return FALSE + +/obj/item/organ/external/add_ailment(var/datum/ailment/ailment) + . = ..() + if(. && owner) + LAZYDISTINCTADD(owner.bad_external_organs, src) + +/obj/item/organ/external/die() //External organs dying on a dime causes some real issues in combat + if(!BP_IS_PROSTHETIC(src) && !BP_IS_CRYSTAL(src)) + var/decay_rate = (brute_dam + burn_dam) / (max_damage*2) + germ_level += round(rand(decay_rate,decay_rate*1.5)) //So instead, we're going to say the damage is so severe its functions are slowly failing due to the extensive damage + else //TODO: more advanced system for synths + if(istype(src,/obj/item/organ/external/chest) || istype(src,/obj/item/organ/external/groin)) + return + status |= ORGAN_DEAD + if(status & ORGAN_DEAD) //The organic dying part is covered in germ handling + STOP_PROCESSING(SSobj, src) + QDEL_NULL_LIST(ailments) + death_time = REALTIMEOFDAY + +/obj/item/organ/external/is_internal() + return FALSE + +/obj/item/organ/external/place_butcher_product(decl/butchery_data/butchery_decl) + if(butchery_decl.bone_type) + butchery_decl.place_products(owner, butchery_decl.bone_material, 1, butchery_decl.bone_type) + return ..() + +/obj/item/organ/external/physically_destroyed(skip_qdel) + if(!owner) + return ..() + if(limb_flags & ORGAN_FLAG_CAN_AMPUTATE) + dismember(FALSE, DISMEMBER_METHOD_BLUNT) // This will also destroy the mob if it removes the last non-core limb. + else + owner.physically_destroyed() // Previously gib(), but that caused blood and guts to fly everywhere. + +/obj/item/organ/external/is_vital_to_owner() + if(isnull(vital_to_owner)) + . = ..() + if(!.) + for(var/obj/item/organ/child in children) + if(child.is_vital_to_owner()) + vital_to_owner = TRUE + break + return vital_to_owner + +/obj/item/organ/external/proc/get_grooming_results(obj/item/grooming/tool) + + for(var/accessory_category in _sprite_accessories) + var/list/draw_accessories = _sprite_accessories[accessory_category] + for(var/accessory in draw_accessories) + var/decl/sprite_accessory/accessory_decl = resolve_accessory_to_decl(accessory) + var/grooming_result = accessory_decl.can_be_groomed_with(src, tool) + . = list( + "success" = grooming_result, + "descriptor" = accessory_decl.get_grooming_descriptor(grooming_result, src, tool) + ) + if(grooming_result != GROOMING_RESULT_FAILED) + return + + var/default_results = bodytype.get_default_grooming_results(src, tool) + if(default_results) + . = default_results + +/obj/item/organ/external/proc/get_sprite_accessories(copy = FALSE) + if(copy) + return _sprite_accessories?.Copy() + return _sprite_accessories + +/obj/item/organ/external/proc/skeletonize(mob/living/donor) + if(limb_flags & ORGAN_FLAG_SKELETAL) + return + if(!donor) + if(!owner) + return + donor = owner + var/decl/butchery_data/butchery_data = GET_DECL(donor.butchery_data) + if(!butchery_data?.bone_material) + return + material = GET_DECL(butchery_data?.bone_material) + limb_flags |= ORGAN_FLAG_SKELETAL + status |= (ORGAN_DEAD|ORGAN_BRITTLE) + _sprite_accessories = null + update_icon() + +/obj/item/organ/external/is_broken() + return (brute_dam + burn_dam) >= min_broken_damage || ..() diff --git a/code/modules/organs/external/_external_damage.dm b/code/modules/organs/external/_external_damage.dm index 73adf9317cd5..2431326554db 100644 --- a/code/modules/organs/external/_external_damage.dm +++ b/code/modules/organs/external/_external_damage.dm @@ -6,12 +6,16 @@ //Continued damage to vital organs can kill you, and robot organs don't count towards total damage so no need to cap them. return (BP_IS_PROSTHETIC(src) || brute_dam + burn_dam + additional_damage < max_damage * 4) -obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) - take_external_damage(amount) +/obj/item/organ/external/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health, override_droplimb) -/obj/item/organ/external/proc/take_external_damage(brute, burn, damage_flags, used_weapon = null) - brute = round(brute * get_brute_mod(damage_flags), 0.1) - burn = round(burn * get_burn_mod(damage_flags), 0.1) + if(!owner) + return ..() + + var/final_brute_mod = get_brute_mod(damage_flags) + (0.2 * burn_dam/max_damage) // extra brute taken if you have burn damage. why? ask whoever originally coded it. + var/final_burn_mod = get_burn_mod(damage_flags) + + var/brute = damage_type == BRUTE ? round(damage * final_brute_mod, 0.1) : 0 + var/burn = damage_type == BURN ? round(damage * final_burn_mod, 0.1) : 0 if((brute <= 0) && (burn <= 0)) return 0 @@ -27,10 +31,10 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) owner.bodytemperature += burn burn = 0 if(prob(25)) - owner.visible_message("\The [owner]'s crystalline [name] shines with absorbed energy!") + owner.visible_message(SPAN_WARNING("\The [owner]'s crystalline [name] shines with absorbed energy!")) - if(used_weapon) - add_autopsy_data(used_weapon, brute + burn) + if(inflicter) + add_autopsy_data(inflicter, brute + burn) var/spillover = 0 var/pure_brute = brute @@ -42,14 +46,15 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) spillover = brute_dam + burn_dam + brute + burn - max_damage if(spillover > 0) burn = max(burn - spillover, 0) + //If limb took enough damage, try to cut or tear it off if(owner && loc == owner) - owner.updatehealth() //droplimb will call updatehealth() again if it does end up being called - if(!is_stump() && (limb_flags & ORGAN_FLAG_CAN_AMPUTATE) && config.limbs_can_break) + owner.update_health() //droplimb will call update_health() again if it does end up being called + if((limb_flags & ORGAN_FLAG_CAN_AMPUTATE) && get_config_value(/decl/config/toggle/on/health_limbs_can_break)) var/total_damage = brute_dam + burn_dam + brute + burn + spillover - var/threshold = max_damage * config.organ_health_multiplier + var/threshold = max_damage * get_config_value(/decl/config/num/health_organ_health_multiplier) if(total_damage > threshold) - if(attempt_dismemberment(pure_brute, burn, sharp, edge, used_weapon, spillover, total_damage > threshold*6)) + if(attempt_dismemberment(pure_brute, burn, sharp, edge, inflicter, spillover, total_damage > threshold*6, override_droplimb = override_droplimb)) return //blunt damage is gud at fracturing @@ -57,15 +62,14 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) fracture() // High brute damage or sharp objects may damage internal organs - if(LAZYLEN(internal_organs)) - if(damage_internal_organs(brute, burn, damage_flags)) - brute /= 2 - burn /= 2 + if(LAZYLEN(internal_organs) && damage_internal_organs(brute, burn, damage_flags)) + brute /= 2 + burn /= 2 - if(status & ORGAN_BROKEN && brute) + if((status & ORGAN_BROKEN) && brute) jostle_bone(brute) if(can_feel_pain() && prob(40)) - owner.emote("scream") //getting hit on broken hand hurts + owner.emote(/decl/emote/audible/scream) //getting hit on broken hand hurts // If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking var/datum/wound/created_wound @@ -83,11 +87,11 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) if(burn) if(laser) - createwound(LASER, burn) + created_wound = createwound(LASER, burn) if(prob(40)) - owner.IgniteMob() + owner.ignite_fire() else - createwound(BURN, burn) + created_wound = createwound(BURN, burn) //Initial pain spike add_pain(0.6*burn + 0.4*brute) @@ -95,30 +99,31 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) //Disturb treated burns if(brute > 5) var/disturbed = 0 - for(var/datum/wound/burn/W in wounds) - if((W.disinfected || W.salved) && prob(brute + W.damage)) - W.disinfected = 0 - W.salved = 0 - disturbed += W.damage + for(var/datum/wound/burn/wound in wounds) + if((wound.disinfected || wound.salved) && prob(brute + wound.damage)) + wound.disinfected = 0 + wound.salved = 0 + disturbed += wound.damage if(disturbed) to_chat(owner,"Ow! Your burns were disturbed.") add_pain(0.5*disturbed) //If there are still hurties to dispense if (spillover) - owner.shock_stage += spillover * config.organ_damage_spillover_multiplier + owner.shock_stage += spillover * get_config_value(/decl/config/num/health_organ_damage_spillover_multiplier) // sync the organ's damage with its wounds update_damages() - owner.updatehealth() + if(do_update_health) + owner.update_health() if(status & ORGAN_BLEEDING) owner.update_bandages() if(owner && update_damstate()) - owner.UpdateDamageIcon() + owner.update_damage_overlays() - if(created_wound && isobj(used_weapon)) - var/obj/O = used_weapon + if(created_wound && isobj(inflicter)) + var/obj/O = inflicter O.after_wounding(src, created_wound) return created_wound @@ -149,10 +154,10 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) var/list/victims = list() var/organ_hit_chance = 0 - for(var/obj/item/organ/internal/I in internal_organs) - if(I.damage < I.max_damage) - victims[I] = I.relative_size - organ_hit_chance += I.relative_size + for(var/obj/item/organ/internal/organ in internal_organs) + if(organ.get_organ_damage() < organ.max_damage) + victims[organ] = organ.relative_size + organ_hit_chance += organ.relative_size //No damageable organs if(!length(victims)) @@ -167,7 +172,7 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) if(prob(organ_hit_chance)) var/obj/item/organ/internal/victim = pickweight(victims) damage_amt -= max(damage_amt*victim.damage_reduction, 0) - victim.take_internal_damage(damage_amt) + victim.take_damage(damage_amt) return TRUE /obj/item/organ/external/heal_damage(brute, burn, internal = 0, robo_repair = 0) @@ -175,38 +180,35 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) return //Heal damage on the individual wounds - for(var/datum/wound/W in wounds) + for(var/datum/wound/wound in wounds) if(brute == 0 && burn == 0) break // heal brute damage - if(W.damage_type == BURN) - burn = W.heal_damage(burn) + if(wound.damage_type == BURN) + burn = wound.heal_damage(burn) else - brute = W.heal_damage(brute) + brute = wound.heal_damage(brute) if(internal) status &= ~ORGAN_BROKEN //Sync the organ's damage with its wounds - src.update_damages() - owner.updatehealth() + update_damages() + owner.update_health() return update_damstate() -// Brute/burn -/obj/item/organ/external/proc/get_brute_damage() - return brute_dam - -/obj/item/organ/external/proc/get_burn_damage() - return burn_dam - // Geneloss/cloneloss. /obj/item/organ/external/proc/get_genetic_damage() - return ((species && (species.species_flags & SPECIES_FLAG_NO_SCAN)) || BP_IS_PROSTHETIC(src)) ? 0 : genetic_degradation + if(!bodytype || (bodytype.body_flags & BODY_FLAG_NO_DNA)) + return 0 + if(BP_IS_PROSTHETIC(src)) + return 0 + return genetic_degradation /obj/item/organ/external/proc/remove_genetic_damage(var/amount) - if((species.species_flags & SPECIES_FLAG_NO_SCAN) || BP_IS_PROSTHETIC(src)) + if(bodytype.body_flags & BODY_FLAG_NO_DNA) genetic_degradation = 0 status &= ~ORGAN_MUTATED return @@ -219,7 +221,7 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) return -(genetic_degradation - last_gene_dam) /obj/item/organ/external/proc/add_genetic_damage(var/amount) - if((species.species_flags & SPECIES_FLAG_NO_SCAN) || BP_IS_PROSTHETIC(src)) + if(bodytype.body_flags & BODY_FLAG_NO_DNA) genetic_degradation = 0 status &= ~ORGAN_MUTATED return @@ -244,7 +246,7 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) // Pain/halloss /obj/item/organ/external/proc/get_pain() - if(!can_feel_pain() || BP_IS_PROSTHETIC(src)) + if(!can_feel_pain()) return 0 var/lasting_pain = 0 if(is_broken()) @@ -252,8 +254,8 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) else if(is_dislocated()) lasting_pain += 5 var/tox_dam = 0 - for(var/obj/item/organ/internal/I in internal_organs) - tox_dam += I.getToxLoss() + for(var/obj/item/organ/internal/organ in internal_organs) + tox_dam += organ.getToxLoss() return pain + lasting_pain + 0.7 * brute_dam + 0.8 * burn_dam + 0.3 * tox_dam + 0.5 * get_genetic_damage() /obj/item/organ/external/proc/remove_pain(var/amount) @@ -270,119 +272,109 @@ obj/item/organ/external/take_general_damage(var/amount, var/silent = FALSE) return var/last_pain = pain if(owner) - amount -= (owner.chem_effects[CE_PAINKILLER]/3) + amount -= (GET_CHEMICAL_EFFECT(owner, CE_PAINKILLER)/3) if(amount <= 0) return pain = max(0,min(max_damage,pain+amount)) if(owner && ((amount > 15 && prob(20)) || (amount > 30 && prob(60)))) - owner.emote("scream") + owner.emote(/decl/emote/audible/scream) return pain-last_pain /obj/item/organ/external/proc/stun_act(var/stun_amount, var/agony_amount) if(agony_amount && owner && can_feel_pain()) - agony_amount -= (owner.chem_effects[CE_PAINKILLER]/2)//painkillers does wonders! + agony_amount -= (GET_CHEMICAL_EFFECT(owner, CE_PAINKILLER)/2)//painkillers does wonders! agony_amount += get_pain() - if(agony_amount < 5) return + if(agony_amount < 5) + return - if(limb_flags & ORGAN_FLAG_CAN_GRASP) - if(prob((agony_amount/max_damage)*100)) - owner.grasp_damage_disarm(src) - return 1 + if(check_pain_disarm()) + return TRUE - else if((limb_flags & ORGAN_FLAG_CAN_STAND)) + if(limb_flags & ORGAN_FLAG_CAN_STAND) if(prob((agony_amount/max_damage)*100)) owner.stance_damage_prone(src) - return 1 + return TRUE else if(agony_amount > 0.5 * max_damage) - owner.visible_message("[owner] reels in pain!") + owner.visible_message(SPAN_WARNING("\The [owner] reels in pain!")) if(has_genitals() || agony_amount > max_damage) - owner.Weaken(4) + SET_STATUS_MAX(owner, STAT_WEAK, 4) else - owner.Stun(4) - owner.drop_l_hand() - owner.drop_r_hand() + SET_STATUS_MAX(owner, STAT_STUN, 4) return 1 /obj/item/organ/external/proc/get_agony_multiplier() return has_genitals() ? 2 : 1 /obj/item/organ/external/proc/sever_artery() - if(species && species.has_organ[BP_HEART]) - var/obj/item/organ/internal/heart/O = species.has_organ[BP_HEART] - if(!BP_IS_PROSTHETIC(src) && !(status & ORGAN_ARTERY_CUT) && !initial(O.open)) + var/obj/item/organ/internal/heart/heart_path = bodytype?.has_organ[BP_HEART] + if(heart_path) + if(!BP_IS_PROSTHETIC(src) && !(limb_flags & ORGAN_FLAG_SKELETAL) && !(status & ORGAN_ARTERY_CUT) && !initial(heart_path.open)) status |= ORGAN_ARTERY_CUT return TRUE return FALSE /obj/item/organ/external/proc/sever_tendon() - if((limb_flags & ORGAN_FLAG_HAS_TENDON) && !BP_IS_PROSTHETIC(src) && !(status & ORGAN_TENDON_CUT)) + if((limb_flags & ORGAN_FLAG_HAS_TENDON) && !BP_IS_PROSTHETIC(src) && !(limb_flags & ORGAN_FLAG_SKELETAL) && !(status & ORGAN_TENDON_CUT)) status |= ORGAN_TENDON_CUT return TRUE return FALSE /obj/item/organ/external/proc/get_brute_mod(var/damage_flags) - var/obj/item/organ/internal/augment/armor/A = owner && owner.internal_organs_by_name[BP_AUGMENT_CHEST_ARMOUR] - var/B = 1 - if(A && istype(A)) - B = A.brute_mult + . = 1 if(!BP_IS_PROSTHETIC(src)) - B *= species.get_brute_mod(owner) - var/blunt = !(damage_flags & DAM_EDGE|DAM_SHARP) - if(blunt && BP_IS_BRITTLE(src)) - B *= 1.5 + . *= species.get_brute_mod(owner) + if(!(damage_flags & DAM_EDGE|DAM_SHARP) && BP_IS_BRITTLE(src)) + . *= 1.5 if(BP_IS_CRYSTAL(src)) - B *= 0.8 - return B + (0.2 * burn_dam/max_damage) //burns make you take more brute damage + . *= 0.8 /obj/item/organ/external/proc/get_burn_mod(var/damage_flags) - var/obj/item/organ/internal/augment/armor/A = owner && owner.internal_organs_by_name[BP_AUGMENT_CHEST_ARMOUR] - var/B = 1 - if(A && istype(A)) - B = A.burn_mult + . = 1 if(!BP_IS_PROSTHETIC(src)) - B *= species.get_burn_mod(owner) + . *= species.get_burn_mod(owner) if(BP_IS_CRYSTAL(src)) - B *= 0.1 - return B + . *= 0.1 //organs can come off in three cases //1. If the damage source is edge_eligible and the brute damage dealt exceeds the edge threshold, then the organ is cut off. //2. If the damage amount dealt exceeds the disintegrate threshold, the organ is completely obliterated. //3. If the organ has already reached or would be put over it's max damage amount (currently redundant), // and the brute damage dealt exceeds the tearoff threshold, the organ is torn off. -/obj/item/organ/external/proc/attempt_dismemberment(brute, burn, sharp, edge, used_weapon, spillover, force_droplimb) +/obj/item/organ/external/proc/attempt_dismemberment(brute, burn, sharp, edge, used_weapon, spillover, force_droplimb, override_droplimb) //Check edge eligibility - var/edge_eligible = 0 + var/edge_eligible = FALSE if(edge) + // used_weapon can be a string sometimes, for some reason + // todo: refactor to avoid? if(istype(used_weapon,/obj/item)) - var/obj/item/W = used_weapon - if(W.w_class >= w_class) - edge_eligible = 1 + var/obj/item/used_item = used_weapon + if(used_item.w_class >= w_class) + edge_eligible = TRUE else - edge_eligible = 1 + edge_eligible = TRUE else if(sharp) brute = 0.5 * brute if(force_droplimb) if(burn) - droplimb(0, DROPLIMB_BURN) + dismember(FALSE, (override_droplimb || DISMEMBER_METHOD_BURN)) else if(brute) - droplimb(0, edge_eligible ? DROPLIMB_EDGE : DROPLIMB_BLUNT) + dismember(FALSE, (override_droplimb || (edge_eligible ? DISMEMBER_METHOD_EDGE : DISMEMBER_METHOD_BLUNT))) return TRUE if(edge_eligible && brute >= max_damage / DROPLIMB_THRESHOLD_EDGE) if(prob(brute)) - droplimb(0, DROPLIMB_EDGE) + dismember(FALSE, (override_droplimb || DISMEMBER_METHOD_EDGE)) return TRUE else if(burn >= max_damage / DROPLIMB_THRESHOLD_DESTROY) if(prob(burn/3)) - droplimb(0, DROPLIMB_BURN) + dismember(FALSE, (override_droplimb || DISMEMBER_METHOD_BURN)) return TRUE else if(brute >= max_damage / DROPLIMB_THRESHOLD_DESTROY) if(prob(brute)) - droplimb(0, DROPLIMB_BLUNT) + dismember(FALSE, (override_droplimb || DISMEMBER_METHOD_BLUNT)) return TRUE else if(brute >= max_damage / DROPLIMB_THRESHOLD_TEAROFF) if(prob(brute/3)) - droplimb(0, DROPLIMB_EDGE) + dismember(FALSE, (override_droplimb || DISMEMBER_METHOD_EDGE)) return TRUE diff --git a/code/modules/organs/external/_external_icons.dm b/code/modules/organs/external/_external_icons.dm index a2dcb7605146..b6351d6da8ff 100644 --- a/code/modules/organs/external/_external_icons.dm +++ b/code/modules/organs/external/_external_icons.dm @@ -1,154 +1,351 @@ -var/list/limb_icon_cache = list() +var/global/list/limb_icon_cache = list() -/obj/item/organ/external/set_dir(var/direction, var/forced) - SHOULD_CALL_PARENT(FALSE) - if(forced) - return ..(direction) - return FALSE +/obj/item/organ/external + var/force_limb_dir = SOUTH + +/obj/item/organ/external/set_dir() + return ..(force_limb_dir) /obj/item/organ/external/proc/compile_icon() - overlays.Cut() // This is a kludge, only one icon has more than one generation of children though. for(var/obj/item/organ/external/organ in contents) if(organ.children && organ.children.len) for(var/obj/item/organ/external/child in organ.children) - overlays += child.mob_icon - overlays += organ.mob_icon + child.update_icon() + child.compile_overlays() + organ.update_icon() + organ.compile_overlays() + update_icon() + compile_overlays() + +/obj/item/organ/external/proc/get_surgery_overlay_icon() + if(limb_flags & ORGAN_FLAG_SKELETAL) + return null + return bodytype?.get_surgery_overlay_icon(owner) -/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human) +/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/human/human) + _icon_cache_key = null skin_tone = null skin_colour = null - skin_base = "" - hair_colour = human.hair_colour - if(BP_IS_PROSTHETIC(src) && !(human.species.appearance_flags & HAS_BASE_SKIN_COLOURS)) - var/datum/robolimb/franchise = all_robolimbs[model] - if(!(franchise && franchise.skintone)) - return - skin_blend = franchise.limb_blend - if(species && human.species && species.name != human.species.name) + var/decl/bodytype/icon_bodytype = get_organ_appearance_bodytype() + if(!icon_bodytype) return - if(!isnull(human.skin_tone) && (human.species.appearance_flags & HAS_A_SKIN_TONE)) + // This used to do a bodytype set but that was *really really bad.* Things that need that should do it themselves. + skin_blend = icon_bodytype.limb_blend + if(!isnull(human.skin_tone) && (icon_bodytype.appearance_flags & HAS_A_SKIN_TONE)) skin_tone = human.skin_tone - if(!isnull(human.skin_base) && (human.species.appearance_flags & HAS_BASE_SKIN_COLOURS)) - skin_base = human.skin_base - if(human.species.appearance_flags & HAS_SKIN_COLOR) - skin_colour = human.skin_colour + if(icon_bodytype.appearance_flags & HAS_SKIN_COLOR) + skin_colour = human.get_skin_colour() -/obj/item/organ/external/proc/sync_colour_to_dna() - skin_tone = null - skin_colour = null - skin_base = dna.skin_base - hair_colour = rgb(dna.GetUIValue(DNA_UI_HAIR_R),dna.GetUIValue(DNA_UI_HAIR_G),dna.GetUIValue(DNA_UI_HAIR_B)) - if(BP_IS_PROSTHETIC(src)) - var/datum/robolimb/franchise = all_robolimbs[model] - if(!(franchise && franchise.skintone)) - return - if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && (species.appearance_flags & HAS_A_SKIN_TONE)) - skin_tone = dna.GetUIValue(DNA_UI_SKIN_TONE) - if(species.appearance_flags & HAS_SKIN_COLOR) - skin_colour = rgb(dna.GetUIValue(DNA_UI_SKIN_R), dna.GetUIValue(DNA_UI_SKIN_G), dna.GetUIValue(DNA_UI_SKIN_B)) - -/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/carbon/human/human) +/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/human/human) ..() - var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[BP_EYES] + var/obj/item/organ/internal/eyes/eyes = human.get_organ(BP_EYES, /obj/item/organ/internal/eyes) if(eyes) eyes.update_colour() -/obj/item/organ/external/head/removed() - update_icon(1) - if(owner) - SetName("[owner.real_name]'s head") - addtimer(CALLBACK(owner, /mob/living/carbon/human/proc/update_hair), 1, TIMER_UNIQUE) - ..() - //Head markings, duplicated (sadly) below. - for(var/M in markings) - var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] - if (mark_style.draw_target == MARKING_TARGET_SKIN) - var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") - mark_s.Blend(markings[M]["color"], mark_style.blend) - overlays |= mark_s //So when it's not on your body, it has icons - mob_icon.Blend(mark_s, mark_style.layer_blend) //So when it's on your body, it has icons - icon_cache_key += "[M][markings[M]["color"]]" - -/obj/item/organ/external/var/icon_cache_key -/obj/item/organ/external/on_update_icon(var/regenerate = 0) - var/gender = "_m" - if(!(limb_flags & ORGAN_FLAG_GENDERED_ICON)) - gender = null - else if (dna && dna.GetUIState(DNA_UI_GENDER)) - gender = "_f" - else if(owner && owner.gender == FEMALE) - gender = "_f" - - icon_state = "[icon_name][gender]" - if(species.base_skin_colours && !isnull(species.base_skin_colours[skin_base])) - icon_state += species.base_skin_colours[skin_base] - icon_cache_key = "[icon_state]_[species ? species.name : "unknown"]" - if(model) - icon_cache_key += "_model_[model]" - - if(force_icon) - icon = force_icon - else if (BP_IS_PROSTHETIC(src)) - icon = 'icons/mob/human_races/cyberlimbs/robotic.dmi' - else if (!dna) - icon = 'icons/mob/human_races/species/human/body.dmi' - else if (status & ORGAN_MUTATED) - icon = species.deform - else if (owner && (MUTATION_SKELETON in owner.mutations)) - icon = 'icons/mob/human_races/species/human/skeleton.dmi' - else - icon = species.get_icobase(owner) - - mob_icon = apply_colouration(new/icon(icon, icon_state)) - - //Body markings, does not include head, duplicated (sadly) above. - for(var/M in markings) - var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] - if (mark_style.draw_target == MARKING_TARGET_SKIN) - var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") - mark_s.Blend(markings[M]["color"], mark_style.blend) - overlays |= mark_s //So when it's not on your body, it has icons - mob_icon.Blend(mark_s, mark_style.layer_blend) //So when it's on your body, it has icons - icon_cache_key += "[M][markings[M]["color"]]" - - if(body_hair && hair_colour) - var/cache_key = "[body_hair]-[icon_name]-[hair_colour]" - if(!limb_icon_cache[cache_key]) - var/icon/I = icon(species.get_icobase(owner), "[icon_name]_[body_hair]") - I.Blend(hair_colour, ICON_ADD) - limb_icon_cache[cache_key] = I - mob_icon.Blend(limb_icon_cache[cache_key], ICON_OVERLAY) - - set_dir(EAST, TRUE) - icon = mob_icon - -/obj/item/organ/external/proc/get_icon() +/obj/item/organ/external/head/on_remove_effects(mob/living/last_owner) update_icon() - return mob_icon + if(last_owner) + SetName("[last_owner.real_name]'s head") + addtimer(CALLBACK(last_owner, TYPE_PROC_REF(/mob, update_hair)), 1, TIMER_UNIQUE) + return ..() -// Returns an image for use by the human health dolly HUD element. -// If the limb is in pain, it will be used as a minimum damage -// amount to represent the obfuscation of being in agonizing pain. +/obj/item/organ/external/set_organ_appearance_bodytype(decl/bodytype/new_bodytype, update_sprite_accessories = TRUE, skip_owner_update = FALSE) + . = ..() + if(.) + if(update_sprite_accessories) + sanitize_sprite_accessories(skip_update = TRUE) + _icon_cache_key = null + get_icon_for_bodytype() + update_icon() + if(owner && !skip_owner_update) + owner.update_body() + +/obj/item/organ/external/proc/update_limb_icon_file() + var/decl/bodytype/icon_bodytype = get_organ_appearance_bodytype() + if(!icon_bodytype) // This should not happen. + icon = initial(icon) + else if(limb_flags & ORGAN_FLAG_SKELETAL) + icon = icon_bodytype.get_skeletal_icon(owner) + else if(!BP_IS_PROSTHETIC(src) && (status & ORGAN_MUTATED)) + icon = icon_bodytype.get_base_icon(owner, get_deform = TRUE) + else + icon = icon_bodytype.get_base_icon(owner) + +var/global/list/organ_icon_cache = list() +/obj/item/organ/external/proc/generate_mob_icon() + + // Generate base icon with colour and tone. + var/decl/bodytype/icon_bodytype = get_organ_appearance_bodytype() + var/icon/ret = icon_bodytype.apply_limb_colouration(src, new /icon(icon, icon_state)) + if(limb_flags & ORGAN_FLAG_SKELETAL) + global.organ_icon_cache[_icon_cache_key] = ret + return ret + + if((status & ORGAN_DEAD)) + ret.ColorTone(rgb(10,50,0)) + ret.SetIntensity(0.7) + + if(skin_tone) + if(skin_tone >= 0) + ret.Blend(rgb(skin_tone, skin_tone, skin_tone), ICON_ADD) + else + ret.Blend(rgb(-skin_tone, -skin_tone, -skin_tone), ICON_SUBTRACT) + + if((icon_bodytype.appearance_flags & HAS_SKIN_COLOR) && skin_colour) + ret.Blend(skin_colour, skin_blend) + + // Body markings, hair, lips, etc. + for(var/accessory_category in _sprite_accessories) + var/list/draw_accessories = _sprite_accessories[accessory_category] + for(var/accessory in draw_accessories) + var/decl/sprite_accessory/accessory_decl = resolve_accessory_to_decl(accessory) + if(!istype(accessory_decl)) + continue + if(!isnull(accessory_decl.sprite_overlay_layer) || !accessory_decl.draw_accessory) + continue + ret.Blend(accessory_decl.get_cached_accessory_icon(src, draw_accessories[accessory]), accessory_decl.layer_blend) + if(render_alpha < 255) + ret += rgb(,,,render_alpha) + global.organ_icon_cache[_icon_cache_key] = ret + return ret + +/obj/item/organ/external/proc/get_limb_mob_overlays() + for(var/accessory_category in _sprite_accessories) + var/list/draw_accessories = _sprite_accessories[accessory_category] + for(var/accessory in draw_accessories) + var/decl/sprite_accessory/accessory_decl = resolve_accessory_to_decl(accessory) + if(!istype(accessory_decl)) + continue + if(isnull(accessory_decl.sprite_overlay_layer) || !accessory_decl.draw_accessory) + continue + var/image/accessory_image = image(accessory_decl.get_cached_accessory_icon(src, draw_accessories[accessory])) + if(accessory_decl.sprite_overlay_layer != FLOAT_LAYER) + accessory_image.layer = accessory_decl.sprite_overlay_layer + if(accessory_decl.sprite_overlay_plane) + accessory_image.plane = accessory_decl.sprite_overlay_plane + if(accessory_decl.layer_blend != ICON_OVERLAY) + accessory_image.blend_mode = iconMode2blendMode(accessory_decl.layer_blend) + LAZYADD(., accessory_image) + +/obj/item/organ/external/proc/get_icon_cache_key_components() + + . = list("[icon_state]_[species.uid]_[get_organ_appearance_bodytype()?.uid || "BAD_BODYTYPE"]_[render_alpha]_[icon]") + + // Skeletons don't care about most icon appearance stuff. + if(limb_flags & ORGAN_FLAG_SKELETAL) + . += "_skeletal_[skin_blend]" + return + + if(status & ORGAN_DEAD) + . += "_dead" + . += "_tone_[skin_tone]_color_[skin_colour]_[skin_blend]" + for(var/accessory_category in _sprite_accessories) + var/list/draw_accessories = _sprite_accessories[accessory_category] + for(var/accessory in draw_accessories) + var/decl/sprite_accessory/accessory_decl = resolve_accessory_to_decl(accessory) + if(istype(accessory_decl) && !accessory_decl.sprite_overlay_layer) + . += "_[accessory]_[json_encode(draw_accessories[accessory])]" + +/obj/item/organ/external/proc/clear_sprite_accessories(var/skip_update = FALSE) + if(!length(_sprite_accessories)) + return + LAZYCLEARLIST(_sprite_accessories) + if(!skip_update) + if(owner) + owner.update_body() + update_icon() + +/obj/item/organ/external/proc/clear_sprite_accessories_by_category(var/accessory_category, var/skip_update = FALSE) + var/list/category_accessories = get_sprite_accessories_by_category(accessory_category) + category_accessories?.Cut() + _sprite_accessories?[accessory_category] = null + if(skip_update) + return + owner?.update_body(update_icons = TRUE) + +/obj/item/organ/external/proc/get_sprite_accessories_by_category(var/accessory_category) + return LAZYACCESS(_sprite_accessories, accessory_category) + +/obj/item/organ/external/proc/get_sprite_accessory_categories() + . = list() + for(var/category_type in _sprite_accessories) + . += GET_DECL(category_type) + +/obj/item/organ/external/proc/get_sprite_accessory_by_category(var/accessory_category) + var/list/accessories = get_sprite_accessories_by_category(accessory_category) + if(length(accessories)) + return accessories[1] + +/obj/item/organ/external/proc/get_sprite_accessory_metadata(var/accessory_type, var/metadata_tag) + var/decl/sprite_accessory/accessory = GET_DECL(accessory_type) + var/list/accessories = istype(accessory) && LAZYACCESS(_sprite_accessories, accessory.accessory_category) + if(accessories) + var/list/metadata = accessories[accessory_type] || accessory.get_default_accessory_metadata() + if(islist(metadata) && metadata_tag) + metadata = metadata[metadata_tag] + return islist(metadata) ? metadata.Copy() : metadata + +/obj/item/organ/external/proc/set_sprite_accessory(var/accessory_type, var/accessory_category, var/accessory_metadata, var/skip_update = FALSE) + + var/decl/sprite_accessory/accessory_decl = GET_DECL(accessory_type) + if(!accessory_category) + if(!accessory_decl) + return FALSE + accessory_category = accessory_decl.accessory_category + + var/decl/sprite_accessory_category/accessory_cat_decl = GET_DECL(accessory_category) + + var/list/accessories = LAZYACCESS(_sprite_accessories, accessory_category) + if(!accessories) + accessories = list() + LAZYSET(_sprite_accessories, accessory_category, accessories) + + if(!accessory_type) + var/decl/sprite_accessory_category/accessory_cat = GET_DECL(accessory_category) + accessory_type = accessory_cat?.default_accessory + if(!accessory_type) + return FALSE + accessory_decl = GET_DECL(accessory_type) + + var/list/refresh_accessories + if(accessory_metadata) + if(!accessory_decl.accessory_is_available(owner, species, get_organ_appearance_bodytype(), (owner ? owner.get_traits() : FALSE))) + return FALSE + var/list/existing_metadata = LAZYACCESS(accessories, accessory_type) + if(same_entries(existing_metadata, accessory_metadata)) + return FALSE + if(accessory_cat_decl.single_selection) + LAZYDISTINCTADD(refresh_accessories, accessories) + accessories.Cut() + LAZYSET(accessories, accessory_type, accessory_decl.update_metadata(accessory_metadata, existing_metadata)) + LAZYDISTINCTADD(refresh_accessories, accessory_decl) + else + if(!(accessory_type in accessories)) + return FALSE + remove_sprite_accessory(accessory_type, TRUE) + + if(!skip_update) + if(owner && length(refresh_accessories)) + for(var/refresh_accessory_type in refresh_accessories) + var/decl/sprite_accessory/refresh_accessory = GET_DECL(refresh_accessory_type) + if(refresh_accessory) + refresh_accessory.refresh_mob(owner) + update_icon() + return TRUE + +/obj/item/organ/external/proc/get_heritable_sprite_accessories() + for(var/accessory_category in _sprite_accessories) + var/list/draw_accessories = _sprite_accessories[accessory_category] + for(var/accessory in draw_accessories) + var/decl/sprite_accessory/accessory_decl = GET_DECL(accessory) + if(accessory_decl?.is_heritable) + LAZYSET(., accessory, draw_accessories[accessory]) + +/obj/item/organ/external/proc/set_sprite_accessory_by_category(accessory_type, accessory_category, accessory_metadata, preserve_colour = TRUE, preserve_type = TRUE, skip_update) + if(!accessory_category) + return FALSE + if(istype(accessory_type, /decl/sprite_accessory)) + var/decl/accessory_decl = accessory_type + accessory_type = accessory_decl.type + + // If there is a pre-existing sprite accessory to replace, we may want to keep the old colour value. + var/replacing_type = get_sprite_accessory_by_category(accessory_category) + if(replacing_type) + + if(preserve_colour && !accessory_metadata) + accessory_metadata = get_sprite_accessory_metadata(replacing_type) + + // We may only be setting colour, in which case we don't bother with a removal. + if(preserve_type && !accessory_type) + accessory_type = replacing_type + else if (accessory_type != replacing_type) + remove_sprite_accessory(replacing_type, TRUE) + + // We have already done our removal above and have nothing further to set below. + if(!accessory_metadata && !accessory_type) + if(!skip_update) + if(owner) + var/decl/sprite_accessory/refresh_accessory = GET_DECL(replacing_type || accessory_category) + if(refresh_accessory) + refresh_accessory.refresh_mob(owner) + update_icon() + return TRUE + + // We need to now set a replacement accessory type down the chain. + return set_sprite_accessory(accessory_type, accessory_category, accessory_metadata, skip_update) + +/obj/item/organ/external/proc/remove_sprite_accessory(var/accessory_type, var/skip_update = FALSE) + if(!accessory_type) + return + var/decl/sprite_accessory/removing_accessory = GET_DECL(accessory_type) + var/list/removing = LAZYACCESS(_sprite_accessories, removing_accessory.accessory_category) + if(!LAZYLEN(removing)) + return + LAZYREMOVE(removing, accessory_type) + if(!length(removing)) + LAZYREMOVE(_sprite_accessories, removing_accessory.accessory_category) + if(!skip_update) + if(owner && removing_accessory) + removing_accessory.refresh_mob(owner) + update_icon() + +/obj/item/organ/external/on_update_icon() + . = ..() + + if(!istext(organ_tag)) // how?? this happened on Scav in relation to runtimes in update_limb_icon_file() so might be unneeded with that fixed + return + + // Update our cache key and refresh or create our base icon. + var/next_state = owner ? "[organ_tag][owner.get_overlay_state_modifier()]" : organ_tag + update_limb_icon_file() + if(icon_state != next_state) + icon_state = next_state + + _icon_cache_key = jointext(get_icon_cache_key_components(), null) + var/icon/mob_icon = global.organ_icon_cache[_icon_cache_key] || generate_mob_icon() + if(icon != mob_icon) + icon = mob_icon + + // We may have some overlays of our own (hair, glowing eyes, layered markings) + var/list/additional_overlays = get_limb_mob_overlays() + if(length(additional_overlays)) + for(var/new_overlay in additional_overlays) + add_overlay(new_overlay) + + // If we've been severed, we may contain child organs that should be rendered (feet on legs etc). + if(!owner && length(contents)) + for(var/obj/item/organ/external/child in contents) + child.update_icon() + child.compile_overlays() // We need the appearance immediately. + add_overlay(child) // Global scope, used in code below. -var/list/flesh_hud_colours = list("#00ff00","#aaff00","#ffff00","#ffaa00","#ff0000","#aa0000","#660000") -var/list/robot_hud_colours = list("#ffffff","#cccccc","#aaaaaa","#888888","#666666","#444444","#222222","#000000") +var/global/list/flesh_hud_colours = list("#00ff00","#aaff00","#ffff00","#ffaa00","#ff0000","#aa0000","#660000") +var/global/list/robot_hud_colours = list("#ffffff","#cccccc","#aaaaaa","#888888","#666666","#444444","#222222","#000000") +// Returns an image for use by the human health dolly HUD element. +// If the limb is in pain, it will be used as a minimum damage +// amount to represent the obfuscation of being in agonizing pain. /obj/item/organ/external/proc/get_damage_hud_image() + if(skip_body_icon_draw) + return null + // Generate the greyscale base icon and cache it for later. - // icon_cache_key is set by any get_icon() calls that are made. + // _icon_cache_key is set by any get_icon() calls that are made. // This looks convoluted, but it's this way to avoid icon proc calls. if(!hud_damage_image) - var/cache_key = "dambase-[icon_cache_key]" - if(!icon_cache_key || !limb_icon_cache[cache_key]) - limb_icon_cache[cache_key] = icon(get_icon(), null, SOUTH) + update_icon() + var/cache_key = "dambase-[_icon_cache_key]" + if(!cache_key || !limb_icon_cache[cache_key]) + limb_icon_cache[cache_key] = icon(icon, null, SOUTH) var/image/temp = image(limb_icon_cache[cache_key]) if(species) // Calculate the required colour matrix. - var/r = 0.30 * species.health_hud_intensity - var/g = 0.59 * species.health_hud_intensity - var/b = 0.11 * species.health_hud_intensity + var/hud_intensity = get_organ_appearance_bodytype()?.health_hud_intensity || 1 + var/r = 0.30 * hud_intensity + var/g = 0.59 * hud_intensity + var/b = 0.11 * hud_intensity temp.color = list(r, r, r, g, g, g, b, b, b) temp.pixel_x = owner.default_pixel_x temp.pixel_y = owner.default_pixel_y @@ -165,36 +362,8 @@ var/list/robot_hud_colours = list("#ffffff","#cccccc","#aaaaaa","#888888","#6666 hud_damage_image.color = hud_colours[max(1,min(ceil(dam_state*hud_colours.len),hud_colours.len))] return hud_damage_image -/obj/item/organ/external/proc/apply_colouration(var/icon/applying) - - if(species.limbs_are_nonsolid) - applying.MapColors("#4d4d4d","#969696","#1c1c1c", "#000000") - if(species) - applying.SetIntensity(species.limb_icon_intensity) - else - applying.SetIntensity(0.7) - applying += rgb(,,,180) // Makes the icon translucent, SO INTUITIVE TY BYOND - - else if(status & ORGAN_DEAD) - icon_cache_key += "_dead" - applying.ColorTone(rgb(10,50,0)) - applying.SetIntensity(0.7) - - if(skin_tone) - if(skin_tone >= 0) - applying.Blend(rgb(skin_tone, skin_tone, skin_tone), ICON_ADD) - else - applying.Blend(rgb(-skin_tone, -skin_tone, -skin_tone), ICON_SUBTRACT) - icon_cache_key += "_tone_[skin_tone]" - if(species.appearance_flags & HAS_SKIN_COLOR) - if(skin_colour) - applying.Blend(skin_colour, skin_blend) - icon_cache_key += "_color_[skin_colour]_[skin_blend]" - - return applying - /obj/item/organ/external/proc/bandage_level() - if(damage_state_text() == "00") + if(damage_state_text() == "00") return 0 if(!is_bandaged()) return 0 @@ -205,4 +374,27 @@ var/list/robot_hud_colours = list("#ffffff","#cccccc","#aaaaaa","#888888","#6666 else if (burn_dam + brute_dam < (max_damage * 0.75 / 2)) . = 2 else - . = 3 \ No newline at end of file + . = 3 + +/obj/item/organ/external/proc/resolve_accessory_to_decl(var/decl/sprite_accessory/accessory_style) + if(ispath(accessory_style)) + accessory_style = GET_DECL(accessory_style) + // Check if this style is permitted for this species, period. + if(!istype(accessory_style) || !accessory_style?.accessory_is_available(owner, species, get_organ_appearance_bodytype(), (owner ? owner.get_traits() : FALSE))) + return null + // Check if we are concealed (long hair under a hat for example). + if(accessory_style.is_hidden(src)) + return accessory_style.get_hidden_substitute() + return accessory_style + +/obj/item/organ/external/proc/sanitize_sprite_accessories(var/skip_update = FALSE) + for(var/acc_cat in _sprite_accessories) + for(var/accessory in _sprite_accessories[acc_cat]) + var/decl/sprite_accessory/accessory_style = GET_DECL(accessory) + if(!istype(accessory_style) || !accessory_style?.accessory_is_available(owner, species, get_organ_appearance_bodytype(), (owner ? owner.get_traits() : FALSE))) + _sprite_accessories[acc_cat] -= accessory + . = TRUE + if(.) + _icon_cache_key = null + if(!skip_update) + update_icon() diff --git a/code/modules/organs/external/diagnostics.dm b/code/modules/organs/external/diagnostics.dm index 4ddee281e585..d7047a14aa82 100644 --- a/code/modules/organs/external/diagnostics.dm +++ b/code/modules/organs/external/diagnostics.dm @@ -23,32 +23,32 @@ return english_list(descriptors) var/list/flavor_text = list() - if((status & ORGAN_CUT_AWAY) && !is_stump() && !(parent && parent.status & ORGAN_CUT_AWAY)) + if((status & ORGAN_CUT_AWAY) && !(parent && parent.status & ORGAN_CUT_AWAY)) flavor_text += "a tear at the [amputation_point] so severe that it hangs by a scrap of flesh" var/list/wound_descriptors = list() - for(var/datum/wound/W in wounds) - var/this_wound_desc = W.desc - if(W.damage_type == BURN && W.salved) + for(var/datum/wound/wound in wounds) + var/this_wound_desc = wound.desc + if(wound.damage_type == BURN && wound.salved) this_wound_desc = "salved [this_wound_desc]" - if(W.bleeding()) - if(W.wound_damage() > W.bleed_threshold) + if(wound.bleeding()) + if(wound.wound_damage() > wound.bleed_threshold) this_wound_desc = "bleeding [this_wound_desc]" else this_wound_desc = "bleeding [this_wound_desc]" - else if(W.bandaged) + else if(wound.bandaged) this_wound_desc = "bandaged [this_wound_desc]" - if(W.germ_level > 600) + if(wound.germ_level > 600) this_wound_desc = "badly infected [this_wound_desc]" - else if(W.germ_level > 330) + else if(wound.germ_level > 330) this_wound_desc = "lightly infected [this_wound_desc]" if(wound_descriptors[this_wound_desc]) - wound_descriptors[this_wound_desc] += W.amount + wound_descriptors[this_wound_desc] += wound.amount else - wound_descriptors[this_wound_desc] = W.amount + wound_descriptors[this_wound_desc] = wound.amount if(how_open() >= SURGERY_RETRACTED) var/bone = encased ? encased : "bone" @@ -84,15 +84,17 @@ . += "[capitalize(artery_name)] ruptured" if(status & ORGAN_TENDON_CUT) . += "Severed [tendon_name]" - if(dislocated == 2) // non-magical constants when + if(is_dislocated()) . += "Dislocated" if(splinted) . += "Splinted" if(status & ORGAN_BLEEDING) . += "Bleeding" + if(limb_flags & ORGAN_FLAG_SKELETAL) + . += "Skeletal" if(status & ORGAN_BROKEN) . += capitalize(broken_description) - if (implants.len) + if (LAZYLEN(implants)) var/unknown_body = 0 for(var/I in implants) var/obj/item/implant/imp = I @@ -105,16 +107,21 @@ unknown_body++ if(unknown_body) . += "Unknown body present" - for(var/obj/item/organ/internal/augment/aug in internal_organs) - if(istype(aug) && aug.known) - . += "[capitalize(aug.name)] implanted" + var/obj/item/organ/internal/lungs/L = locate() in src + if( L && L.is_bruised()) + . += "Lung ruptured" /obj/item/organ/external/proc/inspect(mob/user) - if(is_stump()) - to_chat(user, "[owner] is missing that bodypart.") - return user.visible_message("[user] starts inspecting [owner]'s [name] carefully.") + for(var/ailment in has_diagnosable_ailments(user, scanner = FALSE)) + if(!do_mob(user, owner, 5)) + return + to_chat(user, SPAN_NOTICE(ailment)) + + if(!do_mob(user, owner, 5)) + return + if(LAZYLEN(wounds)) to_chat(user, "You find [get_wounds_desc()]") var/list/stuff = list() @@ -126,7 +133,7 @@ else to_chat(user, "You find no visible wounds.") - to_chat(user, "Checking skin now...") + to_chat(user, "You start checking [owner]'s skin...") if(!do_mob(user, owner, 10)) to_chat(user, "You must stand still to check [owner]'s skin for abnormalities.") return @@ -142,20 +149,20 @@ else to_chat(user, "[owner]'s skin is [english_list(badness)].") - to_chat(user, "Checking bones now...") + to_chat(user, "You start checking [owner]'s bones...") if(!do_mob(user, owner, 10)) to_chat(user, "You must stand still to feel [src] for fractures.") return if(status & ORGAN_BROKEN) - to_chat(user, "The [encased ? encased : "bone in the [name]"] moves slightly when you poke it!") + to_chat(user, "The [encased ? encased : "bone in \the [src]"] moves slightly when you poke it!") owner.custom_pain("Your [name] hurts where it's poked.",40, affecting = src) else - to_chat(user, "The [encased ? encased : "bones in the [name]"] seem to be fine.") + to_chat(user, "The [encased ? encased : "bones in \the [src]"] seem to be fine.") if(status & ORGAN_TENDON_CUT) to_chat(user, "The tendons in [name] are severed!") - if(dislocated == 2) + if(is_dislocated()) to_chat(user, "The [joint] is dislocated!") return 1 @@ -166,7 +173,7 @@ if(gutsound) sounds += gutsound if(!sounds.len) - if(owner.pulse()) + if(owner.get_pulse()) sounds += "faint pulse" return sounds @@ -182,7 +189,7 @@ /decl/diagnostic_sign/proc/get_description(mob/user) . = descriptor if(user && user.skill_check(SKILL_MEDICAL, hint_min_skill)) - . += "(?)" + . += "(?)" /decl/diagnostic_sign/Topic(var/href, var/list/href_list) . = ..() @@ -206,7 +213,7 @@ explanation = "Patient has internal organ damage." /decl/diagnostic_sign/liver/manifested_in(obj/item/organ/external/victim) - return victim.owner && victim.owner.getToxLoss() >= 25 + return victim.owner && victim.owner.get_damage(TOX) >= 25 /decl/diagnostic_sign/oxygenation name = "Cyanosis" diff --git a/code/modules/organs/external/head.dm b/code/modules/organs/external/head.dm index 111859fd4e1b..4b1886424b9f 100644 --- a/code/modules/organs/external/head.dm +++ b/code/modules/organs/external/head.dm @@ -1,45 +1,63 @@ /obj/item/organ/external/head organ_tag = BP_HEAD - icon_name = "head" name = "head" - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY max_damage = 75 min_broken_damage = 35 w_class = ITEM_SIZE_NORMAL cavity_max_w_class = ITEM_SIZE_SMALL - body_part = HEAD + body_part = SLOT_HEAD parent_organ = BP_CHEST joint = "jaw" amputation_point = "neck" encased = "skull" - artery_name = "cartoid artery" - cavity_name = "cranial" + artery_name = "carotid artery" + cavity_name = "cranial cavity" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_GENDERED_ICON | ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK - - var/draw_eyes = TRUE var/glowing_eyes = FALSE - var/can_intake_reagents = 1 - var/has_lips = 1 + var/can_intake_reagents = TRUE var/forehead_graffiti var/graffiti_style -/obj/item/organ/external/head/proc/get_eye_overlay() - if(glowing_eyes || (owner && owner.chem_effects[CE_GLOWINGEYES])) - var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[owner.species.vision_organ ? owner.species.vision_organ : BP_EYES] - if(eyes) - return eyes.get_special_overlay() +/obj/item/organ/external/head/get_natural_attacks() + if(!can_intake_reagents) + return null + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite) + return unarmed_attack + +/obj/item/organ/external/head/sharp_bite/get_natural_attacks() + if(!can_intake_reagents) + return null + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/sharp) + return unarmed_attack + +/obj/item/organ/external/head/strong_bite/get_natural_attacks() + if(!can_intake_reagents) + return null + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/strong) + return unarmed_attack + +/obj/item/organ/external/head/proc/get_organ_eyes_overlay() + if(!glowing_eyes && !owner?.has_chemical_effect(CE_GLOWINGEYES, 1)) + return + var/obj/item/organ/internal/eyes/eyes = get_eyes_organ() + var/icon/eyes_icon = eyes?.get_onhead_icon() // refreshes cache key + if(!eyes_icon) + return + var/cache_key = "[eyes.last_eye_cache_key]-glow" + if(!global.eye_icon_cache[cache_key]) + global.eye_icon_cache[cache_key] = emissive_overlay(eyes_icon, "") + return global.eye_icon_cache[cache_key] -/obj/item/organ/external/head/proc/get_eyes() - var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[owner.species.vision_organ ? owner.species.vision_organ : BP_EYES] - if(eyes) - return eyes.get_onhead_icon() +// Let people with mouth slots pick things up. +/obj/item/organ/external/head/get_manual_dexterity() + . = DEXTERITY_SIMPLE_MACHINES | DEXTERITY_HOLD_ITEM | DEXTERITY_EQUIP_ITEM | DEXTERITY_KEYBOARDS | DEXTERITY_TOUCHSCREENS -/obj/item/organ/external/head/examine(mob/user) +/obj/item/organ/external/head/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(forehead_graffiti && graffiti_style) - to_chat(user, "It has \"[forehead_graffiti]\" written on it in [graffiti_style]!") + . += SPAN_NOTICE("It has \"[forehead_graffiti]\" written on it in [graffiti_style]!") /obj/item/organ/external/head/proc/write_on(var/mob/penman, var/style) var/head_name = name @@ -52,7 +70,7 @@ to_chat(penman, "There is no room left to write on [head_name]!") return - var/graffiti = sanitizeSafe(input(penman, "Enter a message to write on [head_name]:") as text|null, MAX_NAME_LEN) + var/graffiti = sanitize_safe(input(penman, "Enter a message to write on [head_name]:") as text|null, MAX_NAME_LEN) if(graffiti) if(!target.Adjacent(penman)) to_chat(penman, "[head_name] is too far away.") @@ -76,92 +94,48 @@ /obj/item/organ/external/head/get_agony_multiplier() return (owner && owner.headcheck(organ_tag)) ? 1.50 : 1 -/obj/item/organ/external/head/robotize(var/company, var/skip_prosthetics, var/keep_organs) - if(company) - var/datum/robolimb/R = all_robolimbs[company] - if(R) - can_intake_reagents = R.can_eat - draw_eyes = R.has_eyes - . = ..(company, skip_prosthetics, 1) - has_lips = null +/obj/item/organ/external/head/set_bodytype(decl/bodytype/new_bodytype, override_material = null, apply_to_internal_organs = TRUE) + . = ..() + can_intake_reagents = !(bodytype.body_flags & BODY_FLAG_NO_EAT) -/obj/item/organ/external/head/take_external_damage(brute, burn, damage_flags, used_weapon = null) +/obj/item/organ/external/head/take_damage(damage, damage_type, damage_flags, inflicter, armor_pen, silent, do_update_health, override_droplimb) . = ..() if (!(status & ORGAN_DISFIGURED)) if (brute_dam > 40) if (prob(50)) - disfigure("brute") + disfigure(BRUTE) if (burn_dam > 40) - disfigure("burn") + disfigure(BURN) + +/obj/item/organ/external/head/proc/get_eyes_organ() + RETURN_TYPE(/obj/item/organ/internal/eyes) + if(owner) + return owner.get_organ((owner.get_vision_organ_tag() || BP_EYES), /obj/item/organ/internal/eyes) + return locate(/obj/item/organ/internal/eyes) in contents -/obj/item/organ/external/head/on_update_icon() +/obj/item/organ/external/head/get_icon_cache_key_components() + . = ..() + . += "_eyes_[bodytype.eye_icon || "none"]_[get_eyes_organ()?.eye_colour || "none"]" - ..() +/obj/item/organ/external/head/generate_mob_icon() + var/icon/ret = ..() + if(ret) + var/icon/eyes_icon = get_eyes_organ()?.get_onhead_icon() + if(eyes_icon) + ret.Blend(eyes_icon, ICON_OVERLAY) + return ret - if(owner) - // Base eye icon. - if(draw_eyes) - var/icon/I = get_eyes() - if(I) - overlays |= I - mob_icon.Blend(I, ICON_OVERLAY) - - // Floating eyes or other effects. - var/image/eye_glow = get_eye_overlay() - if(eye_glow) overlays |= eye_glow - - if(owner.lip_style && !BP_IS_PROSTHETIC(src) && (species && (species.appearance_flags & HAS_LIPS))) - var/icon/lip_icon = new/icon(species?.lip_icon || 'icons/mob/human_races/species/lips.dmi', "lipstick_s") - lip_icon.Blend(owner.lip_style, ICON_MULTIPLY) - overlays |= lip_icon - mob_icon.Blend(lip_icon, ICON_OVERLAY) - - overlays |= get_hair_icon() - - return mob_icon - -/obj/item/organ/external/head/proc/get_hair_icon() - var/image/res = image(species.icon_template,"") - if(owner.f_style) - var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hair_styles_list[owner.f_style] - if(facial_hair_style) - if(!facial_hair_style.species_allowed || (species.get_root_species_name(owner) in facial_hair_style.species_allowed)) - if(!facial_hair_style.subspecies_allowed || (species.name in facial_hair_style.subspecies_allowed)) - var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - if(owner.facial_hair_colour && facial_hair_style.do_colouration) - facial_s.Blend(owner.facial_hair_colour, facial_hair_style.blend) - res.overlays |= facial_s - - if(owner.h_style) - var/style = owner.h_style - var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_list[style] - if(owner.head && (owner.head.flags_inv & BLOCKHEADHAIR)) - if(!(hair_style.flags & VERY_SHORT)) - hair_style = GLOB.hair_styles_list["Short Hair"] - if(hair_style) - if(!hair_style.species_allowed || (species.get_root_species_name(owner) in hair_style.species_allowed)) - if(!hair_style.subspecies_allowed || (species.name in hair_style.subspecies_allowed)) - var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") - if(hair_style.do_colouration && hair_colour) - hair_s.Blend(hair_colour, hair_style.blend) - res.overlays |= hair_s - - for (var/M in markings) - var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] - if (mark_style.draw_target == MARKING_TARGET_HAIR) - var/icon/mark_icon = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]") - if (!mark_style.do_colouration && owner.h_style) - var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_list[owner.h_style] - if ((~hair_style.flags & HAIR_BALD) && hair_colour) - mark_icon.Blend(hair_colour, ICON_ADD) - else //only baseline human skin tones; others will need species vars for coloration - mark_icon.Blend(rgb(200 + skin_tone, 150 + skin_tone, 123 + skin_tone), ICON_ADD) - else - mark_icon.Blend(markings[M]["color"], ICON_ADD) - res.overlays |= mark_icon - icon_cache_key += "[M][markings[M]["color"]]" - - return res - -/obj/item/organ/external/head/no_eyes - draw_eyes = FALSE +/obj/item/organ/external/head/get_limb_mob_overlays() + . = ..() + var/image/eye_glow = get_organ_eyes_overlay() + if(eye_glow) + LAZYADD(., eye_glow) + +/obj/item/organ/external/head/gripper/do_install(mob/living/human/target, affected, in_place, update_icon, detached) + . = ..() + if(. && owner) + owner.add_held_item_slot(new /datum/inventory_slot/gripper/mouth) + +/obj/item/organ/external/head/gripper/do_uninstall(in_place, detach, ignore_children, update_icon) + owner?.remove_held_item_slot(BP_MOUTH) + . = ..() diff --git a/code/modules/organs/external/insectoid.dm b/code/modules/organs/external/insectoid.dm new file mode 100644 index 000000000000..b139a06b4567 --- /dev/null +++ b/code/modules/organs/external/insectoid.dm @@ -0,0 +1,78 @@ +/obj/item/organ/external/arm/insectoid + name = "left forelimb" + amputation_point = "coxa" + icon_position = LEFT + encased = "carapace" + +/obj/item/organ/external/arm/right/insectoid + name = "right forelimb" + amputation_point = "coxa" + icon_position = RIGHT + encased = "carapace" + +/obj/item/organ/external/leg/insectoid + encased = "carapace" + +/obj/item/organ/external/leg/right/insectoid + encased = "carapace" + +/obj/item/organ/external/foot/insectoid + encased = "carapace" + +/obj/item/organ/external/foot/right/insectoid + encased = "carapace" + +/obj/item/organ/external/hand/insectoid + name = "left grasper" + icon_position = LEFT + encased = "carapace" + +/obj/item/organ/external/hand/right/insectoid + name = "right grasper" + icon_position = RIGHT + encased = "carapace" + +/obj/item/organ/external/groin/insectoid + name = "abdomen" + icon_position = UNDER + encased = "carapace" + +/obj/item/organ/external/head/insectoid + name = "head" + encased = "carapace" + +/obj/item/organ/external/chest/insectoid + name = "thorax" + encased = "carapace" + +/obj/item/organ/external/hand/insectoid/midlimb + name = "central grasper" + joint = "central wrist" + organ_tag = BP_M_HAND + parent_organ = BP_CHEST + amputation_point = "central wrist" + icon_position = 0 + encased = "carapace" + gripper_type = /datum/inventory_slot/gripper/midlimb + +/obj/item/organ/external/hand/insectoid/upper + name = "left raptorial" + joint = "upper left wrist" + amputation_point = "upper left shoulder" + organ_tag = BP_L_HAND_UPPER + parent_organ = BP_CHEST + gripper_type = /datum/inventory_slot/gripper/upper_left_hand + +/obj/item/organ/external/hand/insectoid/upper/get_manual_dexterity() + return (..() & ~(DEXTERITY_WEAPONS|DEXTERITY_COMPLEX_TOOLS)) + +/obj/item/organ/external/hand/right/insectoid/upper + name = "right raptorial" + joint = "upper right wrist" + amputation_point = "upper right shoulder" + organ_tag = BP_R_HAND_UPPER + parent_organ = BP_CHEST + gripper_type = /datum/inventory_slot/gripper/upper_right_hand + +/obj/item/organ/external/hand/right/insectoid/upper/get_manual_dexterity() + return (..() & ~(DEXTERITY_WEAPONS|DEXTERITY_COMPLEX_TOOLS)) diff --git a/code/modules/organs/external/quadruped.dm b/code/modules/organs/external/quadruped.dm new file mode 100644 index 000000000000..5ea0d59dde9c --- /dev/null +++ b/code/modules/organs/external/quadruped.dm @@ -0,0 +1,51 @@ +/obj/item/organ/external/leg/quadruped + name = "left hindleg" + joint = "rear left knee" + +/obj/item/organ/external/leg/right/quadruped + name = "right hindleg" + joint = "rear right knee" + +/obj/item/organ/external/foot/quadruped + name = "left hindpaw" + joint = "rear left ankle" + +/obj/item/organ/external/foot/right/quadruped + name = "right hindpaw" + joint = "rear right ankle" + +/obj/item/organ/external/arm/quadruped + name = "left foreleg" + joint = "front left knee" + amputation_point = "front left knee" + tendon_name = "cruciate ligament" + artery_name = "femoral artery" + organ_categories = @"['" + ORGAN_CATEGORY_STANCE_ROOT + "']" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + +/obj/item/organ/external/arm/right/quadruped + name = "right foreleg" + joint = "front right knee" + amputation_point = "front right knee" + tendon_name = "cruciate ligament" + artery_name = "femoral artery" + organ_categories = @"['" + ORGAN_CATEGORY_STANCE_ROOT + "']" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + +/obj/item/organ/external/hand/quadruped + name = "left forepaw" + joint = "front left ankle" + amputation_point = "front left ankle" + tendon_name = "Achilles tendon" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + organ_categories = @"['" + ORGAN_CATEGORY_STANCE + "']" + gripper_type = null + +/obj/item/organ/external/hand/right/quadruped + name = "right forepaw" + joint = "front right ankle" + amputation_point = "front right ankle" + tendon_name = "Achilles tendon" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + organ_categories = @"['" + ORGAN_CATEGORY_STANCE + "']" + gripper_type = null diff --git a/code/modules/organs/external/standard.dm b/code/modules/organs/external/standard.dm index be8af71281da..570c39460722 100644 --- a/code/modules/organs/external/standard.dm +++ b/code/modules/organs/external/standard.dm @@ -7,88 +7,76 @@ /obj/item/organ/external/chest name = "upper body" organ_tag = BP_CHEST - icon_name = "torso" max_damage = 100 min_broken_damage = 35 w_class = ITEM_SIZE_HUGE //Used for dismembering thresholds, in addition to storage. Humans are w_class 6, so it makes sense that chest is w_class 5. cavity_max_w_class = ITEM_SIZE_NORMAL - body_part = UPPER_TORSO - vital = 1 + body_part = SLOT_UPPER_BODY amputation_point = "spine" joint = "neck" - dislocated = -1 parent_organ = null encased = "ribcage" artery_name = "aorta" - cavity_name = "thoracic" - limb_flags = ORGAN_FLAG_GENDERED_ICON | ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK - can_be_printed = FALSE + cavity_name = "thoracic cavity" + limb_flags = ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK -/obj/item/organ/external/chest/proc/get_current_skin() - return - -/obj/item/organ/external/chest/robotize() - if(..()) - // Give them a new cell. - var/obj/item/organ/internal/cell/C = owner.internal_organs_by_name[BP_CELL] - if(!istype(C)) - owner.internal_organs_by_name[BP_CELL] = new /obj/item/organ/internal/cell(owner,1) - -/obj/item/organ/external/get_scan_results() +/obj/item/organ/external/chest/die() + //Special handling for synthetics + if(BP_IS_PROSTHETIC(src) || BP_IS_CRYSTAL(src)) + return . = ..() - var/obj/item/organ/internal/lungs/L = locate() in src - if( L && L.is_bruised()) - . += "Lung ruptured" /obj/item/organ/external/groin name = "lower body" organ_tag = BP_GROIN - icon_name = "groin" max_damage = 100 min_broken_damage = 35 w_class = ITEM_SIZE_LARGE cavity_max_w_class = ITEM_SIZE_SMALL - body_part = LOWER_TORSO + body_part = SLOT_LOWER_BODY parent_organ = BP_CHEST amputation_point = "lumbar" joint = "hip" - dislocated = -1 artery_name = "iliac artery" - cavity_name = "abdominal" - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_GENDERED_ICON | ORGAN_FLAG_CAN_BREAK + cavity_name = "abdominal cavity" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/groin/die() + //Special handling for synthetics + if(BP_IS_PROSTHETIC(src) || BP_IS_CRYSTAL(src)) + return + . = ..() /obj/item/organ/external/arm organ_tag = BP_L_ARM name = "left arm" - icon_name = "l_arm" max_damage = 50 min_broken_damage = 30 w_class = ITEM_SIZE_NORMAL - body_part = ARM_LEFT + body_part = SLOT_ARM_LEFT parent_organ = BP_CHEST joint = "left elbow" amputation_point = "left shoulder" tendon_name = "palmaris longus tendon" artery_name = "basilic vein" arterial_bleed_severity = 0.75 - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_GRASP | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + organ_categories = @"['" + ORGAN_CATEGORY_MANIPLE + "']" /obj/item/organ/external/arm/right organ_tag = BP_R_ARM name = "right arm" - icon_name = "r_arm" - body_part = ARM_RIGHT + body_part = SLOT_ARM_RIGHT joint = "right elbow" amputation_point = "right shoulder" /obj/item/organ/external/leg organ_tag = BP_L_LEG name = "left leg" - icon_name = "l_leg" max_damage = 50 min_broken_damage = 30 w_class = ITEM_SIZE_NORMAL - body_part = LEG_LEFT + body_part = SLOT_LEG_LEFT icon_position = LEFT parent_organ = BP_GROIN joint = "left knee" @@ -96,13 +84,13 @@ tendon_name = "cruciate ligament" artery_name = "femoral artery" arterial_bleed_severity = 0.75 - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK + organ_categories = @"['" + ORGAN_CATEGORY_STANCE_ROOT + "']" + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE /obj/item/organ/external/leg/right organ_tag = BP_R_LEG name = "right leg" - icon_name = "r_leg" - body_part = LEG_RIGHT + body_part = SLOT_LEG_RIGHT icon_position = RIGHT joint = "right knee" amputation_point = "right hip" @@ -110,24 +98,30 @@ /obj/item/organ/external/foot organ_tag = BP_L_FOOT name = "left foot" - icon_name = "l_foot" max_damage = 30 min_broken_damage = 15 w_class = ITEM_SIZE_SMALL - body_part = FOOT_LEFT + body_part = SLOT_FOOT_LEFT icon_position = LEFT parent_organ = BP_L_LEG joint = "left ankle" amputation_point = "left ankle" tendon_name = "Achilles tendon" arterial_bleed_severity = 0.5 - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + organ_categories = @"['" + ORGAN_CATEGORY_STANCE + "']" + +/obj/item/organ/external/foot/get_natural_attacks() + var/static/list/unarmed_attacks = list( + GET_DECL(/decl/natural_attack/stomp), + GET_DECL(/decl/natural_attack/kick) + ) + return unarmed_attacks /obj/item/organ/external/foot/right organ_tag = BP_R_FOOT name = "right foot" - icon_name = "r_foot" - body_part = FOOT_RIGHT + body_part = SLOT_FOOT_RIGHT icon_position = RIGHT parent_organ = BP_R_LEG joint = "right ankle" @@ -136,23 +130,49 @@ /obj/item/organ/external/hand organ_tag = BP_L_HAND name = "left hand" - icon_name = "l_hand" + icon_position = LEFT max_damage = 30 min_broken_damage = 15 w_class = ITEM_SIZE_SMALL - body_part = HAND_LEFT + body_part = SLOT_HAND_LEFT parent_organ = BP_L_ARM joint = "left wrist" amputation_point = "left wrist" tendon_name = "carpal ligament" arterial_bleed_severity = 0.5 - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_GRASP | ORGAN_FLAG_FINGERPRINT | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_FINGERPRINT | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + is_washable = TRUE + organ_categories = @"['" + ORGAN_CATEGORY_MANIPLE + "']" + var/gripper_type = /datum/inventory_slot/gripper/left_hand + +/obj/item/organ/external/hand/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/punch) + return unarmed_attack + +/obj/item/organ/external/hand/do_install(mob/living/human/target, affected, in_place, update_icon, detached) + . = ..() + if(. && owner && gripper_type) + owner.add_held_item_slot(new gripper_type) + +/obj/item/organ/external/hand/do_uninstall(in_place, detach, ignore_children, update_icon) + if(gripper_type) + owner?.remove_held_item_slot(organ_tag) + . = ..() /obj/item/organ/external/hand/right organ_tag = BP_R_HAND name = "right hand" - icon_name = "r_hand" - body_part = HAND_RIGHT + icon_position = RIGHT + body_part = SLOT_HAND_RIGHT parent_organ = BP_R_ARM joint = "right wrist" amputation_point = "right wrist" + gripper_type = /datum/inventory_slot/gripper/right_hand + +/obj/item/organ/external/hand/clawed/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws) + return unarmed_attack + +/obj/item/organ/external/hand/right/clawed/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws) + return unarmed_attack diff --git a/code/modules/organs/external/stump.dm b/code/modules/organs/external/stump.dm deleted file mode 100644 index 5180b2bc1edb..000000000000 --- a/code/modules/organs/external/stump.dm +++ /dev/null @@ -1,25 +0,0 @@ -/obj/item/organ/external/stump - name = "limb stump" - icon_name = "" - dislocated = -1 - -/obj/item/organ/external/stump/Initialize(mapload, var/internal, var/obj/item/organ/external/limb) - if(istype(limb)) - SetName("stump of \a [limb.name]") - organ_tag = limb.organ_tag - body_part = limb.body_part - amputation_point = limb.amputation_point - joint = limb.joint - parent_organ = limb.parent_organ - artery_name = "mangled [limb.artery_name]" - arterial_bleed_severity = limb.arterial_bleed_severity - . = ..(mapload, internal) - if(istype(limb)) - max_damage = limb.max_damage - if(BP_IS_PROSTHETIC(limb) && (!parent || BP_IS_PROSTHETIC(parent))) - robotize() //if both limb and the parent are robotic, the stump is robotic too - if(BP_IS_CRYSTAL(limb) && (!parent || BP_IS_CRYSTAL(parent))) - status |= ORGAN_CRYSTAL // Likewise with crystalline limbs. - -/obj/item/organ/external/stump/is_stump() - return 1 diff --git a/code/modules/organs/external/tail.dm b/code/modules/organs/external/tail.dm new file mode 100644 index 000000000000..656d6e533c6b --- /dev/null +++ b/code/modules/organs/external/tail.dm @@ -0,0 +1,127 @@ +/obj/item/organ/external/tail + + organ_tag = BP_TAIL + name = "tail" + max_damage = 20 + min_broken_damage = 10 + w_class = ITEM_SIZE_NORMAL + body_part = SLOT_TAIL + parent_organ = BP_GROIN + joint = "tail" + amputation_point = "tail" + artery_name = "vein" + arterial_bleed_severity = 0.3 + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE + skip_body_icon_draw = TRUE + force_limb_dir = WEST + + icon = 'icons/mob/human_races/species/default_tail.dmi' + icon_state = BP_TAIL + + /// Icon to use for tail states; separate to icon above because external organs generated a blended icon for themselves to replace it. + var/tail_icon = 'icons/mob/human_races/species/default_tail.dmi' + /// Blend mode for overlaying colour on the tail. + var/tail_blend = ICON_ADD + /// How many random tail states are available for animations. + var/tail_animation_states = 0 + /// If we have an animation playing, it will be this state. + var/tail_animation_state + /// Are we actively hiding our tail currently? + var/tail_hidden = FALSE + +/mob/living/proc/hide_tail() + set name = "Hide Tail" + set category = "IC" + set src = usr + + if(incapacitated()) + to_chat(usr, SPAN_WARNING("You are in no state to do that.")) + return + + var/obj/item/organ/external/tail/tail = get_organ(BP_TAIL) + if(!istype(tail)) + to_chat(usr, SPAN_WARNING("You don't have a tail!")) + verbs -= /mob/living/proc/hide_tail + return + + if(!tail.tail_hidden && !tail.can_be_hidden()) + to_chat(usr, SPAN_WARNING("You are not wearing clothing in which your tail can be hidden.")) + return + + tail.tail_hidden = !tail.tail_hidden + if(usr == src) + var/decl/pronouns/pronouns = get_pronouns() + visible_message(SPAN_NOTICE("\The [src] [tail.tail_hidden ? "conceals" : "reveals"] [pronouns.his] [tail.name].")) + else + visible_message(SPAN_NOTICE("\The [usr] [tail.tail_hidden ? "conceals" : "reveals"] \the [src]'s [tail.name].")) + update_tail_showing() + +/obj/item/organ/external/tail/proc/can_be_hidden() + if(owner) + var/covered_parts = owner.get_covered_body_parts() + return (covered_parts & (SLOT_LEGS|SLOT_LOWER_BODY)) == (SLOT_LEGS|SLOT_LOWER_BODY) + return FALSE + +/obj/item/organ/external/tail/skeletonize() + . = ..() + tail_animation_state = null + owner?.update_tail_showing() + +/obj/item/organ/external/tail/proc/get_accessory_data() + if(tail_hidden && can_be_hidden()) + return GET_DECL(/decl/sprite_accessory/tail/none/hide_tail) + return get_sprite_accessory_by_category(SAC_TAIL) + +/obj/item/organ/external/tail/do_uninstall(in_place, detach, ignore_children, update_icon) + var/mob/living/prior_owner = owner + if(!(. = ..())) + return + + // Set our onmob appearance. + var/decl/sprite_accessory/tail/tail_data = get_accessory_data() + if(tail_data?.draw_accessory) + icon = tail_data.icon + icon_state = tail_data.icon_state + + if(update_icon && istype(prior_owner) && !QDELETED(prior_owner) && prior_owner != owner) + prior_owner.update_tail_showing(FALSE) + + if(istype(prior_owner) && !prior_owner.get_organ(BP_TAIL)) + prior_owner.verbs -= /mob/living/proc/hide_tail + +/obj/item/organ/external/tail/do_install(mob/living/human/target, affected, in_place, update_icon, detached) + . = ..() + if(istype(owner) && !QDELETED(owner)) + owner.verbs |= /mob/living/proc/hide_tail + if(update_icon) + owner.update_tail_showing(FALSE) + +/obj/item/organ/external/tail/proc/get_tail() + var/modifier = owner?.get_overlay_state_modifier() + . = modifier ? "[get_tail_state()][modifier]" : get_tail_state() + if(tail_animation_state && tail_animation_states) + . = "[.][tail_animation_state]" + +/obj/item/organ/external/tail/proc/get_tail_icon() + var/decl/sprite_accessory/tail/tail_data = get_accessory_data() + return tail_data?.draw_accessory ? tail_data.icon : tail_icon + +/obj/item/organ/external/tail/proc/get_tail_state() + var/decl/sprite_accessory/tail/tail_data = get_accessory_data() + return tail_data?.draw_accessory ? tail_data.icon_state : icon_state + +/obj/item/organ/external/tail/proc/get_tail_animation_states() + var/decl/sprite_accessory/tail/tail_data = get_accessory_data() + return tail_data?.draw_accessory ? tail_data.icon_animation_states : tail_animation_states + +/obj/item/organ/external/tail/proc/get_tail_blend() + var/decl/sprite_accessory/tail/tail_data = get_accessory_data() + return tail_data?.draw_accessory ? tail_data.color_blend : tail_blend + +/obj/item/organ/external/tail/proc/get_tail_metadata() + var/decl/sprite_accessory/tail/tail_data = get_accessory_data() + if(tail_data?.draw_accessory) + return get_sprite_accessory_metadata(tail_data.type) + if(owner && (bodytype?.appearance_flags & HAS_SKIN_COLOR)) + return list(SAM_COLOR = owner.get_skin_colour()) + return list(SAM_COLOR = COLOR_WHITE) diff --git a/code/modules/organs/external/unbreakable.dm b/code/modules/organs/external/unbreakable.dm index 19baf45330b3..c390b07dfc3b 100644 --- a/code/modules/organs/external/unbreakable.dm +++ b/code/modules/organs/external/unbreakable.dm @@ -1,55 +1,44 @@ // Slime/xeno limbs. /obj/item/organ/external/chest/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = 0 /obj/item/organ/external/groin/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/arm/unbreakable - dislocated = -1 arterial_bleed_severity = 0 - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_GRASP + limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/arm/right/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/leg/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND /obj/item/organ/external/leg/right/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/foot/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND /obj/item/organ/external/foot/right/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/hand/unbreakable - dislocated = -1 arterial_bleed_severity = 0 - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_GRASP + limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/hand/right/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE /obj/item/organ/external/head/unbreakable - dislocated = -1 arterial_bleed_severity = 0 limb_flags = ORGAN_FLAG_CAN_AMPUTATE diff --git a/code/modules/organs/external/wounds/wound.dm b/code/modules/organs/external/wounds/wound.dm index 8f8cc9f05460..60219be1f1a4 100644 --- a/code/modules/organs/external/wounds/wound.dm +++ b/code/modules/organs/external/wounds/wound.dm @@ -29,7 +29,7 @@ var/tmp/list/desc_list = list() var/tmp/list/damage_list = list() -/datum/wound/New(var/damage, var/obj/item/organ/external/organ = null) +/datum/wound/New(var/damage, var/obj/item/organ/external/organ = null, var/surgical) created = world.time @@ -39,6 +39,10 @@ desc_list += V damage_list += stages[V] + // Surgical wounds need to be at minimum big enough to be considered open, which is max_bleeding_stage. + if(surgical) + damage = max(damage, damage_list[clamp(max_bleeding_stage, 1, length(damage_list))]+1) + src.damage = damage // initialize with the appropriate stage @@ -75,7 +79,7 @@ return 0 return (wound_damage() <= autoheal_cutoff) ? 1 : is_treated() -// checks whether the wound has been appropriately treated +/// checks whether the wound has been appropriately treated /datum/wound/proc/is_treated() if(!LAZYLEN(embedded_objects)) switch(damage_type) @@ -84,8 +88,8 @@ if(BURN) return salved - // Checks whether other other can be merged into src. -/datum/wound/proc/can_merge(var/datum/wound/other) +/// Checks whether other can be merged into src. +/datum/wound/proc/can_merge_wounds(var/datum/wound/other) if (other.type != src.type) return 0 if (other.current_stage != src.current_stage) return 0 if (other.damage_type != src.damage_type) return 0 @@ -165,6 +169,9 @@ // return amount of healing still leftover, can be used for other wounds return amount +/datum/wound/proc/is_open() + return current_stage <= max_bleeding_stage && !bandaged + // opens the wound again /datum/wound/proc/open_wound(damage) src.damage += damage @@ -194,12 +201,11 @@ return 1 /datum/wound/proc/bleeding() - for(var/obj/item/thing in embedded_objects) - if(thing.w_class > ITEM_SIZE_SMALL) - return FALSE - if(bandaged || clamped) - return FALSE - return ((bleed_timer > 0 || wound_damage() > bleed_threshold) && current_stage <= max_bleeding_stage) + . = !clamped && is_open() && (bleed_timer > 0 || wound_damage() > bleed_threshold) + if(. && length(embedded_objects)) + for(var/obj/item/thing in embedded_objects) + if(thing.w_class > ITEM_SIZE_SMALL) + return FALSE /datum/wound/proc/is_surgical() return 0 \ No newline at end of file diff --git a/code/modules/organs/external/wounds/wound_types.dm b/code/modules/organs/external/wounds/wound_types.dm index b7939c76924f..8a115ca12ab1 100644 --- a/code/modules/organs/external/wounds/wound_types.dm +++ b/code/modules/organs/external/wounds/wound_types.dm @@ -10,55 +10,65 @@ if(70 to INFINITY) return /datum/wound/cut/massive if(60 to 70) - return /datum/wound/cut/gaping_big + . = /datum/wound/cut/gaping_big if(50 to 60) - return /datum/wound/cut/gaping + . = /datum/wound/cut/gaping if(25 to 50) - return /datum/wound/cut/flesh + . = /datum/wound/cut/flesh if(15 to 25) - return /datum/wound/cut/deep + . = /datum/wound/cut/deep if(0 to 15) - return /datum/wound/cut/small + . = /datum/wound/cut/small if(PIERCE) switch(damage) if(60 to INFINITY) - return /datum/wound/puncture/massive + . = /datum/wound/puncture/massive if(50 to 60) - return /datum/wound/puncture/gaping_big + . = /datum/wound/puncture/gaping_big if(30 to 50) - return /datum/wound/puncture/gaping + . = /datum/wound/puncture/gaping if(15 to 30) - return /datum/wound/puncture/flesh + . = /datum/wound/puncture/flesh if(0 to 15) - return /datum/wound/puncture/small + . = /datum/wound/puncture/small if(BRUISE) - return /datum/wound/bruise + . = /datum/wound/bruise if(BURN, LASER) switch(damage) if(50 to INFINITY) - return /datum/wound/burn/carbonised + . = /datum/wound/burn/carbonised if(40 to 50) - return /datum/wound/burn/deep + . = /datum/wound/burn/deep if(30 to 40) - return /datum/wound/burn/severe + . = /datum/wound/burn/severe if(15 to 30) - return /datum/wound/burn/large + . = /datum/wound/burn/large if(0 to 15) - return /datum/wound/burn/moderate + . = /datum/wound/burn/moderate if(SHATTER) switch(damage) if(50 to INFINITY) - return /datum/wound/shatter/smashed + . = /datum/wound/shatter/smashed if(40 to 50) - return /datum/wound/shatter/wide + . = /datum/wound/shatter/wide if(30 to 40) - return /datum/wound/shatter/narrow + . = /datum/wound/shatter/narrow if(15 to 30) - return /datum/wound/shatter/cracked + . = /datum/wound/shatter/cracked if(0 to 15) - return /datum/wound/shatter/chipped - - return null //no wound + . = /datum/wound/shatter/chipped + if(CHARRED) + switch(damage) + if(50 to INFINITY) + . = /datum/wound/charred/charcoal + if(40 to 50) + . = /datum/wound/charred/charred + if(30 to 40) + . = /datum/wound/charred/burned + if(15 to 30) + . = /datum/wound/charred/seared + if(0 to 15) + . = /datum/wound/charred/singed /datum/wound/proc/close() return @@ -82,6 +92,7 @@ min_damage = damage_list[current_stage] if(damage > min_damage) heal_damage(damage-min_damage) + autoheal_cutoff = initial(autoheal_cutoff) /datum/wound/cut/small // link wound descriptions to amounts of damage @@ -104,7 +115,7 @@ "deep cut" = 15, "clotted cut" = 8, "scab" = 2, - "fresh skin" = 0 + "fresh patch of skin" = 0 ) /datum/wound/cut/flesh @@ -115,7 +126,7 @@ "flesh wound" = 25, "blood soaked clot" = 15, "large scab" = 5, - "fresh skin" = 0 + "fresh patch of skin" = 0 ) /datum/wound/cut/gaping @@ -138,7 +149,7 @@ "large straight scar" = 0 ) -datum/wound/cut/massive +/datum/wound/cut/massive max_bleeding_stage = 3 stages = list( "massive wound" = 70, @@ -193,7 +204,7 @@ datum/wound/cut/massive "large round scar" = 0 ) -datum/wound/puncture/massive +/datum/wound/puncture/massive max_bleeding_stage = 3 stages = list( "massive wound" = 60, @@ -232,7 +243,7 @@ datum/wound/puncture/massive "ripped burn" = 10, "moderate burn" = 5, "healing moderate burn" = 2, - "fresh skin" = 0 + "fresh patch of skin" = 0 ) /datum/wound/burn/large @@ -240,7 +251,7 @@ datum/wound/puncture/massive "ripped large burn" = 20, "large burn" = 15, "healing large burn" = 5, - "fresh skin" = 0 + "fresh patch of skin" = 0 ) /datum/wound/burn/severe @@ -268,13 +279,15 @@ datum/wound/puncture/massive /** EXTERNAL ORGAN LOSS **/ /datum/wound/lost_limb + var/limb_tag /datum/wound/lost_limb/New(var/obj/item/organ/external/lost_limb, var/losstype, var/clean) var/damage_amt = lost_limb.max_damage if(clean) damage_amt /= 2 + limb_tag = lost_limb.organ_tag switch(losstype) - if(DROPLIMB_EDGE, DROPLIMB_BLUNT) + if(DISMEMBER_METHOD_EDGE, DISMEMBER_METHOD_BLUNT) damage_type = CUT if(BP_IS_PROSTHETIC(lost_limb)) max_bleeding_stage = -1 @@ -295,7 +308,7 @@ datum/wound/puncture/massive "clotted stump" = damage_amt*0.5, "scarred stump" = 0 ) - if(DROPLIMB_BURN) + if(DISMEMBER_METHOD_BURN, DISMEMBER_METHOD_ACID) damage_type = BURN stages = list( "mangled charred stump" = damage_amt*1.3, @@ -306,7 +319,7 @@ datum/wound/puncture/massive ..(damage_amt) -/datum/wound/lost_limb/can_merge(var/datum/wound/other) +/datum/wound/lost_limb/can_merge_wounds(var/datum/wound/other) return 0 //cannot be merged /** CRYSTALLINE WOUNDS **/ @@ -342,3 +355,18 @@ datum/wound/puncture/massive /datum/wound/shatter/chipped stages = list("chip" = 0) + +/datum/wound/charred/charcoal + stages = list("crumbling charred area" = 0) + +/datum/wound/charred/charred + stages = list("charred area" = 0) + +/datum/wound/charred/burned + stages = list("burned area" = 0) + +/datum/wound/charred/seared + stages = list("lightly seared area" = 0) + +/datum/wound/charred/singed + stages = list("singed area" = 0) diff --git a/code/modules/organs/internal/_internal.dm b/code/modules/organs/internal/_internal.dm index eb39143092b9..a200ebacfc41 100644 --- a/code/modules/organs/internal/_internal.dm +++ b/code/modules/organs/internal/_internal.dm @@ -2,163 +2,152 @@ INTERNAL ORGANS DEFINES ****************************************************/ /obj/item/organ/internal - var/dead_icon // Icon to use when the organ has died. + abstract_type = /obj/item/organ/internal + scale_max_damage_to_species_health = TRUE + + // Damage healing vars (moved here from brains) + /// Number of gradiations of damage we can recover in. ie. set to 10, we can recover up to the most recent 10% damage. Leave null to disable regen. + var/damage_threshold_count = 5 + /// Max threshold before we stop regenerating without stabilizer. + var/max_regeneration_cutoff_threshold = 3 + /// Min threshold at which we stop regenerating back to 0 damage. Null/0 to always respect thresholds. + var/min_regeneration_cutoff_threshold + /// Actual amount of health constituting one gradiation. + var/damage_threshold_value + + var/tmp/alive_icon //icon to use when the organ is alive + var/tmp/dead_icon // Icon to use when the organ has died. + var/tmp/prosthetic_icon //Icon to use when the organ is robotic + var/tmp/prosthetic_dead_icon //Icon to use when the organ is robotic and dead var/surface_accessible = FALSE var/relative_size = 25 // Relative size of the organ. Roughly % of space they take in the target projection :D var/min_bruised_damage = 10 // Damage before considered bruised var/damage_reduction = 0.5 //modifier for internal organ injury -/obj/item/organ/internal/Initialize(mapload, datum/dna/given_dna) - if(max_damage) - min_bruised_damage = Floor(max_damage / 4) + /// Whether or not we should try to transfer a brainmob when removed or replaced in a mob. + var/transfer_brainmob_with_organ = FALSE + + // Current damage to the organ + VAR_PRIVATE/_organ_damage = 0 + +/obj/item/organ/internal/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance, decl/bodytype/new_bodytype) + if(!alive_icon) + alive_icon = initial(icon_state) . = ..() - if(iscarbon(loc)) - var/mob/living/carbon/holder = loc - holder.internal_organs |= src - - var/mob/living/carbon/human/H = holder - if(istype(H)) - var/obj/item/organ/external/E = H.get_organ(parent_organ) - if(!E) - . = INITIALIZE_HINT_QDEL - CRASH("[src] spawned in [holder] without a parent organ: [parent_organ].") - E.internal_organs |= src - -/obj/item/organ/internal/Destroy() - if(owner) - owner.internal_organs.Remove(src) - owner.internal_organs_by_name[organ_tag] = null - owner.internal_organs_by_name -= organ_tag - while(null in owner.internal_organs) - owner.internal_organs -= null - var/obj/item/organ/external/E = owner.organs_by_name[parent_organ] - if(istype(E)) E.internal_organs -= src - return ..() + set_max_damage(absolute_max_damage) -/obj/item/organ/internal/set_dna(var/datum/dna/new_dna) - ..() - if(species && species.organs_icon) +/obj/item/organ/internal/set_species(species_uid) + . = ..() + if(species.organs_icon) icon = species.organs_icon -//disconnected the organ from it's owner but does not remove it, instead it becomes an implant that can be removed with implant surgery -//TODO move this to organ/internal once the FPB port comes through -/obj/item/organ/proc/cut_away(var/mob/living/user) - var/obj/item/organ/external/parent = owner.get_organ(parent_organ) - if(istype(parent)) //TODO ensure that we don't have to check this. - removed(user, 0) - parent.implants += src +/obj/item/organ/internal/do_install(mob/living/human/target, obj/item/organ/external/affected, in_place, update_icon, detached) + . = ..() -/obj/item/organ/internal/removed(var/mob/living/user, var/drop_organ=1, var/detach=1) - if(owner) - owner.internal_organs_by_name[organ_tag] = null - owner.internal_organs_by_name -= organ_tag - owner.internal_organs_by_name -= null - owner.internal_organs -= src - - if(detach) - var/obj/item/organ/external/affected = owner.get_organ(parent_organ) - if(affected) - affected.internal_organs -= src - status |= ORGAN_CUT_AWAY - ..() + if(!affected) + log_warning("'[src]' called obj/item/organ/internal/do_install(), but its expected parent organ is null!") + + //The organ may only update and etc if its being attached, or isn't cut away. + //Calls up the chain should have set the CUT_AWAY flag already + if(status & ORGAN_CUT_AWAY) + LAZYDISTINCTADD(affected.implants, src) //Add us to the detached organs list + LAZYREMOVE(affected.internal_organs, src) + else + STOP_PROCESSING(SSobj, src) + LAZYREMOVE(affected.implants, src) //Make sure we're not in the implant list anymore + LAZYDISTINCTADD(affected.internal_organs, src) + affected.cavity_max_w_class = max(affected.cavity_max_w_class, w_class) + affected.update_internal_organs_cost() -/obj/item/organ/internal/replaced(var/mob/living/carbon/human/target, var/obj/item/organ/external/affected) + // This might need revisiting to stop people successfully implanting brains in groins and transferring minds. + if(transfer_brainmob_with_organ && istype(owner)) + var/mob/living/brainmob = get_brainmob(create_if_missing = FALSE) + if(brainmob?.key) + transfer_key_from_mob_to_mob(brainmob, owner) - if(!istype(target)) - return 0 +/obj/item/organ/internal/do_uninstall(in_place, detach, ignore_children, update_icon) - if(status & ORGAN_CUT_AWAY) - return 0 //organs don't work very well in the body when they aren't properly attached + var/mob/living/victim = owner // cleared in parent proc - // robotic organs emulate behavior of the equivalent flesh organ of the species - if(BP_IS_PROSTHETIC(src) || !species) - species = target.species + //Make sure we're removed from whatever parent organ we have, either in a mob or not + var/obj/item/organ/external/affected + if(owner) + affected = GET_EXTERNAL_ORGAN(owner, parent_organ) + else if(istype(loc, /obj/item/organ/external)) + var/obj/item/organ/external/E = loc + if(E.organ_tag == parent_organ) + affected = E + //We can be removed from a mob even if we have no parents, if we're in a detached state + if(affected) + LAZYREMOVE(affected.internal_organs, src) + affected.update_internal_organs_cost() - ..() + . = ..() - STOP_PROCESSING(SSobj, src) - target.internal_organs |= src - affected.internal_organs |= src - target.internal_organs_by_name[organ_tag] = src - return 1 + //Remove it from the implants if we are fully removing, or add it to the implants if we are detaching + if(affected) + if((status & ORGAN_CUT_AWAY) && detach) + LAZYDISTINCTADD(affected.implants, src) + else + LAZYREMOVE(affected.implants, src) -/obj/item/organ/internal/die() - ..() - if((status & ORGAN_DEAD) && dead_icon) - icon_state = dead_icon + if(transfer_brainmob_with_organ && istype(victim)) + transfer_key_to_brainmob(victim, update_brainmob = TRUE) +//#TODO: Remove rejuv hacks /obj/item/organ/internal/remove_rejuv() - if(owner) - owner.internal_organs -= src - owner.internal_organs_by_name[organ_tag] = null - owner.internal_organs_by_name -= organ_tag - while(null in owner.internal_organs) - owner.internal_organs -= null - var/obj/item/organ/external/E = owner.organs_by_name[parent_organ] - if(istype(E)) E.internal_organs -= src + do_uninstall() ..() /obj/item/organ/internal/is_usable() return ..() && !is_broken() -/obj/item/organ/internal/robotize() - ..() - min_bruised_damage += 5 - min_broken_damage += 10 - LAZYINITLIST(matter) - var/mat_amt = 0 - for(var/mat in matter) - mat_amt += matter[mat] - matter.Cut() - matter[/decl/material/solid/metal/steel] = max(3000, mat_amt) - /obj/item/organ/internal/proc/getToxLoss() if(BP_IS_PROSTHETIC(src)) - return damage * 0.5 - return damage + return _organ_damage * 0.5 + return _organ_damage /obj/item/organ/internal/proc/bruise() - damage = max(damage, min_bruised_damage) - -/obj/item/organ/internal/proc/is_damaged() - return damage > 0 + _organ_damage = max(_organ_damage, min_bruised_damage) /obj/item/organ/internal/proc/is_bruised() - return damage >= min_bruised_damage + return _organ_damage >= min_bruised_damage + +/obj/item/organ/internal/set_max_damage(var/ndamage) + . = ..() + min_broken_damage = floor(0.75 * max_damage) + min_bruised_damage = floor(0.25 * max_damage) + if(damage_threshold_count > 0) + damage_threshold_value = round(max_damage / damage_threshold_count) -/obj/item/organ/internal/proc/set_max_damage(var/ndamage) - max_damage = Floor(ndamage) - min_broken_damage = Floor(0.75 * max_damage) - min_bruised_damage = Floor(0.25 * max_damage) +/obj/item/organ/internal/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) -obj/item/organ/internal/take_general_damage(var/amount, var/silent = FALSE) - take_internal_damage(amount, silent) + if(!owner) + return ..() -/obj/item/organ/internal/proc/take_internal_damage(amount, var/silent=0) if(BP_IS_PROSTHETIC(src)) - damage = between(0, src.damage + (amount * 0.8), max_damage) + _organ_damage = clamp(_organ_damage + (damage * 0.8), 0, max_damage) else - damage = between(0, src.damage + amount, max_damage) - - //only show this if the organ is not robotic - if(owner && can_feel_pain() && parent_organ && (amount > 5 || prob(10))) - var/obj/item/organ/external/parent = owner.get_organ(parent_organ) - if(parent && !silent) - var/degree = "" - if(is_bruised()) - degree = " a lot" - if(damage < 5) - degree = " a bit" - owner.custom_pain("Something inside your [parent.name] hurts[degree].", amount, affecting = parent) + _organ_damage = clamp(_organ_damage + damage, 0, max_damage) + + if(can_feel_pain() && parent_organ && (damage > 5 || prob(10))) + var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(owner, parent_organ) + if(parent && !silent) + var/degree = "" + if(is_bruised()) + degree = " a lot" + if(damage < 5) + degree = " a bit" + owner.custom_pain("Something inside your [parent.name] hurts[degree].", damage, affecting = parent) /obj/item/organ/internal/proc/get_visible_state() - if(damage > max_damage) + if(_organ_damage > max_damage) . = "bits and pieces of a destroyed " else if(is_broken()) . = "broken " else if(is_bruised()) . = "badly damaged " - else if(damage > 5) + else if(_organ_damage > 5) . = "damaged " if(status & ORGAN_DEAD) if(can_recover()) @@ -167,34 +156,78 @@ obj/item/organ/internal/take_general_damage(var/amount, var/silent = FALSE) . = "necrotic [.]" if(BP_IS_CRYSTAL(src)) . = "crystalline " - else if(BP_IS_ASSISTED(src)) - . = "assisted " else if(BP_IS_PROSTHETIC(src)) . = "mechanical " . = "[.][name]" /obj/item/organ/internal/Process() + SHOULD_CALL_PARENT(TRUE) ..() - handle_regeneration() - -/obj/item/organ/internal/proc/handle_regeneration() - if(!damage || BP_IS_PROSTHETIC(src) || !owner || owner.chem_effects[CE_TOXIN] || owner.is_asystole()) - return - if(damage < 0.1*max_damage) - heal_damage(0.1) + //check if we've hit max_damage + if(_organ_damage >= max_damage) + die() + if(owner && _organ_damage && !(status & ORGAN_DEAD)) + handle_damage_effects() + +/obj/item/organ/internal/proc/has_limited_healing() + return !min_regeneration_cutoff_threshold || past_damage_threshold(min_regeneration_cutoff_threshold) + +/obj/item/organ/internal/proc/handle_damage_effects() + SHOULD_CALL_PARENT(TRUE) + if(organ_can_heal()) + + // Determine the lowest our damage can go with the current state. + // If we're under the min regeneration cutoff threshold, we can always heal to zero. + // If we don't have one set, we can only heal to the nearest threshold value. + var/min_heal_val = has_limited_healing() ? (get_current_damage_threshold() * damage_threshold_value) : 0 + + // We clamp/round here so that we don't accidentally heal past the threshold and + // cheat our way into a full second threshold of healing. + _organ_damage = clamp(_organ_damage - max(0, get_organ_heal_amount()), min_heal_val, absolute_max_damage) + + // If we're within 1 damage of the nearest threshold (such as 0), round us down. + // This should be removed when float-aware modulo comes in in 515, but for now is needed + // as modulo only deals with integers, but organ regeneration is <= 0.3 by default. + if(!(_organ_damage % damage_threshold_value)) + _organ_damage = round(_organ_damage) + +/obj/item/organ/internal/proc/get_organ_heal_amount() + if(_organ_damage >= min_broken_damage) + return 0.1 + if(_organ_damage >= min_bruised_damage) + return 0.2 + return 0.3 + +/obj/item/organ/internal/proc/organ_can_heal() + // We cannot regenerate, period. + if(!damage_threshold_count || !damage_threshold_value || BP_IS_PROSTHETIC(src)) + return FALSE + // Our owner is under stress. + if(owner.get_blood_oxygenation() < BLOOD_VOLUME_SAFE || GET_CHEMICAL_EFFECT(owner, CE_TOXIN) || owner.radiation || owner.is_asystole()) + return FALSE + // If we haven't hit the regeneration cutoff point, heal. + if(min_regeneration_cutoff_threshold && !past_damage_threshold(min_regeneration_cutoff_threshold)) + return TRUE + // We have room to heal within this threshold, and we either: + // - do not have a max cutoff threshold (point at which no further regeneration will occur) + // - are not past our max cutoff threshold + // - are dosed with stabilizer (ignores max cutoff threshold) + if((_organ_damage % damage_threshold_value) && (!max_regeneration_cutoff_threshold || !past_damage_threshold(max_regeneration_cutoff_threshold) || GET_CHEMICAL_EFFECT(owner, CE_STABLE))) + return TRUE + return FALSE /obj/item/organ/internal/proc/surgical_fix(mob/user) - if(damage > min_broken_damage) - var/scarring = damage/max_damage + if(_organ_damage > min_broken_damage) + var/scarring = _organ_damage/max_damage scarring = 1 - 0.3 * scarring ** 2 // Between ~15 and 30 percent loss - var/new_max_dam = Floor(scarring * max_damage) + var/new_max_dam = floor(scarring * max_damage) if(new_max_dam < max_damage) - to_chat(user, "Not every part of [src] could be saved, some dead tissue had to be removed, making it more suspectable to damage in the future.") + to_chat(user, SPAN_WARNING("Not every part of [src] could be saved; some dead tissue had to be removed, making it more susceptible to damage in the future.")) set_max_damage(new_max_dam) - heal_damage(damage) + heal_damage(_organ_damage) /obj/item/organ/internal/proc/get_scarring_level() - . = (initial(max_damage) - max_damage)/initial(max_damage) + . = (absolute_max_damage - max_damage)/absolute_max_damage /obj/item/organ/internal/get_scan_results() . = ..() @@ -207,8 +240,91 @@ obj/item/organ/internal/take_general_damage(var/amount, var/silent = FALSE) return switch (severity) if (1) - take_internal_damage(16) + take_damage(16) if (2) - take_internal_damage(9) + take_damage(9) if (3) - take_internal_damage(6.5) + take_damage(6.5) + +/obj/item/organ/internal/on_update_icon() + . = ..() + if(BP_IS_PROSTHETIC(src) && prosthetic_icon) + icon_state = ((status & ORGAN_DEAD) && prosthetic_dead_icon) ? prosthetic_dead_icon : prosthetic_icon + else + icon_state = ((status & ORGAN_DEAD) && dead_icon) ? dead_icon : alive_icon + +/obj/item/organ/internal/is_internal() + return TRUE + +// Damage recovery procs! Very exciting. +/obj/item/organ/internal/proc/get_current_damage_threshold() + return damage_threshold_value > 0 ? round(_organ_damage / damage_threshold_value) : INFINITY + +/obj/item/organ/internal/proc/past_damage_threshold(var/threshold) + return (get_current_damage_threshold() > threshold) + +/obj/item/organ/internal/on_add_effects() + . = ..() + if(parent_organ && owner) + var/obj/item/organ/O = owner.get_organ(parent_organ) + if(O) + O.vital_to_owner = null + +/obj/item/organ/internal/on_remove_effects(mob/living/last_owner) + . = ..() + if(parent_organ && last_owner) + var/obj/item/organ/O = last_owner.get_organ(parent_organ) + if(O) + O.vital_to_owner = null + +// Stub to allow brain interfaces to return their wrapped brainmob. +/obj/item/organ/internal/proc/get_brainmob(var/create_if_missing = FALSE) + return + +/obj/item/organ/internal/proc/transfer_key_to_brainmob(var/mob/living/M, var/update_brainmob = TRUE) + var/mob/living/brainmob = get_brainmob(create_if_missing = TRUE) + if(brainmob) + transfer_key_from_mob_to_mob(M, brainmob) + if(update_brainmob) + brainmob.SetName(M.real_name) + brainmob.real_name = M.real_name + brainmob.languages = M.languages?.Copy() + brainmob.default_language = M.default_language + to_chat(brainmob, SPAN_NOTICE("You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].")) + RAISE_EVENT(/decl/observ/debrain, brainmob, src, M) + return TRUE + return FALSE + +/obj/item/organ/internal/proc/get_synthetic_owner_name() + return "Cyborg" + +/obj/item/organ/internal/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + var/mob/living/brainmob = get_brainmob() + return brainmob?.key + +/obj/item/organ/internal/proc/set_organ_damage(amt) + _organ_damage = amt + +/obj/item/organ/internal/proc/adjust_organ_damage(amt) + _organ_damage = clamp(_organ_damage + amt, 0, max_damage) + +/obj/item/organ/internal/proc/get_organ_damage() + return _organ_damage // TODO: get_max_health() - current_health, unify organ/item damage handling. + +/obj/item/organ/internal/is_broken() + return _organ_damage >= min_broken_damage || ..() + +/obj/item/organ/internal/die() + _organ_damage = max_damage + return ..() + +/obj/item/organ/internal/rejuvenate(var/ignore_organ_traits) + _organ_damage = 0 + return ..() + +/obj/item/organ/internal/heal_damage(amount) + if(can_recover()) + _organ_damage = clamp(_organ_damage - round(amount, 0.1), 0, max_damage) + if(owner) + owner.update_health() + diff --git a/code/modules/organs/internal/appendix.dm b/code/modules/organs/internal/appendix.dm index 38495e7c9a84..8f4c372ea7cf 100644 --- a/code/modules/organs/internal/appendix.dm +++ b/code/modules/organs/internal/appendix.dm @@ -22,10 +22,10 @@ owner.visible_message("\The [owner] winces slightly.") if(inflamed > 200) if(prob(3)) - take_internal_damage(0.1) + take_damage(0.1) if(owner.can_feel_pain()) owner.visible_message("\The [owner] winces painfully.") - owner.adjustToxLoss(1) + owner.take_damage(1, TOX) if(inflamed > 400) if(prob(1)) germ_level += rand(2,6) @@ -34,11 +34,10 @@ if(prob(1)) if(owner.can_feel_pain()) owner.custom_pain("You feel a stinging pain in your abdomen!") - owner.Weaken(10) + SET_STATUS_MAX(owner, STAT_WEAK, 10) - var/obj/item/organ/external/E = owner.get_organ(parent_organ) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(owner, parent_organ) E.sever_artery() E.germ_level = max(INFECTION_LEVEL_TWO, E.germ_level) - owner.adjustToxLoss(25) - removed() + owner.take_damage(25, TOX) qdel(src) diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index 94e03956e04a..b3afab56119a 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -3,125 +3,93 @@ desc = "A piece of juicy meat found in a person's head." organ_tag = BP_BRAIN parent_organ = BP_HEAD - vital = 1 icon_state = "brain2" - force = 1.0 w_class = ITEM_SIZE_SMALL - throwforce = 1.0 throw_speed = 3 throw_range = 5 - origin_tech = "{'biotech':3}" + origin_tech = @'{"biotech":3}' attack_verb = list("attacked", "slapped", "whacked") relative_size = 85 damage_reduction = 0 - can_be_printed = FALSE - - var/can_use_mmi = TRUE - var/mob/living/carbon/brain/brainmob = null - var/const/damage_threshold_count = 10 - var/damage_threshold_value - var/healed_threshold = 1 + scale_max_damage_to_species_health = FALSE + transfer_brainmob_with_organ = TRUE + _base_attack_force = 1 + var/can_use_brain_interface = TRUE + var/should_announce_brain_damage = TRUE var/oxygen_reserve = 6 + VAR_PRIVATE/mob/living/_brainmob = /mob/living/brain + +/obj/item/organ/internal/brain/get_brainmob(var/create_if_missing = FALSE) + if(!istype(_brainmob) && create_if_missing) + initialize_brainmob() + if(istype(_brainmob)) + return _brainmob -/obj/item/organ/internal/brain/robotize() - replace_self_with(/obj/item/organ/internal/posibrain) +/obj/item/organ/internal/brain/Initialize() + . = ..() + if(species) + set_max_damage(species.total_health) + else + set_max_damage(200) -/obj/item/organ/internal/brain/mechassist() - replace_self_with(/obj/item/organ/internal/mmi_holder) +/obj/item/organ/internal/brain/proc/initialize_brainmob() + if(istype(_brainmob)) + return + if(!ispath(_brainmob)) + _brainmob = initial(_brainmob) + if(ispath(_brainmob)) + _brainmob = new _brainmob(src) + else + _brainmob = null /obj/item/organ/internal/brain/getToxLoss() return 0 -/obj/item/organ/internal/brain/proc/replace_self_with(replace_path) - var/mob/living/carbon/human/tmp_owner = owner - qdel(src) - if(tmp_owner) - tmp_owner.internal_organs_by_name[organ_tag] = new replace_path(tmp_owner, 1) - tmp_owner = null - -/obj/item/organ/internal/brain/robotize() +/obj/item/organ/internal/brain/set_species(species_uid) . = ..() icon_state = "brain-prosthetic" - -/obj/item/organ/internal/brain/Initialize() - . = ..() if(species) set_max_damage(species.total_health) else set_max_damage(200) - spawn(5) - if(brainmob && brainmob.client) - brainmob.client.screen.len = null //clear the hud - -/obj/item/organ/internal/brain/set_max_damage(var/ndamage) - ..() - damage_threshold_value = round(max_damage / damage_threshold_count) - /obj/item/organ/internal/brain/Destroy() - QDEL_NULL(brainmob) + if(istype(_brainmob)) + QDEL_NULL(_brainmob) . = ..() -/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H) - - if(!brainmob) - brainmob = new(src) - brainmob.SetName(H.real_name) - brainmob.real_name = H.real_name - brainmob.dna = H.dna.Clone() - brainmob.timeofhostdeath = H.timeofdeath - - if(H.mind) - H.mind.transfer_to(brainmob) - - to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].") - callHook("debrain", list(brainmob)) - -/obj/item/organ/internal/brain/examine(mob/user) +/obj/item/organ/internal/brain/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(brainmob && brainmob.client)//if thar be a brain inside... the brain. - to_chat(user, "You can feel the small spark of life still left in this one.") + if(distance <= 1) + var/brain_status = get_brain_status(user) + if(brain_status) + . += brain_status + +/obj/item/organ/internal/brain/proc/get_brain_status(mob/user) + . = list() + if(istype(_brainmob) && _brainmob?.client) //if thar be a brain inside... the brain. + . += "You can feel the small spark of life still left in this one." else - to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later..") - -/obj/item/organ/internal/brain/removed(var/mob/living/user) - if(!istype(owner)) - return ..() - - if(name == initial(name)) - name = "\the [owner.real_name]'s [initial(name)]" - - transfer_identity(owner) + . += "This one seems particularly lifeless. Perhaps it will regain some of its luster later." - ..() - -/obj/item/organ/internal/brain/replaced(var/mob/living/target) - - if(!..()) return 0 - - if(target.key) - target.ghostize() - - if(brainmob) - if(brainmob.mind) - brainmob.mind.transfer_to(target) - else - target.key = brainmob.key +/obj/item/organ/internal/brain/do_install(mob/living/target, affected, in_place, update_icon, detached) + if(!(. = ..())) + return + if(istype(owner)) + SetName(initial(name)) //Reset the organ's name to stay coherent if we're putting it back into someone's skull - return 1 +/obj/item/organ/internal/brain/do_uninstall(in_place, detach, ignore_children, update_icon) + if(!in_place && istype(owner) && name == initial(name)) + SetName("\the [owner.real_name]'s [initial(name)]") + if(!(. = ..())) + return /obj/item/organ/internal/brain/can_recover() - return ~status & ORGAN_DEAD - -/obj/item/organ/internal/brain/proc/get_current_damage_threshold() - return round(damage / damage_threshold_value) - -/obj/item/organ/internal/brain/proc/past_damage_threshold(var/threshold) - return (get_current_damage_threshold() > threshold) + return !(status & ORGAN_DEAD) -/obj/item/organ/internal/brain/proc/handle_severe_brain_damage() +/obj/item/organ/internal/brain/proc/handle_severe_damage() set waitfor = FALSE - healed_threshold = 0 + should_announce_brain_damage = FALSE to_chat(owner, "Where am I...?") sleep(5 SECONDS) if(!owner) @@ -133,16 +101,24 @@ to_chat(owner, "What happened...?") alert(owner, "You have taken massive brain damage! You will not be able to remember the events leading up to your injury.", "Brain Damaged") +/obj/item/organ/internal/brain/organ_can_heal() + return (_organ_damage && owner && GET_CHEMICAL_EFFECT(owner, CE_BRAIN_REGEN) > 0) || ..() + +/obj/item/organ/internal/brain/has_limited_healing() + return (!owner || GET_CHEMICAL_EFFECT(owner, CE_BRAIN_REGEN) <= 0) && ..() + +/obj/item/organ/internal/brain/get_organ_heal_amount() + if(!has_limited_healing()) + . = 1 // We have full healing, so we always heal at least 1 unit of damage. + . += (owner ? GET_CHEMICAL_EFFECT(owner, CE_BRAIN_REGEN) : 0) + /obj/item/organ/internal/brain/Process() if(owner) - if(damage > max_damage / 2 && healed_threshold) - handle_severe_brain_damage() - if(damage < (max_damage / 4)) - healed_threshold = 1 + if(_organ_damage < (max_damage / 4)) + should_announce_brain_damage = TRUE handle_disabilities() - handle_damage_effects() // Brain damage from low oxygenation or lack of blood. if(owner.should_have_organ(BP_HEART)) @@ -150,111 +126,113 @@ // No heart? You are going to have a very bad time. Not 100% lethal because heart transplants should be a thing. var/blood_volume = owner.get_blood_oxygenation() if(blood_volume < BLOOD_VOLUME_SURVIVE) - if(!owner.chem_effects[CE_STABLE] || prob(60)) + if(!owner.has_chemical_effect(CE_STABLE, 1) || prob(60)) oxygen_reserve = max(0, oxygen_reserve-1) else oxygen_reserve = min(initial(oxygen_reserve), oxygen_reserve+1) if(!oxygen_reserve) //(hardcrit) - owner.Paralyse(3) - var/can_heal = damage && damage < max_damage && (damage % damage_threshold_value || owner.chem_effects[CE_BRAIN_REGEN] || (!past_damage_threshold(3) && owner.chem_effects[CE_STABLE])) - var/damprob - //Effects of bloodloss - switch(blood_volume) + SET_STATUS_MAX(owner, STAT_PARA, 3) - if(BLOOD_VOLUME_SAFE to INFINITY) - if(can_heal) - damage = max(damage-1, 0) - if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) - if(prob(1)) - to_chat(owner, "You feel [pick("dizzy","woozy","faint")]...") - damprob = owner.chem_effects[CE_STABLE] ? 30 : 60 - if(!past_damage_threshold(2) && prob(damprob)) - take_internal_damage(1) - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - owner.eye_blurry = max(owner.eye_blurry,6) - damprob = owner.chem_effects[CE_STABLE] ? 40 : 80 - if(!past_damage_threshold(4) && prob(damprob)) - take_internal_damage(1) - if(!owner.paralysis && prob(10)) - owner.Paralyse(rand(1,3)) - to_chat(owner, "You feel extremely [pick("dizzy","woozy","faint")]...") - if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) - owner.eye_blurry = max(owner.eye_blurry,6) - damprob = owner.chem_effects[CE_STABLE] ? 60 : 100 - if(!past_damage_threshold(6) && prob(damprob)) - take_internal_damage(1) - if(!owner.paralysis && prob(15)) - owner.Paralyse(3,5) - to_chat(owner, "You feel extremely [pick("dizzy","woozy","faint")]...") - if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) // Also see heart.dm, being below this point puts you into cardiac arrest. - owner.eye_blurry = max(owner.eye_blurry,6) - damprob = owner.chem_effects[CE_STABLE] ? 80 : 100 - if(prob(damprob)) - take_internal_damage(1) - if(prob(damprob)) - take_internal_damage(1) + //Effects of bloodloss + if(blood_volume < BLOOD_VOLUME_SAFE) + var/damprob + var/stability_effect = GET_CHEMICAL_EFFECT(owner, CE_STABLE) + switch(blood_volume) + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + if(prob(1)) + to_chat(owner, "You feel [pick("dizzy","woozy","faint")]...") + damprob = stability_effect ? 30 : 60 + if(!past_damage_threshold(2) && prob(damprob)) + take_damage(1) + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + SET_STATUS_MAX(owner, STAT_BLURRY, 6) + damprob = stability_effect ? 40 : 80 + if(!past_damage_threshold(4) && prob(damprob)) + take_damage(1) + if(!HAS_STATUS(owner, STAT_PARA) && prob(10)) + SET_STATUS_MAX(owner, STAT_PARA, rand(1,3)) + to_chat(owner, "You feel extremely [pick("dizzy","woozy","faint")]...") + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + SET_STATUS_MAX(owner, STAT_BLURRY, 6) + damprob = stability_effect ? 60 : 100 + if(!past_damage_threshold(6) && prob(damprob)) + take_damage(1) + if(!HAS_STATUS(owner, STAT_PARA) && prob(15)) + SET_STATUS_MAX(owner, STAT_PARA, rand(3,5)) + to_chat(owner, "You feel extremely [pick("dizzy","woozy","faint")]...") + if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) // Also see heart.dm, being below this point puts you into cardiac arrest. + SET_STATUS_MAX(owner, STAT_BLURRY, 6) + damprob = stability_effect ? 80 : 100 + if(prob(damprob)) + take_damage(1) + if(prob(damprob)) + take_damage(1) ..() -/obj/item/organ/internal/brain/take_internal_damage(var/damage, var/silent) - set waitfor = 0 - ..() - if(damage >= 10) //This probably won't be triggered by oxyloss or mercury. Probably. +/obj/item/organ/internal/brain/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + . = ..() + if(owner && damage >= 10) //This probably won't be triggered by oxyloss or mercury. Probably. var/damage_secondary = damage * 0.20 owner.flash_eyes() - owner.eye_blurry += damage_secondary - owner.confused += damage_secondary * 2 - owner.Paralyse(damage_secondary) - owner.Weaken(round(damage, 1)) + SET_STATUS_MAX(owner, STAT_BLURRY, damage_secondary) + SET_STATUS_MAX(owner, STAT_CONFUSE, damage_secondary * 2) + SET_STATUS_MAX(owner, STAT_PARA, damage_secondary) + SET_STATUS_MAX(owner, STAT_WEAK, round(damage, 1)) if(prob(30)) - addtimer(CALLBACK(src, .proc/brain_damage_callback, damage), rand(6, 20) SECONDS, TIMER_UNIQUE) + addtimer(CALLBACK(src, PROC_REF(brain_damage_callback), damage), rand(6, 20) SECONDS, TIMER_UNIQUE) /obj/item/organ/internal/brain/proc/brain_damage_callback(var/damage) //Confuse them as a somewhat uncommon aftershock. Side note: Only here so a spawn isn't used. Also, for the sake of a unique timer. - to_chat(owner, "I can't remember which way is forward...") - owner.confused += damage + if(!QDELETED(owner)) + to_chat(owner, SPAN_NOTICE(FONT_HUGE("I can't remember which way is forward..."))) + ADJ_STATUS(owner, STAT_CONFUSE, damage) /obj/item/organ/internal/brain/proc/handle_disabilities() if(owner.stat) return - if((owner.disabilities & EPILEPSY) && prob(1)) + if(owner.has_genetic_condition(GENE_COND_EPILEPSY) && prob(1)) owner.seizure() - else if((owner.disabilities & TOURETTES) && prob(10)) - owner.Stun(10) + else if(owner.has_genetic_condition(GENE_COND_TOURETTES) && prob(10)) + SET_STATUS_MAX(owner, STAT_STUN, 10) switch(rand(1, 3)) if(1) - owner.emote("twitch") + owner.emote(/decl/emote/visible/twitch) if(2 to 3) owner.say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]") - owner.make_jittery(100) - else if((owner.disabilities & NERVOUS) && prob(10)) - owner.stuttering = max(10, owner.stuttering) + ADJ_STATUS(owner, STAT_JITTER, 100) + else if(owner.has_genetic_condition(GENE_COND_NERVOUS) && prob(10)) + SET_STATUS_MAX(owner, STAT_STUTTER, 10) -/obj/item/organ/internal/brain/proc/handle_damage_effects() - if(owner.stat) - return - if(damage > 0 && prob(1)) + +/obj/item/organ/internal/brain/handle_damage_effects() + ..() + + if(_organ_damage >= round(max_damage / 2) && should_announce_brain_damage) + handle_severe_damage() + + if(!BP_IS_PROSTHETIC(src) && prob(1)) owner.custom_pain("Your head feels numb and painful.",10) - if(is_bruised() && prob(1) && owner.eye_blurry <= 0) + if(is_bruised() && prob(1) && !HAS_STATUS(owner, STAT_BLURRY)) to_chat(owner, "It becomes hard to see for some reason.") - owner.eye_blurry = 10 - if(damage >= 0.5*max_damage && prob(1) && owner.get_active_hand()) + owner.set_status_condition(STAT_BLURRY, 10) + var/held = owner.get_active_held_item() + if(_organ_damage >= 0.5*max_damage && prob(1) && held) to_chat(owner, "Your hand won't respond properly, and you drop what you are holding!") - owner.unequip_item() - if(damage >= 0.6*max_damage) - owner.slurring = max(owner.slurring, 2) + owner.try_unequip(held) + if(_organ_damage >= 0.6*max_damage) + SET_STATUS_MAX(owner, STAT_SLUR, 2) if(is_broken()) - if(!owner.lying) + if(!owner.current_posture.prone) to_chat(owner, "You black out!") - owner.Paralyse(10) + SET_STATUS_MAX(owner, STAT_PARA, 10) /obj/item/organ/internal/brain/surgical_fix(mob/user) var/blood_volume = owner.get_blood_oxygenation() if(blood_volume < BLOOD_VOLUME_SURVIVE) - to_chat(user, "Parts of [src] didn't survive the procedure due to lack of air supply!") - set_max_damage(Floor(max_damage - 0.25*damage)) - heal_damage(damage) - -/obj/item/organ/internal/brain/get_scarring_level() - . = (species.total_health - max_damage)/species.total_health + to_chat(user, SPAN_DANGER("Parts of \the [src] didn't survive the procedure due to lack of air supply!")) + set_max_damage(floor(max_damage - 0.25*_organ_damage)) + heal_damage(_organ_damage) -/obj/item/organ/internal/brain/get_mechanical_assisted_descriptor() - return "machine-interface [name]" \ No newline at end of file +/obj/item/organ/internal/brain/die() + if(istype(_brainmob) && _brainmob.stat != DEAD) + _brainmob.death() + ..() diff --git a/code/modules/organs/internal/brain_computer.dm b/code/modules/organs/internal/brain_computer.dm new file mode 100644 index 000000000000..e67b6be22c8f --- /dev/null +++ b/code/modules/organs/internal/brain_computer.dm @@ -0,0 +1,94 @@ +// Robobrain. +/obj/item/organ/internal/brain/robotic + name = "computer intelligence core" + desc = "The pinnacle of artificial intelligence technology, conveniently stored in a fist-sized cube." + icon = 'icons/obj/items/brain_interface_robotic.dmi' + origin_tech = @'{"engineering":4,"materials":4,"wormholes":2,"programming":4}' + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, + /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE + ) + bodytype = /decl/bodytype/prosthetic/basic_human + can_use_brain_interface = FALSE + var/searching = FALSE + var/brain_name + +/obj/item/organ/internal/brain/robotic/handle_severe_damage() + return // TODO: computer maladies + +/obj/item/organ/internal/brain/robotic/handle_disabilities() + return // TODO: computer maladies + +/obj/item/organ/internal/brain/robotic/Initialize() + . = ..() + update_icon() + brain_name = "[pick(list("ADA","DOS","GNU","MAC","WIN"))]-[random_id(type,1000,9999)]" + SetName("[name] ([brain_name])") + +/obj/item/organ/internal/brain/robotic/initialize_brainmob() + ..() + if(istype(_brainmob)) + _brainmob.SetName(brain_name) + _brainmob.add_language(/decl/language/machine) + +/obj/item/organ/internal/brain/robotic/on_update_icon() + . = ..() + var/mob/living/brainmob = get_brainmob() + icon_state = get_world_inventory_state() + if(!searching) + if(!brainmob?.key || brainmob.stat == DEAD) + icon_state = "[icon_state]-dead" + else + icon_state = "[icon_state]-full" + +/obj/item/organ/internal/brain/robotic/attack_self(mob/user) + var/mob/living/brainmob = get_brainmob(create_if_missing = TRUE) + if(!brainmob?.key && !searching) + to_chat(user, SPAN_NOTICE("You press the power button and boot up \the [src].")) + searching = TRUE + update_icon() + var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/machine_intelligence) + G.request_player(brainmob, "Someone is requesting a personality for \a [name].", 1 MINUTE) + addtimer(CALLBACK(src, PROC_REF(reset_search)), 1 MINUTE) + return TRUE + . = ..() + +/obj/item/organ/internal/brain/robotic/proc/reset_search() + searching = FALSE + update_icon() + var/mob/living/brainmob = get_brainmob() + if(!brainmob?.key) + visible_message(SPAN_WARNING("\The [src] emits a series of loud beeps, indicating a failure to boot. Try again in a few minutes.")) + +/obj/item/organ/internal/brain/robotic/attack_ghost(var/mob/observer/ghost/user) + var/mob/living/brainmob = get_brainmob(create_if_missing = TRUE) + if(brainmob?.key) + to_chat(user, SPAN_WARNING("\The [src] is already inhabited; there's no room for you!")) + return TRUE + + var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/machine_intelligence) + if(G.assess_candidate(user)) + var/response = alert(user, "Are you sure you wish to possess \the [src]?", "Possess [capitalize(name)]", "Yes", "No") + if(response == "Yes" && brainmob && !brainmob?.key && G.assess_candidate(user)) + G.transfer_personality(user, brainmob) + +/obj/item/organ/internal/brain/robotic/get_brain_status(mob/user) + . = list() + var/mob/living/brainmob = get_brainmob() + if(brainmob?.key) + switch(brainmob.stat) + if(CONSCIOUS) + if(!brainmob.client) + . += SPAN_WARNING("It appears to be in stand-by mode.") + if(UNCONSCIOUS) + . += SPAN_WARNING("It doesn't seem to be responsive.") + if(DEAD) + . += SPAN_WARNING("It appears to be completely inactive.") + else + . += SPAN_WARNING("It appears to be completely inactive.") + +/obj/item/organ/internal/brain/robotic/get_synthetic_owner_name() + return "Robot" diff --git a/code/modules/organs/internal/cell.dm b/code/modules/organs/internal/cell.dm new file mode 100644 index 000000000000..e778d84defe7 --- /dev/null +++ b/code/modules/organs/internal/cell.dm @@ -0,0 +1,99 @@ +/obj/item/organ/internal/cell + name = "microbattery" + desc = "A small, powerful cell for use in fully prosthetic bodies." + icon_state = "cell" + dead_icon = "cell_bork" + organ_tag = BP_CELL + parent_organ = BP_CHEST + var/open + var/obj/item/cell/cell = /obj/item/cell/hyper + //at 0.8 completely depleted after 60ish minutes of constant walking or 130 minutes of standing still + var/servo_cost = 0.8 + +/obj/item/organ/internal/cell/Initialize() + if(ispath(cell)) + cell = new cell(src) + . = ..() + +/obj/item/organ/internal/cell/proc/percent() + if(!cell) + return 0 + return get_charge()/cell.maxcharge * 100 + +/obj/item/organ/internal/cell/proc/get_charge() + if(!cell) + return 0 + if(status & ORGAN_DEAD) + return 0 + return round(cell.charge*(1 - _organ_damage/max_damage)) + +/obj/item/organ/internal/cell/proc/checked_use(var/amount) + if(!is_usable()) + return FALSE + return cell && cell.checked_use(amount) + +/obj/item/organ/internal/cell/proc/use(var/amount) + if(!is_usable()) + return 0 + return cell && cell.use(amount) + +/obj/item/organ/internal/cell/proc/get_power_drain() + var/damage_factor = 1 + 10 * _organ_damage/max_damage + return servo_cost * damage_factor + +/obj/item/organ/internal/cell/Process() + ..() + if(!owner) + return + if(owner.stat == DEAD) //not a drain anymore + return + var/cost = get_power_drain() + if(world.time - owner.l_move_time < 15) + cost *= 2 + if(!checked_use(cost) && owner.isSynthetic()) + if(!owner.current_posture.prone && !owner.buckled) + to_chat(owner, SPAN_WARNING("You don't have enough energy to function!")) + SET_STATUS_MAX(owner, STAT_PARA, 3) + +/obj/item/organ/internal/cell/emp_act(severity) + ..() + if(cell) + cell.emp_act(severity) + +// TODO: Make this use the cell extension instead? +// Or have it grant a subtype of cell extension to the mob, maybe? +/obj/item/organ/internal/cell/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) + if(open) + open = FALSE + to_chat(user, SPAN_NOTICE("You screw the battery panel in place.")) + else + open = TRUE + to_chat(user, SPAN_NOTICE("You unscrew the battery panel.")) + return TRUE + else if(open) + if(IS_CROWBAR(used_item)) + if(cell) + user.put_in_hands(cell) + to_chat(user, SPAN_NOTICE("You remove \the [cell] from \the [src].")) + cell = null + return TRUE + else if (istype(used_item, /obj/item/cell)) + if(cell) + to_chat(user, SPAN_WARNING("There is a power cell already installed.")) + else if(user.try_unequip(used_item, src)) + cell = used_item + to_chat(user, SPAN_NOTICE("You insert \the [cell].")) + return TRUE + return ..() + +/obj/item/organ/internal/cell/on_add_effects() + . = ..() + // This is very ghetto way of rebooting an IPC. TODO better way. + if(owner && owner.stat == DEAD) + owner.set_stat(CONSCIOUS) + owner.visible_message(SPAN_NOTICE("\The [owner] twitches visibly!")) + +/obj/item/organ/internal/cell/listen() + if(get_charge()) + return "faint hum of the power bank" diff --git a/code/modules/organs/internal/eyes.dm b/code/modules/organs/internal/eyes.dm index d67080afe93c..27d1be46f409 100644 --- a/code/modules/organs/internal/eyes.dm +++ b/code/modules/organs/internal/eyes.dm @@ -2,79 +2,83 @@ /obj/item/organ/internal/eyes name = "eyeballs" icon_state = "eyes" + prosthetic_icon = "camera" + prosthetic_dead_icon = "camera_broken" gender = PLURAL organ_tag = BP_EYES parent_organ = BP_HEAD surface_accessible = TRUE relative_size = 5 max_damage = 45 - var/contaminant_guard = 0 + z_flags = ZMM_MANGLE_PLANES + var/eye_colour = COLOR_BLACK - var/innate_flash_protection = FLASH_PROTECTION_NONE - var/eye_icon = 'icons/mob/human_races/species/default_eyes.dmi' - var/apply_eye_colour = TRUE var/tmp/last_cached_eye_colour var/tmp/last_eye_cache_key - var/flash_mod - var/darksight_range - var/darksight_tint -/obj/item/organ/internal/eyes/proc/get_eye_cache_key() - last_cached_eye_colour = eye_colour - last_eye_cache_key = "[type]-[eye_icon]-[last_cached_eye_colour]" - return last_eye_cache_key +/obj/item/organ/internal/eyes/proc/get_innate_flash_protection() + return bodytype.eye_innate_flash_protection -/obj/item/organ/internal/eyes/proc/get_onhead_icon() - var/cache_key = get_eye_cache_key() - if(!human_icon_cache[cache_key]) - var/icon/eyes_icon = icon(icon = eye_icon, icon_state = "") - if(apply_eye_colour) - eyes_icon.Blend(last_cached_eye_colour, ICON_ADD) - human_icon_cache[cache_key] = eyes_icon - return human_icon_cache[cache_key] - -/obj/item/organ/internal/eyes/proc/get_special_overlay() - var/icon/I = get_onhead_icon() - if(I) - var/cache_key = "[last_eye_cache_key]-glow" - if(!human_icon_cache[cache_key]) - var/image/eye_glow = image(I) - eye_glow.layer = EYE_GLOW_LAYER - eye_glow.plane = EFFECTS_ABOVE_LIGHTING_PLANE - human_icon_cache[cache_key] = eye_glow - return human_icon_cache[cache_key] - -/obj/item/organ/internal/eyes/proc/change_eye_color() - set name = "Change Eye Color" - set desc = "Changes your robotic eye color." - set category = "IC" - set src in usr - if (!owner || owner.incapacitated()) - return - var/new_eyes = input("Please select eye color.", "Eye Color", owner.eye_colour) as color|null - if(new_eyes && do_after(owner, 10) && owner.change_eye_color(new_eyes)) - update_colour() - // Finally, update the eye icon on the mob. - owner.regenerate_icons() - owner.visible_message(SPAN_NOTICE("\The [owner] changes their eye color."),SPAN_NOTICE("You change your eye color."),) +/obj/item/organ/internal/eyes/proc/get_flash_mod() + return bodytype.eye_flash_mod -/obj/item/organ/internal/eyes/replaced(var/mob/living/carbon/human/target) +/obj/item/organ/internal/eyes/proc/get_flash_burn() + return bodytype.eye_flash_burn - // Apply our eye colour to the target. - if(istype(target) && eye_colour) - target.eye_colour = eye_colour - target.update_eyes() - ..() +/obj/item/organ/internal/eyes/proc/get_darksight_range() + return bodytype.eye_darksight_range + +/obj/item/organ/internal/eyes/robot + name = "optical sensor" + bodytype = /decl/bodytype/prosthetic/basic_human + organ_properties = ORGAN_PROP_PROSTHETIC + icon = 'icons/obj/robot_component.dmi' + +/obj/item/organ/internal/eyes/robot/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance, decl/bodytype/new_bodytype) + . = ..() + verbs |= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + verbs |= /obj/item/organ/internal/eyes/proc/toggle_eye_glow + +/obj/item/organ/external/eyes/set_organ_appearance_bodytype(decl/bodytype/new_bodytype, update_sprite_accessories = TRUE, skip_owner_update = FALSE) + . = ..() + if(. && owner && !skip_owner_update) + owner.update_eyes() + +/obj/item/organ/internal/eyes/proc/get_onhead_icon() + var/decl/bodytype/icon_bodytype = get_organ_appearance_bodytype() + var/modifier = owner?.get_overlay_state_modifier() + var/eye_state = modifier ? "eyes[modifier]" : "eyes" + last_cached_eye_colour = eye_colour + last_eye_cache_key = "[type]-[icon_bodytype.eye_icon]-[last_cached_eye_colour]-[icon_bodytype.eye_offset]-[eye_state]" + if(!icon_bodytype.eye_icon) + return + if(!global.eye_icon_cache[last_eye_cache_key]) + var/icon/eyes_icon = icon(icon = icon_bodytype.eye_icon, icon_state = eye_state) + if(icon_bodytype.eye_offset) + eyes_icon.Shift(NORTH, icon_bodytype.eye_offset) + if(icon_bodytype.apply_eye_colour) + eyes_icon.Blend(last_cached_eye_colour, icon_bodytype.eye_blend) + global.eye_icon_cache[last_eye_cache_key] = eyes_icon + return global.eye_icon_cache[last_eye_cache_key] /obj/item/organ/internal/eyes/proc/update_colour() if(!owner) return - if(owner.chem_effects[CE_GLOWINGEYES]) - eye_colour = "#75bdd6" // blue glow, hardcoded for now. + // Update our eye colour. + var/new_eye_colour + if(owner.has_chemical_effect(CE_GLOWINGEYES, 1)) + new_eye_colour = "#75bdd6" // blue glow, hardcoded for now. else - eye_colour = owner.eye_colour || COLOR_BLACK + new_eye_colour = owner.get_eye_colour() + + if(new_eye_colour && eye_colour != new_eye_colour) + eye_colour = new_eye_colour + // Clear the head cache key so they can update their cached icon. + var/obj/item/organ/external/head/head = GET_EXTERNAL_ORGAN(owner, BP_HEAD) + if(istype(head)) + head._icon_cache_key = null -/obj/item/organ/internal/eyes/take_internal_damage(amount, var/silent=0) +/obj/item/organ/internal/eyes/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) var/oldbroken = is_broken() . = ..() if(is_broken() && !oldbroken && owner && !owner.stat) @@ -85,40 +89,82 @@ if(!owner) return if(is_bruised()) - owner.eye_blurry = 20 + SET_STATUS_MAX(owner, STAT_BLURRY, 20) if(is_broken()) - owner.eye_blind = 20 - -/obj/item/organ/internal/eyes/Initialize() - . = ..() - flash_mod = species.flash_mod - darksight_range = species.darksight_range - darksight_tint = species.darksight_tint + SET_STATUS_MAX(owner, STAT_BLIND, 20) /obj/item/organ/internal/eyes/proc/get_total_protection(var/flash_protection = FLASH_PROTECTION_NONE) - return (flash_protection + innate_flash_protection) + return (flash_protection + get_innate_flash_protection()) /obj/item/organ/internal/eyes/proc/additional_flash_effects(var/intensity) return -1 -/obj/item/organ/internal/eyes/robot - name = "optical sensor" +/obj/item/organ/internal/eyes/do_install(mob/living/human/target, affected, in_place, update_icon, detached) + // Apply our eye colour to the target. + if(istype(target) && eye_colour) + target.set_eye_colour(eye_colour, skip_update = TRUE) + target.update_eyes(update_icons = update_icon) + if(owner && BP_IS_PROSTHETIC(src)) + verbs |= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + verbs |= /obj/item/organ/internal/eyes/proc/toggle_eye_glow + . = ..() -/obj/item/organ/internal/eyes/robot/Initialize() +/obj/item/organ/internal/eyes/do_uninstall(in_place, detach, ignore_children, update_icon) . = ..() - robotize() + verbs -= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + verbs -= /obj/item/organ/internal/eyes/proc/toggle_eye_glow -/obj/item/organ/internal/eyes/robotize() - ..() - name = "optical sensor" - icon = 'icons/obj/robot_component.dmi' - icon_state = "camera" - dead_icon = "camera_broken" - verbs |= /obj/item/organ/internal/eyes/proc/change_eye_color +// TODO: FIND A BETTER WAY TO DO THIS +// MAYBE JUST REMOVE IT ENTIRELY? +/obj/item/organ/internal/eyes/reset_status() + . = ..() + if(BP_IS_PROSTHETIC(src)) + name = "optical sensor" + icon = 'icons/obj/robot_component.dmi' + verbs |= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + verbs |= /obj/item/organ/internal/eyes/proc/toggle_eye_glow + else + name = initial(name) + icon = initial(icon) + verbs -= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + verbs -= /obj/item/organ/internal/eyes/proc/toggle_eye_glow update_colour() - flash_mod = 1 - darksight_range = 2 - darksight_tint = DARKTINT_NONE -/obj/item/organ/internal/eyes/get_mechanical_assisted_descriptor() - return "retinal overlayed [name]" +/obj/item/organ/internal/eyes/proc/change_eye_color_verb() + set name = "Change Eye Color" + set desc = "Changes your robotic eye color." + set category = "IC" + set src in usr + + if(!owner || !BP_IS_PROSTHETIC(src)) + verbs -= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + return + + if(owner.incapacitated()) + return + + var/new_eyes = input("Please select eye color.", "Eye Color", owner.get_eye_colour()) as color|null + if(new_eyes && do_after(owner, 10) && owner.set_eye_colour(new_eyes)) + update_colour() + // Finally, update the eye icon on the mob. + owner.try_refresh_visible_overlays() + owner.visible_message(SPAN_NOTICE("\The [owner] changes their eye color."),SPAN_NOTICE("You change your eye color."),) + +/obj/item/organ/internal/eyes/proc/toggle_eye_glow() + + set name = "Toggle Eye Glow" + set desc = "Toggles your robotic eye glow." + set category = "IC" + set src in usr + + if(!owner || !BP_IS_PROSTHETIC(src)) + verbs -= /obj/item/organ/internal/eyes/proc/toggle_eye_glow + return + + if(owner.incapacitated()) + return + + var/obj/item/organ/external/head/head = owner.get_organ(BP_HEAD, /obj/item/organ/external/head) + if(head) + head.glowing_eyes = !head.glowing_eyes + owner.try_refresh_visible_overlays() diff --git a/code/modules/organs/internal/heart.dm b/code/modules/organs/internal/heart.dm index ce46fccdcad0..4617c8b74a22 100644 --- a/code/modules/organs/internal/heart.dm +++ b/code/modules/organs/internal/heart.dm @@ -1,58 +1,54 @@ /obj/item/organ/internal/heart name = "heart" - icon_state = "heart-on" organ_tag = "heart" parent_organ = BP_CHEST + icon_state = "heart-on" dead_icon = "heart-off" + prosthetic_icon = "heart-prosthetic" + damage_reduction = 0.7 + relative_size = 5 + max_damage = 45 var/pulse = PULSE_NORM var/heartbeat = 0 var/beat_sound = 'sound/effects/singlebeat.ogg' var/tmp/next_blood_squirt = 0 - damage_reduction = 0.7 - relative_size = 5 - max_damage = 45 var/open var/list/external_pump +/obj/item/organ/internal/heart/on_holder_death(var/gibbed) + pulse = PULSE_NONE + update_icon() + /obj/item/organ/internal/heart/open open = 1 -/obj/item/organ/internal/heart/die() - if(dead_icon) - icon_state = dead_icon - ..() - -/obj/item/organ/internal/heart/robotize() - . = ..() - icon_state = "heart-prosthetic" - /obj/item/organ/internal/heart/Process() if(owner) handle_pulse() if(pulse) handle_heartbeat() if(pulse == PULSE_2FAST && prob(1)) - take_internal_damage(0.5) + take_damage(0.5) if(pulse == PULSE_THREADY && prob(5)) - take_internal_damage(0.5) + take_damage(0.5) handle_blood() ..() /obj/item/organ/internal/heart/proc/handle_pulse() - if(BP_IS_PROSTHETIC(src)) + if(BP_IS_PROSTHETIC(src) || !owner || owner.vital_organ_missing_time) pulse = PULSE_NONE //that's it, you're dead (or your metal heart is), nothing can influence your pulse return // pulse mod starts out as just the chemical effect amount - var/pulse_mod = owner.chem_effects[CE_PULSE] - var/is_stable = owner.chem_effects[CE_STABLE] - + var/pulse_mod = GET_CHEMICAL_EFFECT(owner, CE_PULSE) + var/is_stable = GET_CHEMICAL_EFFECT(owner, CE_STABLE) + // If you have enough heart chemicals to be over 2, you're likely to take extra damage. if(pulse_mod > 2 && !is_stable) var/damage_chance = (pulse_mod - 2) ** 2 if(prob(damage_chance)) - take_internal_damage(0.5) - + take_damage(0.5) + // Now pulse mod is impacted by shock stage and other things too if(owner.shock_stage > 30) pulse_mod++ @@ -65,24 +61,25 @@ if(oxy < BLOOD_VOLUME_BAD) //MOAR pulse_mod++ - if(owner.status_flags & FAKEDEATH || owner.chem_effects[CE_NOPULSE]) - pulse = Clamp(PULSE_NONE + pulse_mod, PULSE_NONE, PULSE_2FAST) //pretend that we're dead. unlike actual death, can be inflienced by meds + if(owner.status_flags & FAKEDEATH || GET_CHEMICAL_EFFECT(owner, CE_NOPULSE)) + pulse = clamp(PULSE_NONE + pulse_mod, PULSE_NONE, PULSE_2FAST) //pretend that we're dead. unlike actual death, can be inflienced by meds return //If heart is stopped, it isn't going to restart itself randomly. if(pulse == PULSE_NONE) return - else //and if it's beating, let's see if it should - var/should_stop = prob(80) && owner.get_blood_circulation() < BLOOD_VOLUME_SURVIVE //cardiovascular shock, not enough liquid to pump - should_stop = should_stop || prob(max(0, owner.getBrainLoss() - owner.maxHealth * 0.75)) //brain failing to work heart properly - should_stop = should_stop || (prob(5) && pulse == PULSE_THREADY) //erratic heart patterns, usually caused by oxyloss - if(should_stop) // The heart has stopped due to going into traumatic or cardiovascular shock. - to_chat(owner, "Your heart has stopped!") - pulse = PULSE_NONE - return + + //and if it's beating, let's see if it should + var/should_stop = prob(80) && oxy < BLOOD_VOLUME_SURVIVE //cardiovascular shock, not enough liquid to pump + should_stop = should_stop || prob(max(0, owner.get_damage(BRAIN) - owner.get_max_health() * 0.75)) //brain failing to work heart properly + should_stop = should_stop || (prob(5) && pulse == PULSE_THREADY) //erratic heart patterns, usually caused by oxyloss + if(should_stop) // The heart has stopped due to going into traumatic or cardiovascular shock. + to_chat(owner, SPAN_DANGER("Your heart has stopped!")) + pulse = PULSE_NONE + return // Pulse normally shouldn't go above PULSE_2FAST - pulse = Clamp(PULSE_NORM + pulse_mod, PULSE_SLOW, PULSE_2FAST) + pulse = clamp(PULSE_NORM + pulse_mod, PULSE_SLOW, PULSE_2FAST) // If fibrillation, then it can be PULSE_THREADY var/fibrillation = oxy <= BLOOD_VOLUME_SURVIVE || (prob(30) && owner.shock_stage > 120) @@ -102,7 +99,7 @@ //High pulse value corresponds to a fast rate of heartbeat. //Divided by 2, otherwise it is too slow. var/rate = (PULSE_THREADY - pulse)/2 - if(owner.chem_effects[CE_PULSE] > 2) + if(owner.has_chemical_effect(CE_PULSE, 2)) heartbeat++ if(heartbeat >= rate) @@ -117,14 +114,14 @@ return //Dead or cryosleep people do not pump the blood. - if(!owner || owner.InStasis() || owner.stat == DEAD || owner.bodytemperature < 170) + if(!owner || owner.has_mob_modifier(/decl/mob_modifier/stasis) || owner.stat == DEAD || owner.bodytemperature < 170) return if(pulse != PULSE_NONE || BP_IS_PROSTHETIC(src)) //Bleeding out var/blood_max = 0 var/list/do_spray = list() - for(var/obj/item/organ/external/temp in owner.organs) + for(var/obj/item/organ/external/temp in owner.get_external_organs()) if(BP_IS_PROSTHETIC(temp)) continue @@ -132,25 +129,25 @@ var/open_wound if(temp.status & ORGAN_BLEEDING) - for(var/datum/wound/W in temp.wounds) + for(var/datum/wound/wound in temp.wounds) - if(!open_wound && (W.damage_type == CUT || W.damage_type == PIERCE) && W.damage && !W.is_treated()) + if(!open_wound && (wound.damage_type == CUT || wound.damage_type == PIERCE) && wound.damage && !wound.is_treated()) open_wound = TRUE - if(W.bleeding()) + if(wound.bleeding()) if(temp.applied_pressure) if(ishuman(temp.applied_pressure)) - var/mob/living/carbon/human/H = temp.applied_pressure + var/mob/living/human/H = temp.applied_pressure H.bloody_hands(src, 0) //somehow you can apply pressure to every wound on the organ at the same time //you're basically forced to do nothing at all, so let's make it pretty effective - var/min_eff_damage = max(0, W.damage - 10) / 6 //still want a little bit to drip out, for effect - blood_max += max(min_eff_damage, W.damage - 30) / 40 + var/min_eff_damage = max(0, wound.damage - 10) / 6 //still want a little bit to drip out, for effect + blood_max += max(min_eff_damage, wound.damage - 30) / 40 else - blood_max += W.damage / 40 + blood_max += wound.damage / 40 if(temp.status & ORGAN_ARTERY_CUT) - var/bleed_amount = Floor((owner.vessel.total_volume / (temp.applied_pressure || !open_wound ? 400 : 250))*temp.arterial_bleed_severity) + var/bleed_amount = floor((REAGENT_TOTAL_VOLUME(owner.vessel) / (temp.applied_pressure || !open_wound ? 400 : 250))*temp.arterial_bleed_severity) if(bleed_amount) if(open_wound) blood_max += bleed_amount @@ -166,17 +163,17 @@ if(PULSE_2FAST, PULSE_THREADY) blood_max *= 1.5 - if(CE_STABLE in owner.chem_effects) + if(GET_CHEMICAL_EFFECT(owner, CE_STABLE)) blood_max *= 0.8 - if(world.time >= next_blood_squirt && istype(owner.loc, /turf) && do_spray.len) + if(world.time >= next_blood_squirt && isturf(owner.loc) && do_spray.len) var/spray_organ = pick(do_spray) owner.visible_message( SPAN_DANGER("Blood sprays out from \the [owner]'s [spray_organ]!"), FONT_HUGE(SPAN_DANGER("Blood sprays out from your [spray_organ]!")) ) - owner.Stun(1) - owner.eye_blurry = 2 + SET_STATUS_MAX(owner, STAT_STUN, 1) + owner.set_status_condition(STAT_BLURRY, 2) //AB occurs every heartbeat, this only throttles the visible effect next_blood_squirt = world.time + 80 @@ -190,12 +187,13 @@ owner.drip(blood_max) /obj/item/organ/internal/heart/proc/is_working() - if(!is_usable()) - return FALSE - - return pulse > PULSE_NONE || BP_IS_PROSTHETIC(src) || (owner.status_flags & FAKEDEATH) + return is_usable() && (pulse > PULSE_NONE || BP_IS_PROSTHETIC(src) || (owner.status_flags & FAKEDEATH)) /obj/item/organ/internal/heart/listen() + + if(!owner || (status & (ORGAN_DEAD|ORGAN_CUT_AWAY))) + return "no pulse" + if(BP_IS_PROSTHETIC(src) && is_working()) if(is_bruised()) return "sputtering pump" @@ -221,5 +219,9 @@ . = "[pulsesound] pulse" -/obj/item/organ/internal/heart/get_mechanical_assisted_descriptor() - return "pacemaker-assisted [name]" \ No newline at end of file +/obj/item/organ/internal/heart/rejuvenate(ignore_organ_traits) + . = ..() + if(!BP_IS_PROSTHETIC(src)) + pulse = PULSE_NORM + else + pulse = PULSE_NONE \ No newline at end of file diff --git a/code/modules/organs/internal/insectoid.dm b/code/modules/organs/internal/insectoid.dm new file mode 100644 index 000000000000..9be454266584 --- /dev/null +++ b/code/modules/organs/internal/insectoid.dm @@ -0,0 +1,26 @@ + +/obj/item/organ/internal/heart/insectoid + name = "hemolymph pump" + +/obj/item/organ/internal/stomach/insectoid + name = "digestive sac" + +/obj/item/organ/internal/lungs/insectoid + name = "spiracle junction" + icon_state = "trach" + gender = NEUTER + +/obj/item/organ/internal/liver/insectoid + name = "primary filters" + gender = PLURAL + +/obj/item/organ/internal/kidneys/insectoid + name = "secondary filters" + +/obj/item/organ/internal/brain/insectoid + name = "ganglial junction" + icon_state = "brain-distributed" + +/obj/item/organ/internal/eyes/insectoid + name = "compound ocelli" + icon_state = "eyes-compound" diff --git a/code/modules/organs/internal/kidneys.dm b/code/modules/organs/internal/kidneys.dm index ebdf914430be..31a222f99772 100644 --- a/code/modules/organs/internal/kidneys.dm +++ b/code/modules/organs/internal/kidneys.dm @@ -1,6 +1,7 @@ /obj/item/organ/internal/kidneys name = "kidneys" icon_state = "kidneys" + prosthetic_icon = "kidneys-prosthetic" gender = PLURAL organ_tag = BP_KIDNEYS parent_organ = BP_GROIN @@ -9,10 +10,6 @@ max_damage = 70 relative_size = 10 -/obj/item/organ/internal/kidneys/robotize() - . = ..() - icon_state = "kidneys-prosthetic" - /obj/item/organ/internal/kidneys/Process() ..() @@ -24,23 +21,23 @@ // what else kidneys can process in our reagent list. if(REAGENT_VOLUME(owner.reagents, /decl/material/liquid/drink/coffee)) if(is_bruised()) - owner.adjustToxLoss(0.1) + owner.take_damage(0.1, TOX) else if(is_broken()) - owner.adjustToxLoss(0.3) + owner.take_damage(0.3, TOX) if(is_bruised()) if(prob(5) && REAGENT_VOLUME(reagents, /decl/material/solid/potassium) < 5) - reagents.add_reagent(/decl/material/solid/potassium, REM*5) + add_to_reagents(/decl/material/solid/potassium, REM*5) if(is_broken()) if(REAGENT_VOLUME(owner.reagents, /decl/material/solid/potassium) < 15) - owner.reagents.add_reagent(/decl/material/solid/potassium, REM*2) + owner.add_to_reagents(/decl/material/solid/potassium, REM*2) //If your kidneys aren't working, your body's going to have a hard time cleaning your blood. - if(!owner.chem_effects[CE_ANTITOX]) + if(!GET_CHEMICAL_EFFECT(owner, CE_ANTITOX)) if(prob(33)) if(is_broken()) - owner.adjustToxLoss(0.5) + owner.take_damage(0.5, TOX) if(status & ORGAN_DEAD) - owner.adjustToxLoss(1) + owner.take_damage(1, TOX) diff --git a/code/modules/organs/internal/liver.dm b/code/modules/organs/internal/liver.dm index 42aa7fe45c7c..c672c1c121ae 100644 --- a/code/modules/organs/internal/liver.dm +++ b/code/modules/organs/internal/liver.dm @@ -2,6 +2,7 @@ /obj/item/organ/internal/liver name = "liver" icon_state = "liver" + prosthetic_icon = "liver-prosthetic" w_class = ITEM_SIZE_SMALL organ_tag = BP_LIVER parent_organ = BP_GROIN @@ -9,10 +10,12 @@ min_broken_damage = 45 max_damage = 70 relative_size = 60 + // Liver recovers a lot better than most meat. + min_regeneration_cutoff_threshold = 2 + max_regeneration_cutoff_threshold = 5 -/obj/item/organ/internal/liver/robotize() - . = ..() - icon_state = "liver-prosthetic" +/obj/item/organ/internal/liver/organ_can_heal() + return !GET_CHEMICAL_EFFECT(owner, CE_ALCOHOL) && ..() /obj/item/organ/internal/liver/Process() @@ -20,17 +23,17 @@ if(!owner) return - if (germ_level > INFECTION_LEVEL_ONE) - if(prob(1)) - to_chat(owner, "Your skin itches.") - if (germ_level > INFECTION_LEVEL_TWO) - if(prob(1)) - spawn owner.vomit() + if (germ_level > INFECTION_LEVEL_ONE && prob(1)) + to_chat(owner, SPAN_DANGER("Your skin itches.")) + if (germ_level > INFECTION_LEVEL_TWO && prob(1)) + owner.vomit() //Detox can heal small amounts of damage - if (damage < max_damage && !owner.chem_effects[CE_TOXIN]) - heal_damage(0.2 * owner.chem_effects[CE_ANTITOX]) + if (_organ_damage < max_damage && !GET_CHEMICAL_EFFECT(owner, CE_TOXIN)) + heal_damage(0.2 * GET_CHEMICAL_EFFECT(owner, CE_ANTITOX)) + var/alco = GET_CHEMICAL_EFFECT(owner, CE_ALCOHOL) + var/alcotox = GET_CHEMICAL_EFFECT(owner, CE_ALCOHOL_TOXIC) // Get the effectiveness of the liver. var/filter_effect = 3 if(is_bruised()) @@ -40,25 +43,18 @@ // Robotic organs filter better but don't get benefits from antitoxins for filtering. if(BP_IS_PROSTHETIC(src)) filter_effect += 1 - else if(owner.chem_effects[CE_ANTITOX]) + else if(owner.has_chemical_effect(CE_ANTITOX, 1)) filter_effect += 1 // If you're not filtering well, you're in trouble. Ammonia buildup to toxic levels and damage from alcohol if(filter_effect < 2) - if(owner.chem_effects[CE_ALCOHOL]) - owner.adjustToxLoss(0.5 * max(2 - filter_effect, 0) * (owner.chem_effects[CE_ALCOHOL_TOXIC] + 0.5 * owner.chem_effects[CE_ALCOHOL])) + if(alco) + owner.take_damage(0.5 * max(2 - filter_effect, TOX, 0) * (alcotox + 0.5 * alco)) - if(owner.chem_effects[CE_ALCOHOL_TOXIC]) - take_internal_damage(owner.chem_effects[CE_ALCOHOL_TOXIC], prob(90)) // Chance to warn them - - // Heal a bit if needed and we're not busy. This allows recovery from low amounts of toxloss. - if(!owner.chem_effects[CE_ALCOHOL] && !owner.chem_effects[CE_TOXIN] && !owner.radiation && damage > 0) - if(damage < min_broken_damage) - heal_damage(0.2) - if(damage < min_bruised_damage) - heal_damage(0.3) + if(alcotox) + take_damage(alcotox, prob(90)) // Chance to warn them //Blood regeneration if there is some space - owner.regenerate_blood(0.1 + owner.chem_effects[CE_BLOODRESTORE]) + owner.regenerate_blood(0.1 + GET_CHEMICAL_EFFECT(owner, CE_BLOODRESTORE)) // Blood loss or liver damage make you lose nutriments var/blood_volume = owner.get_blood_volume() @@ -67,7 +63,3 @@ owner.adjust_nutrition(-10) else if(owner.nutrition >= 200) owner.adjust_nutrition(-3) - -//We got it covered in Process with more detailed thing -/obj/item/organ/internal/liver/handle_regeneration() - return \ No newline at end of file diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm index 591d751136e7..aeea20125422 100644 --- a/code/modules/organs/internal/lungs.dm +++ b/code/modules/organs/internal/lungs.dm @@ -1,6 +1,7 @@ /obj/item/organ/internal/lungs name = "lungs" icon_state = "lungs" + prosthetic_icon = "lungs-prosthetic" gender = PLURAL organ_tag = BP_LUNGS parent_organ = BP_CHEST @@ -10,7 +11,7 @@ max_damage = 70 relative_size = 60 - var/active_breathing = 1 + var/active_breathing = TRUE var/has_gills = FALSE var/breath_type var/exhale_type @@ -22,63 +23,84 @@ var/max_pressure_diff = 60 var/oxygen_deprivation = 0 - var/safe_exhaled_max = 6 var/safe_toxins_max = 0.2 - var/SA_para_min = 1 - var/SA_sleep_min = 5 var/breathing = 0 var/last_successful_breath var/breath_fail_ratio // How badly they failed a breath. Higher is worse. -/obj/item/organ/internal/lungs/proc/can_drown() - return (is_broken() || !has_gills) + var/datum/reagents/metabolism/inhaled + +/obj/item/organ/internal/lungs/Destroy() + QDEL_NULL(inhaled) + . = ..() -/obj/item/organ/internal/lungs/proc/remove_oxygen_deprivation(var/amount) - var/last_suffocation = oxygen_deprivation - oxygen_deprivation = min(species.total_health,max(0,oxygen_deprivation - amount)) - return -(oxygen_deprivation - last_suffocation) +/obj/item/organ/internal/lungs/Serialize() + . = ..() + SERIALIZE_REAGENTS(inhaled, /obj/item/organ/internal/lungs, "inhaled") -/obj/item/organ/internal/lungs/proc/add_oxygen_deprivation(var/amount) - var/last_suffocation = oxygen_deprivation - oxygen_deprivation = min(species.total_health,max(0,oxygen_deprivation + amount)) - return (oxygen_deprivation - last_suffocation) +/obj/item/organ/internal/lungs/Deserialize(list/instance_map) + . = ..() + DESERIALIZE_REAGENTS(inhaled, "inhaled") + +/obj/item/organ/internal/lungs/initialize_reagents() + FINALIZE_REAGENTS_SERDE(inhaled) + if(!inhaled) + inhaled = new/datum/reagents/metabolism(240, src, CHEM_INHALE) + var/owner_atom = owner || src + REAGENT_SET_ATOM(inhaled, owner_atom) + . = ..() -// Returns a percentage value for use by GetOxyloss(). -/obj/item/organ/internal/lungs/proc/get_oxygen_deprivation() - if(status & ORGAN_DEAD) - return 100 - return round((oxygen_deprivation/species.total_health)*100) +/obj/item/organ/internal/lungs/do_install(mob/living/human/target, obj/item/organ/external/affected, in_place) + if(!(. = ..())) + return + REAGENT_SET_ATOM(inhaled, owner) + inhaled.parent = owner -/obj/item/organ/internal/lungs/robotize() +/obj/item/organ/internal/lungs/do_uninstall(in_place, detach, ignore_children) . = ..() - icon_state = "lungs-prosthetic" + if(inhaled) + REAGENT_SET_ATOM(inhaled, src) + inhaled.parent = null -/obj/item/organ/internal/lungs/set_dna(var/datum/dna/new_dna) - ..() - sync_breath_types() - max_pressure_diff = species.max_pressure_diff +/obj/item/organ/internal/lungs/proc/can_drown() + return !has_gills || !is_usable() -/obj/item/organ/internal/lungs/replaced() - ..() +/obj/item/organ/internal/lungs/proc/adjust_oxygen_deprivation(var/amount) + oxygen_deprivation = clamp(oxygen_deprivation + amount, 0, species.total_health) + +/obj/item/organ/internal/lungs/set_species(species_uid) + . = ..() sync_breath_types() /** * Set these lungs' breath types based on the lungs' species */ /obj/item/organ/internal/lungs/proc/sync_breath_types() - min_breath_pressure = species.breath_pressure - breath_type = species.breath_type ? species.breath_type : /decl/material/gas/oxygen - poison_types = species.poison_types ? species.poison_types : list(/decl/material/gas/chlorine = TRUE) - exhale_type = species.exhale_type ? species.exhale_type : /decl/material/gas/carbon_dioxide + if(species) + max_pressure_diff = species.max_pressure_diff + min_breath_pressure = species.breath_pressure + breath_type = species.breath_type || /decl/material/gas/oxygen + poison_types = species.poison_types || list(/decl/material/gas/chlorine = TRUE) + exhale_type = species.exhale_type || /decl/material/gas/carbon_dioxide + else + max_pressure_diff = initial(max_pressure_diff) + min_breath_pressure = initial(min_breath_pressure) + breath_type = /decl/material/gas/oxygen + poison_types = list(/decl/material/gas/chlorine = TRUE) + exhale_type = /decl/material/gas/carbon_dioxide /obj/item/organ/internal/lungs/Process() ..() if(!owner) return + if(owner.vital_organ_missing_time) + owner.suffocation_counter = max(10, owner.suffocation_counter) + return + if (germ_level > INFECTION_LEVEL_ONE && active_breathing) if(prob(5)) - owner.emote("cough") //respitory tract infection + owner.cough() //respitory tract infection if(is_bruised() && !owner.is_asystole()) if(prob(2)) @@ -89,7 +111,7 @@ "You hear someone coughing!", ) else - var/obj/item/organ/parent = owner.get_organ(parent_organ) + var/obj/item/organ/parent = GET_EXTERNAL_ORGAN(owner, parent_organ) owner.visible_message( "blood drips from \the [owner]'s [parent.name]!", ) @@ -105,10 +127,10 @@ else to_chat(owner, "You're having trouble getting enough [breath_type]!") - owner.losebreath += round(damage/2) + owner.suffocation_counter = max(3, owner.suffocation_counter) /obj/item/organ/internal/lungs/proc/rupture() - var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(owner, parent_organ) if(istype(parent)) owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50, affecting = parent) bruise() @@ -127,7 +149,7 @@ if(!is_bruised() && lung_rupture_prob) //only rupture if NOT already ruptured rupture() -/obj/item/organ/internal/lungs/proc/handle_breath(datum/gas_mixture/breath, var/forced) +/obj/item/organ/internal/lungs/proc/handle_owner_breath(datum/gas_mixture/breath, var/forced) if(!owner) return 1 @@ -150,10 +172,14 @@ var/safe_pressure_min = min_breath_pressure // Minimum safe partial pressure of breathable gas in kPa // Lung damage increases the minimum safe pressure. - safe_pressure_min *= 1 + rand(1,4) * damage/max_damage + safe_pressure_min *= 1 + rand(1,4) * _organ_damage/max_damage - if(!forced && owner.chem_effects[CE_BREATHLOSS] && !owner.chem_effects[CE_STABLE]) //opiates are bad mmkay - safe_pressure_min *= 1 + rand(1,4) * owner.chem_effects[CE_BREATHLOSS] + var/breatheffect = GET_CHEMICAL_EFFECT(owner, CE_BREATHLOSS) + if(!forced && breatheffect && !GET_CHEMICAL_EFFECT(owner, CE_STABLE)) //opiates are bad mmkay + safe_pressure_min *= 1 + breatheffect + + if(owner.current_posture.prone) + safe_pressure_min *= 0.8 var/failed_inhale = 0 var/failed_exhale = 0 @@ -164,21 +190,23 @@ // Not enough to breathe if(inhale_efficiency < 1) if(prob(20) && active_breathing) - if(inhale_efficiency < 0.8) - owner.emote("gasp") + if(inhale_efficiency < 0.6) + owner.emote(/decl/emote/audible/gasp) else if(prob(20)) to_chat(owner, SPAN_WARNING("It's hard to breathe...")) - breath_fail_ratio = 1 - inhale_efficiency + breath_fail_ratio = clamp(0,(1 - inhale_efficiency + breath_fail_ratio)/2,1) failed_inhale = 1 else - breath_fail_ratio = 0 + if(breath_fail_ratio && prob(20)) + to_chat(owner, SPAN_NOTICE("It gets easier to breathe.")) + breath_fail_ratio = clamp(0,breath_fail_ratio-0.05,1) - owner.oxygen_alert = failed_inhale * 2 + SET_HUD_ALERT(owner, HUD_OXY, (failed_inhale * 2)) var/inhaled_gas_used = inhaling / 4 breath.adjust_gas(breath_type, -inhaled_gas_used, update = 0) //update afterwards - owner.toxins_alert = 0 // Reset our toxins alert for now. + SET_HUD_ALERT(owner, HUD_TOX, 0) // Reset our toxins alert for now. if(!failed_inhale) // Enough gas to tell we're being poisoned via chemical burns or whatever. var/poison_total = 0 if(poison_types) @@ -186,32 +214,33 @@ if(poison_types[gname]) poison_total += breath.gas[gname] if(((poison_total/breath.total_moles)*breath_pressure) > safe_toxins_max) - owner.toxins_alert = 1 + SET_HUD_ALERT(owner, HUD_TOX, 1) // Pass reagents from the gas into our body. // Presumably if you breathe it you have a specialized metabolism for it, so we drop/ignore breath_type. Also avoids - // humans processing thousands of units of oxygen over the course of a round for the sole purpose of poisoning vox. + // humans processing thousands of units of oxygen over the course of a round. var/ratio = BP_IS_PROSTHETIC(src)? 0.66 : 1 for(var/gasname in breath.gas - breath_type) - var/decl/material/gas = decls_repository.get_decl(gasname) + var/decl/material/gas = GET_DECL(gasname) if(gas.gas_metabolically_inert) continue // Little bit of sanity so we aren't trying to add 0.0000000001 units of CO2, and so we don't end up with 99999 units of CO2. var/reagent_amount = breath.gas[gasname] * REAGENT_UNITS_PER_GAS_MOLE * ratio - if(reagent_amount < 0.05) + if(reagent_amount < MINIMUM_CHEMICAL_VOLUME) continue - owner.reagents.add_reagent(gasname, reagent_amount) + inhaled.add_reagent(gasname, reagent_amount) breath.adjust_gas(gasname, -breath.gas[gasname], update = 0) //update after // Moved after reagent injection so we don't instantly poison ourselves with CO2 or whatever. - if(exhale_type && (!istype(owner.wear_mask) || !(exhale_type in owner.wear_mask.filtered_gases))) + var/obj/item/clothing/mask/mask = owner.get_equipped_item(slot_wear_mask_str) + if(exhale_type && (!istype(mask) || !(exhale_type in mask.filtered_gases))) breath.adjust_gas_temp(exhale_type, inhaled_gas_used, owner.bodytemperature, update = 0) //update afterwards // Were we able to breathe? var/failed_breath = failed_inhale || failed_exhale if(!failed_breath) last_successful_breath = world.time - owner.adjustOxyLoss(-5 * inhale_efficiency) + owner.heal_damage(OXY, 5 * inhale_efficiency) if(!BP_IS_PROSTHETIC(src) && species.breathing_sound && is_below_sound_pressure(get_turf(owner))) if(breathing || owner.shock_stage >= 10) sound_to(owner, sound(species.breathing_sound,0,0,0,5)) @@ -225,60 +254,60 @@ if(failed_breath) handle_failed_breath() else - owner.oxygen_alert = 0 + SET_HUD_ALERT(owner, HUD_OXY, 0) return failed_breath /obj/item/organ/internal/lungs/proc/handle_failed_breath() if(prob(15) && !owner.nervous_system_failure()) if(!owner.is_asystole()) if(active_breathing) - owner.emote("gasp") + owner.emote(/decl/emote/audible/gasp) else - owner.emote(pick("shiver","twitch")) + owner.emote(pick(/decl/emote/visible/shiver,/decl/emote/visible/twitch)) - if(damage || owner.chem_effects[CE_BREATHLOSS] || world.time > last_successful_breath + 2 MINUTES) - owner.adjustOxyLoss(HUMAN_MAX_OXYLOSS*breath_fail_ratio) + if(_organ_damage || GET_CHEMICAL_EFFECT(owner, CE_BREATHLOSS) || world.time > last_successful_breath + 2 MINUTES) + owner.take_damage(HUMAN_MAX_OXYLOSS*breath_fail_ratio, OXY) - owner.oxygen_alert = max(owner.oxygen_alert, 2) + SET_HUD_ALERT_MAX(owner, HUD_OXY, 2) last_int_pressure = 0 /obj/item/organ/internal/lungs/proc/handle_temperature_effects(datum/gas_mixture/breath) // Hot air hurts :( - if((breath.temperature < species.cold_level_1 || breath.temperature > species.heat_level_1) && !(MUTATION_COLD_RESISTANCE in owner.mutations)) - var/damage = 0 - if(breath.temperature <= species.cold_level_1) + var/cold_1 = bodytype.get_body_temperature_threshold(COLD_LEVEL_1) + var/heat_1 = bodytype.get_body_temperature_threshold(HEAT_LEVEL_1) + if((breath.temperature < cold_1 || breath.temperature > heat_1) && !owner.has_genetic_condition(GENE_COND_COLD_RESISTANCE)) + var/breath_damage = 0 + if(breath.temperature <= cold_1) if(prob(20)) to_chat(owner, "You feel your face freezing and icicles forming in your lungs!") - switch(breath.temperature) - if(species.cold_level_3 to species.cold_level_2) - damage = COLD_GAS_DAMAGE_LEVEL_3 - if(species.cold_level_2 to species.cold_level_1) - damage = COLD_GAS_DAMAGE_LEVEL_2 - else - damage = COLD_GAS_DAMAGE_LEVEL_1 + if(breath.temperature < bodytype.get_body_temperature_threshold(COLD_LEVEL_3)) + breath_damage = COLD_GAS_DAMAGE_LEVEL_3 + else if(breath.temperature < bodytype.get_body_temperature_threshold(COLD_LEVEL_2)) + breath_damage = COLD_GAS_DAMAGE_LEVEL_2 + else + breath_damage = COLD_GAS_DAMAGE_LEVEL_1 if(prob(20)) - owner.apply_damage(damage, BURN, BP_HEAD, used_weapon = "Excessive Cold") + owner.apply_damage(breath_damage, BURN, BP_HEAD, used_weapon = "Excessive Cold") else - src.damage += damage - owner.fire_alert = 1 - else if(breath.temperature >= species.heat_level_1) + _organ_damage += breath_damage + SET_HUD_ALERT(owner, HUD_FIRE, 1) + else if(breath.temperature >= heat_1) if(prob(20)) to_chat(owner, "You feel your face burning and a searing heat in your lungs!") - switch(breath.temperature) - if(species.heat_level_1 to species.heat_level_2) - damage = HEAT_GAS_DAMAGE_LEVEL_1 - if(species.heat_level_2 to species.heat_level_3) - damage = HEAT_GAS_DAMAGE_LEVEL_2 - else - damage = HEAT_GAS_DAMAGE_LEVEL_3 + if(breath.temperature < bodytype.get_body_temperature_threshold(HEAT_LEVEL_2)) + breath_damage = HEAT_GAS_DAMAGE_LEVEL_1 + else if(breath.temperature < bodytype.get_body_temperature_threshold(HEAT_LEVEL_3)) + breath_damage = HEAT_GAS_DAMAGE_LEVEL_2 + else + breath_damage = HEAT_GAS_DAMAGE_LEVEL_3 if(prob(20)) - owner.apply_damage(damage, BURN, BP_HEAD, used_weapon = "Excessive Heat") + owner.apply_damage(breath_damage, BURN, BP_HEAD, used_weapon = "Excessive Heat") else - src.damage += damage - owner.fire_alert = 2 + _organ_damage += breath_damage + SET_HUD_ALERT(owner, HUD_FIRE, 2) //breathing in hot/cold air also heats/cools you a bit var/temp_adj = breath.temperature - owner.bodytemperature @@ -287,7 +316,7 @@ else temp_adj /= (BODYTEMP_HEAT_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed - var/relative_density = breath.total_moles / (MOLES_CELLSTANDARD * breath.volume/CELL_VOLUME) + var/relative_density = breath.total_moles / (MOLES_CELLSTANDARD * breath.total_volume/CELL_VOLUME) temp_adj *= relative_density if (temp_adj > BODYTEMP_HEATING_MAX) temp_adj = BODYTEMP_HEATING_MAX @@ -295,13 +324,18 @@ // log_debug("Breath: [breath.temperature], [src]: [bodytemperature], Adjusting: [temp_adj]") owner.bodytemperature += temp_adj - else if(breath.temperature >= species.heat_discomfort_level) - species.get_environment_discomfort(owner,"heat") - else if(breath.temperature <= species.cold_discomfort_level) - species.get_environment_discomfort(owner,"cold") + else + // Get root bodytype as discomfort messages are not specifically related to the lungs. + var/decl/bodytype/root_bodytype = owner?.get_bodytype() || bodytype + if(root_bodytype) + if(breath.temperature >= root_bodytype.heat_discomfort_level) + root_bodytype.get_environment_discomfort(owner,"heat") + else if(breath.temperature <= root_bodytype.cold_discomfort_level) + root_bodytype.get_environment_discomfort(owner,"cold") /obj/item/organ/internal/lungs/listen() - if(owner.failed_last_breath || !active_breathing) + + if((status & (ORGAN_DEAD|ORGAN_CUT_AWAY)) || !owner || owner.failed_last_breath || !active_breathing) return "no respiration" if(BP_IS_PROSTHETIC(src)) @@ -315,7 +349,7 @@ . += "[pick("wheezing", "gurgling")] sounds" var/list/breathtype = list() - if(get_oxygen_deprivation() > 50) + if(owner.getOxyLossPercent() > 50) breathtype += pick("straining","labored") if(owner.shock_stage > 50) breathtype += pick("shallow and rapid") @@ -324,4 +358,32 @@ . += "[english_list(breathtype)] breathing" - return english_list(.) \ No newline at end of file + return english_list(.) + +/obj/item/organ/internal/lungs/gills + name = "lungs and gills" + has_gills = TRUE + +/mob/living/proc/cough(silent = FALSE, deliberate = FALSE) + + var/obj/item/organ/internal/lungs/lung = get_organ(BP_LUNGS) + if(!lung || !lung.active_breathing || isSynthetic() || stat == DEAD || (deliberate && last_cough + 3 SECONDS > world.time)) + return + + if(lung.breath_fail_ratio > 0.9 && world.time > lung.last_successful_breath + 2 MINUTES) + if(deliberate) + to_chat(src, SPAN_WARNING("You try to cough, but no air comes out!")) + return + + if(deliberate && incapacitated()) + to_chat(src, SPAN_WARNING("You cannot do that right now.")) + return + + if(!silent) + audible_message("[src] coughs!", "You cough!", radio_message = "coughs!") // styled like an emote + + last_cough = world.time + + // Coughing clears out 1-2 reagents from the lungs. + if(REAGENT_TOTAL_VOLUME(lung.inhaled) > 0 && loc) + lung.inhaled.splash(loc, rand(1, 2)) \ No newline at end of file diff --git a/code/modules/organs/internal/posibrain.dm b/code/modules/organs/internal/posibrain.dm deleted file mode 100644 index 14c43facaab1..000000000000 --- a/code/modules/organs/internal/posibrain.dm +++ /dev/null @@ -1,379 +0,0 @@ -/obj/item/organ/internal/posibrain - name = "positronic brain" - desc = "A cube of shining metal, four inches to a side and covered in shallow grooves." - icon = 'icons/obj/assemblies.dmi' - icon_state = "posibrain" - organ_tag = BP_POSIBRAIN - parent_organ = BP_CHEST - vital = 0 - force = 1.0 - w_class = ITEM_SIZE_NORMAL - throwforce = 1.0 - throw_speed = 3 - throw_range = 5 - origin_tech = "{'engineering':4,'materials':4,'wormholes':2,'programming':4}" - attack_verb = list("attacked", "slapped", "whacked") - material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, - /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, - /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE - ) - relative_size = 60 - req_access = list(access_robotics) - - var/mob/living/silicon/sil_brainmob/brainmob = null - var/searching = 0 - var/askDelay = 10 * 60 * 1 - var/list/shackled_verbs = list( - /obj/item/organ/internal/posibrain/proc/show_laws_brain, - /obj/item/organ/internal/posibrain/proc/brain_checklaws - ) - var/shackle = 0 - -/obj/item/organ/internal/posibrain/Initialize() - . = ..() - if(!brainmob && iscarbon(loc)) - init(loc) - robotize() - unshackle() - update_icon() - -/obj/item/organ/internal/posibrain/proc/init(var/mob/living/carbon/H) - brainmob = new(src) - - if(istype(H)) - brainmob.SetName(H.real_name) - brainmob.real_name = H.real_name - brainmob.dna = H.dna.Clone() - brainmob.add_language(/decl/language/human/common) - -/obj/item/organ/internal/posibrain/Destroy() - QDEL_NULL(brainmob) - return ..() - -/obj/item/organ/internal/posibrain/attack_self(mob/user) - if(brainmob && !brainmob.key && searching == 0) - //Start the process of searching for a new user. - to_chat(user, "You carefully locate the manual activation switch and start the positronic brain's boot process.") - icon_state = "posibrain-searching" - src.searching = 1 - var/datum/ghosttrap/G = get_ghost_trap("positronic brain") - G.request_player(brainmob, "Someone is requesting a personality for a positronic brain.", 60 SECONDS) - spawn(600) reset_search() - -/obj/item/organ/internal/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer. - if(src.brainmob && src.brainmob.key) return - - src.searching = 0 - icon_state = "posibrain" - - var/turf/T = get_turf_or_move(src.loc) - for (var/mob/M in viewers(T)) - M.show_message("The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?") - -/obj/item/organ/internal/posibrain/attack_ghost(var/mob/observer/ghost/user) - if(!searching || (src.brainmob && src.brainmob.key)) - return - - var/datum/ghosttrap/G = get_ghost_trap("positronic brain") - if(!G.assess_candidate(user)) - return - var/response = alert(user, "Are you sure you wish to possess this [src]?", "Possess [src]", "Yes", "No") - if(response == "Yes") - G.transfer_personality(user, brainmob) - return - -/obj/item/organ/internal/posibrain/examine(mob/user) - . = ..() - - var/msg = "*---------*\nThis is \icon[src] \a [src]!\n[desc]\n" - - if(shackle) msg += "It is clamped in a set of metal straps with a complex digital lock.\n" - - msg += "" - - if(src.brainmob && src.brainmob.key) - switch(src.brainmob.stat) - if(CONSCIOUS) - if(!src.brainmob.client) msg += "It appears to be in stand-by mode.\n" //afk - if(UNCONSCIOUS) msg += "It doesn't seem to be responsive.\n" - if(DEAD) msg += "It appears to be completely inactive.\n" - else - msg += "It appears to be completely inactive.\n" - - msg += "*---------*" - to_chat(user, msg) - return - -/obj/item/organ/internal/posibrain/emp_act(severity) - if(!src.brainmob) - return - else - switch(severity) - if(1) - src.brainmob.emp_damage += rand(20,30) - if(2) - src.brainmob.emp_damage += rand(10,20) - if(3) - src.brainmob.emp_damage += rand(0,10) - ..() - -/obj/item/organ/internal/posibrain/proc/PickName() - src.brainmob.SetName("[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[random_id(type,100,999)]") - src.brainmob.real_name = src.brainmob.name - -/obj/item/organ/internal/posibrain/proc/shackle(var/given_lawset) - if(given_lawset) - brainmob.laws = given_lawset - shackle = 1 - verbs |= shackled_verbs - update_icon() - return 1 - -/obj/item/organ/internal/posibrain/proc/unshackle() - shackle = 0 - verbs -= shackled_verbs - update_icon() - -/obj/item/organ/internal/posibrain/on_update_icon() - if(src.brainmob && src.brainmob.key) - icon_state = "posibrain-occupied" - else - icon_state = "posibrain" - - overlays.Cut() - if(shackle) - overlays |= image('icons/obj/assemblies.dmi', "posibrain-shackles") - -/obj/item/organ/internal/posibrain/proc/transfer_identity(var/mob/living/carbon/H) - if(H && H.mind) - brainmob.set_stat(CONSCIOUS) - H.mind.transfer_to(brainmob) - brainmob.SetName(H.real_name) - brainmob.real_name = H.real_name - brainmob.dna = H.dna.Clone() - brainmob.show_laws(brainmob) - - update_icon() - - to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].") - callHook("debrain", list(brainmob)) - -/obj/item/organ/internal/posibrain/removed(var/mob/living/user) - if(!istype(owner)) - return ..() - - if(name == initial(name)) - SetName("\the [owner.real_name]'s [initial(name)]") - - transfer_identity(owner) - - ..() - -/obj/item/organ/internal/posibrain/replaced(var/mob/living/target) - - if(!..()) return 0 - - if(target.key) - target.ghostize() - - if(brainmob) - if(brainmob.mind) - brainmob.mind.transfer_to(target) - else - target.key = brainmob.key - - return 1 - -/* - This is for law stuff directly. This is how a human mob will be able to communicate with the posi_brainmob in the - posibrain organ for laws when the posibrain organ is shackled. -*/ -/obj/item/organ/internal/posibrain/proc/show_laws_brain() - set category = "Shackle" - set name = "Show Laws" - set src in usr - - brainmob.show_laws(owner) - -/obj/item/organ/internal/posibrain/proc/brain_checklaws() - set category = "Shackle" - set name = "State Laws" - set src in usr - - - brainmob.open_subsystem(/datum/nano_module/law_manager, usr) - - -/obj/item/organ/internal/cell - name = "microbattery" - desc = "A small, powerful cell for use in fully prosthetic bodies." - icon_state = "cell" - dead_icon = "cell_bork" - organ_tag = BP_CELL - parent_organ = BP_CHEST - vital = 1 - var/open - var/obj/item/cell/cell = /obj/item/cell/hyper - //at 0.8 completely depleted after 60ish minutes of constant walking or 130 minutes of standing still - var/servo_cost = 0.8 - -/obj/item/organ/internal/cell/Initialize() - if(ispath(cell)) - cell = new cell(src) - . = ..() - -/obj/item/organ/internal/cell/proc/percent() - if(!cell) - return 0 - return get_charge()/cell.maxcharge * 100 - -/obj/item/organ/internal/cell/proc/get_charge() - if(!cell) - return 0 - if(status & ORGAN_DEAD) - return 0 - return round(cell.charge*(1 - damage/max_damage)) - -/obj/item/organ/internal/cell/proc/checked_use(var/amount) - if(!is_usable()) - return FALSE - return cell && cell.checked_use(amount) - -/obj/item/organ/internal/cell/proc/use(var/amount) - if(!is_usable()) - return 0 - return cell && cell.use(amount) - -/obj/item/organ/internal/cell/proc/get_power_drain() - var/damage_factor = 1 + 10 * damage/max_damage - return servo_cost * damage_factor - -/obj/item/organ/internal/cell/Process() - ..() - if(!owner) - return - if(owner.stat == DEAD) //not a drain anymore - return - var/cost = get_power_drain() - if(world.time - owner.l_move_time < 15) - cost *= 2 - if(!checked_use(cost) && owner.isSynthetic()) - if(!owner.lying && !owner.buckled) - to_chat(owner, "You don't have enough energy to function!") - owner.Paralyse(3) - -/obj/item/organ/internal/cell/emp_act(severity) - ..() - if(cell) - cell.emp_act(severity) - -/obj/item/organ/internal/cell/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - if(open) - open = 0 - to_chat(user, "You screw the battery panel in place.") - else - open = 1 - to_chat(user, "You unscrew the battery panel.") - - if(isCrowbar(W)) - if(open) - if(cell) - user.put_in_hands(cell) - to_chat(user, "You remove \the [cell] from \the [src].") - cell = null - - if (istype(W, /obj/item/cell)) - if(open) - if(cell) - to_chat(user, "There is a power cell already installed.") - else if(user.unEquip(W, src)) - cell = W - to_chat(user, "You insert \the [cell].") - -/obj/item/organ/internal/cell/replaced() - ..() - // This is very ghetto way of rebooting an IPC. TODO better way. - if(owner && owner.stat == DEAD) - owner.set_stat(CONSCIOUS) - owner.visible_message("\The [owner] twitches visibly!") - -/obj/item/organ/internal/cell/listen() - if(get_charge()) - return "faint hum of the power bank" - -// Used for an MMI or posibrain being installed into a human. -/obj/item/organ/internal/mmi_holder - name = "brain interface" - icon_state = "mmi-empty" - organ_tag = BP_BRAIN - parent_organ = BP_HEAD - vital = 1 - var/obj/item/mmi/stored_mmi - var/datum/mind/persistantMind //Mind that the organ will hold on to after being removed, used for transfer_and_delete - var/ownerckey // used in the event the owner is out of body - -/obj/item/organ/internal/mmi_holder/Destroy() - stored_mmi = null - return ..() - -/obj/item/organ/internal/mmi_holder/Initialize(mapload, var/internal) - . = ..() - if(!stored_mmi) - stored_mmi = new(src) - sleep(-1) - update_from_mmi() - persistantMind = owner.mind - ownerckey = owner.ckey - -/obj/item/organ/internal/mmi_holder/proc/update_from_mmi() - - if(!stored_mmi.brainmob) - stored_mmi.brainmob = new(stored_mmi) - stored_mmi.brainobj = new(stored_mmi) - stored_mmi.brainmob.container = stored_mmi - stored_mmi.brainmob.real_name = owner.real_name - stored_mmi.brainmob.SetName(stored_mmi.brainmob.real_name) - stored_mmi.SetName("[initial(stored_mmi.name)] ([owner.real_name])") - - if(!owner) return - - name = stored_mmi.name - desc = stored_mmi.desc - icon = stored_mmi.icon - - stored_mmi.icon_state = "mmi-full" - icon_state = stored_mmi.icon_state - - if(owner && owner.stat == DEAD) - owner.set_stat(CONSCIOUS) - owner.switch_from_dead_to_living_mob_list() - owner.visible_message("\The [owner] twitches visibly!") - -/obj/item/organ/internal/mmi_holder/cut_away(var/mob/living/user) - var/obj/item/organ/external/parent = owner.get_organ(parent_organ) - if(istype(parent)) - removed(user, 0) - parent.implants += transfer_and_delete() - -/obj/item/organ/internal/mmi_holder/removed() - if(owner && owner.mind) - persistantMind = owner.mind - if(owner.ckey) - ownerckey = owner.ckey - ..() - -/obj/item/organ/internal/mmi_holder/proc/transfer_and_delete() - if(stored_mmi) - . = stored_mmi - stored_mmi.forceMove(src.loc) - if(persistantMind) - persistantMind.transfer_to(stored_mmi.brainmob) - else - var/response = input(find_dead_player(ownerckey, 1), "Your [initial(stored_mmi.name)] has been removed from your body. Do you wish to return to life?", "Robotic Rebirth") as anything in list("Yes", "No") - if(response == "Yes") - persistantMind.transfer_to(stored_mmi.brainmob) - qdel(src) \ No newline at end of file diff --git a/code/modules/organs/internal/species/adherent.dm b/code/modules/organs/internal/species/adherent.dm deleted file mode 100644 index 09df31041218..000000000000 --- a/code/modules/organs/internal/species/adherent.dm +++ /dev/null @@ -1,156 +0,0 @@ -#define PROTOCOL_ARTICLE "Protocol article [rand(100,999)]-[uppertext(pick(GLOB.full_alphabet))] subsection #[rand(10,99)]" - -/obj/item/organ/internal/brain/adherent - name = "mentality matrix" - desc = "The self-contained, self-supporting internal 'brain' of an Adherent unit." - icon = 'icons/mob/human_races/species/adherent/organs.dmi' - icon_state = "brain" - action_button_name = "Reset Ident" - var/next_rename - var/rename_delay = 15 MINUTES - -/obj/item/organ/internal/brain/adherent/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "adherent-brain" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/internal/brain/adherent/attack_self(var/mob/user) - . = ..() - if(.) - - var/regex/name_regex = regex("\[A-Z\]{2}-\[A-Z\]{1} \[0-9\]{4}") - name_regex.Find(owner.real_name) - - if(world.time < next_rename) - to_chat(owner, "[PROTOCOL_ARTICLE] forbids changing your ident again so soon.") - return - - var/res = name_regex.match - if(isnull(res)) - to_chat(user, "Nonstandard names are not subject to real-time modification under [PROTOCOL_ARTICLE].") - return - - var/newname = sanitizeSafe(input(user, "Enter a new ident.", "Reset Ident") as text, MAX_NAME_LEN) - if(newname) - var/confirm = input(user, "Are you sure you wish your name to become [newname] [res]?","Reset Ident") as anything in list("No", "Yes") - if(confirm == "Yes" && owner && user == owner && !owner.incapacitated() && world.time >= next_rename) - next_rename = world.time + rename_delay - owner.real_name = "[newname] [res]" - if(owner.mind) - owner.mind.name = owner.real_name - owner.SetName(owner.real_name) - to_chat(user, "You are now designated [owner.real_name].") - -/obj/item/organ/internal/powered - icon = 'icons/mob/human_races/species/adherent/organs.dmi' - var/maintenance_cost = 1 - var/base_action_state - var/active = FALSE - var/use_descriptor - -/obj/item/organ/internal/powered/Process() - . = ..() - if(owner) - var/obj/item/organ/internal/cell/cell = locate() in owner.internal_organs - if(active && !(cell && cell.use(maintenance_cost))) - active = FALSE - to_chat(owner, "Your [name] [gender == PLURAL ? "are" : "is"] out of power!") - refresh_action_button() - -/obj/item/organ/internal/powered/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "[base_action_state]-[active ? "on" : "off"]" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/internal/powered/attack_self(var/mob/user) - . = ..() - if(.) - sound_to(user, sound('sound/effects/ding2.ogg')) - if(is_broken()) - to_chat(owner, "\The [src] [gender == PLURAL ? "are" : "is"] too damaged to function.") - active = FALSE - else - active = !active - to_chat(owner, "You are [active ? "now" : "no longer"] using your [name] to [use_descriptor].") - refresh_action_button() - -/obj/item/organ/internal/powered/jets - name = "maneuvering jets" - desc = "Gas jets from a Adherent chassis." - action_button_name = "Toggle Maneuvering Pack" - use_descriptor = "adjust your vector" - organ_tag = BP_JETS - parent_organ = BP_CHEST - gender = PLURAL - icon_state = "jets" - base_action_state = "adherent-pack" - maintenance_cost = 2 - -/obj/item/organ/internal/powered/float - name = "levitation plate" - desc = "A broad, flat disc of exotic matter. Slick to the touch." - action_button_name = "Toggle Antigravity" - organ_tag = BP_FLOAT - parent_organ = BP_GROIN - icon_state = "float" - use_descriptor = "hover" - base_action_state = "adherent-float" - -/obj/item/organ/internal/powered/float/Process() - . = ..() - if(owner) - if(active) - owner.pass_flags |= PASS_FLAG_TABLE - if(owner.floatiness <= 5) - owner.make_floating(5) - else - owner.pass_flags &= ~PASS_FLAG_TABLE - -/obj/item/organ/internal/eyes/adherent - name = "receptor prism" - icon = 'icons/mob/human_races/species/adherent/organs.dmi' - eye_icon = 'icons/mob/human_races/species/adherent/eyes.dmi' - icon_state = "eyes" - status = ORGAN_PROSTHETIC - contaminant_guard = TRUE - innate_flash_protection = FLASH_PROTECTION_MAJOR - -/obj/item/organ/internal/eyes/adherent/Initialize() - . = ..() - verbs |= /obj/item/organ/internal/eyes/proc/change_eye_color - -/obj/item/organ/internal/cell/adherent - name = "piezoelectric core" - icon = 'icons/mob/human_races/species/adherent/organs.dmi' - icon_state = "cell" - -/obj/item/organ/internal/powered/cooling_fins - name = "cooling fins" - gender = PLURAL - desc = "A lacy filligree of heat-radiating fins." - action_button_name = "Toggle Cooling" - organ_tag = BP_COOLING_FINS - parent_organ = BP_GROIN - icon_state = "fins" - maintenance_cost = 0 - use_descriptor = "radiate heat" - base_action_state = "adherent-fins" - var/max_cooling = 10 - var/target_temp = T20C - -/obj/item/organ/internal/powered/cooling_fins/Process() - if(owner) - var/temp_diff = min(owner.bodytemperature - target_temp, max_cooling) - if(temp_diff >= 1) - maintenance_cost = max(temp_diff, 1) - . = ..() - if(active) - owner.bodytemperature -= temp_diff - else - maintenance_cost = 0 - else - . = ..() - -#undef PROTOCOL_ARTICLE \ No newline at end of file diff --git a/code/modules/organs/internal/species/golem.dm b/code/modules/organs/internal/species/golem.dm deleted file mode 100644 index 93e368c2e646..000000000000 --- a/code/modules/organs/internal/species/golem.dm +++ /dev/null @@ -1,8 +0,0 @@ -/obj/item/organ/internal/brain/golem - name = "chem" - desc = "A tightly furled roll of paper, covered with indecipherable runes." - icon = 'icons/obj/wizard.dmi' - icon_state = "scroll" - -/obj/item/organ/internal/brain/golem/can_recover() - return 0 diff --git a/code/modules/organs/internal/stomach.dm b/code/modules/organs/internal/stomach.dm index cca2e4d09cc3..52016ae3967b 100644 --- a/code/modules/organs/internal/stomach.dm +++ b/code/modules/organs/internal/stomach.dm @@ -2,7 +2,6 @@ name = "stomach" desc = "Gross. This is hard to stomach." icon_state = "stomach" - dead_icon = "stomach" organ_tag = BP_STOMACH parent_organ = BP_GROIN var/stomach_capacity @@ -13,29 +12,47 @@ QDEL_NULL(ingested) . = ..() -/obj/item/organ/internal/stomach/Initialize() +/obj/item/organ/internal/stomach/Serialize() + . = ..() + SERIALIZE_REAGENTS(ingested, /obj/item/organ/internal/stomach, "ingested") + +/obj/item/organ/internal/stomach/Deserialize(list/instance_map) + . = ..() + DESERIALIZE_REAGENTS(ingested, "ingested") + +/obj/item/organ/internal/stomach/set_species(species_uid) + if(species?.gluttonous) + verbs -= /obj/item/organ/internal/stomach/proc/throw_up . = ..() - ingested = new/datum/reagents/metabolism(240, (owner || src), CHEM_INGEST) - if(!ingested.my_atom) - ingested.my_atom = src if(species.gluttonous) verbs |= /obj/item/organ/internal/stomach/proc/throw_up - -/obj/item/organ/internal/stomach/removed() + if(species && !stomach_capacity) + stomach_capacity = species.stomach_capacity + +/obj/item/organ/internal/stomach/initialize_reagents() + FINALIZE_REAGENTS_SERDE(ingested) + if(!ingested) + ingested = new/datum/reagents/metabolism(240, src, CHEM_INGEST) + var/owner_atom = owner || src + REAGENT_SET_ATOM(ingested, owner_atom) . = ..() - ingested.my_atom = src - ingested.parent = null -/obj/item/organ/internal/stomach/replaced() +/obj/item/organ/internal/stomach/do_install() . = ..() - ingested.my_atom = owner + REAGENT_SET_ATOM(ingested, owner) ingested.parent = owner +/obj/item/organ/internal/stomach/do_uninstall(in_place, detach, ignore_children) + . = ..() + if(ingested) //Don't bother if we're destroying + REAGENT_SET_ATOM(ingested, src) + ingested.parent = null + /obj/item/organ/internal/stomach/proc/can_eat_atom(var/atom/movable/food) return !isnull(get_devour_time(food)) /obj/item/organ/internal/stomach/proc/is_full(var/atom/movable/food) - var/total = Floor(ingested.total_volume / 10) + var/total = floor(REAGENT_TOTAL_VOLUME(ingested) / 10) for(var/a in contents + food) if(ismob(a)) var/mob/M = a @@ -45,12 +62,12 @@ total += I.get_storage_cost() else continue - if(total > species.stomach_capacity) + if(total > stomach_capacity) return TRUE return FALSE /obj/item/organ/internal/stomach/proc/get_devour_time(var/atom/movable/food) - if(iscarbon(food) || isanimal(food)) + if(isliving(food)) var/mob/living/L = food if((species.gluttonous & GLUT_TINY) && (L.mob_size <= MOB_SIZE_TINY) && !ishuman(food)) // Anything MOB_SIZE_TINY or smaller return DEVOUR_SLOW @@ -61,16 +78,15 @@ else if(istype(food, /obj/item) && !istype(food, /obj/item/holder)) //Don't eat holders. They are special. var/obj/item/I = food var/cost = I.get_storage_cost() - if(cost < ITEM_SIZE_NO_CONTAINER) - if((species.gluttonous & GLUT_ITEM_TINY) && cost < 4) + if(!(I.obj_flags & OBJ_FLAG_NO_STORAGE)) + if((species.gluttonous & GLUT_ITEM_TINY) && cost < ITEM_SIZE_LARGE) return DEVOUR_SLOW - else if((species.gluttonous & GLUT_ITEM_NORMAL) && cost <= 4) + else if((species.gluttonous & GLUT_ITEM_NORMAL) && cost <= ITEM_SIZE_LARGE) return DEVOUR_SLOW else if(species.gluttonous & GLUT_ITEM_ANYTHING) return DEVOUR_FAST - -obj/item/organ/internal/stomach/proc/throw_up() +/obj/item/organ/internal/stomach/proc/throw_up() set name = "Empty Stomach" set category = "IC" set src in usr @@ -80,20 +96,14 @@ obj/item/organ/internal/stomach/proc/throw_up() /obj/item/organ/internal/stomach/return_air() return null -// This call needs to be split out to make sure that all the ingested things are metabolised -// before the process call is made on any of the other organs -/obj/item/organ/internal/stomach/proc/metabolize() - if(is_usable()) - ingested.metabolize() - #define STOMACH_VOLUME 65 - + /obj/item/organ/internal/stomach/Process() ..() if(owner) var/functioning = is_usable() - if(damage >= min_bruised_damage && prob((damage / max_damage) * 100)) + if(_organ_damage >= min_bruised_damage && prob((_organ_damage / max_damage) * 100)) functioning = FALSE if(functioning) @@ -102,9 +112,9 @@ obj/item/organ/internal/stomach/proc/throw_up() qdel(M) continue - M.adjustBruteLoss(3) - M.adjustFireLoss(3) - M.adjustToxLoss(3) + M.take_damage(3, do_update_health = FALSE) + M.take_damage(3, BURN, do_update_health = FALSE) + M.take_damage(3, TOX) var/digestion_product = M.get_digestion_product() if(digestion_product) @@ -114,15 +124,16 @@ obj/item/organ/internal/stomach/proc/throw_up() next_cramp = world.time + rand(200,800) owner.custom_pain("Your stomach cramps agonizingly!",1) - var/alcohol_volume = REAGENT_VOLUME(ingested, /decl/material/liquid/ethanol) - + // TODO: check if this even works - it won't be picking up alcohol subtypes. + var/alcohol_volume = REAGENT_VOLUME(ingested, /decl/material/liquid/alcohol/ethanol) + var/alcohol_threshold_met = alcohol_volume > STOMACH_VOLUME / 2 - if(alcohol_threshold_met && (owner.disabilities & EPILEPSY) && prob(20)) + if(alcohol_threshold_met && owner.has_genetic_condition(GENE_COND_EPILEPSY) && prob(20)) owner.seizure() - + // Alcohol counts as double volume for the purposes of vomit probability - var/effective_volume = ingested.total_volume + alcohol_volume - + var/effective_volume = REAGENT_TOTAL_VOLUME(ingested) + alcohol_volume + // Just over the limit, the probability will be low. It rises a lot such that at double ingested it's 64% chance. var/vomit_probability = (effective_volume / STOMACH_VOLUME) ** 6 if(prob(vomit_probability)) diff --git a/code/modules/organs/internal/voice.dm b/code/modules/organs/internal/voice.dm index 0af058083d64..c7387afdbd03 100644 --- a/code/modules/organs/internal/voice.dm +++ b/code/modules/organs/internal/voice.dm @@ -10,9 +10,8 @@ var/list/language_datums = list() if(LAZYLEN(assists_languages)) for(var/L in assists_languages) - var/lang = decls_repository.get_decl(L) + if(!ispath(L)) + continue + var/lang = GET_DECL(L) if(lang) language_datums[lang] = TRUE assists_languages = language_datums - -/obj/item/organ/internal/voicebox/get_mechanical_assisted_descriptor() - return "surgically altered [name]" diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 9f2c2f82c210..c255185fed0f 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -1,111 +1,233 @@ -var/list/organ_cache = list() - /obj/item/organ - name = "organ" - icon = 'icons/obj/surgery.dmi' - germ_level = 0 - w_class = ITEM_SIZE_TINY + name = "organ" + icon = 'icons/obj/surgery.dmi' + germ_level = 0 + w_class = ITEM_SIZE_SMALL default_action_type = /datum/action/item_action/organ + origin_tech = @'{"materials":1,"biotech":1}' + abstract_type = /obj/item/organ + pickup_sound = 'sound/foley/meat1.ogg' + drop_sound = 'sound/foley/meat2.ogg' + hitsound = 'sound/effects/squelch1.ogg' // Strings. - var/organ_tag = "organ" // Unique identifier. - var/parent_organ = BP_CHEST // Organ holding this object. + /// Unique identifier. + var/organ_tag = "organ" + /// Identifiers for use in organ collections, unused if unset. Must be formatted as a JSON list string. + var/organ_categories + /// Organ holding this object. + var/parent_organ = BP_CHEST // Status tracking. - var/status = 0 // Various status flags (such as robotic) - var/vital // Lose a vital limb, die immediately. + /// Various status flags (such as robotic) + var/status = 0 + /// A flag for telling what capabilities this organ has. ORGAN_PROP_PROSTHETIC, ORGAN_PROP_CRYSTAL, etc. + var/organ_properties = 0 + /// Cache var for vitality to current owner. + var/vital_to_owner // Reference data. - var/mob/living/carbon/human/owner // Current mob owning the organ. - var/datum/dna/dna // Original DNA. - var/datum/species/species // Original species. + var/datum/mob_snapshot/organ_appearance + /// Current mob owning the organ. + var/mob/living/human/owner + /// Original species. + var/decl/species/species + /// Original bodytype. + var/decl/bodytype/bodytype + /// A bodytype used only for icons, marking validation and equipment offsets. + var/decl/bodytype/appearance_bodytype + /// Current active ailments if any. + var/list/ailments + /// Taken from first owner. + var/meat_name // Damage vars. - var/damage = 0 // Current damage to the organ - var/min_broken_damage = 30 // Damage before becoming broken - var/max_damage = 30 // Damage cap - var/rejecting // Is this organ already being rejected? - + /// Damage before becoming broken + var/min_broken_damage = 30 + /// Damage cap, including scarring + var/max_damage = 30 + /// Lifetime damage cap, ignoring scarring. + var/absolute_max_damage = 0 + /// Is this organ already being rejected? + var/rejecting + /// REALTIMEOFDAY at moment of death. var/death_time + /// Whether or not we should scale the damage values of this organ to the owner species. + var/scale_max_damage_to_species_health + + /// Set to TRUE if this organ should return info to Stat(). See get_stat_info(). + var/has_stat_info = FALSE - // Bioprinter stats - var/can_be_printed = TRUE - var/print_cost +/obj/item/organ/proc/reset_matter() + matter = null /obj/item/organ/Destroy() - owner = null - dna = null + if(owner) + owner.remove_organ(src, FALSE, FALSE, TRUE, TRUE, FALSE) //Tell our parent we're unisntalling in place + owner = null + else + do_uninstall(TRUE, FALSE, FALSE, FALSE) //Don't ignore children here since we might own/contain them + species = null + bodytype = null + QDEL_NULL(organ_appearance) + QDEL_NULL_LIST(ailments) return ..() +/obj/item/organ/proc/on_holder_death(var/gibbed) + return + /obj/item/organ/proc/refresh_action_button() - return action + if(!QDELETED(src) && istype(action)) + return action /obj/item/organ/attack_self(var/mob/user) return (owner && loc == owner && owner == user) -/obj/item/organ/proc/update_health() - return - /obj/item/organ/proc/is_broken() - return (damage >= min_broken_damage || (status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN)) - -//Second argument may be a dna datum; if null will be set to holder's dna. -/obj/item/organ/Initialize(mapload, var/datum/dna/given_dna) - . = ..(mapload) - if(!istype(given_dna)) - given_dna = null - - if(max_damage) - min_broken_damage = Floor(max_damage / 2) + return (status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN) || (status & ORGAN_DEAD) + +//Third argument may be a dna datum; if null will be set to holder's dna. +/obj/item/organ/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance) + chem_volume = 5 * (w_class-1)**2 + . = ..(mapload, material_key) + if(. == INITIALIZE_HINT_QDEL) + return . + setup_organ(supplied_appearance) + +/obj/item/organ/proc/setup_organ(datum/mob_snapshot/supplied_appearance) + //Null DNA setup + if(!supplied_appearance) + if(organ_appearance) + supplied_appearance = organ_appearance //Use existing if possible + else if(owner) + if(owner) + supplied_appearance = owner.get_mob_snapshot() //Grab our owner's appearance info if we don't have any, and they have + else + //The owner having no DNA can be a valid reason to keep our appearance data null in some cases + log_debug("obj/item/organ/setup(): [src] had null appearance data, with a owner with null appearance data!") + organ_appearance = null //#TODO: Not sure that's really legal + return + else + //If we have NO OWNER and supplied_appearance, just make one up for consistency + supplied_appearance = new + // order of bodytype preference: new, current, owner, species + var/decl/bodytype/new_bodytype = supplied_appearance?.root_bodytype || bodytype || owner?.get_bodytype() + if(ispath(new_bodytype, /decl/bodytype)) + new_bodytype = GET_DECL(new_bodytype) + if(!new_bodytype) + // this can be fine if appearance data with species is passed + log_debug("obj/item/organ/setup(): [src] had null bodytype, with an owner with null bodytype!") + bodytype = new_bodytype // used in later setup procs + if(supplied_appearance) + copy_from_mob_snapshot(supplied_appearance) else - max_damage = min_broken_damage * 2 - - if(iscarbon(loc)) - owner = loc - if(!given_dna && owner.dna) - given_dna = owner.dna + set_species(owner?.get_species() || global.using_map.default_species) + +// todo: make this redundant with matter shenanigans +/obj/item/organ/populate_reagents() + var/reagent_to_add = /decl/material/solid/organic/meat + if(bodytype) + reagent_to_add = bodytype.edible_reagent // can set this to null and skip the next block + if(reagent_to_add) + add_to_reagents(reagent_to_add, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/organ/proc/copy_from_mob_snapshot(var/datum/mob_snapshot/supplied_appearance) + if(supplied_appearance != organ_appearance) // Hacky. Is this ever used? Do any organs ever have DNA set before setup_as_organic? + QDEL_NULL(organ_appearance) + organ_appearance = supplied_appearance.Clone() + blood_DNA = list(organ_appearance.unique_enzymes = organ_appearance.blood_type) + if(species != organ_appearance.root_species) + if(organ_appearance.root_bodytype && organ_appearance.root_bodytype != bodytype) + bodytype = organ_appearance.root_bodytype // this lets us take advantage of set_bodytype being called in set_species + set_species(organ_appearance.root_species?.uid || global.using_map.default_species) + else if(organ_appearance.root_bodytype && organ_appearance.root_bodytype != bodytype) + set_bodytype(organ_appearance.root_bodytype) + +/obj/item/organ/proc/set_bodytype(decl/bodytype/new_bodytype, override_material = null, apply_to_internal_organs = TRUE) + SHOULD_CALL_PARENT(TRUE) + if(isnull(new_bodytype)) + PRINT_STACK_TRACE("Null bodytype passed to set_bodytype!") + return FALSE + if(ispath(new_bodytype, /decl/bodytype)) + new_bodytype = GET_DECL(new_bodytype) + if(!istype(new_bodytype)) + PRINT_STACK_TRACE("Invalid bodytype [new_bodytype]") + return FALSE + bodytype = new_bodytype + if(bodytype.modifier_string) + name = "[bodytype.modifier_string] [initial(name)]" + desc = bodytype.desc + origin_tech = bodytype.limb_tech + max_damage *= bodytype.hardiness + min_broken_damage *= bodytype.hardiness + bodytype.resize_organ(src) + + reset_matter() + set_material(override_material || bodytype.organ_material) + for(var/mat in bodytype.matter) + if(mat in matter) + matter[mat] += bodytype.matter[mat] else - log_debug("[src] spawned in [owner] without a proper DNA.") + LAZYSET(matter, mat, bodytype.matter[mat]) + create_matter() + + // maybe this should be a generalized repopulate_reagents helper?? + if(reagents) + reagents.clear_reagents() + populate_reagents() + reset_status() + return TRUE + +// resets scarring, but ah well +/obj/item/organ/proc/set_max_damage(var/ndamage) + absolute_max_damage = floor(ndamage) + max_damage = absolute_max_damage + +/obj/item/organ/proc/set_species(species_uid) + vital_to_owner = null // This generally indicates the owner mob is having species set, and this value may be invalidated. + if(istext(species_uid)) + species = decls_repository.get_decl_by_id(species_uid) + else + species = species_uid + if(!species) + species = decls_repository.get_decl_by_id(global.using_map.default_species) + PRINT_STACK_TRACE("Invalid species. Expected a valid species UID as string, was: [log_info_line(species_uid)]") - if (given_dna) - set_dna(given_dna) - if (!species) - species = get_species_by_key(GLOB.using_map.default_species) - species.resize_organ(src) + set_bodytype(bodytype || species.default_bodytype, override_material = material?.type) - create_reagents(5 * (w_class-1)**2) - reagents.add_reagent(/decl/material/liquid/nutriment/protein, reagents.maximum_volume) + // Adjust limb health proportinate to total species health. + var/total_health_coefficient = scale_max_damage_to_species_health ? (species.total_health / DEFAULT_SPECIES_HEALTH) : 1 - update_icon() + //Use initial value to prevent scaling down each times we change the species during init + absolute_max_damage = initial(absolute_max_damage) + min_broken_damage = initial(min_broken_damage) + + if(absolute_max_damage) + set_max_damage(max(1, floor(absolute_max_damage * total_health_coefficient))) + min_broken_damage = max(1, floor(absolute_max_damage * 0.5)) + else + min_broken_damage = max(1, floor(min_broken_damage * total_health_coefficient)) + set_max_damage(max(1, floor(min_broken_damage * 2))) -/obj/item/organ/proc/set_dna(var/datum/dna/new_dna) - if(new_dna) - dna = new_dna.Clone() - if(!blood_DNA) - blood_DNA = list() - blood_DNA.Cut() - blood_DNA[dna.unique_enzymes] = dna.b_type - species = get_species_by_key(dna.species) - if (!species) - crash_with("Invalid DNA species. Expected a valid species name as string, was: [log_info_line(dna.species)]") + reset_status() /obj/item/organ/proc/die() - damage = max_damage status |= ORGAN_DEAD STOP_PROCESSING(SSobj, src) - death_time = world.time - if(owner && vital) - owner.death() + QDEL_NULL_LIST(ailments) + death_time = REALTIMEOFDAY + update_icon() /obj/item/organ/Process() - if(loc != owner) + if(loc != owner) //#FIXME: looks like someone was trying to hide a bug :P That probably could break organs placed inside a wrapper though owner = null + vital_to_owner = null //dead already, no need for more processing if(status & ORGAN_DEAD) return - // Don't process if we're in a freezer, an MMI or a stasis bag.or a freezer or something I dunno + // Don't process if we're in a freezer, an interface or a stasis bag. if(is_preserved()) return //Process infections @@ -114,12 +236,12 @@ var/list/organ_cache = list() return if(!owner && reagents) - if(prob(40) && reagents.total_volume >= 0.1) + if(prob(40) && REAGENT_TOTAL_VOLUME(reagents) >= 0.1) if(reagents.has_reagent(/decl/material/liquid/blood)) blood_splatter(get_turf(src), src, 1) - reagents.remove_any(0.1) - if(config.organs_decay) - take_general_damage(rand(1,3)) + remove_any_reagents(0.1) + if(get_config_value(/decl/config/toggle/health_organs_decay)) + take_damage(rand(1,3)) germ_level += rand(2,6) if(germ_level >= INFECTION_LEVEL_TWO) germ_level += rand(2,6) @@ -132,25 +254,49 @@ var/list/organ_cache = list() handle_rejection() handle_germ_effects() - //check if we've hit max_damage - if(damage >= max_damage) - die() + if(owner && length(ailments)) + for(var/datum/ailment/ailment in ailments) + handle_ailment(ailment) + +/obj/item/organ/proc/handle_ailment(var/datum/ailment/ailment) + if(ailment.treated_by_reagent_type) + for(var/datum/reagents/source as anything in owner.get_metabolizing_reagent_holders()) + var/source_volumes = REAGENT_VOLUMES(source) + for(var/decl/material/reagent as anything in source_volumes) + if(ailment.treated_by_medication(reagent.type, source_volumes[reagent])) + ailment.was_treated_by_medication(source, reagent.type) + return + if(ailment.treated_by_chem_effect && owner.has_chemical_effect(ailment.treated_by_chem_effect, ailment.treated_by_chem_effect_strength)) + ailment.was_treated_by_chem_effect() /obj/item/organ/proc/is_preserved() - if(istype(loc,/obj/item/organ)) + if(istype(loc, /obj/item/organ)) var/obj/item/organ/O = loc return O.is_preserved() - else - return (istype(loc,/obj/item/mmi) || istype(loc,/obj/structure/closet/body_bag/cryobag) || istype(loc,/obj/structure/closet/crate/freezer) || istype(loc,/obj/item/storage/box/freezer)) - -/obj/item/organ/examine(mob/user) - . = ..(user) - show_decay_status(user) - -/obj/item/organ/proc/show_decay_status(mob/user) + var/static/list/preserved_types = list( + /obj/item/box/freezer, + /obj/structure/closet/crate/freezer, + /obj/structure/closet/body_bag/cryobag + ) + for(var/preserved_type in preserved_types) + if(istype(loc, preserved_type)) + return TRUE + return FALSE + +/obj/item/organ/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/decay_status = get_decay_status(user) + if(decay_status) + . += decay_status + +/obj/item/organ/proc/get_decay_status(mob/user) + SHOULD_CALL_PARENT(TRUE) + . = list() if(status & ORGAN_DEAD) - to_chat(user, "The decay has set into \the [src].") + . += SPAN_WARNING("Decay has set into \the [src].") +// TODO: bodytemp rework that handles this with better respect to +// individual organs vs. expected body temperature for other organs. /obj/item/organ/proc/handle_germ_effects() //** Handle the effects of infections var/germ_immunity = owner.get_immunity() //reduces the amount of times we need to call this proc @@ -163,22 +309,22 @@ var/list/organ_cache = list() //aiming for germ level to go from ambient to INFECTION_LEVEL_TWO in an average of 15 minutes, when immunity is full. if(antibiotics < 5 && prob(round(germ_level/6 * owner.immunity_weakness() * 0.01))) if(germ_immunity > 0) - germ_level += Clamp(round(1/germ_immunity), 1, 10) // Immunity starts at 100. This doubles infection rate at 50% immunity. Rounded to nearest whole. + germ_level += clamp(round(1/germ_immunity), 1, 10) // Immunity starts at 100. This doubles infection rate at 50% immunity. Rounded to nearest whole. else // Will only trigger if immunity has hit zero. Once it does, 10x infection rate. germ_level += 10 if(germ_level >= INFECTION_LEVEL_ONE) - var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature - owner.bodytemperature += between(0, (fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, fever_temperature - owner.bodytemperature) + var/fever_temperature = (owner.get_mob_temperature_threshold(HEAT_LEVEL_1) - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature + owner.bodytemperature += clamp((fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, 0, fever_temperature - owner.bodytemperature) if (germ_level >= INFECTION_LEVEL_TWO) - var/obj/item/organ/external/parent = owner.get_organ(parent_organ) + var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(owner, parent_organ) //spread germs if (antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(owner.immunity_weakness() * 0.3) )) parent.germ_level++ if (prob(3)) //about once every 30 seconds - take_general_damage(1,silent=prob(30)) + take_damage(1, silent =prob(30)) /obj/item/organ/proc/handle_rejection() // Process unsuitable transplants. TODO: consider some kind of @@ -187,9 +333,9 @@ var/list/organ_cache = list() return if(BP_IS_PROSTHETIC(src)) return - if(dna) + if(organ_appearance) if(!rejecting) - if(owner.blood_incompatible(dna.b_type, species)) + if(owner.is_blood_incompatible(organ_appearance.blood_type)) rejecting = 1 else rejecting++ //Rejection severity increases over time. @@ -203,138 +349,102 @@ var/list/organ_cache = list() germ_level += rand(2,3) if(501 to INFINITY) germ_level += rand(3,5) - owner.reagents.add_reagent(/decl/material/liquid/coagulated_blood, rand(1,2)) - -/obj/item/organ/proc/receive_chem(chemical) - return 0 + var/decl/blood_type/blood_decl = organ_appearance?.blood_type && get_blood_type_by_name(organ_appearance.blood_type) + if(istype(blood_decl)) + owner.add_to_reagents(blood_decl.transfusion_fail_reagent, round(rand(2,4) * blood_decl.transfusion_fail_percentage)) + else + owner.add_to_reagents(/decl/material/liquid/coagulated_blood, rand(1,2)) /obj/item/organ/proc/remove_rejuv() qdel(src) -/obj/item/organ/proc/rejuvenate(var/ignore_prosthetic_prefs) - damage = 0 +/obj/item/organ/proc/rejuvenate(var/ignore_organ_traits) + SHOULD_CALL_PARENT(TRUE) + if(!owner) + PRINT_STACK_TRACE("rejuvenate() called on organ of type [type] with no owner.") + reset_status() + QDEL_NULL_LIST(ailments) + if(!ignore_organ_traits) + for(var/trait_type in owner.get_traits()) + var/decl/trait/trait = GET_DECL(trait_type) + if(trait.applies_to_organ(organ_tag) && trait.reapply_on_rejuvenation) + trait.apply_trait(owner) + +/obj/item/organ/proc/reset_status() + vital_to_owner = null // organ modifications might need this to be recalculated status = initial(status) - if(!ignore_prosthetic_prefs && owner && owner.client && owner.client.prefs && owner.client.prefs.real_name == owner.real_name) - var/status = owner.client.prefs.organ_data[organ_tag] - if(status == "assisted") - mechassist() - else if(status == "mechanical") - robotize() - if(species) - species.post_organ_rejuvenate(src, owner) + if(bodytype) // qdel clears bodytype ref + bodytype.apply_bodytype_organ_modifications(src) //Germs /obj/item/organ/proc/handle_antibiotics() if(!owner || !germ_level) return - var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] + var/antibiotics = GET_CHEMICAL_EFFECT(owner, CE_ANTIBIOTIC) if (!antibiotics) return if (germ_level < INFECTION_LEVEL_ONE) germ_level = 0 //cure instantly else if (germ_level < INFECTION_LEVEL_TWO) - germ_level -= 5 //at germ_level == 500, this should cure the infection in 5 minutes + germ_level -= round(5 * antibiotics) //at germ_level == 500, this should cure the infection in 5 minutes else - germ_level -= 3 //at germ_level == 1000, this will cure the infection in 10 minutes - if(owner && owner.lying) - germ_level -= 2 + germ_level -= round(3 * antibiotics) //at germ_level == 1000, this will cure the infection in 10 minutes + if(owner && owner.current_posture.prone) + germ_level -= round(2 * antibiotics) germ_level = max(0, germ_level) -/obj/item/organ/proc/take_general_damage(var/amount, var/silent = FALSE) - CRASH("Not Implemented") +// Bypass the atom damage system when inside an owner, as organs implement their own health handling etc. +/obj/item/organ/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + if(!owner) + return ..() /obj/item/organ/proc/heal_damage(amount) - if (can_recover()) - damage = between(0, damage - round(amount, 0.1), max_damage) - - -/obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc - status = ORGAN_PROSTHETIC - reagents?.clear_reagents() - -/obj/item/organ/proc/mechassist() //Used to add things like pacemakers, etc - status = ORGAN_ASSISTED - -/** - * Remove an organ - * - * drop_organ - if true, organ will be dropped at the loc of its former owner - * - * Also, Observer Pattern Implementation: Dismembered Handling occurs here. - */ -/obj/item/organ/proc/removed(var/mob/living/user, var/drop_organ=1) - - if(!istype(owner)) - return - GLOB.dismembered_event.raise_event(owner, src) - - action_button_name = null - - if(drop_organ) - dropInto(owner.loc) - - START_PROCESSING(SSobj, src) - rejecting = null - if(!BP_IS_PROSTHETIC(src) && species && reagents?.total_volume < 5) - owner.vessel.trans_to(src, 5 - reagents.total_volume, 1, 1) - - if(vital) - if(user) - admin_attack_log(user, owner, "Removed a vital organ ([src]).", "Had a vital organ ([src]) removed.", "removed a vital organ ([src]) from") - owner.death() - screen_loc = null - owner.client?.screen -= src - owner = null - -/obj/item/organ/proc/replaced(var/mob/living/carbon/human/target, var/obj/item/organ/external/affected) - owner = target - action_button_name = initial(action_button_name) - forceMove(owner) //just in case - if(BP_IS_PROSTHETIC(src)) - set_dna(owner.dna) - return 1 + return -/obj/item/organ/attack(var/mob/target, var/mob/user) - if(status & ORGAN_PROSTHETIC || !istype(target) || !istype(user) || (user != target && user.a_intent == I_HELP)) +/obj/item/organ/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(BP_IS_PROSTHETIC(src) || !istype(target) || !istype(user) || (user != target && user.check_intent(I_FLAG_HELP))) return ..() if(alert("Do you really want to use this organ as food? It will be useless for anything else afterwards.",,"Ew, no.","Bon appetit!") == "Ew, no.") to_chat(user, SPAN_NOTICE("You successfully repress your cannibalistic tendencies.")) - return + return TRUE if(QDELETED(src)) - return - - if(!user.unEquip(src)) - return - - var/obj/item/chems/food/snacks/organ/O = new(get_turf(src)) - O.SetName(name) - O.appearance = src - if(reagents && reagents.total_volume) - reagents.trans_to(O, reagents.total_volume) - transfer_fingerprints_to(O) - user.put_in_active_hand(O) + return TRUE + + if(!user.try_unequip(src)) + return TRUE + + target.attackby(convert_to_food(user), user) + return TRUE + +/obj/item/organ/proc/convert_to_food(mob/user) + var/obj/item/food/organ/yum = new(get_turf(src)) + yum.SetName(name) + yum.appearance = src + if(reagents && REAGENT_TOTAL_VOLUME(reagents)) + reagents.trans_to(yum, REAGENT_TOTAL_VOLUME(reagents)) + transfer_fingerprints_to(yum) + if(user) + user.put_in_active_hand(yum) qdel(src) - target.attackby(O, user) + return yum /obj/item/organ/proc/can_feel_pain() - return (!BP_IS_PROSTHETIC(src) && (!species || !(species.species_flags & SPECIES_FLAG_NO_PAIN))) + return bodytype && !(bodytype.body_flags & BODY_FLAG_NO_PAIN) && !(status & ORGAN_DEAD) /obj/item/organ/proc/is_usable() - return !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED|ORGAN_DEAD)) + . = !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED|ORGAN_DEAD)) /obj/item/organ/proc/can_recover() - return (max_damage > 0) && !(status & ORGAN_DEAD) || death_time >= world.time - ORGAN_RECOVERY_THRESHOLD + return (max_damage > 0) && !(status & ORGAN_DEAD) || death_time >= REALTIMEOFDAY - ORGAN_RECOVERY_THRESHOLD /obj/item/organ/proc/get_scan_results(var/tag = FALSE) . = list() if(BP_IS_CRYSTAL(src)) . += tag ? "Crystalline" : "Crystalline" - else if(BP_IS_ASSISTED(src)) - . += tag ? "Assisted" : "Assisted" else if(BP_IS_PROSTHETIC(src)) . += tag ? "Mechanical" : "Mechanical" if(status & ORGAN_CUT_AWAY) @@ -348,7 +458,6 @@ var/list/organ_cache = list() . += tag ? "Necrotic" : "Necrotic" if(BP_IS_BRITTLE(src)) . += tag ? "Brittle" : "Brittle" - switch (germ_level) if (INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + ((INFECTION_LEVEL_TWO - INFECTION_LEVEL_ONE) / 3)) . += "Mild Infection" @@ -386,5 +495,212 @@ var/list/organ_cache = list() /obj/item/organ/proc/listen() return -/obj/item/organ/proc/get_mechanical_assisted_descriptor() - return "mechanically-assisted [name]" +var/global/list/ailment_reference_cache = list() +/proc/get_ailment_reference(var/datum/ailment/ailment_type) + if(!ispath(ailment_type, /datum/ailment)) + return + if(TYPE_IS_ABSTRACT(ailment_type)) + return + if(!global.ailment_reference_cache[ailment_type]) + global.ailment_reference_cache[ailment_type] = new ailment_type + return global.ailment_reference_cache[ailment_type] + +/obj/item/organ/proc/get_possible_ailments() + . = list() + if(owner.status_flags & GODMODE) + return . + for(var/ailment_type in subtypesof(/datum/ailment)) + var/datum/ailment/ailment = ailment_type + if(TYPE_IS_ABSTRACT(ailment)) + continue + ailment = get_ailment_reference(ailment_type) + if(ailment.can_apply_to(src)) + . += ailment_type + for(var/datum/ailment/ailment in ailments) + . -= ailment.type + +/obj/item/organ/emp_act(severity) + . = ..() + if(BP_IS_PROSTHETIC(src)) + if(length(ailments) < 3 && prob(15 - (5 * length(ailments)))) + var/list/possible_ailments = get_possible_ailments() + if(length(possible_ailments)) + add_ailment(pick(possible_ailments)) + +/obj/item/organ/proc/add_ailment(var/datum/ailment/ailment) + if(ispath(ailment, /datum/ailment)) + ailment = get_ailment_reference(ailment) + if(!istype(ailment) || !ailment.can_apply_to(src)) + return FALSE + LAZYADD(ailments, new ailment.type(src)) + return TRUE + +/obj/item/organ/proc/add_random_ailment() + var/list/possible_ailments = get_possible_ailments() + if(length(possible_ailments)) + add_ailment(pick(possible_ailments)) + +/obj/item/organ/proc/remove_ailment(var/datum/ailment/ailment) + if(ispath(ailment, /datum/ailment)) + for(var/datum/ailment/ext_ailment in ailments) + if(ailment == ext_ailment.type) + qdel(ext_ailment) + return TRUE + else if(istype(ailment)) + for(var/datum/ailment/ext_ailment in ailments) + if(ailment == ext_ailment) + qdel(ext_ailment) + return TRUE + return FALSE + +/obj/item/organ/proc/has_diagnosable_ailments(var/mob/user, var/scanner = FALSE) + for(var/datum/ailment/ailment in ailments) + if(ailment.manual_diagnosis_string && !scanner) + LAZYADD(., ailment.replace_tokens(message = ailment.manual_diagnosis_string, user = user)) + else if(ailment.scanner_diagnosis_string && scanner) + LAZYADD(., ailment.replace_tokens(message = ailment.scanner_diagnosis_string, user = user)) + +/obj/item/organ/proc/get_ailment_of_type(ailment_type) + for(var/datum/ailment/ext_ailment in ailments) + if(ailment_type == ext_ailment.type) + return ext_ailment + return null + +/obj/item/organ/proc/has_ailment_of_type(ailment_type) + return !!get_ailment_of_type(ailment_type) + +//Handles only the installation of the organ, without triggering any callbacks. +//if we're an internal organ, having a null "target" is legal if we have an "affected" +//CASES: +// 1. When creating organs and running their init this is called to properly set them up +// 2. When installing an organ through surgery this is called. +// 3. When attaching a detached organ through surgery this is called. +// The organ may be inside an external organ that's not inside a mob, or inside a mob +//detached : If true, the organ will be installed in a detached state, otherwise it will be added in an attached state +/obj/item/organ/proc/do_install(var/mob/living/human/target, var/obj/item/organ/external/affected, var/in_place = FALSE, var/update_icon = TRUE, var/detached = FALSE) + + // While on an owner, do not take damage. + max_health = ITEM_HEALTH_NO_DAMAGE + current_health = ITEM_HEALTH_NO_DAMAGE + + //Make sure to force the flag accordingly + set_detached(detached) + if(QDELETED(src)) + return + + owner = target + if(owner && isnull(meat_name)) + meat_name = owner.get_butchery_product_name() + vital_to_owner = null + action_button_name = initial(action_button_name) + if(owner) + forceMove(owner) + if(!(status & ORGAN_CUT_AWAY)) //Don't run ailments if we're still detached + for(var/datum/ailment/ailment in ailments) + ailment.begin_ailment_event() + else if(affected) + forceMove(affected) //When installed in a limb with no owner + return src + +//Handles uninstalling the organ from its owner and parent limb, without triggering effects or deep updates +//CASES: +// 1. Before deletion to clear our references. +// 2. Called through removal on surgery or dismemberement +// 3. Called when we're changing a mob's species. +//detach: If detach is true, we're going to set the organ to detached, and add it to the detached organs list, and remove it from processing lists. +// If it's false, we just remove the organ from all lists +/obj/item/organ/proc/do_uninstall(var/in_place = FALSE, var/detach = FALSE, var/ignore_children = FALSE, var/update_icon = TRUE) + + max_health = max_damage + if(current_health == ITEM_HEALTH_NO_DAMAGE) + current_health = get_max_health() + else + current_health = min(current_health, get_max_health()) + + action_button_name = null + screen_loc = null + rejecting = null + for(var/datum/ailment/ailment in ailments) + if(ailment.timer_id) + deltimer(ailment.timer_id) + ailment.timer_id = null + + //When we detach, we set the ORGAN_CUT_AWAY flag on, depending on whether the organ supports it or not + if(detach) + set_detached(TRUE) + else + owner = null + vital_to_owner = null + if(!QDELETED(src)) + return src + +//Events handling for checks and effects that should happen when removing the organ through interactions. Called by the owner mob. +/obj/item/organ/proc/on_remove_effects(var/mob/living/last_owner) + START_PROCESSING(SSobj, src) + vital_to_owner = null + +//Events handling for checks and effects that should happen when installing the organ through interactions. Called by the owner mob. +/obj/item/organ/proc/on_add_effects() + STOP_PROCESSING(SSobj, src) + vital_to_owner = null + +//Since some types of organs completely ignore being detached, moved it to an overrideable organ proc for external prosthetics +/obj/item/organ/proc/set_detached(var/is_detached) + if(is_detached) + status |= ORGAN_CUT_AWAY + else + status &= ~ORGAN_CUT_AWAY + +//Some checks to avoid doing type checks for nothing +/obj/item/organ/proc/is_internal() + return FALSE + +// If an organ is inside a holder, the holder should be handling damage in their explosion_act() proc. +/obj/item/organ/explosion_act(severity) + return !owner && ..() + +/obj/item/organ/proc/is_vital_to_owner() + var/decl/bodytype/root_bodytype = owner?.get_bodytype() + if(isnull(vital_to_owner)) + if(!root_bodytype) + vital_to_owner = null + return FALSE + vital_to_owner = (organ_tag in root_bodytype.vital_organs) + return vital_to_owner + +/obj/item/organ/proc/place_butcher_product(decl/butchery_data/butchery_decl) + if(butchery_decl.meat_type) + var/list/products = butchery_decl.place_products(owner, material?.type, clamp(w_class, 1, 3), butchery_decl.meat_type) + if(meat_name) + for(var/obj/item/food/butchery/product in products) + product.set_meat_name(meat_name) + +/obj/item/organ/physically_destroyed(skip_qdel) + if(!owner && !BP_IS_PROSTHETIC(src) && species?.butchery_data) + place_butcher_product(GET_DECL(species.butchery_data)) + return ..() + +/// Returns a list with two entries, first being the stat panel title, the second being the value. See has_stat_info bool above. +/obj/item/organ/proc/get_stat_info() + return null + +/obj/item/organ/handle_destroyed_by_heat() + if(owner) + return + if(isturf(loc)) + new /obj/effect/decal/cleanable/ash(loc) + if(!QDELETED(src)) + qdel(src) + +// For overriding on shapeshifters/changelings in the future. +/obj/item/organ/proc/set_organ_appearance_bodytype(decl/bodytype/new_bodytype, update_sprite_accessories = TRUE, skip_owner_update = FALSE) + if(ispath(new_bodytype, /decl/bodytype)) + new_bodytype = GET_DECL(new_bodytype) + if((new_bodytype && !istype(new_bodytype)) || appearance_bodytype == new_bodytype || bodytype == new_bodytype) + return FALSE + appearance_bodytype = new_bodytype + return TRUE + +/obj/item/organ/proc/get_organ_appearance_bodytype() + RETURN_TYPE(/decl/bodytype) + return appearance_bodytype || bodytype diff --git a/code/modules/organs/organ_prosthetics.dm b/code/modules/organs/organ_prosthetics.dm new file mode 100644 index 000000000000..dc864aa098da --- /dev/null +++ b/code/modules/organs/organ_prosthetics.dm @@ -0,0 +1,190 @@ +/* + A system for easily and quickly removing your own bodyparts, with a view towards + swapping them out for new ones, or just doing it as a party trick to horrify an + audience. Current implementation only supports robolimbs and uses a modular_bodypart + value on the manufacturer datum, but I have tried to keep it generic for future work. + PS. jesus christ this was meant to be a half an hour port +*/ + +// External organ procs: +// Does this bodypart count as a modular limb, and if so, what kind? +/obj/item/organ/external/proc/get_modular_limb_category() + return isnull(bodytype?.modular_limb_tier) ? MODULAR_BODYPART_INVALID : bodytype.modular_limb_tier + +// Checks if a limb could theoretically be removed. +// Note that this does not currently bother checking if a child or internal organ is vital. +/obj/item/organ/external/proc/can_remove_modular_limb(var/mob/living/human/user) + if((owner?.species && is_vital_to_owner()) || !(limb_flags & ORGAN_FLAG_CAN_AMPUTATE)) + return FALSE + var/bodypart_cat = get_modular_limb_category() + if(bodypart_cat == MODULAR_BODYPART_CYBERNETIC) + if(!parent_organ) + return FALSE + var/obj/item/organ/external/parent = user && GET_EXTERNAL_ORGAN(user, parent_organ) + if(!parent || parent.get_modular_limb_category(user) < MODULAR_BODYPART_CYBERNETIC) + return FALSE + . = (bodypart_cat != MODULAR_BODYPART_INVALID) + +// Note that this proc is checking if the organ can be attached -to-, not attached itself. +/obj/item/organ/external/proc/can_attach_modular_limb_here(var/mob/living/human/user) + var/list/limb_data = user?.get_bodytype()?.has_limbs[organ_tag] + . = FALSE + if(islist(limb_data) && limb_data["has_children"] > 0) + . = (LAZYLEN(children) < limb_data["has_children"]) + +/obj/item/organ/external/proc/can_be_attached_modular_limb(var/mob/living/user) + var/bodypart_cat = get_modular_limb_category() + if(bodypart_cat == MODULAR_BODYPART_INVALID) + return FALSE + if(!parent_organ) + return FALSE + var/obj/item/organ/external/parent = user && GET_EXTERNAL_ORGAN(user, parent_organ) + if(!parent) + return FALSE + if(!parent.can_attach_modular_limb_here(user)) + return FALSE + if(bodypart_cat == MODULAR_BODYPART_CYBERNETIC && parent.get_modular_limb_category(src) < MODULAR_BODYPART_CYBERNETIC) + return FALSE + return TRUE + +// Checks if an organ (or the parent of one) is in a fit state for modular limb stuff to happen. +/obj/item/organ/external/proc/check_modular_limb_damage(var/mob/living/human/user) + . = (brute_dam + burn_dam) >= min_broken_damage || (status & ORGAN_BROKEN) // can't use is_broken() as the limb has ORGAN_CUT_AWAY + +// Human mob procs: +// Checks the organ list for limbs meeting a predicate. Way overengineered for such a limited use +// case but I can see it being expanded in the future if meat limbs or doona limbs use it. +/mob/living/human/proc/get_modular_limbs(var/return_first_found = FALSE, var/validate_proc) + for(var/obj/item/organ/external/limb as anything in get_external_organs()) + if(!validate_proc || call(limb, validate_proc)(src) > MODULAR_BODYPART_INVALID) + LAZYADD(., limb) + if(return_first_found) + return + // Prune children so we can't remove every individual component of an entire prosthetic arm + // piece by piece. Technically a circular dependency here would remove the limb entirely but + // if there's a parent whose child is also its parent, there's something wrong regardless. + for(var/obj/item/organ/external/limb as anything in .) + if(length(limb.children)) + . -= limb.children + +// Called in bodytype.apply_bodytype_organ_modifications(), replaced() and removed() to update our modular limb verbs. +/mob/living/human/proc/refresh_modular_limb_verbs() + if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_attach_modular_limb_here))) + verbs |= .proc/attach_limb_verb + else + verbs -= .proc/attach_limb_verb + if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb))) + verbs |= .proc/detach_limb_verb + else + verbs -= .proc/detach_limb_verb + +// Proc helper for attachment verb. +/mob/living/human/proc/check_can_attach_modular_limb(var/obj/item/organ/external/E) + if(is_on_special_ability_cooldown() || get_active_held_item() != E) + return FALSE + if(incapacitated() || restrained()) + to_chat(src, SPAN_WARNING("You can't do that in your current state!")) + return FALSE + if(QDELETED(E) || !istype(E)) + to_chat(src, SPAN_WARNING("You are not holding a compatible limb to attach.")) + return FALSE + if(!E.can_be_attached_modular_limb(src)) + to_chat(src, SPAN_WARNING("\The [E] cannot be attached to your current body.")) + return FALSE + if(E.get_modular_limb_category() <= MODULAR_BODYPART_INVALID) + to_chat(src, SPAN_WARNING("\The [E] cannot be attached by your own hand.")) + return FALSE + if(GET_EXTERNAL_ORGAN(src, E.organ_tag)) + to_chat(src, SPAN_WARNING("There is already a limb attached at that part of your body.")) + return FALSE + if(E.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("\The [E] is too damaged to be attached.")) + return FALSE + var/obj/item/organ/external/parent = E.parent_organ && GET_EXTERNAL_ORGAN(src, E.parent_organ) + if(!parent) + to_chat(src, SPAN_WARNING("\The [E] needs an existing limb to be attached to.")) + return FALSE + if(parent.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("Your [parent.name] is too damaged to have anything attached.")) + return FALSE + return TRUE + +// Proc helper for detachment verb. +/mob/living/human/proc/check_can_detach_modular_limb(var/obj/item/organ/external/E) + if(is_on_special_ability_cooldown()) + return FALSE + if(incapacitated() || restrained()) + to_chat(src, SPAN_WARNING("You can't do that in your current state!")) + return FALSE + if(!istype(E) || QDELETED(src) || QDELETED(E) || E.owner != src || E.loc != src) + return FALSE + if(E.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("That limb is too damaged to be removed!")) + return FALSE + var/obj/item/organ/external/parent = E.parent_organ && GET_EXTERNAL_ORGAN(src, E.parent_organ) + if(!parent) + return FALSE + if(parent.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("Your [parent.name] is too damaged to detach anything from it.")) + return FALSE + return (E in get_modular_limbs(return_first_found = FALSE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb)) + +// Verbs below: +// Add or remove robotic limbs; check refresh_modular_limb_verbs() above. +/mob/living/human/proc/attach_limb_verb() + set name = "Attach Limb" + set category = "Object" + set desc = "Attach a replacement limb." + set src = usr + + var/obj/item/organ/external/E = get_active_held_item() + if(!check_can_attach_modular_limb(E)) + return FALSE + if(!do_after(src, 2 SECONDS, src)) + return FALSE + if(!check_can_attach_modular_limb(E)) + return FALSE + + set_special_ability_cooldown(2 SECONDS) + drop_from_inventory(E) + src.add_organ(E) + + // Reconnect the organ and children as normally this is done with surgery. + E.status &= ~ORGAN_CUT_AWAY + for(var/obj/item/organ/external/child in E.children) + child.status &= ~ORGAN_CUT_AWAY + + var/decl/pronouns/pronouns = get_pronouns() + visible_message( + SPAN_NOTICE("\The [src] attaches \the [E] to [pronouns.his] body!"), + SPAN_NOTICE("You attach \the [E] to your body!")) + try_refresh_visible_overlays() // Not sure why this isn't called by removed(), but without it we don't update our limb appearance. + return TRUE + +/mob/living/human/proc/detach_limb_verb() + set name = "Remove Limb" + set category = "Object" + set desc = "Detach one of your limbs." + set src = usr + + var/list/detachable_limbs = get_modular_limbs(return_first_found = FALSE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb) + if(!length(detachable_limbs)) + to_chat(src, SPAN_WARNING("You have no detachable limbs.")) + return FALSE + var/obj/item/organ/external/E = input(usr, "Which limb do you wish to detach?", "Limb Removal") as null|anything in detachable_limbs + if(!check_can_detach_modular_limb(E)) + return FALSE + if(!do_after(src, 2 SECONDS, src)) + return FALSE + if(!check_can_detach_modular_limb(E)) + return FALSE + + set_special_ability_cooldown(2 SECONDS) + remove_organ(E, update_icon = TRUE) + E.dropInto(loc) + put_in_hands(E) + var/decl/pronouns/pronouns = get_pronouns() + visible_message( + SPAN_NOTICE("\The [src] detaches [pronouns.his] [E.name]!"), + SPAN_NOTICE("You detach your [E.name]!")) + return TRUE diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm index df5ad895ee36..96a83f894ce1 100644 --- a/code/modules/organs/pain.dm +++ b/code/modules/organs/pain.dm @@ -1,4 +1,15 @@ -mob/proc/flash_pain(var/target) +/mob/living + var/obj/screen/fullscreen/pain/pain + +/mob/living/Initialize() + pain = new(null, src) + . = ..() + +/mob/living/Destroy() + QDEL_NULL(pain) + . = ..() + +/mob/living/proc/flash_pain(var/target) if(pain) var/matrix/M if(client && max(client.last_view_x_dim, client.last_view_y_dim) > 7) @@ -8,26 +19,25 @@ mob/proc/flash_pain(var/target) animate(pain, alpha = target, time = 15, easing = ELASTIC_EASING) animate(pain, alpha = 0, time = 20) -mob/var/last_pain_message -mob/var/next_pain_time = 0 +/mob/living/proc/can_feel_pain(var/check_organ) + if(check_organ) + return get_organ(check_organ)?.can_feel_pain() + return !(get_bodytype()?.body_flags & BODY_FLAG_NO_PAIN) // message is the custom message to be displayed // power decides how much painkillers will stop the message // force means it ignores anti-spam timer -mob/living/carbon/proc/custom_pain(var/message, var/power, var/force, var/obj/item/organ/external/affecting, var/nohalloss) +/mob/living/proc/custom_pain(var/message, var/power, var/force, var/obj/item/organ/external/affecting, var/nohalloss) set waitfor = FALSE - if(!message || stat || !can_feel_pain() || chem_effects[CE_PAINKILLER] > power) + if(!message || stat || !can_feel_pain() || has_chemical_effect(CE_PAINKILLER, power)) return - - power -= chem_effects[CE_PAINKILLER]/2 //Take the edge off. - + power -= GET_CHEMICAL_EFFECT(src, CE_PAINKILLER)/2 //Take the edge off. // Excessive halloss is horrible, just give them enough to make it visible. if(!nohalloss && power) if(affecting) affecting.add_pain(ceil(power/2)) else - adjustHalLoss(ceil(power/2)) - + take_damage(ceil(power/2), PAIN) flash_pain(min(round(2*power)+55, 255)) // Anti message spam checks @@ -41,15 +51,16 @@ mob/living/carbon/proc/custom_pain(var/message, var/power, var/force, var/obj/it to_chat(src, "[message]") else to_chat(src, "[message]") + next_pain_time = world.time + max(30 SECONDS - power, 10 SECONDS) - var/force_emote = species.get_pain_emote(src, power) - if(force_emote && prob(power)) - var/decl/emote/use_emote = usable_emotes[force_emote] - if(!(use_emote.message_type == AUDIBLE_MESSAGE && silent)) - emote(force_emote) - next_pain_time = world.time + (100-power) + var/decl/species/my_species = get_species() + var/force_emote = my_species?.get_pain_emote(src, power) + if(force_emote && prob(power)) + var/decl/emote/use_emote = GET_DECL(force_emote) + if(!(use_emote.message_type == AUDIBLE_MESSAGE &&HAS_STATUS(src, STAT_SILENCE))) + emote(force_emote) -mob/living/carbon/human/proc/handle_pain() +/mob/living/human/proc/handle_pain() if(stat) return if(!can_feel_pain()) @@ -58,7 +69,7 @@ mob/living/carbon/human/proc/handle_pain() return var/maxdam = 0 var/obj/item/organ/external/damaged_organ = null - for(var/obj/item/organ/external/E in organs) + for(var/obj/item/organ/external/E in get_external_organs()) if(!E.can_feel_pain()) continue var/dam = E.get_damage() // make the choice of the organ depend on damage, @@ -66,11 +77,11 @@ mob/living/carbon/human/proc/handle_pain() if(dam > maxdam && (maxdam == 0 || prob(70)) ) damaged_organ = E maxdam = dam - if(damaged_organ && chem_effects[CE_PAINKILLER] < maxdam) - if(maxdam > 10 && paralysis) - paralysis = max(0, paralysis - round(maxdam/10)) + if(damaged_organ && has_chemical_effect(CE_PAINKILLER, maxdam)) + if(maxdam > 10 &&HAS_STATUS(src, STAT_PARA)) + ADJ_STATUS(src, STAT_PARA, -(round(maxdam/10))) if(maxdam > 50 && prob(maxdam / 5)) - unequip_item() + drop_held_items() var/burning = damaged_organ.burn_dam > damaged_organ.brute_dam var/msg switch(maxdam) @@ -82,29 +93,31 @@ mob/living/carbon/human/proc/handle_pain() msg = "OH GOD! Your [damaged_organ.name] is [burning ? "on fire" : "hurting terribly"]!" custom_pain(msg, maxdam, prob(10), damaged_organ, TRUE) // Damage to internal organs hurts a lot. - for(var/obj/item/organ/internal/I in internal_organs) - if(prob(1) && !((I.status & ORGAN_DEAD) || BP_IS_PROSTHETIC(I)) && I.damage > 5) - var/obj/item/organ/external/parent = get_organ(I.parent_organ) - var/pain = 10 - var/message = "You feel a dull pain in your [parent.name]" - if(I.is_bruised()) - pain = 25 - message = "You feel a pain in your [parent.name]" - if(I.is_broken()) - pain = 50 - message = "You feel a sharp pain in your [parent.name]" - src.custom_pain(message, pain, affecting = parent) + for(var/obj/item/organ/internal/organ in get_internal_organs()) + if(prob(1) && !((organ.status & ORGAN_DEAD) || BP_IS_PROSTHETIC(organ)) && organ.get_organ_damage() > 5) + var/obj/item/organ/external/parent = GET_EXTERNAL_ORGAN(src, organ.parent_organ) + if(parent) + var/pain = 10 + var/message = "You feel a dull pain in your [parent.name]" + if(organ.is_bruised()) + pain = 25 + message = "You feel a pain in your [parent.name]" + if(organ.is_broken()) + pain = 50 + message = "You feel a sharp pain in your [parent.name]" + src.custom_pain(message, pain, affecting = parent) if(prob(1)) - switch(getToxLoss()) + var/tox_damage = get_damage(TOX) + switch(tox_damage) if(5 to 17) - custom_pain("Your body stings slightly.", getToxLoss()) + custom_pain("Your body stings slightly.", tox_damage) if(17 to 35) - custom_pain("Your body stings.", getToxLoss()) + custom_pain("Your body stings.", tox_damage) if(35 to 60) - custom_pain("Your body stings strongly.", getToxLoss()) + custom_pain("Your body stings strongly.", tox_damage) if(60 to 100) - custom_pain("Your whole body hurts badly.", getToxLoss()) + custom_pain("Your whole body hurts badly.", tox_damage) if(100 to INFINITY) - custom_pain("Your body aches all over, it's driving you mad.", getToxLoss()) \ No newline at end of file + custom_pain("Your body aches all over, it's driving you mad.", tox_damage) diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm deleted file mode 100644 index 0d6ea56d9d9b..000000000000 --- a/code/modules/organs/robolimbs.dm +++ /dev/null @@ -1,66 +0,0 @@ -var/list/all_robolimbs = list() -var/list/chargen_robolimbs = list() -var/datum/robolimb/basic_robolimb - -/proc/populate_robolimb_list() - basic_robolimb = new() - for(var/limb_type in typesof(/datum/robolimb)) - var/datum/robolimb/R = new limb_type() - all_robolimbs[R.company] = R - if(!R.unavailable_at_chargen) - chargen_robolimbs[R.company] = R - -#define DEFINE_ROBOLIMB_DESIGNS(MODEL_PATH, MODEL_ID, MODEL_NAME) \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID { \ - category = MODEL_NAME + " Prosthetics"; \ - path = /obj/item/organ/external/leg; \ - model = MODEL_PATH; \ -} \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/right_leg { \ - path = /obj/item/organ/external/leg/right; \ -} \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/left_arm { \ - path = /obj/item/organ/external/arm; \ -} \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/right_arm { \ - path = /obj/item/organ/external/arm/right; \ -} \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/head { \ - path = /obj/item/organ/external/head; \ -} \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/chest { \ - path = /obj/item/organ/external/chest; \ -} \ -/datum/fabricator_recipe/robotics/prosthetic/model_##MODEL_ID/groin { \ - path = /obj/item/organ/external/groin; \ -} - -/datum/robolimb - var/company = "Unbranded" // Shown when selecting the limb. - var/desc = "A generic unbranded robotic prosthesis." // Seen when examining a limb. - var/icon = 'icons/mob/human_races/cyberlimbs/robotic.dmi' // Icon base to draw from. - var/unavailable_at_chargen // If set, not available at chargen. - var/can_eat - var/has_eyes = TRUE - var/can_feel_pain - var/skintone - var/limb_blend - var/list/bodytypes_cannot_use = list() - var/list/species_restricted - var/list/applies_to_part = list() //TODO. - var/list/allowed_bodytypes = list(BODYTYPE_HUMANOID) - var/modifier_string = "robotic" - var/hardiness = 1 - var/manual_dexterity = DEXTERITY_FULL - var/movement_slowdown = 0 - var/is_robotic = TRUE - -/datum/robolimb/wooden - company = "wooden prosthesis" - desc = "A crude wooden prosthetic." - icon = 'icons/mob/human_races/cyberlimbs/morgan/morgan_main.dmi' - modifier_string = "wooden" - hardiness = 0.75 - manual_dexterity = DEXTERITY_SIMPLE_MACHINES - movement_slowdown = 1 - is_robotic = FALSE diff --git a/code/modules/overmap/README.dm b/code/modules/overmap/README.dm index 97d8272ccf4b..dc9664df5917 100644 --- a/code/modules/overmap/README.dm +++ b/code/modules/overmap/README.dm @@ -37,11 +37,11 @@ If this zlevel (or any of connected ones for multiz) doesn't have this object, y 2. Put it anywhere on the ship/sector map. It will do the rest on its own during init. If your thing is multiz, only one is needed per multiz sector/ship. -If it's player's main base (e.g Exodus), set 'base' var to 1, so it adds itself to station_levels list. +If it's player's main base (e.g tradeship), set 'base' var to 1, so it adds itself to station_levels list. If this place cannot be reached or left with EVA, set 'in_space' var to 0 If you want exploration shuttles (look below) to be able to dock here, set up waypoints lists. generic_waypoints is list of landmark_tags of waypoints any shttle should be able to visit. -restricted_waypoints is list of 'shuttle name = list(landmark_tags)' pairs for waypoints only those shuttles can visit +restricted_waypoints is list of 'shuttle type = list(landmark_tags)' pairs for waypoints only those shuttles can visit ************************************************************* # Helm console diff --git a/code/modules/overmap/_defines.dm b/code/modules/overmap/_defines.dm index 3585f674b019..e82c7adc05c2 100644 --- a/code/modules/overmap/_defines.dm +++ b/code/modules/overmap/_defines.dm @@ -1,34 +1,60 @@ //How far from the edge of overmap zlevel could randomly placed objects spawn #define OVERMAP_EDGE 2 //Dimension of overmap (squares 4 lyfe) -var/global/list/map_sectors = list() - -/area/overmap/ +/area/overmap name = "System Map" icon_state = "start" requires_power = 0 base_turf = /turf/unsimulated/map - dynamic_lighting = 0 + dynamic_lighting = FALSE /turf/unsimulated/map icon = 'icons/turf/space.dmi' icon_state = "map" permit_ao = FALSE + dynamic_lighting = FALSE /turf/unsimulated/map/edge - opacity = 1 - density = 1 + opacity = TRUE + +///Turf to hide the outside of the overmap +/turf/unsimulated/dark_filler + name = "out of sight" + icon = 'icons/turf/space.dmi' + icon_state = "black" + permit_ao = FALSE + dynamic_lighting = FALSE + opacity = TRUE + density = TRUE + plane = ABOVE_LIGHTING_PLANE + layer = OBFUSCATION_LAYER // Cover all non-hud material. -/turf/unsimulated/map/Initialize(var/ml) - . = ..(ml) +///Turf with its map coordinate written on. Handy for debugging. +/turf/unsimulated/debug_grid + name = "grid" + icon = 'icons/turf/space.dmi' + icon_state = "black" + permit_ao = FALSE + dynamic_lighting = FALSE + +/turf/unsimulated/debug_grid/New() + . = ..() + name = "[initial(name)]-[x],[y]" + maptext = STYLE_SMALLFONTS("[x],[y]", 6, "green") + maptext_width = 32 + maptext_height = 16 + +/turf/unsimulated/map/New() + ..() name = "[x]-[y]" var/list/numbers = list() - if(x == 1 || x == GLOB.using_map.overmap_size) + var/datum/overmap/overmap = global.overmaps_by_z[num2text(z)] + if(x == 1 || x == overmap.map_size_x) numbers += list("[round(y/10)]","[round(y%10)]") - if(y == 1 || y == GLOB.using_map.overmap_size) + if(y == 1 || y == overmap.map_size_y) numbers += "-" - if(y == 1 || y == GLOB.using_map.overmap_size) + if(y == 1 || y == overmap.map_size_y) numbers += list("[round(x/10)]","[round(x%10)]") for(var/i = 1 to numbers.len) @@ -38,17 +64,17 @@ var/global/list/map_sectors = list() if(y == 1) I.pixel_y = 3 I.pixel_x = 5*i + 4 - if(y == GLOB.using_map.overmap_size) + if(y == overmap.map_size_y) I.pixel_y = world.icon_size - 9 I.pixel_x = 5*i + 4 if(x == 1) I.pixel_x = 5*i - 2 - if(x == GLOB.using_map.overmap_size) + if(x == overmap.map_size_x) I.pixel_x = 5*i + 2 overlays += I //list used to track which zlevels are being 'moved' by the proc below -var/list/moving_levels = list() +var/global/list/moving_levels = list() //Proc to 'move' stars in spess //yes it looks ugly, but it should only fire when state actually change. //null direction stops movement @@ -56,25 +82,12 @@ var/list/moving_levels = list() if(!zlevel) return - var/gen_dir = null - if(direction & (NORTH|SOUTH)) - gen_dir += "ns" - else if(direction & (EAST|WEST)) - gen_dir += "ew" - if(!direction) - gen_dir = null + if (moving_levels["[zlevel]"] != direction) + moving_levels["[zlevel]"] = direction - if (moving_levels["[zlevel]"] != gen_dir) - moving_levels["[zlevel]"] = gen_dir - - var/list/spaceturfs = block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)) - for(var/turf/space/T in spaceturfs) - if(!gen_dir) - T.icon_state = "white" - else - T.icon_state = "speedspace_[gen_dir]_[rand(1,15)]" - for(var/atom/movable/AM in T) - if (AM.simulated && !AM.anchored) - AM.throw_at(get_step(T, GLOB.reverse_dir[direction]), 5, 1) - CHECK_TICK + var/datum/level_data/level = SSmapping.levels_by_z[zlevel] + var/list/space_turfs = block(level.level_inner_min_x, level.level_inner_min_y, zlevel, level.level_inner_max_x, level.level_inner_max_y, zlevel) + for(var/turf/space/T in space_turfs) + T.toggle_transit(direction) CHECK_TICK + diff --git a/code/modules/overmap/_overmap.dm b/code/modules/overmap/_overmap.dm new file mode 100644 index 000000000000..96d9180a2402 --- /dev/null +++ b/code/modules/overmap/_overmap.dm @@ -0,0 +1,148 @@ +/datum/overmap + var/name + var/assigned_z + + var/event_areas = 11 + var/map_size_x = 20 + var/map_size_y = 20 + + var/overmap_edge_type = /turf/unsimulated/map/edge + var/overmap_turf_type = /turf/unsimulated/map + var/overmap_area_type = /area/overmap + var/empty_level_type = /datum/level_data/space + + var/list/valid_event_types + + /// list used to cache empty zlevels to avoid needless z-stack bloat + var/list/cached_temporary_sectors = list() + +/datum/overmap/New(var/_name) + + name = _name + + if(!name) + PRINT_STACK_TRACE("Unnamed overmap datum instantiated: [type]") + + if(global.overmaps_by_name[name]) + PRINT_STACK_TRACE("Duplicate overmap datum instantiated: [type], [name], [overmaps_by_name[name]]") + global.overmaps_by_name[name] = src + + generate_overmap() + testing("Overmap build for [name] complete.") + + for(var/decl/overmap_event/event in decls_repository.get_decls_of_subtype_unassociated(/decl/overmap_event)) + if(event.overmap_id == name) + LAZYADD(valid_event_types, event.type) + + ..() + +/datum/overmap/proc/populate_overmap() + var/area/overmap/A = locate(overmap_area_type) || new overmap_area_type //level_data should have initialized the area + for(var/turf/square as anything in block(1, 1, assigned_z, map_size_x, map_size_y, assigned_z)) + if(square.x == map_size_x || square.y == map_size_y) + square = square.ChangeTurf(overmap_edge_type) + else + square = square.ChangeTurf(overmap_turf_type) + ChangeArea(square, A) + +/datum/overmap/proc/generate_overmap() + testing("Building overmap [name]...") + SSmapping.increment_world_z_size(/datum/level_data/overmap) + assigned_z = world.maxz + testing("Putting [name] on [assigned_z].") + if(global.overmaps_by_z["[assigned_z]"]) + PRINT_STACK_TRACE("Duplicate overmap datum instantiated for z-level: [type], [assigned_z], [overmaps_by_name[name]]") + global.overmaps_by_z["[assigned_z]"] = src + populate_overmap() + SSmapping.sealed_levels |= assigned_z + . = TRUE + +/datum/overmap/proc/travel(var/turf/space/T, var/atom/movable/A) + if (!T || !A) + return + + var/obj/effect/overmap/visitable/M = global.overmap_sectors[T.z] + if (!M) + return + + if(A.overmap_can_discard()) + if(!QDELETED(A)) + qdel(A) + return + + var/nx = 1 + var/ny = 1 + var/nz = 1 + + if(T.x <= TRANSITIONEDGE) + nx = world.maxx - TRANSITIONEDGE - 2 + ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) + + else if (A.x >= (world.maxx - TRANSITIONEDGE - 1)) + nx = TRANSITIONEDGE + 2 + ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) + + else if (T.y <= TRANSITIONEDGE) + ny = world.maxy - TRANSITIONEDGE -2 + nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) + + else if (A.y >= (world.maxy - TRANSITIONEDGE - 1)) + ny = TRANSITIONEDGE + 2 + nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) + + testing("[name]: [A] ([A.z],[A.y],[A.z]) travelling from [M] ([M.x],[M.y]).") + + var/turf/map = locate(M.x,M.y,assigned_z) + var/obj/effect/overmap/visitable/TM + for(var/obj/effect/overmap/visitable/O in map) + if(O != M && (O.sector_flags & OVERMAP_SECTOR_IN_SPACE) && prob(50)) + TM = O + break + if(!TM) + TM = create_temporary_sector(M.x,M.y) + nz = pick(TM.map_z) + + var/turf/dest = locate(nx,ny,nz) + if(dest && !dest.density) + A.forceMove(dest) + if(isliving(A)) + var/mob/living/L = A + for(var/obj/item/grab/grab as anything in L.get_active_grabs()) + grab.affecting.forceMove(dest) + + if(istype(M, /obj/effect/overmap/visitable/sector/temporary)) + var/obj/effect/overmap/visitable/sector/temporary/source = M + if(source.can_die()) + source.forceMove(null) + if(!QDELETED(source)) + testing("Caching [M] for future use") + if(!length(cached_temporary_sectors[empty_level_type])) + cached_temporary_sectors[empty_level_type] = list() + cached_temporary_sectors[empty_level_type] |= source + +/datum/overmap/proc/create_temporary_sector(x,y) + + // There's already a sector at this x/y + var/obj/effect/overmap/visitable/sector/temporary/res = locate(x, y, assigned_z) + if(istype(res) && !QDELETED(res)) + return res + + // We might have a sector cached we can give them. + if(length(cached_temporary_sectors[empty_level_type])) + res = pick_n_take(cached_temporary_sectors[empty_level_type]) + if(!length(cached_temporary_sectors[empty_level_type])) + cached_temporary_sectors -= empty_level_type + if(istype(res) && !QDELETED(res)) + res.forceMove(locate(x, y, assigned_z)) + return res + + // Create a new one. + var/datum/level_data/level = SSmapping.increment_world_z_size(empty_level_type) + return new /obj/effect/overmap/visitable/sector/temporary(null, x, y, level.level_z) + +/datum/overmap/proc/discard_temporary_sector(var/obj/effect/overmap/visitable/sector/temporary/sector) + if(!length(cached_temporary_sectors[empty_level_type])) + return + cached_temporary_sectors[empty_level_type] -= sector + if(!length(cached_temporary_sectors[empty_level_type])) + cached_temporary_sectors -= empty_level_type diff --git a/code/modules/overmap/contacts/_contacts.dm b/code/modules/overmap/contacts/_contacts.dm index 21b8194d408e..069f914a4d9c 100644 --- a/code/modules/overmap/contacts/_contacts.dm +++ b/code/modules/overmap/contacts/_contacts.dm @@ -21,25 +21,36 @@ owner.contact_datums[effect] = src marker = new(loc = effect) - marker.appearance = effect - marker.alpha = 0 // Marker fades in on detection. + update_marker_icon() + marker.alpha = 0 // Marker fades in on detection. + marker.appearance_flags |= RESET_TRANSFORM images += marker - + radar = image(loc = effect, icon = 'icons/obj/overmap.dmi', icon_state = "sensor_range") - radar.tag = "radar" - radar.filters = filter(type="blur", size = 1) + radar.color = source.color + radar.add_filter("blur", 1, list(type = "blur", size = 1)) + radar.appearance_flags |= RESET_TRANSFORM | KEEP_APART + radar.appearance_flags &= ~PIXEL_SCALE -/datum/overmap_contact/proc/update_marker_icon(var/range = 0) - marker.icon_state = effect.icon_state - marker.dir = effect.dir - marker.overlays.Cut() +/datum/overmap_contact/proc/update_marker_icon() + + marker.appearance = effect + marker.appearance_flags |= RESET_TRANSFORM + // Pixel offsets are included in appearance but since this marker's loc + // is the effect, it's already offset and we don't want to double it. + marker.pixel_x = 0 + marker.pixel_y = 0 + marker.transform = effect.transform + marker.overlays.Cut() if(check_effect_shield()) var/image/shield_image = image(icon = 'icons/obj/overmap.dmi', icon_state = "shield") shield_image.pixel_x = 8 marker.overlays += shield_image +/datum/overmap_contact/proc/ping_radar(var/range = 0) + radar.transform = null radar.alpha = 255 @@ -53,19 +64,33 @@ images -= radar /datum/overmap_contact/proc/show() - for(var/weakref/W in owner?.viewers) - var/mob/M = W.resolve() - if(istype(M)) - M.client?.images |= images + if(!owner) + return + var/list/showing = owner.linked?.navigation_viewers || owner.viewers + if(length(showing)) + for(var/weakref/viewer_ref in showing) + var/mob/M = viewer_ref.resolve() + if(istype(M) && M.client) + M.client.images |= images + +/datum/overmap_contact/proc/hide() + if(!owner) + return + var/list/showing = owner.linked?.navigation_viewers || owner.viewers + if(length(showing)) + for(var/weakref/viewer_ref in showing) + var/mob/M = viewer_ref.resolve() + if(istype(M) && M.client) + M.client.images -= images /datum/overmap_contact/proc/check_effect_shield() var/obj/effect/overmap/visitable/visitable_effect = effect if(!visitable_effect || !istype(visitable_effect)) return FALSE - for(var/obj/machinery/power/shield_generator/S in SSmachines.machinery) - if(S.z in visitable_effect.map_z) - if(S.running == SHIELD_RUNNING) - return TRUE + for(var/thing in visitable_effect.get_linked_machines_of_type(/obj/machinery/shield_generator)) + var/obj/machinery/shield_generator/S = thing + if(S.running == SHIELD_RUNNING) + return TRUE return FALSE /datum/overmap_contact/proc/ping() @@ -74,7 +99,7 @@ pinged = TRUE show() animate(marker, alpha=255, 0.5 SECOND, 1, LINEAR_EASING) - addtimer(CALLBACK(src, .proc/unping), 1 SECOND) + addtimer(CALLBACK(src, PROC_REF(unping)), 1 SECOND) /datum/overmap_contact/proc/unping() animate(marker, alpha=75, 2 SECOND, 1, LINEAR_EASING) @@ -82,13 +107,10 @@ /datum/overmap_contact/Destroy() if(owner) - for(var/weakref/W in owner?.viewers) - var/mob/M = W.resolve() - if(istype(M)) - M.client?.images -= images - - if(effect) owner.contact_datums -= effect - owner = null + hide() + if(effect) + owner.contact_datums -= effect + owner = null effect = null QDEL_NULL_LIST(images) - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/overmap/contacts/contact_sensors.dm b/code/modules/overmap/contacts/contact_sensors.dm index 63722c1584cb..68f0907ac833 100644 --- a/code/modules/overmap/contacts/contact_sensors.dm +++ b/code/modules/overmap/contacts/contact_sensors.dm @@ -4,23 +4,28 @@ var/list/contact_datums = list() var/list/trackers = list() -/obj/machinery/computer/ship/sensors/Destroy() - objects_in_view.Cut() - trackers.Cut() - - for(var/key in contact_datums) - var/datum/overmap_contact/record = contact_datums[key] - qdel(record) - contact_datums.Cut() - . = ..() - /obj/machinery/computer/ship/sensors/attempt_hook_up(obj/effect/overmap/visitable/ship/sector) . = ..() - if(. && linked && !contact_datums[linked]) + if(!linked) + return + for(var/obj/effect/overmap/overmap_object in linked.contents) + if(!overmap_object.requires_contact) + continue + new /datum/overmap_contact(src, overmap_object) + if(istype(loc, /obj/effect/overmap)) + var/obj/effect/overmap/overmap_location = loc + if(overmap_location.requires_contact) + new /datum/overmap_contact(src, overmap_location) + if(!contact_datums[linked]) var/datum/overmap_contact/record = new(src, linked) - contact_datums[linked] = record record.marker.alpha = 255 +/obj/machinery/computer/ship/sensors/Destroy() + objects_in_view.Cut() + QDEL_LIST_ASSOC_VAL(contact_datums) + trackers.Cut() + . = ..() + /obj/machinery/computer/ship/sensors/proc/reveal_contacts(var/mob/user) if(user && user.client) for(var/key in contact_datums) @@ -40,11 +45,16 @@ update_sound() if(!linked) return - + // Update our own marker icon regardless of power or sensor connections. - var/sensor_range = round(sensors.range,1) + var/sensor_range = 0 + + var/obj/machinery/shipsensors/sensors = get_sensors() + if(sensors?.use_power) + sensor_range = round(sensors.range,1) var/datum/overmap_contact/self_record = contact_datums[linked] - self_record.update_marker_icon(sensor_range) + self_record.update_marker_icon() + self_record.ping_radar(sensor_range) self_record.show() // Update our 'sensor range' (ie. overmap lighting) @@ -53,7 +63,7 @@ var/datum/overmap_contact/record = contact_datums[key] if(record.effect == linked) continue - qdel(record) // Immediately cut records if power is lost. + qdel(record) // Immediately cut records if power is lost. Note that this handles removing from the list. objects_in_view.Cut() return @@ -64,34 +74,42 @@ // Find all sectors with a tracker on their z-level. Only works on ships when they are in space. for(var/obj/item/ship_tracker/tracker in trackers) if(tracker.enabled) - var/obj/effect/overmap/visitable/tracked_effect = map_sectors["[get_z(tracker)]"] + var/obj/effect/overmap/visitable/tracked_effect = global.overmap_sectors[get_z(tracker)] if(tracked_effect && istype(tracked_effect) && tracked_effect != linked && tracked_effect.requires_contact) objects_in_current_view[tracked_effect] = TRUE objects_in_view[tracked_effect] = 100 - for(var/obj/effect/overmap/contact in view(sensor_range, linked)) + for(var/obj/effect/overmap/contained_contact in linked.contents) + if(!contained_contact.requires_contact) + continue + objects_in_current_view[contained_contact] = TRUE + objects_in_view[contained_contact] = 100 + new /datum/overmap_contact(src, contained_contact) // Don't give a contact notification! + + for(var/obj/effect/overmap/contact in view(sensor_range, get_turf(linked))) if(contact == linked) continue if(!contact.requires_contact) // Only some effects require contact for visibility. continue objects_in_current_view[contact] = TRUE - if(!objects_in_view[contact]) - if(contact.instant_contact) // Instantly identify the object in range. - objects_in_view[contact] = 100 - else - objects_in_view[contact] = 0 + + if(contact.instant_contact) // Instantly identify the object in range. + objects_in_view[contact] = 100 + else if(isnull(objects_in_view[contact])) + objects_in_view[contact] = 0 for(var/obj/effect/overmap/contact in objects_in_view) //Update everything. + // Are we already aware of this object? var/datum/overmap_contact/record = contact_datums[contact] - + // Fade out and remove anything that is out of range. if(QDELETED(contact) || !objects_in_current_view[contact]) // Object has exited sensor range. if(record) animate(record.marker, alpha=0, 2 SECOND, 1, LINEAR_EASING) QDEL_IN(record, 2 SECOND) // Need to restart the search if you've lost contact with the object. if(contact.scannable) // Scannable objects are the only ones that give off notifications to prevent spam - visible_message(SPAN_NOTICE("[src] states, 'Contact lost with [record.name]'")) + visible_message(SPAN_NOTICE("\The [src] states, \"Contact lost with [record.name].\"")) playsound(loc, "sound/machines/sensors/contact_lost.ogg", 30, 1) objects_in_view -= contact continue @@ -101,50 +119,54 @@ if(bearing < 0) bearing += 360 if(!record) // Begin attempting to identify ship. - // The chance of detection decreases with distance to the target ship. - if(prob((SENSORS_DISTANCE_COEFFICIENT * contact.sensor_visibility)/max(get_dist(linked, contact), 0.5))) - objects_in_view[contact] += (sensors.sensor_strength**2) - if(contact.scannable) - var/bearing_variability = round(30/sensors.sensor_strength, 5) - var/bearing_estimate = round(rand(bearing-bearing_variability, bearing+bearing_variability), 5) - if(bearing_estimate < 0) - bearing_estimate += 360 - // Give the player an idea of where the ship is in relation to the ship. - visible_message(SPAN_NOTICE("\The [src] states, \"Contact nearby, bearing [bearing_estimate], error +/- [bearing_variability].\"")) - playsound(loc, "sound/machines/sensors/contactgeneric.ogg", 10, 1) //Let players know there's something nearby. + // The chance of detection decreases with distance to the target ship. + if(contact.scannable && prob((SENSORS_DISTANCE_COEFFICIENT * contact.sensor_visibility)/max(get_dist(linked, contact), 0.5))) + var/bearing_variability = round(30/sensors.sensor_strength, 5) + var/bearing_estimate = round(rand(bearing-bearing_variability, bearing+bearing_variability), 5) + if(bearing_estimate < 0) + bearing_estimate += 360 + // Give the player an idea of where the ship is in relation to the ship. + if(objects_in_view[contact] <= 0) + if(!muted) + visible_message(SPAN_NOTICE("\The [src] states, \"Unknown contact designation '[contact.unknown_id]' detected nearby, bearing [bearing_estimate], error +/- [bearing_variability]. Beginning trace.\"")) + objects_in_view[contact] = round(sensors.sensor_strength**2) + else + objects_in_view[contact] += round(sensors.sensor_strength**2) + if(!muted) + visible_message(SPAN_NOTICE("\The [src] states, \"Contact '[contact.unknown_id]' tracing [objects_in_view[contact]]% complete, bearing [bearing_estimate], error +/- [bearing_variability].\"")) + playsound(loc, "sound/machines/sensors/contactgeneric.ogg", 10, 1) //Let players know there's something nearby. if(objects_in_view[contact] >= 100) // Identification complete. record = new /datum/overmap_contact(src, contact) - contact_datums[contact] = record if(contact.scannable) playsound(loc, "sound/machines/sensors/newcontact.ogg", 30, 1) visible_message(SPAN_NOTICE("\The [src] states, \"New contact identified, designation [record.name], bearing [bearing].\"")) - record.show() + record.ping() animate(record.marker, alpha=255, 2 SECOND, 1, LINEAR_EASING) continue // Update identification information for this record. record.update_marker_icon() - + var/time_delay = max((SENSOR_TIME_DELAY * get_dist(linked, contact)),1) if(!record.pinged) - addtimer(CALLBACK(record, .proc/ping), time_delay) + addtimer(CALLBACK(record, PROC_REF(ping)), time_delay) -/obj/machinery/computer/ship/sensors/attackby(var/obj/item/I, var/mob/user) +/obj/machinery/computer/ship/sensors/attackby(var/obj/item/used_item, var/mob/user) . = ..() - var/obj/item/multitool/P = I + var/obj/item/multitool/P = used_item if(!istype(P)) return var/obj/item/ship_tracker/tracker = P.get_buffer() if(!tracker || !istype(tracker)) return - + if(tracker in trackers) trackers -= tracker - GLOB.destroyed_event.unregister(tracker, src, .proc/remove_tracker) - to_chat(user, SPAN_NOTICE("You unlink the tracker in \the [P]'s buffer from \the [src]")) + events_repository.unregister(/decl/observ/destroyed, tracker, src, PROC_REF(remove_tracker)) + to_chat(user, SPAN_NOTICE("You unlink the tracker in \the [P]'s buffer from \the [src].")) return trackers += tracker - GLOB.destroyed_event.register(tracker, src, .proc/remove_tracker) - to_chat(user, SPAN_NOTICE("You link the tracker in \the [P]'s buffer to \the [src]")) + events_repository.register(/decl/observ/destroyed, tracker, src, PROC_REF(remove_tracker)) + to_chat(user, SPAN_NOTICE("You link the tracker in \the [P]'s buffer to \the [src].")) /obj/machinery/computer/ship/sensors/proc/remove_tracker(var/obj/item/ship_tracker/tracker) trackers -= tracker diff --git a/code/modules/overmap/contacts/tracker.dm b/code/modules/overmap/contacts/tracker.dm index c80090023968..f8fbff10d09f 100644 --- a/code/modules/overmap/contacts/tracker.dm +++ b/code/modules/overmap/contacts/tracker.dm @@ -4,8 +4,8 @@ icon = 'icons/obj/ship_tracker.dmi' icon_state = "disabled" w_class = ITEM_SIZE_SMALL - - origin_tech = "{'magnets':3, 'programming':2}" + + origin_tech = @'{"magnets":3, "programming":2}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT) var/enabled = FALSE @@ -23,6 +23,6 @@ . = ..() icon_state = enabled ? "enabled" : "disabled" -/obj/item/ship_tracker/examine(var/mob/user) +/obj/item/ship_tracker/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It appears to be [enabled ? "enabled" : "disabled"]") \ No newline at end of file + . += "It appears to be [enabled ? "enabled" : "disabled"]" diff --git a/code/modules/overmap/disperser/disperser.dm b/code/modules/overmap/disperser/disperser.dm index ee1670b7d7a1..5059a21e44a9 100644 --- a/code/modules/overmap/disperser/disperser.dm +++ b/code/modules/overmap/disperser/disperser.dm @@ -7,19 +7,20 @@ anchored = TRUE construct_state = /decl/machine_construction/default/panel_closed -/obj/machinery/disperser/examine(mob/user) +/obj/machinery/disperser/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(panel_open) - to_chat(user, "The maintenance panel is open.") + . += "The maintenance panel is open." -/obj/machinery/disperser/attackby(obj/item/I, mob/user) - if(isWrench(I)) +/obj/machinery/disperser/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) if(panel_open) - user.visible_message("\The [user] rotates \the [src] with \the [I].", "You rotate \the [src] with \the [I].") + user.visible_message("\The [user] rotates \the [src] with \the [used_item].", "You rotate \the [src] with \the [used_item].") set_dir(turn(dir, 90)) playsound(src, 'sound/items/jaws_pry.ogg', 50, 1) else to_chat(user,"The maintenance panel must be screwed open for this!") + return TRUE else return ..() diff --git a/code/modules/overmap/disperser/disperser_charge.dm b/code/modules/overmap/disperser/disperser_charge.dm index db2dafe43ee8..4ab024556663 100644 --- a/code/modules/overmap/disperser/disperser_charge.dm +++ b/code/modules/overmap/disperser/disperser_charge.dm @@ -2,34 +2,44 @@ name = "unknown disperser charge" desc = "A charge to power the obstruction field disperser with. It looks impossibly round and shiny. This charge does not have a defined purpose." icon_state = "slug" - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + atom_flags = ATOM_FLAG_CLIMBABLE + material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/copper = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/exotic_matter = MATTER_AMOUNT_TRACE + ) var/chargetype var/chargedesc +/obj/structure/ship_munition/disperser_charge/get_single_monetary_worth() + . = round(..() * 3) // Artificially inflate the value a bit. + +/obj/structure/ship_munition/disperser_charge/Initialize(ml, _mat, _reinf_mat) + . = ..() + if(chargedesc) + name = "\improper [chargedesc] charge" + /obj/structure/ship_munition/disperser_charge/fire - name = "FR1-ENFER charge" color = "#b95a00" desc = "A charge to power the obstruction field disperser with. It looks impossibly round and shiny. This charge is designed to release a localised fire on impact." chargetype = OVERMAP_WEAKNESS_FIRE - chargedesc = "ENFER" + chargedesc = "FR1-ENFER" /obj/structure/ship_munition/disperser_charge/emp - name = "EM2-QUASAR charge" color = "#6a97b0" desc = "A charge to power the obstruction field disperser with. It looks impossibly round and shiny. This charge is designed to release a blast of electromagnetic pulse on impact." chargetype = OVERMAP_WEAKNESS_EMP - chargedesc = "QUASAR" + chargedesc = "EM2-QUASAR" /obj/structure/ship_munition/disperser_charge/mining - name = "MN3-BERGBAU charge" color = "#cfcf55" desc = "A charge to power the obstruction field disperser with. It looks impossibly round and shiny. This charge is designed to mine ores on impact." chargetype = OVERMAP_WEAKNESS_MINING - chargedesc = "BERGBAU" + chargedesc = "MN3-BERGBAU" /obj/structure/ship_munition/disperser_charge/explosive - name = "XP4-INDARRA charge" color = "#aa5f61" desc = "A charge to power the obstruction field disperser with. It looks impossibly round and shiny. This charge is designed to explode on impact." chargetype = OVERMAP_WEAKNESS_EXPLOSIVE - chargedesc = "INDARRA" \ No newline at end of file + chargedesc = "XP4-INDARRA" diff --git a/code/modules/overmap/disperser/disperser_circuit.dm b/code/modules/overmap/disperser/disperser_circuit.dm index 82d92dab0b1e..16b2aa0bf9b2 100644 --- a/code/modules/overmap/disperser/disperser_circuit.dm +++ b/code/modules/overmap/disperser/disperser_circuit.dm @@ -1,31 +1,31 @@ /obj/item/stock_parts/circuitboard/disperser - name = T_BOARD("obstruction field disperser control") + name = "circuitboard (obstruction field disperser control)" build_path = /obj/machinery/computer/ship/disperser - origin_tech = "{'engineering':2,'combat':2,'wormholes':2}" + origin_tech = @'{"engineering":2,"combat":2,"wormholes":2}' /obj/item/stock_parts/circuitboard/disperserfront - name = T_BOARD("obstruction field disperser beam generator") + name = "circuitboard (obstruction field disperser beam generator)" build_path = /obj/machinery/disperser/front board_type = "machine" - origin_tech = "{'engineering':2,'combat':2,'wormholes':2}" + origin_tech = @'{"engineering":2,"combat":2,"wormholes":2}' req_components = list ( /obj/item/stock_parts/manipulator/pico = 5 ) /obj/item/stock_parts/circuitboard/dispersermiddle - name = T_BOARD("obstruction field disperser fusor") + name = "circuitboard (obstruction field disperser fusor)" build_path = /obj/machinery/disperser/middle board_type = "machine" - origin_tech = "{'engineering':2,'combat':2,'wormholes':2}" + origin_tech = @'{"engineering":2,"combat":2,"wormholes":2}' req_components = list ( /obj/item/stock_parts/subspace/crystal = 10 ) /obj/item/stock_parts/circuitboard/disperserback - name = T_BOARD("obstruction field disperser material deconstructor") + name = "circuitboard (obstruction field disperser material deconstructor)" build_path = /obj/machinery/disperser/back board_type = "machine" - origin_tech = "{'engineering':2,'combat':2,'wormholes':2}" + origin_tech = @'{"engineering":2,"combat":2,"wormholes":2}' req_components = list ( /obj/item/stock_parts/capacitor/super = 5 ) \ No newline at end of file diff --git a/code/modules/overmap/disperser/disperser_console.dm b/code/modules/overmap/disperser/disperser_console.dm index d7491b833d1b..14105d9f912b 100644 --- a/code/modules/overmap/disperser/disperser_console.dm +++ b/code/modules/overmap/disperser/disperser_console.dm @@ -14,7 +14,7 @@ var/obj/machinery/disperser/front/front var/obj/machinery/disperser/middle/middle var/obj/machinery/disperser/back/back - var/const/link_range = 10 //How far can the above stuff be maximum before we start complaining + var/link_range = 10 //How far can the above stuff be maximum before we start complaining var/overmapdir = 0 @@ -25,7 +25,7 @@ var/range = 1 //range of the explosion var/strength = 1 //strength of the explosion var/next_shot = 0 //round time where the next shot can start from - var/const/coolinterval = 2 MINUTES //time to wait between safe shots in deciseconds + var/coolinterval = 2 MINUTES //time to wait between safe shots in deciseconds /obj/machinery/computer/ship/disperser/Initialize() . = ..() @@ -54,13 +54,13 @@ middle = M back = B if(is_valid_setup()) - GLOB.destroyed_event.register(F, src, .proc/release_links) - GLOB.destroyed_event.register(M, src, .proc/release_links) - GLOB.destroyed_event.register(B, src, .proc/release_links) + events_repository.register(/decl/observ/destroyed, F, src, PROC_REF(release_links)) + events_repository.register(/decl/observ/destroyed, M, src, PROC_REF(release_links)) + events_repository.register(/decl/observ/destroyed, B, src, PROC_REF(release_links)) return TRUE return FALSE -obj/machinery/computer/ship/disperser/proc/is_valid_setup() +/obj/machinery/computer/ship/disperser/proc/is_valid_setup() if(front && middle && back) var/everything_in_range = (get_dist(src, front) < link_range) && (get_dist(src, middle) < link_range) && (get_dist(src, back) < link_range) var/everything_in_order = (middle.Adjacent(front) && middle.Adjacent(back)) && (front.dir == middle.dir && middle.dir == back.dir) @@ -68,9 +68,9 @@ obj/machinery/computer/ship/disperser/proc/is_valid_setup() return FALSE /obj/machinery/computer/ship/disperser/proc/release_links() - GLOB.destroyed_event.unregister(front, src, .proc/release_links) - GLOB.destroyed_event.unregister(middle, src, .proc/release_links) - GLOB.destroyed_event.unregister(back, src, .proc/release_links) + events_repository.unregister(/decl/observ/destroyed, front, src, PROC_REF(release_links)) + events_repository.unregister(/decl/observ/destroyed, middle, src, PROC_REF(release_links)) + events_repository.unregister(/decl/observ/destroyed, back, src, PROC_REF(release_links)) front = null middle = null back = null @@ -133,7 +133,7 @@ obj/machinery/computer/ship/disperser/proc/is_valid_setup() data["strength"] = strength data["range"] = range data["next_shot"] = round(get_next_shot_seconds()) - data["nopower"] = !data["faillink"] && (!front.powered() || !middle.powered() || !back.powered()) + data["nopower"] = !data["faillink"] && ((front.stat | middle.stat | back.stat) & NOPOWER) data["skill"] = user.get_skill_value(core_skill) > skill_offset var/charge = SPAN_BOLD("UNKNOWN ERROR") diff --git a/code/modules/overmap/disperser/disperser_fire.dm b/code/modules/overmap/disperser/disperser_fire.dm index 4d55dd8c04f2..c6fed02bafd9 100644 --- a/code/modules/overmap/disperser/disperser_fire.dm +++ b/code/modules/overmap/disperser/disperser_fire.dm @@ -2,7 +2,7 @@ log_and_message_admins("attempted to launch a disperser beam.") if(!link_parts()) return FALSE //no disperser, no service - if(!front.powered() || !middle.powered() || !back.powered()) + if((front.stat | middle.stat | back.stat) & NOPOWER) return FALSE //no power, no boom boom var/chargetype = get_charge_type() if(chargetype <= 0) @@ -30,8 +30,8 @@ else A.explosion_act(1) - var/list/relevant_z = GetConnectedZlevels(start.z) - for(var/mob/M in GLOB.player_list) + var/list/relevant_z = SSmapping.get_connected_levels(start.z) + for(var/mob/M in global.player_list) var/turf/T = get_turf(M) if(!T || !(T.z in relevant_z)) continue @@ -76,7 +76,7 @@ if(chargetype & finaltarget.weaknesses) var/turf/T = finaltarget.loc qdel(finaltarget) - overmap_event_handler.update_hazards(T) + SSmapping.overmap_event_handler.update_hazards(T) /obj/machinery/computer/ship/disperser/proc/handle_beam(turf/start, direction) set waitfor = FALSE diff --git a/code/modules/overmap/events/event.dm b/code/modules/overmap/events/event.dm index f5f48c34d9a8..d2d63a62c262 100644 --- a/code/modules/overmap/events/event.dm +++ b/code/modules/overmap/events/event.dm @@ -1,33 +1,32 @@ -/var/decl/overmap_event_handler/overmap_event_handler = new() - /decl/overmap_event_handler var/list/hazard_by_turf var/list/ship_events -/decl/overmap_event_handler/New() - ..() +/decl/overmap_event_handler/Initialize() + . = ..() hazard_by_turf = list() ship_events = list() -/decl/overmap_event_handler/proc/create_events(var/z_level, var/overmap_size, var/number_of_events) +/decl/overmap_event_handler/proc/create_events(var/datum/overmap/overmap) + + if(!length(overmap.valid_event_types)) + return + // Acquire the list of not-yet utilized overmap turfs on this Z-level - var/list/candidate_turfs = block(locate(OVERMAP_EDGE, OVERMAP_EDGE, z_level),locate(overmap_size - OVERMAP_EDGE, overmap_size - OVERMAP_EDGE,z_level)) - candidate_turfs = where(candidate_turfs, /proc/can_not_locate, /obj/effect/overmap/visitable) + var/list/candidate_turfs = block(OVERMAP_EDGE, OVERMAP_EDGE, overmap.assigned_z, overmap.map_size_x - OVERMAP_EDGE, overmap.map_size_y - OVERMAP_EDGE, overmap.assigned_z) + candidate_turfs = where(candidate_turfs, /proc/can_not_locate, /obj/effect/overmap) - for(var/i = 1 to number_of_events) + for(var/i = 1 to overmap.event_areas) if(!candidate_turfs.len) break - var/overmap_event_type = pick(subtypesof(/datum/overmap_event)) - var/datum/overmap_event/datum_spawn = new overmap_event_type + var/decl/overmap_event/datum_spawn = GET_DECL(pick(overmap.valid_event_types)) var/list/event_turfs = acquire_event_turfs(datum_spawn.count, datum_spawn.radius, candidate_turfs, datum_spawn.continuous) candidate_turfs -= event_turfs for(var/event_turf in event_turfs) - var/type = pick(datum_spawn.hazards) - new type(event_turf) - - qdel(datum_spawn)//idk help how do I do this better? + var/hazard_type = pick(datum_spawn.hazards) + new hazard_type(event_turf) /decl/overmap_event_handler/proc/acquire_event_turfs(var/number_of_turfs, var/distance_from_origin, var/list/candidate_turfs, var/continuous = TRUE) number_of_turfs = min(number_of_turfs, candidate_turfs.len) @@ -124,13 +123,13 @@ if(!active_hazards.len) hazard_by_turf -= T - GLOB.entered_event.unregister(T, src, /decl/overmap_event_handler/proc/on_turf_entered) - GLOB.exited_event.unregister(T, src, /decl/overmap_event_handler/proc/on_turf_exited) + events_repository.unregister(/decl/observ/entered, T, src, PROC_REF(on_turf_entered)) + events_repository.unregister(/decl/observ/exited, T, src, PROC_REF(on_turf_exited)) else hazard_by_turf |= T hazard_by_turf[T] = active_hazards - GLOB.entered_event.register(T, src,/decl/overmap_event_handler/proc/on_turf_entered) - GLOB.exited_event.register(T, src, /decl/overmap_event_handler/proc/on_turf_exited) + events_repository.register(/decl/observ/entered, T, src, PROC_REF(on_turf_entered)) + events_repository.register(/decl/observ/exited, T, src, PROC_REF(on_turf_exited)) for(var/obj/effect/overmap/visitable/ship/ship in T) for(var/datum/event/E in ship_events[ship]) @@ -144,7 +143,7 @@ /decl/overmap_event_handler/proc/is_event_in_turf(var/datum/event/E, var/turf/T) for(var/obj/effect/overmap/event/hazard in hazard_by_turf[T]) - if(E in hazard.events && E.severity == hazard.difficulty) + if((E in hazard.events) && E.severity == hazard.difficulty) return TRUE /decl/overmap_event_handler/proc/is_event_included(var/list/hazards, var/obj/effect/overmap/event/E, var/equal_or_better)//this proc is only used so it can break out of 2 loops cleanly @@ -166,7 +165,6 @@ name = "event" icon = 'icons/obj/overmap.dmi' icon_state = "blank" - opacity = 1 color = "#880000" // Events must be detected by sensors, but are otherwise instantly visible. @@ -177,13 +175,12 @@ var/list/event_icon_states var/difficulty = EVENT_LEVEL_MODERATE var/weaknesses //if the BSA can destroy them and with what - var/list/victims //basically cached events on which Z level var/list/colors = list() //Pick a color from this list on init /obj/effect/overmap/event/Initialize() . = ..() icon_state = pick(event_icon_states) - overmap_event_handler.update_hazards(loc) + SSmapping.overmap_event_handler.update_hazards(loc) if(LAZYLEN(colors)) color = pick(colors) @@ -191,20 +188,20 @@ var/turf/old_loc = loc . = ..() if(.) - overmap_event_handler.update_hazards(old_loc) - overmap_event_handler.update_hazards(loc) + SSmapping.overmap_event_handler.update_hazards(old_loc) + SSmapping.overmap_event_handler.update_hazards(loc) /obj/effect/overmap/event/forceMove(atom/destination) var/old_loc = loc . = ..() if(.) - overmap_event_handler.update_hazards(old_loc) - overmap_event_handler.update_hazards(loc) + SSmapping.overmap_event_handler.update_hazards(old_loc) + SSmapping.overmap_event_handler.update_hazards(loc) /obj/effect/overmap/event/Destroy()//takes a look at this one as well, make sure everything is A-OK var/turf/T = loc . = ..() - overmap_event_handler.update_hazards(T) + SSmapping.overmap_event_handler.update_hazards(T) /obj/effect/overmap/event/meteor name = "asteroid field" @@ -217,7 +214,7 @@ /obj/effect/overmap/event/electric name = "electrical storm" events = list(/datum/event/electrical_storm) - opacity = 0 + opacity = FALSE event_icon_states = list("electrical1", "electrical2", "electrical3", "electrical4") difficulty = EVENT_LEVEL_MAJOR weaknesses = OVERMAP_WEAKNESS_EMP @@ -233,7 +230,7 @@ /obj/effect/overmap/event/ion name = "ion cloud" events = list(/datum/event/ionstorm, /datum/event/computer_damage) - opacity = 0 + opacity = FALSE event_icon_states = list("ion1", "ion2", "ion3", "ion4") difficulty = EVENT_LEVEL_MAJOR weaknesses = OVERMAP_WEAKNESS_EMP @@ -242,7 +239,7 @@ /obj/effect/overmap/event/carp name = "carp shoal" events = list(/datum/event/carp_migration/overmap) - opacity = 0 + opacity = FALSE difficulty = EVENT_LEVEL_MODERATE event_icon_states = list("carp1", "carp2") weaknesses = OVERMAP_WEAKNESS_EXPLOSIVE | OVERMAP_WEAKNESS_FIRE @@ -255,51 +252,48 @@ colors = list("#a709db", "#c228c7", "#c444e4") //These now are basically only used to spawn hazards. Will be useful when we need to spawn group of moving hazards -/datum/overmap_event +/decl/overmap_event var/name = "map event" var/radius = 2 var/count = 6 var/hazards - var/opacity = 1 var/continuous = TRUE //if it should form continous blob, or can have gaps + var/overmap_id = OVERMAP_ID_SPACE -/datum/overmap_event/meteor +/decl/overmap_event/meteor name = "asteroid field" count = 15 radius = 4 continuous = FALSE hazards = /obj/effect/overmap/event/meteor -/datum/overmap_event/electric +/decl/overmap_event/electric name = "electrical storm" count = 11 radius = 3 - opacity = 0 hazards = /obj/effect/overmap/event/electric -/datum/overmap_event/dust +/decl/overmap_event/dust name = "dust cloud" count = 16 radius = 4 hazards = /obj/effect/overmap/event/dust -/datum/overmap_event/ion +/decl/overmap_event/ion name = "ion cloud" count = 8 radius = 3 - opacity = 0 hazards = /obj/effect/overmap/event/ion -/datum/overmap_event/carp +/decl/overmap_event/carp name = "carp shoal" count = 8 radius = 3 - opacity = 0 continuous = FALSE hazards = /obj/effect/overmap/event/carp -/datum/overmap_event/carp/major +/decl/overmap_event/carp/major name = "carp school" count = 5 radius = 4 - hazards = /obj/effect/overmap/event/carp/major \ No newline at end of file + hazards = /obj/effect/overmap/event/carp/major diff --git a/code/modules/overmap/exoplanets/_exoplanet.dm b/code/modules/overmap/exoplanets/_exoplanet.dm index 7b11b20874fd..c25daa09869c 100644 --- a/code/modules/overmap/exoplanets/_exoplanet.dm +++ b/code/modules/overmap/exoplanets/_exoplanet.dm @@ -1,259 +1,25 @@ -/obj/effect/overmap/visitable/sector/exoplanet - name = "exoplanet" - icon = 'icons/obj/overmap.dmi' - icon_state = "globe" - sector_flags = OVERMAP_SECTOR_KNOWN - free_landing = TRUE - var/area/planetary_area - - var/lightlevel = 0 //This default makes turfs not generate light. Adjust to have exoplanents be lit. - var/night = TRUE - var/daycycle //How often do we change day and night - var/daycolumn = 0 //Which column's light needs to be updated next? - var/daycycle_column_delay = 10 SECONDS - - // maximum size dimensions, if less than world's dimensions, invisible walls will be spawned - var/maxx - var/maxy - //realworld coordinates taking in account the fake world's edge - var/x_origin - var/y_origin - var/x_size - var/y_size - - var/landmark_type = /obj/effect/shuttle_landmark/automatic - - var/list/rock_colors = list(COLOR_ASTEROID_ROCK) - var/list/plant_colors = list("RANDOM") - var/grass_color - var/surface_color = COLOR_ASTEROID_ROCK - var/water_color = "#436499" - var/image/skybox_image - - var/list/actors = list() //things that appear in engravings on xenoarch finds. - var/list/species = list() //list of names to use for simple animals instead of 'alien creature' - - var/datum/gas_mixture/atmosphere - var/list/breathgas = list() //list of gases animals/plants require to survive - var/badgas //id of gas that is toxic to life here - - var/repopulating = 0 - var/repopulate_types = list() // animals which have died that may come back - var/list/fauna_types = list() // possible types of mobs to spawn - var/list/megafauna_types = list() // possibble types of megafauna to spawn - var/list/animals = list() // rerences to mobs 'born' on this planet - var/max_animal_count - - var/flora_diversity = 4 // max number of different seeds growing here - var/has_trees = TRUE // if large flora should be generated - var/list/small_flora_types = list() // seeds of 'small' flora - var/list/big_flora_types = list() // seeds of tree-tier flora - - // themes are datums affecting various parameters of the planet and spawning their own maps - var/max_themes = 2 - var/list/possible_themes = list( - /datum/exoplanet_theme = 30, - /datum/exoplanet_theme/mountains = 100, - /datum/exoplanet_theme/radiation_bombing = 10, - /datum/exoplanet_theme/ruined_city = 5, - /datum/exoplanet_theme/robotic_guardians = 10 - ) - var/list/themes = list() // themes that have been picked to be applied to this planet - - var/list/map_generators = list() - - //Flags deciding what features to pick - var/ruin_tags_whitelist - var/ruin_tags_blacklist - var/features_budget = 4 - var/list/possible_features = list() - var/list/spawned_features - - var/habitability_class // if it's above bad, atmosphere will be adjusted to be better for humans (no extreme temps / oxygen to breathe) - -/obj/effect/overmap/visitable/sector/exoplanet/Initialize(mapload, z_level) - if(GLOB.using_map.use_overmap) - forceMove(locate(1, 1, z_level)) - return ..() - -/obj/effect/overmap/visitable/sector/exoplanet/proc/build_level(max_x, max_y) - maxx = max_x ? max_x : world.maxx - maxy = max_y ? max_y : world.maxy - x_origin = TRANSITIONEDGE + 1 - y_origin = TRANSITIONEDGE + 1 - x_size = maxx - 2 * (TRANSITIONEDGE + 1) - y_size = maxy - 2 * (TRANSITIONEDGE + 1) - planetary_area = new planetary_area() - var/themes_num = min(length(possible_themes), rand(1, max_themes)) - for(var/i = 1 to themes_num) - var/datum/exoplanet_theme/T = pickweight(possible_themes) - themes += new T - possible_themes -= T - name = "[generate_planet_name()], \a [name]" - - generate_habitability() - generate_atmosphere() - for(var/datum/exoplanet_theme/T in themes) - T.adjust_atmosphere(src) - generate_flora() - generate_map() - generate_features() - for(var/datum/exoplanet_theme/T in themes) - T.after_map_generation(src) - generate_landing(2) - generate_daycycle() - generate_planet_image() - START_PROCESSING(SSobj, src) - -//attempt at more consistent history generation for xenoarch finds. -/obj/effect/overmap/visitable/sector/exoplanet/proc/get_engravings() - if(!actors.len) - actors += pick("alien humanoid","an amorphic blob","a short, hairy being","a rodent-like creature","a robot","a primate","a reptilian alien","an unidentifiable object","a statue","a starship","unusual devices","a structure") - actors += pick("alien humanoids","amorphic blobs","short, hairy beings","rodent-like creatures","robots","primates","reptilian aliens") - - var/engravings = "[actors[1]] \ - [pick("surrounded by","being held aloft by","being struck by","being examined by","communicating with")] \ - [actors[2]]" - if(prob(50)) - engravings += ", [pick("they seem to be enjoying themselves","they seem extremely angry","they look pensive","they are making gestures of supplication","the scene is one of subtle horror","the scene conveys a sense of desperation","the scene is completely bizarre")]" - engravings += "." - return engravings +///////////////////////////////////////////////////////////////////////// +// Exoplanet +///////////////////////////////////////////////////////////////////////// -/obj/effect/overmap/visitable/sector/exoplanet/Process(wait, tick) - if(animals.len < 0.5*max_animal_count && !repopulating) - repopulating = 1 - max_animal_count = round(max_animal_count * 0.5) - - handle_atmosphere() - - if(repopulating) - handle_repopulation() - - if(daycycle) - if(tick % round(daycycle / wait) == 0) - night = !night - daycolumn = 1 - if(daycolumn && tick % round(daycycle_column_delay / wait) == 0) - update_daynight() - -/obj/effect/overmap/visitable/sector/exoplanet/proc/update_daynight() - var/light = 0.1 - if(!night) - light = lightlevel - for(var/turf/simulated/floor/exoplanet/T in block(locate(daycolumn,1,min(map_z)),locate(daycolumn,maxy,max(map_z)))) - T.set_light(light, 0.1, 2) - daycolumn++ - if(daycolumn > maxx) - daycolumn = 0 - -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_map() - var/list/grasscolors = plant_colors.Copy() - grasscolors -= "RANDOM" - if(length(grasscolors)) - grass_color = pick(grasscolors) - - for(var/datum/exoplanet_theme/T in themes) - T.before_map_generation(src) - for(var/zlevel in map_z) - var/list/edges - edges += block(locate(1, 1, zlevel), locate(TRANSITIONEDGE, maxy, zlevel)) - edges |= block(locate(maxx-TRANSITIONEDGE, 1, zlevel),locate(maxx, maxy, zlevel)) - edges |= block(locate(1, 1, zlevel), locate(maxx, TRANSITIONEDGE, zlevel)) - edges |= block(locate(1, maxy-TRANSITIONEDGE, zlevel),locate(maxx, maxy, zlevel)) - for(var/turf/T in edges) - T.ChangeTurf(/turf/simulated/planet_edge) - for(var/map_type in map_generators) - if(ispath(map_type, /datum/random_map/noise/exoplanet)) - new map_type(null,x_origin,y_origin,zlevel,x_size,y_size,0,1,1,planetary_area, plant_colors) - else - new map_type(null,x_origin,y_origin,zlevel,x_size,y_size,0,1,1,planetary_area) - -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_features() - for(var/T in subtypesof(/datum/map_template/ruin/exoplanet)) - var/datum/map_template/ruin/exoplanet/ruin = T - if(ruin_tags_whitelist && !(ruin_tags_whitelist & initial(ruin.ruin_tags))) - continue - if(ruin_tags_blacklist & initial(ruin.ruin_tags)) - continue - possible_features += new ruin - spawned_features = seedRuins(map_z, features_budget, /area/exoplanet, possible_features, maxx, maxy) - -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_daycycle() - if(lightlevel) - night = FALSE //we start with a day if we have light. - - //When you set daycycle ensure that the minimum is larger than [maxx * daycycle_column_delay]. - //Otherwise the right side of the exoplanet can get stuck in a forever day. - daycycle = rand(10 MINUTES, 40 MINUTES) - -//Tries to generate num landmarks, but avoids repeats. -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_landing(num = 1) - var/places = list() - var/attempts = 10*num - var/new_type = /obj/effect/shuttle_landmark/automatic - while(num) - attempts-- - var/turf/T = locate(rand(20, maxx-20), rand(20, maxy - 10),map_z[map_z.len]) - if(!T || (T in places)) // Two landmarks on one turf is forbidden as the landmark code doesn't work with it. - continue - if(attempts >= 0) // While we have the patience, try to find better spawn points. If out of patience, put them down wherever, so long as there are no repeats. - var/valid = 1 - var/list/block_to_check = block(locate(T.x - 10, T.y - 10, T.z), locate(T.x + 10, T.y + 10, T.z)) - for(var/turf/check in block_to_check) - if(!istype(get_area(check), /area/exoplanet) || check.turf_flags & TURF_FLAG_NORUINS) - valid = 0 - break - if(attempts >= 10) - if(check_collision(T.loc, block_to_check)) //While we have lots of patience, ensure landability - valid = 0 - else //Running out of patience, but would rather not clear ruins, so switch to clearing landmarks and bypass landability check - new_type = /obj/effect/shuttle_landmark/automatic/clearing - - if(!valid) - continue - - num-- - places += T - new new_type(T) +///Helper subtype for exoplanet overmap markers +/obj/effect/overmap/visitable/sector/planetoid/exoplanet + name = "exoplanet" + sector_flags = OVERMAP_SECTOR_KNOWN -/obj/effect/overmap/visitable/sector/exoplanet/get_scan_data(mob/user) +/obj/effect/overmap/visitable/sector/planetoid/exoplanet/get_scan_data(mob/user) . = ..() - var/list/extra_data = list("
    ") - if(atmosphere) - if(user.skill_check(SKILL_SCIENCE, SKILL_EXPERT) || user.skill_check(SKILL_ATMOS, SKILL_EXPERT)) - var/list/gases = list() - for(var/g in atmosphere.gas) - if(atmosphere.gas[g] > atmosphere.total_moles * 0.05) - var/decl/material/mat = decls_repository.get_decl(g) - gases += mat.gas_name - extra_data += "Atmosphere composition: [english_list(gases)]" - var/inaccuracy = rand(8,12)/10 - extra_data += "Atmosphere pressure [atmosphere.return_pressure()*inaccuracy] kPa, temperature [atmosphere.temperature*inaccuracy] K" - else if(user.skill_check(SKILL_SCIENCE, SKILL_BASIC) || user.skill_check(SKILL_ATMOS, SKILL_BASIC)) - extra_data += "Atmosphere present" - extra_data += "
    " - - if(small_flora_types.len && user.skill_check(SKILL_SCIENCE, SKILL_BASIC)) - extra_data += "Xenoflora detected" - - if(animals.len && user.skill_check(SKILL_SCIENCE, SKILL_BASIC)) - extra_data += "Life traces detected" - - if(LAZYLEN(spawned_features) && user.skill_check(SKILL_SCIENCE, SKILL_ADEPT)) - var/ruin_num = 0 - for(var/datum/map_template/ruin/exoplanet/R in spawned_features) - if(!(R.ruin_tags & RUIN_NATURAL)) - ruin_num++ - if(ruin_num) - extra_data += "
    [ruin_num] possible artificial structure\s detected." - - for(var/datum/exoplanet_theme/T in themes) - if(T.get_sensor_data()) - extra_data += T.get_sensor_data() - . += jointext(extra_data, "
    ") - -/area/exoplanet - name = "\improper Planetary surface" - ambience = list('sound/effects/wind/wind_2_1.ogg','sound/effects/wind/wind_2_2.ogg','sound/effects/wind/wind_3_1.ogg','sound/effects/wind/wind_4_1.ogg','sound/effects/wind/wind_4_2.ogg','sound/effects/wind/wind_5_1.ogg') - always_unpowered = 1 - area_flags = AREA_FLAG_IS_BACKGROUND | AREA_FLAG_EXTERNAL \ No newline at end of file + var/datum/planetoid_data/E = SSmapping.planetoid_data_by_id[planetoid_id] + + if(E.has_flora() && user.skill_check(SKILL_SCIENCE, SKILL_BASIC)) + . += "Xenoflora detected
    " + if(E.has_fauna() && user.skill_check(SKILL_SCIENCE, SKILL_BASIC)) + . += "Life traces detected
    " + + if(LAZYLEN(E.subtemplates) && user.skill_check(SKILL_SCIENCE, SKILL_ADEPT)) + var/poi_num = 0 + for(var/datum/map_template/R in E.subtemplates) + if(!(R.get_template_tags() & TEMPLATE_TAG_NATURAL)) + poi_num++ + if(poi_num) + . += "
    [poi_num] possible artificial structure\s detected.
    " diff --git a/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm b/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm deleted file mode 100644 index 9510e2ca87f1..000000000000 --- a/code/modules/overmap/exoplanets/exoplanet_atmosphere.dm +++ /dev/null @@ -1,74 +0,0 @@ - - -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_atmosphere() - atmosphere = new - if(habitability_class == HABITABILITY_IDEAL) - atmosphere.adjust_gas(/decl/material/gas/oxygen, MOLES_O2STANDARD, 0) - atmosphere.adjust_gas(/decl/material/gas/nitrogen, MOLES_N2STANDARD) - else //let the fuckery commence - var/list/newgases = subtypesof(/decl/material/gas) - newgases = newgases.Copy() // So we don't mutate the global list. - if(prob(50)) //alium gas should be slightly less common than mundane shit - newgases -= /decl/material/gas/alien - newgases -= /decl/material/liquid/water - - var/total_moles = MOLES_CELLSTANDARD * rand(80,120)/100 - var/badflag = 0 - - //Breathable planet - if(habitability_class == HABITABILITY_OKAY) - atmosphere.gas[/decl/material/gas/oxygen] += MOLES_O2STANDARD - total_moles -= MOLES_O2STANDARD - badflag = XGM_GAS_FUEL|XGM_GAS_CONTAMINANT - - var/gasnum = rand(1,4) - var/i = 1 - var/sanity = prob(99.9) - while(i <= gasnum && total_moles && newgases.len) - if(badflag && sanity) - for(var/g in newgases) - var/decl/material/mat = decls_repository.get_decl(g) - if(mat.gas_flags & badflag) - newgases -= g - var/ng = pick_n_take(newgases) //pick a gas - var/decl/material/mat = decls_repository.get_decl(ng) - if(sanity) //make sure atmosphere is not flammable... always - if(mat.gas_flags & XGM_GAS_OXIDIZER) - badflag |= XGM_GAS_FUEL - if(mat.gas_flags & XGM_GAS_FUEL) - badflag |= XGM_GAS_OXIDIZER - sanity = 0 - - var/part = total_moles * rand(3,80)/100 //allocate percentage to it - if(i == gasnum || !newgases.len) //if it's last gas, let it have all remaining moles - part = total_moles - atmosphere.gas[ng] += part - total_moles = max(total_moles - part, 0) - i++ - -//Tries to 'reset' planet's surface atmos to normal values -/obj/effect/overmap/visitable/sector/exoplanet/proc/handle_atmosphere() - if(!atmosphere) - return - for(var/zlevel in map_z) - var/zone/Z - for(var/i = TRANSITIONEDGE to maxx - TRANSITIONEDGE) - var/turf/simulated/floor/exoplanet/T = locate(i, 2, zlevel) - if(istype(T) && T.zone && T.zone.contents.len > (maxx*maxy*0.25)) //if it's a zone quarter of zlevel, good enough odds it's planetary main one - Z = T.zone - break - if(Z && !Z.fire_tiles.len && !atmosphere.compare(Z.air)) //let fire die out first if there is one - var/datum/gas_mixture/daddy = new() //make a fake 'planet' zone gas - daddy.copy_from(atmosphere) - daddy.group_multiplier = Z.air.group_multiplier - Z.air.equalize(daddy) - -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_habitability() - var/roll = rand(1,100) - switch(roll) - if(1 to 10) - habitability_class = HABITABILITY_IDEAL - if(11 to 50) - habitability_class = HABITABILITY_OKAY - else - habitability_class = HABITABILITY_BAD \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/exoplanet_fauna.dm b/code/modules/overmap/exoplanets/exoplanet_fauna.dm deleted file mode 100644 index b87eba5134f5..000000000000 --- a/code/modules/overmap/exoplanets/exoplanet_fauna.dm +++ /dev/null @@ -1,106 +0,0 @@ - -/obj/effect/overmap/visitable/sector/exoplanet/proc/remove_animal(var/mob/M) - animals -= M - GLOB.death_event.unregister(M, src) - GLOB.destroyed_event.unregister(M, src) - repopulate_types |= M.type - -/obj/effect/overmap/visitable/sector/exoplanet/proc/handle_repopulation() - for(var/i = 1 to round(max_animal_count - animals.len)) - if(prob(10)) - var/turf/simulated/T = pick_area_turf(planetary_area, list(/proc/not_turf_contains_dense_objects)) - var/mob_type = pick(repopulate_types) - var/mob/S = new mob_type(T) - track_animal(S) - adapt_animal(S) - if(animals.len >= max_animal_count) - repopulating = 0 - -/obj/effect/overmap/visitable/sector/exoplanet/proc/track_animal(mob/A) - animals += A - GLOB.death_event.register(A, src, /obj/effect/overmap/visitable/sector/exoplanet/proc/remove_animal) - GLOB.destroyed_event.register(A, src, /obj/effect/overmap/visitable/sector/exoplanet/proc/remove_animal) - -/obj/effect/overmap/visitable/sector/exoplanet/proc/adapt_animal(var/mob/living/simple_animal/A) - if(species[A.type]) - A.SetName(species[A.type]) - A.real_name = species[A.type] - else - A.SetName("alien creature") - A.real_name = "alien creature" - A.verbs |= /mob/living/simple_animal/proc/name_species - if(atmosphere) - //Set up gases for living things - var/list/all_gasses = subtypesof(/decl/material/gas) - if(!LAZYLEN(breathgas)) - var/list/goodgases = all_gasses.Copy() - var/gasnum = min(rand(1,3), goodgases.len) - for(var/i = 1 to gasnum) - var/gas = pick(goodgases) - breathgas[gas] = round(0.4*goodgases[gas], 0.1) - goodgases -= gas - if(!badgas) - var/list/badgases = all_gasses.Copy() - badgases -= atmosphere.gas - badgas = pick(badgases) - - A.minbodytemp = atmosphere.temperature - 20 - A.maxbodytemp = atmosphere.temperature + 30 - A.bodytemperature = (A.maxbodytemp+A.minbodytemp)/2 - if(A.min_gas) - A.min_gas = breathgas.Copy() - if(A.max_gas) - A.max_gas = list() - A.max_gas[badgas] = 5 - else - A.min_gas = null - A.max_gas = null - for(var/datum/exoplanet_theme/T in themes) - T.adapt_animal(src, A) - -/obj/effect/overmap/visitable/sector/exoplanet/proc/get_random_species_name() - return pick("nol","shan","can","fel","xor")+pick("a","e","o","t","ar")+pick("ian","oid","ac","ese","inian","rd") - -/obj/effect/overmap/visitable/sector/exoplanet/proc/rename_species(var/species_type, var/newname, var/force = FALSE) - if(species[species_type] && !force) - return FALSE - - species[species_type] = newname - log_and_message_admins("renamed [species_type] to [newname]") - for(var/mob/living/simple_animal/A in animals) - if(istype(A,species_type)) - A.SetName(newname) - A.real_name = newname - A.verbs -= /mob/living/simple_animal/proc/name_species - return TRUE - -// Landmarks placed by random map generator -/obj/effect/landmark/exoplanet_spawn - name = "spawn exoplanet animal" - -/obj/effect/landmark/exoplanet_spawn/Initialize() - ..() - return INITIALIZE_HINT_LATELOAD - -/obj/effect/landmark/exoplanet_spawn/LateInitialize() - . = ..() - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(istype(E)) - do_spawn(E) - -/obj/effect/landmark/exoplanet_spawn/proc/do_spawn(var/obj/effect/overmap/visitable/sector/exoplanet/planet) - if(LAZYLEN(planet.fauna_types)) - var/beastie = pick(planet.fauna_types) - var/mob/M = new beastie(get_turf(src)) - planet.adapt_animal(M) - planet.track_animal(M) - -/obj/effect/landmark/exoplanet_spawn/megafauna - name = "spawn exoplanet megafauna" - -/obj/effect/landmark/exoplanet_spawn/megafauna/do_spawn(var/obj/effect/overmap/visitable/sector/exoplanet/planet) - if(LAZYLEN(planet.megafauna_types)) - var/beastie = pick(planet.megafauna_types) - var/mob/M = new beastie(get_turf(src)) - planet.adapt_animal(M) - planet.track_animal(M) diff --git a/code/modules/overmap/exoplanets/exoplanet_flora.dm b/code/modules/overmap/exoplanets/exoplanet_flora.dm deleted file mode 100644 index f376e0a2d2db..000000000000 --- a/code/modules/overmap/exoplanets/exoplanet_flora.dm +++ /dev/null @@ -1,75 +0,0 @@ -//Generates initial generic alien plants -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_flora() - for(var/i = 1 to flora_diversity) - var/datum/seed/S = new() - S.randomize() - var/planticon = "alien[rand(1,4)]" - S.set_trait(TRAIT_PRODUCT_ICON,planticon) - S.set_trait(TRAIT_PLANT_ICON,planticon) - var/color = pick(plant_colors) - if(color == "RANDOM") - color = get_random_colour(0,75,190) - S.set_trait(TRAIT_PLANT_COLOUR,color) - var/carnivore_prob = rand(100) - if(carnivore_prob < 10) - S.set_trait(TRAIT_CARNIVOROUS,2) - S.set_trait(TRAIT_SPREAD,1) - else if(carnivore_prob < 20) - S.set_trait(TRAIT_CARNIVOROUS,1) - adapt_seed(S) - small_flora_types += S - if(has_trees) - var/tree_diversity = max(1,flora_diversity/2) - for(var/i = 1 to tree_diversity) - var/datum/seed/S = new() - S.randomize() - S.set_trait(TRAIT_PRODUCT_ICON,"alien[rand(1,5)]") - S.set_trait(TRAIT_PLANT_ICON,"tree") - S.set_trait(TRAIT_SPREAD,0) - S.set_trait(TRAIT_HARVEST_REPEAT,1) - S.set_trait(TRAIT_LARGE,1) - var/color = pick(plant_colors) - if(color == "RANDOM") - color = get_random_colour(0,75,190) - S.set_trait(TRAIT_LEAVES_COLOUR,color) - S.chems[/decl/material/solid/wood] = 1 - adapt_seed(S) - big_flora_types += S - -//Adapts seeds to this planet's atmopshere. Any special planet-speicific adaptations should go here too -/obj/effect/overmap/visitable/sector/exoplanet/proc/adapt_seed(var/datum/seed/S) - S.set_trait(TRAIT_IDEAL_HEAT, atmosphere.temperature + rand(-5,5),800,70) - S.set_trait(TRAIT_HEAT_TOLERANCE, S.get_trait(TRAIT_HEAT_TOLERANCE) + rand(-5,5),800,70) - S.set_trait(TRAIT_LOWKPA_TOLERANCE, atmosphere.return_pressure() + rand(-5,-50),80,0) - S.set_trait(TRAIT_HIGHKPA_TOLERANCE, atmosphere.return_pressure() + rand(5,50),500,110) - if(S.exude_gasses) - S.exude_gasses -= badgas - if(atmosphere) - if(S.consume_gasses) - S.consume_gasses = list(pick(atmosphere.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it - for(var/g in atmosphere.gas) - var/decl/material/mat = decls_repository.get_decl(g) - if(mat.gas_flags & XGM_GAS_CONTAMINANT) - S.set_trait(TRAIT_TOXINS_TOLERANCE, rand(10,15)) - if(prob(50)) - var/chem_type = SSmaterials.get_random_chem(TRUE, atmosphere ? atmosphere.temperature : T0C) - if(chem_type) - var/nutriment = S.chems[/decl/material/liquid/nutriment] - S.chems.Cut() - S.chems[/decl/material/liquid/nutriment] = nutriment - S.chems[chem_type] = list(rand(1,10),rand(10,20)) - -// Landmarks placed by random map generator -/obj/effect/landmark/exoplanet_spawn/plant - name = "spawn exoplanet plant" - -/obj/effect/landmark/exoplanet_spawn/plant/do_spawn(var/obj/effect/overmap/visitable/sector/exoplanet/planet) - if(LAZYLEN(planet.small_flora_types)) - new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(src), pick(planet.small_flora_types), 1) - -/obj/effect/landmark/exoplanet_spawn/large_plant - name = "spawn exoplanet large plant" - -/obj/effect/landmark/exoplanet_spawn/large_plant/do_spawn(var/obj/effect/overmap/visitable/sector/exoplanet/planet) - if(LAZYLEN(planet.big_flora_types)) - new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(src), pick(planet.big_flora_types), 1) \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/exoplanet_skybox.dm b/code/modules/overmap/exoplanets/exoplanet_skybox.dm deleted file mode 100644 index c03862aa911e..000000000000 --- a/code/modules/overmap/exoplanets/exoplanet_skybox.dm +++ /dev/null @@ -1,69 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/get_skybox_representation() - return skybox_image - -/obj/effect/overmap/visitable/sector/exoplanet/proc/get_base_image() - var/image/base = image('icons/skybox/planet.dmi', "base") - base.color = get_surface_color() - return base - -/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_planet_image() - skybox_image = image('icons/skybox/planet.dmi', "") - - skybox_image.overlays += get_base_image() - - for(var/datum/exoplanet_theme/theme in themes) - skybox_image.overlays += theme.get_planet_image_extra() - - if(water_color) //TODO: move water levels out of randommap into exoplanet - var/image/water = image('icons/skybox/planet.dmi', "water") - water.color = water_color - water.appearance_flags = PIXEL_SCALE - water.transform = water.transform.Turn(rand(0,360)) - skybox_image.overlays += water - - if(atmosphere && atmosphere.return_pressure() > SOUND_MINIMUM_PRESSURE) - - var/atmo_color = get_atmosphere_color() - if(!atmo_color) - atmo_color = COLOR_WHITE - - var/image/clouds = image('icons/skybox/planet.dmi', "weak_clouds") - - if(water_color) - clouds.overlays += image('icons/skybox/planet.dmi', "clouds") - - clouds.color = atmo_color - skybox_image.overlays += clouds - - var/image/atmo = image('icons/skybox/planet.dmi', "atmoring") - skybox_image.underlays += atmo - - var/image/shadow = image('icons/skybox/planet.dmi', "shadow") - shadow.blend_mode = BLEND_MULTIPLY - skybox_image.overlays += shadow - - var/image/light = image('icons/skybox/planet.dmi', "lightrim") - skybox_image.overlays += light - - if(prob(20)) - var/image/rings = image('icons/skybox/planet_rings.dmi') - rings.icon_state = pick("sparse", "dense") - rings.color = pick("#f0fcff", "#dcc4ad", "#d1dcad", "#adb8dc") - rings.pixel_x = -128 - rings.pixel_y = -128 - skybox_image.overlays += rings - - skybox_image.pixel_x = rand(0,64) - skybox_image.pixel_y = rand(128,256) - skybox_image.appearance_flags = RESET_COLOR - -/obj/effect/overmap/visitable/sector/exoplanet/proc/get_surface_color() - return surface_color - -/obj/effect/overmap/visitable/sector/exoplanet/proc/get_atmosphere_color() - var/list/colors = list() - for(var/g in atmosphere.gas) - var/decl/material/mat = decls_repository.get_decl(g) - colors += mat.color - if(colors.len) - return MixColors(colors) diff --git a/code/modules/overmap/exoplanets/planet_themes/_planet_theme.dm b/code/modules/overmap/exoplanets/planet_themes/_planet_theme.dm deleted file mode 100644 index 2db010c6060f..000000000000 --- a/code/modules/overmap/exoplanets/planet_themes/_planet_theme.dm +++ /dev/null @@ -1,16 +0,0 @@ -/datum/exoplanet_theme - var/name = "Nothing Special" - -// Called by exoplanet datum before applying its map generators -/datum/exoplanet_theme/proc/before_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - -// Called by exoplanet datum after applying its map generators and spawning ruins -/datum/exoplanet_theme/proc/after_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - -/datum/exoplanet_theme/proc/adjust_atmosphere(obj/effect/overmap/visitable/sector/exoplanet/E) - -/datum/exoplanet_theme/proc/get_planet_image_extra() - -/datum/exoplanet_theme/proc/get_sensor_data() - -/datum/exoplanet_theme/proc/adapt_animal(obj/effect/overmap/visitable/sector/exoplanet/E, mob/A) diff --git a/code/modules/overmap/exoplanets/planet_themes/mountains.dm b/code/modules/overmap/exoplanets/planet_themes/mountains.dm deleted file mode 100644 index f97633d5606e..000000000000 --- a/code/modules/overmap/exoplanets/planet_themes/mountains.dm +++ /dev/null @@ -1,34 +0,0 @@ -/datum/exoplanet_theme/mountains - name = "Mountains" - var/rock_color - -/datum/exoplanet_theme/mountains/before_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - rock_color = pick(E.rock_colors) - for(var/zlevel in E.map_z) - new /datum/random_map/automata/cave_system/mountains(null,E.x_origin,E.y_origin,zlevel,E.x_size,E.y_size,0,1,1, E.planetary_area, rock_color) - -/datum/exoplanet_theme/mountains/get_planet_image_extra() - var/image/res = image('icons/skybox/planet.dmi', "mountains") - res.color = rock_color - return res - -/datum/random_map/automata/cave_system/mountains - iterations = 2 - descriptor = "space mountains" - wall_type = /turf/simulated/wall/natural - cell_threshold = 6 - var/rock_color - -/datum/random_map/automata/cave_system/mountains/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0, var/used_area, var/_rock_color) - if(_rock_color) - rock_color = _rock_color - target_turf_type = world.turf - floor_type = world.turf - ..() - -/datum/random_map/automata/cave_system/mountains/get_additional_spawns(value, var/turf/simulated/wall/natural/T) - if(istype(T)) - T.paint_color = rock_color - T.queue_icon_update() - if(use_area) - T.floor_type = use_area.base_turf diff --git a/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm b/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm deleted file mode 100644 index 1675507ce701..000000000000 --- a/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm +++ /dev/null @@ -1,28 +0,0 @@ -/datum/exoplanet_theme/radiation_bombing - name = "Radiation Bombardment" - -/datum/exoplanet_theme/radiation_bombing/adjust_atmosphere(obj/effect/overmap/visitable/sector/exoplanet/E) - if(E.atmosphere) - E.atmosphere.temperature += rand(20, 100) - E.atmosphere.update_values() - -/datum/exoplanet_theme/radiation_bombing/get_sensor_data() - return "Hotspots of radiation detected." - -/datum/exoplanet_theme/radiation_bombing/after_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - var/radiation_power = rand(10, 37.5) - var/num_craters = round(min(0.5, rand()) * 0.02 * E.maxx * E.maxy) - for(var/i = 1 to num_craters) - var/turf/simulated/T = pick_area_turf(E.planetary_area, list(/proc/not_turf_contains_dense_objects)) - if(!T) // ran out of space somehow - return - new/obj/structure/rubble/war(T) - var/datum/radiation_source/S = new(T, radiation_power, FALSE) - S.range = 4 - SSradiation.add_source(S) - T.set_light(0.4, 1, 2, l_color = PIPE_COLOR_GREEN) - for(var/turf/simulated/floor/exoplanet/crater in circlerangeturfs(T, 3)) - if(prob(10)) - new/obj/item/remains/xeno/charred(crater) - crater.melt() - crater.update_icon() diff --git a/code/modules/overmap/exoplanets/planet_themes/robotic_guardians.dm b/code/modules/overmap/exoplanets/planet_themes/robotic_guardians.dm deleted file mode 100644 index 61159eed828c..000000000000 --- a/code/modules/overmap/exoplanets/planet_themes/robotic_guardians.dm +++ /dev/null @@ -1,23 +0,0 @@ -/datum/exoplanet_theme/robotic_guardians - name = "Robotic Guardians" - var/list/guardian_types = list( - /mob/living/simple_animal/hostile/hivebot, - /mob/living/simple_animal/hostile/hivebot/range, - /mob/living/simple_animal/hostile/viscerator/hive - ) - var/list/mega_guardian_types = list( - /mob/living/simple_animal/hostile/hivebot/mega - ) - -/datum/exoplanet_theme/robotic_guardians/before_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - E.ruin_tags_whitelist |= RUIN_ALIEN - E.fauna_types |= guardian_types - E.megafauna_types |= mega_guardian_types - -/datum/exoplanet_theme/robotic_guardians/adapt_animal(obj/effect/overmap/visitable/sector/exoplanet/E, mob/A) - // Stopping robots from fighting each other - if(is_type_in_list(A, guardian_types | mega_guardian_types)) - A.faction = "Ancient Guardian" - -/datum/exoplanet_theme/robotic_guardians/get_sensor_data() - return "Movement without corresponding lifesigns detected on the surface." \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm b/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm deleted file mode 100644 index 26946592eef8..000000000000 --- a/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm +++ /dev/null @@ -1,197 +0,0 @@ - -#define FLOOR_VALUE 0 -#define WALL_VALUE 1 -#define DOOR_VALUE 3 -#define ROAD_VALUE 10 -#define ARTIFACT_VALUE 11 - -#define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) - -/datum/exoplanet_theme/ruined_city - name = "Ruined City" - var/spooky_ambience = list( - 'sound/ambience/ominous1.ogg', - 'sound/ambience/ominous2.ogg', - 'sound/ambience/ominous3.ogg' - ) - -/datum/exoplanet_theme/ruined_city/before_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - E.ruin_tags_whitelist |= RUIN_ALIEN - for(var/zlevel in E.map_z) - new /datum/random_map/city(null,E.x_origin,E.y_origin,zlevel,E.x_size,E.y_size,0,1,1, E.planetary_area) - -/datum/exoplanet_theme/ruined_city/after_map_generation(obj/effect/overmap/visitable/sector/exoplanet/E) - var/area/A = E.planetary_area - LAZYDISTINCTADD(A.ambience, spooky_ambience) - -/datum/exoplanet_theme/ruined_city/get_sensor_data() - return "Extensive artificial structures detected on the surface." - -/datum/exoplanet_theme/ruined_city/get_planet_image_extra() - return image('icons/skybox/planet.dmi', "ruins") - -// Generates a grid of roads with buildings between them -/datum/random_map/city - descriptor = "ruined city" - initial_wall_cell = 0 - initial_cell_char = -1 - var/max_building_size = 11 //Size of buildings in tiles. Must be odd number for building generation to work properly. - var/buildings_number = 4 //Buildings per block - var/list/blocks_x = list(2) //coordinates for start of blocs - var/list/blocks_y = list(2) - var/list/building_types = list( - /datum/random_map/maze/concrete = 90, - /datum/random_map/maze/lab - ) - var/list/building_maps - -/datum/random_map/city/generate_map() - var/block_size = buildings_number * max_building_size + 2 - var/num_blocks_x = round(limit_x/block_size) - var/num_blocks_y = round(limit_y/block_size) - - //Get blocks borders coordinates - for(var/i = 1 to num_blocks_x) - blocks_x += blocks_x[i] + block_size + 1 - for(var/i = 1 to num_blocks_y) - blocks_y += blocks_x[i] + block_size + 1 - blocks_x += limit_x - 1 - blocks_y += limit_y - 1 - //Draw roads - for(var/x in blocks_x) - for(var/y = 1 to limit_y) - map[TRANSLATE_COORD(x-1,y)] = ROAD_VALUE - map[TRANSLATE_COORD(x,y)] = ROAD_VALUE - map[TRANSLATE_COORD(x+1,y)] = ROAD_VALUE - for(var/y in blocks_y) - for(var/x = 1 to limit_x) - map[TRANSLATE_COORD(x,y-1)] = ROAD_VALUE - map[TRANSLATE_COORD(x,y)] = ROAD_VALUE - map[TRANSLATE_COORD(x,y+1)] = ROAD_VALUE - - //Place buildings - for(var/i = 1 to blocks_x.len - 1) - for(var/j = 1 to blocks_y.len - 1) - for(var/k = 0 to buildings_number - 1) - for(var/l = 0 to buildings_number - 1) - var/building_x = blocks_x[i] + 1 + max_building_size * k - var/building_y = blocks_y[j] + 1 + max_building_size * l - var/building_size_x = pick(7,9,9,11,11,11) - var/building_size_y = pick(7,9,9,11,11,11) - if(building_x + building_size_x >= limit_x) - continue - if(building_y + building_size_y >= limit_y) - continue - var/building_type = pickweight(building_types) - var/datum/random_map/building = new building_type(null, origin_x + building_x, origin_y + building_y, origin_z, building_size_x, building_size_y, 1, 1, 1, use_area) - LAZYADD(building_maps, building) // They're applied later to let buildings handle their own shit - return 1 - -/datum/random_map/city/get_appropriate_path(var/value) - if(value == ROAD_VALUE) - return /turf/simulated/floor/exoplanet/concrete/reinforced/road - -/datum/random_map/city/apply_to_map() - ..() - for(var/datum/random_map/building in building_maps) - building.apply_to_map() - -// Buildings - -//Generic ruin -/datum/random_map/maze/concrete - wall_type = /turf/simulated/wall/concrete - floor_type = /turf/simulated/floor/exoplanet/concrete/reinforced - preserve_map = 0 - -/datum/random_map/maze/concrete/get_appropriate_path(var/value) - if(value == WALL_VALUE) - if(prob(80)) - return /turf/simulated/wall/concrete - else - return /turf/simulated/floor/exoplanet/concrete/reinforced/damaged - return ..() - -/datum/random_map/maze/concrete/get_additional_spawns(var/value, var/turf/simulated/floor/T) - if(!istype(T)) - return - if(prob(10)) - new/obj/item/remains/xeno/charred(T) - if((T.broken && prob(80)) || prob(10)) - new/obj/structure/rubble/house(T) - if(prob(1)) - new/obj/effect/landmark/exoplanet_spawn(T) - -//Artifact containment lab -/turf/simulated/wall/containment - paint_color = COLOR_GRAY20 - floor_type = /turf/simulated/floor/fixed/alium/airless - -/turf/simulated/wall/containment/Initialize(var/ml) - . = ..(ml, /decl/material/solid/stone/concrete, /decl/material/solid/metal/aliumium) - -/datum/random_map/maze/lab - wall_type = /turf/simulated/wall/containment - floor_type = /turf/simulated/floor/fixed/alium/airless - preserve_map = 0 - var/artifacts_to_spawn = 1 - -/datum/random_map/maze/lab/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0) - if(prob(10)) - artifacts_to_spawn = rand(2,3) - ..() - -/datum/random_map/maze/lab/generate_map() - ..() - for(var/x in 1 to limit_x - 1) - for(var/y in 1 to limit_y - 1) - var/value = map[get_map_cell(x,y)] - if(value != FLOOR_VALUE) - continue - var/list/neighbors = list() - for(var/offset in list(list(0,1), list(0,-1), list(1,0), list(-1,0))) - var/char = map[get_map_cell(x + offset[1], y + offset[2])] - if(char == FLOOR_VALUE || char == DOOR_VALUE) - neighbors.Add(get_map_cell(x + offset[1], y + offset[2])) - if(length(neighbors) > 1) - continue - - map[neighbors[1]] = DOOR_VALUE - if(artifacts_to_spawn) - map[get_map_cell(x,y)] = ARTIFACT_VALUE - artifacts_to_spawn-- - var/entrance_x = pick(rand(2,limit_x-1), 1, limit_x) - var/entrance_y = pick(1, limit_y) - if(entrance_x == 1 || entrance_x == limit_x) - entrance_y = rand(2,limit_y-1) - map[get_map_cell(entrance_x,entrance_y)] = DOOR_VALUE - -/datum/random_map/maze/lab/get_appropriate_path(var/value) - if(value == ARTIFACT_VALUE) - return floor_type - if(value == DOOR_VALUE) - return floor_type - . = ..() - -/datum/random_map/maze/lab/get_additional_spawns(var/value, var/turf/simulated/floor/T) - if(!istype(T)) - return - - if(value == DOOR_VALUE) - new/obj/machinery/door/airlock/alien(T) - return - - if(value == ARTIFACT_VALUE) - var/datum/artifact_find/A = new() - new A.artifact_find_type(T) - qdel(A) - return - - if(value == FLOOR_VALUE) - if(prob(20)) - new/obj/structure/rubble/lab(T) - if(prob(20)) - new/obj/item/remains/xeno/charred(T) - - -#undef TRANSLATE_COORD \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/planet_types/barren.dm b/code/modules/overmap/exoplanets/planet_types/barren.dm deleted file mode 100644 index aab4a45ad7f7..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/barren.dm +++ /dev/null @@ -1,52 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/barren - name = "barren exoplanet" - desc = "An exoplanet that couldn't hold its atmosphere." - color = "#6c6c6c" - planetary_area = /area/exoplanet/barren - rock_colors = list(COLOR_BEIGE, COLOR_GRAY80, COLOR_BROWN) - possible_themes = list(/datum/exoplanet_theme/mountains) - map_generators = list(/datum/random_map/noise/exoplanet/barren, /datum/random_map/noise/ore/rich) - ruin_tags_blacklist = RUIN_HABITAT|RUIN_WATER - features_budget = 6 - surface_color = "#807d7a" - water_color = null - has_trees = FALSE - -/obj/effect/overmap/visitable/sector/exoplanet/barren/generate_flora() - if(prob(10)) - flora_diversity = 1 - ..() - -/obj/effect/overmap/visitable/sector/exoplanet/barren/generate_habitability() - return HABITABILITY_BAD - -/obj/effect/overmap/visitable/sector/exoplanet/barren/generate_atmosphere() - ..() - atmosphere.remove_ratio(0.9) - -/datum/random_map/noise/exoplanet/barren - descriptor = "barren exoplanet" - smoothing_iterations = 4 - land_type = /turf/simulated/floor/exoplanet/barren - flora_prob = 0.1 - large_flora_prob = 0 - fauna_prob = 0 - -/turf/simulated/floor/exoplanet/barren - name = "ground" - icon = 'icons/turf/flooring/asteroid.dmi' - icon_state = "asteroid" - -/turf/simulated/floor/exoplanet/barren/on_update_icon() - cut_overlays() - if(prob(20)) - add_overlay(image('icons/turf/flooring/decals.dmi', "asteroid[rand(0,9)]")) - -/turf/simulated/floor/exoplanet/barren/Initialize() - . = ..() - update_icon() - -/area/exoplanet/barren - name = "\improper Planetary surface" - ambience = list('sound/effects/wind/wind_2_1.ogg','sound/effects/wind/wind_2_2.ogg','sound/effects/wind/wind_3_1.ogg','sound/effects/wind/wind_4_1.ogg','sound/effects/wind/wind_4_2.ogg','sound/effects/wind/wind_5_1.ogg') - base_turf = /turf/simulated/floor/exoplanet/barren \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/planet_types/chlorine.dm b/code/modules/overmap/exoplanets/planet_types/chlorine.dm deleted file mode 100644 index b3f4d8169b4c..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/chlorine.dm +++ /dev/null @@ -1,70 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/chlorine - name = "chlorine exoplanet" - desc = "An exoplanet with a chlorine based ecosystem. Large quantities of liquid chlorine are present." - color = "#c9df9f" - planetary_area = /area/exoplanet/chlorine - rock_colors = list(COLOR_GRAY80, COLOR_PALE_GREEN_GRAY, COLOR_PALE_BTL_GREEN) - plant_colors = list("#eba487", "#ceeb87", "#eb879c", "#ebd687", "#f6d6c9", "#f2b3e0") - map_generators = list(/datum/random_map/noise/exoplanet/chlorine, /datum/random_map/noise/ore/poor) - ruin_tags_blacklist = RUIN_HABITAT|RUIN_WATER - surface_color = "#a3b879" - water_color = COLOR_BOTTLE_GREEN - has_trees = FALSE - flora_diversity = 5 - fauna_types = list(/mob/living/simple_animal/thinbug, /mob/living/simple_animal/hostile/retaliate/beast/samak/alt, /mob/living/simple_animal/yithian, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/retaliate/jelly) - megafauna_types = list(/mob/living/simple_animal/hostile/retaliate/jelly/mega) - -/obj/effect/overmap/visitable/sector/exoplanet/chlorine/generate_habitability() - return HABITABILITY_BAD - -/obj/effect/overmap/visitable/sector/exoplanet/chlorine/get_atmosphere_color() - return "#e5f2bd" - -/obj/effect/overmap/visitable/sector/exoplanet/chlorine/generate_map() - if(prob(50)) - lightlevel = rand(7,10)/10 //It could be night. - else - lightlevel = 0.1 - ..() - -/obj/effect/overmap/visitable/sector/exoplanet/chlorine/generate_atmosphere() - ..() - if(atmosphere) - atmosphere.adjust_gas(/decl/material/gas/chlorine, MOLES_O2STANDARD) - atmosphere.temperature = T100C - rand(0, 100) - atmosphere.update_values() - -/datum/random_map/noise/exoplanet/chlorine - descriptor = "chlorine exoplanet" - smoothing_iterations = 3 - land_type = /turf/simulated/floor/exoplanet/chlorine_sand - water_type = /turf/simulated/floor/exoplanet/water/shallow/chlorine_liquid - water_level_min = 2 - water_level_max = 3 - fauna_prob = 2 - flora_prob = 5 - large_flora_prob = 0 - -/area/exoplanet/chlorine - ambience = list('sound/effects/wind/desert0.ogg','sound/effects/wind/desert1.ogg','sound/effects/wind/desert2.ogg','sound/effects/wind/desert3.ogg','sound/effects/wind/desert4.ogg','sound/effects/wind/desert5.ogg') - base_turf = /turf/simulated/floor/exoplanet/chlorine_sand - -/turf/simulated/floor/exoplanet/water/shallow/chlorine_liquid - name = "chlorine marsh" - icon = 'icons/turf/chlorine.dmi' - icon_state = "chlorine_liquid" - desc = "A pool of noxious liquid chlorine. It's full of silt and plant matter." - dirt_color = "#d2e0b7" - reagent_type = /decl/material/gas/chlorine - -/turf/simulated/floor/exoplanet/chlorine_sand - name = "chlorinated sand" - icon = 'icons/turf/chlorine.dmi' - icon_state = "chlorine_sand1" - desc = "Sand that has been heavily contaminated by chlorine." - dirt_color = "#d2e0b7" - footstep_type = /decl/footsteps/sand - -/turf/simulated/floor/exoplanet/chlorine_sand/Initialize(var/ml) - . = ..() - icon_state = "chlorine_sand[rand(0,11)]" diff --git a/code/modules/overmap/exoplanets/planet_types/desert.dm b/code/modules/overmap/exoplanets/planet_types/desert.dm deleted file mode 100644 index 2d0b3693c2d9..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/desert.dm +++ /dev/null @@ -1,158 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/desert - name = "desert exoplanet" - desc = "An arid exoplanet with sparse biological resources but rich mineral deposits underground." - color = "#a08444" - planetary_area = /area/exoplanet/desert - rock_colors = list(COLOR_BEIGE, COLOR_PALE_YELLOW, COLOR_GRAY80, COLOR_BROWN) - plant_colors = list("#efdd6f","#7b4a12","#e49135","#ba6222","#5c755e","#420d22") - map_generators = list(/datum/random_map/noise/exoplanet/desert, /datum/random_map/noise/ore/rich) - surface_color = "#d6cca4" - water_color = null - has_trees = FALSE - flora_diversity = 4 - fauna_types = list(/mob/living/simple_animal/thinbug, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/voxslug, /mob/living/simple_animal/hostile/antlion) - megafauna_types = list(/mob/living/simple_animal/hostile/antlion/mega) - -/obj/effect/overmap/visitable/sector/exoplanet/desert/generate_map() - if(prob(70)) - lightlevel = rand(5,10)/10 //deserts are usually :lit: - ..() - -/obj/effect/overmap/visitable/sector/exoplanet/desert/generate_atmosphere() - ..() - if(atmosphere) - var/limit = 1000 - if(habitability_class <= HABITABILITY_OKAY) - var/datum/species/human/H = /datum/species/human - limit = initial(H.heat_level_1) - rand(1,10) - atmosphere.temperature = min(T20C + rand(20, 100), limit) - atmosphere.update_values() - -/obj/effect/overmap/visitable/sector/exoplanet/desert/adapt_seed(var/datum/seed/S) - ..() - if(prob(90)) - S.set_trait(TRAIT_REQUIRES_WATER,0) - else - S.set_trait(TRAIT_REQUIRES_WATER,1) - S.set_trait(TRAIT_WATER_CONSUMPTION,1) - if(prob(75)) - S.set_trait(TRAIT_STINGS,1) - if(prob(75)) - S.set_trait(TRAIT_CARNIVOROUS,2) - S.set_trait(TRAIT_SPREAD,0) - -/datum/random_map/noise/exoplanet/desert - descriptor = "desert exoplanet" - smoothing_iterations = 4 - land_type = /turf/simulated/floor/exoplanet/desert - - flora_prob = 5 - large_flora_prob = 0 - -/datum/random_map/noise/exoplanet/desert/get_additional_spawns(var/value, var/turf/T) - ..() - if(is_edge_turf(T)) - return - var/v = noise2value(value) - if(v > 6) - T.icon_state = "desert[v-1]" - if(prob(10)) - new/obj/structure/quicksand(T) - -/area/exoplanet/desert - ambience = list('sound/effects/wind/desert0.ogg','sound/effects/wind/desert1.ogg','sound/effects/wind/desert2.ogg','sound/effects/wind/desert3.ogg','sound/effects/wind/desert4.ogg','sound/effects/wind/desert5.ogg') - base_turf = /turf/simulated/floor/exoplanet/desert - -/obj/structure/quicksand - name = "sand" - icon = 'icons/obj/quicksand.dmi' - icon_state = "intact0" - density = 0 - anchored = 1 - can_buckle = 1 - buckle_dir = SOUTH - var/exposed = 0 - var/busy - -/obj/structure/quicksand/Initialize() - . = ..() - icon_state = "intact[rand(0,2)]" - -/obj/structure/quicksand/user_unbuckle_mob(mob/user) - if(buckled_mob && !user.stat && !user.restrained()) - if(busy) - to_chat(user, "[buckled_mob] is already getting out, be patient.") - return - var/delay = 60 - if(user == buckled_mob) - delay *=2 - user.visible_message( - "\The [user] tries to climb out of \the [src].", - "You begin to pull yourself out of \the [src].", - "You hear water sloushing." - ) - else - user.visible_message( - "\The [user] begins pulling \the [buckled_mob] out of \the [src].", - "You begin to pull \the [buckled_mob] out of \the [src].", - "You hear water sloushing." - ) - busy = 1 - if(do_after(user, delay, src)) - busy = 0 - if(user == buckled_mob) - if(prob(80)) - to_chat(user, "You slip and fail to get out!") - return - user.visible_message("\The [buckled_mob] pulls himself out of \the [src].") - else - user.visible_message("\The [buckled_mob] has been freed from \the [src] by \the [user].") - unbuckle_mob() - else - busy = 0 - to_chat(user, "You slip and fail to get out!") - return - -/obj/structure/quicksand/unbuckle_mob() - ..() - update_icon() - -/obj/structure/quicksand/buckle_mob(var/mob/L) - ..() - update_icon() - -/obj/structure/quicksand/on_update_icon() - if(!exposed) - return - icon_state = "open" - overlays.Cut() - if(buckled_mob) - overlays += buckled_mob - var/image/I = image(icon,icon_state="overlay") - I.layer = ABOVE_HUMAN_LAYER - overlays += I - -/obj/structure/quicksand/proc/expose() - if(exposed) - return - visible_message("The upper crust breaks, exposing treacherous quicksands underneath!") - name = "quicksand" - desc = "There is no candy at the bottom." - exposed = 1 - update_icon() - -/obj/structure/quicksand/attackby(obj/item/W, mob/user) - if(!exposed && W.force) - expose() - else - ..() - -/obj/structure/quicksand/Crossed(var/atom/movable/AM) - if(isliving(AM)) - var/mob/living/L = AM - if(L.throwing || L.can_overcome_gravity()) - return - buckle_mob(L) - if(!exposed) - expose() - to_chat(L, SPAN_DANGER("You fall into \the [src]!")) diff --git a/code/modules/overmap/exoplanets/planet_types/grass.dm b/code/modules/overmap/exoplanets/planet_types/grass.dm deleted file mode 100644 index 066c378d6a03..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/grass.dm +++ /dev/null @@ -1,68 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/grass - name = "lush exoplanet" - desc = "Planet with abundant flora and fauna." - color = "#407c40" - planetary_area = /area/exoplanet/grass - rock_colors = list(COLOR_ASTEROID_ROCK, COLOR_GRAY80, COLOR_BROWN) - plant_colors = list("#0e1e14","#1a3e38","#5a7467","#9eab88","#6e7248", "RANDOM") - map_generators = list(/datum/random_map/noise/exoplanet/grass) - flora_diversity = 6 - fauna_types = list(/mob/living/simple_animal/yithian, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/retaliate/jelly) - megafauna_types = list(/mob/living/simple_animal/hostile/retaliate/parrot/space/megafauna, /mob/living/simple_animal/hostile/retaliate/goose/dire) - -/obj/effect/overmap/visitable/sector/exoplanet/grass/generate_map() - if(prob(40)) - lightlevel = rand(1,7)/10 //give a chance of twilight jungle - ..() - -/obj/effect/overmap/visitable/sector/exoplanet/grass/generate_atmosphere() - ..() - if(atmosphere) - atmosphere.temperature = T20C + rand(10, 30) - atmosphere.update_values() - -/obj/effect/overmap/visitable/sector/exoplanet/grass/get_surface_color() - return grass_color - -/obj/effect/overmap/visitable/sector/exoplanet/grass/adapt_seed(var/datum/seed/S) - ..() - var/carnivore_prob = rand(100) - if(carnivore_prob < 30) - S.set_trait(TRAIT_CARNIVOROUS,2) - if(prob(75)) - S.get_trait(TRAIT_STINGS, 1) - else if(carnivore_prob < 60) - S.set_trait(TRAIT_CARNIVOROUS,1) - if(prob(50)) - S.get_trait(TRAIT_STINGS) - if(prob(15) || (S.get_trait(TRAIT_CARNIVOROUS) && prob(40))) - S.set_trait(TRAIT_BIOLUM,1) - S.set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190)) - - if(prob(30)) - S.set_trait(TRAIT_PARASITE,1) - if(!S.get_trait(TRAIT_LARGE)) - var/vine_prob = rand(100) - if(vine_prob < 15) - S.set_trait(TRAIT_SPREAD,2) - else if(vine_prob < 30) - S.set_trait(TRAIT_SPREAD,1) - -/area/exoplanet/grass - base_turf = /turf/simulated/floor/exoplanet/grass - ambience = list('sound/effects/wind/wind_2_1.ogg','sound/effects/wind/wind_2_2.ogg','sound/effects/wind/wind_3_1.ogg','sound/effects/wind/wind_4_1.ogg','sound/ambience/eeriejungle2.ogg','sound/ambience/eeriejungle1.ogg') - -/area/exoplanet/grass/play_ambience(var/mob/living/L) - ..() - if(!L.ear_deaf && L.client && !L.client.ambience_playing) - L.client.ambience_playing = 1 - L.playsound_local(get_turf(L),sound('sound/ambience/jungle.ogg', repeat = 1, wait = 0, volume = 25, channel = GLOB.ambience_sound_channel)) - -/datum/random_map/noise/exoplanet/grass - descriptor = "grass exoplanet" - smoothing_iterations = 2 - land_type = /turf/simulated/floor/exoplanet/grass - water_type = /turf/simulated/floor/exoplanet/water/shallow - - flora_prob = 10 - large_flora_prob = 30 diff --git a/code/modules/overmap/exoplanets/planet_types/shrouded.dm b/code/modules/overmap/exoplanets/planet_types/shrouded.dm deleted file mode 100644 index 4a71285659ca..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/shrouded.dm +++ /dev/null @@ -1,70 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/shrouded - name = "shrouded exoplanet" - desc = "An exoplanet shrouded in a perpetual storm of bizzare, light absorbing particles." - color = "#783ca4" - planetary_area = /area/exoplanet/shrouded - rock_colors = list(COLOR_INDIGO, COLOR_DARK_BLUE_GRAY, COLOR_NAVY_BLUE) - plant_colors = list("#3c5434", "#2f6655", "#0e703f", "#495139", "#394c66", "#1a3b77", "#3e3166", "#52457c", "#402d56", "#580d6d") - map_generators = list(/datum/random_map/noise/exoplanet/shrouded, /datum/random_map/noise/ore/poor) - ruin_tags_blacklist = RUIN_HABITAT - lightlevel = -0.15 - surface_color = "#3e3960" - water_color = "#2b2840" - flora_diversity = 3 - fauna_types = list(/mob/living/simple_animal/hostile/retaliate/royalcrab, - /mob/living/simple_animal/hostile/retaliate/jelly/alt, - /mob/living/simple_animal/hostile/retaliate/beast/shantak/alt, - /mob/living/simple_animal/hostile/leech) - -/obj/effect/overmap/visitable/sector/exoplanet/shrouded/generate_atmosphere() - ..() - if(atmosphere) - atmosphere.temperature = T20C - rand(10, 20) - atmosphere.update_values() - -/obj/effect/overmap/visitable/sector/exoplanet/shrouded/get_atmosphere_color() - return COLOR_BLACK - -/datum/random_map/noise/exoplanet/shrouded - descriptor = "shrouded exoplanet" - smoothing_iterations = 2 - flora_prob = 5 - large_flora_prob = 20 - megafauna_spawn_prob = 2 //Remember to change this if more types are added. - water_level_max = 3 - water_level_min = 2 - land_type = /turf/simulated/floor/exoplanet/shrouded - water_type = /turf/simulated/floor/exoplanet/water/shallow/tar - -/datum/random_map/noise/exoplanet/shrouded/get_additional_spawns(var/value, var/turf/T) - ..() - if(prob(2)) - new/obj/structure/leech_spawner(T) - -/area/exoplanet/shrouded - forced_ambience = list("sound/ambience/spookyspace1.ogg", "sound/ambience/spookyspace2.ogg") - base_turf = /turf/simulated/floor/exoplanet/shrouded - -/turf/simulated/floor/exoplanet/water/shallow/tar - name = "tar" - icon = 'icons/turf/shrouded.dmi' - icon_state = "shrouded_tar" - desc = "A pool of viscous and sticky tar." - movement_delay = 12 - reagent_type = /decl/material/liquid/tar - dirt_color = "#3e3960" - -/turf/simulated/floor/exoplanet/water/shallow/tar/get_footstep_sound(var/mob/caller) - return get_footstep(/decl/footsteps/water, caller) - - -/turf/simulated/floor/exoplanet/shrouded - name = "packed sand" - icon = 'icons/turf/shrouded.dmi' - icon_state = "shrouded" - desc = "Sand that has been packed in to solid earth." - dirt_color = "#3e3960" - -/turf/simulated/floor/exoplanet/shrouded/Initialize(var/ml) - . = ..() - icon_state = "shrouded[rand(0,8)]" diff --git a/code/modules/overmap/exoplanets/planet_types/snow.dm b/code/modules/overmap/exoplanets/planet_types/snow.dm deleted file mode 100644 index c17ec5bd34db..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/snow.dm +++ /dev/null @@ -1,46 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/snow - name = "snow exoplanet" - desc = "Cold planet with limited plant life." - color = "#dcdcdc" - planetary_area = /area/exoplanet/snow - rock_colors = list(COLOR_DARK_BLUE_GRAY, COLOR_GUNMETAL, COLOR_GRAY80, COLOR_DARK_GRAY) - plant_colors = list("#d0fef5","#93e1d8","#93e1d8", "#b2abbf", "#3590f3", "#4b4e6d") - map_generators = list( - /datum/random_map/automata/cave_system/mountains/snow, - /datum/random_map/noise/exoplanet/snow, - /datum/random_map/noise/ore/poor - ) - surface_color = "#e8faff" - water_color = "#b5dfeb" - fauna_types = list(/mob/living/simple_animal/hostile/retaliate/beast/samak, /mob/living/simple_animal/hostile/retaliate/beast/diyaab, /mob/living/simple_animal/hostile/retaliate/beast/shantak) - megafauna_types = list(/mob/living/simple_animal/hostile/retaliate/giant_crab) - -/datum/random_map/automata/cave_system/mountains/snow - iterations = 2 - descriptor = "ice mountains" - wall_type = /turf/simulated/wall/natural/ice - mineral_turf = /turf/simulated/wall/natural/random/ice - rock_color = COLOR_CYAN_BLUE - -/obj/effect/overmap/visitable/sector/exoplanet/snow/generate_atmosphere() - ..() - if(atmosphere) - var/limit = 0 - if(habitability_class <= HABITABILITY_OKAY) - var/datum/species/human/H = /datum/species/human - limit = initial(H.cold_level_1) + rand(1,10) - atmosphere.temperature = max(T0C - rand(10, 100), limit) - atmosphere.update_values() - -/datum/random_map/noise/exoplanet/snow - descriptor = "snow exoplanet" - smoothing_iterations = 1 - flora_prob = 5 - large_flora_prob = 10 - water_level_max = 3 - land_type = /turf/simulated/floor/exoplanet/snow - water_type = /turf/simulated/floor/exoplanet/ice - -/area/exoplanet/snow - ambience = list('sound/effects/wind/tundra0.ogg','sound/effects/wind/tundra1.ogg','sound/effects/wind/tundra2.ogg','sound/effects/wind/spooky0.ogg','sound/effects/wind/spooky1.ogg') - base_turf = /turf/simulated/floor/exoplanet/snow/ diff --git a/code/modules/overmap/exoplanets/planet_types/volcanic.dm b/code/modules/overmap/exoplanets/planet_types/volcanic.dm deleted file mode 100644 index e7e4aff7c8a0..000000000000 --- a/code/modules/overmap/exoplanets/planet_types/volcanic.dm +++ /dev/null @@ -1,150 +0,0 @@ -/obj/effect/overmap/visitable/sector/exoplanet/volcanic - name = "volcanic exoplanet" - desc = "A tectonically unstable planet, extremely rich in minerals." - color = "#9c2020" - planetary_area = /area/exoplanet/volcanic - rock_colors = list(COLOR_DARK_GRAY) - plant_colors = list("#a23c05","#3f1f0d","#662929","#ba6222","#7a5b3a","#120309") - max_themes = 1 - possible_themes = list( - /datum/exoplanet_theme = 100, - /datum/exoplanet_theme/robotic_guardians = 10 - ) - map_generators = list( - /datum/random_map/automata/cave_system/mountains/volcanic, - /datum/random_map/noise/exoplanet/volcanic, - /datum/random_map/noise/ore/filthy_rich - ) - ruin_tags_blacklist = RUIN_HABITAT|RUIN_WATER - surface_color = "#261e19" - water_color = "#c74d00" - flora_diversity = 3 - fauna_types = list(/mob/living/simple_animal/thinbug, /mob/living/simple_animal/hostile/retaliate/beast/shantak/lava, /mob/living/simple_animal/hostile/retaliate/beast/charbaby) - megafauna_types = list(/mob/living/simple_animal/hostile/drake) - has_trees = FALSE - -/obj/effect/overmap/visitable/sector/exoplanet/volcanic/get_atmosphere_color() - return COLOR_GRAY20 - -/obj/effect/overmap/visitable/sector/exoplanet/volcanic/generate_habitability() - return HABITABILITY_BAD - -/obj/effect/overmap/visitable/sector/exoplanet/volcanic/generate_atmosphere() - ..() - if(atmosphere) - atmosphere.temperature = T20C + rand(220, 800) - atmosphere.update_values() - -/obj/effect/overmap/visitable/sector/exoplanet/volcanic/adapt_seed(var/datum/seed/S) - ..() - S.set_trait(TRAIT_REQUIRES_WATER,0) - S.set_trait(TRAIT_HEAT_TOLERANCE, 1000 + S.get_trait(TRAIT_HEAT_TOLERANCE)) - -/obj/effect/overmap/visitable/sector/exoplanet/volcanic/adapt_animal(var/mob/living/simple_animal/A) - ..() - A.heat_damage_per_tick = 0 //animals not hot, no burning in lava - -/datum/random_map/noise/exoplanet/volcanic - descriptor = "volcanic exoplanet" - smoothing_iterations = 5 - land_type = /turf/simulated/floor/exoplanet/volcanic - water_type = /turf/simulated/floor/exoplanet/lava - water_level_min = 5 - water_level_max = 6 - - fauna_prob = 1 - flora_prob = 3 - large_flora_prob = 0 - -//Squashing most of 1 tile lava puddles -/datum/random_map/noise/exoplanet/volcanic/cleanup() - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) - if(noise2value(map[current_cell]) < water_level) - continue - var/frendos - for(var/dx in list(-1,0,1)) - for(var/dy in list(-1,0,1)) - var/tmp_cell = get_map_cell(x+dx,y+dy) - if(tmp_cell && tmp_cell != current_cell && noise2value(map[tmp_cell]) >= water_level) - frendos = 1 - break - if(!frendos) - map[current_cell] = 1 - -/area/exoplanet/volcanic - forced_ambience = list('sound/ambience/magma.ogg') - base_turf = /turf/simulated/floor/exoplanet/volcanic - -/turf/simulated/floor/exoplanet/volcanic - name = "volcanic floor" - icon = 'icons/turf/flooring/lava.dmi' - icon_state = "cold" - dirt_color = COLOR_GRAY20 - -/datum/random_map/automata/cave_system/mountains/volcanic - iterations = 2 - descriptor = "space volcanic mountains" - wall_type = /turf/simulated/wall/natural/volcanic - mineral_turf = /turf/simulated/wall/natural/random/volcanic - rock_color = COLOR_DARK_GRAY - -/datum/random_map/automata/cave_system/mountains/volcanic/get_additional_spawns(value, var/turf/simulated/wall/natural/T) - ..() - if(use_area && istype(T)) - T.floor_type = prob(90) ? use_area.base_turf : /turf/simulated/floor/exoplanet/lava - -/turf/simulated/floor/exoplanet/lava - name = "lava" - icon = 'icons/turf/flooring/lava.dmi' - icon_state = "lava" - movement_delay = 4 - dirt_color = COLOR_GRAY20 - var/list/victims - -/turf/simulated/floor/exoplanet/lava/on_update_icon() - return - -/turf/simulated/floor/exoplanet/lava/Initialize() - . = ..() - set_light(0.95, 0.5, 2, l_color = COLOR_ORANGE) - -/turf/simulated/floor/exoplanet/lava/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/turf/simulated/floor/exoplanet/lava/Entered(atom/movable/AM) - ..() - if(locate(/obj/structure/catwalk/) in src) - return - var/mob/living/L = AM - if (istype(L) && L.can_overcome_gravity()) - return - if(AM.is_burnable()) - LAZYADD(victims, weakref(AM)) - START_PROCESSING(SSobj, src) - -/turf/simulated/floor/exoplanet/lava/Exited(atom/movable/AM) - . = ..() - LAZYREMOVE(victims, weakref(AM)) - -/turf/simulated/floor/exoplanet/lava/Process() - if(locate(/obj/structure/catwalk/) in src) - victims = null - return PROCESS_KILL - for(var/weakref/W in victims) - var/atom/movable/AM = W.resolve() - if (AM == null || get_turf(AM) != src || AM.is_burnable() == FALSE) - victims -= W - continue - var/datum/gas_mixture/environment = return_air() - var/pressure = environment.return_pressure() - var/destroyed = AM.lava_act(environment, 5000 + environment.temperature, pressure) - if(destroyed == TRUE) - victims -= W - if(!LAZYLEN(victims)) - return PROCESS_KILL - -/turf/simulated/floor/exoplanet/lava/get_footstep_sound(var/mob/caller) - return get_footstep(/decl/footsteps/lava, caller) diff --git a/code/modules/overmap/exoplanets/random_map.dm b/code/modules/overmap/exoplanets/random_map.dm deleted file mode 100644 index 170b2d004bfd..000000000000 --- a/code/modules/overmap/exoplanets/random_map.dm +++ /dev/null @@ -1,107 +0,0 @@ -/datum/random_map/noise/exoplanet - descriptor = "exoplanet" - smoothing_iterations = 1 - - var/water_level - var/water_level_min = 0 - var/water_level_max = 5 - var/land_type = /turf/simulated/floor - var/water_type - - //intended x*y size, used to adjust spawn probs - var/intended_x = 150 - var/intended_y = 150 - var/large_flora_prob = 30 - var/flora_prob = 10 - var/fauna_prob = 2 - var/megafauna_spawn_prob = 0.5 //chance that a given fauna mob will instead be a megafauna - - var/list/plantcolors = list("RANDOM") - var/list/grass_cache - -/datum/random_map/noise/exoplanet/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0, var/used_area, var/list/_plant_colors) - target_turf_type = world.turf - water_level = rand(water_level_min,water_level_max) - //automagically adjust probs for bigger maps to help with lag - var/size_mod = intended_x / tlx * intended_y / tly - flora_prob *= size_mod - large_flora_prob *= size_mod - fauna_prob *= size_mod - if(_plant_colors) - plantcolors = _plant_colors - ..() - - GLOB.using_map.base_turf_by_z[num2text(tz)] = land_type - -/datum/random_map/noise/exoplanet/proc/noise2value(var/value) - return min(9,max(0,round((value/cell_range)*10))) - -/datum/random_map/noise/exoplanet/proc/is_edge_turf(turf/T) - return T.x <= TRANSITIONEDGE || T.x >= (limit_x - TRANSITIONEDGE + 1) || T.y <= TRANSITIONEDGE || T.y >= (limit_y - TRANSITIONEDGE + 1) - -/datum/random_map/noise/exoplanet/get_map_char(var/value) - if(water_type && noise2value(value) < water_level) - return "~" - return "[noise2value(value)]" - -/datum/random_map/noise/exoplanet/get_appropriate_path(var/value) - if(water_type && noise2value(value) < water_level) - return water_type - else - return land_type - -/datum/random_map/noise/exoplanet/get_additional_spawns(var/value, var/turf/T) - if(is_edge_turf(T)) - return - if(T.is_wall()) - return - var/parsed_value = noise2value(value) - switch(parsed_value) - if(2 to 3) - if(prob(fauna_prob)) - spawn_fauna(T) - if(5 to 6) - if(flora_prob > 5 && prob(flora_prob * 5)) - spawn_grass(T) - if(prob(flora_prob/3)) - spawn_flora(T) - if(7 to 9) - if(flora_prob > 1 && prob(flora_prob * 10)) - spawn_grass(T) - if(prob(flora_prob)) - spawn_flora(T) - else if(prob(large_flora_prob)) - spawn_flora(T, 1) - -/datum/random_map/noise/exoplanet/proc/spawn_fauna(var/turf/T) - if(prob(megafauna_spawn_prob)) - new /obj/effect/landmark/exoplanet_spawn/megafauna(T) - else - new /obj/effect/landmark/exoplanet_spawn(T) - -/datum/random_map/noise/exoplanet/proc/get_grass_overlay() - var/grass_num = "[rand(1,6)]" - if(!LAZYACCESS(grass_cache, grass_num)) - var/color = pick(plantcolors) - if(color == "RANDOM") - color = get_random_colour(0,75,190) - var/image/grass = overlay_image('icons/obj/flora/greygrass.dmi', "grass_[grass_num]", color, RESET_COLOR) - grass.underlays += overlay_image('icons/obj/flora/greygrass.dmi', "grass_[grass_num]_shadow", null, RESET_COLOR) - LAZYSET(grass_cache, grass_num, grass) - return grass_cache[grass_num] - -/datum/random_map/noise/exoplanet/proc/spawn_flora(var/turf/T, var/big) - if(big) - new /obj/effect/landmark/exoplanet_spawn/large_plant(T) - for(var/turf/neighbor in RANGE_TURFS(T, 1)) - spawn_grass(neighbor) - else - new /obj/effect/landmark/exoplanet_spawn/plant(T) - spawn_grass(T) - -/datum/random_map/noise/exoplanet/proc/spawn_grass(var/turf/T) - if(istype(T, water_type)) - return - if(locate(/obj/effect/floor_decal) in T) - return - new /obj/effect/floor_decal(T, null, null, get_grass_overlay()) \ No newline at end of file diff --git a/code/modules/overmap/exoplanets/turfs.dm b/code/modules/overmap/exoplanets/turfs.dm deleted file mode 100644 index afa637572637..000000000000 --- a/code/modules/overmap/exoplanets/turfs.dm +++ /dev/null @@ -1,281 +0,0 @@ -/turf/simulated/floor/exoplanet - name = "space land" - icon = 'icons/turf/desert.dmi' - icon_state = "desert" - has_resources = 1 - footstep_type = /decl/footsteps/asteroid - var/diggable = 1 - var/dirt_color = "#7c5e42" - -/turf/simulated/floor/exoplanet/can_engrave() - return FALSE - -/turf/simulated/floor/exoplanet/Initialize(var/ml) - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(istype(E)) - if(E.atmosphere) - initial_gas = E.atmosphere.gas.Copy() - temperature = E.atmosphere.temperature - else - initial_gas = list() - temperature = T0C - //Must be done here, as light data is not fully carried over by ChangeTurf (but overlays are). - set_light(E.lightlevel, 0.1, 2) - if(E.planetary_area && istype(loc, world.area)) - ChangeArea(src, E.planetary_area) - . = ..() - -/turf/simulated/floor/exoplanet/attackby(obj/item/C, mob/user) - if(diggable && istype(C,/obj/item/shovel)) - visible_message("\The [user] starts digging \the [src]") - . = TRUE - if(do_after(user, 50)) - to_chat(user,"You dig a deep pit.") - new /obj/structure/pit(src) - diggable = 0 - else - to_chat(user,"You stop shoveling.") - else if(istype(C, /obj/item/stack/tile)) - var/obj/item/stack/tile/T = C - if(T.use(1)) - playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) - ChangeTurf(/turf/simulated/floor, FALSE, FALSE, TRUE) - . = TRUE - else - return ..() - -/turf/simulated/floor/exoplanet/explosion_act(severity) - SHOULD_CALL_PARENT(FALSE) - if(!istype(src, get_base_turf_by_area(src)) && (severity == 1 || (severity == 2 && prob(40)))) - ChangeTurf(get_base_turf_by_area(src)) - -/turf/simulated/floor/exoplanet/Initialize() - . = ..() - update_icon(1) - -/turf/simulated/floor/exoplanet/on_update_icon(var/update_neighbors) - cut_overlays() - if(LAZYLEN(decals)) - add_overlay(decals) - for(var/direction in GLOB.cardinal) - var/turf/turf_to_check = get_step(src,direction) - if(!istype(turf_to_check, type)) - var/image/rock_side = image(icon, "edge[pick(0,1,2)]", dir = turn(direction, 180)) - rock_side.layer = DECAL_PLATING_LAYER - switch(direction) - if(NORTH) - rock_side.pixel_y += world.icon_size - if(SOUTH) - rock_side.pixel_y -= world.icon_size - if(EAST) - rock_side.pixel_x += world.icon_size - if(WEST) - rock_side.pixel_x -= world.icon_size - add_overlay(rock_side) - else if(update_neighbors) - turf_to_check.update_icon() - -//WAter -/turf/simulated/floor/exoplanet/water/on_update_icon() - return - -/turf/simulated/floor/exoplanet/water/is_flooded(lying_mob, absolute) - . = absolute ? ..() : lying_mob - -/turf/simulated/floor/exoplanet/water/shallow - name = "shallow water" - icon = 'icons/misc/beach.dmi' - icon_state = "seashallow" - movement_delay = 2 - footstep_type = /decl/footsteps/water - var/reagent_type = /decl/material/liquid/water - -/turf/simulated/floor/exoplanet/water/shallow/attackby(obj/item/O, var/mob/living/user) - var/obj/item/chems/RG = O - if (reagent_type && istype(RG) && ATOM_IS_OPEN_CONTAINER(RG) && RG.reagents) - RG.reagents.add_reagent(reagent_type, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this)) - user.visible_message("[user] fills \the [RG] from \the [src].","You fill \the [RG] from \the [src].") - . = TRUE - else - return ..() - -/turf/simulated/floor/exoplanet/water/update_dirt() - return // Water doesn't become dirty - -//Ice -/turf/simulated/floor/exoplanet/ice - name = "ice" - icon = 'icons/turf/snow.dmi' - icon_state = "ice" - -/turf/simulated/floor/exoplanet/ice/on_update_icon() - return - -//Snow -/turf/simulated/floor/exoplanet/snow - name = "snow" - icon = 'icons/turf/snow.dmi' - icon_state = "snow" - dirt_color = "#e3e7e8" - footstep_type = /decl/footsteps/snow - -/turf/simulated/floor/exoplanet/snow/Initialize() - . = ..() - icon_state = pick("snow[rand(1,12)]","snow0") - -/turf/simulated/floor/exoplanet/snow/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - melt() - -/turf/simulated/floor/exoplanet/snow/melt() - SetName("permafrost") - icon_state = "permafrost" - footstep_type = /decl/footsteps/asteroid - -//Grass -/turf/simulated/floor/exoplanet/grass - name = "grass" - icon = 'icons/turf/jungle.dmi' - icon_state = "greygrass" - color = "#799c4b" - footstep_type = /decl/footsteps/grass - -/turf/simulated/floor/exoplanet/grass/Initialize() - . = ..() - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(istype(E) && E.grass_color) - color = E.grass_color - if(!resources) - resources = list() - if(prob(70)) - resources[/decl/material/solid/mineral/graphite] = rand(3,5) - if(prob(5)) - resources[/decl/material/solid/metal/uranium] = rand(1,3) - if(prob(2)) - resources[/decl/material/solid/gemstone/diamond] = 1 - -/turf/simulated/floor/exoplanet/grass/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if((temperature > T0C + 200 && prob(5)) || temperature > T0C + 1000) - melt() - -/turf/simulated/floor/exoplanet/grass/melt() - SetName("scorched ground") - icon_state = "scorched" - footstep_type = /decl/footsteps/asteroid - color = null - -//Sand -/turf/simulated/floor/exoplanet/desert - name = "sand" - desc = "It's coarse and gets everywhere." - dirt_color = "#ae9e66" - footstep_type = /decl/footsteps/sand - -/turf/simulated/floor/exoplanet/desert/Initialize() - . = ..() - icon_state = "desert[rand(0,5)]" - -/turf/simulated/floor/exoplanet/desert/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if((temperature > T0C + 1700 && prob(5)) || temperature > T0C + 3000) - melt() - -/turf/simulated/floor/exoplanet/desert/melt() - SetName("molten silica") - desc = "A glassed patch of sand." - icon_state = "sandglass" - diggable = 0 - -//Concrete -/turf/simulated/floor/exoplanet/concrete - name = "concrete" - desc = "Stone-like artificial material." - icon = 'icons/turf/flooring/misc.dmi' - icon_state = "concrete" - -/turf/simulated/floor/exoplanet/concrete/on_update_icon() - cut_overlays() - if(burnt) - add_overlay(get_damage_overlay("burned[(x + y) % 3]", BLEND_MULTIPLY)) - if(broken) - add_overlay(get_damage_overlay("broken[(x + y) % 5]", BLEND_MULTIPLY)) - -/turf/simulated/floor/exoplanet/concrete/melt() - burnt = TRUE - update_icon() - -/turf/simulated/floor/exoplanet/concrete/reinforced - name = "reinforced concrete" - desc = "Stone-like artificial material. It has been reinforced with an unknown compound" - icon_state = "hexacrete" - -/turf/simulated/floor/exoplanet/concrete/reinforced/road - icon_state = "hexacrete_dark" - -/turf/simulated/floor/exoplanet/concrete/reinforced/damaged - broken = TRUE - -//Special world edge turf - -/turf/simulated/planet_edge - name = "world's edge" - desc = "Government didn't want you to see this!" - density = TRUE - blocks_air = TRUE - dynamic_lighting = FALSE - icon = null - icon_state = null - permit_ao = FALSE - -/turf/simulated/planet_edge/Initialize() - . = ..() - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(!istype(E)) - return - var/nx = x - if (x <= TRANSITIONEDGE) - nx = x + (E.maxx - 2*TRANSITIONEDGE) - 1 - else if (x >= (E.maxx - TRANSITIONEDGE)) - nx = x - (E.maxx - 2*TRANSITIONEDGE) + 1 - - var/ny = y - if(y <= TRANSITIONEDGE) - ny = y + (E.maxy - 2*TRANSITIONEDGE) - 1 - else if (y >= (E.maxy - TRANSITIONEDGE)) - ny = y - (E.maxy - 2*TRANSITIONEDGE) + 1 - - var/turf/NT = locate(nx, ny, z) - if(NT) - vis_contents = list(NT) - - //Need to put a mouse-opaque overlay there to prevent people turning/shooting towards ACTUAL location of vis_content things - var/obj/effect/overlay/O = new(src) - O.mouse_opacity = 2 - O.name = "distant terrain" - O.desc = "You need to come over there to take a better look." - -/turf/simulated/planet_edge/Bumped(atom/movable/A) - . = ..() - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(!istype(E)) - return - if(E.planetary_area && istype(loc, world.area)) - ChangeArea(src, E.planetary_area) - var/new_x = A.x - var/new_y = A.y - if(x <= TRANSITIONEDGE) - new_x = E.maxx - TRANSITIONEDGE - 1 - else if (x >= (E.maxx - TRANSITIONEDGE)) - new_x = TRANSITIONEDGE + 1 - else if (y <= TRANSITIONEDGE) - new_y = E.maxy - TRANSITIONEDGE - 1 - else if (y >= (E.maxy - TRANSITIONEDGE)) - new_y = TRANSITIONEDGE + 1 - - var/turf/T = locate(new_x, new_y, A.z) - if(T && !T.density) - A.forceMove(T) - if(isliving(A)) - var/mob/living/L = A - for(var/obj/item/grab/G in L.get_active_grabs()) - G.affecting.forceMove(T) diff --git a/code/modules/overmap/ftl_shunt/_shunt.dm b/code/modules/overmap/ftl_shunt/_shunt.dm new file mode 100644 index 000000000000..ea641c1e9b86 --- /dev/null +++ b/code/modules/overmap/ftl_shunt/_shunt.dm @@ -0,0 +1,32 @@ +#define CHARGE_TIME_PER_TON 0.1 //In deciseconds. +#define JOULES_PER_TON 5000 +#define REQUIRED_CHARGE_MULTIPLIER 0.005 + +#define FTL_START_FAILURE_FUEL 1 //Not enough fuel. +#define FTL_START_FAILURE_POWER 2 //Not enough power. +#define FTL_START_FAILURE_BROKEN 3 //ftl machine broken +#define FTL_START_FAILURE_COOLDOWN 4 //Cooling down. +#define FTL_START_FAILURE_OTHER 5 //Unspecific failure. + +#define FTL_START_CONFIRMED 6 //All good. + +#define SHUNT_SEVERITY_MINOR 1 +#define SHUNT_SEVERITY_MAJOR 2 +#define SHUNT_SEVERITY_CRITICAL 3 +#define SHUNT_SEVERITY_CATASTROPHIC 4 + +#define SHUNT_SABOTAGE_MINOR 1 +#define SHUNT_SABOTAGE_MAJOR 2 +#define SHUNT_SABOTAGE_CRITICAL 3 + +#define FTL_STATUS_COOLDOWN 1 +#define FTL_STATUS_OFFLINE 2 +#define FTL_STATUS_GOOD 3 +#define FTL_STATUS_SPOOLING_UP 4 + +#define BASE_PLOT_TIME_PER_TILE 2 SECONDS + +#define JUMP_STATUS_SAFE 1 +#define JUMP_STATUS_PLOTTING 2 +#define JUMP_STATUS_DANGEROUS 3 +#define JUMP_STATUS_NO_PLOT 4 \ No newline at end of file diff --git a/code/modules/overmap/ftl_shunt/computer.dm b/code/modules/overmap/ftl_shunt/computer.dm new file mode 100644 index 000000000000..989d9f1be8ee --- /dev/null +++ b/code/modules/overmap/ftl_shunt/computer.dm @@ -0,0 +1,273 @@ +/obj/machinery/computer/ship/ftl + name = "superluminal shunt control console" + icon_keyboard = "teleport_key" + icon_screen = "teleport" + light_color = "#77fff8" + + var/obj/machinery/ftl_shunt/core/linked_core + var/plotting_jump = FALSE + var/jump_plot_timer + var/jump_plotted = FALSE + var/to_plot_x = 1 + var/to_plot_y = 1 + +/obj/machinery/computer/ship/ftl/Initialize() + . = ..() + find_core() + +/obj/machinery/computer/ship/ftl/Destroy() + . = ..() + if(linked_core) + linked_core.ftl_computer = null + linked_core = null + +/obj/machinery/computer/ship/ftl/proc/recalc_cost() + if(!linked_core) + return INFINITY + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[z] + if(!istype(sector)) + return INFINITY + var/jump_dist = get_dist(linked, locate(linked_core.shunt_x, linked_core.shunt_y, sector.z)) + var/jump_cost = ((linked.vessel_mass * JOULES_PER_TON) / 1000) * jump_dist + return jump_cost + +/obj/machinery/computer/ship/ftl/proc/recalc_cost_power() + if(!linked_core) + return INFINITY + + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[z] + if(!istype(sector)) + return INFINITY + + var/jump_dist = get_dist(linked, locate(linked_core.shunt_x, linked_core.shunt_y, sector.z)) + var/jump_cost = ((linked.vessel_mass * JOULES_PER_TON) / 1000) * jump_dist + var/jump_cost_power = jump_cost * REQUIRED_CHARGE_MULTIPLIER + return jump_cost_power + +/obj/machinery/computer/ship/ftl/proc/get_status() + if(is_jump_unsafe()) + return JUMP_STATUS_DANGEROUS + if(plotting_jump) + return JUMP_STATUS_PLOTTING + if(jump_plotted == FALSE) + return JUMP_STATUS_NO_PLOT + else + return JUMP_STATUS_SAFE + +/obj/machinery/computer/ship/ftl/proc/is_jump_unsafe() + . = FALSE + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + var/dist = get_dist(locate(linked_core.shunt_x, linked_core.shunt_y, overmap.assigned_z), get_turf(linked)) + if(dist > linked_core.safe_jump_distance) + . = TRUE + +/obj/machinery/computer/ship/ftl/proc/plot_jump(var/x, var/y) + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + var/jump_dist = get_dist(linked, locate(x, y, overmap.assigned_z)) + var/plot_delay_mult + var/delay + if(jump_dist < linked_core.safe_jump_distance) + plot_delay_mult = 1 + else if(jump_dist < linked_core.moderate_jump_distance) + plot_delay_mult = 1.5 + else + plot_delay_mult = 2 + + delay = clamp(((jump_dist * BASE_PLOT_TIME_PER_TILE) * plot_delay_mult),1, INFINITY) + jump_plot_timer = addtimer(CALLBACK(src, PROC_REF(finish_plot), x, y), delay, TIMER_STOPPABLE) + plotting_jump = TRUE + jump_plotted = FALSE + return delay + +/obj/machinery/computer/ship/ftl/proc/finish_plot(var/x, var/y) + linked_core.shunt_x = x + linked_core.shunt_y = y + linked_core.calculate_jump_requirements() + plotting_jump = FALSE + jump_plotted = TRUE + jump_plot_timer = null + ping("Jump plotting completed!") + +/obj/machinery/computer/ship/ftl/proc/find_core() + if(!linked) + return + + if(linked_core) + linked_core.ftl_computer = null + linked_core = null + + for(var/obj/machinery/ftl_shunt/core/C in SSmachines.machinery) + if(C.z in linked.map_z) + linked_core = C + C.ftl_computer = src + break + +/obj/machinery/computer/ship/ftl/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!linked) + display_reconnect_dialog(user, "superluminal shunt management system") + return + + var/data[0] + + if(!linked_core) + find_core() + if(!linked_core) + to_chat(user, SPAN_WARNING("Unable to establish connection to superluminal shunt.")) + return + + data["ftlstatus"] = linked_core.get_status() + data["shunt_x"] = linked_core.shunt_x + data["shunt_y"] = linked_core.shunt_y + data["to_plot_x"] = to_plot_x + data["to_plot_y"] = to_plot_y + data["fuel_joules"] = (linked_core.get_fuel(linked_core.fuel_ports) / 1000) + data["fuel_conversion"] = linked_core.get_total_fuel_conversion_rate() + data["jumpcost"] = recalc_cost() + data["powercost"] = recalc_cost_power() + data["chargetime"] = linked_core.get_charge_time() + data["chargepercent"] = linked_core.chargepercent + data["maxfuel"] = linked_core.get_fuel_maximum(linked_core.fuel_ports) + data["jump_status"] = get_status() + data["power_input"] = linked_core.allowed_power_usage / 1000 + data["max_power"] = linked_core.max_power_usage / 1000 + data["max_charge"] = linked_core.max_charge / 1000 + data["target_charge"] = linked_core.target_charge / 1000 + data["charging"] = linked_core.charging + + + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "ftl_computer.tmpl", "[linked.name] Superluminal Shunt Control", 420, 530, src) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/ship/ftl/OnTopic(var/mob/user, var/list/href_list, state) + . = ..() + if(.) + return + + if (!linked) + return TOPIC_NOACTION + + if(href_list["set_shunt_x"] || href_list["set_shunt_y"]) + if(!linked_core) + return TOPIC_NOACTION + if(plotting_jump) + to_chat(user, SPAN_WARNING("Unable to alter programmed coordinates: Plotting in progress.")) + return TOPIC_REFRESH + + var/input_x = to_plot_x + var/input_y = to_plot_y + var/fumble = user.skill_check(SKILL_PILOT, SKILL_ADEPT) ? 0 : rand(-2, 2) + + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + if(href_list["set_shunt_x"]) + input_x = input(user, "Enter Destination X Coordinates", "FTL Computer", to_plot_x) as num|null + input_x += fumble + input_x = clamp(input_x, 1, overmap.map_size_x - 1) + + if(href_list["set_shunt_y"]) + input_y = input(user, "Enter Destination Y Coordinates", "FTL Computer", to_plot_y) as num|null + input_y += fumble + input_y = clamp(input_y, 1, overmap.map_size_y - 1) + + if(!CanInteract(user, state)) + return TOPIC_NOACTION + if(fumble) + to_chat(user, SPAN_WARNING("You fumble the input because of your inexperience!")) + to_plot_x = input_x + to_plot_y = input_y + jump_plotted = FALSE + return TOPIC_REFRESH + + if(href_list["start_shunt"]) + if(linked_core) + if(linked_core.jump_timer) + to_chat(user, SPAN_NOTICE("Superluminal jump warm-up in progress. Please wait for completion of jump!")) + return TOPIC_REFRESH + if(linked_core.get_status() != FTL_STATUS_GOOD) + to_chat(user, SPAN_WARNING("Superluminal shunt inoperable. Please try again later.")) + return TOPIC_REFRESH + + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + var/dist = get_dist(locate(linked_core.shunt_x, linked_core.shunt_y, overmap.assigned_z), get_turf(linked)) + if(is_jump_unsafe()) //We are above the safe jump distance, give them a warning. + var/warning = alert(user, "Current shunt distance is above safe distance! Do you wish to continue?","Jump Safety System", "Yes", "No") + if(warning == "No" || !CanInteract(user, state)) + return TOPIC_REFRESH + + if(dist > linked_core.max_jump_distance) + to_chat(user, SPAN_WARNING("Shunt aborted: Selected jump coordinates beyond maximum range.")) + return TOPIC_REFRESH + + + var/feedback = linked_core.start_shunt() + switch(feedback) + if(FTL_START_FAILURE_FUEL) + to_chat(user, SPAN_WARNING("Superluminal shunt inoperable: verify fuel levels.")) + if(FTL_START_FAILURE_POWER) + to_chat(user, SPAN_WARNING("Superluminal shunt inoperable: verify primary power.")) + if(FTL_START_FAILURE_BROKEN) + to_chat(user, SPAN_WARNING("Superluminal shunt inoperable: safety interlocks engaged.")) + if(FTL_START_FAILURE_COOLDOWN) + to_chat(user, SPAN_WARNING("Superluminal shunt inoperable: cooldown interlocks engaged.")) + if(FTL_START_FAILURE_OTHER) + to_chat(user, SPAN_WARNING("Superluminal shunt inoperable: unknown error.")) + if(FTL_START_CONFIRMED) + to_chat(user, SPAN_NOTICE("Superluminal shunt operational: spooling up.")) + return TOPIC_REFRESH + + if(href_list["cancel_shunt"]) + if(linked_core) + var/warning = alert(user, "Cancel current shunt?","Jump Safety System", "Yes", "No") + if(warning == "Yes" && CanInteract(user, state)) + linked_core.cancel_shunt(FALSE) + else + return TOPIC_REFRESH + return TOPIC_REFRESH + + if(href_list["adjust_power"]) + var/input_power + input_power = input(user, "Enter allowed power input (in kilowatts)", "FTL Computer", (linked_core.allowed_power_usage / 1000)) as num|null + if(!input_power) + return + + if(!CanInteract(user, state)) + return TOPIC_NOACTION + + input_power = input_power KILOWATTS + linked_core.allowed_power_usage = clamp(input_power, 0, linked_core.max_power_usage) + return TOPIC_REFRESH + + if(href_list["adjust_target"]) + var/target_joules + target_joules = input(user, "Enter desired capacitor charge level (in megajoules)", "FTL Computer", (linked_core.target_charge / 1000)) as num|null + if(!target_joules) + return + + if(!CanInteract(user, state)) + return TOPIC_NOACTION + + target_joules = target_joules KILOWATTS + linked_core.target_charge = clamp(target_joules, 0, linked_core.max_charge) + return TOPIC_REFRESH + + if(href_list["toggle_charge"]) + linked_core.charging = !linked_core.charging + + if(href_list["plot_jump"]) + if(jump_plot_timer) + return // already plotting a jump. + var/jd = plot_jump(to_plot_x, to_plot_y) + ping("Jump plotting initiated, ETA [jd/ (1 SECOND)] seconds.") + + if(href_list["cancel_plot"]) + if(jump_plot_timer) + deltimer(jump_plot_timer) + jump_plot_timer = null + plotting_jump = FALSE + ping("Jump plotting cancelled!") + + diff --git a/code/modules/overmap/ftl_shunt/core.dm b/code/modules/overmap/ftl_shunt/core.dm new file mode 100644 index 000000000000..5ad561f38a01 --- /dev/null +++ b/code/modules/overmap/ftl_shunt/core.dm @@ -0,0 +1,660 @@ +/obj/machinery/ftl_shunt + anchored = TRUE + icon = 'icons/obj/shunt_drive.dmi' + var/initial_id_tag = "ftl" + +/obj/machinery/ftl_shunt/core + name = "superluminal shunt core" + desc = "An immensely powerful transdimensional superluminal bridge initiator capable of forming a micro-wormhole and shunting an entire ship through it in a nanosecond." + base_type = /obj/machinery/ftl_shunt/core + uncreated_component_parts = list(/obj/item/stock_parts/ftl_core = 1) + construct_state = /decl/machine_construction/default/no_deconstruct + + var/list/fuel_ports = list() //We mainly use fusion fuels. + var/charge_time //Actually, we do use power now. This is here for the console. + var/charging = FALSE + var/jumping = FALSE + var/shunt_x = 1 + var/shunt_y = 1 + var/chargepercent = 0 + var/obj/machinery/computer/ship/ftl/ftl_computer + var/required_fuel_joules + var/required_charge //This is a function of the required fuel joules. + var/accumulated_charge + var/max_charge = 2000000 + var/target_charge + var/cooldown_delay = 5 MINUTES + var/cooldown + var/max_jump_distance = 8 //How many overmap tiles can this move the ship? + var/moderate_jump_distance = 6 + var/safe_jump_distance = 3 + var/sabotaged + var/sabotaged_amt = 0 //amount of crystals used to sabotage us. + var/max_power_usage = 5 MEGAWATTS //how much power can we POSSIBLY consume. + var/allowed_power_usage = 150 KILOWATTS + var/last_power_drawn + var/jump_delay = 2 MINUTES + var/jump_timer //used to cancel the jump. + + var/static/datum/announcement/priority/ftl_announcement = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice2.ogg')) + + var/static/shunt_start_text = "Attention! Superluminal shunt warm-up initiated! Spool-up ETA: %%TIME%%" + var/static/shunt_cancel_text = "Attention! Faster-than-light transition cancelled." + var/static/shunt_complete_text = "Attention! Faster-than-light transition completed." + var/static/shunt_spooling_text = "Attention! Superluminal shunt warm-up complete, spooling up." + + var/static/shunt_sabotage_text_minor = "Warning! Electromagnetic flux beyond safety limits - aborting shunt!" + var/static/shunt_sabotage_text_major = "Warning! Critical electromagnetic flux in accelerator core! Dumping core and aborting shunt!" + var/static/shunt_sabotage_text_critical = "ALERT! Critical malfunction in microsingularity containment core! Safety systems offline!" + + use_power = POWER_USE_OFF + power_channel = EQUIP + idle_power_usage = 1600 + icon_state = "bsd" + light_color = COLOR_BLUE + stock_part_presets = list(/decl/stock_part_preset/terminal_setup) +//Base procs + +/obj/machinery/ftl_shunt/core/Initialize(mapload, d, populate_parts) + . = ..() + set_extension(src, /datum/extension/local_network_member) + if(initial_id_tag) + var/datum/extension/local_network_member/local_network = get_extension(src, /datum/extension/local_network_member) + local_network.set_tag(null, initial_id_tag) + find_ports() + set_light(2) + target_charge = max_charge * 0.25 //Target charge set to a quarter of our maximum charge, just for weirdness prevention + +/obj/machinery/ftl_shunt/core/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + +/obj/machinery/ftl_shunt/core/Destroy() + . = ..() + for(var/obj/machinery/ftl_shunt/fuel_port/FP in fuel_ports) + FP.master = null + fuel_ports -= FP + if(ftl_computer) + ftl_computer.linked_core = null + ftl_computer = null + +/obj/machinery/ftl_shunt/core/on_update_icon() + cut_overlays() + + if(charging) + var/image/I = image('icons/obj/shunt_drive.dmi', "activating") + var/matrix/M = new() + I.transform = M + add_overlay(I) + + if(jumping) + add_overlay(image('icons/obj/shunt_drive.dmi', "activated")) + var/image/S = image('icons/obj/objects.dmi', "bhole3") + var/matrix/M = new() + M.Scale(0.75) + S.transform = M + S.alpha = 0 + animate(S, alpha = 255, time = 5.9 SECONDS) + add_overlay(S) + +/obj/machinery/ftl_shunt/core/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(sabotaged) + if(user.skill_check(SKILL_ENGINES, SKILL_ADEPT)) + switch(sabotaged) + if(SHUNT_SABOTAGE_MINOR) + . += SPAN_WARNING("It looks like it's been tampered with in some way, and the accelerator vanes seem out of place.") + if(SHUNT_SABOTAGE_MAJOR) + . += SPAN_WARNING("Light behaves oddly around the core of [src], and it looks to have been tampered with! The vanes are definitely out of place.") + if(SHUNT_SABOTAGE_CRITICAL) + . += SPAN_DANGER("Light bends around the core of [src] in a manner that eerily reminds you of a singularity... the vanes look completely misaligned!") + else + . += SPAN_WARNING("It looks like it's been tampered with, but you're not sure to what extent.") + +/obj/machinery/ftl_shunt/core/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/stack/telecrystal)) + var/obj/item/stack/telecrystal/TC = used_item + + if(TC.amount < 10) + to_chat(user, SPAN_WARNING("You don't have enough telecrystals to sabotage [src].")) + return FALSE + + var/tc_input = input(user, "How many telecrystals do you want to put in?", "TC Input", 0) as num|null + + + if(QDELETED(user) || user.incapacitated() || !user.Adjacent(src) || !(TC in user.get_held_items())) + return FALSE + + if(!tc_input) + return FALSE + + if(TC.amount < tc_input) + to_chat(user, SPAN_WARNING("You don't have enough telecrystals for that.")) + return FALSE + + to_chat(user, SPAN_DANGER("You begin to insert the crystals into [src]...")) + + if(!do_after(user, 6 SECONDS, src)) + return FALSE + + switch(tc_input) + if(10 to 24) + sabotaged = SHUNT_SABOTAGE_MINOR + if(25 to 49) + sabotaged = SHUNT_SABOTAGE_MAJOR + if(50 to INFINITY) + sabotaged = SHUNT_SABOTAGE_CRITICAL + + sabotaged_amt = tc_input + TC.use(tc_input) + to_chat(user, SPAN_DANGER("You successfully sabotage [src] by inserting the crystals!")) + return TRUE + . = ..() + +/obj/machinery/ftl_shunt/core/physical_attack_hand(var/mob/user) + if(sabotaged) + var/mob/living/human/h_user = user + if(!istype(h_user)) + return TRUE + var/skill_delay = user.skill_delay_mult(SKILL_ENGINES, 0.3) + if(!user.skill_check(SKILL_ENGINES, SKILL_BASIC)) + to_chat(user, SPAN_DANGER("You are nowhere near experienced enough to stick your hand into that thing.")) + return FALSE + to_chat(user, SPAN_NOTICE("You reach your hand inside of [src] and slowly begin to re-align the accelerator vanes...")) + if(!do_after(user, (4 SECOND * skill_delay), src)) + to_chat(user, SPAN_DANGER("You try to pull your hand away from the vanes, but you touch a conductor!")) + h_user.electrocute_act(rand(150,250), src, def_zone = user.get_active_held_item_slot()) + return TRUE + var/obj/item/stack/telecrystal/TC = new + TC.amount = sabotaged_amt + TC.forceMove(get_turf(user)) + user.put_in_hands(TC) + to_chat(user, SPAN_NOTICE("You remove \the [TC] from \the [src] and realign the accelerator vanes, preventing what could have been a catastrophe.")) + sabotaged = null + sabotaged_amt = 0 + return TRUE + . = ..() + +//Custom procs. +//Finds fuel ports. +/obj/machinery/ftl_shunt/core/proc/find_ports() + var/datum/extension/local_network_member/network = get_extension(src, /datum/extension/local_network_member) + var/datum/local_network/lan = network.get_local_network() + if(lan) + var/list/ports = lan.get_devices(/obj/machinery/ftl_shunt/fuel_port) + fuel_ports.Cut() + for(var/obj/machinery/ftl_shunt/fuel_port/FP in ports) + if(!FP.master) + FP.master = src + fuel_ports += FP + +//Starts the teleport process, returns 1-6, with 6 being the all-clear. +/obj/machinery/ftl_shunt/core/proc/start_shunt() + + if(isnull(ftl_computer)) + return + + if(isnull(ftl_computer.linked)) + return + + if(stat & BROKEN) + return FTL_START_FAILURE_BROKEN + if(stat & NOPOWER) + return FTL_START_FAILURE_POWER + + if(world.time <= cooldown) + return FTL_START_FAILURE_COOLDOWN + + if(!length(fuel_ports)) //no fuel ports + find_ports() + if(!length(fuel_ports)) + return FTL_START_FAILURE_OTHER + + calculate_jump_requirements() + + if(accumulated_charge < required_charge) + return FTL_START_FAILURE_POWER + if(max_charge < required_charge) + return FTL_START_FAILURE_POWER + + if(required_fuel_joules > get_fuel(fuel_ports)) + return FTL_START_FAILURE_FUEL + + if(sabotaged) + for(var/mob/living/human/H in global.living_mob_list_) //Give engineers a hint that something might be very, very wrong. + if(!(H.z in ftl_computer.linked.map_z)) + continue + if(H.skill_check(SKILL_ENGINES, SKILL_EXPERT)) + to_chat(H, SPAN_DANGER("The deck vibrates with a harmonic that sets your teeth on edge and fills you with dread.")) + + var/announcetxt = replacetext(shunt_start_text, "%%TIME%%", "[round(jump_delay/600)] minutes.") + + ftl_announcement.Announce(announcetxt, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg')) + update_icon() + + if(check_charge()) + jump_timer = addtimer(CALLBACK(src, PROC_REF(execute_shunt)), jump_delay, TIMER_STOPPABLE) + return FTL_START_CONFIRMED + +/obj/machinery/ftl_shunt/core/proc/calculate_jump_requirements() + var/obj/effect/overmap/visitable/site = global.overmap_sectors[z] + if(site) + var/shunt_distance + var/vessel_mass = ftl_computer.linked.get_vessel_mass() + var/shunt_turf = locate(shunt_x, shunt_y, site.z) + shunt_distance = get_dist(get_turf(ftl_computer.linked), shunt_turf) + required_fuel_joules = (vessel_mass * JOULES_PER_TON) * shunt_distance + required_charge = required_fuel_joules * REQUIRED_CHARGE_MULTIPLIER + +//Cancels the in-progress shunt. +/obj/machinery/ftl_shunt/core/proc/cancel_shunt(var/silent = FALSE) + if(!jump_timer) + return + deltimer(jump_timer) + charge_time = null + cooldown = null + required_fuel_joules = null + if(!silent) + ftl_announcement.Announce(shunt_cancel_text, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg')) + update_icon() + jump_timer = null + +//Starts the shunt, and then hands off to do_shunt to finish it. +/obj/machinery/ftl_shunt/core/proc/execute_shunt() + ftl_announcement.Announce(shunt_spooling_text, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg')) + if(sabotaged) + cancel_shunt(TRUE) + do_sabotage() + ftl_computer.jump_plotted = FALSE + return + + if(use_fuel(required_fuel_joules)) + jump_timer = addtimer(CALLBACK(src, PROC_REF(execute_shunt)), jump_delay, TIMER_STOPPABLE) + else + cancel_shunt() + return //If for some reason we don't have fuel now, just return. + + var/obj/effect/overmap/visitable/site = global.overmap_sectors[z] + if(site) + var/destination = locate(shunt_x, shunt_y, site.z) + var/jumpdist = get_dist(get_turf(ftl_computer.linked), destination) + var/obj/effect/portal/wormhole/wormhole = new(destination) //Generate a wormhole effect on overmap to give some indication that something is about to happen. + QDEL_IN(wormhole, 6 SECONDS) + addtimer(CALLBACK(src, PROC_REF(do_shunt), shunt_x, shunt_y, jumpdist, destination), 6 SECONDS) + jumping = TRUE + update_icon() + for(var/mob/living/M in global.living_mob_list_) + if(!(M.z in ftl_computer.linked.map_z)) + continue + sound_to(M, 'sound/machines/hyperspace_begin.ogg') + +/obj/machinery/ftl_shunt/core/proc/do_shunt(var/turfx, var/turfy, var/jumpdist, var/destination) //this does the actual teleportation, execute_shunt is there to give us time to do our fancy effects + ftl_computer.linked.forceMove(destination) + ftl_announcement.Announce(shunt_complete_text, "FTL Shunt Management System", new_sound = sound('sound/misc/notice2.ogg')) + cooldown = world.time + cooldown_delay + do_effects(jumpdist) + deltimer(jump_timer) + jumping = FALSE + update_use_power(POWER_USE_IDLE) + accumulated_charge -= required_charge + jump_timer = null + ftl_computer.jump_plotted = FALSE + +//Handles all the effects of the jump. +/obj/machinery/ftl_shunt/core/proc/do_effects(var/distance) //If we're jumping too far, have some !!FUN!! with people and ship systems. + var/shunt_sev + if(distance < safe_jump_distance) + shunt_sev = SHUNT_SEVERITY_MINOR + else if(distance < moderate_jump_distance) + shunt_sev = SHUNT_SEVERITY_MAJOR + else + shunt_sev = SHUNT_SEVERITY_CRITICAL + + for(var/mob/living/human/H in global.living_mob_list_) //Affect mobs, skip synthetics. + sound_to(H, 'sound/machines/hyperspace_end.ogg') + + if(!(H.z in ftl_computer.linked.map_z)) + continue + + handle_spacefloat(H) + + if(isnull(H) || QDELETED(H)) + continue + + if(H.isSynthetic()) + continue //We don't affect synthetics. + + switch(shunt_sev) + if(SHUNT_SEVERITY_MINOR) + to_chat(H, SPAN_NOTICE("You feel your insides flutter about inside of you as you are briefly shunted into an alternate dimension.")) //No major effects. + shake_camera(H, 2, 1) + + if(SHUNT_SEVERITY_MAJOR) + to_chat(H, SPAN_WARNING("You feel your insides twisted inside and out as you are violently shunted between dimensions, and you feel like something is watching you!")) + if(prob(25)) + H.set_hallucination(50, 50) + if(prob(15)) + H.vomit() + shake_camera(H, 2, 1) + + if(SHUNT_SEVERITY_CRITICAL) + to_chat(H, SPAN_DANGER("You feel an overwhelming sense of nausea and vertigo wash over you, your instincts screaming that something is wrong!")) + if(prob(50)) + H.set_hallucination(100, 100) + if(prob(45)) + H.vomit() + shake_camera(H, 5, 4) + + for(var/obj/machinery/light/L in SSmachines.machinery) //Fuck with and or break lights. + if(!(L.z in ftl_computer.linked.map_z)) + continue + switch(shunt_sev) + if(SHUNT_SEVERITY_MINOR) + if(prob(15)) + L.flicker() + if(SHUNT_SEVERITY_MAJOR) + if(prob(35)) + L.flicker() + + for(var/obj/machinery/apc/A in SSmachines.machinery) + if(!(A.z in ftl_computer.linked.map_z)) + continue + switch(shunt_sev) + if(SHUNT_SEVERITY_MAJOR) + if(prob(15)) + A.energy_fail(rand(30, 80)) + if(prob(10)) + A.overload_lighting(25) + + if(SHUNT_SEVERITY_CRITICAL) + if(prob(35)) + A.energy_fail(rand(60, 150)) + if(prob(50)) + A.overload_lighting(50) + +/obj/machinery/ftl_shunt/core/proc/handle_spacefloat(var/mob/living/human/H) + if(H.can_slip(magboots_only = TRUE)) + //Flip a coin ... + to_chat(H, SPAN_WARNING("Being untethered from a ship entering FTL is a bad idea, but you roll the dice...")) + if(prob(50)) + to_chat(H, SPAN_NOTICE("and win, surviving the energy dancing over your body. Not unharmed, however.")) + H.apply_damage(300, IRRADIATE, damage_flags = DAM_DISPERSED) + return + else + to_chat(H, SPAN_DANGER("and lose, being ripped apart in a nanosecond by energies beyond comprehension.")) + H.gib() + +/obj/machinery/ftl_shunt/core/proc/do_sabotage() + var/announcetxt + + switch(sabotaged) + if(SHUNT_SABOTAGE_MINOR) + announcetxt = shunt_sabotage_text_minor + for(var/mob/living/human/H in view(7)) + H.show_message(SPAN_DANGER("\The [src] emits a flash of incredibly bright, searing light!"), VISIBLE_MESSAGE) + H.flash_eyes(FLASH_PROTECTION_NONE) + empulse(src, 8, 10) + + if(SHUNT_SABOTAGE_MAJOR) + announcetxt = shunt_sabotage_text_major + + visible_message(SPAN_DANGER("\The [src] hisses and sparks, before the coolant lines burst and spew superheated coolant!")) //Effect One: scary text. + + explosion(get_turf(src),-1,-1,8,10) //Effect Two: blow the windows out. + + for(var/obj/machinery/apc/A in SSmachines.machinery) //Effect Three: shut down power across the ship. + if(!(A.z in ftl_computer.linked.map_z)) + continue + A.energy_fail(rand(60,80)) + + if(SHUNT_SABOTAGE_CRITICAL) + announcetxt = shunt_sabotage_text_critical + + for(var/obj/machinery/apc/A in SSmachines.machinery) //Effect One: shut down power across the ship. + if(!(A.z in ftl_computer.linked.map_z)) + continue + A.energy_fail(rand(100,120)) + + for(var/mob/living/human/H in view(7)) //scary text if you're in view, because you're fucked now boy. + H.show_message(SPAN_DANGER("The light around \the [src] warps before it emits a flash of incredibly bright, searing light!"), VISIBLE_MESSAGE) + H.flash_eyes(FLASH_PROTECTION_NONE) + + new /obj/effect/singularity/(get_turf(src)) + + + ftl_announcement.Announce(announcetxt, "FTL Shunt Management System", new_sound = sound('sound/misc/ftlsiren.ogg')) + + +//Returns status to ftl computer. +/obj/machinery/ftl_shunt/core/proc/get_status() + if(stat & (BROKEN|NOPOWER)) + return FTL_STATUS_OFFLINE + if(cooldown) + return FTL_STATUS_COOLDOWN + if(jump_timer) + return FTL_STATUS_SPOOLING_UP + else + return FTL_STATUS_GOOD + +/obj/machinery/ftl_shunt/core/proc/get_fuel(var/list/input) + . = 0 + for(var/obj/machinery/ftl_shunt/fuel_port/F in input) + . += F.get_fuel_joules(FALSE) + +/obj/machinery/ftl_shunt/core/proc/get_fuel_maximum(var/list/input) + . = 0 + for(var/obj/machinery/ftl_shunt/fuel_port/F in input) + . += F.get_fuel_joules(TRUE) + +/obj/machinery/ftl_shunt/core/proc/fuelpercentage() + if(!length(fuel_ports)) + return 0 + var/fuel_max = get_fuel_maximum(fuel_ports) + if(fuel_max == 0) + return 0 + return round(100.0*get_fuel(fuel_ports)/fuel_max, 0.1) + + +/obj/machinery/ftl_shunt/core/proc/use_fuel(var/joules_req) + var/avail_fuel = get_fuel(fuel_ports) + + if(joules_req > avail_fuel) //Not enough fuel in the system. + return FALSE + + var/list/fueled_ports = list() + var/total_joules + var/joules_per_port + var/joule_debt + + for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports) //Step one, loop through ports, sort them by those who are fully fueled and those that are not. + if(!F.has_fuel()) + continue + fueled_ports += F + + joules_per_port = (joules_req / length(fueled_ports)) + + for(var/obj/machinery/ftl_shunt/fuel_port/F in fueled_ports) //Loop through all our ports, use fuel from those that have enough and those that are partially empty. + if(F.get_fuel_joules() >= joules_per_port) //Enough fuel in this one! + if(F.use_fuel_joules(joules_per_port)) + total_joules += joules_per_port + continue + else //Not enough fuel in this port to meet the per-port quota - take as much as we can and pick up the slack with others. + var/available_fuel = F.get_fuel_joules() + if(F.use_fuel_joules(available_fuel)) + total_joules += available_fuel + joule_debt += joules_per_port - available_fuel + fueled_ports -= F //Remove this one from the pool of avaliable ports, since it's used up. + continue + + if(total_joules == joules_req) + return TRUE //All ports supplied enough fuel first go around, return early. + + if(joule_debt) //We haven't rallied up enough energy for the jump, probably from ports that were only partially fueled. + var/fuel_debt_spread = joule_debt / length(fueled_ports) + for(var/obj/machinery/ftl_shunt/fuel_port/F in fueled_ports) //Loop through all our ports, use fuel from those that have enough and those that are partially empty. + if(F.get_fuel_joules() >= fuel_debt_spread) //Enough fuel in this one! + if(F.use_fuel_joules(fuel_debt_spread)) + total_joules += fuel_debt_spread + continue + else //Not enough fuel in this port to meet the per-port quota - take as much as we can and pick up the slack with others. + var/available_fuel_debt = F.get_fuel_joules() + if(F.use_fuel_joules(available_fuel_debt)) + total_joules += available_fuel_debt + joule_debt -= available_fuel_debt + continue + + if(total_joules == joules_req && !joule_debt) + return TRUE + +/obj/machinery/ftl_shunt/core/proc/get_charge_time() + if(isnull(last_power_drawn)) + return "UNKNOWN" + return "[clamp(round((target_charge-accumulated_charge)/((last_power_drawn*CELLRATE) * 1 SECOND / SSmachines.wait), 0.1),0, INFINITY)] Seconds" + +/obj/machinery/ftl_shunt/core/proc/check_charge() + if(accumulated_charge >= required_charge) + return TRUE + +/obj/machinery/ftl_shunt/core/proc/draw_charge(var/input) + if(stat & NOPOWER) + return FALSE + + var/drawn_charge = use_power_oneoff(input) + last_power_drawn = drawn_charge + accumulated_charge += drawn_charge * CELLRATE + + return TRUE + +/obj/machinery/ftl_shunt/core/proc/get_total_fuel_conversion_rate() + var/rate + for(var/obj/machinery/ftl_shunt/fuel_port/F in fuel_ports) + rate += F.get_fuel_conversion_rate() + . = round((rate / length(fuel_ports)), 0.1) + + +/obj/machinery/ftl_shunt/core/Process() + if(stat & (BROKEN|NOPOWER)) + return + update_icon() + + if(charging) + if(accumulated_charge < target_charge) + draw_charge(allowed_power_usage) + accumulated_charge = clamp(accumulated_charge, 0, max_charge) + SSradiation.radiate(src, (active_power_usage / 1000)) + chargepercent = round(100*(accumulated_charge/max_charge), 0.1) + +/obj/machinery/ftl_shunt/fuel_port + name = "superluminal shunt fuel port" + desc = "A fuel port for an FTL shunt." + icon_state = "empty" + + var/static/list/fuels = list( + /decl/material/gas/hydrogen/tritium = 25000, + /decl/material/gas/hydrogen/deuterium = 25000, + /decl/material/gas/hydrogen = 25000, + /decl/material/solid/exotic_matter = 50000 + ) + var/obj/item/fuel_assembly/fuel + var/obj/machinery/ftl_shunt/core/master + var/max_fuel = 0 + +/obj/machinery/ftl_shunt/fuel_port/on_update_icon() + if(fuel) + icon_state = "full" + else + icon_state = "empty" + +/obj/machinery/ftl_shunt/fuel_port/Initialize() + set_extension(src, /datum/extension/local_network_member) + if(initial_id_tag) + var/datum/extension/local_network_member/local_network = get_extension(src, /datum/extension/local_network_member) + local_network.set_tag(null, initial_id_tag) + . = ..() + +/obj/machinery/ftl_shunt/fuel_port/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + +/obj/machinery/ftl_shunt/fuel_port/Destroy() + . = ..() + if(master) + master.fuel_ports -= src + master = null + QDEL_NULL(fuel) + +/obj/machinery/ftl_shunt/fuel_port/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/fuel_assembly) && !fuel) + if(!do_after(user, 2 SECONDS, src) || fuel) + return TRUE + if(!user || !user.try_unequip(used_item, src)) + return TRUE + fuel = used_item + max_fuel = get_fuel_joules(TRUE) + update_icon() + return TRUE + + . = ..() + +/obj/machinery/ftl_shunt/fuel_port/physical_attack_hand(var/mob/user) + if(fuel) + to_chat(user, SPAN_NOTICE("You begin to remove the fuel assembly from [src]...")) + if(!do_after(user, 2 SECONDS, src) || !fuel || fuel.loc != src) + return FALSE + fuel.dropInto(loc) + user.put_in_hands(fuel) + fuel = null + max_fuel = 0 + to_chat(user, SPAN_NOTICE("You remove the fuel assembly!")) + return TRUE + + . = ..() + +/obj/machinery/ftl_shunt/fuel_port/proc/has_fuel() + return !!fuel + +/obj/machinery/ftl_shunt/fuel_port/proc/get_fuel_joules(var/get_fuel_maximum) + if(fuel) + for(var/G in fuel.matter) + if(G in fuels) + . += (get_fuel_maximum ? 10000 : fuel.matter[G]) * fuels[G] + +/obj/machinery/ftl_shunt/fuel_port/proc/get_fuel_conversion_rate() //This is mostly a fluff proc, since internally everything is done in joules. + if(fuel) + for(var/G in fuel.matter) + if(G in fuels) + . = fuels[G] + +/obj/machinery/ftl_shunt/fuel_port/proc/use_fuel_joules(var/joules) + if(!fuel) + return FALSE + + for(var/G in fuel.matter) + if(G in fuels) + var/fuel_to_use = joules / fuels[G] + fuel.matter[G] -= fuel_to_use + + return TRUE + +// +// Construction MacGuffins down here. +// + +/obj/item/stock_parts/circuitboard/ftl_shunt + name = "circuit board (superluminal shunt)" + board_type = "machine" + build_path = /obj/machinery/ftl_shunt/core + origin_tech = @'{"programming":3,"magnets":5,"materials":5,"wormholes":5}' + additional_spawn_components = list(/obj/item/stock_parts/power/terminal = 1) + +/obj/item/stock_parts/ftl_core + name = "exotic matter bridge" + desc = "The beating heart of a superluminal shunt - without this, the power to manipulate space-time is out of reach." + origin_tech = @'{"programming":3,"magnets":5,"materials":5,"wormholes":5}' + icon = 'icons/obj/items/stock_parts/stock_parts.dmi' + icon_state = "smes_coil" + color = COLOR_YELLOW + matter = list( + /decl/material/solid/exotic_matter = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/plasteel = MATTER_AMOUNT_PRIMARY + ) diff --git a/code/modules/overmap/internet/internet_circuitboards.dm b/code/modules/overmap/internet/internet_circuitboards.dm new file mode 100644 index 000000000000..3e865580bda4 --- /dev/null +++ b/code/modules/overmap/internet/internet_circuitboards.dm @@ -0,0 +1,37 @@ +/obj/item/stock_parts/circuitboard/internet_uplink + name = "circuitboard (PLEXUS uplink)" + board_type = "machine" + build_path = /obj/machinery/internet_uplink + origin_tech = @'{"magnets":4,"wormholes":3,"powerstorage":3,"engineering":3}' + req_components = list( + /obj/item/stock_parts/capacitor = 2, + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/smes_coil = 1 + ) + additional_spawn_components = null + +/obj/item/stock_parts/circuitboard/internet_uplink_computer + name = "circuitboard (PLEXUS uplink controller)" + build_path = /obj/machinery/computer/internet_uplink + origin_tech = @'{"programming":2,"engineering":2}' + +/obj/item/stock_parts/circuitboard/internet_repeater + name = "circuitboard (PLEXUS repeater)" + build_path = /obj/machinery/internet_repeater + board_type = "machine" + origin_tech = @'{"magnets":3,"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/subspace/filter = 1, + /obj/item/stock_parts/capacitor = 2, + /obj/item/stock_parts/micro_laser = 1 + ) + additional_spawn_components = null + +/datum/fabricator_recipe/imprinter/circuit/internet_uplink + path = /obj/item/stock_parts/circuitboard/internet_uplink + +/datum/fabricator_recipe/imprinter/circuit/internet_uplink_computer + path = /obj/item/stock_parts/circuitboard/internet_uplink_computer + +/datum/fabricator_recipe/imprinter/circuit/internet_repeater + path = /obj/item/stock_parts/circuitboard/internet_repeater \ No newline at end of file diff --git a/code/modules/overmap/internet/internet_repeater.dm b/code/modules/overmap/internet/internet_repeater.dm new file mode 100644 index 000000000000..e8dde83b7da7 --- /dev/null +++ b/code/modules/overmap/internet/internet_repeater.dm @@ -0,0 +1,71 @@ +var/global/list/internet_repeaters = list() + +/obj/machinery/internet_repeater + name = "\improper PLEXUS repeater" + desc = "A signal repeater that provides access to PLEXUS for all network devices in the local area, provided a PLEXUS uplink is in range." + icon = 'icons/obj/machines/tcomms/bus.dmi' + icon_state = "bus" + density = TRUE + anchored = TRUE + use_power = POWER_USE_ACTIVE + idle_power_usage = 50 + active_power_usage = 5000 + construct_state = /decl/machine_construction/default/panel_closed + stock_part_presets = list( + /decl/stock_part_preset/terminal_setup, + ) + uncreated_component_parts = list( + /obj/item/stock_parts/power/terminal, + ) + +/obj/machinery/internet_repeater/Initialize() + . = ..() + internet_repeaters += src + +/obj/machinery/internet_repeater/Destroy() + internet_repeaters -= src + . = ..() + +/obj/machinery/internet_repeater/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + if(href_list["toggle"]) + if(use_power == POWER_USE_IDLE) + update_use_power(POWER_USE_ACTIVE) + else + update_use_power(POWER_USE_IDLE) + return TOPIC_REFRESH + +/obj/machinery/internet_repeater/on_update_icon() + icon_state = initial(icon_state) + if(panel_open) + icon_state = "[icon_state]_o" + if(use_power != POWER_USE_ACTIVE || !operable()) + icon_state = "[icon_state]_off" + +/obj/machinery/internet_repeater/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/internet_repeater/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) + . = ..() + var/data = list() + data["powered"] = (use_power == POWER_USE_ACTIVE) + + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[get_z(src)] + + if(sector) + var/list/internet_connections = sector.get_internet_connections() + var/list/connections = list() + for(var/list/pos in internet_connections) + var/list/connection_data = list() + connection_data["position"] = "([pos[1]], [pos[2]])" + connection_data["permitted"] = internet_connections[pos] + connections.Add(list(connection_data)) + + data["connections"] = connections + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "internet_repeater.tmpl", "PLEXUS Repeater", 420, 530, nref = src) + ui.set_initial_data(data) + ui.open() \ No newline at end of file diff --git a/code/modules/overmap/internet/internet_uplink.dm b/code/modules/overmap/internet/internet_uplink.dm new file mode 100644 index 000000000000..8c32bc016983 --- /dev/null +++ b/code/modules/overmap/internet/internet_uplink.dm @@ -0,0 +1,196 @@ +#define BASE_INTERNET_RANGE 5 + +var/global/list/internet_uplinks = list() +/obj/machinery/internet_uplink + name = "\improper PLEXUS uplink" + desc = "A machine designed to route massive amounts of data to and from PLEXUS receivers in a local area using a miniaturized wormhole." + icon = 'icons/obj/machines/internet_uplink.dmi' + icon_state = "unpowered" + density = TRUE + anchored = TRUE + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = list( + /obj/item/stock_parts/power/terminal, + ) + stock_part_presets = list( + /decl/stock_part_preset/terminal_setup, + ) + + var/overmap_range = BASE_INTERNET_RANGE + var/max_overmap_range = BASE_INTERNET_RANGE + + var/max_temperature = 100 CELSIUS + var/power_per_range = 20000 + + var/restrict_networks = FALSE // Whether or not a network needs to be permitted to use this uplink. + var/list/permitted_networks = list() // Network IDs which are permitted to connect through this uplink. + var/initial_id_tag = "plexus" + +/obj/machinery/internet_uplink/Initialize() + . = ..() + global.internet_uplinks += src + set_extension(src, /datum/extension/local_network_member, TRUE) + if(initial_id_tag) + var/datum/extension/local_network_member/uplink_comp = get_extension(src, /datum/extension/local_network_member) + uplink_comp.set_tag(null, initial_id_tag) + update_range(overmap_range) + +/obj/machinery/internet_uplink/Destroy() + global.internet_uplinks -= src + . = ..() + +/obj/machinery/internet_uplink/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) + var/datum/extension/local_network_member/uplink_comp = get_extension(src, /datum/extension/local_network_member) + uplink_comp.get_new_tag(user) + return TRUE + + return ..() + +/obj/machinery/internet_uplink/Process() + if(stat & (BROKEN|NOPOWER)) + return + + if(use_power != POWER_USE_ACTIVE) + return + + // Larger ranges not only require more power, but greater cooling. + var/inefficiency = clamp(0.3 + (0.1 * (overmap_range - BASE_INTERNET_RANGE)), 0.1, 0.6) + + var/datum/gas_mixture/env = return_air() + if(!istype(env) || env.return_pressure() < 10) // Vacuum cooling is insufficient for this machine. + take_damage(10, BURN) + return + env.add_thermal_energy(active_power_usage * inefficiency) + if(env.temperature > max_temperature) + take_damage(5, BURN) + +/obj/machinery/internet_uplink/set_broken(new_state, cause) + . = ..() + if(use_power == POWER_USE_ACTIVE) + visible_message(SPAN_WARNING("\The [src]'s wormhole collapses as its containment mechanisms fail!")) + update_use_power(POWER_USE_IDLE) + +/obj/machinery/internet_uplink/on_update_icon() + if((use_power == POWER_USE_ACTIVE) && !(stat & NOPOWER)) + if(icon_state == "unpowered") // Switching states, flash an animation. + flick("startup", src) + + icon_state = "powered" + else + icon_state = "unpowered" + +/obj/machinery/internet_uplink/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + if(.) + return + + if(href_list["toggle_power"]) + var/new_power = (use_power == POWER_USE_ACTIVE ? POWER_USE_IDLE : POWER_USE_ACTIVE) + update_use_power(new_power) + return TOPIC_REFRESH + + if(href_list["modify_range"]) + var/new_range = input(user,"Enter the desired range in standard sectors (1 - [max_overmap_range]). Higher ranges increase power usage and heat production.", "Enter new range") as num|null + if(!CanInteract(user, state)) + return TOPIC_HANDLED + if(!new_range) + return TOPIC_HANDLED + update_range(new_range) + return TOPIC_REFRESH + + if(href_list["restrict_networks"]) + restrict_networks = !restrict_networks + return TOPIC_REFRESH + + if(href_list["toggle_permitted_network"]) + var/network_id = sanitize(input(user,"Enter the network ID you wish to permit/unpermit for this uplink:", "Enter Network ID") as text|null) + if(!CanInteract(user, state)) + return TOPIC_HANDLED + if(network_id) + if(network_id in permitted_networks) + permitted_networks -= network_id + return TOPIC_REFRESH + else if(network_id in SSnetworking.networks) + permitted_networks += network_id + return TOPIC_REFRESH + else + to_chat(user, SPAN_WARNING("The network '[network_id]' could not be found!")) + return TOPIC_HANDLED + +/obj/machinery/internet_uplink/proc/update_range(new_range) + overmap_range = clamp(1, new_range, max_overmap_range) + change_power_consumption(power_per_range * overmap_range, POWER_USE_ACTIVE) + +/obj/machinery/internet_uplink/power_change() + . = ..() + if(.) + if(use_power == POWER_USE_ACTIVE) + playsound(src, 'sound/mecha/powerup.ogg', 50) + else + playsound(src, 'sound/machines/apc_nopower.ogg', 50) + +/obj/machinery/internet_uplink/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, datum/topic_state/state = global.default_topic_state) + var/list/data = list() + data["active"] = (use_power == POWER_USE_ACTIVE) + data["power_draw"] = "[active_power_usage/1000] kW" + var/datum/gas_mixture/env = return_air() + data["temperature"] = (env?.get_total_moles() > 10) ? env.temperature : "NO HEATSINK FOUND" + data["max_temperature"] = max_temperature + data["overmap_range"] = overmap_range + data["restrict_networks"] = restrict_networks + if(restrict_networks) + data["permitted"] = permitted_networks + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + ui = new(user, src, ui_key, "internet_uplink.tmpl", "PLEXUS Uplink Settings", 540, 400, state = state) + ui.set_initial_data(data) + ui.set_auto_update(TRUE) + ui.open() + +/obj/machinery/internet_uplink/RefreshParts() + max_overmap_range = BASE_INTERNET_RANGE + clamp(total_component_rating_of_type(/obj/item/stock_parts/smes_coil), 0, 10) + update_range(overmap_range) // Check to ensure the set overmap range is still below the new maximum. + . = ..() + +#undef BASE_INTERNET_RANGE + +/obj/machinery/computer/internet_uplink + name = "PLEXUS uplink control computer" + icon_keyboard = "power_key" + icon_screen = "comm_logs" + light_color = COLOR_GREEN + idle_power_usage = 250 + active_power_usage = 500 + var/initial_id_tag = "plexus" + +/obj/machinery/computer/internet_uplink/Initialize() + . = ..() + set_extension(src, /datum/extension/local_network_member, TRUE) + if(initial_id_tag) + var/datum/extension/local_network_member/uplink_comp = get_extension(src, /datum/extension/local_network_member) + uplink_comp.set_tag(null, initial_id_tag) + +/obj/machinery/computer/internet_uplink/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) + var/datum/extension/local_network_member/uplink_comp = get_extension(src, /datum/extension/local_network_member) + uplink_comp.get_new_tag(user) + return TRUE + + return ..() + +/obj/machinery/computer/internet_uplink/interface_interact(mob/user) + var/datum/extension/local_network_member/uplink_comp = get_extension(src, /datum/extension/local_network_member) + var/datum/local_network/lan = uplink_comp.get_local_network() + + // Internet uplinks are restricted to one per network, so this should return the only uplink linked. + var/obj/machinery/internet_uplink/linked = lan.get_devices(/obj/machinery/internet_uplink)?[1] + + if(!istype(linked)) + to_chat(user, SPAN_WARNING("\The [src] flashes an error: No PLEXUS uplink connected!")) + return FALSE + + var/datum/topic_state/remote/R = new(src, linked) + linked.ui_interact(user, state = R) + return TRUE \ No newline at end of file diff --git a/code/modules/overmap/internet/sector_internet.dm b/code/modules/overmap/internet/sector_internet.dm new file mode 100644 index 000000000000..62472321dfe4 --- /dev/null +++ b/code/modules/overmap/internet/sector_internet.dm @@ -0,0 +1,40 @@ +/obj/effect/overmap/visitable/proc/has_internet_connection(connecting_network) + . = FALSE + // Must have an active and operable PLEXUS repeater in the sector. + var/found_repeater = FALSE + for(var/obj/machinery/internet_repeater/repeater in global.internet_repeaters) + if(!(get_z(repeater) in map_z)) + continue + if(repeater.use_power == POWER_USE_ACTIVE && repeater.operable()) + found_repeater = TRUE + break + if(!found_repeater) + return + + // Must have an operable internet uplink in range on the overmap. + for(var/obj/machinery/internet_uplink/inet_uplink in global.internet_uplinks) + if(inet_uplink.use_power != POWER_USE_ACTIVE || !inet_uplink.operable()) + continue + if(inet_uplink.restrict_networks && !(connecting_network in inet_uplink.permitted_networks)) + continue + + // Ensure the sectors are within range. + var/obj/effect/overmap/sector = inet_uplink.get_owning_overmap_object() + if(sector == src || (get_dist(get_turf(sector), get_turf(src)) <= inet_uplink.overmap_range)) + return TRUE + +// Helper to get nearby connections. Returns list(list(x, y) = allowed networks). +/obj/effect/overmap/visitable/proc/get_internet_connections() + var/found = list() + for(var/obj/machinery/internet_uplink/inet_uplink in global.internet_uplinks) + if(inet_uplink.use_power != POWER_USE_ACTIVE || !inet_uplink.operable()) + continue + + // Range check. + var/obj/effect/overmap/sector = inet_uplink.get_owning_overmap_object() + if(sector == src || (get_dist(get_turf(sector), get_turf(src)) <= inet_uplink.overmap_range)) + var/list/location = list(sector.x, sector.y) + var/allowed = inet_uplink.restrict_networks ? english_list(inet_uplink.permitted_networks, nothing_text = "NO NETWORKS") : "ALL NETWORKS" + found[location] = allowed + + return found \ No newline at end of file diff --git a/code/modules/overmap/overmap_object.dm b/code/modules/overmap/overmap_object.dm index 673045a409ba..e2344487a1e1 100644 --- a/code/modules/overmap/overmap_object.dm +++ b/code/modules/overmap/overmap_object.dm @@ -3,15 +3,16 @@ icon = 'icons/obj/overmap.dmi' icon_state = "object" color = "#c0c0c0" + animate_movement = NO_STEPS + is_spawnable_type = FALSE - var/known = 1 //shows up on nav computers automatically - var/scannable //if set to TRUE will show up on ship sensors for detailed scans, and will ping when detected by scanners. - - var/requires_contact = FALSE //whether or not the effect must be identified by ship sensors before being seen. - var/instant_contact = FALSE //do we instantly identify ourselves to any ship in sensors range? + var/scannable // if set to TRUE will show up on ship sensors for detailed scans, and will ping when detected by scanners. + var/unknown_id // A unique identifier used when this entity is scanned. Assigned in Initialize(). + var/requires_contact = FALSE // whether or not the effect must be identified by ship sensors before being seen. + var/instant_contact = FALSE // do we instantly identify ourselves to any ship in sensors range? var/halted = FALSE var/can_move = FALSE - var/sensor_visibility = 10 //how likely it is to increase identification process each scan. + var/sensor_visibility = 10 // how likely it is to increase identification process each scan. var/vessel_mass = 10000 // metric tonnes, very rough number, affects acceleration provided by engines @@ -23,6 +24,21 @@ var/last_burn = 0 // worldtime when ship last acceleated var/burn_delay = 1 SECOND // how often ship can do burns + var/list/comms_masers + var/list/comms_antennae + var/can_switch_ident = TRUE + var/ident_transmitter = TRUE + var/overmap_id = OVERMAP_ID_SPACE // Which overmap datum this object expects to be dealing with + var/adjacency_radius = 0 // draws a circle under the effect scaled to this size, 1 = 1 turf + +/obj/effect/overmap/proc/get_heading_angle() + . = round(Atan2(speed[2], speed[1])) + if(. < 0) // Speeds can be negative so invert the degree value. + . += 360 + +/obj/effect/overmap/touch_map_edge(var/overmap_id) + return + //Overlay of how this object should look on other skyboxes /obj/effect/overmap/proc/get_skybox_representation() return @@ -32,52 +48,74 @@ /obj/effect/overmap/Initialize() . = ..() - glide_size = world.icon_size - if(!GLOB.using_map.use_overmap) - return INITIALIZE_HINT_QDEL - if(known) - layer = ABOVE_LIGHTING_LAYER - plane = EFFECTS_ABOVE_LIGHTING_PLANE - for(var/obj/machinery/computer/ship/helm/H in SSmachines.machinery) - H.get_known_sectors() + if(!length(global.using_map.overmap_ids)) + return INITIALIZE_HINT_QDEL if(requires_contact) - invisibility = INVISIBILITY_OVERMAP // Effects that require identification have their images cast to the client via sensors. - update_icon() + set_invisibility(INVISIBILITY_OVERMAP) // Effects that require identification have their images cast to the client via sensors. + + if(scannable) + unknown_id = "[pick(global.phonetic_alphabet)]-[random_id(/obj/effect/overmap, 100, 999)]" -/obj/effect/overmap/Crossed(var/obj/effect/overmap/visitable/other) - if(istype(other)) - for(var/obj/effect/overmap/visitable/O in loc) - SSskybox.rebuild_skyboxes(O.map_z) + update_moving() + + add_filter("glow", 1, list(type = "drop_shadow", color = color + "F0", size = 2, offset = 1,x = 0, y = 0)) + update_icon() -/obj/effect/overmap/Uncrossed(var/obj/effect/overmap/visitable/other) - if(istype(other)) - SSskybox.rebuild_skyboxes(other.map_z) - for(var/obj/effect/overmap/visitable/O in loc) - SSskybox.rebuild_skyboxes(O.map_z) +/obj/effect/overmap/Crossed(atom/movable/AM) + var/obj/effect/overmap/visitable/other = AM + if(!istype(other)) + return + for(var/obj/effect/overmap/visitable/O in loc) + SSskybox.rebuild_skyboxes(O.map_z) + +/obj/effect/overmap/Uncrossed(atom/movable/AM) + var/obj/effect/overmap/visitable/other = AM + if(!istype(other)) + return + SSskybox.rebuild_skyboxes(other.map_z) + for(var/obj/effect/overmap/visitable/O in loc) + SSskybox.rebuild_skyboxes(O.map_z) /obj/effect/overmap/on_update_icon() - filters = filter(type="drop_shadow", color = color + "F0", size = 2, offset = 1,x = 0, y = 0) + . = ..() + underlays.Cut() + if(adjacency_radius) + var/image/radius = image(icon = 'icons/obj/overmap.dmi', icon_state = "radius") + if(adjacency_radius != 1) + var/matrix/M = matrix() + M.Scale(adjacency_radius) + radius.transform = M + radius.appearance_flags = (RESET_ALPHA | KEEP_APART) + radius.alpha = 50 + radius.filters = filter(type="blur", size = 1) + underlays += radius /obj/effect/overmap/proc/handle_wraparound() + + var/turf/T = get_turf(src) + if(!istype(T) || !global.overmaps_by_z["[T.z]"]) + PRINT_STACK_TRACE("Overmap effect handling wraparound on a non-overmap z-level.") + + var/datum/overmap/overmap = global.overmaps_by_z["[T.z]"] var/nx = x var/ny = y - var/low_edge = 1 - var/high_edge = GLOB.using_map.overmap_size - 1 - - if((dir & WEST) && x == low_edge) - nx = high_edge - else if((dir & EAST) && x == high_edge) - nx = low_edge - if((dir & SOUTH) && y == low_edge) - ny = high_edge - else if((dir & NORTH) && y == high_edge) - ny = low_edge + + var/heading_dir = get_heading_dir() + + if((heading_dir & WEST) && x == 1) + nx = overmap.map_size_y - 1 + else if((heading_dir & EAST) && x == overmap.map_size_y) + nx = 2 + if((heading_dir & SOUTH) && y == 1) + ny = overmap.map_size_y - 1 + else if((heading_dir & NORTH) && y == overmap.map_size_y) + ny = 2 if((x == nx) && (y == ny)) return //we're not flying off anywhere - var/turf/T = locate(nx,ny,z) + T = locate(nx,ny,z) if(T) forceMove(T) @@ -87,7 +125,7 @@ /obj/effect/overmap/proc/get_speed() return round(sqrt(speed[1] ** 2 + speed[2] ** 2), SHIP_MOVE_RESOLUTION) -/obj/effect/overmap/proc/get_heading() +/obj/effect/overmap/proc/get_heading_dir() var/res = 0 if(MOVING(speed[1], min_speed)) if(speed[1] > 0) @@ -104,8 +142,22 @@ /obj/effect/overmap/proc/adjust_speed(n_x, n_y) CHANGE_SPEED_BY(speed[1], n_x, min_speed) CHANGE_SPEED_BY(speed[2], n_y, min_speed) + update_moving() + +/obj/effect/overmap/proc/update_moving() + if(is_still()) + SSovermap.moving_entities -= src + else + SSovermap.moving_entities[src] = TRUE update_icon() +/obj/effect/overmap/Destroy() + STOP_PROCESSING(SSobj, src) + SSovermap.moving_entities -= src + speed = list(0, 0) + position = list(0, 0) + . = ..() + /obj/effect/overmap/proc/can_burn() if(halted) return FALSE @@ -114,33 +166,48 @@ else return TRUE -/obj/effect/overmap/Process() - if(!halted && !is_still() && can_move) - var/list/deltas = list(0,0) - for(var/i = 1 to 2) - if(MOVING(speed[i], min_speed)) - position[i] += speed[i] * OVERMAP_SPEED_CONSTANT - if(position[i] < 0) - deltas[i] = ceil(position[i]) - else if(position[i] > 0) - deltas[i] = Floor(position[i]) - if(deltas[i] != 0) - position[i] -= deltas[i] - position[i] += (deltas[i] > 0) ? -1 : 1 - - update_icon() +/obj/effect/overmap/proc/ProcessOvermap(wait, tick) + + if(halted || is_still()) + return PROCESS_KILL + + if(!can_move) + return + + var/moved = FALSE + var/list/deltas = list(0,0) + for(var/i = 1 to 2) + if(!MOVING(speed[i], min_speed)) + continue + // Add speed to this dimension of our position. + position[i] += clamp((speed[i] * OVERMAP_SPEED_CONSTANT) * (wait / (1 SECOND)), -1, 1) + if(position[i] < 0) + deltas[i] = ceil(position[i]) + else if(position[i] > 0) + deltas[i] = floor(position[i]) + moved = TRUE + // Delta over 0 means we've moved a turf, so we adjust our position accordingly. + if(deltas[i] != 0) + position[i] -= deltas[i] + // Note for future self when confused: this line offsets the effect within the new turf. + // Can probably be tidied up at some point but math is spooky. + position[i] += (deltas[i] > 0) ? -1 : 1 + + if(moved) var/turf/newloc = locate(x + deltas[1], y + deltas[2], z) if(newloc && loc != newloc) Move(newloc) handle_wraparound() - handle_overmap_pixel_movement() + handle_overmap_pixel_movement() /obj/effect/overmap/proc/accelerate(var/direction, var/accel_limit) var/actual_accel_limit = accel_limit / KM_OVERMAP_RATE if(can_burn()) last_burn = world.time var/delta_v = get_delta_v() / KM_OVERMAP_RATE - var/partial_power = Clamp(actual_accel_limit / delta_v, 0, 1) + if(delta_v == 0) + return + var/partial_power = clamp(actual_accel_limit / delta_v, 0, 1) var/acceleration = min(get_delta_v(TRUE, partial_power) / KM_OVERMAP_RATE, actual_accel_limit) if(direction & EAST) adjust_speed(acceleration, 0) @@ -153,20 +220,32 @@ /obj/effect/overmap/proc/decelerate() - if(((speed[1]) || (speed[2])) && can_burn()) - if (speed[1]) - var/partial_power = Clamp(speed[1] / (get_delta_v() / KM_OVERMAP_RATE), 0, 1) - var/delta_v = get_delta_v(TRUE, partial_power) / KM_OVERMAP_RATE - adjust_speed(-SIGN(speed[1]) * min(delta_v, abs(speed[1])), 0) - if (speed[2]) - var/partial_power = Clamp(speed[2] / (get_delta_v() / KM_OVERMAP_RATE), 0, 1) - var/delta_v = get_delta_v(TRUE, partial_power) / KM_OVERMAP_RATE - adjust_speed(0, -SIGN(speed[2]) * min(delta_v, abs(speed[2]))) + if(!can_burn()) + return + + var/burn = FALSE + . = list(0, 0) + for(var/i = 1 to 2) + var/spd = speed[i] + var/abs_spd = abs(spd) + if(abs_spd) + var/base_delta_v = get_delta_v() + if(base_delta_v > 0) + var/partial_power = clamp(abs_spd / (base_delta_v / KM_OVERMAP_RATE), 0, 1) + var/delta_v = min(get_delta_v(TRUE, partial_power) / KM_OVERMAP_RATE, abs_spd) + .[i] = -SIGN(spd) * delta_v + burn = TRUE + + if(burn) last_burn = world.time + adjust_speed(.[1], .[2]) /obj/effect/overmap/proc/handle_overmap_pixel_movement() pixel_x = position[1] * (world.icon_size/2) pixel_y = position[2] * (world.icon_size/2) /obj/effect/overmap/proc/get_delta_v() - return + return 0 + +/obj/effect/overmap/proc/get_vessel_mass() //Same as above. + return vessel_mass diff --git a/code/modules/overmap/overmap_shuttle.dm b/code/modules/overmap/overmap_shuttle.dm index eaf30100eb5f..9d7b32efcc81 100644 --- a/code/modules/overmap/overmap_shuttle.dm +++ b/code/modules/overmap/overmap_shuttle.dm @@ -1,4 +1,4 @@ -#define waypoint_sector(waypoint) map_sectors["[waypoint.z]"] +#define waypoint_sector(waypoint) global.overmap_sectors[waypoint.z] /datum/shuttle/autodock/overmap warmup_time = 10 @@ -7,12 +7,13 @@ var/fuel_consumption = 0 //Amount of moles of gas consumed per trip; If zero, then shuttle is magic and does not need fuel var/list/obj/structure/fuel_port/fuel_ports //the fuel ports of the shuttle (but usually just one) - category = /datum/shuttle/autodock/overmap + abstract_type = /datum/shuttle/autodock/overmap var/skill_needed = SKILL_BASIC + var/landing_skill_needed = SKILL_EXPERT var/operator_skill = SKILL_MIN -/datum/shuttle/autodock/overmap/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint) - ..(_name, start_waypoint) +/datum/shuttle/autodock/overmap/New(var/map_hash, var/obj/effect/shuttle_landmark/start_waypoint) + ..() refresh_fuel_ports_list() /datum/shuttle/autodock/overmap/proc/refresh_fuel_ports_list() //loop through all @@ -23,13 +24,13 @@ fuel_ports += fuel_port_in_area /datum/shuttle/autodock/overmap/fuel_check() - if(!src.try_consume_fuel()) //insufficient fuel - for(var/area/A in shuttle_area) - for(var/mob/living/M in A) - M.show_message(SPAN_WARNING("You hear the shuttle engines sputter... perhaps it doesn't have enough fuel?"), AUDIBLE_MESSAGE, - SPAN_WARNING("The shuttle shakes but fails to take off."), VISIBLE_MESSAGE) - return 0 //failure! - return 1 //sucess, continue with launch + if(!try_consume_fuel()) //insufficient fuel + message_passengers( + SPAN_WARNING("You hear the shuttle engines sputter... perhaps it doesn't have enough fuel?"), + SPAN_WARNING("The shuttle shakes but fails to take off.") + ) + return FALSE //failure + return TRUE //sucess, continue with launch /datum/shuttle/autodock/overmap/proc/can_go() if(!next_location) @@ -67,7 +68,7 @@ /datum/shuttle/autodock/overmap/proc/get_possible_destinations() var/list/res = list() for (var/obj/effect/overmap/visitable/S in range(get_turf(waypoint_sector(current_location)), range)) - var/list/waypoints = S.get_waypoints(name) + var/list/waypoints = S.get_waypoints(type) for(var/obj/effect/shuttle_landmark/LZ in waypoints) if(LZ.is_valid(src)) res["[waypoints[LZ]] - [LZ.name]"] = LZ @@ -76,7 +77,7 @@ /datum/shuttle/autodock/overmap/get_location_name() if(moving_status == SHUTTLE_INTRANSIT) return "In transit" - return "[waypoint_sector(current_location)] - [current_location]" + return "\the [waypoint_sector(current_location)] - [current_location]" /datum/shuttle/autodock/overmap/get_destination_name() if(!next_location) @@ -113,58 +114,9 @@ fuel_to_consume -= fuel_available FT.remove_air_by_flag(XGM_GAS_FUEL, fuel_available) -/obj/structure/fuel_port - name = "fuel port" - desc = "The fuel input port of the shuttle. Holds one fuel tank. Use a crowbar to open and close it." - icon = 'icons/turf/shuttle.dmi' - icon_state = "fuel_port" - density = 0 - anchored = 1 - var/icon_closed = "fuel_port" - var/icon_empty = "fuel_port_empty" - var/icon_full = "fuel_port_full" - var/opened = 0 - var/parent_shuttle - -/obj/structure/fuel_port/Initialize() - . = ..() - new /obj/item/tank/hydrogen(src) - -/obj/structure/fuel_port/attack_hand(mob/user) - if(!opened) - to_chat(user, SPAN_WARNING("The door is secured tightly. You'll need a crowbar to open it.")) - return - else if(contents.len > 0) - user.put_in_hands(contents[1]) - update_icon() - -/obj/structure/fuel_port/on_update_icon() - if(opened) - if(contents.len > 0) - icon_state = icon_full - else - icon_state = icon_empty - else - icon_state = icon_closed - -/obj/structure/fuel_port/attackby(obj/item/W, mob/user) - if(isCrowbar(W)) - if(opened) - to_chat(user, SPAN_NOTICE("You tightly shut \the [src] door.")) - playsound(src.loc, 'sound/effects/locker_close.ogg', 25, 0, -3) - opened = 0 - else - to_chat(user, SPAN_NOTICE("You open up \the [src] door.")) - playsound(src.loc, 'sound/effects/locker_open.ogg', 15, 1, -3) - opened = 1 - else if(istype(W,/obj/item/tank)) - if(!opened) - to_chat(user, SPAN_WARNING("\The [src] door is still closed!")) - return - if(contents.len == 0) - user.unEquip(W, src) - update_icon() - -// Walls hide stuff inside them, but we want to be visible. -/obj/structure/fuel_port/hide() - return \ No newline at end of file +// When we rotate, rotate our overmap landmark's fore_dir too, so meteors come from the right direction. +/datum/shuttle/autodock/overmap/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) + ..() + var/obj/effect/overmap/visitable/ship/landable/our_ship = SSshuttle.ship_by_shuttle(name) + if(our_ship && angle != 0) + our_ship.fore_dir = turn(our_ship.fore_dir, angle) \ No newline at end of file diff --git a/code/modules/overmap/planetoids/_planetoids.dm b/code/modules/overmap/planetoids/_planetoids.dm new file mode 100644 index 000000000000..16ea48dfe92b --- /dev/null +++ b/code/modules/overmap/planetoids/_planetoids.dm @@ -0,0 +1,74 @@ +///////////////////////////////////////////////////////////////////////// +// Planetoid +///////////////////////////////////////////////////////////////////////// + +///Overmap marker for a planet-like entity. +/obj/effect/overmap/visitable/sector/planetoid + name = "planetoid" + icon = 'icons/obj/overmap.dmi' + icon_state = "globe" + free_landing = TRUE + sector_flags = 0 //By default, can't space walk over there + color = "#4e3570" + + ///ID of the associated planetoid data id for lookup. + var/planetoid_id + ///The icon file to use for this planetoid's skybox image + var/icon/skybox_icon = 'icons/skybox/planet.dmi' + ///Skybox background image when floating in space above this sector. Generated at runtime + var/tmp/image/skybox_image + ///Color of the primary layer of the skybox image + var/surface_color = COLOR_ASTEROID_ROCK + ///Color of the secondary layer of the skybox image. Is usually water-like features. + var/water_color = "#436499" + +/obj/effect/overmap/visitable/sector/planetoid/Initialize(mapload) + . = ..() + if(length(planetoid_id)) + var/datum/planetoid_data/P = get_planetoid_data() + P.set_overmap_marker(src) + +///Returns the /datum/planetoid_data associated with planet this overmap marker represents. +/obj/effect/overmap/visitable/sector/planetoid/proc/get_planetoid_data() + return LAZYACCESS(SSmapping.planetoid_data_by_id, planetoid_id) + +///Returns the planetoid's atmosphere if there's any +/obj/effect/overmap/visitable/sector/planetoid/proc/get_atmosphere() + var/datum/planetoid_data/P = get_planetoid_data() + return P.atmosphere + +///Returns the strata associated to the planetoid we represent +/obj/effect/overmap/visitable/sector/planetoid/proc/get_strata() + var/datum/planetoid_data/P = get_planetoid_data() + return P.strata + +///Update our name, and refs to match the planetoid we're representing +/obj/effect/overmap/visitable/sector/planetoid/proc/update_from_data(var/datum/planetoid_data/P) + SetName("[P.name], \a [initial(name)]") + planetoid_id = P.id + surface_color = P.surface_color + water_color = P.water_color + +/obj/effect/overmap/visitable/sector/planetoid/get_scan_data(mob/user) + . = ..() + . += "
    " + var/datum/gas_mixture/atmosphere = get_atmosphere() + if(atmosphere) + if(user.skill_check(SKILL_SCIENCE, SKILL_EXPERT) || user.skill_check(SKILL_ATMOS, SKILL_EXPERT)) + var/list/gases = list() + for(var/g in atmosphere.gas) + if(atmosphere.gas[g] > atmosphere.total_moles * 0.05) + var/decl/material/mat = GET_DECL(g) + gases += mat.gas_name + . += "Atmosphere composition: [english_list(gases)]
    " + var/inaccuracy = rand(8,12)/10 + . += "Atmosphere pressure [atmosphere.return_pressure()*inaccuracy] kPa, temperature [atmosphere.temperature*inaccuracy] K
    " + else if(user.skill_check(SKILL_SCIENCE, SKILL_BASIC) || user.skill_check(SKILL_ATMOS, SKILL_BASIC)) + . += "Atmosphere present. Sensor suite calibration required for detailed scan. Contact a qualified technician for calibration assistance.
    " + . += "
    " + + var/datum/planetoid_data/E = get_planetoid_data() + for(var/datum/exoplanet_theme/T in E.themes) + if(T.get_sensor_data()) + . += jointext(T.get_sensor_data(), "
    ") + . += "
    " diff --git a/code/modules/overmap/planetoids/planetoid_skybox.dm b/code/modules/overmap/planetoids/planetoid_skybox.dm new file mode 100644 index 000000000000..d9528a9bfc38 --- /dev/null +++ b/code/modules/overmap/planetoids/planetoid_skybox.dm @@ -0,0 +1,121 @@ +/// Whether to draw rings on the planet's skybox image, and aknowledge anywhere else that it has rings. +/obj/effect/overmap/visitable/sector/planetoid/proc/has_rings() + var/datum/planetoid_data/PD = SSmapping.planetoid_data_by_id[planetoid_id] + return PD.has_rings + +/// Returns the name of the type of ring overlay to use for the planetary rings. +/// Basically, the icon_state for the planetoid's rings +/obj/effect/overmap/visitable/sector/planetoid/proc/get_ring_type_name() + var/datum/planetoid_data/PD = SSmapping.planetoid_data_by_id[planetoid_id] + return PD.ring_type_name + +/// Returns the color for the ring overlay +/obj/effect/overmap/visitable/sector/planetoid/proc/get_ring_color() + var/datum/planetoid_data/PD = SSmapping.planetoid_data_by_id[planetoid_id] + return PD.ring_color + +/// Get the primary surface color used for the skybox image +/obj/effect/overmap/visitable/sector/planetoid/proc/get_surface_color() + return surface_color + +/obj/effect/overmap/visitable/sector/planetoid/proc/has_atmosphere() + var/datum/planetoid_data/PD = SSmapping.planetoid_data_by_id[planetoid_id] + var/datum/level_data/LD = SSmapping.levels_by_id[PD.surface_level_id] + return !isnull(LD.exterior_atmosphere) + +/obj/effect/overmap/visitable/sector/planetoid/proc/get_atmosphere_color() + var/list/colors = list() + for(var/lvl in map_z) + var/datum/level_data/level_data = SSmapping.levels_by_z[lvl] + ///#TODO: Check if the z-level is visible from space + for(var/g in level_data.exterior_atmosphere?.gas) + var/decl/material/mat = GET_DECL(g) + colors += mat.color + if(length(colors)) + return MixColors(colors) + +/// Get cached skybox background image. +/obj/effect/overmap/visitable/sector/planetoid/get_skybox_representation() + if(!skybox_image) + generate_skybox_image() + return skybox_image + +/// Returns the image for the planetary surface of the skybox background image. +/obj/effect/overmap/visitable/sector/planetoid/proc/get_skybox_primary_surface() + return overlay_image(skybox_icon, "base", get_surface_color()) + +/// Returns the image for the secondary planetary feature of the surface of the +/// skybox background image. Usually is the color of the oceans on the surface. +/obj/effect/overmap/visitable/sector/planetoid/proc/get_skybox_secondary_surface() + if(!water_color) + return + var/image/secondary = image(skybox_icon, "water") + secondary.color = water_color + secondary.transform = secondary.transform.Turn(rand(0,360)) + return secondary + +/// Generates the raw base/surface of the planetoid skybox image. +/obj/effect/overmap/visitable/sector/planetoid/proc/generate_skybox_planetoid_surface() + var/image/surface = image(skybox_icon, "") + var/image/primary = get_skybox_primary_surface() + var/image/secondary = get_skybox_secondary_surface() + surface.add_overlay(primary) + if(secondary) + surface.add_overlay(secondary) + + //Slap on anything added by themes to the surface + var/datum/planetoid_data/PD = SSmapping.planetoid_data_by_id[planetoid_id] + for(var/datum/exoplanet_theme/TH in PD.themes) + var/img = TH.get_planet_image_extra(PD) + if(img) + surface.add_overlay(img) + return surface + +/// Generates the cloud cover over the planetoid. +/obj/effect/overmap/visitable/sector/planetoid/proc/generate_skybox_planetoid_clouds() + if(!has_atmosphere()) + return + var/image/clouds = overlay_image(skybox_icon, "weak_clouds", get_atmosphere_color() || COLOR_WHITE) + if(water_color) //#FIXME: This really should check if there's actually some liquid to make clouds from or something, instead of checking if there's a water overlay + clouds.overlays += image(skybox_icon, "clouds") + return clouds + +/// Generates the halo underlay around the planetoid if there's any. +/obj/effect/overmap/visitable/sector/planetoid/proc/generate_skybox_planetoid_halo() + if(!has_atmosphere()) + return + return image(skybox_icon, "atmoring") + +/// Generates the planetoid's shadow and rimlight overlays +/obj/effect/overmap/visitable/sector/planetoid/proc/generate_skybox_planetoid_shading() + var/list/shading_overlays = list() + var/image/shadow = image(skybox_icon, "shadow") + shadow.blend_mode = BLEND_MULTIPLY + shading_overlays += shadow + shading_overlays += image(skybox_icon, "lightrim") + return shading_overlays + +/// Generate the planetoid's rings overlay if it has rings +/obj/effect/overmap/visitable/sector/planetoid/proc/generate_skybox_planetoid_rings() + if(!has_rings()) + return + var/image/rings = overlay_image('icons/skybox/planet_rings.dmi', get_ring_type_name(), get_ring_color()) + //Need to offset the ring overlay because it's 512x512px, and the planet images are 256x256px + rings.pixel_x = -128 + rings.pixel_y = -128 + return rings + +/// Generates the skybox background displayed when a ship or viewer is in a sector above the planetoid +/obj/effect/overmap/visitable/sector/planetoid/proc/generate_skybox_image() + //Everything is done in a separate proc for each layers, to allow for overriding + // for a variety of planetoids + skybox_image = generate_skybox_planetoid_surface() + ASSERT(skybox_image) + skybox_image.pixel_x = rand(0,64) + skybox_image.pixel_y = rand(128,256) + skybox_image.appearance_flags = RESET_COLOR + + skybox_image.underlays += generate_skybox_planetoid_halo() + skybox_image.add_overlay(generate_skybox_planetoid_clouds()) + skybox_image.add_overlay(generate_skybox_planetoid_shading()) + skybox_image.add_overlay(generate_skybox_planetoid_rings()) diff --git a/code/modules/overmap/radio_beacon.dm b/code/modules/overmap/radio_beacon.dm index f8f5525f0210..7ccc75501352 100644 --- a/code/modules/overmap/radio_beacon.dm +++ b/code/modules/overmap/radio_beacon.dm @@ -13,8 +13,8 @@

    ---END OF TRANSMISSION---" /obj/effect/overmap/radio/proc/set_origin(obj/effect/overmap/origin) - GLOB.moved_event.register(origin, src, /obj/effect/overmap/radio/proc/follow) - GLOB.destroyed_event.register(origin, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/moved, origin, src, TYPE_PROC_REF(/obj/effect/overmap/radio, follow)) + events_repository.register(/decl/observ/destroyed, origin, src, TYPE_PROC_REF(/datum, qdel_self)) forceMove(origin.loc) source = origin pixel_x = -(origin.bound_width - 6) @@ -24,8 +24,8 @@ if(!QDELETED(src)) forceMove(new_loc) /obj/effect/overmap/radio/Destroy() - GLOB.destroyed_event.unregister(source, src) - GLOB.moved_event.unregister(source, src) + events_repository.unregister(/decl/observ/destroyed, source, src) + events_repository.unregister(/decl/observ/moved, source, src) source = null . = ..() @@ -35,18 +35,18 @@ icon = 'icons/obj/items/device/radio/beacon.dmi' icon_state = "beacon" - origin_tech = "{'magnets':2, 'programming':2}" + origin_tech = @'{"magnets":2, "programming":2}' material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT) - var/obj/effect/overmap/radio/signal + var/obj/effect/overmap/radio/signal /obj/item/radio_beacon/attack_self(mob/user) if(signal) to_chat(user, SPAN_NOTICE("You deactivate \the [src], cutting short it's radio broadcast.")) QDEL_NULL(signal) return - var/obj/effect/overmap/visitable/O = map_sectors["[get_z(src)]"] + var/obj/effect/overmap/visitable/O = global.overmap_sectors[get_z(src)] if(!O) to_chat(user, SPAN_WARNING("You cannot deploy \the [src] here.")) return @@ -55,11 +55,10 @@ return signal = new() - + signal.message = message signal.set_origin(O) /obj/item/radio_beacon/Destroy() QDEL_NULL(signal) . = ..() - \ No newline at end of file diff --git a/code/modules/overmap/sectors.dm b/code/modules/overmap/sectors.dm index 0722de6823f4..f6988ec8a794 100644 --- a/code/modules/overmap/sectors.dm +++ b/code/modules/overmap/sectors.dm @@ -1,3 +1,5 @@ +var/global/list/known_overmap_sectors + //=================================================================================== //Overmap object representing zlevel(s) //=================================================================================== @@ -9,44 +11,113 @@ var/list/initial_restricted_waypoints //For use with non-automatic landmarks (automatic ones add themselves). var/list/generic_waypoints = list() //waypoints that any shuttle can use - var/list/restricted_waypoints = list() //waypoints for specific shuttles + var/list/restricted_waypoints = list() //waypoints for specific shuttle types var/docking_codes - var/start_x //Coordinates for self placing - var/start_y //will use random values if unset + // Custom spawn coordinates. Will pick random place if one of them or both not set. + /// Custom X coordinate to spawn. Require `start_y` set to work. + var/start_x + /// Custom Y coordinate to spawn. Require `start_x` set to work. + var/start_y var/sector_flags = OVERMAP_SECTOR_IN_SPACE var/hide_from_reports = FALSE var/has_distress_beacon - var/free_landing = FALSE //whether or not shuttles can land in arbitrary places within the sector's z-levels. + var/free_landing = TRUE // Whether or not shuttles can land in arbitrary places within the sector's z-levels. + var/restricted_area = 0 // Regardless of if free_landing is set to TRUE, this square area (centered on the z level) will be restricted from free shuttle landing unless permitted by a docking becaon. + var/list/map_z = list() - var/list/consoles + var/list/associated_machinery + +/obj/effect/overmap/visitable/proc/get_linked_machines_of_type(var/base_type) + ASSERT(ispath(base_type, /obj/machinery)) + for(var/thing in LAZYACCESS(associated_machinery, base_type)) + var/weakref/machine_ref = thing + var/obj/machinery/machine = machine_ref.resolve() + if(istype(machine, base_type) && !QDELETED(machine)) + LAZYDISTINCTADD(., machine) + else + LAZYREMOVE(associated_machinery[base_type], thing) + +/obj/effect/overmap/visitable/proc/unregister_machine(var/obj/machinery/machine, var/base_type) + ASSERT(istype(machine)) + base_type = base_type || machine.base_type || machine.type + if(islist(associated_machinery) && associated_machinery[base_type]) + LAZYREMOVE(associated_machinery[base_type], weakref(machine)) + +/obj/effect/overmap/visitable/proc/register_machine(var/obj/machinery/machine, var/base_type) + ASSERT(istype(machine)) + if(!QDELETED(machine)) + base_type = base_type || machine.base_type || machine.type + LAZYINITLIST(associated_machinery) + LAZYDISTINCTADD(associated_machinery[base_type], weakref(machine)) + +/obj/effect/overmap/visitable/Destroy() + LAZYREMOVE(global.known_overmap_sectors, src) + associated_machinery = null + . = ..() /obj/effect/overmap/visitable/Initialize() . = ..() if(. == INITIALIZE_HINT_QDEL) return - find_z_levels() // This populates map_z and assigns z levels to the ship. - register_z_levels() // This makes external calls to update global z level information. - - if(!GLOB.using_map.overmap_z) - build_overmap() - - start_x = start_x || rand(OVERMAP_EDGE, GLOB.using_map.overmap_size - OVERMAP_EDGE) - start_y = start_y || rand(OVERMAP_EDGE, GLOB.using_map.overmap_size - OVERMAP_EDGE) - - forceMove(locate(start_x, start_y, GLOB.using_map.overmap_z)) + find_z_levels() // This populates map_z and assigns z levels to the ship. + move_to_starting_location() // Moves us to the appropriate spot on the overmap level. + register_z_levels() // This makes external calls to update global z level information. docking_codes = "[ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))]" - testing("Located sector \"[name]\" at [start_x],[start_y], containing Z [english_list(map_z)]") + if(sector_flags & OVERMAP_SECTOR_KNOWN) + LAZYADD(global.known_overmap_sectors, src) + layer = ABOVE_LIGHTING_LAYER + plane = ABOVE_LIGHTING_PLANE + for(var/obj/machinery/computer/ship/helm/H as anything in global.overmap_helm_computers) + H.add_known_sector(src) LAZYADD(SSshuttle.sectors_to_initialize, src) //Queued for further init. Will populate the waypoint lists; waypoints not spawned yet will be added in as they spawn. SSshuttle.clear_init_queue() + testing("Located sector \"[name]\" at [x],[y],[z], containing Z [english_list(map_z)]") + +/obj/effect/overmap/visitable/modify_mapped_vars(map_hash) + ..() + if(map_hash) + var/new_generic + for(var/old_tag in initial_generic_waypoints) + ADJUST_TAG_VAR(old_tag, map_hash) + LAZYADD(new_generic, old_tag) + initial_generic_waypoints = new_generic + for(var/shuttle_type in initial_restricted_waypoints) + var/new_restricted = list() + for(var/old_tag in initial_restricted_waypoints[shuttle_type]) + ADJUST_TAG_VAR(old_tag, map_hash) + new_restricted += old_tag + initial_restricted_waypoints[shuttle_type] = new_restricted + +/obj/effect/overmap/visitable/proc/move_to_starting_location() + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + var/location + + if(start_x && start_y) + location = locate(start_x, start_y, overmap.assigned_z) + else + var/list/candidate_turfs = block( + OVERMAP_EDGE, OVERMAP_EDGE, overmap.assigned_z, + overmap.map_size_x - OVERMAP_EDGE, overmap.map_size_y - OVERMAP_EDGE, overmap.assigned_z + ) + + candidate_turfs = where(candidate_turfs, /proc/can_not_locate, /obj/effect/overmap) + location = SAFEPICK(candidate_turfs) || locate( + rand(OVERMAP_EDGE, overmap.map_size_x - OVERMAP_EDGE), + rand(OVERMAP_EDGE, overmap.map_size_y - OVERMAP_EDGE), + overmap.assigned_z + ) + + forceMove(location) + //This is called later in the init order by SSshuttle to populate sector objects. Importantly for subtypes, shuttles will be created by then. /obj/effect/overmap/visitable/proc/populate_sector_objects() @@ -54,93 +125,129 @@ return get_filtered_areas(list(/proc/area_belongs_to_zlevels = map_z)) /obj/effect/overmap/visitable/proc/find_z_levels() - map_z = GetConnectedZlevels(z) + map_z = SSmapping.get_connected_levels(z) /obj/effect/overmap/visitable/proc/register_z_levels() - for(var/zlevel in map_z) - map_sectors["[zlevel]"] = src + var/datum/overmap/overmap = global.overmaps_by_z[num2text(z)] + if(istype(overmap)) + for(var/zlevel in map_z) + global.overmap_sectors[zlevel] = src - GLOB.using_map.player_levels |= map_z + SSmapping.player_levels |= map_z if(!(sector_flags & OVERMAP_SECTOR_IN_SPACE)) - GLOB.using_map.sealed_levels |= map_z + SSmapping.sealed_levels |= map_z if(sector_flags & OVERMAP_SECTOR_BASE) - GLOB.using_map.station_levels |= map_z - GLOB.using_map.contact_levels |= map_z - GLOB.using_map.map_levels |= map_z + SSmapping.station_levels |= map_z + SSmapping.contact_levels |= map_z + SSmapping.map_levels |= map_z //Helper for init. /obj/effect/overmap/visitable/proc/check_ownership(obj/object) if((object.z in map_z) && !(get_area(object) in SSshuttle.shuttle_areas)) return 1 +// Returns the /obj/effect/overmap/visitable to which the atom belongs based on localtion, or null +/atom/proc/get_owning_overmap_object() + var/z = get_z(src) + var/initial_sector = global.overmap_sectors[z] + if(!initial_sector) + return + + var/list/check_sectors = list(initial_sector) + var/list/checked_sectors + + while(length(check_sectors)) + + var/obj/effect/overmap/visitable/sector = check_sectors[1] + if(sector.check_ownership(src)) + return sector + + check_sectors -= sector + LAZYADD(checked_sectors, sector) + for(var/obj/effect/overmap/visitable/next_sector in sector) + if(!(next_sector in checked_sectors)) + check_sectors |= next_sector + //If shuttle_name is false, will add to generic waypoints; otherwise will add to restricted. Does not do checks. -/obj/effect/overmap/visitable/proc/add_landmark(obj/effect/shuttle_landmark/landmark, shuttle_name) - landmark.sector_set(src, shuttle_name) - if(shuttle_name) - LAZYADD(restricted_waypoints[shuttle_name], landmark) +/obj/effect/overmap/visitable/proc/add_landmark(obj/effect/shuttle_landmark/landmark, shuttle_restricted_type) + landmark.sector_set(src, shuttle_restricted_type) + if(shuttle_restricted_type) + LAZYADD(restricted_waypoints[shuttle_restricted_type], landmark) else generic_waypoints += landmark -/obj/effect/overmap/visitable/proc/remove_landmark(obj/effect/shuttle_landmark/landmark, shuttle_name) - if(shuttle_name) - var/list/shuttles = restricted_waypoints[shuttle_name] +/obj/effect/overmap/visitable/proc/remove_landmark(obj/effect/shuttle_landmark/landmark, shuttle_restricted_type) + if(shuttle_restricted_type) + var/list/shuttles = restricted_waypoints[shuttle_restricted_type] LAZYREMOVE(shuttles, landmark) else generic_waypoints -= landmark -/obj/effect/overmap/visitable/proc/get_waypoints(var/shuttle_name) +/obj/effect/overmap/visitable/proc/get_waypoints(var/shuttle_type) . = list() for(var/obj/effect/overmap/visitable/contained in src) - . += contained.get_waypoints(shuttle_name) + . += contained.get_waypoints(shuttle_type) for(var/thing in generic_waypoints) .[thing] = name - if(shuttle_name in restricted_waypoints) - for(var/thing in restricted_waypoints[shuttle_name]) + if(shuttle_type in restricted_waypoints) + for(var/thing in restricted_waypoints[shuttle_type]) .[thing] = name /obj/effect/overmap/visitable/proc/generate_skybox() return +/obj/effect/overmap/visitable/MouseEntered(location, control, params) + openToolTip(user = usr, tip_src = src, params = params, title = name) + ..() + +/obj/effect/overmap/visitable/MouseDown() + closeToolTip(usr) //No reason not to, really + ..() + +/obj/effect/overmap/visitable/MouseExited() + closeToolTip(usr) //No reason not to, really + ..() + +///Returns the level_data for the highest level in the root z-stack associated to this marker. +/obj/effect/overmap/visitable/proc/get_topmost_level_data() + if(!length(map_z)) + CRASH("Tried to get the topmost level for an overmap marker that doesn't have associated z-levels.") + + //Save some time for simple cases + if(length(map_z) == 1) + return SSmapping.levels_by_z[map_z[1]] + + //Attempts grabbing the map_data for the current level stack, and use it if we have one + var/obj/abstract/map_data/M = global.get_map_data(map_z[1]) + if(M) + return SSmapping.levels_by_z[M.z] + + //If no z stack data, assume levels are laid out from the bottommost z level towards the topmost. + return SSmapping.levels_by_z[max(map_z)] + /obj/effect/overmap/visitable/sector name = "generic sector" desc = "Sector with some stuff in it." icon_state = "sector" - anchored = 1 + anchored = TRUE // Because of the way these are spawned, they will potentially have their invisibility adjusted by the turfs they are mapped on // prior to being moved to the overmap. This blocks that. Use set_invisibility to adjust invisibility as needed instead. /obj/effect/overmap/visitable/sector/hide() + return -/proc/build_overmap() - if(!GLOB.using_map.use_overmap) - return 1 - - testing("Building overmap...") - INCREMENT_WORLD_Z_SIZE - GLOB.using_map.overmap_z = world.maxz - - - testing("Putting overmap on [GLOB.using_map.overmap_z]") - var/area/overmap/A = new - for (var/square in block(locate(1,1,GLOB.using_map.overmap_z), locate(GLOB.using_map.overmap_size,GLOB.using_map.overmap_size,GLOB.using_map.overmap_z))) - var/turf/T = square - if(T.x == GLOB.using_map.overmap_size || T.y == GLOB.using_map.overmap_size) - T = T.ChangeTurf(/turf/unsimulated/map/edge) - else - T = T.ChangeTurf(/turf/unsimulated/map) - ChangeArea(T, A) - - GLOB.using_map.sealed_levels |= GLOB.using_map.overmap_z - - testing("Overmap build complete.") - return 1 +/obj/effect/overmap/visitable/proc/allow_free_landing(var/datum/shuttle/landing_shuttle) + return free_landing /obj/effect/overmap/visitable/handle_overmap_pixel_movement() ..() - for(var/obj/machinery/computer/ship/machine in consoles) + for(var/thing in get_linked_machines_of_type(/obj/machinery/computer/ship)) + var/obj/machinery/computer/ship/machine = thing if(machine.z in map_z) - for(var/weakref/W in machine.viewers) - var/mob/M = W.resolve() + for(var/weakref/viewer_ref in machine.viewers) + var/mob/M = viewer_ref.resolve() if(istype(M) && M.client) + M.client.default_pixel_x = pixel_x + M.client.default_pixel_y = pixel_y M.client.pixel_x = pixel_x - M.client.pixel_y = pixel_y \ No newline at end of file + M.client.pixel_y = pixel_y diff --git a/code/modules/overmap/ships/circuits.dm b/code/modules/overmap/ships/circuits.dm index 05aa32c66fcd..3d729a46a55b 100644 --- a/code/modules/overmap/ships/circuits.dm +++ b/code/modules/overmap/ships/circuits.dm @@ -1,8 +1,8 @@ /obj/item/stock_parts/circuitboard/unary_atmos/engine - name = T_BOARD("gas thruster") - icon_state = "mcontroller" + name = "circuitboard (gas thruster)" + icon = 'icons/obj/modules/module_controller.dmi' build_path = /obj/machinery/atmospherics/unary/engine - origin_tech = "{'powerstorage':1,'engineering':2}" + origin_tech = @'{"powerstorage":1,"engineering":2}' req_components = list( /obj/item/stack/cable_coil = 30, /obj/item/pipe = 2 @@ -14,10 +14,10 @@ ) /obj/item/stock_parts/circuitboard/unary_atmos/fusion_engine - name = T_BOARD("fusion thruster") - icon_state = "mcontroller" + name = "circuitboard (fusion thruster)" + icon = 'icons/obj/modules/module_controller.dmi' build_path = /obj/machinery/atmospherics/unary/engine/fusion - origin_tech = "{'powerstorage':1,'engineering':2}" + origin_tech = @'{"powerstorage":1,"engineering":2}' req_components = list( /obj/item/stack/cable_coil = 30, /obj/item/pipe = 2 diff --git a/code/modules/overmap/ships/computers/comms.dm b/code/modules/overmap/ships/computers/comms.dm new file mode 100644 index 000000000000..221fa1200d5a --- /dev/null +++ b/code/modules/overmap/ships/computers/comms.dm @@ -0,0 +1,248 @@ +/obj/machinery/computer/ship/comms + name = "ship communication console" + icon_keyboard = "generic_key" + icon_screen = "helm" + light_color = "#7faaff" + core_skill = SKILL_DEVICES + +// TODO: add enabling or disabling comms transponder to hide transmission location +// TODO: use comms console to target a specific entity with a specific maser rather than targetting everyone in range +/obj/machinery/computer/ship/comms/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + if(!linked) + display_reconnect_dialog(user, "Communication") + return + + var/data[0] + + var/list/printing_entities = list() + var/list/entities = list() + var/list/broadcasters = list() + var/list/receivers = list() + + for(var/obj/machinery/shipcomms/comms in linked.comms_masers) + var/functional = !(comms.stat & (BROKEN|NOPOWER)) + broadcasters += list(list( + "name" = comms.name, + "coords" = "[comms.x],[comms.y],[comms.z]", + "desc" = (functional ? "active" : "inactive") + )) + if(functional) + for(var/obj/effect/overmap/entity in comms.get_nearby_entities()) + if(entity == linked) + continue + if(entity in printing_entities) + continue + printing_entities += entity + var/has_receiver = FALSE + for(var/obj/machinery/shipcomms/receiver/antenna in entity.comms_antennae) + if(!(antenna.stat & (BROKEN|NOPOWER))) + has_receiver = TRUE + if(!has_receiver) + continue + var/has_broadcaster = FALSE + for(var/obj/machinery/shipcomms/broadcaster/maser in entity.comms_masers) + if(!(maser.stat & (BROKEN|NOPOWER))) + has_broadcaster = TRUE + entities += list(list( + "name" = entity.name, + "coords" = "[entity.x],[entity.y]", + "desc" = entity.desc, + "status" = ((has_broadcaster && has_receiver) ? "Responding to comms pings." : "Not responding to comms pings.") + )) + + for(var/obj/machinery/shipcomms/comms in linked.comms_antennae) + receivers += list(list( + "name" = comms.name, + "coords" = "[comms.x],[comms.y],[comms.z]", + "desc" = ((comms.stat & (BROKEN|NOPOWER)) ? "inactive" : "active") + )) + + if(!length(entities)) + entities += list(list( + "name" = "None.", + "coords" = "-,-", + "desc" = "-", + "status" = "No local entities responding to comms ping." + )) + if(!length(broadcasters)) + broadcasters += list(list( + "name" = "None.", + "coords" = "-,-,-", + "desc" = "No broadcasters available." + )) + if(!length(receivers)) + receivers += list(list( + "name" = "None.", + "coords" = "-,-,-", + "desc" = "No receivers available." + )) + + data["allow_ident_change"] = linked.can_switch_ident + data["ident_enabled"] = linked.ident_transmitter + + data["entities"] = entities + data["broadcasters"] = broadcasters + data["receivers"] = receivers + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "shipcomms.tmpl", "[linked.name] Communication Screen", 380, 530) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/ship/comms/OnTopic(var/mob/user, var/list/href_list) + if(..()) + return TOPIC_HANDLED + if (!linked) + return TOPIC_NOACTION + if(href_list["toggle_comms_visibility"]) + if(linked.can_switch_ident) + linked.ident_transmitter = !linked.ident_transmitter + . = TOPIC_REFRESH + +/obj/machinery/shipcomms + density = TRUE + anchored = TRUE + idle_power_usage = 1000 + req_access = list(access_tcomsat) + icon = 'icons/obj/machines/tcomms/comms.dmi' + var/effective_range = 1 // TODO: upgrade with components. + +/obj/machinery/shipcomms/proc/toggle() + if((stat & BROKEN) || use_power != POWER_USE_OFF) + update_use_power(POWER_USE_OFF) + else + update_use_power(POWER_USE_IDLE) + +/obj/machinery/shipcomms/proc/refresh_overmap_registration() + var/turf/T = get_turf(src) + if(!T) + return + var/obj/effect/overmap/O = global.overmap_sectors[z] + if(!O) + return + if(stat & (BROKEN|NOPOWER)) + unregister(O) + else + register(O) + +/obj/machinery/shipcomms/Initialize() + ..() + . = INITIALIZE_HINT_LATELOAD + +/obj/machinery/shipcomms/proc/register(var/obj/effect/overmap/O) + return + +/obj/machinery/shipcomms/proc/unregister(var/obj/effect/overmap/O) + return + +/obj/machinery/shipcomms/proc/get_nearby_entities() + . = list() + var/obj/effect/overmap/O = global.overmap_sectors[z] + if(!O) + return + var/turf/origin = get_turf(O) + if(!origin) + return + for(var/turf/T as anything in RANGE_TURFS(origin, effective_range)) + for(var/obj/effect/overmap/other in get_turf(T)) + . |= other + +/obj/machinery/shipcomms/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + if(!. && href_list["toggle"]) + toggle() + . = TOPIC_HANDLED + +/obj/machinery/shipcomms/LateInitialize() + . = ..() + refresh_overmap_registration() + +/obj/machinery/shipcomms/power_change() + . = ..() + if(.) + refresh_overmap_registration() + +/obj/machinery/shipcomms/set_broken(new_state, cause) + . = ..() + if(.) + refresh_overmap_registration() + +/obj/machinery/shipcomms/Destroy() + var/turf/T = get_turf(src) + if(istype(T)) + var/obj/effect/overmap/O = global.overmap_sectors[T.z] + if(O) + unregister(O) + . = ..() + +/obj/machinery/shipcomms/update_power_on_move(atom/movable/mover, atom/old_loc, atom/new_loc) + ..() + if(istype(old_loc) && old_loc != new_loc && (!istype(new_loc) || new_loc.z != old_loc.z)) + var/obj/effect/overmap/lastsector = global.overmap_sectors[old_loc.z] + var/obj/effect/overmap/currentsector = istype(new_loc) && global.overmap_sectors[new_loc.z] + if(istype(lastsector) && lastsector != currentsector) + unregister(lastsector.comms_masers) + refresh_overmap_registration() + +/obj/machinery/shipcomms/proc/get_available_z_levels() + . = list() + +/obj/machinery/shipcomms/proc/has_clear_adjacent_turf() + var/turf/T = loc + if(!istype(T)) + return FALSE + for(var/turf/neighbor as anything in RANGE_TURFS(T, 1)) + if(istype(neighbor, /turf/space) || neighbor.is_outside()) + return TRUE + return FALSE + +/obj/machinery/shipcomms/on_update_icon() + cut_overlays() + if(stat & (BROKEN|NOPOWER)) + set_light(0) + else + var/image/I = emissive_overlay(icon, "[icon_state]_on") + I.color = COLOR_CYAN + add_overlay(I) + set_light(0.8, 1, 6, l_color = COLOR_CYAN) + +/obj/machinery/shipcomms/broadcaster + name = "communications maser" + desc = "A large maser emitter intended for tight-beam inter-ship communication." + icon_state = "maser" + construct_state = /decl/machine_construction/default/panel_closed + base_type = /obj/machinery/shipcomms/broadcaster + +/obj/machinery/shipcomms/broadcaster/register(var/obj/effect/overmap/O) + LAZYDISTINCTADD(O.comms_masers, src) + +/obj/machinery/shipcomms/broadcaster/unregister(var/obj/effect/overmap/O) + LAZYREMOVE(O.comms_masers, src) + +/obj/machinery/shipcomms/broadcaster/get_available_z_levels() + . = ..() + if(!(stat & (BROKEN|NOPOWER)) && has_clear_adjacent_turf()) + for(var/obj/effect/overmap/other in get_nearby_entities()) + for(var/obj/machinery/shipcomms/receiver/antenna in other.comms_antennae) + . |= antenna.get_available_z_levels() + +/obj/machinery/shipcomms/receiver + name = "communications antenna" + desc = "A tall antenna designed to receive comms maser bursts from nearby ships or stations." + icon_state = "antenna" + construct_state = /decl/machine_construction/default/panel_closed + base_type = /obj/machinery/shipcomms/receiver + +/obj/machinery/shipcomms/receiver/register(var/obj/effect/overmap/O) + LAZYDISTINCTADD(O.comms_antennae, src) + +/obj/machinery/shipcomms/receiver/unregister(var/obj/effect/overmap/O) + LAZYREMOVE(O.comms_antennae, src) + +/obj/machinery/shipcomms/receiver/get_available_z_levels() + . = ..() + if(!(stat & (BROKEN|NOPOWER)) && has_clear_adjacent_turf()) + . = SSmapping.get_connected_levels(z) \ No newline at end of file diff --git a/code/modules/overmap/ships/computers/engine_control.dm b/code/modules/overmap/ships/computers/engine_control.dm index 3145dd53829d..c2085997ee93 100644 --- a/code/modules/overmap/ships/computers/engine_control.dm +++ b/code/modules/overmap/ships/computers/engine_control.dm @@ -6,6 +6,21 @@ icon_screen = "engines" var/display_state = "status" +/// A stub used for modpacks to modify per-ship readout information. +/// This mutates the UI data list, so it can be used to mask or remove features +/// as well as to add entirely new ones. +/// It does not return a value. +/// While it can access per-engine data, it should be dispreferred for that compared to modify_engine_ui_data(). +/obj/machinery/computer/ship/engines/proc/modify_ship_ui_data(list/ui_data) + return + +/// A stub used for modpacks to modify per-engine readout information. +/// This mutates the engine's data list, so it can be used to mask or remove features +/// as well as to add entirely new ones. +/// It does not return a value. +/obj/machinery/computer/ship/engines/proc/modify_engine_ui_data(datum/extension/ship_engine/engine, list/engine_data) + return + /obj/machinery/computer/ship/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) if(!linked) display_reconnect_dialog(user, "ship control systems") @@ -29,17 +44,13 @@ var/thrust = E.get_exhaust_velocity() total_thrust += thrust rdata["eng_thrust"] = "[thrust] m/s" + modify_engine_ui_data(E, rdata) enginfo.Add(list(rdata)) data["engines_info"] = enginfo data["total_thrust"] = "[total_thrust] m/s" - var/damping_strength = 0 - for(var/datum/ship_inertial_damper/I in linked.inertial_dampers) - var/obj/machinery/inertial_damper/ID = I.holder - damping_strength += ID.get_damping_strength(FALSE) - data["damping_strength"] = damping_strength - data["needs_dampers"] = linked.needs_dampers + modify_ship_ui_data(data) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -61,31 +72,32 @@ return TOPIC_REFRESH if(href_list["set_global_limit"]) - var/newlim = input("Input new thrust limit (0..100%)", "Thrust limit", linked.get_thrust_limit() * 100) as num + var/newlim = input("Input new thrust limit (0-100%)", "Thrust limit", linked.get_thrust_limit() * 100) as num if(!CanInteract(user, state)) return TOPIC_NOACTION - var/thrust_limit = Clamp(newlim / 100, 0, 1) + var/thrust_limit = clamp(newlim / 100, 0, 1) for(var/datum/extension/ship_engine/E in linked.engines) E.thrust_limit = thrust_limit return TOPIC_REFRESH if(href_list["global_limit"]) - linked.set_thrust_limit(text2num(href_list["global_limit"])) + var/current_thrust_limit = linked.get_thrust_limit() + linked.set_thrust_limit(current_thrust_limit + text2num(href_list["global_limit"])) return TOPIC_REFRESH if(href_list["engine"]) if(href_list["set_limit"]) var/datum/extension/ship_engine/E = locate(href_list["engine"]) - var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.thrust_limit) as num + var/newlim = input("Input new thrust limit (0-100)", "Thrust limit", E.thrust_limit) as num if(!CanInteract(user, state)) return - var/limit = Clamp(newlim/100, 0, 1) + var/limit = clamp(newlim/100, 0, 1) if(istype(E)) E.thrust_limit = limit return TOPIC_REFRESH if(href_list["limit"]) var/datum/extension/ship_engine/E = locate(href_list["engine"]) - var/limit = Clamp(E.thrust_limit + text2num(href_list["limit"]), 0, 1) + var/limit = clamp(E.thrust_limit + text2num(href_list["limit"]), 0, 1) if(istype(E)) E.thrust_limit = limit return TOPIC_REFRESH diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm index a11f3dbc43e6..cf103d9e0758 100644 --- a/code/modules/overmap/ships/computers/helm.dm +++ b/code/modules/overmap/ships/computers/helm.dm @@ -1,36 +1,74 @@ -LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) +var/global/list/all_waypoints = list() +/datum/computer_file/data/waypoint + var/list/fields = list() + +/datum/computer_file/data/waypoint/New() + global.all_waypoints += src + +/datum/computer_file/data/waypoint/Destroy() + . = ..() + global.all_waypoints -= src + +var/global/list/overmap_helm_computers /obj/machinery/computer/ship/helm name = "helm control console" icon_keyboard = "teleport_key" icon_screen = "helm" light_color = "#7faaff" core_skill = SKILL_PILOT + var/autopilot = 0 var/list/known_sectors = list() var/dx //desitnation var/dy //coordinates var/speedlimit = 1/(20 SECONDS) //top speed for autopilot, 5 var/accellimit = 1 //manual limiter for acceleration + /// The mob currently operating the helm - The last one to click one of the movement buttons and be on the overmap screen. Set to `null` for autopilot or when the mob isn't in range. + var/weakref/current_operator + var/obj/compass_holder/overmap/compass /obj/machinery/computer/ship/helm/Initialize() . = ..() - get_known_sectors() - -/obj/machinery/computer/ship/helm/proc/get_known_sectors() - var/area/overmap/map = locate() in world - for(var/obj/effect/overmap/visitable/sector/S in map) - if ((S.sector_flags & OVERMAP_SECTOR_KNOWN)) - var/datum/computer_file/data/waypoint/R = new() - R.fields["name"] = S.name - R.fields["x"] = S.x - R.fields["y"] = S.y - known_sectors[S.name] = R + LAZYADD(global.overmap_helm_computers, src) + for(var/obj/effect/overmap/visitable/sector as anything in global.known_overmap_sectors) + add_known_sector(sector) + +/obj/machinery/computer/ship/helm/attempt_hook_up(obj/effect/overmap/visitable/ship/sector) + . = ..() + if(linked) + if(!compass) + compass = new(src) + else + if(compass) + QDEL_NULL(compass) + +/obj/machinery/computer/ship/helm/Destroy() + . = ..() + QDEL_NULL(compass) + LAZYREMOVE(global.overmap_helm_computers, src) + +/obj/machinery/computer/ship/helm/proc/add_known_sector(var/obj/effect/overmap/visitable/sector) + var/datum/computer_file/data/waypoint/R = new + R.fields["name"] = sector.name + R.fields["x"] = sector.x + R.fields["y"] = sector.y + known_sectors[sector.name] = R /obj/machinery/computer/ship/helm/Process() ..() + + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + var/mob/current_operator_actual = current_operator?.resolve() + if (current_operator_actual) + if (!linked) + to_chat(current_operator_actual, SPAN_DANGER("\The [src]'s controls lock up with an error flashing across the screen: Connection to vessel lost!")) + set_operator(null, TRUE) + else if (!Adjacent(current_operator_actual) || CanUseTopic(current_operator_actual) != STATUS_INTERACTIVE || !viewing_overmap(current_operator_actual)) + set_operator(null) + if (autopilot && dx && dy) - var/turf/T = locate(dx,dy,GLOB.using_map.overmap_z) + var/turf/T = locate(dx, dy, overmap.assigned_z) if(linked.loc == T) if(linked.is_still()) autopilot = 0 @@ -41,7 +79,7 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) var/direction = get_dir(linked.loc, T) var/acceleration = min(linked.get_delta_v(), accellimit) var/speed = linked.get_speed() - var/heading = linked.get_heading() + var/heading = linked.get_heading_dir() // Destination is current grid or speedlimit is exceeded if ((get_dist(linked.loc, T) <= brake_path) || speed > speedlimit) @@ -52,14 +90,23 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) // All other cases, move toward direction else if (speed + acceleration <= speedlimit) linked.accelerate(direction, accellimit) - linked.operator_skill = null//if this is on you can't dodge meteors - return + + // Re-resolve as the above set_operator() calls may have nullified or changed this. + current_operator_actual = current_operator?.resolve() + if (current_operator_actual) + to_chat(current_operator_actual, SPAN_DANGER("\The [src]'s autopilot is active and wrests control from you!")) + set_operator(null, TRUE, TRUE) + + if(compass) + compass.recalculate_heading(FALSE) + compass.rebuild_overlay_lists(TRUE) /obj/machinery/computer/ship/helm/relaymove(var/mob/user, direction) if(viewing_overmap(user) && linked) if(prob(user.skill_fail_chance(SKILL_PILOT, 50, linked.skill_needed, factor = 1))) direction = turn(direction,pick(90,-90)) linked.relaymove(user, direction, accellimit) + set_operator(user) return 1 /obj/machinery/computer/ship/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -81,7 +128,7 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) data["d_y"] = dy data["speedlimit"] = speedlimit ? speedlimit : "Halted" data["accel"] = min(round(linked.get_delta_v(), 0.01),accellimit) - data["heading"] = linked.get_heading() ? dir2angle(linked.get_heading()) : 0 + data["heading"] = linked.get_heading_angle() data["autopilot"] = autopilot data["manual_control"] = viewing_overmap(user) data["canburn"] = linked.can_burn() @@ -101,19 +148,22 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) var/list/locations[0] for (var/key in known_sectors) + var/datum/computer_file/data/waypoint/R = known_sectors[key] var/list/rdata[0] - rdata["name"] = R.fields["name"] - rdata["x"] = R.fields["x"] - rdata["y"] = R.fields["y"] + rdata["name"] = R.fields["name"] + rdata["x"] = R.fields["x"] + rdata["y"] = R.fields["y"] + rdata["tracking"] = R.fields["tracking"] rdata["reference"] = "\ref[R]" + locations.Add(list(rdata)) data["locations"] = locations ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 565, 545) + ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 565, 545, nref = src) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -127,11 +177,11 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) if (href_list["add"]) var/datum/computer_file/data/waypoint/R = new() - var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text + var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[length(known_sectors)]") as text if(!CanInteract(user,state)) return TOPIC_NOACTION if(!sec_name) - sec_name = "Sector #[known_sectors.len]" + sec_name = "Sector #[length(known_sectors)]" R.fields["name"] = sec_name if(sec_name in known_sectors) to_chat(user, "Sector with that name already exists, please input a different name.") @@ -147,29 +197,53 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num if(!CanInteract(user,state)) return TOPIC_NOACTION - R.fields["x"] = Clamp(newx, 1, world.maxx) - R.fields["y"] = Clamp(newy, 1, world.maxy) + R.fields["x"] = clamp(newx, 1, world.maxx) + R.fields["y"] = clamp(newy, 1, world.maxy) known_sectors[sec_name] = R + compass.set_waypoint("\ref[R]", R.fields["name"], R.fields["x"], R.fields["y"], 1, R.fields["color"] || COLOR_CYAN) + compass.hide_waypoint("\ref[R]") if (href_list["remove"]) var/datum/computer_file/data/waypoint/R = locate(href_list["remove"]) if(R) known_sectors.Remove(R.fields["name"]) + compass.clear_waypoint("\ref[R]") qdel(R) + if(href_list["toggle_wp_tracking"]) + var/datum/computer_file/data/waypoint/R = locate(href_list["toggle_wp_tracking"]) + if(R && (R.fields["name"] in known_sectors)) + R.fields["tracking"] = !R.fields["tracking"] + to_chat(user, SPAN_NOTICE("[R.fields["name"]] is [R.fields["tracking"] ? "now" : "no longer"] being tracked.")) + if(R.fields["tracking"]) + compass.set_waypoint("\ref[R]", R.fields["name"], R.fields["x"], R.fields["y"], 1, R.fields["color"] || COLOR_CYAN) + compass.show_waypoint("\ref[R]") + else + compass.hide_waypoint("\ref[R]") + + if(href_list["set_wp_color"]) + var/datum/computer_file/data/waypoint/R = locate(href_list["set_wp_color"]) + if(!R || !(R.fields["name"] in known_sectors)) + return TOPIC_NOACTION + var/new_color = input(user, "Please select the main colour.", "Crayon colour") as color + if(!CanInteract(user,state) || !R || known_sectors[R.fields["name"]] != R) + return TOPIC_NOACTION + R.fields["color"] = new_color + compass.set_waypoint("\ref[R]", R.fields["name"], R.fields["x"], R.fields["y"], 1, new_color) + if (href_list["setx"]) var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null if(!CanInteract(user,state)) - return + return TOPIC_NOACTION if (newx) - dx = Clamp(newx, 1, world.maxx) + dx = clamp(newx, 1, world.maxx) if (href_list["sety"]) var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null if(!CanInteract(user,state)) - return + return TOPIC_NOACTION if (newy) - dy = Clamp(newy, 1, world.maxy) + dy = clamp(newy, 1, world.maxy) if (href_list["x"] && href_list["y"]) dx = text2num(href_list["x"]) @@ -182,7 +256,7 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) if (href_list["speedlimit"]) var/newlimit = input("Input new speed limit for autopilot (0 to brake)", "Autopilot speed limit", speedlimit) as num|null if(newlimit) - speedlimit = Clamp(newlimit, 0, 100) + speedlimit = clamp(newlimit, 0, 100) if (href_list["accellimit"]) var/newlimit = input("Input new acceleration limit", "Acceleration limit", accellimit) as num|null if(newlimit) @@ -199,13 +273,85 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) if (href_list["apilot"]) autopilot = !autopilot + if (autopilot) + set_operator(null, autopilot = TRUE) + else if (viewing_overmap(user)) + set_operator(user) if (href_list["manual"]) + if(!isliving(user)) + to_chat(user, SPAN_WARNING("You can't use this.")) + return TOPIC_NOACTION viewing_overmap(user) ? unlook(user) : look(user) add_fingerprint(user) updateUsrDialog() +/obj/machinery/computer/ship/helm/unlook(mob/user) + . = ..() + if (current_operator?.resolve() == user) + set_operator(null) + if(user.client && compass) + user.client.screen -= compass + +/obj/machinery/computer/ship/helm/look(mob/user) + . = ..() + if (!autopilot) + set_operator(user) + if(user.client && compass) + user.client.screen |= compass + +/** + * Updates `current_operator` to the new user, or `null` and ejects the old operator from the overmap view - Only one person on a helm at a time! + * Will call `display_operator_change_message()` if `silent` is `FALSE`. + * `autopilot` will prevent ejection from the overmap (You want to monitor your autopilot right?) and by passed on to `display_operator_change_message()`. + * Skips ghosts and observers to prevent accidental external influencing of flight. + */ +/obj/machinery/computer/ship/helm/proc/set_operator(mob/user, silent, autopilot) + var/mob/current_operator_actual = current_operator?.resolve() + if (isobserver(user) || user == current_operator_actual) + return + + var/mob/old_operator = current_operator_actual + current_operator_actual = user + current_operator = weakref(current_operator_actual) + linked.update_operator_skill(current_operator_actual) + if (!autopilot && old_operator && viewing_overmap(old_operator)) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/computer/ship, unlook), old_operator), 0) // Workaround for linter SHOULD_NOT_SLEEP checks. + + log_debug("HELM CONTROL: [current_operator_actual ? current_operator_actual : "NO PILOT"] taking control of [src] from [old_operator ? old_operator : "NO PILOT"] in [get_area_name(src)]. [autopilot ? "(AUTOPILOT MODE)" : null]") + + if (!silent) + display_operator_change_message(old_operator, current_operator_actual, autopilot) + + +/** + * Displays visible messages indicating a change in operator. + * `autopilot` will affect the displayed message. + */ +/obj/machinery/computer/ship/helm/proc/display_operator_change_message(mob/old_operator, mob/new_operator, autopilot) + if (!old_operator) + new_operator.visible_message( + SPAN_NOTICE("\The [new_operator] takes \the [src]'s controls."), + SPAN_NOTICE("You take \the [src]'s controls.") + ) + else if (!new_operator) + if (autopilot) + old_operator.visible_message( + SPAN_NOTICE("\The [old_operator] engages \the [src]'s autopilot and releases the controls."), + SPAN_NOTICE("You engage \the [src]'s autopilot and release the controls.") + ) + else + old_operator.visible_message( + SPAN_WARNING("\The [old_operator] releases \the [src]'s controls."), + SPAN_WARNING("You release \the [src]'s controls.") + ) + else + old_operator.visible_message( + SPAN_WARNING("\The [new_operator] takes \the [src]'s controls from \the [old_operator]."), + SPAN_DANGER("\The [new_operator] takes \the [src]'s controls from you!") + ) + /obj/machinery/computer/ship/navigation name = "navigation console" @@ -229,7 +375,7 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) data["s_y"] = linked.y data["speed"] = round(linked.get_speed() * KM_OVERMAP_RATE, 0.01) data["accel"] = round(linked.get_delta_v(), 0.01) - data["heading"] = linked.get_heading() ? dir2angle(linked.get_heading()) : 0 + data["heading"] = linked.get_heading_angle() data["viewing"] = viewing_overmap(user) if(linked.get_speed()) @@ -239,7 +385,7 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "nav.tmpl", "[linked.name] Navigation Screen", 380, 530) + ui = new(user, src, ui_key, "nav.tmpl", "[linked.name] Navigation Screen", 380, 530, nref = src) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -257,7 +403,7 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) /obj/machinery/computer/ship/navigation/telescreen //little hacky but it's only used on one ship so it should be okay icon_state = "tele_nav" - density = 0 + density = FALSE /obj/machinery/computer/ship/navigation/telescreen/on_update_icon() if(reason_broken & MACHINE_BROKEN_NO_PARTS || stat & NOPOWER || stat & BROKEN) @@ -265,4 +411,4 @@ LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint) set_light(0) else icon_state = "tele_nav" - set_light(light_max_bright_on, light_inner_range_on, light_outer_range_on, 2, light_color) + set_light(light_range_on, light_power_on, light_color) diff --git a/code/modules/overmap/ships/computers/sensors.dm b/code/modules/overmap/ships/computers/sensors.dm index 43801dcb4946..9e2494128f91 100644 --- a/code/modules/overmap/ships/computers/sensors.dm +++ b/code/modules/overmap/ships/computers/sensors.dm @@ -4,12 +4,19 @@ icon_screen = "teleport" light_color = "#77fff8" extra_view = 4 - var/obj/machinery/shipsensors/sensors + var/weakref/sensor_ref var/list/last_scan + var/tmp/muted = FALSE var/working_sound = 'sound/machines/sensors/dradis.ogg' var/datum/sound_token/sound_token var/sound_id +/obj/machinery/computer/ship/sensors/proc/get_sensors() + var/obj/machinery/shipsensors/sensors = sensor_ref?.resolve() + if(!istype(sensors) || QDELETED(sensors)) + sensor_ref = null + return sensors + /obj/machinery/computer/ship/sensors/attempt_hook_up(obj/effect/overmap/visitable/ship/sector) if(!(. = ..())) return @@ -20,7 +27,7 @@ return for(var/obj/machinery/shipsensors/S in SSmachines.machinery) if(linked.check_ownership(S)) - sensors = S + sensor_ref = weakref(S) break /obj/machinery/computer/ship/sensors/proc/update_sound() @@ -28,14 +35,40 @@ return if(!sound_id) sound_id = "[type]_[sequential_id(/obj/machinery/computer/ship/sensors)]" - if(linked && sensors.use_power ** sensors.powered()) - var/volume = 10 + + var/obj/machinery/shipsensors/sensors = get_sensors() + if(linked && sensors?.use_power && !(sensors.stat & NOPOWER)) + var/ping_volume = 10 if(!sound_token) - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, working_sound, volume = volume, range = 10) - sound_token.SetVolume(volume) + sound_token = play_looping_sound(src, sound_id, working_sound, volume = ping_volume, range = 10) + sound_token.SetVolume(ping_volume) else if(sound_token) QDEL_NULL(sound_token) +/obj/machinery/computer/ship/sensors/proc/get_potential_contacts(include_self = FALSE) + var/list/potential_contacts = get_known_contacts(include_self = include_self) + // Broken or disabled sensors can't pick up nearby objects. + var/obj/machinery/shipsensors/sensors = get_sensors() + if(!sensors || sensors.inoperable() || !sensors.use_power || !sensors.range) + return potential_contacts + for(var/obj/effect/overmap/nearby in view(sensors.range,linked)) + if(nearby.requires_contact) + continue + potential_contacts |= nearby + if(!include_self && linked) + potential_contacts -= linked + return potential_contacts + +/obj/machinery/computer/ship/sensors/proc/get_known_contacts(include_self = FALSE) + var/list/known_contacts = list() + // Effects that require contact are only added to the contacts if they have been identified. + // Allows for coord tracking out of range of the player's view. + for(var/obj/effect/overmap/visitable/identified_contact in contact_datums) + known_contacts |= identified_contact + if(!include_self && linked) + known_contacts -= linked + return known_contacts + /obj/machinery/computer/ship/sensors/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) if(!linked) display_reconnect_dialog(user, "sensors") @@ -43,7 +76,9 @@ var/data[0] + var/obj/machinery/shipsensors/sensors = get_sensors() data["viewing"] = viewing_overmap(user) + data["muted"] = muted if(sensors) data["on"] = sensors.use_power data["range"] = sensors.range @@ -51,7 +86,7 @@ data["critical_heat"] = sensors.critical_heat if(sensors.is_broken()) data["status"] = "DESTROYED" - else if(!sensors.powered()) + else if(sensors.stat & NOPOWER) data["status"] = "NO POWER" else if(!sensors.in_vacuum()) data["status"] = "VACUUM SEAL BROKEN" @@ -59,27 +94,27 @@ data["status"] = "OK" var/list/contacts = list() - var/list/potential_contacts = list() - - for(var/obj/effect/overmap/nearby in view(7,linked)) - if(nearby.requires_contact) // Some ships require. - continue - potential_contacts |= nearby - - // Effects that require contact are only added to the contacts if they have been identified. - // Allows for coord tracking out of range of the player's view. - for(var/obj/effect/overmap/visitable/identified_contact in contact_datums) - potential_contacts |= identified_contact - - for(var/obj/effect/overmap/O in potential_contacts) - if(linked == O) - continue + for(var/obj/effect/overmap/O in get_potential_contacts()) if(!O.scannable) continue var/bearing = round(90 - Atan2(O.x - linked.x, O.y - linked.y),5) if(bearing < 0) bearing += 360 - contacts.Add(list(list("name"=O.name, "color"= O.color, "ref"="\ref[O]", "bearing"=bearing))) + contacts.Add(list(list("name"=O.name, "color"= O.color, "ref"="\ref[O]", "bearing"=bearing, "scannable"=TRUE))) + for(var/obj/effect/overmap/UFO in objects_in_view) + var/progress = objects_in_view[UFO] + if((progress >= 100) || !isnull(contact_datums[UFO])) // Not a UFO if it's identified! + continue + if(!UFO.scannable) + continue + var/bearing = round(90 - Atan2(UFO.x - linked.x, UFO.y - linked.y),5) + if(bearing < 0) + bearing += 360 + var/bearing_variability = round(30/sensors.sensor_strength, 5) + var/bearing_estimate = round(rand(bearing-bearing_variability, bearing+bearing_variability), 5) + if(bearing_estimate < 0) + bearing_estimate += 360 + contacts.Add(list(list("name"=UFO.unknown_id, "color"= UFO.color, "variability" = bearing_variability, "progress"=progress, "bearing"=bearing_estimate, "scannable"=FALSE))) if(contacts.len) data["contacts"] = contacts data["last_scan"] = last_scan @@ -90,7 +125,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "shipsensors.tmpl", "[linked.name] Sensors Control", 420, 530, src) + ui = new(user, src, ui_key, "shipsensors.tmpl", "[linked.name] Sensors Control", 420, 530, nref = src) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -111,13 +146,18 @@ find_sensors() return TOPIC_REFRESH + if (href_list["mute"]) + muted = !muted + return TOPIC_REFRESH + + var/obj/machinery/shipsensors/sensors = get_sensors() if(sensors) if (href_list["range"]) var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null if(!CanInteract(user,state)) return TOPIC_NOACTION if (nrange) - sensors.set_range(Clamp(nrange, 1, world.view)) + sensors.set_range(clamp(nrange, 1, world.view)) return TOPIC_REFRESH if (href_list["toggle"]) sensors.toggle() @@ -126,7 +166,7 @@ if (href_list["scan"]) var/obj/effect/overmap/O = locate(href_list["scan"]) if(istype(O) && !QDELETED(O)) - if((O in view(7,linked))|| (O in contact_datums)) + if((O in view(sensors.range, linked)) || !isnull(contact_datums[O])) playsound(loc, "sound/effects/ping.ogg", 50, 1) LAZYSET(last_scan, "data", O.get_scan_data(user)) LAZYSET(last_scan, "location", "[O.x],[O.y]") @@ -139,7 +179,7 @@ if (href_list["print"]) playsound(loc, "sound/machines/dotprinter.ogg", 30, 1) - new/obj/item/paper/(get_turf(src), last_scan["data"], "paper (Sensor Scan - [last_scan["name"]])") + new/obj/item/paper/(get_turf(src), null, last_scan["data"], "paper (Sensor Scan - [last_scan["name"]])") return TOPIC_HANDLED /obj/machinery/shipsensors @@ -147,18 +187,19 @@ desc = "Long range gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements." icon = 'icons/obj/machines/ship_sensors.dmi' icon_state = "sensors" - anchored = 1 - var/critical_heat = 50 // sparks and takes damage when active & above this heat - var/heat_reduction = 1.5 // mitigates this much heat per tick - var/heat = 0 - var/range = 1 - var/sensor_strength //used for detecting ships via contacts + anchored = TRUE + density = TRUE idle_power_usage = 5000 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = NOSCREEN | NOINPUT - frame_type = /obj/machinery/constructable_frame base_type = /obj/machinery/shipsensors + stock_part_presets = list(/decl/stock_part_preset/terminal_connect) + var/critical_heat = 50 // sparks and takes damage when active & above this heat + var/heat_reduction = 1.5 // mitigates this much heat per tick + var/heat = 0 + var/range = 1 + var/sensor_strength //used for detecting ships via contacts /obj/machinery/shipsensors/proc/in_vacuum() var/turf/T=get_turf(src) @@ -180,7 +221,6 @@ if(!use_power) //need some juice to kickstart use_power_oneoff(idle_power_usage*5) update_use_power(!use_power) - queue_icon_update() /obj/machinery/shipsensors/Process() if(use_power) //can't run in non-vacuum @@ -188,9 +228,7 @@ toggle() if(heat > critical_heat) src.visible_message("\The [src] violently spews out sparks!") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) take_damage(10, BURN) toggle() heat += idle_power_usage/15000 @@ -200,7 +238,7 @@ /obj/machinery/shipsensors/power_change() . = ..() - if(use_power && !powered()) + if(use_power && (stat & NOPOWER)) toggle() /obj/machinery/shipsensors/proc/set_range(nrange) @@ -215,8 +253,8 @@ /obj/machinery/shipsensors/RefreshParts() ..() - sensor_strength = Clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 0, 5) + sensor_strength = clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 0, 5) /obj/machinery/shipsensors/weak heat_reduction = 0.2 - desc = "Miniturized gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements." + desc = "Miniaturized gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements." diff --git a/code/modules/overmap/ships/computers/ship.dm b/code/modules/overmap/ships/computers/ship.dm index 7af01a069283..33aff495d218 100644 --- a/code/modules/overmap/ships/computers/ship.dm +++ b/code/modules/overmap/ships/computers/ship.dm @@ -7,6 +7,7 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov var/obj/effect/overmap/visitable/ship/linked var/list/viewers // Weakrefs to mobs in direct-view mode. var/extra_view = 0 // how much the view is increased by when the mob is in overmap mode. + var/overmap_id = OVERMAP_ID_SPACE // A late init operation called in SSshuttle, used to attach the thing to the right ship. /obj/machinery/computer/ship/proc/attempt_hook_up(obj/effect/overmap/visitable/ship/sector) @@ -14,30 +15,25 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov return if(sector.check_ownership(src)) linked = sector - LAZYSET(linked.consoles, src, TRUE) + linked.register_machine(src, /obj/machinery/computer/ship) return 1 /obj/machinery/computer/ship/Destroy() if(linked) - LAZYREMOVE(linked.consoles, src) + linked.unregister_machine(src, /obj/machinery/computer/ship) + linked = null . = ..() /obj/machinery/computer/ship/proc/sync_linked() - var/obj/effect/overmap/visitable/ship/sector = map_sectors["[z]"] - if(!sector) + var/obj/effect/overmap/visitable/ship/sector = get_owning_overmap_object() + if(!istype(sector)) return - return attempt_hook_up_recursive(sector) - -/obj/machinery/computer/ship/proc/attempt_hook_up_recursive(obj/effect/overmap/visitable/ship/sector) - if(attempt_hook_up(sector)) - return sector - for(var/obj/effect/overmap/visitable/ship/candidate in sector) - if((. = .(candidate))) - return + attempt_hook_up(sector) + return linked /obj/machinery/computer/ship/proc/display_reconnect_dialog(var/mob/user, var/flavor) - var/datum/browser/written/popup = new (user, "[src]", "[src]") - popup.set_content("
    Error
    Unable to connect to [flavor].
    Reconnect
    ") + var/datum/browser/written_digital/popup = new (user, "[src]", "[src]") + popup.set_content("
    Error
    Unable to connect to [flavor].
    Reconnect
    ") popup.open() /obj/machinery/computer/ship/interface_interact(var/mob/user) @@ -64,30 +60,39 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov if(linked) user.reset_view(linked) if(user.client) - user.client.view = world.view + extra_view + if(istext(user.client.view)) + var/list/retrieved_view = splittext(user.client.view, "x") + user.client.view = "[text2num(retrieved_view[1]) + extra_view]x[text2num(retrieved_view[2]) + extra_view]" + else + user.client.view = user.client.view + extra_view if(linked) - for(var/obj/machinery/computer/ship/sensors/sensor in linked.consoles) + for(var/obj/machinery/computer/ship/sensors/sensor in linked.get_linked_machines_of_type(/obj/machinery/computer/ship)) sensor.reveal_contacts(user) - GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook) - GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook) + events_repository.register(/decl/observ/moved, user, src, TYPE_PROC_REF(/obj/machinery/computer/ship, unlook)) + if(isliving(user)) + events_repository.register(/decl/observ/stat_set, user, src, TYPE_PROC_REF(/obj/machinery/computer/ship, unlook)) LAZYDISTINCTADD(viewers, weakref(user)) + if(linked) + LAZYDISTINCTADD(linked.navigation_viewers, weakref(user)) /obj/machinery/computer/ship/proc/unlook(var/mob/user) user.reset_view() if(user.client) - user.client.view = world.view user.client.OnResize() if(linked) - for(var/obj/machinery/computer/ship/sensors/sensor in linked.consoles) + for(var/obj/machinery/computer/ship/sensors/sensor in linked.get_linked_machines_of_type(/obj/machinery/computer/ship)) sensor.hide_contacts(user) - GLOB.moved_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook) - GLOB.stat_set_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook) + events_repository.unregister(/decl/observ/moved, user, src, TYPE_PROC_REF(/obj/machinery/computer/ship, unlook)) + if(isliving(user)) + events_repository.unregister(/decl/observ/stat_set, user, src, TYPE_PROC_REF(/obj/machinery/computer/ship, unlook)) LAZYREMOVE(viewers, weakref(user)) + if(linked) + LAZYREMOVE(linked.navigation_viewers, weakref(user)) /obj/machinery/computer/ship/proc/viewing_overmap(mob/user) - return (weakref(user) in viewers) + return (weakref(user) in viewers) || (linked && (weakref(user) in linked.navigation_viewers)) /obj/machinery/computer/ship/CouldNotUseTopic(mob/user) . = ..() @@ -99,21 +104,19 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov look(user) /obj/machinery/computer/ship/check_eye(var/mob/user) - if (!get_dist(user, src) > 1 || user.blinded || !linked ) + if (!get_dist(user, src) > 1 || user.is_blind() || !linked ) unlook(user) return -1 else return 0 -/obj/machinery/computer/ship/Destroy() - linked.consoles -= src - . = ..() - /obj/machinery/computer/ship/sensors/Destroy() - sensors = null + sensor_ref = null if(LAZYLEN(viewers)) - for(var/weakref/W in viewers) - var/M = W.resolve() + for(var/weakref/viewer_ref in viewers) + var/M = viewer_ref.resolve() if(M) - unlook(M) - . = ..() \ No newline at end of file + INVOKE_ASYNC(PROC_REF(unlook), M) + if(linked) + LAZYREMOVE(linked.navigation_viewers, viewer_ref) + . = ..() diff --git a/code/modules/overmap/ships/computers/shuttle.dm b/code/modules/overmap/ships/computers/shuttle.dm index 9c728b2dddc6..b855f1b207d6 100644 --- a/code/modules/overmap/ships/computers/shuttle.dm +++ b/code/modules/overmap/ships/computers/shuttle.dm @@ -23,6 +23,7 @@ . += list( "destination_name" = shuttle.get_destination_name(), + "port_name" = shuttle.get_port_name(), "can_pick" = shuttle.moving_status == SHUTTLE_IDLE, "fuel_usage" = shuttle.fuel_consumption * 100, "remaining_fuel" = round(total_gas, 0.01) * 100, @@ -35,15 +36,24 @@ if((. = ..()) != null) return + if(href_list["dock_pick"]) + var/list/port_choices = shuttle.get_port_choices() + var/port + if(length(port_choices)) + port = input("Choose shuttle docking port:", "Shuttle Docking Port") as null|anything in port_choices + else + to_chat(user, SPAN_WARNING("No functional docking ports, defaulting to center-of-mass landing.")) + if(CanInteract(user, global.default_topic_state) && (port in port_choices)) + shuttle.set_port(port_choices[port]) if(href_list["pick"]) var/list/possible_d = shuttle.get_possible_destinations() var/D if(possible_d.len) D = input("Choose shuttle destination", "Shuttle Destination") as null|anything in possible_d else - to_chat(usr, SPAN_WARNING("No valid landing sites in range.")) + to_chat(user, SPAN_WARNING("No valid landing sites in range.")) possible_d = shuttle.get_possible_destinations() - if(CanInteract(usr, GLOB.default_state) && (D in possible_d)) + if(CanInteract(user, global.default_topic_state) && (D in possible_d)) shuttle.set_destination(possible_d[D]) return TOPIC_REFRESH if(href_list["manual_landing"]) @@ -51,24 +61,23 @@ if(!landing_eye) to_chat(user, SPAN_WARNING("Could not begin landing procedure!")) return - if(user.skill_check(SKILL_PILOT, SKILL_PROF)) + if(user.skill_check(SKILL_PILOT, shuttle.landing_skill_needed)) if(landing_eye.current_looker && landing_eye.current_looker != user) to_chat(user, SPAN_WARNING("Someone is already performing a landing maneuver!")) return TOPIC_HANDLED else start_landing(user, shuttle) return TOPIC_REFRESH - to_chat(usr, SPAN_WARNING("The manual controls look hopelessly complex to you!")) + to_chat(user, SPAN_WARNING("The manual controls look hopelessly complex to you!")) /obj/machinery/computer/shuttle_control/explore/proc/start_landing(var/mob/user, var/datum/shuttle/autodock/overmap/shuttle) - - var/obj/effect/overmap/visitable/current_sector = map_sectors["[z]"] + var/obj/effect/overmap/visitable/current_sector = global.overmap_sectors[z] var/obj/effect/overmap/visitable/target_sector if(current_sector && istype(current_sector)) var/list/available_sectors = list() for(var/obj/effect/overmap/visitable/S in range(get_turf(current_sector), shuttle.range)) - if(S.free_landing) + if(S.allow_free_landing(shuttle)) available_sectors += S if(LAZYLEN(available_sectors)) @@ -77,47 +86,49 @@ to_chat(user, SPAN_WARNING("No valid landing sites in range!")) return - if(target_sector && CanInteract(user, GLOB.default_state)) + if(target_sector && CanInteract(user, global.default_topic_state)) var/datum/extension/eye/landing_eye = get_extension(src, /datum/extension/eye) if(landing_eye) if(landing_eye.current_looker) // Double checking in case someone jumped ahead of us. to_chat(user, SPAN_WARNING("Someone is already performing a landing maneuver!")) return - var/turf/eye_turf = locate(world.maxx/2, world.maxy/2, target_sector.map_z[target_sector.map_z.len]) // Center of the top z-level of the target sector. - if(landing_eye.look(user, list(shuttle_tag), eye_turf)) // Placement of the eye was successful + var/turf/eye_turf = WORLD_CENTER_TURF(target_sector.map_z[target_sector.map_z.len]) // Center of the top z-level of the target sector. + if(landing_eye.look(user, list(shuttle_tag, target_sector))) // Placement of the eye was successful landing_eye.extension_eye.forceMove(eye_turf) return - + to_chat(user, SPAN_WARNING("You are unable to land!")) return /obj/machinery/computer/shuttle_control/explore/proc/finish_landing(var/mob/user) - var/datum/extension/eye/landing_eye = get_extension(src, /datum/extension/eye/) + var/datum/extension/eye/eye_extension = get_extension(src, /datum/extension/eye/) - if(!landing_eye) + if(!eye_extension) return - var/turf/lz_turf = landing_eye.get_eye_turf() + var/mob/observer/eye/landing/landing_eye = eye_extension.extension_eye + var/turf/lz_turf = eye_extension.get_eye_turf() - var/obj/effect/overmap/visitable/sector = map_sectors["[lz_turf.z]"] - if(!sector.free_landing) // Additional safety check to ensure the sector permits landing. + var/obj/effect/overmap/visitable/sector = global.overmap_sectors[lz_turf.z] + if(!sector.allow_free_landing()) // Additional safety check to ensure the sector permits landing. to_chat(user, SPAN_WARNING("Invalid landing zone!")) - landing_eye.unlook() return var/datum/shuttle/autodock/overmap/shuttle = SSshuttle.shuttles[shuttle_tag] - var/obj/effect/shuttle_landmark/temporary/lz = new(lz_turf) - if(lz.is_valid(shuttle)) // Preliminary check that the shuttle fits. - shuttle.set_destination(lz) - else - qdel(lz) - to_chat(user, SPAN_WARNING("Invalid landing zone!")) - landing_eye.unlook() - -/obj/machinery/computer/shuttle_control/proc/end_landing() - var/datum/extension/eye/landing_eye = get_extension(src, /datum/extension/eye/) - if(landing_eye) - landing_eye.unlook() + var/atom/movable/center_of_rotation = shuttle.get_center_of_rotation() + + if(landing_eye.check_landing()) // Make sure the landmark is in a valid location. + var/obj/effect/shuttle_landmark/temporary/lz = new(lz_turf, landing_eye.check_secure_landing()) + lz.flags |= SLANDMARK_FLAG_REORIENT + lz.dir = landing_eye?.shuttle_dir || center_of_rotation.dir + if(lz.is_valid(shuttle)) // Make sure the shuttle fits. + to_chat(user, SPAN_NOTICE("Landing zone set!")) + shuttle.set_destination(lz) + eye_extension.unlook() + return + else + qdel(lz) + to_chat(user, SPAN_WARNING("Invalid landing zone!")) /obj/machinery/computer/shuttle_control/explore/power_change() . = ..() diff --git a/code/modules/overmap/ships/created.dm b/code/modules/overmap/ships/created.dm new file mode 100644 index 000000000000..71bac7afebb3 --- /dev/null +++ b/code/modules/overmap/ships/created.dm @@ -0,0 +1,12 @@ +/obj/effect/overmap/visitable/ship/landable/created/Initialize(mapload, ship_name, ship_color, ship_dir) + if(ship_name) + name = ship_name + shuttle = ship_name + + if(ship_color) + color = ship_color + + if(ship_dir) + fore_dir = ship_dir + + . = ..(mapload) \ No newline at end of file diff --git a/code/modules/overmap/ships/device_types/_engine.dm b/code/modules/overmap/ships/device_types/_engine.dm index b7cad993f2f4..707efb352416 100644 --- a/code/modules/overmap/ships/device_types/_engine.dm +++ b/code/modules/overmap/ships/device_types/_engine.dm @@ -1,4 +1,4 @@ -var/list/ship_engines = list() +var/global/list/ship_engines = list() /datum/extension/ship_engine base_type = /datum/extension/ship_engine expected_type = /obj/machinery @@ -19,6 +19,12 @@ var/list/ship_engines = list() engine_type = e_type ship_engines |= src +/datum/extension/ship_engine/Destroy() + . = ..() + ship_engines -= src + for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.ships) + S.engines -= src + /datum/extension/ship_engine/proc/is_on() var/obj/machinery/M = holder if(M.use_power && M.operable()) @@ -47,7 +53,7 @@ var/list/ship_engines = list() . = list() var/obj/machinery/M = holder - .+= "Location: [get_area(holder)]." + .+= "Location: [get_area_name(holder)]." if(M.stat & NOPOWER) .+= "Insufficient power to operate." if(!has_fuel()) @@ -67,11 +73,13 @@ var/list/ship_engines = list() /datum/extension/ship_engine/proc/check_blockage() var/obj/machinery/M = holder blockage = FALSE - var/exhaust_dir = GLOB.reverse_dir[M.dir] + var/exhaust_dir = global.reverse_dir[M.dir] var/turf/A = get_step(src, exhaust_dir) var/turf/B = A - while(isturf(A) && !(isspace(A) || isopenspace(A))) - if((B.c_airblock(A)) & AIR_BLOCKED) + var/airblock + while(isturf(A) && !(isspaceturf(A) || A.is_open())) + ATMOS_CANPASS_TURF(airblock, B, A) + if(airblock & AIR_BLOCKED) blockage = TRUE break B = A @@ -94,4 +102,11 @@ var/list/ship_engines = list() if(M.stat & NOPOWER)//try again M.power_change() if(is_on())//if everything is in working order, start booting! - next_on = world.time + boot_time \ No newline at end of file + next_on = world.time + boot_time + +/datum/extension/ship_engine/proc/sync_to_ship() + . = FALSE + for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.ships) + if(S.check_ownership(holder)) + S.engines |= src + return TRUE \ No newline at end of file diff --git a/code/modules/overmap/ships/device_types/bluespace_thruster.dm b/code/modules/overmap/ships/device_types/bluespace_thruster.dm deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/code/modules/overmap/ships/device_types/fusion_thruster.dm b/code/modules/overmap/ships/device_types/fusion_thruster.dm index 3e669f7f716c..e2a16504901e 100644 --- a/code/modules/overmap/ships/device_types/fusion_thruster.dm +++ b/code/modules/overmap/ships/device_types/fusion_thruster.dm @@ -4,12 +4,12 @@ /datum/extension/ship_engine/gas/fusion/get_propellant(var/sample_only = TRUE) var/obj/machinery/atmospherics/unary/engine/fusion/thruster = holder - if(!thruster.harvest_from || !thruster.harvest_from.owned_field) + if(!istype(thruster) || !thruster.harvest_from?.owned_field) return // No valid propellant. - var/obj/effect/fusion_em_field/owned_field = thruster.harvest_from.owned_field var/datum/gas_mixture/propellant = ..() - propellant.temperature += owned_field.plasma_temperature * efficiency - return propellant + if(propellant) + propellant.temperature += log(100, (thruster.harvest_from.owned_field.plasma_temperature * efficiency)) + . = propellant /datum/extension/ship_engine/gas/fusion/has_fuel() . = ..() @@ -23,4 +23,4 @@ if(!.) return var/obj/machinery/atmospherics/unary/engine/fusion/thruster = holder - return thruster.harvest_from && thruster.harvest_from.owned_field \ No newline at end of file + return !!thruster.harvest_from?.owned_field \ No newline at end of file diff --git a/code/modules/overmap/ships/device_types/gas_thruster.dm b/code/modules/overmap/ships/device_types/gas_thruster.dm index ed4ee28b3356..1f09c65b3187 100644 --- a/code/modules/overmap/ships/device_types/gas_thruster.dm +++ b/code/modules/overmap/ships/device_types/gas_thruster.dm @@ -8,7 +8,7 @@ var/obj/machinery/atmospherics/unary/engine/E = holder if(!is_on()) return 0 - if(!has_fuel() || (0 < E.use_power_oneoff(charge_per_burn)) || check_blockage()) + if(!has_fuel() || (0 < E.use_power_oneoff(charge_per_burn * thrust_limit)) || check_blockage()) E.audible_message(src, SPAN_WARNING("[holder] coughs once and goes silent!")) E.update_use_power(POWER_USE_OFF) return 0 @@ -18,34 +18,36 @@ return 0 . = get_exhaust_velocity(removed) playsound(E.loc, 'sound/machines/thruster.ogg', 100 * thrust_limit * partial, 0, world.view * 4, 0.1) - if(E.network) - E.network.update = 1 + E.update_networks() + E.update_icon() - var/exhaust_dir = GLOB.reverse_dir[E.dir] + var/exhaust_dir = global.reverse_dir[E.dir] var/turf/T = get_step(holder, exhaust_dir) if(T) T.assume_air(removed) - new/obj/effect/engine_exhaust(T, exhaust_dir, removed.check_combustibility() && removed.temperature >= FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE) + new/obj/effect/engine_exhaust(T, E.dir) /datum/extension/ship_engine/gas/proc/get_propellant(var/sample_only = TRUE, var/partial = 1) var/obj/machinery/atmospherics/unary/engine/E = holder - var/datum/gas_mixture/removed = E.air_contents.remove_ratio((volume_per_burn * thrust_limit * partial) / E.air_contents.volume) - if(sample_only) - var/datum/gas_mixture/sample = new(removed.volume) - sample.copy_from(removed) - E.air_contents.merge(removed) - return sample - return removed + if(istype(E) && E.air_contents?.total_volume > 0) + var/datum/gas_mixture/removed = E.air_contents.remove_ratio((volume_per_burn * thrust_limit * partial) / E.air_contents.total_volume) + if(removed && sample_only) + var/datum/gas_mixture/sample = new(removed.total_volume) + sample.copy_from(removed) + E.air_contents.merge(removed) + return sample + . = removed /datum/extension/ship_engine/gas/get_exhaust_velocity(var/datum/gas_mixture/propellant) if(!is_on() || !has_fuel()) return 0 + propellant = propellant || get_propellant() if(!propellant) - propellant = get_propellant() + return 0 var/exit_pressure = get_nozzle_exit_pressure() var/ratio_specific_heat = get_ratio_specific_heat(propellant) - if(propellant.return_pressure() <= MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND) + if((propellant.return_pressure() - exit_pressure) <= MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND) return 0 var/mm = propellant.specific_mass() if(mm == 0) @@ -58,7 +60,7 @@ /datum/extension/ship_engine/gas/proc/get_nozzle_exit_pressure() var/obj/machinery/atmospherics/unary/engine/E = holder - var/exhaust_dir = GLOB.reverse_dir[E.dir] + var/exhaust_dir = global.reverse_dir[E.dir] var/turf/A = get_step(holder, exhaust_dir) var/datum/gas_mixture/nozzle_exit_air = A.return_air() var/exit_pressure = 0 @@ -68,13 +70,12 @@ /datum/extension/ship_engine/gas/proc/get_ratio_specific_heat(var/datum/gas_mixture/propellant) var/ratio_specific_heat = 0 - if(!propellant) - propellant = get_propellant() - if(!length(propellant.gas) || !propellant.total_moles) + propellant = propellant || get_propellant() + if(!propellant || !length(propellant.gas) || !propellant.total_moles) return 0.01 // Divide by zero protection. for(var/mat in propellant.gas) - var/decl/material/gas/G = decls_repository.get_decl(mat) + var/decl/material/gas/G = GET_DECL(mat) // 0.08 chosen to get the RATIO of the specific heat, we don't have cV/cP here, so this is a rough approximate. var/ratio = (G.gas_specific_heat / 25) + 0.8// These numbers are meaningless, just magic numbers to calibrate range. ratio_specific_heat += ratio * (propellant.gas[mat] / propellant.total_moles) @@ -82,7 +83,7 @@ if(ratio_specific_heat == 0 || ratio_specific_heat == 1) // rare case of avoiding a divide by zero error. ratio_specific_heat += 0.01 - return Clamp(ratio_specific_heat, MINIMUM_RATIO_SPECIFIC_HEAT, MAXIMUM_RATIO_SPECIFIC_HEAT) + return clamp(ratio_specific_heat, MINIMUM_RATIO_SPECIFIC_HEAT, MAXIMUM_RATIO_SPECIFIC_HEAT) /datum/extension/ship_engine/gas/get_specific_wet_mass() var/datum/gas_mixture/propellant = get_propellant() @@ -111,5 +112,5 @@ var/exit_pressure = get_nozzle_exit_pressure() .+= exit_pressure ? "Nozzle exit pressure: [exit_pressure] kPA" : "Nozzle exit pressure: VACUUM" - + return jointext(.,"
    ") \ No newline at end of file diff --git a/code/modules/overmap/ships/landable.dm b/code/modules/overmap/ships/landable.dm index c09b521c6fa1..93adc8097675 100644 --- a/code/modules/overmap/ships/landable.dm +++ b/code/modules/overmap/ships/landable.dm @@ -6,12 +6,19 @@ var/shuttle // Name of associated shuttle. Must be autodock. var/obj/effect/shuttle_landmark/ship/landmark // Record our open space landmark for easy reference. var/multiz = 0 // Index of multi-z levels, starts at 0 + var/use_mapped_z_levels = FALSE // If true, it will use the z level block on which it's mapped as the "Open Space" block; if false it creates a new block for that. + // If you use this, use /obj/effect/shuttle_landmark/ship as the landmark (set the landmark tag to match on the shuttle; no other setup needed) var/status = SHIP_STATUS_LANDED + var/level_type = /datum/level_data/space icon_state = "shuttle" moving_state = "shuttle_moving" +/obj/effect/overmap/visitable/ship/landable/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(shuttle, map_hash) + /obj/effect/overmap/visitable/ship/landable/Destroy() - GLOB.shuttle_moved_event.unregister(SSshuttle.shuttles[shuttle], src) + events_repository.unregister(/decl/observ/shuttle_moved, SSshuttle.shuttles[shuttle], src) return ..() /obj/effect/overmap/visitable/ship/landable/can_burn() @@ -20,7 +27,7 @@ return ..() /obj/effect/overmap/visitable/ship/landable/burn() - if(status != SHIP_STATUS_OVERMAP && status != SHIP_STATUS_ENCOUNTER) + if(status != SHIP_STATUS_OVERMAP && status != SHIP_STATUS_ENCOUNTER) return 0 return ..() @@ -32,34 +39,35 @@ if(get_area(object) in areas) return 1 -/obj/effect/overmap/visitable/ship/landable/Process() +/obj/effect/overmap/visitable/ship/landable/allow_free_landing(var/datum/shuttle/landing_shuttle) + var/datum/shuttle/autodock/overmap/child_shuttle = SSshuttle.shuttles[shuttle] + if(child_shuttle == landing_shuttle) + return FALSE // Use the main landmark. + if(child_shuttle.current_location != landmark) + return FALSE // Cannot encounter a shuttle while it is landed elsewhere. . = ..() + +/obj/effect/overmap/visitable/ship/landable/Process(wait, tick) + ..() var/datum/shuttle/autodock/overmap/child_shuttle = SSshuttle.shuttles[shuttle] if(!child_shuttle || !istype(child_shuttle)) return if(child_shuttle.current_location.flags & SLANDMARK_FLAG_DISCONNECTED) // Keep an eye on the distance between the shuttle and the sector if we aren't fully docked. - if(get_dist(src, map_sectors["[child_shuttle.current_location.z]"]) > min(child_shuttle.range, 1)) // Some leeway so 0 range shuttles are still able to chase. + var/obj/effect/overmap/visitable/ship/landable/encounter = global.overmap_sectors[child_shuttle.current_location.z] + if((get_dist(src, encounter) > min(child_shuttle.range, 1))) // Some leeway so 0 range shuttles are still able to chase. child_shuttle.attempt_force_move(landmark) + if(istype(encounter)) + if(encounter.status != SHIP_STATUS_OVERMAP) // Check if the encountered sector has moved out of space and landed elsewhere. + child_shuttle.attempt_force_move(landmark) // We autobuild our z levels. /obj/effect/overmap/visitable/ship/landable/find_z_levels() - for(var/i = 0 to multiz) - INCREMENT_WORLD_Z_SIZE - map_z += world.maxz - - var/turf/center_loc = locate(round(world.maxx/2), round(world.maxy/2), world.maxz) - landmark = new (center_loc, shuttle) - add_landmark(landmark, shuttle) - - var/visitor_dir = fore_dir - for(var/landmark_name in list("FORE", "PORT", "AFT", "STARBOARD")) - var/turf/visitor_turf = get_ranged_target_turf(center_loc, visitor_dir, round(min(world.maxx/4, world.maxy/4))) - var/obj/effect/shuttle_landmark/visiting_shuttle/visitor_landmark = new (visitor_turf, landmark, landmark_name) - add_landmark(visitor_landmark) - visitor_dir = turn(visitor_dir, 90) - - if(multiz) - new /obj/effect/landmark/map_data(center_loc, (multiz + 1)) + if(!use_mapped_z_levels) + for(var/i = 0 to multiz) + SSmapping.increment_world_z_size(level_type) + map_z += world.maxz + else + ..() /obj/effect/overmap/visitable/ship/landable/get_areas() var/datum/shuttle/shuttle_datum = SSshuttle.shuttles[shuttle] @@ -67,26 +75,77 @@ return list() return shuttle_datum.find_childfree_areas() +/obj/effect/overmap/visitable/ship/landable/move_to_starting_location() + if(!use_mapped_z_levels) + ..() + return // it actually doesn't matter what we do in this case + + // Attempt to find a safe and random overmap turf to start on + var/datum/overmap/overmap = global.overmaps_by_name[overmap_id] + var/list/candidates = list() + for(var/turf/T as anything in block(OVERMAP_EDGE, OVERMAP_EDGE, overmap.assigned_z, overmap.map_size_x - 1, overmap.map_size_y - 1, overmap.assigned_z)) + if(locate(/obj/effect/overmap) in T) + continue + candidates += T + if(length(candidates)) + forceMove(pick(candidates)) + else + ..() // this picks a random turf + /obj/effect/overmap/visitable/ship/landable/populate_sector_objects() ..() + var/datum/shuttle/shuttle_datum = SSshuttle.shuttles[shuttle] - GLOB.shuttle_moved_event.register(shuttle_datum, src, .proc/on_shuttle_jump) + + // Finish "open space" z block setup + if(!use_mapped_z_levels) + var/top_z = map_z[map_z.len] + var/turf/center_loc = WORLD_CENTER_TURF(top_z) + landmark = new (center_loc, shuttle) + add_landmark(landmark) // we don't restrict it but it does a more strict check in is_valid anyway + else + var/obj/effect/shuttle_landmark/ship/ship_landmark = shuttle_datum.current_location + if(!istype(ship_landmark)) + PRINT_STACK_TRACE("Landable ship [src] with shuttle [shuttle] was mapped with a starting landmark type [ship_landmark.type], but should be /obj/effect/shuttle_landmark/ship.") + ship_landmark = new(ship_landmark.loc, shuttle) // this is not great, but probably mostly works, and we already reported the issue + qdel(shuttle_datum.current_location) + shuttle_datum.current_location = ship_landmark + landmark = ship_landmark + landmark.shuttle_name = shuttle + LAZYDISTINCTADD(initial_generic_waypoints, landmark.landmark_tag) // this is us being user-friendly: it means we register it properly regardless of whether the mapper put the tag in initial_restricted_waypoints + + var/visitor_dir = fore_dir + for(var/landmark_name in list("FORE", "PORT", "AFT", "STARBOARD")) + var/turf/visitor_turf = get_ranged_target_turf(get_turf(landmark), visitor_dir, round(min(world.maxx/4, world.maxy/4))) + var/obj/effect/shuttle_landmark/visiting_shuttle/visitor_landmark = new (visitor_turf, landmark, landmark_name) + add_landmark(visitor_landmark) + visitor_dir = turn(visitor_dir, 90) + + // Configure shuttle datum + events_repository.register(/decl/observ/shuttle_moved, shuttle_datum, src, PROC_REF(on_shuttle_jump)) on_landing(landmark, shuttle_datum.current_location) // We "land" at round start to properly place ourselves on the overmap. + if(landmark == shuttle_datum.current_location) + status = SHIP_STATUS_OVERMAP // we spawned on the overmap, so have to initialize our state properly. /obj/effect/shuttle_landmark/ship name = "Open Space" landmark_tag = "ship" - flags = SLANDMARK_FLAG_AUTOSET | SLANDMARK_FLAG_ZERO_G + flags = SLANDMARK_FLAG_AUTOSET | SLANDMARK_FLAG_ZERO_G | SLANDMARK_FLAG_REORIENT var/shuttle_name var/list/visitors // landmark -> visiting shuttle stationed there /obj/effect/shuttle_landmark/ship/Initialize(mapload, shuttle_name) - landmark_tag += "_[shuttle_name]" - src.shuttle_name = shuttle_name + if(!mapload) + landmark_tag += "_[shuttle_name]" + src.shuttle_name = shuttle_name + . = ..() + +/obj/effect/shuttle_landmark/ship/modify_mapped_vars(map_hash) . = ..() + ADJUST_TAG_VAR(shuttle_name, map_hash) /obj/effect/shuttle_landmark/ship/Destroy() - var/obj/effect/overmap/visitable/ship/landable/ship = map_sectors["[z]"] + var/obj/effect/overmap/visitable/ship/landable/ship = global.overmap_sectors[z] if(istype(ship) && ship.landmark == src) ship.landmark = null . = ..() @@ -95,6 +154,9 @@ if(LAZYLEN(visitors)) return "Cannot maneuver with other shuttles nearby." +/obj/effect/shuttle_landmark/ship/is_valid(datum/shuttle/shuttle) + return (shuttle.name == shuttle_name) && ..() + /obj/effect/shuttle_landmark/visiting_shuttle flags = SLANDMARK_FLAG_AUTOSET | SLANDMARK_FLAG_ZERO_G | SLANDMARK_FLAG_DISCONNECTED var/obj/effect/shuttle_landmark/ship/core_landmark @@ -103,11 +165,11 @@ core_landmark = master SetName(_name) landmark_tag = master.shuttle_name + _name - GLOB.destroyed_event.register(master, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/destroyed, master, src, TYPE_PROC_REF(/datum, qdel_self)) . = ..() /obj/effect/shuttle_landmark/visiting_shuttle/Destroy() - GLOB.destroyed_event.unregister(core_landmark, src) + events_repository.unregister(/decl/observ/destroyed, core_landmark, src) LAZYREMOVE(core_landmark.visitors, src) core_landmark = null . = ..() @@ -147,7 +209,7 @@ on_landing(from, into) /obj/effect/overmap/visitable/ship/landable/proc/on_landing(obj/effect/shuttle_landmark/from, obj/effect/shuttle_landmark/into) - var/obj/effect/overmap/visitable/target = map_sectors["[into.z]"] + var/obj/effect/overmap/visitable/target = global.overmap_sectors[into.z] var/datum/shuttle/shuttle_datum = SSshuttle.shuttles[shuttle] if(into.landmark_tag == shuttle_datum.motherdock) // If our motherdock is a landable ship, it won't be found properly here so we need to find it manually. for(var/obj/effect/overmap/visitable/ship/landable/landable in SSshuttle.ships) @@ -169,15 +231,129 @@ if(SHIP_STATUS_LANDED) var/obj/effect/overmap/visitable/location = loc if(istype(loc, /obj/effect/overmap/visitable/sector)) - return "Landed on \the [location.name]. Use secondary thrust to get clear before activating primary engines." + return "Landed on \the [location]. Use secondary thrust to get clear before activating primary engines." if(istype(loc, /obj/effect/overmap/visitable/ship)) - return "Docked with \the [location.name]. Use secondary thrust to get clear before activating primary engines." + return "Docked with \the [location]. Use secondary thrust to get clear before activating primary engines." return "Docked with an unknown object." if(SHIP_STATUS_ENCOUNTER) var/datum/shuttle/autodock/overmap/child_shuttle = SSshuttle.shuttles[shuttle] - var/obj/effect/overmap/visitable/location = map_sectors["[child_shuttle.current_location.z]"] - return "Maneuvering nearby \the [location.name]." + var/obj/effect/overmap/visitable/location = global.overmap_sectors[child_shuttle.current_location.z] + return "Maneuvering nearby \the [location]." if(SHIP_STATUS_TRANSIT) return "Maneuvering under secondary thrust." if(SHIP_STATUS_OVERMAP) - return "In open space." \ No newline at end of file + return "In open space." + +// Creates a docking port spawner +/obj/abstract/docking_port_spawner + name = "docking port spawner" + icon = 'icons/effects/landmarks.dmi' + icon_state = "shuttle_landmark" + /// Used both to name the landing site and to set the landmark tag. + var/port_name = "docking port" + var/core_landmark_tag + var/docking_tag + +/obj/abstract/docking_port_spawner/modify_mapped_vars(map_hash) + . = ..() + ADJUST_TAG_VAR(core_landmark_tag, map_hash) + ADJUST_TAG_VAR(docking_tag, map_hash) + +/obj/abstract/docking_port_spawner/Initialize() + ..() + if(!core_landmark_tag) + PRINT_STACK_TRACE("Unset core_landmark_tag: [log_info_line(src)]") + return INITIALIZE_HINT_QDEL + return INITIALIZE_HINT_LATELOAD + +/obj/abstract/docking_port_spawner/LateInitialize() + var/obj/effect/shuttle_landmark/ship/core = SSshuttle.get_landmark(core_landmark_tag) + if(!core) + PRINT_STACK_TRACE("Unable to find shuttle landmark with tag [core_landmark_tag]") + qdel(src) + return + if(!core.shuttle_name || !SSshuttle.shuttles[core.shuttle_name]) + events_repository.register_global(/decl/observ/shuttle_added, src, PROC_REF(try_create_dock_for)) + else + create_dock(core) + +/obj/abstract/docking_port_spawner/proc/try_create_dock_for(shuttle) + var/obj/effect/shuttle_landmark/ship/new_core = SSshuttle.get_landmark(core_landmark_tag) + if(!new_core.shuttle_name || SSshuttle.shuttles[new_core.shuttle_name] != shuttle) + return // wait for the next shuttle to init + create_dock(new_core) + events_repository.unregister_global(/decl/observ/shuttle_added, src, PROC_REF(try_create_dock_for)) + +/obj/abstract/docking_port_spawner/proc/create_dock(obj/effect/shuttle_landmark/ship/core) + var/obj/effect/shuttle_landmark/visiting_shuttle/docking/docking_landmark = new (loc, core, port_name) + docking_landmark.docking_controller = SSshuttle.docking_registry[docking_tag] + docking_landmark.dir = dir + var/obj/effect/overmap/visitable/our_ship = SSshuttle.ship_by_shuttle(core.shuttle_name) + var/datum/shuttle/our_shuttle = SSshuttle.shuttles[core.shuttle_name] + our_ship.add_landmark(docking_landmark) + var/turf/match_turf = get_step(docking_landmark, docking_landmark.dir) + if(match_turf) + var/obj/abstract/local_dock/our_dock = new /obj/abstract/local_dock(match_turf, port_name) + our_dock.dir = turn(dir, 180) + our_dock.name = port_name + our_shuttle.add_port(our_dock) + qdel(src) + +/obj/effect/shuttle_landmark/visiting_shuttle/docking + name = "docking port" + flags = SLANDMARK_FLAG_AUTOSET | SLANDMARK_FLAG_ZERO_G | SLANDMARK_FLAG_REORIENT // not disconnected, they are physically attached + +/// Cannot actually be landed at. Used for alignment when landing or docking, however. +/obj/abstract/local_dock + name = "docking port" // Rename for subtypes/instances, this is shown to players. + icon = 'icons/effects/landmarks.dmi' + icon_state = "shuttle_landmark" + anchored = TRUE + simulated = FALSE + layer = ABOVE_PROJECTILE_LAYER + invisibility = INVISIBILITY_ABSTRACT + movable_flags = MOVABLE_FLAG_ALWAYS_SHUTTLEMOVE + is_spawnable_type = FALSE + var/reorient = TRUE + var/port_tag + /// The id_tag of the docking controller associated with this docking port. If null, disables docking when using this port. + var/dock_target + +/obj/abstract/local_dock/Initialize(ml, new_port_tag) + if(new_port_tag) + port_tag = new_port_tag + . = ..() + +/obj/abstract/local_dock/modify_mapped_vars(map_hash) + . = ..() + ADJUST_TAG_VAR(port_tag, map_hash) + ADJUST_TAG_VAR(dock_target, map_hash) + +/// This subtype automatically adds itself to its shuttle based on the shuttle_tag var. +/obj/abstract/local_dock/automatic + var/shuttle_tag + +/obj/abstract/local_dock/automatic/modify_mapped_vars(map_hash) + . = ..() + ADJUST_TAG_VAR(shuttle_tag, map_hash) + +/obj/abstract/local_dock/automatic/Initialize(ml, new_port_tag, new_shuttle_tag) + if(new_shuttle_tag) + shuttle_tag = new_shuttle_tag + . = ..() + if(!shuttle_tag) + CRASH("[type] created without a shuttle tag!") + var/datum/shuttle/our_shuttle = SSshuttle.shuttles[shuttle_tag] + if(!our_shuttle) + events_repository.register_global(/decl/observ/shuttle_added, src, PROC_REF(try_late_hookup)) + else + hookup(our_shuttle) + +/obj/abstract/local_dock/automatic/proc/try_late_hookup(datum/shuttle/shuttle) + if(shuttle.name != shuttle_tag) + return + events_repository.unregister_global(/decl/observ/shuttle_added, src, PROC_REF(hookup)) + hookup(shuttle) + +/obj/abstract/local_dock/automatic/proc/hookup(datum/shuttle/shuttle) + shuttle.add_port(src) \ No newline at end of file diff --git a/code/modules/overmap/ships/machines/bluespace_thruster.dm b/code/modules/overmap/ships/machines/bluespace_thruster.dm deleted file mode 100644 index bf2a4d06fb3e..000000000000 --- a/code/modules/overmap/ships/machines/bluespace_thruster.dm +++ /dev/null @@ -1,33 +0,0 @@ -/obj/machinery/zero_point_thruster - name = "zero-point propulsion device" - desc = "An advanced propulsion device, using energy and minutes amount of gas to generate thrust." - icon = 'icons/obj/ship_engine.dmi' - icon_state = "nozzle" - power_channel = ENVIRON - idle_power_usage = 100 - anchored = TRUE - construct_state = /decl/machine_construction/default/panel_closed - -/obj/machinery/zero_point_thruster/Initialize() - . = ..() - set_extension(src, /datum/extension/ship_engine/zero_point, "zero-point thruster") - var/datum/extension/ship_engine/engine = get_extension(src, /datum/extension/ship_engine) - engine.connect_to_ship() - -/obj/item/stock_parts/circuitboard/engine/zero_point - name = T_BOARD("zero-point propulsion device") - board_type = "machine" - icon_state = "mcontroller" - build_path = /obj/machinery/zero_point_thruster - origin_tech = "{'powerstorage':1,'engineering':2}" - req_components = list( - /obj/item/stack/cable_coil = 2, - /obj/item/stock_parts/matter_bin = 1, - /obj/item/stock_parts/capacitor = 2) - material = /decl/material/solid/metal/gold - matter = list( - /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE, - /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE - ) \ No newline at end of file diff --git a/code/modules/overmap/ships/machines/fusion_thruster.dm b/code/modules/overmap/ships/machines/fusion_thruster.dm index c146066d682a..f3da75287c27 100644 --- a/code/modules/overmap/ships/machines/fusion_thruster.dm +++ b/code/modules/overmap/ships/machines/fusion_thruster.dm @@ -1,42 +1,44 @@ /obj/machinery/atmospherics/unary/engine/fusion name = "fusion nozzle" - desc = "Simple rocket nozzle, expelling gas at hypersonic velocities to propell the ship." + desc = "Simple rocket nozzle, expelling gas at hypersonic velocities to propel the ship." - base_type = /obj/machinery/atmospherics/unary/engine - construct_state = /decl/machine_construction/default/panel_closed - maximum_component_parts = list(/obj/item/stock_parts = 8)//don't want too many, let upgraded component shine + base_type = /obj/machinery/atmospherics/unary/engine/fusion engine_extension = /datum/extension/ship_engine/gas/fusion - use_power = POWER_USE_OFF - power_channel = EQUIP idle_power_usage = 13600 var/initial_id_tag - var/obj/machinery/power/fusion_core/harvest_from + var/obj/machinery/fusion_core/harvest_from /obj/machinery/atmospherics/unary/engine/fusion/Initialize() - . = ..() - + ..() set_extension(src, /datum/extension/local_network_member) if(initial_id_tag) var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member) lanm.set_tag(null, initial_id_tag) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/atmospherics/unary/engine/fusion/LateInitialize() find_core() +/obj/machinery/atmospherics/unary/engine/fusion/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + /obj/machinery/atmospherics/unary/engine/fusion/proc/find_core() harvest_from = null var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member) var/datum/local_network/lan = lanm.get_local_network() - if(lan) - var/list/fusion_cores = lan.get_devices(/obj/machinery/power/fusion_core) - if(fusion_cores && fusion_cores.len) + if(lan) + var/list/fusion_cores = lan.get_devices(/obj/machinery/fusion_core) + if(LAZYLEN(fusion_cores)) harvest_from = fusion_cores[1] return harvest_from -/obj/machinery/atmospherics/unary/engine/fusion/attackby(var/obj/item/thing, var/mob/user) - if(isMultitool(thing)) +/obj/machinery/atmospherics/unary/engine/fusion/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member) if(lanm.get_new_tag(user)) find_core() - return + return TRUE return ..() \ No newline at end of file diff --git a/code/modules/overmap/ships/machines/gas_thruster.dm b/code/modules/overmap/ships/machines/gas_thruster.dm index 58a68d0d027e..67ea291ac16e 100644 --- a/code/modules/overmap/ships/machines/gas_thruster.dm +++ b/code/modules/overmap/ships/machines/gas_thruster.dm @@ -1,26 +1,48 @@ /obj/machinery/atmospherics/unary/engine name = "rocket nozzle" - desc = "Simple rocket nozzle, expelling gas at hypersonic velocities to propell the ship." + desc = "Simple rocket nozzle, expelling gas at hypersonic velocities to propel the ship." icon = 'icons/obj/ship_engine.dmi' icon_state = "nozzle" - opacity = 1 - density = 1 + layer = STRUCTURE_LAYER + opacity = TRUE + density = TRUE atmos_canpass = CANPASS_NEVER connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL - var/engine_extension = /datum/extension/ship_engine/gas construct_state = /decl/machine_construction/default/panel_closed maximum_component_parts = list(/obj/item/stock_parts = 8)//don't want too many, let upgraded component shine - + uncreated_component_parts = null + base_type = /obj/machinery/atmospherics/unary/engine use_power = POWER_USE_OFF power_channel = EQUIP - idle_power_usage = 11600 + idle_power_usage = 2320 + var/engine_extension = /datum/extension/ship_engine/gas /obj/machinery/atmospherics/unary/engine/Initialize() . = ..() update_nearby_tiles(need_rebuild=1) - set_extension(src, engine_extension, "propellant thruster") +/obj/machinery/atmospherics/unary/engine/on_update_icon() + cut_overlays() + if(operable()) + z_flags |= ZMM_MANGLE_PLANES + add_overlay(emissive_overlay(icon, "indicator_power")) + if(use_power) + add_overlay(emissive_overlay(icon, "nozzle_idle")) + else + z_flags &= ~ZMM_MANGLE_PLANES + +/obj/machinery/atmospherics/unary/engine/attackby(obj/item/used_item, mob/user) + if(IS_MULTITOOL(used_item) && !panel_open) + var/datum/extension/ship_engine/engine = get_extension(src, /datum/extension/ship_engine) + if(engine.sync_to_ship()) + to_chat(user, SPAN_NOTICE("\The [src] emits a ping as it syncs its controls to a nearby ship.")) + else + to_chat(user, SPAN_WARNING("\The [src] flashes an error!")) + return TRUE + + . = ..() + /obj/machinery/atmospherics/unary/engine/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) return 0 @@ -39,33 +61,32 @@ if(!E) return //allows them to upgrade the max limit of fuel intake (which only gives diminishing returns) for increase in max thrust but massive reduction in fuel economy - var/bin_upgrade = 10 * Clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 6)//5 litre per rank + var/bin_upgrade = 10 * clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 6)//5 litre per rank E.volume_per_burn = bin_upgrade ? initial(E.volume_per_burn) + bin_upgrade : 2 //Penalty missing part: 10% fuel use, no thrust E.boot_time = bin_upgrade ? initial(E.boot_time) - bin_upgrade : initial(E.boot_time) * 2 //energy cost - thb all of this is to limit the use of back up batteries - var/energy_upgrade = Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0.1, 6) + var/energy_upgrade = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0.1, 6) E.charge_per_burn = initial(E.charge_per_burn) / energy_upgrade change_power_consumption(initial(idle_power_usage) / energy_upgrade, POWER_USE_IDLE) //Exhaust effect /obj/effect/engine_exhaust name = "engine exhaust" - icon = 'icons/effects/effects.dmi' - icon_state = "smoke" - light_color = "#ed9200" - anchored = 1 + icon = 'icons/obj/ship_engine.dmi' + icon_state = "nozzle_burn" + light_color = "#00a2ff" + anchored = TRUE -/obj/effect/engine_exhaust/Initialize(mapload, var/ndir, var/flame) +/obj/effect/engine_exhaust/Initialize(mapload, ndir) . = ..(mapload) - if(flame) - icon_state = "exhaust" - if(isturf(loc)) - var/turf/T = loc - T.hotspot_expose(1000,125) - set_light(0.5, 1, 4) + if(isturf(loc)) + var/turf/T = loc + T.hotspot_expose(1000,125) + set_light(5, 2) set_dir(ndir) QDEL_IN(src, 2 SECONDS) +// This comes with an additional terminal component and tries to set it up on init (you should map a terminal beneath it). This is for mapping only. /obj/machinery/atmospherics/unary/engine/terminal - base_type = /obj/machinery/atmospherics/unary/engine - stock_part_presets = list(/decl/stock_part_preset/terminal_setup) + uncreated_component_parts = list(/obj/item/stock_parts/power/terminal/buildable) + stock_part_presets = list(/decl/stock_part_preset/terminal_connect) diff --git a/code/modules/overmap/ships/machines/ion_thruster.dm b/code/modules/overmap/ships/machines/ion_thruster.dm new file mode 100644 index 000000000000..e06e58e11d72 --- /dev/null +++ b/code/modules/overmap/ships/machines/ion_thruster.dm @@ -0,0 +1,96 @@ +/datum/extension/ship_engine/ion_thruster + expected_type = /obj/machinery/ion_thruster + +/datum/extension/ship_engine/ion_thruster/burn(var/partial = 1) + var/obj/machinery/ion_thruster/thruster = holder + if(istype(thruster) && thruster.get_thrust(partial)) + return get_exhaust_velocity() * thruster.thrust_effectiveness + return 0 + +/datum/extension/ship_engine/ion_thruster/get_exhaust_velocity() + . = 300 // Arbitrary value based on being slightly less than a default configuration gas engine. + +/datum/extension/ship_engine/ion_thruster/get_specific_wet_mass() + . = 1.5 // Arbitrary value based on being slightly less than a default configuration gas engine. + +/datum/extension/ship_engine/ion_thruster/has_fuel() + var/obj/machinery/ion_thruster/thruster = holder + . = istype(thruster) && !(thruster.stat & NOPOWER) + +/datum/extension/ship_engine/ion_thruster/get_status() + . = list() + . += ..() + var/obj/machinery/ion_thruster/thruster = holder + if(!istype(thruster)) + . += "Hardware failure - check machinery." + else if(thruster.stat & NOPOWER) + . += "Insufficient power or hardware offline." + else + . += "Online." + return jointext(.,"
    ") + +/obj/machinery/ion_thruster + name = "ion thruster" + desc = "An advanced propulsion device, using energy and minute amounts of gas to generate thrust." + icon = 'icons/obj/ship_engine.dmi' + icon_state = "nozzle2" + density = TRUE + power_channel = ENVIRON + idle_power_usage = 100 + anchored = TRUE + construct_state = /decl/machine_construction/default/panel_closed + use_power = POWER_USE_IDLE + + // TODO: modify these with upgraded parts? + var/thrust_limit = 1 + var/thrust_cost = 750 + var/thrust_effectiveness = 1 + +/obj/machinery/ion_thruster/attackby(obj/item/used_item, mob/user) + if(IS_MULTITOOL(used_item) && !panel_open) + var/datum/extension/ship_engine/engine = get_extension(src, /datum/extension/ship_engine) + if(engine.sync_to_ship()) + to_chat(user, SPAN_NOTICE("\The [src] emits a ping as it syncs its controls to a nearby ship.")) + else + to_chat(user, SPAN_WARNING("\The [src] flashes an error!")) + return TRUE + + . = ..() + +/obj/machinery/ion_thruster/proc/get_thrust() + if(use_power && !(stat & NOPOWER)) + use_power_oneoff(thrust_cost) + return thrust_limit + return 0 + +/obj/machinery/ion_thruster/on_update_icon() + cut_overlays() + if(!(stat & (NOPOWER | BROKEN))) + add_overlay(emissive_overlay(icon, "ion_glow")) + z_flags |= ZMM_MANGLE_PLANES + else + z_flags &= ~ZMM_MANGLE_PLANES + +/obj/machinery/ion_thruster/power_change() + . = ..() + queue_icon_update() + +/obj/machinery/ion_thruster/Initialize() + . = ..() + set_extension(src, /datum/extension/ship_engine/ion_thruster, "ion thruster") + +/obj/item/stock_parts/circuitboard/engine/ion + name = "circuitboard (ion thruster)" + board_type = "machine" + icon = 'icons/obj/modules/module_controller.dmi' + build_path = /obj/machinery/ion_thruster + origin_tech = @'{"powerstorage":1,"engineering":2}' + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/stock_parts/matter_bin = 1, + /obj/item/stock_parts/capacitor = 2) + matter = list( + /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE + ) diff --git a/code/modules/overmap/ships/ship.dm b/code/modules/overmap/ships/ship.dm index 9af903d8dcd5..133c506ffa63 100644 --- a/code/modules/overmap/ships/ship.dm +++ b/code/modules/overmap/ships/ship.dm @@ -1,4 +1,4 @@ -var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) +var/global/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) /obj/effect/overmap/visitable/ship name = "generic ship" @@ -6,6 +6,7 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) icon_state = "ship" requires_contact = TRUE can_move = TRUE + appearance_flags = TILE_BOUND | LONG_GLIDE var/moving_state = "ship_moving" @@ -18,11 +19,9 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) var/skill_needed = SKILL_ADEPT //piloting skill needed to steer it without going in random dir var/operator_skill - var/needs_dampers = FALSE - var/list/inertial_dampers = list() - var/damping_strength = null var/vessel_size = SHIP_SIZE_LARGE // arbitrary number, affects how likely are we to evade meteors + var/list/navigation_viewers // list of weakrefs to people viewing the overmap via this ship /obj/effect/overmap/visitable/ship/Initialize() . = ..() @@ -33,18 +32,16 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) base_sensor_visibility = round((vessel_mass/SENSOR_COEFFICENT),1) /obj/effect/overmap/visitable/ship/Destroy() - STOP_PROCESSING(SSobj, src) SSshuttle.ships -= src - if(LAZYLEN(consoles)) - for(var/obj/machinery/computer/ship/machine in consoles) - if(machine.linked == src) - machine.linked = null - consoles = null + for(var/thing in get_linked_machines_of_type(/obj/machinery/computer/ship)) + var/obj/machinery/computer/ship/machine = thing + if(machine.linked == src) + machine.linked = null . = ..() /obj/effect/overmap/visitable/ship/proc/set_thrust_limit(var/thrust_limit) for(var/datum/extension/ship_engine/E in engines) - E.thrust_limit = Clamp(thrust_limit, 0, 1) + E.thrust_limit = clamp(thrust_limit, 0, 1) /obj/effect/overmap/visitable/ship/proc/set_engine_power(var/engine_power) for(var/datum/extension/ship_engine/E in engines) @@ -58,33 +55,33 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) /obj/effect/overmap/visitable/ship/proc/get_thrust_limit() for(var/datum/extension/ship_engine/E in engines) - if(E.thrust_limit > 0 && E.thrust_limit < .) + if(E.thrust_limit > .) . = E.thrust_limit /obj/effect/overmap/visitable/ship/relaymove(mob/user, direction, accel_limit) - operator_skill = user.get_skill_value(SKILL_PILOT) + update_operator_skill(user) accelerate(direction, accel_limit) +/** + * Updates `operator_skill` to match the current user's skill level, or to null if no user is provided. + * Will skip observers to avoid allowing unintended external influences on flight. + */ +/obj/effect/overmap/visitable/ship/proc/update_operator_skill(mob/user) + if (isobserver(user)) + return + operator_skill = user?.get_skill_value(SKILL_PILOT) + /obj/effect/overmap/visitable/ship/get_scan_data(mob/user) . = ..() . += "
    Mass: [vessel_mass] tons." if(!is_still()) - . += "
    Heading: [dir2angle(get_heading())], speed [get_speed() * KM_OVERMAP_RATE]" + . += "
    Heading: [get_heading_angle()], speed [get_speed() * KM_OVERMAP_RATE]" if(instant_contact) . += "
    It is broadcasting a distress signal." /obj/effect/overmap/visitable/ship/adjust_speed(n_x, n_y) . = ..() - var/magnitude = norm(n_x, n_y) - var/inertia_dir = magnitude >= 0 ? turn(fore_dir, 180) : fore_dir - var/inertia_strength = magnitude * 1e3 - if(needs_dampers && damping_strength < inertia_strength) - var/list/areas_by_name = area_repository.get_areas_by_z_level() - for(var/area_name in areas_by_name) - var/area/A = areas_by_name[area_name] - if(area_belongs_to_zlevels(A, map_z)) - A.throw_unbuckled_occupants(inertia_strength+2, inertia_strength, inertia_dir) for(var/zz in map_z) if(is_still()) toggle_move_stars(zz) @@ -100,24 +97,27 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) return 0 if(!get_speed()) return 0 - var/num_burns = get_speed() / get_delta_v() + 2 //some padding in case acceleration drops fromm fuel usage - var/burns_per_grid = 1/ (burn_delay * get_speed()) + var/delta_v = get_delta_v() + 2 + if(delta_v <= 0) + return 0 + var/num_burns = get_speed() / delta_v //some padding in case acceleration drops fromm fuel usage + var/burns_per_grid = 1 / (burn_delay * get_speed()) + if(burns_per_grid <= 0) + return 0 return round(num_burns / burns_per_grid) -/obj/effect/overmap/visitable/ship/Process() - . = ..() - damping_strength = 0 - for(var/datum/ship_inertial_damper/I in inertial_dampers) - var/obj/machinery/inertial_damper/ID = I.holder - damping_strength += ID.get_damping_strength(TRUE) +/obj/effect/overmap/visitable/ship/Process(wait, tick) sensor_visibility = min(round(base_sensor_visibility + get_speed_sensor_increase(), 1), 100) /obj/effect/overmap/visitable/ship/on_update_icon() if(!is_still()) icon_state = moving_state - set_dir(get_heading()) + var/matrix/M = matrix() + M.Turn(get_heading_angle()) + transform = M else icon_state = initial(icon_state) + transform = null ..() @@ -143,11 +143,12 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) /obj/effect/overmap/visitable/ship/proc/halt() adjust_speed(-speed[1], -speed[2]) - halted = 1 + halted = TRUE /obj/effect/overmap/visitable/ship/proc/unhalt() if(!SSshuttle.overmap_halted) - halted = 0 + halted = FALSE + update_moving() /obj/effect/overmap/visitable/ship/Bump(var/atom/A) if(istype(A,/turf/unsimulated/map/edge)) @@ -161,12 +162,9 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) ..() for(var/obj/machinery/computer/ship/S in SSmachines.machinery) S.attempt_hook_up(src) - for(var/datum/extension/ship_engine/E in ship_engines) + for(var/datum/extension/ship_engine/E in global.ship_engines) if(check_ownership(E.holder)) engines |= E - for(var/datum/ship_inertial_damper/I in global.ship_inertial_dampers) - if(check_ownership(I.holder)) - inertial_dampers |= I var/v_mass = recalculate_vessel_mass() if(v_mass) vessel_mass = v_mass @@ -177,9 +175,6 @@ var/const/OVERMAP_SPEED_CONSTANT = (1 SECOND) /obj/effect/overmap/visitable/ship/proc/get_speed_sensor_increase() return min(get_speed() * 1000, 50) //Engines should never increase sensor visibility by more than 50. -/obj/effect/overmap/proc/get_vessel_mass() //Same as above. - return vessel_mass - #undef MOVING #undef SANITIZE_SPEED #undef CHANGE_SPEED_BY \ No newline at end of file diff --git a/code/modules/overmap/ships/ship_physics.dm b/code/modules/overmap/ships/ship_physics.dm index f5407af917dd..28e71cf1f5b1 100644 --- a/code/modules/overmap/ships/ship_physics.dm +++ b/code/modules/overmap/ships/ship_physics.dm @@ -5,7 +5,7 @@ // partial power is used with burn() in order to only do partial burns. /obj/effect/overmap/visitable/ship/get_delta_v(var/real_burn = FALSE, var/partial_power = 1) var/total_exhaust_velocity = 0 - partial_power = Clamp(partial_power, 0, 1) + partial_power = clamp(partial_power, 0, 1) for(var/datum/extension/ship_engine/E in engines) total_exhaust_velocity += real_burn ? E.burn(partial_power) : E.get_exhaust_velocity() var/vessel_mass = get_vessel_mass() @@ -36,23 +36,43 @@ /obj/effect/overmap/visitable/ship/proc/recalculate_vessel_mass() var/list/zones = list() + // for(var/turf/tile in area) is an implied in-world loop + // an in-world loop per area is very bad, so instead + // we do one in-world loop and check area + var/list/areas = list() + // create an associative list of area -> TRUE so that lookup is faster for(var/area/A in get_areas()) - for(var/turf/simulated/T in A) - if(istype(T, /turf/simulated/open)) + if(istype(A, world.area)) // exclude the base area + continue + areas[A] = TRUE + var/start_z = min(map_z) + var/end_z = max(map_z) + if(!start_z || !end_z) + return initial(vessel_mass) // This shouldn't happen ideally so just go with the initial vessel mass + for(var/z_level in start_z to end_z) + var/datum/level_data/z_data = SSmapping.levels_by_z[z_level] + for(var/turf/tile in block(z_data.level_inner_min_x, z_data.level_inner_min_y, z_level, z_data.level_inner_max_x, z_data.level_inner_max_y)) + var/area/tile_area = tile.loc + if(!tile_area || !areas[tile_area]) + continue + + if(!tile.simulated || tile.is_open()) continue . += DEFAULT_TURF_MASS - if(istype(T, /turf/simulated/wall)) - var/turf/simulated/wall/W = T - if(W.material) - . += W.material.weight * 5 - if(W.reinf_material) - . += W.reinf_material.weight * 5 - if(W.girder_material) - . += W.girder_material.weight * 5 + if(istype(tile, /turf/wall)) + var/turf/wall/wall_tile = tile + if(wall_tile.material) + . += wall_tile.material.weight * 5 + if(wall_tile.reinf_material) + . += wall_tile.reinf_material.weight * 5 + if(wall_tile.girder_material) + . += wall_tile.girder_material.weight * 5 + + if(tile.zone) + zones[tile.zone] = TRUE // assoc list for fast deduplication - zones |= T.zone - for(var/atom/movable/C in T) + for(var/atom/movable/C as anything in tile) // as anything is safe here since only movables can be in turf contents if(!C.simulated) continue . += C.get_mass() @@ -61,8 +81,9 @@ continue . += C2.get_mass() - for(var/zone/Z in zones) - . += Z.air.get_mass() + // loop over keys of all zones in the list + for(var/zone/zone as anything in zones) + . += zone.air.get_mass() // Convert kilograms to metric tonnes. . = . / 1000 \ No newline at end of file diff --git a/code/modules/overmap/spacetravel.dm b/code/modules/overmap/spacetravel.dm index c3e1884fc8ed..24747a3d46f6 100644 --- a/code/modules/overmap/spacetravel.dm +++ b/code/modules/overmap/spacetravel.dm @@ -1,115 +1,47 @@ -//list used to cache empty zlevels to avoid nedless map bloat -var/list/cached_space = list() - //Space stragglers go here - /obj/effect/overmap/visitable/sector/temporary name = "Deep Space" - invisibility = 101 + invisibility = INVISIBILITY_ABSTRACT sector_flags = OVERMAP_SECTOR_IN_SPACE /obj/effect/overmap/visitable/sector/temporary/Initialize(mapload, var/nx, var/ny, var/nz) - var/start_loc = locate(1, 1, nz) // This will be moved to the overmap in ..(), but must start on this z level for init to function. + var/start_loc = locate(nx, ny, nz) forceMove(start_loc) start_x = nx // This is overmap position start_y = ny - testing("Temporary sector at [x],[y] was created, corresponding zlevel is [nz].") . = ..() + if(. != INITIALIZE_HINT_QDEL) + testing("Temporary sector at [x],[y],[z] was created, corresponding zlevel is [nz].") /obj/effect/overmap/visitable/sector/temporary/Destroy() + for(var/num in map_z) - map_sectors["[num]"] = null - testing("Temporary sector at [x],[y] was deleted.") + global.overmap_sectors -= "[num]" + + var/datum/overmap/overmap = global.overmaps_by_z[num2text(z)] + if(istype(overmap)) + overmap.discard_temporary_sector(src) + + testing("Temporary sector at [x],[y],[z] was deleted.") + return ..() /obj/effect/overmap/visitable/sector/temporary/proc/can_die(var/mob/observer) testing("Checking if sector at [map_z[1]] can die.") - for(var/mob/M in GLOB.player_list) + for(var/mob/M in global.player_list) if(M != observer && (M.z in map_z)) testing("There are people on it.") return 0 return 1 -proc/get_deepspace(x,y) - var/obj/effect/overmap/visitable/sector/temporary/res = locate(x,y,GLOB.using_map.overmap_z) - if(istype(res)) - return res - else if(cached_space.len) - res = cached_space[cached_space.len] - cached_space -= res - res.forceMove(locate(x, y, GLOB.using_map.overmap_z)) - return res - else - return new /obj/effect/overmap/visitable/sector/temporary(null, x, y, GLOB.using_map.get_empty_zlevel()) - -/atom/movable/proc/lost_in_space() +/atom/movable/proc/overmap_can_discard() for(var/atom/movable/AM in contents) - if(!AM.lost_in_space()) + if(!AM.overmap_can_discard()) return FALSE return TRUE -/mob/lost_in_space() +/mob/overmap_can_discard() return isnull(client) -/mob/living/carbon/human/lost_in_space() +/mob/living/human/overmap_can_discard() return isnull(client) && (!last_ckey || stat == DEAD) - -proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A) - if (!T || !A) - return - - var/obj/effect/overmap/visitable/M = map_sectors["[T.z]"] - if (!M) - return - - if(A.lost_in_space()) - if(!QDELETED(A)) - qdel(A) - return - - var/nx = 1 - var/ny = 1 - var/nz = 1 - - if(T.x <= TRANSITIONEDGE) - nx = world.maxx - TRANSITIONEDGE - 2 - ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (A.x >= (world.maxx - TRANSITIONEDGE - 1)) - nx = TRANSITIONEDGE + 2 - ny = rand(TRANSITIONEDGE + 2, world.maxy - TRANSITIONEDGE - 2) - - else if (T.y <= TRANSITIONEDGE) - ny = world.maxy - TRANSITIONEDGE -2 - nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - else if (A.y >= (world.maxy - TRANSITIONEDGE - 1)) - ny = TRANSITIONEDGE + 2 - nx = rand(TRANSITIONEDGE + 2, world.maxx - TRANSITIONEDGE - 2) - - testing("[A] spacemoving from [M] ([M.x], [M.y]).") - - var/turf/map = locate(M.x,M.y,GLOB.using_map.overmap_z) - var/obj/effect/overmap/visitable/TM - for(var/obj/effect/overmap/visitable/O in map) - if(O != M && (O.sector_flags & OVERMAP_SECTOR_IN_SPACE) && prob(50)) - TM = O - break - if(!TM) - TM = get_deepspace(M.x,M.y) - nz = pick(TM.map_z) - - var/turf/dest = locate(nx,ny,nz) - if(dest && !dest.density) - A.forceMove(dest) - if(isliving(A)) - var/mob/living/L = A - for(var/obj/item/grab/G in L.get_active_grabs()) - G.affecting.forceMove(dest) - - if(istype(M, /obj/effect/overmap/visitable/sector/temporary)) - var/obj/effect/overmap/visitable/sector/temporary/source = M - if (source.can_die()) - testing("Caching [M] for future use") - source.forceMove(null) - cached_space += source diff --git a/code/modules/paperwork/_paper.dm b/code/modules/paperwork/_paper.dm new file mode 100644 index 000000000000..af411daf7cd4 --- /dev/null +++ b/code/modules/paperwork/_paper.dm @@ -0,0 +1,645 @@ +// large amount of fields creates a heavy load on the server, see updateinfolinks() and addtofield() +#define MAX_FIELDS 50 + +/* + * Paper + * also scraps of paper + */ +/obj/item/paper + name = "sheet of paper" + icon = 'icons/obj/items/paperwork/paper.dmi' + icon_state = ICON_STATE_WORLD + layer = ABOVE_OBJ_LAYER + slot_flags = SLOT_HEAD + body_parts_covered = SLOT_HEAD + randpixel = 8 + throw_range = 1 + throw_speed = 1 + w_class = ITEM_SIZE_TINY + attack_verb = "bapped" + material = /decl/material/solid/organic/paper + drop_sound = 'sound/foley/paperpickup1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + item_flags = ITEM_FLAG_CAN_TAPE + //#TODO: Fonts probably should be stored in the pens or something? + var/tmp/deffont = PEN_FONT_DEFAULT + var/tmp/signfont = PEN_FONT_SIGNATURE + var/tmp/crayonfont = PEN_FONT_CRAYON + var/tmp/fancyfont = PEN_FONT_FANCY_PEN + var/scan_file_type = /datum/computer_file/data/text + var/persist_on_init = TRUE + var/age = 0 + var/fields = 0 // Amount of user created fields + var/free_space = MAX_PAPER_MESSAGE_LEN + var/rigged = FALSE + var/tmp/is_honking = FALSE + var/is_crumpled = FALSE //Whether the paper is currently crumpled + var/info // What's actually written on the paper. + var/info_links // A different version of the paper which includes html links at fields and EOF (aka the "write" link) + var/stamp_text // The (text for the) stamps on the paper. + var/list/metadata + var/list/applied_stamps //List of stamp overlays. + var/last_modified_ckey + +/obj/item/paper/Initialize(mapload, material_key, var/_text, var/_title, var/list/md = null) + . = ..(mapload, material_key) + set_content(_text ? _text : info, _title ? _title : name) + if(md) + LAZYDISTINCTADD(metadata, md) //Merge them + if(!mapload && persist_on_init) + SSpersistence.track_value(src, /decl/persistence_handler/paper) + +/obj/item/paper/GetCloneArgs() + return list(null, material?.type, info, name) + +/obj/item/paper/PopulateClone(obj/item/paper/clone) + clone = ..() + clone.fields = fields + clone.last_modified_ckey = last_modified_ckey + clone.rigged = rigged + clone.is_crumpled = is_crumpled + clone.stamp_text = stamp_text + clone.applied_stamps = LAZYLEN(applied_stamps)? listDeepClone(applied_stamps) : null + clone.metadata = LAZYLEN(metadata)? listDeepClone(metadata, TRUE) : null + return clone + +/obj/item/paper/Clone() + var/obj/item/paper/clone = ..() + if(clone) + clone.updateinfolinks() + return clone + +/obj/item/paper/get_matter_amount_modifier() + return 0.2 + +/obj/item/paper/proc/set_content(text,title) + if(title) + SetName(title) + info = html_encode(text) + info = parsepencode(text) + update_icon() + update_space(info) + updateinfolinks() + updateUsrDialog() + +/obj/item/paper/on_update_icon() + . = ..() + + icon_state = get_world_inventory_state() + if(is_crumpled) + icon_state = "[icon_state]-scrap" + else + update_contents_overlays() + //The appearence is the key, the type is the value + for(var/image/key in applied_stamps) + add_overlay(key) + + // Update clipboard/paper bundle. + if(istype(loc, /obj/item/clipboard) || istype(loc, /obj/item/paper_bundle)) + compile_overlays() + loc.update_icon() + +/**Applies the overlay displayed when the paper contains some text. */ +/obj/item/paper/proc/update_contents_overlays() + if(length(info)) + var/words_state = "[icon_state]-words" + if(check_state_in_icon(words_state, icon)) + add_overlay(words_state) + +/obj/item/paper/proc/update_space(var/new_text) + if(new_text) + free_space -= length(strip_html_properly(new_text)) + +/obj/item/paper/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(name != initial(name)) + . += "It's titled '[name]'." + +/obj/item/paper/examined_by(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + interact(user, readonly = TRUE) + else + to_chat(user, SPAN_NOTICE("You have to go closer if you want to read it.")) + +/obj/item/paper/interact(mob/user, forceshow, readonly, admin_interact = FALSE) + var/show_info = readonly ? info : info_links + if(!admin_interact) + show_info = user.handle_reading_literacy(user, show_info, FALSE, (forceshow || get_dist(src, user) <= 1)) + if(show_info) + user.set_machine(src) + show_browser(user, "[name][show_info][stamp_text]", "window=[name]") + onclose(user, "[name]") + return TRUE + +/obj/item/paper/attack_self(mob/user) + if(user.check_intent(I_FLAG_HARM)) + if(is_crumpled) + user.show_message(SPAN_WARNING("\The [src] is already crumpled.")) + return + //crumple dat paper + crumple() + user.visible_message("\The [user] crumples \the [src] into a ball!") + return TRUE + + interact(user, readonly = FALSE) //Allow us writing on paper since we're holding it somwhere + + if(rigged && (global.current_holiday?.name == "April Fool's Day")) + if(!is_honking) + is_honking = TRUE + playsound(loc, 'sound/items/bikehorn.ogg', 50, TRUE) + spawn(20) + is_honking = FALSE + return TRUE + +/obj/item/paper/attack_ai(mob/living/silicon/ai/user) + interact(user, readonly = TRUE) + return TRUE + +/obj/item/paper/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + var/target_zone = user.get_target_zone() + if(target_zone == BP_EYES) + user.visible_message( + SPAN_NOTICE("You show the paper to [target]."), + SPAN_NOTICE("[user] holds up a paper and shows it to [target].") + ) + target.examine_verb(src) + return TRUE + + target_zone = check_zone(target_zone) + if(target.get_organ_sprite_accessory_by_category(SAC_COSMETICS, target_zone)) + if(target == user) + to_chat(user, SPAN_NOTICE("You wipe off the makeup with [src].")) + target.set_organ_sprite_accessory_by_category(null, SAC_COSMETICS, null, FALSE, FALSE, target_zone, FALSE) + return TRUE + user.visible_message( + SPAN_NOTICE("\The [user] begins to wipe \the [target]'s makeup off with \the [src]."), + SPAN_NOTICE("You begin to wipe off [target]'s makeup .") + ) + if(do_after(user, 10, target) && do_after(target, 10, check_holding = 0)) //user needs to keep their active hand, H does not. + user.visible_message( + SPAN_NOTICE("\The [user] wipes \the [target]'s makeup off with \the [src]."), + SPAN_NOTICE("You wipe off \the [target]'s makeup .") + ) + target.set_organ_sprite_accessory_by_category(null, SAC_COSMETICS, null, FALSE, FALSE, target_zone, FALSE) + return TRUE + + . = ..() + +/obj/item/paper/proc/addtofield(var/id, var/text, var/links = 0) + var/locid = 0 + var/laststart = 1 + var/textindex = 1 + while(locid < MAX_FIELDS) + var/istart = 0 + if(links) + istart = findtext_char(info_links, "", laststart) + else + istart = findtext_char(info, "", laststart) + + if(istart==0) + return // No field found with matching id + + laststart = istart+1 + locid++ + if(locid == id) + var/iend = 1 + if(links) + iend = findtext_char(info_links, "", istart) + else + iend = findtext_char(info, "", istart) + + textindex = iend + break + + if(links) + var/before = copytext_char(info_links, 1, textindex) + var/after = copytext_char(info_links, textindex) + info_links = before + text + after + else + var/before = copytext_char(info, 1, textindex) + var/after = copytext_char(info, textindex) + info = before + text + after + updateinfolinks() + +/obj/item/paper/proc/updateinfolinks() + info_links = info + var/i = 0 + for(i=1,i<=fields,i++) + addtofield(i, "write", 1) + info_links = info_links + "write" + +/obj/item/paper/proc/clearpaper() + info = null + stamp_text = null + free_space = MAX_PAPER_MESSAGE_LEN + LAZYCLEARLIST(applied_stamps) + is_crumpled = FALSE + updateinfolinks() + update_icon() + +/obj/item/paper/proc/get_signature(var/obj/item/pen/pen, mob/user) + if(pen && IS_PEN(pen)) + var/decl/tool_archetype/pen/parch = GET_DECL(TOOL_PEN) + return parch.get_signature(user, pen) + return (user && user.real_name) ? user.real_name : "Anonymous" + +/obj/item/paper/proc/parsepencode(t, obj/item/pen/pen, mob/user, iscrayon, isfancy) + if(length(t) == 0) + return "" + + if(findtext(t, "\[sign\]")) + t = replacetext(t, "\[sign\]", "[get_signature(pen, user)]") + + if(iscrayon) // If it is a crayon, and he still tries to use these, make them empty! + t = replacetext(t, "\[*\]", "") + t = replacetext(t, "\[hr\]", "") + t = replacetext(t, "\[small\]", "") + t = replacetext(t, "\[/small\]", "") + t = replacetext(t, "\[list\]", "") + t = replacetext(t, "\[/list\]", "") + t = replacetext(t, "\[table\]", "") + t = replacetext(t, "\[/table\]", "") + t = replacetext(t, "\[row\]", "") + t = replacetext(t, "\[cell\]", "") + t = replacetext(t, "\[logo\]", "") + + var/pen_color = pen ? pen.get_tool_property(TOOL_PEN, TOOL_PROP_COLOR) : "black" + if(iscrayon) + t = "[t]" + else if(isfancy) + t = "[t]" + else + t = "[t]" + + t = pencode2html(t) + + //Count the fields + var/laststart = 1 + while(fields < MAX_FIELDS) + var/i = findtext(t, "", laststart) // + if(i==0) + break + laststart = i+1 + fields++ + + return t + +/obj/item/paper/proc/burnpaper(obj/item/paper, mob/user) + var/class = "warning" + + if(paper.isflamesource() && !user.restrained()) + if(istype(paper, /obj/item/flame/fuelled/lighter/zippo)) + class = "rose" + + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message("[user] holds \the [paper] up to \the [src], it looks like [pronouns.he] [pronouns.is] trying to burn it!", \ + "You hold \the [paper] up to \the [src], burning it slowly.") + + spawn(20) + if(get_dist(src, user) < 2 && user.get_active_held_item() == paper && paper.isflamesource()) + user.visible_message("[user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + + new /obj/effect/decal/cleanable/ash(get_turf(src)) + qdel(src) + + else + to_chat(user, SPAN_WARNING("You must hold \the [paper] steady to burn \the [src].")) + +/obj/item/paper/CouldNotUseTopic(mob/user) + to_chat(user, SPAN_WARNING("You can't reach!")) + +/obj/item/paper/OnTopic(mob/user, href_list, datum/topic_state/state) + + if(href_list["write"]) + var/id = href_list["write"] + if(free_space <= 0) + to_chat(user, SPAN_INFO("There isn't enough space left on \the [src] to write anything.")) + return TOPIC_NOACTION + + //Try to find a usable pen on the user, if not abort + var/obj/item/I = user.get_accessible_pen() + if(!IS_PEN(I)) + to_chat(user, SPAN_WARNING("You need something to write with!")) + return TOPIC_NOACTION + + //If we got a pen that's not in our hands, make sure to move it over + if(user.get_active_held_item() != I && user.get_empty_hand_slot() && user.put_in_hands(I)) + to_chat(user, SPAN_NOTICE("You grab your trusty [I.name]!")) + else if(user.get_active_held_item() != I) + to_chat(user, SPAN_WARNING("You'd use your trusty [I.name], but your hands are full!")) + return TOPIC_NOACTION + + var/pen_flags = I.get_tool_property(TOOL_PEN, TOOL_PROP_PEN_FLAG) + var/decl/tool_archetype/pen/parch = GET_DECL(TOOL_PEN) + if(!(pen_flags & PEN_FLAG_ACTIVE)) + parch.toggle_active(user, I) + var/iscrayon = pen_flags & PEN_FLAG_CRAYON + var/isfancy = pen_flags & PEN_FLAG_FANCY + + var/t = sanitize(input("Enter what you want to write:", "Write", null, null) as message, free_space, extra = 0, trim = 0) + if(!t) + return TOPIC_NOACTION + + var/last_fields_value = fields + t = parsepencode(t, I, user, iscrayon, isfancy) // Encode everything from pencode to html + + if(fields > MAX_FIELDS) + to_chat(user, SPAN_WARNING("Too many fields. Sorry, you can't do this.")) + fields = last_fields_value + return TOPIC_NOACTION + + var/processed_text = user.handle_writing_literacy(user, t) + if(length(t)) + playsound(src, pick('sound/effects/pen1.ogg','sound/effects/pen2.ogg'), 30) + var/actual_characters = length_char(strip_html_properly(t)) + if(actual_characters > 0) + // 25 characters per charge, crayons get 30 charges + // we're really permissive here, we don't cut you short + // but we also use a charge even if you write <25 characters + if(parch.decrement_uses(user, I, max(round(actual_characters / 25, 1), 1)) <= 0) + parch.warn_out_of_ink(user, I) + + if(id!="end") + addtofield(text2num(id), processed_text) // He wants to edit a field, let him. + else + info += processed_text // Oh, he wants to edit to the end of the file, let him. + updateinfolinks() + + last_modified_ckey = user.ckey + update_space(t) + . = TOPIC_REFRESH + + if(. & TOPIC_REFRESH) + updateUsrDialog() + update_icon() + return + + return ..() + +/obj/item/paper/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/stack/tape_roll/duct_tape)) + var/obj/item/stack/tape_roll/duct_tape/tape = used_item + return tape.stick(src, user) + + else if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo)) + var/obj/item/paper_bundle/B = try_bundle_with(used_item, user) + if(!B) + return TRUE + user.put_in_hands(B) + to_chat(user, SPAN_NOTICE("You clip \the [used_item] and \the [name] together.")) + return TRUE + + else if(IS_PEN(used_item)) + if(is_crumpled) + to_chat(user, SPAN_WARNING("\The [src] is too crumpled to write on.")) + return TRUE + + var/obj/item/pen/robopen/RP = used_item + if ( istype(RP) && RP.mode == 2 ) + RP.RenamePaper(user,src) + else + interact(user, readonly = FALSE) + return TRUE + + else if(used_item.get_tool_quality(TOOL_STAMP)) + apply_custom_stamp(used_item.icon, "with \the [used_item]") + playsound(src, 'sound/effects/stamp.ogg', 50, TRUE) + to_chat(user, SPAN_NOTICE("You stamp the paper with your [used_item.name].")) + return TRUE + + else if(used_item.isflamesource()) + burnpaper(used_item, user) + return TRUE + + else if(istype(used_item, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = used_item + B.merge(src, user) + return TRUE + return ..() + +/obj/item/paper/proc/try_bundle_with(var/obj/item/paper/other, var/mob/user) + if(!can_bundle_with(other)) + if(user) + to_chat(user, SPAN_WARNING("You can't bundle those!")) + return + + var/obj/item/paper_bundle/B = new(loc) + if(user) + if(!user.can_unequip_item(src)) + to_chat(user, SPAN_WARNING("You can't unequip \the [src]!")) + return + if(!user.can_unequip_item(other)) + to_chat(user, SPAN_WARNING("You can't unequip \the [other]!")) + return + user.try_unequip(src, B) + user.try_unequip(other, B) + + if (name != initial(name)) + B.SetName(name) + else if (other.name != initial(other.name)) + B.SetName(other.name) + + B.insert_sheet_at(user, src) + B.insert_sheet_at(user, other) + return B + +/obj/item/paper/proc/can_bundle() + return TRUE + +/obj/item/paper/proc/can_bundle_with(var/obj/item/other) + if(istype(other, /obj/item/paper)) + var/obj/item/paper/paper = other + return can_bundle() && paper.can_bundle() + else if(istype(other, /obj/item/photo)) + return can_bundle() + else if(istype(other, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = other + return can_bundle() && !B.is_full() + return FALSE + +/obj/item/paper/DefaultTopicState() + return global.paper_topic_state + +/**Whether the paper can be considered blank, for purposes of refilling machines and etc. */ +/obj/item/paper/proc/is_blank() + return !length(info) && !length(stamp_text) && !is_crumpled && !LAZYLEN(applied_stamps) + +/**Stamp the paper with the specified values. + * stamper_name: what is stamped. Or what comes after the sentence "This paper has been stamped " +*/ +/obj/item/paper/proc/apply_custom_stamp(stamp_icon, stamper_name, offset_x, offset_y) + + if(!stamp_icon || !check_state_in_icon("stamp", stamp_icon)) + return + + var/image/stamp = overlay_image(stamp_icon, "stamp", COLOR_WHITE, RESET_COLOR) + + if(isnull(offset_x)) + stamp.pixel_x = rand(-2, 2) + else if(offset_x != 0) + stamp.pixel_x = offset_x + + if(isnull(offset_y)) + stamp.pixel_y = rand(-2, 2) + else if(offset_y != 0) + stamp.pixel_y = offset_y + + stamp.blend_mode = BLEND_INSET_OVERLAY + appearance_flags |= KEEP_TOGETHER + LAZYADD(applied_stamps, stamp) + stamp_text += "[length(stamp_text)? "
    " : "
    "]This paper has been stamped [length(stamper_name) ? stamper_name : "by the generic stamp"]." + update_icon() + +/**Merge the paper with other papers or bundles inside "location" */ +/obj/item/paper/proc/merge_with_existing(var/atom/location, var/mob/user) + if(!location || !can_bundle()) + return + for(var/obj/item/I in location) + if(istype(I, /obj/item/paper)) + return try_bundle_with(I, user) + + if(istype(I, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = I + if(B.is_full()) + continue + if(B.merge(src, user)) + return B + +/obj/item/paper/proc/crumple() + info = stars(info,85) + is_crumpled = TRUE + update_icon() + +/obj/item/paper/verb/rename() + set name = "Rename paper" + set category = "Object" + set src in usr + if(usr.incapacitated()) + to_chat(usr, SPAN_WARNING("You can't do that in your current state!")) + return + + if(usr.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) + to_chat(usr, SPAN_WARNING("You cut yourself on the paper.")) + return + var/n_name = sanitize_safe(input(usr, "What would you like to name the paper?", "Paper Naming", name) as text, MAX_NAME_LEN) + + // We check loc one level up, so we can rename in clipboards and such. See also: /obj/item/photo/rename() + if(!n_name || !CanInteract(usr, global.deep_inventory_topic_state)) + return + n_name = usr.handle_writing_literacy(usr, n_name) + if(n_name) + SetName(length(n_name) > 0? n_name : initial(name)) + add_fingerprint(usr) + +/obj/item/paper/dropped(mob/user) + . = ..() + if(CanUseTopic(user, DefaultTopicState())) + updateUsrDialog() + else + close_browser(user, name) + +// +//Topic state for paper since we can use it within clipboards and folders +// +var/global/datum/topic_state/default/paper_state/paper_topic_state = new +/datum/topic_state/default/paper_state/can_use_topic(var/src_object, var/mob/user) + . = ..() + if(. == STATUS_INTERACTIVE) + return + + //Check inside held objects + for(var/atom/movable/AM in user.get_held_items()) + if(src_object in AM) + return user.shared_nano_interaction() //Have to check this again, since we ignore all the distance stuff that was already done + +/////////////////////////////////////////////////// +// Paper Templates +/////////////////////////////////////////////////// +/obj/item/paper/manifest + name = "supply manifest" + metadata = list( + "order_total" = 0, + "is_copy" = TRUE, + ) + +/obj/item/paper/court + name = "Judgement" + info = "For crimes as specified, the offender is sentenced to:
    \n
    \n" + +/obj/item/paper/aromatherapy_disclaimer + name = "aromatherapy disclaimer" + info = "The manufacturer and the retailer make no claims of the contained products' effacy.

    Use at your own risk." + +/////////////////////////////////////////////////// +// Colored Paper +/////////////////////////////////////////////////// +/obj/item/paper/blue + name = "blue sheet of paper" + color = "#ccffff" + +/obj/item/paper/green + name = "green sheet of paper" + color = "#ccffaa" + +/obj/item/paper/yellow + name = "yellow sheet of paper" + color = "#ffffcc" + +/obj/item/paper/pink + name = "pink sheet of paper" + color = "#ffccff" + +/////////////////////////////////////////////////// +// Crumpled Paper +/////////////////////////////////////////////////// +/obj/item/paper/crumpled + name = "paper scrap" + is_crumpled = TRUE + +// Stub type for moving teleportation scrolls into a modpack. +/obj/item/paper/scroll + name = "scroll" + desc = "A length of writing material curled into a scroll." + icon = 'icons/obj/items/paperwork/scroll.dmi' + color = "#feeebc" + w_class = ITEM_SIZE_SMALL + var/furled = FALSE + +/obj/item/paper/scroll/can_bundle() + return FALSE + +/obj/item/paper/scroll/update_contents_overlays() + return furled ? null : ..() + +/obj/item/paper/scroll/on_update_icon() + . = ..() + if(furled) + icon_state = "[icon_state]-furled" + +/obj/item/paper/scroll/get_alt_interactions(mob/user) + . = ..() + if(furled) + LAZYADD(., /decl/interaction_handler/scroll/unfurl) + else + LAZYADD(., /decl/interaction_handler/scroll/furl) + +/decl/interaction_handler/scroll + abstract_type = /decl/interaction_handler/scroll + expected_target_type = /obj/item/paper/scroll + +/decl/interaction_handler/scroll/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/paper/scroll/scroll = target + // TODO: paper sound + scroll.furled = !scroll.furled + user.visible_message(SPAN_NOTICE("\The [user] [scroll.furled ? "furls" : "unfurls"] \the [target].")) + scroll.update_icon() + +/decl/interaction_handler/scroll/furl + name = "Furl Scroll" + examine_desc = "furl $TARGET_THEM$" + +/decl/interaction_handler/scroll/unfurl + name = "Unfurl Scroll" + examine_desc = "unfurl $TARGET_THEM$" diff --git a/code/modules/paperwork/_paper_serde.dm b/code/modules/paperwork/_paper_serde.dm new file mode 100644 index 000000000000..8fbfe734b9bb --- /dev/null +++ b/code/modules/paperwork/_paper_serde.dm @@ -0,0 +1,30 @@ +/obj/item/paper/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(age, /obj/item/paper) + SERIALIZE_IF_MODIFIED(is_crumpled, /obj/item/paper) + SERIALIZE_IF_MODIFIED(last_modified_ckey, /obj/item/paper) + SERIALIZE_IF_MODIFIED(name, /obj/item/paper) + SERIALIZE_IF_MODIFIED(info, /obj/item/paper) + +/obj/item/paper/Deserialize() + . = ..() + SSpersistence.track_value(src, /decl/persistence_handler/paper) + +/obj/item/paper/ShouldSerialize(_age) + return ..() && (isnull(_age) || age < _age) + +/obj/item/paper/GetPossiblySerializableInstances() + . = ..() + if(istype(loc, /obj/structure/noticeboard)) + LAZYDISTINCTADD(., loc) + +// If it's old enough we start to trim down any textual information and scramble strings. +#define SERDE_MESSAGE nameof(/obj/item/paper::info) +/obj/item/paper/HandlePersistentDecay(entries_decay_at, entry_decay_weight) + __deserialization_payload[SERDE_MESSAGE] = apply_serde_message_decay( + __deserialization_payload[SERDE_MESSAGE], + __deserialization_payload[nameof(/obj/item/paper::age)], + entry_decay_weight, + entries_decay_at + ) +#undef SERDE_MESSAGE diff --git a/code/modules/paperwork/adminpaper.dm b/code/modules/paperwork/adminpaper.dm index 4c06546f17c3..d886c4defe19 100644 --- a/code/modules/paperwork/adminpaper.dm +++ b/code/modules/paperwork/adminpaper.dm @@ -8,7 +8,7 @@ var/isCrayon = 0 var/origin = null var/mob/sender = null - var/obj/machinery/photocopier/faxmachine/destination + var/weakref/destination_ref var/header = null var/headerOn = TRUE @@ -16,28 +16,28 @@ var/footer = null var/footerOn = FALSE - var/logo_list = list() // Todo: Ivenmoth logo. + var/logo_list = list() var/logo = "" + var/signature //Signature entered by the admin -/obj/item/paper/admin/Initialize() +/obj/item/paper/admin/Initialize(mapload, material_key, _text, _title, list/md) . = ..() generateInteractions() - /obj/item/paper/admin/proc/generateInteractions() //clear first interactions = null //Snapshot is crazy and likes putting each topic hyperlink on a seperate line from any other tags so it's nice and clean. interactions += "
    The fax will transmit everything above this line
    " - interactions += "Send fax " - interactions += "Pen mode: [isCrayon ? "Crayon" : "Pen"] " - interactions += "Cancel fax " + interactions += "Send fax " + interactions += "Pen mode: [isCrayon ? "Crayon" : "Pen"] " + interactions += "Cancel fax " interactions += "
    " - interactions += "Change logo " - interactions += "Toggle Header " - interactions += "Toggle Footer " - interactions += "Clear page " + interactions += "Change logo " + interactions += "Toggle Header " + interactions += "Toggle Footer " + interactions += "Clear page " interactions += "
    " /obj/item/paper/admin/proc/generateHeader() @@ -57,23 +57,20 @@ text = "
    " text += "This transmission is intended only for the addressee and may contain confidential information. Any unauthorized disclosure is strictly prohibited.

    " - text += "If this transmission is recieved in error, please notify both the sender and the office of [GLOB.using_map.boss_name] Internal Affairs immediately so that corrective action may be taken." + text += "If this transmission is received in error, please notify both the sender and the office of [global.using_map.boss_name] Internal Affairs immediately so that corrective action may be taken." text += "Failure to comply is a breach of regulation and may be prosecuted to the fullest extent of the law, where applicable." text += "
    " footer = text - /obj/item/paper/admin/proc/adminbrowse() updateinfolinks() generateHeader() generateFooter() updateDisplay() -obj/item/paper/admin/proc/updateDisplay() - show_browser(usr, "[name][headerOn ? header : ""][info_links][stamps][footerOn ? footer : ""][interactions]", "window=[name];can_close=0") - - +/obj/item/paper/admin/proc/updateDisplay() + show_browser(usr, "[name][headerOn ? header : ""][info_links][stamp_text][footerOn ? footer : ""][interactions]", "window=[name];can_close=0") /obj/item/paper/admin/Topic(href, href_list) if(href_list["write"]) @@ -113,6 +110,10 @@ obj/item/paper/admin/proc/updateDisplay() return if(href_list["confirm"]) + var/obj/machinery/faxmachine/F = destination_ref.resolve() + if(!istype(F)) + to_chat(usr, "The destination machine doesn't exist anymore.") + return switch(alert("Are you sure you want to send the fax as is?",, "Yes", "No")) if("Yes") if(headerOn) @@ -121,7 +122,7 @@ obj/item/paper/admin/proc/updateDisplay() info += footer updateinfolinks() close_browser(usr, "window=[name]") - admindatum.faxCallback(src, destination) + admindatum.faxCallback(src, F) return if(href_list["penmode"]) @@ -156,5 +157,8 @@ obj/item/paper/admin/proc/updateDisplay() updateDisplay() return -/obj/item/paper/admin/get_signature() - return input(usr, "Enter the name you wish to sign the paper with (will prompt for multiple entries, in order of entry)", "Signature") as text|null \ No newline at end of file +/obj/item/paper/admin/get_signature(obj/item/pen/P, mob/user) + return signature + +/obj/item/paper/admin/proc/set_signature(var/sig) + signature = sig \ No newline at end of file diff --git a/code/modules/paperwork/bodyscan_paper.dm b/code/modules/paperwork/bodyscan_paper.dm index b6fd84bc3edd..30784f9b5d14 100644 --- a/code/modules/paperwork/bodyscan_paper.dm +++ b/code/modules/paperwork/bodyscan_paper.dm @@ -2,10 +2,6 @@ color = COLOR_OFF_WHITE scan_file_type = /datum/computer_file/data/bodyscan -/obj/item/paper/bodyscan/examine(mob/user) - set_content(display_medical_data(metadata, user.get_skill_value(SKILL_MEDICAL), TRUE)) - . = ..() - -/obj/item/paper/bodyscan/show_info(var/mob/user) +/obj/item/paper/bodyscan/interact(mob/user, forceshow, readonly, admin_interact = FALSE) set_content(display_medical_data(metadata, user.get_skill_value(SKILL_MEDICAL), TRUE)) . = ..() \ No newline at end of file diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm index b748c8dcbddc..5991f75c6c49 100644 --- a/code/modules/paperwork/carbonpaper.dm +++ b/code/modules/paperwork/carbonpaper.dm @@ -1,52 +1,63 @@ +///////////////////////////////////////////////// +// Carbon paper +///////////////////////////////////////////////// /obj/item/paper/carbon - name = "sheet of paper" - icon_state = "paper_stack" - item_state = "paper" - var/copied = 0 - var/iscopy = 0 - - -/obj/item/paper/carbon/on_update_icon() - if(iscopy) - if(info) - icon_state = "cpaper_words" - return - icon_state = "cpaper" - else if (copied) - if(info) - icon_state = "paper_words" - return - icon_state = "paper" - else - if(info) - icon_state = "paper_stack_words" - return - icon_state = "paper_stack" - - - -/obj/item/paper/carbon/verb/removecopy() - set name = "Remove carbon-copy" - set category = "Object" - set src in usr - - if (copied == 0) - var/obj/item/paper/carbon/c = src - var/copycontents = html_decode(c.info) - var/obj/item/paper/carbon/copy = new /obj/item/paper/carbon (usr.loc) - // - if(info) - copycontents = replacetext(copycontents, "" - copy.SetName("Copy - " + c.name) - copy.fields = c.fields - copy.updateinfolinks() - to_chat(usr, "You tear off the carbon-copy!") - c.copied = 1 - copy.iscopy = 1 - copy.update_icon() - c.update_icon() - else - to_chat(usr, "There are no more carbon copies attached to this paper!") + name = "sheets of paper with carbon paper" + icon = 'icons/obj/items/paperwork/carbon_paper.dmi' + +/obj/item/paper/carbon/proc/remove_copy(var/mob/user) + //Make a new paper that copies our contents + var/obj/item/paper/original = copy_to(new /obj/item/paper) + var/obj/item/paper/copy = original.Clone() + LAZYSET(copy.metadata, "is_copy", TRUE) + copy.set_color("#ffccff") + + //Make all stamps on the copy be grayscale + for(var/image/stamp in copy.applied_stamps) + stamp.filters += filter(type = "color", color = list(1,0,0, 0,0,0, 0,0,1), space = FILTER_COLOR_HSV) + stamp.appearance_flags |= RESET_COLOR + + //Silly hack to make all the text grayscale, since nobody is using standard css classes for pens we could override instead. Also, all using deprecated tags as well. + var/copycontents = copy.info + copycontents = replacetext(copycontents, "[copycontents]", (original.name != initial(original.name))? "Copy - [original.name]" : null) + original.update_icon() + + qdel(src) + user.put_in_active_hand(original) + user.put_in_hands(copy) + return copy + +///Copy our contents to a regular sheet of paper +/obj/item/paper/carbon/proc/copy_to(var/obj/item/paper/other) + //Don't copy the default name of the carbon paper + if(name != initial(name)) + other.SetName(name) + other.fields = fields + other.last_modified_ckey = last_modified_ckey + other.free_space = free_space + other.rigged = rigged + other.is_crumpled = is_crumpled + other.info = info + other.stamp_text = stamp_text + other.applied_stamps = LAZYLEN(applied_stamps)? listDeepClone(applied_stamps) : null + other.metadata = LAZYLEN(metadata)? listDeepClone(metadata, TRUE) : null + other.updateinfolinks() + return other + +/obj/item/paper/carbon/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/carbon_paper_remove) + +///////////////////////////////////////////////// +// Carbon Paper Alt Interactions +///////////////////////////////////////////////// +/decl/interaction_handler/carbon_paper_remove + name = "Remove Carbon-Copy" + expected_target_type = /obj/item/paper/carbon + examine_desc = "remove the carbon-copy" + +/decl/interaction_handler/carbon_paper_remove/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/paper/carbon/paper = target + paper.remove_copy(user) diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index c572f50dfa3f..c3f87b29d4d9 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -1,195 +1,228 @@ /obj/item/clipboard - name = "clipboard" - desc = "It's a board with a clip used to organise papers." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "clipboard" - item_state = "clipboard" - throwforce = 0 - w_class = ITEM_SIZE_SMALL - throw_speed = 3 - throw_range = 10 - var/obj/item/pen/haspen //The stored pen. - var/obj/item/toppaper //The topmost piece of paper. - slot_flags = SLOT_BELT - material = /decl/material/solid/wood - applies_material_name = FALSE - material = /decl/material/solid/wood - -/obj/item/clipboard/Initialize() + name = "clipboard" + desc = "It's a board with a clip used to organise papers." + icon = 'icons/obj/items/clipboard.dmi' + icon_state = "clipboard" + item_state = "clipboard" + w_class = ITEM_SIZE_SMALL + throw_speed = 3 + throw_range = 10 + slot_flags = SLOT_LOWER_BODY + material_alteration = MAT_FLAG_ALTERATION_COLOR + material = /decl/material/solid/organic/wood/oak + drop_sound = 'sound/foley/tooldrop5.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + + var/obj/item/stored_pen //The stored pen. + var/list/papers + var/tmp/max_papers = 50 + +/obj/item/clipboard/Initialize(ml, material_key) . = ..() update_icon() - if(material) - desc = initial(desc) - desc += " It's made of [material.use_name]." - -/obj/item/clipboard/MouseDrop(obj/over_object) //Quick clipboard fix. -Agouri - if(ishuman(usr)) - var/mob/M = usr - if(!(istype(over_object, /obj/screen) )) - return ..() - - if(!M.restrained() && !M.stat) - switch(over_object.name) - if("r_hand") - if(M.unEquip(src)) - M.put_in_r_hand(src) - if("l_hand") - if(M.unEquip(src)) - M.put_in_l_hand(src) - - add_fingerprint(usr) - return -/obj/item/clipboard/on_update_icon() - ..() - if(toppaper) - overlays += overlay_image(toppaper.icon, toppaper.icon_state, flags=RESET_COLOR) - overlays += toppaper.overlays - if(haspen) - overlays += overlay_image(icon, "clipboard_pen", flags=RESET_COLOR) - overlays += overlay_image(icon, "clipboard_over", flags=RESET_COLOR) - return +/obj/item/clipboard/Destroy() + QDEL_NULL_LIST(papers) + stored_pen = null + return ..() + +/obj/item/clipboard/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(stored_pen) + . += "It's holding \a [stored_pen]." + if(!LAZYLEN(papers)) + . += "It contains [length(papers)] / [max_papers] paper\s." + else + . += "It has room for [max_papers] paper\s." -/obj/item/clipboard/attackby(obj/item/W, mob/user) +/obj/item/clipboard/proc/top_paper() + return LAZYACCESS(papers, 1) - if(istype(W, /obj/item/paper) || istype(W, /obj/item/photo)) - if(!user.unEquip(W, src)) - return - if(istype(W, /obj/item/paper)) - toppaper = W - to_chat(user, "You clip the [W] onto \the [src].") - update_icon() +/obj/item/clipboard/proc/push_paper(var/obj/item/P) + LAZYINSERT(papers, P, 1) + updateUsrDialog() + update_icon() + +/obj/item/clipboard/proc/pop_paper() + . = top_paper() + LAZYREMOVE(papers, 1) + updateUsrDialog() + update_icon() - else if(istype(toppaper) && istype(W, /obj/item/pen)) - toppaper.attackby(W, usr) +/obj/item/clipboard/on_update_icon() + ..() + var/obj/item/top_paper = top_paper() + if(top_paper) + var/mutable_appearance/I = new /mutable_appearance(top_paper) + I.appearance_flags |= RESET_COLOR + I.plane = FLOAT_PLANE + I.layer = FLOAT_LAYER + I.pixel_x = 0 + I.pixel_y = 0 + I.pixel_w = 0 + I.pixel_z = 0 //randpixel + add_overlay(I) + if(stored_pen) + add_overlay(overlay_image(icon, "clipboard_pen", stored_pen.color, RESET_COLOR)) + add_overlay(overlay_image(icon, "clipboard_over", flags=RESET_COLOR)) + +/obj/item/clipboard/attackby(obj/item/used_item, mob/user) + var/obj/item/top_paper = top_paper() + if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo)) + if(!user.try_unequip(used_item, src)) + return TRUE + push_paper(used_item) + to_chat(user, SPAN_NOTICE("You clip the [used_item] onto \the [src].")) + return TRUE + + else if(top_paper?.attackby(used_item, user)) + updateUsrDialog() update_icon() + return TRUE - return + else if(IS_PEN(used_item) && add_pen(used_item, user)) //If we don't have any paper, and hit it with a pen, try slotting it in + return TRUE + + return ..() /obj/item/clipboard/attack_self(mob/user) + if(CanPhysicallyInteractWith(user, src)) + interact(user) + return TRUE + +/obj/item/clipboard/interact(mob/user) var/dat = "Clipboard" - if(haspen) - dat += "Remove Pen

    " + if(stored_pen) + dat += "Remove Pen

    " else - dat += "Add Pen

    " - - //The topmost paper. I don't think there's any way to organise contents in byond, so this is what we're stuck with. -Pete - if(toppaper) - var/obj/item/paper/P = toppaper - dat += "Write Remove Rename - [P.name]

    " - - for(var/obj/item/paper/P in src) - if(P==toppaper) - continue - dat += "Remove Rename - [P.name]
    " - for(var/obj/item/photo/Ph in src) - dat += "Remove Rename - [Ph.name]
    " - - show_browser(user, dat, "window=clipboard") - onclose(user, "clipboard") - add_fingerprint(usr) + dat += "Add Pen

    " + + dat += "" + for(var/i = 1 to LAZYLEN(papers)) + var/obj/item/P = papers[i] + dat += "" + if(i == 1) + dat += "" + else + dat += "" + dat += "
    [P.name]Write" + dat += "RemoveRename
    " + + user.set_machine(src) + show_browser(user, dat, "window=[initial(name)]") + onclose(user, initial(name)) + add_fingerprint(user) return -/obj/item/clipboard/Topic(href, href_list) - ..() - if((usr.stat || usr.restrained())) - return - - if(src.loc == usr) - - if(href_list["pen"]) - if(istype(haspen) && (haspen.loc == src)) - usr.put_in_hands(haspen) - haspen = null - - else if(href_list["addpen"]) - if(!haspen) - var/obj/item/pen/W = usr.get_active_hand() - if(istype(W, /obj/item/pen)) - if(!usr.unEquip(W, src)) - return - haspen = W - to_chat(usr, "You slot the pen into \the [src].") - - else if(href_list["write"]) - var/obj/item/P = locate(href_list["write"]) - - if(P && (P.loc == src) && istype(P, /obj/item/paper) && (P == toppaper) ) - - var/obj/item/I = usr.get_active_hand() - - if(istype(I, /obj/item/pen)) - - P.attackby(I, usr) - - else if(href_list["remove"]) - var/obj/item/P = locate(href_list["remove"]) - - if(P && (P.loc == src) && (istype(P, /obj/item/paper) || istype(P, /obj/item/photo)) ) - usr.put_in_hands(P) - if(P == toppaper) - toppaper = null - var/obj/item/paper/newtop = locate(/obj/item/paper) in src - if(newtop && (newtop != P)) - toppaper = newtop - else - toppaper = null - - else if(href_list["rename"]) - var/obj/item/O = locate(href_list["rename"]) - - if(O && (O.loc == src)) - if(istype(O, /obj/item/paper)) - var/obj/item/paper/to_rename = O - to_rename.rename() - - else if(istype(O, /obj/item/photo)) - var/obj/item/photo/to_rename = O - to_rename.rename() - - else if(href_list["read"]) - var/obj/item/paper/P = locate(href_list["read"]) - - if(P && (P.loc == src) && istype(P, /obj/item/paper) ) - - if(!(istype(usr, /mob/living/carbon/human) || isghost(usr) || istype(usr, /mob/living/silicon))) - show_browser(usr, "[P.name][stars(P.info)][P.stamps]", "window=[P.name]") - onclose(usr, "[P.name]") - else - show_browser(usr, "[P.name][P.info][P.stamps]", "window=[P.name]") - onclose(usr, "[P.name]") - - else if(href_list["look"]) - var/obj/item/photo/P = locate(href_list["look"]) - if(P && (P.loc == src) && istype(P, /obj/item/photo) ) - P.show(usr) - - else if(href_list["top"]) // currently unused - var/obj/item/P = locate(href_list["top"]) - if(P && (P.loc == src) && istype(P, /obj/item/paper) ) - toppaper = P - to_chat(usr, "You move [P.name] to the top.") - - //Update everything - attack_self(usr) +/obj/item/clipboard/proc/add_pen(var/obj/item/I, var/mob/user) + if(!stored_pen && I.w_class <= ITEM_SIZE_TINY && IS_PEN(I) && user.try_unequip(I, src)) + stored_pen = I + to_chat(user, SPAN_NOTICE("You slot \the [I] into \the [src].")) + updateUsrDialog() update_icon() - return + return TRUE + else if(stored_pen) + to_chat(user, SPAN_WARNING("There is already \a [stored_pen] in \the [src].")) + else if(I.w_class > ITEM_SIZE_TINY) + to_chat(user, SPAN_WARNING("\The [I] is too big to fit in \the [src].")) + +/obj/item/clipboard/proc/remove_pen(var/mob/user) + if(stored_pen && user.get_empty_hand_slot()) + to_chat(user, SPAN_NOTICE("You pull \the [stored_pen] from your [src].")) + user.put_in_hands(stored_pen) + . = stored_pen + stored_pen = null + updateUsrDialog() + update_icon() + return . + else if(!stored_pen) + to_chat(user, SPAN_WARNING("There is no pen in \the [src].")) + else + to_chat(user, SPAN_WARNING("Your hands are full.")) +/obj/item/clipboard/DefaultTopicState() + return global.physical_topic_state + +/obj/item/clipboard/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + var/obj/item/tpaper = top_paper() + + if(href_list["pen"] && remove_pen(user)) + . = TOPIC_REFRESH + + else if(href_list["addpen"] && add_pen(user.get_accessible_pen(), user)) + . = TOPIC_REFRESH + + else if(href_list["write"]) + if(tpaper) + var/obj/item/I = user.get_accessible_pen() + //We can also use the stored pen if we have one and a free hand + if(!I && IS_PEN(stored_pen)) + I = remove_pen(user) + else if(!I) + to_chat(user, SPAN_WARNING("You don't have a pen!")) + return TOPIC_NOACTION + + if(I) + tpaper.attackby(I, user) + . = TOPIC_REFRESH + else + . = TOPIC_NOACTION + + else if(href_list["remove"]) + var/obj/item/P = locate(href_list["remove"]) + user.put_in_hands(P) + papers.Remove(P) + . = TOPIC_REFRESH + + else + . = handle_paper_stack_shared_topics(user, href_list) + + //Update everything + if(. & TOPIC_REFRESH) + updateUsrDialog() + update_icon() + +/obj/item/clipboard/dropped(mob/user) + . = ..() + if(CanUseTopic(user, DefaultTopicState())) + updateUsrDialog() + else + close_browser(user, initial(name)) + +/obj/item/clipboard/get_alt_interactions(mob/user) + . = ..() + if(stored_pen) + LAZYADD(., /decl/interaction_handler/clipboard_remove_pen) + +/decl/interaction_handler/clipboard_remove_pen + name = "Remove Pen" + expected_target_type = /obj/item/clipboard + examine_desc = "remove the pen" + +/decl/interaction_handler/clipboard_remove_pen/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/obj/item/clipboard/clipboard = target + return !!clipboard.stored_pen + +/decl/interaction_handler/clipboard_remove_pen/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/clipboard/clipboard = target + if(clipboard.stored_pen) + clipboard.remove_pen(user) + +// Subtypes below. /obj/item/clipboard/ebony - material = /decl/material/solid/wood/ebony + material = /decl/material/solid/organic/wood/ebony /obj/item/clipboard/steel material = /decl/material/solid/metal/steel - material = /decl/material/solid/metal/steel /obj/item/clipboard/aluminium material = /decl/material/solid/metal/aluminium - material = /decl/material/solid/metal/aluminium /obj/item/clipboard/glass material = /decl/material/solid/glass - material = /decl/material/solid/glass /obj/item/clipboard/plastic - material = /decl/material/solid/plastic - material = /decl/material/solid/plastic \ No newline at end of file + material = /decl/material/solid/organic/plastic diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 381cc51ba06a..fd66d7857a94 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -1,234 +1,680 @@ -GLOBAL_LIST_EMPTY(allfaxes) -GLOBAL_LIST_EMPTY(alldepartments) - -GLOBAL_LIST_EMPTY(adminfaxes) //cache for faxes that have been sent to admins - -/obj/machinery/photocopier/faxmachine - name = "fax machine" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "fax" - insert_anim = "faxsend" - var/send_access = list(list(access_lawyer, access_bridge, access_armory, access_qm)) - - idle_power_usage = 30 - active_power_usage = 200 - - var/obj/item/card/id/scan = null // identification - var/authenticated = 0 - var/sendcooldown = 0 // to avoid spamming fax messages - var/department = "Unknown" // our department - var/destination = null // the department we're sending to - - var/static/list/admin_departments - -/obj/machinery/photocopier/faxmachine/Initialize() +#define FAX_QUICK_DIAL_FILE "quickdial" +#define FAX_HISTORY_FILE "fax_history" +#define FAX_COOLDOWN 15 SECONDS //Cooldown after sending a regular fax +#define FAX_ADMIN_COOLDOWN 30 SECONDS //Cooldown after faxing an admin + +var/global/list/allfaxes = list() +var/global/list/adminfaxes = list() //cache for faxes that have been sent to admins + +//////////////////////////////////////////////////////////////////////////////////////// +// Fax Machine Board +//////////////////////////////////////////////////////////////////////////////////////// +/obj/item/stock_parts/circuitboard/fax_machine + name = "circuitboard (fax machine)" + build_path = /obj/machinery/faxmachine + board_type = "machine" + origin_tech = @'{"engineering":1, "programming":1}' + req_components = list( + /obj/item/stock_parts/printer = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/scanning_module = 1, + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1, + /obj/item/stock_parts/computer/lan_port = 1, + /obj/item/stock_parts/computer/network_card = 1, + /obj/item/stock_parts/item_holder/disk_reader/buildable = 1, + /obj/item/stock_parts/item_holder/card_reader/buildable = 1, + /obj/item/stock_parts/access_lock/buildable = 1, + ) + +//////////////////////////////////////////////////////////////////////////////////////// +// Fax Machine Network Device +//////////////////////////////////////////////////////////////////////////////////////// +/datum/extension/network_device/fax + has_commands = TRUE + long_range = TRUE + +//////////////////////////////////////////////////////////////////////////////////////// +// Fax Machine +//////////////////////////////////////////////////////////////////////////////////////// +/obj/machinery/faxmachine + name = "fax machine" + icon = 'icons/obj/machines/fax_machine.dmi' + icon_state = "fax" + anchored = TRUE + density = TRUE + idle_power_usage = 30 + active_power_usage = 200 + base_type = /obj/machinery/faxmachine + construct_state = /decl/machine_construction/default/panel_closed + maximum_component_parts = list( + /obj/item/stock_parts/item_holder/disk_reader = 1, + /obj/item/stock_parts/item_holder/card_reader = 1, + /obj/item/stock_parts/printer = 1, + /obj/item/stock_parts = 15, + ) + stock_part_presets = list( + /decl/stock_part_preset/access_lock, //Empty access list + ) + uncreated_component_parts = null + public_methods = list( + /decl/public_access/public_method/fax_receive_document, + ) + var/obj/item/stock_parts/item_holder/disk_reader/disk_reader //Cached ref to the disk_reader component. Used for handling data disks. + var/obj/item/stock_parts/item_holder/card_reader/card_reader //Cached ref to the card_reader component. Used for scanning a user's id card. + var/obj/item/stock_parts/printer/printer //Cached ref to the printer component. Used for printing things. + var/obj/item/scanner_item //Item to fax + var/list/quick_dial //List of name tag to network ids for other fax machines that the user added as quick dial options + var/list/fax_history //List of the last 10 devices that sent us faxes, and when + var/tmp/init_network_tag //The network tag of this fax machine, set by mappers. + + var/tmp/time_cooldown_end = 0 + var/tmp/current_page = "main" + var/tmp/dest_uri //The currently set destination URI for the target machine. Format is "[network_tag].[network_id]" + +/obj/machinery/faxmachine/Initialize(mapload, d=0, populate_parts = TRUE) + . = ..() + if(. != INITIALIZE_HINT_QDEL) + global.allfaxes += src + var/datum/extension/network_device/fax/netdevice = set_extension(src, /datum/extension/network_device/fax) + if(init_network_tag) + netdevice.set_network_tag(init_network_tag) + if(populate_parts && printer) + printer.make_full() + +/obj/machinery/faxmachine/Destroy() + global.allfaxes -= src + disk_reader = null + card_reader = null + printer = null + scanner_item = null . = ..() - if(!admin_departments) - admin_departments = list("[GLOB.using_map.boss_name]", "Sol Federal Police", "[GLOB.using_map.boss_short] Supply") + GLOB.using_map.map_admin_faxes - GLOB.allfaxes += src - if(!destination) destination = "[GLOB.using_map.boss_name]" - if( !(("[department]" in GLOB.alldepartments) || ("[department]" in admin_departments))) - GLOB.alldepartments |= department - -/obj/machinery/photocopier/faxmachine/attackby(obj/item/O, mob/user) - if(istype(O, /obj/item/card/id)) - if(!user.unEquip(O, src)) - return - scan = O - to_chat(user, "You insert \the [O] into \the [src].") +/obj/machinery/faxmachine/on_update_icon() + if(!QDELETED(scanner_item)) + icon_state = "faxpaper" //not using an overlay, because animations else - ..() + icon_state = initial(icon_state) -/obj/machinery/photocopier/faxmachine/interface_interact(mob/user) - interact(user) +/obj/machinery/faxmachine/RefreshParts() + . = ..() + disk_reader = get_component_of_type(/obj/item/stock_parts/item_holder/disk_reader) + card_reader = get_component_of_type(/obj/item/stock_parts/item_holder/card_reader) + printer = get_component_of_type(/obj/item/stock_parts/printer) + + if(disk_reader) + disk_reader.register_on_insert(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, on_insert_disk))) + disk_reader.register_on_eject( CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, update_ui))) + + if(card_reader) + card_reader.register_on_insert(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, on_insert_card))) + card_reader.register_on_eject( CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, update_ui))) + + if(printer) + printer.register_on_printed_page( CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, on_printed_page))) + printer.register_on_finished_queue(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, on_queue_finished))) + printer.register_on_print_error( CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, on_print_error))) + printer.register_on_status_changed(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/faxmachine, update_ui))) + +/obj/machinery/faxmachine/interface_interact(mob/user) + ui_interact(user) return TRUE -/obj/machinery/photocopier/faxmachine/interact(mob/user) - user.set_machine(src) - - var/dat = "Fax Machine
    " - - var/scan_name - if(scan) - scan_name = scan.name - else - scan_name = "--------" - - dat += "Confirm Identity: [scan_name]
    " - - if(authenticated) - dat += "{Log Out}" - else - dat += "{Log In}" - - dat += "
    " +/obj/machinery/faxmachine/attackby(obj/item/used_item, mob/user) + if(istype(construct_state, /decl/machine_construction/default/panel_closed)) + if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo) || istype(used_item, /obj/item/paper_bundle)) + insert_scanner_item(used_item, user) + return TRUE + . = ..() - if(authenticated) - dat += "Logged in to: [GLOB.using_map.boss_name] Quantum Entanglement Network

    " +/obj/machinery/faxmachine/ui_data(mob/user, ui_key) + . = ..() + var/datum/extension/network_device/fax/net = get_extension(src, /datum/extension/network_device) + LAZYADD(., net.ui_data(user)) //Grab some of the network data stuff + + //Convert the list to something we can use in the nanoui + var/list/uiqd + for(var/key in quick_dial) + var/list/element = list("key" = key, "value" = quick_dial[key]) + LAZYADD(uiqd, list(element)) + + LAZYSET(., "quick_dial_targets", uiqd) + LAZYSET(., "fax_history", fax_history) + LAZYSET(., "scanner_item", "[!QDELETED(scanner_item)? scanner_item : ""]") + LAZYSET(., "is_cooling_down", (time_cooldown_end > world.timeofday)) + LAZYSET(., "dest_uri", dest_uri) + LAZYSET(., "src", "\ref[src]") + LAZYSET(., "emagged", emagged) + LAZYSET(., "is_operational", operable()) + LAZYSET(., "page", current_page) + + //Printer stuff + if(printer) + LAZYADD(., printer.ui_data(user)) + + //Card reader stuff + var/obj/item/card/C = card_reader?.get_inserted() + LAZYSET(., "has_card_reader", !isnull(card_reader)) + LAZYSET(., "id_card", C) + LAZYSET(., "data_card", card_reader?.get_data_card()) + if(C) + var/info = C.name + if(istype(C, /obj/item/card/id)) + var/obj/item/card/id/ID = C + info = ID.get_display_name() + LAZYSET(., "id_card_info", info) + + //Disk stuff + var/obj/item/disk/D = disk_reader?.get_inserted() + LAZYSET(., "has_disk_drive", !isnull(disk_reader)) + LAZYSET(., "disk", D) + LAZYSET(., "disk_name", D?.name) + +/obj/machinery/faxmachine/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) + var/list/data = ui_data(user, ui_key) + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "fax_machine.tmpl", name, 640, 480) + ui.add_template("net_shared", "network_shared.tmpl") //Shared network UI stuff + ui.add_template("stock_parts_printer_shared", "stock_parts_printer.tmpl") + ui.set_initial_data(data) + ui.open() + +/obj/machinery/faxmachine/DefaultTopicState() + return global.physical_topic_state + +/obj/machinery/faxmachine/OnTopic(mob/user, list/href_list, datum/topic_state/state) + if(!CanInteract(user, state)) + to_chat(user, SPAN_WARNING("You must be close to \the [src] to do this!")) + return TOPIC_NOACTION + + if(href_list["change_page"]) + var/pagename = href_list["change_page"] + current_page = pagename + return TOPIC_REFRESH - if(copyitem) - dat += "Remove Item

    " + if(href_list["network_settings"]) + var/datum/extension/network_device/fax/net = get_extension(src, /datum/extension/network_device) + net.ui_interact(user) + return TOPIC_REFRESH - if(sendcooldown) - dat += "Transmitter arrays realigning. Please stand by.
    " + // --- Sending Fax --- + if(href_list["send"]) + if(QDELETED(scanner_item)) + to_chat(user, SPAN_WARNING("You must insert something to send first!")) + return TOPIC_NOACTION + if(world.timeofday < time_cooldown_end) + to_chat(user, SPAN_WARNING("\The [src] isn't ready yet for sending again! [max(0, time_cooldown_end - world.timeofday) / (1 SECOND)] second\s left.")) + return TOPIC_REFRESH + + //Prioritize the quick dial value + dest_uri = replacetext(sanitize(href_list["quick_dial"], encode = FALSE), " ", "_") + if(!length(dest_uri)) + dest_uri = replacetext(sanitize(href_list["network_uri"], encode = FALSE), " ", "_") + if(!length(dest_uri)) + to_chat(user, SPAN_WARNING("You must specify a destination!")) + return TOPIC_NOACTION + + var/list/parsed = parse_network_uri(dest_uri) + if(!length(parsed)) + to_chat(user, SPAN_WARNING("Bad target URI!")) + return TOPIC_NOACTION + send_fax(user, parsed["network_tag"], parsed["network_id"]) + return TOPIC_REFRESH + // --- Insert/Eject --- + if(href_list["id_card"]) + if(card_reader) + var/obj/item/card/C = card_reader.get_inserted() + if(C) + eject_card(user) else + var/obj/item/card/id/ID = user.get_active_held_item() + if(!istype(ID) && !istype(ID, /obj/item/card/data)) + to_chat(user, SPAN_WARNING("You need to hold a valid id/data card!")) + else if(card_reader.should_swipe) + to_chat(user, SPAN_WARNING("\The [card_reader] is currently set to swipe mode, which is unsupported by this machine. Please contact your system administrator.")) + else + card_reader.insert_item(ID, user) + else + to_chat(user, SPAN_WARNING("The card reader is not responding!")) + return TOPIC_NOACTION + return TOPIC_REFRESH - dat += "Send
    " - dat += "Currently sending: [copyitem.name]
    " - dat += "Sending to: [destination]
    " - + if(href_list["insert_item"]) + if(!QDELETED(scanner_item)) + to_chat(user, SPAN_WARNING("There's already a [scanner_item] in \the [src]!")) + return TOPIC_NOACTION else - if(sendcooldown) - dat += "Please insert paper to send via secure connection.

    " - dat += "Transmitter arrays realigning. Please stand by.
    " + var/obj/item/thing = user.get_active_held_item() + if(thing) + insert_scanner_item(thing, user) else - dat += "Please insert paper to send via secure connection.

    " - - else - dat += "Proper authentication is required to use this device.

    " - - if(copyitem) - dat += "Remove Item
    " + to_chat(user, SPAN_WARNING("You're not holding anything!")) + return TOPIC_NOACTION + return TOPIC_REFRESH - show_browser(user, dat, "window=copier") - onclose(user, "copier") - return - -/obj/machinery/photocopier/faxmachine/OnTopic(mob/user, href_list, state) - if(href_list["send"]) - if(copyitem) - if (destination in admin_departments) - send_admin_fax(user, destination) - else - sendfax(destination) + if(href_list["remove_item"]) + eject_scanner_item(user) + return TOPIC_REFRESH - if (sendcooldown) - spawn(sendcooldown) // cooldown time - sendcooldown = 0 + //Handle extra disk ops here + if(disk_reader && (OnTopic_DiskOps(user, href_list, state) != TOPIC_NOACTION)) return TOPIC_REFRESH - if(href_list["remove"]) - OnRemove(user) + if(printer?.OnTopic(user, href_list, state) != TOPIC_NOACTION) return TOPIC_REFRESH - if(href_list["scan"]) - if (scan) - if(ishuman(user)) - user.put_in_hands(scan) - else - scan.dropInto(loc) - scan = null +/**Handle disk operations topics. */ +/obj/machinery/faxmachine/proc/OnTopic_DiskOps(mob/user, list/href_list, datum/topic_state/state) + if(href_list["insert_disk"]) + if(!disk_reader) + to_chat(user, SPAN_WARNING("There is no disk drive installed on \the [src]!")) + return TOPIC_NOACTION + var/obj/item/disk/D = user.get_active_held_item() + if(!istype(D)) + to_chat(user, SPAN_WARNING("You need to hold a valid data disk!")) + return TOPIC_NOACTION else - var/obj/item/I = user.get_active_hand() - if (istype(I, /obj/item/card/id) && user.unEquip(I, src)) - scan = I - authenticated = 0 + disk_reader.insert_item(D, user) return TOPIC_REFRESH - if(href_list["dept"]) - var/desired_destination = input(user, "Which department?", "Choose a department", "") as null|anything in (GLOB.alldepartments + admin_departments) - if(desired_destination && CanInteract(user, state)) - destination = desired_destination + if(href_list["eject_disk"]) + eject_disk(user) return TOPIC_REFRESH - if(href_list["auth"]) - if ( (!( authenticated ) && (scan)) ) - if (has_access(send_access, scan.GetAccess())) - authenticated = 1 + // --- Quick Dial Operations --- + if(href_list["add_qd"]) + var/qduri = uppertext(replacetext(sanitize(href_list["network_uri"], encode = FALSE), " ", "_")) + if(!length(qduri)) + to_chat(user, SPAN_WARNING("Please specify a destination URI!")) + return TOPIC_NOACTION + + var/inputname = input(user, "Name for the new quick dial contact?", "New quick dial contact") + if(length(inputname) && CanPhysicallyInteract(user)) + add_quick_dial_contact(sanitize_name(inputname, MAX_NAME_LEN, TRUE, TRUE), qduri, user) return TOPIC_REFRESH - if(href_list["logout"]) - authenticated = 0 + if(href_list["rem_qd"]) + var/qduri = uppertext(replacetext(sanitize(href_list["quick_dial"], encode = FALSE), " ", "_")) + var/qdname + for(var/key in quick_dial) + if(quick_dial[key] == qduri) + qdname = key + break + rem_quick_dial_contact(qdname, user) return TOPIC_REFRESH + return TOPIC_NOACTION + +/**Returns the inserted card if there is a reader and if there is a card. Otherwise print a warning to the user, if a user was passed */ +/obj/machinery/faxmachine/proc/try_get_card(var/mob/user) + var/obj/item/card/C = card_reader?.get_inserted() + if(!card_reader) + if(user) + to_chat(user, SPAN_WARNING("There is no card reader!")) + return + else if(!C) + if(user) + to_chat(user, SPAN_WARNING("There is no card in \the [card_reader]!")) + return + return C + +/**Warn the user if the disk cannot be accessed. Otherwise returns the disk in the disk reader. */ +/obj/machinery/faxmachine/proc/try_get_disk(var/mob/user) + var/obj/item/disk/D = disk_reader?.get_inserted() + if(!disk_reader) + if(user) + to_chat(user, SPAN_WARNING("There is no disk drive!")) + return + else if(!D) + if(user) + to_chat(user, SPAN_WARNING("There is no disk in \the [disk_reader]!")) + return + return D + +/obj/machinery/faxmachine/proc/insert_scanner_item(var/obj/item/thing, var/mob/user) + if(!QDELETED(scanner_item)) + if(user) + to_chat(user, SPAN_WARNING("\The [src] already has something being scanned!")) + return FALSE + + if(user) + to_chat(user, SPAN_NOTICE("You place \the [thing] into \the [src]'s scanner.")) + if(!user.try_unequip(thing, src)) + return FALSE + else + thing.dropInto(src) + scanner_item = thing + update_ui() + return TRUE + +/obj/machinery/faxmachine/proc/eject_scanner_item(var/mob/user) + if(QDELETED(scanner_item)) + if(user) + to_chat(user, SPAN_WARNING("There's nothing to eject from \the [src].")) + return FALSE -/obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination) - if(stat & (BROKEN|NOPOWER)) + if(user) + to_chat(user, SPAN_NOTICE("You eject \the [scanner_item] from \the [src].")) + user.put_in_hands(scanner_item) + else + scanner_item.dropInto(get_turf(src)) + scanner_item = null + update_ui() + return TRUE + +/obj/machinery/faxmachine/proc/on_insert_card(var/obj/item/card/C, var/mob/user) + if(card_reader.should_swipe) //We don't support swiping + if(user) + to_chat(user, SPAN_WARNING("\The [card_reader] is currently set to swipe mode, which is unsupported by this machine. Please contact your system administrator.")) return + if(user) + to_chat(user, SPAN_NOTICE("You insert \the [C] into \the [src].")) + update_ui() + +/obj/machinery/faxmachine/proc/eject_card(var/mob/user) + if(!card_reader) + if(user) + to_chat(user, SPAN_WARNING("\The [src] has no card reader installed.")) + return FALSE + card_reader.eject_item(user) + update_ui() + return TRUE - use_power_oneoff(200) +/obj/machinery/faxmachine/proc/on_insert_disk(var/obj/item/disk/D, var/mob/user) + //Read any existing disk data + var/datum/computer_file/data/qdfile = D.read_file(FAX_QUICK_DIAL_FILE) + if(qdfile) + quick_dial = json_decode(qdfile.stored_data) + + var/datum/computer_file/data/histfile = D.read_file(FAX_HISTORY_FILE) + if(histfile) + fax_history = json_decode(histfile.stored_data) + update_ui() + +/obj/machinery/faxmachine/proc/eject_disk(var/mob/user) + if(!disk_reader) + to_chat(user, SPAN_WARNING("\The [src] has no disk drive installed.")) + return FALSE + disk_reader.eject_item(user) + LAZYCLEARLIST(quick_dial) + LAZYCLEARLIST(fax_history) + update_ui() + return TRUE - var/success = 0 - for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) - if( F.department == destination ) - success = F.recievefax(copyitem) +/obj/machinery/faxmachine/proc/send_fax(var/mob/user, var/target_net_tag, var/target_net_id) + if(QDELETED(scanner_item)) + to_chat(user, SPAN_WARNING("You need to insert something to fax first!")) + return FALSE + if(inoperable()) + return FALSE + if(world.timeofday < time_cooldown_end) + to_chat(user, SPAN_WARNING("Cannot send while busy! [max(0, world.timeofday - time_cooldown_end) / (1 SECOND)] second\s remaining.")) + return FALSE + + //Try to get enough power + if(can_use_power_oneoff(active_power_usage) > 0) + return FALSE + use_power_oneoff(active_power_usage) - if (success) - visible_message("[src] beeps, \"Message transmitted successfully.\"") - //sendcooldown = 600 + var/obj/item/card/id/ID = try_get_card() + ID = istype(ID)? ID : null + + //Grab our network + var/datum/extension/network_device/sender_dev = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/origin_network = sender_dev?.get_network() + if(!origin_network) + to_chat(user, SPAN_WARNING("No network connection!")) + return FALSE + + //If sending to admins, don't try to get a target network or device + var/target_URI = uppertext("[target_net_tag].[target_net_id]") + var/list/target_admin_fax = LAZYACCESS(global.using_map.map_admin_faxes, target_URI) + if(target_admin_fax) + var/list/fax_req_access = target_admin_fax["access"] + if(!emagged) + if(!has_access(req_access, ID?.GetAccess())) + to_chat(user, SPAN_WARNING("You do not have the right credentials to use the send function on this device!")) + return FALSE + if(!has_access(fax_req_access, ID?.GetAccess())) + to_chat(user, SPAN_WARNING("You do not have the right credentials to send a fax to this recipient!")) + return FALSE + else if(prob(1)) + spark_at(src, 1) + + . = send_fax_to_admin(user, scanner_item, target_URI, src) + log_history("Outgoing", "'[scanner_item]', from '[get_area(src)]'s [src]' @ '[sender_dev?.get_network_URI() || "UNKNOWN SENDER"]' to [target_admin_fax["name"]]' @ '[target_URI]'.") + update_ui() + flick("faxsend", src) + //#TODO: sync the animation, sound and message together when I got enough patience. + playsound(src, 'sound/machines/fax_send.ogg', 30, FALSE, 0, 4) + ping("Message transmitted successfully!") + time_cooldown_end = world.timeofday + FAX_ADMIN_COOLDOWN + return TRUE + + if(!length(target_net_id)) + target_net_id = origin_network.network_id //Use the current network if none specified + + if((target_net_id != origin_network.network_id) && !sender_dev.has_internet_connection(origin_network)) + to_chat(user, SPAN_WARNING("No internet connection!")) + return FALSE + + var/datum/computer_network/target_net + if(target_net_id != origin_network.network_id) + target_net = origin_network.get_internet_connection(target_net_id) else - visible_message("[src] beeps, \"Error transmitting message.\"") - -/obj/machinery/photocopier/faxmachine/proc/recievefax(var/obj/item/incoming) - if(stat & (BROKEN|NOPOWER)) - return 0 + target_net = origin_network + + if(!target_net) + to_chat(user, SPAN_WARNING("No such network '[target_net_id]'!")) + return FALSE + + var/datum/extension/network_device/fax/target_dev = target_net.get_device_by_tag(target_net_tag) + if(!target_dev) + to_chat(user, SPAN_WARNING("No such devices '[target_net_tag]'!")) + return FALSE + if(!istype(target_dev) || !target_dev.has_commands) + to_chat(user, SPAN_WARNING("Invalid target device '[target_net_tag]'!")) + return FALSE + var/obj/machinery/target = target_dev.holder + if(!target) + CRASH("There is a network_device extension without a holder!") + + //Authenticate as needed + if(!emagged) + if(!has_access(req_access, ID?.GetAccess())) + to_chat(user, SPAN_WARNING("You do not have the right credentials to use the send function on this device!")) + return FALSE + if(!has_access(target.req_access, ID?.GetAccess())) + to_chat(user, SPAN_WARNING("You do not have the right credentials to send a fax to this recipient!")) + return FALSE + else if(prob(1)) + spark_at(src, 1) + + //Setup cooldown + time_cooldown_end = world.timeofday + FAX_COOLDOWN + + //Call receive on the target machine + var/decl/public_access/public_method/send_method = GET_DECL(/decl/public_access/public_method/fax_receive_document) + if(send_method.perform(target, scanner_item.Clone(), "[get_area(src)]'s [src]", sender_dev.get_network_URI())) + log_history("Outgoing", "'[scanner_item]', from '[get_area(src)]'s [src]' @ '[sender_dev.get_network_URI()]' to '[get_area(target)]'s [target]' @ '[target_dev.get_network_URI()]'.") + //#TODO: sync the animation, sound and message together when I got enough patience. + ping("Message transmitted successfully.") + playsound(src, 'sound/machines/fax_send.ogg', 30, FALSE, 0, 4) + update_ui() + flick("faxsend", src) + return TRUE + else if(target.inoperable()) + buzz("Error transmitting message, receiving machine won't reply.") + else + buzz("Error transmitting message.") + return FALSE - if(department == "Unknown") - return 0 //You can't send faxes to "Unknown" +/**Handles queuing any received fax message in the printer queue, and starts the printer if needed. */ +/obj/machinery/faxmachine/proc/receive_fax(var/obj/item/incoming, var/source_name = "unknown", var/source_URI = "unknown.unknown") + if(inoperable()) + return FALSE - flick("faxreceive", src) - playsound(loc, "sound/machines/dotprinter.ogg", 50, 1) + //Try to get enough power + if(can_use_power_oneoff(active_power_usage) > 0) + return FALSE - // give the sprite some time to flick - sleep(20) + printer?.queue_job(incoming) //Add it to the printer queue so we don't lose it on failure + if(printer?.is_printing()) + return TRUE //Don't do anything extra if we're already printing - if (istype(incoming, /obj/item/paper)) - copy(incoming) - else if (istype(incoming, /obj/item/photo)) - photocopy(incoming) - else if (istype(incoming, /obj/item/paper_bundle)) - bundlecopy(incoming) - else - return 0 + if(!printer?.has_enough_to_print()) + buzz("Error while printing, not enough toner or paper to print the received message! Please refill, and resume printing!") + return FALSE + //Tell the printer to do its job + printer.start_printing_queue() use_power_oneoff(active_power_usage) - return 1 + var/datum/extension/network_device/fax/ND = get_extension(src, /datum/extension/network_device) + log_history("Incoming", "'[incoming]', from '[source_name]'@'[source_URI]' to '[get_area(src)]'s [src]'@'[ND.get_network_URI()]'.") + return TRUE -/obj/machinery/photocopier/faxmachine/proc/send_admin_fax(var/mob/sender, var/destination) - if(stat & (BROKEN|NOPOWER)) - return +/**Cause the nanoui to update, also updates the icon of the machine. */ +/obj/machinery/faxmachine/proc/update_ui() + SSnano.update_uis(src) + update_icon() - use_power_oneoff(200) +/**Plays print animation async. */ +/obj/machinery/faxmachine/proc/on_printed_page() + flick("faxreceive", src) - //recieved copies should not use toner since it's being used by admins only. - var/obj/item/rcvdcopy - if (istype(copyitem, /obj/item/paper)) - rcvdcopy = copy(copyitem, 0) - else if (istype(copyitem, /obj/item/photo)) - rcvdcopy = photocopy(copyitem, 0) - else if (istype(copyitem, /obj/item/paper_bundle)) - rcvdcopy = bundlecopy(copyitem, 0) - else - visible_message("[src] beeps, \"Error transmitting message.\"") +/**Tells the user we just printed the last page of the queue, and do the print anim. */ +/obj/machinery/faxmachine/proc/on_queue_finished() + if(QDELETED(src)) return + state("Printing tasks complete!") + on_printed_page() - rcvdcopy.forceMove(null) //hopefully this shouldn't cause trouble - GLOB.adminfaxes += rcvdcopy - - //message badmins that a fax has arrived - if (destination == GLOB.using_map.boss_name) - message_admins(sender, "[uppertext(destination)] FAX", rcvdcopy, destination, "#006100") - else if (destination == "Sol Federal Police") - message_admins(sender, "[uppertext(destination)] FAX", rcvdcopy, destination, "#1f66a0") - else if (destination == "[GLOB.using_map.boss_short] Supply") - message_admins(sender, "[uppertext(destination)] FAX", rcvdcopy, destination, "#5f4519") - else if (destination in GLOB.using_map.map_admin_faxes) - message_admins(sender, "[uppertext(destination)] FAX", rcvdcopy, destination, "#510b74") +/**Warn the user that something interrupted printing. */ +/obj/machinery/faxmachine/proc/on_print_error() + if(!printer?.has_enough_to_print()) + buzz("Error while printing, not enough toner or paper to print the received message! Please refill, and resume printing!") else - message_admins(sender, "[uppertext(destination)] FAX", rcvdcopy, "UNKNOWN") + buzz("Error while printing!") + +/obj/machinery/faxmachine/proc/log_history(var/operation, var/text) + LAZYADD(fax_history, "[stationdate2text()], [stationtime2text()]: [operation] - [text]") + var/obj/item/disk/D = disk_reader?.get_inserted() + if(!D) + return + var/datum/computer_file/data/hist = new + hist.stored_data = json_encode(fax_history) + D.write_file(hist, FAX_HISTORY_FILE) + +/obj/machinery/faxmachine/proc/add_quick_dial_contact(var/contact_name, var/contact_URI, var/mob/user) + if(!length(contact_URI)) + if(user) + to_chat(user, SPAN_WARNING("Please specify a destination URI!")) + return FALSE + + if(!length(contact_name)) + if(user) + to_chat(user, SPAN_WARNING("Please specify a valid name for the contact!")) + return FALSE + LAZYSET(quick_dial, contact_name, contact_URI) + + //Overwrite quick dial + var/obj/item/disk/D = try_get_disk() + if(D) + var/datum/computer_file/data/datfile = new + datfile.stored_data = json_encode(quick_dial) + D.write_file(datfile, FAX_QUICK_DIAL_FILE) + + if(user) + to_chat(user, SPAN_NOTICE("New contact '[contact_name]' with URI '[contact_URI]' added successfully!")) + update_ui() + return TRUE + +/obj/machinery/faxmachine/proc/rem_quick_dial_contact(var/contact_name, var/mob/user) + if(!length(contact_name)) + if(user) + to_chat(user, SPAN_WARNING("Please select a contact to remove!")) + return FALSE + + var/remove_uri = LAZYACCESS(quick_dial, contact_name) + LAZYREMOVE(quick_dial, contact_name) + + //Overwrite quick dial + var/obj/item/disk/D = try_get_disk() + if(D) + var/datum/computer_file/data/datfile = new + datfile.stored_data = json_encode(quick_dial) + D.write_file(datfile, FAX_QUICK_DIAL_FILE) + + if(user) + to_chat(user, SPAN_NOTICE("Successfully removed contact '[contact_name]' with URI '[remove_uri]'!")) + update_ui() + return TRUE + +//////////////////////////////////////////////////////////////////////////////////////// +// Public Methods +//////////////////////////////////////////////////////////////////////////////////////// +/decl/public_access/public_method/fax_receive_document + name = "Send Fax Message" + desc = "Sends the specified document over to the specified network tag." + call_proc = TYPE_PROC_REF(/obj/machinery/faxmachine, receive_fax) + forward_args = TRUE + +//////////////////////////////////////////////////////////////////////////////////////// +// Admin Faxes Handling +//////////////////////////////////////////////////////////////////////////////////////// + +/**Helper for sending a fax from a fax machine to an admin destination. */ +/proc/send_fax_to_admin(var/mob/sender, var/obj/item/doc, var/network_URI, var/obj/machinery/faxmachine/source_fax) + var/obj/item/rcvdcopy = doc.Clone() + if(!rcvdcopy) + return + rcvdcopy.forceMove(null) + LAZYADD(global.adminfaxes, rcvdcopy) - sendcooldown = 1800 - sleep(50) - visible_message("[src] beeps, \"Message transmitted successfully.\"") + var/list/fax_details = LAZYACCESS(global.using_map?.map_admin_faxes, network_URI) + var/dest_display_name = LAZYACCESS(fax_details, "name") || network_URI + var/font_colour = LAZYACCESS(fax_details, "color") || "#006100" + var/faxname = "[uppertext(dest_display_name)] FAX" + var/reply_type = dest_display_name + if(!(network_URI in global.using_map.map_admin_faxes)) + reply_type = "UNKNOWN" -/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/obj/item/sent, var/reply_type, font_colour="#006100") var/msg = "[faxname]: [get_options_bar(sender, 2,1,1)]" - msg += "(TAKE) (REPLY): " - msg += "Receiving '[sent.name]' via secure connection ... view message" + msg += "(TAKE) (REPLY): " + msg += "Receiving '[rcvdcopy.name]' via secure connection ... view message" + + if (istype(doc, /obj/item/paper)) + var/obj/item/paper/paper = doc + SSwebhooks.send(WEBHOOK_FAX_SENT, list("title" = "Incoming fax transmission from [sender] in [faxname] for [dest_display_name].", "body" = "[paper.info]")) - for(var/client/C in GLOB.admins) + for(var/client/C in global.admins) if(check_rights((R_ADMIN|R_MOD),0,C)) to_chat(C, msg) sound_to(C, 'sound/machines/dotprinter.ogg') + return TRUE + +#undef FAX_QUICK_DIAL_FILE +#undef FAX_HISTORY_FILE +#undef FAX_COOLDOWN +#undef FAX_ADMIN_COOLDOWN + +/obj/machinery/faxmachine/mapped/Initialize() + . = ..() + if(. != INITIALIZE_HINT_QDEL) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/faxmachine/mapped/LateInitialize() + ..() + // Pre-populate our admin targets. + if(!disk_reader) + CRASH("Missing disk reader from pre-mapped fax machine!") + if(!disk_reader.disk) + disk_reader.insert_item(new /obj/item/disk(disk_reader)) + for(var/uri in global.using_map.map_admin_faxes) + var/list/contact_info = global.using_map.map_admin_faxes[uri] + add_quick_dial_contact(contact_info["name"], uri) diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index a2e85b6c0129..b5f0fdc5e78a 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -1,81 +1,145 @@ -/* Filing cabinets! - * Contains: - * Filing Cabinets - * Security Record Cabinets - * Medical Record Cabinets - */ - -/* - * Filing Cabinets - */ -/obj/structure/filingcabinet - name = "filing cabinet" - desc = "A large cabinet with drawers." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "filingcabinet" - density = 1 - anchored = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE - obj_flags = OBJ_FLAG_ANCHORABLE - var/list/can_hold = list( +///////////////////////////////////////////////////////////////// +// Filling Cabinet +///////////////////////////////////////////////////////////////// +/obj/structure/filing_cabinet + name = "filing cabinet" + desc = "A large cabinet with drawers." + icon = 'icons/obj/structures/filling_cabinets.dmi' + icon_state = "filingcabinet" + material = /decl/material/solid/metal/steel + density = TRUE + anchored = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ANCHORABLE + tool_interaction_flags = TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT + var/tmp/list/can_hold = list( /obj/item/paper, /obj/item/folder, /obj/item/photo, /obj/item/paper_bundle, - /obj/item/forensics/sample) + /obj/item/forensics/sample + ) -/obj/structure/filingcabinet/chestdrawer - name = "chest drawer" - icon_state = "chestdrawer" +/obj/structure/filing_cabinet/Initialize(ml, _mat, _reinf_mat) + if(ml) + for(var/obj/item/I in loc) + if(is_type_in_list(I, can_hold)) + I.forceMove(src) + . = ..() + +/obj/structure/filing_cabinet/attackby(obj/item/used_item, mob/user) + if(!is_type_in_list(used_item, can_hold)) + return ..() + if(!user.try_unequip(used_item, src)) + return TRUE + add_fingerprint(user) + to_chat(user, SPAN_NOTICE("You put [used_item] in [src].")) + flick("[initial(icon_state)]-open",src) + updateUsrDialog() + return TRUE + +/obj/structure/filing_cabinet/interact(mob/user) + user.set_machine(src) + var/dat = "
    " + for(var/obj/item/paper in src) + dat += "" + dat += "
    [paper.name]
    " + show_browser(user, "[name][dat]", "window=filingcabinet;size=350x300") + +/obj/structure/filing_cabinet/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + return interact(user) + +/obj/structure/filing_cabinet/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["retrieve"]) + close_browser(user, "window=filingcabinet") + var/obj/item/paper = locate(href_list["retrieve"]) + if(istype(paper) && CanPhysicallyInteractWith(user, src)) + user.put_in_hands(paper) + flick("[initial(icon_state)]-open", src) + updateUsrDialog() + . = TOPIC_REFRESH -/obj/structure/filingcabinet/wallcabinet - name = "wall-mounted filing cabinet" - desc = "A filing cabinet installed into a cavity in the wall to save space. Wow!" - icon_state = "wallcabinet" - density = 0 - obj_flags = 0 +// Subtypes for mapping! +/obj/structure/filing_cabinet/chestdrawer + name = "chest drawer" + icon_state = "chestdrawer" +/obj/structure/filing_cabinet/wall + name = "wall-mounted filing cabinet" + desc = "A filing cabinet installed into a cavity in the wall to save space. Wow!" + icon_state = "wallcabinet" + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-32}, "SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' -/obj/structure/filingcabinet/filingcabinet //not changing the path to avoid unecessary map issues, but please don't name stuff like this in the future -Pete +/obj/structure/filing_cabinet/tall icon_state = "tallcabinet" +// Record cabinets fill with paper records on first interaction. +/obj/structure/filing_cabinet/records + name = "security record archive" + var/generated = FALSE + var/archive_name = "security record" -/obj/structure/filingcabinet/Initialize() - for(var/obj/item/I in loc) - if(is_type_in_list(I, can_hold)) - I.forceMove(src) - . = ..() +// We generate records on first interaction, as latejoin, +// joining crew, etc. are hard to plan for and order around. +// It's also a fair few atoms to worry about. +/obj/structure/filing_cabinet/records/attack_hand(mob/user) + if(!generated) + generate_records() + return ..() -/obj/structure/filingcabinet/attackby(obj/item/P, mob/user) - if(is_type_in_list(P, can_hold)) - if(!user.unEquip(P, src)) - return - add_fingerprint(user) - to_chat(user, "You put [P] in [src].") - flick("[initial(icon_state)]-open",src) - updateUsrDialog() - else - ..() - -/obj/structure/filingcabinet/attack_hand(mob/user) - if(contents.len <= 0) - to_chat(user, "\The [src] is empty.") +/obj/structure/filing_cabinet/records/proc/generate_records() + generated = TRUE + var/datum/computer_network/network = get_local_network_at(get_turf(src)) + if(!network) return + for(var/datum/computer_file/report/crew_record/record in network.get_crew_records()) + var/obj/item/paper/record_paperwork = new(src) + record_paperwork.name = "[archive_name] - [record.get_name()]" + record_paperwork.info = collate_data(record) + record_paperwork.update_icon() - user.set_machine(src) - var/dat = list("
    ") - for(var/obj/item/P in src) - dat += "" - dat += "
    [P.name]
    " - show_browser(user, "[name][jointext(dat,null)]", "window=filingcabinet;size=350x300") +/obj/structure/filing_cabinet/records/proc/collate_data(var/datum/computer_file/report/crew_record/record) + . = list() + . += "Name: [record.get_name()]" + . += "Criminal Status: [record.get_criminalStatus()]" + . += "Details: [record.get_security_record()]" + return jointext(., "
    ") -/obj/structure/filingcabinet/Topic(href, href_list) - if(href_list["retrieve"]) - show_browser(usr, "", "window=filingcabinet") // Close the menu +/obj/structure/filing_cabinet/records/medical + name = "medical record archive" + archive_name = "medical record" - //var/retrieveindex = text2num(href_list["retrieve"]) - var/obj/item/P = locate(href_list["retrieve"])//contents[retrieveindex] - if(istype(P) && (P.loc == src) && src.Adjacent(usr)) - usr.put_in_hands(P) - updateUsrDialog() - flick("[initial(icon_state)]-open",src) +/obj/structure/filing_cabinet/records/medical/collate_data(var/datum/computer_file/report/crew_record/record) + . = list() + . += "Name: [record.get_name()]" + . += "Gender: [record.get_gender()]" + . += "Species: [record.get_species_name()]" + . += "Blood Type: [record.get_bloodtype()]" + . += "Details: [record.get_medical_record()]" + return jointext(., "
    ") + +/obj/structure/filing_cabinet/records/employment + name = "employment record archive" + archive_name = "employment record" + +/obj/structure/filing_cabinet/records/employment/collate_data(var/datum/computer_file/report/crew_record/record) + . = list() + . += "Name: [record.get_name()]" + . += "Gender: [record.get_gender()]" + . += "Species: [record.get_species_name()]" + . += "Details: [record.get_employment_record()]" + return jointext(., "
    ") + +/obj/structure/filing_cabinet/records/security + name = "security record archive" + archive_name = "security record" + +/obj/structure/filing_cabinet/records/security/collate_data(var/datum/computer_file/report/crew_record/record) + . = list() + . += "Name: [record.get_name()]" + . += "Gender: [record.get_gender()]" + . += "Species: [record.get_species_name()]" + . += "Details: [record.get_security_record()]" + return jointext(., "
    ") diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index dfa0bcf1a812..f8f0e65df56b 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -1,123 +1,108 @@ +/////////////////////////////////////////////// +// Folder +/////////////////////////////////////////////// /obj/item/folder - name = "folder" - desc = "A folder." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "folder" - w_class = ITEM_SIZE_SMALL + name = "folder" + desc = "A folder." + icon = 'icons/obj/items/folders.dmi' + icon_state = "folder" + w_class = ITEM_SIZE_SMALL + drop_sound = 'sound/foley/paperpickup1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + material = /decl/material/solid/organic/cardboard + item_flags = ITEM_FLAG_CAN_TAPE + /// If true, add a cosmetic overlay when we have contents. + var/has_paper_overlay = TRUE /obj/item/folder/blue - desc = "A blue folder." + desc = "A blue folder." icon_state = "folder_blue" /obj/item/folder/red - desc = "A red folder." + desc = "A red folder." icon_state = "folder_red" /obj/item/folder/yellow - desc = "A yellow folder." + desc = "A yellow folder." icon_state = "folder_yellow" /obj/item/folder/cyan - desc = "A cyan folder." + desc = "A cyan folder." icon_state = "folder_cyan" /obj/item/folder/on_update_icon() - overlays.Cut() - if(contents.len) - overlays += "folder_paper" - return - -/obj/item/folder/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/paper) || istype(W, /obj/item/photo) || istype(W, /obj/item/paper_bundle)) - if(!user.unEquip(W, src)) - return - to_chat(user, "You put the [W] into \the [src].") + . = ..() + if(has_paper_overlay && length(contents)) + add_overlay("folder_paper") + +/obj/item/folder/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo) || istype(used_item, /obj/item/paper_bundle)) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, SPAN_NOTICE("You put the [used_item] into \the [src].")) + updateUsrDialog() update_icon() - else if(istype(W, /obj/item/pen)) - var/n_name = sanitizeSafe(input(usr, "What would you like to label the folder?", "Folder Labelling", null) as text, MAX_NAME_LEN) - if((loc == usr && usr.stat == 0)) - SetName("folder[(n_name ? text("- '[n_name]'") : null)]") - return + return TRUE + + else if(IS_PEN(used_item)) + updateUsrDialog() + var/n_name = sanitize_safe(input(user, "What would you like to label the folder?", "Folder Labelling", null) as text, MAX_NAME_LEN) + if(!CanPhysicallyInteractWith(user, src)) + to_chat(user, SPAN_WARNING("You must stay close to \the [src].")) + return TRUE + SetName("folder[(n_name ? text("- '[n_name]'") : null)]") + return TRUE + return ..() /obj/item/folder/attack_self(mob/user) + return interact(user) + +/obj/item/folder/interact(mob/user) var/dat = "[name]" - for(var/obj/item/paper/P in src) - dat += "Remove Rename - [P.name]
    " - for(var/obj/item/photo/Ph in src) - dat += "Remove Rename - [Ph.name]
    " - for(var/obj/item/paper_bundle/Pb in src) - dat += "Remove Rename - [Pb.name]
    " - show_browser(user, dat, "window=folder") - onclose(user, "folder") - add_fingerprint(usr) - return - -/obj/item/folder/Topic(href, href_list) - ..() - if((usr.stat || usr.restrained())) - return + for(var/obj/item/I in src) + dat += "Remove Rename - [I.name]
    " + + user.set_machine(src) + show_browser(user, dat, "window=[initial(name)]") + onclose(user, initial(name)) + return TRUE + +/obj/item/folder/DefaultTopicState() + return global.physical_topic_state + +/obj/item/folder/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["remove"]) + var/obj/item/P = locate(href_list["remove"]) + user.put_in_hands(P) + . = TOPIC_REFRESH + else + . = handle_paper_stack_shared_topics(user, href_list) - if(src.loc == usr) - - if(href_list["remove"]) - var/obj/item/P = locate(href_list["remove"]) - if(P && (P.loc == src) && istype(P)) - usr.put_in_hands(P) - - else if(href_list["read"]) - var/obj/item/paper/P = locate(href_list["read"]) - if(P && (P.loc == src) && istype(P)) - if(!(istype(usr, /mob/living/carbon/human) || isghost(usr) || istype(usr, /mob/living/silicon))) - show_browser(usr, "[P.name][stars(P.show_info(usr))][P.stamps]", "window=[P.name]") - onclose(usr, "[P.name]") - else - show_browser(usr, "[P.name][P.show_info(usr)][P.stamps]", "window=[P.name]") - onclose(usr, "[P.name]") - else if(href_list["look"]) - var/obj/item/photo/P = locate(href_list["look"]) - if(P && (P.loc == src) && istype(P)) - P.show(usr) - else if(href_list["browse"]) - var/obj/item/paper_bundle/P = locate(href_list["browse"]) - if(P && (P.loc == src) && istype(P)) - P.attack_self(usr) - onclose(usr, "[P.name]") - else if(href_list["rename"]) - var/obj/item/O = locate(href_list["rename"]) - - if(O && (O.loc == src)) - if(istype(O, /obj/item/paper)) - var/obj/item/paper/to_rename = O - to_rename.rename() - - else if(istype(O, /obj/item/photo)) - var/obj/item/photo/to_rename = O - to_rename.rename() - - else if(istype(O, /obj/item/paper_bundle)) - var/obj/item/paper_bundle/to_rename = O - to_rename.rename() - - //Update everything - attack_self(usr) + //Update everything + if(. & TOPIC_REFRESH) + updateUsrDialog() update_icon() - return +/////////////////////////////////////////////// +// Envelope +/////////////////////////////////////////////// /obj/item/folder/envelope name = "envelope" desc = "A thick envelope. You can't see what's inside." icon_state = "envelope_sealed" + has_paper_overlay = FALSE var/sealed = 1 /obj/item/folder/envelope/on_update_icon() + . = ..() if(sealed) icon_state = "envelope_sealed" else icon_state = "envelope[contents.len > 0]" -/obj/item/folder/envelope/examine(mob/user) +/obj/item/folder/envelope/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The seal is [sealed ? "intact" : "broken"].") + . += "The seal is [sealed ? "intact" : "broken"]." /obj/item/folder/envelope/proc/sealcheck(user) var/ripperoni = alert("Are you sure you want to break the seal on \the [src]?", "Confirmation","Yes", "No") @@ -134,9 +119,9 @@ else ..() -/obj/item/folder/envelope/attackby(obj/item/W, mob/user) +/obj/item/folder/envelope/attackby(obj/item/used_item, mob/user) if(sealed) sealcheck(user) - return + return TRUE else - ..() \ No newline at end of file + return ..() \ No newline at end of file diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index c91a77a0645b..23df3cdf036e 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -1,66 +1,277 @@ +#define HAND_LABELER_MODE_ADD 0 //Add a new label if possible +#define HAND_LABELER_MODE_REM 1 //Remove the last label +#define HAND_LABELER_MODE_REMALL 2 //Remove all labels +//Mode names +#define HAND_LABELER_SAFETY_TOGGLE "Safety" +#define HAND_LABELER_MODE_ADD_NAME "Label" +#define HAND_LABELER_MODE_REM_NAME "Remove one" +#define HAND_LABELER_MODE_REMALL_NAME "Remove all" + +#define LABEL_MATERIAL_COST 120 //units of matter a single label is worth + +////////////////////////////////////////////////////// +// Hand Labeler +////////////////////////////////////////////////////// /obj/item/hand_labeler - name = "hand labeler" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "labeler0" - item_state = "flight" - var/label = null - var/labels_left = 30 - var/mode = 0 //off or on. - material = /decl/material/solid/plastic - -/obj/item/hand_labeler/attack() - return - -/obj/item/hand_labeler/afterattack(atom/A, mob/user, proximity) - if(!proximity) - return - if(!mode) //if it's off, give up. - return - if(A == loc) // if placing the labeller into something (e.g. backpack) - return // don't set a label + name = "hand labeler" + icon = 'icons/obj/items/hand_labeler.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/plastic + w_class = ITEM_SIZE_SMALL + item_flags = ITEM_FLAG_NO_BLUDGEON + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, //These things always got some metal parts + ) + var/label //What the labeler will label its target with + var/labels_left = 30 + var/tmp/max_labels = 30 //Maximum amount of label charges + var/safety = TRUE //Whether the safety is on or off. Set to FALSE to allow labeler to interact with things + var/mode = HAND_LABELER_MODE_ADD //What operation the labeler is set to do - if(!labels_left) - to_chat(user, "No labels left.") - return - if(!label || !length(label)) - to_chat(user, "No label text set.") +/obj/item/hand_labeler/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance < 1) + . += safety? "Safety is on." : SPAN_WARNING("Safety is off!") + var/modename + switch(mode) + if(HAND_LABELER_MODE_ADD) + modename = HAND_LABELER_MODE_ADD_NAME + if(HAND_LABELER_MODE_REM) + modename = HAND_LABELER_MODE_REM_NAME + if(HAND_LABELER_MODE_REMALL) + modename = HAND_LABELER_MODE_REMALL_NAME + . += "It's set to '[SPAN_ITALIC(modename)]' mode." + . += "It has [get_labels_left()]/[max_labels] label(s)." + if(length(label)) + . += "Its label text reads '[SPAN_ITALIC(label)]'." + else + . += SPAN_NOTICE("You're too far away to tell much more.") + +/obj/item/hand_labeler/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE + +/obj/item/hand_labeler/afterattack(atom/movable/A, mob/user, proximity) + if(safety || !proximity || !istype(A) || A == loc) return - if(has_extension(A, /datum/extension/labels)) - var/datum/extension/labels/L = get_extension(A, /datum/extension/labels) - if(!L.CanAttachLabel(user, label)) - return - A.attach_label(user, src, label) -/atom/proc/attach_label(var/user, var/atom/labeler, var/label_text) - to_chat(user, "The label refuses to stick to [name].") + switch(mode) + if(HAND_LABELER_MODE_ADD) + if(!get_labels_left()) + to_chat(user, SPAN_WARNING("No labels left.")) + return + if(!length(label)) + to_chat(user, SPAN_WARNING("No label text set.")) + return + if(A.attach_label(user, src, label)) + rem_paper_labels(1) + + if(HAND_LABELER_MODE_REM, HAND_LABELER_MODE_REMALL) + var/datum/extension/labels/L = get_extension(A, /datum/extension/labels) + if(!LAZYLEN(L?.labels)) + to_chat(user, SPAN_WARNING("\The [A] is not labeled!")) + return + + var/nb_removed + var/removed = L.labels[L.labels.len] + if(mode == HAND_LABELER_MODE_REMALL) + L.RemoveAllLabels() + nb_removed = length(L.labels) + else + L.RemoveLabel(user, L.labels[L.labels.len]) + nb_removed = 1 -/mob/observer/attach_label(var/user, var/atom/labeler, var/label_text) - to_chat(user, "\The [labeler] passes through \the [src].") + user.visible_message( + SPAN_NOTICE("[user] removes [nb_removed > 1? "some labels" : "a label"] from \the [A]."), + SPAN_NOTICE("You remove [nb_removed > 1? "[nb_removed] labels" : "the '[removed]' label"] from \the [A].") + ) + playsound(loc, 'sound/items/poster_ripped.ogg', 50, TRUE) + + //Update stuff + A.queue_icon_update() //Ask them to update their icons if possible + update_icon() + +/obj/item/hand_labeler/proc/show_action_radial_menu(var/mob/user) + //#TODO: Cache some of that stuff. + var/image/btn_power = image('icons/screen/radial.dmi', icon_state = safety? "radial_power" : "radial_power_off") + btn_power.plane = FLOAT_PLANE + btn_power.layer = FLOAT_LAYER + btn_power.name = "Turn Safety [safety? "Off": "On"]" + var/image/btn_set_label = new() + btn_set_label.appearance = src + btn_set_label.plane = FLOAT_PLANE + btn_set_label.layer = FLOAT_LAYER + btn_set_label.name = "Set Label Text" + var/image/btn_rem_one = new() + btn_rem_one.appearance = src + btn_rem_one.plane = FLOAT_PLANE + btn_rem_one.layer = FLOAT_LAYER + btn_rem_one.name = "Remove One" + var/image/btn_rem_all = new() + btn_rem_all.appearance = src + btn_rem_all.plane = FLOAT_PLANE + btn_rem_all.layer = FLOAT_LAYER + btn_rem_all.name = "Remove All" + + var/list/choices = list( + HAND_LABELER_SAFETY_TOGGLE = btn_power, + HAND_LABELER_MODE_ADD_NAME = btn_set_label, + HAND_LABELER_MODE_REM_NAME = btn_rem_one, + HAND_LABELER_MODE_REMALL_NAME = btn_rem_all, + ) + return show_radial_menu(user, user, choices, use_labels = RADIAL_LABELS_OFFSET) + +/obj/item/hand_labeler/attack_self(mob/user) + var/choice = show_action_radial_menu(user) + switch(choice) + if(HAND_LABELER_SAFETY_TOGGLE) + safety = !safety + playsound(user, 'sound/machines/click.ogg', 30, TRUE) + to_chat(loc, SPAN_NOTICE("You toggle the safety [safety? "on" : "off"]!")) + + if(HAND_LABELER_MODE_ADD_NAME) + to_chat(user, SPAN_NOTICE("You switch to labeling mode.")) + var/str = sanitize_safe(input(user,"Label text?", "Set label", label), MAX_LNAME_LEN) + if(!length(str)) + return + label = str + mode = HAND_LABELER_MODE_ADD + to_chat(user, SPAN_NOTICE("You set the label text to '[str]'.")) + + if(HAND_LABELER_MODE_REMALL_NAME, HAND_LABELER_MODE_REM_NAME) + mode = (choice == HAND_LABELER_MODE_REMALL_NAME)? HAND_LABELER_MODE_REMALL : HAND_LABELER_MODE_REM + to_chat(user, SPAN_NOTICE("You switch to remove [mode == HAND_LABELER_MODE_REMALL? "all labels" : "one label"] mode.")) + playsound(loc, 'sound/effects/pop.ogg', 10) + if(prob(5)) + spark_at(src, amount = 2) + + update_icon() + return TRUE -/obj/machinery/portable_atmospherics/hydroponics/attach_label(var/user) +/obj/item/hand_labeler/attackby(obj/item/used_item, mob/user) + + //Allow refilling with paper sheets too + if(istype(used_item, /obj/item/paper)) + var/obj/item/paper/P = used_item + if(!P.is_blank()) + to_chat(user, SPAN_WARNING("\The [P] is not blank. You can't use that for refilling \the [src].")) + return TRUE + + var/incoming_amt = LAZYACCESS(P.matter, /decl/material/solid/organic/paper) + var/current_amt = LAZYACCESS(matter, /decl/material/solid/organic/paper) + var/label_added = incoming_amt / LABEL_MATERIAL_COST + + if(incoming_amt < LABEL_MATERIAL_COST) + to_chat(user, SPAN_WARNING("\The [P] does not contains enough paper.")) + return TRUE + if(((incoming_amt + current_amt) / LABEL_MATERIAL_COST) > max_labels) + to_chat(user, SPAN_WARNING("There's not enough room in \the [src] for the [label_added] label(s) \the [P] is worth.")) + return TRUE + if(!user.do_skilled(2 SECONDS, SKILL_LITERACY, src) || (QDELETED(used_item) || QDELETED(src))) + return TRUE + + to_chat(user, SPAN_NOTICE("You slice \the [P] into [label_added] small strips and insert them into \the [src]'s paper feed.")) + add_paper_labels(label_added) + qdel(used_item) + update_icon() + return TRUE + + //Allow reloading from stacks much faster + else if(istype(used_item, /obj/item/stack/material)) + var/obj/item/stack/material/ST = used_item + var/decl/material/M = ST.material + var/max_accepted_labels = max_labels - get_labels_left() + var/max_accepted_units = max_accepted_labels * LABEL_MATERIAL_COST + var/available_units = ST.get_amount() * SHEET_MATERIAL_AMOUNT + var/added_labels = 0 + + if(available_units > max_accepted_units) + //Take only what's needed + var/needed_sheets = ceil(max_accepted_units / SHEET_MATERIAL_AMOUNT) + var/leftover_units = max_accepted_units % SHEET_MATERIAL_AMOUNT + ST.use(needed_sheets) + //Drop the extra as shards + if(leftover_units) + M.place_cuttings(get_turf(user), leftover_units) + to_chat(user, SPAN_NOTICE("Some leftover [ST.singular_name] cuttings fall to the ground...")) + add_paper_labels(max_accepted_labels) + added_labels = max_accepted_labels + to_chat(user, SPAN_NOTICE("You use [max_accepted_units/SHEET_MATERIAL_AMOUNT] [ST.plural_name] to refill \the [src] with [added_labels] label(s).")) + + else if(available_units > LABEL_MATERIAL_COST) + //Take all that's available + ST.use(ceil(available_units/SHEET_MATERIAL_AMOUNT)) + added_labels = round(available_units / LABEL_MATERIAL_COST) + add_paper_labels(added_labels) + to_chat(user, SPAN_NOTICE("You use [ceil(available_units/SHEET_MATERIAL_AMOUNT)] [ST.plural_name] to refill \the [src] with [added_labels] label(s).")) + else + //Abort because not enough materials for even a single label + to_chat(user, SPAN_WARNING("There's not enough [ST.plural_name] in \the [ST] to refil \the [src]!")) + + update_icon() + return TRUE + return ..() + +/**Gets the amount of labels we can apply with our current supply of paper. */ +/obj/item/hand_labeler/proc/get_labels_left() + return labels_left + +/**Adds a paper label to the labeler if there's room for it. */ +/obj/item/hand_labeler/proc/add_paper_labels(var/amount) + if(get_labels_left() >= max_labels || amount <= 0) + return FALSE + labels_left = clamp((labels_left + amount), 0, max_labels) + update_icon() + return TRUE + +/**Remove a paper label from the labeler if there's any. */ +/obj/item/hand_labeler/proc/rem_paper_labels(var/amount) + if(get_labels_left() <= 0 || amount <= 0) + return FALSE + labels_left = clamp((labels_left - amount), 0, max_labels) + update_icon() + return TRUE + +/obj/item/hand_labeler/dump_contents(atom/forced_loc = loc, mob/user) + . = ..() + //Dump label paper left + if(labels_left > 0) + var/decl/material/M = GET_DECL(/decl/material/solid/organic/paper) + var/turf/T = get_turf(forced_loc) + var/total_sheets = round((labels_left * LABEL_MATERIAL_COST) / SHEET_MATERIAL_AMOUNT) + var/leftovers = round((labels_left * LABEL_MATERIAL_COST) % SHEET_MATERIAL_AMOUNT) + M.create_object(T, total_sheets) + if(leftovers > 0) + M.place_cuttings(T, leftovers) + +//////////////////////////////////////////////////////////// +// Attach Label Overrides +//////////////////////////////////////////////////////////// +/atom/proc/attach_label(var/mob/user, var/atom/labeler, var/label_text) + to_chat(user, SPAN_WARNING("The label refuses to stick to \the [src].")) + return FALSE + +/mob/observer/attach_label(mob/user, atom/labeler, label_text) + to_chat(user, SPAN_DANGER("\The [labeler] passes through \the [src]!")) + return FALSE + +/obj/machinery/portable_atmospherics/hydroponics/attach_label(mob/user, atom/labeler, label_text) if(!mechanical) - to_chat(user, "How are you going to label that?") + to_chat(user, SPAN_WARNING("How are you going to label that?")) return - ..() + . = ..() update_icon() -/obj/attach_label(var/user, var/atom/labeler, var/label_text) +/obj/attach_label(mob/user, atom/labeler, label_text) if(!simulated) return var/datum/extension/labels/L = get_or_create_extension(src, /datum/extension/labels) - L.AttachLabel(user, label_text) + return L.AttachLabel(user, label_text) -/obj/item/hand_labeler/attack_self(mob/user) - mode = !mode - icon_state = "labeler[mode]" - if(mode) - to_chat(user, "You turn on \the [src].") - //Now let them chose the text. - var/str = sanitizeSafe(input(user,"Label text?","Set label",""), MAX_LNAME_LEN) - if(!str || !length(str)) - to_chat(user, "Invalid text.") - return - label = str - to_chat(user, "You set the text to '[str]'.") - else - to_chat(user, "You turn off \the [src].") +#undef HAND_LABELER_MODE_ADD +#undef HAND_LABELER_MODE_REM +#undef HAND_LABELER_MODE_REMALL +#undef HAND_LABELER_SAFETY_TOGGLE +#undef HAND_LABELER_MODE_ADD_NAME +#undef HAND_LABELER_MODE_REM_NAME +#undef HAND_LABELER_MODE_REMALL_NAME +#undef LABEL_MATERIAL_COST \ No newline at end of file diff --git a/code/modules/paperwork/helpers.dm b/code/modules/paperwork/helpers.dm new file mode 100644 index 000000000000..520d67dfef73 --- /dev/null +++ b/code/modules/paperwork/helpers.dm @@ -0,0 +1,35 @@ +/**Handles topic interactions shared by folders and clipboard.*/ +/proc/handle_paper_stack_shared_topics(var/mob/user, var/list/href_list) + if(href_list["rename"]) + var/obj/item/O = locate(href_list["rename"]) + if(istype(O, /obj/item/paper)) + var/obj/item/paper/to_rename = O + to_rename.rename() + . = TOPIC_REFRESH + + else if(istype(O, /obj/item/photo)) + var/obj/item/photo/to_rename = O + to_rename.rename() + . = TOPIC_REFRESH + + else if(istype(O, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/to_rename = O + to_rename.rename() + . = TOPIC_REFRESH + + else if(href_list["examine"]) + var/obj/item/P = locate(href_list["examine"]) + if(istype(P, /obj/item/paper)) + var/obj/item/paper/PP = P + PP.attack_self(user) + . = TOPIC_HANDLED + + else if(istype(P, /obj/item/photo)) + var/obj/item/photo/PP = P + PP.attack_self(user) + . = TOPIC_HANDLED + + else if(istype(P, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/PP = P + PP.attack_self(user) + . = TOPIC_HANDLED diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm deleted file mode 100644 index 5223fef376ab..000000000000 --- a/code/modules/paperwork/paper.dm +++ /dev/null @@ -1,479 +0,0 @@ -// large amount of fields creates a heavy load on the server, see updateinfolinks() and addtofield() -#define MAX_FIELDS 50 - -/* - * Paper - * also scraps of paper - */ - -/obj/item/paper - name = "sheet of paper" - gender = NEUTER - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "paper" - item_state = "paper" - randpixel = 8 - throwforce = 0 - w_class = ITEM_SIZE_TINY - throw_range = 1 - throw_speed = 1 - layer = ABOVE_OBJ_LAYER - slot_flags = SLOT_HEAD - body_parts_covered = HEAD - attack_verb = list("bapped") - - var/info //What's actually written on the paper. - var/info_links //A different version of the paper which includes html links at fields and EOF - var/stamps //The (text for the) stamps on the paper. - var/fields //Amount of user created fields - var/free_space = MAX_PAPER_MESSAGE_LEN - var/list/stamped - var/list/ico[0] //Icons and - var/list/offset_x[0] //offsets stored for later - var/list/offset_y[0] //usage by the photocopier - var/rigged = 0 - var/spam_flag = 0 - var/last_modified_ckey - var/age = 0 - var/list/metadata - - var/const/deffont = "Verdana" - var/const/signfont = "Times New Roman" - var/const/crayonfont = "Comic Sans MS" - var/const/fancyfont = "Segoe Script" - - var/scan_file_type = /datum/computer_file/data/text - -/obj/item/paper/Initialize(mapload, text, title, list/md = null) - . = ..(mapload) - set_content(text ? text : info, title) - metadata = md - if(!mapload) - SSpersistence.track_value(src, /datum/persistent/paper) - -/obj/item/paper/proc/set_content(text,title) - if(title) - SetName(title) - info = html_encode(text) - info = parsepencode(text) - update_icon() - update_space(info) - updateinfolinks() - -/obj/item/paper/on_update_icon() - if(icon_state == "paper_talisman") - return - else if(info) - icon_state = "paper_words" - else - icon_state = "paper" - -/obj/item/paper/proc/update_space(var/new_text) - if(new_text) - free_space -= length(strip_html_properly(new_text)) - -/obj/item/paper/examine(mob/user, distance) - . = ..() - if(name != "sheet of paper") - to_chat(user, "It's titled '[name]'.") - if(distance <= 1) - show_content(usr) - else - to_chat(user, "You have to go closer if you want to read it.") - -/obj/item/paper/proc/show_content(mob/user, forceshow) - var/show_info = user.handle_reading_literacy(user, info, FALSE, (forceshow || get_dist(src, user) <= 1)) - if(show_info) - show_browser(user, "[name][show_info][stamps]", "window=[name]") - onclose(user, "[name]") - -/obj/item/paper/verb/rename() - set name = "Rename paper" - set category = "Object" - set src in usr - - if((MUTATION_CLUMSY in usr.mutations) && prob(50)) - to_chat(usr, "You cut yourself on the paper.") - return - var/n_name = sanitizeSafe(input(usr, "What would you like to label the paper?", "Paper Labelling", null) as text, MAX_NAME_LEN) - - // We check loc one level up, so we can rename in clipboards and such. See also: /obj/item/photo/rename() - if(!n_name || !CanInteract(usr, GLOB.deep_inventory_state)) - return - n_name = usr.handle_writing_literacy(usr, n_name) - if(n_name) - SetName(n_name) - add_fingerprint(usr) - -/obj/item/paper/attack_self(mob/living/user) - if(user.a_intent == I_HURT) - if(icon_state == "scrap") - user.show_message("\The [src] is already crumpled.") - return - //crumple dat paper - info = stars(info,85) - user.visible_message("\The [user] crumples \the [src] into a ball!") - icon_state = "scrap" - return - user.examinate(src) - if(rigged && (global.current_holiday?.name == "April Fool's Day")) - if(spam_flag == 0) - spam_flag = 1 - playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) - spawn(20) - spam_flag = 0 - -/obj/item/paper/attack_ai(var/mob/living/silicon/ai/user) - show_content(user) - -/obj/item/paper/attack(mob/living/carbon/M, mob/living/carbon/user) - if(user.zone_sel.selecting == BP_EYES) - user.visible_message("You show the paper to [M]. ", \ - " [user] holds up a paper and shows it to [M]. ") - M.examinate(src) - - else if(user.zone_sel.selecting == BP_MOUTH) // lipstick wiping - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H == user) - to_chat(user, "You wipe off the lipstick with [src].") - H.lip_style = null - H.update_body() - else - user.visible_message("[user] begins to wipe [H]'s lipstick off with \the [src].", \ - "You begin to wipe off [H]'s lipstick.") - if(do_after(user, 10, H) && do_after(H, 10, needhand = 0)) //user needs to keep their active hand, H does not. - user.visible_message("[user] wipes [H]'s lipstick off with \the [src].", \ - "You wipe off [H]'s lipstick.") - H.lip_style = null - H.update_body() - -/obj/item/paper/proc/addtofield(var/id, var/text, var/links = 0) - var/locid = 0 - var/laststart = 1 - var/textindex = 1 - while(locid < MAX_FIELDS) - var/istart = 0 - if(links) - istart = findtext(info_links, "", laststart) - else - istart = findtext(info, "", laststart) - - if(istart==0) - return // No field found with matching id - - laststart = istart+1 - locid++ - if(locid == id) - var/iend = 1 - if(links) - iend = findtext(info_links, "", istart) - else - iend = findtext(info, "", istart) - - textindex = iend - break - - if(links) - var/before = copytext(info_links, 1, textindex) - var/after = copytext(info_links, textindex) - info_links = before + text + after - else - var/before = copytext(info, 1, textindex) - var/after = copytext(info, textindex) - info = before + text + after - updateinfolinks() - -/obj/item/paper/proc/updateinfolinks() - info_links = info - var/i = 0 - for(i=1,i<=fields,i++) - addtofield(i, "write", 1) - info_links = info_links + "write" - - -/obj/item/paper/proc/clearpaper() - info = null - stamps = null - free_space = MAX_PAPER_MESSAGE_LEN - stamped = list() - overlays.Cut() - updateinfolinks() - update_icon() - -/obj/item/paper/proc/get_signature(var/obj/item/pen/P, mob/user) - if(P && istype(P, /obj/item/pen)) - return P.get_signature(user) - return (user && user.real_name) ? user.real_name : "Anonymous" - -/obj/item/paper/proc/parsepencode(t, obj/item/pen/P, mob/user, iscrayon, isfancy) - if(length(t) == 0) - return "" - - if(findtext(t, "\[sign\]")) - t = replacetext(t, "\[sign\]", "[get_signature(P, user)]") - - if(iscrayon) // If it is a crayon, and he still tries to use these, make them empty! - t = replacetext(t, "\[*\]", "") - t = replacetext(t, "\[hr\]", "") - t = replacetext(t, "\[small\]", "") - t = replacetext(t, "\[/small\]", "") - t = replacetext(t, "\[list\]", "") - t = replacetext(t, "\[/list\]", "") - t = replacetext(t, "\[table\]", "") - t = replacetext(t, "\[/table\]", "") - t = replacetext(t, "\[row\]", "") - t = replacetext(t, "\[cell\]", "") - t = replacetext(t, "\[logo\]", "") - - if(iscrayon) - t = "[t]" - else if(isfancy) - t = "[t]" - else - t = "[t]" - - t = pencode2html(t) - - //Count the fields - var/laststart = 1 - while(fields < MAX_FIELDS) - var/i = findtext(t, "", laststart) // - if(i==0) - break - laststart = i+1 - fields++ - - return t - - -/obj/item/paper/proc/burnpaper(obj/item/flame/P, mob/user) - var/class = "warning" - - if(P.lit && !user.restrained()) - if(istype(P, /obj/item/flame/lighter/zippo)) - class = "rose" - - user.visible_message("[user] holds \the [P] up to \the [src], it looks like \he's trying to burn it!", \ - "You hold \the [P] up to \the [src], burning it slowly.") - - spawn(20) - if(get_dist(src, user) < 2 && user.get_active_hand() == P && P.lit) - user.visible_message("[user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ - "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") - - new /obj/effect/decal/cleanable/ash(get_turf(src)) - qdel(src) - - else - to_chat(user, "You must hold \the [P] steady to burn \the [src].") - - -/obj/item/paper/Topic(href, href_list) - ..() - if(!usr || (usr.stat || usr.restrained())) - return - - if(href_list["write"]) - var/id = href_list["write"] - //var/t = strip_html_simple(input(usr, "What text do you wish to add to " + (id=="end" ? "the end of the paper" : "field "+id) + "?", "[name]", null),8192) as message - - if(free_space <= 0) - to_chat(usr, "There isn't enough space left on \the [src] to write anything.") - return - - var/obj/item/I = usr.get_active_hand() // Check to see if he still got that darn pen, also check what type of pen - var/iscrayon = 0 - var/isfancy = 0 - if(!istype(I, /obj/item/pen)) - if(usr.back && istype(usr.back,/obj/item/rig)) - var/obj/item/rig/r = usr.back - var/obj/item/rig_module/device/pen/m = locate(/obj/item/rig_module/device/pen) in r.installed_modules - if(!r.offline && m) - I = m.device - else - return - else - return - - var/obj/item/pen/P = I - if(!P.active) - P.toggle() - - if(P.iscrayon) - iscrayon = TRUE - - if(P.isfancy) - isfancy = TRUE - - var/t = sanitize(input("Enter what you want to write:", "Write", null, null) as message, free_space, extra = 0, trim = 0) - - if(!t) - return - - // if paper is not in usr, then it must be near them, or in a clipboard or folder, which must be in or near usr - if(src.loc != usr && !src.Adjacent(usr) && !((istype(src.loc, /obj/item/clipboard) || istype(src.loc, /obj/item/folder)) && (src.loc.loc == usr || src.loc.Adjacent(usr)) ) ) - return - - var/last_fields_value = fields - - t = parsepencode(t, I, usr, iscrayon, isfancy) // Encode everything from pencode to html - - - if(fields > MAX_FIELDS) - to_chat(usr, "Too many fields. Sorry, you can't do this.") - fields = last_fields_value - return - - var/processed_text = usr.handle_writing_literacy(usr, t) - - if(id!="end") - addtofield(text2num(id), processed_text) // He wants to edit a field, let him. - else - info += processed_text // Oh, he wants to edit to the end of the file, let him. - updateinfolinks() - - last_modified_ckey = usr.ckey - - update_space(t) - var/processed_info_links = usr.handle_reading_literacy(usr, info_links, TRUE) - if(processed_info_links) - show_browser(usr, "[name][processed_info_links][stamps]", "window=[name]") // Update the window - playsound(src, pick('sound/effects/pen1.ogg','sound/effects/pen2.ogg'), 10) - update_icon() - - -/obj/item/paper/attackby(obj/item/P, mob/user) - ..() - var/clown = 0 - if(user.mind && (user.mind.assigned_role == "Clown")) - clown = 1 - - if(istype(P, /obj/item/tape_roll)) - var/obj/item/tape_roll/tape = P - tape.stick(src, user) - return - - if(istype(P, /obj/item/paper) || istype(P, /obj/item/photo)) - if(!can_bundle()) - return - var/obj/item/paper/other = P - if(istype(other) && !other.can_bundle()) - return - if (istype(P, /obj/item/paper/carbon)) - var/obj/item/paper/carbon/C = P - if (!C.iscopy && !C.copied) - to_chat(user, "Take off the carbon copy first.") - add_fingerprint(user) - return - var/obj/item/paper_bundle/B = new(src.loc) - if (name != "paper") - B.SetName(name) - else if (P.name != "paper" && P.name != "photo") - B.SetName(P.name) - - if(!user.unEquip(P, B) || !user.unEquip(src, B)) - return - user.put_in_hands(B) - - to_chat(user, "You clip the [P.name] to [(src.name == "paper") ? "the paper" : src.name].") - - B.pages.Add(src) - B.pages.Add(P) - B.update_icon() - - else if(istype(P, /obj/item/pen)) - if(icon_state == "scrap") - to_chat(usr, "\The [src] is too crumpled to write on.") - return - - var/obj/item/pen/robopen/RP = P - if ( istype(RP) && RP.mode == 2 ) - RP.RenamePaper(user,src) - else - var/processed_info_links = user.handle_reading_literacy(user, info_links, length(info)) - if(processed_info_links) - show_browser(user, "[name][processed_info_links][stamps]", "window=[name]") - return - - else if(istype(P, /obj/item/stamp) || istype(P, /obj/item/clothing/ring/seal)) - if((!in_range(src, usr) && loc != user && !( istype(loc, /obj/item/clipboard) ) && loc.loc != user && user.get_active_hand() != P)) - return - - stamps += (stamps=="" ? "
    " : "
    ") + "This paper has been stamped with the [P.name]." - - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - var/x - var/y - if(istype(P, /obj/item/stamp/captain) || istype(P, /obj/item/stamp/boss)) - x = rand(-2, 0) - y = rand(-1, 2) - else - x = rand(-2, 2) - y = rand(-3, 2) - offset_x += x - offset_y += y - stampoverlay.pixel_x = x - stampoverlay.pixel_y = y - - if(istype(P, /obj/item/stamp/clown)) - if(!clown) - to_chat(user, "You are totally unable to use the stamp. HONK!") - return - - if(!ico) - ico = new - ico += "paper_[P.icon_state]" - stampoverlay.icon_state = "paper_[P.icon_state]" - - if(!stamped) - stamped = new - stamped += P.type - overlays += stampoverlay - - playsound(src, 'sound/effects/stamp.ogg', 50, 1) - to_chat(user, "You stamp the paper with your [P.name].") - - else if(istype(P, /obj/item/flame)) - burnpaper(P, user) - - else if(istype(P, /obj/item/paper_bundle)) - if(!can_bundle()) - return - var/obj/item/paper_bundle/attacking_bundle = P - attacking_bundle.insert_sheet_at(user, (attacking_bundle.pages.len)+1, src) - attacking_bundle.update_icon() - - add_fingerprint(user) - -/obj/item/paper/proc/can_bundle() - return TRUE - -/obj/item/paper/proc/show_info(var/mob/user) - return info - -//For supply. -/obj/item/paper/manifest - name = "supply manifest" - var/order_total = 0 - var/is_copy = 1 -/* - * Premade paper - */ -/obj/item/paper/court - name = "Judgement" - info = "For crimes as specified, the offender is sentenced to:
    \n
    \n" - -/obj/item/paper/crumpled - name = "paper scrap" - icon_state = "scrap" - -/obj/item/paper/crumpled/on_update_icon() - return - -/obj/item/paper/crumpled/bloody - icon_state = "scrap_bloodied" - -/obj/item/paper/aromatherapy_disclaimer - name = "aromatherapy disclaimer" - info = "The manufacturer and the retailer make no claims of the contained products' effacy.

    Use at your own risk." \ No newline at end of file diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm index 8c8323353713..36e3a047c95d 100644 --- a/code/modules/paperwork/paper_bundle.dm +++ b/code/modules/paperwork/paper_bundle.dm @@ -1,239 +1,538 @@ +#define MAX_PHOTO_OVERLAYS 10 //Maximum amount of photo overlays displayed on the paper bundle +#define MAX_PAPER_UNDERLAYS 20 //Maximum amount of paper underlays displayed under the bundle icon + +/////////////////////////////////////////////////////////////////////////// +// Paper Bundle +/////////////////////////////////////////////////////////////////////////// /obj/item/paper_bundle - name = "paper bundle" - gender = NEUTER - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "paper" - item_state = "paper" - randpixel = 8 - throwforce = 0 - w_class = ITEM_SIZE_SMALL - throw_range = 2 - throw_speed = 1 - layer = ABOVE_OBJ_LAYER - attack_verb = list("bapped") - var/page = 1 // current page - var/list/pages = list() // Ordered list of pages as they are to be displayed. Can be different order than src.contents. - - -/obj/item/paper_bundle/attackby(obj/item/W, mob/user) - ..() - if(!istype(W)) - return - var/obj/item/paper/paper = W - if(istype(paper) && !paper.can_bundle()) - return //non-paper or bundlable paper only - if (istype(W, /obj/item/paper/carbon)) - var/obj/item/paper/carbon/C = W - if (!C.iscopy && !C.copied) - to_chat(user, "Take off the carbon copy first.") - add_fingerprint(user) - return + name = "paper bundle" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paper" + item_state = "paper" + layer = ABOVE_OBJ_LAYER + randpixel = 8 + throw_range = 2 + throw_speed = 1 + w_class = ITEM_SIZE_SMALL + attack_verb = "bapped" + drop_sound = 'sound/foley/paperpickup1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + item_flags = ITEM_FLAG_CAN_TAPE + max_health = 10 + var/tmp/cur_page = 1 // current page + var/tmp/max_pages = 100 //Maximum number of papers that can be in the bundle + var/list/pages // Ordered list of pages as they are to be displayed. Can be different order than src.contents. + +/obj/item/paper_bundle/Destroy() + LAZYCLEARLIST(pages) //Get rid of refs + return ..() + +/obj/item/paper_bundle/attackby(obj/item/used_item, mob/user) + // adding sheets - if(istype(W, /obj/item/paper) || istype(W, /obj/item/photo)) - insert_sheet_at(user, pages.len+1, W) + if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo)) + var/obj/item/paper/paper = used_item + if(istype(paper) && !paper.can_bundle()) + return TRUE //non-paper or bundlable paper only + merge(used_item, user, cur_page) + return TRUE + + // merging bundles + else if(istype(used_item, /obj/item/paper_bundle) && merge(used_item, user, cur_page)) + to_chat(user, SPAN_NOTICE("You add \the [used_item] to \the [name].")) + return TRUE // burning - else if(istype(W, /obj/item/flame)) - burnpaper(W, user) + else if(used_item.isflamesource()) + burnpaper(used_item, user) + return TRUE + + else if(istype(used_item, /obj/item/stack/tape_roll/duct_tape)) + var/obj/P = LAZYACCESS(pages, cur_page) + if(P) + . = P.attackby(used_item, user) + update_icon() + updateUsrDialog() + return + // How did we not have a page? Dunno, fall through to parent call anyway, I guess - // merging bundles - else if(istype(W, /obj/item/paper_bundle)) - for(var/obj/O in W) - O.forceMove(src) - O.add_fingerprint(user) - pages.Add(O) - - to_chat(user, "You add \the [W.name] to [(src.name == "paper bundle") ? "the paper bundle" : src.name].") - qdel(W) - else - if(istype(W, /obj/item/tape_roll)) - return 0 - if(istype(W, /obj/item/pen)) - show_browser(user, "", "window=[name]") //Closes the dialog - var/obj/P = pages[page] - P.attackby(W, user) + else if(IS_PEN(used_item) || istype(used_item, /obj/item/stamp)) + close_browser(user, "window=[name]") + var/obj/P = LAZYACCESS(pages, cur_page) + if(P) + . = P.attackby(used_item, user) + update_icon() + updateUsrDialog() + return + // How did we not have a page? Dunno, fall through to parent call anyway, I guess - update_icon() - attack_self(user) //Update the browsed page. - add_fingerprint(user) - return + return ..() + +/**Check if the bundle should break itself down, and does it if needed. */ +/obj/item/paper_bundle/proc/reevaluate_existence(var/mob/user) + if(LAZYLEN(pages) < 2) + break_bundle(user) -/obj/item/paper_bundle/proc/insert_sheet_at(mob/user, var/index, obj/item/sheet) - if (!user.unEquip(sheet, src)) +/**Insert the given item into the bundle, optionally at the index specified, or otherwise at the end. */ +/obj/item/paper_bundle/proc/insert_sheet_at(var/mob/user, var/obj/item/sheet, var/index = null) + if (user && !user.try_unequip(sheet, src)) return - var/bundle_name = "paper bundle" - var/sheet_name = istype(sheet, /obj/item/photo) ? "photo" : "sheet of paper" - bundle_name = (bundle_name == name) ? "the [bundle_name]" : name - sheet_name = (sheet_name == sheet.name) ? "the [sheet_name]" : sheet.name - - to_chat(user, "You add [sheet_name] to [bundle_name].") - pages.Insert(index, sheet) - if(index <= page) - page++ + else if(!user) + sheet.forceMove(src) -/obj/item/paper_bundle/proc/burnpaper(obj/item/flame/P, mob/user) - var/class = "warning" + if(isnull(index)) + LAZYDISTINCTADD(pages, sheet) + index = length(pages) + else + LAZYINSERT(pages, sheet, index) - if(P.lit && !user.restrained()) - if(istype(P, /obj/item/flame/lighter/zippo)) - class = "rose>" + //Make sure the cur_page stays valid, and pointing at the right index + cur_page = clamp((index <= cur_page)? (cur_page + 1) : cur_page, 1, length(pages)) - user.visible_message("[user] holds \the [P] up to \the [src], it looks like \he's trying to burn it!", \ - "You hold \the [P] up to \the [src], burning it slowly.") + if(user) + to_chat(user, SPAN_NOTICE("You add \the [sheet] as the [get_ordinal_string(index)] page in \the [name].")) + updateUsrDialog() + update_icon() + return TRUE + +/obj/item/paper_bundle/proc/remove_sheet(var/obj/item/I, var/mob/user, var/skip_qdel = FALSE) + var/found = -1 + for(var/i = 1 to length(pages)) + if(pages[i] == I) + found = i + break + if(found == -1) + return + return remove_sheet_at(found, user, skip_qdel) + +/**Indiscriminatly remove sheets from the bundle */ +/obj/item/paper_bundle/proc/remove_sheets(var/amount, var/mob/user, var/delete_pages = TRUE) + if(LAZYLEN(pages) <= 0 || amount > LAZYLEN(pages)) + return //Not a user error + + for(var/i = 1 to amount) + var/obj/item/I = pages[pages.len] + pages -= I + if(delete_pages) + qdel(I) + else + I.dropInto(loc) + reevaluate_existence(user) + + if(!QDELETED(src)) + cur_page = 1 //Reset current page + updateUsrDialog() + update_icon() + return TRUE - spawn(20) - if(get_dist(src, user) < 2 && user.get_active_hand() == P && P.lit) - user.visible_message("[user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ - "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") +/obj/item/paper_bundle/proc/remove_sheet_at(var/index, var/mob/user, var/skip_qdel = FALSE) + var/obj/item/I = LAZYACCESS(pages, index) + if(!I) + return - if(user.get_inactive_hand() == src) - user.drop_from_inventory(src) + LAZYREMOVE(pages, I) + if(user) + user.put_in_hands(I) + to_chat(user, SPAN_NOTICE("You remove the [I.name] from the bundle.")) + else + I.dropInto(loc) - new /obj/effect/decal/cleanable/ash(src.loc) - qdel(src) + if(!skip_qdel) + reevaluate_existence(user) + if(QDELETED(src)) + return TRUE - else - to_chat(user, "You must hold \the [P] steady to burn \the [src].") + //Make sure the cur_page stays valid, and pointing at the right index + cur_page = clamp((cur_page >= index)? (cur_page - 1) : cur_page, 1, length(pages)) -/obj/item/paper_bundle/examine(mob/user, distance) + updateUsrDialog() + update_icon() + return TRUE + +/**Delete the bundle and drop all pages */ +/obj/item/paper_bundle/proc/break_bundle(var/mob/user) + if(user && user == loc) + user.drop_from_inventory(src) + + close_browser(user, "window=[name]") + for(var/obj/item/I in src) + if(user && user.get_empty_hand_slot()) + user.put_in_hands(I) + else + I.add_fingerprint(user) + I.dropInto(loc) + qdel(src) + return TRUE + +/obj/item/paper_bundle/proc/burn_callback(var/obj/item/flame/P, var/mob/user, var/span_class) + if(QDELETED(P) || QDELETED(user)) + return + if(!Adjacent(user) || user.get_active_held_item() != P || !P.lit) + to_chat(user, SPAN_WARNING("You must hold \the [P] steady to burn \the [src].")) + return + user.visible_message( \ + "\The [user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + new /obj/effect/decal/cleanable/ash(loc) + qdel(src) + +/obj/item/paper_bundle/proc/burnpaper(var/obj/item/P, var/mob/user) + if(!P.isflamesource() || user.incapacitated()) + return + var/span_class = istype(P, /obj/item/flame/fuelled/lighter/zippo) ? "rose" : "warning" + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message( \ + "\The [user] holds \the [P] up to \the [src]. It looks like [pronouns.he] [pronouns.is] trying to burn it!", \ + "You hold \the [P] up to \the [src], burning it slowly.") + addtimer(CALLBACK(src, PROC_REF(burn_callback), P, user, span_class), 2 SECONDS) + +/obj/item/paper_bundle/examined_by(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - src.show_content(user) + interact(user) else - to_chat(user, "It is too far away.") + to_chat(user, SPAN_WARNING("It's too far away.")) -/obj/item/paper_bundle/proc/show_content(mob/user) +/obj/item/paper_bundle/interact(mob/user) var/dat - var/obj/item/W = pages[page] - - // first - if(page == 1) - dat+= "" - dat+= "" - dat+= "

    " - // last - else if(page == pages.len) - dat+= "" - dat+= "" - dat+= "

    " - // middle pages + var/obj/item/cur_page_item = LAZYACCESS(pages, cur_page) + //Header + dat = "" + dat += "" + + dat += "" - if(istype(pages[page], /obj/item/paper)) - var/obj/item/paper/P = W - dat+= "[P.name][P.show_info(user)][P.stamps]" + dat += "" + + dat += "" + + dat += "" + dat += "
    " + if(cur_page > 1) + dat += "First" + else + dat += "First" + dat += "" + if(cur_page > 1) + dat += "Previous" else - dat+= "" - dat+= "" - dat+= "

    " + dat += "Previous" + dat += "
    [cur_page]/[length(pages)] Remove" + if(cur_page < pages.len) + dat += "Next" + else + dat += "Next" + dat += "" + if(cur_page < pages.len) + dat += "Last" + else + dat += "Last" + dat += "

    " + + //Contents + if(istype(cur_page_item, /obj/item/paper)) + var/obj/item/paper/cur_paper = cur_page_item + dat += "[cur_paper.name][cur_paper.info][cur_paper.stamp_text]" + show_browser(user, dat, "window=[name]") + onclose(user, name) + + else if(istype(cur_page_item, /obj/item/photo)) + var/obj/item/photo/cur_photo = cur_page_item + dat += {" + [cur_photo.name] +
    Written on the back:
    [cur_photo.scribble]" : null ] + "} + send_rsc(user, cur_photo.img, "tmp_photo.png") show_browser(user, dat, "window=[name]") - else if(istype(pages[page], /obj/item/photo)) - var/obj/item/photo/P = W - dat += "[P.name]" - dat += "
    Written on the back:
    [P.scribble]" : null ]" - send_rsc(user, P.img, "tmp_photo.png") - show_browser(user, JOINTEXT(dat), "window=[name]") + onclose(user, name) + user.set_machine(src) + return TRUE /obj/item/paper_bundle/attack_self(mob/user) - src.show_content(user) - add_fingerprint(user) - update_icon() - return - -/obj/item/paper_bundle/Topic(href, href_list) - if(..()) - return 1 - if((src in usr.contents) || (istype(src.loc, /obj/item/folder) && (src.loc in usr.contents))) - usr.set_machine(src) - var/obj/item/in_hand = usr.get_active_hand() - if(href_list["next_page"]) - if(in_hand && (istype(in_hand, /obj/item/paper) || istype(in_hand, /obj/item/photo))) - insert_sheet_at(usr, page+1, in_hand) - else if(page != pages.len) - page++ - playsound(src.loc, "pageturn", 50, 1) - if(href_list["prev_page"]) - if(in_hand && (istype(in_hand, /obj/item/paper) || istype(in_hand, /obj/item/photo))) - insert_sheet_at(usr, page, in_hand) - else if(page > 1) - page-- - playsound(src.loc, "pageturn", 50, 1) - if(href_list["remove"]) - var/obj/item/W = pages[page] - usr.put_in_hands(W) - pages.Remove(pages[page]) - - to_chat(usr, "You remove the [W.name] from the bundle.") - - if(pages.len <= 1) - var/obj/item/paper/P = src[1] - usr.drop_from_inventory(src) - usr.put_in_hands(P) - qdel(src) + return interact(user) - return +/obj/item/paper_bundle/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() - if(page > pages.len) - page = pages.len + //Handle page turning + if(href_list["next_page"] && (cur_page < LAZYLEN(pages))) + cur_page = clamp(cur_page + 1, 1, length(pages)) + playsound(src.loc, "pageturn", 50, 1) + . = TOPIC_REFRESH + + if(href_list["prev_page"] && (cur_page > 1)) + cur_page = clamp(cur_page - 1, 1, length(pages)) + playsound(src.loc, "pageturn", 50, 1) + . = TOPIC_REFRESH + + if(href_list["first_page"] && (cur_page > 1)) + cur_page = 1 + playsound(src.loc, "pageturn", 50, TRUE) + spawn(5) + playsound(src.loc, "pageturn", 20, TRUE) + . = TOPIC_REFRESH + + if(href_list["last_page"] && (cur_page < LAZYLEN(pages))) + cur_page = length(pages) + playsound(src.loc, "pageturn", 50, TRUE) + spawn(5) + playsound(src.loc, "pageturn", 20, TRUE) + . = TOPIC_REFRESH + + if(href_list["jump_to"]) + var/newpage = input(user, "Page: ", "Which page?", cur_page) as num + if(!CanPhysicallyInteractWith(user, src)) + to_chat(user, SPAN_WARNING("You must stay close to \the [src].")) + else if(newpage > 0 && newpage <= length(pages)) + cur_page = newpage + playsound(src.loc, "pageturn", 50, TRUE) + . = TOPIC_REFRESH + + if(href_list["remove"] && remove_sheet_at(cur_page, user) && !QDELETED(src)) + . = TOPIC_REFRESH + + if(. & TOPIC_REFRESH) + update_icon() + updateUsrDialog() - update_icon() +/obj/item/paper_bundle/on_update_icon() + . = ..() - src.attack_self(usr) - updateUsrDialog() + underlays.Cut() + var/obj/item/paper/P = LAZYACCESS(pages, 1) + if(P) + icon = P.icon + icon_state = P.icon_state + copy_overlays(P) + + var/paper_count = 0 + var/photo_count = 0 + + for(var/obj/O in pages) + if(istype(O, /obj/item/paper) && (paper_count < MAX_PAPER_UNDERLAYS)) + //We can't even see them, so don't bother create appearences form each paper's icon, and use a generic one + var/mutable_appearance/img = mutable_appearance('icons/obj/bureaucracy.dmi', "paper") + img.color = O.color + img.pixel_x -= min(paper_count, 2) + img.pixel_y -= min(paper_count, 2) + default_pixel_x = min(0.5 * paper_count, 1) + default_pixel_y = min(paper_count, 2) + reset_offsets(0) + underlays += img + paper_count++ + + else if(istype(O, /obj/item/photo) && (photo_count < MAX_PHOTO_OVERLAYS)) + var/obj/item/photo/Ph = O + if(photo_count < 1) + add_overlay(Ph.tiny) + else + add_overlay("photo") //We can't even see them, so don't bother create new unique appearences + photo_count++ + + //Break if we have nothing else to do + if((paper_count >= MAX_PAPER_UNDERLAYS) && (photo_count >= MAX_PHOTO_OVERLAYS)) + break + + if(paper_count > 1) + desc = "[paper_count] papers clipped to each other." else - to_chat(usr, "You need to hold it in hands!") + desc = "A single sheet of paper." + + if(photo_count > 1) + desc += "\nThere are [photo_count] photos attached to it." + else if(photo_count > 0) + desc += "\nThere is a photo attached to it." + + add_overlay("clip") + +/** + * Merge another bundle or paper into us. + */ +/obj/item/paper_bundle/proc/merge(var/obj/item/I, var/mob/user, var/at_hint = null) + + //Merge lone paper + if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo)) + var/obj/item/paper/P = I + if(is_full() || (istype(P) && !P.can_bundle())) //Only paper check if they can be bundled apparently + return FALSE + //Merge the thing + insert_sheet_at(user, I, at_hint) + if(user) + if(!user.try_unequip(I, src)) + to_chat(user, SPAN_WARNING("You can't unequip \the [I]!")) + return + I.add_fingerprint(user) + else + I.forceMove(src) + + //Update + update_icon() + updateUsrDialog() + return TRUE + + //Merge paper bundle + else if(istype(I, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = I + if(LAZYLEN(B.pages) <= 0) + return FALSE + + var/cur_num_pages = LAZYLEN(pages) + if(cur_num_pages == max_pages) + return FALSE + + //Merge the paper lists + var/num_added = min(max_pages, LAZYLEN(pages) + LAZYLEN(B.pages)) - cur_num_pages + var/insert_index = ((!isnull(at_hint) && (at_hint >= 0) && (at_hint <= length(pages)))? at_hint : length(pages) + 1) + LAZYINSERT(pages, B.pages, insert_index) + if(length(pages) > max_pages) + pages.Cut(max_pages) + B.pages.Cut(1, num_added + 1) + + //Make sure to move all the things we grabbed from the old stack + for(var/obj/item/O in pages) + if(O.loc != src) + O.forceMove(src) + if(user) + O.add_fingerprint(user) + + //Update + update_icon() + updateUsrDialog() + + //If old stack now empty, delete it + if(LAZYLEN(B.pages) <= 0) + qdel(B) + else + B.cur_page = 1 //Make sure the other bundle won't runtime + B.update_icon() + return TRUE + + CRASH("Tried to merge \a [I] ([I?.type]), which has an unhandled type, into a paper bundle!") + +/**Attempts to merge all mergeable papers in the specified location into src. */ +/obj/item/paper_bundle/proc/merge_all_in_loc(var/atom/location, var/mob/user) + if(is_full()) + return + + for(var/obj/item/I in location) + if(is_full()) + break + if(!QDELETED(I) && (istype(I, /obj/item/paper_bundle) || istype(I, /obj/item/paper) || istype(I, /obj/item/photo))) + merge(I) + +//Make sure we can be interacted with when inside a folder +/obj/item/paper_bundle/DefaultTopicState() + return global.paper_topic_state + +//We don't contain any matter, since we're not really a material thing. +/obj/item/paper_bundle/create_matter() + UNSETEMPTY(matter) + +/obj/item/paper_bundle/proc/get_amount_papers() + return LAZYLEN(pages) + +/obj/item/paper_bundle/proc/is_full() + return LAZYLEN(pages) >= max_pages + +/**Whether all the papers in the pile are blank /obj/item/paper */ +/obj/item/paper_bundle/proc/is_blank() + for(var/obj/item/I in pages) + if(!istype(I, /obj/item/paper)) + return FALSE + var/obj/item/paper/P = I + if(!P.is_blank()) + return FALSE + return TRUE + +/obj/item/paper_bundle/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/rename/paper_bundle) + LAZYADD(., /decl/interaction_handler/unbundle/paper_bundle) + +/obj/item/paper_bundle/PopulateClone(obj/item/paper_bundle/clone) + clone = ..() + for(var/obj/item/I in pages) + clone.merge(I.Clone()) + return clone /obj/item/paper_bundle/verb/rename() - set name = "Rename bundle" + set name = "Rename Bundle" set category = "Object" set src in usr + if(!CanPhysicallyInteractWith(usr, src)) + to_chat(usr, SPAN_WARNING("You cannot do this currently!")) + return - var/n_name = sanitizeSafe(input(usr, "What would you like to label the bundle?", "Bundle Labelling", null) as text, MAX_NAME_LEN) - if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == 0) - SetName("[(n_name ? text("[n_name]") : "paper")]") + var/n_name = sanitize_safe(input(usr, "What would you like to name \the [src]? (Leave empty to reset name.)", "Renaming", name) as text, MAX_NAME_LEN) + if(CanPhysicallyInteractWith(usr, src) && !QDELETED(src)) + SetName("[length(n_name) ? "[n_name]" : initial(name)]") add_fingerprint(usr) - return +/////////////////////////////////////////////////////////////////////////// +// Paper Refill +/////////////////////////////////////////////////////////////////////////// +/obj/item/paper_bundle/refill + name = "paper refill" + desc = "A bundle of blank sheets of paper." + var/tmp/bundle_size = 30 //Amount of paper sheets in this bundle -/obj/item/paper_bundle/verb/remove_all() - set name = "Loose bundle" - set category = "Object" - set src in usr +/obj/item/paper_bundle/refill/Initialize(ml, material_key) + . = ..() + if(. != INITIALIZE_HINT_QDEL) + setup_contents() - to_chat(usr, "You loosen the bundle.") - for(var/obj/O in src) - O.dropInto(usr.loc) - O.reset_plane_and_layer() - O.add_fingerprint(usr) - qdel(src) +/obj/item/paper_bundle/refill/proc/setup_contents() + for(var/i=1 to bundle_size) + var/obj/item/paper/P = new /obj/item/paper(src) + LAZYADD(pages, P) + update_icon() +/obj/item/paper_bundle/refill/attack_self(mob/user) + return break_bundle(user) -/obj/item/paper_bundle/on_update_icon() - var/obj/item/paper/P = pages[1] - icon_state = P.icon_state - overlays = P.overlays - underlays.Cut() - var/i = 0 - var/photo - for(var/obj/O in src) - var/image/img = image('icons/obj/bureaucracy.dmi') - if(istype(O, /obj/item/paper)) - img.icon_state = O.icon_state - img.pixel_x -= min(1*i, 2) - img.pixel_y -= min(1*i, 2) - pixel_x = min(0.5*i, 1) - pixel_y = min( 1*i, 2) - underlays += img - i++ - else if(istype(O, /obj/item/photo)) - var/obj/item/photo/Ph = O - img = Ph.tiny - photo = 1 - overlays += img - if(i>1) - desc = "[i] papers clipped to each other." - else - desc = "A single sheet of paper." - if(photo) - desc += "\nThere is a photo attached to it." - overlays += image('icons/obj/bureaucracy.dmi', "clip") - return +/obj/item/paper_bundle/refill/interact(mob/user) + return //We don't show the menu + +/obj/item/paper_bundle/refill/insert_sheet_at(mob/user, obj/item/sheet, index) + return //Don't let us insert + +/obj/item/paper_bundle/refill/merge(obj/item/I, mob/user, at_hint) + return //Don't merge + +/obj/item/paper_bundle/refill/break_bundle(mob/user) + user?.try_unequip(src) + var/turf/T = get_turf(src) + for(var/i = 1 to bundle_size) + new /obj/item/paper(T) + qdel(src) + +/obj/item/paper_bundle/refill/on_update_icon() + . = ..() + add_overlay("refill") + +/////////////////////////////////////////////////////////////////////////// +// Interaction Rename +/////////////////////////////////////////////////////////////////////////// +/decl/interaction_handler/rename/paper_bundle + name = "Rename Bundle" + expected_target_type = /obj/item/paper_bundle + examine_desc = "rename $TARGET_THEM$" + +/decl/interaction_handler/rename/paper_bundle/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/paper_bundle/bundle = target + bundle.rename() + +/////////////////////////////////////////////////////////////////////////// +// Interaction Break +/////////////////////////////////////////////////////////////////////////// +/decl/interaction_handler/unbundle/paper_bundle + name = "Unbundle" + expected_target_type = /obj/item/paper_bundle + +/decl/interaction_handler/unbundle/paper_bundle/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/paper_bundle/bundle = target + to_chat(user, SPAN_NOTICE("You loosen \the [target].")) + bundle.break_bundle(user) + +#undef MAX_PHOTO_OVERLAYS +#undef MAX_PAPER_UNDERLAYS diff --git a/code/modules/paperwork/paper_plane.dm b/code/modules/paperwork/paper_plane.dm new file mode 100644 index 000000000000..2e183472066b --- /dev/null +++ b/code/modules/paperwork/paper_plane.dm @@ -0,0 +1,95 @@ +/////////////////////////////////////////////////// +// Paper Plane +/////////////////////////////////////////////////// +/obj/item/paper_plane + name = "paper plane" + desc = "A sheet of paper folded into a plane." + icon = 'icons/obj/items/paperwork/paper_plane.dmi' + icon_state = ICON_STATE_WORLD + layer = ABOVE_OBJ_LAYER + does_spin = FALSE + throw_range = 20 + throw_speed = 1 + w_class = ITEM_SIZE_TINY + item_flags = ITEM_FLAG_CAN_TAPE + attack_verb = list("stabbed", "pricked") + material = /decl/material/solid/organic/paper + var/obj/item/paper/my_paper //The sheet of paper this paper_plane is made of + +/obj/item/paper_plane/proc/set_paper(var/obj/item/paper/_paper) + if(my_paper) + return FALSE + _paper.forceMove(src) + my_paper = _paper + if(my_paper.material) + set_material(my_paper.material.type) + color = my_paper.color + update_icon() + return TRUE + +/obj/item/paper_plane/proc/unfold(var/mob/user) + if(user) + if(!user.try_unequip(src)) + return + user.visible_message(SPAN_NOTICE("\The [user] unfolds \the [src]."), SPAN_NOTICE("You unfold \the [src].")) + if(my_paper) + user.put_in_active_hand(my_paper) + else if(my_paper) + my_paper.dropInto(loc) + my_paper = null + qdel(src) + return TRUE + +/obj/item/paper_plane/throw_impact(atom/hit_atom, datum/thrownthing/TT) + . = ..() + if(isliving(hit_atom)) + var/mob/living/M = hit_atom + //Only hurt if received right into the eyes + if(TT.target_zone == BP_EYES && !(BP_EYES in M.get_covered_body_parts())) + M.apply_damage(1, BRUTE, BP_EYES, 0, src, 0) + M.apply_effects(2, 0, 0, 0, 1, 0, 15) + take_damage(TT.speed * w_class) + +/obj/item/paper_plane/attack_self(mob/user) + if(user.check_intent(I_FLAG_HARM)) + return crumple(user) + return unfold(user) + +/obj/item/paper_plane/proc/crumple(var/mob/user) + if(user) + user.visible_message(SPAN_WARNING("\The [user] crumples \the [src].")) + + if(my_paper) + my_paper.crumple() + unfold(user) + else + //If no paper, just make one + if(user) + user.try_unequip(src) + var/obj/item/paper/P = new(loc) + P.crumple() + qdel(src) + return TRUE + +/////////////////////////////////////////////////// +// Alt Interactions +/////////////////////////////////////////////////// +/decl/interaction_handler/make_paper_plane + name = "Fold Into Paper Plane" + expected_target_type = /obj/item/paper + examine_desc = "make a paper plane" + +/decl/interaction_handler/make_paper_plane/is_possible(obj/item/paper/target, mob/user, obj/item/prop) + return ..() && !target.is_crumpled + +/decl/interaction_handler/make_paper_plane/invoked(atom/target, mob/user, obj/item/prop) + user.visible_message(SPAN_NOTICE("\The [user] folds \the [target] into a plane."), SPAN_NOTICE("You fold \the [target] into a plane.")) + var/obj/item/paper_plane/PP = new + user.try_unequip(target, PP) + PP.set_paper(target) + user.put_in_hands(PP) + return TRUE + +/obj/item/paper/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/make_paper_plane) \ No newline at end of file diff --git a/code/modules/paperwork/paper_sticky.dm b/code/modules/paperwork/paper_sticky.dm index a304aaca6572..d8acfabf7598 100644 --- a/code/modules/paperwork/paper_sticky.dm +++ b/code/modules/paperwork/paper_sticky.dm @@ -1,115 +1,133 @@ +//////////////////////////////////////////////// +// Sticky Note Pad +//////////////////////////////////////////////// /obj/item/sticky_pad - name = "sticky note pad" - desc = "A pad of densely packed sticky notes." - color = COLOR_YELLOW - icon = 'icons/obj/stickynotes.dmi' - icon_state = "pad_full" - item_state = "paper" - w_class = ITEM_SIZE_SMALL - - var/papers = 50 - var/written_text - var/written_by - var/paper_type = /obj/item/paper/sticky + name = "sticky note pad" + desc = "A pad of densely packed sticky notes." + color = COLOR_YELLOW + icon = 'icons/obj/stickynotes.dmi' + icon_state = "pad_full" + item_state = "paper" + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/paper + var/const/max_papers = 50 + var/papers = max_papers + var/paper_type = /obj/item/paper/sticky + var/obj/item/paper/top //The instantiated paper on the top of the pad, if there's one + +/obj/item/sticky_pad/Initialize(ml, material_key) + . = ..() + update_top_paper() + +/obj/item/sticky_pad/Destroy() + top = null + return ..() + +/obj/item/sticky_pad/proc/update_matter() + matter = list( + /decl/material/solid/organic/paper = round((papers * SHEET_MATERIAL_AMOUNT) * 0.2) + ) + +/obj/item/sticky_pad/create_matter() + update_matter() /obj/item/sticky_pad/on_update_icon() + . = ..() if(papers <= 15) icon_state = "pad_empty" - else if(papers <= 50) + else if(papers <= max_papers) icon_state = "pad_used" else icon_state = "pad_full" - if(written_text) + + if(top?.info) icon_state = "[icon_state]_writing" -/obj/item/sticky_pad/attackby(var/obj/item/thing, var/mob/user) - if(istype(thing, /obj/item/pen)) +/obj/item/sticky_pad/attackby(var/obj/item/used_item, var/mob/user) + if(IS_PEN(used_item) || istype(used_item, /obj/item/stamp)) + . = top?.attackby(used_item, user) + update_icon() + return . + return ..() - if(jobban_isbanned(user, "Graffiti")) - to_chat(user, SPAN_WARNING("You are banned from leaving persistent information across rounds.")) - return +/obj/item/sticky_pad/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += SPAN_NOTICE("It has [papers] sticky note\s left.") - var/writing_space = MAX_MESSAGE_LEN - length(written_text) - if(writing_space <= 0) - to_chat(user, SPAN_WARNING("There is no room left on \the [src].")) - return - var/text = sanitizeSafe(input("What would you like to write?") as text, writing_space) - if(!text || thing.loc != user || (!Adjacent(user) && loc != user) || user.incapacitated()) - return - user.visible_message(SPAN_NOTICE("\The [user] jots a note down on \the [src].")) - written_by = user.ckey - if(written_text) - written_text = "[written_text] [text]" - else - written_text = text - update_icon() - return - ..() +/obj/item/sticky_pad/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + LAZYADD(., SPAN_NOTICE("You can click it on grab intent to pick it up.")) -/obj/item/sticky_pad/examine(mob/user) +/obj/item/sticky_pad/dragged_onto(mob/user) + user.put_in_hands(top) . = ..() - to_chat(user, SPAN_NOTICE("It has [papers] sticky note\s left.")) - to_chat(user, SPAN_NOTICE("You can click it on grab intent to pick it up.")) /obj/item/sticky_pad/attack_hand(var/mob/user) - if(user.a_intent == I_GRAB) - ..() + if(user.check_intent(I_FLAG_GRAB)) + return ..() + if(!top) + return TRUE + user.put_in_active_hand(top) + top = null + papers-- + update_top_paper() + to_chat(user, SPAN_NOTICE("You pull \the [top] off \the [src].")) + if(papers <= 0) + qdel(src) else - var/obj/item/paper/paper = new paper_type(get_turf(src)) - paper.set_content(written_text, "sticky note") - paper.last_modified_ckey = written_by - paper.color = color - written_text = null - user.put_in_hands(paper) - to_chat(user, SPAN_NOTICE("You pull \the [paper] off \the [src].")) - papers-- - if(papers <= 0) - qdel(src) - else - update_icon() + update_top_paper() + update_icon() + return TRUE + +/**Creates the paper the user can write on, if there's any paper left. */ +/obj/item/sticky_pad/proc/update_top_paper() + if(!top && papers > 0) + top = new paper_type(src) + top.set_color(color) /obj/item/sticky_pad/random/Initialize() . = ..() - color = pick(COLOR_YELLOW, COLOR_LIME, COLOR_CYAN, COLOR_ORANGE, COLOR_PINK) + set_color(pick(COLOR_YELLOW, COLOR_LIME, COLOR_CYAN, COLOR_ORANGE, COLOR_PINK)) +//////////////////////////////////////////////// +// Sticky Note Sheet +//////////////////////////////////////////////// /obj/item/paper/sticky - name = "sticky note" - desc = "Note to self: buy more sticky notes." - icon = 'icons/obj/stickynotes.dmi' - color = COLOR_YELLOW - slot_flags = 0 - layer = ABOVE_WINDOW_LAYER + name = "sticky note" + desc = "Note to self: buy more sticky notes." + icon = 'icons/obj/items/paperwork/sticky_note.dmi' + color = COLOR_YELLOW + slot_flags = 0 + layer = ABOVE_WINDOW_LAYER + persist_on_init = FALSE + item_flags = ITEM_FLAG_CAN_TAPE /obj/item/paper/sticky/Initialize() . = ..() - GLOB.moved_event.register(src, src, /obj/item/paper/sticky/proc/reset_persistence_tracking) + events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/obj/item/paper/sticky, reset_persistence_tracking)) /obj/item/paper/sticky/proc/reset_persistence_tracking() - SSpersistence.forget_value(src, /datum/persistent/paper/sticky) + SSpersistence.forget_value(src, /decl/persistence_handler/paper/sticky) pixel_x = 0 pixel_y = 0 /obj/item/paper/sticky/Destroy() reset_persistence_tracking() - GLOB.moved_event.unregister(src, src) + events_repository.unregister(/decl/observ/moved, src, src) . = ..() -/obj/item/paper/sticky/on_update_icon() - if(icon_state != "scrap") - icon_state = info ? "paper_words" : "paper" - // Copied from duct tape. /obj/item/paper/sticky/attack_hand() . = ..() - if(!istype(loc, /turf)) + if(!isturf(loc)) reset_persistence_tracking() /obj/item/paper/sticky/can_bundle() return FALSE // Would otherwise lead to buggy interaction -/obj/item/paper/sticky/afterattack(var/A, var/mob/user, var/flag, var/params) +/obj/item/paper/sticky/afterattack(var/atom/A, var/mob/user, var/flag, var/params) - if(!in_range(user, A) || istype(A, /obj/machinery/door) || istype(A, /obj/item/storage) || icon_state == "scrap") + if(!in_range(user, A) || istype(A, /obj/machinery/door) || A.storage || is_crumpled) return var/turf/target_turf = get_turf(A) @@ -118,23 +136,24 @@ var/dir_offset = 0 if(target_turf != source_turf) dir_offset = get_dir(source_turf, target_turf) - if(!(dir_offset in GLOB.cardinal)) + if(!(dir_offset in global.cardinal)) to_chat(user, SPAN_WARNING("You cannot reach that from here.")) return - if(user.unEquip(src, source_turf)) - SSpersistence.track_value(src, /datum/persistent/paper/sticky) + if(user.try_unequip(src, source_turf)) + SSpersistence.track_value(src, /decl/persistence_handler/paper/sticky) if(params) var/list/mouse_control = params2list(params) if(mouse_control["icon-x"]) - pixel_x = text2num(mouse_control["icon-x"]) - 16 + default_pixel_x = text2num(mouse_control["icon-x"]) - 16 if(dir_offset & EAST) - pixel_x += 32 + default_pixel_x += 32 else if(dir_offset & WEST) - pixel_x -= 32 + default_pixel_x -= 32 if(mouse_control["icon-y"]) - pixel_y = text2num(mouse_control["icon-y"]) - 16 + default_pixel_y = text2num(mouse_control["icon-y"]) - 16 if(dir_offset & NORTH) - pixel_y += 32 + default_pixel_y += 32 else if(dir_offset & SOUTH) - pixel_y -= 32 + default_pixel_y -= 32 + reset_offsets(0) diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 8ff14e8380fb..4bc17502521d 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -1,115 +1,168 @@ +///////////////////////////////////////////////////////////////// +// Paper Bin +///////////////////////////////////////////////////////////////// /obj/item/paper_bin - name = "paper bin" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "paper_bin1" - item_state = "sheet-metal" - randpixel = 0 - throwforce = 1 - w_class = ITEM_SIZE_NORMAL - throw_speed = 3 - throw_range = 7 - layer = BELOW_OBJ_LAYER - var/amount = 30 //How much paper is in the bin. - var/list/papers = new/list() //List of papers put in the bin for reference. - - -/obj/item/paper_bin/MouseDrop(mob/user) - if((user == usr && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr)))))) - if(!istype(usr, /mob/living/carbon/slime) && !istype(usr, /mob/living/simple_animal)) - if( !usr.get_active_hand() ) //if active hand is empty - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] - - if (H.hand) - temp = H.organs_by_name[BP_L_HAND] - if(temp && !temp.is_usable()) - to_chat(user, "You try to move your [temp.name], but cannot!") - return - - to_chat(user, "You pick up the [src].") - user.put_in_hands(src) - - return + name = "paper bin" + icon = 'icons/obj/items/paper_bin.dmi' + icon_state = "paper_bin1" + item_state = "sheet-metal" + randpixel = 0 + layer = BELOW_OBJ_LAYER + w_class = ITEM_SIZE_NORMAL + throw_speed = 3 + throw_range = 7 + material = /decl/material/solid/organic/plastic + var/amount = 30 //How much paper is in the bin. + var/tmp/max_amount = 30 //How much paper fits in the bin + var/list/papers //List of papers put in the bin for reference. + +/obj/item/paper_bin/Destroy() + LAZYCLEARLIST(papers) //Gets rid of any refs + return ..() + +/obj/item/paper_bin/handle_mouse_drop(atom/over, mob/user, params) + if((loc == user || in_range(src, user)) && user.get_empty_hand_slot()) + user.put_in_hands(src) + return TRUE + . = ..() /obj/item/paper_bin/attack_hand(mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/temp = H.organs_by_name[BP_R_HAND] - if (H.hand) - temp = H.organs_by_name[BP_L_HAND] - if(temp && !temp.is_usable()) - to_chat(user, "You try to move your [temp.name], but cannot!") - return - var/response = "" - if(!papers.len > 0) - response = alert(user, "Do you take regular paper, or Carbon copy paper?", "Paper type request", "Regular", "Carbon-Copy", "Cancel") - if (response != "Regular" && response != "Carbon-Copy") - add_fingerprint(user) - return - if(amount >= 1) - amount-- - if(amount==0) - update_icon() - - var/obj/item/paper/P - if(papers.len > 0) //If there's any custom paper on the stack, use that instead of creating a new paper. - P = papers[papers.len] - papers.Remove(P) - else - if(response == "Regular") + + // This is required due to the mousedrop code calling attack_hand directly. + if(!CanPhysicallyInteract(user)) + return FALSE + + if(user.check_intent(I_FLAG_HARM) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + + if(LAZYLEN(papers) < 1 && amount < 1) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return TRUE + + var/obj/item/paper/P + if(LAZYLEN(papers) > 0) //If there's any custom paper on the stack, use that instead of creating a new paper. + P = papers[papers.len] + LAZYREMOVE(papers, P) + else + var/paper_kind = input(user, "What kind of paper?") in list("Regular", "Green", "Blue", "Pink", "Yellow", "Carbon-Copy", "Cancel") + switch(paper_kind) + if("Regular") P = new /obj/item/paper - if(global.current_holiday?.name == "April Fool's Day") - if(prob(30)) - P.info = "HONK HONK HONK HONK HONK HONK HONK
    HOOOOOOOOOOOOOOOOOOOOOONK
    APRIL FOOLS
    " - P.rigged = 1 - P.updateinfolinks() - else if (response == "Carbon-Copy") + if("Green") + P = new /obj/item/paper/green + if("Blue") + P = new /obj/item/paper/blue + if("Pink") + P = new /obj/item/paper/pink + if("Yellow") + P = new /obj/item/paper/yellow + if("Carbon-Copy") P = new /obj/item/paper/carbon - user.put_in_hands(P) - to_chat(user, "You take [P] out of the [src].") - else - to_chat(user, "[src] is empty!") + else + return TRUE + + if(!istype(P, /obj/item/paper/carbon) && global.current_holiday?.name == "April Fool's Day" && prob(30)) + P.rigged = TRUE + P.set_content("HONK HONK HONK HONK HONK HONK HONK
    HOOOOOOOOOOOOOOOOOOOOOONK
    APRIL FOOLS
    ") + user.put_in_hands(P) + to_chat(user, SPAN_NOTICE("You take \the [P] out of \the [src].")) + amount-- + update_icon() add_fingerprint(user) - return - - -/obj/item/paper_bin/attackby(obj/item/i, mob/user) - if(istype(i, /obj/item/paper)) - if(!user.unEquip(i, src)) - return - to_chat(user, "You put [i] in [src].") - papers.Add(i) - update_icon() - amount++ - else if(istype(i, /obj/item/paper_bundle)) - to_chat(user, "You loosen \the [i] and add its papers into \the [src].") - var/was_there_a_photo = 0 - for(var/obj/item/bundleitem in i) //loop through items in bundle + return TRUE + +/obj/item/paper_bin/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/paper)) + if(amount >= max_amount) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + add_paper(used_item) + to_chat(user, SPAN_NOTICE("You put [used_item] in [src].")) + return TRUE + else if(istype(used_item, /obj/item/paper_bundle)) + if(amount >= max_amount) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return TRUE + var/obj/item/paper_bundle/B = used_item + var/was_there_a_photo = FALSE + for(var/obj/item/bundleitem in used_item) //loop through items in bundle if(istype(bundleitem, /obj/item/paper)) //if item is paper, add into the bin - papers.Add(bundleitem) - update_icon() - amount++ + LAZYREMOVE(B.pages, bundleitem) + add_paper(bundleitem) else if(istype(bundleitem, /obj/item/photo)) //if item is photo, drop it on the ground - was_there_a_photo = 1 + was_there_a_photo = TRUE bundleitem.dropInto(user.loc) bundleitem.reset_plane_and_layer() - qdel(i) + to_chat(user, SPAN_NOTICE("You loosen \the [used_item] and add its papers into \the [src].")) + B.reevaluate_existence() if(was_there_a_photo) - to_chat(user, "The photo cannot go into \the [src].") - + to_chat(user, SPAN_NOTICE("The photo cannot go into \the [src].")) + return TRUE + return ..() -/obj/item/paper_bin/examine(mob/user, distance) +/obj/item/paper_bin/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance <= 1) - if(amount) - to_chat(user, "There " + (amount > 1 ? "are [amount] papers" : "is one paper") + " in the bin.") - else - to_chat(user, "There are no papers in the bin.") - + if(distance > 1) + return + if(amount) + . += SPAN_NOTICE("There [(amount > 1 ? "are [amount] papers" : "is one paper")] in the bin.") + else + . += SPAN_NOTICE("There are no papers in the bin.") + . += SPAN_NOTICE("It can contain at most [max_amount] papers.") /obj/item/paper_bin/on_update_icon() - if(amount < 1) + . = ..() + if(amount <= 0) icon_state = "paper_bin0" - else + else if(amount <= (max_amount / 3)) icon_state = "paper_bin1" + else if(amount >= max_amount) + icon_state = "paper_bin3" + else + icon_state = "paper_bin2" + +/obj/item/paper_bin/dump_contents(atom/forced_loc = loc, mob/user) + . = ..() + //Dump all stored papers too + for(var/i=1 to amount) + var/obj/item/paper/P = new /obj/item/paper(forced_loc) + P.merge_with_existing(forced_loc, user) + LAZYCLEARLIST(papers) + +/obj/item/paper_bin/proc/add_paper(var/obj/item/paper/P) + if(amount >= max_amount) + return + //Add only non-blank papers into the paper list + if(P.is_blank()) + qdel(P) + else + LAZYDISTINCTADD(papers, P) + P.forceMove(src) + amount++ + update_icon() + return TRUE + +/obj/item/paper_bin/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/paper_bin_dump_contents) + +///////////////////////////////////////////////////////////////// +// Empty Bin Interaction +///////////////////////////////////////////////////////////////// +/decl/interaction_handler/paper_bin_dump_contents + name = "Dump Contents" + expected_target_type = /obj/item/paper_bin + examine_desc = "empty $TARGET_THEM$" + +/decl/interaction_handler/paper_bin_dump_contents/is_possible(var/obj/item/paper_bin/target, mob/user, obj/item/prop) + return ..() && target.amount > 0 + +/decl/interaction_handler/paper_bin_dump_contents/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/paper_bin/bin = target + to_chat(user, SPAN_NOTICE("You start emptying \the [bin]...")) + if(do_after(user, 2 SECONDS) && !QDELETED(bin)) + bin.dump_contents() + to_chat(user, SPAN_NOTICE("You emptied \the [bin].")) diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm index a14c79c63d4b..6a48a772660d 100644 --- a/code/modules/paperwork/papershredder.dm +++ b/code/modules/paperwork/papershredder.dm @@ -1,147 +1,257 @@ +////////////////////////////////////////////////////////////////// +// Paper Shredder +////////////////////////////////////////////////////////////////// /obj/machinery/papershredder - name = "paper shredder" - desc = "For those documents you don't want seen." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "papershredder0" - density = 1 - anchored = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE - obj_flags = OBJ_FLAG_ANCHORABLE - var/max_paper = 10 - var/paperamount = 0 - - var/list/shred_amounts = list( - /obj/item/photo = 1, - /obj/item/shreddedp = 1, - /obj/item/paper = 1, - /obj/item/newspaper = 3, - /obj/item/card/id = 3, - /obj/item/paper_bundle = 3, - /obj/item/forensics/sample/print = 1 - ) - -/obj/machinery/papershredder/attackby(var/obj/item/W, var/mob/user) - - if(istype(W, /obj/item/storage)) - empty_bin(user, W) + name = "paper shredder" + desc = "For those documents you don't want seen." + icon = 'icons/obj/machines/paper_shredder.dmi' + icon_state = "papershredder0" + density = TRUE + anchored = TRUE + atom_flags = ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ANCHORABLE + idle_power_usage = 0 + stat_immune = NOSCREEN | NOINPUT + waterproof = FALSE + construct_state = /decl/machine_construction/default/panel_closed + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + uncreated_component_parts = list( + /obj/item/stock_parts/power/apc = 1 + ) + var/list/shredder_bin //List of shreded material type to matter amount + var/cached_total_matter = 0 //Total of all the matter units we put in the shredder so far + var/tmp/max_total_matter = SHEET_MATERIAL_AMOUNT * 10 //Maximum amount of matter that can be stored inside the bin + +/obj/machinery/papershredder/Initialize() + . = ..() + update_icon() + +/obj/machinery/papershredder/on_component_failure(obj/item/stock_parts/component) + . = ..() + + if(istype(component, /obj/item/stock_parts/circuitboard)) + spark_at(get_turf(src), 30, FALSE, src) + empty_bin(violent = TRUE) + +/**Shreds the given object. */ +/obj/machinery/papershredder/proc/shred(var/obj/item/I, var/mob/user) + if(inoperable()) + to_chat(user, SPAN_WARNING("\The [src] doesn't seem to work.")) + return + if(is_bin_full()) + visible_message(SPAN_WARNING("The \"bin full\" warning light is flashing on \the [src]!")) return + //#TODO: Uncomment this once the bug is fixed, so we check for available power before actually working + // if(!powered() || can_use_power_oneoff(60) <= 0) + // to_chat(user, SPAN_WARNING("\The [src] seems to be lacking power...")) + // return + use_power_oneoff(60) + user.try_unequip(I, src) + + //If the material is too hard damage the shredder + var/decl/material/M = I.material + if(M.hardness > MAT_VALUE_FLEXIBLE && M.hardness < MAT_VALUE_RIGID) + audible_message(SPAN_WARNING("You hear a loud mechanical grinding!")) + take_damage(1, silent = TRUE) + spark_at(get_turf(src), 1, FALSE, src) + . = TRUE + + else if(M.hardness >= MAT_VALUE_RIGID) + audible_message(SPAN_DANGER("You hear rattling and then a loud bang!")) + use_power_oneoff(200) + take_damage(25, silent = TRUE) + set_broken(TRUE, MACHINE_BROKEN_GENERIC) + . = FALSE + else - var/paper_result - for(var/shred_type in shred_amounts) - if(istype(W, shred_type)) - paper_result = shred_amounts[shred_type] - if(paper_result) - if(paperamount == max_paper) - to_chat(user, "\The [src] is full; please empty it before you continue.") - return - paperamount += paper_result - qdel(W) - playsound(src.loc, 'sound/items/pshred.ogg', 75, 1) - if(paperamount > max_paper) - to_chat(user, "\The [src] was too full, and shredded paper goes everywhere!") - for(var/i=(paperamount-max_paper);i>0;i--) - var/obj/item/shreddedp/SP = get_shredded_paper() - SP.dropInto(loc) - SP.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),1,5) - paperamount = max_paper - update_icon() - return - ..() - return - -/obj/machinery/papershredder/verb/empty_contents() - set name = "Empty bin" - set category = "Object" - set src in range(1) - - if(usr.stat || usr.restrained() || usr.weakened || usr.paralysis || usr.lying || usr.stunned) + visible_message(SPAN_NOTICE("\The [src] happily consumes \the [I].")) + . = TRUE + + if(.) + //Move over the matter + for(var/key in I.matter) + if(I.matter[key] < 1) + continue + var/new_matter = LAZYACCESS(shredder_bin, key) + I.matter[key] + cached_total_matter += new_matter + LAZYSET(shredder_bin, key, new_matter) + + I.physically_destroyed() + playsound(get_turf(src), 'sound/items/pshred.ogg', 50, TRUE) + else + I.dropInto(get_turf(user)) + playsound(get_turf(src), 'sound/effects/metalscrape1.ogg', 40, TRUE) + update_icon() + +/obj/machinery/papershredder/proc/is_bin_full() + return cached_total_matter >= max_total_matter + +/obj/machinery/papershredder/proc/is_bin_empty() + return !(length(shredder_bin) > 0 && cached_total_matter) + +/obj/machinery/papershredder/proc/can_shred_document(var/obj/item/I, var/mob/user = null) + if(!istype(I)) + if(user) + to_chat(user, SPAN_WARNING("\The [I] cannot be shredded by \the [src]!")) return - if(!paperamount) - to_chat(usr, "\The [src] is empty.") + //Being one of those types bypasses the checks + if(istype(I, /obj/item/paper) || istype(I, /obj/item/paper_bundle) || istype(I, /obj/item/folder) || istype(I, /obj/item/newspaper) || istype(I, /obj/item/photo)) + return TRUE + + //Generic tests for random objects + if(I.w_class > ITEM_SIZE_TINY) + if(user) + to_chat(user, SPAN_WARNING("\The [I] is too big to be inserted into \the [src]!")) return - empty_bin(usr) + var/decl/material/M = I.material + if(!istype(M) || M.hardness >= MAT_VALUE_HARD) + if(user) + to_chat(user, SPAN_WARNING("\The [I] is obviously not shreddable.")) + return + return TRUE -/obj/machinery/papershredder/proc/empty_bin(var/mob/living/user, var/obj/item/storage/empty_into) - - if(empty_into) // If the user tries to empty the bin into something +/obj/machinery/papershredder/attackby(var/obj/item/used_item, var/mob/user) + //Silently skip tools, and things we don't have the dexterity to use + if(!has_extension(used_item, /datum/extension/tool) && used_item.user_can_attack_with(user, silent = TRUE)) + var/trying_to_smack = !(used_item.item_flags & ITEM_FLAG_NO_BLUDGEON) && user && user.check_intent(I_FLAG_HARM) + if(used_item.storage) + empty_bin(user, used_item) + return TRUE - if(paperamount == 0) // Can't empty what is already empty - to_chat(user, "\The [src] is empty.") - return + else if(!trying_to_smack && can_shred_document(used_item)) + shred(used_item, user) + return TRUE + return ..() - if(empty_into && !istype(empty_into)) // Make sure we can store paper in the thing - to_chat(user, "You cannot put shredded paper into the [empty_into].") - return +/**Creates shredded products, and empty the matter bin */ +/obj/machinery/papershredder/proc/create_shredded() + for(var/key in shredder_bin) + var/decl/material/M = GET_DECL(key) + var/shard_type = M.shard_type + if(!shard_type) + continue + var/amt_per_shard = atom_info_repository.get_matter_for(M.shard_type, key, 1) + if(shredder_bin[key] > amt_per_shard) + LAZYADD(., M.place_cuttings(src, shredder_bin[key])) - // Move papers one by one as they fit; stop when we are empty or can't fit any more - while(paperamount > 0) + //Anything leftover we just assume the machine ate or something + cached_total_matter = 0 + LAZYCLEARLIST(shredder_bin) - var/obj/item/shred_temp = get_shredded_paper() +/**Empties the paper bin into the given container, and/or on the floor. If violent is on, and there's no container passed, we're going to throw around the trash. */ +/obj/machinery/papershredder/proc/empty_bin(var/mob/living/user, var/obj/item/empty_into, var/violent = FALSE) + if(is_bin_empty()) + if(user) + to_chat(user, SPAN_NOTICE("\The [src] is empty.")) + return + if(empty_into && !istype(empty_into) || !empty_into.storage) // Make sure we can store paper in the thing + if(user) + to_chat(user, SPAN_NOTICE("You cannot put shredded paper into the [empty_into].")) + return - if(empty_into.can_be_inserted(shred_temp, user, 0)) - empty_into.handle_item_insertion(shred_temp) - else - qdel(shred_temp) - paperamount++ - break + //If we got a container put what we can into it + var/list/shredded = create_shredded() + if(empty_into) + for(var/obj/item/I in shredded) + if(empty_into.storage.can_be_inserted(I, user, !isnull(user))) + empty_into.storage.handle_item_insertion(null, I, TRUE) + LAZYREMOVE(shredded, I) // Report on how we did - if(paperamount == 0) - to_chat(user, "You empty \the [src] into \the [empty_into].") - if(paperamount > 0) - to_chat(user, "\The [empty_into] will not fit any more shredded paper.") + if(user) + if(length(shredded) < 1) + to_chat(user, SPAN_NOTICE("You empty \the [src] into \the [empty_into].")) + else + to_chat(user, SPAN_NOTICE("\The [empty_into] will not fit any more shredded paper.")) - else // Just dump the paper out on the floor - while(paperamount > 0) - get_shredded_paper() + //Drop the leftovers + if(LAZYLEN(shredded)) + var/turf/T = get_turf(user? user : src) + for(var/obj/item/I in shredded) + I.dropInto(T) + if(violent) + I.throw_at(get_edge_target_turf(src, pick(global.alldirs)), I.throw_range, I.throw_speed) update_icon() - -/obj/machinery/papershredder/proc/get_shredded_paper() - if(paperamount) - paperamount-- - return new /obj/item/shreddedp(get_turf(src)) + return TRUE /obj/machinery/papershredder/on_update_icon() - icon_state = "papershredder[max(0,min(5,Floor(paperamount/2)))]" + cut_overlays() + var/ratio = ((cached_total_matter * 5) / max_total_matter) + icon_state = "papershredder[clamp(ceil(ratio), 0, 5)]" + if(!is_unpowered()) + add_overlay("papershredder_power") + if(is_broken() || is_bin_full()) + add_overlay("papershredder_bad") -/obj/item/shreddedp/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/flame/lighter)) - burnpaper(W, user) - else - ..() +/obj/machinery/papershredder/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/empty/paper_shredder) + +////////////////////////////////////////////////////////////////// +// Empty Bin Interaction +////////////////////////////////////////////////////////////////// +/decl/interaction_handler/empty/paper_shredder + name = "Empty Bin" + expected_target_type = /obj/machinery/papershredder + examine_desc = "empty $TARGET_THEM$" + +/decl/interaction_handler/empty/paper_shredder/is_possible(obj/machinery/papershredder/target, mob/user, obj/item/prop) + return ..() && !target.is_bin_empty() + +/decl/interaction_handler/empty/paper_shredder/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/papershredder/shredder = target + shredder.empty_bin(user) -/obj/item/shreddedp/proc/burnpaper(var/obj/item/flame/lighter/P, var/mob/user) - if(user.restrained()) +////////////////////////////////////////////////////////////////// +// Shredded Paper +////////////////////////////////////////////////////////////////// +/obj/item/shreddedp + name = "shredded" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "shredp" + randpixel = 5 + throw_range = 3 + throw_speed = 2 + w_class = ITEM_SIZE_TINY + material = /decl/material/solid/organic/paper + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + +/obj/item/shreddedp/get_matter_amount_modifier() + return 0.2 + +/obj/item/shreddedp/set_material(new_material) + . = ..() + if(material) + SetName("[initial(name)] [material.solid_name]") + +/obj/item/shreddedp/attackby(var/obj/item/used_item, var/mob/user) + if(used_item.isflamesource()) + burnpaper(used_item, user) + return TRUE + return ..() + +/obj/item/shreddedp/proc/burnpaper(var/obj/item/P, var/mob/user) + if(!CanPhysicallyInteractWith(user, src) || material?.accelerant_value <= FUEL_VALUE_NONE) return - if(!P.lit) - to_chat(user, "\The [P] is not lit.") + if(!P.isflamesource()) + to_chat(user, SPAN_WARNING("\The [P] is not lit.")) return - user.visible_message("\The [user] holds \the [P] up to \the [src]. It looks like \he's trying to burn it!", \ - "You hold \the [P] up to \the [src], burning it slowly.") + var/decl/pronouns/pronouns = user.get_pronouns() + user.visible_message(\ + SPAN_WARNING("\The [user] holds \the [P] up to \the [src]. It looks like [pronouns.he] [pronouns.is] trying to burn it!"), \ + SPAN_WARNING("You hold \the [P] up to \the [src], burning it slowly.")) if(!do_after(user,20, src)) - to_chat(user, "You must hold \the [P] steady to burn \the [src].") + to_chat(user, SPAN_WARNING("You must hold \the [P] steady to burn \the [src].")) return - user.visible_message("\The [user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ - "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") - FireBurn() + user.visible_message( \ + SPAN_DANGER("\The [user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap."), \ + SPAN_DANGER("You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.")) + fire_act(return_air(), P.get_heat(), 500) -/obj/item/shreddedp/proc/FireBurn() +/obj/item/shreddedp/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + SHOULD_CALL_PARENT(FALSE) new /obj/effect/decal/cleanable/ash(get_turf(src)) - qdel(src) - -/obj/item/shreddedp - name = "shredded paper" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "shredp" - randpixel = 5 - throwforce = 0 - w_class = ITEM_SIZE_TINY - throw_range = 3 - throw_speed = 1 - -/obj/item/shreddedp/Initialize() - . = ..() - if(prob(65)) color = pick("#bababa","#7f7f7f") + physically_destroyed() diff --git a/code/modules/paperwork/pen/chameleon_pen.dm b/code/modules/paperwork/pen/chameleon_pen.dm index c773da9b4b04..3bd6e1cbd440 100644 --- a/code/modules/paperwork/pen/chameleon_pen.dm +++ b/code/modules/paperwork/pen/chameleon_pen.dm @@ -1,5 +1,6 @@ -/obj/item/pen/chameleon - var/signature = "" +/obj/item/pen/chameleon/Initialize(ml, material_key) + . = ..() + set_tool_property(TOOL_PEN, TOOL_PROP_PEN_SIG, "Anonymous") //Always default to anonymous for this pen, since it should never uses the user's real_name /obj/item/pen/chameleon/attack_self(mob/user) /* @@ -13,13 +14,8 @@ if(new_signature) signature = new_signature */ - signature = sanitize(input("Enter new signature. Leave blank for 'Anonymous'", "New Signature", signature)) - -/obj/item/pen/proc/get_signature(var/mob/user) - return (user && user.real_name) ? user.real_name : "Anonymous" - -/obj/item/pen/chameleon/get_signature(var/mob/user) - return signature ? signature : "Anonymous" + var/signature = sanitize(input("Enter new signature. Leave blank for 'Anonymous'", "New Signature", get_tool_property(TOOL_PEN, TOOL_PROP_PEN_SIG))) + set_tool_property(TOOL_PEN, TOOL_PROP_PEN_SIG, signature ? signature : "Anonymous") /obj/item/pen/chameleon/verb/set_colour() set name = "Change Pen Colour" @@ -31,30 +27,22 @@ if(selected_type) switch(selected_type) if("Yellow") - colour = COLOR_YELLOW - color_description = "yellow ink" + set_medium_color(COLOR_YELLOW, "yellow") if("Green") - colour = COLOR_LIME - color_description = "green ink" + set_medium_color(COLOR_LIME, "green") if("Pink") - colour = COLOR_PINK - color_description = "pink ink" + set_medium_color(COLOR_PINK, "pink") if("Blue") - colour = COLOR_BLUE - color_description = "blue ink" + set_medium_color(COLOR_BLUE, "blue") if("Orange") - colour = COLOR_ORANGE - color_description = "orange ink" + set_medium_color(COLOR_ORANGE, "orange") if("Cyan") - colour = COLOR_CYAN - color_description = "cyan ink" + set_medium_color(COLOR_CYAN, "cyan") if("Red") - colour = COLOR_RED - color_description = "red ink" + set_medium_color(COLOR_RED, "red") if("Invisible") - colour = COLOR_WHITE - color_description = "transluscent ink" + set_medium_color(COLOR_WHITE, "transluscent") else - colour = COLOR_BLACK - color_description = "black ink" - to_chat(usr, "You select the [lowertext(selected_type)] ink container.") \ No newline at end of file + set_medium_color(COLOR_BLACK, "black") + + to_chat(usr, SPAN_INFO("You select the [lowertext(selected_type)] [medium_name] container.")) \ No newline at end of file diff --git a/code/modules/paperwork/pen/crayon.dm b/code/modules/paperwork/pen/crayon.dm index c70a5bc3876a..f06419b8711c 100644 --- a/code/modules/paperwork/pen/crayon.dm +++ b/code/modules/paperwork/pen/crayon.dm @@ -1,19 +1,136 @@ /obj/item/pen/crayon - name = "crayon" - desc = "A colourful crayon. Please refrain from eating it or putting it in your nose." - icon = 'icons/obj/items/crayons.dmi' - icon_state = "crayonred" - w_class = ITEM_SIZE_TINY - attack_verb = list("attacked", "coloured") - colour = "#ff0000" //RGB - color_description = "red crayon" - iscrayon = TRUE - - var/shadeColour = "#220000" //RGB - var/uses = 30 //0 for unlimited uses - var/instant = 0 - var/colourName = "red" //for updateIcon purposes + name = "crayon" + icon = 'icons/obj/items/crayon.dmi' + attack_verb = list("attacked", "coloured", "crayon'd") + stroke_color = COLOR_RED + color = COLOR_RED + stroke_color_name = "red" + medium_name = "crayon" + pen_flag = PEN_FLAG_ACTIVE | PEN_FLAG_CRAYON | PEN_FLAG_DEL_EMPTY + pen_quality = TOOL_QUALITY_BAD //Writing with those things is awkward + max_uses = 30 + pen_font = PEN_FONT_CRAYON + material = /decl/material/solid/organic/wax + var/shade_color = "#220000" //RGB + var/pigment_type = /decl/material/liquid/pigment + var/use_stroke_color = TRUE /obj/item/pen/crayon/Initialize() - name = "[colourName] crayon" . = ..() + if(use_stroke_color) + set_color(stroke_color) + +/obj/item/pen/crayon/make_pen_description() + desc = "A colourful [stroke_color_name] [istype(material)?"[material.name] ":null][medium_name]. Please refrain from eating it or putting it in your nose." + +/obj/item/pen/crayon/set_medium_color(_color, _color_name, var/_shade_color) + . = ..(_color, _color_name) + shade_color = _shade_color + set_tool_property(TOOL_PEN, TOOL_PROP_PEN_SHADE_COLOR, shade_color) + +/obj/item/pen/crayon/afterattack(turf/target, mob/user, proximity) + if(!proximity) + return + + if(istype(target) && target.is_floor()) + var/static/list/drawtypes = list(CRAYON_DRAW_GRAFFITI, CRAYON_DRAW_RUNE, CRAYON_DRAW_LETTER, CRAYON_DRAW_ARROW) + var/drawtype = input(user, "Choose what you'd like to draw.", "Crayon scribbles") as null|anything in drawtypes + var/draw_message = "drawing" + switch(drawtype) + if(CRAYON_DRAW_LETTER) + drawtype = input(user, "Choose a letter.", "Crayon scribbles") as null|anything in global.alphabet + draw_message = "drawing a letter" + if(CRAYON_DRAW_GRAFFITI) + draw_message = "drawing graffiti" + if(CRAYON_DRAW_RUNE) + draw_message = "drawing a rune" + if(CRAYON_DRAW_ARROW) + var/static/list/arrow_dirs = list("left", "right", "up", "down") + drawtype = input(user, "Choose an arrow.", "Crayon scribbles") as null|anything in arrow_dirs + draw_message = "drawing an arrow" + + if(!drawtype || QDELETED(src) || QDELETED(target) || QDELETED(user) || user.get_active_held_item() != src || !CanPhysicallyInteractWith(user, target)) + return TRUE + + if(do_tool_interaction(TOOL_PEN, user, target, 5 SECONDS, draw_message, "drawing on", fuel_expenditure = 1)) + var/obj/effect/decal/cleanable/crayon/graffiti = new(target, stroke_color, shade_color, drawtype) + target.add_fingerprint(user) // Adds their fingerprints to the floor the crayon is drawn on. + graffiti.add_fingerprint(user) + + return TRUE + +/obj/item/pen/crayon/red + stroke_color = "#da0000" + shade_color = "#810c0c" + stroke_color_name = "red" + pigment_type = /decl/material/liquid/pigment/red + +/obj/item/pen/crayon/orange + stroke_color = "#ff9300" + stroke_color_name = "orange" + shade_color = "#a55403" + pigment_type = /decl/material/liquid/pigment/orange + +/obj/item/pen/crayon/yellow + stroke_color = "#fff200" + shade_color = "#886422" + stroke_color_name = "yellow" + pigment_type = /decl/material/liquid/pigment/yellow + +/obj/item/pen/crayon/green + stroke_color = "#a8e61d" + shade_color = "#61840f" + stroke_color_name = "green" + pigment_type = /decl/material/liquid/pigment/green + +/obj/item/pen/crayon/blue + stroke_color = "#00b7ef" + shade_color = "#0082a8" + stroke_color_name = "blue" + pigment_type = /decl/material/liquid/pigment/blue + +/obj/item/pen/crayon/purple + stroke_color = "#da00ff" + shade_color = "#810cff" + stroke_color_name = "purple" + pigment_type = /decl/material/liquid/pigment/purple + +/obj/item/pen/crayon/mime + icon = 'icons/obj/items/crayon_mime.dmi' + color = null + stroke_color = "#ffffff" + shade_color = "#000000" + stroke_color_name = "mime" + max_uses = -1 //Infinite + pigment_type = null + use_stroke_color = FALSE + +/obj/item/pen/crayon/mime/make_pen_description() + desc = "A very sad-looking crayon." + +/obj/item/pen/crayon/mime/attack_self(mob/user) //inversion + if(stroke_color != "#ffffff" && shade_color != "#000000") + set_medium_color("#ffffff", stroke_color_name, "#000000") + to_chat(user, "You will now draw in white and black with this crayon.") + else + set_medium_color("#000000", stroke_color_name, "#ffffff") + to_chat(user, "You will now draw in black and white with this crayon.") + return + +/obj/item/pen/crayon/rainbow + icon = 'icons/obj/items/crayon_rainbow.dmi' + color = null + stroke_color = "#fff000" + shade_color = "#000fff" + stroke_color_name = "rainbow" + max_uses = -1 + pigment_type = null + use_stroke_color = FALSE + +/obj/item/pen/crayon/rainbow/make_pen_description() + desc = "A very colourful [istype(material)?"[material.name] ":null][medium_name]. Please refrain from eating it or putting it in your nose." + +/obj/item/pen/crayon/rainbow/attack_self(mob/user) + stroke_color = input(user, "Please select the main colour.", "Crayon colour") as color + shade_color = input(user, "Please select the shade colour.", "Crayon colour") as color + set_medium_color(stroke_color, stroke_color_name, shade_color) diff --git a/code/modules/paperwork/pen/crayon_edibility.dm b/code/modules/paperwork/pen/crayon_edibility.dm new file mode 100644 index 000000000000..88259e4920e0 --- /dev/null +++ b/code/modules/paperwork/pen/crayon_edibility.dm @@ -0,0 +1,21 @@ +/obj/item/pen/crayon/transfer_eaten_material(mob/eater, amount) + var/decl/tool_archetype/pen/parch = GET_DECL(TOOL_PEN) + parch.decrement_uses(eater, src, amount, destroy_on_zero = FALSE) // we'll qdel in food code if we eat the end of the crayon + if(!isliving(eater)) + return + var/mob/living/living_eater = eater + var/datum/reagents/eater_ingested = living_eater.get_ingested_reagents() + if(!eater_ingested) + return + if(pigment_type) + var/partial_amount = ceil(amount * 0.4) + eater_ingested.add_reagent(pigment_type, partial_amount) + eater_ingested.add_reagent(/decl/material/solid/organic/wax, amount - partial_amount) + else + eater_ingested.add_reagent(/decl/material/solid/organic/wax, amount) + +/obj/item/pen/crayon/get_edible_material_amount(mob/eater) + return max(0, get_tool_property(TOOL_PEN, TOOL_PROP_USES)) + +/obj/item/pen/crayon/get_food_default_transfer_amount(mob/eater) + return eater?.get_eaten_transfer_amount(5) diff --git a/code/modules/paperwork/pen/fancy.dm b/code/modules/paperwork/pen/fancy.dm index b8b8559aaa80..098033965e66 100644 --- a/code/modules/paperwork/pen/fancy.dm +++ b/code/modules/paperwork/pen/fancy.dm @@ -1,13 +1,13 @@ /obj/item/pen/fancy - name = "fancy pen" - desc = "A high quality traditional fountain pen with an internal reservoir and an extra fine gold-platinum nib. Guaranteed never to leak." - icon_state = "fancy" - throwforce = 1 //pointy - colour = "#1c1713" //dark ashy brownish - material = /decl/material/solid/metal/steel - isfancy = TRUE + name = "fountain pen" + icon = 'icons/obj/items/pens/pen_fancy.dmi' + sharp = TRUE + stroke_color = "#1c1713" //dark ashy brownish + stroke_color_name = "dark ashy brownish" + material = /decl/material/solid/metal/steel + pen_flag = PEN_FLAG_ACTIVE | PEN_FLAG_FANCY + pen_quality = TOOL_QUALITY_GOOD + pen_font = PEN_FONT_FANCY_PEN -/obj/item/pen/fancy/quill - name = "dire goose quill" - desc = "A quill fashioned from a feather of the dire goose makes an excellent writing instrument, as well as a valuable trophy." - matter = null \ No newline at end of file +/obj/item/pen/fancy/make_pen_description() + desc = "A high quality [istype(material)?"[material.name] ":null]traditional [stroke_color_name] [medium_name] fountain pen with an internal reservoir and an extra fine gold-platinum nib. Guaranteed never to leak." diff --git a/code/modules/paperwork/pen/multi_pen.dm b/code/modules/paperwork/pen/multi_pen.dm index 34ae66ad5e6b..500a573a8eb7 100644 --- a/code/modules/paperwork/pen/multi_pen.dm +++ b/code/modules/paperwork/pen/multi_pen.dm @@ -1,20 +1,31 @@ /obj/item/pen/multi - name = "multicoloured pen" - desc = "It's a pen with multiple colors of ink!" - var/selectedColor = 1 - var/colors = list("black","blue","red","green") - var/color_descriptions = list("black ink", "blue ink", "red ink", "green ink") + name = "multicoloured pen" + desc = "It's a pen with multiple colors of ink!" + pen_quality = TOOL_QUALITY_MEDIOCRE + var/colour_idx = 1 + var/stroke_colors = list("black", "blue", "red", "green") + var/stroke_color_names = list("black", "blue", "red", "green") + var/colour_icons = list( + 'icons/obj/items/pens/pen.dmi', + 'icons/obj/items/pens/pen_blue.dmi', + 'icons/obj/items/pens/pen_red.dmi', + 'icons/obj/items/pens/pen_green.dmi', + ) -/obj/item/pen/multi/attack_self(mob/user) - if(++selectedColor > length(colors)) - selectedColor = 1 +/obj/item/pen/multi/Initialize(ml, material_key) + . = ..() + change_colour(colour_idx) - colour = colors[selectedColor] - color_description = color_descriptions[selectedColor] +/obj/item/pen/multi/make_pen_description() + desc = "It's [istype(material)?"[ADD_ARTICLE(material.name)]":"a"] pen with multiple colors of ink! It's currently set to [stroke_color_name] [medium_name]." - if(colour == "black") - icon_state = "pen" - else - icon_state = "pen_[colour]" +/obj/item/pen/multi/proc/change_colour(var/new_idx) + colour_idx = new_idx + if(colour_idx > length(stroke_colors)) + colour_idx = 1 + icon = colour_icons[colour_idx] + set_medium_color(stroke_colors[colour_idx], stroke_color_names[colour_idx]) - to_chat(user, "Changed color to '[colour].'") \ No newline at end of file +/obj/item/pen/multi/attack_self(mob/user) + change_colour((++colour_idx)) + to_chat(user, SPAN_NOTICE("Changed color to '[stroke_color_name] [medium_name].'")) diff --git a/code/modules/paperwork/pen/pen.dm b/code/modules/paperwork/pen/pen.dm index f0b825006c73..b11689c5b70c 100644 --- a/code/modules/paperwork/pen/pen.dm +++ b/code/modules/paperwork/pen/pen.dm @@ -1,62 +1,92 @@ /obj/item/pen - desc = "It's a normal black ink pen." - name = "pen" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "pen" - item_state = "pen" - slot_flags = SLOT_BELT | SLOT_EARS - throwforce = 0 - w_class = ITEM_SIZE_TINY - throw_speed = 7 - throw_range = 15 - material = /decl/material/solid/plastic - var/colour = "black" //what colour the ink is! - var/color_description = "black ink" - - var/active = TRUE - var/iscrayon = FALSE - var/isfancy = FALSE + name = "pen" + desc = "" + icon = 'icons/obj/items/pens/pen.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY | SLOT_EARS + w_class = ITEM_SIZE_TINY + throw_speed = 7 + throw_range = 15 + material = /decl/material/solid/organic/plastic + _base_attack_force = 1 + var/pen_flag = PEN_FLAG_ACTIVE //Properties/state of the pen used. + var/stroke_color = "black" //What colour the ink is! Can be hexadecimal colour or a colour name string. + var/stroke_color_name = "black" //Human readable name of the stroke colour. Used in text strings, and to identify the nearest colour to the stroke colour. + var/medium_name = "ink" //Whatever the pen uses to leave its mark. Used in text strings. + var/max_uses = -1 //-1 for unlimited uses. + var/pen_quality = TOOL_QUALITY_DEFAULT //What will be set as tool quality for the pen + ///The type of font this pen's written text will be represented with + var/pen_font = PEN_FONT_DEFAULT + +/obj/item/pen/Initialize(ml, material_key) + . = ..() + set_extension(src, /datum/extension/tool, + list( + TOOL_SURGICAL_DRILL = TOOL_QUALITY_WORST, + TOOL_PEN = pen_quality), + + list( + TOOL_PEN = list( + TOOL_PROP_COLOR_NAME = stroke_color_name, + TOOL_PROP_COLOR = stroke_color, + TOOL_PROP_PEN_FLAG = pen_flag, + TOOL_PROP_USES = max_uses, + TOOL_PROP_PEN_FONT = pen_font))) + make_pen_description() + +/obj/item/pen/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(user.check_intent(I_FLAG_HELP) && user.get_target_zone() == BP_HEAD) + var/obj/item/organ/external/head/head = target.get_organ(BP_HEAD, /obj/item/organ/external/head) + if(istype(head)) + head.write_on(user, "[stroke_color_name] [medium_name]") + return TRUE + + if(istype(target, /obj/item/organ/external/head)) + var/obj/item/organ/external/head/head = target + head.write_on(user, "[stroke_color_name] [medium_name]") + return TRUE + + return ..() + +/obj/item/pen/proc/toggle() + if(pen_flag & PEN_FLAG_ACTIVE) + pen_flag &= ~PEN_FLAG_ACTIVE + else + pen_flag |= PEN_FLAG_ACTIVE + playsound(src, 'sound/items/penclick.ogg', 5, 0, -4) + set_tool_property(TOOL_PEN, TOOL_PROP_PEN_FLAG, pen_flag) + update_icon() + +/obj/item/pen/proc/set_medium_color(var/_color, var/_color_name) + stroke_color = _color + stroke_color_name = _color_name + set_tool_property(TOOL_PEN, TOOL_PROP_COLOR, stroke_color) + set_tool_property(TOOL_PEN, TOOL_PROP_COLOR_NAME, stroke_color_name) + make_pen_description() + +/obj/item/pen/proc/make_pen_description() + desc = "It's [ADD_ARTICLE(stroke_color_name)] [medium_name] [istype(material)? material.name : ""] pen." /obj/item/pen/blue - name = "blue pen" - desc = "It's a normal blue ink pen." - icon_state = "pen_blue" - colour = "blue" - color_description = "blue ink" + name = "blue pen" + icon = 'icons/obj/items/pens/pen_blue.dmi' + stroke_color = "blue" + stroke_color_name = "blue" /obj/item/pen/red - name = "red pen" - desc = "It's a normal red ink pen." - icon_state = "pen_red" - colour = "red" - color_description = "red ink" + name = "red pen" + icon = 'icons/obj/items/pens/pen_red.dmi' + stroke_color = "red" + stroke_color_name = "red" /obj/item/pen/green - name = "green pen" - desc = "It's a normal green ink pen." - icon_state = "pen_green" - colour = "green" + name = "green pen" + icon = 'icons/obj/items/pens/pen_green.dmi' + stroke_color = "green" + stroke_color_name = "green" /obj/item/pen/invisible - desc = "It's an invisble pen marker." - icon_state = "pen" - colour = "white" - color_description = "transluscent ink" - -/obj/item/pen/attack(atom/A, mob/user, target_zone) - if(ismob(A)) - var/mob/M = A - if(ishuman(A) && user.a_intent == I_HELP && target_zone == BP_HEAD) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/head/head = H.organs_by_name[BP_HEAD] - if(istype(head)) - head.write_on(user, color_description) - else - to_chat(user, SPAN_WARNING("You stab [M] with \the [src].")) - admin_attack_log(user, M, "Stabbed using \a [src]", "Was stabbed with \a [src]", "used \a [src] to stab") - else if(istype(A, /obj/item/organ/external/head)) - var/obj/item/organ/external/head/head = A - head.write_on(user, color_description) - -/obj/item/pen/proc/toggle() - return \ No newline at end of file + name = "pen" + stroke_color = "white" + stroke_color_name = "transluscent" diff --git a/code/modules/paperwork/pen/quill_and_ink.dm b/code/modules/paperwork/pen/quill_and_ink.dm new file mode 100644 index 000000000000..c6cda0c11177 --- /dev/null +++ b/code/modules/paperwork/pen/quill_and_ink.dm @@ -0,0 +1,137 @@ +/obj/item/pen/fancy/quill + name = "quill pen" + icon = 'icons/obj/items/pens/pen_quill.dmi' + sharp = FALSE + material = /decl/material/solid/organic/skin/feathers + pen_quality = TOOL_QUALITY_DEFAULT + max_uses = 5 // gotta re-ink it often! + stroke_color = /decl/material/liquid/pigment/black/ink::color + stroke_color_name = "inky black" + +/obj/item/pen/fancy/quill/Initialize(ml, material_key) + . = ..() + set_tool_property(TOOL_PEN, TOOL_PROP_EMPTY_MESSAGE, "out of ink") + +/obj/item/pen/fancy/quill/fluid_act(datum/reagents/fluids) + . = ..() + if(!IS_PEN(src)) + return // someone made us not a pen, somehow + var/ink_amount = fluids.has_reagent(/decl/material/liquid/pigment/black/ink) + if(ink_amount <= 0) + return + // be lenient about contamination; it just has to be at least half + if(!istype(fluids.get_primary_reagent_decl(), /decl/material/liquid/pigment/black/ink)) + return + var/current_uses = get_tool_property(TOOL_PEN, TOOL_PROP_USES) + var/const/charges_per_ink = 4 // this many charges per unit of ink + var/ink_used = CHEMS_QUANTIZE(min((max_uses - current_uses) / charges_per_ink, ink_amount)) + fluids.remove_reagent(/decl/material/liquid/pigment/black/ink, ink_used) + set_tool_property(TOOL_PEN, TOOL_PROP_USES, max(max_uses, current_uses + (ink_used * charges_per_ink))) + update_icon() + +// ink overlay that fades as we run out of ink +/obj/item/pen/fancy/quill/on_update_icon() + . = ..() + var/ink_alpha = 255 * get_tool_property(TOOL_PEN, TOOL_PROP_USES) / max_uses + if(ink_alpha > 25) // some arbitrary minimum alpha cutoff + var/image/ink_overlay = overlay_image(icon, "[icon_state]-inked") + ink_overlay.alpha = ink_alpha + add_overlay(ink_overlay) + +/obj/item/pen/fancy/quill/make_pen_description() + desc = "A large feather, sharpened and cut to hold ink for scribing." + +/obj/item/pen/fancy/quill/goose + name = "dire goose quill" + icon = 'icons/obj/items/pens/pen_dire_quill.dmi' + pen_quality = TOOL_QUALITY_BEST + max_uses = 10 + +/obj/item/pen/fancy/quill/goose/make_pen_description() + desc = "A quill fashioned from a feather of the dire goose makes an excellent writing instrument, as well as a valuable trophy." + +// Inkwell +/obj/item/chems/glass/inkwell + name = "inkwell" + icon = 'icons/obj/items/inkwell.dmi' + icon_state = ICON_STATE_WORLD + desc = "An inkwell used to hold ink. Dip a quill pen into this to re-ink it." + chem_volume = 30 + /// The minimum amount of ink in the inkwell when populating reagents. + var/starting_volume_low = 20 + /// The maximum amount of ink in the inkwell when populating reagents. + var/starting_volume_high = 30 + +/obj/item/chems/glass/inkwell/get_edible_material_amount(mob/eater) + return 0 + +/obj/item/chems/glass/inkwell/get_utensil_food_type() + return null + +/obj/item/chems/glass/inkwell/can_lid() + return FALSE + +/obj/item/chems/glass/inkwell/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/pigment/black/ink, rand(starting_volume_low, starting_volume_high)) + +/obj/item/chems/glass/inkwell/update_overlays() + . = ..() + icon_state = get_world_inventory_state() + if(locate(/obj/item/pen/fancy/quill) in src) + add_overlay("[icon_state]-quill") + +/obj/item/chems/glass/inkwell/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item) && istype(used_item, /obj/item/pen/fancy/quill)) + var/obj/item/pen/fancy/quill/quill = used_item + var/current_uses = quill.get_tool_property(TOOL_PEN, TOOL_PROP_USES) + if(current_uses >= quill.max_uses) + to_chat(user, SPAN_WARNING("\The [quill] doesn't need any more ink!")) + return TRUE + if(REAGENT_TOTAL_LIQUID_VOLUME(reagents) <= 0) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return TRUE + to_chat(user, SPAN_NOTICE("You dip \the [quill] into \the [src].")) + quill.fluid_act(reagents) + update_icon() + return TRUE + return ..() + +/obj/item/chems/glass/inkwell/attack_hand(mob/user) + var/obj/item/pen/fancy/quill/existing_quill = locate(/obj/item/pen/fancy/quill) in src + if(existing_quill) + user.put_in_hands(existing_quill) + to_chat(user, SPAN_NOTICE("You remove \the [existing_quill] from \the [src].")) + update_icon() + return TRUE + return ..() + +// This override lets you pick up an inkwell without removing the quill in it first. +/obj/item/chems/glass/inkwell/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && Adjacent(user) && user.get_empty_hand_slot()) + user.put_in_hands(src) + return TRUE + . = ..() + +/obj/item/chems/glass/inkwell/receive_mouse_drop(atom/dropping, mob/user, params) + if(istype(dropping, /obj/item/pen/fancy/quill) && Adjacent(user) && user.Adjacent(dropping)) + var/obj/item/pen/fancy/quill/new_quill = dropping + var/obj/item/pen/fancy/quill/existing_quill = locate(/obj/item/pen/fancy/quill) in src + if(existing_quill) + to_chat(user, SPAN_WARNING("\The [existing_quill] is already in \the [src], \the [new_quill] won't fit!")) + return TRUE + to_chat(user, SPAN_NOTICE("You put \the [new_quill] into \the [src].")) + user.remove_from_mob(new_quill, src) + update_icon() + return TRUE + return ..() + +// This subtype starts with a quill. +/obj/item/chems/glass/inkwell/quilled + icon_state = "quilled_preview" + +/obj/item/chems/glass/inkwell/quilled/Initialize(ml, material_key) + . = ..() + var/obj/item/new_quill = new /obj/item/pen/fancy/quill(src) + new_quill.fluid_act(reagents) + update_icon() \ No newline at end of file diff --git a/code/modules/paperwork/pen/reagent_pen.dm b/code/modules/paperwork/pen/reagent_pen.dm index aff32fc648a7..cc0c50f51bed 100644 --- a/code/modules/paperwork/pen/reagent_pen.dm +++ b/code/modules/paperwork/pen/reagent_pen.dm @@ -1,40 +1,38 @@ /obj/item/pen/reagent - atom_flags = ATOM_FLAG_OPEN_CONTAINER - origin_tech = "{'materials':2,'esoteric':5}" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + origin_tech = @'{"materials":2,"esoteric":5}' + sharp = TRUE + pen_quality = TOOL_QUALITY_MEDIOCRE + chem_volume = 30 -/obj/item/pen/reagent/Initialize() - . = ..() - create_reagents(30) - -/obj/item/pen/reagent/attack(mob/living/M, mob/user, var/target_zone) - - if(!istype(M)) - return - - . = ..() +/obj/item/pen/reagent/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) - var/allow = M.can_inject(user, target_zone) - if(allow) + var/allow = target.can_inject(user, user.get_target_zone()) + if(allow && user.check_intent(I_FLAG_HELP)) if (allow == INJECTION_PORT) - if(M != user) - to_chat(user, SPAN_WARNING("You begin hunting for an injection port on \the [M]'s suit!")) + if(target != user) + to_chat(user, SPAN_WARNING("You begin hunting for an injection port on \the [target]'s suit!")) else to_chat(user, SPAN_NOTICE("You begin hunting for an injection port on your suit.")) - if(!user.do_skilled(INJECTION_PORT_DELAY, SKILL_MEDICAL, M)) - return - if(reagents.total_volume) - if(M.reagents) + if(!user.do_skilled(INJECTION_PORT_DELAY, SKILL_MEDICAL, target)) + return TRUE + if(REAGENT_TOTAL_VOLUME(reagents)) + if(target.reagents) var/contained_reagents = reagents.get_reagents() - var/trans = reagents.trans_to_mob(M, 30, CHEM_INJECT) - admin_inject_log(user, M, src, contained_reagents, trans) + var/trans = reagents.trans_to_mob(target, 30, CHEM_INJECT) + admin_inject_log(user, target, src, contained_reagents, trans) + return TRUE + + . = ..() /* * Sleepy Pens */ /obj/item/pen/reagent/sleepy - desc = "It's a black ink pen with a sharp point and a carefully engraved \"Waffle Co.\"." - origin_tech = "{'materials':2,'esoteric':5}" + origin_tech = @'{"materials":2,"esoteric":5}' -/obj/item/pen/reagent/sleepy/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/paralytics, 15) +/obj/item/pen/reagent/sleepy/make_pen_description() + desc = "It's \a [stroke_color_name] [medium_name] pen with a sharp point and a carefully engraved \"Waffle Co.\"." + +/obj/item/pen/reagent/sleepy/populate_reagents() + add_to_reagents(/decl/material/liquid/paralytics, round(REAGENT_MAXIMUM_VOLUME(reagents)/2)) diff --git a/code/modules/paperwork/pen/retractable_pen.dm b/code/modules/paperwork/pen/retractable_pen.dm index 8e105b85a69b..e26f5974d784 100644 --- a/code/modules/paperwork/pen/retractable_pen.dm +++ b/code/modules/paperwork/pen/retractable_pen.dm @@ -1,46 +1,37 @@ /obj/item/pen/retractable - desc = "It's a retractable pen." - icon_state = "pen" //for map visibility - active = FALSE - var/base_state = "ret_black" + desc = "It's a retractable pen." + icon = 'icons/obj/items/pens/pen_retractable.dmi' + pen_flag = PEN_FLAG_TOGGLEABLE /obj/item/pen/retractable/blue - icon_state = "pen_blue" - colour = "blue" - color_description = "blue ink" - base_state = "ret_blue" + stroke_color = "blue" + stroke_color_name = "blue" + icon = 'icons/obj/items/pens/pen_retractable_blue.dmi' /obj/item/pen/retractable/red - icon_state = "pen_red" - colour = "red" - color_description = "red ink" - base_state = "ret_blue" + stroke_color = "red" + stroke_color_name = "red" + icon = 'icons/obj/items/pens/pen_retractable_red.dmi' /obj/item/pen/retractable/green - icon_state = "pen_green" - colour = "green" - color_description = "green ink" - base_state = "ret_green" + stroke_color = "green" + stroke_color_name = "green" + icon = 'icons/obj/items/pens/pen_retractable_green.dmi' /obj/item/pen/retractable/Initialize() . = ..() - desc = "It's a retractable [color_description] pen." + desc = "It's a retractable [stroke_color_name] [medium_name] pen." /obj/item/pen/retractable/on_update_icon() - if(active) - icon_state = "[base_state]-a" - else - icon_state = "[base_state]" + . = ..() + icon_state = get_world_inventory_state() + if(pen_flag & PEN_FLAG_ACTIVE) + icon_state = "[icon_state]-on" -/obj/item/pen/retractable/attack(atom/A, mob/user, target_zone) - if(!active) +/obj/item/pen/retractable/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(!(pen_flag & PEN_FLAG_ACTIVE)) toggle() - ..() + return ..() /obj/item/pen/retractable/attack_self(mob/user) toggle() - -/obj/item/pen/retractable/toggle() - active = !active - playsound(src, 'sound/items/penclick.ogg', 5, 0, -4) - update_icon() diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 76423f632cbb..369418bb480e 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -1,225 +1,304 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// Photocopier Board +//////////////////////////////////////////////////////////////////////////////////////// +/obj/item/stock_parts/circuitboard/photocopier + name = "circuitboard (photocopier)" + build_path = /obj/machinery/photocopier + board_type = "machine" + origin_tech = @'{"engineering":1, "programming":1}' + req_components = list( + /obj/item/stock_parts/printer/buildable = 1, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/scanning_module = 1, + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +//////////////////////////////////////////////////////////////////////////////////////// +// Photocopier +//////////////////////////////////////////////////////////////////////////////////////// /obj/machinery/photocopier - name = "photocopier" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "photocopier" - var/insert_anim = "photocopier_animation" - anchored = 1 - density = 1 - idle_power_usage = 30 - active_power_usage = 200 - power_channel = EQUIP - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE - obj_flags = OBJ_FLAG_ANCHORABLE - var/obj/item/copyitem = null //what's in the copier! - var/copies = 1 //how many copies to print! - var/toner = 30 //how much toner is left! woooooo~ - var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier! + name = "photocopier" + icon = 'icons/obj/machines/photocopier.dmi' + icon_state = "photocopier" + anchored = TRUE + density = TRUE + idle_power_usage = 30 + active_power_usage = 200 + atom_flags = ATOM_FLAG_CLIMBABLE + obj_flags = OBJ_FLAG_ANCHORABLE + construct_state = /decl/machine_construction/default/panel_closed + maximum_component_parts = list( + /obj/item/stock_parts/printer = 1, + /obj/item/stock_parts = 10, + ) + uncreated_component_parts = null + var/tmp/insert_anim = "photocopier_animation" + var/obj/item/scanner_item //what's in the scanner + var/obj/item/stock_parts/printer/printer //What handles the printing queue + var/tmp/max_copies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier! + var/total_printing = 0 //The total number of pages we are printing in the current run + +/obj/machinery/photocopier/Initialize(mapload, d=0, populate_parts = TRUE) + . = ..() + if(. != INITIALIZE_HINT_QDEL && populate_parts && printer) + //Mapped photocopiers shall spawn with ink and paper + printer.make_full() + +/obj/machinery/photocopier/Destroy() + scanner_item = null + printer = null + return ..() + +/obj/machinery/photocopier/RefreshParts() + . = ..() + printer = get_component_of_type(/obj/item/stock_parts/printer) //Cache the printer component + if(printer) + printer.show_queue_ctrl = FALSE //Make sure we don't let users mess with the print queue + printer.register_on_printed_page( CALLBACK(src, TYPE_PROC_REF(/obj/machinery/photocopier, update_ui))) + printer.register_on_finished_queue(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/photocopier, update_ui))) + printer.register_on_print_error( CALLBACK(src, TYPE_PROC_REF(/obj/machinery/photocopier, update_ui))) + printer.register_on_status_changed(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/photocopier, update_ui))) + +/obj/machinery/photocopier/on_update_icon() + cut_overlays() + //Set the icon first + if(scanner_item) + icon_state = "photocopier_paper" + else + icon_state = initial(icon_state) + + //If powered and working add the flashing lights + if(inoperable()) + return + //Warning lights + if(scanner_item) + add_overlay("photocopier_ready") + if(!has_enough_to_print()) + add_overlay("photocopier_bad") + +/obj/machinery/photocopier/proc/update_ui() + SSnano.update_uis(src) + update_icon() + +/obj/machinery/photocopier/proc/queue_copies(var/copy_amount, var/mob/user) + if(!scanner_item) + if(user) + to_chat(user, SPAN_WARNING("Insert something to copy first!")) + return FALSE + + //First, check we have enough to print the copies + var/required_toner = 0 + var/required_paper = 1 + + //Compile the total amount needed for printing the whole bundle if applicable + if(istype(scanner_item, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = scanner_item + for(var/obj/item/I in B.pages) + required_toner += istype(I, /obj/item/photo)? TONER_USAGE_PHOTO : TONER_USAGE_PAPER + required_paper = length(B.pages) + else if(istype(scanner_item, /obj/item/photo)) + required_toner = TONER_USAGE_PHOTO + else + required_toner = TONER_USAGE_PAPER + + if(!has_enough_to_print(required_toner, required_paper * copy_amount)) + buzz("Warning: Not enough paper or toner!") + return FALSE + + //If we have enough go ahead + var/list/obj/item/scanned_item = scan_item(scanner_item) //Generate the copies we'll queue for printing + for(var/i=1 to copy_amount) + for(var/obj/item/page in scanned_item) + printer.queue_job(page) + + //Play the scanner animation + flick(insert_anim, src) + + //Actually start printing out the copies we created when queueing + start_processing_queue() + return TRUE + +/obj/machinery/photocopier/proc/start_processing_queue() + if(!printer) + return FALSE + audible_message(SPAN_NOTICE("\The [src] whirrs into action.")) + total_printing = printer.get_amount_queued() + printer.start_printing_queue() + + use_power_oneoff(active_power_usage) + update_icon() + SSnano.update_uis(src) + return TRUE + +/obj/machinery/photocopier/proc/stop_processing_queue() + if(!printer) + return FALSE + total_printing = 0 + printer.stop_printing_queue() + printer.clear_job_queue() + + update_use_power(POWER_USE_IDLE) + update_icon() + SSnano.update_uis(src) + return TRUE /obj/machinery/photocopier/interface_interact(mob/user) - interact(user) + ui_interact(user) return TRUE -/obj/machinery/photocopier/interact(mob/user) - user.set_machine(src) - - var/dat = "Photocopier

    " - if(copyitem) - dat += "Remove Item
    " - if(toner) - dat += "Copy
    " - dat += "Printing: [copies] copies." - dat += "- " - dat += "+

    " - else if(toner) - dat += "Please insert something to copy.

    " - if(istype(user,/mob/living/silicon)) - dat += "Print photo from database

    " - dat += "Current toner level: [toner]" - if(!toner) - dat +="
    Please insert a new toner cartridge!" - show_browser(user, dat, "window=copier") - onclose(user, "copier") - return +/obj/machinery/photocopier/proc/get_name_copy_item() + if(istype(scanner_item, /obj/item/paper)) + return "Sheet of paper" + else if(istype(scanner_item, /obj/item/paper_bundle)) + return "Paper bundle" + else if(istype(scanner_item, /obj/item/photo)) + return "Photo" -/obj/machinery/photocopier/OnTopic(user, href_list, state) - if(href_list["copy"]) - for(var/i = 0, i < copies, i++) - if(toner <= 0) - break - if (istype(copyitem, /obj/item/paper)) - copy(copyitem, 1) - sleep(15) - else if (istype(copyitem, /obj/item/photo)) - photocopy(copyitem) - sleep(15) - else if (istype(copyitem, /obj/item/paper_bundle)) - var/obj/item/paper_bundle/B = bundlecopy(copyitem) - sleep(15*B.pages.len) - else - to_chat(user, "\The [copyitem] can't be copied by \the [src].") - break +/obj/machinery/photocopier/ui_data(mob/user, ui_key) + . = ..() + //Printer header stuff + if(printer) + LAZYADD(., printer.ui_data(user)) - use_power_oneoff(active_power_usage) - return TOPIC_REFRESH + //Photocopier stuff + LAZYSET(., "src", "\ref[src]") + LAZYSET(., "is_sillicon_mode", issilicon(user)) + LAZYSET(., "copies_max", max_copies) + LAZYSET(., "is_operational", operable()) + LAZYSET(., "total_printing", total_printing) + LAZYSET(., "loaded_item_name", get_name_copy_item()) + +/obj/machinery/photocopier/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nanoui/master_ui, datum/topic_state/state) + var/list/data = ui_data(user, ui_key) + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "photocopier.tmpl", name, 640, 480) + ui.add_template("stock_parts_printer_shared", "stock_parts_printer.tmpl") //printer info header + ui.set_initial_data(data) + ui.open() + +/obj/machinery/photocopier/DefaultTopicState() + return global.physical_topic_state + +/obj/machinery/photocopier/OnTopic(user, href_list, state) + //We don't plug in the printer's own OnTopic here since we don't want to allow the user control over it - if(href_list["remove"]) - OnRemove(user) + if(href_list["eject"]) + eject_item(user) return TOPIC_REFRESH - if(href_list["min"]) - if(copies > 1) - copies-- + if(href_list["copy_amount"]) + queue_copies(sanitize_integer(text2num(href_list["copy_amount"]), 1, max_copies, 1)) return TOPIC_REFRESH - else if(href_list["add"]) - if(copies < maxcopies) - copies++ + if(href_list["cancel_queue"]) + stop_processing_queue() return TOPIC_REFRESH if(href_list["aipic"]) - if(!istype(user,/mob/living/silicon)) return - - if(toner >= 5) + if(!issilicon(user)) + return TOPIC_NOACTION + if(has_enough_to_print(TONER_USAGE_PHOTO)) var/mob/living/silicon/tempAI = user var/obj/item/camera/siliconcam/camera = tempAI.silicon_camera - if(!camera) - return + return TOPIC_NOACTION var/obj/item/photo/selection = camera.selectpicture() if (!selection) - return + return TOPIC_NOACTION - var/obj/item/photo/p = photocopy(selection) + var/obj/item/photo/p = selection.Clone() if (p.desc == "") p.desc += "Copied by [tempAI.name]" else p.desc += " - Copied by [tempAI.name]" - toner -= 5 - sleep(15) + printer.queue_job(p) + start_processing_queue() + else + to_chat(user, SPAN_WARNING("Not enough toner and/or paper to print!")) + return TOPIC_NOACTION return TOPIC_REFRESH -/obj/machinery/photocopier/proc/OnRemove(mob/user) - if(copyitem) - user.put_in_hands(copyitem) - to_chat(user, "You take \the [copyitem] out of \the [src].") - copyitem = null - -/obj/machinery/photocopier/attackby(obj/item/O, mob/user) - if(istype(O, /obj/item/paper) || istype(O, /obj/item/photo) || istype(O, /obj/item/paper_bundle)) - if(!copyitem) - if(!user.unEquip(O, src)) - return - copyitem = O - to_chat(user, "You insert \the [O] into \the [src].") - flick(insert_anim, src) - updateUsrDialog() - else - to_chat(user, "There is already something in \the [src].") - else if(istype(O, /obj/item/toner)) - if(toner <= 10) //allow replacing when low toner is affecting the print darkness - if(!user.unEquip(O, src)) - return - to_chat(user, "You insert the toner cartridge into \the [src].") - var/obj/item/toner/T = O - toner += T.toner_amount - qdel(O) - updateUsrDialog() - else - to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") - else ..() +/obj/machinery/photocopier/proc/insert_item(var/obj/item/I, var/mob/user) + if(!scanner_item) + if(!user.try_unequip(I, src)) + return + scanner_item = I + to_chat(user, SPAN_NOTICE("You insert \the [I] into \the [src].")) + SSnano.update_uis(src) + update_icon() + return TRUE + else + to_chat(user, SPAN_NOTICE("There is already something in \the [src].")) -/obj/machinery/photocopier/explosion_act(severity) +/obj/machinery/photocopier/proc/eject_item(var/mob/user) + if(!scanner_item) + return + user.put_in_hands(scanner_item) + to_chat(user, SPAN_NOTICE("You take \the [scanner_item] out of \the [src].")) + scanner_item = null + SSnano.update_uis(src) + update_icon() + return TRUE + +/obj/machinery/photocopier/attackby(obj/item/used_item, mob/user) + if(printer.is_printing()) + to_chat(user, SPAN_WARNING("\The [src] is busy!")) + return TRUE + if(istype(construct_state, /decl/machine_construction/default/panel_closed) && (istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo) || istype(used_item, /obj/item/paper_bundle))) + insert_item(used_item, user) + return TRUE + return ..() //Components attackby will handle refilling with paper and toner + +/**Creates a clone of the specified item. Returns a list of cloned items. */ +/obj/machinery/photocopier/proc/scan_item(var/obj/item/I) + LAZYADD(., I.Clone()) + +/**Check if the amount of toner and paper are available */ +/obj/machinery/photocopier/proc/has_enough_to_print(var/req_toner = TONER_USAGE_PAPER, var/req_paper = 1) + return printer?.has_enough_to_print(req_toner, req_paper) + +/obj/machinery/photocopier/get_alt_interactions(mob/user) . = ..() - if(.) - if(severity == 1 || (severity == 2 && prob(50))) - physically_destroyed() - else if((severity == 2 || prob(50)) && toner) - new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) - toner = 0 - -/obj/machinery/photocopier/proc/copy(var/obj/item/paper/copy, var/need_toner=1) - var/obj/item/paper/c = new copy.type(loc, copy.text, copy.name, copy.metadata ) - - c.color = COLOR_WHITE - - if(toner > 10) //lots of toner, make it dark - c.info = "" - else //no toner? shitty copies for you! - c.info = "" - var/copied = html_decode(copy.info) - copied = replacetext(copied, ""// - c.SetName(copy.name) // -- Doohl - c.fields = copy.fields - c.stamps = copy.stamps - c.stamped = copy.stamped - c.ico = copy.ico - c.offset_x = copy.offset_x - c.offset_y = copy.offset_y - var/list/temp_overlays = copy.overlays //Iterates through stamps - var/image/img //and puts a matching - for (var/j = 1, j <= min(temp_overlays.len, copy.ico.len), j++) //gray overlay onto the copy - if (findtext(copy.ico[j], "cap") || findtext(copy.ico[j], "cent")) - img = image('icons/obj/bureaucracy.dmi', "paper_stamp-circle") - else if (findtext(copy.ico[j], "deny")) - img = image('icons/obj/bureaucracy.dmi', "paper_stamp-x") - else - img = image('icons/obj/bureaucracy.dmi', "paper_stamp-dots") - img.pixel_x = copy.offset_x[j] - img.pixel_y = copy.offset_y[j] - c.overlays += img - c.updateinfolinks() - if(need_toner) - toner-- - if(toner == 0) - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") - c.update_icon() - return c - -/obj/machinery/photocopier/proc/photocopy(var/obj/item/photo/photocopy, var/need_toner=1) - var/obj/item/photo/p = photocopy.copy() - p.dropInto(loc) - - if(toner > 10) //plenty of toner, go straight greyscale - p.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))//I'm not sure how expensive this is, but given the many limitations of photocopying, it shouldn't be an issue. - p.update_icon() - else //not much toner left, lighten the photo - p.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(100,100,100)) - p.update_icon() - if(need_toner) - toner -= 5 //photos use a lot of ink! - if(toner < 0) - toner = 0 - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") - - return p - -//If need_toner is 0, the copies will still be lightened when low on toner, however it will not be prevented from printing. TODO: Implement print queues for fax machines and get rid of need_toner -/obj/machinery/photocopier/proc/bundlecopy(var/obj/item/paper_bundle/bundle, var/need_toner=1) - var/obj/item/paper_bundle/p = new /obj/item/paper_bundle (src) - for(var/obj/item/W in bundle.pages) - if(toner <= 0 && need_toner) - toner = 0 - visible_message("A red light on \the [src] flashes, indicating that it is out of toner.") - break - - if(istype(W, /obj/item/paper)) - W = copy(W) - else if(istype(W, /obj/item/photo)) - W = photocopy(W) - W.forceMove(p) - p.pages += W - - p.dropInto(loc) - p.update_icon() - p.icon_state = "paper_words" - p.SetName(bundle.name) - return p - -/obj/item/toner - name = "toner cartridge" - icon = 'icons/obj/items/tonercartridge.dmi' - icon_state = "tonercartridge" - var/toner_amount = 30 + LAZYADD(., /decl/interaction_handler/empty/photocopier_paper_bin) + LAZYADD(., /decl/interaction_handler/remove/photocopier_scanner_item) + +//////////////////////////////////////////////////////////////////////////////////////// +// Empty paper bin +//////////////////////////////////////////////////////////////////////////////////////// +/decl/interaction_handler/empty/photocopier_paper_bin + name = "Empty Paper Bin" + expected_target_type = /obj/machinery/photocopier + examine_desc = "empty $TARGET_THEM$" + +/decl/interaction_handler/empty/photocopier_paper_bin/is_possible(obj/machinery/photocopier/target, mob/user, obj/item/prop) + return (target.printer?.get_amount_paper() > 0) && ..() + +/decl/interaction_handler/empty/photocopier_paper_bin/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/photocopier/copier = target + if(copier.printer?.get_amount_paper() <= 0) + return + var/obj/item/paper_bundle/B = copier.printer?.remove_paper(user) + if(B) + user.put_in_hands(B) + target.update_icon() + SSnano.update_uis(target) + +//////////////////////////////////////////////////////////////////////////////////////// +// Remove item from scanner +//////////////////////////////////////////////////////////////////////////////////////// +/decl/interaction_handler/remove/photocopier_scanner_item + name = "Remove Item From Scanner" + expected_target_type = /obj/machinery/photocopier + examine_desc = "remove a loaded item" + +/decl/interaction_handler/remove/photocopier_scanner_item/is_possible(obj/machinery/photocopier/target, mob/user, obj/item/prop) + return target.scanner_item && ..() + +/decl/interaction_handler/remove/photocopier_scanner_item/invoked(atom/target, mob/user, obj/item/prop) + var/obj/machinery/photocopier/copier = target + copier.eject_item(user) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 27a62df329a3..db79cb62b396 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -10,260 +10,368 @@ * film * *******/ /obj/item/camera_film - name = "film cartridge" - icon = 'icons/obj/photography.dmi' - desc = "A camera film cartridge. Insert it into a camera to reload it." - icon_state = "film" - item_state = "electropack" - w_class = ITEM_SIZE_TINY + name = "film cartridge" + icon = 'icons/obj/photography.dmi' + desc = "A camera film cartridge. Insert it into a camera to reload it." + icon_state = "film" + item_state = "electropack" + w_class = ITEM_SIZE_SMALL + throw_range = 10 + material = /decl/material/solid/organic/plastic + var/const/max_uses = 10 + var/uses_left = max_uses + +/obj/item/camera_film/Initialize(ml, material_key) + set_extension(src, /datum/extension/base_icon_state, icon_state) + . = ..() + update_icon() +/obj/item/camera_film/on_update_icon() + . = ..() + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + if(uses_left > 1) + icon_state = "[bis.base_icon_state]" + SetName(initial(name)) + else + icon_state = "[bis.base_icon_state]-empty" + SetName("spent [initial(name)]") + +/obj/item/camera_film/proc/use() + if(uses_left < 1) + return FALSE + uses_left-- + update_icon() + return TRUE + +/obj/item/camera_film/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(uses_left < 1) + . += SPAN_WARNING("This cartridge is completely spent!") + else + . += "[uses_left] uses left." + +/obj/item/camera_film/proc/get_remaining() + return uses_left /******** * photo * ********/ -var/global/photo_count = 0 - /obj/item/photo - name = "photo" - icon = 'icons/obj/photography.dmi' - icon_state = "photo" - item_state = "paper" - randpixel = 10 - w_class = ITEM_SIZE_TINY - var/id - var/icon/img //Big photo image - var/scribble //Scribble on the back. - var/image/tiny - var/photo_size = 3 - -/obj/item/photo/Initialize() + name = "photo" + icon = 'icons/obj/photography.dmi' + icon_state = "photo" + item_state = "paper" + randpixel = 10 + w_class = ITEM_SIZE_TINY + item_flags = ITEM_FLAG_CAN_TAPE + material = /decl/material/solid/organic/plastic + var/id //Unique id used to name the photo resource to upload to the client, and for synthetic photo synchronization + var/icon/img //The actual real photo image + var/image/tiny //A thumbnail of the image that's displayed on the actual world icon of the photo + var/scribble //User written text on the backside of the photo + var/photo_size = 3 //Square size of the pictured scene in turfs + +/obj/item/photo/Initialize(ml, material_key, var/icon/_img, var/_scribble) . = ..() - id = photo_count++ + id = sequential_id("obj/item/photo") + if(_img) + img = _img + if(length(_scribble)) + scribble = _scribble + update_icon() + +/obj/item/photo/GetCloneArgs() + return list(null, material, img, scribble) + +/obj/item/photo/PopulateClone(obj/item/photo/clone) + clone = ..() + clone.photo_size = photo_size + return clone /obj/item/photo/attack_self(mob/user) - user.examinate(src) + user.examine_verb(src) + +/obj/item/photo/get_matter_amount_modifier() + return 0.2 /obj/item/photo/on_update_icon() - overlays.Cut() - var/scale = 8/(photo_size*32) + . = ..() + + var/scale = 8/(photo_size * WORLD_ICON_SIZE) var/image/small_img = image(img) small_img.transform *= scale - small_img.pixel_x = -32*(photo_size-1)/2 - 3 - small_img.pixel_y = -32*(photo_size-1)/2 - overlays |= small_img - + small_img.pixel_x = -WORLD_ICON_SIZE * (photo_size-1)/2 - 3 + small_img.pixel_y = -WORLD_ICON_SIZE * (photo_size-1)/2 + add_overlay(small_img) tiny = image(img) - tiny.transform *= 0.5*scale - tiny.underlays += image('icons/obj/bureaucracy.dmi',"photo") - tiny.pixel_x = -32*(photo_size-1)/2 - 3 - tiny.pixel_y = -32*(photo_size-1)/2 + 3 - -/obj/item/photo/attackby(obj/item/P, mob/user) - if(istype(P, /obj/item/pen)) - var/txt = sanitize(input(user, "What would you like to write on the back?", "Photo Writing", null) as text, 128) - if(loc == user && user.stat == 0) - scribble = txt - ..() - -/obj/item/photo/examine(mob/user, distance) + tiny.transform *= 0.5 * scale + tiny.underlays += image(icon, "photo_underlay") + tiny.pixel_x = -WORLD_ICON_SIZE * (photo_size-1)/2 - 3 + tiny.pixel_y = -WORLD_ICON_SIZE * (photo_size-1)/2 + 3 + +/obj/item/photo/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) + if(!CanPhysicallyInteractWith(user, src)) + to_chat(user, SPAN_WARNING("You can't interact with this!")) + return TRUE + scribble = sanitize(input(user, "What would you like to write on the back? (Leave empty to erase)", "Photo Writing", scribble), MAX_DESC_LEN) + return TRUE + return ..() + +/obj/item/photo/examined_by(mob/user, distance, infix, suffix) . = ..() + if(distance > 1) + to_chat(user, SPAN_NOTICE("It is too far away.")) + return if(!img) return - if(distance <= 1) - show(user) - to_chat(user, desc) - else - to_chat(user, "It is too far away.") + interact(user) -/obj/item/photo/proc/show(mob/user) +/obj/item/photo/interact(mob/user) send_rsc(user, img, "tmp_photo_[id].png") - user << browse("[name]" \ - + "" \ - + "" \ - + "[scribble ? "
    Written on the back:
    [scribble]" : ""]"\ - + "", "window=book;size=[64*photo_size]x[scribble ? 400 : 64*photo_size]") + // todo: remove -ms-interpolation-mode once 516 is required + var/photo_html = {" + [name] + + + [scribble ? "
    Written on the back:
    [scribble]" : ""] + + "} + user.set_machine(src) + show_browser(user, photo_html, "window=book;size=[64*photo_size]x[scribble ? 400 : 64*photo_size]") onclose(user, "[name]") +/obj/item/photo/proc/copy(var/copy_id = FALSE) + var/obj/item/photo/p = new + + p.SetName(name) // Do this first, manually, to make sure listeners are alerted properly. + p.appearance = appearance + + p.tiny = new + p.tiny.appearance = tiny.appearance + p.img = icon(img) + + p.photo_size = photo_size + p.scribble = scribble + + if(copy_id) + p.id = id + + return p + /obj/item/photo/verb/rename() set name = "Rename photo" set category = "Object" set src in usr - var/n_name = sanitizeSafe(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text, MAX_NAME_LEN) + var/n_name = sanitize_safe(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text, MAX_NAME_LEN) //loc.loc check is for making possible renaming photos in clipboards - if(!n_name || !CanInteract(usr, GLOB.deep_inventory_state)) + if(!n_name || !CanInteract(usr, global.deep_inventory_topic_state)) return SetName("[(n_name ? text("[n_name]") : "photo")]") add_fingerprint(usr) return - /************** * photo album * **************/ -/obj/item/storage/photo_album - name = "Photo album" - icon = 'icons/obj/photography.dmi' - icon_state = "album" - item_state = "briefcase" - w_class = ITEM_SIZE_NORMAL //same as book - storage_slots = DEFAULT_BOX_STORAGE //yes, that's storage_slots. Photos are w_class 1 so this has as many slots equal to the number of photos you could put in a box - can_hold = list(/obj/item/photo) - -/obj/item/storage/photo_album/MouseDrop(obj/over_object) - - if((istype(usr, /mob/living/carbon/human))) - var/mob/M = usr - if(!( istype(over_object, /obj/screen) )) - return ..() - playsound(loc, "rustle", 50, 1, -5) - if((!( M.restrained() ) && !( M.stat ) && M.back == src)) - switch(over_object.name) - if("r_hand") - if(M.unEquip(src)) - M.put_in_r_hand(src) - if("l_hand") - if(M.unEquip(src)) - M.put_in_l_hand(src) - add_fingerprint(usr) - return - if(over_object == usr && in_range(src, usr) || usr.contents.Find(src)) - if(usr.s_active) - usr.s_active.close(usr) - show_to(usr) - return - return +//#TODO: This thing is awful. Might as well use a trashbag instead since you get the same thing, just with more space.... +/obj/item/photo_album + name = "photo album" + icon = 'icons/obj/photo_album.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_NORMAL //same as book + storage = /datum/storage/photo_album + material = /decl/material/solid/organic/plastic + +/obj/item/photo_album/handle_mouse_drop(atom/over, mob/user, params) + if(over == user && in_range(src, user) || loc == user) + if(user.active_storage) + user.active_storage.close(user) + storage?.show_to(user) + return TRUE + . = ..() /********* * camera * *********/ /obj/item/camera - name = "camera" - icon = 'icons/obj/photography.dmi' - desc = "A polaroid camera." - icon_state = "camera" - item_state = "electropack" - w_class = ITEM_SIZE_SMALL - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT) - var/pictures_max = 10 - var/pictures_left = 10 - var/on = 1 - var/icon_on = "camera" - var/icon_off = "camera_off" - var/size = 3 -/obj/item/camera/on_update_icon() - var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) - if(on) - icon_state = "[bis.base_icon_state]" - else - icon_state = "[bis.base_icon_state]_off" + name = "camera" + icon = 'icons/obj/photography.dmi' + desc = "A polaroid camera." + icon_state = "camera" + item_state = "electropack" + item_flags = ITEM_FLAG_NO_BLUDGEON + w_class = ITEM_SIZE_SMALL + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + var/turned_on = TRUE + var/field_of_view = 3 // squared, so 3 is a 3x3 of tiles + var/obj/item/camera_film/film = new //Currently loaded film + +/obj/item/camera/loaded/Initialize() + film = new(src) + return ..() + /obj/item/camera/Initialize() set_extension(src, /datum/extension/base_icon_state, icon_state) + . = ..() update_icon() + +/obj/item/camera/loaded/Initialize() . = ..() + film = new /obj/item/camera_film(src) -/obj/item/camera/verb/change_size() - set name = "Set Photo Focus" - set category = "Object" - var/nsize = input("Photo Size","Pick a size of resulting photo.") as null|anything in list(1,3,5,7) - if(nsize) - size = nsize - to_chat(usr, "Camera will now take [size]x[size] photos.") +/obj/item/camera/on_update_icon() + . = ..() + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + if(turned_on) + icon_state = "[bis.base_icon_state]" + else + icon_state = "[bis.base_icon_state]_off" -/obj/item/camera/attack(mob/living/carbon/human/M, mob/user) - return +/obj/item/camera/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE /obj/item/camera/attack_self(mob/user) - on = !on - update_icon() - to_chat(user, "You switch the camera [on ? "on" : "off"].") - return - -/obj/item/camera/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/camera_film)) - if(pictures_left) - to_chat(user, "[src] still has some film in it!") - return - to_chat(user, "You insert [I] into [src].") - qdel(I) - pictures_left = pictures_max - return - ..() - + if(film) + turned_on = !turned_on + to_chat(user, SPAN_NOTICE("You switch the camera [turned_on ? "on" : "off"].")) + update_icon() + return TRUE + else + to_chat(user, SPAN_WARNING("\The [src] needs film loaded to turn on!")) + return FALSE -/obj/item/camera/proc/get_mobs(turf/the_turf) - var/mob_detail - for(var/mob/living/carbon/A in the_turf) - if(A.invisibility) continue - var/holding = null - if(A.l_hand || A.r_hand) - if(A.l_hand) holding = "They are holding \a [A.l_hand]" - if(A.r_hand) - if(holding) - holding += " and \a [A.r_hand]" +/obj/item/camera/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/camera_eject_film) + +/obj/item/camera/proc/eject_film(mob/user) + if(film) + user.visible_message(SPAN_NOTICE("[user] ejects \the [film] from \the [src]."), SPAN_NOTICE("You eject \the [film] from \the [src].")) + playsound(user, 'sound/machines/button1.ogg', 40, TRUE) + user.put_in_hands(film) + film = null + turned_on = FALSE + update_icon() + return TRUE + + to_chat(user, SPAN_WARNING("There is no cartridge in \the [src] to eject!")) + +/obj/item/camera/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/camera_film)) + if(film) + //Skilled people don't have to remove the film first! + if(user.get_skill_value(SKILL_DEVICES) >= SKILL_EXPERT) + if(user.do_skilled(1 SECONDS, SKILL_DEVICES, src)) + user.visible_message( + SPAN_NOTICE("In a swift flick of the finger, [user] ejects \the [film], and slides in \the [used_item]!"), + SPAN_NOTICE("From habit you instinctively pop the old [film] from \the [src] and insert a new [used_item] deftly!")) + user.try_unequip(used_item, src) + user.put_in_active_hand(film) + film = used_item + return TRUE + return TRUE + //Unskilled losers have to remove it first + to_chat(user, SPAN_NOTICE("[src] already has some film in it! Remove it first!")) + return TRUE + else + if(user.do_skilled(1 SECONDS, SKILL_DEVICES, src)) + if(user.get_skill_value(SKILL_DEVICES) >= SKILL_EXPERT) + user.visible_message( + SPAN_NOTICE("[user] swiftly slides \the [used_item] into \the [src]!"), + SPAN_NOTICE("You insert \a [used_item] swiftly into \the [src]!")) else - holding = "They are holding \a [A.r_hand]" - + user.visible_message( + SPAN_NOTICE("[user] inserts \a [used_item] into his [src]."), + SPAN_NOTICE("You insert \the [used_item] into \the [src].")) + user.try_unequip(used_item, src) + film = used_item + return TRUE + return TRUE + return ..() + +/obj/item/camera/proc/get_mob_details(turf/the_turf) + var/mob_detail + for(var/mob/living/seen in the_turf) + if(seen.invisibility) + continue + var/holding + for(var/obj/item/thing in seen.get_held_items()) + LAZYADD(holding, "\a [thing]") + if(length(holding)) + var/decl/pronouns/mob_pronouns = seen.get_pronouns() + holding = "[mob_pronouns.He] [mob_pronouns.is] holding [english_list(holding)]." if(!mob_detail) - mob_detail = "You can see [A] on the photo[(A.health / A.maxHealth) < 0.75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. " + mob_detail = "You can see [seen] on the photo[seen.get_health_ratio() < 0.75 ? " - [seen] looks hurt":""].[holding ? " [holding]":"."]. " else - mob_detail += "You can also see [A] on the photo[(A.health / A.maxHealth)< 0.75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]." + mob_detail += "You can also see [seen] on the photo[seen.get_health_ratio() < 0.75 ? " - [seen] looks hurt":""].[holding ? " [holding]":"."]." return mob_detail /obj/item/camera/afterattack(atom/target, mob/user, flag) - if(!on || !pictures_left || ismob(target.loc)) return - captureimage(target, user, flag) + if(!turned_on && (user.get_skill_value(SKILL_LITERACY) < SKILL_EXPERT)) + to_chat(user, SPAN_WARNING("Turn \the [src] on first!")) + return + else if(!turned_on) + to_chat(user, SPAN_NOTICE("From habit you turn your [src] on.")) + turned_on = TRUE + update_icon() + + if(!film?.get_remaining()) + //If out of pictures, and if we're an expert and are holding a film offhand, try to automatically load it + if((user.get_skill_value(SKILL_LITERACY) >= SKILL_EXPERT)) + var/obj/item/camera_film/F = locate(/obj/item/camera_film) in user.get_held_items() + if(F && F.get_remaining() > 0) + attackby(F, user) + + if(!film?.get_remaining()) + update_icon() + to_chat(user, SPAN_WARNING("It's out of film!")) + return + film.use() + captureimage(target, user, flag) playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3) + to_chat(user, SPAN_NOTICE("[film.get_remaining()] photo\s left.")) + return TRUE - pictures_left-- - to_chat(user, "[pictures_left] photos left.") - - on = 0 - update_icon() - -/obj/item/camera/examine(mob/user) +/obj/item/camera/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It has [pictures_left] photo\s left.") - -//Proc for capturing check -/mob/living/proc/can_capture_turf(turf/T) - var/viewer = src - if(src.client) //To make shooting through security cameras possible - viewer = src.client.eye - var/can_see = (T in view(viewer)) - return can_see + if(film) + . += "It has [film?.get_remaining()] photo\s left." + else + . += "It doesn't have a film cartridge." /obj/item/camera/proc/captureimage(atom/target, mob/living/user, flag) - var/x_c = target.x - (size-1)/2 - var/y_c = target.y + (size-1)/2 + var/x_c = target.x - (field_of_view-1)/2 + var/y_c = target.y + (field_of_view-1)/2 var/z_c = target.z - var/mobs = "" - for(var/i = 1 to size) - for(var/j = 1 to size) + var/mob_details = "" + for(var/i = 1 to field_of_view) + for(var/j = 1 to field_of_view) var/turf/T = locate(x_c, y_c, z_c) if(user.can_capture_turf(T)) - mobs += get_mobs(T) + mob_details += get_mob_details(T) x_c++ y_c-- - x_c = x_c - size + x_c = x_c - field_of_view - var/obj/item/photo/p = createpicture(target, user, mobs, flag) + var/obj/item/photo/p = createpicture(target, user, mob_details, flag) printpicture(user, p) -/obj/item/camera/proc/createpicture(atom/target, mob/user, mobs, flag) - var/x_c = target.x - (size-1)/2 - var/y_c = target.y - (size-1)/2 +/obj/item/camera/proc/createpicture(atom/target, mob/user, new_description, flag) + var/x_c = target.x - (field_of_view-1)/2 + var/y_c = target.y - (field_of_view-1)/2 var/z_c = target.z - var/icon/photoimage = generate_image(x_c, y_c, z_c, size, CAPTURE_MODE_REGULAR, user, 0) + var/icon/photoimage = create_area_image(x_c, y_c, z_c, field_of_view, TRUE, user) var/obj/item/photo/p = new() p.img = photoimage - p.desc = mobs - p.photo_size = size + p.desc = new_description + p.photo_size = field_of_view p.update_icon() return p @@ -272,20 +380,32 @@ var/global/photo_count = 0 if(!user.put_in_inactive_hand(p)) p.dropInto(loc) -/obj/item/photo/proc/copy(var/copy_id = 0) - var/obj/item/photo/p = new/obj/item/photo() - - p.SetName(name) // Do this first, manually, to make sure listeners are alerted properly. - p.appearance = appearance - - p.tiny = new - p.tiny.appearance = tiny.appearance - p.img = icon(img) - - p.photo_size = photo_size - p.scribble = scribble +/obj/item/camera/verb/change_size() + set name = "Set Photo Focus" + set category = "Object" + var/nsize = input("Photo Size","Pick a size of resulting photo.") as null|anything in list(1,3,5,7) + if(nsize) + field_of_view = nsize + to_chat(usr, SPAN_NOTICE("Camera will now take [field_of_view]x[field_of_view] photos.")) - if(copy_id) - p.id = id +//Proc for capturing check +/mob/living/proc/can_capture_turf(turf/T) + var/viewer = src + if(src.client) //To make shooting through security cameras possible + viewer = src.client.eye + var/can_see = (T in view(viewer)) + return can_see - return p +//////////////////////////////////////////// +// Eject Film Interaction +//////////////////////////////////////////// +/decl/interaction_handler/camera_eject_film + name = "eject film cartridge" + icon = 'icons/screen/radial.dmi' + icon_state = "radial_eject" + expected_target_type = /obj/item/camera + examine_desc = "eject the film" + +/decl/interaction_handler/camera_eject_film/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/camera/camera = target + camera.eject_film(user) diff --git a/code/modules/paperwork/printer.dm b/code/modules/paperwork/printer.dm new file mode 100644 index 000000000000..802624d7d04b --- /dev/null +++ b/code/modules/paperwork/printer.dm @@ -0,0 +1,441 @@ +#define PRINTER_LOW_TONER_THRESHOLD 10 //Below this threshold we consider the toner to be low, and print lighter tones. + +//////////////////////////////////////////////////////////////////////////////////////// +// Printer Component +//////////////////////////////////////////////////////////////////////////////////////// +/obj/item/stock_parts/printer + name = "printer" + desc = "A full-fledged laser printer. This one is meant to be installed inside another machine. Comes with its own paper feeder and toner slot." + icon = 'icons/obj/items/stock_parts/modular_components.dmi' + icon_state = "printer" + randpixel = 5 + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/copper = MATTER_AMOUNT_REINFORCEMENT, + ) + base_type = /obj/item/stock_parts/printer + max_health = ITEM_HEALTH_NO_DAMAGE + part_flags = PART_FLAG_QDEL + var/list/print_queue //Contains a single copy of each of the /obj/item/paper or /obj/item/photo that we'll print. + var/obj/item/chems/toner_cartridge/toner //Contains our ink + var/paper_left = 0 //Amount of blank paper sheets left in the printer + var/tmp/paper_max = 100 //Maximum amount of blank paper sheets in the printer + var/is_printing = FALSE //Whether we're currently running our print queue + var/time_last_print = 0 //Time we last printed a sheet + var/tmp/print_time = 1 SECONDS //Time it takes to print a sheet + var/show_queue_ctrl = TRUE //Whether the UI will display queue controls for the printer + + var/datum/callback/call_on_printed_page //Callback called when we printed a page from the queue. + var/datum/callback/call_on_finished_queue //Callback called when we finish printing all queued items. + var/datum/callback/call_on_print_error //Callback called when we run out of paper or toner, or something else interrupts printing. + var/datum/callback/call_on_status_changed //Callback called when the status of the printer changes, and the owner ui should update. + +//Buildable: Can be removed from the machine, and damaged +/obj/item/stock_parts/printer/buildable + part_flags = PART_FLAG_HAND_REMOVE + max_health = 64 + +//Buildable + Filled variant: has sheet and toner on spawn +/obj/item/stock_parts/printer/buildable/filled/Initialize(ml, material_key) + . = ..() + if(. != INITIALIZE_HINT_QDEL) + make_full() + +/obj/item/stock_parts/printer/proc/make_full() + paper_left = paper_max + toner = new(src) + +/obj/item/stock_parts/printer/Destroy() + stop_printing_queue() + QDEL_NULL_LIST(print_queue) //Since we don't drop those, we have to delete them + QDEL_NULL(toner) + unregister_on_printed_page() + unregister_on_finished_queue() + unregister_on_print_error() + unregister_on_status_changed() + return ..() + +/obj/item/stock_parts/printer/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/chems/toner_cartridge)) + if(toner) + to_chat(user, SPAN_WARNING("There is already \a [used_item] in \the [src]!")) + return TRUE + return insert_toner(used_item, user) + + else if(istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/paper_bundle)) + if(paper_left >= paper_max) + to_chat(user, SPAN_WARNING("There is no more room for paper in \the [src]!")) + return TRUE + return insert_paper(used_item, user) + . = ..() + +/obj/item/stock_parts/printer/attack_hand(mob/user) + if(toner && istype(loc, /obj/machinery) && user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return remove_toner(user) + return ..() + +/obj/item/stock_parts/printer/attack_self(mob/user) + if(toner) + return remove_toner(user) + return ..() + +/obj/item/stock_parts/printer/dump_contents(atom/forced_loc = loc, mob/user) + . = ..() + LAZYREMOVE(., print_queue) //Don't drop our stored copies, those are gonna get deleted + remove_paper() //Dump the blank paper we contain + +/obj/item/stock_parts/printer/machine_process() + if(!is_functional() || !has_enough_to_print() || (LAZYLEN(print_queue) <= 0)) + stop_printing_queue() + return PROCESS_KILL + + //Process print queue + if(world.timeofday > (time_last_print + print_time)) + //update queue + print(print_queue[print_queue.len]) + print_queue.len-- + time_last_print = world.timeofday + +//Since its hard to store all data from all kinds of printable things in a generic way, just create a copy and store it in us +/** Enqueue a job and make a copy of the paper, picture, bundle or text string or image that's passed into parameters. */ +/obj/item/stock_parts/printer/proc/queue_job(var/obj/item/doc) + if(istype(doc, /obj/item/paper)) + var/obj/item/paper/P = doc + P = P.Clone() + P.forceMove(src) + LAZYADD(print_queue, P) + + else if(istype(doc, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = doc + B = B.Clone() + B.forceMove(src) + LAZYADD(print_queue, B) + + else if(istype(doc, /obj/item/photo)) + var/obj/item/photo/Ph = doc + Ph = Ph.Clone() + Ph.forceMove(src) + LAZYADD(print_queue, Ph) + + else if(istext(doc)) + var/obj/item/paper/P = new(src, null, doc) + LAZYADD(print_queue, P) + + else if(istype(doc, /image)) + var/obj/item/photo/Ph = new(src, null, new /icon(doc)) + LAZYADD(print_queue, Ph) + + else + CRASH("Invalid type '[doc]'([doc?.type]) was passed to printer!") + + if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + return TRUE + +/**Fully clears the job queue */ +/obj/item/stock_parts/printer/proc/clear_job_queue() + QDEL_NULL_LIST(print_queue) + +/**Allow inserting a toner cartridge into the printer */ +/obj/item/stock_parts/printer/proc/insert_toner(var/obj/item/chems/toner_cartridge/T, var/mob/user) + if(toner) + if(user) + to_chat(user, SPAN_WARNING("There's already a cartridge in \the [src].")) + return TRUE + + if(!user.try_unequip(T, src)) + return TRUE + toner = T + if(user) + to_chat(user, SPAN_NOTICE("You install \a [T] in \the [src].")) + if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + return TRUE + +/**Allow removing the toner cartridge from the printer */ +/obj/item/stock_parts/printer/proc/remove_toner(var/mob/user) + if(!toner) + if(user) + to_chat(user, SPAN_WARNING("There is no toner cartridge in \the [src].")) + return TRUE + + if(user) + user.put_in_hands(toner) + to_chat(user, SPAN_NOTICE("You remove \the [toner] from \the [src].")) + else + toner.dropInto(get_turf(loc)) + toner = null + if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + return TRUE + +/**Allow inserting either a blank paper or blank paper bundle into the printer. */ +/obj/item/stock_parts/printer/proc/insert_paper(var/obj/item/paper_refill, var/mob/user) + if(paper_left >= paper_max) + if(user) + to_chat(user, SPAN_WARNING("There is no room for more paper in \the [src].")) + return TRUE + + if(istype(paper_refill, /obj/item/paper)) + var/obj/item/paper/P = paper_refill + if(!P.is_blank()) + if(user) + to_chat(user, SPAN_WARNING("\The [P] isn't blank!")) + return TRUE + if(!user?.try_unequip(paper_refill)) + return TRUE + if(user) + to_chat(user, SPAN_NOTICE("You insert \a [paper_refill] in \the [src].")) + qdel(paper_refill) + paper_left++ + + else if(istype(paper_refill, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/B = paper_refill + if(!B.is_blank()) + if(user) + to_chat(user, SPAN_WARNING("\The [B] contains some non-blank pages, or something else than paper sheets!")) + return TRUE + + var/amt_papers = B.get_amount_papers() + var/to_insert = min((paper_max - paper_left), amt_papers) + if(to_insert >= amt_papers) + if(!user.try_unequip(B)) + return TRUE + if(user) + to_chat(user, SPAN_NOTICE("You insert \a [paper_refill] in \the [src].")) + qdel(B) + else + B.remove_sheets(to_insert, user) + paper_left += to_insert + + if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + return TRUE + +/obj/item/stock_parts/printer/proc/remove_paper(var/mob/user) + if(paper_left <= 0) + if(user) + to_chat(user, SPAN_WARNING("There are no sheets of paper in \the [src].")) + return + + var/obj/item/paper_bundle/B = new + while(paper_left > 0) + B.merge(new /obj/item/paper) + paper_left-- + + if(user) + user.put_in_hands(B) + to_chat(user, SPAN_NOTICE("You grab all the paper sheets from \the [src].")) + else + B.dropInto(get_turf(loc)) + if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + return B + +/obj/item/stock_parts/printer/proc/has_enough_to_print(var/req_toner = 1, var/req_paper = 1) + return (req_paper <= paper_left) && (req_toner <= (toner?.get_amount_toner())) + +/obj/item/stock_parts/printer/proc/get_amount_paper() + return paper_left + +/obj/item/stock_parts/printer/proc/get_amount_paper_max() + return paper_max + +/obj/item/stock_parts/printer/proc/get_amount_toner() + return toner? toner.get_amount_toner() : 0 + +/obj/item/stock_parts/printer/proc/get_amount_toner_max() + return toner? toner.get_amount_toner_max() : 0 + +/obj/item/stock_parts/printer/proc/get_amount_queued() + return length(print_queue) + +/obj/item/stock_parts/printer/proc/is_printing() + return is_printing + +/obj/item/stock_parts/printer/proc/start_printing_queue() + start_processing(loc) + is_printing = TRUE + if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + +/obj/item/stock_parts/printer/proc/stop_printing_queue() + stop_processing(loc) + is_printing = FALSE + + if(LAZYLEN(print_queue) < 1 && call_on_finished_queue) + call_on_finished_queue.InvokeAsync() + else if(call_on_status_changed) + call_on_status_changed.InvokeAsync() + +/obj/item/stock_parts/printer/proc/print(var/obj/item/queued_element) + if(istype(queued_element, /obj/item/photo)) + if(!has_enough_to_print(TONER_USAGE_PHOTO)) + var/obj/machinery/M = loc + if(istype(M)) + M.state("Warning: Not enough paper or toner!") + stop_printing_queue() + return FALSE + print_picture(queued_element) + else if(istype(queued_element, /obj/item/paper_bundle)) + var/obj/item/paper_bundle/bundle = queued_element + var/photo_count = 0 + for(var/obj/item/photo/picture in bundle.pages) + photo_count++ + if(!has_enough_to_print((TONER_USAGE_PAPER * (length(bundle.pages) - photo_count)) + (TONER_USAGE_PHOTO * photo_count))) + var/obj/machinery/M = loc + if(istype(M)) + M.state("Warning: Not enough paper or toner!") + stop_printing_queue() + return FALSE + print_paper_bundle(bundle) + else if(istype(queued_element, /obj/item/paper)) + if(!has_enough_to_print(TONER_USAGE_PAPER)) + var/obj/machinery/M = loc + if(istype(M)) + M.state("Warning: Not enough paper or toner!") + stop_printing_queue() + return FALSE + print_paper(queued_element) + else + PRINT_STACK_TRACE("A printer printed something that wasn't a paper, paper bundle, or photo: [queued_element] ([queued_element.type])") + + //#TODO: machinery should allow a component to trigger and wait for an animation sequence. So that we can drop out the paper in sync. + queued_element.dropInto(get_turf(loc)) + playsound(loc, "sound/machines/dotprinter.ogg", 50, TRUE) + return TRUE + +/obj/item/stock_parts/printer/proc/print_picture(var/obj/item/photo/P) + if(get_amount_toner() > PRINTER_LOW_TONER_THRESHOLD) //plenty of toner, go straight greyscale + P.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))//I'm not sure how expensive this is, but given the many limitations of photocopying, it shouldn't be an issue. + P.update_icon() + else //not much toner left, lighten the photo + P.img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(100,100,100)) + P.update_icon() + + use_toner(TONER_USAGE_PHOTO, FALSE) //photos use a lot of ink! + use_paper(1) + P.update_icon() + +/obj/item/stock_parts/printer/proc/print_paper_bundle(var/obj/item/paper_bundle/bundle) + for(var/obj/item/paper/page in bundle.pages) + print_paper(page) + for(var/obj/item/photo/picture in bundle.pages) + print_picture(picture) + bundle.update_icon() + +/obj/item/stock_parts/printer/proc/print_paper(var/obj/item/paper/P) + //Apply a greyscale filter on all stamps overlays + for(var/image/I in P.applied_stamps) + I.filters += filter(type = "color", color = list(1,0,0, 0,0,0, 0,0,1), space = FILTER_COLOR_HSV) + var/copied = P.info + + //#TODO: This is very janky, but too many things work this way in pencode to change it for now. + //This basically just breaks the existing color tag, which we need to do because the innermost tag takes priority. + copied = replacetext(copied, " PRINTER_LOW_TONER_THRESHOLD)? "#101010" : "#808080"]>[copied]") + + use_toner(TONER_USAGE_PAPER, FALSE) + use_paper(1) + P.update_icon() // reapply stamp overlays + +/obj/item/stock_parts/printer/proc/use_toner(var/amount, var/update_parent = TRUE) + if(!toner?.use_toner(amount)) + return FALSE + if(update_parent && call_on_status_changed) + call_on_status_changed.InvokeAsync() + return TRUE + +/obj/item/stock_parts/printer/proc/use_paper(var/amount, var/update_parent = TRUE) + if(paper_left <= 0) + return FALSE + paper_left -= amount + if(update_parent && call_on_status_changed) + call_on_status_changed.InvokeAsync() + return TRUE + +/obj/item/stock_parts/printer/proc/register_on_printed_page(var/datum/callback/cb) + call_on_printed_page = cb +/obj/item/stock_parts/printer/proc/unregister_on_printed_page() + QDEL_NULL(call_on_printed_page) + +/obj/item/stock_parts/printer/proc/register_on_finished_queue(var/datum/callback/cb) + call_on_finished_queue = cb +/obj/item/stock_parts/printer/proc/unregister_on_finished_queue() + QDEL_NULL(call_on_finished_queue) + +/obj/item/stock_parts/printer/proc/register_on_print_error(var/datum/callback/cb) + call_on_print_error = cb +/obj/item/stock_parts/printer/proc/unregister_on_print_error() + QDEL_NULL(call_on_print_error) + +/obj/item/stock_parts/printer/proc/register_on_status_changed(var/datum/callback/cb) + call_on_status_changed = cb +/obj/item/stock_parts/printer/proc/unregister_on_status_changed() + QDEL_NULL(call_on_status_changed) + +/obj/item/stock_parts/printer/on_install(obj/machinery/machine) + unregister_on_printed_page() + unregister_on_finished_queue() + unregister_on_print_error() + unregister_on_status_changed() + . = ..() + +/obj/item/stock_parts/printer/on_uninstall(obj/machinery/machine, temporary) + . = ..() + unregister_on_printed_page() + unregister_on_finished_queue() + unregister_on_print_error() + unregister_on_status_changed() + +/obj/item/stock_parts/printer/ui_data(mob/user, ui_key) + . = ..() + LAZYSET(., "toner", get_amount_toner()) + LAZYSET(., "toner_max", get_amount_toner_max()) + LAZYSET(., "paper_feeder", get_amount_paper()) + LAZYSET(., "paper_feeder_max", get_amount_paper_max()) + LAZYSET(., "is_printing", is_printing()) + LAZYSET(., "is_functional", is_functional()) + LAZYSET(., "left_printing", get_amount_queued()) + LAZYSET(., "show_print_ctrl", show_queue_ctrl) + +/obj/item/stock_parts/printer/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["resume_print"]) + if(has_enough_to_print() && (get_amount_queued() > 0)) + start_printing_queue() + else if(user) + to_chat(user, SPAN_WARNING("\The [src] is out of paper or toner!")) + . = TOPIC_REFRESH + + if(href_list["stop_print"]) + if(is_printing()) + stop_printing_queue() + else if(user) + to_chat(user, SPAN_WARNING("\The [src] is not currently printing!")) + . = TOPIC_REFRESH + +// Interactions +/decl/interaction_handler/empty/stock_parts_printer + name = "Empty Paper Bin" + expected_target_type = /obj/item/stock_parts/printer + examine_desc = "empty $TARGET_THEM$" + +/decl/interaction_handler/empty/stock_parts_printer/is_possible(obj/item/stock_parts/printer/target, mob/user, obj/item/prop) + return (target.get_amount_paper() > 0) && ..() + +/decl/interaction_handler/empty/stock_parts_printer/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/stock_parts/printer/printer = target + if(printer.get_amount_paper() <= 0) + return + var/obj/item/paper_bundle/B = printer.remove_paper(user) + if(B) + user.put_in_hands(B) + target.update_icon() + SSnano.update_uis(target) + +#undef PRINTER_LOW_TONER_THRESHOLD \ No newline at end of file diff --git a/code/modules/paperwork/silicon_photography.dm b/code/modules/paperwork/silicon_photography.dm index 984efe49798e..6c6f4835a0f6 100644 --- a/code/modules/paperwork/silicon_photography.dm +++ b/code/modules/paperwork/silicon_photography.dm @@ -24,11 +24,11 @@ /obj/item/camera/siliconcam/proc/injectmasteralbum(obj/item/photo/p) //stores image information to a list similar to that of the datacore var/mob/living/silicon/robot/C = usr if(C.connected_ai) - C.connected_ai.silicon_camera.injectaialbum(p.copy(1), " (synced from [C.name])") - to_chat(C.connected_ai, "Image uploaded by [C.name]") - to_chat(usr, "Image synced to remote database, and can be printed from any photocopier.")//feedback to the Cyborg player that the picture was taken + C.connected_ai.silicon_camera.injectaialbum(p.copy(1), " (synced from [C])") + to_chat(C.connected_ai, SPAN_NOTICE("Image uploaded by [C].")) + to_chat(usr, SPAN_NOTICE("Image synced to remote database, and can be printed from any photocopier."))//feedback to the Cyborg player that the picture was taken else - to_chat(usr, "Image recorded, and can be printed from any photocopier.") + to_chat(usr, SPAN_NOTICE("Image recorded, and can be printed from any photocopier.")) // Always save locally injectaialbum(p) @@ -39,7 +39,7 @@ var/list/nametemp = list() var/find if(cam.aipictures.len == 0) - to_chat(usr, "No images saved") + to_chat(usr, SPAN_DANGER("No images saved.")) return for(var/obj/item/photo/t in cam.aipictures) nametemp += t.name @@ -57,7 +57,7 @@ if(!selection) return - selection.show(usr) + selection.interact(usr) to_chat(usr, selection.desc) /obj/item/camera/siliconcam/proc/deletepicture(obj/item/camera/siliconcam/cam) var/selection = selectpicture(cam) @@ -66,7 +66,7 @@ return aipictures -= selection - to_chat(usr, "Local image deleted") + to_chat(usr, SPAN_NOTICE("Local image deleted.")) //Capture Proc for AI / Robot /mob/living/silicon/ai/can_capture_turf(turf/T) var/mob/living/silicon/ai = src @@ -86,7 +86,7 @@ to_chat(usr, "Camera Mode activated") /obj/item/camera/siliconcam/ai_camera/printpicture(mob/user, obj/item/photo/p) injectaialbum(p) - to_chat(usr, "Image recorded") + to_chat(usr, SPAN_NOTICE("Image recorded.")) /obj/item/camera/siliconcam/robot_camera/printpicture(mob/user, obj/item/photo/p) injectmasteralbum(p) @@ -138,8 +138,8 @@ deletepicture(src) -obj/item/camera/siliconcam/proc/getsource() - if(istype(src.loc, /mob/living/silicon/ai)) +/obj/item/camera/siliconcam/proc/getsource() + if(isAI(src.loc)) return src var/mob/living/silicon/robot/C = usr diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm index 95b661480500..9e5dbd514a42 100644 --- a/code/modules/paperwork/stamps.dm +++ b/code/modules/paperwork/stamps.dm @@ -1,71 +1,49 @@ /obj/item/stamp - name = "rubber stamp" - desc = "A rubber stamp for stamping important documents." - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "stamp-deckchief" - item_state = "stamp" - throwforce = 0 - w_class = ITEM_SIZE_TINY + name = "rubber stamp" + desc = "A rubber stamp for stamping important documents." + icon = 'icons/obj/items/stamps/stamp_deckchief.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL throw_speed = 7 throw_range = 15 - material = /decl/material/solid/metal/steel - attack_verb = list("stamped") + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, + ) + attack_verb = "stamped" -/obj/item/stamp/captain - name = "captain's rubber stamp" - icon_state = "stamp-cap" - -/obj/item/stamp/ce - name = "chief engineer's rubber stamp" - icon_state = "stamp-ce" - -/obj/item/stamp/rd - name = "chief science officer's rubber stamp" - icon_state = "stamp-rd" - -/obj/item/stamp/cmo - name = "chief medical officer's rubber stamp" - icon_state = "stamp-cmo" +/obj/item/stamp/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_STAMP = TOOL_QUALITY_DEFAULT)) /obj/item/stamp/denied name = "\improper DENIED rubber stamp" - icon_state = "stamp-deny" + icon = 'icons/obj/items/stamps/stamp_deny.dmi' /obj/item/stamp/clown name = "clown's rubber stamp" - icon_state = "stamp-clown" + icon = 'icons/obj/items/stamps/stamp_clown.dmi' /obj/item/stamp/boss name = "boss' rubber stamp" - icon_state = "stamp-boss" + icon = 'icons/obj/items/stamps/stamp_boss.dmi' /obj/item/stamp/boss/Initialize() - name = "[GLOB.using_map.boss_name]'s' rubber stamp" + name = "[global.using_map.boss_name]'s' rubber stamp" . = ..() -/obj/item/stamp/cargo - name = "cargo rubber stamp" - icon_state = "stamp-cargo" - // Syndicate stamp to forge documents. /obj/item/stamp/chameleon/attack_self(mob/user) - - var/list/stamp_types = typesof(/obj/item/stamp) - src.type // Get all stamp types except our own var/list/stamps = list() - // Generate them into a list - for(var/stamp_type in stamp_types) - var/obj/item/stamp/S = new stamp_type - stamps[capitalize(S.name)] = S - - var/list/show_stamps = list("EXIT" = null) + sortList(stamps) // the list that will be shown to the user to pick from - + for(var/stamp_type in typesof(/obj/item/stamp)-type) // Don't include our own type. + var/obj/item/stamp/S = stamp_type + if(!TYPE_IS_ABSTRACT(S)) + stamps[capitalize(initial(S.name))] = S + var/list/show_stamps = list("EXIT" = null) + sortTim(stamps, /proc/cmp_text_asc) // the list that will be shown to the user to pick from var/input_stamp = input(user, "Choose a stamp to disguise as.", "Choose a stamp.") in show_stamps - - if(user && (src in user.contents)) - + if(input_stamp && !QDELETED(user) && !QDELETED(src) && user.get_active_held_item() == src) var/obj/item/stamp/chosen_stamp = stamps[capitalize(input_stamp)] - if(chosen_stamp) - SetName(chosen_stamp.name) - icon_state = chosen_stamp.icon_state + appearance = chosen_stamp + SetName(atom_info_repository.get_name_for(chosen_stamp)) // needed for dynamic centcomm stamp diff --git a/code/modules/paperwork/toner_cartridge.dm b/code/modules/paperwork/toner_cartridge.dm new file mode 100644 index 000000000000..7c1eedfb5991 --- /dev/null +++ b/code/modules/paperwork/toner_cartridge.dm @@ -0,0 +1,51 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// Toner Cartridge +//////////////////////////////////////////////////////////////////////////////////////// +/obj/item/chems/toner_cartridge + name = "toner cartridge" + desc = "A large cartridge containing pigmented polymer powder for photocopiers to print with." + icon = 'icons/obj/items/tonercartridge.dmi' + icon_state = ICON_STATE_WORLD + throw_range = 5 + throw_speed = 4 + w_class = ITEM_SIZE_NORMAL + material = /decl/material/solid/organic/plastic + chem_volume = 60 + amount_per_transfer_from_this = 30 + possible_transfer_amounts = @"[30,60]" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + _base_attack_force = 3 + +/obj/item/chems/toner_cartridge/populate_reagents() + //Normally this would be toner powder, but probably not worth making a material for that. + add_to_reagents(/decl/material/liquid/paint, REAGENT_MAXIMUM_VOLUME(reagents)/2) + add_to_reagents(/decl/material/liquid/pigment/black, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/toner_cartridge/dump_contents(atom/forced_loc = loc, mob/user) + . = ..() + reagents?.splash(get_turf(forced_loc), REAGENT_TOTAL_VOLUME(reagents)) + +/obj/item/chems/toner_cartridge/physically_destroyed(skip_qdel) + material.place_shards(get_turf(src), 2) + . = ..() + +/obj/item/chems/toner_cartridge/throw_impact(atom/hit_atom, datum/thrownthing/TT) + . = ..() + current_health = clamp(current_health - (TT.speed * w_class), 0, get_max_health()) //You don't wanna throw this around too much + check_health() + +/obj/item/chems/toner_cartridge/proc/get_amount_toner() + //Since ink is paint + pigment in a 1:1 ratio, we get the lowest amount we can + return round(min(REAGENT_VOLUME(reagents, /decl/material/liquid/pigment/black), REAGENT_VOLUME(reagents, /decl/material/liquid/paint)), 0.01) + +/obj/item/chems/toner_cartridge/proc/get_amount_toner_max() + //Since ink is paint + pigment in a 1:1 ratio, only half the volume is actually usable + return round(REAGENT_MAXIMUM_VOLUME(reagents) / 2, 0.01) + +/obj/item/chems/toner_cartridge/proc/use_toner(var/amount) + if(!reagents) + return + var/amt_each = round(amount/2) + if(reagents.has_reagent(/decl/material/liquid/pigment/black, amt_each) && reagents.has_reagent(/decl/material/liquid/paint, amt_each)) + remove_any_reagents(amount) + return TRUE \ No newline at end of file diff --git a/code/modules/persistence/filth.dm b/code/modules/persistence/filth.dm index 2bce08e43318..07af39cfc8d9 100644 --- a/code/modules/persistence/filth.dm +++ b/code/modules/persistence/filth.dm @@ -1,13 +1,14 @@ /obj/effect/decal/cleanable/filth - name = "filth" - desc = "Disgusting. Someone from last shift didn't do their job properly." - icon = 'icons/effects/blood.dmi' - icon_state = "mfloor1" - random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") - color = "#464f33" - persistent = TRUE - anchored = TRUE + name = "filth" + desc = "Disgusting. Someone from last shift didn't do their job properly." + icon = 'icons/effects/blood.dmi' + icon_state = "mfloor1" + random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") + color = "#464f33" + use_legacy_persistence = TRUE + anchored = TRUE /obj/effect/decal/cleanable/filth/Initialize() . = ..() - alpha = rand(180,220) + // Gets more transparent as it ages out + alpha = rand(200 / (age || 1), 250) diff --git a/code/modules/persistence/graffiti.dm b/code/modules/persistence/graffiti.dm index 7018aad26e08..6c6515ec6ba8 100644 --- a/code/modules/persistence/graffiti.dm +++ b/code/modules/persistence/graffiti.dm @@ -10,54 +10,75 @@ anchored = TRUE var/message - var/graffiti_age = 0 var/author = "unknown" +/obj/effect/decal/writing/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(message, /obj/effect/decal/writing) + SERIALIZE_IF_MODIFIED(author, /obj/effect/decal/writing) + +// If it's old enough we start to trim down any textual information and scramble strings. +#define SERDE_MESSAGE nameof(/obj/effect/decal/writing::message) +/obj/effect/decal/writing/HandlePersistentDecay(entries_decay_at, entry_decay_weight) + var/original_message = __deserialization_payload[SERDE_MESSAGE] + var/decayed_message = apply_serde_message_decay( + __deserialization_payload[SERDE_MESSAGE], + __deserialization_payload[nameof(/obj/effect/decal::age)], + entry_decay_weight, + entries_decay_at + ) + to_world_log("decayed graffifi: [original_message] -> [decayed_message]") + __deserialization_payload[SERDE_MESSAGE] = decayed_message +#undef SERDE_MESSAGE + /obj/effect/decal/writing/Initialize(mapload, var/_age, var/_message, var/_author) - var/list/random_icon_states = icon_states(icon) - for(var/obj/effect/decal/writing/W in loc) - random_icon_states.Remove(W.icon_state) - if(random_icon_states.len) + + var/turf/checking_turf = loc + if(istype(checking_turf) && !checking_turf.can_engrave()) + return INITIALIZE_HINT_QDEL + + var/too_much_graffiti = 0 + for(var/obj/effect/decal/writing/writing in loc) + too_much_graffiti++ + if(too_much_graffiti >= 5) + return INITIALIZE_HINT_QDEL + + var/list/random_icon_states = get_states_in_icon(icon) + for(var/obj/effect/decal/writing/writing in loc) + random_icon_states -= writing.icon_state + if(length(random_icon_states)) icon_state = pick(random_icon_states) - SSpersistence.track_value(src, /datum/persistent/graffiti) + SSpersistence.track_value(src, /decl/persistence_handler/graffiti) . = ..(mapload) if(!isnull(_age)) - graffiti_age = _age - message = _message - if(!isnull(author)) + age = _age + if(_message && !message) + message = _message + if(_author && !author) author = _author /obj/effect/decal/writing/Destroy() - SSpersistence.forget_value(src, /datum/persistent/graffiti) + SSpersistence.forget_value(src, /decl/persistence_handler/graffiti) . = ..() -/obj/effect/decal/writing/examine(mob/user) +/obj/effect/decal/writing/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) var/processed_message = user.handle_reading_literacy(user, message) if(processed_message) - to_chat(user, "It reads \"[processed_message]\".") - -/obj/effect/decal/writing/attackby(var/obj/item/thing, var/mob/user) - if(isWelder(thing)) - var/obj/item/weldingtool/welder = thing - if(welder.isOn() && welder.remove_fuel(0,user) && do_after(user, 5, src) && !QDELETED(src)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - user.visible_message("\The [user] clears away some graffiti.") - qdel(src) - else if(thing.sharp) + . += "It reads \"[processed_message]\"." +/obj/effect/decal/writing/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WELDER(used_item) && used_item.do_tool_interaction(TOOL_WELDER, user, src, 3 SECONDS)) + playsound(src, 'sound/items/Welder2.ogg', 50, TRUE) + user.visible_message(SPAN_NOTICE("\The [user] clears away some graffiti.")) + qdel(src) + return TRUE + else if(used_item.is_sharp() && !user.check_intent(I_FLAG_HELP)) //Check intent so you don't go insane trying to unscrew a light fixture over a graffiti if(jobban_isbanned(user, "Graffiti")) to_chat(user, SPAN_WARNING("You are banned from leaving persistent information across rounds.")) - return - - var/_message = sanitize(input("Enter an additional message to engrave.", "Graffiti") as null|text, trim = TRUE) - if(_message && loc && user && !user.incapacitated() && user.Adjacent(loc) && thing.loc == user) - user.visible_message("\The [user] begins carving something into \the [loc].") - if(do_after(user, max(20, length(_message)), src) && loc) - user.visible_message("\The [user] carves some graffiti into \the [loc].") - message = "[message] [_message]" - author = user.ckey - if(lowertext(message) == "elbereth") - to_chat(user, "You feel much safer.") - else - . = ..() + return TRUE + var/turf/T = get_turf(src) + if(T) + T.try_graffiti(user, used_item) + return TRUE + return ..() diff --git a/code/modules/persistence/noticeboards.dm b/code/modules/persistence/noticeboards.dm index c901913696f6..02daf6cc11c2 100644 --- a/code/modules/persistence/noticeboards.dm +++ b/code/modules/persistence/noticeboards.dm @@ -1,63 +1,49 @@ /obj/structure/noticeboard - name = "notice board" - desc = "A board for pinning important notices upon." - icon = 'icons/obj/structures/noticeboard.dmi' - icon_state = "nboard00" - density = 0 - anchored = 1 - layer = ABOVE_WINDOW_LAYER + name = "notice board" + desc = "A board for pinning important notices upon." + icon = 'icons/obj/structures/noticeboard.dmi' + icon_state = "nboard" + density = FALSE + anchored = TRUE + layer = ABOVE_WINDOW_LAYER tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT - + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"SOUTH":{"y":32}, "EAST":{"x":-32}, "WEST":{"x":32}}' + material = /decl/material/solid/organic/wood/oak + var/tmp/max_notices = 5 var/list/notices - var/base_icon_state = "nboard0" - var/const/max_notices = 5 - -/obj/structure/noticeboard/Initialize() +/obj/structure/noticeboard/Initialize(ml, _mat, _reinf_mat) + set_extension(src, /datum/extension/base_icon_state, icon_state) . = ..() // Grab any mapped notices. - notices = list() - for(var/obj/item/paper/note in get_turf(src)) - note.forceMove(src) - LAZYADD(notices, note) - if(LAZYLEN(notices) >= max_notices) - break + if(ml) + for(var/obj/item/paper/note in contents) + add_paper(note, skip_icon_update = TRUE) + if(LAZYLEN(notices) >= max_notices) + break + if(LAZYLEN(notices) < max_notices) + for(var/obj/item/paper/note in get_turf(src)) + add_paper(note, skip_icon_update = TRUE) + if(LAZYLEN(notices) >= max_notices) + break // Automatically place noticeboards that aren't mapped to specific positions. - if(pixel_x == 0 && pixel_y == 0) - + if(default_pixel_x == 0 && default_pixel_y == 0) var/turf/here = get_turf(src) - var/placing = 0 - for(var/checkdir in GLOB.cardinal) + for(var/checkdir in global.cardinal) var/turf/T = get_step(here, checkdir) - if(!T) - continue - if(T.density) - placing = checkdir + if(T && T.density) + set_dir(global.reverse_dir[checkdir]) break - for(var/thing in T) - var/atom/A = thing - if(A.simulated && !A.CanPass(src, T)) - placing = checkdir - break - - switch(placing) - if(NORTH) - pixel_x = 0 - pixel_y = 32 - if(SOUTH) - pixel_x = 0 - pixel_y = -32 - if(EAST) - pixel_x = 32 - pixel_y = 0 - if(WEST) - pixel_x = -32 - pixel_y = 0 update_icon() +/obj/structure/noticeboard/Destroy() + QDEL_NULL_LIST(notices) + return ..() + /obj/structure/noticeboard/proc/add_paper(var/atom/movable/paper, var/skip_icon_update) if(istype(paper)) LAZYDISTINCTADD(notices, paper) @@ -69,78 +55,57 @@ if(istype(paper) && paper.loc == src) paper.dropInto(loc) LAZYREMOVE(notices, paper) - SSpersistence.forget_value(paper, /datum/persistent/paper) if(!skip_icon_update) update_icon() -/obj/structure/noticeboard/dismantle() +/obj/structure/noticeboard/dump_contents(atom/forced_loc = loc, mob/user) for(var/thing in notices) remove_paper(thing, skip_icon_update = TRUE) - . = ..() - -/obj/structure/noticeboard/Destroy() - QDEL_NULL_LIST(notices) - . = ..() - -/obj/structure/noticeboard/explosion_act(var/severity) - . = ..() - if(.) - physically_destroyed() + return ..() /obj/structure/noticeboard/on_update_icon() - icon_state = "[base_icon_state][LAZYLEN(notices)]" - -/obj/structure/noticeboard/attackby(var/obj/item/thing, var/mob/user) . = ..() - if(!.) - - if(isScrewdriver(thing)) - var/choice = input("Which direction do you wish to place the noticeboard?", "Noticeboard Offset") as null|anything in list("North", "South", "East", "West") - if(choice && Adjacent(user) && thing.loc == user && !user.incapacitated()) - playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) - switch(choice) - if("North") - pixel_x = 0 - pixel_y = 32 - if("South") - pixel_x = 0 - pixel_y = -32 - if("East") - pixel_x = 32 - pixel_y = 0 - if("West") - pixel_x = -32 - pixel_y = 0 - return TRUE - - if(!istype(thing, /obj/item/paper/sticky) && (istype(thing, /obj/item/paper) || istype(thing, /obj/item/photo))) - if(jobban_isbanned(user, "Graffiti")) - to_chat(user, SPAN_WARNING("You are banned from leaving persistent information across rounds.")) - else if(LAZYLEN(notices) < max_notices && user.unEquip(thing, src)) - add_fingerprint(user) - add_paper(thing) - to_chat(user, SPAN_NOTICE("You pin \the [thing] to \the [src].")) - SSpersistence.track_value(thing, /datum/persistent/paper) - else - to_chat(user, SPAN_WARNING("You hesitate, certain \the [thing] will not be seen among the many others already attached to \the [src].")) - return TRUE + var/datum/extension/base_icon_state/bis = get_extension(src, /datum/extension/base_icon_state) + var/nb_notices = LAZYLEN(notices) + icon_state = "[bis.base_icon_state][nb_notices > 0? "0[nb_notices]" : ""]" + +/obj/structure/noticeboard/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/paper/sticky) && (istype(used_item, /obj/item/paper) || istype(used_item, /obj/item/photo))) + if(jobban_isbanned(user, "Graffiti")) + to_chat(user, SPAN_WARNING("You are banned from leaving persistent information across rounds.")) + else if(LAZYLEN(notices) < max_notices && user.try_unequip(used_item, src)) + add_fingerprint(user) + add_paper(used_item) + to_chat(user, SPAN_NOTICE("You pin \the [used_item] to \the [src].")) + else + to_chat(user, SPAN_WARNING("You hesitate, certain \the [used_item] will not be seen among the many others already attached to \the [src].")) + return TRUE + return ..() /obj/structure/noticeboard/attack_ai(var/mob/user) - examine(user) + interact(user) + return TRUE /obj/structure/noticeboard/attack_hand(var/mob/user) - examine(user) + if(user.check_intent(I_FLAG_HARM)) + return ..() + interact(user) + return TRUE -/obj/structure/noticeboard/examine(mob/user) +/obj/structure/noticeboard/examined_by(mob/user, distance, infix, suffix) . = ..() + interact(user) + +/obj/structure/noticeboard/interact(mob/user) var/list/dat = list("") for(var/thing in notices) LAZYADD(dat, "") + LAZYADD(dat, "Look") + LAZYADD(dat, "Remove") + var/datum/browser/popup = new(user, "noticeboard-\ref[src]", "Noticeboard") popup.set_content(jointext(dat, null)) popup.open() @@ -150,13 +115,13 @@ if(href_list["read"]) var/obj/item/paper/P = locate(href_list["read"]) if(P && P.loc == src) - P.show_content(user) + P.interact(user) . = TOPIC_HANDLED if(href_list["look"]) var/obj/item/photo/P = locate(href_list["look"]) if(P && P.loc == src) - P.show(user) + P.interact(user) . = TOPIC_HANDLED if(href_list["remove"]) @@ -168,10 +133,8 @@ var/obj/item/P = locate(href_list["write"]) if(!P) return - var/obj/item/pen/pen = user.r_hand - if(!istype(pen)) - pen = user.l_hand - if(istype(pen)) + var/obj/item/pen = locate() in user.get_held_items() + if(IS_PEN(pen)) add_fingerprint(user) P.attackby(pen, user) else @@ -186,37 +149,32 @@ /obj/structure/noticeboard/anomaly/Initialize() . = ..() - var/obj/item/paper/P = new() - P.SetName("Memo RE: proper analysis procedure") - P.info = "
    We keep test dummies in pens here for a reason, so standard procedure should be to activate newfound alien artifacts and place the two in close proximity. Promising items I might even approve monkey testing on." - P.stamped = list(/obj/item/stamp/rd) - P.overlays = list("paper_stamped_rd") + var/obj/item/paper/P = new(src, null, + "
    We keep test dummies in pens here for a reason, so standard procedure should be to activate newfound alien artifacts and place the two in close proximity. Promising items I might even approve monkey testing on.", + "Memo RE: proper analysis procedure") + P.apply_custom_stamp('icons/obj/items/stamps/stamp_rd.dmi', "Research Department") add_paper(P, skip_icon_update = TRUE) - P = new() - P.SetName("Memo RE: materials gathering") - P.info = "Corasang,
    the hands-on approach to gathering our samples may very well be slow at times, but it's safer than allowing the blundering miners to roll willy-nilly over our dig sites in their mechs, destroying everything in the process. And don't forget the excavation tools on your way out there!
    - R.W" - P.stamped = list(/obj/item/stamp/rd) - P.overlays = list("paper_stamped_rd") + P = new(src, null, + "Corasang,
    the hands-on approach to gathering our samples may very well be slow at times, but it's safer than allowing the blundering miners to roll willy-nilly over our dig sites in their mechs, destroying everything in the process. And don't forget the excavation tools on your way out there!
    - R.W", + "Memo RE: materials gathering") + P.apply_custom_stamp('icons/obj/items/stamps/stamp_rd.dmi', "Research Department") add_paper(P, skip_icon_update = TRUE) - P = new() - P.SetName("Memo RE: ethical quandaries") - P.info = "Darion-

    I don't care what his rank is, our business is that of science and knowledge - questions of moral application do not come into this. Sure, so there are those who would employ the energy-wave particles my modified device has managed to abscond for their own personal gain, but I can hardly see the practical benefits of some of these artifacts our benefactors left behind. Ward--" - P.stamped = list(/obj/item/stamp/rd) - P.overlays = list("paper_stamped_rd") + P = new(src, null, + "Darion-

    I don't care what his rank is, our business is that of science and knowledge - questions of moral application do not come into this. Sure, so there are those who would employ the energy-wave particles my modified device has managed to abscond for their own personal gain, but I can hardly see the practical benefits of some of these artifacts our benefactors left behind. Ward--", + "Memo RE: ethical quandaries") + P.apply_custom_stamp('icons/obj/items/stamps/stamp_rd.dmi', "Research Department") add_paper(P, skip_icon_update = TRUE) - P = new() - P.SetName("READ ME! Before you people destroy any more samples") - P.info = "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, concentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely - like someone did to the chemical dispenser! W, the one who signs your paychecks" - P.stamped = list(/obj/item/stamp/rd) - P.overlays = list("paper_stamped_rd") + P = new(src, null, + "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, concentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely - like someone did to the chemical dispenser! W, the one who signs your paychecks", + "READ ME! Before you people destroy any more samples") + P.apply_custom_stamp('icons/obj/items/stamps/stamp_rd.dmi', "Research Department") add_paper(P, skip_icon_update = TRUE) - P = new() - P.SetName("Reminder regarding the anomalous material suits") - P.info = "Do you people think the anomaly suits are cheap to come by? I'm about a hair trigger away from instituting a log book for the damn things. Only wear them if you're going out for a dig, and for god's sake don't go tramping around in them unless you're field testing something, R" - P.stamped = list(/obj/item/stamp/rd) - P.overlays = list("paper_stamped_rd") + P = new(src, null, + "Do you people think the anomaly suits are cheap to come by? I'm about a hair trigger away from instituting a log book for the damn things. Only wear them if you're going out for a dig, and for god's sake don't go tramping around in them unless you're field testing something, R", + "Reminder regarding the anomalous material suits") + P.apply_custom_stamp('icons/obj/items/stamps/stamp_rd.dmi', "Research Department") add_paper(P) diff --git a/code/modules/persistence/persistence_datum.dm b/code/modules/persistence/persistence_datum.dm index d972b04cbcf2..db43dff3f8a2 100644 --- a/code/modules/persistence/persistence_datum.dm +++ b/code/modules/persistence/persistence_datum.dm @@ -2,118 +2,114 @@ // They basically just handle loading, processing and saving specific forms // of persistent data like graffiti and round to round filth. -/datum/persistent - var/name // Unique descriptive name. Used for generating filename. - var/filename // Set at runtime. Full path and .json extension for loading saved data. - var/entries_expire_at // Entries are removed if they are older than this number of rounds. - var/entries_decay_at // Entries begin to decay if they are older than this number of rounds (if applicable). - var/entry_decay_weight = 0.5 // A modifier for the rapidity of decay. - var/has_admin_data // If set, shows up on the admin persistence panel. - -/datum/persistent/New() - SetFilename() - ..() - -/datum/persistent/proc/SetFilename() +/decl/persistence_handler + var/name // Unique descriptive name. Used for generating filename. + var/filename // Set at runtime. Full path and .json extension for loading saved data. + var/entries_expire_at // Entries are removed if they are older than this number of rounds. + var/entries_decay_at // Entries begin to decay if they are older than this number of rounds (if applicable). + var/entry_decay_weight = 0.5 // A modifier for the rapidity of decay. + var/has_admin_data // If set, shows up on the admin persistence panel. + var/ignore_area_flags = FALSE // Set to TRUE to skip area flag checks such as nonpersistent areas. + var/ignore_invalid_loc = FALSE // Set to TRUE to skip checking for a non-null station turf for the entry. + var/list/legacy_map_values // A list of legacy keys to new keys. + var/legacy_type + var/serialization_handler = /decl/serialization_handler/json // Which serialization handler to use for load/save + var/area_restricted = TRUE // Can this item persist outside of a flagged area? + var/station_restricted = TRUE // Can this item persist outside of a station level? + +/decl/persistence_handler/proc/SetFilename() if(name) - filename = "data/persistent/[lowertext(GLOB.using_map.name)]-[lowertext(name)].json" + filename = "data/persistent/[ckey(global.using_map.name)]-[ckey(name)].json" if(!isnull(entries_decay_at) && !isnull(entries_expire_at)) - entries_decay_at = Floor(entries_expire_at * entries_decay_at) - -/datum/persistent/proc/GetValidTurf(var/turf/T, var/list/tokens) - if(T && CheckTurfContents(T, tokens)) - return T - -/datum/persistent/proc/CheckTurfContents(var/turf/T, var/list/tokens) - return TRUE - -/datum/persistent/proc/CheckTokenSanity(var/list/tokens) - return ( \ - !isnull(tokens["x"]) && \ - !isnull(tokens["y"]) && \ - !isnull(tokens["z"]) && \ - !isnull(tokens["age"]) && \ - tokens["age"] <= entries_expire_at \ - ) - -/datum/persistent/proc/CreateEntryInstance(var/turf/creating, var/list/tokens) - return - -/datum/persistent/proc/ProcessAndApplyTokens(var/list/tokens) - - // If it's old enough we start to trim down any textual information and scramble strings. - if(tokens["message"] && !isnull(entries_decay_at) && !isnull(entry_decay_weight)) - var/_n = tokens["age"] - var/_message = tokens["message"] - if(_n >= entries_decay_at) - var/decayed_message = "" - for(var/i = 1 to length(_message)) - var/char = copytext(_message, i, i + 1) - if(prob(round(_n * entry_decay_weight))) - if(prob(99)) - decayed_message += pick(".",",","-","'","\\","/","\"",":",";") - else - decayed_message += char - _message = decayed_message - if(length(_message)) - tokens["message"] = _message - else - return - - var/_z = tokens["z"] - if(_z in GLOB.using_map.station_levels) - . = GetValidTurf(locate(tokens["x"], tokens["y"], _z), tokens) - if(.) - CreateEntryInstance(., tokens) + entries_decay_at = floor(entries_expire_at * entries_decay_at) -/datum/persistent/proc/IsValidEntry(var/atom/entry) +/decl/persistence_handler/proc/IsValidEntry(var/atom/entry) if(!istype(entry)) return FALSE - if(!isnull(entries_expire_at) && GetEntryAge(entry) >= entries_expire_at) + if(!entry.ShouldSerialize(entries_expire_at)) return FALSE var/turf/T = get_turf(entry) - if(!T || !(T.z in GLOB.using_map.station_levels) ) + if(!ignore_invalid_loc && (!T || !isStationLevel(T.z))) return FALSE var/area/A = get_area(T) - if(!A || (A.area_flags & AREA_FLAG_IS_NOT_PERSISTENT)) + if(!ignore_area_flags && (!A || (A.area_flags & AREA_FLAG_NO_LEGACY_PERSISTENCE))) return FALSE return TRUE -/datum/persistent/proc/GetEntryAge(var/atom/entry) +/decl/persistence_handler/proc/GetEntryAge(var/atom/entry) return 0 -/datum/persistent/proc/CompileEntry(var/atom/entry) - var/turf/T = get_turf(entry) - . = list() - .["x"] = T.x - .["y"] = T.y - .["z"] = T.z - .["age"] = GetEntryAge(entry) - -/datum/persistent/proc/FinalizeTokens(var/list/tokens) - . = tokens - -/datum/persistent/proc/Initialize() - if(fexists(filename)) - var/list/token_sets = cached_json_decode(file2text(filename)) - for(var/tokens in token_sets) - tokens = FinalizeTokens(tokens) - if(CheckTokenSanity(tokens)) - ProcessAndApplyTokens(tokens) - -/datum/persistent/proc/Shutdown() +/decl/persistence_handler/Initialize() + + SetFilename() + + . = ..() + + if(!fexists(filename)) + return + + var/decl/serialization_handler/handler = GET_DECL(serialization_handler) + var/list/entries = handler.load_data_from_file(filename) + + if(!length(entries)) + return + + // Check for old-style persistence data and generate a key. + if(length(entries) && !istext(entries[1])) + try + // Save a backup of the old file just in case we cook it. + fcopy(filename, "[filename]-legacy.[time2text(REALTIMEOFDAY, "YY-MM-DD_hh-mm")].backup") + catch(var/exception/e) + log_error("Exception during saving backup of legacy file [filename]: [EXCEPTION_TEXT(e)]") + + // Update the data to match the expected format of the new system. + var/list/entries_with_key = list() + var/i = 1 + for(var/entry in entries) + entries_with_key[num2text(i)] = UpdateFromLegacyFormat(entry) + entries = entries_with_key + + instantiate_serialized_data(null, name, entries, entries_decay_at, entry_decay_weight) + +/decl/persistence_handler/proc/Shutdown() var/list/entries = list() - for(var/thing in SSpersistence.tracking_values[type]) + for(var/atom/thing in SSpersistence.tracking_values[type]) if(IsValidEntry(thing)) - entries += list(CompileEntry(thing)) - if(fexists(filename)) - fdel(filename) - to_file(file(filename), json_encode(entries)) + var/list/things_to_serialize = thing.GetPossiblySerializableInstances() + for(var/datum/subthing in things_to_serialize) + entries[subthing.get_run_uid()] = subthing.Serialize() + var/decl/serialization_handler/handler = GET_DECL(serialization_handler) + handler.save_data_to_file(filename, entries, name) -/datum/persistent/proc/RemoveValue(var/atom/value) +/decl/persistence_handler/proc/RemoveValue(var/atom/value) qdel(value) -/datum/persistent/proc/GetAdminSummary(var/mob/user, var/can_modify) +/decl/persistence_handler/proc/UpdateFromLegacyFormat(list/_entry) + + // Convert any old values to the new indices. + for(var/map_key in legacy_map_values) + if(map_key in _entry) + var/value = _entry[map_key] + _entry -= map_key + _entry[legacy_map_values[map_key]] = value + + // Convert entry coords into new format. + if(("x" in _entry) || ("y" in _entry) || ("z" in _entry)) + _entry["loc"] = list( + _entry["x"] || 1, + _entry["y"] || 1, + _entry["z"] || 1 + ) + _entry -= "x" + _entry -= "y" + _entry -= "z" + + if(legacy_type && !(nameof(/datum::type) in _entry)) + _entry[nameof(/datum::type)] = legacy_type + + return _entry + +/decl/persistence_handler/proc/GetAdminSummary(var/mob/user, var/can_modify) . = list("") . += "" for(var/thing in SSpersistence.tracking_values[type]) @@ -121,13 +117,13 @@ . += "[GetAdminDataStringFor(thing, can_modify, user)]" . += "" -/datum/persistent/proc/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) +/decl/persistence_handler/proc/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) if(can_modify) - . = "" + . = "" else . = "" -/datum/persistent/Topic(var/href, var/href_list) +/decl/persistence_handler/Topic(var/href, var/href_list) . = ..() if(!.) if(href_list["remove_entry"]) @@ -136,6 +132,6 @@ RemoveValue(value) . = TRUE if(.) - var/mob/user = locate(href_list["caller"]) + var/mob/user = locate(href_list["user"]) if(user) SSpersistence.show_info(user) diff --git a/code/modules/persistence/persistence_datum_book.dm b/code/modules/persistence/persistence_datum_book.dm index b66c83490932..9b96bca8dff5 100644 --- a/code/modules/persistence/persistence_datum_book.dm +++ b/code/modules/persistence/persistence_datum_book.dm @@ -1,38 +1,23 @@ -/datum/persistent/book +/decl/persistence_handler/book name = "books" - has_admin_data = TRUE - -/datum/persistent/book/CreateEntryInstance(var/turf/creating, var/list/tokens) - var/obj/item/book/book = new(creating) - book.dat = tokens["message"] - book.title = tokens["title"] - book.author = tokens["writer"] - book.icon_state = tokens["icon_state"] - book.last_modified_ckey = tokens["author"] || "unknown" - book.unique = TRUE - book.SetName(book.title) - var/obj/structure/bookcase/case = locate() in creating - if(case) - book.forceMove(case) - case.update_icon() - . = book + has_admin_data = TRUE + ignore_area_flags = TRUE + ignore_invalid_loc = TRUE + legacy_type = /obj/item/book + legacy_map_values = list( + "author" = nameof(/obj/item/book::last_modified_ckey), + "writer" = nameof(/obj/item/book::author), + "book_type" = nameof(/obj/item/book::type), + "message" = nameof(/obj/item/book::dat) + ) -/datum/persistent/book/IsValidEntry(var/atom/entry) +/decl/persistence_handler/book/IsValidEntry(var/atom/entry) . = ..() if(.) var/obj/item/book/book = entry . = istype(book) && book.dat && book.last_modified_ckey -/datum/persistent/book/CompileEntry(var/atom/entry, var/write_file) - . = ..() - var/obj/item/book/book = entry - .["author"] = book.last_modified_ckey || "" - .["message"] = book.dat || "dat" - .["title"] = book.title || "Untitled" - .["writer"] = book.author || "unknown" - .["icon_state"] = book.icon_state || "book" - -/datum/persistent/book/RemoveValue(var/atom/movable/value) +/decl/persistence_handler/book/RemoveValue(var/atom/movable/value) var/obj/structure/bookcase/bookcase = value.loc if(istype(bookcase)) if(istype(value)) @@ -40,15 +25,9 @@ bookcase.update_icon() ..() -/datum/persistent/book/GetValidTurf(var/turf/T, var/list/tokens) - . = ..(T || get_turf(pick(GLOB.station_bookcases)), tokens) - -/datum/persistent/book/GetEntryAge(var/atom/entry) - . = -1 - -/datum/persistent/book/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) +/decl/persistence_handler/book/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) var/obj/item/book/book = thing if(can_modify) - . = "" + . = "" else . = "" diff --git a/code/modules/persistence/persistence_datum_filth.dm b/code/modules/persistence/persistence_datum_filth.dm index 5348f16c212b..249535eed99b 100644 --- a/code/modules/persistence/persistence_datum_filth.dm +++ b/code/modules/persistence/persistence_datum_filth.dm @@ -1,34 +1,11 @@ -/datum/persistent/filth +/decl/persistence_handler/filth name = "filth" entries_expire_at = 5 + legacy_type = /obj/effect/decal/cleanable/filth + legacy_map_values = list( + "path" = nameof(/obj/effect/decal/cleanable::type), + "filthiness" = nameof(/obj/effect/decal/cleanable/dirt::dirt_amount) + ) -/datum/persistent/filth/IsValidEntry(var/atom/entry) +/decl/persistence_handler/filth/IsValidEntry(var/atom/entry) . = ..() && entry.invisibility == 0 - -/datum/persistent/filth/CheckTokenSanity(var/list/tokens) - return ..() && ispath(tokens["path"]) - -/datum/persistent/filth/CheckTurfContents(var/turf/T, var/list/tokens) - return !(locate(tokens["path"]) in T) - -/datum/persistent/filth/FinalizeTokens(var/list/tokens) - . = ..() - if(.["path"] && !ispath(.["path"])) - .["path"] = text2path(.["path"]) - . = tokens - -/datum/persistent/filth/CreateEntryInstance(var/turf/creating, var/list/tokens) - var/_path = tokens["path"] - new _path(creating, tokens["age"]+1) - -/datum/persistent/filth/GetEntryAge(var/atom/entry) - var/obj/effect/decal/cleanable/filth = entry - return filth.age - -/datum/persistent/filth/proc/GetEntryPath(var/atom/entry) - var/obj/effect/decal/cleanable/filth = entry - return filth.generic_filth ? /obj/effect/decal/cleanable/filth : filth.type - -/datum/persistent/filth/CompileEntry(var/atom/entry) - . = ..() - .["path"] = "[GetEntryPath(entry)]" diff --git a/code/modules/persistence/persistence_datum_filth_trash.dm b/code/modules/persistence/persistence_datum_filth_trash.dm index 98ed1245cf5f..dab2fcfed354 100644 --- a/code/modules/persistence/persistence_datum_filth_trash.dm +++ b/code/modules/persistence/persistence_datum_filth_trash.dm @@ -1,17 +1,3 @@ -/datum/persistent/filth/trash +/decl/persistence_handler/filth/trash name = "trash" - -/datum/persistent/filth/trash/CheckTurfContents(var/turf/T, var/list/tokens) - var/too_much_trash = 0 - for(var/obj/item/trash/trash in T) - too_much_trash++ - if(too_much_trash >= 5) - return FALSE - return TRUE - -/datum/persistent/filth/trash/GetEntryAge(var/atom/entry) - var/obj/item/trash/trash = entry - return trash.age - -/datum/persistent/filth/trash/GetEntryPath(var/atom/entry) - return entry.type + legacy_type = /obj/random/trash diff --git a/code/modules/persistence/persistence_datum_graffiti.dm b/code/modules/persistence/persistence_datum_graffiti.dm index bac393d66d0d..3e30ab2c4ecb 100644 --- a/code/modules/persistence/persistence_datum_graffiti.dm +++ b/code/modules/persistence/persistence_datum_graffiti.dm @@ -1,43 +1,18 @@ -/datum/persistent/graffiti +/decl/persistence_handler/graffiti name = "graffiti" entries_expire_at = 50 has_admin_data = TRUE + legacy_type = /obj/effect/decal/writing -/datum/persistent/graffiti/GetValidTurf(var/turf/T, var/list/tokens) - var/turf/checking_turf = ..() - if(istype(checking_turf) && checking_turf.can_engrave()) - return checking_turf - -/datum/persistent/graffiti/CheckTurfContents(var/turf/T, var/list/tokens) - var/too_much_graffiti = 0 - for(var/obj/effect/decal/writing/W in .) - too_much_graffiti++ - if(too_much_graffiti >= 5) - return FALSE - return TRUE - -/datum/persistent/graffiti/CreateEntryInstance(var/turf/creating, var/list/tokens) - new /obj/effect/decal/writing(creating, tokens["age"]+1, tokens["message"], tokens["author"]) - -/datum/persistent/graffiti/IsValidEntry(var/atom/entry) +/decl/persistence_handler/graffiti/IsValidEntry(var/atom/entry) . = ..() if(.) var/turf/T = entry.loc . = T.can_engrave() -/datum/persistent/graffiti/GetEntryAge(var/atom/entry) - var/obj/effect/decal/writing/save_graffiti = entry - return save_graffiti.graffiti_age - -/datum/persistent/graffiti/CompileEntry(var/atom/entry, var/write_file) - . = ..() - var/obj/effect/decal/writing/save_graffiti = entry - .["author"] = save_graffiti.author || "unknown" - .["message"] = save_graffiti.message - -/datum/persistent/graffiti/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) +/decl/persistence_handler/graffiti/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) var/obj/effect/decal/writing/save_graffiti = thing if(can_modify) - . = "" + . = "" else . = "" diff --git a/code/modules/persistence/persistence_datum_paper.dm b/code/modules/persistence/persistence_datum_paper.dm index b9550740e66c..a14cb7d79878 100644 --- a/code/modules/persistence/persistence_datum_paper.dm +++ b/code/modules/persistence/persistence_datum_paper.dm @@ -1,52 +1,29 @@ -/datum/persistent/paper +/decl/persistence_handler/paper name = "paper" entries_expire_at = 50 has_admin_data = TRUE - var/paper_type = /obj/item/paper - var/requires_noticeboard = TRUE + legacy_map_values = list( + "author" = nameof(/obj/item/paper::last_modified_ckey), + "message" = nameof(/obj/item/paper::info), + "title" = nameof(/obj/item/paper::name) + ) + legacy_type = /obj/item/paper -/datum/persistent/paper/CheckTurfContents(var/turf/T, var/list/tokens) - if(requires_noticeboard && !(locate(/obj/structure/noticeboard) in T)) - new /obj/structure/noticeboard(T) - . = ..() - -/datum/persistent/paper/CreateEntryInstance(var/turf/creating, var/list/tokens) - var/obj/structure/noticeboard/board = locate() in creating - if(requires_noticeboard && LAZYLEN(board.notices) >= board.max_notices) - return - var/obj/item/paper/paper = new paper_type(creating) - paper.set_content(tokens["message"], tokens["title"]) - paper.last_modified_ckey = tokens["author"] - if(requires_noticeboard) - board.add_paper(paper) - . = paper - -/datum/persistent/paper/GetEntryAge(var/atom/entry) - var/obj/item/paper/paper = entry - return paper.age - -/datum/persistent/paper/CompileEntry(var/atom/entry, var/write_file) - . = ..() - var/obj/item/paper/paper = entry - .["author"] = paper.last_modified_ckey || "unknown" - .["message"] = paper.info || "" - .["title"] = paper.name || "paper" - -/datum/persistent/paper/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) +/decl/persistence_handler/paper/GetAdminDataStringFor(var/thing, var/can_modify, var/mob/user) var/obj/item/paper/paper = thing if(can_modify) - . = "" + . = "" else . = "" -/datum/persistent/paper/RemoveValue(var/atom/value) +/decl/persistence_handler/paper/IsValidEntry(var/atom/entry) + . = ..() + if(.) + var/obj/item/paper/paper = entry + . = istype(paper) && paper.info && paper.last_modified_ckey + +/decl/persistence_handler/paper/RemoveValue(var/atom/value) var/obj/structure/noticeboard/board = value.loc if(istype(board)) board.remove_paper(value) - qdel(value) - -/datum/persistent/paper/IsValidEntry(var/atom/entry) . = ..() - if(.) - var/obj/item/paper/paper = entry - . = istype(paper) && paper.info && paper.last_modified_ckey \ No newline at end of file diff --git a/code/modules/persistence/persistence_datum_paper_sticky.dm b/code/modules/persistence/persistence_datum_paper_sticky.dm index 3a45d457a532..2eeee9e7a371 100644 --- a/code/modules/persistence/persistence_datum_paper_sticky.dm +++ b/code/modules/persistence/persistence_datum_paper_sticky.dm @@ -1,19 +1,3 @@ -/datum/persistent/paper/sticky +/decl/persistence_handler/paper/sticky name = "stickynotes" - paper_type = /obj/item/paper/sticky - requires_noticeboard = FALSE - -/datum/persistent/paper/sticky/CreateEntryInstance(var/turf/creating, var/list/tokens) - var/atom/paper = ..() - if(paper) - paper.pixel_x = tokens["offset_x"] - paper.pixel_y = tokens["offset_y"] - paper.color = tokens["color"] - return paper - -/datum/persistent/paper/sticky/CompileEntry(var/atom/entry, var/write_file) - . = ..() - var/obj/item/paper/sticky/paper = entry - .["offset_x"] = paper.pixel_x - .["offset_y"] = paper.pixel_y - .["color"] = paper.color + legacy_type = /obj/item/paper/sticky diff --git a/code/modules/pointdefense/pointdefense.dm b/code/modules/pointdefense/pointdefense.dm index 8d47597c774c..9c23c78e1360 100644 --- a/code/modules/pointdefense/pointdefense.dm +++ b/code/modules/pointdefense/pointdefense.dm @@ -1,17 +1,18 @@ -//Point defense +//Point defense /obj/machinery/pointdefense_control name = "fire assist mainframe" desc = "A specialized computer designed to synchronize a variety of weapon systems and a vessel's astronav data." icon = 'icons/obj/artillery.dmi' icon_state = "control" - var/ui_template = "pointdefense_control.tmpl" - var/initial_id_tag density = TRUE anchored = TRUE base_type = /obj/machinery/pointdefense_control construct_state = /decl/machine_construction/default/panel_closed + atom_flags = ATOM_FLAG_CLIMBABLE + + var/ui_template = "pointdefense_control.tmpl" + var/initial_id_tag var/list/targets = list() - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE /obj/machinery/pointdefense_control/Initialize() . = ..() @@ -26,6 +27,10 @@ if(pointdefense_controllers.len > 1) lan.remove_device(src) +/obj/machinery/pointdefense_control/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + /obj/machinery/pointdefense_control/ui_interact(var/mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) if(ui_template) var/list/data = build_ui_data() @@ -80,35 +85,33 @@ data["turrets"] = turrets return data -/obj/machinery/pointdefense_control/attackby(var/obj/item/thing, var/mob/user) - if(isMultitool(thing)) +/obj/machinery/pointdefense_control/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/pointdefense = get_extension(src, /datum/extension/local_network_member) pointdefense.get_new_tag(user) //Check if there is more than 1 controller var/datum/local_network/lan = pointdefense.get_local_network() if(lan) var/list/pointdefense_controllers = lan.get_devices(/obj/machinery/pointdefense_control) - if(pointdefense_controllers && pointdefense_controllers.len > 1) + if(LAZYLEN(pointdefense_controllers) > 1) lan.remove_device(src) - return - else - return ..() + return TRUE + return ..() /obj/machinery/pointdefense - name = "\improper point defense battery" + name = "point defense battery" icon = 'icons/obj/artillery.dmi' icon_state = "pointdefense" desc = "A Kuiper pattern anti-meteor battery. Capable of destroying most threats in a single salvo." density = TRUE anchored = TRUE - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + atom_flags = ATOM_FLAG_CLIMBABLE idle_power_usage = 0.1 KILOWATTS construct_state = /decl/machine_construction/default/panel_closed - maximum_component_parts = list(/obj/item/stock_parts = 10) //null - no max. list(type part = number max). base_type = /obj/machinery/pointdefense - stock_part_presets = list(/decl/stock_part_preset/terminal_setup) + stock_part_presets = list(/decl/stock_part_preset/terminal_connect) uncreated_component_parts = null - appearance_flags = PIXEL_SCALE + appearance_flags = DEFAULT_APPEARANCE_FLAGS | LONG_GLIDE var/active = TRUE var/charge_cooldown = 1 SECOND //time between it can fire at different targets var/last_shot = 0 @@ -119,15 +122,27 @@ /obj/machinery/pointdefense/Initialize() . = ..() + set_dir(dir) // Ensure it's valid. set_extension(src, /datum/extension/local_network_member/multilevel) if(initial_id_tag) var/datum/extension/local_network_member/pointdefense = get_extension(src, /datum/extension/local_network_member) pointdefense.set_tag(null, initial_id_tag) -/obj/machinery/pointdefense/attackby(var/obj/item/thing, var/mob/user) - if(isMultitool(thing)) +/obj/machinery/pointdefense/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + +/obj/machinery/pointdefense/set_dir(new_dir) + if(new_dir != NORTH && new_dir != SOUTH) // Other dirs are invalid + new_dir = SOUTH + . = ..() + +/obj/machinery/pointdefense/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/pointdefense = get_extension(src, /datum/extension/local_network_member) pointdefense.get_new_tag(user) + return TRUE + return ..() //Guns cannot shoot through hull or generally dense turfs. /obj/machinery/pointdefense/proc/space_los(meteor) @@ -136,7 +151,7 @@ return FALSE return TRUE -/obj/machinery/pointdefense/proc/Shoot(var/weakref/target) +/obj/machinery/pointdefense/proc/shoot_at(var/weakref/target) var/obj/effect/meteor/M = target.resolve() if(!istype(M)) return @@ -144,9 +159,9 @@ var/Angle = round(Get_Angle(src,M)) var/matrix/rot_matrix = matrix() rot_matrix.Turn(Angle) - addtimer(CALLBACK(src, .proc/finish_shot, target), rotation_speed) + addtimer(CALLBACK(src, PROC_REF(finish_shot), target), rotation_speed) animate(src, transform = rot_matrix, rotation_speed, easing = SINE_EASING) - + set_dir(transform.get_angle() > 0 ? NORTH : SOUTH) /obj/machinery/pointdefense/proc/finish_shot(var/weakref/target) @@ -185,8 +200,8 @@ set_dir(desiredir) if(engaging || ((world.time - last_shot) < charge_cooldown)) return - - if(GLOB.meteor_list.len == 0) + + if(global.meteor_list.len == 0) return var/datum/extension/local_network_member/pointdefense = get_extension(src, /datum/extension/local_network_member) var/datum/local_network/lan = pointdefense.get_local_network() @@ -198,7 +213,7 @@ if(!istype(PC)) return - for(var/obj/effect/meteor/M in GLOB.meteor_list) + for(var/obj/effect/meteor/M in global.meteor_list) var/already_targeted = FALSE for(var/weakref/WR in PC.targets) var/obj/effect/meteor/m = WR.resolve() @@ -211,14 +226,14 @@ if(already_targeted) continue - if(!(M.z in GetConnectedZlevels(z))) + if(!(M.z in SSmapping.get_connected_levels(z))) continue if(get_dist(M, src) > kill_range) continue if(!emagged && space_los(M)) var/weakref/target = weakref(M) PC.targets +=target - Shoot(target) + shoot_at(target) return /obj/machinery/pointdefense/RefreshParts() diff --git a/code/modules/posters/_poster.dm b/code/modules/posters/_poster.dm new file mode 100644 index 000000000000..93b1dbe141bc --- /dev/null +++ b/code/modules/posters/_poster.dm @@ -0,0 +1,201 @@ +////////////////////////////////////////////////////////////////////////////////// +// Poster Structure +////////////////////////////////////////////////////////////////////////////////// + +///A wall mounted poster +/obj/structure/sign/poster + icon = 'icons/obj/items/posters.dmi' + icon_state = "poster0" + anchored = TRUE + directional_offset = @'{"NORTH":{"y":32}, "SOUTH":{"y":-32}, "EAST":{"x":32}, "WEST":{"x":-32}}' + material = /decl/material/solid/organic/paper + max_health = 10 + parts_type = /obj/item/poster + parts_amount = 1 + + ///Whether the poster is too damaged to take off from the wall or not. + var/ruined = FALSE + ///Sound played when the poster is destroyed or ruined + var/sound_destroyed = 'sound/items/poster_ripped.ogg' + ///Type path to the /decl for the design on this poster. At runtime is replaced with the actual /decl instance. + var/decl/poster_design/poster_design + + ///The icon state to use when the poster is ruined + var/ruined_icon_state = "poster_ripped" + + ///Name of the medium (The sign/poster) + var/base_name = "poster" + ///Name of the medium after it's been ruined. + var/base_name_ruined = "ripped poster" + + ///Description of the medium (The sign/poster) + var/base_desc = "A large piece of space-resistant printed paper." + ///Description of the medium after it's been ruined. + var/base_desc_ruined = "You can't make out anything from the poster's original print. It's ruined." + +/obj/structure/sign/poster/Initialize(var/ml, var/_mat, var/_reinf_mat, var/placement_dir = null, var/given_poster_type = null) + . = ..(ml, _mat, _reinf_mat) + set_design(given_poster_type || poster_design || pick(decls_repository.get_decl_paths_of_subtype(/decl/poster_design))) + set_dir(placement_dir || dir) + +/obj/structure/sign/poster/physically_destroyed(skip_qdel) + playsound(src, sound_destroyed, 80, TRUE) + //Only fully destroy if we're ruined first + if(ruined) + return ..() + //If we weren't ruined, mark us as ruined, so next time we get destroyed + set_ruined(TRUE) + +/obj/structure/sign/poster/attackby(obj/item/used_item, mob/user) + //Prevent the sign implementation from removing us from the wall via unscrewing us + if(IS_SCREWDRIVER(used_item)) + return FALSE //#FIXME: once /obj/structure/sign use the generic structure tools procs we won't need to intercept this here anymore. + return ..() + +/obj/structure/sign/poster/dismantle_structure(mob/user) + //If not ruined, we can drop an intact poster item + if(!ruined) + return ..() + //Don't dismantle when ruined, so we don't drop an intact poster. + if(!QDELETED(src)) + qdel(src) + return TRUE + +/obj/structure/sign/poster/create_dismantled_part(turf/T) + return new parts_type(T, (material && material.type), istype(poster_design)? poster_design.type : poster_design) + +/obj/structure/sign/poster/handle_default_wirecutter_attackby(mob/user, obj/item/wirecutters/wirecutters) + if(!wirecutters.do_tool_interaction(TOOL_WIRECUTTERS, user, src, 0, ruined? "scrapping off the remnants of" : "carefully removing", ruined? "cutting off" : "carefully removing")) + return TRUE //Don't run after_attack + dismantle_structure(user) + return TRUE + +/obj/structure/sign/poster/attack_hand(mob/user) + if(!user.check_intent(I_FLAG_HARM) || ruined) + return ..() + if(!CanPhysicallyInteract(user) || !user.check_dexterity(DEXTERITY_HOLD_ITEM)) + return TRUE + add_fingerprint(user) + visible_message(SPAN_WARNING("\The [user] rips \the '[src]' in a single, decisive motion!")) + playsound(src, sound_destroyed, 80, TRUE) + set_ruined(TRUE) + return TRUE + +/obj/structure/sign/poster/proc/update_appearence() + if(ruined) + desc = base_desc_ruined + SetName(base_name_ruined) + set_icon_state(ruined_icon_state) + else + desc = "[base_desc] [poster_design.desc]" + SetName("[base_name] - [poster_design.name]") + icon = poster_design.icon + set_icon_state(poster_design.icon_state) + update_icon() + +/obj/structure/sign/poster/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + . += "The bottom right of \the [src] reads: '[poster_design.serial_number]'." + +/obj/structure/sign/poster/proc/set_design(var/decl/poster_design/_design_path) + if(ispath(_design_path, /decl)) + _design_path = GET_DECL(_design_path) + if(!istype(_design_path)) + CRASH("Invali design path was set for [src]: [log_info_line(_design_path)]") + + poster_design = _design_path + //Apply the poster design to us + update_appearence() + +/obj/structure/sign/poster/proc/set_ruined(var/_ruined) + if(ruined == _ruined) + return + ruined = _ruined + current_health = (!ruined)? max(current_health, 1) : 0 //setting unruined implies health > 0 + + //Make sure we look the part + update_appearence() + +////////////////////////////////////////////////////////////////////////////////// +// Poster Item +////////////////////////////////////////////////////////////////////////////////// + +///A rolled up version of the wall-mounted poster structure +/obj/item/poster + name = "rolled-up poster" + desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface." + icon = 'icons/obj/items/posters.dmi' + icon_state = "rolled_poster" + _base_attack_force = 0 + material = /decl/material/solid/organic/paper + + ///Type path to the /decl for the design on this poster. At runtime is changed for a reference to the decl + var/decl/poster_design/poster_design + +/obj/item/poster/Initialize(ml, material_key, var/given_poster_type = null) + //Init design + . = ..(ml, material_key) + set_design(given_poster_type || poster_design || pick(decls_repository.get_decl_paths_of_subtype(/decl/poster_design))) + +/obj/item/poster/proc/set_design(var/decl/poster_design/_design_path) + if(ispath(_design_path, /decl)) + _design_path = GET_DECL(_design_path) + if(_design_path == poster_design) + return TRUE + if(!istype(_design_path)) + CRASH("Invalid poster type: [log_info_line(_design_path)]") + + poster_design = _design_path + desc = "[base_desc] [poster_design.desc]" + SetName("[base_name] - [poster_design.name] - [poster_design.serial_number]") + +//Places the poster on a wall +/obj/item/poster/afterattack(var/atom/A, var/mob/user, var/adjacent, var/clickparams) + if (!adjacent) + return + + //must place on a wall and user must not be inside a closet/exosuit/whatever + var/turf/used_item = get_turf(A) + if(!istype(used_item) || !used_item.is_wall() || !isturf(user.loc)) + to_chat(user, SPAN_WARNING("You can't place this here!")) + return + + var/placement_dir = get_dir(user, used_item) + if (!(placement_dir in global.cardinal)) + to_chat(user, SPAN_WARNING("You must stand directly in front of the wall you wish to place that on.")) + return + + if (ArePostersOnWall(used_item)) + to_chat(user, SPAN_WARNING("There is already a poster there!")) + return + + user.visible_message( + SPAN_NOTICE("\The [user] starts placing a poster on \the [used_item]."), + SPAN_NOTICE("You start placing the poster on \the [used_item].")) + + var/obj/structure/sign/poster/P = new (user.loc, null, null, placement_dir, poster_design) + qdel(src) + flick("poster_being_set", P) + // Time to place is equal to the time needed to play the flick animation + if(do_after(user, 28, used_item) && used_item.is_wall() && !ArePostersOnWall(used_item, P)) + user.visible_message( + SPAN_NOTICE("\The [user] has placed a poster on \the [used_item]."), + SPAN_NOTICE("You have placed the poster on \the [used_item].")) + else + // We cannot rely on user being on the appropriate turf when placement fails + P.dismantle_structure(user) + +/obj/item/poster/proc/ArePostersOnWall(var/turf/used_item, var/placed_poster) + //just check if there is a poster on or adjacent to the wall + if (locate(/obj/structure/sign/poster) in used_item) + return TRUE + + //crude, but will cover most cases. We could do stuff like check pixel_x/y but it's not really worth it. + for (var/dir in global.cardinal) + var/turf/T = get_step(used_item, dir) + var/poster = locate(/obj/structure/sign/poster) in T + if (poster && placed_poster != poster) + return TRUE + + return FALSE diff --git a/code/modules/posters/_poster_design.dm b/code/modules/posters/_poster_design.dm new file mode 100644 index 000000000000..e96a70f21d1e --- /dev/null +++ b/code/modules/posters/_poster_design.dm @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////// +// Poster Design +/////////////////////////////////////////////////////////////// + +///Contains information on what a poster displays. +/decl/poster_design + abstract_type = /decl/poster_design + ///The display name/title of the design. Suffixed to the name of the medium displaying the design. + var/name + ///The description of the design shown to users. This is suffixed to the description of the medium displaying this design. + var/desc + ///Collectible serial number string, if any. + var/serial_number + ///The icon to use for this design. + var/icon = 'icons/obj/items/posters.dmi' + ///The icon state to use for this design. The display medium will use this to pick it's icon state. + var/icon_state + +/decl/poster_design/Initialize() + . = ..() + generate_serial_number() + +/decl/poster_design/proc/generate_serial_number() + if(length(serial_number)) + return + serial_number = "serial #[sequential_id(/decl/poster_design)]" + +/decl/poster_design/validate() + . = ..() + if(!icon_state) + . += "no icon_state set" + if(!icon) + . += "no icon set" + if(icon && icon_state && !check_state_in_icon(icon_state, icon)) + . += "icon state [icon_state] not present in [icon]" diff --git a/code/modules/posters/bs12.dm b/code/modules/posters/bs12.dm new file mode 100644 index 000000000000..6a585fa4e933 --- /dev/null +++ b/code/modules/posters/bs12.dm @@ -0,0 +1,63 @@ +// baystation12 posters +//-----------|-------|-------------|--------------------------------------------------|--------------- +// | TYPE | ICON | TITLE | DESCRIPTION +//-----------|-------|-------------|--------------------------------------------------|--------------- +DEFINE_POSTER( bay_1, "bsposter1", "Unlucky Space Explorer", "This particular one depicts a skeletal form within a space suit." ) +DEFINE_POSTER( bay_2, "bsposter2", "Positronic Logic Conflicts", "This particular one depicts the cold, unmoving stare of a particular advanced AI.") +DEFINE_POSTER( bay_3, "bsposter3", "Paranoia", "This particular one warns of the dangers of trusting your co-workers too much.") +DEFINE_POSTER( bay_4, "bsposter4", "Keep Calm", "This particular one is of a famous New Earth design, although a bit modified. Someone has scribbled an O over the A on the poster.") +DEFINE_POSTER( bay_5, "bsposter5", "Martian Warlord", "This particular one depicts the cartoony mug of a certain Martial Warmonger.") +DEFINE_POSTER( bay_6, "bsposter6", "Technological Singularity", "This particular one is of the blood-curdling symbol of a long-since defeated enemy of humanity.") +DEFINE_POSTER( bay_7, "bsposter7", "Wasteland", "This particular one is of a couple of ragged gunmen, one male and one female, on top of a mound of rubble. The number \"12\" is visible on their blue jumpsuits.") +DEFINE_POSTER( bay_8, "bsposter8", "Pinup Girl Cindy", "This particular one is of a historical corporate PR girl, Cindy, in a particularly feminine pose.") +DEFINE_POSTER( bay_9, "bsposter9", "Pinup Girl Amy", "This particular one is of Amy, the nymphomaniac urban legend of deep space. How this photograph came to be is not known.") +DEFINE_POSTER( bay_10, "bsposter10", "Don't Panic", "This particular one depicts some sort of star in a grimace. The \"Don't Panic\" is written in big, friendly letters.") +DEFINE_POSTER( bay_11, "bsposter11", "Underwater Laboratory", "This particular one is of the fabled last crew of a previous Company project.") +DEFINE_POSTER( bay_12, "bsposter12", "Rogue AI", "This particular one depicts the shell of the infamous AI that catastropically comandeered one of humanity's earliest space stations. Back then, the Company was just known as TriOptimum.") +DEFINE_POSTER( bay_13, "bsposter13", "User of the Arcane Arts", "This particular one depicts a wizard, casting a spell. You can't really make out if it's an actual photograph or a computer-generated image.") +DEFINE_POSTER( bay_14, "bsposter14", "Levitating Skull", "This particular one is the portrait of a flying enchanted skull. Its adventures along with its fabled companion are now fading through history...") +DEFINE_POSTER( bay_15, "bsposter15", "Augmented Legend", "This particular one is of an obviously augmented individual, gazing towards the sky. The cyber-city in the backround is rather punkish.") +DEFINE_POSTER( bay_16, "bsposter16", "Dangerous Static", "This particular one depicts nothing remarkable other than a rather mesmerising pattern of monitor static. There's a tag on the sides of the poster, but it's ripped off.") +DEFINE_POSTER( bay_17, "bsposter17", "Pinup Girl Val", "Luscious Val McNeil, the vertically challenged Legal Extraordinaire, winner of Miss Space two years running and favoured pinup girl of Lawyers Weekly.") +DEFINE_POSTER( bay_18, "bsposter18", "Derpman, Enforcer of the State", "Here to protect and serve... your donuts! A generously proportioned man, he teaches you the value of hiding your snacks.") +DEFINE_POSTER( bay_19, "bsposter19", "Respect an Alien", "This poster depicts a well dressed looking lizard-alien receiving a prestigious award. It appears to espouse greater co-operation and harmony between the two races.") +DEFINE_POSTER( bay_20, "bsposter20", "Alien Twilight", "This poster depicts a mysteriously inscrutable, alien scene. Numerous aliens can be seen conversing amidst great, crystalline towers rising above crashing waves") +DEFINE_POSTER( bay_21, "bsposter21", "Join the Fuzz!", "It's a nice recruitment poster of a white haired Chinese woman that says; \"Big Guns, Hot Women, Good Times. Security. We get it done.\"") +DEFINE_POSTER( bay_22, "bsposter22", "Looking for a career with excitement?", "A recruitment poster starring a dark haired woman with glasses and a purple shirt that has \"Got Brains? Got Talent? Not afraid of electric flying monsters that want to suck the soul out of you? Then Xenobiology could use someone like you!\" written on the bottom.") +DEFINE_POSTER( bay_23, "bsposter23", "Safety first: because electricity doesn't wait!", "A safety poster starring a clueless looking redhead with frazzled hair. \"Every year, hundreds of employees expose themselves to electric shock. Play it safe. Avoid suspicious doors after electrical storms, and always wear protection when doing electric maintenance.\"") +DEFINE_POSTER( bay_24, "bsposter24", "Responsible medbay habits, No #259", "A poster with a nervous looking geneticist on it states; \"Friends Tell Friends They're Clones. It can cause severe and irreparable emotional trauma if a person is not properly informed of their recent demise. Always follow your contractual obligation and inform them of their recent rejuvenation.\"") +DEFINE_POSTER( bay_25, "bsposter25", "Irresponsible medbay habits, No #2", "This is a safety poster starring a perverted looking naked doctor. \"Sexual harassment is never okay. REPORT any acts of sexual deviance or harassment that disrupt a healthy working environment.\"") +DEFINE_POSTER( bay_26, "bsposter26", "The Men We Knew", "This movie poster depicts a group of soldiers fighting a large exosuit, the movie seems to be a patriotic war movie.") +DEFINE_POSTER( bay_27, "bsposter27", "Plastic Sheep Can't Scream", "This is a movie poster for an upcoming horror movie, it features an AI in the front of it.") +DEFINE_POSTER( bay_28, "bsposter28", "The Stars Know Love", "This is a movie poster. A bleeding woman is shown drawing a heart in her blood on the window of space ship, it seems to be a romantic Drama.") +DEFINE_POSTER( bay_29, "bsposter29", "Winter Is Coming", "On the poster is a frighteningly large wolf, he warns: \"Only YOU can keep humanity from freezing during planetary occultation!\"") +DEFINE_POSTER( bay_30, "bsposter30", "Ambrosia Vulgaris", "Just looking at this poster makes you feel a little bit dizzy.") +DEFINE_POSTER( bay_31, "bsposter31", "Donut Corp", "This is an advertisement for Donut Corp, the new innovation in donut technology!") +DEFINE_POSTER( bay_32, "bsposter32", "Eat!", "A poster depicting a hamburger. The poster orders you to consume the hamburger.") +DEFINE_POSTER( bay_33, "bsposter33", "Tools, tools, tools", "You can never have enough tools, thats for sure!") +DEFINE_POSTER( bay_34, "bsposter34", "Power Up!", "High reward, higher risk!") +DEFINE_POSTER( bay_35, "bsposter35", "Lamarr", "This is a poster depicting the pet and mascot of the science department.") +DEFINE_POSTER( bay_36, "bsposter36", "Fancy Borg", "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it.") +DEFINE_POSTER( bay_37, "bsposter37", "Fancier Borg", "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it. This is even fancier than the first poster.") +DEFINE_POSTER( bay_38, "bsposter38", "Toaster Love", "This is a poster of a toaster containing two slices of bread. The word LOVE is written in big pink letters underneath.") +DEFINE_POSTER( bay_39, "bsposter39", "Responsible medbay habits, No #91", "A safety poster with a chemist holding a vial. \"Always wear safety gear while handling dangerous chemicals, even if it concerns only small amounts.\"") +DEFINE_POSTER( bay_40, "bsposter40", "Agreeable work environment", "This poster depicts a young woman in a stylish dress. \"Try to aim for a pleasant atmosphere in the workspace. A friendly word can do more than forms in triplicate.\"") +DEFINE_POSTER( bay_41, "bsposter41", "Professional work environment", "A safety poster featuring a green haired woman in a shimmering blue dress. \"As an Internal Affairs Agent, your job is to create a fair and agreeable work environment for the crewmembers, as discreetly and professionally as possible.\"") +DEFINE_POSTER( bay_42, "bsposter42", "Engineering pinup", "This is pin-up poster. A half-naked girl with white hair, toned muscles and stunning blue eyes looks back at you from the poster. Her welding helmet, tattoos and grey jumpsuit hanging around her waist gives a bit of a rugged feel.") +DEFINE_POSTER( bay_43, "bsposter43", "Responsible medbay habits, No #3", "A safety poster with a purple-haired surgeon. She looks a bit cross. \"Let the surgeons do their work. NEVER replace or remove a surgery tool from where the surgeon put it.\"") +// --- Missing #44 --- +DEFINE_POSTER( bay_45, "bsposter45", "Responsible engineering habits, No #1", "A safety poster featuring a blue haired engineer. \"When repairing a machine or construction, always aim for long-term solutions.\"") +DEFINE_POSTER( bay_46, "bsposter46", "Inspirational lawyer", "An inspirational poster depicting an alien lawyer. He seems to be shouting something, while pointing fiercely to the right.") +DEFINE_POSTER( bay_47, "bsposter47", "Security pinup", "This is a pin-up poster. A dark skinned white haired girl poses in the sunlight wearing a tank top with her stomach exposed. The text on the poster states \"M, Succubus of Security.\" and a lipstick mark stains the top right corner, as if kissed by the model herself.") +DEFINE_POSTER( bay_48, "bsposter48", "Borg pinup?", "This is a... pin-up poster? It is a diagram of an old model of cyborg with a note scribbled in marker on the bottom, on the top there is a large XO written in red marker.") +DEFINE_POSTER( bay_49, "bsposter49", "Engineering recruitment", "This is a poster showing an engineer relaxing by a computer, the text states \"Living the life! Join Engineering today!\"") +DEFINE_POSTER( bay_50, "bsposter50", "Pinup Girl Cindy Kate", "This particular one is of Cindy Kate, a seductive performer well known among less savoury circles.") +DEFINE_POSTER( bay_51, "bsposter51", "space appreciation poster", "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. One of three.") +DEFINE_POSTER( bay_52, "bsposter52", "fire safety poster", "This is a poster reminding you of what you should do if you are on fire, or if you are at a dance party.") +DEFINE_POSTER( bay_53, "bsposter53", "fire extinguisher poster", "This is a poster reminding you of what you should use to put out a fire.") +DEFINE_POSTER( bay_54, "bsposter54", "firefighter poster", "This is a poster of a particularly stern looking firefighter. The caption reads, \"Only you can prevent space fires.\"") +DEFINE_POSTER( bay_55, "bsposter55", "Earth appreciation poster", "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Two of three.") +DEFINE_POSTER( bay_56, "bsposter56", "Mars appreciation poster", "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Three of three.") +DEFINE_POSTER( bay_57, "bsposter57", "space carp warning poster", "This poster tells of the dangers of space carp infestations.") +DEFINE_POSTER( bay_58, "bsposter58", "space carp information poster", "This poster showcases an old spacer saying on the dangers of migrant space carp.") +DEFINE_POSTER( bay_59, "bsposter59", "poster - Miss Science 2299", "This pin-up poster depicts a woman wearing a corporate labcoat, a bikini, and a sheepish grin. She's shyly posing atop some highly specialized research equipment.") diff --git a/code/modules/posture/_posture.dm b/code/modules/posture/_posture.dm new file mode 100644 index 000000000000..ffa26d4d0f29 --- /dev/null +++ b/code/modules/posture/_posture.dm @@ -0,0 +1,21 @@ +/decl/posture + abstract_type = /decl/posture + /// Identifier for choosing from posture input(). + var/name + /// Whether or not this posture is considered lying down. + var/prone = FALSE + /// Whether or not this posture is deliberate, ie. if you should automatically try to stand up from it. + var/deliberate = FALSE + /// Whether or not this posture should show up in Change Posture. + var/is_user_selectable = FALSE + /// Whether or not this posture should supply a string value to get_overlay_state_modifier(). + var/overlay_modifier + /// An override for use when determining selectable postures. + var/selectable_type + /// String to use in Change Posture. + var/posture_change_message + /// Postural multiplier to effective blood circulation volume, a generalization of the old feature of 'laying down increases your effective blood volume'. + var/blood_volume_multiplier = 1 + +/decl/posture/proc/can_be_selected_by(mob/mob) + return is_user_selectable diff --git a/code/modules/posture/posture_bodytype.dm b/code/modules/posture/posture_bodytype.dm new file mode 100644 index 000000000000..0b051b0c94cd --- /dev/null +++ b/code/modules/posture/posture_bodytype.dm @@ -0,0 +1,26 @@ +/decl/bodytype + // This will generally not be used, except when a posture is not present in available_mob_postures. + var/list/basic_posture_map = list( + /decl/posture/standing = /decl/posture/standing, + /decl/posture/lying = /decl/posture/lying, + /decl/posture/lying/deliberate = /decl/posture/lying/deliberate + ) + var/list/available_mob_postures = list( + /decl/posture/standing, + /decl/posture/lying, + /decl/posture/lying/deliberate + ) + +/decl/bodytype/validate() + . = ..() + var/static/list/mandatory_postures = list( + /decl/posture/standing, + /decl/posture/lying, + /decl/posture/lying/deliberate + ) + for(var/mandatory_posture in mandatory_postures) + if(!basic_posture_map[mandatory_posture]) + . += "basic posture map missing [mandatory_posture]" + +/decl/bodytype/proc/get_equivalent_posture_type(posture_type) + return basic_posture_map[posture_type] diff --git a/code/modules/posture/posture_mob.dm b/code/modules/posture/posture_mob.dm new file mode 100644 index 000000000000..d6d30686caeb --- /dev/null +++ b/code/modules/posture/posture_mob.dm @@ -0,0 +1,62 @@ +/mob + var/decl/posture/current_posture + +/mob/Initialize() + var/list/postures = get_available_postures() + if(length(postures)) + set_posture(postures[1]) + return ..() + +/mob/proc/set_posture(decl/posture/posture, skip_buckled_update = FALSE) + current_posture = GET_DECL(/decl/posture/standing) + +/mob/proc/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing + ) + return available_postures + +/mob/living/proc/get_selectable_postures() + for(var/posture_type in get_available_postures()) + if(posture_type == current_posture.type || posture_type == current_posture.selectable_type) + continue + var/decl/posture/posture = GET_DECL(posture_type) + if(posture.can_be_selected_by(src)) + LAZYDISTINCTADD(., posture) + +/mob/living/get_available_postures() + var/decl/bodytype/my_bodytype = get_bodytype() + if(my_bodytype) + return my_bodytype.available_mob_postures + return ..() + +/mob/living/set_posture(decl/posture/posture, skip_buckled_update = FALSE) + + if(ispath(posture)) + if(!(posture in get_available_postures())) + posture = get_bodytype()?.get_equivalent_posture_type(posture) + posture = GET_DECL(posture) + else if(istype(posture) && !(posture.type in get_available_postures())) + posture = GET_DECL(get_bodytype()?.get_equivalent_posture_type(posture.type)) + + if(!istype(posture) || posture == current_posture) + return FALSE + + current_posture = posture + if(current_posture.prone) + set_density(FALSE) + drop_held_items() + stop_aiming(no_message=1) + if(buckled_mob) + unbuckle_mob() + else + set_density(initial(density)) + + if(skip_buckled_update) + reset_layer() + update_icon() + update_transform() + else + update_posture(force_update = TRUE) + + return TRUE diff --git a/code/modules/posture/posture_subtypes.dm b/code/modules/posture/posture_subtypes.dm new file mode 100644 index 000000000000..77d53d3fa7d1 --- /dev/null +++ b/code/modules/posture/posture_subtypes.dm @@ -0,0 +1,25 @@ +/decl/posture/standing + name = "standing" + posture_change_message = "standing up" + is_user_selectable = TRUE + deliberate = TRUE + +/decl/posture/lying + name = "lying" + prone = TRUE + posture_change_message = "lying down" + selectable_type = /decl/posture/lying/deliberate + blood_volume_multiplier = 1.25 + +/decl/posture/lying/deliberate + name = "resting" + is_user_selectable = TRUE + deliberate = TRUE + +/decl/posture/sitting + name = "sitting" + posture_change_message = "sitting down" + is_user_selectable = TRUE + deliberate = TRUE + prone = TRUE + blood_volume_multiplier = 1.1 // sitting is a little less intense than standing diff --git a/code/modules/power/admin_setup_engine.dm b/code/modules/power/admin_setup_engine.dm new file mode 100644 index 000000000000..e5aae9005847 --- /dev/null +++ b/code/modules/power/admin_setup_engine.dm @@ -0,0 +1,162 @@ +#define ENGINE_SETUP_OK 1 // All good +#define ENGINE_SETUP_WARNING 2 // Something that shouldn't happen happened, but it's not critical so we will continue +#define ENGINE_SETUP_ERROR 3 // Something bad happened, and it's important so we won't continue setup. +#define ENGINE_SETUP_DELAYED 4 // Wait for other things first. + +var/global/list/engine_setup_markers = list() + +/obj/effect/engine_setup + name = "Engine Setup Marker" + desc = "You shouldn't see this." + invisibility = INVISIBILITY_ABSTRACT + anchored = TRUE + density = FALSE + icon = 'icons/effects/markers.dmi' + icon_state = "x3" + +/obj/effect/engine_setup/Initialize() + . = ..() + global.engine_setup_markers += src + +/obj/effect/engine_setup/Destroy() + global.engine_setup_markers -= src + . = ..() + +/obj/effect/engine_setup/proc/activate(var/last = 0) + return 1 + + + +// Tries to locate a pump, enables it, and sets it to MAX. Triggers warning if unable to locate a pump. +/obj/effect/engine_setup/pump_max + name = "Pump Setup Marker" + +/obj/effect/engine_setup/pump_max/activate() + ..() + var/obj/machinery/atmospherics/binary/pump/P = locate() in get_turf(src) + if(!P) + log_and_message_admins("## WARNING: Unable to locate pump at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + P.target_pressure = P.max_pressure_setting + P.update_use_power(POWER_USE_IDLE) + return ENGINE_SETUP_OK + + + +// Spawns an empty canister on this turf, if it has a connector port. Triggers warning if unable to find a connector port +/obj/effect/engine_setup/empty_canister + name = "Empty Canister Marker" + +/obj/effect/engine_setup/empty_canister/activate() + ..() + var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src) + if(!P) + log_and_message_admins("## WARNING: Unable to locate connector port at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + new/obj/machinery/portable_atmospherics/canister(get_turf(src)) // Canisters automatically connect to connectors in New() + return ENGINE_SETUP_OK + + + + +// Spawns a coolant canister on this turf, if it has a connector port. +// Triggers error when unable to locate connector port or when coolant canister type is unset. +/obj/effect/engine_setup/coolant_canister + name = "Coolant Canister Marker" + var/canister_type = null + +/obj/effect/engine_setup/coolant_canister/activate() + ..() + var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src) + if(!P) + log_and_message_admins("## ERROR: Unable to locate coolant connector port at [x] [y] [z]!") + return ENGINE_SETUP_ERROR + if(!canister_type) + log_and_message_admins("## ERROR: Canister type unset at [x] [y] [z]!") + return ENGINE_SETUP_ERROR + new canister_type(get_turf(src)) + return ENGINE_SETUP_OK + + + +// Tries to enable the SMES on max input/output settings. With load balancing it should be fine as long as engine outputs at least ~500kW +/obj/effect/engine_setup/smes + name = "SMES Marker" + + var/target_input_level //These are in watts, the display is in kilowatts. Add three zeros to the value you want. + var/target_output_level //These are in watts, the display is in kilowatts. Add three zeros to the value you want. + +/obj/effect/engine_setup/smes/main + name = "Main SMES Marker" + target_input_level = INFINITY + target_output_level = INFINITY + +/obj/effect/engine_setup/smes/activate() + ..() + var/obj/machinery/power/smes/S = locate() in get_turf(src) + if(!S) + log_and_message_admins("## WARNING: Unable to locate SMES unit at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + S.input_attempt = 1 + S.input_level = min(target_input_level, S.input_level_max) + S.output_attempt = 1 + S.output_level = min(target_output_level, S.output_level_max) + S.update_icon() + return ENGINE_SETUP_OK + +// Sets up filters. This assumes filters are set to filter out CO2 back to the core loop by default! +/obj/effect/engine_setup/filter + name = "Omni Filter Marker" + var/coolant = null + +/obj/effect/engine_setup/filter/activate() + ..() + var/obj/machinery/atmospherics/omni/filter/F = locate() in get_turf(src) + if(!F) + log_and_message_admins("## WARNING: Unable to locate omni filter at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + if(!coolant) + log_and_message_admins("## WARNING: No coolant type set at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + + // Non-co2 coolant, adjust the filter's config first. + if(coolant != "CO2") + for(var/datum/omni_port/P in F.ports) + if(P.filtering != /decl/material/gas/carbon_dioxide) + continue + else if(coolant == "N2") + P.filtering = /decl/material/gas/nitrogen + break + else if(coolant == "H2") + P.filtering = /decl/material/gas/hydrogen + break + else + log_and_message_admins("## WARNING: Inapropriate filter coolant type set at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + F.rebuild_filtering_list() + + F.update_use_power(POWER_USE_IDLE) + return ENGINE_SETUP_OK + +// Closes the monitoring room shutters so the first Engi to show up doesn't get microwaved +/obj/effect/engine_setup/shutters + name = "Shutter Button Marker" + // This needs to be set to whatever the shutter button is called + var/target_button = "Engine Monitoring Room Blast Doors" + +/obj/effect/engine_setup/shutters/activate() + if(!target_button) + log_and_message_admins("## WARNING: No button type set at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + var/obj/machinery/button/blast_door/found = null + var/turf/T = get_turf(src) + for(var/obj/machinery/button/blast_door/B in T.contents) + if(B.name == target_button) + found = B + break + if(!found) + log_and_message_admins("## WARNING: Unable to locate button at [x] [y] [z]!") + return ENGINE_SETUP_WARNING + found.activate() + found.update_icon() + return ENGINE_SETUP_OK \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm deleted file mode 100644 index 9c825a5c5fbc..000000000000 --- a/code/modules/power/apc.dm +++ /dev/null @@ -1,939 +0,0 @@ - - -// The Area Power Controller (APC) -// Controls and provides power to most electronics in an area -// Only one required per area -// Requires a wire connection to a power network through a terminal -// Generates a terminal based on the direction of the APC on spawn - -// There are three different power channels, lighting, equipment, and enviroment -// Each may have one of the following states - -#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 - -// Power channels set to Auto change when power levels rise or drop below a threshold - -#define AUTO_THRESHOLD_LIGHTING 50 -#define AUTO_THRESHOLD_EQUIPMENT 25 -// The ENVIRON channel stays on as long as possible, and doesn't have a threshold - -#define CRITICAL_APC_EMP_PROTECTION 10 // EMP effect duration is divided by this number if the APC has "critical" flag -#define APC_UPDATE_ICON_COOLDOWN 100 // Time between automatically updating the icon (10 seconds) - -// Used to check whether or not to update the icon_state -#define UPDATE_CELL_IN 1 -#define UPDATE_OPENED1 2 -#define UPDATE_OPENED2 4 -#define UPDATE_MAINT 8 -#define UPDATE_BROKE 16 -#define UPDATE_BLUESCREEN 32 -#define UPDATE_WIREEXP 64 -#define UPDATE_ALLGOOD 128 - -// Used to check whether or not to update the overlay -#define APC_UPOVERLAY_CHARGEING0 1 -#define APC_UPOVERLAY_CHARGEING1 2 -#define APC_UPOVERLAY_CHARGEING2 4 -#define APC_UPOVERLAY_LOCKED 8 -#define APC_UPOVERLAY_OPERATING 16 - -// Various APC types -/obj/machinery/power/apc/inactive - lighting = 0 - equipment = 0 - environ = 0 - locked = FALSE - -/obj/machinery/power/apc/critical - is_critical = 1 - -/obj/machinery/power/apc/high - uncreated_component_parts = list( - /obj/item/cell/high - ) - -/obj/machinery/power/apc/high/inactive - lighting = 0 - equipment = 0 - environ = 0 - locked = FALSE - -/obj/machinery/power/apc/super - uncreated_component_parts = list( - /obj/item/cell/super - ) - -/obj/machinery/power/apc/super/critical - is_critical = 1 - -/obj/machinery/power/apc/hyper - uncreated_component_parts = list( - /obj/item/cell/hyper - ) - -// Main APC code -/obj/machinery/power/apc - name = "area power controller" - desc = "A control terminal for the area electrical systems." - - icon_state = "apc0" - icon = 'icons/obj/apc.dmi' - anchored = 1 - use_power = POWER_USE_IDLE // Has custom handling here. - power_channel = LOCAL // Do not manipulate this; you don't want to power the APC off itself. - interact_offline = TRUE // Can use UI even if unpowered - - initial_access = list(access_engine_equip) - clicksound = "switch" - layer = ABOVE_WINDOW_LAYER - var/needs_powerdown_sound - var/area/area - var/areastring = null - var/shorted = 0 - var/lighting = POWERCHAN_ON_AUTO - var/equipment = POWERCHAN_ON_AUTO - var/environ = POWERCHAN_ON_AUTO - var/operating = 1 // Bool for main toggle. - var/charging = 0 // Whether or not it's charging. 0 - not charging but not full, 1 - charging, 2 - full - var/chargemode = 1 // Whether charging is toggled on or off. - var/aidisabled = 0 - var/lastused_light = 0 // Internal stuff for UI and bookkeeping; can read off values but don't modify. - var/lastused_equip = 0 - var/lastused_environ = 0 - var/lastused_charging = 0 // Not an actual channel, and not summed into total. How much battery was recharged, if any, last tick. - var/lastused_total = 0 - var/main_status = 0 // UI var for whether we are getting external power. 0 = no external power at all, 1 = some, but not enough, 2 = getting enough. - var/mob/living/silicon/ai/hacker = null // Malfunction var. If set AI hacked the APC and has full control. - powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :( - var/autoflag= 0 // 0 = off, 1= eqp and lights off, 2 = eqp off, 3 = all on. - var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment - var/longtermpower = 10 // Counter to smooth out power state changes; do not modify. - wires = /datum/wires/apc - var/update_state = -1 - var/update_overlay = -1 - var/list/update_overlay_chan // Used to determine if there is a change in channels - var/is_critical = 0 - var/global/status_overlays = 0 - var/failure_timer = 0 // Cooldown thing for apc outage event - var/force_update = 0 - var/emp_hardened = 0 - var/global/list/status_overlays_lock - var/global/list/status_overlays_charging - var/global/list/status_overlays_equipment - var/global/list/status_overlays_lighting - var/global/list/status_overlays_environ - var/autoname = 1 - var/cover_removed = FALSE // Cover is gone; can't close it anymore. - var/locked = TRUE // This is the interface, not the hardware. - - base_type = /obj/machinery/power/apc/buildable - stat_immune = 0 - frame_type = /obj/item/frame/apc - construct_state = /decl/machine_construction/wall_frame/panel_closed/hackable - uncreated_component_parts = list( - /obj/item/cell/apc - ) - -/obj/machinery/power/apc/buildable - uncreated_component_parts = null - -/obj/machinery/power/apc/connect_to_network() - //Override because the APC does not directly connect to the network; it goes through a terminal. - //The terminal is what the power computer looks for anyway. - var/obj/machinery/power/terminal/terminal = terminal() - if(terminal) - terminal.connect_to_network() - -/obj/machinery/power/apc/drain_power(var/drain_check, var/surge, var/amount = 0) - - if(drain_check) - return 1 - - // Prevents APCs from being stuck on 0% cell charge while reporting "Fully Charged" status. - charging = 0 - - // If the APC's interface is locked, limit the charge rate to 25%. - if(locked) - amount /= 4 - - return amount - use_power_oneoff(amount, LOCAL) - -/obj/machinery/power/apc/Initialize(mapload, var/ndir, var/populate_parts = TRUE) - if(areastring) - area = get_area_name(areastring) - else - var/area/A = get_area(src) - //if area isn't specified use current - area = A - if(!area) - return ..() // Spawned in nullspace means it's a test entity or prototype. - if(autoname) - SetName("\improper [area.name] APC") - area.apc = src - - GLOB.name_set_event.register(area, src, .proc/change_area_name) - - . = ..() - - if (populate_parts) - init_round_start() - else - operating = 0 - queue_icon_update() - - if(operating) - force_update_channels() - power_change() - -/obj/machinery/power/apc/Destroy() - if(area) - update() - area.apc = null - area.power_light = 0 - area.power_equip = 0 - area.power_environ = 0 - area.power_change() - - GLOB.name_set_event.unregister(area, src, .proc/change_area_name) - - // Malf AI, removes the APC from AI's hacked APCs list. - if((hacker) && (hacker.hacked_apcs) && (src in hacker.hacked_apcs)) - hacker.hacked_apcs -= src - - return ..() - -/obj/machinery/power/apc/get_req_access() - if(!locked) - return list() - return ..() - -/obj/machinery/power/apc/proc/energy_fail(var/duration) - if(emp_hardened) - return - failure_timer = max(failure_timer, round(duration)) - playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0) - -/obj/machinery/power/apc/proc/init_round_start() - var/obj/item/stock_parts/power/terminal/term = get_component_of_type(/obj/item/stock_parts/power/terminal) - term.make_terminal(src) // intentional crash if there is no terminal - queue_icon_update() - -/obj/machinery/power/apc/proc/terminal() - var/obj/item/stock_parts/power/terminal/term = get_component_of_type(/obj/item/stock_parts/power/terminal) - return term && term.terminal - -/obj/machinery/power/apc/examine(mob/user, distance) - . = ..() - if(distance <= 1) - if(stat & BROKEN) - to_chat(user, "Looks broken.") - return - var/terminal = terminal() - to_chat(user, "\The [src] is [terminal ? "" : "not "]connected to external power.") - if(!panel_open) - to_chat(user, "The cover is closed.") - else - to_chat(user, "The cover is [cover_removed ? "removed" : "open"] and the power cell is [ get_cell() ? "installed" : "missing"].") -// Broken/missing board should be shown by parent. - -// update the APC icon to show the three base states -// also add overlays for indicator lights -/obj/machinery/power/apc/on_update_icon() - if (!status_overlays) - status_overlays = 1 - status_overlays_lock = new - status_overlays_charging = new - status_overlays_equipment = new - status_overlays_lighting = new - status_overlays_environ = new - - status_overlays_lock.len = 2 - status_overlays_charging.len = 3 - status_overlays_equipment.len = 5 - status_overlays_lighting.len = 5 - status_overlays_environ.len = 5 - - status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red - status_overlays_lock[2] = image(icon, "apcox-1") - - status_overlays_charging[1] = image(icon, "apco3-0") - status_overlays_charging[2] = image(icon, "apco3-1") - status_overlays_charging[3] = image(icon, "apco3-2") - - var/list/channel_overlays = list(status_overlays_equipment, status_overlays_lighting, status_overlays_environ) - var/channel = 0 - for(var/list/channel_leds in channel_overlays) - channel_leds[POWERCHAN_OFF + 1] = overlay_image(icon,"apco[channel]",COLOR_RED) - channel_leds[POWERCHAN_OFF_TEMP + 1] = overlay_image(icon,"apco[channel]",COLOR_ORANGE) - channel_leds[POWERCHAN_OFF_AUTO + 1] = overlay_image(icon,"apco[channel]",COLOR_ORANGE) - channel_leds[POWERCHAN_ON + 1] = overlay_image(icon,"apco[channel]",COLOR_LIME) - channel_leds[POWERCHAN_ON_AUTO + 1] = overlay_image(icon,"apco[channel]",COLOR_BLUE) - channel++ - - if(update_state < 0) - pixel_x = 0 - pixel_y = 0 - var/turf/T = get_step(get_turf(src), dir) - if(istype(T) && T.density) - if(dir == SOUTH) - pixel_y = -22 - else if(dir == NORTH) - pixel_y = 22 - else if(dir == EAST) - pixel_x = 22 - else if(dir == WEST) - pixel_x = -22 - - var/update = check_updates() //returns 0 if no need to update icons. - // 1 if we need to update the icon_state - // 2 if we need to update the overlays - - if(!update) - return - - if(update & 1) // Updating the icon state - if(update_state & UPDATE_ALLGOOD) - icon_state = "apc0" - else if(update_state & (UPDATE_OPENED1|UPDATE_OPENED2)) - var/basestate = "apc[ get_cell() ? "2" : "1" ]" - if(update_state & UPDATE_OPENED1) - if(update_state & (UPDATE_MAINT|UPDATE_BROKE)) - icon_state = "apcmaint" //disabled APC cannot hold cell - else - icon_state = basestate - else if(update_state & UPDATE_OPENED2) - icon_state = "[basestate]-nocover" - else if(update_state & UPDATE_BROKE) - icon_state = "apc-b" - else if(update_state & UPDATE_BLUESCREEN) - icon_state = "apcemag" - else if(update_state & UPDATE_WIREEXP) - icon_state = "apcewires" - - if(!(update_state & UPDATE_ALLGOOD)) - if(overlays.len) - overlays.Cut() - return - - if(update & 2) - if(overlays.len) - overlays.Cut() - if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) - overlays += status_overlays_lock[locked+1] - overlays += status_overlays_charging[charging+1] - if(operating) - overlays += status_overlays_equipment[equipment+1] - overlays += status_overlays_lighting[lighting+1] - overlays += status_overlays_environ[environ+1] - - if(update & 3) - if(update_state & (UPDATE_OPENED1|UPDATE_OPENED2|UPDATE_BROKE)) - set_light(0) - else if(update_state & UPDATE_BLUESCREEN) - set_light(0.8, 0.1, 1, 2, "#00ecff") - else if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) - var/color - switch(charging) - if(0) - color = "#f86060" - if(1) - color = "#a8b0f8" - if(2) - color = "#82ff4c" - set_light(0.8, 0.1, 1, l_color = color) - else - set_light(0) - -/obj/machinery/power/apc/proc/check_updates() - if(!update_overlay_chan) - update_overlay_chan = new/list() - var/last_update_state = update_state - var/last_update_overlay = update_overlay - var/list/last_update_overlay_chan = update_overlay_chan.Copy() - update_state = 0 - update_overlay = 0 - if(get_cell()) - update_state |= UPDATE_CELL_IN - if(stat & BROKEN) - update_state |= UPDATE_BROKE - if(stat & MAINT) - update_state |= UPDATE_MAINT - if(panel_open) - if(!cover_removed) - update_state |= UPDATE_OPENED1 - else - update_state |= UPDATE_OPENED2 - else if(emagged || (hacker && !hacker.hacked_apcs_hidden) || failure_timer) - update_state |= UPDATE_BLUESCREEN - else if(istype(construct_state, /decl/machine_construction/wall_frame/panel_closed/hackable/hacking)) - update_state |= UPDATE_WIREEXP - if(update_state <= 1) - update_state |= UPDATE_ALLGOOD - - if(operating) - update_overlay |= APC_UPOVERLAY_OPERATING - - if(update_state & UPDATE_ALLGOOD) - if(locked) - update_overlay |= APC_UPOVERLAY_LOCKED - - if(!charging) - update_overlay |= APC_UPOVERLAY_CHARGEING0 - else if(charging == 1) - update_overlay |= APC_UPOVERLAY_CHARGEING1 - else if(charging == 2) - update_overlay |= APC_UPOVERLAY_CHARGEING2 - - - update_overlay_chan["Equipment"] = equipment - update_overlay_chan["Lighting"] = lighting - update_overlay_chan["Enviroment"] = environ - - - var/results = 0 - if(last_update_state == update_state && last_update_overlay == update_overlay && last_update_overlay_chan == update_overlay_chan) - return 0 - if(last_update_state != update_state) - results += 1 - if(last_update_overlay != update_overlay || last_update_overlay_chan != update_overlay_chan) - results += 2 - return results - -/obj/machinery/power/apc/set_broken(new_state, cause) - . = ..() - if(. && (stat & BROKEN)) - operating = 0 - update() - -/obj/machinery/power/apc/cannot_transition_to(state_path, mob/user) - if(ispath(state_path, /decl/machine_construction/wall_frame/panel_closed) && cover_removed) - return SPAN_NOTICE("You cannot close the cover: it was completely removed!") - . = ..() - -/obj/machinery/power/apc/proc/force_open_panel(mob/user) - var/decl/machine_construction/wall_frame/panel_closed/closed_state = construct_state - if(!istype(closed_state)) - return MCS_CONTINUE - var/list/locks = get_all_components_of_type(/obj/item/stock_parts/access_lock) - for(var/obj/item/stock_parts/access_lock/lock in locks) - lock.locked = FALSE - . = closed_state.try_change_state(src, closed_state.open_state, user) - if(. != MCS_CHANGE) - return - panel_open = TRUE - queue_icon_update() - -/obj/machinery/power/apc/attackby(obj/item/W, mob/user) - if (istype(construct_state, /decl/machine_construction/wall_frame/panel_closed/hackable/hacking) && (isMultitool(W) || isWirecutter(W) || istype(W, /obj/item/assembly/signaler))) - return wires.Interact(user) - return ..() - -/obj/machinery/power/apc/bash(obj/item/W, mob/user) - if (!(user.a_intent == I_HURT) || (W.item_flags & ITEM_FLAG_NO_BLUDGEON)) - return - - if(!panel_open && W.force >= 5 && W.w_class >= ITEM_SIZE_NORMAL) - if (((stat & BROKEN) || (hacker && !hacker.hacked_apcs_hidden)) && prob(20)) - playsound(get_turf(src), 'sound/weapons/smash.ogg', 75, 1) - if(force_open_panel(user) == MCS_CHANGE) - cover_removed = TRUE - user.visible_message("The APC cover was knocked down with the [W.name] by [user.name]!", \ - "You knock down the APC cover with your [W.name]!", \ - "You hear a bang") - return TRUE - return ..() - -// attack with hand - remove cell (if cover open) or interact with the APC - -/obj/machinery/power/apc/emag_act(var/remaining_charges, var/mob/user) - if (!(emagged || (hacker && !hacker.hacked_apcs_hidden))) // trying to unlock with an emag card - if(panel_open) - to_chat(user, "You must close the cover to swipe an ID card.") - else if(stat & (BROKEN|MAINT)) - to_chat(user, "Nothing happens.") - else - flick("apc-spark", src) - if (do_after(user,6,src)) - if(prob(50)) - emagged = 1 - req_access.Cut() - locked = 0 - to_chat(user, "You emag the APC interface.") - update_icon() - else if(prob(50)) - return max(..(), 1) // might unlock the panel lock instead. - else - to_chat(user, "You fail to [ locked ? "unlock" : "lock"] the APC interface.") - return 1 - -/obj/machinery/power/apc/CanUseTopicPhysical(var/mob/user) - return GLOB.physical_state.can_use_topic(nano_host(), user) - -/obj/machinery/power/apc/physical_attack_hand(mob/user) - //Human mob special interaction goes here. - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - - if(H.species.can_shred(H)) - user.visible_message("\The [user] slashes at \the [src]!", "You slash at \the [src]!") - playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - - var/allcut = wires.IsAllCut() - if(beenhit >= pick(3, 4) && allcut == 0) - wires.CutAll() - src.update_icon() - src.visible_message("\The [src]'s wires are shredded!") - else - beenhit += 1 - return TRUE - -/obj/machinery/power/apc/interface_interact(mob/user) - ui_interact(user) - return TRUE - -/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(!user) - return - var/obj/item/cell/cell = get_cell() - var/coverlocked = FALSE - for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) - if(lock.locked) - coverlocked = TRUE - break - - var/list/data = list( - "pChan_Off" = POWERCHAN_OFF, - "pChan_Off_T" = POWERCHAN_OFF_TEMP, - "pChan_Off_A" = POWERCHAN_OFF_AUTO, - "pChan_On" = POWERCHAN_ON, - "pChan_On_A" = POWERCHAN_ON_AUTO, - "locked" = locked, - "isOperating" = operating, - "externalPower" = main_status, - "powerCellStatus" = cell ? cell.percent() : null, - "chargeMode" = chargemode, - "chargingStatus" = charging, - "totalLoad" = round(lastused_total), - "totalCharging" = round(lastused_charging), - "coverLocked" = coverlocked, - "failTime" = failure_timer * 2, - "siliconUser" = istype(user, /mob/living/silicon), - "powerChannels" = list( - list( - "title" = "Equipment", - "powerLoad" = lastused_equip, - "status" = equipment, - "topicParams" = list( - "auto" = list("eqp" = 2), - "on" = list("eqp" = 1), - "off" = list("eqp" = 0) - ) - ), - list( - "title" = "Lighting", - "powerLoad" = round(lastused_light), - "status" = lighting, - "topicParams" = list( - "auto" = list("lgt" = 2), - "on" = list("lgt" = 1), - "off" = list("lgt" = 0) - ) - ), - list( - "title" = "Environment", - "powerLoad" = round(lastused_environ), - "status" = environ, - "topicParams" = list( - "auto" = list("env" = 2), - "on" = list("env" = 1), - "off" = list("env" = 0) - ) - ) - ) - ) - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 440) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) - -/obj/machinery/power/apc/proc/report() - var/obj/item/cell/cell = get_cell() - return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" - -/obj/machinery/power/apc/proc/update() - if(operating && !shorted && !failure_timer) - - //prevent unnecessary updates to emergency lighting - var/new_power_light = (lighting >= POWERCHAN_ON) - if(area.power_light != new_power_light) - area.power_light = new_power_light - area.set_emergency_lighting(lighting == POWERCHAN_OFF_AUTO) //if lights go auto-off, emergency lights go on - - area.power_equip = (equipment >= POWERCHAN_ON) - area.power_environ = (environ >= POWERCHAN_ON) - else - area.power_light = 0 - area.power_equip = 0 - area.power_environ = 0 - - area.power_change() - - var/obj/item/cell/cell = get_cell() - if(!cell || cell.charge <= 0) - if(needs_powerdown_sound == TRUE) - playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0) - needs_powerdown_sound = FALSE - else - needs_powerdown_sound = TRUE - -/obj/machinery/power/apc/proc/isWireCut(var/wireIndex) - return wires.IsIndexCut(wireIndex) - - -/obj/machinery/power/apc/CanUseTopic(mob/user, datum/topic_state/state) - if(user.lying) - to_chat(user, "You must stand to use [src]!") - return STATUS_CLOSE - if(istype(user, /mob/living/silicon)) - var/permit = 0 // Malfunction variable. If AI hacks APC it can control it even without AI control wire. - var/mob/living/silicon/ai/AI = user - var/mob/living/silicon/robot/robot = user - if(hacker && !hacker.hacked_apcs_hidden) - if(hacker == AI) - permit = 1 - else if(istype(robot) && robot.connected_ai && robot.connected_ai == hacker) // Cyborgs can use APCs hacked by their AI - permit = 1 - - if(aidisabled && !permit) - return STATUS_CLOSE - . = ..() - if(user.restrained()) - to_chat(user, "You must have free hands to use [src].") - . = min(., STATUS_UPDATE) - -/obj/machinery/power/apc/OnTopic(mob/user, list/href_list, state) - if(href_list["toggleaccess"]) - if(emagged || (stat & (BROKEN|MAINT)) || (hacker && !hacker.hacked_apcs_hidden)) - to_chat(user, "The APC does not respond to the command.") - else - locked = !locked - update_icon() - return TOPIC_REFRESH - - if(locked) - return TOPIC_REFRESH - - if(href_list["lock"]) - var/coverlocked = FALSE - var/list/locks = get_all_components_of_type(/obj/item/stock_parts/access_lock) - for(var/obj/item/stock_parts/access_lock/lock in locks) - if(lock.locked) - coverlocked = TRUE - break - for(var/obj/item/stock_parts/access_lock/lock in locks) - lock.locked = !coverlocked - return TOPIC_REFRESH - - if(href_list["reboot"] ) - failure_timer = 0 - update_icon() - update() - return TOPIC_REFRESH - - if(href_list["breaker"]) - toggle_breaker() - return TOPIC_REFRESH - - if(href_list["cmode"]) - set_chargemode(!chargemode) - if(!chargemode) - charging = 0 - update_icon() - return TOPIC_REFRESH - - if(href_list["eqp"]) - var/val = text2num(href_list["eqp"]) - equipment = setsubsystem(val) - force_update_channels() - return TOPIC_REFRESH - - if(href_list["lgt"]) - var/val = text2num(href_list["lgt"]) - lighting = setsubsystem(val) - force_update_channels() - return TOPIC_REFRESH - - if(href_list["env"]) - var/val = text2num(href_list["env"]) - environ = setsubsystem(val) - force_update_channels() - return TOPIC_REFRESH - - if(href_list["overload"]) - if(istype(user, /mob/living/silicon)) - overload_lighting() - return TOPIC_REFRESH - -/obj/machinery/power/apc/proc/force_update_channels() - autoflag = -1 // This clears state, forcing a full recalculation - update_channels(TRUE) - update() - queue_icon_update() - -/obj/machinery/power/apc/proc/toggle_breaker() - operating = !operating - force_update_channels() - -/obj/machinery/power/apc/get_power_usage() - if(autoflag) - return lastused_total // If not, we need to do something more sophisticated: compute how much power we would need in order to come back online. - . = 0 - if(!area) - return - if(autoset(lighting, 2) >= POWERCHAN_ON) - . += area.usage(LIGHT) - if(autoset(equipment, 2) >= POWERCHAN_ON) - . += area.usage(EQUIP) - if(autoset(environ, 1) >= POWERCHAN_ON) - . += area.usage(EQUIP) - -/obj/machinery/power/apc/Process() - if(!area.requires_power) - return PROCESS_KILL - - if(stat & (BROKEN|MAINT)) - return - - if(failure_timer) - update() - queue_icon_update() - failure_timer-- - force_update = 1 - return - - lastused_light = (lighting >= POWERCHAN_ON) ? area.usage(LIGHT) : 0 - lastused_equip = (equipment >= POWERCHAN_ON) ? area.usage(EQUIP) : 0 - lastused_environ = (environ >= POWERCHAN_ON) ? area.usage(ENVIRON) : 0 - area.clear_usage() - - lastused_total = lastused_light + lastused_equip + lastused_environ - - //store states to update icon if any change - var/last_lt = lighting - var/last_eq = equipment - var/last_en = environ - var/last_ch = charging - - var/obj/machinery/power/terminal/terminal = terminal() - var/avail = (terminal && terminal.avail()) || 0 - var/excess = (terminal && terminal.surplus()) || 0 - - if(!avail) - main_status = 0 - else if(excess < 0) - main_status = 1 - else - main_status = 2 - - var/obj/item/cell/cell = get_cell() - if(!cell || shorted) // We aren't going to be doing any power processing in this case. - charging = 0 - else - ..() // Actual processing happens in here. - - //update state - var/obj/item/stock_parts/power/battery/power = get_component_of_type(/obj/item/stock_parts/power/battery) - lastused_charging = max(power && power.cell && (power.cell.charge - power.last_cell_charge) * CELLRATE, 0) - charging = lastused_charging ? 1 : 0 - if(cell.fully_charged()) - charging = 2 - - if(stat & NOPOWER) - power_change() // We are the ones responsible for triggering listeners once power returns, so we run this to detect possible changes. - - // Set channels depending on how much charge we have left - update_channels() - - // update icon & area power if anything changed - if(last_lt != lighting || last_eq != equipment || last_en != environ || force_update) - force_update = 0 - queue_icon_update() - update() - else if (last_ch != charging) - queue_icon_update() - -/obj/machinery/power/apc/proc/update_channels(suppress_alarms = FALSE) - // Allow the APC to operate as normal if the cell can charge - if(charging && longtermpower < 10) - longtermpower += 1 - else if(longtermpower > -10) - longtermpower -= 2 - var/obj/item/cell/cell = get_cell() - var/percent = cell && cell.percent() - - if(!cell || shorted || (stat & NOPOWER) || !operating) - if(autoflag != 0) - equipment = autoset(equipment, 0) - lighting = autoset(lighting, 0) - environ = autoset(environ, 0) - if(!suppress_alarms) - power_alarm.triggerAlarm(loc, src) - autoflag = 0 - else if((percent > AUTO_THRESHOLD_LIGHTING) || longtermpower >= 0) // Put most likely at the top so we don't check it last, effeciency 101 - if(autoflag != 3) - equipment = autoset(equipment, 1) - lighting = autoset(lighting, 1) - environ = autoset(environ, 1) - autoflag = 3 - power_alarm.clearAlarm(loc, src) - else if((percent <= AUTO_THRESHOLD_LIGHTING) && (percent > AUTO_THRESHOLD_EQUIPMENT) && longtermpower < 0) // <50%, turn off lighting - if(autoflag != 2) - equipment = autoset(equipment, 1) - lighting = autoset(lighting, 2) - environ = autoset(environ, 1) - if(!suppress_alarms) - power_alarm.triggerAlarm(loc, src) - autoflag = 2 - else if(percent <= AUTO_THRESHOLD_EQUIPMENT) // <25%, turn off lighting & equipment - if(autoflag != 1) - equipment = autoset(equipment, 2) - lighting = autoset(lighting, 2) - environ = autoset(environ, 1) - if(!suppress_alarms) - power_alarm.triggerAlarm(loc, src) - autoflag = 1 - -// val 0=off, 1=off(auto) 2=on 3=on(auto) -// on 0=off, 1=on, 2=autooff -// defines a state machine, returns the new state -obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) - //autoset will never turn on a channel set to off - switch(cur_state) - if(POWERCHAN_OFF_TEMP) - if(on == 1 || on == 2) - return POWERCHAN_ON - if(POWERCHAN_OFF_AUTO) - if(on == 1) - return POWERCHAN_ON_AUTO - if(POWERCHAN_ON) - if(on == 0) - return POWERCHAN_OFF_TEMP - if(POWERCHAN_ON_AUTO) - if(on == 0 || on == 2) - return POWERCHAN_OFF_AUTO - - return cur_state //leave unchanged - - -// damage and destruction acts -/obj/machinery/power/apc/emp_act(severity) - if(emp_hardened) - return - // Fail for 8-12 minutes (divided by severity) - // Division by 2 is required, because machinery ticks are every two seconds. Without it we would fail for 16-24 minutes. - if(is_critical) - // Critical APCs are considered EMP shielded and will be offline only for about half minute. Prevents AIs being one-shot disabled by EMP strike. - // Critical APCs are also more resilient to cell corruption/power drain. - energy_fail(rand(240, 360) / severity / CRITICAL_APC_EMP_PROTECTION) - else - // Regular APCs fail for normal time. - energy_fail(rand(240, 360) / severity) - queue_icon_update() - ..() - -/obj/machinery/power/apc/on_component_failure(obj/item/stock_parts/component) - var/was_broken = stat & BROKEN - . = ..() - if(!was_broken && (stat & BROKEN)) - visible_message("[src]'s screen flickers with warnings briefly!") - power_alarm.triggerAlarm(loc, src) - spawn(rand(2,5)) - operating = 0 - update() - -/obj/machinery/power/apc/proc/reboot() - //reset various counters so that process() will start fresh - charging = initial(charging) - autoflag = initial(autoflag) - longtermpower = initial(longtermpower) - failure_timer = initial(failure_timer) - - //start with main breaker off, chargemode in the default state and all channels on auto upon reboot - operating = 0 - - set_chargemode(initial(chargemode)) - power_alarm.clearAlarm(loc, src) - - lighting = POWERCHAN_ON_AUTO - equipment = POWERCHAN_ON_AUTO - environ = POWERCHAN_ON_AUTO - - force_update_channels() - -/obj/machinery/power/apc/proc/set_chargemode(new_mode) - chargemode = new_mode - var/obj/item/stock_parts/power/battery/power = get_component_of_type(/obj/item/stock_parts/power/battery) - if(power) - power.can_charge = chargemode - power.charge_wait_counter = initial(power.charge_wait_counter) - -/obj/machinery/power/apc/proc/change_area_name(var/area/A, var/old_area_name, var/new_area_name) - if(A != get_area(src) || !autoname) - return - SetName(replacetext(name,old_area_name,new_area_name)) - -// overload the lights in this APC area -/obj/machinery/power/apc/proc/overload_lighting(var/chance = 100) - if(/* !get_connection() || */ !operating || shorted) - return - var/amount = use_power_oneoff(20, LOCAL) - if(amount <= 0) - spawn(0) - for(var/obj/machinery/light/L in area) - if(prob(chance)) - L.on = 1 - L.broken() - sleep(1) - -/obj/machinery/power/apc/proc/setsubsystem(val) - switch(val) - if(2) - return POWERCHAN_OFF_AUTO - if(1) - return POWERCHAN_OFF_TEMP - else - return POWERCHAN_OFF - -// Malfunction: Transfers APC under AI's control -/obj/machinery/power/apc/proc/ai_hack(var/mob/living/silicon/ai/A = null) - if(!A || !A.hacked_apcs || hacker || aidisabled || A.stat == DEAD) - return 0 - src.hacker = A - A.hacked_apcs += src - locked = 1 - update_icon() - return 1 - -/obj/machinery/power/apc/malf_upgrade(var/mob/living/silicon/ai/user) - ..() - malf_upgraded = 1 - emp_hardened = 1 - to_chat(user, "\The [src] has been upgraded. It is now protected against EM pulses.") - return 1 - - - -#undef APC_UPDATE_ICON_COOLDOWN diff --git a/code/modules/power/apc/_apc.dm b/code/modules/power/apc/_apc.dm new file mode 100644 index 000000000000..b6721a8aa9cf --- /dev/null +++ b/code/modules/power/apc/_apc.dm @@ -0,0 +1,888 @@ +var/global/list/all_apcs = list() + +// The Area Power Controller (APC) +// Controls and provides power to most electronics in an area +// Only one required per area +// Requires a wire connection to a power network through a terminal +// Generates a terminal based on the direction of the APC on spawn + +// There are three different power channels, lighting, equipment, and environment +// Power channels set to Auto change when power levels rise or drop below a threshold + + +// Main APC code +/obj/machinery/apc + name = "area power controller" + desc = "A control terminal for the area electrical systems." + + icon_state = "apc0" + icon = 'icons/obj/apc.dmi' + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + use_power = POWER_USE_IDLE // Has custom handling here. + power_channel = LOCAL // Do not manipulate this; you don't want to power the APC off itself. + interact_offline = TRUE // Can use UI even if unpowered + + initial_access = list(access_engine_equip) + clicksound = "switch" + layer = ABOVE_WINDOW_LAYER + directional_offset = @'{"NORTH":{"y":22}, "SOUTH":{"y":-22}, "EAST":{"x":22}, "WEST":{"x":-22}}' + + var/powered_down = FALSE + var/area/area + var/areastring = null + var/shorted = 0 + var/lighting = POWERCHAN_ON_AUTO + var/equipment = POWERCHAN_ON_AUTO + var/environ = POWERCHAN_ON_AUTO + var/operating = 1 // Bool for main toggle. + var/charging = 0 // Whether or not it's charging. 0 - not charging but not full, 1 - charging, 2 - full + var/chargemode = 1 // Whether charging is toggled on or off. + var/aidisabled = FALSE + var/lastused_light = 0 // Internal stuff for UI and bookkeeping; can read off values but don't modify. + var/lastused_equip = 0 + var/lastused_environ = 0 + var/lastused_charging = 0 // Not an actual channel, and not summed into total. How much battery was recharged, if any, last tick. + var/lastused_total = 0 + var/main_status = 0 // UI var for whether we are getting external power. 0 = no external power at all, 1 = some, but not enough, 2 = getting enough. + var/mob/living/silicon/ai/hacker = null // Malfunction var. If set AI hacked the APC and has full control. + var/autoflag= 0 // 0 = off, 1= eqp and lights off, 2 = eqp off, 3 = all on. + var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment + var/longtermpower = 10 // Counter to smooth out power state changes; do not modify. + wires = /datum/wires/apc + // Values used for update_state. + var/const/UPDATE_CELL_IN = BITFLAG(0) + var/const/UPDATE_OPENED1 = BITFLAG(1) + var/const/UPDATE_OPENED2 = BITFLAG(2) + var/const/UPDATE_MAINT = BITFLAG(3) + var/const/UPDATE_BROKE = BITFLAG(4) + var/const/UPDATE_BLUESCREEN = BITFLAG(5) + var/const/UPDATE_WIREEXP = BITFLAG(6) + var/const/UPDATE_ALLGOOD = BITFLAG(7) + var/update_state = -1 + // Used to check whether or not to update the overlay + var/const/UPOVERLAY_CHARGEING0 = BITFLAG(0) + var/const/UPOVERLAY_CHARGEING1 = BITFLAG(1) + var/const/UPOVERLAY_CHARGEING2 = BITFLAG(2) + var/const/UPOVERLAY_LOCKED = BITFLAG(3) + var/const/UPOVERLAY_OPERATING = BITFLAG(4) + var/update_overlay = -1 + var/list/update_overlay_chan // Used to determine if there is a change in channels + var/is_critical = 0 + var/static/status_overlays = 0 + var/failure_timer = 0 // Cooldown thing for apc outage event + var/force_update = 0 + var/emp_hardened = 0 + var/static/list/status_overlays_lock + var/static/list/status_overlays_charging + var/static/list/status_overlays_equipment + var/static/list/status_overlays_lighting + var/static/list/status_overlays_environ + var/remote_control = FALSE //is remote control enabled? + var/autoname = 1 + var/cover_removed = FALSE // Cover is gone; can't close it anymore. + var/locked = TRUE // This is the interface, not the hardware. + /// EMP effect duration is divided by this number if the APC has "critical" flag + var/const/CRITICAL_EMP_PROTECTION = 10 + // Thresholds for lights/equipment turning off based on cell charge level + var/const/AUTO_THRESHOLD_LIGHTING = 50 + var/const/AUTO_THRESHOLD_EQUIPMENT = 25 + // The ENVIRON channel stays on as long as possible, and doesn't have a threshold + + base_type = /obj/machinery/apc/buildable + stat_immune = 0 + frame_type = /obj/item/frame/apc + construct_state = /decl/machine_construction/wall_frame/panel_closed/hackable + uncreated_component_parts = list( + /obj/item/cell/apc + ) + stock_part_presets = list(/decl/stock_part_preset/terminal_setup) + +/obj/machinery/apc/buildable + uncreated_component_parts = null + +/obj/machinery/apc/drain_power(var/drain_check, var/surge, var/amount = 0) + + if(drain_check) + return 1 + + // Prevents APCs from being stuck on 0% cell charge while reporting "Fully Charged" status. + charging = 0 + + // If the APC's interface is locked, limit the charge rate to 25%. + if(locked) + amount /= 4 + + return amount - use_power_oneoff(amount, LOCAL) + +/obj/machinery/apc/Initialize(mapload, var/ndir, var/populate_parts = TRUE) + global.all_apcs += src + if(areastring) + reset_area(null, get_area_by_name(strip_improper(areastring))) + else if (mapload) //if area isn't specified during mapload use current + reset_area(null, get_area(src)) + // otherwise, it'll be handled by Entered/area_changed + if(!area) + return ..() // Spawned in nullspace means it's a test entity or prototype. + + . = ..() + + if(!populate_parts) + operating = 0 + + queue_icon_update() + + if(operating) + force_update_channels() + power_change() + +/obj/machinery/apc/Destroy() + if(area) + reset_area(area, null) + global.all_apcs -= src + + // Malf AI, removes the APC from AI's hacked APCs list. + if((hacker) && (hacker.hacked_apcs) && (src in hacker.hacked_apcs)) + hacker.hacked_apcs -= src + + return ..() + +// Attempts to set the area and update all refs. Calling this outside of Initialize is experimental at best. +/obj/machinery/apc/proc/reset_area(area/old_area, area/new_area) + if(new_area == old_area) + return + if(old_area && old_area == area) + area = null + old_area.apc = null + old_area.power_light = 0 + old_area.power_equip = 0 + old_area.power_environ = 0 + power_alarm.clearAlarm(old_area, src) + old_area.power_change() + events_repository.unregister(/decl/observ/name_set, old_area, src, PROC_REF(change_area_name)) + if(new_area) + ASSERT(isnull(new_area.apc)) + ASSERT(isnull(area)) + new_area.apc = src + area = new_area + change_area_name(new_area, null, new_area.name) + events_repository.register(/decl/observ/name_set, new_area, src, PROC_REF(change_area_name)) + +/obj/machinery/apc/get_req_access() + if(!locked) + return list() + return ..() + +/obj/machinery/apc/proc/energy_fail(var/duration) + if(emp_hardened) + return + if(!failure_timer && duration) + playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0) + failure_timer = max(failure_timer, round(duration)) + +/obj/machinery/apc/proc/terminal(var/functional_only) + var/obj/item/stock_parts/power/terminal/term = get_component_of_type(/obj/item/stock_parts/power/terminal) + if(term && (!functional_only || term.is_functional())) + return term.terminal + +/obj/machinery/apc/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + if(stat & BROKEN) + . += "Looks broken." + return + var/terminal = terminal() + . += "\The [src] is [terminal ? "" : "not "]connected to external power." + if(!panel_open) + . += "The cover is closed." + else + . += "The cover is [cover_removed ? "removed" : "open"] and the power cell is [ get_cell(FALSE) ? "installed" : "missing"]." +// Broken/missing board should be shown by parent. + +// update the APC icon to show the three base states +// also add overlays for indicator lights +/obj/machinery/apc/on_update_icon() + if (!status_overlays) + status_overlays = 1 + status_overlays_lock = new + status_overlays_charging = new + status_overlays_equipment = new + status_overlays_lighting = new + status_overlays_environ = new + + status_overlays_lock.len = 2 + status_overlays_charging.len = 3 + status_overlays_equipment.len = 5 + status_overlays_lighting.len = 5 + status_overlays_environ.len = 5 + + status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red + status_overlays_lock[2] = image(icon, "apcox-1") + + status_overlays_charging[1] = image(icon, "apco3-0") + status_overlays_charging[2] = image(icon, "apco3-1") + status_overlays_charging[3] = image(icon, "apco3-2") + + var/list/channel_overlays = list(status_overlays_equipment, status_overlays_lighting, status_overlays_environ) + var/channel = 0 + for(var/list/channel_leds in channel_overlays) + channel_leds[POWERCHAN_OFF + 1] = overlay_image(icon,"apco[channel]",COLOR_RED) + channel_leds[POWERCHAN_OFF_TEMP + 1] = overlay_image(icon,"apco[channel]",COLOR_ORANGE) + channel_leds[POWERCHAN_OFF_AUTO + 1] = overlay_image(icon,"apco[channel]",COLOR_ORANGE) + channel_leds[POWERCHAN_ON + 1] = overlay_image(icon,"apco[channel]",COLOR_LIME) + channel_leds[POWERCHAN_ON_AUTO + 1] = overlay_image(icon,"apco[channel]",COLOR_BLUE) + channel++ + + var/update = check_updates() //returns 0 if no need to update icons. + // 1 if we need to update the icon_state + // 2 if we need to update the overlays + + if(!update) + return + + if(update & 1) // Updating the icon state + if(update_state & UPDATE_ALLGOOD) + icon_state = "apc0" + else if(update_state & (UPDATE_OPENED1|UPDATE_OPENED2)) + var/basestate = "apc[ get_cell(FALSE) ? "2" : "1" ]" + if(update_state & UPDATE_OPENED1) + if(update_state & (UPDATE_MAINT|UPDATE_BROKE)) + icon_state = "apcmaint" //disabled APC cannot hold cell + else + icon_state = basestate + else if(update_state & UPDATE_OPENED2) + icon_state = "[basestate]-nocover" + else if(update_state & UPDATE_BROKE) + icon_state = "apc-b" + else if(update_state & UPDATE_BLUESCREEN) + icon_state = "apcemag" + else if(update_state & UPDATE_WIREEXP) + icon_state = "apcewires" + + if(!(update_state & UPDATE_ALLGOOD)) + if(overlays.len) + overlays.Cut() + return + + if(update & 2) + if(overlays.len) + overlays.Cut() + if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) + overlays += status_overlays_lock[locked+1] + if(!(stat & NOSCREEN)) + overlays += status_overlays_charging[charging+1] + if(operating) + overlays += status_overlays_equipment[equipment+1] + overlays += status_overlays_lighting[lighting+1] + overlays += status_overlays_environ[environ+1] + + if(update & 3) + if((update_state & (UPDATE_OPENED1|UPDATE_OPENED2|UPDATE_BROKE)) || (stat & NOSCREEN)) + set_light(0) + else if(update_state & UPDATE_BLUESCREEN) + set_light(l_range = 2, l_power = 0.5, l_color = "#00ecff") + else if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) + var/color + switch(charging) + if(0) + color = "#f86060" + if(1) + color = "#a8b0f8" + if(2) + color = "#82ff4c" + set_light(l_range = 2, l_power = 0.5, l_color = color) + else + set_light(0) + +/obj/machinery/apc/proc/check_updates() + if(!update_overlay_chan) + update_overlay_chan = new/list() + var/last_update_state = update_state + var/last_update_overlay = update_overlay + var/list/last_update_overlay_chan = update_overlay_chan.Copy() + update_state = 0 + update_overlay = 0 + if(get_cell(FALSE)) + update_state |= UPDATE_CELL_IN + if(stat & BROKEN) + update_state |= UPDATE_BROKE + if(stat & MAINT) + update_state |= UPDATE_MAINT + if(panel_open) + if(!cover_removed) + update_state |= UPDATE_OPENED1 + else + update_state |= UPDATE_OPENED2 + else if(emagged || (hacker && !hacker.hacked_apcs_hidden) || failure_timer) + update_state |= UPDATE_BLUESCREEN + else if(istype(construct_state, /decl/machine_construction/wall_frame/panel_closed/hackable/hacking)) + update_state |= UPDATE_WIREEXP + if(update_state <= 1) + update_state |= UPDATE_ALLGOOD + + if(operating) + update_overlay |= UPOVERLAY_OPERATING + + if(update_state & UPDATE_ALLGOOD) + if(locked) + update_overlay |= UPOVERLAY_LOCKED + + if(!charging) + update_overlay |= UPOVERLAY_CHARGEING0 + else if(charging == 1) + update_overlay |= UPOVERLAY_CHARGEING1 + else if(charging == 2) + update_overlay |= UPOVERLAY_CHARGEING2 + + + update_overlay_chan["Equipment"] = equipment + update_overlay_chan["Lighting"] = lighting + update_overlay_chan["Enviroment"] = environ + + + var/results = 0 + if(last_update_state == update_state && last_update_overlay == update_overlay && last_update_overlay_chan == update_overlay_chan) + return 0 + if(last_update_state != update_state) + results += 1 + if(last_update_overlay != update_overlay || last_update_overlay_chan != update_overlay_chan) + results += 2 + return results + +/obj/machinery/apc/set_broken(new_state, cause) + . = ..() + if(. && (stat & BROKEN)) + operating = 0 + update() + +/obj/machinery/apc/cannot_transition_to(state_path, mob/user) + if(ispath(state_path, /decl/machine_construction/wall_frame/panel_open)) + for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) + if(lock.locked) + return SPAN_WARNING("You cannot open the cover: it is locked!") + if(ispath(state_path, /decl/machine_construction/wall_frame/panel_closed) && cover_removed) + return SPAN_WARNING("You cannot close the cover: it was completely removed!") + . = ..() + +/obj/machinery/apc/proc/force_open_panel(mob/user) + var/decl/machine_construction/wall_frame/panel_closed/closed_state = construct_state + if(!istype(closed_state)) + return MCS_CONTINUE + var/list/locks = get_all_components_of_type(/obj/item/stock_parts/access_lock) + for(var/obj/item/stock_parts/access_lock/lock in locks) + lock.locked = FALSE + . = closed_state.try_change_state(src, closed_state.open_state, user) + if(. != MCS_CHANGE) + return + panel_open = TRUE + queue_icon_update() + +/obj/machinery/apc/attackby(obj/item/used_item, mob/user) + if (istype(construct_state, /decl/machine_construction/wall_frame/panel_closed/hackable/hacking) && (IS_MULTITOOL(used_item) || IS_WIRECUTTER(used_item) || istype(used_item, /obj/item/assembly/signaler))) + wires.Interact(user) + return TRUE + return ..() + +/obj/machinery/apc/bash(obj/item/used_item, mob/user) + if (!(user.check_intent(I_FLAG_HARM)) || (used_item.item_flags & ITEM_FLAG_NO_BLUDGEON)) + return FALSE + + if(!used_item.user_can_attack_with(user)) + return FALSE + + . = ..() + if(. && !panel_open && used_item.w_class >= ITEM_SIZE_NORMAL) + if (((stat & BROKEN) || (hacker && !hacker.hacked_apcs_hidden)) && prob(20)) + playsound(get_turf(src), 'sound/weapons/smash.ogg', 75, TRUE) + if(force_open_panel(user) == MCS_CHANGE) + cover_removed = TRUE + user.visible_message( + SPAN_DANGER("\The [user] knocks open the APC cover with \the [used_item]!"), + SPAN_DANGER("You knock down the APC cover with your [used_item.name]!"), + "You hear a bang." + ) + +// attack with hand - remove cell (if cover open) or interact with the APC + +/obj/machinery/apc/emag_act(var/remaining_charges, var/mob/user) + if (!(emagged || (hacker && !hacker.hacked_apcs_hidden))) // trying to unlock with an emag card + if(panel_open) + to_chat(user, "You must close the cover to swipe an ID card.") + else if(stat & (BROKEN|MAINT)) + to_chat(user, "Nothing happens.") + else + flick("apc-spark", src) + if (do_after(user,6,src)) + if(prob(50)) + emagged = 1 + req_access.Cut() + locked = 0 + to_chat(user, "You emag the APC interface.") + update_icon() + else if(prob(50)) + return max(..(), 1) // might unlock the panel lock instead. + else + to_chat(user, "You fail to [ locked ? "unlock" : "lock"] the APC interface.") + return 1 + +/obj/machinery/apc/CanUseTopicPhysical(var/mob/user) + return global.physical_topic_state.can_use_topic(nano_host(), user) + +/obj/machinery/apc/physical_attack_hand(mob/user) + //Human mob special interaction goes here. + if(user.can_shred()) + user.visible_message( + SPAN_DANGER("\The [user] slashes at \the [src]!"), + SPAN_DANGER("You slash at \the [src]!") + ) + playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) + var/allcut = wires.IsAllCut() + if(beenhit >= pick(3, 4) && allcut == 0) + wires.CutAll() + update_icon() + visible_message(SPAN_DANGER("\The [src]'s wires are shredded!")) + else + beenhit += 1 + return TRUE + return FALSE + +/obj/machinery/apc/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!user) + return + var/obj/item/cell/cell = get_cell() + var/coverlocked = FALSE + for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) + if(lock.locked) + coverlocked = TRUE + break + + var/list/data = list( + "pChan_Off" = POWERCHAN_OFF, + "pChan_Off_T" = POWERCHAN_OFF_TEMP, + "pChan_Off_A" = POWERCHAN_OFF_AUTO, + "pChan_On" = POWERCHAN_ON, + "pChan_On_A" = POWERCHAN_ON_AUTO, + "locked" = locked, + "isOperating" = operating, + "externalPower" = main_status, + "powerCellStatus" = cell ? cell.percent() : null, + "chargeMode" = chargemode, + "chargingStatus" = charging, + "totalLoad" = round(lastused_total), + "totalCharging" = round(lastused_charging), + "coverLocked" = coverlocked, + "failTime" = failure_timer * 2, + "siliconUser" = issilicon(user), + "remote_control" = remote_control, + "powerChannels" = list( + list( + "title" = "Equipment", + "powerLoad" = lastused_equip, + "status" = equipment, + "topicParams" = list( + "auto" = list("eqp" = 2), + "on" = list("eqp" = 1), + "off" = list("eqp" = 0) + ) + ), + list( + "title" = "Lighting", + "powerLoad" = round(lastused_light), + "status" = lighting, + "topicParams" = list( + "auto" = list("lgt" = 2), + "on" = list("lgt" = 1), + "off" = list("lgt" = 0) + ) + ), + list( + "title" = "Environment", + "powerLoad" = round(lastused_environ), + "status" = environ, + "topicParams" = list( + "auto" = list("env" = 2), + "on" = list("env" = 1), + "off" = list("env" = 0) + ) + ) + ) + ) + + // update the ui if it exists, returns null if no ui is passed/found + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "apc.tmpl", "[area? area.proper_name : "ERROR"] - APC", 520, data["siliconUser"] ? 465 : 440) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/obj/machinery/apc/proc/update() + var/old_power_light = area.power_light + var/old_power_environ = area.power_environ + var/old_power_equip = area.power_equip + if(operating && !shorted && !failure_timer) + + area.power_light = (lighting >= POWERCHAN_ON) + area.power_equip = (equipment >= POWERCHAN_ON) + area.power_environ = (environ >= POWERCHAN_ON) + + //prevent unnecessary updates to emergency lighting + if(area.power_light != old_power_light) + area.set_emergency_lighting(lighting == POWERCHAN_OFF_AUTO) //if lights go auto-off, emergency lights go on + else + area.power_light = 0 + area.power_equip = 0 + area.power_environ = 0 + + if(area.power_light != old_power_light || area.power_environ != old_power_environ || area.power_equip != old_power_equip) + area.power_change() + + var/obj/item/cell/cell = get_cell() + if(!powered_down) + if(!cell || cell.charge <= 0) + playsound(src, 'sound/machines/apc_nopower.ogg', 75, 0) + powered_down = TRUE + + else if(cell?.charge > 0) + powered_down = FALSE + +/obj/machinery/apc/CanUseTopic(mob/user, datum/topic_state/state) + if(user.current_posture.prone) + to_chat(user, "You must stand to use [src]!") + return STATUS_CLOSE + if(issilicon(user)) + var/permit = 0 // Malfunction variable. If AI hacks APC it can control it even without AI control wire. + var/mob/living/silicon/ai/AI = user + var/mob/living/silicon/robot/robot = user + if(hacker && !hacker.hacked_apcs_hidden) + if(hacker == AI) + permit = 1 + else if(istype(robot) && robot.connected_ai && robot.connected_ai == hacker) // Cyborgs can use APCs hacked by their AI + permit = 1 + + if(aidisabled && !permit) + return STATUS_CLOSE + . = ..() + if(user.restrained()) + to_chat(user, "You must have free hands to use [src].") + . = min(., STATUS_UPDATE) + +/obj/machinery/apc/OnTopic(mob/user, list/href_list, state) + if(href_list["reboot"] ) + failure_timer = 0 + update_icon() + update() + return TOPIC_REFRESH + + if(href_list["toggleaccess"]) + if(emagged || (stat & (BROKEN|MAINT)) || (hacker && !hacker.hacked_apcs_hidden)) + to_chat(user, "The APC does not respond to the command.") + else + locked = !locked + update_icon() + return TOPIC_REFRESH + + if(locked) + return TOPIC_REFRESH + + if(href_list["lock"]) + var/coverlocked = FALSE + var/list/locks = get_all_components_of_type(/obj/item/stock_parts/access_lock) + for(var/obj/item/stock_parts/access_lock/lock in locks) + if(lock.locked) + coverlocked = TRUE + break + for(var/obj/item/stock_parts/access_lock/lock in locks) + lock.locked = !coverlocked + return TOPIC_REFRESH + + if(href_list["breaker"]) + toggle_breaker() + return TOPIC_REFRESH + + if(href_list["cmode"]) + set_chargemode(!chargemode) + if(!chargemode) + charging = 0 + update_icon() + return TOPIC_REFRESH + + if(href_list["eqp"]) + var/val = text2num(href_list["eqp"]) + equipment = setsubsystem(val) + force_update_channels() + return TOPIC_REFRESH + + if(href_list["lgt"]) + var/val = text2num(href_list["lgt"]) + lighting = setsubsystem(val) + force_update_channels() + return TOPIC_REFRESH + + if(href_list["env"]) + var/val = text2num(href_list["env"]) + environ = setsubsystem(val) + force_update_channels() + return TOPIC_REFRESH + + if(href_list["overload"]) + if(issilicon(user)) + overload_lighting() + return TOPIC_REFRESH + + if(href_list["toggle_rc"]) + remote_control = !remote_control + return TOPIC_REFRESH + +/obj/machinery/apc/proc/force_update_channels() + autoflag = -1 // This clears state, forcing a full recalculation + update_channels(TRUE) + update() + queue_icon_update() + +/obj/machinery/apc/proc/toggle_breaker() + operating = !operating + force_update_channels() + +/obj/machinery/apc/get_power_usage() + if(autoflag) + return lastused_total // If not, we need to do something more sophisticated: compute how much power we would need in order to come back online. + . = 0 + if(!area) + return + if(autoset(lighting, 2) >= POWERCHAN_ON) + . += area.usage(LIGHT) + if(autoset(equipment, 2) >= POWERCHAN_ON) + . += area.usage(EQUIP) + if(autoset(environ, 1) >= POWERCHAN_ON) + . += area.usage(ENVIRON) + +/obj/machinery/apc/Process() + if(!area?.requires_power) + return PROCESS_KILL + + if(stat & (BROKEN|MAINT)) + return + + if(failure_timer) + update() + queue_icon_update() + failure_timer-- + force_update = 1 + return + + lastused_light = (lighting >= POWERCHAN_ON) ? area.usage(LIGHT) : 0 + lastused_equip = (equipment >= POWERCHAN_ON) ? area.usage(EQUIP) : 0 + lastused_environ = (environ >= POWERCHAN_ON) ? area.usage(ENVIRON) : 0 + area.clear_usage() + + lastused_total = lastused_light + lastused_equip + lastused_environ + + //store states to update icon if any change + var/last_lt = lighting + var/last_eq = equipment + var/last_en = environ + var/last_ch = charging + + var/obj/machinery/power/terminal/terminal = terminal(TRUE) + var/avail = (terminal && terminal.avail()) || 0 + var/excess = (terminal && terminal.surplus()) || 0 + + if(!avail) + main_status = 0 + else if(excess < 0) + main_status = 1 + else + main_status = 2 + + var/obj/item/cell/cell = get_cell() + if(!cell || shorted) // We aren't going to be doing any power processing in this case. + charging = 0 + else + //update state + var/obj/item/stock_parts/power/battery/power = get_component_of_type(/obj/item/stock_parts/power/battery) + lastused_charging = max(power && power.cell && (power.cell.charge - power.last_cell_charge) * CELLRATE, 0) + charging = lastused_charging ? 1 : 0 + if(cell.fully_charged()) + charging = 2 + + if(stat & NOPOWER) + power_change() // We are the ones responsible for triggering listeners once power returns, so we run this to detect possible changes. + + // Set channels depending on how much charge we have left + update_channels() + + // update icon & area power if anything changed + if(last_lt != lighting || last_eq != equipment || last_en != environ || force_update) + force_update = 0 + queue_icon_update() + update() + else if (last_ch != charging) + queue_icon_update() + +/obj/machinery/apc/proc/update_channels(suppress_alarms = FALSE) + // Allow the APC to operate as normal if the cell can charge + if(charging && longtermpower < 10) + longtermpower += 1 + else if(longtermpower > -10) + longtermpower -= 2 + var/obj/item/cell/cell = get_cell() + var/percent = cell && cell.percent() + + if(!cell || shorted || (stat & NOPOWER) || !operating) + if(autoflag != 0) + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + if(!suppress_alarms) + power_alarm.triggerAlarm(loc, src) + autoflag = 0 + else if((percent > AUTO_THRESHOLD_LIGHTING) || longtermpower >= 0) // Put most likely at the top so we don't check it last, effeciency 101 + if(autoflag != 3) + equipment = autoset(equipment, 1) + lighting = autoset(lighting, 1) + environ = autoset(environ, 1) + autoflag = 3 + power_alarm.clearAlarm(loc, src) + else if((percent <= AUTO_THRESHOLD_LIGHTING) && (percent > AUTO_THRESHOLD_EQUIPMENT) && longtermpower < 0) // <50%, turn off lighting + if(autoflag != 2) + equipment = autoset(equipment, 1) + lighting = autoset(lighting, 2) + environ = autoset(environ, 1) + if(!suppress_alarms) + power_alarm.triggerAlarm(loc, src) + autoflag = 2 + else if(percent <= AUTO_THRESHOLD_EQUIPMENT) // <25%, turn off lighting & equipment + if(autoflag != 1) + equipment = autoset(equipment, 2) + lighting = autoset(lighting, 2) + environ = autoset(environ, 1) + if(!suppress_alarms) + power_alarm.triggerAlarm(loc, src) + autoflag = 1 + +// val 0=off, 1=off(auto) 2=on 3=on(auto) +// on 0=off, 1=on, 2=autooff +// defines a state machine, returns the new state +/obj/machinery/apc/proc/autoset(var/cur_state, var/on) + //autoset will never turn on a channel set to off + switch(cur_state) + if(POWERCHAN_OFF_TEMP) + if(on == 1 || on == 2) + return POWERCHAN_ON + if(POWERCHAN_OFF_AUTO) + if(on == 1) + return POWERCHAN_ON_AUTO + if(POWERCHAN_ON) + if(on == 0) + return POWERCHAN_OFF_TEMP + if(POWERCHAN_ON_AUTO) + if(on == 0 || on == 2) + return POWERCHAN_OFF_AUTO + + return cur_state //leave unchanged + + +// damage and destruction acts +/obj/machinery/apc/emp_act(severity) + if(emp_hardened) + return + // Fail for 8-12 minutes (divided by severity) + // Division by 2 is required, because machinery ticks are every two seconds. Without it we would fail for 16-24 minutes. + if(is_critical) + // Critical APCs are considered EMP shielded and will be offline only for about half minute. Prevents AIs being one-shot disabled by EMP strike. + // Critical APCs are also more resilient to cell corruption/power drain. + energy_fail(rand(240, 360) / severity / CRITICAL_EMP_PROTECTION) + else + // Regular APCs fail for normal time. + energy_fail(rand(240, 360) / severity) + queue_icon_update() + ..() + +/obj/machinery/apc/on_component_failure(obj/item/stock_parts/component) + var/was_broken = stat & BROKEN + . = ..() + if(!was_broken && (stat & BROKEN)) + visible_message("[src]'s screen flickers with warnings briefly!") + power_alarm.triggerAlarm(loc, src) + spawn(rand(2,5)) + operating = 0 + update() + +/obj/machinery/apc/proc/set_chargemode(new_mode) + chargemode = new_mode + var/obj/item/stock_parts/power/battery/power = get_component_of_type(/obj/item/stock_parts/power/battery) + if(power) + power.can_charge = chargemode + power.charge_wait_counter = initial(power.charge_wait_counter) + +/obj/machinery/apc/proc/change_area_name(var/area/A, var/old_area_name, var/new_area_name) + if(A != area || !autoname) + return + SetName("[A.proper_name] APC") + +// overload the lights in this APC area +/obj/machinery/apc/proc/overload_lighting(var/chance = 100) + if(/* !get_connection() || */ !operating || shorted) + return + var/amount = use_power_oneoff(20, LOCAL) + if(amount <= 0) + spawn(0) + for(var/obj/machinery/light/L in area) + if(prob(chance)) + L.on = 1 + L.broken() + sleep(1) + +/obj/machinery/apc/proc/setsubsystem(val) + switch(val) + if(2) + return POWERCHAN_OFF_AUTO + if(1) + return POWERCHAN_OFF_TEMP + else + return POWERCHAN_OFF +/obj/machinery/apc/proc/set_channel_state_manual(var/channel, var/state) + switch(channel) + if(APC_POWERCHAN_EQUIPMENT) + equipment = state + if(APC_POWERCHAN_LIGHTING) + lighting = state + if(APC_POWERCHAN_ENVIRONMENT) + environ = state + force_update_channels() + +/obj/machinery/apc/area_changed(area/old_area, area/new_area) + . = ..() + if(QDELETED(src)) + return + if(. && !areastring) // if areastring is there, we do not update our area as we are supposed to be operating in some kind of "remote" mode + reset_area(old_area, new_area) + // Attempting the most aggressive recalculation available here; unclear if this is "correct." + force_update_channels() + power_change() + //Make sure to resume processing if our area changed to something else than null + if(area && !(processing_flags & MACHINERY_PROCESS_SELF)) + START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + +/obj/machinery/apc/unlocked + initial_access = list() + req_access = list() + +/obj/machinery/apc/unlocked/Initialize(mapload, ndir, populate_parts) + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/apc/unlocked/LateInitialize() + . = ..() + for(var/obj/item/stock_parts/access_lock/lock in get_all_components_of_type(/obj/item/stock_parts/access_lock)) + lock.locked = FALSE diff --git a/code/modules/power/apc/apc_frame.dm b/code/modules/power/apc/apc_frame.dm new file mode 100644 index 000000000000..7241115768a1 --- /dev/null +++ b/code/modules/power/apc/apc_frame.dm @@ -0,0 +1,30 @@ +// APC HULL + +/obj/item/frame/apc + name = "\improper APC frame" + desc = "Used for repairing or building APCs." + icon = 'icons/obj/apc_repair.dmi' + icon_state = "apc_frame" + obj_flags = OBJ_FLAG_CONDUCTIBLE + build_machine_type = /obj/machinery/apc/buildable + reverse = TRUE + +/obj/item/frame/apc/try_build(turf/on_wall) + var/area/A = get_area(src) + if (A.requires_power == 0 || A.always_unpowered) + to_chat(usr, SPAN_WARNING("An APC cannot be placed in this area.")) + return + if (A.get_apc()) + to_chat(usr, SPAN_WARNING("This area already has an APC.")) + return //only one APC per area + for(var/obj/machinery/power/terminal/T in loc) + if (T.master) + to_chat(usr, SPAN_WARNING("There is another network terminal here.")) + return + return ..() + +/obj/item/frame/apc/kit + fully_construct = TRUE + name = "APC kit" + desc = "An all-in-one APC kit, comes preassembled." + build_machine_type = /obj/machinery/apc \ No newline at end of file diff --git a/code/modules/power/apc/apc_presets.dm b/code/modules/power/apc/apc_presets.dm new file mode 100644 index 000000000000..62648417633b --- /dev/null +++ b/code/modules/power/apc/apc_presets.dm @@ -0,0 +1,47 @@ +// Various APC types +/obj/machinery/apc/inactive + lighting = 0 + equipment = 0 + environ = 0 + locked = FALSE + +/obj/machinery/apc/critical + is_critical = 1 + +/obj/machinery/apc/high + uncreated_component_parts = list( + /obj/item/cell/high + ) + +/obj/machinery/apc/high/inactive + lighting = 0 + equipment = 0 + environ = 0 + locked = FALSE + +/obj/machinery/apc/super + uncreated_component_parts = list( + /obj/item/cell/super + ) + +/obj/machinery/apc/super/critical + is_critical = 1 + +/obj/machinery/apc/hyper + uncreated_component_parts = list( + /obj/item/cell/hyper + ) + +/obj/machinery/apc/derelict + lighting = 0 + equipment = 0 + environ = 0 + locked = 0 + uncreated_component_parts = list( + /obj/item/cell/crap/empty + ) + +/obj/machinery/apc/derelict/full + uncreated_component_parts = list( + /obj/item/cell/crap + ) \ No newline at end of file diff --git a/code/modules/power/apc/apc_wires.dm b/code/modules/power/apc/apc_wires.dm new file mode 100644 index 000000000000..6f6cb10deb75 --- /dev/null +++ b/code/modules/power/apc/apc_wires.dm @@ -0,0 +1,75 @@ +/datum/wires/apc + holder_type = /obj/machinery/apc + wire_count = 4 + descriptions = list( + new /datum/wire_description(APC_WIRE_IDSCAN, "This wire is connected to the ID scanning panel.", SKILL_EXPERT), + new /datum/wire_description(APC_WIRE_MAIN_POWER1, "This wire seems to be carrying a heavy current."), + new /datum/wire_description(APC_WIRE_MAIN_POWER2, "This wire seems to be carrying a heavy current."), + new /datum/wire_description(APC_WIRE_AI_CONTROL, "This wire connects to automated control systems.") + ) + var/const/APC_WIRE_IDSCAN = BITFLAG(0) + var/const/APC_WIRE_MAIN_POWER1 = BITFLAG(1) + var/const/APC_WIRE_MAIN_POWER2 = BITFLAG(2) + var/const/APC_WIRE_AI_CONTROL = BITFLAG(3) + +/datum/wires/apc/GetInteractWindow(mob/user) + var/obj/machinery/apc/A = holder + . += ..() + . += text("
    \n[(A.locked ? "The APC is locked." : "The APC is unlocked.")]
    \n[(A.shorted ? "The APCs power has been shorted." : "The APC is working properly!")]
    \n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]") + +/datum/wires/apc/CanUse(var/mob/living/L) + var/obj/machinery/apc/A = holder + if(istype(A.construct_state, /decl/machine_construction/wall_frame/panel_closed/hackable/hacking) && !(A.stat & BROKEN)) + return TRUE + return FALSE + +/datum/wires/apc/proc/reset_locked() + var/obj/machinery/apc/A = holder + if(A) + A.locked = TRUE + +/datum/wires/apc/proc/reset_shorted() + var/obj/machinery/apc/A = holder + if(A && !IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2)) + A.shorted = FALSE + +/datum/wires/apc/proc/reset_ai_disabled() + var/obj/machinery/apc/A = holder + if(A && !IsIndexCut(APC_WIRE_AI_CONTROL)) + A.aidisabled = FALSE + +/datum/wires/apc/UpdatePulsed(var/index) + + var/obj/machinery/apc/A = holder + + switch(index) + + if(APC_WIRE_IDSCAN) + A.locked = FALSE + addtimer(CALLBACK(src, PROC_REF(reset_locked)), 30 SECONDS) + + if (APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2) + if(!A.shorted) + A.shorted = TRUE + addtimer(CALLBACK(src, PROC_REF(reset_shorted)), 2 MINUTES) + + if (APC_WIRE_AI_CONTROL) + if (!A.aidisabled) + A.aidisabled = TRUE + addtimer(CALLBACK(src, PROC_REF(reset_ai_disabled)), 1 SECOND) + +/datum/wires/apc/UpdateCut(var/index, var/mended) + var/obj/machinery/apc/A = holder + + switch(index) + if(APC_WIRE_MAIN_POWER1, APC_WIRE_MAIN_POWER2) + if(!mended) + A.shock(usr, 50) + A.shorted = TRUE + + else if(!IsIndexCut(APC_WIRE_MAIN_POWER1) && !IsIndexCut(APC_WIRE_MAIN_POWER2)) + A.shorted = FALSE + A.shock(usr, 50) + + if(APC_WIRE_AI_CONTROL) + A.aidisabled = !mended \ No newline at end of file diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm index 15a77abeb3c6..144d6f5b2703 100644 --- a/code/modules/power/batteryrack.dm +++ b/code/modules/power/batteryrack.dm @@ -22,13 +22,12 @@ var/mode = PSU_OFFLINE // Current inputting/outputting mode var/list/internal_cells = list() // Cells stored in this PSU var/max_cells = 3 // Maximal amount of stored cells at once. Capped at 9. - var/previous_charge = 0 // Charge previous tick. var/equalise = 0 // If true try to equalise charge between cells var/icon_update = 0 // Timer in ticks for icon update. var/ui_tick = 0 /obj/machinery/power/smes/batteryrack/RefreshParts() - var/capacitor_efficiency = Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) + var/capacitor_efficiency = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) var/maxcells = 3 * total_component_rating_of_type(/obj/item/stock_parts/matter_bin) max_transfer_rate = 10000 * capacitor_efficiency // 30kw - 90kw depending on used capacitors. @@ -38,8 +37,8 @@ ..() /obj/machinery/power/smes/batteryrack/Destroy() - for(var/obj/item/cell/C in internal_cells) - qdel(C) + for(var/obj/item/cell/cell in internal_cells) + qdel(cell) internal_cells = null return ..() @@ -48,27 +47,27 @@ icon_update = 0 var/cellcount = 0 - var/charge_level = between(0, round(Percentage() / 12), 7) + var/charge_level = clamp(round(Percentage() / 12), 0, 7) overlays += "charge[charge_level]" - for(var/obj/item/cell/C in internal_cells) + for(var/obj/item/cell/cell in internal_cells) cellcount++ overlays += "cell[cellcount]" - if(C.fully_charged()) + if(cell.fully_charged()) overlays += "cell[cellcount]f" - else if(!C.charge) + else if(!cell.charge) overlays += "cell[cellcount]e" // Recalculate maxcharge and similar variables. /obj/machinery/power/smes/batteryrack/proc/update_maxcharge() var/newmaxcharge = 0 - for(var/obj/item/cell/C in internal_cells) - newmaxcharge += C.maxcharge + for(var/obj/item/cell/cell in internal_cells) + newmaxcharge += cell.maxcharge capacity = newmaxcharge - charge = between(0, charge, newmaxcharge) + charge = clamp(charge, 0, newmaxcharge) // Sets input/output depending on our "mode" var. @@ -100,8 +99,8 @@ if(!amount) return // We're still here, so it means the least charged cell was full OR we don't care about equalising the charge. Give power to other cells instead. - for(var/obj/item/cell/C in internal_cells) - amount -= C.give(amount) + for(var/obj/item/cell/cell in internal_cells) + amount -= cell.give(amount) // No more power to input so return. if(!amount) return @@ -116,8 +115,8 @@ if(!amount) return // We're still here, so it means the most charged cell didn't have enough power OR we don't care about equalising the charge. Use power from other cells instead. - for(var/obj/item/cell/C in internal_cells) - amount -= C.use(amount) + for(var/obj/item/cell/cell in internal_cells) + amount -= cell.use(amount) // No more power to output so return. if(!amount) return @@ -125,31 +124,31 @@ // Helper procs to get most/least charged cells. /obj/machinery/power/smes/batteryrack/proc/get_most_charged_cell() var/obj/item/cell/CL = null - for(var/obj/item/cell/C in internal_cells) + for(var/obj/item/cell/cell in internal_cells) if(CL == null) - CL = C - else if(CL.percent() < C.percent()) - CL = C + CL = cell + else if(CL.percent() < cell.percent()) + CL = cell return CL /obj/machinery/power/smes/batteryrack/proc/get_least_charged_cell() var/obj/item/cell/CL = null - for(var/obj/item/cell/C in internal_cells) + for(var/obj/item/cell/cell in internal_cells) if(CL == null) - CL = C - else if(CL.percent() > C.percent()) - CL = C + CL = cell + else if(CL.percent() > cell.percent()) + CL = cell return CL -/obj/machinery/power/smes/batteryrack/proc/insert_cell(var/obj/item/cell/C, var/mob/user) - if(!istype(C)) +/obj/machinery/power/smes/batteryrack/proc/insert_cell(var/obj/item/cell/cell, var/mob/user) + if(!istype(cell)) return 0 if(internal_cells.len >= max_cells) return 0 - if(user && !user.unEquip(C)) + if(user && !user.try_unequip(cell)) return 0 - internal_cells.Add(C) - C.forceMove(src) + internal_cells.Add(cell) + cell.forceMove(src) RefreshParts() update_maxcharge() update_icon() @@ -158,8 +157,8 @@ /obj/machinery/power/smes/batteryrack/Process() charge = 0 - for(var/obj/item/cell/C in internal_cells) - charge += C.charge + for(var/obj/item/cell/cell in internal_cells) + charge += cell.charge ..() ui_tick = !ui_tick @@ -183,7 +182,7 @@ celldiff = (least.maxcharge / 100) * percentdiff else celldiff = (most.maxcharge / 100) * percentdiff - celldiff = between(0, celldiff, max_transfer_rate * CELLRATE) + celldiff = clamp(celldiff, 0, max_transfer_rate * CELLRATE) // Ensure we don't transfer more energy than the most charged cell has, and that the least charged cell can input. celldiff = min(min(celldiff, most.charge), least.maxcharge - least.charge) least.give(most.use(celldiff)) @@ -201,19 +200,19 @@ data["cells_cur"] = internal_cells.len var/list/cells = list() var/cell_index = 1 - for(var/obj/item/cell/C in internal_cells) - var/list/cell[0] - cell["slot"] = cell_index - cell["used"] = 1 - cell["percentage"] = round(C.percent(), 0.01) + for(var/obj/item/cell/cell in internal_cells) + var/list/cell_data = list() + cell_data["slot"] = cell_index + cell_data["used"] = 1 + cell_data["percentage"] = round(cell.percent(), 0.01) cell_index++ - cells += list(cell) + cells += list(cell_data) while(cell_index <= PSU_MAXCELLS) - var/list/cell[0] - cell["slot"] = cell_index - cell["used"] = 0 + var/list/cell_data = list() + cell_data["slot"] = cell_index + cell_data["used"] = 0 cell_index++ - cells += list(cell) + cells += list(cell_data) data["cells_list"] = cells ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -224,19 +223,21 @@ ui.set_auto_update(1) /obj/machinery/power/smes/batteryrack/dismantle() - for(var/obj/item/cell/C in internal_cells) - C.dropInto(loc) - internal_cells -= C + for(var/obj/item/cell/cell in internal_cells) + cell.dropInto(loc) + internal_cells -= cell return ..() -/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/W, var/mob/user) - if(..()) - return TRUE - if(istype(W, /obj/item/cell)) // ID Card, try to insert it. - if(insert_cell(W, user)) - to_chat(user, "You insert \the [W] into \the [src].") +/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/used_item, var/mob/user) + . = ..() + if(.) + return + if(istype(used_item, /obj/item/cell)) // ID Card, try to insert it. + if(insert_cell(used_item, user)) + to_chat(user, "You insert \the [used_item] into \the [src].") else - to_chat(user, "\The [src] has no empty slot for \the [W]") + to_chat(user, "\The [src] has no empty slot for \the [used_item].") + return TRUE /obj/machinery/power/smes/batteryrack/interface_interact(var/mob/user) ui_interact(user) @@ -248,36 +249,34 @@ /obj/machinery/power/smes/batteryrack/outputting() return -/obj/machinery/power/smes/batteryrack/Topic(href, href_list) +/obj/machinery/power/smes/batteryrack/OnTopic(mob/user, href_list) // ..() would respond to those topic calls, but we don't want to use them at all. // Calls to these shouldn't occur anyway, due to usage of different nanoUI, but // it's here in case someone decides to try hrefhacking/modified templates. if(href_list["input"] || href_list["output"]) - return 1 - - if(..()) - return 1 + return TOPIC_HANDLED + if((. = ..())) + return if( href_list["disable"] ) update_io(0) - return 1 + return TOPIC_REFRESH else if( href_list["enable"] ) - update_io(between(1, text2num(href_list["enable"]), 3)) - return 1 + update_io(clamp(text2num(href_list["enable"]), 1, 3)) + return TOPIC_REFRESH else if( href_list["equaliseon"] ) equalise = 1 - return 1 + return TOPIC_REFRESH else if( href_list["equaliseoff"] ) equalise = 0 - return 1 + return TOPIC_REFRESH else if( href_list["ejectcell"] ) var/slot_number = text2num(href_list["ejectcell"]) - if(slot_number != Clamp(round(slot_number), 1, length(internal_cells))) - return 1 - var/obj/item/cell/C = internal_cells[slot_number] + if(slot_number != clamp(round(slot_number), 1, length(internal_cells))) + return TOPIC_HANDLED + var/obj/item/cell/cell = internal_cells[slot_number] - C.dropInto(loc) - internal_cells -= C - update_icon() + cell.dropInto(loc) + internal_cells -= cell RefreshParts() update_maxcharge() - return 1 \ No newline at end of file + return TOPIC_REFRESH \ No newline at end of file diff --git a/code/modules/power/breaker_box.dm b/code/modules/power/breaker_box.dm index 3da34bc43a06..2cd7d48af023 100644 --- a/code/modules/power/breaker_box.dm +++ b/code/modules/power/breaker_box.dm @@ -1,106 +1,100 @@ // Updated version of old powerswitch by Atlantis // Has better texture, and is now considered electronic device -// AI has ability to toggle it in 5 seconds -// Humans need 30 seconds (AI is faster when it comes to complex electronics) +// Requires 5 seconds to toggle and can be toggled once a minute // Used for advanced grid control (read: Substations) /obj/machinery/power/breakerbox - name = "Breaker Box" + name = "breaker box" icon = 'icons/obj/power.dmi' icon_state = "bbox_off" - //directwired = 0 - var/icon_state_on = "bbox_on" - var/icon_state_off = "bbox_off" - density = 1 - anchored = 1 - var/on = 0 - var/busy = 0 - var/directions = list(1,2,4,8,5,6,9,10) - var/RCon_tag = "NO_TAG" - var/update_locked = 0 - + desc = "A large machine with heavy-duty switching circuits used for advanced grid control." + density = TRUE + anchored = TRUE construct_state = /decl/machine_construction/default/panel_closed stat_immune = 0 uncreated_component_parts = null base_type = /obj/machinery/power/breakerbox + var/icon_state_on = "bbox_on" + var/icon_state_off = "bbox_off" + var/on = FALSE + var/busy = FALSE + var/RCon_tag = "NO_TAG" + /// If world.time < lock_time, system is locked for interactions. + var/lock_time = 0 + /obj/machinery/power/breakerbox/activated - icon_state = "bbox_on" + icon_state = parent_type::icon_state_on // Enabled on server startup. Used in substations to keep them in bypass mode. /obj/machinery/power/breakerbox/activated/Initialize() - set_state(1) + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/power/breakerbox/activated/LateInitialize() + set_state(TRUE) . = ..() -/obj/machinery/power/breakerbox/examine(mob/user) +/obj/machinery/power/breakerbox/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "Large machine with heavy duty switching circuits used for advanced grid control") if(on) - to_chat(user, "It seems to be online.") + . += SPAN_GOOD("It seems to be online.") else - to_chat(user, "It seems to be offline.") - -/obj/machinery/power/breakerbox/attack_ai(mob/user) - if(update_locked) - to_chat(user, "System locked. Please try again later.") - return - - if(busy) - to_chat(user, "System is busy. Please wait until current operation is finished before changing power settings.") - return + . += SPAN_WARNING("It seems to be offline.") - busy = 1 - to_chat(user, "Updating power settings..") - if(do_after(user, 50, src)) - set_state(!on) - to_chat(user, "Update Completed. New setting:[on ? "on": "off"]") - update_locked = 1 - spawn(600) - update_locked = 0 - busy = 0 - -/obj/machinery/power/breakerbox/physical_attack_hand(mob/user) - if(update_locked) - to_chat(user, "System locked. Please try again later.") +/obj/machinery/power/breakerbox/proc/try_toggle_state(mob/living/user, digital = FALSE) + if(lock_time < world.time) + to_chat(user, SPAN_WARNING("System locked. Please try again later.")) return TRUE if(busy) - to_chat(user, "System is busy. Please wait until current operation is finished before changing power settings.") + to_chat(user, SPAN_WARNING("System is busy. Please wait until current operation is finished before changing power settings.")) return TRUE - busy = 1 - for(var/mob/O in viewers(user)) - O.show_message(text("\The [user] started reprogramming \the [src]!"), 1) - - if(do_after(user, 50,src)) + busy = TRUE + if(digital) + to_chat(user, SPAN_GOOD("Updating power settings...")) + else + user.visible_message(SPAN_NOTICE("\The [user] starts reprogramming \the [src]!")) + if(do_after(user, 5 SECONDS, src)) set_state(!on) - user.visible_message(\ - "[user.name] [on ? "enabled" : "disabled"] the breaker box!",\ - "You [on ? "enabled" : "disabled"] the breaker box!") - update_locked = 1 - spawn(600) - update_locked = 0 - busy = 0 + if(digital) + to_chat(user, SPAN_GOOD("Update completed. New setting:[on ? "on": "off"]")) + else + user.visible_message( + SPAN_NOTICE("\The [user] [on ? "enabled" : "disabled"] \the [src]!"),\ + SPAN_NOTICE("You [on ? "enabled" : "disabled"] \the [src]!")) + lock_time = world.time + 1 MINUTE + busy = FALSE return TRUE -/obj/machinery/power/breakerbox/attackby(var/obj/item/W, var/mob/user) - if(isMultitool(W)) +/obj/machinery/power/breakerbox/attack_ai(mob/living/silicon/ai/user) + return try_toggle_state(user, digital = TRUE) + +/obj/machinery/power/breakerbox/physical_attack_hand(mob/user) + return try_toggle_state(user, digital = FALSE) + +/obj/machinery/power/breakerbox/attackby(obj/item/used_item, mob/user) + if(IS_MULTITOOL(used_item)) var/newtag = input(user, "Enter new RCON tag. Use \"NO_TAG\" to disable RCON or leave empty to cancel.", "SMES RCON system") as text if(!CanPhysicallyInteract(user)) return TRUE if(newtag) RCon_tag = newtag - to_chat(user, "You changed the RCON tag to: [newtag]") + to_chat(user, SPAN_NOTICE("You changed the RCON tag to: [newtag]")) return TRUE - return ..() -/obj/machinery/power/breakerbox/proc/set_state(var/state) +/obj/machinery/power/breakerbox/on_update_icon() + . = ..() + icon_state = on ? icon_state_on : icon_state_off + +/obj/machinery/power/breakerbox/proc/set_state(state) on = state + update_icon() if(on) - icon_state = icon_state_on var/list/connection_dirs = list() - for(var/direction in directions) + for(var/direction in global.alldirs) for(var/obj/structure/cable/C in get_step(src,direction)) if(C.d1 == turn(direction, 180) || C.d2 == turn(direction, 180)) connection_dirs += direction @@ -110,7 +104,7 @@ var/obj/structure/cable/C = new/obj/structure/cable(src.loc) C.d1 = 0 C.d2 = direction - C.icon_state = "[C.d1]-[C.d2]" + C.update_icon() C.breaker_box = src var/datum/powernet/PN = new() @@ -119,18 +113,16 @@ C.mergeConnectedNetworks(C.d2) C.mergeConnectedNetworksOnTurf() - if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + if(!IS_POWER_OF_TWO(C.d2))// if the cable is layed diagonally, check the others 2 possible directions C.mergeDiagonalsNetworks(C.d2) else - icon_state = icon_state_off for(var/obj/structure/cable/C in src.loc) qdel(C) // Used by RCON to toggle the breaker box. /obj/machinery/power/breakerbox/proc/auto_toggle() - if(!update_locked) - set_state(!on) - update_locked = 1 - spawn(600) - update_locked = 0 \ No newline at end of file + if(lock_time > world.time) + return FALSE // still on cooldown + set_state(!on) + lock_time = world.time + 1 MINUTE diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 6615f29077d5..7067ecc7974b 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -22,23 +22,30 @@ If d1 = dir1 and d2 = dir2, it's a full X-X cable, getting from dir1 to dir2 By design, d1 is the smallest direction and d2 is the highest */ +/// Tracks all cable instances, so that powernets don't have to look through the entire world all the time +var/global/list/obj/structure/cable/all_cables = list() /obj/structure/cable - level = 1 - anchored =1 - var/datum/powernet/powernet name = "power cable" desc = "A flexible superconducting cable for heavy-duty power transfer." icon = 'icons/obj/power_cond_white.dmi' - icon_state = "0-1" - var/d1 = 0 - var/d2 = 1 - - layer = EXPOSED_WIRE_LAYER - - color = COLOR_MAROON + icon_state = "0-1" + layer = EXPOSED_WIRE_LAYER + color = COLOR_MAROON + paint_color = COLOR_MAROON + anchored = TRUE + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + level = LEVEL_BELOW_PLATING + + /// The base cable stack that should be produced, not including color. + /// cable_type::stack_merge_type should equal cable_type, ideally + var/cable_type = /obj/item/stack/cable_coil + /// Whether this cable type can be (re)colored. + var/can_have_color = TRUE + var/d1 + var/d2 + var/datum/powernet/powernet var/obj/machinery/power/breakerbox/breaker_box - /obj/structure/cable/drain_power(var/drain_check, var/surge, var/amount = 0) if(drain_check) @@ -51,50 +58,67 @@ By design, d1 is the smallest direction and d2 is the highest /obj/structure/cable/yellow color = COLOR_AMBER + paint_color = COLOR_AMBER /obj/structure/cable/green color = COLOR_GREEN + paint_color = COLOR_GREEN /obj/structure/cable/blue color = COLOR_CYAN_BLUE + paint_color = COLOR_CYAN_BLUE /obj/structure/cable/pink color = COLOR_PURPLE + paint_color = COLOR_PURPLE /obj/structure/cable/orange color = COLOR_ORANGE + paint_color = COLOR_ORANGE /obj/structure/cable/cyan color = COLOR_SKY_BLUE + paint_color = COLOR_SKY_BLUE /obj/structure/cable/white color = COLOR_SILVER + paint_color = COLOR_SILVER + +/obj/structure/cable/proc/canonize_cable_dirs() + // ensure d1 & d2 reflect the icon_state for entering and exiting cable + var/dir_components = splittext(icon_state, "-") + if(length(dir_components) < 2) + CRASH("Cable segment updating dirs with invalid icon_state: [d1], [d2]") + d1 = text2num(dir_components[1]) + d2 = text2num(dir_components[2]) + if(!(d1 in global.cabledirs) || !(d2 in global.cabledirs)) + CRASH("Cable segment updating dirs with invalid values: [d1], [d2]") /obj/structure/cable/Initialize(var/ml) - . = ..(ml) // ensure d1 & d2 reflect the icon_state for entering and exiting cable - var/dash = findtext(icon_state, "-") - d1 = text2num(copytext(icon_state, 1, dash)) - d2 = text2num(copytext(icon_state, dash+1)) + if(isnull(d1) || isnull(d2)) + canonize_cable_dirs() + . = ..(ml) var/turf/T = src.loc // hide if turf is not intact - if(level==1 && T) hide(!T.is_plating()) - cable_list += src //add it to the global cable list + if(level == LEVEL_BELOW_PLATING && T) + hide(!T.is_plating()) + global.all_cables += src //add it to the global cable list /obj/structure/cable/Destroy() // called when a cable is deleted if(powernet) cut_cable_from_powernet() // update the powernets - cable_list -= src // remove it from global cable list + global.all_cables -= src // remove it from global cable list . = ..() // then go ahead and delete the cable // Ghost examining the cable -> tells him the power /obj/structure/cable/attack_ghost(mob/user) if(user.client && user.client.inquisitive_ghost) - user.examinate(src) + user.examine_verb(src) // following code taken from attackby (multitool) if(powernet && (powernet.avail > 0)) - to_chat(user, "[get_wattage()] in power network.") + to_chat(user, SPAN_WARNING("[get_wattage()] in power network.")) else - to_chat(user, "The cable is not powered.") + to_chat(user, SPAN_WARNING("\The [src] is not powered.")) return /////////////////////////////////// @@ -102,15 +126,15 @@ By design, d1 is the smallest direction and d2 is the highest /////////////////////////////////// /obj/structure/cable/proc/get_wattage() - if(powernet.avail >= 1000000000) - return "[round(powernet.avail/1000000, 0.01)] MW" - if(powernet.avail >= 1000000) - return "[round(powernet.avail/1000, 0.01)] kW" + if(powernet.avail >= 1 GIGAWATTS) + return "[round(powernet.avail/(1 MEGAWATTS), 0.01)] MW" + if(powernet.avail >= 1 MEGAWATTS) + return "[round(powernet.avail/(1 KILOWATTS), 0.01)] kW" return "[round(powernet.avail)] W" //If underfloor, hide the cable /obj/structure/cable/hide(var/i) - if(istype(loc, /turf)) + if(isturf(loc)) set_invisibility(i ? 101 : 0) update_icon() @@ -118,9 +142,25 @@ By design, d1 is the smallest direction and d2 is the highest return 1 /obj/structure/cable/on_update_icon() + ..() + // this should be less necessary now but it might still be just in case a subtype calls update_icon() in Initialize prior to its parent call + // which... don't do that, but better safe than sorry. + if(isnull(d1) || isnull(d2)) + canonize_cable_dirs() icon_state = "[d1]-[d2]" alpha = invisibility ? 127 : 255 +/obj/structure/cable/shuttle_rotate(angle) + // DON'T CALL PARENT, we never change our actual dir + if(d1 == 0) + d2 = turn(d2, angle) + else + var/nd1 = min(turn(d1, angle), turn(d2, angle)) + var/nd2 = max(turn(d1, angle), turn(d2, angle)) + d1 = nd1 + d2 = nd2 + update_icon() + // returns the powernet this cable belongs to /obj/structure/cable/proc/get_powernet() //TODO: remove this as it is obsolete return powernet @@ -131,67 +171,67 @@ By design, d1 is the smallest direction and d2 is the highest // - Multitool : get the power currently passing through the cable // -/obj/structure/cable/attackby(obj/item/W, mob/user) - if(isWirecutter(W)) - cut_wire(W, user) +// TODO: take a closer look at cable attackby, make it call parent? +/obj/structure/cable/attackby(obj/item/used_item, mob/user) - else if(isCoil(W)) - var/obj/item/stack/cable_coil/coil = W + if(IS_WIRECUTTER(used_item)) + cut_wire(used_item, user) + return TRUE + + if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/coil = used_item if (coil.get_amount() < 1) - to_chat(user, "Not enough cable") - return + to_chat(user, "You don't have enough cable to lay down.") + return TRUE coil.cable_join(src, user) + return TRUE - else if(isMultitool(W)) - + if(IS_MULTITOOL(used_item)) if(powernet && (powernet.avail > 0)) // is it powered? - to_chat(user, "[get_wattage()] in power network.") - + to_chat(user, SPAN_WARNING("[get_wattage()] in power network.")) + shock(user, 5, 0.2) else - to_chat(user, "The cable is not powered.") + to_chat(user, SPAN_WARNING("\The [src] is not powered.")) + return TRUE - shock(user, 5, 0.2) - - - else if(W.edge) + else if(used_item.has_edge()) var/delay_holder - - if(W.force < 5) - visible_message("[user] starts sawing away roughly at the cable with \the [W].") + if(used_item.expend_attack_force(user) < 5) + visible_message(SPAN_WARNING("[user] starts sawing away roughly at \the [src] with \the [used_item].")) delay_holder = 8 SECONDS else - visible_message("[user] begins to cut through the cable with \the [W].") + visible_message(SPAN_WARNING("[user] begins to cut through \the [src] with \the [used_item].")) delay_holder = 3 SECONDS - if(user.do_skilled(delay_holder, SKILL_ELECTRICAL, src)) - cut_wire(W, user) - if(W.obj_flags & OBJ_FLAG_CONDUCTIBLE) + cut_wire(used_item, user) + if(used_item.obj_flags & OBJ_FLAG_CONDUCTIBLE) shock(user, 66, 0.7) else - visible_message("[user] stops cutting before any damage is done.") + visible_message(SPAN_WARNING("[user] stops cutting before any damage is done.")) + return TRUE - src.add_fingerprint(user) + return ..() -/obj/structure/cable/proc/cut_wire(obj/item/W, mob/user) +/obj/structure/cable/proc/cut_wire(obj/item/used_item, mob/user) var/turf/T = get_turf(src) if(!T || !T.is_plating()) return if(d1 == UP || d2 == UP) - to_chat(user, "You must cut this cable from above.") + to_chat(user, SPAN_WARNING("You must cut this [name] from above.")) return if(breaker_box) - to_chat(user, "This cable is connected to a nearby breaker box. Use the breaker box to interact with it.") + to_chat(user, SPAN_WARNING("This [name] is connected to a nearby breaker box. Use the breaker box to interact with it.")) return if (shock(user, 50)) return - new/obj/item/stack/cable_coil(T, (src.d1 ? 2 : 1), color) + new cable_type(T, (src.d1 ? 2 : 1), color) - visible_message("[user] cuts the cable.") + visible_message(SPAN_WARNING("[user] cuts \the [src].")) if(HasBelow(z)) for(var/turf/turf in GetBelow(src)) @@ -199,23 +239,23 @@ By design, d1 is the smallest direction and d2 is the highest if(c.d1 == UP || c.d2 == UP) qdel(c) - investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]","wires") + investigate_log("was cut by [key_name(user, user.client)] in [get_area_name(user)]","wires") qdel(src) // shock the user with probability prb /obj/structure/cable/proc/shock(mob/user, prb, var/siemens_coeff = 1.0) - if(!prob(prb)) - return 0 + if(!prob(prb) || powernet?.avail <= 0) + return FALSE if (electrocute_mob(user, powernet, src, siemens_coeff)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() - if(usr.stunned) - return 1 - return 0 + spark_at(src, amount=5, cardinal_only = TRUE) + if(HAS_STATUS(user, STAT_STUN)) + return TRUE + return FALSE +// TODO: generalize to matter list and parts_type. /obj/structure/cable/create_dismantled_products(turf/T) + SHOULD_CALL_PARENT(FALSE) new /obj/item/stack/cable_coil(loc, (d1 ? 2 : 1), color) //explosion handling @@ -224,11 +264,19 @@ By design, d1 is the smallest direction and d2 is the highest if(. && (severity == 1 || (severity == 2 && prob(50)) || (severity == 3 && prob(25)))) physically_destroyed() -obj/structure/cable/proc/cableColor(var/colorC) +/obj/structure/cable/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + var/turf/T = get_turf(src) + if(!T || !T.is_plating()) + return + . = ..() + +/obj/structure/cable/proc/cableColor(var/colorC) + if(!can_have_color) + return var/color_n = "#dd0000" if(colorC) color_n = colorC - color = color_n + set_color(color_n) ///////////////////////////////////////////////// // Cable laying helpers @@ -239,7 +287,7 @@ obj/structure/cable/proc/cableColor(var/colorC) /obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction) //search for and merge diagonally matching cables from the first direction component (north/south) - var/turf/T = get_step(src, direction&3)//go north/south + var/turf/T = get_step_resolving_mimic(src, direction & (NORTH|SOUTH)) for(var/obj/structure/cable/C in T) @@ -249,7 +297,7 @@ obj/structure/cable/proc/cableColor(var/colorC) if(src == C) continue - if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable + if(C.d1 == (direction ^ (NORTH|SOUTH)) || C.d2 == (direction ^ (NORTH|SOUTH))) //we've got a diagonally matching cable if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) var/datum/powernet/newPN = new() newPN.add_cable(C) @@ -260,7 +308,7 @@ obj/structure/cable/proc/cableColor(var/colorC) C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet //the same from the second direction component (east/west) - T = get_step(src, direction&12)//go east/west + T = get_step_resolving_mimic(src, direction & (EAST|WEST)) for(var/obj/structure/cable/C in T) @@ -269,7 +317,7 @@ obj/structure/cable/proc/cableColor(var/colorC) if(src == C) continue - if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable + if(C.d1 == (direction ^ (EAST|WEST)) || C.d2 == (direction ^ (EAST|WEST))) //we've got a diagonally matching cable if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables) var/datum/powernet/newPN = new() newPN.add_cable(C) @@ -282,12 +330,12 @@ obj/structure/cable/proc/cableColor(var/colorC) // merge with the powernets of power objects in the given direction /obj/structure/cable/proc/mergeConnectedNetworks(var/direction) - var/fdir = direction ? GLOB.reverse_dir[direction] : 0 //flip the direction, to match with the source position on its turf + var/fdir = direction ? global.reverse_dir[direction] : 0 //flip the direction, to match with the source position on its turf if(!(d1 == direction || d2 == direction)) //if the cable is not pointed in this direction, do nothing return - var/turf/TB = get_zstep(src, direction) + var/turf/TB = get_zstep_resolving_mimic(src, direction) for(var/obj/structure/cable/C in TB) @@ -327,8 +375,8 @@ obj/structure/cable/proc/cableColor(var/colorC) else powernet.add_cable(C) //the cable was powernetless, let's just add it to our powernet - else if(istype(AM,/obj/machinery/power/apc)) - var/obj/machinery/power/apc/N = AM + else if(istype(AM,/obj/machinery/apc)) + var/obj/machinery/apc/N = AM var/obj/machinery/power/terminal/terminal = N.terminal() if(!terminal) continue // APC are connected through their terminal @@ -354,8 +402,7 @@ obj/structure/cable/proc/cableColor(var/colorC) // Powernets handling helpers ////////////////////////////////////////////// -//if powernetless_only = 1, will only get connections without powernet -/obj/structure/cable/proc/get_connections(var/powernetless_only = 0) +/obj/structure/cable/proc/get_cable_connections(var/skip_assigned_powernets = FALSE) . = list() // this will be a list of all connected power objects var/turf/T @@ -363,17 +410,17 @@ obj/structure/cable/proc/cableColor(var/colorC) for(var/cable_dir in list(d1, d2)) if(cable_dir == 0) continue - var/reverse = GLOB.reverse_dir[cable_dir] - T = get_zstep(src, cable_dir) + var/reverse = global.reverse_dir[cable_dir] + T = get_zstep_resolving_mimic(src, cable_dir) if(T) for(var/obj/structure/cable/C in T) if(C.d1 == reverse || C.d2 == reverse) . += C if(cable_dir & (cable_dir - 1)) // Diagonal, check for /\/\/\ style cables along cardinal directions for(var/pair in list(NORTH|SOUTH, EAST|WEST)) - T = get_step(src, cable_dir & pair) + T = get_step_resolving_mimic(src, cable_dir & pair) // move either vertically or horizontally if(T) - var/req_dir = cable_dir ^ pair + var/req_dir = cable_dir ^ pair // flip along the direction we moved, so if we're NORTHEAST we want a cable to our east that's NORTHWEST for(var/obj/structure/cable/C in T) if(C.d1 == req_dir || C.d2 == req_dir) . += C @@ -383,17 +430,21 @@ obj/structure/cable/proc/cableColor(var/colorC) if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) // if either of C's d1 and d2 match either of ours . += C + // if asked, skip any cables with powernts + if(skip_assigned_powernets) + for(var/obj/structure/cable/C in .) + if(C.powernet) + . -= C + +/obj/structure/cable/proc/get_machine_connections(var/skip_assigned_powernets = FALSE) + . = list() // this will be a list of all connected power objects if(d1 == 0) for(var/obj/machinery/power/P in loc) - if(P.powernet == 0) continue // exclude APCs with powernet=0 - if(!powernetless_only || !P.powernet) + if(!skip_assigned_powernets || !P.powernet) . += P - // if the caller asked for powernetless cables only, dump the ones with powernets - if(powernetless_only) - for(var/obj/structure/cable/C in .) - if(C.powernet) - . -= C +/obj/structure/cable/proc/get_connections(var/skip_assigned_powernets = FALSE) + return get_cable_connections(skip_assigned_powernets) + get_machine_connections(skip_assigned_powernets) //should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf. //needed as this can, unlike other placements, disconnect cables @@ -401,10 +452,10 @@ obj/structure/cable/proc/cableColor(var/colorC) var/turf/T1 = loc if(!T1) return - var/list/powerlist = power_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a powernet - if(powerlist.len>0) + var/obj/structure/cable/other_cable = get_matching_cable(T1, src, 0) // find a cable to start a replacement network from, if it exists + if(other_cable) var/datum/powernet/PN = new() - propagate_network(powerlist[1],PN) //propagates the new powernet beginning at the source cable + propagate_network(other_cable,PN) //propagates the new powernet beginning at the source cable if(PN.is_empty()) //can happen with machines made nodeless when smoothing cables qdel(PN) @@ -412,16 +463,16 @@ obj/structure/cable/proc/cableColor(var/colorC) // cut the cable's powernet at this cable and updates the powergrid /obj/structure/cable/proc/cut_cable_from_powernet() var/turf/T1 = loc - var/list/P_list + var/obj/structure/cable/other_cable if(!T1) return if(d1) - T1 = get_step(T1, d1) - P_list = power_list(T1, src, turn(d1,180),0,cable_only = 1) // what adjacently joins on to cut cable... - - P_list += power_list(loc, src, d1, 0, cable_only = 1)//... and on turf + T1 = get_zstep_resolving_mimic(T1, d1) + other_cable = get_matching_cable(T1, src, d1) // check our adjacent turf for connecting cables first + if(!other_cable) + other_cable = get_matching_cable(loc, src, d1) // and fall back to our own turf if we don't find one - if(P_list.len == 0)//if nothing in both list, then the cable was a lone cable, just delete it and its powernet + if(!other_cable) // if we didn't find another cable, then the cable was a lone cable, just delete it and its powernet powernet.remove_cable(src) for(var/obj/machinery/power/P in T1)//check if it was powering a machine @@ -434,7 +485,7 @@ obj/structure/cable/proc/cableColor(var/colorC) powernet.remove_cable(src) //remove the cut cable from its powernet var/datum/powernet/newPN = new()// creates a new powernet... - propagate_network(P_list[1], newPN)//... and propagates it to the other side of the cable + propagate_network(other_cable, newPN)//... and propagates it to the other side of the cable // Disconnect machines connected to nodes if(d1 == 0) // if we cut a node (O-X) cable @@ -456,27 +507,35 @@ obj/structure/cable/proc/cableColor(var/colorC) /obj/item/stack/cable_coil name = "multipurpose cable coil" - icon = 'icons/obj/power.dmi' - icon_state = "coil" + icon = 'icons/obj/items/cable_coil.dmi' + icon_state = ICON_STATE_WORLD randpixel = 2 amount = MAXCOIL max_amount = MAXCOIL color = COLOR_MAROON - desc = "A coil of wiring, for delicate electronics use aswell as the more basic cable laying." - throwforce = 0 + paint_color = COLOR_MAROON + desc = "A coil of wiring, suitable for both delicate electronics and heavy-duty power supply." + singular_name = "length of cable" + plural_name = "lengths of cable" w_class = ITEM_SIZE_NORMAL throw_speed = 2 throw_range = 5 - material = /decl/material/solid/metal/steel + material = /decl/material/solid/metal/copper matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY item_state = "coil" attack_verb = list("whipped", "lashed", "disciplined", "flogged") - stacktype = /obj/item/stack/cable_coil + stack_merge_type = /obj/item/stack/cable_coil + matter_multiplier = 0.15 + /// Whether or not this cable coil can even have a color in the first place. + var/can_have_color = TRUE + /// The type of cable structure produced when laying down this cable. + /// src.cable_type::cable_type should equal stack_merge_type, ideally + var/cable_type = /obj/structure/cable /obj/item/stack/cable_coil/single amount = 1 @@ -488,12 +547,17 @@ obj/structure/cable/proc/cableColor(var/colorC) matter = null uses_charge = 1 charge_costs = list(1) - -/obj/item/stack/cable_coil/Initialize(mapload, length = MAXCOIL, var/param_color = null) - . = ..(mapload, length) - src.amount = length - if (param_color) // It should be red by default, so only recolor it if parameter was specified. - color = param_color + max_health = ITEM_HEALTH_NO_DAMAGE + is_spawnable_type = FALSE + +/obj/item/stack/cable_coil/Initialize(mapload, c_length, var/param_color = null) + . = ..(mapload, c_length) + set_extension(src, /datum/extension/tool/variable/simple, list( + TOOL_CABLECOIL = TOOL_QUALITY_DEFAULT, + TOOL_SUTURES = TOOL_QUALITY_MEDIOCRE + )) + if (can_have_color && param_color) // It should be red by default, so only recolor it if parameter was specified. + set_color(param_color) update_icon() update_wclass() @@ -502,30 +566,25 @@ obj/structure/cable/proc/cableColor(var/colorC) /////////////////////////////////// //you can use wires to heal robotics -/obj/item/stack/cable_coil/attack(var/atom/A, var/mob/living/user, var/def_zone) - if(ishuman(A) && user.a_intent == I_HELP) - var/mob/living/carbon/human/H = A - var/obj/item/organ/external/S = H.organs_by_name[user.zone_sel.selecting] - - if (!S) return - if(!BP_IS_PROSTHETIC(S) || user.a_intent != I_HELP) - return ..() - - if(BP_IS_BRITTLE(S)) - to_chat(user, "\The [H]'s [S.name] is hard and brittle - \the [src] cannot repair it.") - return 1 - - var/use_amt = min(src.amount, ceil(S.burn_dam/3), 5) - if(can_use(use_amt)) - if(S.robo_repair(3*use_amt, BURN, "some damaged wiring", src, user)) - src.use(use_amt) - return +/obj/item/stack/cable_coil/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + var/obj/item/organ/external/affecting = istype(target) && GET_EXTERNAL_ORGAN(target, user?.get_target_zone()) + if(affecting && user.check_intent(I_FLAG_HELP)) + if(!affecting.is_robotic()) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is not robotic. \The [src] cannot repair it.")) + else if(BP_IS_BRITTLE(affecting)) + to_chat(user, SPAN_WARNING("\The [target]'s [affecting.name] is hard and brittle. \The [src] cannot repair it.")) + else + var/use_amt = min(src.amount, ceil(affecting.burn_dam/3), 5) + if(can_use(use_amt) && affecting.robo_repair(3*use_amt, BURN, "some damaged wiring", src, user)) + use(use_amt) + return TRUE return ..() - /obj/item/stack/cable_coil/on_update_icon() - if (!color) - color = GLOB.possible_cable_colours[pick(GLOB.possible_cable_colours)] + . = ..() + if (!paint_color && can_have_color) + var/list/possible_cable_colours = get_global_cable_colors() + set_color(possible_cable_colours[pick(possible_cable_colours)]) if(amount == 1) icon_state = "coil1" SetName("cable piece") @@ -540,15 +599,16 @@ obj/structure/cable/proc/cableColor(var/colorC) SetName(initial(name)) /obj/item/stack/cable_coil/proc/set_cable_color(var/selected_color, var/user) - if(!selected_color) + if(!selected_color || !can_have_color) return - var/final_color = GLOB.possible_cable_colours[selected_color] + var/list/possible_cable_colours = get_global_cable_colors() + var/final_color = possible_cable_colours[selected_color] if(!final_color) selected_color = "Red" - final_color = GLOB.possible_cable_colours[selected_color] - color = final_color - to_chat(user, "You change \the [src]'s color to [lowertext(selected_color)].") + final_color = possible_cable_colours[selected_color] + set_color(final_color) + to_chat(user, SPAN_NOTICE("You change \the [src]'s color to [lowertext(selected_color)].")) /obj/item/stack/cable_coil/proc/update_wclass() if(amount == 1) @@ -556,18 +616,16 @@ obj/structure/cable/proc/cableColor(var/colorC) else w_class = ITEM_SIZE_SMALL -/obj/item/stack/cable_coil/examine(mob/user, distance) +/obj/item/stack/cable_coil/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance > 1) return - if(get_amount() == 1) - to_chat(user, "A short piece of power cable.") + . += "\A [singular_name]." else if(get_amount() == 2) - to_chat(user, "A piece of power cable.") + . += "Two [plural_name]." else - to_chat(user, "A coil of power cable. There are [get_amount()] lengths of cable in the coil.") - + . += "A coil of power cable. There are [get_amount()] [plural_name] in the coil." /obj/item/stack/cable_coil/verb/make_restraint() set name = "Make Cable Restraints" @@ -575,36 +633,36 @@ obj/structure/cable/proc/cableColor(var/colorC) var/mob/M = usr if(ishuman(M) && !M.incapacitated()) - if(!istype(usr.loc,/turf)) return + if(!isturf(usr.loc)) return if(!src.use(15)) - to_chat(usr, "You need at least 15 lengths to make restraints!") + to_chat(usr, SPAN_WARNING("You need at least 15 [plural_name] to make restraints!")) return var/obj/item/handcuffs/cable/B = new /obj/item/handcuffs/cable(usr.loc) - B.color = color - to_chat(usr, "You wind some cable together to make some restraints.") + B.set_color(color) + to_chat(usr, SPAN_NOTICE("You wind some [plural_name] together to make some restraints.")) else - to_chat(usr, "You cannot do that.") + to_chat(usr, SPAN_NOTICE("You cannot do that.")) /obj/item/stack/cable_coil/cyborg/verb/set_colour() set name = "Change Colour" set category = "Object" - var/selected_type = input("Pick new colour.", "Cable Colour", null, null) as null|anything in GLOB.possible_cable_colours + var/selected_type = input("Pick new colour.", "Cable Colour", null, null) as null|anything in get_global_cable_colors() set_cable_color(selected_type, usr) // Items usable on a cable coil : // - Wirecutters : cut them duh ! // - Cable coil : merge cables -/obj/item/stack/cable_coil/proc/can_merge(var/obj/item/stack/cable_coil/C) - return color == C.color +/obj/item/stack/cable_coil/can_merge_stacks(var/obj/item/stack/other) + return !other || (istype(other) && other.color == color) -/obj/item/stack/cable_coil/cyborg/can_merge() - return 1 +/obj/item/stack/cable_coil/cyborg/can_merge_stacks(var/obj/item/stack/other) + return TRUE -/obj/item/stack/cable_coil/transfer_to(obj/item/stack/cable_coil/S) - if(!istype(S)) +/obj/item/stack/cable_coil/transfer_to(obj/item/stack/cable_coil/coil) + if(!istype(coil)) return 0 - if(!(can_merge(S) || S.can_merge(src))) + if(!(can_merge_stacks(coil) || coil.can_merge_stacks(src))) return 0 return ..() @@ -613,21 +671,21 @@ obj/structure/cable/proc/cableColor(var/colorC) // Cable laying procedures ////////////////////////////////////////////// -// called when cable_coil is clicked on a turf/simulated/floor -/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/F, mob/user) +// called when cable_coil is clicked on a turf +/obj/item/stack/cable_coil/proc/turf_place(turf/F, mob/user) if(!isturf(user.loc)) return if(get_amount() < 1) // Out of cable - to_chat(user, "There is no cable left.") + to_chat(user, SPAN_WARNING("There is no [plural_name] left.")) return if(get_dist(F,user) > 1) // Too far - to_chat(user, "You can't lay cable at a place that far away.") + to_chat(user, SPAN_WARNING("You can't lay cable at a place that far away.")) return if(!F.is_plating()) // Ff floor is intact, complain - to_chat(user, "You can't lay cable there unless the floor tiles are removed.") + to_chat(user, SPAN_WARNING("You can't lay cable there unless the floor tiles are removed.")) return var/dirn @@ -637,20 +695,21 @@ obj/structure/cable/proc/cableColor(var/colorC) dirn = get_dir(F, user) var/end_dir = 0 - if(istype(F, /turf/simulated/open)) + if(istype(F) && F.is_open()) if(!can_use(2)) - to_chat(user, "You don't have enough cable to do this!") + to_chat(user, SPAN_WARNING("You don't have enough [plural_name] to do this!")) return end_dir = DOWN for(var/obj/structure/cable/LC in F) if((LC.d1 == dirn && LC.d2 == end_dir ) || ( LC.d2 == dirn && LC.d1 == end_dir)) - to_chat(user, "There's already a cable at that position.") + to_chat(user, SPAN_WARNING("There's already a cable at that position.")) return put_cable(F, user, end_dir, dirn) if(end_dir == DOWN) put_cable(GetBelow(F), user, UP, 0) + return TRUE // called when cable_coil is click on an installed obj/cable // or click on a turf that already contains a "node" cable @@ -665,19 +724,18 @@ obj/structure/cable/proc/cableColor(var/colorC) return if(get_dist(C, user) > 1) // make sure it's close enough - to_chat(user, "You can't lay cable at a place that far away.") + to_chat(user, SPAN_WARNING("You can't lay cable at a place that far away.")) return if(U == T) //if clicked on the turf we're standing on, try to put a cable in the direction we're facing - turf_place(T,user) - return + return turf_place(T,user) var/dirn = get_dir(C, user) // one end of the clicked cable is pointing towards us if(C.d1 == dirn || C.d2 == dirn) if(!U.is_plating()) // can't place a cable if the floor is complete - to_chat(user, "You can't lay cable there unless the floor tiles are removed.") + to_chat(user, SPAN_WARNING("You can't lay cable there unless the floor tiles are removed.")) return else // cable is pointing at us, we're standing on an open tile @@ -687,10 +745,10 @@ obj/structure/cable/proc/cableColor(var/colorC) for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already if(LC.d1 == fdirn || LC.d2 == fdirn) - to_chat(user, "There's already a cable at that position.") + to_chat(user, SPAN_WARNING("There's already a cable at that position.")) return put_cable(U,user,0,fdirn) - return + return TRUE // exisiting cable doesn't point at our position, so see if it's a stub else if(C.d1 == 0) @@ -708,7 +766,7 @@ obj/structure/cable/proc/cableColor(var/colorC) if(LC == C) // skip the cable we're interacting with continue if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction - to_chat(user, "There's already a cable at that position.") + to_chat(user, SPAN_WARNING("There's already a cable at that position.")) return @@ -740,13 +798,19 @@ obj/structure/cable/proc/cableColor(var/colorC) return C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets. - return + return TRUE -/obj/item/stack/cable_coil/proc/put_cable(turf/simulated/F, mob/user, d1, d2) + else if(C.d1 == UP) //Special cases for zcables, since they behave weirdly + . = turf_place(T, user) + if(.) + to_chat(user, SPAN_NOTICE("You connect the cable hanging from the ceiling.")) + return . + +/obj/item/stack/cable_coil/proc/put_cable(turf/F, mob/user, d1, d2) if(!istype(F)) - return + return FALSE - var/obj/structure/cable/C = new(F) + var/obj/structure/cable/C = new cable_type(F) C.cableColor(color) C.d1 = d1 C.d2 = d2 @@ -767,15 +831,18 @@ obj/structure/cable/proc/cableColor(var/colorC) if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions C.mergeDiagonalsNetworks(C.d2) - use(1) + . = use(1) if (C.shock(user, 50)) if (prob(50)) //fail new/obj/item/stack/cable_coil(C.loc, 1, C.color) qdel(C) + return FALSE ////////////////////////////// // Misc. ///////////////////////////// +/obj/item/stack/cable_coil/five + amount = 5 /obj/item/stack/cable_coil/cut item_state = "coil2" @@ -788,27 +855,39 @@ obj/structure/cable/proc/cableColor(var/colorC) /obj/item/stack/cable_coil/yellow color = COLOR_AMBER + paint_color = COLOR_AMBER /obj/item/stack/cable_coil/blue color = COLOR_CYAN_BLUE + paint_color = COLOR_CYAN_BLUE /obj/item/stack/cable_coil/green color = COLOR_GREEN + paint_color = COLOR_GREEN /obj/item/stack/cable_coil/pink color = COLOR_PURPLE + paint_color = COLOR_PURPLE /obj/item/stack/cable_coil/orange color = COLOR_ORANGE + paint_color = COLOR_ORANGE /obj/item/stack/cable_coil/cyan color = COLOR_SKY_BLUE + paint_color = COLOR_SKY_BLUE /obj/item/stack/cable_coil/white color = COLOR_SILVER + paint_color = COLOR_SILVER + +/obj/item/stack/cable_coil/lime + color = COLOR_LIME + paint_color = COLOR_LIME -/obj/item/stack/cable_coil/random/Initialize() - color = GLOB.possible_cable_colours[pick(GLOB.possible_cable_colours)] +/obj/item/stack/cable_coil/random/Initialize(mapload, c_length, param_color) + var/list/possible_cable_colours = get_global_cable_colors() + set_color(possible_cable_colours[pick(possible_cable_colours)]) . = ..() // Produces cable coil from a rig power cell. @@ -823,18 +902,18 @@ obj/structure/cable/proc/cableColor(var/colorC) if(istype(loc, /obj/item/rig_module)) var/obj/item/rig_module/module = loc return module.get_cell() - if(istype(loc, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = loc - return R.get_cell() + if(isrobot(loc)) + var/mob/living/silicon/robot/robot = loc + return robot.get_cell() /obj/item/stack/cable_coil/fabricator/use(var/used) var/obj/item/cell/cell = get_cell() - if(cell) cell.use(used * cost_per_cable) + return cell?.use(used * cost_per_cable) /obj/item/stack/cable_coil/fabricator/get_amount() var/obj/item/cell/cell = get_cell() - . = (cell ? Floor(cell.charge / cost_per_cable) : 0) + . = (cell ? floor(cell.charge / cost_per_cable) : 0) /obj/item/stack/cable_coil/fabricator/get_max_amount() var/obj/item/cell/cell = get_cell() - . = (cell ? Floor(cell.maxcharge / cost_per_cable) : 0) + . = (cell ? floor(cell.maxcharge / cost_per_cable) : 0) diff --git a/code/modules/power/cable_logic.dm b/code/modules/power/cable_logic.dm deleted file mode 100644 index 3b5b67a3ea4f..000000000000 --- a/code/modules/power/cable_logic.dm +++ /dev/null @@ -1,292 +0,0 @@ -#define LOGIC_HIGH 5 - -//Indicators only have one input and no outputs -/obj/machinery/logic/indicator - //Input is searched from the 'dir' direction - var/obj/structure/cable/input - -/obj/machinery/logic/indicator/process() - if(input) - return 1 - - - if(!input) - var/turf/T = get_step(src, dir) - if(T) - var/inv_dir = turn(dir, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - input = C - return 1 - - return 0 //If it gets to here, it means no suitable wire to link to was found. - -/obj/machinery/logic/indicator/bulb - icon = 'icons/obj/lighting.dmi' - icon_state = "bulb0" - -/obj/machinery/logic/indicator/bulb/process() - if(!..()) //Parent proc checks if input1 exists. - return - - var/datum/powernet/pn_input = input.powernet - if(!pn_input) - return - - if(pn_input.avail >= LOGIC_HIGH) - icon_state = "bulb1" - else - icon_state = "bulb0" - - - - -//Sensors only have one output and no inputs -/obj/machinery/logic/sensor - //Output is searched from the 'dir' direction - var/obj/structure/cable/output - -/obj/machinery/logic/sensor/process() - if(output) - return 1 - - if(!output) - var/turf/T = get_step(src, dir) - if(T) - var/inv_dir = turn(dir, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - output = C - return 1 - - return 0 //If it gets to here, it means no suitable wire to link to was found. - -//Constant high generator. This will continue to send a signal of LOGIC_HIGH as long as it exists. -/obj/machinery/logic/sensor/constant_high - icon = 'icons/obj/atmospherics/outlet_injector.dmi' - icon_state = "off" - -/obj/machinery/logic/sensor/constant_high/process() - if(!..()) //Parent proc checks if input1 exists. - return - - var/datum/powernet/pn_output = output.powernet - if(!pn_output) - return - - pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) - - - - -//ONE INPUT logic elements have one input and one output -/obj/machinery/logic/oneinput - var/dir_input = 2 - var/dir_output = 1 - var/obj/structure/cable/input - var/obj/structure/cable/output - icon = 'icons/atmos/heat.dmi' - icon_state = "intact" - -/obj/machinery/logic/oneinput/process() - if(input && output) - return 1 - - if(!dir_input || !dir_output) - return 0 - - if(!input) - var/turf/T = get_step(src, dir_input) - if(T) - var/inv_dir = turn(dir_input, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - input = C - - if(!output) - var/turf/T = get_step(src, dir_output) - if(T) - var/inv_dir = turn(dir_output, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - output = C - - return 0 //On the process() call, where everything is still being searched for, it returns 0. It will return 1 on the next process() call. - -//NOT GATE -/obj/machinery/logic/oneinput/not/process() - if(!..()) //Parent proc checks if input1, input2 and output exist. - return - - var/datum/powernet/pn_input = input.powernet - - if(!pn_input) - return - - var/datum/powernet/pn_output = output.powernet - if(!pn_output) - return - - if( !(pn_input.avail >= LOGIC_HIGH)) - pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. - else - pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 - - - - - - - - - -//TWO INPUT logic elements have two inputs and one output -/obj/machinery/logic/twoinput - var/dir_input1 = 2 - var/dir_input2 = 8 - var/dir_output = 1 - var/obj/structure/cable/input1 - var/obj/structure/cable/input2 - var/obj/structure/cable/output - icon = 'icons/obj/atmospherics/mixer.dmi' - icon_state = "intact_off" - -/obj/machinery/logic/twoinput/process() - if(input1 && input2 && output) - return 1 - - if(!dir_input1 || !dir_input2 || !dir_output) - return 0 - - if(!input1) - var/turf/T = get_step(src, dir_input1) - if(T) - var/inv_dir = turn(dir_input1, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - input1 = C - - if(!input2) - var/turf/T = get_step(src, dir_input2) - if(T) - var/inv_dir = turn(dir_input2, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - input2 = C - - if(!output) - var/turf/T = get_step(src, dir_output) - if(T) - var/inv_dir = turn(dir_output, 180) - for(var/obj/structure/cable/C in T) - if(C.d1 == inv_dir || C.d2 == inv_dir) - output = C - - return 0 //On the process() call, where everything is still being searched for, it returns 0. It will return 1 on the next process() call. - -//AND GATE -/obj/machinery/logic/twoinput/and/process() - if(!..()) //Parent proc checks if input1, input2 and output exist. - return - - var/datum/powernet/pn_input1 = input1.powernet - var/datum/powernet/pn_input2 = input2.powernet - - if(!pn_input1 || !pn_input2) - return - - var/datum/powernet/pn_output = output.powernet - if(!pn_output) - return - - if( (pn_input1.avail >= LOGIC_HIGH) && (pn_input2.avail >= LOGIC_HIGH) ) - pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. - else - pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 - -//OR GATE -/obj/machinery/logic/twoinput/or/process() - if(!..()) //Parent proc checks if input1, input2 and output exist. - return - - var/datum/powernet/pn_input1 = input1.powernet - var/datum/powernet/pn_input2 = input2.powernet - - if(!pn_input1 || !pn_input2) - return - - var/datum/powernet/pn_output = output.powernet - if(!pn_output) - return - - if( (pn_input1.avail >= LOGIC_HIGH) || (pn_input2.avail >= LOGIC_HIGH) ) - pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. - else - pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 - -//XOR GATE -/obj/machinery/logic/twoinput/xor/process() - if(!..()) //Parent proc checks if input1, input2 and output exist. - return - - var/datum/powernet/pn_input1 = input1.powernet - var/datum/powernet/pn_input2 = input2.powernet - - if(!pn_input1 || !pn_input2) - return - - var/datum/powernet/pn_output = output.powernet - if(!pn_output) - return - - if( (pn_input1.avail >= LOGIC_HIGH) != (pn_input2.avail >= LOGIC_HIGH) ) - pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. - else - pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 - -//XNOR GATE (EQUIVALENCE) -/obj/machinery/logic/twoinput/xnor/process() - if(!..()) //Parent proc checks if input1, input2 and output exist. - return - - var/datum/powernet/pn_input1 = input1.powernet - var/datum/powernet/pn_input2 = input2.powernet - - if(!pn_input1 || !pn_input2) - return - - var/datum/powernet/pn_output = output.powernet - if(!pn_output) - return - - if( (pn_input1.avail >= LOGIC_HIGH) == (pn_input2.avail >= LOGIC_HIGH) ) - pn_output.newavail = max(pn_output.avail, LOGIC_HIGH) //Set the output avilable power to 5 or whatever it was before. - else - pn_output.draw_power(LOGIC_HIGH) //Otherwise increase the load to 5 - -#define RELAY_POWER_TRANSFER 2000 //How much power a relay transfers through. - -//RELAY - input1 governs the flow from input2 to output -/obj/machinery/logic/twoinput/relay/process() - if(!..()) //Parent proc checks if input1, input2 and output exist. - return - - var/datum/powernet/pn_input1 = input1.powernet - - if(!pn_input1) - return - - if( pn_input1.avail >= LOGIC_HIGH ) - var/datum/powernet/pn_input2 = input2.powernet - var/datum/powernet/pn_output = output.powernet - - if(!pn_output) - return - - if(pn_input2.avail >= RELAY_POWER_TRANSFER) - pn_input2.draw_power(RELAY_POWER_TRANSFER) - pn_output.newavail += RELAY_POWER_TRANSFER - - -#undef RELAY_POWER_TRANSFER -#undef LOGIC_HIGH \ No newline at end of file diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 035e136ecf26..d9e93ff2da18 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -1,24 +1,21 @@ // Power Cells /obj/item/cell name = "power cell" - desc = "A rechargable electrochemical power cell." + desc = "A rechargeable electrochemical power cell." icon = 'icons/obj/power.dmi' icon_state = "cell" item_state = "cell" - origin_tech = "{'powerstorage':1}" - force = 5.0 - throwforce = 5.0 + origin_tech = @'{"powerstorage":1}' throw_speed = 3 throw_range = 5 w_class = ITEM_SIZE_NORMAL material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) var/charge // Current charge var/maxcharge = 1000 // Capacity in Wh - var/overlay_state /obj/item/cell/Initialize() . = ..() @@ -39,21 +36,17 @@ return use(cell_amt) / CELLRATE /obj/item/cell/on_update_icon() - - var/new_overlay_state = null + . = ..() + var/overlay_state = null switch(percent()) if(95 to 100) - new_overlay_state = "cell-o2" + overlay_state = "cell-o2" if(25 to 95) - new_overlay_state = "cell-o1" + overlay_state = "cell-o1" if(0.05 to 25) - new_overlay_state = "cell-o0" - - if(new_overlay_state != overlay_state) - overlay_state = new_overlay_state - overlays.Cut() - if(overlay_state) - overlays += image('icons/obj/power.dmi', overlay_state) + overlay_state = "cell-o0" + if(overlay_state) + add_overlay(overlay_state) /obj/item/cell/proc/percent() // return % charge of cell return maxcharge && (100.0*charge/maxcharge) @@ -86,16 +79,17 @@ update_icon() return amount_used -/obj/item/cell/examine(mob/user) +/obj/item/cell/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The label states it's capacity is [maxcharge] Wh") - to_chat(user, "The charge meter reads [round(src.percent(), 0.1)]%") + . += "The label states it's capacity is [maxcharge] Wh." + . += "The charge meter reads [round(src.percent(), 0.1)]%." /obj/item/cell/emp_act(severity) - //remove this once emp changes on dev are merged in + // remove this if EMPs are ever rebalanced so that they don't instantly drain borg cells + // todo: containers (partially) shielding contents? if(isrobot(loc)) - var/mob/living/silicon/robot/R = loc - severity *= R.cell_emp_mult + var/mob/living/silicon/robot/robot = loc + severity *= robot.cell_emp_mult // Lose 1/2, 1/4, 1/6 of the current charge per hit or 1/4, 1/8, 1/12 of the max charge per hit, whichever is highest charge -= max(charge / (2 * severity), maxcharge/(4 * severity)) @@ -130,16 +124,16 @@ desc = "A small power cell designed to power handheld devices." icon_state = "device" w_class = ITEM_SIZE_SMALL - force = 0 throw_speed = 5 throw_range = 7 maxcharge = 100 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) -/obj/item/cell/device/variable/Initialize(mapload, charge_amount) - maxcharge = charge_amount - return ..(mapload) +/obj/item/cell/device/variable/Initialize(ml, material_key, charge_amount) + if(!isnull(charge_amount)) + maxcharge = charge_amount + return ..(ml, material_key) /obj/item/cell/device/standard name = "standard device power cell" @@ -151,17 +145,52 @@ icon_state = "hdevice" maxcharge = 100 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"powerstorage":2}' + +/obj/item/cell/device/infinite + name = "experimental device power cell" + desc = "This special experimental power cell has both very large capacity, and ability to recharge itself with zero-point energy." + icon_state = "icell" + origin_tech = null + maxcharge = 3000 + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE + ) + +/obj/item/cell/device/infinite/percent() + return 100 + +/obj/item/cell/device/infinite/fully_charged() + return TRUE + +/obj/item/cell/device/infinite/check_charge(var/amount) + return (maxcharge >= amount) + +/obj/item/cell/device/infinite/use(var/amount) + return min(maxcharge, amount) + +/obj/item/cell/device/infinite/checked_use(var/amount) + return check_charge(amount) + +/obj/item/cell/device/infinite/give() + return 0 + +/obj/item/cell/device/infinite/get_electrocute_damage() + charge = maxcharge + return ..() /obj/item/cell/crap name = "old power cell" desc = "A cheap old power cell. It's probably been in use for quite some time now." - origin_tech = "{'powerstorage':1}" + origin_tech = @'{"powerstorage":1}' maxcharge = 100 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) /obj/item/cell/crap/empty @@ -170,36 +199,36 @@ /obj/item/cell/standard name = "standard power cell" desc = "A standard and relatively cheap power cell, commonly used." - origin_tech = "{'powerstorage':1}" + origin_tech = @'{"powerstorage":1}' maxcharge = 250 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) /obj/item/cell/apc name = "APC power cell" desc = "A special power cell designed for heavy-duty use in area power controllers." - origin_tech = "{'powerstorage':1}" + origin_tech = @'{"powerstorage":1}' maxcharge = 500 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) /obj/item/cell/high name = "advanced power cell" desc = "An advanced high-grade power cell, for use in important systems." - origin_tech = "{'powerstorage':2}" + origin_tech = @'{"powerstorage":2}' icon_state = "hcell" maxcharge = 1000 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) /obj/item/cell/high/empty @@ -208,12 +237,12 @@ /obj/item/cell/exosuit name = "exosuit power cell" desc = "A special power cell designed for heavy-duty use in industrial exosuits." - origin_tech = "{'powerstorage':3}" + origin_tech = @'{"powerstorage":3}' icon_state = "hcell" maxcharge = 1500 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE ) @@ -221,12 +250,12 @@ /obj/item/cell/super name = "enhanced power cell" desc = "A very advanced power cell with increased energy density, for use in critical applications." - origin_tech = "{'powerstorage':5}" + origin_tech = @'{"powerstorage":5}' icon_state = "scell" maxcharge = 2000 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE ) @@ -236,14 +265,14 @@ /obj/item/cell/hyper name = "superior power cell" desc = "Pinnacle of power storage technology, this very expensive power cell provides the best energy density reachable with conventional electrochemical cells." - origin_tech = "{'powerstorage':6}" + origin_tech = @'{"powerstorage":6}' icon_state = "hpcell" maxcharge = 3000 material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE ) @@ -258,7 +287,7 @@ maxcharge = 3000 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE ) @@ -286,18 +315,25 @@ /obj/item/cell/potato name = "potato battery" - desc = "A rechargable starch based power cell." - origin_tech = "{'powerstorage':1}" - icon = 'icons/obj/power.dmi' //'icons/obj/harvest.dmi' - icon_state = "potato_cell" //"potato_battery" + desc = "A rechargeable starch based power cell." + origin_tech = @'{"powerstorage":1}' + icon = 'icons/obj/power.dmi' + icon_state = "potato_cell" maxcharge = 20 +//Generic battery cell for guns with rechargeable batteries. +/obj/item/cell/gun + name = "weapon energy cell" + desc = "A military grade high-density battery, expected to deplete after tens of thousands of complete charge cycles." + origin_tech = @'{"combat":2,"materials":2,"powerstorage": 2}' + icon_state = "gunbattery" + maxcharge = 500 + w_class = ITEM_SIZE_SMALL //Perhaps unwise. + +/obj/item/cell/gun/empty + charge = 0 -/obj/item/cell/slime - name = "charged slime core" - desc = "A yellow slime core that crackles with power." - origin_tech = "{'powerstorage':2,'biotech':4}" - icon = 'icons/mob/simple_animal/slimes.dmi' //'icons/obj/harvest.dmi' - icon_state = "yellow slime extract" //"potato_battery" - maxcharge = 200 - matter = null +/obj/item/cell/gun/on_update_icon() + . = ..() + //Color the battery charging overlay against the percentage of the battery capacity. However the index of gradient() is set to 1, instead of 100, so we divide it by 100. Colors were chosen by the sprite artist. + add_overlay(overlay_image(icon, "gunbattery_charge", gradient("#fa6a0a", "#9cdb43", clamp(percent(), 0, 100) ))) diff --git a/code/modules/power/debug_items.dm b/code/modules/power/debug_items.dm index 22307bfada5e..35a6efc12070 100644 --- a/code/modules/power/debug_items.dm +++ b/code/modules/power/debug_items.dm @@ -1,18 +1,20 @@ -/obj/machinery/power/debug_items/ +/obj/machinery/debug_items + abstract_type = /obj/machinery/debug_items icon = 'icons/obj/power.dmi' icon_state = "tracker" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/show_extended_information = 1 // Set to 0 to disable extra information on examining (for example, when used on admin events) -/obj/machinery/power/debug_items/examine(mob/user) +/obj/machinery/debug_items/examined_by(mob/user) . = ..() if(show_extended_information) show_info(user) -/obj/machinery/power/debug_items/proc/show_info(var/mob/user) +/obj/machinery/debug_items/proc/show_info(var/mob/user) + var/datum/powernet/powernet = get_powernet() if(!powernet) - to_chat(user, "This device is not connected to a powernet") + to_chat(user, "This device is not connected to a powernet.") return to_chat(user, "Connected to powernet: [powernet]") @@ -24,42 +26,43 @@ // An infinite power generator. Adds energy to connected cable. -/obj/machinery/power/debug_items/infinite_generator +/obj/machinery/debug_items/infinite_generator name = "Fractal Energy Reactor" desc = "An experimental power generator" var/power_generation_rate = 1000000 -/obj/machinery/power/debug_items/infinite_generator/Process() - add_avail(power_generation_rate) +/obj/machinery/debug_items/infinite_generator/Process() + generate_power(power_generation_rate) -/obj/machinery/power/debug_items/infinite_generator/show_info(var/mob/user) +/obj/machinery/debug_items/infinite_generator/show_info(var/mob/user) ..() to_chat(user, "Generator is providing [num2text(power_generation_rate, 20)] W") // A cable powersink, without the explosion/network alarms normal powersink causes. -/obj/machinery/power/debug_items/infinite_cable_powersink +/obj/machinery/debug_items/infinite_cable_powersink name = "Null Point Core" desc = "An experimental device that disperses energy, used for grid testing purposes." var/power_usage_rate = 0 var/last_used = 0 -/obj/machinery/power/debug_items/infinite_cable_powersink/Process() - last_used = draw_power(power_usage_rate) +/obj/machinery/debug_items/infinite_cable_powersink/Process() + var/datum/powernet/powernet = get_powernet() + last_used = powernet.draw_power(power_usage_rate) -/obj/machinery/power/debug_items/infinite_cable_powersink/show_info(var/mob/user) +/obj/machinery/debug_items/infinite_cable_powersink/show_info(var/mob/user) ..() to_chat(user, "Power sink is demanding [num2text(power_usage_rate, 20)] W") to_chat(user, "[num2text(last_used, 20)] W was actually used last tick") -/obj/machinery/power/debug_items/infinite_apc_powersink +/obj/machinery/debug_items/infinite_apc_powersink name = "APC Dummy Load" desc = "A dummy load that connects to an APC, used for load testing purposes." use_power = POWER_USE_ACTIVE active_power_usage = 0 -/obj/machinery/power/debug_items/infinite_apc_powersink/show_info(var/mob/user) +/obj/machinery/debug_items/infinite_apc_powersink/show_info(var/mob/user) ..() to_chat(user, "Dummy load is using [num2text(active_power_usage, 20)] W") - to_chat(user, "Powered: [powered() ? "YES" : "NO"]") + to_chat(user, "Powered: [!(stat & NOPOWER) ? "YES" : "NO"]") diff --git a/code/modules/power/fission/core.dm b/code/modules/power/fission/core.dm new file mode 100644 index 000000000000..06ca2a1f6740 --- /dev/null +++ b/code/modules/power/fission/core.dm @@ -0,0 +1,302 @@ +#define RATIO_PER_NEUTRON 0.0000001 +#define MIN_RADIATION_ENERGY 2000 +#define ACTIVE_THRESHOLD 200 +#define MAX_RODS 7 +#define JUMPED_FLUX 1000 +#define JUMPED_ENERGY 1200 +#define MAX_RADS 50 + +#define MAX_INTERACT_RATIO 0.5 +#define HI_NEUT_DIVISOR 125 +#define LO_NEUT_DIVISOR 50 +#define CONTROL_ROD_DIVISOR 5 + +/obj/machinery/atmospherics/unary/fission_core + name = "nuclear fission core" + desc = "An advanced atomic pile used to generate heat and create isotopes via nuclear fission." + icon = 'icons/obj/machines/power/fission.dmi' + icon_state = "fission_core" + layer = ABOVE_HUMAN_LAYER + density = TRUE + stat_immune = NOINPUT | NOSCREEN + base_type = /obj/machinery/atmospherics/unary/fission_core + construct_state = /decl/machine_construction/default/panel_closed + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL + + var/control_rod_depth = 1 // 0-1, how deeply the control rods are inserted into the core, controlling neutron absorption. + var/neutron_flux = 0 // The amount of neutrons in the core. Determines the ratio of fuel inside the core that is interacted with each tick. + var/neutron_energy = 0 // The average energy of the neutrons in the core. Df + + var/list/fuel_rods = list() // Material inserted into the core, fuel, moderators etc. + + var/max_temperature = 1000 // Maximum temperature of the interior gas mixture before the core begins to take damage. + var/last_message // Time of the last damage warning message. + var/damage = 0 + var/melted_down = FALSE + + // Diagnostics + var/last_neutron_flux_increase = 0 + var/last_neutron_flux_decrease = 0 + var/net_neutron_flux_change = 0 + + var/last_neutron_energy_increase = 0 + var/last_neutron_energy_decrease = 0 + var/net_neutron_energy_change = 0 + + var/initial_id_tag = "fission" + +/obj/machinery/atmospherics/unary/fission_core/Initialize() + . = ..() + set_extension(src, /datum/extension/local_network_member) + if(initial_id_tag) + var/datum/extension/local_network_member/fission = get_extension(src, /datum/extension/local_network_member) + fission.set_tag(null, initial_id_tag) + +/obj/machinery/atmospherics/unary/fission_core/Destroy() + fuel_rods.Cut() + . = ..() + +/obj/machinery/atmospherics/unary/fission_core/Process() + ..() + + last_neutron_flux_increase = 0 + last_neutron_flux_decrease = 0 + net_neutron_flux_change = 0 + + last_neutron_energy_increase = 0 + last_neutron_energy_decrease = 0 + net_neutron_energy_change = 0 + + if((!air_contents.get_total_moles() && check_active()) || (air_contents.temperature > max_temperature)) + // Stopping the reaction is relatively easy, but removing the heat rapidly is not. Total meltdown takes some time. + damage += air_contents.temperature ? min(3, round(air_contents.temperature/max_temperature)) : 3 + + if(world.time >= last_message + 10 SECONDS) + if(damage > 75) + visible_message(SPAN_DANGER("Parts of \the [src] begin to buckle outwards threateningly!")) + last_message = world.time + else if(damage > 50) + visible_message(SPAN_WARNING("\The [src]'s outward facing insulation begins to melt!")) + last_message = world.time + else if(damage > 10) + visible_message(SPAN_WARNING("\The [src] creaks loudly!")) + last_message = world.time + + if(damage >= 100) + meltdown() + return + + // Interactions modify these values, so to prevent inconsistencies depending on the order of materials, use the initial values for most calculations. + var/old_neutron_flux = neutron_flux + var/old_neutron_energy = neutron_energy + + // What percentage of the material is interacted with. Capped at 0.5 to prevent instantaneous disasters. + var/interaction_ratio = min(MAX_INTERACT_RATIO, RATIO_PER_NEUTRON*old_neutron_flux) + for(var/obj/item/fuel_assembly/fr in fuel_rods) + if(!fuel_rods[fr]) // The fuel rod is not exposed. + continue + for(var/mat_type in fr.matter) + var/decl/material/mat = GET_DECL(mat_type) + if(!(mat.flags & MAT_FLAG_FISSIBLE)) + continue + var/total_interacted_units = interaction_ratio * fr.matter[mat_type] + var/list/interactions = mat.neutron_interact(old_neutron_energy, total_interacted_units, fr.matter[mat_type]) + for(var/interaction in interactions) + var/interaction_units = interactions[interaction] // How many units of the material underwent this specific interaction. + var/removed = 0 + if(!interaction_units) + continue + switch(interaction) + if(INTERACTION_FISSION) + if(length(mat.fission_products)) + if(fr.matter[mat_type] - interaction_units < 0) + removed = fr.matter[mat_type] + fr.matter -= mat_type + else + removed = interaction_units + fr.matter[mat_type] -= removed + // Add the fission byproducts to the fuel assembly. + for(var/byproduct_type in mat.fission_products) + fr.matter[byproduct_type] += removed * mat.fission_products[byproduct_type] + + if(mat.neutron_production) + // Determine how many neutrons should be added to the flux. + var/d_neutron_flux = mat.neutron_production*removed + // Fission releases high energy neutrons that increase the average energy of the neutrons in the core. + var/d_neutron_energy = max(0, interaction_units * (mat.fission_energy - old_neutron_energy)/HI_NEUT_DIVISOR) + last_neutron_energy_increase += d_neutron_energy + neutron_energy += d_neutron_energy + neutron_flux += d_neutron_flux + last_neutron_flux_increase += d_neutron_flux + + if(mat.fission_heat) + air_contents.add_thermal_energy(removed*mat.fission_heat) + + // A simplification of neutron capture and/or subsequent beta decay. + if(INTERACTION_ABSORPTION) + if(length(mat.absorption_products)) + if(fr.matter[mat_type] - interaction_units < 0) + removed = fr.matter[mat_type] + fr.matter -= mat_type + else + removed = interaction_units + fr.matter[mat_type] -= removed + + for(var/byproduct_type in mat.absorption_products) + fr.matter[byproduct_type] += removed * mat.absorption_products[byproduct_type] + + var/d_neutron_flux = mat.neutron_absorption*removed + neutron_flux -= d_neutron_flux + last_neutron_flux_decrease += d_neutron_flux + + // Neutron moderation, reduction of neutron energy towards the target value for that material. + if(INTERACTION_SCATTER) + // Neutron moderators can only slow, not speed up neutrons. Check against the current neutron energy to ensure this. + if(mat.moderation_target > neutron_energy) + continue + var/d_neutron_energy = min(neutron_energy, interaction_units * (old_neutron_energy - mat.moderation_target)/LO_NEUT_DIVISOR) + last_neutron_energy_decrease += d_neutron_energy + neutron_energy = max(mat.moderation_target, neutron_energy - d_neutron_energy) + + // Neutron energy must pass a threshold for there to be danger of radiation. + if(neutron_energy >= MIN_RADIATION_ENERGY) + var/radiation_power = clamp(old_neutron_energy/1000 * old_neutron_flux/1000, 0, 40) + SSradiation.radiate(src, round(radiation_power)) + + // Control rods reduces neutron flux by 1/5th at full depth. + last_neutron_flux_decrease += round(neutron_flux*(control_rod_depth/CONTROL_ROD_DIVISOR)) + neutron_flux = round(neutron_flux*(1 - (control_rod_depth/CONTROL_ROD_DIVISOR))) + + if(!neutron_flux) + neutron_energy = 0 + + net_neutron_energy_change = last_neutron_energy_increase - last_neutron_energy_decrease + net_neutron_flux_change = last_neutron_flux_increase - last_neutron_flux_decrease + +/obj/machinery/atmospherics/unary/fission_core/proc/meltdown() + if(melted_down) + return + melted_down = TRUE + var/total_radioactivity = 0 + + for(var/obj/item/fuel_assembly/rod in fuel_rods) + if(total_radioactivity >= MAX_RADS) + break + for(var/mat_type in rod.matter) + var/decl/material/mat = GET_DECL(mat_type) + total_radioactivity += mat.radioactivity*SHEET_MATERIAL_AMOUNT / rod.matter[mat_type] + + visible_message(SPAN_DANGER("\The [src] explodes, blowing out its stored material!")) + // The core contained radioactive material, so irradiate the surroundings. + SSradiation.radiate(src, total_radioactivity) + + // Determine how powerful the explosion produced by the reactor will be. A larger explosion can be achieved by heating the reactor up very quickly. + var/temperature = clamp(air_contents.temperature, 1000, 7500) + explosion(get_turf(src), temperature/1500, temperature/750, temperature/500, temperature/500) + qdel(src) + +/obj/machinery/atmospherics/unary/fission_core/proc/check_active() + return neutron_flux >= ACTIVE_THRESHOLD + +/obj/machinery/atmospherics/unary/fission_core/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) + var/datum/extension/local_network_member/fission = get_extension(src, /datum/extension/local_network_member) + fission.get_new_tag(user) + return TRUE + + // Cannot deconstruct etc. the core while it is active. + if(check_active()) + to_chat(user, SPAN_WARNING("You cannot do that while \the [src] is active!")) + return TRUE + + if(istype(used_item, /obj/item/fuel_assembly)) + if(length(fuel_rods) >= MAX_RODS) + to_chat(user, SPAN_WARNING("\The [src] is full!")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + fuel_rods[used_item] = FALSE // Rod is not exposed to begin with. + user.visible_message(SPAN_NOTICE("\The [user] inserts \a [used_item] into \the [src]."), SPAN_NOTICE("You insert \a [used_item] into \the [src].")) + return TRUE + . = ..() + +/obj/machinery/atmospherics/unary/fission_core/proc/jump_start() + if((stat & (BROKEN|NOPOWER)) || (can_use_power_oneoff(5 KILOWATTS) > 0)) + visible_message("\The [src] flashes an 'Insufficient Power' error.") + return + use_power_oneoff(5 KILOWATTS) + + neutron_flux = JUMPED_FLUX + neutron_energy = JUMPED_ENERGY + +/obj/machinery/atmospherics/unary/fission_core/proc/adjust_control_rods(var/new_depth) + if(stat & (BROKEN|NOPOWER)) + return + new_depth = clamp(new_depth, 0, 1) + control_rod_depth = new_depth + +/obj/machinery/atmospherics/unary/fission_core/proc/toggle_rod_exposure(var/rod) + if(stat & (BROKEN|NOPOWER)) + return + if(!rod || !fuel_rods[rod]) + return FALSE + var/obj/item/fuel_assembly/fr = fuel_rods[rod] + if(fuel_rods[fr] && check_active()) + return FALSE + + fuel_rods[fr] = !fuel_rods[fr] + return TRUE + +/obj/machinery/atmospherics/unary/fission_core/proc/eject_rod(var/rod) + if(check_active() || !rod || !fuel_rods[rod]) + return FALSE + var/obj/item/fuel_assembly/fr = fuel_rods[rod] + fuel_rods -= fr + fr.dropInto(loc) + return TRUE + +// Returns the data visible via a fission core control computer. +/obj/machinery/atmospherics/unary/fission_core/proc/build_ui_data(var/rod) + . = list() + .["core"] = "\ref[src]" + .["neutron_flux"] = neutron_flux + .["neutron_energy"] = neutron_energy + .["temperature"] = air_contents.temperature + .["control_rod_depth"] = control_rod_depth + for(var/obj/item/fuel_assembly/fa in fuel_rods) + .["rods"] += list(list("name" = "[fa.name]")) + var/list/rod_mats = list() + if(rod && length(fuel_rods) >= rod) + var/obj/item/fuel_assembly/current_rod = fuel_rods[rod] + if(istype(current_rod)) + for(var/mat_type in current_rod.matter) + var/decl/material/mat = GET_DECL(mat_type) + rod_mats += list(list("name" = mat.name, "amount" = current_rod.matter[mat_type])) + .["rod_exposed"] = fuel_rods[current_rod] + .["rod_materials"] = rod_mats + // Advanced diagnostics - used for precise balancing of the reaction + .["lastenergyincrease"] = last_neutron_energy_increase + .["lastenergydecrease"] = last_neutron_energy_decrease + .["netenergychange"] = net_neutron_energy_change + + .["lastfluxincrease"] = last_neutron_flux_increase + .["lastfluxdecrease"] = last_neutron_flux_decrease + .["netfluxchange"] = net_neutron_flux_change + +/obj/machinery/atmospherics/unary/fission_core/explosion_act(severity) + . = ..() + if(!QDELETED(src)) + damage += 10 * severity + +#undef RATIO_PER_NEUTRON +#undef MIN_RADIATION_ENERGY +#undef ACTIVE_THRESHOLD +#undef MAX_RODS +#undef JUMPED_FLUX +#undef JUMPED_ENERGY +#undef MAX_RADS + +#undef MAX_INTERACT_RATIO +#undef HI_NEUT_DIVISOR +#undef LO_NEUT_DIVISOR +#undef CONTROL_ROD_DIVISOR \ No newline at end of file diff --git a/code/modules/power/fission/core_control.dm b/code/modules/power/fission/core_control.dm new file mode 100644 index 000000000000..2b56f3d892ab --- /dev/null +++ b/code/modules/power/fission/core_control.dm @@ -0,0 +1,117 @@ +/obj/machinery/computer/fission + name = "fission control computer" + icon_keyboard = "power_key" + icon_screen = "fission_screen" + light_color = COLOR_ORANGE + idle_power_usage = 250 + active_power_usage = 500 + var/initial_id_tag = "fission" + + var/current_core = 1 // Which core connected to the console is being controlled/viewed. + var/current_rod = 0 // Which fuel rod in the selected core is being viewed. 0 if no rod is being viewed. + var/diagnostics = FALSE // Whether or not the control computer displays advanced diagnostics. + +/obj/machinery/computer/fission/Initialize() + . = ..() + set_extension(src, /datum/extension/local_network_member) + if(initial_id_tag) + var/datum/extension/local_network_member/fission = get_extension(src, /datum/extension/local_network_member) + fission.set_tag(null, initial_id_tag) + +/obj/machinery/computer/fission/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) + var/datum/extension/local_network_member/fission = get_extension(src, /datum/extension/local_network_member) + fission.get_new_tag(user) + return TRUE + + return ..() + +/obj/machinery/computer/fission/proc/build_ui_data() + . = list() + var/datum/extension/local_network_member/fission = get_extension(src, /datum/extension/local_network_member) + var/datum/local_network/lan = fission.get_local_network() + .["current_core"] = current_core + .["current_rod"] = current_rod + .["diagnostics"] = diagnostics + if(lan) + var/list/fission_cores = lan.get_devices(/obj/machinery/atmospherics/unary/fission_core) + if(!length(fission_cores)) + .["no_cores"] = 1 + return + current_core = clamp(current_core, 1, length(fission_cores)) + var/obj/machinery/atmospherics/unary/fission_core/selected_core = fission_cores[current_core] + if(istype(selected_core)) + if(selected_core.stat & (BROKEN|NOPOWER)) + .["error"] = 1 + return + . |= selected_core.build_ui_data(current_rod) + +/obj/machinery/computer/fission/OnTopic(var/mob/user, href_list, state) + var/datum/extension/local_network_member/fission = get_extension(src, /datum/extension/local_network_member) + var/datum/local_network/lan = fission.get_local_network() + if(href_list["change_core"]) + if(lan) + var/num_cores = length(lan.get_devices(/obj/machinery/atmospherics/unary/fission_core)) + if(num_cores) + current_core += text2num(href_list["change_core"]) + if(current_core > num_cores) + current_core = 1 + if(current_core < 1) + current_core = num_cores + return TOPIC_REFRESH + + if(href_list["toggle_diagnostics"]) + diagnostics = !diagnostics + return TOPIC_REFRESH + + if(href_list["machine"]) + var/obj/machinery/atmospherics/unary/fission_core/C = locate(href_list["machine"]) + if(!istype(C)) + return TOPIC_NOACTION + + if(!lan || !lan.is_connected(C)) + return TOPIC_NOACTION + + if(href_list["control_rod"]) + var/new_depth = input(user,"Enter the desired control rod depth between 0 and 1:" ,"Control Rod Depth", 0) as num|null + if(!CanInteract(user, state)) + return TOPIC_NOACTION + C.adjust_control_rods(clamp(new_depth, 0, 1)) + return TOPIC_REFRESH + + if(href_list["jump_start"]) + if(C.check_active()) + to_chat(user, SPAN_NOTICE("\The [C] is already active!")) + return TOPIC_NOACTION + C.jump_start() + return TOPIC_REFRESH + + if(href_list["rod"]) + var/new_rod = text2num(href_list["rod"]) + current_rod = (current_rod == new_rod ? 0 : new_rod) + return TOPIC_REFRESH + + if(href_list["eject_rod"]) + if(!C.eject_rod(current_rod)) + to_chat(user, SPAN_WARNING("You cannot eject rods from \the [C] while it is active!")) + return TOPIC_NOACTION + return TOPIC_REFRESH + + if(href_list["expose_rod"]) + if(!C.toggle_rod_exposure(current_rod)) + to_chat(user, SPAN_WARNING("You cannot unexpose a rod while \the [C] is active!")) + return TOPIC_NOACTION + return TOPIC_REFRESH + +/obj/machinery/computer/fission/ui_interact(var/mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/list/data = build_ui_data() + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "fission_core.tmpl", name, 400, 600) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/fission/interface_interact(var/mob/user) + ui_interact(user) + return TRUE diff --git a/code/modules/power/fission/fission_circuits.dm b/code/modules/power/fission/fission_circuits.dm new file mode 100644 index 000000000000..f36b48f2fa37 --- /dev/null +++ b/code/modules/power/fission/fission_circuits.dm @@ -0,0 +1,19 @@ +/obj/item/stock_parts/circuitboard/fission_core_control + name = "circuit board (fission core controller)" + build_path = /obj/machinery/computer/fission + origin_tech = @'{"programming":2,"engineering":3}' + +/obj/item/stock_parts/circuitboard/unary_atmos/fission_core + name = "circuit board (fission core)" + build_path = /obj/machinery/atmospherics/unary/fission_core + board_type = "machine" + origin_tech = @'{"engineering":2,"materials":2}' + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) + req_components = list( + /obj/item/stack/cable_coil = 20, + /obj/item/stock_parts/matter_bin = 2, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/micro_laser = 1 + ) \ No newline at end of file diff --git a/code/modules/power/fuel_assembly/fuel_assembly.dm b/code/modules/power/fuel_assembly/fuel_assembly.dm new file mode 100644 index 000000000000..0527ee149418 --- /dev/null +++ b/code/modules/power/fuel_assembly/fuel_assembly.dm @@ -0,0 +1,106 @@ +/obj/item/fuel_assembly + name = "fuel rod assembly" + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "fuel_assembly" + layer = 4 + abstract_type = /obj/item/fuel_assembly + max_health = 150 + + var/material_name + var/percent_depleted = 1 + var/radioactivity = 0 + var/luminescence = 0 + var/initial_amount + +// Unmeltable for the time being; TODO proper fix on dev. +/obj/item/fuel_assembly/handle_melting(list/meltable_materials) + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/fuel_assembly/Initialize(mapload, var/_material, var/list/makeup, var/_colour) + . = ..(mapload, _material) + LAZYINITLIST(matter) + + if(LAZYLEN(makeup)) + if(length(makeup) == 1) // Rod is only made from one material. + var/decl/material/mat = GET_DECL(makeup[1]) + SetName("[mat.use_name] fuel rod assembly") + desc = "A fuel rod for nuclear power production. This one is made from [mat.use_name]." + material_name = mat.use_name + else + desc = "A fuel rod for nuclear power production, made up from various materials." + material_name = "Mixed material" + + for(var/mat_p in makeup) + var/decl/material/mat = GET_DECL(mat_p) + matter[mat_p] = makeup[mat_p] + initial_amount += makeup[mat_p] + radioactivity = max(radioactivity, mat.radioactivity) + luminescence = max(luminescence, mat.luminescence) + else + initial_amount = SHEET_MATERIAL_AMOUNT * 5 + matter[material.type] = initial_amount + SetName("[material.use_name] fuel rod assembly") + desc = "A fuel rod for nuclear power production. This one is made from [material.use_name]." + material_name = material.use_name + if(material.radioactivity) + radioactivity = material.radioactivity + if(material.luminescence) + luminescence = material.luminescence + if(luminescence) + set_light(material.luminescence, material.luminescence, material.color) + if(radioactivity) + desc += " It is warm to the touch." + START_PROCESSING(SSobj, src) + update_icon() + +/obj/item/fuel_assembly/on_update_icon() + . = ..() + icon_state = "fuel_assembly" + if(material) + color = material.color + else if(length(matter)) + var/list/colors = list() + for(var/mat_p in matter) + var/decl/material/mat = GET_DECL(mat_p) + colors += mat.color + color = MixColors(colors) + var/image/I = image(icon, "fuel_assembly_bracket") + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/fuel_assembly/Process() + if(!radioactivity) + return PROCESS_KILL + + if(istype(loc, /turf)) + SSradiation.radiate(src, max(1,ceil(radioactivity/15))) + +/obj/item/fuel_assembly/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +// Mapper shorthand. +/obj/item/fuel_assembly/deuterium + material = /decl/material/gas/hydrogen/deuterium + +/obj/item/fuel_assembly/tritium + material = /decl/material/gas/hydrogen/tritium + +/obj/item/fuel_assembly/exotic_matter + material = /decl/material/solid/exotic_matter + +/obj/item/fuel_assembly/hydrogen + material = /decl/material/gas/hydrogen + +/obj/item/fuel_assembly/uranium + material = /decl/material/solid/metal/uranium + +/obj/item/fuel_assembly/plutonium + material = /decl/material/solid/metal/plutonium + +/obj/item/fuel_assembly/graphite + material = /decl/material/solid/graphite + +/obj/item/fuel_assembly/boron + material = /decl/material/solid/boron \ No newline at end of file diff --git a/code/modules/power/fuel_assembly/fuel_compressor.dm b/code/modules/power/fuel_assembly/fuel_compressor.dm new file mode 100644 index 000000000000..77e506b3883f --- /dev/null +++ b/code/modules/power/fuel_assembly/fuel_compressor.dm @@ -0,0 +1,144 @@ +#define MAX_ROD_MATERIAL 10000 + +/obj/machinery/fuel_compressor + name = "fuel compressor" + desc = "A machine used for the compression of fuel rods for nuclear power production." + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "fuel_compressor1" + density = TRUE + anchored = TRUE + layer = 4 + construct_state = /decl/machine_construction/default/panel_closed + var/list/stored_material = list() + var/list/rod_makeup = list() + +/obj/machinery/fuel_compressor/interface_interact(var/mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/fuel_compressor/ui_interact(var/mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/list/data = list() + for(var/mat_type in stored_material) + var/decl/material/mat = GET_DECL(mat_type) + data["stored_material"] += list(list("name" = mat.name, "amount" = stored_material[mat_type])) + + for(var/mat_type in rod_makeup) + var/decl/material/mat = GET_DECL(mat_type) + data["rod_makeup"] += list(list("name" = mat.name, "amount" = rod_makeup[mat_type])) + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "fuel_compressor.tmpl", name, 500, 600) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/fuel_compressor/OnTopic(user, href_list, state) + . = ..() + if(href_list["eject_material"]) + . = eject_material(href_list["eject_material"]) + if(href_list["make_rod"]) + . = make_rod() + if(href_list["change_makeup"]) + . = change_makeup(href_list["change_makeup"], user) + if(href_list["clear_makeup"]) + rod_makeup.Cut() + return TOPIC_REFRESH + +/obj/machinery/fuel_compressor/proc/eject_material(var/mat_name) + var/mat_type + for(var/mat_p in stored_material) + var/decl/material/mat = GET_DECL(mat_p) + if(mat.name == mat_name) + mat_type = mat.type + break + + if(!mat_type) + return TOPIC_HANDLED + + var/decl/material/mat = GET_DECL(mat_type) + if(mat && stored_material[mat_type] >= SHEET_MATERIAL_AMOUNT) + var/sheet_count = floor(stored_material[mat_type]/SHEET_MATERIAL_AMOUNT) + stored_material[mat_type] -= sheet_count * SHEET_MATERIAL_AMOUNT + SSmaterials.create_object(mat_type, get_turf(src), sheet_count) + if(isnull(stored_material[mat_type])) + stored_material -= mat_type + else if(!isnull(stored_material[mat_type])) + stored_material -= mat_type + + return TOPIC_REFRESH + +/obj/machinery/fuel_compressor/proc/make_rod() + var/total_matter = 0 + for(var/mat_p in rod_makeup) + total_matter += rod_makeup[mat_p] + if(total_matter > MAX_ROD_MATERIAL) + visible_message(SPAN_WARNING("\The [src] flashes an 'Over max material' error!")) + return TOPIC_HANDLED + if(rod_makeup[mat_p] > stored_material[mat_p]) + visible_message(SPAN_WARNING("\The [src] flashes an 'Insufficient Materials' error!")) + return TOPIC_HANDLED + + if(!LAZYLEN(rod_makeup) || !total_matter) + visible_message(SPAN_WARNING("\The [src] flashes a 'No Recipe' error!")) + return TOPIC_HANDLED + + for(var/mat_p in rod_makeup) + stored_material[mat_p] -= rod_makeup[mat_p] + if(stored_material[mat_p] == 0) + stored_material -= mat_p + + visible_message(SPAN_NOTICE("\The [src] compresses the material into a new fuel assembly.")) + new /obj/item/fuel_assembly(get_turf(src), null, rod_makeup) + return TOPIC_REFRESH + +/obj/machinery/fuel_compressor/proc/change_makeup(var/mat_name, var/mob/user) + var/mat_type + for(var/mat_p in stored_material) + var/decl/material/mat = GET_DECL(mat_p) + if(mat.name == mat_name) + mat_type = mat.type + break + + if(!mat_type) + return TOPIC_HANDLED + var/amt = input(user, "Enter the amount of this material per rod (Max [MAX_ROD_MATERIAL]):", "Fuel Rod Makeup", rod_makeup[mat_type]) as null|num + if(!CanInteract(user, DefaultTopicState())) + return TOPIC_HANDLED + amt = round(clamp(amt, 0, MAX_ROD_MATERIAL)) + if(!amt) + rod_makeup -= mat_type + return TOPIC_REFRESH + rod_makeup[mat_type] = amt + return TOPIC_REFRESH + +/obj/machinery/fuel_compressor/receive_mouse_drop(atom/dropping, mob/user, params) + if(user.incapacitated() || !user.Adjacent(src)) + return + return !add_material(dropping, user) + +/obj/machinery/fuel_compressor/attackby(var/obj/item/used_item, var/mob/user) + return add_material(used_item, user) || ..() + +/obj/machinery/fuel_compressor/proc/add_material(var/obj/item/thing, var/mob/user) + if(istype(thing) && thing.reagents && REAGENT_TOTAL_VOLUME(thing.reagents) && ATOM_IS_OPEN_CONTAINER(thing)) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(thing.reagents)) + var/taking_reagent = REAGENT_VOLUME(thing.reagents, reagent) + thing.remove_from_reagents(reagent, taking_reagent) + stored_material[reagent.type] += taking_reagent + + to_chat(user, SPAN_NOTICE("You add the contents of \the [thing] to \the [src]'s material buffer.")) + return TRUE + + if(istype(thing, /obj/item/stack/material)) + var/obj/item/stack/material/M = thing + var/decl/material/mat = M.get_material() + + var/taken = min(M.amount, 5) + M.use(taken) + stored_material[mat.type] += taken * SHEET_MATERIAL_AMOUNT + to_chat(user, SPAN_NOTICE("You add [taken] sheet\s of \the [thing] to \the [src]'s material buffer.")) + return TRUE + + return FALSE + +#undef MAX_ROD_MATERIAL \ No newline at end of file diff --git a/code/modules/power/fusion/_setup.dm b/code/modules/power/fusion/_setup.dm index c5a743864797..d6a1fde3058b 100644 --- a/code/modules/power/fusion/_setup.dm +++ b/code/modules/power/fusion/_setup.dm @@ -17,7 +17,7 @@ to_chat(usr, "Error: you are not an admin!") return - if(!(locate(/obj/machinery/power/fusion_core/mapped) in world)) + if(!(locate(/obj/machinery/fusion_core/mapped) in SSmachines.machinery)) to_chat(usr, "This map is not appropriate for this verb.") return @@ -31,16 +31,20 @@ log_and_message_admins("## FUSION CORE SETUP - Setup initiated by [usr].") - for(var/obj/machinery/fusion_fuel_injector/mapped/injector in SSmachines.machinery) - injector.cur_assembly = new /obj/item/fuel_assembly/deuterium(injector) - injector.BeginInjecting() - - var/obj/machinery/power/fusion_core/mapped/core = locate() in SSmachines.machinery + var/obj/machinery/fusion_core/mapped/core = locate() in SSmachines.machinery if(core.jumpstart(15000)) + + for(var/obj/machinery/fusion_fuel_injector/mapped/injector in SSmachines.machinery) + injector.cur_assembly = new /obj/item/fuel_assembly/deuterium(injector) + injector.BeginInjecting() + + for(var/obj/machinery/emitter/gyrotron/gyro in SSmachines.machinery) + gyro.activate(usr) + var/list/delayed_objects = list() // SETUP PHASE - for(var/obj/effect/engine_setup/S in world) + for(var/obj/effect/engine_setup/S in global.engine_setup_markers) var/result = S.activate(0) switch(result) if(SETUP_OK) diff --git a/code/modules/power/fusion/consoles/_consoles.dm b/code/modules/power/fusion/consoles/_consoles.dm index 319e435e7049..c5bae885e06c 100644 --- a/code/modules/power/fusion/consoles/_consoles.dm +++ b/code/modules/power/fusion/consoles/_consoles.dm @@ -14,19 +14,19 @@ fusion.set_tag(null, initial_id_tag) . = ..() -/obj/machinery/computer/fusion/get_codex_value() - return name - +/obj/machinery/computer/fusion/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) /obj/machinery/computer/fusion/proc/get_local_network() var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) return fusion.get_local_network() -/obj/machinery/computer/fusion/attackby(var/obj/item/thing, var/mob/user) - if(isMultitool(thing)) +/obj/machinery/computer/fusion/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) fusion.get_new_tag(user) - return + return TRUE else return ..() diff --git a/code/modules/power/fusion/consoles/core_control.dm b/code/modules/power/fusion/consoles/core_control.dm index f4bbe6897bd4..4c5e4d38a999 100644 --- a/code/modules/power/fusion/consoles/core_control.dm +++ b/code/modules/power/fusion/consoles/core_control.dm @@ -5,7 +5,7 @@ /obj/machinery/computer/fusion/core_control/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state) if(href_list["toggle_active"] || href_list["str"]) - var/obj/machinery/power/fusion_core/C = locate(href_list["machine"]) + var/obj/machinery/fusion_core/C = locate(href_list["machine"]) if(!istype(C)) return TOPIC_NOACTION @@ -13,7 +13,7 @@ if(!lan || !lan.is_connected(C)) return TOPIC_NOACTION - if(!C.check_core_status()) + if(C.stat & BROKEN) return TOPIC_NOACTION if(href_list["toggle_active"]) @@ -38,10 +38,11 @@ var/datum/local_network/lan = fusion.get_local_network() var/list/cores = list() if(lan) - var/list/fusion_cores = lan.get_devices(/obj/machinery/power/fusion_core) + var/list/fusion_cores = lan.get_devices(/obj/machinery/fusion_core) for(var/i = 1 to LAZYLEN(fusion_cores)) var/list/core = list() - var/obj/machinery/power/fusion_core/C = fusion_cores[i] + var/obj/machinery/fusion_core/C = fusion_cores[i] + var/datum/powernet/p_network = C.get_powernet() core["id"] = "#[i]" core["ref"] = "\ref[C]" core["field"] = !isnull(C.owned_field) @@ -49,11 +50,11 @@ core["size"] = C.owned_field ? "[C.owned_field.size] meter\s" : "Field offline." core["instability"] = C.owned_field ? "[C.owned_field.percent_unstable * 100]%" : "Field offline." core["temperature"] = C.owned_field ? "[C.owned_field.plasma_temperature + 295]K" : "Field offline." - core["powerstatus"] = "[C.avail()]/[C.active_power_usage] W" + core["powerstatus"] = "[p_network ? p_network.avail : 0]/[C.active_power_usage] W" var/fuel_string = "
    [thing]") if(istype(thing, /obj/item/paper)) - LAZYADD(dat, "ReadWrite") + LAZYADD(dat, "ReadWrite") else if(istype(thing, /obj/item/photo)) - LAZYADD(dat, "Look") - LAZYADD(dat, "Remove
    [capitalize(name)]


    [thing]Destroy[thing]Destroy[thing][book.dat][book.title][book.last_modified_ckey]Destroy[book.dat][book.title][book.last_modified_ckey]Destroy[book.dat][book.title][book.last_modified_ckey][save_graffiti.message][save_graffiti.author]Destroy[save_graffiti.message][save_graffiti.author]Destroy[save_graffiti.message][save_graffiti.author][paper.info][paper.name][paper.last_modified_ckey]Destroy[paper.info][paper.name][paper.last_modified_ckey]Destroy[paper.info][paper.name][paper.last_modified_ckey]
    " if(C.owned_field && LAZYLEN(C.owned_field.reactants)) for(var/reactant in C.owned_field.reactants) - var/decl/material/mat = decls_repository.get_decl(reactant) + var/decl/material/mat = GET_DECL(reactant) fuel_string += "" else fuel_string += "" diff --git a/code/modules/power/fusion/consoles/gyrotron_control.dm b/code/modules/power/fusion/consoles/gyrotron_control.dm index 20eacdc51221..8667035e7b99 100644 --- a/code/modules/power/fusion/consoles/gyrotron_control.dm +++ b/code/modules/power/fusion/consoles/gyrotron_control.dm @@ -9,12 +9,12 @@ if(href_list["modifypower"] || href_list["modifyrate"] || href_list["toggle"]) - var/obj/machinery/power/emitter/gyrotron/G = locate(href_list["machine"]) + var/obj/machinery/emitter/gyrotron/G = locate(href_list["machine"]) if(!istype(G)) return TOPIC_NOACTION var/datum/local_network/lan = get_local_network() - var/list/gyrotrons = lan.get_devices(/obj/machinery/power/emitter/gyrotron) + var/list/gyrotrons = lan.get_devices(/obj/machinery/emitter/gyrotron) if(!lan || !gyrotrons || !gyrotrons[G]) return TOPIC_NOACTION @@ -25,7 +25,7 @@ if(!new_val) to_chat(user, SPAN_WARNING("That's not a valid number.")) return TOPIC_NOACTION - G.mega_energy = Clamp(new_val, 1, 50) + G.mega_energy = clamp(new_val, 1, 50) G.change_power_consumption(G.mega_energy * 1500, POWER_USE_ACTIVE) return TOPIC_REFRESH @@ -36,7 +36,7 @@ if(!new_val) to_chat(user, SPAN_WARNING("That's not a valid number.")) return TOPIC_NOACTION - G.rate = Clamp(new_val, 2, 10) + G.rate = clamp(new_val, 2, 10) return TOPIC_REFRESH if(href_list["toggle"]) @@ -49,12 +49,12 @@ var/datum/local_network/lan = fusion.get_local_network() var/list/gyrotrons = list() if(lan && gyrotrons) - var/list/lan_gyrotrons = lan.get_devices(/obj/machinery/power/emitter/gyrotron) + var/list/lan_gyrotrons = lan.get_devices(/obj/machinery/emitter/gyrotron) for(var/i = 1 to LAZYLEN(lan_gyrotrons)) var/list/gyrotron = list() - var/obj/machinery/power/emitter/gyrotron/G = lan_gyrotrons[i] + var/obj/machinery/emitter/gyrotron/G = lan_gyrotrons[i] gyrotron["id"] = "#[i]" - gyrotron["ref"] = "\ref[G]" + gyrotron["ref"] = "\ref[G]" gyrotron["active"] = G.active gyrotron["firedelay"] = G.rate gyrotron["energy"] = G.mega_energy diff --git a/code/modules/power/fusion/consoles/injector_control.dm b/code/modules/power/fusion/consoles/injector_control.dm index 5088f9f70704..4e03f2fe076b 100644 --- a/code/modules/power/fusion/consoles/injector_control.dm +++ b/code/modules/power/fusion/consoles/injector_control.dm @@ -11,7 +11,7 @@ if(href_list["global_toggle"]) if(!lan || !fuel_injectors) return TOPIC_NOACTION - + for(var/obj/machinery/fusion_fuel_injector/F in fuel_injectors) if(F.injecting) F.StopInjecting() @@ -37,7 +37,7 @@ if(!new_injection_rate) to_chat(user, SPAN_WARNING("That's not a valid injection rate.")) return TOPIC_NOACTION - I.injection_rate = Clamp(new_injection_rate, 0, 100) / 100 + I.injection_rate = clamp(new_injection_rate, 0, 100) / 100 return TOPIC_REFRESH /obj/machinery/computer/fusion/fuel_control/build_ui_data() @@ -53,7 +53,7 @@ injector["id"] = "#[i]" injector["ref"] = "\ref[I]" injector["injecting"] = I.injecting - injector["fueltype"] = "[I.cur_assembly ? capitalize(I.cur_assembly.material.solid_name) : "No Fuel Inserted"]" + injector["fueltype"] = "[I.cur_assembly ? capitalize(I.cur_assembly.material_name) : "No Fuel Inserted"]" injector["depletion"] = "[I.cur_assembly ? (I.cur_assembly.percent_depleted * 100) : 100]%" injector["injection_rate"] = "[I.injection_rate * 100]%" injectors += list(injector) diff --git a/code/modules/power/fusion/core/_core.dm b/code/modules/power/fusion/core/_core.dm index ea7eea31feb8..e9b94cc7f7e3 100644 --- a/code/modules/power/fusion/core/_core.dm +++ b/code/modules/power/fusion/core/_core.dm @@ -1,52 +1,54 @@ #define MAX_FIELD_STR 10000 #define MIN_FIELD_STR 1 -/obj/machinery/power/fusion_core +/obj/machinery/fusion_core name = "\improper R-UST Mk. 8 Tokamak core" desc = "An enormous solenoid for generating extremely high power electromagnetic fields. It includes a kinetic energy harvester." icon = 'icons/obj/machines/power/fusion_core.dmi' icon_state = "core0" layer = ABOVE_HUMAN_LAYER - density = 1 + density = TRUE use_power = POWER_USE_IDLE idle_power_usage = 50 active_power_usage = 500 //multiplied by field strength - anchored = 0 + anchored = FALSE construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 - base_type = /obj/machinery/power/fusion_core + stat_immune = NOINPUT + base_type = /obj/machinery/fusion_core + stock_part_presets = list(/decl/stock_part_preset/terminal_setup) var/obj/effect/fusion_em_field/owned_field var/field_strength = 1//0.01 var/initial_id_tag -/obj/machinery/power/fusion_core/mapped - anchored = 1 +/obj/machinery/fusion_core/mapped + anchored = TRUE -/obj/machinery/power/fusion_core/Initialize() +/obj/machinery/fusion_core/Initialize() . = ..() - connect_to_network() set_extension(src, /datum/extension/local_network_member) if(initial_id_tag) var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) fusion.set_tag(null, initial_id_tag) -/obj/machinery/power/fusion_core/Process() - if((stat & BROKEN) || !powernet || !owned_field) +/obj/machinery/fusion_core/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + +/obj/machinery/fusion_core/Process() + if(use_power == POWER_USE_ACTIVE) + if((stat & BROKEN) || !owned_field) + update_use_power(POWER_USE_IDLE) + else + owned_field.handle_tick() + +/obj/machinery/fusion_core/update_use_power(new_use_power) + . = ..() + if(use_power == POWER_USE_IDLE && owned_field) Shutdown() -/obj/machinery/power/fusion_core/Topic(href, href_list) - if(..()) - return 1 - if(href_list["str"]) - var/dif = text2num(href_list["str"]) - field_strength = min(max(field_strength + dif, MIN_FIELD_STR), MAX_FIELD_STR) - change_power_consumption(500 * field_strength, POWER_USE_ACTIVE) - if(owned_field) - owned_field.ChangeFieldStrength(field_strength) - -/obj/machinery/power/fusion_core/proc/Startup() +/obj/machinery/fusion_core/proc/Startup() if(owned_field) return owned_field = new(loc, src) @@ -55,7 +57,7 @@ update_use_power(POWER_USE_ACTIVE) . = 1 -/obj/machinery/power/fusion_core/proc/Shutdown(var/force_rupture) +/obj/machinery/fusion_core/proc/Shutdown(var/force_rupture) if(owned_field) icon_state = "core0" if(force_rupture || owned_field.plasma_temperature > 1000) @@ -64,67 +66,60 @@ owned_field.RadiateAll() qdel(owned_field) owned_field = null - update_use_power(POWER_USE_IDLE) -/obj/machinery/power/fusion_core/proc/AddParticles(var/name, var/quantity = 1) +/obj/machinery/fusion_core/proc/AddParticles(var/name, var/quantity = 1) if(owned_field) owned_field.AddParticles(name, quantity) . = 1 -/obj/machinery/power/fusion_core/bullet_act(var/obj/item/projectile/Proj) +/obj/machinery/fusion_core/bullet_act(var/obj/item/projectile/Proj) if(owned_field) . = owned_field.bullet_act(Proj) -/obj/machinery/power/fusion_core/proc/set_strength(var/value) - value = Clamp(value, MIN_FIELD_STR, MAX_FIELD_STR) +/obj/machinery/fusion_core/proc/set_strength(var/value) + value = clamp(value, MIN_FIELD_STR, MAX_FIELD_STR) field_strength = value change_power_consumption(5 * value, POWER_USE_ACTIVE) if(owned_field) owned_field.ChangeFieldStrength(value) -/obj/machinery/power/fusion_core/physical_attack_hand(var/mob/user) - visible_message("\The [user] hugs \the [src] to make it feel better!") - if(owned_field) - Shutdown() +/obj/machinery/fusion_core/physical_attack_hand(var/mob/user) + visible_message(SPAN_NOTICE("\The [user] hugs \the [src] to make it feel better!")) + Shutdown() return TRUE -/obj/machinery/power/fusion_core/attackby(var/obj/item/W, var/mob/user) +/obj/machinery/fusion_core/attackby(var/obj/item/used_item, var/mob/user) if(owned_field) - to_chat(user,"Shut \the [src] off first!") - return + to_chat(user, SPAN_WARNING("Shut \the [src] off first!")) + return TRUE - if(isMultitool(W)) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) fusion.get_new_tag(user) - return - - else if(isWrench(W)) + return TRUE + + else if(IS_WRENCH(used_item)) anchored = !anchored playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) if(anchored) - user.visible_message("[user.name] secures [src.name] to the floor.", \ - "You secure the [src.name] to the floor.", \ - "You hear a ratchet") + user.visible_message("\The [user] secures \the [src] to the floor.", + "You secure \the [src] to the floor.", + "You hear a ratchet." + ) else - user.visible_message("[user.name] unsecures [src.name] from the floor.", \ - "You unsecure the [src.name] from the floor.", \ - "You hear a ratchet") - return + user.visible_message("\The [user] unsecures \the [src] from the floor.", + "You unsecure \the [src] from the floor.", + "You hear a ratchet." + ) + return TRUE return ..() -/obj/machinery/power/fusion_core/proc/jumpstart(var/field_temperature) - field_strength = 501 // Generally a good size. +/obj/machinery/fusion_core/proc/jumpstart(var/field_temperature) + field_strength = 200 // 3x3, generally a good size. Startup() if(!owned_field) return FALSE owned_field.plasma_temperature = field_temperature - return TRUE - -/obj/machinery/power/fusion_core/proc/check_core_status() - if(stat & BROKEN) - return FALSE - if(idle_power_usage > avail()) - return FALSE - . = TRUE + return TRUE \ No newline at end of file diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm index 60500190593f..f9c366bc4960 100644 --- a/code/modules/power/fusion/core/core_field.dm +++ b/code/modules/power/fusion/core/core_field.dm @@ -1,16 +1,19 @@ -#define FUSION_ENERGY_PER_K 20 -#define FUSION_INSTABILITY_DIVISOR 50000 -#define FUSION_RUPTURE_THRESHOLD 10000 -#define FUSION_REACTANT_CAP 10000 +#define FUSION_ENERGY_PER_K 20 +#define FUSION_INSTABILITY_DIVISOR 50000 +#define FUSION_RUPTURE_THRESHOLD 10000 +#define FUSION_FIELD_CAP_COEFF 5000 +#define FUSION_COHESION_LOSS_COEFF 3 +#define FUSION_COHESION_LOSS_LIMIT 4.5 /obj/effect/fusion_em_field name = "electromagnetic field" desc = "A coruscating, barely visible field of energy. It is shaped like a slightly flattened torus." icon = 'icons/obj/machines/power/fusion.dmi' icon_state = "emfield_s1" - alpha = 50 + alpha = 30 layer = 4 - light_color = COLOR_BLUE + light_color = COLOR_RED + color = COLOR_RED var/size = 1 var/energy = 0 @@ -19,8 +22,11 @@ var/field_strength = 0.01 var/tick_instability = 0 var/percent_unstable = 0 + var/field_cohesion = 100 //Should be 100-0. + var/fusion_reactant_cap + var/cohesion_regeneration = 1 - var/obj/machinery/power/fusion_core/owned_core + var/obj/machinery/fusion_core/owned_core var/list/reactants = list() var/list/particle_catchers = list() @@ -28,21 +34,23 @@ /obj/item/projectile, /obj/effect, /obj/structure/cable, - /obj/machinery/atmospherics + /obj/machinery/atmospherics, + /obj/machinery/air_sensor, + /obj/machinery/power/terminal ) var/light_min_range = 2 - var/light_min_power = 0.2 + var/light_min_power = 3 var/light_max_range = 12 - var/light_max_power = 1 + var/light_max_power = 12 var/last_range var/last_power -/obj/effect/fusion_em_field/Initialize(mapload, var/obj/machinery/power/fusion_core/new_owned_core) +/obj/effect/fusion_em_field/Initialize(mapload, var/obj/machinery/fusion_core/new_owned_core) . = ..() - set_light(light_min_power, light_min_range / 10, light_min_range) + set_light(light_min_range, light_min_power) last_range = light_min_range last_power = light_min_power @@ -79,11 +87,11 @@ catcher.SetSize((iter*2)+1) particle_catchers.Add(catcher) - START_PROCESSING(SSobj, src) + addtimer(CALLBACK(src, PROC_REF(update_light_colors)), 10 SECONDS, TIMER_LOOP) -/obj/effect/fusion_em_field/Process() +/obj/effect/fusion_em_field/proc/handle_tick() //make sure the field generator is still intact - if(!owned_core || QDELETED(owned_core)) + if(QDELETED(owned_core)) qdel(src) return @@ -105,7 +113,7 @@ React() // Dump power to our powernet. - owned_core.add_avail(FUSION_ENERGY_PER_K * plasma_temperature) + owned_core.generate_power(FUSION_ENERGY_PER_K * plasma_temperature) // Energy decay. if(plasma_temperature >= 1) @@ -118,35 +126,59 @@ var/amount = reactants[reactant] if(amount < 1) reactants.Remove(reactant) - else if(amount >= FUSION_REACTANT_CAP) + else if(amount >= fusion_reactant_cap) var/radiate = rand(3 * amount / 4, amount / 4) reactants[reactant] -= radiate radiation += radiate - var/use_range - var/use_power - if(plasma_temperature <= 6000) - use_range = light_min_range - use_power = light_min_power - else if(plasma_temperature >= 25000) - use_range = light_max_range - use_power = light_max_power - else - var/temp_mod = ((plasma_temperature-5000)/20000) - use_range = light_min_range + ceil((light_max_range-light_min_range)*temp_mod) - use_power = light_min_power + ceil((light_max_power-light_min_power)*temp_mod) - - if(last_range != use_range || last_power != use_power) - set_light(min(use_power, 1), use_range / 6, use_range) //cap first arg at 1 to avoid breaking lighting stuff. - last_range = use_range - last_power = use_power - check_instability() Radiate() + handle_cohesion() if(radiation) SSradiation.radiate(src, round(radiation*0.001)) return 1 +/obj/effect/fusion_em_field/proc/update_light_colors() + var/use_range + var/use_power + switch (plasma_temperature) + if (-INFINITY to 1000) + light_color = COLOR_RED + use_range = light_min_range + use_power = light_min_power + alpha = 30 + if (100000 to INFINITY) + light_color = COLOR_VIOLET + use_range = light_max_range + use_power = light_max_power + alpha = 230 + else + var/temp_mod = ((plasma_temperature-5000)/20000) + use_range = light_min_range + ceil((light_max_range-light_min_range)*temp_mod) + use_power = light_min_power + ceil((light_max_power-light_min_power)*temp_mod) + switch (plasma_temperature) + if (1000 to 6000) + light_color = COLOR_ORANGE + alpha = 50 + if (6000 to 20000) + light_color = COLOR_YELLOW + alpha = 80 + if (20000 to 50000) + light_color = COLOR_GREEN + alpha = 120 + if (50000 to 70000) + light_color = COLOR_CYAN + alpha = 160 + if (70000 to 100000) + light_color = COLOR_BLUE + alpha = 200 + + if (last_range != use_range || last_power != use_power || color != light_color) + color = light_color + set_light(use_range, min(use_power, 1)) + last_range = use_range + last_power = use_power + /obj/effect/fusion_em_field/proc/check_instability() if(tick_instability > 0) percent_unstable += (tick_instability*size)/FUSION_INSTABILITY_DIVISOR @@ -160,55 +192,47 @@ if(percent_unstable > 0) percent_unstable = max(0, percent_unstable-rand(0.01,0.03)) - if(percent_unstable >= 1) + if(field_cohesion == 0) owned_core.Shutdown(force_rupture=1) - else - if(percent_unstable > 0.5 && prob(percent_unstable*100)) - if(plasma_temperature < FUSION_RUPTURE_THRESHOLD) + + if(percent_unstable > 0.5 && prob(percent_unstable*100)) + if(plasma_temperature < FUSION_RUPTURE_THRESHOLD) + visible_message("\The [src] ripples uneasily, like a disturbed pond.") + else + var/flare + var/fuel_loss + if(percent_unstable < 0.7) visible_message("\The [src] ripples uneasily, like a disturbed pond.") + fuel_loss = prob(5) + else if(percent_unstable < 0.9) + visible_message("\The [src] undulates violently, shedding plumes of plasma!") + flare = prob(50) + fuel_loss = prob(20) else - var/flare - var/fuel_loss - var/rupture - if(percent_unstable < 0.7) - visible_message("\The [src] ripples uneasily, like a disturbed pond.") - fuel_loss = prob(5) - else if(percent_unstable < 0.9) - visible_message("\The [src] undulates violently, shedding plumes of plasma!") - flare = prob(50) - fuel_loss = prob(20) - rupture = prob(5) - else - visible_message("\The [src] is wracked by a series of horrendous distortions, buckling and twisting like a living thing!") - flare = 1 - fuel_loss = prob(50) - rupture = prob(25) - - if(rupture) - owned_core.Shutdown(force_rupture=1) - else - var/lost_plasma = (plasma_temperature*percent_unstable) - radiation += lost_plasma - if(flare) - radiation += plasma_temperature/2 - plasma_temperature -= lost_plasma - - if(fuel_loss) - for(var/particle in reactants) - var/lost_fuel = reactants[particle]*percent_unstable - radiation += lost_fuel - reactants[particle] -= lost_fuel - if(reactants[particle] <= 0) - reactants.Remove(particle) - Radiate() + visible_message("\The [src] is wracked by a series of horrendous distortions, buckling and twisting like a living thing!") + flare = 1 + fuel_loss = prob(50) + var/lost_plasma = (plasma_temperature*percent_unstable) + radiation += lost_plasma + if(flare) + radiation += plasma_temperature/2 + + if(fuel_loss) + for(var/particle in reactants) + var/lost_fuel = reactants[particle]*percent_unstable + radiation += lost_fuel + reactants[particle] -= lost_fuel + if(reactants[particle] <= 0) + reactants.Remove(particle) return /obj/effect/fusion_em_field/proc/is_shutdown_safe() return plasma_temperature < 1000 /obj/effect/fusion_em_field/proc/Rupture() + set waitfor = FALSE visible_message("\The [src] shudders like a dying animal before flaring to eye-searing brightness and rupturing!") - set_light(1, 0.1, 15, 2, "#ccccff") + set_light(15, 15, "#ccccff") empulse(get_turf(src), ceil(plasma_temperature/1000), ceil(plasma_temperature/300)) sleep(5) RadiateAll() @@ -233,6 +257,7 @@ calc_size = 13 field_strength = new_strength change_size(calc_size) + fusion_reactant_cap = field_strength * FUSION_FIELD_CAP_COEFF // Excess reactants will be ejected over the next few calls to Process() /obj/effect/fusion_em_field/proc/AddEnergy(var/a_energy, var/a_plasma_temperature) energy += a_energy @@ -281,9 +306,9 @@ Radiate() /obj/effect/fusion_em_field/proc/Radiate() - if(istype(loc, /turf)) + if(isturf(loc)) var/empsev = max(1, min(3, ceil(size/2))) - for(var/atom/movable/AM in range(max(1,Floor(size/2)), loc)) + for(var/atom/movable/AM in range(max(1,floor(size/2)), loc)) if(AM == src || AM == owned_core || !AM.simulated) continue @@ -304,16 +329,15 @@ var/datum/gas_mixture/environment = owned_core.loc.return_air() if(environment && environment.temperature < (T0C+1000)) // Putting an upper bound on it to stop it being used in a TEG. environment.add_thermal_energy(plasma_temperature*20000) - radiation = 0 /obj/effect/fusion_em_field/proc/change_size(var/newsize = 1) var/changed = 0 var/static/list/size_to_icon = list( - "3" = 'icons/effects/96x96.dmi', - "5" = 'icons/effects/160x160.dmi', - "7" = 'icons/effects/224x224.dmi', - "9" = 'icons/effects/288x288.dmi', - "11" = 'icons/effects/352x352.dmi', + "3" = 'icons/effects/96x96.dmi', + "5" = 'icons/effects/160x160.dmi', + "7" = 'icons/effects/224x224.dmi', + "9" = 'icons/effects/288x288.dmi', + "11" = 'icons/effects/352x352.dmi', "13" = 'icons/effects/416x416.dmi' ) @@ -333,6 +357,7 @@ //the !!fun!! part /obj/effect/fusion_em_field/proc/React() + set waitfor = FALSE //loop through the reactants in random order var/list/react_pool = reactants.Copy() @@ -341,7 +366,7 @@ //determine a random amount to actually react this cycle, and remove it from the standard pool //this is a hack, and quite nonrealistic :( for(var/reactant in react_pool) - react_pool[reactant] = rand(Floor(react_pool[reactant]/2),react_pool[reactant]) + react_pool[reactant] = rand(floor(react_pool[reactant]/2),react_pool[reactant]) reactants[reactant] -= react_pool[reactant] if(!react_pool[reactant]) react_pool -= reactant @@ -398,7 +423,7 @@ continue //randomly determined amount to react - var/amount_reacting = rand(1, max_num_reactants) + var/amount_reacting = max_num_reactants //removing the reacting substances from the list of substances that are primed to react this cycle //if there aren't enough of that substance (there should be) then modify the reactant amounts accordingly @@ -449,12 +474,10 @@ /obj/effect/fusion_em_field/Destroy() set_light(0) RadiateAll() - for(var/obj/effect/fusion_particle_catcher/catcher in particle_catchers) - qdel(catcher) + QDEL_NULL_LIST(particle_catchers) if(owned_core) owned_core.owned_field = null owned_core = null - STOP_PROCESSING(SSobj, src) . = ..() /obj/effect/fusion_em_field/bullet_act(var/obj/item/projectile/Proj) @@ -462,7 +485,10 @@ update_icon() return 0 +/obj/effect/fusion_em_field/proc/handle_cohesion() + field_cohesion = clamp(((field_cohesion + cohesion_regeneration) - clamp(percent_unstable*FUSION_COHESION_LOSS_COEFF, 0, FUSION_COHESION_LOSS_LIMIT)),0,100) + #undef FUSION_HEAT_CAP #undef FUSION_INSTABILITY_DIVISOR #undef FUSION_RUPTURE_THRESHOLD -#undef FUSION_REACTANT_CAP +#undef FUSION_FIELD_CAP_COEFF diff --git a/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm b/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm deleted file mode 100644 index b2f3c8b80cdb..000000000000 --- a/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm +++ /dev/null @@ -1,56 +0,0 @@ -/obj/item/fuel_assembly - name = "fuel rod assembly" - icon = 'icons/obj/machines/power/fusion.dmi' - icon_state = "fuel_assembly" - layer = 4 - - var/material_name - var/percent_depleted = 1 - var/list/rod_quantities = list() - var/radioactivity = 0 - var/initial_amount - -/obj/item/fuel_assembly/Initialize(mapload, var/_material, var/_colour) - . = ..(mapload, _material) - initial_amount = SHEET_MATERIAL_AMOUNT * 5 // Fuel compressor eats 5 sheets. - SetName("[material.use_name] fuel rod assembly") - desc = "A fuel rod for a fusion reactor. This one is made from [material.use_name]." - if(material.radioactivity) - radioactivity = material.radioactivity - desc += " It is warm to the touch." - START_PROCESSING(SSobj, src) - if(material.luminescence) - set_light(material.luminescence, material.luminescence, material.color) - rod_quantities[material.type] = initial_amount - update_icon() - -/obj/item/fuel_assembly/on_update_icon() - icon_state = "fuel_assembly" - color = material.color - var/image/I = image(icon, "fuel_assembly_bracket") - I.appearance_flags |= RESET_COLOR - overlays = list(I) - -/obj/item/fuel_assembly/Process() - if(!radioactivity) - return PROCESS_KILL - - if(istype(loc, /turf)) - SSradiation.radiate(src, max(1,ceil(radioactivity/15))) - -/obj/item/fuel_assembly/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -// Mapper shorthand. -/obj/item/fuel_assembly/deuterium - material = /decl/material/gas/hydrogen/deuterium - -/obj/item/fuel_assembly/tritium - material = /decl/material/gas/hydrogen/tritium - -/obj/item/fuel_assembly/supermatter - material = /decl/material/solid/exotic_matter - -/obj/item/fuel_assembly/hydrogen - material = /decl/material/gas/hydrogen diff --git a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm deleted file mode 100644 index f9d910e35fa1..000000000000 --- a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm +++ /dev/null @@ -1,56 +0,0 @@ -// 5 sheets == ~12500 matter units == ~100u reagents -// Try to avoid letting people produce more material -// with the kinetic harvester than they put into the -// field in the first place. - -/obj/machinery/fusion_fuel_compressor - name = "fuel compressor" - icon = 'icons/obj/machines/power/fusion.dmi' - icon_state = "fuel_compressor1" - density = 1 - anchored = 1 - layer = 4 - construct_state = /decl/machine_construction/default/panel_closed - -/obj/machinery/fusion_fuel_compressor/MouseDrop_T(var/atom/movable/target, var/mob/user) - if(user.incapacitated() || !user.Adjacent(src)) - return - return do_fuel_compression(target, user) - -/obj/machinery/fusion_fuel_compressor/attackby(var/obj/item/thing, var/mob/user) - return do_fuel_compression(thing, user) || ..() - -/obj/machinery/fusion_fuel_compressor/proc/do_fuel_compression(var/obj/item/thing, var/mob/user) - if(istype(thing) && thing.reagents && thing.reagents.total_volume && ATOM_IS_OPEN_CONTAINER(thing)) - if(LAZYLEN(thing.reagents.reagent_volumes) > 1) - to_chat(user, "The contents of \the [thing] are impure and cannot be used as fuel.") - return 1 - if(thing.reagents.total_volume < 100) - to_chat(user, "You need at least one hundred units of material to form a fuel rod.") - return 1 - var/decl/material/R = decls_repository.get_decl(thing.reagents.reagent_volumes[1]) - visible_message("\The [src] compresses the contents of \the [thing] into a new fuel assembly.") - var/obj/item/fuel_assembly/F = new(get_turf(src), R.type, R.color) - thing.reagents.remove_reagent(R.type, 100) - user.put_in_hands(F) - return 1 - else if(istype(thing, /obj/machinery/power/supermatter/shard)) - var/obj/item/fuel_assembly/F = new(get_turf(src), /decl/material/solid/exotic_matter) - visible_message("\The [src] compresses the \[thing] into a new fuel assembly.") - qdel(thing) - user.put_in_hands(F) - return 1 - else if(istype(thing, /obj/item/stack/material)) - var/obj/item/stack/material/M = thing - var/decl/material/mat = M.get_material() - if(!(mat.flags & MAT_FLAG_FUSION_FUEL)) - to_chat(user, "It would be pointless to make a fuel rod out of [mat.use_name].") - return - if(!M.use(5)) - to_chat(user, "You need at least five [mat.sheet_plural_name] to make a fuel rod.") - return - var/obj/item/fuel_assembly/F = new(get_turf(src), mat.type) - visible_message("\The [src] compresses the [mat.use_name] into a new fuel assembly.") - user.put_in_hands(F) - return 1 - return 0 diff --git a/code/modules/power/fusion/fuel_assembly/fuel_injector.dm b/code/modules/power/fusion/fuel_injector/fuel_injector.dm similarity index 78% rename from code/modules/power/fusion/fuel_assembly/fuel_injector.dm rename to code/modules/power/fusion/fuel_injector/fuel_injector.dm index 744cdf0ebb30..111c4f73fe12 100644 --- a/code/modules/power/fusion/fuel_assembly/fuel_injector.dm +++ b/code/modules/power/fusion/fuel_injector/fuel_injector.dm @@ -2,14 +2,13 @@ name = "fuel injector" icon = 'icons/obj/machines/power/fusion.dmi' icon_state = "injector0" - density = 1 - anchored = 0 + density = TRUE + anchored = FALSE initial_access = list(access_engine) idle_power_usage = 10 active_power_usage = 500 construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 base_type = /obj/machinery/fusion_fuel_injector var/fuel_usage = 0.001 @@ -25,6 +24,10 @@ fusion.set_tag(null, initial_id_tag) . = ..() +/obj/machinery/fusion_fuel_injector/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + /obj/machinery/fusion_fuel_injector/Destroy() if(cur_assembly) cur_assembly.dropInto(loc) @@ -32,7 +35,7 @@ . = ..() /obj/machinery/fusion_fuel_injector/mapped - anchored = 1 + anchored = TRUE /obj/machinery/fusion_fuel_injector/Process() if(injecting) @@ -41,41 +44,41 @@ else Inject() -/obj/machinery/fusion_fuel_injector/attackby(obj/item/W, mob/user) +/obj/machinery/fusion_fuel_injector/attackby(obj/item/used_item, mob/user) - if(isMultitool(W)) - var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member) - lanm.set_tag(null, initial_id_tag) - return + if(IS_MULTITOOL(used_item)) + var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) + fusion.get_new_tag(user) + return TRUE - if(istype(W, /obj/item/fuel_assembly)) + if(istype(used_item, /obj/item/fuel_assembly)) if(injecting) to_chat(user, "Shut \the [src] off before playing with the fuel rod!") - return - if(!user.unEquip(W, src)) - return + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE if(cur_assembly) - visible_message("\The [user] swaps \the [src]'s [cur_assembly] for \a [W].") + visible_message("\The [user] swaps \the [src]'s [cur_assembly] for \a [used_item].") else - visible_message("\The [user] inserts \a [W] into \the [src].") + visible_message("\The [user] inserts \a [used_item] into \the [src].") if(cur_assembly) cur_assembly.dropInto(loc) user.put_in_hands(cur_assembly) - cur_assembly = W - return + cur_assembly = used_item + return TRUE - if(isWrench(W)) + if(IS_WRENCH(used_item)) if(injecting) to_chat(user, "Shut \the [src] off first!") - return + return TRUE anchored = !anchored playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) if(anchored) user.visible_message("\The [user] secures \the [src] to the floor.") else user.visible_message("\The [user] unsecures \the [src] from the floor.") - return + return TRUE return ..() @@ -111,18 +114,18 @@ return if(cur_assembly) var/amount_left = 0 - for(var/reagent in cur_assembly.rod_quantities) - if(cur_assembly.rod_quantities[reagent] > 0) - var/amount = cur_assembly.rod_quantities[reagent] * fuel_usage * injection_rate + for(var/mat in cur_assembly.matter) + if(cur_assembly.matter[mat] > 0) + var/amount = cur_assembly.matter[mat] * fuel_usage * injection_rate if(amount < 1) amount = 1 var/obj/effect/accelerated_particle/A = new/obj/effect/accelerated_particle(get_turf(src), dir) - A.particle_type = reagent + A.particle_type = mat A.additional_particles = amount A.move(1) if(cur_assembly) - cur_assembly.rod_quantities[reagent] -= amount - amount_left += cur_assembly.rod_quantities[reagent] + cur_assembly.matter[mat] -= amount + amount_left += cur_assembly.matter[mat] if(cur_assembly) cur_assembly.percent_depleted = amount_left / cur_assembly.initial_amount flick("injector-emitting",src) diff --git a/code/modules/power/fusion/fusion_circuits.dm b/code/modules/power/fusion/fusion_circuits.dm index 2ac2b49c227a..b03d6a03616d 100644 --- a/code/modules/power/fusion/fusion_circuits.dm +++ b/code/modules/power/fusion/fusion_circuits.dm @@ -1,47 +1,41 @@ /obj/item/stock_parts/circuitboard/fusion/core_control - name = T_BOARD("fusion core controller") + name = "circuitboard (fusion core controller)" build_path = /obj/machinery/computer/fusion/core_control - origin_tech = "{'programming':4,'engineering':4}" + origin_tech = @'{"programming":4,"engineering":4}' /obj/item/stock_parts/circuitboard/kinetic_harvester - name = T_BOARD("kinetic harvester") + name = "circuitboard (kinetic harvester)" build_path = /obj/machinery/kinetic_harvester board_type = "machine" - origin_tech = "{'programming':4,'engineering':4,'materials':4}" + origin_tech = @'{"programming":4,"engineering":4,"materials":4}' + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1 + ) req_components = list( /obj/item/stock_parts/manipulator/pico = 2, /obj/item/stock_parts/matter_bin/super = 1, - /obj/item/stock_parts/console_screen = 1, /obj/item/stack/cable_coil = 5 - ) - -/obj/item/stock_parts/circuitboard/fusion_fuel_compressor - name = T_BOARD("fusion fuel compressor") - build_path = /obj/machinery/fusion_fuel_compressor - board_type = "machine" - origin_tech = "{'powerstorage':3,'engineering':4,'materials':4}" - req_components = list( - /obj/item/stock_parts/manipulator/pico = 2, - /obj/item/stock_parts/matter_bin/super = 2, - /obj/item/stock_parts/console_screen = 1, - /obj/item/stack/cable_coil = 5 - ) + ) /obj/item/stock_parts/circuitboard/fusion_fuel_control - name = T_BOARD("fusion fuel controller") + name = "circuitboard (fusion fuel controller)" build_path = /obj/machinery/computer/fusion/fuel_control - origin_tech = "{'programming':4,'engineering':4}" + origin_tech = @'{"programming":4,"engineering":4}' /obj/item/stock_parts/circuitboard/gyrotron_control - name = T_BOARD("gyrotron controller") + name = "circuitboard (gyrotron controller)" build_path = /obj/machinery/computer/fusion/gyrotron - origin_tech = "{'programming':4,'engineering':4}" + origin_tech = @'{"programming":4,"engineering":4}' /obj/item/stock_parts/circuitboard/fusion_core - name = T_BOARD("fusion core") - build_path = /obj/machinery/power/fusion_core + name = "circuitboard (fusion core)" + build_path = /obj/machinery/fusion_core board_type = "machine" - origin_tech = "{'wormholes':2,'magnets':4,'powerstorage':4}" + origin_tech = @'{"wormholes":2,"magnets":4,"powerstorage":4}' + additional_spawn_components = list( + /obj/item/stock_parts/power/terminal = 1 + ) req_components = list( /obj/item/stock_parts/manipulator/pico = 2, /obj/item/stock_parts/micro_laser/ultra = 1, @@ -51,10 +45,10 @@ ) /obj/item/stock_parts/circuitboard/fusion_injector - name = T_BOARD("fusion fuel injector") + name = "circuitboard (fusion fuel injector)" build_path = /obj/machinery/fusion_fuel_injector board_type = "machine" - origin_tech = "{'powerstorage':3,'engineering':4,'materials':4}" + origin_tech = @'{"powerstorage":3,"engineering":4,"materials":4}' req_components = list( /obj/item/stock_parts/manipulator/pico = 2, /obj/item/stock_parts/scanning_module/phasic = 1, @@ -64,11 +58,14 @@ ) /obj/item/stock_parts/circuitboard/gyrotron - name = T_BOARD("gyrotron") - build_path = /obj/machinery/power/emitter/gyrotron + name = "circuitboard (gyrotron)" + build_path = /obj/machinery/emitter/gyrotron board_type = "machine" - origin_tech = "{'powerstorage':4,'engineering':4}" + origin_tech = @'{"powerstorage":4,"engineering":4}' + additional_spawn_components = list( + /obj/item/stock_parts/power/terminal = 1 + ) req_components = list( /obj/item/stack/cable_coil = 20, /obj/item/stock_parts/micro_laser/ultra = 2 - ) + ) \ No newline at end of file diff --git a/code/modules/power/fusion/fusion_particle_catcher.dm b/code/modules/power/fusion/fusion_particle_catcher.dm index 982156d5edfe..fc23d2ce3044 100644 --- a/code/modules/power/fusion/fusion_particle_catcher.dm +++ b/code/modules/power/fusion/fusion_particle_catcher.dm @@ -1,9 +1,11 @@ /obj/effect/fusion_particle_catcher icon = 'icons/effects/effects.dmi' - density = 1 - anchored = 1 - invisibility = 101 + density = TRUE + anchored = TRUE + invisibility = INVISIBILITY_ABSTRACT light_color = COLOR_BLUE + is_spawnable_type = FALSE // invalid without parent passed + var/obj/effect/fusion_em_field/parent var/mysize = 0 @@ -37,4 +39,7 @@ return 0 /obj/effect/fusion_particle_catcher/CanPass(var/atom/movable/mover, var/turf/target, var/height=0, var/air_group=0) - return ismob(mover) + return !density || (!istype(mover, /obj/item/projectile) && !istype(mover, /obj/effect/accelerated_particle)) + +/obj/effect/fusion_particle_catcher/CanFluidPass(var/coming_from) + return TRUE diff --git a/code/modules/power/fusion/fusion_reactions.dm b/code/modules/power/fusion/fusion_reactions.dm index acfc59d31581..5ff951b477b0 100644 --- a/code/modules/power/fusion/fusion_reactions.dm +++ b/code/modules/power/fusion/fusion_reactions.dm @@ -1,7 +1,8 @@ +#define FUSION_PROCESSING_TIME_MULT 2 // SSmachines.wait / (1 SECOND) - previous values were intended for SSobj 1-second wait. /decl/fusion_reaction - var/p_react = "" // Primary reactant. - var/s_react = "" // Secondary reactant. + var/p_react // Primary reactant. + var/s_react // Secondary reactant. var/minimum_energy_level = 1 var/energy_consumption = 0 var/energy_production = 0 @@ -11,6 +12,19 @@ var/minimum_reaction_temperature = 100 var/priority = 100 var/hidden_from_codex = FALSE + var/codex_name + +/decl/fusion_reaction/validate() + . = ..() + if(p_react && !ispath(p_react, /decl/material)) + . += "invalid primary reactant type [p_react]." + if(s_react && !ispath(s_react, /decl/material)) + . += "invalid secondary reactant type [s_react]." + for(var/product in products) + if(!ispath(product, /decl/material)) + . += "invalid product type [product || "(NULL)"]." + else if(products[product] <= 0) + . += "invalid product amount for [product]." /decl/fusion_reaction/proc/handle_reaction_special(var/obj/effect/fusion_em_field/holder) return 0 @@ -20,110 +34,108 @@ /decl/fusion_reaction/hydrogen_hydrogen p_react = /decl/material/gas/hydrogen s_react = /decl/material/gas/hydrogen - energy_consumption = 1 - energy_production = 2 + energy_consumption = 1 * FUSION_PROCESSING_TIME_MULT + energy_production = 2 * FUSION_PROCESSING_TIME_MULT products = list(/decl/material/gas/helium = 1) priority = 10 /decl/fusion_reaction/deuterium_deuterium p_react = /decl/material/gas/hydrogen/deuterium s_react = /decl/material/gas/hydrogen/deuterium - energy_consumption = 1 - energy_production = 2 + energy_consumption = 1 * FUSION_PROCESSING_TIME_MULT + energy_production = 2 * FUSION_PROCESSING_TIME_MULT priority = 0 // Advanced production reactions (todo) /decl/fusion_reaction/deuterium_helium p_react = /decl/material/gas/hydrogen/deuterium s_react = /decl/material/gas/helium - energy_consumption = 1 - energy_production = 5 + energy_consumption = 1 * FUSION_PROCESSING_TIME_MULT + energy_production = 5 * FUSION_PROCESSING_TIME_MULT radiation = 2 /decl/fusion_reaction/deuterium_tritium p_react = /decl/material/gas/hydrogen/deuterium s_react = /decl/material/gas/hydrogen/tritium - energy_consumption = 1 - energy_production = 1 + energy_consumption = 1 * FUSION_PROCESSING_TIME_MULT + energy_production = 1 * FUSION_PROCESSING_TIME_MULT + instability = 0.5 * FUSION_PROCESSING_TIME_MULT + radiation = 3 * FUSION_PROCESSING_TIME_MULT products = list(/decl/material/gas/helium = 1) - instability = 0.5 - radiation = 3 /decl/fusion_reaction/deuterium_lithium p_react = /decl/material/gas/hydrogen/deuterium s_react = /decl/material/solid/lithium - energy_consumption = 2 - energy_production = 0 - radiation = 3 + energy_production = 0 + energy_consumption = 2 * FUSION_PROCESSING_TIME_MULT + radiation = 3 * FUSION_PROCESSING_TIME_MULT + instability = 1 * FUSION_PROCESSING_TIME_MULT products = list(/decl/material/gas/hydrogen/tritium= 1) - instability = 1 // Unideal/material production reactions /decl/fusion_reaction/oxygen_oxygen p_react = /decl/material/gas/oxygen s_react = /decl/material/gas/oxygen - energy_consumption = 10 - energy_production = 0 - instability = 5 - radiation = 5 - products = list(MAT_SILICON = 1) + energy_production = 0 + energy_consumption = 10 * FUSION_PROCESSING_TIME_MULT + instability = 5 * FUSION_PROCESSING_TIME_MULT + radiation = 5 * FUSION_PROCESSING_TIME_MULT + products = list(/decl/material/solid/silicon = 1) /decl/fusion_reaction/iron_iron p_react = /decl/material/solid/metal/iron s_react = /decl/material/solid/metal/iron products = list(/decl/material/solid/metal/silver = 10, /decl/material/solid/metal/gold = 10, /decl/material/solid/metal/platinum = 10) // Not realistic but w/e - energy_consumption = 10 - energy_production = 0 - instability = 2 + energy_production = 0 + energy_consumption = 10 * FUSION_PROCESSING_TIME_MULT + instability = 2 * FUSION_PROCESSING_TIME_MULT minimum_reaction_temperature = 10000 // VERY UNIDEAL REACTIONS. -/decl/fusion_reaction/helium_supermatter +/decl/fusion_reaction/helium_exotic_matter p_react = /decl/material/solid/exotic_matter s_react = /decl/material/gas/helium energy_consumption = 0 - energy_production = 5 - radiation = 40 - instability = 20 + energy_production = 5 * FUSION_PROCESSING_TIME_MULT + radiation = 40 * FUSION_PROCESSING_TIME_MULT + instability = 20 * FUSION_PROCESSING_TIME_MULT hidden_from_codex = TRUE -/decl/fusion_reaction/helium_supermatter/handle_reaction_special(var/obj/effect/fusion_em_field/holder) - - wormhole_event(GetConnectedZlevels(holder)) +/decl/fusion_reaction/helium_exotic_matter/handle_reaction_special(var/obj/effect/fusion_em_field/holder) + set waitfor = FALSE + . = 1 + var/datum/event/wormholes/WM = new /datum/event/wormholes(new /datum/event_meta(EVENT_LEVEL_MAJOR)) + WM.setup(affected_z_levels = SSmapping.get_connected_levels(holder)) var/turf/origin = get_turf(holder) holder.Rupture() qdel(holder) var/radiation_level = rand(100, 200) - // Copied from the SM for proof of concept. //Not any more --Cirra //Use the whole z proc --Leshana - SSradiation.z_radiate(locate(1, 1, holder.z), radiation_level, 1) + SSradiation.z_radiate(origin, radiation_level, respect_maint = TRUE) - for(var/mob/living/mob in GLOB.living_mob_list_) - var/turf/T = get_turf(mob) + for(var/mob/living/human/H in global.living_mob_list_) + var/turf/T = get_turf(H) if(T && (holder.z == T.z)) - if(istype(mob, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = mob - H.hallucination(rand(100,150), 51) + H.set_hallucination(rand(100,150), 51) for(var/obj/machinery/fusion_fuel_injector/I in range(world.view, origin)) - if(I.cur_assembly && I.cur_assembly.material && I.cur_assembly.material.type == /decl/material/solid/exotic_matter) + if(I.cur_assembly && I.cur_assembly.material && I.cur_assembly.material.type == p_react) explosion(get_turf(I), 1, 2, 3) - spawn(5) - if(I && I.loc) - qdel(I) + if(!QDELETED(I)) + addtimer(CALLBACK(I, TYPE_PROC_REF(/atom, physically_destroyed)), 0.5 SECONDS) sleep(5) explosion(origin, 1, 2, 5) - return 1 - // High end reactions. /decl/fusion_reaction/boron_hydrogen p_react = /decl/material/solid/boron s_react = /decl/material/gas/hydrogen minimum_energy_level = FUSION_HEAT_CAP * 0.5 - energy_consumption = 3 - energy_production = 15 - radiation = 3 - instability = 3 + energy_consumption = 3 * FUSION_PROCESSING_TIME_MULT + energy_production = 15 * FUSION_PROCESSING_TIME_MULT + radiation = 3 * FUSION_PROCESSING_TIME_MULT + instability = 3 * FUSION_PROCESSING_TIME_MULT + +#undef FUSION_PROCESSING_TIME_MULT diff --git a/code/modules/power/fusion/gyrotron/gyrotron.dm b/code/modules/power/fusion/gyrotron/gyrotron.dm index 70967d972d76..f70c73ffb5d1 100644 --- a/code/modules/power/fusion/gyrotron/gyrotron.dm +++ b/code/modules/power/fusion/gyrotron/gyrotron.dm @@ -1,9 +1,9 @@ #define GYRO_POWER 25000 -/obj/machinery/power/emitter/gyrotron +/obj/machinery/emitter/gyrotron name = "gyrotron" icon = 'icons/obj/machines/power/fusion.dmi' - desc = "It is a heavy duty industrial gyrotron suited for powering fusion reactors." + desc = "It is a heavy-duty industrial gyrotron suited for powering fusion reactors." icon_state = "emitter-off" initial_access = list(access_engine) use_power = POWER_USE_IDLE @@ -15,16 +15,15 @@ construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = list( - /obj/item/stock_parts/radio/receiver, + /obj/item/stock_parts/radio/receiver ) - stat_immune = 0 - base_type = /obj/machinery/power/emitter/gyrotron + base_type = /obj/machinery/emitter/gyrotron -/obj/machinery/power/emitter/gyrotron/anchored - anchored = 1 +/obj/machinery/emitter/gyrotron/anchored + anchored = TRUE state = 2 -/obj/machinery/power/emitter/gyrotron/Initialize() +/obj/machinery/emitter/gyrotron/Initialize() set_extension(src, /datum/extension/local_network_member) if(initial_id_tag) var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) @@ -32,32 +31,37 @@ change_power_consumption(mega_energy * GYRO_POWER, POWER_USE_ACTIVE) . = ..() -/obj/machinery/power/emitter/gyrotron/Process() +/obj/machinery/emitter/gyrotron/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + +/obj/machinery/emitter/gyrotron/Process() change_power_consumption(mega_energy * GYRO_POWER, POWER_USE_ACTIVE) . = ..() -/obj/machinery/power/emitter/gyrotron/get_rand_burst_delay() +/obj/machinery/emitter/gyrotron/get_rand_burst_delay() return rate*10 -/obj/machinery/power/emitter/gyrotron/get_burst_delay() +/obj/machinery/emitter/gyrotron/get_burst_delay() return rate*10 -/obj/machinery/power/emitter/gyrotron/get_emitter_beam() - var/obj/item/projectile/beam/emitter/E = ..() - E.damage = mega_energy * 50 - return E +/obj/machinery/emitter/gyrotron/get_emitter_beam() + var/obj/item/projectile/beam/emitter/beam = ..() + if(istype(beam)) + beam.damage = mega_energy * 50 + return beam -/obj/machinery/power/emitter/gyrotron/on_update_icon() - if (active && powernet && avail(active_power_usage)) +/obj/machinery/emitter/gyrotron/on_update_icon() + if (active && (can_use_power_oneoff(active_power_usage) <= 0)) icon_state = "emitter-on" else icon_state = "emitter-off" -/obj/machinery/power/emitter/gyrotron/attackby(var/obj/item/W, var/mob/user) - if(isMultitool(W)) +/obj/machinery/emitter/gyrotron/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/fusion = get_extension(src, /datum/extension/local_network_member) fusion.get_new_tag(user) - return + return TRUE return ..() #undef GYRO_POWER diff --git a/code/modules/power/fusion/kinetic_harvester.dm b/code/modules/power/fusion/kinetic_harvester.dm index efff283ea6ba..f9273dc7850c 100644 --- a/code/modules/power/fusion/kinetic_harvester.dm +++ b/code/modules/power/fusion/kinetic_harvester.dm @@ -6,14 +6,15 @@ use_power = POWER_USE_IDLE icon = 'icons/obj/kinetic_harvester.dmi' icon_state = "off" - var/initial_id_tag - var/list/stored = list() - var/list/harvesting = list() - var/obj/machinery/power/fusion_core/harvest_from construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 + var/initial_id_tag + var/list/stored = list() + var/list/harvesting = list() + var/obj/machinery/fusion_core/harvest_from + /obj/machinery/kinetic_harvester/Initialize() set_extension(src, /datum/extension/local_network_member) if(initial_id_tag) @@ -23,16 +24,20 @@ queue_icon_update() . = ..() +/obj/machinery/kinetic_harvester/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_id_tag, map_hash) + /obj/machinery/kinetic_harvester/interface_interact(mob/user) ui_interact(user) return TRUE -/obj/machinery/kinetic_harvester/attackby(var/obj/item/thing, var/mob/user) - if(isMultitool(thing)) +/obj/machinery/kinetic_harvester/attackby(var/obj/item/used_item, var/mob/user) + if(IS_MULTITOOL(used_item)) var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member) if(lanm.get_new_tag(user)) find_core() - return + return TRUE return ..() /obj/machinery/kinetic_harvester/proc/find_core() @@ -40,9 +45,9 @@ var/datum/extension/local_network_member/lanm = get_extension(src, /datum/extension/local_network_member) var/datum/local_network/lan = lanm.get_local_network() - if(lan) - var/list/fusion_cores = lan.get_devices(/obj/machinery/power/fusion_core) - if(fusion_cores && fusion_cores.len) + if(lan) + var/list/fusion_cores = lan.get_devices(/obj/machinery/fusion_core) + if(LAZYLEN(fusion_cores)) harvest_from = fusion_cores[1] return harvest_from @@ -60,10 +65,9 @@ data["status"] = (use_power >= POWER_USE_ACTIVE) data["materials"] = list() for(var/mat in stored) - var/decl/material/material = decls_repository.get_decl(mat) - if(material) - var/sheets = Floor(stored[mat]/(SHEET_MATERIAL_AMOUNT * 1.5)) - data["materials"] += list(list("material" = mat, "rawamount" = stored[mat], "amount" = sheets, "harvest" = harvesting[mat])) + var/decl/material/stored_material = GET_DECL(mat) + var/sheets = floor(stored[mat]/(SHEET_MATERIAL_AMOUNT * 1.5)) + data["materials"] += list(list("name" = stored_material.solid_name, "amount" = sheets, "harvest" = harvesting[mat], "mat_ref" = "\ref[stored_material]")) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -73,16 +77,17 @@ ui.set_auto_update(1) /obj/machinery/kinetic_harvester/Process() + if(harvest_from && get_dist(src, harvest_from) > 10) harvest_from = null if(use_power >= POWER_USE_ACTIVE) if(harvest_from && harvest_from.owned_field) for(var/mat in harvest_from.owned_field.reactants) - if(SSmaterials.materials_by_name[mat] && !stored[mat]) + if(!(mat in stored)) stored[mat] = 0 for(var/mat in harvesting) - if(!SSmaterials.materials_by_name[mat] || !harvest_from.owned_field.reactants[mat]) + if(!harvest_from.owned_field.reactants[mat]) harvesting -= mat else var/harvest = min(harvest_from.owned_field.reactants[mat], rand(100,200)) @@ -102,17 +107,17 @@ icon_state = "off" /obj/machinery/kinetic_harvester/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state) + if(href_list["remove_mat"]) - var/mat = href_list["remove_mat"] - var/decl/material/material = decls_repository.get_decl(mat) - if(material) + var/decl/material/remove_material = locate(href_list["remove_mat"]) + if(istype(remove_material)) var/sheet_cost = (SHEET_MATERIAL_AMOUNT * 1.5) - var/sheets = Floor(stored[mat]/sheet_cost) + var/sheets = floor(stored[remove_material.type]/sheet_cost) if(sheets > 0) - material.place_sheet(loc, sheets) - stored[mat] -= sheets * sheet_cost - if(stored[mat] <= 0) - stored -= mat + remove_material.create_object(loc, sheets) + stored[remove_material.type] -= (sheets * sheet_cost) + if(stored[remove_material.type] <= 0) + stored -= remove_material.type return TOPIC_REFRESH if(href_list["toggle_power"]) @@ -121,11 +126,12 @@ return TOPIC_REFRESH if(href_list["toggle_harvest"]) - var/mat = href_list["toggle_harvest"] - if(harvesting[mat]) - harvesting -= mat - else - harvesting[mat] = TRUE - if(!(mat in stored)) - stored[mat] = 0 + var/decl/material/harvest_material = locate(href_list["toggle_harvest"]) + if(istype(harvest_material)) + if(harvesting[harvest_material.type]) + harvesting -= harvest_material.type + else + harvesting[harvest_material.type] = TRUE + if(!(harvest_material.type in stored)) + stored[harvest_material.type] = 0 return TOPIC_REFRESH diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index 3b49582a4047..01ab115896a3 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -1,9 +1,10 @@ -/obj/machinery/power/generator +/obj/machinery/generator name = "thermoelectric generator" desc = "It's a high efficiency thermoelectric generator." + icon = 'icons/obj/power.dmi' icon_state = "teg-unassembled" - density = 1 - anchored = 0 + density = TRUE + anchored = FALSE use_power = POWER_USE_IDLE idle_power_usage = 100 //Watts, I hope. Just enough to do the computer and display things. @@ -27,7 +28,7 @@ construct_state = /decl/machine_construction/default/panel_closed stat_immune = 0 -/obj/machinery/power/generator/Initialize() +/obj/machinery/generator/Initialize() . = ..() desc = initial(desc) + " Rated for [round(max_power/1000)] kW." reconnect() @@ -37,7 +38,7 @@ //so a circulator to the NORTH of the generator connects first to the EAST, then to the WEST //and a circulator to the WEST of the generator connects first to the NORTH, then to the SOUTH //note that the circulator's outlet dir is it's always facing dir, and it's inlet is always the reverse -/obj/machinery/power/generator/proc/reconnect() +/obj/machinery/generator/proc/reconnect() if(circ1) circ1.temperature_overlay = null if(circ2) @@ -63,7 +64,7 @@ circ2 = null update_icon() -/obj/machinery/power/generator/on_update_icon() +/obj/machinery/generator/on_update_icon() icon_state = anchored ? "teg-assembled" : "teg-unassembled" overlays.Cut() if (circ1) @@ -85,7 +86,7 @@ circ2.temperature_overlay = "circ-[extreme]cold" return 1 -/obj/machinery/power/generator/Process() +/obj/machinery/generator/Process() if(!circ1 || !circ2 || !anchored || stat & (BROKEN|NOPOWER)) stored_energy = 0 return @@ -126,16 +127,12 @@ circ2.air2.merge(air2) //Update the gas networks - if(circ1.network2) - circ1.network2.update = 1 - if(circ2.network2) - circ2.network2.update = 1 + circ1.update_networks(circ1.dir) + circ2.update_networks(circ2.dir) //Exceeding maximum power leads to some power loss if(effective_gen > max_power && prob(5)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) stored_energy *= 0.5 //Power @@ -153,36 +150,33 @@ if(genlev != lastgenlev) lastgenlev = genlev update_icon() - add_avail(effective_gen) - -/obj/machinery/power/generator/attackby(obj/item/W, mob/user) - if(isWrench(W)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - anchored = !anchored - user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \ - "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \ - "You hear a ratchet") - update_use_power(anchored) - if(anchored) // Powernet connection stuff. - connect_to_network() - else - disconnect_from_network() - reconnect() - else - ..() -/obj/machinery/power/generator/CanUseTopic(mob/user) + generate_power(effective_gen) + +/obj/machinery/generator/attackby(obj/item/used_item, mob/user) + if(!IS_WRENCH(used_item)) + return ..() + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + anchored = !anchored + user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \ + "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \ + "You hear a ratchet.") + update_use_power(anchored) + reconnect() + return TRUE + +/obj/machinery/generator/CanUseTopic(mob/user) if(!anchored) return STATUS_CLOSE return ..() -/obj/machinery/power/generator/interface_interact(mob/user) +/obj/machinery/generator/interface_interact(mob/user) if(!circ1 || !circ2) //Just incase the middle part of the TEG was not wrenched last. reconnect() ui_interact(user) return TRUE -/obj/machinery/power/generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) // this is the data which will be sent to the ui var/vertical = 0 if (dir == NORTH || dir == SOUTH) @@ -233,7 +227,7 @@ // auto update every Master Controller tick ui.set_auto_update(1) -/obj/machinery/power/generator/verb/rotate_clock() +/obj/machinery/generator/verb/rotate_clock() set category = "Object" set name = "Rotate Generator (Clockwise)" set src in view(1) @@ -243,7 +237,7 @@ src.set_dir(turn(src.dir, 90)) -/obj/machinery/power/generator/verb/rotate_anticlock() +/obj/machinery/generator/verb/rotate_anticlock() set category = "Object" set name = "Rotate Generator (Counterclockwise)" set src in view(1) diff --git a/code/modules/power/geothermal/_geothermal.dm b/code/modules/power/geothermal/_geothermal.dm new file mode 100644 index 000000000000..138a38cd1cf4 --- /dev/null +++ b/code/modules/power/geothermal/_geothermal.dm @@ -0,0 +1,276 @@ +var/global/const/GEOTHERMAL_EFFICIENCY_MOD = 0.2 +var/global/const/GEOTHERMAL_PRESSURE_LOSS = 0.3 +var/global/const/GEOTHERMAL_PRESSURE_CONSUMED_PER_TICK = 0.05 +var/global/const/GEOTHERMAL_PRESSURE_TO_POWER = 800 +var/global/const/MAX_GEOTHERMAL_PRESSURE = 12000 + +////////////////////////////////////////////////////////////////////// +// Geyser Steam Particle Emitter +////////////////////////////////////////////////////////////////////// + +///Particle emitter that emits a ~64 pixels by ~192 pixels high column of steam while active. +/particles/geyser_steam + icon_state = "smallsmoke" + icon = 'icons/effects/effects.dmi' + width = WORLD_ICON_SIZE * 2 //Particles expand a bit as they climb, so need a bit of space on the width + height = WORLD_ICON_SIZE * 6 //Needs to be really tall, because particles stop being drawn outside of the canvas. + count = 64 + spawning = 5 + lifespan = generator("num", 1 SECOND, 2.5 SECONDS, LINEAR_RAND) + fade = 3 SECONDS + fadein = 0.25 SECONDS + grow = 0.1 + velocity = generator("vector", list(0, 0), list(0, 0.2)) + position = generator("circle", -6, 6, NORMAL_RAND) + gravity = list(0, 0.40) + scale = generator("vector", list(0.3, 0.3), list(1,1), NORMAL_RAND) + rotation = generator("num", -45, 45) + spin = generator("num", -20, 20) + +////////////////////////////////////////////////////////////////////// +// Geyser Object +////////////////////////////////////////////////////////////////////// + +/// A prop that periodically emit steam spouts and can have a geothermal generator placed on top to generate power. +/obj/effect/geyser + name = "geothermal vent" + desc = "A vent leading to an underground geothermally heated reservoir, which periodically spews superheated liquid." + icon = 'icons/effects/geyser.dmi' + icon_state = "geyser" + anchored = TRUE + layer = TURF_LAYER + 0.01 + level = LEVEL_BELOW_PLATING // Goes under floor/plating + /// The particle emitter that will generate the steam column effect for this geyser + var/particles/geyser_steam/steamfx + +/obj/effect/geyser/Initialize(ml) + . = ..() + if(prob(50)) + var/matrix/M = matrix() + M.Scale(-1, 1) + transform = M + set_extension(src, /datum/extension/geothermal_vent) + steamfx = new //Prepare our FX + +///Async proc that enables the particle emitter for the steam column for a few seconds +/obj/effect/geyser/proc/do_spout() + set waitfor = FALSE + particles = steamfx + particles.spawning = initial(particles.spawning) + sleep(6 SECONDS) + particles.spawning = 0 + +/obj/effect/geyser/explosion_act(severity) + . = ..() + if(!QDELETED(src) && prob(100 - (25 * severity))) + physically_destroyed() + +/obj/effect/geyser/hide(hide) + var/datum/extension/geothermal_vent/E = get_extension(src, /datum/extension/geothermal_vent) + if(istype(E)) + E.set_obstructed(hide) + . = ..() + update_icon() + +////////////////////////////////////////////////////////////////////// +// Underwater Geyser Variant +////////////////////////////////////////////////////////////////////// + +/obj/effect/geyser/underwater + desc = "A crack in the ocean floor that occasionally vents gouts of superheated water and steam." + +/obj/effect/geyser/underwater/Initialize(ml) + . = ..() + if(!loc) + return INITIALIZE_HINT_QDEL + for(var/turf/floor/seafloor/T in RANGE_TURFS(loc, 5)) + var/dist = get_dist(loc, T)-1 + if(prob(100 - (dist * 20))) + if(prob(25)) + T = T.ChangeTurf(/turf/floor/clay) + else + T = T.ChangeTurf(/turf/floor/mud) + if(prob(50 - (dist * 10))) + new /obj/random/seaweed(T) + +/obj/effect/geyser/underwater/do_spout() + set waitfor = FALSE + var/turf/T = get_turf(src) + T.show_bubbles() + +////////////////////////////////////////////////////////////////////// +// Geothermal Generator +////////////////////////////////////////////////////////////////////// + +///A power generator that can create power from being placed on top of a geyser. +/obj/machinery/geothermal + name = "geothermal generator" + icon = 'icons/obj/machines/power/geothermal.dmi' + icon_state = "geothermal-base" + density = TRUE + anchored = TRUE + waterproof = TRUE + interact_offline = TRUE + stat_immune = NOSCREEN | NOINPUT | NOPOWER + core_skill = SKILL_ENGINES + required_interaction_dexterity = DEXTERITY_SIMPLE_MACHINES + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = list( + /obj/item/stock_parts/power/terminal, + ) + stock_part_presets = list( + /decl/stock_part_preset/terminal_setup/offset_dir, + ) + var/tmp/neighbors = 0 + var/tmp/current_pressure = 0 + var/tmp/efficiency = 0.5 + var/tmp/last_generated = 0 + var/tmp/datum/extension/geothermal_vent/vent + var/tmp/obj/item/stock_parts/power/terminal/connector + var/tmp/image/glow + var/tmp/list/neighbor_connectors + var/tmp/list/neighbor_connectors_glow + +//#TODO: Maybe should cache neighbors and put listeners on them? + +/obj/machinery/geothermal/Initialize(mapload, d, populate_parts = TRUE) + . = ..() + if(get_turf(loc)) + refresh_neighbors() + propagate_refresh_neighbors() + STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/geothermal/LateInitialize() + . = ..() + setup_vent() + +/obj/machinery/geothermal/Destroy() + var/atom/last_loc = loc + unset_vent() + connector = null + . = ..() + if(istype(last_loc)) + propagate_refresh_neighbors(last_loc) + +///Tell all neighbors of the center atom to call update neighbors +/obj/machinery/geothermal/proc/propagate_refresh_neighbors(var/atom/center = src) + for(var/adir in global.alldirs) + var/obj/machinery/geothermal/G = locate(/obj/machinery/geothermal) in get_step(center, adir) + if(G?.anchored) + G.refresh_neighbors() + +/obj/machinery/geothermal/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance < 2) + . += SPAN_INFO("Pressure: [current_pressure]kPa") + . += SPAN_INFO("Output: [last_generated]W") + +///Attempts to connect to any existing geothermal vents in our turf. +/obj/machinery/geothermal/proc/setup_vent() + var/turf/T = get_turf(src) + for(var/obj/O in T) + var/datum/extension/geothermal_vent/GV = get_extension(O, /datum/extension/geothermal_vent) + if(!GV || QDELETED(GV)) + continue + vent = GV + vent.set_my_generator(src) + return TRUE + +///Disconnect from any geothermal vents we may be connected to +/obj/machinery/geothermal/proc/unset_vent() + if(QDELETED(vent)) + return + vent.set_my_generator(null) + vent = null + +/obj/machinery/geothermal/RefreshParts() + ..() + efficiency = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor) * GEOTHERMAL_EFFICIENCY_MOD, GEOTHERMAL_EFFICIENCY_MOD, 1) + connector = get_component_of_type(/obj/item/stock_parts/power/terminal) + +/obj/machinery/geothermal/proc/add_pressure(var/pressure) + current_pressure = clamp(current_pressure + pressure, 0, MAX_GEOTHERMAL_PRESSURE) + var/leftover = round(pressure - current_pressure) + if(leftover > 0) + addtimer(CALLBACK(src, PROC_REF(propagate_pressure), leftover), 5) + update_icon() + START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + +/obj/machinery/geothermal/Process() + if(loc && anchored && !(stat & BROKEN)) + var/consumed_pressure = current_pressure * GEOTHERMAL_PRESSURE_CONSUMED_PER_TICK + current_pressure -= consumed_pressure + var/remaining_pressure = consumed_pressure + consumed_pressure = round(consumed_pressure * efficiency, 0.01) + remaining_pressure -= consumed_pressure + + last_generated = round(consumed_pressure * GEOTHERMAL_PRESSURE_TO_POWER, 0.01) + if(last_generated) + generate_power(last_generated) + remaining_pressure = round(remaining_pressure * GEOTHERMAL_PRESSURE_LOSS) + if(remaining_pressure) + addtimer(CALLBACK(src, PROC_REF(propagate_pressure), remaining_pressure), 5) + update_icon() + if(current_pressure <= 1) + return PROCESS_KILL + +/obj/machinery/geothermal/proc/propagate_pressure(var/remaining_pressure) + var/list/neighbors + for(var/neighbordir in global.cardinal) + var/obj/machinery/geothermal/neighbor = (locate() in get_step(loc, neighbordir)) + if(neighbor?.anchored && !(neighbor.stat & BROKEN)) + LAZYADD(neighbors, neighbor) + if(LAZYLEN(neighbors)) + remaining_pressure = round(remaining_pressure / LAZYLEN(neighbors)) + if(remaining_pressure) + for(var/obj/machinery/geothermal/neighbor as anything in neighbors) + neighbor.add_pressure(remaining_pressure) + +/obj/machinery/geothermal/proc/refresh_neighbors() + var/last_neighbors = neighbors + neighbors = 0 + for(var/neighbordir in global.cardinal) + if(locate(/obj/machinery/geothermal) in get_step(loc, neighbordir)) + neighbors |= neighbordir + if(last_neighbors != neighbors) + update_icon() + +/obj/machinery/geothermal/on_update_icon() + cut_overlays() + var/output_ratio = current_pressure / 3000 + var/glow_alpha = clamp(round((current_pressure / MAX_GEOTHERMAL_PRESSURE) * 255), 10, 255) + if(!glow) + glow = emissive_overlay(icon, "geothermal-glow") + if(!length(neighbor_connectors)) + for(var/neighbordir in global.cardinal) + LAZYSET(neighbor_connectors, "[neighbordir]", image(icon, "geothermal-connector", dir = neighbordir)) + LAZYSET(neighbor_connectors_glow, "[neighbordir]", image(icon, "geothermal-connector-glow", dir = neighbordir)) + + if(neighbors) + for(var/neighbordir in global.cardinal) + if(neighbors & neighbordir) + add_overlay(neighbor_connectors["[neighbordir]"]) + // emissive_overlay is not setting dir and setting plane/layer directly also causes dir to break :( + var/image/neighborglow = neighbor_connectors_glow["[neighbordir]"] + neighborglow.alpha = glow_alpha + add_overlay(neighborglow) + + if(round(current_pressure, 0.1) <= 0) + set_light(0) + return + + set_light(1, clamp(output_ratio, 0.2, 1.0), COLOR_RED) + add_overlay("geothermal-turbine-[clamp(round(output_ratio * 3), 0, 3)]") + glow.alpha = glow_alpha + add_overlay(glow) + +/obj/machinery/geothermal/dismantle() + . = ..() + unset_vent() + +/obj/machinery/geothermal/get_powernet() + return connector?.terminal?.get_powernet() + +/obj/machinery/geothermal/drain_power() + return -1 \ No newline at end of file diff --git a/code/modules/power/geothermal/geothermal_circuit.dm b/code/modules/power/geothermal/geothermal_circuit.dm new file mode 100644 index 000000000000..f569521f85e3 --- /dev/null +++ b/code/modules/power/geothermal/geothermal_circuit.dm @@ -0,0 +1,11 @@ +/obj/item/stock_parts/circuitboard/geothermal + name = "circuitboard (geothermal generator)" + build_path = /obj/machinery/geothermal + board_type = "machine" + origin_tech = @'{"magnets":3,"powerstorage":3}' + req_components = list( + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stack/cable_coil = 5 + ) + additional_spawn_components = null diff --git a/code/modules/power/geothermal/geothermal_extension.dm b/code/modules/power/geothermal/geothermal_extension.dm new file mode 100644 index 000000000000..0d734d381165 --- /dev/null +++ b/code/modules/power/geothermal/geothermal_extension.dm @@ -0,0 +1,45 @@ +/datum/extension/geothermal_vent + base_type = /datum/extension/geothermal_vent + expected_type = /obj/effect/geyser + flags = EXTENSION_FLAG_IMMEDIATE + var/pressure_min = 1000 + var/pressure_max = 2000 + var/steam_min = 20 SECONDS + var/steam_max = 60 SECONDS + var/tmp/next_steam = 0 + var/tmp/obstructed = FALSE + var/obj/machinery/geothermal/my_machine + var/obj/effect/geyser/my_vent + +/datum/extension/geothermal_vent/New(datum/holder) + ..() + START_PROCESSING(SSprocessing, src) + my_vent = holder + +/datum/extension/geothermal_vent/Destroy() + my_machine = null + my_vent = null + . = ..() + STOP_PROCESSING(SSprocessing, src) + +/datum/extension/geothermal_vent/proc/set_my_generator(var/obj/machinery/geothermal/G) + my_machine = G + +/datum/extension/geothermal_vent/proc/set_obstructed(var/state) + obstructed = state + if(obstructed) + STOP_PROCESSING(SSprocessing, src) + else + START_PROCESSING(SSprocessing, src) + +/datum/extension/geothermal_vent/Process() + if(obstructed && !my_machine) //If we have a machine, don't care about obstruction, or it might cause problems + return PROCESS_KILL + + if(world.time >= next_steam) + next_steam = world.time + rand(steam_min, steam_max) + //If we cached something, make it work + if(my_machine?.anchored) + my_machine.add_pressure(rand(pressure_min, pressure_max)) + else + my_vent.do_spout() //Let the holder decide what to do when spewing steam diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm deleted file mode 100644 index f765b5496d7c..000000000000 --- a/code/modules/power/gravitygenerator.dm +++ /dev/null @@ -1,110 +0,0 @@ -// It.. uses a lot of power. Everything under power is engineering stuff, at least. - -/obj/machinery/computer/gravity_control_computer - name = "Gravity Generator Control" - desc = "A computer to control a local gravity generator. Qualified personnel only." - icon = 'icons/obj/computer.dmi' - icon_state = "airtunnel0e" - anchored = 1 - density = 1 - var/obj/machinery/gravity_generator/gravity_generator - -/obj/machinery/gravity_generator/ - name = "Gravitational Generator" - desc = "A device which produces a gravaton field when set up." - icon = 'icons/obj/singularity.dmi' - icon_state = "TheSingGen" - anchored = 1 - density = 1 - idle_power_usage = 200 - active_power_usage = 1000 - var/on = 1 - var/list/localareas = list() - var/effectiverange = 25 - - // Borrows code from cloning computer -/obj/machinery/computer/gravity_control_computer/Initialize() - . = ..() - updatemodules() - -/obj/machinery/gravity_generator/Initialize() - . = ..() - locatelocalareas() - -/obj/machinery/computer/gravity_control_computer/proc/updatemodules() - for(dir in list(NORTH,EAST,SOUTH,WEST)) - gravity_generator = locate(/obj/machinery/gravity_generator/, get_step(src, dir)) - if (gravity_generator) - return - -/obj/machinery/gravity_generator/proc/locatelocalareas() - for(var/area/A in range(src,effectiverange)) - if(istype(A,/area/space)) - continue // No (de)gravitizing space. - localareas |= A - -/obj/machinery/computer/gravity_control_computer/interface_interact(mob/user) - interact(user) - return TRUE - -/obj/machinery/computer/gravity_control_computer/interact(mob/user) - user.set_machine(src) - - updatemodules() - - var/dat = "

    Generator Control System

    " - //dat += "Refresh" - if(gravity_generator) - if(gravity_generator.on) - dat += "
    Gravity Status: ON

    " - else - dat += "
    Gravity Status: OFF

    " - - dat += "
    Currently Supplying Gravitons To:
    " - - for(var/area/A in gravity_generator.localareas) - if(A.has_gravity && gravity_generator.on) - dat += "[A]
    " - - else if (A.has_gravity) - dat += "[A]
    " - - else - dat += "[A]
    " - - dat += "
    Maintainence Functions:
    " - if(gravity_generator.on) - dat += " TURN GRAVITY GENERATOR OFF. " - else - dat += " TURN GRAVITY GENERATOR ON. " - - else - dat += "No local gravity generator detected!" - - show_browser(user, dat, "window=gravgen") - onclose(user, "gravgen") - - -/obj/machinery/computer/gravity_control_computer/Topic(href, href_list) - set background = 1 - if((. = ..())) - close_browser(usr, "window=air_alarm") - return - - if(href_list["gentoggle"]) - if(gravity_generator.on) - gravity_generator.on = 0 - - for(var/area/A in gravity_generator.localareas) - var/obj/machinery/gravity_generator/G - for(G in SSmachines.machinery) - if((A in G.localareas) && (G.on)) - break - if(!G) - A.gravitychange(0) - else - for(var/area/A in gravity_generator.localareas) - gravity_generator.on = 1 - A.gravitychange(1) - - src.updateUsrDialog() diff --git a/code/modules/power/heavycable.dm b/code/modules/power/heavycable.dm new file mode 100644 index 000000000000..ed452d7e1fb8 --- /dev/null +++ b/code/modules/power/heavycable.dm @@ -0,0 +1,42 @@ +// HEAVY DUTY CABLES +/obj/item/stack/cable_coil/heavyduty + name = "heavy cable coil" + icon = 'icons/obj/power_cond_heavy.dmi' + stack_merge_type = /obj/item/stack/cable_coil/heavyduty + cable_type = /obj/structure/cable/heavyduty + color = null + can_have_color = FALSE + +/obj/structure/cable/heavyduty + icon = 'icons/obj/power_cond_heavy.dmi' + name = "large power cable" + desc = "This cable is tough. It cannot be cut with simple hand tools." + cable_type = /obj/item/stack/cable_coil/heavyduty + color = null + can_have_color = FALSE + +#define IS_TOOL_WITH_QUALITY(A, T, Q) (isatom(A) && A.get_tool_quality(T) >= Q) +/obj/structure/cable/heavyduty/attackby(obj/item/used_item, mob/user) + if(IS_WIRECUTTER(used_item)) + // Must be cut with power tools like the hydraulic clamp. + if(IS_TOOL_WITH_QUALITY(used_item, TOOL_WIRECUTTERS, TOOL_QUALITY_GOOD)) + cut_wire(used_item, user) + else + to_chat(user, SPAN_WARNING("\The [used_item] isn't strong enough to cut \the [src].")) + return TRUE + if(istype(used_item, /obj/item/stack/cable_coil) && !istype(used_item, /obj/item/stack/cable_coil/heavyduty)) + to_chat(user, SPAN_WARNING("\The [used_item] isn't heavy enough to connect to \the [src].")) + return TRUE + return ..() + +#undef IS_TOOL_WITH_QUALITY + +// No diagonals or Z-cables for this subtype. +/obj/item/stack/cable_coil/heavyduty/put_cable(turf/F, mob/user, d1, d2) + if((d1 & (UP|DOWN)) || (d2 & (UP|DOWN))) + to_chat(user, SPAN_WARNING("\The [src] is too heavy to connect vertically!")) + return FALSE + if((d1 & (d1 - 1)) || (d2 & (d2 - 1))) + to_chat(user, SPAN_WARNING("\The [src] can't connect at that angle!")) + return FALSE + return ..(F, user, d1, d2) \ No newline at end of file diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm deleted file mode 100644 index 2a5f1dfa84ba..000000000000 --- a/code/modules/power/lighting.dm +++ /dev/null @@ -1,635 +0,0 @@ -// The lighting system -// -// consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/light) - - -// status values shared between lighting fixtures and items -#define LIGHT_OK 0 -#define LIGHT_EMPTY 1 -#define LIGHT_BROKEN 2 -#define LIGHT_BURNED 3 - -#define LIGHT_BULB_TEMPERATURE 400 //K - used value for a 60W bulb -#define LIGHTING_POWER_FACTOR 5 //5W per luminosity * range - - -#define LIGHTMODE_EMERGENCY "emergency_lighting" -#define LIGHTMODE_READY "ready" - -// the standard tube light fixture -/obj/machinery/light - name = "light fixture" - icon = 'icons/obj/lighting.dmi' - var/base_state = "tube" // base description and icon_state - icon_state = "tube_map" - desc = "A lighting fixture." - anchored = 1 - layer = ABOVE_HUMAN_LAYER // They were appearing under mobs which is a little weird - Ostaf - use_power = POWER_USE_ACTIVE - idle_power_usage = 2 - active_power_usage = 20 - power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list - - var/on = 0 // 1 if on, 0 if off - var/flickering = 0 - var/light_type = /obj/item/light/tube // the type of light item - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - - var/obj/item/light/lightbulb - - var/current_mode = null - uncreated_component_parts = list( - /obj/item/stock_parts/power/apc/buildable - ) - construct_state = /decl/machine_construction/wall_frame/panel_closed/simple - base_type = /obj/machinery/light/buildable - frame_type = /obj/item/frame/light - -/obj/machinery/light/buildable - uncreated_component_parts = null - -// the smaller bulb light fixture -/obj/machinery/light/small - icon_state = "bulb_map" - base_state = "bulb" - desc = "A small lighting fixture." - light_type = /obj/item/light/bulb - base_type = /obj/machinery/light/small/buildable - frame_type = /obj/item/frame/light/small - -/obj/machinery/light/small/buildable - uncreated_component_parts = null - -/obj/machinery/light/small/emergency - light_type = /obj/item/light/bulb/red - -/obj/machinery/light/small/red - light_type = /obj/item/light/bulb/red - -/obj/machinery/light/spot - name = "spotlight" - desc = "A more robust socket for light tubes that demand more power." - light_type = /obj/item/light/tube/large - base_type = /obj/machinery/light/spot/buildable - frame_type = /obj/item/frame/light/spot - -/obj/machinery/light/spot/buildable - uncreated_component_parts = null - -// create a new lighting fixture -/obj/machinery/light/Initialize(mapload, d=0, populate_parts = TRUE) - . = ..() - - s.set_up(1, 1, src) - - if(populate_parts) - lightbulb = new light_type(src) - if(prob(lightbulb.broken_chance)) - broken(1) - - on = powered() - update_icon(0) - -/obj/machinery/light/Destroy() - QDEL_NULL(lightbulb) - QDEL_NULL(s) - . = ..() - -/obj/machinery/light/on_update_icon(var/trigger = 1) - // Handle pixel offsets - pixel_y = 0 - pixel_x = 0 - var/turf/T = get_step(get_turf(src), src.dir) - if(istype(T) && T.density) - if(src.dir == NORTH) - pixel_y = 21 - else if(src.dir == EAST) - pixel_x = 10 - else if(src.dir == WEST) - pixel_x = -10 - - // Update icon state - overlays.Cut() - switch(construct_state.type) //Never use the initial state. That'll just reset it to the mapping icon. - if(/decl/machine_construction/wall_frame/no_wires/simple) - icon_state = "[base_state]-construct-stage1" - return - if(/decl/machine_construction/wall_frame/panel_open/simple) - icon_state = "[base_state]-construct-stage2" - return - - icon_state = "[base_state]_empty" - - // Extra overlays if we're active - var/_state - switch(get_status()) // set icon_states - if(LIGHT_OK) - _state = "[base_state][on]" - if(LIGHT_EMPTY) - on = 0 - if(LIGHT_BURNED) - _state = "[base_state]_burned" - on = 0 - if(LIGHT_BROKEN) - _state = "[base_state]_broken" - on = 0 - - if(istype(lightbulb, /obj/item/light)) - var/image/I = image(icon, _state) - I.color = lightbulb.b_colour - overlays += I - - if(on) - - update_use_power(POWER_USE_ACTIVE) - - var/changed = 0 - if(current_mode && (current_mode in lightbulb.lighting_modes)) - changed = set_light(arglist(lightbulb.lighting_modes[current_mode])) - else - changed = set_light(lightbulb.b_max_bright, lightbulb.b_inner_range, lightbulb.b_outer_range, lightbulb.b_curve, lightbulb.b_colour) - - if(trigger && changed && get_status() == LIGHT_OK) - switch_check() - else - update_use_power(POWER_USE_OFF) - set_light(0) - change_power_consumption((light_outer_range * light_max_bright) * LIGHTING_POWER_FACTOR, POWER_USE_ACTIVE) - -/obj/machinery/light/proc/get_status() - if(!lightbulb) - return LIGHT_EMPTY - else - return lightbulb.status - -/obj/machinery/light/proc/switch_check() - lightbulb.switch_on() - if(get_status() != LIGHT_OK) - set_light(0) - -/obj/machinery/light/proc/set_mode(var/new_mode) - if(current_mode != new_mode) - current_mode = new_mode - update_icon(0) - -/obj/machinery/light/proc/set_emergency_lighting(var/enable) - if(!lightbulb) - return - - if(enable) - if(LIGHTMODE_EMERGENCY in lightbulb.lighting_modes) - set_mode(LIGHTMODE_EMERGENCY) - update_power_channel(ENVIRON) - else - if(current_mode == LIGHTMODE_EMERGENCY) - set_mode(null) - update_power_channel(initial(power_channel)) - -// attempt to set the light's on/off status -// will not switch on if broken/burned/empty -/obj/machinery/light/proc/seton(var/state) - on = (state && get_status() == LIGHT_OK) - queue_icon_update() - -// examine verb -/obj/machinery/light/examine(mob/user) - . = ..() - var/fitting = get_fitting_name() - switch(get_status()) - if(LIGHT_OK) - to_chat(user, "It is turned [on? "on" : "off"].") - if(LIGHT_EMPTY) - to_chat(user, "The [fitting] has been removed.") - if(LIGHT_BURNED) - to_chat(user, "The [fitting] is burnt out.") - if(LIGHT_BROKEN) - to_chat(user, "The [fitting] has been smashed.") - -/obj/machinery/light/proc/get_fitting_name() - var/obj/item/light/L = light_type - return initial(L.name) - -// attack with item - insert light (if right type), otherwise try to break the light - -/obj/machinery/light/proc/insert_bulb(obj/item/light/L) - L.forceMove(src) - lightbulb = L - - on = powered() - update_icon() - -/obj/machinery/light/proc/remove_bulb() - . = lightbulb - lightbulb.dropInto(loc) - lightbulb.update_icon() - lightbulb = null - update_icon() - -/obj/machinery/light/cannot_transition_to(state_path, mob/user) - if(lightbulb && !ispath(state_path, /decl/machine_construction/wall_frame/panel_closed)) - return SPAN_WARNING("You must first remove the lightbulb!") - return ..() - -/obj/machinery/light/attackby(obj/item/W, mob/user) - . = ..() - if(. || panel_open) - return - - // attempt to insert light - if(istype(W, /obj/item/light)) - if(lightbulb) - to_chat(user, "There is a [get_fitting_name()] already inserted.") - return - if(!istype(W, light_type)) - to_chat(user, "This type of light requires a [get_fitting_name()].") - return - if(!user.unEquip(W, src)) - return - to_chat(user, "You insert [W].") - insert_bulb(W) - src.add_fingerprint(user) - - // attempt to break the light - //If xenos decide they want to smash a light bulb with a toolbox, who am I to stop them? /N - - else if(lightbulb && (lightbulb.status != LIGHT_BROKEN)) - - if(prob(1 + W.force * 5)) - - user.visible_message("[user.name] smashed the light!", "You smash the light!", "You hear a tinkle of breaking glass") - if(on && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE)) - if (prob(12)) - electrocute_mob(user, get_area(src), src, 0.3) - broken() - - else - to_chat(user, "You hit the light!") - - // attempt to stick weapon into light socket - else if(!lightbulb) - to_chat(user, "You stick \the [W] into the light socket!") - if(powered() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - if (prob(75)) - electrocute_mob(user, get_area(src), src, rand(0.7,1.0)) - - -// returns whether this light has power -// true if area has power and lightswitch is on -/obj/machinery/light/powered() - var/area/A = get_area(src) - return A && A.lightswitch && ..(power_channel) - -/obj/machinery/light/proc/flicker(var/amount = rand(10, 20)) - if(flickering) return - flickering = 1 - spawn(0) - if(on && get_status() == LIGHT_OK) - for(var/i = 0; i < amount; i++) - if(get_status() != LIGHT_OK) break - on = !on - update_icon(0) - sleep(rand(5, 15)) - on = (get_status() == LIGHT_OK) - update_icon(0) - flickering = 0 - -// ai attack - make lights flicker, because why not - -/obj/machinery/light/attack_ai(mob/user) - src.flicker(1) - -// attack with hand - remove tube/bulb -// if hands aren't protected and the light is on, burn the player -/obj/machinery/light/physical_attack_hand(mob/living/user) - if(!lightbulb) - to_chat(user, "There is no [get_fitting_name()] in this light.") - return TRUE - - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species.can_shred(H)) - visible_message("[user.name] smashed the light!", 3, "You hear a tinkle of breaking glass") - broken() - return TRUE - - // make it burn hands if not wearing fire-insulated gloves - if(on) - var/prot = 0 - var/mob/living/carbon/human/H = user - - if(istype(H)) - if(H.gloves) - var/obj/item/clothing/gloves/G = H.gloves - if(G.max_heat_protection_temperature) - if(G.max_heat_protection_temperature > LIGHT_BULB_TEMPERATURE) - prot = 1 - else - prot = 1 - - if(prot > 0 || (MUTATION_COLD_RESISTANCE in user.mutations)) - to_chat(user, "You remove the [get_fitting_name()]") - else if(istype(user) && user.is_telekinetic()) - to_chat(user, "You telekinetically remove the [get_fitting_name()].") - else if(user.a_intent != I_HELP) - var/obj/item/organ/external/hand = H.organs_by_name[user.hand ? BP_L_HAND : BP_R_HAND] - if(hand && hand.is_usable() && !hand.can_feel_pain()) - user.apply_damage(3, BURN, user.hand ? BP_L_HAND : BP_R_HAND, used_weapon = src) - user.visible_message(SPAN_WARNING("\The [user]'s [hand] burns and sizzles as \he touches the hot [get_fitting_name()]."), SPAN_WARNING("Your [hand] burns and sizzles as you remove the hot [get_fitting_name()].")) - else - to_chat(user, "You try to remove the [get_fitting_name()], but it's too hot and you don't want to burn your hand.") - return TRUE - else - to_chat(user, "You remove the [get_fitting_name()].") - - // create a light tube/bulb item and put it in the user's hand - user.put_in_active_hand(remove_bulb()) //puts it in our active hand - return TRUE - -// ghost attack - make lights flicker like an AI, but even spookier! -/obj/machinery/light/attack_ghost(mob/user) - if(round_is_spooky()) - src.flicker(rand(2,5)) - else return ..() - -// break the light and make sparks if was on -/obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0) - if(!lightbulb) - return - - if(!skip_sound_and_sparks) - if(lightbulb && !(lightbulb.status == LIGHT_BROKEN)) - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - if(on) - s.set_up(3, 1, src) - s.start() - lightbulb.status = LIGHT_BROKEN - update_icon() - -/obj/machinery/light/proc/fix() - if(get_status() == LIGHT_OK || !lightbulb) - return - lightbulb.status = LIGHT_OK - on = 1 - update_icon() - -// explosion effect -// destroy the whole light fixture or just shatter it - -/obj/machinery/light/explosion_act(severity) - . = ..() - if(. && !QDELETED(src)) - if(severity == 1) - physically_destroyed() - else if((severity == 2 && prob(75)) || (severity == 3 && prob(50))) - broken() - -// timed process -// use power - -// called when area power state changes -/obj/machinery/light/power_change() - spawn(10) - seton(powered()) - -// called when on fire - -/obj/machinery/light/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C - broken() - -/obj/machinery/light/small/readylight - light_type = /obj/item/light/bulb/red/readylight - var/state = 0 - -/obj/machinery/light/small/readylight/proc/set_state(var/new_state) - state = new_state - if(state) - set_mode(LIGHTMODE_READY) - else - set_mode(null) - -/obj/machinery/light/navigation - name = "navigation light" - desc = "A periodically flashing light." - icon = 'icons/obj/lighting_nav.dmi' - icon_state = "nav10" - base_state = "nav1" - light_type = /obj/item/light/tube/large - on = TRUE - var/delay = 1 - base_type = /obj/machinery/light/navigation/buildable - frame_type = /obj/item/frame/light/nav - -/obj/machinery/light/navigation/on_update_icon() - . = ..() // this will handle pixel offsets - overlays.Cut() - icon_state = "[delay][!!(lightbulb && on)]" - -/obj/machinery/light/navigation/attackby(obj/item/W, mob/user) - . = ..() - if(!. && isMultitool(W)) - delay = 5 + ((delay + 1) % 5) - to_chat(user, SPAN_NOTICE("You adjust the delay on \the [src]")) - return TRUE - -/obj/machinery/light/navigation/buildable - uncreated_component_parts = null - -/obj/machinery/light/navigation/delay2 - delay = 2 - -/obj/machinery/light/navigation/delay3 - delay = 3 - -/obj/machinery/light/navigation/delay4 - delay = 4 - -/obj/machinery/light/navigation/delay5 - delay = 5 - -/obj/machinery/light/navigation/powered() - return TRUE - - -// the light item -// can be tube or bulb subtypes -// will fit into empty /obj/machinery/light of the corresponding type - -/obj/item/light - icon = 'icons/obj/lighting.dmi' - force = 2 - throwforce = 5 - w_class = ITEM_SIZE_TINY - var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN - var/base_state - var/switchcount = 0 // number of times switched - material = /decl/material/solid/metal/steel - var/rigged = 0 // true if rigged to explode - var/broken_chance = 2 - - var/b_max_bright = 0.9 - var/b_inner_range = 1 - var/b_outer_range = 5 - var/b_curve = 2 - var/b_colour = "#fffee0" - var/list/lighting_modes = list() - var/sound_on - -/obj/item/light/tube - name = "light tube" - desc = "A replacement light tube." - icon_state = "ltube" - base_state = "ltube" - item_state = "c_tube" - material = /decl/material/solid/glass - matter = list(/decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT) - - b_outer_range = 5 - b_colour = "#fffee0" - lighting_modes = list( - LIGHTMODE_EMERGENCY = list(l_outer_range = 4, l_max_bright = 1, l_color = "#da0205"), - ) - sound_on = 'sound/machines/lightson.ogg' - -/obj/item/light/tube/party/Initialize() //Randomly colored light tubes. Mostly for testing, but maybe someone will find a use for them. - . = ..() - b_colour = rgb(pick(0,255), pick(0,255), pick(0,255)) - -/obj/item/light/tube/large - w_class = ITEM_SIZE_SMALL - name = "large light tube" - b_max_bright = 0.95 - b_inner_range = 2 - b_outer_range = 8 - b_curve = 2.5 - -/obj/item/light/tube/large/party/Initialize() //Randomly colored light tubes. Mostly for testing, but maybe someone will find a use for them. - . = ..() - b_colour = rgb(pick(0,255), pick(0,255), pick(0,255)) - -/obj/item/light/bulb - name = "light bulb" - desc = "A replacement light bulb." - icon_state = "lbulb" - base_state = "lbulb" - item_state = "contvapour" - broken_chance = 3 - material = /decl/material/solid/glass - - b_max_bright = 0.6 - b_inner_range = 0.1 - b_outer_range = 4 - b_curve = 3 - b_colour = "#fcfcc7" - lighting_modes = list( - LIGHTMODE_EMERGENCY = list(l_outer_range = 3, l_max_bright = 1, l_color = "#da0205"), - ) - -/obj/item/light/bulb/red - color = "#da0205" - b_colour = "#da0205" - -/obj/item/light/bulb/red/readylight - lighting_modes = list( - LIGHTMODE_READY = list(l_outer_range = 5, l_max_bright = 1, l_color = "#00ff00"), - ) - -/obj/item/light/throw_impact(atom/hit_atom) - ..() - shatter() - -/obj/item/light/bulb/fire - name = "fire bulb" - desc = "A replacement fire bulb." - icon_state = "fbulb" - base_state = "fbulb" - item_state = "egg4" - material = /decl/material/solid/glass - -// update the icon state and description of the light -/obj/item/light/on_update_icon() - color = b_colour - var/broken - switch(status) - if(LIGHT_OK) - icon_state = base_state - desc = "A replacement [name]." - if(LIGHT_BURNED) - icon_state = "[base_state]_burned" - desc = "A burnt-out [name]." - if(LIGHT_BROKEN) - icon_state = "[base_state]_broken" - desc = "A broken [name]." - broken = TRUE - var/image/I = image(icon, src, "[base_state]_attachment[broken ? "_broken" : ""]") - I.color = null - overlays += I - -/obj/item/light/Initialize(mapload, obj/machinery/light/fixture = null) - . = ..() - update_icon() - -// attack bulb/tube with object -// if a syringe, can inject flammable liquids to make it explode -/obj/item/light/attackby(var/obj/item/I, var/mob/user) - ..() - if(istype(I, /obj/item/chems/syringe) && I.reagents?.total_volume) - var/obj/item/chems/syringe/S = I - to_chat(user, "You inject the solution into the [src].") - for(var/rtype in S.reagents) - var/decl/material/R = decls_repository.get_decl(rtype) - if(R.fuel_value) - rigged = TRUE - log_and_message_admins("injected a light with flammable reagents, rigging it to explode.", user) - break - S.reagents.clear_reagents() - return TRUE - . = ..() - -// called after an attack with a light item -// shatter light, unless it was an attempt to put it in a light socket -// now only shatter if the intent was harm - -/obj/item/light/afterattack(atom/target, mob/user, proximity) - if(!proximity) return - if(istype(target, /obj/machinery/light)) - return - if(user.a_intent != I_HURT) - return - - shatter() - -/obj/item/light/shatter() - if(status == LIGHT_OK || status == LIGHT_BURNED) - src.visible_message("[name] shatters.","You hear a small glass object shatter.") - status = LIGHT_BROKEN - force = 5 - sharp = 1 - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - update_icon() - -/obj/item/light/proc/switch_on() - switchcount++ - if(rigged) - log_and_message_admins("Rigged light explosion, last touched by [fingerprintslast]") - var/turf/T = get_turf(src.loc) - spawn(0) - sleep(2) - explosion(T, 0, 0, 3, 5) - sleep(1) - qdel(src) - status = LIGHT_BROKEN - else if(prob(min(60, switchcount*switchcount*0.01))) - status = LIGHT_BURNED - else if(sound_on) - playsound(src, sound_on, 75) - return status - -/obj/machinery/light/do_simple_ranged_interaction(var/mob/user) - if(lightbulb) - remove_bulb() - return TRUE diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 0e23b17b6035..82591b2c3d4d 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -1,55 +1,54 @@ //Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power). -/obj/machinery/power/port_gen +/obj/machinery/port_gen name = "Placeholder Generator" //seriously, don't use this. It can't be anchored without VV magic. desc = "A portable generator for emergency backup power." icon = 'icons/obj/power.dmi' icon_state = "portgen0" - density = 1 - anchored = 0 + density = TRUE + anchored = FALSE interact_offline = TRUE var/active = 0 var/power_gen = 5000 - var/recent_fault = 0 var/power_output = 1 atom_flags = ATOM_FLAG_CLIMBABLE var/datum/sound_token/sound_token var/sound_id var/working_sound -/obj/machinery/power/port_gen/proc/IsBroken() +/obj/machinery/port_gen/proc/IsBroken() return (stat & (BROKEN|EMPED)) -/obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check. +/obj/machinery/port_gen/proc/HasFuel() //Placeholder for fuel check. return 1 -/obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use. +/obj/machinery/port_gen/proc/UseFuel() //Placeholder for fuel use. return -/obj/machinery/power/port_gen/proc/DropFuel() +/obj/machinery/port_gen/proc/DropFuel() return -/obj/machinery/power/port_gen/proc/handleInactive() +/obj/machinery/port_gen/proc/handleInactive() return -/obj/machinery/power/port_gen/proc/update_sound() +/obj/machinery/port_gen/proc/update_sound() if(!working_sound) return if(!sound_id) - sound_id = "[type]_[sequential_id(/obj/machinery/power/port_gen)]" + sound_id = "[type]_[sequential_id(/obj/machinery/port_gen)]" if(active && HasFuel() && !IsBroken()) - var/volume = 10 + 15*power_output + var/work_volume = 10 + 15*power_output if(!sound_token) - sound_token = GLOB.sound_player.PlayLoopingSound(src, sound_id, working_sound, volume = volume) - sound_token.SetVolume(volume) + sound_token = play_looping_sound(src, sound_id, working_sound, volume = work_volume) + sound_token.SetVolume(work_volume) else if(sound_token) QDEL_NULL(sound_token) -/obj/machinery/power/port_gen/Process() +/obj/machinery/port_gen/Process() ..() - if(active && HasFuel() && !IsBroken() && anchored && powernet) - add_avail(power_gen * power_output) + if(active && HasFuel() && !IsBroken() && anchored) + generate_power(power_gen * power_output) UseFuel() src.updateDialog() else @@ -58,28 +57,28 @@ update_icon() update_sound() -/obj/machinery/power/port_gen/on_update_icon() +/obj/machinery/port_gen/on_update_icon() if(!active) icon_state = initial(icon_state) return 1 else icon_state = "[initial(icon_state)]on" -/obj/machinery/power/port_gen/CanUseTopic(mob/user) +/obj/machinery/port_gen/CanUseTopic(mob/user) if(!anchored) to_chat(user, "The generator needs to be secured first.") return STATUS_CLOSE return ..() -/obj/machinery/power/port_gen/examine(mob/user, distance) +/obj/machinery/port_gen/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(distance > 1) - return - if(active) - to_chat(usr, "The generator is on.") - else - to_chat(usr, "The generator is off.") -/obj/machinery/power/port_gen/emp_act(severity) + if(distance <= 1) + if(active) + . += SPAN_NOTICE("The generator is on.") + else + . += SPAN_NOTICE("The generator is off.") + +/obj/machinery/port_gen/emp_act(severity) if(!active) return var/duration = 6000 //ten minutes @@ -99,7 +98,7 @@ spawn(duration) stat &= ~EMPED -/obj/machinery/power/port_gen/proc/explode() +/obj/machinery/port_gen/proc/explode() explosion(src.loc, -1, 3, 5, -1) qdel(src) @@ -107,16 +106,13 @@ #define TEMPERATURE_CHANGE_MAX 20 //A power generator that runs on solid plasma sheets. -/obj/machinery/power/port_gen/pacman - name = "\improper P.A.C.M.A.N.-type Portable Generator" - desc = "A power generator that runs on solid deuterium sheets. Rated for 80 kW max safe output." - - var/sheet_name = "Deuterium Sheets" - var/sheet_path = /obj/item/stack/material/deuterium +/obj/machinery/port_gen/pacman + name = "portable generator" + desc = "A power generator that runs on solid graphite sheets. Rated for 80 kW max safe output." /* These values were chosen so that the generator can run safely up to 80 kW - A full 50 deuterium sheet stack should last 20 minutes at power_output = 4 + A full 50 graphite sheet stack should last 20 minutes at power_output = 4 temperature_gain and max_temperature are set so that the max safe power level is 4. Setting to 5 or higher can only be done temporarily before the generator overheats. */ @@ -125,6 +121,10 @@ construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 + + var/sheet_path // Base object type that it will accept, set in Initialize() if null + var/sheet_material = /decl/material/solid/graphite // Material type that the fuel needs to match. + var/max_power_output = 5 //The maximum power setting without emagging. var/max_safe_output = 4 // For UI use, maximal output that won't cause overheat. var/time_per_sheet = 96 //fuel efficiency - how long 1 sheet lasts at power level 1 @@ -138,51 +138,68 @@ var/overheating = 0 //if this gets high enough the generator explodes var/max_overheat = 150 -/obj/machinery/power/port_gen/pacman/Initialize() +/obj/machinery/port_gen/pacman/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(active) + . += "\The [src] appears to be producing [power_gen*power_output] W." + else + . += "\The [src] is turned off." + if(IsBroken()) + . += SPAN_WARNING("\The [src] seems to have broken down.") + if(overheating) + . += SPAN_DANGER("\The [src] is overheating!") + if(sheet_path && sheet_material) + var/decl/material/mat = GET_DECL(sheet_material) + var/obj/item/stack/material/sheet = sheet_path + . += "There [sheets == 1 ? "is" : "are"] [sheets] [sheets == 1 ? initial(sheet.singular_name) : initial(sheet.plural_name)] left in the hopper." + . += SPAN_SUBTLE("\The [src] uses [mat.solid_name] [initial(sheet.plural_name)] as fuel to produce power.") + +/obj/machinery/port_gen/pacman/Initialize() . = ..() - if(anchored) - connect_to_network() -/obj/machinery/power/port_gen/pacman/Destroy() + if(isnull(sheet_path)) + var/decl/material/mat = GET_DECL(sheet_material) + if(mat) + sheet_path = mat.default_solid_form + +/obj/machinery/port_gen/pacman/Destroy() DropFuel() return ..() -/obj/machinery/power/port_gen/pacman/RefreshParts() +/obj/machinery/port_gen/pacman/RefreshParts() var/temp_rating = total_component_rating_of_type(/obj/item/stock_parts/micro_laser) temp_rating += total_component_rating_of_type(/obj/item/stock_parts/capacitor) - max_sheets = 50 * Clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 5) ** 2 + max_sheets = 50 * clamp(total_component_rating_of_type(/obj/item/stock_parts/matter_bin), 0, 5) ** 2 - power_gen = round(initial(power_gen) * Clamp(temp_rating, 0, 20) / 2) + power_gen = round(initial(power_gen) * clamp(temp_rating, 0, 20) / 2) ..() -/obj/machinery/power/port_gen/pacman/examine(mob/user) - . = ..(user) - to_chat(user, "\The [src] appears to be producing [power_gen*power_output] W.") - to_chat(user, "There [sheets == 1 ? "is" : "are"] [sheets] sheet\s left in the hopper.") - if(IsBroken()) to_chat(user, "\The [src] seems to have broken down.") - if(overheating) to_chat(user, "\The [src] is overheating!") - -/obj/machinery/power/port_gen/pacman/proc/process_exhaust() - var/datum/gas_mixture/environment = loc.return_air() - if(environment) - environment.adjust_gas(/decl/material/gas/carbon_monoxide, 0.05*power_output) +/obj/machinery/port_gen/pacman/proc/process_exhaust() + var/decl/material/mat = GET_DECL(sheet_material) + var/datum/gas_mixture/environment = loc?.return_air() + if(mat && environment) + mat.add_burn_product(environment, 0.05*power_output) -/obj/machinery/power/port_gen/pacman/HasFuel() +/obj/machinery/port_gen/pacman/HasFuel() var/needed_sheets = power_output / time_per_sheet if(sheets >= needed_sheets - sheet_left) return 1 return 0 //Removes one stack's worth of material from the generator. -/obj/machinery/power/port_gen/pacman/DropFuel() +/obj/machinery/port_gen/pacman/DropFuel() if(sheets) - var/obj/item/stack/material/S = new sheet_path(loc) - var/amount = min(sheets, S.max_amount) - S.amount = amount - sheets -= amount + var/obj/item/stack/sheet_prototype = sheet_path + var/dump_amount = min(sheets, initial(sheet_prototype.max_amount)) + if(sheet_material) + var/decl/material/mat = GET_DECL(sheet_material) + mat.create_object(loc, dump_amount, sheet_path) + else + new sheet_path(loc, dump_amount) + sheets -= dump_amount -/obj/machinery/power/port_gen/pacman/UseFuel() +/obj/machinery/port_gen/pacman/UseFuel() //how much material are we using this iteration? var/needed_sheets = power_output / time_per_sheet @@ -223,7 +240,7 @@ var/average = (upper_limit + lower_limit)/2 //calculate the temperature increase - var/bias = Clamp(round((average - operating_temperature)/TEMPERATURE_DIVISOR, 1), -TEMPERATURE_CHANGE_MAX, TEMPERATURE_CHANGE_MAX) + var/bias = clamp(round((average - operating_temperature)/TEMPERATURE_DIVISOR, 1), -TEMPERATURE_CHANGE_MAX, TEMPERATURE_CHANGE_MAX) operating_temperature += bias + rand(-7, 7) if (operating_temperature > max_temperature) @@ -232,9 +249,9 @@ overheating-- process_exhaust() -/obj/machinery/power/port_gen/pacman/handleInactive() +/obj/machinery/port_gen/pacman/handleInactive() var/cooling_temperature = 20 - var/datum/gas_mixture/environment = loc.return_air() + var/datum/gas_mixture/environment = loc?.return_air() if (environment) var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1) var/ambient = environment.temperature - T20C @@ -242,32 +259,31 @@ if (operating_temperature > cooling_temperature) var/temp_loss = (operating_temperature - cooling_temperature)/TEMPERATURE_DIVISOR - temp_loss = between(2, round(temp_loss, 1), TEMPERATURE_CHANGE_MAX) + temp_loss = clamp(round(temp_loss, 1), 2, TEMPERATURE_CHANGE_MAX) operating_temperature = max(operating_temperature - temp_loss, cooling_temperature) src.updateDialog() if(overheating) overheating-- -/obj/machinery/power/port_gen/pacman/proc/overheat() +/obj/machinery/port_gen/pacman/proc/overheat() overheating++ if (overheating > max_overheat) explode() -/obj/machinery/power/port_gen/pacman/explode() - //Vapourize all the deuterium - //When ground up in a grinder, 1 sheet produces 20 u of deuterium -- Chemistry-Machinery.dm - //1 mol = 10 u? I dunno. 1 mol of carbon is definitely bigger than a pill - var/deuterium = (sheets+sheet_left)*20 +/obj/machinery/port_gen/pacman/explode() + // Vaporize all the fuel + // When ground up in a grinder, 1 sheet produces 20 u of material -- Chemistry-Machinery.dm + // 1 mol = 10 u? I dunno. 1 mol of carbon is definitely bigger than a pill + var/fuel_vapor = (sheets+sheet_left)*20 var/datum/gas_mixture/environment = loc.return_air() - if (environment) - environment.adjust_gas_temp(/decl/material/gas/hydrogen/deuterium, deuterium/10, operating_temperature + T0C) - + if(environment) + environment.adjust_gas_temp(sheet_material, fuel_vapor * 0.1, operating_temperature + T0C) sheets = 0 sheet_left = 0 ..() -/obj/machinery/power/port_gen/pacman/emag_act(var/remaining_charges, var/mob/user) +/obj/machinery/port_gen/pacman/emag_act(var/remaining_charges, var/mob/user) if (active && prob(25)) explode() //if they're foolish enough to emag while it's running @@ -275,56 +291,55 @@ emagged = 1 return 1 -/obj/machinery/power/port_gen/pacman/components_are_accessible(path) +/obj/machinery/port_gen/pacman/components_are_accessible(path) return !active && ..() -/obj/machinery/power/port_gen/pacman/cannot_transition_to(state_path, mob/user) +/obj/machinery/port_gen/pacman/cannot_transition_to(state_path, mob/user) if(active) return SPAN_WARNING("You cannot do this while \the [src] is running!") return ..() -/obj/machinery/power/port_gen/pacman/attackby(var/obj/item/O, var/mob/user) - if(istype(O, sheet_path)) - var/obj/item/stack/addstack = O +/obj/machinery/port_gen/pacman/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, sheet_path) && (isnull(sheet_material) || sheet_material == used_item.get_material_type())) + var/obj/item/stack/addstack = used_item var/amount = min((max_sheets - sheets), addstack.amount) if(amount < 1) - to_chat(user, "The [src.name] is full!") - return - to_chat(user, "You add [amount] sheet\s to the [src.name].") + to_chat(user, "\The [src] is full!") + return TRUE + to_chat(user, "You add [amount] sheet\s to \the [src].") sheets += amount addstack.use(amount) updateUsrDialog() - return - if(isWrench(O) && !active) + return TRUE + if(IS_WRENCH(used_item) && !active) if(!anchored) - connect_to_network() - to_chat(user, "You secure the generator to the floor.") + to_chat(user, "You secure \the [src] to the floor.") else - disconnect_from_network() - to_chat(user, "You unsecure the generator from the floor.") + to_chat(user, "You unsecure \the [src] from the floor.") playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) anchored = !anchored - return component_attackby(O, user) + return TRUE + return component_attackby(used_item, user) -/obj/machinery/power/port_gen/pacman/dismantle() +/obj/machinery/port_gen/pacman/dismantle() while (sheets > 0) DropFuel() . = ..() -/obj/machinery/power/port_gen/pacman/interface_interact(mob/user) +/obj/machinery/port_gen/pacman/interface_interact(mob/user) ui_interact(user) return TRUE -/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/port_gen/pacman/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) if(IsBroken()) return var/data[0] data["active"] = active - if(istype(user, /mob/living/silicon/ai)) + if(isAI(user)) data["is_ai"] = 1 - else if(istype(user, /mob/living/silicon/robot) && !Adjacent(user)) + else if(isrobot(user) && !Adjacent(user)) data["is_ai"] = 1 else data["is_ai"] = 0 @@ -342,9 +357,17 @@ data["fuel_stored"] = round((sheets * 1000) + (sheet_left * 1000)) data["fuel_capacity"] = round(max_sheets * 1000, 0.1) data["fuel_usage"] = active ? round((power_output / time_per_sheet) * 1000) : 0 - data["fuel_type"] = sheet_name + var/obj/item/stack/sheet_prototype = sheet_path + var/sheet_name = initial(sheet_prototype.plural_name) || "sheets" + if(sheet_material) + var/decl/material/sheet_mat = GET_DECL(sheet_material) + sheet_name = capitalize("[sheet_mat.solid_name] [capitalize(sheet_name)]") + data["fuel_type"] = capitalize(sheet_name) + data["uses_coolant"] = !!reagents + data["coolant_stored"] = REAGENT_TOTAL_VOLUME(reagents) + data["coolant_capacity"] = REAGENT_MAXIMUM_VOLUME(reagents) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -353,79 +376,52 @@ ui.open() ui.set_auto_update(1) - -/* -/obj/machinery/power/port_gen/pacman/interact(mob/user) - if (get_dist(src, user) > 1 ) - if (!istype(user, /mob/living/silicon/ai)) - user.unset_machine() - close_browser(user, "window=port_gen") - return - - user.set_machine(src) - - var/dat = text("[name]
    ") - if (active) - dat += text("Generator: On
    ") - else - dat += text("Generator: Off
    ") - dat += text("[capitalize(sheet_name)]: [sheets] - Eject
    ") - var/stack_percent = round(sheet_left * 100, 1) - dat += text("Current stack: [stack_percent]%
    ") - dat += text("Power output: - [power_gen * power_output] Watts+
    ") - dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]
    ") - - var/tempstr = "Temperature: [temperature]°C
    " - dat += (overheating)? "[tempstr]" : tempstr - dat += "
    Close" - show_browser(user, "[dat]", "window=port_gen") - onclose(user, "port_gen") -*/ - -/obj/machinery/power/port_gen/pacman/Topic(href, href_list) - if(..()) +/obj/machinery/port_gen/pacman/OnTopic(mob/user, href_list) + if((. = ..())) return - src.add_fingerprint(usr) if(href_list["action"]) if(href_list["action"] == "enable") if(!active && HasFuel() && !IsBroken()) - active = 1 - update_icon() + active = TRUE + . = TOPIC_REFRESH if(href_list["action"] == "disable") if (active) - active = 0 - update_icon() + active = FALSE + . = TOPIC_REFRESH if(href_list["action"] == "eject") if(!active) DropFuel() + . = TOPIC_REFRESH if(href_list["action"] == "lower_power") if (power_output > 1) power_output-- + . = TOPIC_REFRESH if (href_list["action"] == "higher_power") if (power_output < max_power_output || (emagged && power_output < round(max_power_output*2.5))) power_output++ + . = TOPIC_REFRESH -/obj/machinery/power/port_gen/pacman/super - name = "S.U.P.E.R.P.A.C.M.A.N.-type Portable Generator" - desc = "A power generator that utilizes uranium sheets as fuel. Can run for much longer than the standard PACMAN type generators. Rated for 80 kW max safe output." +/obj/machinery/port_gen/pacman/super + name = "portable fission generator" + desc = "A power generator that utilizes uranium sheets as fuel. Can run for much longer than the standard portable generators. Rated for 80 kW max safe output." icon_state = "portgen1" - sheet_path = /obj/item/stack/material/uranium - sheet_name = "Uranium Sheets" + sheet_path = /obj/item/stack/material/puck + sheet_material = /decl/material/solid/metal/uranium time_per_sheet = 576 //same power output, but a 50 sheet stack will last 2 hours at max safe power var/rad_power = 4 //nuclear energy is green energy! -/obj/machinery/power/port_gen/pacman/super/process_exhaust() +/obj/machinery/port_gen/pacman/super/process_exhaust() return -/obj/machinery/power/port_gen/pacman/super/UseFuel() +/obj/machinery/port_gen/pacman/super/UseFuel() //produces a tiny amount of radiation when in use if (prob(rad_power*power_output)) SSradiation.radiate(src, 2*rad_power) ..() -/obj/machinery/power/port_gen/pacman/super/on_update_icon() +/obj/machinery/port_gen/pacman/super/on_update_icon() if(..()) set_light(0) return 1 @@ -435,12 +431,12 @@ I.blend_mode = BLEND_ADD I.alpha = round(255*power_output/max_power_output) overlays += I - set_light(0.7, 0.1, rad_power + power_output - max_safe_output, 2, "#3b97ca") + set_light(rad_power + power_output - max_safe_output,1,"#3b97ca") else set_light(0) -/obj/machinery/power/port_gen/pacman/super/explode() +/obj/machinery/port_gen/pacman/super/explode() //a nice burst of radiation var/rads = rad_power*25 + (sheets + sheet_left)*1.5 SSradiation.radiate(src, (max(40, rads))) @@ -448,7 +444,7 @@ explosion(src.loc, rad_power+1, rad_power+1, rad_power*2, 3) qdel(src) -/obj/machinery/power/port_gen/pacman/super/potato +/obj/machinery/port_gen/pacman/super/potato name = "nuclear reactor" desc = "PTTO-3, an industrial all-in-one nuclear power plant by Neo-Chernobyl GmbH. It uses uranium and vodka as a fuel source. Rated for 150 kW max safe output." power_gen = 30000 //Watts output per power_output level @@ -460,21 +456,18 @@ time_per_sheet = 400 rad_power = 12 atom_flags = ATOM_FLAG_OPEN_CONTAINER - anchored = 1 - -/obj/machinery/power/port_gen/pacman/super/potato/Initialize() - create_reagents(120) - . = ..() + anchored = TRUE + chem_volume = 120 -/obj/machinery/power/port_gen/pacman/super/potato/examine(mob/user) +/obj/machinery/port_gen/pacman/super/potato/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "Auxilary tank shows [reagents.total_volume]u of liquid in it.") + . += "Auxilary tank shows [REAGENT_TOTAL_VOLUME(reagents)]u of liquid in it." -/obj/machinery/power/port_gen/pacman/super/potato/UseFuel() - if(reagents.has_reagent(/decl/material/liquid/ethanol/vodka)) +/obj/machinery/port_gen/pacman/super/potato/UseFuel() + if(reagents.has_reagent(/decl/material/liquid/alcohol/vodka)) rad_power = 4 temperature_gain = 60 - reagents.remove_any(1) + remove_any_reagents(1) if(prob(2)) audible_message("[src] churns happily") else @@ -482,31 +475,31 @@ temperature_gain = initial(temperature_gain) ..() -/obj/machinery/power/port_gen/pacman/super/potato/on_update_icon() +/obj/machinery/port_gen/pacman/super/potato/on_update_icon() if(..()) return 1 if(power_output > max_safe_output) icon_state = "potatodanger" -/obj/machinery/power/port_gen/pacman/super/potato/attackby(var/obj/item/O, var/mob/user) - if(istype(O, /obj/item/chems/)) - var/obj/item/chems/R = O - if(R.standard_pour_into(src,user)) - if(reagents.has_reagent(/decl/material/liquid/ethanol/vodka)) - audible_message("[src] blips happily") - playsound(get_turf(src),'sound/machines/synth_yes.ogg', 50, 0) - else - audible_message("[src] blips in disappointment") - playsound(get_turf(src), 'sound/machines/synth_no.ogg', 50, 0) - return - ..() +/obj/machinery/port_gen/pacman/super/potato/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/chems)) + var/obj/item/chems/chem_container = used_item + var/old_vodka_amount = REAGENT_VOLUME(reagents, /decl/material/liquid/alcohol/vodka) + if(chem_container.standard_pour_into(src,user)) + if(REAGENT_VOLUME(reagents, /decl/material/liquid/alcohol/vodka) > old_vodka_amount) // yay, booze! + audible_message(SPAN_NOTICE("[src] blips happily!")) + playsound(get_turf(src),'sound/machines/synth_yes.ogg', 50, FALSE) + else // you didn't add any more than we already had + audible_message(SPAN_WARNING("[src] blips in disappointment.")) + playsound(get_turf(src), 'sound/machines/synth_no.ogg', 50, FALSE) + return TRUE + return ..() -/obj/machinery/power/port_gen/pacman/mrs - name = "M.R.S.P.A.C.M.A.N.-type Portable Generator" - desc = "An advanced power generator that runs on tritium. Rated for 200 kW maximum safe output!" +/obj/machinery/port_gen/pacman/mrs + name = "portable fusion generator" + desc = "An advanced portable fusion generator that runs on tritium. Rated for 200 kW maximum safe output!" icon_state = "portgen2" - sheet_path = /obj/item/stack/material/tritium - sheet_name = "Tritium Fuel Sheets" + sheet_material = /decl/material/gas/hydrogen/tritium //I don't think tritium has any other use, so we might as well make this rewarding for players //max safe power output (power level = 8) is 200 kW and lasts for 1 hour - 3 or 4 of these could power the station @@ -517,7 +510,7 @@ max_temperature = 800 temperature_gain = 90 -/obj/machinery/power/port_gen/pacman/mrs/explode() +/obj/machinery/port_gen/pacman/mrs/explode() //no special effects, but the explosion is pretty big (same as a supermatter shard). explosion(src.loc, 3, 6, 12, 16, 1) qdel(src) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index 518d386155fd..8a49627444c2 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -1,5 +1,9 @@ ////////////////////////////// // POWER MACHINERY BASE CLASS +// This subtype is for machinery which needs to be directly referenced by its parent powernet during powernet processing. +// This subtype does not encompass all power generating machinery, or machinery that needs to draw from a powernet in general. +// If you try using this, make sure you can't just use get_powernet() instead. Ideally either the powernet needs to know about it (APCs) +// or we need to run logic when we connect or disconnect from a powernet (solar panels/trackers). ////////////////////////////// ///////////////////////////// @@ -7,9 +11,10 @@ ///////////////////////////// /obj/machinery/power + abstract_type = /obj/machinery/power name = null icon = 'icons/obj/power.dmi' - anchored = 1.0 + anchored = TRUE var/datum/powernet/powernet = null use_power = POWER_USE_OFF idle_power_usage = 0 @@ -42,12 +47,6 @@ powernet.trigger_warning() return powernet.draw_power(amount) -/obj/machinery/power/proc/add_avail(var/amount) - if(powernet) - powernet.newavail += amount - return 1 - return 0 - /obj/machinery/power/proc/draw_power(var/amount) if(powernet) return powernet.draw_power(amount) @@ -58,6 +57,11 @@ return powernet.avail-powernet.load else return 0 +/obj/machinery/power/proc/add_avail(var/amount) + if(powernet) + powernet.newavail += amount + return 1 + return 0 /obj/machinery/power/proc/avail() if(powernet) @@ -67,153 +71,78 @@ // connect the machine to a powernet if a node cable is present on the turf /obj/machinery/power/proc/connect_to_network() - var/turf/T = src.loc - if(!T || !istype(T)) - return 0 - - var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked - if(!C || !C.powernet) - return 0 - - C.powernet.add_machine(src) - return 1 + var/datum/powernet/P = get_powernet() + if(P) + P.add_machine(src) + return TRUE // remove and disconnect the machine from its current powernet /obj/machinery/power/proc/disconnect_from_network() if(!powernet) - return 0 + return powernet.remove_machine(src) - return 1 + return TRUE // attach a wire to a power machine - leads from the turf you are standing on //almost never called, overwritten by all power machines but terminal and generator -/obj/machinery/power/attackby(obj/item/W, mob/user) +/obj/machinery/power/attackby(obj/item/used_item, mob/user) if((. = ..())) return - - if(isCoil(W)) - - var/obj/item/stack/cable_coil/coil = W - + if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/coil = used_item var/turf/T = user.loc - - if(!T.is_plating() || !istype(T, /turf/simulated/floor)) + if(!istype(T) || T.density || T.cannot_build_cable()) return - if(get_dist(src, user) > 1) return - coil.turf_place(T, user) return TRUE -/////////////////////////////////////////// -// Powernet handling helpers -////////////////////////////////////////// - -//returns all the cables WITHOUT a powernet in neighbors turfs, -//pointing towards the turf the machine is located at -/obj/machinery/power/proc/get_connections() - - . = list() - - var/cdir - var/turf/T - - for(var/card in GLOB.cardinal) - T = get_step(loc,card) - cdir = get_dir(T,loc) - - for(var/obj/structure/cable/C in T) - if(C.powernet) continue - if(C.d1 == cdir || C.d2 == cdir) - . += C - return . - -//returns all the cables in neighbors turfs, -//pointing towards the turf the machine is located at -/obj/machinery/power/proc/get_marked_connections() - - . = list() - - var/cdir - var/turf/T - - for(var/card in GLOB.cardinal) - T = get_step(loc,card) - cdir = get_dir(T,loc) - - for(var/obj/structure/cable/C in T) - if(C.d1 == cdir || C.d2 == cdir) - . += C - return . - -//returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at -/obj/machinery/power/proc/get_indirect_connections() - . = list() - for(var/obj/structure/cable/C in loc) - if(C.powernet) continue - if(C.d1 == 0) // the cable is a node cable - . += C - return . - /////////////////////////////////////////// // GLOBAL PROCS for powernets handling ////////////////////////////////////////// - -// returns a list of all power-related objects (nodes, cable, junctions) in turf, -// excluding source, that match the direction d -// if unmarked==1, only return those with no powernet -/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0, var/cable_only = 0) +/// Returns all cables in target_turf matching target_direction, excluding excluded_cable. +/// If only_no_powernet is TRUE, only cables with no powernet will be returned. +/// Unused, because get_maching_cable or get_connected_cables is usually preferable, but kept just in case. +/proc/cable_list(var/turf/target_turf, var/obj/structure/cable/excluded_cable = null, var/target_direction) . = list() - - var/reverse = d ? GLOB.reverse_dir[d] : 0 - for(var/AM in T) - if(AM == source) continue //we don't want to return source - - if(!cable_only && istype(AM,/obj/machinery/power)) - var/obj/machinery/power/P = AM - if(P.powernet == 0) continue // exclude APCs which have powernet=0 - - if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet - if(d == 0) - . += P - - else if(istype(AM,/obj/structure/cable)) - var/obj/structure/cable/C = AM - - if(!unmarked || !C.powernet) - if(C.d1 == d || C.d2 == d || C.d1 == reverse || C.d2 == reverse ) - . += C - return . + var/reverse_direction = target_direction ? global.reverse_dir[target_direction] : 0 + for(var/obj/structure/cable/other_cable in target_turf) + if(other_cable == excluded_cable) + continue + if(other_cable.d1 == target_direction || other_cable.d2 == target_direction || other_cable.d1 == reverse_direction || other_cable.d2 == reverse_direction) + . += other_cable + +/// Like cable_list, but only returns the first cable, since that's all most uses of it check. +/proc/get_matching_cable(var/turf/target_turf, var/obj/structure/cable/excluded_cable = null, var/target_direction) + var/reverse_direction = target_direction ? global.reverse_dir[target_direction] : 0 + for(var/obj/structure/cable/other_cable in target_turf) + if(other_cable == excluded_cable) + continue + if(other_cable.d1 == target_direction || other_cable.d2 == target_direction || other_cable.d1 == reverse_direction || other_cable.d2 == reverse_direction) + return other_cable //remove the old powernet and replace it with a new one throughout the network. -/proc/propagate_network(var/obj/O, var/datum/powernet/PN) +/proc/propagate_network(var/obj/structure/cable/cable, var/datum/powernet/PN) //to_world_log("propagating new network") - var/list/worklist = list() + var/list/cables = list() var/list/found_machines = list() var/index = 1 - var/obj/P = null + var/obj/structure/cable/working_cable = null - worklist+=O //start propagating from the passed object - - while(index<=worklist.len) //until we've exhausted all power objects - P = worklist[index] //get the next power object found + // add the first cable to the list + cables[cable] = TRUE // associative list for speedy deduplication + while(index <= length(cables)) //until we've exhausted all power objects + working_cable = cables[index] //get the next power object found index++ - if( istype(P,/obj/structure/cable)) - var/obj/structure/cable/C = P - if(C.powernet != PN) //add it to the powernet, if it isn't already there - PN.add_cable(C) - worklist |= C.get_connections() //get adjacents power objects, with or without a powernet - - else if(P.anchored && istype(P,/obj/machinery/power)) - var/obj/machinery/power/M = P - found_machines |= M //we wait until the powernet is fully propagates to connect the machines - - else - continue + for(var/new_cable in working_cable.get_cable_connections()) //get adjacent cables, with or without a powernet + cables[new_cable] = TRUE + for(var/obj/structure/cable/cable_entry in cables) + PN.add_cable(cable_entry) + found_machines += cable_entry.get_machine_connections() //now that the powernet is set, connect found machines to it for(var/obj/machinery/power/PM in found_machines) if(!PM.connect_to_network()) //couldn't find a node on its turf... @@ -247,11 +176,14 @@ return net1 //Determines how strong could be shock, deals damage to mob, uses power. -//M is a mob who touched wire/whatever +//victim is a mob who touched wire/whatever //power_source is a source of electricity, can be powercell, area, apc, cable, powernet or null //source is an object caused electrocuting (airlock, grille, etc) //No animations will be performed by this proc. -/proc/electrocute_mob(mob/living/carbon/M, var/power_source, var/obj/source, var/siemens_coeff = 1.0) +/proc/electrocute_mob(mob/living/victim, power_source, obj/source, siemens_coeff = 1.0, coverage_flags = SLOT_HANDS) + + coverage_flags = victim?.get_active_hand_bodypart_flags() || coverage_flags + var/area/source_area if(istype(power_source,/area)) source_area = power_source @@ -267,8 +199,8 @@ PN = power_source else if(istype(power_source,/obj/item/cell)) cell = power_source - else if(istype(power_source,/obj/machinery/power/apc)) - var/obj/machinery/power/apc/apc = power_source + else if(istype(power_source,/obj/machinery/apc)) + var/obj/machinery/apc/apc = power_source cell = apc.get_cell() var/obj/machinery/power/terminal/term = apc.terminal() if (term) @@ -276,19 +208,16 @@ else if (!power_source) return 0 else - log_admin("ERROR: /proc/electrocute_mob([M], [power_source], [source]): wrong power_source") + log_admin("ERROR: /proc/electrocute_mob([victim], [power_source], [source]): wrong power_source") return 0 + //Triggers powernet warning, but only for 5 ticks (if applicable) //If following checks determine user is protected we won't alarm for long. if(PN) PN.trigger_warning(5) - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.species.siemens_coefficient <= 0) - return - if(H.gloves) - var/obj/item/clothing/gloves/G = H.gloves - if(G.siemens_coefficient == 0) return 0 //to avoid spamming with insulated glvoes on + + if(victim.get_siemens_coefficient_for_coverage(coverage_flags) <= 0) + return //Checks again. If we are still here subject will be shocked, trigger standard 20 tick warning //Since this one is longer it will override the original one. @@ -310,7 +239,7 @@ else power_source = cell shock_damage = cell_damage - var/drained_hp = M.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap! + var/drained_hp = victim.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap! var/drained_energy = drained_hp*20 if (source_area) diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm index fe2e32c64a79..6727118ba2f8 100644 --- a/code/modules/power/powernet.dm +++ b/code/modules/power/powernet.dm @@ -40,7 +40,7 @@ return max(avail - load, 0) /datum/powernet/proc/draw_power(var/amount) - var/draw = between(0, amount, avail - load) + var/draw = clamp(0, amount, avail - load) load += draw return draw @@ -101,10 +101,9 @@ if(problem > 0) problem = max(problem - 1, 0) - if(nodes && nodes.len) // Added to fix a bad list bug -- TLE - for(var/obj/machinery/power/terminal/term in nodes) - if( istype( term.master_machine(), /obj/machinery/power/apc ) ) - numapc++ + for(var/obj/machinery/power/terminal/term in nodes) + if( istype( term.master_machine(), /obj/machinery/apc ) ) + numapc++ netexcess = avail - load @@ -121,7 +120,7 @@ // At this point, all other machines have finished using power. Anything left over may be used up to charge SMESs. if(inputting.len && smes_demand) - var/smes_input_percentage = between(0, (netexcess / smes_demand) * 100, 100) + var/smes_input_percentage = clamp(0, (netexcess / smes_demand) * 100, 100) for(var/obj/machinery/power/smes/S in inputting) S.input_power(smes_input_percentage) @@ -149,11 +148,11 @@ var/smes_used = load - (avail - smes_avail) // SMESs are always last to provide power if(!smes_used || smes_used < 0 || !smes_avail) // SMES power isn't available or being used at all, SMES load is therefore 0% return 0 - return between(0, (smes_used / smes_avail) * 100, 100) // Otherwise return percentage load of SMESs. + return clamp(0, (smes_used / smes_avail) * 100, 100) // Otherwise return percentage load of SMESs. else if(!load) return 0 - return between(0, (avail / load) * 100, 100) + return clamp(0, (avail / load) * 100, 100) /datum/powernet/proc/get_electrocute_damage() switch(avail) @@ -178,13 +177,9 @@ // return a knot cable (O-X) if one is present in the turf // null if there's none /turf/proc/get_cable_node() - if(!istype(src, /turf/simulated)) - return null for(var/obj/structure/cable/C in src) if(C.d1 == 0) return C - return null - /area/proc/get_apc() return apc diff --git a/code/modules/power/powernet_sensor.dm b/code/modules/power/powernet_sensor.dm new file mode 100644 index 000000000000..0f52a584883a --- /dev/null +++ b/code/modules/power/powernet_sensor.dm @@ -0,0 +1,151 @@ +// POWERNET SENSOR +// +// Last Change 31.12.2014 by Atlantis +// +// Powernet sensors are devices which relay information about connected powernet. This information may be relayed +// via two procs. Proc return_reading_text will return fully HTML styled string which contains all information. This +// may be used in PDAs or similar applications. Second proc, return_reading_data will return list containing needed data. +// This is used in NanoUI, for example. + +/obj/machinery/power_sensor + name = "powernet sensor" + desc = "A sensor that records and transmits data about its connected power network." + anchored = TRUE + density = FALSE + level = LEVEL_BELOW_PLATING + icon = 'icons/obj/objects.dmi' + icon_state = "floor_beacon" // If anyone wants to make better sprite, feel free to do so without asking me. + + uncreated_component_parts = null + stat_immune = NOINPUT | NOSCREEN | NOPOWER + construct_state = /decl/machine_construction/pipe + frame_type = /obj/item/machine_chassis/power_sensor + +// Proc: New() +// Parameters: None +// Description: Automatically assigns name according to ID tag. +/obj/machinery/power_sensor/Initialize() + . = ..() + auto_set_name() + +// Proc: auto_set_name() +// Parameters: None +// Description: Sets name of this sensor according to the ID tag. +/obj/machinery/power_sensor/proc/auto_set_name() + if(!id_tag) + var/area/A = get_area(src) + if(!A) + return // in nullspace + var/suffix = uniqueness_repository.Generate(/datum/uniqueness_generator/id_sequential, "[A.proper_name]power/sensor", 1) // unlike sequential_id, starts at 1 instead of 100 + if(suffix == 1) + suffix = null + id_tag = "[A.proper_name][suffix ? " #[suffix]" : null]" + name = "[id_tag] - powernet sensor" + +// Proc: has_grid_warning() +// Parameters: None +// Description: Checks connected powernet for warnings. If warning is found returns TRUE +/obj/machinery/power_sensor/proc/has_grid_warning() + var/datum/powernet/net_to_check = get_powernet() + return net_to_check?.problem ? TRUE : FALSE + +// Proc: reading_to_text() +// Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW) +// Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter) +/obj/machinery/power_sensor/proc/reading_to_text(var/amount = 0) + var/units = "" + // 10kW and less - Watts + if(amount < 10000) + units = "W" + // 10MW and less - KiloWatts + else if(amount < 10000000) + units = "kW" + amount = (round(amount/100) / 10) + // More than 10MW - MegaWatts + else + units = "MW" + amount = (round(amount/10000) / 100) + if (units == "W") + return "[amount] W" + else + return "~[amount] [units]" //kW and MW are only approximate readings, therefore add "~" + +// Proc: find_apcs() +// Parameters: None +// Description: Searches powernet for APCs and returns them in a list. +/obj/machinery/power_sensor/proc/find_apcs() + var/datum/powernet/net_to_check = get_powernet() + if(!net_to_check) + return + + var/list/L = list() + for(var/obj/machinery/power/terminal/term in net_to_check.nodes) + var/obj/machinery/apc/A = term.master_machine() + if(istype(A)) + L += A + + return L + +// Proc: return_reading_data() +// Parameters: None +// Description: Generates list containing all powernet data. Optimised for usage with NanoUI +/obj/machinery/power_sensor/proc/return_reading_data() + var/datum/powernet/net_to_check = get_powernet() + var/list/data = list() + data["name"] = id_tag + if(!net_to_check) + data["error"] = "# SYSTEM ERROR - NO POWERNET #" + data["alarm"] = 0 // Runtime Prevention + return data + + var/list/L = find_apcs() + var/total_apc_load = 0 + var/list/APC_data = list() + if(L.len > 0) + // These lists are used as replacement for number based APC settings + var/list/S = list("M-OFF", "DC-OFF","A-OFF","M-ON", "A-ON") + var/list/chg = list("N","C","F") + + for(var/obj/machinery/apc/A in L) + var/list/APC_entry = list() + APC_entry["breaker"] = A.operating + APC_entry["failure"] = A.failure_timer + APC_entry["telemetry"] = A.aidisabled + APC_entry["remote_control"] = A.remote_control + // Channel Statuses + APC_entry["s_equipment"] = S[A.equipment+1] + APC_entry["s_lighting"] = S[A.lighting+1] + APC_entry["s_environment"] = S[A.environ+1] + // Channel Statuses (actual vars) + APC_entry["n_equipment"] = A.equipment + APC_entry["n_lighting"] = A.lighting + APC_entry["n_environment"] = A.environ + // Cell Status + var/obj/item/cell/cell = A.get_cell() + APC_entry["cell_charge"] = cell ? round(cell.percent()) : "NO CELL" + APC_entry["cell_status"] = cell ? chg[A.charging+1] : "N" + // Other info + APC_entry["total_load"] = reading_to_text(A.lastused_total) + APC_entry["name"] = A.area.proper_name + APC_entry["ref"] = "\ref[A]" + // Add data into main list of APC data. + APC_data += list(APC_entry) + // Add load of this APC to total APC load calculation + total_apc_load += A.lastused_total + data["apc_data"] = APC_data + data["total_avail"] = reading_to_text(max(net_to_check.avail, 0)) + data["total_used_apc"] = reading_to_text(max(total_apc_load, 0)) + data["total_used_other"] = reading_to_text(max(net_to_check.viewload - total_apc_load, 0)) + data["total_used_all"] = reading_to_text(max(net_to_check.viewload, 0)) + // Prevents runtimes when avail is 0 (division by zero) + if(net_to_check.avail) + data["load_percentage"] = round((net_to_check.viewload / net_to_check.avail) * 100) + else + data["load_percentage"] = 100 + data["alarm"] = net_to_check.problem ? 1 : 0 + return data + + + + + diff --git a/code/modules/power/sensors/powernet_sensor.dm b/code/modules/power/sensors/powernet_sensor.dm deleted file mode 100644 index 7913f50c59c5..000000000000 --- a/code/modules/power/sensors/powernet_sensor.dm +++ /dev/null @@ -1,192 +0,0 @@ -// POWERNET SENSOR -// -// Last Change 31.12.2014 by Atlantis -// -// Powernet sensors are devices which relay information about connected powernet. This information may be relayed -// via two procs. Proc return_reading_text will return fully HTML styled string which contains all information. This -// may be used in PDAs or similar applications. Second proc, return_reading_data will return list containing needed data. -// This is used in NanoUI, for example. - -/obj/machinery/power/sensor - name = "Powernet Sensor" - desc = "Small machine which transmits data about specific powernet." - anchored = 1 - density = 0 - level = 1 - icon = 'icons/obj/objects.dmi' - icon_state = "floor_beacon" // If anyone wants to make better sprite, feel free to do so without asking me. - - uncreated_component_parts = null - stat_immune = NOINPUT | NOSCREEN | NOPOWER - construct_state = /decl/machine_construction/pipe - frame_type = /obj/item/machine_chassis/power_sensor - -// Proc: New() -// Parameters: None -// Description: Automatically assigns name according to ID tag. -/obj/machinery/power/sensor/Initialize() - . = ..() - auto_set_name() - -// Proc: auto_set_name() -// Parameters: None -// Description: Sets name of this sensor according to the ID tag. -/obj/machinery/power/sensor/proc/auto_set_name() - if(!id_tag) - var/area/A = get_area(src) - if(!A) - return // in nullspace - id_tag = "[A.name] #[sequential_id(A.name + "power/sensor")]" - name = "[id_tag] - Powernet Sensor" - -// Proc: check_grid_warning() -// Parameters: None -// Description: Checks connected powernet for warnings. If warning is found returns 1 -/obj/machinery/power/sensor/proc/check_grid_warning() - connect_to_network() - if(powernet) - if(powernet.problem) - return 1 - return 0 - -// Proc: reading_to_text() -// Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW) -// Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter) -/obj/machinery/power/sensor/proc/reading_to_text(var/amount = 0) - var/units = "" - // 10kW and less - Watts - if(amount < 10000) - units = "W" - // 10MW and less - KiloWatts - else if(amount < 10000000) - units = "kW" - amount = (round(amount/100) / 10) - // More than 10MW - MegaWatts - else - units = "MW" - amount = (round(amount/10000) / 100) - if (units == "W") - return "[amount] W" - else - return "~[amount] [units]" //kW and MW are only approximate readings, therefore add "~" - -// Proc: find_apcs() -// Parameters: None -// Description: Searches powernet for APCs and returns them in a list. -/obj/machinery/power/sensor/proc/find_apcs() - if(!powernet) - return - - var/list/L = list() - for(var/obj/machinery/power/terminal/term in powernet.nodes) - var/obj/machinery/power/apc/A = term.master_machine() - if(istype(A)) - L += A - - return L - - -// Proc: return_reading_text() -// Parameters: None -// Description: Generates string which contains HTML table with reading data. -/obj/machinery/power/sensor/proc/return_reading_text() - // No powernet. Try to connect to one first. - if(!powernet) - connect_to_network() - var/out = "" - if(!powernet) // No powernet. - out = "# SYSTEM ERROR - NO POWERNET #" - return out - - - var/list/L = find_apcs() - var/total_apc_load = 0 - if(L.len <= 0) // No APCs found. - out = "No APCs located in connected powernet!" - else // APCs found. Create very ugly (but working!) HTML table. - - out += "
    [capitalize(mat.gas_name)][C.owned_field.reactants[reactant]]
    Nothing.
    " - dat += "" + dat += "" dat += "" - dat += "" + dat += "" - dat += "" + dat += "" dat += "
    NameEQUIPLIGHTENVIRONCELLLOAD" - - // These lists are used as replacement for number based APC settings - var/list/S = list("M-OFF","A-OFF","M-ON", "A-ON") - var/list/chg = list("N","C","F") - - // Split to multiple lines to make it more readable - for(var/obj/machinery/power/apc/A in L) - out += "
    \The [A.area]" // Add area name - out += "[S[A.equipment+1]][S[A.lighting+1]][S[A.environ+1]]" // Show status of channels - var/obj/item/cell/cell = A.get_cell() - if(cell) - out += "[round(cell.percent())]% - [chg[A.charging+1]]" - else - out += "NO CELL" - var/load = A.lastused_total // Load. - total_apc_load += load - load = reading_to_text(load) - out += "[load]" - - out += "
    TOTAL AVAILABLE: [reading_to_text(powernet.avail)]" - out += "
    APC LOAD: [reading_to_text(total_apc_load)]" - out += "
    OTHER LOAD: [reading_to_text(max(powernet.load - total_apc_load, 0))]" - out += "
    TOTAL GRID LOAD: [reading_to_text(powernet.viewload)] ([round((powernet.load / powernet.avail) * 100)]%)" - - if(powernet.problem) - out += "
    WARNING: Abnormal grid activity detected!" - return out - -// Proc: return_reading_data() -// Parameters: None -// Description: Generates list containing all powernet data. Optimised for usage with NanoUI -/obj/machinery/power/sensor/proc/return_reading_data() - // No powernet. Try to connect to one first. - if(!powernet) - connect_to_network() - var/list/data = list() - data["name"] = id_tag - if(!powernet) - data["error"] = "# SYSTEM ERROR - NO POWERNET #" - data["alarm"] = 0 // Runtime Prevention - return data - - var/list/L = find_apcs() - var/total_apc_load = 0 - var/list/APC_data = list() - if(L.len > 0) - // These lists are used as replacement for number based APC settings - var/list/S = list("M-OFF", "DC-OFF","A-OFF","M-ON", "A-ON") - var/list/chg = list("N","C","F") - - for(var/obj/machinery/power/apc/A in L) - var/list/APC_entry = list() - // Channel Statuses - APC_entry["s_equipment"] = S[A.equipment+1] - APC_entry["s_lighting"] = S[A.lighting+1] - APC_entry["s_environment"] = S[A.environ+1] - // Cell Status - var/obj/item/cell/cell = A.get_cell() - APC_entry["cell_charge"] = cell ? round(cell.percent()) : "NO CELL" - APC_entry["cell_status"] = cell ? chg[A.charging+1] : "N" - // Other info - APC_entry["total_load"] = reading_to_text(A.lastused_total) - APC_entry["name"] = A.area.name - // Add data into main list of APC data. - APC_data += list(APC_entry) - // Add load of this APC to total APC load calculation - total_apc_load += A.lastused_total - data["apc_data"] = APC_data - data["total_avail"] = reading_to_text(max(powernet.avail, 0)) - data["total_used_apc"] = reading_to_text(max(total_apc_load, 0)) - data["total_used_other"] = reading_to_text(max(powernet.viewload - total_apc_load, 0)) - data["total_used_all"] = reading_to_text(max(powernet.viewload, 0)) - // Prevents runtimes when avail is 0 (division by zero) - if(powernet.avail) - data["load_percentage"] = round((powernet.viewload / powernet.avail) * 100) - else - data["load_percentage"] = 100 - data["alarm"] = powernet.problem ? 1 : 0 - return data - - - - - diff --git a/code/modules/power/sensors/sensor_monitoring.dm b/code/modules/power/sensors/sensor_monitoring.dm deleted file mode 100644 index a9252f605c3c..000000000000 --- a/code/modules/power/sensors/sensor_monitoring.dm +++ /dev/null @@ -1,62 +0,0 @@ -// POWERNET SENSOR MONITORING CONSOLE -// Connects to powernet sensors and loads data from them. Shows this data to the user. -// Newly supports NanoUI. - - -/obj/machinery/computer/power_monitor - name = "Power Monitoring Console" - desc = "Computer designed to remotely monitor power levels." - icon = 'icons/obj/computer.dmi' - icon_keyboard = "power_key" - icon_screen = "power" - light_color = "#ffcc33" - - //computer stuff - density = 1 - anchored = 1.0 - var/alerting = 0 - idle_power_usage = 300 - active_power_usage = 300 - var/datum/nano_module/power_monitor/power_monitor - -// Checks the sensors for alerts. If change (alerts cleared or detected) occurs, calls for icon update. -/obj/machinery/computer/power_monitor/Process() - var/alert = check_warnings() - if(alert != alerting) - alerting = !alerting - update_icon() - -// Updates icon of this computer according to current status. -/obj/machinery/computer/power_monitor/on_update_icon() - if(stat & BROKEN) - icon_state = "powerb" - return - if(stat & NOPOWER) - icon_state = "power0" - return - if(alerting) - icon_state = "power_alert" - return - icon_state = "power" - -// On creation automatically connects to active sensors. This is delayed to ensure sensors already exist. -/obj/machinery/computer/power_monitor/Initialize() - . = ..() - power_monitor = new(src) - -// On user click opens the UI of this computer. -/obj/machinery/computer/power_monitor/interface_interact(mob/user) - ui_interact(user) - return TRUE - -// Uses dark magic to operate the NanoUI of this computer. -/obj/machinery/computer/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - power_monitor.ui_interact(user, ui_key, ui, force_open) - - -// Verifies if any warnings were registered by connected sensors. -/obj/machinery/computer/power_monitor/proc/check_warnings() - for(var/obj/machinery/power/sensor/S in power_monitor.grid_sensors) - if(S.check_grid_warning()) - return 1 - return 0 diff --git a/code/modules/power/singularity/act.dm b/code/modules/power/singularity/act.dm deleted file mode 100644 index dd185bb3fba4..000000000000 --- a/code/modules/power/singularity/act.dm +++ /dev/null @@ -1,114 +0,0 @@ -#define I_SINGULO "singulo" - -/atom/proc/singularity_act() - return - -/atom/proc/singularity_pull(S, current_size) - return - -/mob/living/singularity_act() - investigate_log("has been consumed by a singularity", I_SINGULO) - gib() - return 20 - -/mob/living/singularity_pull(S, current_size) - step_towards(src, S) - apply_damage(current_size * 3, IRRADIATE, damage_flags = DAM_DISPERSED) - -/mob/living/carbon/human/singularity_pull(S, current_size) - if(current_size >= STAGE_THREE) - var/list/handlist = list(l_hand, r_hand) - for(var/obj/item/hand in handlist) - if(prob(current_size*5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand)) - step_towards(hand, S) - to_chat(src, "\The [S] pulls \the [hand] from your grip!") - if(!lying && (!shoes || !(shoes.item_flags & ITEM_FLAG_NOSLIP)) && (!species || !(species.check_no_slip(src))) && prob(current_size*5)) - to_chat(src, "A strong gravitational force slams you to the ground!") - Weaken(current_size) - ..() - -/obj/singularity_act() - if(simulated) - explosion_act(1) - if(!QDELETED(src)) - qdel(src) - return 2 - -/obj/singularity_pull(S, current_size) - if(simulated && !anchored) - step_towards(src, S) - -/obj/effect/beam/singularity_pull() - return - -/obj/effect/overlay/singularity_pull() - return - -/obj/item/singularity_pull(S, current_size) - set waitfor = 0 - if(anchored) - return - sleep(0) //this is needed or multiple items will be thrown sequentially and not simultaneously - if(current_size >= STAGE_FOUR) - //throw_at(S, 14, 3) - step_towards(src,S) - sleep(1) - step_towards(src,S) - else if(current_size > STAGE_ONE) - step_towards(src,S) - else ..() - -/obj/machinery/atmospherics/pipe/singularity_pull() - return - -/obj/machinery/power/supermatter/shard/singularity_act() - src.forceMove(null) - qdel(src) - return 5000 - -/obj/machinery/power/supermatter/singularity_act() - if(!src.loc) - return - - var/prints = "" - if(src.fingerprintshidden) - prints = ", all touchers : " + src.fingerprintshidden - - SetUniversalState(/datum/universal_state/supermatter_cascade) - log_and_message_admins("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].") - src.forceMove(null) - qdel(src) - return 50000 - -/obj/item/projectile/beam/emitter/singularity_pull() - return - -/obj/item/storage/backpack/holding/singularity_act(S, current_size) - var/dist = max((current_size - 2), 1) - explosion(src.loc,(dist),(dist*2),(dist*4)) - return 1000 - -/turf/singularity_act(S, current_size) - if(!is_plating()) - for(var/obj/O in contents) - if(O.level != 1) - continue - if(O.invisibility == 101) - O.singularity_act(src, current_size) - ChangeTurf(get_base_turf_by_area(src)) - return 2 - -/turf/space/singularity_act() - return - -/******************* -* Nar-Sie Act/Pull * -*******************/ -/atom/proc/singuloCanEat() - return 1 - -/mob/observer/singuloCanEat() - return 0 - -/mob/new_player/singuloCanEat() - return 0 diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 003e6c4a57aa..cd70fdbc44a5 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -2,17 +2,17 @@ var/global/list/rad_collectors = list() // TODO: swap the hydrogen tanks out for lithium sheets or something like that. -/obj/machinery/power/rad_collector +/obj/machinery/rad_collector name = "radiation collector array" - desc = "A device which uses radiation and hydrogen to produce power." + desc = "A device which uses radiation and a reactant to produce power." icon = 'icons/obj/machines/rad_collector.dmi' icon_state = "ca" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE initial_access = list(access_engine_equip) - var/obj/item/tank/hydrogen/loaded_tank = null + max_health = 100 + var/obj/item/tank/loaded_tank = null - var/health = 100 var/max_safe_temp = 1000 + T0C var/melted @@ -29,23 +29,23 @@ var/global/list/rad_collectors = list() var/end_time = 0 var/alert_delay = 10 SECONDS -/obj/machinery/power/rad_collector/Initialize() +/obj/machinery/rad_collector/Initialize() . = ..() - rad_collectors += src + global.rad_collectors += src -/obj/machinery/power/rad_collector/Destroy() - rad_collectors -= src +/obj/machinery/rad_collector/Destroy() + global.rad_collectors -= src . = ..() -/obj/machinery/power/rad_collector/Process() +/obj/machinery/rad_collector/Process() if((stat & BROKEN) || melted) return var/turf/T = get_turf(src) if(T) var/datum/gas_mixture/our_turfs_air = T.return_air() if(our_turfs_air.temperature > max_safe_temp) - health -= ((our_turfs_air.temperature - max_safe_temp) / 10) - if(health <= 0) + current_health -= ((our_turfs_air.temperature - max_safe_temp) / 10) + if(current_health <= 0) collector_break() //so that we don't zero out the meter if the SM is processed first. @@ -59,7 +59,7 @@ var/global/list/rad_collectors = list() if(last_rads > max_rads) if(world.time > end_time) end_time = world.time + alert_delay - visible_message("\icon[src] \the [src] beeps loudly as the radiation reaches dangerous levels, indicating imminent damage.") + visible_message("[html_icon(src)] \the [src] beeps loudly as the radiation reaches dangerous levels, indicating imminent damage.") playsound(src, 'sound/effects/screech.ogg', 100, 1, 1) receive_pulse(12.5*(last_rads/max_rads)/(0.3+(last_rads/max_rads))) @@ -70,85 +70,80 @@ var/global/list/rad_collectors = list() else loaded_tank.air_adjust_gas(/decl/material/gas/hydrogen, -0.01*drainratio*min(last_rads,max_rads)/max_rads) //fuel cost increases linearly with incoming radiation -/obj/machinery/power/rad_collector/CanUseTopic(mob/user) +/obj/machinery/rad_collector/CanUseTopic(mob/user) if(!anchored) return STATUS_CLOSE return ..() -/obj/machinery/power/rad_collector/interface_interact(mob/user) +/obj/machinery/rad_collector/interface_interact(mob/user) if(!CanInteract(user, DefaultTopicState())) return FALSE . = TRUE if((stat & BROKEN) || melted) - to_chat(user, "The [src] is completely destroyed!") + to_chat(user, SPAN_WARNING("\The [src] is completely destroyed!")) if(!src.locked) toggle_power() - user.visible_message("[user.name] turns the [src.name] [active? "on":"off"].", \ - "You turn the [src.name] [active? "on":"off"].") + user.visible_message("[user.name] turns \the [src] [active? "on":"off"].", \ + "You turn \the [src] [active? "on":"off"].") investigate_log("turned [active?"on":"off"] by [user.key]. [loaded_tank?"Fuel: [round(loaded_tank.air_contents.gas[/decl/material/gas/hydrogen]/0.29)]%":"It is empty"].","singulo") else - to_chat(user, "The controls are locked!") + to_chat(user, SPAN_WARNING("The controls are locked!")) -/obj/machinery/power/rad_collector/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/tank/hydrogen)) +/obj/machinery/rad_collector/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/tank)) if(!src.anchored) - to_chat(user, "The [src] needs to be secured to the floor first.") - return 1 + to_chat(user, SPAN_WARNING("\The [src] needs to be secured to the floor first.")) + return TRUE if(src.loaded_tank) - to_chat(user, "There's already a tank loaded.") - return 1 - if(!user.unEquip(W, src)) - return - src.loaded_tank = W + to_chat(user, SPAN_WARNING("There's already a tank loaded.")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + src.loaded_tank = used_item update_icon() - return 1 - else if(isCrowbar(W)) + return TRUE + else if(IS_CROWBAR(used_item)) if(loaded_tank && !src.locked) eject() - return 1 - else if(isWrench(W)) + return TRUE + else if(IS_WRENCH(used_item)) if(loaded_tank) - to_chat(user, "Remove the tank first.") - return 1 - for(var/obj/machinery/power/rad_collector/R in get_turf(src)) + to_chat(user, SPAN_NOTICE("Remove the tank first.")) + return TRUE + for(var/obj/machinery/rad_collector/R in get_turf(src)) if(R != src) - to_chat(user, "You cannot install more than one collector on the same spot.") - return 1 + to_chat(user, SPAN_WARNING("You cannot install more than one collector on the same spot.")) + return TRUE playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) src.anchored = !src.anchored - user.visible_message("[user.name] [anchored? "secures":"unsecures"] the [src.name].", \ + user.visible_message("[user.name] [anchored? "secures":"unsecures"] \the [src].", \ "You [anchored? "secure":"undo"] the external bolts.", \ - "You hear a ratchet") - if(anchored && !(stat & BROKEN)) - connect_to_network() - else - disconnect_from_network() - return 1 - else if(istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer)) + "You hear a ratchet.") + return TRUE + else if(istype(used_item, /obj/item/card/id)||istype(used_item, /obj/item/modular_computer)) if (src.allowed(user)) if(active) src.locked = !src.locked to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]") else src.locked = 0 //just in case it somehow gets locked - to_chat(user, "The controls can only be locked when the [src] is active") + to_chat(user, SPAN_WARNING("The controls can only be locked when \the [src] is active.")) else - to_chat(user, "Access denied!") - return 1 + to_chat(user, SPAN_WARNING("Access denied!")) + return TRUE return ..() -/obj/machinery/power/rad_collector/examine(mob/user, distance) +/obj/machinery/rad_collector/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if (distance <= 3 && !(stat & BROKEN)) - to_chat(user, "The meter indicates that \the [src] is collecting [last_power] W.") - return 1 + . += "The meter indicates that \the [src] is collecting [last_power] W." -/obj/machinery/power/rad_collector/explosion_act(severity) +/obj/machinery/rad_collector/explosion_act(severity) if(severity != 1) eject() . = ..() -/obj/machinery/power/rad_collector/proc/collector_break() +/obj/machinery/rad_collector/proc/collector_break() if(loaded_tank?.air_contents) var/turf/T = get_turf(src) if(T) @@ -157,7 +152,6 @@ var/global/list/rad_collectors = list() fragmentate(T, 2, 4, list(/obj/item/projectile/bullet/pellet/fragment/tank/small = 3, /obj/item/projectile/bullet/pellet/fragment/tank = 1)) explosion(T, -1, -1, 0) QDEL_NULL(loaded_tank) - disconnect_from_network() stat |= BROKEN melted = TRUE anchored = FALSE @@ -165,33 +159,32 @@ var/global/list/rad_collectors = list() desc += " This one is destroyed beyond repair." update_icon() -/obj/machinery/power/rad_collector/return_air() +/obj/machinery/rad_collector/return_air() . =loaded_tank?.return_air() -/obj/machinery/power/rad_collector/proc/eject() +/obj/machinery/rad_collector/proc/eject() locked = 0 - var/obj/item/tank/hydrogen/Z = src.loaded_tank - if (!Z) + if (!loaded_tank) return - Z.dropInto(loc) - Z.reset_plane_and_layer() - src.loaded_tank = null + loaded_tank.dropInto(loc) + loaded_tank.reset_plane_and_layer() + loaded_tank = null if(active) toggle_power() else update_icon() -/obj/machinery/power/rad_collector/proc/receive_pulse(var/pulse_strength) +/obj/machinery/rad_collector/proc/receive_pulse(var/pulse_strength) if(loaded_tank && active) var/power_produced = 0 power_produced = min(100*loaded_tank.air_contents.gas[/decl/material/gas/hydrogen]*pulse_strength*pulse_coeff,max_power) - add_avail(power_produced) + generate_power(power_produced) last_power_new = power_produced return return -/obj/machinery/power/rad_collector/on_update_icon() +/obj/machinery/rad_collector/on_update_icon() if(melted) icon_state = "ca_melt" else if(active) @@ -213,7 +206,7 @@ var/global/list/rad_collectors = list() overlays += image(icon, "rads_[rad_power]") overlays += image(icon, "on") -/obj/machinery/power/rad_collector/toggle_power() +/obj/machinery/rad_collector/toggle_power() active = !active if(active) flick("ca_active", src) diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index 5fd04d357185..58102806b842 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -1,66 +1,55 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 -/obj/machinery/containment_field - name = "Containment Field" +/obj/effect/containment_field + name = "containment field" desc = "An energy field." icon = 'icons/obj/singularity.dmi' icon_state = "Contain_F" - anchored = 1 - density = 0 - unacidable = 1 - use_power = POWER_USE_OFF - uncreated_component_parts = null - light_outer_range = 4 + anchored = TRUE + density = FALSE + light_range = 4 movable_flags = MOVABLE_FLAG_PROXMOVE var/obj/machinery/field_generator/FG1 = null var/obj/machinery/field_generator/FG2 = null - var/hasShocked = 0 //Used to add a delay between shocks. In some cases this used to crash servers by spawning hundreds of sparks every second. + var/next_shock_time = 0 SECONDS //Used to add a delay between shocks. In some cases this used to crash servers by spawning hundreds of sparks every second. -/obj/machinery/containment_field/Destroy() +/obj/effect/containment_field/Destroy() if(FG1 && !FG1.clean_up) FG1.cleanup() if(FG2 && !FG2.clean_up) FG2.cleanup() . = ..() -/obj/machinery/containment_field/physical_attack_hand(mob/user) - return shock(user) +/obj/effect/containment_field/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + shock(user) + return TRUE -/obj/machinery/containment_field/explosion_act(severity) +/obj/effect/containment_field/explosion_act(severity) SHOULD_CALL_PARENT(FALSE) - return 0 + return FALSE -/obj/machinery/containment_field/HasProximity(atom/movable/AM) - if(istype(AM,/mob/living/silicon) && prob(40)) - shock(AM) - return 1 - if(istype(AM,/mob/living/carbon) && prob(50)) +/obj/effect/containment_field/HasProximity(atom/movable/AM) + . = ..() + if(. && isliving(AM) && prob(50)) shock(AM) - return 1 - return 0 - - -/obj/machinery/containment_field/shock(mob/living/user) - if(hasShocked) - return 0 +/obj/effect/containment_field/proc/shock(mob/living/user) + if(next_shock_time > world.time) + return FALSE if(!FG1 || !FG2) qdel(src) - return 0 + return FALSE if(isliving(user)) - hasShocked = 1 + next_shock_time = world.time + 2 SECONDS var/shock_damage = min(rand(30,40),rand(30,40)) user.electrocute_act(shock_damage, src) - var/atom/target = get_edge_target_turf(user, get_dir(src, get_step_away(user, src))) user.throw_at(target, 200, 4) - - sleep(20) - - hasShocked = 0 return TRUE + return FALSE -/obj/machinery/containment_field/proc/set_master(var/master1,var/master2) +/obj/effect/containment_field/proc/set_master(var/master1,var/master2) if(!master1 || !master2) return 0 FG1 = master1 diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 8d65bc18cffc..192376cc994f 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -1,18 +1,18 @@ #define EMITTER_DAMAGE_POWER_TRANSFER 450 //used to transfer power to containment field generators -/obj/machinery/power/emitter +/obj/machinery/emitter name = "emitter" desc = "A massive heavy industrial laser. This design is a fixed installation, capable of shooting in only one direction." icon = 'icons/obj/singularity.dmi' icon_state = "emitter" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE initial_access = list(access_engine_equip) active_power_usage = 100 KILOWATTS var/efficiency = 0.3 // Energy efficiency. 30% at this time, so 100kW load means 30kW laser pulses. + var/minimum_power = 10 KILOWATTS // The minimum power below which the emitter will turn off; different than the power needed to fire. var/active = 0 - var/powered = 0 var/fire_delay = 100 var/max_burst_delay = 100 var/min_burst_delay = 20 @@ -21,11 +21,12 @@ var/shot_number = 0 var/state = 0 var/locked = 0 + var/powered = 0 core_skill = SKILL_ENGINES uncreated_component_parts = list( /obj/item/stock_parts/radio/receiver, - /obj/item/stock_parts/power/apc + /obj/item/stock_parts/power/terminal ) public_variables = list( /decl/public_access/public_variable/emitter_active, @@ -34,58 +35,50 @@ public_methods = list( /decl/public_access/public_method/toggle_emitter ) - stock_part_presets = list(/decl/stock_part_preset/radio/receiver/emitter = 1) + stock_part_presets = list(/decl/stock_part_preset/radio/receiver/emitter = 1, /decl/stock_part_preset/terminal_connect = 1) -/obj/machinery/power/emitter/anchored - anchored = 1 +/obj/machinery/emitter/anchored + anchored = TRUE state = 2 -/obj/machinery/power/emitter/Initialize() - . = ..() - if(state == 2 && anchored) - connect_to_network() - -/obj/machinery/power/emitter/Destroy() +/obj/machinery/emitter/Destroy() log_and_message_admins("deleted \the [src]") investigate_log("deleted at ([x],[y],[z])","singulo") return ..() -/obj/machinery/power/emitter/on_update_icon() - if (active && powernet && avail(active_power_usage)) +/obj/machinery/emitter/on_update_icon() + if (active && powered) icon_state = "emitter_+a" else icon_state = "emitter" -/obj/machinery/power/emitter/interface_interact(mob/user) +/obj/machinery/emitter/interface_interact(mob/user) if(!CanInteract(user, DefaultTopicState())) return FALSE activate(user) return TRUE -/obj/machinery/power/emitter/proc/activate(mob/user) +/obj/machinery/emitter/proc/activate(mob/user) if(!istype(user)) user = null // safety, as the proc is publicly available. if(state == 2) - if(!powernet) - to_chat(user, "\The [src] isn't connected to a wire.") - return 1 - if(!src.locked) - if(src.active==1) - src.active = 0 + if(!locked) + if(active==1) + active = 0 to_chat(user, "You turn off \the [src].") - log_and_message_admins("turned off \the [src]") - investigate_log("turned off by [key_name_admin(user || usr)]","singulo") + log_and_message_admins("turned off \the [src]", user) + investigate_log("turned off by [key_name_admin(user)]","singulo") else - src.active = 1 + active = 1 if(user) operator_skill = user.get_skill_value(core_skill) update_efficiency() to_chat(user, "You turn on \the [src].") - src.shot_number = 0 - src.fire_delay = get_initial_fire_delay() - log_and_message_admins("turned on \the [src]") - investigate_log("turned on by [key_name_admin(user || usr)]","singulo") + shot_number = 0 + fire_delay = get_initial_fire_delay() + log_and_message_admins("turned on \the [src]", user) + investigate_log("turned on by [key_name_admin(user)]","singulo") update_icon() else to_chat(user, "The controls are locked!") @@ -93,135 +86,127 @@ to_chat(user, "\The [src] needs to be firmly secured to the floor first.") return 1 -/obj/machinery/power/emitter/proc/update_efficiency() +/obj/machinery/emitter/proc/update_efficiency() efficiency = initial(efficiency) if(!operator_skill) return var/skill_modifier = 0.8 * (SKILL_MAX - operator_skill)/(SKILL_MAX - SKILL_MIN) //How much randomness is added efficiency *= 1 + (rand() - 1) * skill_modifier //subtract off between 0.8 and 0, depending on skill and luck. -/obj/machinery/power/emitter/emp_act(var/severity) +/obj/machinery/emitter/emp_act(var/severity) return 1 -/obj/machinery/power/emitter/Process() +/obj/machinery/emitter/Process() if(stat & (BROKEN)) return - if(src.state != 2 || (!powernet && active_power_usage)) - src.active = 0 + if(state != 2) + active = FALSE update_icon() return - if(((src.last_shot + src.fire_delay) <= world.time) && (src.active == 1)) - - var/actual_load = draw_power(active_power_usage) - if(actual_load >= active_power_usage) //does the laser have enough power to shoot? - if(!powered) - powered = 1 - update_icon() - investigate_log("regained power and turned on","singulo") - else - if(powered) - powered = 0 - update_icon() - investigate_log("lost power and turned off","singulo") + if(((last_shot + fire_delay) <= world.time) && (active == 1)) + if(active_power_usage - can_use_power_oneoff(active_power_usage) < minimum_power) + powered = FALSE + update_icon() return - - src.last_shot = world.time - if(src.shot_number < burst_shots) - src.fire_delay = get_burst_delay() - src.shot_number ++ + var/drawn_power = min(active_power_usage, active_power_usage - use_power_oneoff(active_power_usage)) + last_shot = world.time + if(shot_number < burst_shots) + fire_delay = get_burst_delay() + shot_number ++ else - src.fire_delay = get_rand_burst_delay() - src.shot_number = 0 + fire_delay = get_rand_burst_delay() + shot_number = 0 //need to calculate the power per shot as the emitter doesn't fire continuously. var/burst_time = (min_burst_delay + max_burst_delay)/2 + 2*(burst_shots-1) - var/power_per_shot = (active_power_usage * efficiency) * (burst_time/10) / burst_shots + var/power_per_shot = (drawn_power * efficiency) * (burst_time/10) / burst_shots if(prob(35)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() + spark_at(src, amount=5, cardinal_only = TRUE) var/obj/item/projectile/beam/emitter/A = get_emitter_beam() - playsound(src.loc, A.fire_sound, 25, 1) + playsound(loc, A.fire_sound, 25, 1) A.damage = round(power_per_shot/EMITTER_DAMAGE_POWER_TRANSFER) - A.launch( get_step(src.loc, src.dir) ) + A.launch( get_step(loc, dir) ) + + if(!powered) + powered = TRUE + update_icon() -/obj/machinery/power/emitter/attackby(obj/item/W, mob/user) +/obj/machinery/emitter/attackby(obj/item/used_item, mob/user) - if(isWrench(W)) + if(IS_WRENCH(used_item)) if(active) to_chat(user, "Turn off [src] first.") - return + return TRUE switch(state) if(0) state = 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) user.visible_message("[user.name] secures [src] to the floor.", \ "You secure the external reinforcing bolts to the floor.", \ - "You hear a ratchet") - src.anchored = 1 + "You hear a ratchet.") + anchored = TRUE if(1) state = 0 - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) user.visible_message("[user.name] unsecures [src] reinforcing bolts from the floor.", \ "You undo the external reinforcing bolts.", \ - "You hear a ratchet") - src.anchored = 0 + "You hear a ratchet.") + anchored = FALSE if(2) to_chat(user, "\The [src] needs to be unwelded from the floor.") - return + return TRUE - if(isWelder(W)) - var/obj/item/weldingtool/WT = W + if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item if(active) to_chat(user, "Turn off [src] first.") - return + return TRUE switch(state) if(0) to_chat(user, "\The [src] needs to be wrenched to the floor.") if(1) - if (WT.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - user.visible_message("[user.name] starts to weld [src] to the floor.", \ - "You start to weld [src] to the floor.", \ - "You hear welding") - if (do_after(user,20,src)) - if(!src || !WT.isOn()) return - state = 2 - to_chat(user, "You weld [src] to the floor.") - connect_to_network() - else + if (!welder.weld(0,user)) to_chat(user, "You need more welding fuel to complete this task.") + return TRUE + playsound(loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to weld [src] to the floor.", \ + "You start to weld [src] to the floor.", \ + "You hear welding.") + if (!do_after(user, 2 SECONDS, src)) + return TRUE + if(!src || !welder.isOn()) return TRUE + state = 2 + to_chat(user, "You weld [src] to the floor.") if(2) - if (WT.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + if (welder.weld(0,user)) + playsound(loc, 'sound/items/Welder2.ogg', 50, 1) user.visible_message("[user.name] starts to cut [src] free from the floor.", \ "You start to cut [src] free from the floor.", \ - "You hear welding") - if (do_after(user,20,src)) - if(!src || !WT.isOn()) return - state = 1 - to_chat(user, "You cut [src] free from the floor.") - disconnect_from_network() + "You hear welding.") + if (!do_after(user, 2 SECONDS, src)) + return TRUE + if(!src || !welder.isOn()) return TRUE + state = 1 + to_chat(user, "You cut [src] free from the floor.") else to_chat(user, "You need more welding fuel to complete this task.") - return + return TRUE - if(istype(W, /obj/item/card/id) || istype(W, /obj/item/modular_computer)) + if(istype(used_item, /obj/item/card/id) || istype(used_item, /obj/item/modular_computer)) if(emagged) to_chat(user, "The lock seems to be broken.") - return - if(src.allowed(user)) - src.locked = !src.locked - to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]") + return TRUE + if(allowed(user)) + locked = !locked + to_chat(user, "The controls are now [locked ? "locked." : "unlocked."]") else to_chat(user, "Access denied.") - return - ..() - return + return TRUE + return ..() -/obj/machinery/power/emitter/emag_act(var/remaining_charges, var/mob/user) +/obj/machinery/emitter/emag_act(var/remaining_charges, var/mob/user) if(!emagged) locked = 0 emagged = 1 @@ -229,41 +214,46 @@ user.visible_message("[user.name] emags [src].","You short out the lock.") return 1 -/obj/machinery/power/emitter/proc/get_initial_fire_delay() +/obj/machinery/emitter/components_are_accessible(var/path) + if(ispath(path, /obj/item/stock_parts/power/terminal)) + return TRUE + return ..() + +/obj/machinery/emitter/proc/get_initial_fire_delay() return 100 -/obj/machinery/power/emitter/proc/get_rand_burst_delay() +/obj/machinery/emitter/proc/get_rand_burst_delay() return rand(min_burst_delay, max_burst_delay) -/obj/machinery/power/emitter/proc/get_burst_delay() +/obj/machinery/emitter/proc/get_burst_delay() return 2 -/obj/machinery/power/emitter/proc/get_emitter_beam() +/obj/machinery/emitter/proc/get_emitter_beam() return new /obj/item/projectile/beam/emitter(get_turf(src)) /decl/public_access/public_method/toggle_emitter name = "toggle emitter" desc = "Toggles whether or not the emitter is active. It must be unlocked to work." - call_proc = /obj/machinery/power/emitter/proc/activate + call_proc = TYPE_PROC_REF(/obj/machinery/emitter, activate) /decl/public_access/public_variable/emitter_active - expected_type = /obj/machinery/power/emitter + expected_type = /obj/machinery/emitter name = "emitter active" desc = "Whether or not the emitter is firing." can_write = FALSE has_updates = FALSE -/decl/public_access/public_variable/emitter_active/access_var(obj/machinery/power/emitter/emitter) +/decl/public_access/public_variable/emitter_active/access_var(obj/machinery/emitter/emitter) return emitter.active /decl/public_access/public_variable/emitter_locked - expected_type = /obj/machinery/power/emitter + expected_type = /obj/machinery/emitter name = "emitter locked" desc = "Whether or not the emitter is locked. Being locked prevents one from changing the active state." can_write = FALSE has_updates = FALSE -/decl/public_access/public_variable/emitter_locked/access_var(obj/machinery/power/emitter/emitter) +/decl/public_access/public_variable/emitter_locked/access_var(obj/machinery/emitter/emitter) return emitter.locked /decl/stock_part_preset/radio/receiver/emitter diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index b994ea18d2a9..ae6c9ec7eda3 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -18,8 +18,8 @@ field_generator power level display desc = "A large thermal battery that projects a high amount of energy when powered." icon = 'icons/obj/machines/field_generator.dmi' icon_state = "Field_Gen" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE use_power = POWER_USE_OFF var/const/num_power_levels = 6 // Total number of power level icon has var/Varedit_start = 0 @@ -28,7 +28,7 @@ field_generator power level display var/power = 30000 // Current amount of power var/state = 0 var/warming_up = 0 - var/list/obj/machinery/containment_field/fields + var/list/obj/effect/containment_field/fields var/list/obj/machinery/field_generator/connected_gens var/clean_up = 0 @@ -48,7 +48,7 @@ field_generator power level display // Scale % power to % num_power_levels and truncate value var/level = round(num_power_levels * power / field_generator_max_power) // Clamp between 0 and num_power_levels for out of range power values - level = between(0, level, num_power_levels) + level = clamp(level, 0, num_power_levels) if(level) overlays += "+p[level]" @@ -66,7 +66,7 @@ field_generator power level display active = 1 state = 2 power = field_generator_max_power - anchored = 1 + anchored = TRUE warming_up = 3 start_fields() update_icon() @@ -81,77 +81,80 @@ field_generator power level display if(state == 2) if(get_dist(src, user) <= 1)//Need to actually touch the thing to turn it on if(src.active >= 1) - to_chat(user, "You are unable to turn off the [src.name] once it is online.") + to_chat(user, "You are unable to turn off \the [src] once it is online.") return TRUE else - user.visible_message("[user.name] turns on the [src.name]", \ - "You turn on the [src.name].", \ - "You hear heavy droning") + user.visible_message("[user.name] turns on \the [src]", \ + "You turn on \the [src].", \ + "You hear heavy droning.") turn_on() investigate_log("activated by [user.key].","singulo") src.add_fingerprint(user) return TRUE + return FALSE else - to_chat(user, "The [src] needs to be firmly secured to the floor first.") + to_chat(user, "\The [src] needs to be firmly secured to the floor first.") return TRUE -/obj/machinery/field_generator/attackby(obj/item/W, mob/user) +/obj/machinery/field_generator/attackby(obj/item/used_item, mob/user) if(active) - to_chat(user, "The [src] needs to be off.") - return - else if(isWrench(W)) + to_chat(user, "\The [src] needs to be off.") + return TRUE + else if(IS_WRENCH(used_item)) switch(state) if(0) state = 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) user.visible_message("[user.name] secures [src.name] to the floor.", \ "You secure the external reinforcing bolts to the floor.", \ - "You hear ratchet") - src.anchored = 1 + "You hear ratchet.") + src.anchored = TRUE + return TRUE if(1) state = 0 playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) user.visible_message("[user.name] unsecures [src.name] reinforcing bolts from the floor.", \ "You undo the external reinforcing bolts.", \ - "You hear ratchet") - src.anchored = 0 + "You hear ratchet.") + src.anchored = FALSE + return TRUE if(2) - to_chat(user, " The [src.name] needs to be unwelded from the floor.") - return - else if(isWelder(W)) - var/obj/item/weldingtool/WT = W + to_chat(user, " \The [src] needs to be unwelded from the floor.") + return TRUE + else if(IS_WELDER(used_item)) + var/obj/item/weldingtool/welder = used_item switch(state) if(0) - to_chat(user, "The [src.name] needs to be wrenched to the floor.") - return + to_chat(user, "\The [src] needs to be wrenched to the floor.") + return TRUE if(1) - if (WT.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \ - "You start to weld the [src] to the floor.", \ - "You hear welding") - if (do_after(user,20,src)) - if(!src || !WT.isOn()) return - state = 2 - to_chat(user, "You weld the field generator to the floor.") - else - return + if (!welder.weld(0,user)) + return TRUE + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to weld \the [src] to the floor.", \ + "You start to weld \the [src] to the floor.", \ + "You hear welding.") + if (!do_after(user, 2 SECONDS, src)) + return TRUE + if(!src || !welder.isOn()) return TRUE + state = 2 + to_chat(user, "You weld the field generator to the floor.") + return TRUE if(2) - if (WT.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \ - "You start to cut the [src] free from the floor.", \ - "You hear welding") - if (do_after(user,20,src)) - if(!src || !WT.isOn()) return - state = 1 - to_chat(user, "You cut the [src] free from the floor.") - else - return - else - ..() - return + if (!welder.weld(0,user)) + return TRUE + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + user.visible_message("[user.name] starts to cut \the [src] free from the floor.", \ + "You start to cut \the [src] free from the floor.", \ + "You hear welding.") + if (!do_after(user, 2 SECONDS, src)) + return TRUE + if(!src || !welder.isOn()) return TRUE + state = 1 + to_chat(user, "You cut \the [src] free from the floor.") + return TRUE + return ..() /obj/machinery/field_generator/emp_act() @@ -201,15 +204,14 @@ field_generator power level display for(var/obj/machinery/field_generator/FG in connected_gens) if (!isnull(FG)) power_draw += gen_power_draw - for (var/obj/machinery/containment_field/F in fields) + for (var/obj/effect/containment_field/F in fields) if (!isnull(F)) power_draw += field_power_draw power_draw /= 2 //because this will be mirrored for both generators if(draw_power(round(power_draw)) >= power_draw) return 1 else - for(var/mob/M in viewers(src)) - M.show_message("\The [src] shuts down!") + visible_message(SPAN_WARNING("\The [src] shuts down!")) turn_off() investigate_log("ran out of power and deactivated","singulo") src.power = 0 @@ -265,7 +267,7 @@ field_generator power level display if(ismob(A)) continue if(!istype(A,/obj/machinery/field_generator)) - if((istype(A,/obj/machinery/door)||istype(A,/obj/machinery/the_singularitygen))&&(A.density)) + if((istype(A,/obj/machinery/door)||istype(A,/obj/machinery/singularity_generator))&&(A.density)) return 0 steps += 1 G = locate(/obj/machinery/field_generator) in T @@ -280,8 +282,8 @@ field_generator power level display for(var/dist = 0, dist < steps, dist += 1) // creates each field tile var/field_dir = get_dir(T,get_step(G.loc, NSEW)) T = get_step(T, NSEW) - if(!locate(/obj/machinery/containment_field) in T) - var/obj/machinery/containment_field/CF = new/obj/machinery/containment_field() + if(!locate(/obj/effect/containment_field) in T) + var/obj/effect/containment_field/CF = new/obj/effect/containment_field() CF.set_master(src,G) fields += CF G.fields += CF @@ -309,7 +311,7 @@ field_generator power level display /obj/machinery/field_generator/proc/cleanup() clean_up = 1 - for (var/obj/machinery/containment_field/F in fields) + for (var/obj/effect/containment_field/F in fields) if (QDELETED(F)) continue qdel(F) @@ -330,7 +332,7 @@ field_generator power level display //I want to avoid using global variables. spawn(1) var/temp = 1 //stops spam - for(var/obj/singularity/O in SSmachines.machinery) + for(var/obj/effect/singularity/O in SSmachines.machinery) if(O.last_warning && temp) if((world.time - O.last_warning) > 50) //to stop message-spam temp = 0 diff --git a/code/modules/power/singularity/generator.dm b/code/modules/power/singularity/generator.dm index b8be0168b220..82a33b48a77e 100644 --- a/code/modules/power/singularity/generator.dm +++ b/code/modules/power/singularity/generator.dm @@ -1,17 +1,25 @@ /////SINGULARITY SPAWNER -/obj/machinery/the_singularitygen/ - name = "Gravitational Singularity Generator" - desc = "An Odd Device which produces a Gravitational Singularity when set up." +/obj/machinery/singularity_generator + name = "gravitational singularity generator" + desc = "An odd device which produces a gravitational singularity when set up." icon = 'icons/obj/singularity.dmi' icon_state = "TheSingGen" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE use_power = POWER_USE_OFF + matter = list( + /decl/material/solid/exotic_matter = MATTER_AMOUNT_PRIMARY, + /decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY + ) + var/energy = 0 - var/creation_type = /obj/singularity + var/creation_type = /obj/effect/singularity var/is_activated = FALSE -/obj/machinery/the_singularitygen/Process() +/obj/machinery/singularity_generator/get_matter_amount_modifier() + . = ..() * (1/HOLLOW_OBJECT_MATTER_MULTIPLIER) * 10 // Big solid chunk of matter. + +/obj/machinery/singularity_generator/Process() var/turf/T = get_turf(src) if(energy >= 200 && !is_activated) is_activated = TRUE @@ -21,25 +29,27 @@ animation.pixel_y = -32 animation.layer = SINGULARITY_EFFECT_LAYER flick('icons/effects/singularity_effect.dmi', animation) - addtimer(CALLBACK(src, .proc/spawn_contained, T), 6 SECOND) + addtimer(CALLBACK(src, PROC_REF(spawn_contained), T), 6 SECOND) QDEL_IN(animation, 7 SECOND) + return PROCESS_KILL -/obj/machinery/the_singularitygen/proc/spawn_contained(turf/T) - new creation_type(T || get_turf(src), 50) +/obj/machinery/singularity_generator/proc/spawn_contained(turf/T) + if(creation_type) + new creation_type(T || get_turf(src), 50) if(!QDELETED(src)) qdel(src) -/obj/machinery/the_singularitygen/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/wrench)) - anchored = !anchored - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - if(anchored) - user.visible_message("[user.name] secures [src.name] to the floor.", \ - "You secure the [src.name] to the floor.", \ - "You hear a ratchet") - else - user.visible_message("[user.name] unsecures [src.name] from the floor.", \ - "You unsecure the [src.name] from the floor.", \ - "You hear a ratchet") - return - return ..() +/obj/machinery/singularity_generator/attackby(obj/item/used_item, mob/user) + if(!IS_WRENCH(used_item)) + return ..() + anchored = !anchored + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + if(anchored) + user.visible_message("[user.name] secures \the [src] to the floor.", \ + "You secure \the [src] to the floor.", \ + "You hear a ratchet.") + else + user.visible_message("[user.name] unsecures \the [src] from the floor.", \ + "You unsecure \the [src] from the floor.", \ + "You hear a ratchet.") + return TRUE \ No newline at end of file diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm index e6105b7b2dd6..dc88c1bb9c83 100644 --- a/code/modules/power/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/singularity/particle_accelerator/particle.dm @@ -5,8 +5,8 @@ desc = "Small things moving very fast." icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "particle"//Need a new icon for this - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/movement_range = 10 var/energy = 10 //energy in eV var/mega_energy = 0 //energy in MeV @@ -35,10 +35,10 @@ if (A) if(ismob(A)) toxmob(A) - if((istype(A,/obj/machinery/the_singularitygen))||(istype(A,/obj/singularity/))) + if((istype(A,/obj/machinery/singularity_generator))||(istype(A,/obj/effect/singularity/))) A:energy += energy - else if(istype(A,/obj/machinery/power/fusion_core)) - var/obj/machinery/power/fusion_core/collided_core = A + else if(istype(A,/obj/machinery/fusion_core)) + var/obj/machinery/fusion_core/collided_core = A if(particle_type && particle_type != "neutron") if(collided_core.AddParticles(particle_type, 1 + additional_particles)) collided_core.owned_field.plasma_temperature += mega_energy @@ -63,7 +63,6 @@ /obj/effect/accelerated_particle/proc/toxmob(var/mob/living/M) var/radiation = (energy*2) M.apply_damage((radiation*3),IRRADIATE, damage_flags = DAM_DISPERSED) - M.updatehealth() /obj/effect/accelerated_particle/proc/move(var/lag) set waitfor = FALSE diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm index 01a8d64d68ed..aab6c0dc67a3 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm @@ -63,8 +63,8 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin desc = "Part of a Particle Accelerator." icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "none" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE obj_flags = OBJ_FLAG_ROTATABLE var/obj/machinery/particle_accelerator/control_box/master = null @@ -86,36 +86,29 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin icon_state = "end_cap" reference = "end_cap" -/obj/structure/particle_accelerator/on_update_icon() - ..() - return - -/obj/structure/particle_accelerator/examine(mob/user) +/obj/structure/particle_accelerator/get_examine_strings(mob/user, distance, infix, suffix) . = ..() switch(construction_state) if(0) - to_chat(user, "Looks like it's not attached to the flooring") + . += "Looks like it's not attached to the flooring." if(1) - to_chat(user, "It is missing some cables") + . += "It is missing some cables." if(2) - to_chat(user, "The panel is open") + . += "The panel is open." if(3) if(powered) - to_chat(user, desc_holder) + . += desc_holder else - to_chat(user, "\The [src] is assembled") - - -/obj/structure/particle_accelerator/attackby(obj/item/W, mob/user) - if(istool(W)) - if(src.process_tool_hit(W,user)) - return - ..() - return + . += "\The [src] is assembled." +/obj/structure/particle_accelerator/attackby(obj/item/used_item, mob/user) + if(has_extension(used_item, /datum/extension/tool)) + if(process_tool_hit(used_item,user)) + return TRUE + return ..() /obj/structure/particle_accelerator/Move() - ..() + . = ..() if(master && master.active) master.toggle_power() investigate_log("was moved whilst active; it powered down.","singulo") @@ -126,6 +119,7 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin physically_destroyed() /obj/structure/particle_accelerator/on_update_icon() + ..() switch(construction_state) if(0,1) icon_state="[reference]" @@ -136,7 +130,6 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin icon_state="[reference]p[strength]" else icon_state="[reference]c" - return /obj/structure/particle_accelerator/proc/update_state() if(master) @@ -165,45 +158,43 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin return 0 -/obj/structure/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user) - if(!(O) || !(user)) - return 0 - if(!ismob(user) || !isobj(O)) - return 0 - var/temp_state = src.construction_state +/obj/structure/particle_accelerator/proc/process_tool_hit(var/obj/item/O, var/mob/user) + if(!istype(O) || !ismob(user)) + return FALSE + var/temp_state = src.construction_state switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps if(0) - if(isWrench(O)) + if(IS_WRENCH(O)) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 1 - user.visible_message("[user.name] secures the [src.name] to the floor.", \ + src.anchored = TRUE + user.visible_message("[user.name] secures \the [src] to the floor.", \ "You secure the external bolts.") temp_state++ if(1) - if(isWrench(O)) + if(IS_WRENCH(O)) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 0 - user.visible_message("[user.name] detaches the [src.name] from the floor.", \ + src.anchored = FALSE + user.visible_message("[user.name] detaches \the [src] from the floor.", \ "You remove the external bolts.") temp_state-- - else if(isCoil(O)) + else if(IS_COIL(O)) if(O:use(1,user)) - user.visible_message("[user.name] adds wires to the [src.name].", \ + user.visible_message("[user.name] adds wires to \the [src].", \ "You add some wires.") temp_state++ if(2) - if(isWirecutter(O))//TODO:Shock user if its on? - user.visible_message("[user.name] removes some wires from the [src.name].", \ + if(IS_WIRECUTTER(O))//TODO:Shock user if it's on? + user.visible_message("[user.name] removes some wires from \the [src].", \ "You remove some wires.") temp_state-- - else if(isScrewdriver(O)) - user.visible_message("[user.name] closes the [src.name]'s access panel.", \ + else if(IS_SCREWDRIVER(O)) + user.visible_message("[user.name] closes \the [src]'s access panel.", \ "You close the access panel.") temp_state++ if(3) - if(isScrewdriver(O)) - user.visible_message("[user.name] opens the [src.name]'s access panel.", \ + if(IS_SCREWDRIVER(O)) + user.visible_message("[user.name] opens \the [src]'s access panel.", \ "You open the access panel.") temp_state-- if(temp_state == src.construction_state)//Nothing changed @@ -220,8 +211,8 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin desc = "Part of a Particle Accelerator." icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "none" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE use_power = POWER_USE_OFF idle_power_usage = 0 active_power_usage = 0 @@ -235,28 +226,26 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin /obj/machinery/particle_accelerator/on_update_icon() return -/obj/machinery/particle_accelerator/examine(mob/user) +/obj/machinery/particle_accelerator/get_examine_strings(mob/user, distance, infix, suffix) . = ..() switch(construction_state) if(0) - to_chat(user, "Looks like it's not attached to the flooring") + . += "Looks like it's not attached to the flooring." if(1) - to_chat(user, "It is missing some cables") + . += "It is missing some cables." if(2) - to_chat(user, "The panel is open") + . += "The panel is open." if(3) if(powered) - to_chat(user, desc_holder) + . += desc_holder else - to_chat(user, "\The [src] is assembled") + . += "\The [src] is assembled." - -/obj/machinery/particle_accelerator/attackby(obj/item/W, mob/user) - if(istool(W)) - if(src.process_tool_hit(W,user)) - return - ..() - return +/obj/machinery/particle_accelerator/attackby(obj/item/used_item, mob/user) + if(has_extension(used_item, /datum/extension/tool)) + if(process_tool_hit(used_item,user)) + return TRUE + return ..() /obj/machinery/particle_accelerator/explosion_act(severity) . = ..() @@ -266,44 +255,42 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin /obj/machinery/particle_accelerator/proc/update_state() return 0 -/obj/machinery/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user) - if(!(O) || !(user)) - return 0 - if(!ismob(user) || !isobj(O)) - return 0 +/obj/machinery/particle_accelerator/proc/process_tool_hit(var/obj/item/O, var/mob/user) + if(!istype(O) || !ismob(user)) + return FALSE var/temp_state = src.construction_state switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps if(0) - if(isWrench(O)) + if(IS_WRENCH(O)) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 1 - user.visible_message("[user.name] secures the [src.name] to the floor.", \ + src.anchored = TRUE + user.visible_message("[user.name] secures \the [src] to the floor.", \ "You secure the external bolts.") temp_state++ if(1) - if(isWrench(O)) + if(IS_WRENCH(O)) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - src.anchored = 0 - user.visible_message("[user.name] detaches the [src.name] from the floor.", \ + src.anchored = FALSE + user.visible_message("[user.name] detaches \the [src] from the floor.", \ "You remove the external bolts.") temp_state-- - else if(isCoil(O)) + else if(IS_COIL(O)) if(O:use(1)) - user.visible_message("[user.name] adds wires to the [src.name].", \ + user.visible_message("[user.name] adds wires to \the [src].", \ "You add some wires.") temp_state++ if(2) - if(isWirecutter(O))//TODO:Shock user if its on? - user.visible_message("[user.name] removes some wires from the [src.name].", \ + if(IS_WIRECUTTER(O))//TODO:Shock user if it's on? + user.visible_message("[user.name] removes some wires from \the [src].", \ "You remove some wires.") temp_state-- - else if(isScrewdriver(O)) - user.visible_message("[user.name] closes the [src.name]'s access panel.", \ + else if(IS_SCREWDRIVER(O)) + user.visible_message("[user.name] closes \the [src]'s access panel.", \ "You close the access panel.") temp_state++ if(3) - if(isScrewdriver(O)) - user.visible_message("[user.name] opens the [src.name]'s access panel.", \ + if(IS_SCREWDRIVER(O)) + user.visible_message("[user.name] opens \the [src]'s access panel.", \ "You open the access panel.") temp_state-- active = 0 diff --git a/code/modules/power/singularity/particle_accelerator/particle_chamber.dm b/code/modules/power/singularity/particle_accelerator/particle_chamber.dm index 7a9400f5acc5..4d666e12c389 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_chamber.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_chamber.dm @@ -4,7 +4,3 @@ icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "fuel_chamber" reference = "fuel_chamber" - -/obj/structure/particle_accelerator/fuel_chamber/on_update_icon() - ..() - return \ No newline at end of file diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index f0415a9251ad..c267422e0893 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -6,8 +6,8 @@ icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "control_box" reference = "control_box" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE idle_power_usage = 500 active_power_usage = 70000 //70 kW per unit of strength construction_state = 0 @@ -17,7 +17,6 @@ var/interface_control = 1 var/list/obj/structure/particle_accelerator/connected_parts var/assembled = 0 - var/parts = null wires = /datum/wires/particle_acc/control_box /obj/machinery/particle_accelerator/control_box/Initialize() @@ -75,35 +74,35 @@ return /obj/machinery/particle_accelerator/control_box/Topic(href, href_list) - ..() - //Ignore input if we are broken, !silicon guy cant touch us, or nonai controlling from super far away - if(stat & (BROKEN|NOPOWER) || (get_dist(src, usr) > 1 && !istype(usr, /mob/living/silicon)) || (get_dist(src, usr) > 8 && !istype(usr, /mob/living/silicon/ai))) - usr.unset_machine() + . = ..() + if(. == TOPIC_CLOSE) close_browser(usr, "window=pacontrol") - return - if( href_list["close"] ) - close_browser(usr, "window=pacontrol") - usr.unset_machine() +/obj/machinery/particle_accelerator/control_box/OnTopic(href, href_list) + if((. = ..())) return - + if(inoperable()) + return TOPIC_CLOSE + if(href_list["close"]) + return TOPIC_CLOSE if(href_list["togglep"]) - if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE)) - src.toggle_power() + if(wires.IsIndexCut(PARTICLE_TOGGLE_WIRE)) + return TOPIC_HANDLED + toggle_power() + return TOPIC_REFRESH else if(href_list["scan"]) - src.part_scan() - + part_scan() + return TOPIC_REFRESH else if(href_list["strengthup"]) - if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) - add_strength() - + if(wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) + return TOPIC_HANDLED + add_strength() + return TOPIC_REFRESH else if(href_list["strengthdown"]) - if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) - remove_strength() - - src.updateDialog() - src.update_icon() - return + if(wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) + return TOPIC_HANDLED + remove_strength() + return TOPIC_REFRESH /obj/machinery/particle_accelerator/control_box/proc/strength_change() for(var/obj/structure/particle_accelerator/part in connected_parts) @@ -116,7 +115,7 @@ if(strength > strength_upper_limit) strength = strength_upper_limit else - message_admins("PA Control Computer increased to [strength] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) + message_admins("PA Control Computer increased to [strength] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("PA Control Computer increased to [strength] by [usr.ckey]([usr]) in ([x],[y],[z])") investigate_log("increased to [strength] by [usr.key]","singulo") strength_change() @@ -127,7 +126,7 @@ if(strength < 0) strength = 0 else - message_admins("PA Control Computer decreased to [strength] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) + message_admins("PA Control Computer decreased to [strength] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("PA Control Computer decreased to [strength] by [usr.ckey]([usr]) in ([x],[y],[z])") investigate_log("decreased to [strength] by [usr.key]","singulo") strength_change() @@ -206,7 +205,7 @@ /obj/machinery/particle_accelerator/control_box/toggle_power() src.active = !src.active investigate_log("turned [active?"ON":"OFF"] by [usr ? usr.key : "outside forces"]","singulo") - message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) + message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("PA Control Computer turned [active ?"ON":"OFF"] by [usr.ckey]([usr]) in ([x],[y],[z])") if(src.active) update_use_power(POWER_USE_ACTIVE) @@ -225,7 +224,7 @@ /obj/machinery/particle_accelerator/control_box/interact(mob/user) if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER))) - if(!istype(user, /mob/living/silicon)) + if(!issilicon(user)) user.unset_machine() close_browser(user, "window=pacontrol") return @@ -233,11 +232,11 @@ var/dat = "" dat += "Particle Accelerator Control Panel
    " - dat += "Close

    " + dat += "Close

    " dat += "Status:
    " if(!assembled) dat += "Unable to detect all parts!
    " - dat += "Run Scan

    " + dat += "Run Scan

    " else dat += "All parts in place.

    " dat += "Power:" @@ -245,9 +244,9 @@ dat += "On
    " else dat += "Off
    " - dat += "Toggle Power

    " + dat += "Toggle Power

    " dat += "Particle Strength: [src.strength] " - dat += "--|++

    " + dat += "--|++

    " show_browser(user, dat, "window=pacontrol;size=420x500") onclose(user, "pacontrol") diff --git a/code/modules/power/singularity/particle_accelerator/particle_emitter.dm b/code/modules/power/singularity/particle_accelerator/particle_emitter.dm index eba322bb19fb..7cfffcf5a8f1 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_emitter.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_emitter.dm @@ -20,13 +20,6 @@ icon_state = "emitter_right" reference = "emitter_right" -/obj/structure/particle_accelerator/particle_emitter/proc/set_delay(var/delay) - if(delay && delay >= 0) - src.fire_delay = delay - return 1 - return 0 - - /obj/structure/particle_accelerator/particle_emitter/proc/emit_particle(var/strength = 0) if((src.last_shot + src.fire_delay) <= world.time) src.last_shot = world.time diff --git a/code/modules/power/singularity/particle_accelerator/particle_power.dm b/code/modules/power/singularity/particle_accelerator/particle_power.dm index a7d5c5da9690..07de6e3b6026 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_power.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_power.dm @@ -4,7 +4,3 @@ icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "power_box" reference = "power_box" - -/obj/structure/particle_accelerator/power_box/on_update_icon() - ..() - return diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 30a26249cb5d..97a0d08fa836 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -1,345 +1,210 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 - -/obj/singularity/ +var/global/list/singularities = list() +/obj/effect/singularity name = "gravitational singularity" desc = "A gravitational singularity." icon = 'icons/obj/singularity.dmi' icon_state = "singularity_s1" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE layer = SINGULARITY_LAYER - light_outer_range = 6 - unacidable = 1 //Don't comment this out. - - var/current_size = 1 - var/allowed_size = 1 - var/contained = 1 //Are we going to move around? - var/energy = 100 //How strong are we? - var/dissipate = 1 //Do we lose energy over time? - var/dissipate_delay = 10 - var/dissipate_track = 0 - var/dissipate_strength = 1 //How much energy do we lose? - var/move_self = 1 //Do we move on our own? - var/grav_pull = 4 //How many tiles out do we pull? - var/consume_range = 0 //How many tiles out do we eat. - var/event_chance = 15 //Prob for event each tick. - var/target = null //Its target. Moves towards the target if it has one. - var/last_failed_movement = 0 //Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing. + light_power = 1 + light_range = 6 + is_spawnable_type = FALSE // No... + + /// Category used for investigation entries relating to this atom. + var/const/investigation_label = "singulo" + /// A weighted list of events. + var/static/list/singularity_events = list( + /decl/singularity_event/empulse = 1, + /decl/singularity_event/toxins = 2, + /decl/singularity_event/mesmerize = 1, + /decl/singularity_event/nothing = 1 + ) + + /// When did we last emit a warning about a containment failure? var/last_warning - - var/chained = 0//Adminbus chain-grab - -/obj/singularity/Initialize(mapload, var/starting_energy = 50, var/temp = 0) + /// What are our current values, icons, strings, etc? + var/decl/singularity_stage/current_stage + /// How strong/large are we? How much have we eaten? + var/energy = 100 + /// Will we wander, if our stage permits it? Only set by var edit or mapped subtype. + var/move_self = TRUE + /// Our current target. Moves towards the target if it has one. + var/weakref/target + /// Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing. + var/last_failed_movement = 0 + /// How many atoms can we pull in a single tick? + var/const/max_atoms_assessed_per_tick = 100 + +/obj/effect/singularity/Initialize(mapload, var/starting_energy = 50, var/temp = 0) . = ..(mapload) - - //CARN: admin-alert for chuckle-fuckery. - admin_investigate_setup() + var/found_containment = locate(/obj/effect/containment_field) in orange(30, src) + if(!found_containment) + last_warning = world.time + message_admins("A singulo has been created without containment fields active ([x], [y], [z] - JMP).") + investigate_log("was created. [found_containment ? "" : "No containment fields were active."]", investigation_label) + current_stage = GET_DECL(/decl/singularity_stage/stage_one) energy = starting_energy - + global.singularities += src if (temp) QDEL_IN(src, temp) START_PROCESSING(SSobj, src) - for(var/obj/machinery/power/singularity_beacon/singubeacon in SSmachines.machinery) - if(singubeacon.active) - target = singubeacon - break -/obj/singularity/Destroy() +/obj/effect/singularity/Destroy() + global.singularities -= src STOP_PROCESSING(SSobj, src) . = ..() -/obj/singularity/attack_hand(mob/user) - consume(user) - return 1 +/obj/effect/singularity/is_space_movement_permitted(allow_movement = FALSE) + return SPACE_MOVE_PERMITTED -/obj/singularity/explosion_act(severity) +/obj/effect/singularity/proc/consume(atom/A) + energy += A.singularity_act(src, current_stage.stage_size) + +/obj/effect/singularity/explosion_act(severity) SHOULD_CALL_PARENT(FALSE) - if(current_size == STAGE_SUPER)//IT'S UNSTOPPABLE + if(!current_stage.explosion_vulnerable)//IT'S UNSTOPPABLE return - switch(severity) - if(1.0) - if(prob(25)) - investigate_log("has been destroyed by an explosion.", I_SINGULO) - qdel(src) - return - else - energy += 50 - if(2.0 to 3.0) - energy += round((rand(20,60)/2),1) - return - -/obj/singularity/bullet_act(obj/item/projectile/P) - return 0 //Will there be an impact? Who knows. Will we see it? No. - -/obj/singularity/Bump(atom/A) - consume(A) - -/obj/singularity/Bumped(atom/A) - consume(A) - -/obj/singularity/Process() - eat() - dissipate() - check_energy() - - if (current_size >= STAGE_TWO) - move() - pulse() - - if (prob(event_chance)) //Chance for it to run a special event TODO: Come up with one or two more that fit. - event() - -/obj/singularity/attack_ai() //To prevent ais from gibbing themselves when they click on one. - return + if(severity == 1) + if(prob(25)) + investigate_log("has been destroyed by an explosion.", investigation_label) + qdel(src) + else + energy += 50 + else + energy += round((rand(20,60)/2), 1) -/obj/singularity/proc/admin_investigate_setup() - last_warning = world.time - var/count = locate(/obj/machinery/containment_field) in orange(30, src) +/obj/effect/singularity/bullet_act(obj/item/projectile/P) + return FALSE - if (!count) - message_admins("A singulo has been created without containment fields active ([x], [y], [z] - JMP).") +/obj/effect/singularity/Process() - investigate_log("was created. [count ? "" : "No containment fields were active."]", I_SINGULO) + // Eat or pull anything close to us. + var/consumed = 0 + for(var/atom/consuming in range(current_stage.grav_pull, src)) + if(consuming == src) + continue + var/dist = get_dist(consuming, src) + if(dist <= current_stage.consume_range) + consume(consuming) + else + consuming.singularity_pull(src, current_stage.stage_size) + if(consumed++ >= max_atoms_assessed_per_tick || TICK_CHECK) + break -/obj/singularity/proc/dissipate() - if (!dissipate) + if(TICK_CHECK) return - if(dissipate_track >= dissipate_delay) - energy -= dissipate_strength - dissipate_track = 0 - else - dissipate_track++ + // Check if we should be shrinking this tick, and apply it if we should. + current_stage.handle_dissipation(src) + + // Check if we're large and energetic enough to move. + if(!check_energy() || !current_stage.wander) + return // Just hangs out for now. + + // Refresh our beacon target, if needed. + var/obj/machinery/singularity_beacon/target_beacon + if(length(global.singularity_beacons)) + if(target) + target_beacon = target.resolve() + if(!istype(target_beacon) || target_beacon.use_power != POWER_USE_ACTIVE) + target_beacon = null + target = null + if(!target) + for(var/obj/machinery/singularity_beacon/singubeacon as anything in global.singularity_beacons) + if(singubeacon.use_power == POWER_USE_ACTIVE) + target_beacon = singubeacon + target = weakref(singubeacon) + break + + // Move randomly towards our target, or in a random direction. + if(move_self) + + // Get a direction to move. + var/movement_dir + if(target_beacon && prob(60)) + //moves to a singulo beacon, if there is one + if(target_beacon.z == z) + movement_dir = get_dir(src, target_beacon) + else if(target_beacon.z > z && GetAbove(src)) + movement_dir = UP + else if(target_beacon.z < z && GetBelow(src)) + movement_dir = DOWN + + else if(prob(16) && !(locate(/obj/effect/containment_field) in orange(7, src))) + var/list/available_vertical_moves = list() + if(GetAbove(src)) + available_vertical_moves += UP + if(GetBelow(src)) + available_vertical_moves += DOWN + if(length(available_vertical_moves)) + movement_dir = pick(available_vertical_moves) + if(!movement_dir || movement_dir == last_failed_movement) + movement_dir = pick(global.alldirs - last_failed_movement) + + // Try to move in it. + if(!try_move(movement_dir, (movement_dir == UP || movement_dir == DOWN))) + last_failed_movement = movement_dir + + // Feed any nearby rad collectors. + for(var/obj/machinery/rad_collector/R in global.rad_collectors) + if (get_dist(R, src) <= 15) //Better than using orange() every process. + R.receive_pulse(energy) -/obj/singularity/proc/expand(var/force_size = 0, var/growing = 1) - if(current_size == STAGE_SUPER)//if this is happening, this is an error - message_admins("expand() was called on a super singulo. This should not happen. Contact a coder immediately!") - return - var/temp_allowed_size = allowed_size - - if (force_size) - temp_allowed_size = force_size - - switch (temp_allowed_size) - if (STAGE_ONE) - SetName("gravitational singularity") - desc = "A gravitational singularity." - current_size = STAGE_ONE - icon = 'icons/obj/singularity.dmi' - icon_state = "singularity_s1" - pixel_x = 0 - pixel_y = 0 - grav_pull = 4 - consume_range = 0 - dissipate_delay = 10 - dissipate_track = 0 - dissipate_strength = 1 - overlays.Cut() - if(chained) - overlays = list("chain_s1") - visible_message("The singularity has shrunk to a rather pitiful size.") - if (STAGE_TWO) //1 to 3 does not check for the turfs if you put the gens right next to a 1x1 then its going to eat them. - SetName("gravitational singularity") - desc = "A gravitational singularity." - current_size = STAGE_TWO - icon = 'icons/effects/96x96.dmi' - icon_state = "singularity_s3" - pixel_x = -32 - pixel_y = -32 - grav_pull = 6 - consume_range = 1 - dissipate_delay = 5 - dissipate_track = 0 - dissipate_strength = 5 - overlays.Cut() - if(chained) - overlays = list("chain_s3") - if(growing) - visible_message("The singularity noticeably grows in size.") - else - visible_message("The singularity has shrunk to a less powerful size.") - if (STAGE_THREE) - if ((check_turfs_in(1, 2)) && (check_turfs_in(2, 2)) && (check_turfs_in(4, 2)) && (check_turfs_in(8, 2))) - SetName("gravitational singularity") - desc = "A gravitational singularity." - current_size = STAGE_THREE - icon = 'icons/effects/160x160.dmi' - icon_state = "singularity_s5" - pixel_x = -64 - pixel_y = -64 - grav_pull = 8 - consume_range = 2 - dissipate_delay = 4 - dissipate_track = 0 - dissipate_strength = 20 - overlays.Cut() - if(chained) - overlays = list("chain_s5") - if(growing) - visible_message("The singularity expands to a reasonable size.") - else - visible_message("The singularity has returned to a safe size.") - if(STAGE_FOUR) - if ((check_turfs_in(1, 3)) && (check_turfs_in(2, 3)) && (check_turfs_in(4, 3)) && (check_turfs_in(8, 3))) - SetName("gravitational singularity") - desc = "A gravitational singularity." - current_size = STAGE_FOUR - icon = 'icons/effects/224x224.dmi' - icon_state = "singularity_s7" - pixel_x = -96 - pixel_y = -96 - grav_pull = 10 - consume_range = 3 - dissipate_delay = 10 - dissipate_track = 0 - dissipate_strength = 10 - overlays.Cut() - if(chained) - overlays = list("chain_s7") - if(growing) - visible_message("The singularity expands to a dangerous size.") - else - visible_message("Miraculously, the singularity reduces in size, and can be contained.") - if(STAGE_FIVE) //This one also lacks a check for gens because it eats everything. - SetName("gravitational singularity") - desc = "A gravitational singularity." - current_size = STAGE_FIVE - icon = 'icons/effects/288x288.dmi' - icon_state = "singularity_s9" - pixel_x = -128 - pixel_y = -128 - grav_pull = 10 - consume_range = 4 - dissipate = 0 //It cant go smaller due to e loss. - overlays.Cut() - if(chained) - overlays = list("chain_s9") - if(growing) - visible_message("The singularity has grown out of control!") - else - visible_message("The singularity miraculously reduces in size and loses its supermatter properties.") - if(STAGE_SUPER)//SUPERSINGULO - SetName("super gravitational singularity") - desc = "A gravitational singularity with the properties of supermatter. It has the power to destroy worlds." - current_size = STAGE_SUPER - icon = 'icons/effects/352x352.dmi' - icon_state = "singularity_s11"//uh, whoever drew that, you know that black holes are supposed to look dark right? What's this, the clown's singulo? - pixel_x = -160 - pixel_y = -160 - grav_pull = 16 - consume_range = 5 - dissipate = 0 //It cant go smaller due to e loss - event_chance = 25 //Events will fire off more often. - if(chained) - overlays = list("chain_s9") - visible_message("You witness the creation of a destructive force that cannot possibly be stopped by human hands.") - - if (current_size == allowed_size) - investigate_log("grew to size [current_size].", I_SINGULO) - return 1 - else if (current_size < (--temp_allowed_size) && current_size != STAGE_SUPER) - expand(temp_allowed_size) - else - return 0 + // Handle random events. + if(prob(current_stage.event_chance)) + var/decl/singularity_event/singularity_event = current_stage.forced_event || pickweight(singularity_events) + singularity_event = GET_DECL(singularity_event) + singularity_event.handle_event(src) + +/obj/effect/singularity/proc/try_move(var/movement_dir, var/vertical_move) + set waitfor = FALSE + if(current_stage.ignore_obstacles)//The superlarge one does not care about things in its way + step(src, movement_dir) + if(!vertical_move) + sleep(1) + if(!QDELETED(src)) + step(src, movement_dir) + else if(check_turfs_in(movement_dir)) + last_failed_movement = 0 // Reset this because we moved + step(src, movement_dir) + return TRUE + return FALSE -/obj/singularity/proc/check_energy() +/obj/effect/singularity/proc/check_energy() if (energy <= 0) - investigate_log("collapsed.", I_SINGULO) + investigate_log("collapsed.", investigation_label) qdel(src) - return 0 - - switch (energy) //Some of these numbers might need to be changed up later -Mport. - if (1 to 199) - allowed_size = STAGE_ONE - if (200 to 499) - allowed_size = STAGE_TWO - if (500 to 999) - allowed_size = STAGE_THREE - if (1000 to 1999) - allowed_size = STAGE_FOUR - if(2000 to 49999) - allowed_size = STAGE_FIVE - if(50000 to INFINITY) - allowed_size = STAGE_SUPER - - if (current_size != allowed_size && current_size != STAGE_SUPER) - expand(null, current_size < allowed_size) - return 1 + return FALSE -/obj/singularity/proc/eat() - for(var/atom/X in orange(grav_pull, src)) - var/dist = get_dist(X, src) - var/obj/singularity/S = src - if(!istype(src)) + . = TRUE + var/list/singulo_stages = decls_repository.get_decls_of_subtype(/decl/singularity_stage) + for(var/stage_type in singulo_stages) + var/decl/singularity_stage/stage = singulo_stages[stage_type] + if(stage != current_stage && energy >= stage.min_energy && energy < stage.max_energy && stage.has_expansion_room(src)) + set_stage(stage) return - if(dist > consume_range) - X.singularity_pull(S, current_size) - else if(dist <= consume_range) - consume(X) - - return - -/obj/singularity/proc/consume(const/atom/A) - src.energy += A.singularity_act(src, current_size) - return -/obj/singularity/proc/move(force_move_direction = 0) - if(!move_self) +/obj/effect/singularity/proc/set_stage(decl/singularity_stage/next_stage) + if(!next_stage || next_stage == current_stage) return FALSE - - var/movement_dir = pick(GLOB.alldirs - last_failed_movement) - - if(force_move_direction) - movement_dir = force_move_direction - - if(target && prob(60)) - movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one - else - var/location - if(prob(16)) - location = GetAbove(src) - if (location) - src.Move(location, UP) - return TRUE - else if(prob(16)) - location = GetBelow(src) - if (location) - src.Move(location, DOWN) - return TRUE - - if(current_size >= 9)//The superlarge one does not care about things in its way - spawn(0) - step(src, movement_dir) - spawn(1) - step(src, movement_dir) - return TRUE - else if(check_turfs_in(movement_dir)) - last_failed_movement = 0 // Reset this because we moved - spawn(0) - step(src, movement_dir) - return TRUE - else - last_failed_movement = movement_dir - return FALSE - -/obj/singularity/proc/check_turfs_in(var/direction = 0, var/step = 0) + if(next_stage.stage_size < current_stage.stage_size) + next_stage.shrink_to(src) + investigate_log("shrank to size [next_stage.stage_size].", investigation_label) + else if(next_stage.stage_size > current_stage.stage_size) + next_stage.grow_to(src) + investigate_log("grew to size [next_stage.stage_size].", investigation_label) + current_stage = next_stage + update_icon() + update_strings() + return TRUE + +/obj/effect/singularity/proc/check_turfs_in(var/direction = 0, var/step = 0) if(!direction) return 0 - var/steps = 0 + var/steps if(!step) - switch(current_size) - if(1) - steps = 1 - if(3) - steps = 3//Yes this is right - if(5) - steps = 3 - if(7) - steps = 4 - if(9) - steps = 5 - if(11) - steps = 6 + steps = current_stage?.footprint || 1 else steps = step var/list/turfs = list() @@ -352,10 +217,10 @@ var/dir2 = 0 var/dir3 = 0 switch(direction) - if(NORTH||SOUTH) + if(NORTH,SOUTH) dir2 = 4 dir3 = 8 - if(EAST||WEST) + if(EAST,WEST) dir2 = 1 dir3 = 2 var/turf/T2 = T @@ -376,11 +241,11 @@ return 0 return 1 -/obj/singularity/proc/can_move(const/turf/T) +/obj/effect/singularity/proc/can_move(const/turf/T) if (!isturf(T)) return 0 - if ((locate(/obj/machinery/containment_field) in T) || (locate(/obj/machinery/shieldwall) in T)) + if ((locate(/obj/effect/containment_field) in T) || (locate(/obj/machinery/shieldwall) in T)) return 0 else if (locate(/obj/machinery/field_generator) in T) var/obj/machinery/field_generator/G = locate(/obj/machinery/field_generator) in T @@ -394,104 +259,56 @@ return 0 return 1 -/obj/singularity/proc/event() - var/numb = pick(1, 2, 3, 4, 5, 6) +/obj/effect/singularity/proc/update_strings() + if(current_stage) + SetName(current_stage.name) + desc = current_stage.desc + else + SetName(initial(name)) + desc = initial(desc) - switch (numb) - if (1) //EMP. - emp_area() - if (2, 3) //Tox damage all carbon mobs in area. - toxmob() - if (4) //Stun mobs who lack optic scanners. - mezzer() - else - return 0 - if(current_size == 11) - smwave() - return 1 +/obj/effect/singularity/on_update_icon() + . = ..() + var/last_pixel_x = default_pixel_x + var/last_pixel_y = default_pixel_y + if(current_stage) + icon = current_stage.icon + icon_state = current_stage.icon_state + default_pixel_x = current_stage.pixel_x + default_pixel_y = current_stage.pixel_y + else + icon = initial(icon) + icon_state = initial(icon_state) + default_pixel_x = initial(default_pixel_x) + default_pixel_y = initial(default_pixel_y) + if(last_pixel_x != default_pixel_x || last_pixel_y != default_pixel_y) + reset_offsets(0) + +/obj/effect/singularity/singularity_act(S, size) + if(current_stage.stage_size <= size) + var/gain = (energy/2) + var/dist = max((current_stage.stage_size - 2), 1) + explosion(src.loc,(dist),(dist*2),(dist*4)) + QDEL_IN(src, 1) + return gain + return 0 +// Various overrides used to consume things interacting with the singularity. +/obj/effect/singularity/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + consume(user) + return TRUE -/obj/singularity/proc/toxmob() - var/toxrange = 10 - var/toxdamage = 4 - var/radiation = 15 - if (src.energy>200) - toxdamage = round(((src.energy-150)/50)*4,1) - radiation = round(((src.energy-150)/50)*5,1) - SSradiation.radiate(src, radiation) //Always radiate at max, so a decent dose of radiation is applied - for(var/mob/living/M in view(toxrange, src.loc)) - if(M.status_flags & GODMODE) - continue - M.apply_damage(toxdamage, TOX, null, damage_flags = DAM_DISPERSED) +/obj/effect/singularity/Bump(atom/A) + consume(A) -/obj/singularity/proc/mezzer() - for(var/mob/living/carbon/M in oviewers(8, src)) - if(istype(M, /mob/living/carbon/brain)) //Ignore brains - continue - if(M.status_flags & GODMODE) - continue - if(M.stat == CONSCIOUS) - if (istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(istype(H.glasses,/obj/item/clothing/glasses/meson) && current_size != 11) - to_chat(H, "You look directly into The [src.name], good thing you had your protective eyewear on!") - return - else - to_chat(H, "You look directly into The [src.name], but your eyewear does absolutely nothing to protect you from it!") - to_chat(M, "You look directly into The [src.name] and feel [current_size == 11 ? "helpless" : "weak"].") - M.apply_effect(3, STUN) - for(var/mob/O in viewers(M, null)) - O.show_message(text("[] stares blankly at The []!", M, src), 1) - -/obj/singularity/proc/emp_area() - if(current_size != 11) - empulse(src, 8, 10) - else - empulse(src, 12, 16) +/obj/effect/singularity/Bumped(atom/A) + consume(A) -/obj/singularity/proc/smwave() - for(var/mob/living/M in view(10, src.loc)) - if(prob(67)) - to_chat(M, "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") - to_chat(M, "Miraculously, it fails to kill you.") - else - to_chat(M, "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") - to_chat(M, "You don't even have a moment to react as you are reduced to ashes by the intense radiation.") - M.dust() - SSradiation.radiate(src, rand(energy)) - return - -/obj/singularity/proc/pulse() - for(var/obj/machinery/power/rad_collector/R in rad_collectors) - if (get_dist(R, src) <= 15) //Better than using orange() every process. - R.receive_pulse(energy) +/obj/effect/singularity/attack_ai() //To prevent ais from gibbing themselves when they click on one. + return TRUE -/obj/singularity/proc/on_capture() - chained = 1 - overlays.Cut() - move_self = 0 - switch (current_size) - if(1) - overlays += image('icons/obj/singularity.dmi',"chain_s1") - if(3) - overlays += image('icons/effects/96x96.dmi',"chain_s3") - if(5) - overlays += image('icons/effects/160x160.dmi',"chain_s5") - if(7) - overlays += image('icons/effects/224x224.dmi',"chain_s7") - if(9) - overlays += image('icons/effects/288x288.dmi',"chain_s9") - -/obj/singularity/proc/on_release() - chained = 0 - overlays.Cut() - move_self = 1 - -/obj/singularity/singularity_act(S, size) - if(current_size <= size) - var/gain = (energy/2) - var/dist = max((current_size - 2), 1) - explosion(src.loc,(dist),(dist*2),(dist*4)) - spawn(0) - qdel(src) - return gain +/obj/effect/singularity/attack_robot(mob/user) + if(Adjacent(user)) + consume(user) + return TRUE diff --git a/code/modules/power/singularity/singularity_events.dm b/code/modules/power/singularity/singularity_events.dm new file mode 100644 index 000000000000..f3bc342ac90e --- /dev/null +++ b/code/modules/power/singularity/singularity_events.dm @@ -0,0 +1,41 @@ +/decl/singularity_event + abstract_type = /decl/singularity_event + +/decl/singularity_event/proc/handle_event(obj/effect/singularity/source) + return + +/decl/singularity_event/nothing // Nothing happens. + +/decl/singularity_event/empulse/handle_event(obj/effect/singularity/source) + empulse(source, source.current_stage.em_heavy_range, source.current_stage.em_light_range) + +/decl/singularity_event/toxins + var/toxrange = 10 + +/decl/singularity_event/toxins/handle_event(obj/effect/singularity/source) + var/toxdamage = 4 + var/radiation = 15 + if (source.energy > 200) + toxdamage = round(((source.energy-150)/50)*4,1) + radiation = round(((source.energy-150)/50)*5,1) + SSradiation.radiate(source, radiation) //Always radiate at max, so a decent dose of radiation is applied + for(var/mob/living/M in view(toxrange, source.loc)) + M.apply_damage(toxdamage, TOX, null, damage_flags = DAM_DISPERSED) + +/decl/singularity_event/mesmerize/handle_event(obj/effect/singularity/source) + for(var/mob/living/M in oviewers(8, source)) + if(isbrain(M)) //Ignore brains + continue + if(M.status_flags & GODMODE) + continue + if(M.stat == CONSCIOUS) + if(ishuman(M)) + var/mob/living/human/H = M + if(istype(H.get_equipped_item(slot_glasses_str), /obj/item/clothing/glasses/meson)) + if(!source.current_stage.the_goggles_do_nothing) + to_chat(H, SPAN_WARNING("You look directly into \the [source]. Good thing you had your protective eyewear on!")) + continue + to_chat(H, SPAN_WARNING("Your eyewear does absolutely nothing to protect you from \the [source]")) + to_chat(M, SPAN_DANGER("You look directly into \the [source] and feel [source.current_stage.mesmerize_text].")) + M.apply_effect(3, STUN) + M.visible_message(SPAN_DANGER("\The [M] stares blankly at \the [source]!")) diff --git a/code/modules/power/singularity/singularity_stages.dm b/code/modules/power/singularity/singularity_stages.dm new file mode 100644 index 000000000000..f644a21e1ec2 --- /dev/null +++ b/code/modules/power/singularity/singularity_stages.dm @@ -0,0 +1,193 @@ +/decl/singularity_stage + abstract_type = /decl/singularity_stage + var/name = "gravitational singularity" + var/desc = "A gravitational singularity." + /// What is the effective physical size of this singularity? + var/footprint = 1 + /// What is the numerical size of this singularity? + var/stage_size = 0 + /// What is the minimum singularity energy to reach this sage? + var/min_energy = -(INFINITY) + /// What is the maximum singularity energy to stay at this sage? + var/max_energy = 0 + /// What icon should the singularity use at this stage? + var/icon + /// What icon_state should the singularity use at this stage? + var/icon_state + /// What x offset should the singularity use at this stage? + var/pixel_x = 0 + /// What y offset should the singularity use at this stage? + var/pixel_y = 0 + /// What is the pull range of a singularity at this stage? + var/grav_pull = 0 + /// What is the feeding range of a singularity at this stage? + var/consume_range = 0 + /// If true, the singularity will lose energy in Process(). + var/dissipates_over_time = TRUE + /// How many Process() ticks do we have between dissipations? + var/ticks_between_dissipations = 10 + /// A counter variable for how many ticks we are along the dissipation. + var/ticks_since_last_dissipation = 0 + /// How much energy do we lose when we dissipate? + var/dissipation_energy_loss = 1 + /// What is the percent chance of an event each tick? + var/event_chance = 0 + /// Do we force a specific event when we proc events? + var/decl/singularity_event/forced_event = null + /// Will we wander around? + var/wander = FALSE + /// Can explosions destroy the singularity? + var/explosion_vulnerable = FALSE + /// What is the heavy range for the EM pulse event in this stage? + var/em_heavy_range = 8 + /// What is the light range for the EM pulse event in this stage? + var/em_light_range = 10 + /// What do characters feel when they're mesmerized during this stage? + var/mesmerize_text = "weak" + /// Do we ignore PPE for mesmerizing in this stage? + var/the_goggles_do_nothing = FALSE + /// Do we ignore obstacles in our way? + var/ignore_obstacles = FALSE + +/decl/singularity_stage/validate() + . = ..() + if(consume_range < 0) + . += "negative consume_range" + if(grav_pull < 0) + . += "negative grav_pull" + else if(consume_range >= 0 && grav_pull < consume_range) + . += "grav_pull is smaller than consume_range; consume_range will be truncated" + if(min_energy > max_energy) + . += "min_energy is larger than max_energy, stage will never be able to exist" + +/decl/singularity_stage/proc/handle_dissipation(obj/effect/singularity/source) + if(dissipates_over_time) + if(ticks_since_last_dissipation >= ticks_between_dissipations) + source.energy -= dissipation_energy_loss + ticks_since_last_dissipation = 0 + return TRUE + ticks_since_last_dissipation++ + return FALSE + +/decl/singularity_stage/proc/grow_to(obj/effect/singularity/source) + return + +/decl/singularity_stage/proc/shrink_to(obj/effect/singularity/source) + return + +/decl/singularity_stage/proc/has_expansion_room(obj/effect/singularity/source) + return TRUE + +/decl/singularity_stage/stage_one + stage_size = STAGE_ONE + min_energy = -(INFINITY) + max_energy = 200 + footprint = 1 + icon = 'icons/obj/singularity.dmi' + icon_state = "singularity_s1" + pixel_x = 0 + pixel_y = 0 + grav_pull = 4 + consume_range = 0 + ticks_between_dissipations = 10 + ticks_since_last_dissipation = 0 + dissipation_energy_loss = 1 + wander = FALSE + event_chance = 0 + +/decl/singularity_stage/stage_one/shrink_to(obj/effect/singularity/source) + source.visible_message(SPAN_NOTICE("\The [source] has shrunk to a rather pitiful size.")) + +/decl/singularity_stage/stage_two + stage_size = STAGE_TWO + min_energy = 200 + max_energy = 500 + footprint = 3 + icon = 'icons/effects/96x96.dmi' + icon_state = "singularity_s3" + pixel_x = -32 + pixel_y = -32 + grav_pull = 6 + consume_range = 1 + ticks_between_dissipations = 5 + ticks_since_last_dissipation = 0 + dissipation_energy_loss = 5 + wander = TRUE + event_chance = 10 + +/decl/singularity_stage/stage_two/grow_to(obj/effect/singularity/source) + source.visible_message(SPAN_NOTICE("\The [source] noticeably grows in size.")) + +/decl/singularity_stage/stage_two/shrink_to(obj/effect/singularity/source) + source.visible_message(SPAN_NOTICE("\The [source] has shrunk to a less powerful size.")) + +/decl/singularity_stage/stage_three + min_energy = 500 + max_energy = 1000 + stage_size = STAGE_THREE + footprint = 3 + icon = 'icons/effects/160x160.dmi' + icon_state = "singularity_s5" + pixel_x = -64 + pixel_y = -64 + grav_pull = 8 + consume_range = 2 + ticks_between_dissipations = 4 + ticks_since_last_dissipation = 0 + dissipation_energy_loss = 20 + wander = TRUE + event_chance = 10 + +/decl/singularity_stage/stage_three/has_expansion_room(obj/effect/singularity/source) + return source.check_turfs_in(1, 2) && source.check_turfs_in(2, 2) && source.check_turfs_in(4, 2) && source.check_turfs_in(8, 2) + +/decl/singularity_stage/stage_three/grow_to(obj/effect/singularity/source) + source.visible_message(SPAN_NOTICE("\The [source] expands to a reasonable size.")) + +/decl/singularity_stage/stage_three/shrink_to(obj/effect/singularity/source) + source.visible_message(SPAN_NOTICE("\The [source] has returned to a safe size.")) + +/decl/singularity_stage/stage_four + min_energy = 1000 + max_energy = 2000 + stage_size = STAGE_FOUR + footprint = 4 + icon = 'icons/effects/224x224.dmi' + icon_state = "singularity_s7" + pixel_x = -96 + pixel_y = -96 + grav_pull = 10 + consume_range = 3 + ticks_between_dissipations = 10 + ticks_since_last_dissipation = 0 + dissipation_energy_loss = 10 + wander = TRUE + event_chance = 16 + +/decl/singularity_stage/stage_four/has_expansion_room(obj/effect/singularity/source) + return source.check_turfs_in(1, 2) && source.check_turfs_in(2, 2) && source.check_turfs_in(4, 2) && source.check_turfs_in(8, 2) + +/decl/singularity_stage/stage_four/grow_to(obj/effect/singularity/source) + source.visible_message(SPAN_WARNING("\The [source] expands to a dangerous size.")) + +/decl/singularity_stage/stage_four/shrink_to(obj/effect/singularity/source) + source.visible_message(SPAN_NOTICE("Miraculously, \the [source] reduces in size, and can be contained.")) + +/decl/singularity_stage/stage_five + min_energy = 2000 + max_energy = 50000 + stage_size = STAGE_FIVE + footprint = 5 + icon = 'icons/effects/288x288.dmi' + icon_state = "singularity_s9" + pixel_x = -128 + pixel_y = -128 + grav_pull = 10 + consume_range = 4 + dissipates_over_time = FALSE //It cant go smaller due to e loss. + wander = TRUE + event_chance = 20 + ignore_obstacles = TRUE + +/decl/singularity_stage/stage_five/grow_to(obj/effect/singularity/source) + source.visible_message(SPAN_DANGER("\The [source] has grown out of control!")) diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 0e40879e742f..f075340d7aa0 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -8,8 +8,8 @@ name = "power storage unit" desc = "A high-capacity superconducting magnetic energy storage (SMES) unit." icon_state = "smes" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE clicksound = "switch" core_skill = SKILL_ELECTRICAL power_channel = LOCAL // Draws power from direct connections to powernets. @@ -18,6 +18,7 @@ stat_immune = 0 stat = BROKEN // Should be removed if the terminals initialize fully. reason_broken = MACHINE_BROKEN_GENERIC + abstract_type = /obj/machinery/power/smes var/capacity = 5e6 // maximum charge var/charge = 1e6 // actual charge @@ -70,7 +71,7 @@ queue_icon_update() /obj/machinery/power/smes/populate_parts() - for(var/d in GLOB.cardinal) + for(var/d in global.cardinal) var/obj/item/stock_parts/power/terminal/part = install_component(/obj/item/stock_parts/power/terminal, refresh_parts = FALSE) part.terminal_dir = d var/turf/T = get_step(src, d) @@ -115,7 +116,7 @@ /obj/machinery/power/smes/proc/input_power(var/percentage) var/to_input = target_load * (percentage/100) - to_input = between(0, to_input, target_load) + to_input = clamp(to_input, 0, target_load) input_available = 0 if(percentage == 100) inputting = 2 @@ -165,9 +166,9 @@ var/is_input_available = FALSE for(var/obj/item/stock_parts/power/terminal/term in power_components) if(!term.terminal || !term.terminal.powernet) - continue + continue is_input_available = TRUE - term.terminal.powernet.smes_demand += target_load + term.terminal.powernet.smes_demand += target_load term.terminal.powernet.inputting.Add(src) if(!is_input_available) target_load = 0 // We won't input any power without powernet connection. @@ -196,7 +197,7 @@ return var/total_restore = output_used * (percent_load / 100) // First calculate amount of power used from our output - total_restore = between(0, total_restore, output_used) // Now clamp the value between 0 and actual output, just for clarity. + total_restore = clamp(total_restore, 0, output_used) // Now clamp the value between 0 and actual output, just for clarity. total_restore = output_used - total_restore // And, at last, subtract used power from outputted power, to get amount of power we will give back to the SMES. // now recharge this amount @@ -219,13 +220,10 @@ ui_interact(user) return TRUE -/obj/machinery/power/smes/attackby(var/obj/item/W, var/mob/user) - if(component_attackby(W, user)) - return TRUE - - if (!panel_open) - to_chat(user, "You need to open the access hatch on \the [src] first!") - return TRUE +/obj/machinery/power/smes/attackby(var/obj/item/used_item, var/mob/user) + if((. = component_attackby(used_item, user))) + return + return bash(used_item, user) /obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) // this is the data which will be sent to the ui @@ -265,22 +263,19 @@ return 0 return round(100.0*charge/capacity, 0.1) -/obj/machinery/power/smes/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/power/smes/OnTopic(mob/user, href_list) + if((. = ..())) + return if( href_list["cmode"] ) inputting(!input_attempt) - update_icon() - return 1 + . = TOPIC_REFRESH else if( href_list["online"] ) outputting(!output_attempt) - update_icon() - return 1 + . = TOPIC_REFRESH else if( href_list["reboot"] ) failure_timer = 0 - update_icon() - return 1 + . = TOPIC_REFRESH else if( href_list["input"] ) switch( href_list["input"] ) if("min") @@ -290,7 +285,7 @@ if("set") input_level = (input(usr, "Enter new input level (0-[input_level_max/1000] kW)", "SMES Input Power Control", input_level/1000) as num) * 1000 input_level = max(0, min(input_level_max, input_level)) // clamp to range - return 1 + . = TOPIC_REFRESH else if( href_list["output"] ) switch( href_list["output"] ) if("min") @@ -300,7 +295,7 @@ if("set") output_level = (input(usr, "Enter new output level (0-[output_level_max/1000] kW)", "SMES Output Power Control", output_level/1000) as num) * 1000 output_level = max(0, min(output_level_max, output_level)) // clamp to range - return 1 + . = TOPIC_REFRESH /obj/machinery/power/smes/proc/energy_fail(var/duration) @@ -341,6 +336,6 @@ update_icon() ..() -/obj/machinery/power/smes/examine(mob/user) +/obj/machinery/power/smes/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The service hatch is [panel_open ? "open" : "closed"].") + . += "The service hatch is [panel_open ? "open" : "closed"]." diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm index 119ae590982e..cb78bef66777 100644 --- a/code/modules/power/smes_construction.dm +++ b/code/modules/power/smes_construction.dm @@ -10,14 +10,14 @@ name = "superconductive magnetic coil" desc = "Standard superconductive magnetic coil with average capacity and I/O rating." icon = 'icons/obj/items/stock_parts/stock_parts.dmi' - icon_state = "smes_coil" // Just few icons patched together. If someone wants to make better icon, feel free to do so! + icon_state = "smes_coil" w_class = ITEM_SIZE_LARGE // It's LARGE (backpack size) - origin_tech = "{'materials':7,'powerstorage':7,'engineering':5}" + origin_tech = @'{"materials":7,"powerstorage":7,"engineering":5}' base_type = /obj/item/stock_parts/smes_coil part_flags = PART_FLAG_HAND_REMOVE material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE @@ -30,23 +30,27 @@ /obj/item/stock_parts/smes_coil/weak name = "basic superconductive magnetic coil" desc = "Cheaper model of standard superconductive magnetic coil. It's capacity and I/O rating are considerably lower." + icon_state = "smes_coil_weak" ChargeCapacity = 10 KILOWATTS IOCapacity = 150 KILOWATTS // 500% Charge Capacity, 40% I/O Capacity. Holds a lot of energy, but charges slowly if not combined with other coils. Ideal for backup storage. /obj/item/stock_parts/smes_coil/super_capacity name = "superconductive capacitance coil" - desc = "Specialised version of standard superconductive magnetic coil. This one has significantly stronger containment field, allowing for significantly larger power storage. It's IO rating is much lower, however." + desc = "Specialised version of standard superconductive magnetic coil. This one has significantly stronger containment field, allowing for significantly larger power storage. Its IO rating is much lower, however." + icon_state = "smes_coil_capacitance" ChargeCapacity = 250 KILOWATTS IOCapacity = 100 KILOWATTS + rating = 2 // 40% Charge Capacity, 500% I/O Capacity. Technically turns SMES into large super capacitor. Ideal for shields. /obj/item/stock_parts/smes_coil/super_io name = "superconductive transmission coil" - desc = "Specialised version of standard superconductive magnetic coil. While this one won't store almost any power, it rapidly transfers power, making it useful in systems which require large throughput." + desc = "Specialised version of standard superconductive magnetic coil. While this one won't store almost any power, it rapidly transfers current, making it useful in systems which require large throughput." + icon_state = "smes_coil_transmission" ChargeCapacity = 20 KILOWATTS IOCapacity = 1.25 MEGAWATTS - + rating = 2 // DEPRECATED // These are used on individual outposts as backup should power line be cut, or engineering outpost lost power. @@ -65,28 +69,18 @@ // SMES itself /obj/machinery/power/smes/buildable - var/safeties_enabled = 1 // If 0 modifications can be done without discharging the SMES, at risk of critical failure. - var/failing = 0 // If 1 critical failure has occured and SMES explosion is imminent. - wires = /datum/wires/smes - var/grounding = 1 // Cut to quickly discharge, at cost of "minor" electrical issues in output powernet. - var/RCon = 1 // Cut to disable AI and remote control. - var/RCon_tag = "NO_TAG" // RCON tag, change to show it on SMES Remote control console. - var/emp_proof = 0 // Whether the SMES is EMP proof - charge = 0 + wires = /datum/wires/smes should_be_mapped = 1 base_type = /obj/machinery/power/smes/buildable maximum_component_parts = list(/obj/item/stock_parts/smes_coil = 6, /obj/item/stock_parts = 15) interact_offline = TRUE - -/obj/machinery/power/smes/buildable/malf_upgrade(var/mob/living/silicon/ai/user) - ..() - malf_upgraded = 1 - emp_proof = 1 - RefreshParts() - to_chat(user, "\The [src] has been upgraded. It's transfer rate and capacity has increased, and it is now resistant against EM pulses.") - return 1 - + var/safeties_enabled = 1 // If 0 modifications can be done without discharging the SMES, at risk of critical failure. + var/failing = 0 // If 1 critical failure has occurred and SMES explosion is imminent. + var/grounding = 1 // Cut to quickly discharge, at cost of "minor" electrical issues in output powernet. + var/RCon = 1 // Cut to disable AI and remote control. + var/RCon_tag = "NO_TAG" // RCON tag, change to show it on SMES Remote control console. + var/emp_proof = 0 // Whether the SMES is EMP proof /obj/machinery/power/smes/buildable/max_cap_in_out/Initialize() . = ..() @@ -102,9 +96,7 @@ // This also causes the SMES to quickly discharge, and has small chance of damaging output APCs. /obj/machinery/power/smes/buildable/Process() if(!grounding && (Percentage() > 5)) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() + spark_at(src, amount=5, cardinal_only = TRUE) charge -= (output_level_max * CELLRATE) if(prob(1)) // Small chance of overload occuring since grounding is disabled. apcs_overload(5,10,20) @@ -114,7 +106,7 @@ // Proc: attack_ai() // Parameters: None // Description: AI requires the RCON wire to be intact to operate the SMES. -/obj/machinery/power/smes/buildable/attack_ai(mob/user) +/obj/machinery/power/smes/buildable/attack_ai(mob/living/silicon/ai/user) if(RCon) ..() else // RCON wire cut @@ -132,11 +124,7 @@ capacity += C.ChargeCapacity input_level_max += C.IOCapacity output_level_max += C.IOCapacity - if(malf_upgraded) - capacity *= 1.2 - input_level_max *= 2 - output_level_max *= 2 - charge = between(0, charge, capacity) + charge = clamp(charge, 0, capacity) // Proc: total_system_failure() // Parameters: 2 (intensity - how strong the failure is, user - person which caused the failure) @@ -147,7 +135,7 @@ // Possible effects: // Sparks - Lets out few sparks, mostly fire hazard if flammable gas present. Otherwise purely aesthetic. // Shock - Depending on intensity harms the user. Insultated Gloves protect against weaker shocks, but strong shock bypasses them. - // EMP Pulse - Lets out EMP pulse discharge which screws up nearby electronics. + // EMP - Lets out EMP discharge which screws up nearby electronics. // Light Overload - X% chance to overload each lighting circuit in connected powernet. APC based. // APC Failure - X% chance to destroy APC causing very weak explosion too. Won't cause hull breach or serious harm. // SMES Explosion - X% chance to destroy the SMES, in moderate explosion. May cause small hull breach. @@ -155,47 +143,41 @@ if (!intensity) return - var/mob/living/carbon/human/h_user = null - if (!istype(user, /mob/living/carbon/human)) + var/mob/living/human/h_user = null + if (!ishuman(user)) return else h_user = user - // Preparations - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread // Check if user has protected gloves. var/user_protected = 0 - if(h_user.gloves) - var/obj/item/clothing/gloves/G = h_user.gloves - if(G.siemens_coefficient == 0) - user_protected = 1 - log_and_message_admins("SMES FAILURE: [src.x]X [src.y]Y [src.z]Z User: [usr.ckey], Intensity: [intensity]/100 - JMP") - + var/obj/item/clothing/gloves/G = h_user.get_equipped_item(slot_gloves_str) + if(istype(G) && G.siemens_coefficient == 0) + user_protected = 1 + log_and_message_admins("SMES FAILURE: [src.x]X [src.y]Y [src.z]Z User: [user.ckey], Intensity: [intensity]/100 - JMP") switch (intensity) if (0 to 15) // Small overcharge // Sparks, Weak shock - s.set_up(2, 1, src) - s.start() + spark_at(src, amount = 2, cardinal_only = TRUE) if(user_protected && prob(80)) to_chat(h_user, SPAN_WARNING("Small electrical arc almost burns your hand. Luckily you had your gloves on!")) else - to_chat(h_user, SPAN_DANGER("Small electrical arc sparks and burns your hand as you touch the [src]!")) - h_user.electrocute_act(rand(5,20), src, def_zone = h_user.hand ? BP_L_HAND : BP_R_HAND)//corrected to counter act armor and stuff + to_chat(h_user, SPAN_DANGER("Small electrical arc sparks and burns your hand as you touch \the [src]!")) + h_user.electrocute_act(rand(5,20), src, def_zone = h_user.get_active_held_item_slot())//corrected to counter act armor and stuff charge = 0 if (16 to 35) // Medium overcharge // Sparks, Medium shock, Weak EMP - s.set_up(4,1,src) - s.start() + spark_at(src, amount = 4, cardinal_only = TRUE) if (user_protected && prob(25)) to_chat(h_user, SPAN_WARNING("Medium electrical arc sparks and almost burns your hand. Luckily you had your gloves on!")) else - to_chat(h_user, SPAN_DANGER("Medium electrical sparks as you touch the [src], severely burning your hand!")) - h_user.electrocute_act(rand(15,35), src, def_zone = h_user.hand ? BP_L_HAND : BP_R_HAND) + to_chat(h_user, SPAN_DANGER("Medium electrical sparks as you touch \the [src], severely burning your hand!")) + h_user.electrocute_act(rand(15,35), src, def_zone = h_user.get_active_held_item_slot()) spawn(0) empulse(src.loc, 2, 4) apcs_overload(0, 5, 10) @@ -204,36 +186,34 @@ if (36 to 60) // Strong overcharge // Sparks, Strong shock, Strong EMP, 10% light overload. 1% APC failure - s.set_up(7,1,src) - s.start() + spark_at(src, amount = 7, cardinal_only = TRUE) if (user_protected) to_chat(h_user, SPAN_DANGER("Strong electrical arc sparks between you and [src], ignoring your gloves and burning your hand!")) - h_user.electrocute_act(rand(30,60), src, def_zone = h_user.hand ? BP_L_HAND : BP_R_HAND) - h_user.Paralyse(3) + h_user.electrocute_act(rand(30,60), src, def_zone = h_user.get_active_held_item_slot()) + SET_STATUS_MAX(h_user, STAT_PARA, 3) else to_chat(h_user, SPAN_DANGER("Strong electrical arc sparks between you and [src], knocking you out for a while!")) h_user.electrocute_act(rand(40,80), src, def_zone = ran_zone(null)) - h_user.Paralyse(6) + SET_STATUS_MAX(h_user, STAT_PARA, 6) spawn(0) empulse(src.loc, 8, 16) - charge = 0 apcs_overload(1, 10, 20) + charge = 0 energy_fail(10) src.ping("Caution. Output regulators malfunction. Uncontrolled discharge detected.") if (61 to INFINITY) // Massive overcharge // Sparks, Near - instantkill shock, Strong EMP, 25% light overload, 5% APC failure. 50% of SMES explosion. This is bad. - s.set_up(10,1,src) - s.start() + spark_at(src, amount = 10, cardinal_only = TRUE) to_chat(h_user, SPAN_WARNING("Massive electrical arc sparks between you and [src].
    Last thing you can think about is \"Oh shit...\"")) - // Remember, we have few gigajoules of electricity here.. Turn them into crispy toast. + // Remember, we have few gigajoules of electricity here. Turn them into crispy toast. h_user.electrocute_act(rand(170,210), src, def_zone = ran_zone(null)) - h_user.Paralyse(8) + SET_STATUS_MAX(h_user, STAT_PARA, 8) spawn(0) empulse(src.loc, 32, 64) - charge = 0 apcs_overload(5, 25, 100) + charge = 0 energy_fail(30) src.ping("Caution. Output regulators malfunction. Significant uncontrolled discharge detected.") @@ -250,7 +230,7 @@ return src.ping("DANGER! Magnetic containment field failure in 3 ... 2 ... 1 ...") explosion(src.loc,1,2,4,8) - // Not sure if this is necessary, but just in case the SMES *somehow* survived.. + // Not sure if this is necessary, but just in case the SMES *somehow* survived. qdel(src) /obj/machinery/power/smes/buildable/proc/check_total_system_failure(var/mob/user) @@ -265,23 +245,34 @@ total_system_failure(failure_probability, user) return TRUE -// Proc: apcs_overload() -// Parameters: 3 (failure_chance - chance to actually break the APC, overload_chance - Chance of breaking lights, reboot_chance - Chance of temporarily disabling the APC) -// Description: Damages output powernet by power surge. Destroys few APCs and lights, depending on parameters. +/** + * Processes the APCs overloaded by malfunctioning SMES. + * + * Damages output powernet by power surge. Destroys or damages few APCs and lights, depending on parameters and current SMES charge. + * + * - `failure_chance`: chance to actually damage the individual APC (in %). Damage scales from SMES charge, can easily destroy some. + * - `overload_chance`: chance of breaking the lightbulbs on individual APC network (in %). + * - `reboot_chance`: chance of temporarily (30..60 sec) disabling the individual APC (in %). + */ /obj/machinery/power/smes/buildable/proc/apcs_overload(var/failure_chance, var/overload_chance, var/reboot_chance) if (!src.powernet) return - + var/list/obj/machinery/apc/apcs = list() for(var/obj/machinery/power/terminal/T in powernet.nodes) - var/obj/machinery/power/apc/A = T.master_machine() + var/obj/machinery/apc/A = T.master_machine() if(istype(A)) if (prob(overload_chance)) A.overload_lighting() if (prob(failure_chance)) - A.set_broken(TRUE) + apcs |= A if(prob(reboot_chance)) A.energy_fail(rand(30,60)) + if (apcs.len) + var/overload_damage = charge/100/apcs.len + for (var/obj/machinery/apc/A in apcs) + A.take_damage(overload_damage, ELECTROCUTE) + // Proc: update_icon() // Parameters: None // Description: Allows us to use special icon overlay for critical SMESs @@ -304,7 +295,7 @@ if(!(stat & BROKEN)) return SPAN_WARNING("You have to disassemble the terminal[num_terminals > 1 ? "s" : ""] first!") if(user) - if(!do_after(user, 5 SECONDS * number_of_components(/obj/item/stock_parts/smes_coil), src) && isCrowbar(user.get_active_hand())) + if(!do_after(user, 5 SECONDS * number_of_components(/obj/item/stock_parts/smes_coil), src) && IS_CROWBAR(user.get_active_held_item())) return MCS_BLOCK if(check_total_system_failure(user)) return MCS_BLOCK @@ -337,22 +328,24 @@ ..() // Proc: attackby() -// Parameters: 2 (W - object that was used on this machine, user - person which used the object) +// Parameters: 2 (used_item - object that was used on this machine, user - person which used the object) // Description: Handles tool interaction. Allows deconstruction/upgrading/fixing. -/obj/machinery/power/smes/buildable/attackby(var/obj/item/W, var/mob/user) +/obj/machinery/power/smes/buildable/attackby(var/obj/item/used_item, var/mob/user) // No more disassembling of overloaded SMESs. You broke it, now enjoy the consequences. if (failing) to_chat(user, "\The [src]'s screen is flashing with alerts. It seems to be overloaded! Touching it now is probably not a good idea.") + return TRUE + . = ..() + if(.) return - - if (!..()) - - // Multitool - change RCON tag - if(isMultitool(W)) - var/newtag = input(user, "Enter new RCON tag. Use \"NO_TAG\" to disable RCON or leave empty to cancel.", "SMES RCON system") as text - if(newtag) - RCon_tag = newtag - to_chat(user, "You changed the RCON tag to: [newtag]") + // Multitool - change RCON tag + if(IS_MULTITOOL(used_item)) + var/newtag = input(user, "Enter new RCON tag. Use \"NO_TAG\" to disable RCON or leave empty to cancel.", "SMES RCON system") as text + if(newtag) + RCon_tag = newtag + to_chat(user, "You changed the RCON tag to: [newtag]") + return TRUE + return FALSE // Proc: toggle_input() // Parameters: None @@ -372,14 +365,14 @@ // Parameters: 1 (new_input - New input value in Watts) // Description: Sets input setting on this SMES. Trims it if limits are exceeded. /obj/machinery/power/smes/buildable/proc/set_input(var/new_input = 0) - input_level = between(0, new_input, input_level_max) + input_level = clamp(new_input, 0, input_level_max) update_icon() // Proc: set_output() // Parameters: 1 (new_output - New output value in Watts) // Description: Sets output setting on this SMES. Trims it if limits are exceeded. /obj/machinery/power/smes/buildable/proc/set_output(var/new_output = 0) - output_level = between(0, new_output, output_level_max) + output_level = clamp(new_output, 0, output_level_max) update_icon() /obj/machinery/power/smes/buildable/emp_act(var/severity) diff --git a/code/modules/power/smes_presets.dm b/code/modules/power/smes_presets.dm index 0775d5ca164c..39d638616c0c 100644 --- a/code/modules/power/smes_presets.dm +++ b/code/modules/power/smes_presets.dm @@ -14,4 +14,12 @@ input_attempt = _input_on output_attempt = _output_on if(_fully_charged) - charge = capacity \ No newline at end of file + charge = capacity + +// Pre-installed and pre-charged SMES hidden from the station, for use in submaps. +/obj/machinery/power/smes/buildable/preset/hidden + _fully_charged = TRUE + _input_on = TRUE + _input_maxed = TRUE + _output_maxed = TRUE + RCon = FALSE \ No newline at end of file diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index e8287c1be0b4..29c458486a8b 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -1,25 +1,35 @@ +/obj/machinery/proc/get_best_sun() + var/turf/my_turf = get_turf(src) + if(!istype(my_turf)) + return + var/datum/level_data/level = SSmapping.levels_by_z[my_turf.z] + if(!level?.daycycle_id) + return + var/datum/daycycle/daycycle = SSdaycycle.get_daycycle(level.daycycle_id) + if(!length(daycycle?.suns)) + return + //TODO: iterate list and return best sun for this solar panel + return daycycle.suns[1] + #define SOLAR_MAX_DIST 40 -var/solar_gen_rate = 1500 -var/list/solars_list = list() +var/global/solar_gen_rate = 1500 +var/global/list/solars_list = list() /obj/machinery/power/solar - name = "solar panel" + name = "basic solar panel" desc = "A solar electrical generator." icon = 'icons/obj/power.dmi' icon_state = "sp_base" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE idle_power_usage = 0 active_power_usage = 0 - var/id = 0 - var/health = 10 + max_health = 10 var/obscured = 0 var/sunfrac = 0 var/efficiency = 1 - var/adir = SOUTH // actual dir - var/ndir = SOUTH // target dir - var/turn_angle = 0 + var/adir = 0 // direction we're facing in degrees var/obj/machinery/power/solar_control/control = null /obj/machinery/power/solar/improved @@ -54,37 +64,36 @@ var/list/solars_list = list() /obj/machinery/power/solar/proc/Make(var/obj/item/solar_assembly/S) if(!S) S = new /obj/item/solar_assembly(src) - S.glass_type = /obj/item/stack/material/glass - S.anchored = 1 + S.glass_type = /decl/material/solid/glass + S.anchored = TRUE S.forceMove(src) - if(S.glass_type == /obj/item/stack/material/glass/reinforced) //if the panel is in reinforced glass - health *= 2 //this need to be placed here, because panels already on the map don't have an assembly linked to + if(S.glass_reinforced) //if the panel is in reinforced glass + current_health *= 2 //this need to be placed here, because panels already on the map don't have an assembly linked to update_icon() -/obj/machinery/power/solar/attackby(obj/item/W, mob/user) - - if(isCrowbar(W)) - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) +/obj/machinery/power/solar/attackby(obj/item/used_item, mob/user) + if(IS_CROWBAR(used_item)) + playsound(loc, 'sound/machines/click.ogg', 50, 1) user.visible_message("[user] begins to take the glass off the solar panel.") if(do_after(user, 50,src)) var/obj/item/solar_assembly/S = locate() in src if(S) S.dropInto(loc) S.give_glass() - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) user.visible_message("[user] takes the glass off the solar panel.") qdel(src) - return - else if (W) - src.add_fingerprint(user) - src.health -= W.force - src.healthcheck() - ..() + return TRUE + else if (used_item) + add_fingerprint(user) + current_health -= used_item.expend_attack_force(user) + healthcheck() + return ..() /obj/machinery/power/solar/proc/healthcheck() - if (src.health <= 0) + if (current_health <= 0) if(!(stat & BROKEN)) set_broken(TRUE) @@ -95,31 +104,35 @@ var/list/solars_list = list() overlays += image('icons/obj/power.dmi', icon_state = "solar_panel-b", layer = ABOVE_HUMAN_LAYER) else overlays += image('icons/obj/power.dmi', icon_state = "solar_panel", layer = ABOVE_HUMAN_LAYER) - src.set_dir(angle2dir(adir)) + set_dir(angle2dir(adir)) return -//calculates the fraction of the sunlight that the panel recieves +//calculates the fraction of the sunlight that the panel receives /obj/machinery/power/solar/proc/update_solar_exposure() - if(!GLOB.sun) + + var/datum/sun/sun = get_best_sun() + if(!sun) return if(obscured) sunfrac = 0 return //find the smaller angle between the direction the panel is facing and the direction of the sun (the sign is not important here) - var/p_angle = min(abs(adir - GLOB.sun.angle), 360 - abs(adir - GLOB.sun.angle)) + var/p_angle = min(abs(adir - sun.angle), 360 - abs(adir - sun.angle)) if(p_angle > 90) // if facing more than 90deg from sun, zero output sunfrac = 0 return sunfrac = cos(p_angle) ** 2 - //isn't the power recieved from the incoming light proportionnal to cos(p_angle) (Lambert's cosine law) rather than cos(p_angle)^2 ? + //isn't the power received from the incoming light proportionnal to cos(p_angle) (Lambert's cosine law) rather than cos(p_angle)^2 ? /obj/machinery/power/solar/Process() if(stat & BROKEN) return - if(!GLOB.sun || !control) //if there's no sun or the panel is not linked to a solar control computer, no need to proceed + + var/datum/sun/sun = get_best_sun() + if(!sun || !control) //if there's no sun or the panel is not linked to a solar control computer, no need to proceed return if(powernet) @@ -135,9 +148,9 @@ var/list/solars_list = list() /obj/machinery/power/solar/set_broken(new_state) . = ..() if(. && new_state) - health = 0 - new /obj/item/shard(src.loc) - new /obj/item/shard(src.loc) + current_health = 0 + new /obj/item/shard(loc) + new /obj/item/shard(loc) var/obj/item/solar_assembly/S = locate() in src S.glass_type = null unset_control() @@ -147,12 +160,12 @@ var/list/solars_list = list() if(. && !QDELETED(src)) if(severity == 1) if(prob(15)) - new /obj/item/shard( src.loc ) - physically_destroyed(src) + new /obj/item/shard( loc ) + physically_destroyed() else if(severity == 2) if (prob(25)) - new /obj/item/shard( src.loc ) - physically_destroyed(src) + new /obj/item/shard( loc ) + physically_destroyed() else if (prob(50)) set_broken(TRUE) else if(severity == 3 && prob(25)) @@ -173,27 +186,33 @@ var/list/solars_list = list() var/ay = y var/turf/T = null + var/datum/sun/sun = get_best_sun() + if(!sun) + obscured = TRUE + return + // On planets, we take fewer steps because the light is mostly up // Also, many planets barely have any spots with enough clear space around - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] + if(isturf(loc)) + var/obj/effect/overmap/visitable/sector/planetoid/E = global.overmap_sectors[loc.z] if(istype(E)) steps = 5 + for(var/i = 1 to steps) - ax += GLOB.sun.dx - ay += GLOB.sun.dy + ax += sun.dx + ay += sun.dy T = locate( round(ax,0.5),round(ay,0.5),z) - if(!T || T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge + if(!T || T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge break - if(T.opacity) // if we hit a solid turf, panel is obscured - obscured = 1 + if(T.opacity) // if we hit a solid turf, panel is obscured + obscured = TRUE return - obscured = 0 // if hit the edge or stepped max times, not obscured + obscured = FALSE // if hit the edge or stepped max times, not obscured update_solar_exposure() @@ -208,69 +227,60 @@ var/list/solars_list = list() icon_state = "sp_base" item_state = "electropack" w_class = ITEM_SIZE_HUGE // Pretty big! - anchored = 0 + anchored = FALSE material = /decl/material/solid/metal/steel var/tracker = 0 - var/glass_type = null - -/obj/item/solar_assembly/attack_hand(var/mob/user) - if(!anchored && isturf(loc)) // You can't pick it up - ..() + var/glass_type + var/glass_reinforced // Give back the glass type we were supplied with /obj/item/solar_assembly/proc/give_glass() if(glass_type) - var/obj/item/stack/material/S = new glass_type(src.loc) - S.amount = 2 + SSmaterials.create_object(glass_type, loc, 2, null, glass_reinforced) glass_type = null - - -/obj/item/solar_assembly/attackby(var/obj/item/W, var/mob/user) - - if(!anchored && isturf(loc)) - if(isWrench(W)) - anchored = 1 - pixel_x = 0 - pixel_y = 0 - pixel_z = 0 + glass_reinforced = null + +/obj/item/solar_assembly/attackby(var/obj/item/used_item, var/mob/user) + if(IS_WRENCH(used_item)) + if(!anchored && isturf(loc)) + anchored = TRUE + default_pixel_x = 0 + default_pixel_y = 0 + default_pixel_z = 0 + reset_offsets(0) user.visible_message("[user] wrenches the solar assembly into place.") - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - return 1 - else - if(isWrench(W)) - anchored = 0 - user.visible_message("[user] unwrenches the solar assembly from it's place.") - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - return 1 - - if(istype(W, /obj/item/stack/material) && W.get_material_type() == /decl/material/solid/glass) - var/obj/item/stack/material/S = W - if(S.use(2)) - glass_type = W.type - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) - user.visible_message("[user] places the glass on the solar assembly.") - if(tracker) - new /obj/machinery/power/tracker(get_turf(src), src) - else - new /obj/machinery/power/solar(get_turf(src), src) - else - to_chat(user, "You need two sheets of glass to put them into a solar panel.") - return - return 1 - - if(!tracker) - if(istype(W, /obj/item/tracker_electronics)) - tracker = 1 - qdel(W) - user.visible_message("[user] inserts the electronics into the solar assembly.") - return 1 - else - if(isCrowbar(W)) - new /obj/item/tracker_electronics(src.loc) - tracker = 0 - user.visible_message("[user] takes out the electronics from the solar assembly.") - return 1 - ..() + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + return TRUE + else + anchored = FALSE + user.visible_message("[user] unwrenches the solar assembly from its place.") + playsound(loc, 'sound/items/Ratchet.ogg', 75, 1) + return TRUE + else if(istype(used_item, /obj/item/stack/material) && used_item.get_material_type() == /decl/material/solid/glass) + var/obj/item/stack/material/S = used_item + if(!S.use(2)) + to_chat(user, "You need two sheets of glass to put them into a solar panel.") + return TRUE + glass_type = S.material.type + glass_reinforced = S.reinf_material?.type + playsound(loc, 'sound/machines/click.ogg', 50, 1) + user.visible_message("[user] places the glass on the solar assembly.") + if(tracker) + new /obj/machinery/power/tracker(get_turf(src), src) + else + new /obj/machinery/power/solar(get_turf(src), src) + return TRUE + if(!tracker && istype(used_item, /obj/item/tracker_electronics)) + tracker = TRUE + qdel(used_item) + user.visible_message("[user] inserts the electronics into the solar assembly.") + return TRUE + else if(IS_CROWBAR(used_item)) + new /obj/item/tracker_electronics(loc) + tracker = 0 + user.visible_message("[user] takes out the electronics from the solar assembly.") + return TRUE + return ..() // // Solar Control Computer @@ -281,14 +291,13 @@ var/list/solars_list = list() desc = "A controller for solar panel arrays." icon = 'icons/obj/computer.dmi' icon_state = "solar" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE use_power = POWER_USE_IDLE idle_power_usage = 250 construct_state = /decl/machine_construction/default/panel_closed/computer base_type = /obj/machinery/power/solar_control - frame_type = /obj/machinery/constructable_frame/computerframe - var/id = 0 + frame_type = /obj/machinery/constructable_frame/computerframe/deconstruct var/cdir = 0 var/targetdir = 0 // target angle in manual tracking (since it updates every game minute) var/gen = 0 @@ -307,7 +316,7 @@ var/list/solars_list = list() M.unset_control() if(connected_tracker) connected_tracker.unset_control() - ..() + return ..() /obj/machinery/power/solar_control/disconnect_from_network() ..() @@ -345,8 +354,9 @@ var/list/solars_list = list() if(trackrate) //we're manual tracking. If we set a rotation speed... cdir = targetdir //...the current direction is the targetted one (and rotates panels to it) if(2) // auto-tracking - if(connected_tracker) - connected_tracker.set_angle(GLOB.sun.angle) + var/datum/sun/sun = get_best_sun() + if(connected_tracker && sun) + connected_tracker.set_angle(sun.angle) set_panels(cdir) updateDialog() @@ -359,17 +369,11 @@ var/list/solars_list = list() /obj/machinery/power/solar_control/on_update_icon() if(stat & BROKEN) icon_state = "broken" - overlays.Cut() return if(stat & NOPOWER) icon_state = "c_unpowered" - overlays.Cut() return icon_state = "solar" - overlays.Cut() - if(cdir > -1) - overlays += image('icons/obj/computer.dmi', "solcon-o", ABOVE_OBJ_LAYER, angle2dir(cdir)) - return /obj/machinery/power/solar_control/interface_interact(mob/user) interact(user) @@ -377,29 +381,30 @@ var/list/solars_list = list() /obj/machinery/power/solar_control/interact(mob/user) + var/datum/sun/sun = get_best_sun() var/t = "Generated power : [round(lastgen)] W
    " - t += "Star Orientation: [GLOB.sun.angle]° ([angle2text(GLOB.sun.angle)])
    " + t += "Star Orientation: [sun?.angle || 0]° ([angle2text(sun?.angle || 0)])
    " t += "Array Orientation: [rate_control(src,"cdir","[cdir]°",1,15)] ([angle2text(cdir)])
    " t += "Tracking:
    " switch(track) if(0) - t += "Off Timed Auto
    " + t += "Off Timed Auto
    " if(1) - t += "Off Timed Auto
    " + t += "Off Timed Auto
    " if(2) - t += "Off Timed Auto
    " + t += "Off Timed Auto
    " t += "Tracking Rate: [rate_control(src,"tdir","[trackrate] deg/h ([trackrate<0 ? "CCW" : "CW"])",1,30,180)]

    " t += "Connected devices:
    " - t += "Search for devices
    " + t += "Search for devices
    " t += "Solar panels : [connected_panels.len] connected
    " t += "Solar tracker : [connected_tracker ? "Found" : "Not found"]

    " - t += "Close" + t += "Close" - var/datum/browser/written/popup = new(user, "solar", name) + var/datum/browser/written_digital/popup = new(user, "solar", name) popup.set_content(t) popup.open() @@ -422,46 +427,48 @@ var/list/solars_list = list() updateDialog() /obj/machinery/power/solar_control/Topic(href, href_list) - if(..()) - close_browser(usr, "window=solcon") - usr.unset_machine() - return 0 - if(href_list["close"] ) + . = ..() + if(. == TOPIC_CLOSE) close_browser(usr, "window=solcon") - usr.unset_machine() - return 0 + +/obj/machinery/power/solar_control/OnTopic(mob/user, href_list) + if((. = ..())) + return + if(href_list["close"]) + return TOPIC_CLOSE if(href_list["rate control"]) if(href_list["cdir"]) - src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360) - src.targetdir = src.cdir + cdir = clamp((360+cdir+text2num(href_list["cdir"]))%360, 0, 359) + targetdir = cdir if(track == 2) //manual update, so losing auto-tracking track = 0 - spawn(1) - set_panels(cdir) + addtimer(CALLBACK(src, PROC_REF(set_panels), cdir), 1) if(href_list["tdir"]) - src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"])) - if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) + trackrate = clamp(trackrate+text2num(href_list["tdir"]), -7200, 7200) + if(trackrate) nexttime = world.time + 36000/abs(trackrate) + return TOPIC_REFRESH if(href_list["track"]) track = text2num(href_list["track"]) if(track == 2) - if(connected_tracker) - connected_tracker.set_angle(GLOB.sun.angle) + var/datum/sun/sun = get_best_sun() + if(connected_tracker && sun) + connected_tracker.set_angle(sun.angle) set_panels(cdir) else if (track == 1) //begin manual tracking - src.targetdir = src.cdir - if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) + targetdir = cdir + if(trackrate) nexttime = world.time + 36000/abs(trackrate) set_panels(targetdir) + return TOPIC_REFRESH if(href_list["search_connected"]) - src.search_for_connected() - if(connected_tracker && track == 2) - connected_tracker.set_angle(GLOB.sun.angle) - src.set_panels(cdir) - - interact(usr) - return 1 + search_for_connected() + var/datum/sun/sun = get_best_sun() + if(connected_tracker && track == 2 && sun) + connected_tracker.set_angle(sun.angle) + set_panels(cdir) + return TOPIC_REFRESH //rotates the panel to the passed angle /obj/machinery/power/solar_control/proc/set_panels(var/cdir) @@ -485,8 +492,9 @@ var/list/solars_list = list() /obj/machinery/power/solar_control/autostart/Initialize() search_for_connected() - if(connected_tracker && track == 2) - connected_tracker.set_angle(GLOB.sun.angle) + var/datum/sun/sun = get_best_sun() + if(connected_tracker && track == 2 && sun) + connected_tracker.set_angle(sun.angle) set_panels(cdir) . = ..() @@ -496,10 +504,10 @@ var/list/solars_list = list() /obj/item/paper/solar name = "paper- 'Going green! Setup your own solar array instructions.'" - info = "

    Welcome

    At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuels! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.

    You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!

    Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the GLOB.sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the GLOB.sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.

    Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.

    That's all to it, be safe, be green!

    " + info = "

    Welcome

    At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuels! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.

    You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!

    Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.

    Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.

    That's all to it, be safe, be green!

    " /proc/rate_control(var/S, var/V, var/C, var/Min=1, var/Max=5, var/Limit=null) //How not to name vars - var/href = "-"+rate+"[href]=[Limit]'>+" return rate diff --git a/code/modules/power/stirling.dm b/code/modules/power/stirling.dm new file mode 100644 index 000000000000..bc329ce9e5cc --- /dev/null +++ b/code/modules/power/stirling.dm @@ -0,0 +1,240 @@ +#define HEAT_TRANSFER 300 +#define MAX_FREQUENCY 60 +#define MIN_DELTA_T 5 + +/obj/machinery/atmospherics/binary/stirling + name = "stirling engine" + desc = "A mechanical stirling generator. It generates power dependent on the temperature differential between two gas lines." + icon = 'icons/obj/power.dmi' + icon_state = "stirling" + density = TRUE + anchored = TRUE + layer = STRUCTURE_LAYER + base_type = /obj/machinery/atmospherics/binary/stirling + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = NOSCREEN | NOINPUT | NOPOWER // Mechanical machine and display. + connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL + + var/obj/item/tank/stirling/inserted_cylinder + + var/cycle_frequency = MAX_FREQUENCY/2 + var/active = FALSE + + var/max_power = 150000 + var/genlev = 0 + var/last_genlev + + var/last_gen = 0 + var/skipped_cycle = FALSE + + var/sound_id + var/datum/sound_token/sound_token + +/obj/machinery/atmospherics/binary/stirling/Destroy() + QDEL_NULL(inserted_cylinder) + QDEL_NULL(sound_token) + . = ..() + +/obj/machinery/atmospherics/binary/stirling/Process() + ..() + + if(!active) + return + + var/line1_heatcap = air1.heat_capacity() + var/line2_heatcap = air2.heat_capacity() + + if(!(line1_heatcap + line2_heatcap)) + return + + var/delta_t = air1.temperature - air2.temperature + + // Absolute value of the heat transfer required to bring both lines in equilibrium. + var/line_equilibrium_heat = ((line1_heatcap*line2_heatcap)/(line1_heatcap + line2_heatcap))*abs(delta_t) + + // Some passive equilibrium between the lines. + var/passive_heat_transfer = min(HEAT_TRANSFER*abs(delta_t), line_equilibrium_heat) + + air1.add_thermal_energy(-(SIGN(delta_t))*passive_heat_transfer) + air2.add_thermal_energy( (SIGN(delta_t))*passive_heat_transfer) + + if(!istype(inserted_cylinder)) + return + if(!active) + return + + var/datum/gas_mixture/working_volume = inserted_cylinder.air_contents + + if((stat & BROKEN) || !air1.total_moles || !air2.total_moles || !working_volume?.total_moles || !working_volume?.return_pressure()) + stop_engine() + return + + // A rough approximation of a Stirling cycle with perfect regeneration e.g. Carnot efficiency. + var/working_heatcap = working_volume.heat_capacity() + + // Bring the internal tank in thermal equilibrium with the hottest line. The temperature/pressure + // is kept at the maximum constantly. + var/equil_transfer + + if(air1.temperature >= air2.temperature) + equil_transfer = (working_heatcap*line1_heatcap)/(working_heatcap + line1_heatcap)*(air1.temperature - working_volume.temperature) + air1.add_thermal_energy(-equil_transfer) + else + equil_transfer = (working_heatcap*line2_heatcap)/(working_heatcap + line2_heatcap)*(air2.temperature - working_volume.temperature) + air2.add_thermal_energy(-equil_transfer) + + working_volume.add_thermal_energy(equil_transfer) + + // Redefine in case there was a change from passive heat transfer. + delta_t = air1.temperature - air2.temperature + line_equilibrium_heat = ((line1_heatcap*line2_heatcap)/(line1_heatcap + line2_heatcap))*abs(delta_t) + + // The cycle requires a minimum temperature to overcome friction. + if(abs(delta_t) < MIN_DELTA_T) + if(skipped_cycle) // Allow some leeway since networks can take some time to update. + stop_engine() + skipped_cycle = TRUE + return + skipped_cycle = FALSE + + // Positive/negative work from volume expansion/compression. Maximum volume is 1.5 tank volume. The volume of the tank is not actually adjusted. + var/work_coefficient = working_volume.get_total_moles()*R_IDEAL_GAS_EQUATION*log(1.5) + + // Direction of heat flow, 1 for air1 -> air 2, -1 for air2 -> air 1 + var/heat_dir = SIGN(delta_t) + + // We multiply by the cycle frequency to get reasonable values for power generation. + // Energy is still conserved, but the efficiency of the engine is slightly overestimated. + + // The hot line and cold line will not receive or give more than the heat required to reach equilibrium. + var/air1_dq = -heat_dir*min(work_coefficient*air1.temperature*cycle_frequency, line_equilibrium_heat) + var/air2_dq = heat_dir*min(work_coefficient*air2.temperature*cycle_frequency, line_equilibrium_heat) + + var/work_done = -(air1_dq + air2_dq) + + var/power_generated = 0.75*work_done + // Excessive power is transferred as heat to the cooler side, reducing efficiency. + if(power_generated > max_power) + if(heat_dir == 1) + air2_dq += 0.85*(max_power - power_generated) + else + air1_dq += 0.85*(max_power - power_generated) + power_generated = max_power + if(prob(5)) + spark_at(src, cardinal_only = TRUE) + + generate_power(power_generated) + last_gen = power_generated + genlev = max(0, min(round(4*power_generated / max_power), 4)) + if(genlev != last_genlev) + update_icon() + update_sound() + last_genlev = genlev + update_networks() + +/obj/machinery/atmospherics/binary/stirling/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + if(active) + . += "\The [src] is generating [round(last_gen/1000, 0.1)] kW" + if(!inserted_cylinder) + . += "There is no piston cylinder inserted into \the [src]." + +/obj/machinery/atmospherics/binary/stirling/attackby(var/obj/item/used_item, var/mob/user) + if((istype(used_item, /obj/item/tank/stirling))) + if(inserted_cylinder) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, SPAN_NOTICE("You insert \the [used_item] into \the [src].")) + inserted_cylinder = used_item + update_icon() + return TRUE + + if(!panel_open) + if(IS_CROWBAR(used_item) && inserted_cylinder) + inserted_cylinder.dropInto(get_turf(src)) + to_chat(user, SPAN_NOTICE("You remove \the [inserted_cylinder] from \the [src].")) + inserted_cylinder = null + stop_engine() + return TRUE + + if(IS_WRENCH(used_item)) + var/target_frequency = input(user, "Enter the cycle frequency you would like \the [src] to operate at ([MAX_FREQUENCY/4] - [MAX_FREQUENCY] Hz)", "Stirling Frequency", cycle_frequency) as num | null + if(!CanPhysicallyInteract(user) || !target_frequency) + return TRUE + cycle_frequency = round(clamp(target_frequency, MAX_FREQUENCY/4, MAX_FREQUENCY)) + to_chat(user, SPAN_NOTICE("You adjust \the [src] to operate at a frequency of [cycle_frequency] Hz.")) + return TRUE + + . = ..() + +/obj/machinery/atmospherics/binary/stirling/physical_attack_hand(mob/user) + + if((stat & BROKEN) || active || panel_open) + return ..() + + if(!inserted_cylinder) + to_chat(user, SPAN_WARNING("You must insert a stirling piston cylinder into \the [src] before you can start it!")) + return TRUE + to_chat(user, "You start trying to manually rev up \the [src].") + if(do_after(user, 2 SECONDS, src) && !active && inserted_cylinder && !(stat & BROKEN)) + visible_message("[user] pulls on the starting cord of \the [src], revving it up!", "You pull on the starting cord of \the [src], revving it up!") + playsound(src.loc, 'sound/machines/engine.ogg', 35, 1) + active = TRUE + return TRUE + +/obj/machinery/atmospherics/binary/stirling/on_update_icon() + cut_overlays() + if (stat & (BROKEN)) + return + if (genlev != 0) + add_overlay(emissive_overlay('icons/obj/power.dmi', "stirling-op[genlev]")) + +/obj/machinery/atmospherics/binary/stirling/proc/update_sound() + if(!sound_id) + sound_id = "[type]_[sequential_id(/obj/machinery/atmospherics/binary/stirling)]" + if(active) + var/work_volume = 10 + 15*genlev + if(!sound_token) + sound_token = play_looping_sound(src, sound_id, 'sound/machines/engine.ogg', volume = work_volume) + sound_token.SetVolume(work_volume) + else if(sound_token) + QDEL_NULL(sound_token) + +/obj/machinery/atmospherics/binary/stirling/proc/stop_engine() + skipped_cycle = FALSE + if(active) + visible_message(SPAN_WARNING("\The [src] sputters to a violent halt!")) + active = FALSE + update_sound() + update_icon() + +/obj/machinery/atmospherics/binary/stirling/dismantle() + if(inserted_cylinder) + inserted_cylinder.dropInto(get_turf(src)) + . = ..() + +/obj/item/tank/stirling + name = "stirling piston cylinder" + desc = "A piston cylinder designed for use in a stirling engine. It must be charged with gas before it can be used." + icon = 'icons/obj/items/tanks/tank_stirling.dmi' + gauge_icon = null + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = null + starting_pressure = list(/decl/material/gas/hydrogen = 2 ATM) + + gas_volume = 30 + failure_temp = 1000 + +/obj/item/tank/stirling/Initialize() + . = ..() + desc += " It's rated for temperatures up to [failure_temp] C." + +/obj/item/tank/stirling/empty + starting_pressure = list() + +#undef HEAT_TRANSFER +#undef MAX_FREQUENCY +#undef MIN_DELTA_T \ No newline at end of file diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm index addffd960bdf..7e6227927a0c 100644 --- a/code/modules/power/terminal.dm +++ b/code/modules/power/terminal.dm @@ -7,18 +7,60 @@ name = "terminal" icon_state = "term" desc = "It's an underfloor wiring terminal for power equipment." - level = 1 + level = LEVEL_BELOW_PLATING layer = EXPOSED_WIRE_TERMINAL_LAYER var/obj/item/stock_parts/power/terminal/master - anchored = 1 + anchored = TRUE + stat_immune = NOINPUT | NOSCREEN | NOPOWER + interact_offline = TRUE uncreated_component_parts = null - construct_state = /decl/machine_construction/noninteractive // Axiliary entity; all interactions pass through owner machine part instead. + construct_state = /decl/machine_construction/noninteractive/terminal // Auxiliary entity; all interactions pass through owner machine part instead. /obj/machinery/power/terminal/Initialize() . = ..() var/turf/T = src.loc - if(level==1) hide(!T.is_plating()) + if(level == LEVEL_BELOW_PLATING && isturf(T)) + hide(!T.is_plating()) + +/obj/machinery/power/terminal/Destroy() + master = null + . = ..() + +/obj/machinery/power/terminal/attackby(obj/item/used_item, mob/user) + if(IS_WIRECUTTER(used_item)) + var/turf/T = get_turf(src) + var/obj/machinery/machine = master_machine() + + if(istype(T) && !T.is_plating()) + to_chat(user, SPAN_WARNING("You must remove the floor plating in front of \the [machine] first!")) + return TRUE + + // If this is a terminal that's somehow been left behind, let it be removed freely. + if(machine && !machine.components_are_accessible(/obj/item/stock_parts/power/terminal)) + to_chat(user, SPAN_WARNING("You must open the panel on \the [machine] first!")) + return TRUE + + user.visible_message(SPAN_WARNING("\The [user] dismantles the power terminal from \the [machine]."), \ + "You begin to cut the cables...") + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + if(do_after(user, 50, src)) + if(!QDELETED(src) && (!master || !machine || machine.components_are_accessible(/obj/item/stock_parts/power/terminal))) + if (prob(50) && electrocute_mob(user, powernet, src)) + spark_at(machine, amount=5, cardinal_only = TRUE) + if(HAS_STATUS(user, STAT_STUN)) + return TRUE + new /obj/item/stack/cable_coil(T, 10) + to_chat(user, SPAN_NOTICE("You cut the cables and dismantle the power terminal.")) + qdel_self() + return TRUE + . = ..() + +/obj/machinery/power/terminal/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/obj/machinery/machine = master_machine() + if(machine) + . += "It is attached to \the [machine]." /obj/machinery/power/terminal/proc/master_machine() var/obj/machinery/machine = master && master.loc @@ -26,7 +68,7 @@ return machine /obj/machinery/power/terminal/hide(var/do_hide) - if(do_hide && level == 1) + if(do_hide && level == LEVEL_BELOW_PLATING) layer = WIRE_TERMINAL_LAYER else reset_plane_and_layer() @@ -41,4 +83,15 @@ . = ..() var/obj/machinery/machine = master_machine() if(machine) - machine.power_change() \ No newline at end of file + machine.power_change() + +/obj/machinery/power/terminal/on_update_icon() + . = ..() + if(master) + var/obj/machinery/machine = master_machine() + + // Wall frames and SMES have directional terminals. + if(!master.terminal_dir && !ispath(machine.frame_type, /obj/item/frame) && machine.loc == loc) + icon_state = "term-omni" + else + icon_state = "term" \ No newline at end of file diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm index 9e42f5e92428..b6f3bfb0274d 100644 --- a/code/modules/power/tracker.dm +++ b/code/modules/power/tracker.dm @@ -8,10 +8,9 @@ desc = "A solar directional tracker." icon = 'icons/obj/power.dmi' icon_state = "tracker" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE - var/id = 0 var/sun_angle = 0 // sun angle as set by sun datum var/obj/machinery/power/solar_control/control = null @@ -40,9 +39,9 @@ /obj/machinery/power/tracker/proc/Make(var/obj/item/solar_assembly/S) if(!S) S = new /obj/item/solar_assembly(src) - S.glass_type = /obj/item/stack/material/glass + S.glass_type = /decl/material/solid/glass S.tracker = 1 - S.anchored = 1 + S.anchored = TRUE S.forceMove(src) update_icon() @@ -56,27 +55,29 @@ if(powernet && (powernet == control.powernet)) //update if we're still in the same powernet control.cdir = angle -/obj/machinery/power/tracker/attackby(var/obj/item/W, var/mob/user) +/obj/machinery/power/tracker/attackby(var/obj/item/used_item, var/mob/user) - if(isCrowbar(W)) + if(IS_CROWBAR(used_item)) playsound(src.loc, 'sound/machines/click.ogg', 50, 1) user.visible_message("[user] begins to take the glass off the solar tracker.") - if(do_after(user, 50,src)) - var/obj/item/solar_assembly/S = locate() in src - if(S) - S.dropInto(loc) - S.give_glass() - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - user.visible_message("[user] takes the glass off the tracker.") - qdel(src) - return - ..() + if(!do_after(user, 5 SECONDS, src)) + return TRUE + var/obj/item/solar_assembly/S = locate() in src + if(S) + S.dropInto(loc) + S.give_glass() + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + user.visible_message("[user] takes the glass off the tracker.") + qdel(src) + return TRUE + return ..() // Tracker Electronic /obj/item/tracker_electronics - name = "tracker electronics" + name = "solar tracker electronics" icon = 'icons/obj/doors/door_assembly.dmi' icon_state = "door_electronics" w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/fiberglass \ No newline at end of file diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm index 3354c690e6af..aa6c612f55b0 100644 --- a/code/modules/power/turbine.dm +++ b/code/modules/power/turbine.dm @@ -3,11 +3,11 @@ desc = "The compressor stage of a gas turbine generator." icon = 'icons/obj/pipes.dmi' icon_state = "compressor" - anchored = 1 - density = 1 - var/obj/machinery/power/turbine/turbine + anchored = TRUE + density = TRUE + var/obj/machinery/turbine/turbine var/datum/gas_mixture/gas_contained - var/turf/simulated/inturf + var/turf/inturf var/starter = 0 var/rpm = 0 var/rpmtarget = 0 @@ -17,15 +17,15 @@ uncreated_component_parts = null construct_state = /decl/machine_construction/default/panel_closed -/obj/machinery/power/turbine +/obj/machinery/turbine name = "gas turbine generator" desc = "A gas turbine used for backup power generation." icon = 'icons/obj/pipes.dmi' icon_state = "turbine" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/obj/machinery/compressor/compressor - var/turf/simulated/outturf + var/turf/outturf var/lastgen uncreated_component_parts = null @@ -38,8 +38,8 @@ icon = 'icons/obj/computer.dmi' icon_keyboard = "tech_key" icon_screen = "turbinecomp" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/obj/machinery/compressor/compressor var/list/obj/machinery/door/blast/doors var/door_status = 0 @@ -103,17 +103,17 @@ overlays += image('icons/obj/pipes.dmi', "comp-o1", FLY_LAYER) //TODO: DEFERRED -/obj/machinery/power/turbine/Initialize() +/obj/machinery/turbine/Initialize() ..() outturf = get_step(src, dir) return INITIALIZE_HINT_LATELOAD -/obj/machinery/power/turbine/LateInitialize() +/obj/machinery/turbine/LateInitialize() ..() if(!compressor) // It should have found us and subscribed. set_broken(TRUE) -/obj/machinery/power/turbine/Destroy() +/obj/machinery/turbine/Destroy() if(compressor) compressor.turbine = null compressor.set_broken(TRUE) @@ -124,15 +124,15 @@ #define TURBGENQ 20000 #define TURBGENG 0.8 -/obj/machinery/power/turbine/Process() - if(!compressor.starter) +/obj/machinery/turbine/Process() + if(!compressor?.starter) return overlays.Cut() if(stat & BROKEN) return lastgen = ((compressor.rpm / TURBGENQ)**TURBGENG) *TURBGENQ - add_avail(lastgen) + generate_power(lastgen) var/newrpm = ((compressor.gas_contained.temperature) * compressor.gas_contained.total_moles)/4 newrpm = max(0, newrpm) @@ -153,9 +153,9 @@ src.interact(M) AutoUpdateAI(src) -/obj/machinery/power/turbine/interact(mob/user) +/obj/machinery/turbine/interact(mob/user) - if ( (get_dist(src, user) > 1 ) || (stat & (NOPOWER|BROKEN)) && (!istype(user, /mob/living/silicon/ai)) ) + if ( (get_dist(src, user) > 1 ) || (stat & (NOPOWER|BROKEN)) && (!isAI(user)) ) user.machine = null close_browser(user, "window=turbine") return @@ -168,9 +168,9 @@ t += "Turbine: [round(compressor.rpm)] RPM
    " - t += "Starter: [ compressor.starter ? "Off On" : "Off On"]" + t += "Starter: [ compressor.starter ? "Off On" : "Off On"]" - t += "
    Close" + t += "
    Close" t += "" show_browser(user, t, "window=turbine") @@ -178,14 +178,14 @@ return -/obj/machinery/power/turbine/CanUseTopic(var/mob/user, href_list) +/obj/machinery/turbine/CanUseTopic(var/mob/user, href_list) if(!user.check_dexterity(DEXTERITY_KEYBOARDS)) return min(..(), STATUS_UPDATE) return ..() -/obj/machinery/power/turbine/OnTopic(user, href_list) +/obj/machinery/turbine/OnTopic(user, href_list) if(href_list["close"]) - close_browser(usr, "window=turbine") + close_browser(user, "window=turbine") return TOPIC_HANDLED if(href_list["str"]) @@ -225,14 +225,14 @@ var/dat if(src.compressor) dat += {"
    Gas turbine remote control system
    - \nTurbine status: [ src.compressor.starter ? "Off On" : "Off On"] + \nTurbine status: [ src.compressor.starter ? "Off On" : "Off On"] \n
    \nTurbine speed: [src.compressor.rpm]rpm
    \nPower currently being generated: [src.compressor.turbine.lastgen]W
    \nInternal gas temperature: [src.compressor.gas_contained.temperature]K
    - \nVent doors: [ src.door_status ? "Closed Open" : "Closed Open"] - \n
    View - \n
    Close + \nVent doors: [ src.door_status ? "Closed Open" : "Closed Open"] + \n
    View + \n
    Close \n
    \n"} else @@ -244,9 +244,9 @@ -/obj/machinery/computer/turbine_computer/OnTopic(user, href_list) +/obj/machinery/computer/turbine_computer/OnTopic(mob/user, href_list) if( href_list["view"] ) - usr.client.eye = src.compressor + user.client.eye = src.compressor . = TOPIC_HANDLED else if( href_list["str"] ) src.compressor.starter = !src.compressor.starter diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index b2b2d6569838..76e6fe93677a 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -1,22 +1,36 @@ /obj/item/ammo_casing name = "bullet casing" desc = "A bullet casing." - icon = 'icons/obj/ammo.dmi' - icon_state = "pistolcasing" + icon = 'icons/obj/ammo/casings/pistol.dmi' + icon_state = ICON_STATE_WORLD + "-preview" randpixel = 10 - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT | SLOT_EARS - throwforce = 1 + obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_HOLLOW + slot_flags = SLOT_LOWER_BODY | SLOT_EARS w_class = ITEM_SIZE_TINY + color = /decl/material/solid/metal/brass::color // mapping preview color + material = /decl/material/solid/metal/brass + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + drop_sound = list( + 'sound/weapons/guns/casingfall1.ogg', + 'sound/weapons/guns/casingfall2.ogg', + 'sound/weapons/guns/casingfall3.ogg' + ) - var/leaves_residue = 1 + var/leaves_residue = TRUE var/caliber = "" //Which kind of guns it can be loaded into var/projectile_type //The bullet type to create when New() is called var/obj/item/projectile/BB = null //The loaded bullet - make it so that the projectiles are created only when needed? - var/spent_icon = "pistolcasing-spent" var/bullet_color = COLOR_COPPER var/marking_color - var/fall_sounds = list('sound/weapons/guns/casingfall1.ogg','sound/weapons/guns/casingfall2.ogg','sound/weapons/guns/casingfall3.ogg') + +/obj/item/ammo_casing/get_contained_external_atoms() + . = ..() + if(. && BB) + LAZYREMOVE(., BB) + +/obj/item/ammo_casing/spent/Initialize() + . = ..() + expend() /obj/item/ammo_casing/Initialize() if(ispath(projectile_type)) @@ -24,38 +38,50 @@ if(caliber && istype(BB, /obj/item/projectile/bullet)) var/obj/item/projectile/bullet/B = BB B.caliber = caliber - if(randpixel) - pixel_x = rand(-randpixel, randpixel) - pixel_y = rand(-randpixel, randpixel) . = ..() +/obj/item/ammo_casing/Destroy() + QDEL_NULL(BB) + return ..() + //removes the projectile from the ammo casing /obj/item/ammo_casing/proc/expend() . = BB BB = null - set_dir(pick(GLOB.alldirs)) //spin spent casings - + set_dir(pick(global.alldirs)) //spin spent casings // Aurora forensics port, gunpowder residue. if(leaves_residue) leave_residue() - update_icon() + update_name() + +/obj/item/ammo_casing/Crossed(atom/movable/AM) + ..() + if(!isliving(AM)) + return + + var/mob/living/L = AM + if(L.buckled || MOVING_DELIBERATELY(L) || prob(90)) + return + + playsound(src, pick(drop_sound), 50, 1) + var/turf/turf_current = get_turf(src) + var/turf/turf_destiinaton = get_step(turf_current, AM.dir) + if(turf_destiinaton.Adjacent(turf_current)) + throw_at(turf_destiinaton, 2, 2, spin = FALSE) + animate(src, pixel_x = rand(-16, 16), pixel_y = rand(-16, 16), transform = turn(matrix(), rand(120, 300)), time = rand(3, 8)) /obj/item/ammo_casing/proc/leave_residue() - var/mob/living/carbon/human/H = get_holder_of_type(src, /mob/living/carbon/human) - var/obj/item/gun/G = get_holder_of_type(src, /obj/item/gun) - put_residue_on(G) - if(H) - var/zone - if(H.l_hand == G) - zone = BP_L_HAND - else if(H.r_hand == G) - zone = BP_R_HAND - if(zone) - var/target = H.get_covering_equipped_item_by_zone(zone) - if(!target) - target = H.get_organ(zone) - put_residue_on(target) + var/obj/item/gun/G = get_recursive_loc_of_type(/obj/item/gun) + if(G) + put_residue_on(G) + var/mob/living/human/H = G.get_recursive_loc_of_type(/mob/living/human) + if(H) + var/holding_slot = H.get_held_slot_for_item(G) + if(holding_slot) + var/target = H.get_covering_equipped_item_by_zone(holding_slot) || GET_EXTERNAL_ORGAN(H, holding_slot) + if(target) + put_residue_on(target) if(prob(30)) put_residue_on(get_turf(src)) @@ -64,44 +90,52 @@ var/datum/extension/forensic_evidence/forensics = get_or_create_extension(A, /datum/extension/forensic_evidence) forensics.add_from_atom(/datum/forensics/gunshot_residue, src) -/obj/item/ammo_casing/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) - if(!BB) - to_chat(user, "There is no bullet in the casing to inscribe anything into.") - return - - var/tmp_label = "" - var/label_text = sanitizeSafe(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), MAX_NAME_LEN) - if(length(label_text) > 20) - to_chat(user, "The inscription can be at most 20 characters long.") - else if(!label_text) - to_chat(user, "You scratch the inscription off of [initial(BB)].") - BB.SetName(initial(BB.name)) - else - to_chat(user, "You inscribe \"[label_text]\" into \the [initial(BB.name)].") - BB.SetName("[initial(BB.name)] (\"[label_text]\")") - else ..() +/obj/item/ammo_casing/attackby(obj/item/used_item, mob/user) + if(!IS_SCREWDRIVER(used_item)) + return ..() + if(!BB) + to_chat(user, "There is no bullet in the casing to inscribe anything into.") + return TRUE + + var/tmp_label = "" + var/label_text = sanitize_safe(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), MAX_NAME_LEN) + if(length(label_text) > 20) + to_chat(user, "The inscription can be at most 20 characters long.") + else if(!label_text) + to_chat(user, "You scratch the inscription off of [initial(BB)].") + BB.SetName(initial(BB.name)) + else + to_chat(user, "You inscribe \"[label_text]\" into \the [initial(BB.name)].") + BB.SetName("[initial(BB.name)] (\"[label_text]\")") + return TRUE + +// This is separate because on_update_icon() needs to call parent, +// and shells need to override this. +/obj/item/ammo_casing/proc/update_casing_icon() + if(BB) + var/image/I = overlay_image(icon, "[icon_state]-bullet", bullet_color, flags=RESET_COLOR) + I.dir = dir // don't overlays inherit dir already? is this needed? + add_overlay(I) + if(marking_color) + var/image/I = overlay_image(icon, "[icon_state]-marking", marking_color, flags=RESET_COLOR) + I.dir = dir + add_overlay(I) /obj/item/ammo_casing/on_update_icon() - if(use_single_icon) - cut_overlays() - if(BB) - var/image/I = overlay_image(icon, "[icon_state]-bullet", bullet_color, flags=RESET_COLOR) - I.dir = dir - add_overlay(I) - if(marking_color) - var/image/I = overlay_image(icon, "[icon_state]-marking", marking_color, flags=RESET_COLOR) - I.dir = dir - add_overlay(I) - else if(spent_icon && !BB) - icon_state = spent_icon - -/obj/item/ammo_casing/examine(mob/user) + . = ..() + update_casing_icon() + +/obj/item/ammo_casing/update_name() + . = ..() + if(!BB) + SetName("spent [name]") + +/obj/item/ammo_casing/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(caliber) - to_chat(user, "Its caliber is [caliber].") + . += "Its caliber is [caliber]." if (!BB) - to_chat(user, "This one is spent.") + . += "This one is spent." //An item that holds casings and can be used to put them inside guns /obj/item/ammo_magazine @@ -110,10 +144,9 @@ icon_state = "357" icon = 'icons/obj/ammo.dmi' obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY item_state = "syringe_kit" material = /decl/material/solid/metal/steel - throwforce = 5 w_class = ITEM_SIZE_SMALL throw_speed = 4 throw_range = 10 @@ -132,9 +165,36 @@ var/list/icon_keys = list() //keys var/list/ammo_states = list() //values + /// Determines whether or not we wait until the first time our contents are gotten to initialize contents. May lead to icon bugs if not handled delicately. + var/lazyload_contents = TRUE + /// Whether or not our contents have been initialized or not, used in lazyloaded contents. + var/contents_initialized = FALSE + /obj/item/ammo_magazine/box w_class = ITEM_SIZE_NORMAL +/obj/item/ammo_magazine/proc/create_initial_contents() + if(contents_initialized || !initial_ammo || !ammo_type) + return + for(var/i in 1 to initial_ammo) + stored_ammo += new ammo_type(src) + contents_initialized = TRUE + +/obj/item/ammo_magazine/get_contained_matter(include_reagents = TRUE) + . = ..() + if(!lazyload_contents || contents_initialized || !ammo_type || !initial_ammo) + return + // Add our expected matter from lazyloaded stuff. + var/list/ammo_matter = atom_info_repository.get_matter_for(ammo_type).Copy() + for(var/matter_entry in ammo_matter) + ammo_matter[matter_entry] *= initial_ammo + . = MERGE_ASSOCS_WITH_NUM_VALUES(., ammo_matter) + +/obj/item/ammo_magazine/proc/get_stored_ammo_count() + . = length(stored_ammo) + if(!contents_initialized) + . += initial_ammo + /obj/item/ammo_magazine/Initialize() . = ..() if(multiple_sprites) @@ -143,74 +203,82 @@ if(isnull(initial_ammo)) initial_ammo = max_ammo - if(initial_ammo) - for(var/i in 1 to initial_ammo) - stored_ammo += new ammo_type(src) + if(!lazyload_contents) + create_initial_contents() if(caliber) LAZYINSERT(labels, caliber, 1) if(LAZYLEN(labels)) SetName("[name] ([english_list(labels, and_text = ", ")])") update_icon() -/obj/item/ammo_magazine/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/ammo_casing)) - var/obj/item/ammo_casing/C = W - if(C.caliber != caliber) - to_chat(user, "[C] does not fit into [src].") - return - if(stored_ammo.len >= max_ammo) - to_chat(user, "[src] is full!") - return - if(!user.unEquip(C, src)) - return - stored_ammo.Add(C) - update_icon() - else ..() +/obj/item/ammo_magazine/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/ammo_casing)) + return ..() + var/obj/item/ammo_casing/C = used_item + if(C.caliber != caliber) + to_chat(user, "[C] does not fit into [src].") + return TRUE + if(get_stored_ammo_count() >= max_ammo) + to_chat(user, "[src] is full!") + return TRUE + if(!user.try_unequip(C, src)) + return TRUE + stored_ammo.Add(C) + playsound(user, 'sound/weapons/guns/interaction/bullet_insert.ogg', 50, 1) + update_icon() + return TRUE /obj/item/ammo_magazine/attack_self(mob/user) - if(!stored_ammo.len) - to_chat(user, "[src] is already empty!") + if(!get_stored_ammo_count()) + to_chat(user, SPAN_NOTICE("[src] is already empty!")) return - to_chat(user, "You empty [src].") + to_chat(user, SPAN_NOTICE("You empty [src].")) + create_initial_contents() for(var/obj/item/ammo_casing/C in stored_ammo) C.forceMove(user.loc) - C.set_dir(pick(GLOB.alldirs)) + C.set_dir(pick(global.alldirs)) stored_ammo.Cut() update_icon() /obj/item/ammo_magazine/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - if(!stored_ammo.len) - to_chat(user, "[src] is already empty!") - else - var/obj/item/ammo_casing/C = stored_ammo[stored_ammo.len] - stored_ammo-=C - user.put_in_hands(C) - user.visible_message("\The [user] removes \a [C] from [src].", "You remove \a [C] from [src].") - update_icon() - else - ..() - return + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(!get_stored_ammo_count()) + to_chat(user, SPAN_NOTICE("\The [src] is already empty!")) + return TRUE + create_initial_contents() + var/obj/item/ammo_casing/C = stored_ammo[stored_ammo.len] + stored_ammo -= C + user.put_in_hands(C) + user.visible_message( + "\The [user] removes \a [C] from [src].", + SPAN_NOTICE("You remove \a [C] from [src].") + ) + update_icon() + return TRUE /obj/item/ammo_magazine/on_update_icon() + . = ..() if(multiple_sprites) - //find the lowest key greater than or equal to stored_ammo.len + //find the lowest key greater than or equal to our ammo count var/new_state = null + var/self_ammo_count = get_stored_ammo_count() for(var/idx in 1 to icon_keys.len) - var/ammo_count = icon_keys[idx] - if (ammo_count >= stored_ammo.len) + var/icon_ammo_count = icon_keys[idx] + if (icon_ammo_count >= self_ammo_count) new_state = ammo_states[idx] break icon_state = (new_state)? new_state : initial(icon_state) -/obj/item/ammo_magazine/examine(mob/user) +/obj/item/ammo_magazine/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "There [(stored_ammo.len == 1)? "is" : "are"] [stored_ammo.len] round\s left!") + var/self_ammo_count = get_stored_ammo_count() + . += "There [(self_ammo_count == 1)? "is" : "are"] [self_ammo_count] round\s left!" //magazine icon state caching -/var/global/list/magazine_icondata_keys = list() -/var/global/list/magazine_icondata_states = list() +var/global/list/magazine_icondata_keys = list() +var/global/list/magazine_icondata_states = list() /proc/initialize_magazine_icondata(var/obj/item/ammo_magazine/M) var/typestr = "[M.type]" @@ -223,10 +291,9 @@ /proc/magazine_icondata_cache_add(var/obj/item/ammo_magazine/M) var/list/icon_keys = list() var/list/ammo_states = list() - var/list/states = icon_states(M.icon) for(var/i = 0, i <= M.max_ammo, i++) var/ammo_state = "[M.icon_state]-[i]" - if(ammo_state in states) + if(check_state_in_icon(ammo_state, M.icon)) icon_keys += i ammo_states += ammo_state diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm index 15bc7d0245e0..56f1456a0630 100644 --- a/code/modules/projectiles/ammunition/boxes.dm +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -1,11 +1,13 @@ /obj/item/ammo_magazine/speedloader + name = "speed loader" + desc = "A speed loader for revolvers." icon = 'icons/obj/ammo/speedloader.dmi' icon_state = ICON_STATE_WORLD caliber = CALIBER_PISTOL_MAGNUM ammo_type = /obj/item/ammo_casing/pistol/magnum material = /decl/material/solid/metal/steel max_ammo = 6 - var/list/global/bullet_offsets = list( + var/static/list/bullet_offsets = list( list("x" = 0, "y" = 0), list("x" = -2, "y" = -3), list("x" = -2, "y" = -7), @@ -15,22 +17,24 @@ ) /obj/item/ammo_magazine/speedloader/on_update_icon() - cut_overlays() - if(!length(stored_ammo)) + . = ..() + var/ammo_count = get_stored_ammo_count() + if(!ammo_count) return + create_initial_contents() // Not ideal, but we need instances for the icon gen. switch(icon_state) - if("world") + if(ICON_STATE_WORLD) var/ammo_state = "world-some" - if(length(stored_ammo) == 1) + if(ammo_count == 1) ammo_state = "world-one" - else if(length(stored_ammo) == max_ammo) + else if(ammo_count == max_ammo) ammo_state = "world-full" var/obj/item/ammo_casing/A = stored_ammo[1] add_overlay(overlay_image(icon, ammo_state, A.color, RESET_COLOR)) add_overlay(overlay_image(icon, "[ammo_state]-bullets", A.bullet_color, flags = RESET_COLOR)) if(A.marking_color) add_overlay(overlay_image(icon, "[ammo_state]-markings", A.marking_color, RESET_COLOR)) - if("inventory") + if(ICON_STATE_INV) for(var/i = 1 to length(stored_ammo)) var/obj/item/ammo_casing/A = stored_ammo[i] var/image/I = overlay_image(icon, "casing", A.color, RESET_COLOR) @@ -55,21 +59,22 @@ /obj/item/ammo_magazine/shotholder/on_update_icon() ..() - overlays.Cut() if(marking_color) - var/image/I = image(icon, "shotholder-marking") - I.color = marking_color - overlays += I + add_overlay(overlay_image(icon, "shotholder-marking", marking_color, RESET_COLOR)) /obj/item/ammo_magazine/shotholder/attack_hand(mob/user) - if((user.a_intent == I_HURT) && (stored_ammo.len)) - var/obj/item/ammo_casing/C = stored_ammo[stored_ammo.len] - stored_ammo-=C - user.put_in_hands(C) - user.visible_message("\The [user] removes \a [C] from [src].", "You remove \a [C] from [src].") - update_icon() - else - ..() + if(loc != user || !user.check_intent(I_FLAG_HARM) || !get_stored_ammo_count() || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + create_initial_contents() + var/obj/item/ammo_casing/C = stored_ammo[stored_ammo.len] + stored_ammo -= C + user.put_in_hands(C) + user.visible_message( + "\The [user] removes \a [C] from [src].", + SPAN_NOTICE("You remove \a [C] from [src].") + ) + update_icon() + return TRUE /obj/item/ammo_magazine/shotholder/shell name = "shotgun shell holder" @@ -86,14 +91,14 @@ name = "illumination shell holder" ammo_type = /obj/item/ammo_casing/shotgun/flash material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) marking_color = COLOR_PALE_YELLOW /obj/item/ammo_magazine/shotholder/stun name = "stun shell holder" ammo_type = /obj/item/ammo_casing/shotgun/stunshell material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) marking_color = COLOR_MUZZLE_FLASH /obj/item/ammo_magazine/shotholder/empty @@ -125,7 +130,7 @@ /obj/item/ammo_magazine/pistol name = "pistol magazine" icon_state = "pistol" - origin_tech = "{'combat':2}" + origin_tech = @'{"combat":2}' mag_type = MAGAZINE caliber = CALIBER_PISTOL material = /decl/material/solid/metal/steel @@ -140,6 +145,18 @@ labels = list("rubber") ammo_type = /obj/item/ammo_casing/pistol/rubber +/obj/item/ammo_magazine/pistol/practice + labels = list("practice") + ammo_type = /obj/item/ammo_casing/pistol/practice + +/obj/item/ammo_magazine/pistol/flash + labels = list("flash") + ammo_type = /obj/item/ammo_casing/pistol/flash + +/obj/item/ammo_magazine/pistol/emp + labels = list("haywire") + ammo_type = /obj/item/ammo_casing/pistol/emp + /obj/item/ammo_magazine/pistol/small icon_state = "holdout" material = /decl/material/solid/metal/steel @@ -150,19 +167,27 @@ /obj/item/ammo_magazine/pistol/small/empty initial_ammo = 0 +/obj/item/ammo_magazine/pistol/small/rubber + labels = list("rubber") + ammo_type = /obj/item/ammo_casing/pistol/small/rubber + +/obj/item/ammo_magazine/pistol/small/practice + labels = list("practice") + ammo_type = /obj/item/ammo_casing/pistol/small/practice + /obj/item/ammo_magazine/box/smallpistol - name = "ammunition box" + name = "ammunition box (pistol, small)" icon_state = "smallpistol" - origin_tech = "{'combat':2}" + origin_tech = @'{"combat":2}' material = /decl/material/solid/metal/steel caliber = CALIBER_PISTOL_SMALL ammo_type = /obj/item/ammo_casing/pistol/small max_ammo = 30 /obj/item/ammo_magazine/box/pistol - name = "ammunition box" + name = "ammunition box (pistol)" icon_state = "smallpistol" - origin_tech = "{'combat':2}" + origin_tech = @'{"combat":2}' caliber = CALIBER_PISTOL material = /decl/material/solid/metal/steel ammo_type = /obj/item/ammo_casing/pistol @@ -172,25 +197,27 @@ initial_ammo = 0 /obj/item/ammo_magazine/box/emp/pistol - name = "ammunition box" + name = "ammunition box (pistol, haywire)" desc = "A box containing loose rounds of standard EMP ammo." labels = list("haywire") ammo_type = /obj/item/ammo_casing/pistol/emp caliber = CALIBER_PISTOL max_ammo = 15 + origin_tech = @'{"combat":2,"magnets":2,"powerstorage":2}' /obj/item/ammo_magazine/box/emp/smallpistol - name = "ammunition box" + name = "ammunition box (pistol, small, haywire)" desc = "A box containing loose rounds of small EMP ammo." labels = list("haywire") ammo_type = /obj/item/ammo_casing/pistol/small/emp caliber = CALIBER_PISTOL_SMALL max_ammo = 8 + origin_tech = @'{"combat":2,"magnets":2,"powerstorage":2}' /obj/item/ammo_magazine/rifle name = "assault rifle magazine" icon_state = "bullup" - origin_tech = "{'combat':2}" + origin_tech = @'{"combat":2}' mag_type = MAGAZINE caliber = CALIBER_RIFLE material = /decl/material/solid/metal/steel @@ -205,6 +232,16 @@ labels = list("practice") ammo_type = /obj/item/ammo_casing/rifle/practice +/obj/item/ammo_magazine/rifle/drum + name = "machine gun drum magazine" + icon_state = "drum" + origin_tech = @'{"combat":2}' + mag_type = MAGAZINE + caliber = CALIBER_RIFLE + material = /decl/material/solid/metal/steel + ammo_type = /obj/item/ammo_casing/rifle + max_ammo = 100 + /obj/item/ammo_magazine/caps name = "speed loader" desc = "A cheap plastic speed loader for some kind of revolver." @@ -215,6 +252,14 @@ max_ammo = 7 multiple_sprites = 1 +/obj/item/ammo_magazine/speedloader/rubber + labels = list("rubber") + ammo_type = /obj/item/ammo_casing/pistol/magnum/rubber + +/obj/item/ammo_magazine/speedloader/practice + labels = list("practice") + ammo_type = /obj/item/ammo_casing/pistol/magnum/practice + /obj/item/ammo_magazine/speedloader/laser_revolver caliber = CALIBER_PISTOL_LASBULB - ammo_type = /obj/item/ammo_casing/lasbulb \ No newline at end of file + ammo_type = /obj/item/ammo_casing/lasbulb diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm index 75400e9c572b..f02b0bde75a4 100644 --- a/code/modules/projectiles/ammunition/bullets.dm +++ b/code/modules/projectiles/ammunition/bullets.dm @@ -16,11 +16,17 @@ bullet_color = COLOR_OFF_WHITE marking_color = COLOR_SUN +/obj/item/ammo_casing/pistol/flash + desc = "A bullet casing loaded with a chemical charge." + projectile_type = /obj/item/projectile/energy/flash + marking_color = COLOR_ORANGE + /obj/item/ammo_casing/pistol/emp name = "haywire round" desc = "A pistol bullet casing fitted with a single-use ion pulse generator." projectile_type = /obj/item/projectile/ion/small material = /decl/material/solid/metal/steel + color = /decl/material/solid/metal/steel::color matter = list(/decl/material/solid/metal/uranium = MATTER_AMOUNT_REINFORCEMENT) bullet_color = COLOR_ACID_CYAN marking_color = COLOR_LUMINOL @@ -28,10 +34,11 @@ /obj/item/ammo_casing/pistol/small desc = "A small pistol bullet casing." color = COLOR_POLISHED_BRASS + bullet_color = COLOR_POLISHED_BRASS icon = 'icons/obj/ammo/casings/small_pistol.dmi' caliber = CALIBER_PISTOL_SMALL projectile_type = /obj/item/projectile/bullet/pistol/holdout - + /obj/item/ammo_casing/pistol/small/rubber desc = "A small pistol rubber bullet casing." projectile_type = /obj/item/projectile/bullet/pistol/rubber/holdout @@ -54,49 +61,87 @@ desc = "A high-power pistol bullet casing." caliber = CALIBER_PISTOL_MAGNUM color = COLOR_POLISHED_BRASS + bullet_color = COLOR_POLISHED_BRASS marking_color = COLOR_MAROON projectile_type = /obj/item/projectile/bullet/pistol/strong icon = 'icons/obj/ammo/casings/magnum.dmi' +/obj/item/ammo_casing/pistol/magnum/rubber + desc = "A rubber bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/rubber/strong + bullet_color = COLOR_GRAY40 + +/obj/item/ammo_casing/pistol/magnum/practice + desc = "A practice bullet casing." + projectile_type = /obj/item/projectile/bullet/pistol/practice + bullet_color = COLOR_OFF_WHITE + marking_color = COLOR_SUN + +// This uses a shotgun shell icon despite not being a shotgun shell... +// TODO: Unify the casing icon system somehow to avoid code duplication. +/obj/item/ammo_casing/pistol/magnum/stun + name = "stun round" + desc = "An energy stun cartridge." + icon = 'icons/obj/ammo/shells/stun.dmi' + icon_state = ICON_STATE_WORLD + projectile_type = /obj/item/projectile/energy/electrode/stunshot + leaves_residue = FALSE + material = /decl/material/solid/metal/steel + material_alteration = MAT_FLAG_ALTERATION_NONE + matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"combat":3,"materials":3}' + +/obj/item/ammo_casing/pistol/magnum/stun/update_casing_icon() + icon_state = get_world_inventory_state() + if(!BB) // use spent icon + icon_state = "[icon_state]-spent" + /obj/item/ammo_casing/shotgun name = "shotgun slug" desc = "A shotgun slug." - icon_state = "slshell" - spent_icon = "slshell-spent" + icon = 'icons/obj/ammo/shells/slugs.dmi' + icon_state = ICON_STATE_WORLD caliber = CALIBER_SHOTGUN projectile_type = /obj/item/projectile/bullet/shotgun - material = /decl/material/solid/metal/steel - fall_sounds = list('sound/weapons/guns/shotgun_fall.ogg') + material = /decl/material/solid/metal/steel // at some point this should use matter, brass + plastic + color = null + material_alteration = MAT_FLAG_ALTERATION_NONE + drop_sound = 'sound/weapons/guns/shotgun_fall.ogg' + +/obj/item/ammo_casing/shotgun/update_casing_icon() + icon_state = get_world_inventory_state() + if(!BB) // use spent icon + icon_state = "[icon_state]-spent" /obj/item/ammo_casing/shotgun/pellet name = "shotgun shell" - desc = "A shotshell." - icon_state = "gshell" - spent_icon = "gshell-spent" + desc = "A shotgun shell." + icon = 'icons/obj/ammo/shells/buckshot.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/bullet/pellet/shotgun material = /decl/material/solid/metal/steel /obj/item/ammo_casing/shotgun/blank name = "shotgun shell" desc = "A blank shell." - icon_state = "blshell" - spent_icon = "blshell-spent" + icon = 'icons/obj/ammo/shells/blanks.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/bullet/blank material = /decl/material/solid/metal/steel /obj/item/ammo_casing/shotgun/practice name = "shotgun shell" desc = "A practice shell." - icon_state = "pshell" - spent_icon = "pshell-spent" + icon = 'icons/obj/ammo/shells/practice.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/bullet/shotgun/practice material = /decl/material/solid/metal/steel /obj/item/ammo_casing/shotgun/beanbag name = "beanbag shell" desc = "A beanbag shell." - icon_state = "bshell" - spent_icon = "bshell-spent" + icon = 'icons/obj/ammo/shells/beanbag.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/bullet/shotgun/beanbag material = /decl/material/solid/metal/steel @@ -105,12 +150,13 @@ /obj/item/ammo_casing/shotgun/stunshell name = "stun shell" desc = "An energy stun cartridge." - icon_state = "stunshell" - spent_icon = "stunshell-spent" + icon = 'icons/obj/ammo/shells/stun.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/energy/electrode/stunshot - leaves_residue = 0 + leaves_residue = FALSE material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"combat":3,"materials":3}' /obj/item/ammo_casing/shotgun/stunshell/emp_act(severity) if(prob(100/severity)) BB = null @@ -120,8 +166,8 @@ /obj/item/ammo_casing/shotgun/flash name = "flash shell" desc = "A chemical shell used to signal distress or provide illumination." - icon_state = "fshell" - spent_icon = "fshell-spent" + icon = 'icons/obj/ammo/shells/flash.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/energy/flash/flare material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) @@ -129,20 +175,22 @@ /obj/item/ammo_casing/shotgun/emp name = "haywire slug" desc = "A 12-gauge shotgun slug fitted with a single-use ion pulse generator." - icon_state = "empshell" - spent_icon = "empshell-spent" + icon = 'icons/obj/ammo/shells/haywire.dmi' + icon_state = ICON_STATE_WORLD projectile_type = /obj/item/projectile/ion material = /decl/material/solid/metal/steel matter = list(/decl/material/solid/metal/uranium = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"combat":4,"materials":3}' /obj/item/ammo_casing/shell name = "shell casing" - desc = "An antimaterial shell casing." - caliber = CALIBER_ANTIMATERIAL + desc = "An anti-materiel shell casing." + caliber = CALIBER_ANTI_MATERIEL projectile_type = /obj/item/projectile/bullet/rifle/shell material = /decl/material/solid/metal/steel color = COLOR_POLISHED_BRASS - icon = 'icons/obj/ammo/casings/antimaterial.dmi' + bullet_color = COLOR_POLISHED_BRASS + icon = 'icons/obj/ammo/casings/anti_materiel.dmi' /obj/item/ammo_casing/shell/apds name = "\improper APDS shell casing" @@ -188,4 +236,4 @@ color = COLOR_BLUE_GRAY bullet_color = COLOR_BLUE_LIGHT material = /decl/material/solid/glass - matter = list(/decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file diff --git a/code/modules/projectiles/ammunition/chemdart.dm b/code/modules/projectiles/ammunition/chemdart.dm index a40a12e087ed..bc6423ac6aab 100644 --- a/code/modules/projectiles/ammunition/chemdart.dm +++ b/code/modules/projectiles/ammunition/chemdart.dm @@ -2,23 +2,18 @@ name = "dart" icon_state = "dart" damage = 5 - sharp = 1 + sharp = TRUE embed = 1 //the dart is shot fast enough to pierce space suits, so I guess splintering inside the target can be a thing. Should be rare due to low damage. - var/reagent_amount = 15 life_span = 15 //shorter range - unacidable = 1 - muzzle_type = null - -/obj/item/projectile/bullet/chemdart/Initialize() - . = ..() - create_reagents(reagent_amount) + material = /decl/material/solid/glass + chem_volume = 15 /obj/item/projectile/bullet/chemdart/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) - if(blocked < 100 && isliving(target)) + if(REAGENT_TOTAL_VOLUME(reagents) && blocked < 100 && isliving(target)) var/mob/living/L = target if(L.can_inject(null, def_zone) == CAN_INJECT) - reagents.trans_to_mob(L, reagent_amount, CHEM_INJECT) + reagents.trans_to_mob(L, REAGENT_TOTAL_VOLUME(reagents), CHEM_INJECT) /obj/item/ammo_casing/chemdart name = "chemical dart" @@ -26,7 +21,10 @@ icon_state = "dart" caliber = CALIBER_DART projectile_type = /obj/item/projectile/bullet/chemdart - leaves_residue = 0 + leaves_residue = FALSE + material = /decl/material/solid/organic/plastic + color = null + material_alteration = MAT_FLAG_ALTERATION_NONE /obj/item/ammo_casing/chemdart/expend() qdel(src) @@ -36,7 +34,7 @@ desc = "A rack of hollow darts." icon_state = "darts" item_state = "rcdammo" - origin_tech = "{'materials':2}" + origin_tech = @'{"materials":2}' mag_type = MAGAZINE caliber = CALIBER_DART ammo_type = /obj/item/ammo_casing/chemdart diff --git a/code/modules/projectiles/ammunition/magnetic.dm b/code/modules/projectiles/ammunition/magnetic.dm index 4ad8d7492070..51ea0ffed07a 100644 --- a/code/modules/projectiles/ammunition/magnetic.dm +++ b/code/modules/projectiles/ammunition/magnetic.dm @@ -8,9 +8,9 @@ var/basetype = /obj/item/magnetic_ammo w_class = ITEM_SIZE_SMALL material = /decl/material/solid/metal/steel - origin_tech = "{'combat':1}" + origin_tech = @'{"combat":1}' var/remaining = 9 -/obj/item/magnetic_ammo/examine(mob/user) +/obj/item/magnetic_ammo/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "There [(remaining == 1)? "is" : "are"] [remaining] [projectile_name]\s left!") + . += "There [(remaining == 1)? "is" : "are"] [remaining] [projectile_name]\s left!" diff --git a/code/modules/projectiles/effects.dm b/code/modules/projectiles/effects.dm deleted file mode 100644 index 35ca695c5bf4..000000000000 --- a/code/modules/projectiles/effects.dm +++ /dev/null @@ -1,309 +0,0 @@ -/obj/effect/projectile - icon = 'icons/effects/projectiles.dmi' - icon_state = "bolt" - plane = EFFECTS_ABOVE_LIGHTING_PLANE - layer = BEAM_PROJECTILE_LAYER //Muzzle flashes would be above the lighting plane anyways. - //Standard compiletime light vars aren't working here, so we've made some of our own. - light_outer_range = 2 - light_max_bright = 1 - light_color = "#ff00dc" - mouse_opacity = 0 - var/overlay_state - var/overlay_color - -/obj/effect/projectile/proc/set_transform(var/matrix/M) - if(istype(M)) - transform = M - -/obj/effect/projectile/Initialize(var/ml, var/obj/item/owner) - if(owner) - if(owner.light_color) - light_color = owner.light_color - if(owner.color) - color = owner.color - . = ..() - if(overlay_state) - update_icon() - -/obj/effect/projectile/on_update_icon() - cut_overlays() - if(overlay_state) - var/image/I = image(icon, "[icon_state][overlay_state]") - I.color = overlay_color - I.appearance_flags |= RESET_COLOR - add_overlay(I) - // Projectile effects only exist for a tick or two, need to call - // this to ensure they show their overlays before expiring. - compile_overlays() - -//---------------------------- -// Laser beam -//---------------------------- -/obj/effect/projectile/laser - light_color = COLOR_RED_LIGHT - -/obj/effect/projectile/laser/tracer - icon_state = "beam" - -/obj/effect/projectile/laser/muzzle - icon_state = "muzzle_laser" - -/obj/effect/projectile/laser/impact - icon_state = "impact_laser" - -//---------------------------- -// Variable (white base) laser beam -//---------------------------- -/obj/effect/projectile/laser/variable - light_color = COLOR_RED_LIGHT - color = COLOR_RED - overlay_state = "_overlay" - -/obj/effect/projectile/laser/variable/tracer - icon_state = "beam_white" - -/obj/effect/projectile/laser/variable/muzzle - icon_state = "muzzle_laser_white" - -/obj/effect/projectile/laser/variable/impact - icon_state = "impact_laser_white" - -/obj/effect/projectile/laser/variable/heavy_tracer - icon_state = "beam_heavy_white" - -/obj/effect/projectile/laser/variable/heavy_muzzle - icon_state = "muzzle_laser_heavy_white" - -/obj/effect/projectile/laser/variable/heavy_impact - icon_state = "impact_laser_heavy_white" - -//---------------------------- -// Blue laser beam -//---------------------------- -/obj/effect/projectile/laser/blue - light_color = COLOR_BLUE_LIGHT - -/obj/effect/projectile/laser/blue/tracer - icon_state = "beam_blue" - -/obj/effect/projectile/laser/blue/muzzle - icon_state = "muzzle_blue" - -/obj/effect/projectile/laser/blue/impact - icon_state = "impact_blue" - -//---------------------------- -// Omni laser beam -//---------------------------- -/obj/effect/projectile/laser/omni - light_color = COLOR_LUMINOL - -/obj/effect/projectile/laser/omni/tracer - icon_state = "beam_omni" - -/obj/effect/projectile/laser/omni/muzzle - icon_state = "muzzle_omni" - -/obj/effect/projectile/laser/omni/impact - icon_state = "impact_omni" - -//---------------------------- -// Xray laser beam -//---------------------------- -/obj/effect/projectile/laser/xray - light_color = "#00cc00" - -/obj/effect/projectile/laser/xray/tracer - icon_state = "xray" - -/obj/effect/projectile/laser/xray/muzzle - icon_state = "muzzle_xray" - -/obj/effect/projectile/laser/xray/impact - icon_state = "impact_xray" - -//---------------------------- -// Heavy laser beam -//---------------------------- -/obj/effect/projectile/laser/heavy - light_max_bright = 1 - -/obj/effect/projectile/laser/heavy/tracer - icon_state = "beam_heavy" - -/obj/effect/projectile/laser/heavy/muzzle - icon_state = "muzzle_beam_heavy" - -/obj/effect/projectile/laser/heavy/impact - icon_state = "impact_beam_heavy" - -//---------------------------- -// Pulse laser beam -//---------------------------- -/obj/effect/projectile/laser/pulse - light_max_bright = 1 - light_color = COLOR_DEEP_SKY_BLUE - -/obj/effect/projectile/laser/pulse/tracer - icon_state = "u_laser" - - -/obj/effect/projectile/laser/pulse/muzzle - icon_state = "muzzle_u_laser" - -/obj/effect/projectile/laser/pulse/impact - icon_state = "impact_u_laser" - -//---------------------------- -// Pulse muzzle effect only -//---------------------------- -/obj/effect/projectile/pulse/muzzle - icon_state = "muzzle_pulse" - light_max_bright = 1 - light_color = COLOR_DEEP_SKY_BLUE - -//---------------------------- -// Treye beam -//---------------------------- -/obj/effect/projectile/trilaser/ - light_color = COLOR_LUMINOL - -/obj/effect/projectile/trilaser/tracer - icon_state = "plasmacutter" - -/obj/effect/projectile/trilaser/muzzle - icon_state = "muzzle_plasmacutter" - -/obj/effect/projectile/trilaser/impact - icon_state = "impact_plasmacutter" - -//---------------------------- -// Emitter beam -//---------------------------- -/obj/effect/projectile/laser/emitter/ - light_max_bright = 1 - light_color = "#00cc00" - -/obj/effect/projectile/laser/emitter/tracer - icon_state = "emitter" - -/obj/effect/projectile/laser/emitter/muzzle - icon_state = "muzzle_emitter" - -/obj/effect/projectile/laser/emitter/impact - icon_state = "impact_emitter" - -//---------------------------- -// Stun beam -//---------------------------- -/obj/effect/projectile/stun/ - light_color = COLOR_YELLOW - -/obj/effect/projectile/stun/tracer - icon_state = "stun" - -/obj/effect/projectile/stun/muzzle - icon_state = "muzzle_stun" - -/obj/effect/projectile/stun/impact - icon_state = "impact_stun" - -//---------------------------- -// Bullet -//---------------------------- -/obj/effect/projectile/bullet/muzzle - icon_state = "muzzle_bullet" - light_outer_range = 5 - light_max_bright = 1 - light_color = COLOR_MUZZLE_FLASH - -//---------------------------- -// confuse ray -//---------------------------- -/obj/effect/projectile/confuseray - light_color = COLOR_GREEN_GRAY - -/obj/effect/projectile/confuseray/tracer - icon_state = "beam_grass" - -/obj/effect/projectile/confuseray/muzzle - icon_state = "muzzle_grass" - -/obj/effect/projectile/confuseray/impact - icon_state = "impact_grass" - -//---------------------------- -// Particle beam -//---------------------------- -/obj/effect/projectile/laser_particle - light_color = COLOR_CYAN - -/obj/effect/projectile/laser_particle/tracer - icon_state = "beam_particle" - -/obj/effect/projectile/laser_particle/muzzle - icon_state = "muzzle_particle" - -/obj/effect/projectile/laser_particle/impact - icon_state = "impact_particle" - -//---------------------------- -// Dark matter -//---------------------------- -/obj/effect/projectile/darkmatter - light_color = COLOR_PURPLE - -/obj/effect/projectile/darkmatter/tracer - icon_state = "beam_darkb" - -/obj/effect/projectile/darkmatter/muzzle - icon_state = "muzzle_darkb" - -/obj/effect/projectile/darkmatter/impact - icon_state = "impact_darkb" - - //---------------------------- -// Dark matter stun -//---------------------------- -/obj/effect/projectile/stun/darkmatter - light_color = COLOR_PURPLE - -/obj/effect/projectile/stun/darkmatter/tracer - icon_state = "beam_darkt" - -/obj/effect/projectile/stun/darkmatter/muzzle - icon_state = "muzzle_darkt" - -/obj/effect/projectile/stun/darkmatter/impact - icon_state = "impact_darkt" - -//---------------------------- -// Point defense -//---------------------------- -/obj/effect/projectile/pointdefense - light_color = COLOR_GOLD - light_max_bright = 1 - -/obj/effect/projectile/pointdefense/tracer - icon_state = "beam_pointdef_d" - -/obj/effect/projectile/pointdefense/muzzle - icon_state = "muzzle_pointdef_d" - -/obj/effect/projectile/pointdefense/impact - icon_state = "impact_pointdef_d" - -//---------------------------- -// incendiary laser -//---------------------------- -/obj/effect/projectile/incen - light_color = COLOR_PALE_ORANGE - -/obj/effect/projectile/incen/tracer - icon_state = "beam_incen" - -/obj/effect/projectile/incen/muzzle - icon_state = "muzzle_incen" - -/obj/effect/projectile/incen/impact - icon_state = "impact_incen" \ No newline at end of file diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 3c0a442d6932..13b739cf041a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -30,24 +30,28 @@ //Parent gun type. Guns are weapons that can be aimed at mobs and act over a distance /obj/item/gun name = "gun" - desc = "Its a gun. It's pretty terrible, though." + desc = "It's a gun. It's pretty terrible, though." icon_state = ICON_STATE_WORLD icon = 'icons/obj/guns/pistol.dmi' obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT|SLOT_HOLSTER + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER material = /decl/material/solid/metal/steel w_class = ITEM_SIZE_NORMAL - throwforce = 5 throw_speed = 4 throw_range = 5 - force = 5 - origin_tech = "{'combat':1}" + origin_tech = @'{"combat":1}' attack_verb = list("struck", "hit", "bashed") zoomdevicename = "scope" - + drop_sound = 'sound/foley/drop1.ogg' + pickup_sound = 'sound/foley/pickup2.ogg' + can_be_twohanded = TRUE // also checks one_hand_penalty + needs_attack_dexterity = DEXTERITY_WEAPONS + wieldsound = 'sound/weapons/TargetOn.ogg' + unwieldsound = 'sound/weapons/TargetOff.ogg' + + var/fire_verb = "fire" var/waterproof = FALSE var/burst = 1 - var/can_autofire = FALSE var/fire_delay = 6 //delay after shooting before the gun can be used again. Cannot be less than [burst_delay+1] var/burst_delay = 1 //delay between shots, if firing in bursts var/fire_sound = 'sound/weapons/gunshot/gunshot.ogg' @@ -55,7 +59,7 @@ var/fire_anim = null var/screen_shake = 0 //shouldn't be greater than 2 unless zoomed var/space_recoil = 0 //knocks back in space - var/silenced = 0 + var/silencer var/accuracy = 0 //accuracy is measured in tiles. +1 accuracy means that everything is effectively one tile closer for the purpose of miss chance, -1 means the opposite. launchers are not supported, at the moment. var/accuracy_power = 5 //increase of to-hit chance per 1 point of accuracy var/bulk = 0 //how unwieldy this weapon for its size, affects accuracy when fired without aiming @@ -65,7 +69,6 @@ var/list/burst_accuracy = list(0) //allows for different accuracies for each shot in a burst. Applied on top of accuracy var/list/dispersion = list(0) var/one_hand_penalty - var/wielded_item_state var/combustion //whether it creates hotspot when fired var/next_fire_time = 0 @@ -75,97 +78,158 @@ var/selector_sound = 'sound/weapons/guns/selector.ogg' //aiming system stuff - var/keep_aim = 1 //1 for keep shooting until aim is lowered - //0 for one bullet after tarrget moves and aim is lowered - var/multi_aim = 0 //Used to determine if you can target multiple people. var/tmp/list/mob/living/aim_targets //List of who yer targeting. - var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person. - var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. - var/tmp/lock_time = -100 var/tmp/last_safety_check = -INFINITY var/safety_state = 1 var/has_safety = TRUE var/safety_icon //overlay to apply to gun based on safety state, if any + var/autofire_enabled = FALSE + var/atom/autofiring_at + var/mob/autofiring_by + var/autofiring_timer + + // Spam prevention + var/last_fire_message_type + var/last_fire_message_time + /obj/item/gun/Initialize() - . = ..() + // must have firemodes initialized prior to any update_icon_calls + // including reconsider_single_icon(), which is done in ..() + LAZYINITLIST(firemodes) for(var/i in 1 to firemodes.len) firemodes[i] = new /datum/firemode(src, firemodes[i]) - + . = ..() if(isnull(scoped_accuracy)) scoped_accuracy = accuracy - if(scope_zoom) verbs += /obj/item/gun/proc/scope +/obj/item/gun/Destroy() + // autofire timer is automatically cleaned up + autofiring_at = null + autofiring_by = null + . = ..() + +/obj/item/gun/is_held_twohanded(mob/living/wielder) + return one_hand_penalty > 0 && ..() + +/obj/item/gun/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE + +/obj/item/gun/proc/set_autofire(var/atom/fire_at, var/mob/fire_by, var/autoturn = TRUE) + . = TRUE + if(!istype(fire_at) || !istype(fire_by)) + . = FALSE + else if(QDELETED(fire_at) || QDELETED(fire_by) || QDELETED(src)) + . = FALSE + else if(!autofire_enabled) + . = FALSE + if(.) + autofiring_at = fire_at + autofiring_by = fire_by + if(!autofiring_timer) + autofiring_timer = addtimer(CALLBACK(src, PROC_REF(handle_autofire), autoturn), burst_delay, (TIMER_STOPPABLE | TIMER_LOOP | TIMER_UNIQUE | TIMER_OVERRIDE)) + else + clear_autofire() + +/obj/item/gun/proc/clear_autofire() + autofiring_at = null + autofiring_by = null + if(autofiring_timer) + deltimer(autofiring_timer) + autofiring_timer = null + +/obj/item/gun/proc/handle_autofire(autoturn) + set waitfor = FALSE + . = TRUE + if(QDELETED(autofiring_at) || QDELETED(autofiring_by)) + . = FALSE + else if(!autofiring_by.can_autofire(src, autofiring_at)) + . = FALSE + if(!.) + clear_autofire() + else if(can_autofire()) + try_autofire(autoturn) + +/obj/item/gun/proc/try_autofire(autoturn) + if(autoturn) + autofiring_by.set_dir(get_dir(src, autofiring_at)) + Fire(autofiring_at, autofiring_by, null, (get_dist(autofiring_at, autofiring_by) <= 1), FALSE, FALSE) + /obj/item/gun/update_twohanding() if(one_hand_penalty) update_icon() // In case item_state is set somewhere else. ..() +/obj/item/gun/proc/update_base_icon_state() + icon_state = get_world_inventory_state() + /obj/item/gun/on_update_icon() var/mob/living/M = loc - overlays.Cut() - update_base_icon() + . = ..() + update_base_icon_state() if(istype(M)) - if(M.skill_check(SKILL_WEAPONS,SKILL_BASIC)) - overlays += image('icons/obj/guns/gui.dmi',"safety[safety()]") - if (src == M.r_hand) - M.update_inv_r_hand() - else if (src == M.l_hand) - M.update_inv_l_hand() - if(safety_icon) - overlays += get_safety_indicator() + if(has_safety && M.skill_check(SKILL_WEAPONS,SKILL_BASIC)) + add_overlay(image('icons/obj/guns/gui.dmi',"safety[safety()]")) + if(src in M.get_held_items()) + M.update_inhand_overlays() -/obj/item/gun/proc/update_base_icon() + if(silencer) + var/silenced_state = "[icon_state]-silencer" + if(check_state_in_icon(silenced_state, icon)) + add_overlay(mutable_appearance(icon, silenced_state)) -/obj/item/gun/proc/get_safety_indicator() - return get_mutable_overlay(icon, "[get_world_inventory_state()][safety_icon][safety()]") + if(safety_icon) + add_overlay(get_safety_indicator()) -/obj/item/gun/get_mob_overlay(mob/user_mob, slot) - var/image/I = ..() - if(wielded_item_state && user_mob.can_wield_item(src) && is_held_twohanded(user_mob)) - I.icon_state = wielded_item_state - return I +/obj/item/gun/get_on_belt_overlay() + if(silencer && check_state_in_icon("on_belt_silenced", icon)) + return overlay_image(icon, "on_belt_silenced", color) + return ..() -/obj/item/gun/experimental_mob_overlay(mob/user_mob, slot) - var/image/I = ..() - if(user_mob.can_wield_item(src) && is_held_twohanded(user_mob) && check_state_in_icon("[I.icon_state]-wielded", icon)) - I.icon_state = "[I.icon_state]-wielded" - return I +/obj/item/gun/proc/get_safety_indicator() + return mutable_appearance(icon, "[get_world_inventory_state()][safety_icon][safety()]") //Checks whether a given mob can use the gun //Any checks that shouldn't result in handle_click_empty() being called if they fail should go here. //Otherwise, if you want handle_click_empty() to be called, check in consume_next_projectile() and return null there. /obj/item/gun/proc/special_check(var/mob/user) - if(!istype(user, /mob/living)) - return 0 - if(!user.check_dexterity(DEXTERITY_WEAPONS)) - return 0 + if(!isliving(user)) + return FALSE + + if(!user.check_dexterity(get_required_attack_dexterity(user))) + return FALSE + + if(is_secure_gun() && !free_fire() && (!authorized_modes[sel_mode] || !registered_owner)) + audible_message(SPAN_WARNING("\The [src] buzzes, refusing to fire."), hearing_distance = 3) + playsound(loc, 'sound/machines/buzz-sigh.ogg', 10, 0) + return FALSE var/mob/living/M = user if(!safety() && world.time > last_safety_check + 5 MINUTES && !user.skill_check(SKILL_WEAPONS, SKILL_BASIC)) if(prob(30)) toggle_safety() - return 1 - if(MUTATION_HULK in M.mutations) - to_chat(M, "Your fingers are much too large for the trigger guard!") - return 0 - if((MUTATION_CLUMSY in M.mutations) && prob(40)) //Clumsy handling + + if(M.has_genetic_condition(GENE_COND_CLUMSY) && prob(40)) //Clumsy handling var/obj/P = consume_next_projectile() if(P) - if(process_projectile(P, user, user, pick(BP_L_FOOT, BP_R_FOOT))) + var/pew_loc = pick(BP_L_FOOT, BP_R_FOOT) + if(process_projectile(P, user, user, pew_loc)) + var/decl/pronouns/pronouns = user.get_pronouns() handle_post_fire(user, user) + var/obj/item/affecting = GET_EXTERNAL_ORGAN(user, pew_loc) + pew_loc = affecting ? "\the [affecting]" : "the foot" user.visible_message( - "\The [user] shoots \himself in the foot with \the [src]!", - "You shoot yourself in the foot with \the [src]!" - ) - M.unequip_item() + SPAN_DANGER("\The [user] shoots [pronouns.self] in [pew_loc] with \the [src]!"), + SPAN_DANGER("You shoot yourself in [pew_loc] with \the [src]!")) + M.try_unequip(src) else handle_click_empty(user) - return 0 - return 1 + return FALSE + + return TRUE /obj/item/gun/emp_act(severity) for(var/obj/O in contents) @@ -183,67 +247,90 @@ Fire(A,user,params) //Otherwise, fire normally. -/obj/item/gun/attack(atom/A, mob/living/user, def_zone) - if (A == user && user.zone_sel.selecting == BP_MOUTH && !mouthshoot) +/obj/item/gun/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if (target == user && user.get_target_zone() == BP_MOUTH && !mouthshoot) handle_suicide(user) - else if(user.a_intent != I_HURT && user.aiming && user.aiming.active) //if aim mode, don't pistol whip - if (user.aiming.aiming_at != A) - PreFire(A, user) + return TRUE + + if(!user.check_intent(I_FLAG_HARM) && user.aiming && user.aiming.active) //if aim mode, don't pistol whip + if (user.aiming.aiming_at != target) + PreFire(target, user) else - Fire(A, user, pointblank=1) - else if(user.a_intent == I_HURT) //point blank shooting - Fire(A, user, pointblank=1) - else - return ..() //Pistolwhippin' + Fire(target, user, pointblank=1) + return TRUE + + if(user.check_intent(I_FLAG_HARM)) //point blank shooting + Fire(target, user, pointblank = TRUE) + return TRUE + + return ..() //Pistolwhippin' /obj/item/gun/dropped(var/mob/living/user) check_accidents(user) update_icon() - return ..() - -/obj/item/gun/proc/Fire(atom/target, mob/living/user, clickparams, pointblank=0, reflex=0) - if(!user || !target) return - if(target.z != user.z) return - - add_fingerprint(user) + . = ..() + clear_autofire() - if((!waterproof && submerged()) || !special_check(user)) +/obj/item/gun/proc/Fire(atom/target, atom/movable/firer, clickparams, pointblank = FALSE, reflex = FALSE, set_click_cooldown = TRUE, target_zone = BP_CHEST) + if(!firer || !target) + return + if(target.z != firer.z) return - if(safety()) - if(user.a_intent == I_HURT && !user.skill_fail_prob(SKILL_WEAPONS, 100, SKILL_EXPERT, 0.5)) //reflex un-safeying - toggle_safety(user) - else - handle_click_empty(user) - return + if((!waterproof && submerged())) + return if(world.time < next_fire_time) if (world.time % 3) //to prevent spam - to_chat(user, "[src] is not ready to fire again!") + to_chat(firer, "[src] is not ready to fire again!") return - last_safety_check = world.time - var/shoot_time = (burst - 1)* burst_delay - user.setClickCooldown(shoot_time) //no clicking on things while shooting - next_fire_time = world.time + shoot_time + var/mob/living/user = null + if(isliving(firer)) + user = firer + target_zone = user.get_target_zone() + + if(istype(user)) + add_fingerprint(user) + + if(!special_check(user)) + return - var/held_twohanded = (user.can_wield_item(src) && src.is_held_twohanded(user)) + if(safety()) + if(user.check_intent(I_FLAG_HARM) && !user.skill_fail_prob(SKILL_WEAPONS, 100, SKILL_EXPERT, 0.5)) //reflex un-safeying + toggle_safety(user) + else + handle_click_empty(user) + return + + last_safety_check = world.time + + if(set_click_cooldown) + var/shoot_time = (burst - 1) * burst_delay + if(istype(user)) + user.setClickCooldown(shoot_time) //no clicking on things while shooting + next_fire_time = world.time + shoot_time + + var/held_twohanded = TRUE // Assume a non-mob shooter won't suffer from accuracy penalties. + if(istype(user)) + held_twohanded = user.can_twohand_item(src) && is_held_twohanded(user) //actually attempt to shoot var/turf/targloc = get_turf(target) //cache this in case target gets deleted during shooting, e.g. if it was a securitron that got destroyed. for(var/i in 1 to burst) - var/obj/projectile = consume_next_projectile(user) + var/obj/projectile = consume_next_projectile(firer) if(!projectile) - handle_click_empty(user) + handle_click_empty(firer) break - process_accuracy(projectile, user, target, i, held_twohanded) + process_accuracy(projectile, firer, target, i, held_twohanded) if(pointblank) - process_point_blank(projectile, user, target) + process_point_blank(projectile, firer, target) - if(process_projectile(projectile, user, target, user.zone_sel?.selecting, clickparams)) - handle_post_fire(user, target, pointblank, reflex, projectile) + if(process_projectile(projectile, firer, target, target_zone, clickparams)) + handle_post_fire(firer, target, pointblank, reflex, projectile) update_icon() if(i < burst) @@ -254,13 +341,13 @@ pointblank = 0 //update timing - var/delay = min(max(burst_delay+1, fire_delay), DEFAULT_QUICK_COOLDOWN) - if(delay) + var/delay = max(fire_delay, burst_delay + 1, DEFAULT_QUICK_COOLDOWN) + if(delay && istype(user)) user.setClickCooldown(delay) next_fire_time = world.time + delay //obtains the next projectile to fire -/obj/item/gun/proc/consume_next_projectile() +/obj/item/gun/proc/consume_next_projectile(atom/movable/firer) return null //used by aiming code @@ -269,72 +356,72 @@ return 2 //just assume we can shoot through glass and stuff. No big deal, the player can just choose to not target someone //on the other side of a window if it makes a difference. Or if they run behind a window, too bad. - return check_trajectory(target, user) + return (target in check_trajectory(target, user)) + +#define FIREARM_MESSAGE_SPAM_TIME (1 SECOND) +/obj/item/gun/proc/check_fire_message_spam(var/check_type = "click") + . = (last_fire_message_type != check_type) || (world.time >= last_fire_message_time + FIREARM_MESSAGE_SPAM_TIME) + if(.) + last_fire_message_type = check_type + last_fire_message_time = world.time +#undef FIREARM_MESSAGE_SPAM_TIME //called if there was no projectile to shoot -/obj/item/gun/proc/handle_click_empty(mob/user) - if (user) - user.visible_message("*click click*", "*click*") - else - src.visible_message("*click click*") +/obj/item/gun/proc/handle_click_empty(atom/movable/firer) + if(check_fire_message_spam("click")) + if(firer) + firer.visible_message("*click click*", "*click*") + else + src.visible_message("*click click*") playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1) //called after successfully firing -/obj/item/gun/proc/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0, var/obj/projectile) +/obj/item/gun/proc/get_firing_name(obj/projectile) + return "\the [src]" + +/obj/item/gun/proc/handle_post_fire(atom/movable/firer, atom/target, var/pointblank=0, var/reflex=0, var/obj/projectile) if(fire_anim) flick(fire_anim, src) - if(!silenced) - if(reflex) - user.visible_message( - "\The [user] fires \the [src][pointblank ? " point blank at \the [target]":""] by reflex!", - "You fire \the [src] by reflex!", - "You hear a [fire_sound_text]!" - ) + if(check_fire_message_spam("fire")) + var/user_message = SPAN_WARNING("You [fire_verb] [get_firing_name(projectile)][pointblank ? " point blank":""] at \the [target][reflex ? " by reflex" : ""]!") + if (silencer) + to_chat(firer, user_message) else - user.visible_message( - "\The [user] fires \the [src][pointblank ? " point blank at \the [target]":""]!", - "You fire \the [src]!", - "You hear a [fire_sound_text]!" - ) - - if(one_hand_penalty) - if(!src.is_held_twohanded(user)) - switch(one_hand_penalty) - if(4 to 6) - if(prob(50)) //don't need to tell them every single time - to_chat(user, "Your aim wavers slightly.") - if(6 to 8) - to_chat(user, "You have trouble keeping \the [src] on target with just one hand.") - if(8 to INFINITY) - to_chat(user, "You struggle to keep \the [src] on target with just one hand!") - else if(!user.can_wield_item(src)) - switch(one_hand_penalty) - if(4 to 6) - if(prob(50)) //don't need to tell them every single time - to_chat(user, "Your aim wavers slightly.") - if(6 to 8) - to_chat(user, "You have trouble holding \the [src] steady.") - if(8 to INFINITY) - to_chat(user, "You struggle to hold \the [src] steady!") + firer.visible_message( + SPAN_DANGER("\The [firer] fires \the [src][pointblank ? " point blank":""] at \the [target][reflex ? " by reflex" : ""]!"), + user_message, + SPAN_DANGER("You hear a [fire_sound_text]!") + ) - if(screen_shake) - shake_camera(user, max(burst_delay*burst, fire_delay), screen_shake) + if (pointblank && ismob(target) && isliving(firer)) + admin_attack_log(firer, target, + "shot point blank with \a [type]", + "shot point blank with \a [type]", + "shot point blank (\a [type])" + ) if(combustion) var/turf/curloc = get_turf(src) if(curloc) curloc.hotspot_expose(700, 5) - if(istype(user,/mob/living/carbon/human) && user.is_cloaked()) //shooting will disable a rig cloaking device - var/mob/living/carbon/human/H = user - if(istype(H.back,/obj/item/rig)) - var/obj/item/rig/R = H.back - for(var/obj/item/rig_module/stealth_field/S in R.installed_modules) - S.deactivate() - - if(space_recoil) - if(!user.check_space_footing()) + if(isliving(firer)) + var/mob/living/user = firer + + inaccuracy_feedback(user) + + if(screen_shake) + shake_camera(user, max(burst_delay*burst, fire_delay), screen_shake) + + if(ishuman(user) && user.is_cloaked()) //shooting will disable a rig cloaking device + var/mob/living/human/H = user + var/obj/item/rig/rig = H.get_rig() + if(rig) + for(var/obj/item/rig_module/stealth_field/S in rig.installed_modules) + S.deactivate() + + if(space_recoil && user.can_slip(magboots_only = TRUE)) var/old_dir = user.dir user.inertia_ignore = projectile step(user,get_dir(target,user)) @@ -342,8 +429,28 @@ update_icon() +/obj/item/gun/proc/inaccuracy_feedback(mob/living/user) + if(one_hand_penalty) + if(!src.is_held_twohanded(user)) + switch(one_hand_penalty) + if(4 to 6) + if(prob(50)) //don't need to tell them every single time + to_chat(user, SPAN_WARNING("Your aim wavers slightly.")) + if(6 to 8) + to_chat(user, SPAN_WARNING("You have trouble keeping \the [src] on target with just one hand.")) + if(8 to INFINITY) + to_chat(user, SPAN_WARNING("You struggle to keep \the [src] on target with just one hand!")) + else if(!user.can_twohand_item(src)) + switch(one_hand_penalty) + if(4 to 6) + if(prob(50)) + to_chat(user, SPAN_WARNING("Your aim wavers slightly.")) + if(6 to 8) + to_chat(user, SPAN_WARNING("You have trouble holding \the [src] steady.")) + if(8 to INFINITY) + to_chat(user, "You struggle to hold \the [src] steady!") -/obj/item/gun/proc/process_point_blank(obj/projectile, mob/user, atom/target) +/obj/item/gun/proc/process_point_blank(obj/projectile, atom/movable/firer, atom/target) var/obj/item/projectile/P = projectile if(!istype(P)) return //default behaviour only applies to true projectiles @@ -356,11 +463,11 @@ var/mob/living/L = target if(L.incapacitated()) max_mult = 1.2 - for(var/obj/item/grab/G in L.grabbed_by) - max_mult = max(max_mult, G.point_blank_mult()) + for(var/obj/item/grab/grab as anything in L.grabbed_by) + max_mult = max(max_mult, grab.point_blank_mult()) P.damage *= max_mult -/obj/item/gun/proc/process_accuracy(obj/projectile, mob/living/user, atom/target, var/burst, var/held_twohanded) +/obj/item/gun/proc/process_accuracy(obj/projectile, atom/movable/firer, atom/target, var/burst, var/held_twohanded) var/obj/item/projectile/P = projectile if(!istype(P)) return //default behaviour only applies to true projectiles @@ -368,41 +475,46 @@ var/acc_mod = burst_accuracy[min(burst, burst_accuracy.len)] var/disp_mod = dispersion[min(burst, dispersion.len)] var/stood_still = last_handled - //Not keeping gun active will throw off aim (for non-Masters) - if(user.skill_check(SKILL_WEAPONS, SKILL_PROF)) - stood_still = min(user.l_move_time, last_handled) - else - stood_still = max(user.l_move_time, last_handled) - stood_still = max(0,round((world.time - stood_still)/10) - 1) - if(stood_still) - acc_mod += min(max(3, accuracy), stood_still) - else - acc_mod -= w_class - ITEM_SIZE_NORMAL - acc_mod -= bulk + // Living specific accuracy modifiers. + if(isliving(firer)) + var/mob/living/user = firer + //Not keeping gun active will throw off aim (for non-Masters) + if(user.skill_check(SKILL_WEAPONS, SKILL_PROF)) + stood_still = min(user.l_move_time, last_handled) + else + stood_still = max(user.l_move_time, last_handled) + + stood_still = max(0,round((world.time - stood_still)/10) - 1) + if(stood_still) + acc_mod += min(max(3, accuracy), stood_still) + else + acc_mod -= w_class - ITEM_SIZE_NORMAL + acc_mod -= bulk + + if(one_hand_penalty >= 4 && !held_twohanded) + acc_mod -= one_hand_penalty/2 + disp_mod += one_hand_penalty*0.5 //dispersion per point of two-handedness - if(one_hand_penalty >= 4 && !held_twohanded) - acc_mod -= one_hand_penalty/2 - disp_mod += one_hand_penalty*0.5 //dispersion per point of two-handedness + if(burst > 1 && !user.skill_check(SKILL_WEAPONS, SKILL_ADEPT)) + acc_mod -= 1 + disp_mod += 0.5 - if(burst > 1 && !user.skill_check(SKILL_WEAPONS, SKILL_ADEPT)) - acc_mod -= 1 - disp_mod += 0.5 + //accuracy bonus from aiming + if (aim_targets && (target in aim_targets)) + //If you aim at someone beforehead, it'll hit more often. + //Kinda balanced by fact you need like 2 seconds to aim + //As opposed to no-delay pew pew + acc_mod += 2 - //accuracy bonus from aiming - if (aim_targets && (target in aim_targets)) - //If you aim at someone beforehead, it'll hit more often. - //Kinda balanced by fact you need like 2 seconds to aim - //As opposed to no-delay pew pew - acc_mod += 2 + acc_mod += user.ranged_accuracy_mods() - acc_mod += user.ranged_accuracy_mods() acc_mod += accuracy P.hitchance_mod = accuracy_power*acc_mod P.dispersion = disp_mod //does the actual launching of the projectile -/obj/item/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null) +/obj/item/gun/proc/process_projectile(obj/projectile, atom/movable/firer, atom/target, var/target_zone, var/params=null) var/obj/item/projectile/P = projectile if(!istype(P)) return 0 //default behaviour only applies to true projectiles @@ -411,51 +523,52 @@ P.set_clickpoint(params) //shooting while in shock - var/x_offset = 0 - var/y_offset = 0 - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/mob = user + var/shock_dispersion = 0 + if(ishuman(firer)) + var/mob/living/human/mob = firer if(mob.shock_stage > 120) - y_offset = rand(-2,2) - x_offset = rand(-2,2) + shock_dispersion = rand(-4,4) else if(mob.shock_stage > 70) - y_offset = rand(-1,1) - x_offset = rand(-1,1) + shock_dispersion = rand(-2,2) - var/launched = !P.launch_from_gun(target, user, src, target_zone, x_offset, y_offset) + P.dispersion += shock_dispersion + + var/launched = !P.launch_from_gun(target, target_zone, firer, params) if(launched) - play_fire_sound(user,P) + play_fire_sound(firer, P) return launched -/obj/item/gun/proc/play_fire_sound(var/mob/user, var/obj/item/projectile/P) +/obj/item/gun/proc/play_fire_sound(atom/movable/firer, obj/item/projectile/P) var/shot_sound = fire_sound var/shot_sound_vol = 50 if((istype(P) && P.fire_sound)) shot_sound = P.fire_sound shot_sound_vol = P.fire_sound_vol - if(silenced) - shot_sound_vol = 10 - - playsound(user, shot_sound, shot_sound_vol, 1) + if(silencer) + shot_sound_vol = P.fire_sound_vol_silenced + + playsound(firer, shot_sound, shot_sound_vol, 1) //Suicide handling. /obj/item/gun/var/mouthshoot = 0 //To stop people from suiciding twice... >.> /obj/item/gun/proc/handle_suicide(mob/living/user) if(!ishuman(user)) return - var/mob/living/carbon/human/M = user + var/mob/living/human/M = user mouthshoot = 1 + admin_attacker_log(user, "is attempting to suicide with \a [src]") M.visible_message("[user] sticks their gun in their mouth, ready to pull the trigger...") if(!do_after(user, 40, progress=0)) - M.visible_message("[user] decided life was worth living") + M.visible_message(SPAN_NOTICE("[user] decided life was worth living.")) mouthshoot = 0 return if(safety()) user.visible_message("*click click*", SPAN_DANGER("*click*")) + playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1) mouthshoot = 0 return @@ -463,7 +576,7 @@ if (istype(in_chamber)) user.visible_message("[user] pulls the trigger.") var/shot_sound = in_chamber.fire_sound? in_chamber.fire_sound : fire_sound - if(silenced) + if(silencer) playsound(user, shot_sound, 10, 1) else playsound(user, shot_sound, 50, 1) @@ -473,9 +586,9 @@ return in_chamber.on_hit(M) - if (in_chamber.damage_type != PAIN) + if (in_chamber.atom_damage_type != PAIN) log_and_message_admins("[key_name(user)] commited suicide using \a [src]") - user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, BP_HEAD, in_chamber.damage_flags(), used_weapon = "Point blank shot in the mouth with \a [in_chamber]") + user.apply_damage(in_chamber.damage*2.5, in_chamber.atom_damage_type, BP_HEAD, in_chamber.damage_flags(), used_weapon = "Point blank shot in the mouth with \a [in_chamber]") user.death() else to_chat(user, "Ow...") @@ -520,19 +633,29 @@ accuracy = initial(accuracy) screen_shake = initial(screen_shake) -/obj/item/gun/examine(mob/user) +/obj/item/gun/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(user.skill_check(SKILL_WEAPONS, SKILL_BASIC)) if(firemodes.len > 1) var/datum/firemode/current_mode = firemodes[sel_mode] - to_chat(user, "The fire selector is set to [current_mode.name].") + . += "The fire selector is set to [current_mode.name]." if(has_safety) - to_chat(user, "The safety is [safety() ? "on" : "off"].") + . += "The safety is [safety() ? "on" : "off"]." last_safety_check = world.time -/obj/item/gun/proc/switch_firemodes() +/obj/item/gun/proc/try_switch_firemodes(mob/user) + if(!istype(user) || length(firemodes) <= 1 || !user.check_dexterity(DEXTERITY_WEAPONS)) + return FALSE + var/datum/firemode/new_mode = switch_firemodes() + if(prob(20) && !user.skill_check(SKILL_WEAPONS, SKILL_BASIC)) + new_mode = switch_firemodes() + if(new_mode) + to_chat(user, SPAN_NOTICE("\The [src] is now set to [new_mode.name].")) + return !!new_mode - var/next_mode = get_next_firemode() +/obj/item/gun/proc/switch_firemodes(next_mode) + if(!next_mode) + next_mode = get_next_firemode() if(!next_mode || next_mode == sel_mode) return null @@ -550,13 +673,16 @@ . = 1 /obj/item/gun/attack_self(mob/user) - var/datum/firemode/new_mode = switch_firemodes(user) - if(prob(20) && !user.skill_check(SKILL_WEAPONS, SKILL_BASIC)) - new_mode = switch_firemodes(user) - if(new_mode) - to_chat(user, "\The [src] is now set to [new_mode.name].") + if(try_switch_firemodes(user)) + return TRUE + return ..() /obj/item/gun/proc/toggle_safety(var/mob/user) + if(user && !user.check_dexterity(DEXTERITY_WEAPONS)) + return TRUE + if(!has_safety) + to_chat(user,SPAN_NOTICE("You can't find a safety on \the [src]!")) + return safety_state = !safety_state update_icon() if(user) @@ -571,12 +697,6 @@ if(usr == loc) toggle_safety(usr) -/obj/item/gun/CtrlClick(var/mob/user) - if(loc == user) - toggle_safety(user) - return TRUE - . = ..() - /obj/item/gun/proc/safety() return has_safety && safety_state @@ -589,25 +709,74 @@ last_handled = world.time /obj/item/gun/on_disarm_attempt(mob/target, mob/attacker) - var/list/turfs = list() - for(var/turf/T in view()) - turfs += T - if(turfs.len) + var/list/turfs = view() + if(length(turfs)) var/turf/shoot_to = pick(turfs) - target.visible_message("\The [src] goes off during the struggle!") + target.visible_message(SPAN_DANGER("\The [src] goes off during the struggle!")) afterattack(shoot_to,target) - return 1 + return TRUE + return FALSE /obj/item/gun/proc/can_autofire() - return (can_autofire && world.time >= next_fire_time) + return (autofire_enabled && world.time >= next_fire_time) + +/obj/item/gun/proc/check_accidents(mob/living/user, message = "[user] fumbles with \the [src] and it goes off!",skill_path = SKILL_WEAPONS, fail_chance = 20, no_more_fail = SKILL_EXPERT, factor = 2) + if(istype(user) && !safety() && user.skill_fail_prob(skill_path, fail_chance, no_more_fail, factor) && special_check(user)) + user.visible_message(SPAN_WARNING(message)) + var/list/targets = list(user) + var/turf/checking = get_turf(src) + targets += RANGE_TURFS(checking, 2) + var/picked = pick(targets) + afterattack(picked, user) + return TRUE + return FALSE -/obj/item/gun/proc/check_accidents(mob/living/user, message = "[user] fumbles with the [src] and it goes off!",skill_path = SKILL_WEAPONS, fail_chance = 20, no_more_fail = SKILL_EXPERT, factor = 2) - if(istype(user)) - if(!safety() && user.skill_fail_prob(skill_path, fail_chance, no_more_fail, factor) && special_check(user)) - user.visible_message(SPAN_WARNING(message)) - var/list/targets = list(user) - var/turf/checking = get_turf(src) - targets += RANGE_TURFS(checking, 2) - var/picked = pick(targets) - afterattack(picked, user) - return 1 \ No newline at end of file +/obj/item/gun/handle_reflexive_fire(var/mob/user, var/atom/aiming_at) + . = ..() + if(. && isliving(user)) + var/mob/living/M = user + if(prob(M.skill_fail_chance(SKILL_WEAPONS, 30, SKILL_ADEPT, 3))) + to_chat(user, SPAN_WARNING("You fumble with \the [src], throwing off your aim!")) + M.stop_aiming(src) + else + M.setClickCooldown(DEFAULT_QUICK_COOLDOWN) // Spam prevention, essentially. + M.visible_message(SPAN_DANGER("\The [M] pulls the trigger reflexively!")) + Fire(aiming_at, M) + if(M.aiming) + M.aiming.toggle_active(FALSE, TRUE) + +/mob/proc/can_autofire(var/obj/item/gun/autofiring, var/atom/autofiring_at) + if(!client || !(autofiring_at in view(client.view,src))) + return FALSE + if(get_active_held_item() != autofiring || incapacitated()) + return FALSE + return TRUE + +/obj/item/gun/get_quick_interaction_handler(mob/user) + return GET_DECL(/decl/interaction_handler/gun/toggle_safety) + +/obj/item/gun/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/gun/toggle_safety) + if(length(firemodes) > 1) + LAZYADD(., /decl/interaction_handler/gun/toggle_firemode) + +/decl/interaction_handler/gun + abstract_type = /decl/interaction_handler/gun + expected_target_type = /obj/item/gun + +/decl/interaction_handler/gun/toggle_safety + name = "Toggle Safety" + examine_desc = "toggle the safety" + +/decl/interaction_handler/gun/toggle_safety/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/gun/gun = target + gun.toggle_safety(user) + +/decl/interaction_handler/gun/toggle_firemode + name = "Change Firemode" + examine_desc = "change the firemode" + +/decl/interaction_handler/gun/toggle_firemode/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/gun/gun = target + gun.try_switch_firemodes(user) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 33aa3e901721..7671a3a759ca 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -1,45 +1,42 @@ -GLOBAL_LIST_INIT(registered_weapons, list()) -GLOBAL_LIST_INIT(registered_cyborg_weapons, list()) +var/global/list/registered_weapons = list() +var/global/list/registered_cyborg_weapons = list() /obj/item/gun/energy name = "energy gun" desc = "A basic energy-based gun." icon = 'icons/obj/guns/basic_energy.dmi' - icon_state = "energy" + icon_state = ICON_STATE_WORLD fire_sound = 'sound/weapons/Taser.ogg' fire_sound_text = "laser blast" accuracy = 1 - var/obj/item/cell/power_supply //What type of power cell this uses - var/charge_cost = 20 //How much energy is needed to fire. - var/max_shots = 10 //Determines the capacity of the weapon's power cell. Specifying a cell_type overrides this value. - var/cell_type = null + var/charge_cost = 20 // How much energy is needed to fire. + var/max_shots = 10 // Determines the capacity of the weapon's power cell, if the type is not overridded in setup_power_supply(). + var/modifystate // Changes the icon_state used for the charge overlay. + var/charge_meter = 1 // If set, the icon state will be chosen based on the current charge + var/indicator_color // Color used for overlay based charge meters + var/self_recharge = 0 // If set, the weapon will recharge itself + var/use_external_power = 0 // If set, the weapon will look for an external power source to draw from, otherwise it recharges magically + var/recharge_time = 4 // How many ticks between recharges. + var/charge_tick = 0 // Current charge tick tracker. + + // Which projectile type to create when firing. var/projectile_type = /obj/item/projectile/beam/practice - var/modifystate - var/charge_meter = 1 //if set, the icon state will be chosen based on the current charge - var/indicator_color // color used for overlay based charge meters - //self-recharging - var/self_recharge = 0 //if set, the weapon will recharge itself - var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically - var/recharge_time = 4 - var/charge_tick = 0 +/obj/item/gun/energy/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + accepted_cell_type = accepted_cell_type || loaded_cell_type || /obj/item/cell/device/variable + loaded_cell_type = loaded_cell_type || accepted_cell_type + power_supply_extension_type = power_supply_extension_type || /datum/extension/loaded_cell/unremovable + return ..(loaded_cell_type, accepted_cell_type, power_supply_extension_type, max_shots*charge_cost) /obj/item/gun/energy/switch_firemodes() . = ..() if(.) update_icon() -/obj/item/gun/energy/emp_act(severity) - ..() - update_icon() - -/obj/item/gun/energy/Initialize() +/obj/item/gun/energy/Initialize(var/ml, var/material_key) + setup_power_supply() . = ..() - if(cell_type) - power_supply = new cell_type(src) - else - power_supply = new /obj/item/cell/device/variable(src, max_shots*charge_cost) if(self_recharge) START_PROCESSING(SSobj, src) update_icon() @@ -49,10 +46,8 @@ GLOBAL_LIST_INIT(registered_cyborg_weapons, list()) STOP_PROCESSING(SSobj, src) return ..() -/obj/item/gun/energy/get_cell() - return power_supply - /obj/item/gun/energy/Process() + var/obj/item/cell/power_supply = get_cell() if(self_recharge) //Every [recharge_time] ticks, recharge a shot for the cyborg charge_tick++ if(charge_tick < recharge_time) return 0 @@ -71,9 +66,13 @@ GLOBAL_LIST_INIT(registered_cyborg_weapons, list()) return 1 /obj/item/gun/energy/consume_next_projectile() - if(!power_supply) return null - if(!ispath(projectile_type)) return null - if(!power_supply.checked_use(charge_cost)) return null + var/obj/item/cell/power_supply = get_cell() + if(!power_supply) + return null + if(!ispath(projectile_type)) + return null + if(!power_supply.checked_use(charge_cost)) + return null return new projectile_type(src) /obj/item/gun/energy/proc/get_external_power_supply() @@ -81,20 +80,25 @@ GLOBAL_LIST_INIT(registered_cyborg_weapons, list()) return loc.get_cell() /obj/item/gun/energy/proc/get_shots_remaining() - . = round(power_supply.charge / charge_cost) + var/obj/item/cell/power_supply = get_cell() + if(!power_supply) + return 0 + return round(power_supply.charge / charge_cost) -/obj/item/gun/energy/examine(mob/user) - . = ..(user) +/obj/item/gun/energy/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/obj/item/cell/power_supply = get_cell() if(!power_supply) - to_chat(user, "Seems like it's dead.") + . += "Seems like it's dead." return if (charge_cost == 0) - to_chat(user, "This gun seems to have an unlimited number of shots.") + . += "This gun seems to have an unlimited number of shots." else - to_chat(user, "Has [get_shots_remaining()] shot\s remaining.") + . += "Has [get_shots_remaining()] shot\s remaining." /obj/item/gun/energy/proc/get_charge_ratio() . = 0 + var/obj/item/cell/power_supply = get_cell() if(power_supply) var/ratio = power_supply.percent() //make sure that rounding down will not give us the empty state even if we have charge for a shot left. @@ -102,7 +106,7 @@ GLOBAL_LIST_INIT(registered_cyborg_weapons, list()) if(power_supply.charge < charge_cost) ratio = 0 else - ratio = Clamp(round(ratio, 25), 25, 100) + ratio = clamp(round(ratio, 25), 25, 100) return ratio /obj/item/gun/energy/on_update_icon() @@ -110,20 +114,24 @@ GLOBAL_LIST_INIT(registered_cyborg_weapons, list()) if(charge_meter) update_charge_meter() -/obj/item/gun/energy/experimental_mob_overlay(mob/user_mob, slot) - var/image/I = ..() - if(charge_meter) - I = add_onmob_charge_meter(I) - return I +/obj/item/gun/energy/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && charge_meter) + var/charge_state = get_charge_state(overlay.icon_state) + if(charge_state && check_state_in_icon(charge_state, overlay.icon)) + overlay.overlays += mutable_appearance(overlay.icon, charge_state, get_charge_color()) + . = ..() + +/obj/item/gun/energy/proc/get_charge_state(var/initial_state) + return "[initial_state][get_charge_ratio()]" -/obj/item/gun/energy/proc/add_onmob_charge_meter(image/I) - I.overlays += get_mutable_overlay(icon, "[I.icon_state][get_charge_ratio()]", indicator_color) - return I +/obj/item/gun/energy/proc/get_charge_color() + return indicator_color /obj/item/gun/energy/proc/update_charge_meter() if(use_single_icon) - overlays += get_mutable_overlay(icon, "[get_world_inventory_state()][get_charge_ratio()]", indicator_color) + add_overlay(mutable_appearance(icon, "[get_world_inventory_state()][get_charge_ratio()]", indicator_color)) return + var/obj/item/cell/power_supply = get_cell() if(power_supply) if(modifystate) icon_state = "[modifystate][get_charge_ratio()]" diff --git a/code/modules/projectiles/guns/energy/capacitor.dm b/code/modules/projectiles/guns/energy/capacitor.dm index c0b5a5c2e2b9..ac72d5d1e52b 100644 --- a/code/modules/projectiles/guns/energy/capacitor.dm +++ b/code/modules/projectiles/guns/energy/capacitor.dm @@ -1,4 +1,4 @@ -var/list/laser_wavelengths +var/global/list/laser_wavelengths /decl/laser_wavelength var/name @@ -47,33 +47,41 @@ var/list/laser_wavelengths desc = "An excitingly chunky directed energy weapon that uses a modular capacitor array to charge each shot." icon = 'icons/obj/guns/capacitor_pistol.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':4,'materials':4,'powerstorage':4}" + origin_tech = @'{"combat":4,"materials":4,"powerstorage":4}' w_class = ITEM_SIZE_NORMAL charge_cost = 100 + charge_meter = FALSE accuracy = 2 fire_delay = 10 - slot_flags = SLOT_BELT - cell_type = /obj/item/cell/high + slot_flags = SLOT_LOWER_BODY material = /decl/material/solid/metal/steel projectile_type = /obj/item/projectile/beam/variable matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + z_flags = ZMM_MANGLE_PLANES var/wiring_color = COLOR_CYAN_BLUE var/max_capacitors = 2 - var/list/capacitors = /obj/item/stock_parts/capacitor + var/list/capacitors + var/initial_capacitor_type = /obj/item/stock_parts/capacitor var/const/charge_iteration_delay = 3 var/const/capacitor_charge_constant = 10 - var/decl/laser_wavelength/charging + var/charging var/decl/laser_wavelength/selected_wavelength -/obj/item/gun/energy/capacitor/examine(mob/user, distance) +/obj/item/gun/energy/capacitor/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell/high + accepted_cell_type = accepted_cell_type || /obj/item/cell + power_supply_extension_type = power_supply_extension_type || /datum/extension/loaded_cell/secured + return ..(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + +/obj/item/gun/energy/capacitor/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(loc == user || distance <= 1) - to_chat(user, "The wavelength selector is dialled to [selected_wavelength.name].") - + . += "The wavelength selector is dialled to [selected_wavelength.name]." + /obj/item/gun/energy/capacitor/Destroy() if(capacitors) QDEL_NULL_LIST(capacitors) @@ -82,55 +90,43 @@ var/list/laser_wavelengths /obj/item/gun/energy/capacitor/Initialize() if(!laser_wavelengths) laser_wavelengths = list() - for(var/laser in subtypesof(/decl/laser_wavelength)) - laser_wavelengths += decls_repository.get_decl(laser) + var/list/all_wavelengths = decls_repository.get_decls_of_subtype(/decl/laser_wavelength) + for(var/laser in all_wavelengths) + laser_wavelengths += all_wavelengths[laser] selected_wavelength = pick(laser_wavelengths) - if(ispath(capacitors)) - var/capacitor_type = capacitors + if(!islist(capacitors) && ispath(initial_capacitor_type)) capacitors = list() for(var/i = 1 to max_capacitors) - capacitors += new capacitor_type(src) + capacitors += new initial_capacitor_type(src) . = ..() /obj/item/gun/energy/capacitor/afterattack(atom/A, mob/living/user, adjacent, params) . = !charging && ..() - -/obj/item/gun/energy/capacitor/attackby(obj/item/W, mob/user) + +/obj/item/gun/energy/capacitor/attackby(obj/item/used_item, mob/user) if(charging) return ..() - if(isScrewdriver(W)) + if(IS_SCREWDRIVER(used_item)) + // Unload the cell before the caps. + if(get_cell()) + return ..() if(length(capacitors)) var/obj/item/stock_parts/capacitor/capacitor = capacitors[1] capacitor.charge = 0 user.put_in_hands(capacitor) LAZYREMOVE(capacitors, capacitor) - else if(power_supply) - user.put_in_hands(power_supply) - power_supply = null - else - to_chat(user, SPAN_WARNING("\The [src] does not have a cell or capacitor installed.")) - return TRUE - playsound(loc, 'sound/items/Screwdriver2.ogg', 25) - update_icon() - return TRUE - - if(istype(W, /obj/item/cell)) - if(power_supply) - to_chat(user, SPAN_WARNING("\The [src] already has a cell installed.")) - else if(user.unEquip(W, src)) - power_supply = W - to_chat(user, SPAN_NOTICE("You fit \the [W] into \the [src].")) + playsound(loc, 'sound/items/Screwdriver2.ogg', 25) update_icon() - return TRUE + return TRUE - if(istype(W, /obj/item/stock_parts/capacitor)) + if(istype(used_item, /obj/item/stock_parts/capacitor)) if(length(capacitors) >= max_capacitors) to_chat(user, SPAN_WARNING("\The [src] cannot fit any additional capacitors.")) - else if(user.unEquip(W, src)) - LAZYADD(capacitors, W) - to_chat(user, SPAN_NOTICE("You fit \the [W] into \the [src].")) + else if(user.try_unequip(used_item, src)) + LAZYADD(capacitors, used_item) + to_chat(user, SPAN_NOTICE("You fit \the [used_item] into \the [src].")) update_icon() return TRUE @@ -145,27 +141,25 @@ var/list/laser_wavelengths charging = FALSE else var/new_wavelength = input("Select the desired laser wavelength.", "Capacitor Laser Wavelength", selected_wavelength) as null|anything in global.laser_wavelengths - if(!charging && new_wavelength != selected_wavelength && (loc == user || user.Adjacent(src)) && !user.incapacitated()) + if(!charging && new_wavelength && new_wavelength != selected_wavelength && (loc == user || user.Adjacent(src)) && !user.incapacitated()) selected_wavelength = new_wavelength to_chat(user, SPAN_NOTICE("You dial \the [src] wavelength to [selected_wavelength.name].")) update_icon() return TRUE -/obj/item/gun/energy/capacitor/Process() - . = ..() - /obj/item/gun/energy/capacitor/proc/charge(var/mob/user) . = FALSE if(!charging && istype(user)) - charging = selected_wavelength + charging = TRUE playsound(loc, 'sound/effects/capacitor_whine.ogg', 100, 0) - while(!QDELETED(user) && length(capacitors) && charging && user.get_active_hand() == src) + while(!QDELETED(user) && length(capacitors) && charging && user.get_active_held_item() == src) var/charged = TRUE for(var/obj/item/stock_parts/capacitor/capacitor in capacitors) if(capacitor.charge < capacitor.max_charge) charged = FALSE + var/obj/item/cell/power_supply = get_cell() var/use_charge_cost = min(charge_cost * capacitor.rating, round((capacitor.max_charge - capacitor.charge) / capacitor_charge_constant)) - if(power_supply.use(use_charge_cost)) + if(power_supply?.use(use_charge_cost)) capacitor.charge(use_charge_cost * capacitor_charge_constant) update_icon() else @@ -174,22 +168,23 @@ var/list/laser_wavelengths if(charged) . = TRUE break - sleep(5) + sleep(charge_iteration_delay) charging = FALSE /obj/item/gun/energy/capacitor/get_shots_remaining() var/total_charge_cost = 0 for(var/obj/item/stock_parts/capacitor/capacitor in capacitors) total_charge_cost += capacitor.max_charge + var/obj/item/cell/power_supply = get_cell() . = round(power_supply?.charge / (total_charge_cost / capacitor_charge_constant)) /obj/item/gun/energy/capacitor/on_update_icon() - cut_overlays() + . = ..() var/image/I = image(icon, "[icon_state]-wiring") I.color = wiring_color I.appearance_flags |= RESET_COLOR add_overlay(I) - if(power_supply) + if(get_cell()) I = image(icon, "[icon_state]-cell") add_overlay(I) @@ -198,54 +193,48 @@ var/list/laser_wavelengths I = image(icon, "[icon_state]-capacitor-[i]") add_overlay(I) if(capacitor.charge > 0) - I = image(icon, "[icon_state]-charging-[i]") - I.alpha = Clamp(255 * (capacitor.charge/capacitor.max_charge), 0, 255) - I.color = selected_wavelength.color if(icon_state == "world") - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - I.layer = ABOVE_LIGHTING_LAYER + I = emissive_overlay(icon, "[icon_state]-charging-[i]") + else + I = image(icon, "[icon_state]-charging-[i]") + I.alpha = clamp(255 * (capacitor.charge/capacitor.max_charge), 0, 255) + I.color = selected_wavelength.color I.appearance_flags |= RESET_COLOR add_overlay(I) - I = image(icon, "[icon_state]-charging-glow-[i]") if(icon_state == "world") - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - I.layer = ABOVE_LIGHTING_LAYER + I = emissive_overlay(icon, "[icon_state]-charging-glow-[i]") + else + I = image(icon, "[icon_state]-charging-glow-[i]") I.appearance_flags |= RESET_COLOR add_overlay(I) - // So much of this item is overlay based that it looks weird when + // So much of this item is overlay based that it looks weird when // being picked up and having all the detail snap in a tick later. - compile_overlays() + compile_overlays() if(ismob(loc)) var/mob/M = loc - if(M.l_hand == src) - M.update_inv_l_hand() - else if(M.r_hand == src) - M.update_inv_r_hand() - -/obj/item/gun/energy/capacitor/get_mob_overlay(mob/user_mob, slot) - var/image/ret = ..() - if(slot == slot_l_hand_str || slot == slot_r_hand_str || slot == slot_back_str) - var/image/I = image(icon, "[ret.icon_state]-wiring") + M.update_inhand_overlays() + +/obj/item/gun/energy/capacitor/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + ..() + if(overlay && (slot == BP_L_HAND || slot == BP_R_HAND || slot == slot_back_str)) + var/image/I = image(overlay.icon, "[overlay.icon_state]-wiring") I.color = wiring_color I.appearance_flags |= RESET_COLOR - ret.add_overlay(I) - if(power_supply) - I = image(icon, "[ret.icon_state]-cell") - ret.add_overlay(I) - if(slot != slot_back_str) - for(var/i = 1 to length(capacitors)) - var/obj/item/stock_parts/capacitor/capacitor = capacitors[i] - if(capacitor.charge > 0) - I = image(icon, "[ret.icon_state]-charging-[i]") - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - I.layer = ABOVE_LIGHTING_LAYER - I.alpha = Clamp(255 * (capacitor.charge/capacitor.max_charge), 0, 255) - I.color = selected_wavelength.color - I.appearance_flags |= RESET_COLOR - ret.add_overlay(I) - . = ret + overlay.add_overlay(I) + if(get_cell()) + I = image(overlay.icon, "[overlay.icon_state]-cell") + overlay.add_overlay(I) + for(var/i = 1 to length(capacitors)) + var/obj/item/stock_parts/capacitor/capacitor = capacitors[i] + if(capacitor.charge > 0) + I = emissive_overlay(overlay.icon, "[overlay.icon_state]-charging-[i]") + I.alpha = clamp(255 * (capacitor.charge/capacitor.max_charge), 0, 255) + I.color = selected_wavelength.color + I.appearance_flags |= RESET_COLOR + overlay.overlays += I + return overlay /obj/item/gun/energy/capacitor/consume_next_projectile() @@ -258,37 +247,40 @@ var/list/laser_wavelengths if(charged) var/obj/item/projectile/P = new projectile_type(src) - P.color = selected_wavelength.color + P.set_color(selected_wavelength.color) P.set_light(l_color = selected_wavelength.light_color) - P.damage = Floor(sqrt(total_charge) * selected_wavelength.damage_multiplier) - P.armor_penetration = Floor(sqrt(total_charge) * selected_wavelength.armour_multiplier) + P.damage = floor(sqrt(total_charge) * selected_wavelength.damage_multiplier) + P.armor_penetration = floor(sqrt(total_charge) * selected_wavelength.armour_multiplier) . = P // Subtypes. /obj/item/gun/energy/capacitor/rifle name = "capacitor rifle" - desc = "A heavy, unwieldly directed energy weapon that uses a linear capacitor array to charge a powerful beam." + desc = "A heavy, unwieldy directed energy weapon that uses a linear capacitor array to charge a powerful beam." max_capacitors = 4 icon = 'icons/obj/guns/capacitor_rifle.dmi' slot_flags = SLOT_BACK one_hand_penalty = 6 fire_delay = 20 w_class = ITEM_SIZE_HUGE - cell_type = /obj/item/cell/super + +/obj/item/gun/energy/capacitor/rifle/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + loaded_cell_type = loaded_cell_type || /obj/item/cell/super + return ..(loaded_cell_type, accepted_cell_type, /datum/extension/loaded_cell, charge_value) /obj/item/gun/energy/capacitor/rifle/linear_fusion name = "linear fusion rifle" desc = "A chunky, angular, carbon-fiber-finish capacitor rifle, shipped complete with a self-charging power cell. The operating instructions seem to be written in backwards Cyrillic." color = COLOR_GRAY40 - cell_type = /obj/item/cell/infinite - capacitors = /obj/item/stock_parts/capacitor/super + initial_capacitor_type = /obj/item/stock_parts/capacitor/super projectile_type = /obj/item/projectile/beam/variable/split wiring_color = COLOR_GOLD -/obj/item/gun/energy/capacitor/rifle/linear_fusion/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) +/obj/item/gun/energy/capacitor/rifle/linear_fusion/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/infinite, accepted_cell_type, /datum/extension/loaded_cell/unremovable, charge_value) + +/obj/item/gun/energy/capacitor/rifle/linear_fusion/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) to_chat(user, SPAN_WARNING("\The [src] is hermetically sealed; you can't get the components out.")) return TRUE . = ..() - - diff --git a/code/modules/projectiles/guns/energy/ebow.dm b/code/modules/projectiles/guns/energy/ebow.dm index 27b08be70c63..74b5d718c48c 100644 --- a/code/modules/projectiles/guns/energy/ebow.dm +++ b/code/modules/projectiles/guns/energy/ebow.dm @@ -5,10 +5,10 @@ icon = 'icons/obj/guns/energy_crossbow.dmi' icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_NORMAL - origin_tech = "{'combat':2,'magnets':2,'esoteric':5}" + origin_tech = @'{"combat":2,"magnets":2,"esoteric":5}' material = /decl/material/solid/metal/steel - slot_flags = SLOT_BELT - silenced = 1 + slot_flags = SLOT_LOWER_BODY + silencer = TRUE fire_sound = 'sound/weapons/Genhit.ogg' projectile_type = /obj/item/projectile/energy/bolt max_shots = 8 @@ -16,20 +16,11 @@ charge_meter = 0 combustion = 0 -/obj/item/gun/energy/crossbow/ninja - name = "energy dart thrower" - projectile_type = /obj/item/projectile/energy/dart - max_shots = 5 - -/obj/item/gun/energy/crossbow/ninja/mounted - use_external_power = 1 - has_safety = FALSE - /obj/item/gun/energy/crossbow/largecrossbow name = "energy crossbow" desc = "A weapon favored by mercenary infiltration teams." w_class = ITEM_SIZE_LARGE - force = 10 + _base_attack_force = 10 one_hand_penalty = 1 material = /decl/material/solid/metal/steel projectile_type = /obj/item/projectile/energy/bolt/large diff --git a/code/modules/projectiles/guns/energy/egun.dm b/code/modules/projectiles/guns/energy/egun.dm index c5e74881d672..2e2de1a943d8 100644 --- a/code/modules/projectiles/guns/energy/egun.dm +++ b/code/modules/projectiles/guns/energy/egun.dm @@ -9,7 +9,7 @@ fire_delay = 10 // To balance for the fact that it is a pistol and can be used one-handed without penalty projectile_type = /obj/item/projectile/beam/stun - origin_tech = "{'combat':3,'magnets':2}" + origin_tech = @'{"combat":3,"magnets":2}' indicator_color = COLOR_CYAN firemodes = list( @@ -25,7 +25,7 @@ icon_state = ICON_STATE_WORLD max_shots = 5 w_class = ITEM_SIZE_SMALL - force = 2 //it's the size of a car key, what did you expect? + _base_attack_force = 2 //it's the size of a car key, what did you expect? firemodes = list( list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun, indicator_color=COLOR_CYAN), @@ -37,4 +37,11 @@ name = "mounted energy gun" self_recharge = 1 use_external_power = 1 - has_safety = FALSE \ No newline at end of file + has_safety = FALSE + +/obj/item/gun/energy/gun/reloadable + name = "reloadable energy gun" + desc = "Another bestseller of Lawson Arms and the FTU, the LAEP90 Perun is a versatile energy based sidearm, capable of switching between low, medium and high power projectile settings. In other words: stun, shock or kill." + +/obj/item/gun/energy/gun/reloadable/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/gun, /obj/item/cell/gun, /datum/extension/loaded_cell, charge_value) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 8a1b3e8396b8..a9af3a3c1e46 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -3,14 +3,18 @@ desc = "A G40E carbine, designed to kill with concentrated energy blasts." icon = 'icons/obj/guns/laser_carbine.dmi' icon_state = ICON_STATE_WORLD - slot_flags = SLOT_BELT|SLOT_BACK + slot_flags = SLOT_LOWER_BODY|SLOT_BACK w_class = ITEM_SIZE_LARGE - force = 10 + _base_attack_force = 10 one_hand_penalty = 2 bulk = GUN_BULK_RIFLE - origin_tech = "{'combat':3,'magnets':2}" + origin_tech = @'{"combat":3,"magnets":2}' material = /decl/material/solid/metal/steel projectile_type = /obj/item/projectile/beam/midlaser + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT + ) /obj/item/gun/energy/laser/mounted self_recharge = 1 @@ -26,7 +30,7 @@ /obj/item/gun/energy/laser/practice/on_update_icon() . = ..() - overlays += get_mutable_overlay(icon, "[icon_state]_stripe", COLOR_ORANGE) + add_overlay(mutable_appearance(icon, "[icon_state]_stripe", COLOR_ORANGE)) /obj/item/gun/energy/laser/practice/proc/hacked() return projectile_type != /obj/item/projectile/beam/practice @@ -34,44 +38,53 @@ /obj/item/gun/energy/laser/practice/emag_act(var/remaining_charges, var/mob/user, var/emag_source) if(hacked()) return NO_EMAG_ACT - to_chat(user, "You disable the safeties on [src] and crank the output to the lethal levels.") + to_chat(user, SPAN_WARNING("You disable the safeties on [src] and crank the output to the lethal levels.")) desc += " Its safeties are disabled and output is set to dangerous levels." projectile_type = /obj/item/projectile/beam/midlaser charge_cost = 20 max_shots = rand(3,6) //will melt down after those return 1 -/obj/item/gun/energy/laser/practice/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0) +/obj/item/gun/energy/laser/practice/handle_post_fire(atom/movable/firer, atom/target, var/pointblank=0, var/reflex=0) ..() if(hacked()) max_shots-- if(!max_shots) //uh hoh gig is up - to_chat(user, "\The [src] sizzles in your hands, acrid smoke rising from the firing end!") + to_chat(firer, SPAN_DANGER("\The [src] sizzles in your hands, acrid smoke rising from the firing end!")) desc += " The optical pathway is melted and useless." projectile_type = null -/obj/item/gun/energy/captain - name = "antique laser gun" +/obj/item/gun/energy/retro + name = "retro laser pistol" icon = 'icons/obj/guns/caplaser.dmi' + desc = "A now-obsolete handheld laser weapon, still popular with some for ease of maintenance." icon_state = ICON_STATE_WORLD - desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well." - force = 5 - slot_flags = SLOT_BELT //too unusually shaped to fit in a holster w_class = ITEM_SIZE_NORMAL projectile_type = /obj/item/projectile/beam origin_tech = null max_shots = 5 //to compensate a bit for self-recharging one_hand_penalty = 1 //a little bulky + +/obj/item/gun/energy/retro/empty/Initialize(ml, material_key) + . = ..() + var/obj/item/cell/cell = get_cell() + if(cell) + cell.charge = 0 + update_icon() + +/obj/item/gun/energy/retro/captain + name = "antique laser gun" + desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well." self_recharge = 1 + slot_flags = SLOT_LOWER_BODY //too unusually shaped to fit in a holster /obj/item/gun/energy/lasercannon name = "laser cannon" desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!" - icon_state = "lasercannon" icon = 'icons/obj/guns/laser_cannon.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':4,'materials':3,'powerstorage':3}" - slot_flags = SLOT_BELT|SLOT_BACK + origin_tech = @'{"combat":4,"materials":3,"powerstorage":3}' + slot_flags = SLOT_LOWER_BODY|SLOT_BACK one_hand_penalty = 6 //large and heavy w_class = ITEM_SIZE_HUGE projectile_type = /obj/item/projectile/beam/heavylaser @@ -81,7 +94,7 @@ fire_delay = 20 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) @@ -93,3 +106,10 @@ accuracy = 0 //mounted laser cannons don't need any help, thanks one_hand_penalty = 0 has_safety = FALSE + +/obj/item/gun/energy/laser/reloadable + name = "reloadable laser carbine" + desc = "A G40E carbine, designed to kill with concentrated energy blasts. Uses removable energy cells." + +/obj/item/gun/energy/laser/reloadable/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/gun, /obj/item/cell/gun, /datum/extension/loaded_cell, charge_value) diff --git a/code/modules/projectiles/guns/energy/laser_sniper.dm b/code/modules/projectiles/guns/energy/laser_sniper.dm index bc037c6c4a02..18fdd794070f 100644 --- a/code/modules/projectiles/guns/energy/laser_sniper.dm +++ b/code/modules/projectiles/guns/energy/laser_sniper.dm @@ -4,14 +4,14 @@ desc = "The HI DMR 9E is an older design. A designated marksman rifle capable of shooting powerful ionized beams, this is a weapon to kill from a distance." icon = 'icons/obj/guns/laser_sniper.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':6,'materials':5,'powerstorage':4}" + origin_tech = @'{"combat":6,"materials":5,"powerstorage":4}' projectile_type = /obj/item/projectile/beam/sniper one_hand_penalty = 5 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand. slot_flags = SLOT_BACK charge_cost = 40 max_shots = 4 fire_delay = 35 - force = 10 + _base_attack_force = 10 w_class = ITEM_SIZE_HUGE accuracy = -2 //shooting at the hip scoped_accuracy = 9 diff --git a/code/modules/projectiles/guns/energy/lasertag.dm b/code/modules/projectiles/guns/energy/lasertag.dm index 5fd1c76e41e9..fd6af12baa06 100644 --- a/code/modules/projectiles/guns/energy/lasertag.dm +++ b/code/modules/projectiles/guns/energy/lasertag.dm @@ -4,17 +4,16 @@ icon = 'icons/obj/guns/laser_carbine.dmi' icon_state = ICON_STATE_WORLD desc = "Standard issue weapon of the Imperial Guard." - origin_tech = "{'combat':1,'magnets':2}" + origin_tech = @'{"combat":1,"magnets":2}' self_recharge = 1 material = /decl/material/solid/metal/steel projectile_type = /obj/item/projectile/beam/lastertag/blue var/required_vest -/obj/item/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M) - if(ishuman(M)) - if(!istype(M.wear_suit, required_vest)) - to_chat(M, "You need to be wearing your laser tag vest!") - return 0 +/obj/item/gun/energy/lasertag/special_check(var/mob/living/human/M) + if(ishuman(M) && !istype(M.get_equipped_item(slot_wear_suit_str), required_vest)) + to_chat(M, SPAN_WARNING("You need to be wearing your laser tag vest!")) + return FALSE return ..() /obj/item/gun/energy/lasertag/blue diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index 68b5de97b7ff..696f4594eb92 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -2,15 +2,15 @@ name = "advanced energy gun" desc = "An energy gun with an experimental miniaturized reactor." icon = 'icons/obj/guns/adv_egun.dmi' - origin_tech = "{'combat':3,'materials':5,'powerstorage':3}" - slot_flags = SLOT_BELT + origin_tech = @'{"combat":3,"materials":5,"powerstorage":3}' + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_LARGE - force = 8 //looks heavier than a pistol + _base_attack_force = 8 //looks heavier than a pistol self_recharge = 1 one_hand_penalty = 1 //bulkier than an e-gun, but not quite the size of a carbine material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) @@ -40,7 +40,7 @@ if(ismob(loc)) to_chat(loc, "\The [src] feels pleasantly warm.") -/obj/item/gun/energy/gun/nuclear/proc/get_charge_color() +/obj/item/gun/energy/gun/nuclear/get_charge_color() switch(get_charge_ratio()) if(25) return COLOR_RED @@ -54,15 +54,10 @@ /obj/item/gun/energy/gun/nuclear/on_update_icon() indicator_color = get_charge_color() . = ..() - var/list/new_overlays = list() - var/reactor_icon = fail_counter ? "danger" : "clean" - new_overlays += get_mutable_overlay(icon, "[get_world_inventory_state()]_[reactor_icon]") + add_overlay("[get_world_inventory_state()]_[reactor_icon]") var/datum/firemode/current_mode = firemodes[sel_mode] - new_overlays += get_mutable_overlay(icon, "[get_world_inventory_state()]_[current_mode.name]") - - overlays += new_overlays + add_overlay("[get_world_inventory_state()]_[current_mode.name]") -/obj/item/gun/energy/gun/nuclear/add_onmob_charge_meter(image/I) - I.overlays += get_mutable_overlay(icon, "[I.icon_state]_charge", get_charge_color()) - return I \ No newline at end of file +/obj/item/gun/energy/gun/nuclear/get_charge_state(var/initial_state) + return "[initial_state]_charge" diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index 20b496ae1bff..d9258107771d 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -5,16 +5,13 @@ icon = 'icons/obj/guns/pulse_pistol.dmi' icon_state = ICON_STATE_WORLD indicator_color = COLOR_LUMINOL - slot_flags = SLOT_BELT|SLOT_HOLSTER - force = 6 + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER + _base_attack_force = 6 projectile_type = /obj/item/projectile/beam/pulse max_shots = 21 w_class = ITEM_SIZE_NORMAL one_hand_penalty=1 //a bit heavy - burst_delay = 1 - multi_aim = 1 burst_delay = 3 burst = 3 accuracy = -1 - wielded_item_state = null bulk = 0 diff --git a/code/modules/projectiles/guns/energy/secure.dm b/code/modules/projectiles/guns/energy/secure.dm index 6b6fae6bd5e5..c8df1f2ea053 100644 --- a/code/modules/projectiles/guns/energy/secure.dm +++ b/code/modules/projectiles/guns/energy/secure.dm @@ -21,21 +21,22 @@ one_hand_penalty = 0 has_safety = FALSE item_flags = ITEM_FLAG_INVALID_FOR_CHAMELEON + is_spawnable_type = FALSE // Do not manually spawn this, it will runtime/break. /obj/item/gun/energy/gun/secure/mounted/Initialize() - var/mob/borg = get_holder_of_type(src, /mob/living/silicon/robot) + var/mob/borg = get_recursive_loc_of_type(/mob/living/silicon/robot) if(!borg) . = INITIALIZE_HINT_QDEL CRASH("Invalid spawn location.") registered_owner = borg.name - GLOB.registered_cyborg_weapons += src + global.registered_cyborg_weapons += src . = ..() /obj/item/gun/energy/laser/secure name = "laser carbine" - desc = "A G40E carbine, designed to kill with concentrated energy blasts. Fitted with an NT1019 chip to make sure killcount is tracked appropriately." + desc = "A G40E carbine, designed to kill with concentrated energy blasts. Fitted with an NT1019 chip to make sure kill count is tracked appropriately." req_access = list(list(access_brig, access_bridge)) /obj/item/gun/energy/laser/secure/on_update_icon() . = ..() - overlays += get_mutable_overlay(icon, "[icon_state]_stripe", COLOR_BLUE_GRAY) \ No newline at end of file + add_overlay(mutable_appearance(icon, "[icon_state]_stripe", COLOR_BLUE_GRAY)) diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index af6fde7b0c25..d69f9bdef703 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -3,9 +3,9 @@ desc = "The Mk60 EW Halicon is a man portable anti-armor weapon designed to disable mechanical threats. Not the best of its type." icon = 'icons/obj/guns/ion_rifle.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':2,'magnets':4}" + origin_tech = @'{"combat":2,"magnets":4}' w_class = ITEM_SIZE_HUGE - force = 10 + _base_attack_force = 10 obj_flags = OBJ_FLAG_CONDUCTIBLE slot_flags = SLOT_BACK one_hand_penalty = 4 @@ -14,16 +14,27 @@ fire_delay = 30 projectile_type = /obj/item/projectile/ion combustion = 0 + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/metal/uranium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT + ) /obj/item/gun/energy/ionrifle/emp_act(severity) ..(max(severity, 2)) //so it doesn't EMP itself, I guess +/obj/item/gun/energy/ionrifle/mounted + name = "mounted ion gun" + self_recharge = TRUE + use_external_power = TRUE + has_safety = FALSE + /obj/item/gun/energy/decloner name = "biological demolecularisor" desc = "A gun that discharges high amounts of controlled radiation to slowly break a target into component elements." icon = 'icons/obj/guns/decloner.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':5,'materials':4,'powerstorage':3}" + origin_tech = @'{"combat":5,"materials":4,"powerstorage":3}' max_shots = 10 projectile_type = /obj/item/projectile/energy/declone combustion = 0 @@ -38,11 +49,11 @@ charge_cost = 10 max_shots = 10 projectile_type = /obj/item/projectile/energy/floramut - origin_tech = "{'materials':2,'biotech':3,'powerstorage':3}" + origin_tech = @'{"materials":2,"biotech":3,"powerstorage":3}' self_recharge = 1 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) combustion = 0 @@ -51,11 +62,10 @@ list(mode_name="increase yield", projectile_type=/obj/item/projectile/energy/florayield, indicator_color=COLOR_YELLOW), list(mode_name="induce specific mutations", projectile_type=/obj/item/projectile/energy/floramut/gene, indicator_color=COLOR_LIME), ) - var/decl/plantgene/gene = null + var/decl/plant_gene/gene = null -/obj/item/gun/energy/floragun/add_onmob_charge_meter(image/I) - I.overlays += get_mutable_overlay(icon, "[I.icon_state]100", indicator_color) - return I +/obj/item/gun/energy/floragun/get_charge_state(var/initial_state) + return "[initial_state]100" /obj/item/gun/energy/floragun/resolve_attackby(atom/A) if(istype(A,/obj/machinery/portable_atmospherics/hydroponics)) @@ -75,16 +85,10 @@ set category = "Object" set src in view(1) - var/genemask = input("Choose a gene to modify.") as null|anything in SSplants.plant_gene_datums - - if(!genemask) - return - - gene = SSplants.plant_gene_datums[genemask] - - to_chat(usr, "You set the [src]'s targeted genetic area to [genemask].") - - return + var/decl/plant_gene/new_gene = input("Choose a gene to modify.") as null|anything in decls_repository.get_decls_of_type_unassociated(/decl/plant_gene) + if(istype(new_gene)) + gene = new_gene + to_chat(usr, SPAN_INFO("You set the \the [src]'s targeted genetic area to [gene.name].")) /obj/item/gun/energy/floragun/consume_next_projectile() . = ..() @@ -98,11 +102,11 @@ icon = 'icons/obj/guns/toxgun.dmi' icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_NORMAL - origin_tech = "{'combat':5,'exoticmatter':4}" + origin_tech = @'{"combat":5,"exoticmatter":4}' projectile_type = /obj/item/projectile/energy/radiation material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) @@ -113,21 +117,24 @@ icon = 'icons/obj/guns/plasmacutter.dmi' icon_state = ICON_STATE_WORLD fire_sound = 'sound/weapons/plasma_cutter.ogg' - slot_flags = SLOT_BELT|SLOT_BACK + slot_flags = SLOT_LOWER_BODY|SLOT_BACK w_class = ITEM_SIZE_NORMAL - force = 8 - origin_tech = "{'materials':4,'exoticmatter':4,'engineering':6,'combat':3}" + _base_attack_force = 8 + origin_tech = @'{"materials":4,"exoticmatter":4,"engineering":6,"combat":3}' material = /decl/material/solid/metal/steel projectile_type = /obj/item/projectile/beam/plasmacutter max_shots = 10 self_recharge = 1 - material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) - var/datum/effect/effect/system/spark_spread/spark_system + +/obj/item/gun/energy/plasmacutter/Initialize() + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_SAW = TOOL_QUALITY_BAD)) + set_extension(src, /datum/extension/demolisher/energy) /obj/item/gun/energy/plasmacutter/get_heat() . = max(..(), 3800) @@ -138,28 +145,19 @@ max_shots = 4 has_safety = FALSE -/obj/item/gun/energy/plasmacutter/Initialize() - . = ..() - spark_system = new /datum/effect/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) - -/obj/item/gun/energy/plasmacutter/Destroy() - QDEL_NULL(spark_system) - return ..() - /obj/item/gun/energy/plasmacutter/proc/slice(var/mob/M = null) - if(!safety() && power_supply.checked_use(charge_cost)) //consumes a shot per use + var/obj/item/cell/power_supply = get_cell() + if(!safety() && power_supply?.checked_use(charge_cost)) //consumes a shot per use if(M) M.welding_eyecheck()//Welding tool eye check if(check_accidents(M, "[M] loses grip on [src] from its sudden recoil!",SKILL_CONSTRUCTION, 60, SKILL_ADEPT)) - return 0 - spark_system.start() - return 1 + return FALSE + spark_at(src, amount = 5, holder = src) + return TRUE handle_click_empty(M) - return 0 + return FALSE -/obj/item/gun/energy/plasmacutter/is_special_cutting_tool() +/obj/item/gun/energy/plasmacutter/is_special_cutting_tool(var/high_power) return TRUE /obj/item/gun/energy/incendiary_laser @@ -168,10 +166,10 @@ icon = 'icons/obj/guns/incendiary_laser.dmi' icon_state = ICON_STATE_WORLD safety_icon = "safety" - origin_tech = "{'combat':7,'magnets':4,'esoteric':4}" + origin_tech = @'{"combat":7,"magnets":4,"esoteric":4}' material = /decl/material/solid/metal/aluminium matter = list( - /decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) projectile_type = /obj/item/projectile/beam/incendiary_laser diff --git a/code/modules/projectiles/guns/energy/staves.dm b/code/modules/projectiles/guns/energy/staves.dm index b3cb5ec4626f..965c8f208e07 100644 --- a/code/modules/projectiles/guns/energy/staves.dm +++ b/code/modules/projectiles/guns/energy/staves.dm @@ -5,22 +5,21 @@ icon_state = ICON_STATE_WORLD fire_sound = 'sound/weapons/emitter.ogg' obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT|SLOT_BACK + slot_flags = SLOT_LOWER_BODY|SLOT_BACK w_class = ITEM_SIZE_LARGE max_shots = 5 projectile_type = /obj/item/projectile/change origin_tech = null self_recharge = 1 charge_meter = 0 - var/required_antag_type = MODE_WIZARD + has_safety = FALSE + var/required_antag_type /obj/item/gun/energy/staff/special_check(var/mob/user) - if(required_antag_type) - var/datum/antagonist/antag = get_antag_data(required_antag_type) - if(user.mind && !antag.is_antagonist(user.mind)) - to_chat(usr, "You focus your mind on \the [src], but nothing happens!") - return 0 - + var/decl/special_role/antag = GET_DECL(required_antag_type) + if(user.mind && (!antag?.is_antagonist(user.mind))) + to_chat(user, SPAN_WARNING("You focus your mind on \the [src], but nothing happens!")) + return FALSE return ..() /obj/item/gun/energy/staff/handle_click_empty(mob/user = null) @@ -42,3 +41,9 @@ desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out." icon = 'icons/obj/guns/focus_staff.dmi' projectile_type = /obj/item/projectile/forcebolt + +/obj/item/gun/energy/staff/fire + name = "flaming staff" + desc = "A long, everburning torch." + icon = 'icons/obj/guns/fire_staff.dmi' + projectile_type = /obj/item/projectile/firebolt diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index e84d8628c956..75de92c76f3e 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -8,11 +8,15 @@ max_shots = 5 projectile_type = /obj/item/projectile/beam/stun combustion = 0 - firemodes = list( list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun), list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock), ) + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, + ) /obj/item/gun/energy/taser/mounted name = "mounted electrolaser" @@ -30,7 +34,7 @@ desc = "The Mars Military Industries MA21 Selkie is a weapon that uses a laser pulse to ionise the local atmosphere, creating a disorienting pulse of plasma and deafening shockwave as the wave expands." icon = 'icons/obj/guns/plasma_stun.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':2,'materials':2,'powerstorage':3}" + origin_tech = @'{"combat":2,"materials":2,"powerstorage":3}' fire_delay = 20 max_shots = 4 projectile_type = /obj/item/projectile/energy/plasmastun @@ -43,10 +47,10 @@ icon = 'icons/obj/guns/confuseray.dmi' icon_state = ICON_STATE_WORLD safety_icon = "safety" - origin_tech = "{'combat':2,'materials':2,'powerstorage':2}" + origin_tech = @'{"combat":2,"materials":2,"powerstorage":2}' w_class = ITEM_SIZE_SMALL max_shots = 4 projectile_type = /obj/item/projectile/beam/confuseray combustion = 0 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm index eff52b9387b2..414aa4a3ccdb 100644 --- a/code/modules/projectiles/guns/energy/temperature.dm +++ b/code/modules/projectiles/guns/energy/temperature.dm @@ -6,19 +6,21 @@ desc = "A gun that changes temperatures. It has a small label on the side, 'More extreme temperatures will cost more charge!'" material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) charge_cost = 10 - origin_tech = "{'combat':3,'materials':4,'powerstorage':3,'magnets':2}" - slot_flags = SLOT_BELT|SLOT_BACK + origin_tech = @'{"combat":3,"materials":4,"powerstorage":3,"magnets":2}' + slot_flags = SLOT_LOWER_BODY|SLOT_BACK one_hand_penalty = 2 projectile_type = /obj/item/projectile/temp - cell_type = /obj/item/cell/high combustion = 0 + indicator_color = COLOR_GREEN var/firing_temperature = T20C var/current_temperature = T20C - indicator_color = COLOR_GREEN + +/obj/item/gun/energy/temperature/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/high, /obj/item/cell, power_supply_extension_type, charge_value) /obj/item/gun/energy/temperature/Initialize() . = ..() @@ -30,7 +32,7 @@ . = ..() -/obj/item/gun/energy/temperature/attack_self(mob/living/user) +/obj/item/gun/energy/temperature/attack_self(mob/user) user.set_machine(src) var/temp_text = "" if(firing_temperature > (T0C - 50)) @@ -40,14 +42,14 @@ var/dat = {"Freeze Gun Configuration:
    Current output temperature: [temp_text]
    - Target output temperature: - - - [current_temperature] + + +
    + Target output temperature: - - - [current_temperature] + + +
    "} show_browser(user, dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1") onclose(user, "window=freezegun", src) -/obj/item/gun/energy/temperature/Topic(user, href_list, state = GLOB.inventory_state) - ..() +/obj/item/gun/energy/temperature/DefaultTopicState() + return global.inventory_topic_state /obj/item/gun/energy/temperature/OnTopic(user, href_list) if(href_list["temp"]) diff --git a/code/modules/projectiles/guns/energy/vox.dm b/code/modules/projectiles/guns/energy/vox.dm deleted file mode 100644 index f359dea1406f..000000000000 --- a/code/modules/projectiles/guns/energy/vox.dm +++ /dev/null @@ -1,58 +0,0 @@ -/datum/extension/voxform - base_type = /datum/extension/voxform - -/datum/extension/voxform/proc/check_held_user(var/mob/living/carbon/human/user, var/atom/movable/thing) - if(!istype(user)) - return FALSE - return TRUE - -/obj/item/gun/special_check(var/mob/living/carbon/human/user) - . = ..() - if(!QDELETED(src) && src.loc == user && has_extension(src, /datum/extension/voxform)) - var/datum/extension/voxform/voxform = get_extension(src, /datum/extension/voxform) - . = voxform.check_held_user(user, src) - -/* - * Vox Darkmatter Cannon - */ -/obj/item/gun/energy/darkmatter - name = "flux cannon" - desc = "A vicious beam weapon that crushes targets with dark-matter gravity pulses. Parts of it twitch and writhe, as if alive." - icon = 'icons/obj/guns/darkcannon.dmi' - item_state = "world" - w_class = ITEM_SIZE_LARGE - projectile_type = /obj/item/projectile/beam/stun/darkmatter - one_hand_penalty = 2 //a little bulky - self_recharge = 1 - firemodes = list( - list(mode_name="stunning", burst=1, fire_delay=null, burst_accuracy=list(30), dispersion=null, projectile_type=/obj/item/projectile/beam/stun/darkmatter, charge_cost = 50), - list(mode_name="focused", burst=1, fire_delay=null, burst_accuracy=list(30), dispersion=null, projectile_type=/obj/item/projectile/beam/darkmatter, charge_cost = 75), - list(mode_name="scatter burst", burst=8, fire_delay=null, burst_accuracy=list(0, 0, 0, 0, 0, 0, 0, 0), dispersion=list(0, 1, 2, 2, 3, 3, 3, 3, 3), projectile_type=/obj/item/projectile/energy/darkmatter, charge_cost = 10), - ) - -/obj/item/gun/energy/darkmatter/Initialize() - . = ..() - set_extension(src, /datum/extension/voxform) - -/* - * Vox Sonic Cannon - */ -/obj/item/gun/energy/sonic - name = "soundcannon" - desc = "A vicious sonic weapon of alien manufacture. Parts of it quiver gelatinously, as though the insectile-looking thing is alive." - icon = 'icons/obj/guns/noise.dmi' - item_state = "world" - w_class = ITEM_SIZE_LARGE - one_hand_penalty = 1 - self_recharge = 1 - recharge_time = 10 - fire_delay = 15 - projectile_type=/obj/item/projectile/energy/plasmastun/sonic/weak - firemodes = list( - list(mode_name="normal", projectile_type=/obj/item/projectile/energy/plasmastun/sonic/weak, charge_cost = 50), - list(mode_name="overcharge", projectile_type=/obj/item/projectile/energy/plasmastun/sonic/strong, charge_cost = 200), - ) - -/obj/item/gun/energy/sonic/Initialize() - . = ..() - set_extension(src, /datum/extension/voxform) diff --git a/code/modules/projectiles/guns/energy/xray.dm b/code/modules/projectiles/guns/energy/xray.dm index 501d5571c8a7..cf20a5f1e003 100644 --- a/code/modules/projectiles/guns/energy/xray.dm +++ b/code/modules/projectiles/guns/energy/xray.dm @@ -4,8 +4,8 @@ desc = "A high-power laser gun capable of emitting concentrated x-ray blasts, that are able to penetrate laser-resistant armor much more readily than standard photonic beams." icon = 'icons/obj/guns/xray.dmi' icon_state = ICON_STATE_WORLD - slot_flags = SLOT_BELT|SLOT_BACK - origin_tech = "{'combat':5,'materials':3,'magnets':2,'esoteric':2}" + slot_flags = SLOT_LOWER_BODY|SLOT_BACK + origin_tech = @'{"combat":5,"materials":3,"magnets":2,"esoteric":2}' projectile_type = /obj/item/projectile/beam/xray/midlaser one_hand_penalty = 2 w_class = ITEM_SIZE_LARGE @@ -14,7 +14,7 @@ combustion = 0 material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE ) diff --git a/code/modules/projectiles/guns/launcher/alien.dm b/code/modules/projectiles/guns/launcher/alien.dm deleted file mode 100644 index 0522aefc3706..000000000000 --- a/code/modules/projectiles/guns/launcher/alien.dm +++ /dev/null @@ -1,53 +0,0 @@ -/obj/item/gun/launcher/alien - var/last_regen = 0 - var/ammo_gen_time = 100 - var/max_ammo = 3 - var/ammo = 3 - var/ammo_type - var/ammo_name - -/obj/item/gun/launcher/alien/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - last_regen = world.time - -/obj/item/gun/launcher/alien/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/gun/launcher/alien/Process() - if(ammo < max_ammo && world.time > last_regen + ammo_gen_time) - ammo++ - last_regen = world.time - update_icon() - -/obj/item/gun/launcher/alien/examine(mob/user) - . = ..() - to_chat(user, "It has [ammo] [ammo_name]\s remaining.") - -/obj/item/gun/launcher/alien/consume_next_projectile() - if(ammo < 1) return null - if(ammo == max_ammo) //stops people from buffering a reload (gaining effectively +1 to the clip) - last_regen = world.time - ammo-- - return new ammo_type - -/obj/item/gun/launcher/alien/Initialize() - . = ..() - set_extension(src, /datum/extension/voxform) - -//Vox pinning weapon. -/obj/item/gun/launcher/alien/spikethrower - name = "spike thrower" - desc = "A vicious alien projectile weapon. Parts of it quiver gelatinously, as though the thing is insectile and alive." - w_class = ITEM_SIZE_LARGE - ammo_name = "spike" - ammo_type = /obj/item/spike - release_force = 30 - icon = 'icons/obj/guns/launcher/voxspike.dmi' - icon_state = ICON_STATE_WORLD - fire_sound_text = "a strange noise" - fire_sound = 'sound/weapons/spike.ogg' - -/obj/item/gun/launcher/alien/spikethrower/on_update_icon() - icon_state = "[get_world_inventory_state()][Clamp(ammo,0,3)]" \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/bows/_bow.dm b/code/modules/projectiles/guns/launcher/bows/_bow.dm new file mode 100644 index 000000000000..d4182d48fddb --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/_bow.dm @@ -0,0 +1,198 @@ +/obj/item/gun/launcher/bow + name = "bow" + desc = "A projectile weapon of ancient design that turns elastic tension into long-range death." + icon = 'icons/obj/guns/launcher/bow.dmi' + icon_state = ICON_STATE_WORLD + fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise. + fire_sound_text = "a solid thunk" + fire_delay = 25 + slot_flags = SLOT_BACK + has_safety = FALSE + w_class = ITEM_SIZE_LARGE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/organic/wood/yew + color = /decl/material/solid/organic/wood/yew::color + fire_verb = "loose" + autofire_enabled = TRUE + + /// What are we strung with? + var/obj/item/bowstring/string = /obj/item/bowstring + /// Does this weapon require a string to fire? + var/requires_string = TRUE + /// Currently loaded ammo. + var/obj/item/_loaded + /// Current draw on the bow. + var/tension = 0 + /// Highest possible tension. + var/max_tension = 3 + /// Speed per unit of tension. + var/release_speed = 14 + /// Time needed to draw the bow back by one "tension" + var/draw_time = 1 SECOND + /// Does this bow need an arrow nocked to draw? + var/require_loaded_to_draw = TRUE + /// What skill is used to load and fire this bow? + var/work_skill = SKILL_WEAPONS + /// Does this bow keep tension when dropped? + var/keep_tension_when_dropped = FALSE + /// What kind of ammunition does this bow expect? + var/bow_ammo_type = /obj/item/stack/material/bow_ammo/arrow + /// Flag for tracking if a bow is currently being drawn, to avoid double draw. + var/drawing_bow = FALSE + /// Timer for tracking next increase in tension from click and hold. + var/next_tension_step + /// How big is this bow when strung? Uses initial w_class if unset. + var/strung_w_class = ITEM_SIZE_HUGE + /// How big is this bow when unstrung? Uses initial w_class if unset. + var/unstrung_w_class + +/obj/item/gun/launcher/bow/set_autofire(var/atom/fire_at, var/mob/fire_by, var/autoturn = TRUE) + if(!autofire_enabled || autofiring_at) + return ..() + . = ..() + if(ismob(fire_by)) + if(!get_loaded_arrow(fire_by) && fire_by.skill_check(SKILL_WEAPONS, SKILL_ADEPT)) + load_available_ammo(fire_by) + if(check_can_draw(fire_by)) + tension = 0 + next_tension_step = world.time + get_draw_time(fire_by) + fire_by.set_dir(get_dir(fire_by, fire_at)) + show_draw_message(fire_by) + update_icon() + +/obj/item/gun/launcher/bow/try_autofire(autoturn) + if(!autofire_enabled) + return ..() + var/mob/wielder = loc + if(!ismob(wielder) || !check_can_draw(wielder)) + clear_autofire() + else + wielder.set_dir(get_dir(wielder, autofiring_at)) + if(world.time >= next_tension_step && tension < max_tension) + next_tension_step = world.time + get_draw_time(wielder) + tension++ + if(tension == max_tension) + show_max_draw_message(wielder) + else + show_working_draw_message(wielder) + update_icon() + +/obj/item/gun/launcher/bow/clear_autofire() + if(!autofire_enabled) + return ..() + var/mob/living/wielder = loc + if(tension && istype(wielder) && !wielder.incapacitated() && wielder.get_active_held_item() == src && get_loaded_arrow()) + wielder.set_dir(get_dir(wielder, autofiring_at)) + Fire(autofiring_at, autofiring_by, null, (get_dist(autofiring_at, autofiring_by) <= 1), FALSE, FALSE) + . = ..() + if(tension) + if(istype(wielder)) + show_cancel_draw_message(wielder) + tension = 0 + update_icon() + +/obj/item/gun/launcher/bow/handle_click_empty(atom/movable/firer) + if(check_fire_message_spam("click")) + to_chat(firer, SPAN_WARNING("\The [src] has nothing loaded.")) + +/obj/item/gun/launcher/bow/fancy + desc = "A projectile weapon of ancient design that turns elastic tension into long-range death. This one has decorative engraving and flourishes." + icon = 'icons/obj/guns/launcher/bow_fancy.dmi' + +/obj/item/gun/launcher/bow/crafted + string = null + +/obj/item/gun/launcher/bow/fancy/crafted + string = null + +/obj/item/gun/launcher/bow/Initialize() + if(ispath(string)) + set_string(new string(src)) + return ..() + +/obj/item/gun/launcher/bow/proc/set_string(new_string) + if(string == new_string) + return FALSE + string = new_string + if(istype(string)) + w_class = strung_w_class || initial(w_class) + else + w_class = unstrung_w_class || initial(w_class) + +/obj/item/gun/launcher/bow/Destroy() + QDEL_NULL(_loaded) + QDEL_NULL(string) + return ..() + +/obj/item/gun/launcher/bow/physically_destroyed() + if(_loaded) + _loaded.dropInto(loc) + _loaded = null + if(string) + string.dropInto(loc) + set_string(null) + return ..() + +/obj/item/gun/launcher/bow/dropped() + if(!keep_tension_when_dropped) + if(tension) + tension = 0 + if(_loaded) + remove_arrow() + update_icon() + return ..() + +/obj/item/gun/launcher/bow/get_firing_name(obj/projectile) + if(!projectile) + return ..() + return "\the [projectile] from \the [src]" + +/obj/item/gun/launcher/bow/proc/add_base_bow_overlays() + return + +/obj/item/gun/launcher/bow/on_update_icon() + + . = ..() + + icon_state = get_world_inventory_state() + + add_base_bow_overlays() + + if(_loaded) + var/bolt_state = "[icon_state]-loaded" + if(tension) + bolt_state = "[bolt_state]-drawn" + if(check_state_in_icon(bolt_state, icon)) + add_overlay(overlay_image(icon, bolt_state, _loaded.color, RESET_COLOR)) + + if(string) + var/string_state = "[icon_state]-string" + if(tension) + string_state = "[string_state]-drawn" + if(check_state_in_icon(string_state, icon)) + add_overlay(overlay_image(icon, string_state, string.color, RESET_COLOR)) + +/obj/item/gun/launcher/bow/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + if(string) + var/string_state = "[overlay.icon_state]-string" + if(check_state_in_icon(string_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, string_state, string.color, RESET_COLOR) + if(_loaded) + var/loaded_state = "[overlay.icon_state]-loaded" + if(check_state_in_icon(loaded_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, loaded_state, _loaded.color, RESET_COLOR) + return ..() + +/obj/item/gun/launcher/bow/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/list/strings = list() + if(material_alteration & MAT_FLAG_ALTERATION_DESC) + strings += "is made of [material.solid_name]" + if(string) + strings += "is strung with \a [string]" + if(_loaded) + strings += "has \a [_loaded] ready" + if(!length(strings)) + return + . += "It [english_list(strings)]." diff --git a/code/modules/projectiles/guns/launcher/bows/arrow.dm b/code/modules/projectiles/guns/launcher/bows/arrow.dm new file mode 100644 index 000000000000..073c4d5928ba --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/arrow.dm @@ -0,0 +1,99 @@ +/obj/item/stack/material/bow_ammo + abstract_type = /obj/item/stack/material/bow_ammo + icon_state = ICON_STATE_WORLD + base_state = ICON_STATE_WORLD + plural_icon_state = ICON_STATE_WORLD + "-mult" + max_icon_state = ICON_STATE_WORLD + "-max" + w_class = ITEM_SIZE_NORMAL + sharp = TRUE + edge = FALSE + lock_picking_level = 3 + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + matter_multiplier = 0.2 + is_spawnable_type = TRUE + _base_attack_force = 7 // Legolas mode... + _thrown_force_multiplier = 1.15 + var/superheated = FALSE + +/obj/item/stack/material/bow_ammo/on_update_icon() + . = ..() + if(superheated) + add_overlay(overlay_image(icon, "[icon_state]-superheated", COLOR_WHITE, RESET_COLOR)) + +/obj/item/stack/material/bow_ammo/update_attack_force() + . = ..() + if(superheated) + _cached_attack_force *= 2 + +/obj/item/stack/material/bow_ammo/proc/make_superheated() + if(!superheated) + superheated = TRUE + update_attack_force() + update_icon() + +/// Helper for metal rods falling apart. +/obj/item/stack/material/bow_ammo/proc/removed_from_bow(mob/user) + if(!superheated) + return + // The rod has been superheated - we don't want it to be useable when removed from the bow. + to_chat(user, SPAN_DANGER("\The [src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.")) + var/obj/item/shard/shrapnel/S = new() + S.dropInto(loc) + qdel(src) + +/obj/item/stack/material/bow_ammo/arrow + name = "arrow" + singular_name = "arrow" + plural_name = "arrows" + icon = 'icons/obj/items/weapon/arrow.dmi' + desc = "A long, sharp stick, fletched at one end." + var/decl/material/fletching_material + +/obj/item/stack/material/bow_ammo/arrow/iron + material = /decl/material/solid/metal/iron + +/obj/item/stack/material/bow_ammo/arrow/iron/fifteen + amount = 15 + +/obj/item/stack/material/bow_ammo/arrow/fifteen + amount = 15 + +/obj/item/stack/material/bow_ammo/arrow/Initialize() + if(ispath(fletching_material)) + fletching_material = GET_DECL(fletching_material) + . = ..() + update_icon() + +/obj/item/stack/material/bow_ammo/arrow/fletched + fletching_material = /decl/material/solid/organic/skin/feathers + +/obj/item/stack/material/bow_ammo/arrow/on_update_icon() + . = ..() + if(fletching_material) + add_overlay(overlay_image(icon, "[icon_state]-fletching", fletching_material.color, RESET_COLOR)) + +/obj/item/stack/material/bow_ammo/bolt + name = "bolt" + singular_name = "bolt" + plural_name = "bolts" + icon = 'icons/obj/items/weapon/arrow_bolt.dmi' + desc = "It's got a tip for you - get the point?" + _thrown_force_multiplier = 1.2 + +/obj/item/stack/material/bow_ammo/spike + name = "alloy spike" + singular_name = "alloy spike" + plural_name = "alloy spikes" + desc = "It's about a foot of weird silver metal with a wicked point." + material = /decl/material/solid/metal/alienalloy + _thrown_force_multiplier = 1.25 + +/obj/item/stack/material/bow_ammo/rod + name = "rod" + singular_name = "rod" + plural_name = "rods" + desc = "Don't cry for me, Orithena." + icon = 'icons/obj/items/weapon/arrow_rod.dmi' + material = /decl/material/solid/metal/steel + _thrown_force_multiplier = 1.2 diff --git a/code/modules/projectiles/guns/launcher/bows/bow_drawing.dm b/code/modules/projectiles/guns/launcher/bows/bow_drawing.dm new file mode 100644 index 000000000000..ccef4f510c15 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/bow_drawing.dm @@ -0,0 +1,65 @@ +/obj/item/gun/launcher/bow/proc/get_loaded_arrow(mob/user) + return _loaded + +/obj/item/gun/launcher/bow/proc/get_draw_time(mob/firer) + . = draw_time + if(firer) + . = max(1, round(draw_time * firer.skill_delay_mult(work_skill))) + +/obj/item/gun/launcher/bow/proc/check_can_draw(mob/user) + . = istype(user) && !QDELETED(user) && !QDELETED(src) && (!require_loaded_to_draw || get_loaded_arrow(user)) + if(. && requires_string) + . = istype(string) && !QDELETED(string) + +/obj/item/gun/launcher/bow/proc/start_drawing(var/mob/user) + + if(tension != 0 || autofire_enabled) + return + + if(!get_loaded_arrow(user) && require_loaded_to_draw) + to_chat(user, SPAN_WARNING("You don't have anything loaded in \the [src].")) + return + + if(user.restrained() || tension > 0 || drawing_bow) + return + + drawing_bow = TRUE + show_draw_message(user) + if(!user.do_skilled(get_draw_time(), work_skill, src)) + drawing_bow = FALSE + show_cancel_draw_message(user) + tension = 0 + return + + if(!check_can_draw(user)) + drawing_bow = FALSE + tension = 0 + update_icon() + return + + tension = 1 + update_icon() + if(tension < max_tension) + show_working_draw_message(user) + continue_drawing(user) + else + drawing_bow = FALSE + show_max_draw_message(user) + +/obj/item/gun/launcher/bow/proc/continue_drawing(mob/user) + set waitfor = FALSE + if(!check_can_draw(user) || !user.do_skilled(get_draw_time(), work_skill, src) || !check_can_draw(user)) + tension = 0 + drawing_bow = FALSE + if(user) + show_cancel_draw_message(user) + else + tension++ + if(tension >= max_tension) + tension = max_tension + show_max_draw_message(user) + drawing_bow = FALSE + else + show_working_draw_message(user) + continue_drawing(user) + update_icon() diff --git a/code/modules/projectiles/guns/launcher/bows/bow_firing.dm b/code/modules/projectiles/guns/launcher/bows/bow_firing.dm new file mode 100644 index 000000000000..b1854dd4885e --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/bow_firing.dm @@ -0,0 +1,36 @@ +/obj/item/gun/launcher/bow/proc/can_load_arrow(obj/item/ammo) + return istype(ammo, bow_ammo_type) + +/obj/item/gun/launcher/bow/proc/load_arrow(mob/user, obj/item/ammo) + if(requires_string && !istype(string)) + if(user) + to_chat(user, SPAN_WARNING("\The [src] has no bowstring!")) + return FALSE + if(istype(ammo, /obj/item/stack)) + var/obj/item/stack/stack = ammo + ammo = stack.split(1) + if(QDELETED(ammo)) + return FALSE + ammo.forceMove(src) + else if(user && !user.try_unequip(ammo, src)) + return FALSE + _loaded = ammo + if(user) + show_load_message(user) + update_icon() + return TRUE + +/obj/item/gun/launcher/bow/update_release_force() + release_force = tension * release_speed + +/obj/item/gun/launcher/bow/consume_next_projectile(atom/movable/firer) + if(tension <= 0 && isliving(firer)) + to_chat(firer, SPAN_WARNING("\The [src] is not ready to fire!")) + return null + return get_loaded_arrow(firer) + +/obj/item/gun/launcher/bow/handle_post_fire(atom/movable/firer, atom/target) + _loaded = null + tension = 0 + . = ..() + update_icon() diff --git a/code/modules/projectiles/guns/launcher/bows/bow_interaction.dm b/code/modules/projectiles/guns/launcher/bows/bow_interaction.dm new file mode 100644 index 000000000000..14eaf8359812 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/bow_interaction.dm @@ -0,0 +1,122 @@ +/obj/item/gun/launcher/bow/attack_self(mob/user) + + if(tension) + relax_tension(user) + return TRUE + + if(!get_loaded_arrow(user) && !autofire_enabled && user.skill_check(SKILL_WEAPONS, SKILL_ADEPT) && load_available_ammo(user)) + return TRUE + + if(!autofire_enabled && get_loaded_arrow(user)) + start_drawing(user) + return TRUE + + return ..() + +/obj/item/gun/launcher/bow/proc/load_available_ammo(mob/living/user) + + var/list/possible_arrows = list() + possible_arrows += user.get_inactive_held_items() + for(var/accessory_slot in list(slot_back_str, slot_w_uniform_str, slot_wear_suit_str, slot_back_str)) + var/obj/item/gear = user.get_equipped_item(accessory_slot) + if(!istype(gear)) + continue + if(gear.storage) + possible_arrows |= gear.get_stored_inventory() + if(istype(gear, /obj/item/clothing)) + var/obj/item/clothing/clothes = gear + for(var/obj/item/clothing/accessory in clothes.accessories) + if(accessory.storage) + possible_arrows |= accessory.get_stored_inventory() + + for(var/obj/item/ammo in possible_arrows) + if(!can_load_arrow(ammo)) + continue + attackby(ammo, user) + if(get_loaded_arrow(user)) + if(!autofire_enabled) + start_drawing(user) + return TRUE + + return FALSE + +/obj/item/gun/launcher/bow/attack_hand(mob/user) + if(user.is_holding_offhand(src)) + if(tension) + relax_tension(user) + if(_loaded) + remove_arrow(user) + else if(istype(string)) + remove_string(user) + else + return ..() + return TRUE + return ..() + +/obj/item/gun/launcher/bow/proc/remove_string(mob/user) + if(!istype(string)) + return + string.dropInto(loc) + if(user) + show_string_remove_message(user) + user.put_in_hands(string) + set_string(null) + update_icon() + +/obj/item/gun/launcher/bow/proc/remove_arrow(mob/user) + if(user) + show_unload_message(user) + + if(_loaded) + + if(istype(_loaded, /obj/item/stack/material/bow_ammo)) + var/obj/item/stack/material/bow_ammo/arrow = _loaded + arrow.removed_from_bow(user) + + if(!QDELETED(_loaded)) + _loaded.dropInto(loc) + if(user) + user.put_in_hands(_loaded) + _loaded = null + + update_icon() + +/obj/item/gun/launcher/bow/proc/relax_tension(mob/user) + tension = 0 + update_icon() + if(autofire_enabled) + clear_autofire() + else if(user) + show_string_relax_message(user) + +/obj/item/gun/launcher/bow/proc/try_string(mob/user, obj/item/bowstring/new_string) + if(string) + to_chat(user, SPAN_WARNING("\The [src] is already strung.")) + return TRUE + // check to make sure it fits + var/datum/storage/loc_storage = loc.storage + if(loc_storage) + if(strung_w_class > loc_storage.max_w_class) + to_chat(user, SPAN_WARNING("\The [src] can't fit in \the [loc] when strung, take it out first!")) + return TRUE + if((loc_storage.storage_space_used() - w_class + strung_w_class) > loc_storage.max_storage_space) + to_chat(user, SPAN_WARNING("\The [loc] is too full to fit \the [src] when strung, make some room!")) + return TRUE + if(user.try_unequip(new_string, src)) + set_string(new_string) + if(user) + show_string_message(user) + update_icon() + return TRUE + return FALSE + +/obj/item/gun/launcher/bow/attackby(obj/item/used_item, mob/user) + if(can_load_arrow(used_item)) + if(_loaded) + to_chat(user, SPAN_WARNING("\The [src] already has \the [_loaded] ready.")) + else + load_arrow(user, used_item) + return TRUE + if(istype(used_item, /obj/item/bowstring) && try_string(user, used_item)) + return TRUE + return ..() diff --git a/code/modules/projectiles/guns/launcher/bows/bow_messages.dm b/code/modules/projectiles/guns/launcher/bows/bow_messages.dm new file mode 100644 index 000000000000..f1e6760af5ed --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/bow_messages.dm @@ -0,0 +1,52 @@ +/obj/item/gun/launcher/bow/proc/show_string_relax_message(mob/user) + if(user) + user.visible_message( + "\The [user] relaxes the tension on \the [src]'s string.", + "You relax the tension on \the [src]'s string." + ) + +/obj/item/gun/launcher/bow/proc/show_unload_message(mob/user) + if(user) + user.visible_message( + "\The [user] removes \the [_loaded] from \the [src].", + "You remove \the [_loaded] from \the [src]." + ) + +/obj/item/gun/launcher/bow/proc/show_draw_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] begins to draw back the string of \the [src]."), + SPAN_NOTICE("You begin to draw back the string of \the [src].") + ) + +/obj/item/gun/launcher/bow/proc/show_max_draw_message(mob/user) + to_chat(user, SPAN_NOTICE("\The [src] strains as you draw the string to its maximum tension!")) + +/obj/item/gun/launcher/bow/proc/show_cancel_draw_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] stops drawing and relaxes the string of \the [src]."), + SPAN_NOTICE("You stop drawing back and relax the string of \the [src].") + ) + +/obj/item/gun/launcher/bow/proc/show_working_draw_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] draws back the string of \the [src]!"), + SPAN_NOTICE("You continue drawing back the string of \the [src]!") + ) + +/obj/item/gun/launcher/bow/proc/show_load_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] nocks \the [_loaded] on \the [src]."), + SPAN_NOTICE("You nock \the [_loaded] on \the [src].") + ) + +/obj/item/gun/launcher/bow/proc/show_string_remove_message(mob/user) + if(user) + user.visible_message("\The [user] unstrings \the [src].") + +/obj/item/gun/launcher/bow/proc/show_string_message(mob/user) + if(user) + user.visible_message("\The [user] strings \the [src] with \the [string].") diff --git a/code/modules/projectiles/guns/launcher/bows/bow_string.dm b/code/modules/projectiles/guns/launcher/bows/bow_string.dm new file mode 100644 index 000000000000..72212cde43b1 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/bow_string.dm @@ -0,0 +1,36 @@ +/obj/item/bowstring + name = "bowstring" + icon = 'icons/obj/fishing_line.dmi' // works well enough for the time being + icon_state = ICON_STATE_WORLD + desc = "A flexible length of material used to string bows." + material = /decl/material/solid/organic/meat/gut + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_DESC + max_health = 100 + w_class = ITEM_SIZE_SMALL + +/obj/item/bowstring/Initialize() + . = ..() + if(material) + max_health = max(1, round(initial(max_health) * material.tensile_strength)) + current_health = get_max_health() + +/obj/item/bowstring/Destroy() + if(istype(loc, /obj/item/gun/launcher/bow)) + var/obj/item/gun/launcher/bow/bow = loc + if(bow.string == src) + bow.remove_string() + return ..() + +#define MAT_COLOR(MAT) \ + material = MAT;\ + color = MAT::color + +/obj/item/bowstring/synthetic + MAT_COLOR(/decl/material/solid/fiberglass) + +/obj/item/bowstring/steel + MAT_COLOR(/decl/material/solid/metal/steel) + +/obj/item/bowstring/copper + MAT_COLOR(/decl/material/solid/metal/copper) +#undef MAT_COLOR \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/bows/crossbow.dm b/code/modules/projectiles/guns/launcher/bows/crossbow.dm new file mode 100644 index 000000000000..f2af34063ec3 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/crossbow.dm @@ -0,0 +1,22 @@ +/obj/item/gun/launcher/bow/crossbow + name = "crossbow" + desc = "A mechanically-powered projectile weapon." + icon = 'icons/obj/guns/launcher/crossbow.dmi' + fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise. + fire_sound_text = "a solid thunk" + fire_delay = 25 + require_loaded_to_draw = FALSE + keep_tension_when_dropped = TRUE + bow_ammo_type = /obj/item/stack/material/bow_ammo/bolt + draw_time = 2 SECONDS + release_speed = 18 + autofire_enabled = FALSE + w_class = ITEM_SIZE_HUGE + strung_w_class = null + +/obj/item/gun/launcher/bow/crossbow/show_load_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] slides \the [_loaded] into \the [src]."), + SPAN_NOTICE("You slide \the [_loaded] into \the [src].") + ) diff --git a/code/modules/projectiles/guns/launcher/bows/crossbow_powered.dm b/code/modules/projectiles/guns/launcher/bows/crossbow_powered.dm new file mode 100644 index 000000000000..290878f861b3 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/crossbow_powered.dm @@ -0,0 +1,156 @@ +/obj/item/gun/launcher/bow/crossbow/powered + name = "powered crossbow" + desc = "A modern twist on an old classic." + string = /obj/item/bowstring/copper // made from wire when crafted + bow_ammo_type = /obj/item/stack/material/bow_ammo/rod + material_alteration = MAT_FLAG_ALTERATION_NONE + + /// Used for firing superheated rods. + var/obj/item/cell/cell + +/obj/item/gun/launcher/bow/crossbow/powered/can_load_arrow(obj/item/ammo) + return istype(ammo, /obj/item/stack/material/rods) || ..() + +/obj/item/gun/launcher/bow/crossbow/powered/add_base_bow_overlays() + add_overlay(overlay_image(icon, "[icon_state]-cell_mount", COLOR_WHITE, RESET_COLOR)) + +/obj/item/gun/launcher/bow/crossbow/powered/physically_destroyed() + if(cell) + cell.dropInto(loc) + cell = null + return ..() + +/obj/item/gun/launcher/bow/crossbow/powered/Destroy() + QDEL_NULL(cell) + return ..() + +/obj/item/gun/launcher/bow/crossbow/powered/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/rcd)) + var/obj/item/rcd/rcd = used_item + if(rcd.crafting && user.try_unequip(rcd) && user.try_unequip(src)) + new /obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice(get_turf(src)) + qdel(rcd) + qdel_self() + else + to_chat(user, SPAN_WARNING("\The [rcd] is not prepared for installation in \the [src].")) + return TRUE + + if(istype(used_item, /obj/item/cell)) + if(!cell) + if(user.try_unequip(used_item, src)) + cell = used_item + to_chat(user, SPAN_NOTICE("You jam [cell] into [src] and wire it to the firing coil.")) + superheat_rod(user) + else + to_chat(user, SPAN_NOTICE("[src] already has a cell installed.")) + return TRUE + + if(IS_SCREWDRIVER(used_item)) + if(cell) + var/obj/item/C = cell + C.dropInto(user.loc) + to_chat(user, SPAN_NOTICE("You jimmy [cell] out of [src] with [used_item].")) + cell = null + else + to_chat(user, SPAN_WARNING("[src] doesn't have a cell installed.")) + return TRUE + + return ..() + +/obj/item/gun/launcher/bow/crossbow/powered/proc/superheat_rod(var/mob/user) + if(!user || !cell || !get_loaded_arrow(user)) + return + if(cell.charge < 500) + return + if(_loaded.get_thrown_attack_force() >= 15) + return + if(!istype(_loaded, /obj/item/stack/material/bow_ammo)) + return + to_chat(user, SPAN_NOTICE("\The [_loaded] plinks and crackles as it begins to glow red-hot.")) + var/obj/item/stack/material/bow_ammo/loaded_arrow = _loaded + loaded_arrow.make_superheated() + cell.use(500) + +/obj/item/gun/launcher/bow/crossbow/powered/load_arrow(mob/user, obj/item/ammo) + if(istype(ammo, /obj/item/stack/material/rods)) + var/obj/item/stack/material/rods/rods = ammo + if(rods.use(1)) + ammo = new /obj/item/stack/material/bow_ammo/rod(src, 1, rods.material?.type) + . = ..() + if(.) + superheat_rod(user) + +/*//////////////////////////// +// Rapid Crossbow Device // +*///////////////////////////// +/obj/item/stack/material/bow_ammo/bolt/rcd + name = "flashforged bolt" + desc = "The ultimate ghetto deconstruction implement." + material = /decl/material/solid/slag + +/obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice + name = "rapid crossbow device" + desc = "A hacked RCD turns an innocent construction tool into the penultimate deconstruction tool. Flashforges bolts using matter units when the string is drawn back." + icon = 'icons/obj/guns/launcher/rcd_bow.dmi' + slot_flags = null + draw_time = 10 + bow_ammo_type = /obj/item/stack/material/bow_ammo/bolt/rcd + require_loaded_to_draw = TRUE + var/stored_matter = 0 + var/max_stored_matter = 120 + var/boltcost = 30 + +/obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice/proc/generate_bolt(var/mob/user) + if(stored_matter >= boltcost && !_loaded) + _loaded = new/obj/item/stack/material/bow_ammo/bolt/rcd(src) + stored_matter -= boltcost + to_chat(user, SPAN_NOTICE("The RCD flashforges a new bolt!")) + queue_icon_update() + else + to_chat(user, SPAN_WARNING("The \'Low Ammo\' light on the device blinks yellow.")) + flick("[icon_state]-empty", src) + +/obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice/get_loaded_arrow(mob/user) + if(!_loaded) + generate_bolt(user) + return ..() + +/obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/rcd_ammo)) + var/obj/item/rcd_ammo/cartridge = used_item + if((stored_matter + cartridge.remaining) > max_stored_matter) + to_chat(user, SPAN_NOTICE("The RCD can't hold that many additional matter-units.")) + return TRUE + stored_matter += cartridge.remaining + qdel(used_item) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("The RCD now holds [stored_matter]/[max_stored_matter] matter-units.")) + update_icon() + return TRUE + if(istype(used_item, /obj/item/stack/material/bow_ammo/bolt/rcd)) + var/obj/item/stack/material/bow_ammo/bolt/rcd/A = used_item + if((stored_matter + 10) > max_stored_matter) + to_chat(user, SPAN_NOTICE("Unable to reclaim flashforged bolt. The RCD can't hold that many additional matter-units.")) + return TRUE + stored_matter += 10 + qdel(A) + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("Flashforged bolt reclaimed. The RCD now holds [stored_matter]/[max_stored_matter] matter-units.")) + update_icon() + return TRUE + return ..() + +/obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice/on_update_icon() + . = ..() + var/ratio = 0 + if(stored_matter < boltcost) + ratio = 0 + else + ratio = stored_matter / max_stored_matter + ratio = max(round(ratio, 0.25) * 100, 25) + add_overlay("[get_world_inventory_state()][ratio]") + +/obj/item/gun/launcher/bow/crossbow/powered/rapidcrossbowdevice/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "It currently holds [stored_matter]/[max_stored_matter] matter-units." diff --git a/code/modules/projectiles/guns/launcher/bows/sling.dm b/code/modules/projectiles/guns/launcher/bows/sling.dm new file mode 100644 index 000000000000..c3f3822d4d84 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/bows/sling.dm @@ -0,0 +1,57 @@ +/obj/item/gun/launcher/bow/sling + name = "sling" + desc = "A simple strip of leather with a cup in the center, used to hurl stones with great speed." + slot_flags = 0 + draw_time = 0.5 SECONDS + icon = 'icons/obj/guns/launcher/sling.dmi' + material = /decl/material/solid/organic/leather + color = /decl/material/solid/organic/leather::color + string = null + requires_string = FALSE + max_tension = 1 + bow_ammo_type = null + +/obj/item/gun/launcher/bow/sling/try_string(mob/user, obj/item/bowstring/new_string) + return FALSE + +/obj/item/gun/launcher/bow/sling/can_load_arrow(obj/item/ammo) + return istype(ammo, /obj/item/rock) || istype(ammo, /obj/item/stack/material/ore) || istype(ammo, /obj/item/stack/material/lump) + +/obj/item/gun/launcher/bow/sling/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && tension) + overlay.icon_state = "[overlay.icon_state]-swing" + return ..() + +/obj/item/gun/launcher/bow/sling/show_load_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] drops \the [_loaded] into \the cup of \the [src]."), + SPAN_NOTICE("You drop \the [_loaded] into \the cup of \the [src].") + ) + +/obj/item/gun/launcher/bow/sling/show_string_relax_message(mob/user) + if(user) + user.visible_message( + "\The [user] ceases swinging \the [src].", + "You cease swinging \the [src]." + ) + +/obj/item/gun/launcher/bow/sling/show_cancel_draw_message(mob/user) + if(user) + user.visible_message( + "\The [user] ceases swinging \the [src].", + "You cease swinging \the [src]." + ) + +/obj/item/gun/launcher/bow/sling/show_draw_message(mob/user) + if(user) + user.visible_message( + SPAN_NOTICE("\The [user] starts swinging \the [src]"), + SPAN_NOTICE("You start swinging \the [src].") + ) + +/obj/item/gun/launcher/bow/sling/show_max_draw_message(mob/user) + return + +/obj/item/gun/launcher/bow/sling/show_working_draw_message(mob/user) + return diff --git a/code/modules/projectiles/guns/launcher/crossbow.dm b/code/modules/projectiles/guns/launcher/crossbow.dm deleted file mode 100644 index 9cffac267355..000000000000 --- a/code/modules/projectiles/guns/launcher/crossbow.dm +++ /dev/null @@ -1,293 +0,0 @@ -//AMMUNITION - -/obj/item/arrow - name = "bolt" - desc = "It's got a tip for you - get the point?" - icon = 'icons/obj/items/weapon/crossbow_bolt.dmi' - icon_state = "bolt" - item_state = "bolt" - throwforce = 8 - w_class = ITEM_SIZE_NORMAL - sharp = 1 - edge = 0 - lock_picking_level = 3 - -/obj/item/arrow/proc/removed() //Helper for metal rods falling apart. - return - -/obj/item/spike - name = "alloy spike" - desc = "It's about a foot of weird silver metal with a wicked point." - sharp = 1 - edge = 0 - throwforce = 5 - w_class = ITEM_SIZE_SMALL - icon = 'icons/obj/items/weapon/crossbow_bolt.dmi' - icon_state = "metal-rod" - item_state = "bolt" - -/obj/item/arrow/quill - name = "vox quill" - desc = "A wickedly barbed quill from some bizarre animal." - icon_state = "quill" - item_state = "quill" - throwforce = 5 - -/obj/item/arrow/rod - name = "metal rod" - desc = "Don't cry for me, Orithena." - icon_state = "metal-rod" - -/obj/item/arrow/rod/removed(mob/user) - if(throwforce == 15) // The rod has been superheated - we don't want it to be useable when removed from the bow. - to_chat(user, "[src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.") - var/obj/item/shard/shrapnel/S = new() - S.dropInto(loc) - qdel(src) - -/obj/item/gun/launcher/crossbow - name = "powered crossbow" - desc = "A modern twist on an old classic. Pick up that can." - icon = 'icons/obj/guns/launcher/crossbow.dmi' - icon_state = ICON_STATE_WORLD - fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise. - fire_sound_text = "a solid thunk" - fire_delay = 25 - slot_flags = SLOT_BACK - has_safety = FALSE - - var/obj/item/bolt - var/tension = 0 // Current draw on the bow. - var/max_tension = 3 // Highest possible tension. - var/release_speed = 10 // Speed per unit of tension. - var/obj/item/cell/cell = null // Used for firing superheated rods. - var/current_user // Used to check if the crossbow has changed hands since being drawn. - var/draw_time = 20 // Time needed to draw the bow back by one "tension" - -/obj/item/gun/launcher/crossbow/toggle_safety(var/mob/user) - to_chat(user, "There's no safety on \the [src]!") - -/obj/item/gun/launcher/crossbow/update_release_force() - release_force = tension*release_speed - -/obj/item/gun/launcher/crossbow/consume_next_projectile(mob/user=null) - if(tension <= 0) - to_chat(user, "\The [src] is not drawn back!") - return null - return bolt - -/obj/item/gun/launcher/crossbow/handle_post_fire(mob/user, atom/target) - bolt = null - tension = 0 - update_icon() - ..() - -/obj/item/gun/launcher/crossbow/attack_self(mob/living/user) - if(tension) - if(bolt) - user.visible_message("[user] relaxes the tension on [src]'s string and removes [bolt].","You relax the tension on [src]'s string and remove [bolt].") - bolt.dropInto(loc) - var/obj/item/arrow/A = bolt - bolt = null - A.removed(user) - else - user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") - tension = 0 - update_icon() - else - draw(user) - -/obj/item/gun/launcher/crossbow/proc/draw(var/mob/user) - - if(!bolt) - to_chat(user, "You don't have anything nocked to [src].") - return - - if(user.restrained()) - return - - current_user = user - user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].") - tension = 1 - - while(bolt && tension && loc == current_user) - if(!do_after(user, draw_time, src)) //crossbow strings don't just magically pull back on their own. - user.visible_message("[usr] stops drawing and relaxes the string of [src].","You stop drawing back and relax the string of [src].") - tension = 0 - update_icon() - return - - //double check that the user hasn't removed the bolt in the meantime - if(!(bolt && tension && loc == current_user)) - return - - tension++ - update_icon() - - if(tension >= max_tension) - tension = max_tension - to_chat(usr, "[src] clunks as you draw the string to its maximum tension!") - return - - user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!") - -/obj/item/gun/launcher/crossbow/proc/increase_tension(var/mob/user) - - if(!bolt || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed. - return - - -/obj/item/gun/launcher/crossbow/attackby(obj/item/W, mob/user) - - if(istype(W, /obj/item/rcd)) - var/obj/item/rcd/rcd = W - if(rcd.crafting && user.unEquip(rcd) && user.unEquip(src)) - new /obj/item/gun/launcher/crossbow/rapidcrossbowdevice(get_turf(src)) - qdel(rcd) - qdel_self() - else - to_chat(user, SPAN_WARNING("\The [rcd] is not prepared for installation in \the [src].")) - return - - if(!bolt) - if (istype(W,/obj/item/arrow) && user.unEquip(W, src)) - bolt = W - user.visible_message("[user] slides [bolt] into [src].","You slide [bolt] into [src].") - update_icon() - return - else if(istype(W,/obj/item/stack/material/rods)) - var/obj/item/stack/material/rods/R = W - if (R.use(1)) - bolt = new /obj/item/arrow/rod(src) - bolt.fingerprintslast = src.fingerprintslast - bolt.dropInto(loc) - update_icon() - user.visible_message("[user] jams [bolt] into [src].","You jam [bolt] into [src].") - superheat_rod(user) - return - - if(istype(W, /obj/item/cell)) - if(!cell) - if(!user.unEquip(W, src)) - return - cell = W - to_chat(user, "You jam [cell] into [src] and wire it to the firing coil.") - superheat_rod(user) - else - to_chat(user, "[src] already has a cell installed.") - - else if(isScrewdriver(W)) - if(cell) - var/obj/item/C = cell - C.dropInto(user.loc) - to_chat(user, "You jimmy [cell] out of [src] with [W].") - cell = null - else - to_chat(user, "[src] doesn't have a cell installed.") - - else - ..() - -/obj/item/gun/launcher/crossbow/proc/superheat_rod(var/mob/user) - if(!user || !cell || !bolt) return - if(cell.charge < 500) return - if(bolt.throwforce >= 15) return - if(!istype(bolt,/obj/item/arrow/rod)) return - - to_chat(user, "[bolt] plinks and crackles as it begins to glow red-hot.") - bolt.throwforce = 15 - bolt.icon_state = "metal-rod-superheated" - cell.use(500) - -/obj/item/gun/launcher/crossbow/on_update_icon() - if(tension > 1) - icon_state = "[get_world_inventory_state()]-drawn" - else if(bolt) - icon_state = "[get_world_inventory_state()]-nocked" - else - icon_state = "[get_world_inventory_state()]" - -/*//////////////////////////// -// Rapid Crossbow Device // -*///////////////////////////// - -/obj/item/arrow/rapidcrossbowdevice - name = "flashforged bolt" - desc = "The ultimate ghetto deconstruction implement." - throwforce = 4 - -/obj/item/gun/launcher/crossbow/rapidcrossbowdevice - name = "rapid crossbow device" - desc = "A hacked RCD turns an innocent construction tool into the penultimate deconstruction tool. Flashforges bolts using matter units when the string is drawn back." - icon = 'icons/obj/guns/launcher/rcd_bow.dmi' - slot_flags = null - draw_time = 10 - var/stored_matter = 0 - var/max_stored_matter = 120 - var/boltcost = 30 - -/obj/item/gun/launcher/crossbow/rapidcrossbowdevice/proc/generate_bolt(var/mob/user) - if(stored_matter >= boltcost && !bolt) - bolt = new/obj/item/arrow/rapidcrossbowdevice(src) - stored_matter -= boltcost - to_chat(user, "The RCD flashforges a new bolt!") - queue_icon_update() - else - to_chat(user, "The \'Low Ammo\' light on the device blinks yellow.") - flick("[icon_state]-empty", src) - - -/obj/item/gun/launcher/crossbow/rapidcrossbowdevice/attack_self(mob/living/user) - if(tension) - user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") - tension = 0 - update_icon() - else - generate_bolt(user) - draw(user) - -/obj/item/gun/launcher/crossbow/rapidcrossbowdevice/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/rcd_ammo)) - var/obj/item/rcd_ammo/cartridge = W - if((stored_matter + cartridge.remaining) > max_stored_matter) - to_chat(user, "The RCD can't hold that many additional matter-units.") - return - stored_matter += cartridge.remaining - qdel(W) - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) - to_chat(user, "The RCD now holds [stored_matter]/[max_stored_matter] matter-units.") - update_icon() - - if(istype(W, /obj/item/arrow/rapidcrossbowdevice)) - var/obj/item/arrow/rapidcrossbowdevice/A = W - if((stored_matter + 10) > max_stored_matter) - to_chat(user, "Unable to reclaim flashforged bolt. The RCD can't hold that many additional matter-units.") - return - stored_matter += 10 - qdel(A) - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) - to_chat(user, "Flashforged bolt reclaimed. The RCD now holds [stored_matter]/[max_stored_matter] matter-units.") - update_icon() - -/obj/item/gun/launcher/crossbow/rapidcrossbowdevice/on_update_icon() - overlays.Cut() - - if(bolt) - overlays += "[get_world_inventory_state()]-bolt" - - var/ratio = 0 - if(stored_matter < boltcost) - ratio = 0 - else - ratio = stored_matter / max_stored_matter - ratio = max(round(ratio, 0.25) * 100, 25) - overlays += "[get_world_inventory_state()][ratio]" - - if(tension > 1) - icon_state = "[get_world_inventory_state()]-drawn" - else - icon_state = "[get_world_inventory_state()]" - -/obj/item/gun/launcher/crossbow/rapidcrossbowdevice/examine(mob/user) - . = ..() - to_chat(user, "It currently holds [stored_matter]/[max_stored_matter] matter-units.") diff --git a/code/modules/projectiles/guns/launcher/foam_gun.dm b/code/modules/projectiles/guns/launcher/foam_gun.dm index 092762abe433..6a351feeda82 100644 --- a/code/modules/projectiles/guns/launcher/foam_gun.dm +++ b/code/modules/projectiles/guns/launcher/foam_gun.dm @@ -3,36 +3,39 @@ desc = "The classic Jorf blaster!" icon = 'icons/obj/guns/foam/blaster.dmi' icon_state = ICON_STATE_WORLD - force = 1 + _base_attack_force = 1 w_class = ITEM_SIZE_SMALL obj_flags = null - slot_flags = SLOT_BELT | SLOT_HOLSTER + slot_flags = SLOT_LOWER_BODY | SLOT_HOLSTER release_force = 1.5 throw_distance = 6 accuracy = 1 one_hand_penalty = 0 fire_sound = 'sound/weapons/foamblaster.ogg' fire_sound_text = "a pleasing 'pomp'" - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic var/max_darts = 1 var/list/darts = new/list() -/obj/item/gun/launcher/foam/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/foam_dart)) - if(darts.len < max_darts) - if(!user.unEquip(I, src)) - return - darts += I - to_chat(user, SPAN_NOTICE("You slot \the [I] into \the [src].")) - else - to_chat(user, SPAN_WARNING("\The [src] can hold no more darts.")) +/obj/item/gun/launcher/foam/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/foam_dart)) + return ..() + if(darts.len < max_darts) + if(!user.try_unequip(used_item, src)) + return TRUE + darts += used_item + to_chat(user, SPAN_NOTICE("You slot \the [used_item] into \the [src].")) + return TRUE + else + to_chat(user, SPAN_WARNING("\The [src] can hold no more darts.")) + return TRUE /obj/item/gun/launcher/foam/consume_next_projectile() if(darts.len) - var/obj/item/I = darts[1] - darts -= I - return I + var/obj/item/thing = darts[1] + darts -= thing + return thing return null /obj/item/gun/launcher/foam/CtrlAltClick(mob/user) @@ -43,6 +46,12 @@ D.dropInto(user.loc) D.mix_up() +/obj/item/gun/launcher/foam/crossbow + name = "foam dart crossbow" + desc = "A weapon favored by many overactive children. Ages 8 and up." + icon = 'icons/obj/guns/energy_crossbow.dmi' + max_darts = 5 + /obj/item/gun/launcher/foam/burst name = "foam machine pistol" desc = "The Jorf Outlander, a machine pistol blaster, fires two darts in rapid succession. Holds 4 darts." @@ -66,71 +75,104 @@ release_force = 3 throw_distance = 12 -/obj/item/gun/launcher/foam/revolver/tampered/examine(mob/user, distance) +/obj/item/gun/launcher/foam/revolver/tampered/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "The hammer is a lot more resistant than you'd expect.") + . += "The hammer is a lot more resistant than you'd expect." + +/obj/item/gun/launcher/foam/machine_gun + name = "foam machine gun" + desc = "The Jorf machine gun, hose the competition down and hate yourself while you spend forever reloading! It holds 30 darts." + icon = 'icons/obj/guns/foam/machine_gun.dmi' + w_class = ITEM_SIZE_NORMAL + fire_delay = 0 + autofire_enabled = 1 + one_hand_penalty = 3 + max_darts = 30 + burst_delay = 1 + burst = 3 + burst_accuracy = list(0,-1,-1) + dispersion = list(0.0, 0.6, 1.0) //the projectile /obj/item/foam_dart name = "foam dart" - desc = "An offical Jorf brand foam dart, for use only with offical Jorf brand foam dart launching products." + desc = "An official Jorf brand foam dart, for use only with official Jorf brand foam dart launching products." icon = 'icons/obj/guns/foam/dart.dmi' icon_state = "dart" w_class = ITEM_SIZE_TINY - force = 0 randpixel = 10 - throwforce = 0 throw_range = 3 does_spin = FALSE + material = /decl/material/solid/organic/plastic/foam + _base_attack_force = 0 + _thrown_force_multiplier = 5 /obj/item/foam_dart/Initialize() mix_up() . = ..() - + /obj/item/foam_dart/proc/mix_up() pixel_x = rand(-randpixel, randpixel) pixel_y = rand(-randpixel, randpixel) - set_dir(pick(GLOB.alldirs)) + set_dir(pick(global.alldirs)) /obj/item/foam_dart/tampered - throwforce = 4 + _base_attack_force = 1 -/obj/item/foam_dart/tampered/examine(mob/user, distance) +/obj/item/foam_dart/tampered/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, SPAN_WARNING("Closer inspection reveals some weights in the rubber dome.")) + . += SPAN_WARNING("Closer inspection reveals some weights in the rubber dome.") //boxes of the projectile -/obj/item/storage/box/foam_darts +/obj/item/box/foam_darts name = "box of foam darts" - desc = "It's a box of offical Jorf brand foam darts, for use only with offical Jorf brand products." + desc = "It's a box of official Jorf brand foam darts, for use only with official Jorf brand products." icon = 'icons/obj/guns/foam/boxes.dmi' icon_state = "dart_box" - startswith = list(/obj/item/foam_dart = 14) + +/obj/item/box/foam_darts/WillContain() + return list(/obj/item/foam_dart = 14) //preset boxes -/obj/item/storage/box/large/foam_gun +/obj/item/box/large/foam_gun name = "\improper Jorf blaster set" desc = "It's an official Jorf brand blaster, with three official Jorf brand darts!" icon = 'icons/obj/guns/foam/boxes.dmi' icon_state = "blaster_box" - startswith = list(/obj/item/gun/launcher/foam, - /obj/item/foam_dart = 3) -/obj/item/storage/box/large/foam_gun/burst +/obj/item/box/large/foam_gun/WillContain() + return list( + /obj/item/gun/launcher/foam, + /obj/item/foam_dart = 3 + ) + +/obj/item/box/large/foam_gun/burst name = "\improper Jorf Outlander set" desc = "It's an official Jorf brand Outlander, with six official Jorf brand darts!" - startswith = list(/obj/item/gun/launcher/foam/burst, - /obj/item/foam_dart = 6) -/obj/item/storage/box/large/foam_gun/revolver +/obj/item/box/large/foam_gun/burst/WillContain() + return list( + /obj/item/gun/launcher/foam/burst, + /obj/item/foam_dart = 6 + ) + +/obj/item/box/large/foam_gun/revolver name = "\improper Jorf Desperado set" desc = "It's an official Jorf brand Desperado, with eight official Jorf brand darts!" - startswith = list(/obj/item/gun/launcher/foam/revolver, - /obj/item/foam_dart = 8) -/obj/item/storage/box/large/foam_gun/revolver/tampered +/obj/item/box/large/foam_gun/revolver/WillContain() + return list( + /obj/item/gun/launcher/foam/revolver, + /obj/item/foam_dart = 8 + ) + +/obj/item/box/large/foam_gun/revolver/tampered desc = "It's a Jorf brand Desperado, with fourteen Jorf brand darts!" - startswith = list(/obj/item/gun/launcher/foam/revolver/tampered, - /obj/item/foam_dart/tampered = 14) \ No newline at end of file + +/obj/item/box/large/foam_gun/revolver/tampered/WillContain() + return list( + /obj/item/gun/launcher/foam/revolver/tampered, + /obj/item/foam_dart/tampered = 14 + ) \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/grenade_launcher.dm b/code/modules/projectiles/guns/launcher/grenade_launcher.dm index a5bc4fabf7f5..2fc0015f2667 100644 --- a/code/modules/projectiles/guns/launcher/grenade_launcher.dm +++ b/code/modules/projectiles/guns/launcher/grenade_launcher.dm @@ -3,9 +3,9 @@ desc = "A bulky pump-action grenade launcher. Holds up to 6 grenades in a revolving magazine." icon = 'icons/obj/guns/launcher/grenade.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':2,'materials':3}" + origin_tech = @'{"combat":2,"materials":3}' w_class = ITEM_SIZE_HUGE - force = 10 + _base_attack_force = 10 fire_sound = 'sound/weapons/empty.ogg' fire_sound_text = "a metallic thunk" @@ -14,7 +14,7 @@ release_force = 5 combustion = 1 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) var/obj/item/grenade/chambered var/list/grenades = new/list() @@ -46,13 +46,13 @@ to_chat(M, "You pump [src], but the magazine is empty.") update_icon() -/obj/item/gun/launcher/grenade/examine(mob/user, distance) +/obj/item/gun/launcher/grenade/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 2) var/grenade_count = grenades.len + (chambered? 1 : 0) - to_chat(user, "Has [grenade_count] grenade\s remaining.") + . += "Has [grenade_count] grenade\s remaining." if(chambered) - to_chat(user, "\A [chambered] is chambered.") + . += "\A [chambered] is chambered." /obj/item/gun/launcher/grenade/proc/load(obj/item/grenade/G, mob/user) if(!can_load_grenade_type(G, user)) @@ -61,7 +61,7 @@ if(grenades.len >= max_grenades) to_chat(user, "\The [src] is full.") return - if(!user.unEquip(G, src)) + if(!user.try_unequip(G, src)) return grenades.Insert(1, G) //add to the head of the list, so that it is loaded on the next pump user.visible_message("\The [user] inserts \a [G] into \the [src].", "You insert \a [G] into \the [src].") @@ -78,17 +78,17 @@ /obj/item/gun/launcher/grenade/attack_self(mob/user) pump(user) -/obj/item/gun/launcher/grenade/attackby(obj/item/I, mob/user) - if((istype(I, /obj/item/grenade))) - load(I, user) - else - ..() +/obj/item/gun/launcher/grenade/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/grenade)) + load(used_item, user) + return TRUE + return ..() /obj/item/gun/launcher/grenade/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - unload(user) - else - ..() + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + unload(user) + return TRUE /obj/item/gun/launcher/grenade/consume_next_projectile() if(chambered) @@ -96,7 +96,7 @@ chambered.activate(null) return chambered -/obj/item/gun/launcher/grenade/handle_post_fire(mob/user) +/obj/item/gun/launcher/grenade/handle_post_fire(atom/movable/firer) log_and_message_admins("fired a grenade ([chambered.name]) from a grenade launcher.") chambered = null @@ -108,9 +108,38 @@ return FALSE return TRUE -// For uplink purchase, comes loaded with a random assortment of grenades +/obj/item/gun/launcher/grenade/loaded + var/initial_load_type + /obj/item/gun/launcher/grenade/loaded/Initialize() . = ..() + if(initial_load_type) + chambered = new initial_load_type(src) + LAZYINITLIST(grenades) + for(var/i = 1 to max_grenades) + grenades += new initial_load_type(src) + +/obj/item/gun/launcher/grenade/loaded/anti_photon + initial_load_type = /obj/item/grenade/anti_photon + +/obj/item/gun/launcher/grenade/loaded/smoke + initial_load_type = /obj/item/grenade/smokebomb + +/obj/item/gun/launcher/grenade/loaded/teargas + initial_load_type = /obj/item/grenade/chem_grenade/teargas + +/obj/item/gun/launcher/grenade/loaded/flashbang + initial_load_type = /obj/item/grenade/flashbang + +/obj/item/gun/launcher/grenade/loaded/emp + initial_load_type = /obj/item/grenade/empgrenade + +/obj/item/gun/launcher/grenade/loaded/frag + initial_load_type = /obj/item/grenade/frag/shell + +// For uplink purchase, comes loaded with a random assortment of grenades +/obj/item/gun/launcher/grenade/random/Initialize() + . = ..() var/list/grenade_types = list( /obj/item/grenade/anti_photon = 2, @@ -132,7 +161,6 @@ name = "underslung grenade launcher" desc = "Not much more than a tube and a firing mechanism, this grenade launcher is designed to be fitted to a rifle." w_class = ITEM_SIZE_NORMAL - force = 5 max_grenades = 0 /obj/item/gun/launcher/grenade/underslung/attack_self() @@ -146,7 +174,7 @@ if(chambered) to_chat(user, "\The [src] is already loaded.") return - if(!user.unEquip(G, src)) + if(!user.try_unequip(G, src)) return chambered = G user.visible_message("\The [user] load \a [G] into \the [src].", "You load \a [G] into \the [src].") diff --git a/code/modules/projectiles/guns/launcher/money_cannon.dm b/code/modules/projectiles/guns/launcher/money_cannon.dm index a9a605a13da9..57b3ffbb62c9 100644 --- a/code/modules/projectiles/guns/launcher/money_cannon.dm +++ b/code/modules/projectiles/guns/launcher/money_cannon.dm @@ -3,8 +3,8 @@ desc = "A blocky, plastic novelty launcher that claims to be able to shoot money at considerable velocities." icon = 'icons/obj/guns/launcher/money.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':1,'materials':1}" - slot_flags = SLOT_BELT + origin_tech = @'{"combat":1,"materials":1}' + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_SMALL release_force = 80 fire_sound_text = "a whoosh and a crisp, papery rustle" @@ -18,8 +18,8 @@ /obj/item/gun/launcher/money/hacked emagged = 1 -/obj/item/gun/launcher/money/proc/vomit_cash(var/mob/vomit_onto, var/projectile_vomit) - var/bundle_worth = Floor(receptacle_value / 10) +/obj/item/gun/launcher/money/proc/vomit_cash(var/mob/living/vomit_onto, var/projectile_vomit) + var/bundle_worth = floor(receptacle_value / 10) var/turf/T = get_turf(vomit_onto) for(var/i = 1 to 10) var/nv = bundle_worth @@ -30,16 +30,16 @@ var/obj/item/cash/bling = new(T) bling.adjust_worth(nv) if(projectile_vomit) - for(var/j = 1, j <= rand(2, 4), j++) - step(bling, pick(GLOB.cardinal)) + for(var/j in 1 to rand(2, 4)) + step(bling, pick(global.cardinal)) if(projectile_vomit) - vomit_onto.AdjustStunned(3) - vomit_onto.AdjustWeakened(3) + ADJ_STATUS(vomit_onto, STAT_STUN, 3) + ADJ_STATUS(vomit_onto, STAT_WEAK, 3) vomit_onto.visible_message("\The [vomit_onto] blasts themselves full in the face with \the [src]!") playsound(T, "sound/weapons/gunshot/money_launcher_jackpot.ogg", 100, 1) else - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) vomit_onto.visible_message("\The [vomit_onto] ejects a few [cur.name] into their face.") playsound(T, 'sound/weapons/gunshot/money_launcher.ogg', 100, 1) @@ -64,7 +64,7 @@ var/obj/item/cash/bling = new bling.adjust_worth(receptacle_value) user.put_in_hands(bling) - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) to_chat(user, "You eject [receptacle_value] [cur.name_singular] from [src]'s receptacle.") receptacle_value = 0 @@ -77,7 +77,7 @@ to_chat(user, "You load [bling] into [src].") qdel(bling) -/obj/item/gun/launcher/money/consume_next_projectile(mob/user=null) +/obj/item/gun/launcher/money/consume_next_projectile() if(!receptacle_value || receptacle_value < 1) return null @@ -92,14 +92,12 @@ bling.update_icon() update_release_force(bling.absolute_worth) if(release_force >= 1) - var/datum/effect/effect/system/spark_spread/s = new() - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) return bling /obj/item/gun/launcher/money/attack_self(mob/user) - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) var/disp_amount = min(input(user, "How many [cur.name_singular] do you want to dispense at a time? (0 to [src.receptacle_value])", "Money Cannon Settings", 20) as num, receptacle_value) if (disp_amount < 1) to_chat(user, "You have to dispense at least one [cur.name_singular] at a time!") @@ -108,49 +106,46 @@ to_chat(user, "You set [src] to dispense [dispensing] [cur.name_singular] at a time.") /obj/item/gun/launcher/money/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - unload_receptacle(user) - else + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() + unload_receptacle(user) + return TRUE -/obj/item/gun/launcher/money/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/cash/)) - var/obj/item/cash/bling = W +/obj/item/gun/launcher/money/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/cash)) + var/obj/item/cash/bling = used_item if(bling.absolute_worth < 1) to_chat(user, "You can't seem to get \the [bling] to slide into the receptacle.") - return + return TRUE - var/decl/currency/cur = decls_repository.get_decl(bling.currency) - if(bling.currency != GLOB.using_map.default_currency) + var/decl/currency/cur = GET_DECL(bling.currency) + if(bling.currency != global.using_map.default_currency) to_chat(user, SPAN_WARNING("Due to local legislation and budget cuts, \the [src] will only accept [cur.name].")) - return + return TRUE receptacle_value += bling.absolute_worth to_chat(user, "You slide [bling.get_worth()] [cur.name_singular] into [src]'s receptacle.") qdel(bling) - + return TRUE else - to_chat(user, "That's not going to fit in there.") + return ..() -/obj/item/gun/launcher/money/examine(mob/user) +/obj/item/gun/launcher/money/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) - var/decl/currency/cur = decls_repository.get_decl(GLOB.using_map.default_currency) - to_chat(user, "It is configured to dispense [dispensing] [cur.name_singular] at a time.") - + var/decl/currency/cur = GET_DECL(global.using_map.default_currency) + . += "It is configured to dispense [dispensing] [cur.name_singular] at a time." if(receptacle_value >= 1) - to_chat(user, "The receptacle is loaded with [receptacle_value] [cur.name_singular].") - + . += "The receptacle is loaded with [receptacle_value] [cur.name_singular]." else - to_chat(user, "The receptacle is empty.") - + . += "The receptacle is empty." if(emagged) - to_chat(user, "Its motors are severely overloaded.") + . += SPAN_NOTICE("Its motors are severely overloaded.") /obj/item/gun/launcher/money/handle_suicide(mob/living/user) if(!ishuman(user)) return - var/mob/living/carbon/human/M = user + var/mob/living/human/M = user M.visible_message("[user] sticks [src] in their mouth, ready to pull the trigger...") if(!do_after(user, 40, progress = 0)) @@ -164,8 +159,6 @@ if(!emagged) emagged = 1 to_chat(user, "You slide the sequencer into [src]... only for it to spit it back out and emit a motorized squeal!") - var/datum/effect/effect/system/spark_spread/s = new() - s.set_up(3, 1, src) - s.start() + spark_at(src, cardinal_only = TRUE) else to_chat(user, "[src] seems to have been tampered with already.") \ No newline at end of file diff --git a/code/modules/projectiles/guns/launcher/pneumatic.dm b/code/modules/projectiles/guns/launcher/pneumatic.dm index 6242905298ad..c5cb01283104 100644 --- a/code/modules/projectiles/guns/launcher/pneumatic.dm +++ b/code/modules/projectiles/guns/launcher/pneumatic.dm @@ -3,32 +3,28 @@ desc = "A large gas-powered cannon." icon = 'icons/obj/guns/launcher/pneumatic.dmi' icon_state = ICON_STATE_WORLD - origin_tech = "{'combat':4,'materials':3}" - slot_flags = SLOT_BELT + origin_tech = @'{"combat":4,"materials":3}' + slot_flags = SLOT_LOWER_BODY w_class = ITEM_SIZE_HUGE obj_flags = OBJ_FLAG_CONDUCTIBLE fire_sound_text = "a loud whoosh of moving air" fire_delay = 50 fire_sound = 'sound/weapons/tablehit1.ogg' + storage = /datum/storage/hopper - var/fire_pressure // Used in fire checks/pressure checks. - var/max_w_class = ITEM_SIZE_NORMAL // Hopper intake size. - var/max_storage_space = DEFAULT_BOX_STORAGE // Total internal storage size. - var/obj/item/tank/tank = null // Tank of gas for use in firing the cannon. + var/fire_pressure // Used in fire checks/pressure checks. + var/obj/item/tank/tank = null // Tank of gas for use in firing the cannon. - var/obj/item/storage/item_storage - var/pressure_setting = 10 // Percentage of the gas in the tank used to fire the projectile. var/possible_pressure_amounts = list(5,10,20,25,50) // Possible pressure settings. + var/pressure_setting = 10 // Percentage of the gas in the tank used to fire the projectile. var/force_divisor = 400 // Force equates to speed. Speed/5 equates to a damage multiplier for whoever you hit. - // For reference, a fully pressurized oxy tank at 50% gas release firing a health - // analyzer with a force_divisor of 10 hit with a damage multiplier of 3000+. -/obj/item/gun/launcher/pneumatic/Initialize() + // For reference, a fully pressurized oxy tank at 50% gas release firing a health + // analyzer with a force_divisor of 10 hit with a damage multiplier of 3000+. + +/obj/item/gun/launcher/pneumatic/get_stored_inventory() . = ..() - item_storage = new(src) - item_storage.SetName("hopper") - item_storage.max_w_class = max_w_class - item_storage.max_storage_space = max_storage_space - item_storage.use_sound = null + if(length(.) && tank) + . -= tank /obj/item/gun/launcher/pneumatic/verb/set_pressure() //set amount of tank pressure. set name = "Set Valve Pressure" @@ -50,36 +46,41 @@ update_icon() /obj/item/gun/launcher/pneumatic/proc/unload_hopper(mob/user) - if(item_storage.contents.len > 0) - var/obj/item/removing = item_storage.contents[item_storage.contents.len] - item_storage.remove_from_storage(removing, src.loc) + var/list/item_contents = storage?.get_contents() + if(length(item_contents)) + var/obj/item/removing = item_contents[item_contents.len] + storage.remove_from_storage(user, removing, src.loc) user.put_in_hands(removing) to_chat(user, "You remove [removing] from the hopper.") else to_chat(user, "There is nothing to remove in \the [src].") /obj/item/gun/launcher/pneumatic/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - unload_hopper(user) - else + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() - -/obj/item/gun/launcher/pneumatic/attackby(obj/item/W, mob/user) - if(!tank && istype(W,/obj/item/tank) && user.unEquip(W, src)) - tank = W - user.visible_message("[user] jams [W] into [src]'s valve and twists it closed.","You jam [W] into [src]'s valve and twist it closed.") + unload_hopper(user) + return TRUE + +/obj/item/gun/launcher/pneumatic/attackby(obj/item/used_item, mob/user) + if(!tank && istype(used_item, /obj/item/tank) && user.try_unequip(used_item, src)) + tank = used_item + user.visible_message( + "\The [user] jams \the [used_item] into [src]'s valve and twists it closed.", + "You jam \the [used_item] into \the [src]'s valve and twist it closed." + ) update_icon() - else if(istype(W) && item_storage.can_be_inserted(W, user)) - item_storage.handle_item_insertion(W) + return TRUE + return ..() /obj/item/gun/launcher/pneumatic/attack_self(mob/user) eject_tank(user) -/obj/item/gun/launcher/pneumatic/consume_next_projectile(mob/user=null) - if(!item_storage.contents.len) +/obj/item/gun/launcher/pneumatic/consume_next_projectile(atom/movable/firer) + var/list/storage_contents = storage?.get_contents() + if(!length(storage_contents)) return null if (!tank) - to_chat(user, "There is no gas tank in [src]!") + to_chat(firer, "There is no gas tank in [src]!") return null var/environment_pressure = 10 @@ -91,26 +92,26 @@ fire_pressure = (tank.air_contents.return_pressure() - environment_pressure)*pressure_setting/100 if(fire_pressure < 10) - to_chat(user, "There isn't enough gas in the tank to fire [src].") + to_chat(firer, "There isn't enough gas in the tank to fire [src].") return null - var/obj/item/launched = item_storage.contents[1] - item_storage.remove_from_storage(launched, src) + var/obj/item/launched = storage_contents[1] + storage.remove_from_storage((ismob(firer) ? firer : null), launched, src) return launched -/obj/item/gun/launcher/pneumatic/examine(mob/user, distance) +/obj/item/gun/launcher/pneumatic/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance > 2) return - to_chat(user, "The valve is dialed to [pressure_setting]%.") + . += "The valve is dialed to [pressure_setting]%." if(tank) - to_chat(user, "The tank dial reads [tank.air_contents.return_pressure()] kPa.") + . += "The tank dial reads [tank.air_contents.return_pressure()] kPa." else - to_chat(user, "Nothing is attached to the tank valve!") + . += "Nothing is attached to the tank valve!" /obj/item/gun/launcher/pneumatic/update_release_force(obj/item/projectile) if(tank) - release_force = ((fire_pressure*tank.volume)/projectile.w_class)/force_divisor //projectile speed. + release_force = ((fire_pressure*tank.gas_volume)/projectile.w_class)/force_divisor //projectile speed. if(release_force > 80) release_force = 80 //damage cap. else release_force = 0 @@ -125,21 +126,20 @@ ..() /obj/item/gun/launcher/pneumatic/on_update_icon() + . = ..() if(tank) icon_state = "[get_world_inventory_state()]-tank" else icon_state = get_world_inventory_state() - update_held_icon() -/obj/item/gun/launcher/pneumatic/experimental_mob_overlay(mob/user_mob, slot) - var/image/I = ..() - if(tank) - I.icon_state += "-tank" - return I +/obj/item/gun/launcher/pneumatic/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && tank) + overlay.icon_state += "-tank" + . = ..() /obj/item/gun/launcher/pneumatic/small name = "small pneumatic cannon" desc = "It looks smaller than your garden variety cannon" - max_w_class = ITEM_SIZE_TINY - w_class = ITEM_SIZE_NORMAL \ No newline at end of file + w_class = ITEM_SIZE_NORMAL + storage = /datum/storage/hopper/small diff --git a/code/modules/projectiles/guns/launcher/rocket.dm b/code/modules/projectiles/guns/launcher/rocket.dm index 643521d7b2dd..5300df1294a4 100644 --- a/code/modules/projectiles/guns/launcher/rocket.dm +++ b/code/modules/projectiles/guns/launcher/rocket.dm @@ -6,10 +6,9 @@ w_class = ITEM_SIZE_HUGE throw_speed = 2 throw_range = 10 - force = 5.0 obj_flags = OBJ_FLAG_CONDUCTIBLE slot_flags = 0 - origin_tech = "{'combat':8,'materials':5}" + origin_tech = @'{"combat":8,"materials":5}' fire_sound = 'sound/effects/bang.ogg' combustion = 1 @@ -18,31 +17,34 @@ var/max_rockets = 1 var/list/rockets = new/list() -/obj/item/gun/launcher/rocket/examine(mob/user, distance) +/obj/item/gun/launcher/rocket/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 2) - to_chat(user, "[rockets.len] / [max_rockets] rockets.") + . += SPAN_NOTICE("[rockets.len]/[max_rockets] rocket\s.") -/obj/item/gun/launcher/rocket/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/ammo_casing/rocket)) +/obj/item/gun/launcher/rocket/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/ammo_casing/rocket)) if(rockets.len < max_rockets) - if(!user.unEquip(I, src)) - return - rockets += I + if(!user.try_unequip(used_item, src)) + return TRUE + rockets += used_item to_chat(user, "You put the rocket in [src].") to_chat(user, "[rockets.len] / [max_rockets] rockets.") + return TRUE else - to_chat(usr, "\The [src] cannot hold more rockets.") + to_chat(user, "\The [src] cannot hold more rockets.") + return TRUE + return ..() /obj/item/gun/launcher/rocket/consume_next_projectile() if(rockets.len) - var/obj/item/ammo_casing/rocket/I = rockets[1] + var/obj/item/ammo_casing/rocket/rocket = rockets[1] var/obj/item/missile/M = new (src) M.primed = 1 - rockets -= I + rockets -= rocket return M return null -/obj/item/gun/launcher/rocket/handle_post_fire(mob/user, atom/target) - log_and_message_admins("fired a rocket from a rocket launcher ([src.name]) at [target].") +/obj/item/gun/launcher/rocket/handle_post_fire(atom/movable/firer, atom/target) + log_and_message_admins("fired a rocket from a rocket launcher ([src.name]) at [target].", firer) ..() diff --git a/code/modules/projectiles/guns/launcher/slugsling.dm b/code/modules/projectiles/guns/launcher/slugsling.dm deleted file mode 100644 index f82da48d7164..000000000000 --- a/code/modules/projectiles/guns/launcher/slugsling.dm +++ /dev/null @@ -1,58 +0,0 @@ -/obj/item/slugegg - name = "slugegg" - desc = "A pulsing, disgusting door to new life." - force = 1 - throwforce = 6 - icon = 'icons/obj/items/slug_egg.dmi' - icon_state = "slugegg" - var/break_on_impact = 1 //There are two modes to the eggs. - //One breaks the egg on hit, - -/obj/item/slugegg/throw_impact(atom/hit_atom) - if(break_on_impact) - squish() - else - movable_flags |= MOVABLE_FLAG_PROXMOVE //Dont want it active during the throw... loooots of unneeded checking. - return ..() - -/obj/item/slugegg/attack_self(var/mob/living/user) - squish() - -/obj/item/slugegg/HasProximity(var/atom/movable/AM) - if(isliving(AM)) - squish() - -/obj/item/slugegg/proc/squish() - src.visible_message("\The [src] bursts open!") - new /mob/living/simple_animal/hostile/voxslug(get_turf(src)) - playsound(src.loc,'sound/effects/attackblob.ogg',100, 1) - qdel(src) - -//a slug sling basically launches a small egg that hatches (either on a person or on the floor), releasing a terrible blood thirsty monster. -//Balanced due to the non-spammy nature of the gun, as well as the frailty of the creatures. -/obj/item/gun/launcher/alien/slugsling - name = "slug sling" - desc = "A bulbous looking rifle. It feels like holding a plastic bag full of meat." - w_class = ITEM_SIZE_LARGE - icon = 'icons/obj/guns/launcher/voxslug.dmi' - icon_state = ICON_STATE_WORLD - fire_sound_text = "a strange noise" - fire_sound = 'sound/weapons/towelwhip.ogg' - release_force = 6 - ammo_name = "slug" - ammo_type = /obj/item/slugegg - max_ammo = 2 - ammo = 2 - ammo_gen_time = 600 - var/mode = "Impact" - -/obj/item/gun/launcher/alien/slugsling/consume_next_projectile() - var/obj/item/slugegg/S = ..() - if(S) - S.break_on_impact = (mode == "Impact") - return S - - -/obj/item/gun/launcher/alien/slugsling/attack_self(var/mob/living/user) - mode = mode == "Impact" ? "Sentry" : "Impact" - to_chat(user,"You switch \the [src]'s mode to \"[mode]\"") diff --git a/code/modules/projectiles/guns/launcher/syringe_gun.dm b/code/modules/projectiles/guns/launcher/syringe_gun.dm index a4616bf3c426..ea57b6b0f4a1 100644 --- a/code/modules/projectiles/guns/launcher/syringe_gun.dm +++ b/code/modules/projectiles/guns/launcher/syringe_gun.dm @@ -3,36 +3,45 @@ desc = "An impact-triggered compressed gas cartridge that can be fitted to a syringe for rapid injection." icon = 'icons/obj/ammo.dmi' icon_state = "syringe-cartridge" - var/icon_flight = "syringe-cartridge-flight" //so it doesn't look so weird when shot material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT | SLOT_EARS - throwforce = 3 - force = 3 - w_class = ITEM_SIZE_TINY + slot_flags = SLOT_LOWER_BODY | SLOT_EARS + w_class = ITEM_SIZE_SMALL + var/icon_flight = "syringe-cartridge-flight" //so it doesn't look so weird when shot var/obj/item/chems/syringe/syringe /obj/item/syringe_cartridge/on_update_icon() + . = ..() underlays.Cut() if(syringe) - underlays += image(syringe.icon, src, syringe.icon_state) - underlays += syringe.filling - -/obj/item/syringe_cartridge/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/chems/syringe) && user.unEquip(I, src)) - syringe = I + var/mutable_appearance/MA = new /mutable_appearance(syringe) + MA.pixel_x = 0 + MA.pixel_y = 0 + MA.pixel_w = 0 + MA.pixel_z = 0 + MA.layer = FLOAT_LAYER + MA.plane = FLOAT_PLANE + underlays += MA + +/obj/item/syringe_cartridge/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/chems/syringe)) + if(!user.try_unequip(used_item, src)) + return TRUE + syringe = used_item to_chat(user, "You carefully insert [syringe] into [src].") - sharp = 1 + set_sharp(TRUE) name = "syringe dart" update_icon() + return TRUE + return ..() /obj/item/syringe_cartridge/attack_self(mob/user) if(syringe) to_chat(user, "You remove [syringe] from [src].") user.put_in_hands(syringe) syringe = null - sharp = initial(sharp) + set_sharp(initial(sharp)) SetName(initial(name)) update_icon() @@ -49,12 +58,12 @@ if(TT.speed >= 10 && isliving(hit_atom)) var/mob/living/L = hit_atom //unfortuately we don't know where the dart will actually hit, since that's done by the parent. - if(L.can_inject(null, ran_zone(TT.target_zone, 30)) == CAN_INJECT && syringe.reagents) + if(L.can_inject(null, ran_zone(TT.target_zone, 30, L)) == CAN_INJECT && syringe.reagents) var/reagent_log = syringe.reagents.get_reagents() - syringe.reagents.trans_to_mob(L, 15, CHEM_INJECT) + syringe.reagents.trans_to_mob(L, REAGENT_TOTAL_VOLUME(syringe.reagents), CHEM_INJECT) admin_inject_log(TT.thrower? TT.thrower : null, L, src, reagent_log, 15, violent=1) - syringe.break_syringe(iscarbon(hit_atom)? hit_atom : null) + syringe.break_syringe(ishuman(hit_atom)? hit_atom : null) syringe.update_icon() icon_state = initial(icon_state) //reset icon state @@ -62,13 +71,13 @@ /obj/item/gun/launcher/syringe name = "syringe gun" - desc = "A spring loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance." + desc = "A spring-loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance." icon = 'icons/obj/guns/launcher/syringe.dmi' icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_LARGE - force = 7 + _base_attack_force = 7 material = /decl/material/solid/metal/steel - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY fire_sound = 'sound/weapons/empty.ogg' fire_sound_text = "a metallic thunk" @@ -91,43 +100,47 @@ darts -= next next = null -/obj/item/gun/launcher/syringe/attack_self(mob/living/user) +/obj/item/gun/launcher/syringe/attack_self(mob/user) if(next) user.visible_message("[user] unlatches and carefully relaxes the bolt on [src].", "You unlatch and carefully relax the bolt on [src], unloading the spring.") next = null else if(darts.len) playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) - user.visible_message("[user] draws back the bolt on [src], clicking it into place.", "You draw back the bolt on the [src], loading the spring!") + user.visible_message("[user] draws back the bolt on [src], clicking it into place.", "You draw back the bolt on \the [src], loading the spring!") next = darts[1] add_fingerprint(user) -/obj/item/gun/launcher/syringe/attack_hand(mob/living/user) - if(user.get_inactive_hand() == src) - if(!darts.len) - to_chat(user, "[src] is empty.") - return - if(next) - to_chat(user, "[src]'s cover is locked shut.") - return - var/obj/item/syringe_cartridge/C = darts[1] - darts -= C - user.put_in_hands(C) - user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src].") - else - ..() - -/obj/item/gun/launcher/syringe/attackby(var/obj/item/A, mob/user) - if(istype(A, /obj/item/syringe_cartridge)) - var/obj/item/syringe_cartridge/C = A +/obj/item/gun/launcher/syringe/attack_hand(mob/user) + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(!darts.len) + to_chat(user, SPAN_WARNING("\The [src] is empty.")) + return TRUE + if(next) + to_chat(user, SPAN_WARNING("\The [src]'s cover is locked shut.")) + return TRUE + var/obj/item/syringe_cartridge/C = darts[1] + darts -= C + user.put_in_hands(C) + user.visible_message( + SPAN_NOTICE("\The [user] removes \a [C] from \the [src]."), + SPAN_NOTICE("You remove \a [C] from \the [src].") + ) + return TRUE + +/obj/item/gun/launcher/syringe/attackby(var/obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/syringe_cartridge)) + var/obj/item/syringe_cartridge/C = used_item if(darts.len >= max_darts) to_chat(user, "[src] is full!") - return - if(!user.unEquip(C, src)) - return + return TRUE + if(!user.try_unequip(C, src)) + return TRUE darts += C //add to the end user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src].") + return TRUE else - ..() + return ..() /obj/item/gun/launcher/syringe/rapid name = "syringe gun revolver" @@ -135,20 +148,23 @@ icon = 'icons/obj/guns/launcher/syringe_rapid.dmi' max_darts = 5 material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/gun/launcher/syringe/disguised name = "deluxe electronic cigarette" - desc = "A premium model eGavana MK3 electronic cigarette, shaped like a cigar." - icon = 'icons/obj/items/ecig.dmi' - icon_state = "pcigoff1" - item_state = "pcigoff1" + desc = "A premium model eHavana MK3 electronic cigarette, shaped like a cigar." + icon = 'icons/clothing/mask/smokables/cigarette_electronic_deluxe.dmi' + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL - force = 3 + _base_attack_force = 3 throw_distance = 7 release_force = 10 -/obj/item/gun/launcher/syringe/disguised/examine(mob/user, distance) +/obj/item/gun/launcher/syringe/disguised/on_update_icon() + . = ..() + add_overlay("[icon_state]-loaded") + +/obj/item/gun/launcher/syringe/disguised/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 1) - to_chat(user, "The button is a little stiff.") + . += "The button is a little stiff." diff --git a/code/modules/projectiles/guns/magnetic/magnetic.dm b/code/modules/projectiles/guns/magnetic/magnetic.dm index bfa63ad9fdb7..43478d115947 100644 --- a/code/modules/projectiles/guns/magnetic/magnetic.dm +++ b/code/modules/projectiles/guns/magnetic/magnetic.dm @@ -5,26 +5,41 @@ icon_state = ICON_STATE_WORLD one_hand_penalty = 5 fire_delay = 20 - origin_tech = "{'combat':5,'materials':4,'esoteric':2,'magnets':4}" + origin_tech = @'{"combat":5,"materials":4,"esoteric":2,"magnets":4}' w_class = ITEM_SIZE_LARGE bulk = GUN_BULK_RIFLE combustion = 1 - var/obj/item/cell/cell // Currently installed powercell. - var/obj/item/stock_parts/capacitor/capacitor // Installed capacitor. Higher rating == faster charge between shots. + var/obj/item/stock_parts/capacitor/capacitor // Installed capacitor. Higher rating == faster charge between shots. var/removable_components = TRUE // Whether or not the gun can be dismantled. var/gun_unreliable = 15 // Percentage chance of detonating in your hands. var/obj/item/loaded // Currently loaded object, for retrieval/unloading. - var/load_type = /obj/item/stack/material/rods // Type of stack to load with. - var/load_sheet_max = 1 // Maximum number of "sheets" you can load from a stack. + var/load_type = /obj/item/stack/material/rods // Type of stack to load with. + var/load_sheet_max = 1 // Maximum number of "sheets" you can load from a stack. var/projectile_type = /obj/item/projectile/bullet/magnetic // Actual fire type, since this isn't throw_at rod launcher. var/power_cost = 950 // Cost per fire, should consume almost an entire basic cell. var/power_per_tick // Capacitor charge per process(). Updated based on capacitor rating. +/obj/item/gun/magnetic/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(loaded_cell_type, /obj/item/cell, (removable_components ? /datum/extension/loaded_cell : /datum/extension/loaded_cell/unremovable), charge_value) + +/obj/item/gun/magnetic/preloaded + capacitor = /obj/item/stock_parts/capacitor/adv + +/obj/item/gun/magnetic/preloaded/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/high, accepted_cell_type, power_supply_extension_type, charge_value) + /obj/item/gun/magnetic/Initialize() START_PROCESSING(SSobj, src) + setup_power_supply() + if (ispath(capacitor)) + capacitor = new capacitor() + capacitor.charge = capacitor.max_charge + if (ispath(loaded)) + loaded = new loaded(src, load_sheet_max) + if(capacitor) power_per_tick = (power_cost*0.15) * capacitor.rating update_icon() @@ -32,16 +47,13 @@ /obj/item/gun/magnetic/Destroy() STOP_PROCESSING(SSobj, src) - QDEL_NULL(cell) QDEL_NULL(loaded) QDEL_NULL(capacitor) . = ..() -/obj/item/gun/magnetic/get_cell() - return cell - /obj/item/gun/magnetic/Process() if(capacitor) + var/obj/item/cell/cell = get_cell() if(cell) if(capacitor.charge < capacitor.max_charge && cell.checked_use(power_per_tick)) capacitor.charge(power_per_tick) @@ -52,148 +64,127 @@ /obj/item/gun/magnetic/on_update_icon() . = ..() - var/list/overlays_to_add = list() + var/obj/item/cell/cell = get_cell() if(removable_components) if(cell) - overlays_to_add += image(icon, "[icon_state]_cell") + add_overlay("[icon_state]_cell") if(capacitor) - overlays_to_add += image(icon, "[icon_state]_capacitor") + add_overlay("[icon_state]_capacitor") if(!cell || !capacitor) - overlays_to_add += image(icon, "[icon_state]_red") + add_overlay("[icon_state]_red") else if(capacitor.charge < power_cost) - overlays_to_add += image(icon, "[icon_state]_amber") + add_overlay("[icon_state]_amber") else - overlays_to_add += image(icon, "[icon_state]_green") + add_overlay("[icon_state]_green") if(loaded) - overlays_to_add += image(icon, "[icon_state]_loaded") + add_overlay("[icon_state]_loaded") var/obj/item/magnetic_ammo/mag = loaded if(istype(mag)) if(mag.remaining) - overlays_to_add += image(icon, "[icon_state]_ammo") - - overlays += overlays_to_add + add_overlay("[icon_state]_ammo") /obj/item/gun/magnetic/proc/show_ammo(var/mob/user) if(loaded) to_chat(user, "It has \a [loaded] loaded.") -/obj/item/gun/magnetic/examine(mob/user) +/obj/item/gun/magnetic/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(cell) - to_chat(user, "The installed [cell.name] has a charge level of [round((cell.charge/cell.maxcharge)*100)]%.") - if(capacitor) - to_chat(user, "The installed [capacitor.name] has a charge level of [round((capacitor.charge/capacitor.max_charge)*100)]%.") - if(!cell || !capacitor) - to_chat(user, "The capacitor charge indicator is blinking red. Maybe you should check the cell or capacitor.") + if(!get_cell() || !capacitor) + . += SPAN_NOTICE("The capacitor charge indicator is blinking [SPAN_RED("red")]. Maybe you should check the cell or capacitor.") else + . += SPAN_NOTICE("The installed [capacitor.name] has a charge level of [round((capacitor.charge/capacitor.max_charge)*100)]%.") if(capacitor.charge < power_cost) - to_chat(user, "The capacitor charge indicator is amber.") + . += SPAN_NOTICE("The capacitor charge indicator is [SPAN_ORANGE("amber")].") else - to_chat(user, "The capacitor charge indicator is green.") + . += SPAN_NOTICE("The capacitor charge indicator is [SPAN_GREEN("green")].") -/obj/item/gun/magnetic/attackby(var/obj/item/thing, var/mob/user) +/obj/item/gun/magnetic/attackby(var/obj/item/used_item, var/mob/user) if(removable_components) - if(istype(thing, /obj/item/cell)) - if(cell) - to_chat(user, "\The [src] already has \a [cell] installed.") - return - if(!user.unEquip(thing, src)) - return - cell = thing - playsound(loc, 'sound/machines/click.ogg', 10, 1) - user.visible_message("\The [user] slots \the [cell] into \the [src].") - update_icon() - return - - if(isScrewdriver(thing)) + if(IS_SCREWDRIVER(used_item)) if(!capacitor) to_chat(user, "\The [src] has no capacitor installed.") - return + return TRUE user.put_in_hands(capacitor) user.visible_message("\The [user] unscrews \the [capacitor] from \the [src].") playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) capacitor = null update_icon() - return - - if(istype(thing, /obj/item/stock_parts/capacitor)) + return TRUE + if(istype(used_item, /obj/item/stock_parts/capacitor)) if(capacitor) to_chat(user, "\The [src] already has \a [capacitor] installed.") - return - if(!user.unEquip(thing, src)) - return - capacitor = thing + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + capacitor = used_item playsound(loc, 'sound/machines/click.ogg', 10, 1) power_per_tick = (power_cost*0.15) * capacitor.rating user.visible_message("\The [user] slots \the [capacitor] into \the [src].") update_icon() - return - - if(istype(thing, load_type)) - - // This is not strictly necessary for the magnetic gun but something using - // specific ammo types may exist down the track. - var/obj/item/stack/ammo = thing - if(!istype(ammo)) - if(loaded) - to_chat(user, "\The [src] already has \a [loaded] loaded.") - return - var/obj/item/magnetic_ammo/mag = thing - if(istype(mag)) - if(!(load_type == mag.basetype)) - to_chat(user, "\The [src] doesn't seem to accept \a [mag].") - return - projectile_type = mag.projectile_type - if(!user.unEquip(thing, src)) - return - - loaded = thing - else if(load_sheet_max > 1) - var ammo_count = 0 - var/obj/item/stack/loaded_ammo = loaded - if(!istype(loaded_ammo)) - ammo_count = min(load_sheet_max,ammo.amount) - loaded = new load_type(src, ammo_count) - else - ammo_count = min(load_sheet_max-loaded_ammo.amount,ammo.amount) - loaded_ammo.amount += ammo_count - if(ammo_count <= 0) - // This will also display when someone tries to insert a stack of 0, but that shouldn't ever happen anyway. - to_chat(user, "\The [src] is already fully loaded.") - return - ammo.use(ammo_count) - else - if(loaded) - to_chat(user, "\The [src] already has \a [loaded] loaded.") - return - loaded = new load_type(src, 1) - ammo.use(1) - - user.visible_message("\The [user] loads \the [src] with \the [loaded].") - playsound(loc, 'sound/weapons/flipblade.ogg', 50, 1) - update_icon() - return - . = ..() + return TRUE -/obj/item/gun/magnetic/attack_hand(var/mob/user) - if(user.get_inactive_hand() == src) - var/obj/item/removing + if(!istype(used_item, load_type)) + return ..() + // This is not strictly necessary for the magnetic gun but something using + // specific ammo types may exist down the track. + var/obj/item/stack/ammo = used_item + if(!istype(ammo)) if(loaded) - removing = loaded - loaded = null - else if(cell && removable_components) - removing = cell - cell = null - - if(removing) - user.put_in_hands(removing) - user.visible_message("\The [user] removes \the [removing] from \the [src].") - playsound(loc, 'sound/machines/click.ogg', 10, 1) - update_icon() - return - . = ..() + to_chat(user, "\The [src] already has \a [loaded] loaded.") + return TRUE + var/obj/item/magnetic_ammo/mag = used_item + if(istype(mag)) + if(!(load_type == mag.basetype)) + to_chat(user, "\The [src] doesn't seem to accept \a [mag].") + return TRUE + projectile_type = mag.projectile_type + if(!user.try_unequip(used_item, src)) + return TRUE + + loaded = used_item + else if(load_sheet_max > 1) + var ammo_count = 0 + var/obj/item/stack/loaded_ammo = loaded + if(!istype(loaded_ammo)) + ammo_count = min(load_sheet_max,ammo.amount) + loaded = new load_type(src, ammo_count) + else + ammo_count = min(load_sheet_max-loaded_ammo.amount,ammo.amount) + loaded_ammo.amount += ammo_count + if(ammo_count <= 0) + // This will also display when someone tries to insert a stack of 0, but that shouldn't ever happen anyway. + to_chat(user, "\The [src] is already fully loaded.") + return TRUE + ammo.use(ammo_count) + else + if(loaded) + to_chat(user, "\The [src] already has \a [loaded] loaded.") + return TRUE + loaded = new load_type(src, 1) + ammo.use(1) + + user.visible_message("\The [user] loads \the [src] with \the [loaded].") + playsound(loc, 'sound/weapons/flipblade.ogg', 50, 1) + update_icon() + return TRUE + +/obj/item/gun/magnetic/attack_hand(var/mob/user) + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + var/obj/item/removing + if(loaded) + removing = loaded + loaded = null + else if(removable_components && get_cell()) + return ..() + if(removing) + user.put_in_hands(removing) + user.visible_message(SPAN_NOTICE("\The [user] removes \the [removing] from \the [src].")) + playsound(loc, 'sound/machines/click.ogg', 10, 1) + update_icon() + return TRUE /obj/item/gun/magnetic/proc/check_ammo() return loaded @@ -217,4 +208,4 @@ explosion(get_turf(src), -1, 0, 2) qdel(src) - return new projectile_type(src) \ No newline at end of file + return new projectile_type(src) diff --git a/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm b/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm index 8f49f199e7a7..30bb71cea69e 100644 --- a/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm +++ b/code/modules/projectiles/guns/magnetic/magnetic_railgun.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/guns/railgun.dmi' removable_components = TRUE // Can swap out the capacitor for more shots, or cell for longer usage before recharge load_type = /obj/item/rcd_ammo - origin_tech = "{'combat':5,'materials':4,'magnets':4}" + origin_tech = @'{"combat":5,"materials":4,"magnets":4}' projectile_type = /obj/item/projectile/bullet/magnetic/slug one_hand_penalty = 6 power_cost = 300 @@ -14,26 +14,20 @@ loaded = /obj/item/rcd_ammo/large // ~30 shots combustion = 1 bulk = GUN_BULK_RIFLE + 3 - - var/initial_cell_type = /obj/item/cell/hyper - var/initial_capacitor_type = /obj/item/stock_parts/capacitor/adv // 6-8 shots + capacitor = /obj/item/stock_parts/capacitor/adv // 6-8 shots gun_unreliable = 0 var/slowdown_held = 3 var/slowdown_worn = 2 -/obj/item/gun/magnetic/railgun/Initialize() - - capacitor = new initial_capacitor_type(src) - capacitor.charge = capacitor.max_charge +/obj/item/gun/magnetic/railgun/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/hyper, accepted_cell_type, power_supply_extension_type, charge_value) - cell = new initial_cell_type(src) - if (ispath(loaded)) - loaded = new loaded (src, load_sheet_max) - slowdown_per_slot[slot_l_hand] = slowdown_held - slowdown_per_slot[slot_r_hand] = slowdown_held - slowdown_per_slot[slot_back] = slowdown_worn - slowdown_per_slot[slot_belt] = slowdown_worn - slowdown_per_slot[slot_s_store] = slowdown_worn +/obj/item/gun/magnetic/railgun/Initialize() + LAZYSET(slowdown_per_slot, BP_L_HAND, slowdown_held) + LAZYSET(slowdown_per_slot, BP_R_HAND, slowdown_held) + LAZYSET(slowdown_per_slot, slot_back_str, slowdown_worn) + LAZYSET(slowdown_per_slot, slot_belt_str, slowdown_worn) + LAZYSET(slowdown_per_slot, slot_s_store_str, slowdown_worn) . = ..() @@ -70,8 +64,7 @@ one_hand_penalty = 2 fire_delay = 8 removable_components = FALSE - initial_cell_type = /obj/item/cell/hyper - initial_capacitor_type = /obj/item/stock_parts/capacitor/adv + capacitor = /obj/item/stock_parts/capacitor/adv slot_flags = SLOT_BACK power_cost = 100 load_type = /obj/item/magnetic_ammo diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index c5eb5daf7c43..e3f38df807fc 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -2,8 +2,7 @@ name = "gun" desc = "A gun that fires bullets." icon = 'icons/obj/guns/pistol.dmi' - icon_state = "pistol" - origin_tech = "{'combat':2,'materials':2}" + origin_tech = @'{"combat":2,"materials":2}' w_class = ITEM_SIZE_NORMAL material = /decl/material/solid/metal/steel screen_shake = 1 @@ -30,6 +29,7 @@ var/auto_eject_sound = null var/mag_insert_sound = 'sound/weapons/guns/interaction/pistol_magin.ogg' var/mag_remove_sound = 'sound/weapons/guns/interaction/pistol_magout.ogg' + var/manual_unload = TRUE //Whether or not the gun can be unloaded by hand. var/is_jammed = 0 //Whether this gun is jammed var/jam_chance = 0 //Chance it jams on fire @@ -49,6 +49,12 @@ ammo_magazine = new magazine_type(src) update_icon() +/obj/item/gun/projectile/Destroy() + chambered = null + loaded.Cut() + ammo_magazine = null + return ..() + /obj/item/gun/projectile/consume_next_projectile() if(!is_jammed && prob(jam_chance)) src.visible_message("\The [src] jams!") @@ -68,10 +74,16 @@ chambered = loaded[1] //load next casing. if(handle_casings != HOLD_CASINGS) loaded -= chambered - else if(ammo_magazine && ammo_magazine.stored_ammo.len) - chambered = ammo_magazine.stored_ammo[ammo_magazine.stored_ammo.len] - if(handle_casings != HOLD_CASINGS) - ammo_magazine.stored_ammo -= chambered + else if(ammo_magazine) + if(!ammo_magazine.contents_initialized && ammo_magazine.initial_ammo > 0) + chambered = new ammo_magazine.ammo_type(src) + if(handle_casings == HOLD_CASINGS) + ammo_magazine.stored_ammo += chambered + ammo_magazine.initial_ammo-- + else if(length(ammo_magazine.stored_ammo)) + chambered = ammo_magazine.stored_ammo[length(ammo_magazine.stored_ammo)] + if(handle_casings != HOLD_CASINGS) + ammo_magazine.stored_ammo -= chambered if (chambered) return chambered.BB @@ -83,14 +95,15 @@ chambered.expend() process_chambered() -/obj/item/gun/projectile/process_point_blank(obj/projectile, mob/user, atom/target) +/obj/item/gun/projectile/process_point_blank(obj/projectile, atom/movable/firer, atom/target) ..() if(chambered && ishuman(target)) - var/mob/living/carbon/human/H = target + var/mob/living/human/H = target var/zone = BP_CHEST - if(user && user.zone_sel) - zone = user.zone_sel.selecting - var/obj/item/organ/external/E = H.get_organ(zone) + if(isliving(firer)) + var/mob/living/user = firer + zone = user.get_target_zone() || zone + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(H, zone) if(E) chambered.put_residue_on(E) H.apply_damage(3, BURN, used_weapon = "Gunpowder Burn", given_organ = E) @@ -106,8 +119,8 @@ if(EJECT_CASINGS) //eject casing onto ground. chambered.dropInto(loc) chambered.throw_at(get_ranged_target_turf(get_turf(src),turn(loc.dir,270),1), rand(0,1), 5) - if(LAZYLEN(chambered.fall_sounds)) - playsound(loc, pick(chambered.fall_sounds), 50, 1) + if(chambered.drop_sound) + playsound(loc, pick(chambered.drop_sound), 50, 1) if(CYCLE_CASINGS) //cycle the casing back to the end. if(ammo_magazine) ammo_magazine.stored_ammo += chambered @@ -121,11 +134,17 @@ //Attempts to load A into src, depending on the type of thing being loaded and the load_method //Maybe this should be broken up into separate procs for each load method? /obj/item/gun/projectile/proc/load_ammo(var/obj/item/A, mob/user) + + // This gun cannot be manually reloaded. + if(caliber == CALIBER_UNUSABLE) + return + if(istype(A, /obj/item/ammo_magazine)) . = TRUE var/obj/item/ammo_magazine/AM = A if(!(load_method & AM.mag_type) || caliber != AM.caliber) return //incompatible + AM.create_initial_contents() switch(AM.mag_type) if(MAGAZINE) @@ -136,7 +155,7 @@ to_chat(user, "[src] already has a magazine loaded.")//already a magazine here return - if(!user.unEquip(AM, src)) + if(!user.try_unequip(AM, src)) return ammo_magazine = AM user.visible_message("[user] inserts [AM] into [src].", "You insert [AM] into [src].") @@ -166,7 +185,7 @@ if(loaded.len >= max_shells) to_chat(user, "[src] is full.") return - if(!user.unEquip(C, src)) + if(!user.try_unequip(C, src)) return loaded.Insert(1, C) //add to the head of the list user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src].") @@ -176,60 +195,115 @@ //attempts to unload src. If allow_dump is set to 0, the speedloader unloading method will be disabled /obj/item/gun/projectile/proc/unload_ammo(mob/user, var/allow_dump=1) + + . = FALSE if(is_jammed) - user.visible_message("\The [user] begins to unjam [src].", "You clear the jam and unload [src]") + user.visible_message("\The [user] begins to unjam [src].", "You clear the jam and unload [src].") if(!do_after(user, 4, src)) return is_jammed = 0 playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) + if(ammo_magazine) user.put_in_hands(ammo_magazine) user.visible_message("[user] removes [ammo_magazine] from [src].", "You remove [ammo_magazine] from [src].") playsound(loc, mag_remove_sound, 50, 1) ammo_magazine.update_icon() ammo_magazine = null - else if(loaded.len) + . = TRUE + + else if(length(loaded)) //presumably, if it can be speed-loaded, it can be speed-unloaded. if(allow_dump && (load_method & SPEEDLOADER)) var/count = 0 var/turf/T = get_turf(user) if(T) for(var/obj/item/ammo_casing/C in loaded) - if(LAZYLEN(C.fall_sounds)) - playsound(loc, pick(C.fall_sounds), 50, 1) + if(LAZYLEN(C.drop_sound)) + playsound(loc, pick(C.drop_sound), 50, 1) C.forceMove(T) count++ loaded.Cut() if(count) user.visible_message("[user] unloads [src].", "You unload [count] round\s from [src].") + . = TRUE else if(load_method & SINGLE_CASING) var/obj/item/ammo_casing/C = loaded[loaded.len] loaded.len-- user.put_in_hands(C) user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src].") - else - to_chat(user, "[src] is empty.") + . = TRUE + if(.) + update_icon() + +/obj/item/gun/projectile/proc/try_remove_silencer(mob/user) + if(!istype(user) || !istype(silencer, /obj/item)) + return FALSE + if(!user.is_holding_offhand(src)) + return FALSE + if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS, TRUE)) + return FALSE + to_chat(user, SPAN_NOTICE("You unscrew \the [silencer] from \the [src].")) + user.put_in_hands(silencer) + silencer = initial(silencer) + w_class = initial(w_class) update_icon() + return TRUE + +/obj/item/gun/projectile/proc/can_have_silencer() + return FALSE + +/obj/item/gun/projectile/attackby(var/obj/item/used_item, mob/user) + + if(load_ammo(used_item, user)) + return TRUE + + if(istype(used_item, /obj/item/silencer)) -/obj/item/gun/projectile/attackby(var/obj/item/A, mob/user) - if(!load_ammo(A, user)) - return ..() + if(istype(silencer, /obj/item)) + to_chat(user, SPAN_WARNING("\The [src] already has \a [silencer] attached.")) + return TRUE + + if(silencer) + to_chat(user, SPAN_WARNING("\The [src] does not need a silencer; it is already silent.")) + return TRUE + + if(!can_have_silencer()) + to_chat(user, SPAN_WARNING("\The [src] cannot be fitted with a silencer.")) + return TRUE + + if(!(src in user.get_held_items())) //if we're not in his hands + to_chat(user, SPAN_WARNING("You'll need \the [src] in your hands to do that.")) + return TRUE + + if(user.try_unequip(used_item, src)) + to_chat(user, SPAN_NOTICE("You screw \the [used_item] onto \the [src].")) + silencer = used_item + w_class = ITEM_SIZE_NORMAL + update_icon() + return TRUE + + . = ..() /obj/item/gun/projectile/attack_self(mob/user) - if(firemodes.len > 1) - ..() - else - unload_ammo(user) + if(length(firemodes) <= 1) + if(manual_unload && unload_ammo(user)) + return TRUE + if(try_remove_silencer(user)) + return TRUE + return ..() /obj/item/gun/projectile/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - unload_ammo(user, allow_dump=0) - else - return ..() + if(src in user.get_inactive_held_items()) + if(manual_unload && unload_ammo(user, allow_dump = FALSE)) + return TRUE + if(try_remove_silencer(user)) + return TRUE + return ..() /obj/item/gun/projectile/afterattack(atom/A, mob/living/user) ..() - if(auto_eject && ammo_magazine && ammo_magazine.stored_ammo && !ammo_magazine.stored_ammo.len) + if(auto_eject && ammo_magazine && !ammo_magazine.get_stored_ammo_count()) ammo_magazine.dropInto(loc) user.visible_message( "[ammo_magazine] falls out and clatters on the floor!", @@ -241,21 +315,21 @@ ammo_magazine = null update_icon() //make sure to do this after unsetting ammo_magazine -/obj/item/gun/projectile/examine(mob/user) +/obj/item/gun/projectile/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(is_jammed && user.skill_check(SKILL_WEAPONS, SKILL_BASIC)) - to_chat(user, "It looks jammed.") + . += SPAN_WARNING("It looks jammed.") if(ammo_magazine) - to_chat(user, "It has \a [ammo_magazine] loaded.") + . += "It has \a [ammo_magazine] loaded." if(user.skill_check(SKILL_WEAPONS, SKILL_ADEPT)) - to_chat(user, "Has [getAmmo()] round\s remaining.") + . += "Has [getAmmo()] round\s remaining." /obj/item/gun/projectile/proc/getAmmo() var/bullets = 0 if(loaded) bullets += loaded.len - if(ammo_magazine && ammo_magazine.stored_ammo) - bullets += ammo_magazine.stored_ammo.len + if(ammo_magazine) + bullets += ammo_magazine.get_stored_ammo_count() if(chambered) bullets += 1 return bullets @@ -263,25 +337,40 @@ /obj/item/gun/projectile/on_update_icon() ..() if(ammo_indicator) - overlays += get_ammo_indicator() - + add_overlay(get_ammo_indicator()) + /obj/item/gun/projectile/proc/get_ammo_indicator() var/base_state = get_world_inventory_state() - if(!ammo_magazine || !LAZYLEN(ammo_magazine.stored_ammo)) - return get_mutable_overlay(icon, "[base_state]_ammo_bad") - else if(LAZYLEN(ammo_magazine.stored_ammo) <= 0.5 * ammo_magazine.max_ammo) - return get_mutable_overlay(icon, "[base_state]_ammo_warn") + if(!ammo_magazine || !ammo_magazine.get_stored_ammo_count()) + return mutable_appearance(icon, "[base_state]_ammo_bad") + else if(LAZYLEN(ammo_magazine.get_stored_ammo_count()) <= 0.5 * ammo_magazine.max_ammo) + return mutable_appearance(icon, "[base_state]_ammo_warn") else - return get_mutable_overlay(icon, "[base_state]_ammo_ok") + return mutable_appearance(icon, "[base_state]_ammo_ok") + +/obj/item/gun/projectile/get_alt_interactions(mob/user) + . = ..() + if(isitem(silencer)) + LAZYADD(., /decl/interaction_handler/projectile/remove_silencer) + if(ammo_magazine || length(loaded)) + LAZYADD(., /decl/interaction_handler/projectile/unload_ammo) + +/decl/interaction_handler/projectile + abstract_type = /decl/interaction_handler/projectile + expected_target_type = /obj/item/gun/projectile + +/decl/interaction_handler/projectile/remove_silencer + name = "Remove Silencer" + examine_desc = "remove the silencer" -/* Unneeded -- so far. -//in case the weapon has firemodes and can't unload using attack_hand() -/obj/item/gun/projectile/verb/unload_gun() - set name = "Unload Ammo" - set category = "Object" - set src in usr +/decl/interaction_handler/projectile/remove_silencer/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/gun/projectile/gun = target + gun.try_remove_silencer(user) - if(usr.stat || usr.restrained()) return +/decl/interaction_handler/projectile/unload_ammo + name = "Remove Ammunition" + examine_desc = "unload the ammunition" - unload_ammo(usr) -*/ +/decl/interaction_handler/projectile/unload_ammo/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/gun/projectile/gun = target + gun.unload_ammo(user) diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index a4b77d8fc4c6..1614d25961e8 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -6,8 +6,8 @@ safety_icon = "safety" w_class = ITEM_SIZE_NORMAL caliber = CALIBER_PISTOL_SMALL - origin_tech = "{'combat':5,'materials':2}" - slot_flags = SLOT_BELT|SLOT_BACK + origin_tech = @'{"combat":5,"materials":2}' + slot_flags = SLOT_LOWER_BODY|SLOT_BACK ammo_type = /obj/item/ammo_casing/pistol/small load_method = MAGAZINE magazine_type = /obj/item/ammo_magazine/smg/rubber @@ -27,24 +27,24 @@ firemodes = list( list(mode_name="semi auto", burst=1, fire_delay=null, one_hand_penalty=3, burst_accuracy=null, dispersion=null), - list(mode_name="3-round bursts", burst=3, fire_delay=null, one_hand_penalty=4, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)), - list(mode_name="short bursts", burst=5, fire_delay=null, one_hand_penalty=5, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(0.6, 0.6, 1.0, 1.0, 1.2)), - list(mode_name="full auto", can_autofire=1, burst=1, fire_delay=1, one_hand_penalty=7, burst_accuracy = list(0,-1,-1,-2,-2,-2,-3,-3), dispersion = list(1.0, 1.0, 1.0, 1.0, 1.2)) - ) + list(mode_name="3-round bursts", burst=3, fire_delay=null, one_hand_penalty=4, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 1.6, 2.4, 2.4)), + list(mode_name="short bursts", burst=5, fire_delay=null, one_hand_penalty=5, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(1.6, 1.6, 2.0, 2.0, 2.4)), + list(mode_name="full auto", burst=1, fire_delay=0, burst_delay=1, one_hand_penalty=5, burst_accuracy=list(0,-1,-1,-1,-2), dispersion=list(1.6, 1.6, 2.0, 2.0, 2.4), autofire_enabled=1) + ) /obj/item/gun/projectile/automatic/smg/on_update_icon() ..() if(ammo_magazine) - overlays += image(icon, "[get_world_inventory_state()]mag-[round(ammo_magazine.stored_ammo.len,5)]") + add_overlay("[get_world_inventory_state()]mag-[round(ammo_magazine.get_stored_ammo_count(),5)]") /obj/item/gun/projectile/automatic/assault_rifle name = "assault rifle" desc = "The Z8 Bulldog is an older model bullpup carbine. Makes you feel like a space marine when you hold it." icon = 'icons/obj/guns/bullpup_rifle.dmi' w_class = ITEM_SIZE_HUGE - force = 10 + _base_attack_force = 10 caliber = CALIBER_RIFLE - origin_tech = "{'combat':8,'materials':3}" + origin_tech = @'{"combat":7,"materials":3}' ammo_type = /obj/item/ammo_casing/rifle slot_flags = SLOT_BACK load_method = MAGAZINE @@ -65,50 +65,128 @@ /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) firemodes = list( - list(mode_name="semi auto", burst=1, fire_delay=null, use_launcher=null, one_hand_penalty=8, burst_accuracy=null, dispersion=null), - list(mode_name="3-round bursts", burst=3, fire_delay=null, use_launcher=null, one_hand_penalty=9, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)), - list(mode_name="fire grenades", burst=null, fire_delay=null, use_launcher=1, one_hand_penalty=10, burst_accuracy=null, dispersion=null) + list(mode_name="semi auto", burst=1, fire_delay=null, one_hand_penalty=8, burst_accuracy=null, dispersion=null), + list(mode_name="3-round bursts", burst=3, fire_delay=null, one_hand_penalty=9, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)), + list(mode_name="full auto", burst=1, fire_delay=0, burst_delay=1, one_hand_penalty=7, burst_accuracy = list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), autofire_enabled=1) + ) + +/obj/item/gun/projectile/automatic/assault_rifle/update_base_icon_state() + . = ..() + if(ammo_magazine?.get_stored_ammo_count()) + icon_state = "[icon_state]-loaded" + else + icon_state = "[icon_state]-empty" + +/obj/item/gun/projectile/automatic/assault_rifle/grenade + name = "assault rifle" + desc = "The Z8 Bulldog is an older model bullpup carbine. This one has an underslung grenade launcher. REALLY makes you feel like a space marine when you hold it." + origin_tech = @'{"combat":8,"materials":3}' + + firemodes = list( + list(mode_name="semi auto", burst=1, fire_delay=null, use_launcher=null, one_hand_penalty=8, burst_accuracy=null, dispersion=null), + list(mode_name="3-round bursts", burst=3, fire_delay=null, use_launcher=null, one_hand_penalty=9, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)), + list(mode_name="fire grenades", burst=null, fire_delay=null, use_launcher=1, one_hand_penalty=10, burst_accuracy=null, dispersion=null), + list(mode_name="full auto", burst=1, fire_delay=0, burst_delay=1, use_launcher=null, one_hand_penalty=7, burst_accuracy = list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), autofire_enabled=1) ) var/use_launcher = 0 var/obj/item/gun/launcher/grenade/underslung/launcher -/obj/item/gun/projectile/automatic/assault_rifle/Initialize() +/obj/item/gun/projectile/automatic/assault_rifle/grenade/Initialize() . = ..() launcher = new(src) -/obj/item/gun/projectile/automatic/assault_rifle/attackby(obj/item/I, mob/user) - if((istype(I, /obj/item/grenade))) - launcher.load(I, user) - else - ..() +/obj/item/gun/projectile/automatic/assault_rifle/grenade/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/grenade)) + return ..() + launcher.load(used_item, user) + return TRUE -/obj/item/gun/projectile/automatic/assault_rifle/attack_hand(mob/user) - if(user.get_inactive_hand() == src && use_launcher) - launcher.unload(user) - else - ..() +/obj/item/gun/projectile/automatic/assault_rifle/grenade/attack_hand(mob/user) + if(!user.is_holding_offhand(src) || !use_launcher || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + launcher.unload(user) + return TRUE -/obj/item/gun/projectile/automatic/assault_rifle/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0) +/obj/item/gun/projectile/automatic/assault_rifle/grenade/Fire(atom/target, atom/movable/firer, clickparams, pointblank = FALSE, reflex = FALSE, set_click_cooldown = TRUE, target_zone = BP_CHEST) if(use_launcher) - launcher.Fire(target, user, params, pointblank, reflex) + launcher.Fire(target, firer, clickparams, pointblank, reflex) if(!launcher.chambered) switch_firemodes() //switch back automatically else ..() -/obj/item/gun/projectile/automatic/assault_rifle/update_base_icon() - if(ammo_magazine) - if(ammo_magazine.stored_ammo.len) - icon_state = "[get_world_inventory_state()]-loaded" - else - icon_state = "[get_world_inventory_state()]-empty" - else - icon_state = get_world_inventory_state() - -/obj/item/gun/projectile/automatic/assault_rifle/examine(mob/user) +/obj/item/gun/projectile/automatic/assault_rifle/grenade/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(launcher.chambered) - to_chat(user, "\The [launcher] has \a [launcher.chambered] loaded.") + . += "\The [launcher] has \a [launcher.chambered] loaded." else - to_chat(user, "\The [launcher] is empty.") + . += "\The [launcher] is empty." + +/obj/item/gun/projectile/automatic/assault_rifle/grenade/toggle_safety(mob/user) + . = ..() + launcher.toggle_safety() // Do not pass user to prevent double messages. + +// Admin-spawn machine gun. Mech subtype is meant to be used, but this can be spawned for hulks. +/obj/item/gun/projectile/automatic/machine + name = "massive machine gun" + desc = "The XC-67 \"Creosote\" is a massive machine gun, and ranks high on most tin-pot dictators' wish lists. Firing this thing without some sort of weapons platform is a hopeless task." + icon = 'icons/obj/guns/machine.dmi' + w_class = ITEM_SIZE_HUGE + _base_attack_force = 10 + caliber = CALIBER_RIFLE + origin_tech = @'{"combat":9,"materials":3}' + ammo_type = /obj/item/ammo_casing/rifle + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/rifle/drum + allowed_magazines = /obj/item/ammo_magazine/rifle/drum + accuracy = 1 + accuracy_power = 7 + one_hand_penalty = 3000 + bulk = GUN_BULK_RIFLE + + burst_delay = 1 + burst = 3 + burst_accuracy = list(0,-1,-1) + dispersion = list(0.0, 0.6, 1.0) + + fire_delay = 0 + autofire_enabled = 1 + + mag_insert_sound = 'sound/weapons/guns/interaction/batrifle_magin.ogg' + mag_remove_sound = 'sound/weapons/guns/interaction/batrifle_magout.ogg' + material = /decl/material/solid/metal/steel + + var/spin_up_time = null + var/sound_token + +/obj/item/gun/projectile/automatic/machine/Fire(atom/target, mob/living/user, clickparams, pointblank, reflex, set_click_cooldown, target_zone) + if(!spin_up_time || world.time < spin_up_time + 1 SECONDS) + return FALSE + . = ..() + +/obj/item/gun/projectile/automatic/machine/special_check(mob/user) + if(!isliving(user)) + return FALSE + if(!user.check_dexterity(DEXTERITY_WEAPONS)) + return FALSE + + var/mob/living/M = user + if(M.mob_size < MOB_SIZE_LARGE) + to_chat(user, SPAN_WARNING("You can barely lift \the [src], let alone fire it!")) + return FALSE + return TRUE + +/obj/item/gun/projectile/automatic/machine/set_autofire(atom/fire_at, mob/fire_by, autoturn) + if(!special_check(fire_by)) + return FALSE + . = ..() + if(. && !spin_up_time) + if(!sound_token) + sound_token = play_looping_sound(src, "machine_gun", 'sound/mecha/hydraulic.ogg', volume = 30) + spin_up_time = world.time + +/obj/item/gun/projectile/automatic/machine/clear_autofire() + . = ..() + spin_up_time = null + QDEL_NULL(sound_token) \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/bolt_action.dm b/code/modules/projectiles/guns/projectile/bolt_action.dm new file mode 100644 index 000000000000..6b4d368adefa --- /dev/null +++ b/code/modules/projectiles/guns/projectile/bolt_action.dm @@ -0,0 +1,89 @@ +/obj/item/gun/projectile/bolt_action + name = "bolt-action rifle" + desc = "A slow-firing but reliable bolt-action rifle. Rather old-fashioned." + icon = 'icons/obj/guns/bolt_action.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + origin_tech = @'{"combat":4,"materials":2}' + caliber = CALIBER_RIFLE + handle_casings = HOLD_CASINGS + load_method = SINGLE_CASING + max_shells = 1 + ammo_type = /obj/item/ammo_casing/rifle + one_hand_penalty = 2 + load_sound = 'sound/weapons/guns/interaction/rifle_load.ogg' + fire_delay = 8 + var/bolt_open = FALSE + +/obj/item/gun/projectile/bolt_action/on_update_icon() + ..() + if(bolt_open) + icon_state = "[get_world_inventory_state()]-open" + else + icon_state = get_world_inventory_state() + +/obj/item/gun/projectile/bolt_action/handle_post_fire(atom/movable/firer, atom/target, var/pointblank=0, var/reflex=0) + ..() + if(ismob(firer)) + var/mob/user = firer + if(user.skill_check(SKILL_WEAPONS, SKILL_PROF)) + to_chat(user, "You work the bolt open with a reflexive motion, ejecting [chambered]!") + unload_shell() + +/obj/item/gun/projectile/bolt_action/proc/unload_shell() + if(chambered) + if(!bolt_open) + playsound(src.loc, 'sound/weapons/guns/interaction/rifle_boltback.ogg', 50, 1) + bolt_open = TRUE + chambered.dropInto(src.loc) + loaded -= chambered + chambered = null + +/obj/item/gun/projectile/bolt_action/attack_self(mob/user) + bolt_open = !bolt_open + if(bolt_open) + if(chambered) + to_chat(user, "You work the bolt open, ejecting [chambered]!") + unload_shell() + else + to_chat(user, "You work the bolt open.") + playsound(src.loc, 'sound/weapons/guns/interaction/rifle_boltback.ogg', 50, 1) + else + to_chat(user, "You work the bolt closed.") + playsound(src.loc, 'sound/weapons/guns/interaction/rifle_boltforward.ogg', 50, 1) + bolt_open = FALSE + add_fingerprint(user) + update_icon() + +/obj/item/gun/projectile/bolt_action/special_check(mob/user) + if(bolt_open) + to_chat(user, "You can't fire [src] while the bolt is open!") + return 0 + return ..() + +/obj/item/gun/projectile/bolt_action/load_ammo(var/obj/item/A, mob/user) + if(!bolt_open) + return + ..() + +/obj/item/gun/projectile/bolt_action/unload_ammo(mob/user, var/allow_dump=1) + if(!bolt_open) + return FALSE + return ..() + +/obj/item/gun/projectile/bolt_action/sniper + name = "anti-materiel rifle" + desc = "A portable anti-armour rifle fitted with a scope, the HI PTR-7 Rifle was originally designed to be used against armoured exosuits. It is capable of punching through windows and non-reinforced walls with ease." + icon = 'icons/obj/guns/heavysniper.dmi' + _base_attack_force = 10 + origin_tech = @'{"combat":7,"materials":2,"esoteric":8}' + caliber = CALIBER_ANTI_MATERIEL + screen_shake = 2 //extra kickback + one_hand_penalty = 6 + accuracy = -2 + bulk = 8 + scoped_accuracy = 8 //increased accuracy over the LWAP because only one shot + scope_zoom = 2 + fire_delay = 12 + ammo_type = /obj/item/ammo_casing/shell diff --git a/code/modules/projectiles/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm index 4cdd4debb19e..ddf20a47a306 100644 --- a/code/modules/projectiles/guns/projectile/dartgun.dm +++ b/code/modules/projectiles/guns/projectile/dartgun.dm @@ -8,7 +8,7 @@ fire_sound = 'sound/weapons/empty.ogg' fire_sound_text = "a metallic click" screen_shake = 0 - silenced = 1 + silencer = TRUE load_method = MAGAZINE magazine_type = /obj/item/ammo_magazine/chemdart allowed_magazines = /obj/item/ammo_magazine/chemdart @@ -18,53 +18,57 @@ var/list/beakers = list() //All containers inside the gun. var/list/mixing = list() //Containers being used for mixing. var/max_beakers = 3 - var/dart_reagent_amount = 15 var/container_type = /obj/item/chems/glass/beaker var/list/starting_chems = null /obj/item/gun/projectile/dartgun/Initialize() - if(starting_chems) - for(var/chem in starting_chems) - var/obj/B = new container_type(src) - B.reagents.add_reagent(chem, 60) - beakers += B + chem_volume = length(starting_chems) * 60 . = ..() update_icon() +/obj/item/gun/projectile/dartgun/populate_reagents() + if(!starting_chems) + return + for(var/chem in starting_chems) + var/obj/B = new container_type(src) + B.add_to_reagents(chem, 60) + beakers += B + /obj/item/gun/projectile/dartgun/on_update_icon() ..() if(ammo_magazine) - icon_state = "[get_world_inventory_state()]-[Clamp(length(ammo_magazine.stored_ammo.len), 0, 5)]" + icon_state = "[get_world_inventory_state()]-[clamp(ammo_magazine.get_stored_ammo_count(), 0, 5)]" else icon_state = get_world_inventory_state() -/obj/item/gun/projectile/dartgun/experimental_mob_overlay(mob/user_mob, slot) - var/image/I = ..() - if(slot == slot_r_hand_str || slot == slot_l_hand_str) - if(ammo_magazine) - I.icon_state += "-[Clamp(length(ammo_magazine.stored_ammo.len), 0, 5)]" - return I -/obj/item/gun/projectile/dartgun/consume_next_projectile() +/obj/item/gun/projectile/dartgun/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && (slot in user_mob?.get_held_item_slots()) && ammo_magazine) + overlay.icon_state += "-[clamp(ammo_magazine.get_stored_ammo_count(), 0, 5)]" . = ..() - var/obj/item/projectile/bullet/chemdart/dart = . + +/obj/item/gun/projectile/dartgun/consume_next_projectile() + var/obj/item/projectile/bullet/chemdart/dart = ..() if(istype(dart)) fill_dart(dart) + return dart -/obj/item/gun/projectile/dartgun/examine(mob/user) +/obj/item/gun/projectile/dartgun/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if (beakers.len) - to_chat(user, "\The [src] contains:") + . += SPAN_NOTICE("\The [src] contains:") for(var/obj/item/chems/glass/beaker/B in beakers) - if(B.reagents && LAZYLEN(B.reagents?.reagent_volumes)) - for(var/rtype in B.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - to_chat(user, "[REAGENT_VOLUME(B.reagents, rtype)] units of [R.name]") - -/obj/item/gun/projectile/dartgun/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/chems/glass)) - add_beaker(I, user) - return 1 - ..() + var/reagent_volumes = REAGENT_VOLUMES(B.reagents) + if(B.reagents && LAZYLEN(reagent_volumes)) + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(B.reagents)) + . += SPAN_NOTICE("[LIQUID_VOLUME(B.reagents, reagent)] units of [reagent.get_reagent_name(B.reagents, MAT_PHASE_LIQUID)]") + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(B.reagents)) + . += SPAN_NOTICE("[SOLID_VOLUME(B.reagents, reagent)] units of [reagent.get_reagent_name(B.reagents, MAT_PHASE_SOLID)]") + +/obj/item/gun/projectile/dartgun/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/chems/glass)) + add_beaker(used_item, user) + return TRUE + return ..() /obj/item/gun/projectile/dartgun/proc/add_beaker(var/obj/item/chems/glass/B, mob/user) if(!istype(B, container_type)) @@ -73,7 +77,7 @@ if(beakers.len >= max_beakers) to_chat(user, "[src] already has [max_beakers] beakers in it - another one isn't going to fit!") return - if(!user.unEquip(B, src)) + if(!user.try_unequip(B, src)) return beakers |= B user.visible_message("\The [user] inserts \a [B] into [src].", "You slot [B] into [src].") @@ -86,8 +90,8 @@ //fills the given dart with reagents /obj/item/gun/projectile/dartgun/proc/fill_dart(var/obj/item/projectile/bullet/chemdart/dart) - if(mixing.len) - var/mix_amount = dart.reagent_amount/mixing.len + if(length(mixing)) + var/mix_amount = REAGENT_TOTAL_VOLUME(dart.reagents)/length(mixing) for(var/obj/item/chems/glass/beaker/B in mixing) B.reagents.trans_to_obj(dart, mix_amount) @@ -106,26 +110,27 @@ if(!istype(B)) continue dat += "Beaker [i] contains: " - if(B.reagents && LAZYLEN(B.reagents.reagent_volumes)) - for(var/rtype in B.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - dat += "
    [REAGENT_VOLUME(B.reagents, rtype)] units of [R.name], " + var/reagent_volumes = REAGENT_VOLUMES(B.reagents) + if(LAZYLEN(reagent_volumes)) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(B.reagents)) + dat += "
    [REAGENT_VOLUME(B.reagents, reagent)] unit\s of [reagent.get_reagent_name(B.reagents)], " if(B in mixing) - dat += "Mixing " + dat += "Mixing " else - dat += "Not mixing " + dat += "Not mixing " else dat += "nothing." - dat += " \[Eject\]
    " + dat += " \[Eject\]
    " if(ammo_magazine) - if(ammo_magazine.stored_ammo && ammo_magazine.stored_ammo.len) - dat += "The dart cartridge has [ammo_magazine.stored_ammo.len] shots remaining." + var/stored_ammo_count = ammo_magazine?.get_stored_ammo_count() + if(stored_ammo_count) + dat += "The dart cartridge has [stored_ammo_count] shot\s remaining." else dat += "The dart cartridge is empty!" - dat += " \[Eject\]
    " + dat += " \[Eject\]
    " - dat += "
    \[Refresh\]" + dat += "
    \[Refresh\]" var/datum/browser/popup = new(user, "dartgun", "[src] mixing control") popup.set_content(jointext(dat,null)) @@ -143,13 +148,13 @@ else if (href_list["eject"]) var/index = text2num(href_list["eject"]) if(beakers[index]) - remove_beaker(beakers[index], usr) + remove_beaker(beakers[index], user) . = TOPIC_REFRESH else if (href_list["eject_cart"]) - unload_ammo(usr) + unload_ammo(user) . = TOPIC_REFRESH - Interact(usr) + Interact(user) /obj/item/gun/projectile/dartgun/medical starting_chems = list(/decl/material/liquid/burn_meds,/decl/material/liquid/brute_meds,/decl/material/liquid/antitoxins) diff --git a/code/modules/projectiles/guns/projectile/flaregun.dm b/code/modules/projectiles/guns/projectile/flaregun.dm index c73a374995e9..6ff9c0074e04 100644 --- a/code/modules/projectiles/guns/projectile/flaregun.dm +++ b/code/modules/projectiles/guns/projectile/flaregun.dm @@ -5,11 +5,10 @@ icon_state = ICON_STATE_WORLD fire_sound = 'sound/weapons/empty.ogg' fire_sound_text = "a satisfying 'thump'" - slot_flags = SLOT_BELT | SLOT_HOLSTER + slot_flags = SLOT_LOWER_BODY | SLOT_HOLSTER w_class = ITEM_SIZE_SMALL obj_flags = 0 - slot_flags = SLOT_BELT | SLOT_HOLSTER - material = /decl/material/solid/plastic + material = /decl/material/solid/organic/plastic matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT) caliber = CALIBER_SHOTGUN @@ -21,24 +20,25 @@ /obj/item/gun/projectile/flare/loaded ammo_type = /obj/item/ammo_casing/shotgun/flash -/obj/item/gun/projectile/flare/examine(mob/user, distance) +/obj/item/gun/projectile/flare/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 2 && loaded.len) - to_chat(user, "\A [loaded[1]] is chambered.") + . += "\A [loaded[1]] is chambered." /obj/item/gun/projectile/flare/special_check() if(loaded.len && !istype(loaded[1], /obj/item/ammo_casing/shotgun/flash)) - var/damage = chambered.BB.get_structure_damage() - if(istype(chambered.BB, /obj/item/projectile/bullet/pellet)) - var/obj/item/projectile/bullet/pellet/PP = chambered.BB + var/obj/item/ammo_casing/chambered_round = loaded[1] + var/damage = chambered_round.BB.get_structure_damage() + if(istype(chambered_round.BB, /obj/item/projectile/bullet/pellet)) + var/obj/item/projectile/bullet/pellet/PP = chambered_round.BB damage = PP.damage*PP.pellets if(damage > 5) - var/mob/living/carbon/C = loc - if(istype(C)) - C.visible_message("[src] explodes in [C]'s hands!", "[src] explodes in your face!") - C.drop_from_inventory(src) + var/mob/living/user = loc + if(istype(user)) + user.visible_message("[src] explodes in [user]'s hands!", "[src] explodes in your face!") + user.drop_from_inventory(src) for(var/zone in list(BP_L_HAND, BP_R_HAND)) - C.apply_damage(rand(10,20), def_zone=zone) + user.apply_damage(rand(10,20), def_zone=zone) else visible_message("[src] explodes!") explosion(get_turf(src), -1, -1, 1) diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index 6e3cc2b97956..e64e7c3f731e 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -1,8 +1,6 @@ - /obj/item/gun/projectile/pistol name = "pistol" icon = 'icons/obj/guns/pistol.dmi' - icon_state = ICON_STATE_WORLD load_method = MAGAZINE caliber = CALIBER_PISTOL magazine_type = /obj/item/ammo_magazine/pistol @@ -11,69 +9,31 @@ safety_icon = "safety" ammo_indicator = TRUE -/obj/item/gun/projectile/pistol/update_base_icon() - var/base_state = get_world_inventory_state() - if(!length(ammo_magazine?.stored_ammo) && check_state_in_icon("[base_state]-e", icon)) - icon_state = "[base_state]-e" - else - icon_state = base_state +/obj/item/gun/projectile/pistol/rubber + magazine_type = /obj/item/ammo_magazine/pistol/rubber + +/obj/item/gun/projectile/pistol/emp + magazine_type = /obj/item/ammo_magazine/pistol/emp + +/obj/item/gun/projectile/pistol/update_base_icon_state() + . = ..() + if(!ammo_magazine?.get_stored_ammo_count()) + var/empty_state = "[icon_state]-e" + if(check_state_in_icon(empty_state, icon)) + icon_state = empty_state /obj/item/gun/projectile/pistol/holdout name = "holdout pistol" desc = "The Lumoco Arms P3 Whisper. A small, easily concealable gun." icon = 'icons/obj/guns/holdout_pistol.dmi' - icon_state = ICON_STATE_WORLD item_state = null ammo_indicator = FALSE w_class = ITEM_SIZE_SMALL caliber = CALIBER_PISTOL_SMALL - silenced = 0 fire_delay = 4 - origin_tech = "{'combat':2,'materials':2,'esoteric':8}" + origin_tech = @'{"combat":2,"materials":2,"esoteric":8}' magazine_type = /obj/item/ammo_magazine/pistol/small allowed_magazines = /obj/item/ammo_magazine/pistol/small -/obj/item/gun/projectile/pistol/holdout/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - if(silenced) - if(user.l_hand != src && user.r_hand != src) - ..() - return - to_chat(user, "You unscrew [silenced] from [src].") - user.put_in_hands(silenced) - silenced = initial(silenced) - w_class = initial(w_class) - update_icon() - return - ..() - -/obj/item/gun/projectile/pistol/holdout/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/silencer)) - if(user.l_hand != src && user.r_hand != src) //if we're not in his hands - to_chat(user, "You'll need [src] in your hands to do that.") - return - if(!user.unEquip(I, src)) - return//put the silencer into the gun - to_chat(user, "You screw [I] onto [src].") - silenced = I //dodgy? - w_class = ITEM_SIZE_NORMAL - update_icon() - return - ..() - -/obj/item/gun/projectile/pistol/holdout/update_base_icon() - ..() - if(silenced) - overlays += get_mutable_overlay(icon, "[get_world_inventory_state()]-silencer") - -/obj/item/gun/projectile/pistol/holdout/get_on_belt_overlay() - if(silenced && check_state_in_icon("on_belt_silenced", icon)) - return overlay_image(icon, "on_belt_silenced", color) - return ..() - -/obj/item/silencer - name = "silencer" - desc = "A silencer." - icon = 'icons/obj/guns/holdout_pistol_silencer.dmi' - icon_state = ICON_STATE_WORLD - w_class = ITEM_SIZE_SMALL +/obj/item/gun/projectile/pistol/holdout/can_have_silencer() + return TRUE diff --git a/code/modules/projectiles/guns/projectile/random_pistol.dm b/code/modules/projectiles/guns/projectile/random_pistol.dm index c6cb222a0d85..ba767072bafa 100644 --- a/code/modules/projectiles/guns/projectile/random_pistol.dm +++ b/code/modules/projectiles/guns/projectile/random_pistol.dm @@ -1,54 +1,39 @@ /obj/item/gun/projectile/pistol/random name = "pistol" - icon = 'icons/obj/guns/randompistol.dmi' - icon_state = "preview" + icon = 'icons/obj/guns/random_pistol/base.dmi' var/decl/gun_look/gun_look var/handle_icon - var/ammo_offset - var/safety_offset - var/list/global/descriptor = list( + // ammo and safety offsets were moved to gun_look + var/static/list/descriptor = list( "Shining", "Power", "Instant", "Reliable", "Neo", "Super", "Boom", "Big", "Nitro", "Automatic" ) - var/list/global/noun = list( + var/static/list/noun = list( "Justice", "Protection", "Defense", "Penetrator", "Compensator", "Police Special", "Combat", "Point & Shoot" ) - var/list/global/appearance_cache = list() /obj/item/gun/projectile/pistol/random/Initialize() var/index = pick(caliber, rand(200,900), "P-[rand(10,99)]") desc = "A semi-automatic pistol of unknown origin. The inscription on the side claims the model is '[pick(descriptor)] [pick(noun)] [index]'" var/list/styles = decls_repository.get_decls_of_type(/decl/gun_look) - var/decl/gun_look/style = pick(styles) - gun_look = styles[style] - handle_icon = gun_look.get_handle_icon() + gun_look = styles[pick(styles)] + handle_icon = pick(gun_look.handle_icons) . = ..() - has_inventory_icon = TRUE -/obj/item/gun/projectile/pistol/random/update_base_icon() - var/base_state = get_world_inventory_state() - icon_state = "[base_state]_[gun_look.base_icon_state]" - overlays += image(icon, "[base_state]_[gun_look.front_icon_state]") - overlays += image(icon, "[base_state]_[handle_icon]") +/obj/item/gun/projectile/pistol/random/on_update_icon() + . = ..() + add_overlay(image(gun_look.icon, icon_state)) + add_overlay(image(handle_icon, icon_state)) /obj/item/gun/projectile/pistol/random/get_ammo_indicator() - var/mutable_appearance/ammo_indicator = ..() - var/base_state = get_world_inventory_state() - ammo_indicator.icon_state = replacetext(ammo_indicator.icon_state, "[base_state]_", "") - ammo_indicator.pixel_x = gun_look.ammo_offset[base_state][1] - ammo_indicator.pixel_y = gun_look.ammo_offset[base_state][2] - return ammo_indicator + return gun_look.adjust_ammo_indicator(..(), get_world_inventory_state()) /obj/item/gun/projectile/pistol/random/get_safety_indicator() - var/base_state = get_world_inventory_state() - var/mutable_appearance/safety = get_mutable_overlay(icon, "safety[safety()]") - safety.pixel_x = gun_look.safety_offset[base_state][1] - safety.pixel_y = gun_look.safety_offset[base_state][2] - return safety + var/mutable_appearance/safety = mutable_appearance(icon, "safety[safety()]") + return gun_look.adjust_safety_indicator(safety, get_world_inventory_state()) /decl/gun_look - var/base_icon_state = "base" - var/front_icon_state = "gunbits1" + var/icon = 'icons/obj/guns/random_pistol/looks/plated.dmi' // offsets for LEDs, base state = x,y var/list/ammo_offset = list( ICON_STATE_WORLD = list(15, 15), @@ -58,12 +43,24 @@ ICON_STATE_WORLD = list(17, 15), ICON_STATE_INV = list(17, 17) ) + var/list/handle_icons = list( + 'icons/obj/guns/random_pistol/handle/ergonomic.dmi', + 'icons/obj/guns/random_pistol/handle/black.dmi', + 'icons/obj/guns/random_pistol/handle/revolver.dmi' + ) -/decl/gun_look/proc/get_handle_icon() - return "handle[rand(1,3)]" +/decl/gun_look/proc/adjust_ammo_indicator(mutable_appearance/ammo_indicator, base_state) + ammo_indicator.icon_state = replacetext(ammo_indicator.icon_state, "[base_state]_", "") + ammo_indicator.pixel_x = ammo_offset[base_state][1] + ammo_indicator.pixel_y = ammo_offset[base_state][2] + return ammo_indicator -/decl/gun_look/two - front_icon_state = "gunbits2" +/decl/gun_look/proc/adjust_safety_indicator(mutable_appearance/safety, base_state) + safety.pixel_x = safety_offset[base_state][1] + safety.pixel_y = safety_offset[base_state][2] + return safety +/decl/gun_look/cover + icon = 'icons/obj/guns/random_pistol/looks/cover.dmi' ammo_offset = list( ICON_STATE_WORLD = list(11, 14), ICON_STATE_INV = list(8, 15) @@ -73,8 +70,8 @@ ICON_STATE_INV = list(10, 15) ) -/decl/gun_look/three - front_icon_state = "gunbits3" +/decl/gun_look/short + icon = 'icons/obj/guns/random_pistol/looks/short.dmi' ammo_offset = list( ICON_STATE_WORLD = list(16, 14), ICON_STATE_INV = list(16, 15) @@ -84,8 +81,8 @@ ICON_STATE_INV = list(18, 15) ) -/decl/gun_look/four - front_icon_state = "gunbits4" +/decl/gun_look/drilled + icon = 'icons/obj/guns/random_pistol/looks/drilled.dmi' ammo_offset = list( ICON_STATE_WORLD = list(16, 14), ICON_STATE_INV = list(16, 15) diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index 0179f9009d86..44b580822317 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -5,7 +5,7 @@ icon_state = ICON_STATE_WORLD safety_icon = "safety" caliber = CALIBER_PISTOL_MAGNUM - origin_tech = "{'combat':2,'materials':2}" + origin_tech = @'{"combat":2,"materials":2}' handle_casings = CYCLE_CASINGS max_shells = 6 fire_delay = 12 //Revolvers are naturally slower-firing @@ -18,10 +18,6 @@ one_hand_penalty = 2 bulk = 3 -/obj/item/gun/projectile/revolver/AltClick() - if(CanPhysicallyInteract(usr)) - spin_cylinder() - /obj/item/gun/projectile/revolver/verb/spin_cylinder() set name = "Spin cylinder" set desc = "Fun when you're bored out of your skull." @@ -45,25 +41,41 @@ chamber_offset = 0 return ..() +/obj/item/gun/projectile/revolver/stun + ammo_type = /obj/item/ammo_casing/pistol/magnum/stun + /obj/item/gun/projectile/revolver/capgun name = "cap gun" desc = "Looks almost like the real thing! Ages 8 and up." caliber = CALIBER_CAPS - origin_tech = "{'combat':1,'materials':1}" + origin_tech = @'{"combat":1,"materials":1}' ammo_type = /obj/item/ammo_casing/cap var/cap = TRUE /obj/item/gun/projectile/revolver/capgun/on_update_icon() . = ..() if(cap) - overlays += image(icon, "[icon_state]-toy") + add_overlay("[icon_state]-toy") -/obj/item/gun/projectile/revolver/capgun/attackby(obj/item/wirecutters/W, mob/user) - if(!istype(W) || !cap) +/obj/item/gun/projectile/revolver/capgun/attackby(obj/item/used_item, mob/user) + if(!IS_WIRECUTTER(used_item) || !cap) return ..() - to_chat(user, "You snip off the toy markings off the [src].") + to_chat(user, "You snip off the toy markings off \the [src].") name = "revolver" desc += " Someone snipped off the barrel's toy mark. How dastardly." cap = FALSE update_icon() return 1 + +/obj/item/gun/projectile/revolver/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/revolver_spin_cylinder) + +/decl/interaction_handler/revolver_spin_cylinder + name = "Spin Cylinder" + expected_target_type = /obj/item/gun/projectile/revolver + examine_desc = "spin the cylinder" + +/decl/interaction_handler/revolver_spin_cylinder/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/gun/projectile/revolver/R = target + R.spin_cylinder() diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm index 4b8a91cdce6b..5c298cdb09bf 100644 --- a/code/modules/projectiles/guns/projectile/shotgun.dm +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -1,15 +1,15 @@ /obj/item/gun/projectile/shotgun/pump name = "shotgun" - desc = "The mass-produced W-T Remmington 29x shotgun is a favourite of police and security forces on many worlds. Useful for sweeping alleys." + desc = "The mass-produced W-T Remington 29x shotgun is a favourite of police and security forces on many worlds. Useful for sweeping alleys." icon = 'icons/obj/guns/shotgun/pump.dmi' icon_state = ICON_STATE_WORLD max_shells = 4 w_class = ITEM_SIZE_HUGE - force = 10 + _base_attack_force = 10 obj_flags = OBJ_FLAG_CONDUCTIBLE slot_flags = SLOT_BACK caliber = CALIBER_SHOTGUN - origin_tech = "{'combat':4,'materials':2}" + origin_tech = @'{"combat":4,"materials":2}' load_method = SINGLE_CASING ammo_type = /obj/item/ammo_casing/shotgun/beanbag handle_casings = HOLD_CASINGS @@ -18,18 +18,26 @@ var/recentpump = 0 // to prevent spammage load_sound = 'sound/weapons/guns/interaction/shotgun_instert.ogg' -/obj/item/gun/projectile/shotgun/update_base_icon() +/obj/item/gun/projectile/shotgun/update_base_icon_state() if(length(loaded)) icon_state = get_world_inventory_state() else icon_state = "[get_world_inventory_state()]-empty" +/obj/item/gun/projectile/shotgun/pump/update_base_icon_state() + if(chambered) + icon_state = get_world_inventory_state() + else + icon_state = "[get_world_inventory_state()]-empty" + /obj/item/gun/projectile/shotgun/pump/consume_next_projectile() if(chambered) return chambered.BB return null -/obj/item/gun/projectile/shotgun/pump/attack_self(mob/living/user) +/obj/item/gun/projectile/shotgun/pump/attack_self(mob/user) + if(!user_can_attack_with(user)) + return TRUE if(world.time >= recentpump + 10) pump(user) recentpump = world.time @@ -39,8 +47,8 @@ if(chambered)//We have a shell in the chamber chambered.dropInto(loc)//Eject casing - if(LAZYLEN(chambered.fall_sounds)) - playsound(loc, pick(chambered.fall_sounds), 50, 1) + if(chambered.drop_sound) + playsound(loc, pick(chambered.drop_sound), 50, 1) chambered = null if(loaded.len) @@ -60,11 +68,11 @@ handle_casings = CYCLE_CASINGS max_shells = 2 w_class = ITEM_SIZE_HUGE - force = 10 + _base_attack_force = 10 obj_flags = OBJ_FLAG_CONDUCTIBLE slot_flags = SLOT_BACK caliber = CALIBER_SHOTGUN - origin_tech = "{'combat':3,'materials':1}" + origin_tech = @'{"combat":3,"materials":1}' ammo_type = /obj/item/ammo_casing/shotgun/beanbag one_hand_penalty = 2 @@ -75,13 +83,13 @@ ) /obj/item/gun/projectile/shotgun/doublebarrel/unload_ammo(user, allow_dump) - ..(user, allow_dump=1) + return ..(user, allow_dump=1) //this is largely hacky and bad :( -Pete -/obj/item/gun/projectile/shotgun/doublebarrel/attackby(var/obj/item/A, mob/user) - if(w_class > ITEM_SIZE_NORMAL && (istype(A, /obj/item/circular_saw) || istype(A, /obj/item/energy_blade) || istype(A, /obj/item/gun/energy/plasmacutter))) - if(istype(A, /obj/item/gun/energy/plasmacutter)) - var/obj/item/gun/energy/plasmacutter/cutter = A +/obj/item/gun/projectile/shotgun/doublebarrel/attackby(var/obj/item/used_item, mob/user) + if(w_class > ITEM_SIZE_NORMAL && used_item.get_tool_quality(TOOL_SAW) > 0) + if(istype(used_item, /obj/item/gun/energy/plasmacutter)) + var/obj/item/gun/energy/plasmacutter/cutter = used_item if(!cutter.slice(user)) return ..() to_chat(user, "You begin to shorten the barrel of \the [src].") @@ -89,26 +97,43 @@ for(var/i in 1 to max_shells) Fire(user, user) //will this work? //it will. we call it twice, for twice the FUN user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!") - return - if(do_after(user, 30, src)) //SHIT IS STEALTHY EYYYYY - user.unEquip(src) - var/obj/item/gun/projectile/shotgun/doublebarrel/sawn/empty/buddy = new(loc) - transfer_fingerprints_to(buddy) - qdel(src) - to_chat(user, "You shorten the barrel of \the [src]!") + return TRUE + if(!do_after(user, 3 SECONDS, src)) //SHIT IS STEALTHY EYYYYY + return TRUE + user.try_unequip(src) + var/obj/item/gun/projectile/shotgun/doublebarrel/sawn/empty/buddy = new(loc) + transfer_fingerprints_to(buddy) + qdel(src) + to_chat(user, "You shorten the barrel of \the [src]!") + return TRUE else - ..() + return ..() /obj/item/gun/projectile/shotgun/doublebarrel/sawn name = "sawn-off shotgun" desc = "Omar's coming!" icon = 'icons/obj/guns/shotgun/sawnoff.dmi' - slot_flags = SLOT_BELT|SLOT_HOLSTER + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER ammo_type = /obj/item/ammo_casing/shotgun/pellet w_class = ITEM_SIZE_NORMAL - force = 5 one_hand_penalty = 4 bulk = 2 /obj/item/gun/projectile/shotgun/doublebarrel/sawn/empty - starts_loaded = FALSE \ No newline at end of file + starts_loaded = FALSE + +/obj/item/gun/projectile/shotgun/doublebarrel/quad + name = "quad-barreled shotgun" + desc = "A true classic - but doubled. Firing it has a heck of a kick - knocks the air right out of you." + icon = 'icons/obj/guns/shotgun/quadbarrel.dmi' + max_shells = 4 + w_class = ITEM_SIZE_HUGE + origin_tech = @'{"combat":6,"materials":3,"esoteric":9}' + firemodes = list( + list(mode_name="fire one barrel at a time", burst=1), + list(mode_name="fire two barrels at once", burst=2), + list(mode_name="fire all barrels at once", burst=4) + ) + +/obj/item/gun/projectile/shotgun/doublebarrel/quad/empty + starts_loaded = FALSE diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm deleted file mode 100644 index 1e910c220e36..000000000000 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ /dev/null @@ -1,76 +0,0 @@ -/obj/item/gun/projectile/heavysniper - name = "anti-materiel rifle" - desc = "A portable anti-armour rifle fitted with a scope, the HI PTR-7 Rifle was originally designed to be used against armoured exosuits. It is capable of punching through windows and non-reinforced walls with ease." - icon = 'icons/obj/guns/heavysniper.dmi' - icon_state = ICON_STATE_WORLD - w_class = ITEM_SIZE_HUGE - force = 10 - slot_flags = SLOT_BACK - origin_tech = "{'combat':7,'materials':2,'esoteric':8}" - caliber = CALIBER_ANTIMATERIAL - screen_shake = 2 //extra kickback - handle_casings = HOLD_CASINGS - load_method = SINGLE_CASING - max_shells = 1 - ammo_type = /obj/item/ammo_casing/shell - one_hand_penalty = 6 - accuracy = -2 - bulk = 8 - scoped_accuracy = 8 //increased accuracy over the LWAP because only one shot - scope_zoom = 2 - var/bolt_open = 0 - load_sound = 'sound/weapons/guns/interaction/rifle_load.ogg' - fire_delay = 12 - -/obj/item/gun/projectile/heavysniper/on_update_icon() - ..() - if(bolt_open) - icon_state = "[get_world_inventory_state()]-open" - else - icon_state = get_world_inventory_state() - -/obj/item/gun/projectile/heavysniper/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0) - ..() - if(user && user.skill_check(SKILL_WEAPONS, SKILL_PROF)) - to_chat(user, "You work the bolt open with a reflexive motion, ejecting [chambered]!") - unload_shell() - -/obj/item/gun/projectile/heavysniper/proc/unload_shell() - if(chambered) - if(!bolt_open) - playsound(src.loc, 'sound/weapons/guns/interaction/rifle_boltback.ogg', 50, 1) - bolt_open = 1 - chambered.dropInto(src.loc) - loaded -= chambered - chambered = null - -/obj/item/gun/projectile/heavysniper/attack_self(mob/user) - bolt_open = !bolt_open - if(bolt_open) - if(chambered) - to_chat(user, "You work the bolt open, ejecting [chambered]!") - unload_shell() - else - to_chat(user, "You work the bolt open.") - else - to_chat(user, "You work the bolt closed.") - playsound(src.loc, 'sound/weapons/guns/interaction/rifle_boltforward.ogg', 50, 1) - bolt_open = 0 - add_fingerprint(user) - update_icon() - -/obj/item/gun/projectile/heavysniper/special_check(mob/user) - if(bolt_open) - to_chat(user, "You can't fire [src] while the bolt is open!") - return 0 - return ..() - -/obj/item/gun/projectile/heavysniper/load_ammo(var/obj/item/A, mob/user) - if(!bolt_open) - return - ..() - -/obj/item/gun/projectile/heavysniper/unload_ammo(mob/user, var/allow_dump=1) - if(!bolt_open) - return - ..() diff --git a/code/modules/projectiles/guns/projectile/zipgun.dm b/code/modules/projectiles/guns/projectile/zipgun.dm index bbdcaf94421f..b87c20985a43 100644 --- a/code/modules/projectiles/guns/projectile/zipgun.dm +++ b/code/modules/projectiles/guns/projectile/zipgun.dm @@ -10,7 +10,7 @@ has_safety = FALSE w_class = ITEM_SIZE_NORMAL - var/global/list/ammo_types = list( + var/static/list/ammo_types = list( /obj/item/ammo_casing/pistol, /obj/item/ammo_casing/shotgun, /obj/item/ammo_casing/shotgun, diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 9c25158eb198..d36ec1783cc9 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -1,18 +1,38 @@ //Amount of time in deciseconds to wait before deleting all drawn segments of a projectile. #define SEGMENT_DELETION_DELAY 5 - +#define MUZZLE_EFFECT_PIXEL_INCREMENT 16 /obj/item/projectile name = "projectile" icon = 'icons/obj/projectiles.dmi' icon_state = "bullet" - density = 1 - unacidable = 1 - anchored = 1 //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots. + density = TRUE + anchored = TRUE //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots. pass_flags = PASS_FLAG_TABLE - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + randpixel = 0 + material = null + is_spawnable_type = FALSE + atom_damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, ELECTROCUTE are the only things that should be in here, Try not to use PAIN as it doesn't go through stun_effect_act + + // Code for handling tails, if any. + /// If the projectile leaves a trail. + var/proj_trail = FALSE + /// How long the trail lasts. + var/proj_trail_lifespan = 0 + /// What icon to use for the projectile trail. + var/proj_trail_icon = 'icons/effects/projectiles/trail.dmi' + /// What icon_state to use for the projectile trail. + var/proj_trail_icon_state = "trail" + /// Any extant trail effects. + var/list/proj_trails + /// An effect to spawn when a non-hitscan projectile collides with a target. + var/impact_effect_type + /// A sound to play when striking a non-mob (hitsound is used for mobs) + var/hitsound_non_mob + var/bumped = 0 //Prevents it from hitting more than one guy at once var/def_zone = "" //Aiming at - var/mob/firer = null//Who shot it + var/atom/movable/firer = null//Who shot it var/silenced = 0 //Attack message var/yo = null var/xo = null @@ -21,7 +41,6 @@ var/atom/original = null // the target clicked (not necessarily where the projectile is headed). Should probably be renamed to 'target' or something. var/turf/starting = null // the projectile's starting turf var/list/permutated = list() // we've passed through these atoms, don't try to hit them again - var/list/segments = list() //For hitscan projectiles with tracers. var/p_x = 16 var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center @@ -31,12 +50,10 @@ var/distance_falloff = 2 //multiplier, higher value means accuracy drops faster with distance var/damage = 10 - var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, ELECTROCUTE are the only things that should be in here, Try not to use PAIN as it doesn't go through stun_effect_act var/nodamage = 0 //Determines if the projectile will skip any damage inflictions var/damage_flags = DAM_BULLET - var/projectile_type = /obj/item/projectile var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate() - var/life_span = 50 //This will de-increment every process(). When 0, it will delete the projectile. + var/life_span //If non-null, this will de-increment every after_move(). When 0, it will delete the projectile. //Effects var/stun = 0 var/weaken = 0 @@ -46,11 +63,11 @@ var/eyeblur = 0 var/drowsy = 0 var/agony = 0 + var/embed = 0 // whether or not the projectile can embed itself in the mob var/space_knockback = 0 //whether or not it will knock things back in space var/penetration_modifier = 0.2 //How much internal damage this projectile can deal, as a multiplier. - var/hitscan = 0 // whether the projectile should be hitscan var/step_delay = 1 // the delay between iterations if not a hitscan projectile // effect types to be used @@ -60,47 +77,70 @@ var/fire_sound var/fire_sound_vol = 50 + var/fire_sound_vol_silenced = 10 var/miss_sounds var/ricochet_sounds var/list/impact_sounds //for different categories, IMPACT_MEAT etc var/shrapnel_type = /obj/item/shard/shrapnel var/vacuum_traversal = 1 //Determines if the projectile can exist in vacuum, if false, the projectile will be deleted if it enters vacuum. - - var/datum/plot_vector/trajectory // used to plot the path of the projectile - var/datum/vector_loc/location // current location of the projectile in pixel space - var/matrix/effect_transform // matrix to rotate and scale projectile effects - putting it here so it doesn't - // have to be recreated multiple times +//Movement parameters + var/speed = 0.4 //Amount of deciseconds it takes for projectile to travel + var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN! + var/Angle = 0 + var/original_Angle = 0 //Angle at firing + var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing Angle + var/forcedodge = FALSE //to pass through everything + + //Fired processing vars + var/fired = FALSE //Have we been fired yet + var/paused = FALSE //for suspending the projectile midair + var/last_projectile_move = 0 + var/last_process = 0 + var/time_offset = 0 + var/datum/point/vector/trajectory + var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location! + var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile. + + //Hitscan + var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored. + var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation. + var/datum/point/beam_index + var/turf/hitscan_last //last turf touched during hitscanning. /obj/item/projectile/Initialize() - damtype = damage_type //TODO unify these vars properly if(!hitscan) animate_movement = SLIDE_STEPS else animate_movement = NO_STEPS . = ..() +/obj/item/projectile/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + return TRUE + /obj/item/projectile/damage_flags() return damage_flags //TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not /obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) - if(blocked >= 100) return 0//Full block - if(!isliving(target)) return 0 - if(isanimal(target)) return 0 + if(blocked >= 100) + return FALSE + if(!isliving(target)) + return FALSE var/mob/living/L = target - L.apply_effects(0, weaken, paralyze, stutter, eyeblur, drowsy, 0, blocked) L.stun_effect_act(stun, agony, def_zone, src) //radiation protection is handled separately from other armour types. L.apply_damage(irradiate, IRRADIATE, damage_flags = DAM_DISPERSED) - - return 1 + return TRUE //called when the projectile stops flying because it collided with something /obj/item/projectile/proc/on_impact(var/atom/A) - impact_effect(effect_transform) // generate impact effect - if(damage && damage_type == BURN) + + impact_sounds(A) + impact_visuals(A) + + if(damage && atom_damage_type == BURN) var/turf/T = get_turf(A) if(T) T.hotspot_expose(700, 5) @@ -110,7 +150,7 @@ if(!AM.anchored && !AM.has_gravity()) if(ismob(AM)) var/mob/M = AM - if(M.check_space_footing()) + if(!M.can_slip(magboots_only = TRUE)) return var/old_dir = AM.dir step(AM,get_dir(firer,AM)) @@ -119,23 +159,35 @@ //Checks if the projectile is eligible for embedding. Not that it necessarily will. /obj/item/projectile/can_embed() //embed must be enabled and damage type must be brute - if(!embed || damage_type != BRUTE) - return 0 - return 1 + if(!embed || atom_damage_type != BRUTE) + return FALSE + return TRUE /obj/item/projectile/proc/get_structure_damage() - if(damage_type == BRUTE || damage_type == BURN) + if(atom_damage_type == BRUTE || atom_damage_type == BURN) return damage return 0 -//return 1 if the projectile should be allowed to pass through after all, 0 if not. -/obj/item/projectile/proc/check_penetrate(var/atom/A) - return 1 +/obj/item/projectile/proc/check_penetrate(atom/A) + return TRUE -/obj/item/projectile/proc/check_fire(atom/target, var/mob/living/user) //Checks if you can hit them or not. - check_trajectory(target, user, pass_flags, item_flags, obj_flags) +//called to launch a projectile +/obj/item/projectile/proc/launch(atom/target, target_zone, atom/movable/shooter, params, Angle_override, forced_spread = 0) + original = target + def_zone = check_zone(target_zone) + firer = shooter + var/direct_target + var/turf/actual_target_turf = get_turf(target) + actual_target_turf = actual_target_turf?.resolve_to_actual_turf() + if(actual_target_turf == get_turf(src)) + direct_target = target + preparePixelProjectile(target, shooter ? shooter : get_turf(src), params, forced_spread) + return fire(Angle_override, direct_target) + +//called to launch a projectile from a gun +/obj/item/projectile/proc/launch_from_gun(atom/target, target_zone, atom/movable/shooter, params, Angle_override, forced_spread, var/obj/item/gun/launcher) + return launch(target, target_zone, shooter, params) -//sets the click point of the projectile using mouse input params /obj/item/projectile/proc/set_clickpoint(var/params) var/list/mouse_control = params2list(params) if(mouse_control["icon-x"]) @@ -146,61 +198,26 @@ //randomize clickpoint a bit based on dispersion if(dispersion) var/radius = round((dispersion*0.443)*world.icon_size*0.8) //0.443 = sqrt(pi)/4 = 2a, where a is the side length of a square that shares the same area as a circle with diameter = dispersion - p_x = between(0, p_x + rand(-radius, radius), world.icon_size) - p_y = between(0, p_y + rand(-radius, radius), world.icon_size) - -//called to launch a projectile -/obj/item/projectile/proc/launch(atom/target, var/target_zone, var/x_offset=0, var/y_offset=0, var/angle_offset=0) - var/turf/curloc = get_turf(src) - var/turf/targloc = get_turf(target) - if (!istype(targloc) || !istype(curloc)) - return 1 - - if(targloc == curloc) //Shooting something in the same turf - target.bullet_act(src, target_zone) - on_impact(target) - qdel(src) - return 0 - - original = target - def_zone = target_zone - - addtimer(CALLBACK(src, .proc/finalize_launch, curloc, targloc, x_offset, y_offset, angle_offset),0) - return 0 - -/obj/item/projectile/proc/finalize_launch(var/turf/curloc, var/turf/targloc, var/x_offset, var/y_offset, var/angle_offset) - setup_trajectory(curloc, targloc, x_offset, y_offset, angle_offset) //plot the initial trajectory - Process() - spawn(SEGMENT_DELETION_DELAY) //running this from a proc wasn't working. - QDEL_NULL_LIST(segments) - -//called to launch a projectile from a gun -/obj/item/projectile/proc/launch_from_gun(atom/target, mob/user, obj/item/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0) - if(user == target) //Shooting yourself - user.bullet_act(src, target_zone) - qdel(src) - return 0 - - dropInto(user.loc) //move the projectile out into the world - - firer = user - shot_from = launcher.name - silenced = launcher.silenced - - return launch(target, target_zone, x_offset, y_offset) + p_x = clamp(p_x + gaussian(0, radius) * 0.25, 0, world.icon_size) + p_y = clamp(p_y + gaussian(0, radius) * 0.25, 0, world.icon_size) //Used to change the direction of the projectile in flight. -/obj/item/projectile/proc/redirect(var/new_x, var/new_y, var/atom/starting_loc, var/mob/new_firer=null) +/obj/item/projectile/proc/redirect(var/new_x, var/new_y, var/atom/starting_loc, var/atom/movable/new_firer=null, var/is_ricochet = FALSE) + var/turf/starting_turf = get_turf(src) var/turf/new_target = locate(new_x, new_y, src.z) original = new_target if(new_firer) firer = src + var/new_Angle = Atan2(starting_turf, new_target) + if(is_ricochet) // Add some dispersion. + new_Angle += (rand(-5,5) * 5) + setAngle(new_Angle) - setup_trajectory(starting_loc, new_target) //Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying. /obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/special_miss_modifier=0) + SHOULD_CALL_PARENT(TRUE) if(!istype(target_mob)) return @@ -220,26 +237,31 @@ var/result = PROJECTILE_FORCE_MISS if(hit_zone) def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part - if(!target_mob.aura_check(AURA_TYPE_BULLET, src,def_zone)) - return 1 + if(target_mob.mob_modifiers_block_attack(MM_ATTACK_TYPE_PROJECTILE, src, def_zone)) + return TRUE result = target_mob.bullet_act(src, def_zone) if(result == PROJECTILE_FORCE_MISS) if(!silenced) target_mob.visible_message("\The [src] misses [target_mob] narrowly!") + var/list/miss_sounds = get_miss_sounds() if(LAZYLEN(miss_sounds)) playsound(target_mob.loc, pick(miss_sounds), 60, 1) - return 0 + return FALSE //hit messages if(silenced) - to_chat(target_mob, "You've been hit in the [parse_zone(def_zone)] by \the [src]!") + to_chat(target_mob, SPAN_DANGER("You've been hit in the [parse_zone(def_zone)] by \the [src]!")) + if(hitsound) + var/impact_volume = get_impact_volume_by_damage() + if(impact_volume) + playsound(target_mob, hitsound, impact_volume, 1, -1) else target_mob.visible_message("\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter //admin logs if(!no_attack_log) - if(istype(firer, /mob)) + if(ismob(firer)) var/attacker_message = "shot with \a [src.type]" var/victim_message = "shot with \a [src.type]" @@ -251,9 +273,9 @@ //sometimes bullet_act() will want the projectile to continue flying if (result == PROJECTILE_CONTINUE) - return 0 + return FALSE - return 1 + return TRUE /obj/item/projectile/Bump(atom/A, forced=0) if(A == src) @@ -272,12 +294,12 @@ bumped = 1 if(ismob(A)) var/mob/M = A - if(istype(A, /mob/living)) + if(isliving(A)) //if they have a neck grab on someone, that person gets hit instead - var/obj/item/grab/G = locate() in M - if(G && G.shield_assailant()) - visible_message("\The [M] uses [G.affecting] as a shield!") - if(Bump(G.affecting, forced=1)) + var/obj/item/grab/grab = locate() in M + if(grab && grab.shield_assailant()) + visible_message("\The [M] uses [grab.affecting] as a shield!") + if(Bump(grab.affecting, forced=1)) return //If Bump() returns 0 (keep going) then we continue on to attack M. passthrough = !attack_mob(M, distance) @@ -298,7 +320,7 @@ penetrating-- //the bullet passes through a dense object! - if(passthrough) + if(passthrough || forcedodge) //move ourselves onto A so we can continue on our way. var/turf/T = get_turf(A) if(T) @@ -311,194 +333,34 @@ on_impact(A) set_density(0) - set_invisibility(101) + set_invisibility(INVISIBILITY_ABSTRACT) qdel(src) return 1 /obj/item/projectile/explosion_act() SHOULD_CALL_PARENT(FALSE) - return - -/obj/item/projectile/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - return 1 - -/obj/item/projectile/Process() - var/first_step = 1 - - spawn while(src && src.loc) - if(life_span-- < 1) - on_impact(src.loc) //for any final impact behaviours - qdel(src) - return - if((!( current ) || loc == current)) - current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) - if((x == 1 || x == world.maxx || y == 1 || y == world.maxy)) - qdel(src) - return - - trajectory.increment() // increment the current location - location = trajectory.return_location(location) // update the locally stored location data - - if(!location) - qdel(src) // if it's left the world... kill it - return - - if (is_below_sound_pressure(get_turf(src)) && !vacuum_traversal) //Deletes projectiles that aren't supposed to bein vacuum if they leave pressurised areas - qdel(src) - return - - before_move() - Move(location.return_turf()) - - if(!bumped && !isturf(original)) - if(loc == get_turf(original)) - if(!(original in permutated)) - if(Bump(original)) - return - - if(first_step) - muzzle_effect(effect_transform) - first_step = 0 - else if(!bumped && life_span > 0) - tracer_effect(effect_transform) - if(!hitscan) - sleep(step_delay) //add delay between movement iterations if it's not a hitscan weapon + return /obj/item/projectile/proc/before_move() - return 0 - -/obj/item/projectile/proc/setup_trajectory(turf/startloc, turf/targloc, var/x_offset = 0, var/y_offset = 0) - // setup projectile state - starting = startloc - current = startloc - yo = round(targloc.y - startloc.y + y_offset, 1) - xo = round(targloc.x - startloc.x + x_offset, 1) - - // trajectory dispersion - var/offset = 0 - if(dispersion) - var/radius = round(dispersion*9, 1) - offset = rand(-radius, radius) - - // plot the initial trajectory - trajectory = new() - trajectory.setup(starting, original, pixel_x, pixel_y, angle_offset=offset) - - // generate this now since all visual effects the projectile makes can use it - effect_transform = new() - effect_transform.Scale(round(trajectory.return_hypotenuse() + 0.005, 0.001) , 1) //Seems like a weird spot to truncate, but it minimizes gaps. - effect_transform.Turn(round(-trajectory.return_angle(), 0.1)) //no idea why this has to be inverted, but it works - - transform = turn(transform, -(trajectory.return_angle() + 90)) //no idea why 90 needs to be added, but it works - -/obj/item/projectile/proc/muzzle_effect(var/matrix/T) - if(silenced) + if(!proj_trail || !isturf(loc) || !proj_trail_icon || !proj_trail_icon_state || !proj_trail_lifespan) return - - if(ispath(muzzle_type)) - var/obj/effect/projectile/M = new muzzle_type(get_turf(src), src) - - if(istype(M)) - M.set_transform(T) - M.pixel_x = round(location.pixel_x, 1) - M.pixel_y = round(location.pixel_y, 1) - if(!hitscan) //Bullets don't hit their target instantly, so we can't link the deletion of the muzzle flash to the bullet's Destroy() - QDEL_IN(M,1) - else - segments += M - -/obj/item/projectile/proc/tracer_effect(var/matrix/M) - if(ispath(tracer_type)) - var/obj/effect/projectile/P = new tracer_type(location.loc, src) - - if(istype(P)) - P.set_transform(M) - P.pixel_x = round(location.pixel_x, 1) - P.pixel_y = round(location.pixel_y, 1) - if(!hitscan) - QDEL_IN(M,1) - else - segments += P - -/obj/item/projectile/proc/impact_effect(var/matrix/M) - if(ispath(impact_type)) - var/obj/effect/projectile/P = new impact_type(location ? location.loc : get_turf(src), src) - - if(istype(P) && location) - P.set_transform(M) - P.pixel_x = round(location.pixel_x, 1) - P.pixel_y = round(location.pixel_y, 1) - segments += P - -//"Tracing" projectile -/obj/item/projectile/test //Used to see if you can hit them. - invisibility = 101 //Nope! Can't see me! - yo = null - xo = null - var/result = 0 //To pass the message back to the gun. - -/obj/item/projectile/test/Bump(atom/A, forced=0) - if(A == firer) - forceMove(A.loc) - return //cannot shoot yourself - if(istype(A, /obj/item/projectile)) - return - if(istype(A, /mob/living) || istype(A, /obj/vehicle)) - result = 2 //We hit someone, return 1! - return - result = 1 - return - -/obj/item/projectile/test/launch(atom/target) - var/turf/curloc = get_turf(src) - var/turf/targloc = get_turf(target) - if(!curloc || !targloc) - return 0 - - original = target - - //plot the initial trajectory - setup_trajectory(curloc, targloc) - return Process(targloc) - -/obj/item/projectile/test/Process(var/turf/targloc) - while(src) //Loop on through! - if(result) - return (result - 1) - if((!( targloc ) || loc == targloc)) - targloc = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge - - trajectory.increment() // increment the current location - location = trajectory.return_location(location) // update the locally stored location data - - Move(location.return_turf()) - - var/mob/living/M = locate() in get_turf(src) - if(istype(M)) //If there is someting living... - return 1 //Return 1 - else - M = locate() in get_step(src,targloc) - if(istype(M)) - return 1 - -//Helper proc to check if you can hit them or not. -/proc/check_trajectory(atom/target, atom/firer, var/pass_flags=PASS_FLAG_TABLE|PASS_FLAG_GLASS|PASS_FLAG_GRILLE, item_flags, obj_flags) - if(!istype(target) || !istype(firer)) - return 0 - - var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test.... - - //Set the flags and pass flags to that of the real projectile... - if(!isnull(item_flags)) - trace.item_flags = item_flags - if(!isnull(obj_flags)) - trace.obj_flags = obj_flags - trace.pass_flags = pass_flags - - var/output = trace.launch(target) //Test it! - qdel(trace) //No need for it anymore - return output //Send it back to the gun! + var/obj/effect/overlay/projectile_trail/trail = new(loc) + trail.master = src + trail.icon = proj_trail_icon + trail.icon_state = proj_trail_icon_state + trail.set_density(FALSE) + LAZYADD(proj_trails, trail) + QDEL_IN(trail, proj_trail_lifespan) + +/obj/item/projectile/proc/after_move() + if(hitscan && tracer_type && !(locate(/obj/effect/projectile) in loc)) + var/obj/effect/projectile/invislight/light = new + light.forceMove(loc) + light.copy_from(tracer_type) + QDEL_IN(light, 3) + if(!isnull(life_span) && --life_span <= 0) + qdel(src) /obj/item/projectile/after_wounding(obj/item/organ/external/organ, datum/wound/wound) //Check if we even broke skin in first place @@ -513,7 +375,7 @@ var/obj/item/shrapnel = get_shrapnel() if(shrapnel) shrapnel.forceMove(organ) - organ.embed(shrapnel) + organ.embed_in_organ(shrapnel) else if(prob(2 * damage_prob)) organ.sever_artery() @@ -525,9 +387,361 @@ SP.SetName((name != "shrapnel")? "[name] shrapnel" : "shrapnel") SP.desc += " It looks like it was fired from [shot_from]." return SP - + /obj/item/projectile/get_autopsy_descriptors() return list(name) -/obj/item/projectile/Process_Spacemove() - return TRUE //Bullets don't drift in space +/obj/item/projectile/is_space_movement_permitted(allow_movement = FALSE) + //Deletes projectiles that aren't supposed to be in vacuum if they leave pressurised areas + if (is_below_sound_pressure(get_turf(src)) && !vacuum_traversal) + qdel(src) + return + return SPACE_MOVE_PERMITTED //Bullets don't drift in space + +/obj/item/projectile/proc/fire(angle, atom/direct_target) + //If no Angle needs to resolve it from xo/yo! + if(direct_target) + direct_target.bullet_act(src, def_zone) + on_impact(direct_target) + qdel(src) + return + if(isnum(Angle)) + setAngle(Angle) + // trajectory dispersion + var/turf/starting = get_turf(src) + if(!starting) + return + if(isnull(Angle)) //Try to resolve through offsets if there's no Angle set. + if(isnull(xo) || isnull(yo)) + PRINT_STACK_TRACE("WARNING: Projectile [type] deleted due to being unable to resolve a target after Angle was null!") + qdel(src) + return + var/turf/target = locate(clamp(starting + xo, 1, world.maxx), clamp(starting + yo, 1, world.maxy), starting.z) + setAngle(get_projectile_angle(src, target.resolve_to_actual_turf())) + if(dispersion) + var/DeviationAngle = (dispersion * 15) + setAngle(Angle + rand(-DeviationAngle, DeviationAngle)) + original_Angle = Angle + if(!nondirectional_sprite) + var/matrix/M = new + M.Turn(Angle) + transform = M + forceMove(starting) + trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed) + last_projectile_move = world.time + fired = TRUE + if(hitscan) + return process_hitscan() + + if(muzzle_type) + var/atom/movable/thing = new muzzle_type + update_effect(thing) + thing.forceMove(starting) + thing.pixel_x = trajectory.return_px() + (trajectory.mpx * 0.5) + thing.pixel_y = trajectory.return_py() + (trajectory.mpy * 0.5) + var/matrix/M = new + M.Turn(Angle) + thing.transform = M + QDEL_IN(thing, 3) + + if(!is_processing) + START_PROCESSING(SSprojectiles, src) + pixel_move(1) //move it now! + +/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, Angle_offset = 0) + var/turf/curloc = get_turf(source) + var/turf/targloc = get_turf(target) + targloc = targloc?.resolve_to_actual_turf() + forceMove(get_turf(source)) + starting = get_turf(source) + original = target + + var/list/calculated = list(null,null,null) + var/mob/living/S = source + if(istype(S)) + S = S.get_effective_gunner() + if(istype(S) && S.client && params) + calculated = calculate_projectile_Angle_and_pixel_offsets(S, params) + p_x = calculated[2] + p_y = calculated[3] + setAngle(calculated[1]) + + else if(targloc && curloc) + yo = targloc.y - curloc.y + xo = targloc.x - curloc.x + setAngle(get_projectile_angle(src, targloc)) + else + PRINT_STACK_TRACE("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!") + qdel(src) + if(Angle_offset) + setAngle(Angle + Angle_offset) + +/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it. + ..() + if(isliving(AM) && (AM.density || AM == original) && !(pass_flags & PASS_FLAG_MOB)) + Bump(AM) + +/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1, hitscanning = FALSE) + if(!loc || !trajectory) + if(!QDELETED(src)) + if(loc) + on_impact(loc) + qdel(src) + return + last_projectile_move = world.time + if(!nondirectional_sprite && !hitscanning) + var/matrix/M = new + M.Turn(Angle) + transform = M + trajectory.increment(trajectory_multiplier) + + var/turf/T = trajectory.return_turf() + if(!T) + if(!QDELETED(src)) + if(loc) + on_impact(loc) + qdel(src) + return + + if(T.z != loc.z) + before_move() + before_z_change(loc, T) + trajectory_ignore_forcemove = TRUE + forceMove(T) + trajectory_ignore_forcemove = FALSE + after_move() + if(!hitscanning) + pixel_x = trajectory.return_px() + pixel_y = trajectory.return_py() + else + before_move() + step_towards(src, T) + after_move() + if(!hitscanning) + pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier + pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier + if(!hitscanning) + animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW) + if(isturf(loc)) + hitscan_last = loc + if(can_hit_target(original, permutated)) + Bump(original, TRUE) + check_distance_left() + +//Returns true if the target atom is on our current turf and above the right layer +/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough) + return (target && ((target.layer >= STRUCTURE_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough))) + +/proc/calculate_projectile_Angle_and_pixel_offsets(mob/user, params) + var/list/mouse_control = params2list(params) + var/p_x = 0 + var/p_y = 0 + var/Angle = 0 + if(mouse_control["icon-x"]) + p_x = text2num(mouse_control["icon-x"]) + if(mouse_control["icon-y"]) + p_y = text2num(mouse_control["icon-y"]) + if(mouse_control["screen-loc"]) + //Split screen-loc up into X+Pixel_X and Y+Pixel_Y + var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") + + //Split X+Pixel_X up into list(X, Pixel_X) + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + + //Split Y+Pixel_Y up into list(Y, Pixel_Y) + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32 + var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32 + + //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. + var/list/screenview = getviewsize(user.client.view) + var/screenviewX = screenview[1] * world.icon_size + var/screenviewY = screenview[2] * world.icon_size + + var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x + var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y + Angle = Atan2(y - oy, x - ox) + return list(Angle, p_x, p_y) + +/obj/item/projectile/proc/check_distance_left() + range-- + if(range <= 0 && loc) + end_distance() + +/obj/item/projectile/proc/end_distance() //if we want there to be effects when they reach the end of their range + on_impact(loc) + qdel(src) + +/obj/item/projectile/proc/store_hitscan_collision(datum/point/pcache) + beam_segments[beam_index] = pcache + beam_index = pcache + beam_segments[beam_index] = null + +/obj/item/projectile/proc/process_hitscan() + set waitfor = FALSE + var/safety = range * 3 + var/return_vector = RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1) + record_hitscan_start(return_vector) + while(loc && !QDELETED(src)) + if(paused) + stoplag(1) + continue + safety-- + if(safety <= 0) + qdel(src) + PRINT_STACK_TRACE("WARNING: [type] projectile encountered infinite recursion during hitscanning!") + return //Kill! + pixel_move(1, 1, TRUE) + +/obj/item/projectile/proc/record_hitscan_start(datum/point/pcache) + beam_segments = list() //initialize segment list with the list for the first segment + beam_index = pcache + beam_segments[beam_index] = null //record start. + +/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc) + var/datum/point/pcache = trajectory.copy_to() + if(hitscan) + store_hitscan_collision(pcache) + +/obj/item/projectile/Process() + last_process = world.time + if(!loc || !fired || !trajectory) + fired = FALSE + return PROCESS_KILL + if(paused || !isturf(loc)) + last_projectile_move += world.time - last_process //Compensates for pausing, so it doesn't become a hitscan projectile when unpaused from charged up ticks. + return + var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset + time_offset = 0 + var/required_moves = 0 + if(speed > 0) + required_moves = floor(elapsed_time_deciseconds / speed) + if(required_moves > SSprojectiles.global_max_tick_moves) + var/overrun = required_moves - SSprojectiles.global_max_tick_moves + required_moves = SSprojectiles.global_max_tick_moves + time_offset += overrun * speed + time_offset += MODULUS_FLOAT(elapsed_time_deciseconds, speed) + else + required_moves = SSprojectiles.global_max_tick_moves + if(!required_moves) + return + for(var/i in 1 to required_moves) + pixel_move(required_moves) + +/obj/item/projectile/proc/setAngle(new_Angle) //wrapper for overrides. + Angle = new_Angle + if(!nondirectional_sprite) + var/matrix/M = new + M.Turn(Angle) + transform = M + if(trajectory) + trajectory.set_angle(new_Angle) + return TRUE + +/obj/item/projectile/forceMove(atom/target) + . = ..() + if(trajectory && !trajectory_ignore_forcemove && isturf(target)) + trajectory.initialize_location(target.x, target.y, target.z, 0, 0) + +/obj/item/projectile/Destroy() + QDEL_NULL_LIST(proj_trails) + if(hitscan) + if(loc && trajectory) + var/datum/point/pcache = trajectory.copy_to() + beam_segments[beam_index] = pcache + generate_hitscan_tracers() + STOP_PROCESSING(SSprojectiles, src) + return ..() + +/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3) + if(!length(beam_segments)) + return + if(duration <= 0) + return + if(tracer_type) + for(var/datum/point/p in beam_segments) + generate_tracer_between_points(src, p, beam_segments[p], tracer_type, color, duration) + if(muzzle_type && !silenced) + var/datum/point/p = beam_segments[1] + var/atom/movable/thing = new muzzle_type + update_effect(thing) + p.move_atom_to_src(thing) + var/matrix/M = new + M.Turn(original_Angle) + thing.transform = M + QDEL_IN(thing, duration) + if(impact_type) + var/datum/point/p = beam_segments[beam_segments[beam_segments.len]] + var/atom/movable/thing = new impact_type + update_effect(thing) + p.move_atom_to_src(thing) + var/matrix/M = new + M.Turn(Angle) + thing.transform = M + QDEL_IN(thing, duration) + if(cleanup) + for(var/i in beam_segments) + qdel(i) + beam_segments = null + QDEL_NULL(beam_index) + +/obj/item/projectile/proc/update_effect(var/obj/effect/projectile/effect) + return + +/obj/item/projectile/proc/get_projectile_damage(mob/living/target) + return damage + +// Makes a brief effect sprite appear when the projectile hits something solid. +/obj/item/projectile/proc/impact_visuals(atom/A, hit_x, hit_y) + // Hitscan things have their own impact sprite. + if(!impact_effect_type || hitscan) + return + if(isnull(hit_x) && isnull(hit_y)) + if(trajectory) + // Effect goes where the projectile 'stopped'. + hit_x = A.pixel_x + trajectory.return_px() + hit_y = A.pixel_y + trajectory.return_py() + else if(A == original) + // Otherwise it goes where the person who fired clicked. + hit_x = A.pixel_x + p_x - 16 + hit_y = A.pixel_y + p_y - 16 + else + // Otherwise it'll be random. + hit_x = A.pixel_x + rand(-8, 8) + hit_y = A.pixel_y + rand(-8, 8) + new impact_effect_type(get_turf(A), src, hit_x, hit_y) + +/obj/item/projectile/proc/get_impact_volume_by_damage() + if(damage || agony) + var/value_to_use = damage > agony ? damage : agony + // Multiply projectile damage by 1.2, then CLAMP the value between 30 and 100. + // This was 0.67 but in practice it made all projectiles that did 45 or less damage play at 30, + // which is hard to hear over the gunshots, and is rather rare for a projectile to do that much. + return clamp((value_to_use) * 1.2, 30, 100) + return 50 //if the projectile doesn't do damage or agony, play its hitsound at 50% volume. + +/obj/item/projectile/proc/impact_sounds(atom/A) + + var/play_volume = clamp(get_impact_volume_by_damage() + 20, 0, 100) + if(play_volume <= 0) + return + if(silenced) + play_volume = min(play_volume, 5) + + var/play_sound + if(ismob(A)) // Mob sounds are handled in attack_mob(). + play_sound = hitsound + else + play_sound = hitsound_non_mob + if(!play_sound) + return + playsound(A, play_sound, play_volume, 1, -1) + +/obj/item/projectile/proc/get_miss_sounds() + return + +/obj/item/projectile/proc/get_ricochet_sounds() + return + +/obj/item/projectile/proc/get_impact_sounds() + return diff --git a/code/modules/projectiles/projectile/animate.dm b/code/modules/projectiles/projectile/animate.dm index ca33176583b6..4287cb8680e5 100644 --- a/code/modules/projectiles/projectile/animate.dm +++ b/code/modules/projectiles/projectile/animate.dm @@ -2,7 +2,7 @@ name = "bolt of animation" icon_state = "ice_1" damage = 0 - damage_type = BURN + atom_damage_type = BURN nodamage = 1 damage_flags = 0 diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index f465dd68dffb..1c8b74eeb566 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -3,31 +3,60 @@ icon_state = "laser" temperature = T0C + 300 fire_sound='sound/weapons/Laser.ogg' - impact_sounds = list(BULLET_IMPACT_MEAT = SOUNDS_LASER_MEAT, BULLET_IMPACT_METAL = SOUNDS_LASER_METAL) pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE damage = 40 - damage_type = BURN - sharp = 1 //concentrated burns + atom_damage_type = BURN + sharp = TRUE //concentrated burns damage_flags = DAM_LASER eyeblur = 4 hitscan = 1 - invisibility = 101 //beam projectiles are invisible as they are rendered by the effect engine + invisibility = INVISIBILITY_ABSTRACT //beam projectiles are invisible as they are rendered by the effect engine penetration_modifier = 0.3 distance_falloff = 2.5 + hitsound = 'sound/weapons/sear.ogg' + hitsound_non_mob = 'sound/weapons/searwall.ogg' - muzzle_type = /obj/effect/projectile/laser/muzzle - tracer_type = /obj/effect/projectile/laser/tracer - impact_type = /obj/effect/projectile/laser/impact + muzzle_type = /obj/effect/projectile/muzzle/laser + tracer_type = /obj/effect/projectile/tracer/laser + impact_type = /obj/effect/projectile/impact/laser + +/obj/item/projectile/beam/get_impact_sounds() + var/static/list/impact_sounds = list( + (BULLET_IMPACT_MEAT) = SOUNDS_LASER_MEAT, + (BULLET_IMPACT_METAL) = SOUNDS_LASER_METAL + ) + return impact_sounds + +/obj/item/projectile/beam/blue + damage = 30 + muzzle_type = /obj/effect/projectile/muzzle/laser/blue + tracer_type = /obj/effect/projectile/tracer/laser/blue + impact_type = /obj/effect/projectile/impact/laser/blue + +/obj/item/projectile/beam/megabot + damage = 45 + distance_falloff = 0.5 /obj/item/projectile/beam/variable - muzzle_type = /obj/effect/projectile/laser/variable/muzzle - tracer_type = /obj/effect/projectile/laser/variable/tracer - impact_type = /obj/effect/projectile/laser/variable/impact + muzzle_type = /obj/effect/projectile/muzzle/variable + tracer_type = /obj/effect/projectile/tracer/variable + impact_type = /obj/effect/projectile/impact/variable + +/obj/item/projectile/beam/variable/after_move() + . = ..() + var/obj/effect/projectile/invislight/light = locate() in loc + if(light) + light.light_color = color + light.set_light(l_color = light.light_color) + +/obj/item/projectile/beam/variable/update_effect(var/obj/effect/projectile/effect) + effect.color = color + effect.set_light(l_color = effect.light_color) /obj/item/projectile/beam/variable/split - muzzle_type = /obj/effect/projectile/laser/variable/heavy_muzzle - tracer_type = /obj/effect/projectile/laser/variable/heavy_tracer - impact_type = /obj/effect/projectile/laser/variable/heavy_impact + muzzle_type = /obj/effect/projectile/muzzle/variable_heavy + tracer_type = /obj/effect/projectile/tracer/variable_heavy + impact_type = /obj/effect/projectile/impact/variable_heavy var/split_type = /obj/item/projectile/beam/variable var/split_count = 3 @@ -46,8 +75,8 @@ P.light_color = color P.firer = firer P.shot_from = shot_from - P.damage = Floor(damage/split_count) - P.armor_penetration = Floor(armor_penetration/split_count) + P.damage = floor(damage/split_count) + P.armor_penetration = floor(armor_penetration/split_count) P.launch(pick_n_take(targets), def_zone) . = ..() @@ -73,9 +102,9 @@ armor_penetration = 30 distance_falloff = 0.5 - muzzle_type = /obj/effect/projectile/laser/heavy/muzzle - tracer_type = /obj/effect/projectile/laser/heavy/tracer - impact_type = /obj/effect/projectile/laser/heavy/impact + muzzle_type = /obj/effect/projectile/muzzle/heavy_laser + tracer_type = /obj/effect/projectile/tracer/heavy_laser + impact_type = /obj/effect/projectile/impact/heavy_laser /obj/item/projectile/beam/xray name = "x-ray beam" @@ -85,9 +114,9 @@ armor_penetration = 30 penetration_modifier = 0.8 - muzzle_type = /obj/effect/projectile/laser/xray/muzzle - tracer_type = /obj/effect/projectile/laser/xray/tracer - impact_type = /obj/effect/projectile/laser/xray/impact + muzzle_type = /obj/effect/projectile/muzzle/xray + tracer_type = /obj/effect/projectile/tracer/xray + impact_type = /obj/effect/projectile/impact/xray /obj/item/projectile/beam/xray/midlaser damage = 30 @@ -99,9 +128,9 @@ fire_sound='sound/weapons/pulse.ogg' damage = 15 //lower damage, but fires in bursts - muzzle_type = /obj/effect/projectile/laser/pulse/muzzle - tracer_type = /obj/effect/projectile/laser/pulse/tracer - impact_type = /obj/effect/projectile/laser/pulse/impact + muzzle_type = /obj/effect/projectile/muzzle/pulse + tracer_type = /obj/effect/projectile/tracer/pulse + impact_type = /obj/effect/projectile/impact/pulse /obj/item/projectile/beam/pulse/destroy name = "destroyer pulse" @@ -119,9 +148,9 @@ fire_sound = 'sound/weapons/emitter.ogg' damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm - muzzle_type = /obj/effect/projectile/laser/emitter/muzzle - tracer_type = /obj/effect/projectile/laser/emitter/tracer - impact_type = /obj/effect/projectile/laser/emitter/impact + muzzle_type = /obj/effect/projectile/muzzle/emitter + tracer_type = /obj/effect/projectile/tracer/emitter + impact_type = /obj/effect/projectile/impact/emitter /obj/item/projectile/beam/lastertag/blue name = "lasertag beam" @@ -129,17 +158,17 @@ pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE damage = 0 no_attack_log = 1 - damage_type = BURN + atom_damage_type = BURN - muzzle_type = /obj/effect/projectile/laser/blue/muzzle - tracer_type = /obj/effect/projectile/laser/blue/tracer - impact_type = /obj/effect/projectile/laser/blue/impact + muzzle_type = /obj/effect/projectile/muzzle/laser/blue + tracer_type = /obj/effect/projectile/tracer/laser/blue + impact_type = /obj/effect/projectile/impact/laser/blue /obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/M = target - if(istype(M.wear_suit, /obj/item/clothing/suit/redtag)) - M.Weaken(5) + if(ishuman(target)) + var/mob/living/human/M = target + if(istype(M.get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/redtag)) + SET_STATUS_MAX(M, STAT_WEAK, 5) return 1 /obj/item/projectile/beam/lastertag/red @@ -148,13 +177,13 @@ pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE damage = 0 no_attack_log = 1 - damage_type = BURN + atom_damage_type = BURN /obj/item/projectile/beam/lastertag/red/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/M = target - if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag)) - M.Weaken(5) + if(ishuman(target)) + var/mob/living/human/M = target + if(istype(M.get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/bluetag)) + SET_STATUS_MAX(M, STAT_WEAK, 5) return 1 /obj/item/projectile/beam/lastertag/omni//A laser tag bolt that stuns EVERYONE @@ -162,17 +191,18 @@ icon_state = "omnilaser" pass_flags = PASS_FLAG_TABLE | PASS_FLAG_GLASS | PASS_FLAG_GRILLE damage = 0 - damage_type = BURN + atom_damage_type = BURN - muzzle_type = /obj/effect/projectile/laser/omni/muzzle - tracer_type = /obj/effect/projectile/laser/omni/tracer - impact_type = /obj/effect/projectile/laser/omni/impact + muzzle_type = /obj/effect/projectile/muzzle/cult + tracer_type = /obj/effect/projectile/tracer/cult + impact_type = /obj/effect/projectile/impact/cult /obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/M = target - if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag))) - M.Weaken(5) + if(ishuman(target)) + var/mob/living/human/M = target + var/obj/item/suit = M.get_equipped_item(slot_wear_suit_str) + if((istype(suit, /obj/item/clothing/suit/bluetag))||(istype(suit, /obj/item/clothing/suit/redtag))) + SET_STATUS_MAX(M, STAT_WEAK, 5) return 1 /obj/item/projectile/beam/sniper @@ -185,24 +215,24 @@ weaken = 3 stutter = 3 - muzzle_type = /obj/effect/projectile/laser/xray/muzzle - tracer_type = /obj/effect/projectile/laser/xray/tracer - impact_type = /obj/effect/projectile/laser/xray/impact + muzzle_type = /obj/effect/projectile/muzzle/xray + tracer_type = /obj/effect/projectile/tracer/xray + impact_type = /obj/effect/projectile/impact/xray /obj/item/projectile/beam/stun name = "stun beam" icon_state = "stun" fire_sound = 'sound/weapons/Taser.ogg' damage_flags = 0 - sharp = 0 //not a laser + sharp = FALSE //not a laser damage = 1//flavor burn! still not a laser, dmg will be reduce by energy resistance not laser resistances - damage_type = BURN + atom_damage_type = BURN eyeblur = 1//Some feedback that you've been hit agony = 40 - muzzle_type = /obj/effect/projectile/stun/muzzle - tracer_type = /obj/effect/projectile/stun/tracer - impact_type = /obj/effect/projectile/stun/impact + muzzle_type = /obj/effect/projectile/muzzle/stun + tracer_type = /obj/effect/projectile/tracer/stun + impact_type = /obj/effect/projectile/impact/stun /obj/item/projectile/beam/stun/heavy name = "heavy stun beam" @@ -213,7 +243,7 @@ name = "shock beam" agony = 0 damage = 15 - damage_type = ELECTROCUTE + atom_damage_type = ELECTROCUTE fire_sound='sound/weapons/pulse.ogg' /obj/item/projectile/beam/stun/shock/heavy @@ -225,21 +255,21 @@ icon_state = "omnilaser" fire_sound = 'sound/weapons/plasma_cutter.ogg' damage = 15 - sharp = 1 - edge = 1 - damage_type = BURN + sharp = TRUE + edge = TRUE + atom_damage_type = BURN life_span = 5 pass_flags = PASS_FLAG_TABLE distance_falloff = 4 - muzzle_type = /obj/effect/projectile/trilaser/muzzle - tracer_type = /obj/effect/projectile/trilaser/tracer - impact_type = /obj/effect/projectile/trilaser/impact + muzzle_type = /obj/effect/projectile/muzzle/plasma_cutter + tracer_type = /obj/effect/projectile/tracer/plasma_cutter + impact_type = /obj/effect/projectile/impact/plasma_cutter /obj/item/projectile/beam/plasmacutter/on_impact(var/atom/A) - if(istype(A, /turf/simulated/wall/natural)) - var/turf/simulated/wall/natural/M = A - M.dismantle_wall() + if(istype(A, /turf/wall/natural)) + var/turf/wall/natural/M = A + M.dismantle_turf() . = ..() /obj/item/projectile/beam/confuseray @@ -251,27 +281,24 @@ sharp = FALSE distance_falloff = 5 damage_flags = 0 - damage_type = STUN + atom_damage_type = STUN life_span = 3 penetration_modifier = 0 var/potency_min = 4 var/potency_max = 6 - muzzle_type = /obj/effect/projectile/confuseray/muzzle - tracer_type = /obj/effect/projectile/confuseray/tracer - impact_type = /obj/effect/projectile/confuseray/impact + muzzle_type = /obj/effect/projectile/muzzle/disabler + tracer_type = /obj/effect/projectile/tracer/disabler + impact_type = /obj/effect/projectile/impact/disabler /obj/item/projectile/beam/confuseray/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living)) + if(isliving(target)) var/mob/living/L = target var/potency = rand(potency_min, potency_max) - L.confused += potency - L.eye_blurry += potency - if(L.confused >= 10) - L.Stun(1) - L.drop_l_hand() - L.drop_r_hand() - + ADJ_STATUS(L, STAT_CONFUSE, potency) + ADJ_STATUS(L, STAT_BLURRY, potency) + if(GET_STATUS(L, STAT_CONFUSE) >= 10) + SET_STATUS_MAX(L, STAT_STUN, 1) return 1 /obj/item/projectile/beam/particle @@ -279,9 +306,9 @@ icon_state = "particle" damage = 35 armor_penetration = 50 - muzzle_type = /obj/effect/projectile/laser_particle/muzzle - tracer_type = /obj/effect/projectile/laser_particle/tracer - impact_type = /obj/effect/projectile/laser_particle/impact + muzzle_type = /obj/effect/projectile/muzzle/particle + tracer_type = /obj/effect/projectile/tracer/particle + impact_type = /obj/effect/projectile/impact/particle penetration_modifier = 0.5 /obj/item/projectile/beam/particle/small @@ -295,31 +322,31 @@ icon_state = "darkb" damage = 40 armor_penetration = 35 - damage_type = BRUTE - muzzle_type = /obj/effect/projectile/darkmatter/muzzle - tracer_type = /obj/effect/projectile/darkmatter/tracer - impact_type = /obj/effect/projectile/darkmatter/impact + atom_damage_type = BRUTE + muzzle_type = /obj/effect/projectile/muzzle/darkmatter + tracer_type = /obj/effect/projectile/tracer/darkmatter + impact_type = /obj/effect/projectile/impact/darkmatter /obj/item/projectile/beam/stun/darkmatter name = "dark matter wave" icon_state = "darkt" damage_flags = 0 - sharp = 0 //not a laser + sharp = FALSE //not a laser agony = 40 - damage_type = STUN - muzzle_type = /obj/effect/projectile/stun/darkmatter/muzzle - tracer_type = /obj/effect/projectile/stun/darkmatter/tracer - impact_type = /obj/effect/projectile/stun/darkmatter/impact + atom_damage_type = STUN + muzzle_type = /obj/effect/projectile/muzzle/darkmattertaser + tracer_type = /obj/effect/projectile/tracer/darkmattertaser + impact_type = /obj/effect/projectile/impact/darkmattertaser /obj/item/projectile/beam/pointdefense name = "point defense salvo" icon_state = "laser" damage = 15 - damage_type = ELECTROCUTE //You should be safe inside a voidsuit + atom_damage_type = ELECTROCUTE //You should be safe inside a voidsuit sharp = FALSE //"Wide" spectrum beam - muzzle_type = /obj/effect/projectile/pointdefense/muzzle - tracer_type = /obj/effect/projectile/pointdefense/tracer - impact_type = /obj/effect/projectile/pointdefense/impact + muzzle_type = /obj/effect/projectile/muzzle/pd + tracer_type = /obj/effect/projectile/tracer/pd + impact_type = /obj/effect/projectile/impact/pd /obj/item/projectile/beam/incendiary_laser name = "scattered laser blast" @@ -333,23 +360,23 @@ life_span = 8 penetration_modifier = 0.1 - muzzle_type = /obj/effect/projectile/incen/muzzle - tracer_type = /obj/effect/projectile/incen/tracer - impact_type = /obj/effect/projectile/incen/impact + muzzle_type = /obj/effect/projectile/muzzle/incen + tracer_type = /obj/effect/projectile/tracer/incen + impact_type = /obj/effect/projectile/impact/incen /obj/item/projectile/beam/incendiary_laser/on_hit(var/atom/target, var/blocked = 0) ..() if(isliving(target)) var/mob/living/L = target - L.adjust_fire_stacks(rand(2,4)) - if(L.fire_stacks >= 3) - L.IgniteMob() + L.adjust_fire_intensity(rand(2,4)) + if(L.get_fire_intensity() >= 3) + L.ignite_fire() /obj/item/projectile/beam/pop icon_state = "bluelaser" fire_sound = 'sound/weapons/gunshot/laserbulb.ogg' fire_sound_vol = 100 - muzzle_type = /obj/effect/projectile/laser/blue/muzzle - tracer_type = /obj/effect/projectile/laser/blue/tracer - impact_type = /obj/effect/projectile/laser/blue/impact \ No newline at end of file + muzzle_type = /obj/effect/projectile/muzzle/laser/blue + tracer_type = /obj/effect/projectile/tracer/laser/blue + impact_type = /obj/effect/projectile/impact/laser/blue diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index b6f0eea333b9..e94f5926a344 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -3,20 +3,37 @@ icon_state = "bullet" fire_sound = 'sound/weapons/gunshot/gunshot_strong.ogg' damage = 50 - damage_type = BRUTE + atom_damage_type = BRUTE damage_flags = DAM_BULLET | DAM_SHARP nodamage = 0 embed = 1 space_knockback = 1 penetration_modifier = 1.0 + impact_effect_type = /obj/effect/temp_visual/impact_effect + muzzle_type = /obj/effect/projectile/muzzle/bullet + hitsound_non_mob = "ricochet" + var/mob_passthrough_check = 0 var/caliber - muzzle_type = /obj/effect/projectile/bullet/muzzle - miss_sounds = list('sound/weapons/guns/miss1.ogg','sound/weapons/guns/miss2.ogg','sound/weapons/guns/miss3.ogg','sound/weapons/guns/miss4.ogg') - ricochet_sounds = list('sound/weapons/guns/ricochet1.ogg', 'sound/weapons/guns/ricochet2.ogg', - 'sound/weapons/guns/ricochet3.ogg', 'sound/weapons/guns/ricochet4.ogg') - impact_sounds = list(BULLET_IMPACT_MEAT = SOUNDS_BULLET_MEAT, BULLET_IMPACT_METAL = SOUNDS_BULLET_METAL) +/obj/item/projectile/bullet/get_miss_sounds() + var/static/list/miss_sounds = list( + 'sound/weapons/guns/miss1.ogg', + 'sound/weapons/guns/miss2.ogg', + 'sound/weapons/guns/miss3.ogg', + 'sound/weapons/guns/miss4.ogg' + ) + +/obj/item/projectile/bullet/get_ricochet_sounds() + return global.ricochet_sound + +/obj/item/projectile/bullet/get_impact_sounds() + + var/static/list/impact_sounds = list( + (BULLET_IMPACT_MEAT) = SOUNDS_BULLET_MEAT, + (BULLET_IMPACT_METAL) = SOUNDS_BULLET_METAL + ) + return impact_sounds /obj/item/projectile/bullet/get_autopsy_descriptors() . = ..() @@ -28,15 +45,16 @@ var/mob/living/L = target shake_camera(L, 3, 2) -/obj/item/projectile/bullet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier) +/obj/item/projectile/bullet/attack_mob(var/mob/target_mob, var/distance, var/miss_modifier) if(penetrating > 0 && damage > 20 && prob(damage)) mob_passthrough_check = 1 else mob_passthrough_check = 0 . = ..() - - if(. == 1 && iscarbon(target_mob)) - damage *= 0.7 //squishy mobs absorb KE + if(. == 1 && isliving(target_mob)) + var/mob/living/squish = target_mob + if(!squish.isSynthetic()) + damage *= 0.7 //squishy mobs absorb KE /obj/item/projectile/bullet/can_embed() //prevent embedding if the projectile is passing through the mob @@ -55,7 +73,7 @@ var/chance = damage if(has_extension(A, /datum/extension/penetration)) var/datum/extension/penetration/P = get_extension(A, /datum/extension/penetration) - chance = P.PenetrationProbability(chance, damage, damage_type) + chance = P.PenetrationProbability(chance, damage, atom_damage_type) if(prob(chance)) if(A.opacity) @@ -91,6 +109,10 @@ agony = 30 embed = 0 +/obj/item/projectile/bullet/pistol/rubber/strong + damage = 8 + agony = 38 + /obj/item/projectile/bullet/pistol/rubber/holdout agony = 20 @@ -140,7 +162,7 @@ /* Miscellaneous */ /obj/item/projectile/bullet/blank - invisibility = 101 + invisibility = INVISIBILITY_ABSTRACT damage = 1 embed = 0 @@ -158,9 +180,9 @@ /obj/item/projectile/bullet/pistol/cap name = "cap" - invisibility = 101 + invisibility = INVISIBILITY_ABSTRACT fire_sound = null - damage_type = PAIN + atom_damage_type = PAIN damage_flags = 0 damage = 0 nodamage = 1 diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm index 8b10305434f5..7e498de80efc 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -2,98 +2,66 @@ name = "bolt of change" icon_state = "ice_1" damage = 0 - damage_type = BURN + atom_damage_type = BURN damage_flags = 0 nodamage = 1 /obj/item/projectile/change/on_hit(var/atom/change) wabbajack(change) -/obj/item/projectile/change/proc/wabbajack(var/mob/M) - if(istype(M, /mob/living) && M.stat != DEAD) - if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(M)) - return - - M.handle_pre_transformation() - - if(istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/Robot = M - if(Robot.mmi) - qdel(Robot.mmi) - else - for(var/obj/item/W in M) - if(istype(W, /obj/item/implant)) //TODO: Carn. give implants a dropped() or something - qdel(W) - continue - M.drop_from_inventory(W) +/obj/item/projectile/change/proc/get_random_transformation_options(var/mob/M) + . = list() + if(!isrobot(M)) + . += "robot" + for(var/decl/species/species as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/species)) + . += species.uid + if(ishuman(M)) + var/mob/living/human/H = M + . -= H.species.uid - var/mob/living/new_mob +/obj/item/projectile/change/proc/apply_transformation(var/mob/M, var/choice) - var/options = list("robot", "slime") - for(var/t in get_all_species()) - options += t - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species) - options -= H.species.name - else if(isrobot(M)) - options -= "robot" - else if(isslime(M)) - options -= "slime" + if(choice == "robot") + var/mob/living/silicon/robot/robot = new(get_turf(M)) + robot.set_gender(M.get_gender()) + robot.job = ASSIGNMENT_ROBOT + robot.central_processor = new /obj/item/organ/internal/brain_interface(robot) + transfer_key_from_mob_to_mob(M, robot) + return robot - var/randomize = pick(options) - switch(randomize) - if("robot") - new_mob = new /mob/living/silicon/robot(M.loc) - new_mob.gender = M.gender - new_mob.set_invisibility(0) - new_mob.job = "Robot" - var/mob/living/silicon/robot/Robot = new_mob - Robot.mmi = new /obj/item/mmi(new_mob) - Robot.mmi.transfer_identity(M) //Does not transfer key/client. - if("slime") - new_mob = new /mob/living/carbon/slime(M.loc) - new_mob.universal_speak = TRUE - else - var/mob/living/carbon/human/H - if(ishuman(M)) - H = M - else - new_mob = new /mob/living/carbon/human(M.loc) - H = new_mob + if(decls_repository.get_decl_by_id(choice)) + var/mob/living/human/H = M + if(!istype(H)) + H = new(get_turf(M)) + H.set_gender(M.get_gender()) + H.name = "unknown" // This will cause set_species() to randomize the mob name. + H.real_name = H.name + H.change_species(choice) + H.universal_speak = TRUE + var/datum/preferences/A = new() + A.randomize_appearance_and_body_for(H) + return H - if(M.gender == MALE) - H.gender = MALE - H.SetName(pick(GLOB.first_names_male)) - else if(M.gender == FEMALE) - H.gender = FEMALE - H.SetName(pick(GLOB.first_names_female)) - else - H.gender = NEUTER - H.SetName(pick(GLOB.first_names_female|GLOB.first_names_male)) - - H.name += " [pick(GLOB.last_names)]" - H.real_name = H.name - - H.set_species(randomize) - H.universal_speak = TRUE - var/datum/preferences/A = new() //Randomize appearance for the human - A.randomize_appearance_and_body_for(H) +/obj/item/projectile/change/proc/wabbajack(var/mob/M) - if(new_mob) - for (var/spell/S in M.mind.learned_spells) - new_mob.add_spell(new S.type) + if(!isliving(M) || M.stat == DEAD) + return - new_mob.a_intent = "hurt" - if(M.mind) - M.mind.transfer_to(new_mob) - else - new_mob.key = M.key + if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(M)) + return - to_chat(new_mob, "Your form morphs into that of \a [lowertext(randomize)].") + M.handle_pre_transformation() + var/choice = pick(get_random_transformation_options(M)) + var/mob/living/new_mob = apply_transformation(M, choice) + if(new_mob) + new_mob.set_intent(I_FLAG_HARM) + new_mob.copy_abilities_from(M) + transfer_key_from_mob_to_mob(M, new_mob) + to_chat(new_mob, "Your form morphs into that of \a [choice].") + else + new_mob = M + if(new_mob) + to_chat(new_mob, SPAN_WARNING("Your form morphs into that of \a [choice].")) - qdel(M) - return - else - to_chat(M, "Your form morphs into that of \a [lowertext(randomize)].") - return \ No newline at end of file + if(new_mob != M && !QDELETED(M)) + qdel(M) diff --git a/code/modules/projectiles/projectile/effects/projectile_effects.dm b/code/modules/projectiles/projectile/effects/projectile_effects.dm new file mode 100644 index 000000000000..42692c3ebc2b --- /dev/null +++ b/code/modules/projectiles/projectile/effects/projectile_effects.dm @@ -0,0 +1,83 @@ +/obj/effect/projectile + name = "pew" + icon = 'icons/obj/projectiles.dmi' + icon_state = "nothing" + plane = ABOVE_LIGHTING_PLANE + layer = BEAM_PROJECTILE_LAYER //Muzzle flashes would be above the lighting plane anyways. + anchored = TRUE + light_color = "#00ffff" + light_range = 2 + light_power = 1 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + appearance_flags = 0 + var/overlay_state + var/overlay_color + +/obj/effect/projectile/invislight + alpha = 0 + invisibility = INVISIBILITY_MAXIMUM + +/obj/effect/projectile/invislight/proc/copy_from(var/obj/effect/projectile/owner) + light_range = initial(owner.light_range) + light_power = initial(owner.light_power) + light_color = initial(owner.light_color) + light_wedge = initial(owner.light_wedge) + + set_light(light_range, light_power, light_color, light_wedge) + +/obj/effect/projectile/on_update_icon() + cut_overlays() + if(overlay_state) + var/image/I = image(icon, "[icon_state][overlay_state]") + I.color = overlay_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + // Projectile effects only exist for a tick or two, need to call + // this to ensure they show their overlays before expiring. + compile_overlays() + +/obj/effect/projectile/singularity_pull() + return + +/obj/effect/projectile/singularity_act() + return 0 + +/obj/effect/projectile/proc/scale_to(nx,ny,override=TRUE) + var/matrix/M + if(override) + M = new + else + M = transform + M.Scale(nx,ny) + transform = M + +/obj/effect/projectile/proc/turn_to(angle,override=TRUE) + var/matrix/M + if(override) + M = new + else + M = transform + M.Turn(angle) + transform = M + +/obj/effect/projectile/Initialize(mapload, angle_override, p_x, p_y, color_override, scaling = 1) + if(angle_override && p_x && p_y && color_override && scaling) + apply_vars(angle_override, p_x, p_y, color_override, scaling) + . = ..() + if(overlay_state) + update_icon() + +/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0) + var/mutable_appearance/look = new(src) + look.pixel_x = p_x + look.pixel_y = p_y + if(color_override) + look.color = color_override + appearance = look + scale_to(1,scaling, FALSE) + turn_to(angle_override, FALSE) + if(!isnull(new_loc)) //If you want to null it just delete it... + forceMove(new_loc) + for(var/i in 1 to increment) + pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1) + pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1) diff --git a/code/modules/projectiles/projectile/effects/projectile_impact.dm b/code/modules/projectiles/projectile/effects/projectile_impact.dm new file mode 100644 index 000000000000..b762d6aeb698 --- /dev/null +++ b/code/modules/projectiles/projectile/effects/projectile_impact.dm @@ -0,0 +1,95 @@ +/obj/effect/projectile/impact + name = "beam impact" + icon = 'icons/effects/projectiles/impact.dmi' + +/obj/effect/projectile/impact/laser + name = "laser impact" + icon_state = "impact_laser" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/laser/blue + name = "laser impact" + icon_state = "impact_blue" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/impact/disabler + name = "disabler impact" + icon_state = "impact_omni" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/impact/xray + name = "xray impact" + icon_state = "impact_xray" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/impact/pulse + name = "pulse impact" + icon_state = "impact_u_laser" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/impact/plasma_cutter + name = "plasma impact" + icon_state = "impact_plasmacutter" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/impact/stun + name = "stun impact" + icon_state = "impact_stun" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/impact/heavy_laser + name = "heavy laser impact" + icon_state = "impact_beam_heavy" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/cult + name = "arcane blast" + icon_state = "impact_cult" + light_color = LIGHT_COLOR_VIOLET + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/impact/cult/heavy + icon_state = "impact_hcult" + +/obj/effect/projectile/impact/solar + name = "solar eruption" + icon_state = "impact_solar" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/impact/eyelaser + icon_state = "impact_eye" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/emitter + icon_state = "impact_emitter" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/impact/particle + icon_state = "impact_particle" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/impact/darkmatter + icon_state = "impact_darkmatter" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/impact/darkmattertaser + icon_state = "impact_darkt" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/impact/incen + icon_state = "impact_incen" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/impact/pd + icon_state = "impact_pd" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/impact/variable + icon_state = "impact_laser_white" + overlay_state = "_overlay" + light_color = COLOR_WHITE + +/obj/effect/projectile/impact/variable_heavy + icon_state = "impact_laser_heavy_white" + overlay_state = "_overlay" + light_color = COLOR_WHITE diff --git a/code/modules/projectiles/projectile/effects/projectile_muzzle.dm b/code/modules/projectiles/projectile/effects/projectile_muzzle.dm new file mode 100644 index 000000000000..f5fbb23e9034 --- /dev/null +++ b/code/modules/projectiles/projectile/effects/projectile_muzzle.dm @@ -0,0 +1,90 @@ +/obj/effect/projectile/muzzle + name = "muzzle flash" + icon = 'icons/effects/projectiles/muzzle.dmi' + +/obj/effect/projectile/muzzle/laser + icon_state = "muzzle_laser" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/laser/blue + icon_state = "muzzle_laser_blue" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/muzzle/disabler + icon_state = "muzzle_omni" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/muzzle/xray + icon_state = "muzzle_xray" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/muzzle/pulse + icon_state = "muzzle_u_laser" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/muzzle/plasma_cutter + icon_state = "muzzle_plasmacutter" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/muzzle/stun + icon_state = "muzzle_stun" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/muzzle/heavy_laser + icon_state = "muzzle_beam_heavy" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/cult + name = "arcane flash" + icon_state = "muzzle_cult" + light_color = LIGHT_COLOR_VIOLET + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/muzzle/cult/heavy + icon_state = "muzzle_hcult" + +/obj/effect/projectile/muzzle/solar + icon_state = "muzzle_solar" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/muzzle/eyelaser + icon_state = "muzzle_eye" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/emitter + icon_state = "muzzle_emitter" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/muzzle/bullet + icon_state = "muzzle_bullet" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/muzzle/particle + icon_state = "muzzle_particle" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/muzzle/darkmatter + icon_state = "muzzle_darkmatter" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/muzzle/darkmattertaser + icon_state = "muzzle_darkt" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/muzzle/incen + icon_state = "muzzle_incen" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/muzzle/pd + icon_state = "muzzle_pd" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/muzzle/variable + icon_state = "muzzle_laser_white" + overlay_state = "_overlay" + light_color = COLOR_WHITE + +/obj/effect/projectile/muzzle/variable_heavy + icon_state = "muzzle_laser_heavy_white" + overlay_state = "_overlay" + light_color = COLOR_WHITE diff --git a/code/modules/projectiles/projectile/effects/projectile_tracer.dm b/code/modules/projectiles/projectile/effects/projectile_tracer.dm new file mode 100644 index 000000000000..9d1af0e67937 --- /dev/null +++ b/code/modules/projectiles/projectile/effects/projectile_tracer.dm @@ -0,0 +1,120 @@ +/proc/generate_tracer_between_points(var/obj/item/projectile/source, datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported! + if(!istype(starting) || !istype(ending) || !ispath(beam_type)) + return + if(starting.z != ending.z) + PRINT_STACK_TRACE("Projectile tracer generation of cross-Z beam detected. This feature is not supported!") //Do it anyways though. + var/datum/point/midpoint = point_midpoint_points(starting, ending) + var/obj/effect/projectile/tracer/PB = new beam_type + source.update_effect(PB) + PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0) + . = PB + if(qdel_in) + QDEL_IN(PB, qdel_in) + +/obj/effect/projectile/tracer + name = "beam" + icon = 'icons/effects/projectiles/tracer.dmi' + +/obj/effect/projectile/tracer/laser + name = "laser" + icon_state = "beam" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/laser/blue + icon_state = "beam_blue" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/tracer/disabler + name = "disabler" + icon_state = "beam_omni" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/tracer/xray + name = "xray laser" + icon_state = "xray" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/tracer/pulse + name = "pulse laser" + icon_state = "u_laser" + light_color = LIGHT_COLOR_BLUE + +/obj/effect/projectile/tracer/plasma_cutter + name = "plasma blast" + icon_state = "plasmacutter" + light_color = LIGHT_COLOR_CYAN + +/obj/effect/projectile/tracer/stun + name = "stun beam" + icon_state = "stun" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/tracer/heavy_laser + name = "heavy laser" + icon_state = "beam_heavy" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/cult + name = "arcane beam" + icon_state = "cult" + light_color = LIGHT_COLOR_VIOLET + appearance_flags = NO_CLIENT_COLOR + +/obj/effect/projectile/tracer/cult/heavy + name = "heavy arcane beam" + icon_state = "hcult" + +/obj/effect/projectile/tracer/solar + name = "solar energy" + icon_state = "solar" + light_color = LIGHT_COLOR_FIRE + +/obj/effect/projectile/tracer/eyelaser + icon_state = "eye" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/emitter + icon_state = "emitter" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/tracer/tachyon + name = "particle beam" + icon_state = "invisible" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/tracer/bfg + icon_state = "bfg" + light_color = LIGHT_COLOR_GREEN + +/obj/effect/projectile/tracer/particle + name = "particle beam" + icon_state = "particle" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/tracer/darkmatter + name = "darkmatter beam" + icon_state = "darkmatter" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/tracer/darkmattertaser + name = "darktaser beam" + icon_state = "darkt" + light_color = LIGHT_COLOR_VIOLET + +/obj/effect/projectile/tracer/incen + icon_state = "incen" + light_color = LIGHT_COLOR_RED + +/obj/effect/projectile/tracer/pd + icon_state = "pd" + light_color = LIGHT_COLOR_YELLOW + +/obj/effect/projectile/tracer/variable + icon_state = "beam_white" + overlay_state = "_overlay" + light_color = COLOR_WHITE + +/obj/effect/projectile/tracer/variable_heavy + icon_state = "beam_heavy_white" + overlay_state = "_overlay" + light_color = COLOR_WHITE diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index 377e47887625..e08ffc8d1f01 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -3,9 +3,12 @@ icon_state = "spark" temperature = T0C + 300 damage = 0 - damage_type = BURN + atom_damage_type = BURN damage_flags = 0 distance_falloff = 2.5 + impact_effect_type = /obj/effect/temp_visual/impact_effect + hitsound_non_mob = 'sound/weapons/searwall.ogg' + hitsound = 'sound/weapons/zapbang.ogg' //releases a burst of light on impact or after travelling a distance /obj/item/projectile/energy/flash @@ -15,32 +18,31 @@ damage = 5 agony = 20 life_span = 15 //if the shell hasn't hit anything after travelling this far it just explodes. - muzzle_type = /obj/effect/projectile/bullet/muzzle + muzzle_type = /obj/effect/projectile/muzzle/bullet + hitsound_non_mob = null var/flash_range = 1 var/brightness = 7 - var/light_colour = "#ffffff" + var/light_flash_color = COLOR_WHITE /obj/item/projectile/energy/flash/on_impact(var/atom/A) var/turf/T = flash_range? src.loc : get_turf(A) if(!istype(T)) return //blind and confuse adjacent people - for (var/mob/living/carbon/M in viewers(T, flash_range)) + for (var/mob/living/M in viewers(T, flash_range)) if(M.eyecheck() < FLASH_PROTECTION_MAJOR) M.flash_eyes() - M.eye_blurry += (brightness / 2) - M.confused += (brightness / 2) + ADJ_STATUS(M, STAT_BLURRY, brightness / 2) + ADJ_STATUS(M, STAT_CONFUSE, brightness / 2) //snap pop playsound(src, 'sound/effects/snap.ogg', 50, 1) src.visible_message("\The [src] explodes in a bright flash!") - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(2, 1, T) - sparks.start() + spark_at(T, amount=2, cardinal_only = TRUE) new /obj/effect/decal/cleanable/ash(src.loc) //always use src.loc so that ash doesn't end up inside windows - new /obj/effect/effect/smoke/illumination(T, 5, 4, 1, light_colour) + new /obj/effect/effect/smoke/illumination(T, 5, 4, 1, light_flash_color) //blinds people like the flash round, but in a larger area and can also be used for temporary illumination /obj/item/projectile/energy/flash/flare @@ -51,21 +53,21 @@ brightness = 15 /obj/item/projectile/energy/flash/flare/on_impact(var/atom/A) - light_colour = pick("#e58775", "#ffffff", "#faa159", "#e34e0e") - set_light(1, 1, 4, 2, light_colour) + light_flash_color = pick("#e58775", "#ffffff", "#faa159", "#e34e0e") + set_light(4, 2, light_flash_color) ..() //initial flash //residual illumination - new /obj/effect/effect/smoke/illumination(loc, rand(190,240), 8, 1, light_colour) //same lighting power as flare + new /obj/effect/effect/smoke/illumination(loc, rand(190,240), 8, 1, light_flash_color) //same lighting power as flare var/turf/TO = get_turf(src) var/area/AO = TO.loc if(AO && (AO.area_flags & AREA_FLAG_EXTERNAL)) //Everyone saw that! - for(var/mob/living/mob in GLOB.living_mob_list_) + for(var/mob/living/mob in global.living_mob_list_) var/turf/T = get_turf(mob) var/area/A1 = T.loc - if(T && (T != TO) && (TO.z == T.z) && !mob.blinded) + if(T && (T != TO) && (TO.z == T.z) && !mob.is_blind()) var/visible = FALSE if(A1 && (A1.area_flags & AREA_FLAG_EXTERNAL)) visible = TRUE @@ -81,16 +83,16 @@ visible = TRUE break if(visible) - to_chat(mob, SPAN_NOTICE("You see a bright light to \the [dir2text(get_dir(T,TO))]")) + to_chat(mob, SPAN_NOTICE("You see a bright light to \the [dir2text(get_dir(T,TO))].")) CHECK_TICK - -/obj/item/projectile/energy/electrode //has more pain than a beam because it's harder to hit + +/obj/item/projectile/energy/electrode //has more pain than a beam because it's harder to hit name = "electrode" icon_state = "spark" fire_sound = 'sound/weapons/Taser.ogg' agony = 50 damage = 2 - damage_type = BURN + atom_damage_type = BURN eyeblur = 1//Some feedback that you've been hit step_delay = 0.7 @@ -106,21 +108,22 @@ icon_state = "declone" fire_sound = 'sound/weapons/pulse3.ogg' damage = 30 - damage_type = CLONE + atom_damage_type = CLONE irradiate = 40 + impact_effect_type = /obj/effect/temp_visual/impact_effect/monochrome_laser /obj/item/projectile/energy/dart name = "dart" icon_state = "toxin" damage = 5 - damage_type = TOX + atom_damage_type = TOX weaken = 5 /obj/item/projectile/energy/bolt name = "bolt" icon_state = "cbbolt" damage = 10 - damage_type = TOX + atom_damage_type = TOX nodamage = 0 agony = 40 stutter = 10 @@ -134,7 +137,7 @@ name = "neuro" icon_state = "neurotoxin" damage = 5 - damage_type = TOX + atom_damage_type = TOX weaken = 5 /obj/item/projectile/energy/radiation @@ -142,8 +145,9 @@ icon_state = "energy" fire_sound = 'sound/effects/stealthoff.ogg' damage = 20 - damage_type = TOX + atom_damage_type = TOX irradiate = 20 + impact_effect_type = /obj/effect/temp_visual/impact_effect/monochrome_laser /obj/item/projectile/energy/plasmastun name = "plasma pulse" @@ -153,13 +157,13 @@ life_span = 4 damage = 5 agony = 70 - damage_type = BURN + atom_damage_type = BURN vacuum_traversal = 0 var/min_dizziness_amt = 60 var/med_dizziness_amt = 120 var/max_dizziness_amt = 300 -/obj/item/projectile/energy/plasmastun/proc/bang(var/mob/living/carbon/M) +/obj/item/projectile/energy/plasmastun/proc/bang(var/mob/living/M) if(!istype(M)) return @@ -169,29 +173,28 @@ var/ear_safety = 0 if(M.get_sound_volume_multiplier() < 0.2) ear_safety += 2 - if(MUTATION_HULK in M.mutations) - ear_safety += 1 if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(istype(H.head, /obj/item/clothing/head/helmet)) + var/mob/living/human/H = M + if(istype(H.get_equipped_item(slot_head_str), /obj/item/clothing/head/helmet)) ear_safety += 1 if(!ear_safety) - M.make_dizzy(max_dizziness_amt) - M.ear_damage += rand(1, 10) - M.ear_deaf = max(M.ear_deaf,15) + SET_STATUS_MAX(M, STAT_DIZZY, max_dizziness_amt) + ADJ_STATUS(M, STAT_TINNITUS, rand(1, 10)) + SET_STATUS_MAX(M, STAT_DEAF, 15) + else if(ear_safety > 1) - M.make_dizzy(min_dizziness_amt) + SET_STATUS_MAX(M, STAT_DIZZY, min_dizziness_amt) else - M.make_dizzy(med_dizziness_amt) + SET_STATUS_MAX(M, STAT_DIZZY, med_dizziness_amt) - if(M.ear_damage >= 15) + if(GET_STATUS(M, STAT_TINNITUS) >= 15) to_chat(M, SPAN_DANGER("Your ears start to ring badly!")) - if(prob(M.ear_damage - 5)) + if(prob(GET_STATUS(M, STAT_TINNITUS) - 5)) to_chat(M, SPAN_DANGER("You can't hear anything!")) - M.set_sdisability(DEAFENED) + M.add_genetic_condition(GENE_COND_DEAFENED) else - if(M.ear_damage >= 5) + if(GET_STATUS(M, STAT_TINNITUS) >= 5) to_chat(M, SPAN_DANGER("Your ears start to ring!")) /obj/item/projectile/energy/plasmastun/on_hit(var/atom/target) @@ -204,7 +207,7 @@ fire_sound = 'sound/effects/basscannon.ogg' damage = 5 armor_penetration = 40 - damage_type = BRUTE + atom_damage_type = BRUTE vacuum_traversal = 0 penetration_modifier = 0.2 penetrating = 1 @@ -212,7 +215,7 @@ med_dizziness_amt = 60 max_dizziness_amt = 120 -/obj/item/projectile/energy/plasmastun/sonic/bang(var/mob/living/carbon/M) +/obj/item/projectile/energy/plasmastun/sonic/bang(var/mob/living/M) ..() if(istype(M, /atom/movable) && M.simulated && !M.anchored) M.throw_at(get_edge_target_turf(M, get_dir(src, M)), rand(1,5), 6) @@ -230,4 +233,4 @@ fire_sound = 'sound/weapons/eLuger.ogg' damage = 10 armor_penetration = 35 - damage_type = BRUTE + atom_damage_type = BRUTE diff --git a/code/modules/projectiles/projectile/fireball.dm b/code/modules/projectiles/projectile/fireball.dm new file mode 100644 index 000000000000..6221b8bf1348 --- /dev/null +++ b/code/modules/projectiles/projectile/fireball.dm @@ -0,0 +1,45 @@ +/obj/item/projectile/fireball + name = "fireball" + icon_state = "fireball" + fire_sound = 'sound/effects/bamf.ogg' + damage = 20 + atom_damage_type = BURN + damage_flags = DAM_DISPERSED // burn all over + var/fire_lifetime = 2 SECONDS + var/fire_temperature = (288 CELSIUS) / 0.9 + 1 // hot enough to ignite wood! divided by 0.9 and plus one to ensure we can light firepits + +/obj/effect/fake_fire/variable + name = "fire" + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + firelevel = 1 + pressure = ONE_ATMOSPHERE + +/obj/effect/fake_fire/variable/Initialize(ml, new_temperature, new_lifetime) + lifetime = new_lifetime + last_temperature = new_temperature + return ..() + +// we deal our damage via fire_act, not via direct burn damage. our burn damage is specifically for mobs +/obj/item/projectile/fireball/get_structure_damage() + return 0 + +/obj/item/projectile/fireball/on_impact(var/atom/A) + . = ..() + var/obj/effect/fake_fire/fire = new /obj/effect/fake_fire/variable(get_turf(A), fire_temperature, fire_lifetime) + fire.Process() // process at least once! + qdel_self() + +/obj/item/projectile/fireball/after_move() + . = ..() + if(!loc) + return + for(var/mob/living/victim in loc) + if(!victim.simulated) + continue + victim.FireBurn(1, fire_temperature, ONE_ATMOSPHERE) + loc.fire_act(1, fire_temperature, ONE_ATMOSPHERE) + for(var/atom/burned in loc) + if(!burned.simulated || burned == src) + continue + burned.fire_act(1, fire_temperature, ONE_ATMOSPHERE) diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm index 3ce9bcd0cd1a..e0b8ea2745f9 100644 --- a/code/modules/projectiles/projectile/force.dm +++ b/code/modules/projectiles/projectile/force.dm @@ -3,14 +3,33 @@ icon = 'icons/obj/projectiles.dmi' icon_state = "ice_1" damage = 20 - damage_type = BURN + atom_damage_type = BURN damage_flags = 0 + impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser + hitsound_non_mob = 'sound/weapons/searwall.ogg' /obj/item/projectile/forcebolt/strong name = "force bolt" /obj/item/projectile/forcebolt/on_hit(var/atom/movable/target, var/blocked = 0) - if(istype(target)) + if(istype(target) && isturf(target.loc)) var/throwdir = get_dir(firer,target) target.throw_at(get_edge_target_turf(target, throwdir),10,10) - return 1 \ No newline at end of file + return 1 + +/obj/item/projectile/firebolt + name = "fireball" + icon_state = "fireball" + fire_sound = 'sound/magic/fireball.ogg' + damage = 20 + atom_damage_type = BURN + damage_flags = 0 + + var/ex_severe = -1 + var/ex_heavy = -1 + var/ex_light = 1 + var/ex_flash = 2 + +/obj/item/projectile/firebolt/on_impact(var/atom/A) + . = ..() + explosion(A, ex_severe, ex_heavy, ex_light, ex_flash) diff --git a/code/modules/projectiles/projectile/pellets.dm b/code/modules/projectiles/projectile/pellets.dm index 4823a8fcfe3b..5c19804a9c2f 100644 --- a/code/modules/projectiles/projectile/pellets.dm +++ b/code/modules/projectiles/projectile/pellets.dm @@ -16,8 +16,10 @@ var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance return max(pellets - pellet_loss, 1) -/obj/item/projectile/bullet/pellet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier) - if (pellets < 0) return 1 +/obj/item/projectile/bullet/pellet/attack_mob(var/mob/target_mob, var/distance, var/miss_modifier) + SHOULD_CALL_PARENT(FALSE) + if (pellets < 0) + return 1 var/total_pellets = get_pellets(distance) var/spread = max(base_spread - (spread_step*distance), 0) @@ -29,17 +31,19 @@ var/hits = 0 for (var/i in 1 to total_pellets) - if(target_mob.lying && target_mob != original && prob(prone_chance)) + if(target_mob.current_posture.prone && target_mob != original && prob(prone_chance)) continue //pellet hits spread out across different zones, but 'aim at' the targeted zone with higher probability //whether the pellet actually hits the def_zone or a different zone should still be determined by the parent using get_zone_with_miss_chance(). var/old_zone = def_zone - def_zone = ran_zone(def_zone, spread) + def_zone = ran_zone(def_zone, spread, target_mob) if (..()) hits++ def_zone = old_zone //restore the original zone the projectile was aimed at - pellets -= hits //each hit reduces the number of pellets left + if(hits > 0) + pellets -= hits //each hit reduces the number of pellets left + if (hits >= total_pellets || pellets <= 0) return 1 return 0 @@ -54,7 +58,7 @@ //If this is a shrapnel explosion, allow mobs that are prone to get hit, too if(. && !base_spread && isturf(loc)) for(var/mob/living/M in loc) - if(M.lying || !M.CanPass(src, loc, 0.5, 0)) //Bump if lying or if we would normally Bump. + if(M.current_posture.prone || !M.CanPass(src, loc, 0.5, 0)) //Bump if lying or if we would normally Bump. if(Bump(M)) //Bump will make sure we don't hit a mob multiple times return diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index e045d8dc877b..d7ee296a8f14 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -3,15 +3,18 @@ icon_state = "ion" fire_sound = 'sound/weapons/Laser.ogg' damage = 0 - damage_type = BURN + atom_damage_type = BURN damage_flags = 0 nodamage = 1 + impact_effect_type = /obj/effect/temp_visual/impact_effect/ion + hitsound_non_mob = 'sound/weapons/searwall.ogg' + hitsound = 'sound/weapons/ionrifle.ogg' var/heavy_effect_range = 1 var/light_effect_range = 2 - on_impact(var/atom/A) - empulse(A, heavy_effect_range, light_effect_range) - return 1 +/obj/item/projectile/ion/on_impact(var/atom/A) + empulse(A, heavy_effect_range, light_effect_range) + return 1 /obj/item/projectile/ion/small name = "ion pulse" @@ -27,125 +30,132 @@ icon_state= "bolter" damage = 50 damage_flags = DAM_BULLET | DAM_SHARP | DAM_EDGE - - on_hit(var/atom/target, var/blocked = 0) - explosion(target, -1, 0, 2) - return 1 + var/gyro_devastation = -1 + var/gyro_heavy_impact = 0 + var/gyro_light_impact = 2 + +/obj/item/projectile/bullet/gyro/on_hit(var/atom/target, var/blocked = 0) + target = get_turf(target) + if(istype(target)) + explosion(target, gyro_devastation, gyro_heavy_impact, gyro_light_impact) + return 1 + +/obj/item/projectile/bullet/gyro/microrocket + name = "microrocket" + distance_falloff = 1.3 + fire_sound = 'sound/effects/Explosion1.ogg' + gyro_light_impact = 1 /obj/item/projectile/temp name = "freeze beam" icon_state = "ice_2" fire_sound = 'sound/weapons/pulse3.ogg' damage = 0 - damage_type = BURN + atom_damage_type = BURN damage_flags = 0 nodamage = 1 + impact_effect_type = /obj/effect/temp_visual/impact_effect/monochrome_laser var/firing_temperature = 300 - on_hit(var/atom/target, var/blocked = 0)//These two could likely check temp protection on the mob - if(istype(target, /mob/living)) - var/mob/M = target - M.bodytemperature = firing_temperature - return 1 +/obj/item/projectile/temp/on_hit(var/atom/target, var/blocked = 0)//These two could likely check temp protection on the mob + if(isliving(target)) + var/mob/M = target + M.bodytemperature = firing_temperature + return 1 /obj/item/projectile/meteor name = "meteor" icon = 'icons/obj/meteor.dmi' icon_state = "smallf" damage = 0 - damage_type = BRUTE + atom_damage_type = BRUTE nodamage = 1 - Bump(atom/A as mob|obj|turf|area, forced=0) - if(A == firer) - forceMove(A.loc) - return - - sleep(-1) //Might not be important enough for a sleep(-1) but the sleep/spawn itself is necessary thanks to explosions and metoerhits - - if(src)//Do not add to this if() statement, otherwise the meteor won't delete them - if(A) - - A.explosion_act(2) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) - - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai))\ - shake_camera(M, 3, 1) - qdel(src) - return 1 - else - return 0 +/obj/item/projectile/meteor/Bump(var/atom/A, forced=0) + if(!istype(A)) + return + if(A == firer) + forceMove(A.loc) + return + A.explosion_act(2) + playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) + for(var/mob/M in range(10, src)) + if(!M.stat && !isAI(M)) + shake_camera(M, 3, 1) + qdel(src) + return TRUE /obj/item/projectile/energy/floramut name = "alpha somatoray" icon_state = "energy" fire_sound = 'sound/effects/stealthoff.ogg' damage = 0 - damage_type = TOX + atom_damage_type = TOX nodamage = 1 - - on_hit(var/atom/target, var/blocked = 0) - var/mob/living/M = target - if(ishuman(target)) - var/mob/living/carbon/human/H = M - if((H.species.species_flags & SPECIES_FLAG_IS_PLANT) && (H.nutrition < 500)) - if(prob(15)) - H.apply_damage((rand(30,80)),IRRADIATE, damage_flags = DAM_DISPERSED) - H.Weaken(5) - for (var/mob/V in viewers(src)) - V.show_message("[M] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) - if(prob(35)) - if(prob(80)) - randmutb(M) - domutcheck(M,null) - else - randmutg(M) - domutcheck(M,null) + impact_effect_type = /obj/effect/temp_visual/impact_effect/monochrome_laser + +/obj/item/projectile/energy/floramut/on_hit(var/atom/target, var/blocked = 0) + if(!isliving(target)) + return + + var/mob/living/M = target + if(M.get_species()?.species_flags & SPECIES_FLAG_IS_PLANT) + if(M.get_nutrition() < 500) + if(prob(15)) + M.apply_damage((rand(30,80)),IRRADIATE, damage_flags = DAM_DISPERSED) + SET_STATUS_MAX(M, STAT_WEAK, 5) + var/decl/pronouns/pronouns = M.get_pronouns() + visible_message( + SPAN_DANGER("\The [M] writhes in pain as [pronouns.his] vacuoles boil."), + blind_message = SPAN_WARNING("You hear a crunching sound.") + ) + if(prob(35)) + if(prob(80)) + M.add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/disability))) else - M.adjustFireLoss(rand(5,15)) - M.show_message("The radiation beam singes you!") - else if(istype(target, /mob/living/carbon/)) - M.show_message("The radiation beam dissipates harmlessly through your body.") + M.add_genetic_condition(pick(decls_repository.get_decls_of_type(/decl/genetic_condition/superpower))) else - return 1 + M.heal_damage(BURN, rand(5,15)) + M.show_message(SPAN_DANGER("The radiation beam singes you!")) + else + M.show_message(SPAN_NOTICE("The radiation beam dissipates harmlessly through your body.")) /obj/item/projectile/energy/floramut/gene name = "gamma somatoray" icon_state = "energy2" fire_sound = 'sound/effects/stealthoff.ogg' damage = 0 - damage_type = TOX + atom_damage_type = TOX nodamage = 1 - var/decl/plantgene/gene = null + var/decl/plant_gene/gene = null /obj/item/projectile/energy/florayield name = "beta somatoray" icon_state = "energy2" fire_sound = 'sound/effects/stealthoff.ogg' damage = 0 - damage_type = TOX + atom_damage_type = TOX nodamage = 1 - - on_hit(var/atom/target, var/blocked = 0) - var/mob/M = target - if(ishuman(target)) //These rays make plantmen fat. - var/mob/living/carbon/human/H = M - if((H.species.species_flags & SPECIES_FLAG_IS_PLANT) && (H.nutrition < 500)) - H.adjust_nutrition(30) - else if (istype(target, /mob/living/carbon/)) - M.show_message("The radiation beam dissipates harmlessly through your body.") - else - return 1 + impact_effect_type = /obj/effect/temp_visual/impact_effect/monochrome_laser + +/obj/item/projectile/energy/florayield/on_hit(var/atom/target, var/blocked = 0) + if(!isliving(target)) + return + var/mob/living/M = target + if(M.get_species()?.species_flags & SPECIES_FLAG_IS_PLANT) + if(M.get_nutrition() < 500) + M.adjust_nutrition(30) + else + M.show_message(SPAN_NOTICE("The radiation beam dissipates harmlessly through your body.")) /obj/item/projectile/beam/mindflayer name = "flayer ray" - on_hit(var/atom/target, var/blocked = 0) - if(ishuman(target)) - var/mob/living/carbon/human/M = target - M.confused += rand(5,8) +/obj/item/projectile/beam/mindflayer/on_hit(var/atom/target, var/blocked = 0) + if(ishuman(target)) + var/mob/living/human/M = target + ADJ_STATUS(M, STAT_CONFUSE, rand(5,8)) /obj/item/projectile/chameleon name = "bullet" @@ -153,41 +163,46 @@ damage = 1 // stop trying to murderbone with a fake gun dumbass!!! embed = 0 // nope nodamage = 1 - damage_type = PAIN + atom_damage_type = PAIN damage_flags = 0 - muzzle_type = /obj/effect/projectile/bullet/muzzle + muzzle_type = /obj/effect/projectile/muzzle/bullet /obj/item/projectile/venom name = "venom bolt" icon_state = "venom" damage = 5 //most damage is in the reagent - damage_type = TOX + atom_damage_type = TOX damage_flags = 0 /obj/item/projectile/venom/on_hit(atom/target, blocked, def_zone) . = ..() var/mob/living/L = target if(L.reagents) - L.reagents.add_reagent(/decl/material/liquid/venom, 5) + L.add_to_reagents(/decl/material/liquid/venom, 5) /obj/item/missile - icon = 'icons/obj/grenade.dmi' - icon_state = "missile" + icon = 'icons/obj/items/grenades/missile.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/fiberglass + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE, + /decl/material/liquid/anfo = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/liquid/fuel = MATTER_AMOUNT_REINFORCEMENT, + ) var/primed = null - throwforce = 15 /obj/item/missile/throw_impact(atom/hit_atom) + ..() if(primed) explosion(hit_atom, 0, 1, 2, 4) qdel(src) - else - ..() - return /obj/item/projectile/hotgas name = "gas vent" icon_state = null - damage_type = BURN + atom_damage_type = BURN damage_flags = 0 life_span = 3 silenced = TRUE @@ -197,5 +212,5 @@ if(isliving(target)) var/mob/living/L = target to_chat(target, SPAN_WARNING("You feel a wave of heat wash over you!")) - L.adjust_fire_stacks(rand(5,8)) - L.IgniteMob() \ No newline at end of file + L.adjust_fire_intensity(rand(5,8)) + L.ignite_fire() \ No newline at end of file diff --git a/code/modules/projectiles/projectile/trace.dm b/code/modules/projectiles/projectile/trace.dm new file mode 100644 index 000000000000..6abad14dbe3d --- /dev/null +++ b/code/modules/projectiles/projectile/trace.dm @@ -0,0 +1,36 @@ +//Helper proc to check if you can hit them or not. +/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, pass_flags=PASS_FLAG_TABLE|PASS_FLAG_GLASS|PASS_FLAG_GRILLE, lifespan = null) + if(!istype(target) || !istype(firer)) + return 0 + + var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test.... + + //Set the flags and pass flags to that of the real projectile... + trace.pass_flags = pass_flags + if(lifespan) + trace.life_span = lifespan + + return trace.launch(target) //Test it! + +//"Tracing" projectile +/obj/item/projectile/test //Used to see if you can hit them. + invisibility = INVISIBILITY_ABSTRACT + hitscan = TRUE + nodamage = TRUE + damage = 0 + var/list/hit = list() + +/obj/item/projectile/test/process_hitscan() + . = ..() + if(!QDELING(src)) + qdel(src) + return hit + +/obj/item/projectile/test/Bump(atom/A, forced = FALSE) + if(A != src) + hit |= A + return ..() + +/obj/item/projectile/test/attack_mob() + SHOULD_CALL_PARENT(FALSE) + return diff --git a/code/modules/projectiles/secure.dm b/code/modules/projectiles/secure.dm index 224819b6b2c2..88fd79c91ef1 100644 --- a/code/modules/projectiles/secure.dm +++ b/code/modules/projectiles/secure.dm @@ -11,34 +11,36 @@ for(var/i = authorized_modes.len + 1 to firemodes.len) authorized_modes.Add(default_mode_authorization) - + set_extension(src, /datum/extension/network_device/lazy) verbs |= /obj/item/gun/proc/network_setup . = ..() /obj/item/gun/Destroy() - GLOB.registered_weapons -= src + global.registered_weapons -= src . = ..() -/obj/item/gun/examine(mob/user, distance) +/obj/item/gun/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(distance <= 0 && is_secure_gun()) - to_chat(user, "The registration screen shows, \"" + (registered_owner ? "[registered_owner]" : "unregistered") + "\"") + . += "The registration screen shows, \"" + (registered_owner ? "[registered_owner]" : "unregistered") + "\"." -/obj/item/gun/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/card/id) && is_secure_gun()) +/obj/item/gun/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/card/id) && is_secure_gun()) user.visible_message("[user] swipes an ID through \the [src].", range = 3) if(!registered_owner) - var/obj/item/card/id/id = W - GLOB.registered_weapons += src + var/obj/item/card/id/id = used_item + global.registered_weapons += src verbs += /obj/item/gun/proc/reset_registration registered_owner = id.registered_name to_chat(user, SPAN_NOTICE("\The [src] chimes quietly as it registers to \"[registered_owner]\".")) + return TRUE else to_chat(user, SPAN_NOTICE("\The [src] buzzes quietly, refusing to register without first being reset.")) + return TRUE else - ..() + return ..() /obj/item/gun/emag_act(var/charges, var/mob/user) if(!charges) @@ -46,7 +48,7 @@ if(is_secure_gun()) registered_owner = null - GLOB.registered_weapons -= src + global.registered_weapons -= src verbs -= /obj/item/gun/proc/reset_registration req_access.Cut() to_chat(user, SPAN_NOTICE("\The [src]'s authorization chip fries, giving you full access.")) @@ -71,7 +73,7 @@ to_chat(usr, SPAN_NOTICE("\The [src] chimes quietly as its registration resets.")) registered_owner = null - GLOB.registered_weapons -= src + global.registered_weapons -= src verbs -= /obj/item/gun/proc/reset_registration @@ -84,7 +86,7 @@ if(mode == sel_mode && !authorized) switch_firemodes() - var/mob/user = get_holder_of_type(src, /mob) + var/mob/user = get_recursive_loc_of_type(/mob) if(user) to_chat(user, SPAN_NOTICE("Your [src.name] has been [authorized ? "granted" : "denied"] [firemodes[mode]] fire authorization by [by].")) @@ -94,17 +96,9 @@ return length(req_access) /obj/item/gun/proc/free_fire() - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) return security_state.current_security_level_is_same_or_higher_than(security_state.high_security_level) -/obj/item/gun/special_check() - if(is_secure_gun() && !free_fire() && (!authorized_modes[sel_mode] || !registered_owner)) - audible_message(SPAN_WARNING("\The [src] buzzes, refusing to fire."), hearing_distance = 3) - playsound(loc, 'sound/machines/buzz-sigh.ogg', 10, 0) - return 0 - - . = ..() - /obj/item/gun/get_next_firemode() if(!is_secure_gun()) return ..() diff --git a/code/modules/projectiles/targeting/targeting_client.dm b/code/modules/projectiles/targeting/targeting_client.dm deleted file mode 100644 index eeaf61909deb..000000000000 --- a/code/modules/projectiles/targeting/targeting_client.dm +++ /dev/null @@ -1,12 +0,0 @@ -//These are called by the on-screen buttons, adjusting what the victim can and cannot do. -/client/proc/add_gun_icons() - if(!usr || !usr.item_use_icon) return 1 // This can runtime if someone manages to throw a gun out of their hand before the proc is called. - screen |= usr.item_use_icon - screen |= usr.gun_move_icon - screen |= usr.radio_use_icon - -/client/proc/remove_gun_icons() - if(!usr) return 1 // Runtime prevention on N00k agents spawning with SMG - screen -= usr.item_use_icon - screen -= usr.gun_move_icon - screen -= usr.radio_use_icon diff --git a/code/modules/projectiles/targeting/targeting_gun.dm b/code/modules/projectiles/targeting/targeting_gun.dm index a443d5d34e20..061c7bf404de 100644 --- a/code/modules/projectiles/targeting/targeting_gun.dm +++ b/code/modules/projectiles/targeting/targeting_gun.dm @@ -5,17 +5,11 @@ return ..() /obj/item/gun/equipped(var/mob/living/user, var/slot) - if(istype(user) && (slot != slot_l_hand && slot != slot_r_hand)) + if(istype(user) && !(slot in user.get_held_item_slots())) user.stop_aiming(src) return ..() //Compute how to fire..... //Return 1 if a target was found, 0 otherwise. /obj/item/gun/proc/PreFire(var/atom/A, var/mob/living/user, var/params) - if(!user.aiming) - user.aiming = new(user) - user.face_atom(A) - if(ismob(A) && user.aiming) - user.aiming.aim_at(A, src) - return 1 - return 0 \ No newline at end of file + return istype(user) && user.aim_at(A, src) diff --git a/code/modules/projectiles/targeting/targeting_mob.dm b/code/modules/projectiles/targeting/targeting_mob.dm index 908adafd377f..9dd3234cd92d 100644 --- a/code/modules/projectiles/targeting/targeting_mob.dm +++ b/code/modules/projectiles/targeting/targeting_mob.dm @@ -1,5 +1,6 @@ -/mob/living/var/obj/aiming_overlay/aiming -/mob/living/var/list/aimed = list() +/mob/living + var/obj/aiming_overlay/aiming + var/list/aimed_at_by /mob/verb/toggle_gun_mode() set name = "Toggle Gun Mode" @@ -21,25 +22,3 @@ if(thing && aiming.aiming_with != thing) return aiming.cancel_aiming(no_message) - -/mob/living/death(gibbed, deathmessage="seizes up and falls limp...", show_dead_message) - . = ..(gibbed, deathmessage, show_dead_message) - if(.) - stop_aiming(no_message=1) - -/mob/living/UpdateLyingBuckledAndVerbStatus() - ..() - if(lying) - stop_aiming(no_message=1) - -/mob/living/Weaken(amount) - stop_aiming(no_message=1) - ..() - -/mob/living/Destroy() - if(aiming) - qdel(aiming) - aiming = null - aimed.Cut() - return ..() - diff --git a/code/modules/projectiles/targeting/targeting_overlay.dm b/code/modules/projectiles/targeting/targeting_overlay.dm index 08bfd1329ae1..c0bb7ce8a7bf 100644 --- a/code/modules/projectiles/targeting/targeting_overlay.dm +++ b/code/modules/projectiles/targeting/targeting_overlay.dm @@ -3,12 +3,12 @@ desc = "Stick 'em up!" icon = 'icons/effects/Targeted.dmi' icon_state = "locking" - anchored = 1 - density = 0 - opacity = 0 + anchored = TRUE + density = FALSE + opacity = FALSE layer = ABOVE_HUMAN_LAYER simulated = 0 - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE var/mob/living/aiming_at // Who are we currently targeting, if anyone? var/obj/item/aiming_with // What are we targeting with? @@ -21,7 +21,7 @@ /obj/aiming_overlay/Initialize() . = ..() owner = loc - loc = null + forceMove(null) verbs.Cut() /obj/aiming_overlay/proc/toggle_permission(var/perm) @@ -32,29 +32,8 @@ target_permissions |= perm // Update HUD icons. - if(owner.gun_move_icon) - if(!(target_permissions & TARGET_CAN_MOVE)) - owner.gun_move_icon.icon_state = "no_walk0" - owner.gun_move_icon.SetName("Allow Movement") - else - owner.gun_move_icon.icon_state = "no_walk1" - owner.gun_move_icon.SetName("Disallow Movement") - - if(owner.item_use_icon) - if(!(target_permissions & TARGET_CAN_CLICK)) - owner.item_use_icon.icon_state = "no_item0" - owner.item_use_icon.SetName("Allow Item Use") - else - owner.item_use_icon.icon_state = "no_item1" - owner.item_use_icon.SetName("Disallow Item Use") - - if(owner.radio_use_icon) - if(!(target_permissions & TARGET_CAN_RADIO)) - owner.radio_use_icon.icon_state = "no_radio0" - owner.radio_use_icon.SetName("Allow Radio Use") - else - owner.radio_use_icon.icon_state = "no_radio1" - owner.radio_use_icon.SetName("Disallow Radio Use") + if(istype(owner?.hud_used, /datum/hud)) + owner.hud_used.update_gun_mode_icons(target_permissions) var/message = "no longer permitted to " var/use_span = "warning" @@ -88,7 +67,7 @@ owner = null return ..() -obj/aiming_overlay/proc/update_aiming_deferred() +/obj/aiming_overlay/proc/update_aiming_deferred() set waitfor = 0 sleep(0) update_aiming() @@ -109,18 +88,18 @@ obj/aiming_overlay/proc/update_aiming_deferred() var/cancel_aim = 1 - if(!(aiming_with in owner) || (istype(owner, /mob/living/carbon/human) && (owner.l_hand != aiming_with && owner.r_hand != aiming_with))) - to_chat(owner, "You must keep hold of your weapon!") - else if(owner.eye_blind) - to_chat(owner, "You are blind and cannot see your target!") - else if(!aiming_at || !istype(aiming_at.loc, /turf)) - to_chat(owner, "You have lost sight of your target!") - else if(owner.incapacitated() || owner.lying || owner.restrained()) - to_chat(owner, "You must be conscious and standing to keep track of your target!") + if(!(aiming_with in owner) || (ishuman(owner) && !(aiming_with in owner.get_held_items()))) + to_chat(owner, SPAN_WARNING("You must keep hold of your weapon!")) + else if(GET_STATUS(owner, STAT_BLIND)) + to_chat(owner, SPAN_WARNING("You are blind and cannot see your target!")) + else if(!aiming_at || !isturf(aiming_at.loc)) + to_chat(owner, SPAN_WARNING("You have lost sight of your target!")) + else if(owner.incapacitated() || owner.current_posture.prone || owner.restrained()) + to_chat(owner, SPAN_WARNING("You must be conscious and standing to keep track of your target!")) else if(aiming_at.is_invisible_to(owner)) - to_chat(owner, "Your target has become invisible!") + to_chat(owner, SPAN_WARNING("Your target has become invisible!")) else if(!(aiming_at in view(owner))) - to_chat(owner, "Your target is too far away to track!") + to_chat(owner, SPAN_WARNING("Your target is too far away to track!")) else cancel_aim = 0 @@ -140,26 +119,28 @@ obj/aiming_overlay/proc/update_aiming_deferred() return if(owner.incapacitated()) - to_chat(owner, "You cannot aim a gun in your current state.") + to_chat(owner, SPAN_WARNING("You cannot You cannot threaten \the [target] with \the [thing] in your current state.")) return - if(owner.lying) - to_chat(owner, "You cannot aim a gun while prone.") + if(owner.current_posture.prone) + to_chat(owner, SPAN_WARNING("You cannot threaten \the [target] with \the [thing] while prone.")) return if(owner.restrained()) - to_chat(owner, "You cannot aim a gun while handcuffed.") + to_chat(owner, SPAN_WARNING("You cannot threaten \the [target] with \the [thing] while handcuffed.")) return if(aiming_at) if(aiming_at == target) return cancel_aiming(1) - owner.visible_message("\The [owner] turns \the [thing] on \the [target]!") + owner.visible_message(SPAN_DANGER("\The [owner] turns \the [thing] on \the [target]!")) else - owner.visible_message("\The [owner] aims \the [thing] at \the [target]!") + owner.visible_message(SPAN_DANGER("\The [owner] aims \the [thing] at \the [target]!")) - if(owner.client) - owner.client.add_gun_icons() - to_chat(target, "You now have a gun pointed at you. No sudden moves!") + if(istype(owner.hud_used) && owner.client) + owner.hud_used.add_gun_icons() + + var/decl/pronouns/pronouns = owner.get_pronouns() + to_chat(target, FONT_LARGE(SPAN_DANGER("\The [owner] [pronouns.is] menacing you with \a [thing]. No sudden moves!"))) aiming_with = thing aiming_at = target if(istype(aiming_with, /obj/item/gun)) @@ -169,14 +150,15 @@ obj/aiming_overlay/proc/update_aiming_deferred() forceMove(get_turf(target)) START_PROCESSING(SSobj, src) - aiming_at.aimed |= src + LAZYDISTINCTADD(aiming_at.aimed_at_by, src) toggle_active(1) locked = 0 + update_icon() lock_time = world.time + 35 - GLOB.moved_event.register(owner, src, /obj/aiming_overlay/proc/update_aiming) - GLOB.moved_event.register(aiming_at, src, /obj/aiming_overlay/proc/target_moved) - GLOB.destroyed_event.register(aiming_at, src, /obj/aiming_overlay/proc/cancel_aiming) + events_repository.register(/decl/observ/moved, owner, src, TYPE_PROC_REF(/obj/aiming_overlay, update_aiming)) + events_repository.register(/decl/observ/moved, aiming_at, src, TYPE_PROC_REF(/obj/aiming_overlay, target_moved)) + events_repository.register(/decl/observ/destroyed, aiming_at, src, TYPE_PROC_REF(/obj/aiming_overlay, cancel_aiming)) /obj/aiming_overlay/on_update_icon() if(locked) @@ -184,7 +166,7 @@ obj/aiming_overlay/proc/update_aiming_deferred() else icon_state = "locking" -/obj/aiming_overlay/proc/toggle_active(var/force_state = null) +/obj/aiming_overlay/proc/toggle_active(var/force_state = null, var/no_message = FALSE) if(!isnull(force_state)) if(active == force_state) return @@ -193,35 +175,36 @@ obj/aiming_overlay/proc/update_aiming_deferred() active = !active if(!active) - cancel_aiming() + cancel_aiming(no_message) - if(owner.client) + if(owner.client && istype(owner.hud_used)) if(active) - to_chat(owner, "You will now aim rather than fire.") - owner.client.add_gun_icons() + if(!no_message) + to_chat(owner, "You will now aim rather than fire.") + owner.hud_used.add_gun_icons() else - to_chat(owner, "You will no longer aim rather than fire.") - owner.client.remove_gun_icons() - owner.gun_setting_icon.icon_state = "gun[active]" + if(!no_message) + to_chat(owner, "You will no longer aim rather than fire.") + owner.hud_used.remove_gun_icons() /obj/aiming_overlay/proc/cancel_aiming(var/no_message = 0) if(!aiming_with || !aiming_at) return - if(istype(aiming_with, /obj/item/gun)) - sound_to(aiming_at, sound('sound/weapons/TargetOff.ogg')) - sound_to(owner, sound('sound/weapons/TargetOff.ogg')) if(!no_message) owner.visible_message("\The [owner] lowers \the [aiming_with].") + if(istype(aiming_with, /obj/item/gun)) + sound_to(aiming_at, sound('sound/weapons/TargetOff.ogg')) + sound_to(owner, sound('sound/weapons/TargetOff.ogg')) - GLOB.moved_event.unregister(owner, src) + events_repository.unregister(/decl/observ/moved, owner, src) if(aiming_at) - GLOB.moved_event.unregister(aiming_at, src) - GLOB.destroyed_event.unregister(aiming_at, src) - aiming_at.aimed -= src + events_repository.unregister(/decl/observ/moved, aiming_at, src) + events_repository.unregister(/decl/observ/destroyed, aiming_at, src) + LAZYREMOVE(aiming_at.aimed_at_by, src) aiming_at = null aiming_with = null - loc = null + forceMove(null) STOP_PROCESSING(SSobj, src) /obj/aiming_overlay/proc/target_moved() diff --git a/code/modules/projectiles/targeting/targeting_triggers.dm b/code/modules/projectiles/targeting/targeting_triggers.dm index bfb87ce142b4..d318f1f32755 100644 --- a/code/modules/projectiles/targeting/targeting_triggers.dm +++ b/code/modules/projectiles/targeting/targeting_triggers.dm @@ -3,28 +3,27 @@ return /mob/living/trigger_aiming(var/trigger_type) - if(!aimed.len) - return - for(var/obj/aiming_overlay/AO in aimed) + for(var/obj/aiming_overlay/AO as anything in aimed_at_by) if(AO.aiming_at == src) AO.update_aiming() if(AO.aiming_at == src) AO.trigger(trigger_type) AO.update_aiming_deferred() +/mob/living/proc/aim_at(var/atom/target, var/obj/item/with) + if(!ismob(target) || !istype(with) || incapacitated()) + return FALSE + if(!aiming) + aiming = new(src) + face_atom(target) + aiming.aim_at(target, with) + return TRUE + /obj/aiming_overlay/proc/trigger(var/perm) if(!owner || !aiming_with || !aiming_at || !locked) - return + return FALSE if(perm && (target_permissions & perm)) - return + return FALSE if(!owner.canClick()) - return - if(prob(owner.skill_fail_chance(SKILL_WEAPONS, 30, SKILL_ADEPT, 3))) - to_chat(owner, "You fumble with the gun, throwing your aim off!") - owner.stop_aiming(aiming_with) - return - owner.setClickCooldown(DEFAULT_QUICK_COOLDOWN) // Spam prevention, essentially. - owner.visible_message("\The [owner] pulls the trigger reflexively!") - var/obj/item/gun/G = aiming_with - if(istype(G)) - G.Fire(aiming_at, owner) + return FALSE + return aiming_with.handle_reflexive_fire(owner, aiming_at) diff --git a/code/modules/prometheus_metrics/_defines.dm b/code/modules/prometheus_metrics/_defines.dm deleted file mode 100644 index f810234d08f1..000000000000 --- a/code/modules/prometheus_metrics/_defines.dm +++ /dev/null @@ -1,5 +0,0 @@ -#define PROMETHEUS_METRIC_COUNTER 0 -#define PROMETHEUS_METRIC_GAUGE 1 - -GLOBAL_LIST_INIT(prometheus_metric_names, list("counter", "gauge")) -#define PROMETHEUS_METRIC_NAME(m) GLOB.prometheus_metric_names[m + 1] diff --git a/code/modules/prometheus_metrics/metrics.dm b/code/modules/prometheus_metrics/metrics.dm deleted file mode 100644 index a1e8b44ddde3..000000000000 --- a/code/modules/prometheus_metrics/metrics.dm +++ /dev/null @@ -1,24 +0,0 @@ -GLOBAL_DATUM_INIT(prometheus_metrics, /datum/prometheus_metrics, new) - -// prometheus_metrics holds a list of metric_family datums and uses them to -// create a json protobuf. -/datum/prometheus_metrics - var/list/metric_families - -/datum/prometheus_metrics/New() - metric_families = list() - for(var/T in typesof(/datum/metric_family) - /datum/metric_family) - var/datum/metric_family/mf = T - if(initial(mf.name) == null || initial(mf.metric_type) == null) - continue - metric_families += new T - -/datum/prometheus_metrics/proc/collect() - var/list/out = list() - - for(var/datum/metric_family/MF in metric_families) - var/proto = MF._to_proto() - if(proto != null) - out[++out.len] = MF._to_proto() - - return json_encode(out) diff --git a/code/modules/prometheus_metrics/metrics/byond.dm b/code/modules/prometheus_metrics/metrics/byond.dm deleted file mode 100644 index 232bce38fafe..000000000000 --- a/code/modules/prometheus_metrics/metrics/byond.dm +++ /dev/null @@ -1,40 +0,0 @@ -// byond-specific metrics - -/datum/metric_family/byond_time - name = "byond_world_time_seconds" - metric_type = PROMETHEUS_METRIC_COUNTER - help = "Counter of 'game-time' seconds since server startup" - -/datum/metric_family/byond_time/collect() - return list(list(null, world.time / 10)) - - -/datum/metric_family/byond_tick_lag - name = "byond_tick_lag" - metric_type = PROMETHEUS_METRIC_GAUGE - help = "Current value of world.tick_lag" - -/datum/metric_family/byond_tick_lag/collect() - return list(list(null, world.tick_lag)) - - -/datum/metric_family/byond_players - name = "byond_players" - metric_type = PROMETHEUS_METRIC_GAUGE - help = "Number of players currently connected to the server" - -/datum/metric_family/byond_players/collect() - var/c = 0 - for(var/client/C) - if(C.connection == "seeker" || C.connection == "web") - c++ - return list(list(null, c)) - - -/datum/metric_family/byond_cpu - name = "byond_cpu" - metric_type = PROMETHEUS_METRIC_GAUGE - help = "Current value of world.cpu" - -/datum/metric_family/byond_cpu/collect() - return list(list(null, world.cpu)) diff --git a/code/modules/prometheus_metrics/metrics/ss13.dm b/code/modules/prometheus_metrics/metrics/ss13.dm deleted file mode 100644 index 5c6d315b04d0..000000000000 --- a/code/modules/prometheus_metrics/metrics/ss13.dm +++ /dev/null @@ -1,71 +0,0 @@ -// ss13-specific metrics - -/datum/metric_family/ss13_controller_time_seconds - name = "ss13_controller_time_seconds" - metric_type = PROMETHEUS_METRIC_COUNTER - help = "Counter of time spent in a controller in seconds" - -/datum/metric_family/ss13_controller_time_seconds/collect() - var/list/out = list() - if(Master) - for(var/name in Master.total_run_times) - out[++out.len] = list(list("type" = "subsystem", "name" = name), Master.total_run_times[name]) - - return out - - -/datum/metric_family/ss13_master_runlevel - name = "ss13_master_runlevel" - metric_type = PROMETHEUS_METRIC_GAUGE - help = "Current MC runlevel" - -/datum/metric_family/ss13_master_runlevel/collect() - if(Master) - return list(list(null, Master.current_runlevel)) - return list() - - -/datum/metric_family/ss13_garbage_queue_length - name = "ss13_garbage_queue_length" - metric_type = PROMETHEUS_METRIC_GAUGE - help = "Length of SSgarbage queues" - -/datum/metric_family/ss13_garbage_queue_length/collect() - var/list/out = list() - - if(SSgarbage) - for(var/i = 1 to GC_QUEUE_COUNT) - out[++out.len] = list(list("queue" = "[i]"), length(SSgarbage.queues[i])) - - return out - - -/datum/metric_family/ss13_garbage_queue_results - name = "ss13_garbage_queue_results" - metric_type = PROMETHEUS_METRIC_COUNTER - help = "Counter of pass/fail results for SSgarbage queues" - -/datum/metric_family/ss13_garbage_queue_results/collect() - var/list/out = list() - - if(SSgarbage) - for(var/i = 1 to GC_QUEUE_COUNT) - out[++out.len] = list(list("queue" = "[i]", "result" = "pass"), SSgarbage.pass_counts[i]) - out[++out.len] = list(list("queue" = "[i]", "result" = "fail"), SSgarbage.fail_counts[i]) - - return out - - -/datum/metric_family/ss13_garbage_total_cleaned - name = "ss13_garbage_total_cleaned" - metric_type = PROMETHEUS_METRIC_COUNTER - help = "Counter for number of objects deleted/GCed by SSgarbage" - -/datum/metric_family/ss13_garbage_total_cleaned/collect() - var/list/out = list() - - if(SSgarbage) - out[++out.len] = list(list("type" = "gc"), SSgarbage.totalgcs) - out[++out.len] = list(list("type" = "del"), SSgarbage.totaldels) - - return out diff --git a/code/modules/pronouns/_pronouns.dm b/code/modules/pronouns/_pronouns.dm new file mode 100644 index 000000000000..174e9edb8c03 --- /dev/null +++ b/code/modules/pronouns/_pronouns.dm @@ -0,0 +1,100 @@ +/decl/pronouns + uid = "pronouns_plural" + decl_flags = DECL_FLAG_MANDATORY_UID + var/name = PLURAL + var/bureaucratic_term = "others" + var/informal_term = "hoopy froods" + var/honorific = "Mxes." + var/pronoun_string + + var/He = "They" + var/he = "they" + var/His = "Their" + var/his = "their" + var/him = "them" + var/has = "have" + var/is = "are" + var/does = "do" + var/self = "themselves" + var/s = "" + var/es = "" + /// Never inflect verbs with this pronoun set, for both nouns ("The bats spin around.") and pronouns ("They spin around.") + var/const/PLURALIZE_NONE = 0 + /// Inflect only verbs after nouns ("Unknown (as David Hasselhoff) spins around.") but not after pronouns ("They spin around.") + var/const/PLURALIZE_PSEUDO = 1 + /// Inflect verbs after both nouns and pronouns, e.g. "David Hasselhoff spins around." and "He spins around." + var/const/PLURALIZE_ALL = 2 + /// When should we give verbs plural inflections? Valid values: PLURALIZE_NONE, PLURALIZE_PSEUDO, PLURALIZE_ALL. + var/pluralize_verb = PLURALIZE_NONE + +/decl/pronouns/Initialize() + pronoun_string = "[He]/[him]/[his]" + . = ..() + +// I regret having to refactor this, but someone put it in unarmed attacks and here we are. +/decl/pronouns/proc/get_message_for_being_kicked_in_the_dick() + return "Oh god, that hurt!" + +/proc/get_pronouns_by_gender(var/gender) + switch(gender) + if(PLURAL) + . = /decl/pronouns + if(MALE) + . = /decl/pronouns/male + if(FEMALE) + . = /decl/pronouns/female + if(NEUTER) + . = /decl/pronouns/neuter + else + gender = lowertext(gender) + var/list/all_genders = decls_repository.get_decls_of_type(/decl/pronouns) + for(var/g in all_genders) + var/decl/pronouns/pronouns = all_genders[g] + if(lowertext(pronouns.name) == gender) + . = g + break + . = GET_DECL(.) || GET_DECL(/decl/pronouns) + +// Atom helpers. +/atom/proc/get_pronouns(var/ignore_coverings) + RETURN_TYPE(/decl/pronouns) + . = get_pronouns_by_gender(gender) + +var/global/list/byond_genders = list(MALE, FEMALE, NEUTER, PLURAL) +/atom/proc/set_gender(var/new_gender = NEUTER, var/update_body = FALSE) + if(gender != new_gender) + if(new_gender in global.byond_genders) + gender = new_gender + else + gender = NEUTER + if(update_body) + update_icon() + return TRUE + return FALSE + +// Living mob helpers. +/mob/living + var/pronoun_gender + var/decl/pronouns/pronouns + +/mob/living/get_gender() + if(!pronoun_gender) + pronoun_gender = gender + return pronoun_gender + +/mob/living/set_gender(var/new_gender, var/update_body = FALSE) + . = ..() + if(.) + pronoun_gender = new_gender + pronouns = null + +/mob/living/get_pronouns(var/ignore_coverings) + RETURN_TYPE(/decl/pronouns) + if(!ignore_coverings) + var/obj/item/suit = get_equipped_item(slot_wear_suit_str) + var/obj/item/head = get_equipped_item(slot_head_str) + if(suit && (suit.flags_inv & HIDEJUMPSUIT) && ((head && head.flags_inv & HIDEMASK) || get_equipped_item(slot_wear_mask_str))) + return GET_DECL(/decl/pronouns/pseudoplural) + if(!pronouns) + pronouns = get_pronouns_by_gender(get_gender()) + return pronouns || GET_DECL(/decl/pronouns/pseudoplural) diff --git a/code/modules/pronouns/pronouns_female.dm b/code/modules/pronouns/pronouns_female.dm new file mode 100644 index 000000000000..5127c3742b4d --- /dev/null +++ b/code/modules/pronouns/pronouns_female.dm @@ -0,0 +1,19 @@ +/decl/pronouns/female + uid = "pronouns_female" + name = FEMALE + bureaucratic_term = "female" + informal_term = "lady" + honorific = "Ms." + + He = "She" + he = "she" + His = "Her" + his = "her" + him = "her" + has = "has" + is = "is" + does = "does" + self = "herself" + s = "s" + es = "es" + pluralize_verb = PLURALIZE_ALL diff --git a/code/modules/pronouns/pronouns_male.dm b/code/modules/pronouns/pronouns_male.dm new file mode 100644 index 000000000000..ef1a15d413c2 --- /dev/null +++ b/code/modules/pronouns/pronouns_male.dm @@ -0,0 +1,39 @@ +/decl/pronouns/male + name = MALE + uid = "pronouns_male" + bureaucratic_term = "male" + informal_term = "guy" + honorific = "Mr." + + He = "He" + he = "he" + His = "His" + his = "his" + him = "him" + has = "has" + is = "is" + does = "does" + self = "himself" + s = "s" + es = "es" + pluralize_verb = PLURALIZE_ALL + + // Thanks oldcoders. + var/static/list/weird_euphemisms_for_your_balls = list( + "testicles", + "crown jewels", + "clockweights", + "family jewels", + "marbles", + "bean bags", + "teabags", + "sweetmeats", + "goolies", + "boys", + "nutsack", + "block and tackle", + "cojones" + ) + +/decl/pronouns/male/get_message_for_being_kicked_in_the_dick() + return "Oh no, not your [pick(weird_euphemisms_for_your_balls)]!" diff --git a/code/modules/pronouns/pronouns_neuter.dm b/code/modules/pronouns/pronouns_neuter.dm new file mode 100644 index 000000000000..a9f32b216e06 --- /dev/null +++ b/code/modules/pronouns/pronouns_neuter.dm @@ -0,0 +1,28 @@ +/decl/pronouns/neuter + uid = "pronouns_neuter" + name = NEUTER + He = "It" + he = "it" + His = "Its" + his = "its" + him = "it" + has = "has" + is = "is" + does = "does" + self = "itself" + s = "s" + es = "es" + pluralize_verb = PLURALIZE_ALL + +// Alternative to plural neuter. +// With thanks to https://tib.cjcs.com/genderless-pronouns-ey-em-and-eir-2/ +/decl/pronouns/neuter/person + uid = "pronouns_neuter_animate" + name = NEUTER_ANIMATE + He = "Ey" + he = "ey" + His = "Eir" + his = "eir" + him = "em" + has = "has" + self = "emself" diff --git a/code/modules/pronouns/pronouns_pseudoplural.dm b/code/modules/pronouns/pronouns_pseudoplural.dm new file mode 100644 index 000000000000..f7cbb29e4625 --- /dev/null +++ b/code/modules/pronouns/pronouns_pseudoplural.dm @@ -0,0 +1,19 @@ +/decl/pronouns/pseudoplural + uid = "pronouns_pseudoplural" + name = PSEUDOPLURAL + bureaucratic_term = "other" + informal_term = "hoopy frood" + honorific = "Mx." + + He = "They" + he = "they" + His = "Their" + his = "their" + him = "them" + has = "have" + is = "are" + does = "do" + self = "themself" + pluralize_verb = PLURALIZE_PSEUDO + s = "" + es = "" \ No newline at end of file diff --git a/code/modules/pronouns/pronouns_second_person.dm b/code/modules/pronouns/pronouns_second_person.dm new file mode 100644 index 000000000000..239f4e99d7f0 --- /dev/null +++ b/code/modules/pronouns/pronouns_second_person.dm @@ -0,0 +1,14 @@ +/decl/pronouns/second_person_singular + uid = "pronouns_second_person_singular" + name = SECOND_PERSON_SINGULAR + He = "You" + he = "you" + His = "Your" + his = "your" + him = "you" // yourself? you? + has = "have" + is = "are" + does = "do" + self = "yourself" + s = "" + es = "" \ No newline at end of file diff --git a/code/modules/radiation/radiation.dm b/code/modules/radiation/radiation.dm index 46aadb354d5e..b2249461050f 100644 --- a/code/modules/radiation/radiation.dm +++ b/code/modules/radiation/radiation.dm @@ -23,12 +23,12 @@ /datum/radiation_source/proc/update_rad_power(var/new_power = null) if(new_power == null || new_power == rad_power) return // No change - else if(new_power <= config.radiation_lower_limit) + else if(new_power <= get_config_value(/decl/config/num/radiation_lower_limit)) qdel(src) // Decayed to nothing else rad_power = new_power if(!flat) - range = min(round(sqrt(rad_power / config.radiation_lower_limit)), 31) // R = rad_power / dist**2 - Solve for dist + range = min(round(sqrt(rad_power / get_config_value(/decl/config/num/radiation_lower_limit))), 31) // R = rad_power / dist**2 - Solve for dist /turf var/cached_rad_resistance = 0 @@ -39,13 +39,13 @@ if(!(O.rad_resistance_modifier <= 0) && O.density) var/decl/material/M = O.get_material() if(!M) continue - cached_rad_resistance += (M.weight * O.rad_resistance_modifier) / config.radiation_material_resistance_divisor + cached_rad_resistance += (M.weight * O.rad_resistance_modifier) / get_config_value(/decl/config/num/radiation_material_resistance_divisor) // Looks like storing the contents length is meant to be a basic check if the cache is stale due to items enter/exiting. Better than nothing so I'm leaving it as is. ~Leshana SSradiation.resistance_cache[src] = (length(contents) + 1) -/turf/simulated/wall/calc_rad_resistance() +/turf/wall/calc_rad_resistance() SSradiation.resistance_cache[src] = (length(contents) + 1) - cached_rad_resistance = (density ? material.weight / config.radiation_material_resistance_divisor : 0) + cached_rad_resistance = (density ? material.weight / get_config_value(/decl/config/num/radiation_material_resistance_divisor) : 0) /obj var/rad_resistance_modifier = 1 // Allow overriding rad resistance @@ -63,7 +63,7 @@ return 1 /mob/living/rad_act(var/severity) - if(severity) + if(severity > RAD_LEVEL_LOW) src.apply_damage(severity, IRRADIATE, damage_flags = DAM_DISPERSED) for(var/atom/I in src) I.rad_act(severity) diff --git a/code/modules/random_map/_random_map_setup.dm b/code/modules/random_map/_random_map_setup.dm index e89f0cd035db..afcb3288e319 100644 --- a/code/modules/random_map/_random_map_setup.dm +++ b/code/modules/random_map/_random_map_setup.dm @@ -3,30 +3,40 @@ */ #define MIN_SURFACE_COUNT_PER_CHUNK 0.1 -#define MIN_RARE_COUNT_PER_CHUNK 0.05 -#define MIN_DEEP_COUNT_PER_CHUNK 0.025 -#define RESOURCE_HIGH_MAX 4 -#define RESOURCE_HIGH_MIN 2 -#define RESOURCE_MID_MAX 3 -#define RESOURCE_MID_MIN 1 -#define RESOURCE_LOW_MAX 1 -#define RESOURCE_LOW_MIN 0 +#define MIN_RARE_COUNT_PER_CHUNK 0.05 +#define MIN_DEEP_COUNT_PER_CHUNK 0.025 +#define RESOURCE_HIGH_MAX 4 +#define RESOURCE_HIGH_MIN 2 +#define RESOURCE_MID_MAX 3 +#define RESOURCE_MID_MIN 1 +#define RESOURCE_LOW_MAX 1 +#define RESOURCE_LOW_MIN 0 +#define RESOURCE_COMMON_MAX 5 +#define RESOURCE_COMMON_MIN 3 -#define FLOOR_CHAR 0 -#define WALL_CHAR 1 -#define DOOR_CHAR 2 -#define EMPTY_CHAR 3 -#define ROOM_TEMP_CHAR 4 -#define MONSTER_CHAR 5 -#define ARTIFACT_TURF_CHAR 6 -#define ARTIFACT_CHAR 7 -#define CORRIDOR_TURF_CHAR 8 +#define FLOOR_CHAR 0 +#define WALL_CHAR 1 +#define DOOR_CHAR 2 +#define EMPTY_CHAR 3 +#define ROOM_TEMP_CHAR 4 +#define MONSTER_CHAR 5 +#define ARTIFACT_TURF_CHAR 6 +#define ARTIFACT_CHAR 7 +#define CORRIDOR_TURF_CHAR 8 #define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) #define TRANSLATE_AND_VERIFY_COORD(X,Y) TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,map.len) #define TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,LEN) \ tmp_cell = TRANSLATE_COORD(X,Y);\ + if (tmp_cell < 1 || tmp_cell > LEN) {\ + tmp_cell = null;\ + } + +#define TRANSLATE_COORD_OTHER_MAP(X,Y,MAP) ((((Y) - 1) * MAP.limit_x) + (X)) +#define TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(X,Y,MAP) TRANSLATE_AND_VERIFY_COORD_OTHER_MAP_MLEN(X, Y, MAP, MAP.map.len) +#define TRANSLATE_AND_VERIFY_COORD_OTHER_MAP_MLEN(X,Y,MAP,LEN) \ + tmp_cell = TRANSLATE_COORD_OTHER_MAP(X,Y,MAP);\ if (tmp_cell < 1 || tmp_cell > LEN) {\ tmp_cell = null;\ } \ No newline at end of file diff --git a/code/modules/random_map/automata/automata.dm b/code/modules/random_map/automata/automata.dm index 544b625a331e..3e45c90f4fc3 100644 --- a/code/modules/random_map/automata/automata.dm +++ b/code/modules/random_map/automata/automata.dm @@ -11,58 +11,68 @@ var/cell_threshold = 5 // Cell becomes alive with this many live neighbors. // Automata-specific procs and processing. -/datum/random_map/automata/generate_map() - for(var/iter = 1 to iterations) - var/list/next_map[limit_x*limit_y] - var/count - var/is_not_border_left - var/is_not_border_right - var/ilim_u - var/ilim_d - var/bottom_lim = ((limit_y - 1) * limit_x) - - if (!islist(map)) - set_map_size() - - for (var/i in 1 to (limit_x * limit_y)) - count = 0 - - is_not_border_left = i != 1 && ((i - 1) % limit_x) - is_not_border_right = i % limit_x +// we make a map slightly larger than we need in order to avoid needing to check edges +/datum/random_map/automata/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) + ..(tx, ty, tz, tlx+2, tly+2, do_not_apply, do_not_announce, used_area) - if (CELL_ALIVE(map[i])) // Center row. - ++count - if (is_not_border_left && CELL_ALIVE(map[i - 1])) - ++count - if (is_not_border_right && CELL_ALIVE(map[i + 1])) - ++count +/datum/random_map/automata/seed_map() + // we skip the edges here because they're just for indexing purposes + for(var/x in 2 to limit_x - 1) + for(var/y in 2 to limit_y - 1) + var/current_cell = TRANSLATE_COORD(x,y) + if(prob(initial_wall_cell)) + map[current_cell] = WALL_CHAR + else + map[current_cell] = initial_cell_char - if (i > limit_x) // top row - ilim_u = i - limit_x - if (CELL_ALIVE(map[ilim_u])) - ++count - if (is_not_border_left && CELL_ALIVE(map[ilim_u - 1])) - ++count - if (is_not_border_right && CELL_ALIVE(map[ilim_u + 1])) - ++count - - if (i <= bottom_lim) // bottom row - ilim_d = i + limit_x - if (CELL_ALIVE(map[ilim_d])) - ++count - if (is_not_border_left && CELL_ALIVE(map[ilim_d - 1])) - ++count - if (is_not_border_right && CELL_ALIVE(map[ilim_d + 1])) - ++count - - if(count >= cell_threshold) - REVIVE_CELL(i, next_map) - else // Nope. Can't be alive. Kill it. - KILL_CELL(i, next_map) +/datum/random_map/automata/apply_to_map() + if(!origin_x) origin_x = 1 + if(!origin_y) origin_y = 1 + if(!origin_z) origin_z = 1 + // adjust for automata map bounds weirdness + // this means that x=2 will be origin_x, which is good + // and that we only apply 2 to n-1, which is also good + origin_x -= 1 + origin_y -= 1 + for(var/x in 2 to limit_x-1) + for(var/y in 2 to limit_y-1) CHECK_TICK + apply_to_turf(x,y) +/datum/random_map/automata/generate_map() + var/list/map = src.map + // Instead of allocating a new next_map every iteration, + // we just flip the next_map and map lists. + var/list/next_map = new /list(length(map)) + var/temp // used to swap the maps + // do a running count to save on repeated accesses + // this reduces us from 9 checks per tile to just 3 + var/bottom_count = 0 + var/middle_count = 0 + var/top_count = 0 + for(var/iter = 1 to iterations) + // we have a 1 tile buffer on both sides so go from 2 to lim-1 + for (var/x in 2 to limit_x - 1) + bottom_count = 0 + middle_count = CELL_ALIVE(map[TRANSLATE_COORD(x-1, 1)]) + CELL_ALIVE(map[TRANSLATE_COORD(x, 1)]) + CELL_ALIVE(map[TRANSLATE_COORD(x+1, 1)]) + top_count = CELL_ALIVE(map[TRANSLATE_COORD(x-1, 2)]) + CELL_ALIVE(map[TRANSLATE_COORD(x, 2)]) + CELL_ALIVE(map[TRANSLATE_COORD(x+1, 2)]) + for (var/y in 2 to limit_y - 1) + var/i = TRANSLATE_COORD(x, y) + // shift everything down a row + bottom_count = middle_count + middle_count = top_count + top_count = CELL_ALIVE(map[i + limit_x - 1]) + CELL_ALIVE(map[i + limit_x]) + CELL_ALIVE(map[i + limit_x + 1]) + if((bottom_count + middle_count + top_count) >= cell_threshold) + REVIVE_CELL(i, next_map) + else // Nope. Can't be alive. Kill it. + KILL_CELL(i, next_map) + CHECK_TICK + // end iteration + temp = map // save this to use as our next slate map = next_map + next_map = temp // restore our next_map slate + src.map = map /datum/random_map/automata/get_additional_spawns(value, turf/T) return diff --git a/code/modules/random_map/automata/caves.dm b/code/modules/random_map/automata/caves.dm index 1bc2f2411fa1..91044cd99d54 100644 --- a/code/modules/random_map/automata/caves.dm +++ b/code/modules/random_map/automata/caves.dm @@ -1,26 +1,20 @@ /datum/random_map/automata/cave_system iterations = 5 descriptor = "moon caves" - wall_type = /turf/simulated/wall/natural - floor_type = /turf/simulated/floor/asteroid + wall_type = /turf/wall/natural + floor_type = /turf/floor/barren target_turf_type = /turf/unsimulated/mask - var/mineral_turf = /turf/simulated/wall/natural/random - var/list/ore_turfs = list() - var/list/minerals_sparse - var/list/minerals_rich - -/datum/random_map/automata/cave_system/New() - if(!minerals_sparse) - minerals_sparse = SSmaterials.weighted_minerals_sparse - if(!minerals_rich) - minerals_rich = SSmaterials.weighted_minerals_rich - ..() + var/sparse_mineral_turf = /turf/wall/natural/random + var/rich_mineral_turf = /turf/wall/natural/random/high_chance + var/list/ore_turfs = list() /datum/random_map/automata/cave_system/get_appropriate_path(var/value) switch(value) - if(DOOR_CHAR, EMPTY_CHAR) - return mineral_turf + if(DOOR_CHAR) + return sparse_mineral_turf + if(EMPTY_CHAR) + return rich_mineral_turf if(FLOOR_CHAR) return floor_type if(WALL_CHAR) @@ -49,8 +43,7 @@ var/empty_count = 0 while((ore_count>0) && (ore_turfs.len>0)) - if(!priority_process) - CHECK_TICK + CHECK_TICK var/check_cell = pick(ore_turfs) ore_turfs -= check_cell @@ -70,37 +63,18 @@ if(!origin_x) origin_x = 1 if(!origin_y) origin_y = 1 if(!origin_z) origin_z = 1 - var/tmp_cell var/new_path var/num_applied = 0 - for (var/thing in block(locate(origin_x, origin_y, origin_z), locate(limit_x, limit_y, origin_z))) - var/turf/T = thing - new_path = null + for (var/turf/T as anything in block(origin_x, origin_y, origin_z, limit_x, limit_y, origin_z)) if (!T || (target_turf_type && !istype(T, target_turf_type))) continue - tmp_cell = TRANSLATE_COORD(T.x, T.y) - - var/minerals - switch (map[tmp_cell]) - if(DOOR_CHAR) - new_path = mineral_turf - minerals = pickweight(minerals_sparse) - if(EMPTY_CHAR) - new_path = mineral_turf - minerals = pickweight(minerals_rich) - if(FLOOR_CHAR) - new_path = floor_type - if(WALL_CHAR) - new_path = wall_type - + new_path = get_appropriate_path(map[tmp_cell]) if (!new_path) continue - num_applied += 1 - T.ChangeTurf(new_path, minerals) + T.ChangeTurf(new_path) get_additional_spawns(map[tmp_cell], T) CHECK_TICK - game_log("ASGEN", "Applied [num_applied] turfs.") \ No newline at end of file diff --git a/code/modules/random_map/building/building.dm b/code/modules/random_map/building/building.dm index 98a157c45998..5a24fa367082 100644 --- a/code/modules/random_map/building/building.dm +++ b/code/modules/random_map/building/building.dm @@ -6,7 +6,7 @@ /datum/random_map/building/generate_map() for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue if(x == 1 || y == 1 || x == limit_x || y == limit_y) @@ -18,7 +18,7 @@ var/list/possible_doors for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue if(!(x == 1 || y == 1 || x == limit_x || y == limit_y)) @@ -39,7 +39,10 @@ if(place_door) - possible_doors |= target_map.get_map_cell(tx+x,ty+y) + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(tx+x, ty+y, target_map) + if(tmp_cell) + possible_doors |= tmp_cell if(possible_doors.len) // Place at least one door. diff --git a/code/modules/random_map/drop/drop_types.dm b/code/modules/random_map/drop/drop_types.dm index bdde75533fc0..1560263f9968 100644 --- a/code/modules/random_map/drop/drop_types.dm +++ b/code/modules/random_map/drop/drop_types.dm @@ -22,12 +22,6 @@ var/global/list/datum/supply_drop_loot/supply_drop /datum/supply_drop_loot/dd_SortValue() return name -/datum/supply_drop_loot/supermatter - name = "Supermatter" -/datum/supply_drop_loot/supermatter/New() - ..() - contents = list(/obj/machinery/power/supermatter) - /datum/supply_drop_loot/lasers name = "Lasers" container = /obj/structure/largecrate @@ -51,18 +45,6 @@ var/global/list/datum/supply_drop_loot/supply_drop /obj/item/gun/projectile/automatic/smg, /obj/item/gun/projectile/automatic/assault_rifle) -/datum/supply_drop_loot/ballistics - name = "Ballistics" - container = /obj/structure/largecrate -/datum/supply_drop_loot/ballistics/New() - ..() - contents = list( - /obj/item/gun/projectile/pistol, - /obj/item/gun/projectile/shotgun/doublebarrel, - /obj/item/gun/projectile/shotgun/pump, - /obj/item/gun/projectile/automatic/smg, - /obj/item/gun/projectile/automatic/assault_rifle) - /datum/supply_drop_loot/seeds name = "Seeds" container = /obj/structure/closet/crate @@ -92,16 +74,18 @@ var/global/list/datum/supply_drop_loot/supply_drop /datum/supply_drop_loot/food/New() ..() contents = list( - /obj/item/chems/food/condiment/flour, - /obj/item/chems/food/condiment/flour, - /obj/item/chems/food/condiment/flour, - /obj/item/chems/food/drinks/milk, - /obj/item/chems/food/drinks/milk, - /obj/item/storage/fancy/egg_box, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/tofu, - /obj/item/chems/food/snacks/meat, - /obj/item/chems/food/snacks/meat) + /obj/item/chems/condiment/yeast, + /obj/item/chems/condiment/flour, + /obj/item/chems/condiment/flour, + /obj/item/chems/condiment/flour, + /obj/item/chems/drinks/milk, + /obj/item/chems/drinks/milk, + /obj/item/food/dairy/butter/stick, + /obj/item/box/fancy/egg_box, + /obj/item/food/tofu, + /obj/item/food/tofu, + /obj/item/food/butchery/meat, + /obj/item/food/butchery/meat) /datum/supply_drop_loot/armour name = "Armour" @@ -128,15 +112,15 @@ var/global/list/datum/supply_drop_loot/supply_drop /datum/supply_drop_loot/materials/New() ..() contents = list( - /obj/item/stack/material/steel, - /obj/item/stack/material/steel, - /obj/item/stack/material/steel, - /obj/item/stack/material/glass, - /obj/item/stack/material/glass, - /obj/item/stack/material/wood, - /obj/item/stack/material/plastic, - /obj/item/stack/material/glass/reinforced, - /obj/item/stack/material/plasteel) + /obj/item/stack/material/sheet/mapped/steel, + /obj/item/stack/material/sheet/mapped/steel, + /obj/item/stack/material/sheet/mapped/steel, + /obj/item/stack/material/pane/mapped/glass, + /obj/item/stack/material/pane/mapped/glass, + /obj/item/stack/material/plank/mapped/wood, + /obj/item/stack/material/panel/mapped/plastic, + /obj/item/stack/material/pane/mapped/rglass, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel) /datum/supply_drop_loot/medical name = "Medical" @@ -144,33 +128,33 @@ var/global/list/datum/supply_drop_loot/supply_drop /datum/supply_drop_loot/medical/New() ..() contents = list( - /obj/item/storage/firstaid/regular, - /obj/item/storage/firstaid/trauma, - /obj/item/storage/firstaid/fire, - /obj/item/storage/firstaid/toxin, - /obj/item/storage/firstaid/o2, - /obj/item/storage/firstaid/adv, + /obj/item/firstaid/regular, + /obj/item/firstaid/trauma, + /obj/item/firstaid/fire, + /obj/item/firstaid/toxin, + /obj/item/firstaid/o2, + /obj/item/firstaid/adv, /obj/item/chems/glass/bottle/antitoxin, /obj/item/chems/glass/bottle/stabilizer, /obj/item/chems/glass/bottle/sedatives, - /obj/item/storage/box/syringes, - /obj/item/storage/box/autoinjectors) + /obj/item/box/syringes, + /obj/item/box/autoinjectors) -/datum/supply_drop_loot/power - name = "Power" +/datum/supply_drop_loot/materials + name = "Materials" container = /obj/structure/largecrate -/datum/supply_drop_loot/power/New() +/datum/supply_drop_loot/materials/New() ..() contents = list( - /obj/item/stack/material/steel, - /obj/item/stack/material/steel, - /obj/item/stack/material/steel, - /obj/item/stack/material/glass, - /obj/item/stack/material/glass, - /obj/item/stack/material/wood, - /obj/item/stack/material/plastic, - /obj/item/stack/material/glass/reinforced, - /obj/item/stack/material/plasteel) + /obj/item/stack/material/sheet/mapped/steel, + /obj/item/stack/material/sheet/mapped/steel, + /obj/item/stack/material/sheet/mapped/steel, + /obj/item/stack/material/pane/mapped/glass, + /obj/item/stack/material/pane/mapped/glass, + /obj/item/stack/material/plank/mapped/wood, + /obj/item/stack/material/panel/mapped/plastic, + /obj/item/stack/material/pane/mapped/rglass, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel) /datum/supply_drop_loot/hydroponics name = "Hydroponics" @@ -188,9 +172,9 @@ var/global/list/datum/supply_drop_loot/supply_drop /datum/supply_drop_loot/power/New() ..() contents = list( - /obj/machinery/power/port_gen/pacman, - /obj/machinery/power/port_gen/pacman/super, - /obj/machinery/power/port_gen/pacman/mrs) + /obj/machinery/port_gen/pacman, + /obj/machinery/port_gen/pacman/super, + /obj/machinery/port_gen/pacman/mrs) /datum/supply_drop_loot/power/contents() return list(pick(contents)) diff --git a/code/modules/random_map/drop/droppod.dm b/code/modules/random_map/drop/droppod.dm index 55cb892d2305..7c81af16f087 100644 --- a/code/modules/random_map/drop/droppod.dm +++ b/code/modules/random_map/drop/droppod.dm @@ -11,11 +11,11 @@ limit_y = 3 preserve_map = 0 - wall_type = /turf/simulated/wall/titanium - floor_type = /turf/simulated/floor/reinforced + wall_type = /turf/wall/titanium + floor_type = /turf/floor/reinforced var/list/supplied_drop_types = list() var/door_type = /obj/structure/droppod_door - var/drop_type = /mob/living/simple_animal/hostile/retaliate/parrot + var/drop_type = /mob/living/simple_animal/hostile/parrot var/auto_open_doors var/placement_explosion_dev = 1 @@ -23,7 +23,7 @@ var/placement_explosion_light = 6 var/placement_explosion_flash = 4 -/datum/random_map/droppod/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/supplied_drop, var/list/supplied_drops, var/automated) +/datum/random_map/droppod/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area, var/supplied_drop, var/list/supplied_drops, var/automated) if(supplied_drop) drop_type = supplied_drop @@ -41,13 +41,13 @@ /datum/random_map/droppod/generate_map() // No point calculating these 200 times. - var/x_midpoint = Ceiling(limit_x / 2) - var/y_midpoint = Ceiling(limit_y / 2) + var/x_midpoint = ceil(limit_x / 2) + var/y_midpoint = ceil(limit_y / 2) // Draw walls/floors/doors. for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue @@ -73,14 +73,14 @@ map[current_cell] = SD_FLOOR_TILE // Draw the drop contents. - var/current_cell = get_map_cell(x_midpoint,y_midpoint) + var/current_cell = TRANSLATE_COORD(x_midpoint,y_midpoint) if(current_cell) map[current_cell] = SD_SUPPLY_TILE return 1 /datum/random_map/droppod/apply_to_map() if(placement_explosion_dev || placement_explosion_heavy || placement_explosion_light || placement_explosion_flash) - var/turf/T = locate((origin_x + Ceiling(limit_x / 2)-1), (origin_y + Ceiling(limit_y / 2)-1), origin_z) + var/turf/T = locate((origin_x + ceil(limit_x / 2)-1), (origin_y + ceil(limit_y / 2)-1), origin_z) if(istype(T)) explosion(T, placement_explosion_dev, placement_explosion_heavy, placement_explosion_light, placement_explosion_flash) sleep(15) // Let the explosion finish proccing before we ChangeTurf(), otherwise it might destroy our spawned objects. @@ -97,8 +97,8 @@ // Pods are circular. Get the direction this object is facing from the center of the pod. /datum/random_map/droppod/get_spawn_dir(var/x, var/y) - var/x_midpoint = Ceiling(limit_x / 2) - var/y_midpoint = Ceiling(limit_y / 2) + var/x_midpoint = ceil(limit_x / 2) + var/y_midpoint = ceil(limit_y / 2) if(x == x_midpoint && y == y_midpoint) return null var/turf/target = locate(origin_x+x-1, origin_y+y-1, origin_z) @@ -124,8 +124,8 @@ get_spawned_drop(T) /datum/random_map/droppod/proc/get_spawned_drop(var/turf/T) - var/obj/structure/bed/chair/C = new(T) - C.set_light(0.5, 0.1, 3, 2, l_color = "#cc0000") + var/obj/structure/chair/C = new(T) + C.set_light(3, 1, l_color = "#cc0000") var/mob/living/drop // This proc expects a list of mobs to be passed to the spawner. // Use the supply pod if you don't want to drop mobs. @@ -136,7 +136,6 @@ drop = pick(supplied_drop_types) supplied_drop_types -= drop if(istype(drop)) - drop.tag = null if(drop.buckled) drop.buckled = null drop.forceMove(T) @@ -158,7 +157,7 @@ var/mob/living/spawned_mob var/list/spawned_mobs = list() - var/spawn_path = input("Select a mob type.", "Drop Pod Selection", null) as null|anything in typesof(/mob/living)-/mob/living + var/spawn_path = input("Select a mob type.", "Drop Pod Selection", null) as null|anything in subtypesof(/mob/living) if(!spawn_path) return @@ -168,11 +167,10 @@ return for(var/i=0;iYou prime the explosive bolts. Better get clear!") - sleep(30) - deploy() + if(deploying) + return ..() + deploy(user, 3 SECONDS) + return TRUE + +/obj/structure/droppod_door/proc/deploy(var/mob/user, var/delay) + set waitfor = FALSE -/obj/structure/droppod_door/proc/deploy() if(deployed) return - deployed = 1 - visible_message("The explosive bolts on \the [src] detonate, throwing it open!") + if(user) + to_chat(user, SPAN_DANGER("You prime the explosive bolts. Better get clear!")) + deployed = TRUE + + if(delay) + sleep(delay) + + if(QDELETED(src)) + return + + visible_message(SPAN_DANGER("The explosive bolts on \the [src] detonate, throwing it open!")) playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, 5) // This is shit but it will do for the sake of testing. for(var/obj/structure/droppod_door/D in orange(1,src)) if(D.deployed) continue - D.deploy() + D.deploy(null, 0) // Overwrite turfs. var/turf/origin = get_turf(src) - origin.ChangeTurf(/turf/simulated/floor/reinforced) + origin.ChangeTurf(/turf/floor/reinforced) origin.set_light(0) // Forcing updates var/turf/T = get_step(origin, src.dir) - T.ChangeTurf(/turf/simulated/floor/reinforced) + T.ChangeTurf(/turf/floor/reinforced) T.set_light(0) // Forcing updates // Destroy turf contents. diff --git a/code/modules/random_map/drop/supply.dm b/code/modules/random_map/drop/supply.dm index 3d3543c06406..3b8333bab12a 100644 --- a/code/modules/random_map/drop/supply.dm +++ b/code/modules/random_map/drop/supply.dm @@ -18,7 +18,7 @@ var/obj/structure/largecrate/C = locate() in T for(var/drop_type in supplied_drop_types) var/atom/movable/A = new drop_type(T) - if(!istype(A, /mob)) + if(!ismob(A)) if(!C) C = new(T) C.contents |= A return @@ -90,4 +90,4 @@ if(choice == "No") return log_admin("[key_name(usr)] dropped supplies at ([usr.x],[usr.y],[usr.z])") - new /datum/random_map/droppod/supply(null, usr.x-2, usr.y-2, usr.z, supplied_drops = chosen_loot_types, supplied_drop = chosen_loot_type) \ No newline at end of file + new /datum/random_map/droppod/supply(usr.x-2, usr.y-2, usr.z, supplied_drops = chosen_loot_types, supplied_drop = chosen_loot_type) \ No newline at end of file diff --git a/code/modules/random_map/dungeon/predefined.dm b/code/modules/random_map/dungeon/predefined.dm index 633f16e0d762..91b22c5c42eb 100644 --- a/code/modules/random_map/dungeon/predefined.dm +++ b/code/modules/random_map/dungeon/predefined.dm @@ -5,10 +5,9 @@ room_theme_rare = list(/datum/room_theme/metal = 1, /datum/room_theme = 3, /datum/room_theme/metal/secure = 1) monsters_common = list(/mob/living/simple_animal/hostile/carp = 50, /mob/living/simple_animal/hostile/carp/pike = 1) - monsters_uncommon = list(/mob/living/simple_animal/hostile/hivebot = 10, /mob/living/simple_animal/hostile/hivebot/strong = 1) + monsters_uncommon = list(/mob/living/simple_animal/hostile/hivebot = 10, /mob/living/simple_animal/hostile/hivebot/melee/armored = 1) -/datum/random_map/winding_dungeon/premade/New() - loot_common = subtypesof(/obj/item/energy_blade/sword) + subtypesof(/obj/item/baton) + subtypesof(/obj/item/chems/food) +/datum/random_map/winding_dungeon/premade/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) + loot_common = subtypesof(/obj/item/energy_blade/sword) + subtypesof(/obj/item/baton) + subtypesof(/obj/item/food) + subtypesof(/obj/item/chems/condiment) + subtypesof(/obj/item/chems/drinks) loot_uncommon += subtypesof(/obj/item/gun/projectile) + subtypesof(/obj/item/ammo_magazine) - monsters_rare += typesof(/mob/living/simple_animal/hostile/syndicate) + typesof(/mob/living/simple_animal/hostile/pirate) ..() \ No newline at end of file diff --git a/code/modules/random_map/dungeon/room.dm b/code/modules/random_map/dungeon/room.dm index 8c60a977c27d..c95dff95a9f8 100644 --- a/code/modules/random_map/dungeon/room.dm +++ b/code/modules/random_map/dungeon/room.dm @@ -41,35 +41,45 @@ If its complexity is lower than our theme's then for(var/j = 0, j < height, j++) var/truex = xorigin + x + i - 1 var/truey = yorigin + y + j - 1 - var/cell = map.get_map_cell(x+i,y+j) + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i, y+j, map) + var/cell = tmp_cell room_theme.apply_room_theme(truex,truey,map.map[cell]) if(generate_doors && room_theme.door_type && !(map.map[cell] == WALL_CHAR || map.map[cell] == ARTIFACT_TURF_CHAR) && (i == 0 || i == width-1 || j == 0 || j == height-1)) var/isGood = 1 if(j == 0 || j == height-1) //check horizontally - var/curCell = map.map[map.get_map_cell(x+i-1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i-1,y+j, map) + var/curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i+1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i+1,y+j, map) + curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i,y+j-1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j-1, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i,y+j+1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j+1, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 - if(i == 0 || i == width-1) //verticle + if(i == 0 || i == width-1) //vertical isGood = 1 //if it failed above, it might not fail here. - var/curCell = map.map[map.get_map_cell(x+i,y+j-1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j-1, map) + var/curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i,y+j+1)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i,y+j+1, map) + curCell = map.map[tmp_cell] if(curCell != WALL_CHAR && curCell != ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i-1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i-1,y+j, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 - curCell = map.map[map.get_map_cell(x+i+1,y+j)] + TRANSLATE_AND_VERIFY_COORD_OTHER_MAP(x+i+1,y+j, map) + curCell = map.map[tmp_cell] if(curCell == WALL_CHAR || curCell == ARTIFACT_TURF_CHAR) isGood = 0 if(isGood) diff --git a/code/modules/random_map/dungeon/room_generation.dm b/code/modules/random_map/dungeon/room_generation.dm index 005ce8aae308..c480fac04ec1 100644 --- a/code/modules/random_map/dungeon/room_generation.dm +++ b/code/modules/random_map/dungeon/room_generation.dm @@ -18,7 +18,7 @@ return 1 /datum/random_room/proc/apply_loot(var/xorigin = 1,var/yorigin = 1,var/zorigin = 1, var/type) - if(!item_spawns || !item_spawns.len) + if(!LAZYLEN(item_spawns)) return 0 var/place = pick(item_spawns) if(istype(place,/obj)) //we assume what object we get is some sort of container. @@ -26,7 +26,7 @@ if(O.contents && prob(O.contents.len * (25 / O.w_class))) return 0 new type(place) - else if(istype(place,/mob)) + else if(ismob(place)) var/mob/M = place var/atom/movable/A = new type(M.loc) M.equip_to_appropriate_slot(A) //we dont have to check if its an object or not since hte proc in question already does that diff --git a/code/modules/random_map/dungeon/room_theme.dm b/code/modules/random_map/dungeon/room_theme.dm index f6ec7ffacc52..9033a10375f3 100644 --- a/code/modules/random_map/dungeon/room_theme.dm +++ b/code/modules/random_map/dungeon/room_theme.dm @@ -48,9 +48,8 @@ var/turf/check = locate(T.x + i, T.y + j, T.z) if(!check) continue - for(var/atom/movable/M in check.contents) - if(!istype(M, /atom/movable/lighting_overlay) && M.density) - return 0 + if(check.contains_dense_objects()) + return FALSE if(!T) return 0 if(ispath(door_type,/obj/structure/door)) @@ -64,8 +63,8 @@ return null /datum/room_theme/metal - wall_type = /turf/simulated/wall - floor_type = /turf/simulated/floor/plating + wall_type = /turf/wall + floor_type = /turf/floor/plating lock_complexity_max = 2 layout_chance = 30 room_layouts = list(/datum/random_room/mimic = 1, /datum/random_room/tomb = 1) diff --git a/code/modules/random_map/dungeon/rooms/mimic_room.dm b/code/modules/random_map/dungeon/rooms/mimic_room.dm index 87bfce78e6d5..be75e3b01bd1 100644 --- a/code/modules/random_map/dungeon/rooms/mimic_room.dm +++ b/code/modules/random_map/dungeon/rooms/mimic_room.dm @@ -1,6 +1,5 @@ /datum/random_room/mimic var/mimic_type = /obj/structure/closet/crate - var/list/mimic_vars = list() var/chance_of_mimic = 5 /datum/random_room/mimic/apply_to_map(var/xorigin,var/yorigin,var/zorigin) diff --git a/code/modules/random_map/dungeon/rooms/tomb.dm b/code/modules/random_map/dungeon/rooms/tomb.dm index bde46e86e808..339b027250f5 100644 --- a/code/modules/random_map/dungeon/rooms/tomb.dm +++ b/code/modules/random_map/dungeon/rooms/tomb.dm @@ -22,13 +22,13 @@ var/type = pickweight(corpses) var/mob/M if(istext(type)) - M = new /mob/living/carbon/human() - var/mob/living/carbon/human/H = M + M = new /mob/living/human() + var/mob/living/human/H = M H.set_species(type) - H.ChangeToHusk() + H.add_genetic_condition(GENE_COND_HUSK) else M = new type() - M.death(0) + M.death() M.forceMove(C1) item_spawns += M check = locate(truex + (direction ? width - 2 : 0), truey + (direction ? 0 : height - 2), zorigin) @@ -38,12 +38,12 @@ var/type = pickweight(corpses) var/mob/M if(istext(type)) - M = new /mob/living/carbon/human() - var/mob/living/carbon/human/H = M + M = new /mob/living/human() + var/mob/living/human/H = M H.set_species(type) - H.ChangeToHusk() + H.add_genetic_condition(GENE_COND_HUSK) else M = new type() - M.death(0) + M.death() M.forceMove(C2) item_spawns += M \ No newline at end of file diff --git a/code/modules/random_map/dungeon/winding_dungeon.dm b/code/modules/random_map/dungeon/winding_dungeon.dm index 448790be6535..762213b7640b 100644 --- a/code/modules/random_map/dungeon/winding_dungeon.dm +++ b/code/modules/random_map/dungeon/winding_dungeon.dm @@ -18,9 +18,9 @@ /datum/random_map/winding_dungeon descriptor = "winding dungeon" - wall_type = /turf/simulated/wall/natural - floor_type = /turf/simulated/floor/tiled - var/room_wall_type = /turf/simulated/wall + wall_type = /turf/wall/natural + floor_type = /turf/floor/tiled + var/room_wall_type = /turf/wall var/border_wall_type = /turf/unsimulated/mineral target_turf_type = /turf/unsimulated/mask @@ -60,7 +60,7 @@ limit_x = 50 limit_y = 50 -/datum/random_map/winding_dungeon/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/list/variable_list) +/datum/random_map/winding_dungeon/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area, var/list/variable_list) for(var/variable in variable_list) if(variable in src.vars) src.vars[variable] = variable_list[variable] @@ -73,10 +73,10 @@ /datum/random_map/winding_dungeon/proc/get_appropriate_list(var/list/common, var/list/uncommon, var/list/rare, var/x, var/y) var/distance = sqrt((x - round(first_room_x+first_room_width/2)) ** 2 + (y - round(first_room_y+first_room_height/2)) ** 2) if(prob(distance)) - if(prob(distance/100) && rare && rare.len) + if(prob(distance/100) && LAZYLEN(rare)) logging("Returning rare list.") return rare - else if(uncommon && uncommon.len) + else if(LAZYLEN(uncommon)) logging("Returning uncommon list.") return uncommon logging("Returning common list.") @@ -86,20 +86,18 @@ /datum/random_map/winding_dungeon/apply_to_map() logging("You have [rooms.len] # of rooms") for(var/datum/room/R in rooms) - if(!priority_process) - sleep(-1) + CHECK_TICK R.apply_to_map(origin_x,origin_y,origin_z,src) ..() var/num_of_loot = round(limit_x * limit_y * loot_multiplier) logging("Attempting to add [num_of_loot] # of loot") var/sanity = 0 - if((loot_common && loot_common.len) || (loot_uncommon && loot_uncommon.len) || (loot_rare && loot_rare.len)) //no monsters no problem + if((LAZYLEN(loot_common)) || (LAZYLEN(loot_uncommon)) || (LAZYLEN(loot_rare))) //no monsters no problem while(rooms.len && num_of_loot > 0) - if(!priority_process) - sleep(-1) + CHECK_TICK var/datum/room/R = pick(rooms) var/list/loot_list = get_appropriate_list(loot_common, loot_uncommon, loot_rare, round(R.x+R.width/2), round(R.y+R.height/2)) - if(!loot_list || !loot_list.len || R.add_loot(origin_x,origin_y,origin_z,pickweight(loot_list))) + if(!LAZYLEN(loot_list) || R.add_loot(origin_x,origin_y,origin_z,pickweight(loot_list))) num_of_loot-- sanity -= 10 //we hahve success so more tries continue @@ -112,7 +110,7 @@ rooms -= R qdel(R) - if((!monsters_common || !monsters_common.len) && (!monsters_uncommon || !monsters_uncommon.len) && (!monsters_rare || !monsters_rare.len)) //no monsters no problem + if(!LAZYLEN(monsters_common) && !LAZYLEN(monsters_uncommon) && !LAZYLEN(monsters_rare)) //no monsters no problem logging("No monster lists detected. Not spawning monsters.") return @@ -120,16 +118,15 @@ logging("Attempting to add [num_of_monsters] # of monsters") while(num_of_monsters > 0) - if(!priority_process) - sleep(-1) - if(!monster_available || !monster_available.len) + CHECK_TICK + if(!LAZYLEN(monster_available)) logging("There are no available turfs left.") num_of_monsters = 0 continue var/turf/T = pick(monster_available) monster_available -= T var/list/monster_list = get_appropriate_list(monsters_common, monsters_uncommon, monsters_rare, T.x, T.y) - if(monster_list && monster_list.len) + if(LAZYLEN(monster_list)) var/type = pickweight(monster_list) logging("Generating a monster of type [type] at position ([T.x],[T.y],[origin_z])") var/mob/M = new type(T) @@ -142,26 +139,26 @@ monster_available = null //Get rid of all the references /datum/random_map/winding_dungeon/apply_to_turf(var/x, var/y) - . = ..() - var/turf/T = locate((origin_x-1)+x,(origin_y-1)+y,origin_z) + var/turf/T = ..() if(T && !T.density) var/can = 1 for(var/atom/movable/M in T) - if(istype(M,/mob/living) || M.density) + if(isliving(M) || M.density) can = 0 break if(can) monster_available += T + return T /datum/random_map/winding_dungeon/generate_map() logging("Winding Dungeon Generation Start") //first generate the border for(var/xx = 1, xx <= limit_x, xx++) - map[get_map_cell(xx,1)] = BORDER_CHAR - map[get_map_cell(xx,limit_y)] = BORDER_CHAR + map[TRANSLATE_COORD(xx,1)] = BORDER_CHAR + map[TRANSLATE_COORD(xx,limit_y)] = BORDER_CHAR for(var/yy = 1, yy < limit_y, yy++) - map[get_map_cell(1,yy)] = BORDER_CHAR - map[get_map_cell(limit_x,yy)] = BORDER_CHAR + map[TRANSLATE_COORD(1,yy)] = BORDER_CHAR + map[TRANSLATE_COORD(limit_x,yy)] = BORDER_CHAR var/num_of_features = limit_x * limit_y * features_multiplier logging("Number of features: [num_of_features]") @@ -170,9 +167,7 @@ logging("First room result: [result ? "Success" : "Failure"]") var/sanity = 0 for(sanity = 0, sanity < 1000, sanity++) - if(!priority_process) - sleep(-1) - + CHECK_TICK if(currentFeatures == num_of_features) break /* WHAT THIS CODE IS DOING: @@ -202,7 +197,7 @@ logging("open_positions empty. Using randomly chosen coords ([newx],[newy])") //We want to make sure we aren't RIGHT next to another corridor or something. - if(map[get_map_cell(newx,newy+1)] == ARTIFACT_CHAR || map[get_map_cell(newx-1,newy)] == ARTIFACT_CHAR || map[get_map_cell(newx,newy-1)] == ARTIFACT_CHAR || map[get_map_cell(newx+1,newy)] == ARTIFACT_CHAR) + if(LAZYACCESS(map, TRANSLATE_COORD(newx,newy+1)) == ARTIFACT_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx-1,newy)) == ARTIFACT_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx,newy-1)) == ARTIFACT_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx+1,newy)) == ARTIFACT_CHAR) logging("Coords ([newx],[newy]) are too close to an ARTIFACT_CHAR position.") continue @@ -212,9 +207,9 @@ height = rand(room_size_min,room_size_max) isRoom = rand(100) <= chance_of_room - if(map[get_map_cell(newx, newy)] == ARTIFACT_TURF_CHAR || map[get_map_cell(newx, newy)] == CORRIDOR_TURF_CHAR) + if(LAZYACCESS(map, TRANSLATE_COORD(newx, newy)) == ARTIFACT_TURF_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx, newy)) == CORRIDOR_TURF_CHAR) //we are basically checking to see where we're going. Up, right, down or left and finding the bottom left corner. - if(map[get_map_cell(newx,newy+1)] == FLOOR_CHAR || map[get_map_cell(newx,newy+1)] == CORRIDOR_TURF_CHAR) //0 - down + if(LAZYACCESS(map, TRANSLATE_COORD(newx,newy+1)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx,newy+1)) == CORRIDOR_TURF_CHAR) //0 - down logging("This feature is DOWN") if(isRoom) //gotta do some math for this one, since the origin is centered. xmod = -width/2 @@ -224,7 +219,7 @@ ymod = -height //a lot of this will seem nonsense but I swear its not doorx = 0 doory = -1 - else if(map[get_map_cell(newx-1,newy)] == FLOOR_CHAR || map[get_map_cell(newx-1,newy)] == CORRIDOR_TURF_CHAR) //1 - right + else if(LAZYACCESS(map, TRANSLATE_COORD(newx-1,newy)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx-1,newy)) == CORRIDOR_TURF_CHAR) //1 - right logging("This feature is RIGHT") if(isRoom) ymod = -height/2 @@ -234,7 +229,7 @@ xmod = 1 doorx = 1 doory = 0 - else if(map[get_map_cell(newx,newy-1)] == FLOOR_CHAR || map[get_map_cell(newx,newy-1)] == CORRIDOR_TURF_CHAR) //2 - up + else if(LAZYACCESS(map, TRANSLATE_COORD(newx,newy-1)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx,newy-1)) == CORRIDOR_TURF_CHAR) //2 - up logging("This feature is UP") if(isRoom) xmod = -width/2 @@ -244,7 +239,7 @@ ymod = 1 doorx = 0 doory = 1 - else if(map[get_map_cell(newx+1,newy)] == FLOOR_CHAR || map[get_map_cell(newx+1,newy)] == CORRIDOR_TURF_CHAR) // 3 - left + else if(LAZYACCESS(map, TRANSLATE_COORD(newx+1,newy)) == FLOOR_CHAR || LAZYACCESS(map, TRANSLATE_COORD(newx+1,newy)) == CORRIDOR_TURF_CHAR) // 3 - left logging("This feature is LEFT") if(isRoom) ymod = -height/2 @@ -268,16 +263,17 @@ currentFeatures++ if(isRoom) logging("Room created at: [newx+xmod], [newy+ymod].") - map[get_map_cell(newx,newy)] = FLOOR_CHAR - map[get_map_cell(newx+doorx,newy+doory)] = ARTIFACT_CHAR + map[TRANSLATE_COORD(newx,newy)] = FLOOR_CHAR + map[TRANSLATE_COORD(newx+doorx,newy+doory)] = ARTIFACT_CHAR if(rand(0,100) >= chance_of_room_empty) var/room_result = create_room_features(round(newx+xmod),round(newy+ymod),width,height) logging("Attempted room feature creation: [room_result ? "Success" : "Failure"]") else logging("Creating corridor.") - var/door = get_map_cell(newx,newy) - if(map[door] == ARTIFACT_TURF_CHAR) - map[door] = ARTIFACT_CHAR + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD(newx,newy) + if(map[tmp_cell] == ARTIFACT_TURF_CHAR) + map[tmp_cell] = ARTIFACT_CHAR logging("Map completed. Loops: [sanity], [currentFeatures] out of [num_of_features] created.") open_positions.Cut() @@ -292,17 +288,17 @@ if(xtemp < 0 || xtemp > limit_x) logging("We are beyond our x limits") return 0 - if(map[get_map_cell(xtemp,ytemp)] != WALL_CHAR) + if(map[TRANSLATE_COORD(xtemp,ytemp)] != WALL_CHAR) logging("[xtemp],[ytemp] is not equal to WALL_CHAR") return 0 else if(wall_char && (ytemp == truey || ytemp == truey + height - 1 || xtemp == truex || xtemp == truex + width - 1)) - map[get_map_cell(xtemp,ytemp)] = wall_char + map[TRANSLATE_COORD(xtemp,ytemp)] = wall_char if(!("[xtemp]:[ytemp]" in open_positions)) open_positions += "[xtemp]:[ytemp]" logging("Adding \"[xtemp]:[ytemp]\" to open_positions (length: [open_positions.len])") else - map[get_map_cell(xtemp,ytemp)] = char + map[TRANSLATE_COORD(xtemp,ytemp)] = char return 1 /datum/random_map/winding_dungeon/proc/create_room_features(var/rox,var/roy,var/width,var/height) @@ -317,10 +313,6 @@ rooms += R return 1 -/datum/random_map/winding_dungeon/proc/add_loot(var/xorigin,var/yorigin,var/zorigin,var/type) - var/datum/room/room = pick(rooms) - return room.add_loot(type) - /datum/random_map/winding_dungeon/get_appropriate_path(var/value) switch(value) if(WALL_CHAR) diff --git a/code/modules/random_map/dungeon/winding_dungeon_verb.dm b/code/modules/random_map/dungeon/winding_dungeon_verb.dm index 135737d866d1..4e8bae557fee 100644 --- a/code/modules/random_map/dungeon/winding_dungeon_verb.dm +++ b/code/modules/random_map/dungeon/winding_dungeon_verb.dm @@ -95,7 +95,7 @@ if(alert("Are you sure you want to create this? It will appear at your position.",,"No","Yes") != "Yes") return - var/datum/random_map/winding_dungeon/W = /datum/random_map/winding_dungeon + var/datum/random_map/winding_dungeon/dungeon = /datum/random_map/winding_dungeon for(var/x in 1 to vars["limit_x"]) for(var/y in 1 to vars["limit_y"]) @@ -104,5 +104,5 @@ if(!T) to_chat(src, "Error, turf could not be located. Probably out of bounds.") return - T.ChangeTurf(initial(W.target_turf_type)) - new /datum/random_map/winding_dungeon(null,usr.x, usr.y, usr.z, variable_list = vars) + T.ChangeTurf(initial(dungeon.target_turf_type)) + new /datum/random_map/winding_dungeon(usr.x, usr.y, usr.z, variable_list = vars) diff --git a/code/modules/random_map/mazes/maze.dm b/code/modules/random_map/mazes/maze.dm index 557adbd6e8e6..b9e5cc24b3ea 100644 --- a/code/modules/random_map/mazes/maze.dm +++ b/code/modules/random_map/mazes/maze.dm @@ -31,19 +31,28 @@ // Preliminary marking-off... closedlist[next.name] = next - map[get_map_cell(next.x,next.y)] = FLOOR_CHAR + map[TRANSLATE_COORD(next.x,next.y)] = FLOOR_CHAR // Apply the values required and fill gap between this cell and origin point. + var/tmp_cell if(next.ox && next.oy) if(next.ox < next.x) - map[get_map_cell(next.x-1,next.y)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x-1, next.y) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR else if(next.ox == next.x) if(next.oy < next.y) - map[get_map_cell(next.x,next.y-1)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x, next.y-1) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR else - map[get_map_cell(next.x,next.y+1)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x, next.y+1) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR else - map[get_map_cell(next.x+1,next.y)] = FLOOR_CHAR + TRANSLATE_AND_VERIFY_COORD(next.x+1, next.y) + if(tmp_cell) + map[tmp_cell] = FLOOR_CHAR // Grab valid neighbors for use in the open list! add_to_openlist(next.x,next.y+2,next.x,next.y) @@ -60,6 +69,6 @@ if(tx < 1 || ty < 1 || tx > limit_x || ty > limit_y || !isnull(checked_coord_cache["[tx]-[ty]"])) return 0 checked_coord_cache["[tx]-[ty]"] = 1 - map[get_map_cell(tx,ty)] = DOOR_CHAR + map[TRANSLATE_COORD(tx,ty)] = DOOR_CHAR var/datum/maze_cell/new_cell = new(tx,ty,nx,ny) openlist |= new_cell diff --git a/code/modules/random_map/mazes/maze_cell.dm b/code/modules/random_map/mazes/maze_cell.dm index 0b4fa1ac8694..da5013c55ad8 100644 --- a/code/modules/random_map/mazes/maze_cell.dm +++ b/code/modules/random_map/mazes/maze_cell.dm @@ -1,4 +1,4 @@ -var/maze_cell_count = 0 +var/global/maze_cell_count = 0 /datum/maze_cell var/name diff --git a/code/modules/random_map/noise/desert.dm b/code/modules/random_map/noise/desert.dm index 1c7ca229a41c..05146ce50e2d 100644 --- a/code/modules/random_map/noise/desert.dm +++ b/code/modules/random_map/noise/desert.dm @@ -4,7 +4,7 @@ /datum/random_map/noise/desert/replace_space descriptor = "desert (replacement)" - target_turf_type = /turf/space + target_turf_type = TRUE /datum/random_map/noise/desert/get_map_char(var/value) return "[pick(list(",",".","'","`"))]" @@ -14,9 +14,9 @@ if(isnull(val)) val = 0 switch(val) if(0 to 1) - return /turf/simulated/floor/beach/water + return /turf/floor/rock/sand/water else - return /turf/simulated/floor/beach/sand/desert + return /turf/floor/rock/sand /datum/random_map/noise/desert/get_additional_spawns(var/value, var/turf/T) var/val = min(9,max(0,round((value/cell_range)*10))) @@ -24,14 +24,14 @@ switch(val) if(2 to 3) if(prob(60)) - var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass) + var/grass_path = pick(subtypesof(/obj/structure/flora/grass)) new grass_path(T) if(prob(5)) - var/mob_type = pick(list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse)) + var/mob_type = pick(list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/passive/mouse, /mob/living/simple_animal/passive/mouse/rat)) new mob_type(T) if(5 to 6) if(prob(20)) - var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass) + var/grass_path = pick(subtypesof(/obj/structure/flora/grass)) new grass_path(T) if(7 to 9) if(prob(60)) diff --git a/code/modules/random_map/noise/forage.dm b/code/modules/random_map/noise/forage.dm new file mode 100644 index 000000000000..13977e05684e --- /dev/null +++ b/code/modules/random_map/noise/forage.dm @@ -0,0 +1,193 @@ +// These are foul, but apparent we can't reliably access z-level strata during +// SSmapping gen. Using /atom/movable so they don't show up in the mapper. + +/obj/item/stack/material/ore/basalt + is_spawnable_type = TRUE + material = /decl/material/solid/stone/basalt + +/obj/item/stack/material/ore/basalt/three + amount = 3 + +/obj/item/stack/material/ore/basalt/ten + amount = 10 + +/atom/movable/spawn_boulder + name = "material boulder spawner" + is_spawnable_type = FALSE + simulated = FALSE + var/spawn_type = /obj/structure/boulder/basalt + +/atom/movable/spawn_boulder/Initialize() + ..() + if(isturf(loc)) + if(islist(spawn_type)) + spawn_type = pickweight(spawn_type) + if(spawn_type) + new spawn_type(loc) + return INITIALIZE_HINT_QDEL + +/atom/movable/spawn_boulder/rock + name = "material rock spawner" + spawn_type = list( + /obj/item/stack/material/ore/basalt/three, + /obj/item/rock/basalt = 10, + /obj/item/rock/hematite = 1 + ) + +/datum/random_map/noise/forage + target_turf_type = null + var/list/forage = list( + "rocks" = list( + /atom/movable/spawn_boulder, + /atom/movable/spawn_boulder/rock + ), + "caves" = list( + "plumphelmet", + "glowbell", + "caverncandle", + "weepingmoon", + "towercap" + ), + "shallows" = list( + /obj/item/rock/flint, + "rice", + "mollusc", + "clam", + "sugarcane" + ), + "cave_shallows" = list( + /obj/item/rock/flint, + "algae", + "mollusc", + "clam" + ), + "grass" = list( + "carrot", + "berries", + "potato", + "cotton", + "nettle", + "ambrosiavulgaris", + "harebells", + "poppies", + "sunflowers", + "lavender", + "garlic", + "peppercorn", + "bamboo", + "coffee", + "tea" + ), + "riverbed" = list( + /obj/item/rock/flint, + // no rice, generally rice wants at most 10cm water + "mollusc", + "clam" + ) + ) + var/list/trees = list( + /obj/structure/flora/tree/hardwood/walnut = 9, + /obj/structure/flora/tree/dead/walnut = 1, + /obj/structure/flora/tree/hardwood/ebony = 1, + /obj/structure/flora/tree/dead/ebony = 1, + ) + var/list/cave_trees = list( + /obj/structure/flora/tree/softwood/towercap + ) + var/tree_weight = 0.35 + var/cave_tree_weight = 0.35 + var/forage_weight = 0.3 + var/cave_forage_weight = 0.3 + +/datum/random_map/noise/forage/New() + for(var/category in forage) + var/list/forage_seeds = forage[category] + for(var/forage_seed in forage_seeds) + if(ispath(forage_seed) || istype(forage_seed, /datum/seed)) + continue + forage_seeds -= forage_seed + var/datum/seed/seed_datum = SSplants.seeds[forage_seed] + if(istype(seed_datum)) + forage_seeds += seed_datum + else + log_error("Invalid seed name: [forage_seed]") + return ..() + +/datum/random_map/noise/forage/get_appropriate_path(value) + return + +// TODO: /decl system to handle different forage categories. +/datum/random_map/noise/forage/get_additional_spawns(value, turf/T) + if(!istype(T, /turf/floor)) + return + var/turf/floor/floor = T + var/decl/flooring/flooring = floor.get_topmost_flooring() + var/parse_value = noise2value(value) + var/place_prob + var/place_type + + if(floor.is_outside()) + + if(istype(flooring, /decl/flooring/rock)) + if(prob(15) && !floor.contains_dense_objects()) // Static as current map has limited amount of rock turfs + var/rock_type = SAFEPICK(forage["rocks"]) + new rock_type(floor) + return + + if(istype(flooring, /decl/flooring/grass)) + if(prob(parse_value * tree_weight)) + if(length(trees)) + var/tree_type = pickweight(trees) + new tree_type(floor) + return + place_prob = parse_value * forage_weight + place_type = SAFEPICK(forage["grass"]) + + if(istype(flooring, /decl/flooring/mud)) + switch(floor.get_fluid_depth()) + if(FLUID_OVER_MOB_HEAD to FLUID_MAX_DEPTH) + place_prob = parse_value * forage_weight + place_type = SAFEPICK(forage["riverbed"]) + if(FLUID_SLURRY to FLUID_OVER_MOB_HEAD) + place_prob = parse_value * forage_weight + place_type = SAFEPICK(forage["shallows"]) + else + place_prob = parse_value * forage_weight + place_type = SAFEPICK(forage["riverbank"]) // no entries by default, expanded on subtypes + + if(istype(flooring, /decl/flooring/snow)) + place_prob = parse_value * forage_weight + place_type = SAFEPICK(forage["snow"]) + + if(istype(flooring, /decl/flooring/dirt)) + place_prob = parse_value * forage_weight + place_type = SAFEPICK(forage["dirt"]) + + else + if(istype(flooring, /decl/flooring/mud)) + switch(floor.get_fluid_depth()) + if(FLUID_SLURRY to FLUID_OVER_MOB_HEAD) + place_prob = parse_value * cave_forage_weight + place_type = SAFEPICK(forage["cave_shallows"]) + if(0 to FLUID_SLURRY) + if(prob(parse_value * cave_tree_weight)) + if(length(cave_trees)) + var/tree_type = pick(cave_trees) + new tree_type(floor) + return + place_prob = parse_value * cave_forage_weight * 2 + place_type = SAFEPICK(forage["caves"]) + else if(istype(flooring, /decl/flooring/dirt)) + place_prob = parse_value * cave_forage_weight + place_type = SAFEPICK(forage["caves"]) + + if(place_type && prob(place_prob)) + if(istype(place_type, /datum/seed)) + new /obj/structure/flora/plant(floor, null, null, place_type) + for(var/stepdir in global.alldirs) + if(prob(15)) + var/turf/neighbor = get_step(floor, stepdir) + if(istype(neighbor, floor.type) && !(locate(/obj/structure/flora/plant) in neighbor)) + new /obj/structure/flora/plant(neighbor, null, null, place_type) + else if(ispath(place_type, /atom)) + new place_type(floor) diff --git a/code/modules/random_map/noise/magma.dm b/code/modules/random_map/noise/magma.dm index b52041aac9b3..f6130645dba3 100644 --- a/code/modules/random_map/noise/magma.dm +++ b/code/modules/random_map/noise/magma.dm @@ -3,31 +3,32 @@ /datum/random_map/noise/volcanism descriptor = "volcanism" smoothing_iterations = 6 - target_turf_type = /turf/simulated + target_turf_type = /turf/floor // Get rid of those dumb little single-tile volcanic areas. /datum/random_map/noise/volcanism/cleanup() for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/current_cell = TRANSLATE_COORD(x,y) if(map[current_cell] < 178) continue var/count - var/tmp_cell = get_map_cell(x+1,y+1) + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD(x+1, y+1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x-1,y-1) + TRANSLATE_AND_VERIFY_COORD(x-1,y-1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x+1,y-1) + TRANSLATE_AND_VERIFY_COORD(x+1,y-1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x-1,y+1) + TRANSLATE_AND_VERIFY_COORD(x-1,y+1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x-1,y) + TRANSLATE_AND_VERIFY_COORD(x-1,y) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x,y-1) + TRANSLATE_AND_VERIFY_COORD(x,y-1) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x+1,y) + TRANSLATE_AND_VERIFY_COORD(x+1,y) if(tmp_cell && map[tmp_cell] >= 178) count++ - tmp_cell = get_map_cell(x,y+1) + TRANSLATE_AND_VERIFY_COORD(x,y+1) if(tmp_cell && map[tmp_cell] >= 178) count++ if(!count) map[current_cell] = 177 @@ -37,8 +38,8 @@ /datum/random_map/noise/volcanism/get_additional_spawns(var/value, var/turf/T) if(value>=178) - if(istype(T,/turf/simulated/floor/asteroid)) - T.ChangeTurf(/turf/simulated/floor/airless/lava) - else if(istype(T,/turf/simulated/wall/natural)) - var/turf/simulated/wall/natural/M = T - M.floor_type = /turf/simulated/floor/airless/lava \ No newline at end of file + if(istype(T,/turf/floor)) + T.ChangeTurf(/turf/floor/lava) + else if(istype(T,/turf/wall/natural)) + var/turf/wall/natural/M = T + M.floor_type = /turf/floor/lava \ No newline at end of file diff --git a/code/modules/random_map/noise/noise.dm b/code/modules/random_map/noise/noise.dm index daecfdf67d32..91667bc86faf 100644 --- a/code/modules/random_map/noise/noise.dm +++ b/code/modules/random_map/noise/noise.dm @@ -4,14 +4,14 @@ /datum/random_map/noise descriptor = "distribution map" var/cell_range = 255 // These values are used to seed ore values rather than to determine a turf type. - var/cell_smooth_amt = 5 var/random_variance_chance = 25 // % chance of applying random_element. var/random_element = 0.5 // Determines the variance when smoothing out cell values. var/cell_base // Set in New() var/initial_cell_range // Set in New() var/smoothing_iterations = 0 + var/smooth_single_tiles // Single turfs of different value are not allowed -/datum/random_map/noise/New() +/datum/random_map/noise/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) initial_cell_range = cell_range/5 cell_base = cell_range/2 ..() @@ -19,10 +19,10 @@ /datum/random_map/noise/set_map_size() // Make sure the grid is a square with limits that are // (n^2)+1, otherwise diamond-square won't work. - if(!IsPowerOfTwo((limit_x-1))) - limit_x = RoundUpToPowerOfTwo(limit_x) + 1 - if(!IsPowerOfTwo((limit_y-1))) - limit_y = RoundUpToPowerOfTwo(limit_y) + 1 + if(!IS_POWER_OF_TWO((limit_x-1))) + limit_x = ROUND_UP_TO_POWER_OF_TWO(limit_x) + 1 + if(!IS_POWER_OF_TWO((limit_y-1))) + limit_y = ROUND_UP_TO_POWER_OF_TWO(limit_y) + 1 // Sides must be identical lengths. if(limit_x > limit_y) limit_y = limit_x @@ -52,60 +52,49 @@ if(isnull(val)) val = 0 return "[val]" +/datum/random_map/noise/proc/noise2value(var/value) + return min(9,max(0,round((value/cell_range)*10))) + /datum/random_map/noise/proc/subdivide(var/iteration,var/x,var/y,var/input_size) var/isize = input_size var/hsize = round(input_size/2) /* - (x,y+isize)----(x+hsize,y+isize)----(x+size,y+isize) + (x,y+isize)----(x+hsize,y+isize)----(x+isize,y+isize) | | | | | | | | | - (x,y+hsize)----(x+hsize,y+hsize)----(x+isize,y) + (x,y+hsize)----(x+hsize,y+hsize)----(x+isize,y+hsize) | | | | | | | | | (x,y)----------(x+hsize,y)----------(x+isize,y) */ + // Pre-halve them to prevent extra divisions. + var/topleft = map[TRANSLATE_COORD(x,y+isize)]/2 + var/topright = map[TRANSLATE_COORD(x+isize,y+isize)]/2 + var/bottomleft = map[TRANSLATE_COORD(x, y)]/2 + var/bottomright = map[TRANSLATE_COORD(x+isize,y)]/2 + // Central edge values become average of corners. - map[TRANSLATE_COORD(x+hsize,y+isize)] = round((\ - map[TRANSLATE_COORD(x,y+isize)] + \ - map[TRANSLATE_COORD(x+isize,y+isize)] \ - )/2) - - map[TRANSLATE_COORD(x+hsize,y)] = round(( \ - map[TRANSLATE_COORD(x,y)] + \ - map[TRANSLATE_COORD(x+isize,y)] \ - )/2) - - map[get_map_cell(x,y+hsize)] = round(( \ - map[TRANSLATE_COORD(x,y+isize)] + \ - map[TRANSLATE_COORD(x,y)] \ - )/2) - - map[TRANSLATE_COORD(x+isize,y+hsize)] = round(( \ - map[TRANSLATE_COORD(x+isize,y+isize)] + \ - map[TRANSLATE_COORD(x+isize,y)] \ - )/2) + map[TRANSLATE_COORD(x+hsize,y+isize)] = round(topleft + topright) // top = topleft + topright + map[TRANSLATE_COORD(x+hsize,y)] = round(bottomleft + bottomright) // bottom = bottomleft + bottomright + map[TRANSLATE_COORD(x,y+hsize)] = round(topleft + bottomleft) // left = topleft + bottomleft + map[TRANSLATE_COORD(x+isize,y+hsize)] = round(topright + bottomright) // right = topright + bottomright // Centre value becomes the average of all other values + possible random variance. var/current_cell = TRANSLATE_COORD(x+hsize,y+hsize) - map[current_cell] = round(( \ - map[TRANSLATE_COORD(x+hsize,y+isize)] + \ - map[TRANSLATE_COORD(x+hsize,y)] + \ - map[TRANSLATE_COORD(x,y+hsize)] + \ - map[TRANSLATE_COORD(x+isize,y)] \ - )/4) + // yes, this is equivalent to the prior averaging. it just avoids more list indexing + map[current_cell] = round(round(topleft+topright)/4 + round(bottomleft + bottomright)/4 + round(topleft + bottomleft)/4 + round(topright + bottomright)/4) if(prob(random_variance_chance)) - map[current_cell] *= (rand(1,2)==1 ? (1.0-random_element) : (1.0+random_element)) + map[current_cell] *= (prob(50) ? (1.0-random_element) : (1.0+random_element)) map[current_cell] = max(0,min(cell_range,map[current_cell])) // Recurse until size is too small to subdivide. if(isize>3) - if(!priority_process) - CHECK_TICK + CHECK_TICK iteration++ subdivide(iteration, x, y, hsize) subdivide(iteration, x+hsize, y, hsize) @@ -113,55 +102,100 @@ subdivide(iteration, x+hsize, y+hsize, hsize) /datum/random_map/noise/cleanup() - var/is_not_border_left - var/is_not_border_right for(var/i = 1 to smoothing_iterations) - var/list/next_map[limit_x*limit_y] + // var/list/next_map[limit_x*limit_y] + // simple box blur from http://amritamaz.net/blog/understanding-box-blur + // basically: we do two very fast one-dimensional blurs + var/total + for(var/y = 1 to limit_y) // for each row + // init window for x=1 + // for a blur with a radius >1 use a for loop instead and replace 2 with the real count + var/first_coord = TRANSLATE_COORD(1, y) + var/second_coord = TRANSLATE_COORD(2, y) + var/cellone = map[first_coord] + var/celltwo = map[second_coord] + total = cellone + celltwo + map[first_coord] = round(total / 2) + // hardcoding x=2 also, to lower checks in the loop + // larger radius would need to also cover all x < 1 + blur_radius + total += map[TRANSLATE_COORD(3, y)] + map[second_coord] = round(total / 3) + for(var/x = 3 to limit_x-1) // should technically be 2 + blur_radius to limit_x - blur_radius + total -= map[TRANSLATE_COORD(x-2, y)] // x - blur_radius - 1 + total += map[TRANSLATE_COORD(x+1, y)] // x + blur_radius + map[TRANSLATE_COORD(x, y)] = round(total / 3) // should technically be 2*blur_radius+1 + // now do the same in the x axis + // map = next_map.Copy() for(var/x = 1 to limit_x) - for(var/y = 1 to limit_y) - var/current_cell = TRANSLATE_COORD(x,y) - next_map[current_cell] = map[current_cell] - var/val_count = 1 - var/total = map[current_cell] - - is_not_border_left = (x != 1) - is_not_border_right = (x != limit_x) - - // Center row. Center value's already been done above. - if (is_not_border_left) - total += map[TRANSLATE_COORD(x - 1, y)] - ++val_count - if (is_not_border_right) - total += map[TRANSLATE_COORD(x + 1, y)] - ++val_count - - if (y != 1) // top row - total += map[TRANSLATE_COORD(x, y - 1)] - ++val_count - if (is_not_border_left) - total += map[TRANSLATE_COORD(x - 1, y - 1)] - ++val_count - if (is_not_border_right) - total += map[TRANSLATE_COORD(x + 1, y - 1)] - ++val_count - - if (y != limit_y) // bottom row - total += map[TRANSLATE_COORD(x, y + 1)] - ++val_count - if (is_not_border_left) - total += map[TRANSLATE_COORD(x - 1, y + 1)] - ++val_count - if (is_not_border_right) - total += map[TRANSLATE_COORD(x + 1, y + 1)] - ++val_count - - total = round(total/val_count) - - if(abs(map[current_cell]-total) <= cell_smooth_amt) - map[current_cell] = total - else if(map[current_cell] < total) - map[current_cell]+=cell_smooth_amt - else if(map[current_cell] < total) - map[current_cell]-=cell_smooth_amt - map[current_cell] = max(0,min(cell_range,map[current_cell])) - map = next_map \ No newline at end of file + // see comments above + var/first_coord = TRANSLATE_COORD(x, 1) + var/second_coord = TRANSLATE_COORD(x, 2) + var/cellone = map[first_coord] + var/celltwo = map[second_coord] + total = cellone + celltwo + map[first_coord] = round(total / 2) + // hardcoding x=2 also, to lower checks in the loop + // larger radius would need to also cover all x < 1 + blur_radius + total += map[TRANSLATE_COORD(x, 3)] + map[second_coord] = round(total / 3) + for(var/y = 3 to limit_y-1) + total -= map[TRANSLATE_COORD(x, y-2)] + total += map[TRANSLATE_COORD(x, y+1)] + map[TRANSLATE_COORD(x, y)] = round(total / 3) + // map = next_map + CHECK_TICK + + if(smooth_single_tiles) + for(var/x in 1 to limit_x - 1) + for(var/y in 1 to limit_y - 1) + var/mapcell = TRANSLATE_COORD(x,y) + if(has_neighbor_with_path(x, y, get_appropriate_path(map[mapcell]), TRUE)) + continue + map[mapcell] = map[pick(get_neighbors(x, y, TRUE))] + CHECK_TICK + +#define CHECK_NEIGHBOR_FOR_PATH(X, Y) \ + TRANSLATE_AND_VERIFY_COORD(X,Y);\ + if(tmp_cell && (get_appropriate_path(map[tmp_cell]) == path)) {\ + return TRUE;\ + } + +/// Checks if the cell at x,y has a neighbor with the given path. +/// Faster than looping over get_neighbors for the same purpose because it doesn't use list ops. +/datum/random_map/noise/proc/has_neighbor_with_path(x, y, path, include_diagonals) + var/tmp_cell + CHECK_NEIGHBOR_FOR_PATH(x-1,y) + CHECK_NEIGHBOR_FOR_PATH(x+1,y) + CHECK_NEIGHBOR_FOR_PATH(x,y+1) + CHECK_NEIGHBOR_FOR_PATH(x,y-1) + if(include_diagonals) + CHECK_NEIGHBOR_FOR_PATH(x+1,y+1) + CHECK_NEIGHBOR_FOR_PATH(x+1,y-1) + CHECK_NEIGHBOR_FOR_PATH(x-1,y-1) + CHECK_NEIGHBOR_FOR_PATH(x-1,y+1) + return FALSE + +#undef CHECK_NEIGHBOR_FOR_PATH + +#define VERIFY_AND_ADD_CELL(X, Y) \ + TRANSLATE_AND_VERIFY_COORD(X,Y);\ + if(tmp_cell) {\ + . += tmp_cell;\ + } + +/// Gets the neighbors of the cell at x, y, optionally including diagonals. +/// (x,y) and its neighbors can safely be invalid/not validated before calling. +/datum/random_map/noise/proc/get_neighbors(x, y, include_diagonals) + . = list() + var/tmp_cell + VERIFY_AND_ADD_CELL(x-1,y) + VERIFY_AND_ADD_CELL(x+1,y) + VERIFY_AND_ADD_CELL(x,y+1) + VERIFY_AND_ADD_CELL(x,y-1) + if(include_diagonals) + VERIFY_AND_ADD_CELL(x+1,y+1) + VERIFY_AND_ADD_CELL(x+1,y-1) + VERIFY_AND_ADD_CELL(x-1,y-1) + VERIFY_AND_ADD_CELL(x-1,y+1) + +#undef VERIFY_AND_ADD_CELL \ No newline at end of file diff --git a/code/modules/random_map/noise/ore.dm b/code/modules/random_map/noise/ore.dm index b943189433a7..3f61d35d3b1e 100644 --- a/code/modules/random_map/noise/ore.dm +++ b/code/modules/random_map/noise/ore.dm @@ -8,36 +8,36 @@ var/min_deep_ratio = MIN_DEEP_COUNT_PER_CHUNK var/list/surface_metals = list( - /decl/material/solid/metal/iron = list(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX), - /decl/material/solid/metal/aluminium = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), - /decl/material/solid/metal/gold = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), - /decl/material/solid/metal/silver = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), - /decl/material/solid/metal/uranium = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX) + /decl/material/solid/metal/iron = list(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX), + /decl/material/solid/metal/aluminium = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), + /decl/material/solid/metal/gold = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), + /decl/material/solid/metal/silver = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), + /decl/material/solid/metal/uranium = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX) ) var/list/rare_metals = list( - /decl/material/solid/metal/gold = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), - /decl/material/solid/metal/silver = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), - /decl/material/solid/metal/uranium = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), - /decl/material/solid/metal/osmium = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), - /decl/material/solid/mineral/rutile = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX) + /decl/material/solid/metal/gold = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), + /decl/material/solid/metal/silver = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), + /decl/material/solid/metal/uranium = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), + /decl/material/solid/metal/osmium = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), + /decl/material/solid/rutile = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX) ) var/list/deep_metals = list( - /decl/material/solid/metal/uranium = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), - /decl/material/solid/gemstone/diamond = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), - /decl/material/solid/metal/osmium = list(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX), - /decl/material/solid/metallic_hydrogen = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), - /decl/material/solid/mineral/rutile = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX) + /decl/material/solid/metal/uranium = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), + /decl/material/solid/gemstone/diamond = list(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX), + /decl/material/solid/metal/osmium = list(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX), + /decl/material/solid/metallic_hydrogen = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX), + /decl/material/solid/rutile = list(RESOURCE_MID_MIN, RESOURCE_MID_MAX) ) var/list/common_resources = list( - /decl/material/solid/mineral/sand = list(3,5), - /decl/material/solid/mineral/clay = list(3,5), - /decl/material/solid/mineral/graphite = list(3,5) + /decl/material/solid/sand = list(RESOURCE_COMMON_MIN, RESOURCE_COMMON_MAX), + /decl/material/solid/clay = list(RESOURCE_COMMON_MIN, RESOURCE_COMMON_MAX), + /decl/material/solid/graphite = list(RESOURCE_COMMON_MIN, RESOURCE_COMMON_MAX) ) -/datum/random_map/noise/ore/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/never_be_priority = 0) +/datum/random_map/noise/ore/New(var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce, var/used_area) rare_val = cell_range * rare_val deep_val = cell_range * deep_val - ..(seed, tx, ty, tz, (tlx / chunk_size), (tly / chunk_size), do_not_apply, do_not_announce, never_be_priority) + ..(tx / chunk_size, ty / chunk_size, tz, (tlx / chunk_size), (tly / chunk_size), do_not_apply, do_not_announce) /datum/random_map/noise/ore/check_map_sanity() @@ -70,37 +70,42 @@ return 1 /datum/random_map/noise/ore/apply_to_turf(var/x,var/y) + . = list() var/tx = ((origin_x-1)+x)*chunk_size var/ty = ((origin_y-1)+y)*chunk_size for(var/i=0,iGenerating [name].", R_DEBUG) - CHECK_TICK - - // Testing needed to see how reliable this is (asynchronous calls, called during worldgen), DM ref is not optimistic - if(seed) - rand_seed(seed) - priority_process = !never_be_priority + if(!do_not_announce) + admin_notice("Generating [name].", R_DEBUG) for(var/i = 0;i[capitalize(name)] generation completed in [round(0.1*(world.timeofday-start_time),0.1)] seconds.", R_DEBUG) - return - if(!do_not_announce) admin_notice("[capitalize(name)] failed to generate ([round(0.1*(world.timeofday-start_time),0.1)] seconds): could not produce sane map.", R_DEBUG) + . = TRUE + break -/datum/random_map/proc/get_map_cell(var/x,var/y) - if(!map) - set_map_size() - . = ((y-1)*limit_x)+x - if((. < 1) || (. > map.len)) - return null + if(!do_not_announce) + if(.) + admin_notice(SPAN_DANGER("[capitalize(name)] generation completed in [round(0.1*(world.timeofday-start_time),0.1)] seconds."), R_DEBUG) + else + admin_notice(SPAN_DANGER("[capitalize(name)] failed to generate ([round(0.1*(world.timeofday-start_time),0.1)] seconds): could not produce sane map."), R_DEBUG) /datum/random_map/proc/get_map_char(var/value) switch(value) @@ -102,37 +100,36 @@ var/global/list/map_count = list() else return " " -/datum/random_map/proc/display_map(atom/user) - +/datum/random_map/proc/display_map(user) if(!user) user = world - var/dat = "+------+
    " - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + var/dat = list("+------+
    ") + for(var/x in 1 to limit_x) + for(var/y in 1 to limit_y) + var/current_cell = TRANSLATE_COORD(x,y) if(current_cell) dat += get_map_char(map[current_cell]) dat += "
    " - to_chat(user, "[dat]+------+
    ") + dat += "+------+
    " + to_chat(user, JOINTEXT(dat)) /datum/random_map/proc/set_map_size() - map = list() - map.len = limit_x * limit_y + map = new /list(limit_x * limit_y) /datum/random_map/proc/seed_map() - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + for(var/x in 1 to limit_x) + for(var/y in 1 to limit_y) + var/current_cell = TRANSLATE_COORD(x,y) if(prob(initial_wall_cell)) map[current_cell] = WALL_CHAR else map[current_cell] = initial_cell_char /datum/random_map/proc/clear_map() - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - map[get_map_cell(x,y)] = 0 + for(var/x in 1 to limit_x) + for(var/y in 1 to limit_y) + map[TRANSLATE_COORD(x,y)] = 0 /datum/random_map/proc/generate() seed_map() @@ -140,7 +137,9 @@ var/global/list/map_count = list() if(check_map_sanity()) cleanup() if(auto_apply) + Master.StartLoadingMap() apply_to_map() + Master.StopLoadingMap() return 1 return 0 @@ -160,27 +159,23 @@ var/global/list/map_count = list() if(!origin_x) origin_x = 1 if(!origin_y) origin_y = 1 if(!origin_z) origin_z = 1 - - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - if(!priority_process) - CHECK_TICK + for(var/x in 1 to limit_x) + for(var/y in 1 to limit_y) + CHECK_TICK apply_to_turf(x,y) /datum/random_map/proc/apply_to_turf(var/x,var/y) - var/current_cell = get_map_cell(x,y) - if(!current_cell) + var/current_cell = TRANSLATE_COORD(x,y) + if(!current_cell || current_cell > length(map)) return 0 var/turf/T = locate((origin_x-1)+x,(origin_y-1)+y,origin_z) if(!T || (target_turf_type && !istype(T,target_turf_type))) return 0 var/newpath = get_appropriate_path(map[current_cell]) - if(newpath) - T.ChangeTurf(newpath) - get_additional_spawns(map[current_cell],T,get_spawn_dir(x, y)) + . = (newpath && !istype(T, newpath)) ? T.ChangeTurf(newpath) : T + get_additional_spawns(map[current_cell], ., get_spawn_dir(x, y)) if(use_area) - ChangeArea(T, use_area) - return T + ChangeArea(., use_area) /datum/random_map/proc/get_spawn_dir() return 0 @@ -193,8 +188,7 @@ var/global/list/map_count = list() return wall_type /datum/random_map/proc/get_additional_spawns(var/value, var/turf/T) - if(value == DOOR_CHAR) - new /obj/machinery/door/airlock(T) + // e.g. if(value == DOOR_CHAR) new /obj/machinery/door/airlock(T) /datum/random_map/proc/cleanup() return @@ -204,16 +198,19 @@ var/global/list/map_count = list() return tx-- // Update origin so that x/y index ty-- // doesn't push it off-kilter by one. - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) + for(var/x in 1 to limit_x) + for(var/y in 1 to limit_y) + var/current_cell = TRANSLATE_COORD(x,y) if(!current_cell) continue if(tx+x > target_map.limit_x) continue if(ty+y > target_map.limit_y) continue - target_map.map[target_map.get_map_cell(tx+x,ty+y)] = map[current_cell] + var/tmp_cell + TRANSLATE_AND_VERIFY_COORD_MLEN(tx+x, ty+y, target_map.map.len) + if(tmp_cell) + target_map.map[tmp_cell] = map[current_cell] handle_post_overlay_on(target_map,tx,ty) diff --git a/code/modules/random_map/random_map_verbs.dm b/code/modules/random_map/random_map_verbs.dm index f94bcd458948..327cd285e35e 100644 --- a/code/modules/random_map/random_map_verbs.dm +++ b/code/modules/random_map/random_map_verbs.dm @@ -36,18 +36,17 @@ if(!holder) return - var/map_datum = input("Choose a map to create.") as null|anything in typesof(/datum/random_map)-/datum/random_map + var/map_datum = input("Choose a map to create.") as null|anything in subtypesof(/datum/random_map) if(!map_datum) return var/datum/random_map/M if(alert("Do you wish to customise the map?",,"Yes","No") == "Yes") - var/seed = input("Seed? (blank for none)") as text|null var/lx = input("X-size? (blank for default)") as num|null var/ly = input("Y-size? (blank for default)") as num|null - M = new map_datum(seed,null,null,null,lx,ly,1) + M = new map_datum(null,null,null,lx,ly,TRUE) else - M = new map_datum(null,null,null,null,null,null,1) + M = new map_datum(null,null,null,null,null,TRUE) if(M) message_admins("[key_name_admin(usr)] has created [M.name].") diff --git a/code/modules/reagents/Chemistry-Colours.dm b/code/modules/reagents/Chemistry-Colours.dm index 4bdd24a77b17..16d5d8ad9d62 100644 --- a/code/modules/reagents/Chemistry-Colours.dm +++ b/code/modules/reagents/Chemistry-Colours.dm @@ -1,22 +1,22 @@ /datum/reagents/proc/get_color() - if(!LAZYLEN(reagent_volumes)) - return "#ffffffff" - if(LAZYLEN(reagent_volumes) == 1) // It's pretty common and saves a lot of work - var/decl/material/R = decls_repository.get_decl(reagent_volumes[1]) - return R.color + num2hex(R.opacity * 255) - - var/list/colors = list(0, 0, 0, 0) - var/tot_w = 0 - for(var/rtype in reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - if(R.color_weight <= 0) - continue - var/hex = uppertext(R.color) + num2hex(R.opacity * 255) - var/mod = REAGENT_VOLUME(src, rtype) * R.color_weight - colors[1] += HEX_RED(hex) * mod - colors[2] += HEX_GREEN(hex) * mod - colors[3] += HEX_BLUE(hex) * mod - colors[4] += HEX_ALPHA(hex) * mod - tot_w += mod - - return rgb(colors[1] / tot_w, colors[2] / tot_w, colors[3] / tot_w, colors[4] / tot_w) \ No newline at end of file + if(!cached_color) + if(!LAZYLEN(reagent_volumes)) + cached_color = "#ffffffff" + else if(LAZYLEN(reagent_volumes) == 1) // It's pretty common and saves a lot of work + var/decl/material/reagent = reagent_volumes[1] + cached_color = reagent.get_reagent_color(src) + num2hex(reagent.opacity * 255) + else + var/list/colors = list(0, 0, 0, 0) + var/tot_w = 0 + for(var/decl/material/reagent as anything in reagent_volumes) + if(reagent.color_weight <= 0) + continue + var/hex = uppertext(reagent.get_reagent_color(src)) + num2hex(reagent.opacity * 255) + var/mod = REAGENT_VOLUME(src, reagent) * reagent.color_weight + colors[1] += HEX_RED(hex) * mod + colors[2] += HEX_GREEN(hex) * mod + colors[3] += HEX_BLUE(hex) * mod + colors[4] += HEX_ALPHA(hex) * mod + tot_w += mod + cached_color = rgb(colors[1] / tot_w, colors[2] / tot_w, colors[3] / tot_w, colors[4] / tot_w) + return cached_color \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Grinder.dm b/code/modules/reagents/Chemistry-Grinder.dm index cd558f8b7d3e..d71b5f24b7e6 100644 --- a/code/modules/reagents/Chemistry-Grinder.dm +++ b/code/modules/reagents/Chemistry-Grinder.dm @@ -16,8 +16,8 @@ var/list/holdingitems = list() var/list/bag_whitelist = list( - /obj/item/storage/pill_bottle, - /obj/item/storage/plants + /obj/item/pill_bottle, + /obj/item/plant_satchel ) var/blacklisted_types = list() var/item_size_limit = ITEM_SIZE_HUGE @@ -41,23 +41,23 @@ else icon_state = "[initial(icon_state)]" -/obj/machinery/reagentgrinder/attackby(var/obj/item/O, var/mob/user) +/obj/machinery/reagentgrinder/attackby(var/obj/item/used_item, var/mob/user) if((. = ..())) return - if(!istype(O)) + if(!istype(used_item)) return FALSE - if (istype(O,/obj/item/chems/glass) || \ - istype(O,/obj/item/chems/food/drinks/glass2) || \ - istype(O,/obj/item/chems/food/drinks/shaker)) + if (istype(used_item,/obj/item/chems/glass) || \ + istype(used_item,/obj/item/chems/drinks/glass2) || \ + istype(used_item,/obj/item/chems/drinks/shaker)) - if (beaker) + if(beaker) return TRUE else - if(!user.unEquip(O, src)) + if(!user.try_unequip(used_item, src)) return FALSE - beaker = O + beaker = used_item update_icon() SSnano.update_uis(src) return FALSE @@ -66,52 +66,52 @@ to_chat(user, SPAN_NOTICE("\The [src] cannot hold any additional items.")) return TRUE - if(is_type_in_list(O, blacklisted_types)) - to_chat(user, SPAN_NOTICE("\The [src] cannot grind \the [O].")) + if(is_type_in_list(used_item, blacklisted_types)) + to_chat(user, SPAN_NOTICE("\The [src] cannot grind \the [used_item].")) return FALSE - if(is_type_in_list(O, bag_whitelist)) - var/obj/item/storage/bag = O - var/failed = TRUE - for(var/obj/item/G in O) - if(!G.reagents || !G.reagents.total_volume) - continue - failed = FALSE - bag.remove_from_storage(G, src) - holdingitems += G - if(LAZYLEN(holdingitems) >= limit) - break + if(is_type_in_list(used_item, bag_whitelist)) + if(used_item.storage) + var/failed = TRUE + for(var/obj/item/G in used_item) + if(!G.reagents || !REAGENT_TOTAL_VOLUME(G.reagents)) + continue + failed = FALSE + used_item.storage.remove_from_storage(user, G, src) + holdingitems += G + if(LAZYLEN(holdingitems) >= limit) + break + + if(failed) + to_chat(user, SPAN_NOTICE("Nothing in \the [used_item] is usable.")) + return TRUE + used_item.storage.finish_bulk_removal() + + if(!length(used_item.contents)) + to_chat(user, "You empty \the [used_item] into \the [src].") + else + to_chat(user, "You fill \the [src] from \the [used_item].") - if(failed) - to_chat(user, SPAN_NOTICE("Nothing in \the [O] is usable.")) - return TRUE - bag.finish_bulk_removal() - - if(!length(O.contents)) - to_chat(user, "You empty \the [O] into \the [src].") - else - to_chat(user, "You fill \the [src] from \the [O].") - - SSnano.update_uis(src) - return FALSE + SSnano.update_uis(src) + return FALSE - if(O.w_class > item_size_limit) - to_chat(user, SPAN_NOTICE("\The [src] cannot fit \the [O].")) + if(used_item.w_class > item_size_limit) + to_chat(user, SPAN_NOTICE("\The [src] cannot fit \the [used_item].")) return - if(istype(O,/obj/item/stack/material)) - var/decl/material/material = O.get_material() - if(!material) - to_chat(user, SPAN_NOTICE("\The [material.solid_name] cannot be ground down to any usable reagents.")) + if(istype(used_item,/obj/item/stack/material)) + var/decl/material/grind_material = used_item.get_material() + if(!grind_material) + to_chat(user, SPAN_NOTICE("\The [grind_material.solid_name] cannot be ground down to any usable reagents.")) return TRUE - else if(!O.reagents?.total_volume) - to_chat(user, SPAN_NOTICE("\The [O] is not suitable for grinding.")) + else if(!REAGENT_TOTAL_VOLUME(used_item.reagents)) + to_chat(user, SPAN_NOTICE("\The [used_item] is not suitable for grinding.")) return TRUE - if(!user.unEquip(O, src)) + if(!user.try_unequip(used_item, src)) return FALSE - holdingitems += O + holdingitems += used_item SSnano.update_uis(src) return FALSE @@ -120,7 +120,7 @@ return TRUE /obj/machinery/reagentgrinder/DefaultTopicState() - return GLOB.physical_state + return global.physical_topic_state /obj/machinery/reagentgrinder/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/list/data = list() @@ -128,14 +128,13 @@ data["beaker"] = !!beaker data["contents"] = list() - for(var/obj/item/O in holdingitems) - data["contents"] += "[capitalize(O.name)]" + for(var/obj/item/thing in holdingitems) + data["contents"] += "[capitalize(thing.name)]" data["beakercontents"] = list() if(beaker?.reagents) - for(var/rtype in beaker.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - data["beakercontents"] += "[capitalize(R.name)] ([REAGENT_VOLUME(beaker.reagents, rtype)]u)" + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(beaker.reagents)) + data["beakercontents"] += "[capitalize(reagent.get_reagent_name(beaker.reagents))] ([REAGENT_VOLUME(beaker.reagents, reagent)]u)" ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) @@ -171,9 +170,9 @@ if (!LAZYLEN(holdingitems)) return FALSE - for(var/obj/item/O in holdingitems) - O.dropInto(loc) - holdingitems -= O + for(var/obj/item/thing in holdingitems) + thing.dropInto(loc) + holdingitems -= thing holdingitems.Cut() /obj/machinery/reagentgrinder/proc/grind(mob/user) @@ -183,7 +182,7 @@ return FALSE // Sanity check. - if (!beaker || (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) + if (!beaker || (REAGENT_TOTAL_VOLUME(beaker.reagents) >= REAGENT_MAXIMUM_VOLUME(beaker.reagents))) return FALSE attempt_skill_effect(user) @@ -192,45 +191,45 @@ update_icon() // Reset the machine. - addtimer(CALLBACK(src, .proc/end_grind, user), 6 SECONDS, TIMER_UNIQUE) + addtimer(CALLBACK(src, PROC_REF(end_grind), user), 6 SECONDS, TIMER_UNIQUE) var/skill_factor = CLAMP01(1 + 0.3*(user.get_skill_value(skill_to_check) - SKILL_EXPERT)/(SKILL_EXPERT - SKILL_MIN)) // Process. - for (var/obj/item/O in holdingitems) + for (var/obj/item/thing in holdingitems) - var/remaining_volume = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/remaining_volume = REAGENT_MAXIMUM_VOLUME(beaker.reagents) - REAGENT_TOTAL_VOLUME(beaker.reagents) if(remaining_volume <= 0) break - var/obj/item/stack/material/stack = O + var/obj/item/stack/material/stack = thing if(istype(stack)) - var/decl/material/material = stack.get_material() - if(!material) + var/decl/material/grind_material = stack.get_material() + if(!grind_material) break - var/amount_to_take = max(0,min(stack.amount, Floor(remaining_volume / REAGENT_UNITS_PER_MATERIAL_SHEET))) + var/amount_to_take = max(0,min(stack.amount, floor(remaining_volume / REAGENT_UNITS_PER_MATERIAL_SHEET))) if(amount_to_take) stack.use(amount_to_take) if(QDELETED(stack)) holdingitems -= stack - beaker.reagents.add_reagent(material.type, (amount_to_take * REAGENT_UNITS_PER_MATERIAL_SHEET * skill_factor)) + beaker.add_to_reagents(grind_material.type, (amount_to_take * REAGENT_UNITS_PER_MATERIAL_SHEET * skill_factor)) continue - else if(O.reagents) - O.reagents.trans_to(beaker, O.reagents.total_volume, skill_factor) - holdingitems -= O - qdel(O) + else if(thing.reagents) + thing.reagents.trans_to(beaker, REAGENT_TOTAL_VOLUME(thing.reagents), skill_factor) + holdingitems -= thing + qdel(thing) /obj/machinery/reagentgrinder/proc/end_grind(mob/user) inuse = FALSE if(CanPhysicallyInteractWith(user, src)) interface_interact(user) -/obj/machinery/reagentgrinder/proc/attempt_skill_effect(mob/living/carbon/human/user) +/obj/machinery/reagentgrinder/proc/attempt_skill_effect(mob/living/human/user) if(!istype(user) || !prob(user.skill_fail_chance(skill_to_check, 50, SKILL_BASIC))) return FALSE var/hand = pick(BP_L_HAND, BP_R_HAND) - var/obj/item/organ/external/hand_organ = user.get_organ(hand) + var/obj/item/organ/external/hand_organ = GET_EXTERNAL_ORGAN(user, hand) if(!hand_organ) return FALSE @@ -238,23 +237,23 @@ user.visible_message(SPAN_DANGER("\The [user]'s hand gets caught in \the [src]!"), SPAN_DANGER("Your hand gets caught in \the [src]!")) user.apply_damage(dam, BRUTE, hand, damage_flags = DAM_SHARP, used_weapon = "grinder") if(BP_IS_PROSTHETIC(hand_organ)) - beaker.reagents.add_reagent(/decl/material/solid/metal/iron, dam) + beaker.add_to_reagents(/decl/material/solid/metal/iron, dam) else user.take_blood(beaker, dam) - user.Stun(2) - shake(user, 40) + SET_STATUS_MAX(user, STAT_STUN, 2) + shake_target(user, 4 SECONDS) -/obj/machinery/reagentgrinder/proc/shake(mob/user, duration) +/obj/machinery/reagentgrinder/proc/shake_target(mob/living/user, duration) if(!user) return for(var/i = 1 to duration) sleep(1) if(!Adjacent(user)) break - if(!user.is_jittery) + if(!HAS_STATUS(user, STAT_JITTER)) user.do_jitter(4) - if(!user.is_jittery) + if(!HAS_STATUS(user, STAT_JITTER)) user.do_jitter(0) /obj/machinery/reagentgrinder/juicer @@ -266,13 +265,13 @@ obj_flags = null grind_sound = 'sound/machines/juicer.ogg' blacklisted_types = list(/obj/item/stack/material) - bag_whitelist = list(/obj/item/storage/plants) + bag_whitelist = list(/obj/item/plant_satchel) item_size_limit = ITEM_SIZE_SMALL skill_to_check = SKILL_COOKING -/obj/machinery/reagentgrinder/juicer/attempt_skill_effect(mob/living/carbon/human/user) +/obj/machinery/reagentgrinder/juicer/attempt_skill_effect(mob/living/human/user) if(!istype(user) || !prob(user.skill_fail_chance(skill_to_check, 50, SKILL_BASIC))) return visible_message(SPAN_NOTICE("\The [src] whirrs violently and spills its contents all over \the [user]!")) if(beaker?.reagents) - beaker.reagents.splash(user, beaker.reagents.total_volume) \ No newline at end of file + beaker.reagents.splash(user, REAGENT_TOTAL_VOLUME(beaker.reagents)) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index c486f65e2462..2f03bcaf2a23 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -1,282 +1,657 @@ -GLOBAL_DATUM_INIT(temp_reagents_holder, /obj, new) +var/global/obj/temp_reagents_holder = new +var/global/datum/reagents/sink/infinite_reagent_sink = new + +/atom/proc/add_to_reagents(decl/material/reagent, amount, data, safety = FALSE, defer_update = FALSE, phase = null) + return reagents?.add_reagent(reagent, amount, data, safety, defer_update, phase) + +/atom/proc/remove_from_reagents(decl/material/reagent, amount, safety = FALSE, defer_update = FALSE) + return reagents?.remove_reagent(reagent, amount, safety, defer_update) + +/atom/proc/remove_any_reagents(amount = 1, defer_update = FALSE, removed_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID), skip_reagents = null) + return reagents?.remove_any(amount, defer_update, removed_phases, skip_reagents) + +/// Adds reagents, but contaminated. A fraction of `amount` is replaced with `contaminant_type` according to `contaminant_proportion`. +/// Handles null contaminant_type and zero contaminant_proportion, but it's probably faster to check before you call this. +/atom/proc/add_to_reagents_contaminated(reagent_type, amount, data, contaminant_type = null, contaminant_proportion = 0, safety = FALSE, defer_update = FALSE, phase = null) + var/contaminant_to_add = 0 + if(contaminant_type) + contaminant_to_add = CHEMS_QUANTIZE(amount * contaminant_proportion) + add_to_reagents(reagent_type, amount - contaminant_to_add, data, safety = safety, defer_update = !!contaminant_to_add, phase = MAT_PHASE_LIQUID) + if(contaminant_to_add) + add_to_reagents(contaminant_type, contaminant_to_add, phase = MAT_PHASE_LIQUID) + +/atom/proc/get_reagent_space() + if(!REAGENT_MAXIMUM_VOLUME(reagents)) + return 0 + return REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents) + +/atom/proc/get_reagents() + return reagents +/atom/proc/take_waste_burn_products(list/materials, exposed_temperature, ambient_pressure) + + // This might not be needed. Leaving it in for safety. + var/turf/T = get_turf(src) + if(T != src) + return T?.take_waste_burn_products(materials, exposed_temperature, ambient_pressure) + + var/datum/reagents/liquids + var/datum/gas_mixture/vapor + var/obj/item/debris/scraps/scraps + for(var/mat in materials) + var/amount = materials[mat] + var/decl/material/burn_material = GET_DECL(mat) + switch(burn_material.phase_at_temperature(exposed_temperature, ambient_pressure)) + + if(MAT_PHASE_SOLID) + if(!scraps) + scraps = (locate() in src) || new(src) + LAZYINITLIST(scraps.matter) + scraps.matter[mat] += amount + + if(MAT_PHASE_LIQUID) + if(!liquids) + liquids = get_reagents() + liquids?.add_reagent(mat, max(1, round(amount * REAGENT_UNITS_PER_MATERIAL_UNIT)), defer_update = TRUE) + + if(MAT_PHASE_GAS) + if(!vapor) + vapor = return_air() + vapor?.adjust_gas_temp(mat, MOLES_PER_MATERIAL_UNIT(amount), exposed_temperature, update = FALSE) + + if(scraps) + UNSETEMPTY(scraps.matter) + scraps.update_primary_material() + vapor?.update_values() + liquids?.update_total() + +// These vars are privated due to the potential for reagents to be either null, a list, or a datum. +// Always use the REAGENT_FOO macros! /datum/reagents - var/primary_reagent - var/list/reagent_volumes - var/list/reagent_data - var/total_volume = 0 - var/maximum_volume = 120 - var/atom/my_atom - var/cached_color + VAR_PRIVATE/list/reagent_volumes + VAR_PRIVATE/list/liquid_volumes + VAR_PRIVATE/list/solid_volumes // This should be taken as powders/flakes, rather than large solid pieces of material. + VAR_PRIVATE/list/reagent_data + VAR_PRIVATE/atom/my_atom + VAR_PRIVATE/maximum_volume = 120 + VAR_PRIVATE/tmp/cached_color + VAR_PRIVATE/tmp/primary_reagent + VAR_PRIVATE/tmp/primary_solid + VAR_PRIVATE/tmp/primary_liquid + VAR_PRIVATE/tmp/total_volume = 0 + VAR_PRIVATE/tmp/total_liquid_volume // Used to determine when to create fluids in the world and the like. + +// Reagent serde is handled per atom. +/datum/reagents/ShouldSerialize(_age) + SHOULD_CALL_PARENT(FALSE) + return FALSE /datum/reagents/New(var/maximum_volume = 120, var/atom/my_atom) src.maximum_volume = maximum_volume - if(!istype(my_atom)) -#ifdef DISABLE_DEBUG_CRASH - return ..() -#else - CRASH("Invalid reagents holder: [log_info_line(my_atom)]") -#endif - ..() src.my_atom = my_atom + ..() /datum/reagents/Destroy() . = ..() UNQUEUE_REACTIONS(src) // While marking for reactions should be avoided just before deleting if possible, the async nature means it might be impossible. + if(SSfluids.holders_to_update[src]) + SSfluids.holders_to_update -= src reagent_volumes = null - reagent_data = null - my_atom = null -/datum/reagents/proc/get_primary_reagent_name() // Returns the name of the reagent with the biggest volume. + liquid_volumes = null + solid_volumes = null + + reagent_data = null + if(my_atom) + if(my_atom.reagents == src) + my_atom.reagents = null + if(total_volume > 0) // we can assume 0 reagents and null reagents are broadly identical for the purposes of atom logic + my_atom.try_on_reagent_change() + my_atom = null + +/datum/reagents/GetCloneArgs() + return list(maximum_volume, global.temp_reagents_holder) //Always clone with the dummy holder to prevent things being done on the owner atom + +//Don't forget to call set_holder() after getting the copy! +/datum/reagents/PopulateClone(datum/reagents/clone) + clone.primary_reagent = primary_reagent + clone.reagent_volumes = reagent_volumes?.Copy() + clone.liquid_volumes = liquid_volumes?.Copy() + clone.solid_volumes = solid_volumes?.Copy() + clone.reagent_data = listDeepClone(reagent_data, TRUE) + clone.total_volume = total_volume + clone.maximum_volume = maximum_volume + clone.cached_color = cached_color + return clone + +/datum/reagents/proc/get_reaction_loc(chemical_reaction_flags) + if((chemical_reaction_flags & CHEM_REACTION_FLAG_OVERFLOW_CONTAINER) && my_atom.reaction_can_overflow()) + return get_turf(my_atom) + return my_atom + +/datum/reagents/proc/get_primary_reagent_name(var/codex = FALSE) // Returns the name of the reagent with the biggest volume. var/decl/material/reagent = get_primary_reagent_decl() if(reagent) - . = reagent.name + if(codex && reagent.codex_name) + . = reagent.codex_name + else + if(LIQUID_VOLUME(src, reagent.type) >= SOLID_VOLUME(src, reagent.type)) + return reagent.get_reagent_name(src, MAT_PHASE_LIQUID) + else + return reagent.get_reagent_name(src, MAT_PHASE_SOLID) + +/datum/reagents/proc/get_primary_reagent_type() + return primary_reagent /datum/reagents/proc/get_primary_reagent_decl() - . = primary_reagent && decls_repository.get_decl(primary_reagent) + return RESOLVE_TO_DECL(primary_reagent) /datum/reagents/proc/update_total() // Updates volume. - cached_color = null total_volume = 0 + total_liquid_volume = 0 primary_reagent = null - for(var/R in reagent_volumes) - var/vol = reagent_volumes[R] + + reagent_volumes = list() + primary_liquid = null + for(var/decl/material/reagent as anything in liquid_volumes) + var/vol = CHEMS_QUANTIZE(liquid_volumes[reagent]) + if(vol < MINIMUM_CHEMICAL_VOLUME) + clear_reagent(reagent, defer_update = TRUE, force = TRUE) // defer_update is important to avoid infinite recursion + else + LAZYSET(liquid_volumes, reagent, vol) + LAZYSET(reagent_volumes, reagent, vol) + total_volume += vol + total_liquid_volume += vol + if(!primary_liquid || liquid_volumes[primary_liquid] < vol) + primary_liquid = reagent + + primary_solid = null + for(var/decl/material/reagent as anything in solid_volumes) + var/vol = CHEMS_QUANTIZE(solid_volumes[reagent]) if(vol < MINIMUM_CHEMICAL_VOLUME) - LAZYREMOVE(reagent_volumes, R) - LAZYREMOVE(reagent_data, R) + clear_reagent(reagent, defer_update = TRUE, force = TRUE) else + LAZYSET(solid_volumes, reagent, vol) + if(!reagent_volumes?[reagent]) + LAZYSET(reagent_volumes, reagent, vol) + else + reagent_volumes[reagent] += vol total_volume += vol - if(!primary_reagent || reagent_volumes[primary_reagent] < vol) - primary_reagent = R + if(!primary_solid || (solid_volumes[primary_solid] < vol)) + primary_solid = reagent + + if(solid_volumes?[primary_solid] > liquid_volumes?[primary_liquid]) + primary_reagent = primary_solid + else // By default, take the primary_liquid as the primary_reagent. + primary_reagent = primary_liquid + + UNSETEMPTY(reagent_volumes) + if(total_volume > maximum_volume) - remove_any(maximum_volume - total_volume) + remove_any(total_volume-maximum_volume) + /datum/reagents/proc/process_reactions() - if(!my_atom?.loc) - return 0 + var/atom/location = get_reaction_loc() + var/check_flags = location?.atom_flags || 0 - if(my_atom.atom_flags & ATOM_FLAG_NO_REACT) + if((check_flags & ATOM_FLAG_NO_REACT) && (check_flags & ATOM_FLAG_NO_PHASE_CHANGE) && (check_flags & ATOM_FLAG_NO_DISSOLVE)) return 0 - var/reaction_occured = FALSE + var/reaction_occurred = FALSE var/list/eligible_reactions = list() - var/temperature = my_atom ? my_atom.temperature : T20C - for(var/thing in reagent_volumes) - var/decl/material/R = decls_repository.get_decl(thing) + var/temperature = location?.temperature || T20C + for(var/decl/material/reagent as anything in reagent_volumes) // Check if the reagent is decaying or not. var/list/replace_self_with var/replace_message var/replace_sound - if(!isnull(R.chilling_point) && R.type != R.bypass_cooling_products_for_root_type && LAZYLEN(R.chilling_products) && temperature <= R.chilling_point) - replace_self_with = R.chilling_products - replace_message = "\The [lowertext(R.name)] [R.chilling_message]" - replace_sound = R.chilling_sound - - else if(!isnull(R.heating_point) && R.type != R.bypass_heating_products_for_root_type && LAZYLEN(R.heating_products) && temperature >= R.heating_point) - replace_self_with = R.heating_products - replace_message = "\The [lowertext(R.name)] [R.heating_message]" - replace_sound = R.heating_sound - - else if(!isnull(R.dissolves_in) && LAZYLEN(R.dissolves_into)) - for(var/other in reagent_volumes) - if(other == thing) + if(!(check_flags & ATOM_FLAG_NO_PHASE_CHANGE)) + if(!isnull(reagent.chilling_point) && LAZYLEN(reagent.chilling_products) && temperature <= reagent.chilling_point) + replace_self_with = reagent.chilling_products + if(reagent.chilling_message) + replace_message = "\The [reagent.get_reagent_name(src)] [reagent.chilling_message]" + replace_sound = reagent.chilling_sound + else if(!isnull(reagent.heating_point) && LAZYLEN(reagent.heating_products) && temperature >= reagent.heating_point) + replace_self_with = reagent.heating_products + if(reagent.heating_message) + replace_message = "\The [reagent.get_reagent_name(src)] [reagent.heating_message]" + replace_sound = reagent.heating_sound + + if(isnull(replace_self_with) && !isnull(reagent.dissolves_in) && !(check_flags & ATOM_FLAG_NO_DISSOLVE) && LAZYLEN(reagent.dissolves_into)) + for(var/decl/material/solvent as anything in reagent_volumes) + if(solvent == reagent) continue - var/decl/material/solvent = decls_repository.get_decl(other) - if(solvent.solvent_power >= R.dissolves_in) - replace_self_with = R.dissolves_into - replace_message = "\The [lowertext(R.name)] [R.dissolve_message] \the [lowertext(solvent.name)]." - replace_sound = R.dissolve_sound + if(solvent.solvent_power >= reagent.dissolves_in) + replace_self_with = reagent.dissolves_into + if(reagent.dissolve_message) + replace_message = "\The [reagent.get_reagent_name(src)] [reagent.dissolve_message] \the [solvent.get_reagent_name(src)]." + replace_sound = reagent.dissolve_sound break // If it is, handle replacing it with the decay product. if(replace_self_with) - var/replace_amount = REAGENT_VOLUME(src, R.type) - clear_reagent(R.type) + var/replace_amount = REAGENT_VOLUME(src, reagent) + clear_reagent(reagent) for(var/product in replace_self_with) add_reagent(product, replace_self_with[product] * replace_amount) - reaction_occured = TRUE + reaction_occurred = TRUE - if(my_atom) + if(location) if(replace_message) - my_atom.visible_message("\icon[my_atom] [replace_message]") + location.visible_message("[html_icon(location)] [replace_message]") if(replace_sound) - playsound(my_atom, replace_sound, 80, 1) - - else // Otherwise, collect all possible reactions. - eligible_reactions |= SSmaterials.chemical_reactions_by_id[R.type] - - var/list/active_reactions = list() - - for(var/datum/chemical_reaction/C in eligible_reactions) - if(C.can_happen(src)) - active_reactions[C] = 1 // The number is going to be 1/(fraction of remaining reagents we are allowed to use), computed below - reaction_occured = 1 - - var/list/used_reagents = list() - // if two reactions share a reagent, each is allocated half of it, so we compute this here - for(var/datum/chemical_reaction/C in active_reactions) - var/list/adding = C.get_used_reagents() - for(var/R in adding) - LAZYADD(used_reagents[R], C) - - for(var/R in used_reagents) - var/counter = length(used_reagents[R]) - if(counter <= 1) - continue // Only used by one reaction, so nothing we need to do. - for(var/datum/chemical_reaction/C in used_reagents[R]) - active_reactions[C] = max(counter, active_reactions[C]) - counter-- //so the next reaction we execute uses more of the remaining reagents - // Note: this is not guaranteed to maximize the size of the reactions we do (if one reaction is limited by reagent A, we may be over-allocating reagent B to it) - // However, we are guaranteed to fully use up the most profligate reagent if possible. - // Further reactions may occur on the next tick, when this runs again. - - for(var/thing in active_reactions) - var/datum/chemical_reaction/C = thing - C.process(src, active_reactions[C]) - - for(var/thing in active_reactions) - var/datum/chemical_reaction/C = thing - C.post_reaction(src) + playsound(location, replace_sound, 80, 1) + + else if(!(check_flags & ATOM_FLAG_NO_REACT)) // Otherwise, collect all possible reactions. + eligible_reactions |= SSmaterials.chemical_reactions_by_id[reagent.type] + + if(!(check_flags & ATOM_FLAG_NO_REACT)) + var/list/active_reactions = list() + + for(var/decl/chemical_reaction/reaction in eligible_reactions) + if(reaction.can_happen(src)) + active_reactions[reaction] = 1 // The number is going to be 1/(fraction of remaining reagents we are allowed to use), computed below + reaction_occurred = 1 + + var/list/used_reagents = list() + // if two reactions share a reagent, each is allocated half of it, so we compute this here + for(var/decl/chemical_reaction/reaction in active_reactions) + var/list/adding = reaction.get_used_reagents() + for(var/reagent in adding) + LAZYADD(used_reagents[reagent], reaction) + + for(var/reagent in used_reagents) + var/counter = length(used_reagents[reagent]) + if(counter <= 1) + continue // Only used by one reaction, so nothing we need to do. + for(var/decl/chemical_reaction/reaction in used_reagents[reagent]) + active_reactions[reaction] = max(counter, active_reactions[reaction]) + counter-- //so the next reaction we execute uses more of the remaining reagents + // Note: this is not guaranteed to maximize the size of the reactions we do (if one reaction is limited by reagent A, we may be over-allocating reagent B to it) + // However, we are guaranteed to fully use up the most profligate reagent if possible. + // Further reactions may occur on the next tick, when this runs again. + + for(var/decl/chemical_reaction/reaction as anything in active_reactions) + reaction.process(src, active_reactions[reaction]) + + for(var/decl/chemical_reaction/reaction as anything in active_reactions) + reaction.post_reaction(src) update_total() - if(reaction_occured) + if(reaction_occurred) HANDLE_REACTIONS(src) // Check again in case the new reagents can react again - return reaction_occured + return reaction_occurred /* Holder-to-chemical */ +/datum/reagents/proc/handle_update(var/safety) + if(QDELETED(src)) + return + SSfluids.holders_to_update -= src + update_total() + if(!safety) + HANDLE_REACTIONS(src) + my_atom?.try_on_reagent_change() + +///Set and call updates on the target holder. +/datum/reagents/proc/set_holder(var/obj/new_holder) + if(my_atom == new_holder) + return + my_atom = new_holder + my_atom?.try_on_reagent_change() + handle_update() -/datum/reagents/proc/add_reagent(var/reagent_type, var/amount, var/data = null, var/safety = 0) +/datum/reagents/proc/add_reagent(var/decl/material/reagent, var/amount, var/data = null, var/safety = 0, var/defer_update = FALSE, var/phase) + amount = CHEMS_QUANTIZE(min(amount, REAGENTS_FREE_SPACE(src))) if(amount <= 0) return FALSE - amount = min(amount, REAGENTS_FREE_SPACE(src)) - var/decl/material/newreagent = decls_repository.get_decl(reagent_type) + reagent = RESOLVE_TO_DECL(reagent) + if(!istype(reagent)) + return FALSE + + if(!phase) + // By default, assume the reagent phase at STP. + phase = reagent.phase_at_temperature() + // Assume it's in solution, somehow. + if(phase == MAT_PHASE_GAS) + phase = MAT_PHASE_LIQUID + + var/list/phase_volumes + if(phase == MAT_PHASE_LIQUID) + LAZYINITLIST(liquid_volumes) + phase_volumes = liquid_volumes + else + LAZYINITLIST(solid_volumes) + phase_volumes = solid_volumes + + if(!phase_volumes[reagent]) + phase_volumes[reagent] = amount + else + phase_volumes[reagent] += amount + LAZYINITLIST(reagent_volumes) - if(!reagent_volumes[reagent_type]) - reagent_volumes[reagent_type] = amount - var/tmp_data = newreagent.initialize_data(data) + if(!reagent_volumes[reagent]) + reagent_volumes[reagent] = amount + var/tmp_data = reagent.initialize_data(data) if(tmp_data) - LAZYSET(reagent_data, reagent_type, tmp_data) + LAZYSET(reagent_data, reagent, tmp_data) + if(reagent_volumes.len == 1) // if this is the first reagent, uncache color + cached_color = null else - reagent_volumes[reagent_type] += amount + reagent_volumes[reagent] += amount if(!isnull(data)) - LAZYSET(reagent_data, reagent_type, newreagent.mix_data(src, data, amount)) - UNSETEMPTY(reagent_volumes) + LAZYSET(reagent_data, reagent, reagent.mix_data(src, data, amount)) + if(reagent_volumes.len > 1) // otherwise if we have a mix of reagents, uncache as well + cached_color = null - update_total() - if(!safety) - HANDLE_REACTIONS(src) - if(my_atom) - SSmaterials.queue_reagent_change(my_atom) + UNSETEMPTY(reagent_volumes) + UNSETEMPTY(phase_volumes) + if(defer_update) + total_volume = clamp(total_volume + amount, 0, maximum_volume) // approximation, call update_total() if deferring + else + handle_update(safety) return TRUE -/datum/reagents/proc/remove_reagent(var/reagent_type, var/amount, var/safety = 0) - if(!isnum(amount) || REAGENT_VOLUME(src, reagent_type) <= 0) +/datum/reagents/proc/remove_reagent(var/decl/material/reagent, var/amount, var/safety = 0, var/defer_update = FALSE, var/removed_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) + amount = CHEMS_QUANTIZE(amount) + if(!isnum(amount) || amount <= 0 || REAGENT_VOLUME(src, reagent) <= 0) return FALSE - reagent_volumes[reagent_type] -= amount - update_total() - if(!safety) - HANDLE_REACTIONS(src) - if(my_atom) - SSmaterials.queue_reagent_change(my_atom) + + reagent = RESOLVE_TO_DECL(reagent) + if(!istype(reagent)) + return FALSE + + var/removed = 0 + if((removed_phases & MAT_PHASE_LIQUID) && LIQUID_VOLUME(src, reagent) > 0) + + removed += min(liquid_volumes[reagent], amount) + liquid_volumes[reagent] -= removed + + // If both liquid and solid reagents are being removed, we prioritize the liquid reagents. + if((removed < amount) && (removed_phases & MAT_PHASE_SOLID) && SOLID_VOLUME(src, reagent) > 0) + + var/solid_removed = min(solid_volumes[reagent], amount - removed) + solid_volumes[reagent] -= solid_removed + + removed += solid_removed + + if(removed == 0) + return FALSE + + // If removed < amount, a reagent has been removed completely from a state, so uncache the color. + if((LAZYLEN(liquid_volumes) > 1 || LAZYLEN(solid_volumes) > 1) || (removed < amount)) + cached_color = null + if(defer_update) + total_volume = clamp(total_volume - removed, 0, maximum_volume) // approximation, call update_total() if deferring + else + handle_update(safety) return TRUE -/datum/reagents/proc/clear_reagent(var/reagent_type) - . = !!(REAGENT_VOLUME(src, reagent_type) || REAGENT_DATA(src, reagent_type)) +/datum/reagents/proc/clear_reagent(var/decl/material/reagent, var/defer_update = FALSE, var/force = FALSE) + + reagent = RESOLVE_TO_DECL(reagent) + if(!istype(reagent)) + return FALSE + + . = force || !!REAGENT_DATA(src, reagent) || !!REAGENT_VOLUME(src, reagent) if(.) - LAZYREMOVE(reagent_volumes, reagent_type) - LAZYREMOVE(reagent_data, reagent_type) - if(primary_reagent == reagent_type) + + var/amount = LAZYACCESS(reagent_volumes, reagent) + LAZYREMOVE(liquid_volumes, reagent) + LAZYREMOVE(solid_volumes, reagent) + + LAZYREMOVE(reagent_volumes, reagent) + LAZYREMOVE(reagent_data, reagent) + if(primary_reagent == reagent) primary_reagent = null - update_total() - if(my_atom) - SSmaterials.queue_reagent_change(my_atom) + if(primary_liquid == reagent) + primary_liquid = null + if(primary_solid == reagent) + primary_solid = null + cached_color = null + + if(defer_update) + total_volume = clamp(total_volume - amount, 0, maximum_volume) // approximation, call update_total() if deferring + else + handle_update() -/datum/reagents/proc/has_reagent(var/reagent_type, var/amount) - . = REAGENT_VOLUME(src, reagent_type) +/datum/reagents/proc/has_reagent(var/decl/material/reagent, var/amount, var/phases) + . = 0 + reagent = RESOLVE_TO_DECL(reagent) + if(!istype(reagent)) + return + if(phases) + if(phases & MAT_PHASE_SOLID) + . += SOLID_VOLUME(src, reagent) + if(phases & MAT_PHASE_LIQUID) + . += LIQUID_VOLUME(src, reagent) + else + . = REAGENT_VOLUME(src, reagent) if(. && amount) . = (. >= amount) -/datum/reagents/proc/has_any_reagent(var/list/check_reagents) +/datum/reagents/proc/has_any_reagent(var/list/check_reagents, var/phases) for(var/check in check_reagents) - var/vol = REAGENT_VOLUME(src, check) - if(vol > 0 && vol >= check_reagents[check]) + if(has_reagent(check, check_reagents[check], phases)) return TRUE return FALSE -/datum/reagents/proc/has_all_reagents(var/list/check_reagents) +/datum/reagents/proc/has_all_reagents(var/list/check_reagents, var/phases) + . = TRUE for(var/check in check_reagents) - if(REAGENT_VOLUME(src, check) < check_reagents[check]) - return FALSE - return TRUE + . = min(., has_reagent(RESOLVE_TO_DECL(check), check_reagents[check], phases)) + if(!.) + return /datum/reagents/proc/clear_reagents() - reagent_volumes = null - reagent_data = null + for(var/decl/material/reagent as anything in reagent_volumes) + clear_reagent(reagent, defer_update = TRUE) + + LAZYCLEARLIST(liquid_volumes) + LAZYCLEARLIST(solid_volumes) + LAZYCLEARLIST(reagent_volumes) + LAZYCLEARLIST(reagent_data) total_volume = 0 + my_atom?.try_on_reagent_change() -/datum/reagents/proc/get_overdose(var/decl/material/current) - if(current) - return initial(current.overdose) +/datum/reagents/proc/get_overdose(var/decl/material/reagent) + if(reagent) + return initial(reagent.overdose) return 0 /datum/reagents/proc/get_reagents(scannable_only = 0, precision) . = list() - for(var/rtype in reagent_volumes) - var/decl/material/current= decls_repository.get_decl(rtype) - if(scannable_only && !current.scannable) + for(var/decl/material/reagent as anything in liquid_volumes) + if(scannable_only && !reagent.scannable) continue - var/volume = REAGENT_VOLUME(src, rtype) + var/scan_volume = REAGENT_VOLUME(src, reagent) if(precision) - volume = round(volume, precision) - if(volume) - . += "[current.name] ([volume])" + scan_volume = round(scan_volume, precision) + if(scan_volume) + . += "[reagent.get_reagent_name(src, MAT_PHASE_LIQUID)] ([scan_volume])" + for(var/decl/material/reagent as anything in solid_volumes) + if(scannable_only && !reagent.scannable) + continue + var/scan_volume = REAGENT_VOLUME(src, reagent) + if(precision) + scan_volume = round(scan_volume, precision) + if(scan_volume) + . += "[reagent.get_reagent_name(src, MAT_PHASE_SOLID)] ([scan_volume])" return english_list(., "EMPTY", "", ", ", ", ") +/datum/reagents/proc/get_dirtiness() + for(var/decl/material/reagent as anything in reagent_volumes) + . += reagent.dirtiness + return . / length(reagent_volumes) + +/datum/reagents/proc/get_accelerant_value() + for(var/decl/material/reagent as anything in reagent_volumes) + . += reagent.accelerant_value + return . / length(reagent_volumes) + /* Holder-to-holder and similar procs */ +/// Removes up to [amount] of reagents from [src]. Returns actual amount removed. +/datum/reagents/proc/remove_any(var/amount = 1, var/defer_update = FALSE, var/removed_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID), skip_reagents = null) -/datum/reagents/proc/remove_any(var/amount = 1) // Removes up to [amount] of reagents from [src]. Returns actual amount removed. - . = min(amount, total_volume) - if(.) - var/part = . / total_volume - for(var/current in reagent_volumes) - remove_reagent(current, REAGENT_VOLUME(src, current) * part, 1) - update_total() - HANDLE_REACTIONS(src) + amount = CHEMS_QUANTIZE(amount) + + if(amount <= 0) + return 0 + + if(skip_reagents) // use the infinite sink for this + return trans_to_holder(global.infinite_reagent_sink, amount, skip_reagents = skip_reagents, transferred_phases = removed_phases) + + // The list we're iterating over to remove reagents. + var/list/removing_volumes + var/removing_volumes_total + // Shortcut if we're removing both liquids and solids (most cases). + if((removed_phases & MAT_PHASE_LIQUID) && (removed_phases & MAT_PHASE_SOLID)) + if(amount >= total_volume) + . = total_volume + clear_reagents() + return + + removing_volumes = reagent_volumes + removing_volumes_total = total_volume + + else if(removed_phases & MAT_PHASE_LIQUID) + if(!LAZYLEN(liquid_volumes)) + return 0 + + removing_volumes = liquid_volumes + removing_volumes_total = total_liquid_volume + + else if(removed_phases & MAT_PHASE_SOLID) + if(!LAZYLEN(solid_volumes)) + return 0 + + removing_volumes = solid_volumes + removing_volumes_total = total_volume - total_liquid_volume + else + return 0 + + var/removing = clamp(amount, 0, total_volume) // not ideal but something is making total_volume become NaN + if(!removing) + return 0 // don't clear, we aren't removing any + + if(total_volume <= removing) // we're removing everything + . = 0 + clear_reagents() + return + + // Some reagents may be too low to remove from, so do multiple passes. + . = 0 + var/part = removing / removing_volumes_total + var/failed_remove = FALSE + while(removing >= MINIMUM_CHEMICAL_VOLUME && total_volume >= MINIMUM_CHEMICAL_VOLUME && !failed_remove) + failed_remove = TRUE + for(var/decl/material/reagent as anything in removing_volumes) + var/removing_amt = min(CHEMS_QUANTIZE(removing_volumes[reagent] * part), removing) + if(removing_amt <= 0) + continue + failed_remove = FALSE + removing -= removing_amt + . += removing_amt + remove_reagent(reagent, removing_amt, TRUE, TRUE, removed_phases = removed_phases) + + if(!defer_update) + handle_update() // Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. // Returns actual amount removed from [src] (not amount transferred to [target]). // Use safety = 1 for temporary targets to avoid queuing them up for processing. -/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/safety = 0) +// Reagent phases are preserved. +/datum/reagents/proc/trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/safety = 0, var/defer_update = FALSE, var/list/skip_reagents, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) + if(!target || !istype(target)) - return + return 0 amount = max(0, min(amount, total_volume, REAGENTS_FREE_SPACE(target) / multiplier)) - if(!amount) - return - - var/part = amount / total_volume + return 0 - for(var/rtype in reagent_volumes) - var/amount_to_transfer = REAGENT_VOLUME(src, rtype) * part - target.add_reagent(rtype, amount_to_transfer * multiplier, REAGENT_DATA(src, rtype), safety = 1) // We don't react until everything is in place + var/part = amount + if(skip_reagents) + var/using_volume = total_volume + for(var/reagent in skip_reagents) + using_volume -= LAZYACCESS(reagent_volumes, reagent) + if(using_volume <= 0) + return 0 + part /= using_volume + else + var/using_volume = total_volume + if(!(transferred_phases & MAT_PHASE_LIQUID)) + using_volume -= total_liquid_volume + else if(!(transferred_phases & MAT_PHASE_SOLID)) + using_volume = total_liquid_volume + part /= using_volume + + . = 0 + for(var/decl/material/reagent as anything in reagent_volumes - skip_reagents) + var/amount_to_transfer = CHEMS_QUANTIZE(REAGENT_VOLUME(src, reagent) * part) + + // Prioritize liquid transfers + if(transferred_phases & MAT_PHASE_LIQUID) + var/liquid_transferred = min(amount_to_transfer, CHEMS_QUANTIZE(LIQUID_VOLUME(src, reagent))) + target.add_reagent(reagent, liquid_transferred * multiplier, REAGENT_DATA(src, reagent), TRUE, TRUE, MAT_PHASE_LIQUID) // We don't react until everything is in place + + . += liquid_transferred + amount_to_transfer -= liquid_transferred + + if(!copy) + remove_reagent(reagent, liquid_transferred, TRUE, TRUE, MAT_PHASE_LIQUID) + + if(transferred_phases & MAT_PHASE_SOLID) + var/solid_transferred = (min(amount_to_transfer, CHEMS_QUANTIZE(SOLID_VOLUME(src, reagent)))) + target.add_reagent(reagent, solid_transferred * multiplier, REAGENT_DATA(src, reagent), TRUE, TRUE, MAT_PHASE_SOLID) // Ditto + . += solid_transferred + amount_to_transfer -= solid_transferred + + if(!copy) + remove_reagent(reagent, solid_transferred, TRUE, TRUE, MAT_PHASE_SOLID) + + + // Due to rounding, we may have taken less than we wanted. + // If we're up short, add the remainder taken from the primary reagent. + // If we're skipping the primary reagent we just don't do this step. + if(. < amount) + var/remainder = CHEMS_QUANTIZE(amount - .) + + var/liquid_remainder + if((transferred_phases & MAT_PHASE_LIQUID) && primary_liquid && !(primary_liquid in skip_reagents) && LIQUID_VOLUME(src, primary_liquid) > 0) + liquid_remainder = min(remainder, LIQUID_VOLUME(src, primary_liquid)) + var/solid_remainder + if((transferred_phases & MAT_PHASE_SOLID) && primary_solid && !(primary_solid in skip_reagents) && SOLID_VOLUME(src, primary_solid) > 0) + solid_remainder = min(remainder - liquid_remainder, SOLID_VOLUME(src, primary_solid)) + + if(liquid_remainder > 0) + target.add_reagent(primary_reagent, liquid_remainder * multiplier, REAGENT_DATA(src, primary_reagent), TRUE, TRUE, MAT_PHASE_LIQUID) + . += liquid_remainder + remainder -= liquid_remainder + if(solid_remainder > 0) + target.add_reagent(primary_reagent, solid_remainder * multiplier, REAGENT_DATA(src, primary_reagent), TRUE, TRUE, MAT_PHASE_SOLID) + . += solid_remainder + remainder -= solid_remainder if(!copy) - remove_reagent(rtype, amount_to_transfer, 1) - - if(!copy) - HANDLE_REACTIONS(src) - if(!safety) - HANDLE_REACTIONS(target) - return amount + if(liquid_remainder > 0) + remove_reagent(primary_reagent, liquid_remainder, TRUE, TRUE, MAT_PHASE_LIQUID) + if(solid_remainder > 0) + remove_reagent(primary_reagent, solid_remainder, TRUE, TRUE, MAT_PHASE_SOLID) + + if(!defer_update) + target.handle_update(safety) + handle_update(safety) + if(!copy) + HANDLE_REACTIONS(src) /* Holder-to-atom and similar procs */ @@ -284,147 +659,367 @@ GLOBAL_DATUM_INIT(temp_reagents_holder, /obj, new) //not directly injected into the contents. It first calls touch, then the appropriate trans_to_*() or splash_mob(). //If for some reason touch effects are bypassed (e.g. injecting stuff directly into a reagent container or person), //call the appropriate trans_to_*() proc. -/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - touch(target) //First, handle mere touch effects - +/datum/reagents/proc/trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/defer_update = FALSE, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) if(ismob(target)) - return splash_mob(target, amount, copy) + touch_mob(target) + if(QDELETED(target)) + return 0 + return splash_mob(target, amount, copy, defer_update = defer_update) if(isturf(target)) - return trans_to_turf(target, amount, multiplier, copy) - if(isobj(target) && ATOM_IS_OPEN_CONTAINER(target)) - return trans_to_obj(target, amount, multiplier, copy) + return trans_to_turf(target, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) + if(isobj(target)) + touch_obj(target) + if(!QDELETED(target) && target.can_be_poured_into(my_atom)) + return trans_to_obj(target, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) + return 0 return 0 -//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well. -/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60) - var/spill = 0 - if(!isturf(target) && target.loc) - spill = amount*(rand(min_spill, max_spill)/100) - amount -= spill - if(spill) - splash(target.loc, spill, multiplier, copy, min_spill, max_spill) +//Splashing reagents is messier than trans_to, the target's loc gets some of the reagents as well. All phases are transferred by default +/datum/reagents/proc/splash(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/min_spill=0, var/max_spill=60, var/defer_update = FALSE) - trans_to(target, amount, multiplier, copy) + if(!istype(target)) + return -/datum/reagents/proc/trans_type_to(var/atom/target, var/type, var/amount = 1, var/multiplier = 1) - if (!target || !target.reagents || !target.simulated) + if(isturf(target)) + trans_to_turf(target, amount, multiplier, copy, defer_update = defer_update) return - amount = min(amount, REAGENT_VOLUME(src, type)) + if(isturf(target.loc) && min_spill && max_spill) + var/spill = floor(amount*(rand(min_spill, max_spill)/100)) + if(spill) + amount -= spill + trans_to_turf(target.loc, spill, multiplier, copy, defer_update) + if(amount) + trans_to(target, amount, multiplier, copy, defer_update = defer_update) + +//Spreads the contents of this reagent holder all over the vicinity of the target turf. +/datum/reagents/proc/splash_area(var/turf/epicentre, var/range = 3, var/portion = 1.0, var/multiplier = 1, var/copy = 0) + var/list/things = list() + DVIEW(things, range, epicentre, INVISIBILITY_LIGHTING) + + var/list/turfs = list() + for (var/turf/T in things) + turfs += T + + if (!turfs.len) + return//Nowhere to splash to, somehow + + //Create a temporary holder to hold all the amount that will be spread + var/datum/reagents/reagent = new /datum/reagents(total_volume * portion * multiplier, global.temp_reagents_holder) + trans_to_holder(reagent, total_volume * portion, multiplier, copy) + + //The exact amount that will be given to each turf + var/turfportion = reagent.total_volume / turfs.len + for (var/turf/T in turfs) + reagent.splash_turf(T, amount = turfportion, multiplier = 1, copy = FALSE) + qdel(reagent) + +//Spreads the contents of this reagent holder all over the target turf, dividing among things in it. +//50% is divided between mobs, 20% between objects, and whatever's left on the turf itself +/datum/reagents/proc/splash_turf(var/turf/T, var/amount = null, var/multiplier = 1, var/copy = 0) + if (isnull(amount)) + amount = total_volume + else + amount = min(amount, total_volume) + if (amount <= 0) + return + + var/list/mobs = list() + for (var/mob/M in T) + mobs += M + + var/list/objs = list() + for (var/obj/O in T) + //Todo: Add some check here to not hit wires/pipes that are hidden under floor tiles. + //Maybe also not hit things under tables. + objs += O + + if (objs.len) + var/objportion = (amount * 0.2) / objs.len + for (var/o in objs) + var/obj/O = o + + trans_to(O, objportion, multiplier, copy) + + amount = min(amount, total_volume) + + if (mobs.len) + var/mobportion = (amount * 0.5) / mobs.len + for (var/m in mobs) + var/mob/M = m + trans_to(M, mobportion, multiplier, copy) + + trans_to(T, total_volume, multiplier, copy) + + if (total_volume <= 0) + qdel(src) + +/datum/reagents/proc/trans_type_to(var/atom/target, var/type, var/amount = 1, var/multiplier = 1, var/defer_update = FALSE, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) + if (!target || !target.reagents || !target.simulated || !transferred_phases) + return + + amount = max(0, min(amount, REAGENT_VOLUME(src, type), REAGENTS_FREE_SPACE(target.reagents) / multiplier)) if(!amount) return - var/datum/reagents/F = new(amount, GLOB.temp_reagents_holder) - F.add_reagent(type, amount, REAGENT_DATA(src, type)) - remove_reagent(type, amount) - . = F.trans_to(target, amount, multiplier) // Let this proc check the atom's type + // Small check for optimization. + if (!(transferred_phases & MAT_PHASE_LIQUID)) + if(!SOLID_VOLUME(src, type)) + return + + if (!(transferred_phases & MAT_PHASE_SOLID)) + if(!LIQUID_VOLUME(src, type)) + return + var/datum/reagents/F = new(amount, global.temp_reagents_holder) + + var/amount_remaining = amount + + // Prioritize liquid transfers. + if(transferred_phases & MAT_PHASE_LIQUID) + var/liquid_transferred = NONUNIT_FLOOR(min(amount_remaining, LIQUID_VOLUME(src, type)), MINIMUM_CHEMICAL_VOLUME) + F.add_reagent(type, liquid_transferred, REAGENT_DATA(src, type), defer_update = TRUE, phase = MAT_PHASE_LIQUID) + remove_reagent(type, liquid_transferred, defer_update = TRUE, removed_phases = MAT_PHASE_LIQUID) + amount_remaining -= liquid_transferred + + if(transferred_phases & MAT_PHASE_SOLID) + var/solid_transferred = NONUNIT_FLOOR(min(amount_remaining, SOLID_VOLUME(src, type)), MINIMUM_CHEMICAL_VOLUME) + F.add_reagent(type, solid_transferred, REAGENT_DATA(src, type), defer_update = TRUE, phase = MAT_PHASE_SOLID) + remove_reagent(type, solid_transferred, defer_update = TRUE, removed_phases = MAT_PHASE_SOLID) + amount_remaining -= solid_transferred + + // Now that both liquid and solid components are removed, we can update if necessary. + if(!defer_update) + handle_update() + + . = F.trans_to(target, amount, multiplier, defer_update = defer_update, transferred_phases = transferred_phases) // Let this proc check the atom's type qdel(F) -// When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. -// This does not handle transferring reagents to things. +/datum/reagents/proc/trans_type_to_holder(var/datum/reagents/target, var/type, var/amount = 1, var/multiplier = 1, var/defer_update = FALSE, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) + if (!target) + return + + amount = max(0, min(amount, REAGENT_VOLUME(src, type), REAGENTS_FREE_SPACE(target) / multiplier)) + + if(!amount) + return + + // Small check for optimization. + if (!(transferred_phases & MAT_PHASE_LIQUID)) + if(!SOLID_VOLUME(src, type)) + return + + if (!(transferred_phases & MAT_PHASE_SOLID)) + if(!LIQUID_VOLUME(src, type)) + return + + var/filtered_types = reagent_volumes - type + return trans_to_holder(target, amount, multiplier, skip_reagents = filtered_types, defer_update = defer_update, transferred_phases = transferred_phases) // Let this proc check the atom's type + +// When applying reagents to an atom externally, touch procs are called to trigger any on-touch effects of the reagent. +// Options are touch_turf(), touch_mob() and touch_obj(). This does not handle transferring reagents to things. // For example, splashing someone with water will get them wet and extinguish them if they are on fire, // even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. -/datum/reagents/proc/touch(var/atom/target) + +/datum/reagents/proc/touch_atom(atom/target, touch_atoms = TRUE) if(ismob(target)) - touch_mob(target) - if(isturf(target)) - touch_turf(target) + return touch_mob(target) if(isobj(target)) - touch_obj(target) + return touch_obj(target) + if(isturf(target)) + return touch_turf(target, touch_atoms) + return FALSE -/datum/reagents/proc/touch_mob(var/mob/target) +/datum/reagents/proc/touch_mob(mob/target) if(!target || !istype(target) || !target.simulated) return - for(var/rtype in reagent_volumes) - var/decl/material/current = decls_repository.get_decl(rtype) - current.touch_mob(target, REAGENT_VOLUME(src, rtype), src) - update_total() + for(var/decl/material/reagent as anything in reagent_volumes) + reagent.touch_mob(target, REAGENT_VOLUME(src, reagent), src) -/datum/reagents/proc/touch_turf(var/turf/target) - if(!target || !istype(target) || !target.simulated) +/datum/reagents/proc/touch_turf(turf/touching_turf, touch_atoms = TRUE) + + if(!istype(touching_turf) || !touching_turf.simulated) return - for(var/rtype in reagent_volumes) - var/decl/material/current = decls_repository.get_decl(rtype) - current.touch_turf(target, REAGENT_VOLUME(src, rtype), src) - update_total() -/datum/reagents/proc/touch_obj(var/obj/target) + for(var/decl/material/reagent as anything in reagent_volumes) + reagent.touch_turf(touching_turf, REAGENT_VOLUME(src, reagent), src) + + var/dirtiness = get_dirtiness() + if(dirtiness <= DIRTINESS_CLEAN) + touching_turf.clean() + touching_turf.remove_cleanables() + + if(dirtiness > DIRTINESS_NEUTRAL) + touching_turf.add_dirt(ceil(total_volume * dirtiness)) + else if(dirtiness < DIRTINESS_NEUTRAL) + if(dirtiness <= DIRTINESS_STERILE) + touching_turf.germ_level -= min(total_volume*20, touching_turf.germ_level) + for(var/obj/item/I in touching_turf.contents) + I.was_bloodied = null + for(var/obj/effect/decal/cleanable/blood/B in touching_turf) + qdel(B) + if(dirtiness <= DIRTINESS_CLEAN) + touching_turf.clean() + + if(touch_atoms) + for(var/atom/movable/thing in touching_turf.get_contained_external_atoms()) + if(thing.simulated && !istype(thing, /obj/effect/effect/smoke/chem)) + touch_atom(thing) + +/datum/reagents/proc/touch_obj(obj/target) if(!target || !istype(target) || !target.simulated) return - for(var/rtype in reagent_volumes) - var/decl/material/current = decls_repository.get_decl(rtype) - current.touch_obj(target, REAGENT_VOLUME(src, rtype), src) - update_total() + for(var/decl/material/reagent as anything in reagent_volumes) + reagent.touch_obj(target, REAGENT_VOLUME(src, reagent), src) // Attempts to place a reagent on the mob's skin. // Reagents are not guaranteed to transfer to the target. // Do not call this directly, call trans_to() instead. -/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0) +/datum/reagents/proc/splash_mob(var/mob/target, var/amount = 1, var/copy = 0, var/defer_update = FALSE) var/perm = 1 if(isliving(target)) //will we ever even need to tranfer reagents to non-living mobs? var/mob/living/L = target perm = L.reagent_permeability() - return trans_to_mob(target, amount * perm, CHEM_TOUCH, 1, copy) + return trans_to_mob(target, amount * perm, CHEM_TOUCH, 1, copy, defer_update = defer_update) -/datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_INJECT, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder... +/datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_INJECT, var/multiplier = 1, var/copy = 0, var/defer_update = FALSE, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) // Transfer after checking into which holder... if(!target || !istype(target) || !target.simulated) return - if(iscarbon(target)) - var/mob/living/carbon/C = target + if(isliving(target)) + var/mob/living/L = target if(type == CHEM_INJECT) - var/datum/reagents/R = C.reagents - return trans_to_holder(R, amount, multiplier, copy) + var/datum/reagents/reagent = L.get_injected_reagents() + if(reagent) + return trans_to_holder(reagent, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) if(type == CHEM_INGEST) - var/datum/reagents/R = C.get_ingested_reagents() - return C.ingest(src, R, amount, multiplier, copy) //perhaps this is a bit of a hack, but currently there's no common proc for eating reagents + var/datum/reagents/reagent = L.get_ingested_reagents() + if(reagent) + return L.ingest(src, reagent, amount, multiplier, copy) //perhaps this is a bit of a hack, but currently there's no common proc for eating reagents if(type == CHEM_TOUCH) - var/datum/reagents/R = C.touching - return trans_to_holder(R, amount, multiplier, copy) - else - var/datum/reagents/R = new /datum/reagents(amount, GLOB.temp_reagents_holder) - . = trans_to_holder(R, amount, multiplier, copy, 1) - R.touch_mob(target) - qdel(R) + var/datum/reagents/reagent = L.get_contact_reagents() + if(reagent) + return trans_to_holder(reagent, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) + if(type == CHEM_INHALE) + var/datum/reagents/reagent = L.get_inhaled_reagents() + if(reagent) + return trans_to_holder(reagent, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) + var/datum/reagents/reagent = new /datum/reagents(amount, global.temp_reagents_holder) + . = trans_to_holder(reagent, amount, multiplier, copy, TRUE, defer_update = defer_update, transferred_phases = transferred_phases) + reagent.touch_mob(target) + qdel(reagent) + +/datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/defer_update = FALSE, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) + if(!target?.simulated) + return 0 -/datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it. - if(!target || !target.simulated) + // If we're only dumping solids, and there's not enough liquid present on the turf to make a slurry, we dump the solids directly. + // This avoids creating an unnecessary reagent holder that won't be immediately deleted. + if((!(transferred_phases & MAT_PHASE_LIQUID) || !total_liquid_volume) && (target.reagents?.total_liquid_volume < FLUID_SLURRY)) + var/datum/reagents/reagent = new /datum/reagents(amount, global.temp_reagents_holder) + . = trans_to_holder(reagent, amount, multiplier, copy, TRUE, defer_update = defer_update, transferred_phases = MAT_PHASE_SOLID) + reagent.touch_turf(target) + target.dump_solid_reagents(reagent) + qdel(reagent) return - var/datum/reagents/R = new /datum/reagents(amount * multiplier, GLOB.temp_reagents_holder) - . = trans_to_holder(R, amount, multiplier, copy, 1) - var/obj/effect/fluid/F = locate() in target - if(!F) F = new(target) - trans_to_holder(F.reagents, amount, multiplier, copy) -/datum/reagents/proc/trans_to_obj(var/obj/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch. + target.create_or_update_reagents(FLUID_MAX_DEPTH) + + . = trans_to_holder(target.reagents, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) + // Deferred updates are presumably being done by SSfluids. + // Do an immediate fluid_act call rather than waiting for SSfluids to proc. + if(!defer_update && REAGENT_TOTAL_VOLUME(target.reagents) >= FLUID_PUDDLE) + target.fluid_act(target.reagents) + + // Objects may or may not have reagents; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch. +/datum/reagents/proc/trans_to_obj(var/obj/target, var/amount = 1, var/multiplier = 1, var/copy = 0, var/defer_update = FALSE, var/transferred_phases = (MAT_PHASE_LIQUID | MAT_PHASE_SOLID)) if(!target || !target.simulated) - return + return 0 if(!target.reagents) - var/datum/reagents/R = new /datum/reagents(amount * multiplier, GLOB.temp_reagents_holder) - . = trans_to_holder(R, amount, multiplier, copy, 1) - R.touch_obj(target) - qdel(R) + var/datum/reagents/reagent = new /datum/reagents(amount * multiplier, global.temp_reagents_holder) + . = trans_to_holder(reagent, amount, multiplier, copy, TRUE, defer_update = defer_update, transferred_phases = transferred_phases) + reagent.touch_obj(target) + qdel(reagent) return - return trans_to_holder(target.reagents, amount, multiplier, copy) + return trans_to_holder(target.reagents, amount, multiplier, copy, defer_update = defer_update, transferred_phases = transferred_phases) + +/datum/reagents/proc/get_skimmable_reagents() + for(var/decl/material/reagent as anything in reagent_volumes) + if(reagent.skimmable) + LAZYADD(., reagent) + +/// Used to return strings like "dilute blood" for use in phrases like "It's covered in dilute oily slimy bloody mud!" +/// This is explicitly inspired by Caves of Qud, by the way. +/datum/reagents/proc/get_coated_name() + /// arbitrary number, number of words that will be included in the name. will always have primary in addition + var/const/MAX_COATING_NAMES = 4 + if(!total_volume) + return null + // sort reagents from low to high, so largest reagent comes last (feels most impactful? idk, it's arbitrary) + var/list/volumes_temp = sortTim(reagent_volumes.Copy(), /proc/cmp_numeric_asc, associative = TRUE) + var/list/accumulator = list() + var/decl/material/primary_reagent_decl = get_primary_reagent_decl() // this also sets src.primary_reagent to the typepath + for(var/decl/material/reagent as anything in volumes_temp) + if(reagent == primary_reagent) + continue // added later + reagent.build_coated_name(src, accumulator) + if(length(accumulator) >= MAX_COATING_NAMES) + break + var/primary_name = primary_reagent_decl.get_primary_coating_name(src) + if(get_config_value(/decl/config/enum/colored_coating_names) == CONFIG_COATING_COLOR_COMPONENTS) + var/primary_color = primary_reagent_decl.get_reagent_color(src) + primary_name = FONT_COLORED(primary_color, primary_name) + accumulator += primary_name // add primary to the end + . = jointext(accumulator, " ") // dilute oily slimy bloody mud + if(get_config_value(/decl/config/enum/colored_coating_names) == CONFIG_COATING_COLOR_MIXTURE) + . = FONT_COLORED(get_color(), .) + +/// Used to return strings like "inky bloody muddy snowy oily wet" for use in phrases like "You are wearing some inky bloody muddy snowy oily wet leather boots." +/// This is explicitly inspired by Caves of Qud, by the way. +/datum/reagents/proc/get_coated_adjectives() + var/const/MAX_COATING_ADJECTIVES = 5 // arbitrary number, limit how many reagents will show up in the name on examine + if(!total_volume) + return null + // sort reagents from low to high, so primary reagent comes last (feels most impactful? idk, it's arbitrary) + // todo: maybe at some point we could make staining have some kind of priority to sort by? + var/list/volumes_temp = sortTim(reagent_volumes.Copy(), /proc/cmp_numeric_asc, associative = TRUE) + var/list/accumulator = list() + for(var/decl/material/reagent in volumes_temp) + var/coated_name = reagent.get_coated_adjective(src) + accumulator |= coated_name + if(length(accumulator) >= MAX_COATING_ADJECTIVES) + break + . = jointext(accumulator, " ") // bloody muddy inky slimy wet + if(get_config_value(/decl/config/enum/colored_coating_names) == CONFIG_COATING_COLOR_MIXTURE) + . = FONT_COLORED(get_color(), .) /* Atom reagent creation - use it all the time */ - -/atom/proc/create_reagents(var/max_vol) - if(reagents) - log_debug("Attempted to create a new reagents holder when already referencing one: [log_info_line(src)]") - reagents.maximum_volume = max(reagents.maximum_volume, max_vol) - else - reagents = new/datum/reagents(max_vol, src) +/atom/proc/create_or_update_reagents(vol, override_volume) + if(islist(reagents)) + return // We are pending serde, this will be handled in initialize_reagents(). + else if(istype(reagents)) + var/use_max_vol = override_volume ? vol : max(vol, REAGENT_MAXIMUM_VOLUME(reagents)) + REAGENT_SET_MAX_VOL(reagents, use_max_vol) + reagents.update_total() + else if(isnull(reagents)) + reagents = new /datum/reagents(vol, src) return reagents -/datum/reagents/Topic(href, href_list) - . = ..() - if(!. && href_list["deconvert"]) - var/list/data = REAGENT_DATA(src, /decl/material/liquid/water) - if(LAZYACCESS(data, "holy")) - var/mob/living/carbon/C = locate(href_list["deconvert"]) - if(istype(C) && !QDELETED(C) && C.mind) - GLOB.godcult.remove_antagonist(C.mind,1) +/// Infinite reagent sink: nothing is ever actually added to it, useful for complex, filtered deletion of reagents without holder churn. +/datum/reagents/sink/add_reagent(var/decl/material/reagent, amount, data, safety, defer_update, phase) + amount = CHEMS_QUANTIZE(min(amount, REAGENTS_FREE_SPACE(src))) + if(amount <= 0) + return FALSE + reagent = RESOLVE_TO_DECL(reagent) + if(!istype(reagent)) + return FALSE + return TRUE + +/datum/reagents/proc/get_explosive_power() + for(var/decl/material/mat in reagent_volumes) + if(isnull(mat.explosive_power_divisor)) + continue + . += (reagent_volumes[mat] / mat.explosive_power_divisor) + . = round(., 1) diff --git a/code/modules/reagents/Chemistry-Logging.dm b/code/modules/reagents/Chemistry-Logging.dm deleted file mode 100644 index 5e8f835a4470..000000000000 --- a/code/modules/reagents/Chemistry-Logging.dm +++ /dev/null @@ -1,28 +0,0 @@ - -/var/list/chemical_reaction_logs = list() - -/proc/log_chemical_reaction(atom/A, datum/chemical_reaction/R, multiplier) - if(!A || !R) - return - - var/turf/T = get_turf(A) - var/logstr = "[usr ? key_name(usr) : "EVENT"] mixed [R.name] ([R.result]) (x[multiplier]) in \the [A] at [T ? "[T.x],[T.y],[T.z]" : "*null*"]" - - chemical_reaction_logs += "\[[time_stamp()]\] [logstr]" - - if(R.log_is_important) - message_admins(logstr) - log_admin(logstr) - -/client/proc/view_chemical_reaction_logs() - set name = "Show Chemical Reactions" - set category = "Admin" - - if(!check_rights(R_ADMIN)) - return - - var/html = "" - for(var/entry in chemical_reaction_logs) - html += "[entry]
    " - - show_browser(usr, html, "window=chemlogs") diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index e7691ae8eaa5..eb852d575ccf 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -1,94 +1,129 @@ -#define BOTTLE_SPRITES list("bottle-1", "bottle-2", "bottle-3", "bottle-4") //list of available bottle sprites - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /obj/machinery/chem_master name = "\improper ChemMaster 3000" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE icon = 'icons/obj/machines/chemistry/chemmaster.dmi' icon_state = "mixer0" layer = BELOW_OBJ_LAYER idle_power_usage = 20 clicksound = "button" clickvol = 20 + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = 0 + base_type = /obj/machinery/chem_master + atom_flags = ATOM_FLAG_OPEN_CONTAINER + core_skill = SKILL_CHEMISTRY + chem_volume = 120 + var/obj/item/chems/beaker = null - var/obj/item/storage/pill_bottle/loaded_pill_bottle = null + var/obj/item/pill_bottle/loaded_pill_bottle = null var/mode = 0 var/useramount = 30 // Last used amount var/pillamount = 10 - var/bottlesprite = "bottle-1" //yes, strings var/pillsprite = "1" - var/client/has_sprites = list() + var/list/client/has_sprites = list() var/max_pill_count = 20 - atom_flags = ATOM_FLAG_OPEN_CONTAINER - core_skill = SKILL_CHEMISTRY var/sloppy = 1 //Whether reagents will not be fully purified (sloppy = 1) or there will be reagent loss (sloppy = 0) on reagent add. + var/bottle_label_color = COLOR_WHITE + var/bottle_lid_color = COLOR_OFF_WHITE -/obj/machinery/chem_master/Initialize() - . = ..() - create_reagents(120) - -/obj/machinery/chem_master/explosion_act(severity) - . = ..() - if(. && (severity == 1) || (severity == 2 && prob(50))) - physically_destroyed() +/obj/machinery/chem_master/proc/get_remaining_volume() + return reagents ? clamp(REAGENT_MAXIMUM_VOLUME(reagents) - REAGENT_TOTAL_VOLUME(reagents), 0, REAGENT_MAXIMUM_VOLUME(reagents)) : 0 -/obj/machinery/chem_master/attackby(var/obj/item/B, var/mob/user) +/obj/machinery/chem_master/attackby(var/obj/item/used_item, var/mob/user) - if(istype(B, /obj/item/chems/glass)) + if(istype(used_item, /obj/item/chems/glass)) - if(src.beaker) - to_chat(user, "A beaker is already loaded into the machine.") - return - if(!user.unEquip(B, src)) - return - src.beaker = B - to_chat(user, "You add the beaker to the machine!") - src.updateUsrDialog() + if(beaker) + to_chat(user, SPAN_WARNING("A beaker is already loaded into the machine.")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + beaker = used_item + to_chat(user, SPAN_NOTICE("You add the beaker to the machine!")) + updateUsrDialog() icon_state = "mixer1" + return TRUE - else if(istype(B, /obj/item/storage/pill_bottle)) + if(istype(used_item, /obj/item/chems)) + to_chat(user, SPAN_WARNING("\The [src] will only accept beakers.")) + return TRUE - if(src.loaded_pill_bottle) - to_chat(user, "A pill bottle is already loaded into the machine.") - return - if(!user.unEquip(B, src)) - return - src.loaded_pill_bottle = B - to_chat(user, "You add the pill bottle into the dispenser slot!") - src.updateUsrDialog() + if(istype(used_item, /obj/item/pill_bottle)) -/obj/machinery/chem_master/Topic(href, href_list, state) - if(..()) - return 1 - var/mob/user = usr + if(loaded_pill_bottle) + to_chat(user, SPAN_WARNING("A pill bottle is already loaded into the machine.")) + return TRUE + if(!user.try_unequip(used_item, src)) + return TRUE + loaded_pill_bottle = used_item + to_chat(user, SPAN_NOTICE("You add the pill bottle into the dispenser slot!")) + updateUsrDialog() + return TRUE + + return ..() + +/obj/machinery/chem_master/Topic(href, href_list) + . = ..() + if(. == TOPIC_CLOSE) + close_browser(usr, "window=chem_master") +/obj/machinery/chem_master/OnTopic(mob/user, href_list, state) + if((. = ..())) + return if (href_list["ejectp"]) if(loaded_pill_bottle) loaded_pill_bottle.dropInto(loc) loaded_pill_bottle = null else if(href_list["close"]) - show_browser(user, null, "window=chem_master") - user.unset_machine() - return + return TOPIC_CLOSE if(beaker) + // The custom ones modify our href_list. + if (href_list["addcustom"]) + var/decl/material/their_reagent = locate(href_list["addcustom"]) + if(their_reagent) + useramount = input("Select the amount to transfer.", 30, useramount) as null|num + if(useramount) + useramount = clamp(useramount, 0, 200) + href_list["amount"] = num2text(useramount) + href_list["add"] = href_list["addcustom"] + href_list -= "addcustom" + else + return TOPIC_HANDLED + else + return TOPIC_REFRESH // Tried to move a nonexistent reagent, maybe their UI is stale? + else if(href_list["removecustom"]) + var/decl/material/my_reagents = locate(href_list["removecustom"]) + if(my_reagents) + useramount = input("Select the amount to transfer.", 30, useramount) as null|num + if(useramount) + useramount = clamp(useramount, 0, 200) + href_list["amount"] = num2text(useramount) + href_list["remove"] = href_list["removecustom"] + href_list -= "removecustom" + else + return TOPIC_HANDLED + + // DO NOT use else if here, we want these to run even if the custom ones do var/datum/reagents/R = beaker.reagents if (href_list["analyze"]) var/decl/material/reagent = locate(href_list["analyze"]) var/dat = get_chem_info(reagent) if(dat && REAGENT_VOLUME(beaker.reagents, reagent.type)) show_browser(user, dat, "window=chem_master;size=575x400") - return + return TOPIC_HANDLED else if (href_list["add"]) if(href_list["amount"]) var/decl/material/their_reagent = locate(href_list["add"]) if(their_reagent) var/mult = 1 - var/amount = Clamp((text2num(href_list["amount"])), 0, 200) + var/amount = clamp((text2num(href_list["amount"])), 0, get_remaining_volume()) if(sloppy) var/contaminants = fetch_contaminants(user, R, their_reagent) for(var/decl/material/reagent in contaminants) @@ -96,113 +131,95 @@ else mult -= 0.4 * (SKILL_MAX - user.get_skill_value(core_skill))/(SKILL_MAX-SKILL_MIN) //10% loss per skill level down from max R.trans_type_to(src, their_reagent.type, amount, mult) - - - - else if (href_list["addcustom"]) - var/decl/material/their_reagent = locate(href_list["addcustom"]) - if(their_reagent) - useramount = input("Select the amount to transfer.", 30, useramount) as null|num - if(useramount) - useramount = Clamp(useramount, 0, 200) - src.Topic(href, list("amount" = "[useramount]", "add" = href_list["addcustom"]), state) + return TOPIC_REFRESH else if (href_list["remove"]) if(href_list["amount"]) var/decl/material/my_reagents = locate(href_list["remove"]) if(my_reagents) - var/amount = Clamp((text2num(href_list["amount"])), 0, 200) + var/amount = clamp((text2num(href_list["amount"])), 0, 200) var/contaminants = fetch_contaminants(user, reagents, my_reagents) if(mode) reagents.trans_type_to(beaker, my_reagents.type, amount) for(var/decl/material/reagent in contaminants) reagents.trans_type_to(beaker, reagent.type, round(rand()*amount, 0.1)) else - reagents.remove_reagent(my_reagents.type, amount) + remove_from_reagents(my_reagents.type, amount) for(var/decl/material/reagent in contaminants) - reagents.remove_reagent(reagent.type, round(rand()*amount, 0.1)) - - else if (href_list["removecustom"]) - var/decl/material/my_reagents = locate(href_list["removecustom"]) - if(my_reagents) - useramount = input("Select the amount to transfer.", 30, useramount) as null|num - if(useramount) - useramount = Clamp(useramount, 0, 200) - src.Topic(href, list("amount" = "[useramount]", "remove" = href_list["removecustom"]), state) + remove_from_reagents(reagent.type, round(rand()*amount, 0.1)) + return TOPIC_REFRESH else if (href_list["toggle"]) mode = !mode + return TOPIC_REFRESH else if (href_list["toggle_sloppy"]) sloppy = !sloppy + return TOPIC_REFRESH else if (href_list["main"]) - interact(user) - return + return TOPIC_REFRESH else if (href_list["eject"]) beaker.forceMove(loc) beaker = null reagents.clear_reagents() icon_state = "mixer0" + return TOPIC_REFRESH else if (href_list["createpill"] || href_list["createpill_multiple"]) var/count = 1 - if(reagents.total_volume/count < 1) //Sanity checking. - return + if(REAGENT_TOTAL_VOLUME(reagents)/count < 1) //Sanity checking. + return TOPIC_HANDLED if (href_list["createpill_multiple"]) count = input("Select the number of pills to make.", "Max [max_pill_count]", pillamount) as num - count = Clamp(count, 1, max_pill_count) - - if(reagents.total_volume/count < 1) //Sanity checking. - return - - var/amount_per_pill = reagents.total_volume/count - if (amount_per_pill > 30) amount_per_pill = 30 - - var/name = sanitizeSafe(input(usr,"Name:","Name your pill!","[reagents.get_primary_reagent_name()] ([amount_per_pill]u)"), MAX_NAME_LEN) - - if(reagents.total_volume/count < 1) //Sanity checking. - return + if(!CanInteract(user, state)) + return TOPIC_HANDLED + count = clamp(count, 1, max_pill_count) + + var/amount_per_pill = min(REAGENT_TOTAL_VOLUME(reagents)/count, 30) + if(amount_per_pill < 1) // Sanity checking. + return TOPIC_HANDLED + + var/name = sanitize_safe(input(usr,"Name:","Name your pill!","[reagents.get_primary_reagent_name()] ([amount_per_pill]u)"), MAX_NAME_LEN) + if(!CanInteract(user, state)) + return TOPIC_HANDLED + if(REAGENT_TOTAL_VOLUME(reagents)/count < 1) //Sanity checking. + return TOPIC_HANDLED while (count-- && count >= 0) - var/obj/item/chems/pill/P = new/obj/item/chems/pill(loc) + var/obj/item/chems/pill/dispensed/P = new(loc) if(!name) name = reagents.get_primary_reagent_name() P.SetName("[name] pill") P.icon_state = "pill"+pillsprite - if(P.icon_state in list("pill1", "pill2", "pill3", "pill4", "pill5")) // if using greyscale, take colour from reagent - P.color = reagents.get_color() reagents.trans_to_obj(P,amount_per_pill) - if(loaded_pill_bottle) - if(loaded_pill_bottle.contents.len < loaded_pill_bottle.max_storage_space) - P.forceMove(loaded_pill_bottle) + P.update_icon() + if(loaded_pill_bottle && loaded_pill_bottle.storage && loaded_pill_bottle.contents.len < loaded_pill_bottle.storage.max_storage_space) + P.forceMove(loaded_pill_bottle) + return TOPIC_REFRESH else if (href_list["createbottle"]) create_bottle(user) + return TOPIC_REFRESH else if(href_list["change_pill"]) #define MAX_PILL_SPRITE 25 //max icon state of the pill sprites var/dat = "" for(var/i = 1 to MAX_PILL_SPRITE) - dat += "" - dat += "
    " - show_browser(user, dat, "window=chem_master") - return - else if(href_list["change_bottle"]) - var/dat = "" - for(var/sprite in BOTTLE_SPRITES) - dat += "" + dat += "" dat += "
    " show_browser(user, dat, "window=chem_master") - return + return TOPIC_HANDLED else if(href_list["pill_sprite"]) pillsprite = href_list["pill_sprite"] - else if(href_list["bottle_sprite"]) - bottlesprite = href_list["bottle_sprite"] - - updateUsrDialog() + return TOPIC_REFRESH + else if(href_list["label_color"]) + bottle_label_color = input(usr, "Pick new bottle label color", "Label color", bottle_label_color) as color + return TOPIC_REFRESH + else if(href_list["lid_color"]) + bottle_lid_color = input(usr, "Pick new bottle lid color", "Lid color", bottle_lid_color) as color + return TOPIC_REFRESH /obj/machinery/chem_master/proc/fetch_contaminants(mob/user, datum/reagents/reagents, decl/material/main_reagent) . = list() - for(var/rtype in reagents.reagent_volumes) - var/decl/material/reagent = decls_repository.get_decl(rtype) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) if(reagent != main_reagent && prob(user.skill_fail_chance(core_skill, 100))) . += reagent @@ -211,28 +228,30 @@ return . = list() . += "[name]" - . += "[heading]:

    Name:
    [reagent.name]" + . += "[heading]:

    Name:
    [reagent.use_name]" . += "

    Description:
    " if(detailed_blood && istype(reagent, /decl/material/liquid/blood)) var/blood_data = REAGENT_DATA(beaker?.reagents, /decl/material/liquid/blood) - . += "Blood Type: [LAZYACCESS(blood_data, "blood_type")]
    DNA: [LAZYACCESS(blood_data, "blood.DNA")]" + . += "Blood Type: [LAZYACCESS(blood_data, DATA_BLOOD_TYPE)]
    DNA: [LAZYACCESS(blood_data, DATA_BLOOD_DNA)]" else . += "[reagent.lore_text]" - . += "


    (Back)" + . += "


    (Back)" . = JOINTEXT(.) /obj/machinery/chem_master/proc/create_bottle(mob/user) - var/name = sanitizeSafe(input(usr,"Name:","Name your bottle!",reagents.get_primary_reagent_name()), MAX_NAME_LEN) + var/name = sanitize_safe(input(usr,"Name:","Name your bottle!",reagents.get_primary_reagent_name()), MAX_NAME_LEN) var/obj/item/chems/glass/bottle/P = new/obj/item/chems/glass/bottle(loc) if(!name) name = reagents.get_primary_reagent_name() - P.SetName("[name] bottle") - P.icon_state = bottlesprite + P.label_text = name + P.update_name() + P.lid_color = bottle_lid_color + P.label_color = bottle_label_color reagents.trans_to_obj(P,60) P.update_icon() /obj/machinery/chem_master/DefaultTopicState() - return GLOB.physical_state + return global.physical_topic_state /obj/machinery/chem_master/interface_interact(mob/user) interact(user) @@ -244,52 +263,48 @@ spawn() has_sprites += user.client for(var/i = 1 to MAX_PILL_SPRITE) - send_rsc(usr, icon('icons/obj/items/chem/pill.dmi', "pill" + num2text(i)), "pill[i].png") - for(var/sprite in BOTTLE_SPRITES) - send_rsc(usr, icon('icons/obj/items/chem/bottle.dmi', sprite), "[sprite].png") + send_rsc(user, icon('icons/obj/items/chem/pill.dmi', "pill" + num2text(i)), "pill[i].png") var/dat = list() dat += "[name]" dat += "[name] Menu:" if(!beaker) dat += "Please insert beaker.
    " - if(loaded_pill_bottle) - dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.max_storage_space]\]

    " + if(loaded_pill_bottle?.storage) + dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.storage.max_storage_space]\]

    " else dat += "No pill bottle inserted.

    " - dat += "Close" + dat += "Close" else var/datum/reagents/R = beaker.reagents - dat += "Eject beaker and Clear Buffer
    " - dat += "Toggle purification mode: [sloppy ? "Quick" : "Thorough"]
    " - if(loaded_pill_bottle) - dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.max_storage_space]\]

    " + dat += "Eject beaker and Clear Buffer
    " + dat += "Toggle purification mode: [sloppy ? "Quick" : "Thorough"]
    " + if(loaded_pill_bottle?.storage) + dat += "Eject Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.storage.max_storage_space]\]

    " else dat += "No pill bottle inserted.

    " - if(!R.total_volume) + if(!REAGENT_TOTAL_VOLUME(R)) dat += "Beaker is empty." else dat += "Add to buffer:
    " - for(var/rtype in R.reagent_volumes) - var/decl/material/G = decls_repository.get_decl(rtype) - dat += "[G.name], [REAGENT_VOLUME(R, rtype)] Units - " - dat += "(Analyze) " - dat += "(1) " - dat += "(5) " - dat += "(10) " - dat += "(All) " - dat += "(Custom)
    " - - dat += "
    Transfer to [(!mode ? "disposal" : "beaker")]:
    " - if(reagents.total_volume) - for(var/rtype in reagents.reagent_volumes) - var/decl/material/N = decls_repository.get_decl(rtype) - dat += "[N.name], [REAGENT_VOLUME(reagents, rtype)] Units - " - dat += "(Analyze) " - dat += "(1) " - dat += "(5) " - dat += "(10) " - dat += "(All) " - dat += "(Custom)
    " + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(R)) + dat += "[reagent.use_name], [REAGENT_VOLUME(R, reagent)] Units - " + dat += "(Analyze) " + dat += "(1) " + dat += "(5) " + dat += "(10) " + dat += "(All) " + dat += "(Custom)
    " + + dat += "
    Transfer to [(!mode ? "disposal" : "beaker")]:
    " + if(REAGENT_TOTAL_VOLUME(reagents)) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + dat += "[reagent.use_name], [REAGENT_VOLUME(reagents, reagent)] Units - " + dat += "(Analyze) " + dat += "(1) " + dat += "(5) " + dat += "(10) " + dat += "(All) " + dat += "(Custom)
    " else dat += "Empty
    " dat += extra_options() @@ -299,9 +314,11 @@ //Use to add extra stuff to the end of the menu. /obj/machinery/chem_master/proc/extra_options() . = list() - . += "

    Create pill (30 units max)
    " - . += "Create multiple pills
    " - . += "Create bottle (60 units max)" + . += "

    Create pill (30 units max)
    " + . += "Create multiple pills
    " + . += "Create bottle (60 units max)" + . += "
    Bottle Label Color:\t▉" + . += "
    Bottle Lid Color:\t▉" return JOINTEXT(.) /obj/machinery/chem_master/condimaster @@ -312,8 +329,8 @@ return ..(reagent, "Condiment infos", 0) /obj/machinery/chem_master/condimaster/create_bottle(mob/user) - var/obj/item/chems/food/condiment/P = new/obj/item/chems/food/condiment(src.loc) + var/obj/item/chems/condiment/P = new/obj/item/chems/condiment(src.loc) reagents.trans_to_obj(P,50) /obj/machinery/chem_master/condimaster/extra_options() - return "Create bottle (50 units max)" \ No newline at end of file + return "Create bottle (50 units max)" diff --git a/code/modules/reagents/Chemistry-Metabolism.dm b/code/modules/reagents/Chemistry-Metabolism.dm index 6d56e3618610..f15b50662785 100644 --- a/code/modules/reagents/Chemistry-Metabolism.dm +++ b/code/modules/reagents/Chemistry-Metabolism.dm @@ -1,27 +1,28 @@ /datum/reagents/metabolism var/metabolism_class //CHEM_TOUCH, CHEM_INGEST, or CHEM_INJECT - var/mob/living/carbon/parent + var/mob/living/parent -/datum/reagents/metabolism/clear_reagent(var/reagent_type) - if(REAGENT_VOLUME(src, reagent_type)) - var/decl/material/current = decls_repository.get_decl(reagent_type) - current.on_leaving_metabolism(parent, metabolism_class) +/datum/reagents/metabolism/clear_reagent(var/decl/material/reagent, var/defer_update = FALSE, var/force = FALSE) + // Duplicated check so that reagent data is accessible in on_leaving_metabolism. + reagent = RESOLVE_TO_DECL(reagent) + if(force || !!(REAGENT_VOLUME(src, reagent) || REAGENT_DATA(src, reagent))) + reagent.on_leaving_metabolism(src) . = ..() -/datum/reagents/metabolism/New(var/max = 100, mob/living/carbon/parent_mob, var/met_class) +/datum/reagents/metabolism/New(var/max = 100, mob/living/parent_mob, var/met_class) ..(max, parent_mob) metabolism_class = met_class if(istype(parent_mob)) parent = parent_mob -/datum/reagents/metabolism/proc/metabolize() - if(parent) - var/metabolism_type = 0 //non-human mobs - if(ishuman(parent)) - var/mob/living/carbon/human/H = parent - metabolism_type = H.species.reagent_tag - for(var/rtype in reagent_volumes) - var/decl/material/current = decls_repository.get_decl(rtype) - current.on_mob_life(parent, metabolism_type, metabolism_class, src) - update_total() \ No newline at end of file +/datum/reagents/metabolism/Destroy() + parent = null + return ..() + +/datum/reagents/metabolism/proc/metabolize(list/dosage_tracker) + if(!parent || total_volume < MINIMUM_CHEMICAL_VOLUME || !length(reagent_volumes)) + return + for(var/decl/material/reagent as anything in reagent_volumes) + reagent.on_mob_life(parent, metabolism_class, src, dosage_tracker) + update_total() diff --git a/code/modules/reagents/Chemistry-Taste.dm b/code/modules/reagents/Chemistry-Taste.dm new file mode 100644 index 000000000000..959f790b398c --- /dev/null +++ b/code/modules/reagents/Chemistry-Taste.dm @@ -0,0 +1,74 @@ +/* what this does: +catalogue the 'taste strength' of each one +calculate text size per text. +*/ +/datum/reagents/proc/generate_taste_message(mob/living/taster, datum/reagents/source_holder) + + if(!istype(taster)) + return + + var/minimum_percent + if(taster.isSynthetic()) + minimum_percent = TASTE_DULL + else + var/decl/species/my_species = istype(taster) && taster?.get_species() + if(my_species) + // the taste bonus makes it so that sipping a drink lets you taste it better + // 1u makes it 2x as strong, 2u makes it 1.5x, 5u makes it 1.2x, etc + minimum_percent = (my_species.taste_sensitivity * clamp(1 + (1/max(total_volume, 1)), 1, 2)) + else + minimum_percent = TASTE_NORMAL + minimum_percent = round(TASTE_DEGREE_PROB/minimum_percent) + + if(minimum_percent > 100) + return + + var/list/tastes = get_taste_list(source_holder) //descriptor = strength + var/total_taste = 0 + for(var/taste in tastes) + total_taste += tastes[taste] + + //deal with percentages + for(var/taste in tastes) + var/percent = tastes[taste]/total_taste * 100 + if(percent < minimum_percent) + continue + var/intensity_desc = "a hint of" + if(percent > minimum_percent * 2 || percent == 100) + intensity_desc = "" + else if(percent > minimum_percent * 3) + intensity_desc = "the strong flavor of" + if(intensity_desc == "") + LAZYADD(., "[taste]") + else + LAZYADD(., "[intensity_desc] [taste]") + + if(length(.)) + . = english_list(., "something indescribable") + +/datum/reagents/proc/get_taste_list(datum/reagents/source_holder) + var/list/tastes = list() //descriptor = strength + for(var/decl/material/reagent as anything in reagent_volumes) + var/list/nutriment_data = LAZYACCESS(reagent_data, reagent) + var/list/taste_data = LAZYACCESS(nutriment_data, DATA_TASTE) + if(length(taste_data)) + for(var/taste in taste_data) + var/taste_power = taste_data[taste] + tastes[taste] += taste_power + else if(reagent.taste_description) + tastes[reagent.taste_description] += reagent.taste_mult + + var/decl/material/primary_ingredient = get_primary_reagent_decl() + if(primary_ingredient?.cocktail_ingredient && source_holder?.my_atom) + for(var/decl/cocktail/cocktail in SSmaterials.get_cocktails_by_primary_ingredient(primary_ingredient.type)) + if(!LAZYLEN(cocktail.tastes)) + continue + if(!cocktail.matches(source_holder.my_atom)) + continue + var/cocktail_volume = 0 + for(var/chem in cocktail.ratios) + cocktail_volume += REAGENT_VOLUME(src, chem) + for(var/taste_desc in cocktail.tastes) + var/taste_power = cocktail.tastes[taste_desc] * cocktail_volume + tastes[taste_desc] += taste_power + return tastes diff --git a/code/modules/reagents/chems/chems_alcohol.dm b/code/modules/reagents/chems/chems_alcohol.dm new file mode 100644 index 000000000000..8580983b784a --- /dev/null +++ b/code/modules/reagents/chems/chems_alcohol.dm @@ -0,0 +1,562 @@ +/decl/material/liquid/alcohol + abstract_type = /decl/material/liquid/alcohol + color = "#404030" + touch_met = 5 + ignition_point = T0C+150 + accelerant_value = FUEL_VALUE_ACCELERANT + solvent_power = MAT_SOLVENT_MODERATE + + boiling_point = null // Pure ethanol boils, the rest has to separate first. + + heating_message = "boils away its water content, leaving pure alcohol." + heating_point = T0C + 78.37 + heating_products = list( + /decl/material/liquid/alcohol/ethanol = 0.75, + /decl/material/liquid/water = 0.25 + ) + + chilling_message = "separates as its water content freezes, leaving pure alcohol." + chilling_point = T0C + chilling_products = list( + /decl/material/liquid/alcohol/ethanol = 0.75, + /decl/material/solid/ice = 0.25 + ) + affect_blood_on_ingest = FALSE // prevents automatic toxins/inebriation as though injected + affect_blood_on_inhale = FALSE + + value = 1.2 + + var/strength = 10 // This is, essentially, units between stages - the lower, the stronger. Less fine tuning, more clarity. + var/alcohol_toxicity = 1 + var/adj_temp = 0 + var/targ_temp = 310 + var/halluci = 0 + +/decl/material/liquid/alcohol/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + M.take_damage(removed * 2 * alcohol_toxicity, TOX) + M.add_chemical_effect(CE_ALCOHOL_TOXIC, alcohol_toxicity) + +/decl/material/liquid/alcohol/affect_inhale(mob/living/M, removed, datum/reagents/holder) + if(M.has_trait(/decl/trait/metabolically_inert)) + return + ..() + affect_ingest(M, removed, holder) // a bit of a hack, but it avoids code duplication + +/decl/material/liquid/alcohol/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + ..() + + M.add_chemical_effect(CE_ALCOHOL, 1) + var/strength_mod = (M.get_trait_level(/decl/trait/malus/ethanol) * 2.5) || 1 + + var/effective_dose = CHEM_DOSE(M, src) * strength_mod * (1 + REAGENT_VOLUME(holder, src)/60) //drinking a LOT will make you go down faster + if(effective_dose >= strength) // Early warning + ADJ_STATUS(M, STAT_DIZZY, 6) // It is decreased at the speed of 3 per tick + if(effective_dose >= strength * 2) // Slurring + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + SET_STATUS_MAX(M, STAT_SLUR, 30) + if(effective_dose >= strength * 3) // Confusion - walking in random directions + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + SET_STATUS_MAX(M, STAT_CONFUSE, 20) + if(effective_dose >= strength * 4) // Blurry vision + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + SET_STATUS_MAX(M, STAT_BLURRY, 10) + if(effective_dose >= strength * 5) // Drowsyness - periodically falling asleep + M.add_chemical_effect(CE_PAINKILLER, 150/strength) + SET_STATUS_MAX(M, STAT_DROWSY, 20) + if(effective_dose >= strength * 6) // Toxic dose + M.add_chemical_effect(CE_ALCOHOL_TOXIC, alcohol_toxicity) + if(effective_dose >= strength * 7) // Pass out + SET_STATUS_MAX(M, STAT_PARA, 20) + SET_STATUS_MAX(M, STAT_ASLEEP, 30) + if(euphoriant) + SET_STATUS_MAX(M, STAT_DRUGGY, euphoriant) + + if(adj_temp > 0 && M.bodytemperature < targ_temp) // 310 is the normal bodytemp. 310.055 + M.bodytemperature = min(targ_temp, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + if(adj_temp < 0 && M.bodytemperature > targ_temp) + M.bodytemperature = min(targ_temp, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) + + if(halluci) + M.adjust_hallucination(halluci, halluci) + +// Somewhat a dummy type for 'pure ethanol' to avoid having to set dirtiness/heating products/etc on literally everything else. +/decl/material/liquid/alcohol/ethanol + name = "ethanol" + lore_text = "A well-known alcohol with a variety of applications." + taste_description = "pure alcohol" + glass_name = "ethanol" + glass_desc = "A well-known alcohol with a variety of applications." + dirtiness = DIRTINESS_STERILE + uid = "chem_ethanol" + + // Uncomment when refining spirits is less annoying, specifically when we have more precise temperature control. + // boiling_point = T0C + 78.37 + // can_boil_to_gas = TRUE + // temperature_burn_milestone_material = /decl/material/liquid/alcohol/ethanol + + // Pure ethanol does not separate. + heating_point = null + heating_products = null + chilling_point = null + chilling_products = null + +/decl/material/liquid/alcohol/absinthe + name = "absinthe" + lore_text = "Watch out that the Green Fairy doesn't come for you!" + taste_description = "death and licorice" + taste_mult = 1.5 + color = "#33ee00" + strength = 12 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + glass_name = "absinthe" + glass_desc = "Wormwood, anise, oh my." + uid = "chem_ethanol_absinthe" + +/decl/material/liquid/alcohol/ale + name = "ale" + lore_text = "A dark alcoholic beverage made by malted barley and yeast." + taste_description = "hearty barley ale" + color = "#4c3100" + strength = 50 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + glass_name = "ale" + glass_desc = "A freezing container of delicious ale" + uid = "chem_ethanol_ale" + +/decl/material/liquid/alcohol/beer + name = "beer" + codex_name = "plain beer" + lore_text = "An alcoholic beverage made from malted grains, hops, yeast, and water." + taste_description = "piss water" + color = "#ffd300" + strength = 50 + nutriment_factor = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + + glass_name = "beer" + glass_desc = "A freezing container of beer" + uid = "chem_ethanol_beer" + +/decl/material/liquid/alcohol/beer/good + uid = "chem_ethanol_beer_good" + codex_name = "premium beer" + taste_description = "beer" + +/decl/material/liquid/alcohol/beer/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + if(M.has_trait(/decl/trait/metabolically_inert)) + return + ADJ_STATUS(M, STAT_JITTER, -3) + +/decl/material/liquid/alcohol/bluecuracao + name = "blue curacao" + lore_text = "Exotically blue, fruity drink, distilled from oranges." + taste_description = "oranges" + taste_mult = 1.1 + color = "#0000cd" + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_bluecuracao" + + glass_name = "blue curacao" + glass_desc = "Exotically blue, fruity drink, distilled from oranges." + +/decl/material/liquid/alcohol/cognac + name = "cognac" + lore_text = "A sweet and strongly alcoholic drink, made after numerous distillations and years of maturing. Classy as fornication." + taste_description = "rich and smooth alcohol" + taste_mult = 1.1 + color = "#ab3c05" + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_cognac" + + glass_name = "cognac" + glass_desc = "Damn, you feel like some kind of French aristocrat just by holding this." + +/decl/material/liquid/alcohol/gin + name = "gin" + lore_text = "It's gin. In space. I say, good sir." + taste_description = "an alcoholic christmas tree" + color = "#0064c6" + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_gin" + + glass_name = "gin" + glass_desc = "A crystal clear glass of Griffeater gin." + +//Base type for alcoholic drinks containing coffee +/decl/material/liquid/alcohol/coffee + name = "coffee liqueur" + lore_text = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936!" + taste_description = "spiked coffee" + taste_mult = 1.1 + color = "#4c3100" + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_coffee" + glass_name = "coffee liqueur" + glass_desc = "Guaranteed to perk you up." + overdose = 45 + +/decl/material/liquid/alcohol/coffee/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + ADJ_STATUS(M, STAT_DIZZY, -5) + ADJ_STATUS(M, STAT_DROWSY, -3) + ADJ_STATUS(M, STAT_ASLEEP, -2) + if(M.bodytemperature > 310) + M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) + +/decl/material/liquid/alcohol/coffee/affect_overdose(mob/living/victim, total_dose) + ADJ_STATUS(victim, STAT_JITTER, 5) + +/decl/material/liquid/alcohol/melonliquor + name = "melon liqueur" + lore_text = "A relatively sweet and fruity 46 proof liqueur." + taste_description = "fruity alcohol" + color = "#138808" // rgb: 19, 136, 8 + strength = 50 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_melon" + + glass_name = "melon liqueur" + glass_desc = "A relatively sweet and fruity 46 proof liquor." + +/decl/material/liquid/alcohol/rum + name = "dark rum" + lore_text = "Yohoho and all that." + taste_description = "spiked butterscotch" + taste_mult = 1.1 + color = "#ecb633" + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_rum" + + glass_name = "rum" + glass_desc = "Now you want to Pray for a pirate suit, don't you?" + +/decl/material/liquid/alcohol/sake + name = "sake" + lore_text = "Anime's favorite drink." + taste_description = "dry alcohol" + color = "#dddddd" + strength = 25 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_sake" + + glass_name = "sake" + glass_desc = "A glass of sake." + +/decl/material/liquid/alcohol/tequila + name = "tequila" + lore_text = "A strong and mildly flavoured, mexican produced spirit. Feeling thirsty hombre?" + taste_description = "paint stripper" + color = "#ffff91" + strength = 25 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_tequila" + + glass_name = "tequila" + glass_desc = "Now all that's missing is the weird colored shades!" + +/decl/material/liquid/alcohol/thirteenloko + name = "Thirteen Loko" + lore_text = "A potent mixture of caffeine and alcohol." + taste_description = "jitters and death" + color = "#102000" + strength = 25 + nutriment_factor = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_thirteenloko" + + glass_name = "Thirteen Loko" + glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass." + +/decl/material/liquid/alcohol/thirteenloko/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + ADJ_STATUS(M, STAT_DROWSY, -7) + if(M.bodytemperature > 310) + M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) + ADJ_STATUS(M, STAT_JITTER, 5) + M.add_chemical_effect(CE_PULSE, 2) + +/decl/material/liquid/alcohol/vermouth + name = "vermouth" + lore_text = "You suddenly feel a craving for a martini..." + taste_description = "dry alcohol" + taste_mult = 1.3 + color = "#91ff91" // rgb: 145, 255, 145 + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_vermouth" + + glass_name = "vermouth" + glass_desc = "You wonder why you're even drinking this straight." + +/decl/material/liquid/alcohol/vodka + name = "vodka" + codex_name = "plain vodka" + lore_text = "High-proof grain alcohol, useful for cocktails... and as bootleg rocket fuel, for those prone to amateur rocketry or trade sanctions." + taste_description = "grain alcohol" + color = "#0064c8" // rgb: 0, 100, 200 + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_vodka" + + glass_name = "vodka" + glass_desc = "The glass contain wodka. Xynta." + +/decl/material/liquid/alcohol/vodka/premium + name = "premium vodka" + codex_name = null + lore_text = "Premium distilled vodka made from real, planet-grown potatoes." + taste_description = "clear kvass" + color = "#aaddff" // rgb: 170, 221, 255 - very light blue. + strength = 10 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_premiumvodka" + +/decl/material/liquid/alcohol/whiskey + name = "malt whiskey" + lore_text = "A superb and well-aged single-malt whiskey. Damn." + taste_description = "molasses" + color = "#4c3100" + strength = 25 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_whiskey" + + glass_name = "whiskey" + glass_desc = "The silky, smokey whiskey goodness inside the glass makes the drink look very classy." + +/decl/material/liquid/alcohol/wine + name = "red wine" + lore_text = "An premium alcoholic beverage made from distilled grape juice." + taste_description = "bitter sweetness" + color = "#7e4043" // rgb: 126, 64, 67 + strength = 15 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_wine" + + glass_name = "red wine" + glass_desc = "A very classy looking drink." + +/decl/material/liquid/alcohol/wine/premium + name = "white wine" + lore_text = "An exceptionally expensive alcoholic beverage made from distilled white grapes." + taste_description = "white velvet" + color = "#ffddaa" // rgb: 255, 221, 170 - a light cream + strength = 20 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_whitewine" + +/decl/material/liquid/alcohol/herbal + name = "herbal liquor" + lore_text = "A complex blend of herbs, spices and roots mingle in this old Earth classic." + taste_description = "a sweet summer garden" + color = "#dfff00" + strength = 13 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_herbal" + + glass_name = "herbal liquor" + glass_desc = "It's definitely green. Or is it yellow?" + +/decl/material/liquid/alcohol/hooch + name = "hooch" + lore_text = "Either someone's failure at cocktail making or attempt in alchohol production. In any case, do you really want to drink that?" + taste_description = "pure resignation" + color = "#4c3100" + strength = 25 + alcohol_toxicity = 2 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_hooch" + + glass_name = "Hooch" + glass_desc = "You've really hit rock bottom now... your liver packed its bags and left last night." + +/decl/material/liquid/alcohol/irish_cream + name = "Irish cream" + lore_text = "Whiskey-imbued cream." + taste_description = "creamy alcohol" + color = "#dddd9a" + strength = 25 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_irishcream" + + glass_name = "Irish cream" + glass_desc = "It's cream, mixed with whiskey." + +/decl/material/liquid/alcohol/mead + name = "mead" + lore_text = "A Viking's drink, though a cheap one." + taste_description = "sweet, sweet alcohol" + color = "#ffbb00" + strength = 30 + nutriment_factor = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_mead" + + glass_name = "mead" + glass_desc = "A Viking's beverage, though a cheap one." + +/decl/material/liquid/alcohol/moonshine + name = "moonshine" + lore_text = "You've really hit rock bottom now... your liver packed its bags and left last night." + taste_description = "bitterness" + taste_mult = 2.5 + color = "#0064c8" + strength = 12 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_moonshine" + + glass_name = "moonshine" + glass_desc = "You've really hit rock bottom now... your liver packed its bags and left last night." + +/decl/material/liquid/alcohol/pwine + name = "poison wine" + lore_text = "Is this even wine? Toxic! Hallucinogenic! Probably consumed in boatloads by your superiors!" + taste_description = "purified alcoholic death" + color = "#000000" + strength = 10 + halluci = 10 + glass_name = "???" + glass_desc = "A black ichor with an oily purple sheer on top. Are you sure you should drink this?" + euphoriant = 50 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_poisonwine" + +/decl/material/liquid/alcohol/pwine/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + var/dose = CHEM_DOSE(M, src) + if(dose > 30) + M.take_damage(2 * removed, TOX) + if(dose > 60 && ishuman(M) && prob(5)) + var/mob/living/human/H = M + var/obj/item/organ/internal/heart = GET_INTERNAL_ORGAN(H, BP_HEART) + if(heart) + if(dose < 120) + heart.take_damage(10 * removed, 0) + else + heart.take_damage(100, 0) + +/decl/material/liquid/alcohol/aged_whiskey // I have no idea what this is and where it comes from. //It comes from Dinnlan now + name = "aged whiskey" + lore_text = "A well-aged whiskey of high quality. Probably imported. Just a sip'll do it, but that burn will leave you wanting more." + color = "#523600" + strength = 25 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_agedwhiskey" + + glass_name = "aged whiskey" + glass_desc = "A well-aged whiskey of high quality. Probably imported." + +/decl/material/liquid/alcohol/cider_apple + name = "apple cider" + lore_text = "A refreshing glass of apple cider." + taste_description = "cool apple cider" + color = "#cac089" + strength = 50 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_applecider" + + glass_name = "apple cider" + glass_desc = "A refreshing glass of apple cider." + +/decl/material/liquid/alcohol/cider_pear + name = "pear cider" + lore_text = "A refreshing glass of pear cider." + taste_description = "cool pear cider" + color = "#cac089" + strength = 50 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_pearcider" + + glass_name = "pear cider" + glass_desc = "A refreshing glass of pear cider." + +/decl/material/liquid/alcohol/champagne + name = "champagne" + lore_text = "Smooth sparkling wine, produced in the same region of France as it has been for centuries." + taste_description = "bitterness and fizz" + color = "#a89410" + strength = 18 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_champagne" + + glass_name = "champagne" + glass_desc = "Sparkling white wine, produced in the same region of France as it has been for centuries." + glass_special = list(DRINK_FIZZ) + +/decl/material/liquid/alcohol/jagermeister + name = "Jagermeister" + lore_text = "A special blend of alcohol, herbs, and spices. It has remained a popular Earther drink." + taste_description = "herbs, spices, and alcohol" + color = "#596e3e" + strength = 20 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_jagermeister" + + glass_name = "jagermeister" + glass_desc = "A special blend of alcohol, herbs, and spices. It has remained a popular Earther drink." + +/decl/material/liquid/alcohol/kvass + name = "kvass" + lore_text = "An alcoholic drink commonly made from bread." + taste_description = "vkusnyy kvas, ypa!" + color = "#362f22" + strength = 30 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_ethanol_kvass" + + glass_name = "kvass" + glass_desc = "An alcoholic drink commonly made from bread." diff --git a/code/modules/reagents/chems/chems_blood.dm b/code/modules/reagents/chems/chems_blood.dm index 5f4642f36754..299944612356 100644 --- a/code/modules/reagents/chems/chems_blood.dm +++ b/code/modules/reagents/chems/chems_blood.dm @@ -1,5 +1,7 @@ /decl/material/liquid/blood name = "blood" + codex_name = "whole blood" + uid = "chem_blood" lore_text = "A red (or blue) liquid commonly found inside animals, most of whom are pretty insistent about it being left where you found it." metabolism = REM * 5 color = "#c80000" @@ -8,7 +10,12 @@ taste_mult = 1.3 glass_name = "tomato juice" glass_desc = "Are you sure this is tomato juice?" + coated_adjective = "bloody" value = 2.5 + opacity = 1.0 + min_fluid_opacity = FLUID_MAX_ALPHA + max_fluid_opacity = 240 + compost_value = 1 // yum chilling_products = list( /decl/material/liquid/coagulated_blood = 1 @@ -21,63 +28,57 @@ ) heating_point = 318 heating_message = "coagulates and clumps together." + affect_blood_on_ingest = FALSE -/decl/material/liquid/blood/initialize_data(var/newdata) +/decl/material/liquid/blood/initialize_data(list/newdata) . = ..() || list() - if(.) - .["species"] = .["species"] || GLOB.using_map.default_species + .[DATA_BLOOD_SPECIES] ||= global.using_map.default_species -/decl/material/liquid/blood/mix_data(var/datum/reagents/reagents, var/list/newdata, var/amount) - var/list/data = REAGENT_DATA(reagents, type) - if(LAZYACCESS(newdata, "trace_chem")) - var/list/other_chems = LAZYACCESS(newdata, "trace_chem") - if(!data) - data = newdata.Copy() - else if(!data["trace_chem"]) - data["trace_chem"] = other_chems.Copy() +/decl/material/liquid/blood/mix_data(var/datum/reagents/reagents, var/list/newdata, var/amount) + . = ..() + if(LAZYACCESS(newdata, DATA_BLOOD_TRACE_CHEM)) + var/list/other_chems = LAZYACCESS(newdata, DATA_BLOOD_TRACE_CHEM) + if(!.) + . = newdata.Copy() + else if(!.[DATA_BLOOD_TRACE_CHEM]) + .[DATA_BLOOD_TRACE_CHEM] = other_chems.Copy() else - var/list/my_chems = data["trace_chem"] + var/list/my_chems = .[DATA_BLOOD_TRACE_CHEM] for(var/chem in other_chems) my_chems[chem] = my_chems[chem] + other_chems[chem] - . = data -/decl/material/liquid/blood/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) - var/data = REAGENT_DATA(holder, type) - if(!istype(T) || REAGENT_VOLUME(holder, type) < 3) +/decl/material/liquid/blood/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) + var/data = REAGENT_DATA(holder, src) + if(!istype(touching_turf) || REAGENT_VOLUME(holder, src) < 3) return - var/weakref/W = LAZYACCESS(data, "donor") - if (!W) - blood_splatter(T, src, 1) - return - W = W.resolve() - if(ishuman(W)) - blood_splatter(T, src, 1) - else if(isalien(W)) - var/obj/effect/decal/cleanable/blood/B = blood_splatter(T, holder.my_atom, 1) - if(B) - B.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" - -/decl/material/liquid/blood/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) + var/weakref/donor = LAZYACCESS(data, DATA_BLOOD_DONOR) + blood_splatter(touching_turf, donor?.resolve() || REAGENT_GET_ATOM(holder), 1) - if(M.chem_doses[type] > 5) - M.adjustToxLoss(removed) - if(M.chem_doses[type] > 15) - M.adjustToxLoss(removed) +/decl/material/liquid/blood/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(M.has_trait(/decl/trait/metabolically_inert)) + return + if(CHEM_DOSE(M, src) > 5) + M.take_damage(removed, TOX) + if(CHEM_DOSE(M, src) > 15) + M.take_damage(removed, TOX) -/decl/material/liquid/blood/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/blood/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.isSynthetic()) - return + var/affect_volume = REAGENT_VOLUME(holder, src) + var/mob/living/human/H = M + H.inject_blood(affect_volume, holder) + holder.remove_reagent(type, affect_volume) + . = ..() -/decl/material/liquid/blood/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - M.inject_blood(volume, holder) - holder.remove_reagent(type, volume) +/decl/material/liquid/blood/get_reagent_color(datum/reagents/holder) + var/list/blood_data = REAGENT_DATA(holder, src) + return blood_data?[DATA_BLOOD_COLOR] || ..() /decl/material/liquid/coagulated_blood name = "coagulated blood" color = "#aa0000" + uid = "chem_blood_coagulated" taste_description = "chewy iron" taste_mult = 1.5 lore_text = "When exposed to unsuitable conditions, such as the floor or an oven, blood becomes coagulated and useless for transfusions. It's great for making blood pudding, though." @@ -86,3 +87,6 @@ hidden_from_codex = TRUE toxicity = 4 value = 0 + exoplanet_rarity_gas = MAT_RARITY_UNCOMMON + compost_value = 1 // yum + opacity = 1.0 diff --git a/code/modules/reagents/chems/chems_cleaner.dm b/code/modules/reagents/chems/chems_cleaner.dm index c40a29631f17..007ce32ffa67 100644 --- a/code/modules/reagents/chems/chems_cleaner.dm +++ b/code/modules/reagents/chems/chems_cleaner.dm @@ -6,3 +6,36 @@ touch_met = 50 value = 0.15 // shelf price of bug spray per ml, cleaner in general is too cheap dirtiness = DIRTINESS_CLEAN + turf_touch_threshold = 0.1 + uid = "chem_cleaner" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/contaminant_cleaner + name = "akaline detergent" + lore_text = "A highly akaline hydrazine based detergent. Able to clean contaminants, but may release ammonia gas if used in open air." + taste_description = "bleach" + vapor_products = list(/decl/material/gas/ammonia = 0.5) + color = "#213799" + touch_met = 5 + toxicity = 5 + scent = "clean linen" + scent_descriptor = "fragrance" + value = 0.25 + dirtiness = DIRTINESS_DECONTAMINATE + decontamination_dose = 5 + turf_touch_threshold = 0.1 + uid = "chem_contaminant_cleaner" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/cleaner/soap + name = "soap" + lore_text = "A soft solid compound used to clean things. Usually derived from oil or fat." + taste_description = "waxy blandness" + color = COLOR_BEIGE + uid = "chem_soap" + hardness = MAT_VALUE_FLEXIBLE + 10 + melting_point = 323 + ignition_point = 353 + boiling_point = 373 + accelerant_value = 0.3 + opacity = 1.0 // liquid is opaque by default, but soap is solid (or maybe it should be like, mostly opaque? tbd) diff --git a/code/modules/reagents/chems/chems_compounds.dm b/code/modules/reagents/chems/chems_compounds.dm index e9b3f4dd9b16..f080406738f4 100644 --- a/code/modules/reagents/chems/chems_compounds.dm +++ b/code/modules/reagents/chems/chems_compounds.dm @@ -1,8 +1,11 @@ /decl/material/liquid/luminol name = "luminol" + uid = "chem_luminol" lore_text = "A compound that interacts with blood on the molecular level." taste_description = "metal" color = "#f2f3f4" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE /decl/material/liquid/luminol/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) O.reveal_blood() @@ -15,27 +18,29 @@ lore_text = "A popular party drug for adventurous types who want to BE the glowstick. Rumoured to be hallucinogenic in high doses." overdose = 15 color = "#9eefff" + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // No sap air. + uid = "chem_glowsap" + affect_blood_on_ingest = 1 -/decl/material/liquid/glowsap/affect_ingest(mob/living/carbon/M, alien, removed, var/datum/reagents/holder) - affect_blood(M, alien, removed, holder) - -/decl/material/liquid/glowsap/affect_blood(mob/living/carbon/M, alien, removed, var/datum/reagents/holder) +/decl/material/liquid/glowsap/affect_blood(mob/living/M, removed, var/datum/reagents/holder) + . = ..() M.add_chemical_effect(CE_GLOWINGEYES, 1) if(ishuman(M)) - var/mob/living/carbon/human/H = M + var/mob/living/human/H = M H.update_eyes() -/decl/material/liquid/glowsap/on_leaving_metabolism(mob/parent, metabolism_class) - if(ishuman(parent)) - var/mob/living/carbon/human/H = parent - addtimer(CALLBACK(H, /mob/living/carbon/human/proc/update_eyes), 5 SECONDS) +/decl/material/liquid/glowsap/on_leaving_metabolism(datum/reagents/metabolism/holder) + var/my_atom = REAGENT_GET_ATOM(holder) + if(ishuman(my_atom)) + var/mob/living/human/H = my_atom + addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living/human, update_eyes)), 5 SECONDS) . = ..() -/decl/material/liquid/glowsap/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) +/decl/material/liquid/glowsap/affect_overdose(mob/living/victim, total_dose) . = ..() - M.add_chemical_effect(CE_TOXIN, 1) - M.hallucination(60, 20) - M.adjust_drugged(2) + victim.add_chemical_effect(CE_TOXIN, 1) + victim.set_hallucination(60, 20) + SET_STATUS_MAX(victim, STAT_DRUGGY, 10) /decl/material/solid/blackpepper name = "black pepper" @@ -43,14 +48,31 @@ taste_description = "pepper" color = "#000000" value = 0.1 + uid = "chem_blackpepper" + +/decl/material/solid/cinnamon + name = "cinnamon" + lore_text = "A powder used to flavor food and drinks. Unpleasant to eat a full spoonful of." + taste_description = "cinnamon" + color = "#a34b0d" + value = 0.2 + uid = "chem_cinnamon" /decl/material/liquid/enzyme name = "universal enzyme" + uid = "chem_enzyme" lore_text = "A universal enzyme used in the preperation of certain chemicals and foods." taste_description = "sweetness" taste_mult = 0.7 color = "#365e30" overdose = REAGENTS_OVERDOSE + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/enzyme/rennet + name = "rennet" + uid = "chem_rennet" + lore_text = "A complex mix of enzymes extracted from a ruminant's stomach. Important to cheesemaking, and as a chemical precursor." + taste_description = "sweet bile" /decl/material/liquid/frostoil name = "chilly oil" @@ -60,15 +82,39 @@ color = "#07aab2" value = 2 fruit_descriptor = "numbing" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_frostoil" -/decl/material/liquid/frostoil/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/frostoil/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0) if(prob(1)) - M.emote("shiver") - if(istype(M, /mob/living/carbon/slime)) - M.bodytemperature = max(M.bodytemperature - rand(10,20), 0) + M.emote(/decl/emote/visible/shiver) holder.remove_reagent(/decl/material/liquid/capsaicin, 5) +/decl/material/liquid/nettle_histamine + name = "nettle histamine" + lore_text = "A combination of substances injected by contact with the stinging hairs of the common nettle. Itchy and painful, but not dangerous." + heating_products = null + uid = "chem_nettle_histamine" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + color = "#9bbe90" + heating_point = 60 CELSIUS + heating_message = "thins as it separates." + heating_products = list( + /decl/material/liquid/drink/juice/nettle = 0.5, + /decl/material/liquid/water = 0.5 + ) + +// This should really be contact only but fruit injects it (do_sting()). +/decl/material/liquid/nettle_histamine/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(M.has_trait(/decl/trait/metabolically_inert) || !M.can_feel_pain()) + return + M.apply_effect(6, PAIN, 0) + if(prob(5)) + to_chat(M, SPAN_DANGER("Your skin [pick("itches", "burns", "stings")]!")) + /decl/material/liquid/capsaicin name = "capsaicin oil" lore_text = "This is what makes chilis hot." @@ -76,38 +122,34 @@ taste_mult = 1.5 color = "#b31008" fruit_descriptor = "spicy" - - heating_point = T100C - heating_message = "darkens and thickens as it seperates from its water content" - heating_products = list( - /decl/material/liquid/capsaicin/condensed = 0.5, - /decl/material/liquid/water = 0.5 - ) + uid = "chem_capsaicin" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC var/agony_dose = 5 var/agony_amount = 2 var/discomfort_message = "Your insides feel uncomfortably hot!" var/slime_temp_adj = 10 -/decl/material/liquid/capsaicin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.adjustToxLoss(0.5 * removed) +/decl/material/liquid/capsaicin/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + M.take_damage(0.5 * removed, TOX) -/decl/material/liquid/capsaicin/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.can_feel_pain()) - return - if(M.chem_doses[type] < agony_dose) - if(prob(5) || M.chem_doses[type] == metabolism) //dose == metabolism is a very hacky way of forcing the message the first time this procs +/decl/material/liquid/capsaicin/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + holder.remove_reagent(/decl/material/liquid/frostoil, 5) + + if(M.has_trait(/decl/trait/metabolically_inert) || !M.can_feel_pain()) + return + + var/dose = CHEM_DOSE(M, src) + if(dose < agony_dose) + if(prob(5) || dose == metabolism) //dose == metabolism is a very hacky way of forcing the message the first time this procs to_chat(M, discomfort_message) else M.apply_effect(agony_amount, PAIN, 0) if(prob(5)) M.custom_emote(2, "[pick("dry heaves!","coughs!","splutters!")]") to_chat(M, "You feel like your insides are burning!") - if(istype(M, /mob/living/carbon/slime)) - M.bodytemperature += rand(0, 15) + slime_temp_adj - holder.remove_reagent(/decl/material/liquid/frostoil, 5) /decl/material/liquid/capsaicin/condensed name = "condensed capsaicin" @@ -121,52 +163,49 @@ discomfort_message = "You feel like your insides are burning!" slime_temp_adj = 15 value = 2 + uid = "chem_capsaicin_condensed" + heating_message = null + heating_products = null + heating_point = null + exoplanet_rarity_gas = MAT_RARITY_NOWHERE -/decl/material/liquid/capsaicin/condensed/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/capsaicin/condensed/affect_touch(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() var/eyes_covered = 0 var/mouth_covered = 0 var/partial_mouth_covered = 0 var/stun_probability = 50 - var/no_pain = 0 + var/no_pain = !M.can_feel_pain() var/obj/item/eye_protection = null var/obj/item/face_protection = null var/obj/item/partial_face_protection = null - var/effective_strength = 5 - var/list/protection - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - protection = list(H.head, H.glasses, H.wear_mask) - if(!H.can_feel_pain()) - no_pain = 1 //TODO: living-level can_feel_pain() proc - else - protection = list(M.wear_mask) - - for(var/obj/item/I in protection) - if(I) - if(I.body_parts_covered & EYES) + for(var/slot in global.standard_headgear_slots) + var/obj/item/thing = M.get_equipped_item(slot) + if(istype(thing)) + if(thing.body_parts_covered & SLOT_EYES) eyes_covered = 1 - eye_protection = I.name - if((I.body_parts_covered & FACE) && !(I.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) + eye_protection = thing.name + if((thing.body_parts_covered & SLOT_FACE) && !(thing.item_flags & ITEM_FLAG_FLEXIBLEMATERIAL)) mouth_covered = 1 - face_protection = I.name - else if(I.body_parts_covered & FACE) + face_protection = thing.name + else if(thing.body_parts_covered & SLOT_FACE) partial_mouth_covered = 1 - partial_face_protection = I.name + partial_face_protection = thing.name if(eyes_covered) if(!mouth_covered) to_chat(M, "Your [eye_protection] protects your eyes from the pepperspray!") else to_chat(M, "The pepperspray gets in your eyes!") - M.confused += 2 + ADJ_STATUS(M, STAT_CONFUSE, 2) if(mouth_covered) - M.eye_blurry = max(M.eye_blurry, effective_strength * 3) - M.eye_blind = max(M.eye_blind, effective_strength) + SET_STATUS_MAX(M, STAT_BLURRY, effective_strength * 3) + SET_STATUS_MAX(M, STAT_BLIND, effective_strength) else - M.eye_blurry = max(M.eye_blurry, effective_strength * 5) - M.eye_blind = max(M.eye_blind, effective_strength * 2) + SET_STATUS_MAX(M, STAT_BLURRY, effective_strength * 5) + SET_STATUS_MAX(M, STAT_BLIND, effective_strength * 2) if(mouth_covered) to_chat(M, "Your [face_protection] protects you from the pepperspray!") @@ -175,28 +214,27 @@ to_chat(M, "Your [partial_face_protection] partially protects you from the pepperspray!") stun_probability *= 0.5 to_chat(M, "Your face and throat burn!") - if(M.stunned > 0 && !M.lying) - M.Weaken(4) + if(HAS_STATUS(M, STAT_STUN) && !M.current_posture.prone) + SET_STATUS_MAX(M, STAT_WEAK, 4) if(prob(stun_probability)) M.custom_emote(2, "[pick("coughs!","coughs hysterically!","splutters!")]") - M.Stun(3) + SET_STATUS_MAX(M, STAT_STUN, 3) -/decl/material/liquid/capsaicin/condensed/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.can_feel_pain()) - return - if(M.chem_doses[type] == metabolism) + return TRUE + +/decl/material/liquid/capsaicin/condensed/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + holder.remove_reagent(/decl/material/liquid/frostoil, 5) + if(M.has_trait(/decl/trait/metabolically_inert) || !M.can_feel_pain()) + return + if(CHEM_DOSE(M, src) == metabolism) to_chat(M, "You feel like your insides are burning!") else M.apply_effect(6, PAIN, 0) if(prob(5)) to_chat(M, "You feel like your insides are burning!") M.custom_emote(2, "[pick("coughs.","gags.","retches.")]") - M.Stun(2) - if(istype(M, /mob/living/carbon/slime)) - M.bodytemperature += rand(15, 30) - holder.remove_reagent(/decl/material/liquid/frostoil, 5) + SET_STATUS_MAX(M, STAT_STUN, 2) /decl/material/liquid/mutagenics name = "mutagenics" @@ -204,34 +242,28 @@ taste_description = "slime" taste_mult = 0.9 color = "#13bc5e" + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_mutagenics" + affect_blood_on_ingest = FALSE -/decl/material/liquid/mutagenics/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/mutagenics/affect_touch(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() if(prob(33)) - affect_blood(M, alien, removed, holder) + affect_blood(M, removed, holder) + return TRUE -/decl/material/liquid/mutagenics/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/mutagenics/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() if(prob(67)) - affect_blood(M, alien, removed, holder) + affect_blood(M, removed, holder) -/decl/material/liquid/mutagenics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - - if(M.isSynthetic()) - return - - var/mob/living/carbon/human/H = M - if(istype(H) && (H.species.species_flags & SPECIES_FLAG_NO_SCAN)) +/decl/material/liquid/mutagenics/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(!M.has_genetic_information()) return - - if(M.dna) - if(prob(removed * 0.1)) // Approx. one mutation per 10 injected/20 ingested/30 touching units - randmuti(M) - if(prob(98)) - randmutb(M) - else - randmutg(M) - domutcheck(M, null) - M.UpdateAppearance() - M.apply_damage(10 * removed, IRRADIATE, armor_pen = 100) + if(prob(removed * 0.1)) // Approx. one mutation per 10 injected/20 ingested/30 touching units + M.apply_random_mutation(10 * removed) /decl/material/liquid/lactate name = "lactate" @@ -240,17 +272,21 @@ color = "#eeddcc" scannable = 1 overdose = REAGENTS_OVERDOSE - metabolism = REM + metabolism = REM*2 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_lactate" -/decl/material/liquid/lactate/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) +/decl/material/liquid/lactate/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/affect_volume = REAGENT_VOLUME(holder, src) M.add_chemical_effect(CE_PULSE, 1) - M.add_chemical_effect(CE_BREATHLOSS, 0.02 * volume) - if(volume >= 5) + if(affect_volume >= 10) M.add_chemical_effect(CE_PULSE, 1) - M.add_chemical_effect(CE_SLOWDOWN, (volume/5) ** 2) - else if(M.chem_doses[type] > 20) //after prolonged exertion - M.make_jittery(10) + M.add_chemical_effect(CE_SLOWDOWN, (affect_volume/15) ** 2) + else if(CHEM_DOSE(M, src) > 30) //after prolonged exertion + ADJ_STATUS(M, STAT_JITTER, 5) + M.add_chemical_effect(CE_BREATHLOSS, 0.02 * affect_volume) /decl/material/liquid/nanoblood name = "nanoblood" @@ -260,14 +296,21 @@ scannable = 1 overdose = 5 metabolism = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nanoblood" -/decl/material/liquid/nanoblood/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed, var/datum/reagents/holder) - if(!M.should_have_organ(BP_HEART)) //We want the var for safety but we can do without the actual blood. +/decl/material/liquid/nanoblood/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/mob/living/human/H = M + if(!istype(H)) + return + if(!H.should_have_organ(BP_HEART)) //We want the var for safety but we can do without the actual blood. return - if(M.regenerate_blood(4 * removed)) - M.immunity = max(M.immunity - 0.1, 0) - if(M.chem_doses[type] > M.species.blood_volume/8) //half of blood was replaced with us, rip white bodies - M.immunity = max(M.immunity - 0.5, 0) + if(H.regenerate_blood(4 * removed)) + H.adjust_immunity(-0.1) + if(CHEM_DOSE(H, src) > H.species.blood_volume/8) //half of blood was replaced with us, rip white bodies + H.adjust_immunity(-0.5) /decl/material/solid/tobacco name = "tobacco" @@ -276,22 +319,24 @@ color = "#684b3c" scannable = 1 scent = "cigarette smoke" - scent_descriptor = SCENT_DESC_ODOR + scent_descriptor = "odour" scent_range = 4 hidden_from_codex = TRUE + uid = "chem_tobacco" var/nicotine = REM * 0.2 -/decl/material/solid/tobacco/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/solid/tobacco/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.reagents.add_reagent(/decl/material/liquid/nicotine, nicotine) + M.add_to_reagents(/decl/material/liquid/nicotine, nicotine) /decl/material/solid/tobacco/fine name = "fine tobacco" taste_description = "fine tobacco" value = 1.5 scent = "fine tobacco smoke" - scent_descriptor = SCENT_DESC_FRAGRANCE + scent_descriptor = "fragrance" + uid = "chem_tobacco_fine" /decl/material/solid/tobacco/bad name = "terrible tobacco" @@ -299,7 +344,8 @@ value = 0.5 scent = "acrid tobacco smoke" scent_intensity = /decl/scent_intensity/strong - scent_descriptor = SCENT_DESC_ODOR + scent_descriptor = "odour" + uid = "chem_tobacco_terrible" /decl/material/solid/tobacco/liquid name = "nicotine solution" @@ -311,6 +357,9 @@ scent_intensity = null scent_descriptor = null scent_range = null + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nicotinesolution" /decl/material/liquid/menthol name = "menthol" @@ -321,29 +370,38 @@ overdose = REAGENTS_OVERDOSE * 0.25 scannable = 1 hidden_from_codex = TRUE + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_tobacco_menthol" -/decl/material/liquid/menthol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(world.time > REAGENT_DATA(holder, type) + 3 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) +/decl/material/liquid/menthol/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/list/data = REAGENT_DATA(holder, src) + if(world.time > LAZYACCESS(data, DATA_COOLDOWN_TIME) + 3 MINUTES) + LAZYSET(data, DATA_COOLDOWN_TIME, world.time) + REAGENT_SET_DATA(holder, type, data) to_chat(M, SPAN_NOTICE("You feel faintly sore in the throat.")) /decl/material/liquid/nanitefluid - name = "Nanite Fluid" + name = "nanite fluid" lore_text = "A solution of repair nanites used to repair robotic organs. Due to the nature of the small magnetic fields used to guide the nanites, it must be used in temperatures below 170K." taste_description = "metallic sludge" color = "#c2c2d6" scannable = 1 flags = IGNORE_MOB_SIZE + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_nanite_fluid" -/decl/material/liquid/nanitefluid/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/nanitefluid/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() M.add_chemical_effect(CE_CRYO, 1) if(M.bodytemperature < 170) M.heal_organ_damage(30 * removed, 30 * removed, affect_robo = 1) if(ishuman(M)) - var/mob/living/carbon/human/H = M - for(var/obj/item/organ/internal/I in H.internal_organs) - if(BP_IS_PROSTHETIC(I)) - I.heal_damage(20*removed) + var/mob/living/human/H = M + for(var/obj/item/organ/internal/organ in H.get_internal_organs()) + if(BP_IS_PROSTHETIC(organ)) + organ.heal_damage(20*removed) /decl/material/liquid/antiseptic name = "antiseptic" @@ -352,21 +410,29 @@ color = "#c8a5dc" touch_met = 5 dirtiness = DIRTINESS_STERILE + turf_touch_threshold = 0.1 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_antiseptic" /decl/material/liquid/crystal_agent name = "crystallizing agent" taste_description = "sharpness" color = "#13bc5e" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_crystalizing_agent" -/decl/material/liquid/crystal_agent/proc/do_material_check(var/mob/living/carbon/M) +/decl/material/liquid/crystal_agent/proc/do_material_check(var/mob/living/M) . = /decl/material/solid/gemstone/crystal -/decl/material/liquid/crystal_agent/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/crystal_agent/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() var/result_mat = do_material_check(M) if(ishuman(M)) - var/mob/living/carbon/human/H = M - for(var/obj/item/organ/external/E in shuffle(H.organs.Copy())) - if(E.is_stump() || BP_IS_PROSTHETIC(E)) + var/mob/living/human/H = M + var/list/limbs = H.get_external_organs() + var/list/shuffled_limbs = LAZYLEN(limbs) ? shuffle(limbs.Copy()) : null + for(var/obj/item/organ/external/E in shuffled_limbs) + if(BP_IS_PROSTHETIC(E)) continue if(BP_IS_CRYSTAL(E)) @@ -381,26 +447,28 @@ else if(E.organ_tag != BP_CHEST && E.organ_tag != BP_GROIN && prob(15)) to_chat(H, SPAN_DANGER("Your [E.name] is being lacerated from within!")) if(E.can_feel_pain()) - H.emote("scream") + H.emote(/decl/emote/audible/scream) if(prob(25)) for(var/i = 1 to rand(3,5)) new /obj/item/shard(get_turf(E), result_mat) - E.droplimb(0, DROPLIMB_BLUNT) + E.dismember(0, DISMEMBER_METHOD_BLUNT) else - E.take_external_damage(rand(20,30), 0) - E.status |= ORGAN_CRYSTAL + E.take_damage(rand(20,30)) + BP_SET_CRYSTAL(E) E.status |= ORGAN_BRITTLE break - for(var/obj/item/organ/internal/I in shuffle(H.internal_organs.Copy())) - if(BP_IS_PROSTHETIC(I) || !BP_IS_CRYSTAL(I) || I.damage <= 0 || I.organ_tag == BP_BRAIN) + var/list/internal_organs = H.get_internal_organs() + var/list/shuffled_organs = LAZYLEN(internal_organs) ? shuffle(internal_organs.Copy()) : null + for(var/obj/item/organ/internal/organ in shuffled_organs) + if(BP_IS_PROSTHETIC(organ) || !BP_IS_CRYSTAL(organ) || organ.get_organ_damage() <= 0 || organ.organ_tag == BP_BRAIN) continue if(prob(35)) - to_chat(M, SPAN_NOTICE("You feel a deep, sharp tugging sensation as your [I.name] is mended.")) - I.heal_damage(rand(1,3)) + to_chat(M, SPAN_NOTICE("You feel a deep, sharp tugging sensation as your [organ.name] is mended.")) + organ.heal_damage(rand(1,3)) break - else + else to_chat(M, SPAN_DANGER("Your flesh is being lacerated from within!")) - M.adjustBruteLoss(rand(3,6)) + M.take_damage(rand(3,6)) if(prob(10)) new /obj/item/shard(get_turf(M), result_mat) diff --git a/code/modules/reagents/chems/chems_drinks.dm b/code/modules/reagents/chems/chems_drinks.dm index d07137143779..7afcd04de1df 100644 --- a/code/modules/reagents/chems/chems_drinks.dm +++ b/code/modules/reagents/chems/chems_drinks.dm @@ -2,54 +2,78 @@ name = "drink" lore_text = "Uh, some kind of drink." color = "#e78108" - hidden_from_codex = TRUE // They don't need to generate a codex entry, their recipes will do that. - value = 1.2 + value = 0.4 + abstract_type = /decl/material/liquid/drink + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // Please, no more berry juice atmosphere planets. + compost_value = 1 + nutriment_factor = 0 + hydration_factor = 6 + affect_blood_on_ingest = FALSE + affect_blood_on_inhale = FALSE - var/nutrition = 0 // Per unit - var/hydration = 6 // Per unit var/adj_dizzy = 0 // Per tick var/adj_drowsy = 0 var/adj_sleepy = 0 var/adj_temp = 0 -/decl/material/liquid/drink/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.adjustToxLoss(removed) // Probably not a good idea; not very deadly though - -/decl/material/liquid/drink/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(nutrition) - M.adjust_nutrition(nutrition * removed) - if(hydration) - M.adjust_hydration(hydration * removed) - M.dizziness = max(0, M.dizziness + adj_dizzy) - M.drowsyness = max(0, M.drowsyness + adj_drowsy) - M.sleeping = max(0, M.sleeping + adj_sleepy) +/decl/material/liquid/drink/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(!injectable_nutrition) + M.take_damage(removed, TOX) // Probably not a good idea; not very deadly though + +/decl/material/liquid/drink/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + ADJ_STATUS(M, STAT_DIZZY, adj_dizzy) + ADJ_STATUS(M, STAT_DROWSY, adj_drowsy) + ADJ_STATUS(M, STAT_ASLEEP, adj_sleepy) + if(adj_temp > 0 && M.bodytemperature < 310) // 310 is the normal bodytemp. 310.055 M.bodytemperature = min(310, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) if(adj_temp < 0 && M.bodytemperature > 310) M.bodytemperature = min(310, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) // Juices -/decl/material/chem/drink/juice +/decl/material/liquid/drink/juice + uid = "chem_drink_juice" fruit_descriptor = "sweet" + allergen_flags = ALLERGEN_FRUIT -/decl/material/liquid/drink/juice/affect_ingest(var/mob/living/carbon/human/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/juice/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.immunity = min(M.immunity + 0.25, M.immunity_norm*1.5) + if(!M.has_trait(/decl/trait/metabolically_inert)) + M.immunity = min(M.immunity + 0.25, M.immunity_norm*1.5) + +/decl/material/liquid/drink/juice/nettle + name = "nettle juice" + lore_text = "A liquid extracted from nettles. Reputedly useful for treating allergies and sneezing." + taste_description = "stinging" + color = "#7a9b79" + uid = "chem_drink_nettle" + + glass_name = "nettle juice" + glass_desc = "A tall glass of pureed stinging nettles." /decl/material/liquid/drink/juice/banana name = "banana juice" lore_text = "The raw essence of a banana." taste_description = "banana" color = "#c3af00" + uid = "chem_drink_banana" glass_name = "banana juice" glass_desc = "The raw essence of a banana. HONK!" /decl/material/liquid/drink/juice/berry name = "berry juice" + codex_name = "blended berry juice" lore_text = "A delicious blend of several different kinds of berries." taste_description = "berries" color = "#990066" + uid = "chem_drink_berry" glass_name = "berry juice" glass_desc = "Berry juice. Or maybe it's jam. Who cares?" @@ -59,19 +83,22 @@ lore_text = "It is just like a carrot but without crunching." taste_description = "carrots" color = "#ff8c00" // rgb: 255, 140, 0 + uid = "chem_drink_carrot" glass_name = "carrot juice" glass_desc = "It is just like a carrot but without crunching." + allergen_flags = ALLERGEN_VEGETABLE -/decl/material/liquid/drink/juice/carrot/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/juice/carrot/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.reagents.add_reagent(/decl/material/liquid/eyedrops, removed * 0.2) + M.add_to_reagents(/decl/material/liquid/eyedrops, removed * 0.2) /decl/material/liquid/drink/juice/grape name = "grape juice" lore_text = "It's grrrrrape!" taste_description = "grapes" color = "#863333" + uid = "chem_drink_grape" glass_name = "grape juice" glass_desc = "It's grrrrrape!" @@ -83,6 +110,7 @@ taste_mult = 1.1 color = "#afaf00" fruit_descriptor = "sweet-sour" + uid = "chem_drink_lemon" glass_name = "lemon juice" glass_desc = "Sour..." @@ -94,13 +122,18 @@ taste_mult = 1.1 color = "#365e30" fruit_descriptor = "sweet-sour" + uid = "chem_drink_lime" glass_name = "lime juice" glass_desc = "A glass of sweet-sour lime juice" -/decl/material/liquid/drink/juice/lime/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/juice/lime/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.adjustToxLoss(-0.5 * removed) + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + M.heal_damage(TOX, 0.5 * removed) /decl/material/liquid/drink/juice/orange name = "orange juice" @@ -108,65 +141,88 @@ taste_description = "oranges" color = "#e78108" fruit_descriptor = "sweet-sour" + uid = "chem_drink_orange" glass_name = "orange juice" glass_desc = "Vitamins! Yay!" -/decl/material/liquid/drink/juice/orange/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/juice/orange/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.adjustOxyLoss(-2 * removed) -/decl/material/liquid/poisonberryjuice // It has more in common with toxins than drinks... but it's a juice + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + M.heal_damage(OXY, 2 * removed) + +/decl/material/liquid/poisonberryjuice name = "poison berry juice" lore_text = "A tasty juice blended from various kinds of very deadly and toxic berries." taste_description = "berries" color = "#863353" toxicity = 5 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // No more juice air. + uid = "chem_drink_berry_poison" glass_name = "poison berry juice" glass_desc = "A glass of deadly juice." /decl/material/liquid/drink/juice/potato name = "potato juice" - lore_text = "Juice of the potato. Bleh." - taste_description = "sadness and potatoes" - nutrition = 2 + lore_text = "Juice of the potato." + taste_description = "starch" + nutriment_factor = 2 color = "#302000" + uid = "chem_drink_potato" glass_name = "potato juice" - glass_desc = "Juice from a potato. Bleh." + glass_desc = "Juice from a potato. Possibly the most boring drink in existence, other than water." + allergen_flags = ALLERGEN_VEGETABLE /decl/material/liquid/drink/juice/garlic - name = "garlic juice" - lore_text = "Who would even drink this?" + name = "garlic oil" + lore_text = "A strong-smelling, pungent oil pressed from garlic cloves. It has some antibiotic properties, and can help with infections." taste_description = "bad breath" - nutrition = 1 + nutriment_factor = 0.5 // Injectable Nutrition flag causes it to be digested twice + hydration_factor = 3 // Cut in half from 6 so double digestion gives normal amount color = "#eeddcc" + uid = "chem_drink_garlic" + antibiotic_strength = 0.65 + affect_blood_on_ingest = TRUE + injectable_nutrition = TRUE - glass_name = "garlic juice" - glass_desc = "Who would even drink juice from garlic?" + glass_name = "garlic oil" + glass_desc = "A potion of guaranteed bad breath." + allergen_flags = ALLERGEN_ALLIUM /decl/material/liquid/drink/juice/onion name = "onion juice" lore_text = "Juice from an onion, for when you need to cry." taste_description = "stinging tears" - nutrition = 1 + nutriment_factor = 1 color = "#ffeedd" + uid = "chem_drink_onion" glass_name = "onion juice" glass_desc = "Juice from an onion, for when you need to cry." + allergen_flags = ALLERGEN_ALLIUM /decl/material/liquid/drink/juice/tomato name = "tomato juice" lore_text = "Tomatoes made into juice. What a waste of big, juicy tomatoes, huh?" taste_description = "tomatoes" color = "#731008" + uid = "chem_drink_tomato" glass_name = "tomato juice" glass_desc = "Are you sure this is tomato juice?" + allergen_flags = ALLERGEN_FRUIT | ALLERGEN_VEGETABLE -/decl/material/liquid/drink/juice/tomato/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/juice/tomato/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + M.heal_organ_damage(0, 0.5 * removed) /decl/material/liquid/drink/juice/watermelon @@ -174,82 +230,109 @@ lore_text = "Delicious juice made from watermelon." taste_description = "sweet watermelon" color = "#b83333" + uid = "chem_drink_watermelon" glass_name = "watermelon juice" glass_desc = "Delicious juice made from watermelon." + allergen_flags = ALLERGEN_FRUIT /decl/material/liquid/drink/juice/turnip name = "turnip juice" lore_text = "Delicious (?) juice made from turnips." taste_description = "turnip and uncertainty" color = "#b1166e" + uid = "chem_drink_turnip" glass_name = "turnip juice" glass_desc = "Delicious (?) juice made from turnips." + allergen_flags = ALLERGEN_VEGETABLE /decl/material/liquid/drink/juice/apple name = "apple juice" lore_text = "Delicious sweet juice made from apples." taste_description = "sweet apples" color = "#c07c40" + uid = "chem_drink_apple" glass_name = "apple juice" glass_desc = "Delicious juice made from apples." + allergen_flags = ALLERGEN_FRUIT /decl/material/liquid/drink/juice/pear name = "pear juice" lore_text = "Delicious sweet juice made from pears." taste_description = "sweet pears" color = "#ffff66" + uid = "chem_drink_pear" glass_name = "pear juice" glass_desc = "Delicious juice made from pears." + allergen_flags = ALLERGEN_FRUIT // Everything else /decl/material/liquid/drink/milk name = "milk" - lore_text = "An opaque white liquid produced by tiplods." + codex_name = "whole milk" + lore_text = "An opaque white liquid produced by mammals." taste_description = "milk" color = "#dfdfdf" + uid = "chem_drink_milk" glass_name = "milk" glass_desc = "White and nutritious goodness!" + allergen_flags = ALLERGEN_DAIRY /decl/material/liquid/drink/milk/chocolate name = "chocolate milk" + codex_name = null lore_text = "A mixture of perfectly healthy milk and delicious chocolate." taste_description = "chocolate milk" color = "#74533b" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_milk_chocolate" glass_name = "chocolate milk" glass_desc = "Deliciously fattening!" -/decl/material/liquid/drink/milk/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/milk/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.heal_organ_damage(0.5 * removed, 0) + holder.remove_reagent(/decl/material/liquid/capsaicin, 10 * removed) + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + M.heal_organ_damage(0.5 * removed, 0) + /decl/material/liquid/drink/milk/cream name = "cream" - lore_text = "The fatty, still liquid part of milk." + codex_name = "milk cream" + lore_text = "The fatty, still-liquid part of milk." taste_description = "creamy milk" color = "#dfd7af" + uid = "chem_drink_cream" + skimmable = TRUE glass_name = "cream" glass_desc = "Ewwww..." /decl/material/liquid/drink/milk/soymilk name = "soy milk" + codex_name = null lore_text = "An opaque white liquid made from soybeans." taste_description = "soy milk" color = "#dfdfc7" + uid = "chem_drink_soymilk" + allergen_flags = ALLERGEN_SOY glass_name = "soy milk" glass_desc = "White and nutritious soy goodness!" /decl/material/liquid/drink/coffee name = "coffee" + codex_name = "brewed coffee" lore_text = "Coffee is a brewed drink prepared from roasted seeds, commonly called coffee beans, of the coffee plant." taste_description = "bitterness" taste_mult = 1.3 @@ -261,6 +344,10 @@ overdose = 60 glass_name = "coffee" glass_desc = "Don't drop it, or you'll send scalding liquid and glass shards everywhere." + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_coffee" + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT var/list/flavour_modifiers = list() /decl/material/liquid/drink/coffee/Initialize() @@ -278,23 +365,27 @@ if(!inserted) flavour_modifiers += syrup -/decl/material/liquid/drink/coffee/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/coffee/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() if(adj_temp > 0) holder.remove_reagent(/decl/material/liquid/frostoil, 10 * removed) - var/volume = REAGENT_VOLUME(holder, type) - if(volume > 15) + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + var/affect_volume = REAGENT_VOLUME(holder, src) + if(affect_volume > 15) M.add_chemical_effect(CE_PULSE, 1) - if(volume > 45) + if(affect_volume > 45) M.add_chemical_effect(CE_PULSE, 1) -/decl/material/liquid/drink/coffee/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/coffee/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() M.add_chemical_effect(CE_PULSE, 2) -/decl/material/liquid/drink/coffee/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) - M.make_jittery(5) - M.add_chemical_effect(CE_PULSE, 1) +/decl/material/liquid/drink/coffee/affect_overdose(mob/living/victim, total_dose) + ADJ_STATUS(victim, STAT_JITTER, 5) + victim.add_chemical_effect(CE_PULSE, 1) /decl/material/liquid/drink/coffee/build_presentation_name_from_reagents(var/obj/item/prop, var/supplied) @@ -324,8 +415,11 @@ lore_text = "Made with love! And cocoa beans." taste_description = "creamy chocolate" color = "#403010" - nutrition = 2 + nutriment_factor = 2 adj_temp = 5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_hot_chocolate" glass_name = "hot chocolate" glass_desc = "Made with love! And cocoa beans." @@ -338,6 +432,9 @@ adj_dizzy = -5 adj_drowsy = -3 adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_sodawater" glass_name = "soda water" glass_desc = "A glass of fizzy soda water." @@ -349,6 +446,9 @@ taste_description = "grape soda" color = "#421c52" adj_drowsy = -3 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_grapesoda" glass_name = "grape soda" glass_desc = "Looks like a delicious drink!" @@ -363,6 +463,9 @@ adj_drowsy = -3 adj_sleepy = -2 adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_tonicwater" glass_name = "tonic water" glass_desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." @@ -373,6 +476,9 @@ taste_description = "tartness" color = "#ffff00" adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_lemonade" glass_name = "lemonade" glass_desc = "Oh the nostalgia..." @@ -384,6 +490,9 @@ taste_description = "tart and tasty" color = "#cccc99" adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_citrus_seltzer" glass_name = "citrus seltzer" glass_desc = "A tasty blend of fizz and citrus." @@ -395,6 +504,9 @@ taste_description = "orange and cola" color = "#9f3400" adj_temp = -2 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_orangecola" glass_name = "orange cola" glass_desc = "It's an unpleasant shade of muddy brown, and smells like over-ripe citrus." @@ -405,9 +517,13 @@ taste_description = "creamy vanilla" color = "#aee5e4" adj_temp = -9 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_milkshake" glass_name = "milkshake" glass_desc = "Glorious brainfreezing mixture." + allergen_flags = ALLERGEN_DAIRY /decl/material/liquid/drink/mutagencola name = "mutagen cola" @@ -416,39 +532,62 @@ color = "#100800" adj_temp = -5 adj_sleepy = -2 + euphoriant = 30 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_mutagencola" glass_name = "mutagen cola" glass_desc = "The unstable energy of a radioactive isotope in beverage form." glass_special = list(DRINK_FIZZ) + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT -/decl/material/liquid/drink/mutagencola/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/mutagencola/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + M.add_chemical_effect(CE_SPEEDBOOST, 1) - M.make_jittery(20) - M.adjust_drugged(30, 30) - M.dizziness += 5 - M.drowsyness = 0 + SET_STATUS_MAX(M, STAT_JITTER, 20) + SET_STATUS_MAX(M, STAT_DIZZY, 20) + ADJ_STATUS(M, STAT_DIZZY, 2) + ADJ_STATUS(M, STAT_JITTER, 2) + M.set_status_condition(STAT_DROWSY, 0) /decl/material/liquid/drink/grenadine name = "grenadine syrup" lore_text = "Made in the modern day with proper pomegranate substitute. Who uses real fruit, anyways?" taste_description = "100% pure pomegranate" color = "#ff004f" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_grenadine" glass_name = "grenadine syrup" glass_desc = "Sweet and tangy, a bar syrup used to add color or flavor to drinks." /decl/material/liquid/drink/cola name = "cola" + codex_name = "classic cola" // urgh need a less bad name for codex overlap checks lore_text = "A refreshing beverage." taste_description = "cola" color = "#100800" adj_drowsy = -3 adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_cola" glass_name = "cola" glass_desc = "A glass of refreshing cola." glass_special = list(DRINK_FIZZ) + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT + +/decl/material/liquid/drink/cola/build_presentation_name_from_reagents(var/obj/item/prop, var/supplied) + if(prop.reagents.has_reagent(/decl/material/liquid/drink/milk)) + supplied = "pilk" + . = ..() /decl/material/liquid/drink/citrussoda name = "citrus soda" @@ -458,6 +597,9 @@ adj_drowsy = -7 adj_sleepy = -1 adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_citrussoda" glass_name = "citrus soda" glass_desc = "A glass of fizzy citrus soda." @@ -470,6 +612,9 @@ color = "#102000" adj_drowsy = -6 adj_temp = -5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_cherrysoda" glass_name = "cherry soda" glass_desc = "A glass of cherry soda, a delicious blend of 42 flavours." @@ -480,6 +625,9 @@ taste_description = "a hull breach" color = "#202800" adj_temp = -8 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_lemonade" glass_name = "lemonade" glass_desc = "A glass of lemonade. It helps keep you cool." @@ -491,6 +639,9 @@ taste_description = "tangy lime and lemon soda" color = "#878f00" adj_temp = -8 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_lemonlimesoda" glass_name = "lemon lime soda" glass_desc = "A tangy substance made of 0.5% natural citrus!" @@ -500,28 +651,48 @@ name = "dry ramen" lore_text = "Space age food, since August 25, 1958. Contains dried noodles, vegetables, and chemicals that boil in contact with water." taste_description = "dry and cheap noodles" - nutrition = 1 + nutriment_factor = 1 color = "#302000" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_dryramen" + allergen_flags = ALLERGEN_GLUTEN | ALLERGEN_VEGETABLE /decl/material/liquid/drink/hot_ramen name = "hot ramen" lore_text = "The noodles are boiled, the flavors are artificial, just like being back in school." taste_description = "wet and cheap noodles" color = "#302000" - nutrition = 5 + nutriment_factor = 5 adj_temp = 5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_hotramen" + allergen_flags = ALLERGEN_GLUTEN | ALLERGEN_VEGETABLE /decl/material/liquid/drink/hell_ramen name = "hell ramen" lore_text = "The noodles are boiled, the flavors are artificial, just like being back in school." taste_description = "wet and cheap noodles on fire" color = "#302000" - nutrition = 5 + nutriment_factor = 5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_hellramen" + allergen_flags = ALLERGEN_GLUTEN | ALLERGEN_VEGETABLE -/decl/material/liquid/drink/hell_ramen/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/hell_ramen/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + M.bodytemperature += 10 * TEMPERATURE_DAMAGE_COEFFICIENT +/decl/material/liquid/drink/tea + abstract_type = /decl/material/liquid/drink/tea + allergen_flags = ALLERGEN_STIMULANT + /decl/material/liquid/drink/tea/build_presentation_name_from_reagents(var/obj/item/prop, var/supplied) . = supplied || glass_name if(prop.reagents.has_reagent(/decl/material/liquid/nutriment/sugar) || prop.reagents.has_reagent(/decl/material/liquid/nutriment/honey)) @@ -530,9 +701,13 @@ . = "mint [.]" . = ..(prop, .) -/decl/material/liquid/drink/tea/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/tea/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.adjustToxLoss(-0.5 * removed) + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + M.heal_damage(TOX, 0.5 * removed) /decl/material/liquid/drink/tea/black name = "black tea" @@ -545,12 +720,16 @@ adj_temp = 20 glass_name = "black tea" glass_desc = "Tasty black tea, it has antioxidants, it's good for you!" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_blacktea" + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT /decl/material/liquid/drink/tea/black/build_presentation_name_from_reagents(var/obj/item/prop, var/supplied) if(prop.reagents.has_reagent(/decl/material/liquid/drink/juice/orange)) - if(prop.reagents.has_reagent(/decl/material/liquid/drink/milk)) + if(prop.reagents.has_reagent(/decl/material/liquid/drink/milk) && prop.reagents.has_reagent(/decl/material/liquid/drink/syrup/vanilla)) //real london fogs need vanilla syrup . = "London Fog" - else if(prop.reagents.has_reagent(/decl/material/liquid/drink/milk/soymilk)) + else if(prop.reagents.has_reagent(/decl/material/liquid/drink/milk/soymilk) && prop.reagents.has_reagent(/decl/material/liquid/drink/syrup/vanilla)) . = "soy London Fog" else . = "Baron Grey" @@ -562,6 +741,9 @@ lore_text = "Subtle green tea, it has antioxidants, it's good for you!" taste_description = "subtle green tea" color = "#b4cd94" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_greentea" glass_name = "green tea" glass_desc = "Subtle green tea, it has antioxidants, it's good for you!" @@ -571,6 +753,9 @@ lore_text = "A spiced, dark tea. Goes great with milk." taste_description = "spiced black tea" color = "#151000" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_chai" glass_name = "chai" glass_desc = "A spiced, dark tea. Goes great with milk." @@ -587,11 +772,15 @@ lore_text = "A caffeine-free dark red tea, flavorful and full of antioxidants." taste_description = "nutty red tea" color = "#ab4c3a" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_redtea" glass_name = "redbush tea" glass_desc = "A caffeine-free dark red tea, flavorful and full of antioxidants." /decl/material/liquid/drink/syrup + abstract_type = /decl/material/liquid/drink/syrup var/coffee_priority var/coffee_modifier @@ -606,6 +795,9 @@ taste_description = "mint" color = "#07aab2" coffee_priority = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_mint" glass_name = "mint flavouring" glass_desc = "Also known as mentha." @@ -617,6 +809,9 @@ color = "#542a0c" coffee_modifier = "mocha" coffee_priority = 5 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_chocolatesyrup" glass_name = "chocolate syrup" glass_desc = "Thick chocolate syrup used to flavor drinks." @@ -627,6 +822,9 @@ taste_description = "caramel" color = "#85461e" coffee_priority = 2 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_caramelsyrup" glass_name = "caramel syrup" glass_desc = "Thick caramel syrup used to flavor drinks." @@ -637,6 +835,9 @@ taste_description = "vanilla" color = "#f3e5ab" coffee_priority = 3 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_vanillasyrup" glass_name = "vanilla syrup" glass_desc = "Thick vanilla syrup used to flavor drinks." @@ -647,10 +848,26 @@ taste_description = "pumpkin spice" color = "#d88b4c" coffee_priority = 4 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_pumpkinsyrup" glass_name = "pumpkin spice syrup" glass_desc = "Thick spiced pumpkin syrup used to flavor drinks." +/decl/material/liquid/drink/syrup/lavender + name = "lavender syrup" + lore_text = "Thick lavender syrup used to flavor drinks." + taste_description = "lavender" + color = "#c38be7" + coffee_priority = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_lavendersyrup" + + glass_name = "lavender syrup" + glass_desc = "Thick lavender syrup used to flavor drinks." + /decl/material/liquid/drink/gingerbeer name = "ginger beer" lore_text = "A hearty, non-alcoholic beverage brewed from ginger." @@ -658,6 +875,9 @@ color = "#44371f" glass_name = "ginger beer" glass_desc = "A hearty, non-alcoholic beverage brewed from ginger." + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_gingerbeer" /decl/material/liquid/drink/beastenergy name = "Beast Energy" @@ -666,11 +886,19 @@ color = "#d69115" glass_name = "beast energy" glass_desc = "Why would you drink this without mixer?" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_energydrink" + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT -/decl/material/liquid/drink/beastenergy/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/drink/beastenergy/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.drowsyness = max(0, M.drowsyness - 7) - M.make_jittery(2) + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + ADJ_STATUS(M, STAT_DROWSY, -7) + ADJ_STATUS(M, STAT_JITTER, 2) M.add_chemical_effect(CE_PULSE, 1) /decl/material/liquid/drink/kefir @@ -680,3 +908,32 @@ color = "#ece4e3" glass_name = "Kefir" glass_desc = "Fermented milk, looks a lot like yougurt." + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_kefir" + allergen_flags = ALLERGEN_DAIRY + +/decl/material/liquid/drink/compote + name = "compote" + lore_text = "Traditional dessert drink made from fruits or berries. Grandma would be proud." + taste_description = "sweet-sour berries" + color = "#9e4b00" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_compote" + + glass_name = "Compote" + glass_desc = "Traditional dessert drink made from fruits or berries. Grandma would be proud." + allergen_flags = ALLERGEN_FRUIT + +/decl/material/liquid/drink/horchata + name = "horchata" + lore_text = "A traditional Mexican drink made from rice, milk, vanilla, and cinnamon." + taste_description = "refreshing vanilla and cinnamon" + color = "#d6c9be" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_drink_horchata" + + glass_name = "Horchata" + glass_desc = "A traditional Mexican drink made from rice, milk, vanilla, and cinnamon." diff --git a/code/modules/reagents/chems/chems_drugs.dm b/code/modules/reagents/chems/chems_drugs.dm index 0831f270d840..05a13fe3670c 100644 --- a/code/modules/reagents/chems/chems_drugs.dm +++ b/code/modules/reagents/chems/chems_drugs.dm @@ -1,16 +1,19 @@ /decl/material/liquid/amphetamines name = "amphetamines" - lore_text = "A powerful, long-lasting stimulant." + lore_text = "A powerful, long-lasting stimulant." taste_description = "acid" color = "#ff3300" metabolism = REM * 0.15 overdose = REAGENTS_OVERDOSE * 0.5 value = 2 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_amphetamines" -/decl/material/liquid/amphetamines/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/amphetamines/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() if(prob(5)) - M.emote(pick("twitch", "blink_r", "shiver")) + M.emote(pick(/decl/emote/visible/twitch, /decl/emote/visible/blink_r, /decl/emote/visible/shiver)) M.add_chemical_effect(CE_SPEEDBOOST, 1) M.add_chemical_effect(CE_PULSE, 3) @@ -21,15 +24,18 @@ color = "#c8a5dc" overdose = REAGENTS_OVERDOSE value = 2 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_narcotics" -/decl/material/liquid/narcotics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.jitteriness = max(M.jitteriness - 5, 0) +/decl/material/liquid/narcotics/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + ADJ_STATUS(M, STAT_JITTER, -5) if(prob(80)) - M.adjustBrainLoss(5.25 * removed) + M.take_damage(5.25 * removed, BRAIN) if(prob(50)) - M.drowsyness = max(M.drowsyness, 3) + SET_STATUS_MAX(M, STAT_DROWSY, 3) if(prob(10)) - M.emote("drool") + M.emote(/decl/emote/visible/drool) /decl/material/liquid/nicotine name = "nicotine" @@ -40,21 +46,31 @@ overdose = 6 scannable = 1 value = 2 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_nicotine" -/decl/material/liquid/nicotine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - if(prob(volume*20)) +/decl/material/liquid/nicotine/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + var/affect_volume = REAGENT_VOLUME(holder, src) + . = ..() + if(prob(affect_volume*20)) M.add_chemical_effect(CE_PULSE, 1) - if(volume <= 0.02 && M.chem_doses[type] >= 0.05 && world.time > REAGENT_DATA(holder, type) + 3 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) + + var/update_data = FALSE + var/list/data = REAGENT_DATA(holder, src) + if(affect_volume <= 0.02 && CHEM_DOSE(M, src) >= 0.05 && world.time > LAZYACCESS(data, DATA_COOLDOWN_TIME) + 3 MINUTES) + update_data = TRUE to_chat(M, "You feel antsy, your concentration wavers...") - else if(world.time > REAGENT_DATA(holder, type) + 3 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) + else if(world.time > LAZYACCESS(data, DATA_COOLDOWN_TIME) + 3 MINUTES) + update_data = TRUE to_chat(M, "You feel invigorated and calm.") -/decl/material/liquid/nicotine/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) + if(update_data) + LAZYSET(data, DATA_COOLDOWN_TIME, world.time) + REAGENT_SET_DATA(holder, type, data) + +/decl/material/liquid/nicotine/affect_overdose(mob/living/victim, total_dose) ..() - M.add_chemical_effect(CE_PULSE, 2) + victim.add_chemical_effect(CE_PULSE, 2) /decl/material/liquid/sedatives name = "sedatives" @@ -64,23 +80,33 @@ metabolism = REM * 0.5 overdose = REAGENTS_OVERDOSE value = 2 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_sedatives" + var/sedative_strength = 1 // A multiplier on dose. -/decl/material/liquid/sedatives/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.make_jittery(-50) +/decl/material/liquid/sedatives/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + + . = ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + ADJ_STATUS(M, STAT_JITTER, -50) var/threshold = 1 - if(M.chem_doses[type] < 0.5 * threshold) - if(M.chem_doses[type] == metabolism * 2 || prob(5)) - M.emote("yawn") - else if(M.chem_doses[type] < 1 * threshold) - M.eye_blurry = max(M.eye_blurry, 10) - else if(M.chem_doses[type] < 2 * threshold) + var/dose = CHEM_DOSE(M, src) * sedative_strength + if(dose < 0.5 * threshold) + if(dose == metabolism * 2 || prob(5)) + M.emote(/decl/emote/audible/yawn) + else if(dose < 1 * threshold) + SET_STATUS_MAX(M, STAT_BLURRY, 10) + else if(dose < 2 * threshold) if(prob(50)) - M.Weaken(2) + SET_STATUS_MAX(M, STAT_WEAK, 2) M.add_chemical_effect(CE_SEDATE, 1) - M.drowsyness = max(M.drowsyness, 20) + SET_STATUS_MAX(M, STAT_DROWSY, 20) else - M.sleeping = max(M.sleeping, 20) - M.drowsyness = max(M.drowsyness, 60) + SET_STATUS_MAX(M, STAT_ASLEEP, 20) + SET_STATUS_MAX(M, STAT_DROWSY, 60) M.add_chemical_effect(CE_SEDATE, 1) M.add_chemical_effect(CE_PULSE, -1) @@ -95,13 +121,17 @@ value = 2 narcosis = 7 fruit_descriptor = "rich" - euphoriant = 15 - euphoriant_max = 15 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_psychoactives" -/decl/material/liquid/psychoactives/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/psychoactives/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() - M.adjust_drugged(15, 15) + + if(M.has_trait(/decl/trait/metabolically_inert)) + return + + SET_STATUS_MAX(M, STAT_DRUGGY, 15) M.add_chemical_effect(CE_PULSE, -1) /decl/material/liquid/hallucinogenics @@ -112,10 +142,17 @@ metabolism = REM * 0.25 overdose = REAGENTS_OVERDOSE value = 2 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_hallucinogenics" -/decl/material/liquid/hallucinogenics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/hallucinogenics/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + + if(M.has_trait(/decl/trait/metabolically_inert)) + return M.add_chemical_effect(CE_MIND, -2) - M.hallucination(50, 50) + M.set_hallucination(50, 50) + /decl/material/liquid/psychotropics name = "psychotropics" @@ -126,32 +163,39 @@ metabolism = REM * 0.5 value = 2 euphoriant = 30 - euphoriant_max = 30 fruit_descriptor = "hallucinogenic" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + compost_value = 0.1 // a pittance, but it's so that compost bins don't end up filled with uncompostable psychotropics + uid = "chem_psychotropics" -/decl/material/liquid/psychotropics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/psychotropics/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(M.has_trait(/decl/trait/metabolically_inert)) + return var/threshold = 1 - if(M.chem_doses[type] < 1 * threshold) + var/dose = CHEM_DOSE(M, src) + if(dose < 1 * threshold) M.apply_effect(3, STUTTER) - M.make_dizzy(5) + ADJ_STATUS(M, STAT_DIZZY, 1) if(prob(5)) - M.emote(pick("twitch", "giggle")) - else if(M.chem_doses[type] < 2 * threshold) + M.emote(pick(/decl/emote/visible/twitch, /decl/emote/audible/giggle)) + else if(dose < 2 * threshold) M.apply_effect(3, STUTTER) - M.make_jittery(5) - M.make_dizzy(5) - M.adjust_drugged(35, 35) + ADJ_STATUS(M, STAT_JITTER, 2) + ADJ_STATUS(M, STAT_DIZZY, 2) + SET_STATUS_MAX(M, STAT_DRUGGY, 35) if(prob(10)) - M.emote(pick("twitch", "giggle")) + M.emote(pick(/decl/emote/visible/twitch, /decl/emote/audible/giggle)) else M.add_chemical_effect(CE_MIND, -1) M.apply_effect(3, STUTTER) - M.make_jittery(10) - M.make_dizzy(10) - M.adjust_drugged(40, 40) + ADJ_STATUS(M, STAT_JITTER, 5) + ADJ_STATUS(M, STAT_DIZZY, 5) + SET_STATUS_MAX(M, STAT_DRUGGY, 40) if(prob(15)) - M.emote(pick("twitch", "giggle")) + M.emote(pick(/decl/emote/visible/twitch, /decl/emote/audible/giggle)) + // Welcome back, Three Eye /decl/material/liquid/glowsap/gleam @@ -160,9 +204,11 @@ color = "#ccccff" metabolism = REM overdose = 25 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_gleam" // M A X I M U M C H E E S E - var/global/list/dose_messages = list( + var/static/list/dose_messages = list( "Your name is called. It is your time.", "You are dissolving. Your hands are wax...", "It all runs together. It all mixes.", @@ -183,7 +229,7 @@ "Come back from there. Please." ) - var/global/list/overdose_messages = list( + var/static/list/overdose_messages = list( "THE SIGNAL THE SIGNAL THE SIGNAL THE SIGNAL", "IT CRIES IT CRIES IT WAITS IT CRIES", "NOT YOURS NOT YOURS NOT YOURS NOT YOURS", @@ -193,29 +239,30 @@ "THE LIGHT THE DARK A STAR IN CHAINS" ) -/decl/material/liquid/glowsap/gleam/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/glowsap/gleam/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) . = ..() - M.add_client_color(/datum/client_color/thirdeye) + M.add_client_color(/datum/client_color/noir/thirdeye) M.add_chemical_effect(CE_THIRDEYE, 1) M.add_chemical_effect(CE_MIND, -2) - M.hallucination(50, 50) - M.make_jittery(3) - M.make_dizzy(3) + M.set_hallucination(50, 50) + ADJ_STATUS(M, STAT_JITTER, 3) + ADJ_STATUS(M, STAT_DIZZY, 3) if(prob(0.1) && ishuman(M)) - var/mob/living/carbon/human/H = M + var/mob/living/human/H = M H.seizure() - H.adjustBrainLoss(rand(8, 12)) + H.take_damage(rand(8, 12), BRAIN) if(prob(5)) to_chat(M, SPAN_WARNING("[pick(dose_messages)]")) -/decl/material/liquid/glowsap/gleam/on_leaving_metabolism(var/mob/parent, var/metabolism_class) +/decl/material/liquid/glowsap/gleam/on_leaving_metabolism(datum/reagents/metabolism/holder) . = ..() - parent.remove_client_color(/datum/client_color/thirdeye) + var/mob/M = REAGENT_GET_ATOM(holder) + if(istype(M)) + M.remove_client_color(/datum/client_color/noir/thirdeye) -/decl/material/liquid/glowsap/gleam/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) - M.adjustBrainLoss(rand(1, 5)) - if(ishuman(M) && prob(10)) - var/mob/living/carbon/human/H = M - H.seizure() +/decl/material/liquid/glowsap/gleam/affect_overdose(mob/living/victim, total_dose) + victim.take_damage(rand(1, 5), BRAIN) + if(prob(10)) + victim.seizure() if(prob(10)) - to_chat(M, SPAN_DANGER("[pick(overdose_messages)]")) + to_chat(victim, SPAN_DANGER("[pick(overdose_messages)]")) diff --git a/code/modules/reagents/chems/chems_ethanol.dm b/code/modules/reagents/chems/chems_ethanol.dm deleted file mode 100644 index 4b6361f11157..000000000000 --- a/code/modules/reagents/chems/chems_ethanol.dm +++ /dev/null @@ -1,417 +0,0 @@ -/decl/material/liquid/ethanol - name = "ethanol" //Parent class for all alcoholic reagents. - lore_text = "A well-known alcohol with a variety of applications." - taste_description = "pure alcohol" - color = "#404030" - touch_met = 5 - fuel_value = 0.75 - solvent_power = MAT_SOLVENT_MODERATE - - heating_message = "boils away its water content, leaving pure ethanol." - heating_point = T100C + 10 - heating_products = list( - /decl/material/liquid/ethanol = 0.75, - /decl/material/liquid/water = 0.25 - ) - bypass_heating_products_for_root_type = /decl/material/liquid/ethanol - - chilling_message = "separates as its water content freezes, leaving pure ethanol." - chilling_point = T0C - 10 - chilling_products = list( - /decl/material/liquid/ethanol = 0.75, - /decl/material/liquid/water = 0.25 - ) - bypass_cooling_products_for_root_type = /decl/material/liquid/ethanol - - var/nutriment_factor = 0 - var/hydration_factor = 0 - var/strength = 10 // This is, essentially, units between stages - the lower, the stronger. Less fine tuning, more clarity. - var/alcohol_toxicity = 1 - var/adj_temp = 0 - var/targ_temp = 310 - var/halluci = 0 - - glass_name = "ethanol" - glass_desc = "A well-known alcohol with a variety of applications." - value = 1.2 - -/decl/material/liquid/ethanol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - M.adjustToxLoss(removed * 2 * alcohol_toxicity) - -/decl/material/liquid/ethanol/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - M.adjust_nutrition(nutriment_factor * removed) - M.adjust_hydration(hydration_factor * removed) - var/strength_mod = 1 - M.add_chemical_effect(CE_ALCOHOL, 1) - var/effective_dose = M.chem_doses[type] * strength_mod * (1 + REAGENT_VOLUME(holder, type)/60) //drinking a LOT will make you go down faster - if(effective_dose >= strength) // Early warning - M.make_dizzy(6) // It is decreased at the speed of 3 per tick - if(effective_dose >= strength * 2) // Slurring - M.add_chemical_effect(CE_PAINKILLER, 150/strength) - M.slurring = max(M.slurring, 30) - if(effective_dose >= strength * 3) // Confusion - walking in random directions - M.add_chemical_effect(CE_PAINKILLER, 150/strength) - M.confused = max(M.confused, 20) - if(effective_dose >= strength * 4) // Blurry vision - M.add_chemical_effect(CE_PAINKILLER, 150/strength) - M.eye_blurry = max(M.eye_blurry, 10) - if(effective_dose >= strength * 5) // Drowsyness - periodically falling asleep - M.add_chemical_effect(CE_PAINKILLER, 150/strength) - M.drowsyness = max(M.drowsyness, 20) - if(effective_dose >= strength * 6) // Toxic dose - M.add_chemical_effect(CE_ALCOHOL_TOXIC, alcohol_toxicity) - if(effective_dose >= strength * 7) // Pass out - M.Paralyse(20) - M.Sleeping(30) - - if(euphoriant) - M.adjust_drugged(euphoriant, euphoriant_max) - - if(adj_temp > 0 && M.bodytemperature < targ_temp) // 310 is the normal bodytemp. 310.055 - M.bodytemperature = min(targ_temp, M.bodytemperature + (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) - if(adj_temp < 0 && M.bodytemperature > targ_temp) - M.bodytemperature = min(targ_temp, M.bodytemperature - (adj_temp * TEMPERATURE_DAMAGE_COEFFICIENT)) - - if(halluci) - M.adjust_hallucination(halluci, halluci) - -/decl/material/liquid/ethanol/absinthe - name = "absinthe" - lore_text = "Watch out that the Green Fairy doesn't come for you!" - taste_description = "death and licorice" - taste_mult = 1.5 - color = "#33ee00" - strength = 12 - - glass_name = "absinthe" - glass_desc = "Wormwood, anise, oh my." - -/decl/material/liquid/ethanol/ale - name = "ale" - lore_text = "A dark alchoholic beverage made by malted barley and yeast." - taste_description = "hearty barley ale" - color = "#4c3100" - strength = 50 - - glass_name = "ale" - glass_desc = "A freezing container of delicious ale" - -/decl/material/liquid/ethanol/beer - name = "beer" - lore_text = "An alcoholic beverage made from malted grains, hops, yeast, and water." - taste_description = "piss water" - color = "#ffd300" - strength = 50 - nutriment_factor = 1 - - glass_name = "beer" - glass_desc = "A freezing container of beer" - -/decl/material/liquid/ethanol/beer/good - taste_description = "beer" - -/decl/material/liquid/ethanol/beer/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - M.jitteriness = max(M.jitteriness - 3, 0) - -/decl/material/liquid/ethanol/bluecuracao - name = "blue curacao" - lore_text = "Exotically blue, fruity drink, distilled from oranges." - taste_description = "oranges" - taste_mult = 1.1 - color = "#0000cd" - strength = 15 - - glass_name = "blue curacao" - glass_desc = "Exotically blue, fruity drink, distilled from oranges." - -/decl/material/liquid/ethanol/cognac - name = "cognac" - lore_text = "A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. Classy as fornication." - taste_description = "rich and smooth alcohol" - taste_mult = 1.1 - color = "#ab3c05" - strength = 15 - - glass_name = "cognac" - glass_desc = "Damn, you feel like some kind of French aristocrat just by holding this." - -/decl/material/liquid/ethanol/gin - name = "gin" - lore_text = "It's gin. In space. I say, good sir." - taste_description = "an alcoholic christmas tree" - color = "#0064c6" - strength = 15 - - glass_name = "gin" - glass_desc = "A crystal clear glass of Griffeater gin." - -//Base type for alchoholic drinks containing coffee -/decl/material/liquid/ethanol/coffee - overdose = 45 - -/decl/material/liquid/ethanol/coffee/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - M.dizziness = max(0, M.dizziness - 5) - M.drowsyness = max(0, M.drowsyness - 3) - M.sleeping = max(0, M.sleeping - 2) - if(M.bodytemperature > 310) - M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) - -/decl/material/liquid/ethanol/coffee/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) - M.make_jittery(5) - -/decl/material/liquid/ethanol/coffee/kahlua - name = "coffee liqueur" - lore_text = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936!" - taste_description = "spiked coffee" - taste_mult = 1.1 - color = "#4c3100" - strength = 15 - - glass_name = "RR coffee liquor" - glass_desc = "DAMN, THIS THING LOOKS ROBUST" - -/decl/material/liquid/ethanol/melonliquor - name = "melon liqueur" - lore_text = "A relatively sweet and fruity 46 proof liqueur." - taste_description = "fruity alcohol" - color = "#138808" // rgb: 19, 136, 8 - strength = 50 - - glass_name = "melon liqueur" - glass_desc = "A relatively sweet and fruity 46 proof liquor." - -/decl/material/liquid/ethanol/rum - name = "rum" - lore_text = "Yohoho and all that." - taste_description = "spiked butterscotch" - taste_mult = 1.1 - color = "#ecb633" - strength = 15 - - glass_name = "rum" - glass_desc = "Now you want to Pray for a pirate suit, don't you?" - -/decl/material/liquid/ethanol/sake - name = "sake" - lore_text = "Anime's favorite drink." - taste_description = "dry alcohol" - color = "#dddddd" - strength = 25 - - glass_name = "sake" - glass_desc = "A glass of sake." - -/decl/material/liquid/ethanol/tequilla - name = "tequila" - lore_text = "A strong and mildly flavoured, mexican produced spirit. Feeling thirsty hombre?" - taste_description = "paint stripper" - color = "#ffff91" - strength = 25 - - glass_name = "tequilla" - glass_desc = "Now all that's missing is the weird colored shades!" - -/decl/material/liquid/ethanol/thirteenloko - name = "Thirteen Loko" - lore_text = "A potent mixture of caffeine and alcohol." - taste_description = "jitters and death" - color = "#102000" - strength = 25 - nutriment_factor = 1 - - glass_name = "Thirteen Loko" - glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass." - -/decl/material/liquid/ethanol/thirteenloko/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - M.drowsyness = max(0, M.drowsyness - 7) - if (M.bodytemperature > 310) - M.bodytemperature = max(310, M.bodytemperature - (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) - M.make_jittery(5) - M.add_chemical_effect(CE_PULSE, 2) - -/decl/material/liquid/ethanol/vermouth - name = "vermouth" - lore_text = "You suddenly feel a craving for a martini..." - taste_description = "dry alcohol" - taste_mult = 1.3 - color = "#91ff91" // rgb: 145, 255, 145 - strength = 15 - - glass_name = "vermouth" - glass_desc = "You wonder why you're even drinking this straight." - -/decl/material/liquid/ethanol/vodka - name = "vodka" - lore_text = "Number one drink AND fueling choice for Independents around the galaxy." - taste_description = "grain alcohol" - color = "#0064c8" // rgb: 0, 100, 200 - strength = 15 - - glass_name = "vodka" - glass_desc = "The glass contain wodka. Xynta." - -/decl/material/liquid/ethanol/vodka/premium - name = "premium vodka" - lore_text = "Premium distilled vodka imported directly from the Gilgamesh Colonial Confederation." - taste_description = "clear kvass" - color = "#aaddff" // rgb: 170, 221, 255 - very light blue. - strength = 10 - -/decl/material/liquid/ethanol/whiskey - name = "whiskey" - lore_text = "A superb and well-aged single-malt whiskey. Damn." - taste_description = "molasses" - color = "#4c3100" - strength = 25 - - glass_name = "whiskey" - glass_desc = "The silky, smokey whiskey goodness inside the glass makes the drink look very classy." - -/decl/material/liquid/ethanol/wine - name = "wine" - lore_text = "An premium alchoholic beverage made from distilled grape juice." - taste_description = "bitter sweetness" - color = "#7e4043" // rgb: 126, 64, 67 - strength = 15 - - glass_name = "wine" - glass_desc = "A very classy looking drink." - -/decl/material/liquid/ethanol/wine/premium - name = "white wine" - lore_text = "An exceptionally expensive alchoholic beverage made from distilled white grapes." - taste_description = "white velvet" - color = "#ffddaa" // rgb: 255, 221, 170 - a light cream - strength = 20 - -/decl/material/liquid/ethanol/herbal - name = "herbal liquor" - lore_text = "A complex blend of herbs, spices and roots mingle in this old Earth classic." - taste_description = "a sweet summer garden" - color = "#dfff00" - strength = 13 - - glass_name = "herbal liquor" - glass_desc = "It's definitely green. Or is it yellow?" - -/decl/material/liquid/ethanol/hooch - name = "hooch" - lore_text = "Either someone's failure at cocktail making or attempt in alchohol production. In any case, do you really want to drink that?" - taste_description = "pure resignation" - color = "#4c3100" - strength = 25 - alcohol_toxicity = 2 - - glass_name = "Hooch" - glass_desc = "You've really hit rock bottom now... your liver packed its bags and left last night." - -/decl/material/liquid/ethanol/irish_cream - name = "Irish cream" - lore_text = "Whiskey-imbued cream." - taste_description = "creamy alcohol" - color = "#dddd9a" - strength = 25 - - glass_name = "Irish cream" - glass_desc = "It's cream, mixed with whiskey." - -/decl/material/liquid/ethanol/mead - name = "mead" - lore_text = "A Viking's drink, though a cheap one." - taste_description = "sweet, sweet alcohol" - color = "#ffbb00" - strength = 30 - nutriment_factor = 1 - - glass_name = "mead" - glass_desc = "A Viking's beverage, though a cheap one." - -/decl/material/liquid/ethanol/moonshine - name = "moonshine" - lore_text = "You've really hit rock bottom now... your liver packed its bags and left last night." - taste_description = "bitterness" - taste_mult = 2.5 - color = "#0064c8" - strength = 12 - - glass_name = "moonshine" - glass_desc = "You've really hit rock bottom now... your liver packed its bags and left last night." - -/decl/material/liquid/ethanol/pwine - name = "poison wine" - lore_text = "Is this even wine? Toxic! Hallucinogenic! Probably consumed in boatloads by your superiors!" - taste_description = "purified alcoholic death" - color = "#000000" - strength = 10 - halluci = 10 - glass_name = "???" - glass_desc = "A black ichor with an oily purple sheer on top. Are you sure you should drink this?" - euphoriant = 50 - euphoriant_max = 50 - -/decl/material/liquid/ethanol/pwine/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - ..() - if(M.chem_doses[type] > 30) - M.adjustToxLoss(2 * removed) - if(M.chem_doses[type] > 60 && ishuman(M) && prob(5)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/internal/heart/L = H.internal_organs_by_name[BP_HEART] - if (L && istype(L)) - if(M.chem_doses[type] < 120) - L.take_internal_damage(10 * removed, 0) - else - L.take_internal_damage(100, 0) - -/decl/material/liquid/ethanol/aged_whiskey // I have no idea what this is and where it comes from. //It comes from Dinnlan now - name = "aged whiskey" - lore_text = "A well-aged whiskey of high quality. Probably imported. Just a sip'll do it, but that burn will leave you wanting more." - color = "#523600" - strength = 25 - - glass_name = "aged whiskey" - glass_desc = "A well-aged whiskey of high quality. Probably imported." - -/decl/material/liquid/ethanol/applecider - name = "apple cider" - lore_text = "A refreshing glass of apple cider." - taste_description = "cool apple cider" - color = "#cac089" - strength = 50 - - glass_name = "apple cider" - glass_desc = "A refreshing glass of apple cider." - -/decl/material/liquid/ethanol/champagne - name = "champagne" - lore_text = "Smooth sparkling wine, produced in the same region of France as it has for centuries." - taste_description = "a superior taste of sparkling wine" - color = "#e8dfc1" - strength = 25 - - glass_name = "champagne" - glass_desc = "Smooth sparkling wine, produced in the same region of France as it has for centuries." - -/decl/material/liquid/ethanol/jagermeister - name = "Jagermeister" - lore_text = "A special blend of alcohol, herbs, and spices. It has remained a popular Earther drink." - taste_description = "herbs, spices, and alcohol" - color = "#596e3e" - strength = 20 - - glass_name = "jagermeister" - glass_desc = "A special blend of alcohol, herbs, and spices. It has remained a popular Earther drink." - -/decl/material/liquid/ethanol/kvass - name = "kvass" - lore_text = "An alcoholic drink commonly made from bread." - taste_description = "vkusnyy kvas, ypa!" - color = "#362f22" - strength = 30 - - glass_name = "kvass" - glass_desc = "An alcoholic drink commonly made from bread." diff --git a/code/modules/reagents/chems/chems_explosives.dm b/code/modules/reagents/chems/chems_explosives.dm index 43b3385926ee..c23813eed550 100644 --- a/code/modules/reagents/chems/chems_explosives.dm +++ b/code/modules/reagents/chems/chems_explosives.dm @@ -3,28 +3,33 @@ lore_text = "Ammonia Nitrate Fuel Oil mix, an explosive compound known for centuries. Safe to handle, can be set off with a small explosion." taste_description = "fertilizer and fuel" color = "#dbc3c3" + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_anfo" var/boompower = 1 /decl/material/liquid/anfo/explosion_act(obj/item/chems/holder, severity) . = ..() if(.) - var/volume = REAGENT_VOLUME(holder?.reagents, type) - var/activated_volume = volume + var/affect_volume = REAGENT_VOLUME(holder?.reagents, type) + var/activated_volume = affect_volume switch(severity) if(2) - if(prob(max(0, 2*(volume - 120)))) - activated_volume = rand(volume/4, volume) + if(prob(max(0, 2*(affect_volume - 120)))) + activated_volume = rand(affect_volume/4, affect_volume) if(3) - if(prob(max(0, 2*(volume - 60)))) - activated_volume = rand(volume, 120) + if(prob(max(0, 2*(affect_volume - 60)))) + activated_volume = rand(affect_volume, 120) if(activated_volume < 30) //whiff return var/turf/T = get_turf(holder) if(T) var/adj_power = round(boompower * activated_volume/60) var/datum/gas_mixture/products = new(_temperature = 5 * FLAMMABLE_GAS_FLASHPOINT) - var/gas_moles = 3 * volume - products.adjust_multi(/decl/material/gas/carbon_dioxide, 0.5 * gas_moles, /decl/material/gas/nitrogen, 0.3 * gas_moles, /decl/material/liquid/water, 0.2 * gas_moles) + var/gas_moles = 3 * affect_volume + products.adjust_gas(/decl/material/gas/carbon_dioxide, 0.5 * gas_moles, FALSE) + products.adjust_gas(/decl/material/gas/nitrogen, 0.3 * gas_moles, FALSE) + products.adjust_gas(/decl/material/liquid/water, 0.2 * gas_moles, TRUE) T.assume_air(products) holder?.reagents?.remove_reagent(type, activated_volume) explosion(T, adj_power, adj_power + 1, adj_power*2 + 2) @@ -34,3 +39,6 @@ lore_text = "Ammonia Nitrate Fuel Oil, with aluminium powder, an explosive compound known for centuries. Safe to handle, can be set off with a small explosion." color = "#ffe8e8" boompower = 2 + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_anfoplus" diff --git a/code/modules/reagents/chems/chems_fuel.dm b/code/modules/reagents/chems/chems_fuel.dm index 2385bb129845..c3adf5d8c90a 100644 --- a/code/modules/reagents/chems/chems_fuel.dm +++ b/code/modules/reagents/chems/chems_fuel.dm @@ -4,40 +4,48 @@ taste_description = "gross metal" color = "#660000" touch_met = 5 - fuel_value = 1 + ignition_point = T0C+150 + accelerant_value = FUEL_VALUE_ACCELERANT + 0.2 + burn_product = /decl/material/gas/carbon_monoxide + gas_flags = XGM_GAS_FUEL + exoplanet_rarity_plant = MAT_RARITY_UNCOMMON + exoplanet_rarity_gas = MAT_RARITY_UNCOMMON + uid = "chem_fuel" + toxicity = 2 glass_name = "welder fuel" glass_desc = "Unless you are an industrial tool, this is probably not safe for consumption." value = 1.5 -/decl/material/liquid/fuel/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.adjustToxLoss(2 * removed) - /decl/material/liquid/fuel/explosion_act(obj/item/chems/holder, severity) . = ..() if(.) - var/volume = REAGENT_VOLUME(holder?.reagents, type) - if(volume <= 50) + var/product_volume = REAGENT_VOLUME(holder?.reagents, type) + if(product_volume <= 50) return var/turf/T = get_turf(holder) var/datum/gas_mixture/products = new(_temperature = 5 * FLAMMABLE_GAS_FLASHPOINT) - var/gas_moles = 3 * volume - products.adjust_multi(/decl/material/gas/nitricoxide, 0.1 * gas_moles, /decl/material/gas/nitrodioxide, 0.1 * gas_moles, /decl/material/gas/nitrogen, 0.6 * gas_moles, /decl/material/gas/hydrogen, 0.02 * gas_moles) + var/gas_moles = 3 * product_volume + products.adjust_gas(/decl/material/gas/nitricoxide, 0.1 * gas_moles, FALSE) + products.adjust_gas(/decl/material/gas/nitrodioxide, 0.1 * gas_moles, FALSE) + products.adjust_gas(/decl/material/gas/nitrogen, 0.6 * gas_moles, FALSE) + products.adjust_gas(/decl/material/gas/hydrogen, 0.02 * gas_moles, TRUE) T.assume_air(products) - if(volume > 500) + if(product_volume > 500) explosion(T,1,2,4) - else if(volume > 100) + else if(product_volume > 100) explosion(T,0,1,3) - else if(volume > 50) + else if(product_volume > 50) explosion(T,-1,1,2) - holder?.reagents?.remove_reagent(type, volume) + holder?.reagents?.remove_reagent(type, product_volume) /decl/material/liquid/fuel/hydrazine name = "hydrazine" - lore_text = "A toxic, colorless, flammable liquid with a strong ammonia-like odor, in hydrate form." + lore_text = "A toxic, colorless, flammable liquid with a strong ammonia-like odour, in hydrate form." taste_description = "sweet tasting metal" color = "#808080" metabolism = REM * 0.2 touch_met = 5 value = 1.2 - fuel_value = 1.2 + accelerant_value = FUEL_VALUE_ACCELERANT + 0.5 + uid = "chem_hydrazine" diff --git a/code/modules/reagents/chems/chems_herbal.dm b/code/modules/reagents/chems/chems_herbal.dm new file mode 100644 index 000000000000..676142113fb2 --- /dev/null +++ b/code/modules/reagents/chems/chems_herbal.dm @@ -0,0 +1,97 @@ +/decl/material/liquid/brute_meds/yarrow + name = "powdered yarrow flower" + uid = "chem_brute_herbal" + lore_text = "Yarrow flower is a herbal remedy for physical injury, helping with slowing bleeding and encouraging healing." + taste_description = "bitter herbs" + effectiveness = 0.35 + +/decl/material/liquid/burn_meds/aloe + name = "aloe vera gel" + uid = "chem_burn_herbal" + lore_text = "Aloe vera gel has soothing and healing properties when used as a burn treatment." + taste_description = "soothing coolness" + effectiveness = 0.35 + +/decl/material/liquid/antitoxins/ginseng + name = "powdered ginseng" + uid = "chem_antitoxins_herbal" + lore_text = "Ginseng root has curative properties and encourages organ recovery and restoration of blood volume after poisoning or blood loss." + taste_description = "bitter herbs" + antitoxin_strength = 0.35 + +/decl/material/liquid/antitoxins/ginseng/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(M.has_trait(/decl/trait/metabolically_inert)) + return + M.add_chemical_effect(CE_BLOODRESTORE, 8 * removed) + +/decl/material/liquid/sedatives/valerian + name = "powdered valerian flower" + uid = "chem_sedatives_herbal" + lore_text = "Valerian flower is a herbal rememdy for anxiety and insomnia." + taste_description = "bitter herbs" + sedative_strength = 0.35 + +/decl/material/liquid/stabilizer/foxglove + name = "powdered foxglove flower" + uid = "chem_stabilizer_herbal" + lore_text = "Foxglove flower is a herbal remedy for cardiac problems, and assists in the treatment of shock." + taste_description = "bitter herbs" + // Stabilizer is kind of boolean so no way to make this one weaker currently. + +/decl/material/liquid/brute_meds/yarrow/tea + name = "yarrow tea" + uid = "chem_brute_tea" + lore_text = "A herbal tea brewed from powdered yarrow flower, used to treat injury." + taste_description = "bitterness" + effectiveness = 0.65 + +/decl/material/liquid/burn_meds/aloe/tea + name = "aloe tea" + uid = "chem_burns_tea" + lore_text = "A herbal tea brewed from aloe vera, used to treat burns." + taste_description = "coolness" + effectiveness = 0.65 + +/decl/material/liquid/antitoxins/ginseng/tea + name = "ginseng tea" + uid = "chem_antitoxins_tea" + lore_text = "A herbal tea brewed from powdered ginseng root, used to treat poisoning." + taste_description = "bitterness" + antitoxin_strength = 0.65 + +/decl/material/liquid/sedatives/valerian/tea + name = "valerian tea" + uid = "chem_sedatives_tea" + lore_text = "A herbal tea brewed from powdered valerian flower, used to soothe anxiety and insomnia." + taste_description = "bitterness" + sedative_strength = 0.65 + +// TODO: tincture mechanics - side effects of alcohol, low overdose limit? +/decl/material/liquid/brute_meds/yarrow/tincture + name = "tincture of yarrow" + uid = "chem_brute_tincture" + lore_text = "A tincture of strong spirits and powdered yarrow, used to treat severe injury." + taste_description = "bitterness" + effectiveness = 0.8 + +/decl/material/liquid/burn_meds/aloe/tincture + name = "tincture of aloe" + uid = "chem_burns_tincture" + lore_text = "A tincture of strong spirits and aloe vera, used to treat severe burns." + taste_description = "coolness" + effectiveness = 0.8 + +/decl/material/liquid/antitoxins/ginseng/tincture + name = "tincture of ginseng" + uid = "chem_antitoxins_tincture" + lore_text = "A tincture of strong spirits and powdered ginseng root, used to treat severe poisoning." + taste_description = "bitterness" + antitoxin_strength = 0.8 + +/decl/material/liquid/sedatives/valerian/tincture + name = "tincture of valerian" + uid = "chem_sedatives_tincture" + lore_text = "A tincture of strong spirits and powdered valerian flower, used to treat serious cases of anxiety and insomnia." + taste_description = "bitterness" + sedative_strength = 0.8 diff --git a/code/modules/reagents/chems/chems_medicines.dm b/code/modules/reagents/chems/chems_medicines.dm index 798e27051144..b771084ef239 100644 --- a/code/modules/reagents/chems/chems_medicines.dm +++ b/code/modules/reagents/chems/chems_medicines.dm @@ -7,15 +7,16 @@ scannable = 1 flags = IGNORE_MOB_SIZE value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_eyedrops" -/decl/material/liquid/eyedrops/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[BP_EYES] - if(E && istype(E) && !E.is_broken()) - M.eye_blurry = max(M.eye_blurry - 5, 0) - M.eye_blind = max(M.eye_blind - 5, 0) - E.damage = max(E.damage - 5 * removed, 0) +/decl/material/liquid/eyedrops/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/obj/item/organ/internal/eyes = GET_INTERNAL_ORGAN(M, BP_EYES) + if(istype(eyes) && !eyes.is_broken()) + ADJ_STATUS(M, STAT_BLURRY, -5) + ADJ_STATUS(M, STAT_BLIND, -5) + eyes.adjust_organ_damage(-(5 * removed)) /decl/material/liquid/antirads name = "antirads" @@ -27,9 +28,13 @@ scannable = 1 flags = IGNORE_MOB_SIZE value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_antirads" + var/antirad_power = 30 -/decl/material/liquid/antirads/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.radiation = max(M.radiation - 30 * removed, 0) +/decl/material/liquid/antirads/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + M.radiation = max(M.radiation - antirad_power * removed, 0) /decl/material/liquid/brute_meds name = "styptic powder" @@ -42,18 +47,23 @@ flags = IGNORE_MOB_SIZE value = 1.5 fruit_descriptor = "medicinal" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_styptic" + var/effectiveness = 1 -/decl/material/liquid/brute_meds/affect_overdose(mob/living/carbon/M, alien, var/datum/reagents/holder) +/decl/material/liquid/brute_meds/affect_overdose(mob/living/victim, total_dose) ..() - if(ishuman(M)) - M.add_chemical_effect(CE_BLOCKAGE, (15 + REAGENT_VOLUME(holder, type))/100) - var/mob/living/carbon/human/H = M - for(var/obj/item/organ/external/E in H.organs) - if(E.status & ORGAN_ARTERY_CUT && prob(2)) - E.status &= ~ORGAN_ARTERY_CUT - -/decl/material/liquid/brute_meds/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.heal_organ_damage(6 * removed, 0) + victim.add_chemical_effect(CE_BLOCKAGE, (15 + total_dose) / 100) + for(var/obj/item/organ/external/limb in victim.get_external_organs()) + if((limb.status & ORGAN_ARTERY_CUT) && prob(2 + total_dose / overdose)) + limb.status &= ~ORGAN_ARTERY_CUT + +//This is a logistic function that effectively doubles the healing rate as brute amounts get to around 200. Any injury below 60 is essentially unaffected and there's a scaling inbetween. +#define ADJUSTED_REGEN_VAL(X) (6+(6/(1+200*2.71828**(-0.05*(X))))) +/decl/material/liquid/brute_meds/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + M.add_stressor(/datum/stressor/used_chems, 5 MINUTES) + M.add_chemical_effect_max(CE_REGEN_BRUTE, round(effectiveness*ADJUSTED_REGEN_VAL(M.get_damage(BRUTE)))) M.add_chemical_effect(CE_PAINKILLER, 10) /decl/material/liquid/burn_meds @@ -65,10 +75,16 @@ scannable = 1 flags = IGNORE_MOB_SIZE value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_synthskin" + var/effectiveness = 1 -/decl/material/liquid/burn_meds/affect_blood(mob/living/carbon/M, alien, removed, var/datum/reagents/holder) - M.heal_organ_damage(0, 6 * removed) +/decl/material/liquid/burn_meds/affect_blood(mob/living/M, removed, var/datum/reagents/holder) + ..() + M.add_stressor(/datum/stressor/used_chems, 5 MINUTES) + M.add_chemical_effect_max(CE_REGEN_BURN, round(effectiveness*ADJUSTED_REGEN_VAL(M.get_damage(BURN)))) M.add_chemical_effect(CE_PAINKILLER, 10) +#undef ADJUSTED_REGEN_VAL /decl/material/liquid/adminordrazine //An OP chemical for admins name = "Adminordrazine" @@ -76,14 +92,20 @@ taste_description = "100% abuse" color = "#c8a5dc" flags = AFFECTS_DEAD //This can even heal dead people. + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_adminorazine" glass_name = "liquid gold" glass_desc = "It's magic. We don't have to explain it." -/decl/material/liquid/adminordrazine/affect_touch(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - affect_blood(M, alien, removed, holder) +/decl/material/liquid/adminordrazine/affect_touch(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + affect_blood(M, removed, holder) + return TRUE -/decl/material/liquid/adminordrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/adminordrazine/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() M.rejuvenate() /decl/material/liquid/antitoxins @@ -95,29 +117,31 @@ flags = IGNORE_MOB_SIZE value = 1.5 fruit_descriptor = "astringent" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_antitoxins" + var/antitoxin_strength = 1 // effect multiplier var/remove_generic = 1 var/list/remove_toxins = list( /decl/material/liquid/zombiepowder ) -/decl/material/liquid/antitoxins/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/antitoxins/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() if(remove_generic) - M.drowsyness = max(0, M.drowsyness - 6 * removed) - M.adjust_hallucination(-9 * removed) - M.add_up_to_chemical_effect(CE_ANTITOX, 1) + ADJ_STATUS(M, STAT_DROWSY, -6 * removed * antitoxin_strength) + M.adjust_hallucination(-9 * removed * antitoxin_strength) + M.add_chemical_effect(CE_ANTITOX, 1) - var/removing = (4 * removed) + var/removing = (4 * removed * antitoxin_strength) var/datum/reagents/ingested = M.get_ingested_reagents() - for(var/R in ingested.reagent_volumes) - var/decl/material/chem = decls_repository.get_decl(R) - if((remove_generic && chem.toxicity) || (R in remove_toxins)) - M.reagents.remove_reagent(R, removing) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(ingested)) + if((remove_generic && reagent.toxicity) || (reagent.type in remove_toxins)) + ingested.remove_reagent(reagent, removing) return - for(var/R in M.reagents?.reagent_volumes) - var/decl/material/chem = decls_repository.get_decl(R) - if((remove_generic && chem.toxicity) || (R in remove_toxins)) - M.reagents.remove_reagent(R, removing) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(M.reagents)) + if((remove_generic && reagent.toxicity) || (reagent.type in remove_toxins)) + M.remove_from_reagents(reagent, removing) return /decl/material/liquid/immunobooster @@ -129,59 +153,21 @@ overdose = REAGENTS_OVERDOSE value = 1.5 scannable = 1 - -/decl/material/liquid/immunobooster/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(REAGENT_VOLUME(holder, type) < REAGENTS_OVERDOSE) - M.immunity = min(M.immunity_norm * 0.5, removed + M.immunity) // Rapidly brings someone up to half immunity. - -/decl/material/liquid/immunobooster/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_immunobooster" + +/decl/material/liquid/immunobooster/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + if(REAGENT_VOLUME(holder, src) >= REAGENTS_OVERDOSE) + return + var/immunity_to_add = clamp((M.immunity_norm / 2) - M.get_immunity(), 0, removed) + if(immunity_to_add > 0) + M.adjust_immunity(immunity_to_add) // Rapidly brings someone up to half immunity. + +/decl/material/liquid/immunobooster/affect_overdose(mob/living/victim, total_dose) ..() - M.add_chemical_effect(CE_TOXIN, 1) - M.immunity -= 0.5 //inverse effects when abused - -/decl/material/liquid/stimulants - name = "stimulants" - lore_text = "Improves the ability to concentrate." - taste_description = "sourness" - color = "#bf80bf" - scannable = 1 - metabolism = 0.01 - value = 1.5 - -/decl/material/liquid/stimulants/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - if(volume <= 0.1 && M.chem_doses[type] >= 0.5 && world.time > REAGENT_DATA(holder, type) + 5 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) - to_chat(M, "You lose focus...") - else - M.drowsyness = max(M.drowsyness - 5, 0) - M.AdjustParalysis(-1) - M.AdjustStunned(-1) - M.AdjustWeakened(-1) - if(world.time > REAGENT_DATA(holder, type) + 5 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) - to_chat(M, "Your mind feels focused and undivided.") - -/decl/material/liquid/antidepressants - name = "antidepressants" - lore_text = "Stabilizes the mind a little." - taste_description = "bitterness" - color = "#ff80ff" - scannable = 1 - metabolism = 0.01 - value = 1.5 - -/decl/material/liquid/antidepressants/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - if(volume <= 0.1 && M.chem_doses[type] >= 0.5 && world.time > REAGENT_DATA(holder, type) + 5 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) - to_chat(M, "Your mind feels a little less stable...") - else - M.add_chemical_effect(CE_MIND, 1) - M.adjust_hallucination(-10) - if(world.time > REAGENT_DATA(holder, type) + 5 MINUTES) - LAZYSET(holder.reagent_data, type, world.time) - to_chat(M, "Your mind feels stable... a little stable.") + victim.add_chemical_effect(CE_TOXIN, 1) + victim.adjust_immunity(-0.5) /decl/material/liquid/antibiotics name = "antibiotics" @@ -192,21 +178,16 @@ overdose = REAGENTS_OVERDOSE/2 scannable = 1 value = 1.5 + antibiotic_strength = 1 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_antibiotics" -/decl/material/liquid/antibiotics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - M.immunity = max(M.immunity - 0.1, 0) - M.add_chemical_effect(CE_ANTIBIOTIC, 1) - if(volume > 10) - M.immunity = max(M.immunity - 0.3, 0) - if(M.chem_doses[type] > 15) - M.immunity = max(M.immunity - 0.25, 0) - -/decl/material/liquid/antibiotics/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) +/decl/material/liquid/antibiotics/affect_overdose(mob/living/victim, total_dose) ..() - M.immunity = max(M.immunity - 0.25, 0) + victim.adjust_immunity(-0.5) + victim.immunity = max(victim.immunity - 0.25, 0) if(prob(2)) - M.immunity_norm = max(M.immunity_norm - 1, 0) + victim.immunity_norm = max(victim.immunity_norm - 1, 0) /decl/material/liquid/retrovirals name = "retrovirals" @@ -216,27 +197,23 @@ scannable = 1 overdose = REAGENTS_OVERDOSE value = 1.5 - -/decl/material/liquid/retrovirals/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.adjustCloneLoss(-20 * removed) - M.adjustOxyLoss(-2 * removed) - M.heal_organ_damage(20 * removed, 20 * removed) - M.adjustToxLoss(-20 * removed) - if(M.chem_doses[type] > 3 && ishuman(M)) - var/mob/living/carbon/human/H = M - for(var/obj/item/organ/external/E in H.organs) - E.status |= ORGAN_DISFIGURED //currently only matters for the head, but might as well disfigure them all. - if(M.chem_doses[type] > 10) - M.make_dizzy(5) - M.make_jittery(5) - - var/needs_update = M.mutations.len > 0 - M.disabilities = 0 - M.sdisabilities = 0 - if(needs_update && ishuman(M)) - M.dna.ResetUI() - M.dna.ResetSE() - domutcheck(M, null, MUTCHK_FORCED) + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_retrovirals" + +/decl/material/liquid/retrovirals/affect_overdose(mob/living/victim, total_dose) + . = ..() + for(var/obj/item/organ/external/limb in victim.get_external_organs()) + if(!BP_IS_PROSTHETIC(limb) && prob(25) && !(limb.status & ORGAN_MUTATED)) + limb.mutate() + limb.limb_flags |= ORGAN_FLAG_DEFORMED + +/decl/material/liquid/retrovirals/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + M.heal_damage(CLONE, 20 * removed) + if(CHEM_DOSE(M, src) > 10) + ADJ_STATUS(M, STAT_DIZZY, 5) + ADJ_STATUS(M, STAT_JITTER, 5) + M.reset_genetic_conditions() /decl/material/liquid/adrenaline name = "adrenaline" @@ -247,22 +224,27 @@ overdose = 20 metabolism = 0.1 value = 1.5 - -/decl/material/liquid/adrenaline/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) - if(M.chem_doses[type] < 0.2) //not that effective after initial rush - M.add_chemical_effect(CE_PAINKILLER, min(30*volume, 80)) + uid = "chem_adrenaline" + +/decl/material/liquid/adrenaline/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + var/affect_volume = REAGENT_VOLUME(holder, src) + var/dose = CHEM_DOSE(M, src) + . = ..() + if(dose < 0.2) //not that effective after initial rush + M.add_chemical_effect(CE_PAINKILLER, min(30*affect_volume, 80)) M.add_chemical_effect(CE_PULSE, 1) - else if(M.chem_doses[type] < 1) - M.add_chemical_effect(CE_PAINKILLER, min(10*volume, 20)) + else if(dose < 1) + M.add_chemical_effect(CE_PAINKILLER, min(10*affect_volume, 20)) M.add_chemical_effect(CE_PULSE, 2) - if(M.chem_doses[type] > 10) - M.make_jittery(5) - if(volume >= 5 && M.is_asystole()) + if(dose > 10) + ADJ_STATUS(M, STAT_JITTER, 5) + if(affect_volume >= 5 && M.is_asystole()) holder.remove_reagent(type, 5) - if(M.resuscitate()) - var/obj/item/organ/internal/heart = M.internal_organs_by_name[BP_HEART] - heart.take_internal_damage(heart.max_damage * 0.15) + if(ishuman(M)) + var/mob/living/human/H = M + if(H.resuscitate()) + var/obj/item/organ/internal/heart = GET_INTERNAL_ORGAN(H, BP_HEART) + heart.take_damage(heart.max_damage * 0.15) /decl/material/liquid/stabilizer name = "stabilizer" @@ -272,9 +254,13 @@ scannable = 1 metabolism = 0.5 * REM value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_stabilizer" -/decl/material/liquid/stabilizer/affect_blood(var/mob/living/carbon/human/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/stabilizer/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() M.add_chemical_effect(CE_STABLE) + M.remove_chemical_effect(CE_ALLERGEN) /decl/material/liquid/regenerator name = "regenerative serum" @@ -284,9 +270,14 @@ scannable = 1 flags = IGNORE_MOB_SIZE value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_regenerative_serum" -/decl/material/liquid/regenerator/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.heal_organ_damage(3 * removed, 3 * removed) +/decl/material/liquid/regenerator/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + M.add_stressor(/datum/stressor/used_chems, 5 MINUTES) + M.add_chemical_effect_max(CE_REGEN_BRUTE, 3 * removed) + M.add_chemical_effect_max(CE_REGEN_BURN, 3 * removed) /decl/material/liquid/neuroannealer name = "neuroannealer" @@ -298,21 +289,105 @@ scannable = 1 flags = IGNORE_MOB_SIZE value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_neuroannealer" -/decl/material/liquid/neuroannealer/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/neuroannealer/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() M.add_chemical_effect(CE_PAINKILLER, 10) M.add_chemical_effect(CE_BRAIN_REGEN, 1) if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.confused++ - H.drowsyness++ + var/mob/living/human/H = M + ADJ_STATUS(H, STAT_CONFUSE, 1) + ADJ_STATUS(H, STAT_DROWSY, 1) /decl/material/liquid/oxy_meds name = "oxygel" lore_text = "A biodegradable gel full of oxygen-laden synthetic molecules. Injected into suffocation victims to stave off the effects of oxygen deprivation." taste_description = "tasteless slickness" + scannable = 1 color = COLOR_GRAY80 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_oxygel" -/decl/material/liquid/oxy_meds/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/oxy_meds/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() M.add_chemical_effect(CE_OXYGENATED, 1) holder.remove_reagent(/decl/material/gas/carbon_monoxide, 2 * removed) + +/decl/material/liquid/clotting_agent + name = "clotting agent" + uid = "chem_clotting_agent" + lore_text = "A medication used to rapidly clot internal hemorrhages by increasing the effectiveness of platelets." + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE * 0.5 + color = "#4246c7" + scannable = TRUE + +/decl/material/liquid/clotting_agent/affect_blood(mob/living/M, removed, datum/reagents/holder) + SET_STATUS_MAX(M, STAT_BLURRY, 30) + M.add_chemical_effect(CE_BLOCKAGE, (15 + REAGENT_VOLUME(holder, src))/100) + for(var/obj/item/organ/external/limb in M.get_external_organs()) + if(!(limb.status & (ORGAN_ARTERY_CUT|ORGAN_BLEEDING)) || !prob(2 + REAGENT_VOLUME(holder, src))) + continue + if(limb.status & ORGAN_ARTERY_CUT) + limb.status &= ~ORGAN_ARTERY_CUT + break + if(limb.status & ORGAN_BLEEDING) + var/closed_wound = FALSE + for(var/datum/wound/wound in limb.wounds) + if(wound.bleeding() && !wound.clamped) + wound.clamped = TRUE + closed_wound = TRUE + break + if(closed_wound) + break + ..() + +/decl/material/liquid/clotting_agent/affect_overdose(mob/living/victim, total_dose) + var/obj/item/organ/internal/heart = GET_INTERNAL_ORGAN(victim, BP_HEART) + if(heart && prob(25)) + heart.take_damage(rand(1,3)) + return ..() + +#define DETOXIFIER_EFFECTIVENESS 6 // 6u of opiates removed per 1u of detoxifier; 5u is enough to remove 30u, i.e. an overdose +#define DETOXIFIER_DOSE_EFFECTIVENESS 2 // 2u of metabolised opiates removed per 1u of detoxifier; will leave you vulnerable to another OD if you use more +/decl/material/liquid/detoxifier + name = "detoxifier" + lore_text = "A compound designed to purge opiates and narcotics from the body when inhaled or injected." + taste_description = "bitterness" + color = "#6666ff" + metabolism = REM + scannable = TRUE + affect_blood_on_ingest = FALSE + value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_detoxifier" + +/decl/material/liquid/detoxifier/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + var/charges = removed * DETOXIFIER_EFFECTIVENESS + var/dosecharges = CHEM_DOSE(M, src) * DETOXIFIER_DOSE_EFFECTIVENESS + for(var/datum/reagents/container as anything in M.get_metabolizing_reagent_holders()) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(container)) + var/decl/material/liquid/painkillers/painkiller = reagent + if(!istype(painkiller) || !painkiller.narcotic) + continue + var/amount = min(charges, REAGENT_VOLUME(container, reagent)) + if(amount) + charges -= amount + container.remove_reagent(reagent, amount) + var/dose_amount = min(dosecharges, CHEM_DOSE(M, reagent)) + if(dose_amount) + var/dose = CHEM_DOSE(M, reagent) - dose_amount + LAZYSET(M._chem_doses, reagent, dose) + if(CHEM_DOSE(M, reagent) <= 0) + LAZYREMOVE(M._chem_doses, reagent) + dosecharges -= dose_amount + if(charges <= 0 && dosecharges <= 0) + break + if(charges <= 0 && dosecharges <= 0) + break +#undef DETOXIFIER_EFFECTIVENESS +#undef DETOXIFIER_DOSE_EFFECTIVENESS + diff --git a/code/modules/reagents/chems/chems_nutriment.dm b/code/modules/reagents/chems/chems_nutriment.dm index 7cf7a1508cc5..e1b478c93fab 100644 --- a/code/modules/reagents/chems/chems_nutriment.dm +++ b/code/modules/reagents/chems/chems_nutriment.dm @@ -4,98 +4,63 @@ lore_text = "All the vitamins, minerals, and carbohydrates the body needs in pure form." taste_mult = 4 metabolism = REM * 4 - hidden_from_codex = TRUE // They don't need to generate a codex entry, their recipes will do that. color = "#664330" value = 1.2 fruit_descriptor = "nutritious" - - var/nutriment_factor = 10 // Per unit - var/hydration_factor = 0 // Per unit - var/injectable = 0 - -/decl/material/liquid/nutriment/mix_data(var/datum/reagents/reagents, var/list/newdata, var/newamount) - - if(!islist(newdata) || !newdata.len) - return - - //add the new taste data - var/data = ..() - for(var/taste in newdata) - if(taste in data) - data[taste] += newdata[taste] - else - data[taste] = newdata[taste] - - //cull all tastes below 10% of total - var/totalFlavor = 0 - for(var/taste in data) - totalFlavor += data[taste] - if(totalFlavor) - for(var/taste in data) - if(data[taste]/totalFlavor < 0.1) - data -= taste - . = data - -/decl/material/liquid/nutriment/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - if(!injectable) - M.adjustToxLoss(0.2 * removed) - return - affect_ingest(M, alien, removed, holder) - -/decl/material/liquid/nutriment/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - M.heal_organ_damage(0.5 * removed, 0) //what - - adjust_nutrition(M, alien, removed) - M.add_chemical_effect(CE_BLOODRESTORE, 4 * removed) - -/decl/material/liquid/nutriment/proc/adjust_nutrition(var/mob/living/carbon/M, var/alien, var/removed) - var/nut_removed = removed - var/hyd_removed = removed - if(nutriment_factor) - M.adjust_nutrition(nutriment_factor * nut_removed) // For hunger and fatness - if(hydration_factor) - M.adjust_hydration(hydration_factor * hyd_removed) // For thirst + uid = "chem_nutriment" + exoplanet_rarity_gas = MAT_RARITY_NOWHERE // Please, no more animal protein or glowsap or corn oil atmosphere. + fishing_bait_value = 0.65 + compost_value = 1 + nutriment_factor = 10 + affect_blood_on_ingest = 0 + affect_blood_on_inhale = 0 + opacity = 1.0 // liquids are half transparent by default; meat and etc should not be transparent + + // Technically a room-temperature solid, but saves + // repathing it to /solid all over the codebase. + melting_point = 323 + ignition_point = 353 + boiling_point = 373 + accelerant_value = 0.65 + +/decl/material/liquid/nutriment/Initialize() + solid_name = name // avoid 'frozen sugar' + liquid_name = name // avoid 'molten honey' + return ..() /decl/material/liquid/nutriment/slime_meat name = "slime-meat" lore_text = "Mollusc meat, or slug meat - something slimy, anyway." scannable = 1 taste_description = "cold, bitter slime" - overdose = 10 hydration_factor = 6 + uid = "chem_nutriment_slime" + allergen_flags = ALLERGEN_MEAT | ALLERGEN_FISH /decl/material/liquid/nutriment/glucose name = "glucose" color = "#ffffff" scannable = 1 - injectable = 1 + injectable_nutrition = TRUE + uid = "chem_nutriment_glucose" /decl/material/liquid/nutriment/bread name = "bread" + uid = "chem_nutriment_bread" + allergen_flags = ALLERGEN_GLUTEN /decl/material/liquid/nutriment/bread/cake name = "cake" - -/decl/material/liquid/nutriment/protein - name = "animal protein" - taste_description = "some sort of protein" - color = "#440000" - -/decl/material/liquid/nutriment/protein/adjust_nutrition(var/mob/living/carbon/M, var/alien, var/removed) - M.adjust_nutrition(nutriment_factor * removed) - -/decl/material/liquid/nutriment/protein/egg - name = "egg yolk" - taste_description = "egg" - color = "#ffffaa" + uid = "chem_nutriment_cake" //vegetamarian alternative that is safe for vegans to ingest//rewired it from its intended nutriment/protein/egg/softtofu because it would not actually work, going with plan B, more recipes. - /decl/material/liquid/nutriment/plant_protein name = "plant protein" lore_text = "A gooey pale paste." taste_description = "healthy sadness" color = "#ffffff" + uid = "chem_nutriment_plant" + allergen_flags = ALLERGEN_VEGETABLE /decl/material/liquid/nutriment/honey name = "honey" @@ -104,6 +69,10 @@ nutriment_factor = 10 color = "#ffff00" fruit_descriptor = "rich" + uid = "chem_nutriment_honey" + melting_point = 273 + boiling_point = 373 + opacity = 0.5 /decl/material/liquid/nutriment/flour name = "flour" @@ -112,56 +81,76 @@ nutriment_factor = 1 color = "#ffffff" slipperiness = -1 + uid = "chem_nutriment_flour" + allergen_flags = ALLERGEN_GLUTEN -/decl/material/liquid/nutriment/flour/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) +/decl/material/liquid/nutriment/flour/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) ..() - new /obj/effect/decal/cleanable/flour(T) + new /obj/effect/decal/cleanable/flour(touching_turf) /decl/material/liquid/nutriment/batter name = "batter" + codex_name = "plain batter" lore_text = "A gooey mixture of eggs and flour, a base for turning wheat into food." taste_description = "blandness" nutriment_factor = 3 color = "#ffd592" slipperiness = -1 - -/decl/material/liquid/nutriment/batter/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_batter" + melting_point = 273 + boiling_point = 373 + allergen_flags = ALLERGEN_EGG | ALLERGEN_GLUTEN + +/decl/material/liquid/nutriment/batter/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) ..() - new /obj/effect/decal/cleanable/pie_smudge(T) + new /obj/effect/decal/cleanable/pie_smudge(touching_turf) /decl/material/liquid/nutriment/batter/cakebatter name = "cake batter" + codex_name = null lore_text = "A gooey mixture of eggs, flour and sugar, a important precursor to cake!" taste_description = "sweetness" color = "#ffe992" + uid = "chem_nutriment_cakebatter" + allergen_flags = ALLERGEN_EGG | ALLERGEN_GLUTEN /decl/material/liquid/nutriment/coffee - name = "coffee powder" + name = "ground coffee" lore_text = "A bitter powder made by grinding coffee beans." taste_description = "bitterness" taste_mult = 1.3 nutriment_factor = 1 color = "#482000" fruit_descriptor = "bitter" + uid = "chem_nutriment_coffeepowder" + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT -/decl/material/liquid/nutriment/coffee/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/nutriment/coffee/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) ..() M.add_chemical_effect(CE_PULSE, 2) /decl/material/liquid/nutriment/coffee/instant name = "instant coffee powder" lore_text = "A bitter powder made by processing coffee beans." + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_instantcoffee" /decl/material/liquid/nutriment/tea - name = "tea powder" + name = "tea leaves" lore_text = "A dark, tart powder made from black tea leaves." taste_description = "tartness" taste_mult = 1.3 nutriment_factor = 1 color = "#101000" + uid = "chem_nutriment_teapowder" + allergen_flags = ALLERGEN_CAFFEINE | ALLERGEN_STIMULANT /decl/material/liquid/nutriment/tea/instant name = "instant tea powder" + uid = "chem_nutriment_instanttea" /decl/material/liquid/nutriment/coco name = "coco powder" @@ -171,36 +160,53 @@ nutriment_factor = 5 color = "#302000" fruit_descriptor = "bitter" + uid = "chem_nutriment_cocoa" /decl/material/liquid/nutriment/instantjuice name = "juice concentrate" lore_text = "Dehydrated, powdered juice of some kind." taste_mult = 1.3 nutriment_factor = 1 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_juice" + allergen_flags = ALLERGEN_FRUIT /decl/material/liquid/nutriment/instantjuice/grape name = "grape concentrate" lore_text = "Dehydrated, powdered grape juice." taste_description = "dry grapes" color = "#863333" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_juice_grape" /decl/material/liquid/nutriment/instantjuice/orange name = "orange concentrate" lore_text = "Dehydrated, powdered orange juice." taste_description = "dry oranges" color = "#e78108" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_juice_orange" /decl/material/liquid/nutriment/instantjuice/watermelon name = "watermelon concentrate" lore_text = "Dehydrated, powdered watermelon juice." taste_description = "dry sweet watermelon" color = "#b83333" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_juice_watermelon" /decl/material/liquid/nutriment/instantjuice/apple name = "apple concentrate" lore_text = "Dehydrated, powdered apple juice." taste_description = "dry sweet apples" color = "#c07c40" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_juice_apple" /decl/material/liquid/nutriment/soysauce name = "soy sauce" @@ -209,6 +215,12 @@ taste_mult = 1.1 nutriment_factor = 2 color = "#792300" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_soysauce" + melting_point = 273 + boiling_point = 373 + opacity = 0.5 /decl/material/liquid/nutriment/ketchup name = "ketchup" @@ -216,12 +228,24 @@ taste_description = "ketchup" nutriment_factor = 5 color = "#731008" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_ketchup" + melting_point = 273 + boiling_point = 373 + allergen_flags = ALLERGEN_FRUIT | ALLERGEN_VEGETABLE // Is a tomato a fruit or a vegetable? /decl/material/liquid/nutriment/banana_cream name = "banana cream" lore_text = "A creamy confection that tastes of banana." taste_description = "banana" color = "#f6dfaa" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_bananacream" + melting_point = 273 + boiling_point = 373 + allergen_flags = ALLERGEN_DAIRY | ALLERGEN_FRUIT /decl/material/liquid/nutriment/barbecue name = "barbecue sauce" @@ -229,6 +253,13 @@ taste_description = "barbecue" nutriment_factor = 5 color = "#4f330f" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_bbqsauce" + melting_point = 273 + boiling_point = 373 + allergen_flags = ALLERGEN_FRUIT | ALLERGEN_VEGETABLE // Is a tomato a fruit or a vegetable? + opacity = 0.9 /decl/material/liquid/nutriment/garlicsauce name = "garlic sauce" @@ -236,6 +267,13 @@ taste_description = "garlic" nutriment_factor = 4 color = "#d8c045" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_garlicsauce" + melting_point = 273 + boiling_point = 373 + allergen_flags = ALLERGEN_VEGETABLE + opacity = 0.9 /decl/material/liquid/nutriment/rice name = "rice" @@ -244,14 +282,10 @@ taste_mult = 0.4 nutriment_factor = 1 color = "#ffffff" - -/decl/material/liquid/nutriment/rice/chazuke - name = "chazuke" - lore_text = "Green tea over rice. How rustic!" - taste_description = "green tea and rice" - taste_mult = 0.4 - nutriment_factor = 1 - color = "#f1ffdb" + uid = "chem_nutriment_rice" + reagent_overlay_base = "rice_base" + reagent_overlay = "soup_meatballs" + allergen_flags = ALLERGEN_GLUTEN /decl/material/liquid/nutriment/cherryjelly name = "cherry jelly" @@ -261,15 +295,11 @@ nutriment_factor = 1 color = "#801e28" fruit_descriptor = "sweet" - -/decl/material/liquid/nutriment/cornoil - name = "corn oil" - lore_text = "An oil derived from various types of corn." - taste_description = "slime" - taste_mult = 0.1 - nutriment_factor = 20 - color = "#302000" - slipperiness = 8 + uid = "chem_nutriment_cherryjelly" + melting_point = 273 + boiling_point = 373 + allergen_flags = ALLERGEN_FRUIT + opacity = 0.7 /decl/material/liquid/nutriment/sprinkles name = "sprinkles" @@ -277,6 +307,9 @@ taste_description = "childhood whimsy" nutriment_factor = 1 color = "#ff00ff" + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_sprinkles" /decl/material/liquid/nutriment/sugar name = "sugar" @@ -291,6 +324,7 @@ glass_icon = DRINK_ICON_NOISY fruit_descriptor = "sweet" hidden_from_codex = FALSE + uid = "chem_nutriment_sugar" /decl/material/liquid/nutriment/vinegar name = "vinegar" @@ -298,10 +332,49 @@ taste_description = "vinegar" color = "#e8dfd0" taste_mult = 3 + uid = "chem_nutriment_vinegar" + melting_point = 273 + boiling_point = 373 + opacity = 0.5 /decl/material/liquid/nutriment/mayo name = "mayonnaise" lore_text = "A mixture of egg yolk with lemon juice or vinegar. Usually put on bland food to make it more edible." taste_description = "mayo" color = "#efede8" - taste_mult = 2 \ No newline at end of file + taste_mult = 2 + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + uid = "chem_nutriment_mayonnaise" + allergen_flags = ALLERGEN_EGG + +/decl/material/liquid/nutriment/yeast + name = "yeast" + lore_text = "A collection of live fungal cultures, cultivated across history for use in fermentation and baking." + taste_description = "mustiness" + nutriment_factor = 1 + color = "#d3af70" + uid = "chem_nutriment_yeast" + +/decl/material/liquid/nutriment/cheese + name = "cheese" + lore_text = "Aged, fermented, curdled milk." + uid = "chem_nutriment_cheese" + color = "#ffd000" + allergen_flags = ALLERGEN_DAIRY | ALLERGEN_CHEESE + +/decl/material/liquid/nutriment/butter + name = "butter" + lore_text = "The product of churning cream. Great for baking and on sandwiches." + color = "#ffe864" + taste_description = "butter" + uid = "chem_nutriment_butter" + allergen_flags = ALLERGEN_DAIRY + +/decl/material/liquid/nutriment/margarine + name = "margarine" + lore_text = "Emulsified plant oil solids. A popular non-dairy alternative to butter." + color = "#fff2ab" + taste_description = "bland oiliness" + uid = "chem_nutriment_margarine" + allergen_flags = ALLERGEN_VEGETABLE diff --git a/code/modules/reagents/chems/chems_oil.dm b/code/modules/reagents/chems/chems_oil.dm new file mode 100644 index 000000000000..e540efb9844b --- /dev/null +++ b/code/modules/reagents/chems/chems_oil.dm @@ -0,0 +1,53 @@ +/decl/material/liquid/oil + name = "fuel oil" // paraffin etc + lore_text = "Clarified fuel oil, perfect for fuelling a lantern." + burn_product = /decl/material/gas/carbon_monoxide + ignition_point = T0C+150 + accelerant_value = FUEL_VALUE_ACCELERANT + gas_flags = XGM_GAS_FUEL + melting_point = 273 + boiling_point = 373 + uid = "chem_oil_lamp" + color = "#664330" + value = 1.5 + fishing_bait_value = 0 + taste_mult = 4 + metabolism = REM * 4 + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + affect_blood_on_ingest = 0 + affect_blood_on_inhale = 0 + slipperiness = 8 + coated_adjective = "oily" + +/decl/material/liquid/oil/plant + name = "plant oil" + lore_text = "A thin yellow oil pressed from vegetables or nuts. Useful as fuel, or in cooking." + uid = "chem_oil_plant" + taste_description = "oily blandness" + allergen_flags = ALLERGEN_VEGETABLE + compost_value = 1 + nutriment_factor = 8 + +/decl/material/liquid/oil/plant/corn + name = "corn oil" + lore_text = "An oil derived from various types of corn." + taste_description = "slime" + nutriment_factor = 20 + color = "#302000" + uid = "chem_oil_corn" + taste_mult = 0.1 + +/decl/material/liquid/oil/fish + name = "fish oil" + lore_text = "A pungent yellow oil pressed from fish meat and fish skin. Useful as fuel, or in cooking, or for encouraging recovery after brain injuries." + uid = "chem_oil_fish" + taste_description = "pungent, oily fish" + allergen_flags = ALLERGEN_FISH + compost_value = 1 + nutriment_factor = 6 + +// Copied from neuroannealer; yes, it's silly, but we need a way to treat brain damage on the medieval map. +// Should possibly be an ingredient rather than the be-all end-all medication. +/decl/material/liquid/oil/fish/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() + M.add_chemical_effect(CE_BRAIN_REGEN, 0.5) // Half as effective as neuroannealer, without the side-effects. diff --git a/code/modules/reagents/chems/chems_painkillers.dm b/code/modules/reagents/chems/chems_painkillers.dm index d7f631bdf945..5f35447a5538 100644 --- a/code/modules/reagents/chems/chems_painkillers.dm +++ b/code/modules/reagents/chems/chems_painkillers.dm @@ -1,62 +1,139 @@ - /decl/material/liquid/painkillers - name = "painkillers" - lore_text = "A highly effective opioid painkiller. Do not mix with alcohol." - taste_description = "sourness" - color = "#cb68fc" - overdose = 30 + name = "mild painkillers" + uid = "chem_painkillers" + lore_text = "A mild painkiller, used to treat headaches and other low-grade pain." + taste_description = "bitterness" + color = "#c8a5dc" + overdose = 60 scannable = 1 metabolism = 0.05 ingest_met = 0.02 flags = IGNORE_MOB_SIZE value = 1.8 - var/pain_power = 80 //magnitide of painkilling effect - var/effective_dose = 0.5 //how many units it need to process to reach max power + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + /// Magnitude of painkilling effect + var/pain_power = 35 + /// How many units it need to process to reach max power + var/effective_dose = 0.5 + /// Cumulative dosage at which slowdown and drowsiness are applied + var/additional_effect_threshold = 20 + /// how strong is this chemical as a sedative + var/sedation = 0 + /// how strong will breathloss related effects be + var/breathloss_severity = 1 + var/slowdown_severity = 1.2 + var/blurred_vision = 0.5 + var/stuttering_severity = 0.5 + var/slur_severity = 0 + /// confusion randomizes your movement + var/confusion_severity = 0.2 + /// weakness makes you remain floored + var/weakness_severity = 0 + var/dizziness_severity = 1 + var/narcotic = FALSE + +/decl/material/liquid/painkillers/strong + name = "strong painkillers" + lore_text = "A highly effective opioid painkiller. Do not mix with alcohol." + taste_description = "sourness" + uid = "chem_painkillers_strong" + pain_power = 80 + color = "#cb68fc" + overdose = 30 + narcotic = TRUE -/decl/material/liquid/painkillers/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) - var/volume = REAGENT_VOLUME(holder, type) +/decl/material/liquid/painkillers/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + var/affect_volume = REAGENT_VOLUME(holder, src) + var/dose = CHEM_DOSE(M, src) + . = ..() var/effectiveness = 1 - if(M.chem_doses[type] < effective_dose) //some ease-in ease-out for the effect - effectiveness = M.chem_doses[type]/effective_dose - else if(volume < effective_dose) - effectiveness = volume/effective_dose - M.add_chemical_effect(CE_PAINKILLER, pain_power * effectiveness) - if(M.chem_doses[type] > 0.5 * overdose) - M.add_chemical_effect(CE_SLOWDOWN, 1) - if(prob(1)) - M.slurring = max(M.slurring, 10) - if(M.chem_doses[type] > 0.75 * overdose) - M.add_chemical_effect(CE_SLOWDOWN, 1) - if(prob(5)) - M.slurring = max(M.slurring, 20) - if(M.chem_doses[type] > overdose) - M.add_chemical_effect(CE_SLOWDOWN, 1) - M.slurring = max(M.slurring, 30) - if(prob(1)) - M.Weaken(2) - M.drowsyness = max(M.drowsyness, 5) + if(dose < effective_dose) //some ease-in ease-out for the effect + effectiveness = dose/effective_dose + else if(affect_volume < effective_dose) + effectiveness = affect_volume/effective_dose + + M.add_chemical_effect(CE_PAINKILLER, (pain_power * effectiveness)) + + if(!narcotic) + return + if(dose > 0.5 * additional_effect_threshold) + if(slowdown_severity) + M.add_chemical_effect(CE_SLOWDOWN, slowdown_severity) + if(prob(15) && slur_severity) + SET_STATUS_MAX(M, STAT_SLUR, (slur_severity * 10)) + + if(dose > 0.75 * additional_effect_threshold) //minor side effects may start here + if(slowdown_severity) + M.add_chemical_effect(CE_SLOWDOWN, slowdown_severity) + if(prob(30) && slur_severity) + SET_STATUS_MAX(M, STAT_SLUR, (slur_severity * 20)) + if(prob(30) && dizziness_severity) + SET_STATUS_MAX(M, STAT_DIZZY, (dizziness_severity * 20)) + if(prob(30) && confusion_severity) + SET_STATUS_MAX(M, STAT_CONFUSE, (confusion_severity * 20)) + if(prob(75) && blurred_vision) + SET_STATUS_MAX(M, STAT_BLURRY, (blurred_vision * 20)) + if(prob(30) && stuttering_severity) + SET_STATUS_MAX(M, STAT_STUTTER, (stuttering_severity * 20)) + if(prob(30) && weakness_severity) + SET_STATUS_MAX(M, STAT_WEAK, (weakness_severity * 10)) + if(sedation > 0) + if(prob(20)) + M.add_chemical_effect(CE_SEDATE, (sedation * 1)) + SET_STATUS_MAX(M, STAT_DROWSY, (sedation * 10)) + else + SET_STATUS_MAX(M, STAT_DROWSY, (sedation * 20)) + + if(dose > additional_effect_threshold) //not quite an overdose yet, but it's a lot of medicine to take at once. + if(slowdown_severity) + M.add_chemical_effect(CE_SLOWDOWN, (slowdown_severity * 2)) + SET_STATUS_MAX(M, STAT_BLURRY, (blurred_vision * 40)) + if(prob(75) && slur_severity) + SET_STATUS_MAX(M, STAT_SLUR, (slur_severity * 40)) + if(prob(75) && dizziness_severity) + SET_STATUS_MAX(M, STAT_DIZZY, (dizziness_severity * 40)) + if(prob(75) && confusion_severity) + SET_STATUS_MAX(M, STAT_CONFUSE, (confusion_severity * 40)) + if(prob(75) && stuttering_severity) + SET_STATUS_MAX(M, STAT_STUTTER, (stuttering_severity * 40)) + if(prob(75) && weakness_severity) + SET_STATUS_MAX(M, STAT_WEAK, (weakness_severity * 20)) + if(sedation > 0) + if(prob(50)) //fall asleep + M.add_chemical_effect(CE_SEDATE, (sedation * 1)) + SET_STATUS_MAX(M, STAT_ASLEEP, (sedation * 20)) //is CE_SEDATE and STAT_DROWSY redundant with STAT_ASLEEP? reminder for further testing + SET_STATUS_MAX(M, STAT_DROWSY, (sedation * 40)) + else //stay awake, but immobilized. + SET_STATUS_MAX(M, STAT_WEAK, (weakness_severity * 40)) + SET_STATUS_MAX(M, STAT_DROWSY, (sedation * 40)) + var/boozed = isboozed(M) if(boozed) M.add_chemical_effect(CE_ALCOHOL_TOXIC, 1) - M.add_chemical_effect(CE_BREATHLOSS, 0.1 * boozed) //drinking and opiating makes breathing kinda hard + M.add_chemical_effect(CE_BREATHLOSS, 1 * boozed) //drinking and opiating suppresses breathing. -/decl/material/liquid/painkillers/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) +/decl/material/liquid/painkillers/affect_overdose(mob/living/victim, total_dose) ..() - M.hallucination(120, 30) - M.adjust_drugged(10, 10) - M.add_chemical_effect(CE_PAINKILLER, pain_power*0.5) //extra painkilling for extra trouble - M.add_chemical_effect(CE_BREATHLOSS, 0.6) //Have trouble breathing, need more air - if(isboozed(M)) - M.add_chemical_effect(CE_BREATHLOSS, 0.2) //Don't drink and OD on opiates folks - -/decl/material/liquid/painkillers/proc/isboozed(var/mob/living/carbon/M) + victim.add_chemical_effect(CE_PAINKILLER, pain_power*0.5) //extra painkilling for extra trouble + if(narcotic) + SET_STATUS_MAX(victim, STAT_DRUGGY, 10) + victim.set_hallucination(120, 30) + victim.add_chemical_effect(CE_BREATHLOSS, breathloss_severity*2) //ODing on opiates can be deadly. + if(isboozed(victim)) + victim.add_chemical_effect(CE_BREATHLOSS, breathloss_severity*4) //Don't drink and OD on opiates folks + else + victim.add_chemical_effect(CE_TOXIN, 1) + +/decl/material/liquid/painkillers/proc/isboozed(var/mob/living/M) . = 0 + if(!narcotic) + return var/datum/reagents/ingested = M.get_ingested_reagents() if(ingested) - var/list/pool = M.reagents.reagent_volumes | ingested.reagent_volumes - for(var/rtype in pool) - var/decl/material/liquid/ethanol/booze = decls_repository.get_decl(rtype) - if(!istype(booze) || M.chem_doses[rtype] < 2) //let them experience false security at first + var/list/pool = REAGENT_VOLUMES(M.reagents) | REAGENT_VOLUMES(ingested) + for(var/reagent in pool) + var/decl/material/liquid/alcohol/booze = reagent + if(!istype(booze) ||CHEM_DOSE(M, reagent) < 2) //let them experience false security at first continue . = 1 if(booze.strength < 40) //liquor stuff hits harder diff --git a/code/modules/reagents/chems/chems_pigments.dm b/code/modules/reagents/chems/chems_pigments.dm index d350ac7c78fc..95685fbc3db0 100644 --- a/code/modules/reagents/chems/chems_pigments.dm +++ b/code/modules/reagents/chems/chems_pigments.dm @@ -1,54 +1,102 @@ -/decl/material/pigment +/decl/material/liquid/pigment name = "pigment" - lore_text = "Intensely coloured powder." + lore_text = "Intensely coloured powder." // then why is it a liquid? taste_description = "the back of class" color = "#888888" overdose = 5 hidden_from_codex = TRUE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + opacity = 1.0 + uid = "chem_pigment" -/decl/material/pigment/red +/decl/material/liquid/pigment/red name = "red pigment" color = "#fe191a" + uid = "chem_pigment_red" -/decl/material/pigment/orange +/decl/material/liquid/pigment/orange name = "orange pigment" color = "#ffbe4f" + uid = "chem_pigment_orange" -/decl/material/pigment/yellow +/decl/material/liquid/pigment/yellow name = "yellow pigment" color = "#fdfe7d" + uid = "chem_pigment_yellow" -/decl/material/pigment/green +/decl/material/liquid/pigment/green name = "green pigment" color = "#18a31a" + uid = "chem_pigment_green" -/decl/material/pigment/blue +/decl/material/liquid/pigment/blue name = "blue pigment" color = "#247cff" + uid = "chem_pigment_blue" -/decl/material/pigment/purple +/decl/material/liquid/pigment/purple name = "purple pigment" color = "#cc0099" + uid = "chem_pigment_purple" -/decl/material/pigment/grey //Mime +/decl/material/liquid/pigment/grey //Mime name = "grey pigment" color = "#808080" + uid = "chem_pigment_grey" -/decl/material/pigment/brown //Rainbow +/decl/material/liquid/pigment/brown //Rainbow name = "brown pigment" color = "#846f35" + uid = "chem_pigment_brown" -/decl/material/pigment/grey //Mime +/decl/material/liquid/pigment/grey //Mime name = "grey pigment" color = "#808080" + uid = "chem_pigment_grey" -/decl/material/pigment/black +/decl/material/liquid/pigment/black name = "black pigment" color = "#222222" + uid = "chem_pigment_black" -/decl/material/pigment/white +/decl/material/liquid/pigment/black/ink + name = "ink" + lore_text = "Ink used for writing or dyeing materials, often made from soot or charcoal and some sort of binder." + uid = "chem_ink" + +/decl/material/liquid/pigment/white name = "white pigment" color = "#aaaaaa" + uid = "chem_pigment_white" + +/decl/material/liquid/paint_stripper + name = "paint stripper" + uid = "liquid_paint_remover" + lore_text = "A highly toxic compound used as an effective paint stripper." + taste_description = "bleach and acid" + color = "#a0a0a0" + metabolism = REM * 0.2 + value = 0.1 + solvent_power = MAT_SOLVENT_MODERATE + toxicity = 10 + +/decl/material/liquid/paint_stripper/proc/remove_paint(var/atom/painting, var/datum/reagents/holder) + if(istype(painting) && istype(holder)) + var/keep_alpha = painting.alpha + painting.reset_color() + painting.set_alpha(keep_alpha) + +/decl/material/liquid/paint_stripper/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) + if(istype(touching_turf) && !isspaceturf(touching_turf)) + remove_paint(touching_turf, holder) + +/decl/material/liquid/paint_stripper/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) + if(istype(O)) + remove_paint(O, holder) + +/decl/material/liquid/paint_stripper/touch_mob(var/mob/living/M, var/amount, var/datum/reagents/holder) + if(istype(M)) + remove_paint(M, holder) /decl/material/liquid/paint name = "paint" @@ -57,15 +105,23 @@ color = "#808080" overdose = REAGENTS_OVERDOSE * 0.5 color_weight = 0 + uid = "chem_pigment_paint" + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + +/decl/material/liquid/paint/proc/apply_paint(var/atom/painting, var/datum/reagents/holder, var/threshold = 1) + if(istype(painting) && istype(holder) && REAGENT_VOLUME(holder, src) >= threshold) + var/keep_alpha = painting.alpha + painting.set_color(holder.get_color()) + painting.set_alpha(keep_alpha) -/decl/material/liquid/paint/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) - if(istype(T) && !istype(T, /turf/space)) - T.color = holder.get_color() +/decl/material/liquid/paint/touch_turf(var/turf/touching_turf, var/amount, var/datum/reagents/holder) + if(istype(touching_turf) && !isspaceturf(touching_turf)) + apply_paint(touching_turf, holder, FLUID_MINIMUM_TRANSFER) /decl/material/liquid/paint/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) if(istype(O)) - O.color = holder.get_color() + apply_paint(O, holder, O.get_object_size()) /decl/material/liquid/paint/touch_mob(var/mob/living/M, var/amount, var/datum/reagents/holder) - if(istype(M) && !isobserver(M)) - M.color = holder.get_color() + if(istype(M)) + apply_paint(M, holder, M.get_object_size()) diff --git a/code/modules/reagents/chems/chems_poisons.dm b/code/modules/reagents/chems/chems_poisons.dm index 230e8c50d22a..09bf18e6d357 100644 --- a/code/modules/reagents/chems/chems_poisons.dm +++ b/code/modules/reagents/chems/chems_poisons.dm @@ -6,23 +6,27 @@ metabolism = REM * 0.5 overdose = REAGENTS_OVERDOSE * 0.5 value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_pigment_paralytics" -/decl/material/liquid/paralytics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/paralytics/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) var/threshold = 2 - if(M.chem_doses[type] >= metabolism * threshold * 0.5) - M.confused = max(M.confused, 2) + var/dose = CHEM_DOSE(M, src) + . = ..() + if(dose >= metabolism * threshold * 0.5) + SET_STATUS_MAX(M, STAT_CONFUSE, 2) M.add_chemical_effect(CE_VOICELOSS, 1) - if(M.chem_doses[type] > threshold * 0.5) - M.make_dizzy(3) - M.Weaken(2) - if(M.chem_doses[type] == round(threshold * 0.5, metabolism)) + if(dose > threshold * 0.5) + ADJ_STATUS(M, STAT_DIZZY, 3) + SET_STATUS_MAX(M, STAT_WEAK, 2) + if(dose == round(threshold * 0.5, metabolism)) to_chat(M, SPAN_WARNING("Your muscles slacken and cease to obey you.")) - if(M.chem_doses[type] >= threshold) + if(dose >= threshold) M.add_chemical_effect(CE_SEDATE, 1) - M.eye_blurry = max(M.eye_blurry, 10) + SET_STATUS_MAX(M, STAT_BLURRY, 10) - if(M.chem_doses[type] > 1 * threshold) - M.adjustToxLoss(removed) + if(dose > 1 * threshold) + M.take_damage(removed, TOX) /decl/material/liquid/presyncopics name = "presyncopics" @@ -33,13 +37,16 @@ overdose = REAGENTS_OVERDOSE heating_point = 61 CELSIUS heating_products = list( - /decl/material/solid/potassium = 0.3, - /decl/material/liquid/acetone = 0.3, + /decl/material/solid/potassium = 0.3, + /decl/material/liquid/acetone = 0.3, /decl/material/liquid/nutriment/sugar = 0.4 ) value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_pigment_presyncopics" -/decl/material/liquid/presyncopics/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/presyncopics/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() var/drug_strength = 4 - M.make_dizzy(drug_strength) - M.confused = max(M.confused, drug_strength * 5) + ADJ_STATUS(M, STAT_DIZZY, drug_strength) + SET_STATUS_MAX(M, STAT_CONFUSE, drug_strength * 5) diff --git a/code/modules/reagents/chems/chems_psychiatric.dm b/code/modules/reagents/chems/chems_psychiatric.dm new file mode 100644 index 000000000000..a6f64a93262c --- /dev/null +++ b/code/modules/reagents/chems/chems_psychiatric.dm @@ -0,0 +1,91 @@ +/// This material type has mob effects based on accumulated dose. +/// If the drug has been in your system enough to accumulate a dose, +/// and the level of it in your bloodstream drops below a certain volume, +/// you will get discontinuation effects. +/// If it is above that volume or hasn't been in your system long enough to accumulate, +/// you will get the positive effects. +/decl/material/liquid/accumulated + abstract_type = /decl/material/liquid/accumulated + /// (FLOAT) The dose under which you will receive effects from discontinuation. + var/required_dose = 0.5 + /// (FLOAT) The minimum volume to get the positive effect of this reagent. + var/required_volume = 0.1 + /// (FLOAT) The cooldown between effect triggers. + var/effect_cooldown = 5 MINUTES + +/decl/material/liquid/accumulated/affect_blood(mob/living/victim, removed, datum/reagents/holder) + var/affect_volume = REAGENT_VOLUME(holder, src) + . = ..() + + var/update_data = FALSE + var/list/data = REAGENT_DATA(holder, src) + var/is_off_cooldown = world.time > LAZYACCESS(data, DATA_COOLDOWN_TIME) + effect_cooldown + if(affect_volume <= required_volume && CHEM_DOSE(victim, src) >= required_dose) + update_data = discontinuation_effect(victim, removed, holder, is_off_cooldown) + else + update_data = positive_effect(victim, removed, holder, is_off_cooldown) + + if(update_data) + LAZYSET(data, DATA_COOLDOWN_TIME, world.time) + REAGENT_SET_DATA(holder, type, data) + +/// Returns TRUE to signal that the effect should go on cooldown. +/decl/material/liquid/accumulated/proc/positive_effect(mob/living/victim, removed, datum/reagents/holder, is_off_cooldown) + return FALSE + +/// Returns TRUE to signal that the effect should go on cooldown. +/decl/material/liquid/accumulated/proc/discontinuation_effect(mob/living/victim, removed, datum/reagents/holder, is_off_cooldown) + return FALSE + +/decl/material/liquid/accumulated/stimulants + name = "stimulants" + lore_text = "Improves the ability to concentrate." + taste_description = "sourness" + color = "#bf80bf" + scannable = 1 + metabolism = 0.01 + value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_stimulants" + allergen_flags = ALLERGEN_STIMULANT + +/decl/material/liquid/accumulated/stimulants/positive_effect(mob/living/victim, removed, datum/reagents/holder, is_off_cooldown) + ADJ_STATUS(victim, STAT_DROWSY, -5) + ADJ_STATUS(victim, STAT_PARA, -1) + ADJ_STATUS(victim, STAT_STUN, -1) + ADJ_STATUS(victim, STAT_WEAK, -1) + if(is_off_cooldown) + to_chat(victim, SPAN_NOTICE("Your mind feels focused and undivided.")) + return TRUE + return FALSE + +/decl/material/liquid/accumulated/stimulants/discontinuation_effect(mob/living/victim, removed, datum/reagents/holder, is_off_cooldown) + if(is_off_cooldown) + to_chat(victim, SPAN_WARNING("You lose focus...")) + return TRUE + return FALSE + +/decl/material/liquid/accumulated/antidepressants + name = "antidepressants" + lore_text = "Stabilizes the mind a little." + taste_description = "bitterness" + color = "#ff80ff" + scannable = 1 + metabolism = 0.01 + value = 1.5 + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "chem_antidepressants" + +/decl/material/liquid/accumulated/antidepressants/positive_effect(mob/living/victim, removed, datum/reagents/holder, is_off_cooldown) + victim.add_chemical_effect(CE_MIND, 1) + victim.adjust_hallucination(-10) + if(is_off_cooldown) + to_chat(victim, SPAN_NOTICE("Your mind feels stable... a little stable.")) + return TRUE + return FALSE + +/decl/material/liquid/accumulated/antidepressants/discontinuation_effect(mob/living/victim, removed, datum/reagents/holder, is_off_cooldown) + if(is_off_cooldown) + to_chat(victim, SPAN_WARNING("Your mind feels a little less stable...")) + return TRUE + return FALSE diff --git a/code/modules/reagents/chems/random/chems_random.dm b/code/modules/reagents/chems/random/chems_random.dm index 5df71b35728b..a7418e164642 100644 --- a/code/modules/reagents/chems/random/chems_random.dm +++ b/code/modules/reagents/chems/random/chems_random.dm @@ -1,13 +1,13 @@ // subtypes of stuff in here will be avoided when randomizing interactions. -GLOBAL_LIST_INIT(random_chem_interaction_blacklist, list( +var/global/list/random_chem_interaction_blacklist = list( /decl/material/liquid/adminordrazine, /decl/material/solid/tobacco, /decl/material/liquid/drink, /decl/material/liquid/random, - /decl/material/liquid/ethanol // Includes alcoholic beverages -)) + /decl/material/liquid/alcohol // Includes alcoholic beverages +) #define FOR_ALL_EFFECTS \ var/list/all_effects = decls_repository.get_decls_unassociated(data);\ @@ -18,50 +18,55 @@ GLOBAL_LIST_INIT(random_chem_interaction_blacklist, list( lore_text = "A strange and exotic chemical substance." taste_mult = 0 // Random taste not yet implemented hidden_from_codex = TRUE + uid = "chem_random" var/max_effect_number = 8 var/list/data = list() - var/initialized = FALSE + var/data_initialized = FALSE /decl/material/liquid/random/proc/randomize_data(temperature) data = list() - var/list/effects_to_get = subtypesof(/decl/random_chem_effect/random_properties) + + var/list/effects_to_get = decls_repository.get_decl_paths_of_subtype(/decl/random_chem_effect/random_properties) + effects_to_get = effects_to_get.Copy() if(length(effects_to_get) > max_effect_number) shuffle(effects_to_get) effects_to_get.Cut(max_effect_number + 1) - effects_to_get += subtypesof(/decl/random_chem_effect/general_properties) - + + var/list/general_effects = decls_repository.get_decl_paths_of_subtype(/decl/random_chem_effect/general_properties) + effects_to_get += general_effects + var/list/decls = decls_repository.get_decls_unassociated(effects_to_get) for(var/item in decls) var/decl/random_chem_effect/effect = item effect.prototype_process(src, temperature) - - var/whitelist = subtypesof(/decl/material) - for(var/bad_type in GLOB.random_chem_interaction_blacklist) + + var/list/material_whitelist = decls_repository.get_decl_paths_of_subtype(/decl/material) + var/whitelist = material_whitelist.Copy() + for(var/bad_type in global.random_chem_interaction_blacklist) whitelist -= typesof(bad_type) + var/chill_num = pick(1,2,4) + chilling_point = rand(-100 CELSIUS, T0C) // arbitrary values chilling_products = list() for(var/i in 1 to chill_num) chilling_products[pick_n_take(whitelist)] = 1 / chill_num // it's possible that these form a valid reaction, but we're OK with that. + heating_point = rand(100 CELSIUS, HIGH_SMELTING_HEAT_POINT) // also arbitrary values var/heat_num = pick(1,2,4) heating_products = list() for(var/i in 1 to heat_num) heating_products[pick_n_take(whitelist)] = 1 / heat_num - initialized = TRUE + color = rgb(rand(255), rand(255), rand(255)) -/decl/material/liquid/random/proc/stable_at_temperature(temperature) - if(temperature > chilling_point && temperature < heating_point) - return TRUE + data_initialized = TRUE -/decl/material/liquid/random/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder) +/decl/material/liquid/random/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + . = ..() FOR_ALL_EFFECTS - var/data = REAGENT_DATA(holder, type) - effect.affect_blood(M, alien, removed, LAZYACCESS(data, effect.type)) - -/decl/material/liquid/random/proc/on_chemicals_analyze(mob/user) - to_chat(user, get_scan_data(user)) + var/data = REAGENT_DATA(holder, src) + effect.affect_blood(M, removed, LAZYACCESS(data, effect.type)) /decl/material/liquid/random/proc/get_scan_data(mob/user) var/list/dat = list() @@ -102,6 +107,9 @@ GLOBAL_LIST_INIT(random_chem_interaction_blacklist, list( // Extra unique types for exoplanet spawns, etc. /decl/material/liquid/random/one + uid = "chem_random_one" + /decl/material/liquid/random/two + uid = "chem_random_two" #undef FOR_ALL_EFFECTS \ No newline at end of file diff --git a/code/modules/reagents/chems/random/random_effects.dm b/code/modules/reagents/chems/random/random_effects.dm index 1e510d109550..9136a9577f31 100644 --- a/code/modules/reagents/chems/random/random_effects.dm +++ b/code/modules/reagents/chems/random/random_effects.dm @@ -25,7 +25,7 @@ /decl/random_chem_effect/proc/on_property_recompute(var/decl/material/liquid/random/reagent, var/value) -/decl/random_chem_effect/proc/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/value) +/decl/random_chem_effect/proc/affect_blood(var/mob/living/M, var/removed, var/value) // This is referring to monetary value. /decl/random_chem_effect/proc/get_value(var/value) @@ -45,10 +45,10 @@ mode = RANDOM_CHEM_EFFECT_INT /decl/random_chem_effect/general_properties/name/on_property_recompute(var/decl/material/liquid/random/reagent, var/value) - reagent.name = "[initial(reagent.name)]-[value]" + reagent.name = "[initial(reagent.name)]-[value]" // this is a valid use of initial(reagent.name) since we're resetting it to the base value /decl/random_chem_effect/general_properties/color/get_random_value() - return color_rotation(round(rand(0,360),20)) + return color_matrix_rotate_hue(round(rand(0,360),20)) /decl/random_chem_effect/general_properties/color/on_property_recompute(var/decl/material/liquid/random/reagent, var/value) reagent.color = value @@ -96,7 +96,7 @@ /decl/random_chem_effect/random_properties var/chem_effect_define //If it corresponds to a CE_WHATEVER define, place here and it will do generic affect blood based on it -/decl/random_chem_effect/random_properties/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/value) +/decl/random_chem_effect/random_properties/affect_blood(var/mob/living/M, var/removed, var/value) if(chem_effect_define) M.add_chemical_effect(chem_effect_define, value) @@ -227,15 +227,15 @@ mode = RANDOM_CHEM_EFFECT_INT desc = "acute toxicity" -/decl/random_chem_effect/random_properties/heal_brute/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/value) - M.adjustToxLoss(value * removed) +/decl/random_chem_effect/random_properties/tox_damage/affect_blood(var/mob/living/M, var/removed, var/value) + M.take_damage(value * removed, TOX) /decl/random_chem_effect/random_properties/heal_brute beneficial = 1 maximum = 10 desc = "tissue repair" -/decl/random_chem_effect/random_properties/heal_brute/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/value) +/decl/random_chem_effect/random_properties/heal_brute/affect_blood(var/mob/living/M, var/removed, var/value) M.heal_organ_damage(removed * value, 0) /decl/random_chem_effect/random_properties/heal_burns @@ -243,7 +243,7 @@ maximum = 10 desc = "burn repair" -/decl/random_chem_effect/random_properties/heal_brute/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/value) +/decl/random_chem_effect/random_properties/heal_burns/affect_blood(var/mob/living/M, var/removed, var/value) M.heal_organ_damage(0, removed * value) #undef RANDOM_CHEM_EFFECT_TRUE diff --git a/code/modules/reagents/cocktails.dm b/code/modules/reagents/cocktails.dm index 27d5c6e6f0d7..6a04df74b4e3 100644 --- a/code/modules/reagents/cocktails.dm +++ b/code/modules/reagents/cocktails.dm @@ -1,40 +1,84 @@ // This is a system used to change the name and description of a glass of -// alcohol if it meets certain minimum proportions of ingredients. It +// alcohol if it meets certain minimum proportions of ingredients. It // replaces the previous system, which used chemical reactions. /decl/cocktail - var/name // Cocktail name, applied to the glass. - var/description // Cocktail description, applied to the glass. - var/list/ratios // Associative list of reagents to a minimum percentage of mix (<1). - // Reagents with no assoc value will count as valid for any amount (even 0.001u) - var/order_specific = FALSE // If set, cocktail will fail if ingredients were added out of ratio order. - var/hidden_from_codex // Doesn't generate a codex entry. - -// Shoot for total ratios of about 70% (0.7) for any cocktail that doesn't need -// to be super precise - this will leave room in a mix for people to spike your -// drink or to be comfortably over or under their proportions without having to -// be frustratingly picky with measurements. + abstract_type = /decl/cocktail + /// Cocktail name, applied to the glass. + var/name + /// Cocktail description, applied to the glass. + var/description + /// Associative list of reagents. The actual amount only matters for defining proportions and will be normalized. + /// These should ideally be whole numbers in the lowest possible ratio, e.g. + /// 1, 2, 3 instead of 0.1, 0.2, 0.3 or 2, 4, 6. + /// Reagents with no assoc value will count as valid for any amount (even 0.001u). + var/list/ratios + /// The ratio displayed in the codex, which is the same as ratios prior to normalisation. + var/list/display_ratios + /// If TRUE, cocktail ingredients must be added in the order they're specified in the ratio. + var/order_specific = FALSE + /// If TRUE, doesn't generate a codex entry. + var/hidden_from_codex + /// The icon to use for the cocktail. May be null, in which case no custom icon is used. + var/icon/glass_icon + /// The icon_state to use for the cocktail. May be null, in which case the first state in the icon is used. + var/glass_icon_state + /// A list of types (incl. subtypes) to display this cocktail's glass sprite on. + var/display_types = list(/obj/item/chems/drinks/glass2) + + // Impurity tolerance gives a buffer for imprecise mixing, avoiding finnicky measurements + // and allowing for things like spiked drinks. The default is 0.3, meaning aside from ice, + // the drink can be at most 30% other reagents not part of the cocktail recipe. + + /// What fraction of the total volume of the drink (ignoring ice) can be unrelated chems? + var/impurity_tolerance = 0.3 + + /// What tastes (and associated strengths) this cocktail adds. Scaled in taste code by total_volume. + /// Example: list("something funny" = 0.5) + /// Consider using a total strength proportional to the number of ingredients, i.e. 0.25 for 4 ingredients, 0.5 for 2, etc. + var/list/tastes = null + +/decl/cocktail/Initialize() + . = ..() + // Normalize the ratios to ensure a specific degree of tolerance. + if(ratios) + display_ratios = ratios.Copy() // Copy the initial ratio to use for the codex. + var/ratio_wiggle_room = (1-impurity_tolerance) + var/ratio_sum = 0 + for(var/r in ratios) + ratio_sum += ratios[r] + for(var/r in ratios) + ratios[r] *= ratio_wiggle_room / ratio_sum + // Normalize the tastes to be relative to the number of ingredients. + // This lets you roughly reason about the strength of the taste + // of the cocktail relative to its ingredients' tastes. + for(var/t in tastes) + tastes[t] /= length(ratios) /decl/cocktail/proc/get_presentation_name(var/obj/item/prop) . = name if(prop?.reagents?.has_reagent(/decl/material/solid/ice) && !(/decl/material/solid/ice in ratios)) . = "[name], on the rocks" +/decl/cocktail/proc/get_presentation_desc(var/obj/item/prop) + . = description + // placeholder for future functionality (vapor/fizz/etc. descriptions) + /decl/cocktail/proc/mix_priority() . = length(ratios) /decl/cocktail/proc/matches(var/obj/item/prop) - if(length(ratios) > length(prop.reagents.reagent_volumes)) + if(length(ratios) > length(REAGENT_VOLUMES(prop.reagents))) return FALSE var/list/check_ratios var/i = 0 for(var/rtype in ratios) i++ - if(!prop.reagents.has_reagent(rtype) || (order_specific && prop.reagents.reagent_volumes[i] != rtype)) + if(!prop.reagents.has_reagent(rtype) || (order_specific && REAGENT_VOLUME(prop.reagents, i) != rtype)) return FALSE if(isnum(ratios[rtype])) LAZYSET(check_ratios, rtype, ratios[rtype]) - var/effective_volume = prop.reagents.total_volume + var/effective_volume = REAGENT_TOTAL_VOLUME(prop.reagents) if(!(/decl/material/solid/ice in ratios)) effective_volume -= REAGENT_VOLUME(prop.reagents, /decl/material/solid/ice) for(var/rtype in check_ratios) @@ -42,224 +86,240 @@ return FALSE return TRUE +/decl/cocktail/proc/has_sprite(obj/item/prop) + // assumes we match, checks if we have (compatible) sprites + return !(isnull(glass_icon) || isnull(glass_icon_state)) + +/decl/cocktail/proc/can_use_sprite(obj/item/prop) + // assume we already match; just check types + return is_type_in_list(prop, display_types) + +/decl/cocktail/validate() + . = ..() + if(!length(ratios)) + . += "no ratios defined for cocktail" + /decl/cocktail/grog name = "grog" description = "Watered-down rum. Pirate approved!" ratios = list( - /decl/material/liquid/water = 0.5, - /decl/material/liquid/ethanol/rum = 0.2 + /decl/material/liquid/water = 1, + /decl/material/liquid/alcohol/rum = 1 ) /decl/cocktail/screwdriver name = "screwdriver" description = "A classic mixture of vodka and orange juice. Just the thing for the tired engineer." ratios = list( - /decl/material/liquid/drink/juice/orange = 0.6, - /decl/material/liquid/ethanol/vodka = 0.1 + /decl/material/liquid/drink/juice/orange = 4, + /decl/material/liquid/alcohol/vodka = 1 ) -/decl/cocktail/tequilla_sunrise - name = "tequilla sunrise" - description = "A simple cocktail of tequilla and orange juice. Much like a screwdriver." +/decl/cocktail/tequila_sunrise + name = "tequila sunrise" + description = "A simple cocktail of tequila and orange juice. Much like a screwdriver." ratios = list( - /decl/material/liquid/drink/juice/orange = 0.6, - /decl/material/liquid/ethanol/tequilla = 0.1 + /decl/material/liquid/drink/juice/orange = 4, + /decl/material/liquid/alcohol/tequila = 1 ) /decl/cocktail/classic_martini - name = "martini" + name = "gin martini" description = "Vermouth with gin. The classiest of all cocktails." ratios = list( - /decl/material/liquid/ethanol/gin = 0.4, - /decl/material/liquid/ethanol/vermouth = 0.3 + /decl/material/liquid/alcohol/gin = 4, + /decl/material/liquid/alcohol/vermouth = 1 ) /decl/cocktail/vodka_martini name = "vodka martini" description = "A bastardisation of the classic martini. Still great." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.4, - /decl/material/liquid/ethanol/vermouth = 0.3 + /decl/material/liquid/alcohol/vodka = 4, + /decl/material/liquid/alcohol/vermouth = 1 ) /decl/cocktail/allies_cocktail name = "Allies Cocktail" description = "A drink made from your allies, not as sweet as when made from your enemies." ratios = list( - /decl/material/liquid/ethanol/vermouth = 0.3, - /decl/material/liquid/ethanol/vodka = 0.1, - /decl/material/liquid/ethanol/gin = 0.3 + /decl/material/liquid/alcohol/vermouth = 2, + /decl/material/liquid/alcohol/vodka = 2, + /decl/material/liquid/alcohol/gin = 2 ) /decl/cocktail/bilk name = "bilk" description = "A foul brew of milk and beer. For alcoholics who fear osteoporosis." ratios = list( - /decl/material/liquid/ethanol/beer = 0.35, - /decl/material/liquid/drink/milk = 0.35 + /decl/material/liquid/alcohol/beer = 1, + /decl/material/liquid/drink/milk = 1 ) /decl/cocktail/gin_and_tonic name = "gin and tonic" description = "A mild cocktail, widely considered an all-time classic." ratios = list( - /decl/material/liquid/drink/tonic = 0.4, - /decl/material/liquid/ethanol/gin = 0.3 + /decl/material/liquid/drink/tonic = 4, + /decl/material/liquid/alcohol/gin = 1 ) /decl/cocktail/cuba_libre name = "Cuba Libre" description = "A classic mix of rum and cola." ratios = list( - /decl/material/liquid/ethanol/rum = 0.2, - /decl/material/liquid/drink/cola = 0.5 + /decl/material/liquid/drink/cola = 4, + /decl/material/liquid/alcohol/rum = 1 ) /decl/cocktail/black_russian name = "black Russian" description = "Similar to a white Russian, but fit for the lactose-intolerant." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.4, - /decl/material/liquid/ethanol/coffee/kahlua = 0.2 + /decl/material/liquid/alcohol/vodka = 2, + /decl/material/liquid/alcohol/coffee = 1 ) /decl/cocktail/white_russian name = "white Russian" description = "A straightforward cocktail of coffee liqueur and vodka. Popular in a lot of places, but that's just, like, an opinion, man." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.3, - /decl/material/liquid/ethanol/coffee/kahlua = 0.15, - /decl/material/liquid/drink/milk/cream = 0.15 + /decl/material/liquid/alcohol/coffee = 2, + /decl/material/liquid/drink/milk/cream, + /decl/material/liquid/alcohol/vodka = 1 ) /decl/cocktail/whiskey_cola name = "whiskey cola" description = "Whiskey mixed with cola. Quite refreshing." ratios = list( - /decl/material/liquid/ethanol/whiskey = 0.2, - /decl/material/liquid/drink/cola = 0.5 + /decl/material/liquid/drink/cola = 4, + /decl/material/liquid/alcohol/whiskey = 1 ) /decl/cocktail/bloody_mary name = "Bloody Mary" description = "A cocktail of vodka, tomato and lime juice. Celery stalk optional." ratios = list( - /decl/material/liquid/drink/juice/tomato = 0.4, - /decl/material/liquid/ethanol/vodka = 0.15, - /decl/material/liquid/drink/juice/lime = 0.15 + /decl/material/liquid/drink/juice/tomato = 3, + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/drink/juice/lime = 1 ) /decl/cocktail/livergeist name = "The Livergeist" description = "A cocktail pioneered by a small cabal with a vendetta against the liver. Drink very carefully." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.1, - /decl/material/liquid/ethanol/gin = 0.1, - /decl/material/liquid/ethanol/aged_whiskey = 0.1, - /decl/material/liquid/ethanol/cognac = 0.1, - /decl/material/liquid/drink/juice/lime = 0.1 + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/alcohol/gin = 1, + /decl/material/liquid/alcohol/aged_whiskey = 1, + /decl/material/liquid/alcohol/cognac = 1, + /decl/material/liquid/drink/juice/lime = 1 ) /decl/cocktail/brave_bull name = "Brave Bull" description = "A strong cocktail of tequila and coffee liquor." ratios = list( - /decl/material/liquid/ethanol/tequilla = 0.45, - /decl/material/liquid/ethanol/coffee/kahlua = 0.25 + /decl/material/liquid/alcohol/tequila = 2, + /decl/material/liquid/alcohol/coffee = 1 ) /decl/cocktail/toxins_special - name = "H2 Special" + name = "Toxins Special" description = "Raise a glass to the bomb technicians of yesteryear, wherever their ashes now reside." ratios = list( - /decl/material/liquid/ethanol/rum = 0.35, - /decl/material/liquid/ethanol/vermouth = 0.35, + /decl/material/liquid/alcohol/rum = 1, + /decl/material/liquid/alcohol/vermouth = 1, /decl/material/solid/metallic_hydrogen ) /decl/cocktail/beepsky_smash name = "Beepsky Smash" - description = "A cocktail originating with stationside security forces. Rumoured to take the edge off being stunned with your own baton." + description = "A cocktail originating with station-side security forces. Rumoured to take the edge off being stunned with your own baton." ratios = list( - /decl/material/liquid/ethanol/whiskey = 0.4, - /decl/material/liquid/drink/juice/lime = 0.2, - /decl/material/solid/metal/iron = 0.1 + /decl/material/liquid/alcohol/whiskey = 2, + /decl/material/liquid/drink/juice/lime = 1, + /decl/material/solid/metal/iron ) /decl/cocktail/doctor_delight name = "Doctor's Delight" description = "A healthy mixture of juices and medication, guaranteed to keep you healthy until the next maintenance goblin decides to put a few new holes in you." ratios = list( - /decl/material/liquid/regenerator = 0.3, - /decl/material/liquid/drink/juice/lime = 0.1, - /decl/material/liquid/drink/juice/tomato = 0.1, - /decl/material/liquid/drink/juice/orange = 0.1, - /decl/material/liquid/drink/milk/cream = 0.1 + /decl/material/liquid/regenerator = 3, + /decl/material/liquid/drink/juice/lime = 1, + /decl/material/liquid/drink/juice/tomato = 1, + /decl/material/liquid/drink/juice/orange = 1, + /decl/material/liquid/drink/milk/cream ) /decl/cocktail/manly_dorf name = "The Manly Dorf" description = "A cocktail of old that claims to be for manly men, but is mostly for people who can't tell beer and ale apart." ratios = list( - /decl/material/liquid/ethanol/ale = 0.35, - /decl/material/liquid/ethanol/beer = 0.35 + /decl/material/liquid/alcohol/ale = 1, + /decl/material/liquid/alcohol/beer = 1 ) /decl/cocktail/irish_coffee name = "Irish coffee" description = "A cocktail of coffee, whiskey and cream, just the thing to kick you awake while also dulling the pain of existence." ratios = list( - /decl/material/liquid/drink/coffee = 0.5, - /decl/material/liquid/ethanol/irish_cream = 0.2 + /decl/material/liquid/drink/coffee = 4, + /decl/material/liquid/alcohol/irish_cream = 1 ) /decl/cocktail/b52 name = "B-52" description = "A semi-modern spin on an Irish coffee, featuring a dash of cognac. It will get you bombed." ratios = list( - /decl/material/liquid/ethanol/cognac = 0.3, - /decl/material/liquid/ethanol/irish_cream = 0.2, - /decl/material/liquid/ethanol/coffee/kahlua = 0.2 + /decl/material/liquid/alcohol/coffee = 1, + /decl/material/liquid/alcohol/irish_cream = 1, + /decl/material/liquid/alcohol/cognac = 1 ) + order_specific = TRUE // layered cocktail /decl/cocktail/atomicbomb name = "Atomic Bomb" description = "A radioactive take on a B-52, popularized by asteroid miners with prosthetic organs and something to prove." ratios = list( - /decl/material/liquid/ethanol/cognac = 0.3, - /decl/material/liquid/ethanol/irish_cream = 0.2, - /decl/material/liquid/ethanol/coffee/kahlua = 0.2, + /decl/material/liquid/alcohol/coffee = 1, + /decl/material/liquid/alcohol/irish_cream = 1, + /decl/material/liquid/alcohol/cognac = 1, /decl/material/solid/metal/uranium ) + order_specific = TRUE // layered cocktail +// todo: consider creating clear curacao for this /decl/cocktail/margarita name = "margarita" description = "A classic cocktail of antiquity." ratios = list( - /decl/material/liquid/ethanol/tequilla = 0.35, - /decl/material/liquid/drink/juice/lime = 0.35 + /decl/material/liquid/alcohol/tequila = 3, + /decl/material/liquid/drink/juice/lime = 1 ) /decl/cocktail/longislandicedtea name = "Long Island Iced Tea" description = "Most of the liquor cabinet, brought together in a delicious mix. Designed for middle-aged alcoholics." ratios = list( - /decl/material/liquid/drink/cola = 0.2, - /decl/material/liquid/ethanol/rum = 0.1, - /decl/material/liquid/ethanol/vodka = 0.1, - /decl/material/liquid/ethanol/gin = 0.1, - /decl/material/liquid/ethanol/tequilla = 0.1 + /decl/material/liquid/drink/cola = 2, + /decl/material/liquid/alcohol/rum = 1, + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/alcohol/gin = 1, + /decl/material/liquid/alcohol/tequila = 1 ) /decl/cocktail/threemileisland name = "Three Mile Island Iced Tea" description = "Much like the Atomic Bomb, this cocktail was adapted by asteroid miners who couldn't enjoy a drink without a dose of radiation poisoning." ratios = list( - /decl/material/liquid/drink/cola = 0.2, - /decl/material/liquid/ethanol/rum = 0.1, - /decl/material/liquid/ethanol/vodka = 0.1, - /decl/material/liquid/ethanol/gin = 0.1, - /decl/material/liquid/ethanol/tequilla = 0.1, + /decl/material/liquid/drink/cola = 2, + /decl/material/liquid/alcohol/rum = 1, + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/alcohol/gin = 1, + /decl/material/liquid/alcohol/tequila = 1, /decl/material/solid/metal/uranium ) @@ -267,24 +327,24 @@ name = "whiskey soda" description = "A simple cocktail, considered to be cultured and refined." ratios = list( - /decl/material/liquid/ethanol/whiskey = 0.25, - /decl/material/liquid/drink/sodawater = 0.45 + /decl/material/liquid/drink/sodawater = 4, + /decl/material/liquid/alcohol/whiskey = 1 ) /decl/cocktail/manhattan name = "Manhattan" description = "Another classic cocktail of antiquity. Popular with private investigators." ratios = list( - /decl/material/liquid/ethanol/whiskey = 0.45, - /decl/material/liquid/ethanol/vermouth = 0.25 + /decl/material/liquid/alcohol/whiskey = 2, + /decl/material/liquid/alcohol/vermouth = 1 ) /decl/cocktail/manhattan_proj name = "Manhattan Project" description = "A classic cocktail with a spicy twist, pioneered by a robot detective." ratios = list( - /decl/material/liquid/ethanol/whiskey = 0.45, - /decl/material/liquid/ethanol/vermouth = 0.25, + /decl/material/liquid/alcohol/whiskey = 2, + /decl/material/liquid/alcohol/vermouth = 1, /decl/material/solid/metal/uranium ) @@ -292,35 +352,35 @@ name = "vodka and tonic" description = "A simple, refreshing cocktail with a kick to it." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.2, - /decl/material/liquid/drink/tonic = 0.5 + /decl/material/liquid/drink/tonic = 4, + /decl/material/liquid/alcohol/vodka = 1 ) /decl/cocktail/gin_fizz name = "gin fizz" description = "A dry, refreshing cocktail with a tang of lime." ratios = list( - /decl/material/liquid/ethanol/gin = 0.3, - /decl/material/liquid/drink/sodawater = 0.2, - /decl/material/liquid/drink/juice/lime = 0.2 + /decl/material/liquid/alcohol/gin = 2, + /decl/material/liquid/drink/sodawater = 2, + /decl/material/liquid/drink/juice/lime = 1 ) /decl/cocktail/bahama_mama name = "Bahama Mama" description = "A sweet tropical cocktail that is deceptively strong." ratios = list( - /decl/material/liquid/ethanol/rum = 0.2, - /decl/material/liquid/drink/juice/orange = 0.2, - /decl/material/liquid/drink/juice/lime = 0.2, - /decl/material/liquid/drink/grenadine = 0.1 + /decl/material/liquid/alcohol/rum = 2, + /decl/material/liquid/drink/juice/orange = 2, + /decl/material/liquid/drink/juice/lime = 2, + /decl/material/liquid/drink/grenadine = 1 ) /decl/cocktail/singulo name = "Singulo" description = "Traditionally thrown together from maintenance stills and used to treat singularity exposure in engineers who forgot their meson goggles." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.35, - /decl/material/liquid/ethanol/wine = 0.35, + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/alcohol/wine = 1, /decl/material/solid/metal/radium ) @@ -328,180 +388,182 @@ name = "Demon's Blood" description = "A ghoulish cocktail that originated as a practical joke in a fringe habitat." ratios = list( - /decl/material/liquid/ethanol/rum = 0.2, - /decl/material/liquid/drink/citrussoda = 0.2, - /decl/material/liquid/blood = 0.1, - /decl/material/liquid/drink/cherrycola = 0.2 + /decl/material/liquid/alcohol/rum = 2, + /decl/material/liquid/drink/citrussoda = 2, + /decl/material/liquid/drink/cherrycola = 2, + /decl/material/liquid/blood = 1 ) /decl/cocktail/booger name = "Booger" description = "A thick and creamy cocktail." ratios = list( - /decl/material/liquid/drink/milk/cream = 0.2, - /decl/material/liquid/drink/juice/banana = 0.15, - /decl/material/liquid/ethanol/rum = 0.2, - /decl/material/liquid/drink/juice/watermelon = 0.15 + /decl/material/liquid/drink/milk/cream = 2, + /decl/material/liquid/alcohol/rum = 2, + /decl/material/liquid/drink/juice/banana = 1, + /decl/material/liquid/drink/juice/watermelon = 1 ) /decl/cocktail/antifreeze name = "Anti-freeze" description = "A chilled cocktail invented and popularized by corona miners." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.3, - /decl/material/liquid/drink/milk/cream = 0.2, - /decl/material/solid/ice = 0.2 + /decl/material/liquid/alcohol/vodka = 3, + /decl/material/liquid/drink/milk/cream = 2, + /decl/material/solid/ice = 2 ) /decl/cocktail/barefoot name = "Barefoot" description = "A smooth cocktail that will take your mind off the broken glass you stepped on." ratios = list( - /decl/material/liquid/ethanol/vermouth = 0.4, - /decl/material/liquid/drink/juice/berry = 0.2, - /decl/material/liquid/drink/milk/cream = 0.1 + /decl/material/liquid/alcohol/vermouth = 4, + /decl/material/liquid/drink/juice/berry = 2, + /decl/material/liquid/drink/milk/cream = 1 ) /decl/cocktail/sbiten name = "sbiten" description = "A form of spiced mead that will bring tears to the eyes of the most hardened drinker." ratios = list( - /decl/material/liquid/ethanol/mead = 0.6, - /decl/material/liquid/capsaicin = 0.1 + /decl/material/liquid/alcohol/mead = 9, + /decl/material/liquid/capsaicin = 1 ) /decl/cocktail/red_mead name = "red mead" description = "Supposedly a traditional drink amongst mercenary groups prior to dangerous missions." ratios = list( - /decl/material/liquid/ethanol/mead = 0.6, - /decl/material/liquid/blood = 0.1 + /decl/material/liquid/alcohol/mead = 1, + /decl/material/liquid/blood = 1 ) /decl/cocktail/acidspit name = "Acid Spit" description = "A cocktail inspired by monsters of legend, popular with college students daring their friends to drink one." ratios = list( - /decl/material/liquid/ethanol/wine = 0.7, + /decl/material/liquid/alcohol/wine = 1, /decl/material/liquid/acid ) +// A screwdriver, with half the mixer replaced with other citrus juices. /decl/cocktail/changelingsting name = "Changeling Sting" description = "A deceptively simple cocktail with a complex flavour profile. Rumours of causing paralysis and voice loss are common but unsubstantiated." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.4, - /decl/material/liquid/drink/juice/lime = 0.1, - /decl/material/liquid/drink/juice/lemon = 0.1, - /decl/material/liquid/drink/juice/orange = 0.1 + /decl/material/liquid/drink/juice/orange = 2, + /decl/material/liquid/drink/juice/lime = 1, + /decl/material/liquid/drink/juice/lemon = 1, + /decl/material/liquid/alcohol/vodka = 1 ) /decl/cocktail/neurotoxin name = "Neurotoxin" description = "A cocktail primarily intended for people with a grudge against their own brain." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.1, - /decl/material/liquid/ethanol/gin = 0.1, - /decl/material/liquid/ethanol/aged_whiskey = 0.1, - /decl/material/liquid/ethanol/cognac = 0.1, - /decl/material/liquid/drink/juice/lime = 0.1, - /decl/material/liquid/sedatives = 0.1 + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/alcohol/gin = 1, + /decl/material/liquid/alcohol/aged_whiskey = 1, + /decl/material/liquid/alcohol/cognac = 1, + /decl/material/liquid/drink/juice/lime = 1, + /decl/material/liquid/sedatives ) /decl/cocktail/snowwhite name = "Snow White" description = "A tangy, fizzy twist on beer." ratios = list( - /decl/material/liquid/ethanol/beer = 0.4, - /decl/material/liquid/drink/lemon_lime = 0.3 + /decl/material/liquid/drink/lemon_lime = 3, + /decl/material/liquid/alcohol/beer = 1 ) /decl/cocktail/irishslammer name = "Irish Slammer" description = "A rich cocktail of whiskey, stout and cream that was performed using a shot glass before glass-interleaving technology was lost." ratios = list( - /decl/material/liquid/ethanol/ale = 0.5, - /decl/material/liquid/ethanol/whiskey = 0.1, - /decl/material/liquid/ethanol/irish_cream = 0.1 + /decl/material/liquid/alcohol/ale = 5, + /decl/material/liquid/alcohol/whiskey = 1, + /decl/material/liquid/alcohol/irish_cream = 1 ) +// A whiskey cola with added beer. /decl/cocktail/syndicatebomb name = "Syndicate Bomb" description = "A murky cocktail reputed to have originated in criminal circles. It will definitely get you bombed." ratios = list( - /decl/material/liquid/ethanol/whiskey = 0.2, - /decl/material/liquid/ethanol/beer = 0.2, - /decl/material/liquid/drink/cola = 0.3 + /decl/material/liquid/alcohol/whiskey = 1, + /decl/material/liquid/alcohol/beer = 1, + /decl/material/liquid/drink/cola = 4 ) /decl/cocktail/devilskiss name = "Devil's Kiss" description = "A ghoulish cocktail popular in some of the weirder dive bars on the system fringe." ratios = list( - /decl/material/liquid/ethanol/rum = 0.4, - /decl/material/liquid/blood = 0.1, - /decl/material/liquid/ethanol/coffee/kahlua = 0.2 + /decl/material/liquid/alcohol/rum = 4, + /decl/material/liquid/blood = 1, + /decl/material/liquid/alcohol/coffee = 2 ) /decl/cocktail/hippiesdelight name = "Hippy's Delight" description = "A complex cocktail that just might open your third eye." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.1, - /decl/material/liquid/ethanol/gin = 0.1, - /decl/material/liquid/ethanol/aged_whiskey = 0.1, - /decl/material/liquid/ethanol/cognac = 0.1, - /decl/material/liquid/drink/juice/lime = 0.1, - /decl/material/liquid/psychotropics = 0.2 + /decl/material/liquid/alcohol/vodka = 1, + /decl/material/liquid/alcohol/gin = 1, + /decl/material/liquid/alcohol/aged_whiskey = 1, + /decl/material/liquid/alcohol/cognac = 1, + /decl/material/liquid/drink/juice/lime = 1, + /decl/material/liquid/psychotropics = 2 ) /decl/cocktail/bananahonk name = "Banana Honk" description = "A virgin cocktail intended for the class clown. If someone orders you one of these, it is probably an insult." ratios = list( - /decl/material/liquid/drink/juice/banana = 0.4, - /decl/material/liquid/drink/milk/cream = 0.2, - /decl/material/liquid/nutriment/sugar = 0.1 + /decl/material/liquid/drink/juice/banana = 4, + /decl/material/liquid/drink/milk/cream = 2, + /decl/material/liquid/nutriment/sugar = 1 ) /decl/cocktail/ships_surgeon name = "Ship's Surgeon" description = "A smooth, steady cocktail supposedly ordered by sawbones and surgeons of legend." ratios = list( - /decl/material/liquid/drink/cherrycola = 0.5, - /decl/material/liquid/ethanol/rum = 0.2 + /decl/material/liquid/drink/cherrycola = 4, + /decl/material/liquid/alcohol/rum = 2 ) /decl/cocktail/vodkacola name = "vodka cola" description = "A simple mix of cola and vodka, combining sweetness, fizz and a kick in the teeth." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.5, - /decl/material/liquid/drink/cola = 0.2 + /decl/material/liquid/drink/cola = 2, + /decl/material/liquid/alcohol/vodka = 1 ) /decl/cocktail/sawbonesdismay name = "Sawbones' Dismay" description = "Legally, we are required to inform you that drinking this cocktail may invalidate your health insurance." ratios = list( - /decl/material/liquid/ethanol/jagermeister = 0.35, - /decl/material/liquid/drink/beastenergy = 0.35 + /decl/material/liquid/alcohol/jagermeister = 1, + /decl/material/liquid/drink/beastenergy = 1 ) /decl/cocktail/patron name = "Patron" description = "Tequila mixed with flaked silver, for those with moderate expensive tastes." ratios = list( - /decl/material/liquid/ethanol/tequilla = 0.7, + /decl/material/liquid/alcohol/tequila = 1, /decl/material/solid/metal/silver ) /decl/cocktail/rewriter name = "Rewriter" - description = "A sickly concotion that college students and academics swear by for getting you through an all-nighter or six." + description = "A sickly concoction that college students and academics swear by for getting you through an all-nighter or six." ratios = list( - /decl/material/liquid/drink/coffee = 0.35, - /decl/material/liquid/drink/citrussoda = 0.35 + /decl/material/liquid/drink/coffee = 1, + /decl/material/liquid/drink/citrussoda = 1 ) // TODO: add schnapps @@ -509,7 +571,7 @@ name = "Goldschlager" description = "Schnapps mixed with flaked gold, for those with very expensive tastes." ratios = list( - /decl/material/liquid/ethanol/vodka = 0.7, + /decl/material/liquid/alcohol/vodka = 1, /decl/material/solid/metal/gold ) @@ -517,23 +579,23 @@ name = "Brown Dwarf" description = "A foamy chocolate beverage that has failed to sustain nuclear fusion." ratios = list( - /decl/material/liquid/drink/hot_coco = 0.4, - /decl/material/liquid/drink/citrussoda = 0.3 + /decl/material/liquid/drink/hot_coco = 2, + /decl/material/liquid/drink/citrussoda = 1 ) /decl/cocktail/snowball name = "Snowball" description = "A cold pick-me-up frequently drunk in scientific outposts and academic offices." ratios = list( - /decl/material/solid/ice = 0.3, - /decl/material/liquid/drink/coffee = 0.2, - /decl/material/liquid/drink/juice/watermelon = 0.2 + /decl/material/solid/ice = 3, + /decl/material/liquid/drink/coffee = 2, + /decl/material/liquid/drink/juice/watermelon = 1 ) /decl/cocktail/fools_gold name = "Fool's Gold" description = "Watered-down whiskey. Essentially grog, but without the pirates." ratios = list( - /decl/material/liquid/water = 0.5, - /decl/material/liquid/ethanol/whiskey = 0.2 + /decl/material/liquid/water = 1, + /decl/material/liquid/alcohol/whiskey = 1 ) diff --git a/code/modules/reagents/dispenser/cartridge.dm b/code/modules/reagents/dispenser/cartridge.dm index 94111a7c578e..daee57f2381d 100644 --- a/code/modules/reagents/dispenser/cartridge.dm +++ b/code/modules/reagents/dispenser/cartridge.dm @@ -3,94 +3,83 @@ desc = "This goes in a chemical dispenser." icon = 'icons/obj/items/chem/chem_cartridge.dmi' icon_state = "cartridge" - w_class = ITEM_SIZE_NORMAL - - volume = CARTRIDGE_VOLUME_LARGE + chem_volume = CARTRIDGE_VOLUME_LARGE amount_per_transfer_from_this = 50 + material = /decl/material/solid/stone/ceramic // Large, but inaccurate. Use a chem dispenser or beaker for accuracy. possible_transfer_amounts = @"[50,100]" - unacidable = 1 + var/_reagent_label - var/spawn_reagent = null - var/label = "" +/obj/item/chems/chem_disp_cartridge/Serialize() + . = ..() + SERIALIZE_IF_MODIFIED(_reagent_label, /obj/item/chems/chem_disp_cartridge) -/obj/item/chems/chem_disp_cartridge/Initialize() +/obj/item/chems/chem_disp_cartridge/Initialize(ml, material_key) . = ..() - if(spawn_reagent) - reagents.add_reagent(spawn_reagent, volume) - var/decl/material/R = spawn_reagent - setLabel(initial(R.name)) + var/decl/material/primary_reagent = istype(reagents) && reagents.get_primary_reagent_decl() + if(primary_reagent && isnull(_reagent_label)) + _reagent_label = primary_reagent.name + if(_reagent_label) + setLabel(_reagent_label) -/obj/item/chems/chem_disp_cartridge/examine(mob/user) +/obj/item/chems/chem_disp_cartridge/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It has a capacity of [volume] units.") - if(reagents.total_volume <= 0) - to_chat(user, "It is empty.") + . += "It has a capacity of [REAGENT_MAXIMUM_VOLUME(reagents)] unit\s." + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + . += "It is empty." else - to_chat(user, "It contains [reagents.total_volume] units of liquid.") + . += "It contains [REAGENT_TOTAL_VOLUME(reagents)] unit\s of reagents." if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "The cap is sealed.") + . += "The cap is sealed." /obj/item/chems/chem_disp_cartridge/verb/verb_set_label(L as text) set name = "Set Cartridge Label" set category = "Object" set src in view(usr, 1) - setLabel(L, usr) + var/datum/extension/labels/lext = get_or_create_extension(src, /datum/extension/labels) + if(lext) + for(var/lab in lext.labels) + lext.RemoveLabel(null, lab) + if(length(L)) + lext.AttachLabel(null, L) /obj/item/chems/chem_disp_cartridge/proc/setLabel(L, mob/user = null) - if(L) - if(user) - to_chat(user, "You set the label on \the [src] to '[L]'.") - - label = L - SetName("[initial(name)] - '[L]'") - else - if(user) - to_chat(user, "You clear the label on \the [src].") - label = "" - SetName(initial(name)) - -/obj/item/chems/chem_disp_cartridge/attack_self() - ..() + var/datum/extension/labels/lext = get_or_create_extension(src, /datum/extension/labels) + if(lext) + for(var/lab in lext.labels) + lext.RemoveLabel(null, lab) + + if(length(L)) + lext.AttachLabel(user, L) + else if(user) + to_chat(user, SPAN_NOTICE("You clear the label on \the [src].")) + +/obj/item/chems/chem_disp_cartridge/attack_self(mob/user) + if((. = ..())) + return if (ATOM_IS_OPEN_CONTAINER(src)) - to_chat(usr, "You put the cap on \the [src].") + to_chat(user, SPAN_NOTICE("You put the cap on \the [src].")) atom_flags ^= ATOM_FLAG_OPEN_CONTAINER else - to_chat(usr, "You take the cap off \the [src].") + to_chat(user, SPAN_NOTICE("You take the cap off \the [src].")) atom_flags |= ATOM_FLAG_OPEN_CONTAINER -/obj/item/chems/chem_disp_cartridge/afterattack(obj/target, mob/user , flag) - if (!ATOM_IS_OPEN_CONTAINER(src) || !flag) - return - - else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. - target.add_fingerprint(user) - - if(!target.reagents.total_volume && target.reagents) - to_chat(user, "\The [target] is empty.") - return - - if(reagents.total_volume >= reagents.maximum_volume) - to_chat(user, "\The [src] is full.") - return - - var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this) - to_chat(user, "You fill \the [src] with [trans] units of the contents of \the [target].") - - else if(ATOM_IS_OPEN_CONTAINER(target) && target.reagents) //Something like a glass. Player probably wants to transfer TO it. - - if(!reagents.total_volume) - to_chat(user, "\The [src] is empty.") - return - - if(target.reagents.total_volume >= target.reagents.maximum_volume) - to_chat(user, "\The [target] is full.") - return - - var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) - to_chat(user, "You transfer [trans] units of the solution to \the [target].") - - else - return ..() +/obj/item/chems/chem_disp_cartridge/afterattack(obj/target, mob/user, proximity_flag, click_parameters) + if (ATOM_IS_OPEN_CONTAINER(src) && proximity_flag) + if(standard_dispenser_refill(user, target)) + return TRUE + if(standard_pour_into(user, target)) + return TRUE + if(handle_eaten_by_mob(user, target) != EATEN_INVALID) + return TRUE + if(user.check_intent(I_FLAG_HARM)) + if(standard_splash_mob(user,target)) + return TRUE + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(reagents && total_vol) + to_chat(user, SPAN_DANGER("You splash the contents of \the [src] onto \the [target].")) + reagents.splash(target, total_vol) //FIXME: probably shouldn't throw the whole 500 units at the mob, since the bottle neck is a bottle neck. + return TRUE + return ..() diff --git a/code/modules/reagents/dispenser/cartridge_presets.dm b/code/modules/reagents/dispenser/cartridge_presets.dm index cff9cee981f7..bb0cf4c89422 100644 --- a/code/modules/reagents/dispenser/cartridge_presets.dm +++ b/code/modules/reagents/dispenser/cartridge_presets.dm @@ -1,92 +1,102 @@ -/obj/item/chems/chem_disp_cartridge - small - volume = CARTRIDGE_VOLUME_SMALL +/obj/item/chems/chem_disp_cartridge/small + chem_volume = CARTRIDGE_VOLUME_SMALL - medium - volume = CARTRIDGE_VOLUME_MEDIUM +/obj/item/chems/chem_disp_cartridge/medium + chem_volume = CARTRIDGE_VOLUME_MEDIUM - // Multiple - water spawn_reagent = /decl/material/liquid/water - sugar spawn_reagent = /decl/material/liquid/nutriment/sugar +/** + * Helper macro to define a new cartridge type for a given reagent. + * CART_TYPE: the type suffix to append to the cartridge type path. + * REAGENT_TYPE: The reagent decl path to fill the cartridge with. + */ +#define DEFINE_CARTRIDGE_FOR_CHEM(CART_TYPE, REAGENT_TYPE) /obj/item/chems/chem_disp_cartridge/##CART_TYPE/populate_reagents(){add_to_reagents(REAGENT_TYPE, REAGENT_MAXIMUM_VOLUME(reagents));} - // Chemistry - hydrazine spawn_reagent = /decl/material/liquid/fuel/hydrazine - lithium spawn_reagent = /decl/material/solid/lithium - carbon spawn_reagent = /decl/material/solid/carbon - ammonia spawn_reagent = /decl/material/gas/ammonia - acetone spawn_reagent = /decl/material/liquid/acetone - sodium spawn_reagent = /decl/material/solid/sodium - aluminium spawn_reagent = /decl/material/solid/metal/aluminium - silicon spawn_reagent = /decl/material/solid/silicon - phosphorus spawn_reagent = /decl/material/solid/phosphorus - sulfur spawn_reagent = /decl/material/solid/sulfur - hclacid spawn_reagent = /decl/material/liquid/acid/hydrochloric - potassium spawn_reagent = /decl/material/solid/potassium - iron spawn_reagent = /decl/material/solid/metal/iron - copper spawn_reagent = /decl/material/solid/metal/copper - mercury spawn_reagent = /decl/material/liquid/mercury - radium spawn_reagent = /decl/material/solid/metal/radium - ethanol spawn_reagent = /decl/material/liquid/ethanol - sacid spawn_reagent = /decl/material/liquid/acid - tungsten spawn_reagent = /decl/material/solid/metal/tungsten +// Multiple +DEFINE_CARTRIDGE_FOR_CHEM(water, /decl/material/liquid/water) +DEFINE_CARTRIDGE_FOR_CHEM(sugar, /decl/material/liquid/nutriment/sugar) - // Bar, alcoholic - beer spawn_reagent = /decl/material/liquid/ethanol/beer - kahlua spawn_reagent = /decl/material/liquid/ethanol/coffee/kahlua - whiskey spawn_reagent = /decl/material/liquid/ethanol/whiskey - wine spawn_reagent = /decl/material/liquid/ethanol/wine - vodka spawn_reagent = /decl/material/liquid/ethanol/vodka - gin spawn_reagent = /decl/material/liquid/ethanol/gin - rum spawn_reagent = /decl/material/liquid/ethanol/rum - tequila spawn_reagent = /decl/material/liquid/ethanol/tequilla - vermouth spawn_reagent = /decl/material/liquid/ethanol/vermouth - cognac spawn_reagent = /decl/material/liquid/ethanol/cognac - ale spawn_reagent = /decl/material/liquid/ethanol/ale - mead spawn_reagent = /decl/material/liquid/ethanol/mead +// Chemistry +DEFINE_CARTRIDGE_FOR_CHEM(hydrazine, /decl/material/liquid/fuel/hydrazine) +DEFINE_CARTRIDGE_FOR_CHEM(lithium, /decl/material/solid/lithium) +DEFINE_CARTRIDGE_FOR_CHEM(carbon, /decl/material/solid/carbon) +DEFINE_CARTRIDGE_FOR_CHEM(ammonia, /decl/material/gas/ammonia) +DEFINE_CARTRIDGE_FOR_CHEM(acetone, /decl/material/liquid/acetone) +DEFINE_CARTRIDGE_FOR_CHEM(sodium, /decl/material/solid/sodium) +DEFINE_CARTRIDGE_FOR_CHEM(aluminium, /decl/material/solid/metal/aluminium) +DEFINE_CARTRIDGE_FOR_CHEM(silicon, /decl/material/solid/silicon) +DEFINE_CARTRIDGE_FOR_CHEM(phosphorus, /decl/material/solid/phosphorus) +DEFINE_CARTRIDGE_FOR_CHEM(sulfur, /decl/material/solid/sulfur) +DEFINE_CARTRIDGE_FOR_CHEM(hclacid, /decl/material/liquid/acid/hydrochloric) +DEFINE_CARTRIDGE_FOR_CHEM(potassium, /decl/material/solid/potassium) +DEFINE_CARTRIDGE_FOR_CHEM(iron, /decl/material/solid/metal/iron) +DEFINE_CARTRIDGE_FOR_CHEM(copper, /decl/material/solid/metal/copper) +DEFINE_CARTRIDGE_FOR_CHEM(mercury, /decl/material/liquid/mercury) +DEFINE_CARTRIDGE_FOR_CHEM(radium, /decl/material/solid/metal/radium) +DEFINE_CARTRIDGE_FOR_CHEM(ethanol, /decl/material/liquid/alcohol/ethanol) +DEFINE_CARTRIDGE_FOR_CHEM(sacid, /decl/material/liquid/acid) +DEFINE_CARTRIDGE_FOR_CHEM(tungsten, /decl/material/solid/metal/tungsten) - // Bar, soft - ice spawn_reagent = /decl/material/solid/ice - black_tea spawn_reagent = /decl/material/liquid/drink/tea/black - green_tea spawn_reagent = /decl/material/liquid/drink/tea/green - chai_tea spawn_reagent = /decl/material/liquid/drink/tea/chai - red_tea spawn_reagent = /decl/material/liquid/drink/tea/red - cola spawn_reagent = /decl/material/liquid/drink/cola - citrussoda spawn_reagent = /decl/material/liquid/drink/citrussoda - cherrycola spawn_reagent = /decl/material/liquid/drink/cherrycola - lemonade spawn_reagent = /decl/material/liquid/drink/lemonade - tonic spawn_reagent = /decl/material/liquid/drink/tonic - sodawater spawn_reagent = /decl/material/liquid/drink/sodawater - lemon_lime spawn_reagent = /decl/material/liquid/drink/lemon_lime - orange spawn_reagent = /decl/material/liquid/drink/juice/orange - lime spawn_reagent = /decl/material/liquid/drink/juice/lime - watermelon spawn_reagent = /decl/material/liquid/drink/juice/watermelon - // Bar, syrups - syrup_chocolate spawn_reagent = /decl/material/liquid/drink/syrup/chocolate - syrup_caramel spawn_reagent = /decl/material/liquid/drink/syrup/caramel - syrup_vanilla spawn_reagent = /decl/material/liquid/drink/syrup/vanilla - syrup_pumpkin spawn_reagent = /decl/material/liquid/drink/syrup/pumpkin +// Bar, alcoholic +DEFINE_CARTRIDGE_FOR_CHEM(beer, /decl/material/liquid/alcohol/beer) +DEFINE_CARTRIDGE_FOR_CHEM(kahlua, /decl/material/liquid/alcohol/coffee) +DEFINE_CARTRIDGE_FOR_CHEM(whiskey, /decl/material/liquid/alcohol/whiskey) +DEFINE_CARTRIDGE_FOR_CHEM(wine, /decl/material/liquid/alcohol/wine) +DEFINE_CARTRIDGE_FOR_CHEM(vodka, /decl/material/liquid/alcohol/vodka) +DEFINE_CARTRIDGE_FOR_CHEM(gin, /decl/material/liquid/alcohol/gin) +DEFINE_CARTRIDGE_FOR_CHEM(rum, /decl/material/liquid/alcohol/rum) +DEFINE_CARTRIDGE_FOR_CHEM(tequila, /decl/material/liquid/alcohol/tequila) +DEFINE_CARTRIDGE_FOR_CHEM(vermouth, /decl/material/liquid/alcohol/vermouth) +DEFINE_CARTRIDGE_FOR_CHEM(cognac, /decl/material/liquid/alcohol/cognac) +DEFINE_CARTRIDGE_FOR_CHEM(ale, /decl/material/liquid/alcohol/ale) +DEFINE_CARTRIDGE_FOR_CHEM(mead, /decl/material/liquid/alcohol/mead) - // Bar, coffee - coffee spawn_reagent = /decl/material/liquid/drink/coffee - hot_coco spawn_reagent = /decl/material/liquid/drink/hot_coco - milk spawn_reagent = /decl/material/liquid/drink/milk - soymilk spawn_reagent = /decl/material/liquid/drink/milk/soymilk - cream spawn_reagent = /decl/material/liquid/drink/milk/cream +// Bar, soft +DEFINE_CARTRIDGE_FOR_CHEM(ice, /decl/material/solid/ice) +DEFINE_CARTRIDGE_FOR_CHEM(black_tea, /decl/material/liquid/drink/tea/black) +DEFINE_CARTRIDGE_FOR_CHEM(green_tea, /decl/material/liquid/drink/tea/green) +DEFINE_CARTRIDGE_FOR_CHEM(chai_tea, /decl/material/liquid/drink/tea/chai) +DEFINE_CARTRIDGE_FOR_CHEM(red_tea, /decl/material/liquid/drink/tea/red) +DEFINE_CARTRIDGE_FOR_CHEM(cola, /decl/material/liquid/drink/cola) +DEFINE_CARTRIDGE_FOR_CHEM(citrussoda, /decl/material/liquid/drink/citrussoda) +DEFINE_CARTRIDGE_FOR_CHEM(cherrycola, /decl/material/liquid/drink/cherrycola) +DEFINE_CARTRIDGE_FOR_CHEM(lemonade, /decl/material/liquid/drink/lemonade) +DEFINE_CARTRIDGE_FOR_CHEM(tonic, /decl/material/liquid/drink/tonic) +DEFINE_CARTRIDGE_FOR_CHEM(sodawater, /decl/material/liquid/drink/sodawater) +DEFINE_CARTRIDGE_FOR_CHEM(lemon_lime, /decl/material/liquid/drink/lemon_lime) +DEFINE_CARTRIDGE_FOR_CHEM(orange, /decl/material/liquid/drink/juice/orange) +DEFINE_CARTRIDGE_FOR_CHEM(lime, /decl/material/liquid/drink/juice/lime) +DEFINE_CARTRIDGE_FOR_CHEM(watermelon, /decl/material/liquid/drink/juice/watermelon) - // ERT - adrenaline spawn_reagent = /decl/material/liquid/adrenaline - retrovirals spawn_reagent = /decl/material/liquid/retrovirals - painkillers spawn_reagent = /decl/material/liquid/painkillers - antiseptic spawn_reagent = /decl/material/liquid/antiseptic - burn_meds spawn_reagent = /decl/material/liquid/burn_meds - oxy_meds spawn_reagent = /decl/material/liquid/oxy_meds - regenerator spawn_reagent = /decl/material/liquid/regenerator - antitoxins spawn_reagent = /decl/material/liquid/antitoxins - antirads spawn_reagent = /decl/material/liquid/antirads - neuroannealer spawn_reagent = /decl/material/liquid/neuroannealer - eyedrops spawn_reagent = /decl/material/liquid/eyedrops - brute_meds spawn_reagent = /decl/material/liquid/brute_meds - amphetamines spawn_reagent = /decl/material/liquid/amphetamines - antibiotics spawn_reagent = /decl/material/liquid/antibiotics - sedatives spawn_reagent = /decl/material/liquid/sedatives +// Bar, syrups +DEFINE_CARTRIDGE_FOR_CHEM(syrup_chocolate, /decl/material/liquid/drink/syrup/chocolate) +DEFINE_CARTRIDGE_FOR_CHEM(syrup_caramel, /decl/material/liquid/drink/syrup/caramel) +DEFINE_CARTRIDGE_FOR_CHEM(syrup_vanilla, /decl/material/liquid/drink/syrup/vanilla) +DEFINE_CARTRIDGE_FOR_CHEM(syrup_pumpkin, /decl/material/liquid/drink/syrup/pumpkin) +DEFINE_CARTRIDGE_FOR_CHEM(syrup_lavender, /decl/material/liquid/drink/syrup/lavender) +DEFINE_CARTRIDGE_FOR_CHEM(cinnamon, /decl/material/solid/cinnamon) + +// Bar, coffee +DEFINE_CARTRIDGE_FOR_CHEM(coffee, /decl/material/liquid/drink/coffee) +DEFINE_CARTRIDGE_FOR_CHEM(hot_coco, /decl/material/liquid/drink/hot_coco) +DEFINE_CARTRIDGE_FOR_CHEM(milk, /decl/material/liquid/drink/milk) +DEFINE_CARTRIDGE_FOR_CHEM(soymilk, /decl/material/liquid/drink/milk/soymilk) +DEFINE_CARTRIDGE_FOR_CHEM(cream, /decl/material/liquid/drink/milk/cream) + +// ERT +DEFINE_CARTRIDGE_FOR_CHEM(adrenaline, /decl/material/liquid/adrenaline) +DEFINE_CARTRIDGE_FOR_CHEM(retrovirals, /decl/material/liquid/retrovirals) +DEFINE_CARTRIDGE_FOR_CHEM(painkillers, /decl/material/liquid/painkillers) +DEFINE_CARTRIDGE_FOR_CHEM(antiseptic, /decl/material/liquid/antiseptic) +DEFINE_CARTRIDGE_FOR_CHEM(burn_meds, /decl/material/liquid/burn_meds) +DEFINE_CARTRIDGE_FOR_CHEM(oxy_meds, /decl/material/liquid/oxy_meds) +DEFINE_CARTRIDGE_FOR_CHEM(regenerator, /decl/material/liquid/regenerator) +DEFINE_CARTRIDGE_FOR_CHEM(antitoxins, /decl/material/liquid/antitoxins) +DEFINE_CARTRIDGE_FOR_CHEM(antirads, /decl/material/liquid/antirads) +DEFINE_CARTRIDGE_FOR_CHEM(neuroannealer, /decl/material/liquid/neuroannealer) +DEFINE_CARTRIDGE_FOR_CHEM(eyedrops, /decl/material/liquid/eyedrops) +DEFINE_CARTRIDGE_FOR_CHEM(brute_meds, /decl/material/liquid/brute_meds) +DEFINE_CARTRIDGE_FOR_CHEM(amphetamines, /decl/material/liquid/amphetamines) +DEFINE_CARTRIDGE_FOR_CHEM(antibiotics, /decl/material/liquid/antibiotics) +DEFINE_CARTRIDGE_FOR_CHEM(sedatives, /decl/material/liquid/sedatives) +DEFINE_CARTRIDGE_FOR_CHEM(stabilizer, /decl/material/liquid/stabilizer) \ No newline at end of file diff --git a/code/modules/reagents/dispenser/cartridge_spawn.dm b/code/modules/reagents/dispenser/cartridge_spawn.dm index ceea89f8aeaf..d601f2ae2dd6 100644 --- a/code/modules/reagents/dispenser/cartridge_spawn.dm +++ b/code/modules/reagents/dispenser/cartridge_spawn.dm @@ -1,13 +1,14 @@ -/client/proc/spawn_chemdisp_cartridge(size in list("small", "medium", "large"), reagent in subtypesof(/decl/material)) +/client/proc/spawn_chemdisp_cartridge(size in list("small", "medium", "large"), reagent_type in decls_repository.get_decl_paths_of_subtype(/decl/material)) set name = "Spawn Chemical Dispenser Cartridge" set category = "Admin" - var/obj/item/chems/chem_disp_cartridge/C + var/cartridge_type switch(size) - if("small") C = new /obj/item/chems/chem_disp_cartridge/small(usr.loc) - if("medium") C = new /obj/item/chems/chem_disp_cartridge/medium(usr.loc) - if("large") C = new /obj/item/chems/chem_disp_cartridge(usr.loc) - C.reagents.add_reagent(reagent, C.volume) - var/decl/material/R = reagent - C.setLabel(initial(R.name)) - log_and_message_admins("spawned a [size] reagent container containing [reagent]") + if("small") cartridge_type = /obj/item/chems/chem_disp_cartridge/small + if("medium") cartridge_type = /obj/item/chems/chem_disp_cartridge/medium + if("large") cartridge_type = /obj/item/chems/chem_disp_cartridge + var/obj/item/chems/chem_disp_cartridge/cartridge = new cartridge_type(usr.loc) + cartridge.add_to_reagents(reagent_type, REAGENT_MAXIMUM_VOLUME(cartridge.reagents)) + var/reagent_name = cartridge.reagents.get_primary_reagent_name() + cartridge.setLabel(reagent_name) + log_and_message_admins("spawned a [size] reagent container containing [reagent_name] ([reagent_type])") diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/dispenser/dispenser2.dm index 765d65322287..3ad90fe93db7 100644 --- a/code/modules/reagents/dispenser/dispenser2.dm +++ b/code/modules/reagents/dispenser/dispenser2.dm @@ -6,10 +6,14 @@ clicksound = "button" clickvol = 20 + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = 0 + base_type = /obj/machinery/chemical_dispenser var/list/spawn_cartridges = null // Set to a list of types to spawn one of each on New() var/list/cartridges = list() // Associative, label -> cartridge - var/obj/item/chems/container = null + var/obj/item/chems/container var/ui_title = "Chemical Dispenser" @@ -17,24 +21,33 @@ var/amount = 30 idle_power_usage = 100 - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE obj_flags = OBJ_FLAG_ANCHORABLE core_skill = SKILL_CHEMISTRY var/can_contaminate = TRUE + var/buildable = TRUE + var/static/list/acceptable_containers = list( + /obj/item/chems/glass, + /obj/item/chems/condiment, + /obj/item/chems/drinks + ) -/obj/machinery/chemical_dispenser/Initialize() - . = ..() + var/beaker_offset = 0 + var/beaker_positions = list(0,1) - if(spawn_cartridges) +/obj/machinery/chemical_dispenser/Initialize(mapload, d=0, populate_parts = TRUE) + . = ..() + if(spawn_cartridges && populate_parts) for(var/type in spawn_cartridges) add_cartridge(new type(src)) -/obj/machinery/chemical_dispenser/examine(mob/user) +/obj/machinery/chemical_dispenser/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It has [cartridges.len] cartridges installed, and has space for [DISPENSER_MAX_CARTRIDGES - cartridges.len] more.") + . += "It has [cartridges.len] cartridges installed, and has space for [DISPENSER_MAX_CARTRIDGES - cartridges.len] more." /obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/chems/chem_disp_cartridge/C, mob/user) + . = FALSE if(!istype(C)) if(user) to_chat(user, "\The [C] will not fit in \the [src]!") @@ -45,68 +58,86 @@ to_chat(user, "\The [src] does not have any slots open for \the [C] to fit into!") return - if(!C.label) + var/datum/extension/labels/lab = get_extension(C, /datum/extension/labels) + if(!length(lab?.labels)) if(user) to_chat(user, "\The [C] does not have a label!") return - if(cartridges[C.label]) + if(cartridges[lab.labels[1]]) if(user) to_chat(user, "\The [src] already contains a cartridge with that label!") return if(user) - if(user.unEquip(C)) + if(user.try_unequip(C)) to_chat(user, "You add \the [C] to \the [src].") else return C.forceMove(src) - cartridges[C.label] = C - cartridges = sortAssoc(cartridges) + cartridges[lab.labels[1]] = C + cartridges = sortTim(cartridges, /proc/cmp_text_asc) SSnano.update_uis(src) + return TRUE /obj/machinery/chemical_dispenser/proc/remove_cartridge(label) . = cartridges[label] cartridges -= label SSnano.update_uis(src) -/obj/machinery/chemical_dispenser/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/chems/chem_disp_cartridge)) - add_cartridge(W, user) +/obj/machinery/chemical_dispenser/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/chems/chem_disp_cartridge)) + add_cartridge(used_item, user) + return TRUE - else if(isScrewdriver(W)) + if(IS_CROWBAR(used_item) && !panel_open && length(cartridges)) var/label = input(user, "Which cartridge would you like to remove?", "Chemical Dispenser") as null|anything in cartridges - if(!label) return + if(!label) return TRUE var/obj/item/chems/chem_disp_cartridge/C = remove_cartridge(label) if(C) - to_chat(user, "You remove \the [C] from \the [src].") + to_chat(user, SPAN_NOTICE("You remove \the [C] from \the [src].")) C.dropInto(loc) + return TRUE - else if(istype(W, /obj/item/chems/glass) || istype(W, /obj/item/chems/food)) + if(is_type_in_list(used_item, acceptable_containers)) if(container) - to_chat(user, "There is already \a [container] on \the [src]!") - return + to_chat(user, SPAN_WARNING("There is already \a [container] on \the [src]!")) + return TRUE - var/obj/item/chems/RC = W + var/obj/item/chems/new_container = used_item - if(!accept_drinking && istype(RC,/obj/item/chems/food)) - to_chat(user, "This machine only accepts beakers!") - return + if(!accept_drinking && (istype(new_container,/obj/item/chems/condiment) || istype(new_container,/obj/item/chems/drinks))) + to_chat(user, SPAN_WARNING("This machine only accepts beakers!")) + return TRUE - if(!ATOM_IS_OPEN_CONTAINER(RC)) - to_chat(user, "You don't see how \the [src] could dispense reagents into \the [RC].") - return - if(!user.unEquip(RC, src)) - return - container = RC - update_icon() - to_chat(user, "You set \the [RC] on \the [src].") - SSnano.update_uis(src) // update all UIs attached to src + if(!ATOM_IS_OPEN_CONTAINER(new_container)) + to_chat(user, SPAN_WARNING("You don't see how \the [src] could dispense reagents into \the [new_container].")) + return TRUE + if(!user.try_unequip(new_container, src)) + return TRUE + set_container(new_container) + to_chat(user, SPAN_NOTICE("You set \the [new_container] on \the [src].")) + return TRUE - else - ..() - return + return ..() + +/obj/machinery/chemical_dispenser/proc/set_container(var/obj/item/chems/new_container) + if(container == new_container) + return + if(container) + events_repository.unregister(/decl/observ/moved, container, src) + events_repository.unregister(/decl/observ/destroyed, container, src) + container = new_container + if(container) + events_repository.register(/decl/observ/moved, container, src, PROC_REF(check_container_status)) + events_repository.register(/decl/observ/destroyed, container, src, PROC_REF(check_container_status)) + update_icon() + SSnano.update_uis(src) // update all UIs attached to src + +/obj/machinery/chemical_dispenser/proc/check_container_status() + if(container && (QDELETED(container) || container.loc != src)) + set_container(null) /obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1) // this is the data which will be sent to the ui @@ -115,15 +146,15 @@ data["isBeakerLoaded"] = container ? 1 : 0 data["glass"] = accept_drinking var beakerD[0] - if(LAZYLEN(container?.reagents?.reagent_volumes)) - for(var/rtype in container.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - beakerD[++beakerD.len] = list("name" = R.name, "volume" = REAGENT_VOLUME(container.reagents, rtype)) + var/beaker_volumes = REAGENT_VOLUMES(container?.reagents) + if(LAZYLEN(beaker_volumes)) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(container.reagents)) + beakerD[++beakerD.len] = list("name" = reagent.use_name, "volume" = REAGENT_VOLUME(container.reagents, reagent)) data["beakerContents"] = beakerD - if(container) - data["beakerCurrentVolume"] = container.reagents.total_volume - data["beakerMaxVolume"] = container.reagents.maximum_volume + if(container) // Container has had null reagents in the past; may be due to qdel without clearing reference. + data["beakerCurrentVolume"] = REAGENT_TOTAL_VOLUME(container.reagents) + data["beakerMaxVolume"] = REAGENT_MAXIMUM_VOLUME(container.reagents) else data["beakerCurrentVolume"] = null data["beakerMaxVolume"] = null @@ -131,7 +162,7 @@ var chemicals[0] for(var/label in cartridges) var/obj/item/chems/chem_disp_cartridge/C = cartridges[label] - chemicals[++chemicals.len] = list("label" = label, "amount" = C.reagents.total_volume) + chemicals[++chemicals.len] = list("label" = label, "amount" = REAGENT_TOTAL_VOLUME(C.reagents)) data["chemicals"] = chemicals // update the ui if it exists, returns null if no ui is passed/found @@ -167,22 +198,25 @@ return TOPIC_HANDLED else if(href_list["ejectBeaker"]) - if(container) - var/obj/item/chems/B = container - B.dropInto(loc) - container = null - update_icon() - return TOPIC_REFRESH - return TOPIC_HANDLED + if(!container) + return TOPIC_HANDLED + + var/obj/item/chems/previous_container = container + + set_container(null) + + if(CanPhysicallyInteract(user)) + user.put_in_hands(previous_container) + else + previous_container.dropInto(loc) + + return TOPIC_REFRESH /obj/machinery/chemical_dispenser/interface_interact(mob/user) ui_interact(user) return TRUE /obj/machinery/chemical_dispenser/on_update_icon() - overlays.Cut() + cut_overlays() if(container) - var/mutable_appearance/beaker_overlay - beaker_overlay = image(src, src, "lil_beaker") - beaker_overlay.pixel_x = rand(-10, 5) - overlays += beaker_overlay \ No newline at end of file + add_overlay(image(icon, "lil_beaker", pixel_x = pick(beaker_positions), pixel_y = beaker_offset)) diff --git a/code/modules/reagents/dispenser/dispenser_presets.dm b/code/modules/reagents/dispenser/dispenser_presets.dm index 475f29ff4a2e..afc9ccd606c4 100644 --- a/code/modules/reagents/dispenser/dispenser_presets.dm +++ b/code/modules/reagents/dispenser/dispenser_presets.dm @@ -1,3 +1,6 @@ +/obj/machinery/chemical_dispenser/unanchored + anchored = FALSE + /obj/machinery/chemical_dispenser/full spawn_cartridges = list( /obj/item/chems/chem_disp_cartridge/hydrazine, @@ -23,7 +26,9 @@ /obj/item/chems/chem_disp_cartridge/tungsten ) -/obj/machinery/chemical_dispenser/ert + buildable = FALSE + +/obj/machinery/chemical_dispenser/medicine name = "medicine dispenser" spawn_cartridges = list( /obj/item/chems/chem_disp_cartridge/adrenaline, @@ -42,6 +47,7 @@ /obj/item/chems/chem_disp_cartridge/antibiotics, /obj/item/chems/chem_disp_cartridge/sedatives ) + buildable = FALSE /obj/machinery/chemical_dispenser/bar_soft name = "soft drink dispenser" @@ -51,6 +57,12 @@ accept_drinking = 1 core_skill = SKILL_COOKING can_contaminate = FALSE //It's not a complex panel, and I'm fairly sure that most people don't haymaker the control panel on a soft drinks machine. -- Chaoko99 + base_type = /obj/machinery/chemical_dispenser/bar_soft + beaker_offset = -2 + beaker_positions = list(-1,3,7,11,15) + +/obj/machinery/chemical_dispenser/bar_soft/unanchored + anchored = FALSE /obj/machinery/chemical_dispenser/bar_soft/full spawn_cartridges = list( @@ -76,6 +88,8 @@ /obj/item/chems/chem_disp_cartridge/watermelon ) + buildable = FALSE + /obj/machinery/chemical_dispenser/bar_alc name = "booze dispenser" desc = "A beer machine. Like a soda machine, but more fun!" @@ -84,6 +98,12 @@ accept_drinking = 1 core_skill = SKILL_COOKING can_contaminate = FALSE //See above. + base_type = /obj/machinery/chemical_dispenser/bar_alc + beaker_offset = -2 + beaker_positions = list(-3,2,7,12,17) + +/obj/machinery/chemical_dispenser/bar_alc/unanchored + anchored = FALSE /obj/machinery/chemical_dispenser/bar_alc/full spawn_cartridges = list( @@ -107,6 +127,8 @@ /obj/item/chems/chem_disp_cartridge/mead ) + buildable = FALSE + /obj/machinery/chemical_dispenser/bar_coffee name = "coffee dispenser" desc = "Driving crack dealers out of employment since 2280." @@ -115,6 +137,10 @@ accept_drinking = 1 core_skill = SKILL_COOKING can_contaminate = FALSE //See above. + base_type = /obj/machinery/chemical_dispenser/bar_coffee + beaker_offset = -2 + beaker_positions = list(0,14) + /obj/machinery/chemical_dispenser/bar_coffee/full spawn_cartridges = list( @@ -131,5 +157,9 @@ /obj/item/chems/chem_disp_cartridge/syrup_chocolate, /obj/item/chems/chem_disp_cartridge/syrup_caramel, /obj/item/chems/chem_disp_cartridge/syrup_vanilla, - /obj/item/chems/chem_disp_cartridge/syrup_pumpkin + /obj/item/chems/chem_disp_cartridge/syrup_pumpkin, + /obj/item/chems/chem_disp_cartridge/syrup_lavender, + /obj/item/chems/chem_disp_cartridge/cinnamon ) + + buildable = FALSE \ No newline at end of file diff --git a/code/modules/reagents/heat_sources/_heat_source.dm b/code/modules/reagents/heat_sources/_heat_source.dm index f109abdffe28..199a9a79aab8 100644 --- a/code/modules/reagents/heat_sources/_heat_source.dm +++ b/code/modules/reagents/heat_sources/_heat_source.dm @@ -5,8 +5,8 @@ #define HEATER_MODE_COOL "cool" /obj/machinery/reagent_temperature - name = "chemical heater" - desc = "A small electric Bunsen, used to heat beakers and vials of chemicals." + name = "hotplate" + desc = "A small electric hotplate, used to heat cookware, beakers, or vials of chemicals." icon = 'icons/obj/machines/heat_sources.dmi' icon_state = "hotplate" atom_flags = ATOM_FLAG_CLIMBABLE @@ -50,7 +50,7 @@ . = ..() /obj/machinery/reagent_temperature/RefreshParts() - heating_power = initial(heating_power) * Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) + heating_power = initial(heating_power) * clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10) var/comp = 0.25 KILOWATTS * total_component_rating_of_type(/obj/item/stock_parts/micro_laser) if(comp) @@ -63,7 +63,6 @@ queue_icon_update() if(((stat & (BROKEN|NOPOWER)) || !anchored) && use_power >= POWER_USE_ACTIVE) update_use_power(POWER_USE_IDLE) - queue_icon_update() /obj/machinery/reagent_temperature/interface_interact(var/mob/user) interact(user) @@ -71,6 +70,7 @@ /obj/machinery/reagent_temperature/ProcessAtomTemperature() if(use_power >= POWER_USE_ACTIVE) + var/last_temperature = temperature if(heater_mode == HEATER_MODE_HEAT && temperature < target_temperature) temperature = min(target_temperature, temperature + heating_power) @@ -78,33 +78,50 @@ temperature = max(target_temperature, temperature - heating_power) if(temperature != last_temperature) if(container) - QUEUE_TEMPERATURE_ATOMS(container) + queue_temperature_atoms(container) queue_icon_update() + + // Hackery to heat pots placed onto a hotplate without also grilling/baking stuff. + if(isturf(loc)) + for(var/obj/item/chems/cooking_vessel/pot in loc.get_contained_external_atoms()) + pot.handle_external_heating(temperature, src) + return TRUE // Don't kill this processing loop unless we're not powered. . = ..() -/obj/machinery/reagent_temperature/attackby(var/obj/item/thing, var/mob/user) - if(isWrench(thing)) +/obj/machinery/reagent_temperature/attackby(var/obj/item/used_item, var/mob/user) + + if(istype(used_item, /obj/item/chems/cooking_vessel)) + if(!user.try_unequip(used_item, get_turf(src))) + return TRUE + used_item.reset_offsets(anim_time = 0) + user.visible_message(SPAN_NOTICE("\The [user] places \the [used_item] onto \the [src].")) + return TRUE + + if(IS_WRENCH(used_item)) if(use_power == POWER_USE_ACTIVE) to_chat(user, SPAN_WARNING("Turn \the [src] off first!")) else anchored = !anchored visible_message(SPAN_NOTICE("\The [user] [anchored ? "secured" : "unsecured"] \the [src].")) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - return + return TRUE - if(thing.reagents) + if(used_item.reagents) for(var/checktype in permitted_types) - if(istype(thing, checktype)) + if(istype(used_item, checktype)) if(container) to_chat(user, SPAN_WARNING("\The [src] is already holding \the [container].")) - else if(user.unEquip(thing)) - thing.forceMove(src) - container = thing + else if(user.try_unequip(used_item)) + used_item.forceMove(src) + container = used_item visible_message(SPAN_NOTICE("\The [user] places \the [container] on \the [src].")) update_icon() - return - to_chat(user, SPAN_WARNING("\The [src] cannot accept \the [thing].")) + return TRUE + to_chat(user, SPAN_WARNING("\The [src] cannot accept \the [used_item].")) + return FALSE + + . = ..() /obj/machinery/reagent_temperature/on_update_icon() @@ -117,9 +134,9 @@ if(temperature > MINIMUM_GLOW_TEMPERATURE) // 50C if(!glow_icon) glow_icon = image(icon, "[icon_state]-glow") - glow_icon.alpha = Clamp(temperature - MINIMUM_GLOW_TEMPERATURE, MINIMUM_GLOW_VALUE, MAXIMUM_GLOW_VALUE) + glow_icon.alpha = clamp(temperature - MINIMUM_GLOW_TEMPERATURE, MINIMUM_GLOW_VALUE, MAXIMUM_GLOW_VALUE) LAZYADD(adding_overlays, glow_icon) - set_light(0.2, 0.1, 1, l_color = COLOR_RED) + set_light(1, l_color = COLOR_RED) else set_light(0) else @@ -139,21 +156,21 @@ dat += "
    Target temperature:" if(target_temperature > min_temperature) - dat += "- " + dat += "- " dat += "[target_temperature - T0C]C" if(target_temperature < max_temperature) - dat += " +" + dat += " +" dat += "
    Current temperature:[Floor(temperature - T0C)]C
    Current temperature:[floor(temperature - T0C)]C
    Loaded container:[container ? "[container.name] ([Floor(container.temperature - T0C)]C) Remove" : "None."]
    [container ? "[container.name] ([floor(container.temperature - T0C)]C) Remove" : "None."]
    Switched:[use_power == POWER_USE_ACTIVE ? "On" : "Off"]
    Switched:[use_power == POWER_USE_ACTIVE ? "On" : "Off"]
    " var/datum/browser/popup = new(user, "\ref[src]-reagent_temperature_window", "[capitalize(name)]") @@ -162,7 +179,7 @@ /obj/machinery/reagent_temperature/CanUseTopic(var/mob/user, var/state, var/href_list) if(href_list && href_list["remove_container"]) - . = ..(user, GLOB.physical_state, href_list) + . = ..(user, global.physical_topic_state, href_list) if(. == STATUS_CLOSE) to_chat(user, SPAN_WARNING("You are too far away.")) return @@ -174,7 +191,7 @@ return TOPIC_HANDLED update_use_power(use_power <= POWER_USE_IDLE ? POWER_USE_ACTIVE : POWER_USE_IDLE) - QUEUE_TEMPERATURE_ATOMS(src) + queue_temperature_atoms(src) update_icon() return TOPIC_REFRESH @@ -182,7 +199,7 @@ /obj/machinery/reagent_temperature/OnTopic(var/mob/user, var/href_list) if(href_list["adjust_temperature"]) - target_temperature = Clamp(target_temperature + text2num(href_list["adjust_temperature"]), min_temperature, max_temperature) + target_temperature = clamp(target_temperature + text2num(href_list["adjust_temperature"]), min_temperature, max_temperature) . = TOPIC_REFRESH if(href_list["toggle_power"]) diff --git a/code/modules/reagents/reactions/_reaction.dm b/code/modules/reagents/reactions/_reaction.dm index cc35b177a1eb..7a89aba6dd4c 100644 --- a/code/modules/reagents/reactions/_reaction.dm +++ b/code/modules/reagents/reactions/_reaction.dm @@ -1,4 +1,5 @@ -/datum/chemical_reaction +/decl/chemical_reaction + abstract_type = /decl/chemical_reaction var/name = null var/result = null var/list/required_reagents = list() @@ -11,11 +12,13 @@ var/thermal_product var/mix_message = "The solution begins to bubble." var/reaction_sound = 'sound/effects/bubbles.ogg' - var/log_is_important = 0 // If this reaction should be considered important for logging. Important recipes message admins when mixed, non-important ones just log to file. var/lore_text var/mechanics_text + var/reaction_category = REACTION_TYPE_COMPOUND + /// Flags used when reaction processing. + var/chemical_reaction_flags = 0 -/datum/chemical_reaction/proc/can_happen(var/datum/reagents/holder) +/decl/chemical_reaction/proc/can_happen(var/datum/reagents/holder) //check that all the required reagents are present if(!holder.has_all_reagents(required_reagents)) return 0 @@ -28,36 +31,33 @@ if(holder.has_any_reagent(inhibitors)) return 0 - var/temperature = holder.my_atom ? holder.my_atom.temperature : T20C + var/atom/location = holder.get_reaction_loc(chemical_reaction_flags) + var/temperature = location?.temperature || T20C if(temperature < minimum_temperature || temperature > maximum_temperature) return 0 return 1 -/datum/chemical_reaction/proc/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) - if(thermal_product && ATOM_IS_TEMPERATURE_SENSITIVE(holder.my_atom)) - ADJUST_ATOM_TEMPERATURE(holder.my_atom, thermal_product) +/decl/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + var/atom/location = holder.get_reaction_loc(chemical_reaction_flags) + if(thermal_product && location && ATOM_SHOULD_TEMPERATURE_ENQUEUE(location)) + ADJUST_ATOM_TEMPERATURE(location, location.temperature + (location.get_thermal_mass_coefficient() * thermal_product)) // This proc returns a list of all reagents it wants to use; if the holder has several reactions that use the same reagent, it will split the reagent evenly between them -/datum/chemical_reaction/proc/get_used_reagents() +/decl/chemical_reaction/proc/get_used_reagents() . = list() for(var/reagent in required_reagents) . += reagent -/datum/chemical_reaction/proc/get_reaction_flags(var/datum/reagents/holder) - return 0 - -/datum/chemical_reaction/proc/process(var/datum/reagents/holder, var/limit) +/decl/chemical_reaction/proc/process(var/datum/reagents/holder, var/limit) var/data = send_data(holder) - var/reaction_volume = holder.maximum_volume + var/reaction_volume = REAGENT_GET_MAX_VOL(holder) for(var/reactant in required_reagents) - var/A = REAGENT_VOLUME(holder, reactant) / required_reagents[reactant] / limit // How much of this reagent we are allowed to use + var/A = CHEMS_QUANTIZE(REAGENT_VOLUME(holder, reactant) / required_reagents[reactant] / limit) // How much of this reagent we are allowed to use if(reaction_volume > A) reaction_volume = A - var/reaction_flags = get_reaction_flags(holder) - for(var/reactant in required_reagents) holder.remove_reagent(reactant, reaction_volume * required_reagents[reactant], safety = 1) @@ -66,20 +66,21 @@ if(result) holder.add_reagent(result, amt_produced, data, safety = 1) - on_reaction(holder, amt_produced, reaction_flags) + on_reaction(holder, amt_produced, data) //called after processing reactions, if they occurred -/datum/chemical_reaction/proc/post_reaction(var/datum/reagents/holder) - var/atom/container = holder.my_atom +/decl/chemical_reaction/proc/post_reaction(var/datum/reagents/holder) + var/atom/container = holder.get_reaction_loc(chemical_reaction_flags) if(mix_message && container && !ismob(container)) var/turf/T = get_turf(container) if(istype(T)) - T.visible_message(SPAN_NOTICE("\icon[container] [mix_message]")) + T.visible_message(SPAN_NOTICE("[html_icon(container)] [mix_message]")) else - container.visible_message(SPAN_NOTICE("\icon[container] [mix_message]")) - playsound(T || container, reaction_sound, 80, 1) + container.visible_message(SPAN_NOTICE("[html_icon(container)] [mix_message]")) + if(reaction_sound) + playsound(T || container, reaction_sound, 80, 1) //obtains any special data that will be provided to the reaction products //this is called just before reactants are removed. -/datum/chemical_reaction/proc/send_data(var/datum/reagents/holder, var/reaction_limit) +/decl/chemical_reaction/proc/send_data(var/datum/reagents/holder, var/reaction_limit) return null diff --git a/code/modules/reagents/reactions/reaction_alcohol.dm b/code/modules/reagents/reactions/reaction_alcohol.dm index e15e6416b665..4d96bdb5d128 100644 --- a/code/modules/reagents/reactions/reaction_alcohol.dm +++ b/code/modules/reagents/reactions/reaction_alcohol.dm @@ -1,129 +1,150 @@ -/datum/chemical_reaction/recipe/moonshine +/decl/chemical_reaction/recipe + abstract_type = /decl/chemical_reaction/recipe + reaction_category = REACTION_TYPE_RECIPE + +/decl/chemical_reaction/recipe/enzyme + name = "Universal Enzyme" + required_reagents = list( + /decl/material/liquid/enzyme/rennet = 1, + /decl/material/liquid/acid/polyacid = 1 + ) + minimum_temperature = 100 CELSIUS + result = /decl/material/liquid/enzyme + result_amount = 2 + +/decl/chemical_reaction/recipe/moonshine name = "Moonshine" - result = /decl/material/liquid/ethanol/moonshine + result = /decl/material/liquid/alcohol/moonshine required_reagents = list(/decl/material/liquid/nutriment = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution exudes the powerful reek of raw alcohol." -/datum/chemical_reaction/recipe/grenadine +/decl/chemical_reaction/recipe/grenadine name = "Grenadine Syrup" result = /decl/material/liquid/drink/grenadine required_reagents = list(/decl/material/liquid/drink/juice/berry = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 -/datum/chemical_reaction/recipe/wine - name = "Wine" - result = /decl/material/liquid/ethanol/wine +/decl/chemical_reaction/recipe/wine + name = "Red Wine" + result = /decl/material/liquid/alcohol/wine required_reagents = list(/decl/material/liquid/drink/juice/grape = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a rich red liquid." -/datum/chemical_reaction/recipe/pwine +/decl/chemical_reaction/recipe/pwine name = "Poison Wine" - result = /decl/material/liquid/ethanol/pwine + result = /decl/material/liquid/alcohol/pwine required_reagents = list(/decl/material/liquid/poisonberryjuice = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a shifting purple liquid." -/datum/chemical_reaction/recipe/melonliquor +/decl/chemical_reaction/recipe/melonliquor name = "Melon Liquor" - result = /decl/material/liquid/ethanol/melonliquor + result = /decl/material/liquid/alcohol/melonliquor required_reagents = list(/decl/material/liquid/drink/juice/watermelon = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a pale liquor." -/datum/chemical_reaction/recipe/bluecuracao +/decl/chemical_reaction/recipe/bluecuracao name = "Blue Curacao" - result = /decl/material/liquid/ethanol/bluecuracao + result = /decl/material/liquid/alcohol/bluecuracao required_reagents = list(/decl/material/liquid/drink/juice/orange = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a shockingly blue liquor." -/datum/chemical_reaction/recipe/beer - name = "Beer" - result = /decl/material/liquid/ethanol/beer - required_reagents = list(/decl/material/liquid/nutriment/cornoil = 10) +/decl/chemical_reaction/recipe/beer + name = "Plain Beer" + result = /decl/material/liquid/alcohol/beer + required_reagents = list(/decl/material/liquid/oil/plant/corn = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a foaming amber liquid." -/datum/chemical_reaction/recipe/vodka +/decl/chemical_reaction/recipe/vodka name = "Potato Vodka" - result = /decl/material/liquid/ethanol/vodka + result = /decl/material/liquid/alcohol/vodka required_reagents = list(/decl/material/liquid/drink/juice/potato = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a crystal clear liquid." -/datum/chemical_reaction/recipe/vodka2 +/decl/chemical_reaction/recipe/vodka2 name = "Turnip Vodka" - result = /decl/material/liquid/ethanol/vodka + result = /decl/material/liquid/alcohol/vodka required_reagents = list(/decl/material/liquid/drink/juice/turnip = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a crystal clear liquid." -/datum/chemical_reaction/recipe/sake +/decl/chemical_reaction/recipe/sake name = "Sake" - result = /decl/material/liquid/ethanol/sake + result = /decl/material/liquid/alcohol/sake required_reagents = list(/decl/material/liquid/nutriment/rice = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a crystal clear liquid." -/datum/chemical_reaction/recipe/kahlua +/decl/chemical_reaction/recipe/kahlua name = "Kahlua" - result = /decl/material/liquid/ethanol/coffee/kahlua + result = /decl/material/liquid/alcohol/coffee required_reagents = list(/decl/material/liquid/drink/coffee = 5, /decl/material/liquid/nutriment/sugar = 5) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 5 mix_message = "The solution roils as it rapidly ferments into a rich brown liquid." -/datum/chemical_reaction/recipe/irish_cream +/decl/chemical_reaction/recipe/irish_cream name = "Irish Cream" - result = /decl/material/liquid/ethanol/irish_cream - required_reagents = list(/decl/material/liquid/ethanol/whiskey = 2, /decl/material/liquid/drink/milk/cream = 1) + result = /decl/material/liquid/alcohol/irish_cream + required_reagents = list(/decl/material/liquid/alcohol/whiskey = 2, /decl/material/liquid/drink/milk/cream = 1) result_amount = 3 -/datum/chemical_reaction/recipe/hooch +/decl/chemical_reaction/recipe/hooch name = "Hooch" - result = /decl/material/liquid/ethanol/hooch - required_reagents = list (/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/ethanol = 2, /decl/material/liquid/fuel = 1) + result = /decl/material/liquid/alcohol/hooch + required_reagents = list (/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/alcohol/ethanol = 2, /decl/material/liquid/fuel = 1) minimum_temperature = 30 CELSIUS maximum_temperature = (30 CELSIUS) + 100 result_amount = 3 -/datum/chemical_reaction/recipe/mead +/decl/chemical_reaction/recipe/mead name = "Mead" - result = /decl/material/liquid/ethanol/mead + result = /decl/material/liquid/alcohol/mead required_reagents = list(/decl/material/liquid/nutriment/honey = 1, /decl/material/liquid/water = 1) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 2 -/datum/chemical_reaction/recipe/rum - name = "Rum" - result = /decl/material/liquid/ethanol/rum +/decl/chemical_reaction/recipe/rum + name = "Dark Rum" + result = /decl/material/liquid/alcohol/rum required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/water = 1) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 2 mix_message = "The solution roils as it rapidly ferments into a red-brown liquid." -/datum/chemical_reaction/recipe/applecider +/decl/chemical_reaction/recipe/cider_apple name = "Apple Cider" - result = /decl/material/liquid/ethanol/applecider + result = /decl/material/liquid/alcohol/cider_apple required_reagents = list(/decl/material/liquid/drink/juice/apple = 2, /decl/material/liquid/nutriment/sugar = 1) - catalysts = list(/decl/material/liquid/nutriment = 5) + catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 3 -/datum/chemical_reaction/recipe/kvass +/decl/chemical_reaction/recipe/cider_pear + name = "Pear Cider" + result = /decl/material/liquid/alcohol/cider_pear + required_reagents = list(/decl/material/liquid/drink/juice/pear = 2, /decl/material/liquid/nutriment/sugar = 1) + catalysts = list(/decl/material/liquid/enzyme = 5) + result_amount = 3 + +/decl/chemical_reaction/recipe/kvass name = "Kvass" - result = /decl/material/liquid/ethanol/kvass - required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/ethanol/beer = 1) + result = /decl/material/liquid/alcohol/kvass + required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/alcohol/beer = 1) catalysts = list(/decl/material/liquid/enzyme = 5) - result_amount = 3 \ No newline at end of file + result_amount = 3 diff --git a/code/modules/reagents/reactions/reaction_alloys.dm b/code/modules/reagents/reactions/reaction_alloys.dm new file mode 100644 index 000000000000..61bd616d6a8b --- /dev/null +++ b/code/modules/reagents/reactions/reaction_alloys.dm @@ -0,0 +1,88 @@ +/decl/chemical_reaction/alloy + minimum_temperature = GENERIC_SMELTING_HEAT_POINT + maximum_temperature = INFINITY + reaction_sound = null + mix_message = null + reaction_category = REACTION_TYPE_ALLOYING + abstract_type = /decl/chemical_reaction/alloy + +/decl/chemical_reaction/alloy/borosilicate + name = "Borosilicate Glass" + result = /decl/material/solid/glass/borosilicate + required_reagents = list( + /decl/material/solid/glass = 2, + /decl/material/solid/metal/platinum = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/alloy/steel + name = "Carbon Steel Alloy" + result = /decl/material/solid/metal/steel + required_reagents = list( + /decl/material/solid/metal/iron = 1, + /decl/material/solid/graphite = 1 + ) + result_amount = 2 + +/decl/chemical_reaction/alloy/plasteel + name = "Plasteel Alloy" + result = /decl/material/solid/metal/plasteel + required_reagents = list( + /decl/material/solid/metal/steel = 2, + /decl/material/solid/metal/platinum = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/alloy/ocp + name = "Osmium Carbide Plasteel" + result = /decl/material/solid/metal/plasteel/ocp + required_reagents = list( + /decl/material/solid/metal/plasteel = 2, + /decl/material/solid/metal/osmium = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/alloy/bronze + name = "Bronze Alloy" + result = /decl/material/solid/metal/bronze + required_reagents = list( + /decl/material/solid/metal/copper = 4, + /decl/material/solid/metal/tin = 1 + ) + result_amount = 5 + +/decl/chemical_reaction/alloy/brass + name = "Brass Alloy" + result = /decl/material/solid/metal/brass + required_reagents = list( + /decl/material/solid/metal/copper = 2, + /decl/material/solid/metal/zinc = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/alloy/blackbronze + name = "Black Bronze Billon" + result = /decl/material/solid/metal/blackbronze + required_reagents = list( + /decl/material/solid/metal/copper = 2, + /decl/material/solid/metal/silver = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/alloy/redgold + name = "Red Gold Billon" + result = /decl/material/solid/metal/redgold + required_reagents = list( + /decl/material/solid/metal/copper = 2, + /decl/material/solid/metal/gold = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/alloy/stainlesssteel + name = "Stainless Steel Alloy" + result = /decl/material/solid/metal/stainlesssteel + required_reagents = list( + /decl/material/solid/metal/steel = 9, + /decl/material/solid/metal/chromium = 1 + ) + result_amount = 10 \ No newline at end of file diff --git a/code/modules/reagents/reactions/reaction_cafe.dm b/code/modules/reagents/reactions/reaction_cafe.dm index a697b640b8da..edc1b31dcb86 100644 --- a/code/modules/reagents/reactions/reaction_cafe.dm +++ b/code/modules/reagents/reactions/reaction_cafe.dm @@ -1,39 +1,40 @@ -/datum/chemical_reaction/recipe/cafe +/decl/chemical_reaction/recipe/cafe hidden_from_codex = FALSE + abstract_type = /decl/chemical_reaction/recipe/cafe -/datum/chemical_reaction/recipe/cafe/coffee - name = "Coffee" +/decl/chemical_reaction/recipe/cafe/coffee + name = "Brewed Coffee" result = /decl/material/liquid/drink/coffee required_reagents = list(/decl/material/liquid/water = 5, /decl/material/liquid/nutriment/coffee = 1) result_amount = 5 minimum_temperature = 70 CELSIUS maximum_temperature = (70 CELSIUS) + 100 - mix_message = "The solution thickens into a steaming dark brown beverage." + mix_message = "The solution darkens to nearly black." -/datum/chemical_reaction/recipe/cafe/coffee/instant +/decl/chemical_reaction/recipe/cafe/coffee/instant name = "Instant Coffee" required_reagents = list(/decl/material/liquid/water = 5, /decl/material/liquid/nutriment/coffee/instant = 1) maximum_temperature = INFINITY minimum_temperature = 0 - mix_message = "The solution thickens into dark brown beverage." + mix_message = "The solution darkens to nearly black." -/datum/chemical_reaction/recipe/cafe/tea - name = "Black tea" +/decl/chemical_reaction/recipe/cafe/tea + name = "Steeped Black tea" result = /decl/material/liquid/drink/tea/black required_reagents = list(/decl/material/liquid/water = 5, /decl/material/liquid/nutriment/tea = 1) result_amount = 5 minimum_temperature = 70 CELSIUS maximum_temperature = (70 CELSIUS) + 100 - mix_message = "The solution thickens into a steaming black beverage." + mix_message = "The solution darkens to a rich brown." -/datum/chemical_reaction/recipe/cafe/tea/instant +/decl/chemical_reaction/recipe/cafe/tea/instant name = "Instant Black tea" required_reagents = list(/decl/material/liquid/water = 5, /decl/material/liquid/nutriment/tea/instant = 1) maximum_temperature = INFINITY minimum_temperature = 0 - mix_message = "The solution thickens into black beverage." + mix_message = "The solution darkens to a rich brown." -/datum/chemical_reaction/recipe/cafe/hot_coco +/decl/chemical_reaction/recipe/cafe/hot_coco name = "Hot Coco" result = /decl/material/liquid/drink/hot_coco required_reagents = list(/decl/material/liquid/water = 5, /decl/material/liquid/nutriment/coco = 1) diff --git a/code/modules/reagents/reactions/reaction_compounds.dm b/code/modules/reagents/reactions/reaction_compounds.dm new file mode 100644 index 000000000000..a334f65b6ff9 --- /dev/null +++ b/code/modules/reagents/reactions/reaction_compounds.dm @@ -0,0 +1,194 @@ +/decl/chemical_reaction/compound + abstract_type = /decl/chemical_reaction/compound + +/decl/chemical_reaction/compound/surfactant + name = "Azosurfactant" + result = /decl/material/liquid/surfactant + required_reagents = list(/decl/material/liquid/fuel/hydrazine = 2, /decl/material/solid/carbon = 2, /decl/material/liquid/acid = 1) + result_amount = 5 + mix_message = "The solution begins to foam gently." + +/decl/chemical_reaction/compound/space_cleaner + name = "Space cleaner" + result = /decl/material/liquid/cleaner + required_reagents = list(/decl/material/gas/ammonia = 1, /decl/material/liquid/water = 1) + mix_message = "The solution becomes slick and soapy." + result_amount = 2 + +/decl/chemical_reaction/compound/plantbgone + name = "Plant-B-Gone" + result = /decl/material/liquid/weedkiller + required_reagents = list( + /decl/material/liquid/bromide = 1, + /decl/material/liquid/water = 4 + ) + result_amount = 5 + +/decl/chemical_reaction/compound/foaming_agent + name = "Foaming Agent" + result = /decl/material/liquid/foaming_agent + required_reagents = list(/decl/material/solid/lithium = 1, /decl/material/liquid/fuel/hydrazine = 1) + result_amount = 1 + mix_message = "The solution begins to foam vigorously." + +/decl/chemical_reaction/compound/sodiumchloride + name = "Sodium Chloride" + result = /decl/material/solid/sodiumchloride + required_reagents = list(/decl/material/solid/sodium = 1, /decl/material/liquid/acid/hydrochloric = 1) + result_amount = 2 + +/decl/chemical_reaction/compound/hair_remover + name = "Hair Remover" + result = /decl/material/liquid/hair_remover + required_reagents = list(/decl/material/solid/metal/radium = 1, /decl/material/solid/potassium = 1, /decl/material/liquid/acid/hydrochloric = 1) + result_amount = 3 + mix_message = "The solution thins out and emits an acrid smell." + +/decl/chemical_reaction/compound/methyl_bromide + name = "Methyl Bromide" + required_reagents = list( + /decl/material/liquid/bromide = 1, + /decl/material/liquid/alcohol/ethanol = 1, + /decl/material/liquid/fuel/hydrazine = 1 + ) + result_amount = 3 + result = /decl/material/gas/methyl_bromide + mix_message = "The solution begins to bubble, emitting a dark vapor." + +/decl/chemical_reaction/compound/luminol + name = "Luminol" + result = /decl/material/liquid/luminol + required_reagents = list(/decl/material/liquid/fuel/hydrazine = 2, /decl/material/solid/carbon = 2, /decl/material/gas/ammonia = 2) + result_amount = 6 + mix_message = "The solution begins to gleam with a fey inner light." + +/decl/chemical_reaction/compound/anfo + name = "Fertilizer ANFO" + result = /decl/material/liquid/anfo + required_reagents = list( + /decl/material/liquid/fertilizer = 20, + /decl/material/liquid/fuel = 10 + ) + result_amount = 15 + mix_message = "The solution gives off the eye-watering reek of spilled fertilizer and petroleum." + +/decl/chemical_reaction/compound/anfo4 + name = "Chemlab ANFO" + result = /decl/material/liquid/anfo + required_reagents = list( + /decl/material/gas/ammonia = 10, + /decl/material/liquid/fuel = 5 + ) + result_amount = 15 + mix_message = "The solution gives off the eye-watering reek of spilled fertilizer and petroleum." + +/decl/chemical_reaction/compound/anfo_plus + name = "ANFO+" + result = /decl/material/liquid/anfo/plus + required_reagents = list( + /decl/material/liquid/anfo = 15, + /decl/material/solid/metal/aluminium = 5 + ) + result_amount = 20 + mix_message = "The solution gives off the eye-watering reek of spilled fertilizer and petroleum." + +/decl/chemical_reaction/compound/crystal_agent + name = "Crystallizing Agent" + result = /decl/material/liquid/crystal_agent + required_reagents = list(/decl/material/solid/silicon = 1, /decl/material/solid/metal/tungsten = 1, /decl/material/liquid/acid/polyacid = 1) + minimum_temperature = 150 CELSIUS + maximum_temperature = 200 CELSIUS + result_amount = 3 + +/decl/chemical_reaction/compound/paint + name = "Paint" + result = /decl/material/liquid/paint + required_reagents = list(/decl/material/liquid/plasticide = 1, /decl/material/liquid/water = 3) + result_amount = 5 + mix_message = "The solution thickens and takes on a glossy sheen." + +/decl/chemical_reaction/compound/paint_stripper + name = "Paint Stripper" + //TODO: some way to mix chlorine and methane to make proper paint stripper. + required_reagents = list(/decl/material/liquid/acetone = 2, /decl/material/liquid/acid = 2) + result = /decl/material/liquid/paint_stripper + result_amount = 4 + mix_message = "The mixture thins and clears." + +/decl/chemical_reaction/compound/contaminant_cleaner + name = "Akaline Detergent" + result = /decl/material/liquid/contaminant_cleaner + required_reagents = list(/decl/material/solid/sodium = 1, /decl/material/liquid/surfactant = 1) + result_amount = 2 + +/decl/chemical_reaction/compound/lube + name = "Lubricant" + result = /decl/material/liquid/lube + required_reagents = list(/decl/material/liquid/water = 1, /decl/material/solid/silicon = 1, /decl/material/liquid/acetone = 1) + result_amount = 3 + mix_message = "The solution becomes thick and slimy." + +/decl/chemical_reaction/compound/pacid + name = "Polytrinic acid" + result = /decl/material/liquid/acid/polyacid + required_reagents = list(/decl/material/liquid/acid = 1, /decl/material/liquid/acid/hydrochloric = 1, /decl/material/solid/potassium = 1) + result_amount = 3 + +/decl/chemical_reaction/compound/sulfuric_acid + name = "Oil of Vitriol" + result = /decl/material/liquid/acid + required_reagents = list(/decl/material/solid/pyrite = 2, /decl/material/solid/sodiumchloride = 2) + mix_message = "The solution turns a bright red and gives off harsh fumes." + minimum_temperature = 500 CELSIUS + result_amount = 2 + +/decl/chemical_reaction/compound/sulfuric_acid/pure + name = "Sulfuric Acid" + required_reagents = list(/decl/material/solid/sulfur = 1, /decl/material/solid/sodium = 2) + result_amount = 3 + +/decl/chemical_reaction/compound/condensed_capsaicin + name = "Condensed Capsaicin" + minimum_temperature = 100 CELSIUS + maximum_temperature = 200 CELSIUS // To avoid cooking chili creating condensed capsaicin. + mix_message = "darkens and thickens as it separates from its water content" + required_reagents = list(/decl/material/liquid/capsaicin = 2) + result = list(/decl/material/liquid/capsaicin/condensed = 1) + +/decl/chemical_reaction/compound/condensed_capsaicin/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + . = ..() + holder?.add_reagent(/decl/material/liquid/water, created_volume) + +/decl/chemical_reaction/compound/nanitefluid + name = "Nanite Fluid Synthesis" + result = /decl/material/liquid/nanitefluid + required_reagents = list(/decl/material/liquid/plasticide = 1, /decl/material/solid/metal/aluminium = 1, /decl/material/liquid/lube = 1) + catalysts = list(/decl/material/liquid/crystal_agent = 1) + result_amount = 3 + minimum_temperature = (-25 CELSIUS) - 100 + maximum_temperature = -25 CELSIUS + mix_message = "The solution becomes a metallic slime." + +// This is a bit silly, but we need a way to unify oil types until someone rewrites lanterns. +/decl/chemical_reaction/compound/fuel_oil + name = "Plant Fuel Oil" + result = /decl/material/liquid/oil + result_amount = 3 + required_reagents = list( + /decl/material/liquid/oil/plant = 2, + /decl/material/solid/graphite = 1 + ) + +/decl/chemical_reaction/compound/fuel_oil/corn + name = "Corn Fuel Oil" + required_reagents = list( + /decl/material/liquid/oil/plant/corn = 2, + /decl/material/solid/graphite = 1 + ) + +/decl/chemical_reaction/compound/fuel_oil/fish + name = "Fish Fuel Oil" + required_reagents = list( + /decl/material/liquid/oil/fish = 2, + /decl/material/solid/graphite = 1 + ) diff --git a/code/modules/reagents/reactions/reaction_drinks.dm b/code/modules/reagents/reactions/reaction_drinks.dm index f7853b7f5de7..663a7e7e05b1 100644 --- a/code/modules/reagents/reactions/reaction_drinks.dm +++ b/code/modules/reagents/reactions/reaction_drinks.dm @@ -1,41 +1,41 @@ -/datum/chemical_reaction/recipe/mutagen_cola +/decl/chemical_reaction/recipe/mutagen_cola name = "Mutagen Cola" result = /decl/material/liquid/drink/mutagencola required_reagents = list(/decl/material/liquid/mutagenics = 1, /decl/material/liquid/drink/cola = 5) result_amount = 5 mix_message = "The solution bubbles and emits an eerie green glow." -/datum/chemical_reaction/recipe/grapesoda +/decl/chemical_reaction/recipe/grapesoda name = "Grape Soda" result = /decl/material/liquid/drink/grapesoda required_reagents = list(/decl/material/liquid/drink/juice/grape = 2, /decl/material/liquid/drink/cola = 1) result_amount = 3 -/datum/chemical_reaction/recipe/lemonade +/decl/chemical_reaction/recipe/lemonade name = "Lemonade" result = /decl/material/liquid/drink/lemonade required_reagents = list(/decl/material/liquid/drink/juice/lemon = 1, /decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/water = 1) result_amount = 3 -/datum/chemical_reaction/recipe/citrusseltzer +/decl/chemical_reaction/recipe/citrusseltzer name = "Citrus Seltzer" result = /decl/material/liquid/drink/citrusseltzer required_reagents = list(/decl/material/liquid/drink/juice/orange = 1, /decl/material/liquid/drink/juice/lime = 1, /decl/material/liquid/drink/sodawater = 1) result_amount = 3 -/datum/chemical_reaction/recipe/orangecola +/decl/chemical_reaction/recipe/orangecola name = "Orange Cola" result = /decl/material/liquid/drink/orangecola required_reagents = list(/decl/material/liquid/drink/juice/orange = 2, /decl/material/liquid/drink/cola = 1) result_amount = 3 -/datum/chemical_reaction/recipe/milkshake +/decl/chemical_reaction/recipe/milkshake name = "Milkshake" result = /decl/material/liquid/drink/milkshake required_reagents = list(/decl/material/liquid/drink/milk/cream = 1, /decl/material/solid/ice = 2, /decl/material/liquid/drink/milk = 2) result_amount = 5 -/datum/chemical_reaction/recipe/chocolate_milk +/decl/chemical_reaction/recipe/chocolate_milk name = "Chocolate Milk" result = /decl/material/liquid/drink/milk/chocolate required_reagents = list(/decl/material/liquid/drink/milk = 5, /decl/material/liquid/nutriment/coco = 1) @@ -43,10 +43,19 @@ mix_message = "The solution thickens into a creamy brown beverage." maximum_temperature = 70 CELSIUS -/datum/chemical_reaction/recipe/kefir +/decl/chemical_reaction/recipe/kefir name = "Kefir" result = /decl/material/liquid/drink/kefir required_reagents = list(/decl/material/liquid/drink/milk = 2, /decl/material/liquid/drink/milk/cream = 1) result_amount = 3 catalysts = list(/decl/material/liquid/nutriment = 1) - mix_message = "The milk ferments into kefir" \ No newline at end of file + mix_message = "The milk ferments into kefir." + +/decl/chemical_reaction/recipe/compote + name = "Compote" + result = /decl/material/liquid/drink/compote + required_reagents = list(/decl/material/liquid/water = 2, /decl/material/liquid/drink/juice/berry = 1, /decl/material/liquid/drink/juice/apple = 1, /decl/material/liquid/drink/juice/pear = 1) + result_amount = 5 + mix_message = "The mixture turns a soft orange, bubbling faintly." + minimum_temperature = 40 CELSIUS + maximum_temperature = (40 CELSIUS) diff --git a/code/modules/reagents/reactions/reaction_drinks_hidden.dm b/code/modules/reagents/reactions/reaction_drinks_hidden.dm index 017e79a69865..b19f0e9534cc 100644 --- a/code/modules/reagents/reactions/reaction_drinks_hidden.dm +++ b/code/modules/reagents/reactions/reaction_drinks_hidden.dm @@ -1,26 +1,27 @@ -/datum/chemical_reaction/recipe/rehydrate +/decl/chemical_reaction/recipe/rehydrate result_amount = 3 hidden_from_codex = TRUE + abstract_type = /decl/chemical_reaction/recipe/rehydrate -/datum/chemical_reaction/recipe/rehydrate/grapejuice +/decl/chemical_reaction/recipe/rehydrate/grapejuice name = "Grape Juice" result = /decl/material/liquid/drink/juice/grape required_reagents = list(/decl/material/liquid/water = 3, /decl/material/liquid/nutriment/instantjuice/grape = 1) mix_message = "The solution settles into a purplish-red beverage." -/datum/chemical_reaction/recipe/rehydrate/orangejuice +/decl/chemical_reaction/recipe/rehydrate/orangejuice name = "Orange Juice" result = /decl/material/liquid/drink/juice/orange required_reagents = list(/decl/material/liquid/water = 3, /decl/material/liquid/nutriment/instantjuice/orange = 1) mix_message = "The solution settles into an orange beverage." -/datum/chemical_reaction/recipe/rehydrate/watermelonjuice +/decl/chemical_reaction/recipe/rehydrate/watermelonjuice name = "Watermelon Juice" result = /decl/material/liquid/drink/juice/watermelon required_reagents = list(/decl/material/liquid/water = 3, /decl/material/liquid/nutriment/instantjuice/watermelon = 1) mix_message = "The solution settles into a red beverage." -/datum/chemical_reaction/recipe/rehydrate/applejuice +/decl/chemical_reaction/recipe/rehydrate/applejuice name = "Apple Juice" result = /decl/material/liquid/drink/juice/apple required_reagents = list(/decl/material/liquid/water = 3, /decl/material/liquid/nutriment/instantjuice/apple = 1) diff --git a/code/modules/reagents/reactions/reaction_drugs.dm b/code/modules/reagents/reactions/reaction_drugs.dm index ef2e52567ac7..8f0c839b3b0f 100644 --- a/code/modules/reagents/reactions/reaction_drugs.dm +++ b/code/modules/reagents/reactions/reaction_drugs.dm @@ -1,28 +1,46 @@ -/datum/chemical_reaction/antitoxins +/decl/chemical_reaction/drug + abstract_type = /decl/chemical_reaction/drug + reaction_category = REACTION_TYPE_PHARMACEUTICAL + +/decl/chemical_reaction/drug/antitoxins name = "Antitoxins" result = /decl/material/liquid/antitoxins required_reagents = list(/decl/material/solid/silicon = 1, /decl/material/solid/potassium = 1, /decl/material/gas/ammonia = 1) result_amount = 3 -/datum/chemical_reaction/painkillers - name = "Painkillers" +/decl/chemical_reaction/drug/painkillers + name = "Mild Painkillers" result = /decl/material/liquid/painkillers - required_reagents = list(/decl/material/liquid/stabilizer = 1, /decl/material/liquid/ethanol = 1, /decl/material/liquid/acetone = 1) + required_reagents = list( + /decl/material/liquid/painkillers/strong = 1, + /decl/material/liquid/water = 1, + /decl/material/liquid/nutriment/sugar = 1 + ) result_amount = 3 -/datum/chemical_reaction/antiseptic +/decl/chemical_reaction/drug/strong_painkillers + name = "Strong Painkillers" + result = /decl/material/liquid/painkillers/strong + required_reagents = list( + /decl/material/liquid/stabilizer = 1, + /decl/material/liquid/alcohol/ethanol = 1, + /decl/material/liquid/acetone = 1 + ) + result_amount = 3 + +/decl/chemical_reaction/drug/antiseptic name = "Antiseptic" result = /decl/material/liquid/antiseptic - required_reagents = list(/decl/material/liquid/ethanol = 1, /decl/material/liquid/antitoxins = 1, /decl/material/liquid/acid/hydrochloric = 1) + required_reagents = list(/decl/material/liquid/alcohol/ethanol = 1, /decl/material/liquid/antitoxins = 1, /decl/material/liquid/acid/hydrochloric = 1) result_amount = 3 -/datum/chemical_reaction/mutagenics +/decl/chemical_reaction/drug/mutagenics name = "Unstable mutagen" result = /decl/material/liquid/mutagenics required_reagents = list(/decl/material/solid/metal/radium = 1, /decl/material/solid/phosphorus = 1, /decl/material/liquid/acid/hydrochloric = 1) result_amount = 3 -/datum/chemical_reaction/psychoactives +/decl/chemical_reaction/drug/psychoactives name = "Psychoactives" result = /decl/material/liquid/psychoactives required_reagents = list(/decl/material/liquid/mercury = 1, /decl/material/liquid/nutriment/sugar = 1, /decl/material/solid/lithium = 1) @@ -30,39 +48,25 @@ minimum_temperature = 50 CELSIUS maximum_temperature = (50 CELSIUS) + 100 -/datum/chemical_reaction/lube - name = "Lubricant" - result = /decl/material/liquid/lube - required_reagents = list(/decl/material/liquid/water = 1, /decl/material/solid/silicon = 1, /decl/material/liquid/acetone = 1) - result_amount = 4 - mix_message = "The solution becomes thick and slimy." - -/datum/chemical_reaction/pacid - name = "Polytrinic acid" - result = /decl/material/liquid/acid/polyacid - required_reagents = list(/decl/material/liquid/acid = 1, /decl/material/liquid/acid/hydrochloric = 1, /decl/material/solid/potassium = 1) - result_amount = 3 - -/datum/chemical_reaction/antirads +/decl/chemical_reaction/drug/antirads name = "Anti-Radiation Medication" result = /decl/material/liquid/antirads required_reagents = list(/decl/material/solid/metal/radium = 1, /decl/material/liquid/antitoxins = 1) result_amount = 2 -/datum/chemical_reaction/narcotics +/decl/chemical_reaction/drug/narcotics name = "Narcotics" result = /decl/material/liquid/narcotics required_reagents = list(/decl/material/liquid/mercury = 1, /decl/material/liquid/acetone = 1, /decl/material/liquid/nutriment/sugar = 1) result_amount = 2 -/datum/chemical_reaction/burn_meds +/decl/chemical_reaction/drug/burn_meds name = "Anti-Burn Medication" result = /decl/material/liquid/burn_meds required_reagents = list(/decl/material/solid/silicon = 1, /decl/material/solid/carbon = 1) result_amount = 2 - log_is_important = 1 -/datum/chemical_reaction/presyncopics +/decl/chemical_reaction/drug/presyncopics name = "Presyncopics" result = /decl/material/liquid/presyncopics required_reagents = list(/decl/material/solid/potassium = 1, /decl/material/liquid/acetone = 1, /decl/material/liquid/nutriment/sugar = 1) @@ -70,82 +74,72 @@ maximum_temperature = 60 CELSIUS result_amount = 3 -/datum/chemical_reaction/regenerator +/decl/chemical_reaction/drug/regenerator name = "Regenerative Serum" result = /decl/material/liquid/regenerator required_reagents = list(/decl/material/liquid/stabilizer = 1, /decl/material/liquid/antitoxins = 1) result_amount = 2 -/datum/chemical_reaction/neuroannealer +/decl/chemical_reaction/drug/neuroannealer name = "Neuroannealer" result = /decl/material/liquid/neuroannealer required_reagents = list(/decl/material/liquid/acid/hydrochloric = 1, /decl/material/gas/ammonia = 1, /decl/material/liquid/antitoxins = 1) result_amount = 2 -/datum/chemical_reaction/oxy_meds +/decl/chemical_reaction/drug/oxy_meds name = "Oxygen Deprivation Medication" result = /decl/material/liquid/oxy_meds required_reagents = list(/decl/material/liquid/acetone = 1, /decl/material/liquid/water = 1, /decl/material/solid/sulfur = 1) result_amount = 1 -/datum/chemical_reaction/brute_meds +/decl/chemical_reaction/drug/brute_meds name = "Anti-Trauma Medication" result = /decl/material/liquid/brute_meds required_reagents = list(/decl/material/liquid/stabilizer = 1, /decl/material/solid/carbon = 1) inhibitors = list(/decl/material/liquid/nutriment/sugar = 1) // Messes up with adrenaline result_amount = 2 -/datum/chemical_reaction/amphetamines +/decl/chemical_reaction/drug/amphetamines name = "Amphetamines" result = /decl/material/liquid/amphetamines required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/solid/phosphorus = 1, /decl/material/solid/sulfur = 1) result_amount = 3 -/datum/chemical_reaction/retrovirals +/decl/chemical_reaction/drug/retrovirals name = "Retrovirals" result = /decl/material/liquid/retrovirals required_reagents = list(/decl/material/liquid/antirads = 1, /decl/material/solid/carbon = 1) result_amount = 2 -/datum/chemical_reaction/nanitefluid - name = "Nanite Fluid" - result = /decl/material/liquid/nanitefluid - required_reagents = list(/decl/material/liquid/plasticide = 1, /decl/material/solid/metal/aluminium = 1, /decl/material/liquid/lube = 1) - catalysts = list(/decl/material/liquid/crystal_agent = 1) - result_amount = 3 - minimum_temperature = (-25 CELSIUS) - 100 - maximum_temperature = -25 CELSIUS - mix_message = "The solution becomes a metallic slime." - -/datum/chemical_reaction/antibiotics +/decl/chemical_reaction/drug/antibiotics name = "Antibiotics" result = /decl/material/liquid/antibiotics required_reagents = list(/decl/material/liquid/presyncopics = 1, /decl/material/liquid/stabilizer = 1) result_amount = 2 -/datum/chemical_reaction/eyedrops +/decl/chemical_reaction/drug/eyedrops name = "Eye Drops" result = /decl/material/liquid/eyedrops required_reagents = list(/decl/material/solid/carbon = 1, /decl/material/liquid/fuel/hydrazine = 1, /decl/material/liquid/antitoxins = 1) result_amount = 2 -/datum/chemical_reaction/sedatives +/decl/chemical_reaction/drug/sedatives name = "Sedatives" result = /decl/material/liquid/sedatives - required_reagents = list(/decl/material/liquid/ethanol = 1, /decl/material/liquid/nutriment/sugar = 4 + required_reagents = list(/decl/material/liquid/alcohol/ethanol = 1, /decl/material/liquid/nutriment/sugar = 4 ) inhibitors = list( /decl/material/solid/phosphorus ) // Messes with the smoke result_amount = 5 -/datum/chemical_reaction/paralytics +/decl/chemical_reaction/drug/paralytics name = "Paralytics" result = /decl/material/liquid/paralytics - required_reagents = list(/decl/material/liquid/ethanol = 1, /decl/material/liquid/mercury = 2, /decl/material/liquid/fuel/hydrazine = 2) + required_reagents = list(/decl/material/liquid/alcohol/ethanol = 1, /decl/material/liquid/mercury = 2, /decl/material/liquid/fuel/hydrazine = 2) result_amount = 1 -/datum/chemical_reaction/zombiepowder +/decl/chemical_reaction/drug/zombiepowder name = "Zombie Powder" result = /decl/material/liquid/zombiepowder required_reagents = list(/decl/material/liquid/carpotoxin = 5, /decl/material/liquid/sedatives = 5, /decl/material/solid/metal/copper = 5) @@ -154,7 +148,7 @@ maximum_temperature = 99 CELSIUS mix_message = "The solution boils off to form a fine powder." -/datum/chemical_reaction/hallucinogenics +/decl/chemical_reaction/drug/hallucinogenics name = "Hallucinogenics" result = /decl/material/liquid/hallucinogenics required_reagents = list(/decl/material/solid/silicon = 1, /decl/material/liquid/fuel/hydrazine = 1, /decl/material/liquid/antitoxins = 1) @@ -163,84 +157,31 @@ minimum_temperature = 75 CELSIUS maximum_temperature = (75 CELSIUS) + 25 -/datum/chemical_reaction/surfactant - name = "Azosurfactant" - result = /decl/material/liquid/surfactant - required_reagents = list(/decl/material/liquid/fuel/hydrazine = 2, /decl/material/solid/carbon = 2, /decl/material/liquid/acid = 1) - result_amount = 5 - mix_message = "The solution begins to foam gently." - -/datum/chemical_reaction/space_cleaner - name = "Space cleaner" - result = /decl/material/liquid/cleaner - required_reagents = list(/decl/material/gas/ammonia = 1, /decl/material/liquid/water = 1) - result_amount = 2 - -/datum/chemical_reaction/plantbgone - name = "Plant-B-Gone" - result = /decl/material/liquid/weedkiller - required_reagents = list( - /decl/material/liquid/bromide = 1, - /decl/material/liquid/water = 4 - ) - result_amount = 5 - -/datum/chemical_reaction/foaming_agent - name = "Foaming Agent" - result = /decl/material/liquid/foaming_agent - required_reagents = list(/decl/material/solid/lithium = 1, /decl/material/liquid/fuel/hydrazine = 1) - result_amount = 1 - mix_message = "The solution begins to foam vigorously." - -/datum/chemical_reaction/sodiumchloride - name = "Sodium Chloride" - result = /decl/material/solid/mineral/sodiumchloride - required_reagents = list(/decl/material/solid/sodium = 1, /decl/material/liquid/acid/hydrochloric = 1) - result_amount = 2 - -/datum/chemical_reaction/stimulants +/decl/chemical_reaction/drug/stimulants name = "Stimulants" - result = /decl/material/liquid/stimulants + result = /decl/material/liquid/accumulated/stimulants required_reagents = list(/decl/material/liquid/hallucinogenics = 1, /decl/material/solid/lithium = 1) result_amount = 3 -/datum/chemical_reaction/antidepressants +/decl/chemical_reaction/drug/antidepressants name = "Antidepressants" - result = /decl/material/liquid/antidepressants + result = /decl/material/liquid/accumulated/antidepressants required_reagents = list(/decl/material/liquid/hallucinogenics = 1, /decl/material/solid/carbon = 1) result_amount = 3 -/datum/chemical_reaction/hair_remover - name = "Hair Remover" - result = /decl/material/liquid/hair_remover - required_reagents = list(/decl/material/solid/metal/radium = 1, /decl/material/solid/potassium = 1, /decl/material/liquid/acid/hydrochloric = 1) - result_amount = 3 - mix_message = "The solution thins out and emits an acrid smell." - -/datum/chemical_reaction/methyl_bromide - name = "Methyl Bromide" - required_reagents = list( - /decl/material/liquid/bromide = 1, - /decl/material/liquid/ethanol = 1, - /decl/material/liquid/fuel/hydrazine = 1 - ) - result_amount = 3 - result = /decl/material/gas/methyl_bromide - mix_message = "The solution begins to bubble, emitting a dark vapor." - -/datum/chemical_reaction/adrenaline +/decl/chemical_reaction/drug/adrenaline name = "Adrenaline" result = /decl/material/liquid/adrenaline required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/amphetamines = 1, /decl/material/liquid/oxy_meds = 1) result_amount = 3 -/datum/chemical_reaction/stabilizer +/decl/chemical_reaction/drug/stabilizer name = "Stabilizer" result = /decl/material/liquid/stabilizer required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/solid/carbon = 1, /decl/material/liquid/acetone = 1) result_amount = 3 -/datum/chemical_reaction/gleam +/decl/chemical_reaction/drug/gleam name = "Gleam" result = /decl/material/liquid/glowsap/gleam result_amount = 2 @@ -255,8 +196,26 @@ /decl/material/liquid/glowsap = 2 ) -/datum/chemical_reaction/immunobooster +/decl/chemical_reaction/drug/immunobooster + name = "Immunobooster" result = /decl/material/liquid/immunobooster required_reagents = list(/decl/material/liquid/presyncopics = 1, /decl/material/liquid/antitoxins = 1) minimum_temperature = 40 CELSIUS result_amount = 2 + +/decl/chemical_reaction/drug/clotting_agent + name = "Clotting Agent" + result = /decl/material/liquid/clotting_agent + required_reagents = list( + /decl/material/liquid/brute_meds = 1, + /decl/material/solid/metal/iron = 2, + /decl/material/liquid/carpotoxin = 1 + ) + result_amount = 2 + +/decl/chemical_reaction/drug/nanoblood + name = "Nanoblood" + result = /decl/material/liquid/nanoblood + required_reagents = list(/decl/material/liquid/nanitefluid = 1, /decl/material/solid/metal/iron = 1, /decl/material/liquid/blood = 1) + result_amount = 3 + mix_message = "The solution thickens slowly into a glossy liquid." diff --git a/code/modules/reagents/reactions/reaction_grenade_reaction.dm b/code/modules/reagents/reactions/reaction_grenade_reaction.dm index 01a7a703ef99..6c55a14c4c4f 100644 --- a/code/modules/reagents/reactions/reaction_grenade_reaction.dm +++ b/code/modules/reagents/reactions/reaction_grenade_reaction.dm @@ -1,63 +1,73 @@ -/datum/chemical_reaction/grenade_reaction +/decl/chemical_reaction/grenade_reaction result = null + abstract_type = /decl/chemical_reaction/grenade_reaction + result_amount = 1 + chemical_reaction_flags = CHEM_REACTION_FLAG_OVERFLOW_CONTAINER + reaction_category = REACTION_TYPE_COMPOUND -/datum/chemical_reaction/grenade_reaction/explosion_potassium +/decl/chemical_reaction/grenade_reaction/explosion_potassium name = "Explosion" lore_text = "Water and potassium are infamously and violently reactive, causing a large explosion on contact." required_reagents = list(/decl/material/liquid/water = 1, /decl/material/solid/potassium = 1) mix_message = "The solution bubbles vigorously!" -/datum/chemical_reaction/grenade_reaction/explosion_potassium/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/explosion_potassium/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/datum/effect/effect/system/reagents_explosion/e = new() - e.set_up(round (created_volume/10, 1), holder.my_atom, 0, 0) - if(isliving(holder.my_atom)) - e.amount *= 0.5 - var/mob/living/L = holder.my_atom - if(L.stat != DEAD) + var/atom/location = holder.get_reaction_loc(chemical_reaction_flags) + if(location) + var/datum/effect/effect/system/reagents_explosion/e = new() + e.set_up(round(created_volume/3, 1), location, 0, 0) + if(isliving(location)) e.amount *= 0.5 - e.start() + var/mob/living/L = location + if(L.stat != DEAD) + e.amount *= 0.5 + e.start() holder.clear_reagents() -/datum/chemical_reaction/grenade_reaction/flash_powder +/decl/chemical_reaction/grenade_reaction/flash_powder name = "Flash powder" lore_text = "This reaction causes a brief, blinding flash of light." required_reagents = list(/decl/material/solid/metal/aluminium = 1, /decl/material/solid/potassium = 1, /decl/material/solid/sulfur = 1 ) result_amount = null mix_message = "The solution bubbles vigorously!" -/datum/chemical_reaction/grenade_reaction/flash_powder/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/flash_powder/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, location) - s.start() - for(var/mob/living/carbon/M in viewers(world.view, location)) - if(M.eyecheck() < FLASH_PROTECTION_MODERATE) - switch(get_dist(M, location)) - if(0 to 3) - M.flash_eyes() - M.Weaken(15) - if(4 to 5) - M.flash_eyes() - M.Stun(5) - -/datum/chemical_reaction/grenade_reaction/emp_pulse - name = "EMP Pulse" + var/turf/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + spark_at(location, amount=2, cardinal_only = TRUE) + for(var/mob/living/M in viewers(world.view, location)) + if(M.eyecheck() < FLASH_PROTECTION_MODERATE) + switch(get_dist(M, location)) + if(0 to 3) + M.flash_eyes() + SET_STATUS_MAX(M, STAT_WEAK, 15) + if(4 to 5) + M.flash_eyes() + SET_STATUS_MAX(M, STAT_STUN, 5) + +/decl/chemical_reaction/grenade_reaction/emp_pulse + name = "Electromagnetic Pulse" lore_text = "This reaction causes an electromagnetic pulse that knocks out machinery in a sizable radius." - required_reagents = list(/decl/material/solid/metal/uranium = 1, /decl/material/solid/metal/iron = 1) // Yes, laugh, it's the best recipe I could think of that makes a little bit of sense + required_reagents = list( + /decl/material/solid/metal/uranium = 1, + /decl/material/solid/metal/iron = 1 + ) // Yes, laugh, it's the best recipe I could think of that makes a little bit of sense result_amount = 2 mix_message = "The solution bubbles vigorously!" + maximum_temperature = T100C -/datum/chemical_reaction/grenade_reaction/emp_pulse/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/emp_pulse/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) - // 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes. - // 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades. - empulse(location, round(created_volume / 24), round(created_volume / 14), 1) + var/turf/location = holder.get_reaction_loc(chemical_reaction_flags) + if(location) + // 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes. + // 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades. + empulse(location, round(created_volume / 24), round(created_volume / 14), 1) holder.clear_reagents() -/datum/chemical_reaction/grenade_reaction/flash_fire +/decl/chemical_reaction/grenade_reaction/flash_fire name = "Flash Fire" lore_text = "This mixture causes an immediate flash fire." required_reagents = list( @@ -69,79 +79,85 @@ reaction_sound = 'sound/items/Welder.ogg' mix_message = "The solution suddenly ignites!" -/datum/chemical_reaction/grenade_reaction/flash_fire/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/flash_fire/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/turf/location = get_turf(holder.my_atom.loc) + var/turf/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) if(istype(location)) location.assume_gas(/decl/material/gas/hydrogen, created_volume, FLAMMABLE_GAS_FLASHPOINT + 10) - var/datum/effect/effect/system/spark_spread/sparks = new - sparks.set_up(1, 1, location) - sparks.start() + spark_at(location, amount=1, cardinal_only = TRUE) -/datum/chemical_reaction/grenade_reaction/chemsmoke +/decl/chemical_reaction/grenade_reaction/chemsmoke name = "Chemical Smoke" lore_text = "This mixture causes a large cloud of smoke, which will be laden with the other chemicals present in the mixture when it reacted." required_reagents = list(/decl/material/solid/potassium = 1, /decl/material/liquid/nutriment/sugar = 1, /decl/material/solid/phosphorus = 1) result_amount = 0.4 mix_message = "The solution bubbles vigorously!" -/datum/chemical_reaction/grenade_reaction/chemsmoke/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/chemsmoke/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) - var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem - S.attach(location) - S.set_up(holder, created_volume, 0, location) - playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) - spawn(0) - S.start() + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem + S.attach(location) + S.set_up(holder, created_volume, 0, location) + playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) + spawn(0) + S.start() holder.clear_reagents() -/datum/chemical_reaction/grenade_reaction/foam - name = "Foam" +/decl/chemical_reaction/grenade_reaction/foam + name = "Expanding Foam" lore_text = "This mixture explodes in a burst of foam. Good for cleaning!" required_reagents = list(/decl/material/liquid/surfactant = 1, /decl/material/liquid/water = 1) result_amount = 2 mix_message = "The solution bubbles vigorously!" -/datum/chemical_reaction/grenade_reaction/foam/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/foam/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) - for(var/mob/M in viewers(5, location)) - to_chat(M, "The solution spews out foam!") - var/datum/effect/effect/system/foam_spread/s = new() - s.set_up(created_volume, location, holder, 0) - s.start() + var/turf/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + location.visible_message(SPAN_WARNING("The solution spews out foam!"), range = 5) + var/datum/effect/effect/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 0) + s.start() holder.clear_reagents() -/datum/chemical_reaction/grenade_reaction/metalfoam +/decl/chemical_reaction/grenade_reaction/metalfoam name = "Metal Foam" lore_text = "This mixture explodes in a burst of metallic foam. Good for hull repair!" - required_reagents = list(/decl/material/solid/metal/aluminium = 3, /decl/material/liquid/foaming_agent = 1, /decl/material/liquid/acid/polyacid = 1) + required_reagents = list(/decl/material/solid/metal/aluminium = 3, /decl/material/liquid/foaming_agent = 1, /decl/material/liquid/acid = 1) result_amount = 5 - mix_message = "The solution bubbles vigorously!" + mix_message = "The solution foams up violently!" -/datum/chemical_reaction/grenade_reaction/metalfoam/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/metalfoam/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) - for(var/mob/M in viewers(5, location)) - to_chat(M, "The solution spews out a metalic foam!") - var/datum/effect/effect/system/foam_spread/s = new() - s.set_up(created_volume, location, holder, 1) - s.start() - -/datum/chemical_reaction/grenade_reaction/ironfoam + var/atom/location = holder.get_reaction_loc(chemical_reaction_flags) + // This will overflow the container if it's open and create it in the turf + if(isturf(location)) + location.visible_message(SPAN_WARNING("The solution spews out a metallic foam!"), range = 5) + var/datum/effect/effect/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 1) + s.start() + // We failed to overflow the container, try to add it as a reagent + else if(location && REAGENT_MAXIMUM_VOLUME(location.reagents)) + location.reagents.add_reagent(/decl/material/liquid/foam, created_volume) + +/decl/chemical_reaction/grenade_reaction/ironfoam name = "Iron Foam" lore_text = "This mixture explodes in a burst of iron foam. Good for hull repair!" - required_reagents = list(/decl/material/solid/metal/iron = 3, /decl/material/liquid/foaming_agent = 1, /decl/material/liquid/acid/polyacid = 1) + required_reagents = list(/decl/material/solid/metal/iron = 3, /decl/material/liquid/foaming_agent = 1, /decl/material/liquid/acid = 1) result_amount = 5 mix_message = "The solution bubbles vigorously!" -/datum/chemical_reaction/grenade_reaction/ironfoam/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/grenade_reaction/ironfoam/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) - - for(var/mob/M in viewers(5, location)) - to_chat(M, "The solution spews out a metalic foam!") - var/datum/effect/effect/system/foam_spread/s = new() - s.set_up(created_volume, location, holder, 2) - s.start() + var/atom/location = holder.get_reaction_loc(chemical_reaction_flags) + // This will overflow the container if it's open and create it in the turf + if(isturf(location)) + location.visible_message(SPAN_WARNING("The solution spews out a metallic foam!"), range = 5) + var/datum/effect/effect/system/foam_spread/s = new() + s.set_up(created_volume, location, holder, 2) + s.start() + // We failed to overflow the container, try to add it as a reagent + else if(location && REAGENT_MAXIMUM_VOLUME(location.reagents)) + location.reagents.add_reagent(/decl/material/liquid/foam, created_volume) \ No newline at end of file diff --git a/code/modules/reagents/reactions/reaction_herbal.dm b/code/modules/reagents/reactions/reaction_herbal.dm new file mode 100644 index 000000000000..62950dd1d64c --- /dev/null +++ b/code/modules/reagents/reactions/reaction_herbal.dm @@ -0,0 +1,74 @@ +/decl/chemical_reaction/drug/herbal + abstract_type = /decl/chemical_reaction/drug/herbal + result_amount = 2 + minimum_temperature = 100 CELSIUS + +/decl/chemical_reaction/drug/herbal/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + . = ..() + // Add plant matter to represent the herbs that the medicine has been leached out of. + holder?.add_reagent(/decl/material/solid/organic/plantmatter, created_volume) + +/decl/chemical_reaction/drug/herbal/yarrow_tea + name = "yarrow tea" + required_reagents = list( + /decl/material/liquid/water = 1, + /decl/material/liquid/brute_meds/yarrow = 3 + ) + result = /decl/material/liquid/brute_meds/yarrow/tea + +/decl/chemical_reaction/drug/herbal/aloe_tea + name = "aloe tea" + required_reagents = list( + /decl/material/liquid/water = 1, + /decl/material/liquid/burn_meds/aloe = 3 + ) + result = /decl/material/liquid/burn_meds/aloe/tea + +/decl/chemical_reaction/drug/herbal/ginseng_tea + name = "ginseng tea" + required_reagents = list( + /decl/material/liquid/water = 1, + /decl/material/liquid/antitoxins/ginseng = 3 + ) + result = /decl/material/liquid/antitoxins/ginseng/tea + +/decl/chemical_reaction/drug/herbal/valerian_tea + name = "valerian tea" + required_reagents = list( + /decl/material/liquid/water = 1, + /decl/material/liquid/sedatives/valerian = 3 + ) + result = /decl/material/liquid/sedatives/valerian/tea + +// Tinctures are stronger but have side-effects from the alcohol. +/decl/chemical_reaction/drug/herbal/yarrow_tincture + name = "tincture of yarrow" + required_reagents = list( + /decl/material/liquid/alcohol/ethanol = 1, + /decl/material/liquid/brute_meds/yarrow = 3 + ) + result = /decl/material/liquid/brute_meds/yarrow/tincture + +/decl/chemical_reaction/drug/herbal/aloe_tincture + name = "tincture of aloe" + required_reagents = list( + /decl/material/liquid/alcohol/ethanol = 1, + /decl/material/liquid/burn_meds/aloe = 3 + ) + result = /decl/material/liquid/burn_meds/aloe/tincture + +/decl/chemical_reaction/drug/herbal/ginseng_tincture + name = "tincture of ginseng" + required_reagents = list( + /decl/material/liquid/alcohol/ethanol = 1, + /decl/material/liquid/antitoxins/ginseng = 3 + ) + result = /decl/material/liquid/antitoxins/ginseng/tincture + +/decl/chemical_reaction/drug/herbal/valerian_tincture + name = "tincture of valerian" + required_reagents = list( + /decl/material/liquid/alcohol/ethanol = 1, + /decl/material/liquid/sedatives/valerian = 3 + ) + result = /decl/material/liquid/sedatives/valerian/tincture diff --git a/code/modules/reagents/reactions/reaction_other.dm b/code/modules/reagents/reactions/reaction_other.dm index 8b4e1c40b164..dca52f041f62 100644 --- a/code/modules/reagents/reactions/reaction_other.dm +++ b/code/modules/reagents/reactions/reaction_other.dm @@ -1,76 +1,17 @@ -/datum/chemical_reaction/soap_key +/decl/chemical_reaction/soap_key name = "Soap Key" result = null required_reagents = list(/decl/material/liquid/frostoil = 2, /decl/material/liquid/cleaner = 5) hidden_from_codex = TRUE var/strength = 3 -/datum/chemical_reaction/soap_key/can_happen(var/datum/reagents/holder) - if(holder.my_atom && istype(holder.my_atom, /obj/item/soap)) +/decl/chemical_reaction/soap_key/can_happen(var/datum/reagents/holder) + if(istype(holder.get_reaction_loc(chemical_reaction_flags), /obj/item/soap)) return ..() return 0 -/datum/chemical_reaction/soap_key/on_reaction(var/datum/reagents/holder) - var/obj/item/soap/S = holder.my_atom - if(S.key_data) - var/obj/item/key/soap/key = new(get_turf(holder.my_atom), S.key_data) - key.uses = strength +/decl/chemical_reaction/soap_key/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + var/obj/item/soap/S = holder.get_reaction_loc(chemical_reaction_flags) + if(istype(S) && S.key_data) + new /obj/item/key/temporary(get_turf(S), /decl/material/liquid/cleaner, S.key_data, strength) ..() - -/datum/chemical_reaction/luminol - name = "Luminol" - result = /decl/material/liquid/luminol - required_reagents = list(/decl/material/liquid/fuel/hydrazine = 2, /decl/material/solid/carbon = 2, /decl/material/gas/ammonia = 2) - result_amount = 6 - mix_message = "The solution begins to gleam with a fey inner light." - -/datum/chemical_reaction/nanoblood - name = "Nanoblood" - result = /decl/material/liquid/nanoblood - required_reagents = list(/decl/material/liquid/nanitefluid = 1, /decl/material/solid/metal/iron = 1, /decl/material/liquid/blood = 1) - result_amount = 3 - mix_message = "The solution thickens slowly into a glossy liquid." - -/datum/chemical_reaction/anfo - name = "ANFO" - result = /decl/material/liquid/anfo - required_reagents = list( - /decl/material/liquid/fertilizer = 20, - /decl/material/liquid/fuel = 10 - ) - result_amount = 15 - mix_message = "The solution gives off the eye-watering reek of spilled fertilizer and petroleum." - -/datum/chemical_reaction/anfo4 - name = "Chemlab ANFO" - result = /decl/material/liquid/anfo - required_reagents = list( - /decl/material/gas/ammonia = 10, - /decl/material/liquid/fuel = 5 - ) - result_amount = 15 - mix_message = "The solution gives off the eye-watering reek of spilled fertilizer and petroleum." - -/datum/chemical_reaction/anfo_plus - name = "ANFO+" - result = /decl/material/liquid/anfo/plus - required_reagents = list( - /decl/material/liquid/anfo = 15, - /decl/material/solid/metal/aluminium = 5 - ) - result_amount = 20 - mix_message = "The solution gives off the eye-watering reek of spilled fertilizer and petroleum." - -/datum/chemical_reaction/crystal_agent - result = /decl/material/liquid/crystal_agent - required_reagents = list(/decl/material/solid/silicon = 1, /decl/material/solid/metal/tungsten = 1, /decl/material/liquid/acid/polyacid = 1) - minimum_temperature = 150 CELSIUS - maximum_temperature = 200 CELSIUS - result_amount = 3 - -/datum/chemical_reaction/paint - name = "Paint" - result = /decl/material/liquid/narcotics - required_reagents = list(/decl/material/liquid/plasticide = 1, /decl/material/liquid/water = 3) - result_amount = 5 - mix_message = "The solution thickens and takes on a glossy sheen." diff --git a/code/modules/reagents/reactions/reaction_recipe.dm b/code/modules/reagents/reactions/reaction_recipe.dm index c651ea0107bc..f7cd8bb17a5e 100644 --- a/code/modules/reagents/reactions/reaction_recipe.dm +++ b/code/modules/reagents/reactions/reaction_recipe.dm @@ -1,25 +1,25 @@ -/datum/chemical_reaction/recipe/soysauce +/decl/chemical_reaction/recipe/soysauce name = "Vinegar Soy Sauce" result = /decl/material/liquid/nutriment/soysauce required_reagents = list(/decl/material/liquid/drink/milk/soymilk = 5, /decl/material/liquid/nutriment/vinegar = 5) result_amount = 10 mix_message = "The solution settles into a glossy black sauce." -/datum/chemical_reaction/recipe/soysauce_acid +/decl/chemical_reaction/recipe/soysauce_acid name = "Acid Soy Sauce" result = /decl/material/liquid/nutriment/soysauce required_reagents = list(/decl/material/liquid/drink/milk/soymilk = 4, /decl/material/liquid/acid = 1) result_amount = 5 mix_message = "The solution settles into a glossy black sauce." -/datum/chemical_reaction/recipe/ketchup +/decl/chemical_reaction/recipe/ketchup name = "Ketchup" result = /decl/material/liquid/nutriment/ketchup required_reagents = list(/decl/material/liquid/drink/juice/tomato = 2, /decl/material/liquid/water = 1, /decl/material/liquid/nutriment/sugar = 1) result_amount = 4 mix_message = "The solution thickens into a sweet-smelling red sauce." -/datum/chemical_reaction/recipe/banana_cream +/decl/chemical_reaction/recipe/banana_cream name = "Banana Cream" result = /decl/material/liquid/nutriment/banana_cream catalysts = list(/decl/material/liquid/enzyme = 5) @@ -27,73 +27,84 @@ result_amount = 3 mix_message = "The solution thickens into a creamy banana-scented substance." -/datum/chemical_reaction/recipe/barbecue +/decl/chemical_reaction/recipe/barbecue name = "Barbecue Sauce" result = /decl/material/liquid/nutriment/barbecue - required_reagents = list(/decl/material/liquid/nutriment/ketchup = 2, /decl/material/solid/blackpepper = 1, /decl/material/solid/mineral/sodiumchloride = 1) + required_reagents = list(/decl/material/liquid/nutriment/ketchup = 2, /decl/material/solid/blackpepper = 1, /decl/material/solid/sodiumchloride = 1) result_amount = 4 mix_message = "The solution thickens into a sweet-smelling brown sauce." -/datum/chemical_reaction/recipe/garlicsauce +/decl/chemical_reaction/recipe/garlicsauce name = "Garlic Sauce" result = /decl/material/liquid/nutriment/garlicsauce - required_reagents = list(/decl/material/liquid/drink/juice/garlic = 1, /decl/material/liquid/nutriment/cornoil = 1) + required_reagents = list(/decl/material/liquid/drink/juice/garlic = 1, /decl/material/liquid/oil/plant/corn = 1) result_amount = 2 mix_message = "The solution thickens into a creamy white oil." //batter reaction as food precursor, for things that don't use pliable dough precursor. -/datum/chemical_reaction/recipe/batter - name = "Batter" +/decl/chemical_reaction/recipe/batter + name = "Plain Batter" result = /decl/material/liquid/nutriment/batter - required_reagents = list(/decl/material/liquid/nutriment/protein/egg = 3, /decl/material/liquid/nutriment/flour = 5, /decl/material/liquid/drink/milk = 5) + required_reagents = list( + /decl/material/solid/organic/meat/egg = 3, + /decl/material/liquid/nutriment/flour = 5, + /decl/material/liquid/drink/milk = 5 + ) result_amount = 10 mix_message = "The solution thickens into a glossy batter." -/datum/chemical_reaction/recipe/cakebatter +/decl/chemical_reaction/recipe/cakebatter name = "Cake Batter" result = /decl/material/liquid/nutriment/batter/cakebatter required_reagents = list(/decl/material/liquid/nutriment/sugar = 1, /decl/material/liquid/nutriment/batter = 2) result_amount = 3 mix_message = "The sugar lightens the batter and gives it a sweet smell." -/datum/chemical_reaction/recipe/soybatter +/decl/chemical_reaction/recipe/soybatter name = "Vegan Batter" result = /decl/material/liquid/nutriment/batter required_reagents = list(/decl/material/liquid/nutriment/plant_protein = 3, /decl/material/liquid/nutriment/flour = 5, /decl/material/liquid/drink/milk = 5) result_amount = 10 mix_message = "The solution thickens into a glossy batter." -/datum/chemical_reaction/recipe/vinegar +/decl/chemical_reaction/recipe/vinegar name = "Apple Vinegar" result = /decl/material/liquid/nutriment/vinegar required_reagents = list(/decl/material/liquid/drink/juice/apple = 10) catalysts = list(/decl/material/liquid/enzyme = 5) + inhibitors = list(/decl/material/liquid/nutriment/sugar = 1) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a sharp-smelling liquid." -/datum/chemical_reaction/recipe/vinegar2 +/decl/chemical_reaction/recipe/vinegar2 name = "Clear Vinegar" result = /decl/material/liquid/nutriment/vinegar - required_reagents = list(/decl/material/liquid/ethanol = 10) + required_reagents = list(/decl/material/liquid/alcohol/ethanol = 10) catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a sharp-smelling liquid." -/datum/chemical_reaction/recipe/mayo +/decl/chemical_reaction/recipe/mayo name = "Vinegar Mayo" result = /decl/material/liquid/nutriment/mayo - required_reagents = list(/decl/material/liquid/nutriment/vinegar = 5, /decl/material/liquid/nutriment/protein/egg = 5) + required_reagents = list( + /decl/material/liquid/nutriment/vinegar = 5, + /decl/material/solid/organic/meat/egg = 5 + ) result_amount = 10 mix_message = "The solution thickens into a glossy, creamy substance." -/datum/chemical_reaction/recipe/mayo2 +/decl/chemical_reaction/recipe/mayo2 name = "Lemon Mayo" result = /decl/material/liquid/nutriment/mayo - required_reagents = list(/decl/material/liquid/drink/juice/lemon = 5, /decl/material/liquid/nutriment/protein/egg = 5) + required_reagents = list( + /decl/material/liquid/drink/juice/lemon = 5, + /decl/material/solid/organic/meat/egg = 5 + ) result_amount = 10 mix_message = "The solution thickens into a glossy, creamy substance." -/datum/chemical_reaction/recipe/hot_ramen +/decl/chemical_reaction/recipe/hot_ramen name = "Hot Ramen" result = /decl/material/liquid/drink/hot_ramen required_reagents = list(/decl/material/liquid/water = 1, /decl/material/liquid/drink/dry_ramen = 3) @@ -101,7 +112,7 @@ mix_message = "The noodles soften in the hot water, releasing savoury steam." hidden_from_codex = TRUE -/datum/chemical_reaction/recipe/hell_ramen +/decl/chemical_reaction/recipe/hell_ramen name = "Hell Ramen" result = /decl/material/liquid/drink/hell_ramen required_reagents = list(/decl/material/liquid/capsaicin = 1, /decl/material/liquid/drink/hot_ramen = 6) @@ -109,9 +120,9 @@ mix_message = "The broth of the noodles takes on a hellish red gleam." hidden_from_codex = TRUE -/datum/chemical_reaction/recipe/chazuke - name = "Chazuke" - result = /decl/material/liquid/nutriment/rice/chazuke - required_reagents = list(/decl/material/liquid/nutriment/rice = 10, /decl/material/liquid/drink/tea/green = 1) - result_amount = 10 - mix_message = "The tea mingles with the rice." +/decl/chemical_reaction/recipe/horchata + name = "Horchata" + result = /decl/material/liquid/drink/horchata + required_reagents = list(/decl/material/liquid/nutriment/rice = 2, /decl/material/liquid/drink/milk = 2, /decl/material/liquid/drink/syrup/vanilla = 1, /decl/material/solid/cinnamon = 1) + result_amount = 6 + mix_message = "The ingredients combine to create a refreshing white beverage." diff --git a/code/modules/reagents/reactions/reaction_recipe_food.dm b/code/modules/reagents/reactions/reaction_recipe_food.dm index 4b8a3aaacd21..29f4e8824b35 100644 --- a/code/modules/reagents/reactions/reaction_recipe_food.dm +++ b/code/modules/reagents/reactions/reaction_recipe_food.dm @@ -1,65 +1,231 @@ -/datum/chemical_reaction/recipe/food +/decl/chemical_reaction/recipe/food result = null result_amount = 1 + abstract_type = /decl/chemical_reaction/recipe/food var/obj_result -/datum/chemical_reaction/recipe/food/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/recipe/food/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/location = get_turf(holder.my_atom) + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) if(obj_result && isturf(location)) for(var/i = 1, i <= created_volume, i++) - new obj_result(location) + create_food(location, reaction_data) -/datum/chemical_reaction/recipe/food/cheesewheel - name = "Cheesewheel" +/decl/chemical_reaction/recipe/food/proc/create_food(location, list/data) + var/atom/movable/food = new obj_result + if(istype(food)) + food.dropInto(location) + if(length(data) && istype(food, /obj/item/food)) + var/obj/item/food/food_item = food + food_item.set_nutriment_data(data) + return food + +/decl/chemical_reaction/recipe/food/dairy + abstract_type = /decl/chemical_reaction/recipe/food/dairy + var/static/list/milk_data_keys = list( + DATA_MILK_DONOR, + DATA_MILK_NAME, + DATA_MILK_COLOR, + DATA_CHEESE_NAME, + DATA_CHEESE_COLOR + ) + +/decl/chemical_reaction/recipe/food/dairy/send_data(var/datum/reagents/holder, var/reaction_limit) + . = ..() + for(var/reagent in required_reagents) + var/list/data = REAGENT_DATA(holder, reagent) + if(!islist(data)) + continue + for(var/milk_key in milk_data_keys) + var/milk_val = data[milk_key] + if(isnull(milk_val)) + continue + LAZYSET(., milk_key, milk_val) + +/decl/chemical_reaction/recipe/food/dairy/butter + name = "Enzyme Butter" + required_reagents = list( + /decl/material/solid/sodiumchloride = 1, + /decl/material/liquid/drink/milk/cream = 20 + ) + catalysts = list(/decl/material/liquid/enzyme = 5) + mix_message = "The solution thickens and curdles into a buttery yellow solid." + minimum_temperature = 40 CELSIUS + maximum_temperature = (40 CELSIUS) + 100 + obj_result = /obj/item/food/dairy/butter/stick + +/decl/chemical_reaction/recipe/food/dairy/margarine + name = "Enzyme Margarine" + required_reagents = list( + /decl/material/solid/sodiumchloride = 1, + /decl/material/liquid/oil/plant = 20 + ) + catalysts = list(/decl/material/liquid/enzyme = 5) + mix_message = "The solution thickens and curdles into a pale yellow solid." + minimum_temperature = 40 CELSIUS + maximum_temperature = (40 CELSIUS) + 100 + obj_result = /obj/item/food/dairy/butter/stick/margarine + +/decl/chemical_reaction/recipe/food/dairy/cheesewheel + name = "Enzyme Cheesewheel" required_reagents = list(/decl/material/liquid/drink/milk = 40) catalysts = list(/decl/material/liquid/enzyme = 5) - mix_message = "The solution thickens and curdles into a rich yellow substance." + mix_message = "The solution thickens and curdles into a rich yellow solid." minimum_temperature = 40 CELSIUS maximum_temperature = (40 CELSIUS) + 100 - obj_result = /obj/item/chems/food/snacks/sliceable/cheesewheel + obj_result = /obj/item/food/dairy/cheese/wheel + +/decl/chemical_reaction/recipe/food/dairy/cheesewheel/rennet + name = "Rennet Cheesewheel" + catalysts = list() + required_reagents = list( + /decl/material/liquid/drink/milk = 40, + /decl/material/liquid/enzyme/rennet = 3 + ) -/datum/chemical_reaction/recipe/food/rawmeatball +/decl/chemical_reaction/recipe/food/rawmeatball name = "Raw Meatball" - required_reagents = list(/decl/material/liquid/nutriment/protein = 3, /decl/material/liquid/nutriment/flour = 5) + required_reagents = list( + /decl/material/solid/organic/meat = 3, + /decl/material/liquid/nutriment/flour = 5 + ) result_amount = 3 mix_message = "The flour thickens the processed meat until it clumps." - obj_result = /obj/item/chems/food/snacks/rawmeatball + obj_result = /obj/item/food/meatball/raw -/datum/chemical_reaction/recipe/food/dough - name = "Dough" - required_reagents = list(/decl/material/liquid/nutriment/protein/egg = 3, /decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/water = 10) - mix_message = "The solution folds and thickens into a large ball of dough." - obj_result = /obj/item/chems/food/snacks/dough +/decl/chemical_reaction/recipe/food/piecrust + name = "Butter Pie Crust" + required_reagents = list( + /decl/material/liquid/nutriment/sugar = 1, + /decl/material/solid/sodiumchloride = 1, + /decl/material/liquid/nutriment/flour = 10, + /decl/material/liquid/water = 5, + /decl/material/liquid/nutriment/butter = 1 + ) + mix_message = "The solution smooths out into a pie crust." + obj_result = /obj/item/food/piecrust + // Trying to get the chemical recipe overlaps with dough sorted out. + maximum_temperature = 60 CELSIUS -/datum/chemical_reaction/recipe/food/soydough - name = "Soy dough" - required_reagents = list(/decl/material/liquid/nutriment/plant_protein = 3, /decl/material/liquid/nutriment/flour = 10, /decl/material/liquid/water = 10) - mix_message = "The solution folds and thickens into a large ball of dough." - obj_result = /obj/item/chems/food/snacks/dough +/decl/chemical_reaction/recipe/food/piecrust/margarine + name = "Shortening Pie Crust" + required_reagents = list( + /decl/material/liquid/nutriment/sugar = 1, + /decl/material/solid/sodiumchloride = 1, + /decl/material/liquid/nutriment/flour = 10, + /decl/material/liquid/water = 5, + /decl/material/liquid/nutriment/margarine = 1 + ) -/datum/chemical_reaction/recipe/food/syntiflesh +/decl/chemical_reaction/recipe/food/dough + name = "Dough (Leavened)" + required_reagents = list( + /decl/material/liquid/nutriment/yeast = 1, + /decl/material/liquid/nutriment/flour = 10, + /decl/material/liquid/water = 10 + ) + mix_message = "The solution rises into a large ball of leavened dough." + obj_result = /obj/item/food/dough + minimum_temperature = 60 CELSIUS + +/decl/chemical_reaction/recipe/food/dough/unleavened + name = "Dough (Unleavened)" + required_reagents = list( + /decl/material/solid/sodiumchloride = 1, + /decl/material/liquid/nutriment/flour = 10, + /decl/material/liquid/water = 10 + ) + mix_message = "The solution swells into a round of unleavened dough." + obj_result = /obj/item/food/sliceable/unleaveneddough + inhibitors = list(/decl/material/liquid/nutriment/yeast) + +/decl/chemical_reaction/recipe/food/syntiflesh name = "Synthetic Meat" required_reagents = list(/decl/material/liquid/blood = 5, /decl/material/liquid/plasticide = 1) mix_message = "The solution thickens disturbingly, taking on a meaty appearance." - obj_result = /obj/item/chems/food/snacks/meat/syntiflesh + obj_result = /obj/item/food/butchery/meat/syntiflesh -/datum/chemical_reaction/recipe/food/tofu +/decl/chemical_reaction/recipe/food/tofu name = "Tofu" required_reagents = list(/decl/material/liquid/drink/milk/soymilk = 10) catalysts = list(/decl/material/liquid/enzyme = 5) mix_message = "The solution thickens and clumps into a yellow-white substance." - obj_result = /obj/item/chems/food/snacks/tofu + obj_result = /obj/item/food/tofu -/datum/chemical_reaction/recipe/food/chocolate_bar +/decl/chemical_reaction/recipe/food/chocolate_bar name = "Soy Chocolate" required_reagents = list(/decl/material/liquid/drink/milk/soymilk = 2, /decl/material/liquid/nutriment/coco = 2, /decl/material/liquid/nutriment/sugar = 2) mix_message = "The solution thickens and hardens into a glossy brown substance." - obj_result = /obj/item/chems/food/snacks/chocolatebar + obj_result = /obj/item/food/chocolatebar -/datum/chemical_reaction/recipe/food/chocolate_bar2 +/decl/chemical_reaction/recipe/food/chocolate_bar2 name = "Milk Chocolate" required_reagents = list(/decl/material/liquid/drink/milk = 2, /decl/material/liquid/nutriment/coco = 2, /decl/material/liquid/nutriment/sugar = 2) mix_message = "The solution thickens and hardens into a glossy brown substance." - obj_result = /obj/item/chems/food/snacks/chocolatebar - minimum_temperature = 70 CELSIUS \ No newline at end of file + obj_result = /obj/item/food/chocolatebar + minimum_temperature = 70 CELSIUS + +/decl/chemical_reaction/recipe/food/stuffing + name = "Stuffing" + required_reagents = list( + /decl/material/liquid/water = 10, + /decl/material/solid/sodiumchloride = 1, + /decl/material/solid/blackpepper = 1, + /decl/material/liquid/nutriment/bread = 5 + ) + mix_message = "The breadcrumbs and water clump together to form a thick stuffing." + obj_result = /obj/item/food/stuffing + +/decl/chemical_reaction/recipe/food/mint + name = "Mint" + required_reagents = list( + /decl/material/liquid/nutriment/sugar = 5, + /decl/material/liquid/frostoil = 5 + ) + mix_message = "The solution thickens and hardens into a glossy brown substance." + obj_result = /obj/item/food/mint + +/decl/chemical_reaction/recipe/food/pudding + abstract_type = /decl/chemical_reaction/recipe/food/pudding + minimum_temperature = T0C + 80 + +/decl/chemical_reaction/recipe/food/pudding/chazuke + name = "Chazuke" + required_reagents = list( + /decl/material/liquid/nutriment/rice = 5, + /decl/material/liquid/drink/tea/green = 1 + ) + mix_message = "The tea mingles with and cooks the rice." + obj_result = /obj/item/food/chazuke + +/decl/chemical_reaction/recipe/food/pudding/ricepudding + name = "Rice Pudding" + required_reagents = list( + /decl/material/liquid/drink/milk = 5, + /decl/material/liquid/nutriment/rice = 10 + ) + obj_result = /obj/item/food/ricepudding + +/decl/chemical_reaction/recipe/food/pudding/spacylibertyduff + name = "Space Liberty Duff" + required_reagents = list( + /decl/material/liquid/water = 10, + /decl/material/liquid/alcohol/vodka = 5, + /decl/material/liquid/psychotropics = 5 + ) + obj_result = /obj/item/food/spacylibertyduff + +/decl/chemical_reaction/recipe/food/pudding/amanitajelly + name = "Amanita Jelly" + required_reagents = list( + /decl/material/liquid/water = 10, + /decl/material/liquid/alcohol/vodka = 5, + /decl/material/liquid/amatoxin = 5 + ) + obj_result = /obj/item/food/amanitajelly + +/decl/chemical_reaction/recipe/food/pudding/amanitajelly/create_food(location, list/data) + var/obj/item/food/amanitajelly/being_cooked = ..() + if(being_cooked?.reagents) + being_cooked.reagents.clear_reagent(/decl/material/liquid/amatoxin) + return being_cooked diff --git a/code/modules/reagents/reactions/reaction_slimes.dm b/code/modules/reagents/reactions/reaction_slimes.dm deleted file mode 100644 index 021142f1d7ef..000000000000 --- a/code/modules/reagents/reactions/reaction_slimes.dm +++ /dev/null @@ -1,356 +0,0 @@ -/* Slime cores */ -/datum/chemical_reaction/slime - hidden_from_codex = TRUE - mix_message = "The slime core twitches sharply." - var/required = null - -/datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder) - if(holder.my_atom && istype(holder.my_atom, required)) - var/obj/item/slime_extract/T = holder.my_atom - if(T.Uses > 0) - return ..() - return 0 - -/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder) - ..() - var/obj/item/slime_extract/T = holder.my_atom - T.Uses-- - if(T.Uses <= 0) - T.visible_message("\icon[T]\The [T]'s power is consumed in the reaction.") - T.SetName("used slime extract") - T.desc = "This extract has been used up." - -//Grey -/datum/chemical_reaction/slime/spawn - name = "Slime Spawn" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/grey - -/datum/chemical_reaction/slime/spawn/on_reaction(var/datum/reagents/holder) - ..() - holder.my_atom.visible_message(SPAN_WARNING("The core begins to quiver and grow, and soon a new baby slime emerges from it!")) - new /mob/living/carbon/slime(get_turf(holder.my_atom)) - -/datum/chemical_reaction/slime/monkey - name = "Slime Monkey" - result = null - required_reagents = list(/decl/material/liquid/blood = 1) - result_amount = 1 - required = /obj/item/slime_extract/grey - -/datum/chemical_reaction/slime/monkey/on_reaction(var/datum/reagents/holder) - ..() - for(var/i = 1, i <= 3, i++) - new /obj/item/chems/food/snacks/monkeycube(get_turf(holder.my_atom)) - -//Metal -/datum/chemical_reaction/slime/metal - name = "Slime Metal" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/metal - -/datum/chemical_reaction/slime/metal/on_reaction(var/datum/reagents/holder) - ..() - var/obj/item/stack/material/steel/M = new (get_turf(holder.my_atom)) - M.amount = 15 - var/obj/item/stack/material/plasteel/P = new (get_turf(holder.my_atom)) - P.amount = 5 - -//Gold -/datum/chemical_reaction/slime/crit - name = "Slime Crit" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/gold - var/list/possible_mobs = list( - /mob/living/simple_animal/cat, - /mob/living/simple_animal/cat/kitten, - /mob/living/simple_animal/corgi, - /mob/living/simple_animal/corgi/puppy, - /mob/living/simple_animal/cow, - /mob/living/simple_animal/chick, - /mob/living/simple_animal/chicken - ) - -/datum/chemical_reaction/slime/crit/on_reaction(var/datum/reagents/holder) - ..() - var/type = pick(possible_mobs) - new type(get_turf(holder.my_atom)) - -//Silver -/datum/chemical_reaction/slime/bork - name = "Slime Bork" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/silver - -/datum/chemical_reaction/slime/bork/on_reaction(var/datum/reagents/holder) - ..() - var/list/borks = typesof(/obj/item/chems/food/snacks) - /obj/item/chems/food/snacks - playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(get_turf(holder.my_atom), null)) - if(M.eyecheck() < FLASH_PROTECTION_MODERATE) - M.flash_eyes() - - for(var/i = 1, i <= 4 + rand(1,2), i++) - var/chosen = pick(borks) - var/obj/B = new chosen(get_turf(holder.my_atom)) - if(B) - if(prob(50)) - for(var/j = 1, j <= rand(1, 3), j++) - step(B, pick(NORTH, SOUTH, EAST, WEST)) - -//Blue -/datum/chemical_reaction/slime/frost - name = "Slime Frost Oil" - result = /decl/material/liquid/frostoil - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 10 - required = /obj/item/slime_extract/blue - -//Dark Blue -/datum/chemical_reaction/slime/freeze - name = "Slime Freeze" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/darkblue - mix_message = "The slime extract begins to vibrate violently!" - -/datum/chemical_reaction/slime/freeze/on_reaction(var/datum/reagents/holder) - set waitfor = 0 - ..() - sleep(50) - playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/M in range (get_turf(holder.my_atom), 7)) - M.bodytemperature -= 140 - to_chat(M, "You feel a chill!") - -//Orange -/datum/chemical_reaction/slime/casp - name = "Slime Capsaicin Oil" - result = /decl/material/liquid/capsaicin - required_reagents = list(/decl/material/liquid/blood = 1) - result_amount = 10 - required = /obj/item/slime_extract/orange - -/datum/chemical_reaction/slime/fire - name = "Slime fire" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/orange - mix_message = "The slime extract begins to vibrate violently!" - -/datum/chemical_reaction/slime/fire/on_reaction(var/datum/reagents/holder) - set waitfor = 0 - ..() - sleep(50) - if(!(holder.my_atom && holder.my_atom.loc)) - return - - var/turf/location = get_turf(holder.my_atom) - location.assume_gas(/decl/material/gas/hydrogen, 250, 1400) - location.hotspot_expose(700, 400) - -//Yellow -/datum/chemical_reaction/slime/overload - name = "Slime EMP" - result = null - required_reagents = list(/decl/material/liquid/blood = 1) - result_amount = 1 - required = /obj/item/slime_extract/yellow - -/datum/chemical_reaction/slime/overload/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) - ..() - empulse(get_turf(holder.my_atom), 3, 7) - -/datum/chemical_reaction/slime/cell - name = "Slime Powercell" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/yellow - -/datum/chemical_reaction/slime/cell/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) - ..() - new /obj/item/cell/slime(get_turf(holder.my_atom)) - -/datum/chemical_reaction/slime/glow - name = "Slime Glow" - result = null - required_reagents = list(/decl/material/liquid/water = 1) - result_amount = 1 - required = /obj/item/slime_extract/yellow - mix_message = "The contents of the slime core harden and begin to emit a warm, bright light." - -/datum/chemical_reaction/slime/glow/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) - ..() - new /obj/item/flashlight/slime(get_turf(holder.my_atom)) - -//Purple -/datum/chemical_reaction/slime/psteroid - name = "Slime Steroid" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/purple - -/datum/chemical_reaction/slime/psteroid/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) - ..() - new /obj/item/slimesteroid(get_turf(holder.my_atom)) - -/datum/chemical_reaction/slime/jam - name = "Slime Jam" - result = /decl/material/liquid/slimejelly - required_reagents = list(/decl/material/liquid/nutriment/sugar = 1) - result_amount = 10 - required = /obj/item/slime_extract/purple - -//Dark Purple -/datum/chemical_reaction/slime/plasma - name = "Slime Hydrogen" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/darkpurple - -/datum/chemical_reaction/slime/plasma/on_reaction(var/datum/reagents/holder) - ..() - new /obj/item/stack/material/generic(get_turf(holder.my_atom), 10, /decl/material/solid/metallic_hydrogen) - -//Red -/datum/chemical_reaction/slime/bloodlust - name = "Bloodlust" - result = null - required_reagents = list(/decl/material/liquid/blood = 1) - result_amount = 1 - required = /obj/item/slime_extract/red - -/datum/chemical_reaction/slime/bloodlust/on_reaction(var/datum/reagents/holder) - ..() - for(var/mob/living/carbon/slime/slime in viewers(get_turf(holder.my_atom), null)) - slime.rabid = 1 - slime.visible_message("The [slime] is driven into a frenzy!") - -//Pink -/datum/chemical_reaction/slime/ppotion - name = "Slime Potion" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/pink - -/datum/chemical_reaction/slime/ppotion/on_reaction(var/datum/reagents/holder) - ..() - new /obj/item/slimepotion(get_turf(holder.my_atom)) - -//Oil -/datum/chemical_reaction/slime/explosion - name = "Slime Explosion" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/oil - mix_message = "The slime extract begins to vibrate violently!" - -/datum/chemical_reaction/slime/explosion/on_reaction(var/datum/reagents/holder) - set waitfor = 0 - ..() - sleep(50) - explosion(get_turf(holder.my_atom), 1, 3, 6) - -//Light Pink -/datum/chemical_reaction/slime/potion2 - name = "Slime Potion 2" - result = null - result_amount = 1 - required = /obj/item/slime_extract/lightpink - required_reagents = list(/decl/material/solid/metal/uranium = 1) - -/datum/chemical_reaction/slime/potion2/on_reaction(var/datum/reagents/holder) - ..() - new /obj/item/slimepotion2(get_turf(holder.my_atom)) - -//Adamantine -/datum/chemical_reaction/slime/golem - name = "Slime Golem" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/adamantine - -/datum/chemical_reaction/slime/golem/on_reaction(var/datum/reagents/holder) - ..() - var/obj/effect/golemrune/Z = new /obj/effect/golemrune(get_turf(holder.my_atom)) - Z.announce_to_ghosts() - -//Sepia -/datum/chemical_reaction/slime/film - name = "Slime Film" - result = null - required_reagents = list(/decl/material/liquid/blood = 1) - result_amount = 2 - required = /obj/item/slime_extract/sepia - -/datum/chemical_reaction/slime/film/on_reaction(var/datum/reagents/holder) - for(var/i in 1 to result_amount) - new /obj/item/camera_film(get_turf(holder.my_atom)) - ..() - -/datum/chemical_reaction/slime/camera - name = "Slime Camera" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - result_amount = 1 - required = /obj/item/slime_extract/sepia - -/datum/chemical_reaction/slime/camera/on_reaction(var/datum/reagents/holder) - new /obj/item/camera(get_turf(holder.my_atom)) - ..() - -//Quantum -/datum/chemical_reaction/slime/teleport - name = "Slime Teleport" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - required = /obj/item/slime_extract/quantum - reaction_sound = 'sound/effects/teleport.ogg' - -/datum/chemical_reaction/slime/teleport/on_reaction(var/datum/reagents/holder) - var/list/turfs = list() - for(var/turf/T in orange(holder.my_atom,6)) - turfs += T - for(var/atom/movable/a in viewers(holder.my_atom,2)) - if(!a.simulated) - continue - a.forceMove(pick(turfs)) - ..() - -//pyrite -/datum/chemical_reaction/slime/paint - name = "Slime Paint" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - required = /obj/item/slime_extract/pyrite - -/datum/chemical_reaction/slime/paint/on_reaction(var/datum/reagents/holder) - new /obj/item/chems/glass/paint/random(get_turf(holder.my_atom)) - ..() - -//cerulean -/datum/chemical_reaction/slime/extract_enhance - name = "Extract Enhancer" - result = null - required_reagents = list(/decl/material/solid/metal/uranium = 1) - required = /obj/item/slime_extract/cerulean - -/datum/chemical_reaction/slime/extract_enhance/on_reaction(var/datum/reagents/holder) - new /obj/item/slimesteroid2(get_turf(holder.my_atom)) - ..() \ No newline at end of file diff --git a/code/modules/reagents/reactions/reaction_synthesis.dm b/code/modules/reagents/reactions/reaction_synthesis.dm index 3a85f3627cdc..59458d2f0d39 100644 --- a/code/modules/reagents/reactions/reaction_synthesis.dm +++ b/code/modules/reagents/reactions/reaction_synthesis.dm @@ -1,10 +1,34 @@ /* Solidification */ -/datum/chemical_reaction/synthesis +/decl/chemical_reaction/synthesis result = null result_amount = 1 mix_message = "The solution hardens and begins to crystallize." + abstract_type = /decl/chemical_reaction/synthesis + reaction_category = REACTION_TYPE_SYNTHESIS -/datum/chemical_reaction/synthesis/crystalization +/decl/chemical_reaction/synthesis/fiberglass + name = "Fiberglass" + mix_message = "The glass fibers are bound up in the polymer as it hardens." + minimum_temperature = T100C + maximum_temperature = INFINITY + +/decl/chemical_reaction/synthesis/fiberglass/Initialize() + required_reagents = list( + /decl/material/solid/glass = ceil(REAGENT_UNITS_PER_MATERIAL_SHEET/2), + /decl/material/solid/organic/plastic = ceil(REAGENT_UNITS_PER_MATERIAL_SHEET/2) + ) + . = ..() + +/decl/chemical_reaction/synthesis/fiberglass/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + ..() + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + created_volume = ceil(created_volume) + if(created_volume > 0) + var/decl/material/mat = GET_DECL(/decl/material/solid/fiberglass) + mat.create_object(location, created_volume) + +/decl/chemical_reaction/synthesis/crystalization name = "Crystalization" required_reagents = list(/decl/material/liquid/crystal_agent = 1) catalysts = list(/decl/material/liquid/crystal_agent = 5) @@ -12,35 +36,74 @@ /decl/material/solid/silicon ) // Interferes with resin globules. -/datum/chemical_reaction/synthesis/crystalization/can_happen(datum/reagents/holder) - . = ..() && length(holder.reagent_volumes > 1) +/decl/chemical_reaction/synthesis/crystalization/can_happen(datum/reagents/holder) + var/holder_volumes = REAGENT_VOLUMES(holder) + . = ..() && length(holder_volumes) > 1 if(.) . = FALSE - for(var/rtype in holder.reagent_volumes) - if(rtype != /decl/material/liquid/crystal_agent && REAGENT_VOLUME(holder, rtype) >= REAGENT_UNITS_PER_MATERIAL_SHEET) + for(var/decl/material/reagent as anything in holder_volumes) + if(reagent.type != /decl/material/liquid/crystal_agent && REAGENT_VOLUME(holder, reagent) >= REAGENT_UNITS_PER_MATERIAL_SHEET) return TRUE -/datum/chemical_reaction/synthesis/crystalization/on_reaction(datum/reagents/holder, created_volume, reaction_flags) - var/list/removing_reagents = list() - for(var/rtype in holder.reagent_volumes) - if(rtype != /decl/material/liquid/crystal_agent) - var/solidifying = Floor(REAGENT_VOLUME(holder, rtype) / REAGENT_UNITS_PER_MATERIAL_SHEET) - if(solidifying) - new /obj/item/stack/material/generic(get_turf(holder.my_atom), solidifying, rtype) - removing_reagents[rtype] = solidifying * REAGENT_UNITS_PER_MATERIAL_SHEET - for(var/rtype in removing_reagents) - holder.remove_reagent(rtype, removing_reagents[rtype]) - -/datum/chemical_reaction/synthesis/plastication +/decl/chemical_reaction/synthesis/crystalization/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + var/list/removing_reagents = list() + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(holder)) + if(reagent.type != /decl/material/liquid/crystal_agent) + var/solidifying = floor(REAGENT_VOLUME(holder, reagent) / REAGENT_UNITS_PER_MATERIAL_SHEET) + if(solidifying) + SSmaterials.create_object(reagent.type, location, solidifying, /obj/item/stack/material/cubes) + removing_reagents[reagent] = solidifying * REAGENT_UNITS_PER_MATERIAL_SHEET + for(var/reagent in removing_reagents) + holder.remove_reagent(reagent, removing_reagents[reagent]) + +// Turns gas into a "solid" form for use in PACMAN etc. +/decl/chemical_reaction/synthesis/aerogel + name = "Aerogel" + mix_message = "The solution solidifies into a translucent suspension of gas within gel." + required_reagents = list(/decl/material/solid/silicon = 1, /decl/material/liquid/plasticide = 1) + minimum_temperature = 150 CELSIUS + maximum_temperature = 200 CELSIUS + inhibitors = list(/decl/material/liquid/crystal_agent) + +/decl/chemical_reaction/synthesis/aerogel/can_happen(datum/reagents/holder) + var/holder_volumes = REAGENT_VOLUMES(holder) + . = ..() && length(holder_volumes) > 1 + if(.) + . = FALSE + for(var/decl/material/reagent as anything in holder_volumes) + if(REAGENT_VOLUME(holder, reagent) < REAGENT_UNITS_PER_MATERIAL_SHEET) + continue + if(reagent.default_solid_form != /obj/item/stack/material/aerogel) + continue + return TRUE + +/decl/chemical_reaction/synthesis/aerogel/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + var/list/removing_reagents = list() + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(holder)) + if(reagent.default_solid_form == /obj/item/stack/material/aerogel) + var/solidifying = floor(REAGENT_VOLUME(holder, reagent) / REAGENT_UNITS_PER_MATERIAL_SHEET) + if(solidifying) + SSmaterials.create_object(reagent.type, location, solidifying) + removing_reagents[reagent] = solidifying * REAGENT_UNITS_PER_MATERIAL_SHEET + for(var/reagent in removing_reagents) + holder.remove_reagent(reagent, removing_reagents[reagent]) + +/decl/chemical_reaction/synthesis/plastication name = "Plastic" - required_reagents = list(/decl/material/liquid/acid/polyacid = 1, /decl/material/liquid/plasticide = 2) + required_reagents = list(/decl/material/liquid/acid = 1, /decl/material/liquid/plasticide = 2) mix_message = "The solution solidifies into a grey-white mass." -/datum/chemical_reaction/synthesis/plastication/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/synthesis/plastication/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - new /obj/item/stack/material/plastic(get_turf(holder.my_atom), created_volume) + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(location) + SSmaterials.create_object(/decl/material/solid/organic/plastic, location, created_volume) -/datum/chemical_reaction/synthesis/resin_pack +/decl/chemical_reaction/synthesis/resin_pack name = "Resin Globule" required_reagents = list( /decl/material/liquid/crystal_agent = 1, @@ -49,10 +112,104 @@ result_amount = 3 mix_message = "The solution hardens and begins to crystallize." -/datum/chemical_reaction/synthesis/resin_pack/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) +/decl/chemical_reaction/synthesis/resin_pack/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + ..() + var/turf/T = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(!istype(T)) + return + var/create_stacks = floor(created_volume) + if(create_stacks <= 0) + return + new /obj/item/stack/medical/resin/crafted(T, create_stacks) + +/decl/chemical_reaction/synthesis/soap + name = "Handmade Plant Soap" + required_reagents = list( + /decl/material/solid/carbon/ashes = 5, + /decl/material/liquid/water = 5, + /decl/material/liquid/oil/plant = 10 + ) + result_amount = 1 + mix_message = "The solution thickens and solidifies." + minimum_temperature = 100 CELSIUS + +/decl/chemical_reaction/synthesis/soap/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + ..() + var/turf/T = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(!istype(T)) + return + var/create_soap = floor(created_volume) + if(create_soap <= 0) + return + for(var/i = 1 to create_soap) + new /obj/item/soap/crafted(T) + +/decl/chemical_reaction/synthesis/soap/corn + name = "Handmade Corn Soap" + required_reagents = list( + /decl/material/solid/carbon/ashes = 5, + /decl/material/liquid/water = 5, + /decl/material/liquid/oil/plant/corn = 10 + ) + +// Making chipboard out of wood scraps/recycled wood. +/decl/chemical_reaction/synthesis/chipboard + name = "Oak Chipboard" + required_reagents = list( + /decl/material/solid/organic/wood/oak = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2), + /decl/material/solid/organic/plastic = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2) + ) + result_amount = 1 + mix_message = "The wood particulate binds with the plastic to form laminated chipboard." + minimum_temperature = 100 CELSIUS + var/chipboard_type = /decl/material/solid/organic/wood/chipboard + +/decl/chemical_reaction/synthesis/chipboard/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) ..() - var/turf/T = get_turf(holder.my_atom) - if(istype(T)) - var/create_stacks = Floor(created_volume) - if(create_stacks > 0) - new /obj/item/stack/medical/resin/handmade(T, create_stacks) + var/turf/T = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + if(!istype(T)) + return + var/create_sheets = floor(created_volume) + if(create_sheets <= 0) + return + new /obj/item/stack/material/sheet(T, create_sheets, chipboard_type) + +/decl/chemical_reaction/synthesis/chipboard/maple + name = "Maple Chipboard" + required_reagents = list( + /decl/material/solid/organic/wood/maple = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2), + /decl/material/solid/organic/plastic = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2) + ) + chipboard_type = /decl/material/solid/organic/wood/chipboard/maple + +/decl/chemical_reaction/synthesis/chipboard/mahogany + name = "Mahogany Chipboard" + required_reagents = list( + /decl/material/solid/organic/wood/mahogany = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2), + /decl/material/solid/organic/plastic = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2) + ) + chipboard_type = /decl/material/solid/organic/wood/chipboard/mahogany + +/decl/chemical_reaction/synthesis/chipboard/ebony + name = "Ebony Chipboard" + required_reagents = list( + /decl/material/solid/organic/wood/ebony = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2), + /decl/material/solid/organic/plastic = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2) + ) + chipboard_type = /decl/material/solid/organic/wood/chipboard/ebony + +/decl/chemical_reaction/synthesis/chipboard/walnut + name = "Walnut Chipboard" + required_reagents = list( + /decl/material/solid/organic/wood/walnut = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2), + /decl/material/solid/organic/plastic = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2) + ) + chipboard_type = /decl/material/solid/organic/wood/chipboard/walnut + +/decl/chemical_reaction/synthesis/chipboard/yew + name = "Yew Chipboard" + required_reagents = list( + /decl/material/solid/organic/wood/yew = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2), + /decl/material/solid/organic/plastic = (REAGENT_UNITS_PER_MATERIAL_SHEET / 2) + ) + chipboard_type = /decl/material/solid/organic/wood/chipboard/yew diff --git a/code/modules/reagents/reagent_container_edibility.dm b/code/modules/reagents/reagent_container_edibility.dm new file mode 100644 index 000000000000..83d485d0c13f --- /dev/null +++ b/code/modules/reagents/reagent_container_edibility.dm @@ -0,0 +1,8 @@ +/obj/item/chems/get_edible_material_amount(var/mob/eater) + return ATOM_IS_OPEN_CONTAINER(src) && REAGENT_TOTAL_VOLUME(reagents) + +/obj/item/chems/get_food_default_transfer_amount(mob/eater) + return eater?.get_eaten_transfer_amount(amount_per_transfer_from_this) + +/obj/item/chems/get_food_consumption_method(mob/eater) + return EATING_METHOD_DRINK diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 2fac34e2a94d..847d7996b244 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -1,36 +1,86 @@ /obj/item/chems - name = "Container" + name = "container" desc = "..." icon = 'icons/obj/items/chem/container.dmi' icon_state = null w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/organic/plastic + obj_flags = OBJ_FLAG_HOLLOW + abstract_type = /obj/item/chems + watertight = TRUE + chem_volume = 30 var/amount_per_transfer_from_this = 5 var/possible_transfer_amounts = @"[5,10,15,25,30]" - var/volume = 30 var/label_text + var/presentation_flags = 0 + var/detail_color + var/detail_state + +/obj/item/chems/Initialize(ml, material_key) + . = ..() + if(!possible_transfer_amounts) + src.verbs -= /obj/item/chems/verb/set_amount_per_transfer_from_this + +/obj/item/chems/on_update_icon() + . = ..() + if(detail_state) + add_overlay(overlay_image(icon, "[initial(icon_state)][detail_state]", detail_color || COLOR_WHITE, RESET_COLOR)) + var/image/contents_overlay = get_reagents_overlay(use_single_icon ? icon_state : null) + if(contents_overlay) + add_overlay(contents_overlay) + if(detail_state) + add_overlay(overlay_image(icon, "[initial(icon_state)][detail_state]", detail_color || COLOR_WHITE, RESET_COLOR)) + +/obj/item/chems/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing) + var/image/reagents_overlay = get_reagents_overlay(overlay.icon_state) + if(reagents_overlay) + overlay.add_overlay(reagents_overlay) + return ..() + +/obj/item/chems/set_custom_desc(var/new_desc) + base_desc = new_desc + update_container_desc() /obj/item/chems/proc/cannot_interact(mob/user) if(!CanPhysicallyInteract(user)) - to_chat(usr, SPAN_WARNING("You're in no condition to do that!")) + to_chat(user, SPAN_WARNING("You're in no condition to do that!")) return TRUE if(ismob(loc) && loc != user) - to_chat(usr, SPAN_WARNING("You can't set transfer amounts while \the [src] is being held by someone else.")) + to_chat(user, SPAN_WARNING("You can't set transfer amounts while \the [src] is being held by someone else.")) return TRUE return FALSE -/obj/item/chems/proc/get_base_name() - . = initial(name) - -/obj/item/chems/on_reagent_change() - if(atom_flags & ATOM_FLAG_SHOW_REAGENT_NAME) +/obj/item/chems/update_name() + . = ..() // handles material, etc + var/newname = name + if(istype(reagents) && (presentation_flags & PRESENTATION_FLAG_NAME)) + var/decl/material/primary = reagents?.get_primary_reagent_decl() + if(primary) + newname += " of [primary.get_presentation_name(src)]" + if(length(label_text)) + newname += " ([label_text])" + if(newname != name) + SetName(newname) + +/obj/item/chems/proc/get_base_desc() + if(!base_desc) + base_desc = initial(desc) + . = base_desc + +/obj/item/chems/proc/update_container_desc() + var/list/new_desc_list = list(get_base_desc()) + if(presentation_flags & PRESENTATION_FLAG_DESC) var/decl/material/R = reagents?.get_primary_reagent_decl() - var/newname = get_base_name() if(R) - newname = "[newname] of [R.get_presentation_name(src)]" - if(newname != name) - SetName(newname) - update_icon() + new_desc_list += R.get_presentation_desc(src) + desc = new_desc_list.Join("\n") + +/obj/item/chems/on_reagent_change() + if((. = ..())) + update_name() + update_container_desc() + update_icon() /obj/item/chems/verb/set_amount_per_transfer_from_this() set name = "Set Transfer Amount" @@ -42,185 +92,140 @@ if(N && !cannot_interact(usr)) amount_per_transfer_from_this = N -/obj/item/chems/Initialize() - . = ..() - create_reagents(volume) - if(!possible_transfer_amounts) - src.verbs -= /obj/item/chems/verb/set_amount_per_transfer_from_this - -/obj/item/chems/attack_self(mob/user) +/obj/item/chems/afterattack(atom/target, mob/user, proximity_flag, click_parameters) return -/obj/item/chems/afterattack(obj/target, mob/user, flag) - return - -/obj/item/chems/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/pen) || istype(W, /obj/item/flashlight/pen)) - var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) - if(length(tmp_label) > 10) - to_chat(user, "The label can be at most 10 characters long.") - else - to_chat(user, "You set the label to \"[tmp_label]\".") - label_text = tmp_label - update_name_label() - else +/obj/item/chems/attackby(obj/item/used_item, mob/user) + + // Skimming off cream, repurposed from crucibles. + // TODO: potentially make this an alt interaction and unify with slag skimming. + if(istype(used_item, /obj/item/chems) && ATOM_IS_OPEN_CONTAINER(used_item) && REAGENT_MAXIMUM_VOLUME(used_item.reagents) && REAGENT_TOTAL_VOLUME(reagents) && length(REAGENT_VOLUMES(reagents)) > 1) + var/list/skimmable_reagents = reagents.get_skimmable_reagents() + if(length(skimmable_reagents)) + var/removing = min(amount_per_transfer_from_this, REAGENTS_FREE_SPACE(used_item.reagents)) + if(removing <= 0) + to_chat(user, SPAN_WARNING("\The [used_item] is full.")) + else + var/old_amt = REAGENT_TOTAL_VOLUME(used_item.reagents) + reagents.trans_to_holder(used_item.reagents, removing, skip_reagents = (REAGENT_VOLUMES(reagents) - skimmable_reagents)) + to_chat(user, SPAN_NOTICE("You skim [REAGENT_TOTAL_VOLUME(used_item.reagents)-old_amt] unit\s of [used_item.reagents.get_primary_reagent_name()] from the top of \the [reagents.get_primary_reagent_name()].")) + return TRUE + + if(used_item.user_can_attack_with(user, silent = TRUE)) + if(IS_PEN(used_item)) + var/tmp_label = sanitize_safe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) + if(length(tmp_label) > 10) + to_chat(user, SPAN_NOTICE("The label can be at most 10 characters long.")) + else + to_chat(user, SPAN_NOTICE("You set the label to \"[tmp_label]\".")) + label_text = tmp_label + update_name() + return TRUE + return ..() + +/obj/item/chems/standard_pour_into(mob/user, atom/target, amount = 5) + amount = amount_per_transfer_from_this + // We'll be lenient: if you lack the dexterity for proper pouring you get a random amount. + if(!user_can_attack_with(user, silent = TRUE)) + amount = rand(1, floor(amount_per_transfer_from_this * 1.5)) + return ..(user, target, amount) + +/obj/item/chems/do_surgery(mob/living/M, mob/living/user) + if(user.get_target_zone() != BP_MOUTH) //in case it is ever used as a surgery tool return ..() -/obj/item/chems/proc/update_name_label() - if(label_text == "") - SetName(initial(name)) - else - SetName("[initial(name)] ([label_text])") - -/obj/item/chems/proc/standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) // This goes into afterattack - if(!istype(target)) - return 0 - - if(!target.reagents || !target.reagents.total_volume) - to_chat(user, "[target] is empty.") - return 1 - - if(reagents && !REAGENTS_FREE_SPACE(reagents)) - to_chat(user, "[src] is full.") - return 1 - - var/trans = target.reagents.trans_to_obj(src, target:amount_per_transfer_from_this) - to_chat(user, "You fill [src] with [trans] units of the contents of [target].") - return 1 - -/obj/item/chems/proc/standard_splash_mob(var/mob/user, var/mob/target) // This goes into afterattack - if(!istype(target)) +/obj/item/chems/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(!reagents) return + if(hasHUD(user, HUD_SCIENCE)) + var/prec = user.skill_fail_chance(SKILL_CHEMISTRY, 10) + . += SPAN_NOTICE("\The [src] contains: [reagents.get_reagents(precision = prec)].") + else if((loc == user) && user.skill_check(SKILL_CHEMISTRY, SKILL_EXPERT)) + . += SPAN_NOTICE("Using your chemistry knowledge, you identify the following reagents in \the [src]: [reagents.get_reagents(!user.skill_check(SKILL_CHEMISTRY, SKILL_PROF), 5)].") - if(user.a_intent == I_HELP) - to_chat(user, "You can't splash people on help intent.") - return 1 - - if(!reagents || !reagents.total_volume) - to_chat(user, "[src] is empty.") - return 1 - - if(target.reagents && !REAGENTS_FREE_SPACE(target.reagents)) - to_chat(user, "[target] is full.") - return 1 - - var/contained = REAGENT_LIST(src) - admin_attack_log(user, target, "Used \the [name] containing [contained] to splash the victim.", "Was splashed by \the [name] containing [contained].", "used \the [name] containing [contained] to splash") - - user.visible_message("[target] has been splashed with something by [user]!", "You splash the solution onto [target].") - reagents.splash(target, reagents.total_volume) - return 1 +/obj/item/chems/shatter(consumed) + //Skip splashing if we are in nullspace, since splash isn't null guarded + if(loc) + reagents.splash(get_turf(src), REAGENT_TOTAL_VOLUME(reagents)) + . = ..() -/obj/item/chems/proc/self_feed_message(var/mob/user) - to_chat(user, "You eat \the [src]") +/obj/item/chems/proc/set_detail_color(var/new_color) + if(new_color != detail_color) + detail_color = new_color + update_icon() + return TRUE + return FALSE -/obj/item/chems/proc/other_feed_message_start(var/mob/user, var/mob/target) - user.visible_message("[user] is trying to feed [target] \the [src]!") +/obj/item/chems/ProcessAtomTemperature() -/obj/item/chems/proc/other_feed_message_finish(var/mob/user, var/mob/target) - user.visible_message("[user] has fed [target] \the [src]!") + . = ..() -/obj/item/chems/proc/feed_sound(var/mob/user) - return + if(QDELETED(src) || !REAGENT_TOTAL_VOLUME(reagents) || !ATOM_IS_OPEN_CONTAINER(src) || !isatom(loc)) + return -/obj/item/chems/proc/standard_feed_mob(var/mob/user, var/mob/target) // This goes into attack - if(!istype(target)) - return 0 - - if(!reagents || !reagents.total_volume) - to_chat(user, "\The [src] is empty.") - return 1 - - // only carbons can eat - if(istype(target, /mob/living/carbon)) - if(target == user) - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(!H.check_has_mouth()) - to_chat(user, "Where do you intend to put \the [src]? You don't have a mouth!") - return - var/obj/item/blocked = H.check_mouth_coverage() - if(blocked) - to_chat(user, "\The [blocked] is in the way!") - return - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things - self_feed_message(user) - reagents.trans_to_mob(user, issmall(user) ? ceil(amount_per_transfer_from_this/2) : amount_per_transfer_from_this, CHEM_INGEST) - feed_sound(user) - add_trace_DNA(user) - return 1 - - - else - var/mob/living/carbon/H = target - if(!H.check_has_mouth()) - to_chat(user, "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!") - return - var/obj/item/blocked = H.check_mouth_coverage() - if(blocked) - to_chat(user, "\The [blocked] is in the way!") - return - - other_feed_message_start(user, target) - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!do_mob(user, target)) - return - - other_feed_message_finish(user, target) - - var/contained = REAGENT_LIST(src) - admin_attack_log(user, target, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") - - reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INGEST) - feed_sound(user) - add_trace_DNA(target) - return 1 - - return 0 - -/obj/item/chems/proc/standard_pour_into(var/mob/user, var/atom/target) // This goes into afterattack and yes, it's atom-level - if(!target.reagents) - return 0 - - // Ensure we don't splash beakers and similar containers. - if(!ATOM_IS_OPEN_CONTAINER(target) && istype(target, /obj/item/chems)) - to_chat(user, "\The [target] is closed.") - return 1 - // Otherwise don't care about splashing. - else if(!ATOM_IS_OPEN_CONTAINER(target)) - return 0 - - if(!reagents || !reagents.total_volume) - to_chat(user, "[src] is empty.") - return 1 - - if(!REAGENTS_FREE_SPACE(target.reagents)) - to_chat(user, "[target] is full.") - return 1 - - var/trans = reagents.trans_to(target, amount_per_transfer_from_this) - playsound(src, 'sound/effects/pour.ogg', 25, 1) - to_chat(user, "You transfer [trans] unit\s of the solution to \the [target]. \The [src] now contains [src.reagents.total_volume] units.") - return 1 - -/obj/item/chems/do_surgery(mob/living/carbon/M, mob/living/user) - if(user.zone_sel.selecting != BP_MOUTH) //in case it is ever used as a surgery tool + // Vaporize anything over its boiling point. + var/update_reagents = FALSE + var/datum/gas_mixture/environment = loc?.return_air() + var/ambient_pressure = environment ? environment.return_pressure() : ONE_ATMOSPHERE + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.can_boil_to_gas && reagent.phase_at_temperature(temperature, ambient_pressure) == MAT_PHASE_GAS) + // TODO: reduce atom temperature? + var/removing = min(reagent.boil_evaporation_per_run, REAGENT_VOLUME(reagents, reagent)) + reagents.remove_reagent(reagent, removing, defer_update = TRUE, removed_phases = MAT_PHASE_LIQUID) + update_reagents = TRUE + loc.take_vaporized_reagent(reagent, removing) + if(update_reagents) + reagents.update_total() + +/obj/item/chems/take_vaporized_reagent(reagent, amount) + if(!REAGENT_MAXIMUM_VOLUME(reagents)) return ..() + var/take_reagent = min(amount, REAGENTS_FREE_SPACE(reagents)) + if(take_reagent > 0) + reagents.add_reagent(reagent, take_reagent) + amount -= take_reagent + if(amount > 0) + return ..(reagent, amount) + +// +// Interactions +// +/obj/item/chems/get_quick_interaction_handler(mob/user) + var/static/interaction = GET_DECL(/decl/interaction_handler/set_transfer/chems) + return interaction + +/obj/item/chems/get_alt_interactions(var/mob/user) + . = ..() + var/static/list/chem_interactions = list( + /decl/interaction_handler/set_transfer/chems, + /decl/interaction_handler/empty/chems + ) + LAZYADD(., chem_interactions) -/obj/item/chems/AltClick(var/mob/user) - if(possible_transfer_amounts) - set_amount_per_transfer_from_this() - else - return ..() +/decl/interaction_handler/set_transfer/chems + expected_target_type = /obj/item/chems + examine_desc = "set the transfer volume" -/obj/item/chems/examine(mob/user) +/decl/interaction_handler/set_transfer/chems/is_possible(var/atom/target, var/mob/user) . = ..() - if(!reagents) - return - if(hasHUD(user, HUD_SCIENCE)) - var/prec = user.skill_fail_chance(SKILL_CHEMISTRY, 10) - to_chat(user, "The [src] contains: [reagents.get_reagents(precision = prec)].") - else if((loc == user) && user.skill_check(SKILL_CHEMISTRY, SKILL_EXPERT)) - to_chat(user, "Using your chemistry knowledge, you identify the following reagents in \the [src]: [reagents.get_reagents(!user.skill_check(SKILL_CHEMISTRY, SKILL_PROF), 5)].") + if(.) + var/obj/item/chems/C = target + return !!C.possible_transfer_amounts + +/decl/interaction_handler/set_transfer/chems/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/chems/C = target + C.set_amount_per_transfer_from_this() + +///Empty a container onto the floor +/decl/interaction_handler/empty/chems + name = "Empty On Floor" + expected_target_type = /obj/item/chems + interaction_flags = INTERACTION_NEEDS_INVENTORY | INTERACTION_NEEDS_PHYSICAL_INTERACTION | INTERACTION_NEVER_AUTOMATIC + examine_desc = "empty $TARGET_THEM$ onto the floor" + +/decl/interaction_handler/empty/chems/invoked(atom/target, mob/user, obj/item/prop) + var/turf/T = get_turf(user) + if(T) + to_chat(user, SPAN_NOTICE("You empty \the [target] onto the floor.")) + target.reagents.trans_to(T, REAGENT_TOTAL_VOLUME(target.reagents)) diff --git a/code/modules/reagents/reagent_containers/_glass.dm b/code/modules/reagents/reagent_containers/_glass.dm new file mode 100644 index 000000000000..dde3d1891c02 --- /dev/null +++ b/code/modules/reagents/reagent_containers/_glass.dm @@ -0,0 +1,202 @@ + +//////////////////////////////////////////////////////////////////////////////// +/// (Mixing)Glass. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/chems/glass + name = "" + desc = "" + icon_state = "null" + item_state = "null" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = @"[5,10,15,25,30,60]" + chem_volume = 60 + w_class = ITEM_SIZE_SMALL + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/glass + abstract_type = /obj/item/chems/glass + drop_sound = 'sound/foley/bottledrop1.ogg' + pickup_sound = 'sound/foley/bottlepickup1.ogg' + watertight = FALSE // /glass uses the open container flag for this + +/obj/item/chems/glass/proc/get_atoms_can_be_placed_into() + var/static/list/_can_be_placed_into = list( + /obj/machinery/chem_master/, + /obj/machinery/chemical_dispenser, + /obj/machinery/reagentgrinder, + /obj/structure/table, + /obj/structure/closet, + /obj/structure/hygiene/sink, + /obj/item/grenade/chem_grenade, + /mob/living/bot/medbot, + /obj/item/secure_storage/safe, + /obj/structure/iv_drip, + /obj/machinery/disposal, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/hostile/goat, + /obj/machinery/sleeper, + /obj/machinery/smartfridge/, + /obj/machinery/biogenerator, + /obj/machinery/constructable_frame, + /obj/machinery/radiocarbon_spectrometer, + /obj/machinery/material_processing/extractor + ) + return _can_be_placed_into + +/obj/item/chems/glass/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 2) + return + if(REAGENT_TOTAL_VOLUME(reagents)) + . += SPAN_NOTICE("It contains [REAGENT_TOTAL_VOLUME(reagents)] units of reagents.") + else + . += SPAN_NOTICE("It is empty.") + if(!ATOM_IS_OPEN_CONTAINER(src)) + . += SPAN_NOTICE("The airtight lid seals it completely.") + +/obj/item/chems/glass/proc/can_lid() + return TRUE + +/obj/item/chems/glass/proc/should_drink_from(mob/drinker) + . = REAGENT_TOTAL_VOLUME(reagents) > 0 + if(.) + var/decl/material/drinking = reagents.get_primary_reagent_decl() + return drinking ? !drinking.is_unsafe_to_drink(drinker) : FALSE + +#ifdef UNIT_TEST +// Will get generated during atom creation/deletion tests so no need for a distinct unit test. +var/global/list/lid_check_glass_types = list() +/obj/item/chems/glass/Initialize() + . = ..() + if(can_lid() && !global.lid_check_glass_types[type]) + if(!check_state_in_icon("[icon_state]_lid", icon)) + log_error("Liddable vessel [type] missing lid state from [icon]!") + global.lid_check_glass_types[type] = TRUE +#endif + +/obj/item/chems/glass/on_update_icon() + . = ..() + update_overlays() + compile_overlays() + +/obj/item/chems/glass/proc/get_lid_color() + return COLOR_WHITE + +/obj/item/chems/glass/proc/get_lid_flags() + return RESET_COLOR | RESET_ALPHA + +/obj/item/chems/glass/proc/update_overlays() + if (can_lid() && !ATOM_IS_OPEN_CONTAINER(src)) + add_overlay(overlay_image(icon, "[icon_state]_lid", get_lid_color(), get_lid_flags())) + +/obj/item/chems/glass/attack_self(mob/user) + + if(can_lid() && user.check_intent(I_FLAG_HELP)) + if(ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_NOTICE("You put the lid on \the [src].")) + atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + else + to_chat(user, SPAN_NOTICE("You take the lid off \the [src].")) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + return TRUE + + if(should_drink_from(user) && is_edible(user) && handle_eaten_by_mob(user, user) != EATEN_INVALID) + return TRUE + + return ..() + +/obj/item/chems/glass/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(expend_attack_force(user) && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.check_intent(I_FLAG_HARM)) + return ..() + return FALSE + +/obj/item/chems/glass/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!ATOM_IS_OPEN_CONTAINER(src) || !proximity) //Is the container open & are they next to whatever they're clicking? + return FALSE //If not, do nothing. + if(target?.storage) + return TRUE + for(var/type in get_atoms_can_be_placed_into()) //Is it something it can be placed into? + if(istype(target, type)) + return TRUE + if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser? + return TRUE + if(standard_pour_into(user, target)) //Pouring into another beaker? + return TRUE + if(handle_eaten_by_mob(user, target) != EATEN_INVALID) + return TRUE + var/total_vol = REAGENT_TOTAL_VOLUME(reagents) + if(user.check_intent(I_FLAG_HARM)) + if(standard_splash_mob(user,target)) + return TRUE + if(reagents && total_vol) + to_chat(user, SPAN_DANGER("You splash the contents of \the [src] onto \the [target].")) + reagents.splash(target, total_vol) + return TRUE + else if(reagents && total_vol) + to_chat(user, SPAN_NOTICE("You splash a small amount of the contents of \the [src] onto \the [target].")) + reagents.splash(target, min(total_vol, 5)) + return TRUE + . = ..() + +// Drinking out of bowls. +/obj/item/chems/glass/get_edible_material_amount(mob/eater) + return REAGENT_TOTAL_VOLUME(reagents) + +/obj/item/chems/glass/get_utensil_food_type() + return /obj/item/food/lump + +// Interaction code borrowed from /food. +// Should we consider moving this down to /chems for any open container? Medicine from a bottle using a spoon, etc. +/obj/item/chems/glass/attackby(obj/item/used_item, mob/living/user) + + if(!ATOM_IS_OPEN_CONTAINER(src)) + return ..() + + var/obj/item/utensil/utensil = used_item + if(istype(utensil) && (utensil.utensil_flags & UTENSIL_FLAG_SCOOP)) + if(utensil.loaded_food) + to_chat(user, SPAN_WARNING("You already have something on \the [utensil].")) + return TRUE + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("\The [src] is empty.")) + return TRUE + separate_food_chunk(utensil, user) + if(REAGENT_TOTAL_VOLUME(utensil.loaded_food?.reagents)) + to_chat(user, SPAN_NOTICE("You scoop up some of \the [utensil.loaded_food.reagents.get_primary_reagent_name()] with \the [utensil].")) + return TRUE + + return ..() + +/obj/item/chems/glass/get_alt_interactions(mob/user) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) >= FLUID_PUDDLE) + LAZYADD(., /decl/interaction_handler/dip_item) + LAZYADD(., /decl/interaction_handler/fill_from) + if(user?.get_active_held_item()) + LAZYADD(., /decl/interaction_handler/empty_into) + if(can_lid()) + LAZYADD(., /decl/interaction_handler/toggle_lid) + +/decl/interaction_handler/toggle_lid + name = "Toggle Lid" + expected_target_type = /obj/item/chems/glass + +/decl/interaction_handler/toggle_lid/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(. && !istype(prop)) + var/obj/item/chems/glass/glass = target + return glass.can_lid() + +/decl/interaction_handler/toggle_lid/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/chems/glass/glass = target + if(istype(glass) && glass.can_lid()) + if(ATOM_IS_OPEN_CONTAINER(glass)) + to_chat(user, SPAN_NOTICE("You put the lid on \the [glass].")) + glass.atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + else + to_chat(user, SPAN_NOTICE("You take the lid off \the [glass].")) + glass.atom_flags |= ATOM_FLAG_OPEN_CONTAINER + glass.update_icon() + return TRUE + diff --git a/code/modules/reagents/reagent_containers/_glass_edibility.dm b/code/modules/reagents/reagent_containers/_glass_edibility.dm new file mode 100644 index 000000000000..2449de26a43c --- /dev/null +++ b/code/modules/reagents/reagent_containers/_glass_edibility.dm @@ -0,0 +1,7 @@ +/obj/item/chems/glass/handle_eaten_by_mob(var/mob/user, var/mob/target) + if(!ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_WARNING("You need to open \the [src] first.")) + return EATEN_UNABLE + if(user.check_intent(I_FLAG_HARM)) + return EATEN_INVALID + return ..() diff --git a/code/modules/reagents/reagent_containers/beaker.dm b/code/modules/reagents/reagent_containers/beaker.dm index 077d93d210c6..5df1a2aaf168 100644 --- a/code/modules/reagents/reagent_containers/beaker.dm +++ b/code/modules/reagents/reagent_containers/beaker.dm @@ -1,39 +1,39 @@ - /obj/item/chems/glass/beaker name = "beaker" desc = "A beaker." icon = 'icons/obj/items/chem/beakers/beaker.dmi' icon_state = ICON_STATE_WORLD - center_of_mass = @"{'x':15,'y':10}" + center_of_mass = @'{"x":15,"y":10}' material = /decl/material/solid/glass - applies_material_name = TRUE - applies_material_colour = TRUE - material_force_multiplier = 0.25 - atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_SHOW_REAGENT_NAME + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + atom_flags = ATOM_FLAG_OPEN_CONTAINER + presentation_flags = PRESENTATION_FLAG_NAME + var/lid_color = COLOR_BEASTY_BROWN -/obj/item/chems/glass/beaker/Initialize() +/obj/item/chems/glass/beaker/get_lid_color() + return lid_color + +/obj/item/chems/glass/beaker/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - desc += " It can hold up to [volume] units." + . += "It can hold up to [REAGENT_MAXIMUM_VOLUME(reagents)] units." -/obj/item/chems/glass/beaker/pickup(mob/user) - ..() +/obj/item/chems/glass/beaker/on_picked_up(mob/user, atom/old_loc) + . = ..() update_icon() /obj/item/chems/glass/beaker/dropped(mob/user) - ..() + . = ..() update_icon() /obj/item/chems/glass/beaker/attack_hand() - ..() + . = ..() update_icon() -/obj/item/chems/glass/beaker/on_update_icon() - ..() - - if(reagents?.total_volume && check_state_in_icon("[icon_state]100", icon)) - var/mutable_appearance/filling = get_mutable_overlay(icon, "[icon_state]10", reagents.get_color()) +/obj/item/chems/glass/beaker/update_overlays() - var/percent = round((reagents.total_volume / volume) * 100) + if(REAGENT_TOTAL_VOLUME(reagents)) + var/image/filling = mutable_appearance(icon, "[icon_state]1", reagents.get_color()) + var/percent = round((REAGENT_TOTAL_VOLUME(reagents) / REAGENT_MAXIMUM_VOLUME(reagents)) * 100) switch(percent) if(0 to 9) filling.icon_state = "[icon_state]1" if(10 to 24) filling.icon_state = "[icon_state]10" @@ -42,97 +42,143 @@ if(75 to 79) filling.icon_state = "[icon_state]75" if(80 to 90) filling.icon_state = "[icon_state]80" if(91 to INFINITY) filling.icon_state = "[icon_state]100" + add_overlay(filling) - overlays += filling + var/image/overglass = mutable_appearance(icon, "[icon_state]_over", color) + overglass.alpha = alpha * ((alpha/255) ** 3) + add_overlay(overglass) - if(!ATOM_IS_OPEN_CONTAINER(src)) - overlays += get_mutable_overlay(icon, "[icon_state]_lid") + if(material.reflectiveness >= MAT_VALUE_SHINY) + var/mutable_appearance/shine = mutable_appearance(icon, "[icon_state]_shine", adjust_brightness(color, 20 + material.reflectiveness)) + shine.alpha = material.reflectiveness * 3 + add_overlay(shine) + + . = ..() + + compile_overlays() + +/obj/item/chems/glass/beaker/throw_impact(atom/hit_atom) + . = ..() + if(ATOM_IS_OPEN_CONTAINER(src)) + reagents.splash(hit_atom, rand(REAGENT_TOTAL_VOLUME(reagents)*0.25,REAGENT_TOTAL_VOLUME(reagents)), min_spill = 60, max_spill = 100) + take_damage(rand(4,8)) /obj/item/chems/glass/beaker/large - name = "large beaker" + name_prefix = "large" + name = "beaker" // see update_name override below desc = "A large beaker." icon = 'icons/obj/items/chem/beakers/large.dmi' - center_of_mass = @"{'x':16,'y':10}" - volume = 120 + center_of_mass = @'{"x":16,"y":10}' + chem_volume = 120 amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[5,10,15,25,30,60,120]" - material_force_multiplier = 0.5 + w_class = ITEM_SIZE_LARGE /obj/item/chems/glass/beaker/bowl name = "mixing bowl" desc = "A large mixing bowl." icon = 'icons/obj/items/chem/mixingbowl.dmi' - center_of_mass = @"{'x':16,'y':10}" - volume = 180 + center_of_mass = @'{"x":16,"y":10}' + chem_volume = 180 amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[5,10,15,25,30,60,180]" atom_flags = ATOM_FLAG_OPEN_CONTAINER - unacidable = 0 material = /decl/material/solid/metal/steel - material_force_multiplier = 0.2 + +/obj/item/chems/glass/beaker/bowl/can_lid() + return FALSE + +/obj/item/chems/glass/beaker/bowl/pottery + material = /decl/material/solid/stone/pottery + +/obj/item/chems/glass/beaker/kettle + name = "kettle" + desc = "A heavy kettle for heating water." + icon = 'icons/obj/items/chem/kettle.dmi' + icon_state = ICON_STATE_WORLD + chem_volume = 180 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = @"[5,10,15,25,30,60,180]" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + material = /decl/material/solid/metal/iron + obj_flags = OBJ_FLAG_HOLLOW | OBJ_FLAG_INSULATED_HANDLE + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/chems/glass/beaker/kettle/can_lid() + return FALSE /obj/item/chems/glass/beaker/noreact name = "cryostasis beaker" desc = "A cryostasis beaker that allows for chemical storage without reactions." icon = 'icons/obj/items/chem/beakers/stasis.dmi' - center_of_mass = @"{'x':16,'y':8}" - volume = 60 + center_of_mass = @'{"x":16,"y":8}' + chem_volume = 60 amount_per_transfer_from_this = 10 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT | ATOM_FLAG_SHOW_REAGENT_NAME + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_CHEM_CHANGE + presentation_flags = PRESENTATION_FLAG_NAME material = /decl/material/solid/metal/steel - applies_material_name = FALSE - applies_material_colour = FALSE + material_alteration = MAT_FLAG_ALTERATION_NONE + origin_tech = @'{"materials":2}' + lid_color = COLOR_PALE_BLUE_GRAY /obj/item/chems/glass/beaker/advanced name = "advanced beaker" desc = "An advanced beaker, powered by experimental technology." icon = 'icons/obj/items/chem/beakers/advanced.dmi' - center_of_mass = @"{'x':16,'y':10}" - volume = 300 + center_of_mass = @'{"x":16,"y":10}' + chem_volume = 300 amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[5,10,15,25,30,60,120,150,200,250,300]" - material_force_multiplier = 2.5 - applies_material_colour = FALSE - applies_material_name = FALSE + material_alteration = MAT_FLAG_ALTERATION_NONE material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"exoticmatter":2,"materials":6}' + lid_color = COLOR_CYAN_BLUE /obj/item/chems/glass/beaker/vial name = "vial" desc = "A small glass vial." icon = 'icons/obj/items/chem/vial.dmi' - center_of_mass = @"{'x':15,'y':8}" - volume = 30 + center_of_mass = @'{"x":15,"y":8}' + chem_volume = 30 w_class = ITEM_SIZE_TINY //half the volume of a bottle, half the size amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[5,10,15,30]" - material_force_multiplier = 0.1 + +/obj/item/chems/glass/beaker/vial/throw_impact(atom/hit_atom) + . = ..() + if(material?.is_brittle()) + shatter() /obj/item/chems/glass/beaker/insulated name = "insulated beaker" desc = "A glass beaker surrounded with black insulation." icon = 'icons/obj/items/chem/beakers/insulated.dmi' - center_of_mass = @"{'x':15,'y':8}" - matter = list(/decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT) + center_of_mass = @'{"x":15,"y":8}' + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) possible_transfer_amounts = @"[5,10,15,30]" - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_SHOW_REAGENT_NAME - applies_material_colour = FALSE - temperature_coefficient = 1 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + presentation_flags = PRESENTATION_FLAG_NAME material = /decl/material/solid/metal/steel - applies_material_name = FALSE - applies_material_colour = FALSE + material_alteration = MAT_FLAG_ALTERATION_NONE + lid_color = COLOR_GRAY40 + +/obj/item/chems/glass/beaker/insulated/get_thermal_mass_coefficient(delta) + return 0.1 + +// Hack around reagent temp changes. +/obj/item/chems/glass/beaker/insulated/ProcessAtomTemperature() + return PROCESS_KILL /obj/item/chems/glass/beaker/insulated/large name = "large insulated beaker" icon = 'icons/obj/items/chem/beakers/insulated_large.dmi' - center_of_mass = @"{'x':16,'y':10}" - matter = list(/decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT) - volume = 120 + center_of_mass = @'{"x":16,"y":10}' + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + chem_volume = 120 -/obj/item/chems/glass/beaker/sulphuric/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/acid, 60) - update_icon() \ No newline at end of file +/obj/item/chems/glass/beaker/sulfuric/populate_reagents() + add_to_reagents(/decl/material/liquid/acid, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 02e0420a6468..593d6e37a74e 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -1,21 +1,23 @@ -/obj/item/storage/box/bloodpacks +/obj/item/box/bloodpacks name = "blood packs box" desc = "This box contains blood packs." icon_state = "sterile" - startswith = list(/obj/item/chems/ivbag = 7) + +/obj/item/box/bloodpacks/WillContain() + return list(/obj/item/chems/ivbag = 7) /obj/item/chems/ivbag name = "\improper IV bag" desc = "Flexible bag for IV injectors." icon = 'icons/obj/bloodpack.dmi' icon_state = "empty" - w_class = ITEM_SIZE_TINY - volume = 120 + w_class = ITEM_SIZE_SMALL + chem_volume = 120 possible_transfer_amounts = @"[0.2,1,2]" amount_per_transfer_from_this = REM atom_flags = ATOM_FLAG_OPEN_CONTAINER - var/mob/living/carbon/human/attached + var/mob/living/human/attached /obj/item/chems/ivbag/Destroy() STOP_PROCESSING(SSobj,src) @@ -23,36 +25,31 @@ . = ..() /obj/item/chems/ivbag/on_reagent_change() - update_icon() - if(reagents.total_volume > volume/2) - w_class = ITEM_SIZE_SMALL + if(!(. = ..())) + return + if(REAGENT_TOTAL_VOLUME(reagents) > REAGENT_MAXIMUM_VOLUME(reagents) / 2) + w_class = ITEM_SIZE_NORMAL else - w_class = ITEM_SIZE_TINY + w_class = ITEM_SIZE_SMALL /obj/item/chems/ivbag/on_update_icon() - overlays.Cut() - var/percent = round(reagents.total_volume / volume * 100) - if(reagents.total_volume) - var/image/filling = image('icons/obj/bloodpack.dmi', "[round(percent,25)]") - filling.color = reagents.get_color() - overlays += filling - overlays += image('icons/obj/bloodpack.dmi', "top") - if(attached) - overlays += image('icons/obj/bloodpack.dmi', "dongle") - -/obj/item/chems/ivbag/MouseDrop(over_object, src_location, over_location) - if(!CanMouseDrop(over_object)) - return - if(!ismob(loc)) - return - if(attached) - visible_message("\The [attached] is taken off \the [src]") - attached = null - else if(ishuman(over_object)) - if(do_IV_hookup(over_object, usr, src)) - attached = over_object - START_PROCESSING(SSobj,src) - update_icon() + . = ..() + var/percent = round(REAGENT_TOTAL_VOLUME(reagents) / REAGENT_MAXIMUM_VOLUME(reagents) * 100) + if(percent) + add_overlay(overlay_image(icon, "[round(percent,25)]", reagents.get_color())) + add_overlay(attached? "dongle" : "top") + +/obj/item/chems/ivbag/handle_mouse_drop(atom/over, mob/user, params) + if(ismob(loc)) + if(attached) + visible_message(SPAN_NOTICE("\The [attached] is taken off \the [src].")) + attached = null + else if(ishuman(over) && do_IV_hookup(over, user, src)) + attached = over + START_PROCESSING(SSobj, src) + update_icon() + return TRUE + return ..() /obj/item/chems/ivbag/Process() if(!ismob(loc)) @@ -61,50 +58,59 @@ if(attached) if(!loc.Adjacent(attached)) attached = null - visible_message("\The [attached] detaches from \the [src]") + visible_message("\The [attached] detaches from \the [src].") update_icon() return PROCESS_KILL else return PROCESS_KILL var/mob/M = loc - if(M.l_hand != src && M.r_hand != src) + if(!(src in M.get_held_items())) return - if(!reagents.total_volume) + if(!REAGENT_TOTAL_VOLUME(reagents)) return reagents.trans_to_mob(attached, amount_per_transfer_from_this, CHEM_INJECT) update_icon() -/obj/item/chems/ivbag/nanoblood/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/nanoblood, volume) - /obj/item/chems/ivbag/blood name = "blood pack" - var/blood_type = null + var/blood_fill_type = /decl/material/liquid/blood -/obj/item/chems/ivbag/blood/Initialize() - . = ..() - if(blood_type) - name = "blood pack [blood_type]" - reagents.add_reagent(/decl/material/liquid/blood, volume, list("donor" = null, "blood_DNA" = null, "blood_type" = blood_type, "trace_chem" = null)) +/obj/item/chems/ivbag/blood/proc/get_initial_blood_data() + return list( + DATA_BLOOD_DONOR = null, + DATA_BLOOD_DNA = null, + DATA_BLOOD_TYPE = label_text, + DATA_BLOOD_TRACE_CHEM = null + ) + +/obj/item/chems/ivbag/blood/populate_reagents() + if(blood_fill_type) + add_to_reagents(blood_fill_type, REAGENT_MAXIMUM_VOLUME(reagents), get_initial_blood_data()) + +/obj/item/chems/ivbag/blood/nanoblood + label_text = "synthetic" + blood_fill_type = /decl/material/liquid/nanoblood + +/obj/item/chems/ivbag/blood/nanoblood/get_initial_blood_data() + return null -/obj/item/chems/ivbag/blood/APlus - blood_type = "A+" +/obj/item/chems/ivbag/blood/aplus + label_text = "A+" -/obj/item/chems/ivbag/blood/AMinus - blood_type = "A-" +/obj/item/chems/ivbag/blood/aminus + label_text = "A-" -/obj/item/chems/ivbag/blood/BPlus - blood_type = "B+" +/obj/item/chems/ivbag/blood/bplus + label_text = "B+" -/obj/item/chems/ivbag/blood/BMinus - blood_type = "B-" +/obj/item/chems/ivbag/blood/bminus + label_text = "B-" -/obj/item/chems/ivbag/blood/OPlus - blood_type = "O+" +/obj/item/chems/ivbag/blood/oplus + label_text = "O+" -/obj/item/chems/ivbag/blood/OMinus - blood_type = "O-" +/obj/item/chems/ivbag/blood/ominus + label_text = "O-" diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm deleted file mode 100644 index 8af65392b4df..000000000000 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ /dev/null @@ -1,179 +0,0 @@ -/obj/item/chems/borghypo - name = "cyborg hypospray" - desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment." - icon = 'icons/obj/syringe.dmi' - item_state = "hypo" - icon_state = "borghypo" - amount_per_transfer_from_this = 5 - volume = 30 - possible_transfer_amounts = null - - var/mode = 1 - var/charge_cost = 50 - var/charge_tick = 0 - var/recharge_time = 5 //Time it takes for shots to recharge (in seconds) - - var/list/reagent_ids = list(/decl/material/liquid/regenerator, /decl/material/liquid/stabilizer, /decl/material/liquid/antibiotics) - var/list/reagent_volumes = list() - var/list/reagent_names = list() - -/obj/item/chems/borghypo/surgeon - reagent_ids = list(/decl/material/liquid/brute_meds, /decl/material/liquid/oxy_meds, /decl/material/liquid/painkillers) - -/obj/item/chems/borghypo/crisis - reagent_ids = list(/decl/material/liquid/regenerator, /decl/material/liquid/stabilizer, /decl/material/liquid/painkillers) - -/obj/item/chems/borghypo/Initialize() - . = ..() - - for(var/T in reagent_ids) - reagent_volumes[T] = volume - var/decl/material/R = T - reagent_names += initial(R.name) - -/obj/item/chems/borghypo/Initialize() - . = ..() - START_PROCESSING(SSobj, src) - -/obj/item/chems/borghypo/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/chems/borghypo/Process() //Every [recharge_time] seconds, recharge some reagents for the cyborg+ - if(++charge_tick < recharge_time) - return 0 - charge_tick = 0 - - if(isrobot(loc)) - var/mob/living/silicon/robot/R = loc - if(R && R.cell) - for(var/T in reagent_ids) - if(reagent_volumes[T] < volume) - R.cell.use(charge_cost) - reagent_volumes[T] = min(reagent_volumes[T] + 5, volume) - return 1 - -/obj/item/chems/borghypo/attack(var/mob/living/M, var/mob/user, var/target_zone) - if(!istype(M)) - return - - if(!reagent_volumes[reagent_ids[mode]]) - to_chat(user, "The injector is empty.") - return - - var/allow = M.can_inject(user, target_zone) - if (allow) - if (allow == INJECTION_PORT) - user.visible_message(SPAN_WARNING("\The [user] begins hunting for an injection port on \the [M]'s suit!")) - if(!user.do_skilled(INJECTION_PORT_DELAY, SKILL_MEDICAL, M)) - return - to_chat(user, "You inject [M] with the injector.") - to_chat(M, "You feel a tiny prick!") - - if(M.reagents) - var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]]) - M.reagents.add_reagent(reagent_ids[mode], t) - reagent_volumes[reagent_ids[mode]] -= t - admin_inject_log(user, M, src, reagent_ids[mode], t) - to_chat(user, "[t] units injected. [reagent_volumes[reagent_ids[mode]]] units remaining.") - return - -/obj/item/chems/borghypo/attack_self(mob/user) //Change the mode - var/t = "" - for(var/i = 1 to reagent_ids.len) - if(t) - t += ", " - if(mode == i) - t += "[reagent_names[i]]" - else - t += "[reagent_names[i]]" - t = "Available reagents: [t]." - to_chat(user, t) - - return - -/obj/item/chems/borghypo/OnTopic(var/href, var/list/href_list) - if(href_list["reagent_index"]) - var/index = text2num(href_list["reagent_index"]) - if(index > 0 && index <= reagent_ids.len) - playsound(loc, 'sound/effects/pop.ogg', 50, 0) - mode = index - var/decl/material/R = reagent_ids[mode] - to_chat(usr, "Synthesizer is now producing '[initial(R.name)]'.") - return TOPIC_REFRESH - -/obj/item/chems/borghypo/examine(mob/user, distance) - . = ..() - if(distance > 2) - return - - var/decl/material/R = reagent_ids[mode] - to_chat(user, "It is currently producing [initial(R.name)] and has [reagent_volumes[reagent_ids[mode]]] out of [volume] units left.") - -/obj/item/chems/borghypo/service - name = "cyborg drink synthesizer" - desc = "A portable drink dispencer." - icon = 'icons/obj/drinks.dmi' - icon_state = "shaker" - charge_cost = 5 - recharge_time = 3 - volume = 60 - possible_transfer_amounts = @"[5,10,20,30]" - reagent_ids = list( - /decl/material/liquid/ethanol/beer, - /decl/material/liquid/ethanol/coffee/kahlua, - /decl/material/liquid/ethanol/whiskey, - /decl/material/liquid/ethanol/wine, - /decl/material/liquid/ethanol/vodka, - /decl/material/liquid/ethanol/gin, - /decl/material/liquid/ethanol/rum, - /decl/material/liquid/ethanol/tequilla, - /decl/material/liquid/ethanol/vermouth, - /decl/material/liquid/ethanol/cognac, - /decl/material/liquid/ethanol/ale, - /decl/material/liquid/ethanol/mead, - /decl/material/liquid/water, - /decl/material/liquid/nutriment/sugar, - /decl/material/solid/ice, - /decl/material/liquid/drink/tea/black, - /decl/material/liquid/drink/cola, - /decl/material/liquid/drink/citrussoda, - /decl/material/liquid/drink/cherrycola, - /decl/material/liquid/drink/lemonade, - /decl/material/liquid/drink/tonic, - /decl/material/liquid/drink/sodawater, - /decl/material/liquid/drink/lemon_lime, - /decl/material/liquid/drink/juice/orange, - /decl/material/liquid/drink/juice/lime, - /decl/material/liquid/drink/juice/watermelon, - /decl/material/liquid/drink/coffee, - /decl/material/liquid/drink/hot_coco, - /decl/material/liquid/drink/tea/green, - /decl/material/liquid/drink/citrussoda, - /decl/material/liquid/ethanol/beer, - /decl/material/liquid/ethanol/coffee/kahlua - ) - -/obj/item/chems/borghypo/service/attack(var/mob/M, var/mob/user) - return - -/obj/item/chems/borghypo/service/afterattack(var/obj/target, var/mob/user, var/proximity) - if(!proximity) - return - - if(!ATOM_IS_OPEN_CONTAINER(target) || !target.reagents) - return - - if(!reagent_volumes[reagent_ids[mode]]) - to_chat(user, "[src] is out of this reagent, give it some time to refill.") - return - - if(!REAGENTS_FREE_SPACE(target.reagents)) - to_chat(user, "[target] is full.") - return - - var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]]) - target.reagents.add_reagent(reagent_ids[mode], t) - reagent_volumes[reagent_ids[mode]] -= t - to_chat(user, "You transfer [t] units of the solution to [target].") - return diff --git a/code/modules/reagents/reagent_containers/borghypo.dm b/code/modules/reagents/reagent_containers/borghypo.dm new file mode 100644 index 000000000000..a84c183b2bd2 --- /dev/null +++ b/code/modules/reagents/reagent_containers/borghypo.dm @@ -0,0 +1,203 @@ +/obj/item/chems/borghypo + name = "cyborg hypospray" + desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment." + icon = 'icons/obj/hypospray_borg.dmi' + amount_per_transfer_from_this = 5 + chem_volume = 30 + possible_transfer_amounts = null + max_health = ITEM_HEALTH_NO_DAMAGE + + var/mode = 1 + var/charge_cost = 50 + var/charge_tick = 0 + var/recharge_time = 5 //Time it takes for shots to recharge (in seconds) + +/obj/item/chems/borghypo/Initialize() + chem_volume *= length(get_generated_reagents()) + . = ..() + +/obj/item/chems/borghypo/proc/get_generated_reagents() + var/static/list/_reagent_ids = list( + /decl/material/liquid/regenerator, + /decl/material/liquid/stabilizer, + /decl/material/liquid/antibiotics + ) + return _reagent_ids + +/obj/item/chems/borghypo/surgeon/get_generated_reagents() + var/static/list/_reagent_ids = list( + /decl/material/liquid/brute_meds, + /decl/material/liquid/oxy_meds, + /decl/material/liquid/painkillers/strong + ) + return _reagent_ids + +/obj/item/chems/borghypo/crisis/get_generated_reagents() + var/static/list/_reagent_ids = list( + /decl/material/liquid/regenerator, + /decl/material/liquid/stabilizer, + /decl/material/liquid/painkillers/strong + ) + return _reagent_ids + +/obj/item/chems/borghypo/populate_reagents() + . = ..() + var/list/reagent_ids = get_generated_reagents() + for(var/decl/material/reagent in decls_repository.get_decls_unassociated(reagent_ids)) + reagents.add_reagent(reagent.type, round(REAGENT_MAXIMUM_VOLUME(reagents) / length(reagent_ids))) + START_PROCESSING(SSobj, src) + +/obj/item/chems/borghypo/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/chems/borghypo/Process() //Every [recharge_time] seconds, recharge some reagents for the cyborg+ + if(++charge_tick < recharge_time) + return + charge_tick = 0 + if(!isrobot(loc)) + return + var/mob/living/silicon/robot/robot = loc + if(!robot?.cell) + return + var/list/reagent_ids = get_generated_reagents() + var/max_per_reagent = round(REAGENT_MAXIMUM_VOLUME(reagents) / length(reagent_ids)) + for(var/reagent in reagent_ids) + var/has_reagent = REAGENT_VOLUME(reagents, GET_DECL(reagent)) + if(has_reagent < max_per_reagent) + robot.cell.use(charge_cost) + reagents.add_reagent(reagent, round(max_per_reagent - has_reagent)) + +/obj/item/chems/borghypo/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + var/list/reagent_ids = get_generated_reagents() + if(REAGENT_VOLUME(reagents, GET_DECL(reagent_ids[mode])) <= 0) + to_chat(user, SPAN_WARNING("The injector is empty.")) + return TRUE + + var/allow = target.can_inject(user, user.get_target_zone()) + if (allow) + if (allow == INJECTION_PORT) + user.visible_message(SPAN_WARNING("\The [user] begins hunting for an injection port on \the [target]'s suit!")) + if(!user.do_skilled(INJECTION_PORT_DELAY, SKILL_MEDICAL, target)) + return TRUE + + to_chat(user, SPAN_NOTICE("You inject \the [target] with the injector.")) + to_chat(target, SPAN_NOTICE("You feel a tiny prick!")) + + if(target.reagents) + var/t = min(amount_per_transfer_from_this, REAGENT_VOLUME(reagents, GET_DECL(reagent_ids[mode]))) + target.add_to_reagents(reagent_ids[mode], t) + reagents.remove_reagent(reagent_ids[mode], t) + admin_inject_log(user, target, src, reagent_ids[mode], t) + to_chat(user, SPAN_NOTICE("[t] units injected. [REAGENT_VOLUME(reagents, GET_DECL(reagent_ids[mode])) || 0] unit\s remaining.")) + return TRUE + + return ..() + +/obj/item/chems/borghypo/attack_self(mob/user) //Change the mode + var/t = "" + var/list/reagent_ids = get_generated_reagents() + for(var/i = 1 to length(reagent_ids)) + var/decl/material/reagent = GET_DECL(reagent_ids[i]) + if(t) + t += ", " + if(mode == i) + t += "[reagent.liquid_name]" + else + t += "[reagent.liquid_name]" + t = "Available reagents: [t]." + to_chat(user, t) + + return + +/obj/item/chems/borghypo/OnTopic(mob/user, href_list, datum/topic_state/state) + if(href_list["reagent_index"]) + var/list/reagent_ids = get_generated_reagents() + var/index = text2num(href_list["reagent_index"]) + if(index > 0 && index <= reagent_ids.len) + playsound(loc, 'sound/effects/pop.ogg', 50, 0) + mode = index + var/decl/material/reagent = GET_DECL(reagent_ids[mode]) + to_chat(user, SPAN_NOTICE("Synthesizer is now producing '[reagent.use_name]'.")) + return TOPIC_REFRESH + +/obj/item/chems/borghypo/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 2) + return + var/list/reagent_ids = get_generated_reagents() + var/decl/material/reagent = GET_DECL(reagent_ids[mode]) + . += SPAN_NOTICE("It is currently producing [reagent.use_name] and has [REAGENT_VOLUME(reagents, reagent)] out of [round(REAGENT_MAXIMUM_VOLUME(reagents) / length(reagent_ids))] units left.") + +/obj/item/chems/borghypo/service + name = "cyborg drink synthesizer" + desc = "A portable drink dispenser." + icon = 'icons/obj/drinks.dmi' + icon_state = "shaker" + charge_cost = 5 + recharge_time = 3 + chem_volume = 60 + possible_transfer_amounts = @"[5,10,20,30]" + +/obj/item/chems/borghypo/service/get_generated_reagents() + var/static/list/_reagent_ids = list( + /decl/material/liquid/alcohol/beer, + /decl/material/liquid/alcohol/coffee, + /decl/material/liquid/alcohol/whiskey, + /decl/material/liquid/alcohol/wine, + /decl/material/liquid/alcohol/vodka, + /decl/material/liquid/alcohol/gin, + /decl/material/liquid/alcohol/rum, + /decl/material/liquid/alcohol/tequila, + /decl/material/liquid/alcohol/vermouth, + /decl/material/liquid/alcohol/cognac, + /decl/material/liquid/alcohol/ale, + /decl/material/liquid/alcohol/mead, + /decl/material/liquid/water, + /decl/material/liquid/nutriment/sugar, + /decl/material/solid/ice, + /decl/material/liquid/drink/tea/black, + /decl/material/liquid/drink/cola, + /decl/material/liquid/drink/citrussoda, + /decl/material/liquid/drink/cherrycola, + /decl/material/liquid/drink/lemonade, + /decl/material/liquid/drink/tonic, + /decl/material/liquid/drink/sodawater, + /decl/material/liquid/drink/lemon_lime, + /decl/material/liquid/drink/juice/orange, + /decl/material/liquid/drink/juice/lime, + /decl/material/liquid/drink/juice/watermelon, + /decl/material/liquid/drink/coffee, + /decl/material/liquid/drink/hot_coco, + /decl/material/liquid/drink/tea/green, + /decl/material/liquid/drink/citrussoda, + /decl/material/liquid/alcohol/beer, + /decl/material/liquid/alcohol/coffee + ) + return _reagent_ids + +/obj/item/chems/borghypo/service/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE + +/obj/item/chems/borghypo/service/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!proximity) + return + + if(!ATOM_IS_OPEN_CONTAINER(target) || !target.reagents) + return + + var/list/reagent_ids = get_generated_reagents() + if(REAGENT_VOLUME(reagents, GET_DECL(reagent_ids[mode])) <= 0) + to_chat(user, "[src] is out of this reagent, give it some time to refill.") + return + + if(!REAGENTS_FREE_SPACE(target.reagents)) + to_chat(user, "[target] is full.") + return + + var/t = min(amount_per_transfer_from_this, REAGENT_VOLUME(reagents, GET_DECL(reagent_ids[mode]))) + target.add_to_reagents(reagent_ids[mode], t) + reagents.remove_reagent(reagent_ids[mode], t) + to_chat(user, "You transfer [t] units of the solution to [target].") + return diff --git a/code/modules/reagents/reagent_containers/bowl.dm b/code/modules/reagents/reagent_containers/bowl.dm new file mode 100644 index 000000000000..41dd9943d960 --- /dev/null +++ b/code/modules/reagents/reagent_containers/bowl.dm @@ -0,0 +1,216 @@ +/obj/item/chems/glass/bowl + name = "bowl" + desc = "A moderately-sized bowl, suitable for serving soup or other soft or liquid foods." + material = /decl/material/solid/stone/ceramic + icon = 'icons/obj/food/plates/bowl.dmi' + icon_state = ICON_STATE_WORLD + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + presentation_flags = PRESENTATION_FLAG_NAME + chem_volume = 30 + amount_per_transfer_from_this = 5 + +/obj/item/chems/glass/bowl/can_lid() + return FALSE + +// Predefined soup types for mapping. +/obj/item/chems/glass/bowl/mapped + abstract_type = /obj/item/chems/glass/bowl/mapped + var/initial_reagent_amount = 20 + var/initial_reagent_type = /decl/material/liquid/nutriment/soup/simple + +/obj/item/chems/glass/bowl/mapped/proc/get_initial_reagent_data() + return + +/obj/item/chems/glass/bowl/mapped/populate_reagents() + . = ..() + if(initial_reagent_type) + add_to_reagents(initial_reagent_type, initial_reagent_amount, get_initial_reagent_data()) + +/obj/item/chems/glass/bowl/mapped/vegetable/get_initial_reagent_data() + return list( + DATA_TASTE = list("carrot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2), + DATA_INGREDIENT_LIST = list("carrot" = 1, "corn" = 1, "eggplant" = 1, "potato" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_VEGETABLE, + DATA_MASK_NAME = "vegetable soup", + DATA_MASK_COLOR = "#afc4b5" + ) + +/obj/item/chems/glass/bowl/mapped/beet/get_initial_reagent_data() + . = list( + DATA_TASTE = list("whitebeet" = 1, "cabbage" = 1), + DATA_INGREDIENT_LIST = list("whitebeet" = 1, "cabbage" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_VEGETABLE, + DATA_MASK_NAME = pick("borsch","bortsch","borstch","borsh","borshch","borscht"), + DATA_MASK_COLOR = "#fac9ff" + ) + +/obj/item/chems/glass/bowl/mapped/tomato/get_initial_reagent_data() + return list( + DATA_TASTE = list("tomato" = 1), + DATA_INGREDIENT_LIST = list("tomato" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_VEGETABLE, + DATA_MASK_COLOR = "#ff0000" + ) + +/obj/item/chems/glass/bowl/mapped/mushroom/get_initial_reagent_data() + return list( + DATA_TASTE = list("creamy mushroom" = 1), + DATA_INGREDIENT_LIST = list("mushroom" = 1, "milk" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_DAIRY), + DATA_MASK_NAME = "mushroom soup", + DATA_MASK_COLOR = "#e386bf" + ) + +/obj/item/chems/glass/bowl/mapped/blood/get_initial_reagent_data() + return list( + DATA_TASTE = list("iron" = 1, "copper" = 1), + DATA_INGREDIENT_LIST = list("blood" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_MEAT, + DATA_MASK_NAME = "tomato soup", + DATA_MASK_COLOR = "#ff0000" + ) + +/obj/item/chems/glass/bowl/mapped/nettle/get_initial_reagent_data() + return list( + DATA_TASTE = list("sharp acid" = 1, "nettles" = 1, "potato chunks" = 1), + DATA_INGREDIENT_LIST = list("nettle" = 1, "potato" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_VEGETABLE, + DATA_MASK_COLOR = "#afc4b5" + ) + +/obj/item/chems/glass/bowl/mapped/meatball/get_initial_reagent_data() + return list( + DATA_TASTE = list("savoury meatballs" = 2, "cooked carrot" = 1, "cooked potato" = 1), + DATA_INGREDIENT_LIST = list("meatball" = 1, "carrot" = 1, "potato" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_MEAT), + DATA_MASK_COLOR = "#785210" + ) + +/obj/item/chems/glass/bowl/mapped/stew + initial_reagent_type = /decl/material/liquid/nutriment/soup/stew + +/obj/item/chems/glass/bowl/mapped/stew/get_initial_reagent_data() + return list( + DATA_TASTE = list("savoury meat" = 2, "stewed carrot" = 1, "stewed potato" = 1, "stewed tomato" = 1, "stewed eggplant" = 1, "stewed mushroom" = 1), + DATA_INGREDIENT_LIST = list("meat" = 1, "tomato" = 1, "carrot" = 1, "potato" = 1, "eggplant" = 1, "mushroom" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_MEAT), + DATA_MASK_NAME = "hearty stew", + DATA_MASK_COLOR = "#9e673a" + ) + +/obj/item/chems/glass/bowl/mapped/chili + abstract_type = /obj/item/chems/glass/bowl/mapped/chili + initial_reagent_type = /decl/material/liquid/nutriment/soup/chili + +/obj/item/chems/glass/bowl/mapped/chili/hot/get_initial_reagent_data() + return list( + DATA_TASTE = list("chilli peppers" = 1, "burning" = 1, "spicy meat" = 2, "tomato" = 1), + DATA_INGREDIENT_LIST = list("meat" = 1, "tomato" = 1, "chili" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_MEAT), + DATA_MASK_NAME = "hot chili", + DATA_MASK_COLOR = "#ff3c00" + ) + +/obj/item/chems/glass/bowl/mapped/chili/cold/get_initial_reagent_data() + return list( + DATA_TASTE = list("chilly peppers" = 1, "freezing" = 1, "spicy meat" = 2, "tomato" = 1), + DATA_INGREDIENT_LIST = list("meat" = 1, "tomato" = 1, "chili" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_MEAT), + DATA_MASK_NAME = "cold chili", + DATA_MASK_COLOR = "#2b00ff" + ) + +/obj/item/chems/glass/bowl/mapped/curry + abstract_type = /obj/item/chems/glass/bowl/mapped/curry + initial_reagent_type = /decl/material/liquid/nutriment/soup/curry + +/obj/item/chems/glass/bowl/mapped/curry/katsu/get_initial_reagent_data() + return list( + DATA_TASTE = list("crumbed chicken" = 1, "curried apple" = 1, "curried potato" = 1, "curried carrot" = 1), + DATA_INGREDIENT_LIST = list("apple" = 1, "carrot" = 1, "potato" = 1, "chicken" = 1, "rice" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_MEAT), + DATA_MASK_NAME = "chicken katsu curry", + DATA_MASK_COLOR = "#faa005" + ) + +/obj/item/chems/glass/bowl/mapped/noodlesoup + abstract_type = /obj/item/chems/glass/bowl/mapped/noodlesoup + initial_reagent_type = /decl/material/liquid/nutriment/soup/noodle + +/obj/item/chems/glass/bowl/mapped/noodlesoup/chicken/get_initial_reagent_data() + return list( + DATA_TASTE = list("chicken" = 1, "carrot" = 1), + DATA_INGREDIENT_LIST = list("chicken" = 1, "carrot" = 1), + DATA_INGREDIENT_FLAGS = (ALLERGEN_VEGETABLE | ALLERGEN_MEAT), + ) + +// Mystery soup is special/stupid. +/obj/item/chems/glass/bowl/mystery + var/drained = FALSE + +/obj/item/chems/glass/bowl/mystery/populate_reagents() + . = ..() + var/list/fillings = pick(get_random_fillings()) + for(var/filling in fillings) + add_to_reagents(filling, fillings[filling]) + +/obj/item/chems/glass/bowl/mystery/update_name() + if(!drained && REAGENT_TOTAL_VOLUME(reagents)) + SetName("mystery soup") + else + ..() + +/obj/item/chems/glass/bowl/mystery/on_reagent_change() + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + drained = TRUE + . = ..() + +/obj/item/chems/glass/bowl/mystery/update_container_desc() + if(!drained && REAGENT_TOTAL_VOLUME(reagents)) + desc = "The mystery is, why aren't you eating it?" + else + ..() + +/obj/item/chems/glass/bowl/mystery/proc/get_random_fillings() + return list( + list( + /decl/material/liquid/nutriment = 6, + /decl/material/liquid/capsaicin = 3, + /decl/material/liquid/drink/juice/tomato = 2 + ), + list( + /decl/material/liquid/nutriment = 6, + /decl/material/liquid/frostoil = 3, + /decl/material/liquid/drink/juice/tomato = 2 + ), + list( + /decl/material/liquid/nutriment = 5, + /decl/material/liquid/water = 5, + /decl/material/liquid/regenerator = 5 + ), + list( + /decl/material/liquid/nutriment = 5, + /decl/material/liquid/water = 10 + ), + list( + /decl/material/liquid/nutriment = 2, + /decl/material/liquid/drink/juice/banana = 10 + ), + list( + /decl/material/liquid/nutriment = 6, + /decl/material/liquid/blood = 10 + ), + list( + /decl/material/solid/carbon = 10, + /decl/material/liquid/acrylamide = 10 + ), + list( + /decl/material/liquid/nutriment = 5, + /decl/material/liquid/drink/juice/tomato = 10 + ), + list( + /decl/material/liquid/nutriment = 6, + /decl/material/liquid/drink/juice/tomato = 5, + /decl/material/liquid/eyedrops = 5 + ) + ) diff --git a/code/modules/reagents/reagent_containers/bucket.dm b/code/modules/reagents/reagent_containers/bucket.dm new file mode 100644 index 000000000000..228bfb78d19e --- /dev/null +++ b/code/modules/reagents/reagent_containers/bucket.dm @@ -0,0 +1,83 @@ +/obj/item/chems/glass/bucket + name = "bucket" + desc = "It's a bucket." + icon = 'icons/obj/items/bucket.dmi' + icon_state = ICON_STATE_WORLD + center_of_mass = @'{"x":16,"y":9}' + w_class = ITEM_SIZE_NORMAL + amount_per_transfer_from_this = 20 + possible_transfer_amounts = @"[10,20,30,60,120,150,180]" + chem_volume = 180 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + presentation_flags = PRESENTATION_FLAG_NAME + material = /decl/material/solid/organic/plastic + slot_flags = SLOT_HEAD + drop_sound = 'sound/foley/donk1.ogg' + pickup_sound = 'sound/foley/pickup2.ogg' + +/obj/item/chems/glass/bucket/proc/get_handle_overlay() + return overlay_image(icon, "[icon_state]-handle", COLOR_WHITE, RESET_COLOR) + +/obj/item/chems/glass/bucket/update_overlays() + add_overlay(get_handle_overlay()) + . = ..() + +/obj/item/chems/glass/bucket/get_edible_material_amount(mob/eater) + return 0 + +/obj/item/chems/glass/bucket/get_utensil_food_type() + return null + +/obj/item/chems/glass/bucket/attackby(var/obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/mop)) + if(REAGENT_TOTAL_VOLUME(reagents) < 1) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + else if(REAGENTS_FREE_SPACE(used_item.reagents) >= 5) + reagents.trans_to_obj(used_item, 5) + to_chat(user, SPAN_NOTICE("You wet \the [used_item] in \the [src].")) + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + else + to_chat(user, SPAN_WARNING("\The [used_item] is saturated.")) + return TRUE + return ..() + +/obj/item/chems/glass/bucket/get_reagents_overlay(state_prefix) + if(!ATOM_IS_OPEN_CONTAINER(src)) + return null // no overlay while closed! + if(!reagents || (REAGENT_TOTAL_VOLUME(reagents) / REAGENT_MAXIMUM_VOLUME(reagents)) < 0.8) + return null // must be at least 80% full to show + return ..() + +/obj/item/chems/glass/bucket/wood + desc = "It's a wooden bucket. How rustic." + icon = 'icons/obj/items/wooden_bucket.dmi' + chem_volume = 200 + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_COLOR // name is already modified + /// The material used for the chain, belts, and rivets holding the wood together, typically iron or steel. + /// Mostly used for visual and matter reasons. Initially a typepath, set to a decl on init. + var/decl/material/rivet_material = /decl/material/solid/metal/iron + +/obj/item/chems/glass/bucket/wood/Initialize(ml, material_key) + rivet_material = GET_DECL(rivet_material) + . = ..() + +// Until a future point where the bucket recipe is redone, the rivet material will be entirely visual. +// At some point, there could be a create_matter override to handle it, but that would require +// the crafting recipe to be changed. +// Also, pre-emptively, the entry needs to be inserted into the matter list BEFORE the parent call. +// You'll thank me later when you don't make the same mistake a second time. + +/obj/item/chems/glass/bucket/wood/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing) + overlay.add_overlay(overlay_image(icon, "[overlay.icon_state]_overlay", rivet_material.get_reagent_color(), RESET_COLOR | RESET_ALPHA)) + return ..() + +/obj/item/chems/glass/bucket/wood/update_overlays() + . = ..() + add_overlay(overlay_image(icon, "[icon_state]_overlay", rivet_material.get_reagent_color(), RESET_COLOR | RESET_ALPHA)) + +/obj/item/chems/glass/bucket/wood/get_handle_overlay() + return overlay_image(icon, "[icon_state]-handle", rivet_material.get_reagent_color(), RESET_COLOR | RESET_ALPHA) + +/obj/item/chems/glass/bucket/wood/can_lid() + return FALSE // todo: add lid sprite? diff --git a/code/modules/reagents/reagent_containers/condiments/__condiment.dm b/code/modules/reagents/reagent_containers/condiments/__condiment.dm new file mode 100644 index 000000000000..bd3c1e2666d8 --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/__condiment.dm @@ -0,0 +1,93 @@ +/obj/item/chems/condiment + name = "condiment container" + desc = "Just your average condiment container." + icon = 'icons/obj/food/condiments/empty.dmi' + icon_state = ICON_STATE_WORLD + atom_flags = ATOM_FLAG_OPEN_CONTAINER + possible_transfer_amounts = @"[1,5,10]" + center_of_mass = @'{"x":16,"y":6}' + randpixel = 6 + chem_volume = 50 + var/condiment_key + var/morphic_container = TRUE + var/use_condiment_name = TRUE + var/initial_condiment_type + +/obj/item/chems/condiment/populate_reagents() + . = ..() + var/decl/condiment_appearance/condiment = GET_DECL(initial_condiment_type) + if(condiment?.condiment_type) + add_to_reagents(condiment.condiment_type, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/condiment/attackby(var/obj/item/used_item, var/mob/user) + if(IS_PEN(used_item)) + var/tmp_label = sanitize_safe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) + if(tmp_label == label_text) + return TRUE + if(length(tmp_label) > 10) + to_chat(user, SPAN_NOTICE("The label can be at most 10 characters long.")) + return TRUE + if(length(tmp_label)) + to_chat(user, SPAN_NOTICE("You set the label to \"[tmp_label]\".")) + label_text = tmp_label + else + to_chat(user, SPAN_NOTICE("You remove the label.")) + label_text = null + update_name() + update_container_desc() + update_icon() + return TRUE + return ..() + +/obj/item/chems/condiment/afterattack(var/obj/target, var/mob/user, var/proximity) + if(!proximity) + return ..() + if(standard_dispenser_refill(user, target)) + return TRUE + if(standard_pour_into(user, target)) + return TRUE + return ..() + +/obj/item/chems/condiment/proc/get_current_condiment_appearance() + if(!morphic_container) + return GET_DECL(initial_condiment_type) + var/reagent_volumes = REAGENT_VOLUMES(reagents) + switch(LAZYLEN(reagent_volumes)) + if(0) + return GET_DECL(/decl/condiment_appearance/empty) + if(1) + return get_condiment_appearance(reagents?.get_primary_reagent_type(), condiment_key) + else + return GET_DECL(/decl/condiment_appearance/mixed) + +/obj/item/chems/condiment/on_reagent_change() + if((. = ..())) + update_center_of_mass() + +/obj/item/chems/condiment/proc/update_center_of_mass() + var/decl/condiment_appearance/condiment = get_current_condiment_appearance() + center_of_mass = condiment?.condiment_center_of_mass || initial(center_of_mass) + +/obj/item/chems/condiment/update_name() + var/decl/condiment_appearance/condiment = get_current_condiment_appearance() + if(use_condiment_name && condiment?.condiment_name) + SetName(condiment.condiment_name) + else + ..() + if(label_text) + SetName(addtext(name," ([label_text])")) + +/obj/item/chems/condiment/update_container_desc() + var/decl/condiment_appearance/condiment = get_current_condiment_appearance() + desc = condiment?.condiment_desc || get_base_desc() + +/obj/item/chems/condiment/on_update_icon() + . = ..() + var/new_icon + var/decl/condiment_appearance/condiment = get_current_condiment_appearance() + if(condiment?.condiment_icon) + new_icon = condiment.condiment_icon + else + new_icon = initial(icon) + if(new_icon) + set_icon(new_icon) diff --git a/code/modules/reagents/reagent_containers/condiments/__condiment_appearance.dm b/code/modules/reagents/reagent_containers/condiments/__condiment_appearance.dm new file mode 100644 index 000000000000..c3c95a7d9b27 --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/__condiment_appearance.dm @@ -0,0 +1,35 @@ +var/global/list/_primary_reagent_to_condiment_appearance +/proc/get_condiment_appearance(primary_reagent, condiment_key) + if(!global._primary_reagent_to_condiment_appearance) + global._primary_reagent_to_condiment_appearance = list() + for(var/decl/condiment_appearance/condiment in decls_repository.get_decls_of_type_unassociated(/decl/condiment_appearance)) + if(condiment.condiment_type) + if(condiment.condiment_key) + global._primary_reagent_to_condiment_appearance["[condiment.condiment_type]-[condiment.condiment_key]"] = condiment + else + global._primary_reagent_to_condiment_appearance[condiment.condiment_type] = condiment + if(condiment_key) + return global._primary_reagent_to_condiment_appearance["[primary_reagent]-[condiment_key]"] + return global._primary_reagent_to_condiment_appearance[primary_reagent] + +/decl/condiment_appearance + abstract_type = /decl/condiment_appearance + var/condiment_type + var/condiment_key + var/condiment_name + var/condiment_desc + var/condiment_icon + var/condiment_center_of_mass + +/decl/condiment_appearance/validate() + . = ..() + if(condiment_type) + if(!ispath(condiment_type, /decl/material)) + . += "invalid condiment type" + else + for(var/decl/condiment_appearance/other_condiment in decls_repository.get_decls_of_type_unassociated(/decl/condiment_appearance)) + if(other_condiment != src && other_condiment.condiment_type == condiment_type && condiment_key == other_condiment.condiment_key) + . += "non-unique condiment '[condiment_type]' overlaps with [other_condiment.type]" + + if(!isicon(condiment_icon)) + . += "invalid or null icon" diff --git a/code/modules/reagents/reagent_containers/condiments/_condiment_large.dm b/code/modules/reagents/reagent_containers/condiments/_condiment_large.dm new file mode 100644 index 000000000000..0a260a574d22 --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/_condiment_large.dm @@ -0,0 +1,6 @@ +/obj/item/chems/condiment/large + name = "large condiment container" + possible_transfer_amounts = @"[1,5,10,20,50,100]" + chem_volume = 500 + w_class = ITEM_SIZE_LARGE + use_condiment_name = FALSE diff --git a/code/modules/reagents/reagent_containers/condiments/_condiment_small.dm b/code/modules/reagents/reagent_containers/condiments/_condiment_small.dm new file mode 100644 index 000000000000..34c521eec487 --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/_condiment_small.dm @@ -0,0 +1,7 @@ + +/obj/item/chems/condiment/small + name = "small condiment container" + possible_transfer_amounts = @"[1,2,5,8,10,20]" + amount_per_transfer_from_this = 1 + chem_volume = 20 + use_condiment_name = FALSE diff --git a/code/modules/reagents/reagent_containers/condiments/condiment_appearance.dm b/code/modules/reagents/reagent_containers/condiments/condiment_appearance.dm new file mode 100644 index 000000000000..6192a77f4d6a --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/condiment_appearance.dm @@ -0,0 +1,132 @@ +/decl/condiment_appearance/empty + condiment_name = "empty condiment bottle" + condiment_icon = 'icons/obj/food/condiments/empty.dmi' + condiment_desc = "An empty condiment bottle" + +/decl/condiment_appearance/mixed + condiment_name = "condiment bottle" + condiment_desc = "A condiment bottle half-filled with a mix of condiments." + condiment_icon = 'icons/obj/food/condiments/generic.dmi' + +/decl/condiment_appearance/ketchup + condiment_type = /decl/material/liquid/nutriment/ketchup + condiment_name = "ketchup" + condiment_desc = "Tomato, but more liquid, stronger, better." + condiment_icon = 'icons/obj/food/condiments/ketchup.dmi' + +/decl/condiment_appearance/barbecue + condiment_type = /decl/material/liquid/nutriment/barbecue + condiment_name = "barbecue sauce" + condiment_desc = "Barbecue sauce, it's labeled 'sweet and spicy'" + condiment_icon = 'icons/obj/food/condiments/barbecue.dmi' + +/decl/condiment_appearance/capsaicin + condiment_type = /decl/material/liquid/capsaicin + condiment_name = "hotsauce" + condiment_desc = "You can almost TASTE the stomach ulcers now!" + condiment_icon = 'icons/obj/food/condiments/hotsauce.dmi' + +/decl/condiment_appearance/enzyme + condiment_type = /decl/material/liquid/enzyme + condiment_name = "universal enzyme" + condiment_desc = "Used in cooking various dishes." + condiment_icon = 'icons/obj/food/condiments/enzyme.dmi' + +/decl/condiment_appearance/soysauce + condiment_type = /decl/material/liquid/nutriment/soysauce + condiment_name = "soy sauce" + condiment_desc = "A dark, salty, savoury flavoring." + condiment_icon = 'icons/obj/food/condiments/soysauce.dmi' + condiment_key = "small" + +/decl/condiment_appearance/coldsauce + condiment_type = /decl/material/liquid/frostoil + condiment_name = "cold sauce" + condiment_desc = "Leaves the tongue numb in its passage." + condiment_icon = 'icons/obj/food/condiments/coldsauce.dmi' + +/decl/condiment_appearance/salt + condiment_type = /decl/material/solid/sodiumchloride + condiment_name = "salt shaker" + condiment_desc = "Salt. From space oceans, presumably." + condiment_icon = 'icons/obj/food/condiments/saltshaker.dmi' + condiment_key = "small" + condiment_center_of_mass = @'{"x":16,"y":9}' + +/decl/condiment_appearance/salt/sack + condiment_name = "bag of salt" + condiment_desc = "A nonsensically large bag of salt. Carefully refined from countless shifts." + condiment_icon = 'icons/obj/food/condiments/saltsack.dmi' + condiment_key = "large" + +/decl/condiment_appearance/rice + condiment_type = /decl/material/liquid/nutriment/rice + condiment_name = "bag of rice" + condiment_desc = "A large bag of dry rice. Where'd you leave the rice cooker?" + condiment_icon = 'icons/obj/food/condiments/rice.dmi' + condiment_key = "large" + +/decl/condiment_appearance/peppermill + condiment_type = /decl/material/solid/blackpepper + condiment_name = "pepper mill" + condiment_desc = "Often used to flavor food or make people sneeze." + condiment_icon = 'icons/obj/food/condiments/peppermill.dmi' + condiment_key = "small" + condiment_center_of_mass = @'{"x":16,"y":8}' + +/decl/condiment_appearance/cornoil + condiment_type = /decl/material/liquid/oil/plant/corn + condiment_name = "corn oil" + condiment_desc = "A delicious oil used in cooking. Made from corn." + condiment_icon = 'icons/obj/food/condiments/cornoil.dmi' + +/decl/condiment_appearance/sugar + condiment_type = /decl/material/liquid/nutriment/sugar + condiment_name = "sugar" + condiment_desc = "Cavities in a bottle." + condiment_icon = 'icons/obj/food/condiments/sugar.dmi' + condiment_center_of_mass = @'{"x":17,"y":9}' + condiment_key = "small" + +/decl/condiment_appearance/sugar/bag + condiment_name = "sugar bag" + condiment_icon = 'icons/obj/food/condiments/sugarbag.dmi' + condiment_desc = "Cavities in a bag." + condiment_key = null + +/decl/condiment_appearance/mayonnaise + condiment_type = /decl/material/liquid/nutriment/mayo + condiment_name = "mayonnaise" + condiment_desc = "Mayonnaise, used for centuries to make things edible." + condiment_icon = 'icons/obj/food/condiments/mayo.dmi' + +/decl/condiment_appearance/vinegar + condiment_type = /decl/material/liquid/nutriment/vinegar + condiment_name = "vinegar" + condiment_desc = "As acidic as it gets in the kitchen." + condiment_icon = 'icons/obj/food/condiments/vinegar.dmi' + +/decl/condiment_appearance/yeast + condiment_type = /decl/material/liquid/nutriment/yeast + condiment_name = "yeast" + condiment_desc = "A dried form of mold used to ferment food or assist in making bread rise during baking." + condiment_icon = 'icons/obj/food/condiments/yeast.dmi' + +/decl/condiment_appearance/flour + condiment_type = /decl/material/liquid/nutriment/flour + condiment_name = "flour sack" + condiment_desc = "A big bag of flour. Good for baking!" + condiment_icon = 'icons/obj/food/condiments/flour.dmi' + +/decl/condiment_appearance/mint + condiment_type = /decl/material/liquid/drink/syrup/mint + condiment_name = "mint essential oil" + condiment_desc = "A small bottle of the essential oil of some kind of mint plant." + condiment_icon = 'icons/obj/food/condiments/coldsauce.dmi' + condiment_key = "small" + +/decl/condiment_appearance/cinnamon + condiment_type = /decl/material/solid/cinnamon + condiment_name = "cinnamon" + condiment_desc = "A small bottle of ground cinnamon." + condiment_icon = 'icons/obj/food/condiments/generic.dmi' diff --git a/code/modules/reagents/reagent_containers/condiments/condiments.dm b/code/modules/reagents/reagent_containers/condiments/condiments.dm new file mode 100644 index 000000000000..c58d74df45ca --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/condiments.dm @@ -0,0 +1,23 @@ +#define MAPPED_CONDIMENT_TYPE(ID, TYPE) \ +/obj/item/chems/condiment/##ID { \ + initial_condiment_type = TYPE; \ + morphic_container = FALSE; \ + name = TYPE::condiment_name; \ + desc = TYPE::condiment_desc; \ + icon = TYPE::condiment_icon; \ +} + +MAPPED_CONDIMENT_TYPE(enzyme, /decl/condiment_appearance/enzyme) +MAPPED_CONDIMENT_TYPE(barbecue, /decl/condiment_appearance/ketchup) +MAPPED_CONDIMENT_TYPE(sugar, /decl/condiment_appearance/sugar/bag) +MAPPED_CONDIMENT_TYPE(ketchup, /decl/condiment_appearance/ketchup) +MAPPED_CONDIMENT_TYPE(cornoil, /decl/condiment_appearance/cornoil) +MAPPED_CONDIMENT_TYPE(vinegar, /decl/condiment_appearance/vinegar) +MAPPED_CONDIMENT_TYPE(mayo, /decl/condiment_appearance/mayonnaise) +MAPPED_CONDIMENT_TYPE(frostoil, /decl/condiment_appearance/coldsauce) +MAPPED_CONDIMENT_TYPE(capsaicin, /decl/condiment_appearance/capsaicin) +MAPPED_CONDIMENT_TYPE(yeast, /decl/condiment_appearance/yeast) +MAPPED_CONDIMENT_TYPE(flour, /decl/condiment_appearance/flour) +MAPPED_CONDIMENT_TYPE(cinnamon, /decl/condiment_appearance/cinnamon) + +#undef MAPPED_CONDIMENT_TYPE \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/condiments/condiments_large.dm b/code/modules/reagents/reagent_containers/condiments/condiments_large.dm new file mode 100644 index 000000000000..63a0e1b7502a --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/condiments_large.dm @@ -0,0 +1,17 @@ +/obj/item/chems/condiment/large + randpixel = 10 + condiment_key = "large" + +/obj/item/chems/condiment/large/salt + morphic_container = FALSE + initial_condiment_type = /decl/condiment_appearance/salt/sack + name = /decl/condiment_appearance/salt/sack::condiment_name + desc = /decl/condiment_appearance/salt/sack::condiment_desc + icon = /decl/condiment_appearance/salt/sack::condiment_icon + +/obj/item/chems/condiment/large/rice + morphic_container = FALSE + initial_condiment_type = /decl/condiment_appearance/rice + name = /decl/condiment_appearance/rice::condiment_name + desc = /decl/condiment_appearance/rice::condiment_desc + icon = /decl/condiment_appearance/rice::condiment_icon diff --git a/code/modules/reagents/reagent_containers/condiments/condiments_small.dm b/code/modules/reagents/reagent_containers/condiments/condiments_small.dm new file mode 100644 index 000000000000..198f7ca470ba --- /dev/null +++ b/code/modules/reagents/reagent_containers/condiments/condiments_small.dm @@ -0,0 +1,23 @@ +/obj/item/chems/condiment/small + name = "small condiment container" + possible_transfer_amounts = @"[1,2,5,8,10,20]" + amount_per_transfer_from_this = 1 + chem_volume = 20 + condiment_key = "small" + +#define MAPPED_CONDIMENT_TYPE(ID, TYPE) \ +/obj/item/chems/condiment/small/##ID { \ + initial_condiment_type = TYPE; \ + morphic_container = FALSE; \ + name = TYPE::condiment_name; \ + desc = TYPE::condiment_desc; \ + icon = TYPE::condiment_icon; \ +} + +MAPPED_CONDIMENT_TYPE(saltshaker, /decl/condiment_appearance/salt) +MAPPED_CONDIMENT_TYPE(peppermill, /decl/condiment_appearance/peppermill) +MAPPED_CONDIMENT_TYPE(sugar, /decl/condiment_appearance/sugar) +MAPPED_CONDIMENT_TYPE(mint, /decl/condiment_appearance/mint) +MAPPED_CONDIMENT_TYPE(soysauce, /decl/condiment_appearance/soysauce) + +#undef MAPPED_CONDIMENT_TYPE diff --git a/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm b/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm index 26174b267231..e82429d67e9d 100644 --- a/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm @@ -1,169 +1,191 @@ -/var/const/DRINK_FIZZ = "fizz" -/var/const/DRINK_ICE = "ice" -/var/const/DRINK_VAPOR = "vapor" -/var/const/DRINK_ICON_DEFAULT = "" -/var/const/DRINK_ICON_NOISY = "noise" +var/global/const/DRINK_FIZZ = "fizz" +var/global/const/DRINK_ICE = "ice" +var/global/const/DRINK_VAPOR = "vapor" +var/global/const/DRINK_ICON_DEFAULT = "" +var/global/const/DRINK_ICON_NOISY = "noise" + +/obj/item/chems/drinks/glass2 -/obj/item/chems/food/drinks/glass2 name = "glass" // Name when empty - base_name = "glass" desc = "A generic drinking glass." // Description when empty icon = 'icons/obj/drink_glasses/square.dmi' icon_state = null base_icon = "square" // Base icon name filling_states = @"[20,40,60,80,100]" - volume = 30 + chem_volume = 30 material = /decl/material/solid/glass + drop_sound = 'sound/foley/bottledrop1.ogg' + pickup_sound = 'sound/foley/bottlepickup1.ogg' + center_of_mass =@'{"x":16,"y":9}' + amount_per_transfer_from_this = 5 + possible_transfer_amounts = @"[5,10,15,30]" + atom_flags = ATOM_FLAG_OPEN_CONTAINER + presentation_flags = PRESENTATION_FLAG_NAME | PRESENTATION_FLAG_DESC + w_class = ITEM_SIZE_SMALL + /// The icon state prefix used for overlay/addon sprites. If unset, defaults to base_icon. + var/overlay_base_icon = null var/list/extras = list() // List of extras. Two extras maximum - var/rim_pos // Position of the rim for fruit slices. list(y, x_left, x_right) var/filling_overlayed //if filling should go on top of the icon (e.g. opaque cups) - var/global/list/filling_icons_cache = list() - - center_of_mass =@"{'x':16,'y':9}" - - amount_per_transfer_from_this = 5 - possible_transfer_amounts = @"[5,10,15,30]" - atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_SHOW_REAGENT_NAME - temperature_coefficient = 4 - + var/static/list/filling_icons_cache = list() var/custom_name var/custom_desc -/obj/item/chems/food/drinks/glass2/examine(mob/M) - . = ..() - - for(var/I in extras) - if(istype(I, /obj/item/glass_extra)) - to_chat(M, "There is \a [I] in \the [src].") - else if(istype(I, /obj/item/chems/food/snacks/fruit_slice)) - to_chat(M, "There is \a [I] on the rim.") - else - to_chat(M, "There is \a [I] somewhere on the glass. Somehow.") +/obj/item/chems/drinks/glass2/update_name() + if(custom_name) + SetName(custom_name) + return + return ..() - if(has_ice()) - to_chat(M, "There is some ice floating in the drink.") - - if(has_fizz()) - to_chat(M, "It is fizzing slightly.") +// Reverse the matter effect of the hollow flag, keep the force effect. +// Glasses are so tiny that their effective matter is ten times lower than forks/knives due to OBJ_FLAG_HOLLOW. +/obj/item/chems/drinks/glass2/get_matter_amount_modifier() + . = ..() + if(obj_flags & OBJ_FLAG_HOLLOW) + . /= HOLLOW_OBJECT_MATTER_MULTIPLIER -/obj/item/chems/food/drinks/glass2/proc/has_ice() - if(LAZYLEN(reagents.reagent_volumes)) +/obj/item/chems/drinks/glass2/proc/has_ice() + var/reagent_volumes = REAGENT_VOLUMES(reagents) + if(LAZYLEN(reagent_volumes)) var/decl/material/R = reagents.get_primary_reagent_decl() if(!((R.type == /decl/material/solid/ice) || ("ice" in R.glass_special))) // if it's not a cup of ice, and it's not already supposed to have ice in, see if the bartender's put ice in it - if(reagents.has_reagent(/decl/material/solid/ice, reagents.total_volume / 10)) // 10% ice by volume + if(reagents.has_reagent(/decl/material/solid/ice, REAGENT_TOTAL_VOLUME(reagents) / 10)) // 10% ice by volume return 1 return 0 -/obj/item/chems/food/drinks/glass2/proc/has_fizz() - if(LAZYLEN(reagents.reagent_volumes)) - var/decl/material/R = reagents.get_primary_reagent_decl() - if(("fizz" in R.glass_special)) +/obj/item/chems/drinks/glass2/proc/has_fizz() + var/reagent_volumes = REAGENT_VOLUMES(reagents) + if(LAZYLEN(reagent_volumes)) + var/decl/material/primary_reagent = reagents.get_primary_reagent_decl() + if(("fizz" in primary_reagent.glass_special)) return 1 var/totalfizzy = 0 - for(var/rtype in reagents.reagent_volumes) - var/decl/material/re = decls_repository.get_decl(rtype) - if("fizz" in re.glass_special) - totalfizzy += REAGENT_VOLUME(reagents, rtype) - if(totalfizzy >= reagents.total_volume / 5) // 20% fizzy by volume + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if("fizz" in reagent.glass_special) + totalfizzy += REAGENT_VOLUME(reagents, reagent) + if(totalfizzy >= REAGENT_TOTAL_VOLUME(reagents) / 5) // 20% fizzy by volume return 1 return 0 -/obj/item/chems/food/drinks/glass2/proc/has_vapor() - if(LAZYLEN(reagents.reagent_volumes) > 0) +/obj/item/chems/drinks/glass2/proc/has_vapor() + var/reagent_volumes = REAGENT_VOLUMES(reagents) + if(LAZYLEN(reagent_volumes) > 0) if(temperature > T0C + 40) return 1 - var/decl/material/R = reagents.get_primary_reagent_decl() - if(!("vapor" in R.glass_special)) + var/decl/material/primary_reagent = reagents.get_primary_reagent_decl() + if(!("vapor" in primary_reagent.glass_special)) var/totalvape = 0 - for(var/rtype in reagents.reagent_volumes) - var/decl/material/re = decls_repository.get_decl(rtype) - if("vapor" in re.glass_special) - totalvape += REAGENT_VOLUME(reagents, type) - if(totalvape >= volume * 0.6) // 60% vapor by container volume + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if("vapor" in reagent.glass_special) + totalvape += REAGENT_VOLUME(reagents, reagent) + if(totalvape >= REAGENT_MAXIMUM_VOLUME(reagents) * 0.6) // 60% vapor by container volume return 1 return 0 -/obj/item/chems/food/drinks/glass2/Initialize() +/obj/item/chems/drinks/glass2/Initialize() . = ..() if(!icon_state) icon_state = base_icon + if(!overlay_base_icon) + overlay_base_icon = base_icon -/obj/item/chems/food/drinks/glass2/get_base_name() - . = base_name - -/obj/item/chems/food/drinks/glass2/on_reagent_change() - temperature_coefficient = 4 / max(1, reagents.total_volume) - ..() - var/decl/material/R = reagents.get_primary_reagent_decl() - desc = R?.glass_desc || custom_desc || initial(desc) +/obj/item/chems/drinks/glass2/get_base_desc() + . = custom_desc || ..() -/obj/item/chems/food/drinks/glass2/proc/can_add_extra(obj/item/glass_extra/GE) - if(!("[base_icon]_[GE.glass_addition]left" in icon_states(icon))) - return 0 - if(!("[base_icon]_[GE.glass_addition]right" in icon_states(icon))) - return 0 +/obj/item/chems/drinks/glass2/proc/can_add_extra(obj/item/glass_extra/GE) + if(!("[overlay_base_icon]_[GE.glass_addition]left" in icon_states(icon))) + return FALSE + if(!("[overlay_base_icon]_[GE.glass_addition]right" in icon_states(icon))) + return FALSE + return TRUE - return 1 +/obj/item/chems/drinks/glass2/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(!istype(user)) + return + var/list/extra_text + for(var/extra in extras) + if(istype(extra, /obj/item/glass_extra)) + var/obj/item/glass_extra/GE = extra + LAZYADD(extra_text, GE.glass_desc) + else if(istype(extra, /obj/item/food/processed_grown/slice)) + LAZYADD(extra_text, "There is \a [extra] on the rim.") + else + . += "There is \a [extra] somewhere on the glass. Somehow." + if(length(extra_text)) + . += SPAN_NOTICE(jointext(extra_text," ")) + if(has_ice()) + . += "There is some ice floating in the drink." + if(has_fizz()) + . += "It is fizzing slightly." -/obj/item/chems/food/drinks/glass2/proc/get_filling_overlay(amount, overlay) +/obj/item/chems/drinks/glass2/proc/get_filling_overlay(amount, overlay) var/image/I = new() - if(!filling_icons_cache["[base_icon][amount][overlay]"]) - var/icon/base = new/icon(icon, "[base_icon][amount]") + if(!filling_icons_cache["[overlay_base_icon][amount][overlay]"]) + var/icon/base = new/icon(icon, "[overlay_base_icon][amount]") if(overlay) var/icon/extra = new/icon('icons/obj/drink_glasses/extras.dmi', overlay) base.Blend(extra, ICON_MULTIPLY) - filling_icons_cache["[base_icon][amount][overlay]"] = image(base) - I.appearance = filling_icons_cache["[base_icon][amount][overlay]"] + filling_icons_cache["[overlay_base_icon][amount][overlay]"] = image(base) + I.appearance = filling_icons_cache["[overlay_base_icon][amount][overlay]"] return I -/obj/item/chems/food/drinks/glass2/on_update_icon() +/obj/item/chems/drinks/glass2/on_update_icon() + . = ..() underlays.Cut() - overlays.Cut() + icon_state = base_icon - if (LAZYLEN(reagents?.reagent_volumes) > 0) + var/reagent_volumes = REAGENT_VOLUMES(reagents) + if (LAZYLEN(reagent_volumes) > 0) var/decl/material/R = reagents.get_primary_reagent_decl() + if(R.cocktail_ingredient) + for(var/decl/cocktail/cocktail in SSmaterials.get_cocktails_by_primary_ingredient(R.type)) + if(cocktail.matches(src) && cocktail.has_sprite(src) && cocktail.can_use_sprite(src)) + icon_state = null // hide the main sprite + add_overlay(image(cocktail.glass_icon, cocktail.glass_icon_state)) + return // don't do the rest--todo semiprocedural cocktail sprites with fizz/ice/vapor + var/list/under_liquid = list() var/list/over_liquid = list() var/amnt = get_filling_state() if(has_ice()) - over_liquid |= image(icon, src, "[base_icon][amnt]_ice") + over_liquid |= image(icon, src, "[overlay_base_icon][amnt]_ice") if(has_fizz()) over_liquid |= get_filling_overlay(amnt, "fizz") if(has_vapor()) - over_liquid |= image(icon, src, "[base_icon]_vapor") + over_liquid |= image(icon, src, "[overlay_base_icon]_vapor") for(var/S in R.glass_special) - if("[base_icon]_[S]" in icon_states(icon)) - under_liquid |= image(icon, src, "[base_icon]_[S]") - else if("[base_icon][amnt]_[S]" in icon_states(icon)) - over_liquid |= image(icon, src, "[base_icon][amnt]_[S]") + if("[overlay_base_icon]_[S]" in icon_states(icon)) + under_liquid |= image(icon, src, "[overlay_base_icon]_[S]") + else if("[overlay_base_icon][amnt]_[S]" in icon_states(icon)) + over_liquid |= image(icon, src, "[overlay_base_icon][amnt]_[S]") underlays += under_liquid var/image/filling = get_filling_overlay(amnt, R.glass_icon) filling.color = reagents.get_color() if(filling_overlayed) - overlays += filling + add_overlay(filling) else underlays += filling - overlays += over_liquid + add_overlay(over_liquid) var/side = "left" for(var/item in extras) if(istype(item, /obj/item/glass_extra)) var/obj/item/glass_extra/GE = item - var/image/I = image(icon, src, "[base_icon]_[GE.glass_addition][side]") + var/image/I = image(icon, src, "[overlay_base_icon]_[GE.glass_addition][side]") I.color = GE.color underlays += I - else if(rim_pos && istype(item, /obj/item/chems/food/snacks/fruit_slice)) + else if(rim_pos && istype(item, /obj/item/food/processed_grown/slice)) var/obj/FS = item var/image/I = image(FS) @@ -179,22 +201,31 @@ else continue side = "right" -/obj/item/chems/food/drinks/glass2/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/kitchen/utensil/spoon)) - if(user.a_intent == I_HURT) +/obj/item/chems/drinks/glass2/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/utensil/spoon)) + if(user.check_intent(I_FLAG_HARM)) user.visible_message("[user] bashes \the [src] with a spoon, shattering it to pieces! What a rube.") playsound(src, "shatter", 30, 1) if(reagents) user.visible_message("The contents of \the [src] splash all over [user]!") - reagents.splash(user, reagents.total_volume) + reagents.splash(user, REAGENT_TOTAL_VOLUME(reagents)) qdel(src) - return + return TRUE user.visible_message("[user] gently strikes \the [src] with a spoon, calling the room to attention.") playsound(src, "sound/items/wineglass.ogg", 65, 1) - else return ..() + return TRUE + else + return ..() -/obj/item/chems/food/drinks/glass2/ProcessAtomTemperature() +/obj/item/chems/drinks/glass2/ProcessAtomTemperature() var/old_temp = temperature . = ..() if(old_temp != temperature) - update_icon() \ No newline at end of file + update_icon() + +/obj/item/chems/drinks/glass2/physically_destroyed(var/skip_qdel) + reagents.splash(loc, REAGENT_TOTAL_VOLUME(reagents)) + if(istype(material)) + playsound(src, "shatter", 30, 1) + material.place_shards(get_turf(src), w_class) + return ..() \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/drinkingglass/extras.dm b/code/modules/reagents/reagent_containers/drinkingglass/extras.dm index b36c650eee5a..bcf3d0d9d9c5 100644 --- a/code/modules/reagents/reagent_containers/drinkingglass/extras.dm +++ b/code/modules/reagents/reagent_containers/drinkingglass/extras.dm @@ -1,58 +1,59 @@ -/obj/item/chems/food/drinks/glass2/attackby(obj/item/I, mob/user) +/obj/item/chems/drinks/glass2/attackby(obj/item/used_item, mob/user) if(extras.len >= 2) return ..() // max 2 extras, one on each side of the drink - if(istype(I, /obj/item/glass_extra)) - var/obj/item/glass_extra/GE = I - if(can_add_extra(GE)) - extras += GE - if(!user.unEquip(GE, src)) - return - to_chat(user, "You add \the [GE] to \the [src].") - update_icon() - else + if(istype(used_item, /obj/item/glass_extra)) + var/obj/item/glass_extra/GE = used_item + if(!can_add_extra(GE)) to_chat(user, "There's no space to put \the [GE] on \the [src]!") - else if(istype(I, /obj/item/chems/food/snacks/fruit_slice)) + return TRUE + extras += GE + if(!user.try_unequip(GE, src)) + return TRUE + to_chat(user, "You add \the [GE] to \the [src].") + update_icon() + return TRUE + else if(istype(used_item, /obj/item/food/processed_grown/slice)) if(!rim_pos) - to_chat(user, "There's no space to put \the [I] on \the [src]!") - return - var/obj/item/chems/food/snacks/fruit_slice/FS = I + to_chat(user, "There's no space to put \the [used_item] on \the [src]!") + return TRUE + var/obj/item/food/processed_grown/slice/FS = used_item extras += FS - if(!user.unEquip(FS, src)) - return - FS.pixel_x = 0 // Reset its pixel offsets so the icons work! - FS.pixel_y = 0 + if(!user.try_unequip(FS, src)) + return TRUE + reset_offsets(0) // Reset its pixel offsets so the icons work! to_chat(user, "You add \the [FS] to \the [src].") update_icon() + return TRUE else return ..() -/obj/item/chems/food/drinks/glass2/attack_hand(mob/user) - if(src != user.get_inactive_hand()) +/obj/item/chems/drinks/glass2/attack_hand(mob/user) + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) return ..() if(!extras.len) - to_chat(user, "There's nothing on the glass to remove!") - return + to_chat(user, SPAN_WARNING("There's nothing on the glass to remove!")) + return TRUE var/choice = input(user, "What would you like to remove from the glass?") as null|anything in extras if(!choice || !(choice in extras)) - return - - if(user.put_in_active_hand(choice)) - to_chat(user, "You remove \the [choice] from \the [src].") - extras -= choice - else - to_chat(user, "Something went wrong, please try again.") + return TRUE + user.put_in_active_hand(choice) + to_chat(user, SPAN_NOTICE("You remove \the [choice] from \the [src].")) + extras -= choice update_icon() + return TRUE /obj/item/glass_extra + abstract_type = /obj/item/glass_extra name = "generic glass addition" desc = "This goes on a glass." var/glass_addition var/glass_desc w_class = ITEM_SIZE_TINY icon = 'icons/obj/drink_glasses/extras.dmi' + material = /decl/material/solid/organic/plastic /obj/item/glass_extra/stick name = "stick" @@ -61,7 +62,7 @@ glass_desc = "There is a stick in the glass." icon_state = "stick" color = COLOR_BLACK - + /obj/item/glass_extra/stick/Initialize() . = ..() if(prob(50)) diff --git a/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm b/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm index d79460e5d3b8..dd072542c416 100644 --- a/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm +++ b/code/modules/reagents/reagent_containers/drinkingglass/glass_boxes.dm @@ -1,82 +1,99 @@ -/obj/item/storage/box/mixedglasses +//////////////////////////////////////////////////////////////////// +// Box of Mixed Glasses +//////////////////////////////////////////////////////////////////// +/obj/item/box/mixedglasses name = "glassware box" desc = "A box of assorted glassware" - can_hold = list(/obj/item/chems/food/drinks/glass2) - - startswith = list( - /obj/item/chems/food/drinks/glass2/square, - /obj/item/chems/food/drinks/glass2/rocks, - /obj/item/chems/food/drinks/glass2/shake, - /obj/item/chems/food/drinks/glass2/cocktail, - /obj/item/chems/food/drinks/glass2/shot, - /obj/item/chems/food/drinks/glass2/pint, - /obj/item/chems/food/drinks/glass2/mug, - /obj/item/chems/food/drinks/glass2/wine + storage = /datum/storage/box/glasses + +/obj/item/box/mixedglasses/WillContain() + return list( + /obj/item/chems/drinks/glass2/square, + /obj/item/chems/drinks/glass2/rocks, + /obj/item/chems/drinks/glass2/shake, + /obj/item/chems/drinks/glass2/cocktail, + /obj/item/chems/drinks/glass2/shot, + /obj/item/chems/drinks/glass2/pint, + /obj/item/chems/drinks/glass2/mug, + /obj/item/chems/drinks/glass2/wine ) -/obj/item/storage/box/mixedglasses/Initialize() +/obj/item/box/mixedglasses/Initialize(ml, material_key) . = ..() - make_exact_fit() + if(length(contents) && storage) + storage.make_exact_fit() + +//////////////////////////////////////////////////////////////////// +// Box of Glasses +//////////////////////////////////////////////////////////////////// +/obj/item/box/glasses + name = "box of glasses" + abstract_type = /obj/item/box/glasses + storage = /datum/storage/box/glasses + +/obj/item/box/glasses/Initialize(ml, material_key) + . = ..() + //Name the box accordingly + setup_name() + if(length(contents) && storage) + storage.make_exact_fit() -/obj/item/storage/box/glasses - name = "box of glasses" - var/glass_type = /obj/item/chems/food/drinks/glass2 - can_hold = list(/obj/item/chems/food/drinks/glass2) +///Looks at the contents of the box and name if after the first thing it finds inside +/obj/item/box/glasses/proc/setup_name() + if(length(contents)) + var/atom/movable/O = contents[1] + SetName("box of [text_make_plural(O.name)]") -/obj/item/storage/box/glasses/Initialize() - . = ..() +/obj/item/box/glasses/square/WillContain() + return list(/obj/item/chems/drinks/glass2/square = max(1, storage?.storage_slots)) - for(var/i = 1 to 7) - new glass_type(src) - make_exact_fit() +/obj/item/box/glasses/rocks/WillContain() + return list(/obj/item/chems/drinks/glass2/rocks = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/square - name = "box of half-pint glasses" - glass_type = /obj/item/chems/food/drinks/glass2/square +/obj/item/box/glasses/shake/WillContain() + return list(/obj/item/chems/drinks/glass2/shake = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/rocks - name = "box of rocks glasses" - glass_type = /obj/item/chems/food/drinks/glass2/rocks +/obj/item/box/glasses/cocktail/WillContain() + return list(/obj/item/chems/drinks/glass2/cocktail = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/shake - name = "box of milkshake glasses" - glass_type = /obj/item/chems/food/drinks/glass2/shake +/obj/item/box/glasses/shot/WillContain() + return list(/obj/item/chems/drinks/glass2/shot = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/cocktail - name = "box of cocktail glasses" - glass_type = /obj/item/chems/food/drinks/glass2/cocktail +/obj/item/box/glasses/pint/WillContain() + return list(/obj/item/chems/drinks/glass2/pint = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/shot - name = "box of shot glasses" - glass_type = /obj/item/chems/food/drinks/glass2/shot +/obj/item/box/glasses/mug/WillContain() + return list(/obj/item/chems/drinks/glass2/mug = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/pint - name = "box of pint glasses" - glass_type = /obj/item/chems/food/drinks/glass2/pint +/obj/item/box/glasses/coffeecup/WillContain() + return list(/obj/item/chems/drinks/glass2/coffeecup = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/mug - name = "box of glass mugs" - glass_type = /obj/item/chems/food/drinks/glass2/mug +/obj/item/box/glasses/teacup/WillContain() + return list(/obj/item/chems/drinks/glass2/coffeecup/teacup = max(1, storage?.storage_slots)) -/obj/item/storage/box/glasses/wine - name = "box of wine glasses" - glass_type = /obj/item/chems/food/drinks/glass2/wine +/obj/item/box/glasses/wine/WillContain() + return list(/obj/item/chems/drinks/glass2/wine = max(1, storage?.storage_slots)) -/obj/item/storage/box/glass_extras +//////////////////////////////////////////////////////////////////// +// Extras +//////////////////////////////////////////////////////////////////// +/obj/item/box/glass_extras name = "box of cocktail garnishings" - var/extra_type = /obj/item/glass_extra - can_hold = list(/obj/item/glass_extra) - storage_slots = 14 + storage = /datum/storage/box/glass_extras -/obj/item/storage/box/glass_extras/Initialize() - for(var/i = 1 to 14) - new extra_type(src) +/obj/item/box/glass_extras/Initialize(ml, material_key) . = ..() + setup_name() + if(length(contents) && storage) + storage.make_exact_fit() + +/obj/item/box/glass_extras/proc/setup_name() + if(length(contents)) + var/atom/movable/O = contents[1] + SetName("box of [text_make_plural(O.name)]") -/obj/item/storage/box/glass_extras/straws - name = "box of straws" - extra_type = /obj/item/glass_extra/straw +/obj/item/box/glass_extras/straws/WillContain() + return list(/obj/item/glass_extra/straw = max(1, storage?.storage_slots)) -/obj/item/storage/box/glass_extras/sticks - name = "box of drink sticks" - extra_type = /obj/item/glass_extra/stick +/obj/item/box/glass_extras/sticks/WillContain() + return list(/obj/item/glass_extra/stick = max(1, storage?.storage_slots)) diff --git a/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm b/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm index fc58d59d3818..2691cea39a9c 100644 --- a/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm +++ b/code/modules/reagents/reagent_containers/drinkingglass/glass_types.dm @@ -1,228 +1,217 @@ -/obj/item/chems/food/drinks/glass2/square +/obj/item/chems/drinks/glass2/square name = "half-pint glass" - base_name = "glass" base_icon = "square" + icon_state = "square" icon = 'icons/obj/drink_glasses/square.dmi' desc = "Your standard drinking glass." filling_states = @"[20,40,60,80,100]" - volume = 30 + chem_volume = 30 possible_transfer_amounts = @"[5,10,15,30]" - rim_pos = @"{'y':23,'x_left':13,'x_right':20}" + rim_pos = @'{"y":23,"x_left":13,"x_right":20}' -/obj/item/chems/food/drinks/glass2/rocks +/obj/item/chems/drinks/glass2/rocks name = "rocks glass" desc = "A robust tumbler with a thick, weighted bottom." - base_name = "glass" base_icon = "rocks" + icon_state = "rocks" icon = 'icons/obj/drink_glasses/rocks.dmi' filling_states = @"[25,50,75,100]" - volume = 20 + chem_volume = 20 possible_transfer_amounts = @"[5,10,20]" - rim_pos = @"{'y':21,'x_left':10,'x_right':23}" + rim_pos = @'{"y":21,"x_left":10,"x_right":23}' -/obj/item/chems/food/drinks/glass2/shake +/obj/item/chems/drinks/glass2/shake name = "sherry glass" desc = "Stemware with an untapered conical bowl." - base_name = "glass" base_icon = "shake" + icon_state = "shake" icon = 'icons/obj/drink_glasses/shake.dmi' filling_states = @"[25,50,75,100]" - volume = 30 + chem_volume = 30 possible_transfer_amounts = @"[5,10,15,30]" - rim_pos = @"{'y':25,'x_left':13,'x_right':21}" + rim_pos = @'{"y":25,"x_left":13,"x_right":21}' -/obj/item/chems/food/drinks/glass2/cocktail +/obj/item/chems/drinks/glass2/cocktail name = "cocktail glass" desc = "Fragile stemware with a stout conical bowl. Don't spill." - base_name = "glass" base_icon = "cocktail" + icon_state = "cocktail" icon = 'icons/obj/drink_glasses/cocktail.dmi' filling_states = @"[33,66,100]" - volume = 15 + chem_volume = 15 possible_transfer_amounts = @"[5,10,15]" - rim_pos = @"{'y':22,'x_left':13,'x_right':21}" + rim_pos = @'{"y":22,"x_left":13,"x_right":21}' -/obj/item/chems/food/drinks/glass2/shot +/obj/item/chems/drinks/glass2/shot name = "shot glass" desc = "A small glass, designed so that its contents can be consumed in one gulp." - base_name = "shot" base_icon = "shot" + icon_state = "shot" icon = 'icons/obj/drink_glasses/shot.dmi' filling_states = @"[33,66,100]" - volume = 5 - material = /decl/material/solid/glass + chem_volume = 5 possible_transfer_amounts = @"[1,2,5]" - rim_pos = @"{'y':17,'x_left':13,'x_right':21}" + rim_pos = @'{"y":17,"x_left":13,"x_right":21}' -/obj/item/chems/food/drinks/glass2/pint +/obj/item/chems/drinks/glass2/pint name = "pint glass" - base_name = "pint" base_icon = "pint" + icon_state = "pint" icon = 'icons/obj/drink_glasses/pint.dmi' filling_states = @"[16,33,50,66,83,100]" - volume = 60 - material = /decl/material/solid/glass + chem_volume = 60 possible_transfer_amounts = @"[5,10,15,30,60]" - rim_pos = @"{'y':25,'x_left':12,'x_right':21}" + rim_pos = @'{"y":25,"x_left":12,"x_right":21}' -/obj/item/chems/food/drinks/glass2/mug +/obj/item/chems/drinks/glass2/mug name = "glass mug" desc = "A heavy mug with thick walls." - base_name = "mug" base_icon = "mug" + icon_state = "mug" icon = 'icons/obj/drink_glasses/mug.dmi' filling_states = @"[25,50,75,100]" - volume = 40 + chem_volume = 40 possible_transfer_amounts = @"[5,10,20,40]" - rim_pos = @"{'y':22,'x_left':12,'x_right':20}" + rim_pos = @'{"y":22,"x_left":12,"x_right":20}' -/obj/item/chems/food/drinks/glass2/wine +/obj/item/chems/drinks/glass2/wine name = "wine glass" desc = "A piece of elegant stemware." - base_name = "glass" base_icon = "wine" + icon_state = "wine" icon = 'icons/obj/drink_glasses/wine.dmi' filling_states = @"[20,40,60,80,100]" - volume = 25 + chem_volume = 25 possible_transfer_amounts = @"[5,10,15,25]" - rim_pos = @"{'y':25,'x_left':12,'x_right':21}" + rim_pos = @'{"y":25,"x_left":12,"x_right":21}' -/obj/item/chems/food/drinks/glass2/flute +/obj/item/chems/drinks/glass2/flute name = "flute glass" desc = "A piece of very elegant stemware." - base_name = "glass" base_icon = "flute" + icon_state = "flute" icon = 'icons/obj/drink_glasses/flute.dmi' - volume = 25 + chem_volume = 25 filling_states = @"[20,40,60,80,100]" possible_transfer_amounts = @"[5,10,15,25]" - rim_pos = @"{'y':24,'x_left':13,'x_right':19}" + rim_pos = @'{"y":24,"x_left":13,"x_right":19}' -/obj/item/chems/food/drinks/glass2/carafe +/obj/item/chems/drinks/glass2/carafe name = "pitcher" desc = "A handled glass pitcher." - base_name = "pitcher" base_icon = "carafe" + icon_state = "carafe" icon = 'icons/obj/drink_glasses/carafe.dmi' filling_states = @"[10,20,30,40,50,60,70,80,90,100]" - volume = 120 - material = /decl/material/solid/glass + chem_volume = 120 possible_transfer_amounts = @"[5,10,15,30,60,120]" - rim_pos = @"{'y':26,'x_left':12,'x_right':21}" - center_of_mass = @"{'x':16,'y':7}" + rim_pos = @'{"y":26,"x_left":12,"x_right":21}' + center_of_mass = @'{"x":16,"y":7}' -/obj/item/chems/food/drinks/glass2/coffeecup +/obj/item/chems/drinks/glass2/coffeecup name = "coffee cup" desc = "A plain white coffee cup." icon = 'icons/obj/drink_glasses/coffecup.dmi' icon_state = "coffeecup" item_state = "coffee" - volume = 30 - center_of_mass = @"{'x':15,'y':13}" + chem_volume = 30 + center_of_mass = @'{"x":15,"y":13}' filling_states = @"[40,80,100]" base_name = "cup" base_icon = "coffeecup" - rim_pos = @"{'y':22,'x_left':12,'x_right':20}" + overlay_base_icon = "coffeecup" // so that subtypes work properly + rim_pos = @'{"y":22,"x_left":12,"x_right":20}' filling_overlayed = TRUE + material = /decl/material/solid/stone/ceramic -/obj/item/chems/food/drinks/glass2/coffeecup/foundation - name = "\improper Foundation coffee cup" - desc = "A white coffee cup with the Cuchulain Foundation logo stencilled onto it." - icon_state = "coffeecup_foundation" - base_name = "\improper Foundation cup" - -/obj/item/chems/food/drinks/glass2/coffeecup/black +/obj/item/chems/drinks/glass2/coffeecup/black name = "black coffee cup" desc = "A sleek black coffee cup." + base_icon = "coffeecup_black" icon_state = "coffeecup_black" base_name = "black cup" -/obj/item/chems/food/drinks/glass2/coffeecup/green +/obj/item/chems/drinks/glass2/coffeecup/green name = "green coffee cup" desc = "A pale green and pink coffee cup." + base_icon = "coffeecup_green" icon_state = "coffeecup_green" base_name = "green cup" -/obj/item/chems/food/drinks/glass2/coffeecup/heart +/obj/item/chems/drinks/glass2/coffeecup/heart name = "heart coffee cup" desc = "A white coffee cup, it prominently features a red heart." + base_icon = "coffeecup_heart" icon_state = "coffeecup_heart" base_name = "heart cup" -/obj/item/chems/food/drinks/glass2/coffeecup/one +/obj/item/chems/drinks/glass2/coffeecup/one name = "#1 coffee cup" desc = "A white coffee cup, prominently featuring a #1." + base_icon = "coffeecup_one" icon_state = "coffeecup_one" base_name = "#1 cup" -/obj/item/chems/food/drinks/glass2/coffeecup/punitelli +/obj/item/chems/drinks/glass2/coffeecup/punitelli name = "#1 monkey coffee cup" desc = "A white coffee cup, prominently featuring a \"#1 monkey\" decal." + base_icon = "coffeecup_punitelli" icon_state = "coffeecup_punitelli" base_name = "#1 monkey cup" -/obj/item/chems/food/drinks/glass2/coffeecup/punitelli/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/banana, 30) - update_icon() +/obj/item/chems/drinks/glass2/coffeecup/punitelli/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/banana, REAGENT_MAXIMUM_VOLUME(reagents)) -/obj/item/chems/food/drinks/glass2/coffeecup/rainbow +/obj/item/chems/drinks/glass2/coffeecup/rainbow name = "rainbow coffee cup" desc = "A rainbow coffee cup. The colors are almost as blinding as a welder." + base_icon = "coffeecup_rainbow" icon_state = "coffeecup_rainbow" base_name = "rainbow cup" -/obj/item/chems/food/drinks/glass2/coffeecup/metal - name = "metal coffee cup" +/obj/item/chems/drinks/glass2/coffeecup/metal desc = "A metal coffee cup. You're not sure which metal." + base_icon = "coffeecup_metal" icon_state = "coffeecup_metal" - base_name = "metal cup" - atom_flags = ATOM_FLAG_OPEN_CONTAINER - obj_flags = OBJ_FLAG_CONDUCTIBLE + material = /decl/material/solid/metal/stainlesssteel -/obj/item/chems/food/drinks/glass2/coffeecup/STC - name = "\improper ICCG coffee cup" - desc = "A coffee cup adorned with the flag of the Gilgamesh Colonial Confederation, for when you need some espionage charges to go with your morning coffee." - icon_state = "coffeecup_STC" - base_name = "\improper ICCG cup" - -/obj/item/chems/food/drinks/glass2/coffeecup/pawn +/obj/item/chems/drinks/glass2/coffeecup/pawn name = "pawn coffee cup" desc = "A black coffee cup adorned with the image of a red chess pawn." + base_icon = "coffeecup_pawn" icon_state = "coffeecup_pawn" base_name = "pawn cup" -/obj/item/chems/food/drinks/glass2/coffeecup/britcup - name = "british coffee cup" - desc = "A coffee cup with the British flag emblazoned on it." - icon_state = "coffeecup_brit" - base_name = "british cup" - -/obj/item/chems/food/drinks/glass2/coffeecup/tall +/obj/item/chems/drinks/glass2/coffeecup/tall name = "tall coffee cup" desc = "An unreasonably tall coffee cup, for when you really need to wake up in the morning." icon = 'icons/obj/drink_glasses/coffecup_tall.dmi' icon_state = "coffeecup_tall" - volume = 60 - center_of_mass = @"{'x':15,'y':19}" + chem_volume = 60 + center_of_mass = @'{"x":15,"y":19}' filling_states = @"[50,70,90,100]" base_name = "tall cup" base_icon = "coffeecup_tall" + overlay_base_icon = null -/obj/item/chems/food/drinks/glass2/coffeecup/teacup +/obj/item/chems/drinks/glass2/coffeecup/teacup name = "teacup" desc = "A plain white porcelain teacup." icon = 'icons/obj/drink_glasses/teacup.dmi' icon_state = "teacup" item_state = "coffee" - volume = 20 + chem_volume = 20 filling_states = @"[100]" base_name = "teacup" base_icon = "teacup" -/obj/item/chems/food/drinks/glass2/coffeecup/custom/inherit_custom_item_data(var/datum/custom_item/citem) +/obj/item/chems/drinks/glass2/coffeecup/custom/inherit_custom_item_data(var/datum/custom_item/citem) . = ..() if(citem.additional_data["base_name"]) base_name = citem.additional_data["base_name"] || base_name + if(citem.additional_data["base_icon"]) + base_icon = citem.additional_data["base_icon"] || base_icon + if(citem.additional_data["overlay_base_icon"]) + overlay_base_icon = citem.additional_data["overlay_base_icon"] || overlay_base_icon custom_name = citem.item_name - custom_desc = citem.item_desc \ No newline at end of file + custom_desc = citem.item_desc diff --git a/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm b/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm index ccef459b756d..84959a660099 100644 --- a/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm +++ b/code/modules/reagents/reagent_containers/drinkingglass/shaker.dm @@ -1,33 +1,45 @@ -/obj/item/chems/food/drinks/glass2/fitnessflask +/obj/item/chems/drinks/glass2/fitnessflask name = "fitness shaker" base_name = "shaker" desc = "Big enough to contain enough protein to get perfectly swole. Don't mind the bits." icon_state = "fitness-cup_black" base_icon = "fitness-cup" icon = 'icons/obj/drink_glasses/fitness.dmi' - volume = 100 - material = /decl/material/solid/plastic + chem_volume = 100 + material = /decl/material/solid/organic/plastic filling_states = @"[10,20,30,40,50,60,70,80,90,100]" possible_transfer_amounts = @"[5,10,15,25]" rim_pos = null // no fruit slices var/lid_color = "black" -/obj/item/chems/food/drinks/glass2/fitnessflask/Initialize() +/obj/item/chems/drinks/glass2/fitnessflask/Initialize() . = ..() lid_color = pick("black", "red", "blue") update_icon() -/obj/item/chems/food/drinks/glass2/fitnessflask/on_update_icon() +/obj/item/chems/drinks/glass2/fitnessflask/on_update_icon() ..() icon_state = "[base_icon]_[lid_color]" -/obj/item/chems/food/drinks/glass2/fitnessflask/proteinshake +/obj/item/chems/drinks/glass2/fitnessflask/proteinshake name = "protein shake" -/obj/item/chems/food/drinks/glass2/fitnessflask/proteinshake/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/nutriment, 30) - reagents.add_reagent(/decl/material/solid/metal/iron, 10) - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 15) - reagents.add_reagent(/decl/material/liquid/water, 45) +// This exists to let the name auto-set properly. +/decl/cocktail/proteinshake + name = "protein shake" + description = "A revolting slurry of protein and water, fortified with iron." + hidden_from_codex = TRUE + ratios = list( + /decl/material/liquid/nutriment = 2, + /decl/material/solid/organic/meat = 1, + /decl/material/liquid/water = 3, + /decl/material/solid/metal/iron + ) + +/obj/item/chems/drinks/glass2/fitnessflask/proteinshake/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment, 30) + add_to_reagents(/decl/material/solid/metal/iron, 10) + add_to_reagents(/decl/material/solid/organic/meat, 15) + add_to_reagents(/decl/material/liquid/water, 45) + diff --git a/code/modules/reagents/reagent_containers/drinks.dm b/code/modules/reagents/reagent_containers/drinks.dm new file mode 100644 index 000000000000..852d1ee3c400 --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinks.dm @@ -0,0 +1,302 @@ +//////////////////////////////////////////////////////////////////////////////// +/// Drinks. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/chems/drinks + name = "drink" + desc = "Yummy!" + icon = 'icons/obj/drinks.dmi' + icon_state = null + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_HOLLOW + possible_transfer_amounts = null + amount_per_transfer_from_this = 5 + randpixel = 6 + chem_volume = 50 + abstract_type = /obj/item/chems/drinks + watertight = FALSE // /drinks uses the open container flag for this + + var/filling_states // List of percentages full that have icons + var/base_icon = null // Base icon name for fill states + +/obj/item/chems/drinks/Initialize() + base_name ||= name + . = ..() + +/obj/item/chems/drinks/dragged_onto(var/mob/user) + return attack_self(user) + +/obj/item/chems/drinks/attack_self(mob/user) + if(!ATOM_IS_OPEN_CONTAINER(src)) + open(user) + else if(is_edible(user)) + use_on_mob(user, user) + else + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return TRUE + +/obj/item/chems/drinks/proc/open(mob/user) + if(!ATOM_IS_OPEN_CONTAINER(src)) + playsound(loc,'sound/effects/canopen.ogg', rand(10,50), 1) + to_chat(user, SPAN_NOTICE("You open \the [src] with an audible pop!")) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + return TRUE + return FALSE + +/obj/item/chems/drinks/proc/do_open_check(mob/user) + if(!ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_NOTICE("You need to open \the [src]!")) + return FALSE + return TRUE + +/obj/item/chems/drinks/afterattack(obj/target, mob/user, proximity) + if(!proximity) + return + if(standard_dispenser_refill(user, target)) + return + if(standard_pour_into(user, target)) + return + return ..() + +/obj/item/chems/drinks/standard_dispenser_refill(mob/user, obj/structure/reagent_dispensers/target, skip_container_check = FALSE) + return do_open_check(user) && ..() + +/obj/item/chems/drinks/standard_pour_into(var/mob/user, var/atom/target) + return do_open_check(user) && ..() + +/obj/item/chems/drinks/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1) + return + var/total_volume = REAGENT_TOTAL_VOLUME(reagents) + var/max_volume = REAGENT_MAXIMUM_VOLUME(reagents) + if(total_volume <= 0) + . += SPAN_NOTICE("\The [src] is empty!") + else if (total_volume <= max_volume * 0.25) + . += SPAN_NOTICE("\The [src] is almost empty!") + else if (total_volume <= max_volume * 0.66) + . += SPAN_NOTICE("\The [src] is half full!") + else if (total_volume <= max_volume * 0.90) + . += SPAN_NOTICE("\The [src] is almost full!") + else + . += SPAN_NOTICE("\The [src] is full!") + +/obj/item/chems/drinks/proc/get_filling_state() + var/percent = round((REAGENT_TOTAL_VOLUME(reagents) / REAGENT_MAXIMUM_VOLUME(reagents)) * 100) + for(var/k in cached_json_decode(filling_states)) + if(percent <= k) + return k + +/obj/item/chems/drinks/on_update_icon() + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) && filling_states) + add_overlay(overlay_image(icon, "[base_icon][get_filling_state()]", reagents.get_color())) + +//////////////////////////////////////////////////////////////////////////////// +/// Drinks. END +//////////////////////////////////////////////////////////////////////////////// + +/obj/item/chems/drinks/golden_cup + desc = "A golden cup." + name = "golden cup" + icon_state = "golden_cup" + item_state = "" //nope :( + w_class = ITEM_SIZE_HUGE + amount_per_transfer_from_this = 20 + possible_transfer_amounts = null + chem_volume = 150 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + obj_flags = OBJ_FLAG_CONDUCTIBLE + _base_attack_force = 14 + +///////////////////////////////////////////////Drinks +//Notes by Darem: Drinks are simply containers that start preloaded. Unlike condiments, the contents can be ingested directly +// rather then having to add it to something else first. They should only contain liquids. They have a default container size of 50. +// Formatting is the same as food. + +/obj/item/chems/drinks/milk + name = "milk carton" + desc = "It's milk. White and nutritious goodness!" + icon_state = "milk" + item_state = "carton" + center_of_mass = @'{"x":16,"y":9}' + +/obj/item/chems/drinks/milk/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk, REAGENT_MAXIMUM_VOLUME(reagents), data = list(DATA_MILK_DONOR = "cow")) + +/obj/item/chems/drinks/soymilk + name = "soymilk carton" + desc = "It's soy milk. White and nutritious goodness!" + icon_state = "soymilk" + item_state = "carton" + center_of_mass = @'{"x":16,"y":9}' + +/obj/item/chems/drinks/soymilk/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk/soymilk, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/milk/smallcarton + name = "small milk carton" + chem_volume = 30 + icon_state = "mini-milk" + +/obj/item/chems/drinks/milk/smallcarton/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/milk/smallcarton/chocolate + name = "small chocolate milk carton" + desc = "It's milk! This one is in delicious chocolate flavour." + +/obj/item/chems/drinks/milk/smallcarton/chocolate/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk/chocolate, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/coffee + name = "cup of coffee" + desc = "Careful, the beverage you're about to enjoy is extremely hot." + icon_state = "coffee" + center_of_mass = @'{"x":15,"y":10}' + +/obj/item/chems/drinks/coffee/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/coffee, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/ice + name = "cup of ice" + desc = "Careful, cold ice, do not chew." + icon_state = "coffee" + center_of_mass = @'{"x":15,"y":10}' + +/obj/item/chems/drinks/ice/populate_reagents() + add_to_reagents(/decl/material/solid/ice, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/h_chocolate + name = "cup of hot cocoa" + desc = "A tall plastic cup of creamy hot chocolate." + icon_state = "coffee" + item_state = "coffee" + center_of_mass = @'{"x":15,"y":13}' + +/obj/item/chems/drinks/h_chocolate/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/hot_coco, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/dry_ramen + name = "cup ramen" + gender = PLURAL + desc = "Just add 10ml water, self heats! A taste that reminds you of your school years." + icon_state = "ramen" + center_of_mass = @'{"x":16,"y":11}' + +/obj/item/chems/drinks/dry_ramen/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/dry_ramen, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/sillycup + name = "paper cup" + desc = "A paper water cup." + icon_state = "water_cup_e" + possible_transfer_amounts = null + chem_volume = 10 + center_of_mass = @'{"x":16,"y":12}' + +/obj/item/chems/drinks/sillycup/on_update_icon() + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents)) + icon_state = "water_cup" + else + icon_state = "water_cup_e" + + +//////////////////////////pitchers, pots, flasks and cups // +//Note by Darem: This code handles the mixing of drinks. New drinks go in three places: In Chemistry-Reagents.dm (for the drink +// itself), in Chemistry-Recipes.dm (for the reaction that changes the components into the drink), and here (for the drinking glass +// icon states. + +/obj/item/chems/drinks/teapot + name = "china teapot" + desc = "An elegant teapot. It simply oozes class." + icon_state = "teapot" + item_state = "teapot" + amount_per_transfer_from_this = 10 + chem_volume = 120 + center_of_mass = @'{"x":17,"y":7}' + material = /decl/material/solid/stone/ceramic + obj_flags = OBJ_FLAG_HOLLOW | OBJ_FLAG_INSULATED_HANDLE + +/obj/item/chems/drinks/pitcher + name = "insulated pitcher" + desc = "A stainless steel insulated pitcher. Everyone's best friend in the morning." + icon_state = "pitcher" + chem_volume = 120 + amount_per_transfer_from_this = 10 + center_of_mass = @'{"x":16,"y":9}' + filling_states = @"[15,30,50,70,85,100]" + base_icon = "pitcher" + material = /decl/material/solid/metal/stainlesssteel + obj_flags = OBJ_FLAG_HOLLOW | OBJ_FLAG_INSULATED_HANDLE + +/obj/item/chems/drinks/flask + name = "\improper Captain's flask" + desc = "A metal flask belonging to the captain." + icon_state = "flask" + chem_volume = 60 + center_of_mass = @'{"x":17,"y":7}' + +/obj/item/chems/drinks/flask/shiny + name = "shiny flask" + desc = "A shiny metal flask. It appears to have a Greek symbol inscribed on it." + icon_state = "shinyflask" + +/obj/item/chems/drinks/flask/lithium + name = "lithium flask" + desc = "A flask with a Lithium Atom symbol on it." + icon_state = "lithiumflask" + +/obj/item/chems/drinks/flask/detflask + name = "\improper Detective's flask" + desc = "A metal flask with a leather band and golden badge belonging to the detective." + icon_state = "detflask" + chem_volume = 60 + center_of_mass = @'{"x":17,"y":8}' + +/obj/item/chems/drinks/flask/barflask + name = "flask" + desc = "For those who can't be bothered to hang out at the bar to drink." + icon_state = "barflask" + chem_volume = 60 + center_of_mass = @'{"x":17,"y":7}' + +/obj/item/chems/drinks/flask/vacuumflask + name = "vacuum flask" + desc = "Keeping your drinks at the perfect temperature since 1892." + icon_state = "vacuumflask" + chem_volume = 60 + center_of_mass = @'{"x":15,"y":4}' + +//tea and tea accessories +/obj/item/chems/drinks/tea + name = "cup of tea" + desc = "A tall plastic cup full of the concept and ideal of tea." + icon_state = "coffee" + item_state = "coffee" + center_of_mass = @'{"x":16,"y":14}' + filling_states = @"[100]" + base_icon = "cup" + chem_volume = 30 + +/obj/item/chems/drinks/tea/black + name = "cup of black tea" + desc = "A tall plastic cup of hot black tea." + +/obj/item/chems/drinks/tea/black/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/tea/black, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/tea/green + name = "cup of green tea" + desc = "A tall plastic cup of hot green tea." + +/obj/item/chems/drinks/tea/green/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/tea/green, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/tea/chai + name = "cup of chai tea" + desc = "A tall plastic cup of hot chai tea." + +/obj/item/chems/drinks/tea/chai/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/tea/chai, REAGENT_MAXIMUM_VOLUME(reagents)) + diff --git a/code/modules/reagents/reagent_containers/drinks/bottle.dm b/code/modules/reagents/reagent_containers/drinks/bottle.dm new file mode 100644 index 000000000000..e0bd34a5b01e --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinks/bottle.dm @@ -0,0 +1,635 @@ +///////////////////////////////////////////////Alchohol bottles! -Agouri ////////////////////////// +//Functionally identical to regular drinks. The only difference is that the default bottle size is 100. - Darem +//Bottles now weaken and break when smashed on people's heads. - Giacom + +//#TODO: Maybe merge this with /obj/item/glass/bottle? +/obj/item/chems/drinks/bottle + amount_per_transfer_from_this = 10 + chem_volume = 100 + item_state = "broken_beer" //Generic held-item sprite until unique ones are made. + material = /decl/material/solid/glass + drop_sound = 'sound/foley/bottledrop1.ogg' + pickup_sound = 'sound/foley/bottlepickup1.ogg' + abstract_type = /obj/item/chems/drinks/bottle + + var/smash_duration = 5 //Directly relates to the 'weaken' duration. Lowered by armor (i.e. helmets) + var/obj/item/chems/rag/rag = null + var/rag_underlay = "rag" + var/stop_spin_bottle = FALSE //Gotta stop the rotation. + +/obj/item/chems/drinks/bottle/Initialize() + . = ..() + if(material?.type != /decl/material/solid/glass) + verbs -= .verb/spin_bottle + +/obj/item/chems/drinks/bottle/Destroy() + if(!QDELETED(rag)) + rag.dropInto(loc) + rag = null + return ..() + +/obj/item/chems/drinks/bottle/update_container_desc() + return + +//when thrown on impact, bottles smash and spill their contents +/obj/item/chems/drinks/bottle/throw_impact(atom/hit_atom, var/datum/thrownthing/TT) + ..() + if(material?.is_brittle() && TT.thrower && !TT.thrower.check_intent(I_FLAG_HELP)) + if(TT.speed > throw_speed || smash_check(TT.dist_travelled)) //not as reliable as smashing directly + smash(loc, hit_atom) + +/obj/item/chems/drinks/bottle/proc/smash_check(var/distance) + if(!material?.is_brittle()) + return 0 + if(rag?.is_on_fire()) // Molotovs should be somewhat reliable, they're a pain to make. + return TRUE + if(!smash_duration) + return 0 + var/list/chance_table = list(95, 95, 90, 85, 75, 60, 40, 15) //starting from distance 0 + var/idx = max(distance + 1, 1) //since list indices start at 1 + if(idx > chance_table.len) + return 0 + return prob(chance_table[idx]) + +/obj/item/chems/drinks/bottle/proc/smash(var/newloc, atom/against = null) + + // Dump reagents onto the turf. + var/turf/T = against ? get_turf(against) : get_turf(newloc) + if(REAGENT_TOTAL_VOLUME(reagents)) + visible_message(SPAN_DANGER("The contents of \the [src] splash all over \the [against || T]!")) + reagents.splash(against || T, REAGENT_TOTAL_VOLUME(reagents)) + if(!T) + qdel(src) + return + + // Propagate our fire source down to the lowest level we can. + // Ignite any fuel or mobs we have spilled. TODO: generalize to + // flame sources when traversing open space. + if(rag) + rag.dropInto(T) + while(T) + if(!rag || QDELETED(src) || !HasBelow(T.z) || !T.is_open()) + break + rag.forceMove(T) + if(rag.is_on_fire()) + T.hotspot_expose(700, 5) + for(var/mob/living/M in T.contents) + M.ignite_fire() + T = GetBelow(T) + rag = null + + //Creates a shattering noise and replaces the bottle with a broken_bottle + playsound(T, "shatter", 70, 1) + var/obj/item/broken_bottle/B = new(T) + if(prob(33)) + new/obj/item/shard(newloc) // Create a glass shard at the target's location! + B.icon_state = src.icon_state + var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) + I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) + I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) + B.icon = I + B.dropInto(B.loc) + transfer_fingerprints_to(B) + qdel(src) + return B + +/obj/item/chems/drinks/bottle/attackby(obj/item/used_item, mob/user) + if(!rag) + if(istype(used_item, /obj/item/chems/rag)) + insert_rag(used_item, user) + return TRUE + else if(used_item.isflamesource()) + return rag.attackby(used_item, user) + return ..() + +/obj/item/chems/drinks/bottle/attack_self(mob/user) + return rag ? remove_rag(user) : ..() + +/obj/item/chems/drinks/bottle/proc/insert_rag(obj/item/chems/rag/R, mob/user) + if(material?.type != /decl/material/solid/glass) + to_chat(user, SPAN_WARNING("\The [src] isn't made of glass, you can't make a good Molotov with it.")) + return TRUE + + if(rag) + to_chat(user, SPAN_WARNING("\The [src] already has \a [rag] stuffed into it.")) + return TRUE + + if(user.try_unequip(R)) + to_chat(user, SPAN_NOTICE("You stuff [R] into [src].")) + rag = R + rag.forceMove(src) + + // Equalize reagents between the rag and bottle so that + // the rag will probably have something to burn, and the + // bottle contents will be tainted by having the rag dipped + // in it. + if(rag && rag.reagents) + rag.reagents.trans_to(src, REAGENT_TOTAL_VOLUME(rag.reagents)) + if(reagents) + reagents.trans_to(rag, min(REAGENT_TOTAL_VOLUME(reagents), REAGENT_MAXIMUM_VOLUME(rag.reagents))) + rag.update_name() + + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + update_icon() + return TRUE + +/obj/item/chems/drinks/bottle/proc/remove_rag(mob/user) + if(!rag) return + user.put_in_hands(rag) + rag = null + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + +/obj/item/chems/drinks/bottle/open(mob/user) + if(rag) return + ..() + +/obj/item/chems/drinks/bottle/on_update_icon() + . = ..() + underlays.Cut() + if(rag) + var/underlay_image = image(icon='icons/obj/drinks.dmi', icon_state=rag.is_on_fire()? "[rag_underlay]_lit" : rag_underlay) + underlays += underlay_image + set_light(rag.light_range, 0.1, rag.light_color) + else + set_light(0) + +/obj/item/chems/drinks/bottle/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + . = ..() + + if(!user.check_intent(I_FLAG_HARM)) + return + if(!smash_check(1)) + return //won't always break on the first hit + + var/mob/living/human/H = target + if(istype(H) && H.headcheck(hit_zone)) + var/obj/item/organ/affecting = GET_EXTERNAL_ORGAN(H, hit_zone) //headcheck should ensure that affecting is not null + user.visible_message(SPAN_DANGER("\The [user] smashes \the [src] into [H]'s [affecting.name]!")) + // You are going to knock someone out for longer if they are not wearing a helmet. + var/blocked = target.get_blocked_ratio(hit_zone, BRUTE, damage = 10) * 100 + var/weaken_duration = smash_duration + min(0, expend_attack_force(user) - blocked + 10) + if(weaken_duration) + target.apply_effect(min(weaken_duration, 5), WEAKEN, blocked) // Never weaken more than a flash! + else + user.visible_message(SPAN_DANGER("\The [user] smashes \the [src] into [target]!")) + + //The reagents in the bottle splash all over the target, thanks for the idea Nodrak + if(reagents) + user.visible_message(SPAN_NOTICE("The contents of \the [src] splash all over [target]!")) + reagents.splash(target, REAGENT_TOTAL_VOLUME(reagents)) + if(rag?.is_on_fire() && istype(target)) + target.ignite_fire() + + //Finally, smash the bottle. This kills (qdel) the bottle. + var/obj/item/broken_bottle/B = smash(target.loc, target) + user.put_in_active_hand(B) + +/obj/item/chems/drinks/bottle/verb/spin_bottle() + set name = "Spin Bottle" + set category = "Object" + set src in view(1) + + if(!ishuman(usr) || usr.incapacitated()) + return + + if(!stop_spin_bottle) + if(src in usr.get_held_items()) + usr.drop_from_inventory(src) + + if(isturf(loc)) + var/speed = rand(1, 3) + var/loops + var/sleep_not_stacking + switch(speed) //At a low speed, the bottle should not make 10 loops + if(3) + loops = rand(7, 10) + sleep_not_stacking = 40 + if(1 to 2) + loops = rand(10, 15) + sleep_not_stacking = 25 + + stop_spin_bottle = TRUE + SpinAnimation(speed, loops, pick(0, 1)) //SpinAnimation(speed, loops, clockwise, segments) + transform = turn(matrix(), dir2angle(pick(global.alldirs))) + sleep(sleep_not_stacking) //Not stacking + stop_spin_bottle = FALSE + +/obj/item/chems/drinks/bottle/on_picked_up(mob/living/user, atom/old_loc) + animate(src, transform = null, time = 0) //Restore bottle to its original position - animate() is needed to interrupt SpinAnimation() + +//Keeping this here for now, I'll ask if I should keep it here. +/obj/item/broken_bottle + name = "broken bottle" + desc = "A bottle with a sharp broken bottom." + icon = 'icons/obj/drinks.dmi' + icon_state = "broken_bottle" + throw_speed = 3 + throw_range = 5 + item_state = "beer" + attack_verb = list("stabbed", "slashed", "attacked") + sharp = TRUE + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/glass + _base_attack_force = 9 + var/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken") + +/obj/item/broken_bottle/Initialize(ml, material_key) + . = ..() + set_extension(src, /datum/extension/tool, list(TOOL_SCALPEL = TOOL_QUALITY_BAD)) + +/obj/item/broken_bottle/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + . = ..() + if(.) + playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) + +/obj/item/chems/drinks/bottle/gin + name = "Griffeater Gin" + desc = "A bottle of high quality gin, produced in the New London Space Station." + icon_state = "ginbottle" + center_of_mass = @'{"x":16,"y":4}' + +/obj/item/chems/drinks/bottle/gin/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/gin, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/whiskey + name = "Uncle Git's Special Reserve" + desc = "A premium single-malt whiskey, gently matured inside the tunnels of a nuclear shelter. TUNNEL WHISKEY RULES." + icon_state = "whiskeybottle" + center_of_mass = @'{"x":16,"y":3}' + +/obj/item/chems/drinks/bottle/whiskey/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/whiskey, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/agedwhiskey + name = "aged whiskey" + desc = "This rich, smooth, hideously expensive beverage was aged for decades." + icon_state = "whiskeybottle2" + center_of_mass = @'{"x":16,"y":3}' + +/obj/item/chems/drinks/bottle/agedwhiskey/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/aged_whiskey, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/vodka + name = "Tunguska Triple Distilled" + desc = "Aah, vodka. Useful for cocktails... and as bootleg rocket fuel, for those prone to amateur rocketry or trade sanctions." + icon_state = "vodkabottle" + center_of_mass = @'{"x":17,"y":3}' + +/obj/item/chems/drinks/bottle/vodka/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/vodka, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/tequila + name = "Caccavo Guaranteed Quality tequila" + desc = "Made from premium petroleum distillates, pure thalidomide and other fine quality ingredients!" + icon_state = "tequilabottle" + center_of_mass = @'{"x":16,"y":3}' + +/obj/item/chems/drinks/bottle/tequila/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/tequila, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/patron + name = "Wrapp Artiste Patron" + desc = "Silver laced tequila, served in space nightclubs across the galaxy." + icon_state = "patronbottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/patron/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/tequila, REAGENT_MAXIMUM_VOLUME(reagents) - 5) + add_to_reagents(/decl/material/solid/metal/silver, 5) + +/obj/item/chems/drinks/bottle/rum + name = "Captain Pete's Cuban Spiced Rum" + desc = "This isn't just rum, oh no. It's practically GRIFF in a bottle." + icon_state = "rumbottle" + center_of_mass = @'{"x":16,"y":8}' + +/obj/item/chems/drinks/bottle/rum/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/rum, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/holywater + name = "Flask of Holy Water" + desc = "A flask of the chaplain's holy water." + icon_state = "holyflask" + center_of_mass = @'{"x":17,"y":10}' + +/obj/item/chems/drinks/bottle/holywater/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents), list(DATA_WATER_HOLINESS = TRUE)) + +/obj/item/chems/drinks/bottle/vermouth + name = "Goldeneye Vermouth" + desc = "Sweet, sweet dryness~" + icon_state = "vermouthbottle" + center_of_mass = @'{"x":17,"y":3}' + +/obj/item/chems/drinks/bottle/vermouth/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/vermouth, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/kahlua + name = "Robert Robust's Coffee Liqueur" + desc = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936, HONK!" + icon_state = "kahluabottle" + center_of_mass = @'{"x":17,"y":3}' + +/obj/item/chems/drinks/bottle/kahlua/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/coffee, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/goldschlager + name = "College Girl Goldschlager" + desc = "Because they are the only ones who will drink 100 proof cinnamon schnapps." + icon_state = "goldschlagerbottle" + center_of_mass = @'{"x":15,"y":3}' + +/obj/item/chems/drinks/bottle/goldschlager/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/vodka, REAGENT_MAXIMUM_VOLUME(reagents) - 5) + add_to_reagents(/decl/material/solid/metal/gold, 5) + +/obj/item/chems/drinks/bottle/cognac + name = "Chateau De Baton Premium Cognac" + desc = "A sweet and strongly alcoholic drink, made after numerous distillations and years of maturing. You might as well not scream 'SHITCURITY' this time." + icon_state = "cognacbottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/cognac/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/cognac, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/wine + name = "Doublebeard Bearded Special Wine" + desc = "A faint aura of unease and asspainery surrounds the bottle." + icon_state = "winebottle" + center_of_mass = @'{"x":16,"y":4}' + +/obj/item/chems/drinks/bottle/wine/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/wine, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/absinthe + name = "Jailbreaker Verte" + desc = "One sip of this and you just know you're gonna have a good time." + icon_state = "absinthebottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/absinthe/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/absinthe, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/melonliquor + name = "Emeraldine Melon Liquor" + desc = "A bottle of 46 proof Emeraldine Melon Liquor. Sweet and light." + icon_state = "alco-green" //Placeholder. + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/melonliquor/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/melonliquor, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/bluecuracao + name = "Miss Blue Curacao" + desc = "A fruity, exceptionally azure drink. Does not allow the imbiber to use the fifth magic." + icon_state = "alco-blue" //Placeholder. + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/bluecuracao/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/bluecuracao, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/herbal + name = "Liqueur d'Herbe" + desc = "A bottle of the seventh-finest herbal liquor sold under a generic name in the galaxy. The back label has a load of guff about the monks who traditionally made this particular variety." + icon_state = "herbal" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/herbal/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/herbal, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/grenadine + name = "Briar Rose Grenadine Syrup" + desc = "Sweet and tangy, a bar syrup used to add color or flavor to drinks." + icon_state = "grenadinebottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/grenadine/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/grenadine, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/cola + name = "\improper Space Cola" + desc = "Cola... in space." + icon_state = "colabottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/cola/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/cola, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/space_up + name = "\improper Space-Up" + desc = "Tastes like a hull breach in your mouth." + icon_state = "space-up_bottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/space_up/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/lemonade, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/space_mountain_wind + name = "\improper Space Mountain Wind" + desc = "Blows right through you like a space wind." + icon_state = "space_mountain_wind_bottle" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/space_mountain_wind/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/citrussoda, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/pwine + name = "Warlock's Velvet" + desc = "What a delightful packaging for a surely high quality wine! The vintage must be amazing!" + icon_state = "pwinebottle" + center_of_mass = @'{"x":16,"y":4}' + +/obj/item/chems/drinks/bottle/pwine/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/pwine, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/sake + name = "Takeo Sadow's Combined Sake" + desc = "A bottle of the highest-grade sake allowed for import." + icon_state = "sake" + center_of_mass = @'{"x":16,"y":4}' + +/obj/item/chems/drinks/bottle/sake/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/sake, REAGENT_MAXIMUM_VOLUME(reagents)) + + +/obj/item/chems/drinks/bottle/champagne + name = "champagne bottle" + desc = "Sparkling wine made from exquisite grape varieties by the method of secondary fermentation in a bottle. Bubbling." + icon_state = "champagne" + center_of_mass = @'{"x":12,"y":5}' + atom_flags = 0 //starts closed + var/opening + +/obj/item/chems/drinks/bottle/champagne/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/champagne, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/champagne/open(mob/user) + if(ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_NOTICE("\The [src] is already open.")) + return + if(!opening) + user.visible_message(SPAN_NOTICE("\The [user] tries to open \the [src]!")) + opening = TRUE + else + to_chat(user, SPAN_WARNING("You are already trying to open \the [src].")) + return + if(!do_after(user, 3 SECONDS, src)) + if(QDELETED(user) || QDELETED(src)) + return + user.visible_message(SPAN_NOTICE("\The [user] fails to open \the [src].")) + opening = FALSE + return + playsound(src,'sound/effects/champagne_open.ogg', 100, 1) + if(!user.skill_check(SKILL_COOKING, SKILL_BASIC)) + sleep(4) + playsound(src,'sound/effects/champagne_psh.ogg', 100) + user.visible_message(SPAN_WARNING("\The [user] clumsily pops the cork out of \the [src], wasting fizz and getting foam everywhere.")) + new /obj/effect/decal/cleanable/champagne(get_turf(user)) + else + user.visible_message(SPAN_NOTICE("\The [user] pops the cork out of \the [src] with a professional flourish.")) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/chems/drinks/bottle/jagermeister + name = "Kaisermeister Deluxe" + desc = "Jagermeister. This drink just demands a party." + icon_state = "herbal" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/bottle/jagermeister/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/jagermeister, REAGENT_MAXIMUM_VOLUME(reagents)) + +//////////////////////////PREMIUM ALCOHOL /////////////////////// +/obj/item/chems/drinks/bottle/premiumvodka + name = "Quadruple Distilled Vodka" + desc = "Premium distilled vodka made from real, planet-grown potatoes." + icon_state = "premiumvodka" + center_of_mass = @'{"x":17,"y":3}' + +/obj/item/chems/drinks/bottle/premiumvodka/proc/make_random_name() + var/typepick = pick("Absolut","Gold","Quadruple Distilled","Platinum","Premium") + name = "[typepick] Vodka" + +/obj/item/chems/drinks/bottle/premiumvodka/populate_reagents() + make_random_name() + add_to_reagents(/decl/material/liquid/alcohol/vodka/premium, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/premiumwine + name = "Uve De Blanc" + desc = "You feel pretentious just looking at it." + icon_state = "premiumwine" + center_of_mass = @'{"x":16,"y":4}' + var/aged_min = 0 + var/aged_max = 150 + +/obj/item/chems/drinks/bottle/premiumwine/proc/make_random_name() + var/namepick = pick("Calumont","Sciacchemont","Recioto","Torcalota") + return "bottle of Chateau [namepick] De Blanc" + +/obj/item/chems/drinks/bottle/premiumwine/populate_reagents() + var/agedyear = rand(global.using_map.game_year - aged_max, global.using_map.game_year - aged_min) + set_custom_name(make_random_name()) + desc += " This bottle is marked as [agedyear] Vintage." + add_to_reagents(/decl/material/liquid/alcohol/wine/premium, REAGENT_MAXIMUM_VOLUME(reagents)) + +//////////////////////////JUICES AND STUFF /////////////////////// + +/obj/item/chems/drinks/bottle/orangejuice + name = "Orange Juice" + desc = "Full of vitamins and deliciousness!" + icon_state = "orangejuice" + item_state = "carton" + center_of_mass = @'{"x":16,"y":7}' + material = /decl/material/solid/organic/cardboard + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + drop_sound = 'sound/foley/drop1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + +/obj/item/chems/drinks/bottle/orangejuice/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/orange, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/cream + name = "Milk Cream" + desc = "It's cream. Made from milk. What else did you think you'd find in there?" + icon_state = "cream" + item_state = "carton" + center_of_mass = @'{"x":16,"y":8}' + material = /decl/material/solid/organic/cardboard + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + drop_sound = 'sound/foley/drop1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + +/obj/item/chems/drinks/bottle/cream/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk/cream, REAGENT_MAXIMUM_VOLUME(reagents), data = list(DATA_MILK_DONOR = "cow")) + +/obj/item/chems/drinks/bottle/tomatojuice + name = "Tomato Juice" + desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness." + icon_state = "tomatojuice" + item_state = "carton" + center_of_mass = @'{"x":16,"y":8}' + material = /decl/material/solid/organic/cardboard + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + drop_sound = 'sound/foley/drop1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + +/obj/item/chems/drinks/bottle/tomatojuice/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/tomato, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/limejuice + name = "Lime Juice" + desc = "Sweet-sour goodness." + icon_state = "limejuice" + item_state = "carton" + center_of_mass = @'{"x":16,"y":8}' + material = /decl/material/solid/organic/cardboard + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + drop_sound = 'sound/foley/drop1.ogg' + pickup_sound = 'sound/foley/paperpickup2.ogg' + +/obj/item/chems/drinks/bottle/limejuice/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/lime, REAGENT_MAXIMUM_VOLUME(reagents)) + +//Small bottles +/obj/item/chems/drinks/bottle/small + chem_volume = 50 + smash_duration = 1 + atom_flags = 0 //starts closed + rag_underlay = "rag_small" + abstract_type = /obj/item/chems/drinks/bottle/small + +/obj/item/chems/drinks/bottle/small/beer + name = "space beer" + desc = "Contains only water, malt and hops." + icon_state = "beer" + center_of_mass = @'{"x":16,"y":12}' + +/obj/item/chems/drinks/bottle/small/beer/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/beer, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/small/ale + name = "\improper Magm-Ale" + desc = "A true dorf's drink of choice." + icon_state = "alebottle" + item_state = "beer" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/bottle/small/ale/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/ale, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/bottle/small/gingerbeer + name = "Ginger Beer" + desc = "A delicious non-alcoholic beverage enjoyed across Sol space." + icon_state = "gingerbeer" + center_of_mass = @'{"x":16,"y":12}' + +/obj/item/chems/drinks/bottle/small/gingerbeer/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/gingerbeer, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/modules/reagents/reagent_containers/drinks/cans.dm b/code/modules/reagents/reagent_containers/drinks/cans.dm new file mode 100644 index 000000000000..88e6633f2d04 --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinks/cans.dm @@ -0,0 +1,215 @@ +/obj/item/chems/drinks/cans + chem_volume = 40 //just over one and a half cups + amount_per_transfer_from_this = 5 + atom_flags = 0 //starts closed + material = /decl/material/solid/metal/aluminium + abstract_type = /obj/item/chems/drinks/cans + +/obj/item/chems/drinks/cans/update_container_desc() + return + +//DRINKS + +/obj/item/chems/drinks/cans/cola + name = "\improper Space Cola" + desc = "Cola... in space." + icon_state = "cola" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/cola/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/cola, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/waterbottle + name = "bottled water" + desc = "Pure drinking water, imported from the Martian poles." + icon_state = "waterbottle" + center_of_mass = @'{"x":15,"y":8}' + material = /decl/material/solid/organic/plastic + +/obj/item/chems/drinks/cans/waterbottle/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/waterbottle/open(mob/user) + playsound(loc,'sound/effects/bonebreak1.ogg', rand(10,50), 1) + to_chat(user, SPAN_NOTICE("You twist open \the [src], destroying the safety seal!")) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + +/obj/item/chems/drinks/cans/space_mountain_wind + name = "\improper Space Mountain Wind" + desc = "Blows right through you like a space wind." + icon_state = "space_mountain_wind" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/space_mountain_wind/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/citrussoda, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/thirteenloko + name = "\improper Thirteen Loko" + desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsibly." + icon_state = "thirteen_loko" + center_of_mass = @'{"x":16,"y":8}' + +/obj/item/chems/drinks/cans/thirteenloko/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/thirteenloko, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/dr_gibb + name = "\improper Dr. Gibb" + desc = "A delicious mixture of 42 different flavors." + icon_state = "dr_gibb" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/dr_gibb/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/cherrycola, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/starkist + name = "\improper Star-Kist" + desc = "Can you taste a bit of tuna...?" + icon_state = "starkist" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/starkist/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/orangecola, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/space_up + name = "\improper Space-Up" + desc = "Tastes like a hull breach in your mouth." + icon_state = "space-up" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/space_up/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/lemonade, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/lemon_lime + name = "\improper Lemon-Lime" + desc = "You wanted ORANGE. It gave you Lemon Lime." + icon_state = "lemon-lime" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/lemon_lime/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/lemon_lime, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/iced_tea + name = "\improper Vrisk Serket Iced Tea" + desc = "That sweet, refreshing southern earthy flavor. That's where it's from, right? South Earth?" + icon_state = "ice_tea_can" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/iced_tea/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/tea/black, REAGENT_MAXIMUM_VOLUME(reagents) - 5) + add_to_reagents(/decl/material/solid/ice, 5) + +/obj/item/chems/drinks/cans/grape_juice + name = "\improper Grapel Juice" + desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" + icon_state = "purple_can" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/grape_juice/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/grape, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/tonic + name = "\improper T-Borg's Tonic Water" + desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." + icon_state = "tonic" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/tonic/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/tonic, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/sodawater + name = "soda water" + desc = "A can of soda water. Still water's more refreshing cousin." + icon_state = "sodawater" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/sodawater/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/sodawater, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/beastenergy + name = "Beast Energy" + desc = "100% pure energy, and 150% pure liver disease." + icon_state = "beastenergy" + center_of_mass = @'{"x":16,"y":6}' + +/obj/item/chems/drinks/cans/beastenergy/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/beastenergy, REAGENT_MAXIMUM_VOLUME(reagents)) + +//Items exclusive to the BODA machine on deck 4 and wherever else it pops up. First two are a bit jokey. Second two are genuine article. + +/obj/item/chems/drinks/cans/syndicolax + name = "\improper Red Army Twist!" + desc = "A taste of what keeps our glorious nation running! Served as Space Commissariat Stahlin prefers it! Luke warm." + icon_state = "syndi_cola_x" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/syndicolax/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/potato, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/artbru + name = "\improper Arstotzka Bru" + desc = "Just what any bureaucrat needs to get through the day. Keep stamping those papers!" + icon_state = "art_bru" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/artbru/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/turnip, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/syndicola + name = "\improper TerraCola" + desc = "A can of the only soft drink state approved for the benefit of the people. Served at room temperature regardless of ambient temperatures thanks to innovative Terran insulation technology." + icon_state = "syndi_cola" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/syndicola/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents) - 5) + add_to_reagents(/decl/material/solid/metal/iron, 5) + +/obj/item/chems/drinks/glass2/square/boda + name = "boda" + desc = "A tall glass of refreshing Boda!" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/glass2/square/boda/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/sodawater, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/glass2/square/bodaplus + name = "tri kopeiki sirop boda" + desc = "A tall glass of even more refreshing Boda! Now with Sok!" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/glass2/square/bodaplus/populate_reagents() + var/reag = pick(list( + /decl/material/liquid/drink/citrusseltzer, + /decl/material/liquid/drink/juice/grape, + /decl/material/liquid/drink/juice/orange, + /decl/material/liquid/drink/juice/lemon, + /decl/material/liquid/drink/juice/lime, + /decl/material/liquid/drink/juice/apple, + /decl/material/liquid/drink/juice/pear, + /decl/material/liquid/drink/juice/banana, + /decl/material/liquid/drink/juice/berry, + /decl/material/liquid/drink/juice/watermelon)) + var/half_max_vol = REAGENT_MAXIMUM_VOLUME(reagents) / 2 + add_to_reagents(/decl/material/liquid/drink/sodawater, half_max_vol) + add_to_reagents(reag, half_max_vol) + + +//Canned alcohols. + +/obj/item/chems/drinks/cans/speer + name = "\improper Space Beer" + desc = "Now in a can!" + icon_state = "beercan" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/speer/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/beer/good, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/cans/ale + name = "\improper Magm-Ale" + desc = "Now in a can!" + icon_state = "alecan" + center_of_mass = @'{"x":16,"y":10}' + +/obj/item/chems/drinks/cans/ale/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/ale, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/modules/reagents/reagent_containers/drinks/cocktailshaker.dm b/code/modules/reagents/reagent_containers/drinks/cocktailshaker.dm new file mode 100644 index 000000000000..232146b1208c --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinks/cocktailshaker.dm @@ -0,0 +1,35 @@ +/obj/item/chems/drinks/shaker + name = "shaker" + desc = "A three-piece Cobbler-style shaker. Used to mix, cool, and strain drinks." + icon_state = "shaker" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = @"[5,10,15,25,30,60]" //Professional bartender should be able to transfer as much as needed + chem_volume = 120 + center_of_mass = @'{"x":17,"y":10}' + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT + +/obj/item/chems/drinks/shaker/attack_self(mob/user) + if(user.skill_check(SKILL_COOKING, SKILL_PROF)) + user.visible_message("\The [user] shakes \the [src] briskly in one hand, with supreme confidence and competence.", "You shake \the [src] briskly with one hand.") + mix() + return + if(user.skill_check(SKILL_COOKING, SKILL_ADEPT)) + user.visible_message(SPAN_NOTICE("\The [user] shakes \the [src] briskly, with some skill."), SPAN_NOTICE("You shake \the [src] briskly, with some skill.")) + mix() + return + else + user.visible_message(SPAN_NOTICE("\The [user] shakes \the [src] gingerly."), SPAN_NOTICE("You shake \the [src] gingerly.")) + if(prob(15) && (reagents && REAGENT_TOTAL_VOLUME(reagents))) + user.visible_message(SPAN_WARNING("\The [user] spills the contents of \the [src] over themselves!"), SPAN_WARNING("You spill the contents of \the [src] over yourself!")) + reagents.splash(user, REAGENT_TOTAL_VOLUME(reagents)) + else + mix() + +/obj/item/chems/drinks/shaker/proc/mix() + if(reagents && REAGENT_TOTAL_VOLUME(reagents)) + atom_flags &= ~ATOM_FLAG_NO_REACT + HANDLE_REACTIONS(reagents) + addtimer(CALLBACK(src, PROC_REF(stop_react)), SSmaterials.wait) + +/obj/item/chems/drinks/shaker/proc/stop_react() + atom_flags |= ATOM_FLAG_NO_REACT \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/drinks/juicebox.dm b/code/modules/reagents/reagent_containers/drinks/juicebox.dm new file mode 100644 index 000000000000..c18ff521f4b3 --- /dev/null +++ b/code/modules/reagents/reagent_containers/drinks/juicebox.dm @@ -0,0 +1,126 @@ +/obj/item/chems/drinks/juicebox + icon = 'icons/obj/juicebox.dmi' + icon_state = "juicebox_base" + name = "juicebox" + desc = "A small cardboard juicebox. Cheap and flimsy." + chem_volume = 30 + amount_per_transfer_from_this = 5 + atom_flags = 0 + material = /decl/material/solid/organic/cardboard + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + color = "#ff0000" + var/primary_color = "#ff0000" + var/secondary_color = null + var/logo_color = "#ff00000" + var/box_style = "basic" + +/obj/item/chems/drinks/juicebox/proc/set_colors( + primary, + secondary=null, + logo=null, + style="basic" +) + primary_color = primary + secondary_color = secondary + logo_color = logo + box_style = style + update_icon() + +/obj/item/chems/drinks/juicebox/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + var/mutable_appearance/new_appearance = new(src) + new_appearance.appearance_flags = RESET_COLOR + new_appearance.color = primary_color + + if (secondary_color) + var/image/secondary = overlay_image(icon, "juicebox_[box_style]", secondary_color, RESET_COLOR) + new_appearance.overlays += secondary + + var/borderStyle = logo_color == null ? "border" : "border_icon" + var/border = overlay_image(icon, "juicebox_[box_style]_[borderStyle]", null, RESET_COLOR) + new_appearance.overlays += border + + if (logo_color) + var/image/logo = overlay_image(icon, "juicebox_[box_style]_icon", logo_color, RESET_COLOR) + new_appearance.overlays += logo + + var/open = (atom_flags & ATOM_FLAG_OPEN_CONTAINER) ? "open" : "close" + var/image/straw = overlay_image(icon, "juicebox_[open]", null, RESET_COLOR) + new_appearance.overlays += straw + + appearance = new_appearance + +/obj/item/chems/drinks/juicebox/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(atom_flags & ATOM_FLAG_OPEN_CONTAINER) + . += SPAN_NOTICE("It has a straw stuck through the foil seal on top.") + else + . += SPAN_NOTICE("It has a straw stuck to the side and the foil seal is intact.") + +/obj/item/chems/drinks/juicebox/open(mob/user) + playsound(loc,'sound/effects/bonebreak1.ogg', rand(10,50), 1) + to_chat(user, SPAN_NOTICE("You pull off the straw and stab it into \the [src], perforating the foil!")) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + +/obj/item/chems/drinks/juicebox/apple + name = "apple juicebox" + desc = "A small cardboard juicebox with a cartoon apple on it." + +/obj/item/chems/drinks/juicebox/apple/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/apple, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/juicebox/apple/Initialize() + . = ..() + set_colors("#ff0000", "#ffff00", "#ff0000", style="stripe") + +/obj/item/chems/drinks/juicebox/orange + name = "orange juicebox" + desc = "A small cardboard juicebox with a cartoon orange on it." + +/obj/item/chems/drinks/juicebox/orange/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/orange, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/juicebox/orange/Initialize() + . = ..() + set_colors("#ffff00", "#ff0000", "#ffff00", style="stripe") + +/obj/item/chems/drinks/juicebox/grape + name = "grape juicebox" + desc = "A small cardboard juicebox with some cartoon grapes on it." + +/obj/item/chems/drinks/juicebox/grape/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/grape, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/drinks/juicebox/grape/Initialize() + . = ..() + set_colors("#ff00ff", "#00ff00", style="stripe") + +/obj/item/chems/drinks/juicebox/random/Initialize() + . = ..() + var/primary = get_random_colour() + var/secondary = pick(4;get_random_colour(), 1;null) + var/logo = pick(4;get_random_colour(), 1;null) + set_colors(primary, secondary, logo, style=pick(list("basic", "stripe", "corner"))) + +/obj/item/chems/drinks/juicebox/sensible_random + name = "Random Juicebox" + desc = "Juice in a box; who knows what flavor!" + +/obj/item/chems/drinks/juicebox/sensible_random/proc/juice_it() + var/list/drinktypes = decls_repository.get_decl_paths_of_subtype(/decl/material/liquid/drink/juice) + var/decl/material/J = pick(drinktypes) + add_to_reagents(J, 20) + add_to_reagents(pick(drinktypes - J), 5) + return REAGENT_VOLUMES(reagents) + +/obj/item/chems/drinks/juicebox/sensible_random/populate_reagents() + var/list/chosen_reagents = juice_it() + var/decl/material/J = chosen_reagents[1] + var/decl/material/K = chosen_reagents[2] + var/splash = pick("teasing", "splash", "hint", "measure", "nip", "slug", "depth", "dash", "sensation", "surge", "squirt", "spritz", "efflux", "gush", "swell") + desc = "[J.liquid_name]; [J.lore_text] This one comes with \an [splash] of [K.liquid_name] in a neat box." + name = "\improper [J.liquid_name] and [K.liquid_name] juicebox" + set_colors(J.color, K.color, get_random_colour(simple=TRUE), style=pick(list("stripe", "corner"))) diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index de0de3b445ed..3efb2501163f 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -2,7 +2,7 @@ /// Droppers. //////////////////////////////////////////////////////////////////////////////// /obj/item/chems/dropper - name = "Dropper" + name = "dropper" desc = "A small glass tube with a bulbous rubber blister on one end. Used to drop very precise amounts of reagents between vessels." icon = 'icons/obj/items/chem/dropper.dmi' icon_state = "dropper0" @@ -10,27 +10,27 @@ possible_transfer_amounts = @"[1,2,3,4,5]" w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - volume = 5 + chem_volume = 5 item_flags = ITEM_FLAG_NO_BLUDGEON /obj/item/chems/dropper/afterattack(var/obj/target, var/mob/user, var/proximity) - if(!target.reagents || !proximity) + if(!target.reagents || !proximity) return - if(reagents.total_volume) + if(REAGENT_TOTAL_VOLUME(reagents)) if(!REAGENTS_FREE_SPACE(target.reagents)) to_chat(user, SPAN_WARNING("\The [target] is full.")) return - if(!ATOM_IS_OPEN_CONTAINER(target) && !ismob(target) && !istype(target, /obj/item/chems/food) && !istype(target, /obj/item/clothing/mask/smokable/cigarette)) //You can inject humans and food but you cant remove the shit. + if(!ATOM_IS_OPEN_CONTAINER(target) && !ismob(target) && !istype(target, /obj/item/food) && !istype(target, /obj/item/clothing/mask/smokable/cigarette)) //You can inject humans and food but you cant remove the shit. to_chat(user, SPAN_WARNING("You cannot directly fill this object.")) return var/trans = 0 if(ismob(target)) - if(user.a_intent == I_HELP) + if(user.check_intent(I_FLAG_HELP)) return var/time = 20 //2/3rds the time of a syringe @@ -39,36 +39,30 @@ if(!do_mob(user, target, time)) return - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/victim = target - - var/obj/item/safe_thing = null - if(victim.wear_mask) - if (victim.wear_mask.body_parts_covered & EYES) - safe_thing = victim.wear_mask - if(victim.head) - if (victim.head.body_parts_covered & EYES) - safe_thing = victim.head - if(victim.glasses) - if (victim.glasses.body_parts_covered & EYES) - safe_thing = victim.glasses - if(safe_thing) - trans = reagents.splash(safe_thing, amount_per_transfer_from_this, max_spill=30) - user.visible_message(SPAN_DANGER("\The [user] tries to squirt something into [target]'s eyes, but fails!"), SPAN_DANGER("You squirt [trans] unit\s at \the [target]'s eyes, but fail!")) - return + if(isliving(target)) + var/mob/living/victim = target + for(var/slot in global.standard_headgear_slots) + var/obj/item/safe_thing = victim.get_equipped_item(slot) + if(safe_thing && (safe_thing.body_parts_covered & SLOT_EYES)) + trans = reagents.splash(safe_thing, amount_per_transfer_from_this, max_spill=30) + user.visible_message( + SPAN_DANGER("\The [user] tries to squirt something into [target]'s eyes, but fails!"), + SPAN_DANGER("You squirt [trans] unit\s at \the [target]'s eyes, but fail!") + ) + return var/mob/living/M = target - var/contained = REAGENT_LIST(src) + var/contained = REAGENT_LIST(reagents) admin_attack_log(user, M, "Squirted their victim with \a [src] (Reagents: [contained])", "Were squirted with \a [src] (Reagents: [contained])", "used \a [src] (Reagents: [contained]) to squirt at") var/spill_amt = M.incapacitated()? 0 : 30 - trans += reagents.splash(target, reagents.total_volume/2, max_spill = spill_amt) - trans += reagents.trans_to_mob(target, reagents.total_volume/2, CHEM_INJECT) //I guess it gets into the bloodstream through the eyes or something + trans += reagents.splash(M, REAGENT_TOTAL_VOLUME(reagents)/2, max_spill = spill_amt) + trans += reagents.trans_to_mob(M, REAGENT_TOTAL_VOLUME(reagents)/2, CHEM_INJECT) //I guess it gets into the bloodstream through the eyes or something user.visible_message(SPAN_DANGER("[user] squirts something into \the [target]'s eyes!"), SPAN_DANGER("You squirt [trans] unit\s into \the [target]'s eyes!")) return else trans = reagents.splash(target, amount_per_transfer_from_this, max_spill=0) //sprinkling reagents on generic non-mobs. Droppers are very precise - to_chat(user, SPAN_NOTICE("You transfer [trans] units of the solution.")) + to_chat(user, SPAN_NOTICE("You transfer [trans] unit\s of the solution.")) else // Taking from something @@ -76,20 +70,23 @@ to_chat(user, SPAN_NOTICE("You cannot directly remove reagents from [target].")) return - if(!target.reagents || !target.reagents.total_volume) + if(!target.reagents || !REAGENT_TOTAL_VOLUME(target.reagents)) to_chat(user, SPAN_NOTICE("[target] is empty.")) return var/trans = target.reagents.trans_to_obj(src, amount_per_transfer_from_this) - to_chat(user, SPAN_NOTICE("You fill the dropper with [trans] units of the solution.")) + to_chat(user, SPAN_NOTICE("You fill the dropper with [trans] unit\s of the solution.")) +/obj/item/chems/dropper/update_name() + return -/obj/item/chems/dropper/on_reagent_change() - update_icon() +/obj/item/chems/dropper/update_container_desc() + return /obj/item/chems/dropper/on_update_icon() - if(reagents.total_volume) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents)) icon_state = "dropper1" else icon_state = "dropper0" @@ -99,7 +96,7 @@ desc = "A larger dropper. Transfers 10 units." amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[1,2,3,4,5,6,7,8,9,10]" - volume = 10 + chem_volume = 10 //////////////////////////////////////////////////////////////////////////////// /// Droppers. END diff --git a/code/modules/reagents/reagent_containers/food.dm b/code/modules/reagents/reagent_containers/food.dm index a3ecbc545c8c..31266aba67e5 100644 --- a/code/modules/reagents/reagent_containers/food.dm +++ b/code/modules/reagents/reagent_containers/food.dm @@ -1,10 +1,211 @@ -//////////////////////////////////////////////////////////////////////////////// -/// Food. -//////////////////////////////////////////////////////////////////////////////// -/obj/item/chems/food +/////////// +// Foods // +/////////// +//Subtypes of /obj/item/food are food items that people consume whole. The key points are that they are created +// already filled with reagents and are destroyed when empty. Additionally, they make a "munching" noise when eaten. + +//Food can hold a maximum of 50 units Generally speaking, you don't want to go over 40 +// total for the item because you want to leave space for extra condiments. If you want an effect, add a reagent for +// it. Try to stick to existing reagents when possible (so if you want a stronger healing effect, just use regenerative serum). + +/obj/item/food + abstract_type = /obj/item/food + name = "snack" + desc = "Yummy!" + icon = 'icons/obj/food/error.dmi' + icon_state = ICON_STATE_WORLD randpixel = 6 - atom_flags = ATOM_FLAG_OPEN_CONTAINER - possible_transfer_amounts = null - volume = 50 //Sets the default container amount for all food items. + item_flags = null + material = /decl/material/liquid/nutriment + center_of_mass = @'{"x":16,"y":16}' + w_class = ITEM_SIZE_SMALL + abstract_type = /obj/item/food + needs_attack_dexterity = DEXTERITY_NONE + chem_volume = 50 + + /// Indicates the food should give a stress effect on eating. + // This is set to 1 if the food is created by a recipe, -1 if the food is raw. + var/cooked_food = FOOD_PREPARED + var/bitesize = 1 + var/bitecount = 0 + var/slice_path + var/slice_num + var/dry = FALSE + var/nutriment_amt = 0 + var/nutriment_type = /decl/material/liquid/nutriment // Used to determine which base nutriment type is spawned for this item. + // List of flavours and flavour strengths. + // The flavour strength text is determined by the ratio of flavour strengths in the snack. + var/list/nutriment_desc + /// Either a path to a sound file, a get_sfx sound string, or a list of any combination of those. + var/list/eat_sound = 'sound/items/eatfood.ogg' var/filling_color = "#ffffff" //Used by sandwiches. - var/trash = null \ No newline at end of file + var/trash + var/obj/item/plate/plate + /// A type used when cloning this food item for utensils. + var/_utensil_food_type + /// A set of utensil flags determining which utensil interactions are valid with this food. + var/utensil_flags = UTENSIL_FLAG_SCOOP | UTENSIL_FLAG_COLLECT + +/obj/item/food/Initialize(ml, material_key, skip_plate = FALSE) + . = ..() + if(cooked_food == FOOD_RAW) + name = "raw [name]" + + if(skip_plate) + plate = null + else if(ispath(plate)) + plate = new plate(src) + else if(!istype(plate)) + plate = null + + if(isnull(_utensil_food_type)) + _utensil_food_type = type + if(slice_path && slice_num) + utensil_flags |= UTENSIL_FLAG_SLICE + +// Dummy type used solely for soup bowls/soup spoons. +/obj/item/food/lump + name = "lump" + +/obj/item/food/lump/on_reagent_change() + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents)) + SetName(reagents.get_primary_reagent_name()) + filling_color = reagents.get_color() + else + SetName(initial(name)) + filling_color = COLOR_WHITE + color = filling_color + +/obj/item/food/on_reagent_change() + if((. = ..())) + update_icon() + +/obj/item/food/can_be_injected_by(var/atom/injector) + return TRUE + +// Does not rely on ATOM_IS_OPEN_CONTAINER because we want to be able to pour in but not out. +/obj/item/food/can_be_poured_into(atom/source) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) + +/obj/item/food/attack_self(mob/user) + if(is_edible(user) && handle_eaten_by_mob(user, user) != EATEN_INVALID) + return TRUE + return ..() + +/obj/item/food/dragged_onto(var/mob/user) + return attack_self(user) + +/obj/item/food/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1) + return + if(backyard_grilling_rawness > 0 && backyard_grilling_rawness != initial(backyard_grilling_rawness)) + . += "\The [src] is [get_backyard_grilling_text()]." + if(plate) + . += SPAN_NOTICE("\The [src] has been arranged on \a [plate].") + if (bitecount==0) + return + else if (bitecount==1) + . += SPAN_NOTICE("\The [src] was bitten by someone!") + else if (bitecount<=3) + . += SPAN_NOTICE("\The [src] was bitten [bitecount] time\s!") + else + . += SPAN_NOTICE("\The [src] was bitten multiple times!") + +/obj/item/food/proc/is_sliceable() + return (slice_num && slice_path && slice_num > 0) + +/obj/item/food/proc/drop_plate(var/drop_loc) + if(istype(plate)) + plate.dropInto(drop_loc || loc) + plate.make_dirty(src) + plate = null + +/obj/item/food/physically_destroyed() + drop_plate() + return ..() + +/obj/item/food/Destroy() + QDEL_NULL(plate) + trash = null + if(length(contents)) + for(var/atom/movable/something in contents) + something.dropInto(loc) + . = ..() + +/obj/item/food/proc/update_food_appearance_from(var/obj/item/donor, var/food_color, var/copy_donor_appearance = TRUE) + filling_color = food_color + if(copy_donor_appearance) + appearance = donor + color = food_color + if(istype(donor, /obj/item/holder)) + var/matrix/M = matrix() + M.Turn(90) + M.Translate(1,-6) + transform = M + update_icon() + +/obj/item/food/on_update_icon() + underlays.Cut() + . = ..() + //Since other things that don't have filling override this, slap it into its own proc to avoid the overhead of scanning through the icon file + apply_filling_overlay() //#TODO: Maybe generalise food item icons. + // If we have a plate, add it to our icon. + if(plate) + var/image/I = new + I.appearance = plate + I.layer = FLOAT_LAYER + I.plane = FLOAT_PLANE + I.pixel_x = 0 + I.pixel_y = 0 + I.pixel_z = 0 + I.pixel_w = 0 + I.appearance_flags |= RESET_TRANSFORM|RESET_COLOR + underlays += list(I) + +/obj/item/food/proc/apply_filling_overlay() + if(check_state_in_icon("[icon_state]_filling", icon)) + add_overlay(overlay_image(icon, "[icon_state]_filling", filling_color)) + +//Since we automatically create some reagents types for the nutriments, make sure we call this proc when overriding it +/obj/item/food/populate_reagents() + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(!nutriment_amt || !nutriment_type) + return + // Ensure our taste data is in the expected format. + if(nutriment_desc) + if(!islist(nutriment_desc)) + nutriment_desc = list(nutriment_desc) + for(var/taste in nutriment_desc) + if(nutriment_desc[taste] <= 0) + nutriment_desc[taste] = 1 + add_to_reagents(nutriment_type, nutriment_amt, get_nutriment_data()) + +/obj/item/food/proc/get_nutriment_data() + if(nutriment_desc) + LAZYSET(., DATA_TASTE, nutriment_desc) + if(allergen_flags) + LAZYINITLIST(.) + .[DATA_INGREDIENT_FLAGS] |= allergen_flags + +/obj/item/food/proc/set_nutriment_data(list/newdata) + if(REAGENT_TOTAL_VOLUME(reagents) && reagents.has_reagent(nutriment_type, 1)) + REAGENT_SET_DATA(reagents, nutriment_type, newdata) + +/obj/item/food/get_utensil_food_type() + return _utensil_food_type + +/obj/item/food/get_food_filling_color() + return filling_color || ..() + +/obj/item/food/handle_chunk_separated() + bitecount++ + +/obj/item/food/proc/add_allergen_flags(new_flags) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + var/list/newdata = reagent.mix_data(reagents, list(DATA_INGREDIENT_FLAGS = new_flags)) + if(newdata) + REAGENT_SET_DATA(reagents, reagent, newdata) + diff --git a/code/modules/reagents/reagent_containers/food/baking/baked_goods.dm b/code/modules/reagents/reagent_containers/food/baking/baked_goods.dm new file mode 100644 index 000000000000..035296bd59a6 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/baked_goods.dm @@ -0,0 +1,150 @@ +///////////////// +// Baked Goods // +///////////////// + +/obj/item/food/muffin + name = "muffin" + desc = "A delicious and spongy little cake." + icon = 'icons/obj/food/baked/muffin.dmi' + filling_color = "#e0cf9b" + center_of_mass = @'{"x":17,"y":4}' + nutriment_desc = list("sweetness" = 3, "muffin" = 3) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/berryclafoutis + name = "berry clafoutis" + desc = "No black birds, this is a good sign." + icon = 'icons/obj/food/baked/pies/berry.dmi' + plate = /obj/item/plate + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("sweetness" = 2, "pie" = 3) + nutriment_amt = 4 + bitesize = 3 + +/obj/item/food/berryclafoutis/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/drink/juice/berry, 5) + +/obj/item/food/waffles + name = "waffles" + desc = "Mmm, waffles." + icon = 'icons/obj/food/baked/waffles/plain.dmi' + trash = /obj/item/trash/waffles + filling_color = "#e6deb5" + center_of_mass = @'{"x":15,"y":11}' + nutriment_desc = list("waffle" = 8) + nutriment_amt = 8 + bitesize = 2 + +/obj/item/food/rofflewaffles + name = "waffles(?)" + desc = "There's something funny about these waffles." + icon = 'icons/obj/food/baked/waffles/blue.dmi' + trash = /obj/item/trash/waffles + filling_color = "#ff00f7" + center_of_mass = @'{"x":15,"y":11}' + nutriment_desc = list("waffle" = 7, "sweetness" = 1) + nutriment_amt = 8 + bitesize = 4 + +/obj/item/food/rofflewaffles/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/psychotropics, 8) + +/obj/item/food/pancakes + name = "pancakes" + desc = "Pancakes without blueberries, still delicious." + icon = 'icons/obj/food/fried/pancakes.dmi' + plate = /obj/item/plate + center_of_mass = @'{"x":15,"y":11}' + nutriment_desc = list("pancake" = 8) + nutriment_amt = 8 + bitesize = 2 + +/obj/item/food/pancakesblu + name = "blueberry pancakes" + desc = "Pancakes with blueberries, delicious." + icon = 'icons/obj/food/fried/pancakes.dmi' + plate = /obj/item/plate + center_of_mass = @'{"x":15,"y":11}' + nutriment_desc = list("pancake" = 8) + nutriment_amt = 8 + bitesize = 2 + +/obj/item/food/eggplantparm + name = "eggplant parmigiana" + desc = "The only good recipe for eggplant." + icon = 'icons/obj/food/baked/eggplant_parmigiana.dmi' + plate = /obj/item/plate + filling_color = "#4d2f5e" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("cheese" = 3, "eggplant" = 3) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/soylentgreen + name = "\improper Soylent Green" + desc = "Not made of people. Honest."//Totally people. + icon = 'icons/obj/food/baked/waffles/green.dmi' + trash = /obj/item/trash/waffles + filling_color = "#b8e6b5" + center_of_mass = @'{"x":15,"y":11}' + bitesize = 2 + +/obj/item/food/soylentgreen/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 10) + +/obj/item/food/soylenviridians + name = "\improper Soylen Virdians" + desc = "Not made of people. Honest."//Actually honest for once. + icon = 'icons/obj/food/baked/waffles/blue.dmi' + trash = /obj/item/trash/waffles + filling_color = "#e6fa61" + center_of_mass = @'{"x":15,"y":11}' + nutriment_desc = list("some sort of protein" = 10)//seasoned vERY well. + nutriment_amt = 10 + bitesize = 2 + +/obj/item/food/poppypretzel + name = "poppy pretzel" + desc = "It's all twisted up!" + icon = 'icons/obj/food/baked/pretzel.dmi' + filling_color = "#916e36" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("poppy seeds" = 2, "pretzel" = 3) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/fortunecookie + name = "fortune cookie" + desc = "A true prophecy in each cookie!" + icon = 'icons/obj/food/baked/fortune_cookie.dmi' + filling_color = "#e8e79e" + center_of_mass = @'{"x":15,"y":14}' + nutriment_desc = list("fortune cookie" = 2) + nutriment_amt = 3 + bitesize = 2 + + +/obj/item/food/bun + name = "bun" + desc = "A base for any self-respecting burger." + icon = 'icons/obj/food/baked/bun.dmi' + icon_state = ICON_STATE_WORLD + bitesize = 2 + center_of_mass = @'{"x":16,"y":12}' + nutriment_desc = list("bun" = 4) + nutriment_amt = 4 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/bunbun + name = "\improper Bun Bun" + desc = "A small bread monkey fashioned from two burger buns." + icon = 'icons/obj/food/baked/bunbun.dmi' + bitesize = 2 + center_of_mass = @'{"x":16,"y":8}' + nutriment_desc = list("bun" = 8) + nutriment_amt = 8 + nutriment_type = /decl/material/liquid/nutriment/bread diff --git a/code/modules/reagents/reagent_containers/food/baking/bread.dm b/code/modules/reagents/reagent_containers/food/baking/bread.dm new file mode 100644 index 000000000000..0ed284778fbe --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/bread.dm @@ -0,0 +1,134 @@ +/////////////////////// +// Bread-Based Foods // +/////////////////////// + +/obj/item/food/sandwich + name = "sandwich" + desc = "A grand creation of meat, cheese, bread, and several leaves of lettuce!" + icon = 'icons/obj/food/baked/sandwich.dmi' + plate = /obj/item/plate + filling_color = "#d9be29" + center_of_mass = @'{"x":16,"y":4}' + nutriment_desc = list("bread" = 3, "cheese" = 3) + nutriment_amt = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + bitesize = 2 + backyard_grilling_product = /obj/item/food/toastedsandwich + backyard_grilling_announcement = "is toasted golden brown." + +/obj/item/food/sandwich/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 3) + +/obj/item/food/toastedsandwich + name = "toasted sandwich" + desc = "Now if you only had a pepper bar." + icon = 'icons/obj/food/baked/toastedsandwich.dmi' + plate = /obj/item/plate + filling_color = "#d9be29" + center_of_mass = @'{"x":16,"y":4}' + nutriment_desc = list("toasted bread" = 3, "cheese" = 3) + nutriment_amt = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + bitesize = 2 + +/obj/item/food/toastedsandwich/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 3) + add_to_reagents(/decl/material/solid/carbon, 2) + +/obj/item/food/grilledcheese + name = "grilled cheese sandwich" + desc = "Goes great with tomato soup!" + icon = 'icons/obj/food/baked/toastedsandwich.dmi' + plate = /obj/item/plate + filling_color = "#d9be29" + nutriment_desc = list("toasted bread" = 3, "cheese" = 3) + nutriment_amt = 3 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/grilledcheese/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 4) + +/obj/item/food/baguette + name = "baguette" + desc = "Good for pretend sword fights." + icon = 'icons/obj/food/baked/baguette.dmi' + filling_color = "#e3d796" + center_of_mass = @'{"x":18,"y":12}' + nutriment_desc = list("long bread" = 6) + nutriment_amt = 6 + bitesize = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/baguette/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/blackpepper, 1) + add_to_reagents(/decl/material/solid/sodiumchloride, 1) + +/obj/item/food/jelliedtoast + name = "jellied toast" + desc = "A slice of bread covered with delicious jam." + icon = 'icons/obj/food/baked/jellytoast.dmi' + plate = /obj/item/plate + filling_color = "#b572ab" + center_of_mass = @'{"x":16,"y":8}' + nutriment_desc = list("toasted bread" = 2) + nutriment_amt = 1 + bitesize = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/jelliedtoast/cherry/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cherryjelly, 5) + +/obj/item/food/jellysandwich + name = "jelly sandwich" + desc = "You wish you had some peanut butter to go with this..." + icon = 'icons/obj/food/baked/jellysandwich.dmi' + plate = /obj/item/plate + filling_color = "#9e3a78" + center_of_mass = @'{"x":16,"y":8}' + nutriment_desc = list("bread" = 2) + nutriment_amt = 2 + bitesize = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/jellysandwich/cherry/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cherryjelly, 5) + +/obj/item/food/twobread + name = "\improper Two Bread" + desc = "It is very bitter and winy." + icon = 'icons/obj/food/baked/twobread.dmi' + filling_color = "#dbcc9a" + center_of_mass = @'{"x":15,"y":12}' + nutriment_desc = list("sourness" = 2, "bread" = 2) + nutriment_amt = 2 + bitesize = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/threebread + name = "\improper Three Bread" + desc = "Is such a thing even possible?" + icon = 'icons/obj/food/baked/threebread.dmi' + filling_color = "#dbcc9a" + center_of_mass = @'{"x":15,"y":12}' + nutriment_desc = list("sourness" = 2, "bread" = 3) + nutriment_amt = 3 + bitesize = 4 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/flatbread + name = "flatbread" + desc = "Bland but filling." + icon = 'icons/obj/food/baked/flatbread.dmi' + icon_state = ICON_STATE_WORLD + bitesize = 2 + center_of_mass = @'{"x":16,"y":16}' + nutriment_desc = list("bread" = 3) + nutriment_amt = 3 + nutriment_type = /decl/material/liquid/nutriment/bread diff --git a/code/modules/reagents/reagent_containers/food/baking/cookie.dm b/code/modules/reagents/reagent_containers/food/baking/cookie.dm new file mode 100644 index 000000000000..61e22ede1dc1 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/cookie.dm @@ -0,0 +1,11 @@ +/obj/item/food/cookie + name = "cookie" + desc = "It's a cookie!" + icon = 'icons/obj/food/baked/cookie.dmi' + filling_color = "#dbc94f" + center_of_mass = @'{"x":17,"y":18}' + nutriment_amt = 5 + nutriment_desc = list("sweetness" = 3, "crisp cookie" = 2) + w_class = ITEM_SIZE_TINY + bitesize = 1 + nutriment_type = /decl/material/liquid/nutriment/bread diff --git a/code/modules/reagents/reagent_containers/food/baking/donuts.dm b/code/modules/reagents/reagent_containers/food/baking/donuts.dm new file mode 100644 index 000000000000..bc52a6a4c291 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/donuts.dm @@ -0,0 +1,60 @@ +/obj/item/food/donut + name = "donut" + desc = "Goes great with Robust Coffee." + icon = 'icons/obj/food/donuts/donut.dmi' + icon_state = ICON_STATE_WORLD + filling_color = "#d9c386" + center_of_mass = @'{"x":19,"y":16}' + nutriment_desc = list("sweetness", "donut") + nutriment_amt = 3 + bitesize = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + var/iced_icon = 'icons/obj/food/donuts/donut_iced.dmi' + +/obj/item/food/donut/populate_reagents() + . = ..() + if(iced_icon && prob(30) && icon != iced_icon) + icon = iced_icon + SetName("frosted [name]") + add_to_reagents(/decl/material/liquid/nutriment/sprinkles, 2) + +/obj/item/food/donut/chaos + name = "chaos donut" + desc = "Like life, it never quite tastes the same." + filling_color = "#ed11e6" + nutriment_amt = 2 + bitesize = 10 + +/obj/item/food/donut/chaos/proc/get_random_fillings() + . = list( + /decl/material/liquid/nutriment, + /decl/material/liquid/capsaicin, + /decl/material/liquid/frostoil, + /decl/material/liquid/nutriment/sprinkles, + /decl/material/gas/chlorine, + /decl/material/liquid/nutriment/coco, + /decl/material/liquid/nutriment/banana_cream, + /decl/material/liquid/nutriment/cherryjelly, + /decl/material/liquid/fuel, + /decl/material/liquid/regenerator + ) + +/obj/item/food/donut/chaos/populate_reagents() + . = ..() + add_to_reagents(pick(get_random_fillings()), 3) + +/obj/item/food/donut/jelly + name = "jelly donut" + desc = "You jelly?" + icon = 'icons/obj/food/donuts/donut_jelly.dmi' + iced_icon = 'icons/obj/food/donuts/donut_jelly_iced.dmi' + filling_color = "#ed1169" + center_of_mass = @'{"x":16,"y":11}' + nutriment_amt = 3 + bitesize = 5 + nutriment_type = /decl/material/liquid/nutriment/bread + var/jelly_type = /decl/material/liquid/nutriment/cherryjelly + +/obj/item/food/donut/jelly/populate_reagents() + . = ..() + add_to_reagents(jelly_type, 5) diff --git a/code/modules/reagents/reagent_containers/food/baking/leavened_dough.dm b/code/modules/reagents/reagent_containers/food/baking/leavened_dough.dm new file mode 100644 index 000000000000..52918c1d95fd --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/leavened_dough.dm @@ -0,0 +1,50 @@ +/obj/item/food/dough + name = "leavened dough" + desc = "A piece of dough." + icon = 'icons/obj/food/baked/dough.dmi' + icon_state = ICON_STATE_WORLD + bitesize = 2 + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("raw dough" = 3) + nutriment_amt = 3 + nutriment_type = /decl/material/liquid/nutriment/bread + backyard_grilling_product = /obj/item/food/bun + backyard_grilling_announcement = "is baked into a simple bun." + +// Dough + rolling pin = flat dough +/obj/item/food/dough/attackby(obj/item/used_item, mob/user) + if(!istype(used_item,/obj/item/rollingpin)) + return ..() + var/obj/item/food/sliceable/flatdough/result = new() + result.dropInto(loc) + to_chat(user, "You flatten the dough.") + qdel(src) + return TRUE + +// slicable into 3x doughslices +/obj/item/food/sliceable/flatdough + name = "flat leavened dough" + desc = "A flattened lump of dough, made with yeast." + icon = 'icons/obj/food/baked/flattened_dough.dmi' + icon_state = ICON_STATE_WORLD + slice_path = /obj/item/food/doughslice + slice_num = 3 + center_of_mass = @'{"x":16,"y":16}' + utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SLICE + nutriment_amt = 4 + nutriment_desc = list("raw dough" = 1) + // TODO: pizza base with no toppings? Some other round leavened bread product? + backyard_grilling_product = /obj/item/food/flatbread + backyard_grilling_announcement = "is baked into a simple flatbread." + +/obj/item/food/doughslice + name = "leavened dough slice" + desc = "A building block of an impressive dish." + icon = 'icons/obj/food/baked/sliced_dough.dmi' + icon_state = ICON_STATE_WORLD + bitesize = 2 + center_of_mass = @'{"x":17,"y":19}' + nutriment_desc = list("raw dough" = 1) + nutriment_amt = 1 + nutriment_type = /decl/material/liquid/nutriment/bread + utensil_flags = UTENSIL_FLAG_COLLECT diff --git a/code/modules/reagents/reagent_containers/food/baking/piecrust.dm b/code/modules/reagents/reagent_containers/food/baking/piecrust.dm new file mode 100644 index 000000000000..00e2f0635530 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/piecrust.dm @@ -0,0 +1,8 @@ +/obj/item/food/piecrust + name = "pie crust" + desc = "A dense, buttery pie crust, ready for filling." + icon = 'icons/obj/food/baked/flattened_dough.dmi' + icon_state = ICON_STATE_WORLD + center_of_mass = @'{"x":16,"y":16}' + nutriment_amt = 4 + nutriment_desc = list("raw pie crust" = 1) diff --git a/code/modules/reagents/reagent_containers/food/baking/pies.dm b/code/modules/reagents/reagent_containers/food/baking/pies.dm new file mode 100644 index 000000000000..36c945ed89e8 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/pies.dm @@ -0,0 +1,133 @@ +/obj/item/food/bananapie + name = "banana cream pie" + desc = "Just like back home, on clown planet! HONK!" + icon = 'icons/obj/food/baked/pies/pie.dmi' + plate = /obj/item/plate + filling_color = "#fbffb8" + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("pie" = 3, "cream" = 2) + nutriment_amt = 4 + bitesize = 3 + +/obj/item/food/bananapie/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/banana_cream, 5) + +/obj/item/food/bananapie/throw_impact(atom/hit_atom) + ..() + new/obj/effect/decal/cleanable/pie_smudge(src.loc) + visible_message(SPAN_DANGER("\The [src] splats."), SPAN_DANGER("You hear a splat.")) + qdel(src) + +/obj/item/food/meatpie + name = "meat-pie" + icon = 'icons/obj/food/baked/pies/meat.dmi' + desc = "An old barber recipe, very delicious!" + plate = /obj/item/plate + filling_color = "#948051" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 2 + +/obj/item/food/meatpie/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 10) + +/obj/item/food/tofupie + name = "tofu-pie" + icon = 'icons/obj/food/baked/pies/meat.dmi' + desc = "A delicious tofu pie." + plate = /obj/item/plate + filling_color = "#fffee0" + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("tofu" = 2, "pie" = 8) + nutriment_amt = 10 + bitesize = 2 + +/obj/item/food/amanita_pie + name = "amanita pie" + desc = "Sweet and tasty poison pie." + icon = 'icons/obj/food/baked/pies/amanita.dmi' + filling_color = "#ffcccc" + center_of_mass = @'{"x":17,"y":9}' + nutriment_desc = list("sweetness" = 3, "mushroom" = 3, "pie" = 2) + nutriment_amt = 5 + bitesize = 3 + +/obj/item/food/amanita_pie/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/amatoxin, 3) + add_to_reagents(/decl/material/liquid/psychotropics, 1) + +/obj/item/food/plump_pie + name = "plump pie" + desc = "I bet you love stuff made out of plump helmets!" + icon = 'icons/obj/food/baked/pies/plumphelmet.dmi' + filling_color = "#b8279b" + center_of_mass = @'{"x":17,"y":9}' + nutriment_desc = list("heartiness" = 2, "mushroom" = 3, "pie" = 3) + nutriment_amt = 8 + bitesize = 2 + +/obj/item/food/plump_pie/populate_reagents() + . = ..() + if(prob(10)) //#TODO: have this depend on cook's skill within the recipe handling instead maybe? + name = "exceptional plump pie" + desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump pie!" + add_to_reagents(/decl/material/liquid/regenerator, 5) + +/obj/item/food/xemeatpie + name = "xeno-pie" + icon = 'icons/obj/food/baked/pies/xeno.dmi' + desc = "A delicious meatpie. Probably heretical." + plate = /obj/item/plate + filling_color = "#43de18" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 2 + +/obj/item/food/xemeatpie/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/xeno, 10) + +/obj/item/food/applepie + name = "apple pie" + desc = "A pie containing sweet sweet love... or apple." + icon = 'icons/obj/food/baked/pies/apple.dmi' + filling_color = "#e0edc5" + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("sweetness" = 2, "apple" = 2, "pie" = 2) + nutriment_amt = 4 + bitesize = 3 + +/obj/item/food/cherrypie + name = "cherry pie" + desc = "Taste so good, make a grown man cry." + icon = 'icons/obj/food/baked/pies/cherry.dmi' + filling_color = "#ff525a" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("sweetness" = 2, "cherry" = 2, "pie" = 2) + nutriment_amt = 4 + bitesize = 3 + +/obj/item/food/sliceable/pumpkinpie + name = "pumpkin pie" + desc = "A delicious treat for the autumn months." + icon = 'icons/obj/food/baked/cakes/pumpkin.dmi' + slice_path = /obj/item/food/slice/pumpkinpie + slice_num = 5 + filling_color = "#f5b951" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("pie" = 5, "cream" = 5, "pumpkin" = 5) + nutriment_amt = 15 + +/obj/item/food/slice/pumpkinpie + name = "pumpkin pie slice" + desc = "A slice of pumpkin pie, with whipped cream on top. Perfection." + icon = 'icons/obj/food/baked/cakes/slices/pumpkin.dmi' + plate = /obj/item/plate + filling_color = "#f5b951" + bitesize = 2 + center_of_mass = @'{"x":16,"y":12}' + whole_path = /obj/item/food/sliceable/pumpkinpie + +/obj/item/food/slice/pumpkinpie/filled + filled = TRUE \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/baking/unleavened_dough.dm b/code/modules/reagents/reagent_containers/food/baking/unleavened_dough.dm new file mode 100644 index 000000000000..0873a9924e95 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/baking/unleavened_dough.dm @@ -0,0 +1,26 @@ +/obj/item/food/sliceable/unleaveneddough + name = "unleavened dough" + desc = "A flattened lump of dough, made without yeast." + icon = 'icons/obj/food/baked/flattened_dough.dmi' + icon_state = ICON_STATE_WORLD + center_of_mass = @'{"x":16,"y":16}' + backyard_grilling_product = /obj/item/food/flatbread + backyard_grilling_announcement = "is baked into a simple flatbread." + nutriment_amt = 4 + nutriment_desc = list("raw dough" = 1) + slice_path = /obj/item/food/unleaveneddoughslice + slice_num = 3 + +/obj/item/food/unleaveneddoughslice + name = "unleavened dough slice" + desc = "A building block of an impressive dish." + icon = 'icons/obj/food/baked/sliced_dough.dmi' + icon_state = ICON_STATE_WORLD + slice_path = /obj/item/food/spagetti + slice_num = 1 + bitesize = 2 + center_of_mass = @'{"x":17,"y":19}' + nutriment_desc = list("raw dough" = 1) + nutriment_amt = 1 + nutriment_type = /decl/material/liquid/nutriment/bread + utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SLICE diff --git a/code/modules/reagents/reagent_containers/food/burgers.dm b/code/modules/reagents/reagent_containers/food/burgers.dm new file mode 100644 index 000000000000..9945c504f4a0 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/burgers.dm @@ -0,0 +1,201 @@ +///////////// +// Burgers // +///////////// + +/obj/item/food/brainburger + name = "brainburger" + desc = "A strange looking burger. It looks almost sentient." + icon = 'icons/obj/food/burgers/brainburger.dmi' + filling_color = "#f2b6ea" + center_of_mass = @'{"x":15,"y":11}' + bitesize = 2 + material = /decl/material/solid/organic/meat + +/obj/item/food/brainburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 6) + add_to_reagents(/decl/material/liquid/neuroannealer, 6) + +/obj/item/food/ghostburger + name = "ghost burger" + desc = "Spooky! It doesn't look very filling." + icon = 'icons/obj/food/burgers/ghostburger.dmi' + filling_color = "#fff2ff" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("buns" = 3, "spookiness" = 3) + nutriment_amt = 2 + bitesize = 2 + +/obj/item/food/cheeseburger + name = "cheeseburger" + desc = "The cheese adds a good flavor." + icon = 'icons/obj/food/burgers/cheeseburger.dmi' + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("cheese" = 2, "bun" = 2) + nutriment_amt = 2 + +/obj/item/food/cheeseburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 2) + +/obj/item/food/burger + name = "burger" + desc = "The cornerstone of every nutritious breakfast." + icon = 'icons/obj/food/burgers/burger.dmi' + filling_color = "#d63c3c" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("bun" = 2) + nutriment_amt = 3 + bitesize = 2 + +/obj/item/food/burger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 3) + +/obj/item/food/hamburger + name = "hamburger" + desc = "The cornerstone of every nutritious breakfast, now with ham!" + icon = 'icons/obj/food/burgers/hamburger.dmi' + filling_color = "#d63c3c" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("bun" = 2) + nutriment_amt = 3 + bitesize = 2 + +/obj/item/food/hamburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 5) + +/obj/item/food/fishburger + name = "fish sandwich" + desc = "Almost like a carp is yelling somewhere... Give me back that fillet -o- carp, give me that carp." + icon = 'icons/obj/food/burgers/fishburger.dmi' + filling_color = "#ffdefe" + center_of_mass = @'{"x":16,"y":10}' + bitesize = 3 + +/obj/item/food/fishburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 6) + +/obj/item/food/tofuburger + name = "tofu burger" + desc = "What... is that meat?" + icon = 'icons/obj/food/burgers/tofuburger.dmi' + filling_color = "#fffee0" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("bun" = 2, "pseudo-soy meat" = 3) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/roburger + name = "roburger" + desc = "The lettuce is the only organic component. Beep." + icon = 'icons/obj/food/burgers/roburger.dmi' + filling_color = COLOR_GRAY80 + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("bun" = 2, "metal" = 3) + nutriment_amt = 2 + bitesize = 2 + +/obj/item/food/roburger/populate_reagents() + . = ..() + if(prob(5)) + add_to_reagents(/decl/material/liquid/nanitefluid, 2) + +/obj/item/food/roburgerbig + name = "roburger" + desc = "This massive patty looks like poison. Beep." + icon = 'icons/obj/food/burgers/roburger.dmi' + filling_color = COLOR_GRAY80 + chem_volume = 100 + center_of_mass = @'{"x":16,"y":11}' + bitesize = 0.1 + +/obj/item/food/roburgerbig/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nanitefluid, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/food/xenoburger + name = "xenoburger" + desc = "Smells caustic. Tastes like heresy." + icon = 'icons/obj/food/burgers/xenoburger.dmi' + filling_color = "#43de18" + center_of_mass = @'{"x":16,"y":11}' + bitesize = 2 + +/obj/item/food/xenoburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 8) + +/obj/item/food/clownburger + name = "clown burger" + desc = "This tastes funny..." + icon = 'icons/obj/food/burgers/clownburger.dmi' + filling_color = "#ff00ff" + center_of_mass = @'{"x":17,"y":12}' + nutriment_desc = list("bun" = 2, "clown shoe" = 3) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/mimeburger + name = "mime burger" + desc = "Its taste defies language." + icon = 'icons/obj/food/burgers/mimeburger.dmi' + filling_color = "#ffffff" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("bun" = 2, "mime paint" = 3) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/spellburger + name = "spell burger" + desc = "This is absolutely magical." + icon = 'icons/obj/food/burgers/spellburger.dmi' + filling_color = "#d505ff" + nutriment_desc = list("magic" = 3, "buns" = 3) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/bigbiteburger + name = "big bite burger" + desc = "Forget the Luna Burger! THIS is the future!" + icon = 'icons/obj/food/burgers/bigbiteburger.dmi' + filling_color = "#e3d681" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("buns" = 4) + nutriment_amt = 4 + bitesize = 3 + +/obj/item/food/bigbiteburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 10) + +/obj/item/food/jellyburger + name = "jelly burger" + desc = "Culinary delight...?" + icon = 'icons/obj/food/burgers/jellyburger.dmi' + filling_color = "#b572ab" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("buns" = 5) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/jellyburger/cherry/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cherryjelly, 5) + +/obj/item/food/superbiteburger + name = "super bite burger" + desc = "This is a mountain of a burger. FOOD!" + icon = 'icons/obj/food/burgers/superbiteburger.dmi' + filling_color = "#cca26a" + center_of_mass = @'{"x":16,"y":3}' + nutriment_desc = list("buns" = 25) + nutriment_amt = 25 + bitesize = 10 + +/obj/item/food/superbiteburger/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 25) + diff --git a/code/modules/reagents/reagent_containers/food/canned/_canned.dm b/code/modules/reagents/reagent_containers/food/canned/_canned.dm new file mode 100644 index 000000000000..6b7c35f23dff --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/canned/_canned.dm @@ -0,0 +1,156 @@ +//Canned Foods - crack open, eat. + +#define OPEN_HARD 1 +#define OPEN_EASY 0 + +/obj/item/food/can + name = "empty can" + icon = 'icons/obj/food/canned/canned.dmi' + icon_state = "blank" + center_of_mass = @'{"x":15,"y":9}' + atom_flags = 0 + bitesize = 3 + + var/sealed = TRUE + var/open_complexity = OPEN_HARD + +/obj/item/food/can/Initialize(mapload, material_key, skip_plate = FALSE) + . = ..() + if(!sealed) + unseal() + +/obj/item/food/can/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "It is [!ATOM_IS_OPEN_CONTAINER(src) ? "" : "un"]sealed." + . += "It looks [open_complexity ? "hard" : "easy "] to open." + +/obj/item/food/can/proc/unseal(mob/user) + playsound(src, 'sound/effects/canopen.ogg', rand(10, 50), 1) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + sealed = FALSE + +/obj/item/food/can/attack_self(mob/user) + if(!ATOM_IS_OPEN_CONTAINER(src) && !open_complexity) + to_chat(user, SPAN_NOTICE("You unseal \the [src] with a crack of metal.")) + unseal() + +/obj/item/food/can/attackby(obj/item/used_item, mob/user) + if(!ATOM_IS_OPEN_CONTAINER(src)) + if(istype(used_item, /obj/item/knife)) + user.visible_message( + SPAN_NOTICE("\The [user] starts trying to open \the [src] with \the [used_item]."), + SPAN_NOTICE("You start to open \the [src].") + ) + var/open_timer = istype(used_item, /obj/item/knife/opener) ? 5 SECONDS : 15 SECONDS + if(!do_after(user, open_timer, src)) + to_chat(user, SPAN_WARNING("You must remain uninterrupted to open \the [src].")) + return TRUE + to_chat(user, SPAN_NOTICE("You unseal \the [src] with a crack of metal.")) + unseal() + return TRUE + else if(istype(used_item,/obj/item/utensil)) + to_chat(user, SPAN_WARNING("You need a can opener to open this!")) + return TRUE + return ..() + +/obj/item/food/can/on_update_icon() + . = ..() + icon_state = initial(icon_state) + if(ATOM_IS_OPEN_CONTAINER(src)) + icon_state = "[initial(icon_state)]-open" + +/obj/item/food/can/apply_filling_overlay() + return //Bypass searching through the whole icon file for a filling icon + +/obj/item/food/can/can_be_poured_into(atom/source) + return (REAGENT_MAXIMUM_VOLUME(reagents) > 0) && ATOM_IS_OPEN_CONTAINER(src) + +//Just a short line of Canned Consumables, great for treasure in faraway abandoned outposts + +/obj/item/food/can/beef + name = "quadrangled beefium" + icon_state = "beef" + desc = "Proteins carefully cloned from an extinct species of cattle in a secret facility on the outer rim." + trash = /obj/item/trash/beef + filling_color = "#663300" + nutriment_desc = list("beef" = 1) + +/obj/item/food/can/beef/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 12) + +/obj/item/food/can/beans + name = "baked beans" + icon_state = "beans" + desc = "Carefully synthesized from soy." + trash = /obj/item/trash/beans + filling_color = "#ff6633" + nutriment_desc = list("beans" = 1) + nutriment_amt = 12 + +/obj/item/food/can/tomato + name = "tomato soup" + icon_state = "tomato" + desc = "Plain old unseasoned tomato soup. This can is older than you are!" + trash = /obj/item/trash/tomato + filling_color = "#ae0000" + nutriment_desc = list("tomato" = 1) + eat_sound = 'sound/items/drink.ogg' + utensil_flags = UTENSIL_FLAG_SCOOP + +/obj/item/food/can/tomato/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/soup, 12, list( + DATA_TASTE = list("tomato" = 1), + DATA_INGREDIENT_LIST = list("tomato" = 1), + DATA_INGREDIENT_FLAGS = ALLERGEN_VEGETABLE + )) + +/obj/item/food/can/spinach + name = "spinach" + icon_state = "spinach" + desc = "Notably has less iron in it than a watermelon." + trash = /obj/item/trash/spinach + filling_color = "#003300" + nutriment_desc = list("sogginess" = 1, "vegetable" = 1) + bitesize = 20 + +/obj/item/food/can/spinach/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment, 5) + add_to_reagents(/decl/material/liquid/adrenaline, 5) + add_to_reagents(/decl/material/liquid/amphetamines, 5) + add_to_reagents(/decl/material/solid/metal/iron, 5) + +//Vending Machine Foods should go here. + +/obj/item/food/can/caviar + name = "canned caviar" + icon_state = "fisheggs" + desc = "Caviar, or space carp eggs. Carefully faked using alginate, artificial flavoring and salt." + trash = /obj/item/trash/fishegg + filling_color = "#000000" + nutriment_desc = list("fish" = 1, "salt" = 1) + nutriment_amt = 6 + +/obj/item/food/can/caviar/true + name = "canned caviar" + icon_state = "carpeggs" + desc = "Caviar, or space carp eggs. Exceeds the recommended amount of heavy metals in your diet! But very posh." + trash = /obj/item/trash/carpegg + filling_color = "#330066" + nutriment_desc = list("fish" = 1, "salt" = 1, "a numbing sensation" = 1) + nutriment_amt = 6 + +/obj/item/food/can/caviar/true/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/fish, 4) + add_to_reagents(/decl/material/liquid/carpotoxin, 1) + +/obj/item/knife/opener + name = "can-opener" + desc = "A simple can-opener." + icon = 'icons/obj/items/weapon/knives/opener.dmi' + +#undef OPEN_EASY +#undef OPEN_HARD diff --git a/code/modules/reagents/reagent_containers/food/canned/can_edibility.dm b/code/modules/reagents/reagent_containers/food/canned/can_edibility.dm new file mode 100644 index 000000000000..2e39d5e3bb80 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/canned/can_edibility.dm @@ -0,0 +1,5 @@ +/obj/item/food/can/handle_eaten_by_mob(mob/user, mob/target) + if(!ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_NOTICE("You need to open \the [src] first!")) + return EATEN_UNABLE + return ..() diff --git a/code/modules/reagents/reagent_containers/food/cans.dm b/code/modules/reagents/reagent_containers/food/cans.dm deleted file mode 100644 index 78388bc4f17c..000000000000 --- a/code/modules/reagents/reagent_containers/food/cans.dm +++ /dev/null @@ -1,228 +0,0 @@ -/obj/item/chems/food/drinks/cans - volume = 40 //just over one and a half cups - amount_per_transfer_from_this = 5 - atom_flags = 0 //starts closed - material = /decl/material/solid/metal/aluminium - -//DRINKS - -/obj/item/chems/food/drinks/cans/cola - name = "\improper Space Cola" - desc = "Cola. in space." - icon_state = "cola" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/cola/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/cola, 30) - -/obj/item/chems/food/drinks/cans/waterbottle - name = "bottled water" - desc = "Pure drinking water, imported from the Martian poles." - icon_state = "waterbottle" - center_of_mass = @"{'x':15,'y':8}" - material = /decl/material/solid/plastic - -/obj/item/chems/food/drinks/cans/waterbottle/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/water, 30) - -/obj/item/chems/food/drinks/cans/waterbottle/open(mob/user) - playsound(loc,'sound/effects/bonebreak1.ogg', rand(10,50), 1) - to_chat(user, "You twist open \the [src], destroying the safety seal!") - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - -/obj/item/chems/food/drinks/cans/space_mountain_wind - name = "\improper Space Mountain Wind" - desc = "Blows right through you like a space wind." - icon_state = "space_mountain_wind" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/space_mountain_wind/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/citrussoda, 30) - -/obj/item/chems/food/drinks/cans/thirteenloko - name = "\improper Thirteen Loko" - desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsibly." - icon_state = "thirteen_loko" - center_of_mass = @"{'x':16,'y':8}" - -/obj/item/chems/food/drinks/cans/thirteenloko/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/thirteenloko, 30) - -/obj/item/chems/food/drinks/cans/dr_gibb - name = "\improper Dr. Gibb" - desc = "A delicious mixture of 42 different flavors." - icon_state = "dr_gibb" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/dr_gibb/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/cherrycola, 30) - -/obj/item/chems/food/drinks/cans/starkist - name = "\improper Star-Kist" - desc = "Can you taste a bit of tuna...?" - icon_state = "starkist" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/starkist/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/orangecola, 30) - -/obj/item/chems/food/drinks/cans/space_up - name = "\improper Space-Up" - desc = "Tastes like a hull breach in your mouth." - icon_state = "space-up" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/space_up/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/lemonade, 30) - -/obj/item/chems/food/drinks/cans/lemon_lime - name = "\improper Lemon-Lime" - desc = "You wanted ORANGE. It gave you Lemon Lime." - icon_state = "lemon-lime" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/lemon_lime/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/lemon_lime, 30) - -/obj/item/chems/food/drinks/cans/iced_tea - name = "\improper Vrisk Serket Iced Tea" - desc = "That sweet, refreshing southern earthy flavor. That's where it's from, right? South Earth?" - icon_state = "ice_tea_can" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/iced_tea/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/tea/black, 25) - reagents.add_reagent(/decl/material/solid/ice, 5) - -/obj/item/chems/food/drinks/cans/grape_juice - name = "\improper Grapel Juice" - desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" - icon_state = "purple_can" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/grape_juice/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/grape, 30) - -/obj/item/chems/food/drinks/cans/tonic - name = "\improper T-Borg's Tonic Water" - desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." - icon_state = "tonic" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/tonic/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/tonic, 30) - -/obj/item/chems/food/drinks/cans/sodawater - name = "soda water" - desc = "A can of soda water. Still water's more refreshing cousin." - icon_state = "sodawater" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/sodawater/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/sodawater, 30) - -/obj/item/chems/food/drinks/cans/beastenergy - name = "Beast Energy" - desc = "100% pure energy, and 150% pure liver disease." - icon_state = "beastenergy" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/cans/beastenergy/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/beastenergy, 30) - -//Items exclusive to the BODA machine on deck 4 and wherever else it pops up. First two are a bit jokey. Second two are genuine article. - -/obj/item/chems/food/drinks/cans/syndicolax - name = "\improper Red Army Twist!" - desc = "A taste of what keeps our glorious nation running! Served as Space Commissariat Stahlin prefers it! Luke warm." - icon_state = "syndi_cola_x" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/syndicolax/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/potato, 30) - -/obj/item/chems/food/drinks/cans/artbru - name = "\improper Arstotzka Bru" - desc = "Just what any bureaucrat needs to get through the day. Keep stamping those papers!" - icon_state = "art_bru" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/artbru/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/turnip, 30) - -/obj/item/chems/food/drinks/cans/syndicola - name = "\improper TerraCola" - desc = "A can of the only soft drink state approved for the benefit of the people. Served at room temperature regardless of ambient temperatures thanks to innovative Terran insulation technology." - icon_state = "syndi_cola" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/syndicola/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/water, 25) - reagents.add_reagent(/decl/material/solid/metal/iron, 5) - -/obj/item/chems/food/drinks/glass2/square/boda - name = "boda" - desc = "A tall glass of refreshing Boda!" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/glass2/square/boda/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/sodawater, 30) - -/obj/item/chems/food/drinks/glass2/square/bodaplus - name = "tri kopeiki sirop boda" - desc = "A tall glass of even more refreshing Boda! Now with Sok!" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/glass2/square/bodaplus/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/sodawater, 15) - reagents.add_reagent(pick(list( - /decl/material/liquid/drink/citrusseltzer, - /decl/material/liquid/drink/juice/grape, - /decl/material/liquid/drink/juice/orange, - /decl/material/liquid/drink/juice/lemon, - /decl/material/liquid/drink/juice/lime, - /decl/material/liquid/drink/juice/apple, - /decl/material/liquid/drink/juice/pear, - /decl/material/liquid/drink/juice/banana, - /decl/material/liquid/drink/juice/berry, - /decl/material/liquid/drink/juice/watermelon)), 15) - -//Canned alcohols. - -/obj/item/chems/food/drinks/cans/speer - name = "\improper Space Beer" - desc = "Now in a can!" - icon_state = "beercan" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/speer/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/beer/good, 30) - -/obj/item/chems/food/drinks/cans/ale - name = "\improper Magm-Ale" - desc = "Now in a can!" - icon_state = "alecan" - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/drinks/cans/ale/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/ale, 30) diff --git a/code/modules/reagents/reagent_containers/food/chocolate/chocolate.dm b/code/modules/reagents/reagent_containers/food/chocolate/chocolate.dm new file mode 100644 index 000000000000..9c0b4afd7d6e --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/chocolate/chocolate.dm @@ -0,0 +1,30 @@ + +/obj/item/food/chocolatebar + name = "chocolate bar" + desc = "Such sweet, fattening food." + icon = 'icons/obj/food/chocolatebar.dmi' + filling_color = "#7d5f46" + center_of_mass = @'{"x":15,"y":15}' + nutriment_amt = 2 + nutriment_desc = list("chocolate" = 5) + bitesize = 2 + +/obj/item/food/chocolatebar/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/coco, 2) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 2) + +/obj/item/food/chocolateegg + name = "chocolate egg" + desc = "Such sweet, fattening food." + icon = 'icons/obj/food/eggs/egg_chocolate.dmi' + filling_color = "#7d5f46" + center_of_mass = @'{"x":16,"y":13}' + nutriment_amt = 3 + nutriment_desc = list("chocolate" = 5) + bitesize = 2 + +/obj/item/food/chocolateegg/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/coco, 2) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 2) diff --git a/code/modules/reagents/reagent_containers/food/condiment.dm b/code/modules/reagents/reagent_containers/food/condiment.dm deleted file mode 100644 index 0e08412aee56..000000000000 --- a/code/modules/reagents/reagent_containers/food/condiment.dm +++ /dev/null @@ -1,364 +0,0 @@ - -///////////////////////////////////////////////Condiments -//Notes by Darem: The condiments food-subtype is for stuff you don't actually eat but you use to modify existing food. They all -// leave empty containers when used up and can be filled/re-filled with other items. Formatting for first section is identical -// to mixed-drinks code. If you want an object that starts pre-loaded, you need to make it in addition to the other code. - -//Food items that aren't eaten normally and leave an empty container behind. -/obj/item/chems/food/condiment - name = "Condiment Container" - desc = "Just your average condiment container." - icon = 'icons/obj/food.dmi' - icon_state = "emptycondiment" - atom_flags = ATOM_FLAG_OPEN_CONTAINER - possible_transfer_amounts = @"[1,5,10]" - center_of_mass = @"{'x':16,'y':6}" - volume = 50 - var/list/starting_reagents - var/global/list/special_bottles = list( - /decl/material/liquid/nutriment/ketchup = /obj/item/chems/food/condiment/ketchup, - /decl/material/liquid/nutriment/barbecue = /obj/item/chems/food/condiment/barbecue, - /decl/material/liquid/capsaicin = /obj/item/chems/food/condiment/capsaicin, - /decl/material/liquid/enzyme = /obj/item/chems/food/condiment/enzyme, - /decl/material/liquid/nutriment/soysauce = /obj/item/chems/food/condiment/soysauce, - /decl/material/liquid/frostoil = /obj/item/chems/food/condiment/frostoil, - /decl/material/solid/mineral/sodiumchloride = /obj/item/chems/food/condiment/small/saltshaker, - /decl/material/solid/blackpepper = /obj/item/chems/food/condiment/small/peppermill, - /decl/material/liquid/nutriment/cornoil = /obj/item/chems/food/condiment/cornoil, - /decl/material/liquid/nutriment/sugar = /obj/item/chems/food/condiment/sugar, - /decl/material/liquid/nutriment/mayo = /obj/item/chems/food/condiment/mayo, - /decl/material/liquid/nutriment/vinegar = /obj/item/chems/food/condiment/vinegar - ) - -/obj/item/chems/food/condiment/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/pen) || istype(W, /obj/item/flashlight/pen)) - var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) - if(tmp_label == label_text) - return - if(length(tmp_label) > 10) - to_chat(user, "The label can be at most 10 characters long.") - else - if(length(tmp_label)) - to_chat(user, "You set the label to \"[tmp_label]\".") - label_text = tmp_label - name = addtext(name," ([label_text])") - else - to_chat(user, "You remove the label.") - label_text = null - SSmaterials.queue_reagent_change(src) - return - - - -/obj/item/chems/food/condiment/attack_self(var/mob/user) - return - -/obj/item/chems/food/condiment/attack(var/mob/M, var/mob/user, var/def_zone) - if(standard_feed_mob(user, M)) - return - -/obj/item/chems/food/condiment/afterattack(var/obj/target, var/mob/user, var/proximity) - if(!proximity) - return - - if(standard_dispenser_refill(user, target)) - return - if(standard_pour_into(user, target)) - return - - if(istype(target, /obj/item/chems/food/snacks)) // These are not opencontainers but we can transfer to them - if(!reagents || !reagents.total_volume) - to_chat(user, "There is no condiment left in \the [src].") - return - - if(!REAGENTS_FREE_SPACE(target.reagents)) - to_chat(user, "You can't add more condiment to \the [target].") - return - - var/trans = reagents.trans_to_obj(target, amount_per_transfer_from_this) - to_chat(user, "You add [trans] units of the condiment to \the [target].") - else - ..() - -/obj/item/chems/food/condiment/feed_sound(var/mob/user) - playsound(user.loc, 'sound/items/drink.ogg', rand(10, 50), 1) - -/obj/item/chems/food/condiment/self_feed_message(var/mob/user) - to_chat(user, "You swallow some of contents of \the [src].") - -/obj/item/chems/food/condiment/Initialize() - . = ..() - for(var/R in starting_reagents) - reagents.add_reagent(R, starting_reagents[R]) - -/obj/item/chems/food/condiment/on_reagent_change() - var/reagent = reagents.primary_reagent - if(reagent in special_bottles) - var/obj/item/chems/food/condiment/special_bottle = special_bottles[reagent] - name = initial(special_bottle.name) - desc = initial(special_bottle.desc) - icon_state = initial(special_bottle.icon_state) - center_of_mass = initial(special_bottle.center_of_mass) - else - name = initial(name) - desc = initial(desc) - center_of_mass = initial(center_of_mass) - if(LAZYLEN(reagents.reagent_volumes)) - icon_state = "mixedcondiments" - else - icon_state = "emptycondiment" - if(label_text) - name = addtext(name," ([label_text])") - -/obj/item/chems/food/condiment/enzyme - name = "universal enzyme" - desc = "Used in cooking various dishes." - icon_state = "enzyme" - starting_reagents = list(/decl/material/liquid/enzyme = 50) - -/obj/item/chems/food/condiment/barbecue - name = "barbecue sauce" - desc = "Barbecue sauce, it's labeled 'sweet and spicy'" - icon_state = "barbecue" - starting_reagents = list(/decl/material/liquid/nutriment/barbecue = 50) - -/obj/item/chems/food/condiment/sugar - name = "sugar" - desc = "Cavities in a bottle." - starting_reagents = list(/decl/material/liquid/nutriment/sugar = 50) - -/obj/item/chems/food/condiment/ketchup - name = "ketchup" - desc = "Tomato, but more liquid, stronger, better." - icon_state = "ketchup" - starting_reagents = list(/decl/material/liquid/nutriment/ketchup = 50) - -/obj/item/chems/food/condiment/cornoil - name = "corn oil" - desc = "A delicious oil used in cooking. Made from corn." - icon_state = "oliveoil" - starting_reagents = list(/decl/material/liquid/nutriment/cornoil = 50) - -/obj/item/chems/food/condiment/vinegar - name = "vinegar" - icon_state = "vinegar" - desc = "As acidic as it gets in the kitchen." - starting_reagents = list(/decl/material/liquid/nutriment/vinegar = 50) - -/obj/item/chems/food/condiment/mayo - name = "mayonnaise" - icon_state = "mayo" - desc = "Mayonnaise, used for centuries to make things edible." - starting_reagents = list(/decl/material/liquid/nutriment/mayo = 50) - -/obj/item/chems/food/condiment/frostoil - name = "coldsauce" - desc = "Leaves the tongue numb in its passage." - icon_state = "coldsauce" - starting_reagents = list(/decl/material/liquid/frostoil = 50) - -/obj/item/chems/food/condiment/capsaicin - name = "hotsauce" - desc = "You can almost TASTE the stomach ulcers now!" - icon_state = "hotsauce" - starting_reagents = list(/decl/material/liquid/capsaicin = 50) - -/obj/item/chems/food/condiment/small - possible_transfer_amounts = @"[1,20]" - amount_per_transfer_from_this = 1 - volume = 20 - -/obj/item/chems/food/condiment/small/on_reagent_change() - return - -/obj/item/chems/food/condiment/small/saltshaker - name = "salt shaker" - desc = "Salt. From space oceans, presumably." - icon_state = "saltshakersmall" - center_of_mass = @"{'x':16,'y':9}" - starting_reagents = list(/decl/material/solid/mineral/sodiumchloride = 20) - -/obj/item/chems/food/condiment/small/peppermill - name = "pepper mill" - desc = "Often used to flavor food or make people sneeze." - icon_state = "peppermillsmall" - center_of_mass = @"{'x':16,'y':8}" - starting_reagents = list(/decl/material/solid/blackpepper = 20) - -/obj/item/chems/food/condiment/small/sugar - name = "sugar" - desc = "Sweetness in a bottle" - icon_state = "sugarsmall" - center_of_mass = @"{'x':17,'y':9}" - starting_reagents = list(/decl/material/liquid/nutriment/sugar = 20) - -//MRE condiments and drinks. - -/obj/item/chems/food/condiment/small/packet - icon_state = "packet_small" - w_class = ITEM_SIZE_TINY - possible_transfer_amounts = @"[1,5,10]" - amount_per_transfer_from_this = 1 - volume = 10 - -/obj/item/chems/food/condiment/small/packet/salt - name = "salt packet" - desc = "Contains 5u of table salt." - icon_state = "packet_small_white" - starting_reagents = list(/decl/material/solid/mineral/sodiumchloride = 5) - -/obj/item/chems/food/condiment/small/packet/pepper - name = "pepper packet" - desc = "Contains 5u of black pepper." - icon_state = "packet_small_black" - starting_reagents = list(/decl/material/solid/blackpepper = 5) - -/obj/item/chems/food/condiment/small/packet/sugar - name = "sugar packet" - desc = "Contains 5u of refined sugar." - icon_state = "packet_small_white" - starting_reagents = list(/decl/material/liquid/nutriment/sugar = 5) - -/obj/item/chems/food/condiment/small/packet/jelly - name = "jelly packet" - desc = "Contains 10u of cherry jelly. Best used for spreading on crackers." - starting_reagents = list(/decl/material/liquid/nutriment/cherryjelly = 10) - icon_state = "packet_medium" - -/obj/item/chems/food/condiment/small/packet/honey - name = "honey packet" - desc = "Contains 10u of honey." - starting_reagents = list(/decl/material/liquid/nutriment/sugar = 10) - icon_state = "packet_medium" - -/obj/item/chems/food/condiment/small/packet/capsaicin - name = "hot sauce packet" - desc = "Contains 5u of hot sauce. Enjoy in moderation." - icon_state = "packet_small_red" - starting_reagents = list(/decl/material/liquid/capsaicin = 5) - -/obj/item/chems/food/condiment/small/packet/ketchup - name = "ketchup packet" - desc = "Contains 5u of ketchup." - icon_state = "packet_small_red" - starting_reagents = list(/decl/material/liquid/nutriment/ketchup = 5) - -/obj/item/chems/food/condiment/small/packet/mayo - name = "mayonnaise packet" - desc = "Contains 5u of mayonnaise." - icon_state = "packet_small_white" - starting_reagents = list(/decl/material/liquid/nutriment/mayo = 5) - -/obj/item/chems/food/condiment/small/packet/soy - name = "soy sauce packet" - desc = "Contains 5u of soy sauce." - icon_state = "packet_small_black" - starting_reagents = list(/decl/material/liquid/nutriment/soysauce = 5) - -/obj/item/chems/food/condiment/small/packet/coffee - name = "instant coffee powder packet" - desc = "Contains 5u of instant coffee powder. Mix with 25u of water." - starting_reagents = list(/decl/material/liquid/nutriment/coffee/instant = 5) - -/obj/item/chems/food/condiment/small/packet/tea - name = "instant tea powder packet" - desc = "Contains 5u of instant black tea powder. Mix with 25u of water." - starting_reagents = list(/decl/material/liquid/nutriment/tea/instant = 5) - -/obj/item/chems/food/condiment/small/packet/cocoa - name = "cocoa powder packet" - desc = "Contains 5u of cocoa powder. Mix with 25u of water and heat." - starting_reagents = list(/decl/material/liquid/nutriment/coco = 5) - -/obj/item/chems/food/condiment/small/packet/grape - name = "grape juice powder packet" - desc = "Contains 5u of powdered grape juice. Mix with 15u of water." - starting_reagents = list(/decl/material/liquid/nutriment/instantjuice/grape = 5) - -/obj/item/chems/food/condiment/small/packet/orange - name = "orange juice powder packet" - desc = "Contains 5u of powdered orange juice. Mix with 15u of water." - starting_reagents = list(/decl/material/liquid/nutriment/instantjuice/orange = 5) - -/obj/item/chems/food/condiment/small/packet/watermelon - name = "watermelon juice powder packet" - desc = "Contains 5u of powdered watermelon juice. Mix with 15u of water." - starting_reagents = list(/decl/material/liquid/nutriment/instantjuice/watermelon = 5) - -/obj/item/chems/food/condiment/small/packet/apple - name = "apple juice powder packet" - desc = "Contains 5u of powdered apple juice. Mix with 15u of water." - starting_reagents = list(/decl/material/liquid/nutriment/instantjuice/apple = 5) - -/obj/item/chems/food/condiment/small/packet/protein - name = "protein powder packet" - desc = "Contains 10u of powdered protein. Mix with 20u of water." - icon_state = "packet_medium" - starting_reagents = list(/decl/material/liquid/nutriment/protein = 10) - -/obj/item/chems/food/condiment/small/packet/crayon - name = "crayon powder packet" - desc = "Contains 10u of powdered crayon. Mix with 30u of water." - starting_reagents = list(/decl/material/pigment = 10) -/obj/item/chems/food/condiment/small/packet/crayon/red - starting_reagents = list(/decl/material/pigment/red = 10) -/obj/item/chems/food/condiment/small/packet/crayon/orange - starting_reagents = list(/decl/material/pigment/orange = 10) -/obj/item/chems/food/condiment/small/packet/crayon/yellow - starting_reagents = list(/decl/material/pigment/yellow = 10) -/obj/item/chems/food/condiment/small/packet/crayon/green - starting_reagents = list(/decl/material/pigment/green = 10) -/obj/item/chems/food/condiment/small/packet/crayon/blue - starting_reagents = list(/decl/material/pigment/blue = 10) -/obj/item/chems/food/condiment/small/packet/crayon/purple - starting_reagents = list(/decl/material/pigment/purple = 10) -/obj/item/chems/food/condiment/small/packet/crayon/grey - starting_reagents = list(/decl/material/pigment/grey = 10) -/obj/item/chems/food/condiment/small/packet/crayon/brown - starting_reagents = list(/decl/material/pigment/brown = 10) - -//End of MRE stuff. - -/obj/item/chems/food/condiment/flour - name = "flour sack" - desc = "A big bag of flour. Good for baking!" - icon = 'icons/obj/food.dmi' - icon_state = "flour" - item_state = "flour" - randpixel = 10 - starting_reagents = list(/decl/material/liquid/nutriment/flour = 50) - -/obj/item/chems/food/condiment/flour/on_reagent_change() - return - -/obj/item/chems/food/condiment/salt - name = "big bag of salt" - desc = "A nonsensically large bag of salt. Carefully refined from countless shifts." - icon = 'icons/obj/food.dmi' - icon_state = "salt" - item_state = "flour" - randpixel = 10 - volume = 500 - w_class = ITEM_SIZE_LARGE - starting_reagents = list(/decl/material/solid/mineral/sodiumchloride = 500) - -/obj/item/chems/food/condiment/salt/on_reagent_change() - return - -/obj/item/chems/food/condiment/mint - name = "mint essential oil" - desc = "A small bottle of the essential oil of some kind of mint plant." - icon = 'icons/obj/food.dmi' - icon_state = "coldsauce" - starting_reagents = list(/decl/material/liquid/drink/syrup/mint = 15) - -/obj/item/chems/food/condiment/mint/on_reagent_change() - return - -/obj/item/chems/food/condiment/soysauce - name = "soy sauce" - desc = "A dark, salty, savoury flavoring." - icon_state = "soysauce" - amount_per_transfer_from_this = 1 - volume = 20 - starting_reagents = list(/decl/material/liquid/nutriment/soysauce = 20) diff --git a/code/modules/reagents/reagent_containers/food/dairy/_dairy.dm b/code/modules/reagents/reagent_containers/food/dairy/_dairy.dm new file mode 100644 index 000000000000..4265d7079e22 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/dairy/_dairy.dm @@ -0,0 +1,33 @@ +/obj/item/food/dairy + abstract_type = /obj/item/food/dairy + nutriment_type = /decl/material/liquid/drink/milk + bitesize = 2 + icon_state = ICON_STATE_WORLD + var/data_name_field = DATA_MILK_NAME + var/data_color_field = DATA_MILK_COLOR + +/obj/item/food/dairy/proc/get_default_dairy_color() + return COLOR_WHITE + +/obj/item/food/dairy/proc/get_default_dairy_name() + return "milk" + +/obj/item/food/dairy/proc/set_dairy_name(milk_name) + SetName("[milk_name] [initial(name)]") + +/obj/item/food/dairy/on_reagent_change() + + . = ..() + + if(!REAGENT_TOTAL_VOLUME(reagents)) + return + + var/list/data = REAGENT_DATA(reagents, nutriment_type) + var/milk_name = LAZYACCESS(data, data_name_field) + if(milk_name) + set_dairy_name(milk_name) + set_color(LAZYACCESS(data, data_color_field) || get_default_dairy_color()) + else + set_dairy_name(get_default_dairy_name()) + set_color(get_default_dairy_color()) + filling_color = get_color() diff --git a/code/modules/reagents/reagent_containers/food/dairy/butter.dm b/code/modules/reagents/reagent_containers/food/dairy/butter.dm new file mode 100644 index 000000000000..af0a88b417b9 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/dairy/butter.dm @@ -0,0 +1,48 @@ +/obj/item/food/dairy/butter + abstract_type = /obj/item/food/dairy/butter + nutriment_type = /decl/material/liquid/nutriment/butter + color = "#ffe864" + nutriment_desc = list("butter" = 1) + +/obj/item/food/dairy/butter/get_default_dairy_color() + return "#ffe864" + +/obj/item/food/dairy/butter/get_default_dairy_name() + return "butter" + +/obj/item/food/dairy/butter/stick + name = "stick" + desc = "A stick of pure butterfat made from milk products." + icon = 'icons/obj/food/dairy/butter.dmi' + center_of_mass = @'{"x":16,"y":16}' + nutriment_amt = 20 + slice_path = /obj/item/food/dairy/butter/pat + slice_num = 5 + +/obj/item/food/dairy/butter/pat + name = "pat" + desc = "A small pat of butter, separated from some greater whole." + icon = 'icons/obj/food/dairy/butter_pat.dmi' + nutriment_amt = 1 + +// Mappable subtypes below. +/obj/item/food/dairy/butter/stick/margarine + desc = "A stick of emulsified plant oil, often used as a substitute for butter." + nutriment_type = /decl/material/liquid/nutriment/margarine + slice_path = /obj/item/food/dairy/butter/pat/margarine + color = "#f3f2be" + nutriment_desc = list("oil" = 1) + +/obj/item/food/dairy/butter/stick/margarine/get_nutriment_data() + . = ..() + LAZYSET(., data_name_field, "margarine") + LAZYSET(., data_color_field, "#f3f2be") + +/obj/item/food/dairy/butter/pat/margarine + desc = "A small pat of margarine, separated from some greater whole." + nutriment_desc = list("oil" = 1) + +/obj/item/food/dairy/butter/pat/margarine/get_nutriment_data() + . = ..() + LAZYSET(., data_name_field, "margarine") + LAZYSET(., data_color_field, "#f3f2be") diff --git a/code/modules/reagents/reagent_containers/food/dairy/cheeses.dm b/code/modules/reagents/reagent_containers/food/dairy/cheeses.dm new file mode 100644 index 000000000000..b6f7287382da --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/dairy/cheeses.dm @@ -0,0 +1,38 @@ +/obj/item/food/dairy/cheese + nutriment_type = /decl/material/liquid/nutriment/cheese + abstract_type = /obj/item/food/dairy/cheese + data_name_field = DATA_CHEESE_NAME + data_color_field = DATA_CHEESE_COLOR + +/obj/item/food/dairy/cheese/get_default_dairy_color() + return "#ffd000" + +/obj/item/food/dairy/cheese/get_default_dairy_name() + return "cheese" + +/obj/item/food/dairy/cheese/wedge + name = "wedge" + desc = "A wedge of delicious cheese. The cheese wheel it was cut from can't have gone far." + icon = 'icons/obj/food/dairy/cheese_wedge.dmi' + center_of_mass = @'{"x":16,"y":10}' + nutriment_amt = 5 + +/obj/item/food/dairy/cheese/wedge/slice + nutriment_amt = 0 + +/obj/item/food/dairy/cheese/wheel + name = "wheel" + desc = "A big wheel of delicious cheese." + icon = 'icons/obj/food/dairy/cheese_wheel.dmi' + slice_path = /obj/item/food/dairy/cheese/wedge/slice + slice_num = 5 + center_of_mass = @'{"x":16,"y":10}' + nutriment_amt = 20 + w_class = ITEM_SIZE_NORMAL + utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SLICE + +// Mappable subtypes below. +/obj/item/food/dairy/cheese/wheel/goat/get_nutriment_data() + . = ..() + LAZYSET(., data_name_field, "feta") + LAZYSET(., data_color_field, "#f3f2be") diff --git a/code/modules/reagents/reagent_containers/food/donkpocket.dm b/code/modules/reagents/reagent_containers/food/donkpocket.dm new file mode 100644 index 000000000000..55e9e809efee --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/donkpocket.dm @@ -0,0 +1,77 @@ +/obj/item/food/donkpocket + name = "cold donk-pocket" + desc = "The food of choice for the seasoned traitor." + icon = 'icons/obj/food/donkpocket.dmi' + filling_color = "#dedeab" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("heartiness" = 1, "dough" = 2) + nutriment_amt = 2 + var/warm = 0 + var/list/heated_reagents = list(/decl/material/liquid/regenerator = 5) + +/obj/item/food/donkpocket/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 2) + +/obj/item/food/donkpocket/grill(var/atom/heat_source) + + backyard_grilling_rawness-- + if(backyard_grilling_rawness <= 0) + backyard_grilling_rawness = initial(backyard_grilling_rawness) + + // We're already warm, so we burn. + if(warm) + var/obj/item/food/badrecipe/whoops = new + whoops.dropInto(loc) + visible_message(SPAN_DANGER("\The [src] chars and blackens!")) + qdel(src) + return whoops + + // Otherwise we just warm up. + heat() + visible_message(SPAN_NOTICE("\The [src] steams gently!")) + return src + +/obj/item/food/donkpocket/proc/heat() + if(warm) + return + warm = 1 + for(var/reagent in heated_reagents) + add_to_reagents(reagent, heated_reagents[reagent]) + bitesize = 6 + SetName("warm donk-pocket") + addtimer(CALLBACK(src, PROC_REF(cool)), 7 MINUTES) + +/obj/item/food/donkpocket/proc/cool() + if(!warm) + return + warm = 0 + for(var/reagent in heated_reagents) + reagents.clear_reagent(reagent) + SetName(initial(name)) + +/obj/item/food/donkpocket/sinpocket + name = "\improper Sin-pocket" + desc = "The food of choice for the veteran. Do NOT overconsume." + filling_color = "#6d6d00" + heated_reagents = list( + /decl/material/liquid/regenerator = 5, + /decl/material/liquid/amphetamines = 0.75, + /decl/material/liquid/accumulated/stimulants = 0.25 + ) + var/has_been_heated = 0 // Unlike the warm var, this checks if the one-time self-heating operation has been used. + +/obj/item/food/donkpocket/sinpocket/attack_self(mob/user) + if(has_been_heated) + to_chat(user, "The heating chemicals have already been spent.") + return + has_been_heated = 1 + user.visible_message("[user] crushes \the [src] package.", "You crush \the [src] package and feel a comfortable heat build up.") + addtimer(CALLBACK(src, PROC_REF(heat), weakref(user)), 20 SECONDS) + +/obj/item/food/donkpocket/sinpocket/heat(weakref/message_to) + ..() + if(message_to) + var/mob/user = message_to.resolve() + if(user) + to_chat(user, "You think \the [src] is ready to eat about now.") diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm deleted file mode 100644 index cc40bdc76732..000000000000 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ /dev/null @@ -1,339 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// Drinks. -//////////////////////////////////////////////////////////////////////////////// -/obj/item/chems/food/drinks - name = "drink" - desc = "Yummy!" - icon = 'icons/obj/drinks.dmi' - icon_state = null - atom_flags = ATOM_FLAG_OPEN_CONTAINER - amount_per_transfer_from_this = 5 - volume = 50 - - var/filling_states // List of percentages full that have icons - var/base_name = null // Name to put in front of drinks, i.e. "[base_name] of [contents]" - var/base_icon = null // Base icon name for fill states - -/obj/item/chems/food/drinks/Initialize() - . = ..() - base_name = name - -/obj/item/chems/food/drinks/get_base_name() - . = base_name - -/obj/item/chems/food/drinks/dragged_onto(var/mob/user) - attack_self(user) - -/obj/item/chems/food/drinks/attack_self(mob/user) - if(!ATOM_IS_OPEN_CONTAINER(src)) - open(user) - return - attack(user, user) - -/obj/item/chems/food/drinks/proc/open(mob/user) - playsound(loc,'sound/effects/canopen.ogg', rand(10,50), 1) - to_chat(user, SPAN_NOTICE("You open \the [src] with an audible pop!")) - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - -/obj/item/chems/food/drinks/attack(mob/M, mob/user, def_zone) - if(force && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.a_intent == I_HURT) - return ..() - if(standard_feed_mob(user, M)) - return - return 0 - -/obj/item/chems/food/drinks/afterattack(obj/target, mob/user, proximity) - if(!proximity) return - - if(standard_dispenser_refill(user, target)) - return - if(standard_pour_into(user, target)) - return - return ..() - -/obj/item/chems/food/drinks/standard_feed_mob(var/mob/user, var/mob/target) - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "You need to open \the [src]!") - return 1 - return ..() - -/obj/item/chems/food/drinks/standard_dispenser_refill(var/mob/user, var/obj/structure/reagent_dispensers/target) - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "You need to open \the [src]!") - return 1 - return ..() - -/obj/item/chems/food/drinks/standard_pour_into(var/mob/user, var/atom/target) - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "You need to open \the [src]!") - return 1 - return ..() - -/obj/item/chems/food/drinks/self_feed_message(var/mob/user) - to_chat(user, "You swallow a gulp from \the [src].") - if(user.has_personal_goal(/datum/goal/achievement/specific_object/drink)) - for(var/R in reagents.reagent_volumes) - user.update_personal_goal(/datum/goal/achievement/specific_object/drink, R) - -/obj/item/chems/food/drinks/feed_sound(var/mob/user) - playsound(user.loc, 'sound/items/drink.ogg', rand(10, 50), 1) - -/obj/item/chems/food/drinks/examine(mob/user, distance) - . = ..() - if(distance > 1) - return - if(!reagents || reagents.total_volume == 0) - to_chat(user, "\The [src] is empty!") - else if (reagents.total_volume <= volume * 0.25) - to_chat(user, "\The [src] is almost empty!") - else if (reagents.total_volume <= volume * 0.66) - to_chat(user, "\The [src] is half full!") - else if (reagents.total_volume <= volume * 0.90) - to_chat(user, "\The [src] is almost full!") - else - to_chat(user, "\The [src] is full!") - -/obj/item/chems/food/drinks/proc/get_filling_state() - var/percent = round((reagents.total_volume / volume) * 100) - for(var/k in cached_json_decode(filling_states)) - if(percent <= k) - return k - -/obj/item/chems/food/drinks/get_base_name() - . = base_name - -/obj/item/chems/food/drinks/on_reagent_change() - . = ..() - var/decl/material/R = reagents.get_primary_reagent_decl() - desc = R?.glass_desc || initial(desc) - -/obj/item/chems/food/drinks/on_update_icon() - overlays.Cut() - if(LAZYLEN(reagents.reagent_volumes)) - if(filling_states) - var/image/filling = image(icon, src, "[base_icon][get_filling_state()]") - filling.color = reagents.get_color() - overlays += filling - else - SetName(initial(name)) - desc = initial(desc) - - -//////////////////////////////////////////////////////////////////////////////// -/// Drinks. END -//////////////////////////////////////////////////////////////////////////////// - -/obj/item/chems/food/drinks/golden_cup - desc = "A golden cup." - name = "golden cup" - icon_state = "golden_cup" - item_state = "" //nope :( - w_class = ITEM_SIZE_HUGE - force = 14 - throwforce = 10 - amount_per_transfer_from_this = 20 - possible_transfer_amounts = null - volume = 150 - atom_flags = ATOM_FLAG_OPEN_CONTAINER - obj_flags = OBJ_FLAG_CONDUCTIBLE - -///////////////////////////////////////////////Drinks -//Notes by Darem: Drinks are simply containers that start preloaded. Unlike condiments, the contents can be ingested directly -// rather then having to add it to something else first. They should only contain liquids. They have a default container size of 50. -// Formatting is the same as food. - -/obj/item/chems/food/drinks/milk - name = "milk carton" - desc = "It's milk. White and nutritious goodness!" - icon_state = "milk" - item_state = "carton" - center_of_mass = @"{'x':16,'y':9}" - -/obj/item/chems/food/drinks/milk/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk, 50) - -/obj/item/chems/food/drinks/soymilk - name = "soymilk carton" - desc = "It's soy milk. White and nutritious goodness!" - icon_state = "soymilk" - item_state = "carton" - center_of_mass = @"{'x':16,'y':9}" - -/obj/item/chems/food/drinks/soymilk/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk/soymilk, 50) - -/obj/item/chems/food/drinks/milk/smallcarton - name = "small milk carton" - volume = 30 - icon_state = "mini-milk" - -/obj/item/chems/food/drinks/milk/smallcarton/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk, 30) - -/obj/item/chems/food/drinks/milk/smallcarton/chocolate - name = "small chocolate milk carton" - desc = "It's milk! This one is in delicious chocolate flavour." - -/obj/item/chems/food/drinks/milk/smallcarton/chocolate/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk/chocolate, 30) - - -/obj/item/chems/food/drinks/coffee - name = "\improper Robust Coffee" - desc = "Careful, the beverage you're about to enjoy is extremely hot." - icon_state = "coffee" - center_of_mass = @"{'x':15,'y':10}" - -/obj/item/chems/food/drinks/coffee/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/coffee, 30) - -/obj/item/chems/food/drinks/ice - name = "cup of ice" - desc = "Careful, cold ice, do not chew." - icon_state = "coffee" - center_of_mass = @"{'x':15,'y':10}" - -/obj/item/chems/food/drinks/ice/Initialize() - . = ..() - reagents.add_reagent(/decl/material/solid/ice, 30) - -/obj/item/chems/food/drinks/h_chocolate - name = "cup of hot cocoa" - desc = "A tall plastic cup of creamy hot chocolate." - icon_state = "coffee" - item_state = "coffee" - center_of_mass = @"{'x':15,'y':13}" - -/obj/item/chems/food/drinks/h_chocolate/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/hot_coco, 30) - -/obj/item/chems/food/drinks/dry_ramen - name = "cup ramen" - gender = PLURAL - desc = "Just add 10ml water, self heats! A taste that reminds you of your school years." - icon_state = "ramen" - center_of_mass = @"{'x':16,'y':11}" - -/obj/item/chems/food/drinks/dry_ramen/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/dry_ramen, 30) - - -/obj/item/chems/food/drinks/sillycup - name = "paper cup" - desc = "A paper water cup." - icon_state = "water_cup_e" - possible_transfer_amounts = null - volume = 10 - center_of_mass = @"{'x':16,'y':12}" - -/obj/item/chems/food/drinks/sillycup/on_update_icon() - . = ..() - if(reagents.total_volume) - icon_state = "water_cup" - else - icon_state = "water_cup_e" - - -//////////////////////////pitchers, pots, flasks and cups // -//Note by Darem: This code handles the mixing of drinks. New drinks go in three places: In Chemistry-Reagents.dm (for the drink -// itself), in Chemistry-Recipes.dm (for the reaction that changes the components into the drink), and here (for the drinking glass -// icon states. - -/obj/item/chems/food/drinks/teapot - name = "teapot" - desc = "An elegant teapot. It simply oozes class." - icon_state = "teapot" - item_state = "teapot" - amount_per_transfer_from_this = 10 - volume = 120 - center_of_mass = @"{'x':17,'y':7}" - -/obj/item/chems/food/drinks/pitcher - name = "insulated pitcher" - desc = "A stainless steel insulated pitcher. Everyone's best friend in the morning." - icon_state = "pitcher" - volume = 120 - amount_per_transfer_from_this = 10 - center_of_mass = @"{'x':16,'y':9}" - filling_states = @"[15,30,50,70,85,100]" - base_icon = "pitcher" - -/obj/item/chems/food/drinks/flask - name = "\improper Captain's flask" - desc = "A metal flask belonging to the captain." - icon_state = "flask" - volume = 60 - center_of_mass = @"{'x':17,'y':7}" - -/obj/item/chems/food/drinks/flask/shiny - name = "shiny flask" - desc = "A shiny metal flask. It appears to have a Greek symbol inscribed on it." - icon_state = "shinyflask" - -/obj/item/chems/food/drinks/flask/lithium - name = "lithium flask" - desc = "A flask with a Lithium Atom symbol on it." - icon_state = "lithiumflask" - -/obj/item/chems/food/drinks/flask/detflask - name = "\improper Detective's flask" - desc = "A metal flask with a leather band and golden badge belonging to the detective." - icon_state = "detflask" - volume = 60 - center_of_mass = @"{'x':17,'y':8}" - -/obj/item/chems/food/drinks/flask/barflask - name = "flask" - desc = "For those who can't be bothered to hang out at the bar to drink." - icon_state = "barflask" - volume = 60 - center_of_mass = @"{'x':17,'y':7}" - -/obj/item/chems/food/drinks/flask/vacuumflask - name = "vacuum flask" - desc = "Keeping your drinks at the perfect temperature since 1892." - icon_state = "vacuumflask" - volume = 60 - center_of_mass = @"{'x':15,'y':4}" - -//tea and tea accessories -/obj/item/chems/food/drinks/tea - name = "cup of tea master item" - desc = "A tall plastic cup full of the concept and ideal of tea." - icon_state = "coffee" - item_state = "coffee" - center_of_mass = @"{'x':16,'y':14}" - filling_states = @"[100]" - base_name = "cup" - base_icon = "cup" - -/obj/item/chems/food/drinks/tea/black - name = "cup of black tea" - desc = "A tall plastic cup of hot black tea." - -/obj/item/chems/food/drinks/tea/black/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/tea/black, 30) - -/obj/item/chems/food/drinks/tea/green - name = "cup of green tea" - desc = "A tall plastic cup of hot green tea." - -/obj/item/chems/food/drinks/tea/green/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/tea/green, 30) - -/obj/item/chems/food/drinks/tea/chai - name = "cup of chai tea" - desc = "A tall plastic cup of hot chai tea." - -/obj/item/chems/food/drinks/tea/chai/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/tea/chai, 30) diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm deleted file mode 100644 index 0b577e318d97..000000000000 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ /dev/null @@ -1,596 +0,0 @@ -///////////////////////////////////////////////Alchohol bottles! -Agouri ////////////////////////// -//Functionally identical to regular drinks. The only difference is that the default bottle size is 100. - Darem -//Bottles now weaken and break when smashed on people's heads. - Giacom - -/obj/item/chems/food/drinks/bottle - amount_per_transfer_from_this = 10 - volume = 100 - item_state = "broken_beer" //Generic held-item sprite until unique ones are made. - force = 5 - - var/smash_duration = 5 //Directly relates to the 'weaken' duration. Lowered by armor (i.e. helmets) - var/isGlass = TRUE //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it - var/obj/item/chems/glass/rag/rag = null - var/rag_underlay = "rag" - var/stop_spin_bottle = FALSE //Gotta stop the rotation. - -/obj/item/chems/food/drinks/bottle/Initialize() - . = ..() - if(isGlass) - unacidable = TRUE - else - verbs -= .verb/spin_bottle - -/obj/item/chems/food/drinks/bottle/Destroy() - if(!QDELETED(rag)) - rag.dropInto(loc) - rag = null - return ..() - -//when thrown on impact, bottles smash and spill their contents -/obj/item/chems/food/drinks/bottle/throw_impact(atom/hit_atom, var/datum/thrownthing/TT) - ..() - if(isGlass && TT.thrower && TT.thrower.a_intent != I_HELP) - if(TT.speed > throw_speed || smash_check(TT.dist_travelled)) //not as reliable as smashing directly - if(reagents) - hit_atom.visible_message(SPAN_NOTICE("The contents of \the [src] splash all over \the [hit_atom]!")) - reagents.splash(hit_atom, reagents.total_volume) - smash(loc, hit_atom) - -/obj/item/chems/food/drinks/bottle/proc/smash_check(var/distance) - if(!isGlass) - return 0 - if(rag && rag.on_fire) // Molotovs should be somewhat reliable, they're a pain to make. - return TRUE - if(!smash_duration) - return 0 - var/list/chance_table = list(95, 95, 90, 85, 75, 60, 40, 15) //starting from distance 0 - var/idx = max(distance + 1, 1) //since list indices start at 1 - if(idx > chance_table.len) - return 0 - return prob(chance_table[idx]) - -/obj/item/chems/food/drinks/bottle/proc/smash(var/newloc, atom/against = null) - //Creates a shattering noise and replaces the bottle with a broken_bottle - var/obj/item/broken_bottle/B = new(newloc) - if(prob(33)) - new/obj/item/shard(newloc) // Create a glass shard at the target's location! - B.icon_state = src.icon_state - var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) - I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) - I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) - B.icon = I - B.dropInto(newloc) - - // Propagate our fire source down to the lowest level we can. - // Ignite any fuel or mobs we have spilled. TODO: generalize to - // flame sources when traversing open space. - if(rag) - var/turf/T = get_turf(newloc) - if(istype(T)) - while(T) - rag.forceMove(T) - if(rag.on_fire) - T.hotspot_expose(700, 5) - for(var/mob/living/M in T.contents) - M.IgniteMob() - if(HasBelow(T.z) && istype(T, /turf/simulated/open)) - T = GetBelow(T) - else - T = null - rag.dropInto(rag.loc) - else - rag.dropInto(newloc) - rag = null - - playsound(src, "shatter", 70, 1) - src.transfer_fingerprints_to(B) - - qdel(src) - return B - -/obj/item/chems/food/drinks/bottle/attackby(obj/item/W, mob/user) - if(!rag && istype(W, /obj/item/chems/glass/rag)) - insert_rag(W, user) - return - if(rag && W.isflamesource()) - rag.attackby(W, user) - return - ..() - -/obj/item/chems/food/drinks/bottle/attack_self(mob/user) - if(rag) - remove_rag(user) - else - ..() - -/obj/item/chems/food/drinks/bottle/proc/insert_rag(obj/item/chems/glass/rag/R, mob/user) - if(!isGlass || rag) return - - if(user.unEquip(R)) - to_chat(user, SPAN_NOTICE("You stuff [R] into [src].")) - rag = R - rag.forceMove(src) - - // Equalize reagents between the rag and bottle so that - // the rag will probably have something to burn, and the - // bottle contents will be tainted by having the rag dipped - // in it. - if(rag && rag.reagents) - rag.reagents.trans_to(src, rag.reagents.total_volume) - if(reagents) - reagents.trans_to(rag, min(reagents.total_volume, rag.reagents.maximum_volume)) - rag.update_name() - - atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER - update_icon() - -/obj/item/chems/food/drinks/bottle/proc/remove_rag(mob/user) - if(!rag) return - user.put_in_hands(rag) - rag = null - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - update_icon() - -/obj/item/chems/food/drinks/bottle/open(mob/user) - if(rag) return - ..() - -/obj/item/chems/food/drinks/bottle/on_update_icon() - underlays.Cut() - if(rag) - var/underlay_image = image(icon='icons/obj/drinks.dmi', icon_state=rag.on_fire? "[rag_underlay]_lit" : rag_underlay) - underlays += underlay_image - set_light(rag.light_max_bright, 0.1, rag.light_outer_range, 2, rag.light_color) - else - set_light(0) - -/obj/item/chems/food/drinks/bottle/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - . = ..() - - if(user.a_intent != I_HURT) - return - if(!smash_check(1)) - return //won't always break on the first hit - - var/mob/living/carbon/human/H = target - if(istype(H) && H.headcheck(hit_zone)) - var/obj/item/organ/affecting = H.get_organ(hit_zone) //headcheck should ensure that affecting is not null - user.visible_message(SPAN_DANGER("\The [user] smashes \the [src] into [H]'s [affecting.name]!")) - // You are going to knock someone out for longer if they are not wearing a helmet. - var/blocked = target.get_blocked_ratio(hit_zone, BRUTE, damage = 10) * 100 - var/weaken_duration = smash_duration + min(0, force - blocked + 10) - if(weaken_duration) - target.apply_effect(min(weaken_duration, 5), WEAKEN, blocked) // Never weaken more than a flash! - else - user.visible_message(SPAN_DANGER("\The [user] smashes \the [src] into [target]!")) - - //The reagents in the bottle splash all over the target, thanks for the idea Nodrak - if(reagents) - user.visible_message(SPAN_NOTICE("The contents of \the [src] splash all over [target]!")) - reagents.splash(target, reagents.total_volume) - if(rag && rag.on_fire && istype(target)) - target.IgniteMob() - - //Finally, smash the bottle. This kills (qdel) the bottle. - var/obj/item/broken_bottle/B = smash(target.loc, target) - user.put_in_active_hand(B) - -/obj/item/chems/food/drinks/bottle/verb/spin_bottle() - set name = "Spin Bottle" - set category = "Object" - set src in view(1) - - if(!ishuman(usr) || usr.incapacitated()) - return - - if(!stop_spin_bottle) - if(usr.get_active_hand() == src || usr.get_inactive_hand() == src) - usr.drop_from_inventory(src) - - if(isturf(loc)) - var/speed = rand(1, 3) - var/loops - var/sleep_not_stacking - switch(speed) //At a low speed, the bottle should not make 10 loops - if(3) - loops = rand(7, 10) - sleep_not_stacking = 40 - if(1 to 2) - loops = rand(10, 15) - sleep_not_stacking = 25 - - stop_spin_bottle = TRUE - SpinAnimation(speed, loops, pick(0, 1)) //SpinAnimation(speed, loops, clockwise, segments) - transform = turn(matrix(), dir2angle(pick(GLOB.alldirs))) - sleep(sleep_not_stacking) //Not stacking - stop_spin_bottle = FALSE - -/obj/item/chems/food/drinks/bottle/pickup(mob/living/user) - animate(src, transform = null, time = 0) //Restore bottle to its original position - -//Keeping this here for now, I'll ask if I should keep it here. -/obj/item/broken_bottle - name = "broken bottle" - desc = "A bottle with a sharp broken bottom." - icon = 'icons/obj/drinks.dmi' - icon_state = "broken_bottle" - force = 9 - throwforce = 5 - throw_speed = 3 - throw_range = 5 - item_state = "beer" - attack_verb = list("stabbed", "slashed", "attacked") - sharp = 1 - edge = 0 - var/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken") - -/obj/item/broken_bottle/attack(mob/living/carbon/M, mob/living/carbon/user) - playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) - return ..() - -/obj/item/chems/food/drinks/bottle/gin - name = "Griffeater Gin" - desc = "A bottle of high quality gin, produced in the New London Space Station." - icon_state = "ginbottle" - center_of_mass = @"{'x':16,'y':4}" - -/obj/item/chems/food/drinks/bottle/gin/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/gin, 100) - -/obj/item/chems/food/drinks/bottle/whiskey - name = "Uncle Git's Special Reserve" - desc = "A premium single-malt whiskey, gently matured inside the tunnels of a nuclear shelter. TUNNEL WHISKEY RULES." - icon_state = "whiskeybottle" - center_of_mass = @"{'x':16,'y':3}" - -/obj/item/chems/food/drinks/bottle/whiskey/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/whiskey, 100) - -/obj/item/chems/food/drinks/bottle/agedwhiskey - name = "aged whiskey" - desc = "This rich, smooth, hideously expensive beverage was aged for decades." - icon_state = "whiskeybottle2" - center_of_mass = @"{'x':16,'y':3}" - -/obj/item/chems/food/drinks/bottle/agedwhiskey/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/aged_whiskey, 100) - -/obj/item/chems/food/drinks/bottle/vodka - name = "Tunguska Triple Distilled" - desc = "Aah, vodka. Prime choice of drink AND fuel by Indies around the galaxy." - icon_state = "vodkabottle" - center_of_mass = @"{'x':17,'y':3}" - -/obj/item/chems/food/drinks/bottle/vodka/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/vodka, 100) - -/obj/item/chems/food/drinks/bottle/tequilla - name = "Caccavo Guaranteed Quality Tequilla" - desc = "Made from premium petroleum distillates, pure thalidomide and other fine quality ingredients!" - icon_state = "tequillabottle" - center_of_mass = @"{'x':16,'y':3}" - -/obj/item/chems/food/drinks/bottle/tequilla/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/tequilla, 100) - -/obj/item/chems/food/drinks/bottle/patron - name = "Wrapp Artiste Patron" - desc = "Silver laced tequilla, served in space night clubs across the galaxy." - icon_state = "patronbottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/patron/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/tequilla, 95) - reagents.add_reagent(/decl/material/solid/metal/silver, 5) - -/obj/item/chems/food/drinks/bottle/rum - name = "Captain Pete's Cuban Spiced Rum" - desc = "This isn't just rum, oh no. It's practically GRIFF in a bottle." - icon_state = "rumbottle" - center_of_mass = @"{'x':16,'y':8}" - -/obj/item/chems/food/drinks/bottle/rum/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/rum, 100) - -/obj/item/chems/food/drinks/bottle/holywater - name = "Flask of Holy Water" - desc = "A flask of the chaplain's holy water." - icon_state = "holyflask" - center_of_mass = @"{'x':17,'y':10}" - -/obj/item/chems/food/drinks/bottle/holywater/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/water, 100, list("holy" = TRUE)) - -/obj/item/chems/food/drinks/bottle/vermouth - name = "Goldeneye Vermouth" - desc = "Sweet, sweet dryness~" - icon_state = "vermouthbottle" - center_of_mass = @"{'x':17,'y':3}" - -/obj/item/chems/food/drinks/bottle/vermouth/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/vermouth, 100) - -/obj/item/chems/food/drinks/bottle/kahlua - name = "Robert Robust's Coffee Liqueur" - desc = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936, HONK!" - icon_state = "kahluabottle" - center_of_mass = @"{'x':17,'y':3}" - -/obj/item/chems/food/drinks/bottle/kahlua/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/coffee/kahlua, 100) - -/obj/item/chems/food/drinks/bottle/goldschlager - name = "College Girl Goldschlager" - desc = "Because they are the only ones who will drink 100 proof cinnamon schnapps." - icon_state = "goldschlagerbottle" - center_of_mass = @"{'x':15,'y':3}" - -/obj/item/chems/food/drinks/bottle/goldschlager/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/vodka, 95) - reagents.add_reagent(/decl/material/solid/metal/gold, 5) - -/obj/item/chems/food/drinks/bottle/cognac - name = "Chateau De Baton Premium Cognac" - desc = "A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. You might as well not scream 'SHITCURITY' this time." - icon_state = "cognacbottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/cognac/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/cognac, 100) - -/obj/item/chems/food/drinks/bottle/wine - name = "Doublebeard Bearded Special Wine" - desc = "A faint aura of unease and asspainery surrounds the bottle." - icon_state = "winebottle" - center_of_mass = @"{'x':16,'y':4}" - -/obj/item/chems/food/drinks/bottle/wine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/wine, 100) - -/obj/item/chems/food/drinks/bottle/absinthe - name = "Jailbreaker Verte" - desc = "One sip of this and you just know you're gonna have a good time." - icon_state = "absinthebottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/absinthe/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/absinthe, 100) - -/obj/item/chems/food/drinks/bottle/melonliquor - name = "Emeraldine Melon Liquor" - desc = "A bottle of 46 proof Emeraldine Melon Liquor. Sweet and light." - icon_state = "alco-green" //Placeholder. - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/melonliquor/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/melonliquor, 100) - -/obj/item/chems/food/drinks/bottle/bluecuracao - name = "Miss Blue Curacao" - desc = "A fruity, exceptionally azure drink. Does not allow the imbiber to use the fifth magic." - icon_state = "alco-blue" //Placeholder. - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/bluecuracao/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/bluecuracao, 100) - -/obj/item/chems/food/drinks/bottle/herbal - name = "Liqueur d'Herbe" - desc = "A bottle of the seventh-finest herbal liquor sold under a generic name in the galaxy. The back label has a load of guff about the monks who traditionally made this particular variety." - icon_state = "herbal" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/herbal/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/herbal, 100) - -/obj/item/chems/food/drinks/bottle/grenadine - name = "Briar Rose Grenadine Syrup" - desc = "Sweet and tangy, a bar syrup used to add color or flavor to drinks." - icon_state = "grenadinebottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/grenadine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/grenadine, 100) - -/obj/item/chems/food/drinks/bottle/cola - name = "\improper Space Cola" - desc = "Cola. in space." - icon_state = "colabottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/cola/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/cola, 100) - -/obj/item/chems/food/drinks/bottle/space_up - name = "\improper Space-Up" - desc = "Tastes like a hull breach in your mouth." - icon_state = "space-up_bottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/space_up/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/lemonade, 100) - -/obj/item/chems/food/drinks/bottle/space_mountain_wind - name = "\improper Space Mountain Wind" - desc = "Blows right through you like a space wind." - icon_state = "space_mountain_wind_bottle" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/space_mountain_wind/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/citrussoda, 100) - -/obj/item/chems/food/drinks/bottle/pwine - name = "Warlock's Velvet" - desc = "What a delightful packaging for a surely high quality wine! The vintage must be amazing!" - icon_state = "pwinebottle" - center_of_mass = @"{'x':16,'y':4}" - -/obj/item/chems/food/drinks/bottle/pwine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/pwine, 100) - -/obj/item/chems/food/drinks/bottle/sake - name = "Takeo Sadow's Combined Sake" - desc = "A bottle of the highest-grade sake allowed for import." - icon_state = "sake" - center_of_mass = @"{'x':16,'y':4}" - -/obj/item/chems/food/drinks/bottle/sake/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/ethanol/sake, 100) - -/obj/item/chems/food/drinks/bottle/champagne - name = "Murcelano Vinyard's Premium Champagne" - desc = "The regal drink of celebrities and royalty." - icon_state = "champagne" - center_of_mass = @"{'x':16,'y':4}" - -/obj/item/chems/food/drinks/bottle/champagne/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/ethanol/champagne, 100) - -/obj/item/chems/food/drinks/bottle/jagermeister - name = "Kaisermeister Deluxe" - desc = "Jagermeister. This drink just demands a party." - icon_state = "herbal" - center_of_mass = @"{'x':16,'y':6}" - -/obj/item/chems/food/drinks/bottle/jagermeister/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/ethanol/jagermeister, 100) - -//////////////////////////PREMIUM ALCOHOL /////////////////////// -/obj/item/chems/food/drinks/bottle/premiumvodka - name = "Four Stripes Quadruple Distilled" - desc = "Premium distilled vodka imported directly from the Gilgamesh Colonial Confederation." - icon_state = "premiumvodka" - center_of_mass = @"{'x':17,'y':3}" - -/obj/item/chems/food/drinks/bottle/premiumvodka/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/vodka/premium, 100) - var/namepick = pick("Four Stripes","Gilgamesh","Novaya Zemlya","Indie","STS-35") - var/typepick = pick("Absolut","Gold","Quadruple Distilled","Platinum","Standard") - name = "[namepick] [typepick]" - -/obj/item/chems/food/drinks/bottle/premiumwine - name = "Uve De Blanc" - desc = "You feel pretentious just looking at it." - icon_state = "premiumwine" - center_of_mass = @"{'x':16,'y':4}" - -/obj/item/chems/food/drinks/bottle/premiumwine/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/wine/premium, 100) - var/namepick = pick("Calumont","Sciacchemont","Recioto","Torcalota") - var/agedyear = rand(game_year-150,game_year) - name = "Chateau [namepick] De Blanc" - desc += " This bottle is marked as [agedyear] Vintage." - -//////////////////////////JUICES AND STUFF /////////////////////// - -/obj/item/chems/food/drinks/bottle/orangejuice - name = "Orange Juice" - desc = "Full of vitamins and deliciousness!" - icon_state = "orangejuice" - item_state = "carton" - center_of_mass = @"{'x':16,'y':7}" - isGlass = 0 - -/obj/item/chems/food/drinks/bottle/orangejuice/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/orange, 100) - -/obj/item/chems/food/drinks/bottle/cream - name = "Milk Cream" - desc = "It's cream. Made from milk. What else did you think you'd find in there?" - icon_state = "cream" - item_state = "carton" - center_of_mass = @"{'x':16,'y':8}" - isGlass = 0 - -/obj/item/chems/food/drinks/bottle/cream/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk/cream, 100) - -/obj/item/chems/food/drinks/bottle/tomatojuice - name = "Tomato Juice" - desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness." - icon_state = "tomatojuice" - item_state = "carton" - center_of_mass = @"{'x':16,'y':8}" - isGlass = 0 - -/obj/item/chems/food/drinks/bottle/tomatojuice/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 100) - -/obj/item/chems/food/drinks/bottle/limejuice - name = "Lime Juice" - desc = "Sweet-sour goodness." - icon_state = "limejuice" - item_state = "carton" - center_of_mass = @"{'x':16,'y':8}" - isGlass = 0 - -/obj/item/chems/food/drinks/bottle/limejuice/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/lime, 100) - -//Small bottles -/obj/item/chems/food/drinks/bottle/small - volume = 50 - smash_duration = 1 - atom_flags = 0 //starts closed - rag_underlay = "rag_small" - -/obj/item/chems/food/drinks/bottle/small/beer - name = "space beer" - desc = "Contains only water, malt and hops." - icon_state = "beer" - center_of_mass = @"{'x':16,'y':12}" -/obj/item/chems/food/drinks/bottle/small/beer/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/beer, 30) - -/obj/item/chems/food/drinks/bottle/small/ale - name = "\improper Magm-Ale" - desc = "A true dorf's drink of choice." - icon_state = "alebottle" - item_state = "beer" - center_of_mass = @"{'x':16,'y':10}" -/obj/item/chems/food/drinks/bottle/small/ale/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/ethanol/ale, 30) - -/obj/item/chems/food/drinks/bottle/small/gingerbeer - name = "Ginger Beer" - desc = "A delicious non-alcoholic beverage enjoyed across Sol space." - icon_state = "gingerbeer" - center_of_mass = @"{'x':16,'y':12}" - -/obj/item/chems/food/drinks/bottle/small/gingerbeer/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/gingerbeer, 50) diff --git a/code/modules/reagents/reagent_containers/food/drinks/jar.dm b/code/modules/reagents/reagent_containers/food/drinks/jar.dm deleted file mode 100644 index 1e799b41c62f..000000000000 --- a/code/modules/reagents/reagent_containers/food/drinks/jar.dm +++ /dev/null @@ -1,21 +0,0 @@ - - -///jar - -/obj/item/chems/food/drinks/jar - name = "empty jar" - desc = "A jar. You're not sure what it's supposed to hold." - icon_state = "jar" - item_state = "beaker" - center_of_mass = @"{'x':15,'y':8}" - unacidable = 1 - -/obj/item/chems/food/drinks/jar/on_reagent_change() - if(LAZYLEN(reagents.reagent_volumes)) - icon_state ="jar_what" - SetName("jar of something") - desc = "You can't really tell what this is." - else - icon_state = initial(icon_state) - SetName(initial(name)) - desc = "A jar. You're not sure what it's supposed to hold." diff --git a/code/modules/reagents/reagent_containers/food/drinks/juicebox.dm b/code/modules/reagents/reagent_containers/food/drinks/juicebox.dm deleted file mode 100644 index 5e462cdb4316..000000000000 --- a/code/modules/reagents/reagent_containers/food/drinks/juicebox.dm +++ /dev/null @@ -1,118 +0,0 @@ -/obj/item/chems/food/drinks/juicebox - icon = 'icons/obj/juicebox.dmi' - icon_state = "juicebox_base" - name = "juicebox" - desc = "A small cardboard juicebox. Cheap and flimsy." - volume = 30 - amount_per_transfer_from_this = 5 - atom_flags = 0 - material = /decl/material/solid/cardboard - - color = "#ff0000" - var/primary_color = "#ff0000" - var/secondary_color = null - var/logo_color = "#ff00000" - var/box_style = "basic" - -/obj/item/chems/food/drinks/juicebox/proc/set_colors( - primary, - secondary=null, - logo=null, - style="basic" -) - primary_color = primary - secondary_color = secondary - logo_color = logo - box_style = style - update_icon() - -/obj/item/chems/food/drinks/juicebox/on_update_icon() - var/mutable_appearance/new_appearance = new(src) - new_appearance.appearance_flags = RESET_COLOR - new_appearance.color = primary_color - - if (secondary_color) - var/image/secondary = overlay_image(icon, "juicebox_[box_style]", secondary_color, RESET_COLOR) - new_appearance.overlays += secondary - - var/borderStyle = logo_color == null ? "border" : "border_icon" - var/border = overlay_image(icon, "juicebox_[box_style]_[borderStyle]", null, RESET_COLOR) - new_appearance.overlays += border - - if (logo_color) - var/image/logo = overlay_image(icon, "juicebox_[box_style]_icon", logo_color, RESET_COLOR) - new_appearance.overlays += logo - - var/open = (atom_flags & ATOM_FLAG_OPEN_CONTAINER) ? "open" : "close" - var/image/straw = overlay_image(icon, "juicebox_[open]", null, RESET_COLOR) - new_appearance.overlays += straw - - appearance = new_appearance - -/obj/item/chems/food/drinks/juicebox/examine(mob/user, distance) - . = ..() - if(atom_flags & ATOM_FLAG_OPEN_CONTAINER) - to_chat(user, SPAN_NOTICE("It has a straw stuck through the foil seal on top.")) - else - to_chat(user, SPAN_NOTICE("It has a straw stuck to the side and the foil seal is intact.")) - -/obj/item/chems/food/drinks/juicebox/open(mob/user) - playsound(loc,'sound/effects/bonebreak1.ogg', rand(10,50), 1) - to_chat(user, SPAN_NOTICE("You pull off the straw and stab it into \the [src], perforating the foil!")) - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - update_icon() - -/obj/item/chems/food/drinks/juicebox/apple - name = "apple juicebox" - desc = "A small cardboard juicebox with a cartoon apple on it." - -/obj/item/chems/food/drinks/juicebox/apple/Initialize() - . = ..() - set_colors("#ff0000", "#ffff00", "#ff0000", style="stripe") - reagents.add_reagent(/decl/material/liquid/drink/juice/apple, 25) - -/obj/item/chems/food/drinks/juicebox/orange - name = "orange juicebox" - desc = "A small cardboard juicebox with a cartoon orange on it." - -/obj/item/chems/food/drinks/juicebox/orange/Initialize() - . = ..() - set_colors("#ffff00", "#ff0000", "#ffff00", style="stripe") - reagents.add_reagent(/decl/material/liquid/drink/juice/orange, 25) - -/obj/item/chems/food/drinks/juicebox/grape - name = "grape juicebox" - desc = "A small cardboard juicebox with some cartoon grapes on it." - -/obj/item/chems/food/drinks/juicebox/grape/Initialize() - . = ..() - set_colors("#ff00ff", "#00ff00", style="stripe") - reagents.add_reagent(/decl/material/liquid/drink/juice/grape, 25) - -/obj/item/chems/food/drinks/juicebox/random/Initialize() - . = ..() - var/primary = get_random_colour() - var/secondary = pick(4;get_random_colour(), 1;null) - var/logo = pick(4;get_random_colour(), 1;null) - set_colors(primary, secondary, logo, style=pick(list("basic", "stripe", "corner"))) - -/obj/item/chems/food/drinks/juicebox/sensible_random - name = "Random Juicebox" - desc = "Juice in a box; who knows what flavor!" - -/obj/item/chems/food/drinks/juicebox/sensible_random/proc/juice_it() - var/drinktypes = subtypesof(/decl/material/liquid/drink/juice) - var/decl/material/J = pick(drinktypes) - reagents.add_reagent(J, 20) - reagents.add_reagent(pick(drinktypes - J), 5) - return reagents.reagent_volumes - -/obj/item/chems/food/drinks/juicebox/sensible_random/Initialize() - . = ..() - var/list/chosen_reagents = juice_it() - var/decl/material/J = decls_repository.get_decl(chosen_reagents[1]) - var/decl/material/K = decls_repository.get_decl(chosen_reagents[2]) - var/splash = pick("teasing", "splash", "hint", "measure", "nip", "slug", "depth", "dash", "sensation", "surge", "squirt", "spritz", "efflux", "gush", "swell") - desc = "[J.liquid_name]; [J.lore_text] This one comes with \an [splash] of [K.liquid_name] in a neat box." - name = "\improper [J.liquid_name] and [K.liquid_name] juicebox" - set_colors(J.color, K.color, get_random_colour(simple=TRUE), style=pick(list("stripe", "corner"))) diff --git a/code/modules/reagents/reagent_containers/food/eggs.dm b/code/modules/reagents/reagent_containers/food/eggs.dm new file mode 100644 index 000000000000..a5a762da21bd --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/eggs.dm @@ -0,0 +1,132 @@ +////////// +// Eggs // +////////// + +/obj/item/food/egg + name = "egg" + desc = "An egg!" + icon = 'icons/obj/food/eggs/egg.dmi' + icon_state = ICON_STATE_WORLD + filling_color = "#fdffd1" + chem_volume = 10 + center_of_mass = @'{"x":16,"y":13}' + material = /decl/material/solid/organic/bone/eggshell + obj_flags = OBJ_FLAG_HOLLOW + nutriment_amt = 3 + nutriment_type = /decl/material/solid/organic/meat/egg + +/obj/item/food/egg/afterattack(obj/O, mob/user, proximity) + // Don't crack eggs into appliances if you're on help intent. + if(istype(O,/obj/machinery/microwave)) + return ..() + if(!(proximity && ATOM_IS_OPEN_CONTAINER(O))) // Must be adjacent and open. + return + to_chat(user, "You crack \the [src] into \the [O].") + reagents.trans_to(O, REAGENT_TOTAL_VOLUME(reagents)) + qdel(src) + +/obj/item/food/egg/throw_impact(atom/hit_atom) + ..() + if(QDELETED(src)) + return // Could potentially happen with unscupulous atoms on hitby() throwing again, etc. + new/obj/effect/decal/cleanable/egg_smudge(src.loc) + reagents.splash(hit_atom, REAGENT_TOTAL_VOLUME(reagents)) + visible_message("\The [src] has been squashed!","You hear a smack.") + qdel(src) + +/obj/item/food/egg/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) + var/clr = used_item.get_tool_property(TOOL_PEN, TOOL_PROP_COLOR_NAME) + + if(!(clr in list("blue","green","mime","orange","purple","rainbow","red","yellow"))) + to_chat(user, SPAN_WARNING("The egg refuses to take on this color!")) + return TRUE + + to_chat(user, SPAN_NOTICE("You color \the [src] [clr]")) + icon_state = "egg-[clr]" + return TRUE + return ..() + +/obj/item/food/egg/blue + icon = 'icons/obj/food/eggs/egg_blue.dmi' + +/obj/item/food/egg/green + icon = 'icons/obj/food/eggs/egg_green.dmi' + +/obj/item/food/egg/mime + icon = 'icons/obj/food/eggs/egg_mime.dmi' + +/obj/item/food/egg/orange + icon = 'icons/obj/food/eggs/egg_orange.dmi' + +/obj/item/food/egg/purple + icon = 'icons/obj/food/eggs/egg_purple.dmi' + +/obj/item/food/egg/rainbow + icon = 'icons/obj/food/eggs/egg_rainbow.dmi' + +/obj/item/food/egg/red + icon = 'icons/obj/food/eggs/egg_red.dmi' + +/obj/item/food/egg/yellow + icon = 'icons/obj/food/eggs/egg_yellow.dmi' + +/obj/item/food/egg/lizard + icon = 'icons/obj/food/eggs/egg_lizard.dmi' + +/obj/item/food/egg/lizard/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/egg, 5) + if(prob(30)) //extra nutriment + add_to_reagents(/decl/material/solid/organic/meat, 5) + +/obj/item/food/friedegg + name = "fried egg" + desc = "A fried egg, with a touch of salt and pepper." + icon = 'icons/obj/food/fried/friedegg.dmi' + filling_color = "#ffdf78" + center_of_mass = @'{"x":16,"y":14}' + bitesize = 1 + +/obj/item/food/friedegg/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/egg, 3) + add_to_reagents(/decl/material/solid/sodiumchloride, 1) + add_to_reagents(/decl/material/solid/blackpepper, 1) + +/obj/item/food/boiledegg + name = "boiled egg" + desc = "A hard-boiled egg." + icon = 'icons/obj/food/eggs/egg.dmi' + icon_state = ICON_STATE_WORLD + filling_color = "#ffffff" + +/obj/item/food/boiledegg/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/egg, 2) + +/obj/item/food/omelette + name = "cheese omelette" + desc = "Omelette with cheese!" + icon = 'icons/obj/food/fried/omelette.dmi' + plate = /obj/item/plate + filling_color = "#fff9a8" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 1 + +/obj/item/food/omelette/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/egg, 8) + +/obj/item/food/chawanmushi + name = "chawanmushi" + desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat." + icon = 'icons/obj/food/pudding/chawanmushi.dmi' + trash = /obj/item/trash/snack_bowl + filling_color = "#f0f2e4" + center_of_mass = @'{"x":17,"y":10}' + bitesize = 1 + +/obj/item/food/chawanmushi/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/egg, 5) \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/fish.dm b/code/modules/reagents/reagent_containers/food/fish.dm index 166082e24f53..5b6534e4e54c 100644 --- a/code/modules/reagents/reagent_containers/food/fish.dm +++ b/code/modules/reagents/reagent_containers/food/fish.dm @@ -1,75 +1,10 @@ -/obj/item/chems/food/snacks/fish - name = "fillet" - desc = "A fillet of fish." - icon_state = "fishfillet" - filling_color = "#ffdefe" - center_of_mass = @"{'x':17,'y':13}" - bitesize = 6 - nutriment_amt = 6 - nutriment_type = /decl/material/liquid/nutriment/protein - var/fish_type = "fish" - -/obj/item/chems/food/snacks/fish/Initialize() - . = ..() - name = "[fish_type] [initial(name)]" - -// This will remove carp poison etc. Deliberate, meant to be similar to preparing pufferfish. -/obj/item/chems/food/snacks/fish/attackby(var/obj/item/W, var/mob/user) - if(is_sharp(W) && (locate(/obj/structure/table) in loc)) - var/mob/M = loc - if(istype(M) && !M.unEquip(src)) - return - - var/toxin_amt = REAGENT_VOLUME(reagents, /decl/material/liquid/carpotoxin) - if(toxin_amt && !prob(user.skill_fail_chance(SKILL_COOKING, 100, SKILL_PROF))) - reagents.remove_reagent(/decl/material/liquid/carpotoxin, toxin_amt) - user.visible_message("\The [user] slices \the [src] into thin strips.") - - var/transfer_amt = Floor(reagents.total_volume * 0.3) - for(var/i = 1 to 3) - var/obj/item/chems/food/snacks/sashimi/sashimi = new(get_turf(src), fish_type) - reagents.trans_to(sashimi, transfer_amt) - qdel(src) - - else - ..() - -/obj/item/chems/food/snacks/fish/poison - fish_type = "space carp" - -/obj/item/chems/food/snacks/fish/poison/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/carpotoxin, 6) - -/obj/item/chems/food/snacks/fish/shark - fish_type = "shark" - -/obj/item/chems/food/snacks/fish/carp - fish_type = "carp" - -/obj/item/chems/food/snacks/fish/octopus - fish_type = "tako" - -/obj/item/chems/food/snacks/fish/mollusc - name = "meat" - desc = "Some slimy meat from clams or molluscs." - fish_type = "mollusc" - nutriment_type = /decl/material/liquid/nutriment/slime_meat - -/obj/item/chems/food/snacks/fish/mollusc/clam - fish_type = "clam" - -/obj/item/chems/food/snacks/fish/mollusc/barnacle - fish_type = "barnacle" - - // Molluscs! /obj/item/trash/mollusc_shell name = "mollusc shell" icon = 'icons/obj/molluscs.dmi' icon_state = "mollusc_shell" desc = "The cracked shell of an unfortunate mollusc." - material = /decl/material/solid/bone + material = /decl/material/solid/organic/bone /obj/item/trash/mollusc_shell/clam name = "clamshell" @@ -85,24 +20,42 @@ icon = 'icons/obj/molluscs.dmi' icon_state = "mollusc" w_class = ITEM_SIZE_TINY - var/meat_type = /obj/item/chems/food/snacks/fish/mollusc + material = /decl/material/liquid/nutriment/slime_meat + matter = list( + /decl/material/solid/organic/bone/fish = MATTER_AMOUNT_SECONDARY, + ) + var/meat_type = /obj/item/food/butchery/meat/fish/mollusc var/shell_type = /obj/item/trash/mollusc_shell /obj/item/mollusc/barnacle name = "barnacle" desc = "A hull barnacle, probably freshly scraped off a spaceship." icon_state = "barnacle" - meat_type = /obj/item/chems/food/snacks/fish/mollusc/barnacle + meat_type = /obj/item/food/butchery/meat/fish/mollusc/barnacle shell_type = /obj/item/trash/mollusc_shell/barnacle /obj/item/mollusc/clam name = "clam" desc = "A free-ranging space clam." icon_state = "clam" - meat_type = /obj/item/chems/food/snacks/fish/mollusc/clam + meat_type = /obj/item/food/butchery/meat/fish/mollusc/clam shell_type = /obj/item/trash/mollusc_shell/clam -/obj/item/mollusc/proc/crack_shell(var/mob/user) +// This is not a space clam... +/obj/item/mollusc/barnacle/fished + desc = "A squat little barnacle, somehow pried from its perch." +/obj/item/mollusc/clam/fished + desc = "A regular old bivalve. Full of secrets, probably." + +// Subtype to avoid exploiting aquaculture to make infinite pearls. +/obj/item/mollusc/clam/fished/pearl/crack_shell(mob/user) + . = ..() + if(prob(10)) + to_chat(user, SPAN_NOTICE("You find a pearl!")) + var/obj/item/stack/material/lump/pearl = new(get_turf(user), 1, /decl/material/solid/organic/bone/pearl) + user.put_in_hands(pearl) + +/obj/item/mollusc/proc/crack_shell(mob/user) playsound(loc, "fracture", 80, 1) if(user && loc == user) user.drop_from_inventory(src) @@ -116,9 +69,9 @@ user.put_in_hands(shell) qdel(src) -/obj/item/mollusc/attackby(var/obj/item/thing, var/mob/user) - if(thing.sharp || thing.edge) - user.visible_message(SPAN_NOTICE("\The [user] cracks open \the [src] with \the [thing].")) +/obj/item/mollusc/attackby(var/obj/item/used_item, var/mob/user) + if(used_item.is_sharp() || used_item.has_edge()) + user.visible_message(SPAN_NOTICE("\The [user] cracks open \the [src] with \the [used_item].")) crack_shell(user) - return + return TRUE . = ..() diff --git a/code/modules/reagents/reagent_containers/food/fried.dm b/code/modules/reagents/reagent_containers/food/fried.dm new file mode 100644 index 000000000000..3417d11f742b --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/fried.dm @@ -0,0 +1,42 @@ +///////////////// +// Fried Foods // +///////////////// + +// Also contains unfried fried foods. + +/obj/item/food/onionrings + name = "onion rings" + desc = "Like circular fries but better." + icon = 'icons/obj/food/fried/onionrings.dmi' + plate = /obj/item/plate + filling_color = "#eddd00" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("fried onions" = 5) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/fries + name = "chips" + desc = "Frenched potato, fried." + icon = 'icons/obj/food/fried/fries.dmi' + plate = /obj/item/plate + filling_color = "#eddd00" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("fresh fries" = 4) + nutriment_amt = 4 + bitesize = 2 + +/obj/item/food/cheesyfries + name = "cheesy fries" + desc = "Fries. Covered in cheese. Duh." + icon = 'icons/obj/food/fried/cheesyfries.dmi' + plate = /obj/item/plate + filling_color = "#eddd00" + center_of_mass = @'{"x":16,"y":11}' + nutriment_desc = list("fresh fries" = 3, "cheese" = 3) + nutriment_amt = 4 + bitesize = 2 + +/obj/item/food/cheesyfries/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 2) diff --git a/code/modules/reagents/reagent_containers/food/hotdog.dm b/code/modules/reagents/reagent_containers/food/hotdog.dm new file mode 100644 index 000000000000..c74723d57191 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/hotdog.dm @@ -0,0 +1,24 @@ +/obj/item/food/hotdog + name = "hotdog" + desc = "Unrelated to dogs, maybe." + icon = 'icons/obj/food/hotdog.dmi' + bitesize = 2 + center_of_mass = @'{"x":16,"y":17}' + nutriment_type = /decl/material/liquid/nutriment/bread + material = /decl/material/solid/organic/meat + +/obj/item/food/hotdog/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 6) + +/obj/item/food/classichotdog + name = "classic hotdog" + desc = "Going literal." + icon = 'icons/obj/food/hotcorgi.dmi' + bitesize = 6 + center_of_mass = @'{"x":16,"y":17}' + material = /decl/material/solid/organic/meat + +/obj/item/food/classichotdog/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 16) diff --git a/code/modules/reagents/reagent_containers/food/junkfood.dm b/code/modules/reagents/reagent_containers/food/junkfood.dm new file mode 100644 index 000000000000..70a2f267872b --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/junkfood.dm @@ -0,0 +1,421 @@ +/obj/item/food/junk + icon = 'icons/obj/food/junk/junkfood.dmi' + abstract_type = /obj/item/food/junk + +/obj/item/food/junk/sosjerky + name = "emergency meat jerky" + icon_state = "sosjerky" + desc = "For when you desperately want meat and you don't care what kind. Has the same texture as old leather boots." + trash = /obj/item/trash/sosjerky + filling_color = "#631212" + center_of_mass = @'{"x":15,"y":9}' + bitesize = 2 + material = /decl/material/solid/organic/meat + +/obj/item/food/junk/sosjerky/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 4) + +/obj/item/food/junk/no_raisin + name = "raisins" + icon_state = "4no_raisins" + desc = "Pouring water on these will not turn them back into grapes, unfortunately." + trash = /obj/item/trash/raisins + filling_color = "#343834" + center_of_mass = @'{"x":15,"y":4}' + nutriment_desc = list("raisins" = 6) + nutriment_amt = 6 + +/obj/item/food/junk/spacetwinkie + name = "eclair" + icon_state = "space_twinkie" + desc = "So full of preservatives, it's guaranteed to survive longer then you will." + filling_color = "#ffe591" + center_of_mass = @'{"x":15,"y":11}' + bitesize = 2 + +/obj/item/food/junk/spacetwinkie/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/sugar, 4) + +/obj/item/food/junk/cheesiehonkers + name = "cheese puffs" + icon_state = "cheesie_honkers" + desc = "Bite sized cheese flavoured snacks that will leave your fingers coated in cheese dust." + trash = /obj/item/trash/cheesie + filling_color = "#ffa305" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("cheese" = 5, "chips" = 2) + nutriment_amt = 4 + bitesize = 2 + +/obj/item/food/junk/syndicake + name = "subversive cakes" + icon_state = "syndi_cakes" + desc = "Made using extremely unethical labour, ingredients and marketing methods." + filling_color = "#ff5d05" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("sweetness" = 3, "cake" = 1) + nutriment_amt = 4 + trash = /obj/item/trash/syndi_cakes + bitesize = 3 + +/obj/item/food/junk/syndicake/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/regenerator, 5) + +//terran delights + +/obj/item/food/junk/pistachios + name = "pistachios" + icon_state = "pistachios" + desc = "Pistachios. There is absolutely nothing remarkable about these." + trash = /obj/item/trash/pistachios + filling_color = "#825d26" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("nuts" = 1) + nutriment_amt = 3 + bitesize = 0.5 + +/obj/item/food/junk/semki + name = "sunflower seeds" + icon_state = "semki" + desc = "A favorite among birds." + trash = /obj/item/trash/semki + filling_color = "#68645d" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("sunflower seeds" = 1) + nutriment_amt = 6 + bitesize = 0.5 + +/obj/item/food/junk/squid + name = "\improper Calamari Crisps" + icon_state = "squid" + desc = "Space cephalopod tentacles, carefully removed from the squid then dried into strips of delicious rubbery goodness!" + trash = /obj/item/trash/squid + filling_color = "#c0a9d7" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("fish" = 1, "salt" = 1) + nutriment_amt = 2 + bitesize = 1 + +/obj/item/food/junk/squid/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/fish, 4) + +/obj/item/food/junk/croutons + name = "croutons" + icon_state = "croutons" + desc = "Fried bread cubes. Good in salad but I guess you can just eat them as is." + trash = /obj/item/trash/croutons + filling_color = "#c6b17f" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("bread" = 1, "salt" = 1) + nutriment_amt = 3 + bitesize = 1 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/junk/salo + name = "salo" + icon_state = "salo" + desc = "Pig fat. Salted. Just as good as it sounds." + trash = /obj/item/trash/salo + filling_color = "#e0bcbc" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("fat" = 1, "salt" = 1) + nutriment_amt = 2 + bitesize = 2 + +/obj/item/food/junk/salo/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 8) + +/obj/item/food/junk/driedfish + name = "vobla" + icon_state = "driedfish" + desc = "Dried salted beer snack fish." + trash = /obj/item/trash/driedfish + filling_color = "#c8a5bb" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("fish" = 1, "salt" = 1) + nutriment_amt = 2 + bitesize = 1 + +/obj/item/food/junk/driedfish/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/fish, 4) + +/obj/item/food/junk/liquidfood + name = "\improper LiquidFood MRE" + desc = "A prepackaged grey slurry for all of the essential nutrients a soldier requires to survive. No expiration date is visible..." + icon_state = "liquidfood" + trash = /obj/item/trash/liquidfood + filling_color = "#a8a8a8" + center_of_mass = @'{"x":16,"y":15}' + nutriment_desc = list("chalk" = 6) + nutriment_amt = 20 + bitesize = 4 + +/obj/item/food/junk/liquidfood/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/metal/iron, 3) + +/obj/item/food/junk/meatcube + name = "cubed meat" + desc = "Fried, salted lean meat compressed into a cube. Not very appetizing." + icon_state = "meatcube" + filling_color = "#7a3d11" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 3 + material = /decl/material/solid/organic/meat + +/obj/item/food/junk/meatcube/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 15) + +/obj/item/food/junk/tastybread + name = "bread tube" + desc = "Bread in a tube. Chewy... and surprisingly tasty." + icon_state = "tastybread" + trash = /obj/item/trash/tastybread + filling_color = "#a66829" + center_of_mass = @'{"x":17,"y":16}' + nutriment_desc = list("bread" = 2, "sweetness" = 3) + nutriment_amt = 6 + nutriment_type = /decl/material/liquid/nutriment/bread + bitesize = 2 + +/obj/item/food/junk/candy + name = "candy" + desc = "Nougat, love it or hate it." + icon_state = "candy" + trash = /obj/item/trash/candy + filling_color = "#7d5f46" + center_of_mass = @'{"x":15,"y":15}' + nutriment_amt = 1 + nutriment_desc = list("candy" = 1) + bitesize = 2 + +/obj/item/food/junk/candy/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/sugar, 3) + +/obj/item/food/junk/candy/proteinbar + name = "protein bar" + desc = "MuscleLopin brand protein bars, guaranteed to get you soSO strong!" + icon_state = "proteinbar" + trash = /obj/item/trash/candy/proteinbar + bitesize = 6 + +/obj/item/food/junk/candy/proteinbar/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment, 9) + add_to_reagents(/decl/material/solid/organic/meat, 4) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 4) + +/obj/item/food/junk/candy/donor + name = "donor candy" + desc = "A little treat for blood donors." + trash = /obj/item/trash/candy + nutriment_desc = list("candy" = 10) + bitesize = 5 + +/obj/item/food/junk/candy/donor/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment, 10) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 3) + +/obj/item/food/junk/candy_corn + name = "candy corn" + desc = "It's a handful of candy corn. Not actually candied corn." + icon_state = "candy_corn" + filling_color = "#fffcb0" + center_of_mass = @'{"x":14,"y":10}' + nutriment_amt = 4 + nutriment_desc = list("candy corn" = 4) + bitesize = 2 + +/obj/item/food/junk/candy_corn/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment, 4) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 2) + +/obj/item/food/junk/chips + name = "chips" + desc = "It is impossible to open the packet without rustling it loudly." + icon_state = "chips" + trash = /obj/item/trash/chips + filling_color = "#e8c31e" + center_of_mass = @'{"x":15,"y":15}' + nutriment_amt = 3 + nutriment_desc = list("salt" = 1, "chips" = 2) + bitesize = 1 + nutriment_type = /decl/material/liquid/nutriment/bread + +//Sol Vendor +/obj/item/food/junk/lunacake + name = "moon cake" + icon_state = "lunacake_wrapped" + desc = "Now with 20% less lawsuit enabling regolith!" + trash = /obj/item/trash/cakewrap + filling_color = "#ffffff" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("sweet" = 4, "vanilla" = 1) + nutriment_amt = 5 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/junk/lunacake/mochicake + name = "mochi" + icon_state = "mochicake_wrapped" + desc = "A type of rice cake with an extremely soft, glutinous texture." + trash = /obj/item/trash/mochicakewrap + nutriment_desc = list("sweet" = 4, "rice" = 1) + +/obj/item/food/junk/lunacake/mooncake + name = "dark side moon cake" + icon_state = "mooncake_wrapped" + desc = "Explore the dark side! May contain trace amounts of reconstituted cocoa." + trash = /obj/item/trash/mooncakewrap + filling_color = "#000000" + nutriment_desc = list("sweet" = 4, "chocolate" = 1) + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/junk/triton + name = "\improper Tidal Gobs" + icon_state = "tidegobs" + desc = "Contains over 9000% of your daily recommended intake of salt." + trash = /obj/item/trash/tidegobs + filling_color = "#2556b0" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("salt" = 4, "ocean" = 1, "seagull" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/saturn + name = "snack rings" + icon_state = "saturno" + desc = "A day ration of salt, styrofoam and possibly sawdust." + trash = /obj/item/trash/saturno + filling_color = "#dca319" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("salt" = 4, "peanut" = 2, "wood?" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/jupiter + name = "probably gelatin" + icon_state = "jupiter" + desc = "Some kind of gel, maybe?" + trash = /obj/item/trash/jupiter + filling_color = "#dc1919" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("jelly?" = 5) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/pluto + name = "nutrient rods" + icon_state = "pluto" + desc = "Baseless tasteless nutrient rods to get you through the day. Now even less rash inducing!" + trash = /obj/item/trash/pluto + filling_color = "#ffffff" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("chalk" = 4, "sadness" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/mars + name = "instant potato and eggs" + icon_state = "mars" + desc = "A steaming self-heated bowl of sweet eggs and taters!" + trash = /obj/item/trash/mars + filling_color = "#d2c63f" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("eggs" = 4, "potato" = 4, "mustard" = 2) + nutriment_amt = 8 + bitesize = 2 + +/obj/item/food/junk/venus + name = "hot cakes" + icon_state = "venus" + desc = "Hot takes on hot cakes, a timeless classic now finally fit for human consumption!" + trash = /obj/item/trash/venus + filling_color = "#d2c63f" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("heat" = 4, "burning" = 1) + nutriment_amt = 5 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/junk/venus/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/capsaicin, 5) + +/obj/item/food/junk/oort + name = "\improper Cloud Rocks" + icon_state = "oort" + desc = "Pop rocks. The new formula guarantees fewer shrapnel-induced oral injuries." + trash = /obj/item/trash/oort + filling_color = "#3f7dd2" + center_of_mass = @'{"x":15,"y":9}' + nutriment_desc = list("fizz" = 3, "sweet?" = 1, "shrapnel" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/oort/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/frostoil, 5) + +//weebo vend! So japanese it hurts + +/obj/item/food/junk/ricecake + name = "rice ball" + icon_state = "ricecake" + desc = "A snack food made from balled up rice." + nutriment_desc = list("rice" = 3, "sweet" = 1, "seaweed" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/pokey + name = "chocolate coated biscuit sticks" + icon_state = "pokeys" + desc = "A bundle of chocolate coated biscuit sticks. Not as exciting as they seem." + nutriment_desc = list("chocolate" = 1, "biscuit" = 2, "cardboard" = 2) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/weebonuts + name = "spicy nuts" + icon_state = "weebonuts" + trash = /obj/item/trash/weebonuts + desc = "A bag of spicy nuts. Goes well with beer!" + nutriment_desc = list("nuts" = 4, "spicy!" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/weebonuts/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/capsaicin, 1) + +/obj/item/food/junk/chocobanana + name = "choco banana" + icon_state = "chocobanana" + trash = /obj/item/trash/stick + desc = "A chocolate and sprinkles coated banana. On a stick." + nutriment_desc = list("banana" = 3, "chocolate" = 1, "wax?" = 1) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/junk/chocobanana/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/sprinkles, 10) + +/obj/item/food/junk/dango + name = "dango" + icon_state = "dango" + trash = /obj/item/trash/stick + desc = "Food dyed rice dumplings on a stick." + nutriment_desc = list("rice" = 4, "topping?" = 1) + nutriment_amt = 5 + bitesize = 2 diff --git a/code/modules/reagents/reagent_containers/food/lunch.dm b/code/modules/reagents/reagent_containers/food/lunch.dm index b98ec120e09b..0a1b7aa8daaa 100644 --- a/code/modules/reagents/reagent_containers/food/lunch.dm +++ b/code/modules/reagents/reagent_containers/food/lunch.dm @@ -1,75 +1,78 @@ -var/list/lunchables_lunches_ = list( - /obj/item/chems/food/snacks/sandwich, - /obj/item/chems/food/snacks/slice/meatbread/filled, - /obj/item/chems/food/snacks/slice/tofubread/filled, - /obj/item/chems/food/snacks/slice/creamcheesebread/filled, - /obj/item/chems/food/snacks/slice/margherita/filled, - /obj/item/chems/food/snacks/slice/meatpizza/filled, - /obj/item/chems/food/snacks/slice/mushroompizza/filled, - /obj/item/chems/food/snacks/slice/vegetablepizza/filled, - /obj/item/chems/food/snacks/tastybread, - /obj/item/chems/food/snacks/liquidfood, - /obj/item/chems/food/snacks/jellysandwich/cherry, - /obj/item/chems/food/snacks/tossedsalad +var/global/list/lunchables_lunches_ = list( + /obj/item/food/sandwich, + /obj/item/food/slice/meatbread/filled, + /obj/item/food/slice/tofubread/filled, + /obj/item/food/slice/creamcheesebread/filled, + /obj/item/food/slice/pizza/margherita/filled, + /obj/item/food/slice/pizza/meat/filled, + /obj/item/food/slice/pizza/mushroom/filled, + /obj/item/food/slice/pizza/vegetable/filled, + /obj/item/food/junk/tastybread, + /obj/item/food/junk/liquidfood, + /obj/item/food/jellysandwich/cherry, + /obj/item/food/tossedsalad ) -var/list/lunchables_snacks_ = list( - /obj/item/chems/food/snacks/donut/jelly, - /obj/item/chems/food/snacks/donut/cherryjelly, - /obj/item/chems/food/snacks/muffin, - /obj/item/chems/food/snacks/popcorn, - /obj/item/chems/food/snacks/sosjerky, - /obj/item/chems/food/snacks/no_raisin, - /obj/item/chems/food/snacks/spacetwinkie, - /obj/item/chems/food/snacks/cheesiehonkers, - /obj/item/chems/food/snacks/poppypretzel, - /obj/item/chems/food/snacks/carrotfries, - /obj/item/chems/food/snacks/candiedapple, - /obj/item/chems/food/snacks/applepie, - /obj/item/chems/food/snacks/cherrypie, - /obj/item/chems/food/snacks/plumphelmetbiscuit, - /obj/item/chems/food/snacks/appletart, - /obj/item/chems/food/snacks/slice/carrotcake/filled, - /obj/item/chems/food/snacks/slice/cheesecake/filled, - /obj/item/chems/food/snacks/slice/plaincake/filled, - /obj/item/chems/food/snacks/slice/orangecake/filled, - /obj/item/chems/food/snacks/slice/limecake/filled, - /obj/item/chems/food/snacks/slice/lemoncake/filled, - /obj/item/chems/food/snacks/slice/chocolatecake/filled, - /obj/item/chems/food/snacks/slice/birthdaycake/filled, - /obj/item/chems/food/snacks/watermelonslice, - /obj/item/chems/food/snacks/slice/applecake/filled, - /obj/item/chems/food/snacks/slice/pumpkinpie/filled +var/global/list/lunchables_snacks_ = list( + /obj/item/food/donut/jelly, + /obj/item/food/muffin, + /obj/item/food/popcorn, + /obj/item/food/junk/sosjerky, + /obj/item/food/junk/no_raisin, + /obj/item/food/junk/spacetwinkie, + /obj/item/food/junk/cheesiehonkers, + /obj/item/food/poppypretzel, + /obj/item/food/processed_grown/sticks/carrot, + /obj/item/food/candiedapple, + /obj/item/food/applepie, + /obj/item/food/cherrypie, + /obj/item/food/plumphelmetbiscuit, + /obj/item/food/appletart, + /obj/item/food/slice/carrotcake/filled, + /obj/item/food/slice/cheesecake/filled, + /obj/item/food/slice/plaincake/filled, + /obj/item/food/slice/orangecake/filled, + /obj/item/food/slice/limecake/filled, + /obj/item/food/slice/lemoncake/filled, + /obj/item/food/slice/chocolatecake/filled, + /obj/item/food/slice/birthdaycake/filled, + /obj/item/food/slice/applecake/filled, + /obj/item/food/slice/pumpkinpie/filled ) -var/list/lunchables_drinks_ = list( - /obj/item/chems/food/drinks/cans/cola, - /obj/item/chems/food/drinks/cans/waterbottle, - /obj/item/chems/food/drinks/cans/space_mountain_wind, - /obj/item/chems/food/drinks/cans/dr_gibb, - /obj/item/chems/food/drinks/cans/starkist, - /obj/item/chems/food/drinks/cans/space_up, - /obj/item/chems/food/drinks/cans/lemon_lime, - /obj/item/chems/food/drinks/cans/iced_tea, - /obj/item/chems/food/drinks/cans/grape_juice, - /obj/item/chems/food/drinks/cans/tonic, - /obj/item/chems/food/drinks/cans/sodawater +var/global/list/lunchables_drinks_ = list( + /obj/item/chems/drinks/cans/cola, + /obj/item/chems/drinks/cans/waterbottle, + /obj/item/chems/drinks/cans/space_mountain_wind, + /obj/item/chems/drinks/cans/dr_gibb, + /obj/item/chems/drinks/cans/starkist, + /obj/item/chems/drinks/cans/space_up, + /obj/item/chems/drinks/cans/lemon_lime, + /obj/item/chems/drinks/cans/iced_tea, + /obj/item/chems/drinks/cans/grape_juice, + /obj/item/chems/drinks/cans/tonic, + /obj/item/chems/drinks/cans/sodawater ) // This default list is a bit different, it contains items we don't want -var/list/lunchables_drink_reagents_ = list( +var/global/list/lunchables_drink_reagents_ = list( /decl/material/liquid/drink/dry_ramen, /decl/material/liquid/drink/hell_ramen, /decl/material/liquid/drink/hot_ramen, - /decl/material/liquid/drink/mutagencola + /decl/material/liquid/drink/mutagencola, + /decl/material/liquid/drink/syrup, + /decl/material/liquid/drink/syrup/mint, + /decl/material/liquid/drink/syrup/chocolate, + /decl/material/liquid/drink/syrup/caramel, + /decl/material/liquid/drink/syrup/vanilla ) // This default list is a bit different, it contains items we don't want -var/list/lunchables_ethanol_reagents_ = list( - /decl/material/liquid/ethanol/coffee, - /decl/material/liquid/ethanol/hooch, - /decl/material/liquid/ethanol/thirteenloko, - /decl/material/liquid/ethanol/pwine +var/global/list/lunchables_ethanol_reagents_ = list( + /decl/material/liquid/alcohol/coffee, + /decl/material/liquid/alcohol/hooch, + /decl/material/liquid/alcohol/thirteenloko, + /decl/material/liquid/alcohol/pwine ) /proc/lunchables_lunches() @@ -94,21 +97,21 @@ var/list/lunchables_ethanol_reagents_ = list( /proc/lunchables_ethanol_reagents() if(!(lunchables_ethanol_reagents_[lunchables_ethanol_reagents_[1]])) - lunchables_ethanol_reagents_ = init_lunchable_reagent_list(lunchables_ethanol_reagents_, /decl/material/liquid/ethanol) + lunchables_ethanol_reagents_ = init_lunchable_reagent_list(lunchables_ethanol_reagents_, /decl/material/liquid/alcohol) return lunchables_ethanol_reagents_ /proc/init_lunchable_list(var/list/lunches) . = list() for(var/lunch in lunches) - var/obj/O = lunch - .[initial(O.name)] = lunch - return sortAssoc(.) + var/object_name = atom_info_repository.get_name_for(lunch) + .[object_name] = lunch + return sortTim(., /proc/cmp_text_asc) -/proc/init_lunchable_reagent_list(var/list/banned_reagents, var/reagent_types) +/proc/init_lunchable_reagent_list(var/list/banned_reagents, var/reagent_type) . = list() - for(var/reagent_type in subtypesof(reagent_types)) - if(reagent_type in banned_reagents) + for(var/reagent_subtype in decls_repository.get_decls_of_type(reagent_type)) + if(reagent_subtype in banned_reagents) continue - var/decl/material/reagent = reagent_type - .[initial(reagent.name)] = reagent_type - return sortAssoc(.) + var/decl/material/reagent = GET_DECL(reagent_subtype) + .[reagent.liquid_name] = reagent_subtype + return sortTim(., /proc/cmp_text_asc) diff --git a/code/modules/reagents/reagent_containers/food/meat/cubes.dm b/code/modules/reagents/reagent_containers/food/meat/cubes.dm new file mode 100644 index 000000000000..13f680708778 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/meat/cubes.dm @@ -0,0 +1,116 @@ +//cubed animals! +/obj/item/food/animal_cube + abstract_type = /obj/item/food/animal_cube + desc = "Just add water!" + icon = 'icons/obj/items/animal_cube.dmi' + icon_state = ICON_STATE_WORLD + bitesize = 12 + filling_color = "#adac7f" + center_of_mass = @'{"x":16,"y":14}' + var/growing = FALSE + var/spawn_type + var/wrapper_type + +/obj/item/food/animal_cube/wrapped + desc = "Still wrapped in some paper." + item_flags = 0 + obj_flags = 0 + wrapper_type = /obj/item/trash/cubewrapper + abstract_type = /obj/item/food/animal_cube/wrapped + +/obj/item/food/animal_cube/Initialize(ml, material_key, skip_plate) + . = ..() + if(!spawn_type) + return INITIALIZE_HINT_QDEL + if(wrapper_type) + update_icon() + +/obj/item/food/animal_cube/on_update_icon() + . = ..() + icon_state = initial(icon_state) + if(wrapper_type) + icon_state = "[icon_state]_wrapped" + +/obj/item/food/animal_cube/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 10) + +/obj/item/food/animal_cube/get_single_monetary_worth() + . = (spawn_type ? round(atom_info_repository.get_combined_worth_for((islist(spawn_type) ? spawn_type[1] : spawn_type)) * 1.25) : 5) + if(wrapper_type) + . += atom_info_repository.get_combined_worth_for(wrapper_type) + +/obj/item/food/animal_cube/attack_self(var/mob/user) + if(wrapper_type) + unwrap_cube(user) + return TRUE + return ..() + +/obj/item/food/animal_cube/proc/spawn_creature(force_loc) + if(growing) + return + growing = TRUE + visible_message(SPAN_NOTICE("\The [src] expands!")) + if(islist(spawn_type)) + spawn_type = pickweight(spawn_type) + var/mob/critter = new spawn_type + critter.dropInto(force_loc || loc) + qdel(src) + +/obj/item/food/animal_cube/proc/unwrap_cube(var/mob/user) + desc = "Just add water!" + to_chat(user, SPAN_NOTICE("You unwrap \the [src].")) + user.put_in_hands(new wrapper_type(get_turf(user))) + wrapper_type = null + update_icon() + +/obj/item/food/animal_cube/can_be_poured_into(atom/source) + return ..() && !wrapper_type + +/obj/item/food/animal_cube/handle_eaten_by_mob(mob/user, mob/target) + . = ..() + if(. == EATEN_SUCCESS) + target = target || user + if(target) + target.visible_message(SPAN_DANGER("A screeching creature bursts out of \the [target]!")) + var/obj/item/organ/external/organ = GET_EXTERNAL_ORGAN(target, BP_CHEST) + if(organ) + organ.take_damage(50, inflicter = "Animal escaping the ribcage") + spawn_creature(get_turf(target)) + +/obj/item/food/animal_cube/on_reagent_change() + if((. = ..()) && !QDELETED(src) && reagents?.has_reagent(/decl/material/liquid/water)) + spawn_creature() + +//Spider cubes, all that's left of the cube PR +/obj/item/food/animal_cube/spider + name = "spider cube" + spawn_type = /obj/effect/spider/spiderling + +/obj/item/food/animal_cube/wrapped/spider + name = "spider cube" + spawn_type = /obj/effect/spider/spiderling + +/obj/item/food/animal_cube/monkey + name = "monkey cube" + spawn_type = /mob/living/human/monkey + +/obj/item/food/animal_cube/wrapped/monkey + name = "monkey cube" + spawn_type = /mob/living/human/monkey + +/obj/item/food/animal_cube/carp + name = "carp cube" + spawn_type = list( + /mob/living/simple_animal/hostile/carp = 10, + /mob/living/simple_animal/hostile/carp/pike = 3, + /mob/living/simple_animal/hostile/carp/shark = 1 + ) + +/obj/item/food/animal_cube/wrapped/carp + name = "carp cube" + spawn_type = list( + /mob/living/simple_animal/hostile/carp = 10, + /mob/living/simple_animal/hostile/carp/pike = 3, + /mob/living/simple_animal/hostile/carp/shark = 1 + ) diff --git a/code/modules/reagents/reagent_containers/food/meat/fish.dm b/code/modules/reagents/reagent_containers/food/meat/fish.dm new file mode 100644 index 000000000000..4036cb4efe70 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/meat/fish.dm @@ -0,0 +1,41 @@ +/obj/item/food/fishfingers + name = "fish fingers" + desc = "A finger of fish." + icon = 'icons/obj/food/fried/fishfingers.dmi' + filling_color = "#ffdefe" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 3 + +/obj/item/food/fishfingers/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/fish, 4) + +/obj/item/food/cubancarp + name = "\improper Cuban Carp" + desc = "A sandwich that burns your tongue and then leaves it numb!" + icon = 'icons/obj/food/fried/cubancarp.dmi' + plate = /obj/item/plate + filling_color = "#e9adff" + center_of_mass = @'{"x":12,"y":5}' + nutriment_desc = list("toasted bread" = 3) + nutriment_amt = 3 + bitesize = 3 + +/obj/item/food/cubancarp/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/fish, 3) + add_to_reagents(/decl/material/liquid/capsaicin, 3) + +/obj/item/food/fishandchips + name = "fish and chips" + desc = "Best enjoyed wrapped in a newspaper on a cold wet day." + icon = 'icons/obj/food/fried/fishandchips.dmi' + filling_color = "#e3d796" + center_of_mass = @'{"x":16,"y":16}' + nutriment_desc = list("salt" = 1, "chips" = 2, "fish" = 2) + nutriment_amt = 3 + bitesize = 3 + +/obj/item/food/fishandchips/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/fish, 3) \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/meat/jerky.dm b/code/modules/reagents/reagent_containers/food/meat/jerky.dm new file mode 100644 index 000000000000..84a33dd09e9c --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/meat/jerky.dm @@ -0,0 +1,54 @@ +/obj/item/food/jerky + name = "dried meat" + icon = 'icons/obj/food/butchery/jerky.dmi' + icon_state = "jerky" + bitesize = 2 + w_class = ITEM_SIZE_TINY + dry = TRUE + nutriment_type = /decl/material/solid/organic/meat + nutriment_amt = 5 + color = "#81492e" + var/meat_name = "meat" + +/obj/item/food/jerky/get_drying_state() + return "meat" + +/obj/item/food/jerky/Initialize(mapload, material_key, skip_plate = FALSE) + . = ..() + if(meat_name) + set_meat_name(meat_name) + +/obj/item/food/jerky/proc/set_meat_name(new_meat_name) + meat_name = new_meat_name + name = "dried [meat_name]" + +/obj/item/food/jerky/fish + desc = "A piece of dried fish, with a couple of scales still attached." + meat_name = "fish" + color = "#ffd997" + +/obj/item/food/jerky/meat + desc = "A piece of chewy dried meat. It has the texture of leather." + meat_name = "beef" + +/obj/item/food/jerky/cutlet + name = "dried meat stick" + desc = "A stick of chewy dried meat. Great for travel rations." + nutriment_amt = 2 + color = "#81492e" + +/obj/item/food/jerky/cutlet/set_meat_name(new_meat_name) + . = ..() + SetName("[name] stick") + +/obj/item/food/jerky/spider + desc = "A piece of green, stringy, dried meat, full of tubes. It smells faintly of acid." + meat_name = "spider meat" + color = "#6f5b4a" + +/obj/item/food/jerky/spider/poison + color = "#546145" + +/obj/item/food/jerky/spider/poison/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/venom, 3) diff --git a/code/modules/reagents/reagent_containers/food/meat/meat.dm b/code/modules/reagents/reagent_containers/food/meat/meat.dm new file mode 100644 index 000000000000..3b42036d3515 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/meat/meat.dm @@ -0,0 +1,167 @@ +/obj/item/food/meatball/raw/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 2) + +/obj/item/food/meatball + name = "meatball" + desc = "A great meal all round." + icon = 'icons/obj/food/butchery/meatball.dmi' + filling_color = "#db0000" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 2 + material = /decl/material/solid/organic/meat + +/obj/item/food/meatball/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 3) + +/obj/item/food/meatball/raw + desc = "A raw meatball." + icon = 'icons/obj/food/butchery/rawmeatball.dmi' + cooked_food = FOOD_RAW + backyard_grilling_product = /obj/item/food/meatball + backyard_grilling_announcement = "sizzles as it is grilled through." + +/obj/item/food/plainsteak + name = "plain steak" + desc = "A piece of unseasoned cooked meat." + icon = 'icons/obj/food/butchery/steak.dmi' + slice_path = /obj/item/food/butchery/cutlet + slice_num = 3 + filling_color = "#7a3d11" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 3 + material = /decl/material/solid/organic/meat + utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SLICE + +/obj/item/food/plainsteak/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 4) + +/obj/item/food/meatsteak/grilled + plate = null + +/obj/item/food/meatsteak/grilled/add_seasoning() + return + +/obj/item/food/meatsteak + name = "meat steak" + desc = "A slab of meat, cooked medium-rare." + icon = 'icons/obj/food/butchery/steak.dmi' + plate = /obj/item/plate + filling_color = "#7a3d11" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 3 + material = /decl/material/solid/organic/meat + +/obj/item/food/meatsteak/proc/add_seasoning() + add_to_reagents(/decl/material/solid/sodiumchloride, 1) + add_to_reagents(/decl/material/solid/blackpepper, 1) + +/obj/item/food/meatsteak/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 4) + add_seasoning() + +/obj/item/food/meatsteak/synthetic + name = "meaty steak" + desc = "A piece of hot spicy pseudo-meat." + +/obj/item/food/loadedsteak + name = "loaded steak" + desc = "A steak slathered in sauce with sauteed onions and mushrooms." + icon = 'icons/obj/food/butchery/steak.dmi' // Missing icon state? + plate = /obj/item/plate + filling_color = "#7a3d11" + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("onion" = 2, "mushroom" = 2) + nutriment_amt = 4 + bitesize = 3 + material = /decl/material/solid/organic/meat + +/obj/item/food/loadedsteak/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 2) + add_to_reagents(/decl/material/liquid/nutriment/garlicsauce, 2) + +/obj/item/food/tomatomeat + name = "tomato slice" + desc = "A slice from a huge tomato." + icon = 'icons/obj/food/butchery/tomato.dmi' + filling_color = "#db0000" + center_of_mass = @'{"x":17,"y":16}' + nutriment_amt = 3 + nutriment_desc = list("raw" = 2, "tomato" = 3) + bitesize = 6 + +// Shouldn't this be poisonous? +/obj/item/food/spider + name = "giant spider leg" + desc = "An economical replacement for crab. In space! Would probably be a lot nicer cooked." + icon = 'icons/obj/food/butchery/spider_leg.dmi' + filling_color = "#d5f5dc" + center_of_mass = @'{"x":16,"y":10}' + bitesize = 3 + material = /decl/material/solid/organic/meat + drying_wetness = 60 + dried_type = /obj/item/food/jerky/spider/poison + backyard_grilling_product = /obj/item/food/spider/charred + backyard_grilling_announcement = "smokes as the poison burns away." + +/obj/item/food/spider/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/xeno, 9) + +/obj/item/food/spider/charred + name = "charred spider meat" + desc = "A slab of green meat with char lines. The poison has been burned out of it." + color = COLOR_RED_LIGHT + backyard_grilling_product = /obj/item/food/badrecipe + dried_product_takes_color = FALSE + dried_type = /obj/item/food/jerky/spider + +/obj/item/food/spider/cooked + name = "boiled spider meat" + desc = "An economical replacement for crab. In space!" + icon = 'icons/obj/food/butchery/spider_leg_cooked.dmi' + bitesize = 5 + +/obj/item/food/sausage + name = "sausage" + desc = "A piece of mixed, long meat." + icon = 'icons/obj/food/butchery/sausage.dmi' + filling_color = "#db0000" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 2 + material = /decl/material/solid/organic/meat + +/obj/item/food/sausage/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 6) + +/obj/item/food/fatsausage + name = "spiced sausage" + desc = "A piece of mixed, long meat, with some bite to it." + icon = 'icons/obj/food/butchery/sausage.dmi' + filling_color = "#db0000" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 2 + material = /decl/material/solid/organic/meat + +/obj/item/food/fatsausage/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 8) + +/obj/item/food/organ + name = "organ" + desc = "It's good for you, probably." + icon = 'icons/obj/surgery.dmi' + icon_state = "appendix" + filling_color = "#e00d34" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 3 + +/obj/item/food/organ/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, rand(3,5)) + add_to_reagents(/decl/material/gas/ammonia, rand(1,3)) // you probably should not be eating raw organ meat diff --git a/code/modules/reagents/reagent_containers/food/misc.dm b/code/modules/reagents/reagent_containers/food/misc.dm new file mode 100644 index 000000000000..2832a32c2728 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/misc.dm @@ -0,0 +1,236 @@ +/obj/item/food/badrecipe + name = "burned mess" + desc = "Someone should be demoted from chef for this." + icon = 'icons/obj/food/badrecipe.dmi' + filling_color = "#211f02" + center_of_mass = @'{"x":16,"y":12}' + bitesize = 2 + backyard_grilling_product = null + backyard_grilling_rawness = 10 + +/obj/item/food/badrecipe/grill(var/atom/heat_source) + if(backyard_grilling_rawness <= 0) // Smoke on our first grill + // Produce nasty smoke. + playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) + var/datum/effect/effect/system/smoke_spread/bad/smoke = new + smoke.attach(src) + smoke.set_up(10, 0, get_turf(src)) + // Set off fire alarms! + var/obj/machinery/firealarm/FA = locate() in get_area(src) + if(FA) + FA.alarm() + backyard_grilling_rawness-- + if(backyard_grilling_rawness <= 0) + qdel(src) + +/obj/item/food/badrecipe/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/acrylamide, 1) + add_to_reagents(/decl/material/solid/carbon, 3) + +/obj/item/food/stuffing + name = "stuffing" + desc = "Moist, peppery breadcrumbs for filling the body cavities of dead birds. Dig in!" + icon = 'icons/obj/food/baked/stuffing.dmi' + filling_color = "#c9ac83" + center_of_mass = @'{"x":16,"y":10}' + nutriment_amt = 3 + nutriment_desc = list("dryness" = 2, "bread" = 2) + bitesize = 1 + +/obj/item/food/popcorn + name = "popcorn" + desc = "Now let's find some cinema." + icon = 'icons/obj/food/baked/popcorn.dmi' + trash = /obj/item/trash/popcorn + filling_color = "#fffad4" + center_of_mass = @'{"x":16,"y":8}' + nutriment_desc = list("popcorn" = 3) + nutriment_amt = 2 + bitesize = 0.1 + +/obj/item/food/loadedbakedpotato + name = "loaded baked potato" + desc = "Totally baked." + icon = 'icons/obj/food/baked/loaded_potato.dmi' + filling_color = "#9c7a68" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("baked potato" = 3) + nutriment_amt = 3 + bitesize = 2 + +/obj/item/food/loadedbakedpotato/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 3) + +/obj/item/food/spacylibertyduff + name = "party jelly" + desc = "LoOk aT aLl tHe PrEtTy CoLoUrS" + icon = 'icons/obj/food/pudding/liberty_duff.dmi' + trash = /obj/item/trash/snack_bowl + filling_color = "#42b873" + center_of_mass = @'{"x":16,"y":8}' + nutriment_desc = list("mushroom" = 5, "rainbow" = 1) + nutriment_amt = 6 + bitesize = 3 + +/obj/item/food/spacylibertyduff/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/psychotropics, 6) + +/obj/item/food/amanitajelly + name = "amanita jelly" + desc = "Looks curiously toxic." + icon = 'icons/obj/food/pudding/amanita_jelly.dmi' + trash = /obj/item/trash/snack_bowl + filling_color = "#ed0758" + center_of_mass = @'{"x":16,"y":5}' + nutriment_desc = list("jelly" = 3, "mushroom" = 3) + nutriment_amt = 6 + bitesize = 3 + +/obj/item/food/amanitajelly/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/amatoxin, 6) + add_to_reagents(/decl/material/liquid/psychotropics, 3) + +/obj/item/food/enchiladas + name = "enchiladas" + desc = "Not to be confused with an echidna, though I don't know how you would." + icon = 'icons/obj/food/baked/enchiladas.dmi' + plate = /obj/item/plate/tray + filling_color = "#a36a1f" + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("tortilla" = 3, "corn" = 3) + nutriment_amt = 2 + bitesize = 4 + +/obj/item/food/enchiladas/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 6) + add_to_reagents(/decl/material/liquid/capsaicin, 6) + +/obj/item/food/monkeysdelight + name = "monkey's delight" + desc = "Eeee Eee!" + icon = 'icons/obj/food/baked/monkeys_delight.dmi' + plate = /obj/item/plate/tray + filling_color = "#5c3c11" + center_of_mass = @'{"x":16,"y":13}' + bitesize = 6 + +/obj/item/food/monkeysdelight/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 10) + add_to_reagents(/decl/material/liquid/drink/juice/banana, 5) + add_to_reagents(/decl/material/solid/blackpepper, 1) + add_to_reagents(/decl/material/solid/sodiumchloride, 1) + +/obj/item/food/candiedapple + name = "candied apple" + desc = "An apple coated in sugary sweetness." + icon = 'icons/obj/food/candied_apple.dmi' + filling_color = "#f21873" + center_of_mass = @'{"x":15,"y":13}' + nutriment_desc = list("apple" = 3, "caramel" = 3, "sweetness" = 2) + nutriment_amt = 3 + bitesize = 3 + +/obj/item/food/mint + name = "mint" + desc = "A tasty after-dinner mint. It is only wafer thin." + icon = 'icons/obj/food/mint.dmi' + filling_color = "#f2f2f2" + center_of_mass = @'{"x":16,"y":14}' + bitesize = 1 + +/obj/item/food/mint/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/drink/syrup/mint, 1) + +/obj/item/food/plumphelmetbiscuit + name = "plump helmet biscuit" + desc = "This is a finely-prepared plump helmet biscuit. The ingredients are exceptionally minced plump helmet, and well-minced wheat flour." + icon = 'icons/obj/food/baked/scone.dmi' + filling_color = "#cfb4c4" + center_of_mass = @'{"x":16,"y":13}' + nutriment_desc = list("mushroom" = 4) + nutriment_amt = 5 + bitesize = 2 + +/obj/item/food/plumphelmetbiscuit/populate_reagents() + . = ..() + if(prob(10)) + name = "exceptional plump helmet biscuit" + desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump helmet biscuit!" + add_to_reagents(/decl/material/liquid/nutriment, 3) + add_to_reagents(/decl/material/liquid/regenerator, 5) + +/obj/item/food/appletart + name = "golden apple streusel tart" + desc = "A tasty dessert that won't make it through a metal detector." + icon = 'icons/obj/food/baked/apple_tart.dmi' + plate = /obj/item/plate + filling_color = "#ffff00" + center_of_mass = @'{"x":16,"y":18}' + nutriment_desc = list("apple" = 8) + nutriment_amt = 8 + bitesize = 3 + +/obj/item/food/appletart/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/metal/gold, 5) + +/obj/item/food/cracker + name = "cracker" + desc = "It's a salted cracker." + icon = 'icons/obj/food/baked/cracker.dmi' + icon_state = ICON_STATE_WORLD + filling_color = "#f5deb8" + center_of_mass = @'{"x":17,"y":6}' + nutriment_desc = list("salt" = 1, "cracker" = 2) + w_class = ITEM_SIZE_TINY + nutriment_amt = 1 + nutriment_type = /decl/material/liquid/nutriment/bread + +/////////////////////////////////////////// +// new old food stuff from bs12 +/////////////////////////////////////////// + +/obj/item/food/taco + name = "taco" + desc = "Take a bite!" + icon = 'icons/obj/food/taco.dmi' + bitesize = 3 + center_of_mass = @'{"x":21,"y":12}' + nutriment_desc = list("cheese" = 2,"taco shell" = 2) + nutriment_amt = 4 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/taco/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 3) + +/obj/item/food/pelmen + name = "meat pelmen" + desc = "Raw meat appetizer." + icon = 'icons/obj/food/pelmen.dmi' + filling_color = "#ffffff" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 2 + +/obj/item/food/pelmen/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 1) + +/obj/item/food/pelmeni_boiled + name = "boiled pelmeni" + desc = "A dish consisting of boiled pieces of meat wrapped in dough. Delicious!" + icon = 'icons/obj/food/pelmeni_boiled.dmi' + filling_color = "#ffffff" + center_of_mass = @'{"x":16,"y":16}' + bitesize = 2 + +/obj/item/food/pelmeni_boiled/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 30) diff --git a/code/modules/reagents/reagent_containers/food/pasta.dm b/code/modules/reagents/reagent_containers/food/pasta.dm new file mode 100644 index 000000000000..94c12fc4feb7 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/pasta.dm @@ -0,0 +1,82 @@ +/////////// +// Pasta // +/////////// + +/obj/item/food/spagetti + name = "spaghetti" + desc = "A bundle of raw spaghetti." + icon = 'icons/obj/food/pasta/rawspaghetti.dmi' + filling_color = "#eddd00" + center_of_mass = @'{"x":16,"y":16}' + nutriment_desc = list("noodles" = 2) + nutriment_amt = 1 + bitesize = 1 + +/obj/item/food/boiledspagetti + name = "boiled spaghetti" + desc = "A plain dish of pasta, just screaming for sauce." + icon = 'icons/obj/food/pasta/spaghetti.dmi' + plate = /obj/item/plate + filling_color = "#fcee81" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("noodles" = 2) + nutriment_amt = 2 + bitesize = 2 + +/obj/item/food/pastatomato + name = "spaghetti & tomato" + desc = "Spaghetti and crushed tomatoes." + icon = 'icons/obj/food/pasta/tomato_spaghetti.dmi' + plate = /obj/item/plate + filling_color = "#de4545" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("tomato" = 3, "noodles" = 3) + nutriment_amt = 6 + bitesize = 4 + +/obj/item/food/pastatomato/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/drink/juice/tomato, 10) + +/obj/item/food/nanopasta + name = "nanopasta" + desc = "Nanomachines, son!" + icon = 'icons/obj/food/pasta/nanopasta.dmi' + plate = /obj/item/plate + filling_color = "#535e66" + center_of_mass = @'{"x":16,"y":10}' + nutriment_amt = 6 + bitesize = 4 + +/obj/item/food/nanopasta/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nanitefluid, 10) + +/obj/item/food/meatballspagetti + name = "spaghetti & meatballs" + desc = "Now that's a nice meatball!" + icon = 'icons/obj/food/pasta/meatball_spaghetti.dmi' + plate = /obj/item/plate + filling_color = "#de4545" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("noodles" = 4) + nutriment_amt = 4 + bitesize = 2 + +/obj/item/food/meatballspagetti/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 4) + +/obj/item/food/spesslaw + name = "spaghetti & too many meatballs" + desc = "Do you want some pasta with those meatballs?" + icon = 'icons/obj/food/pasta/extra_meatball_spaghetti.dmi' + filling_color = "#de4545" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("noodles" = 4) + nutriment_amt = 4 + bitesize = 2 + +/obj/item/food/spesslaw/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 4) diff --git a/code/modules/reagents/reagent_containers/food/rice.dm b/code/modules/reagents/reagent_containers/food/rice.dm new file mode 100644 index 000000000000..8322e9f36627 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/rice.dm @@ -0,0 +1,40 @@ +////////// +// Rice // +////////// + +/obj/item/food/boiledrice + name = "boiled rice" + desc = "White rice, a very important staple food. Goes excellent with many many things." + icon = 'icons/obj/food/rice/boiled.dmi' + trash = /obj/item/trash/snack_bowl + filling_color = "#fffbdb" + center_of_mass = @'{"x":17,"y":11}' + nutriment_desc = list("rice" = 2) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/chazuke + name = "chazuke" + desc = "An ancient way of using up day-old rice, this dish is composed of plain green tea poured over plain white rice. Hopefully you have something else to put in." + icon = 'icons/obj/food/rice/chazuke.dmi' + trash = /obj/item/trash/snack_bowl + filling_color = "#f1ffdb" + nutriment_desc = list("green tea" = 2, "mild rice" = 2) + bitesize = 3 + nutriment_amt = 5 + nutriment_type = /decl/material/liquid/nutriment/rice + +/obj/item/food/chazuke/populate_reagents() + . = ..() + reagents.add_reagent(/decl/material/liquid/drink/tea/green, 1) + +/obj/item/food/ricepudding + name = "rice pudding" + desc = "Where's the jam?" + icon = 'icons/obj/food/rice/pudding.dmi' + trash = /obj/item/trash/snack_bowl + filling_color = "#fffbdb" + center_of_mass = @'{"x":17,"y":11}' + nutriment_desc = list("rice" = 2) + nutriment_amt = 4 + bitesize = 2 \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/rotten.dm b/code/modules/reagents/reagent_containers/food/rotten.dm new file mode 100644 index 000000000000..4115b5d05dee --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/rotten.dm @@ -0,0 +1,50 @@ +//inedible old vendor food +//filled with inedible and possibly dangerous chemicals +/obj/item/food/old + name = "master old-food" + center_of_mass = @'{"x":15,"y":12}' + nutriment_desc = list("rot" = 5, "mold" = 5) + nutriment_amt = 10 + bitesize = 3 + filling_color = "#336b42" + abstract_type = /obj/item/food/old + +/obj/item/food/old/populate_reagents() + . = ..() + add_to_reagents(pick( + /decl/material/liquid/fuel, + /decl/material/liquid/amatoxin, + /decl/material/liquid/carpotoxin, + /decl/material/liquid/zombiepowder, + /decl/material/liquid/presyncopics, + /decl/material/liquid/psychotropics), 5) + +/obj/item/food/old/pizza + name = "pizza" + desc = "It's so stale you could probably cut something with the cheese." + icon = 'icons/obj/food/old/pizza.dmi' + +/obj/item/food/old/burger + name = "\improper Giga Burger!" + desc = "At some point in time this probably looked delicious." + icon = 'icons/obj/food/old/burger.dmi' + +/obj/item/food/old/hamburger + name = "\improper Horse Burger!" + desc = "Even if you were hungry enough to eat a horse, it'd be a bad idea to eat this." + icon = 'icons/obj/food/old/hamburger.dmi' + +/obj/item/food/old/fries + name = "chips" + desc = "The salt appears to have preserved these, still stale and gross." + icon = 'icons/obj/food/old/fries.dmi' + +/obj/item/food/old/hotdog + name = "hotdog" + desc = "This is probably only marginally less safe to eat than when it was first created." + icon = 'icons/obj/food/old/hotdog.dmi' + +/obj/item/food/old/taco + name = "taco" + desc = "Interestingly, the shell has gone soft and the contents have gone stale." + icon = 'icons/obj/food/old/taco.dmi' diff --git a/code/modules/reagents/reagent_containers/food/sandwich.dm b/code/modules/reagents/reagent_containers/food/sandwich.dm index fb53387081db..3b53ba0c7262 100644 --- a/code/modules/reagents/reagent_containers/food/sandwich.dm +++ b/code/modules/reagents/reagent_containers/food/sandwich.dm @@ -1,54 +1,58 @@ -/obj/item/chems/food/snacks/slice/bread/attackby(obj/item/W, mob/user) +/obj/item/food/slice/bread/attackby(obj/item/used_item, mob/user) - if(istype(W,/obj/item/shard) || istype(W,/obj/item/chems/food/snacks)) - var/obj/item/chems/food/snacks/csandwich/S = new(get_turf(src)) - S.attackby(W,user) + if(istype(used_item,/obj/item/shard) || istype(used_item,/obj/item/food)) + var/obj/item/food/csandwich/S = new() + S.dropInto(loc) + S.attackby(used_item,user) qdel(src) - ..() + return TRUE + return ..() -/obj/item/chems/food/snacks/csandwich +/obj/item/food/csandwich name = "sandwich" desc = "The best thing since sliced bread." - icon_state = "breadslice" - trash = /obj/item/trash/plate + icon = 'icons/obj/food/baked/bread/slices/plain.dmi' + plate = /obj/item/plate bitesize = 2 var/list/ingredients = list() -/obj/item/chems/food/snacks/csandwich/attackby(obj/item/W, mob/user) +/obj/item/food/csandwich/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/food) && !istype(used_item, /obj/item/shard)) + return ..() var/sandwich_limit = 4 for(var/obj/item/O in ingredients) - if(istype(O,/obj/item/chems/food/snacks/slice/bread)) + if(istype(O,/obj/item/food/slice/bread)) sandwich_limit += 4 if(src.contents.len > sandwich_limit) - to_chat(user, "If you put anything else on \the [src] it's going to collapse.") - return - else if(istype(W,/obj/item/shard)) - if(!user.unEquip(W, src)) - return - to_chat(user, "You hide [W] in \the [src].") - update() - return - else if(istype(W,/obj/item/chems/food/snacks)) - if(!user.unEquip(W, src)) - return - to_chat(user, "You layer [W] over \the [src].") - var/obj/item/chems/F = W - F.reagents.trans_to_obj(src, F.reagents.total_volume) - ingredients += W - update() - return - ..() + to_chat(user, "If you put anything else on \the [src] it's going to collapse.") + return TRUE + if(istype(used_item,/obj/item/shard)) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, "You hide [used_item] in \the [src].") + update_icon() + return TRUE + else if(istype(used_item,/obj/item/food)) + if(!user.try_unequip(used_item, src)) + return TRUE + to_chat(user, "You layer [used_item] over \the [src].") + var/obj/item/chems/F = used_item + F.reagents.trans_to_obj(src, REAGENT_TOTAL_VOLUME(F.reagents)) + ingredients += used_item + update_icon() + return TRUE + return FALSE // This shouldn't ever happen but okay. + +/obj/item/food/csandwich/on_update_icon() + . = ..() -/obj/item/chems/food/snacks/csandwich/proc/update() var/fullname = "" //We need to build this from the contents of the var. var/i = 0 - - overlays.Cut() - - for(var/obj/item/chems/food/snacks/O in ingredients) + var/image/I + for(var/obj/item/food/O in ingredients) i++ if(i == 1) @@ -58,44 +62,37 @@ else fullname += ", [O.name]" - var/image/I = new(src.icon, "sandwich_filling") + I = image(icon, "[icon_state]_filling") I.color = O.filling_color I.pixel_x = pick(list(-1,0,1)) I.pixel_y = (i*2)+1 - overlays += I + I.appearance_flags |= RESET_COLOR + add_overlay(I) - var/image/T = new(src.icon, "sandwich_top") - T.pixel_x = pick(list(-1,0,1)) - T.pixel_y = (ingredients.len * 2)+1 - overlays += T + I = image(icon, "[icon_state]_top") + I.pixel_x = pick(list(-1,0,1)) + I.pixel_y = (ingredients.len * 2)+1 + add_overlay(I) SetName(lowertext("[fullname] sandwich")) if(length(name) > 80) SetName("[pick(list("absurd","colossal","enormous","ridiculous"))] sandwich") - w_class = Ceiling(Clamp((ingredients.len/2),2,4)) + w_class = ceil(clamp((ingredients.len/2),2,4)) -/obj/item/chems/food/snacks/csandwich/Destroy() +/obj/item/food/csandwich/Destroy() for(var/obj/item/O in ingredients) qdel(O) - ..() + return ..() -/obj/item/chems/food/snacks/csandwich/examine(mob/user) +/obj/item/food/csandwich/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) var/obj/item/O = pick(contents) - to_chat(user, "You think you can see [O.name] in there.") - -/obj/item/chems/food/snacks/csandwich/attack(mob/M, mob/user, def_zone) - - var/obj/item/shard - for(var/obj/item/O in contents) - if(istype(O,/obj/item/shard)) - shard = O - break - - var/mob/living/H - if(istype(M,/mob/living)) - H = M - - if(H && shard && M == user) //This needs a check for feeding the food to other people, but that could be abusable. - to_chat(H, "You lacerate your mouth on a [shard.name] in the sandwich!") - H.adjustBruteLoss(5) //TODO: Target head if human. - ..() + . += SPAN_WARNING("You think you can see [O.name] in there.") + +/obj/item/food/csandwich/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + var/obj/item/shard = locate() in get_contained_external_atoms() // grab early in case of qdele + . = ..() + if(. && target == user) + //This needs a check for feeding the food to other people, but that could be abusable. + if(shard) + to_chat(target, SPAN_DANGER("You lacerate yourself on \a [shard] in \the [src]!")) + target.take_damage(5) //TODO: Target head if human. diff --git a/code/modules/reagents/reagent_containers/food/shaker.dm b/code/modules/reagents/reagent_containers/food/shaker.dm deleted file mode 100644 index dc33a6f9ea4e..000000000000 --- a/code/modules/reagents/reagent_containers/food/shaker.dm +++ /dev/null @@ -1,35 +0,0 @@ -/obj/item/chems/food/drinks/shaker - name = "shaker" - desc = "A three piece Cobbler-style shaker. Used to mix, cool, and strain drinks." - icon_state = "shaker" - amount_per_transfer_from_this = 10 - possible_transfer_amounts = @"[5,10,15,25,30,60]" //Professional bartender should be able to transfer as much as needed - volume = 120 - center_of_mass = @"{'x':17,'y':10}" - atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_REACT - -/obj/item/chems/food/drinks/shaker/attack_self(mob/user) - if(user.skill_check(SKILL_COOKING, SKILL_PROF)) - user.visible_message("\The [user] shakes \the [src] briskly in one hand, with supreme confidence and competence.", "You shake \the [src] briskly with one hand.") - mix() - return - if(user.skill_check(SKILL_COOKING, SKILL_ADEPT)) - user.visible_message(SPAN_NOTICE("\The [user] shakes \the [src] briskly, with some skill."), SPAN_NOTICE("You shake \the [src] briskly, with some skill.")) - mix() - return - else - user.visible_message(SPAN_NOTICE("\The [user] shakes \the [src] gingerly."), SPAN_NOTICE("You shake \the [src] gingerly.")) - if(prob(15) && (reagents && reagents.total_volume)) - user.visible_message(SPAN_WARNING("\The [user] spills the contents of \the [src] over themselves!"), SPAN_WARNING("You spill the contents of \the [src] over yourself!")) - reagents.splash(user, reagents.total_volume) - else - mix() - -/obj/item/chems/food/drinks/shaker/proc/mix() - if(reagents && reagents.total_volume) - atom_flags &= ~ATOM_FLAG_NO_REACT - HANDLE_REACTIONS(reagents) - addtimer(CALLBACK(src, .proc/stop_react), SSmaterials.wait) - -/obj/item/chems/food/drinks/shaker/proc/stop_react() - atom_flags |= ATOM_FLAG_NO_REACT \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/skewer.dm b/code/modules/reagents/reagent_containers/food/skewer.dm new file mode 100644 index 000000000000..1e6c64964f47 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/skewer.dm @@ -0,0 +1,32 @@ +/obj/item/food/skewer + abstract_type = /obj/item/food/skewer + icon = 'icons/obj/food/butchery/kabob.dmi' + trash = /obj/item/stack/material/rods + center_of_mass = @'{"x":17,"y":15}' + bitesize = 2 + nutriment_desc = list("tofu" = 3, "metal" = 1) + nutriment_amt = 8 + +/obj/item/food/skewer/on_reagent_change() + . = ..() + update_icon() + +/obj/item/food/skewer/on_update_icon() + . = ..() + var/decl/material/meat = reagents?.get_primary_reagent_decl() + if(meat) + add_overlay(overlay_image(icon, "[icon_state]_meat", meat.color, RESET_COLOR)) + +/obj/item/food/skewer/meat + name = "meat skewer" + desc = "Delicious meat, on a stick." + filling_color = "#a85340" + nutriment_type = /decl/material/solid/organic/meat + +/obj/item/food/skewer/tofu + name = "tofu skewer" + icon = 'icons/obj/food/butchery/kabob.dmi' + desc = "Vegan meat, on a stick." + trash = /obj/item/stack/material/rods + filling_color = "#fffee0" + center_of_mass = @'{"x":17,"y":15}' diff --git a/code/modules/reagents/reagent_containers/food/sliceable/_sliceable.dm b/code/modules/reagents/reagent_containers/food/sliceable/_sliceable.dm new file mode 100644 index 000000000000..83dc713862a8 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/_sliceable.dm @@ -0,0 +1,41 @@ +/////////////// +// Sliceable // +/////////////// +// All the food items that can be sliced into smaller bits like meatbread and cheesewheels + +// sliceable is just an organization type path, it doesn't have any additional code or variables tied to it. + +/obj/item/food/sliceable + abstract_type = /obj/item/food/sliceable + w_class = ITEM_SIZE_NORMAL //whole pizzas and cakes shouldn't fit in a pocket, you can slice them if you want to do that. + utensil_flags = UTENSIL_FLAG_COLLECT | UTENSIL_FLAG_SLICE + +/** + * A food item slice + * + * This path contains some extra code for spawning slices pre-filled with + * reagents. + */ +/obj/item/food/slice + name = "slice of... something" + abstract_type = /obj/item/food/slice + var/whole_path // path for the item from which this slice comes + var/filled = FALSE // should the slice spawn with any reagents + +/** + * Spawn a new slice of food + * + * If the slice's filled is TRUE, this will also fill the slice with the + * appropriate amount of reagents. Note that this is done by spawning a new + * whole item, transferring the reagents and deleting the whole item, which may + * have performance implications. + */ +/obj/item/food/slice/Initialize(mapload, material_key, skip_plate = FALSE) + . = ..() + if(filled) + var/obj/item/food/whole = new whole_path() + if(whole && whole.slice_num) + var/reagent_amount = REAGENT_TOTAL_VOLUME(whole.reagents)/whole.slice_num + whole.reagents.trans_to_obj(src, reagent_amount) + + qdel(whole) diff --git a/code/modules/reagents/reagent_containers/food/sliceable/cakes.dm b/code/modules/reagents/reagent_containers/food/sliceable/cakes.dm new file mode 100644 index 000000000000..a59b23872aee --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/cakes.dm @@ -0,0 +1,269 @@ +/obj/item/food/sliceable/carrotcake + name = "carrot cake" + desc = "A favorite desert of sophisticated rabbits." + icon = 'icons/obj/food/baked/cakes/carrot.dmi' + slice_path = /obj/item/food/slice/carrotcake + slice_num = 5 + filling_color = "#ffd675" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "carrot" = 15) + nutriment_amt = 25 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/sliceable/carrotcake/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/eyedrops, 10) + +/obj/item/food/slice/carrotcake + name = "carrot cake slice" + desc = "Carrot-y slice of carrot cake, carrots are good for your eyes! It's true! Probably!" + icon = 'icons/obj/food/baked/cakes/slices/carrot.dmi' + plate = /obj/item/plate + filling_color = "#ffd675" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/carrotcake + +/obj/item/food/slice/carrotcake/filled + filled = TRUE + +/obj/item/food/sliceable/braincake + name = "brain cake" + desc = "A squishy cake-thing." + icon = 'icons/obj/food/baked/cakes/brain.dmi' + slice_path = /obj/item/food/slice/braincake + slice_num = 5 + filling_color = "#e6aedb" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "slime" = 15) + nutriment_amt = 5 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/sliceable/braincake/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 25) + add_to_reagents(/decl/material/liquid/neuroannealer, 10) + +/obj/item/food/slice/braincake + name = "brain cake slice" + desc = "Lemme tell you something about prions. THEY'RE DELICIOUS." + icon = 'icons/obj/food/baked/cakes/slices/brain.dmi' + plate = /obj/item/plate + filling_color = "#e6aedb" + bitesize = 2 + center_of_mass = @'{"x":16,"y":12}' + whole_path = /obj/item/food/sliceable/braincake + +/obj/item/food/slice/braincake/filled + filled = TRUE + +/obj/item/food/sliceable/cheesecake + name = "cheese cake" + desc = "DANGEROUSLY cheesy." + icon = 'icons/obj/food/baked/cakes/cheese.dmi' + slice_path = /obj/item/food/slice/cheesecake + slice_num = 5 + filling_color = "#faf7af" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "cream" = 10, "cheese" = 15) + nutriment_amt = 10 + bitesize = 2 + +/obj/item/food/sliceable/cheesecake/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 15) + +/obj/item/food/slice/cheesecake + name = "cheese cake slice" + desc = "Slice of pure cheesatisfaction." + icon = 'icons/obj/food/baked/cakes/slices/cheese.dmi' + plate = /obj/item/plate + filling_color = "#faf7af" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/cheesecake + +/obj/item/food/slice/cheesecake/filled + filled = TRUE + +/obj/item/food/sliceable/plaincake + name = "vanilla cake" + desc = "A plain cake, but a good cake." + icon = 'icons/obj/food/baked/cakes/plain.dmi' + slice_path = /obj/item/food/slice/plaincake + slice_num = 5 + filling_color = "#f7edd5" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "vanilla" = 15) + nutriment_amt = 20 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/slice/plaincake + name = "vanilla cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon = 'icons/obj/food/baked/cakes/slices/plain.dmi' + plate = /obj/item/plate + filling_color = "#f7edd5" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/plaincake + +/obj/item/food/slice/plaincake/filled + filled = TRUE + +/obj/item/food/sliceable/orangecake + name = "orange cake" + desc = "A cake with added orange." + icon = 'icons/obj/food/baked/cakes/orange.dmi' + slice_path = /obj/item/food/slice/orangecake + slice_num = 5 + filling_color = "#fada8e" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "oranges" = 15) + nutriment_amt = 20 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/slice/orangecake + name = "orange cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon = 'icons/obj/food/baked/cakes/slices/orange.dmi' + plate = /obj/item/plate + filling_color = "#fada8e" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/orangecake + +/obj/item/food/slice/orangecake/filled + filled = TRUE + +/obj/item/food/sliceable/limecake + name = "lime cake" + desc = "A cake with added lime." + icon = 'icons/obj/food/baked/cakes/lime.dmi' + slice_path = /obj/item/food/slice/limecake + slice_num = 5 + filling_color = "#cbfa8e" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "lime" = 15) + nutriment_amt = 20 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/slice/limecake + name = "lime cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon = 'icons/obj/food/baked/cakes/slices/lime.dmi' + plate = /obj/item/plate + filling_color = "#cbfa8e" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/limecake + +/obj/item/food/slice/limecake/filled + filled = TRUE + +/obj/item/food/sliceable/lemoncake + name = "lemon cake" + desc = "A cake with added lemon." + icon = 'icons/obj/food/baked/cakes/lemon.dmi' + slice_path = /obj/item/food/slice/lemoncake + slice_num = 5 + filling_color = "#fafa8e" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "lemon" = 15) + nutriment_amt = 20 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/slice/lemoncake + name = "lemon cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon = 'icons/obj/food/baked/cakes/slices/lemon.dmi' + plate = /obj/item/plate + filling_color = "#fafa8e" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/lemoncake + +/obj/item/food/slice/lemoncake/filled + filled = TRUE + +/obj/item/food/sliceable/chocolatecake + name = "chocolate cake" + desc = "A cake with added chocolate." + icon = 'icons/obj/food/baked/cakes/chocolate.dmi' + slice_path = /obj/item/food/slice/chocolatecake + slice_num = 5 + filling_color = "#805930" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "chocolate" = 15) + nutriment_amt = 20 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/slice/chocolatecake + name = "chocolate cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon = 'icons/obj/food/baked/cakes/slices/chocolate.dmi' + plate = /obj/item/plate + filling_color = "#805930" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/chocolatecake + +/obj/item/food/slice/chocolatecake/filled + filled = TRUE + +/obj/item/food/sliceable/birthdaycake + name = "birthday cake" + desc = "Happy birthday!" + icon = 'icons/obj/food/baked/cakes/birthday.dmi' + slice_path = /obj/item/food/slice/birthdaycake + slice_num = 5 + filling_color = "#ffd6d6" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10) + nutriment_amt = 20 + bitesize = 3 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/sliceable/birthdaycake/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/sprinkles, 10) + +/obj/item/food/slice/birthdaycake + name = "birthday cake slice" + desc = "A slice of your birthday." + icon = 'icons/obj/food/baked/cakes/slices/birthday.dmi' + plate = /obj/item/plate + filling_color = "#ffd6d6" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/birthdaycake + +/obj/item/food/slice/birthdaycake/filled + filled = TRUE + +/obj/item/food/sliceable/applecake + name = "apple cake" + desc = "A cake centred with apples." + icon = 'icons/obj/food/baked/cakes/apple.dmi' + slice_path = /obj/item/food/slice/applecake + slice_num = 5 + filling_color = "#ebf5b8" + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("cake" = 10, "sweetness" = 10, "apple" = 15) + nutriment_amt = 15 + nutriment_type = /decl/material/liquid/nutriment/bread/cake + +/obj/item/food/slice/applecake + name = "apple cake slice" + desc = "A slice of heavenly cake." + icon = 'icons/obj/food/baked/cakes/slices/apple.dmi' + plate = /obj/item/plate + filling_color = "#ebf5b8" + bitesize = 2 + center_of_mass = @'{"x":16,"y":14}' + whole_path = /obj/item/food/sliceable/applecake + +/obj/item/food/slice/applecake/filled + filled = TRUE diff --git a/code/modules/reagents/reagent_containers/food/sliceable/loaves.dm b/code/modules/reagents/reagent_containers/food/sliceable/loaves.dm new file mode 100644 index 000000000000..5fa0639bbe71 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/loaves.dm @@ -0,0 +1,172 @@ +/obj/item/food/sliceable/meatbread + name = "meatbread loaf" + desc = "The culinary base of every self-respecting eloquent gentleman." + icon = 'icons/obj/food/baked/bread/meat.dmi' + slice_path = /obj/item/food/slice/meatbread + slice_num = 5 + filling_color = "#ff7575" + center_of_mass = @'{"x":19,"y":9}' + nutriment_desc = list("bread" = 10) + nutriment_amt = 10 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/sliceable/meatbread/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 20) + +/obj/item/food/slice/meatbread + name = "meatbread slice" + desc = "A slice of delicious meatbread." + icon = 'icons/obj/food/baked/bread/slices/meat.dmi' + plate = /obj/item/plate + filling_color = "#ff7575" + bitesize = 2 + center_of_mass = @'{"x":16,"y":13}' + whole_path = /obj/item/food/sliceable/meatbread + +/obj/item/food/slice/meatbread/filled + filled = TRUE + +/obj/item/food/sliceable/xenomeatbread + name = "xenomeatbread loaf" + desc = "The culinary base of every self-respecting eloquent gentleman. Extra heretical." + icon = 'icons/obj/food/baked/bread/xeno.dmi' + slice_path = /obj/item/food/slice/xenomeatbread + slice_num = 5 + filling_color = "#8aff75" + center_of_mass = @'{"x":16,"y":9}' + nutriment_desc = list("bread" = 10) + nutriment_amt = 10 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/sliceable/xenomeatbread/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat/xeno, 20) + +/obj/item/food/slice/xenomeatbread + name = "xenomeatbread slice" + desc = "A slice of delicious meatbread. Extra Heretical." + icon = 'icons/obj/food/baked/bread/slices/xeno.dmi' + plate = /obj/item/plate + filling_color = "#8aff75" + bitesize = 2 + center_of_mass = @'{"x":16,"y":13}' + whole_path = /obj/item/food/sliceable/xenomeatbread + +/obj/item/food/slice/xenomeatbread/filled + filled = TRUE + +/obj/item/food/sliceable/bananabread + name = "banana-nut bread" + desc = "A heavenly and filling treat." + icon = 'icons/obj/food/baked/bread/banana.dmi' + slice_path = /obj/item/food/slice/bananabread + slice_num = 5 + filling_color = "#ede5ad" + center_of_mass = @'{"x":16,"y":9}' + nutriment_desc = list("bread" = 10) + nutriment_amt = 10 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/sliceable/bananabread/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/banana_cream, 20) + +/obj/item/food/slice/bananabread + name = "banana-nut bread slice" + desc = "A slice of delicious banana bread." + icon = 'icons/obj/food/baked/bread/slices/banana.dmi' + plate = /obj/item/plate + filling_color = "#ede5ad" + bitesize = 2 + center_of_mass = @'{"x":16,"y":8}' + whole_path = /obj/item/food/sliceable/bananabread + +/obj/item/food/slice/bananabread/filled + filled = TRUE + +/obj/item/food/sliceable/tofubread + name = "tofubread" + desc = "Like meatbread but for vegetarians. Not guaranteed to give superpowers." + icon = 'icons/obj/food/baked/bread/tofu.dmi' + slice_path = /obj/item/food/slice/tofubread + slice_num = 5 + filling_color = "#f7ffe0" + center_of_mass = @'{"x":16,"y":9}' + nutriment_desc = list("tofu" = 10) + nutriment_amt = 10 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/slice/tofubread + name = "tofubread slice" + desc = "A slice of delicious tofubread." + icon = 'icons/obj/food/baked/bread/slices/tofu.dmi' + plate = /obj/item/plate + filling_color = "#f7ffe0" + bitesize = 2 + center_of_mass = @'{"x":16,"y":13}' + whole_path = /obj/item/food/sliceable/tofubread + +/obj/item/food/slice/tofubread/filled + filled = TRUE + +/obj/item/food/sliceable/bread + name = "bread" + desc = "Some plain old bread." + icon = 'icons/obj/food/baked/bread/plain.dmi' + slice_path = /obj/item/food/slice/bread + slice_num = 5 + filling_color = "#ffe396" + center_of_mass = @'{"x":16,"y":9}' + nutriment_desc = list("bread" = 6) + nutriment_amt = 6 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/slice/bread + name = "bread slice" + desc = "A slice of home." + icon = 'icons/obj/food/baked/bread/slices/plain.dmi' + plate = /obj/item/plate + filling_color = "#d27332" + bitesize = 2 + center_of_mass = @'{"x":16,"y":4}' + whole_path = /obj/item/food/sliceable/bread + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/slice/bread/filled + filled = TRUE + +/obj/item/food/sliceable/creamcheesebread + name = "cream cheese bread" + desc = "Yum yum yum!" + icon = 'icons/obj/food/baked/bread/cheese.dmi' + slice_path = /obj/item/food/slice/creamcheesebread + slice_num = 5 + filling_color = "#fff896" + center_of_mass = @'{"x":16,"y":9}' + nutriment_desc = list("bread" = 6, "cream" = 3, "cheese" = 3) + nutriment_amt = 5 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + +/obj/item/food/sliceable/creamcheesebread/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 15) + +/obj/item/food/slice/creamcheesebread + name = "cream cheese bread slice" + desc = "A slice of yum!" + icon = 'icons/obj/food/baked/bread/slices/cheese.dmi' + plate = /obj/item/plate + filling_color = "#fff896" + bitesize = 2 + center_of_mass = @'{"x":16,"y":13}' + whole_path = /obj/item/food/sliceable/creamcheesebread + +/obj/item/food/slice/creamcheesebread/filled + filled = TRUE diff --git a/code/modules/reagents/reagent_containers/food/sliceable/pizza/_pizza.dm b/code/modules/reagents/reagent_containers/food/sliceable/pizza/_pizza.dm new file mode 100644 index 000000000000..8d0d6c15ae2d --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/pizza/_pizza.dm @@ -0,0 +1,32 @@ +/obj/item/food/sliceable/pizza + icon_state = ICON_STATE_WORLD + slice_num = 6 + nutriment_amt = 25 + bitesize = 2 + nutriment_type = /decl/material/liquid/nutriment/bread + center_of_mass = @'{"x":16,"y":11}' + filling_color = "#baa14c" + abstract_type = /obj/item/food/sliceable/pizza + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15) + var/ruined = FALSE // Visual only, doesn't actually impact the edibility or sliceability of the pizza. + +/obj/item/food/sliceable/pizza/proc/ruin() + if(!ruined) + ruined = TRUE + name = "ruined [name]" + update_icon() + +/obj/item/food/sliceable/pizza/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(ruined) + var/ruined_state = "[icon_state]_ruined" + if(check_state_in_icon(ruined_state, icon)) + icon_state = ruined_state + +/obj/item/food/slice/pizza + icon = 'icons/obj/food/pizzas/pizza_slices.dmi' + filling_color = "#baa14c" + bitesize = 2 + center_of_mass = @'{"x":18,"y":13}' + abstract_type = /obj/item/food/slice/pizza diff --git a/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_box.dm b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_box.dm new file mode 100644 index 000000000000..759e2fd3b7c6 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_box.dm @@ -0,0 +1,338 @@ +/obj/item/pizzabox + name = "pizza box" + desc = "A box suited for pizzas." + icon = 'icons/obj/food/containers/pizzabox.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/organic/cardboard + + var/const/RISKY_PIZZA_STACK = 6 + var/const/MAXIMUM_PIZZA_STACK = 15 + var/open = FALSE // Is the box open? + var/image/messy_overlay + var/obj/item/food/sliceable/pizza/pizza + var/list/obj/item/pizzabox/stacked_boxes + var/box_tag + var/box_tag_color = COLOR_BLACK + +/obj/item/pizzabox/Initialize(ml, material_key) + . = ..() + if(ispath(pizza)) + pizza = new pizza(src) + if(open) + open = FALSE + toggle_open() + else if(box_tag || pizza) + update_strings() + update_icon() + // We care about our own moved event in case of structural failure. + events_repository.register(/decl/observ/moved, src, src, PROC_REF(check_stack_failure)) + +/obj/item/pizzabox/Destroy() + events_repository.unregister(/decl/observ/moved, src, src) + return ..() + +/obj/item/pizzabox/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && length(stacked_boxes)) + var/i = 1 + for(var/obj/item/pizzabox/box in stacked_boxes) + var/image/overlay_image = box.get_mob_overlay(user_mob, slot, bodypart, use_fallback_if_icon_missing, TRUE) + if(overlay_image) + overlay_image.pixel_y = i * 3 + overlay_image.pixel_x = pick(-1,0,1) + overlay.overlays += overlay_image + i++ + . = ..() + +// Tossing a pizza around can have terrible effects... +/obj/item/pizzabox/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + ..() + return FALSE + +/obj/item/pizzabox/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(proximity_flag && user?.check_intent(I_FLAG_HARM) && user != target) + jostle_pizza() + explode_stack() + +/obj/item/pizzabox/proc/jostle_pizza() + if(pizza && !pizza.ruined && prob(20)) + pizza.ruin() + if(!open && prob(30)) + toggle_open() + else + if(open) + update_icon() + update_strings() + +/obj/item/pizzabox/proc/explode_stack() + var/turf/our_turf = get_turf(src) + if(!our_turf || !LAZYLEN(stacked_boxes)) + return + while(LAZYLEN(stacked_boxes)) + var/obj/item/pizzabox/top_box = stacked_boxes[LAZYLEN(stacked_boxes)] + LAZYREMOVE(stacked_boxes, top_box) + top_box.throw_at(get_edge_target_turf(our_turf, pick(global.alldirs)), 1, 1) // just enough to bonk people + update_strings() + update_icon() + if(ismob(loc)) + var/mob/owner = loc + owner.update_inhand_overlays() + +// This is disgusting, but I can't work out a good way to catch +// the end of a throw regardless of whether or not it hit something. +/obj/item/pizzabox/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, datum/callback/callback) + . = ..() + wait_for_throw_end_then_spill() + +/obj/item/pizzabox/proc/wait_for_throw_end_then_spill() + set waitfor = FALSE + while(!QDELETED(throwing)) + sleep(1) + if(QDELETED(src)) + return + jostle_pizza() + explode_stack() + +/obj/item/pizzabox/proc/check_stack_failure() + + if(isobj(loc) || LAZYLEN(stacked_boxes)+1 < RISKY_PIZZA_STACK) + return // no stack, no worries + + var/fell_off = 0 + var/turf/our_turf = get_turf(src) + if(!isturf(our_turf)) + return // shouldn't happen due to checks above + + var/mob/mover = loc + var/moving_deliberately = ismob(mover) && MOVING_DELIBERATELY(mover) + while(LAZYLEN(stacked_boxes)+1 > RISKY_PIZZA_STACK) + var/danger_zone = ((LAZYLEN(stacked_boxes)+1)-RISKY_PIZZA_STACK) * 10 + if(moving_deliberately) + danger_zone *= 0.5 + if(danger_zone <= 0 || !prob(danger_zone)) + break // we are safe... for now... + var/obj/item/pizzabox/top_box = stacked_boxes[LAZYLEN(stacked_boxes)] + LAZYREMOVE(stacked_boxes, top_box) + top_box.dropInto(our_turf) + top_box.throw_at(get_edge_target_turf(our_turf, pick(global.alldirs)), 1, 1) // just enough to bonk people + fell_off++ + if(fell_off > 0) + our_turf.visible_message(SPAN_DANGER("[fell_off] [fell_off == 1 ? "pizza" : "pizzas"] [fell_off == 1 ? "falls" : "fall"] off the stack!")) + update_strings() + update_icon() + if(ismob(mover)) + mover.update_inhand_overlays() + else if(prob(15) && ismob(mover)) + to_chat(loc, SPAN_WARNING("The stack of pizza boxes sways alarmingly...")) + +/obj/item/pizzabox/proc/toggle_open() + if(LAZYLEN(stacked_boxes)) + return FALSE + open = !open + if(open && pizza && !messy_overlay) + var/mess_state = "[pizza.icon_state]_mess" + if(check_state_in_icon(mess_state, pizza.icon)) + messy_overlay = image(pizza.icon, mess_state) + update_icon() + compile_overlays() // to avoid our tags and messy state flickering + return TRUE + +/obj/item/pizzabox/proc/update_strings() + name = initial(name) + var/list/desc_strings = list(initial(desc)) + if(open && pizza) + desc_strings += "It appears to have \a [pizza] inside." + else if(length(stacked_boxes)) + name = "stack of pizza boxes" + desc_strings += "A pile of boxes suited for pizzas. There appears to be [length(stacked_boxes)+1] boxes in the pile." + var/obj/item/pizzabox/topbox = stacked_boxes[length(stacked_boxes)] + if(topbox?.box_tag) + desc_strings += "The box on top has a tag reading: '[topbox.box_tag]'." + else if(box_tag) + desc_strings += "The box has a tag reading: '[box_tag]'." + desc = jointext(desc_strings, " ") + +/obj/item/pizzabox/on_update_icon() + . = ..() + // Update our own appearance. + icon_state = get_world_inventory_state() + if(open) + icon_state = "[icon_state]_open" + if(messy_overlay) + add_overlay(messy_overlay) + if(pizza) + var/mutable_appearance/pizzaimg = new(pizza) + pizzaimg.layer = FLOAT_LAYER + pizzaimg.plane = FLOAT_PLANE + pizzaimg.pixel_x = 0 + pizzaimg.pixel_y = -3 + pizzaimg.pixel_z = 0 + pizzaimg.pixel_w = 0 + add_overlay(pizzaimg) + return + + // If we're closed, draw our tag and all the pizzas in the stack. + if(box_tag) + add_overlay(overlay_image(icon, "[icon_state]_tag", box_tag_color, RESET_COLOR)) + + // Add all the boxes in the stack. + var/i = 1 + for(var/obj/item/pizzabox/pizza_box in stacked_boxes) + var/mutable_appearance/box_img = new(pizza_box) + box_img.layer = FLOAT_LAYER + box_img.plane = FLOAT_PLANE + box_img.pixel_y = i * 3 + pick(-1,0,1) + box_img.pixel_x = pick(-1,0,1) + box_img.pixel_z = 0 + box_img.pixel_w = 0 + add_overlay(box_img) + i++ + +/obj/item/pizzabox/attack_hand(mob/user) + + if(open && pizza && !user.check_intent(I_FLAG_GRAB)) + if(user.check_dexterity(DEXTERITY_HOLD_ITEM)) + user.put_in_hands(pizza) + to_chat(user, SPAN_NOTICE("You take \the [pizza] out of \the [src].")) + pizza = null + update_icon() + return TRUE + + var/box_count = LAZYLEN(stacked_boxes) + if(box_count && user.is_holding_offhand(src) && user.check_dexterity(DEXTERITY_HOLD_ITEM)) + var/obj/item/pizzabox/box = stacked_boxes[box_count] + LAZYREMOVE(stacked_boxes, box) + user.put_in_hands(box) + to_chat(user, SPAN_WARNING("You remove the topmost [src] from your hand.")) + + if((LAZYLEN(stacked_boxes)+1) == (RISKY_PIZZA_STACK-1)) + to_chat(user, SPAN_NOTICE("The stack looks a bit more stable. It's probably safe to carry now.")) + + box.update_icon() + box.update_strings() + update_icon() + update_strings() + return TRUE + + return ..() + +/obj/item/pizzabox/attack_self(mob/user) + if(toggle_open()) + return TRUE + return ..() + +/obj/item/pizzabox/attackby(obj/item/used_item, mob/user) + + // Stacking pizza boxes. + if(istype(used_item, /obj/item/pizzabox)) + var/obj/item/pizzabox/box = used_item + if(box.open) + to_chat(user, SPAN_WARNING("You need to close \the [box] first!")) + return TRUE + + if(open) + to_chat(user, SPAN_WARNING("You need to close \the [src] first!")) + return TRUE + + var/stack_count = (LAZYLEN(stacked_boxes) + LAZYLEN(box.stacked_boxes) + 2) + if(stack_count > MAXIMUM_PIZZA_STACK) + to_chat(user, SPAN_WARNING("That pizza stack would be too high!")) + return TRUE + + if(!user.try_unequip(box, src)) + return TRUE + + LAZYDISTINCTADD(stacked_boxes, box) + if(box.stacked_boxes) + LAZYDISTINCTADD(stacked_boxes, box.stacked_boxes) + LAZYCLEARLIST(box.stacked_boxes) + update_icon() + update_strings() + box.update_icon() + box.update_strings() + + user.visible_message(SPAN_NOTICE("\The [user] stacks \the [box] on top of \the [src].")) + if(stack_count == RISKY_PIZZA_STACK) + to_chat(user, SPAN_WARNING("The stack sags a bit. You have a bad feeling about carrying it...")) + + return TRUE + + // Putting a pizza back in the box. + if(istype(used_item, /obj/item/food/sliceable/pizza)) + + if(!open) + to_chat(user, SPAN_WARNING("Open \the [src] first!")) + return TRUE + + if(pizza) + to_chat(user, SPAN_WARNING("\The [src] already has \the [pizza] inside!")) + return TRUE + + if(!user.try_unequip(used_item, src)) + return TRUE + + pizza = used_item + update_strings() + update_icon() + user.visible_message(SPAN_NOTICE("\The [user] slides \the [used_item] into \the [src].")) + return TRUE + + // Appending to the tag. + if(IS_PEN(used_item)) + + if(open) + to_chat(user, SPAN_WARNING("Close \the [src] first!")) + return TRUE + + var/tag_string = sanitize(input("Enter what you want to add to the tag.", "Write", null, null) as text|null, 30) + if(!CanPhysicallyInteract(user) || !tag_string || open) + return TRUE + + var/box_count = LAZYLEN(stacked_boxes) + var/obj/item/pizzabox/tagging_box = (box_count > 0) ? stacked_boxes[box_count] : src + tagging_box.box_tag = copytext("[tagging_box.box_tag][tag_string]", 1, 30) + tagging_box.box_tag_color = used_item.get_tool_property(TOOL_PEN, TOOL_PROP_COLOR) || COLOR_BLACK + user.visible_message(SPAN_NOTICE("\The [user] writes something on \the [src].")) + update_strings() + update_icon() + return TRUE + + return ..() + +/obj/item/pizzabox/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/open_pizza_box) + +/decl/interaction_handler/open_pizza_box + expected_target_type = /obj/item/pizzabox + examine_desc = "open or close $TARGET_THEM$" + +/decl/interaction_handler/open_pizza_box/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() + if(.) + var/obj/item/pizzabox/box = target + . = LAZYLEN(box.stacked_boxes) <= 0 + +/decl/interaction_handler/open_pizza_box/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/pizzabox/box = target + box.toggle_open() + +// Subtypes below. +/obj/item/pizzabox/margherita + pizza = /obj/item/food/sliceable/pizza/margherita + box_tag = "Margherita Deluxe" + box_tag_color = COLOR_DARK_RED + +/obj/item/pizzabox/vegetable + pizza = /obj/item/food/sliceable/pizza/vegetablepizza + box_tag = "Gourmet Vegetable" + box_tag_color = COLOR_PAKISTAN_GREEN + +/obj/item/pizzabox/mushroom + pizza = /obj/item/food/sliceable/pizza/mushroompizza + box_tag = "Mushroom Special" + box_tag_color = COLOR_PURPLE_GRAY + +/obj/item/pizzabox/meat + pizza = /obj/item/food/sliceable/pizza/meatpizza + box_tag = "Meatlover's Supreme" + box_tag_color = COLOR_BROWN_ORANGE diff --git a/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_margherita.dm b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_margherita.dm new file mode 100644 index 000000000000..2b508bd4f7e7 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_margherita.dm @@ -0,0 +1,19 @@ +/obj/item/food/sliceable/pizza/margherita + name = "margherita" + desc = "The golden standard of pizzas." + slice_path = /obj/item/food/slice/pizza/margherita + icon = 'icons/obj/food/pizzas/pizza_margherita.dmi' + +/obj/item/food/sliceable/pizza/margherita/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 5) + add_to_reagents(/decl/material/liquid/drink/juice/tomato, 6) + +/obj/item/food/slice/pizza/margherita + name = "margherita slice" + desc = "A slice of the classic pizza." + icon_state = "pizzamargheritaslice" + whole_path = /obj/item/food/sliceable/pizza/margherita + +/obj/item/food/slice/pizza/margherita/filled + filled = TRUE diff --git a/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_meat.dm b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_meat.dm new file mode 100644 index 000000000000..68b216622526 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_meat.dm @@ -0,0 +1,20 @@ +/obj/item/food/sliceable/pizza/meatpizza + name = "meatpizza" + desc = "A pizza with meat topping." + slice_path = /obj/item/food/slice/pizza/meat + nutriment_amt = 10 + icon = 'icons/obj/food/pizzas/pizza_meat.dmi' + +/obj/item/food/sliceable/pizza/meatpizza/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 34) + add_to_reagents(/decl/material/liquid/nutriment/barbecue, 6) + +/obj/item/food/slice/pizza/meat + name = "meatpizza slice" + desc = "A slice of a meaty pizza." + icon_state = "meatpizzaslice" + whole_path = /obj/item/food/sliceable/pizza/meatpizza + +/obj/item/food/slice/pizza/meat/filled + filled = TRUE diff --git a/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_mushroom.dm b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_mushroom.dm new file mode 100644 index 000000000000..efc185318166 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_mushroom.dm @@ -0,0 +1,19 @@ +/obj/item/food/sliceable/pizza/mushroompizza + name = "mushroompizza" + desc = "Very special pizza." + slice_path = /obj/item/food/slice/pizza/mushroom + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "mushroom" = 10) + icon = 'icons/obj/food/pizzas/pizza_mushroom.dmi' + +/obj/item/food/sliceable/pizza/mushroompizza/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 5) + +/obj/item/food/slice/pizza/mushroom + name = "mushroompizza slice" + desc = "Maybe it is the last slice of pizza in your life." + icon_state = "mushroompizzaslice" + whole_path = /obj/item/food/sliceable/pizza/mushroompizza + +/obj/item/food/slice/pizza/mushroom/filled + filled = TRUE diff --git a/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_vegetable.dm b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_vegetable.dm new file mode 100644 index 000000000000..f2003f94b10c --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sliceable/pizza/pizza_vegetable.dm @@ -0,0 +1,21 @@ +/obj/item/food/sliceable/pizza/vegetablepizza + name = "vegetable pizza" + desc = "Vegetarian pizza, huh? What about all the plants that were slaughtered to make this, huh!? Hypocrite." + slice_path = /obj/item/food/slice/pizza/vegetable + nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "eggplant" = 5, "carrot" = 5, "corn" = 5) + icon = 'icons/obj/food/pizzas/pizza_vegetable.dmi' + +/obj/item/food/sliceable/pizza/vegetablepizza/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/cheese, 5) + add_to_reagents(/decl/material/liquid/nutriment/ketchup, 6) + add_to_reagents(/decl/material/liquid/eyedrops, 12) + +/obj/item/food/slice/pizza/vegetable + name = "vegetable pizza slice" + desc = "A slice of the most green pizza of all pizzas not containing green ingredients." + icon_state = "vegetablepizzaslice" + whole_path = /obj/item/food/sliceable/pizza/vegetablepizza + +/obj/item/food/slice/pizza/vegetable/filled + filled = TRUE diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm deleted file mode 100644 index 33534bd3917d..000000000000 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ /dev/null @@ -1,3815 +0,0 @@ -//Food items that are eaten normally and don't leave anything behind. - - -/obj/item/chems/food/snacks - name = "snack" - desc = "Yummy!" - icon = 'icons/obj/food.dmi' - icon_state = null - var/bitesize = 1 - var/bitecount = 0 - var/slice_path - var/slices_num - var/dried_type = null - var/dry = 0 - var/nutriment_amt = 0 - var/nutriment_type = /decl/material/liquid/nutriment // Used to determine which base nutriment type is spawned for this item. - var/list/nutriment_desc = list("food" = 1) // List of flavours and flavour strengths. The flavour strength text is determined by the ratio of flavour strengths in the snack. - var/list/eat_sound = 'sound/items/eatfood.ogg' - center_of_mass = @"{'x':16,'y':16}" - w_class = ITEM_SIZE_SMALL - -/obj/item/chems/food/snacks/Initialize() - .=..() - if(nutriment_amt) - reagents.add_reagent(nutriment_type, nutriment_amt, nutriment_desc) - - //Placeholder for effect that trigger on eating that aren't tied to reagents. -/obj/item/chems/food/snacks/proc/On_Consume(var/mob/M) - if(!reagents.total_volume) - M.visible_message("[M] finishes eating \the [src].","You finish eating \the [src].") - M.drop_item() - M.update_personal_goal(/datum/goal/achievement/specific_object/food, type) - if(trash) - if(ispath(trash,/obj/item)) - var/obj/item/TrashItem = new trash(get_turf(M)) - M.put_in_hands(TrashItem) - else if(istype(trash,/obj/item)) - M.put_in_hands(trash) - qdel(src) - return - -/obj/item/chems/food/snacks/attack_self(mob/user) - attack(user, user) - -/obj/item/chems/food/snacks/dragged_onto(var/mob/user) - attack(user, user) - -/obj/item/chems/food/snacks/attack(mob/M, mob/user, def_zone) - if(!reagents || !reagents.total_volume) - to_chat(user, "None of [src] left!") - qdel(src) - return 0 - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "\The [src] isn't open!") - return 0 - if(istype(M, /mob/living/carbon)) - //TODO: replace with standard_feed_mob() call. - var/mob/living/carbon/C = M - var/fullness = C.get_fullness() - if(C == user) //If you're eating it yourself - if(istype(C,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(!H.check_has_mouth()) - to_chat(user, "Where do you intend to put \the [src]? You don't have a mouth!") - return - var/obj/item/blocked = H.check_mouth_coverage() - if(blocked) - to_chat(user, "\The [blocked] is in the way!") - return - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)//puts a limit on how fast people can eat/drink things - if (fullness <= 50) - to_chat(C, "You hungrily chew out a piece of [src] and gobble it!") - if (fullness > 50 && fullness <= 150) - to_chat(C, "You hungrily begin to eat [src].") - if (fullness > 150 && fullness <= 350) - to_chat(C, "You take a bite of [src].") - if (fullness > 350 && fullness <= 550) - to_chat(C, "You unwillingly chew a bit of [src].") - if (fullness > 550) - to_chat(C, "You cannot force any more of [src] to go down your throat.") - return 0 - else - if(!M.can_force_feed(user, src)) - return - - if (fullness <= 550) - user.visible_message("[user] attempts to feed [M] [src].") - else - user.visible_message("[user] cannot force anymore of [src] down [M]'s throat.") - return 0 - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!do_mob(user, M)) return - - var/contained = REAGENT_LIST(src) - admin_attack_log(user, M, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") - user.visible_message("[user] feeds [M] [src].") - - if(reagents) //Handle ingestion of the reagent. - if(eat_sound) - playsound(M, pick(eat_sound), rand(10, 50), 1) - if(reagents.total_volume) - if(reagents.total_volume > bitesize) - reagents.trans_to_mob(M, bitesize, CHEM_INGEST) - else - reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) - bitecount++ - On_Consume(M) - return 1 - - return 0 - -/obj/item/chems/food/snacks/examine(mob/user, distance) - . = ..() - if(distance > 1) - return - if (bitecount==0) - return - else if (bitecount==1) - to_chat(user, "\The [src] was bitten by someone!") - else if (bitecount<=3) - to_chat(user, "\The [src] was bitten [bitecount] time\s!") - else - to_chat(user, "\The [src] was bitten multiple times!") - -/obj/item/chems/food/snacks/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/storage)) - ..()// -> item/attackby() - return - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "\The [src] isn't open!") - return 0 - // Eating with forks - if(istype(W,/obj/item/kitchen/utensil)) - var/obj/item/kitchen/utensil/U = W - if(U.scoop_food) - if(!U.reagents) - U.create_reagents(5) - - if (U.reagents.total_volume > 0) - to_chat(user, "You already have something on your [U].") - return - - user.visible_message( \ - "\The [user] scoops up some [src] with \the [U]!", \ - "You scoop up some [src] with \the [U]!" \ - ) - - src.bitecount++ - U.overlays.Cut() - U.loaded = "[src]" - var/image/I = new(U.icon, "loadedfood") - I.color = src.filling_color - U.overlays += I - - if(!reagents) - crash_with("A snack [type] failed to have a reagent holder when attacked with a [W.type]. It was [QDELETED(src) ? "" : "not"] being deleted.") - else - reagents.trans_to_obj(U, min(reagents.total_volume,5)) - if (reagents.total_volume <= 0) - qdel(src) - return - - if (is_sliceable()) - //these are used to allow hiding edge items in food that is not on a table/tray - var/can_slice_here = isturf(src.loc) && ((locate(/obj/structure/table) in src.loc) || (locate(/obj/machinery/optable) in src.loc) || (locate(/obj/item/storage/tray) in src.loc)) - var/hide_item = !has_edge(W) || !can_slice_here - - if (hide_item) - if (W.w_class >= src.w_class || is_robot_module(W) || istype(W,/obj/item/chems/food/condiment)) - return - if(!user.unEquip(W, src)) - return - - to_chat(user, "You slip \the [W] inside \the [src].") - add_fingerprint(user) - W.forceMove(src) - return - - if (has_edge(W)) - if (!can_slice_here) - to_chat(user, "You cannot slice \the [src] here! You need a table or at least a tray to do it.") - return - - var/slices_lost = 0 - if (W.w_class > ITEM_SIZE_NORMAL) - user.visible_message("\The [user] crudely slices \the [src] with [W]!", "You crudely slice \the [src] with your [W]!") - slices_lost = rand(1,min(1,round(slices_num/2))) - else - user.visible_message("\The [user] slices \the [src]!", "You slice \the [src]!") - - var/reagents_per_slice = reagents.total_volume/slices_num - for(var/i=1 to (slices_num-slices_lost)) - var/obj/slice = new slice_path (src.loc) - reagents.trans_to_obj(slice, reagents_per_slice) - qdel(src) - return - -/obj/item/chems/food/snacks/proc/is_sliceable() - return (slices_num && slice_path && slices_num > 0) - -/obj/item/chems/food/snacks/Destroy() - if(contents) - for(var/atom/movable/something in contents) - something.dropInto(loc) - . = ..() - -//////////////////////////////////////////////////////////////////////////////// -/// FOOD END -//////////////////////////////////////////////////////////////////////////////// -/obj/item/chems/food/snacks/attack_animal(var/mob/living/user) - if(!isanimal(user) && !isalien(user)) - return - user.visible_message("[user] nibbles away at \the [src].","You nibble away at \the [src].") - bitecount++ - if(reagents && user.reagents) - reagents.trans_to_mob(user, bitesize, CHEM_INGEST) - spawn(5) - if(!src && !user.client) - user.custom_emote(1,"[pick("burps", "cries for more", "burps twice", "looks at the area where the food was")]") - qdel(src) - On_Consume(user) - -////////////////////////////////////////////////// -////////////////////////////////////////////Snacks -////////////////////////////////////////////////// -//Items in the "Snacks" subcategory are food items that people actually eat. The key points are that they are created -// already filled with reagents and are destroyed when empty. Additionally, they make a "munching" noise when eaten. - -//Notes by Darem: Food in the "snacks" subtype can hold a maximum of 50 units Generally speaking, you don't want to go over 40 -// total for the item because you want to leave space for extra condiments. If you want effect besides healing, add a reagent for -// it. Try to stick to existing reagents when possible (so if you want a stronger healing effect, just use regenerative serum). On use -// effect (such as the old officer eating a donut code) requires a unique reagent (unless you can figure out a better way). - -//The nutriment reagent and bitesize variable replace the old heal_amt and amount variables. Each unit of nutriment is equal to -// 2 of the old heal_amt variable. bitesize is the rate at which the reagents are consumed. So if you have 6 nutriment and a -// bitesize of 2, then it'll take 3 bites to eat. Unlike the old system, the contained reagents are evenly spread among all -// the bites. No more contained reagents = no more bites. - - -/obj/item/chems/food/snacks/aesirsalad - name = "\improper Aether salad" - desc = "Probably too incredible for mortal men to fully enjoy." - icon_state = "aesirsalad" - trash = /obj/item/trash/snack_bowl - filling_color = "#468c00" - center_of_mass = @"{'x':17,'y':11}" - nutriment_amt = 8 - nutriment_desc = list("apples" = 3,"salad" = 4, "quintessence" = 2) - bitesize = 3 -/obj/item/chems/food/snacks/aesirsalad/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/regenerator, 8) - -/obj/item/chems/food/snacks/egg - name = "egg" - desc = "An egg!" - icon_state = "egg" - filling_color = "#fdffd1" - volume = 10 - center_of_mass = @"{'x':16,'y':13}" - -/obj/item/chems/food/snacks/egg/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein/egg, 3) - -/obj/item/chems/food/snacks/egg/afterattack(obj/O, mob/user, proximity) - if(istype(O,/obj/machinery/microwave)) - return ..() - if(!(proximity && ATOM_IS_OPEN_CONTAINER(O))) - return - to_chat(user, "You crack \the [src] into \the [O].") - reagents.trans_to(O, reagents.total_volume) - qdel(src) - -/obj/item/chems/food/snacks/egg/throw_impact(atom/hit_atom) - if(QDELETED(src)) - return // Could potentially happen with unscupulous atoms on hitby() throwing again, etc. - new/obj/effect/decal/cleanable/egg_smudge(src.loc) - reagents.splash(hit_atom, reagents.total_volume) - visible_message("\The [src] has been squashed!","You hear a smack.") - ..() - qdel(src) - -/obj/item/chems/food/snacks/egg/attackby(obj/item/W, mob/user) - if(istype( W, /obj/item/pen/crayon )) - var/obj/item/pen/crayon/C = W - var/clr = C.colourName - - if(!(clr in list("blue","green","mime","orange","purple","rainbow","red","yellow"))) - to_chat(usr, "The egg refuses to take on this color!") - return - - to_chat(usr, "You color \the [src] [clr]") - icon_state = "egg-[clr]" - else - ..() - -/obj/item/chems/food/snacks/egg/blue - icon_state = "egg-blue" - -/obj/item/chems/food/snacks/egg/green - icon_state = "egg-green" - -/obj/item/chems/food/snacks/egg/mime - icon_state = "egg-mime" - -/obj/item/chems/food/snacks/egg/orange - icon_state = "egg-orange" - -/obj/item/chems/food/snacks/egg/purple - icon_state = "egg-purple" - -/obj/item/chems/food/snacks/egg/rainbow - icon_state = "egg-rainbow" - -/obj/item/chems/food/snacks/egg/red - icon_state = "egg-red" - -/obj/item/chems/food/snacks/egg/yellow - icon_state = "egg-yellow" - -/obj/item/chems/food/snacks/egg/lizard/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein/egg, 5) - if(prob(30)) //extra nutriment - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - -/obj/item/chems/food/snacks/friedegg - name = "fried egg" - desc = "A fried egg, with a touch of salt and pepper." - icon_state = "friedegg" - filling_color = "#ffdf78" - center_of_mass = @"{'x':16,'y':14}" - bitesize = 1 -/obj/item/chems/food/snacks/friedegg/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - reagents.add_reagent(/decl/material/solid/mineral/sodiumchloride, 1) - reagents.add_reagent(/decl/material/solid/blackpepper, 1) - - -/obj/item/chems/food/snacks/boiledegg - name = "boiled egg" - desc = "A hard boiled egg." - icon_state = "egg" - filling_color = "#ffffff" -/obj/item/chems/food/snacks/boiledegg/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/organ - name = "organ" - desc = "It's good for you." - icon = 'icons/obj/surgery.dmi' - icon_state = "appendix" - filling_color = "#e00d34" - center_of_mass = @"{'x':16,'y':16}" - bitesize = 3 -/obj/item/chems/food/snacks/organ/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, rand(3,5)) - reagents.add_reagent(/decl/material/liquid/bromide, rand(1,3)) - - -/obj/item/chems/food/snacks/tofu - name = "tofu" - icon_state = "tofu" - desc = "We all love tofu." - filling_color = "#fffee0" - center_of_mass = @"{'x':17,'y':10}" -// nutriment_amt = 3 - nutriment_desc = list("tofu" = 3, "softness" = 3) - bitesize = 3 - -/obj/item/chems/food/snacks/tofu/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/plant_protein, 6) - -/obj/item/chems/food/snacks/tofurkey - name = "\improper Tofurkey" - desc = "A fake turkey made from tofu." - icon_state = "tofurkey" - filling_color = "#fffee0" - center_of_mass = @"{'x':16,'y':8}" - nutriment_amt = 12 - nutriment_desc = list("turkey" = 3, "tofu" = 5, "softness" = 4) - bitesize = 3 - -/obj/item/chems/food/snacks/stuffing - name = "stuffing" - desc = "Moist, peppery breadcrumbs for filling the body cavities of dead birds. Dig in!" - icon_state = "stuffing" - filling_color = "#c9ac83" - center_of_mass = @"{'x':16,'y':10}" - nutriment_amt = 3 - nutriment_desc = list("dryness" = 2, "bread" = 2) - bitesize = 1 - -/obj/item/chems/food/snacks/fishfingers - name = "fish fingers" - desc = "A finger of fish." - icon_state = "fishfingers" - filling_color = "#ffdefe" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 3 -/obj/item/chems/food/snacks/fishfingers/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/hugemushroomslice - name = "huge mushroom slice" - desc = "A slice from a huge mushroom." - icon_state = "hugemushroomslice" - filling_color = "#e0d7c5" - center_of_mass = @"{'x':17,'y':16}" - nutriment_amt = 3 - nutriment_desc = list("raw" = 2, "mushroom" = 2) - bitesize = 6 -/obj/item/chems/food/snacks/hugemushroomslice/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/psychotropics, 3) - -/obj/item/chems/food/snacks/tomatomeat - name = "tomato slice" - desc = "A slice from a huge tomato." - icon_state = "tomatomeat" - filling_color = "#db0000" - center_of_mass = @"{'x':17,'y':16}" - nutriment_amt = 3 - nutriment_desc = list("raw" = 2, "tomato" = 3) - bitesize = 6 - -/obj/item/chems/food/snacks/bearmeat - name = "bear meat" - desc = "A very manly slab of meat." - icon_state = "bearmeat" - filling_color = "#db0000" - center_of_mass = @"{'x':16,'y':10}" - bitesize = 3 -/obj/item/chems/food/snacks/bearmeat/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 12) - reagents.add_reagent(/decl/material/liquid/amphetamines, 5) - -/obj/item/chems/food/snacks/spider - name = "giant spider leg" - desc = "An economical replacement for crab. In space! Would probably be a lot nicer cooked." - icon_state = "spiderleg" - filling_color = "#d5f5dc" - center_of_mass = @"{'x':16,'y':10}" - bitesize = 3 - -/obj/item/chems/food/snacks/spider/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 9) - -/obj/item/chems/food/snacks/spider/cooked - name = "boiled spider meat" - desc = "An economical replacement for crab. In space!" - icon_state = "spiderleg_c" - bitesize = 5 - -/obj/item/chems/food/snacks/xenomeat - name = "meat" - desc = "A slab of green meat. Smells like acid." - icon_state = "xenomeat" - filling_color = "#43de18" - center_of_mass = @"{'x':16,'y':10}" - bitesize = 6 -/obj/item/chems/food/snacks/xenomeat/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - reagents.add_reagent(/decl/material/liquid/acid/polyacid,6) - -/obj/item/chems/food/snacks/meatball - name = "meatball" - desc = "A great meal all round." - icon_state = "meatball" - filling_color = "#db0000" - center_of_mass = @"{'x':16,'y':16}" - bitesize = 2 -/obj/item/chems/food/snacks/meatball/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/sausage - name = "sausage" - desc = "A piece of mixed, long meat." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "sausage" - filling_color = "#db0000" - center_of_mass = @"{'x':16,'y':16}" - bitesize = 2 -/obj/item/chems/food/snacks/sausage/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - -/obj/item/chems/food/snacks/fatsausage - name = "fat sausage" - desc = "A piece of mixed, long meat, with some bite to it." - icon_state = "sausage" - filling_color = "#db0000" - center_of_mass = @"{'x':16,'y':16}" - bitesize = 2 -/obj/item/chems/food/snacks/fatsausage/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 8) - -/obj/item/chems/food/snacks/donkpocket/sinpocket - name = "\improper Sin-pocket" - desc = "The food of choice for the veteran. Do NOT overconsume." - filling_color = "#6d6d00" - heated_reagents = list( - /decl/material/liquid/regenerator = 5, - /decl/material/liquid/amphetamines = 0.75, - /decl/material/liquid/stimulants = 0.25 - ) - var/has_been_heated = 0 // Unlike the warm var, this checks if the one-time self-heating operation has been used. - -/obj/item/chems/food/snacks/donkpocket/sinpocket/attack_self(mob/user) - if(has_been_heated) - to_chat(user, "The heating chemicals have already been spent.") - return - has_been_heated = 1 - user.visible_message("[user] crushes \the [src] package.", "You crush \the [src] package and feel a comfortable heat build up.") - addtimer(CALLBACK(src, .proc/heat, weakref(user)), 20 SECONDS) - -/obj/item/chems/food/snacks/donkpocket/sinpocket/heat(weakref/message_to) - ..() - if(message_to) - var/mob/user = message_to.resolve() - if(user) - to_chat(user, "You think \the [src] is ready to eat about now.") - -/obj/item/chems/food/snacks/donkpocket - name = "\improper Donk-pocket" - desc = "The food of choice for the seasoned traitor." - icon_state = "donkpocket" - filling_color = "#dedeab" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("heartiness" = 1, "dough" = 2) - nutriment_amt = 2 - var/warm = 0 - var/list/heated_reagents = list(/decl/material/liquid/regenerator = 5) - -/obj/item/chems/food/snacks/donkpocket/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/donkpocket/proc/heat() - if(warm) - return - warm = 1 - for(var/reagent in heated_reagents) - reagents.add_reagent(reagent, heated_reagents[reagent]) - bitesize = 6 - SetName("warm " + name) - addtimer(CALLBACK(src, .proc/cool), 7 MINUTES) - -/obj/item/chems/food/snacks/donkpocket/proc/cool() - if(!warm) - return - warm = 0 - for(var/reagent in heated_reagents) - reagents.clear_reagent(reagent) - SetName(initial(name)) - -/obj/item/chems/food/snacks/brainburger - name = "brainburger" - desc = "A strange looking burger. It looks almost sentient." - icon_state = "brainburger" - filling_color = "#f2b6ea" - center_of_mass = @"{'x':15,'y':11}" - bitesize = 2 -/obj/item/chems/food/snacks/brainburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - reagents.add_reagent(/decl/material/liquid/neuroannealer, 6) - -/obj/item/chems/food/snacks/ghostburger - name = "ghost burger" - desc = "Spooky! It doesn't look very filling." - icon_state = "ghostburger" - filling_color = "#fff2ff" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("buns" = 3, "spookiness" = 3) - nutriment_amt = 2 - bitesize = 2 - -/obj/item/chems/food/snacks/human - filling_color = "#d63c3c" - var/hname = "" - var/job = null - -/obj/item/chems/food/snacks/human/burger - name = "-burger" - desc = "A bloody burger." - icon_state = "hburger" - center_of_mass = @"{'x':16,'y':11}" - bitesize = 2 -/obj/item/chems/food/snacks/human/burger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - -/obj/item/chems/food/snacks/cheeseburger - name = "cheeseburger" - desc = "The cheese adds a good flavor." - icon_state = "cheeseburger" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("cheese" = 2, "bun" = 2) - nutriment_amt = 2 -/obj/item/chems/food/snacks/cheeseburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/meatburger - name = "burger" - desc = "The cornerstone of every nutritious breakfast." - icon_state = "hburger" - filling_color = "#d63c3c" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("bun" = 2) - nutriment_amt = 3 - bitesize = 2 -/obj/item/chems/food/snacks/meatburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/plainburger - name = "burger" - desc = "The cornerstone of every nutritious breakfast." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "burger" - filling_color = "#d63c3c" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("bun" = 2) - nutriment_amt = 3 - bitesize = 2 -/obj/item/chems/food/snacks/plainburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/hamburger - name = "hamburger" - desc = "The cornerstone of every nutritious breakfast, now with ham!" - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "hamburger" - filling_color = "#d63c3c" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("bun" = 2) - nutriment_amt = 3 - bitesize = 2 -/obj/item/chems/food/snacks/hamburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - -/obj/item/chems/food/snacks/fishburger - name = "fish sandwich" - desc = "Almost like a carp is yelling somewhere... Give me back that fillet -o- carp, give me that carp." - icon_state = "fishburger" - filling_color = "#ffdefe" - center_of_mass = @"{'x':16,'y':10}" - bitesize = 3 -/obj/item/chems/food/snacks/fishburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - -/obj/item/chems/food/snacks/tofuburger - name = "tofu burger" - desc = "What.. is that meat?" - icon_state = "tofuburger" - filling_color = "#fffee0" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("bun" = 2, "pseudo-soy meat" = 3) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/roburger - name = "roburger" - desc = "The lettuce is the only organic component. Beep." - icon_state = "roburger" - filling_color = COLOR_GRAY80 - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("bun" = 2, "metal" = 3) - nutriment_amt = 2 - bitesize = 2 -/obj/item/chems/food/snacks/roburger/Initialize() - .=..() - if(prob(5)) - reagents.add_reagent(/decl/material/liquid/nanitefluid, 2) - -/obj/item/chems/food/snacks/roburgerbig - name = "roburger" - desc = "This massive patty looks like poison. Beep." - icon_state = "roburger" - filling_color = COLOR_GRAY80 - volume = 100 - center_of_mass = @"{'x':16,'y':11}" - bitesize = 0.1 -/obj/item/chems/food/snacks/roburgerbig/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nanitefluid, 100) - -/obj/item/chems/food/snacks/xenoburger - name = "xenoburger" - desc = "Smells caustic. Tastes like heresy." - icon_state = "xburger" - filling_color = "#43de18" - center_of_mass = @"{'x':16,'y':11}" - bitesize = 2 -/obj/item/chems/food/snacks/xenoburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 8) - -/obj/item/chems/food/snacks/clownburger - name = "clown burger" - desc = "This tastes funny..." - icon_state = "clownburger" - filling_color = "#ff00ff" - center_of_mass = @"{'x':17,'y':12}" - nutriment_desc = list("bun" = 2, "clown shoe" = 3) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/mimeburger - name = "mime burger" - desc = "Its taste defies language." - icon_state = "mimeburger" - filling_color = "#ffffff" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("bun" = 2, "mime paint" = 3) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/omelette - name = "cheese omelette" - desc = "Omelette with cheese!" - icon_state = "omelette" - trash = /obj/item/trash/plate - filling_color = "#fff9a8" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 1 -/obj/item/chems/food/snacks/omelette/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 8) - -/obj/item/chems/food/snacks/muffin - name = "muffin" - desc = "A delicious and spongy little cake." - icon_state = "muffin" - filling_color = "#e0cf9b" - center_of_mass = @"{'x':17,'y':4}" - nutriment_desc = list("sweetness" = 3, "muffin" = 3) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/bananapie - name = "banana cream pie" - desc = "Just like back home, on clown planet! HONK!" - icon_state = "pie" - trash = /obj/item/trash/plate - filling_color = "#fbffb8" - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("pie" = 3, "cream" = 2) - nutriment_amt = 4 - bitesize = 3 -/obj/item/chems/food/snacks/pie/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/banana_cream,5) - -/obj/item/chems/food/snacks/pie/throw_impact(atom/hit_atom) - ..() - new/obj/effect/decal/cleanable/pie_smudge(src.loc) - src.visible_message("\The [src.name] splats.","You hear a splat.") - qdel(src) - -/obj/item/chems/food/snacks/berryclafoutis - name = "berry clafoutis" - desc = "No black birds, this is a good sign." - icon_state = "berryclafoutis" - trash = /obj/item/trash/plate - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("sweetness" = 2, "pie" = 3) - nutriment_amt = 4 - bitesize = 3 -/obj/item/chems/food/snacks/berryclafoutis/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/juice/berry, 5) - -/obj/item/chems/food/snacks/waffles - name = "waffles" - desc = "Mmm, waffles." - icon_state = "waffles" - trash = /obj/item/trash/waffles - filling_color = "#e6deb5" - center_of_mass = @"{'x':15,'y':11}" - nutriment_desc = list("waffle" = 8) - nutriment_amt = 8 - bitesize = 2 - -/obj/item/chems/food/snacks/pancakesblu - name = "blueberry pancakes" - desc = "Pancakes with blueberries, delicious." - icon_state = "pancakes" - trash = /obj/item/trash/plate - center_of_mass = @"{'x':15,'y':11}" - nutriment_desc = list("pancake" = 8) - nutriment_amt = 8 - bitesize = 2 - -/obj/item/chems/food/snacks/pancakes - name = "pancakes" - desc = "Pancakes without blueberries, still delicious." - icon_state = "pancakes" - trash = /obj/item/trash/plate - center_of_mass = @"{'x':15,'y':11}" - nutriment_desc = list("pancake" = 8) - nutriment_amt = 8 - bitesize = 2 - -/obj/item/chems/food/snacks/eggplantparm - name = "eggplant parmigiana" - desc = "The only good recipe for eggplant." - icon_state = "eggplantparm" - trash = /obj/item/trash/plate - filling_color = "#4d2f5e" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("cheese" = 3, "eggplant" = 3) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/soylentgreen - name = "\improper Soylent Green" - desc = "Not made of people. Honest."//Totally people. - icon_state = "soylent_green" - trash = /obj/item/trash/waffles - filling_color = "#b8e6b5" - center_of_mass = @"{'x':15,'y':11}" - bitesize = 2 -/obj/item/chems/food/snacks/soylentgreen/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - -/obj/item/chems/food/snacks/soylenviridians - name = "\improper Soylen Virdians" - desc = "Not made of people. Honest."//Actually honest for once. - icon_state = "soylent_yellow" - trash = /obj/item/trash/waffles - filling_color = "#e6fa61" - center_of_mass = @"{'x':15,'y':11}" - nutriment_desc = list("some sort of protein" = 10)//seasoned vERY well. - nutriment_amt = 10 - bitesize = 2 - -/obj/item/chems/food/snacks/meatpie - name = "meat-pie" - icon_state = "meatpie" - desc = "An old barber recipe, very delicious!" - trash = /obj/item/trash/plate - filling_color = "#948051" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 2 -/obj/item/chems/food/snacks/meatpie/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - -/obj/item/chems/food/snacks/tofupie - name = "tofu-pie" - icon_state = "meatpie" - desc = "A delicious tofu pie." - trash = /obj/item/trash/plate - filling_color = "#fffee0" - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("tofu" = 2, "pie" = 8) - nutriment_amt = 10 - bitesize = 2 - -/obj/item/chems/food/snacks/amanita_pie - name = "amanita pie" - desc = "Sweet and tasty poison pie." - icon_state = "amanita_pie" - filling_color = "#ffcccc" - center_of_mass = @"{'x':17,'y':9}" - nutriment_desc = list("sweetness" = 3, "mushroom" = 3, "pie" = 2) - nutriment_amt = 5 - bitesize = 3 -/obj/item/chems/food/snacks/amanita_pie/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/amatoxin, 3) - reagents.add_reagent(/decl/material/liquid/psychotropics, 1) - -/obj/item/chems/food/snacks/plump_pie - name = "plump pie" - desc = "I bet you love stuff made out of plump helmets!" - icon_state = "plump_pie" - filling_color = "#b8279b" - center_of_mass = @"{'x':17,'y':9}" - nutriment_desc = list("heartiness" = 2, "mushroom" = 3, "pie" = 3) - nutriment_amt = 8 - bitesize = 2 -/obj/item/chems/food/snacks/plump_pie/Initialize() - .=..() - if(prob(10)) - name = "exceptional plump pie" - desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump pie!" - reagents.add_reagent(/decl/material/liquid/regenerator, 5) - -/obj/item/chems/food/snacks/xemeatpie - name = "xeno-pie" - icon_state = "xenomeatpie" - desc = "A delicious meatpie. Probably heretical." - trash = /obj/item/trash/plate - filling_color = "#43de18" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 2 -/obj/item/chems/food/snacks/xemeatpie/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - -/obj/item/chems/food/snacks/meatkabob - name = "meat-kabob" - icon_state = "kabob" - desc = "Delicious meat, on a stick." - trash = /obj/item/stack/material/rods - filling_color = "#a85340" - center_of_mass = @"{'x':17,'y':15}" - bitesize = 2 -/obj/item/chems/food/snacks/meatkabob/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 8) - -/obj/item/chems/food/snacks/tofukabob - name = "tofu-kabob" - icon_state = "kabob" - desc = "Vegan meat, on a stick." - trash = /obj/item/stack/material/rods - filling_color = "#fffee0" - center_of_mass = @"{'x':17,'y':15}" - nutriment_desc = list("tofu" = 3, "metal" = 1) - nutriment_amt = 8 - bitesize = 2 - -/obj/item/chems/food/snacks/cubancarp - name = "\improper Cuban Carp" - desc = "A sandwich that burns your tongue and then leaves it numb!" - icon_state = "cubancarp" - trash = /obj/item/trash/plate - filling_color = "#e9adff" - center_of_mass = @"{'x':12,'y':5}" - nutriment_desc = list("toasted bread" = 3) - nutriment_amt = 3 - bitesize = 3 -/obj/item/chems/food/snacks/cubancarp/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - reagents.add_reagent(/decl/material/liquid/capsaicin, 3) - -/obj/item/chems/food/snacks/popcorn - name = "popcorn" - desc = "Now let's find some cinema." - icon_state = "popcorn" - trash = /obj/item/trash/popcorn - filling_color = "#fffad4" - center_of_mass = @"{'x':16,'y':8}" - nutriment_desc = list("popcorn" = 3) - nutriment_amt = 2 - bitesize = 0.1 - -/obj/item/chems/food/snacks/loadedbakedpotato - name = "loaded baked potato" - desc = "Totally baked." - icon_state = "loadedbakedpotato" - filling_color = "#9c7a68" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("baked potato" = 3) - nutriment_amt = 3 - bitesize = 2 -/obj/item/chems/food/snacks/loadedbakedpotato/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/fries - name = "chips" - desc = "Frenched potato, fried." - icon_state = "fries" - trash = /obj/item/trash/plate - filling_color = "#eddd00" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("fresh fries" = 4) - nutriment_amt = 4 - bitesize = 2 - -/obj/item/chems/food/snacks/onionrings - name = "onion rings" - desc = "Like circular fries but better." - icon_state = "onionrings" - trash = /obj/item/trash/plate - filling_color = "#eddd00" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("fried onions" = 5) - nutriment_amt = 5 - bitesize = 2 - -/obj/item/chems/food/snacks/soydope - name = "soy dope" - desc = "Dope from a soy." - icon_state = "soydope" - trash = /obj/item/trash/plate - filling_color = "#c4bf76" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("slime" = 2, "soy" = 2) - nutriment_amt = 2 - bitesize = 2 - -/obj/item/chems/food/snacks/spagetti - name = "spaghetti" - desc = "A bundle of raw spaghetti." - icon_state = "spagetti" - filling_color = "#eddd00" - center_of_mass = @"{'x':16,'y':16}" - nutriment_desc = list("noodles" = 2) - nutriment_amt = 1 - bitesize = 1 - -/obj/item/chems/food/snacks/cheesyfries - name = "cheesy fries" - desc = "Fries. Covered in cheese. Duh." - icon_state = "cheesyfries" - trash = /obj/item/trash/plate - filling_color = "#eddd00" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("fresh fries" = 3, "cheese" = 3) - nutriment_amt = 4 - bitesize = 2 -/obj/item/chems/food/snacks/cheesyfries/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/fortunecookie - name = "fortune cookie" - desc = "A true prophecy in each cookie!" - icon_state = "fortune_cookie" - filling_color = "#e8e79e" - center_of_mass = @"{'x':15,'y':14}" - nutriment_desc = list("fortune cookie" = 2) - nutriment_amt = 3 - bitesize = 2 - -/obj/item/chems/food/snacks/badrecipe - name = "burned mess" - desc = "Someone should be demoted from chef for this." - icon_state = "badrecipe" - filling_color = "#211f02" - center_of_mass = @"{'x':16,'y':12}" - bitesize = 2 -/obj/item/chems/food/snacks/badrecipe/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/bromide, 1) - reagents.add_reagent(/decl/material/solid/carbon, 3) - -/obj/item/chems/food/snacks/plainsteak - name = "plain steak" - desc = "A piece of unseasoned cooked meat." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "steak" - slice_path = /obj/item/chems/food/snacks/cutlet - slices_num = 3 - filling_color = "#7a3d11" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 3 -/obj/item/chems/food/snacks/plainsteak/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/meatsteak - name = "meat steak" - desc = "A piece of hot spicy meat." - icon_state = "meatstake" - trash = /obj/item/trash/plate - filling_color = "#7a3d11" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 3 -/obj/item/chems/food/snacks/meatsteak/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - reagents.add_reagent(/decl/material/solid/mineral/sodiumchloride, 1) - reagents.add_reagent(/decl/material/solid/blackpepper, 1) - -/obj/item/chems/food/snacks/meatsteak/synthetic - name = "meaty steak" - desc = "A piece of hot spicy pseudo-meat." - -/obj/item/chems/food/snacks/loadedsteak - name = "loaded steak" - desc = "A steak slathered in sauce with sauteed onions and mushrooms." - icon_state = "meatstake" - trash = /obj/item/trash/plate - filling_color = "#7a3d11" - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("onion" = 2, "mushroom" = 2) - nutriment_amt = 4 - bitesize = 3 -/obj/item/chems/food/snacks/loadedsteak/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - reagents.add_reagent(/decl/material/liquid/nutriment/garlicsauce, 2) - -/obj/item/chems/food/snacks/spacylibertyduff - name = "party jelly" - desc = "LoOk aT aLl tHe PrEtTy CoLoUrS" - icon_state = "spacylibertyduff" - trash = /obj/item/trash/snack_bowl - filling_color = "#42b873" - center_of_mass = @"{'x':16,'y':8}" - nutriment_desc = list("mushroom" = 5, "rainbow" = 1) - nutriment_amt = 6 - bitesize = 3 -/obj/item/chems/food/snacks/spacylibertyduff/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/psychotropics, 6) - -/obj/item/chems/food/snacks/amanitajelly - name = "amanita jelly" - desc = "Looks curiously toxic." - icon_state = "amanitajelly" - trash = /obj/item/trash/snack_bowl - filling_color = "#ed0758" - center_of_mass = @"{'x':16,'y':5}" - nutriment_desc = list("jelly" = 3, "mushroom" = 3) - nutriment_amt = 6 - bitesize = 3 -/obj/item/chems/food/snacks/amanitajelly/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/amatoxin, 6) - reagents.add_reagent(/decl/material/liquid/psychotropics, 3) - -/obj/item/chems/food/snacks/poppypretzel - name = "poppy pretzel" - desc = "It's all twisted up!" - icon_state = "poppypretzel" - bitesize = 2 - filling_color = "#916e36" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("poppy seeds" = 2, "pretzel" = 3) - nutriment_amt = 5 - bitesize = 2 - -/obj/item/chems/food/snacks/meatballsoup - name = "meatball soup" - desc = "You've got balls kid, BALLS!" - icon_state = "meatballsoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#785210" - center_of_mass = @"{'x':16,'y':8}" - bitesize = 5 - eat_sound = list('sound/items/eatfood.ogg', 'sound/items/drink.ogg') - -/obj/item/chems/food/snacks/meatballsoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 8) - reagents.add_reagent(/decl/material/liquid/water, 5) - -/obj/item/chems/food/snacks/slimesoup - name = "slime soup" - desc = "If no water is available, you may substitute tears." - icon_state = "slimesoup"//nonexistant? - filling_color = "#c4dba0" - bitesize = 5 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/slimesoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/slimejelly, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - -/obj/item/chems/food/snacks/bloodsoup - name = "tomato soup" - desc = "Smells like copper." - icon_state = "tomatosoup" - filling_color = "#ff0000" - center_of_mass = @"{'x':16,'y':7}" - bitesize = 5 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/bloodsoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - reagents.add_reagent(/decl/material/liquid/blood, 10) - reagents.add_reagent(/decl/material/liquid/water, 5) - -/obj/item/chems/food/snacks/clownstears - name = "clown's tears" - desc = "Not very funny." - icon_state = "clownstears" - filling_color = "#c4fbff" - center_of_mass = @"{'x':16,'y':7}" - nutriment_desc = list("salt" = 1, "the worst joke" = 3) - nutriment_amt = 4 - bitesize = 5 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/clownstears/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/juice/banana, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - -/obj/item/chems/food/snacks/vegetablesoup - name = "vegetable soup" - desc = "A highly nutritious blend of vegetative goodness. Guaranteed to leave you with a, er, \"souped-up\" sense of wellbeing." - icon_state = "vegetablesoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#afc4b5" - center_of_mass = @"{'x':16,'y':8}" - nutriment_desc = list("carrot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2) - nutriment_amt = 8 - bitesize = 5 - eat_sound = list('sound/items/eatfood.ogg', 'sound/items/drink.ogg') - -/obj/item/chems/food/snacks/vegetablesoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/water, 5) - -/obj/item/chems/food/snacks/nettlesoup - name = "nettle soup" - desc = "A mean, green, calorically lean dish derived from a poisonous plant. It has a rather acidic bite to its taste." - icon_state = "nettlesoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#afc4b5" - center_of_mass = @"{'x':16,'y':7}" - nutriment_desc = list("salad" = 4, "egg" = 2, "potato" = 2) - nutriment_amt = 8 - bitesize = 5 - eat_sound = list('sound/items/eatfood.ogg', 'sound/items/drink.ogg') - -/obj/item/chems/food/snacks/nettlesoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/water, 5) - reagents.add_reagent(/decl/material/liquid/regenerator, 5) - -/obj/item/chems/food/snacks/mysterysoup - name = "mystery soup" - desc = "The mystery is, why aren't you eating it?" - icon_state = "mysterysoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#f082ff" - center_of_mass = @"{'x':16,'y':6}" - nutriment_desc = list("backwash" = 1) - nutriment_amt = 1 - bitesize = 5 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/mysterysoup/Initialize() - .=..() - switch(rand(1,10)) - if(1) - reagents.add_reagent(/decl/material/liquid/nutriment, 6) - reagents.add_reagent(/decl/material/liquid/capsaicin, 3) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 2) - if(2) - reagents.add_reagent(/decl/material/liquid/nutriment, 6) - reagents.add_reagent(/decl/material/liquid/frostoil, 3) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 2) - if(3) - reagents.add_reagent(/decl/material/liquid/nutriment, 5) - reagents.add_reagent(/decl/material/liquid/water, 5) - reagents.add_reagent(/decl/material/liquid/regenerator, 5) - if(4) - reagents.add_reagent(/decl/material/liquid/nutriment, 5) - reagents.add_reagent(/decl/material/liquid/water, 10) - if(5) - reagents.add_reagent(/decl/material/liquid/nutriment, 2) - reagents.add_reagent(/decl/material/liquid/drink/juice/banana, 10) - if(6) - reagents.add_reagent(/decl/material/liquid/nutriment, 6) - reagents.add_reagent(/decl/material/liquid/blood, 10) - if(7) - reagents.add_reagent(/decl/material/liquid/slimejelly, 10) - reagents.add_reagent(/decl/material/liquid/water, 10) - if(8) - reagents.add_reagent(/decl/material/solid/carbon, 10) - reagents.add_reagent(/decl/material/liquid/bromide, 10) - if(9) - reagents.add_reagent(/decl/material/liquid/nutriment, 5) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 10) - if(10) - reagents.add_reagent(/decl/material/liquid/nutriment, 6) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 5) - reagents.add_reagent(/decl/material/liquid/eyedrops, 5) - -/obj/item/chems/food/snacks/wishsoup - name = "\improper Wish Soup" - desc = "I wish this was soup." - icon_state = "wishsoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#d1f4ff" - center_of_mass = @"{'x':16,'y':11}" - bitesize = 5 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/wishsoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/water, 10) - if(prob(25)) - src.desc = "A wish come true!" - reagents.add_reagent(/decl/material/liquid/nutriment, 8, list("something good" = 8)) - -/obj/item/chems/food/snacks/hotchili - name = "hot chili" - desc = "Sound the fire alarm!" - icon_state = "hotchili" - trash = /obj/item/trash/snack_bowl - filling_color = "#ff3c00" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("chilli peppers" = 2, "burning" = 1) - nutriment_amt = 3 - bitesize = 5 -/obj/item/chems/food/snacks/hotchili/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - reagents.add_reagent(/decl/material/liquid/capsaicin, 3) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 2) - -/obj/item/chems/food/snacks/coldchili - name = "cold chili" - desc = "This slush is barely a liquid!" - icon_state = "coldchili" - filling_color = "#2b00ff" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("chilly peppers" = 3) - nutriment_amt = 3 - trash = /obj/item/trash/snack_bowl - bitesize = 5 -/obj/item/chems/food/snacks/coldchili/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - reagents.add_reagent(/decl/material/liquid/frostoil, 3) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 2) - -//cubed animals! - -/obj/item/chems/food/snacks/monkeycube - name = "monkey cube" - desc = "Just add water!" - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_OPEN_CONTAINER - icon_state = "monkeycube" - bitesize = 12 - filling_color = "#adac7f" - center_of_mass = @"{'x':16,'y':14}" - - var/wrapped = 0 - var/growing = 0 - var/monkey_type = /mob/living/carbon/human/monkey - -/obj/item/chems/food/snacks/monkeycube/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - -/obj/item/chems/food/snacks/monkeycube/attack_self(var/mob/user) - if(wrapped) - Unwrap(user) - -/obj/item/chems/food/snacks/monkeycube/proc/Expand() - if(!growing) - growing = 1 - src.visible_message("\The [src] expands!") - var/mob/monkey = new monkey_type - monkey.dropInto(src.loc) - qdel(src) - -/obj/item/chems/food/snacks/monkeycube/proc/Unwrap(var/mob/user) - icon_state = "monkeycube" - desc = "Just add water!" - to_chat(user, SPAN_NOTICE("You unwrap \the [src].")) - wrapped = 0 - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - var/trash = new /obj/item/trash/cubewrapper(get_turf(user)) - user.put_in_hands(trash) - -/obj/item/chems/food/snacks/monkeycube/On_Consume(var/mob/M) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.visible_message("A screeching creature bursts out of [M]'s chest!") - var/obj/item/organ/external/organ = H.get_organ(BP_CHEST) - organ.take_external_damage(50, 0, 0, "Animal escaping the ribcage") - Expand() - -/obj/item/chems/food/snacks/monkeycube/on_reagent_change() - if(reagents.has_reagent(/decl/material/liquid/water)) - Expand() - -/obj/item/chems/food/snacks/monkeycube/wrapped - desc = "Still wrapped in some paper." - icon_state = "monkeycubewrap" - item_flags = 0 - obj_flags = 0 - wrapped = 1 - -//Spider cubes, all that's left of the cube PR -/obj/item/chems/food/snacks/monkeycube/spidercube - name = "spider cube" - monkey_type = /obj/effect/spider/spiderling - -/obj/item/chems/food/snacks/monkeycube/wrapped/spidercube - name = "spider cube" - monkey_type = /obj/effect/spider/spiderling - -/obj/item/chems/food/snacks/spellburger - name = "spell burger" - desc = "This is absolutely magical." - icon_state = "spellburger" - filling_color = "#d505ff" - nutriment_desc = list("magic" = 3, "buns" = 3) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/bigbiteburger - name = "big bite burger" - desc = "Forget the Luna Burger! THIS is the future!" - icon_state = "bigbiteburger" - filling_color = "#e3d681" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("buns" = 4) - nutriment_amt = 4 - bitesize = 3 -/obj/item/chems/food/snacks/bigbiteburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - -/obj/item/chems/food/snacks/enchiladas - name = "enchiladas" - desc = "Not to be confused with an echidna, though I don't know how you would." - icon_state = "enchiladas" - trash = /obj/item/trash/tray - filling_color = "#a36a1f" - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("tortilla" = 3, "corn" = 3) - nutriment_amt = 2 - bitesize = 4 -/obj/item/chems/food/snacks/enchiladas/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - reagents.add_reagent(/decl/material/liquid/capsaicin, 6) - -/obj/item/chems/food/snacks/monkeysdelight - name = "monkey's delight" - desc = "Eeee Eee!" - icon_state = "monkeysdelight" - trash = /obj/item/trash/tray - filling_color = "#5c3c11" - center_of_mass = @"{'x':16,'y':13}" - bitesize = 6 -/obj/item/chems/food/snacks/monkeysdelight/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - reagents.add_reagent(/decl/material/liquid/drink/juice/banana, 5) - reagents.add_reagent(/decl/material/solid/blackpepper, 1) - reagents.add_reagent(/decl/material/solid/mineral/sodiumchloride, 1) - -/obj/item/chems/food/snacks/baguette - name = "baguette" - desc = "Good for pretend sword fights." - icon_state = "baguette" - filling_color = "#e3d796" - center_of_mass = @"{'x':18,'y':12}" - nutriment_desc = list("long bread" = 6) - nutriment_amt = 6 - bitesize = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/baguette/Initialize() - .=..() - reagents.add_reagent(/decl/material/solid/blackpepper, 1) - reagents.add_reagent(/decl/material/solid/mineral/sodiumchloride, 1) - -/obj/item/chems/food/snacks/fishandchips - name = "fish and chips" - desc = "Best enjoyed wrapped in a newspaper on a cold wet day." - icon_state = "fishandchips" - filling_color = "#e3d796" - center_of_mass = @"{'x':16,'y':16}" - nutriment_desc = list("salt" = 1, "chips" = 2, "fish" = 2) - nutriment_amt = 3 - bitesize = 3 -/obj/item/chems/food/snacks/fishandchips/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/sandwich - name = "sandwich" - desc = "A grand creation of meat, cheese, bread, and several leaves of lettuce!" - icon_state = "sandwich" - trash = /obj/item/trash/plate - filling_color = "#d9be29" - center_of_mass = @"{'x':16,'y':4}" - nutriment_desc = list("bread" = 3, "cheese" = 3) - nutriment_amt = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - bitesize = 2 - -/obj/item/chems/food/snacks/sandwich/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/toastedsandwich - name = "toasted sandwich" - desc = "Now if you only had a pepper bar." - icon_state = "toastedsandwich" - trash = /obj/item/trash/plate - filling_color = "#d9be29" - center_of_mass = @"{'x':16,'y':4}" - nutriment_desc = list("toasted bread" = 3, "cheese" = 3) - nutriment_amt = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - bitesize = 2 - -/obj/item/chems/food/snacks/toastedsandwich/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - reagents.add_reagent(/decl/material/solid/carbon, 2) - -/obj/item/chems/food/snacks/grilledcheese - name = "grilled cheese sandwich" - desc = "Goes great with Tomato soup!" - icon_state = "toastedsandwich" - trash = /obj/item/trash/plate - filling_color = "#d9be29" - nutriment_desc = list("toasted bread" = 3, "cheese" = 3) - nutriment_amt = 3 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/grilledcheese/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/tomatosoup - name = "tomato soup" - desc = "Drinking this feels like being a vampire! A tomato vampire..." - icon_state = "tomatosoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#d92929" - center_of_mass = @"{'x':16,'y':7}" - nutriment_desc = list("soup" = 5) - nutriment_amt = 5 - bitesize = 3 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/tomatosoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 10) - -/obj/item/chems/food/snacks/rofflewaffles - name = "waffles(?)" - desc = "There's something funny about these waffles." - icon_state = "rofflewaffles" - trash = /obj/item/trash/waffles - filling_color = "#ff00f7" - center_of_mass = @"{'x':15,'y':11}" - nutriment_desc = list("waffle" = 7, "sweetness" = 1) - nutriment_amt = 8 - bitesize = 4 -/obj/item/chems/food/snacks/rofflewaffles/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/psychotropics, 8) - -/obj/item/chems/food/snacks/stew - name = "stew" - desc = "A nice and warm stew. Healthy and strong." - icon_state = "stew" - filling_color = "#9e673a" - center_of_mass = @"{'x':16,'y':5}" - nutriment_desc = list("tomato" = 2, "potato" = 2, "carrot" = 2, "eggplant" = 2, "mushroom" = 2) - nutriment_amt = 6 - bitesize = 10 -/obj/item/chems/food/snacks/stew/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 5) - reagents.add_reagent(/decl/material/liquid/eyedrops, 5) - reagents.add_reagent(/decl/material/liquid/water, 5) - -/obj/item/chems/food/snacks/jelliedtoast - name = "jellied toast" - desc = "A slice of bread covered with delicious jam." - icon_state = "jellytoast" - trash = /obj/item/trash/plate - filling_color = "#b572ab" - center_of_mass = @"{'x':16,'y':8}" - nutriment_desc = list("toasted bread" = 2) - nutriment_amt = 1 - bitesize = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/jelliedtoast/cherry -/obj/item/chems/food/snacks/jelliedtoast/cherry/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/cherryjelly, 5) - -/obj/item/chems/food/snacks/jelliedtoast/slime -/obj/item/chems/food/snacks/jelliedtoast/slime/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/slimejelly, 5) - -/obj/item/chems/food/snacks/jellyburger - name = "jelly burger" - desc = "Culinary delight..?" - icon_state = "jellyburger" - filling_color = "#b572ab" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("buns" = 5) - nutriment_amt = 5 - bitesize = 2 - -/obj/item/chems/food/snacks/jellyburger/slime -/obj/item/chems/food/snacks/jellyburger/slime/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/slimejelly, 5) - -/obj/item/chems/food/snacks/jellyburger/cherry -/obj/item/chems/food/snacks/jellyburger/cherry/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/cherryjelly, 5) - -/obj/item/chems/food/snacks/milosoup - name = "milosoup" - desc = "The universes best soup! Yum!!!" - icon_state = "milosoup" - trash = /obj/item/trash/snack_bowl - center_of_mass = @"{'x':16,'y':7}" - nutriment_desc = list("soy" = 8) - nutriment_amt = 8 - bitesize = 4 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/milosoup/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/water, 5) - - -/obj/item/chems/food/snacks/stewedsoymeat - name = "stewed soy meat" - desc = "Even non-vegetarians will LOVE this!" - icon_state = "stewedsoymeat" - trash = /obj/item/trash/plate - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("soy" = 4, "tomato" = 4) - nutriment_amt = 8 - bitesize = 2 - -/obj/item/chems/food/snacks/boiledspagetti - name = "boiled spaghetti" - desc = "A plain dish of pasta, just screaming for sauce." - icon_state = "spagettiboiled" - trash = /obj/item/trash/plate - filling_color = "#fcee81" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("noodles" = 2) - nutriment_amt = 2 - bitesize = 2 - -/obj/item/chems/food/snacks/boiledrice - name = "boiled rice" - desc = "White rice, a very important staple food. Goes excellent with many many things." - icon_state = "boiledrice" - trash = /obj/item/trash/snack_bowl - filling_color = "#fffbdb" - center_of_mass = @"{'x':17,'y':11}" - nutriment_desc = list("rice" = 2) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/boiledrice/chazuke - name = "chazuke" - desc = "An ancient way of using up day-old rice, this dish is composed of plain green tea poured over plain white rice. Hopefully you have something else to put in." - icon_state = "chazuke" - filling_color = "#f1ffdb" - nutriment_desc = list("chazuke" = 2) - bitesize = 3 - -/obj/item/chems/food/snacks/katsucurry - name = "katsu curry" - desc = "An oriental curry dish made from apples, potatoes, and carrots. Served with rice and breaded chicken." - icon_state = "katsu" - trash = /obj/item/trash/snack_bowl - filling_color = "#faa005" - center_of_mass = @"{'x':17,'y':11}" - nutriment_desc = list("rice" = 2, "apple" = 2, "potato" = 2, "carrot" = 2, "bread" = 2, ) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/ricepudding - name = "rice pudding" - desc = "Where's the jam?" - icon_state = "rpudding" - trash = /obj/item/trash/snack_bowl - filling_color = "#fffbdb" - center_of_mass = @"{'x':17,'y':11}" - nutriment_desc = list("rice" = 2) - nutriment_amt = 4 - bitesize = 2 - -/obj/item/chems/food/snacks/pastatomato - name = "spaghetti & tomato" - desc = "Spaghetti and crushed tomatoes." - icon_state = "pastatomato" - trash = /obj/item/trash/plate - filling_color = "#de4545" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("tomato" = 3, "noodles" = 3) - nutriment_amt = 6 - bitesize = 4 -/obj/item/chems/food/snacks/pastatomato/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 10) - -/obj/item/chems/food/snacks/nanopasta - name = "nanopasta" - desc = "Nanomachines, son!" - icon_state = "nanopasta" - trash = /obj/item/trash/plate - filling_color = "#535e66" - center_of_mass = @"{'x':16,'y':10}" - nutriment_amt = 6 - bitesize = 4 -/obj/item/chems/food/snacks/nanopasta/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nanitefluid, 10) - -/obj/item/chems/food/snacks/meatballspagetti - name = "spaghetti & meatballs" - desc = "Now thats a nice meatball!" - icon_state = "meatballspagetti" - trash = /obj/item/trash/plate - filling_color = "#de4545" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("noodles" = 4) - nutriment_amt = 4 - bitesize = 2 -/obj/item/chems/food/snacks/meatballspagetti/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/spesslaw - name = "spaghetti & too many meatballs" - desc = "Do you want some pasta with those meatballs?" - icon_state = "spesslaw" - filling_color = "#de4545" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("noodles" = 4) - nutriment_amt = 4 - bitesize = 2 -/obj/item/chems/food/snacks/spesslaw/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/carrotfries - name = "carrot fries" - desc = "Tasty fries from fresh carrots." - icon_state = "carrotfries" - trash = /obj/item/trash/plate - filling_color = "#faa005" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("carrot" = 3, "salt" = 1) - nutriment_amt = 3 - bitesize = 2 -/obj/item/chems/food/snacks/carrotfries/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/eyedrops, 3) - -/obj/item/chems/food/snacks/superbiteburger - name = "super bite burger" - desc = "This is a mountain of a burger. FOOD!" - icon_state = "superbiteburger" - filling_color = "#cca26a" - center_of_mass = @"{'x':16,'y':3}" - nutriment_desc = list("buns" = 25) - nutriment_amt = 25 - bitesize = 10 -/obj/item/chems/food/snacks/superbiteburger/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 25) - -/obj/item/chems/food/snacks/candiedapple - name = "candied apple" - desc = "An apple coated in sugary sweetness." - icon_state = "candiedapple" - filling_color = "#f21873" - center_of_mass = @"{'x':15,'y':13}" - nutriment_desc = list("apple" = 3, "caramel" = 3, "sweetness" = 2) - nutriment_amt = 3 - bitesize = 3 - -/obj/item/chems/food/snacks/applepie - name = "apple pie" - desc = "A pie containing sweet sweet love... or apple." - icon_state = "applepie" - filling_color = "#e0edc5" - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("sweetness" = 2, "apple" = 2, "pie" = 2) - nutriment_amt = 4 - bitesize = 3 - -/obj/item/chems/food/snacks/cherrypie - name = "cherry pie" - desc = "Taste so good, make a grown man cry." - icon_state = "cherrypie" - filling_color = "#ff525a" - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("sweetness" = 2, "cherry" = 2, "pie" = 2) - nutriment_amt = 4 - bitesize = 3 - -/obj/item/chems/food/snacks/twobread - name = "\improper Two Bread" - desc = "It is very bitter and winy." - icon_state = "twobread" - filling_color = "#dbcc9a" - center_of_mass = @"{'x':15,'y':12}" - nutriment_desc = list("sourness" = 2, "bread" = 2) - nutriment_amt = 2 - bitesize = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/threebread - name = "\improper Three Bread" - desc = "Is such a thing even possible?" - icon_state = "threebread" - filling_color = "#dbcc9a" - center_of_mass = @"{'x':15,'y':12}" - nutriment_desc = list("sourness" = 2, "bread" = 3) - nutriment_amt = 3 - bitesize = 4 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/jellysandwich - name = "jelly sandwich" - desc = "You wish you had some peanut butter to go with this..." - icon_state = "jellysandwich" - trash = /obj/item/trash/plate - filling_color = "#9e3a78" - center_of_mass = @"{'x':16,'y':8}" - nutriment_desc = list("bread" = 2) - nutriment_amt = 2 - bitesize = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/jellysandwich/slime -/obj/item/chems/food/snacks/jellysandwich/slime/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/slimejelly, 5) - -/obj/item/chems/food/snacks/jellysandwich/cherry -/obj/item/chems/food/snacks/jellysandwich/cherry/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/cherryjelly, 5) - -/obj/item/chems/food/snacks/mint - name = "mint" - desc = "A tasty after-dinner mint. It is only wafer thin." - icon_state = "mint" - filling_color = "#f2f2f2" - center_of_mass = @"{'x':16,'y':14}" - bitesize = 1 -/obj/item/chems/food/snacks/mint/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/syrup/mint, 1) - - -/obj/item/chems/food/snacks/mushroomsoup - name = "chantrelle soup" - desc = "A delicious and hearty mushroom soup." - icon_state = "mushroomsoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#e386bf" - center_of_mass = @"{'x':17,'y':10}" - nutriment_desc = list("mushroom" = 8, "milk" = 2) - nutriment_amt = 8 - bitesize = 3 - eat_sound = list('sound/items/eatfood.ogg', 'sound/items/drink.ogg') - -/obj/item/chems/food/snacks/plumphelmetbiscuit - name = "plump helmet biscuit" - desc = "This is a finely-prepared plump helmet biscuit. The ingredients are exceptionally minced plump helmet, and well-minced wheat flour." - icon_state = "phelmbiscuit" - filling_color = "#cfb4c4" - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("mushroom" = 4) - nutriment_amt = 5 - bitesize = 2 -/obj/item/chems/food/snacks/plumphelmetbiscuit/Initialize() - .=..() - if(prob(10)) - name = "exceptional plump helmet biscuit" - desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump helmet biscuit!" - reagents.add_reagent(/decl/material/liquid/nutriment, 3) - reagents.add_reagent(/decl/material/liquid/regenerator, 5) - - -/obj/item/chems/food/snacks/chawanmushi - name = "chawanmushi" - desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat." - icon_state = "chawanmushi" - trash = /obj/item/trash/snack_bowl - filling_color = "#f0f2e4" - center_of_mass = @"{'x':17,'y':10}" - bitesize = 1 -/obj/item/chems/food/snacks/chawanmushi/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - - -/obj/item/chems/food/snacks/beetsoup - name = "beet soup" - desc = "Wait, how do you spell it again..?" - icon_state = "beetsoup" - trash = /obj/item/trash/snack_bowl - filling_color = "#fac9ff" - center_of_mass = @"{'x':15,'y':8}" - nutriment_desc = list("tomato" = 4, "beet" = 4) - nutriment_amt = 8 - bitesize = 2 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/beetsoup/Initialize() - .=..() - name = pick(list("borsch","bortsch","borstch","borsh","borshch","borscht")) - - -/obj/item/chems/food/snacks/tossedsalad - name = "tossed salad" - desc = "A proper salad, basic and simple, with little bits of carrot, tomato and apple intermingled. Vegan!" - icon_state = "herbsalad" - trash = /obj/item/trash/snack_bowl - filling_color = "#76b87f" - center_of_mass = @"{'x':17,'y':11}" - nutriment_desc = list("salad" = 2, "tomato" = 2, "carrot" = 2, "apple" = 2) - nutriment_amt = 8 - bitesize = 3 - -/obj/item/chems/food/snacks/validsalad - name = "valid salad" - desc = "It's just a salad of questionable 'herbs' with meatballs and fried potato slices. Nothing suspicious about it." - icon_state = "validsalad" - trash = /obj/item/trash/snack_bowl - filling_color = "#76b87f" - center_of_mass = @"{'x':17,'y':11}" - nutriment_desc = list("100% real salad") - nutriment_amt = 6 - bitesize = 3 -/obj/item/chems/food/snacks/validsalad/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/appletart - name = "golden apple streusel tart" - desc = "A tasty dessert that won't make it through a metal detector." - icon_state = "gappletart" - trash = /obj/item/trash/plate - filling_color = "#ffff00" - center_of_mass = @"{'x':16,'y':18}" - nutriment_desc = list("apple" = 8) - nutriment_amt = 8 - bitesize = 3 -/obj/item/chems/food/snacks/appletart/Initialize() - .=..() - reagents.add_reagent(/decl/material/solid/metal/gold, 5) - -/////////////////////////////////////////////////Sliceable//////////////////////////////////////// -// All the food items that can be sliced into smaller bits like meatbread and cheesewheels - -// sliceable is just an organization type path, it doesn't have any additional code or variables tied to it. - -/obj/item/chems/food/snacks/sliceable - w_class = ITEM_SIZE_NORMAL //whole pizzas and cakes shouldn't fit in a pocket, you can slice them if you want to do that. -/** - * A food item slice - * - * This path contains some extra code for spawning slices pre-filled with - * reagents. - */ -/obj/item/chems/food/snacks/slice - name = "slice of... something" - var/whole_path // path for the item from which this slice comes - var/filled = FALSE // should the slice spawn with any reagents - -/** - * Spawn a new slice of food - * - * If the slice's filled is TRUE, this will also fill the slice with the - * appropriate amount of reagents. Note that this is done by spawning a new - * whole item, transferring the reagents and deleting the whole item, which may - * have performance implications. - */ -/obj/item/chems/food/snacks/slice/Initialize() - .=..() - if(filled) - var/obj/item/chems/food/snacks/whole = new whole_path() - if(whole && whole.slices_num) - var/reagent_amount = whole.reagents.total_volume/whole.slices_num - whole.reagents.trans_to_obj(src, reagent_amount) - - qdel(whole) - -/obj/item/chems/food/snacks/sliceable/meatbread - name = "meatbread loaf" - desc = "The culinary base of every self-respecting eloquent gentleman." - icon_state = "meatbread" - slice_path = /obj/item/chems/food/snacks/slice/meatbread - slices_num = 5 - filling_color = "#ff7575" - center_of_mass = @"{'x':19,'y':9}" - nutriment_desc = list("bread" = 10) - nutriment_amt = 10 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/meatbread/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 20) - -/obj/item/chems/food/snacks/slice/meatbread - name = "meatbread slice" - desc = "A slice of delicious meatbread." - icon_state = "meatbreadslice" - trash = /obj/item/trash/plate - filling_color = "#ff7575" - bitesize = 2 - center_of_mass = @"{'x':16,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/meatbread - -/obj/item/chems/food/snacks/slice/meatbread/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/xenomeatbread - name = "xenomeatbread loaf" - desc = "The culinary base of every self-respecting eloquent gentleman. Extra heretical." - icon_state = "xenomeatbread" - slice_path = /obj/item/chems/food/snacks/slice/xenomeatbread - slices_num = 5 - filling_color = "#8aff75" - center_of_mass = @"{'x':16,'y':9}" - nutriment_desc = list("bread" = 10) - nutriment_amt = 10 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/xenomeatbread/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 20) - -/obj/item/chems/food/snacks/slice/xenomeatbread - name = "xenomeatbread slice" - desc = "A slice of delicious meatbread. Extra Heretical." - icon_state = "xenobreadslice" - trash = /obj/item/trash/plate - filling_color = "#8aff75" - bitesize = 2 - center_of_mass = @"{'x':16,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/xenomeatbread - -/obj/item/chems/food/snacks/slice/xenomeatbread/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/bananabread - name = "banana-nut bread" - desc = "A heavenly and filling treat." - icon_state = "bananabread" - slice_path = /obj/item/chems/food/snacks/slice/bananabread - slices_num = 5 - filling_color = "#ede5ad" - center_of_mass = @"{'x':16,'y':9}" - nutriment_desc = list("bread" = 10) - nutriment_amt = 10 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/bananabread/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/banana_cream, 20) - -/obj/item/chems/food/snacks/slice/bananabread - name = "banana-nut bread slice" - desc = "A slice of delicious banana bread." - icon_state = "bananabreadslice" - trash = /obj/item/trash/plate - filling_color = "#ede5ad" - bitesize = 2 - center_of_mass = @"{'x':16,'y':8}" - whole_path = /obj/item/chems/food/snacks/sliceable/bananabread - -/obj/item/chems/food/snacks/slice/bananabread/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/tofubread - name = "tofubread" - desc = "Like meatbread but for vegetarians. Not guaranteed to give superpowers." - icon_state = "tofubread" - slice_path = /obj/item/chems/food/snacks/slice/tofubread - slices_num = 5 - filling_color = "#f7ffe0" - center_of_mass = @"{'x':16,'y':9}" - nutriment_desc = list("tofu" = 10) - nutriment_amt = 10 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/slice/tofubread - name = "tofubread slice" - desc = "A slice of delicious tofubread." - icon_state = "tofubreadslice" - trash = /obj/item/trash/plate - filling_color = "#f7ffe0" - bitesize = 2 - center_of_mass = @"{'x':16,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/tofubread - -/obj/item/chems/food/snacks/slice/tofubread/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/carrotcake - name = "carrot cake" - desc = "A favorite desert of sophisticated rabbits." - icon_state = "carrotcake" - slice_path = /obj/item/chems/food/snacks/slice/carrotcake - slices_num = 5 - filling_color = "#ffd675" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "carrot" = 15) - nutriment_amt = 25 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/sliceable/carrotcake/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/eyedrops, 10) - -/obj/item/chems/food/snacks/slice/carrotcake - name = "carrot cake slice" - desc = "Carrotty slice of carrot cake, carrots are good for your eyes! It's true! Probably!" - icon_state = "carrotcake_slice" - trash = /obj/item/trash/plate - filling_color = "#ffd675" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/carrotcake - -/obj/item/chems/food/snacks/slice/carrotcake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/braincake - name = "brain cake" - desc = "A squishy cake-thing." - icon_state = "braincake" - slice_path = /obj/item/chems/food/snacks/slice/braincake - slices_num = 5 - filling_color = "#e6aedb" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "slime" = 15) - nutriment_amt = 5 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/sliceable/braincake/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 25) - reagents.add_reagent(/decl/material/liquid/neuroannealer, 10) - -/obj/item/chems/food/snacks/slice/braincake - name = "brain cake slice" - desc = "Lemme tell you something about prions. THEY'RE DELICIOUS." - icon_state = "braincakeslice" - trash = /obj/item/trash/plate - filling_color = "#e6aedb" - bitesize = 2 - center_of_mass = @"{'x':16,'y':12}" - whole_path = /obj/item/chems/food/snacks/sliceable/braincake - -/obj/item/chems/food/snacks/slice/braincake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/cheesecake - name = "cheese cake" - desc = "DANGEROUSLY cheesy." - icon_state = "cheesecake" - slice_path = /obj/item/chems/food/snacks/slice/cheesecake - slices_num = 5 - filling_color = "#faf7af" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "cream" = 10, "cheese" = 15) - nutriment_amt = 10 - bitesize = 2 - -/obj/item/chems/food/snacks/sliceable/cheesecake/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 15) - -/obj/item/chems/food/snacks/slice/cheesecake - name = "cheese cake slice" - desc = "Slice of pure cheestisfaction." - icon_state = "cheesecake_slice" - trash = /obj/item/trash/plate - filling_color = "#faf7af" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/cheesecake - -/obj/item/chems/food/snacks/slice/cheesecake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/plaincake - name = "vanilla cake" - desc = "A plain cake, but a good cake." - icon_state = "plaincake" - slice_path = /obj/item/chems/food/snacks/slice/plaincake - slices_num = 5 - filling_color = "#f7edd5" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "vanilla" = 15) - nutriment_amt = 20 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/slice/plaincake - name = "vanilla cake slice" - desc = "Just a slice of cake, it is enough for everyone." - icon_state = "plaincake_slice" - trash = /obj/item/trash/plate - filling_color = "#f7edd5" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/plaincake - -/obj/item/chems/food/snacks/slice/plaincake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/orangecake - name = "orange cake" - desc = "A cake with added orange." - icon_state = "orangecake" - slice_path = /obj/item/chems/food/snacks/slice/orangecake - slices_num = 5 - filling_color = "#fada8e" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "orange" = 15) - nutriment_amt = 20 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/slice/orangecake - name = "orange cake slice" - desc = "Just a slice of cake, it is enough for everyone." - icon_state = "orangecake_slice" - trash = /obj/item/trash/plate - filling_color = "#fada8e" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/orangecake - -/obj/item/chems/food/snacks/slice/orangecake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/limecake - name = "lime cake" - desc = "A cake with added lime." - icon_state = "limecake" - slice_path = /obj/item/chems/food/snacks/slice/limecake - slices_num = 5 - filling_color = "#cbfa8e" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "lime" = 15) - nutriment_amt = 20 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/slice/limecake - name = "lime cake slice" - desc = "Just a slice of cake, it is enough for everyone." - icon_state = "limecake_slice" - trash = /obj/item/trash/plate - filling_color = "#cbfa8e" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/limecake - -/obj/item/chems/food/snacks/slice/limecake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/lemoncake - name = "lemon cake" - desc = "A cake with added lemon." - icon_state = "lemoncake" - slice_path = /obj/item/chems/food/snacks/slice/lemoncake - slices_num = 5 - filling_color = "#fafa8e" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "lemon" = 15) - nutriment_amt = 20 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/slice/lemoncake - name = "lemon cake slice" - desc = "Just a slice of cake, it is enough for everyone." - icon_state = "lemoncake_slice" - trash = /obj/item/trash/plate - filling_color = "#fafa8e" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/lemoncake - -/obj/item/chems/food/snacks/slice/lemoncake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/chocolatecake - name = "chocolate cake" - desc = "A cake with added chocolate." - icon_state = "chocolatecake" - slice_path = /obj/item/chems/food/snacks/slice/chocolatecake - slices_num = 5 - filling_color = "#805930" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "chocolate" = 15) - nutriment_amt = 20 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/slice/chocolatecake - name = "chocolate cake slice" - desc = "Just a slice of cake, it is enough for everyone." - icon_state = "chocolatecake_slice" - trash = /obj/item/trash/plate - filling_color = "#805930" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/chocolatecake - -/obj/item/chems/food/snacks/slice/chocolatecake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/cheesewheel - name = "cheese wheel" - desc = "A big wheel of delcious cheddar." - icon_state = "cheesewheel" - slice_path = /obj/item/chems/food/snacks/cheesewedge - slices_num = 5 - filling_color = "#fff700" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cheese" = 10) - nutriment_amt = 10 - bitesize = 2 - -/obj/item/chems/food/snacks/sliceable/cheesewheel/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 10) - -/obj/item/chems/food/snacks/cheesewedge - name = "cheese wedge" - desc = "A wedge of delicious cheddar. The cheese wheel it was cut from can't have gone far." - icon_state = "cheesewedge" - filling_color = "#fff700" - bitesize = 2 - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/snacks/sliceable/birthdaycake - name = "birthday cake" - desc = "Happy birthday!" - icon_state = "birthdaycake" - slice_path = /obj/item/chems/food/snacks/slice/birthdaycake - slices_num = 5 - filling_color = "#ffd6d6" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10) - nutriment_amt = 20 - bitesize = 3 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/sliceable/birthdaycake/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 10) - - -/obj/item/chems/food/snacks/slice/birthdaycake - name = "birthday cake slice" - desc = "A slice of your birthday." - icon_state = "birthdaycakeslice" - trash = /obj/item/trash/plate - filling_color = "#ffd6d6" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/birthdaycake - -/obj/item/chems/food/snacks/slice/birthdaycake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/bread - name = "bread" - desc = "Some plain old bread." - icon_state = "bread" - slice_path = /obj/item/chems/food/snacks/slice/bread - slices_num = 5 - filling_color = "#ffe396" - center_of_mass = @"{'x':16,'y':9}" - nutriment_desc = list("bread" = 6) - nutriment_amt = 6 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/slice/bread - name = "bread slice" - desc = "A slice of home." - icon_state = "breadslice" - trash = /obj/item/trash/plate - filling_color = "#d27332" - bitesize = 2 - center_of_mass = @"{'x':16,'y':4}" - whole_path = /obj/item/chems/food/snacks/sliceable/bread - -/obj/item/chems/food/snacks/slice/bread/filled - filled = TRUE - - -/obj/item/chems/food/snacks/sliceable/creamcheesebread - name = "cream cheese bread" - desc = "Yum yum yum!" - icon_state = "creamcheesebread" - slice_path = /obj/item/chems/food/snacks/slice/creamcheesebread - slices_num = 5 - filling_color = "#fff896" - center_of_mass = @"{'x':16,'y':9}" - nutriment_desc = list("bread" = 6, "cream" = 3, "cheese" = 3) - nutriment_amt = 5 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/creamcheesebread/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 15) - -/obj/item/chems/food/snacks/slice/creamcheesebread - name = "cream cheese bread slice" - desc = "A slice of yum!" - icon_state = "creamcheesebreadslice" - trash = /obj/item/trash/plate - filling_color = "#fff896" - bitesize = 2 - center_of_mass = @"{'x':16,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/creamcheesebread - -/obj/item/chems/food/snacks/slice/creamcheesebread/filled - filled = TRUE - -/obj/item/chems/food/snacks/watermelonslice - name = "watermelon slice" - desc = "A slice of watery goodness." - icon_state = "watermelonslice" - filling_color = "#ff3867" - bitesize = 2 - center_of_mass = @"{'x':16,'y':10}" - -/obj/item/chems/food/snacks/sliceable/applecake - name = "apple cake" - desc = "A cake centred with apples." - icon_state = "applecake" - slice_path = /obj/item/chems/food/snacks/slice/applecake - slices_num = 5 - filling_color = "#ebf5b8" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("cake" = 10, "sweetness" = 10, "apple" = 15) - nutriment_amt = 15 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/slice/applecake - name = "apple cake slice" - desc = "A slice of heavenly cake." - icon_state = "applecakeslice" - trash = /obj/item/trash/plate - filling_color = "#ebf5b8" - bitesize = 2 - center_of_mass = @"{'x':16,'y':14}" - whole_path = /obj/item/chems/food/snacks/sliceable/applecake - -/obj/item/chems/food/snacks/slice/applecake/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/pumpkinpie - name = "pumpkin pie" - desc = "A delicious treat for the autumn months." - icon_state = "pumpkinpie" - slice_path = /obj/item/chems/food/snacks/slice/pumpkinpie - slices_num = 5 - filling_color = "#f5b951" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("pie" = 5, "cream" = 5, "pumpkin" = 5) - nutriment_amt = 15 - -/obj/item/chems/food/snacks/slice/pumpkinpie - name = "pumpkin pie slice" - desc = "A slice of pumpkin pie, with whipped cream on top. Perfection." - icon_state = "pumpkinpieslice" - trash = /obj/item/trash/plate - filling_color = "#f5b951" - bitesize = 2 - center_of_mass = @"{'x':16,'y':12}" - whole_path = /obj/item/chems/food/snacks/sliceable/pumpkinpie - -/obj/item/chems/food/snacks/slice/pumpkinpie/filled - filled = TRUE - -/obj/item/chems/food/snacks/cracker - name = "cracker" - desc = "It's a salted cracker." - icon_state = "cracker" - filling_color = "#f5deb8" - center_of_mass = @"{'x':17,'y':6}" - nutriment_desc = list("salt" = 1, "cracker" = 2) - w_class = ITEM_SIZE_TINY - nutriment_amt = 1 - nutriment_type = /decl/material/liquid/nutriment/bread - -/////////////////////////////////////////////////PIZZA//////////////////////////////////////// - -/obj/item/chems/food/snacks/sliceable/pizza - slices_num = 6 - filling_color = "#baa14c" - -/obj/item/chems/food/snacks/sliceable/pizza/margherita - name = "margherita" - desc = "The golden standard of pizzas." - icon_state = "pizzamargherita" - slice_path = /obj/item/chems/food/snacks/slice/margherita - slices_num = 6 - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15) - nutriment_amt = 35 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/pizza/margherita/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 6) - -/obj/item/chems/food/snacks/slice/margherita - name = "margherita slice" - desc = "A slice of the classic pizza." - icon_state = "pizzamargheritaslice" - filling_color = "#baa14c" - bitesize = 2 - center_of_mass = @"{'x':18,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/pizza/margherita - -/obj/item/chems/food/snacks/slice/margherita/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/pizza/meatpizza - name = "meatpizza" - desc = "A pizza with meat topping." - icon_state = "meatpizza" - slice_path = /obj/item/chems/food/snacks/slice/meatpizza - slices_num = 6 - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15) - nutriment_amt = 10 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/pizza/meatpizza/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 34) - reagents.add_reagent(/decl/material/liquid/nutriment/barbecue, 6) - -/obj/item/chems/food/snacks/slice/meatpizza - name = "meatpizza slice" - desc = "A slice of a meaty pizza." - icon_state = "meatpizzaslice" - filling_color = "#baa14c" - bitesize = 2 - center_of_mass = @"{'x':18,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/pizza/meatpizza - -/obj/item/chems/food/snacks/slice/meatpizza/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/pizza/mushroompizza - name = "mushroompizza" - desc = "Very special pizza." - icon_state = "mushroompizza" - slice_path = /obj/item/chems/food/snacks/slice/mushroompizza - slices_num = 6 - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "mushroom" = 10) - nutriment_amt = 35 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/pizza/mushroompizza/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - -/obj/item/chems/food/snacks/slice/mushroompizza - name = "mushroompizza slice" - desc = "Maybe it is the last slice of pizza in your life." - icon_state = "mushroompizzaslice" - filling_color = "#baa14c" - bitesize = 2 - center_of_mass = @"{'x':18,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/pizza/mushroompizza - -/obj/item/chems/food/snacks/slice/mushroompizza/filled - filled = TRUE - -/obj/item/chems/food/snacks/sliceable/pizza/vegetablepizza - name = "vegetable pizza" - desc = "Vegetarian pizza huh? What about all the plants that were slaughtered to make this huh?? Hypocrite." - icon_state = "vegetablepizza" - slice_path = /obj/item/chems/food/snacks/slice/vegetablepizza - slices_num = 6 - center_of_mass = @"{'x':16,'y':11}" - nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "eggplant" = 5, "carrot" = 5, "corn" = 5) - nutriment_amt = 25 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/sliceable/pizza/vegetablepizza/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - reagents.add_reagent(/decl/material/liquid/nutriment/ketchup, 6) - reagents.add_reagent(/decl/material/liquid/eyedrops, 12) - -/obj/item/chems/food/snacks/slice/vegetablepizza - name = "vegetable pizza slice" - desc = "A slice of the most green pizza of all pizzas not containing green ingredients." - icon_state = "vegetablepizzaslice" - filling_color = "#baa14c" - bitesize = 2 - center_of_mass = @"{'x':18,'y':13}" - whole_path = /obj/item/chems/food/snacks/sliceable/pizza/vegetablepizza - -/obj/item/chems/food/snacks/slice/vegetablepizza/filled - filled = TRUE - -/obj/item/pizzabox - name = "pizza box" - desc = "A box suited for pizzas." - icon = 'icons/obj/food.dmi' - icon_state = "pizzabox1" - - var/open = 0 // Is the box open? - var/ismessy = 0 // Fancy mess on the lid - var/obj/item/chems/food/snacks/sliceable/pizza/pizza // content pizza - var/list/boxes = list()// If the boxes are stacked, they come here - var/boxtag = "" - -/obj/item/pizzabox/on_update_icon() - - overlays.Cut() - - // Set appropriate description - if( open && pizza ) - desc = "A box suited for pizzas. It appears to have a [pizza.name] inside." - else if( boxes.len > 0 ) - desc = "A pile of boxes suited for pizzas. There appears to be [boxes.len + 1] boxes in the pile." - - var/obj/item/pizzabox/topbox = boxes[boxes.len] - var/toptag = topbox.boxtag - if( toptag != "" ) - desc = "[desc] The box on top has a tag, it reads: '[toptag]'." - else - desc = "A box suited for pizzas." - - if( boxtag != "" ) - desc = "[desc] The box has a tag, it reads: '[boxtag]'." - - // Icon states and overlays - if( open ) - if( ismessy ) - icon_state = "pizzabox_messy" - else - icon_state = "pizzabox_open" - - if( pizza ) - var/image/pizzaimg = image("food.dmi", icon_state = pizza.icon_state) - pizzaimg.pixel_y = -3 - overlays += pizzaimg - - return - else - // Stupid code because byondcode sucks - var/doimgtag = 0 - if( boxes.len > 0 ) - var/obj/item/pizzabox/topbox = boxes[boxes.len] - if( topbox.boxtag != "" ) - doimgtag = 1 - else - if( boxtag != "" ) - doimgtag = 1 - - if( doimgtag ) - var/image/tagimg = image("food.dmi", icon_state = "pizzabox_tag") - tagimg.pixel_y = boxes.len * 3 - overlays += tagimg - - icon_state = "pizzabox[boxes.len+1]" - -/obj/item/pizzabox/attack_hand(mob/user) - - if( open && pizza ) - user.put_in_hands( pizza ) - - to_chat(user, "You take \the [src.pizza] out of \the [src].") - src.pizza = null - update_icon() - return - - if( boxes.len > 0 ) - if( user.get_inactive_hand() != src ) - ..() - return - - var/obj/item/pizzabox/box = boxes[boxes.len] - boxes -= box - - user.put_in_hands( box ) - to_chat(user, "You remove the topmost [src] from your hand.") - box.update_icon() - update_icon() - return - ..() - -/obj/item/pizzabox/attack_self(mob/user) - - if( boxes.len > 0 ) - return - - open = !open - - if( open && pizza ) - ismessy = 1 - - update_icon() - -/obj/item/pizzabox/attackby(obj/item/I, mob/user) - if( istype(I, /obj/item/pizzabox/) ) - var/obj/item/pizzabox/box = I - - if( !box.open && !src.open ) - // make a list of all boxes to be added - var/list/boxestoadd = list() - boxestoadd += box - for(var/obj/item/pizzabox/i in box.boxes) - boxestoadd += i - - if( (boxes.len+1) + boxestoadd.len <= 5 ) - if(!user.unEquip(box, src)) - return - box.boxes = list()// clear the box boxes so we don't have boxes inside boxes. - Xzibit - src.boxes.Add( boxestoadd ) - - box.update_icon() - update_icon() - - to_chat(user, "You put \the [box] ontop of \the [src]!") - else - to_chat(user, "The stack is too high!") - else - to_chat(user, "Close \the [box] first!") - - return - - if( istype(I, /obj/item/chems/food/snacks/sliceable/pizza/) ) - - if( src.open ) - if(!user.unEquip(I, src)) - return - src.pizza = I - - update_icon() - - to_chat(user, "You put \the [I] in \the [src]!") - else - to_chat(user, "You try to push \the [I] through the lid but it doesn't work!") - return - - if( istype(I, /obj/item/pen/) ) - - if( src.open ) - return - - var/t = sanitize(input("Enter what you want to add to the tag:", "Write", null, null) as text, 30) - - var/obj/item/pizzabox/boxtotagto = src - if( boxes.len > 0 ) - boxtotagto = boxes[boxes.len] - - boxtotagto.boxtag = copytext("[boxtotagto.boxtag][t]", 1, 30) - - update_icon() - return - ..() - -/obj/item/pizzabox/margherita/Initialize() - . = ..() - pizza = new /obj/item/chems/food/snacks/sliceable/pizza/margherita(src) - boxtag = "Margherita Deluxe" - -/obj/item/pizzabox/vegetable/Initialize() - . = ..() - pizza = new /obj/item/chems/food/snacks/sliceable/pizza/vegetablepizza(src) - boxtag = "Gourmet Vegatable" - -/obj/item/pizzabox/mushroom/Initialize() - . = ..() - pizza = new /obj/item/chems/food/snacks/sliceable/pizza/mushroompizza(src) - boxtag = "Mushroom Special" - -/obj/item/pizzabox/meat/Initialize() - . = ..() - pizza = new /obj/item/chems/food/snacks/sliceable/pizza/meatpizza(src) - boxtag = "Meatlover's Supreme" - -/////////////////////////////////////////// -// new old food stuff from bs12 -/////////////////////////////////////////// - -/obj/item/chems/food/snacks/dough - name = "dough" - desc = "A piece of dough." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "dough" - bitesize = 2 - center_of_mass = @"{'x':16,'y':13}" - nutriment_desc = list("dough" = 3) - nutriment_amt = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -//obj/item/chems/food/snacks/dough/Initialize() -// .=..() -// reagents.add_reagent(/decl/material/liquid/nutriment/protein, 1) - -// Dough + rolling pin = flat dough -/obj/item/chems/food/snacks/dough/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/kitchen/rollingpin)) - new /obj/item/chems/food/snacks/sliceable/flatdough(src) - to_chat(user, "You flatten the dough.") - qdel(src) - -// slicable into 3x doughslices -/obj/item/chems/food/snacks/sliceable/flatdough - name = "flat dough" - desc = "A flattened dough." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "flat dough" - slice_path = /obj/item/chems/food/snacks/doughslice - slices_num = 3 - center_of_mass = @"{'x':16,'y':16}" - -/obj/item/chems/food/snacks/sliceable/flatdough/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 1) - reagents.add_reagent(/decl/material/liquid/nutriment, 3) - -/obj/item/chems/food/snacks/doughslice - name = "dough slice" - desc = "A building block of an impressive dish." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "doughslice" - slice_path = /obj/item/chems/food/snacks/spagetti - slices_num = 1 - bitesize = 2 - center_of_mass = @"{'x':17,'y':19}" - nutriment_desc = list("dough" = 1) - nutriment_amt = 1 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/bun - name = "bun" - desc = "A base for any self-respecting burger." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "bun" - bitesize = 2 - center_of_mass = @"{'x':16,'y':12}" - nutriment_desc = list("bun" = 4) - nutriment_amt = 4 - nutriment_type = /decl/material/liquid/nutriment/bread - -//Items you can craft together. Like bomb making, but with food and less screwdrivers. - -/obj/item/chems/food/snacks/bun/attackby(obj/item/W, mob/user) - // bun + meatball = burger - if(istype(W,/obj/item/chems/food/snacks/meatball)) - new /obj/item/chems/food/snacks/plainburger(src) - to_chat(user, "You make a burger.") - qdel(W) - qdel(src) - - // bun + cutlet = hamburger - else if(istype(W,/obj/item/chems/food/snacks/cutlet)) - new /obj/item/chems/food/snacks/hamburger(src) - to_chat(user, "You make a hamburger.") - qdel(W) - qdel(src) - - // bun + sausage = hotdog - else if(istype(W,/obj/item/chems/food/snacks/sausage)) - new /obj/item/chems/food/snacks/hotdog(src) - to_chat(user, "You make a hotdog.") - qdel(W) - qdel(src) - -// burger + cheese wedge = cheeseburger -/obj/item/chems/food/snacks/plainburger/attackby(obj/item/chems/food/snacks/cheesewedge/W, mob/user) - if(istype(W))// && !istype(src,/obj/item/chems/food/snacks/cheesewedge)) - new /obj/item/chems/food/snacks/cheeseburger(src) - to_chat(user, "You make a cheeseburger.") - qdel(W) - qdel(src) - return - else - ..() - -// Hamburger + cheese wedge = cheeseburger -/obj/item/chems/food/snacks/hamburger/attackby(obj/item/chems/food/snacks/cheesewedge/W, mob/user) - if(istype(W))// && !istype(src,/obj/item/chems/food/snacks/cheesewedge)) - new /obj/item/chems/food/snacks/cheeseburger(src) - to_chat(user, "You make a cheeseburger.") - qdel(W) - qdel(src) - return - else - ..() - -// Human burger + cheese wedge = cheeseburger -/obj/item/chems/food/snacks/human/burger/attackby(obj/item/chems/food/snacks/cheesewedge/W, mob/user) - if(istype(W)) - new /obj/item/chems/food/snacks/cheeseburger(src) - to_chat(user, "You make a cheeseburger.") - qdel(W) - qdel(src) - return - else - ..() - -// Spaghetti + meatball = spaghetti with meatball(s) -/obj/item/chems/food/snacks/boiledspagetti/attackby(obj/item/chems/food/snacks/meatball/W, mob/user) - if(istype(W)) - new /obj/item/chems/food/snacks/meatballspagetti(src) - to_chat(user, "You add some meatballs to the spaghetti.") - qdel(W) - qdel(src) - return - else - ..() - -// Spaghetti with meatballs + meatball = spaghetti with more meatball(s) -/obj/item/chems/food/snacks/meatballspagetti/attackby(obj/item/chems/food/snacks/meatball/W, mob/user) - if(istype(W)) - new /obj/item/chems/food/snacks/spesslaw(src) - to_chat(user, "You add some more meatballs to the spaghetti.") - qdel(W) - qdel(src) - return - else - ..() - -// Spaghetti + tomato = tomato'd spaghetti //commented out because I don't know how to define a tomato. -//obj/item/chems/food/snacks/spagetti/attackby(/obj/item/chems/food/snacks/grown/tomato/W, mob/user) -// if(istype(W)) -// new /obj/item/chems/food/snacks/pastatomato(src) -// to_chat(user, "You add some more meatballs to the spaghetti.") -// qdel(W) -// qdel(src) -// return -// else -// ..() - -/obj/item/chems/food/snacks/bunbun - name = "\improper Bun Bun" - desc = "A small bread monkey fashioned from two burger buns." - icon_state = "bunbun" - bitesize = 2 - center_of_mass = @"{'x':16,'y':8}" - nutriment_desc = list("bun" = 8) - nutriment_amt = 8 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/taco - name = "taco" - desc = "Take a bite!" - icon_state = "taco" - bitesize = 3 - center_of_mass = @"{'x':21,'y':12}" - nutriment_desc = list("cheese" = 2,"taco shell" = 2) - nutriment_amt = 4 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/taco/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 3) - -/obj/item/chems/food/snacks/rawcutlet - name = "raw cutlet" - desc = "A thin piece of raw meat." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "rawcutlet" - bitesize = 1 - center_of_mass = @"{'x':17,'y':20}" - -/obj/item/chems/food/snacks/rawcutlet/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 1) - -/obj/item/chems/food/snacks/cutlet - name = "cutlet" - desc = "A tasty meat slice." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "cutlet" - bitesize = 2 - center_of_mass = @"{'x':17,'y':20}" - -/obj/item/chems/food/snacks/cutlet/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/rawmeatball - name = "raw meatball" - desc = "A raw meatball." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "rawmeatball" - bitesize = 2 - center_of_mass = @"{'x':16,'y':15}" - -/obj/item/chems/food/snacks/rawmeatball/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 2) - -/obj/item/chems/food/snacks/hotdog - name = "hotdog" - desc = "Unrelated to dogs, maybe." - icon_state = "hotdog" - bitesize = 2 - center_of_mass = @"{'x':16,'y':17}" - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/hotdog/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 6) - -/obj/item/chems/food/snacks/classichotdog - name = "classic hotdog" - desc = "Going literal." - icon_state = "hotcorgi" - bitesize = 6 - center_of_mass = @"{'x':16,'y':17}" - -/obj/item/chems/food/snacks/classichotdog/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 16) - -/obj/item/chems/food/snacks/flatbread - name = "flatbread" - desc = "Bland but filling." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "flatbread" - bitesize = 2 - center_of_mass = @"{'x':16,'y':16}" - nutriment_desc = list("bread" = 3) - nutriment_amt = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -// potato + knife = raw sticks -/obj/item/chems/food/snacks/grown/potato/attackby(obj/item/W, mob/user) - if(istype(W,/obj/item/knife)) - new /obj/item/chems/food/snacks/rawsticks(src) - to_chat(user, "You cut the potato.") - qdel(src) - else - ..() - -/obj/item/chems/food/snacks/rawsticks - name = "raw potato sticks" - desc = "Uncooked potato stick, not very tasty." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "rawsticks" - bitesize = 2 - center_of_mass = @"{'x':16,'y':12}" - nutriment_desc = list("raw potato" = 3) - nutriment_amt = 3 - -//Canned Foods - crack open, eat. - -/obj/item/chems/food/snacks/canned - name = "void can" - icon = 'icons/obj/food_canned.dmi' - atom_flags = 0 - var/sealed = TRUE - -/obj/item/chems/food/snacks/canned/Initialize() - . = ..() - if(!sealed) - unseal() - -/obj/item/chems/food/snacks/canned/examine(mob/user) - . = ..() - to_chat(user, "It is [sealed ? "" : "un"]sealed.") - -/obj/item/chems/food/snacks/canned/proc/unseal() - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - sealed = FALSE - update_icon() - -/obj/item/chems/food/snacks/canned/attack_self(var/mob/user) - if(sealed) - playsound(loc,'sound/effects/canopen.ogg', rand(10,50), 1) - to_chat(user, "You unseal \the [src] with a crack of metal.") - unseal() - -/obj/item/chems/food/snacks/canned/on_update_icon() - if(!sealed) - icon_state = "[initial(icon_state)]-open" - -//Just a short line of Canned Consumables, great for treasure in faraway abandoned outposts - -/obj/item/chems/food/snacks/canned/beef - name = "quadrangled beefium" - icon_state = "beef" - desc = "Proteins carefully cloned from an extinct species of cattle in a secret facility on the outer rim." - trash = /obj/item/trash/beef - filling_color = "#663300" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("beef" = 1) - bitesize = 3 -/obj/item/chems/food/snacks/canned/beef/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 12) - -/obj/item/chems/food/snacks/canned/beans - name = "baked beans" - icon_state = "beans" - desc = "Carefully synthethized from soy." - trash = /obj/item/trash/beans - filling_color = "#ff6633" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("beans" = 1) - nutriment_amt = 12 - bitesize = 3 - -/obj/item/chems/food/snacks/canned/tomato - name = "tomato soup" - icon_state = "tomato" - desc = "Plain old unseasoned tomato soup. This can is older than you are!" - trash = /obj/item/trash/tomato - filling_color = "#ae0000" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("tomato" = 1) - bitesize = 3 - eat_sound = 'sound/items/drink.ogg' - -/obj/item/chems/food/snacks/canned/tomato/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/drink/juice/tomato, 12) - - -/obj/item/chems/food/snacks/canned/tomato/feed_sound(var/mob/user) - playsound(user.loc, 'sound/items/drink.ogg', rand(10, 50), 1) - -/obj/item/chems/food/snacks/canned/spinach - name = "spinach" - icon_state = "spinach" - desc = "Notably has less iron in it than a watermelon." - trash = /obj/item/trash/spinach - filling_color = "#003300" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("sogginess" = 1, "vegetable" = 1) - bitesize = 20 -/obj/item/chems/food/snacks/canned/spinach/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment, 5, - /decl/material/liquid/adrenaline, 5, - /decl/material/liquid/amphetamines, 5, - /decl/material/solid/metal/iron, 5) - -//Vending Machine Foods should go here. - -/obj/item/chems/food/snacks/canned/caviar - name = "canned caviar" - icon_state = "fisheggs" - desc = "Caviar, or space carp eggs. Carefully faked using alginate, artificial flavoring and salt." - trash = /obj/item/trash/fishegg - filling_color = "#000000" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("fish" = 1, "salt" = 1) - nutriment_amt = 6 - bitesize = 1 - -/obj/item/chems/food/snacks/canned/caviar/true - name = "canned caviar" - icon_state = "carpeggs" - desc = "Caviar, or space carp eggs. Exceeds the recomended amount of heavy metals in your diet! But very posh." - trash = /obj/item/trash/carpegg - filling_color = "#330066" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("fish" = 1, "salt" = 1, "numbing sensation" = 1) - nutriment_amt = 6 - bitesize = 1 -/obj/item/chems/food/snacks/caviar/true/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - reagents.add_reagent(/decl/material/liquid/carpotoxin, 1) - -/obj/item/chems/food/snacks/sosjerky - name = "emergency meat jerky" - icon_state = "sosjerky" - desc = "For when you desperately want meat and you don't care what kind. Has the same texture as old leather boots." - trash = /obj/item/trash/sosjerky - filling_color = "#631212" - center_of_mass = @"{'x':15,'y':9}" - bitesize = 2 -/obj/item/chems/food/snacks/sosjerky/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/no_raisin - name = "raisins" - icon_state = "4no_raisins" - desc = "Pouring water on these will not turn them back into grapes, unfortunately." - trash = /obj/item/trash/raisins - filling_color = "#343834" - center_of_mass = @"{'x':15,'y':4}" - nutriment_desc = list("raisins" = 6) - nutriment_amt = 6 - -/obj/item/chems/food/snacks/spacetwinkie - name = "eclair" - icon_state = "space_twinkie" - desc = "So full of preservatives, it's guaranteed to survive longer then you will." - filling_color = "#ffe591" - center_of_mass = @"{'x':15,'y':11}" - bitesize = 2 -/obj/item/chems/food/snacks/spacetwinkie/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 4) - -/obj/item/chems/food/snacks/cheesiehonkers - name = "cheese puffs" - icon_state = "cheesie_honkers" - desc = "Bite sized cheese flavoured snacks that will leave your fingers coated in cheese dust." - trash = /obj/item/trash/cheesie - filling_color = "#ffa305" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("cheese" = 5, "chips" = 2) - nutriment_amt = 4 - bitesize = 2 - -/obj/item/chems/food/snacks/syndicake - name = "subversive cakes" - icon_state = "syndi_cakes" - desc = "Made using extremely unethical labour, ingredients and marketing methods." - filling_color = "#ff5d05" - center_of_mass = @"{'x':16,'y':10}" - nutriment_desc = list("sweetness" = 3, "cake" = 1) - nutriment_amt = 4 - trash = /obj/item/trash/syndi_cakes - bitesize = 3 - -/obj/item/chems/food/snacks/syndicake/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/regenerator, 5) - -//terran delights - -/obj/item/chems/food/snacks/pistachios - name = "pistachios" - icon_state = "pistachios" - desc = "Pistachios. There is absolutely nothing remarkable about these." - trash = /obj/item/trash/pistachios - filling_color = "#825d26" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("nuts" = 1) - nutriment_amt = 3 - bitesize = 0.5 - -/obj/item/chems/food/snacks/semki - name = "sunflower seeds" - icon_state = "semki" - desc = "A favorite among birds." - trash = /obj/item/trash/semki - filling_color = "#68645d" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("sunflower seeds" = 1) - nutriment_amt = 6 - bitesize = 0.5 - -/obj/item/chems/food/snacks/squid - name = "\improper Calamari Crisps" - icon_state = "squid" - desc = "Space cepholapod tentacles, carefully removed from the squid then dried into strips of delicious rubbery goodness!" - trash = /obj/item/trash/squid - filling_color = "#c0a9d7" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("fish" = 1, "salt" = 1) - nutriment_amt = 2 - bitesize = 1 -/obj/item/chems/food/snacks/squid/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/croutons - name = "croutons" - icon_state = "croutons" - desc = "Fried bread cubes. Good in salad but I guess you can just eat them as is." - trash = /obj/item/trash/croutons - filling_color = "#c6b17f" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("bread" = 1, "salt" = 1) - nutriment_amt = 3 - bitesize = 1 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/salo - name = "salo" - icon_state = "salo" - desc = "Pig fat. Salted. Just as good as it sounds." - trash = /obj/item/trash/salo - filling_color = "#e0bcbc" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("fat" = 1, "salt" = 1) - nutriment_amt = 2 - bitesize = 2 -/obj/item/chems/food/snacks/salo/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 8) - -/obj/item/chems/food/snacks/driedfish - name = "vobla" - icon_state = "driedfish" - desc = "Dried salted beer snack fish." - trash = /obj/item/trash/driedfish - filling_color = "#c8a5bb" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("fish" = 1, "salt" = 1) - nutriment_amt = 2 - bitesize = 1 -/obj/item/chems/food/snacks/driedfish/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - -/obj/item/chems/food/snacks/liquidfood - name = "\improper LiquidFood MRE" - desc = "A prepackaged grey slurry for all of the essential nutrients a soldier requires to survive. No expiration date is visible..." - icon_state = "liquidfood" - trash = /obj/item/trash/liquidfood - filling_color = "#a8a8a8" - center_of_mass = @"{'x':16,'y':15}" - nutriment_desc = list("chalk" = 6) - nutriment_amt = 20 - bitesize = 4 -/obj/item/chems/food/snacks/liquidfood/Initialize() - .=..() - reagents.add_reagent(/decl/material/solid/metal/iron, 3) - -/obj/item/chems/food/snacks/meatcube - name = "cubed meat" - desc = "Fried, salted lean meat compressed into a cube. Not very appetizing." - icon_state = "meatcube" - filling_color = "#7a3d11" - center_of_mass = @"{'x':16,'y':16}" - bitesize = 3 -/obj/item/chems/food/snacks/meatcube/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 15) - -/obj/item/chems/food/snacks/tastybread - name = "bread tube" - desc = "Bread in a tube. Chewy... and surprisingly tasty." - icon_state = "tastybread" - trash = /obj/item/trash/tastybread - filling_color = "#a66829" - center_of_mass = @"{'x':17,'y':16}" - nutriment_desc = list("bread" = 2, "sweetness" = 3) - nutriment_amt = 6 - nutriment_type = /decl/material/liquid/nutriment/bread - bitesize = 2 - -/obj/item/chems/food/snacks/candy - name = "candy" - desc = "Nougat, love it or hate it." - icon_state = "candy" - trash = /obj/item/trash/candy - filling_color = "#7d5f46" - center_of_mass = @"{'x':15,'y':15}" - nutriment_amt = 1 - nutriment_desc = list("candy" = 1) - bitesize = 2 -/obj/item/chems/food/snacks/candy/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 3) - -/obj/item/chems/food/snacks/candy/proteinbar - name = "protein bar" - desc = "MuscleLopin brand protein bars, guaranteed to get you soSO strong!" - icon_state = "proteinbar" - trash = /obj/item/trash/candy/proteinbar - bitesize = 6 -/obj/item/chems/food/snacks/candy/proteinbar/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment, 9) - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 4) - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 4) - -/obj/item/chems/food/snacks/candy/donor - name = "donor candy" - desc = "A little treat for blood donors." - trash = /obj/item/trash/candy - nutriment_desc = list("candy" = 10) - bitesize = 5 -/obj/item/chems/food/snacks/candy/donor/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment, 10) - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 3) - -/obj/item/chems/food/snacks/candy_corn - name = "candy corn" - desc = "It's a handful of candy corn. Not actually candied corn." - icon_state = "candy_corn" - filling_color = "#fffcb0" - center_of_mass = @"{'x':14,'y':10}" - nutriment_amt = 4 - nutriment_desc = list("candy corn" = 4) - bitesize = 2 -/obj/item/chems/food/snacks/candy_corn/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment, 4) - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 2) - -/obj/item/chems/food/snacks/chips - name = "chips" - desc = "It is impossible to open the packet without rustling it loudly." - icon_state = "chips" - trash = /obj/item/trash/chips - filling_color = "#e8c31e" - center_of_mass = @"{'x':15,'y':15}" - nutriment_amt = 3 - nutriment_desc = list("salt" = 1, "chips" = 2) - bitesize = 1 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/cookie - name = "cookie" - desc = "COOKIE!!!" - icon_state = "cookie" - filling_color = "#dbc94f" - center_of_mass = @"{'x':17,'y':18}" - nutriment_amt = 5 - nutriment_desc = list("sweetness" = 3, "cookie" = 2) - w_class = ITEM_SIZE_TINY - bitesize = 1 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/chocolatebar - name = "chocolate bar" - desc = "Such sweet, fattening food." - icon_state = "chocolatebar" - filling_color = "#7d5f46" - center_of_mass = @"{'x':15,'y':15}" - nutriment_amt = 2 - nutriment_desc = list("chocolate" = 5) - bitesize = 2 -/obj/item/chems/food/snacks/chocolatebar/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 2) - reagents.add_reagent(/decl/material/liquid/nutriment/coco, 2) - -/obj/item/chems/food/snacks/chocolateegg - name = "chocolate egg" - desc = "Such sweet, fattening food." - icon_state = "chocolateegg" - filling_color = "#7d5f46" - center_of_mass = @"{'x':16,'y':13}" - nutriment_amt = 3 - nutriment_desc = list("chocolate" = 5) - bitesize = 2 - -/obj/item/chems/food/snacks/chocolateegg/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 2) - reagents.add_reagent(/decl/material/liquid/nutriment/coco, 2) - -/obj/item/chems/food/snacks/donut - name = "donut" - desc = "Goes great with Robust Coffee." - icon_state = "donut1" - filling_color = "#d9c386" - var/overlay_state = "box-donut1" - center_of_mass = @"{'x':13,'y':16}" - nutriment_desc = list("sweetness", "donut") - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/donut/normal - name = "donut" - desc = "Goes great with Robust Coffee." - icon_state = "donut1" - nutriment_amt = 3 - bitesize = 3 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/donut/normal/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 1) - - if(prob(30)) - src.icon_state = "donut2" - src.overlay_state = "box-donut2" - src.SetName("frosted donut") - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 2) - center_of_mass = @"{'x':19,'y':16}" - -/obj/item/chems/food/snacks/donut/chaos - name = "chaos donut" - desc = "Like life, it never quite tastes the same." - icon_state = "donut1" - filling_color = "#ed11e6" - nutriment_amt = 2 - bitesize = 10 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/donut/chaos/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 1) - reagents.add_reagent(pick(list( - /decl/material/liquid/nutriment, - /decl/material/liquid/capsaicin, - /decl/material/liquid/frostoil, - /decl/material/liquid/nutriment/sprinkles, - /decl/material/gas/chlorine, - /decl/material/liquid/nutriment/coco, - /decl/material/liquid/slimejelly, - /decl/material/liquid/nutriment/banana_cream, - /decl/material/liquid/nutriment/cherryjelly, - /decl/material/liquid/fuel, - /decl/material/liquid/regenerator)), 3) - if(prob(30)) - src.icon_state = "donut2" - src.overlay_state = "box-donut2" - src.SetName("frosted chaos donut") - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 2) - -/obj/item/chems/food/snacks/donut/jelly - name = "jelly donut" - desc = "You jelly?" - icon_state = "jdonut1" - filling_color = "#ed1169" - center_of_mass = @"{'x':16,'y':11}" - nutriment_amt = 3 - bitesize = 5 - nutriment_type = /decl/material/liquid/nutriment/bread - -/obj/item/chems/food/snacks/donut/jelly/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 1) - reagents.add_reagent(/decl/material/liquid/nutriment/cherryjelly, 5) - if(prob(30)) - src.icon_state = "jdonut2" - src.overlay_state = "box-donut2" - src.SetName("frosted jelly donut") - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 2) - -/obj/item/chems/food/snacks/donut/slimejelly - name = "jelly donut" - desc = "You jelly?" - icon_state = "jdonut1" - filling_color = "#ed1169" - center_of_mass = @"{'x':16,'y':11}" - nutriment_amt = 3 - bitesize = 5 -/obj/item/chems/food/snacks/donut/slimejelly/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 1) - reagents.add_reagent(/decl/material/liquid/slimejelly, 5) - if(prob(30)) - src.icon_state = "jdonut2" - src.overlay_state = "box-donut2" - src.SetName("frosted jelly donut") - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 2) - -/obj/item/chems/food/snacks/donut/cherryjelly - name = "jelly donut" - desc = "You jelly?" - icon_state = "jdonut1" - filling_color = "#ed1169" - center_of_mass = @"{'x':16,'y':11}" - nutriment_amt = 3 - bitesize = 5 -/obj/item/chems/food/snacks/donut/cherryjelly/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 1) - reagents.add_reagent(/decl/material/liquid/nutriment/cherryjelly, 5) - if(prob(30)) - src.icon_state = "jdonut2" - src.overlay_state = "box-donut2" - src.SetName("frosted jelly donut") - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 2) - -//Sol Vendor - -obj/item/chems/food/snacks/lunacake - name = "moon cake" - icon_state = "lunacake_wrapped" - desc = "Now with 20% less lawsuit enabling regolith!" - trash = /obj/item/trash/cakewrap - filling_color = "#ffffff" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("sweet" = 4, "vanilla" = 1) - nutriment_amt = 5 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -obj/item/chems/food/snacks/lunacake/mochicake - name = "mochi" - icon_state = "mochicake_wrapped" - desc = "A type of rice cake with an extremely soft, glutinous texture." - trash = /obj/item/trash/mochicakewrap - nutriment_desc = list("sweet" = 4, "rice" = 1) - -obj/item/chems/food/snacks/lunacake/mooncake - name = "dark side moon cake" - icon_state = "mooncake_wrapped" - desc = "Explore the dark side! May contain trace amounts of reconstituted cocoa." - trash = /obj/item/trash/mooncakewrap - filling_color = "#000000" - nutriment_desc = list("sweet" = 4, "chocolate" = 1) - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -obj/item/chems/food/snacks/triton - name = "\improper Tidal Gobs" - icon_state = "tidegobs" - desc = "Contains over 9000% of your daily recommended intake of salt." - trash = /obj/item/trash/tidegobs - filling_color = "#2556b0" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("salt" = 4, "ocean" = 1, "seagull" = 1) - nutriment_amt = 5 - bitesize = 2 - -obj/item/chems/food/snacks/saturn - name = "snack rings" - icon_state = "saturno" - desc = "A day ration of salt, styrofoam and possibly sawdust." - trash = /obj/item/trash/saturno - filling_color = "#dca319" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("salt" = 4, "peanut" = 2, "wood?" = 1) - nutriment_amt = 5 - bitesize = 2 - -obj/item/chems/food/snacks/jupiter - name = "probably gelatin" - icon_state = "jupiter" - desc = "Some kind of gel, maybe?" - trash = /obj/item/trash/jupiter - filling_color = "#dc1919" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("jelly?" = 5) - nutriment_amt = 5 - bitesize = 2 - -obj/item/chems/food/snacks/pluto - name = "nutrient rods" - icon_state = "pluto" - desc = "Baseless tasteless nutrient rods to get you through the day. Now even less rash inducing!" - trash = /obj/item/trash/pluto - filling_color = "#ffffff" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("chalk" = 4, "sadness" = 1) - nutriment_amt = 5 - bitesize = 2 - -obj/item/chems/food/snacks/mars - name = "instant potato and eggs" - icon_state = "mars" - desc = "A steaming self-heated bowl of sweet eggs and taters!" - trash = /obj/item/trash/mars - filling_color = "#d2c63f" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("eggs" = 4, "potato" = 4, "mustard" = 2) - nutriment_amt = 8 - bitesize = 2 - -obj/item/chems/food/snacks/venus - name = "hot cakes" - icon_state = "venus" - desc = "Hot takes on hot cakes, a timeless classic now finally fit for human consumption!" - trash = /obj/item/trash/venus - filling_color = "#d2c63f" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("heat" = 4, "burning" = 1) - nutriment_amt = 5 - bitesize = 2 - nutriment_type = /decl/material/liquid/nutriment/bread/cake - -/obj/item/chems/food/snacks/venus/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/capsaicin = 5) - -obj/item/chems/food/snacks/oort - name = "\improper Cloud Rocks" - icon_state = "oort" - desc = "Pop rocks. The new formula guarantees fewer shrapnel induced oral injuries." - trash = /obj/item/trash/oort - filling_color = "#3f7dd2" - center_of_mass = @"{'x':15,'y':9}" - nutriment_desc = list("fizz" = 3, "sweet?" = 1, "shrapnel" = 1) - nutriment_amt = 5 - bitesize = 2 -/obj/item/chems/food/snacks/oort/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/frostoil = 5) - -//weebo vend! So japanese it hurts - -obj/item/chems/food/snacks/ricecake - name = "rice ball" - icon_state = "ricecake" - desc = "A snack food made from balled up rice." - nutriment_desc = list("rice" = 3, "sweet" = 1, "seaweed" = 1) - nutriment_amt = 5 - bitesize = 2 - -obj/item/chems/food/snacks/pokey - name = "chocolate coated biscuit sticks" - icon_state = "pokeys" - desc = "A bundle of chocolate coated biscuit sticks. Not as exciting as they seem." - nutriment_desc = list("chocolate" = 1, "biscuit" = 2, "cardboard" = 2) - nutriment_amt = 5 - bitesize = 2 - -obj/item/chems/food/snacks/weebonuts - name = "spicy nuts" - icon_state = "weebonuts" - trash = /obj/item/trash/weebonuts - desc = "A bag of spicy nuts. Goes well with beer!" - nutriment_desc = list("nuts" = 4, "spicy!" = 1) - nutriment_amt = 5 - bitesize = 2 -/obj/item/chems/food/snacks/weebonuts/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/capsaicin = 1) - -obj/item/chems/food/snacks/chocobanana - name = "choco banana" - icon_state = "chocobanana" - trash = /obj/item/trash/stick - desc = "A chocolate and sprinkles coated banana. On a stick." - nutriment_desc = list("banana" = 3, "chocolate" = 1, "wax?" = 1) - nutriment_amt = 5 - bitesize = 2 -/obj/item/chems/food/snacks/chocobanana/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/nutriment/sprinkles, 10) - -obj/item/chems/food/snacks/dango - name = "dango" - icon_state = "dango" - trash = /obj/item/trash/stick - desc = "Food dyed rice dumplings on a stick." - nutriment_desc = list("rice" = 4, "topping?" = 1) - nutriment_amt = 5 - bitesize = 2 - -//inedible old vendor food - -/obj/item/chems/food/snacks/old - name = "master old-food" - desc = "they're all inedible and potentially dangerous items" - center_of_mass = @"{'x':15,'y':12}" - nutriment_desc = list("rot" = 5, "mold" = 5) - nutriment_amt = 10 - bitesize = 3 - filling_color = "#336b42" -/obj/item/chems/food/snacks/old/Initialize() - .=..() - reagents.add_reagent(pick(list( - /decl/material/liquid/fuel, - /decl/material/liquid/amatoxin, - /decl/material/liquid/carpotoxin, - /decl/material/liquid/zombiepowder, - /decl/material/liquid/presyncopics, - /decl/material/liquid/psychotropics)), 5) - - -/obj/item/chems/food/snacks/old/pizza - name = "pizza" - desc = "It's so stale you could probably cut something with the cheese." - icon_state = "ancient_pizza" - -/obj/item/chems/food/snacks/old/burger - name = "\improper Giga Burger!" - desc = "At some point in time this probably looked delicious." - icon_state = "ancient_burger" - -/obj/item/chems/food/snacks/old/hamburger - name = "\improper Horse Burger!" - desc = "Even if you were hungry enough to eat a horse, it'd be a bad idea to eat this." - icon_state = "ancient_hburger" - -/obj/item/chems/food/snacks/old/fries - name = "chips" - desc = "The salt appears to have preserved these, still stale and gross." - icon_state = "ancient_fries" - -/obj/item/chems/food/snacks/old/hotdog - name = "hotdog" - desc = "This one is probably only marginally less safe to eat than when it was first created.." - icon_state = "ancient_hotdog" - -/obj/item/chems/food/snacks/old/taco - name = "taco" - desc = "Interestingly, the shell has gone soft and the contents have gone stale." - icon_state = "ancient_taco" \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/snacks/meat.dm b/code/modules/reagents/reagent_containers/food/snacks/meat.dm deleted file mode 100644 index 6560c1bb5a83..000000000000 --- a/code/modules/reagents/reagent_containers/food/snacks/meat.dm +++ /dev/null @@ -1,47 +0,0 @@ -/obj/item/chems/food/snacks/meat - name = "meat" - desc = "A slab of meat." - icon = 'icons/obj/food_ingredients.dmi' - icon_state = "meat" - slice_path = /obj/item/chems/food/snacks/rawcutlet - slices_num = 3 - health = 180 - filling_color = "#ff1c1c" - center_of_mass = @"{'x':16,'y':14}" - -/obj/item/chems/food/snacks/meat/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 9) - bitesize = 3 - -/obj/item/chems/food/snacks/meat/syntiflesh - name = "synthetic meat" - desc = "A slab of flesh synthetized from reconstituted biomass or artificially grown from chemicals." - icon = 'icons/obj/food.dmi' - -// Seperate definitions because some food likes to know if it's human. -// TODO: rewrite kitchen code to check a var on the meat item so we can remove -// all these sybtypes. -/obj/item/chems/food/snacks/meat/human -/obj/item/chems/food/snacks/meat/monkey - //same as plain meat - -/obj/item/chems/food/snacks/meat/corgi - name = "corgi meat" - desc = "Tastes like... well, you know." - -/obj/item/chems/food/snacks/meat/beef - name = "beef slab" - desc = "The classic red meat." - -/obj/item/chems/food/snacks/meat/goat - name = "chevon slab" - desc = "Goat meat, to the uncultured." - -/obj/item/chems/food/snacks/meat/chicken - name = "chicken piece" - desc = "It tastes like you'd expect." - -/obj/item/chems/food/snacks/meat/chicken/game - name = "game bird piece" - desc = "Fresh game meat, harvested from some wild bird." \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/soy.dm b/code/modules/reagents/reagent_containers/food/soy.dm new file mode 100644 index 000000000000..5f2f548b0c0c --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/soy.dm @@ -0,0 +1,33 @@ +/obj/item/food/tofu + name = "tofu" + icon = 'icons/obj/food/tofu/tofu.dmi' + desc = "We all love tofu." + filling_color = "#fffee0" + center_of_mass = @'{"x":17,"y":10}' + nutriment_amt = 3 + nutriment_desc = list("tofu" = 3, "softness" = 3) + bitesize = 3 + +/obj/item/food/tofu/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/nutriment/plant_protein, 6) + +/obj/item/food/tofurkey + name = "\improper Tofurkey" + desc = "A fake turkey made from tofu." + icon = 'icons/obj/food/tofu/tofurkey.dmi' + filling_color = "#fffee0" + center_of_mass = @'{"x":16,"y":8}' + nutriment_amt = 12 + nutriment_desc = list("turkey" = 3, "tofu" = 5, "softness" = 4) + bitesize = 3 + +/obj/item/food/stewedsoymeat + name = "stewed soy meat" + desc = "Even non-vegetarians will LOVE this!" + icon = 'icons/obj/food/tofu/soymeat.dmi' + plate = /obj/item/plate + center_of_mass = @'{"x":16,"y":10}' + nutriment_desc = list("soy" = 4, "tomato" = 4) + nutriment_amt = 8 + bitesize = 2 diff --git a/code/modules/reagents/reagent_containers/food/sushi.dm b/code/modules/reagents/reagent_containers/food/sushi.dm index 3ec7d4e47cdc..e840beb60e33 100644 --- a/code/modules/reagents/reagent_containers/food/sushi.dm +++ b/code/modules/reagents/reagent_containers/food/sushi.dm @@ -1,32 +1,32 @@ -/obj/item/chems/food/snacks/sushi +/obj/item/food/sushi name = "sushi" desc = "A small, neatly wrapped morsel. Itadakimasu!" icon = 'icons/obj/sushi.dmi' icon_state = "sushi_rice" bitesize = 1 + allergen_flags = ALLERGEN_FISH var/fish_type = "fish" -/obj/item/chems/food/snacks/sushi/Initialize(mapload, var/obj/item/chems/food/snacks/rice, var/obj/item/chems/food/snacks/topping) - . = ..(mapload) +/obj/item/food/sushi/Initialize(mapload, material_key, skip_plate = FALSE, obj/item/food/rice, obj/item/food/topping) + . = ..(mapload, material_key, skip_plate) if(istype(topping)) for(var/taste_thing in topping.nutriment_desc) if(!nutriment_desc[taste_thing]) nutriment_desc[taste_thing] = 0 nutriment_desc[taste_thing] += topping.nutriment_desc[taste_thing] - if(istype(topping, /obj/item/chems/food/snacks/sashimi)) - var/obj/item/chems/food/snacks/sashimi/sashimi = topping + if(istype(topping, /obj/item/food/sashimi)) + var/obj/item/food/sashimi/sashimi = topping fish_type = sashimi.fish_type - else if(istype(topping, /obj/item/chems/food/snacks/meat/chicken)) - fish_type = "chicken" - else if(istype(topping, /obj/item/chems/food/snacks/friedegg)) + else if(istype(topping, /obj/item/food/butchery)) + var/obj/item/food/butchery/meat = topping + fish_type = meat.meat_name + else if(istype(topping, /obj/item/food/friedegg)) fish_type = "egg" - else if(istype(topping, /obj/item/chems/food/snacks/tofu)) + else if(istype(topping, /obj/item/food/tofu)) fish_type = "tofu" - else if(istype(topping, /obj/item/chems/food/snacks/rawcutlet) || istype(topping, /obj/item/chems/food/snacks/cutlet)) - fish_type = "meat" if(topping.reagents) - topping.reagents.trans_to(src, topping.reagents.total_volume) + topping.reagents.trans_to(src, REAGENT_TOTAL_VOLUME(topping.reagents)) var/mob/M = topping.loc if(istype(M)) M.drop_from_inventory(topping) @@ -35,115 +35,137 @@ if(istype(rice)) if(rice.reagents) rice.reagents.trans_to(src, 1) - if(!rice.reagents || !rice.reagents.total_volume) + if(!rice.reagents || !REAGENT_TOTAL_VOLUME(rice.reagents)) var/mob/M = rice.loc if(istype(M)) M.drop_from_inventory(rice) qdel(rice) update_icon() -/obj/item/chems/food/snacks/sushi/on_update_icon() +/obj/item/food/sushi/on_update_icon() + . = ..() name = "[fish_type] sushi" - overlays = list("[fish_type]", "nori") + add_overlay(list("[fish_type]", "nori")) + +/obj/item/food/sushi/apply_filling_overlay() + return //Bypass searching through the whole icon file for a filling icon ///////////// // SASHIMI // ///////////// -/obj/item/chems/food/snacks/sashimi +/obj/item/food/sashimi name = "sashimi" icon = 'icons/obj/sushi.dmi' desc = "Thinly sliced raw fish. Tasty." icon_state = "sashimi" gender = PLURAL bitesize = 1 + slice_num = 1 + slice_path = /obj/item/food/butchery/chopped + allergen_flags = ALLERGEN_FISH var/fish_type = "fish" var/slices = 1 -/obj/item/chems/food/snacks/sashimi/Initialize(mapload, var/_fish_type) - . = ..(mapload) - if(_fish_type) fish_type = _fish_type +/obj/item/food/sashimi/Initialize(mapload, material_key, skip_plate = FALSE, _fish_type) + . = ..(mapload, material_key, skip_plate) + if(_fish_type) + fish_type = _fish_type name = "[fish_type] sashimi" update_icon() -/obj/item/chems/food/snacks/sashimi/on_update_icon() +/obj/item/food/sashimi/on_update_icon() + . = ..() icon_state = "sashimi_base" var/list/adding = list() var/slice_offset = (slices-1)*2 for(var/slice = 1 to slices) - var/image/I = image(icon = icon, icon_state = "sashimi") - I.pixel_x = slice_offset-((slice-1)*4) - I.pixel_y = I.pixel_x - adding += I - overlays = adding + var/offset = slice_offset-((slice-1)*4) + adding += image(icon = icon, icon_state = "sashimi", pixel_x = offset, pixel_y = offset) + add_overlay(adding) -/obj/item/chems/food/snacks/sashimi/attackby(var/obj/item/I, var/mob/user) +/obj/item/food/sashimi/attackby(var/obj/item/used_item, var/mob/user) if(!(locate(/obj/structure/table) in loc)) return ..() // Add more slices. - if(istype(I, /obj/item/chems/food/snacks/sashimi)) - var/obj/item/chems/food/snacks/sashimi/other_sashimi = I + if(istype(used_item, /obj/item/food/sashimi)) + var/obj/item/food/sashimi/other_sashimi = used_item if(slices + other_sashimi.slices > 5) to_chat(user, "Show some restraint, would you?") - return - if(!user.unEquip(I)) - return + return TRUE + if(!user.try_unequip(used_item)) + return TRUE slices += other_sashimi.slices bitesize = slices update_icon() - if(I.reagents) - I.reagents.trans_to(src, I.reagents.total_volume) - qdel(I) - return + if(used_item.reagents) + used_item.reagents.trans_to(src, REAGENT_TOTAL_VOLUME(used_item.reagents)) + qdel(used_item) + return TRUE // Make sushi. - if(istype(I, /obj/item/chems/food/snacks/boiledrice)) + if(istype(used_item, /obj/item/food/boiledrice)) if(slices > 1) to_chat(user, "Putting more than one slice of fish on your sushi is just greedy.") else - if(!user.unEquip(I)) - return - new /obj/item/chems/food/snacks/sushi(get_turf(src), I, src) - return + if(!user.try_unequip(used_item)) + return TRUE + new /obj/item/food/sushi(get_turf(src), null, TRUE, used_item, src) + return TRUE + . = ..() + +/obj/item/food/sashimi/handle_utensil_cutting(obj/item/tool, mob/user) + slice_num = slices // to avoid wasting it . = ..() + if(length(.)) + for(var/obj/item/food/food in .) + food.cooked_food = cooked_food + food.add_allergen_flags(allergen_flags) + if(fish_type) + for(var/obj/item/food/butchery/meat in .) + meat.set_meat_name(fish_type) // Used for turning rice into sushi. -/obj/item/chems/food/snacks/boiledrice/attackby(var/obj/item/I, var/mob/user) +/obj/item/food/boiledrice/attackby(var/obj/item/used_item, var/mob/user) if((locate(/obj/structure/table) in loc)) - if(istype(I, /obj/item/chems/food/snacks/sashimi)) - var/obj/item/chems/food/snacks/sashimi/sashimi = I + if(istype(used_item, /obj/item/food/sashimi)) + var/obj/item/food/sashimi/sashimi = used_item if(sashimi.slices > 1) to_chat(user, "Putting more than one slice of fish on your sushi is just greedy.") else - new /obj/item/chems/food/snacks/sushi(get_turf(src), src, I) - return - if(istype(I, /obj/item/chems/food/snacks/friedegg) || \ - istype(I, /obj/item/chems/food/snacks/tofu) || \ - istype(I, /obj/item/chems/food/snacks/cutlet) || \ - istype(I, /obj/item/chems/food/snacks/rawcutlet) || \ - istype(I, /obj/item/chems/food/snacks/spider) || \ - istype(I, /obj/item/chems/food/snacks/meat/chicken)) - new /obj/item/chems/food/snacks/sushi(get_turf(src), src, I) - return + new /obj/item/food/sushi(get_turf(src), null, TRUE, src, used_item) + return TRUE + var/static/list/sushi_types = list( + /obj/item/food/friedegg, + /obj/item/food/tofu, + /obj/item/food/butchery/cutlet, + /obj/item/food/butchery/cutlet/raw, + /obj/item/food/spider, + /obj/item/food/butchery/meat/chicken + ) + if(is_type_in_list(used_item, sushi_types)) + new /obj/item/food/sushi(get_turf(src), null, TRUE, src, used_item) + return TRUE . = ..() // Used for turning other food into sushi. -/obj/item/chems/food/snacks/friedegg/attackby(var/obj/item/I, var/mob/user) - if((locate(/obj/structure/table) in loc) && istype(I, /obj/item/chems/food/snacks/boiledrice)) - new /obj/item/chems/food/snacks/sushi(get_turf(src), I, src) - return +// TODO: maybe make these resolve_attackby overrides on boiledrice instead? +/obj/item/food/friedegg/attackby(var/obj/item/used_item, var/mob/user) + if((locate(/obj/structure/table) in loc) && istype(used_item, /obj/item/food/boiledrice)) + new /obj/item/food/sushi(get_turf(src), null, TRUE, used_item, src) + return TRUE . = ..() -/obj/item/chems/food/snacks/tofu/attackby(var/obj/item/I, var/mob/user) - if((locate(/obj/structure/table) in loc) && istype(I, /obj/item/chems/food/snacks/boiledrice)) - new /obj/item/chems/food/snacks/sushi(get_turf(src), I, src) - return +/obj/item/food/tofu/attackby(var/obj/item/used_item, var/mob/user) + if((locate(/obj/structure/table) in loc) && istype(used_item, /obj/item/food/boiledrice)) + new /obj/item/food/sushi(get_turf(src), null, TRUE, used_item, src) + return TRUE . = ..() -/obj/item/chems/food/snacks/rawcutlet/attackby(var/obj/item/I, var/mob/user) - if((locate(/obj/structure/table) in loc) && istype(I, /obj/item/chems/food/snacks/boiledrice)) - new /obj/item/chems/food/snacks/sushi(get_turf(src), I, src) - return +/obj/item/food/butchery/cutlet/raw/attackby(var/obj/item/used_item, var/mob/user) + if((locate(/obj/structure/table) in loc) && istype(used_item, /obj/item/food/boiledrice)) + new /obj/item/food/sushi(get_turf(src), null, TRUE, used_item, src) + return TRUE . = ..() -/obj/item/chems/food/snacks/cutlet/attackby(var/obj/item/I, var/mob/user) - if((locate(/obj/structure/table) in loc) && istype(I, /obj/item/chems/food/snacks/boiledrice)) - new /obj/item/chems/food/snacks/sushi(get_turf(src), I, src) - return +/obj/item/food/butchery/cutlet/attackby(var/obj/item/used_item, var/mob/user) + if((locate(/obj/structure/table) in loc) && istype(used_item, /obj/item/food/boiledrice)) + new /obj/item/food/sushi(get_turf(src), null, TRUE, used_item, src) + return TRUE . = ..() -// End non-fish sushi. \ No newline at end of file +// End non-fish sushi. diff --git a/code/modules/reagents/reagent_containers/food/veggie.dm b/code/modules/reagents/reagent_containers/food/veggie.dm new file mode 100644 index 000000000000..efb2c56aa1c3 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/veggie.dm @@ -0,0 +1,61 @@ +////////////////// +// Veggie Foods // +////////////////// + +/obj/item/food/aesirsalad + name = "\improper Aether salad" + desc = "Probably too incredible for mortal men to fully enjoy." + icon = 'icons/obj/food/salads/salad.dmi' + icon_state = "aesirsalad" + trash = /obj/item/trash/snack_bowl + filling_color = "#468c00" + center_of_mass = @'{"x":17,"y":11}' + nutriment_amt = 8 + nutriment_desc = list("apples" = 3,"salad" = 4, "quintessence" = 2) + bitesize = 3 + +/obj/item/food/aesirsalad/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/regenerator, 8) + +/obj/item/food/tossedsalad + name = "tossed salad" + desc = "A proper salad, basic and simple, with little bits of carrot, tomato and apple intermingled. Vegan!" + icon = 'icons/obj/food/salads/salad.dmi' + icon_state = "herbsalad" + trash = /obj/item/trash/snack_bowl + filling_color = "#76b87f" + center_of_mass = @'{"x":17,"y":11}' + nutriment_desc = list("salad" = 2, "tomato" = 2, "carrot" = 2, "apple" = 2) + nutriment_amt = 8 + bitesize = 3 + +/obj/item/food/validsalad + name = "valid salad" + desc = "It's just a salad of questionable 'herbs' with meatballs and fried potato slices. Nothing suspicious about it." + icon = 'icons/obj/food/salads/salad.dmi' + icon_state = "validsalad" + trash = /obj/item/trash/snack_bowl + filling_color = "#76b87f" + center_of_mass = @'{"x":17,"y":11}' + nutriment_desc = list("100% real salad") + nutriment_amt = 6 + bitesize = 3 + +/obj/item/food/validsalad/populate_reagents() + . = ..() + add_to_reagents(/decl/material/solid/organic/meat, 2) + +/obj/item/food/hugemushroomslice + name = "huge mushroom slice" + desc = "A slice from a huge mushroom." + icon = 'icons/obj/food/butchery/mushroom.dmi' + filling_color = "#e0d7c5" + center_of_mass = @'{"x":17,"y":16}' + nutriment_amt = 3 + nutriment_desc = list("raw" = 2, "mushroom" = 2) + bitesize = 6 + +/obj/item/food/hugemushroomslice/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/psychotropics, 3) diff --git a/code/modules/reagents/reagent_containers/food_cooking.dm b/code/modules/reagents/reagent_containers/food_cooking.dm new file mode 100644 index 000000000000..3aeedb583b29 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food_cooking.dm @@ -0,0 +1,69 @@ +/obj/item/food + /// What object type the food cooks into. + var/backyard_grilling_product = /obj/item/food/badrecipe + /// How many SSobj ticks it takes for the food to cook. + var/backyard_grilling_rawness = 30 + /// The message shown when the food cooks. + var/backyard_grilling_announcement = "smokes and chars!" + /// The span class used for the message above. Burned food defaults to SPAN_DANGER. + var/backyard_grilling_span = "notice" + /// The number of times this object and its ancestors have been grilled. Used for grown foods' roasted chems. + var/backyard_grilling_count = 0 + /// Is this ingredient considered meat, fish, veg, etc + var/allergen_flags = ALLERGEN_NONE + +/obj/item/food/get_dried_product() + drop_plate(get_turf(loc)) + if(dried_type == type && !dry) + dry = TRUE + name = "dried [name]" + color = "#aaaaaa" + return src + return ..() + +/obj/item/food/is_dryable() + return !dry + +/obj/item/food/get_dryness_text(var/obj/rack) + var/moistness = drying_wetness / get_max_drying_wetness() + if(moistness > 0.65) + return "fresh" + if(moistness > 0.35) + return "somewhat dried" + if(moistness) + return "almost dried" + return "dehydrated" + +/obj/item/food/dry_out(var/obj/rack, var/drying_power = 1, var/fire_exposed = FALSE, var/silent = FALSE) + return fire_exposed ? grill(rack) : ..() + +/obj/item/food/proc/get_grilled_product() + return new backyard_grilling_product(loc) + +/obj/item/food/proc/grill(var/atom/heat_source) + if(!backyard_grilling_product || backyard_grilling_rawness <= 0) + return null + backyard_grilling_rawness-- + if(backyard_grilling_rawness <= 0) + var/obj/item/product = get_grilled_product() + product.dropInto(loc) + var/obj/item/food/food = product + if(istype(food)) + food.backyard_grilling_count = src.backyard_grilling_count + 1 + if(backyard_grilling_announcement) + if(istype(product, /obj/item/food/badrecipe)) + product.visible_message(SPAN_DANGER("\The [src] [backyard_grilling_announcement]")) + else + product.visible_message("\The [src] [backyard_grilling_announcement]") + qdel(src) + return product + +/obj/item/food/proc/get_backyard_grilling_text(var/obj/rack) + var/moistness = backyard_grilling_rawness / initial(backyard_grilling_rawness) + if(moistness > 0.65) + return "uncooked" + if(moistness > 0.35) + return "half-cooked" + if(moistness) + return "nearly cooked" + return "cooked" diff --git a/code/modules/reagents/reagent_containers/food_edibility.dm b/code/modules/reagents/reagent_containers/food_edibility.dm new file mode 100644 index 000000000000..85113627dc92 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food_edibility.dm @@ -0,0 +1,50 @@ +/obj/item/food/get_edible_material_amount(mob/eater) + return REAGENT_TOTAL_VOLUME(reagents) + +/obj/item/food/get_food_consumption_method(mob/eater) + return EATING_METHOD_EAT + +/obj/item/food/play_feed_sound(mob/user, consumption_method = EATING_METHOD_EAT) + if(eat_sound) + playsound(user, pick(eat_sound), rand(10, 50), 1) + return + return ..() + +/obj/item/food/handle_eaten_by_mob(mob/user, mob/target) + . = ..() + if(. == EATEN_SUCCESS) + bitecount++ + +/obj/item/food/get_food_default_transfer_amount(mob/eater) + return eater?.get_eaten_transfer_amount(bitesize) + +/obj/item/food/handle_consumed(mob/feeder, mob/eater, consumption_method = EATING_METHOD_EAT) + + if(isliving(eater)) + var/mob/living/living_eater = eater + if(cooked_food == FOOD_COOKED) + living_eater.add_stressor(/datum/stressor/ate_cooked_food, 15 MINUTES) + else if(cooked_food == FOOD_RAW) + living_eater.add_stressor(/datum/stressor/ate_raw_food, 15 MINUTES) + + var/atom/loc_ref = loc + var/obj/item/plate_ref = plate + var/trash_ref = trash + . = ..() + if(.) + if(trash_ref) + if(ispath(trash_ref, /obj/item)) + var/obj/item/trash_item = new trash_ref(loc_ref) + trash_item.dropInto(loc_ref) + if(feeder) + feeder.put_in_hands(trash_item) + else if(istype(trash_ref, /obj/item)) + var/obj/item/trash_item = trash_ref + if(!QDELETED(trash_item)) + trash_item.dropInto(loc_ref) + if(feeder) + feeder.put_in_hands(trash_item) + if(plate_ref && !QDELETED(plate_ref)) + plate_ref.dropInto(loc_ref) + if(feeder) + feeder.put_in_hands(plate_ref) diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm deleted file mode 100644 index 58a7fa359418..000000000000 --- a/code/modules/reagents/reagent_containers/glass.dm +++ /dev/null @@ -1,144 +0,0 @@ - -//////////////////////////////////////////////////////////////////////////////// -/// (Mixing)Glass. -//////////////////////////////////////////////////////////////////////////////// -/obj/item/chems/glass - name = "" - desc = "" - icon_state = "null" - item_state = "null" - amount_per_transfer_from_this = 10 - possible_transfer_amounts = @"[5,10,15,25,30,60]" - volume = 60 - w_class = ITEM_SIZE_SMALL - atom_flags = ATOM_FLAG_OPEN_CONTAINER - unacidable = 1 //glass doesn't dissolve in acid - - var/list/can_be_placed_into = list( - /obj/machinery/chem_master/, - /obj/machinery/chemical_dispenser, - /obj/machinery/reagentgrinder, - /obj/structure/table, - /obj/structure/closet, - /obj/structure/hygiene/sink, - /obj/item/storage, - /obj/item/grenade/chem_grenade, - /mob/living/bot/medbot, - /obj/item/storage/secure/safe, - /obj/structure/iv_drip, - /obj/machinery/disposal, - /mob/living/simple_animal/cow, - /mob/living/simple_animal/hostile/retaliate/goat, - /obj/machinery/sleeper, - /obj/machinery/smartfridge/, - /obj/machinery/biogenerator, - /obj/machinery/constructable_frame, - /obj/machinery/radiocarbon_spectrometer - ) - -/obj/item/chems/glass/examine(mob/user, distance) - . = ..() - if(distance > 2) - return - - if(reagents?.total_volume) - to_chat(user, "It contains [reagents.total_volume] units of liquid.") - else - to_chat(user, "It is empty.") - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "The airtight lid seals it completely.") - -/obj/item/chems/glass/attack_self() - ..() - if(ATOM_IS_OPEN_CONTAINER(src)) - to_chat(usr, "You put the lid on \the [src].") - atom_flags ^= ATOM_FLAG_OPEN_CONTAINER - else - to_chat(usr, "You take the lid off \the [src].") - atom_flags |= ATOM_FLAG_OPEN_CONTAINER - update_icon() - -/obj/item/chems/glass/attack(mob/M, mob/user, def_zone) - if(force && !(item_flags & ITEM_FLAG_NO_BLUDGEON) && user.a_intent == I_HURT) - return ..() - if(standard_feed_mob(user, M)) - return - return 0 - -/obj/item/chems/glass/standard_feed_mob(var/mob/user, var/mob/target) - if(!ATOM_IS_OPEN_CONTAINER(src)) - to_chat(user, "You need to open \the [src] first.") - return 1 - if(user.a_intent == I_HURT) - return 1 - return ..() - -/obj/item/chems/glass/self_feed_message(var/mob/user) - to_chat(user, "You swallow a gulp from \the [src].") - if(user.has_personal_goal(/datum/goal/achievement/specific_object/drink)) - for(var/R in reagents.reagent_volumes) - user.update_personal_goal(/datum/goal/achievement/specific_object/drink, R) - -/obj/item/chems/glass/afterattack(var/obj/target, var/mob/user, var/proximity) - if(!ATOM_IS_OPEN_CONTAINER(src) || !proximity) //Is the container open & are they next to whatever they're clicking? - return 1 //If not, do nothing. - for(var/type in can_be_placed_into) //Is it something it can be placed into? - if(istype(target, type)) - return 1 - if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser? - return 1 - if(standard_pour_into(user, target)) //Pouring into another beaker? - return - if(user.a_intent == I_HURT) - if(standard_splash_mob(user,target)) - return 1 - if(reagents && reagents.total_volume) - to_chat(user, "You splash the contents of \the [src] onto [target].") //They are on harm intent, aka wanting to spill it. - reagents.splash(target, reagents.total_volume) - return 1 - ..() - -/obj/item/chems/glass/bucket - name = "bucket" - desc = "It's a bucket." - icon = 'icons/obj/items/bucket.dmi' - icon_state = ICON_STATE_WORLD - center_of_mass = @"{'x':16,'y':9}" - w_class = ITEM_SIZE_NORMAL - amount_per_transfer_from_this = 20 - possible_transfer_amounts = @"[10,20,30,60,120,150,180]" - volume = 180 - atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_SHOW_REAGENT_NAME - unacidable = 0 - material = /decl/material/solid/plastic - material_force_multiplier = 0.2 - slot_flags = SLOT_HEAD - -/obj/item/chems/glass/bucket/wood - desc = "It's a wooden bucket. How rustic." - icon = 'icons/obj/items/wooden_bucket.dmi' - volume = 200 - material = /decl/material/solid/wood - -/obj/item/chems/glass/bucket/attackby(var/obj/D, mob/user) - if(istype(D, /obj/item/mop)) - if(reagents.total_volume < 1) - to_chat(user, "\The [src] is empty!") - else - reagents.trans_to_obj(D, 5) - to_chat(user, "You wet \the [D] in \the [src].") - playsound(loc, 'sound/effects/slosh.ogg', 25, 1) - return - else - return ..() - -/obj/item/chems/glass/bucket/on_update_icon() - var/new_overlays - if (!ATOM_IS_OPEN_CONTAINER(src)) - var/image/lid = image(icon, src, "lid_[initial(icon_state)]") - LAZYADD(new_overlays, lid) - else if(reagents && reagents.total_volume && round((reagents.total_volume / volume) * 100) > 80) - var/image/filling = image('icons/obj/reagentfillings.dmi', src, "bucket") - filling.color = reagents.get_color() - LAZYADD(new_overlays, filling) - overlays = new_overlays diff --git a/code/modules/reagents/reagent_containers/glass/bottle.dm b/code/modules/reagents/reagent_containers/glass/bottle.dm index 8bb1fdba2a8c..8b954cb90d07 100644 --- a/code/modules/reagents/reagent_containers/glass/bottle.dm +++ b/code/modules/reagents/reagent_containers/glass/bottle.dm @@ -1,211 +1,174 @@ -//Not to be confused with /obj/item/chems/food/drinks/bottle +//Not to be confused with /obj/item/chems/drinks/bottle /obj/item/chems/glass/bottle name = "bottle" + base_name = "bottle" desc = "A small bottle." icon = 'icons/obj/items/chem/bottle.dmi' - icon_state = null - item_state = "atoxinbottle" + icon_state = ICON_STATE_WORLD randpixel = 7 - center_of_mass = @"{'x':15,'y':10}" + center_of_mass = @'{"x":16,"y":15}' amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[5,10,15,25,30,60]" w_class = ITEM_SIZE_SMALL item_flags = 0 obj_flags = 0 - volume = 60 + chem_volume = 60 + material = /decl/material/solid/glass + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME -/obj/item/chems/glass/bottle/pickup(mob/user) - ..() + var/label_color + var/lid_color = COLOR_GRAY80 + var/autolabel = TRUE // if set, will add label with the name of the first initial reagent + +/obj/item/chems/glass/bottle/get_lid_color() + return lid_color + +/obj/item/chems/glass/bottle/on_picked_up(mob/user, atom/old_loc) + . = ..() update_icon() /obj/item/chems/glass/bottle/dropped(mob/user) - ..() + . = ..() update_icon() /obj/item/chems/glass/bottle/attack_hand() - ..() + . = ..() update_icon() -/obj/item/chems/glass/bottle/Initialize() +/obj/item/chems/glass/bottle/update_overlays() + if(REAGENT_TOTAL_VOLUME(reagents)) + var/percent = round(REAGENT_TOTAL_VOLUME(reagents) / REAGENT_MAXIMUM_VOLUME(reagents) * 100, 25) + add_overlay(mutable_appearance(icon, "[icon_state]_filling_[percent]", reagents.get_color())) + var/image/overglass = mutable_appearance(icon, "[icon_state]_over", color) + overglass.alpha = alpha * ((alpha/255) ** 3) + add_overlay(overglass) + if(istype(material) && material.reflectiveness >= MAT_VALUE_SHINY) + var/mutable_appearance/shine = mutable_appearance(icon, "[icon_state]_shine", adjust_brightness(color, 20 + material.reflectiveness)) + shine.alpha = material.reflectiveness * 3 + add_overlay(shine) + if(label_text) + add_overlay(mutable_appearance(icon, "[icon_state]_label", label_color)) . = ..() - if(!icon_state) - icon_state = "bottle-[rand(1,4)]" -/obj/item/chems/glass/bottle/on_update_icon() - overlays.Cut() - - if(reagents.total_volume && (icon_state == "bottle-1" || icon_state == "bottle-2" || icon_state == "bottle-3" || icon_state == "bottle-4")) - var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") - - var/percent = round((reagents.total_volume / volume) * 100) - switch(percent) - if(0 to 9) filling.icon_state = "[icon_state]--10" - if(10 to 24) filling.icon_state = "[icon_state]-10" - if(25 to 49) filling.icon_state = "[icon_state]-25" - if(50 to 74) filling.icon_state = "[icon_state]-50" - if(75 to 79) filling.icon_state = "[icon_state]-75" - if(80 to 90) filling.icon_state = "[icon_state]-80" - if(91 to INFINITY) filling.icon_state = "[icon_state]-100" - - filling.color = reagents.get_color() - overlays += filling - - if (!ATOM_IS_OPEN_CONTAINER(src)) - var/image/lid = image(icon, src, "lid_bottle") - overlays += lid +/obj/item/chems/glass/bottle/Initialize() + . = ..() + update_icon() +/obj/item/chems/glass/bottle/populate_reagents() + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) > 0 && autolabel && !label_text) // don't override preset labels + label_text = reagents.get_primary_reagent_name() + update_name() /obj/item/chems/glass/bottle/stabilizer - name = "stabilizer bottle" desc = "A small bottle. Contains stabilizer - used to stabilize patients." - icon_state = "bottle-4" -/obj/item/chems/glass/bottle/stabilizer/Initialize() +/obj/item/chems/glass/bottle/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/stabilizer, 60) - update_icon() /obj/item/chems/glass/bottle/bromide - name = "bromide bottle" desc = "A small bottle of bromide. Do not drink, it is poisonous." - icon_state = "bottle-3" -/obj/item/chems/glass/bottle/bromide/Initialize() +/obj/item/chems/glass/bottle/bromide/populate_reagents() + add_to_reagents(/decl/material/liquid/bromide, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/bromide, 60) - update_icon() /obj/item/chems/glass/bottle/cyanide - name = "cyanide bottle" desc = "A small bottle of cyanide. Bitter almonds?" - icon_state = "bottle-3" -/obj/item/chems/glass/bottle/cyanide/Initialize() +/obj/item/chems/glass/bottle/cyanide/populate_reagents() + add_to_reagents(/decl/material/liquid/cyanide, REAGENT_MAXIMUM_VOLUME(reagents) / 2) //volume changed to match chloral . = ..() - reagents.add_reagent(/decl/material/liquid/cyanide, 30) //volume changed to match chloral - update_icon() - /obj/item/chems/glass/bottle/sedatives - name = "sedatives bottle" desc = "A small bottle of soporific medication. Just the fumes make you sleepy." - icon_state = "bottle-3" -/obj/item/chems/glass/bottle/sedatives/Initialize() +/obj/item/chems/glass/bottle/sedatives/populate_reagents() + add_to_reagents(/decl/material/liquid/sedatives, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/sedatives, 60) - update_icon() - /obj/item/chems/glass/bottle/antitoxin - name = "antitoxins bottle" desc = "A small bottle of antitoxins. Counters poisons, and repairs damage. A wonder drug." - icon_state = "bottle-4" -/obj/item/chems/glass/bottle/antitoxin/Initialize() +/obj/item/chems/glass/bottle/antitoxin/populate_reagents() + add_to_reagents(/decl/material/liquid/antitoxins, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/antitoxins, 60) - update_icon() - /obj/item/chems/glass/bottle/mutagenics - name = "unstable mutagen bottle" desc = "A small bottle of unstable mutagen. Randomly changes the DNA structure of whoever comes in contact." - icon_state = "bottle-1" -/obj/item/chems/glass/bottle/mutagenics/Initialize() +/obj/item/chems/glass/bottle/mutagenics/populate_reagents() + add_to_reagents(/decl/material/liquid/mutagenics, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/mutagenics, 60) - update_icon() - -/obj/item/chems/glass/bottle/ammonia - name = "ammonia bottle" - desc = "A small bottle." - icon_state = "bottle-1" - -/obj/item/chems/glass/bottle/ammonia/Initialize() +/obj/item/chems/glass/bottle/ammonia/populate_reagents() + add_to_reagents(/decl/material/gas/ammonia, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/gas/ammonia, 60) - update_icon() - /obj/item/chems/glass/bottle/eznutrient - name = "\improper EZ NUtrient bottle" - desc = "A small bottle." - icon_state = "bottle-4" - -/obj/item/chems/glass/bottle/eznutrient/Initialize() + label_text = "EZ NUtrient" + autolabel = FALSE + label_color = COLOR_PALE_BTL_GREEN + lid_color = COLOR_PALE_BTL_GREEN + material = /decl/material/solid/organic/plastic + +/obj/item/chems/glass/bottle/eznutrient/populate_reagents() + add_to_reagents(/decl/material/liquid/fertilizer, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/fertilizer, 60) - update_icon() /obj/item/chems/glass/bottle/left4zed - name = "\improper Left-4-Zed bottle" - desc = "A small bottle." - icon_state = "bottle-4" - -/obj/item/chems/glass/bottle/left4zed/Initialize() + label_text = "Left-4-Zed" + autolabel = FALSE + label_color = COMMS_COLOR_SCIENCE + lid_color = COMMS_COLOR_SCIENCE + material = /decl/material/solid/organic/plastic + +/obj/item/chems/glass/bottle/left4zed/populate_reagents() + var/mutagen_amount = round(REAGENT_MAXIMUM_VOLUME(reagents) / 6) + add_to_reagents(/decl/material/liquid/fertilizer, REAGENT_MAXIMUM_VOLUME(reagents) - mutagen_amount) + add_to_reagents(/decl/material/liquid/mutagenics, mutagen_amount) . = ..() - reagents.add_reagent(/decl/material/liquid/fertilizer, 50) - reagents.add_reagent(/decl/material/liquid/mutagenics, 10) - update_icon() - /obj/item/chems/glass/bottle/robustharvest - name = "\improper Robust Harvest" - desc = "A small bottle." - icon_state = "bottle-4" - -/obj/item/chems/glass/bottle/robustharvest/Initialize() + label_text = "Robust Harvest" + autolabel = FALSE + label_color = COLOR_ASSEMBLY_GREEN + lid_color = COLOR_ASSEMBLY_GREEN + material = /decl/material/solid/organic/plastic + +/obj/item/chems/glass/bottle/robustharvest/populate_reagents() + var/amonia_amount = round(REAGENT_MAXIMUM_VOLUME(reagents) / 6) + add_to_reagents(/decl/material/liquid/fertilizer, REAGENT_MAXIMUM_VOLUME(reagents) - amonia_amount) + add_to_reagents(/decl/material/gas/ammonia, amonia_amount) . = ..() - reagents.add_reagent(/decl/material/liquid/fertilizer, 50) - reagents.add_reagent(/decl/material/gas/ammonia, 10) - update_icon() - -/obj/item/chems/glass/bottle/pacid - name = "Polytrinic Acid Bottle" - desc = "A small bottle. Contains a small amount of Polytrinic Acid." - icon_state = "bottle-4" -/obj/item/chems/glass/bottle/pacid/Initialize() +/obj/item/chems/glass/bottle/pacid/populate_reagents() + add_to_reagents(/decl/material/liquid/acid/polyacid, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/acid/polyacid, 60) - update_icon() - - /obj/item/chems/glass/bottle/adminordrazine - name = "Adminordrazine Bottle" desc = "A small bottle. Contains the liquid essence of the gods." - icon = 'icons/obj/drinks.dmi' - icon_state = "holyflask" + material = /decl/material/solid/metal/gold + lid_color = COLOR_CYAN_BLUE + label_color = COLOR_CYAN_BLUE - -/obj/item/chems/glass/bottle/adminordrazine/Initialize() +/obj/item/chems/glass/bottle/adminordrazine/populate_reagents() + add_to_reagents(/decl/material/liquid/adminordrazine, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/adminordrazine, 60) - update_icon() - /obj/item/chems/glass/bottle/capsaicin - name = "Capsaicin Bottle" desc = "A small bottle. Contains hot sauce." - icon_state = "bottle-4" -/obj/item/chems/glass/bottle/capsaicin/Initialize() +/obj/item/chems/glass/bottle/capsaicin/populate_reagents() + add_to_reagents(/decl/material/liquid/capsaicin, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/capsaicin, 60) - update_icon() - /obj/item/chems/glass/bottle/frostoil - name = "Chilly Oil Bottle" desc = "A small bottle. Contains cold sauce." - icon_state = "bottle-4" -/obj/item/chems/glass/bottle/frostoil/Initialize() +/obj/item/chems/glass/bottle/frostoil/populate_reagents() + add_to_reagents(/decl/material/liquid/frostoil, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/frostoil, 60) - update_icon() diff --git a/code/modules/reagents/reagent_containers/glass/bottle/robot.dm b/code/modules/reagents/reagent_containers/glass/bottle/robot.dm index 1a1877be543e..501c6017362e 100644 --- a/code/modules/reagents/reagent_containers/glass/bottle/robot.dm +++ b/code/modules/reagents/reagent_containers/glass/bottle/robot.dm @@ -1,31 +1,30 @@ /obj/item/chems/glass/bottle/robot + icon = 'icons/obj/items/chem/bottle.dmi' + icon_state = "bottle-4" amount_per_transfer_from_this = 10 possible_transfer_amounts = @"[5,10,15,25,30,50,100]" atom_flags = ATOM_FLAG_OPEN_CONTAINER - volume = 60 - var/reagent = "" + chem_volume = 60 + +/obj/item/chems/glass/bottle/robot/Initialize() + . = ..() + update_icon() /obj/item/chems/glass/bottle/robot/stabilizer name = "internal stabilizer bottle" desc = "A small bottle. Contains stabilizer - used to stabilize patients." - icon = 'icons/obj/items/chem/bottle.dmi' - icon_state = "bottle-4" - reagent = /decl/material/liquid/stabilizer -/obj/item/chems/glass/bottle/robot/stabilizer/Initialize() +/obj/item/chems/glass/bottle/robot/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/stabilizer, 60) - update_icon() /obj/item/chems/glass/bottle/robot/antitoxin name = "internal anti-toxin bottle" - desc = "A small bottle of Anti-toxins. Counters poisons, and repairs damage, a wonder drug." + desc = "A small bottle of broad-spectrum antitoxins, used to neutralize poisons before they can do significant harm." icon = 'icons/obj/items/chem/bottle.dmi' icon_state = "bottle-4" - reagent = /decl/material/liquid/antitoxins -/obj/item/chems/glass/bottle/robot/antitoxin/Initialize() +/obj/item/chems/glass/bottle/robot/antitoxin/populate_reagents() + add_to_reagents(/decl/material/liquid/antitoxins, REAGENT_MAXIMUM_VOLUME(reagents)) . = ..() - reagents.add_reagent(/decl/material/liquid/antitoxins, 60) - update_icon() \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index a4d6925368a0..07d45320e232 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -2,22 +2,27 @@ /// HYPOSPRAY //////////////////////////////////////////////////////////////////////////////// -/obj/item/chems/hypospray //obsolete, use hypospray/vial for the actual hypospray item +/obj/item/chems/hypospray // abstract shared type, do not use directly name = "hypospray" desc = "A sterile, air-needle autoinjector for rapid administration of drugs to patients." - icon = 'icons/obj/syringe.dmi' - item_state = "hypo" - icon_state = "hypo" - origin_tech = "{'materials':4,'biotech':5}" + icon = 'icons/obj/hypospray.dmi' + icon_state = ICON_STATE_WORLD + abstract_type = /obj/item/chems/hypospray + origin_tech = @'{"materials":4,"biotech":5}' amount_per_transfer_from_this = 5 - unacidable = 1 - volume = 30 + chem_volume = 30 possible_transfer_amounts = null atom_flags = ATOM_FLAG_OPEN_CONTAINER - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE + ) // autoinjectors takes less time than a normal syringe (overriden for hypospray). - // This delay is only applied when injecting concious mobs, and is not applied for self-injection + // This delay is only applied when injecting conscious mobs, and is not applied for self-injection // The 1.9 factor scales it so it takes the following number of seconds: // NONE 1.47 // BASIC 1.00 @@ -27,183 +32,263 @@ var/time = (1 SECONDS) / 1.9 var/single_use = TRUE // autoinjectors are not refillable (overriden for hypospray) -/obj/item/chems/hypospray/attack(mob/living/M, mob/user) - if(!reagents.total_volume) - to_chat(user, "[src] is empty.") - return - if (!istype(M)) - return +/obj/item/chems/hypospray/on_update_icon() + icon_state = get_world_inventory_state() + . = ..() - var/allow = M.can_inject(user, check_zone(user.zone_sel.selecting)) +/obj/item/chems/hypospray/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("\The [src] is empty.")) + return TRUE + + var/allow = target.can_inject(user, check_zone(user.get_target_zone(), target)) if(!allow) - return + return TRUE if (allow == INJECTION_PORT) - if(M != user) - user.visible_message(SPAN_WARNING("\The [user] begins hunting for an injection port on \the [M]'s suit!")) + if(target != user) + user.visible_message(SPAN_WARNING("\The [user] begins hunting for an injection port on \the [target]'s suit!")) else to_chat(user, SPAN_NOTICE("You begin hunting for an injection port on your suit.")) - if(!user.do_skilled(INJECTION_PORT_DELAY, SKILL_MEDICAL, M)) - return + if(!user.do_skilled(INJECTION_PORT_DELAY, SKILL_MEDICAL, target)) + return TRUE user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(M) + user.do_attack_animation(target) - if(user != M && !M.incapacitated() && time) // you're injecting someone else who is concious, so apply the device's intrisic delay - to_chat(user, SPAN_WARNING("\The [user] is trying to inject \the [M] with \the [name].")) - if(!user.do_skilled(time, SKILL_MEDICAL, M)) - return + if(user != target && !target.incapacitated() && time) // you're injecting someone else who is conscious, so apply the device's intrisic delay + to_chat(user, SPAN_WARNING("\The [user] is trying to inject \the [target] with \the [name].")) + if(!user.do_skilled(time, SKILL_MEDICAL, target)) + return TRUE - if(single_use && reagents.total_volume <= 0) // currently only applies to autoinjectors + if(single_use && REAGENT_TOTAL_VOLUME(reagents) <= 0) // currently only applies to autoinjectors atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER // Prevents autoinjectors to be refilled. - to_chat(user, "You inject [M] with [src].") - to_chat(M, "You feel a tiny prick!") + to_chat(user, SPAN_NOTICE("You inject [target] with [src].")) + to_chat(target, SPAN_NOTICE("You feel a tiny prick!")) playsound(src, 'sound/effects/hypospray.ogg',25) - user.visible_message("[user] injects [M] with [src].") + user.visible_message(SPAN_WARNING("[user] injects [target] with [src].")) - if(M.reagents) - var/contained = REAGENT_LIST(src) - var/trans = reagents.trans_to_mob(M, amount_per_transfer_from_this, CHEM_INJECT) - admin_inject_log(user, M, src, contained, trans) - to_chat(user, "[trans] units injected. [reagents.total_volume] units remaining in \the [src].") + if(target.reagents) + var/contained = REAGENT_LIST(reagents) + var/trans = reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INJECT) + admin_inject_log(user, target, src, contained, trans) + to_chat(user, SPAN_NOTICE("[trans] unit\s injected. [REAGENT_TOTAL_VOLUME(reagents)] unit\s remaining in \the [src].")) - return + return TRUE +//////////////////////////////////////////////////////////////////////////////// +/// VIAL HYPOSPRAY +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/vial name = "hypospray" - item_state = "autoinjector" - desc = "A sterile, air-needle autoinjector for rapid administration of drugs to patients. Uses a replacable 30u vial." + desc = "A sterile, air-needle autoinjector for rapid administration of drugs to patients. Uses a replaceable 30u vial." possible_transfer_amounts = @"[1,2,5,10,15,20,30]" amount_per_transfer_from_this = 5 - volume = 0 + chem_volume = 0 time = 0 // hyposprays are instant for conscious people single_use = FALSE material = /decl/material/solid/metal/steel - matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE - ) var/obj/item/chems/glass/beaker/vial/loaded_vial /obj/item/chems/hypospray/vial/Initialize() . = ..() - loaded_vial = new /obj/item/chems/glass/beaker/vial(src) - volume = loaded_vial.volume - reagents.maximum_volume = loaded_vial.reagents.maximum_volume + create_contents() -/obj/item/chems/hypospray/vial/proc/remove_vial(mob/user, swap_mode) - if(!loaded_vial) +/obj/item/chems/hypospray/vial/proc/create_contents() + insert_vial(new /obj/item/chems/glass/beaker/vial(src)) + +/obj/item/chems/hypospray/vial/proc/insert_vial(var/obj/item/chems/glass/beaker/vial/V, var/mob/user) + if(user && !user.try_unequip(V, src)) return - reagents.trans_to_holder(loaded_vial.reagents,volume) - reagents.maximum_volume = 0 + + var/usermessage = "" + if(loaded_vial) + remove_vial(user, "swap", FALSE) + usermessage = "You load \the [V] into \the [src] as you remove the old one." + else + usermessage = "You load \the [V] into \the [src]." + + if(ATOM_IS_OPEN_CONTAINER(V)) + V.atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + V.update_icon() + + loaded_vial = V + create_or_update_reagents(REAGENT_MAXIMUM_VOLUME(loaded_vial.reagents), override_volume = TRUE) + loaded_vial.reagents.trans_to_holder(reagents, REAGENT_MAXIMUM_VOLUME(reagents)) + + if(user) + user.visible_message(SPAN_NOTICE("[user] has loaded [V] into \the [src]."), SPAN_NOTICE("[usermessage]")) + + update_icon() + playsound(loc, 'sound/weapons/empty.ogg', 50, TRUE) + return TRUE + +/obj/item/chems/hypospray/vial/proc/remove_vial(var/mob/user, var/swap_mode, var/should_update_icon = TRUE) + if(!loaded_vial || !istype(reagents)) + return + reagents.trans_to_holder(loaded_vial.reagents, REAGENT_MAXIMUM_VOLUME(reagents)) + REAGENT_SET_MAX_VOL(reagents, 0) loaded_vial.update_icon() - user.put_in_hands(loaded_vial) + if(user) + user.put_in_hands(loaded_vial) loaded_vial = null - if (swap_mode != "swap") // if swapping vials, we will print a different message in another proc - to_chat(user, "You remove the vial from the [src].") + if(user) + if (swap_mode != "swap") // if swapping vials, we will print a different message in another proc + to_chat(user, "You remove the vial from \the [src].") + playsound(loc, 'sound/weapons/flipblade.ogg', 50, TRUE) + if(should_update_icon) + update_icon() + return TRUE /obj/item/chems/hypospray/vial/attack_hand(mob/user) - if(user.get_inactive_hand() == src) - if(!loaded_vial) - to_chat(user, "There is no vial loaded in the [src].") - return + if(!user.is_holding_offhand(src) || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(!loaded_vial) + to_chat(user, SPAN_NOTICE("There is no vial loaded in \the [src].")) + else remove_vial(user) - update_icon() - playsound(loc, 'sound/weapons/flipblade.ogg', 50, 1) - return - return ..() + return TRUE -/obj/item/chems/hypospray/vial/attackby(obj/item/W, mob/user) - var/usermessage = "" - if(istype(W, /obj/item/chems/glass/beaker/vial)) - if(!do_after(user,10) || !(W in user)) - return 0 - if(!user.unEquip(W, src)) - return - if(loaded_vial) - remove_vial(user, "swap") - usermessage = "You load \the [W] into \the [src] as you remove the old one." - else - usermessage = "You load \the [W] into \the [src]." - if(ATOM_IS_OPEN_CONTAINER(W)) - W.atom_flags ^= ATOM_FLAG_OPEN_CONTAINER - W.update_icon() - loaded_vial = W - reagents.maximum_volume = loaded_vial.reagents.maximum_volume - loaded_vial.reagents.trans_to_holder(reagents,volume) - user.visible_message("[user] has loaded [W] into \the [src].","[usermessage]") - update_icon() - playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) - return - ..() +/obj/item/chems/hypospray/vial/attackby(obj/item/used_item, mob/user) + if(!istype(used_item, /obj/item/chems/glass/beaker/vial)) + return ..() + if(!do_after(user, 1 SECOND, src)) + return TRUE + insert_vial(used_item, user) + return TRUE /obj/item/chems/hypospray/vial/afterattack(obj/target, mob/user, proximity) // hyposprays can be dumped into, why not out? uses standard_pour_into helper checks. if(!proximity) return standard_pour_into(user, target) +//////////////////////////////////////////////////////////////////////////////// +/// AUTOINJECTOR +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/autoinjector name = "autoinjector" desc = "A rapid and safe way to administer small amounts of drugs by untrained or trained personnel." - icon_state = "injector" - item_state = "autoinjector" + icon = 'icons/obj/autoinjector.dmi' amount_per_transfer_from_this = 5 - volume = 5 - origin_tech = "{'materials':2,'biotech':2}" - slot_flags = SLOT_BELT | SLOT_EARS - w_class = ITEM_SIZE_TINY - var/list/starts_with = list(/decl/material/liquid/adrenaline = 5) - var/band_color = COLOR_CYAN + chem_volume = 5 + origin_tech = @'{"materials":2,"biotech":2}' + slot_flags = SLOT_LOWER_BODY | SLOT_EARS + w_class = ITEM_SIZE_SMALL + detail_state = "_band" + detail_color = COLOR_CYAN + abstract_type = /obj/item/chems/hypospray/autoinjector + var/autolabel = TRUE // if set, will add label with the name of the first initial reagent /obj/item/chems/hypospray/autoinjector/Initialize() . = ..() - for(var/T in starts_with) - reagents.add_reagent(T, starts_with[T]) + if(label_text) + update_name() update_icon() -/obj/item/chems/hypospray/autoinjector/attack(mob/M as mob, mob/user as mob) - ..() - update_icon() +/obj/item/chems/hypospray/autoinjector/used/Initialize() + . = ..() + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + +/obj/item/chems/hypospray/autoinjector/populate_reagents() + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) > 0 && autolabel && !label_text) // don't override preset labels + label_text = "[reagents.get_primary_reagent_name()], [REAGENT_TOTAL_VOLUME(reagents)]u" + +/obj/item/chems/hypospray/autoinjector/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + . = ..() + if(.) + update_icon() /obj/item/chems/hypospray/autoinjector/on_update_icon() - overlays.Cut() - if(reagents.total_volume > 0) - icon_state = "[initial(icon_state)]1" - else - icon_state = "[initial(icon_state)]0" - overlays+= overlay_image(icon,"injector_band",band_color,RESET_COLOR) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) <= 0) + icon_state = "[icon_state]_used" -/obj/item/chems/hypospray/autoinjector/examine(mob/user) +/obj/item/chems/hypospray/autoinjector/get_examine_strings(mob/user, distance, infix, suffix) . = ..(user) - if(reagents?.total_volume) - to_chat(user, "It is currently loaded.") + if(REAGENT_TOTAL_VOLUME(reagents)) + . += SPAN_NOTICE("It is currently loaded.") else - to_chat(user, "It is spent.") + . += SPAN_NOTICE("It is spent.") +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Stabilizer +//////////////////////////////////////////////////////////////////////////////// +/obj/item/chems/hypospray/autoinjector/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Adrenaline +//////////////////////////////////////////////////////////////////////////////// +/obj/item/chems/hypospray/autoinjector/adrenaline/populate_reagents() + add_to_reagents(/decl/material/liquid/adrenaline, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Detox +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/autoinjector/detox - name = "autoinjector (antitox)" - band_color = COLOR_GREEN - starts_with = list(/decl/material/liquid/antitoxins = 5) + detail_color = COLOR_GREEN +/obj/item/chems/hypospray/autoinjector/detox/populate_reagents() + add_to_reagents(/decl/material/liquid/antitoxins, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Pain +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/autoinjector/pain - name = "autoinjector (painkiller)" - band_color = COLOR_PURPLE - starts_with = list(/decl/material/liquid/painkillers = 5) + detail_color = COLOR_PURPLE +/obj/item/chems/hypospray/autoinjector/pain/populate_reagents() + add_to_reagents(/decl/material/liquid/painkillers, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() + +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Antirad +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/autoinjector/antirad - name = "autoinjector (anti-rad)" - band_color = COLOR_AMBER - starts_with = list(/decl/material/liquid/antirads = 5) + detail_color = COLOR_AMBER + +/obj/item/chems/hypospray/autoinjector/antirad/populate_reagents() + add_to_reagents(/decl/material/liquid/antirads, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Hallucinogenics +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/autoinjector/hallucinogenics - name = "autoinjector" - band_color = COLOR_DARK_GRAY - starts_with = list(/decl/material/liquid/hallucinogenics = 5) + detail_color = COLOR_DARK_GRAY + +/obj/item/chems/hypospray/autoinjector/hallucinogenics/populate_reagents() + add_to_reagents(/decl/material/liquid/hallucinogenics, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Clotting agent +//////////////////////////////////////////////////////////////////////////////// + +/obj/item/chems/hypospray/autoinjector/clotting + name = "autoinjector (clotting agent)" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This variant excels at treating bleeding wounds and internal bleeding." + +/obj/item/chems/hypospray/autoinjector/clotting/populate_reagents() + . = ..() + var/amt = round(REAGENT_MAXIMUM_VOLUME(reagents)*0.5) + add_to_reagents(/decl/material/liquid/stabilizer, amt) + add_to_reagents(/decl/material/liquid/clotting_agent, (REAGENT_MAXIMUM_VOLUME(reagents) - amt)) + +//////////////////////////////////////////////////////////////////////////////// +// Autoinjector - Empty +//////////////////////////////////////////////////////////////////////////////// /obj/item/chems/hypospray/autoinjector/empty name = "autoinjector" - band_color = COLOR_WHITE - starts_with = list() - material = /decl/material/solid/plastic - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) \ No newline at end of file + detail_color = COLOR_WHITE + +/obj/item/chems/hypospray/autoinjector/empty/populate_reagents() + SHOULD_CALL_PARENT(FALSE) + return diff --git a/code/modules/reagents/reagent_containers/inhaler.dm b/code/modules/reagents/reagent_containers/inhaler.dm new file mode 100644 index 000000000000..ef51bccc8e99 --- /dev/null +++ b/code/modules/reagents/reagent_containers/inhaler.dm @@ -0,0 +1,118 @@ +//Inhalers +//Just like hypopsray code +/obj/item/chems/inhaler + name = "autoinhaler" + desc = "A rapid and safe way to administer small amounts of drugs into the lungs by untrained or trained personnel." + icon = 'icons/obj/inhaler.dmi' + icon_state = ICON_STATE_WORLD + center_of_mass = @'{"x":16,"y":11}' + amount_per_transfer_from_this = 5 + chem_volume = 5 + w_class = ITEM_SIZE_SMALL + possible_transfer_amounts = null + atom_flags = ATOM_FLAG_OPEN_CONTAINER + slot_flags = SLOT_LOWER_BODY + origin_tech = @'{"materials":2,"biotech":2}' + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_TRACE + ) + detail_color = COLOR_GREEN + detail_state = "_band" + + var/used = FALSE + var/list/starts_with = null /// A lazylist of starting reagents. Example: list(/decl/material/liquid/adrenaline = 5) + +/obj/item/chems/inhaler/Initialize() + . = ..() + for(var/T in starts_with) + add_to_reagents(T, starts_with[T]) + if(ATOM_IS_OPEN_CONTAINER(src) && REAGENT_TOTAL_VOLUME(reagents) > 0) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + update_icon() + +/obj/item/chems/inhaler/on_update_icon() + icon_state = get_world_inventory_state() + . = ..() + if(ATOM_IS_OPEN_CONTAINER(src)) + add_overlay("[icon_state]_loaded") + if(REAGENT_TOTAL_VOLUME(reagents) > 0) + add_overlay("[icon_state]_reagents") + +/obj/item/chems/inhaler/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if (!ishuman(target)) + return ..() + + if(ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_NOTICE("You must secure the reagents inside \the [src] before using it!")) + return FALSE + + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_WARNING("\The [src] is empty.")) + return TRUE + + if(!user.can_force_feed(target, src)) + return TRUE + + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(target) + + if(user == target) + user.visible_message( + SPAN_NOTICE("\The [user] inhales from \the [src]."), + SPAN_NOTICE("You stick \the [src] in your mouth and press the injection button.") + ) + else + user.visible_message( + SPAN_WARNING("\The [user] attempts to administer \the [src] to \the [target]..."), + SPAN_NOTICE("You attempt to administer \the [src] to \the [target]...") + ) + if (!do_after(user, 1 SECONDS, target)) + to_chat(user, SPAN_NOTICE("You and the target need to be standing still in order to inject \the [src].")) + return TRUE + + user.visible_message( + SPAN_NOTICE("\The [user] administers \the [src] to \the [target]."), + SPAN_NOTICE("You stick \the [src] in \the [target]'s mouth and press the injection button.") + ) + + var/contained = REAGENT_LIST(reagents) + var/trans = reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INHALE) + if(trans) + admin_inject_log(user, target, src, contained, trans) + playsound(src.loc, 'sound/effects/hypospray.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("[trans] units administered. [REAGENT_TOTAL_VOLUME(reagents)] units remaining in \the [src].")) + used = TRUE + + update_icon() + return TRUE + +/obj/item/chems/inhaler/attack_self(mob/user) + if(ATOM_IS_OPEN_CONTAINER(src)) + if(REAGENT_TOTAL_VOLUME(reagents) > 0) + to_chat(user, SPAN_NOTICE("With a quick twist of \the [src]'s lid, you secure the reagents inside.")) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + update_icon() + else + to_chat(user, SPAN_NOTICE("You can't secure \the [src] without putting reagents in!")) + else + to_chat(user, SPAN_NOTICE("The reagents inside \the [src] are already secured.")) + return TRUE + +/obj/item/chems/inhaler/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item) && !ATOM_IS_OPEN_CONTAINER(src)) + to_chat(user, SPAN_NOTICE("Using \the [used_item], you unsecure the inhaler's lid.")) // it locks shut after being secured + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + update_icon() + return TRUE + . = ..() + +/obj/item/chems/inhaler/get_examine_strings(mob/user, distance, infix, suffix) + . = ..(user) + if(distance <= 1) + if(REAGENT_TOTAL_VOLUME(reagents) > 0) + . += SPAN_NOTICE("It is currently loaded.") + else + . += SPAN_WARNING("It is spent.") diff --git a/code/modules/reagents/reagent_containers/mortar.dm b/code/modules/reagents/reagent_containers/mortar.dm new file mode 100644 index 000000000000..e1c415a1ecdd --- /dev/null +++ b/code/modules/reagents/reagent_containers/mortar.dm @@ -0,0 +1,67 @@ +/obj/item/chems/glass/mortar + name = "mortar" + desc = "A hard, sturdy bowl used to hold organic matter for crushing." + icon = 'icons/obj/items/chem/mortar.dmi' + icon_state = ICON_STATE_WORLD + chem_volume = 40 + material = /decl/material/solid/stone/basalt + color = /decl/material/solid/stone/basalt::color + material_alteration = MAT_FLAG_ALTERATION_ALL + storage = /datum/storage/hopper/mortar + var/grinding = FALSE + +// todo: generalize to use TOOL_PESTLE +/obj/item/chems/glass/mortar/attackby(obj/item/used_item, mob/living/user) + if((. = ..())) + return + return try_grind(used_item, user) + +/obj/item/chems/glass/mortar/can_lid() + return FALSE + +/obj/item/chems/glass/mortar/proc/try_grind(obj/item/used_item, mob/living/user) + if(!istype(used_item)) + return FALSE + if(!CanPhysicallyInteract(user) || !user.check_dexterity(DEXTERITY_HOLD_ITEM)) + return TRUE + if(grinding) + to_chat(user, SPAN_WARNING("Something is already being crushed in \the [src].")) + return TRUE + var/list/contained_atoms = get_stored_inventory() + var/obj/item/crushing_item = LAZYACCESS(contained_atoms, 1) + var/decl/material/attacking_material = used_item.get_material() + var/decl/material/crushing_material = crushing_item?.get_material() + var/skill_factor = CLAMP01(1 + 0.3*(user.get_skill_value(SKILL_CHEMISTRY) - SKILL_EXPERT)/(SKILL_EXPERT - SKILL_MIN)) + if(used_item.expend_attack_force(user) <= 0 || !attacking_material || !crushing_material) + return TRUE + if(attacking_material.hardness <= crushing_material.hardness) + to_chat(user, SPAN_NOTICE("\The [used_item] is not hard enough to crush \the [crushing_item].")) + return TRUE + if(REAGENTS_FREE_SPACE(reagents) < REAGENT_TOTAL_VOLUME(crushing_item.reagents)) + to_chat(user, SPAN_WARNING("\The [src] is too full to grind \the [crushing_item], it'd spill everywhere!")) + return TRUE + if(REAGENT_TOTAL_VOLUME(crushing_item.reagents)) // if it has no reagents, skip all the fluff and destroy it instantly + var/stamina_to_consume = max(REAGENT_TOTAL_VOLUME(crushing_item.reagents) * (1 + user.get_stamina_skill_mod()/2), 5) + if(stamina_to_consume > 100) // TODO: add user.get_max_stamina()? + to_chat(user, SPAN_WARNING("\The [crushing_item] is too large for you to grind in \the [src]!")) + return TRUE + if(user.get_stamina() < stamina_to_consume) + to_chat(user, SPAN_WARNING("You are too tired to crush \the [crushing_item], take a break!")) + return TRUE + to_chat(user, SPAN_NOTICE("You start grinding \the [crushing_item] with \the [used_item].")) + grinding = TRUE + if(!do_after(user, stamina_to_consume SECONDS)) + to_chat(user, SPAN_NOTICE("You stop grinding \the [crushing_item].")) + grinding = FALSE + return TRUE + grinding = FALSE + if(QDELETED(crushing_item)) + return TRUE // already been ground! + user.adjust_stamina(-stamina_to_consume) + crushing_item.reagents.trans_to(src, REAGENT_TOTAL_VOLUME(crushing_item.reagents), skill_factor) + to_chat(user, SPAN_NOTICE("You finish grinding \the [crushing_item] with \the [used_item].")) + QDEL_NULL(crushing_item) + // If there's more to crush, try looping + if(length(get_stored_inventory()) > 0) + try_grind(used_item, user) + return TRUE \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/packets.dm b/code/modules/reagents/reagent_containers/packets.dm new file mode 100644 index 000000000000..c8f453ddf521 --- /dev/null +++ b/code/modules/reagents/reagent_containers/packets.dm @@ -0,0 +1,192 @@ +/obj/item/chems/packet + name = "packet" + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/food/condiments/packets/packet_small.dmi' + w_class = ITEM_SIZE_TINY + possible_transfer_amounts = @"[1,2,5,10]" + amount_per_transfer_from_this = 1 + chem_volume = 10 + +/obj/item/chems/packet/attack_self(mob/user) + if(!ATOM_IS_OPEN_CONTAINER(src)) + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + to_chat(user, SPAN_NOTICE("You tear \the [src] open.")) + return TRUE + return ..() + +/obj/item/chems/packet/afterattack(obj/target, mob/user, proximity) + if(!proximity) + return ..() + if(standard_dispenser_refill(user, target)) + return TRUE + if(standard_pour_into(user, target)) + return TRUE + return ..() + +/obj/item/chems/packet/salt + name = "salt packet" + desc = "Contains 5u of table salt." + icon = 'icons/obj/food/condiments/packets/packet_white.dmi' + +/obj/item/chems/packet/salt/populate_reagents() + add_to_reagents(/decl/material/solid/sodiumchloride, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/pepper + name = "pepper packet" + desc = "Contains 5u of black pepper." + icon = 'icons/obj/food/condiments/packets/packet_black.dmi' + +/obj/item/chems/packet/pepper/populate_reagents() + add_to_reagents(/decl/material/solid/blackpepper, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/sugar + name = "sugar packet" + desc = "Contains 5u of refined sugar." + icon = 'icons/obj/food/condiments/packets/packet_white.dmi' + +/obj/item/chems/packet/sugar/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/sugar, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/jelly + name = "jelly packet" + desc = "Contains 10u of cherry jelly. Best used for spreading on crackers." + icon = 'icons/obj/food/condiments/packets/packet_medium.dmi' + +/obj/item/chems/packet/jelly/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/cherryjelly, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/honey + name = "honey packet" + desc = "Contains 10u of honey." + icon = 'icons/obj/food/condiments/packets/packet_medium.dmi' + +/obj/item/chems/packet/honey/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/honey, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/honey_fake + name = "'honey' packet" + desc = "Contains 10u of allergen-free non-GMO 'honey'." + icon = 'icons/obj/food/condiments/packets/packet_medium.dmi' + +/obj/item/chems/packet/honey_fake/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/sugar, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/capsaicin + name = "hot sauce packet" + desc = "Contains 5u of hot sauce. Enjoy in moderation." + icon = 'icons/obj/food/condiments/packets/packet_red.dmi' + +/obj/item/chems/packet/capsaicin/populate_reagents() + add_to_reagents(/decl/material/liquid/capsaicin, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/ketchup + name = "ketchup packet" + desc = "Contains 5u of ketchup." + icon = 'icons/obj/food/condiments/packets/packet_red.dmi' + +/obj/item/chems/packet/ketchup/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/ketchup, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/mayo + name = "mayonnaise packet" + desc = "Contains 5u of mayonnaise." + icon = 'icons/obj/food/condiments/packets/packet_white.dmi' + +/obj/item/chems/packet/mayo/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/mayo, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/soy + name = "soy sauce packet" + desc = "Contains 5u of soy sauce." + icon = 'icons/obj/food/condiments/packets/packet_black.dmi' + +/obj/item/chems/packet/soy/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/soysauce, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/coffee + name = "instant coffee powder packet" + desc = "Contains 5u of instant coffee powder. Mix with 25u of water." + +/obj/item/chems/packet/coffee/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/coffee/instant, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/tea + name = "instant tea powder packet" + desc = "Contains 5u of instant black tea powder. Mix with 25u of water." + +/obj/item/chems/packet/tea/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/tea/instant, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/cocoa + name = "cocoa powder packet" + desc = "Contains 5u of cocoa powder. Mix with 25u of water and heat." + +/obj/item/chems/packet/cocoa/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/coco, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/grape + name = "grape juice powder packet" + desc = "Contains 5u of powdered grape juice. Mix with 15u of water." + +/obj/item/chems/packet/grape/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/instantjuice/grape, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/orange + name = "orange juice powder packet" + desc = "Contains 5u of powdered orange juice. Mix with 15u of water." + +/obj/item/chems/packet/orange/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/instantjuice/orange, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/watermelon + name = "watermelon juice powder packet" + desc = "Contains 5u of powdered watermelon juice. Mix with 15u of water." + +/obj/item/chems/packet/watermelon/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/instantjuice/watermelon, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/apple + name = "apple juice powder packet" + desc = "Contains 5u of powdered apple juice. Mix with 15u of water." + +/obj/item/chems/packet/apple/populate_reagents() + add_to_reagents(/decl/material/liquid/nutriment/instantjuice/apple, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/protein + name = "protein powder packet" + desc = "Contains 10u of powdered protein. Mix with 20u of water." + icon = 'icons/obj/food/condiments/packets/packet_medium.dmi' + +/obj/item/chems/packet/protein/populate_reagents() + add_to_reagents(/decl/material/solid/organic/meat, REAGENT_MAXIMUM_VOLUME(reagents)/2) + +/obj/item/chems/packet/crayon + name = "crayon powder packet" + desc = "Contains 10u of powdered crayon. Mix with 30u of water." + +/obj/item/chems/packet/crayon/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/red/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/red, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/orange/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/orange, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/yellow/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/yellow, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/green/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/green, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/blue/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/blue, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/purple/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/purple, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/grey/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/grey, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/packet/crayon/brown/populate_reagents() + add_to_reagents(/decl/material/liquid/pigment/brown, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 40379b85bc64..74b6bdb129a0 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -3,6 +3,7 @@ //////////////////////////////////////////////////////////////////////////////// /obj/item/chems/pill name = "pill" + base_name = "pill" desc = "A pill." icon = 'icons/obj/items/chem/pill.dmi' icon_state = null @@ -11,309 +12,289 @@ possible_transfer_amounts = null w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - volume = 30 + chem_volume = 30 + material = /decl/material/solid/organic/plantmatter + var/autolabel = TRUE // if set, will add label with the name of the first initial reagent + var/static/list/colorizable_icon_states = list("pill1", "pill2", "pill3", "pill4", "pill5") // if using an icon state from here, color will be derived from reagents + +// Pill subtype that does not use a reagent name. +/obj/item/chems/pill/dispensed + autolabel = FALSE +/obj/item/chems/pill/dispensed/update_name() + return +/obj/item/chems/pill/dispensed/update_container_desc() + return /obj/item/chems/pill/Initialize() . = ..() if(!icon_state) - icon_state = "pill[rand(1, 5)]" //preset pills only use colour changing or unique icons - -/obj/item/chems/pill/attack_self(mob/user) - attack(user, user) + icon_state = pick(colorizable_icon_states) //preset pills only use colour changing or unique icons + update_icon() + if(label_text) + update_name() -/obj/item/chems/pill/dragged_onto(var/mob/user) - attack(user, user) - -/obj/item/chems/pill/attack(mob/M, mob/user, def_zone) - //TODO: replace with standard_feed_mob() call. - if(M == user) - if(!M.can_eat(src)) - return - M.visible_message(SPAN_NOTICE("[M] swallows a pill."), SPAN_NOTICE("You swallow \the [src]."), null, 2) - if(reagents.total_volume) - reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) - qdel(src) - return 1 +/obj/item/chems/pill/populate_reagents() + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) > 0 && autolabel && !label_text) // don't override preset labels + label_text = "[reagents.get_primary_reagent_name()], [REAGENT_TOTAL_VOLUME(reagents)]u" - else if(istype(M, /mob/living/carbon/human)) - if(!M.can_force_feed(user, src)) - return +/obj/item/chems/pill/on_update_icon() + . = ..() + if(icon_state in colorizable_icon_states) + color = reagents?.get_color() + alpha = 255 // above probably reset our alpha + else + color = null - user.visible_message(SPAN_WARNING("[user] attempts to force [M] to swallow \the [src].")) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!do_mob(user, M)) - return - user.visible_message(SPAN_WARNING("[user] forces [M] to swallow \the [src].")) - var/contained = REAGENT_LIST(src) - admin_attack_log(user, M, "Fed the victim with [name] (Reagents: [contained])", "Was fed [src] (Reagents: [contained])", "used [src] (Reagents: [contained]) to feed") - if(reagents.total_volume) - reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) - qdel(src) - return 1 +/obj/item/chems/pill/attack_self(mob/user) + return use_on_mob(user, user) - return 0 +/obj/item/chems/pill/dragged_onto(var/mob/user) + return use_on_mob(user, user) /obj/item/chems/pill/afterattack(obj/target, mob/user, proximity) - if(!proximity) return - - if(ATOM_IS_OPEN_CONTAINER(target) && target.reagents) - if(!target.reagents.total_volume) - to_chat(user, "[target] is empty. Can't dissolve \the [src].") + if(proximity && ATOM_IS_OPEN_CONTAINER(target) && target.reagents) + if(!REAGENT_TOTAL_VOLUME(target.reagents)) + to_chat(user, SPAN_WARNING("\The [target] is empty. You can't dissolve \the [src] in it.")) return - to_chat(user, "You dissolve \the [src] in [target].") - - admin_attacker_log(user, "spiked \a [target] with a pill. Reagents: [REAGENT_LIST(src)]") - reagents.trans_to(target, reagents.total_volume) - for(var/mob/O in viewers(2, user)) - O.show_message("[user] puts something in \the [target].", 1) + to_chat(user, SPAN_NOTICE("You dissolve \the [src] in \the [target].")) + user.visible_message(SPAN_NOTICE("\The [user] puts something in \the [target]."), range = 2) + admin_attacker_log(user, "spiked \a [target] with a pill. Reagents: [REAGENT_LIST(reagents)]") + reagents.trans_to(target, REAGENT_TOTAL_VOLUME(reagents)) qdel(src) - return + return + return ..() //////////////////////////////////////////////////////////////////////////////// /// Pills. END //////////////////////////////////////////////////////////////////////////////// //We lied - it's pills all the way down -/obj/item/chems/pill/antitox - name = "antitoxins (25u)" - desc = "Neutralizes many common toxins." - icon_state = "pill1" -/obj/item/chems/pill/antitox/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/antitoxins, 25) - color = reagents.get_color() - /obj/item/chems/pill/bromide - name = "bromide pill" desc = "Highly toxic." icon_state = "pill4" - volume = 50 -/obj/item/chems/pill/bromide/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/bromide, 50) - color = reagents.get_color() + chem_volume = 50 +/obj/item/chems/pill/bromide/populate_reagents() + add_to_reagents(/decl/material/liquid/bromide, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() /obj/item/chems/pill/cyanide name = "strange pill" desc = "It's marked 'KCN'. Smells vaguely of almonds." icon_state = "pillC" - volume = 50 -/obj/item/chems/pill/cyanide/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/cyanide, 50) + chem_volume = 50 + autolabel = FALSE +/obj/item/chems/pill/cyanide/populate_reagents() + add_to_reagents(/decl/material/liquid/cyanide, REAGENT_MAXIMUM_VOLUME(reagents)) + . = ..() /obj/item/chems/pill/adminordrazine name = "Adminordrazine pill" desc = "It's magic. We don't have to explain it." icon_state = "pillA" + autolabel = FALSE -/obj/item/chems/pill/adminordrazine/Initialize() +/obj/item/chems/pill/adminordrazine/populate_reagents() + add_to_reagents(/decl/material/liquid/adminordrazine, 1) . = ..() - reagents.add_reagent(/decl/material/liquid/adminordrazine, 1) /obj/item/chems/pill/stox - name = "sedatives (15u)" desc = "Commonly used to treat insomnia." icon_state = "pill3" -/obj/item/chems/pill/stox/Initialize() + +/obj/item/chems/pill/stox/populate_reagents() + add_to_reagents(/decl/material/liquid/sedatives, 15) . = ..() - reagents.add_reagent(/decl/material/liquid/sedatives, 15) - color = reagents.get_color() /obj/item/chems/pill/burn_meds - name = "synthskin (15u)" desc = "Used to treat burns." icon_state = "pill2" -/obj/item/chems/pill/burn_meds/Initialize() + +/obj/item/chems/pill/burn_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/burn_meds, 15) . = ..() - reagents.add_reagent(/decl/material/liquid/burn_meds, 15) - color = reagents.get_color() /obj/item/chems/pill/painkillers - name = "painkillers (15u)" desc = "A simple painkiller." icon_state = "pill3" -/obj/item/chems/pill/painkillers/Initialize() + +/obj/item/chems/pill/painkillers/populate_reagents() + add_to_reagents(/decl/material/liquid/painkillers, 15) . = ..() - reagents.add_reagent(/decl/material/liquid/painkillers, 15) - color = reagents.get_color() +/obj/item/chems/pill/strong_painkillers + desc = "A powerful painkiller. Do not mix with alcohol consumption." + icon_state = "pill3" + +/obj/item/chems/pill/strong_painkillers/populate_reagents() + add_to_reagents(/decl/material/liquid/painkillers/strong, 15) + . = ..() /obj/item/chems/pill/stabilizer - name = "stabilizer (30u)" desc = "Used to stabilize patients." icon_state = "pill1" -/obj/item/chems/pill/adrenaline/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/stabilizer, 30) - color = reagents.get_color() +/obj/item/chems/pill/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, 30) + . = ..() /obj/item/chems/pill/oxygen - name = "oxygen (15u)" desc = "Used to treat oxygen deprivation." icon_state = "pill1" -/obj/item/chems/pill/oxygen/Initialize() + +/obj/item/chems/pill/oxygen/populate_reagents() + add_to_reagents(/decl/material/liquid/oxy_meds, 15) . = ..() - reagents.add_reagent(/decl/material/liquid/oxy_meds, 15) - color = reagents.get_color() /obj/item/chems/pill/antitoxins - name = "antitoxins (15u)" desc = "A broad-spectrum anti-toxin." icon_state = "pill1" -/obj/item/chems/pill/antitoxins/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/antitoxins, 15) - color = reagents.get_color() +/obj/item/chems/pill/antitoxins/populate_reagents() + // Antitox is easy to make and has no OD threshold so we can get away with big pills. + . = ..() + add_to_reagents(/decl/material/liquid/antitoxins, 25) /obj/item/chems/pill/brute_meds - name = "styptic (20u)" desc = "Used to treat physical injuries." icon_state = "pill2" -/obj/item/chems/pill/brute_meds/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/brute_meds, 20) - color = reagents.get_color() +/obj/item/chems/pill/brute_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/brute_meds, 20) + . = ..() /obj/item/chems/pill/happy name = "happy pill" desc = "Happy happy joy joy!" icon_state = "pill4" -/obj/item/chems/pill/happy/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/psychoactives, 15) - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 15) - color = reagents.get_color() + autolabel = FALSE +/obj/item/chems/pill/happy/populate_reagents() + add_to_reagents(/decl/material/liquid/psychoactives, 15) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 15) + . = ..() /obj/item/chems/pill/zoom name = "zoom pill" desc = "Zoooom!" icon_state = "pill4" -/obj/item/chems/pill/zoom/Initialize() + autolabel = FALSE + +/obj/item/chems/pill/zoom/populate_reagents() + add_to_reagents(/decl/material/liquid/narcotics, 5) + add_to_reagents(/decl/material/liquid/accumulated/antidepressants, 5) + add_to_reagents(/decl/material/liquid/accumulated/stimulants, 5) + add_to_reagents(/decl/material/liquid/amphetamines, 5) . = ..() - reagents.add_reagent(/decl/material/liquid/narcotics, 5) - reagents.add_reagent(/decl/material/liquid/antidepressants, 5) - reagents.add_reagent(/decl/material/liquid/stimulants, 5) - reagents.add_reagent(/decl/material/liquid/amphetamines, 5) - color = reagents.get_color() /obj/item/chems/pill/gleam name = "strange pill" desc = "The surface of this unlabelled pill crawls against your skin." icon_state = "pill2" + autolabel = FALSE -/obj/item/chems/pill/gleam/Initialize() +/obj/item/chems/pill/gleam/populate_reagents() + add_to_reagents(/decl/material/liquid/glowsap/gleam, 10) . = ..() - reagents.add_reagent(/decl/material/liquid/glowsap/gleam, 10) - color = reagents.get_color() /obj/item/chems/pill/antibiotics - name = "antibiotics (10u)" desc = "Contains antibiotic agents." icon_state = "pill3" -/obj/item/chems/pill/antibiotics/Initialize() + +/obj/item/chems/pill/antibiotics/populate_reagents() + add_to_reagents(/decl/material/liquid/antibiotics, 10) . = ..() - reagents.add_reagent(/decl/material/liquid/antibiotics, 10) - color = reagents.get_color() //Psychiatry pills. /obj/item/chems/pill/stimulants - name = "stimulants (15u)" - desc = "Improves the ability to concentrate." + desc = "Improves the ability to concentrate. Abrupt discontinuation may result in side-effects." icon_state = "pill2" -/obj/item/chems/pill/stimulants/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/stimulants, 15) - color = reagents.get_color() +/obj/item/chems/pill/stimulants/populate_reagents() + add_to_reagents(/decl/material/liquid/accumulated/stimulants, 15) + . = ..() /obj/item/chems/pill/antidepressants - name = "antidepressants (15u)" - desc = "Mild anti-depressant." + desc = "Mild anti-depressant. Abrupt discontinuation may result in side-effects." icon_state = "pill4" -/obj/item/chems/pill/antidepressants/Initialize() + +/obj/item/chems/pill/antidepressants/populate_reagents() + add_to_reagents(/decl/material/liquid/accumulated/antidepressants, 15) . = ..() - reagents.add_reagent(/decl/material/liquid/antidepressants, 15) - color = reagents.get_color() /obj/item/chems/pill/antirads - name = "antirads (7u)" + name = "pill (anti-rad treatment, 15u)" desc = "Used to treat radiation poisoning." icon_state = "pill1" -/obj/item/chems/pill/antirads/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/antirads, 7) - color = reagents.get_color() + autolabel = FALSE -/obj/item/chems/pill/antirad - name = "AntiRad" - desc = "Used to treat radiation poisoning." - icon_state = "yellow" -/obj/item/chems/pill/antirad/Initialize() +/obj/item/chems/pill/antirads/populate_reagents() + add_to_reagents(/decl/material/liquid/antirads, 5) + add_to_reagents(/decl/material/liquid/antitoxins, 10) . = ..() - reagents.add_reagent(/decl/material/liquid/antirads, 5) - reagents.add_reagent(/decl/material/liquid/antitoxins, 10) - /obj/item/chems/pill/sugariron - name = "Sugar-Iron (10u)" + name = "pill (sugar-iron, 10u)" desc = "Used to help the body naturally replenish blood." icon_state = "pill1" -/obj/item/chems/pill/sugariron/Initialize() + autolabel = FALSE + +/obj/item/chems/pill/sugariron/populate_reagents() + add_to_reagents(/decl/material/solid/metal/iron, 5) + add_to_reagents(/decl/material/liquid/nutriment/sugar, 5) . = ..() - reagents.add_reagent(/decl/material/solid/metal/iron, 5) - reagents.add_reagent(/decl/material/liquid/nutriment/sugar, 5) - color = reagents.get_color() /obj/item/chems/pill/detergent name = "detergent pod" desc = "Put in water to get space cleaner. Do not eat. Really." icon_state = "pod21" - var/smell_clean_time = 10 MINUTES + autolabel = FALSE + +// Don't overwrite the custom name. +/obj/item/chems/pill/detergent/update_name() + return -/obj/item/chems/pill/detergent/Initialize() +/obj/item/chems/pill/detergent/populate_reagents() + add_to_reagents(/decl/material/liquid/contaminant_cleaner, 30) . = ..() - reagents.add_reagent(/decl/material/gas/ammonia, 30) /obj/item/chems/pill/pod name = "master flavorpod item" desc = "A cellulose pod containing some kind of flavoring." icon_state = "pill4" + autolabel = FALSE + +// Don't overwrite the custom names. +/obj/item/chems/pill/pod/update_name() + return /obj/item/chems/pill/pod/cream name = "creamer pod" -/obj/item/chems/pill/pod/cream/Initialize() +/obj/item/chems/pill/pod/cream/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk/cream, 5, data = list(DATA_MILK_DONOR = "cow")) . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk, 5) - color = reagents.get_color() /obj/item/chems/pill/pod/cream_soy name = "non-dairy creamer pod" -/obj/item/chems/pill/pod/cream_soy/Initialize() +/obj/item/chems/pill/pod/cream_soy/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/milk/soymilk, 5) . = ..() - reagents.add_reagent(/decl/material/liquid/drink/milk/soymilk, 5) - color = reagents.get_color() /obj/item/chems/pill/pod/orange name = "orange flavorpod" -/obj/item/chems/pill/pod/orange/Initialize() +/obj/item/chems/pill/pod/orange/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/juice/orange, 5) . = ..() - reagents.add_reagent(/decl/material/liquid/drink/juice/orange, 5) - color = reagents.get_color() /obj/item/chems/pill/pod/mint name = "mint flavorpod" -/obj/item/chems/pill/pod/mint/Initialize() +/obj/item/chems/pill/pod/mint/populate_reagents() + add_to_reagents(/decl/material/liquid/drink/syrup/mint, 1) . = ..() - reagents.add_reagent(/decl/material/liquid/drink/syrup/mint, 1) //mint is used as a catalyst in all reactions as of writing - color = reagents.get_color() diff --git a/code/modules/reagents/reagent_containers/pill_edibility.dm b/code/modules/reagents/reagent_containers/pill_edibility.dm new file mode 100644 index 000000000000..20b43f905702 --- /dev/null +++ b/code/modules/reagents/reagent_containers/pill_edibility.dm @@ -0,0 +1,30 @@ +/obj/item/chems/pill/get_food_consumption_method(mob/eater) + return EATING_METHOD_EAT + +/obj/item/chems/pill/get_edible_material_amount(var/mob/eater) + return REAGENT_TOTAL_VOLUME(reagents) + +/obj/item/chems/pill/get_food_default_transfer_amount(mob/eater) + return REAGENT_TOTAL_VOLUME(reagents) // Always eat it in one bite. + +/obj/item/chems/pill/show_feed_message_start(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(user) + if(user == target) + to_chat(user, SPAN_NOTICE("You begin trying to swallow \the [target].")) + else + user.visible_message(SPAN_NOTICE("\The [user] attempts to force \the [target] to swallow \the [src]!")) + +/obj/item/chems/pill/show_feed_message_end(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + target = target || user + if(user) + if(user == target) + to_chat(user, SPAN_NOTICE("You swallow \the [src].")) + else + user.visible_message(SPAN_NOTICE("\The [user] forces \the [target] to swallow \the [src]!")) + +/obj/item/chems/pill/play_feed_sound(mob/user, consumption_method = EATING_METHOD_EAT) + return + +/obj/item/chems/pill/show_food_consumed_message(mob/user, mob/target, consumption_method = EATING_METHOD_EAT) + return diff --git a/code/modules/reagents/reagent_containers/retort.dm b/code/modules/reagents/reagent_containers/retort.dm new file mode 100644 index 000000000000..2dfaf930e349 --- /dev/null +++ b/code/modules/reagents/reagent_containers/retort.dm @@ -0,0 +1,37 @@ +/obj/item/chems/glass/retort + name = "retort" + base_name = "retort" + desc = "A strangely-shaped vessel for separating chemicals when heated." + icon = 'icons/obj/items/retort.dmi' + icon_state = ICON_STATE_WORLD + chem_volume = 120 + material = /decl/material/solid/glass + material_alteration = MAT_FLAG_ALTERATION_ALL + +/obj/item/chems/glass/retort/can_lid() + return FALSE + +/obj/item/chems/glass/retort/copper + material = /decl/material/solid/metal/copper + +/obj/item/chems/glass/retort/earthenware + material = /decl/material/solid/stone/pottery + +/obj/item/chems/glass/retort/update_overlays() + if(REAGENT_TOTAL_VOLUME(reagents) && (!material || material.opacity < 1)) + var/datum/gas_mixture/environment = loc?.return_air() + var/ambient_pressure = environment ? environment.return_pressure() : ONE_ATMOSPHERE + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(reagent.phase_at_temperature(temperature, ambient_pressure) == MAT_PHASE_GAS) + add_overlay(overlay_image(icon, "[icon_state]-fill-boil", reagents.get_color(), (RESET_ALPHA|RESET_COLOR))) + return + add_overlay(overlay_image(icon, "[icon_state]-fill", reagents.get_color(), (RESET_ALPHA|RESET_COLOR))) + . = ..() + +/obj/item/chems/glass/retort/on_reagent_change() + . = ..() + update_icon() + +/obj/item/chems/glass/retort/ProcessAtomTemperature() + . = ..() + update_icon() diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 433c7124ea62..dcea23312bde 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -1,49 +1,53 @@ /obj/item/chems/spray - name = "spray bottle" - desc = "A spray bottle, with an unscrewable top." - icon = 'icons/obj/janitor.dmi' - icon_state = "cleaner" - item_state = "cleaner" - item_flags = ITEM_FLAG_NO_BLUDGEON - atom_flags = ATOM_FLAG_OPEN_CONTAINER - slot_flags = SLOT_BELT - throwforce = 3 - w_class = ITEM_SIZE_SMALL - throw_speed = 2 - throw_range = 10 - amount_per_transfer_from_this = 10 - unacidable = 1 //plastic - possible_transfer_amounts = @"[5,10]" - volume = 250 - var/spray_size = 3 - var/list/spray_sizes = list(1,3) - var/step_delay = 10 // lower is faster + name = "spray bottle" + desc = "A spray bottle, with an unscrewable top." + icon = 'icons/obj/janitor.dmi' + icon_state = "cleaner" + item_state = "cleaner" + item_flags = ITEM_FLAG_NO_BLUDGEON + atom_flags = ATOM_FLAG_OPEN_CONTAINER + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_SMALL + throw_speed = 2 + throw_range = 10 + attack_cooldown = DEFAULT_QUICK_COOLDOWN + material = /decl/material/solid/organic/plastic + chem_volume = 250 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = @"[5,10]" + var/tmp/possible_particle_amounts = @"[1,3]" ///Possible chempuff particles amount for each transfer amount setting + var/spray_particles = 3 ///Amount of chempuff particles + var/tmp/particle_move_delay = 10 ///lower is faster + var/tmp/sound_spray = 'sound/effects/spray2.ogg' ///Sound played when spraying + var/safety = FALSE ///Whether the safety is on + +/obj/item/chems/spray/solvent_can_melt(var/solvent_power = MAT_SOLVENT_STRONG) + return FALSE // maybe reconsider this /obj/item/chems/spray/Initialize() . = ..() src.verbs -= /obj/item/chems/verb/set_amount_per_transfer_from_this -/obj/item/chems/spray/afterattack(atom/A, mob/user, proximity) - if(istype(A, /obj/item/storage) || istype(A, /obj/structure/table) || istype(A, /obj/structure/closet) || istype(A, /obj/item/chems) || istype(A, /obj/structure/hygiene/sink) || istype(A, /obj/structure/janitorialcart)) - return +// Override to avoid drinking from this or feeding it to your neighbor. +/obj/item/chems/spray/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE - if(istype(A, /spell)) +/obj/item/chems/spray/afterattack(atom/A, mob/user, proximity) + if(A?.storage || istype(A, /obj/structure/table) || istype(A, /obj/structure/closet) || istype(A, /obj/item/chems) || istype(A, /obj/structure/hygiene/sink) || istype(A, /obj/structure/janitorialcart)) return if(proximity) if(standard_dispenser_refill(user, A)) return - if(reagents.total_volume < amount_per_transfer_from_this) - to_chat(user, "\The [src] is empty!") + if(REAGENT_TOTAL_VOLUME(reagents) < amount_per_transfer_from_this) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) return Spray_at(A, user, proximity) - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - if(reagents.has_reagent(/decl/material/liquid/acid)) - log_and_message_admins("fired sulphuric acid from \a [src].", user) + log_and_message_admins("fired sulfuric acid from \a [src].", user) if(reagents.has_reagent(/decl/material/liquid/acid/polyacid)) log_and_message_admins("fired polyacid from \a [src].", user) if(reagents.has_reagent(/decl/material/liquid/lube)) @@ -51,104 +55,119 @@ return /obj/item/chems/spray/proc/Spray_at(atom/movable/A, mob/user, proximity) - playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) + if(has_safety() && safety) + to_chat(user, SPAN_WARNING("The safety is on!")) + return + playsound(src, sound_spray, 50, TRUE, -6) if (A.density && proximity) reagents.splash(A, amount_per_transfer_from_this) if(A == user) - A.visible_message("\The [user] sprays themselves with \the [src].") + A.visible_message(SPAN_NOTICE("\The [user] sprays themselves with \the [src].")) else - A.visible_message("\The [user] sprays \the [A] with \the [src].") + A.visible_message(SPAN_NOTICE("\The [user] sprays \the [A] with \the [src].")) else - spawn(0) - var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src)) - var/turf/my_target = get_turf(A) - D.create_reagents(amount_per_transfer_from_this) - if(!src) - return - reagents.trans_to_obj(D, amount_per_transfer_from_this) - D.set_color() - D.set_up(my_target, spray_size, step_delay) - return + create_chempuff(A) + return TRUE -/obj/item/chems/spray/attack_self(var/mob/user) - if(!possible_transfer_amounts) +/obj/item/chems/spray/proc/create_chempuff(var/atom/movable/target, var/particle_amount) + set waitfor = FALSE + + var/obj/effect/effect/water/chempuff/D = new(get_turf(src)) + if(QDELETED(src)) return - amount_per_transfer_from_this = next_in_list(amount_per_transfer_from_this, cached_json_decode(possible_transfer_amounts)) - spray_size = next_in_list(spray_size, spray_sizes) - to_chat(user, "You adjusted the pressure nozzle. You'll now use [amount_per_transfer_from_this] units per spray.") + reagents.trans_to_obj(D, amount_per_transfer_from_this) + D.set_up(get_turf(target), particle_amount? particle_amount : spray_particles, particle_move_delay) + return D + +/obj/item/chems/spray/attack_self(var/mob/user) + if(has_safety()) + toggle_safety(user) + return TRUE + else + //If no safety, we just toggle the nozzle + var/decl/interaction_handler/handler = GET_DECL(/decl/interaction_handler/next_spray_amount) + if(handler.is_possible(src, user)) + handler.invoked(src, user, user.get_active_held_item()) + return TRUE + +///Whether the spray has a safety toggle +/obj/item/chems/spray/proc/has_safety() + return FALSE + +/obj/item/chems/spray/proc/toggle_safety(mob/user) + safety = !safety + to_chat(user, SPAN_NOTICE("You switch the safety [safety ? "on" : "off"].")) + +/obj/item/chems/spray/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(loc == user) + . += "[round(REAGENT_TOTAL_VOLUME(reagents))] unit\s left." + if(has_safety() && distance <= 1) + . += "The safety is [safety ? "on" : "off"]." -/obj/item/chems/spray/examine(mob/user, distance) +/obj/item/chems/spray/get_alt_interactions(mob/user) . = ..() - if(distance == 0 && loc == user) - to_chat(user, "[round(reagents.total_volume)] unit\s left.") + LAZYADD(., /decl/interaction_handler/empty/chems) + LAZYADD(., /decl/interaction_handler/next_spray_amount) -/obj/item/chems/spray/verb/empty() +///Toggle the spray size and transfer amount between the possible options +/decl/interaction_handler/next_spray_amount + name = "Next Nozzle Setting" + expected_target_type = /obj/item/chems/spray + interaction_flags = INTERACTION_NEEDS_INVENTORY | INTERACTION_NEEDS_PHYSICAL_INTERACTION + examine_desc = "select the next nozzle spray amount" - set name = "Empty Spray Bottle" - set category = "Object" - set src in usr +/decl/interaction_handler/next_spray_amount/is_possible(obj/item/chems/spray/target, mob/user, obj/item/prop) + . = ..() + if(.) + return !isnull(target.possible_transfer_amounts) - if (alert(usr, "Are you sure you want to empty that?", "Empty Bottle:", "Yes", "No") != "Yes") +/decl/interaction_handler/next_spray_amount/invoked(atom/target, mob/user, obj/item/prop) + var/obj/item/chems/spray/spray = target + if(!spray.possible_transfer_amounts) return - if(isturf(usr.loc)) - to_chat(usr, "You empty \the [src] onto the floor.") - reagents.splash(usr.loc, reagents.total_volume) + spray.amount_per_transfer_from_this = next_in_list(spray.amount_per_transfer_from_this, cached_json_decode(spray.possible_transfer_amounts)) + spray.spray_particles = next_in_list(spray.spray_particles, cached_json_decode(spray.possible_particle_amounts)) + to_chat(user, SPAN_NOTICE("You adjusted the pressure nozzle. You'll now use [spray.amount_per_transfer_from_this] units per spray.")) //space cleaner /obj/item/chems/spray/cleaner name = "space cleaner" desc = "BLAM!-brand non-foaming space cleaner!" - step_delay = 6 + particle_move_delay = 6 -/obj/item/chems/spray/cleaner/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/cleaner, volume) +/obj/item/chems/spray/cleaner/populate_reagents() + add_to_reagents(/decl/material/liquid/cleaner, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/item/chems/spray/antiseptic name = "antiseptic spray" desc = "Great for hiding incriminating bloodstains and sterilizing scalpels." -/obj/item/chems/spray/antiseptic/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/antiseptic, volume) +/obj/item/chems/spray/antiseptic/populate_reagents() + add_to_reagents(/decl/material/liquid/antiseptic, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/item/chems/spray/hair_remover name = "hair remover" desc = "Very effective at removing hair, feathers, spines and horns." -/obj/item/chems/spray/hair_remover/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/hair_remover, volume) +/obj/item/chems/spray/hair_remover/populate_reagents() + add_to_reagents(/decl/material/liquid/hair_remover, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/item/chems/spray/pepper name = "pepperspray" desc = "Manufactured by Uhang Inc., it fires a mist of condensed capsaicin to blind and down an opponent quickly." icon = 'icons/obj/items/weapon/pepperspray.dmi' - icon_state = "pepperspray" - item_state = "pepperspray" + icon_state = ICON_STATE_WORLD possible_transfer_amounts = null - volume = 60 - var/safety = 1 - step_delay = 1 - -/obj/item/chems/spray/pepper/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/capsaicin/condensed, 60) - -/obj/item/chems/spray/pepper/examine(mob/user, distance) - . = ..() - if(distance <= 1) - to_chat(user, "The safety is [safety ? "on" : "off"].") + chem_volume = 60 + particle_move_delay = 1 + safety = TRUE -/obj/item/chems/spray/pepper/attack_self(var/mob/user) - safety = !safety - to_chat(usr, "You switch the safety [safety ? "on" : "off"].") +/obj/item/chems/spray/pepper/populate_reagents() + add_to_reagents(/decl/material/liquid/capsaicin/condensed, REAGENT_MAXIMUM_VOLUME(reagents)) -/obj/item/chems/spray/pepper/Spray_at(atom/A) - if(safety) - to_chat(usr, "The safety is on!") - return - ..() +/obj/item/chems/spray/pepper/has_safety() + return TRUE /obj/item/chems/spray/waterflower name = "water flower" @@ -158,11 +177,10 @@ item_state = "sunflower" amount_per_transfer_from_this = 1 possible_transfer_amounts = null - volume = 10 + chem_volume = 10 -/obj/item/chems/spray/waterflower/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/water, 10) +/obj/item/chems/spray/waterflower/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/item/chems/spray/chemsprayer name = "chem sprayer" @@ -170,14 +188,13 @@ icon = 'icons/obj/items/device/chemsprayer.dmi' icon_state = "chemsprayer" item_state = "chemsprayer" - throwforce = 3 w_class = ITEM_SIZE_LARGE possible_transfer_amounts = null - volume = 600 - origin_tech = "{'combat':3,'materials':3,'engineering':3}" - step_delay = 8 + chem_volume = 600 + origin_tech = @'{"combat":3,"materials":3,"engineering":3}' + particle_move_delay = 2 //Was hardcoded to 2 before, and 8 was slower than most mob's move speed material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) /obj/item/chems/spray/chemsprayer/Spray_at(atom/A) var/direction = get_dir(src, A) @@ -187,16 +204,9 @@ var/list/the_targets = list(T, T1, T2) for(var/a = 1 to 3) - spawn(0) - if(reagents.total_volume < 1) break - var/obj/effect/effect/water/chempuff/D = new/obj/effect/effect/water/chempuff(get_turf(src)) - var/turf/my_target = the_targets[a] - D.create_reagents(amount_per_transfer_from_this) - if(!src) - return - reagents.trans_to_obj(D, amount_per_transfer_from_this) - D.set_color() - D.set_up(my_target, rand(6, 8), 2) + if(REAGENT_TOTAL_VOLUME(reagents) < 1) + break + create_chempuff(the_targets[a], rand(6, 8)) return /obj/item/chems/spray/plantbgone @@ -205,25 +215,16 @@ icon = 'icons/obj/hydroponics/hydroponics_machines.dmi' icon_state = "plantbgone" item_state = "plantbgone" - volume = 100 - -/obj/item/chems/spray/plantbgone/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/weedkiller, 100) - -/obj/item/chems/spray/plantbgone/afterattack(atom/A, mob/user, proximity) - if(!proximity) return - - if(istype(A, /obj/effect/blob)) // blob damage in blob code - return + chem_volume = 100 - ..() +/obj/item/chems/spray/plantbgone/populate_reagents() + add_to_reagents(/decl/material/liquid/weedkiller, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/item/chems/spray/cleaner/deodorant name = "deodorant" desc = "A can of Gold Standard spray deodorant - for when you're too lazy to shower." gender = PLURAL - volume = 35 + chem_volume = 35 icon = 'icons/obj/items/deodorant.dmi' icon_state = "deodorant" item_state = "deodorant" \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 4426361d9d42..fd4593aee2bd 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -7,37 +7,47 @@ /obj/item/chems/syringe name = "syringe" + base_name = "syringe" desc = "A syringe." icon = 'icons/obj/syringe.dmi' - item_state = "rg0" - icon_state = "rg" + icon_state = ICON_STATE_WORLD material = /decl/material/solid/glass amount_per_transfer_from_this = 5 possible_transfer_amounts = @"[1,2,5]" - volume = 15 + chem_volume = 15 w_class = ITEM_SIZE_TINY slot_flags = SLOT_EARS - sharp = 1 - unacidable = 1 //glass + sharp = TRUE item_flags = ITEM_FLAG_NO_BLUDGEON + var/mode = SYRINGE_DRAW - var/image/filling //holds a reference to the current filling overlay var/visible_name = "a syringe" var/time = 30 + var/autolabel = TRUE // if set, will add label with the name of the first initial reagent + var/can_stab = TRUE /obj/item/chems/syringe/Initialize(var/mapload) . = ..() update_icon() +/obj/item/chems/syringe/populate_reagents() + SHOULD_CALL_PARENT(TRUE) + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents) > 0 && autolabel && !label_text) // don't override preset labels + label_text = reagents.get_primary_reagent_name() + update_name() + + /obj/item/chems/syringe/on_reagent_change() - update_icon() + if((. = ..())) + update_icon() -/obj/item/chems/syringe/pickup(mob/user) - ..() +/obj/item/chems/syringe/on_picked_up(mob/user, atom/old_loc) + . = ..() update_icon() /obj/item/chems/syringe/dropped(mob/user) - ..() + . = ..() update_icon() /obj/item/chems/syringe/attack_self(mob/user) @@ -51,18 +61,18 @@ update_icon() /obj/item/chems/syringe/attack_hand() - ..() + . = ..() update_icon() -/obj/item/chems/syringe/attackby(obj/item/I, mob/user) - return +/obj/item/chems/syringe/attackby(obj/item/used_item, mob/user) + return FALSE // allow afterattack to proceed /obj/item/chems/syringe/afterattack(obj/target, mob/user, proximity) if(!proximity) return if(mode == SYRINGE_BROKEN) - to_chat(user, "This syringe is broken.") + to_chat(user, SPAN_WARNING("This syringe is broken.")) return if(istype(target, /obj/structure/closet/body_bag)) @@ -72,40 +82,32 @@ if(!target.reagents) return - if((user.a_intent == I_HURT) && ismob(target)) - syringestab(target, user) + if((user.check_intent(I_FLAG_HARM)) && ismob(target)) + if(can_stab) + syringestab(target, user) + else + to_chat(user, SPAN_WARNING("This syringe is too big to stab someone with it.")) return handleTarget(target, user) /obj/item/chems/syringe/on_update_icon() - overlays.Cut() + . = ..() underlays.Cut() - + icon_state = get_world_inventory_state() if(mode == SYRINGE_BROKEN) - icon_state = "broken" + icon_state = "[icon_state]_broken" return - - var/rounded_vol = Clamp(round((reagents.total_volume / volume * 15),5), 5, 15) - if (reagents.total_volume == 0) - rounded_vol = 0 + var/rounded_vol = 0 + if (REAGENT_TOTAL_VOLUME(reagents) > 0) + rounded_vol = clamp(round((REAGENT_TOTAL_VOLUME(reagents) / max(1, REAGENT_MAXIMUM_VOLUME(reagents) * 15)),5), 5, 15) if(ismob(loc)) - var/injoverlay - switch(mode) - if (SYRINGE_DRAW) - injoverlay = "draw" - if (SYRINGE_INJECT) - injoverlay = "inject" - overlays += injoverlay - icon_state = "[initial(icon_state)][rounded_vol]" - item_state = "syringe_[rounded_vol]" - - if(reagents.total_volume) - filling = image('icons/obj/reagentfillings.dmi', src, "syringe10") - - filling.icon_state = "syringe[rounded_vol]" - + add_overlay((mode == SYRINGE_DRAW)? "[icon_state]_draw" : "[icon_state]_inject") + icon_state = "[icon_state]_[rounded_vol]" + if(REAGENT_TOTAL_VOLUME(reagents)) + var/image/filling = image(icon, "[icon_state]_underlay") filling.color = reagents.get_color() + filling.appearance_flags |= RESET_COLOR underlays += filling /obj/item/chems/syringe/proc/handleTarget(var/atom/target, var/mob/user) @@ -118,27 +120,22 @@ /obj/item/chems/syringe/proc/drawReagents(var/atom/target, var/mob/user) if(!REAGENTS_FREE_SPACE(reagents)) - to_chat(user, "The syringe is full.") + to_chat(user, SPAN_WARNING("The syringe is full.")) mode = SYRINGE_INJECT return if(ismob(target))//Blood! - if(reagents.total_volume) - to_chat(user, "There is already a blood sample in this syringe.") + if(REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_NOTICE("There is already a blood sample in this syringe.")) return - if(istype(target, /mob/living/carbon)) - if(istype(target, /mob/living/carbon/slime)) - to_chat(user, "You are unable to locate any blood.") - return + if(ishuman(target)) var/amount = REAGENTS_FREE_SPACE(reagents) - var/mob/living/carbon/T = target - if(!T.dna) - to_chat(user, "You are unable to locate any blood.") - if(istype(target, /mob/living/carbon/human)) - CRASH("[T] \[[T.type]\] was missing their dna datum!") + var/mob/living/human/T = target + if(!REAGENT_TOTAL_VOLUME(T.vessel)) + to_chat(user, SPAN_WARNING("You are unable to locate any blood.")) return - var/allow = T.can_inject(user, check_zone(user.zone_sel.selecting)) + var/allow = T.can_inject(user, check_zone(user.get_target_zone(), T)) if(!allow) return @@ -156,8 +153,8 @@ to_chat(user, SPAN_NOTICE("You start trying to take a blood sample from yourself.")) if(prob(user.skill_fail_chance(SKILL_MEDICAL, 60, SKILL_BASIC))) - to_chat(user, "You miss the vein!") - var/target_zone = check_zone(user.zone_sel.selecting) + to_chat(user, SPAN_WARNING("You miss the vein!")) + var/target_zone = check_zone(user.get_target_zone(), T) T.apply_damage(3, BRUTE, target_zone, damage_flags=DAM_SHARP) return @@ -171,16 +168,16 @@ user.visible_message(SPAN_NOTICE("\The [user] takes a blood sample from \the [target].")) else //if not mob - if(!target.reagents.total_volume) - to_chat(user, "[target] is empty.") + if(!REAGENT_TOTAL_VOLUME(target.reagents)) + to_chat(user, SPAN_NOTICE("[target] is empty.")) return - if(!ATOM_IS_OPEN_CONTAINER(target) && !istype(target, /obj/structure/reagent_dispensers) && !istype(target, /obj/item/slime_extract)) - to_chat(user, "You cannot directly remove reagents from this object.") + if(!ATOM_IS_OPEN_CONTAINER(target) && !istype(target, /obj/structure/reagent_dispensers)) + to_chat(user, SPAN_NOTICE("You cannot directly remove reagents from this object.")) return var/trans = target.reagents.trans_to_obj(src, amount_per_transfer_from_this) - to_chat(user, "You fill the syringe with [trans] units of the solution.") + to_chat(user, SPAN_NOTICE("You fill the syringe with [trans] units of the solution.")) update_icon() if(!REAGENTS_FREE_SPACE(reagents)) @@ -188,21 +185,25 @@ update_icon() /obj/item/chems/syringe/proc/injectReagents(var/atom/target, var/mob/user) - if(ismob(target) && !user.skill_check(SKILL_MEDICAL, SKILL_BASIC)) + + if(ismob(target) && !user.skill_check(SKILL_MEDICAL, SKILL_BASIC) && (can_stab == TRUE)) syringestab(target, user) + return - if(!reagents.total_volume) - to_chat(user, "The syringe is empty.") + if(!REAGENT_TOTAL_VOLUME(reagents)) + to_chat(user, SPAN_NOTICE("The syringe is empty.")) mode = SYRINGE_DRAW return - if(istype(target, /obj/item/implantcase/chem)) + + if(!user.Adjacent(target)) return - if(!ATOM_IS_OPEN_CONTAINER(target) && !ismob(target) && !istype(target, /obj/item/chems/food) && !istype(target, /obj/item/slime_extract) && !istype(target, /obj/item/clothing/mask/smokable/cigarette) && !istype(target, /obj/item/storage/fancy/cigarettes)) - to_chat(user, "You cannot directly fill this object.") + if(!ismob(target) && (!target.reagents || !target.can_be_injected_by(src))) + to_chat(user, SPAN_NOTICE("You cannot directly fill this object.")) return + if(!REAGENTS_FREE_SPACE(target.reagents)) - to_chat(user, "[target] is full.") + to_chat(user, SPAN_NOTICE("[target] is full.")) return if(isliving(target)) @@ -210,12 +211,12 @@ return var/trans = reagents.trans_to(target, amount_per_transfer_from_this) - to_chat(user, "You inject \the [target] with [trans] units of the solution. \The [src] now contains [src.reagents.total_volume] units.") - if(reagents.total_volume <= 0 && mode == SYRINGE_INJECT) + to_chat(user, SPAN_NOTICE("You inject \the [target] with [trans] units of the solution. \The [src] now contains [REAGENT_TOTAL_VOLUME(src.reagents)] units.")) + if(REAGENT_TOTAL_VOLUME(reagents) <= 0 && mode == SYRINGE_INJECT) mode = SYRINGE_DRAW update_icon() -/obj/item/chems/syringe/proc/handleBodyBag(var/obj/structure/closet/body_bag/bag, var/mob/living/carbon/user) +/obj/item/chems/syringe/proc/handleBodyBag(var/obj/structure/closet/body_bag/bag, var/mob/living/user) if(bag.opened || !bag.contains_body) return @@ -223,11 +224,11 @@ if(L) injectMob(L, user, bag) -/obj/item/chems/syringe/proc/injectMob(var/mob/living/carbon/target, var/mob/living/carbon/user, var/atom/trackTarget) +/obj/item/chems/syringe/proc/injectMob(var/mob/living/target, var/mob/living/user, var/atom/trackTarget) if(!trackTarget) trackTarget = target - var/allow = target.can_inject(user, check_zone(user.zone_sel.selecting)) + var/allow = target.can_inject(user, check_zone(user.get_target_zone(), target)) if(!allow) return @@ -256,55 +257,54 @@ var/trans = reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_INJECT) if(target != user) - user.visible_message("\the [user] injects \the [target] with [visible_name]!", "You inject \the [target] with [trans] units of the solution. \The [src] now contains [src.reagents.total_volume] units.") + user.visible_message(SPAN_WARNING("\the [user] injects \the [target] with [visible_name]!"), SPAN_NOTICE("You inject \the [target] with [trans] units of the solution. \The [src] now contains [REAGENT_TOTAL_VOLUME(src.reagents)] units.")) else - to_chat(user, "You inject yourself with [trans] units of the solution. \The [src] now contains [src.reagents.total_volume] units.") + to_chat(user, SPAN_NOTICE("You inject yourself with [trans] units of the solution. \The [src] now contains [REAGENT_TOTAL_VOLUME(src.reagents)] units.")) - if(reagents.total_volume <= 0 && mode == SYRINGE_INJECT) + if(REAGENT_TOTAL_VOLUME(reagents) <= 0 && mode == SYRINGE_INJECT) mode = SYRINGE_DRAW update_icon() -/obj/item/chems/syringe/proc/syringestab(var/mob/living/carbon/target, var/mob/living/carbon/user) +/obj/item/chems/syringe/proc/syringestab(var/mob/living/target, var/mob/living/user) - if(istype(target, /mob/living/carbon/human)) + if(ishuman(target)) - var/mob/living/carbon/human/H = target + var/mob/living/human/H = target - var/target_zone = check_zone(user.zone_sel.selecting) - var/obj/item/organ/external/affecting = H.get_organ(target_zone) + var/target_zone = check_zone(user.get_target_zone(), H) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(H, target_zone) - if (!affecting || affecting.is_stump()) - to_chat(user, "They are missing that limb!") + if (!affecting) + to_chat(user, SPAN_DANGER("They are missing that limb!")) return var/hit_area = affecting.name - if((user != target) && H.check_shields(7, src, user, "\the [src]")) + if((user != target) && H.check_shields(7, src, user, target_zone, src)) return if (target != user && H.get_blocked_ratio(target_zone, BRUTE, damage_flags=DAM_SHARP) > 0.1 && prob(50)) - for(var/mob/O in viewers(world.view, user)) - O.show_message(text("[user] tries to stab [target] in \the [hit_area] with [src.name], but the attack is deflected by armor!"), 1) + user.visible_message(SPAN_WARNING("\The [user] tries to stab \the [target] in \the [hit_area] with \the [src], but the attack is deflected by armor!")) qdel(src) admin_attack_log(user, target, "Attacked using \a [src]", "Was attacked with \a [src]", "used \a [src] to attack") return - user.visible_message("[user] stabs [target] in \the [hit_area] with [src.name]!") + user.visible_message(SPAN_DANGER("[user] stabs [target] in \the [hit_area] with [src.name]!")) target.apply_damage(3, BRUTE, target_zone, damage_flags=DAM_SHARP) else - user.visible_message("[user] stabs [target] with [src.name]!") + user.visible_message(SPAN_DANGER("[user] stabs [target] with [src.name]!")) target.apply_damage(3, BRUTE) - var/syringestab_amount_transferred = rand(0, (reagents.total_volume - 5)) //nerfed by popular demand + var/syringestab_amount_transferred = rand(0, (REAGENT_TOTAL_VOLUME(reagents) - 5)) //nerfed by popular demand var/contained_reagents = reagents.get_reagents() var/trans = reagents.trans_to_mob(target, syringestab_amount_transferred, CHEM_INJECT) if(isnull(trans)) trans = 0 admin_inject_log(user, target, src, contained_reagents, trans, violent=1) break_syringe(target, user) -/obj/item/chems/syringe/proc/break_syringe(mob/living/carbon/target, mob/living/carbon/user) +/obj/item/chems/syringe/proc/break_syringe(mob/living/human/target, mob/living/user) desc += " It is broken." mode = SYRINGE_BROKEN if(target) @@ -314,84 +314,82 @@ update_icon() /obj/item/chems/syringe/ld50_syringe - name = "Lethal Injection Syringe" + name = "lethal injection syringe" desc = "A syringe used for lethal injections." amount_per_transfer_from_this = 60 - volume = 60 + chem_volume = 60 visible_name = "a giant syringe" - time = 300 + time = 30 SECONDS + mode = SYRINGE_INJECT + autolabel = FALSE + can_stab = FALSE -/obj/item/chems/syringe/ld50_syringe/syringestab(var/mob/living/carbon/target, var/mob/living/carbon/user) - to_chat(user, "This syringe is too big to stab someone with it.") - return // No instant injecting +/obj/item/chems/syringe/ld50_syringe/populate_reagents() + SHOULD_CALL_PARENT(FALSE) + add_to_reagents(/decl/material/liquid/heartstopper, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/item/chems/syringe/ld50_syringe/drawReagents(var/target, var/mob/user) if(ismob(target)) // No drawing 60 units of blood at once - to_chat(user, "This needle isn't designed for drawing blood.") + to_chat(user, SPAN_NOTICE("This needle isn't designed for drawing blood.")) return ..() -/obj/item/chems/syringe/ld50_syringe/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/heartstopper, 60) - mode = SYRINGE_INJECT - update_icon() - //////////////////////////////////////////////////////////////////////////////// /// Syringes. END //////////////////////////////////////////////////////////////////////////////// /obj/item/chems/syringe/stabilizer - name = "Syringe (stabilizer)" desc = "Contains stabilizer - for patients in danger of brain damage." - -/obj/item/chems/syringe/stabilizer/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/stabilizer, 15) mode = SYRINGE_INJECT - update_icon() + +/obj/item/chems/syringe/stabilizer/populate_reagents() + add_to_reagents(/decl/material/liquid/stabilizer, REAGENT_MAXIMUM_VOLUME(reagents)) + return ..() /obj/item/chems/syringe/antitoxin - name = "Syringe (anti-toxin)" desc = "Contains anti-toxins." - -/obj/item/chems/syringe/antitoxin/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/antitoxins, 15) mode = SYRINGE_INJECT - update_icon() + +/obj/item/chems/syringe/antitoxin/populate_reagents() + add_to_reagents(/decl/material/liquid/antitoxins, REAGENT_MAXIMUM_VOLUME(reagents)) + return ..() /obj/item/chems/syringe/antibiotic - name = "Syringe (antibiotics)" desc = "Contains antibiotic agents." - -/obj/item/chems/syringe/antibiotic/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/antibiotics, 15) mode = SYRINGE_INJECT - update_icon() + +/obj/item/chems/syringe/antibiotic/populate_reagents() + add_to_reagents(/decl/material/liquid/antibiotics, REAGENT_MAXIMUM_VOLUME(reagents)) + return ..() /obj/item/chems/syringe/drugs - name = "Syringe (drugs)" desc = "Contains aggressive drugs meant for torture." - -/obj/item/chems/syringe/drugs/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/psychoactives, 5) - reagents.add_reagent(/decl/material/liquid/hallucinogenics, 5) - reagents.add_reagent(/decl/material/liquid/presyncopics, 5) mode = SYRINGE_INJECT - update_icon() + +/obj/item/chems/syringe/drugs/populate_reagents() + var/vol_each = round(REAGENT_MAXIMUM_VOLUME(reagents) / 3) + add_to_reagents(/decl/material/liquid/psychoactives, vol_each) + add_to_reagents(/decl/material/liquid/hallucinogenics, vol_each) + add_to_reagents(/decl/material/liquid/presyncopics, vol_each) + return ..() /obj/item/chems/syringe/steroid - name = "Syringe (anabolic steroids)" desc = "Contains drugs for muscle growth." + mode = SYRINGE_INJECT -/obj/item/chems/syringe/steroid/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/adrenaline, 5) - reagents.add_reagent(/decl/material/liquid/amphetamines, 10) +/obj/item/chems/syringe/steroid/populate_reagents() + var/vol_third = round(REAGENT_MAXIMUM_VOLUME(reagents)/3) + add_to_reagents(/decl/material/liquid/adrenaline, vol_third) + add_to_reagents(/decl/material/liquid/amphetamines, 2 * vol_third) + return ..() + +/obj/item/chems/syringe/brute_meds + desc = "Contains drugs for treating brute trauma." + mode = SYRINGE_INJECT +/obj/item/chems/syringe/brute_meds/populate_reagents() + add_to_reagents(/decl/material/liquid/brute_meds, REAGENT_MAXIMUM_VOLUME(reagents)) + return ..() // TG ports @@ -399,22 +397,24 @@ name = "advanced syringe" desc = "An advanced syringe that can hold 60 units of chemicals." amount_per_transfer_from_this = 20 - volume = 60 - icon_state = "bs" + chem_volume = 60 + icon = 'icons/obj/syringe_advanced.dmi' material = /decl/material/solid/glass matter = list( /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE, /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"biotech":3,"materials":4,"exoticmatter":2}' /obj/item/chems/syringe/noreact name = "cryostasis syringe" desc = "An advanced syringe that stops reagents inside from reacting. It can hold up to 20 units." - volume = 20 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_REACT - icon_state = "cs" + chem_volume = 20 + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE + icon = 'icons/obj/syringe_cryo.dmi' material = /decl/material/solid/glass matter = list( /decl/material/solid/metal/gold = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) + origin_tech = @'{"biotech":4,"materials":4}' diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 69a86dbef79c..3dd12396af68 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -1,94 +1,71 @@ /obj/structure/reagent_dispensers - name = "dispenser" - desc = "A large tank for storing chemicals." - icon = 'icons/obj/objects.dmi' - icon_state = "watertank" - density = TRUE - anchored = FALSE - - var/unwrenched = FALSE - var/initial_capacity = 1000 - var/initial_reagent_types // A list of reagents and their ratio relative the initial capacity. list(/decl/material/liquid/water = 0.5) would fill the dispenser halfway to capacity. - var/amount_per_transfer_from_this = 10 - var/possible_transfer_amounts = @"[10,25,50,100,500]" - -/obj/structure/reagent_dispensers/Initialize() - . = ..() - create_reagents(initial_capacity) - if (!possible_transfer_amounts) - verbs -= /obj/structure/reagent_dispensers/verb/set_amount_per_transfer_from_this - for(var/reagent_type in initial_reagent_types) - var/reagent_ratio = initial_reagent_types[reagent_type] - reagents.add_reagent(reagent_type, reagent_ratio * initial_capacity) + name = "dispenser" + desc = "A large tank for storing chemicals." + icon = 'icons/obj/objects.dmi' + icon_state = "watertank" + density = TRUE + anchored = FALSE + material = /decl/material/solid/organic/plastic + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY) + max_health = 100 + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + chem_volume = 1000 + + var/wrenchable = TRUE + var/unwrenched = FALSE + var/amount_dispensed = 10 + var/can_toggle_open = TRUE + var/tmp/possible_transfer_amounts = @"[10,25,50,100,500]" + +/obj/structure/reagent_dispensers/get_reagent_amount_dispensed() + return amount_dispensed + +/obj/structure/reagent_dispensers/set_reagent_amount_dispensed(new_amount) + amount_dispensed = new_amount + +/obj/structure/reagent_dispensers/get_possible_reagent_transfer_amounts() + return cached_json_decode(possible_transfer_amounts) + +/obj/structure/reagent_dispensers/on_reagent_change() + if(!(. = ..())) + return + if(REAGENT_TOTAL_VOLUME(reagents) > 0) + tool_interaction_flags &= ~TOOL_INTERACTION_DECONSTRUCT + else + tool_interaction_flags |= TOOL_INTERACTION_DECONSTRUCT /obj/structure/reagent_dispensers/proc/leak() var/turf/T = get_turf(src) if(reagents && T) - reagents.trans_to_turf(T, FLUID_PUDDLE) + reagents.trans_to_turf(T, min(REAGENT_TOTAL_VOLUME(reagents), FLUID_PUDDLE)) /obj/structure/reagent_dispensers/Move() . = ..() if(. && unwrenched) leak() -/obj/structure/reagent_dispensers/Process() - if(unwrenched) - leak() - -/obj/structure/reagent_dispensers/examine(mob/user) +/obj/structure/reagent_dispensers/get_examine_strings(mob/user, distance, infix, suffix) . = ..() if(unwrenched) - to_chat(user, SPAN_WARNING("Someone has wrenched open its tap - it's spilling everywhere!")) + . += SPAN_WARNING("Someone has wrenched open its tap - it's spilling everywhere!") + if(distance <= 2) + if(wrenchable) + if(ATOM_IS_OPEN_CONTAINER(src)) + . += "Its refilling cap is open." + else + . += "Its refilling cap is closed." -/obj/structure/reagent_dispensers/Destroy() - . = ..() - STOP_PROCESSING(SSprocessing, src) +/obj/structure/reagent_dispensers/attackby(obj/item/used_item, mob/user) -/obj/structure/reagent_dispensers/attackby(obj/item/W, mob/user) - if(isWrench(W)) + if(wrenchable && IS_WRENCH(used_item)) unwrenched = !unwrenched visible_message(SPAN_NOTICE("\The [user] wrenches \the [src]'s tap [unwrenched ? "open" : "shut"].")) if(unwrenched) - log_and_message_admins("opened a tank at [get_area(loc)].") - START_PROCESSING(SSprocessing, src) - else - STOP_PROCESSING(SSprocessing, src) + log_and_message_admins("opened a tank at [get_area_name(loc)].") + leak() return TRUE - . = ..() -/obj/structure/reagent_dispensers/examine(mob/user, distance) - . = ..() - if(distance <= 2) - to_chat(user, SPAN_NOTICE("It contains:")) - if(LAZYLEN(reagents?.reagent_volumes)) - for(var/rtype in reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - to_chat(user, SPAN_NOTICE("[REAGENT_VOLUME(reagents, rtype)] units of [R.name]")) - else - to_chat(user, SPAN_NOTICE("Nothing.")) - -/obj/structure/reagent_dispensers/verb/set_amount_per_transfer_from_this() - set name = "Set transfer amount" - set category = "Object" - set src in view(1) - if(!CanPhysicallyInteract(usr)) - to_chat(usr, SPAN_NOTICE("You're in no condition to do that!'")) - return - var/N = input("Amount per transfer from this:","[src]") as null|anything in cached_json_decode(possible_transfer_amounts) - if(!CanPhysicallyInteract(usr)) // because input takes time and the situation can change - to_chat(usr, SPAN_NOTICE("You're in no condition to do that!'")) - return - if (N) - amount_per_transfer_from_this = N - -/obj/structure/reagent_dispensers/physically_destroyed() - if(reagents?.total_volume) - var/turf/T = get_turf(src) - if(T) - var/obj/effect/fluid/F = locate() in T - if(!F) F = new(T) - reagents.trans_to_holder(F.reagents, reagents.total_volume) . = ..() /obj/structure/reagent_dispensers/explosion_act(severity) @@ -96,159 +73,228 @@ if(. && (severity == 1) || (severity == 2 && prob(50)) || (severity == 3 && prob(5))) physically_destroyed() -/obj/structure/reagent_dispensers/AltClick(var/mob/user) - if(possible_transfer_amounts) - set_amount_per_transfer_from_this() - else - return ..() - //Dispensers /obj/structure/reagent_dispensers/watertank - name = "water tank" - desc = "A tank containing water." - icon = 'icons/obj/objects.dmi' - icon_state = "watertank" - amount_per_transfer_from_this = 10 + name = "water tank" + desc = "A tank containing water." + icon_state = "watertank" + amount_dispensed = 10 possible_transfer_amounts = @"[10,25,50,100]" - initial_capacity = 50000 - initial_reagent_types = list(/decl/material/liquid/water = 1) - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE - -/obj/structure/reagent_dispensers/watertank/attackby(obj/item/W, mob/user) - if((istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm)) && user.unEquip(W)) - to_chat(user, "You add \the [W] arm to \the [src].") - qdel(W) + chem_volume = 7500 + atom_flags = ATOM_FLAG_CLIMBABLE + movable_flags = MOVABLE_FLAG_WHEELED + +/obj/structure/reagent_dispensers/watertank/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/watertank/high + name = "high-capacity water tank" + desc = "A highly-pressurized water tank made to hold vast amounts of water." + icon = 'icons/obj/structures/water_tank_high.dmi' + icon_state = ICON_STATE_WORLD + +/obj/structure/reagent_dispensers/watertank/firefighter + name = "firefighting water reserve" + chem_volume = 50000 + +/obj/structure/reagent_dispensers/watertank/attackby(obj/item/used_item, mob/user) + //FIXME: Maybe this should be handled differently? Since it can essentially make the tank unusable. + if((istype(used_item, /obj/item/robot_parts/l_arm) || istype(used_item, /obj/item/robot_parts/r_arm)) && user.try_unequip(used_item)) + to_chat(user, "You add \the [used_item] arm to \the [src].") + qdel(used_item) new /obj/item/farmbot_arm_assembly(loc, src) return TRUE . = ..() /obj/structure/reagent_dispensers/fueltank - name = "fuel tank" - desc = "A tank containing welding fuel." - icon = 'icons/obj/objects.dmi' - icon_state = "weldtank" - amount_per_transfer_from_this = 10 - initial_reagent_types = list(/decl/material/liquid/fuel = 1) - atom_flags = ATOM_FLAG_CLIMBABLE - - var/obj/item/assembly_holder/rig = null - -/obj/structure/reagent_dispensers/fueltank/examine(mob/user) + name = "fuel tank" + desc = "A tank containing welding fuel." + icon_state = "weldtank" + amount_dispensed = 10 + atom_flags = ATOM_FLAG_CLIMBABLE + movable_flags = MOVABLE_FLAG_WHEELED + var/obj/item/assembly_holder/rig + +/obj/structure/reagent_dispensers/fueltank/populate_reagents() + add_to_reagents(/decl/material/liquid/fuel, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/reagent_dispensers/fueltank/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(rig) - to_chat(user, SPAN_WARNING("There is some kind of device rigged to the tank.")) + if(rig && distance < 2) + . += SPAN_WARNING("There is some kind of device rigged to the tank.") /obj/structure/reagent_dispensers/fueltank/attack_hand(var/mob/user) - if (rig) - visible_message(SPAN_NOTICE("\The [user] begins to detach \the [rig] from \the [src].")) - if(do_after(user, 20, src)) - visible_message(SPAN_NOTICE("\The [user] detaches \the [rig] from \the [src].")) - rig.dropInto(loc) - rig = null - overlays.Cut() - -/obj/structure/reagent_dispensers/fueltank/attackby(obj/item/W, mob/user) - add_fingerprint(user) - if(istype(W,/obj/item/assembly_holder)) + if (!rig || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + visible_message(SPAN_NOTICE("\The [user] begins to detach \the [rig] from \the [src].")) + if(!user.do_skilled(2 SECONDS, SKILL_ELECTRICAL, src)) + return TRUE + visible_message(SPAN_NOTICE("\The [user] detaches \the [rig] from \the [src].")) + rig.dropInto(loc) + rig = null + update_icon() + return TRUE + +/obj/structure/reagent_dispensers/fueltank/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/assembly_holder)) if (rig) to_chat(user, SPAN_WARNING("There is another device already in the way.")) return ..() - visible_message(SPAN_NOTICE("\The [user] begins rigging \the [W] to \the [src].")) - if(do_after(user, 20, src) && user.unEquip(W, src)) - visible_message(SPAN_NOTICE("\The [user] rigs \the [W] to \the [src].")) - var/obj/item/assembly_holder/H = W + visible_message(SPAN_NOTICE("\The [user] begins rigging \the [used_item] to \the [src].")) + if(do_after(user, 20, src) && user.try_unequip(used_item, src)) + visible_message(SPAN_NOTICE("\The [user] rigs \the [used_item] to \the [src].")) + var/obj/item/assembly_holder/H = used_item if (istype(H.a_left,/obj/item/assembly/igniter) || istype(H.a_right,/obj/item/assembly/igniter)) log_and_message_admins("rigged a fuel tank for explosion at [loc.loc.name].") - rig = W - var/icon/test = getFlatIcon(W) - test.Shift(NORTH,1) - test.Shift(EAST,6) - overlays += test + rig = used_item + update_icon() return TRUE - if(W.isflamesource()) - log_and_message_admins("triggered a fuel tank explosion with \the [W].") - visible_message(SPAN_DANGER("\The [user] puts \the [W] to \the [src]!")) + + if(used_item.isflamesource()) + log_and_message_admins("triggered a fuel tank explosion with \the [used_item].") + visible_message(SPAN_DANGER("\The [user] puts \the [used_item] to \the [src]!")) try_detonate_reagents() return TRUE + . = ..() +/obj/structure/reagent_dispensers/fueltank/on_update_icon() + . = ..() + if(rig) + var/mutable_appearance/I = new(rig.appearance) + I.pixel_x += 6 + I.pixel_y += 1 + add_overlay(I) + /obj/structure/reagent_dispensers/fueltank/bullet_act(var/obj/item/projectile/Proj) + //FIXME: Probably should check if it can actual inflict that structure damage first. if(Proj.get_structure_damage()) - if(istype(Proj.firer)) + if(isliving(Proj.firer)) var/turf/turf = get_turf(src) if(turf) var/area/area = turf.loc || "*unknown area*" - log_and_message_admins("[key_name_admin(Proj.firer)] shot a fuel tank in \the [area].") + log_and_message_admins("[key_name_admin(Proj.firer)] shot a fuel tank in \the [area.proper_name].") else log_and_message_admins("shot a fuel tank outside the world.") - if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) + if((Proj.damage_flags & DAM_EXPLODE) || (Proj.atom_damage_type == BURN) || (Proj.atom_damage_type == ELECTROCUTE) || (Proj.atom_damage_type == BRUTE)) try_detonate_reagents() + return ..() + /obj/structure/reagent_dispensers/fueltank/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature > T0C+500) try_detonate_reagents() return ..() /obj/structure/reagent_dispensers/peppertank - name = "pepper spray refiller" - desc = "Refills pepper spray canisters." - icon = 'icons/obj/objects.dmi' - icon_state = "peppertank" - anchored = 1 - density = 0 - amount_per_transfer_from_this = 45 - initial_reagent_types = list(/decl/material/liquid/capsaicin/condensed = 1) + name = "pepper spray refiller" + desc = "Refills pepper spray canisters." + icon = 'icons/obj/objects.dmi' + icon_state = "peppertank" + anchored = TRUE + density = FALSE + amount_dispensed = 45 + +/obj/structure/reagent_dispensers/peppertank/populate_reagents() + add_to_reagents(/decl/material/liquid/capsaicin/condensed, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/structure/reagent_dispensers/water_cooler - name = "water cooler" - desc = "A machine that dispenses cool water to drink." - amount_per_transfer_from_this = 5 - icon = 'icons/obj/vending.dmi' - icon_state = "water_cooler" + name = "water cooler" + desc = "A machine that dispenses cool water to drink." + icon = 'icons/obj/structures/water_cooler.dmi' + icon_state = "water_cooler" possible_transfer_amounts = null - anchored = 1 - initial_capacity = 500 - initial_reagent_types = list(/decl/material/liquid/water = 1) - tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) - var/cups = 12 - var/cup_type = /obj/item/chems/food/drinks/sillycup + amount_dispensed = 5 + anchored = TRUE + chem_volume = 500 + tool_interaction_flags = (TOOL_INTERACTION_ANCHOR | TOOL_INTERACTION_DECONSTRUCT) + var/cups = 12 + var/tmp/max_cups = 12 + var/tmp/cup_type = /obj/item/chems/drinks/sillycup + +/obj/structure/reagent_dispensers/water_cooler/populate_reagents() + add_to_reagents(/decl/material/liquid/water, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/structure/reagent_dispensers/water_cooler/attack_hand(var/mob/user) + if(user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return dispense_cup(user) + return ..() + +/obj/structure/reagent_dispensers/water_cooler/proc/dispense_cup(var/mob/user, var/skip_text = FALSE) if(cups > 0) - var/visible_messages = DispenserMessages(user) - visible_message(visible_messages[1], visible_messages[2]) var/cup = new cup_type(loc) user.put_in_active_hand(cup) cups-- - else - to_chat(user, RejectionMessage(user)) - -/obj/structure/reagent_dispensers/water_cooler/proc/DispenserMessages(var/mob/user) - return list("\The [user] grabs a paper cup from \the [src].", "You grab a paper cup from \the [src]'s cup compartment.") + if(!skip_text) + visible_message("\The [user] grabs a paper cup from \the [src].", "You grab a paper cup from \the [src]'s cup compartment.") + return TRUE -/obj/structure/reagent_dispensers/water_cooler/proc/RejectionMessage(var/mob/user) - return "The [src]'s cup dispenser is empty." + if(!skip_text) + to_chat(user, "\The [src]'s cup dispenser is empty.") + return TRUE + +/obj/structure/reagent_dispensers/water_cooler/attackby(obj/item/used_item, mob/user) + //Allow refilling with a box + if(cups < max_cups && used_item?.storage) + for(var/obj/item/chems/drinks/C in used_item.storage.get_contents()) + if(cups >= max_cups) + break + if(istype(C, cup_type)) + used_item.storage.remove_from_storage(user, C, src) + qdel(C) + cups++ + return TRUE + return ..() -/obj/structure/reagent_dispensers/water_cooler/attackby(obj/item/W, mob/user) +/obj/structure/reagent_dispensers/water_cooler/on_reagent_change() . = ..() - if(!.) - flick("[icon_state]-vend", src) + // Bubbles in top of cooler. + if(REAGENT_TOTAL_VOLUME(reagents)) + var/vend_state = "[icon_state]-vend" + if(check_state_in_icon(vend_state, icon)) + flick(vend_state, src) /obj/structure/reagent_dispensers/beerkeg - name = "beer keg" - desc = "A beer keg." - icon = 'icons/obj/objects.dmi' - icon_state = "beertankTEMP" - amount_per_transfer_from_this = 10 - initial_reagent_types = list(/decl/material/liquid/ethanol/beer = 1) - atom_flags = ATOM_FLAG_CLIMBABLE + name = "beer keg" + desc = "A beer keg." + icon_state = "beertankTEMP" + amount_dispensed = 10 + atom_flags = ATOM_FLAG_CLIMBABLE + material = /decl/material/solid/metal/aluminium + matter = list(/decl/material/solid/metal/stainlesssteel = MATTER_AMOUNT_TRACE) + +/obj/structure/reagent_dispensers/beerkeg/populate_reagents() + add_to_reagents(/decl/material/liquid/alcohol/beer, REAGENT_MAXIMUM_VOLUME(reagents)) /obj/structure/reagent_dispensers/acid - name = "sulphuric acid dispenser" - desc = "A dispenser of acid for industrial processes." - icon = 'icons/obj/objects.dmi' - icon_state = "acidtank" - amount_per_transfer_from_this = 10 - anchored = 1 - initial_reagent_types = list(/decl/material/liquid/acid = 1) + name = "sulfuric acid dispenser" + desc = "A dispenser of acid for industrial processes." + icon_state = "acidtank" + amount_dispensed = 10 + anchored = TRUE + density = FALSE + +/obj/structure/reagent_dispensers/acid/populate_reagents() + add_to_reagents(/decl/material/liquid/acid, REAGENT_MAXIMUM_VOLUME(reagents)) + +//Interactions +/obj/structure/reagent_dispensers/get_alt_interactions(var/mob/user) + . = ..() + if(can_toggle_open) + LAZYADD(., /decl/interaction_handler/toggle_open/reagent_dispenser) + +//Allows normal refilling, or toggle back to normal reagent dispenser operation +/decl/interaction_handler/toggle_open/reagent_dispenser + name = "Toggle refilling cap" + expected_target_type = /obj/structure/reagent_dispensers + examine_desc = "open or close the refilling cap" + +/decl/interaction_handler/toggle_open/reagent_dispenser/invoked(atom/target, mob/user, obj/item/prop) + if(target.atom_flags & ATOM_FLAG_OPEN_CONTAINER) + target.atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + else + target.atom_flags |= ATOM_FLAG_OPEN_CONTAINER + target.update_icon() + return TRUE diff --git a/code/modules/reagents/storage/pill_bottle.dm b/code/modules/reagents/storage/pill_bottle.dm index 70f2709eae47..28482973709c 100644 --- a/code/modules/reagents/storage/pill_bottle.dm +++ b/code/modules/reagents/storage/pill_bottle.dm @@ -1,43 +1,33 @@ /* * Pill Bottles */ -/obj/item/storage/pill_bottle +/obj/item/pill_bottle name = "pill bottle" desc = "It's an airtight container for storing medication." icon_state = "pill_canister" icon = 'icons/obj/items/storage/pillbottle.dmi' item_state = "contsolid" w_class = ITEM_SIZE_SMALL - max_w_class = ITEM_SIZE_TINY - max_storage_space = 21 - can_hold = list( - /obj/item/chems/pill, - /obj/item/dice, - /obj/item/paper - ) - allow_quick_gather = 1 - use_to_pickup = 1 - use_sound = 'sound/effects/storage/pillbottle.ogg' - material = /decl/material/solid/plastic - + storage = /datum/storage/pillbottle + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/organic/plastic var/pop_sound = 'sound/effects/peelz.ogg' var/wrapper_color - var/label + /// If a string, a label with this value will be added. + var/labeled_name = null -/obj/item/storage/pill_bottle/remove_from_storage(obj/item/W, atom/new_location, NoUpdate) - . = ..() - if(. && pop_sound) - playsound(get_turf(src), pop_sound, 50) +/obj/item/pill_bottle/proc/pop_pill(var/mob/user) -/obj/item/storage/pill_bottle/proc/pop_pill(var/mob/user) + if(!storage) + return FALSE - var/target_mouth = (user.zone_sel?.selecting == BP_MOUTH) + var/target_mouth = (user.get_target_zone() == BP_MOUTH) if(target_mouth) if(!user.can_eat()) to_chat(user, SPAN_WARNING("You can't eat anything!")) return TRUE else - if(user.get_inactive_hand()) + if(!user.get_empty_hand_slot()) to_chat(user, SPAN_WARNING("You need an empty hand to take something from \the [src].")) return TRUE @@ -47,32 +37,55 @@ return TRUE var/obj/item/chems/pill/pill = pick(pills_here) - if(remove_from_storage(pill, user)) + if(storage.remove_from_storage(user, pill, user)) if(target_mouth) user.visible_message(SPAN_NOTICE("\The [user] pops a pill from \the [src].")) - pill.attack(user, user) + pill.use_on_mob(user, user) else if(user.put_in_inactive_hand(pill)) to_chat(user, SPAN_NOTICE("You take \the [pill] out of \the [src].")) - user.swap_hand() else pill.dropInto(loc) to_chat(user, SPAN_DANGER("You fumble around with \the [src] and drop \the [pill].")) return TRUE -/obj/item/storage/pill_bottle/afterattack(mob/living/target, mob/living/user, proximity_flag) +/obj/item/pill_bottle/afterattack(mob/living/target, mob/living/user, proximity_flag) . = (proximity_flag && user == target && pop_pill(user)) || ..() -/obj/item/storage/pill_bottle/attack_self(mob/living/user) +/obj/item/pill_bottle/attack_self(mob/user) . = pop_pill(user) || ..() -/obj/item/storage/pill_bottle/Initialize() +/obj/item/pill_bottle/Initialize() . = ..() update_icon() + if(istext(labeled_name)) + attach_label(null, null, labeled_name) -/obj/item/storage/pill_bottle/on_update_icon() - overlays.Cut() +/obj/item/pill_bottle/on_update_icon() + . = ..() if(wrapper_color) - var/image/I = image(icon, "pillbottle_wrap") - I.color = wrapper_color - overlays += I \ No newline at end of file + add_overlay(overlay_image(icon, "pillbottle_wrap", wrapper_color, RESET_COLOR)) + +/obj/item/pill_bottle/attackby(obj/item/used_item, mob/user) + if(IS_PEN(used_item)) + var/tmp_label = sanitize_safe(input(user, "Enter a label for [name]", "Label", labeled_name), MAX_NAME_LEN) + tmp_label = user.handle_writing_literacy(user, tmp_label) + + var/label_length = length(tmp_label) + if(label_length > 50) + to_chat(user, "The label can be at most 50 characters long.") + else + if(label_length > 10) + to_chat(user, "You set the label.") + else + to_chat(user, "You set the label to \"[tmp_label]\".") + + var/decl/tool_archetype/pen/parch = GET_DECL(TOOL_PEN) + if(parch.decrement_uses(user, used_item, max(round(label_length / 25, 1), 1)) <= 0) + parch.warn_out_of_ink(user, used_item) + + var/datum/extension/labels/lext = get_or_create_extension(src, /datum/extension/labels) + lext.RemoveAllLabels() + attach_label(null, null, tmp_label) + return TRUE + return ..() \ No newline at end of file diff --git a/code/modules/reagents/storage/pill_bottle_subtypes.dm b/code/modules/reagents/storage/pill_bottle_subtypes.dm index fa1ef8da0e7c..5c7cd359f0a6 100644 --- a/code/modules/reagents/storage/pill_bottle_subtypes.dm +++ b/code/modules/reagents/storage/pill_bottle_subtypes.dm @@ -1,80 +1,99 @@ -/obj/item/storage/pill_bottle/antitox - name = "pill bottle (antitoxins)" - desc = "Contains pills used to counter toxins." - - startswith = list(/obj/item/chems/pill/antitox = 21) - wrapper_color = COLOR_GREEN - -/obj/item/storage/pill_bottle/brute_meds - name = "pill bottle (styptic)" +/obj/item/pill_bottle/brute_meds + labeled_name = "styptic" desc = "Contains pills used to stabilize the severely injured." + wrapper_color = COLOR_MAROON + +/obj/item/pill_bottle/brute_meds/WillContain() + return list(/obj/item/chems/pill/brute_meds = 21) - startswith = list(/obj/item/chems/pill/brute_meds = 21) +/obj/item/pill_bottle/sugariron + labeled_name = "sugar-iron" + desc = "Contains pills used to assist in blood recovery." wrapper_color = COLOR_MAROON -/obj/item/storage/pill_bottle/oxygen - name = "pill bottle (oxygen)" - desc = "Contains pills used to treat oxygen deprivation." +/obj/item/pill_bottle/sugariron/WillContain() + return list(/obj/item/chems/pill/sugariron = 21) - startswith = list(/obj/item/chems/pill/oxygen = 21) +/obj/item/pill_bottle/oxygen + labeled_name = "oxygen" + desc = "Contains pills used to treat oxygen deprivation." wrapper_color = COLOR_LIGHT_CYAN -/obj/item/storage/pill_bottle/antitoxins - name = "pill bottle (antitoxins)" - desc = "Contains pills used to treat toxic substances in the blood." +/obj/item/pill_bottle/oxygen/WillContain() + return list(/obj/item/chems/pill/oxygen = 21) - startswith = list(/obj/item/chems/pill/antitoxins = 21) +/obj/item/pill_bottle/antitoxins + labeled_name = "antitoxins" + desc = "Contains pills used to treat toxic substances." wrapper_color = COLOR_GREEN -/obj/item/storage/pill_bottle/adrenaline - name = "pill bottle (adrenaline)" - desc = "Contains pills used to stabilize patients." +/obj/item/pill_bottle/antitoxins/WillContain() + return list(/obj/item/chems/pill/antitoxins = 21) - startswith = list(/obj/item/chems/pill/adrenaline = 21) +/obj/item/pill_bottle/stabilizer + labeled_name = "stabilizer" + desc = "Contains pills used to stabilize patients." wrapper_color = COLOR_PALE_BLUE_GRAY -/obj/item/storage/pill_bottle/burn_meds - name = "pill bottle (synthskin)" - desc = "Contains pills used to treat burns." +/obj/item/pill_bottle/stabilizer/WillContain() + return list(/obj/item/chems/pill/stabilizer = 21) - startswith = list(/obj/item/chems/pill/burn_meds = 21) +/obj/item/pill_bottle/burn_meds + labeled_name = "synthskin" + desc = "Contains pills used to treat burns." wrapper_color = COLOR_SUN -/obj/item/storage/pill_bottle/antibiotics - name = "pill bottle (antibiotics)" - desc = "A theta-lactam antibiotic. Effective against many diseases likely to be encountered in space." +/obj/item/pill_bottle/burn_meds/WillContain() + return list(/obj/item/chems/pill/burn_meds = 21) - startswith = list(/obj/item/chems/pill/antibiotics = 14) +/obj/item/pill_bottle/antibiotics + labeled_name = "antibiotics" + desc = "A theta-lactam antibiotic. Effective against many diseases likely to be encountered in space." wrapper_color = COLOR_PALE_GREEN_GRAY -/obj/item/storage/pill_bottle/painkillers - name = "pill bottle (painkillers)" +/obj/item/pill_bottle/antibiotics/WillContain() + return list(/obj/item/chems/pill/antibiotics = 14) + +/obj/item/pill_bottle/painkillers + labeled_name = "painkillers" desc = "Contains pills used to relieve pain." + wrapper_color = COLOR_PURPLE_GRAY + +/obj/item/pill_bottle/painkillers/WillContain() + return list(/obj/item/chems/pill/painkillers = 14) - startswith = list(/obj/item/chems/pill/painkillers = 14) +/obj/item/pill_bottle/strong_painkillers + labeled_name = "strong painkillers" + desc = "Contains pills used to relieve pain. Do not mix with alcohol consumption." wrapper_color = COLOR_PURPLE_GRAY +/obj/item/pill_bottle/strong_painkillers/WillContain() + return list(/obj/item/chems/pill/strong_painkillers = 14) + //Baycode specific Psychiatry pills. -/obj/item/storage/pill_bottle/antidepressants - name = "pill bottle (antidepressants)" +/obj/item/pill_bottle/antidepressants + labeled_name = "antidepressants" desc = "Mild antidepressant. For use in individuals suffering from depression or anxiety. 15u dose per pill." - - startswith = list(/obj/item/chems/pill/antidepressants = 21) wrapper_color = COLOR_GRAY -/obj/item/storage/pill_bottle/stimulants - name = "pill bottle (stimulants)" - desc = "Mental stimulant. For use in individuals suffering from ADHD, or general concentration issues. 15u dose per pill." +/obj/item/pill_bottle/antidepressants/WillContain() + return list(/obj/item/chems/pill/antidepressants = 21) - startswith = list(/obj/item/chems/pill/stimulants = 21) +/obj/item/pill_bottle/stimulants + labeled_name = "stimulants" + desc = "Mental stimulant. For use in individuals suffering from ADHD, or general concentration issues. 15u dose per pill." wrapper_color = COLOR_GRAY -/obj/item/storage/pill_bottle/assorted - name = "pill bottle (assorted)" +/obj/item/pill_bottle/stimulants/WillContain() + return list(/obj/item/chems/pill/stimulants = 21) + +/obj/item/pill_bottle/assorted + labeled_name = "assorted" desc = "Commonly found on paramedics, these assorted pill bottles contain all the basics." - startswith = list( - /obj/item/chems/pill/adrenaline = 6, +/obj/item/pill_bottle/assorted/WillContain() + return list( + /obj/item/chems/pill/stabilizer = 6, /obj/item/chems/pill/antitoxins = 6, /obj/item/chems/pill/sugariron = 2, /obj/item/chems/pill/painkillers = 2, diff --git a/code/modules/reagents/storage/pill_foil.dm b/code/modules/reagents/storage/pill_foil.dm index 43b9d8ebd8ca..0d7f1d36fa7f 100644 --- a/code/modules/reagents/storage/pill_foil.dm +++ b/code/modules/reagents/storage/pill_foil.dm @@ -1,68 +1,56 @@ -/obj/item/storage/pill_bottle/foil_pack +/obj/item/pill_bottle/foil_pack name = "foil pack" desc = "A package of pills." icon = 'icons/obj/pill_pack.dmi' icon_state = "pill_pack" pop_sound = 'sound/effects/pop.ogg' + color = COLOR_GRAY80 + storage = /datum/storage/pillbottle/foil var/pill_type var/pill_count = 4 var/pill_positions -/obj/item/storage/pill_bottle/foil_pack/painkillers +/obj/item/pill_bottle/foil_pack/painkillers pill_type = /obj/item/chems/pill/painkillers -/obj/item/storage/pill_bottle/foil_pack/remove_from_storage(obj/item/W, atom/new_location, NoUpdate) - . = ..() - if(. && W.loc != src && pill_positions) - pill_positions -= W - update_icon() - -/obj/item/storage/pill_bottle/foil_pack/Initialize() +/obj/item/pill_bottle/foil_pack/Initialize() . = ..() if(pill_type && pill_count) - var/atom/pill_path = pill_type - name = "[name] ([initial(pill_path.name)])" - pill_positions = list() for(var/i = 1 to pill_count) - pill_positions[new pill_type(src)] = i + var/pill = new pill_type(src) + LAZYSET(pill_positions, pill, i) + if(length(pill_positions)) + var/obj/item/chems/pill = pill_positions[1] + SetName("[initial(name)] ([pill.name])") update_icon() -/obj/item/storage/pill_bottle/foil_pack/pop_pill(var/mob/user) +/obj/item/pill_bottle/foil_pack/pop_pill(var/mob/user) . = ..() update_icon() -/obj/item/storage/pill_bottle/foil_pack/Destroy() +/obj/item/pill_bottle/foil_pack/Destroy() pill_positions = null . = ..() -/obj/item/storage/pill_bottle/foil_pack/can_be_inserted(obj/item/W, mob/user, stop_messages = 0) - return FALSE - -/obj/item/storage/pill_bottle/foil_pack/on_update_icon() +/obj/item/pill_bottle/foil_pack/on_update_icon() ..() var/offset = 0 - var/list/add_overlays = list() for(var/obj/item/chems/pill/pill in pill_positions) - var/image/I = image(icon, "pill") I.color = pill.color I.appearance_flags |= RESET_COLOR I.pixel_y = offset - add_overlays += I - + add_overlay(I) I = image(icon, "pill") I.color = COLOR_LIGHT_CYAN I.alpha = 80 I.appearance_flags |= RESET_COLOR I.pixel_y = offset - add_overlays += I - + add_overlay(I) offset -= 3 - overlays += add_overlays - -/obj/item/storage/pill_bottle/foil_pack/examine(mob/user) +/obj/item/pill_bottle/foil_pack/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, SPAN_NOTICE("It has the following pills in it:")) + . += SPAN_NOTICE("It has the following pills in it:") for(var/obj/item/chems/pill/C in pill_positions) - to_chat(user, SPAN_NOTICE("\icon[C] [C.name]")) + . += SPAN_NOTICE("[html_icon(C)] [C.name]") diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index ceffe0d0b719..ccfd214b9623 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -1,16 +1,16 @@ -var/list/all_conveyors = list() -var/list/all_conveyor_switches = list() +var/global/list/all_conveyors = list() +var/global/list/all_conveyor_switches = list() //conveyor2 is pretty much like the original, except it supports corners, but not diverters. //note that corner pieces transfer stuff clockwise when running forward, and anti-clockwise backwards. /obj/machinery/conveyor - icon = 'icons/obj/recycling.dmi' + icon = 'icons/obj/machines/conveyor_mapped.dmi' icon_state = "conveyor0" name = "conveyor belt" desc = "A conveyor belt." layer = BELOW_OBJ_LAYER // so they appear under stuff - anchored = 1 + anchored = TRUE var/operating = 0 // 1 if running forward, -1 if backwards, 0 if off var/operable = 1 // true if can operate (no broken segments in this belt run) var/forwards // this is the default (forward) direction, set by the map dir @@ -24,6 +24,7 @@ var/list/all_conveyor_switches = list() // create a conveyor /obj/machinery/conveyor/Initialize(mapload, newdir, on = 0) . = ..(mapload) + icon = 'icons/obj/recycling.dmi' global.all_conveyors += src if(newdir) set_dir(newdir) @@ -80,21 +81,22 @@ var/list/all_conveyor_switches = list() if(items_moved >= 10) break +/obj/machinery/conveyor/grab_attack(obj/item/grab/grab, mob/user) + step(grab.affecting, get_dir(grab.affecting.loc, src)) + return TRUE + // attack with item, place item on conveyor -/obj/machinery/conveyor/attackby(var/obj/item/I, mob/user) - if(istype(I, /obj/item/grab)) - var/obj/item/grab/G = I - step(G.affecting, get_dir(G.affecting.loc, src)) - return - if(isCrowbar(I)) +/obj/machinery/conveyor/attackby(var/obj/item/used_item, mob/user) + if(IS_CROWBAR(used_item)) if(!(stat & BROKEN)) var/obj/item/conveyor_construct/C = new/obj/item/conveyor_construct(src.loc) C.id_tag = id_tag transfer_fingerprints_to(C) to_chat(user, "You remove the conveyor belt.") qdel(src) - return - user.unequip_item(get_turf(src)) + else + user.try_unequip(used_item, get_turf(src)) + return TRUE // make the conveyor broken // also propagate inoperability to any connected conveyor with the same id_tag @@ -142,7 +144,7 @@ var/list/all_conveyor_switches = list() if(!id_tag) id_tag = newid update_icon() - . = INITIALIZE_HINT_LATELOAD + . = INITIALIZE_HINT_LATELOAD /obj/machinery/conveyor_switch/LateInitialize() . = ..() @@ -154,7 +156,7 @@ var/list/all_conveyor_switches = list() /obj/machinery/conveyor_switch/Destroy() global.all_conveyor_switches -= src . = ..() - + // update the icon depending on the position /obj/machinery/conveyor_switch/on_update_icon() @@ -205,13 +207,15 @@ var/list/all_conveyor_switches = list() last_pos = position position = 0 -/obj/machinery/conveyor_switch/attackby(obj/item/I, mob/user, params) - if(isCrowbar(I)) - var/obj/item/conveyor_switch_construct/C = new/obj/item/conveyor_switch_construct(src.loc) - C.id_tag = id_tag - transfer_fingerprints_to(C) - to_chat(user, "You deattach the conveyor switch.") - qdel(src) +/obj/machinery/conveyor_switch/attackby(obj/item/used_item, mob/user, params) + if(!IS_CROWBAR(used_item)) + return ..() + var/obj/item/conveyor_switch_construct/C = new/obj/item/conveyor_switch_construct(src.loc) + C.id_tag = id_tag + transfer_fingerprints_to(C) + to_chat(user, "You detach the conveyor switch.") + qdel(src) + return TRUE /obj/machinery/conveyor_switch/oneway var/convdir = 1 //Set to 1 or -1 depending on which way you want the convayor to go. (In other words keep at 1 and set the proper dir on the belts.) @@ -234,21 +238,25 @@ var/list/all_conveyor_switches = list() desc = "A conveyor belt assembly. Must be linked to a conveyor control switch assembly before placement." w_class = ITEM_SIZE_HUGE material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/plastic = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) var/id_tag -/obj/item/conveyor_construct/attackby(obj/item/I, mob/user, params) - ..() - if(istype(I, /obj/item/conveyor_switch_construct)) - to_chat(user, "You link the switch to the conveyor belt assembly.") - var/obj/item/conveyor_switch_construct/C = I - id_tag = C.id_tag +/obj/item/conveyor_construct/attackby(obj/item/used_item, mob/user, params) + if(!istype(used_item, /obj/item/conveyor_switch_construct)) + return ..() + to_chat(user, "You link the switch to the conveyor belt assembly.") + var/obj/item/conveyor_switch_construct/C = used_item + id_tag = C.id_tag + return TRUE /obj/item/conveyor_construct/afterattack(atom/A, mob/user, proximity) - if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated()) + if(!proximity || !istype(A, /turf/floor) || user.incapacitated()) return + var/area/area = get_area(A) + if(!istype(area) || (area.area_flags & AREA_FLAG_SHUTTLE)) + return FALSE var/cdir = get_dir(A, user) - if(!(cdir in GLOB.cardinal) || A == user.loc) + if(!(cdir in global.cardinal) || A == user.loc) return for(var/obj/machinery/conveyor/CB in A) if(CB.dir == cdir || CB.dir == turn(cdir,180)) @@ -261,7 +269,7 @@ var/list/all_conveyor_switches = list() qdel(src) /obj/item/conveyor_switch_construct - name = "conveyor switch assembly" + name = "two-way conveyor switch assembly" desc = "A conveyor control switch assembly." icon = 'icons/obj/recycling.dmi' icon_state = "switch-off" @@ -274,15 +282,18 @@ var/list/all_conveyor_switches = list() id_tag = sequential_id("conveyor_switch_construct") /obj/item/conveyor_switch_construct/afterattack(atom/A, mob/user, proximity) - if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated()) + if(!proximity || !istype(A, /turf/floor) || user.incapacitated()) return + var/area/area = get_area(A) + if(!istype(area) || (area.area_flags & AREA_FLAG_SHUTTLE)) + return FALSE var/found = 0 for(var/obj/machinery/conveyor/C in view()) if(C.id_tag == src.id_tag) found = 1 break if(!found) - to_chat(user, "\icon[src]The conveyor switch did not detect any linked conveyor belts in range.") + to_chat(user, "[html_icon(src)]The conveyor switch did not detect any linked conveyor belts in range.") return var/obj/machinery/conveyor_switch/NC = new /obj/machinery/conveyor_switch(A, id_tag) transfer_fingerprints_to(NC) @@ -290,18 +301,21 @@ var/list/all_conveyor_switches = list() /obj/item/conveyor_switch_construct/oneway name = "one-way conveyor switch assembly" - desc = "An one-way conveyor control switch assembly." + desc = "A one-way conveyor control switch assembly." /obj/item/conveyor_switch_construct/oneway/afterattack(atom/A, mob/user, proximity) - if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated()) + if(!proximity || !istype(A, /turf/floor) || user.incapacitated()) return + var/area/area = get_area(A) + if(!istype(area) || (area.area_flags & AREA_FLAG_SHUTTLE)) + return FALSE var/found = 0 for(var/obj/machinery/conveyor/C in view()) if(C.id_tag == src.id_tag) found = 1 break if(!found) - to_chat(user, "\icon[src]The conveyor switch did not detect any linked conveyor belts in range.") + to_chat(user, "[html_icon(src)]The conveyor switch did not detect any linked conveyor belts in range.") return var/obj/machinery/conveyor_switch/oneway/NC = new /obj/machinery/conveyor_switch/oneway(A, id_tag) transfer_fingerprints_to(NC) diff --git a/code/modules/recycling/destination_tagger.dm b/code/modules/recycling/destination_tagger.dm new file mode 100644 index 000000000000..ddb0e5181bd9 --- /dev/null +++ b/code/modules/recycling/destination_tagger.dm @@ -0,0 +1,81 @@ +#define MAX_DEST_TAGGER_PREVIOUS_TAGS 25 //Give them 25 memory slot until they begin overwriting the first in the list + +/obj/item/destTagger + name = "destination tagger" + desc = "Used to set the destination of properly wrapped packages." + icon = 'icons/obj/items/device/destination_tagger.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT + ) + ///Text of the destination tag we're going to be applying next. + var/current_tag + ///List of the last tags that were actually applied on something. Like a sort of handy quick dial feature. + var/list/last_used_tags + +/obj/item/destTagger/proc/clear_previous_tags() + LAZYCLEARLIST(last_used_tags) + +///Add a previous destionation tag to the list and perform rotation of the tag history if neccessary. +/obj/item/destTagger/proc/add_previous_tag(var/text) + if(LAZYLEN(last_used_tags) >= MAX_DEST_TAGGER_PREVIOUS_TAGS) + last_used_tags.Cut(1, 2) + LAZYADD(last_used_tags, text) + +/obj/item/destTagger/interact(mob/user) + + var/dat = "

    TagMaster 2.3


    " + dat += "
    " + dat += "
    Current Selection:
    " + dat += "
    " + + dat += "

    Tag History:

    " + dat += "Clear History" + dat += "" + var/cnt = 1 + for(var/prevdest in last_used_tags) + if(cnt % 4 == 0) + dat += "" + dat += "" + ++cnt + dat += "
    [prevdest]
    " + + show_browser(user, dat, "window=destTagScreen;size=450x375") + +/obj/item/destTagger/attack_self(mob/user) + interact(user) + +/obj/item/destTagger/OnTopic(user, href_list, state) + if(href_list["set_tag"]) + current_tag = sanitize_safe(href_list["set_tag"], encode = FALSE) + to_chat(user, SPAN_NOTICE("You set \the [src] to [current_tag].")) + playsound(src.loc, 'sound/machines/pda_click.ogg', 30, TRUE) + . = TOPIC_REFRESH + + if(href_list["input_tag"]) + var/dest = input(user, "Please enter custom location.", "Location", current_tag) + if(CanUseTopic(user, state)) + if(dest) + current_tag = sanitize_safe(dest, encode = FALSE) + add_previous_tag(current_tag) + to_chat(user, SPAN_NOTICE("You designate a custom location on \the [src], set to [current_tag].")) + playsound(src.loc, 'sound/machines/pda_click.ogg', 30, TRUE) + else + current_tag = null + to_chat(user, SPAN_NOTICE("You clear \the [src]'s custom location.")) + playsound(src.loc, 'sound/machines/quiet_beep.ogg', 30, TRUE) + . = TOPIC_REFRESH + else + . = TOPIC_HANDLED + else if(href_list["clear_previous_tags"]) + clear_previous_tags() + to_chat(user, SPAN_NOTICE("You clear \the [src]'s tag history.")) + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + interact(user) + +#undef MAX_DEST_TAGGER_PREVIOUS_TAGS \ No newline at end of file diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm index 6f85b2368883..7724f726e4a1 100644 --- a/code/modules/recycling/disposal-construction.dm +++ b/code/modules/recycling/disposal-construction.dm @@ -4,12 +4,12 @@ /obj/structure/disposalconstruct name = "disposal pipe segment" desc = "A huge pipe segment used for constructing disposal systems." - icon = 'icons/obj/pipes/disposal.dmi' icon_state = "conpipe-s" - anchored = 0 - density = 0 + icon = 'icons/obj/pipes/disposal_pipe.dmi' + anchored = FALSE + density = FALSE material = /decl/material/solid/metal/steel - level = 2 + level = LEVEL_ABOVE_PLATING obj_flags = OBJ_FLAG_ROTATABLE var/sort_type = "" var/dpdir = 0 // directions as disposalpipe @@ -65,7 +65,7 @@ // hide called by levelupdate if turf intact status changes // change visibility status and force update of icon /obj/structure/disposalconstruct/hide(var/intact) - set_invisibility((intact && level==1) ? 101: 0) // hide if floor is intact + set_invisibility((intact && level == LEVEL_BELOW_PLATING) ? 101: 0) // hide if floor is intact update() /obj/structure/disposalconstruct/proc/flip() @@ -92,7 +92,8 @@ set_dir(turn(dir, 180)) /obj/structure/disposalconstruct/on_update_icon() - if("con[built_icon_state]" in icon_states(icon)) + ..() + if(check_state_in_icon("con[built_icon_state]", icon)) icon_state = "con[built_icon_state]" else icon_state = built_icon_state @@ -119,48 +120,50 @@ // attackby item // wrench: (un)anchor // weldingtool: convert to real pipe -/obj/structure/disposalconstruct/attackby(var/obj/item/I, var/mob/user) +/obj/structure/disposalconstruct/attackby(var/obj/item/used_item, var/mob/user) var/turf/T = loc if(!istype(T)) - return + return TRUE if(!T.is_plating()) - to_chat(user, "You can only manipulate \the [src] if the floor plating is removed.") - return + to_chat(user, "You can only manipulate \the [src] if the plating is exposed.") + return TRUE var/obj/structure/disposalpipe/CP = locate() in T - if(isWrench(I)) + if(IS_WRENCH(used_item)) if(anchored) - anchored = 0 + anchored = FALSE wrench_down(FALSE) to_chat(user, "You detach \the [src] from the underfloor.") else if(!check_buildability(CP, user)) - return + return TRUE wrench_down(TRUE) to_chat(user, "You attach \the [src] to the underfloor.") playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) update() update_verbs() - - else if(istype(I, /obj/item/weldingtool)) + return TRUE + else if(istype(used_item, /obj/item/weldingtool)) if(anchored) - var/obj/item/weldingtool/W = I - if(W.remove_fuel(0,user)) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) to_chat(user, "Welding \the [src] in place.") - if(do_after(user, 20, src)) - if(!src || !W.isOn()) return + if(do_after(user, 2 SECONDS, src)) + if(!src || !welder.isOn()) return TRUE to_chat(user, "\The [src] has been welded in place!") build(CP) qdel(src) - return + return TRUE + return TRUE else to_chat(user, "You need more welding fuel to complete this task.") - return + return TRUE else to_chat(user, "You need to attach it to the plating first!") - return + return TRUE + return TRUE /obj/structure/disposalconstruct/hides_under_flooring() return anchored @@ -179,11 +182,11 @@ /obj/structure/disposalconstruct/proc/wrench_down(anchor) if(anchor) anchored = TRUE - level = 1 // We don't want disposal bins to disappear under the floors + level = LEVEL_BELOW_PLATING set_density(0) else anchored = FALSE - level = 2 + level = LEVEL_ABOVE_PLATING set_density(1) /obj/structure/disposalconstruct/machine/check_buildability(obj/structure/disposalpipe/CP, mob/user) @@ -210,6 +213,7 @@ /obj/structure/disposalconstruct/machine obj_flags = 0 // No rotating + constructed_path = /obj/machinery/disposal/buildable /obj/structure/disposalconstruct/machine/Initialize(mapload, P) . = ..() @@ -224,7 +228,7 @@ update_icon() /obj/structure/disposalconstruct/machine/build(obj/structure/disposalpipe/CP) - var/obj/machinery/disposal/machine = new /obj/machinery/disposal(get_turf(src), dir) + var/obj/machinery/disposal/machine = new constructed_path(get_turf(src), dir) var/datum/extension/parts_stash/stash = get_extension(src, /datum/extension/parts_stash) if(stash) stash.install_into(machine) @@ -239,6 +243,9 @@ else ..() +/obj/structure/disposalconstruct/machine/outlet + constructed_path = /obj/structure/disposaloutlet + /obj/structure/disposalconstruct/machine/outlet/build(obj/structure/disposalpipe/CP) var/obj/structure/disposaloutlet/P = new constructed_path(loc) transfer_fingerprints_to(P) @@ -247,4 +254,5 @@ Trunk.linked = P /obj/structure/disposalconstruct/machine/chute - obj_flags = OBJ_FLAG_ROTATABLE \ No newline at end of file + obj_flags = OBJ_FLAG_ROTATABLE + constructed_path = /obj/machinery/disposal/deliveryChute/buildable \ No newline at end of file diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 898dab3efe96..49527c33cdbb 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -9,15 +9,15 @@ #define PRESSURE_TANK_VOLUME 150 //L #define PUMP_MAX_FLOW_RATE 90 //L/s - 4 m/s using a 15 cm by 15 cm inlet -GLOBAL_LIST_EMPTY(diversion_junctions) +var/global/list/diversion_junctions = list() /obj/machinery/disposal name = "disposal unit" desc = "A pneumatic waste disposal unit." - icon = 'icons/obj/pipes/disposal.dmi' + icon = 'icons/obj/pipes/disposal_bin.dmi' icon_state = "disposal" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE var/datum/gas_mixture/air_contents // internal reservoir var/mode = 1 // item mode 0=off 1=charging 2=charged var/flush = 0 // true if flush handle is pulled @@ -68,119 +68,121 @@ GLOBAL_LIST_EMPTY(diversion_junctions) return FALSE /obj/machinery/disposal/cannot_transition_to(state_path, mob/user) - if(mode > 0) - return SPAN_NOTICE("Turn off the pump first.") if(contents.len > LAZYLEN(component_parts)) return SPAN_NOTICE("Eject the items first!") return ..() +/obj/machinery/disposal/grab_attack(obj/item/grab/grab, mob/user) + var/mob/living/victim = grab.get_affecting_mob() + if(istype(victim)) + user.visible_message(SPAN_DANGER("\The [user] starts putting \the [victim] into the disposal.")) + if(do_after(user, 2 SECONDS, src)) + if (victim.client) + victim.client.perspective = EYE_PERSPECTIVE + victim.client.eye = src + victim.forceMove(src) + user.visible_message(SPAN_DANGER("\The [victim] has been placed in \the [src] by \the [user].")) + qdel(grab) + admin_attack_log(user, victim, "Placed the victim into \the [src].", "Was placed into \the [src] by the attacker.", "stuffed \the [src] with") + return TRUE + return ..() + // attack by item places it in to disposal -/obj/machinery/disposal/attackby(var/obj/item/I, var/mob/user) +/obj/machinery/disposal/attackby(var/obj/item/used_item, var/mob/user) if((. = ..())) return - if(stat & BROKEN || !I || !user) - return - - if(istype(I, /obj/item/energy_blade/blade)) - to_chat(user, "You can't place that item inside the disposal unit.") - return - - if(istype(I, /obj/item/storage/bag/trash)) - var/obj/item/storage/bag/trash/T = I - to_chat(user, "You empty the bag.") - for(var/obj/item/O in T.contents) - T.remove_from_storage(O,src, 1) - T.finish_bulk_removal() - update_icon() - return - - var/obj/item/grab/G = I - if(istype(G)) // handle grabbed mob - var/mob/GM = G.get_affecting_mob() - if(GM) - usr.visible_message(SPAN_DANGER("\The [usr] starts putting [GM.name] into the disposal.")) - if(do_after(usr, 20, src)) - if (GM.client) - GM.client.perspective = EYE_PERSPECTIVE - GM.client.eye = src - GM.forceMove(src) - usr.visible_message(SPAN_DANGER("\The [GM] has been placed in the [src] by \the [user].")) - qdel(G) - admin_attack_log(usr, GM, "Placed the victim into \the [src].", "Was placed into \the [src] by the attacker.", "stuffed \the [src] with") - return - - if(!user.unEquip(I, src)) - return - - user.visible_message("\The [user] places \the [I] into \the [src].", "You place \the [I] into \the [src].") - - update_icon() - -/obj/machinery/disposal/MouseDrop_T(atom/movable/AM, mob/user) - if(!istype(AM)) // Could be dragging in a turf. - return - var/incapacitation_flags = INCAPACITATION_DEFAULT - if(AM == user) - incapacitation_flags &= ~INCAPACITATION_RESTRAINED - - if(stat & BROKEN || !CanMouseDrop(AM, user, incapacitation_flags) || AM.anchored || !isturf(user.loc)) - return - - // Animals can only put themself in - if(isanimal(user) && AM != user) + if(stat & BROKEN || !used_item || !user) return - // Determine object type and run necessary checks - var/mob/M = AM - var/is_dangerous // To determine css style in messages - if(istype(M)) - is_dangerous = TRUE - if(M.buckled) + if(istype(used_item, /obj/item/bag/trash)) + if(used_item.storage) + to_chat(user, "You empty the bag.") + for(var/obj/item/O in used_item.storage.get_contents()) + used_item.storage.remove_from_storage(user, O, src, TRUE) + used_item.storage.finish_bulk_removal() + update_icon() return - else if(istype(AM, /obj/item)) - attackby(AM, user) - return - else if(!is_type_in_list(AM, allowed_objects)) - return - // Checks completed, start inserting - src.add_fingerprint(user) - var/old_loc = AM.loc - if(AM == user) - user.visible_message("[user] starts climbing into [src].", \ - "You start climbing into [src].") - else - user.visible_message("[user] starts stuffing [AM] into [src].", \ - "You start stuffing [AM] into [src].") - - if(!do_after(user, 2 SECONDS, src)) + if(!user.try_unequip(used_item, src) || QDELETED(used_item)) return - // Repeat checks - if(stat & BROKEN || user.incapacitated(incapacitation_flags)) - return - if(!AM || old_loc != AM.loc || AM.anchored) - return - if(istype(M) && M.buckled) - return + user.visible_message("\The [user] places \the [used_item] into \the [src].", "You place \the [used_item] into \the [src].") - // Messages and logging - if(AM == user) - user.visible_message("[user] climbs into [src].", \ - "You climb into [src].") - log_and_message_admins("has stuffed themselves into [src].", AM) - else - user.visible_message("[user] stuffs [AM] into [src][is_dangerous ? "!" : "."]", \ - "You stuff [AM] into [src].") - if(ismob(M)) - admin_attack_log(user, M, "Placed the victim into \the [src].", "Was placed into \the [src] by the attacker.", "stuffed \the [src] with") - if (M.client) - M.client.perspective = EYE_PERSPECTIVE - M.client.eye = src - - AM.forceMove(src) update_icon() - return + +/obj/machinery/disposal/receive_mouse_drop(atom/dropping, mob/user, params) + + . = (!user?.check_intent(I_FLAG_HARM) && ..()) + + if(!. && !(stat & BROKEN)) + + if(isanimal(user) && dropping != user) + return TRUE + + var/incapacitation_flags = INCAPACITATION_DEFAULT + if(dropping == user) + incapacitation_flags &= ~INCAPACITATION_RESTRAINED + if(!dropping.can_mouse_drop(src, user, incapacitation_flags, params)) + return FALSE + + // Todo rewrite all of this. + var/atom/movable/AM = dropping + if(!istype(AM) || AM.anchored) + return FALSE + + // Determine object type and run necessary checks + var/mob/M = AM + var/is_dangerous // To determine css style in messages + if(istype(M)) + is_dangerous = TRUE + if(M.buckled) + return FALSE + else if(istype(AM, /obj/item)) + attackby(AM, user) + return FALSE + else if(!is_type_in_list(AM, allowed_objects)) + return FALSE + + // Checks completed, start inserting + src.add_fingerprint(user) + var/old_loc = AM.loc + if(AM == user) + user.visible_message("[user] starts climbing into [src].", \ + "You start climbing into [src].") + else + if(istype(M) && isliving(user)) + M.last_handled_by_mob = weakref(user) + user.visible_message("[user] starts stuffing [AM] into [src].", \ + "You start stuffing [AM] into [src].") + + if(!do_after(user, 2 SECONDS, src)) + return FALSE + + // Repeat checks + if((stat & BROKEN) || user.incapacitated()) + return FALSE + if(!AM || old_loc != AM.loc || AM.anchored) + return FALSE + if(istype(M) && M.buckled) + return FALSE + + // Messages and logging + if(AM == user) + user.visible_message("[user] climbs into [src].", \ + "You climb into [src].") + admin_attack_log(user, null, "Stuffed themselves into \the [src].", null, "stuffed themselves into \the [src].") + else + user.visible_message("[user] stuffs [AM] into [src][is_dangerous ? "!" : "."]", \ + "You stuff [AM] into [src].") + if(ismob(M)) + admin_attack_log(user, M, "Placed the victim into \the [src].", "Was placed into \the [src] by the attacker.", "stuffed \the [src] with") + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + + AM.forceMove(src) + update_icon() + return FALSE // attempt to move while inside /obj/machinery/disposal/relaymove(mob/user) @@ -201,7 +203,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) return /obj/machinery/disposal/DefaultTopicState() - return GLOB.outside_state + return global.outside_topic_state // human interact with machine /obj/machinery/disposal/physical_attack_hand(mob/user) @@ -209,6 +211,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) flush = !flush update_icon() return TRUE + return FALSE /obj/machinery/disposal/interface_interact(mob/user) interact(user) @@ -227,18 +230,18 @@ GLOBAL_LIST_EMPTY(diversion_junctions) if(!ai) // AI can't pull flush handle if(flush) - dat += "Disposal handle: Disengage Engaged" + dat += "Disposal handle: Disengage Engaged" else - dat += "Disposal handle: Disengaged Engage" + dat += "Disposal handle: Disengaged Engage" - dat += "

    Eject contents
    " + dat += "

    Eject contents
    " if(mode <= 0) - dat += "Pump: Off On
    " + dat += "Pump: Off On
    " else if(mode == 1) - dat += "Pump: Off On (pressurizing)
    " + dat += "Pump: Off On (pressurizing)
    " else - dat += "Pump: Off On (idle)
    " + dat += "Pump: Off On (idle)
    " var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE) @@ -258,7 +261,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) if(isAI(user) && (href_list["handle"] || href_list["eject"])) return min(STATUS_UPDATE, ..()) if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1 - to_chat(user, "The disposal units power is disabled.") + to_chat(user, "The disposal unit's power is disabled.") return min(STATUS_UPDATE, ..()) if(flushing) return min(STATUS_UPDATE, ..()) @@ -291,14 +294,14 @@ GLOBAL_LIST_EMPTY(diversion_junctions) // eject the contents of the disposal unit /obj/machinery/disposal/proc/eject() - for(var/atom/movable/AM in (contents - component_parts)) + for(var/atom/movable/AM in get_contained_external_atoms()) AM.forceMove(src.loc) AM.pipe_eject(0) update_icon() // update the icon & overlays to reflect mode & status /obj/machinery/disposal/on_update_icon() - overlays.Cut() + cut_overlays() if(stat & BROKEN) mode = 0 flush = 0 @@ -306,7 +309,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) // flush handle if(flush) - overlays += image('icons/obj/pipes/disposal.dmi', "dispover-handle") + add_overlay("[icon_state]-handle") // only handle is shown if no power if(stat & NOPOWER || mode == -1) @@ -314,13 +317,13 @@ GLOBAL_LIST_EMPTY(diversion_junctions) // check for items in disposal - occupied light if(contents.len > LAZYLEN(component_parts)) - overlays += image('icons/obj/pipes/disposal.dmi', "dispover-full") + add_overlay("[icon_state]-full") // charging and ready light if(mode == 1) - overlays += image('icons/obj/pipes/disposal.dmi', "dispover-charge") + add_overlay("[icon_state]-charge") else if(mode == 2) - overlays += image('icons/obj/pipes/disposal.dmi', "dispover-ready") + add_overlay("[icon_state]-ready") // timed process // charge the gas reservoir and perform flush if ready @@ -361,7 +364,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) var/power_draw = -1 if(env && env.temperature > 0) - var/transfer_moles = (PUMP_MAX_FLOW_RATE/env.volume)*env.total_moles //group_multiplier is divided out here + var/transfer_moles = (PUMP_MAX_FLOW_RATE/env.total_volume)*env.total_moles //group_multiplier is divided out here power_draw = pump_gas(src, env, air_contents, transfer_moles, active_power_usage) if (power_draw > 0) @@ -376,21 +379,17 @@ GLOBAL_LIST_EMPTY(diversion_junctions) var/wrapcheck = 0 var/obj/structure/disposalholder/H = new() // virtual holder object which actually // travels through the pipes. - var/list/stuff = contents - component_parts + var/list/stuff = get_contained_external_atoms() //Hacky test to get drones to mail themselves through disposals. for(var/mob/living/silicon/robot/drone/D in stuff) wrapcheck = 1 - for(var/obj/item/smallDelivery/O in stuff) + for(var/obj/item/parcel/O in stuff) wrapcheck = 1 if(wrapcheck == 1) H.tomail = 1 - for(var/mob/living/L in stuff) - if (L.ckey) - log_and_message_admins("has been flushed down [src].", L) - sleep(10) if(last_sound < world.time + 1) playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) @@ -401,6 +400,10 @@ GLOBAL_LIST_EMPTY(diversion_junctions) H.init(src, air_contents) // copy the contents of disposer to holder air_contents = new(PRESSURE_TANK_VOLUME) // new empty gas resv. + for(var/mob/M in H.check_mob(stuff)) + if(M.ckey) + admin_attack_log(null, M, null, "Was flushed down [src].", "has been flushed down [src].") + H.start(src) // start the holder processing movement flushing = 0 // now reset disposal state @@ -423,7 +426,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) AM.forceMove(src.loc) AM.pipe_eject(0) // Poor drones kept smashing windows and taking system damage being fired out of disposals. - if(!istype(AM,/mob/living/silicon/robot/drone)) + if(!isdrone(AM)) spawn(1) if(AM) AM.throw_at(target, 5, 1) @@ -433,14 +436,14 @@ GLOBAL_LIST_EMPTY(diversion_junctions) /obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if (istype(mover,/obj/item) && mover.throwing) - var/obj/item/I = mover - if(istype(I, /obj/item/projectile)) + var/obj/item/thing = mover + if(istype(thing, /obj/item/projectile)) return if(prob(75)) - I.forceMove(src) - visible_message("\The [I] lands in \the [src].") + thing.forceMove(src) + visible_message("\The [thing] lands in \the [src].") else - visible_message("\The [I] bounces off of \the [src]'s rim!") + visible_message("\The [thing] bounces off of \the [src]'s rim!") return 0 else return ..(mover, target, height, air_group) @@ -458,7 +461,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) . = ..(mapload) if(!id_tag) id_tag = newid - for(var/obj/structure/disposalpipe/diversion_junction/D in GLOB.diversion_junctions) + for(var/obj/structure/disposalpipe/diversion_junction/D in global.diversion_junctions) if(D.id_tag && !D.linked && D.id_tag == src.id_tag) junctions += D D.linked = src @@ -467,8 +470,8 @@ GLOBAL_LIST_EMPTY(diversion_junctions) junctions.Cut() return ..() -/obj/machinery/disposal_switch/attackby(obj/item/I, mob/user, params) - if(isCrowbar(I)) +/obj/machinery/disposal_switch/attackby(obj/item/used_item, mob/user, params) + if(IS_CROWBAR(used_item)) var/obj/item/disposal_switch_construct/C = new/obj/item/disposal_switch_construct(src.loc, id_tag) transfer_fingerprints_to(C) user.visible_message("\The [user] deattaches \the [src]") @@ -496,6 +499,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) icon = 'icons/obj/recycling.dmi' icon_state = "switch-off" w_class = ITEM_SIZE_LARGE + material = /decl/material/solid/metal/steel var/id_tag /obj/item/disposal_switch_construct/Initialize(var/id) @@ -505,15 +509,18 @@ GLOBAL_LIST_EMPTY(diversion_junctions) id_tag = "ds[sequential_id(/obj/item/disposal_switch_construct)]" /obj/item/disposal_switch_construct/afterattack(atom/A, mob/user, proximity) - if(!proximity || !istype(A, /turf/simulated/floor) || istype(A, /area/shuttle) || user.incapacitated() || !id_tag) + if(!proximity || !istype(A, /turf/floor) || user.incapacitated() || !id_tag) return + var/area/area = get_area(A) + if(!istype(area) || (area.area_flags & AREA_FLAG_SHUTTLE)) + return FALSE var/found = 0 - for(var/obj/structure/disposalpipe/diversion_junction/D in GLOB.diversion_junctions) + for(var/obj/structure/disposalpipe/diversion_junction/D in global.diversion_junctions) if(D.id_tag == src.id_tag) found = 1 break if(!found) - to_chat(user, "\icon[src]\The [src] is not linked to any junctions!") + to_chat(user, "[html_icon(src)]\The [src] is not linked to any junctions!") return var/obj/machinery/disposal_switch/NC = new/obj/machinery/disposal_switch(A, id_tag) transfer_fingerprints_to(NC) @@ -524,14 +531,13 @@ GLOBAL_LIST_EMPTY(diversion_junctions) /obj/structure/disposaloutlet name = "disposal outlet" desc = "An outlet for the pneumatic disposal system." - icon = 'icons/obj/pipes/disposal.dmi' + icon = 'icons/obj/pipes/disposal_outlet.dmi' icon_state = "outlet" - density = 1 - anchored = 1 - var/active = 0 + density = TRUE + anchored = TRUE var/turf/target // this will be where the output objects are 'thrown' to. var/mode = 0 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE + atom_flags = ATOM_FLAG_CLIMBABLE /obj/structure/disposaloutlet/Initialize() . = ..() @@ -550,7 +556,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) AM.forceMove(src.loc) AM.pipe_eject(dir) // Drones keep smashing windows from being fired out of chutes. - if(!istype(AM,/mob/living/silicon/robot/drone)) + if(!isdrone(AM)) spawn(5) AM.throw_at(target, 3, 1) H.vent_gas(src.loc) @@ -558,44 +564,50 @@ GLOBAL_LIST_EMPTY(diversion_junctions) /obj/structure/disposaloutlet/proc/animate_expel() set waitfor = FALSE - flick("outlet-open", src) + flick("[icon_state]-open", src) playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0) sleep(20) //wait until correct animation frame playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) -/obj/structure/disposaloutlet/attackby(var/obj/item/I, var/mob/user) - if(!I || !user) - return - src.add_fingerprint(user, 0, I) - if(isScrewdriver(I)) - if(mode==0) - mode=1 - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - to_chat(user, "You remove the screws around the power connection.") - return - else if(mode==1) - mode=0 - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - to_chat(user, "You attach the screws around the power connection.") - return - else if(istype(I,/obj/item/weldingtool) && mode==1) - var/obj/item/weldingtool/W = I - if(W.remove_fuel(0,user)) +/obj/structure/disposaloutlet/attackby(var/obj/item/used_item, var/mob/user) + src.add_fingerprint(user, 0, used_item) + if(IS_SCREWDRIVER(used_item)) + switch(mode) + if(0) + mode=1 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You remove the screws around the power connection.") + return TRUE + if(1) + mode=0 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You attach the screws around the power connection.") + return TRUE + else // This should be invalid? + return FALSE + else if(istype(used_item,/obj/item/weldingtool) && mode==1) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) to_chat(user, "You start slicing the floorweld off the disposal outlet.") - if(do_after(user,20, src)) - if(!src || !W.isOn()) return - to_chat(user, "You sliced the floorweld off the disposal outlet.") - var/obj/structure/disposalconstruct/machine/outlet/C = new (loc, src) - src.transfer_fingerprints_to(C) - C.anchored = 1 - C.set_density(1) - C.update() - qdel(src) - return + if(!do_after(user, 2 SECONDS, src)) + to_chat(user, "You must remain still to deconstruct \the [src].") + return TRUE + if(QDELETED(src) || !welder.isOn()) + return TRUE + to_chat(user, "You sliced the floorweld off the disposal outlet.") + var/obj/structure/disposalconstruct/machine/outlet/C = new (loc, src) + src.transfer_fingerprints_to(C) + C.anchored = TRUE + C.set_density(1) + C.update() + qdel(src) + return TRUE else to_chat(user, "You need more welding fuel to complete this task.") - return + return TRUE + else + return ..() /obj/structure/disposaloutlet/forceMove()//updates this when shuttle moves. So you can YEET things out the airlock . = ..() @@ -621,7 +633,7 @@ GLOBAL_LIST_EMPTY(diversion_junctions) if(direction) dirs = list( direction, turn(direction, -45), turn(direction, 45)) else - dirs = GLOB.alldirs.Copy() + dirs = global.alldirs.Copy() src.streak(dirs) @@ -630,6 +642,6 @@ GLOBAL_LIST_EMPTY(diversion_junctions) if(direction) dirs = list( direction, turn(direction, -45), turn(direction, 45)) else - dirs = GLOB.alldirs.Copy() + dirs = global.alldirs.Copy() - src.streak(dirs) \ No newline at end of file + src.streak(dirs) diff --git a/code/modules/recycling/disposalholder.dm b/code/modules/recycling/disposalholder.dm index 43982bc574cb..7a95d7d2ce28 100644 --- a/code/modules/recycling/disposalholder.dm +++ b/code/modules/recycling/disposalholder.dm @@ -5,11 +5,11 @@ // this allows the gas flushed to be tracked /obj/structure/disposalholder - invisibility = 101 + invisibility = INVISIBILITY_ABSTRACT var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point var/active = 0 // true if the holder is moving, otherwise inactive dir = 0 - var/count = 2048 //*** can travel 2048 steps before going inactive (in case of loops) + var/count = 4096 //*** can travel 4096 steps before going inactive (in case of loops) var/destinationTag = "" // changes if contains a delivery container var/tomail = 0 //changes if contains wrapped package var/hasmob = 0 //If it contains a mob @@ -17,49 +17,39 @@ var/partialTag = "" //set by a partial tagger the first time round, then put in destinationTag if it goes through again. - // initialize a holder from the contents of a disposal unit -/obj/structure/disposalholder/proc/init(var/obj/machinery/disposal/D, var/datum/gas_mixture/flush_gas) +/obj/structure/disposalholder/proc/init(var/obj/machinery/disposal/disposal_unit, var/datum/gas_mixture/flush_gas) gas = flush_gas// transfer gas resv. into holder object -- let's be explicit about the data this proc consumes, please. - var/stuff = D.contents - D.component_parts + var/stuff = disposal_unit.get_contained_external_atoms() //Check for any living mobs trigger hasmob. //hasmob effects whether the package goes to cargo or its tagged destination. - for(var/mob/living/M in stuff) - if(M && M.stat != 2 && !istype(M,/mob/living/silicon/robot/drone)) - hasmob = 1 - - //Checks 1 contents level deep. This means that players can be sent through disposals... - //...but it should require a second person to open the package. (i.e. person inside a wrapped locker) - for(var/obj/O in stuff) - if(O.contents) - for(var/mob/living/M in O.contents) - if(M && M.stat != 2 && !istype(M,/mob/living/silicon/robot/drone)) - hasmob = 1 + hasmob = length(check_mob(stuff)) // now everything inside the disposal gets put into the holder // note AM since can contain mobs or objs for(var/atom/movable/AM in stuff) AM.forceMove(src) - if(istype(AM, /obj/structure/bigDelivery) && !hasmob) - var/obj/structure/bigDelivery/T = AM - src.destinationTag = T.sortTag - if(istype(AM, /obj/item/smallDelivery) && !hasmob) - var/obj/item/smallDelivery/T = AM - src.destinationTag = T.sortTag - //Drones can mail themselves through maint. - if(is_drone(AM)) - var/mob/living/silicon/robot/drone/drone = AM - src.destinationTag = drone.mail_destination - + var/datum/extension/sorting_tag/ST = get_extension(AM, /datum/extension/sorting_tag) + if(ST) + destinationTag = ST.destination + +/obj/structure/disposalholder/proc/check_mob(list/stuff, max_depth = 1) + . = list() + if(max_depth > 0) + for(var/mob/living/victim in stuff) + if (!isdrone(victim)) + . += victim + for(var/obj/container in stuff) + . += check_mob(container.contents, max_depth - 1) // start the movement process // argument is the disposal unit the holder started in -/obj/structure/disposalholder/proc/start(var/obj/machinery/disposal/D) - if(!D.trunk) - D.expel(src) // no trunk connected, so expel immediately +/obj/structure/disposalholder/proc/start(var/obj/machinery/disposal/disposal_unit) + if(!disposal_unit.trunk) + disposal_unit.expel(src) // no trunk connected, so expel immediately return - forceMove(D.trunk) + forceMove(disposal_unit.trunk) active = 1 set_dir(DOWN) START_PROCESSING(SSdisposals, src) @@ -75,9 +65,8 @@ var/obj/structure/disposalpipe/last if(hasmob && prob(3)) - for(var/mob/living/H in src) - if(!istype(H,/mob/living/silicon/robot/drone)) //Drones use the mailing code to move through the disposal system, - H.apply_damage(30, BRUTE, null, DAM_DISPERSED, "Blunt Trauma", ARMOR_MELEE_MAJOR)//horribly maim any living creature jumping down disposals. c'est la vie + for(var/mob/living/victim in check_mob(src)) + victim.apply_damage(30, BRUTE, null, DAM_DISPERSED, "Blunt Trauma", ARMOR_MELEE_MAJOR)//horribly maim any living creature jumping down disposals. c'est la vie var/obj/structure/disposalpipe/curr = loc if(!istype(curr)) @@ -93,31 +82,31 @@ if(!curr) last.expel(src, loc, dir) - // find the turf which should contain the next pipe +/// find the turf which should contain the next pipe /obj/structure/disposalholder/proc/nextloc() return get_step(loc,dir) -// find a matching pipe on a turf -/obj/structure/disposalholder/proc/findpipe(var/turf/T) - if(!T) +/// find a matching pipe on a turf +/obj/structure/disposalholder/proc/findpipe(var/turf/containing_turf) + if(!containing_turf) return null var/fdir = turn(dir, 180) // flip the movement direction - for(var/obj/structure/disposalpipe/P in T) - if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir - return P + for(var/obj/structure/disposalpipe/pipe in containing_turf) + if(fdir & pipe.dpdir) // find pipe direction mask that matches flipped dir + return pipe // if no matching pipe, return null return null -// merge two holder objects -// used when a a holder meets a stuck holder +/// merge two holder objects +/// used when a holder meets a stuck holder /obj/structure/disposalholder/proc/merge(var/obj/structure/disposalholder/other) - for(var/atom/movable/AM in other) - AM.forceMove(src) // move everything in other holder to this one - if(ismob(AM)) - var/mob/M = AM - if(M.client) // if a client mob, update eye to follow this holder - M.client.eye = src + for(var/atom/movable/other_movable in other) + other_movable.forceMove(src) // move everything in other holder to this one + if(ismob(other_movable)) + var/mob/other_mob = other_movable + if(other_mob.client) // if a client mob, update eye to follow this holder + other_mob.client.eye = src qdel(other) /obj/structure/disposalholder/proc/settag(var/new_tag) @@ -130,23 +119,22 @@ else partialTag = new_tag -// called when player tries to move while in a pipe +/// called when player tries to move while in a pipe /obj/structure/disposalholder/relaymove(mob/user) - if(!istype(user,/mob/living)) + if(!isliving(user)) return - var/mob/living/U = user + var/mob/living/living_user = user - if (U.stat || U.last_special <= world.time) + if (living_user.stat || living_user.is_on_special_ability_cooldown()) return - U.last_special = world.time+100 - - if (src.loc) - for (var/mob/M in hearers(src.loc.loc)) - to_chat(M, "CLONG, clong!") + living_user.set_special_ability_cooldown(10 SECONDS) - playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0) + var/turf/our_turf = get_turf(src) + if (our_turf) + our_turf.audible_message("You hear a clanging noise.") + playsound(our_turf, 'sound/effects/clang.ogg', 50, 0, 0) // called to vent all gas in holder to a location /obj/structure/disposalholder/proc/vent_gas(var/atom/location) diff --git a/code/modules/recycling/disposalpipe.dm b/code/modules/recycling/disposalpipe.dm index 2f4daade0e26..afc2c082b152 100644 --- a/code/modules/recycling/disposalpipe.dm +++ b/code/modules/recycling/disposalpipe.dm @@ -1,16 +1,16 @@ // Disposal pipes /obj/structure/disposalpipe - icon = 'icons/obj/pipes/disposal.dmi' + icon = 'icons/obj/pipes/disposal_pipe.dmi' name = "disposal pipe" desc = "An underfloor disposal pipe." - anchored = 1 - density = 0 - maxhealth = 10 - level = 1 // underfloor only + anchored = TRUE + density = FALSE + max_health = 10 + level = LEVEL_BELOW_PLATING dir = 0 // dir will contain dominant direction for junction pipes alpha = 192 // Plane and alpha modified for mapping, reset to normal on spawn. - layer = DISPOSALS_PIPE_LAYER + layer = ABOVE_TILE_LAYER var/dpdir = 0 // bitmask of pipe directions var/base_icon_state // initial icon state on map var/sort_type = "" @@ -21,11 +21,13 @@ /obj/structure/disposalpipe/Initialize() . = ..() alpha = 255 + layer = DISPOSALS_PIPE_LAYER base_icon_state = icon_state + update_icon() // pipe is deleted // ensure if holder is present, it is expelled -obj/structure/disposalpipe/Destroy() +/obj/structure/disposalpipe/Destroy() var/obj/structure/disposalholder/H = locate() in src if(H) // holder was present @@ -80,9 +82,9 @@ obj/structure/disposalpipe/Destroy() // update the icon_state to reflect hidden status /obj/structure/disposalpipe/proc/update() - var/turf/T = src.loc - if(loc) - hide(!T.is_plating() && !istype(T,/turf/space)) // space never hides pipes + var/turf/T = loc + if(istype(T)) + hide(!T.is_plating() && !T.is_open()) // space never hides pipes // hide called by levelupdate if turf intact status changes // change visibility status and force update of icon @@ -113,14 +115,14 @@ obj/structure/disposalpipe/Destroy() return - if(!T.is_plating() && istype(T,/turf/simulated/floor)) //intact floor, pop the tile - var/turf/simulated/floor/F = T + if(!T.is_plating() && istype(T,/turf/floor)) //intact floor, pop the tile + var/turf/floor/F = T F.break_tile() new /obj/item/stack/tile(H) // add to holder so it will be thrown with other stuff var/turf/target if(direction) // direction is specified - if(istype(T, /turf/space)) // if ended in space, then range is unlimited + if(isspaceturf(T)) // if ended in space, then range is unlimited target = get_edge_target_turf(T, direction) else // otherwise limit to 10 tiles target = get_ranged_target_turf(T, direction, 10) @@ -157,12 +159,12 @@ obj/structure/disposalpipe/Destroy() // remains : set to leave broken pipe pieces in place /obj/structure/disposalpipe/proc/broken(var/remains = 0) if(remains) - for(var/D in GLOB.cardinal) + for(var/D in global.cardinal) if(D & dpdir) var/obj/structure/disposalpipe/broken/P = new(src.loc) P.set_dir(D) - src.set_invisibility(101) // make invisible (since we won't delete the pipe immediately) + src.set_invisibility(INVISIBILITY_ABSTRACT) // make invisible (since we won't delete the pipe immediately) var/obj/structure/disposalholder/H = locate() in src if(H) // holder was present @@ -182,8 +184,7 @@ obj/structure/disposalpipe/Destroy() if(H) expel(H, T, 0) - spawn(2) // delete pipe after 2 ticks to ensure expel proc finished - qdel(src) + QDEL_IN(src, 2) // delete pipe after 2 ticks to ensure expel proc finished // pipe affected by explosion @@ -194,75 +195,48 @@ obj/structure/disposalpipe/Destroy() else take_damage(rand(5,15)) +/obj/structure/disposalpipe/proc/can_deconstruct() + var/turf/T = get_turf(src) + return T.is_plating() // prevent interaction with T-scanner revealed pipes + //attack by item //weldingtool: unfasten and convert to obj/disposalconstruct -/obj/structure/disposalpipe/attackby(var/obj/item/I, var/mob/user) - - var/turf/T = src.loc - if(!T.is_plating()) - return // prevent interaction with T-scanner revealed pipes - src.add_fingerprint(user, 0, I) - if(istype(I, /obj/item/weldingtool)) - var/obj/item/weldingtool/W = I - if(W.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) - // check if anything changed over 2 seconds - var/turf/uloc = user.loc - var/atom/wloc = W.loc - to_chat(user, "Slicing the disposal pipe.") - sleep(30) - if(!W.isOn()) return - if(user.loc == uloc && wloc == W.loc) - welded() - else - to_chat(user, "You must stay still while welding the pipe.") - else - to_chat(user, "You need more welding fuel to cut the pipe.") - return +/obj/structure/disposalpipe/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/weldingtool)) + return ..() + if(!can_deconstruct()) + return TRUE + src.add_fingerprint(user, 0, used_item) + var/obj/item/weldingtool/welder = used_item + if(welder.weld(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You begin slicing \the [src].") + if(!do_after(user, 3 SECONDS, src)) + to_chat(user, "You must stay still while welding the pipe.") + return TRUE + if(!welder.isOn()) + return TRUE + welded() + return TRUE + to_chat(user, "You need more welding fuel to cut the pipe.") + return TRUE // called when pipe is cut with welder /obj/structure/disposalpipe/proc/welded() var/obj/structure/disposalconstruct/C = new (src.loc, src) src.transfer_fingerprints_to(C) C.set_density(0) - C.anchored = 1 + C.anchored = TRUE C.update() qdel(src) -// pipe is deleted -// ensure if holder is present, it is expelled -/obj/structure/disposalpipe/Destroy() - var/obj/structure/disposalholder/H = locate() in src - if(H) - // holder was present - H.active = 0 - var/turf/T = src.loc - if(T.density) - // deleting pipe is inside a dense turf (wall) - // this is unlikely, but just dump out everything into the turf in case - - for(var/atom/movable/AM in H) - AM.forceMove(T) - AM.pipe_eject(0) - qdel(H) - return ..() - - // otherwise, do normal expel from turf - if(H) - expel(H, T, 0) - . = ..() - /obj/structure/disposalpipe/hides_under_flooring() return 1 -// *** TEST verb -//client/verb/dispstop() -// for(var/obj/structure/disposalholder/H in world) -// H.active = 0 - // a straight or bent segment /obj/structure/disposalpipe/segment + desc = "A linear segment of disposal piping that simply moves things from one end to the other." icon_state = "pipe-s" // Sadly this var stores state. "pipe-c" is corner. Should be changed, but requires huge map diff. turn = DISPOSAL_FLIP_FLIP @@ -391,6 +365,7 @@ obj/structure/disposalpipe/Destroy() //a three-way junction with dir being the dominant direction /obj/structure/disposalpipe/junction + desc = "A three-way segment of disposal piping that merges two incoming directions into a third outgoing one." icon_state = "pipe-j1" turn = DISPOSAL_FLIP_RIGHT|DISPOSAL_FLIP_FLIP flipped_state = /obj/structure/disposalpipe/junction/mirrored @@ -440,6 +415,7 @@ obj/structure/disposalpipe/Destroy() /obj/structure/disposalpipe/tagger name = "package tagger" + desc = "A pipe that tags things passing through it with a sorting tag." icon_state = "pipe-tagger" var/sort_tag = "" var/partial = 0 @@ -459,24 +435,22 @@ obj/structure/disposalpipe/Destroy() /obj/structure/disposalpipe/tagger/Initialize() . = ..() dpdir = dir | turn(dir, 180) - if(sort_tag) GLOB.tagger_locations |= sort_tag + if(sort_tag) global.tagger_locations |= sort_tag updatename() updatedesc() update() -/obj/structure/disposalpipe/tagger/attackby(var/obj/item/I, var/mob/user) - if(..()) - return - - if(istype(I, /obj/item/destTagger)) - var/obj/item/destTagger/O = I - - if(O.currTag)// Tag set - sort_tag = O.currTag - playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) - to_chat(user, "Changed tag to '[sort_tag]'.") - updatename() - updatedesc() +/obj/structure/disposalpipe/tagger/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/destTagger)) + return ..() + var/obj/item/destTagger/tagger = used_item + if(tagger.current_tag)// Tag set + sort_tag = tagger.current_tag + playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) + to_chat(user, SPAN_NOTICE("Changed tag to '[sort_tag]'.")) + updatename() + updatedesc() + return TRUE /obj/structure/disposalpipe/tagger/transfer(var/obj/structure/disposalholder/H) if(sort_tag) @@ -488,6 +462,7 @@ obj/structure/disposalpipe/Destroy() /obj/structure/disposalpipe/tagger/partial //needs two passes to tag name = "partial package tagger" + desc = "A pipe that tags things passing through it with a sorting tag... but only the second time around." icon_state = "pipe-tagger-partial" partial = 1 turn = DISPOSAL_FLIP_FLIP @@ -509,7 +484,7 @@ obj/structure/disposalpipe/Destroy() /obj/structure/disposalpipe/diversion_junction/proc/updatedesc() desc = initial(desc) if(sort_type) - desc += "\nIt's currently [active ? "" : "un"]active!" + desc += "\nIt's currently [active ? "" : "in"]active!" /obj/structure/disposalpipe/diversion_junction/proc/updatedir() inactive_dir = dir @@ -523,7 +498,7 @@ obj/structure/disposalpipe/Destroy() /obj/structure/disposalpipe/diversion_junction/Initialize() . = ..() - GLOB.diversion_junctions += src + global.diversion_junctions += src updatedir() updatedesc() update() @@ -534,22 +509,21 @@ obj/structure/disposalpipe/Destroy() updatedesc() /obj/structure/disposalpipe/diversion_junction/Destroy() - GLOB.diversion_junctions -= src + global.diversion_junctions -= src if(linked) linked.junctions.Remove(src) linked = null return ..() -/obj/structure/disposalpipe/diversion_junction/attackby(var/obj/item/I, var/mob/user) - if(..()) - return 1 - - if(istype(I, /obj/item/disposal_switch_construct)) - var/obj/item/disposal_switch_construct/C = I - if(C.id_tag) - id_tag = C.id_tag - playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) - user.visible_message("\The [user] changes \the [src]'s tag.") +/obj/structure/disposalpipe/diversion_junction/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/disposal_switch_construct)) + return ..() + var/obj/item/disposal_switch_construct/switchcon = used_item + if(switchcon.id_tag) + id_tag = switchcon.id_tag + playsound(src.loc, 'sound/machines/twobeep.ogg', 100, TRUE) + user.visible_message("\The [user] changes \the [src]'s tag.") + return TRUE /obj/structure/disposalpipe/diversion_junction/nextdir(var/fromdir, var/sortTag) @@ -618,9 +592,21 @@ obj/structure/disposalpipe/Destroy() dpdir = sortdir | posdir | negdir -/obj/structure/disposalpipe/sortjunction/Initialize() +/obj/structure/disposalpipe/sortjunction/proc/validate_sort_type() + . = istext(sort_type) && sort_type != "" + if(!.) + if(name == initial(name)) + sort_type = "Unknown" + else + sort_type = name || "Unknown" + log_debug("Mapped untagged junction had empty sort_type, setting to '[sort_type]'.") + +/obj/structure/disposalpipe/sortjunction/Initialize(ml) . = ..() - if(sort_type) GLOB.tagger_locations |= sort_type + if(sort_type) + global.tagger_locations |= sort_type + if(ml && !validate_sort_type()) + log_warning("Mapped sorting junction of type [type] initializing at [x],[y],[z] with invalid sort_type '[sort_type || "EMPTY"]'!") updatedir() updatename() @@ -633,19 +619,17 @@ obj/structure/disposalpipe/Destroy() updatedesc() updatename() -/obj/structure/disposalpipe/sortjunction/attackby(var/obj/item/I, var/mob/user) - if(..()) - return - - if(istype(I, /obj/item/destTagger)) - var/obj/item/destTagger/O = I - - if(O.currTag)// Tag set - sort_type = O.currTag - playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1) - to_chat(user, "Changed filter to '[sort_type]'.") - updatename() - updatedesc() +/obj/structure/disposalpipe/sortjunction/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/destTagger)) + return ..() + var/obj/item/destTagger/tagger = used_item + if(tagger.current_tag)// Tag set + sort_type = tagger.current_tag + playsound(src.loc, 'sound/machines/twobeep.ogg', 100, TRUE) + to_chat(user, SPAN_NOTICE("Changed filter to '[sort_type]'.")) + updatename() + updatedesc() + return TRUE /obj/structure/disposalpipe/sortjunction/proc/divert_check(var/checkTag) return sort_type == checkTag @@ -690,6 +674,9 @@ obj/structure/disposalpipe/Destroy() desc = "An underfloor disposal pipe which filters all wrapped and tagged items." flipped_state = /obj/structure/disposalpipe/sortjunction/wildcard/flipped +/obj/structure/disposalpipe/sortjunction/wildcard/validate_sort_type() + return TRUE // Special case + /obj/structure/disposalpipe/sortjunction/wildcard/divert_check(var/checkTag) return checkTag != "" @@ -699,6 +686,12 @@ obj/structure/disposalpipe/Destroy() desc = "An underfloor disposal pipe which filters all untagged items." flipped_state = /obj/structure/disposalpipe/sortjunction/untagged/flipped +/obj/structure/disposalpipe/sortjunction/untagged/validate_sort_type() + . = (sort_type == "") + if(!.) + log_debug("Mapped untagged junction had non-empty sort_type, setting to empty string.") + sort_type = "" + /obj/structure/disposalpipe/sortjunction/untagged/divert_check(var/checkTag) return checkTag == "" @@ -719,6 +712,7 @@ obj/structure/disposalpipe/Destroy() //a trunk joining to a disposal bin or outlet on the same turf /obj/structure/disposalpipe/trunk + desc = "A section of pneumatic piping made to connect to a bin or outlet." icon_state = "pipe-t" var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet @@ -746,41 +740,22 @@ obj/structure/disposalpipe/Destroy() update() return - // Override attackby so we disallow trunkremoval when somethings ontop -/obj/structure/disposalpipe/trunk/attackby(var/obj/item/I, var/mob/user) - +// Override can_deconstruct so we disallow trunkremoval when something's on top +/obj/structure/disposalpipe/trunk/can_deconstruct() + . = ..() + var/turf/T = get_turf(src) //Disposal constructors - var/obj/structure/disposalconstruct/C = locate() in src.loc - if(C && C.anchored) - return - - var/turf/T = src.loc - if(!T.is_plating()) - return // prevent interaction with T-scanner revealed pipes - src.add_fingerprint(user, 0, I) - if(istype(I, /obj/item/weldingtool)) - var/obj/item/weldingtool/W = I - - if(W.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) - // check if anything changed over 2 seconds - var/turf/uloc = user.loc - var/atom/wloc = W.loc - to_chat(user, "Slicing the disposal pipe.") - sleep(30) - if(!W.isOn()) return - if(user.loc == uloc && wloc == W.loc) - welded() - else - to_chat(user, "You must stay still while welding the pipe.") - else - to_chat(user, "You need more welding fuel to cut the pipe.") - return - - // would transfer to next pipe segment, but we are in a trunk - // if not entering from disposal bin, - // transfer to linked object (outlet or bin) - + for(var/obj/structure/disposalconstruct/C in T) + if(C.anchored) + return FALSE + // Disposal machinery + for(var/obj/machinery/disposal/disposal in T) + if(disposal.anchored) + return FALSE + +// would transfer to next pipe segment, but we are in a trunk +// if not entering from disposal bin, +// transfer to linked object (outlet or bin) /obj/structure/disposalpipe/trunk/transfer(var/obj/structure/disposalholder/H) if(H.dir == DOWN) // we just entered from a disposer diff --git a/code/modules/recycling/package_wrapper.dm b/code/modules/recycling/package_wrapper.dm new file mode 100644 index 000000000000..ba8b75246be9 --- /dev/null +++ b/code/modules/recycling/package_wrapper.dm @@ -0,0 +1,192 @@ +//#TODO: Maybe get the surface area of something instead of using sizes since they're not very accurate +///Returns the amount of sheets of wrapping paper that the given object would need to be wrapped. +/atom/movable/proc/wrapping_paper_needed_to_wrap() + CRASH("Tried to get the amount of paper sheets needed to wrap invalid object type '[type]'.") + +/obj/wrapping_paper_needed_to_wrap() + return min(w_class, 8) //At most, since 20 sheets is a bit much for structures + +/mob/living/wrapping_paper_needed_to_wrap() + //Mob size is scaled weirdly, so we have to slap it through a switch + var/nb_sheets = 1 + switch(mob_size) + if(MOB_SIZE_LARGE) + nb_sheets = 15 + if(MOB_SIZE_MEDIUM) + nb_sheets = 10 + if(MOB_SIZE_SMALL) + nb_sheets = 5 + if(MOB_SIZE_TINY) + nb_sheets = 2 + return nb_sheets + +/////////////////////////////////////////////////////////////////////////////////////// +// Parcel Wrapper +/////////////////////////////////////////////////////////////////////////////////////// +/obj/item/stack/package_wrap + name = "package wrapper roll" + desc = "Heavy duty brown paper used to wrap packages to protect them during shipping." + icon = 'icons/obj/items/gift_wrapper.dmi' + icon_state = "deliveryPaper" + singular_name = "sheet" + w_class = ITEM_SIZE_NORMAL + max_amount = 50 + material = /decl/material/solid/organic/paper + throw_range = 5 + throw_speed = 3 + item_flags = ITEM_FLAG_NO_BLUDGEON + _base_attack_force = 1 + /// Check to prevent people from wrapping something multiple times at once. + var/tmp/currently_wrapping = FALSE + /// The type of wrapped item that will be produced + var/tmp/wrapped_result_type = /obj/item/parcel + +/obj/item/stack/package_wrap/twenty_five + amount = 25 +/obj/item/stack/package_wrap/fifty + amount = 50 + +/obj/item/stack/package_wrap/can_split() + return FALSE //Don't allow splitting the stacks, because it would create cardboard tubes out of nowhere + +/obj/item/stack/package_wrap/proc/can_wrap(var/atom/movable/AM) + return istype(AM) && AM.simulated && !AM.anchored && !is_type_in_list(AM, get_blacklist()) && (isobj(AM) || ishuman(AM)) + +///Attempts wrapping the given object. Returns the wrapper object containing the wrapped object. +/obj/item/stack/package_wrap/proc/wrap(var/atom/movable/AM, var/mob/user) + if(currently_wrapping && user) + return + if(AM == user) + to_chat(user, SPAN_WARNING("You cannot wrap yourself!")) + return + if(ishuman(AM)) + var/mob/living/human/H = AM + if(!H.incapacitated(INCAPACITATION_DISABLED | INCAPACITATION_RESTRAINED)) + if(user) + to_chat(user, SPAN_WARNING("\The [H] is moving around too much. Restrain or incapacitate them first.")) + return + + var/paper_to_use = AM.wrapping_paper_needed_to_wrap() + if(!can_use(paper_to_use)) + if(user) + to_chat(user, SPAN_WARNING("There isn't enough [plural_name] in \the [src] to wrap \the [AM]!")) + return + + currently_wrapping = TRUE + if(user && !user.do_skilled(clamp(paper_to_use, 2, 6) SECONDS, SKILL_HAULING, AM)) + currently_wrapping = FALSE + return + . = create_wrapper(AM, user) + if(.) + use(paper_to_use) + else if(user) + to_chat(user, SPAN_WARNING("You cannot wrap \the [AM]!")) + currently_wrapping = FALSE + +///Create the wrapper object and put the wrapped thing inside of it. +/obj/item/stack/package_wrap/proc/create_wrapper(var/atom/movable/target, var/mob/user) + if(isobj(target)) + var/obj/item/parcel/wrapper = new wrapped_result_type(get_turf(target)) + if(wrapper.make_parcel(target, user)) //Call this directly so it applies our fingerprints + . = wrapper + else + log_warning("Failed to create_wrapper() on \the '[target]'('[target.type]')([target.x], [target.y], [target.z]) with \the '[src]'('[type]')([x], [y], [z]).") + qdel(wrapper) + + else if(ishuman(target)) + var/mob/living/human/H = target + if(H.incapacitated(INCAPACITATION_DISABLED | INCAPACITATION_RESTRAINED)) + var/obj/item/parcel/wrapper = new wrapped_result_type(get_turf(target)) + if(wrapper.make_parcel(target, user)) //Call this directly so it applies our fingerprints + admin_attack_log(user, H, "Used \a [src] to wrap their victim", "Was wrapepd with \a [src]", "used \the [src] to wrap") + . = wrapper + else + log_warning("Failed to create_wrapper() on \the '[target]'('[target.type]')([target.x], [target.y], [target.z]) with \the '[src]'('[type]')([x], [y], [z]).") + qdel(wrapper) + + else if(user) + to_chat(user, SPAN_WARNING("\The [target] moving around too much. Restrain or incapacitate them first.")) + +/obj/item/stack/package_wrap/afterattack(var/obj/target, mob/user, proximity_flag, click_parameters) + if(!proximity_flag || !can_wrap(target) || (user.isEquipped(target) && !user.can_unequip_item(target))) + return + user.setClickCooldown(attack_cooldown) + return wrap(target, user) || ..() + +/obj/item/stack/package_wrap/on_used_last() + var/mob/M = loc + . = ..() + //Drop the cardboard tube after we're emptied out + var/obj/item/c_tube/tube = new(get_turf(M)) + if(istype(M)) + M.put_in_active_hand(tube) + +/obj/item/stack/package_wrap/create_matter() + . = ..() + //Cardboard for the tube, isn't in the matter_per_piece list, has to be added after that's been initialized + LAZYSET(matter, /decl/material/solid/organic/cardboard, MATTER_AMOUNT_PRIMARY * HOLLOW_OBJECT_MATTER_MULTIPLIER) + +/obj/item/stack/package_wrap/update_matter() + //Keep track of the cardboard amount to prevent it creating infinite cardboard matter each times the stack changes + var/cardboard_amount = LAZYACCESS(matter, /decl/material/solid/organic/cardboard) + matter = list() + for(var/mat in matter_per_piece) + matter[mat] = (matter_per_piece[mat] * amount) + matter[/decl/material/solid/organic/cardboard] = cardboard_amount + +///Types that the wrapper cannot wrap, ever +/obj/item/stack/package_wrap/proc/get_blacklist() + var/static/list/wrap_blacklist = list( + /obj/item/parcel, + /obj/item/parcel/gift, + /obj/item/evidencebag, + /obj/item/stack/package_wrap, + ) + return wrap_blacklist + +/////////////////////////////////////////////////////////////////////////////////////// +// Gift Wrapper +/////////////////////////////////////////////////////////////////////////////////////// +/** + * Variant of the wrapping paper that result in gift wrapped items. + */ +/obj/item/stack/package_wrap/gift + name = "gift wrapping paper roll" + desc = "You can use this to wrap items in." + icon_state = "wrap_paper" + wrapped_result_type = /obj/item/parcel/gift + +/obj/item/stack/package_wrap/gift/twenty_five + amount = 25 +/obj/item/stack/package_wrap/gift/fifty + amount = 50 + +/////////////////////////////////////////////////////////////////////////////////////// +// Borg Wrapping Paper Synthesizer +/////////////////////////////////////////////////////////////////////////////////////// +/obj/item/stack/package_wrap/cyborg + name = "package wrapper synthesizer" + gender = NEUTER + material = null + matter = null + uses_charge = TRUE + charge_costs = list(1) + stack_merge_type = /obj/item/stack/package_wrap + is_spawnable_type = FALSE + +/////////////////////////////////////////////////////////////////////////////////////// +// Cardboard Tube +/////////////////////////////////////////////////////////////////////////////////////// +/** + * Basically a trash item left from using paper rolls. + */ +/obj/item/c_tube + name = "cardboard tube" + desc = "A tube... of cardboard." + icon = 'icons/obj/items/gift_wrapper.dmi' + icon_state = "c_tube" + w_class = ITEM_SIZE_NORMAL + throw_speed = 4 + throw_range = 5 + material = /decl/material/solid/organic/cardboard + obj_flags = OBJ_FLAG_HOLLOW diff --git a/code/modules/recycling/sort_tag.dm b/code/modules/recycling/sort_tag.dm new file mode 100644 index 000000000000..6bc603ad1527 --- /dev/null +++ b/code/modules/recycling/sort_tag.dm @@ -0,0 +1,26 @@ +/** + * Sorting tag for the sorting machinery. + */ +/datum/extension/sorting_tag + base_type = /datum/extension/sorting_tag + expected_type = /atom/movable //Both mob and objects can have it + var/destination + var/tag_icon_state + var/tag_x = 0 + var/tag_y = 0 + +/datum/extension/sorting_tag/New(datum/holder, var/_destination, var/_icon_state, var/_tag_x = 0, var/_tag_y = 0) + ..(holder) + destination = _destination + tag_icon_state = _icon_state + tag_x = _tag_x + tag_y = _tag_y + +///Returns a human readable description of the destination tag. +/datum/extension/sorting_tag/proc/tag_description() + return "Its destination tag is: [destination]." + +///Applies the destination tag overlay on the holder. +/datum/extension/sorting_tag/proc/apply_tag_overlay() + var/atom/movable/H = holder + H.add_overlay(image('icons/obj/items/storage/deliverypackage.dmi', tag_icon_state, pixel_x = tag_x, pixel_y = tag_y)) \ No newline at end of file diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 3711d643fac3..23146a957fc4 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -1,400 +1,13 @@ -/obj/structure/bigDelivery - desc = "A big wrapped package." - name = "large parcel" - icon = 'icons/obj/items/storage/deliverypackage.dmi' - icon_state = "deliverycloset" - var/obj/wrapped = null - density = 1 - var/sortTag = null - mouse_drag_pointer = MOUSE_ACTIVE_POINTER - var/examtext = null - var/nameset = 0 - var/label_y - var/label_x - var/tag_x - -/obj/structure/bigDelivery/attack_robot(mob/user) - unwrap(user) - -/obj/structure/bigDelivery/attack_hand(mob/user) - unwrap(user) - -/obj/structure/bigDelivery/proc/unwrap(var/mob/user) - if(Adjacent(user)) - // Destroy will drop our wrapped object on the turf, so let it. - qdel(src) - -/obj/structure/bigDelivery/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/destTagger)) - var/obj/item/destTagger/O = W - if(O.currTag) - if(src.sortTag != O.currTag) - to_chat(user, "You have labeled the destination as [O.currTag].") - if(!src.sortTag) - src.sortTag = O.currTag - update_icon() - else - src.sortTag = O.currTag - playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) - else - to_chat(user, "The package is already labeled for [O.currTag].") - else - to_chat(user, "You need to set a destination first!") - - else if(istype(W, /obj/item/pen)) - switch(alert("What would you like to alter?",,"Title","Description", "Cancel")) - if("Title") - var/str = sanitizeSafe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN) - if(!str || !length(str)) - to_chat(usr, " Invalid text.") - return - user.visible_message("\The [user] titles \the [src] with \a [W], marking down: \"[str]\"",\ - "You title \the [src]: \"[str]\"",\ - "You hear someone scribbling a note.") - SetName("[name] ([str])") - if(!examtext && !nameset) - nameset = 1 - update_icon() - else - nameset = 1 - if("Description") - var/str = sanitize(input(usr,"Label text?","Set label","")) - if(!str || !length(str)) - to_chat(usr, "Invalid text.") - return - if(!examtext && !nameset) - examtext = str - update_icon() - else - examtext = str - user.visible_message("\The [user] labels \the [src] with \a [W], scribbling down: \"[examtext]\"",\ - "You label \the [src]: \"[examtext]\"",\ - "You hear someone scribbling a note.") - return - -/obj/structure/bigDelivery/on_update_icon() - overlays.Cut() - if(nameset || examtext) - var/image/I = new/image(icon,"delivery_label") - if(icon_state == "deliverycloset") - I.pixel_x = 2 - if(label_y == null) - label_y = rand(-6, 11) - I.pixel_y = label_y - else if(icon_state == "deliverycrate") - if(label_x == null) - label_x = rand(-8, 6) - I.pixel_x = label_x - I.pixel_y = -3 - overlays += I - if(src.sortTag) - var/image/I = new/image(icon,"delivery_tag") - if(icon_state == "deliverycloset") - if(tag_x == null) - tag_x = rand(-2, 3) - I.pixel_x = tag_x - I.pixel_y = 9 - else if(icon_state == "deliverycrate") - if(tag_x == null) - tag_x = rand(-8, 6) - I.pixel_x = tag_x - I.pixel_y = -3 - overlays += I - -/obj/structure/bigDelivery/examine(mob/user, distance) - . = ..() - if(distance <= 4) - if(sortTag) - to_chat(user, "It is labeled \"[sortTag]\"") - if(examtext) - to_chat(user, "It has a note attached which reads, \"[examtext]\"") - -/obj/structure/bigDelivery/Destroy() - if(wrapped) //sometimes items can disappear. For example, bombs. --rastaf0 - wrapped.dropInto(loc) - if(istype(wrapped, /obj/structure/closet)) - var/obj/structure/closet/O = wrapped - O.welded = 0 - wrapped = null - var/turf/T = get_turf(src) - for(var/atom/movable/AM in contents) - AM.forceMove(T) - return ..() - -/obj/item/smallDelivery - desc = "A small wrapped package." - name = "small parcel" - icon = 'icons/obj/items/storage/deliverypackage.dmi' - icon_state = "deliverycrate3" - var/obj/item/wrapped = null - var/sortTag = null - var/examtext = null - var/nameset = 0 - var/tag_x - -/obj/item/smallDelivery/proc/unwrap(var/mob/user) - if (!contents.len || !Adjacent(user)) - return - - user.put_in_hands(wrapped) - // Take out any other items that might be in the package - for(var/obj/item/I in src) - user.put_in_hands(I) - - qdel(src) - -/obj/item/smallDelivery/attack_robot(mob/user) - unwrap(user) - -/obj/item/smallDelivery/attack_self(mob/user) - unwrap(user) - -/obj/item/smallDelivery/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/destTagger)) - var/obj/item/destTagger/O = W - if(O.currTag) - if(src.sortTag != O.currTag) - to_chat(user, "You have labeled the destination as [O.currTag].") - if(!src.sortTag) - src.sortTag = O.currTag - update_icon() - else - src.sortTag = O.currTag - playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) - else - to_chat(user, "The package is already labeled for [O.currTag].") - else - to_chat(user, "You need to set a destination first!") - - else if(istype(W, /obj/item/pen)) - switch(alert("What would you like to alter?",,"Title","Description", "Cancel")) - if("Title") - var/str = sanitizeSafe(input(usr,"Label text?","Set label",""), MAX_NAME_LEN) - if(!str || !length(str)) - to_chat(usr, " Invalid text.") - return - user.visible_message("\The [user] titles \the [src] with \a [W], marking down: \"[str]\"",\ - "You title \the [src]: \"[str]\"",\ - "You hear someone scribbling a note.") - SetName("[name] ([str])") - if(!examtext && !nameset) - nameset = 1 - update_icon() - else - nameset = 1 - - if("Description") - var/str = sanitize(input(usr,"Label text?","Set label","")) - if(!str || !length(str)) - to_chat(usr, "Invalid text.") - return - if(!examtext && !nameset) - examtext = str - update_icon() - else - examtext = str - user.visible_message("\The [user] labels \the [src] with \a [W], scribbling down: \"[examtext]\"",\ - "You label \the [src]: \"[examtext]\"",\ - "You hear someone scribbling a note.") - return - -/obj/item/smallDelivery/on_update_icon() - overlays.Cut() - if((nameset || examtext) && icon_state != "deliverycrate1") - var/image/I = new/image(icon,"delivery_label") - if(icon_state == "deliverycrate5") - I.pixel_y = -1 - overlays += I - if(src.sortTag) - var/image/I = new/image(icon,"delivery_tag") - switch(icon_state) - if("deliverycrate1") - I.pixel_y = -5 - if("deliverycrate2") - I.pixel_y = -2 - if("deliverycrate3") - I.pixel_y = 0 - if("deliverycrate4") - if(tag_x == null) - tag_x = rand(0,5) - I.pixel_x = tag_x - I.pixel_y = 3 - if("deliverycrate5") - I.pixel_y = -3 - overlays += I - -/obj/item/smallDelivery/examine(mob/user, distance) - . = ..() - if(distance <= 4) - if(sortTag) - to_chat(user, "It is labeled \"[sortTag]\"") - if(examtext) - to_chat(user, "It has a note attached which reads, \"[examtext]\"") - -/obj/item/stack/package_wrap - name = "package wrapper" - desc = "Heavy duty brown paper used to wrap packages to protect them during shipping." - singular_name = "sheet" - max_amount = 25 - icon = 'icons/obj/items/gift_wrapper.dmi' - icon_state = "deliveryPaper" - w_class = ITEM_SIZE_NORMAL - -/obj/item/stack/package_wrap/twenty_five - amount = 25 - - -/obj/item/c_tube - name = "cardboard tube" - desc = "A tube... of cardboard." - icon = 'icons/obj/items/gift_wrapper.dmi' - icon_state = "c_tube" - throwforce = 1 - w_class = ITEM_SIZE_SMALL - throw_speed = 4 - throw_range = 5 - -/obj/item/stack/package_wrap/afterattack(var/obj/target, mob/user, proximity) - if(!proximity) return - if(!istype(target)) //this really shouldn't be necessary (but it is). -Pete - return - if(istype(target, /obj/item/smallDelivery) || istype(target,/obj/structure/bigDelivery) \ - || istype(target, /obj/item/gift) || istype(target, /obj/item/evidencebag)) - return - if(target.anchored) - return - if(target in user) - return - if(user in target) //no wrapping closets that you are inside - it's not physically possible - return - - if (istype(target, /obj/item) && !(istype(target, /obj/item/storage) && !istype(target,/obj/item/storage/box))) - var/obj/item/O = target - if (src.get_amount() >= 1) - var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(O.loc)) //Aaannd wrap it up! - if(!istype(O.loc, /turf)) - if(user.client) - user.client.screen -= O - P.wrapped = O - O.forceMove(P) - P.w_class = O.w_class - var/i = round(O.w_class) - if(i in list(1,2,3,4,5)) - P.icon_state = "deliverycrate[i]" - switch(i) - if(1) P.SetName("tiny parcel") - if(3) P.SetName("normal-sized parcel") - if(4) P.SetName("large parcel") - if(5) P.SetName("huge parcel") - if(i < 1) - P.icon_state = "deliverycrate1" - P.SetName("tiny parcel") - if(i > 5) - P.icon_state = "deliverycrate5" - P.SetName("huge parcel") - P.add_fingerprint(usr) - O.add_fingerprint(usr) - src.add_fingerprint(usr) - src.use(1) - user.visible_message("\The [user] wraps \a [target] with \a [src].",\ - "You wrap \the [target], leaving [src.get_amount()] units of paper on \the [src].",\ - "You hear someone taping paper around a small object.") - else - // Should be possible only to see this as a borg? - to_chat(user, "The synthesizer is out of paper.") - else if (istype(target, /obj/structure/closet/crate)) - var/obj/structure/closet/crate/O = target - if (src.get_amount() >= 3 && !O.opened) - var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc)) - P.icon_state = "deliverycrate" - P.wrapped = O - O.forceMove(P) - src.use(3) - user.visible_message("\The [user] wraps \a [target] with \a [src].",\ - "You wrap \the [target], leaving [src.get_amount()] units of paper on \the [src].",\ - "You hear someone taping paper around a large object.") - else if(src.get_amount() < 3) - to_chat(user, "You need more paper.") - else if (istype (target, /obj/structure/closet)) - var/obj/structure/closet/O = target - if (src.get_amount() >= 3 && !O.opened) - var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc)) - P.wrapped = O - O.welded = 1 - O.forceMove(P) - src.use(3) - user.visible_message("\The [user] wraps \a [target] with \a [src].",\ - "You wrap \the [target], leaving [src.get_amount()] units of paper on \the [src].",\ - "You hear someone taping paper around a large object.") - else if(src.get_amount() < 3) - to_chat(user, "You need more paper.") - else - to_chat(user, "The object you are trying to wrap is unsuitable for the sorting machinery!") - - return - -/obj/item/destTagger - name = "destination tagger" - desc = "Used to set the destination of properly wrapped packages." - icon = 'icons/obj/items/device/destination_tagger.dmi' - icon_state = "dest_tagger" - var/currTag = 0 - w_class = ITEM_SIZE_SMALL - item_state = "electronic" - obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT - material = /decl/material/solid/metal/steel - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) - -/obj/item/destTagger/proc/openwindow(mob/user) - var/dat = "

    TagMaster 2.3

    " - - dat += "" - for(var/i = 1, i <= GLOB.tagger_locations.len, i++) - dat += "" - - if (i%4==0) - dat += "" - - dat += "
    [GLOB.tagger_locations[i]]

    Current Selection: [currTag ? currTag : "None"]
    " - dat += "
    Enter custom location." - show_browser(user, dat, "window=destTagScreen;size=450x375") - onclose(user, "destTagScreen") - -/obj/item/destTagger/attack_self(mob/user) - openwindow(user) - -/obj/item/destTagger/OnTopic(user, href_list, state) - if(href_list["nextTag"] && (href_list["nextTag"] in GLOB.tagger_locations)) - src.currTag = href_list["nextTag"] - to_chat(user, "You set [src] to [src.currTag].") - playsound(src.loc, 'sound/machines/chime.ogg', 50, 1) - . = TOPIC_REFRESH - if(href_list["nextTag"] == "CUSTOM") - var/dest = input(user, "Please enter custom location.", "Location", src.currTag ? src.currTag : "None") - if(CanUseTopic(user, state)) - if(dest && lowertext(dest) != "none") - src.currTag = dest - to_chat(user, "You designate a custom location on [src], set to [src.currTag].") - playsound(src.loc, 'sound/machines/chime.ogg', 50, 1) - else - src.currTag = 0 - to_chat(user, "You clear [src]'s custom location.") - playsound(src.loc, 'sound/machines/chime.ogg', 50, 1) - . = TOPIC_REFRESH - else - . = TOPIC_HANDLED - - if(. == TOPIC_REFRESH) - openwindow(user) - /obj/machinery/disposal/deliveryChute - name = "Delivery chute" - desc = "A chute for big and small packages alike!" - density = 1 - icon_state = "intake" + name = "delivery chute" + desc = "A chute to put things into a disposal network. Takes big and small packages alike!" + density = TRUE + icon = 'icons/obj/pipes/disposal_chute.dmi' + icon_state = "chute" base_type = /obj/machinery/disposal/deliveryChute/buildable frame_type = /obj/structure/disposalconstruct/machine/chute + // TODO: Convert attackby() override and c_mode vars to use construct states + construct_state = null var/c_mode = 0 @@ -413,17 +26,16 @@ /obj/machinery/disposal/deliveryChute/on_update_icon() return +/obj/machinery/disposal/deliveryChute/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + . = (get_dir(src, mover) != dir) && ..() + /obj/machinery/disposal/deliveryChute/Bumped(var/atom/movable/AM) //Go straight into the chute - if(istype(AM, /obj/item/projectile) || istype(AM, /obj/effect)) return - switch(dir) - if(NORTH) - if(AM.loc.y != src.loc.y+1) return - if(EAST) - if(AM.loc.x != src.loc.x+1) return - if(SOUTH) - if(AM.loc.y != src.loc.y-1) return - if(WEST) - if(AM.loc.x != src.loc.x-1) return + + if(istype(AM, /obj/item/projectile) || istype(AM, /obj/effect)) + return + + if(get_dir(src, AM) != dir) + return var/mob/living/L = AM if (istype(L) && L.ckey) @@ -431,14 +43,14 @@ if(istype(AM, /obj)) var/obj/O = AM O.forceMove(src) - else if(istype(AM, /mob)) + else if(ismob(AM)) var/mob/M = AM M.forceMove(src) src.flush() /obj/machinery/disposal/deliveryChute/flush() flushing = 1 - flick("intake-closing", src) + flick("[icon_state]-closing", src) var/obj/structure/disposalholder/H = new() // virtual holder object which actually // travels through the pipes. air_contents = new() // new empty gas resv. @@ -448,14 +60,14 @@ sleep(5) // wait for animation to finish if(prob(35)) - for(var/mob/living/carbon/human/L in src) + for(var/mob/living/human/L in src) var/list/obj/item/organ/external/crush = L.get_damageable_organs() if(!crush.len) return var/obj/item/organ/external/E = pick(crush) - E.take_external_damage(45, used_weapon = "Blunt Trauma") + E.take_damage(45, inflicter = "Blunt Trauma") to_chat(L, "\The [src]'s mechanisms crush your [E.name]!") H.init(src) // copy the contents of disposer to holder @@ -469,48 +81,36 @@ update_icon() return -/obj/machinery/disposal/deliveryChute/attackby(var/obj/item/I, var/mob/user) - if(!I || !user) - return - - if(isScrewdriver(I)) +/obj/machinery/disposal/deliveryChute/attackby(var/obj/item/used_item, var/mob/user) + if(IS_SCREWDRIVER(used_item)) if(c_mode==0) c_mode=1 - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, TRUE) to_chat(user, "You remove the screws around the power connection.") - return + return TRUE else if(c_mode==1) c_mode=0 - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, TRUE) to_chat(user, "You attach the screws around the power connection.") - return - else if(isWelder(I) && c_mode==1) - var/obj/item/weldingtool/W = I - if(W.remove_fuel(1,user)) - to_chat(user, "You start slicing the floorweld off the delivery chute.") - if(do_after(user,20, src)) - playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) - if(!src || !W.isOn()) return - to_chat(user, "You sliced the floorweld off the delivery chute.") - var/obj/structure/disposalconstruct/C = new (loc, src) - C.update() - qdel(src) - return - else - to_chat(user, "You need more welding fuel to complete this task.") - return + return TRUE + else if(IS_WELDER(used_item) && c_mode==1) + var/obj/item/weldingtool/welder = used_item + if(!welder.weld(1,user)) // 'you need more welding fuel' messages are already handled + return TRUE + to_chat(user, "You start slicing the floorweld off the delivery chute.") + if(!do_after(user, 2 SECONDS, src)) + to_chat(user, "You stop slicing the floorweld off the delivery chute.") + return TRUE + playsound(src.loc, 'sound/items/Welder2.ogg', 100, TRUE) + if(!src || !welder.isOn()) return TRUE + to_chat(user, "You slice the floorweld off the delivery chute.") + var/obj/structure/disposalconstruct/C = new (loc, src) + C.update() + qdel(src) + return TRUE + return ..() /obj/machinery/disposal/deliveryChute/Destroy() if(trunk) trunk.linked = null - ..() - -/obj/item/stack/package_wrap/cyborg - name = "package wrapper synthesizer" - icon = 'icons/obj/items/gift_wrapper.dmi' - icon_state = "deliveryPaper" - gender = NEUTER - matter = null - uses_charge = 1 - charge_costs = list(1) - stacktype = /obj/item/stack/package_wrap \ No newline at end of file + return ..() diff --git a/code/modules/recycling/wrapped_package.dm b/code/modules/recycling/wrapped_package.dm new file mode 100644 index 000000000000..65d8fcd62610 --- /dev/null +++ b/code/modules/recycling/wrapped_package.dm @@ -0,0 +1,287 @@ +///////////////////////////////////////////////////////////////////// +// Parcel +///////////////////////////////////////////////////////////////////// + +/** + * A parcel wrapper for items and structures that can be wrapped in wrapping paper. + */ +/obj/item/parcel + name = "parcel" + desc = "A wrapped package." + icon = 'icons/obj/items/storage/deliverypackage.dmi' + icon_state = "parcel" + obj_flags = OBJ_FLAG_HOLLOW + material = /decl/material/solid/organic/paper + attack_verb = list("delivered a hit", "expedited on", "shipped at", "went postal on") + base_parry_chance = 40 //Boxes tend to be good at parrying + ///A text note attached to the parcel that shows on examine + var/attached_note + ///The first part of the icon_state names + var/tmp/icon_state_prefix = "parcel" + ///Color of the dropped paper trash on unwrapping. + var/tmp/trash_color = "#b97644" + +/obj/item/parcel/Initialize(ml, material_key, var/atom/movable/contained_object = null, var/_attached_note = null) + . = ..(ml, material_key) + + if(contained_object && !make_parcel(contained_object)) + log_warning("[src] ([x], [y], [z]) failed to set its package content. Deleting!") + return INITIALIZE_HINT_QDEL + + if(length(_attached_note)) + attached_note = _attached_note + + update_icon() + +/obj/item/parcel/on_update_icon() + . = ..() + if(w_class < ITEM_SIZE_STRUCTURE) + icon_state = "[icon_state_prefix]_[clamp(round(w_class), ITEM_SIZE_MIN, ITEM_SIZE_HUGE)]" + else + //If it's none of the smaller items, default to crate-sized package + icon_state = "[icon_state_prefix]_crate" + //Try to see if we got a better icon state for whatever we contain + if(length(contents)) + if(istype(contents?[1], /obj/structure/closet) && !istype(contents?[1], /obj/structure/closet/crate)) + icon_state = "[icon_state_prefix]_closet" + else if(ishuman(contents?[1])) + icon_state = "[icon_state_prefix]_human" + + //Apply the sorting tag icon on top of our sprite. The extension does it for us. + var/datum/extension/sorting_tag/S = get_extension(src, /datum/extension/sorting_tag) + if(S) + S.apply_tag_overlay() + + //Put a label on if we added a note + if(length(attached_note) && icon_state != "[icon_state_prefix]_1") + var/off_x = 0 + var/off_y = 0 + if(icon_state == "[icon_state_prefix]_5") + off_y = -1 + else if(icon_state == "[icon_state_prefix]_crate") + off_x = rand(-8, 6) + off_y = -3 + else if(icon_state == "[icon_state_prefix]_closet") + off_x = 2 + off_y = rand(-6, 11) + else if(icon_state == "[icon_state_prefix]_human") + off_x = rand(-3, 3) + off_y = rand(-6, 11) + + //Keep the full icon path, since subclasses may not have the label in their icon file + var/image/I = image('icons/obj/items/storage/deliverypackage.dmi', "delivery_label", pixel_x = off_x, pixel_y = off_y) + add_overlay(I) + +/obj/item/parcel/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance < 3) + var/datum/extension/sorting_tag/S = get_extension(src, /datum/extension/sorting_tag) + if(S) + . += S.tag_description() + if(length(attached_note)) + . += "It has a note attached, which reads:'[attached_note]'." + +/obj/item/parcel/get_mechanics_info() + . = ..() + . += "
    It can be opened by applying any sharp item, with help intent." + . += "
    It can opened by using it while held, if its small enough." + +/obj/item/parcel/proc/make_parcel(var/atom/movable/AM, var/mob/user) + if(!is_type_in_list(AM, get_whitelist())) + log_warning("[src] ([x], [y], [z]) was passed an invalid atom type to contain[istype(AM, /datum)? " '[AM.type]'" : ", value: [AM]"].") + return + var/parcel_name + var/parcel_size + var/obj/O = AM + + if(istype(O)) + parcel_size = round(O.w_class) + else if(ismob(AM)) + var/mob/M = AM + //#FIXME: These will almost 100% be badly named for their size. Since according to scale crab, cat and corgis are bigger than gargantuan for example. + parcel_size = round(M.mob_size) + else + CRASH("Make parcel got passed an invalid atom type '[AM?.type]'.") + + //Name the parcel based on its size + switch(parcel_size) + if(ITEM_SIZE_TINY) + parcel_name = "tiny [initial(name)]" + if(ITEM_SIZE_SMALL) + parcel_name = "small [initial(name)]" + if(ITEM_SIZE_NORMAL) + parcel_name = "normal-sized [initial(name)]" + if(ITEM_SIZE_LARGE) + parcel_name = "large [initial(name)]" + if(ITEM_SIZE_HUGE, ITEM_SIZE_GARGANTUAN) + parcel_name = "huge [initial(name)]" + else + parcel_name = "enormous [initial(name)]" + + SetName(parcel_name) + w_class = parcel_size + density = AM.density + opacity = AM.opacity + + if(AM.atom_flags & ATOM_FLAG_CLIMBABLE) + atom_flags |= ATOM_FLAG_CLIMBABLE + else + atom_flags &= ~ATOM_FLAG_CLIMBABLE + + if(user) + add_fingerprint(user) + AM.add_fingerprint(user) + + //Notify properly whatever we're taking the thing from + //And then put it in the user's hands if it makes sense + if(ismob(AM.loc)) + var/mob/M = AM.loc + if(!M.try_unequip(AM, src)) + CRASH("Tried to make a parcel from an item in a mob's inventory that cannot be unequipped. Should have been filtered out before. [log_info_line(src)]") + if(M == user) + user.put_in_hands(src) + + if(AM.loc?.storage) + AM.loc.storage.remove_from_storage(user, AM, src) + AM.loc.storage.handle_item_insertion(null, src, TRUE) + else + AM.forceMove(src) + + //Make sure we contain exactly the amount of paper sheets used to wrap ourselves + LAZYSET(matter, material.type, (AM.wrapping_paper_needed_to_wrap() * SHEET_MATERIAL_AMOUNT)) + update_icon() + update_held_icon() + return TRUE + +/obj/item/parcel/proc/unwrap(var/mob/user) + visible_message(SPAN_NOTICE("\The [user] starts tearing the wrapping off \the [src]."), SPAN_NOTICE("You start tearing the wrapping off \the [src].")) + //I guess cargo techs would definitely be faster at opening packages. + if(user.do_skilled(3 SECONDS, SKILL_HAULING, src)) + visible_message(SPAN_NOTICE("\The [user] unwrapped \the [src]!"), SPAN_NOTICE("You unwrapped \the [src]!")) + if(!length(contents)) + to_chat(user, SPAN_WARNING("\The [src] was empty!")) + playsound(src, 'sound/items/poster_ripped.ogg', 50, TRUE) + physically_destroyed() + return TRUE + return FALSE + +/obj/item/parcel/attack_robot(mob/user) + unwrap(user) + +/obj/item/parcel/attack_self(mob/user) + unwrap(user) + +/obj/item/parcel/attack_hand(mob/user) + if(w_class >= ITEM_SIZE_STRUCTURE) + return TRUE + return ..() + +/obj/item/parcel/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/destTagger)) + user.setClickCooldown(attack_cooldown) + var/obj/item/destTagger/O = used_item + if(length(O.current_tag)) + to_chat(user, SPAN_NOTICE("You have labeled the destination as '[O.current_tag]'.")) + attach_destination_tag(O, user) + else + to_chat(user, SPAN_WARNING("You need to set a destination tag first!")) + return TRUE + + else if(IS_PEN(used_item)) + var/old_note = attached_note + var/new_note = sanitize(input(user, "What note would you like to add to \the [src]?", "Add Note", attached_note)) + if((new_note != old_note) && user.Adjacent(src) && used_item.do_tool_interaction(TOOL_PEN, user, src, 2 SECONDS) && user.Adjacent(src)) + attached_note = new_note + update_icon() + return TRUE + + else if(used_item.is_sharp() && user.check_intent(I_FLAG_HELP)) + //You can alternative cut the wrapper off with a sharp item + unwrap(user) + return TRUE + + return ..() + +///Attach a destination tag for the sorting machine to route the parcel to its destination. +//#TODO: Eventually should probably be moved somewhere more sensible within the sorting_tag extension? +/obj/item/parcel/proc/attach_destination_tag(var/obj/item/destTagger/T, var/mob/user) + var/off_x = 0 + var/off_y = 0 + if(icon_state == "[icon_state_prefix]_1") + off_y = -5 + else if(icon_state == "[icon_state_prefix]_2") + off_y = -2 + else if(icon_state == "[icon_state_prefix]_4") + off_x = rand(0,5) + off_y = 3 + else if(icon_state == "[icon_state_prefix]_5") + off_y = -3 + else if(icon_state == "[icon_state_prefix]_closet") + off_x = rand(-2, 3) + off_y = 9 + else if(icon_state == "[icon_state_prefix]_crate") + off_x = rand(-8, 6) + off_y = -3 + else if(icon_state == "[icon_state_prefix]_human") + off_x = rand(-2, 2) + off_y = 10 + + //Update or create the tag extension + var/datum/extension/sorting_tag/S = get_or_create_extension(src, /datum/extension/sorting_tag) + S.destination = T.current_tag + S.tag_icon_state = "delivery_tag" + S.tag_x = off_x + S.tag_y = off_y + update_icon() + playsound(src, 'sound/effects/checkout.ogg', 40, TRUE, 2) + +/obj/item/parcel/physically_destroyed(skip_qdel) + if(istype(material) && LAZYACCESS(matter, material.type)) + var/list/cuttings = material.place_cuttings(get_turf(src), matter[material.type]) + //Make the bits of paper the right color + for(var/obj/item/C in cuttings) + C.material_alteration &= ~(MAT_FLAG_ALTERATION_COLOR) //Prevents the update_icon code from recoloring this white + C.set_color(trash_color) + . = ..() + +/obj/item/parcel/dump_contents(atom/forced_loc = loc, mob/user) + for(var/thing in get_contained_external_atoms()) + var/atom/movable/AM = thing + + //If the parcel is broken in someone's hands or bag, make sure its not just dumped on the ground. + if(ismob(loc)) + var/mob/M = loc + M.put_in_hands(AM) + else + if(forced_loc?.storage) + forced_loc.storage.handle_item_insertion(null, AM, TRUE) + else + AM.dropInto(forced_loc) + + if(ismob(AM)) + var/mob/M = AM + M.reset_view() + +///list of atom types that can be wrapped. Includes subtypes of the specified types. +/obj/item/parcel/proc/get_whitelist() + var/static/list/type_whitelist = list( + /obj/item, + /obj/structure, + /obj/machinery, + /mob/living/human, + ) + return type_whitelist + +///////////////////////////////////////////////////////////////////// +// Gift +///////////////////////////////////////////////////////////////////// +/obj/item/parcel/gift + name = "gift" + desc = "A carefully wrapped box. How thoughtful!" + icon = 'icons/obj/items/gift_wrapped.dmi' + icon_state = "gift" + item_state = "gift" + icon_state_prefix = "gift" + w_class = ITEM_SIZE_NORMAL + attack_verb = list("surprised", "gifted", "spoiled", "expressed their grattitude towards") + trash_color = "#009900" diff --git a/code/modules/research/_design.dm b/code/modules/research/_design.dm index 00d9999bb7ad..072f4004019c 100644 --- a/code/modules/research/_design.dm +++ b/code/modules/research/_design.dm @@ -3,4 +3,4 @@ #define SYNC_PUSH_DISK 4 #define SYNC_PULL_DISK 8 -var/list/design_databases = list() +var/global/list/design_databases = list() diff --git a/code/modules/research/design_console.dm b/code/modules/research/design_console.dm index c26951fec905..10af9ac6bc97 100644 --- a/code/modules/research/design_console.dm +++ b/code/modules/research/design_console.dm @@ -1,45 +1,52 @@ /obj/machinery/computer/design_console name = "design database console" desc = "A console for interfacing with a research and development design network." + maximum_component_parts = list( + /obj/item/stock_parts/item_holder/disk_reader = 1, + /obj/item/stock_parts = 15, + ) + /// A cached reference to our disk reader part, if present. + var/obj/item/stock_parts/item_holder/disk_reader/disk_reader var/initial_network_id var/initial_network_key var/list/local_cache - var/obj/item/disk/design_disk/disk var/obj/machinery/design_database/viewing_database var/showing_designs = FALSE /obj/machinery/computer/design_console/Initialize() . = ..() - set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, NETWORK_CONNECTION_WIRED) - -/obj/machinery/computer/design_console/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/disk/design_disk)) - if(disk) - to_chat(user, SPAN_WARNING("\The [src] already has a disk inserted.")) - return - if(user.unEquip(I, src)) - visible_message("\The [user] slots \the [I] into \the [src].") - disk = I - return + set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, RECEIVER_STRONG_WIRELESS) + +/obj/machinery/computer/design_console/Destroy() + viewing_database = null + disk_reader = null + return ..() + +/obj/machinery/computer/design_console/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) + +/obj/machinery/computer/design_console/RefreshParts() . = ..() + disk_reader = get_component_of_type(/obj/item/stock_parts/item_holder/disk_reader) + if(disk_reader) + disk_reader.register_on_insert(CALLBACK(src, PROC_REF(update_ui))) + disk_reader.register_on_eject(CALLBACK(src, PROC_REF(update_ui))) + +/obj/machinery/computer/design_console/proc/try_get_disk() + return disk_reader?.get_inserted() + +/obj/machinery/computer/design_console/proc/update_ui() + SSnano.update_uis(src) + +/obj/machinery/computer/design_console/handle_post_network_connection() + ..() + sync_network() /obj/machinery/computer/design_console/proc/eject_disk(var/mob/user) - if(disk) - disk.dropInto(loc) - if(user) - if(!issilicon(user)) - user.put_in_hands(disk) - if(Adjacent(user, src)) - visible_message(SPAN_NOTICE("\The [user] removes \the [disk] from \the [src].")) - disk = null - return TRUE - return FALSE - -/obj/machinery/computer/design_console/AltClick(mob/user) - if(disk) - eject_disk() - . = ..() + return !!disk_reader.eject_item(user) /obj/machinery/computer/design_console/interface_interact(mob/user) ui_interact(user) @@ -52,9 +59,13 @@ var/datum/computer_network/network = device.get_network() data["network_id"] = device.network_tag + var/obj/item/disk/design_disk/disk = try_get_disk() if(disk) data["disk_name"] = disk.name - data["disk_tech"] = disk.blueprint ? disk.blueprint.name : "no design saved" + if(istype(disk)) + data["disk_tech"] = disk.blueprint ? disk.blueprint.name : "no design saved" + else + data["disk_tech"] = "invalid data format" else data["disk_name"] = "no disk loaded" @@ -64,7 +75,7 @@ var/list/show_tech_levels = list() for(var/tech in viewing_database.tech_levels) var/decl/research_field/field = SSfabrication.get_research_field_by_id(tech) - show_tech_levels += list(list("field" = field.name, "level" = "[viewing_database.tech_levels[tech]].0 GQ")) + show_tech_levels += list(list("field" = field.name, "desc" = field.desc, "level" = "[viewing_database.tech_levels[tech]].0 GQ")) data["tech_levels"] = show_tech_levels else if(showing_designs) @@ -82,11 +93,11 @@ var/list/show_tech_levels = list() for(var/tech in local_cache) var/decl/research_field/field = SSfabrication.get_research_field_by_id(tech) - show_tech_levels += list(list("field" = field.name, "level" = "[local_cache[tech]].0 GQ")) + show_tech_levels += list(list("field" = field.name, "level" = "[local_cache[tech]].0 GQ", "desc" = field.desc)) data["tech_levels"] = show_tech_levels var/list/found_databases = list() - for(var/obj/machinery/design_database/db in network?.get_devices_by_type(/obj/machinery/design_database, user)) + for(var/obj/machinery/design_database/db in network?.get_devices_by_type(/obj/machinery/design_database, user.GetAccess())) var/list/database = list("name" = db.name, "ref" = "\ref[db]") if(db.stat & (BROKEN|NOPOWER)) database["status"] = "Offline" @@ -97,7 +108,7 @@ data["connected_databases"] = found_databases var/list/found_analyzers = list() - for(var/obj/machinery/destructive_analyzer/az in network?.get_devices_by_type(/obj/machinery/destructive_analyzer, user)) + for(var/obj/machinery/destructive_analyzer/az in network?.get_devices_by_type(/obj/machinery/destructive_analyzer, user.GetAccess())) var/list/analyzer = list("name" = az.name, "ref" = "\ref[az]") if(az.stat & (BROKEN|NOPOWER)) analyzer["status"] = "Offline" @@ -156,7 +167,8 @@ if(href_list["save_design"]) var/datum/fabricator_recipe/design = locate(href_list["save_design"]) - if(istype(design) && disk) + var/obj/item/disk/design_disk/disk = try_get_disk() + if(istype(design) && istype(disk)) disk.blueprint = design disk.SetName("[initial(disk.name)] ([disk.blueprint.name])") return TOPIC_REFRESH @@ -174,12 +186,18 @@ if(!(analyzer in network?.get_devices_by_type(/obj/machinery/destructive_analyzer))) return var/list/adding_to_cache = analyzer.process_loaded() - LAZYINITLIST(local_cache) - for(var/tech in adding_to_cache) - local_cache[tech] = max(local_cache[tech], adding_to_cache[tech]) - UNSETEMPTY(local_cache) - if(length(local_cache)) - sync_network() + if(length(adding_to_cache)) + LAZYINITLIST(local_cache) + for(var/tech in adding_to_cache) + var/current_level = local_cache[tech] || 0 + var/new_level = adding_to_cache[tech] || 0 + if(new_level == current_level) + local_cache[tech] = current_level+1 + else + local_cache[tech] = max(current_level, new_level) + UNSETEMPTY(local_cache) + if(length(local_cache)) + sync_network() /obj/machinery/computer/design_console/proc/get_network_tech_levels() . = local_cache || list() diff --git a/code/modules/research/design_database.dm b/code/modules/research/design_database.dm index f49738569044..bc52c9d40f21 100644 --- a/code/modules/research/design_database.dm +++ b/code/modules/research/design_database.dm @@ -1,28 +1,34 @@ +var/global/list/default_initial_tech_levels +/proc/get_default_initial_tech_levels() + if(!global.default_initial_tech_levels) + global.default_initial_tech_levels = list() + var/list/research_fields = decls_repository.get_decls_of_subtype(/decl/research_field) + for(var/field in research_fields) + var/decl/research_field/field_decl = research_fields[field] + global.default_initial_tech_levels[field_decl.id] = field_decl.initial_tech_level + return global.default_initial_tech_levels.Copy() + /obj/machinery/design_database name = "fabricator design database" - icon = 'icons/obj/machines/server.dmi' - icon_state = "server-off" + icon = 'icons/obj/machines/tcomms/blackbox.dmi' + icon_state = "blackbox" density = TRUE anchored = TRUE + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = 0 + maximum_component_parts = list( + /obj/item/stock_parts/item_holder/disk_reader = 1, + /obj/item/stock_parts = 15, + ) + /// A cached reference to our disk reader part, if present. + var/obj/item/stock_parts/item_holder/disk_reader/disk_reader var/initial_network_id var/initial_network_key - var/list/tech_levels = list( - TECH_MATERIAL = 0, - TECH_ENGINEERING = 0, - TECH_EXOTIC_MATTER = 0, - TECH_POWER = 0, - TECH_WORMHOLES = 0, - TECH_BIO = 0, - TECH_COMBAT = 0, - TECH_MAGNET = 0, - TECH_DATA = 0, - TECH_ESOTERIC = 0 - ) - + var/list/tech_levels var/need_disk_operation = FALSE - var/obj/item/disk/tech_disk/disk - var/sync_policy = SYNC_PULL_NETWORK|SYNC_PULL_DISK + var/sync_policy = SYNC_PULL_NETWORK|SYNC_PUSH_NETWORK|SYNC_PULL_DISK /obj/machinery/design_database/proc/toggle_sync_policy_flag(var/sync_flag) if(sync_policy & sync_flag) @@ -35,20 +41,24 @@ var/list/data = list() var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device) data["network_id"] = device.network_tag + var/obj/item/disk/tech_disk/disk = try_get_disk() if(disk) data["disk_name"] = disk.name - var/list/tech_data = list() - for(var/tech in disk.stored_tech) - var/decl/research_field/field = SSfabrication.get_research_field_by_id(tech) - tech_data += list(list("field" = field.name, "level" = "[disk.stored_tech[tech]].0 GQ")) - data["disk_tech"] = tech_data + if(istype(disk)) + var/list/tech_data = list() + for(var/tech in disk.stored_tech) + var/decl/research_field/field = SSfabrication.get_research_field_by_id(tech) + tech_data += list(list("field" = field.name, "desc" = field.desc, "level" = "[disk.stored_tech[tech]].0 GQ")) + data["disk_tech"] = tech_data + else + data["disk_error"] = "invalid data format" else data["disk_name"] = "no disk loaded" var/list/show_tech_levels = list() for(var/tech in tech_levels) var/decl/research_field/field = SSfabrication.get_research_field_by_id(tech) - show_tech_levels += list(list("field" = field.name, "level" = "[tech_levels[tech]].0 GQ")) + show_tech_levels += list(list("field" = field.name, "desc" = field.desc, "level" = "[tech_levels[tech]].0 GQ")) data["tech_levels"] = show_tech_levels data["network_push"] = (sync_policy & SYNC_PUSH_NETWORK) ? "on" : "off" @@ -77,8 +87,7 @@ eject_disk(user) return TOPIC_REFRESH if(href_list["wipe_database"]) - for(var/tech in tech_levels) - tech_levels[tech] = 0 + tech_levels = get_default_initial_tech_levels() return TOPIC_REFRESH if(href_list["settings"]) var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) @@ -86,88 +95,102 @@ return TOPIC_REFRESH /obj/machinery/design_database/Initialize() - . = ..() + if(!tech_levels) + tech_levels = get_default_initial_tech_levels() + ..() design_databases += src - set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, NETWORK_CONNECTION_WIRED) + set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, RECEIVER_STRONG_WIRELESS) update_icon() + . = INITIALIZE_HINT_LATELOAD + +/obj/machinery/design_database/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) + +/obj/machinery/design_database/handle_post_network_connection() + ..() + sync_design_consoles() + +/obj/machinery/design_database/proc/sync_design_consoles() + var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device) + var/datum/computer_network/network = device.get_network() + for(var/obj/machinery/computer/design_console/dc in network?.get_devices_by_type(/obj/machinery/computer/design_console)) + if(!(dc.stat & (BROKEN|NOPOWER))) + dc.sync_network() + return TRUE /obj/machinery/design_database/Process() ..() - if((stat & BROKEN) || (stat & NOPOWER) || !use_power || !powered()) + if((stat & BROKEN) || (stat & NOPOWER) || !use_power) return // Read or write from a loaded disk. + var/obj/item/disk/tech_disk/disk = try_get_disk() if(disk && need_disk_operation) - if(sync_policy & SYNC_PULL_DISK) - var/new_tech = FALSE - for(var/tech in disk.stored_tech) - if(tech_levels[tech] < disk.stored_tech[tech]) - tech_levels[tech] = disk.stored_tech[tech] - new_tech = TRUE - if(new_tech) - visible_message(SPAN_NOTICE("\The [src] clicks and chirps as it reads from \the [disk].")) - if(sync_policy & SYNC_PUSH_NETWORK) - var/synced - var/datum/extension/network_device/device = get_extension(src, /datum/extension/network_device) - var/datum/computer_network/network = device.get_network() - for(var/obj/machinery/computer/design_console/dc in network?.get_devices_by_type(/obj/machinery/computer/design_console)) - if(!(dc.stat & (BROKEN|NOPOWER))) - dc.sync_network(tech_levels) - synced = TRUE - break - if(!synced) + if(!istype(disk)) // wrong type of disk! + visible_message(SPAN_WARNING("\The [src] whirrs and drones, before emitting an ominous grinding sound.")) + else + if(sync_policy & SYNC_PULL_DISK) + var/new_tech = FALSE + for(var/tech in disk.stored_tech) + if(tech_levels[tech] < disk.stored_tech[tech]) + tech_levels[tech] = disk.stored_tech[tech] + new_tech = TRUE + if(new_tech) + visible_message(SPAN_NOTICE("\The [src] clicks and chirps as it reads from \the [disk].")) + if((sync_policy & SYNC_PUSH_NETWORK) && !sync_design_consoles()) visible_message(SPAN_WARNING("\The [src] flashes an error light from its network interface.")) - if(sync_policy & SYNC_PUSH_DISK) - var/new_tech - for(var/tech in tech_levels) - if(tech_levels[tech] > LAZYACCESS(disk.stored_tech, tech)) - new_tech = TRUE - LAZYSET(disk.stored_tech, tech, tech_levels[tech]) - if(new_tech) - visible_message(SPAN_NOTICE("\The [src] whirrs and drones as it writes to \the [disk].")) + if(sync_policy & SYNC_PUSH_DISK) + var/new_tech + for(var/tech in tech_levels) + if(tech_levels[tech] > LAZYACCESS(disk.stored_tech, tech)) + new_tech = TRUE + LAZYSET(disk.stored_tech, tech, tech_levels[tech]) + if(new_tech) + visible_message(SPAN_NOTICE("\The [src] whirrs and drones as it writes to \the [disk].")) visible_message("The I/O light on \the [src] stops blinking.") need_disk_operation = FALSE /obj/machinery/design_database/on_update_icon() - if(!(stat & NOPOWER) && !(stat & BROKEN) && use_power > 0) - icon_state = "server" - else - icon_state = "server-off" + icon_state = initial(icon_state) + if(panel_open) + icon_state = "[icon_state]_o" + if((stat & NOPOWER) || (stat & BROKEN) || !use_power) + icon_state = "[icon_state]_off" /obj/machinery/design_database/Destroy() design_databases -= src - QDEL_NULL(disk) + disk_reader = null . = ..() -/obj/machinery/design_database/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/disk/tech_disk)) - if(disk) - to_chat(user, SPAN_WARNING("\The [src] already has a disk inserted.")) - return - if(user.unEquip(I, src)) - visible_message("\The [user] slots \the [I] into \the [src].") - visible_message(SPAN_NOTICE("\The [src]'s I/O light begins to blink.")) - disk = I - need_disk_operation = TRUE - return +/obj/machinery/design_database/proc/on_insert_disk(obj/item/disk/D, mob/user) + visible_message(SPAN_NOTICE("\The [src]'s I/O light begins to blink.")) + need_disk_operation = TRUE + update_ui() + +/obj/machinery/design_database/proc/on_eject_disk(obj/item/disk/D, mob/user) + need_disk_operation = FALSE + update_ui() +/obj/machinery/design_database/RefreshParts() . = ..() + disk_reader = get_component_of_type(/obj/item/stock_parts/item_holder/disk_reader) + if(disk_reader) + disk_reader.register_on_insert(CALLBACK(src, PROC_REF(on_insert_disk))) + disk_reader.register_on_eject(CALLBACK(src, PROC_REF(on_eject_disk))) + +/obj/machinery/design_database/proc/try_get_disk() + return disk_reader?.get_inserted() +/obj/machinery/design_database/proc/update_ui() + SSnano.update_uis(src) + +// used for, specifically, removing a disk via the UI /obj/machinery/design_database/proc/eject_disk(var/mob/user) - if(disk) - disk.dropInto(loc) - need_disk_operation = FALSE - if(user) - if(!issilicon(user)) - user.put_in_hands(disk) - if(Adjacent(user, src)) - visible_message(SPAN_NOTICE("\The [user] removes \the [disk] from \the [src].")) - disk = null - return TRUE - return FALSE - -/obj/machinery/design_database/AltClick(mob/user) - if(disk) - eject_disk(user) - . = ..() + if(!disk_reader) + to_chat(user, SPAN_WARNING("\The [src] has no disk drive installed.")) + return FALSE + . = !isnull(disk_reader.eject_item(user)) + update_ui() diff --git a/code/modules/research/design_database_analyzer.dm b/code/modules/research/design_database_analyzer.dm index 44ecfc1cab9c..6d57b82a0633 100644 --- a/code/modules/research/design_database_analyzer.dm +++ b/code/modules/research/design_database_analyzer.dm @@ -18,7 +18,12 @@ /obj/machinery/destructive_analyzer/Initialize() . = ..() - set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, NETWORK_CONNECTION_WIRED) + set_extension(src, /datum/extension/network_device, initial_network_id, initial_network_key, RECEIVER_STRONG_WIRELESS) + +/obj/machinery/destructive_analyzer/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(initial_network_id, map_hash) + ADJUST_TAG_VAR(initial_network_key, map_hash) /obj/machinery/destructive_analyzer/RefreshParts() var/T = 0 @@ -56,14 +61,13 @@ var/list/dump_matter for(var/mat in cached_materials) - var/amt = Floor(cached_materials[mat]/SHEET_MATERIAL_AMOUNT) + var/amt = floor(cached_materials[mat]/SHEET_MATERIAL_AMOUNT) if(amt > 0) LAZYSET(dump_matter, mat, amt) if(length(dump_matter)) visible_message("\The [user] unloads \the [src]'s material hopper.") for(var/mat in dump_matter) - var/decl/material/M = decls_repository.get_decl(mat) - M.place_sheet(loc, dump_matter[mat]) + SSmaterials.create_object(mat, loc, dump_matter[mat]) cached_materials[mat] -= dump_matter[mat] * SHEET_MATERIAL_AMOUNT if(cached_materials[mat] <= 0) cached_materials -= mat @@ -76,19 +80,19 @@ D.ui_interact(user) return TRUE -/obj/machinery/destructive_analyzer/attackby(var/obj/item/O, var/mob/user) +/obj/machinery/destructive_analyzer/attackby(var/obj/item/used_item, var/mob/user) - if(isMultitool(O) && user.a_intent != I_HURT) + if(IS_MULTITOOL(used_item) && !user.check_intent(I_FLAG_HARM)) var/datum/extension/local_network_member/fabnet = get_extension(src, /datum/extension/local_network_member) fabnet.get_new_tag(user) return TRUE - if(isrobot(user)) - return if(busy) to_chat(user, SPAN_WARNING("\The [src] is busy right now.")) return TRUE - if(component_attackby(O, user)) + if((. = component_attackby(used_item, user))) + return + if(isrobot(user)) return TRUE if(loaded_item) to_chat(user, SPAN_WARNING("There is something already loaded into \the [src].")) @@ -96,22 +100,24 @@ if(panel_open) to_chat(user, SPAN_WARNING("You can't load \the [src] while it's opened.")) return TRUE - if(!O.origin_tech) - to_chat(user, SPAN_WARNING("Nothing can be learned from \the [O].")) + var/tech = used_item.get_origin_tech() + if(!tech) + to_chat(user, SPAN_WARNING("Nothing can be learned from \the [used_item].")) return TRUE - var/list/techlvls = json_decode(O.origin_tech) - if(!length(techlvls) || O.holographic) + var/list/techlvls = cached_json_decode(tech) + if(!length(techlvls) || used_item.holographic) to_chat(user, SPAN_WARNING("You cannot deconstruct this item.")) return TRUE - if(user.unEquip(O, src)) - busy = TRUE - loaded_item = O - to_chat(user, SPAN_NOTICE("You add \the [O] to \the [src].")) - flick("d_analyzer_la", src) - addtimer(CALLBACK(src, .proc/refresh_busy, 1 SECOND)) + if(!user.try_unequip(used_item, src)) return TRUE + busy = TRUE + loaded_item = used_item + to_chat(user, SPAN_NOTICE("You add \the [used_item] to \the [src].")) + flick("d_analyzer_la", src) + addtimer(CALLBACK(src, PROC_REF(refresh_busy)), 1 SECOND) + return TRUE /obj/machinery/destructive_analyzer/proc/refresh_busy() if(busy) @@ -122,22 +128,26 @@ if(!loaded_item) return busy = TRUE - if(loaded_item.origin_tech) - . = json_decode(loaded_item.origin_tech) - var/increase = (locate(/datum/event/brain_expansion) in SSevent.active_events) ? 2 : 1 - for(var/tech in .) - .[tech] += increase - else - . = list() + var/tech_json = loaded_item.get_origin_tech() + if(tech_json) + . = cached_json_decode(tech_json) + if(length(.) && (locate(/datum/event/brain_expansion) in SSevent.active_events)) + for(var/tech in .) + .[tech] += 1 for(var/mat in loaded_item.matter) LAZYSET(cached_materials, mat, cached_materials[mat] + (loaded_item.matter[mat] * material_return_modifier)) - QDEL_NULL(loaded_item) + loaded_item.physically_destroyed(FALSE) + if(!QDELETED(loaded_item)) + QDEL_NULL(loaded_item) + else + loaded_item = null flick("d_analyzer_process", src) - addtimer(CALLBACK(src, .proc/refresh_busy, 2 SECONDS)) + addtimer(CALLBACK(src, PROC_REF(refresh_busy)), 2 SECONDS) /obj/item/research name = "research debugging device" desc = "Instant research tool. For testing purposes only." icon = 'icons/obj/items/stock_parts/stock_parts.dmi' icon_state = "smes_coil" - origin_tech = "{'materials':19,'engineering':19,'exoticmatter':19,'powerstorage':19,'wormholes':19,'biotech':19,'combat':19,'magnets':19,'programming':19,'esoteric':19}" + origin_tech = @'{"materials":19,"engineering":19,"exoticmatter":19,"powerstorage":19,"wormholes":19,"biotech":19,"combat":19,"magnets":19,"programming":19,"esoteric":19}' + max_health = ITEM_HEALTH_NO_DAMAGE diff --git a/code/modules/research/research_fields.dm b/code/modules/research/research_fields.dm index 7da428d8e38e..d37be7dde722 100644 --- a/code/modules/research/research_fields.dm +++ b/code/modules/research/research_fields.dm @@ -2,6 +2,7 @@ var/name var/desc var/id + var/initial_tech_level = 1 /decl/research_field/material name = "Materials Science" @@ -17,6 +18,7 @@ name = "Exotic Matter" desc = "The study of wormholes, non-baryonic matter, and the manipulation of spacetime." id = TECH_EXOTIC_MATTER + initial_tech_level = 0 /decl/research_field/power name = "Power Storage" @@ -27,6 +29,7 @@ name = "Wormholes" desc = "The study of the realm that lies beyond the singularity." id = TECH_WORMHOLES + initial_tech_level = 0 /decl/research_field/biotech name = "Biotechnology" @@ -37,6 +40,7 @@ name = "Weapon Development" desc = "The study of new and more effective weapon systems." id = TECH_COMBAT + initial_tech_level = 0 /decl/research_field/magnets name = "Magnetic Fields" @@ -45,10 +49,11 @@ /decl/research_field/programming name = "Data Science" - desc = "The study of computer science, data manipuation and artificial intelligence." + desc = "The study of computer science, data manipulation and artificial intelligence." id = TECH_DATA /decl/research_field/esoteria name = "Esoteria" desc = "The study of mysterious pseudoscientific anomalies." id = TECH_ESOTERIC + initial_tech_level = 0 diff --git a/code/modules/salvage/salvage.dm b/code/modules/salvage/salvage.dm new file mode 100644 index 000000000000..ecf3196f8834 --- /dev/null +++ b/code/modules/salvage/salvage.dm @@ -0,0 +1,131 @@ +/obj/item/salvage + desc = "The remains of an unfortunate device." + transform_animate_time = 0 + icon = 'icons/obj/modules/module_id.dmi' + icon_state = ICON_STATE_WORLD + abstract_type = /obj/item/salvage + var/work_skill = SKILL_DEVICES + var/obj/item/salvaged_type + var/list/repairs_required = list() + var/do_rotation = TRUE + +/obj/item/salvage/Initialize(var/ml, var/path) + . = ..(ml) + if(!ispath(salvaged_type, /obj/item)) + return INITIALIZE_HINT_QDEL + // TODO: grab partial initial matter from the salvage type. + icon_rotation = rand(-45, 45) + name = "[pick("busted", "broken", "shattered", "scrapped")] [salvaged_type::name]" + w_class = salvaged_type::w_class + + var/list/all_repair_options = get_repair_options() + var/list/selected_options = list() + for(var/opt_type in all_repair_options) + var/decl/salvage_repair_option/opt = RESOLVE_TO_DECL(opt_type) + if(istype(opt) && prob(opt.selection_prob)) + selected_options += opt + if(!length(selected_options)) + selected_options += RESOLVE_TO_DECL(pick(all_repair_options)) + for(var/decl/salvage_repair_option/opt in selected_options) + repairs_required += opt.create_salvage_requirement() + + update_icon() + +/obj/item/salvage/proc/get_repair_options() + return subtypesof(/decl/salvage_repair_option/material_sheet) + +/obj/item/salvage/attackby(obj/item/used_item, mob/user) + + // Find an appropriate repair (finished or not) + var/datum/salvage_repair_requirement/opt + for(var/datum/salvage_repair_requirement/rep in repairs_required) + if(!istype(used_item, rep.repair_type)) + continue + if(istype(used_item, /obj/item/stack/material) && !istype(used_item.material, rep.repair_material)) + continue + if(!opt || (opt.repair_amount == 0 && rep.repair_amount > 0)) + opt = rep + + // Apply the repair. + if(opt) + if(opt.repair_amount <= 0) + to_chat(user, SPAN_WARNING("\The [src] does not need further repair with \the [used_item].")) + else if(user.do_skilled((5 + rand(10)) SECONDS, work_skill, src) && !QDELETED(opt) && opt.repair_amount > 0) + if(istype(used_item, /obj/item/stack)) + var/obj/item/stack/stack = used_item + var/use_amt = min(opt.repair_amount, stack.get_amount()) + stack.use(use_amt) + opt.repair_amount -= use_amt + else if(user.try_unequip(used_item)) + qdel(used_item) + opt.repair_amount-- + // TODO: transfer material from the donor item to this item. + check_repair_completion(user) + return TRUE + + . = ..() + +/obj/item/salvage/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + . += SPAN_NOTICE("It requires the following items to be fully repaired:") + for(var/datum/salvage_repair_requirement/rep in repairs_required) + if(rep.repair_amount <= 0) + continue + var/is_mat_stack = ispath(rep.repair_type, /obj/item/stack/material) && rep.repair_material + var/obj/item/repair_type = rep.repair_type + var/repair_thing = is_mat_stack ? atom_info_repository.get_name_for(repair_type, rep.repair_material) : atom_info_repository.get_name_for(repair_type) + if(ispath(rep.repair_type, /obj/item/stack)) + var/obj/item/stack/stack = rep.repair_type + repair_thing = rep.repair_amount == 1 ? stack::singular_name : stack::plural_name + if(is_mat_stack) + var/decl/material/repair_mat = GET_DECL(rep.repair_material) + repair_thing = "[repair_mat.solid_name] [repair_thing]" + else if(rep.repair_amount > 1) + repair_thing = text_make_plural(repair_thing) + . += SPAN_NOTICE("- [rep.repair_amount] [repair_thing]") + +/obj/item/salvage/proc/check_repair_completion(mob/user) + + for(var/datum/salvage_repair_requirement/rep in repairs_required) + if(rep.repair_amount > 0) + if(user) + to_chat(user, SPAN_NOTICE("You mend some of the damage to \the [src], but further repair is required.")) + return + + var/obj/item/created = new salvaged_type(get_turf(src)) + if(isitem(created)) + if(created.name_prefix) + created.name_prefix = "[created.name_prefix] [pick("salvaged", "restored", "old", "worn")]" // enormous salvaged pipe wrench + else + created.name_prefix = pick("salvaged", "restored", "old", "worn") // salvaged laser rifle + created.update_name() + + var/atom/created_loc = loc + qdel(src) + + if(user) + to_chat(user, SPAN_NOTICE("You finish repairing \the [created]!")) + + if(user && created_loc == user) + user.put_in_hands(created) + else + created.forceMove(created_loc) + +/obj/item/salvage/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + if(!salvaged_type) + return + var/old_name = name + var/old_desc = desc + var/old_pixel_x = pixel_x + var/old_pixel_y = pixel_y + var/old_plane = plane + var/old_layer = layer + appearance = atom_info_repository.get_appearance_of(salvaged_type) + name = old_name + desc = old_desc + pixel_x = old_pixel_x + pixel_y = old_pixel_y + plane = old_plane + layer = old_layer + update_transform() diff --git a/code/modules/salvage/salvage_ballistic.dm b/code/modules/salvage/salvage_ballistic.dm new file mode 100644 index 000000000000..904f6d0276c9 --- /dev/null +++ b/code/modules/salvage/salvage_ballistic.dm @@ -0,0 +1,24 @@ +/obj/item/salvage/ballistic + name = "broken ballistic weapon" + icon = /obj/item/gun/projectile/automatic/assault_rifle::icon + icon_state = /obj/item/gun/projectile/automatic/assault_rifle::icon_state + abstract_type = /obj/item/salvage/ballistic + +/obj/item/salvage/ballistic/get_repair_options() + return ..() + /decl/salvage_repair_option/component + +/obj/item/salvage/ballistic/assault + salvaged_type = /obj/item/gun/projectile/automatic/assault_rifle + +/obj/item/salvage/ballistic/pistol + salvaged_type = /obj/item/gun/projectile/pistol + +/obj/item/salvage/ballistic/smg + salvaged_type = /obj/item/gun/projectile/automatic/smg + +/obj/item/salvage/ballistic/shotgun_pump + salvaged_type = /obj/item/gun/projectile/shotgun/pump + +/obj/item/salvage/ballistic/shotgun_doublebarrel + salvaged_type = /obj/item/gun/projectile/shotgun/doublebarrel + diff --git a/code/modules/salvage/salvage_energy.dm b/code/modules/salvage/salvage_energy.dm new file mode 100644 index 000000000000..935a3467abbe --- /dev/null +++ b/code/modules/salvage/salvage_energy.dm @@ -0,0 +1,17 @@ +/obj/item/salvage/energy + name = "broken energy weapon" + icon = /obj/item/gun/energy/laser::icon + icon_state = /obj/item/gun/energy/laser::icon_state + abstract_type = /obj/item/salvage/energy + +/obj/item/salvage/energy/get_repair_options() + return ..() + /decl/salvage_repair_option/energy + +/obj/item/salvage/energy/ionrifle + salvaged_type = /obj/item/gun/energy/ionrifle + +/obj/item/salvage/energy/laserrifle + salvaged_type = /obj/item/gun/energy/laser + +/obj/item/salvage/energy/laser_retro + salvaged_type = /obj/item/gun/energy/retro/captain diff --git a/code/modules/salvage/salvage_launcher.dm b/code/modules/salvage/salvage_launcher.dm new file mode 100644 index 000000000000..571f69b6a136 --- /dev/null +++ b/code/modules/salvage/salvage_launcher.dm @@ -0,0 +1,14 @@ +/obj/item/salvage/launcher + name = "broken grenade launcher" + icon = /obj/item/gun/launcher/grenade::icon + icon_state = /obj/item/gun/launcher/grenade::icon_state + abstract_type = /obj/item/salvage/launcher + +/obj/item/salvage/launcher/get_repair_options() + return ..() + /decl/salvage_repair_option/launcher + +/obj/item/salvage/launcher/grenade + salvaged_type = /obj/item/gun/launcher/grenade + +/obj/item/salvage/launcher/dartgun + salvaged_type = /obj/item/gun/projectile/dartgun diff --git a/code/modules/salvage/salvage_magnetic.dm b/code/modules/salvage/salvage_magnetic.dm new file mode 100644 index 000000000000..78b8bcf47baa --- /dev/null +++ b/code/modules/salvage/salvage_magnetic.dm @@ -0,0 +1,12 @@ +/obj/item/salvage/magnetic + name = "broken magnetic weapon" + icon = /obj/item/gun/magnetic/railgun/flechette::icon + icon_state = /obj/item/gun/magnetic/railgun/flechette::icon_state + abstract_type = /obj/item/salvage/magnetic + +/obj/item/salvage/magnetic/get_repair_options() + return ..() + /decl/salvage_repair_option/magnetic + +/obj/item/salvage/magnetic/flechette + salvaged_type = /obj/item/gun/magnetic/railgun/flechette + diff --git a/code/modules/salvage/salvage_repair_option.dm b/code/modules/salvage/salvage_repair_option.dm new file mode 100644 index 000000000000..f63d88afc611 --- /dev/null +++ b/code/modules/salvage/salvage_repair_option.dm @@ -0,0 +1,90 @@ +/decl/salvage_repair_option + abstract_type = /decl/salvage_repair_option + var/selection_prob = 0 + var/list/selection_types + var/list/selection_materials + var/selection_min_amount = 1 + var/selection_max_amount = 3 + +/decl/salvage_repair_option/validate() + . = ..() + if(!islist(selection_types) || !length(selection_types)) + . += "null, empty or malformed selection_types list" + else + for(var/selection_type in selection_types) + if(!ispath(selection_type)) + . += "non-path selection type: '[selection_type]'" + else if(ispath(selection_type, /obj/item/stack/material) && (!islist(selection_materials) || !length(selection_materials))) + . += "material stack '[selection_type]' in selection_types, but selection_materials is empty/malformed" + for(var/selection_material in selection_materials) + if(!ispath(selection_material, /decl/material)) + . += "non-material path '[selection_material]' in selection_materials" + +/decl/salvage_repair_option/proc/create_salvage_requirement() + var/use_type = pick(selection_types) + var/use_mat = ispath(use_type, /obj/item/stack/material) ? pick(selection_materials) : null + return new /datum/salvage_repair_requirement(use_type, use_mat, rand(selection_min_amount, selection_max_amount)) + +/decl/salvage_repair_option/component + selection_prob = 30 + selection_types = list( + /obj/item/stock_parts/manipulator + ) + +/decl/salvage_repair_option/material_sheet + selection_prob = 40 + abstract_type = /decl/salvage_repair_option/material_sheet + +/decl/salvage_repair_option/material_sheet/plastic + selection_types = list( + /obj/item/stack/material/panel + ) + selection_materials = list( + /decl/material/solid/organic/plastic + ) + +/decl/salvage_repair_option/material_sheet/glass + selection_types = list( + /obj/item/stack/material/pane + ) + selection_materials = list( + /decl/material/solid/glass + ) + +/decl/salvage_repair_option/material_sheet/plasteel + selection_types = list( + /obj/item/stack/material/sheet/reinforced + ) + selection_materials = list( + /decl/material/solid/metal/plasteel + ) + +/decl/salvage_repair_option/launcher + selection_prob = 50 + selection_materials = list( + /decl/material/solid/metal/steel + ) + selection_types = list( + /obj/item/stack/tape_roll, + /obj/item/stack/material/rods, + /obj/item/handcuffs/cable + ) + selection_max_amount = 1 + +/decl/salvage_repair_option/energy + selection_prob = 25 + selection_types = list( + /obj/item/stack/cable_coil, + /obj/item/stock_parts/scanning_module, + /obj/item/stock_parts/capacitor + ) + selection_max_amount = 1 + +/decl/salvage_repair_option/magnetic + selection_prob = 70 + selection_types = list( + /obj/item/stock_parts/smes_coil, + /obj/item/assembly/prox_sensor, + /obj/item/stock_parts/circuitboard/apc + ) + selection_max_amount = 1 diff --git a/code/modules/salvage/salvage_repair_requirement.dm b/code/modules/salvage/salvage_repair_requirement.dm new file mode 100644 index 000000000000..fdf524bb61e4 --- /dev/null +++ b/code/modules/salvage/salvage_repair_requirement.dm @@ -0,0 +1,9 @@ +/datum/salvage_repair_requirement + var/repair_type + var/repair_material + var/repair_amount + +/datum/salvage_repair_requirement/New(_type, _mat, _amt) + repair_amount = _amt + repair_material = _mat + repair_type = _type diff --git a/code/modules/salvage/structure.dm b/code/modules/salvage/structure.dm new file mode 100644 index 000000000000..1d71f206157a --- /dev/null +++ b/code/modules/salvage/structure.dm @@ -0,0 +1,23 @@ +/obj/structure/salvage + icon = 'icons/obj/structures/salvage.dmi' + abstract_type = /obj/structure/salvage + tool_interaction_flags = TOOL_INTERACTION_DECONSTRUCT + material = /decl/material/solid/metal/steel + var/frame_type = /obj/machinery/constructable_frame/machine_frame + var/work_skill = SKILL_CONSTRUCTION + +/obj/structure/salvage/proc/get_salvageable_components() + return + +/obj/structure/salvage/Initialize(ml, _mat, _reinf_mat) + . = ..() + name_prefix = pick("broken", "ruined", "destroyed", "slagged", "damaged") + +/obj/structure/salvage/create_dismantled_products(turf/T) + . = ..() + if(frame_type) + new frame_type(T) + var/list/salvageable_components = get_salvageable_components() + for(var/comp in salvageable_components) + if(!salvageable_components[comp] || prob(salvageable_components[comp])) + new comp(T) diff --git a/code/modules/salvage/structure_computer.dm b/code/modules/salvage/structure_computer.dm new file mode 100644 index 000000000000..12b9f700eee3 --- /dev/null +++ b/code/modules/salvage/structure_computer.dm @@ -0,0 +1,116 @@ +/obj/structure/salvage/computer + name = "computer" + desc = "A defunct computer. There might still be useful components inside." + icon_state = "computer0" + +/obj/structure/salvage/computer/Initialize() + . = ..() + icon_state = "computer[rand(0,7)]" + +/obj/structure/salvage/computer/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 90, + /obj/item/stack/material/pane/mapped/glass/five = 90, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/network_card/advanced = 20, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/capacitor/adv = 30, + ) + return salvageable_parts + +/obj/structure/salvage/server + name = "server" + desc = "A damaged, broken server. There might still be useful components inside." + icon_state = "server0" + +/obj/structure/salvage/server/Initialize(ml, _mat, _reinf_mat) + . = ..() + +/obj/structure/salvage/server/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 90, + /obj/item/stack/material/pane/mapped/glass/five = 90, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/subspace/amplifier = 40, + /obj/item/stock_parts/subspace/amplifier = 40, + /obj/item/stock_parts/subspace/analyzer = 40, + /obj/item/stock_parts/subspace/analyzer = 40, + /obj/item/stock_parts/subspace/ansible = 40, + /obj/item/stock_parts/subspace/ansible = 40, + /obj/item/stock_parts/subspace/transmitter = 40, + /obj/item/stock_parts/subspace/transmitter = 40, + /obj/item/stock_parts/subspace/crystal = 30, + /obj/item/stock_parts/subspace/crystal = 30, + /obj/item/stock_parts/computer/network_card/advanced = 20 + ) + return salvageable_parts + +/obj/structure/salvage/computer_old + name = "computer" + desc = "A defunct computer. There might still be useful components inside." + icon_state = "os-computer" + +/obj/structure/salvage/computer_old/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 90, + /obj/item/stack/material/pane/mapped/glass/five = 90, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/computer/processor_unit/photonic = 40, + /obj/item/stock_parts/computer/processor_unit/photonic = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/network_card/advanced = 40 + ) + return salvageable_parts + +/obj/structure/salvage/data + name = "data storage" + desc = "An old, battered, broken data storage rack. There might still be useful components inside." + icon_state = "data0" + +/obj/structure/salvage/data/Initialize() + . = ..() + icon_state = "data[rand(0,1)]" + +/obj/structure/salvage/data/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 90, + /obj/item/stack/material/pane/mapped/glass/five = 90, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/computer/hard_drive = 50, + /obj/item/stock_parts/computer/hard_drive = 50, + /obj/item/stock_parts/computer/hard_drive = 50, + /obj/item/stock_parts/computer/hard_drive = 50, + /obj/item/stock_parts/computer/hard_drive = 50, + /obj/item/stock_parts/computer/hard_drive = 50, + /obj/item/stock_parts/computer/hard_drive/advanced = 30, + /obj/item/stock_parts/computer/hard_drive/advanced = 30, + /obj/item/stock_parts/computer/network_card/advanced = 20 + ) + return salvageable_parts diff --git a/code/modules/salvage/structure_console.dm b/code/modules/salvage/structure_console.dm new file mode 100644 index 000000000000..7f31e5be6ad6 --- /dev/null +++ b/code/modules/salvage/structure_console.dm @@ -0,0 +1,35 @@ +/obj/structure/salvage/console + name = "console" + desc = "A beat-up old console. Might still have some useful components inside." + icon_state = "os_console" + +/obj/structure/salvage/console/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stack/cable_coil/five = 90, + /obj/item/stock_parts/console_screen = 80, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/computer/processor_unit/small = 40, + /obj/item/stock_parts/computer/processor_unit/photonic = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/network_card/advanced = 40 + ) + return salvageable_parts + +/obj/structure/salvage/console/broken + icon_state = "os_console_broken" + +/obj/structure/salvage/console/broken/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stack/cable_coil/five = 90, + /obj/item/stock_parts/console_screen = 80, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/capacitor = 60, + /obj/item/stock_parts/computer/processor_unit = 40, + /obj/item/stock_parts/computer/processor_unit/photonic = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/network_card/advanced = 40 + ) + return salvageable_parts diff --git a/code/modules/salvage/structure_machine.dm b/code/modules/salvage/structure_machine.dm new file mode 100644 index 000000000000..62fa97c6bbfc --- /dev/null +++ b/code/modules/salvage/structure_machine.dm @@ -0,0 +1,92 @@ + +/obj/structure/salvage/fabricator + name = "fabricator" + desc = "A busted, defunct fabricator. There might still be useful components or materials inside." + icon_state = "autolathe" + +/obj/structure/salvage/fabricator/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 80, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/stock_parts/capacitor = 40, + /obj/item/stock_parts/scanning_module = 40, + /obj/item/stock_parts/manipulator = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/capacitor/adv = 20, + /obj/item/stock_parts/micro_laser/high = 20, + /obj/item/stock_parts/micro_laser/high = 20, + /obj/item/stock_parts/matter_bin/adv = 20, + /obj/item/stock_parts/matter_bin/adv = 20, + /obj/item/stack/material/sheet/mapped/steel/twenty = 40, + /obj/item/stack/material/pane/mapped/glass/twenty = 40, + /obj/item/stack/material/panel/mapped/plastic/twenty = 40, + /obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten = 40, + /obj/item/stack/material/ingot/mapped/silver/ten = 20, + /obj/item/stack/material/ingot/mapped/gold/ten = 20 + ) + return salvageable_parts + +/obj/structure/salvage/machine + name = "machine" + desc = "A badly-damaged machine of some kind. There might still be some usable components inside." + icon_state = "machine1" + +/obj/structure/salvage/machine/Initialize() + . = ..() + icon_state = "machine[rand(0,6)]" + +/obj/structure/salvage/machine/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 80, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/stock_parts/capacitor = 40, + /obj/item/stock_parts/capacitor = 40, + /obj/item/stock_parts/scanning_module = 40, + /obj/item/stock_parts/scanning_module = 40, + /obj/item/stock_parts/manipulator = 40, + /obj/item/stock_parts/manipulator = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/capacitor/adv = 20, + /obj/item/stock_parts/scanning_module/adv = 20, + /obj/item/stock_parts/manipulator/nano = 20, + /obj/item/stock_parts/micro_laser/high = 20, + /obj/item/stock_parts/matter_bin/adv = 20 + ) + return salvageable_parts + +/obj/structure/salvage/machine_old + name = "machine" + desc = "A badly-damaged machine of some kind. There might still be some usable components inside." + icon_state = "os-machine" + +/obj/structure/salvage/machine_old/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 80, + /obj/item/stock_parts/capacitor = 40, + /obj/item/stock_parts/capacitor = 40, + /obj/item/stock_parts/scanning_module = 40, + /obj/item/stock_parts/scanning_module = 40, + /obj/item/stock_parts/manipulator = 40, + /obj/item/stock_parts/manipulator = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/micro_laser = 40, + /obj/item/stock_parts/matter_bin = 40, + /obj/item/stock_parts/matter_bin = 40 + ) + return salvageable_parts diff --git a/code/modules/salvage/structure_misc.dm b/code/modules/salvage/structure_misc.dm new file mode 100644 index 000000000000..e1515b69c93b --- /dev/null +++ b/code/modules/salvage/structure_misc.dm @@ -0,0 +1,27 @@ +/obj/structure/salvage/implant_container + name = "old container" + icon_state = "implant_container0" + +/obj/structure/salvage/implant_container/Initialize() + . = ..() + icon_state = "implant_container[rand(0,1)]" + +/obj/structure/salvage/implant_container/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 80, + /obj/item/stack/cable_coil/five = 80, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/implant/death_alarm = 15, + /obj/item/implant/explosive = 10, + /obj/item/implant/freedom = 5, + /obj/item/implant/tracking = 10, + /obj/item/implant/chem = 10, + /obj/item/implantcase = 30, + /obj/item/implanter = 30, + /obj/item/stack/material/sheet/mapped/steel/ten = 30, + /obj/item/stack/material/pane/mapped/glass/ten = 30, + /obj/item/stack/material/ingot/mapped/silver/ten = 30 + ) + return salvageable_parts diff --git a/code/modules/salvage/structure_terminal.dm b/code/modules/salvage/structure_terminal.dm new file mode 100644 index 000000000000..6e2ef10be5c5 --- /dev/null +++ b/code/modules/salvage/structure_terminal.dm @@ -0,0 +1,29 @@ +/obj/structure/salvage/personal + name = "personal terminal" + desc = "An unusable personal terminal. There might still be useful components inside." + icon_state = "personal0" + +/obj/structure/salvage/personal/Initialize(ml, _mat, _reinf_mat) + . = ..() + icon_state = "personal[rand(0,12)]" + +/obj/structure/salvage/personal/get_salvageable_components() + var/static/list/salvageable_parts = list( + /obj/item/stock_parts/console_screen = 90, + /obj/item/stack/cable_coil/five = 90, + /obj/item/stack/material/pane/mapped/glass/five = 70, + /obj/item/debris/salvage/circuit = 60, + /obj/item/debris/salvage/metal = 60, + /obj/item/debris/salvage/metal/plasteel = 15, + /obj/item/stock_parts/computer/network_card = 60, + /obj/item/stock_parts/computer/network_card = 40, + /obj/item/stock_parts/computer/network_card/advanced = 40, + /obj/item/stock_parts/computer/card_slot = 40, + /obj/item/stock_parts/computer/processor_unit = 60, + /obj/item/stock_parts/computer/processor_unit/small = 50, + /obj/item/stock_parts/computer/processor_unit/photonic = 40, + /obj/item/stock_parts/computer/processor_unit/photonic/small = 30, + /obj/item/stock_parts/computer/hard_drive = 60, + /obj/item/stock_parts/computer/hard_drive/advanced = 40 + ) + return salvageable_parts diff --git a/code/game/objects/items/devices/scanners/_scanner.dm b/code/modules/scanners/_scanner.dm similarity index 81% rename from code/game/objects/items/devices/scanners/_scanner.dm rename to code/modules/scanners/_scanner.dm index b43e5fec24a0..8496b049f86c 100644 --- a/code/game/objects/items/devices/scanners/_scanner.dm +++ b/code/modules/scanners/_scanner.dm @@ -2,14 +2,16 @@ name = "handheld scanner" desc = "A hand-held scanner of some sort. You shouldn't be seeing it." icon = 'icons/obj/items/device/scanner/atmos_scanner.dmi' - icon_state = "atmos" - item_state = "analyzer" + icon_state = ICON_STATE_WORLD w_class = ITEM_SIZE_SMALL obj_flags = OBJ_FLAG_CONDUCTIBLE - slot_flags = SLOT_BELT + slot_flags = SLOT_LOWER_BODY item_flags = ITEM_FLAG_NO_BLUDGEON material = /decl/material/solid/metal/aluminium - matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT) + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + drop_sound = 'sound/foley/drop1.ogg' + pickup_sound = 'sound/foley/pickup2.ogg' + var/scan_title var/scan_data var/window_width = 450 @@ -22,12 +24,12 @@ show_menu(user) /obj/item/scanner/proc/show_menu(mob/user) - var/datum/browser/written/popup = new(user, "scanner", scan_title, window_width, window_height) + var/datum/browser/written_digital/popup = new(user, "scanner", scan_title, window_width, window_height) popup.set_content("[get_header()]
    [scan_data]") popup.open() /obj/item/scanner/proc/get_header() - return "Print ReportClear data" + return "Print ReportClear data" /obj/item/scanner/proc/can_use(mob/user) if (user.incapacitated()) @@ -88,7 +90,7 @@ to_chat(user, "There is no scan data to print.") return playsound(loc, "sound/machines/dotprinter.ogg", 20, 1) - var/obj/item/paper/P = new(get_turf(src), scan_data, "paper - [scan_title]") + var/obj/item/paper/P = new(get_turf(src), null, scan_data, "paper - [scan_title]") if(printout_color) P.color = printout_color user.put_in_hands(P) diff --git a/code/modules/scanners/breath.dm b/code/modules/scanners/breath.dm new file mode 100644 index 000000000000..0c596e83f7f6 --- /dev/null +++ b/code/modules/scanners/breath.dm @@ -0,0 +1,122 @@ +/obj/item/scanner/breath + name = "breath analyzer" + desc = "A two-in-one breathalyzer and respirometer, measuring intoxication, breath contents, and respiratory health." + icon = 'icons/obj/items/device/scanner/breath_scanner.dmi' + item_flags = ITEM_FLAG_NO_BLUDGEON + material = /decl/material/solid/metal/aluminium + origin_tech = @'{"biotech":1}' + printout_color = "#deebff" + var/mode = 1 + +/obj/item/scanner/breath/is_valid_scan_target(atom/O) + if(isliving(O)) + var/mob/living/M = O + return !!M.get_inhaled_reagents() + return FALSE + +/obj/item/scanner/breath/scan(atom/A, mob/user) + scan_data = breath_scan_action(A, user, src, mode) + playsound(src, 'sound/effects/fastbeep.ogg', 20) + +/proc/breath_scan_action(mob/living/target, mob/living/user, obj/scanner, var/verbose) + if (!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS) || !istype(target)) + return + + . = breath_scan_results(target, verbose, user.get_skill_value(SKILL_MEDICAL)) + to_chat(user, "
    ") + to_chat(user, .) + to_chat(user, "
    ") + +/proc/breath_scan_results(var/mob/living/target, var/verbose, var/skill_level = SKILL_DEFAULT) + . = list() + var/header = list() + var/b + var/endb + var/dat = list() + + if(skill_level >= SKILL_BASIC) + header += "" + header += "" + header += "" + header += "" + header += "" + header += "" + header += "" + b = "" + endb = "" + + . += "[b]Breath sample results for \the [target]:[endb]" + + var/obj/item/organ/internal/lungs/lungs = target.get_organ(BP_LUNGS) + var/breathing = "none" + if(istype(lungs) && !(target.status_flags & FAKEDEATH)) + if(lungs.breath_fail_ratio < 0.3) + breathing = "normal" + else if(lungs.breath_fail_ratio < 1) + breathing = "shallow" + + var/has_breath = TRUE + switch(breathing) + if("none") + . += "Alert: No breathing detected." + has_breath = FALSE + if("shallow") + . += "Subject's breathing is abnormally shallow." + if("normal") + . += "Subject's breathing is normal." + + // Other general warnings. + if(skill_level >= SKILL_BASIC) + switch(target.get_damage(OXY)) + if(0 to 25) + dat += "Subject oxygen levels nominal." + if(25 to 50) + dat += "Subject oxygen levels abnormal." + if(50 to INFINITY) + dat += "[b]Severe oxygen deprivation detected.[endb]" + + if(istype(lungs)) + if(lungs.is_broken()) + dat += "[b]Tension pneumothorax detected.[endb]" + else if(lungs.is_bruised()) + dat += "Collapsed lung detected." + else + dat += "Subject lung health nominal." + else + dat += "Subject lung health unknown." + + . += (skill_level < SKILL_BASIC) ? shuffle(dat) : dat + + // Reagent data. + . += "[b]Reagent scan:[endb]" + + if(has_breath) + var/print_reagent_default_message = TRUE + if (target.has_chemical_effect(CE_ALCOHOL, 1)) + . += "Alcohol detected in subject's breath." + print_reagent_default_message = FALSE + if (target.has_chemical_effect(CE_ALCOHOL_TOXIC, 1)) + . += "Subject is suffering from alcohol poisoning." + print_reagent_default_message = FALSE + + var/datum/reagents/inhaled = target.get_inhaled_reagents() + if(inhaled && REAGENT_TOTAL_VOLUME(inhaled)) + var/unknown = 0 + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(inhaled)) + if(reagent.scannable) + print_reagent_default_message = FALSE + . += "[capitalize(reagent.gas_name)] found in subject's breath." + else + ++unknown + if(unknown) + print_reagent_default_message = FALSE + . += "Non-medical reagent[(unknown > 1)?"s":""] found in subject's breath." + + if(print_reagent_default_message) + . += "No results." + else + . += "Unable to obtain breath sample!" + + header = jointext(header, null) + . = jointext(.,"
    ") + . = jointext(list(header,.),null) \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/gas.dm b/code/modules/scanners/gas.dm similarity index 88% rename from code/game/objects/items/devices/scanners/gas.dm rename to code/modules/scanners/gas.dm index 35ccfaac395e..397ea46d74bf 100644 --- a/code/game/objects/items/devices/scanners/gas.dm +++ b/code/modules/scanners/gas.dm @@ -6,16 +6,13 @@ name = "gas analyzer" desc = "A hand-held environmental scanner which reports current gas levels. Has a button to cycle modes." icon = 'icons/obj/items/device/scanner/atmos_scanner.dmi' - icon_state = "atmos" - item_state = "analyzer" - - origin_tech = "{'magnets':1,'engineering':1}" + origin_tech = @'{"magnets":1,"engineering":1}' window_width = 350 window_height = 400 var/mode = DEFAULT_MODE /obj/item/scanner/gas/get_header() - return "[..()]Switch Mode" + return "[..()]Switch Mode" /obj/item/scanner/gas/OnTopic(var/user, var/list/href_list) ..() @@ -64,7 +61,7 @@ var/percentage = round(mixture.gas[mix]/total_moles * 100, 0.01) if(!percentage) continue - var/decl/material/mat = decls_repository.get_decl(mix) + var/decl/material/mat = GET_DECL(mix) switch(mode) if(MV_MODE) perGas_add_string = ", Moles: [round(mixture.gas[mix], 0.01)]" @@ -78,11 +75,11 @@ traits += "contaminates clothing with toxic residue" if(mat.flags & MAT_FLAG_FUSION_FUEL) traits += "can be used to fuel fusion reaction" - perGas_add_string = "\n\tSpecific heat: [mat.gas_specific_heat] J/(mol*K), Molar mass: [mat.gas_molar_mass] kg/mol.[traits.len ? "\n\tThis gas [english_list(traits)]" : ""]" + perGas_add_string = "\n\tSpecific heat: [mat.gas_specific_heat] J/(mol*K), Molar mass: [mat.molar_mass] kg/mol.[traits.len ? "\n\tThis gas [english_list(traits)]" : ""]" . += "[capitalize(mat.gas_name)]: [percentage]%[perGas_add_string]" var/totalGas_add_string = "" if(mode == MV_MODE) - totalGas_add_string = ", Total moles: [round(mixture.total_moles, 0.01)], Volume: [mixture.volume]L" + totalGas_add_string = ", Total moles: [round(mixture.total_moles, 0.01)], Volume: [mixture.total_volume]L" . += "Temperature: [round(mixture.temperature-T0C)]°C / [round(mixture.temperature)]K[totalGas_add_string]" return diff --git a/code/game/objects/items/devices/scanners/health.dm b/code/modules/scanners/health.dm similarity index 81% rename from code/game/objects/items/devices/scanners/health.dm rename to code/modules/scanners/health.dm index 07e08ddd71a8..99d49d6bb72c 100644 --- a/code/game/objects/items/devices/scanners/health.dm +++ b/code/modules/scanners/health.dm @@ -2,16 +2,14 @@ name = "health analyzer" desc = "A hand-held body scanner able to distinguish vital signs of the subject." icon = 'icons/obj/items/device/scanner/health_scanner.dmi' - icon_state = "health" - item_state = "analyzer" item_flags = ITEM_FLAG_NO_BLUDGEON material = /decl/material/solid/metal/aluminium - origin_tech = "{'magnets':1,'biotech':1}" + origin_tech = @'{"magnets":1,"biotech":1}' printout_color = "#deebff" var/mode = 1 /obj/item/scanner/health/is_valid_scan_target(atom/O) - return istype(O, /mob/living/carbon/human) || istype(O, /obj/structure/closet/body_bag) + return ishuman(O) || istype(O, /obj/structure/closet/body_bag) /obj/item/scanner/health/scan(atom/A, mob/user) scan_data = medical_scan_action(A, user, src, mode) @@ -21,14 +19,14 @@ if (!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) return - if ((MUTATION_CLUMSY in user.mutations) && prob(50)) + if (user.has_genetic_condition(GENE_COND_CLUMSY) && prob(50)) user.visible_message("\The [user] runs \the [scanner] over the floor.") to_chat(user, "Scan results for the floor:") to_chat(user, "Overall Status: Healthy") return - var/mob/living/carbon/human/scan_subject = null - if (istype(target, /mob/living/carbon/human)) + var/mob/living/human/scan_subject = null + if (ishuman(target)) scan_subject = target else if (istype(target, /obj/structure/closet/body_bag)) var/obj/structure/closet/body_bag/B = target @@ -38,7 +36,7 @@ scan_content.Add(L) if (scan_content.len == 1) - for(var/mob/living/carbon/human/L in scan_content) + for(var/mob/living/human/L in scan_content) scan_subject = L else if (scan_content.len > 1) to_chat(user, "\The [scanner] picks up multiple readings inside \the [target], too close together to scan properly.") @@ -59,7 +57,7 @@ to_chat(user, .) to_chat(user, "
    ") -/proc/medical_scan_results(var/mob/living/carbon/human/H, var/verbose, var/skill_level = SKILL_DEFAULT) +/proc/medical_scan_results(var/mob/living/human/H, var/verbose, var/skill_level = SKILL_DEFAULT) . = list() var/header = list() var/b @@ -82,7 +80,7 @@ // Brain activity. var/brain_result = "normal" if(H.should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[BP_BRAIN] + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(H, BP_BRAIN) if(!brain || H.stat == DEAD || (H.status_flags & FAKEDEATH)) brain_result = "none, patient is braindead" else if(H.stat != DEAD) @@ -117,13 +115,13 @@ if(H.status_flags & FAKEDEATH) pulse_result = 0 else - pulse_result = H.get_pulse(GETPULSE_TOOL) + pulse_result = H.get_pulse_as_string(GETPULSE_TOOL) pulse_result = "[pulse_result]bpm" - if(H.pulse() == PULSE_NONE) + if(H.get_pulse() == PULSE_NONE) pulse_result = "[pulse_result]" - else if(H.pulse() < PULSE_NORM) + else if(H.get_pulse() < PULSE_NORM) pulse_result = "[pulse_result]" - else if(H.pulse() > PULSE_NORM) + else if(H.get_pulse() > PULSE_NORM) pulse_result = "[pulse_result]" else pulse_result = "ERROR - Nonstandard biology" @@ -173,18 +171,17 @@ // Other general warnings. if(skill_level >= SKILL_BASIC) - if(H.getOxyLoss() > 50) + if(H.getOxyLossPercent() > 50) dat += "[b]Severe oxygen deprivation detected.[endb]" - if(H.getToxLoss() > 50) + if(H.get_damage(TOX) > 50) dat += "[b]Major systemic organ failure detected.[endb]" - if(H.getFireLoss() > 50) + if(H.get_damage(BURN) > 50) dat += "[b]Severe burn damage detected.[endb]" - if(H.getBruteLoss() > 50) + if(H.get_damage(BRUTE) > 50) dat += "[b]Severe anatomical damage detected.[endb]" if(skill_level >= SKILL_BASIC) - for(var/name in H.organs_by_name) - var/obj/item/organ/external/e = H.organs_by_name[name] + for(var/obj/item/organ/external/e in H.get_external_organs()) if(!e) continue var/limb = e.name @@ -196,8 +193,7 @@ if(e.has_growths()) dat += "Abnormal internal growths detected in subject [limb]. Surgical removal recommended." - for(var/name in H.organs_by_name) - var/obj/item/organ/external/e = H.organs_by_name[name] + for(var/obj/item/organ/external/e in H.get_external_organs()) if(e && e.status & ORGAN_BROKEN) dat += "Bone fractures detected. Advanced scanner required for location." break @@ -205,9 +201,9 @@ var/found_bleed var/found_tendon var/found_disloc - for(var/obj/item/organ/external/e in H.organs) + for(var/obj/item/organ/external/e in H.get_external_organs()) if(e) - if(!found_disloc && e.dislocated == 2) + if(!found_disloc && e.is_dislocated()) dat += "Dislocation detected. Advanced scanner required for location." found_disloc = TRUE if(!found_bleed && (e.status & ORGAN_ARTERY_CUT)) @@ -245,14 +241,13 @@ . += "[b]Reagent scan:[endb]" var/print_reagent_default_message = TRUE - if(H.reagents.total_volume) + if(REAGENT_TOTAL_VOLUME(H.reagents)) var/unknown = 0 var/reagentdata[0] - for(var/A in H.reagents.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(A) - if(R.scannable) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(H.reagents)) + if(reagent.scannable) print_reagent_default_message = FALSE - reagentdata[A] = "[round(REAGENT_VOLUME(H.reagents, A), 1)]u [R.name]" + reagentdata[reagent.type] = "[round(REAGENT_VOLUME(H.reagents, reagent), 1)]u [reagent.use_name]" else unknown++ if(reagentdata.len) @@ -264,14 +259,14 @@ print_reagent_default_message = FALSE . += "Warning: Unknown substance[(unknown>1)?"s":""] detected in subject's blood." - if(H.touching.total_volume) + var/datum/reagents/touching_reagents = H.get_contact_reagents() + if(touching_reagents && REAGENT_TOTAL_VOLUME(touching_reagents)) var/unknown = 0 var/reagentdata[0] - for(var/A in H.touching.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(A) - if(R.scannable) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(touching_reagents)) + if(reagent.scannable) print_reagent_default_message = FALSE - reagentdata[R.type] = "[round(REAGENT_VOLUME(H.reagents, R.type), 1)]u [R.name]" + reagentdata[reagent.type] = "[round(REAGENT_VOLUME(H.reagents, reagent), 1)]u [reagent.name]" else unknown++ if(reagentdata.len) @@ -284,25 +279,36 @@ . += "Warning: Unknown substance[(unknown>1)?"s":""] detected on subject's body." var/datum/reagents/ingested = H.get_ingested_reagents() - if(ingested && ingested.total_volume) + if(ingested && REAGENT_TOTAL_VOLUME(ingested)) var/unknown = 0 - for(var/rtype in ingested.reagent_volumes) - var/decl/material/R = decls_repository.get_decl(rtype) - if(R.scannable) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(ingested)) + if(reagent.scannable) print_reagent_default_message = FALSE - . += "[R.name] found in subject's stomach." + . += "[capitalize(reagent.use_name)] found in subject's stomach." else ++unknown if(unknown) print_reagent_default_message = FALSE . += "Non-medical reagent[(unknown > 1)?"s":""] found in subject's stomach." - if(H.chem_doses.len) + var/datum/reagents/inhaled = H.get_inhaled_reagents() + if(inhaled && REAGENT_TOTAL_VOLUME(inhaled)) + var/unknown = 0 + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(inhaled)) + if(reagent.scannable) + print_reagent_default_message = FALSE + . += "[capitalize(reagent.use_name)] found in subject's lungs." + else + ++unknown + if(unknown) + print_reagent_default_message = FALSE + . += "Non-medical reagent[(unknown > 1)?"s":""] found in subject's lungs." + + if(length(H._chem_doses)) var/list/chemtraces = list() - for(var/T in H.chem_doses) - var/decl/material/R = T - if(initial(R.scannable)) - chemtraces += "[initial(R.name)] ([H.chem_doses[T]])" + for(var/decl/material/reagent in H._chem_doses) + if(reagent.scannable) + chemtraces += "[reagent.use_name] ([CHEM_DOSE(H, reagent)])" if(chemtraces.len) . += "Metabolism products of [english_list(chemtraces)] found in subject's system." @@ -314,7 +320,7 @@ . = jointext(list(header,.),null) // Calculates severity based on the ratios defined external limbs. -proc/get_wound_severity(var/damage_ratio, var/can_heal_overkill = 0) +/proc/get_wound_severity(var/damage_ratio, var/can_heal_overkill = 0) var/degree switch(damage_ratio) diff --git a/code/modules/scanners/mass_spectrometer.dm b/code/modules/scanners/mass_spectrometer.dm new file mode 100644 index 000000000000..6d66cacddbe4 --- /dev/null +++ b/code/modules/scanners/mass_spectrometer.dm @@ -0,0 +1,84 @@ +/obj/item/scanner/spectrometer + name = "mass spectrometer" + desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample or analyzes unusual chemicals." + icon = 'icons/obj/items/device/scanner/spectrometer.dmi' + atom_flags = ATOM_FLAG_OPEN_CONTAINER + origin_tech = @'{"magnets":2,"biotech":2}' + window_width = 550 + window_height = 300 + scan_sound = 'sound/effects/scanbeep.ogg' + chem_volume = 5 + var/details = 0 + +/obj/item/scanner/spectrometer/on_reagent_change() + if((. = ..())) + update_icon() + +/obj/item/scanner/spectrometer/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(REAGENT_TOTAL_VOLUME(reagents)) + icon_state += "_loaded" + +/obj/item/scanner/spectrometer/is_valid_scan_target(atom/O) + if(!O.reagents || !REAGENT_TOTAL_VOLUME(O.reagents)) + return FALSE + return (O.atom_flags & ATOM_FLAG_OPEN_CONTAINER) || istype(O, /obj/item/chems/syringe) + +/obj/item/scanner/spectrometer/scan(atom/A, mob/user) + if(A != src) + to_chat(user, "\The [src] takes a sample out of \the [A]") + reagents.clear_reagents() + A.reagents.trans_to(src, 5) + scan_title = "Spectrometer scan - [A]" + scan_data = mass_spectrometer_scan(reagents, user, details) + reagents.clear_reagents() + user.show_message(scan_data) + +/obj/item/scanner/spectrometer/attack_self(mob/user) + if(!can_use(user)) + return + if(REAGENT_TOTAL_VOLUME(reagents)) + scan(src, user) + else + ..() + +/proc/mass_spectrometer_scan(var/datum/reagents/reagents, mob/user, var/details) + if(!REAGENT_TOTAL_VOLUME(reagents)) + return SPAN_WARNING("No sample to scan.") + var/list/blood_traces = list() + var/list/blood_doses = list() + + var/decl/material/liquid/random/random = reagents.get_primary_reagent_decl() + if(length(REAGENT_VOLUMES(reagents)) == 1 && istype(random)) + return random.get_scan_data(user) + + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + if(!istype(reagent, /decl/material/liquid/blood)) + return SPAN_WARNING("The sample was contaminated! Please insert another sample.") + var/data = REAGENT_DATA(reagents, reagent) + if(islist(data)) + blood_traces = data[DATA_BLOOD_TRACE_CHEM] + blood_doses = data[DATA_BLOOD_DOSE_CHEM] + break + + var/list/dat = list("Trace Chemicals Found: ") + for(var/trace_type in blood_traces) + var/decl/material/trace_material = GET_DECL(trace_type) + if(details) + dat += "[trace_material.use_name] ([blood_traces[trace_type]] units) " + else + dat += "[trace_material.use_name] " + if(details) + dat += "Metabolism Products of Chemicals Found:" + for(var/dose_type in blood_doses) + var/decl/material/dose_material = GET_DECL(dose_type) + dat += "[dose_material.use_name] ([blood_doses[dose_type]] units) " + + return jointext(dat, "
    ") + +/obj/item/scanner/spectrometer/adv + name = "advanced mass spectrometer" + icon = 'icons/obj/items/device/scanner/advanced_spectrometer.dmi' + details = 1 + origin_tech = @'{"magnets":4,"biotech":2}' \ No newline at end of file diff --git a/code/modules/scanners/mining.dm b/code/modules/scanners/mining.dm new file mode 100644 index 000000000000..9da785d77ced --- /dev/null +++ b/code/modules/scanners/mining.dm @@ -0,0 +1,101 @@ +/datum/extension/buried_resources + base_type = /datum/extension/buried_resources + expected_type = /turf + var/list/resources + var/surveyed = FALSE + +/datum/extension/buried_resources/New(datum/holder, list/resource_list) + resources = resource_list + ..() + +/obj/item/scanner/mining + name = "ore detector" + desc = "A complex device used to locate ore deep underground." + icon = 'icons/obj/items/device/scanner/ore_scanner.dmi' + origin_tech = @'{"magnets":1,"engineering":1}' + use_delay = 50 + printout_color = "#fff7f0" + scan_sound = 'sound/effects/ping.ogg' + var/survey_data = 0 + +/obj/item/scanner/mining/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "A tiny indicator on \the [src] shows it holds [survey_data] survey point\s." + +/obj/item/scanner/mining/is_valid_scan_target(turf/T) + return istype(T) + +/obj/item/scanner/mining/scan(turf/T, mob/user) + scan_title = "Mineral scan data" + var/list/scan_results = mineral_scan_results(T) + if(!scan_data) + scan_data = scan_results[1] + else + scan_data += "
    [scan_results[1]]" + to_chat(user, SPAN_NOTICE("[html_icon(src)] \The [src] displays a readout.")) + to_chat(user, scan_results[1]) + + if(scan_results[2]) + survey_data += scan_results[2] + playsound(loc, 'sound/machines/ping.ogg', 40, 1) + to_chat(user, SPAN_NOTICE("New survey data stored - earned [scan_results[2]] survey points.")) + +/obj/item/scanner/mining/proc/put_disk_in_hand(var/mob/M) + if(!survey_data) + to_chat(M, SPAN_WARNING("There is no survey data stored on \the [src].")) + return FALSE + visible_message(SPAN_NOTICE("\The [src] spits out a disk containing [survey_data] survey points.")) + var/obj/item/disk/survey/D = new(get_turf(src)) + D.data = survey_data + survey_data = 0 + M.put_in_hands(D) + return 1 + +/obj/item/scanner/mining/verb/get_data() + set category = "Object" + set name = "Get Survey Data" + set src in usr + + var/mob/M = usr + if(!istype(M)) + return + if(M.incapacitated()) + return + put_disk_in_hand(M) + +//Returns list of two elements, 1 is text output, 2 is amoutn of GEP data +/proc/mineral_scan_results(turf/target) + var/list/metals = list( + ORE_SURFACE = 0, + ORE_PRECIOUS = 0, + ORE_NUCLEAR = 0, + ORE_EXOTIC = 0 + ) + var/new_data = 0 + + for(var/turf/T in range(2, target)) + + var/datum/extension/buried_resources/resources = get_extension(T, /datum/extension/buried_resources) + if(!length(resources?.resources)) + continue + + for(var/metal in resources.resources) + var/decl/material/mat = GET_DECL(metal) + if(mat.ore_type_value) + metals[mat.ore_type_value] += resources.resources[metal] + if(mat.ore_data_value && !resources.surveyed) + new_data += mat.ore_data_value * resources.resources[metal] + resources.surveyed = TRUE + + var/list/scandata = list("Mineral scan at ([target.x],[target.y])") + for(var/ore_type in metals) + var/result = "no sign" + + switch(metals[ore_type]) + if(1 to 25) result = "trace amounts" + if(26 to 75) result = "significant amounts" + if(76 to INFINITY) result = "huge quantities" + + scandata += "- [result] of [ore_type]." + + return list(jointext(scandata, "
    "), new_data) \ No newline at end of file diff --git a/code/modules/scanners/network.dm b/code/modules/scanners/network.dm new file mode 100644 index 000000000000..e96a840d7e59 --- /dev/null +++ b/code/modules/scanners/network.dm @@ -0,0 +1,37 @@ +/obj/item/scanner/network + name = "network analyzer" + desc = "A hand-held network scanner which detects nearby network devices and returns information about them." + icon = 'icons/obj/items/device/scanner/network_scanner.dmi' + origin_tech = @'{"magnets":1,"engineering":1}' + window_width = 350 + window_height = 400 + +/obj/item/scanner/network/is_valid_scan_target(atom/A) + return istype(A) + +/obj/item/scanner/network/scan(atom/A, mob/user) + scan_title = "Network scan data" + + scan_data = network_scan_results(A) + scan_data = jointext(scan_data, "
    ") + user.show_message(SPAN_NOTICE(scan_data)) + +/proc/network_scan_results(atom/target) + var/list/found_devices = list() + var/target_device = get_extension(target, /datum/extension/network_device) + if(target_device) found_devices |= target_device + + for(var/obj/thing in target.contents) + var/thing_device = get_extension(thing, /datum/extension/network_device) + if(thing_device) found_devices |= thing_device + + if(!length(found_devices)) + return "No network devices found!" + . = list() + . += "Results of the analysis of \the [target]:" + for(var/datum/extension/network_device/device in found_devices) + . += "*----------------------*" + . += "Network Tag: [device.network_tag]" + . += "Network Address: [device.address]" + . += "Connected to: [device.network_id]" + . += "*----------------------*" \ No newline at end of file diff --git a/code/modules/scanners/plant.dm b/code/modules/scanners/plant.dm new file mode 100644 index 000000000000..fc532715c6ad --- /dev/null +++ b/code/modules/scanners/plant.dm @@ -0,0 +1,94 @@ + +/obj/item/scanner/plant + name = "plant analyzer" + desc = "A hand-held botanical scanner used to analyze plants." + icon = 'icons/obj/items/device/scanner/plant_scanner.dmi' + scan_sound = 'sound/effects/fastbeep.ogg' + printout_color = "#eeffe8" + var/static/list/valid_targets = list( + /obj/item/food/grown, + /obj/machinery/portable_atmospherics/hydroponics, + /obj/item/seeds, + /obj/structure/flora/plant + ) + +/obj/item/scanner/plant/is_valid_scan_target(atom/O) + if(is_type_in_list(O, valid_targets)) + return TRUE + return FALSE + +/obj/item/scanner/plant/scan(atom/A, mob/user) + scan_title = "[A] at [get_area_name(A)]" + scan_data = plant_scan_results(A) + show_menu(user) + +/proc/plant_scan_results(obj/target) + + var/datum/seed/grown_seed + var/datum/reagents/grown_reagents + if(istype(target,/obj/item/food/grown)) + var/obj/item/food/grown/G = target + grown_seed = G.seed + grown_reagents = G.reagents + else if(istype(target,/obj/item/seeds)) + var/obj/item/seeds/S = target + grown_seed = S.seed + else if(istype(target,/obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/H = target + grown_seed = H.seed + grown_reagents = H.reagents + else if(istype(target,/obj/structure/flora/plant)) + var/obj/structure/flora/plant/P = target + grown_seed = P.plant + + if(!grown_seed) + return + + if(grown_seed.mysterious && !grown_seed.scanned) + grown_seed.scanned = TRUE + for(var/planetoid_id in SSmapping.planetoid_data_by_id) + var/datum/planetoid_data/P = SSmapping.planetoid_data_by_id[planetoid_id] + if(P.is_native_plant(grown_seed)) + SSstatistics.add_field(STAT_XENOPLANTS_SCANNED, 1) + break + + var/list/dat = list() + + var/form_title = "[grown_seed.product_name] (#[grown_seed.uid])" + dat += "

    Plant data for [form_title]

    " + + var/list/general_data = list() + var/list/extended_trait_data = list() + + if(length(grown_seed.mutants)) + extended_trait_data += "It exhibits a high degree of potential subspecies shift." + + for(var/decl/plant_trait/plant_trait in decls_repository.get_decls_of_subtype_unassociated(/decl/plant_trait)) + if(plant_trait.shows_general_data) + general_data[plant_trait.name] = grown_seed.get_trait(plant_trait.type) + if(plant_trait.shows_extended_data) + var/extended_data = plant_trait.get_extended_data(grown_seed.get_trait(plant_trait.type), grown_seed) + if(extended_data) + extended_trait_data += extended_data + + dat += "

    General Data

    " + dat += "" + if(length(general_data)) + for(var/trait_name in general_data) + dat += "" + dat += "
    [uppertext(trait_name)][general_data[trait_name]]
    " + + var/grown_volumes = REAGENT_VOLUMES(grown_reagents) + if(LAZYLEN(grown_volumes)) + dat += "

    Reagent Data

    " + dat += "
    This sample contains: " + for(var/decl/material/reagent as anything in REAGENT_LIQUID_VOLUMES(grown_reagents)) + dat += "
    - [reagent.get_reagent_name(grown_reagents, MAT_PHASE_LIQUID)], [LIQUID_VOLUME(grown_reagents, reagent)] unit(s)" + for(var/decl/material/reagent as anything in REAGENT_SOLID_VOLUMES(grown_reagents)) + dat += "
    - [reagent.get_reagent_name(grown_reagents, MAT_PHASE_SOLID)], [SOLID_VOLUME(grown_reagents, reagent)] unit(s)" + + dat += "

    Other Data

    " + if(length(extended_trait_data)) + dat += jointext(extended_trait_data, "
    ") + + return JOINTEXT(dat) \ No newline at end of file diff --git a/code/game/objects/items/devices/scanners/price.dm b/code/modules/scanners/price.dm similarity index 78% rename from code/game/objects/items/devices/scanners/price.dm rename to code/modules/scanners/price.dm index 0a71195dbd2c..0f8c0c7036d8 100644 --- a/code/game/objects/items/devices/scanners/price.dm +++ b/code/modules/scanners/price.dm @@ -2,12 +2,11 @@ name = "price scanner" desc = "Using an up-to-date database of various costs and prices, this device estimates the market price of an item up to 0.001% accuracy." icon = 'icons/obj/items/device/scanner/price_scanner.dmi' - icon_state = "price_scanner" - origin_tech = "{'materials':6,'magnets':4}" + origin_tech = @'{"materials":6,"magnets":4}' scan_sound = 'sound/effects/checkout.ogg' material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) var/scanner_currency @@ -15,14 +14,14 @@ /obj/item/scanner/price/Initialize(ml, material_key) . = ..() if(!ispath(scanner_currency, /decl/currency)) - scanner_currency = GLOB.using_map.default_currency + scanner_currency = global.using_map.default_currency /obj/item/scanner/price/is_valid_scan_target(atom/movable/target) return istype(target) && target.get_combined_monetary_worth() > 0 /obj/item/scanner/price/scan(atom/movable/target, mob/user) scan_title = "Price estimations" - var/decl/currency/cur = decls_repository.get_decl(scanner_currency) + var/decl/currency/cur = GET_DECL(scanner_currency) var/data = "\The [target]: [cur.format_value(target.get_combined_monetary_worth())]" if(!scan_data) scan_data = data diff --git a/code/modules/scanners/reagents.dm b/code/modules/scanners/reagents.dm new file mode 100644 index 000000000000..3252aea81854 --- /dev/null +++ b/code/modules/scanners/reagents.dm @@ -0,0 +1,32 @@ +/obj/item/scanner/reagent + name = "reagent scanner" + desc = "A hand-held reagent scanner which identifies chemical agents." + icon = 'icons/obj/items/device/scanner/spectrometer.dmi' + origin_tech = @'{"magnets":2,"biotech":2}' + scan_sound = 'sound/effects/scanbeep.ogg' + var/details = 0 + +/obj/item/scanner/reagent/is_valid_scan_target(obj/O) + return istype(O) + +/obj/item/scanner/reagent/scan(obj/O, mob/user) + scan_data = reagent_scan_results(O, details) + scan_data = jointext(scan_data, "
    ") + user.show_message(SPAN_NOTICE(scan_data)) + +/proc/reagent_scan_results(obj/O, details = 0) + if(isnull(O.reagents)) + return list("No significant chemical agents found in [O].") + var/chem_volumes = REAGENT_VOLUMES(O.reagents) + if(!LAZYLEN(chem_volumes)) + return list("No active chemical agents found in [O].") + . = list("Chemicals found in [O]:") + var/one_percent = REAGENT_TOTAL_VOLUME(O.reagents) / 100 + for (var/decl/material/reagent as anything in REAGENT_VOLUMES(O.reagents)) + . += "[reagent.name][details ? ": [REAGENT_VOLUME(O.reagents, reagent) / one_percent]%" : ""]" + +/obj/item/scanner/reagent/adv + name = "advanced reagent scanner" + icon = 'icons/obj/items/device/scanner/advanced_spectrometer.dmi' + details = 1 + origin_tech = @'{"magnets":4,"biotech":2}' \ No newline at end of file diff --git a/code/modules/scanners/xenobio.dm b/code/modules/scanners/xenobio.dm new file mode 100644 index 000000000000..b7afc80b7a63 --- /dev/null +++ b/code/modules/scanners/xenobio.dm @@ -0,0 +1,71 @@ +/obj/item/scanner/xenobio + name = "xenolife scanner" + desc = "Multipurpose organic life scanner. With spectral breath analyzer you can find out what snacks Ian had! Or what gasses alien life breathes." + icon = 'icons/obj/items/device/scanner/xenobio_scanner.dmi' + icon_state = ICON_STATE_WORLD + scan_sound = 'sound/effects/scanbeep.ogg' + printout_color = "#f3e6ff" + origin_tech = @'{"magnets":1,"biotech":1}' + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE + ) + + var/list/valid_targets = list( + /mob/living/human, + /mob/living/simple_animal + ) + +/obj/item/scanner/xenobio/is_valid_scan_target(atom/O) + if(is_type_in_list(O, valid_targets)) + return TRUE + return FALSE + +/obj/item/scanner/xenobio/scan(mob/O, mob/user) + scan_title = O.name + scan_data = O.xenobio_scan_results() + user.show_message(SPAN_NOTICE(scan_data)) + +/proc/list_gases(var/gases) + . = list() + for(var/g in gases) + var/decl/material/mat = GET_DECL(g) + . += "[capitalize(mat.gas_name)] ([gases[g]]%)" + return english_list(.) + +/mob/proc/xenobio_scan_results() + . = "Incompatible life form, analysis failed." + +/mob/living/human/xenobio_scan_results() + . += "Data for \the [src]:" + . += "Species:\t[species]" + if(species.breath_type) + var/decl/material/mat = GET_DECL(species.breath_type) + . += "Breathes:\t[mat.gas_name]" + if(species.exhale_type) + var/decl/material/mat = GET_DECL(species.exhale_type) + . += "Exhales:\t[mat.gas_name]" + . += "Known toxins:\t[english_list(species.poison_types)]" + var/decl/bodytype/root_bodytype = get_bodytype() + if(root_bodytype) + . += "Temperature comfort zone:\t[root_bodytype.cold_discomfort_level] K to [root_bodytype.heat_discomfort_level] K" + . += "Pressure comfort zone:\t[species.get_warning_low_pressure(src)] kPa to [species.get_warning_high_pressure(src)] kPa" + . = jointext(., "
    ") + +/mob/living/simple_animal/xenobio_scan_results() + . += "Data for \the [src]:" + . += "Species:\t[initial(name)]" + . += "Breathes:\t[list_gases(min_gas)]" + . += "Known toxins:\t[list_gases(max_gas)]" + . += "Temperature comfort zone:\t[minbodytemp] K to [maxbodytemp] K" + + for(var/planet_id in SSmapping.planetoid_data_by_id) + var/datum/planetoid_data/P = SSmapping.planetoid_data_by_id[planet_id] + if(P.is_native_animal(src)) + var/list/discovered = SSstatistics.get_field(STAT_XENOFAUNA_SCANNED) + LAZYDISTINCTADD(discovered, "[P.name]-[type]") + SSstatistics.set_field(STAT_XENOFAUNA_SCANNED, discovered) + . += "New xenofauna species discovered!" + break + . = jointext(., "
    ") diff --git a/code/modules/scent/_scent.dm b/code/modules/scent/_scent.dm new file mode 100644 index 000000000000..9af54db56df2 --- /dev/null +++ b/code/modules/scent/_scent.dm @@ -0,0 +1,139 @@ +/***** +Scent intensity +*****/ +/decl/scent_intensity + var/cooldown = 5 MINUTES + var/intensity = 1 + +/decl/scent_intensity/proc/PrintMessage(var/mob/user, var/descriptor, var/scent) + to_chat(user, SPAN_SUBTLE("The subtle [descriptor] of [scent] tickles your nose...")) + +/decl/scent_intensity/normal + cooldown = 4 MINUTES + intensity = 2 + +/decl/scent_intensity/normal/PrintMessage(var/mob/user, var/descriptor, var/scent) + to_chat(user, SPAN_NOTICE("The [descriptor] of [scent] fills the air.")) + +/decl/scent_intensity/strong + cooldown = 3 MINUTES + intensity = 3 + +/decl/scent_intensity/strong/PrintMessage(var/mob/user, var/descriptor, var/scent) + to_chat(user, SPAN_WARNING("The unmistakable [descriptor] of [scent] bombards your nostrils.")) + +/***** + Scent extensions + Usage: + To add: + set_extension(atom, /datum/extension/scent/PATH/TO/SPECIFIC/SCENT) + This will set up the extension and will make it begin to emit_scent. + To remove: + remove_extension(atom, /datum/extension/scent) +*****/ + +/datum/extension/scent + base_type = /datum/extension/scent + expected_type = /atom + flags = EXTENSION_FLAG_IMMEDIATE + + var/scent = "something" + var/decl/scent_intensity/intensity = /decl/scent_intensity + var/descriptor = "smell" //unambiguous descriptor of smell; food is generally good, sewage is generally bad. how 'nice' the scent is + var/range = 1 //range in tiles + +/datum/extension/scent/New() + ..() + if(ispath(intensity)) + intensity = GET_DECL(intensity) + START_PROCESSING(SSprocessing, src) + +/datum/extension/scent/Destroy() + STOP_PROCESSING(SSprocessing, src) + . = ..() + +/datum/extension/scent/Process() + if(!holder) + PRINT_STACK_TRACE("Scent extension with scent '[scent]', intensity '[intensity]', descriptor '[descriptor]' and range of '[range]' attempted to emit_scent() without a holder.") + qdel(src) + return PROCESS_KILL + emit_scent() + +/datum/extension/scent/proc/check_smeller(var/mob/living/smeller) + if(!istype(smeller) || smeller.stat != CONSCIOUS || smeller.failed_last_breath) + return FALSE + if(smeller.get_equipped_item(slot_wear_mask_str)) + return FALSE + var/obj/item/head = smeller.get_equipped_item(slot_head_str) + if(head?.permeability_coefficient < 1) + return FALSE + return TRUE + +/datum/extension/scent/proc/emit_scent() + for(var/mob/living/M in all_hearers(holder, range)) + var/turf/T = get_turf(M.loc) + if(!T) + continue + if(!check_smeller(M) || !T.return_air()) + continue + show_smell(M) + +/datum/extension/scent/proc/show_smell(var/mob/living/smeller) + if(LAZYACCESS(smeller.smell_cooldown, scent) < world.time) + intensity.PrintMessage(smeller, descriptor, scent) + LAZYSET(smeller.smell_cooldown, scent, world.time + intensity.cooldown) + +/datum/extension/scent/PopulateClone(datum/extension/scent/clone) + var/datum/extension/scent/populated_clone = ..() + populated_clone.scent = scent + populated_clone.intensity = intensity + populated_clone.descriptor = descriptor + populated_clone.range = range + return populated_clone + +/***** +Custom subtype + set_extension(atom, /datum/extension/scent/custom, scent = "scent", intensity = SCENT_INTENSITY_, ... etc) +This will let you set an extension without needing to define it beforehand. Note that all vars are required if generating. +*****/ +/datum/extension/scent/custom/New(var/datum/holder, var/provided_scent, var/provided_intensity, var/provided_descriptor, var/provided_range) + ..() + if(provided_scent && provided_intensity && provided_descriptor && provided_range) + scent = provided_scent + if(ispath(provided_intensity)) + intensity = GET_DECL(provided_intensity) + descriptor = provided_descriptor + range = provided_range + else + CRASH("Attempted to generate a scent extension on [holder], but at least one of the required vars was not provided.") + +/***** +Reagents have the following vars, which coorelate to the vars on the standard scent extension: + scent, + scent_intensity, + scent_descriptor, + scent_range +To add a scent extension to an atom using a reagent's info, where reagent. is the reagent, use set_scent_by_reagents(). +*****/ + +/proc/set_scent_by_reagents(var/atom/smelly_atom) + var/decl/material/smelliest = get_smelliest_reagent(smelly_atom.reagents) + if(smelliest) + set_extension(smelly_atom, /datum/extension/scent/custom, smelliest.scent, smelliest.scent_intensity, smelliest.scent_descriptor, smelliest.scent_range) + +// Returns the smelliest reagent of a reagent holder. +/proc/get_smelliest_reagent(var/datum/reagents/holder) + var/decl/material/smelliest + var/scent_intensity + if(!holder || !REAGENT_TOTAL_VOLUME(holder)) + return + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(holder)) + if(!reagent.scent) + continue + var/decl/scent_intensity/scent = GET_DECL(reagent.scent_intensity) + var/r_scent_intensity = REAGENT_VOLUME(holder, reagent) * scent.intensity + if(r_scent_intensity > scent_intensity) + smelliest = reagent + scent_intensity = r_scent_intensity + + return smelliest \ No newline at end of file diff --git a/code/datums/extensions/scent/scent_candle.dm b/code/modules/scent/scent_candle.dm similarity index 86% rename from code/datums/extensions/scent/scent_candle.dm rename to code/modules/scent/scent_candle.dm index 19791e79a4aa..37830e311c08 100644 --- a/code/datums/extensions/scent/scent_candle.dm +++ b/code/modules/scent/scent_candle.dm @@ -1,6 +1,6 @@ /datum/extension/scent/candle intensity = /decl/scent_intensity/normal - descriptor = SCENT_DESC_FRAGRANCE + descriptor = "fragrance" range = 4 /datum/extension/scent/candle/rose @@ -34,4 +34,7 @@ scent = "a sea breeze" /datum/extension/scent/candle/sandalwood - scent = "sandalwood" \ No newline at end of file + scent = "sandalwood" + +/datum/extension/scent/candle/woodsmoke + scent = "woodsmoke" diff --git a/code/game/objects/items/weapons/candle/scent_decls.dm b/code/modules/scent/scent_decls.dm similarity index 88% rename from code/game/objects/items/weapons/candle/scent_decls.dm rename to code/modules/scent/scent_decls.dm index b0964b2ceb62..93facfba7876 100644 --- a/code/game/objects/items/weapons/candle/scent_decls.dm +++ b/code/modules/scent/scent_decls.dm @@ -56,4 +56,9 @@ /decl/scent_type/sandalwood color = COLOR_YELLOW_GRAY scent = "sandalwood" - scent_datum = /datum/extension/scent/candle/sandalwood \ No newline at end of file + scent_datum = /datum/extension/scent/candle/sandalwood + +/decl/scent_type/woodsmoke + color = COLOR_DARK_GRAY + scent = "woodsmoke" + scent_datum = /datum/extension/scent/candle/woodsmoke diff --git a/code/datums/extensions/scent/scent_misc.dm b/code/modules/scent/scent_misc.dm similarity index 76% rename from code/datums/extensions/scent/scent_misc.dm rename to code/modules/scent/scent_misc.dm index 5e79b5552e89..ecad58d68fc8 100644 --- a/code/datums/extensions/scent/scent_misc.dm +++ b/code/modules/scent/scent_misc.dm @@ -1,5 +1,5 @@ /datum/extension/scent/ashtray scent = "an ashtray" intensity = /decl/scent_intensity - descriptor = SCENT_DESC_ODOR + descriptor = "odour" range = 2 \ No newline at end of file diff --git a/code/modules/security levels/keycard_authentication.dm b/code/modules/security levels/keycard_authentication.dm deleted file mode 100644 index a5fecd918986..000000000000 --- a/code/modules/security levels/keycard_authentication.dm +++ /dev/null @@ -1,196 +0,0 @@ -/obj/machinery/keycard_auth - name = "Keycard Authentication Device" - desc = "This device is used to trigger functions which require more than one ID card to authenticate." - icon = 'icons/obj/monitors.dmi' - icon_state = "auth_off" - - anchored = TRUE - idle_power_usage = 2 - active_power_usage = 6 - power_channel = ENVIRON - - var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made. - var/event = "" - var/screen = 1 - var/confirmed = 0 //This variable is set by the device that confirms the request. - var/confirm_delay = 3 SECONDS - var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device. - var/obj/machinery/keycard_auth/event_source - var/weakref/initial_card - var/mob/event_triggered_by - var/mob/event_confirmed_by - //1 = select event - //2 = authenticate - -/obj/machinery/keycard_auth/attack_ai(mob/user) - to_chat(user, "A firewall prevents you from interfacing with this device!") - return - -/obj/machinery/keycard_auth/attackby(obj/item/W, mob/user) - if(stat & (NOPOWER|BROKEN)) - to_chat(user, "This device is not powered.") - return - if(istype(W,/obj/item/card/id)) - visible_message(SPAN_NOTICE("[user] swipes \the [W] through \the [src].")) - var/obj/item/card/id/ID = W - if(access_keycard_auth in ID.access) - if(active) - if(event_source && initial_card?.resolve() != ID) - event_source.confirmed = 1 - event_source.event_confirmed_by = user - else - visible_message(SPAN_WARNING("\The [src] blinks and displays a message: Unable to confirm the event with the same card."), range=2) - else if(screen == 2) - event_triggered_by = user - initial_card = weakref(ID) - broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices - -//icon_state gets set everwhere besides here, that needs to be fixed sometime -/obj/machinery/keycard_auth/on_update_icon() - if(stat &NOPOWER) - icon_state = "auth_off" - -/obj/machinery/keycard_auth/interface_interact(mob/user) - if(busy) - to_chat(user, "This device is busy.") - return TRUE - interact(user) - return TRUE - -/obj/machinery/keycard_auth/interact(mob/user) - user.set_machine(src) - - var/dat = "

    Keycard Authentication Device

    " - - dat += "This device is used to trigger some high security events. It requires the simultaneous swipe of two high-level ID cards." - dat += "


    " - - if(screen == 1) - dat += "Select an event to trigger:" - show_browser(user, dat, "window=keycard_auth;size=500x250") - if(screen == 2) - dat += "Please swipe your card to authorize the following event: [event]" - dat += "

    Back" - show_browser(user, dat, "window=keycard_auth;size=500x250") - return - -/obj/machinery/keycard_auth/CanUseTopic(var/mob/user, href_list) - if(busy) - to_chat(user, "This device is busy.") - return STATUS_CLOSE - if(!user.check_dexterity(DEXTERITY_KEYBOARDS)) - return min(..(), STATUS_UPDATE) - return ..() - -/obj/machinery/keycard_auth/OnTopic(user, href_list) - if(href_list["triggerevent"]) - event = href_list["triggerevent"] - screen = 2 - . = TOPIC_REFRESH - if(href_list["reset"]) - reset() - . = TOPIC_REFRESH - - if(. == TOPIC_REFRESH) - attack_hand(user) - -/obj/machinery/keycard_auth/proc/reset() - active = 0 - event = "" - screen = 1 - confirmed = 0 - event_source = null - icon_state = "auth_off" - event_triggered_by = null - event_confirmed_by = null - initial_card = null - -/obj/machinery/keycard_auth/proc/broadcast_request() - icon_state = "auth_on" - for(var/obj/machinery/keycard_auth/KA in world) - if(KA == src) - continue - KA.reset() - addtimer(CALLBACK(src, .proc/receive_request, src, initial_card.resolve())) - - if(confirm_delay) - addtimer(CALLBACK(src, .proc/broadcast_check), confirm_delay) - -/obj/machinery/keycard_auth/proc/broadcast_check() - if(confirmed) - confirmed = 0 - trigger_event(event) - log_and_message_admins("triggered and [key_name(event_confirmed_by)] confirmed event [event]", event_triggered_by || usr) - reset() - -/obj/machinery/keycard_auth/proc/receive_request(var/obj/machinery/keycard_auth/source, obj/item/card/id/ID) - if(stat & (BROKEN|NOPOWER)) - return - event_source = source - initial_card = weakref(ID) - busy = 1 - active = 1 - icon_state = "auth_on" - - sleep(confirm_delay) - - event_source = null - initial_card = null - icon_state = "auth_off" - active = 0 - busy = 0 - -/obj/machinery/keycard_auth/proc/trigger_event() - switch(event) - if("Red alert") - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - security_state.stored_security_level = security_state.current_security_level - security_state.set_security_level(security_state.high_security_level) - SSstatistics.add_field("alert_keycard_auth_red",1) - if("Revert alert") - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - security_state.set_security_level(security_state.stored_security_level) - SSstatistics.add_field("alert_keycard_revert_red",1) - if("Grant Emergency Maintenance Access") - GLOB.using_map.make_maint_all_access() - SSstatistics.add_field("alert_keycard_auth_maintGrant",1) - if("Revoke Emergency Maintenance Access") - GLOB.using_map.revoke_maint_all_access() - SSstatistics.add_field("alert_keycard_auth_maintRevoke",1) - if("Emergency Response Team") - if(is_ert_blocked()) - visible_message(SPAN_WARNING("\The [src] blinks and displays a message: All emergency response teams are dispatched and can not be called at this time."), range=2) - return - - trigger_armed_response_team(1) - SSstatistics.add_field("alert_keycard_auth_ert",1) - if("Grant Nuclear Authorization Code") - var/obj/machinery/nuclearbomb/nuke = locate(/obj/machinery/nuclearbomb/station) in world - if(nuke) - visible_message(SPAN_WARNING("\The [src] blinks and displays a message: The nuclear authorization code is [nuke.r_code]"), range=2) - else - visible_message(SPAN_WARNING("\The [src] blinks and displays a message: No self destruct terminal found."), range=2) - SSstatistics.add_field("alert_keycard_auth_nukecode",1) - -/obj/machinery/keycard_auth/proc/is_ert_blocked() - if(config.ert_admin_call_only) return 1 - return SSticker.mode && SSticker.mode.ert_disabled - -var/global/maint_all_access = 0 \ No newline at end of file diff --git a/code/modules/security_levels/_security_level.dm b/code/modules/security_levels/_security_level.dm new file mode 100644 index 000000000000..ca4ba811c82f --- /dev/null +++ b/code/modules/security_levels/_security_level.dm @@ -0,0 +1,48 @@ +/decl/security_level + var/icon = 'icons/misc/security_state.dmi' + var/name + + // These values are primarily for station alarms and status displays, and which light colors and overlays to use + var/light_range + var/light_power + var/light_color_alarm + var/light_color_class + var/light_color_status_display + + var/up_description + var/down_description + + var/datum/alarm_appearance/alarm_appearance + + abstract_type = /decl/security_level + +/decl/security_level/Initialize() + . = ..() + if(ispath(alarm_appearance, /datum/alarm_appearance)) + alarm_appearance = new alarm_appearance + +/decl/security_level/validate() + . = ..() + var/initial_appearance = initial(alarm_appearance) + if(!initial_appearance) + . += "alarm_appearance was not set" + else if(!ispath(initial_appearance)) + . += "alarm_appearance was not set to a /datum/alarm_appearance subpath" + else if(!istype(alarm_appearance, /datum/alarm_appearance)) + . += "alarm_appearance creation failed (check runtimes?)" + +// Called when we're switching from a lower security level to this one. +/decl/security_level/proc/switching_up_to() + return + +// Called when we're switching from a higher security level to this one. +/decl/security_level/proc/switching_down_to() + return + +// Called when we're switching from this security level to a higher one. +/decl/security_level/proc/switching_up_from() + return + +// Called when we're switching from this security level to a lower one. +/decl/security_level/proc/switching_down_from() + return \ No newline at end of file diff --git a/code/modules/security_levels/alarm_appearance.dm b/code/modules/security_levels/alarm_appearance.dm new file mode 100644 index 000000000000..494158a60393 --- /dev/null +++ b/code/modules/security_levels/alarm_appearance.dm @@ -0,0 +1,61 @@ +/datum/alarm_appearance + var/display_icon //The icon_state for the displays. Normally only one is used, unless uses_twotone_displays is TRUE. + var/display_icon_color //The color for the display icon. + + var/display_icon_twotone //Used for two-tone displays. + var/display_icon_twotone_color //The color for the display icon. + + var/display_emblem //The icon_state for the emblem, i.e for delta, a radstorm, alerts. + var/display_emblem_color //The color for the emblem. + + var/alarm_icon //The icon_state for the alarms + var/alarm_icon_color //the color for the icon_state + + var/alarm_icon_twotone //Used for two-tone alarms (i.e delta). + var/alarm_icon_twotone_color //The color for the secondary tone icon. + +/datum/alarm_appearance/green + display_icon = "status_display_lines" + display_icon_color = PIPE_COLOR_GREEN + + display_emblem = "status_display_alert" + display_emblem_color = COLOR_WHITE + + alarm_icon = "alarm_normal" + alarm_icon_color = PIPE_COLOR_GREEN + +/datum/alarm_appearance/blue + display_icon = "status_display_lines" + display_icon_color = COLOR_BLUE + + display_emblem = "status_display_alert" + display_emblem_color = COLOR_WHITE + + alarm_icon = "alarm_normal" + alarm_icon_color = COLOR_BLUE + +/datum/alarm_appearance/red + display_icon = "status_display_lines" + display_icon_color = COLOR_RED + + display_emblem = "status_display_alert" + display_emblem_color = COLOR_WHITE + + alarm_icon = "alarm_blinking" + alarm_icon_color = COLOR_RED + +/datum/alarm_appearance/delta + display_icon = "status_display_twotone1" + display_icon_color = COLOR_RED + + display_icon_twotone = "status_display_twotone2" + display_icon_twotone_color = COLOR_YELLOW + + display_emblem = "delta" + display_emblem_color = COLOR_WHITE + + alarm_icon = "alarm_blinking_twotone1" + alarm_icon_color = COLOR_RED + + alarm_icon_twotone = "alarm_blinking_twotone2" + alarm_icon_twotone_color = PIPE_COLOR_YELLOW \ No newline at end of file diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm new file mode 100644 index 000000000000..cb91e3c505c1 --- /dev/null +++ b/code/modules/security_levels/keycard_authentication.dm @@ -0,0 +1,170 @@ +/obj/machinery/keycard_auth + name = "Keycard Authentication Device" + desc = "This device is used to trigger functions which require more than one ID card to authenticate." + icon = 'icons/obj/monitors.dmi' + icon_state = "auth_off" + + anchored = TRUE + idle_power_usage = 2 + active_power_usage = 6 + power_channel = ENVIRON + obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED + directional_offset = @'{"NORTH":{"y":-20}, "SOUTH":{"y":28}, "EAST":{"x":-24}, "WEST":{"x":24}}' + + var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made. + var/event = "" + var/screen = 1 + var/confirmed = 0 //This variable is set by the device that confirms the request. + var/confirm_delay = 3 SECONDS + var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device. + var/obj/machinery/keycard_auth/event_source + var/weakref/initial_card + var/mob/event_triggered_by + var/mob/event_confirmed_by + //1 = select event + //2 = authenticate + +/obj/machinery/keycard_auth/attack_ai(mob/living/silicon/ai/user) + to_chat(user, "A firewall prevents you from interfacing with this device!") + return TRUE + +/obj/machinery/keycard_auth/attackby(obj/item/used_item, mob/user) + if(!istype(used_item,/obj/item/card/id)) + return ..() + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "This device is not powered.") + return TRUE + visible_message(SPAN_NOTICE("[user] swipes \the [used_item] through \the [src].")) + var/obj/item/card/id/ID = used_item + if(!(access_keycard_auth in ID.access)) // you get nothing! + return TRUE + if(active) + if(!event_source) // Is this even possible? Should active just be !isnull(event_source)? + return TRUE + if(initial_card?.resolve() == ID) + visible_message(SPAN_WARNING("\The [src] blinks and displays a message: Unable to confirm the event with the same card."), range=2) + return TRUE + event_source.confirmed = 1 + event_source.event_confirmed_by = user + return TRUE + if(screen == 2) + event_triggered_by = user + initial_card = weakref(ID) + broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices + return TRUE + +//icon_state gets set everwhere besides here, that needs to be fixed sometime +/obj/machinery/keycard_auth/on_update_icon() + if(stat &NOPOWER) + icon_state = "auth_off" + +/obj/machinery/keycard_auth/interface_interact(mob/user) + if(busy) + to_chat(user, "This device is busy.") + return TRUE + interact(user) + return TRUE + +/obj/machinery/keycard_auth/proc/get_event_options(mob/user) + . = list() + for(var/decl/keycard_auth_event/event in global.decls_repository.get_decls_of_subtype_unassociated(/decl/keycard_auth_event)) + if(!event.is_available(src, user)) + continue + . += event.get_option(src, user) + +/obj/machinery/keycard_auth/interact(mob/user) + user.set_machine(src) + + var/dat = "

    Keycard Authentication Device

    " + + dat += "This device is used to trigger some high security events. It requires the simultaneous swipe of two high-level ID cards." + dat += "


    " + + if(screen == 1) + var/list/options = get_event_options(user) + dat += "Select an event to trigger:
    • [options.Join("
    • ")]
    " + show_browser(user, dat, "window=keycard_auth;size=500x250") + if(screen == 2) + var/decl/keycard_auth_event/real_event = global.decls_repository.get_decl_by_id(event) + dat += "Please swipe your card to authorize the following event: [real_event.get_link_text()]" + dat += "

    Back" + show_browser(user, dat, "window=keycard_auth;size=500x250") + return + +/obj/machinery/keycard_auth/CanUseTopic(var/mob/user, href_list) + if(busy) + to_chat(user, "This device is busy.") + return STATUS_CLOSE + if(!user.check_dexterity(DEXTERITY_KEYBOARDS)) + return min(..(), STATUS_UPDATE) + return ..() + +/obj/machinery/keycard_auth/OnTopic(user, href_list) + if(href_list["triggerevent"]) + event = href_list["triggerevent"] + screen = 2 + . = TOPIC_REFRESH + if(href_list["reset"]) + reset() + . = TOPIC_REFRESH + + if(. == TOPIC_REFRESH) + attack_hand_with_interaction_checks(user) + +/obj/machinery/keycard_auth/proc/reset() + active = 0 + event = "" + screen = 1 + confirmed = 0 + event_source = null + icon_state = "auth_off" + event_triggered_by = null + event_confirmed_by = null + initial_card = null + +/obj/machinery/keycard_auth/proc/broadcast_request() + icon_state = "auth_on" + for(var/obj/machinery/keycard_auth/KA in SSmachines.machinery) + if(KA == src) + continue + KA.reset() + addtimer(CALLBACK(src, PROC_REF(receive_request), src, initial_card.resolve())) + + if(confirm_delay) + addtimer(CALLBACK(src, PROC_REF(broadcast_check)), confirm_delay) + +/obj/machinery/keycard_auth/proc/broadcast_check() + if(confirmed) + confirmed = 0 + var/decl/keycard_auth_event/real_event = global.decls_repository.get_decl_by_id(event) + var/cached_name = real_event.get_link_text() // because triggering the event can change the name + trigger_event(event) + log_and_message_admins("triggered and [key_name(event_confirmed_by)] confirmed event [cached_name]", event_triggered_by || usr) + reset() + +/obj/machinery/keycard_auth/proc/receive_request(var/obj/machinery/keycard_auth/source, obj/item/card/id/ID) + if(stat & (BROKEN|NOPOWER)) + return + event_source = source + initial_card = weakref(ID) + busy = 1 + active = 1 + icon_state = "auth_on" + + sleep(confirm_delay) + + event_source = null + initial_card = null + icon_state = "auth_off" + active = 0 + busy = 0 + +/obj/machinery/keycard_auth/proc/trigger_event() + var/decl/keycard_auth_event/the_event = decls_repository.get_decl_by_id(event) + if(the_event) + the_event.on_event(src) + +/obj/machinery/keycard_auth/update_directional_offset(force = FALSE) + if(!force && (!length(directional_offset) || !is_wall_mounted())) //Check if the thing is actually mapped onto a table or something + return + . = ..() \ No newline at end of file diff --git a/code/modules/security_levels/keycard_authentication_events.dm b/code/modules/security_levels/keycard_authentication_events.dm new file mode 100644 index 000000000000..076501f1b32e --- /dev/null +++ b/code/modules/security_levels/keycard_authentication_events.dm @@ -0,0 +1,79 @@ +/decl/keycard_auth_event + abstract_type = /decl/keycard_auth_event + decl_flags = DECL_FLAG_MANDATORY_UID + var/name = "Abstract Keycard Authentication Event" + +/decl/keycard_auth_event/proc/get_link_text(obj/machinery/keycard_auth/auth, mob/user) + return name + +/decl/keycard_auth_event/proc/is_available(obj/machinery/keycard_auth/auth, mob/user) + return TRUE + +/decl/keycard_auth_event/proc/get_option(obj/machinery/keycard_auth/auth, mob/user) + SHOULD_NOT_OVERRIDE(TRUE) + var/fail_reason = get_failure_reason(user) + if(fail_reason) + return fail_reason + return "[get_link_text(auth, user)]" + +/decl/keycard_auth_event/proc/get_failure_reason(obj/machinery/keycard_auth/auth, mob/user) + return + +/decl/keycard_auth_event/proc/on_event(obj/machinery/keycard_auth/auth) + return + +/decl/keycard_auth_event/high_security + name = "Toggle High Security Level" + uid = "keycard_event_toggle_high_security" + +/decl/keycard_auth_event/high_security/get_failure_reason(obj/machinery/keycard_auth/auth, mob/user) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if(security_state.current_security_level == security_state.severe_security_level) + return "Cannot modify the alert level at this time: [security_state.severe_security_level.name] engaged." + +/decl/keycard_auth_event/high_security/get_link_text(obj/machinery/keycard_auth/auth, mob/user) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if(security_state.current_security_level == security_state.high_security_level) // toggle! + return "Disengage [security_state.high_security_level.name]" + else + return "Engage [security_state.high_security_level.name]" + +/decl/keycard_auth_event/high_security/on_event(obj/machinery/keycard_auth/auth, mob/user) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if(security_state.current_security_level == security_state.high_security_level) + security_state.set_security_level(security_state.stored_security_level) + SSstatistics.add_field("alert_keycard_revert_red",1) + else + security_state.stored_security_level = security_state.current_security_level + security_state.set_security_level(security_state.high_security_level) + SSstatistics.add_field("alert_keycard_auth_red",1) + +/decl/keycard_auth_event/maintenance_access + name = "Toggle Emergency Maintenance Access" + uid = "keycard_event_maintenance_access" + +/decl/keycard_auth_event/maintenance_access/get_link_text(obj/machinery/keycard_auth/auth, mob/user) + if(global.using_map.maint_all_access) + return "Revoke Emergency Maintenance Access" + else + return "Grant Emergency Maintenance Access" + +/decl/keycard_auth_event/maintenance_access/on_event(obj/machinery/keycard_auth/auth) + if(global.using_map.maint_all_access) + global.using_map.revoke_maint_all_access() + SSstatistics.add_field("alert_keycard_auth_maintRevoke",1) + else + global.using_map.make_maint_all_access() + SSstatistics.add_field("alert_keycard_auth_maintGrant",1) + +/decl/keycard_auth_event/nuke_code + name = "Grant Nuclear Authorization Code" + uid = "keycard_event_nuke_code" + +/decl/keycard_auth_event/nuke_code/on_event(obj/machinery/keycard_auth/auth) + var/obj/machinery/nuclearbomb/nuke = locate(/obj/machinery/nuclearbomb/station) in SSmachines.machinery + if(nuke) + auth.visible_message(SPAN_WARNING("\The [src] blinks and displays a message: The nuclear authorization code is [nuke.r_code]"), range=2) + else + auth.visible_message(SPAN_WARNING("\The [src] blinks and displays a message: No self-destruct terminal found."), range=2) + SSstatistics.add_field("alert_keycard_auth_nukecode",1) \ No newline at end of file diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm new file mode 100644 index 000000000000..186fd37fbbe7 --- /dev/null +++ b/code/modules/security_levels/security_levels.dm @@ -0,0 +1,105 @@ +/// The default security state used on most space maps. +/decl/security_state/default + all_security_levels = list( + /decl/security_level/default/code_green, + /decl/security_level/default/code_blue, + /decl/security_level/default/code_red, + /decl/security_level/default/code_delta + ) + +/// An abstract security level type that supports announcements on level change. +/decl/security_level/default + abstract_type = /decl/security_level/default + + var/static/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg')) + var/static/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg')) + +/decl/security_level/default/switching_up_to() + if(up_description) + security_announcement_up.Announce(up_description, "Attention! Alert level elevated to [name]!") + notify_station() + +/decl/security_level/default/switching_down_to() + if(down_description) + security_announcement_down.Announce(down_description, "Attention! Alert level changed to [name]!") + notify_station() + +/decl/security_level/default/proc/notify_station() + for(var/obj/machinery/firealarm/FA in SSmachines.machinery) + if(isContactLevel(FA.z)) + FA.update_icon() + post_status("alert") + +/decl/security_level/default/code_green + name = "code green" + + light_range = 2 + light_power = 1 + + light_color_alarm = COLOR_GREEN + light_color_class = "font_green" + light_color_status_display = COLOR_GREEN + + + alarm_appearance = /datum/alarm_appearance/green + + down_description = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." + +/decl/security_level/default/code_blue + name = "code blue" + + light_range = 2 + light_power = 1 + light_color_alarm = COLOR_BLUE + light_color_class = "font_blue" + light_color_status_display = COLOR_BLUE + + alarm_appearance = /datum/alarm_appearance/blue + + up_description = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted." + down_description = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed." + +/decl/security_level/default/code_red + name = "code red" + + light_range = 4 + light_power = 2 + light_color_alarm = COLOR_RED + light_color_class = "font_red" + light_color_status_display = COLOR_RED + + alarm_appearance = /datum/alarm_appearance/red + + up_description = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised." + down_description = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised." + +/decl/security_level/default/code_delta + name = "code delta" + + light_range = 4 + light_power = 2 + light_color_alarm = COLOR_RED + light_color_class = "font_red" + light_color_status_display = COLOR_RED + + alarm_appearance = /datum/alarm_appearance/delta + + + var/static/datum/announcement/priority/security/security_announcement_delta = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/effects/siren.ogg')) + +/decl/security_level/default/code_delta/switching_up_to() + security_announcement_delta.Announce("The self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.", "Attention! Delta security level reached!") + notify_station() + +// The following are dummy states and levels to soft-disable security levels on some maps. +/// A security state used for maps that don't have security levels exposed to players. +/decl/security_state/none + all_security_levels = list( + /decl/security_level/none + ) + +/// A dummy security level with no effects. +/decl/security_level/none + name = "none" + // Since currently we're required to have an alarm_appearance, we just use a blank one. + alarm_appearance = /datum/alarm_appearance \ No newline at end of file diff --git a/code/modules/security_levels/security_state.dm b/code/modules/security_levels/security_state.dm new file mode 100644 index 000000000000..73945c3c1358 --- /dev/null +++ b/code/modules/security_levels/security_state.dm @@ -0,0 +1,129 @@ +/decl/security_state + abstract_type = /decl/security_state + /// Whether or not security level information should be shown to new players on login. + var/show_on_login = TRUE + // When defining any of these values type paths should be used, not instances. Instances will be acquired in /New() + + var/decl/security_level/severe_security_level // At which security level (and higher) the use of nuclear fission devices and other extreme measures are allowed. Defaults to the last entry in all_security_levels if unset. + var/decl/security_level/high_security_level // At which security level (and higher) transfer votes are disabled, ERT may be requested, and other similar high alert implications. Defaults to the second to last entry in all_security_levels if unset. + // All security levels within the above convention: Low, Guarded, Elevated, High, Severe + + + // Under normal conditions the crew may not raise the current security level higher than the highest_standard_security_level + // The crew may also not adjust the security level once it is above the highest_standard_security_level. + // Defaults to the second to last entry in all_security_levels if unset/null. + // Set to FALSE/0 if there should be no restrictions. + var/decl/security_level/highest_standard_security_level + + var/decl/security_level/current_security_level // The current security level. Defaults to the first entry in all_security_levels if unset. + var/decl/security_level/stored_security_level // The security level that we are escalating to high security from - we will return to this level once we choose to revert. + var/list/all_security_levels // List of all available security levels + var/list/standard_security_levels // List of all normally selectable security levels + var/list/comm_console_security_levels // List of all selectable security levels for the command and communication console - basically standard_security_levels - 1 + +/decl/security_state/Initialize() + + . = ..() + + // Setup the severe security level + if(!(severe_security_level in all_security_levels)) + severe_security_level = all_security_levels[all_security_levels.len] + severe_security_level = GET_DECL(severe_security_level) + + // Setup the high security level + if(!(high_security_level in all_security_levels)) + high_security_level = all_security_levels[max(1, all_security_levels.len - 1)] + high_security_level = GET_DECL(high_security_level) + + // Setup the highest standard security level + if(highest_standard_security_level || isnull(highest_standard_security_level)) + if(!(highest_standard_security_level in all_security_levels)) + highest_standard_security_level = all_security_levels[max(1, all_security_levels.len - 1)] + highest_standard_security_level = GET_DECL(highest_standard_security_level) + else + highest_standard_security_level = null + + // Setup the current security level + if(current_security_level in all_security_levels) + current_security_level = GET_DECL(current_security_level) + else + current_security_level = GET_DECL(all_security_levels[1]) + + // Setup the full list of available security levels now that we no longer need to use "x in all_security_levels" + var/list/security_level_instances = list() + for(var/security_level_type in all_security_levels) + security_level_instances += GET_DECL(security_level_type) + all_security_levels = security_level_instances + + standard_security_levels = list() + // Setup the list of normally selectable security levels + for(var/security_level in all_security_levels) + standard_security_levels += security_level + if(security_level == highest_standard_security_level) + break + + comm_console_security_levels = list() + // Setup the list of selectable security levels available in the comm. console + for(var/security_level in all_security_levels) + if(security_level == highest_standard_security_level) + break + comm_console_security_levels += security_level + + // Now we ensure the high security level is not above the severe one (but we allow them to be equal) + var/severe_index = all_security_levels.Find(severe_security_level) + var/high_index = all_security_levels.Find(high_security_level) + if(high_index > severe_index) + high_security_level = severe_security_level + + // Finally switch up to the default starting security level. + current_security_level.switching_up_to() + +/decl/security_state/proc/can_change_security_level() + return current_security_level in standard_security_levels + +/decl/security_state/proc/can_switch_to(var/given_security_level) + if(!can_change_security_level()) + return FALSE + return given_security_level in standard_security_levels + +/decl/security_state/proc/current_security_level_is_lower_than(var/given_security_level) + var/current_index = all_security_levels.Find(current_security_level) + var/given_index = all_security_levels.Find(given_security_level) + + return given_index && current_index < given_index + +/decl/security_state/proc/current_security_level_is_same_or_higher_than(var/given_security_level) + var/current_index = all_security_levels.Find(current_security_level) + var/given_index = all_security_levels.Find(given_security_level) + + return given_index && current_index >= given_index + +/decl/security_state/proc/current_security_level_is_higher_than(var/given_security_level) + var/current_index = all_security_levels.Find(current_security_level) + var/given_index = all_security_levels.Find(given_security_level) + + return given_index && current_index > given_index + +/decl/security_state/proc/set_security_level(var/decl/security_level/new_security_level, var/force_change = FALSE) + if(new_security_level == current_security_level) + return FALSE + if(!(new_security_level in all_security_levels)) + return FALSE + if(!force_change && !can_switch_to(new_security_level)) + return FALSE + + var/decl/security_level/previous_security_level = current_security_level + current_security_level = new_security_level + + var/previous_index = all_security_levels.Find(previous_security_level) + var/new_index = all_security_levels.Find(new_security_level) + + if(new_index > previous_index) + previous_security_level.switching_up_from() + new_security_level.switching_up_to() + else + previous_security_level.switching_down_from() + new_security_level.switching_down_to() + + log_and_message_admins("has changed the security level from [previous_security_level.name] to [new_security_level.name].") + return TRUE diff --git a/code/modules/shield_generators/floor_diffuser.dm b/code/modules/shield_generators/floor_diffuser.dm index 618e034bc4ec..5cef0619144f 100644 --- a/code/modules/shield_generators/floor_diffuser.dm +++ b/code/modules/shield_generators/floor_diffuser.dm @@ -6,9 +6,9 @@ use_power = POWER_USE_ACTIVE idle_power_usage = 100 active_power_usage = 2000 - anchored = 1 - density = 0 - level = 1 + anchored = TRUE + density = FALSE + level = LEVEL_BELOW_PLATING construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null stat_immune = 0 @@ -25,10 +25,11 @@ if(!enabled) return - for(var/direction in GLOB.cardinal) - var/turf/simulated/shielded_tile = get_step(get_turf(src), direction) - for(var/obj/effect/shield/S in shielded_tile) - S.diffuse(5) + for(var/direction in global.cardinal) + var/turf/shielded_tile = get_step(get_turf(src), direction) + if(shielded_tile?.simulated) + for(var/obj/effect/shield/S in shielded_tile) + S.diffuse(5) /obj/machinery/shield_diffuser/on_update_icon() if(alarm) @@ -49,7 +50,6 @@ return TRUE enabled = !enabled update_use_power(enabled + 1) - update_icon() to_chat(user, "You turn \the [src] [enabled ? "on" : "off"].") return TRUE @@ -59,8 +59,8 @@ alarm = round(max(alarm, duration)) update_icon() -/obj/machinery/shield_diffuser/examine(mob/user) +/obj/machinery/shield_diffuser/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It is [enabled ? "enabled" : "disabled"].") + . += "It is [enabled ? "enabled" : "disabled"]." if(alarm) - to_chat(user, "A red LED labeled \"Proximity Alarm\" is blinking on the control panel.") + . += "A red LED labeled \"Proximity Alarm\" is blinking on the control panel." diff --git a/code/modules/shield_generators/handheld_diffuser.dm b/code/modules/shield_generators/handheld_diffuser.dm index bdd7100aa829..629ddc4f99c6 100644 --- a/code/modules/shield_generators/handheld_diffuser.dm +++ b/code/modules/shield_generators/handheld_diffuser.dm @@ -3,57 +3,53 @@ desc = "A small handheld device designed to disrupt energy barriers." icon = 'icons/obj/machines/shielding.dmi' icon_state = "hdiffuser_off" - origin_tech = "{'magnets':5,'powerstorage':5,'esoteric':2}" + origin_tech = @'{"magnets":5,"powerstorage":5,"esoteric":2}' material = /decl/material/solid/metal/steel matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) - - var/obj/item/cell/device/cell var/enabled = 0 /obj/item/shield_diffuser/on_update_icon() + . = ..() if(enabled) icon_state = "hdiffuser_on" else icon_state = "hdiffuser_off" /obj/item/shield_diffuser/Initialize() + set_extension(src, /datum/extension/loaded_cell/unremovable, /obj/item/cell/device, /obj/item/cell/device/standard) . = ..() - cell = new(src) /obj/item/shield_diffuser/Destroy() - QDEL_NULL(cell) if(enabled) STOP_PROCESSING(SSobj, src) . = ..() -/obj/item/shield_diffuser/get_cell() - return cell - /obj/item/shield_diffuser/Process() - if(!enabled) + var/obj/item/cell/cell = get_cell() + if(!enabled || !cell) return - for(var/direction in GLOB.cardinal) - var/turf/simulated/shielded_tile = get_step(get_turf(src), direction) - for(var/obj/effect/shield/S in shielded_tile) - // 10kJ per pulse, but gap in the shield lasts for longer than regular diffusers. - if(istype(S) && !S.diffused_for && !S.disabled_for && cell.checked_use(10 KILOWATTS * CELLRATE)) - S.diffuse(20) + for(var/direction in global.cardinal) + var/turf/shielded_tile = get_step(get_turf(src), direction) + if(shielded_tile?.simulated) + for(var/obj/effect/shield/S in shielded_tile) + // 10kJ per pulse, but gap in the shield lasts for longer than regular diffusers. + if(istype(S) && !S.diffused_for && !S.disabled_for && cell.checked_use(10 KILOWATTS * CELLRATE)) + S.diffuse(20) -/obj/item/shield_diffuser/attack_self() +/obj/item/shield_diffuser/attack_self(mob/user) enabled = !enabled update_icon() if(enabled) START_PROCESSING(SSobj, src) else STOP_PROCESSING(SSobj, src) - to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].") + to_chat(user, "You turn \the [src] [enabled ? "on" : "off"].") -/obj/item/shield_diffuser/examine(mob/user) +/obj/item/shield_diffuser/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "The charge meter reads [cell ? cell.percent() : 0]%") - to_chat(user, "It is [enabled ? "enabled" : "disabled"].") + . += "It is [enabled ? "enabled" : "disabled"]." diff --git a/code/modules/shield_generators/shield.dm b/code/modules/shield_generators/shield.dm index 9ec35ca902fb..5ad2f51439df 100644 --- a/code/modules/shield_generators/shield.dm +++ b/code/modules/shield_generators/shield.dm @@ -4,49 +4,57 @@ icon = 'icons/obj/machines/shielding.dmi' icon_state = "shield_normal" alpha = 100 - anchored = 1 + anchored = TRUE layer = ABOVE_HUMAN_LAYER - density = 1 - invisibility = 0 + density = TRUE + invisibility = INVISIBILITY_NONE atmos_canpass = CANPASS_PROC - var/obj/machinery/power/shield_generator/gen = null + var/obj/machinery/shield_generator/gen = null var/disabled_for = 0 var/diffused_for = 0 -/obj/effect/shield/on_update_icon(update_neighbors = FALSE) +/obj/effect/shield/on_update_icon() if(gen && gen.check_flag(MODEFLAG_PHOTONIC) && !disabled_for && !diffused_for) - set_opacity(1) + set_opacity(TRUE) else - set_opacity(0) + set_opacity(FALSE) if(gen && gen.check_flag(MODEFLAG_OVERCHARGE)) - icon_state = "shield_overcharged" - set_light(1, 0.1, 2, l_color = "#ff9900") + color = COLOR_VIOLET else - icon_state = "shield_normal" - set_light(1, 0.1, 2, l_color = "#66ffff") + color = COLOR_DEEP_SKY_BLUE + + set_light(2, 1, color) cut_overlays() - for(var/direction in GLOB.cardinal) - var/turf/T = get_step(src, direction) - if(!T) + for(var/direction in global.cardinal) + var/turf/resolved_turf = get_step_resolving_mimic(src, direction) + if(!resolved_turf) continue - var/found = locate(/obj/effect/shield) in T + var/found = locate(/obj/effect/shield) in resolved_turf if(found) - if(update_neighbors) - for(var/obj/effect/shield/shield in T) - shield.update_icon(FALSE) - add_overlay(image(icon = icon, icon_state = "[icon_state]_edge", dir = direction)) + add_overlay(image(icon = icon, icon_state = "[icon_state]edge", dir = direction)) + +/obj/effect/shield/update_nearby_tiles(need_rebuild) + . = ..() + for(var/direction in global.cardinal) + var/turf/resolved_turf = get_step_resolving_mimic(src, direction) + if(!resolved_turf) + continue + for(var/obj/effect/shield/shield in resolved_turf) + if(!(shield.atom_flags & ATOM_FLAG_INITIALIZED)) // they'll update themselves later + continue + shield.update_icon() // Prevents shuttles, singularities and pretty much everything else from moving the field segments away. // The only thing that is allowed to move us is the Destroy() proc. /obj/effect/shield/forceMove() . = QDELING(src) && ..() -/obj/effect/shield/Initialize() +/obj/effect/shield/Initialize(mapload) . = ..() - update_icon(TRUE) + update_icon() update_nearby_tiles() /obj/effect/shield/Destroy() @@ -61,7 +69,7 @@ set_light(0) var/turf/current_loc = get_turf(src) - for(var/direction in GLOB.cardinal) + for(var/direction in global.cardinal) var/turf/T = get_step(current_loc, direction) if(T) for(var/obj/effect/shield/F in T) @@ -94,9 +102,9 @@ if(!disabled_for && !diffused_for) set_density(1) - set_invisibility(0) + set_invisibility(INVISIBILITY_NONE) update_nearby_tiles() - update_icon(TRUE) + update_icon() update_explosion_resistance() gen.damaged_segments -= src @@ -112,15 +120,15 @@ set_density(0) set_invisibility(INVISIBILITY_MAXIMUM) update_nearby_tiles() - update_icon(TRUE) + update_icon() update_explosion_resistance() // Fails shield segments in specific range. Range of 1 affects the shielded turf only. /obj/effect/shield/proc/fail_adjacent_segments(var/range, var/hitby = null) if(hitby) - visible_message("\The [src] flashes a bit as \the [hitby] collides with it, eventually fading out in a rain of sparks!") + visible_message(SPAN_DANGER("\The [src] flashes a bit as \the [hitby] collides with it, eventually fading out in a rain of sparks!")) else - visible_message("\The [src] flashes a bit as it eventually fades out in a rain of sparks!") + visible_message(SPAN_DANGER("\The [src] flashes a bit as it eventually fades out in a rain of sparks!")) fail(range * 2) for(var/obj/effect/shield/S in range(range, src)) @@ -130,7 +138,7 @@ // The closer we are to impact site, the longer it takes for shield to come back up. S.fail(-(-range + get_dist(src, S)) * 2) -/obj/effect/shield/proc/take_damage(var/damage, var/damtype, var/hitby) +/obj/effect/shield/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) if(!gen) qdel(src) return @@ -144,20 +152,20 @@ impact_effect(round(abs(damage * 2))) var/list/field_segments = gen.field_segments - switch(gen.take_shield_damage(damage, damtype)) + switch(gen.take_shield_damage(damage, damage_type)) if(SHIELD_ABSORBED) return if(SHIELD_BREACHED_MINOR) - fail_adjacent_segments(rand(1, 3), hitby) + fail_adjacent_segments(rand(1, 3), inflicter) return if(SHIELD_BREACHED_MAJOR) - fail_adjacent_segments(rand(2, 5), hitby) + fail_adjacent_segments(rand(2, 5), inflicter) return if(SHIELD_BREACHED_CRITICAL) - fail_adjacent_segments(rand(4, 8), hitby) + fail_adjacent_segments(rand(4, 8), inflicter) return if(SHIELD_BREACHED_FAILURE) - fail_adjacent_segments(rand(8, 16), hitby) + fail_adjacent_segments(rand(8, 16), inflicter) for(var/obj/effect/shield/S in field_segments) S.fail(1) return @@ -169,23 +177,15 @@ if(!gen) qdel(src) return 1 - if(disabled_for || diffused_for) return 1 - // Atmosphere containment. if(air_group) return !gen.check_flag(MODEFLAG_ATMOSPHERIC) - if(mover) return mover.can_pass_shield(gen) return 1 - -/obj/effect/shield/c_airblock(turf/other) - return gen.check_flag(MODEFLAG_ATMOSPHERIC) ? BLOCKED : 0 - - // EMP. It may seem weak but keep in mind that multiple shield segments are likely to be affected. /obj/effect/shield/emp_act(var/severity) if(!disabled_for) @@ -201,36 +201,42 @@ // Fire /obj/effect/shield/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + SHOULD_CALL_PARENT(FALSE) if(!disabled_for) take_damage(rand(5,10), SHIELD_DAMTYPE_HEAT) - // Projectiles /obj/effect/shield/bullet_act(var/obj/item/projectile/proj) - if(proj.damage_type == BURN) + if(proj.atom_damage_type == BURN) take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_HEAT) - else if (proj.damage_type == BRUTE) + else if (proj.atom_damage_type == BRUTE) take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_PHYSICAL) else take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_EM) // Attacks with hand tools. Blocked by Hyperkinetic flag. -/obj/effect/shield/attackby(var/obj/item/I, var/mob/user) +/obj/effect/shield/attackby(var/obj/item/used_item, var/mob/user) + return bash(used_item, user) + +/obj/effect/shield/bash(obj/item/weapon, mob/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(src) - if(gen.check_flag(MODEFLAG_HYPERKINETIC)) - user.visible_message("\The [user] [pick(I.attack_verb)] \the [src] with \the [I]!") - if(I.damtype == BURN) - take_damage(I.force, SHIELD_DAMTYPE_HEAT) - else if (I.damtype == BRUTE) - take_damage(I.force, SHIELD_DAMTYPE_PHYSICAL) + if(!gen.check_flag(MODEFLAG_HYPERKINETIC)) + user.visible_message("\The [user] tries to attack \the [src] with \the [weapon], but it passes through!") + return TRUE + var/force = weapon.expend_attack_force(user) + user.visible_message("\The [user] [weapon.pick_attack_verb()] \the [src] with \the [weapon]!") + switch(weapon.atom_damage_type) + if(BURN) + take_damage(force, SHIELD_DAMTYPE_HEAT) + if (BRUTE) + take_damage(force, SHIELD_DAMTYPE_PHYSICAL) else - take_damage(I.force, SHIELD_DAMTYPE_EM) - if(gen.check_flag(MODEFLAG_OVERCHARGE) && (I.obj_flags & OBJ_FLAG_CONDUCTIBLE)) - overcharge_shock(user) - else - user.visible_message("\The [user] tries to attack \the [src] with \the [I], but it passes through!") + take_damage(force, SHIELD_DAMTYPE_EM) + if(gen.check_flag(MODEFLAG_OVERCHARGE) && (weapon.obj_flags & OBJ_FLAG_CONDUCTIBLE)) + overcharge_shock(user) + return TRUE // Special treatment for meteors because they would otherwise penetrate right through the shield. @@ -244,8 +250,8 @@ /obj/effect/shield/proc/overcharge_shock(var/mob/living/M) - M.adjustFireLoss(rand(20, 40)) - M.Weaken(5) + M.take_damage(rand(20, 40), BURN) + SET_STATUS_MAX(M, STAT_WEAK, 5) to_chat(M, "As you come into contact with \the [src] a surge of energy paralyses you!") take_damage(10, SHIELD_DAMTYPE_EM) @@ -257,7 +263,7 @@ // Update airflow update_nearby_tiles() - update_icon(TRUE) + update_icon() update_explosion_resistance() /obj/effect/shield/proc/update_explosion_resistance() @@ -267,34 +273,34 @@ explosion_resistance = 0 // Shield collision checks below -/atom/movable/proc/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/atom/movable/proc/can_pass_shield(var/obj/machinery/shield_generator/gen) return 1 // Other mobs -/mob/living/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/mob/living/can_pass_shield(var/obj/machinery/shield_generator/gen) return !gen.check_flag(MODEFLAG_NONHUMANS) // Human mobs -/mob/living/carbon/human/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/mob/living/human/can_pass_shield(var/obj/machinery/shield_generator/gen) if(isSynthetic()) return !gen.check_flag(MODEFLAG_ANORGANIC) return !gen.check_flag(MODEFLAG_HUMANOIDS) // Silicon mobs -/mob/living/silicon/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/mob/living/silicon/can_pass_shield(var/obj/machinery/shield_generator/gen) return !gen.check_flag(MODEFLAG_ANORGANIC) // Generic objects. Also applies to bullets and meteors. -/obj/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/obj/can_pass_shield(var/obj/machinery/shield_generator/gen) return !gen.check_flag(MODEFLAG_HYPERKINETIC) // Beams -/obj/item/projectile/beam/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/obj/item/projectile/beam/can_pass_shield(var/obj/machinery/shield_generator/gen) return !gen.check_flag(MODEFLAG_PHOTONIC) // Beams -/obj/item/projectile/ship_munition/energy/can_pass_shield(var/obj/machinery/power/shield_generator/gen) +/obj/item/projectile/ship_munition/energy/can_pass_shield(var/obj/machinery/shield_generator/gen) return !gen.check_flag(MODEFLAG_PHOTONIC) // Shield on-impact logic here. This is called only if the object is actually blocked by the field (can_pass_shield applies first) @@ -309,29 +315,29 @@ /obj/effect/meteor/shield_impact(var/obj/effect/shield/S) if(!S.gen.check_flag(MODEFLAG_HYPERKINETIC)) return - S.take_damage(get_shield_damage(), SHIELD_DAMTYPE_PHYSICAL, src) - visible_message("\The [src] breaks into dust!") + S.take_damage(get_shield_damage(), SHIELD_DAMTYPE_PHYSICAL, inflicter = src) + visible_message(SPAN_DANGER("\The [src] breaks into dust!")) make_debris() qdel(src) // Small visual effect, makes the shield tiles brighten up by becoming more opaque for a moment, and spreads to nearby shields. /obj/effect/shield/proc/impact_effect(var/i, var/list/affected_shields = list()) - i = between(1, i, 10) + i = clamp(i, 1, 10) alpha = 255 animate(src, alpha = initial(alpha), time = 1 SECOND) affected_shields |= src i-- if(i) - addtimer(CALLBACK(src, .proc/spread_impact_effect, i, affected_shields), 2) + addtimer(CALLBACK(src, PROC_REF(spread_impact_effect), i, affected_shields), 2) /obj/effect/shield/proc/spread_impact_effect(var/i, var/list/affected_shields = list()) - for(var/direction in GLOB.cardinal) + for(var/direction in global.cardinal) var/turf/T = get_step(src, direction) if(T) // Incase we somehow stepped off the map. for(var/obj/effect/shield/F in T) if(!(F in affected_shields)) F.impact_effect(i, affected_shields) // Spread the effect to them -/obj/effect/shield/attack_hand(var/mob/living/user) +/obj/effect/shield/attack_hand(var/mob/user) impact_effect(3) // Harmless, but still produces the 'impact' effect. - ..() + return ..() diff --git a/code/modules/shield_generators/shield_generator.dm b/code/modules/shield_generators/shield_generator.dm index 1739cd767a2d..4237722668cd 100644 --- a/code/modules/shield_generators/shield_generator.dm +++ b/code/modules/shield_generators/shield_generator.dm @@ -1,86 +1,134 @@ -/obj/machinery/power/shield_generator - name = "advanced shield generator" +/obj/machinery/shield_generator + name = "shield generator" desc = "A heavy-duty shield generator and capacitor, capable of generating energy shields at large distances." icon = 'icons/obj/machines/shielding.dmi' icon_state = "generator0" - density = 1 - base_type = /obj/machinery/power/shield_generator + density = TRUE + base_type = /obj/machinery/shield_generator construct_state = /decl/machine_construction/default/panel_closed wires = /datum/wires/shield_generator - uncreated_component_parts = null + uncreated_component_parts = list(/obj/item/stock_parts/power/terminal) + stock_part_presets = list(/decl/stock_part_preset/terminal_setup) stat_immune = 0 - var/list/field_segments = list() // List of all shield segments owned by this generator. - var/list/damaged_segments = list() // List of shield segments that have failed and are currently regenerating. - var/shield_modes = 0 // Enabled shield mode flags - var/mitigation_em = 0 // Current EM mitigation - var/mitigation_physical = 0 // Current Physical mitigation - var/mitigation_heat = 0 // Current Burn mitigation - var/mitigation_max = 0 // Maximal mitigation reachable with this generator. Set by RefreshParts() - var/max_energy = 0 // Maximal stored energy. In joules. Depends on the type of used SMES coil when constructing this generator. - var/current_energy = 0 // Current stored energy. - var/field_radius = 1 // Current field radius. - var/target_radius = 1 // Desired field radius. - var/running = SHIELD_OFF // Whether the generator is enabled or not. - var/input_cap = 1 MEGAWATTS // Currently set input limit. Set to 0 to disable limits altogether. The shield will try to input this value per tick at most - var/upkeep_power_usage = 0 // Upkeep power usage last tick. - var/upkeep_multiplier = 1 // Multiplier of upkeep values. - var/power_usage = 0 // Total power usage last tick. - var/overloaded = 0 // Whether the field has overloaded and shut down to regenerate. - var/hacked = 0 // Whether the generator has been hacked by cutting the safety wire. - var/offline_for = 0 // The generator will be inoperable for this duration in ticks. - var/input_cut = 0 // Whether the input wire is cut. - var/mode_changes_locked = 0 // Whether the control wire is cut, locking out changes. - var/ai_control_disabled = 0 // Whether the AI control is disabled. - var/list/mode_list = null // A list of shield_mode datums. - var/full_shield_strength = 0 // The amount of power shields need to be at full operating strength. - - var/idle_multiplier = 1 // Trades off cost vs. spin-up time from idle to running - var/idle_valid_values = list(1, 2, 5, 10) - var/spinup_delay = 20 - var/spinup_counter = 0 - -/obj/machinery/power/shield_generator/on_update_icon() + obj_flags = OBJ_FLAG_ANCHORABLE + + /// List of all shield segments owned by this generator. + var/list/field_segments = list() + /// List of shield segments that have failed and are currently regenerating. + var/list/damaged_segments = list() + /// Enabled shield mode flags + var/shield_modes = 0 + /// Current EM mitigation + var/mitigation_em = 0 + /// Current Physical mitigation + var/mitigation_physical = 0 + /// Current Burn mitigation + var/mitigation_heat = 0 + /// Maximal mitigation reachable with this generator. Set by RefreshParts() + var/mitigation_max = 0 + /// Maximal stored energy. In joules. Depends on the type of used SMES coil when constructing this generator. + var/max_energy = 0 + /// Current stored energy. + var/current_energy = 0 + /// Current field radius. + var/field_radius = 1 + /// Desired field radius. + var/target_radius = 1 + /// Whether the generator is enabled or not. + var/running = SHIELD_OFF + /// Currently set input limit. Set to 0 to disable limits altogether. The shield will try to input this value per tick at most + var/input_cap = 1 MEGAWATTS + /// Upkeep power usage last tick. + var/upkeep_power_usage = 0 + /// Multiplier of upkeep values. + var/upkeep_multiplier = 1 + /// Total power usage last tick. + var/power_usage = 0 + /// Whether the field has overloaded and shut down to regenerate. + var/overloaded = 0 + /// Whether the generator has been hacked by cutting the safety wire. + var/hacked = 0 + /// The generator will be inoperable for this duration in ticks. + var/offline_for = 0 + /// Whether the input wire is cut. + var/input_cut = 0 + /// Whether the control wire is cut, locking out changes. + var/mode_changes_locked = 0 + /// Whether the AI control is disabled. + var/ai_control_disabled = 0 + /// The amount of power shields need to be at full operating strength. + var/full_shield_strength = 0 + /// Reverse dir of our vessel + var/vessel_reverse_dir = EAST + /// A list of shield_mode datums. + var/list/mode_list + // Trades off cost vs. spin-up time from idle to running + var/idle_multiplier = 1 + var/idle_valid_values = list(1, 2, 5, 10) + var/spinup_delay = 20 + var/spinup_counter = 0 + + var/obj/effect/overmap/visitable/last_linked_overmap_object + +// We do not anchor by default, so that shield generators in hard storage don't create a terminal. +/obj/machinery/shield_generator/mapped + anchored = TRUE + +/obj/machinery/shield_generator/on_update_icon() if(running) icon_state = "generator1" else icon_state = "generator0" -/obj/machinery/power/shield_generator/Initialize() - . = ..() - connect_to_network() - +/obj/machinery/shield_generator/Initialize() + ..() mode_list = list() for(var/st in subtypesof(/datum/shield_mode/)) var/datum/shield_mode/SM = new st() mode_list.Add(SM) + events_repository.register(/decl/observ/moved, src, src, PROC_REF(update_overmap_shield_list)) + . = INITIALIZE_HINT_LATELOAD +/obj/machinery/shield_generator/LateInitialize() + . = ..() + update_overmap_shield_list() -/obj/machinery/power/shield_generator/Destroy() +/obj/machinery/shield_generator/Destroy() shutdown_field() field_segments = null damaged_segments = null mode_list = null + events_repository.unregister(/decl/observ/moved, src, src) . = ..() - - -/obj/machinery/power/shield_generator/RefreshParts() + update_overmap_shield_list() + +/obj/machinery/shield_generator/proc/update_overmap_shield_list() + var/obj/effect/overmap/visitable/current_overmap_object = get_owning_overmap_object() + if(current_overmap_object != last_linked_overmap_object) + if(last_linked_overmap_object) + last_linked_overmap_object.unregister_machine(src, /obj/machinery/shield_generator) + last_linked_overmap_object = current_overmap_object + if(last_linked_overmap_object) + last_linked_overmap_object.register_machine(src, /obj/machinery/shield_generator) + +/obj/machinery/shield_generator/RefreshParts() max_energy = 0 full_shield_strength = 0 for(var/obj/item/stock_parts/smes_coil/S in component_parts) full_shield_strength += (S.ChargeCapacity / CELLRATE) * 5 max_energy = full_shield_strength * 20 - current_energy = between(0, current_energy, max_energy) + current_energy = clamp(current_energy, 0, max_energy) mitigation_max = MAX_MITIGATION_BASE + MAX_MITIGATION_RESEARCH * total_component_rating_of_type(/obj/item/stock_parts/capacitor) - mitigation_em = between(0, mitigation_em, mitigation_max) - mitigation_physical = between(0, mitigation_physical, mitigation_max) - mitigation_heat = between(0, mitigation_heat, mitigation_max) + mitigation_em = clamp(mitigation_em, 0, mitigation_max) + mitigation_physical = clamp(mitigation_physical, 0, mitigation_max) + mitigation_heat = clamp(mitigation_heat, 0, mitigation_max) ..() // Shuts down the shield, removing all shield segments and unlocking generator settings. -/obj/machinery/power/shield_generator/proc/shutdown_field() +/obj/machinery/shield_generator/proc/shutdown_field() for(var/obj/effect/shield/S in field_segments) qdel(S) @@ -93,7 +141,7 @@ // Generates the field objects. Deletes existing field, if applicable. -/obj/machinery/power/shield_generator/proc/regenerate_field() +/obj/machinery/shield_generator/proc/regenerate_field() if(field_segments.len) for(var/obj/effect/shield/S in field_segments) qdel(S) @@ -109,16 +157,22 @@ else shielded_turfs = fieldtype_square() + // Rotate shield's animation relative to located ship + var/obj/effect/overmap/visitable/ship/sector = get_owning_overmap_object() + if(istype(sector)) + vessel_reverse_dir = global.reverse_dir[sector.fore_dir] + for(var/turf/T in shielded_turfs) var/obj/effect/shield/S = new(T) S.gen = src S.flags_updated() field_segments |= S + S.set_dir(vessel_reverse_dir) update_icon() // Recalculates and updates the upkeep multiplier -/obj/machinery/power/shield_generator/proc/update_upkeep_multiplier() +/obj/machinery/shield_generator/proc/update_upkeep_multiplier() var/new_upkeep = 1.0 for(var/datum/shield_mode/SM in mode_list) if(check_flag(SM.mode_flag)) @@ -126,8 +180,7 @@ upkeep_multiplier = new_upkeep - -/obj/machinery/power/shield_generator/Process() +/obj/machinery/shield_generator/Process() upkeep_power_usage = 0 power_usage = 0 @@ -149,18 +202,19 @@ running = SHIELD_RUNNING regenerate_field() - mitigation_em = between(0, mitigation_em - MITIGATION_LOSS_PASSIVE, mitigation_max) - mitigation_heat = between(0, mitigation_heat - MITIGATION_LOSS_PASSIVE, mitigation_max) - mitigation_physical = between(0, mitigation_physical - MITIGATION_LOSS_PASSIVE, mitigation_max) + mitigation_em = clamp(mitigation_em - MITIGATION_LOSS_PASSIVE, 0, mitigation_max) + mitigation_heat = clamp(mitigation_heat - MITIGATION_LOSS_PASSIVE, 0, mitigation_max) + mitigation_physical = clamp(mitigation_physical - MITIGATION_LOSS_PASSIVE, 0, mitigation_max) if(running == SHIELD_RUNNING) upkeep_power_usage = round((field_segments.len - damaged_segments.len) * ENERGY_UPKEEP_PER_TILE * upkeep_multiplier) else if(running > SHIELD_RUNNING) upkeep_power_usage = round(ENERGY_UPKEEP_IDLE * idle_multiplier * (field_radius * 8) * upkeep_multiplier) // Approximates number of turfs. - if(powernet && (running >= SHIELD_RUNNING) && !input_cut) - var/energy_buffer = 0 - energy_buffer = draw_power(min(upkeep_power_usage, input_cap)) + if((running >= SHIELD_RUNNING) && !input_cut) + var/drawn_power = min(upkeep_power_usage, input_cap) + var/energy_buffer + energy_buffer = drawn_power - use_power_oneoff(drawn_power) power_usage += round(energy_buffer) if(energy_buffer < upkeep_power_usage) @@ -169,10 +223,10 @@ // Now try to recharge our internal energy. var/energy_to_demand if(input_cap) - energy_to_demand = between(0, max_energy - current_energy, input_cap - energy_buffer) + energy_to_demand = clamp(max_energy - current_energy, 0, input_cap - energy_buffer) else energy_to_demand = max(0, max_energy - current_energy) - energy_buffer = draw_power(energy_to_demand) + energy_buffer = energy_to_demand - use_power_oneoff(energy_to_demand) power_usage += energy_buffer current_energy += round(energy_buffer) else @@ -187,23 +241,17 @@ else if (field_integrity() > 25) overloaded = 0 -/obj/machinery/power/shield_generator/components_are_accessible(path) +/obj/machinery/shield_generator/components_are_accessible(path) return !running && ..() -/obj/machinery/power/shield_generator/cannot_transition_to(state_path) +/obj/machinery/shield_generator/cannot_transition_to(state_path) if(running) return SPAN_NOTICE("Turn off \the [src] first!") if(offline_for) return SPAN_NOTICE("Wait until \the [src] cools down from emergency shutdown first!") return ..() -/obj/machinery/power/shield_generator/attackby(obj/item/O, mob/user) - if(panel_open && (isMultitool(O) || isWirecutter(O))) - attack_hand(user) - return TRUE - return component_attackby(O, user) - -/obj/machinery/power/shield_generator/proc/energy_failure() +/obj/machinery/shield_generator/proc/energy_failure() if(running == SHIELD_DISCHARGING) shutdown_field() else @@ -212,7 +260,7 @@ for(var/obj/effect/shield/S in field_segments) S.fail(1) -/obj/machinery/power/shield_generator/proc/set_idle(var/new_state) +/obj/machinery/shield_generator/proc/set_idle(var/new_state) if(new_state) if(running == SHIELD_IDLE) return @@ -225,7 +273,7 @@ running = SHIELD_SPINNING_UP spinup_counter = round(spinup_delay / idle_multiplier) -/obj/machinery/power/shield_generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/shield_generator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] data["running"] = running @@ -259,16 +307,16 @@ ui.set_auto_update(1) -/obj/machinery/power/shield_generator/interface_interact(var/mob/user) +/obj/machinery/shield_generator/interface_interact(var/mob/user) ui_interact(user) return TRUE -/obj/machinery/power/shield_generator/CanUseTopic(var/mob/user) +/obj/machinery/shield_generator/CanUseTopic(var/mob/user) if(issilicon(user) && !Adjacent(user) && ai_control_disabled) return STATUS_UPDATE return ..() -/obj/machinery/power/shield_generator/OnTopic(user, href_list, datum/topic_state/state) +/obj/machinery/shield_generator/OnTopic(user, href_list, datum/topic_state/state) if(href_list["begin_shutdown"]) if(running < SHIELD_RUNNING) return @@ -308,7 +356,7 @@ var/old_energy = current_energy shutdown_field() log_and_message_admins("has triggered \the [src]'s emergency shutdown!", user) - spawn() + spawn() empulse(src, old_energy / 60000000, old_energy / 32000000, 1) // If shields are charged at 450 MJ, the EMP will be 7.5, 14.0625. 90 MJ, 1.5, 2.8125 old_energy = 0 @@ -321,7 +369,7 @@ var/new_range = input(user, "Enter new field range (1-[world.maxx]). Leave blank to cancel.", "Field Radius Control", field_radius) as num if(!new_range) return TOPIC_HANDLED - target_radius = between(1, new_range, world.maxx) + target_radius = clamp(new_range, 1, world.maxx) return TOPIC_REFRESH if(href_list["set_input_cap"]) @@ -348,14 +396,14 @@ idle_multiplier = new_idle return TOPIC_REFRESH -/obj/machinery/power/shield_generator/proc/field_integrity() +/obj/machinery/shield_generator/proc/field_integrity() if(full_shield_strength) return round(CLAMP01(current_energy / full_shield_strength) * 100) return 0 // Takes specific amount of damage -/obj/machinery/power/shield_generator/proc/take_shield_damage(var/damage, var/shield_damtype) +/obj/machinery/shield_generator/proc/take_shield_damage(var/damage, var/shield_damtype) var/energy_to_use = damage * ENERGY_PER_HP if(check_flag(MODEFLAG_MODULATE)) mitigation_em -= MITIGATION_HIT_LOSS @@ -373,9 +421,9 @@ mitigation_heat += MITIGATION_HIT_LOSS + MITIGATION_HIT_GAIN energy_to_use *= 1 - (mitigation_heat / 100) - mitigation_em = between(0, mitigation_em, mitigation_max) - mitigation_heat = between(0, mitigation_heat, mitigation_max) - mitigation_physical = between(0, mitigation_physical, mitigation_max) + mitigation_em = clamp(mitigation_em, 0, mitigation_max) + mitigation_heat = clamp(mitigation_heat, 0, mitigation_max) + mitigation_physical = clamp(mitigation_physical, 0, mitigation_max) current_energy -= energy_to_use @@ -394,11 +442,11 @@ // Checks whether specific flags are enabled -/obj/machinery/power/shield_generator/proc/check_flag(var/flag) +/obj/machinery/shield_generator/proc/check_flag(var/flag) return (shield_modes & flag) -/obj/machinery/power/shield_generator/proc/toggle_flag(var/flag) +/obj/machinery/shield_generator/proc/toggle_flag(var/flag) shield_modes ^= flag update_upkeep_multiplier() for(var/obj/effect/shield/S in field_segments) @@ -413,7 +461,7 @@ mitigation_heat = 0 -/obj/machinery/power/shield_generator/proc/get_flag_descriptions() +/obj/machinery/shield_generator/proc/get_flag_descriptions() var/list/all_flags = list() for(var/datum/shield_mode/SM in mode_list) if(SM.hacked_only && !hacked) @@ -431,7 +479,7 @@ // These two procs determine tiles that should be shielded given the field range. They are quite CPU intensive and may trigger BYOND infinite loop checks, therefore they are set // as background procs to prevent locking up the server. They are only called when the field is generated, or when hull mode is toggled on/off. -/obj/machinery/power/shield_generator/proc/fieldtype_square() +/obj/machinery/shield_generator/proc/fieldtype_square() set background = 1 var/list/out = list() var/list/base_turfs = get_base_turfs() @@ -456,30 +504,26 @@ return out -/obj/machinery/power/shield_generator/proc/fieldtype_hull() +/obj/machinery/shield_generator/proc/fieldtype_hull() set background = 1 . = list() var/list/base_turfs = get_base_turfs() - - - - for(var/turf/gen_turf in base_turfs) var/area/TA = null // Variable for area checking. Defining it here so memory does not have to be allocated repeatedly. - for(var/turf/T in RANGE_TURFS(gen_turf, field_radius)) + for(var/turf/T as anything in RANGE_TURFS(gen_turf, field_radius)) // Don't expand to space or on shuttle areas. - if(istype(T, /turf/space) || istype(T, /turf/simulated/open)) + if(T.is_open()) continue // Find adjacent space/shuttle tiles and cover them. Shuttles won't be blocked if shield diffuser is mapped in and turned on. for(var/turf/TN in orange(1, T)) TA = get_area(TN) - if ((istype(TN, /turf/space) || (istype(TN, /turf/simulated/open) && (istype(TA, /area/space) || TA.area_flags & AREA_FLAG_EXTERNAL)))) + if(TN.is_open() && (istype(TA, /area/space) || (TA.area_flags & AREA_FLAG_EXTERNAL))) . |= TN continue // Returns a list of turfs from which a field will propagate. If multi-Z mode is enabled, this will return a "column" of turfs above and below the generator. -/obj/machinery/power/shield_generator/proc/get_base_turfs() +/obj/machinery/shield_generator/proc/get_base_turfs() var/list/turfs = list() var/turf/T = get_turf(src) diff --git a/code/modules/shieldgen/emergency_shield.dm b/code/modules/shieldgen/emergency_shield.dm index 0b3363d7f9bc..149e2d54001f 100644 --- a/code/modules/shieldgen/emergency_shield.dm +++ b/code/modules/shieldgen/emergency_shield.dm @@ -1,29 +1,47 @@ /obj/machinery/shield - name = "Emergency energy shield" + name = "emergency energy shield" desc = "An energy shield used to contain hull breaches." icon = 'icons/effects/effects.dmi' icon_state = "shield-old" - density = 1 - opacity = 0 - anchored = 1 - unacidable = 1 - var/const/max_health = 200 - var/health = max_health //The shield can only take so much beating (prevents perma-prisons) + density = TRUE + opacity = FALSE + anchored = TRUE + max_health = 200 + frame_type = null + construct_state = /decl/machine_construction/noninteractive var/shield_generate_power = 7500 //how much power we use when regenerating var/shield_idle_power = 1500 //how much power we use when just being sustained. +/obj/machinery/shield/take_damage(amount, damtype, silent) + if(amount <= 0) + return + if(damtype != BRUTE && damtype != BURN && damtype != ELECTROCUTE) + return + if(!silent) + playsound(src.loc, 'sound/effects/EMPulse.ogg', 75, TRUE) + current_health -= amount + set_opacity(TRUE) + check_failure() + if(!QDELETED(src)) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, set_opacity), FALSE), 2 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) + +// This should never be damaged via anything but the shield's health dropping. +/obj/machinery/shield/dismantle() + check_failure() + return QDELING(src) // return true if deleted, false otherwise + /obj/machinery/shield/malfai name = "emergency forcefield" desc = "A weak forcefield which seems to be projected by the emergency atmosphere containment field." - health = max_health/2 // Half health, it's not suposed to resist much. + max_health = 100 // Half health, it's not suposed to resist much. /obj/machinery/shield/malfai/Process() - health -= 0.5 // Slowly lose integrity over time + current_health -= 0.5 // Slowly lose integrity over time check_failure() /obj/machinery/shield/proc/check_failure() - if (src.health <= 0) - visible_message("\The [src] dissipates!") + if (current_health <= 0) + visible_message(SPAN_NOTICE("\The [src] dissipates!")) qdel(src) return @@ -33,40 +51,16 @@ update_nearby_tiles(need_rebuild=1) /obj/machinery/shield/Destroy() - set_opacity(0) - set_density(0) + set_opacity(FALSE) + set_density(FALSE) update_nearby_tiles() . = ..() /obj/machinery/shield/CanPass(atom/movable/mover, turf/target, height, air_group) + // blocks air, normal behavior for everything else if(!height || air_group) return 0 else return ..() -/obj/machinery/shield/attackby(obj/item/W, mob/user) - if(!istype(W)) return - - //Calculate damage - var/aforce = W.force - if(W.damtype == BRUTE || W.damtype == BURN) - src.health -= aforce - - //Play a fitting sound - playsound(src.loc, 'sound/effects/EMPulse.ogg', 75, 1) - - check_failure() - set_opacity(1) - spawn(20) if(!QDELETED(src)) set_opacity(0) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - - ..() - -/obj/machinery/shield/bullet_act(var/obj/item/projectile/Proj) - health -= Proj.get_structure_damage() - ..() - check_failure() - set_opacity(1) - spawn(20) if(!QDELETED(src)) set_opacity(0) - /obj/machinery/shield/explosion_act(severity) . = ..() if(. && ((severity == 1 && prob(75)) || (severity == 2 && prob(50)) || (severity == 3 && prob(25)))) @@ -80,47 +74,36 @@ if(prob(50)) qdel(src) -/obj/machinery/shield/hitby(AM, var/datum/thrownthing/TT) - //Let everyone know we've been hit! - visible_message("\[src] was hit by [AM].") - - //Super realistic, resource-intensive, real-time damage calculations. - var/tforce = 0 - - if(ismob(AM)) // All mobs have a multiplier and a size according to mob_defines.dm - var/mob/I = AM - tforce = I.mob_size * (TT.speed/THROWFORCE_SPEED_DIVISOR) - else - var/obj/O = AM - tforce = O.throwforce * (TT.speed/THROWFORCE_SPEED_DIVISOR) - - src.health -= tforce - - //This seemed to be the best sound for hitting a force field. - playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1) - - check_failure() - - //The shield becomes dense to absorb the blow.. purely asthetic. - set_opacity(1) - spawn(20) if(!QDELETED(src)) set_opacity(0) +/obj/machinery/shield/hitby(atom/movable/hitter, var/datum/thrownthing/thrownthing) + . = ..() + if(.) + //Let everyone know we've been hit! + visible_message(SPAN_DANGER("\The [src] was hit by \the [hitter].")) + //Super realistic, resource-intensive, real-time damage calculations. + var/tforce = 0 + if(ismob(hitter)) // All mobs have a multiplier and a size according to mob_defines.dm + var/mob/mob_hitter = hitter + tforce = mob_hitter.mob_size * (thrownthing.speed/THROWFORCE_SPEED_DIVISOR) + else + var/obj/obj_hitter = hitter + tforce = obj_hitter.get_thrown_attack_force() * (thrownthing.speed/THROWFORCE_SPEED_DIVISOR) + if(tforce > 0) + take_damage(tforce, BRUTE) - ..() /obj/machinery/shieldgen name = "Emergency shield projector" desc = "Used to seal minor hull breaches." icon = 'icons/obj/objects.dmi' icon_state = "shieldoff" - density = 1 - opacity = 0 - anchored = 0 + density = TRUE + opacity = FALSE + anchored = FALSE initial_access = list(access_engine) - var/const/max_health = 100 - var/health = max_health + max_health = 100 var/active = 0 var/malfunction = 0 //Malfunction causes parts of the shield to slowly dissapate var/list/deployed_shields = list() - var/list/regenerating = list() + // var/list/regenerating = list() //TODO: Remove or add regeneration of destroyed shields var/is_open = 0 //Whether or not the wires are exposed var/locked = 0 var/check_delay = 60 //periodically recheck if we need to rebuild a shield @@ -135,7 +118,6 @@ if(active) return 0 //If it's already turned on, how did this get called? src.active = 1 - update_icon() create_shields() @@ -149,7 +131,6 @@ if(!active) return 0 //If it's already off, how did this get called? src.active = 0 - update_icon() collapse_shields() @@ -157,14 +138,14 @@ /obj/machinery/shieldgen/proc/create_shields() for(var/turf/target_tile in range(8, src)) - if ((istype(target_tile,/turf/space)|| istype(target_tile, /turf/simulated/open)) && !(locate(/obj/machinery/shield) in target_tile)) + if(target_tile.is_open() && !(locate(/obj/machinery/shield) in target_tile)) if (malfunction && prob(33) || !malfunction) var/obj/machinery/shield/S = new/obj/machinery/shield(target_tile) deployed_shields += S use_power_oneoff(S.shield_generate_power) for(var/turf/above in range(8, GetAbove(src)))//Probably a better way to do this. - if ((istype(above,/turf/space)|| istype(above, /turf/simulated/open)) && !(locate(/obj/machinery/shield) in above)) + if(above.is_open() && !(locate(/obj/machinery/shield) in above)) if (malfunction && prob(33) || !malfunction) var/obj/machinery/shield/A = new/obj/machinery/shield(above) deployed_shields += A @@ -204,12 +185,12 @@ else check_delay-- +// todo: roll this into normal machinery damage stuff? maybe it only blows up if active when it's destroyed? /obj/machinery/shieldgen/proc/checkhp() - if(health <= 30) + if(current_health <= 30) src.malfunction = 1 - if(health <= 0) - spawn(0) - explosion(get_turf(src.loc), 0, 0, 1, 0, 0, 0) + if(current_health <= 0) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), get_turf(src), 0, 0, 1, 0, 0, 0), 0) qdel(src) update_icon() return @@ -218,24 +199,24 @@ . = ..() if(.) if(severity == 1) - health -= 75 + current_health -= 75 else if(severity == 2) - health -= 30 + current_health -= 30 if(prob(15)) malfunction = 1 else if(severity == 3) - health -= 10 + current_health -= 10 checkhp() /obj/machinery/shieldgen/emp_act(severity) switch(severity) if(1) - src.health /= 2 //cut health in half + current_health /= 2 //cut health in half malfunction = 1 locked = pick(0,1) if(2) if(prob(50)) - src.health *= 0.3 //chop off a third of the health + current_health *= 0.3 //chop off a third of the health malfunction = 1 checkhp() @@ -250,14 +231,14 @@ return TRUE if (src.active) - user.visible_message("\icon[src] [user] deactivated the shield generator.", \ - "\icon[src] You deactivate the shield generator.", \ + user.visible_message("[html_icon(src)] [user] deactivated the shield generator.", \ + "[html_icon(src)] You deactivate the shield generator.", \ "You hear heavy droning fade out.") src.shields_down() else if(anchored) - user.visible_message("\icon[src] [user] activated the shield generator.", \ - "\icon[src] You activate the shield generator.", \ + user.visible_message("[html_icon(src)] [user] activated the shield generator.", \ + "[html_icon(src)] You activate the shield generator.", \ "You hear heavy droning.") src.shields_up() else @@ -270,8 +251,8 @@ update_icon() return 1 -/obj/machinery/shieldgen/attackby(obj/item/W, mob/user) - if(isScrewdriver(W)) +/obj/machinery/shieldgen/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item)) playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) if(is_open) to_chat(user, "You close the panel.") @@ -279,44 +260,43 @@ else to_chat(user, "You open the panel and expose the wiring.") is_open = 1 - - else if(isCoil(W) && malfunction && is_open) - var/obj/item/stack/cable_coil/coil = W + return TRUE + else if(IS_COIL(used_item) && malfunction && is_open) + var/obj/item/stack/cable_coil/coil = used_item to_chat(user, "You begin to replace the wires.") - //if(do_after(user, min(60, round( ((maxhealth/health)*10)+(malfunction*10) ))) //Take longer to repair heavier damage - if(do_after(user, 30,src)) - if (coil.use(1)) - health = max_health - malfunction = 0 - to_chat(user, "You repair the [src]!") - update_icon() - - else if(istype(W, /obj/item/wrench)) + if(!do_after(user, 3 SECONDS, src)) + to_chat(user, SPAN_NOTICE("You stop repairing \the [src].")) + return TRUE + if (coil.use(1)) + current_health = get_max_health() + malfunction = 0 + to_chat(user, "You repair \the [src]!") + update_icon() + return TRUE + else if(IS_WRENCH(used_item)) if(locked) to_chat(user, "The bolts are covered, unlocking this would retract the covers.") - return + return TRUE if(anchored) playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - to_chat(user, "'You unsecure the [src] from the floor!") + to_chat(user, "'You unsecure \the [src] from the floor!") if(active) - to_chat(user, "The [src] shuts off!") + to_chat(user, "\The [src] shuts off!") src.shields_down() - anchored = 0 - else - if(istype(get_turf(src), /turf/space)) return //No wrenching these in space! + anchored = FALSE + else if(!isspaceturf(get_turf(src))) //No wrenching these in space! playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - to_chat(user, "You secure the [src] to the floor!") - anchored = 1 - - - else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/modular_computer/pda)) + to_chat(user, "You secure \the [src] to the floor!") + anchored = TRUE + return TRUE + else if(istype(used_item, /obj/item/card/id) || istype(used_item, /obj/item/modular_computer/pda)) if(src.allowed(user)) src.locked = !src.locked to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]") else to_chat(user, "Access denied.") - else - ..() + return TRUE + return ..() /obj/machinery/shieldgen/on_update_icon() diff --git a/code/modules/shieldgen/energy_field.dm b/code/modules/shieldgen/energy_field.dm index 56c5e79f4437..63ce6167e33b 100644 --- a/code/modules/shieldgen/energy_field.dm +++ b/code/modules/shieldgen/energy_field.dm @@ -6,10 +6,10 @@ desc = "Impenetrable field of energy, capable of blocking anything as long as it's active." icon = 'icons/obj/machines/shielding.dmi' icon_state = "shield_normal" - anchored = 1 + anchored = TRUE layer = PROJECTILE_LAYER - density = 0 - invisibility = 101 + density = FALSE + invisibility = INVISIBILITY_ABSTRACT var/strength = 0 var/ticks_recovering = 10 @@ -35,12 +35,12 @@ //if we take too much damage, drop out - the generator will bring us back up if we have enough power ticks_recovering = min(ticks_recovering + 2, 10) if(strength < 1) - set_invisibility(101) + set_invisibility(INVISIBILITY_ABSTRACT) set_density(0) ticks_recovering = 10 strength = 0 else if(strength >= 1) - set_invisibility(0) + set_invisibility(INVISIBILITY_NONE) set_density(1) /obj/effect/energy_field/proc/Strengthen(var/severity) @@ -51,10 +51,10 @@ //if we take too much damage, drop out - the generator will bring us back up if we have enough power var/old_density = density if(strength >= 1) - set_invisibility(0) + set_invisibility(INVISIBILITY_NONE) set_density(1) else if(strength < 1) - set_invisibility(101) + set_invisibility(INVISIBILITY_ABSTRACT) set_density(0) if (density != old_density) diff --git a/code/modules/shieldgen/shieldwallgen.dm b/code/modules/shieldgen/shieldwallgen.dm index 4de56007f83b..8b1b0afd92c8 100644 --- a/code/modules/shieldgen/shieldwallgen.dm +++ b/code/modules/shieldgen/shieldwallgen.dm @@ -4,8 +4,8 @@ desc = "A shield generator." icon = 'icons/obj/machines/shieldgen.dmi' icon_state = "Shield_Gen" - anchored = 0 - density = 1 + anchored = FALSE + density = TRUE initial_access = list(list(access_engine_equip, access_research)) var/active = 0 var/power = 0 @@ -19,12 +19,12 @@ use_power = POWER_USE_OFF //Draws directly from power net. Does not use APC power. active_power_usage = 1200 -/obj/machinery/shieldwallgen/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/shieldwallgen/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = list() data["draw"] = round(power_draw) data["power"] = round(storedpower) data["maxpower"] = round(max_stored_power) - data["current_draw"] = ((between(500, max_stored_power - storedpower, power_draw)) + power ? active_power_usage : 0) + data["current_draw"] = ((clamp(max_stored_power - storedpower, 500, power_draw)) + power ? active_power_usage : 0) data["online"] = active == 2 ? 1 : 0 ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -85,7 +85,7 @@ if(!anchored) to_chat(user, "The shield generator needs to be firmly secured to the floor first.") return STATUS_CLOSE - if(src.locked && !istype(user, /mob/living/silicon)) + if(src.locked && !issilicon(user)) to_chat(user, "The controls are locked!") return STATUS_CLOSE if(power != 1) @@ -101,14 +101,18 @@ if(!anchored) power = 0 return 0 + var/turf/T = src.loc + if(!T) + power = 0 + return 0 var/obj/structure/cable/C = T.get_cable_node() var/datum/powernet/PN if(C) PN = C.powernet // find the powernet of the connected cable if(PN) - var/shieldload = between(500, max_stored_power - storedpower, power_draw) //what we try to draw + var/shieldload = clamp(max_stored_power - storedpower, 500, power_draw) //what we try to draw shieldload = PN.draw_power(shieldload) //what we actually get storedpower += shieldload @@ -148,8 +152,8 @@ src.active = 2 if(src.active >= 1) if(src.power == 0) - src.visible_message("The [src.name] shuts down due to lack of power!", \ - "You hear heavy droning fade out") + src.visible_message("\The [src] shuts down due to lack of power!", \ + "You hear heavy droning fade away.") src.active = 0 update_icon() for(var/dir in list(1,2,4,8)) src.cleanup(dir) @@ -199,35 +203,29 @@ CF.set_dir(field_dir) -/obj/machinery/shieldwallgen/attackby(obj/item/W, mob/user) - if(isWrench(W)) +/obj/machinery/shieldwallgen/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) if(active) to_chat(user, "Turn off the field generator first.") - return - - else if(anchored == 0) + return TRUE + if(!anchored) playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) to_chat(user, "You secure the external reinforcing bolts to the floor.") - src.anchored = 1 - return - - else if(anchored == 1) - playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) - to_chat(user, "You undo the external reinforcing bolts.") - src.anchored = 0 - return - - if(istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer)) + src.anchored = TRUE + return TRUE + playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) + to_chat(user, "You undo the external reinforcing bolts.") + src.anchored = FALSE + return TRUE + + if(istype(used_item, /obj/item/card/id)||istype(used_item, /obj/item/modular_computer)) if (src.allowed(user)) src.locked = !src.locked to_chat(user, "Controls are now [src.locked ? "locked." : "unlocked."]") else to_chat(user, "Access denied.") - return - - else - src.add_fingerprint(user) - ..() + return TRUE + return ..() /obj/machinery/shieldwallgen/proc/cleanup(var/NSEW) @@ -258,98 +256,85 @@ //////////////Containment Field START /obj/machinery/shieldwall - name = "Shield" + name = "shield" desc = "An energy shield." icon = 'icons/effects/effects.dmi' icon_state = "shieldwall" - anchored = 1 - density = 1 - unacidable = 1 - light_outer_range = 3 - var/needs_power = 0 - var/active = 1 - var/delay = 5 - var/last_active - var/mob/U + anchored = TRUE + density = TRUE + light_range = 3 + frame_type = null + construct_state = /decl/machine_construction/noninteractive + var/needs_power = FALSE var/obj/machinery/shieldwallgen/gen_primary var/obj/machinery/shieldwallgen/gen_secondary var/power_usage = 800 //how much power it takes to sustain the shield var/generate_power_usage = 5000 //how much power it takes to start up the shield +/obj/machinery/shieldwall/proc/use_generator_power(amount) + if(!needs_power) + return + var/obj/machinery/shieldwallgen/G = pick(gen_primary, gen_secondary) // if we use power and still exist, we assume we have both generators + G.storedpower -= amount + +/obj/machinery/shieldwall/take_damage(amount, damtype, silent) + if(amount <= 0) + return + if(damtype != BRUTE && damtype != BURN && damtype != ELECTROCUTE) + return + . = ..() // mostly just plays sound effects on damage + use_generator_power(500 * amount) + +// This should never be deleted via anything but the generator running out of power. +/obj/machinery/shieldwall/dismantle() + return FALSE // nope! + /obj/machinery/shieldwall/Initialize(mapload, obj/machinery/shieldwallgen/A, obj/machinery/shieldwallgen/B) - . = ..() + . = ..(mapload) update_nearby_tiles() gen_primary = A gen_secondary = B - if(A && B && A.active && B.active) - needs_power = 1 - if(prob(50)) - A.storedpower -= generate_power_usage - else - B.storedpower -= generate_power_usage + if(gen_primary?.active && gen_secondary?.active) + needs_power = TRUE + use_generator_power(generate_power_usage) else return INITIALIZE_HINT_QDEL /obj/machinery/shieldwall/Destroy() + gen_primary = null + gen_secondary = null update_nearby_tiles() . = ..() -/obj/machinery/shieldwall/attackby(var/obj/item/I, var/mob/user) - var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary - G.storedpower -= I.force*2500 - user.visible_message("\The [user] hits \the [src] with \the [I]!") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) - playsound(loc, 'sound/weapons/smash.ogg', 75, 1) - /obj/machinery/shieldwall/Process() - if(needs_power) - if(isnull(gen_primary)||isnull(gen_secondary)) - qdel(src) - return - - if(!(gen_primary.active)||!(gen_secondary.active)) - qdel(src) - return - - var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary - G.storedpower -= power_usage - - -/obj/machinery/shieldwall/bullet_act(var/obj/item/projectile/Proj) - if(needs_power) - var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary - G.storedpower -= 400 * Proj.get_structure_damage() - ..() - return + if(!needs_power) + return + if(QDELETED(gen_primary) || QDELETED(gen_secondary)) + qdel(src) + return + if(!gen_primary.active || !gen_secondary.active) + qdel(src) + return + use_generator_power(power_usage) /obj/machinery/shieldwall/explosion_act(severity) SHOULD_CALL_PARENT(FALSE) if(!needs_power) return - var/obj/machinery/shieldwallgen/G = prob(50) ? gen_primary : gen_secondary - switch(severity) - if(1) - G.storedpower -= rand(30000, min(G.storedpower, 60000)) - if(2) - G.storedpower -= rand(15000, min(G.storedpower, 30000)) - if(3) - G.storedpower -= rand(5000, min(G.storedpower, 15000)) + take_damage(100/severity, BRUTE, TRUE) // will drain power according to damage /obj/machinery/shieldwall/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 - + if(!height || air_group || !density) + return TRUE if(istype(mover) && mover.checkpass(PASS_FLAG_GLASS)) return prob(20) - else - if (istype(mover, /obj/item/projectile)) - return prob(10) - else - return !src.density + if (istype(mover, /obj/item/projectile)) + return prob(10) + return FALSE /obj/machinery/shieldwallgen/online - anchored = 1 - active = 1 + anchored = TRUE + active = TRUE /obj/machinery/shieldwallgen/online/Initialize() storedpower = max_stored_power diff --git a/code/modules/shuttles/antagonist.dm b/code/modules/shuttles/antagonist.dm index 2a2b827f10f1..9aa7aeee25ff 100644 --- a/code/modules/shuttles/antagonist.dm +++ b/code/modules/shuttles/antagonist.dm @@ -1,20 +1,9 @@ -/obj/machinery/computer/shuttle_control/multi/vox - name = "skipjack control console" - initial_access = list(access_syndicate) - shuttle_tag = "Skipjack" - -/obj/machinery/computer/shuttle_control/multi/syndicate +/obj/machinery/computer/shuttle_control/multi/mercenary name = "mercenary shuttle control console" - initial_access = list(access_syndicate) + initial_access = list(access_mercenary) shuttle_tag = "Mercenary" /obj/machinery/computer/shuttle_control/multi/rescue name = "rescue shuttle control console" initial_access = list(access_cent_specops) shuttle_tag = "Rescue" - -/obj/machinery/computer/shuttle_control/multi/ninja - name = "stealth shuttle control console" - initial_access = list(access_syndicate) - shuttle_tag = "Ninja" - diff --git a/code/modules/shuttles/docking_beacon.dm b/code/modules/shuttles/docking_beacon.dm new file mode 100644 index 000000000000..1df49863710e --- /dev/null +++ b/code/modules/shuttles/docking_beacon.dm @@ -0,0 +1,353 @@ +#define MAX_DOCKING_SIZE 30 +#define MAX_SHIP_TILES 400 +#define MAX_NAME_LENGTH 30 + +/obj/machinery/docking_beacon + name = "magnetic docking beacon" + desc = "A magnetic docking beacon that coordinates the movement of spacecraft into secure locations. It can additionally be used as a drydock for constructing shuttles." + icon = 'icons/obj/machines/power/fusion.dmi' + icon_state = "injector0" + density = TRUE + anchored = FALSE + construct_state = /decl/machine_construction/default/panel_closed + uncreated_component_parts = null + stat_immune = NOPOWER + base_type = /obj/machinery/docking_beacon + obj_flags = OBJ_FLAG_ROTATABLE + var/display_name // Display name of the docking beacon, editable on the docking control program. + var/list/permitted_shuttles = list() // Shuttles that are always permitted by the docking beacon. + + var/locked = TRUE + var/docking_by_codes = FALSE // Whether or not docking by code is permitted. + var/docking_codes = 0 // Required code for docking by code. + var/docking_width = 10 + var/docking_height = 10 + var/projecting = FALSE + + var/construction_mode = FALSE // Whether or not the docking beacon is constructing a ship. + var/ship_name = "" + var/ship_color = COLOR_WHITE + var/list/errors + +/obj/machinery/docking_beacon/Initialize() + . = ..() + set_extension(src, /datum/extension/network_device) + + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + + display_name = D.network_tag + + SSshuttle.docking_beacons += src + +/obj/machinery/docking_beacon/Destroy() + . = ..() + + SSshuttle.docking_beacons -= src + permitted_shuttles.Cut() + +/obj/machinery/docking_beacon/attackby(obj/item/used_item, mob/user) + if(IS_WRENCH(used_item)) + if(!allowed(user)) + to_chat(user, SPAN_WARNING("The bolts on \the [src] are locked!")) + return TRUE + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) + to_chat(user, SPAN_NOTICE("You [anchored ? "unanchor" : "anchor"] \the [src].")) + anchored = !anchored + return TRUE + + . = ..() + +/obj/machinery/docking_beacon/interface_interact(mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/docking_beacon/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, datum/topic_state/state = global.default_topic_state) + var/list/data = list() + data["size"] = "[docking_width] x [docking_height]" + data["locked"] = locked + data["display_name"] = display_name + data["allow_codes"] = docking_by_codes + if(allowed(user)) + data["permitted"] = permitted_shuttles + data["codes"] = docking_codes + else + data["permitted"] = list("ACCESS DENIED") + data["codes"] = "*******" + + data["construction_mode"] = construction_mode + data["errors"] = errors + data["ship_name"] = ship_name + data["ship_color"] = ship_color + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + ui = new(user, src, ui_key, "docking_beacon.tmpl", "Docking Beacon Settings", 540, 400, state = state) + ui.set_initial_data(data) + ui.open() + +/obj/machinery/docking_beacon/OnTopic(mob/user, href_list, datum/topic_state/state) + . = ..() + if(.) + return + + var/datum/extension/network_device/D = get_extension(src, /datum/extension/network_device) + + if(href_list["edit_codes"]) + var/newcode = sanitize(input("Input new docking codes:", "Docking codes", docking_codes) as text|null) + if(!CanInteract(user,state)) + return TOPIC_NOACTION + if(newcode) + docking_codes = uppertext(newcode) + D?.add_log("Docking codes of Docking Beacon [display_name] were changed.") + return TOPIC_REFRESH + + if(href_list["edit_display_name"]) + var/newname = sanitize(input("Input new display name:", "Display name", display_name) as text|null) + if(!CanInteract(user,state)) + return TOPIC_NOACTION + if(newname) + display_name = newname + D?.add_log("Display name of Docking Beacon [display_name] was changed to [newname].") + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(href_list["edit_size"]) + var/newwidth = input("Input new docking width for beacon:", "Docking size", docking_width) as num|null + var/newheight = input("Input new docking height for beacon:", "Docking size", docking_height) as num|null + if(!CanInteract(user,state)) + return TOPIC_NOACTION + if(newwidth && newheight) + docking_width = clamp(newwidth, 0, MAX_DOCKING_SIZE) + docking_height = clamp(newheight, 0, MAX_DOCKING_SIZE) + D?.add_log("Docking size of Docking Beacon [display_name] was changed to [newwidth], [newheight].") + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(href_list["toggle_lock"]) + locked = !locked + D?.add_log("Docking was [locked ? "locked" : "unlocked"] for Docking Beacon [display_name].") + return TOPIC_REFRESH + + if(href_list["toggle_codes"]) + docking_by_codes = !docking_by_codes + D?.add_log("Docking by codes was [docking_by_codes ? "enabled" : "disabled"] for Docking Beacon [display_name].") + return TOPIC_REFRESH + + if(href_list["edit_permitted_shuttles"]) + var/shuttle = sanitize(input(user,"Enter the ID of the shuttle you wish to permit/unpermit for this beacon:", "Enter ID") as text|null) + if(shuttle) + if(shuttle in permitted_shuttles) + permitted_shuttles -= shuttle + D?.add_log("Docking Beacon [display_name] had [shuttle] removed from its permitted shuttle list.") + return TOPIC_REFRESH + else if(shuttle in SSshuttle.shuttles) + permitted_shuttles += shuttle + D?.add_log("Docking Beacon [display_name] had [shuttle] added to its permitted shuttle list.") + return TOPIC_REFRESH + return TOPIC_HANDLED + + if(href_list["project"]) + if(projecting) + return + visible_message(SPAN_NOTICE("\The [src] projects a hologram of its effective landing area.")) + for(var/turf/T in get_turfs()) + new /obj/effect/temporary(T, 5 SECONDS,'icons/effects/alphacolors.dmi', "green") + projecting = TRUE + addtimer(CALLBACK(src, PROC_REF(allow_projection)), 10 SECONDS) // No spamming holograms. + + if(href_list["settings"]) + D.ui_interact(user) + return TOPIC_HANDLED + + if(href_list["toggle_construction"]) + construction_mode = !construction_mode + LAZYCLEARLIST(errors) + return TOPIC_REFRESH + + if(href_list["change_color"]) + var/new_color = input(user, "Choose a color.", "\the [src]", ship_color) as color|null + if(!CanInteract(user,state)) + return TOPIC_NOACTION + if(new_color && new_color != ship_color) + ship_color = new_color + to_chat(user, SPAN_NOTICE("You set \the [src] to create a ship with this color.")) + return TOPIC_HANDLED + + if(href_list["change_ship_name"]) + var/new_ship_name = sanitize(input(user, "Enter a new name for the ship:", "Change ship name.") as null|text) + if(!CanInteract(user,state)) + return TOPIC_NOACTION + if(!new_ship_name) + return TOPIC_HANDLED + if(length(new_ship_name) > MAX_NAME_LENGTH) + to_chat(user, SPAN_WARNING("That name is too long!")) + return TOPIC_HANDLED + ship_name = new_ship_name + return TOPIC_REFRESH + + if(href_list["check_validity"]) + if(!construction_mode) + return TOPIC_HANDLED + check_ship_validity(get_areas()) + return TOPIC_REFRESH + + if(href_list["finalize"]) + if(!construction_mode) + return TOPIC_HANDLED + var/confirm = alert(user, "This will permanently finalize the ship, are you sure?", "Ship finalization", "No", "Yes") + if(!CanInteract(user,state)) + return TOPIC_NOACTION + if(confirm == "Yes") + if(create_ship()) + construction_mode = FALSE + ship_name = "" + LAZYCLEARLIST(errors) + else + to_chat(user, SPAN_WARNING("Could not finalize the construction of the ship!")) + return TOPIC_REFRESH + +/obj/machinery/docking_beacon/proc/allow_projection() + projecting = FALSE + +/obj/machinery/docking_beacon/proc/check_permission(var/shuttle_tag, var/codes) + . = FALSE + if(construction_mode) + return + if(!locked) + return TRUE + if(docking_by_codes && docking_codes == codes) + return TRUE + if(shuttle_tag in permitted_shuttles) + return TRUE + +/obj/machinery/docking_beacon/proc/get_turfs() + switch(dir) + if(NORTH) + return block(x-((docking_width-1)/2), y+docking_height+1, z, x+((docking_width-1)/2), y+1, z) + if(SOUTH) + return block(x-((docking_width-1)/2), y-docking_height-1, z, x+((docking_width-1)/2), y-1, z) + if(EAST) + return block(x+docking_height+1, y-((docking_width-1)/2), z, x+1, y+((docking_width-1)/2), z) + if(WEST) + return block(x-docking_height-1, y-((docking_width-1)/2), z, x-1, y+((docking_width-1)/2), z) + +/obj/machinery/docking_beacon/proc/get_areas() + . = list() + for(var/turf/T in get_turfs()) + var/area/A = T.loc + // Ignore space or other background areas. + if(A.area_flags & AREA_FLAG_IS_BACKGROUND) + continue + if(A in SSshuttle.shuttle_areas) + continue + . |= A + +/obj/machinery/docking_beacon/proc/check_ship_validity(var/list/target_areas) + LAZYCLEARLIST(errors) + . = TRUE + if(!ship_name || length(ship_name) < 5) + LAZYDISTINCTADD(errors, "The ship must have a name.") + . = FALSE + else + // Check if another ship/shuttle has an identical name. + for(var/shuttle_tag in SSshuttle.shuttles) + if(ship_name == shuttle_tag) + LAZYDISTINCTADD(errors, "A ship with an identical name has already been registered.") + . = FALSE + break + if(!length(target_areas)) + LAZYDISTINCTADD(errors, "The ship must have defined areas in the construction zone.") + return FALSE + var/list/area_turfs = list() + for(var/area/A in target_areas) + for(var/turf/T in A) + area_turfs |= T + if(length(area_turfs) > MAX_SHIP_TILES) + LAZYDISTINCTADD(errors, "The ship is too large.") + return FALSE // If the ship is too large, skip contiguity checks. + + // Check to make sure all the ships areas are connected. + . = min(., check_contiguity(area_turfs)) + if(.) + LAZYDISTINCTADD(errors, "The ship is valid for finalization.") + +/obj/machinery/docking_beacon/proc/check_contiguity(var/list/area_turfs) + if(!area_turfs || !LAZYLEN(area_turfs)) + return FALSE + var/turf/start_turf = pick(area_turfs) // The last added area is the most likely to be incontiguous. + var/list/pending_turfs = list(start_turf) + var/list/checked_turfs = list() + + while(pending_turfs.len) + var/turf/T = pending_turfs[1] + pending_turfs -= T + for(var/dir in global.cardinal) // Floodfill to find all turfs contiguous with the randomly chosen start_turf. + var/turf/NT = get_step(T, dir) + if(!isturf(NT) || !(NT in area_turfs) || (NT in pending_turfs) || (NT in checked_turfs)) + continue + pending_turfs += NT + + checked_turfs += T + + if(LAZYLEN(area_turfs.Copy()) - LAZYLEN(checked_turfs)) // If there are turfs in area_turfs, not in checked_turfs there are non-contiguous turfs in the selection. + LAZYDISTINCTADD(errors, "The ship construction is not contiguous.") + return FALSE + return TRUE + +/obj/machinery/docking_beacon/proc/create_ship() + var/list/shuttle_areas = get_areas() + // Double check to ensure the ship is valid. + if(!check_ship_validity(shuttle_areas)) + return FALSE + + + // Locate the base area by stepping towards the edge of the map in the direction the beacon is facing. + var/area/base_area + var/turf/area_turf = get_step(src, dir) + + while(area_turf) + var/area/A = area_turf.loc + if(A && (A.area_flags & AREA_FLAG_IS_BACKGROUND)) + base_area = A + break + area_turf = get_step(area_turf, dir) + + // Otherwise, use the level or world area. + if(!base_area) + var/datum/level_data/LD = SSmapping.levels_by_z[z] + if(istype(LD)) + base_area = LD.get_base_area_instance() + else + base_area = locate(world.area) + + var/turf/center_turf + switch(dir) + if(NORTH) + center_turf = locate(x, (y+docking_height/2)+1, z) + if(SOUTH) + center_turf = locate(x, (y-docking_height/2)-1, z) + if(EAST) + center_turf = locate(x+(docking_height/2)+1, y, z) + if(WEST) + center_turf = locate(x-(docking_height/2)-1, y, z) + if(!center_turf) + return FALSE + var/obj/effect/shuttle_landmark/temporary/construction/landmark = new(get_turf(src), base_area, get_base_turf(z)) + var/list/shuttle_args = list(landmark, shuttle_areas.Copy(), ship_name) + SSshuttle.initialize_shuttle(/datum/shuttle/autodock/overmap/created, null, shuttle_args) + + new /obj/effect/overmap/visitable/ship/landable/created(get_turf(src), ship_name, ship_color, global.reverse_dir[dir]) + permitted_shuttles |= ship_name + return TRUE + +/obj/effect/shuttle_landmark/temporary/construction + flags = 0 + +/obj/effect/shuttle_landmark/temporary/construction/Initialize(var/mapload, var/area/b_area, var/turf/b_turf) + base_area = b_area + base_turf = b_turf + . = ..(mapload) + +#undef MAX_DOCKING_SIZE +#undef MAX_SHIP_TILES +#undef MAX_NAME_LENGTH \ No newline at end of file diff --git a/code/modules/shuttles/escape_pods.dm b/code/modules/shuttles/escape_pods.dm index c273a86f0b52..8d1ee2489bec 100644 --- a/code/modules/shuttles/escape_pods.dm +++ b/code/modules/shuttles/escape_pods.dm @@ -1,12 +1,17 @@ -var/list/escape_pods = list() -var/list/escape_pods_by_name = list() +var/global/list/escape_pods = list() +var/global/list/escape_pods_by_name = list() /datum/shuttle/autodock/ferry/escape_pod var/datum/computer/file/embedded_program/docking/simple/escape_pod_berth/arming_controller - category = /datum/shuttle/autodock/ferry/escape_pod + abstract_type = /datum/shuttle/autodock/ferry/escape_pod move_time = 100 -/datum/shuttle/autodock/ferry/escape_pod/New() +/datum/shuttle/autodock/ferry/escape_pod/New(map_hash) + ..() + if(map_hash) + ADJUST_TAG_VAR(arming_controller, map_hash) // Unclear how functional this is with lateloaded maps; adjusting for consistency. + if(!SSevac.evacuation_controller) + PRINT_STACK_TRACE("This pod should not be used on any map with no evacuation controller, which includes this one.") if(name in escape_pods_by_name) CRASH("An escape pod with the name '[name]' has already been defined.") move_time = SSevac.evacuation_controller.evac_transit_delay + rand(-30, 60) @@ -14,8 +19,6 @@ var/list/escape_pods_by_name = list() escape_pods += src move_time = round(SSevac.evacuation_controller.evac_transit_delay/10) - ..() - //find the arming controller (berth) var/arming_controller_tag = arming_controller arming_controller = SSshuttle.docking_registry[arming_controller_tag] @@ -62,7 +65,7 @@ var/list/escape_pods_by_name = list() "override_enabled" = docking_program.override_enabled, "door_state" = docking_program.memory["door_status"]["state"], "door_lock" = docking_program.memory["door_status"]["lock"], - "can_force" = pod.can_force() || (SSevac.evacuation_controller.has_evacuated() && pod.can_launch()), //allow players to manually launch ahead of time if the shuttle leaves + "can_force" = pod.can_force() || (SSevac.evacuation_controller?.has_evacuated() && pod.can_launch()), //allow players to manually launch ahead of time if the shuttle leaves "is_armed" = pod.arming_controller.armed, ) @@ -82,7 +85,7 @@ var/list/escape_pods_by_name = list() if(href_list["command"] == "force_launch") if (pod.can_force()) pod.force_launch(src) - else if (SSevac.evacuation_controller.has_evacuated() && pod.can_launch()) //allow players to manually launch ahead of time if the shuttle leaves + else if (SSevac.evacuation_controller?.has_evacuated() && pod.can_launch()) //allow players to manually launch ahead of time if the shuttle leaves pod.launch(src) return TOPIC_REFRESH @@ -116,7 +119,7 @@ var/list/escape_pods_by_name = list() /obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth/emag_act(var/remaining_charges, var/mob/user) if (!emagged) - to_chat(user, "You emag the [src], arming the escape pod!") + to_chat(user, "You emag \the [src], arming the escape pod!") emagged = 1 if (istype(program, /datum/computer/file/embedded_program/docking/simple/escape_pod_berth)) var/datum/computer/file/embedded_program/docking/simple/escape_pod_berth/P = program @@ -139,7 +142,7 @@ var/list/escape_pods_by_name = list() /datum/computer/file/embedded_program/docking/simple/escape_pod_berth/receive_user_command(command) if (!armed) - return TRUE // Eat all commands. + return TOPIC_HANDLED // Eat all commands. return ..(command) /datum/computer/file/embedded_program/docking/simple/escape_pod_berth/process() diff --git a/code/modules/shuttles/landmarks.dm b/code/modules/shuttles/landmarks.dm index 677f34c7bd66..4029741fcbda 100644 --- a/code/modules/shuttles/landmarks.dm +++ b/code/modules/shuttles/landmarks.dm @@ -1,30 +1,39 @@ -//making this separate from /obj/effect/landmark until that mess can be dealt with +var/global/list/shuttle_landmarks = list() + +//making this separate from /obj/abstract/landmark until that mess can be dealt with /obj/effect/shuttle_landmark name = "Nav Point" - icon = 'icons/effects/effects.dmi' - icon_state = "energynet" - anchored = 1 - unacidable = 1 - simulated = 0 - invisibility = 101 + icon = 'icons/effects/landmarks.dmi' + icon_state = "shuttle_landmark" + anchored = TRUE + simulated = FALSE + layer = ABOVE_PROJECTILE_LAYER + invisibility = INVISIBILITY_ABSTRACT + is_spawnable_type = FALSE var/landmark_tag //ID of the controller on the dock side var/datum/computer/file/embedded_program/docking/docking_controller - //ID of controller used for this landmark for shuttles with multiple ones. + //Docking cues for shuttles with multiple docking controllers. Format: shuttle type -> string cue. On the shuttle, set docking_cues as well. var/list/special_dock_targets //when the shuttle leaves this landmark, it will leave behind the base area //also used to determine if the shuttle can arrive here without obstruction var/area/base_area - //Will also leave this type of turf behind if set. + //Will also leave this type of turf behind if set, if the turfs do not have prev_type set. var/turf/base_turf - //Name of the shuttle, null for generic waypoint + //Type path of a shuttle to which this landmark is restricted, null for generic waypoint. var/shuttle_restricted + var/overmap_id = OVERMAP_ID_SPACE var/flags = 0 +/obj/effect/shuttle_landmark/Destroy() + global.shuttle_landmarks -= src + . = ..() + /obj/effect/shuttle_landmark/Initialize() . = ..() + global.shuttle_landmarks += src if(docking_controller) . = INITIALIZE_HINT_LATELOAD @@ -33,7 +42,7 @@ var/turf/T = get_turf(src) if(T) base_turf = T.type - else + else if(ispath(base_area) || !base_area) base_area = locate(base_area || world.area) SetName(name + " ([x],[y])") @@ -46,15 +55,21 @@ docking_controller = SSshuttle.docking_registry[docking_tag] if(!istype(docking_controller)) log_error("Could not find docking controller for shuttle waypoint '[name]', docking tag was '[docking_tag]'.") - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/location = map_sectors["[z]"] - if(location && location.docking_codes) - docking_controller.docking_codes = location.docking_codes + + var/obj/effect/overmap/visitable/location = global.overmap_sectors[z] + if(location && location.docking_codes) + docking_controller.docking_codes = location.docking_codes + +/obj/effect/shuttle_landmark/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(landmark_tag, map_hash) + if(docking_controller) + ADJUST_TAG_VAR(docking_controller, map_hash) /obj/effect/shuttle_landmark/forceMove() - var/obj/effect/overmap/visitable/map_origin = map_sectors["[z]"] + var/obj/effect/overmap/visitable/map_origin = global.overmap_sectors[z] . = ..() - var/obj/effect/overmap/visitable/map_destination = map_sectors["[z]"] + var/obj/effect/overmap/visitable/map_destination = global.overmap_sectors[z] if(map_origin != map_destination) if(map_origin) map_origin.remove_landmark(src, shuttle_restricted) @@ -62,17 +77,19 @@ map_destination.add_landmark(src, shuttle_restricted) //Called when the landmark is added to an overmap sector. -/obj/effect/shuttle_landmark/proc/sector_set(var/obj/effect/overmap/visitable/O, shuttle_name) - shuttle_restricted = shuttle_name +/obj/effect/shuttle_landmark/proc/sector_set(var/obj/effect/overmap/visitable/O, shuttle_restricted_type) + shuttle_restricted = shuttle_restricted_type /obj/effect/shuttle_landmark/proc/is_valid(var/datum/shuttle/shuttle) if(shuttle.current_location == src) return FALSE + var/atom/movable/center_of_rotation = shuttle.get_center_of_rotation() + var/angle_offset = shuttle.get_angle_offset(center_of_rotation, src) for(var/area/A in shuttle.shuttle_area) - var/list/translation = get_turf_translation(get_turf(shuttle.current_location), get_turf(src), A.contents) + var/list/translation = get_turf_translation(get_turf(center_of_rotation), get_turf(src), A.contents, angle = angle_offset) if(check_collision(base_area, list_values(translation))) return FALSE - var/conn = GetConnectedZlevels(z) + var/conn = SSmapping.get_connected_levels(z) for(var/w in (z - shuttle.multiz) to z) if(!(w in conn)) return FALSE @@ -101,6 +118,11 @@ return TRUE //dense turf return FALSE +/obj/effect/shuttle_landmark/proc/get_angle_offset(obj/effect/shuttle_landmark/other) + if(other.flags & SLANDMARK_FLAG_REORIENT) + return dir2angle(other.dir) - dir2angle(dir) + return 0 + //Self-naming/numbering ones. /obj/effect/shuttle_landmark/automatic name = "Navpoint" @@ -113,21 +135,38 @@ /obj/effect/shuttle_landmark/automatic/sector_set(var/obj/effect/overmap/visitable/O) ..() - SetName("[O.name] - [initial(name)] ([x],[y])") + SetName("[initial(name)] ([x],[y],[z])") //Subtype that calls explosion on init to clear space for shuttles /obj/effect/shuttle_landmark/automatic/clearing + name = "clearing" + var/offset = FALSE var/radius = 10 -/obj/effect/shuttle_landmark/automatic/clearing/Initialize() +/obj/effect/shuttle_landmark/automatic/clearing/Initialize(var/ml, var/supplied_radius) ..() + if(!isnull(supplied_radius)) + radius = supplied_radius return INITIALIZE_HINT_LATELOAD /obj/effect/shuttle_landmark/automatic/clearing/LateInitialize() ..() - for(var/turf/T in range(radius, src)) + var/center + if(offset) + switch(dir) + if(NORTH) + center = locate(src.x, src.y - radius / 2, src.z) + if(SOUTH) + center = locate(src.x, src.y + radius / 2, src.z) + if(EAST) + center = locate(src.x - radius / 2, src.y, src.z) + if(WEST) + center = locate(src.x + radius / 2, src.y, src.z) + center ||= src + for(var/turf/T in circlerangeturfs(center, radius)) if(T.density) T.ChangeTurf(get_base_turf_by_area(T)) + T.turf_flags |= TURF_FLAG_NO_POINTS_OF_INTEREST //Used for custom landing locations. Self deletes after a shuttle leaves. /obj/effect/shuttle_landmark/temporary @@ -135,8 +174,10 @@ landmark_tag = "landing" flags = SLANDMARK_FLAG_AUTOSET -/obj/effect/shuttle_landmark/temporary/Initialize() +/obj/effect/shuttle_landmark/temporary/Initialize(var/mapload, var/secure = TRUE) landmark_tag += "-[random_id("landmarks",1,9999)]" + if(!secure) + flags |= (SLANDMARK_FLAG_DISCONNECTED | SLANDMARK_FLAG_ZERO_G) . = ..() /obj/effect/shuttle_landmark/temporary/Destroy() @@ -156,11 +197,12 @@ icon = 'icons/obj/items/device/long_range_flare.dmi' icon_state = "bluflare" light_color = "#3728ff" + material = /decl/material/solid/organic/plastic var/active /obj/item/spaceflare/attack_self(var/mob/user) if(!active) - visible_message("[user] pulls the cord, activating the [src].") + visible_message("[user] pulls the cord, activating \the [src].") activate() /obj/item/spaceflare/proc/activate() @@ -168,11 +210,11 @@ return var/turf/T = get_turf(src) var/mob/M = loc - if(istype(M) && !M.unEquip(src, T)) + if(istype(M) && !M.try_unequip(src, T)) return active = 1 - anchored = 1 + anchored = TRUE var/obj/effect/shuttle_landmark/automatic/mark = new(T) mark.SetName("Beacon signal ([T.x],[T.y])") @@ -180,6 +222,7 @@ update_icon() /obj/item/spaceflare/on_update_icon() + . = ..() if(active) icon_state = "bluflare_on" - set_light(0.3, 0.1, 6, 2, "85d1ff") \ No newline at end of file + set_light(6, 2, "#85d1ff") \ No newline at end of file diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm index ec106e0841fb..2967cb9e7abd 100644 --- a/code/modules/shuttles/shuttle.dm +++ b/code/modules/shuttles/shuttle.dm @@ -2,6 +2,7 @@ /datum/shuttle var/name = "" + var/display_name = "" // User-facing; defaults to name. var/warmup_time = 0 var/moving_status = SHUTTLE_IDLE @@ -11,10 +12,11 @@ var/arrive_time = 0 //the time at which the shuttle arrives when long jumping var/flags = 0 var/process_state = IDLE_STATE //Used with SHUTTLE_FLAGS_PROCESS, as well as to store current state. - var/category = /datum/shuttle + abstract_type = /datum/shuttle var/multiz = 0 //how many multiz levels, starts at 0 - var/ceiling_type = /turf/unsimulated/floor/shuttle_ceiling + var/ceiling_type = /turf/floor/shuttle_ceiling + var/force_ceiling_on_init = TRUE // Whether or not to force ceilings turfs to be created above on initialization. var/sound_takeoff = 'sound/effects/shuttle_takeoff.ogg' var/sound_landing = 'sound/effects/shuttle_landing.ogg' @@ -29,20 +31,44 @@ var/mothershuttle //tag of mothershuttle var/motherdock //tag of mothershuttle landmark, defaults to starting location -/datum/shuttle/New(_name, var/obj/effect/shuttle_landmark/initial_location) + /// The landmark_tag of the landmark being used to match rotation and placement when docking. + var/current_port_tag + /// A list of all available docking ports to use for rotation/placement when landing and docking. + var/list/docking_ports + + /// Set to TRUE to process every time SSshuttle fires, regardless of state. + var/always_process = FALSE + +/datum/shuttle/New(map_hash, var/obj/effect/shuttle_landmark/initial_location) ..() - if(_name) - src.name = _name + if(!display_name) + display_name = name + if(map_hash) // We adjust all tag vars, including name, for the map on which they are loaded. This is also done on subtypes. + ADJUST_TAG_VAR(name, map_hash) + ADJUST_TAG_VAR(current_location, map_hash) + ADJUST_TAG_VAR(logging_home_tag, map_hash) + ADJUST_TAG_VAR(mothershuttle, map_hash) + ADJUST_TAG_VAR(motherdock, map_hash) var/list/areas = list() - if(!islist(shuttle_area)) - shuttle_area = list(shuttle_area) - for(var/T in shuttle_area) - var/area/A = locate(T) - if(!istype(A)) - CRASH("Shuttle \"[name]\" couldn't locate area [T].") - areas += A - shuttle_area = areas + if(!isnull(shuttle_area)) + if(!islist(shuttle_area)) + shuttle_area = list(shuttle_area) + for(var/area_type in shuttle_area) + if(istype(area_type, /area)) // If the shuttle area is already an instance, it does not need to be located. + areas += area_type + events_repository.register(/decl/observ/destroyed, area_type, src, PROC_REF(remove_shuttle_area)) + continue + var/area/A + if(map_hash && islist(SSshuttle.map_hash_to_areas[map_hash])) + A = SSshuttle.map_hash_to_areas[map_hash][area_type] // We try to find the correct area of the given type. + else + A = locate(area_type) // But if this is a mainmap shuttle, there is only one anyway so just find it. + if(!istype(A)) + CRASH("Shuttle \"[name]\" couldn't locate area [area_type].") + areas += A + events_repository.register(/decl/observ/destroyed, A, src, PROC_REF(remove_shuttle_area)) + shuttle_area = areas if(initial_location) current_location = initial_location @@ -63,6 +89,15 @@ CRASH("A supply shuttle is already defined.") SSsupply.shuttle = src + create_ceiling(force_ceiling_on_init) + +/datum/shuttle/proc/remove_shuttle_area(area/area_to_remove) + events_repository.unregister(/decl/observ/destroyed, area_to_remove, src, PROC_REF(remove_shuttle_area)) + SSshuttle.shuttle_areas -= area_to_remove + shuttle_area -= area_to_remove + if(!length(shuttle_area)) + qdel(src) + /datum/shuttle/Destroy() current_location = null @@ -74,6 +109,10 @@ . = ..() +// Return FALSE to end a jump early. +/datum/shuttle/proc/post_warmup_checks() + return TRUE + /datum/shuttle/proc/short_jump(var/obj/effect/shuttle_landmark/destination) if(moving_status != SHUTTLE_IDLE) return @@ -82,9 +121,9 @@ playsound(current_location, sound_takeoff, 100, 20, 0.2) spawn(warmup_time*10) if (moving_status == SHUTTLE_IDLE) - return FALSE //someone cancelled the launch + return //someone cancelled the launch - if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch + if(!post_warmup_checks() || !fuel_check()) //fuel error (probably out of fuel) occurred, so cancel the launch var/datum/shuttle/autodock/S = src if(istype(S)) S.cancel_launch(null) @@ -103,10 +142,11 @@ if(sound_takeoff) playsound(current_location, sound_takeoff, 100, 20, 0.2) spawn(warmup_time*10) + if(moving_status == SHUTTLE_IDLE) return //someone cancelled the launch - if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch + if(!post_warmup_checks() || !fuel_check()) //fuel error (probably out of fuel) occurred, so cancel the launch var/datum/shuttle/autodock/S = src if(istype(S)) S.cancel_launch(null) @@ -144,13 +184,15 @@ return FALSE testing("[src] moving to [destination]. Areas are [english_list(shuttle_area)]") var/list/translation = list() + var/atom/movable/center_of_rotation = get_center_of_rotation() + var/angle_offset = get_angle_offset(center_of_rotation, destination) for(var/area/A in shuttle_area) testing("Moving [A]") - translation += get_turf_translation(get_turf(current_location), get_turf(destination), A.contents) + translation += get_turf_translation(get_turf(center_of_rotation), get_turf(destination), A.contents, angle = angle_offset) var/obj/effect/shuttle_landmark/old_location = current_location - GLOB.shuttle_pre_move_event.raise_event(src, old_location, destination) - shuttle_moved(destination, translation) - GLOB.shuttle_moved_event.raise_event(src, old_location, destination) + RAISE_EVENT(/decl/observ/shuttle_pre_move, src, old_location, destination) + shuttle_moved(destination, translation, angle_offset) + RAISE_EVENT(/decl/observ/shuttle_moved, src, old_location, destination) if(istype(old_location)) old_location.shuttle_departed(src) destination.shuttle_arrived(src) @@ -163,20 +205,18 @@ if(current_location == destination) log_error("Error when attempting to force move a shuttle: Attempted to move [src] to its current location [destination].") return FALSE - if(destination.shuttle_restricted != name) - log_error("Error when attempting to force move a shuttle: Destination location not restricted for [src]'s use.") - return FALSE - + testing("Force moving [src] to [destination]. Areas are [english_list(shuttle_area)]") var/list/translation = list() - + var/atom/movable/center_of_rotation = get_center_of_rotation() + var/angle_offset = get_angle_offset(center_of_rotation, destination) for(var/area/A in shuttle_area) testing("Moving [A]") - translation += get_turf_translation(get_turf(current_location), get_turf(destination), A.contents) + translation += get_turf_translation(get_turf(center_of_rotation), get_turf(destination), A.contents, angle = angle_offset) var/obj/effect/shuttle_landmark/old_location = current_location - GLOB.shuttle_pre_move_event.raise_event(src, old_location, destination) - shuttle_moved(destination, translation) - GLOB.shuttle_moved_event.raise_event(src, old_location, destination) + RAISE_EVENT(/decl/observ/shuttle_pre_move, src, old_location, destination) + shuttle_moved(destination, translation, angle_offset) + RAISE_EVENT(/decl/observ/shuttle_moved, src, old_location, destination) if(istype(old_location)) old_location.shuttle_departed(src) destination.shuttle_arrived(src) @@ -185,7 +225,7 @@ //just moves the shuttle from A to B, if it can be moved //A note to anyone overriding move in a subtype. shuttle_moved() must absolutely not, under any circumstances, fail to move the shuttle. //If you want to conditionally cancel shuttle launches, that logic must go in short_jump(), long_jump() or attempt_move() -/datum/shuttle/proc/shuttle_moved(var/obj/effect/shuttle_landmark/destination, var/list/turf_translation) +/datum/shuttle/proc/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) // log_debug("move_shuttle() called for [shuttle_tag] leaving [origin] en route to [destination].") // log_degug("area_coming_from: [origin]") @@ -213,38 +253,61 @@ bug.gib() else qdel(AM) //it just gets atomized I guess? TODO throw it into space somewhere, prevents people from using shuttles as an atom-smasher - var/list/powernets = list() - for(var/area/A in shuttle_area) - // if there was a zlevel above our origin, erase our ceiling now we're leaving - if(HasAbove(current_location.z)) - for(var/turf/TO in A.contents) - var/turf/TA = GetAbove(TO) - if(istype(TA, ceiling_type)) - TA.ChangeTurf(get_base_turf_by_area(TA), 1, 1) - if(knockdown) + + if(knockdown) + for(var/area/A in shuttle_area) A.throw_unbuckled_occupants(4, 1) - for(var/obj/structure/cable/C in A) - powernets |= C.powernet if(logging_home_tag) var/datum/shuttle_log/s_log = SSshuttle.shuttle_logs[src] s_log.handle_move(current_location, destination) - translate_turfs(turf_translation, current_location.base_area, current_location.base_turf) + // if there's a zlevel above our destination, paint in a ceiling on it so we retain our air + create_translated_ceiling(FALSE, turf_translation) + + var/list/new_turfs = translate_turfs(turf_translation, current_location.base_area, current_location.base_turf, TRUE, TRUE, angle = angle) current_location = destination - // if there's a zlevel above our destination, paint in a ceiling on it so we retain our air - if(HasAbove(current_location.z)) - for(var/area/A in shuttle_area) - for(var/turf/TD in A.contents) - var/turf/TA = GetAbove(TD) - if(istype(TA, get_base_turf_by_area(TA)) || istype(TA, /turf/simulated/open)) - if(get_area(TA) in shuttle_area) - continue - TA.ChangeTurf(ceiling_type, TRUE, TRUE, TRUE) - - // Remove all powernets that were affected, and rebuild them. + // remove the old ceiling, if it existed + for(var/turf/TO in turf_translation) + var/turf/TA = GetAbove(TO) + if(istype(TA)) + if(istype(TA, ceiling_type)) + TA.ChangeTurf(get_base_turf_by_area(TA), TRUE, TRUE, TRUE) + else if(TA.prev_type == ceiling_type) + TA.prev_type = null + + handle_pipes_and_power_on_move(new_turfs) + + if(mothershuttle) + var/datum/shuttle/mothership = SSshuttle.shuttles[mothershuttle] + if(mothership) + if(current_location.landmark_tag == motherdock) + mothership.shuttle_area |= shuttle_area + else + mothership.shuttle_area -= shuttle_area + +// Remove all powernets and pipenets that were affected, and rebuild them. +/datum/shuttle/proc/handle_pipes_and_power_on_move(var/list/new_turfs) + var/list/powernets = list() var/list/cables = list() + var/list/pipes = list() + + for(var/turf/T in new_turfs) + for(var/obj/structure/cable/cable in T) + powernets |= cable.powernet + for(var/obj/machinery/atmospherics/pipe in T) + pipes |= pipe + if(LAZYLEN(pipe.nodes_to_networks)) + pipes |= pipe.nodes_to_networks // This gets all pipes that used to be adjacent to us + for(var/direction in global.cardinal) // We do this so that if a shuttle lands in a way that should imply a new pipe/power connection, that actually happens + var/turf/neighbor = get_step(T, direction) + if(neighbor) + for(var/obj/structure/cable/cable in neighbor) + powernets |= cable.powernet + for(var/obj/machinery/atmospherics/pipe in neighbor) + pipes |= pipe + for(var/datum/powernet/P in powernets) cables |= P.cables qdel(P) @@ -253,14 +316,51 @@ var/datum/powernet/NewPN = new() NewPN.add_cable(C) propagate_network(C,C.powernet) + for(var/obj/machinery/atmospherics/pipe as anything in pipes) + pipe.atmos_init() // this will clear pipenet/pipeline + for(var/obj/machinery/atmospherics/pipe as anything in pipes) + pipe.build_network() + +/datum/shuttle/proc/create_ceiling(force) + if(!HasAbove(current_location.z)) + return + for(var/area/A in shuttle_area) + for(var/turf/TD in A.contents) + // Background turfs don't get a ceiling. + if(TD.turf_flags & TURF_FLAG_BACKGROUND) + continue + var/turf/TA = GetAbove(TD) + if(!TA) + continue + if(force || istype(TA, get_base_turf_by_area(TA)) || TA.is_open()) + if(get_area(TA) in shuttle_area) + continue + TA.ChangeTurf(ceiling_type, TRUE, TRUE, TRUE) + +/datum/shuttle/proc/create_translated_ceiling(force, list/turf_translation) + for(var/turf/TS in turf_translation) + var/turf/TD = turf_translation[TS] + + if(TS.turf_flags & TURF_FLAG_BACKGROUND) + continue + var/turf/TAD = GetAbove(TD) + var/turf/TAS = GetAbove(TS) + if(!istype(TAD)) + continue + + // Check for multi-z shuttles. Don't create a ceiling where the shuttle is about to be. + if((istype(TAS) && (get_area(TAS) in shuttle_area))) + continue - if(mothershuttle) - var/datum/shuttle/mothership = SSshuttle.shuttles[mothershuttle] - if(mothership) - if(current_location.landmark_tag == motherdock) - mothership.shuttle_area |= shuttle_area - else - mothership.shuttle_area -= shuttle_area + + if(force || (istype(TAD, get_base_turf_by_area(TAD)) || TAD.is_open())) + TAD.ChangeTurf(ceiling_type, TRUE, TRUE, TRUE) + + // TODO: Ideally the latter checks here would remain is_open() rather than direct type checks, but unfortunately we can't do that with only the path. + // In nearly all current situations, they are effectively the same thing. + else if(!TAD.prev_type || istype(TAD.prev_type, get_base_turf_by_area(TAD)) || ispath(TAD.prev_type, /turf/open) || ispath(TAD.prev_type, /turf/space)) + // In case there's a pending shuttle move above, prepare it to create a ceiling post-translation. + TAD.prev_type = ceiling_type //returns 1 if the shuttle has a valid arrive time /datum/shuttle/proc/has_arrive_time() @@ -282,9 +382,88 @@ /datum/shuttle/autodock/proc/get_location_name() if(moving_status == SHUTTLE_INTRANSIT) return "In transit" - return current_location.name + return "\the [current_location]" /datum/shuttle/autodock/proc/get_destination_name() if(!next_location) return "None" - return next_location.name \ No newline at end of file + return next_location.name + +// Testing +// Returns either null (all good) or a string explaining any issues. +/datum/shuttle/proc/test_landmark_setup() + if(!current_location) + if(initial(current_location)) + return "Starting location (tag: [initial(current_location)]) was not found." + else + return "Starting location was not set or forwarded properly." + if(!motherdock && initial(motherdock)) + return "The motherdock (tag: [initial(motherdock)]) was not found." + if(!mothershuttle && initial(mothershuttle)) + return "The mothershuttle (tag: [initial(mothershuttle)]) was not found." + +// Landing/docking ports +/datum/shuttle/proc/get_ports() + return docking_ports + +/datum/shuttle/proc/add_port(obj/abstract/local_dock/port) + if(!istype(port)) + return FALSE + LAZYADD(docking_ports, port) + return TRUE + +/datum/shuttle/proc/get_port_choices() + var/list/res = list() + var/list/ports = get_ports() + for(var/obj/abstract/local_dock/port in ports) + res[port.name] = port + res["none"] = null + return res + +/datum/shuttle/proc/get_current_port() + if(!current_port_tag) + return null + var/obj/abstract/local_dock/current_port = get_port_by_tag(current_port_tag) + return current_port + +/datum/shuttle/proc/get_center_of_rotation() + return get_current_port() || current_location + +/datum/shuttle/proc/set_port(port) + if(isnull(port)) // short-circuit special case for null port + current_port_tag = null + return TRUE + var/obj/abstract/local_dock/dock + if(istype(port, /obj/abstract/local_dock)) // We need to check availability. + dock = port + else + dock = get_port_by_tag(port) + if(dock && (dock.port_tag != current_port_tag)) + current_port_tag = dock.port_tag + return TRUE + return FALSE // port did not exist or was already selected + +/datum/shuttle/proc/get_port_by_tag(port_tag) + for(var/obj/abstract/local_dock/port in get_ports()) + if(port.port_tag == port_tag) + return port + return null + +/datum/shuttle/proc/get_port_name() + var/obj/abstract/local_dock/current_port = get_port_by_tag(current_port_tag) + return current_port?.name || "none" + +/datum/shuttle/proc/get_angle_offset(obj/rotation_center, obj/effect/shuttle_landmark/destination) + if(istype(rotation_center, /obj/effect/shuttle_landmark)) + var/obj/effect/shuttle_landmark/center_landmark = rotation_center + return center_landmark.get_angle_offset(destination) + // Fallback case for a docking port. + var/obj/abstract/local_dock/center_dock = rotation_center + if(istype(center_dock) && center_dock.reorient) + return dir2angle(destination.dir) - dir2angle(rotation_center.dir) + return 0 // do not rotate + +/datum/shuttle/proc/message_passengers(audible_message, visible_message) + for(var/mob/hearer in global.living_mob_list_ + global.ghost_mob_list) + if(is_type_in_list(get_area(hearer), shuttle_area)) + hearer.show_message(audible_message, AUDIBLE_MESSAGE, visible_message, VISIBLE_MESSAGE) diff --git a/code/modules/shuttles/shuttle_autodock.dm b/code/modules/shuttles/shuttle_autodock.dm index f711ccab2c69..5d56b4285d46 100644 --- a/code/modules/shuttles/shuttle_autodock.dm +++ b/code/modules/shuttles/shuttle_autodock.dm @@ -6,6 +6,7 @@ var/current_dock_target //ID of the controller on the shuttle var/dock_target = null + var/docking_cues = null // A list of string cues -> controller tags, if we have multiple controllers. On landmarks set special_dock_target = list(our type -> docking cue) to determine which dock is used. var/datum/computer/file/embedded_program/docking/shuttle_docking_controller var/docking_codes @@ -15,19 +16,24 @@ var/obj/effect/shuttle_landmark/landmark_transition //This variable is type-abused initially: specify the landmark_tag, not the actual landmark. var/move_time = 240 //the time spent in the transition area - category = /datum/shuttle/autodock + abstract_type = /datum/shuttle/autodock flags = SHUTTLE_FLAGS_PROCESS | SHUTTLE_FLAGS_ZERO_G -/datum/shuttle/autodock/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint) - ..(_name, start_waypoint) +/datum/shuttle/autodock/New(var/map_hash, var/obj/effect/shuttle_landmark/start_waypoint) + ..() + if(map_hash) + ADJUST_TAG_VAR(landmark_transition, map_hash) + ADJUST_TAG_VAR(dock_target, map_hash) + for(var/cue in docking_cues) + ADJUST_TAG_VAR(docking_cues[cue], map_hash) //Initial dock active_docking_controller = current_location.docking_controller update_docking_target(current_location) if(active_docking_controller) set_docking_codes(active_docking_controller.docking_codes) - else if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/location = map_sectors["[current_location.z]"] + else if(current_location?.overmap_id) + var/obj/effect/overmap/visitable/location = global.overmap_sectors[current_location.z] if(location && location.docking_codes) set_docking_codes(location.docking_codes) dock() @@ -48,21 +54,31 @@ if(shuttle_docking_controller) shuttle_docking_controller.docking_codes = code -/datum/shuttle/autodock/shuttle_moved() +/datum/shuttle/autodock/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) force_undock() //bye! ..() +/datum/shuttle/autodock/proc/get_dock_target_by_port_tag(var/port_tag) + var/obj/abstract/local_dock/dock = get_port_by_tag(port_tag) + if(!dock) + return dock_target // fallback, this should never happen + return dock.dock_target // do not fall back to default here; allow certain rotation points (center, etc) to disable docking + /datum/shuttle/autodock/proc/update_docking_target(var/obj/effect/shuttle_landmark/location) - if(location && location.special_dock_targets && location.special_dock_targets[name]) - current_dock_target = location.special_dock_targets[name] + if(location && docking_cues && location.special_dock_targets && location.special_dock_targets[type]) + current_dock_target = docking_cues[location.special_dock_targets[type]] + else if(current_port_tag) + current_dock_target = get_dock_target_by_port_tag(current_port_tag) else - current_dock_target = dock_target + current_dock_target = dock_target // fallback shuttle_docking_controller = SSshuttle.docking_registry[current_dock_target] /* Docking stuff */ /datum/shuttle/autodock/proc/dock() if(active_docking_controller && shuttle_docking_controller) + if(flags & SHUTTLE_FLAGS_NO_CODE) + set_docking_codes(active_docking_controller.docking_codes) shuttle_docking_controller.initiate_docking(active_docking_controller.id_tag) last_dock_attempt_time = world.time @@ -186,4 +202,11 @@ return //do nothing for now /obj/effect/shuttle_landmark/transit - flags = SLANDMARK_FLAG_ZERO_G \ No newline at end of file + flags = SLANDMARK_FLAG_ZERO_G + +/datum/shuttle/autodock/test_landmark_setup() + . = ..() + if(.) + return + if(!landmark_transition && initial(landmark_transition)) + return "A transition landmark was expected (tag: [initial(landmark_transition)]) but not found." \ No newline at end of file diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm index bf454e4870ba..774c5d4bdf09 100644 --- a/code/modules/shuttles/shuttle_console.dm +++ b/code/modules/shuttles/shuttle_console.dm @@ -10,6 +10,9 @@ var/ui_template = "shuttle_control_console.tmpl" +/obj/machinery/computer/shuttle_control/modify_mapped_vars(map_hash) + ..() + ADJUST_TAG_VAR(shuttle_tag, map_hash) /obj/machinery/computer/shuttle_control/interface_interact(mob/user) ui_interact(user) @@ -31,10 +34,10 @@ else if(cannot_depart) shuttle_status = cannot_depart else - shuttle_status = "Standing-by at \the [shuttle.get_location_name()]." + shuttle_status = "Standing-by at [shuttle.get_location_name()]." if(WAIT_LAUNCH, FORCE_LAUNCH) - shuttle_status = "Shuttle has recieved command and will depart shortly." + shuttle_status = "Shuttle has received command and will depart shortly." if(WAIT_ARRIVE) shuttle_status = "Proceeding to \the [shuttle.get_destination_name()]." if(WAIT_FINISH) @@ -49,6 +52,7 @@ "can_launch" = shuttle.can_launch(), "can_cancel" = shuttle.can_cancel(), "can_force" = shuttle.can_force(), + "timeleft" = max(round((shuttle.arrive_time - world.time) / 10, 1), 0), "docking_codes" = shuttle.docking_codes ) @@ -85,7 +89,7 @@ if(href_list["set_codes"]) var/newcode = input("Input new docking codes", "Docking codes", shuttle.docking_codes) as text|null - if (newcode && CanInteract(usr, GLOB.default_state)) + if (newcode && CanInteract(user, global.default_topic_state)) shuttle.set_docking_codes(uppertext(newcode)) return TOPIC_REFRESH @@ -99,7 +103,7 @@ ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) - ui = new(user, src, ui_key, ui_template, "[shuttle_tag] Shuttle Control", 470, 450) + ui = new(user, src, ui_key, ui_template, "[shuttle.display_name] Shuttle Control", 470, 450) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -113,13 +117,3 @@ hacked = 1 to_chat(user, "You short out the console's ID checking system. It's now available to everyone!") return 1 - -/obj/machinery/computer/shuttle_control/bullet_act(var/obj/item/projectile/Proj) - visible_message("\The [Proj] ricochets off \the [src]!") - -/obj/machinery/computer/shuttle_control/explosion_act() - SHOULD_CALL_PARENT(FALSE) - return - -/obj/machinery/computer/shuttle_control/emp_act() - return diff --git a/code/modules/shuttles/shuttle_console_multi.dm b/code/modules/shuttles/shuttle_console_multi.dm index e6033a8d7d16..28f8805a36d4 100644 --- a/code/modules/shuttles/shuttle_console_multi.dm +++ b/code/modules/shuttles/shuttle_console_multi.dm @@ -9,14 +9,14 @@ "can_pick" = shuttle.moving_status == SHUTTLE_IDLE, ) -/obj/machinery/computer/shuttle_control/multi/handle_topic_href(var/datum/shuttle/autodock/multi/shuttle, var/list/href_list) +/obj/machinery/computer/shuttle_control/multi/handle_topic_href(var/datum/shuttle/autodock/multi/shuttle, var/list/href_list, var/user) if((. = ..()) != null) return if(href_list["pick"]) var/dest_key = input("Choose shuttle destination", "Shuttle Destination") as null|anything in shuttle.get_destinations() - if(dest_key && CanInteract(usr, GLOB.default_state)) - shuttle.set_destination(dest_key, usr) + if(dest_key && CanInteract(user, global.default_topic_state)) + shuttle.set_destination(dest_key, user) return TOPIC_REFRESH diff --git a/code/modules/shuttles/shuttle_created.dm b/code/modules/shuttles/shuttle_created.dm new file mode 100644 index 000000000000..761fa0a8bc89 --- /dev/null +++ b/code/modules/shuttles/shuttle_created.dm @@ -0,0 +1,11 @@ +/datum/shuttle/autodock/overmap/created + defer_initialisation = TRUE + +/datum/shuttle/autodock/overmap/created/New(map_hash, obj/effect/shuttle_landmark/initial_location, list/initial_areas, tag) + if(!tag) + CRASH("Shuttle was created without a shuttle tag!") + name = tag + if(!length(initial_areas)) + CRASH("Shuttle was created without initial areas!") + shuttle_area = initial_areas + . = ..() \ No newline at end of file diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm index 955df274c1e4..b389d0749324 100644 --- a/code/modules/shuttles/shuttle_emergency.dm +++ b/code/modules/shuttles/shuttle_emergency.dm @@ -1,9 +1,11 @@ /datum/shuttle/autodock/ferry/emergency - category = /datum/shuttle/autodock/ferry/emergency + abstract_type = /datum/shuttle/autodock/ferry/emergency move_time = 10 MINUTES + flags = SHUTTLE_FLAGS_PROCESS | SHUTTLE_FLAGS_ZERO_G | SHUTTLE_FLAGS_NO_CODE var/datum/evacuation_controller/shuttle/emergency_controller + var/departed -/datum/shuttle/autodock/ferry/emergency/New() +/datum/shuttle/autodock/ferry/emergency/New(map_hash) . = ..() emergency_controller = SSevac.evacuation_controller if(!istype(emergency_controller)) @@ -25,13 +27,20 @@ /datum/shuttle/autodock/ferry/emergency/long_jump(var/destination, var/interim, var/travel_time, var/direction) ..(destination, interim, emergency_controller.get_long_jump_time(), direction) -/datum/shuttle/autodock/ferry/emergency/shuttle_moved() +/datum/shuttle/autodock/ferry/emergency/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) if(next_location != waypoint_station) - emergency_controller.shuttle_leaving() // This is a hell of a line. v - priority_announcement.Announce(replacetext(replacetext((emergency_controller.emergency_evacuation ? GLOB.using_map.emergency_shuttle_leaving_dock : GLOB.using_map.shuttle_leaving_dock), "%dock_name%", "[GLOB.using_map.dock_name]"), "%ETA%", "[round(emergency_controller.get_eta()/60,1)] minute\s")) - else if(next_location == waypoint_offsite && emergency_controller.has_evacuated()) - emergency_controller.shuttle_evacuated() + var/msg + if(departed) + msg = emergency_controller.emergency_evacuation ? global.using_map.emergency_shuttle_arriving_at_dock_message : global.using_map.shuttle_arriving_at_dock_message + else + msg = emergency_controller.emergency_evacuation ? global.using_map.emergency_shuttle_leaving_dock : global.using_map.shuttle_leaving_dock + emergency_controller.shuttle_leaving() + departed = TRUE + if(msg) + priority_announcement.Announce(replacetext(replacetext(msg, "%dock_name%", "[global.using_map.dock_name]"), "%ETA%", "[round(emergency_controller.get_eta()/60,1)] minute\s")) ..() + if(current_location == waypoint_offsite && emergency_controller.has_evacuated()) + emergency_controller.shuttle_evacuated() /datum/shuttle/autodock/ferry/emergency/can_launch(var/user) if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) @@ -106,13 +115,18 @@ var/debug = 0 var/req_authorizations = 2 var/list/authorized = list() + var/list/original_authorization + +/obj/machinery/computer/shuttle_control/emergency/Initialize() + . = ..() + original_authorization = authorized?.Copy() /obj/machinery/computer/shuttle_control/emergency/proc/has_authorization() return (authorized.len >= req_authorizations || emagged) /obj/machinery/computer/shuttle_control/emergency/proc/reset_authorization() //no need to reset emagged status. If they really want to go back to the station they can. - authorized = initial(authorized) + authorized = original_authorization?.Copy() //returns 1 if the ID was accepted and a new authorization was added, 0 otherwise /obj/machinery/computer/shuttle_control/emergency/proc/read_authorization(var/obj/item/ident) @@ -121,8 +135,8 @@ if (authorized.len >= req_authorizations) return 0 //don't need any more - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - if (!SSevac.evacuation_controller.emergency_evacuation && security_state.current_security_level_is_lower_than(security_state.high_security_level)) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if((!SSevac.evacuation_controller || !SSevac.evacuation_controller.emergency_evacuation) && security_state.current_security_level_is_lower_than(security_state.high_security_level)) src.visible_message("\The [src] buzzes. It does not appear to be accepting any commands.") return 0 @@ -166,9 +180,10 @@ emagged = 1 return 1 -/obj/machinery/computer/shuttle_control/emergency/attackby(obj/item/W, mob/user) - read_authorization(W) - ..() +/obj/machinery/computer/shuttle_control/emergency/attackby(obj/item/used_item, mob/user) + if(read_authorization(used_item)) + return TRUE + return ..() /obj/machinery/computer/shuttle_control/emergency/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/data[0] @@ -188,11 +203,11 @@ if (shuttle.in_use) shuttle_status = "Busy." else if (!shuttle.location) - shuttle_status = "Standing-by at [GLOB.using_map.station_name]." + shuttle_status = "Standing-by at [global.using_map.station_name]." else - shuttle_status = "Standing-by at [GLOB.using_map.dock_name]." + shuttle_status = "Standing-by at [global.using_map.dock_name]." if(WAIT_LAUNCH, FORCE_LAUNCH) - shuttle_status = "Shuttle has recieved command and will depart shortly." + shuttle_status = "Shuttle has received command and will depart shortly." if(WAIT_ARRIVE) shuttle_status = "Proceeding to destination." if(WAIT_FINISH) @@ -244,8 +259,8 @@ else if(!emagged && href_list["scanid"]) //They selected an empty entry. Try to scan their id. - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user if (istype(H)) - if (!read_authorization(H.get_active_hand())) //try to read what's in their hand first - read_authorization(H.wear_id) + if (!read_authorization(H.get_active_held_item())) //try to read what's in their hand first + read_authorization(H.get_equipped_item(slot_wear_id_str)) . = TOPIC_REFRESH diff --git a/code/modules/shuttles/shuttle_engines.dm b/code/modules/shuttles/shuttle_engines.dm index 29307ff431dd..86a407e28d95 100644 --- a/code/modules/shuttles/shuttle_engines.dm +++ b/code/modules/shuttles/shuttle_engines.dm @@ -1,23 +1,22 @@ /obj/structure/shuttle name = "shuttle" - icon = 'icons/turf/shuttle.dmi' + abstract_type = /obj/structure/shuttle + atmos_canpass = CANPASS_NEVER /obj/structure/shuttle/window name = "shuttle window" icon = 'icons/obj/structures/podwindows.dmi' icon_state = "1" - density = 1 - opacity = 0 - anchored = 1 - -/obj/structure/shuttle/window/CanPass(atom/movable/mover, turf/target, height, air_group) - if(!height || air_group) return 0 - else return ..() + density = TRUE + opacity = FALSE + anchored = TRUE /obj/structure/shuttle/engine name = "engine" - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE + icon = 'icons/obj/structures/shuttle_engine.dmi' + abstract_type = /obj/structure/shuttle/engine /obj/structure/shuttle/engine/heater name = "heater" @@ -31,7 +30,13 @@ /obj/structure/shuttle/engine/propulsion name = "propulsion" icon_state = "propulsion" - opacity = 1 + opacity = TRUE + +/obj/structure/shuttle/engine/propulsion/left + icon_state = "propulsion_l" + +/obj/structure/shuttle/engine/propulsion/right + icon_state = "propulsion_r" /obj/structure/shuttle/engine/propulsion/burst name = "burst" diff --git a/code/modules/shuttles/shuttle_ferry.dm b/code/modules/shuttles/shuttle_ferry.dm index 7ad125e5c9bf..020d8c670c9c 100644 --- a/code/modules/shuttles/shuttle_ferry.dm +++ b/code/modules/shuttles/shuttle_ferry.dm @@ -7,15 +7,19 @@ var/obj/effect/shuttle_landmark/waypoint_station //This variable is type-abused initially: specify the landmark_tag, not the actual landmark. var/obj/effect/shuttle_landmark/waypoint_offsite //This variable is type-abused initially: specify the landmark_tag, not the actual landmark. - category = /datum/shuttle/autodock/ferry + abstract_type = /datum/shuttle/autodock/ferry + +/datum/shuttle/autodock/ferry/New(map_hash) + if(map_hash) + ADJUST_TAG_VAR(waypoint_station, map_hash) + ADJUST_TAG_VAR(waypoint_offsite, map_hash) -/datum/shuttle/autodock/ferry/New(_name) if(waypoint_station) waypoint_station = SSshuttle.get_landmark(waypoint_station) if(waypoint_offsite) waypoint_offsite = SSshuttle.get_landmark(waypoint_offsite) - ..(_name, get_location_waypoint(location)) + ..(map_hash, get_location_waypoint(location)) next_location = get_location_waypoint(!location) @@ -36,7 +40,7 @@ direction = !location ..() -/datum/shuttle/autodock/ferry/shuttle_moved() +/datum/shuttle/autodock/ferry/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) ..() if (next_location == waypoint_station) location = 0 @@ -45,3 +49,18 @@ /datum/shuttle/autodock/ferry/process_arrived() ..() next_location = get_location_waypoint(!location) + +/datum/shuttle/autodock/ferry/test_landmark_setup() + . = ..() + if(.) + return + if(!waypoint_station) + if(initial(waypoint_station)) + return "The station waypoint landmark (tag: [initial(waypoint_station)]) was not found." + else + return "A station waypoint was not properly set." + if(!waypoint_offsite) + if(initial(waypoint_offsite)) + return "The offsite waypoint landmark (tag: [initial(waypoint_offsite)]) was not found." + else + return "An offsite waypoint was not properly set." \ No newline at end of file diff --git a/code/modules/shuttles/shuttle_log.dm b/code/modules/shuttles/shuttle_log.dm index 727e80f8fd58..b4cf0a2d7b57 100644 --- a/code/modules/shuttles/shuttle_log.dm +++ b/code/modules/shuttles/shuttle_log.dm @@ -6,7 +6,7 @@ var/list/datum/shuttle_mission/queued_missions = list() //Missions which are queued up, in order ([1] is the next one scheduled). var/datum/shuttle_mission/current_mission //The current mission, planned or ongoing. Will also be in either missions or queued_missions, depending on stage. var/home_base //The landmark tag from which missions originate. - var/list/datum/nano_module/registered = list() //Nanomodules using logs should register to recieve updates. + var/list/datum/nano_module/registered = list() //Nanomodules using logs should register to receive updates. var/last_spam = 0 //Helps with spam control from deck software. /datum/shuttle_log/New(datum/shuttle/given_shuttle) @@ -17,7 +17,7 @@ SSshuttle.shuttle_logs[given_shuttle] = src /datum/shuttle_log/Destroy() - update_registred() + update_registered() registered = null current_mission = null QDEL_NULL_LIST(missions) @@ -28,9 +28,9 @@ registered += module /datum/shuttle_log/proc/unregister(datum/nano_module/module) - registered -= module + registered -= module -/datum/shuttle_log/proc/update_registred() +/datum/shuttle_log/proc/update_registered() for(var/datum/nano_module/module in registered) SSnano.update_uis(module) @@ -49,7 +49,7 @@ qdel(old_report) new_report.mission.set_value(mission.name) mission.other_reports += report - update_registred() + update_registered() return 1 /datum/shuttle_log/proc/process_queue() @@ -64,7 +64,7 @@ if(!current_mission && length(queued_missions)) current_mission = queued_missions[1] current_mission.stage = SHUTTLE_MISSION_PLANNED - update_registred() + update_registered() /datum/shuttle_log/proc/create_mission(name) var/datum/shuttle_mission/mission = new() @@ -85,7 +85,7 @@ mission.name = name for(var/datum/computer_file/report/recipient/shuttle/report in mission.other_reports) report.mission.set_value(name) - update_registred() + update_registered() //Only missions that haven't started can be deleted; returns 0 on failure. /datum/shuttle_log/proc/delete_mission(datum/shuttle_mission/mission) @@ -106,7 +106,7 @@ current_mission.stage = SHUTTLE_MISSION_QUEUED current_mission = null //We'll reset this at the end. var/index = queued_missions.Find(mission) - var/new_index = Clamp(index - relative_position, 1, length(queued_missions)) + var/new_index = clamp(index - relative_position, 1, length(queued_missions)) queued_missions -= mission queued_missions.Insert(new_index, mission) process_queue() diff --git a/code/modules/shuttles/shuttle_specops.dm b/code/modules/shuttles/shuttle_specops.dm index ba915c3476ed..5ffe256bd8d1 100644 --- a/code/modules/shuttles/shuttle_specops.dm +++ b/code/modules/shuttles/shuttle_specops.dm @@ -11,21 +11,10 @@ var/specops_return_delay = 6000 //After moving, the amount of time that must pass before the shuttle may move again var/specops_countdown_time = 600 //Length of the countdown when moving the shuttle - var/obj/item/radio/intercom/announcer = null var/reset_time = 0 //the world.time at which the shuttle will be ready to move again. var/launch_prep = 0 var/cancel_countdown = 0 - category = /datum/shuttle/autodock/ferry/specops - -/datum/shuttle/autodock/ferry/specops/New() - ..() - announcer = new /obj/item/radio/intercom(null)//We need a fake AI to announce some stuff below. Otherwise it will be wonky. - announcer.config(list("Response Team" = 0)) - -/datum/shuttle/autodock/ferry/specops/proc/radio_announce(var/message) - if(announcer) - announcer.autosay(message, "A.L.I.C.E.", "Response Team") - + abstract_type = /datum/shuttle/autodock/ferry/specops /datum/shuttle/autodock/ferry/specops/launch(var/user) if (!can_launch()) @@ -35,7 +24,7 @@ var/obj/machinery/computer/C = user if(world.time <= reset_time) - C.visible_message("[GLOB.using_map.boss_name] will not allow the Special Operations shuttle to launch yet.") + C.visible_message("[global.using_map.boss_name] will not allow the Special Operations shuttle to launch yet.") if (((world.time - reset_time)/10) > 60) C.visible_message("[-((world.time - reset_time)/10)/60] minutes remain!") else @@ -45,9 +34,9 @@ C.visible_message("The Special Operations shuttle will depart in [(specops_countdown_time/10)] seconds.") if (location) //returning - radio_announce("THE SPECIAL OPERATIONS SHUTTLE IS PREPARING TO RETURN") + do_telecomms_announcement(current_location, "THE SPECIAL OPERATIONS SHUTTLE IS PREPARING TO RETURN", "A.L.I.C.E") else - radio_announce("THE SPECIAL OPERATIONS SHUTTLE IS PREPARING FOR LAUNCH") + do_telecomms_announcement(current_location, "THE SPECIAL OPERATIONS SHUTTLE IS PREPARING FOR LAUNCH", "A.L.I.C.E") sleep_until_launch() @@ -56,22 +45,24 @@ if(light) light.set_state(0) //launch - radio_announce("ALERT: INITIATING LAUNCH SEQUENCE") + do_telecomms_announcement(current_location, "ALERT: INITIATING LAUNCH SEQUENCE", "A.L.I.C.E") + + reset_time = world.time + specops_return_delay ..(user) -/datum/shuttle/autodock/ferry/specops/shuttle_moved() +/datum/shuttle/autodock/ferry/specops/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) ..() spawn(2 SECONDS) if (!location) //just arrived home for(var/turf/T in get_area_turfs(shuttle_area)) var/mob/M = locate(/mob) in T - to_chat(M, "You have arrived at [GLOB.using_map.boss_name]. Operation has ended!") + to_chat(M, "You have arrived at [global.using_map.boss_name]. Operation has ended!") else //just left for the station launch_mauraders() for(var/turf/T in get_area_turfs(shuttle_area)) var/mob/M = locate(/mob) in T - to_chat(M, "You have arrived at [GLOB.using_map.station_name]. Commence operation!") + to_chat(M, "You have arrived at [global.using_map.station_name]. Commence operation!") var/obj/machinery/light/small/readylight/light = locate() in T if(light) light.set_state(1) @@ -81,7 +72,7 @@ return cancel_countdown = 1 - radio_announce("ALERT: LAUNCH SEQUENCE ABORTED") + do_telecomms_announcement(current_location, "ALERT: LAUNCH SEQUENCE ABORTED", "A.L.I.C.E") if (istype(in_use, /obj/machinery/computer)) var/obj/machinery/computer/C = in_use C.visible_message("Launch sequence aborted.") @@ -104,7 +95,7 @@ return ..() /datum/shuttle/autodock/ferry/specops/proc/sleep_until_launch() - var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values. + var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a list with potential time values. var/launch_time = world.time + specops_countdown_time var/time_until_launch @@ -121,7 +112,7 @@ //All this does is announce the time before launch. var/rounded_time_left = round(time_until_launch)//Round time so that it will report only once, not in fractions. if(rounded_time_left in message_tracker)//If that time is in the list for message announce. - radio_announce("ALERT: [rounded_time_left] SECOND[(rounded_time_left!=1)?"S":""] REMAIN") + do_telecomms_announcement(current_location, "ALERT: [rounded_time_left] SECOND[(rounded_time_left!=1)?"S":""] REMAIN", "A.L.I.C.E") message_tracker -= rounded_time_left//Remove the number from the list so it won't be called again next cycle. //Should call all the numbers but lag could mean some issues. Oh well. Not much I can do about that. @@ -129,9 +120,12 @@ launch_prep = 0 - /proc/launch_mauraders() - var/area/centcom/specops/special_ops = locate()//Where is the specops area located? + var/specops_area = global.using_map.get_specops_area() + if(!specops_area) + return + + var/area/special_ops = locate(specops_area)//Where is the specops area located? //Begin Marauder launchpad. spawn(0)//So it parallel processes it. for(var/obj/machinery/door/blast/M in special_ops) @@ -152,13 +146,13 @@ sleep(10) var/spawn_marauder[] = new() - for(var/obj/effect/landmark/L in world) + for(var/obj/abstract/landmark/L in global.all_landmarks) if(L.name == "Marauder Entry") spawn_marauder.Add(L) - for(var/obj/effect/landmark/L in world) + for(var/obj/abstract/landmark/L in global.all_landmarks) if(L.name == "Marauder Exit") var/obj/effect/portal/P = new(L.loc) - P.set_invisibility(101)//So it is not seen by anyone. + P.set_invisibility(INVISIBILITY_ABSTRACT)//So it is not seen by anyone. P.failchance = 0//So it has no fail chance when teleporting. P.target = pick(spawn_marauder)//Where the marauder will arrive. spawn_marauder.Remove(P.target) diff --git a/code/modules/shuttles/shuttle_supply.dm b/code/modules/shuttles/shuttle_supply.dm index 2c3ad35cd193..f38e5fef5b31 100644 --- a/code/modules/shuttles/shuttle_supply.dm +++ b/code/modules/shuttles/shuttle_supply.dm @@ -2,9 +2,9 @@ var/away_location = 1 //the location to hide at while pretending to be in-transit var/late_chance = 80 var/max_late_time = (30 SECONDS) - flags = SHUTTLE_FLAGS_PROCESS|SHUTTLE_FLAGS_SUPPLY - category = /datum/shuttle/autodock/ferry/supply - ceiling_type = /turf/simulated/floor/shuttle_ceiling + flags = SHUTTLE_FLAGS_PROCESS|SHUTTLE_FLAGS_SUPPLY|SHUTTLE_FLAGS_NO_CODE + abstract_type = /datum/shuttle/autodock/ferry/supply + ceiling_type = /turf/floor/shuttle_ceiling /datum/shuttle/autodock/ferry/supply/short_jump(var/area/destination) if(moving_status != SHUTTLE_IDLE) @@ -64,15 +64,6 @@ /datum/shuttle/autodock/ferry/supply/proc/at_station() return (!location) -//returns 1 if the shuttle is idle and we can still mess with the cargo shopping list -/datum/shuttle/autodock/ferry/supply/proc/idle() - return (moving_status == SHUTTLE_IDLE) - -//returns the ETA in minutes -/datum/shuttle/autodock/ferry/supply/proc/eta_minutes() - var/ticksleft = arrive_time - world.time - return max(0, round(ticksleft/600,1)) - -/datum/shuttle/autodock/ferry/supply/proc/eta_seconds() - var/ticksleft = arrive_time - world.time - return max(0, round(ticksleft/10,1)) +//returns the ETA as a natural language timestamp +/datum/shuttle/autodock/ferry/supply/proc/eta_readable() + return ticks2readable(max(0, arrive_time - world.time)) diff --git a/code/modules/shuttles/shuttles_multi.dm b/code/modules/shuttles/shuttles_multi.dm index 5c3e0bbded8e..71e144e02e27 100644 --- a/code/modules/shuttles/shuttles_multi.dm +++ b/code/modules/shuttles/shuttles_multi.dm @@ -2,7 +2,16 @@ var/list/destination_tags var/list/destinations_cache = list() var/last_cache_rebuild_time = 0 - category = /datum/shuttle/autodock/multi + abstract_type = /datum/shuttle/autodock/multi + +/datum/shuttle/autodock/multi/New(map_hash) + ..() + if(map_hash) + var/new_tags = list() + for(var/thing in destination_tags) + ADJUST_TAG_VAR(thing, map_hash) + new_tags += map_hash + destination_tags = new_tags /datum/shuttle/autodock/multi/proc/set_destination(var/destination_key, mob/user) if(moving_status != SHUTTLE_IDLE) @@ -33,16 +42,18 @@ var/arrival_message var/departure_message - category = /datum/shuttle/autodock/multi/antag + abstract_type = /datum/shuttle/autodock/multi/antag -/datum/shuttle/autodock/multi/antag/New() +/datum/shuttle/autodock/multi/antag/New(map_hash) ..() if(home_waypoint) + if(map_hash) + ADJUST_TAG_VAR(home_waypoint, map_hash) home_waypoint = SSshuttle.get_landmark(home_waypoint) else home_waypoint = current_location -/datum/shuttle/autodock/multi/antag/shuttle_moved() +/datum/shuttle/autodock/multi/antag/shuttle_moved(obj/effect/shuttle_landmark/destination, list/turf_translation, angle = 0) if(current_location == home_waypoint) announce_arrival() else if(next_location == home_waypoint) @@ -52,9 +63,17 @@ /datum/shuttle/autodock/multi/antag/proc/announce_departure() if(cloaked || isnull(departure_message)) return - command_announcement.Announce(departure_message, announcer || "[GLOB.using_map.boss_name]") + command_announcement.Announce(departure_message, announcer || "[global.using_map.boss_name]") /datum/shuttle/autodock/multi/antag/proc/announce_arrival() if(cloaked || isnull(arrival_message)) return - command_announcement.Announce(arrival_message, announcer || "[GLOB.using_map.boss_name]") + command_announcement.Announce(arrival_message, announcer || "[global.using_map.boss_name]") + +/datum/shuttle/autodock/multi/test_landmark_setup() + . = ..() + if(.) + return + for(var/dest_tag in destination_tags) + if(!SSshuttle.get_landmark(dest_tag)) + return "Could not locate at least one destination landmark (with tag [dest_tag])." \ No newline at end of file diff --git a/code/modules/species/outsider/random.dm b/code/modules/species/outsider/random.dm deleted file mode 100644 index 989e92a0e964..000000000000 --- a/code/modules/species/outsider/random.dm +++ /dev/null @@ -1,152 +0,0 @@ -/datum/species/alium - name = SPECIES_ALIEN - name_plural = "Humanoids" - description = "Some alien humanoid species, unknown to humanity. How exciting." - rarity_value = 5 - bodytype = BODYTYPE_HUMANOID - - species_flags = SPECIES_FLAG_NO_SCAN - spawn_flags = SPECIES_IS_RESTRICTED - - icobase = 'icons/mob/human_races/species/humanoid/body.dmi' - deform = 'icons/mob/human_races/species/humanoid/body.dmi' - bandages_icon = 'icons/mob/bandage.dmi' - appearance_flags = HAS_SKIN_COLOR - limb_blend = ICON_MULTIPLY - - force_cultural_info = list( - TAG_CULTURE = CULTURE_ALIUM - ) - -/datum/species/alium/New() - //Coloring - blood_color = RANDOM_RGB - flesh_color = RANDOM_RGB - base_color = RANDOM_RGB - - //Combat stats - MULT_BY_RANDOM_COEF(total_health, 0.8, 1.2) - MULT_BY_RANDOM_COEF(brute_mod, 0.5, 1.5) - MULT_BY_RANDOM_COEF(burn_mod, 0.8, 1.2) - MULT_BY_RANDOM_COEF(oxy_mod, 0.5, 1.5) - MULT_BY_RANDOM_COEF(toxins_mod, 0, 2) - MULT_BY_RANDOM_COEF(radiation_mod, 0, 2) - MULT_BY_RANDOM_COEF(flash_mod, 0.5, 1.5) - - if(brute_mod < 1 && prob(40)) - species_flags |= SPECIES_FLAG_NO_MINOR_CUT - if(brute_mod < 0.9 && prob(40)) - species_flags |= SPECIES_FLAG_NO_EMBED - if(toxins_mod < 0.1) - species_flags |= SPECIES_FLAG_NO_POISON - - //Gastronomic traits - taste_sensitivity = pick(TASTE_HYPERSENSITIVE, TASTE_SENSITIVE, TASTE_DULL, TASTE_NUMB) - gluttonous = pick(0, GLUT_TINY, GLUT_SMALLER, GLUT_ANYTHING) - stomach_capacity = 5 * stomach_capacity - if(prob(20)) - gluttonous |= pick(GLUT_ITEM_TINY, GLUT_ITEM_NORMAL, GLUT_ITEM_ANYTHING, GLUT_PROJECTILE_VOMIT) - if(gluttonous & GLUT_ITEM_ANYTHING) - stomach_capacity += ITEM_SIZE_HUGE - - //Environment - var/temp_comfort_shift = rand(-50,50) - cold_level_1 += temp_comfort_shift - cold_level_2 += temp_comfort_shift - cold_level_3 += temp_comfort_shift - - heat_level_1 += temp_comfort_shift - heat_level_2 += temp_comfort_shift - heat_level_3 += temp_comfort_shift - - heat_discomfort_level += temp_comfort_shift - cold_discomfort_level += temp_comfort_shift - - body_temperature += temp_comfort_shift - - var/pressure_comfort_shift = rand(-50,50) - hazard_high_pressure += pressure_comfort_shift - warning_high_pressure += pressure_comfort_shift - warning_low_pressure += pressure_comfort_shift - hazard_low_pressure += pressure_comfort_shift - - //Misc traits - darksight_range = rand(1,8) - darksight_tint = pick(DARKTINT_NONE,DARKTINT_MODERATE,DARKTINT_GOOD) - if(prob(40)) - genders = list(PLURAL) - if(prob(10)) - slowdown += pick(-1,1) - if(prob(10)) - species_flags |= SPECIES_FLAG_NO_SLIP - if(prob(10)) - species_flags |= SPECIES_FLAG_NO_TANGLE - if(prob(5)) - species_flags |= SPECIES_FLAG_NO_PAIN - - ..() - -/datum/species/alium/proc/adapt_to_atmosphere(var/datum/gas_mixture/atmosphere) - var/temp_comfort_shift = atmosphere.temperature - body_temperature - - cold_level_1 += temp_comfort_shift - cold_level_2 += temp_comfort_shift - cold_level_3 += temp_comfort_shift - - heat_level_1 += temp_comfort_shift - heat_level_2 += temp_comfort_shift - heat_level_3 += temp_comfort_shift - - heat_discomfort_level += temp_comfort_shift - cold_discomfort_level += temp_comfort_shift - - body_temperature += temp_comfort_shift - - var/normal_pressure = atmosphere.return_pressure() - hazard_high_pressure = 5 * normal_pressure - warning_high_pressure = 0.7 * hazard_high_pressure - - hazard_low_pressure = 0.2 * normal_pressure - warning_low_pressure = 2.5 * hazard_low_pressure - - breath_type = pick(atmosphere.gas) - breath_pressure = 0.8*(atmosphere.gas[breath_type]/atmosphere.total_moles)*normal_pressure - - var/list/newgases = subtypesof(/decl/material/gas) - newgases = newgases.Copy() - newgases ^= atmosphere.gas - for(var/gas in newgases) - var/decl/material/mat = decls_repository.get_decl(gas) - if(mat.gas_flags & (XGM_GAS_OXIDIZER|XGM_GAS_FUEL)) - newgases -= gas - if(newgases.len) - poison_types = list(pick_n_take(newgases)) - if(newgases.len) - exhale_type = pick_n_take(newgases) - -/obj/structure/aliumizer - name = "alien monolith" - desc = "Your true form is calling. Use this to become an alien humanoid." - icon = 'icons/obj/xenoarchaeology.dmi' - icon_state = "ano51" - anchored = 1 - -/obj/structure/aliumizer/attack_hand(mob/living/carbon/human/user) - if(!istype(user)) - to_chat(user, "You got no business touching this.") - return - if(user.species.name == SPECIES_ALIEN) - to_chat(user, "You're already a [SPECIES_ALIEN].") - return - if(alert("Are you sure you want to be an alien?", "Mom Look I'm An Alien!", "Yes", "No") == "No") - to_chat(user, "Okie dokie.") - return - if(user && user.species.name == SPECIES_ALIEN) //no spamming it to get free implants - return - to_chat(user, "You're now an alien humanoid of some undiscovered species. Make up what lore you want, no one knows a thing about your species! You can check info about your traits with Check Species Info verb in IC tab.") - to_chat(user, "You can't speak GalCom or any other languages by default. You can use translator implant that spawns on top of this monolith - it will give you knowledge of any language if you hear it enough times.") - new/obj/item/implanter/translator(get_turf(src)) - user.set_species(SPECIES_ALIEN) - var/decl/cultural_info/culture = user.get_cultural_value(TAG_CULTURE) - user.fully_replace_character_name(culture.get_random_name(user.gender)) - user.rename_self("Humanoid Alien", 1) \ No newline at end of file diff --git a/code/modules/species/outsider/shadow.dm b/code/modules/species/outsider/shadow.dm deleted file mode 100644 index c3b68707821b..000000000000 --- a/code/modules/species/outsider/shadow.dm +++ /dev/null @@ -1,35 +0,0 @@ -/datum/species/starlight/shadow - name = "Shadow" - name_plural = "shadows" - description = "A being of pure darkness, hates the light and all that comes with it." - icobase = 'icons/mob/human_races/species/shadow/body.dmi' - deform = 'icons/mob/human_races/species/shadow/body.dmi' - - meat_type = null - bone_material = null - skin_material = null - - unarmed_attacks = list(/decl/natural_attack/claws/strong, /decl/natural_attack/bite/sharp) - darksight_range = 8 - darksight_tint = DARKTINT_GOOD - siemens_coefficient = 0 - - blood_color = COLOR_GRAY80 - flesh_color = "#aaaaaa" - - remains_type = /obj/effect/decal/cleanable/ash - death_message = "dissolves into ash..." - - species_flags = SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED - -/datum/species/starlight/shadow/handle_environment_special(var/mob/living/carbon/human/H) - if(H.InStasis() || H.stat == DEAD || H.isSynthetic()) - return - var/light_amount = 0 - if(isturf(H.loc)) - var/turf/T = H.loc - light_amount = T.get_lumcount() * 10 - if(light_amount > 2) //if there's enough light, start dying - H.take_overall_damage(1,1) - else //heal in the dark - H.heal_overall_damage(1,1) \ No newline at end of file diff --git a/code/modules/species/outsider/starlight.dm b/code/modules/species/outsider/starlight.dm deleted file mode 100644 index 9b9f89ada4a0..000000000000 --- a/code/modules/species/outsider/starlight.dm +++ /dev/null @@ -1,117 +0,0 @@ -/datum/species/starlight - name = "Starlight Base" - - meat_type = null - bone_material = null - skin_material = null - - has_limbs = list( - BP_CHEST = list("path" = /obj/item/organ/external/chest/unbreakable), - BP_GROIN = list("path" = /obj/item/organ/external/groin/unbreakable), - BP_HEAD = list("path" = /obj/item/organ/external/head/unbreakable), - BP_L_ARM = list("path" = /obj/item/organ/external/arm/unbreakable), - BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/unbreakable), - BP_L_LEG = list("path" = /obj/item/organ/external/leg/unbreakable), - BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/unbreakable), - BP_L_HAND = list("path" = /obj/item/organ/external/hand/unbreakable), - BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/unbreakable), - BP_L_FOOT = list("path" = /obj/item/organ/external/foot/unbreakable), - BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/unbreakable) - ) - has_organ = list( - BP_BRAIN = /obj/item/organ/internal/brain/starlight - ) - spawn_flags = SPECIES_IS_RESTRICTED - genders = list(NEUTER) - force_cultural_info = list( - TAG_CULTURE = CULTURE_STARLIGHT - ) - -/datum/species/starlight/handle_death_check(var/mob/living/carbon/human/H) - if(H.health == 0) - return TRUE - return FALSE - -/datum/species/starlight/handle_death(var/mob/living/carbon/human/H) - addtimer(CALLBACK(H,/mob/proc/dust),0) - -/datum/species/starlight/starborn - name = "Starborn" - name_plural = "Starborn" - icobase = 'icons/mob/human_races/species/starborn/body.dmi' - deform = 'icons/mob/human_races/species/starborn/body.dmi' - husk_icon = 'icons/mob/human_races/species/starborn/husk.dmi' - description = "Beings of fire and light, split off from a sun deity of unbelievable power." - - blood_color = "#ffff00" - flesh_color = "#ffff00" - - unarmed_attacks = list(/decl/natural_attack/punch/starborn) - - cold_discomfort_level = 300 - cold_discomfort_strings = list("You feel your fire dying out...", - "Your fire begins to shrink away from the cold.", - "You feel slow and sluggish from the cold." - ) - cold_level_1 = 260 - cold_level_2 = 250 - cold_level_3 = 235 - - heat_discomfort_level = 10000 - heat_discomfort_strings = list("Surprisingly, you start burning!", - "You're... burning!?!") - heat_level_1 = 20000 - heat_level_2 = 30000 - heat_level_3 = 40000 - - warning_low_pressure = 50 - hazard_low_pressure = 0 - siemens_coefficient = 0 - hunger_factor = 0 - death_message = "dissolves into pure flames!" - breath_type = null - - - total_health = 250 - body_temperature = T0C + 500 //We are being of fire and light. - species_flags = SPECIES_FLAG_NO_MINOR_CUT | SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED | SPECIES_FLAG_NO_TANGLE | SPECIES_FLAG_NO_PAIN - - base_auras = list( - /obj/aura/starborn - ) - -/datum/species/starlight/starborn/handle_death(var/mob/living/carbon/human/H) - ..() - var/turf/T = get_turf(H) - var/obj/effect/fluid/F = locate() in T - if(!F) F = new(T) - F.reagents.add_reagent(/decl/material/liquid/fuel, 20) - T.hotspot_expose(FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE) - -/datum/species/starlight/blueforged - name = "Blueforged" - name_plural = "Blueforged" - icobase = 'icons/mob/human_races/species/blueforged/body.dmi' - deform = 'icons/mob/human_races/species/blueforged/body.dmi' - description = "Living chunks of spacetime, carved out of the original dimension and given life by a being of unbelievable power." - - blood_color = "#2222ff" - flesh_color = "#2222ff" - - warning_low_pressure = 50 - hazard_low_pressure = 0 - hunger_factor = 0 - breath_type = null - - burn_mod = 10 - brute_mod = 0 - oxy_mod = 0 - toxins_mod = 0 - radiation_mod = 0 - species_flags = SPECIES_FLAG_NO_MINOR_CUT | SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_EMBED | SPECIES_FLAG_NO_TANGLE - - override_organ_types = list(BP_EYES = /obj/item/organ/internal/eyes/blueforged) - -/datum/species/starlight/blueforged/handle_death(var/mob/living/carbon/human/H) - ..() - new /obj/effect/temporary(get_turf(H),11, 'icons/mob/mob.dmi', "liquify") \ No newline at end of file diff --git a/code/modules/species/species.dm b/code/modules/species/species.dm index 95e1615f4324..394c6abd75b3 100644 --- a/code/modules/species/species.dm +++ b/code/modules/species/species.dm @@ -1,62 +1,66 @@ /* Datum-based species. Should make for much cleaner and easier to maintain race code. */ +var/global/const/DEFAULT_SPECIES_HEALTH = 200 -/datum/species +/decl/species + abstract_type = /decl/species + decl_flags = DECL_FLAG_MANDATORY_UID // Descriptors and strings. var/name - var/name_plural // Pluralized name (since "[name]s" is not always valid) + var/name_plural // Pluralized name (since "[name]s" is not always valid) var/description var/codex_description + var/roleplay_summary var/ooc_codex_information var/cyborg_noun = "Cyborg" - var/hidden_from_codex = TRUE - var/is_crystalline = FALSE - - // Icon/appearance vars. - var/icobase = 'icons/mob/human_races/species/human/body.dmi' // Normal icon set. - var/deform = 'icons/mob/human_races/species/human/deformed_body.dmi' // Mutated icon set. - var/preview_icon = 'icons/mob/human_races/species/human/preview.dmi' - var/lip_icon = 'icons/mob/human_races/species/human/lips.dmi' - var/husk_icon = 'icons/mob/human_races/species/default_husk.dmi' - var/bandages_icon - var/bodytype = BODYTYPE_OTHER - var/limb_icon_intensity = 1.5 - - // Damage overlay and masks. - var/damage_overlays = 'icons/mob/human_races/species/human/damage_overlay.dmi' - var/damage_mask = 'icons/mob/human_races/species/human/damage_mask.dmi' - var/blood_mask = 'icons/mob/human_races/species/human/blood_mask.dmi' - - var/blood_color = COLOR_BLOOD_HUMAN // Red. - var/flesh_color = "#ffc896" // Pink. - var/blood_oxy = 1 - var/base_color // Used by changelings. Should also be used for icon previes.. - var/limb_blend = ICON_ADD - var/tail // Name of tail state in species effects icon file. - var/tail_animation // If set, the icon to obtain tail animation states from. - var/tail_blend = ICON_ADD - var/tail_hair - - var/list/hair_styles - var/list/facial_hair_styles + var/hidden_from_codex = FALSE + var/secret_codex_info + + var/holder_icon + var/list/available_bodytypes = list() + var/decl/bodytype/default_bodytype + var/base_external_prosthetics_model = /decl/bodytype/prosthetic/basic_human + var/base_internal_prosthetics_model + + /// Set to true to blacklist this species from all map jobs it is not explicitly whitelisted for. + var/job_blacklist_by_default = FALSE + + // A list of customization categories made available in character preferences. + var/list/available_accessory_categories = list( + SAC_HAIR, + SAC_FACIAL_HAIR, + SAC_EARS, + SAC_TAIL, + SAC_COSMETICS, + SAC_MARKINGS + ) - var/organs_icon //species specific internal organs icons + // Lists of accessory types for modpack modification of accessory restrictions. + // These lists are pretty broad and indiscriminate in application, don't use + // them for fine detail restriction/allowing if you can avoid it. + var/list/allow_specific_sprite_accessories + var/list/disallow_specific_sprite_accessories + var/list/accessory_styles + + var/list/blood_types = list( + /decl/blood_type/aplus, + /decl/blood_type/aminus, + /decl/blood_type/bplus, + /decl/blood_type/bminus, + /decl/blood_type/abplus, + /decl/blood_type/abminus, + /decl/blood_type/oplus, + /decl/blood_type/ominus + ) - var/default_h_style = "Bald" - var/default_f_style = "Shaved" + var/flesh_color = "#ffc896" // Pink. + var/blood_oxy = 1 - var/icon_cache_uid // Used for mob icon cache string. - var/icon_template = 'icons/mob/human_races/species/template.dmi' // Used for mob icon generation for non-32x32 species. - var/pixel_offset_x = 0 // Used for offsetting large icons. - var/pixel_offset_y = 0 // Used for offsetting large icons. - var/pixel_offset_z = 0 // Used for offsetting large icons. - var/antaghud_offset_x = 0 // As above, but specifically for the antagHUD indicator. - var/antaghud_offset_y = 0 // As above, but specifically for the antagHUD indicator. + var/organs_icon //species specific internal organs icons - var/mob_size = MOB_SIZE_MEDIUM - var/strength = STR_MEDIUM + var/strength = STR_MEDIUM var/show_ssd = "fast asleep" var/short_sighted // Permanent weldervision. var/light_sensitive // Ditto, but requires sunglasses to fix @@ -66,29 +70,23 @@ var/taste_sensitivity = TASTE_NORMAL // How sensitive the species is to minute tastes. var/silent_steps - var/min_age = 17 - var/max_age = 70 - // Speech vars. - var/assisted_langs = list() // The languages the species can't speak without an assisted organ. + var/assisted_langs = list() // The languages the species can't speak without an assisted organ. + var/unspeakable_langs = list() // The languages the species can't speak at all. var/list/speech_sounds // A list of sounds to potentially play when speaking. var/list/speech_chance // The likelihood of a speech sound playing. + var/scream_verb_1p = "scream" + var/scream_verb_3p = "screams" // Combat vars. - var/total_health = 200 // Point at which the mob will enter crit. - var/list/unarmed_attacks = list( // Possible unarmed attacks that the mob will use in combat, - /decl/natural_attack, - /decl/natural_attack/bite - ) + var/total_health = DEFAULT_SPECIES_HEALTH // Point at which the mob will enter crit. - var/list/natural_armour_values // Armour values used if naked. var/brute_mod = 1 // Physical damage multiplier. var/burn_mod = 1 // Burn damage multiplier. var/toxins_mod = 1 // Toxloss modifier var/radiation_mod = 1 // Radiation modifier var/oxy_mod = 1 // Oxyloss modifier - var/flash_mod = 1 // Stun from blindness modifier. var/metabolism_mod = 1 // Reagent metabolism modifier var/stun_mod = 1 // Stun period modifier. var/paralysis_mod = 1 // Paralysis period modifier. @@ -97,39 +95,37 @@ var/vision_flags = SEE_SELF // Same flags as glasses. // Death vars. - var/meat_type = /obj/item/chems/food/snacks/meat/human - var/meat_amount = 3 - var/skin_material = /decl/material/solid/skin - var/skin_amount = 3 - var/bone_material = /decl/material/solid/bone - var/bone_amount = 3 + var/butchery_data = /decl/butchery_data/humanoid var/remains_type = /obj/item/remains/xeno var/gibbed_anim = "gibbed-h" var/dusted_anim = "dust-h" + /// A modifier applied to move delay when walking on snow. + var/snow_slowdown_mod = 0 + var/death_sound var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." var/knockout_message = "collapses, having been knocked unconscious." var/halloss_message = "slumps over, too weak to continue fighting..." var/halloss_message_self = "The pain is too severe for you to keep going..." - var/limbs_are_nonsolid - var/spawns_with_stack = 0 + var/sniff_message_3p = "sniffs the air." + var/sniff_message_1p = "You sniff the air." + + // Environment tolerance/life processes vars. - var/reagent_tag // Used for metabolizing reagents. var/breath_pressure = 16 // Minimum partial pressure safe for breathing, kPa - var/breath_type = /decl/material/gas/oxygen // Non-oxygen gas breathed, if any. - var/poison_types = list(/decl/material/gas/chlorine = TRUE) // Noticeably poisonous air - ie. updates the toxins indicator on the HUD. - var/exhale_type = /decl/material/gas/carbon_dioxide // Exhaled gas type. + var/breath_type = /decl/material/gas/oxygen // Non-oxygen gas breathed, if any. + /// Material types considered noticeably poisonous when inhaled (ie. updates the toxins indicator on the HUD). + /// This is an associative list for speed. + var/poison_types = list( + /decl/material/gas/chlorine = TRUE + ) + var/exhale_type = /decl/material/gas/carbon_dioxide // Exhaled gas type. var/blood_reagent = /decl/material/liquid/blood var/max_pressure_diff = 60 // Maximum pressure difference that is safe for lungs - var/cold_level_1 = 243 // Cold damage level 1 below this point. -30 Celsium degrees - var/cold_level_2 = 200 // Cold damage level 2 below this point. - var/cold_level_3 = 120 // Cold damage level 3 below this point. - var/heat_level_1 = 360 // Heat damage level 1 above this point. - var/heat_level_2 = 400 // Heat damage level 2 above this point. - var/heat_level_3 = 1000 // Heat damage level 3 above this point. + var/passive_temp_gain = 0 // Species will gain this much temperature every second var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. @@ -137,86 +133,41 @@ var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure. var/body_temperature = 310.15 // Species will try to stabilize at this temperature. // (also affects temperature processing) - var/heat_discomfort_level = 315 // Aesthetic messages about feeling warm. - var/cold_discomfort_level = 285 // Aesthetic messages about feeling chilly. - var/list/heat_discomfort_strings = list( - "You feel sweat drip down your neck.", - "You feel uncomfortably warm.", - "Your skin prickles in the heat." - ) - var/list/cold_discomfort_strings = list( - "You feel chilly.", - "You shiver suddenly.", - "Your chilly flesh stands out in goosebumps." - ) - var/water_soothe_amount // HUD data vars. - var/datum/hud_data/hud - var/hud_type - var/health_hud_intensity = 1 + var/datum/hud_data/species_hud var/grab_type = /decl/grab/normal/passive // The species' default grab type. // Body/form vars. var/list/inherent_verbs // Species-specific verbs. - var/siemens_coefficient = 1 // The lower, the thicker the skin and better the insulation. - var/darksight_range = 2 // Native darksight distance. - var/darksight_tint = DARKTINT_NONE // How shadows are tinted. + var/shock_vulnerability = 1 // The lower, the thicker the skin and better the insulation. var/species_flags = 0 // Various specific features. - var/appearance_flags = 0 // Appearance/display related features. var/spawn_flags = 0 // Flags that specify who can spawn as this species - var/slowdown = 0 // Passive movement speed malus (or boost, if negative) // Move intents. Earlier in list == default for that type of movement. - var/list/move_intents = list(/decl/move_intent/walk, /decl/move_intent/run, /decl/move_intent/creep) + var/list/move_intents = list( + /decl/move_intent/walk, + /decl/move_intent/run, + /decl/move_intent/creep + ) var/primitive_form // Lesser form, if any (ie. monkey for humans) - var/greater_form // Greater form, if any, ie. human for monkeys. var/holder_type var/gluttonous = 0 // Can eat some mobs. Values can be GLUT_TINY, GLUT_SMALLER, GLUT_ANYTHING, GLUT_ITEM_TINY, GLUT_ITEM_NORMAL, GLUT_ITEM_ANYTHING, GLUT_PROJECTILE_VOMIT var/stomach_capacity = 5 // How much stuff they can stick in their stomach var/rarity_value = 1 // Relative rarity/collector value for this species. // Determines the organs that the species spawns with and - var/list/has_organ = list( // which required-organ checks are conducted. - BP_HEART = /obj/item/organ/internal/heart, - BP_STOMACH = /obj/item/organ/internal/stomach, - BP_LUNGS = /obj/item/organ/internal/lungs, - BP_LIVER = /obj/item/organ/internal/liver, - BP_KIDNEYS = /obj/item/organ/internal/kidneys, - BP_BRAIN = /obj/item/organ/internal/brain, - BP_APPENDIX = /obj/item/organ/internal/appendix, - BP_EYES = /obj/item/organ/internal/eyes - ) - var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them. - var/breathing_organ // If set, this organ is required for breathing. Defaults to "lungs" if the species has them. - - var/list/override_organ_types // Used for species that only need to change one or two entries in has_organ. var/obj/effect/decal/cleanable/blood/tracks/move_trail = /obj/effect/decal/cleanable/blood/tracks/footprints // What marks are left when walking - var/list/skin_overlays = list() - - var/list/has_limbs = list( - BP_CHEST = list("path" = /obj/item/organ/external/chest), - BP_GROIN = list("path" = /obj/item/organ/external/groin), - BP_HEAD = list("path" = /obj/item/organ/external/head), - BP_L_ARM = list("path" = /obj/item/organ/external/arm), - BP_R_ARM = list("path" = /obj/item/organ/external/arm/right), - BP_L_LEG = list("path" = /obj/item/organ/external/leg), - BP_R_LEG = list("path" = /obj/item/organ/external/leg/right), - BP_L_HAND = list("path" = /obj/item/organ/external/hand), - BP_R_HAND = list("path" = /obj/item/organ/external/hand/right), - BP_L_FOOT = list("path" = /obj/item/organ/external/foot), - BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right) - ) - - var/list/override_limb_types // Used for species that only need to change one or two entries in has_limbs. - - // The basic skin colours this species uses - var/list/base_skin_colours - - var/list/genders = list(MALE, FEMALE, PLURAL) + var/decl/pronouns/default_pronouns + var/list/available_pronouns = list( + /decl/pronouns/pseudoplural, + /decl/pronouns/neuter/person, + /decl/pronouns/female, + /decl/pronouns/male + ) // Bump vars var/bump_flag = HUMAN // What are we considered to be when bumped? @@ -225,33 +176,16 @@ var/pass_flags = 0 var/breathing_sound = 'sound/voice/monkey.ogg' - var/list/equip_adjust = list() - var/list/equip_overlays = list() - - var/list/base_auras - var/sexybits_location //organ tag where they are located if they can be kicked for increased pain - - var/list/prone_overlay_offset = list(0, 0) // amount to shift overlays when lying - var/job_skill_buffs = list() // A list containing jobs (/datum/job), with values the extra points that job recieves. - - var/list/descriptors = list( - /datum/mob_descriptor/height = 0, - /datum/mob_descriptor/build = 0 - ) + var/job_skill_buffs = list() // A list containing jobs (/datum/job), with values the extra points that job receives. var/standing_jump_range = 2 var/list/maneuvers = list(/decl/maneuver/leap) - var/list/available_cultural_info = list( - TAG_CULTURE = list(CULTURE_OTHER), - TAG_HOMEWORLD = list(HOME_SYSTEM_STATELESS), - TAG_FACTION = list(FACTION_OTHER), - TAG_RELIGION = list(RELIGION_OTHER) - ) - var/list/force_cultural_info = list() - var/list/default_cultural_info = list() - var/list/additional_available_cultural_info = list() + var/list/available_background_info = list() + var/list/force_background_info = list() + var/list/default_background_info = list() + var/list/additional_available_background_info = list() var/max_players // Order matters, higher pain level should be higher up @@ -263,290 +197,313 @@ var/manual_dexterity = DEXTERITY_FULL - var/datum/ai/ai // Type abused. Define with path and will automagically create. Determines behaviour for clientless mobs. This will override mob AIs. + var/datum/mob_controller/ai // Type abused. Define with path and will automagically create. Determines behaviour for clientless mobs. This will override mob AIs. -/* -These are all the things that can be adjusted for equipping stuff and -each one can be in the NORTH, SOUTH, EAST, and WEST direction. Specify -the direction to shift the thing and what direction. - -example: - equip_adjust = list( - slot_back_str = list(NORTH = list(SOUTH = 12, EAST = 7), EAST = list(SOUTH = 2, WEST = 12)) - ) - -This would shift back items (backpacks, axes, etc.) when the mob -is facing either north or east. -When the mob faces north the back item icon is shifted 12 pixes down and 7 pixels to the right. -When the mob faces east the back item icon is shifted 2 pixels down and 12 pixels to the left. - -The slots that you can use are found in items_clothing.dm and are the inventory slot string ones, so make sure - you use the _str version of the slot. -*/ + var/exertion_emote_chance = 5 + var/exertion_effect_chance = 0 + var/exertion_hydration_scale = 0 + var/exertion_nutrition_scale = 0 + var/exertion_charge_scale = 0 + var/exertion_reagent_scale = 0 + + var/exertion_reagent_path + var/list/exertion_emotes_biological + var/list/exertion_emotes_synthetic + + var/list/traits = list() // An associative list of /decl/traits and trait level - See individual traits for valid levels + + // Preview icon gen/tracking vars. + var/icon/preview_icon + var/preview_icon_width = 64 + var/preview_icon_height = 64 + var/preview_icon_path + var/preview_outfit = /decl/outfit/job/generic/assistant -/datum/species/New() + /// List of emote types that this species can use by default. + var/list/default_emotes + +/decl/species/proc/build_codex_strings() if(!codex_description) codex_description = description - for(var/token in ALL_CULTURAL_TAGS) - - var/force_val = force_cultural_info[token] + // Generate OOC info. + var/list/codex_traits = list() + if(spawn_flags & SPECIES_CAN_JOIN) + codex_traits += "

  • Often present among humans.
  • " + if(spawn_flags & SPECIES_IS_WHITELISTED) + codex_traits += "
  • Whitelist restricted.
  • " + if(!default_bodytype.has_organ[BP_HEART]) + codex_traits += "
  • Does not have blood.
  • " + if(!default_bodytype.breathing_organ) + codex_traits += "
  • Does not breathe.
  • " + if(default_bodytype.body_flags & BODY_FLAG_NO_PAIN) + codex_traits += "
  • Does not feel pain.
  • " + if(default_bodytype.body_flags & BODY_FLAG_NO_DNA) + codex_traits += "
  • Does not have DNA.
  • " + if(default_bodytype.body_flags & BODY_FLAG_NO_EAT) + codex_traits += "
  • Lacks a mouth capable of eating.
  • " + if(species_flags & SPECIES_FLAG_NO_MINOR_CUT) + codex_traits += "
  • Has thick skin/scales.
  • " + if(species_flags & SPECIES_FLAG_NO_SLIP) + codex_traits += "
  • Has excellent traction.
  • " + if(species_flags & SPECIES_FLAG_NO_POISON) + codex_traits += "
  • Immune to most poisons.
  • " + if(species_flags & SPECIES_FLAG_IS_PLANT) + codex_traits += "
  • Has a plantlike physiology.
  • " + + var/list/codex_damage_types = list( + "physical trauma" = brute_mod, + "burns" = burn_mod, + "lack of air" = oxy_mod, + ) + for(var/kind in codex_damage_types) + if(codex_damage_types[kind] > 1) + codex_traits += "
  • Vulnerable to [kind].
  • " + else if(codex_damage_types[kind] < 1) + codex_traits += "
  • Resistant to [kind].
  • " + if(breath_type) + var/decl/material/mat = GET_DECL(breath_type) + codex_traits += "
  • They breathe [mat.gas_name].
  • " + if(exhale_type) + var/decl/material/mat = GET_DECL(exhale_type) + codex_traits += "
  • They exhale [mat.gas_name].
  • " + if(LAZYLEN(poison_types)) + var/list/poison_names = list() + for(var/g in poison_types) + var/decl/material/mat = GET_DECL(exhale_type) + poison_names |= mat.gas_name + codex_traits += "
  • [capitalize(english_list(poison_names))] [LAZYLEN(poison_names) == 1 ? "is" : "are"] poisonous to them.
  • " + + if(length(codex_traits)) + var/trait_string = "They have the following notable traits:
      [jointext(codex_traits, null)]
    " + if(ooc_codex_information) + ooc_codex_information += "

    [trait_string]" + else + ooc_codex_information = trait_string + +/decl/species/Initialize() + + . = ..() + + if(!base_internal_prosthetics_model) + // internal bodytypes don't care about icons so this is safe, and also necessary for the default map species + base_internal_prosthetics_model = base_external_prosthetics_model || /decl/bodytype/prosthetic/basic_human + + // Populate blood type table. + for(var/blood_type in blood_types) + var/decl/blood_type/blood_decl = GET_DECL(blood_type) + blood_types -= blood_type + blood_types[blood_decl.name] = blood_decl.random_weighting + + for(var/bodytype in available_bodytypes) + available_bodytypes -= bodytype + available_bodytypes += GET_DECL(bodytype) + + // Update sprite accessory lists for these species. + for(var/accessory_type in allow_specific_sprite_accessories) + var/decl/sprite_accessory/accessory = GET_DECL(accessory_type) + // If this accessory is species restricted, add us to the list. + if(accessory.species_allowed) + accessory.species_allowed |= uid + if(!isnull(accessory.body_flags_allowed)) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.body_flags_allowed |= bodytype.body_flags + if(!isnull(accessory.body_flags_denied)) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.body_flags_denied &= ~bodytype.body_flags + if(accessory.bodytype_categories_allowed) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.bodytype_categories_allowed |= bodytype.bodytype_category + if(accessory.bodytype_categories_denied) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.bodytype_categories_allowed -= bodytype.bodytype_category + + for(var/accessory_type in disallow_specific_sprite_accessories) + var/decl/sprite_accessory/accessory = GET_DECL(accessory_type) + if(accessory.species_allowed) + accessory.species_allowed -= uid + if(!isnull(accessory.body_flags_allowed)) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.body_flags_allowed &= ~bodytype.body_flags + if(!isnull(accessory.body_flags_denied)) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.body_flags_denied |= bodytype.body_flags + if(accessory.bodytype_categories_allowed) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.bodytype_categories_allowed -= bodytype.bodytype_category + if(accessory.bodytype_categories_denied) + for(var/decl/bodytype/bodytype in available_bodytypes) + accessory.bodytype_categories_allowed |= bodytype.bodytype_category + + if(ispath(default_bodytype)) + default_bodytype = GET_DECL(default_bodytype) + else if(length(available_bodytypes) && !default_bodytype) + default_bodytype = available_bodytypes[1] + + for(var/pronoun in available_pronouns) + available_pronouns -= pronoun + available_pronouns += GET_DECL(pronoun) + + if(ispath(default_pronouns)) + default_pronouns = GET_DECL(default_pronouns) + else if(length(available_pronouns) && !default_pronouns) + default_pronouns = available_pronouns[1] + + for(var/cat_type in decls_repository.get_decls_of_subtype(/decl/background_category)) + + var/force_val = force_background_info[cat_type] if(force_val) - default_cultural_info[token] = force_val - available_cultural_info[token] = list(force_val) + default_background_info[cat_type] = force_val + available_background_info[cat_type] = list(force_val) - else if(additional_available_cultural_info[token]) - if(!available_cultural_info[token]) - available_cultural_info[token] = list() - available_cultural_info[token] |= additional_available_cultural_info[token] + else if(additional_available_background_info[cat_type]) + if(!available_background_info[cat_type]) + available_background_info[cat_type] = list() + available_background_info[cat_type] |= additional_available_background_info[cat_type] - else if(!LAZYLEN(available_cultural_info[token])) - var/list/map_systems = GLOB.using_map.available_cultural_info[token] - available_cultural_info[token] = map_systems.Copy() + else if(!LAZYLEN(available_background_info[cat_type])) + var/list/map_systems = global.using_map.available_background_info[cat_type] + available_background_info[cat_type] = islist(map_systems) ? map_systems.Copy() : list() - if(LAZYLEN(available_cultural_info[token]) && !default_cultural_info[token]) - var/list/avail_systems = available_cultural_info[token] - default_cultural_info[token] = avail_systems[1] + if(LAZYLEN(available_background_info[cat_type]) && !default_background_info[cat_type]) + var/list/avail_systems = available_background_info[cat_type] + default_background_info[cat_type] = avail_systems[1] - if(!default_cultural_info[token]) - default_cultural_info[token] = GLOB.using_map.default_cultural_info[token] + if(!default_background_info[cat_type]) + default_background_info[cat_type] = global.using_map.default_background_info[cat_type] - if(hud_type) - hud = new hud_type() + if(species_hud) + species_hud = new species_hud else - hud = new() - - if(LAZYLEN(descriptors)) - var/list/descriptor_datums = list() - for(var/desctype in descriptors) - var/datum/mob_descriptor/descriptor = new desctype - descriptor.comparison_offset = descriptors[desctype] - descriptor_datums[descriptor.name] = descriptor - descriptors = descriptor_datums - - //If the species has eyes, they are the default vision organ - if(!vision_organ && has_organ[BP_EYES]) - vision_organ = BP_EYES - //If the species has lungs, they are the default breathing organ - if(!breathing_organ && has_organ[BP_LUNGS]) - breathing_organ = BP_LUNGS - - // Modify organ lists if necessary. - if(islist(override_organ_types)) - for(var/ltag in override_organ_types) - has_organ[ltag] = override_organ_types[ltag] - - if(islist(override_limb_types)) - for(var/ltag in override_limb_types) - has_limbs[ltag] = list("path" = override_limb_types[ltag]) - - //Build organ descriptors - for(var/limb_type in has_limbs) - var/list/organ_data = has_limbs[limb_type] - var/obj/item/organ/limb_path = organ_data["path"] - organ_data["descriptor"] = initial(limb_path.name) - -/datum/species/proc/equip_survival_gear(var/mob/living/carbon/human/H,var/extendedtank = 1) - if(istype(H.get_equipped_item(slot_back), /obj/item/storage/backpack)) - if (extendedtank) H.equip_to_slot_or_del(new /obj/item/storage/box/engineer(H.back), slot_in_backpack) - else H.equip_to_slot_or_del(new /obj/item/storage/box/survival(H.back), slot_in_backpack) + species_hud = new + + build_codex_strings() + +/decl/species/validate() + . = ..() + + for(var/trait_type in traits) + var/trait_level = traits[trait_type] + var/decl/trait/trait = GET_DECL(trait_type) + if(!trait.validate_level(trait_level)) + . += "invalid levels for species trait [trait_type]" + if(uid in trait.blocked_species) + . += "trait [trait.name] prevents this species from taking it" + if(trait.permitted_species && !(uid in trait.permitted_species)) + . += "trait [trait.name] does not permit this species to take it" + + if(!length(blood_types)) + . += "missing at least one blood type" + if(default_bodytype && !(default_bodytype in available_bodytypes)) + . += "default bodytype is not in available bodytypes list" + if(!length(available_bodytypes)) + . += "missing at least one bodytype" + + if(taste_sensitivity < 0) + . += "taste_sensitivity ([taste_sensitivity]) was negative" + +/decl/species/proc/equip_survival_gear(mob/living/wearer, box_type = /obj/item/box/survival) + if(!box_type) + return + var/obj/item/backpack/backpack = wearer.get_equipped_item(slot_back_str) + if(istype(backpack)) + wearer.equip_to_slot_or_del(new box_type(backpack), slot_in_backpack_str) else - if (extendedtank) H.equip_to_slot_or_del(new /obj/item/storage/box/engineer(H), slot_r_hand) - else H.equip_to_slot_or_del(new /obj/item/storage/box/survival(H), slot_r_hand) + wearer.put_in_hands_or_del(new box_type(wearer)) -/datum/species/proc/get_manual_dexterity(var/mob/living/carbon/human/H) +/decl/species/proc/get_manual_dexterity(var/mob/living/human/H) . = manual_dexterity -/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. - - H.mob_size = mob_size - for(var/obj/item/organ/organ in H.contents) - if((organ in H.organs) || (organ in H.internal_organs)) - qdel(organ) - - if(H.organs) H.organs.Cut() - if(H.internal_organs) H.internal_organs.Cut() - if(H.organs_by_name) H.organs_by_name.Cut() - if(H.internal_organs_by_name) H.internal_organs_by_name.Cut() - - H.organs = list() - H.internal_organs = list() - H.organs_by_name = list() - H.internal_organs_by_name = list() - - for(var/limb_type in has_limbs) - var/list/organ_data = has_limbs[limb_type] - var/limb_path = organ_data["path"] - new limb_path(H) - - for(var/organ_tag in has_organ) - var/organ_type = has_organ[organ_tag] - var/obj/item/organ/O = new organ_type(H) - if(organ_tag != O.organ_tag) - warning("[O.type] has a default organ tag \"[O.organ_tag]\" that differs from the species' organ tag \"[organ_tag]\". Updating organ_tag to match.") - O.organ_tag = organ_tag - H.internal_organs_by_name[organ_tag] = O - - for(var/name in H.organs_by_name) - H.organs |= H.organs_by_name[name] - - for(var/name in H.internal_organs_by_name) - H.internal_organs |= H.internal_organs_by_name[name] - - for(var/obj/item/organ/O in (H.organs|H.internal_organs)) - O.owner = H - post_organ_rejuvenate(O, H) - - H.sync_organ_dna() - -/datum/species/proc/hug(var/mob/living/carbon/human/H,var/mob/living/target) - - var/t_him = "them" - switch(target.gender) - if(MALE) - t_him = "him" - if(FEMALE) - t_him = "her" - - H.visible_message("[H] hugs [target] to make [t_him] feel better!", \ - "You hug [target] to make [t_him] feel better!") - - if(H != target) - H.update_personal_goal(/datum/goal/achievement/givehug, TRUE) - target.update_personal_goal(/datum/goal/achievement/gethug, TRUE) - -/datum/species/proc/add_base_auras(var/mob/living/carbon/human/H) - if(base_auras) - for(var/type in base_auras) - H.add_aura(new type(H)) - -/datum/species/proc/remove_base_auras(var/mob/living/carbon/human/H) - if(base_auras) - var/list/bcopy = base_auras.Copy() - for(var/a in H.auras) - var/obj/aura/A = a - if(is_type_in_list(a, bcopy)) - bcopy -= A.type - H.remove_aura(A) - qdel(A) - -/datum/species/proc/remove_inherent_verbs(var/mob/living/carbon/human/H) +/decl/species/proc/remove_inherent_verbs(var/mob/living/human/H) if(inherent_verbs) for(var/verb_path in inherent_verbs) H.verbs -= verb_path return -/datum/species/proc/add_inherent_verbs(var/mob/living/carbon/human/H) +/decl/species/proc/add_inherent_verbs(var/mob/living/human/H) if(inherent_verbs) for(var/verb_path in inherent_verbs) H.verbs |= verb_path return -/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment. +/decl/species/proc/handle_post_spawn(var/mob/living/human/H) //Handles anything not already covered by basic species assignment. add_inherent_verbs(H) - add_base_auras(H) - H.mob_bump_flag = bump_flag - H.mob_swap_flags = swap_flags - H.mob_push_flags = push_flags - H.pass_flags = pass_flags - handle_limbs_setup(H) + handle_movement_flags_setup(H) -/datum/species/proc/handle_pre_spawn(var/mob/living/carbon/human/H) +/decl/species/proc/handle_pre_spawn(var/mob/living/human/H) return -/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events. +/decl/species/proc/handle_death(var/mob/living/human/H) //Handles any species-specific death events. return -/datum/species/proc/handle_new_grab(var/mob/living/carbon/human/H, var/obj/item/grab/G) - return - -/datum/species/proc/handle_sleeping(var/mob/living/carbon/human/H) +/decl/species/proc/handle_sleeping(var/mob/living/human/H) if(prob(2) && !H.failed_last_breath && !H.isSynthetic()) - if(!H.paralysis) - H.emote("snore") + if(!HAS_STATUS(H, STAT_PARA)) + H.emote(/decl/emote/audible/snore) else - H.emote("groan") + H.emote(/decl/emote/audible/groan) -/datum/species/proc/handle_environment_special(var/mob/living/carbon/human/H) +/decl/species/proc/handle_environment_special(var/mob/living/human/H) return -/datum/species/proc/handle_movement_delay_special(var/mob/living/carbon/human/H) +/decl/species/proc/handle_movement_delay_special(var/mob/living/human/H) return 0 // Used to update alien icons for aliens. -/datum/species/proc/handle_login_special(var/mob/living/carbon/human/H) +/decl/species/proc/handle_login_special(var/mob/living/human/H) return // As above. -/datum/species/proc/handle_logout_special(var/mob/living/carbon/human/H) +/decl/species/proc/handle_logout_special(var/mob/living/human/H) return -// Builds the HUD using species-specific icons and usable slots. -/datum/species/proc/build_hud(var/mob/living/carbon/human/H) - return - -/datum/species/proc/can_understand(var/mob/other) - return - -/datum/species/proc/can_overcome_gravity(var/mob/living/carbon/human/H) +/decl/species/proc/can_overcome_gravity(var/mob/living/human/H) return FALSE // Used for any extra behaviour when falling and to see if a species will fall at all. -/datum/species/proc/can_fall(var/mob/living/carbon/human/H) - return TRUE +/decl/species/proc/can_fall(var/mob/living/human/H) + return !can_overcome_gravity(H) // Used to override normal fall behaviour. Use only when the species does fall down a level. -/datum/species/proc/handle_fall_special(var/mob/living/carbon/human/H, var/turf/landing) +/decl/species/proc/handle_fall_special(var/mob/living/human/H, var/turf/landing) return FALSE -// Called when using the shredding behavior. -/datum/species/proc/can_shred(var/mob/living/carbon/human/H, var/ignore_intent, var/ignore_antag) - - if((!ignore_intent && H.a_intent != I_HURT) || H.pulling_punches) - return 0 - - if(!ignore_antag && H.mind && !player_is_antag(H.mind)) - return 0 - - for(var/attack_type in unarmed_attacks) - var/decl/natural_attack/attack = decls_repository.get_decl(attack_type) - if(!istype(attack) || !attack.is_usable(H)) - continue - if(attack.shredding) - return 1 - return 0 +//Used for swimming +/decl/species/proc/can_float(var/mob/living/human/H) + if(!H.is_physically_disabled()) + return TRUE //We could tie it to stamina + return FALSE -/datum/species/proc/handle_vision(var/mob/living/carbon/human/H) +/decl/species/proc/handle_vision(var/mob/living/human/H) var/list/vision = H.get_accumulated_vision_handlers() H.update_sight() H.set_sight(H.sight|get_vision_flags(H)|H.equipment_vision_flags|vision[1]) - H.change_light_colour(H.getDarkvisionTint()) if(H.stat == DEAD) return 1 - if(!H.drugged) - H.set_see_in_dark((H.sight == (SEE_TURFS|SEE_MOBS|SEE_OBJS)) ? 8 : min(H.getDarkvisionRange() + H.equipment_darkness_modifier, 8)) + if(!HAS_STATUS(H, STAT_DRUGGY)) + H.set_see_in_dark((H.sight == (SEE_TURFS|SEE_MOBS|SEE_OBJS)) ? 8 : min(H.get_darksight_range() + H.equipment_darkness_modifier, 8)) if(H.equipment_see_invis) H.set_see_invisible(max(min(H.see_invisible, H.equipment_see_invis), vision[2])) if(H.equipment_tint_total >= TINT_BLIND) - H.eye_blind = max(H.eye_blind, 1) + SET_STATUS_MAX(H, STAT_BLIND, 2) if(!H.client)//no client, no screen to update return 1 - H.set_fullscreen(H.eye_blind && !H.equipment_prescription, "blind", /obj/screen/fullscreen/blind) + H.set_fullscreen(GET_STATUS(H, STAT_BLIND) && !H.equipment_prescription, "blind", /obj/screen/fullscreen/blind) H.set_fullscreen(H.stat == UNCONSCIOUS, "blackout", /obj/screen/fullscreen/blackout) - if(config.welder_vision) + if(get_config_value(/decl/config/toggle/on/welder_vision)) H.set_fullscreen(H.equipment_tint_total, "welder", /obj/screen/fullscreen/impaired, H.equipment_tint_total) var/how_nearsighted = get_how_nearsighted(H) H.set_fullscreen(how_nearsighted, "nearsighted", /obj/screen/fullscreen/oxy, how_nearsighted) - H.set_fullscreen(H.eye_blurry, "blurry", /obj/screen/fullscreen/blurry) - H.set_fullscreen(H.drugged, "high", /obj/screen/fullscreen/high) - if(H.drugged) + H.set_fullscreen(GET_STATUS(H, STAT_BLURRY), "blurry", /obj/screen/fullscreen/blurry) + H.set_fullscreen(GET_STATUS(H, STAT_DRUGGY), "high", /obj/screen/fullscreen/high) + if(HAS_STATUS(H, STAT_DRUGGY)) H.add_client_color(/datum/client_color/oversaturated) else H.remove_client_color(/datum/client_color/oversaturated) @@ -556,9 +513,9 @@ The slots that you can use are found in items_clothing.dm and are the inventory return 1 -/datum/species/proc/get_how_nearsighted(var/mob/living/carbon/human/H) +/decl/species/proc/get_how_nearsighted(var/mob/living/human/H) var/prescriptions = short_sighted - if(H.disabilities & NEARSIGHTED) + if(H.has_genetic_condition(GENE_COND_NEARSIGHTED)) prescriptions += 7 if(H.equipment_prescription) prescriptions -= H.equipment_prescription @@ -578,58 +535,58 @@ The slots that you can use are found in items_clothing.dm and are the inventory light = round(light * turf_brightness) if(H.equipment_light_protection) light -= H.equipment_light_protection - return Clamp(max(prescriptions, light), 0, 7) - -/datum/species/proc/set_default_hair(var/mob/living/carbon/human/H) - if(H.h_style != H.species.default_h_style) - H.h_style = H.species.default_h_style - . = TRUE - if(H.f_style != H.species.default_f_style) - H.f_style = H.species.default_f_style - . = TRUE - if(.) - H.update_hair() - -/datum/species/proc/handle_additional_hair_loss(var/mob/living/carbon/human/H, var/defer_body_update = TRUE) + return clamp(max(prescriptions, light), 0, 7) + +/decl/species/proc/handle_additional_hair_loss(var/mob/living/human/H, var/defer_body_update = TRUE) return FALSE -/datum/species/proc/get_blood_name() - return "blood" +/decl/species/proc/get_blood_decl(var/mob/living/human/H) + if(istype(H) && H.isSynthetic()) + return GET_DECL(/decl/blood_type/coolant) + return get_blood_type_by_name(blood_types[1]) -/datum/species/proc/handle_death_check(var/mob/living/carbon/human/H) - return FALSE +/decl/species/proc/get_blood_name(var/mob/living/human/H) + var/decl/blood_type/blood = get_blood_decl(H) + return istype(blood) ? blood.splatter_name : "blood" -//Mostly for toasters -/datum/species/proc/handle_limbs_setup(var/mob/living/carbon/human/H) - for(var/thing in H.organs) - post_organ_rejuvenate(thing, H) +/decl/species/proc/get_species_blood_color(var/mob/living/human/H) + var/decl/blood_type/blood = get_blood_decl(H) + return istype(blood) ? blood.splatter_colour : COLOR_BLOOD_HUMAN // Impliments different trails for species depending on if they're wearing shoes. -/datum/species/proc/get_move_trail(var/mob/living/carbon/human/H) - if(H.lying) +/decl/species/proc/get_move_trail(var/mob/living/human/H) + if(H.current_posture.prone) return /obj/effect/decal/cleanable/blood/tracks/body - if(H.shoes || (H.wear_suit && (H.wear_suit.body_parts_covered & FEET))) - var/obj/item/clothing/shoes = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) ? H.wear_suit : H.shoes // suits take priority over shoes + var/obj/item/clothing/suit = H.get_equipped_item(slot_wear_suit_str) + if(istype(suit) && (suit.body_parts_covered & SLOT_FEET)) + return suit.move_trail + var/obj/item/clothing/shoes = H.get_equipped_item(slot_shoes_str) + if(istype(shoes)) return shoes.move_trail - else - return move_trail + return move_trail -/datum/species/proc/update_skin(var/mob/living/carbon/human/H) +/decl/species/proc/handle_trail(var/mob/living/human/H, var/turf/T) return -/datum/species/proc/disarm_attackhand(var/mob/living/carbon/human/attacker, var/mob/living/carbon/human/target) +/decl/species/proc/update_skin(var/mob/living/human/H) + return + +/decl/species/proc/disarm_attackhand(var/mob/living/human/attacker, var/mob/living/human/target) attacker.do_attack_animation(target) - if(target.w_uniform) - target.w_uniform.add_fingerprint(attacker) - var/obj/item/organ/external/affecting = target.get_organ(ran_zone(attacker.zone_sel.selecting)) + var/obj/item/uniform = target.get_equipped_item(slot_w_uniform_str) + if(uniform) + uniform.add_fingerprint(attacker) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(target, ran_zone(attacker.get_target_zone(), target = target)) - var/list/holding = list(target.get_active_hand() = 60, target.get_inactive_hand() = 30) + var/list/holding = list(target.get_active_held_item() = 60) + for(var/thing in target.get_inactive_held_items()) + holding[thing] = 30 var/skill_mod = 10 * attacker.get_skill_difference(SKILL_COMBAT, target) var/state_mod = attacker.melee_accuracy_mods() - target.melee_accuracy_mods() var/push_mod = min(max(1 + attacker.get_skill_difference(SKILL_COMBAT, target), 1), 3) - if(target.a_intent == I_HELP) + if(target.check_intent(I_FLAG_HELP)) state_mod -= 30 //Handle unintended consequences for(var/obj/item/I in holding) @@ -638,7 +595,7 @@ The slots that you can use are found in items_clothing.dm and are the inventory return var/randn = rand(1, 100) - skill_mod + state_mod - if(!(check_no_slip(target)) && randn <= 25) + if(target.can_slip() && randn <= 25) var/armor_check = 100 * target.get_blocked_ratio(affecting, BRUTE, damage = 20) target.apply_effect(push_mod, WEAKEN, armor_check) playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) @@ -656,7 +613,7 @@ The slots that you can use are found in items_clothing.dm and are the inventory //Actually disarm them for(var/obj/item/I in holding) - if(I && target.unEquip(I)) + if(I && target.try_unequip(I)) target.visible_message("[attacker] has disarmed [target]!") playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) return @@ -664,168 +621,132 @@ The slots that you can use are found in items_clothing.dm and are the inventory playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) target.visible_message("[attacker] attempted to disarm \the [target]!") -/datum/species/proc/disfigure_msg(var/mob/living/carbon/human/H) //Used for determining the message a disfigured face has on examine. To add a unique message, just add this onto a specific species and change the "return" message. - var/datum/gender/T = gender_datums[H.get_gender()] - return "[T.His] face is horribly mangled!\n" - -/datum/species/proc/max_skin_tone() - if(appearance_flags & HAS_SKIN_TONE_GRAV) - return 100 - if(appearance_flags & HAS_SKIN_TONE_SPCR) - return 165 - if(appearance_flags & HAS_SKIN_TONE_TRITON) - return 80 - return 220 - -/datum/species/proc/get_hair_styles() - var/list/L = LAZYACCESS(hair_styles, type) - if(!L) - L = list() - LAZYSET(hair_styles, type, L) - for(var/hairstyle in GLOB.hair_styles_list) - var/datum/sprite_accessory/S = GLOB.hair_styles_list[hairstyle] - if(S.species_allowed && !(get_root_species_name() in S.species_allowed)) - continue - if(S.subspecies_allowed && !(name in S.subspecies_allowed)) +/decl/species/proc/disfigure_msg(var/mob/living/human/H) //Used for determining the message a disfigured face has on examine. To add a unique message, just add this onto a specific species and change the "return" message. + var/decl/pronouns/pronouns = H.get_pronouns() + return SPAN_DANGER("[pronouns.His] face is horribly mangled!\n") + +/decl/species/proc/get_available_accessories(var/decl/bodytype/bodytype, accessory_category) + . = list() + for(var/accessory in get_available_accessory_types(bodytype, accessory_category)) + . += GET_DECL(accessory) + +/decl/species/proc/get_available_accessory_types(decl/bodytype/bodytype, accessory_category) + if(!bodytype) + bodytype = default_bodytype + var/list/available_accessories = accessory_styles?[bodytype.type]?[accessory_category] + if(!available_accessories) + available_accessories = list() + LAZYINITLIST(accessory_styles) + LAZYSET(accessory_styles[bodytype.type], accessory_category, available_accessories) + var/decl/sprite_accessory_category/accessory_category_decl = GET_DECL(accessory_category) + var/list/all_accessories = decls_repository.get_decls_of_subtype(accessory_category_decl.base_accessory_type) + for(var/accessory_style in all_accessories) + var/decl/sprite_accessory/check_accessory = all_accessories[accessory_style] + if(!check_accessory || !check_accessory.accessory_is_available(null, src, bodytype, FALSE)) continue - ADD_SORTED(L, hairstyle, /proc/cmp_text_asc) - L[hairstyle] = S - return L - -/datum/species/proc/get_facial_hair_styles(var/gender) - var/list/facial_hair_styles_by_species = LAZYACCESS(facial_hair_styles, type) - if(!facial_hair_styles_by_species) - facial_hair_styles_by_species = list() - LAZYSET(facial_hair_styles, type, facial_hair_styles_by_species) - - var/list/facial_hair_style_by_gender = facial_hair_styles_by_species[gender] - if(!facial_hair_style_by_gender) - facial_hair_style_by_gender = list() - LAZYSET(facial_hair_styles_by_species, gender, facial_hair_style_by_gender) - - for(var/facialhairstyle in GLOB.facial_hair_styles_list) - var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if(S.species_allowed && !(get_root_species_name() in S.species_allowed)) - continue - if(S.subspecies_allowed && !(name in S.subspecies_allowed)) - continue - ADD_SORTED(facial_hair_style_by_gender, facialhairstyle, /proc/cmp_text_asc) - facial_hair_style_by_gender[facialhairstyle] = S - - return facial_hair_style_by_gender + ADD_SORTED(available_accessories, accessory_style, /proc/cmp_text_asc) + available_accessories[accessory_style] = check_accessory + return available_accessories -/datum/species/proc/get_description(var/header, var/append, var/verbose = TRUE, var/skip_detail, var/skip_photo) - var/list/damage_types = list( - "physical trauma" = brute_mod, - "burns" = burn_mod, - "lack of air" = oxy_mod, - "poison" = toxins_mod - ) - if(!header) - header = "

    [name]


    " - var/dat = list() - dat += "[header]" - dat += "" - dat += "" - dat += "" - if((!skip_photo && preview_icon) || !skip_detail) - dat += "" - dat += "" - dat += "
    " - if(verbose || length(description) <= MAX_DESC_LEN) - dat += "[description]" - else - dat += "[copytext(description, 1, MAX_DESC_LEN)] \[...\]" - if(append) - dat += "
    [append]" - dat += "
    " - if(!skip_photo && preview_icon) - send_rsc(usr, icon(icon = preview_icon, icon_state = ""), "species_preview_[name].png") - dat += "

    " - if(!skip_detail) - dat += "" - if(spawn_flags & SPECIES_CAN_JOIN) - dat += "
    Often present among humans." - if(spawn_flags & SPECIES_IS_WHITELISTED) - dat += "
    Whitelist restricted." - if(!has_organ[BP_HEART]) - dat += "
    Does not have blood." - if(!has_organ[breathing_organ]) - dat += "
    Does not breathe." - if(species_flags & SPECIES_FLAG_NO_SCAN) - dat += "
    Does not have DNA." - if(species_flags & SPECIES_FLAG_NO_PAIN) - dat += "
    Does not feel pain." - if(species_flags & SPECIES_FLAG_NO_MINOR_CUT) - dat += "
    Has thick skin/scales." - if(species_flags & SPECIES_FLAG_NO_SLIP) - dat += "
    Has excellent traction." - if(species_flags & SPECIES_FLAG_NO_POISON) - dat += "
    Immune to most poisons." - if(appearance_flags & HAS_A_SKIN_TONE) - dat += "
    Has a variety of skin tones." - if(appearance_flags & HAS_SKIN_COLOR) - dat += "
    Has a variety of skin colours." - if(appearance_flags & HAS_EYE_COLOR) - dat += "
    Has a variety of eye colours." - if(species_flags & SPECIES_FLAG_IS_PLANT) - dat += "
    Has a plantlike physiology." - if(slowdown) - dat += "
    Moves [slowdown > 0 ? "slower" : "faster"] than most." - for(var/kind in damage_types) - if(damage_types[kind] > 1) - dat += "
    Vulnerable to [kind]." - else if(damage_types[kind] < 1) - dat += "
    Resistant to [kind]." - if(breath_type) - var/decl/material/mat = decls_repository.get_decl(breath_type) - dat += "
    They breathe [mat.gas_name]." - if(exhale_type) - var/decl/material/mat = decls_repository.get_decl(exhale_type) - dat += "
    They exhale [mat.gas_name]." - if(LAZYLEN(poison_types)) - var/list/poison_names = list() - for(var/g in poison_types) - var/decl/material/mat = decls_repository.get_decl(exhale_type) - poison_names |= mat.gas_name - dat += "
    [capitalize(english_list(poison_names))] [LAZYLEN(poison_names) == 1 ? "is" : "are"] poisonous to them." - dat += "
    " - dat += "

    " - return jointext(dat, null) - -/mob/living/carbon/human/verb/check_species() - set name = "Check Species Information" - set category = "IC" - set src = usr - - show_browser(src, species.get_description(), "window=species;size=700x400") - -/datum/species/proc/skills_from_age(age) //Converts an age into a skill point allocation modifier. Can be used to give skill point bonuses/penalities not depending on job. +/decl/species/proc/skills_from_age(age) //Converts an age into a skill point allocation modifier. Can be used to give skill point bonuses/penalities not depending on job. switch(age) if(0 to 22) . = -4 if(23 to 30) . = 0 if(31 to 45) . = 4 else . = 8 -/datum/species/proc/post_organ_rejuvenate(var/obj/item/organ/org, var/mob/living/carbon/human/H) - if(org && (org.species ? org.species.is_crystalline : is_crystalline)) - org.status |= (ORGAN_BRITTLE|ORGAN_CRYSTAL) - -/datum/species/proc/check_no_slip(var/mob/living/carbon/human/H) - if(can_overcome_gravity(H)) +/decl/species/proc/check_no_slip(mob/living/user, magboots_only) + if(can_overcome_gravity(user)) return TRUE return (species_flags & SPECIES_FLAG_NO_SLIP) -/datum/species/proc/get_pain_emote(var/mob/living/carbon/human/H, var/pain_power) - if(!(species_flags & SPECIES_FLAG_NO_PAIN)) - return +// This assumes you've already checked that their bodytype can feel pain. +/decl/species/proc/get_pain_emote(var/mob/living/human/H, var/pain_power) for(var/pain_emotes in pain_emotes_with_pain_level) var/pain_level = pain_emotes_with_pain_level[pain_emotes] if(pain_level >= pain_power) // This assumes that if a pain-level has been defined it also has a list of emotes to go with it - var/decl/emote/E = decls_repository.get_decl(pick(pain_emotes)) - return E.key + return pick(pain_emotes) + +/decl/species/proc/handle_post_move(var/mob/living/human/H, exertion = TRUE) + if(exertion) + handle_exertion(H) + +/decl/species/proc/handle_exertion(mob/living/human/H) + if (!exertion_effect_chance) + return + var/chance = max((100 - H.stamina), exertion_effect_chance * H.encumbrance()) + if (chance && prob(H.skill_fail_chance(SKILL_HAULING, chance))) + var/synthetic = H.isSynthetic() + if (synthetic) + if (exertion_charge_scale) + var/obj/item/organ/internal/cell/cell = H.get_organ(BP_CELL, /obj/item/organ/internal/cell) + if (cell) + cell.use(cell.get_power_drain() * exertion_charge_scale) + else + if (exertion_hydration_scale) + H.adjust_hydration(-DEFAULT_THIRST_FACTOR * exertion_hydration_scale) + if (exertion_nutrition_scale) + H.adjust_nutrition(-DEFAULT_HUNGER_FACTOR * exertion_nutrition_scale) + if (exertion_reagent_scale && !isnull(exertion_reagent_path)) + H.make_reagent(REM * exertion_reagent_scale, exertion_reagent_path) + if(prob(exertion_emote_chance)) + var/list/active_emotes = synthetic ? exertion_emotes_synthetic : exertion_emotes_biological + if(length(active_emotes)) + var/decl/emote/exertion_emote = GET_DECL(pick(active_emotes)) + exertion_emote.do_emote(H) + +/decl/species/proc/get_default_name() + return "[lowertext(name)] ([random_id(name, 100, 999)])" + +/decl/species/proc/get_holder_color(var/mob/living/human/H) + return + +//Called after a mob's species is set, organs were created, and we're about to update the icon, color, and etc of the mob being created. +//Consider this might be called post-init +/decl/species/proc/apply_appearance(var/mob/living/human/H) + H.icon_state = lowertext(src.name) + +/decl/species/proc/get_preview_icon() + if(!preview_icon) + + // TODO: generate an icon based on all available bodytypes. + + var/mob/living/human/dummy/mannequin/mannequin = get_mannequin("#species_[ckey(uid)]") + if(mannequin) + + mannequin.change_species(uid) // handles species/bodytype init + default_bodytype.customize_preview_mannequin(mannequin) // handles body colors/styles setup + customize_preview_mannequin(mannequin) // handles 'cultural' things like default outfit + + preview_icon = icon(mannequin?.get_bodytype().icon_template) + var/mob_width = preview_icon.Width() + preview_icon.Scale((mob_width * 2)+16, preview_icon.Height()+16) + + preview_icon.Blend(getFlatIcon(mannequin, defdir = SOUTH, always_use_defdir = TRUE), ICON_OVERLAY, 8, 8) + preview_icon.Blend(getFlatIcon(mannequin, defdir = WEST, always_use_defdir = TRUE), ICON_OVERLAY, mob_width+8, 8) + + preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) + preview_icon_width = preview_icon.Width() + preview_icon_height = preview_icon.Height() + preview_icon_path = "species_preview_[ckey(uid)].png" + + return preview_icon + +/decl/species/proc/handle_movement_flags_setup(var/mob/living/human/H) + H.mob_bump_flag = bump_flag + H.mob_swap_flags = swap_flags + H.mob_push_flags = push_flags + H.pass_flags = pass_flags + +/decl/species/proc/modify_preview_appearance(mob/living/human/dummy/mannequin) + return mannequin + +/decl/species/proc/get_default_background_datum_by_flag(background_flag) + for(var/cat_type in default_background_info) + var/decl/background_category/background_cat = GET_DECL(cat_type) + if(background_cat.background_flags & background_flag) + return GET_DECL(default_background_info[cat_type]) + +/decl/species/proc/get_safe_pressure() + return (warning_high_pressure + warning_low_pressure)/2 \ No newline at end of file diff --git a/code/modules/species/species_allergies.dm b/code/modules/species/species_allergies.dm new file mode 100644 index 000000000000..1fe47cf0811b --- /dev/null +++ b/code/modules/species/species_allergies.dm @@ -0,0 +1,17 @@ +/decl/species + /// This determiens how damaging allergic reactions are. + var/allergen_damage_severity = 2.5 + /// This determines how long nonlethal effects last and how common emotes are. + var/allergen_disable_severity = 10 + /// What type of reactions will you have? These the 'main' options and are intended to approximate anaphylactic shock at high doses. + var/allergen_reaction = ALLERGEN_REACTION_TOX_DMG|ALLERGEN_REACTION_OXY_DMG|ALLERGEN_REACTION_EMOTE|ALLERGEN_REACTION_PAIN|ALLERGEN_REACTION_BLURRY|ALLERGEN_REACTION_CONFUSE + var/list/allergy_choke_emotes = list( + /decl/emote/audible/cough, + /decl/emote/audible/gasp, + /decl/emote/audible/choke + ) + var/list/allergy_faint_emotes = list( + /decl/emote/visible/pale, + /decl/emote/visible/shiver, + /decl/emote/visible/twitch + ) diff --git a/code/modules/species/species_attack.dm b/code/modules/species/species_attack.dm index 1e3a44e711c2..a391a8994bf7 100644 --- a/code/modules/species/species_attack.dm +++ b/code/modules/species/species_attack.dm @@ -2,68 +2,76 @@ attack_verb = list("bit", "chomped on") attack_sound = 'sound/weapons/bite.ogg' shredding = 0 - sharp = 1 - edge = 1 - attack_name = "sharp bite" + sharp = TRUE + edge = TRUE + name = "sharp bite" /decl/natural_attack/claws attack_verb = list("scratched", "clawed", "slashed") attack_noun = list("claws") + selector_icon_state = "attack_claws" eye_attack_text = "claws" eye_attack_text_victim = "sharp claws" attack_sound = 'sound/weapons/slice.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' - sharp = 1 - edge = 1 - attack_name = "claws" + sharp = TRUE + edge = TRUE + name = "claws" usable_with_limbs = list(BP_L_HAND, BP_R_HAND) var/blocked_by_gloves = TRUE -/decl/natural_attack/claws/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) - return (!user.gloves || !blocked_by_gloves) +/decl/natural_attack/claws/attack_is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) + return (!user.get_equipped_item(slot_gloves_str) || !blocked_by_gloves) -/decl/natural_attack/claws/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) +/decl/natural_attack/claws/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) if(!affecting) return ..() - attack_damage = Clamp(attack_damage, 1, 5) - + var/decl/pronouns/user_gender = user.get_pronouns() + attack_damage = clamp(attack_damage, 1, 5) if(target == user) - user.visible_message("[user] [pick(attack_verb)] \himself in the [affecting.name]!") + user.visible_message(SPAN_DANGER("\The [user] [pick(attack_verb)] [user_gender.self] in the [affecting.name]!")) return 0 + var/decl/pronouns/target_gender = target.get_pronouns() + var/attack_string switch(zone) if(BP_HEAD, BP_MOUTH, BP_EYES) // ----- HEAD ----- // switch(attack_damage) - if(1 to 2) user.visible_message("[user] scratched [target] across \his cheek!") + if(1 to 2) + attack_string = "scratches \the [target] across [target_gender.his] cheek" if(3 to 4) - user.visible_message(pick( - 80; user.visible_message("[user] [pick(attack_verb)] [target]'s [pick("face", "neck", affecting.name)]!"), - 20; user.visible_message("[user] [pick(attack_verb)] [pick("[target] in the [affecting.name]", "[target] across \his [pick("face", "neck", affecting.name)]")]!"), - )) + attack_string = pick( + 80; "[pick(attack_verb)] [target]'s [pick("face", "neck", affecting.name)]", + 20; "[pick(attack_verb)] \the [target] [pick("in the [affecting.name]", "across [target_gender.his] [pick("face", "neck", affecting.name)]")]", + ) if(5) - user.visible_message(pick( - "[user] rakes \his [pick(attack_noun)] across [target]'s [pick("face", "neck", affecting.name)]!", - "[user] tears \his [pick(attack_noun)] into [target]'s [pick("face", "neck", affecting.name)]!", - )) + attack_string = pick( + "rakes [user_gender.his] [pick(attack_noun)] across [target]'s [pick("face", "neck", affecting.name)]", + "tears [user_gender.his] [pick(attack_noun)] into [target]'s [pick("face", "neck", affecting.name)]", + ) else // ----- BODY ----- // switch(attack_damage) - if(1 to 2) user.visible_message("[user] [pick("scratched", "grazed")] [target]'s [affecting.name]!") + if(1 to 2) + attack_string = "[pick("scratched", "grazed")] [target]'s [affecting.name]" if(3 to 4) - user.visible_message(pick( - 80; user.visible_message("[user] [pick(attack_verb)] [target]'s [affecting.name]!"), - 20; user.visible_message("[user] [pick(attack_verb)] [pick("[target] in the [affecting.name]", "[target] across \his [affecting.name]")]!"), - )) - if(5) user.visible_message("[user] tears \his [pick(attack_noun)] [pick("deep into", "into", "across")] [target]'s [affecting.name]!") + attack_string = pick( + 80; "[pick(attack_verb)] [target]'s [affecting.name]", + 20; "[pick(attack_verb)] [pick("[target] in the [affecting.name]", "[target] across [target_gender.his] [affecting.name]")]", + ) + if(5) + attack_string = "tears [user_gender.his] [pick(attack_noun)] [pick("deep into", "into", "across")] [target]'s [affecting.name]" + if(attack_string) + user.visible_message(SPAN_DANGER("\The [user] [attack_string]!")) /decl/natural_attack/claws/strong attack_verb = list("slashed") damage = 5 shredding = 1 - attack_name = "strong claws" + name = "strong claws" /decl/natural_attack/claws/strong/gloves blocked_by_gloves = FALSE @@ -72,28 +80,30 @@ attack_verb = list("mauled") damage = 8 shredding = 1 - attack_name = "strong bite" + name = "strong bite" /decl/natural_attack/slime_glomp + name = "glomp" + selector_icon_state = "attack_glomp" attack_verb = list("glomped") attack_noun = list("body") damage = 2 - attack_name = "glomp" usable_with_limbs = list(BP_CHEST, BP_GROIN) -/decl/natural_attack/slime_glomp/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone) - ..() - user.apply_stored_shock_to(target) +/decl/natural_attack/slime_glomp/apply_attack_effects(mob/living/user, mob/living/target, attack_damage, zone) + . = ..() + if(.) + user.apply_stored_shock_to(target) /decl/natural_attack/stomp/weak + name = "weak stomp" attack_verb = list("jumped on") - attack_name = "weak stomp" -/decl/natural_attack/stomp/weak/get_unarmed_damage() +/decl/natural_attack/stomp/weak/get_unarmed_damage(mob/living/user, mob/living/victim) return damage -/decl/natural_attack/stomp/weak/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) +/decl/natural_attack/stomp/weak/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) if(affecting) user.visible_message(SPAN_WARNING("\The [user] jumped up and down on \the [target]'s [affecting.name]!")) else @@ -101,57 +111,49 @@ playsound(user.loc, attack_sound, 25, 1, -1) /decl/natural_attack/tail + name = "tail swipe" + selector_icon_state = "attack_tail" attack_verb = list ("bludgeoned", "lashed", "smacked", "whapped") attack_noun = list ("tail") - attack_name = "tail swipe" usable_with_limbs = list(BP_GROIN) - -/decl/natural_attack/tail/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) //ensures that you can't tail someone in the skull - - if(!(zone in list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT, BP_GROIN))) - - return 0 - - var/obj/item/organ/external/E = user.organs_by_name[BP_L_FOOT] - - if(E && !E.is_stump()) - - return 1 - - - E = user.organs_by_name[BP_R_FOOT] - - if(E && !E.is_stump()) - - return 1 - - return 0 - -/decl/natural_attack/tail/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) - - var/obj/item/organ/external/affecting = istype(target) && zone && target.get_organ(zone) + var/static/list/can_hit_zones = list( + BP_L_LEG, + BP_R_LEG, + BP_L_FOOT, + BP_R_FOOT, + BP_GROIN + ) + +/decl/natural_attack/tail/attack_is_usable(var/mob/living/human/user, var/mob/living/human/target, var/zone) //ensures that you can't tail someone in the skull + if(!(zone in can_hit_zones)) + return FALSE + for(var/foot_tag in list(BP_L_FOOT, BP_R_FOOT)) + if(GET_EXTERNAL_ORGAN(user, foot_tag)) + return TRUE + return FALSE + +/decl/natural_attack/tail/show_attack(var/mob/living/human/user, var/mob/living/human/target, var/zone, var/attack_damage) + + var/obj/item/organ/external/affecting = istype(target) && zone && GET_EXTERNAL_ORGAN(target, zone) if(!affecting) return ..() - var/organ = affecting.name - attack_damage = Clamp(attack_damage, 1, 6) + attack_damage = clamp(attack_damage, 1, 6) attack_damage = 3 + attack_damage - rand(1, 5) switch(attack_damage) - if(1 to 5) user.visible_message("[user] glanced [target] with their [pick(attack_noun)] in the [organ]!") - - if(6 to 7) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ] with their [pick(attack_noun)]!") - - if(8) user.visible_message("[user] landed a heavy blow with their [pick(attack_noun)] against [target]'s [organ]!") + if(1 to 5) user.visible_message("[user] glanced [target] with their [pick(attack_noun)] in \the [affecting]!") + if(6 to 7) user.visible_message("[user] [pick(attack_verb)] [target] in \the [affecting] with their [pick(attack_noun)]!") + if(8) user.visible_message("[user] landed a heavy blow with their [pick(attack_noun)] against [target]'s [affecting.name]!") /decl/natural_attack/punch/weak attack_verb = list("swiped", "smacked", "smecked") - attack_name = "smek" + name = "smek" /decl/natural_attack/punch/starborn attack_verb = list("scorched", "burned", "fried") shredding = 1 - attack_name = "starborn strike" + name = "starborn strike" /decl/natural_attack/punch/starborn/get_damage_type() return BURN @@ -161,7 +163,7 @@ attack_sound = 'sound/weapons/bite.ogg' damage = 5 delay = 120 - attack_name = "venomous bite" + name = "venomous bite" /decl/natural_attack/bite/venom/get_damage_type() return TOX diff --git a/code/modules/species/species_getters.dm b/code/modules/species/species_getters.dm index 86f11bc56921..cf8f78ca0e91 100644 --- a/code/modules/species/species_getters.dm +++ b/code/modules/species/species_getters.dm @@ -1,109 +1,44 @@ -/datum/species/proc/get_valid_shapeshifter_forms(var/mob/living/carbon/human/H) - return list() - -/datum/species/proc/get_additional_examine_text(var/mob/living/carbon/human/H) +/decl/species/proc/get_additional_examine_text(var/mob/living/human/H) return -/datum/species/proc/get_tail(var/mob/living/carbon/human/H) - return tail - -/datum/species/proc/get_tail_animation(var/mob/living/carbon/human/H) - return tail_animation - -/datum/species/proc/get_tail_hair(var/mob/living/carbon/human/H) - return tail_hair - -/datum/species/proc/get_blood_mask(var/mob/living/carbon/human/H) - return blood_mask - -/datum/species/proc/get_damage_overlays(var/mob/living/carbon/human/H) - return damage_overlays - -/datum/species/proc/get_damage_mask(var/mob/living/carbon/human/H) - return damage_mask - -/datum/species/proc/get_examine_name(var/mob/living/carbon/human/H) - return name - -/datum/species/proc/get_icobase(var/mob/living/carbon/human/H, var/get_deform) - return (get_deform ? deform : icobase) - -/datum/species/proc/get_station_variant() - return name - -/datum/species/proc/get_icon_cache_uid(var/mob/H) - if(!icon_cache_uid) - icon_cache_uid = "[sequential_id(/datum/species)]" - return icon_cache_uid - -/datum/species/proc/get_bodytype(var/mob/living/carbon/human/H) - return bodytype - -/datum/species/proc/get_knockout_message(var/mob/living/carbon/human/H) +/decl/species/proc/get_knockout_message(var/mob/living/human/H) return ((H && H.isSynthetic()) ? "encounters a hardware fault and suddenly reboots!" : knockout_message) -/datum/species/proc/get_death_message(var/mob/living/carbon/human/H) +/decl/species/proc/get_species_death_message(var/mob/living/human/H) return ((H && H.isSynthetic()) ? "gives one shrill beep before falling lifeless." : death_message) -/datum/species/proc/get_ssd(var/mob/living/carbon/human/H) +/decl/species/proc/get_ssd(var/mob/living/human/H) return ((H && H.isSynthetic()) ? "flashing a 'system offline' glyph on their monitor" : show_ssd) -/datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H) - return ((H && H.isSynthetic()) ? SYNTH_BLOOD_COLOUR : blood_color) - -/datum/species/proc/get_flesh_colour(var/mob/living/carbon/human/H) +/decl/species/proc/get_species_flesh_color(var/mob/living/human/H) return ((H && H.isSynthetic()) ? SYNTH_FLESH_COLOUR : flesh_color) -/datum/species/proc/get_environment_discomfort(var/mob/living/carbon/human/H, var/msg_type) - - if(!prob(5)) - return - - var/covered = 0 // Basic coverage can help. - for(var/obj/item/clothing/clothes in H) - if(H.l_hand == clothes || H.r_hand == clothes) - continue - if((clothes.body_parts_covered & UPPER_TORSO) && (clothes.body_parts_covered & LOWER_TORSO)) - covered = 1 - break - - switch(msg_type) - if("cold") - if(!covered) - to_chat(H, "[pick(cold_discomfort_strings)]") - if("heat") - if(covered) - to_chat(H, "[pick(heat_discomfort_strings)]") - -/datum/species/proc/get_vision_flags(var/mob/living/carbon/human/H) +/decl/species/proc/get_vision_flags(var/mob/living/human/H) return vision_flags -/datum/species/proc/get_husk_icon(var/mob/living/carbon/human/H) - return husk_icon - -/datum/species/proc/get_sex(var/mob/living/carbon/H) - return H.gender - -/datum/species/proc/get_surgery_overlay_icon(var/mob/living/carbon/human/H) - return 'icons/mob/surgery.dmi' - -/datum/species/proc/get_footstep(var/mob/living/carbon/human/H, var/footstep_type) +/decl/species/proc/get_footstep(var/mob/living/human/H, var/footstep_type) return -/datum/species/proc/get_brute_mod(var/mob/living/carbon/human/H) +/decl/species/proc/get_brute_mod(var/mob/living/human/H) . = brute_mod -/datum/species/proc/get_burn_mod(var/mob/living/carbon/human/H) +/decl/species/proc/get_burn_mod(var/mob/living/human/H) . = burn_mod -/datum/species/proc/get_toxins_mod(var/mob/living/carbon/human/H) - . = toxins_mod - -/datum/species/proc/get_radiation_mod(var/mob/living/carbon/human/H) +/decl/species/proc/get_radiation_mod(var/mob/living/human/H) . = (H && H.isSynthetic() ? 0.5 : radiation_mod) -/datum/species/proc/get_slowdown(var/mob/living/carbon/human/H) - . = (H && H.isSynthetic() ? 0 : slowdown) - -/datum/species/proc/get_root_species_name(var/mob/living/carbon/human/H) - return name +/decl/species/proc/get_bodytype_by_name(var/bodytype_name) + bodytype_name = trim(lowertext(bodytype_name)) + if(!bodytype_name) + return + for(var/decl/bodytype/bodytype in available_bodytypes) + if(lowertext(bodytype.name) == bodytype_name) + return bodytype + +/decl/species/proc/get_bodytype_by_pronouns(var/decl/pronouns/pronouns) + if(istype(pronouns)) + for(var/decl/bodytype/bodytype in available_bodytypes) + if(!isnull(bodytype.associated_gender) && bodytype.associated_gender == pronouns.name) + return bodytype + return default_bodytype diff --git a/code/modules/species/species_helpers.dm b/code/modules/species/species_helpers.dm index cabb01991975..efd996aaf266 100644 --- a/code/modules/species/species_helpers.dm +++ b/code/modules/species/species_helpers.dm @@ -1,80 +1,67 @@ -var/list/stored_shock_by_ref = list() +var/global/list/stored_shock_by_ref = list() /mob/living/proc/apply_stored_shock_to(var/mob/living/target) - if(stored_shock_by_ref["\ref[src]"]) - target.electrocute_act(stored_shock_by_ref["\ref[src]"]*0.9, src) - stored_shock_by_ref["\ref[src]"] = 0 + if(global.stored_shock_by_ref["\ref[src]"]) + target.electrocute_act(global.stored_shock_by_ref["\ref[src]"]*0.9, src) + global.stored_shock_by_ref["\ref[src]"] = 0 -/datum/species/proc/toggle_stance(var/mob/living/carbon/human/H) - if(!H.incapacitated()) - H.pulling_punches = !H.pulling_punches - to_chat(H, "You are now [H.pulling_punches ? "pulling your punches" : "not pulling your punches"].") - -/datum/species/proc/get_offset_overlay_image(var/spritesheet, var/mob_icon, var/mob_state, var/color, var/slot) - - // If we don't actually need to offset this, don't bother with any of the generation/caching. - if(!spritesheet && equip_adjust.len && equip_adjust[slot] && LAZYLEN(equip_adjust[slot])) - - // Check the cache for previously made icons. - var/image_key = "[mob_icon]-[mob_state]-[color]" - if(!equip_overlays[image_key]) - - var/icon/final_I = new(icon_template) - var/list/shifts = equip_adjust[slot] - - // Apply all pixel shifts for each direction. - for(var/shift_facing in shifts) - var/list/facing_list = shifts[shift_facing] - var/use_dir = text2num(shift_facing) - var/icon/equip = new(mob_icon, icon_state = mob_state, dir = use_dir) - var/icon/canvas = new(icon_template) - canvas.Blend(equip, ICON_OVERLAY, facing_list["x"]+1, facing_list["y"]+1) - final_I.Insert(canvas, dir = use_dir) - equip_overlays[image_key] = overlay_image(final_I, color = color, flags = RESET_COLOR) - var/image/I = new() // We return a copy of the cached image, in case downstream procs mutate it. - I.appearance = equip_overlays[image_key] - return I - return overlay_image(mob_icon, mob_state, color, RESET_COLOR) - -/datum/species/proc/fluid_act(var/mob/living/carbon/human/H, var/datum/reagents/fluids) +/decl/species/proc/fluid_act(var/mob/living/human/H, var/datum/reagents/fluids) + SHOULD_CALL_PARENT(TRUE) var/water = REAGENT_VOLUME(fluids, /decl/material/liquid/water) - if(water >= 40 && H.getHalLoss()) - H.adjustHalLoss(-(water_soothe_amount)) + if(water >= 40 && H.get_damage(PAIN)) + H.heal_damage(PAIN, water_soothe_amount) if(prob(5)) to_chat(H, SPAN_NOTICE("The water ripples gently over your skin in a soothing balm.")) -/datum/species/proc/is_available_for_join() +/decl/species/proc/is_available_for_join() if(!(spawn_flags & SPECIES_CAN_JOIN)) return FALSE else if(!isnull(max_players)) var/player_count = 0 - for(var/mob/living/carbon/human/H in GLOB.living_mob_list_) + for(var/mob/living/human/H in global.living_mob_list_) if(H.client && H.key && H.species == src) player_count++ if(player_count >= max_players) return FALSE return TRUE -/datum/species/proc/check_background(var/datum/job/job, var/datum/preferences/prefs) +/decl/species/proc/check_background(var/datum/job/job, var/datum/preferences/prefs) . = TRUE -/datum/species/proc/get_digestion_product() +/decl/species/proc/get_digestion_product() return /decl/material/liquid/nutriment -/datum/species/proc/handle_post_species_pref_set(var/datum/preferences/pref) - return +/decl/species/proc/handle_post_species_pref_set(datum/preferences/pref) + pref.skin_colour = default_bodytype.base_color + pref.eye_colour = default_bodytype.base_eye_color +// pref.hair_colour = default_bodytype.base_hair_color +// pref.facial_hair_colour = default_bodytype.base_hair_color + +/decl/species/proc/equip_default_fallback_uniform(var/mob/living/human/H) + if(istype(H)) + H.equip_to_slot_or_del(new /obj/item/clothing/shirt/harness, slot_w_uniform_str) + +/decl/species/proc/get_hazard_high_pressure(var/mob/living/human/H) + return hazard_high_pressure + +/decl/species/proc/get_warning_high_pressure(var/mob/living/human/H) + return warning_high_pressure + +/decl/species/proc/get_warning_low_pressure(var/mob/living/human/H) + return warning_low_pressure + +/decl/species/proc/get_hazard_low_pressure(var/mob/living/human/H) + return hazard_low_pressure -/datum/species/proc/get_resized_organ_w_class(var/organ_w_class) - . = Clamp(organ_w_class + mob_size_difference(mob_size, MOB_SIZE_MEDIUM), ITEM_SIZE_TINY, ITEM_SIZE_GARGANTUAN) +/decl/species/proc/get_shock_vulnerability(var/mob/living/human/H) + return shock_vulnerability -/datum/species/proc/resize_organ(var/obj/item/organ/organ) - if(!istype(organ)) - return - organ.w_class = get_resized_organ_w_class(initial(organ.w_class)) - if(!istype(organ, /obj/item/organ/external)) - return - var/obj/item/organ/external/limb = organ - for(var/bp_tag in has_organ) - var/obj/item/organ/internal/I = has_organ[bp_tag] - if(initial(I.parent_organ) == organ.organ_tag) - limb.cavity_max_w_class = max(limb.cavity_max_w_class, get_resized_organ_w_class(initial(I.w_class))) \ No newline at end of file +/decl/species/proc/adjust_status(mob/living/target, condition, amount) + switch(condition) + if(STAT_WEAK) + return amount * weaken_mod + if(STAT_STUN) + return amount * stun_mod + if(STAT_PARA) + return amount * paralysis_mod + return amount diff --git a/code/modules/species/species_hud.dm b/code/modules/species/species_hud.dm index e7b0a2a837b9..17ab4381d161 100644 --- a/code/modules/species/species_hud.dm +++ b/code/modules/species/species_hud.dm @@ -1,68 +1,69 @@ /datum/hud_data - var/icon // If set, overrides ui_style. - var/has_a_intent = 1 // Set to draw intent box. - var/has_m_intent = 1 // Set to draw move intent box. - var/has_warnings = 1 // Set to draw environment warnings. - var/has_pressure = 1 // Draw the pressure indicator. - var/has_nutrition = 1 // Draw the nutrition indicator. - var/has_bodytemp = 1 // Draw the bodytemp indicator. - var/has_hands = 1 // Set to draw hands. - var/has_drop = 1 // Set to draw drop button. - var/has_throw = 1 // Set to draw throw button. - var/has_resist = 1 // Set to draw resist button. - var/has_internals = 1 // Set to draw the internals toggle button. - var/has_up_hint = 1 // Set to draw the "look-up" hint icon - var/list/equip_slots = list() // Checked by mob_can_equip(). + /// Checked by mob_can_equip(). + var/list/equip_slots = list() + /// Built in New(), used for unhidable inv updates + var/list/persistent_slots = list() + /// Built in New(), used for hidable inv updates + var/list/hidden_slots = list() - // Contains information on the position and tag for all inventory slots - // to be drawn for the mob. This is fairly delicate, try to avoid messing with it - // unless you know exactly what it does. - var/list/gear = list( - "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1), - "o_clothing" = list("loc" = ui_oclothing, "name" = "Suit", "slot" = slot_wear_suit, "state" = "suit", "toggle" = 1), - "mask" = list("loc" = ui_mask, "name" = "Mask", "slot" = slot_wear_mask, "state" = "mask", "toggle" = 1), - "gloves" = list("loc" = ui_gloves, "name" = "Gloves", "slot" = slot_gloves, "state" = "gloves", "toggle" = 1), - "eyes" = list("loc" = ui_glasses, "name" = "Glasses", "slot" = slot_glasses, "state" = "glasses","toggle" = 1), - "l_ear" = list("loc" = ui_l_ear, "name" = "Left Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), - "r_ear" = list("loc" = ui_r_ear, "name" = "Right Ear", "slot" = slot_r_ear, "state" = "ears", "toggle" = 1), - "head" = list("loc" = ui_head, "name" = "Hat", "slot" = slot_head, "state" = "hair", "toggle" = 1), - "shoes" = list("loc" = ui_shoes, "name" = "Shoes", "slot" = slot_shoes, "state" = "shoes", "toggle" = 1), - "suit storage" = list("loc" = ui_sstore1, "name" = "Suit Storage", "slot" = slot_s_store, "state" = "suitstore"), - "back" = list("loc" = ui_back, "name" = "Back", "slot" = slot_back, "state" = "back"), - "id" = list("loc" = ui_id, "name" = "ID", "slot" = slot_wear_id, "state" = "id"), - "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), - "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), - "belt" = list("loc" = ui_belt, "name" = "Belt", "slot" = slot_belt, "state" = "belt") - ) + var/list/inventory_slots = list( + /datum/inventory_slot/handcuffs, + /datum/inventory_slot/uniform, + /datum/inventory_slot/suit, + /datum/inventory_slot/mask, + /datum/inventory_slot/gloves, + /datum/inventory_slot/glasses, + /datum/inventory_slot/ear, + /datum/inventory_slot/ear/right, + /datum/inventory_slot/head, + /datum/inventory_slot/shoes, + /datum/inventory_slot/suit_storage, + /datum/inventory_slot/back, + /datum/inventory_slot/id, + /datum/inventory_slot/pocket, + /datum/inventory_slot/pocket/right, + /datum/inventory_slot/belt + ) /datum/hud_data/New() ..() - for(var/slot in gear) - equip_slots |= gear[slot]["slot"] - - if(has_hands) - equip_slots |= slot_l_hand - equip_slots |= slot_r_hand - equip_slots |= slot_handcuffed - - if(slot_back in equip_slots) - equip_slots |= slot_in_backpack - - if(slot_w_uniform in equip_slots) - equip_slots |= slot_tie - - equip_slots |= slot_legcuffed + for(var/slot_type in inventory_slots) + var/datum/inventory_slot/inv_slot = new slot_type + inventory_slots -= slot_type + var/slot_id = inv_slot.slot_id + inventory_slots[slot_id] = inv_slot + equip_slots |= slot_id + // Build reference lists for inventory updates + if(inv_slot.can_be_hidden) + hidden_slots |= slot_id + else + persistent_slots |= slot_id + equip_slots |= slot_handcuffed_str + if(slot_back_str in equip_slots) + equip_slots |= slot_in_backpack_str + if(slot_wear_id_str in equip_slots) + equip_slots |= slot_in_wallet_str /datum/hud_data/monkey - gear = list( - "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1), - "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), - "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), - "l_ear" = list("loc" = ui_gloves, "name" = "Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), - "r_ear" = list("loc" = ui_l_ear, "name" = "Right Ear", "slot" = slot_r_ear, "state" = "ears", "toggle" = 1), - "id" = list("loc" = ui_id, "name" = "ID", "slot" = slot_wear_id, "state" = "id"), - "head" = list("loc" = ui_head, "name" = "Hat", "slot" = slot_head, "state" = "hair", "toggle" = 1), - "mask" = list("loc" = ui_oclothing, "name" = "Mask", "slot" = slot_wear_mask, "state" = "mask", "toggle" = 1), - "shoes" = list("loc" = ui_shoes, "name" = "Shoes", "slot" = slot_shoes, "state" = "shoes", "toggle" = 1), - "back" = list("loc" = ui_sstore1, "name" = "Back", "slot" = slot_back, "state" = "back"), - ) + inventory_slots = list( + /datum/inventory_slot/handcuffs, + /datum/inventory_slot/uniform, + /datum/inventory_slot/pocket, + /datum/inventory_slot/pocket/right, + /datum/inventory_slot/ear/monkey, + /datum/inventory_slot/ear/right/monkey, + /datum/inventory_slot/id, + /datum/inventory_slot/head, + /datum/inventory_slot/mask/monkey, + /datum/inventory_slot/shoes, + /datum/inventory_slot/back/monkey + ) + +/datum/inventory_slot/ear/monkey + ui_loc = ui_gloves +/datum/inventory_slot/ear/right/monkey + ui_loc = ui_l_ear +/datum/inventory_slot/mask/monkey + ui_loc = ui_oclothing +/datum/inventory_slot/back/monkey + ui_loc = ui_sstore1 diff --git a/code/modules/species/species_random.dm b/code/modules/species/species_random.dm deleted file mode 100644 index 3b2a775d58e2..000000000000 --- a/code/modules/species/species_random.dm +++ /dev/null @@ -1,76 +0,0 @@ -#define SETUP_RANDOM_COLOR_GETTER(X, Y, Z, W) \ -/datum/species/var/list/random_##Y = W;\ -/datum/species/proc/get_random_##X(){\ - if(!(appearance_flags & Z) || !random_##Y.len){\ - return;\ - }\ - var/decl/color_generator/CG = decls_repository.get_decl(pickweight(random_##Y));\ - return CG && CG.generate_random_colour();\ -} - -#define SETUP_RANDOM_COLOR_SETTER(X, Y)\ -/mob/living/carbon/human/proc/randomize_##X(){\ - if(!species){\ - return;\ - }\ - var/colour = species.get_random_##X();\ - if(colour){\ - Y(colour);\ - }\ -} - -SETUP_RANDOM_COLOR_GETTER(skin_color, skin_colors, HAS_SKIN_COLOR, list( - /decl/color_generator/black, - /decl/color_generator/grey, - /decl/color_generator/brown, - /decl/color_generator/chestnut, - /decl/color_generator/blue, - /decl/color_generator/blue_light, - /decl/color_generator/green, - /decl/color_generator/white)) -SETUP_RANDOM_COLOR_SETTER(skin_color, change_skin_color) - -SETUP_RANDOM_COLOR_GETTER(hair_color, hair_colors, HAS_HAIR_COLOR, list( - /decl/color_generator/black, - /decl/color_generator/blonde, - /decl/color_generator/chestnut, - /decl/color_generator/copper, - /decl/color_generator/brown, - /decl/color_generator/wheat, - /decl/color_generator/old, - /decl/color_generator/punk)) -SETUP_RANDOM_COLOR_SETTER(hair_color, change_hair_color) - -SETUP_RANDOM_COLOR_GETTER(eye_color, eye_colors, HAS_EYE_COLOR, list( - /decl/color_generator/black, - /decl/color_generator/grey, - /decl/color_generator/brown, - /decl/color_generator/chestnut, - /decl/color_generator/blue, - /decl/color_generator/blue_light, - /decl/color_generator/green, - /decl/color_generator/albino_eye)) -SETUP_RANDOM_COLOR_SETTER(eye_color, change_eye_color) - -/datum/species/proc/get_random_facial_hair_color() - return get_random_hair_color() - -SETUP_RANDOM_COLOR_SETTER(facial_hair_color, change_facial_hair_color) - -/datum/species/proc/get_random_skin_tone() - return random_skin_tone(src) - -/mob/living/carbon/human/proc/randomize_skin_tone() - if(!species) - return - var/new_tone = species.get_random_skin_tone() - if(!isnull(new_tone)) - change_skin_tone(new_tone) - -/mob/living/carbon/human/proc/randomize_hair_style() - change_hair(safepick(generate_valid_hairstyles())) - -/mob/living/carbon/human/proc/randomize_facial_hair_style() - change_facial_hair(safepick(generate_valid_facial_hairstyles())) - -#undef SETUP_RANDOM_COLOR_GETTER diff --git a/code/modules/species/species_shapeshift.dm b/code/modules/species/species_shapeshift.dm deleted file mode 100644 index 90804b876ae2..000000000000 --- a/code/modules/species/species_shapeshift.dm +++ /dev/null @@ -1,182 +0,0 @@ -// This is something of an intermediary species used for species that -// need to emulate the appearance of another race. Currently it is only -// used for slimes but it may be useful for changelings later. -var/list/wrapped_species_by_ref = list() - -/datum/species/shapeshifter - - inherent_verbs = list( - /mob/living/carbon/human/proc/shapeshifter_select_shape, - /mob/living/carbon/human/proc/shapeshifter_select_hair, - /mob/living/carbon/human/proc/shapeshifter_select_gender - ) - - var/list/valid_transform_species = list() - var/monochromatic - var/default_form - -/datum/species/shapeshifter/New() - default_form = GLOB.using_map.default_species - valid_transform_species |= default_form - ..() - -/datum/species/shapeshifter/get_valid_shapeshifter_forms(var/mob/living/carbon/human/H) - return valid_transform_species - -/datum/species/shapeshifter/get_icobase(var/mob/living/carbon/human/H, var/get_deform) - if(!H) return ..(null, get_deform) - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_icobase(H, get_deform) - -/datum/species/shapeshifter/get_icon_cache_uid(var/mob/H) - . = ..() - if(H) - . = "[.]-[wrapped_species_by_ref["\ref[H]"]]" - -/datum/species/shapeshifter/get_bodytype(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_bodytype(H) - -/datum/species/shapeshifter/get_root_species_name(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_root_species_name(H) - -/datum/species/shapeshifter/get_blood_mask(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_blood_mask(H) - -/datum/species/shapeshifter/get_damage_mask(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_damage_mask(H) - -/datum/species/shapeshifter/get_damage_overlays(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_damage_overlays(H) - -/datum/species/shapeshifter/get_tail(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_tail(H) - -/datum/species/shapeshifter/get_tail_animation(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_tail_animation(H) - -/datum/species/shapeshifter/get_tail_hair(var/mob/living/carbon/human/H) - if(!H) return ..() - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_tail_hair(H) - -/datum/species/shapeshifter/get_husk_icon(var/mob/living/carbon/human/H) - if(H) - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - if(S) return S.get_husk_icon(H) - return ..() - -/datum/species/shapeshifter/handle_pre_spawn(var/mob/living/carbon/human/H) - ..() - wrapped_species_by_ref["\ref[H]"] = default_form - -/datum/species/shapeshifter/handle_post_spawn(var/mob/living/carbon/human/H) - if(monochromatic) - H.hair_colour = H.skin_colour - H.facial_hair_colour = H.skin_colour - ..() - -/datum/species/shapeshifter/post_organ_rejuvenate(var/obj/item/organ/org, var/mob/living/carbon/human/H) - var/obj/item/organ/external/E = org - if(H && istype(E)) - E.sync_colour_to_human(H) - -/datum/species/shapeshifter/get_pain_emote(var/mob/living/carbon/human/H, var/pain_power) - var/datum/species/S = get_species_by_key(wrapped_species_by_ref["\ref[H]"]) - return S.get_pain_emote(H, pain_power) - -// Verbs follow. -/mob/living/carbon/human/proc/shapeshifter_select_hair() - - set name = "Select Hair" - set category = "Abilities" - - if(stat || world.time < last_special) - return - - last_special = world.time + 10 - - visible_message("\The [src]'s form contorts subtly.") - if(species.get_hair_styles()) - var/new_hair = input("Select a hairstyle.", "Shapeshifter Hair") as null|anything in species.get_hair_styles() - change_hair(new_hair ? new_hair : "Bald") - if(species.get_facial_hair_styles(gender)) - var/new_hair = input("Select a facial hair style.", "Shapeshifter Hair") as null|anything in species.get_facial_hair_styles(gender) - change_facial_hair(new_hair ? new_hair : "Shaved") - -/mob/living/carbon/human/proc/shapeshifter_select_gender() - - set name = "Select Gender" - set category = "Abilities" - - if(stat || world.time < last_special) - return - - last_special = world.time + 50 - - var/new_gender = input("Please select a gender.", "Shapeshifter Gender") as null|anything in list(FEMALE, MALE, NEUTER, PLURAL) - if(!new_gender) - return - - visible_message("\The [src]'s form contorts subtly.") - change_gender(new_gender) - -/mob/living/carbon/human/proc/shapeshifter_select_shape() - - set name = "Select Body Shape" - set category = "Abilities" - - if(stat || world.time < last_special) - return - - last_special = world.time + 50 - - var/new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in species.get_valid_shapeshifter_forms(src) - if(!new_species || !get_species_by_key(new_species) || wrapped_species_by_ref["\ref[src]"] == new_species) - return - - wrapped_species_by_ref["\ref[src]"] = new_species - visible_message("\The [src] shifts and contorts, taking the form of \a ["\improper [new_species]"]!") - regenerate_icons() - -/mob/living/carbon/human/proc/shapeshifter_select_colour() - - set name = "Select Body Colour" - set category = "Abilities" - - if(stat || world.time < last_special) - return - - last_special = world.time + 50 - - var/new_skin = input("Please select a new body color.", "Shapeshifter Colour") as color - if(!new_skin) - return - shapeshifter_set_colour(new_skin) - -/mob/living/carbon/human/proc/shapeshifter_set_colour(var/new_skin) - - skin_colour = new_skin - - var/datum/species/shapeshifter/S = species - if(S.monochromatic) - hair_colour = skin_colour - facial_hair_colour = skin_colour - - for(var/obj/item/organ/external/E in organs) - E.sync_colour_to_human(src) - - regenerate_icons() diff --git a/code/modules/species/station/golem.dm b/code/modules/species/station/golem.dm deleted file mode 100644 index 2b2d6e9b03b2..000000000000 --- a/code/modules/species/station/golem.dm +++ /dev/null @@ -1,55 +0,0 @@ -/datum/species/golem - name = SPECIES_GOLEM - name_plural = "Golems" - - icobase = 'icons/mob/human_races/species/golem/body.dmi' - deform = 'icons/mob/human_races/species/golem/body.dmi' - husk_icon = 'icons/mob/human_races/species/golem/husk.dmi' - - unarmed_attacks = list(/decl/natural_attack/stomp, /decl/natural_attack/kick, /decl/natural_attack/punch) - species_flags = SPECIES_FLAG_NO_PAIN | SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_POISON - spawn_flags = SPECIES_IS_RESTRICTED - siemens_coefficient = 0 - - meat_type = null - bone_material = null - skin_material = null - - breath_type = null - poison_types = null - - blood_color = "#515573" - flesh_color = "#137e8f" - - cold_level_1 = SYNTH_COLD_LEVEL_1 - cold_level_2 = SYNTH_COLD_LEVEL_2 - cold_level_3 = SYNTH_COLD_LEVEL_3 - - heat_level_1 = SYNTH_HEAT_LEVEL_1 - heat_level_2 = SYNTH_HEAT_LEVEL_2 - heat_level_3 = SYNTH_HEAT_LEVEL_3 - - has_organ = list( - BP_BRAIN = /obj/item/organ/internal/brain/golem - ) - - death_message = "becomes completely motionless..." - genders = list(NEUTER) - - is_crystalline = TRUE - - force_cultural_info = list( - TAG_CULTURE = CULTURE_CULTIST, - TAG_HOMEWORLD = HOME_SYSTEM_STATELESS, - TAG_FACTION = FACTION_OTHER - ) - -/datum/species/golem/handle_post_spawn(var/mob/living/carbon/human/H) - if(H.mind) - H.mind.reset() - H.mind.assigned_role = "Golem" - H.mind.special_role = "Golem" - H.real_name = "golem ([rand(1, 1000)])" - H.SetName(H.real_name) - H.status_flags |= NO_ANTAG - ..() diff --git a/code/modules/species/station/human.dm b/code/modules/species/station/human.dm new file mode 100644 index 000000000000..d1f3e5323c30 --- /dev/null +++ b/code/modules/species/station/human.dm @@ -0,0 +1,40 @@ +/decl/species/human + uid = "species_human" + name = "Human" + name_plural = "Humans" + primitive_form = /decl/species/monkey::uid + description = "A medium-sized creature prone to great ambition. If you are reading this, you are probably a human." + hidden_from_codex = FALSE + spawn_flags = SPECIES_CAN_JOIN + inherent_verbs = list(/mob/living/human/proc/tie_hair) + + // Add /decl/bodytype/prosthetic/basic_human to this list to allow full-body prosthetics. + available_bodytypes = list( + /decl/bodytype/human, + /decl/bodytype/human/masculine, + /decl/bodytype/prosthetic/basic_human + ) + + exertion_effect_chance = 10 + exertion_hydration_scale = 1 + exertion_charge_scale = 1 + exertion_reagent_scale = 1 + exertion_reagent_path = /decl/material/liquid/lactate + exertion_emotes_biological = list( + /decl/emote/exertion/biological, + /decl/emote/exertion/biological/breath, + /decl/emote/exertion/biological/pant + ) + exertion_emotes_synthetic = list( + /decl/emote/exertion/synthetic, + /decl/emote/exertion/synthetic/creak + ) + +/decl/species/human/get_ssd(var/mob/living/human/H) + if(H.stat == CONSCIOUS) + return "staring blankly, not reacting to your presence" + return ..() + +/decl/species/human/equip_default_fallback_uniform(var/mob/living/human/H) + if(istype(H)) + H.equip_to_slot_or_del(new /obj/item/clothing/jumpsuit/grey, slot_w_uniform_str) diff --git a/code/modules/species/station/human_bodytypes.dm b/code/modules/species/station/human_bodytypes.dm new file mode 100644 index 000000000000..20f450c46dfb --- /dev/null +++ b/code/modules/species/station/human_bodytypes.dm @@ -0,0 +1,31 @@ +/decl/bodytype/human + name = "feminine" + bodytype_category = BODYTYPE_HUMANOID + cosmetics_icon = 'icons/mob/human_races/species/default_cosmetics.dmi' + icon_base = 'icons/mob/human_races/species/human/body_female.dmi' + icon_deformed = 'icons/mob/human_races/species/human/deformed_body_female.dmi' + blood_overlays = 'icons/mob/human_races/species/human/blood_overlays.dmi' + bandages_icon = 'icons/mob/bandage.dmi' + associated_gender = FEMALE + onmob_state_modifiers = list((slot_w_uniform_str) = "f") + appearance_flags = HAS_SKIN_TONE_NORMAL | HAS_UNDERWEAR | HAS_EYE_COLOR + nail_noun = "nails" + uid = "bodytype_human_fem" + +/decl/bodytype/human/masculine + name = "masculine" + icon_base = 'icons/mob/human_races/species/human/body_male.dmi' + icon_deformed = 'icons/mob/human_races/species/human/deformed_body_male.dmi' + associated_gender = MALE + uid = "bodytype_human_masc" + onmob_state_modifiers = null + override_emote_sounds = list( + "cough" = list( + 'sound/voice/emotes/m_cougha.ogg', + 'sound/voice/emotes/m_coughb.ogg', + 'sound/voice/emotes/m_coughc.ogg' + ), + "sneeze" = list( + 'sound/voice/emotes/m_sneeze.ogg' + ) + ) diff --git a/code/modules/species/station/monkey.dm b/code/modules/species/station/monkey.dm index 51894fa7ac44..8b49d6ffabfe 100644 --- a/code/modules/species/station/monkey.dm +++ b/code/modules/species/station/monkey.dm @@ -1,37 +1,26 @@ -/datum/species/monkey - name = SPECIES_MONKEY +/decl/species/monkey + uid = "species_monkey" + name = "Monkey" name_plural = "Monkeys" description = "Ook." codex_description = "Monkeys and other similar creatures tend to be found on science stations and vessels as \ cheap and disposable test subjects. This, naturally, infuriates animal rights groups." hidden_from_codex = FALSE - bodytype = BODYTYPE_MONKEY - icobase = 'icons/mob/human_races/species/monkey/monkey_body.dmi' - deform = 'icons/mob/human_races/species/monkey/monkey_body.dmi' - damage_overlays = 'icons/mob/human_races/species/monkey/damage_overlays.dmi' - damage_mask = 'icons/mob/human_races/species/monkey/damage_mask.dmi' - blood_mask = 'icons/mob/human_races/species/monkey/blood_mask.dmi' + available_bodytypes = list(/decl/bodytype/monkey) + holder_icon = 'icons/mob/human_races/species/monkey/holder.dmi' - greater_form = SPECIES_HUMAN - mob_size = MOB_SIZE_SMALL show_ssd = null - health_hud_intensity = 1.75 gibbed_anim = "gibbed-m" dusted_anim = "dust-m" death_message = "lets out a faint chimper as it collapses and stops moving..." - tail = "chimptail" - unarmed_attacks = list(/decl/natural_attack/bite, /decl/natural_attack/claws, /decl/natural_attack/punch) - inherent_verbs = list(/mob/living/proc/ventcrawl) - hud_type = /datum/hud_data/monkey - meat_type = /obj/item/chems/food/snacks/meat/monkey + species_hud = /datum/hud_data/monkey + butchery_data = /decl/butchery_data/humanoid/monkey rarity_value = 0.1 total_health = 150 - brute_mod = 1.5 - burn_mod = 1.5 spawn_flags = SPECIES_IS_RESTRICTED @@ -41,27 +30,12 @@ pass_flags = PASS_FLAG_TABLE holder_type = /obj/item/holder - override_limb_types = list(BP_HEAD = /obj/item/organ/external/head/no_eyes) - descriptors = list( - /datum/mob_descriptor/height = -2, - /datum/mob_descriptor/build = -2 + force_background_info = list( + /decl/background_category/heritage = /decl/background_detail/heritage/hidden/monkey, + /decl/background_category/homeworld = /decl/background_detail/location/stateless, + /decl/background_category/citizenship = /decl/background_detail/citizenship/stateless, + /decl/background_category/faction = /decl/background_detail/faction/other ) - force_cultural_info = list( - TAG_CULTURE = CULTURE_MONKEY, - TAG_HOMEWORLD = HOME_SYSTEM_STATELESS, - TAG_FACTION = FACTION_OTHER - ) - - ai = /datum/ai/monkey - -/datum/species/monkey/New() - equip_adjust = list( - slot_l_hand_str = list("[NORTH]" = list("x" = 1, "y" = 3), "[EAST]" = list("x" = -3, "y" = 2), "[SOUTH]" = list("x" = -1, "y" = 3), "[WEST]" = list("x" = 3, "y" = 2)), - slot_r_hand_str = list("[NORTH]" = list("x" = -1, "y" = 3), "[EAST]" = list("x" = 3, "y" = 2), "[SOUTH]" = list("x" = 1, "y" = 3), "[WEST]" = list("x" = -3, "y" = 2)), - slot_shoes_str = list("[NORTH]" = list("x" = 0, "y" = 7), "[EAST]" = list("x" = -1, "y" = 7), "[SOUTH]" = list("x" = 0, "y" = 7), "[WEST]" = list("x" = 1, "y" = 7)), - slot_head_str = list("[NORTH]" = list("x" = 0, "y" = 0), "[EAST]" = list("x" = -2, "y" = 0), "[SOUTH]" = list("x" = 0, "y" = 0), "[WEST]" = list("x" = 2, "y" = 0)), - slot_wear_mask_str = list("[NORTH]" = list("x" = 0, "y" = 0), "[EAST]" = list("x" = -1, "y" = 0), "[SOUTH]" = list("x" = 0, "y" = 0), "[WEST]" = list("x" = 1, "y" = 0)) - ) - ..() \ No newline at end of file + ai = /datum/mob_controller/monkey diff --git a/code/modules/species/station/monkey_bodytypes.dm b/code/modules/species/station/monkey_bodytypes.dm new file mode 100644 index 000000000000..b1b22de545cd --- /dev/null +++ b/code/modules/species/station/monkey_bodytypes.dm @@ -0,0 +1,33 @@ +/decl/bodytype/monkey + name = "humanoid" + bodytype_category = BODYTYPE_MONKEY + icon_base = 'icons/mob/human_races/species/monkey/monkey_body.dmi' + blood_overlays = 'icons/mob/human_races/species/monkey/blood_overlays.dmi' + health_hud_intensity = 1.75 + bodytype_flag = BODY_EQUIP_FLAG_MONKEY + eye_icon = null + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/monkey + ) + mob_size = MOB_SIZE_SMALL + nail_noun = "nails" + + appearance_descriptors = list( + /datum/appearance_descriptor/height = 0.6, + /datum/appearance_descriptor/build = 0.6 + ) + uid = "bodytype_monkey" + +/decl/bodytype/monkey/Initialize() + _equip_adjust = list( + (BP_L_HAND) = list("[NORTH]" = list( 1, 3), "[EAST]" = list(-3, 2), "[SOUTH]" = list(-1, 3), "[WEST]" = list( 3, 2)), + (BP_R_HAND) = list("[NORTH]" = list(-1, 3), "[EAST]" = list( 3, 2), "[SOUTH]" = list( 1, 3), "[WEST]" = list(-3, 2)), + (slot_shoes_str) = list("[NORTH]" = list( 0, 7), "[EAST]" = list(-1, 7), "[SOUTH]" = list( 0, 7), "[WEST]" = list( 1, 7)), + (slot_head_str) = list("[NORTH]" = list( 0, 0), "[EAST]" = list(-2, 0), "[SOUTH]" = list( 0, 0), "[WEST]" = list( 2, 0)), + (slot_wear_mask_str) = list("[NORTH]" = list( 0, 0), "[EAST]" = list(-1, 0), "[SOUTH]" = list( 0, 0), "[WEST]" = list( 1, 0)) + ) + . = ..() + +/obj/item/organ/external/tail/monkey + tail_icon = 'icons/mob/human_races/species/monkey/monkey_body.dmi' + tail_blend = null // The monkey tail is already colored. diff --git a/code/modules/species/station/station.dm b/code/modules/species/station/station.dm deleted file mode 100644 index 23b18ad8d01f..000000000000 --- a/code/modules/species/station/station.dm +++ /dev/null @@ -1,34 +0,0 @@ -/datum/species/human - name = SPECIES_HUMAN - name_plural = "Humans" - primitive_form = SPECIES_MONKEY - unarmed_attacks = list(/decl/natural_attack/stomp, /decl/natural_attack/kick, /decl/natural_attack/punch, /decl/natural_attack/bite) - description = "A medium-sized creature prone to great ambition. If you are reading this, you are probably a human." - min_age = 17 - max_age = 100 - hidden_from_codex = FALSE - bandages_icon = 'icons/mob/bandage.dmi' - bodytype = BODYTYPE_HUMANOID - limb_icon_intensity = 0.7 - - spawn_flags = SPECIES_CAN_JOIN - appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_TONE_NORMAL | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR - - sexybits_location = BP_GROIN - - inherent_verbs = list(/mob/living/carbon/human/proc/tie_hair) - - available_cultural_info = list( - TAG_CULTURE = list( - CULTURE_OTHER, - CULTURE_HUMAN - ) - ) - -/datum/species/human/get_root_species_name(var/mob/living/carbon/human/H) - return SPECIES_HUMAN - -/datum/species/human/get_ssd(var/mob/living/carbon/human/H) - if(H.stat == CONSCIOUS) - return "staring blankly, not reacting to your presence" - return ..() diff --git a/code/modules/species/station/utility_frame.dm b/code/modules/species/station/utility_frame.dm deleted file mode 100644 index 1d4850474043..000000000000 --- a/code/modules/species/station/utility_frame.dm +++ /dev/null @@ -1,128 +0,0 @@ -#define SPECIES_FRAME "Utility Frame" - -/datum/species/utility_frame - name = SPECIES_FRAME - name_plural = "Utility Frames" - description = "Simple AI-driven robots are used for many menial or repetitive tasks in human space." - icobase = 'icons/mob/human_races/cyberlimbs/utility/body.dmi' - deform = 'icons/mob/human_races/cyberlimbs/utility/body.dmi' - limb_blend = ICON_MULTIPLY - - min_age = 1 - max_age = 20 - hidden_from_codex = FALSE - bodytype = BODYTYPE_HUMANOID - species_flags = SPECIES_FLAG_NO_PAIN | SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_POISON - spawn_flags = SPECIES_CAN_JOIN - appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR - strength = STR_HIGH - warning_low_pressure = 50 - hazard_low_pressure = -1 - blood_color = COLOR_GRAY15 - flesh_color = COLOR_GUNMETAL - base_color = COLOR_GUNMETAL - cold_level_1 = SYNTH_COLD_LEVEL_1 - cold_level_2 = SYNTH_COLD_LEVEL_2 - cold_level_3 = SYNTH_COLD_LEVEL_3 - heat_level_1 = SYNTH_HEAT_LEVEL_1 - heat_level_2 = SYNTH_HEAT_LEVEL_2 - heat_level_3 = SYNTH_HEAT_LEVEL_3 - body_temperature = null - passive_temp_gain = 5 // stabilize at ~80 C in a 20 C environment. - heat_discomfort_level = 373.15 - - heat_discomfort_strings = list( - "You are dangerously close to overheating!" - ) - unarmed_attacks = list( - /decl/natural_attack/stomp, - /decl/natural_attack/kick, - /decl/natural_attack/punch - ) - genders = list( - NEUTER, - PLURAL - ) - available_cultural_info = list( - TAG_CULTURE = list(CULTURE_OTHER) - ) - has_organ = list( - BP_POSIBRAIN = /obj/item/organ/internal/posibrain, - BP_EYES = /obj/item/organ/internal/eyes/robot - ) - -/datum/species/utility_frame/post_organ_rejuvenate(obj/item/organ/org, mob/living/carbon/human/H) - var/obj/item/organ/external/E = org - if(istype(E) && !BP_IS_PROSTHETIC(E)) - E.robotize(SPECIES_FRAME) - var/obj/item/organ/external/head/head = H.organs_by_name[BP_HEAD] - if(istype(head)) - head.glowing_eyes = TRUE - var/obj/item/organ/internal/eyes/eyes = H.internal_organs_by_name[vision_organ || BP_EYES] - if(istype(eyes)) - eyes.eye_icon = 'icons/mob/human_races/cyberlimbs/utility/eyes.dmi' - H.regenerate_icons() - -/datum/species/utility_frame/handle_post_species_pref_set(var/datum/preferences/pref) - if(pref) - LAZYINITLIST(pref.body_markings) - for(var/marking in list("Frame Body Plating", "Frame Leg Plating", "Frame Head Plating")) - if(!pref.body_markings[marking]) - pref.body_markings[marking] = "#8888cc" - pref.skin_colour = "#333355" - pref.eye_colour = "#00ccff" - -/datum/species/utility_frame/get_blood_name() - . = "coolant" - -/datum/species/utility_frame/disfigure_msg(var/mob/living/carbon/human/H) - . = SPAN_DANGER("The faceplate is dented and cracked!\n") - -/datum/robolimb/utility_frame - company = SPECIES_FRAME - desc = "This limb is extremely cheap and simplistic, with a raw steel frame and plastic casing." - icon = 'icons/mob/human_races/cyberlimbs/utility/body.dmi' - skintone = TRUE - species_restricted = list(SPECIES_FRAME) - limb_blend = ICON_MULTIPLY - -/datum/sprite_accessory/marking/frame - name = "Frame Department Stripe" - icon_state = "single_stripe" - body_parts = list(BP_CHEST) - species_allowed = list(SPECIES_FRAME) - icon = 'icons/mob/human_races/cyberlimbs/utility/markings.dmi' - blend = ICON_MULTIPLY - -/datum/sprite_accessory/marking/frame/head_stripe - name = "Frame Head Stripe" - icon_state = "head_stripe" - body_parts = list(BP_HEAD) - -/datum/sprite_accessory/marking/frame/double_stripe - name = "Frame Department Stripes" - icon_state = "double_stripe" - -/datum/sprite_accessory/marking/frame/shoulder_stripe - name = "Frame Shoulder Markings" - icon_state = "shoulder_stripe" - -/datum/sprite_accessory/marking/frame/plating - name = "Frame Body Plating" - icon_state = "plating" - body_parts = list(BP_GROIN, BP_CHEST) - -/datum/sprite_accessory/marking/frame/barcode - name = "Frame Matrix Barcode" - icon_state = "barcode" - body_parts = list(BP_CHEST) - -/datum/sprite_accessory/marking/frame/plating/legs - name = "Frame Leg Plating" - body_parts = list(BP_L_LEG, BP_R_LEG) - -/datum/sprite_accessory/marking/frame/plating/head - name = "Frame Head Plating" - body_parts = list(BP_HEAD) - -#undef SPECIES_FRAME \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/aoe_turf.dm b/code/modules/spells/aoe_turf/aoe_turf.dm deleted file mode 100644 index 9f79f694ad84..000000000000 --- a/code/modules/spells/aoe_turf/aoe_turf.dm +++ /dev/null @@ -1,25 +0,0 @@ -/* -Aoe turf spells target a ring of tiles around the user -This ring has an outer radius (range) and an inner radius (inner_radius) -Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm -*/ - -/spell/aoe_turf //affects all turfs in view or range (depends) - spell_flags = IGNOREDENSE - var/inner_radius = -1 //for all your ring spell needs - -/spell/aoe_turf/choose_targets(mob/user = usr) - var/list/targets = list() - - for(var/turf/target in view_or_range(range, holder, selection_type)) - if(!(target in view_or_range(inner_radius, holder, selection_type))) - if(target.density && (spell_flags & IGNOREDENSE)) - continue - if(istype(target, /turf/space) && (spell_flags & IGNORESPACE)) - continue - targets += target - - if(!targets.len) //doesn't waste the spell - return - - return targets \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/blink.dm b/code/modules/spells/aoe_turf/blink.dm deleted file mode 100644 index 3fd742aec243..000000000000 --- a/code/modules/spells/aoe_turf/blink.dm +++ /dev/null @@ -1,44 +0,0 @@ -/spell/aoe_turf/blink - name = "Blink" - desc = "This spell randomly teleports you a short distance." - feedback = "BL" - school = "conjuration" - charge_max = 20 - spell_flags = Z2NOCAST | IGNOREDENSE | IGNORESPACE - invocation = "none" - invocation_type = SpI_NONE - range = 7 - inner_radius = 1 - - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 4) - cooldown_min = 5 //4 deciseconds reduction per rank - hud_state = "wiz_blink" - cast_sound = 'sound/magic/blink.ogg' - -/spell/aoe_turf/blink/cast(var/list/targets, mob/user) - if(!targets.len) - return - - var/turf/T = pick(targets) - var/turf/starting = get_turf(user) - if(T) - if(user.buckled) - user.buckled = null - user.forceMove(T) - - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(3, 0, starting) - smoke.start() - - smoke = new() - smoke.set_up(3, 0, T) - smoke.start() - - return - -/spell/aoe_turf/blink/empower_spell() - if(!..()) - return 0 - inner_radius += 1 - - return "You've increased the inner range of [src]." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/charge.dm b/code/modules/spells/aoe_turf/charge.dm deleted file mode 100644 index 4e45ca627b88..000000000000 --- a/code/modules/spells/aoe_turf/charge.dm +++ /dev/null @@ -1,73 +0,0 @@ -/spell/aoe_turf/charge - name = "Charge" - desc = "This spell can be used to charge up spent magical artifacts, among other things." - - school = "transmutation" - charge_max = 600 - spell_flags = 0 - invocation = "DIRI CEL" - invocation_type = SpI_WHISPER - range = 0 - cooldown_min = 400 //50 deciseconds reduction per rank - - hud_state = "wiz_charge" - cast_sound = 'sound/magic/charge.ogg' - -/spell/aoe_turf/charge/cast(var/list/targets, mob/user) - for(var/turf/T in targets) - depth_cast(T) - -/spell/aoe_turf/charge/proc/depth_cast(var/list/targets) - for(var/atom/A in targets) - if(A.contents.len) - depth_cast(A.contents) - cast_charge(A) - -/spell/aoe_turf/charge/proc/mob_charge(var/mob/living/M) - if(!M.mind) - return - if(M.mind.learned_spells.len != 0) - for(var/spell/S in M.mind.learned_spells) - if(!istype(S, /spell/aoe_turf/charge)) - S.charge_counter = S.charge_max - to_chat(M, "You feel raw magic flowing through you, it feels good!") - else - to_chat(M, "You feel very strange for a moment, but then it passes.") - return M - -/spell/aoe_turf/charge/proc/cast_charge(var/atom/target) - var/atom/charged_item - - if(istype(target, /mob/living)) - charged_item = mob_charge(target) - - if(istype(target, /obj/item/grab)) - var/obj/item/grab/G = target - if(G.affecting) - var/mob/M = G.get_affecting_mob() - if(M) - charged_item = mob_charge(M) - - if(istype(target, /obj/item/cell/)) - var/obj/item/cell/C = target - if(prob(80) && C.maxcharge) - C.maxcharge -= 200 - if(C.maxcharge <= 0) //maxcharge of 0! Madness! - C.maxcharge = 0 - C.charge = C.maxcharge - charged_item = C - - if(!charged_item) - return 0 - else - charged_item.visible_message("[charged_item] suddenly sparks with energy!") - return 1 - - -/spell/aoe_turf/charge/blood - name = "blood charge" - desc = "This spell charges things around it using the lifeforce gained by sacrificed blood." - - charge_type = Sp_HOLDVAR - holder_var_type = "bruteloss" - holder_var_amount = 30 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/conjure.dm b/code/modules/spells/aoe_turf/conjure/conjure.dm deleted file mode 100644 index aa395ae9854e..000000000000 --- a/code/modules/spells/aoe_turf/conjure/conjure.dm +++ /dev/null @@ -1,74 +0,0 @@ -/* -Conjure spells spawn things (mobs, objs, turfs) in their summon_type -How they spawn stuff is decided by behaviour vars, which are explained below -*/ - -/spell/aoe_turf/conjure - name = "Conjure" - desc = "This spell conjures objs of the specified types in range." - - school = "conjuration" //funny, that - - var/list/summon_type = list() //determines what exactly will be summoned - //should NOT be text, like list(/obj/machinery/bot/ed209) - - range = 0 //default values: only spawn on the player tile - selection_type = "view" - - duration = 0 // 0=permanent, any other time in deciseconds - how long the summoned objects last for - var/summon_amt = 1 //amount of objects summoned - var/summon_exclusive = 0 //spawn one of everything, instead of random things - - var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet - //should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example - - cast_sound = 'sound/magic/castsummon.ogg' - -/spell/aoe_turf/conjure/cast(list/targets, mob/user) - - for(var/i=1,i <= summon_amt,i++) - if(!targets.len) - break - var/summoned_object_type - if(summon_exclusive) - if(!summon_type.len) - break - summoned_object_type = summon_type[1] - summon_type -= summoned_object_type - else - summoned_object_type = pick(summon_type) - var/turf/spawn_place = pick(targets) - if(spell_flags & IGNOREPREV) - targets -= spawn_place - - var/atom/summoned_object - if(ispath(summoned_object_type,/turf)) - if(istype(get_turf(user),/turf/simulated/shuttle) || istype(spawn_place, /turf/simulated/shuttle)) - to_chat(user, "You can't build things on shuttles!") - continue - spawn_place.ChangeTurf(summoned_object_type) - summoned_object = spawn_place - else - summoned_object = new summoned_object_type(spawn_place) - var/atom/movable/overlay/animation = new /atom/movable/overlay(summoned_object) - animation.SetName("conjure") - animation.set_density(0) - animation.anchored = 1 - animation.icon = 'icons/effects/effects.dmi' - animation.layer = BASE_HUMAN_LAYER - if(istype(summoned_object,/mob)) //we want them to NOT attack us. - var/mob/M = summoned_object - M.faction = user.faction - for(var/varName in newVars) - if(varName in summoned_object.vars) - summoned_object.vars[varName] = newVars[varName] - - if(duration) - spawn(duration) - if(summoned_object && !istype(summoned_object, /turf)) - qdel(summoned_object) - conjure_animation(animation, spawn_place) - return - -/spell/aoe_turf/conjure/proc/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) - qdel(animation) \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/construct.dm b/code/modules/spells/aoe_turf/conjure/construct.dm deleted file mode 100644 index 193479154bec..000000000000 --- a/code/modules/spells/aoe_turf/conjure/construct.dm +++ /dev/null @@ -1,122 +0,0 @@ -//////////////////////////////Construct Spells///////////////////////// - -/spell/aoe_turf/conjure/construct - name = "Artificer" - desc = "This spell conjures a construct which may be controlled by Shades." - - school = "conjuration" - charge_max = 600 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 - - summon_type = list(/obj/structure/constructshell) - - hud_state = "artificer" - -/spell/aoe_turf/conjure/construct/lesser - charge_max = 1800 - summon_type = list(/obj/structure/constructshell/cult) - hud_state = "const_shell" - override_base = "const" - -/spell/aoe_turf/conjure/floor - name = "Floor Construction" - desc = "This spell constructs a cult floor" - - charge_max = 20 - spell_flags = Z2NOCAST | CONSTRUCT_CHECK - invocation = "none" - invocation_type = SpI_NONE - range = 0 - summon_type = list(/turf/simulated/floor/cult) - - hud_state = "const_floor" - -/spell/aoe_turf/conjure/wall - name = "Lesser Construction" - desc = "This spell constructs a cult wall" - - charge_max = 100 - spell_flags = Z2NOCAST | CONSTRUCT_CHECK - invocation = "none" - invocation_type = SpI_NONE - range = 0 - summon_type = list(/turf/simulated/wall/cult) - - hud_state = "const_wall" - -/spell/aoe_turf/conjure/wall/reinforced - name = "Greater Construction" - desc = "This spell constructs a reinforced metal wall" - - charge_max = 300 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - range = 0 - cast_delay = 50 - - summon_type = list(/turf/simulated/wall/r_wall) - -/spell/aoe_turf/conjure/soulstone - name = "Summon Soulstone" - desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space" - - charge_max = 3000 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 - - summon_type = list(/obj/item/soulstone) - - hud_state = "const_stone" - override_base = "const" - -/spell/aoe_turf/conjure/pylon - name = "Red Pylon" - desc = "This spell conjures a fragile crystal from Nar-Sie's realm. Makes for a convenient light source." - - charge_max = 200 - spell_flags = CONSTRUCT_CHECK - invocation = "none" - invocation_type = SpI_NONE - range = 0 - - summon_type = list(/obj/structure/cult/pylon) - - hud_state = "const_pylon" - -/spell/aoe_turf/conjure/pylon/cast(list/targets) - ..() - var/turf/spawn_place = pick(targets) - for(var/obj/structure/cult/pylon/P in spawn_place.contents) - if(P.isbroken) - P.repair(usr) - continue - return - -/spell/aoe_turf/conjure/forcewall/lesser - name = "Shield" - desc = "Allows you to pull up a shield to protect yourself and allies from incoming threats" - - charge_max = 300 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 - summon_type = list(/obj/effect/forcefield/cult) - duration = 200 - - hud_state = "const_juggwall" - -//Code for the Juggernaut construct's forcefield, that seemed like a good place to put it. -/obj/effect/forcefield/cult - desc = "That eerie looking obstacle seems to have been pulled from another dimension through sheer force." - name = "Juggerwall" - icon = 'icons/effects/effects.dmi' - icon_state = "m_shield_cult" - light_color = "#b40000" - light_outer_range = 2 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm b/code/modules/spells/aoe_turf/conjure/druidic_spells.dm deleted file mode 100644 index 70a37798f3fa..000000000000 --- a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm +++ /dev/null @@ -1,109 +0,0 @@ -/spell/aoe_turf/conjure/summon - var/name_summon = 0 - cast_sound = 'sound/weapons/wave.ogg' - -/spell/aoe_turf/conjure/summon/before_cast() - ..() - if(name_summon) - var/newName = sanitize(input("Would you like to name your summon?") as null|text, MAX_NAME_LEN) - if(newName) - newVars["name"] = newName - -/spell/aoe_turf/conjure/summon/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) - animation.icon_state = "shield2" - flick("shield2",animation) - sleep(10) - ..() - - -/spell/aoe_turf/conjure/summon/bats - name = "Summon Space Bats" - desc = "This spell summons a flock of spooky space bats." - feedback = "SB" - - charge_max = 1200 //2 minutes - spell_flags = NEEDSCLOTHES - invocation = "Bla'yo daya!" - invocation_type = SpI_SHOUT - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3) - cooldown_min = 600 - - range = 1 - - summon_amt = 1 - summon_type = list(/mob/living/simple_animal/hostile/scarybat) - - hud_state = "wiz_bats" - -/spell/aoe_turf/conjure/summon/bats/empower_spell() - if(!..()) - return 0 - - newVars = list("maxHealth" = 20 + spell_levels[Sp_POWER]*5, "health" = 20 + spell_levels[Sp_POWER]*5, "melee_damage_lower" = 10 + spell_levels[Sp_POWER], "melee_damage_upper" = 10 + spell_levels[Sp_POWER]*2) - - return "Your bats are now stronger." - -/spell/aoe_turf/conjure/summon/bear - name = "Summon Bear" - desc = "This spell summons a permanent bear companion that will follow your orders." - feedback = "BR" - charge_max = 3000 //5 minutes because this is a REALLY powerful spell. May tone it down/up. - spell_flags = NEEDSCLOTHES - invocation = "REA'YO GOR DAYA!" - invocation_type = SpI_SHOUT - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 0, Sp_POWER = 4) - - range = 0 - - name_summon = 1 - - summon_amt = 1 - summon_type = list(/mob/living/simple_animal/hostile/commanded/bear) - newVars = list("maxHealth" = 15, - "health" = 15, - "melee_damage_lower" = 10, - "melee_damage_upper" = 10, - ) - - hud_state = "wiz_bear" - -/spell/aoe_turf/conjure/summon/bear/before_cast() - ..() - newVars["master"] = holder //why not do this in the beginning? MIND SWITCHING. - -/spell/aoe_turf/conjure/summon/bear/empower_spell() - if(!..()) - return 0 - switch(spell_levels[Sp_POWER]) - if(1) - newVars = list("maxHealth" = 30, - "health" = 30, - "melee_damage_lower" = 15, - "melee_damage_upper" = 15 - ) - return "Your bear has been upgraded from a cub to a whelp." - if(2) - newVars = list("maxHealth" = 45, - "health" = 45, - "melee_damage_lower" = 20, - "melee_damage_upper" = 20, - "color" = "#d9d9d9" //basically we want them to look different enough that people can recognize it. - ) - return "Your bear has been upgraded from a whelp to an adult." - if(3) - newVars = list("maxHealth" = 60, - "health" = 60, - "melee_damage_lower" = 25, - "melee_damage_upper" = 25, - "color" = "#8c8c8c" - ) - return "Your bear has been upgraded from an adult to an alpha." - if(4) - newVars = list("maxHealth" = 75, - "health" = 75, - "melee_damage_lower" = 35, - "melee_damage_upper" = 35, - "resistance" = 3, - "color" = "#0099ff" - ) - return "Your bear is now worshiped as a god amongst bears." \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/faithful_hound.dm b/code/modules/spells/aoe_turf/conjure/faithful_hound.dm deleted file mode 100644 index d836f9a8a46f..000000000000 --- a/code/modules/spells/aoe_turf/conjure/faithful_hound.dm +++ /dev/null @@ -1,23 +0,0 @@ -/spell/aoe_turf/conjure/faithful_hound - name = "Faithful Hound" - desc = "Summon a spectral watchdog with a special password. Anyone without the password is in for a barking and a biting." - feedback = "FH" - - charge_max = 600 - spell_flags = NEEDSCLOTHES - invocation = "Du korilath tangus" - invocation_type = SpI_WHISPER - range = 0 - - summon_amt = 1 - summon_type = list(/mob/living/simple_animal/faithful_hound) - hud_state = "wiz_hound" - -/spell/aoe_turf/conjure/faithful_hound/before_cast() - ..() - var/password = sanitize(input("What password will this beast listen to?") as text, MAX_NAME_LEN) - newVars = list("password" = password, "allowed_mobs" = list(usr)) - -/spell/aoe_turf/conjure/faithful_hound/tower - charge_max = 1 - spell_flags = 0 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/force_portal.dm b/code/modules/spells/aoe_turf/conjure/force_portal.dm deleted file mode 100644 index 1bf7d7f075e4..000000000000 --- a/code/modules/spells/aoe_turf/conjure/force_portal.dm +++ /dev/null @@ -1,16 +0,0 @@ -/spell/aoe_turf/conjure/force_portal - name = "Force Portal" - desc = "Create a portal that sucks in anything that touches it and then shoots it all out at the end.." - school = "conjuration" - feedback = "FP" - summon_type = list(/obj/effect/force_portal) - charge_max = 200 - spell_flags = NEEDSCLOTHES - range = 0 - cast_sound = null - - hud_state = "wiz_force" - -/spell/aoe_turf/conjure/force_portal/tower - charge_max = 2 - spell_flags = 0 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/forcewall.dm b/code/modules/spells/aoe_turf/conjure/forcewall.dm deleted file mode 100644 index dd63217840c5..000000000000 --- a/code/modules/spells/aoe_turf/conjure/forcewall.dm +++ /dev/null @@ -1,52 +0,0 @@ -/spell/aoe_turf/conjure/forcewall - name = "Forcewall" - desc = "Create a wall of pure energy at your location." - school = "conjuration" - feedback = "FW" - summon_type = list(/obj/effect/forcefield) - duration = 300 - charge_max = 100 - spell_flags = 0 - range = 0 - cast_sound = 'sound/magic/forcewall.ogg' - - hud_state = "wiz_shield" - -/spell/aoe_turf/conjure/forcewall/mime - name = "Invisible wall" - desc = "Create an invisible wall on your location." - school = "mime" - panel = "Mime" - summon_type = list(/obj/effect/forcefield/mime) - invocation_type = SpI_EMOTE - invocation = "mimes placing their hands on a flat surfacing, and pushing against it." - charge_max = 300 - cast_sound = null - - override_base = "grey" - hud_state = "mime_wall" - -/obj/effect/forcefield - desc = "A space wizard's magic wall." - name = "FORCEWALL" - icon = 'icons/effects/effects.dmi' - icon_state = "m_shield" - anchored = 1.0 - opacity = 0 - density = 1 - unacidable = 1 - -/obj/effect/forcefield/bullet_act(var/obj/item/projectile/Proj, var/def_zone) - var/turf/T = get_turf(src.loc) - if(T) - for(var/mob/M in T) - Proj.on_hit(M,M.bullet_act(Proj, def_zone)) - return - -/obj/effect/forcefield/mime - icon_state = "empty" - name = "invisible wall" - desc = "You have a bad feeling about this." - -/spell/aoe_turf/conjure/forcewall/tower - charge_max = 3 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/conjure/grove.dm b/code/modules/spells/aoe_turf/conjure/grove.dm deleted file mode 100644 index a2c2e1f5ade2..000000000000 --- a/code/modules/spells/aoe_turf/conjure/grove.dm +++ /dev/null @@ -1,75 +0,0 @@ -/spell/aoe_turf/conjure/grove - name = "Grove" - desc = "Creates a sanctuary of nature around the wizard as well as creating a healing plant." - - spell_flags = IGNOREDENSE | IGNORESPACE | NEEDSCLOTHES | Z2NOCAST | IGNOREPREV - charge_max = 1200 - school = "transmutation" - - range = 1 - cooldown_min = 600 - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 1) - - summon_amt = 47 - summon_type = list(/turf/simulated/floor/grass) - var/spread = 0 - var/datum/seed/seed - var/seed_type = /datum/seed/merlin_tear - cast_sound = 'sound/magic/repulse.ogg' - -/spell/aoe_turf/conjure/grove/New() - ..() - if(seed_type) - seed = new seed_type() - else - seed = SSplants.create_random_seed(1) - -/spell/aoe_turf/conjure/grove/before_cast() - var/turf/T = get_turf(holder) - var/obj/effect/vine/P = new(T,seed) - P.spread_chance = spread - - -/spell/aoe_turf/conjure/grove/sanctuary - name = "Sanctuary" - desc = "Creates a sanctuary of nature around the wizard as well as creating a healing plant." - feedback = "SY" - invocation = "Bo K'Iitan!" - invocation_type = SpI_SHOUT - spell_flags = IGNOREDENSE | IGNORESPACE | NEEDSCLOTHES | Z2NOCAST | IGNOREPREV - cooldown_min = 600 - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 1) - - seed_type = /datum/seed/merlin_tear - newVars = list("name" = "sanctuary", "desc" = "This grass makes you feel comfortable. Peaceful.","blessed" = 1) - - hud_state = "wiz_grove" -/spell/aoe_turf/conjure/grove/sanctuary/empower_spell() - if(!..()) - return 0 - - seed.set_trait(TRAIT_SPREAD,2) //make it grow. - spread = 40 - return "Your sanctuary will now grow beyond that of the grassy perimeter." - -/datum/seed/merlin_tear - name = "merlin tears" - seed_name = "merlin tears" - display_name = "merlin tears" - chems = list(/decl/material/liquid/brute_meds = list(3,7), /decl/material/liquid/burn_meds = list(3,7), /decl/material/liquid/antitoxins = list(3,7), /decl/material/liquid/regenerator = list(3,7), /decl/material/liquid/neuroannealer = list(1,2), /decl/material/liquid/eyedrops = list(1,2)) - kitchen_tag = "berries" - -/datum/seed/merlin_tear/New() - ..() - set_trait(TRAIT_PLANT_ICON,"bush5") - set_trait(TRAIT_PRODUCT_ICON,"berry") - set_trait(TRAIT_PRODUCT_COLOUR,"#4d4dff") - set_trait(TRAIT_PLANT_COLOUR, "#ff6600") - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_IMMUTABLE,1) //no making op plants pls \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/disable_tech.dm b/code/modules/spells/aoe_turf/disable_tech.dm deleted file mode 100644 index 636a8c1c8652..000000000000 --- a/code/modules/spells/aoe_turf/disable_tech.dm +++ /dev/null @@ -1,37 +0,0 @@ -/spell/aoe_turf/disable_tech - name = "Disable Tech" - desc = "This spell disables all weapons, cameras and most other technology in range." - feedback = "DT" - charge_max = 400 - spell_flags = NEEDSCLOTHES - invocation = "NEC CANTIO" - invocation_type = SpI_SHOUT - selection_type = "range" - range = 0 - inner_radius = -1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) - cooldown_min = 200 //50 deciseconds reduction per rank - - var/emp_heavy = 3 - var/emp_light = 5 - - hud_state = "wiz_tech" - cast_sound = 'sound/magic/disable_tech.ogg' - -/spell/aoe_turf/disable_tech/cast(list/targets) - - for(var/turf/target in targets) - empulse(get_turf(target), emp_heavy, emp_light) - return - -/spell/aoe_turf/disable_tech/empower_spell() - if(!..()) - return 0 - emp_heavy += 2 - emp_light += 2 - - return "You've increased the range of [src]." - -/spell/aoe_turf/disable_tech/starlight - charge_max = 600 - spell_flags = 0 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/drain_blood.dm b/code/modules/spells/aoe_turf/drain_blood.dm deleted file mode 100644 index e02026b469c5..000000000000 --- a/code/modules/spells/aoe_turf/drain_blood.dm +++ /dev/null @@ -1,66 +0,0 @@ -/spell/aoe_turf/drain_blood - name = "Drain Blood" - desc = "this spell allows the caster to borrow blood from those around them. Sharing is caring!" - feedback = "DB" - school = "transmutation" - charge_max = 600 - invocation = "whispers something darkly" - invocation_type = SpI_EMOTE - range = 3 - inner_radius = 0 - - time_between_channels = 100 - number_of_channels = 3 - cast_sound = 'sound/effects/squelch2.ogg' - hud_state = "const_rune" - -/spell/aoe_turf/drain_blood/cast(var/list/targets, var/mob/user) - for(var/t in targets) - for(var/mob/living/L in t) - if(L.stat == DEAD || L == user) - continue - //Hurt target - if(istype(L, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = L - H.vessel.remove_any(10) - else - L.adjustBruteLoss(10) - to_chat(L, "You feel your lifeforce being ripping out of your body!") - - //Do effect - var/obj/item/projectile/beam/blood_effect/effect = new(get_turf(user)) - effect.pixel_x = 0 - effect.pixel_y = 0 - effect.launch(L, "chest") - - //Heal self - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - var/amount = min(10, H.species.blood_volume - H.vessel.total_volume) - if(amount > 0) - H.vessel.add_reagent(H.species.blood_reagent, amount) - continue - L.adjustBruteLoss(-5) - L.adjustFireLoss(-2.5) - L.adjustToxLoss(-2.5) - -/obj/item/projectile/beam/blood_effect - name = "blood jet" - icon_state = "blood" - damage = 0 - randpixel = 0 - no_attack_log = 1 - muzzle_type = /obj/effect/projectile/blood - tracer_type = /obj/effect/projectile/blood - impact_type = /obj/effect/projectile/blood - -/obj/item/projectile/beam/blood_effect/Bump(var/atom/a, forced=0) - if(a == original) - on_impact(a) - qdel(src) - return 1 - return 0 - - -/obj/effect/projectile/blood - icon_state = "blood" \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/exchange_wounds.dm b/code/modules/spells/aoe_turf/exchange_wounds.dm deleted file mode 100644 index 06a0becfff88..000000000000 --- a/code/modules/spells/aoe_turf/exchange_wounds.dm +++ /dev/null @@ -1,43 +0,0 @@ -/spell/aoe_turf/exchange_wounds - name = "Exchange Wounds" - desc = "Syphon the wounds from your allies." - feedback = "EW" - school = "transmutation" - invocation = "Esh Yek Vai!" - invocation_type = SpI_SHOUT - charge_max = 400 - spell_flags = 0 - - var/amt_healed = 0 - var/heal_max = 100 - range = 4 - inner_radius = 0 - number_of_channels = 0 - time_between_channels = 20 - - hud_state = "wiz_exchange" - -/spell/aoe_turf/exchange_wounds/perform() - amt_healed = 0 - ..() - -/spell/aoe_turf/exchange_wounds/cast(var/list/targets, var/mob/living/user) - new /obj/effect/temporary(get_turf(user),10,'icons/effects/effects.dmi',"purple_electricity_constant") - for(var/t in targets) - for(var/mob/living/L in t) - if(L.faction != user.faction) - continue - new /obj/effect/temporary(get_turf(L),10,'icons/effects/effects.dmi',"green_sparkles") - if(L.getBruteLoss() > 5) - L.adjustBruteLoss(-5) - user.adjustBruteLoss(2) - amt_healed += 5 - if(L.getFireLoss() > 5) - L.adjustFireLoss(-5) - user.adjustFireLoss(2) - amt_healed += 5 - -/spell/aoe_turf/exchange_wounds/check_valid_targets() - if(amt_healed > heal_max) - return FALSE - return ..() \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/knock.dm b/code/modules/spells/aoe_turf/knock.dm deleted file mode 100644 index 6e7f723af27a..000000000000 --- a/code/modules/spells/aoe_turf/knock.dm +++ /dev/null @@ -1,40 +0,0 @@ -/spell/aoe_turf/knock - name = "Knock" - desc = "This spell opens nearby doors and does not require wizard garb." - feedback = "KN" - school = "transmutation" - charge_max = 100 - spell_flags = 0 - invocation = "Aulie Oxin Fiera." - invocation_type = SpI_WHISPER - range = 3 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) - cooldown_min = 20 //20 deciseconds reduction per rank - - hud_state = "wiz_knock" - cast_sound = 'sound/magic/knock.ogg' - -/spell/aoe_turf/knock/cast(list/targets) - for(var/turf/T in targets) - for(var/obj/machinery/door/door in T.contents) - spawn(1) - if(istype(door,/obj/machinery/door/airlock)) - var/obj/machinery/door/airlock/AL = door //casting is important - AL.locked = 0 - door.open() - return - - -/spell/aoe_turf/knock/empower_spell() - if(!..()) - return 0 - range *= 2 - - return "You've doubled the range of [src]." - -/spell/aoe_turf/knock/slow - name = "Slow Knock" - charge_max = 200 - -/spell/aoe_turf/knock/tower - charge_max = 2 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/smoke.dm b/code/modules/spells/aoe_turf/smoke.dm deleted file mode 100644 index d9b474d539f0..000000000000 --- a/code/modules/spells/aoe_turf/smoke.dm +++ /dev/null @@ -1,29 +0,0 @@ -/spell/aoe_turf/smoke - name = "Smoke" - desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb." - feedback = "SM" - school = "transmutation" - charge_max = 120 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 1 - inner_radius = -1 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 2) - cooldown_min = 20 //25 deciseconds reduction per rank - - smoke_spread = 2 - smoke_amt = 5 - - hud_state = "wiz_smoke" - cast_sound = 'sound/magic/smoke.ogg' - -/spell/aoe_turf/smoke/empower_spell() - if(!..()) - return 0 - smoke_amt += 2 - - return "[src] will now create more smoke." - -/spell/aoe_turf/smoke/tower - charge_max = 2 \ No newline at end of file diff --git a/code/modules/spells/aoe_turf/summons.dm b/code/modules/spells/aoe_turf/summons.dm deleted file mode 100644 index be61819d9eab..000000000000 --- a/code/modules/spells/aoe_turf/summons.dm +++ /dev/null @@ -1,72 +0,0 @@ -/spell/aoe_turf/conjure/summonEdSwarm //test purposes - name = "Dispense Wizard Justice" - desc = "This spell dispenses wizard justice." - - summon_type = list(/mob/living/bot/secbot/ed209) - summon_amt = 10 - range = 3 - newVars = list("emagged" = 1,"name" = "Wizard's Justicebot") - - hud_state = "wiz_ed" - -/spell/aoe_turf/conjure/carp - name = "Summon Carp" - desc = "This spell conjures a simple carp." - - school = "conjuration" - charge_max = 1200 - spell_flags = NEEDSCLOTHES - invocation = "Nouk Fhumm Sacp Risska!" - invocation_type = SpI_SHOUT - range = 1 - cast_sound = 'sound/magic/summon_carp.ogg' - - summon_type = list(/mob/living/simple_animal/hostile/carp) - - hud_state = "wiz_carp" - -/spell/aoe_turf/conjure/creature - name = "Summon Creature Swarm" - desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth" - - school = "conjuration" - charge_max = 1200 - spell_flags = 0 - invocation = "Ia-Ia! Naomesnalia!" - invocation_type = SpI_SHOUT - summon_amt = 10 - range = 3 - - summon_type = list(/mob/living/simple_animal/hostile/creature) - - hud_state = "wiz_creature" - -/spell/aoe_turf/conjure/mirage - name = "Summon Mirage" - desc = "This spell summons a harmless carp mirage for a few seconds." - feedback = "MR" - school = "illusion" - charge_max = 1200 - spell_flags = NEEDSCLOTHES - invocation = "Nouk Fhunhm Sacp Risska!" - invocation_type = SpI_SHOUT - range = 1 - cast_sound = 'sound/magic/summon_carp.ogg' - - duration = 600 - cooldown_min = 600 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 2, Sp_POWER = 3) - - summon_type = list(/mob/living/simple_animal/hostile/carp) - - hud_state = "wiz_carp" - - newVars = list("melee_damage_lower" = 0, "melee_damage_upper" = 0, "break_stuff_probability" = 0) - -/spell/aoe_turf/conjure/mirage/empower_spell() - if(!..()) - return 0 - - summon_amt++ - - return "You now summon [summon_amt] mirages per spellcast." \ No newline at end of file diff --git a/code/modules/spells/artifacts.dm b/code/modules/spells/artifacts.dm deleted file mode 100644 index 8b3e91274111..000000000000 --- a/code/modules/spells/artifacts.dm +++ /dev/null @@ -1,38 +0,0 @@ -//////////////////////Scrying orb////////////////////// - -/obj/item/scrying - name = "scrying orb" - desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means." - icon = 'icons/obj/projectiles.dmi' - icon_state = "bluespace" - throw_speed = 3 - throw_range = 7 - throwforce = 10 - damtype = BURN - force = 10 - hitsound = 'sound/magic/forcewall.ogg' - -/obj/item/scrying/attack_self(mob/user) - if((user.mind && !GLOB.wizards.is_antagonist(user.mind))) - to_chat(user, "You stare into the orb and see nothing but your own reflection.") - return - - to_chat(user, "You can see... everything!") // This never actually happens. - visible_message("[user] stares into [src], their eyes glazing over.") - - user.teleop = user.ghostize(1) - announce_ghost_joinleave(user.teleop, 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.") - return - - - -/////////////////////////Cursed Dice/////////////////////////// -/obj/item/dice/d20/cursed - desc = "A dice with twenty sides said to have an ill effect on those that are unlucky..." - -/obj/item/dice/d20/cursed/attack_self(mob/living/user) - ..() - if(icon_state == "[name][sides]") - user.adjustBruteLoss(-30) - else if(icon_state == "[name]1") - user.adjustBruteLoss(30) \ No newline at end of file diff --git a/code/modules/spells/artifacts/spellbound_servants.dm b/code/modules/spells/artifacts/spellbound_servants.dm deleted file mode 100644 index ee172f5f2020..000000000000 --- a/code/modules/spells/artifacts/spellbound_servants.dm +++ /dev/null @@ -1,283 +0,0 @@ -/datum/spellbound_type - var/name = "Stuff" - var/desc = "spells n shit" - var/equipment = list() - var/spells = list() - -/datum/spellbound_type/proc/spawn_servant(var/atom/a, var/mob/master, var/mob/user) - set waitfor = 0 - var/mob/living/carbon/human/H = new(a) - H.ckey = user.ckey - H.change_appearance(APPEARANCE_GENDER|APPEARANCE_EYE_COLOR|APPEARANCE_HAIR|APPEARANCE_FACIAL_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR_COLOR|APPEARANCE_SKIN) - - var/obj/item/implant/translator/natural/I = new() - I.implant_in_mob(H, BP_HEAD) - if (length(master.languages)) - var/decl/language/lang = master.languages[1] - H.add_language(lang.type) - H.set_default_language(lang.type) - I.languages[lang.name] = 1 - - modify_servant(equip_servant(H), H) - set_antag(H.mind, master) - var/name_choice = sanitize(input(H, "Choose a name. If you leave this blank, it will be defaulted to your current characters.", "Name change") as null|text, MAX_NAME_LEN) - if(name_choice) - H.SetName(name_choice) - H.real_name = name_choice - -/datum/spellbound_type/proc/equip_servant(var/mob/living/carbon/human/H) - for(var/stype in spells) - var/spell/S = new stype() - if(S.spell_flags & NEEDSCLOTHES) - S.spell_flags &= ~NEEDSCLOTHES - H.add_spell(S) - . = list() - for(var/etype in equipment) - var/obj/item/I = new etype(get_turf(H)) - if(istype(I, /obj/item/clothing)) - I.canremove = 0 - H.equip_to_slot_if_possible(I,equipment[etype],0,1,1,1) - . += I - -/datum/spellbound_type/proc/set_antag(var/datum/mind/M, var/mob/master) - return - -/datum/spellbound_type/proc/modify_servant(var/list/items, var/mob/living/carbon/human/H) - return - -/datum/spellbound_type/apprentice - name = "Apprentice" - desc = "Summon your trusty apprentice, equipped with their very own spellbook." - equipment = list(/obj/item/clothing/head/wizard = slot_head, - /obj/item/clothing/under/color/lightpurple = slot_w_uniform, - /obj/item/clothing/shoes/sandal = slot_shoes, - /obj/item/staff = slot_r_hand, - /obj/item/spellbook/apprentice = slot_l_hand, - /obj/item/clothing/suit/wizrobe = slot_wear_suit) - spells = list(/spell/noclothes) - -/datum/spellbound_type/apprentice/set_antag(var/datum/mind/M, var/mob/master) - GLOB.wizards.add_antagonist_mind(M,1,ANTAG_APPRENTICE,"You are an apprentice-type Servant! You're just an ordinary Wizard-To-Be, with no special abilities, but do not need robes to cast spells. Follow your teacher's orders!") - -/datum/spellbound_type/servant - var/spiel = "You don't do anything in particular." - -/datum/spellbound_type/servant/set_antag(var/datum/mind/M, var/mob/master) - GLOB.wizards.add_antagonist_mind(M,1,ANTAG_SERVANT, "You are a [name]-type Servant! [spiel]") - -/datum/spellbound_type/servant/caretaker - name = "Caretaker" - desc = "A healer, a medic, a shoulder to cry on. This servant will heal you, even from near death." - spiel = "'The last enemy that will be destroyed is death.' You can perceive any injuries with simple sight, and heal them with the Trance spell; potentially even reversing death itself! However, this comes at a price; Trance will become increasingly harder to use as you use it, until you can use it no longer. Be cautious, and aid your Master in any way possible!" - equipment = list(/obj/item/clothing/under/caretaker = slot_w_uniform, - /obj/item/clothing/shoes/dress/caretakershoes = slot_shoes) - spells = list(/spell/toggle_armor/caretaker, - /spell/targeted/heal_target/touch, - /spell/aoe_turf/knock/slow, - /spell/targeted/heal_target/area/slow, - /spell/targeted/analyze, - /spell/targeted/heal_target/trance - ) - -/datum/spellbound_type/servant/champion - name = "Champion" - desc = "A knight in shining armor; a warrior, a protector, and a loyal friend." - spiel = "Your sword and armor are second to none, but you have no unique supernatural powers beyond summoning the sword to your hands. Protect your Master with your life!" - equipment = list(/obj/item/clothing/under/bluetunic = slot_w_uniform, - /obj/item/clothing/shoes/jackboots/medievalboots = slot_shoes) - spells = list(/spell/toggle_armor/champion, - /spell/toggle_armor/excalibur) - -/datum/spellbound_type/servant/familiar - name = "Familiar" - desc = "A friend! Or are they a pet? They can transform into animals, and take some particular traits from said creatures." - spiel = "This form of yours is weak in comparison to your transformed form, but that certainly won't pose a problem, considering the fact that you have an alternative. Whatever it is you can turn into, use its powers wisely and serve your Master as well as possible!" - equipment = list(/obj/item/clothing/head/bandana/familiarband = slot_head, - /obj/item/clothing/under/familiargarb = slot_w_uniform) - -/datum/spellbound_type/servant/familiar/modify_servant(var/list/equipment, var/mob/living/carbon/human/H) - var/familiar_type - switch(input(H,"Choose your desired animal form:", "Form") as anything in list("Space Pike", "Mouse", "Cat", "Bear")) - if("Space Pike") - H.mutations |= mNobreath - H.mutations |= MUTATION_SPACERES - familiar_type = /mob/living/simple_animal/hostile/carp/pike - if("Mouse") - H.verbs |= /mob/living/proc/ventcrawl - familiar_type = /mob/living/simple_animal/mouse - if("Cat") - H.mutations |= mRun - familiar_type = /mob/living/simple_animal/cat - if("Bear") - var/obj/item/clothing/under/under = locate() in equipment - var/obj/item/clothing/head/head = locate() in equipment - - var/datum/extension/armor/A = get_extension(under, /datum/extension/armor) - if(A) - A.armor_values = list( - melee = ARMOR_MELEE_VERY_HIGH, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_SMALL, - energy = ARMOR_ENERGY_SMALL - ) //More armor - A = get_extension(head, /datum/extension/armor) - if(A) - A.armor_values = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_MINOR, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_MINOR - ) - familiar_type = /mob/living/simple_animal/hostile/bear - var/spell/targeted/shapeshift/familiar/F = new() - F.possible_transformations = list(familiar_type) - H.add_spell(F) - -/datum/spellbound_type/servant/fiend - name = "Fiend" - desc = "A practitioner of dark and evil magics, almost certainly a demon, and possibly a lawyer." - spiel = "The Summoning Ritual has bound you to this world with limited access to your infernal powers; you'll have to be strategic in how you use them. Follow your Master's orders as well as you can!" - spells = list(/spell/targeted/projectile/dumbfire/fireball/firebolt, - /spell/targeted/ethereal_jaunt, - /spell/targeted/torment, - /spell/area_teleport, - /spell/hand/charges/blood_shard - ) - -/datum/spellbound_type/servant/fiend/equip_servant(var/mob/living/carbon/human/H) - if(H.gender == MALE) - equipment = list(/obj/item/clothing/under/lawyer/fiendsuit = slot_w_uniform, - /obj/item/clothing/shoes/dress/devilshoes = slot_shoes) - spells += /spell/toggle_armor/fiend - else - equipment = list(/obj/item/clothing/under/devildress = slot_w_uniform, - /obj/item/clothing/shoes/dress/devilshoes = slot_shoes) - spells += /spell/toggle_armor/fiend/fem - ..() - -/datum/spellbound_type/servant/infiltrator - name = "Infiltrator" - desc = "A spy and a manipulator to the end, capable of hiding in plain sight and falsifying information to your heart's content." - spiel = "On the surface, you are a completely normal person, but is that really all you are? People are so easy to fool, do as your Master says, and do it with style!" - spells = list(/spell/toggle_armor/infil_items, - /spell/targeted/exhude_pleasantness, - /spell/targeted/genetic/blind/hysteria) - -/datum/spellbound_type/servant/infiltrator/equip_servant(var/mob/living/carbon/human/H) - if(H.gender == MALE) - equipment = list(/obj/item/clothing/under/lawyer/infil = slot_w_uniform, - /obj/item/clothing/shoes/dress/infilshoes = slot_shoes) - spells += /spell/toggle_armor/infiltrator - else - equipment = list(/obj/item/clothing/under/lawyer/infil/fem = slot_w_uniform, - /obj/item/clothing/shoes/dress/infilshoes = slot_shoes) - spells += /spell/toggle_armor/infiltrator/fem - ..() - -/datum/spellbound_type/servant/overseer - name = "Overseer" - desc = "A ghost, or an imaginary friend; the Overseer is immune to space and can turn invisible at a whim, but has little offensive capabilities." - spiel = "Physicality is not something you are familiar with. Indeed, injuries cannot slow you down, but you can't fight back, either! In addition to this, you can reach into the void and return the soul of a single departed crewmember via the revoke death verb, if so desired; this can even revive your Master, should they fall in combat before you do. Serve them well." - equipment = list(/obj/item/clothing/under/grimhoodie = slot_w_uniform, - /obj/item/clothing/shoes/sandal/grimboots = slot_shoes, - /obj/item/contract/wizard/xray = slot_l_hand, - /obj/item/contract/wizard/telepathy = slot_r_hand) - spells = list(/spell/toggle_armor/overseer, - /spell/targeted/ethereal_jaunt, - /spell/invisibility, - /spell/targeted/revoke) - -/datum/spellbound_type/servant/overseer/equip_servant(var/mob/living/carbon/human/H) - ..() - H.add_aura(new /obj/aura/regenerating(H)) - -/obj/effect/cleanable/spellbound - name = "strange rune" - desc = "some sort of runic symbol drawn in... crayon?" - icon = 'icons/obj/rune.dmi' - icon_state = "spellbound" - var/datum/spellbound_type/stype - var/last_called = 0 - -/obj/effect/cleanable/spellbound/Initialize(mapload, var/spell_type) - . = ..(mapload) - stype = new spell_type() - -/obj/effect/cleanable/spellbound/attack_hand(var/mob/user) - if(last_called > world.time ) - return - last_called = world.time + 30 SECONDS - var/datum/ghosttrap/G = get_ghost_trap("wizard familiar") - for(var/mob/observer/ghost/ghost in GLOB.player_list) - if(G.assess_candidate(ghost,null,FALSE)) - to_chat(ghost,"A wizard is requesting a Spell-Bound Servant! (Join)") - -/obj/effect/cleanable/spellbound/CanUseTopic(var/mob) - if(isliving(mob)) - return STATUS_CLOSE - return STATUS_INTERACTIVE - -/obj/effect/cleanable/spellbound/OnTopic(var/mob/user, href_list, state) - if(href_list["master"]) - var/mob/master = locate(href_list["master"]) - stype.spawn_servant(get_turf(src),master,user) - qdel(src) - return TOPIC_HANDLED - -/obj/effect/cleanable/spellbound/Destroy() - qdel(stype) - stype = null - return ..() - -/obj/item/summoning_stone - name = "summoning stone" - desc = "a small non-descript stone of dubious origin." - icon = 'icons/obj/items/summoning_stone.dmi' - icon_state = "stone" - throw_speed = 5 - throw_range = 10 - w_class = ITEM_SIZE_TINY - -/obj/item/summoning_stone/attack_self(var/mob/user) - if(user.z in GLOB.using_map.admin_levels) - to_chat(user, "You cannot use \the [src] here.") - return - user.set_machine(src) - interact(user) - -/obj/item/summoning_stone/interact(var/mob/user) - var/list/types = subtypesof(/datum/spellbound_type) - /datum/spellbound_type/servant - if(user.mind && !GLOB.wizards.is_antagonist(user.mind)) - use_type(pick(types),user) - return - var/dat = "

    Summoning Stone

    Choose a companion to help you.

    " - for(var/type in types) - var/datum/spellbound_type/SB = type - dat += "
    [initial(SB.name)] - [initial(SB.desc)]" - show_browser(user,dat,"window=summoning") - onclose(user,"summoning") - -/obj/item/summoning_stone/proc/use_type(var/type, var/mob/user) - new /obj/effect/cleanable/spellbound(get_turf(src),type) - if(prob(20)) - var/list/base_areas = maintlocs //Have to do it this way as its a macro - var/list/pareas = base_areas.Copy() - while(pareas.len) - var/a = pick(pareas) - var/area/picked_area = pareas[a] - pareas -= a - var/list/turfs = get_area_turfs(picked_area) - for(var/t in turfs) - var/turf/T = t - if(T.density) - turfs -= T - if(turfs.len) - src.visible_message("\The [src] vanishes!") - src.forceMove(pick(turfs)) - show_browser(user, null, "window=summoning") - qdel(src) - -/obj/item/summoning_stone/OnTopic(user, href_list, state) - if(href_list["type"]) - use_type(href_list["type"],user) - return TOPIC_HANDLED \ No newline at end of file diff --git a/code/modules/spells/artifacts/storage.dm b/code/modules/spells/artifacts/storage.dm deleted file mode 100644 index ecd371c2166f..000000000000 --- a/code/modules/spells/artifacts/storage.dm +++ /dev/null @@ -1,41 +0,0 @@ -/obj/structure/closet/wizard - name = "artifact closet" - desc = "a special lead lined closet used to hold artifacts of immense power." - closet_appearance = /decl/closet_appearance/alien - -/obj/structure/closet/wizard/Initialize() - . = ..() - var/obj/structure/bigDelivery/package = new /obj/structure/bigDelivery(get_turf(src)) - package.wrapped = src - package.examtext = "Imported straight from the Wizard Acadamy. Do not lose the contents or suffer a demerit." - src.forceMove(package) - package.update_icon() - -/obj/structure/closet/wizard/armor - name = "Mastercrafted Armor Set" - desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space." - -/obj/structure/closet/wizard/armor/Initialize() - . = ..() - new /obj/item/clothing/shoes/sandal(src) //In case they've lost them. - new /obj/item/clothing/gloves/wizard(src)//To complete the outfit - new /obj/item/clothing/suit/space/void/wizard(src) - new /obj/item/clothing/head/helmet/space/void/wizard(src) - -/obj/structure/closet/wizard/scrying - name = "Scrying Orb" - desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to reconnoiter with ease. In addition, buying it will permanently grant you x-ray vision." - -/obj/structure/closet/wizard/scrying/Initialize() - . = ..() - new /obj/item/scrying(src) - new /obj/item/contract/wizard/xray(src) - -/obj/structure/closet/wizard/souls - name = "Soul Shard Belt" - desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot. This also includes the spell Artificer, used to create the shells used in construct creation." - -/obj/structure/closet/wizard/souls/Initialize() - . = ..() - new /obj/item/contract/boon/wizard/artificer(src) - new /obj/item/storage/belt/soulstone/full(src) diff --git a/code/modules/spells/construct_spells.dm b/code/modules/spells/construct_spells.dm deleted file mode 100644 index 6905c5b428d1..000000000000 --- a/code/modules/spells/construct_spells.dm +++ /dev/null @@ -1,10 +0,0 @@ -//////////////////////////////Construct Spells///////////////////////// - -proc/findNullRod(var/atom/target) - if(istype(target,/obj/item/nullrod)) - return 1 - else if(target.contents) - for(var/atom/A in target.contents) - if(findNullRod(A)) - return 1 - return 0 diff --git a/code/modules/spells/contracts.dm b/code/modules/spells/contracts.dm deleted file mode 100644 index 8c08d2074fee..000000000000 --- a/code/modules/spells/contracts.dm +++ /dev/null @@ -1,155 +0,0 @@ -/obj/item/contract - name = "contract" - desc = "written in the blood of some unfortunate fellow." - icon = 'icons/mob/screen_spells.dmi' - icon_state = "master_open" - - var/contract_master = null - var/list/contract_spells = list(/spell/contract/reward,/spell/contract/punish,/spell/contract/return_master) - -/obj/item/contract/attack_self(mob/user) - if(contract_master == null) - to_chat(user, "You bind the contract to your soul, making you the recipient of whatever poor fool's soul that decides to contract with you.") - contract_master = user - return - - if(contract_master == user) - to_chat(user, "You can't contract with yourself!") - return - - var/ans = alert(user,"The contract clearly states that signing this contract will bind your soul to \the [contract_master]. Are you sure you want to continue?","[src]","Yes","No") - - if(ans == "Yes") - user.visible_message("\The [user] signs the contract, their body glowing a deep yellow.") - if(!src.contract_effect(user)) - user.visible_message("\The [src] visibly rejects \the [user], erasing their signature from the line.") - return - user.visible_message("\The [src] disappears with a flash of light.") - if(contract_spells.len && istype(contract_master,/mob/living)) //if it aint text its probably a mob or another user - var/mob/living/M = contract_master - for(var/spell_type in contract_spells) - M.add_spell(new spell_type(user), "const_spell_ready") - log_and_message_admins("signed their soul over to \the [contract_master] using \the [src].", user) - qdel(src) - -/obj/item/contract/proc/contract_effect(mob/user) - to_chat(user, "You've signed your soul over to \the [contract_master] and with that your unbreakable vow of servitude begins.") - return 1 - -/obj/item/contract/apprentice - name = "apprentice wizarding contract" - desc = "a wizarding school contract for those who want to sign their soul for a piece of the magic pie." - color = "#993300" - -/obj/item/contract/apprentice/contract_effect(mob/user) - if(user.mind.special_role == ANTAG_APPRENTICE) - to_chat(user, "You are already a wizarding apprentice!") - return 0 - if(user.mind.special_role == ANTAG_SERVANT) - to_chat(user, "You are a servant. You have no need of apprenticeship.") - return 0 - if(GLOB.wizards.add_antagonist_mind(user.mind,1,ANTAG_APPRENTICE,"You are an apprentice! Your job is to learn the wizarding arts!")) - to_chat(user, "With the signing of this paper you agree to become \the [contract_master]'s apprentice in the art of wizardry.") - return 1 - return 0 - - -/obj/item/contract/wizard //contracts that involve making a deal with the Wizard Acadamy (or NON PLAYERS) - contract_master = "\improper Wizard Academy" - -/obj/item/contract/wizard/xray - name = "xray vision contract" - desc = "This contract is almost see-through..." - color = "#339900" - -/obj/item/contract/wizard/xray/contract_effect(mob/user) - ..() - if (!(MUTATION_XRAY in user.mutations)) - user.mutations.Add(MUTATION_XRAY) - user.set_sight(user.sight|SEE_MOBS|SEE_OBJS|SEE_TURFS) - user.set_see_in_dark(8) - user.set_see_invisible(SEE_INVISIBLE_LEVEL_TWO) - to_chat(user, "The walls suddenly disappear.") - return 1 - return 0 - -/obj/item/contract/wizard/telepathy - name = "telepathy contract" - desc = "The edges of the contract grow blurry when you look away from them. To be fair, actually reading it gives you a headache." - color = "#fcc605" - -/obj/item/contract/wizard/telepathy/contract_effect(mob/user) - ..() - if (!ishuman(user)) - return 0 - var/mob/living/carbon/human/H = user - if (mRemotetalk in H.mutations) - return 0 - H.mutations.Add(mRemotetalk) - H.verbs += /mob/living/carbon/human/proc/remotesay - to_chat(H, "You expand your mind outwards.") - return 1 - -/obj/item/contract/boon - name = "boon contract" - desc = "this contract grants you a boon for signing it." - var/path - -/obj/item/contract/boon/Initialize(mapload, var/new_path) - . = ..(mapload) - if(new_path) - path = new_path - var/item_name = "" - if(ispath(path,/obj)) - var/obj/O = path - item_name = initial(O.name) - else if(ispath(path,/spell)) - var/spell/S = path - item_name = initial(S.name) - name = "[item_name] contract" - -/obj/item/contract/boon/contract_effect(mob/user) - ..() - if(user.mind.special_role == ANTAG_SERVANT) - to_chat(user, "As a servant you find yourself unable to use this contract.") - return 0 - if(ispath(path,/spell)) - user.add_spell(new path) - return 1 - else if(ispath(path,/obj)) - new path(get_turf(user.loc)) - playsound(get_turf(usr),'sound/magic/charge.ogg',50,1) - return 1 - -/obj/item/contract/boon/wizard - contract_master = "\improper Wizard Academy" - -/obj/item/contract/boon/wizard/artificer - path = /spell/aoe_turf/conjure/construct - desc = "This contract has a passage dedicated to an entity known as 'Nar-Sie'." - -/obj/item/contract/boon/wizard/fireball - path = /spell/targeted/projectile/dumbfire/fireball - desc = "This contract feels warm to the touch." - -/obj/item/contract/boon/wizard/smoke - path = /spell/aoe_turf/smoke - desc = "This contract smells as dank as they come." - -/obj/item/contract/boon/wizard/forcewall - path = /spell/aoe_turf/conjure/forcewall - contract_master = "\improper Mime Federation" - desc = "This contract has a dedication to mimes everywhere at the top." - -/obj/item/contract/boon/wizard/knock - path = /spell/aoe_turf/knock - desc = "This contract is hard to hold still." - -/obj/item/contract/boon/wizard/horsemask - path = /spell/targeted/equip_item/horsemask - desc = "This contract is more horse than your mind has room for." - -/obj/item/contract/boon/wizard/charge - path = /spell/aoe_turf/charge - desc = "This contract is made of 100% post-consumer wizard." - diff --git a/code/modules/spells/general/acid_spray.dm b/code/modules/spells/general/acid_spray.dm deleted file mode 100644 index 97d5af84b0ae..000000000000 --- a/code/modules/spells/general/acid_spray.dm +++ /dev/null @@ -1,30 +0,0 @@ -/spell/acid_spray - name = "Acid Spray" - desc = "A common spell used to destroy basically anything in front of the wizard." - school = "conjuration" - feedback = "as" - spell_flags = 0 - charge_max = 600 - - invocation = "Tagopar lethodar!" - invocation_type = SpI_SHOUT - var/reagent_type = /decl/material/liquid/acid/hydrochloric - hud_state = "wiz_acid" - cast_sound = 'sound/magic/disintegrate.ogg' - -/spell/acid_spray/choose_targets() - return list(holder) - -/spell/acid_spray/cast(var/list/targets, var/mob/user) - var/atom/target = targets[1] - var/angle = dir2angle(target.dir) - for(var/mod in list(315, 0, 45)) - var/obj/effect/effect/water/chempuff/chem = new(get_turf(target)) - chem.create_reagents(10) - chem.reagents.add_reagent(reagent_type,10) - chem.set_color() - spawn(0) - chem.set_up(get_ranged_target_turf(target, angle2dir(angle+mod), 3)) - -/spell/acid_spray/tower - charge_max = 2 \ No newline at end of file diff --git a/code/modules/spells/general/area_teleport.dm b/code/modules/spells/general/area_teleport.dm deleted file mode 100644 index 0a4830e0aa68..000000000000 --- a/code/modules/spells/general/area_teleport.dm +++ /dev/null @@ -1,54 +0,0 @@ -/spell/area_teleport - name = "Teleport" - desc = "This spell teleports you to a type of area of your selection." - feedback = "TP" - school = "conjuration" - charge_max = 600 - spell_flags = NEEDSCLOTHES - invocation = "Scyar Nila!" - invocation_type = SpI_SHOUT - cooldown_min = 200 //100 deciseconds reduction per rank - - smoke_spread = 1 - smoke_amt = 5 - - var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list - var/invocation_area = 1 //if the invocation appends the selected area - - cast_sound = 'sound/effects/teleport.ogg' - - hud_state = "wiz_tele" - -/spell/area_teleport/before_cast() - return - -/spell/area_teleport/choose_targets() - var/area/thearea - if(!randomise_selection) - thearea = input("Area to teleport to", "Teleport") as null|anything in wizteleportlocs - if(!thearea) return - else - thearea = pick(wizteleportlocs) - return list(wizteleportlocs[thearea]) - -/spell/area_teleport/cast(area/thearea, mob/user) - playsound(get_turf(user),cast_sound,50,1) - var/turf/end = user.try_teleport(thearea) - - if(!end) - to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") - return - return - -/spell/area_teleport/after_cast() - return - -/spell/area_teleport/invocation(mob/user, area/chosenarea) - if(!istype(chosenarea)) - return //can't have that, can we - if(!invocation_area || !chosenarea) - ..() - else - invocation += "[uppertext(chosenarea.name)]" - ..() - return diff --git a/code/modules/spells/general/contract_spells.dm b/code/modules/spells/general/contract_spells.dm deleted file mode 100644 index 4894632e0890..000000000000 --- a/code/modules/spells/general/contract_spells.dm +++ /dev/null @@ -1,67 +0,0 @@ -//These spells are given to the owner of a contract when a victim signs it. -//As such they are REALLY REALLY powerful (because the victim is rewarded for signing it, and signing contracts is completely voluntary) - -/spell/contract - name = "Contract Spell" - desc = "A spell perfecting the techniques of keeping a servant happy and obedient." - - school = "transmutation" - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - - - var/mob/subject - -/spell/contract/New(var/mob/M) - ..() - subject = M - name += " ([M.real_name])" - -/spell/contract/choose_targets() - return list(subject) - -/spell/contract/cast(mob/target,mob/user) - if(!subject) - to_chat(usr, "This spell was not properly given a target. Contact a coder.") - return null - - if(istype(target,/list)) - target = target[1] - return target - - -/spell/contract/reward - name = "Reward Contractee" - desc = "A spell that makes your contracted victim feel better." - - charge_max = 300 - cooldown_min = 100 - - hud_state = "wiz_jaunt_old" - -/spell/contract/reward/cast(mob/living/target,mob/user) - target = ..(target,user) - if(!target) - return - - to_chat(target, "You feel great!") - target.ExtinguishMob() - -/spell/contract/punish - name = "Punish Contractee" - desc = "A spell that sets your contracted victim ablaze." - - charge_max = 300 - cooldown_min = 100 - - hud_state = "gen_immolate" - -/spell/contract/punish/cast(mob/living/target,mob/user) - target = ..(target,user) - if(!target) - return - - to_chat(target, "You feel punished!") - target.fire_stacks += 15 - target.IgniteMob() \ No newline at end of file diff --git a/code/modules/spells/general/create_air.dm b/code/modules/spells/general/create_air.dm deleted file mode 100644 index d051f9a152c2..000000000000 --- a/code/modules/spells/general/create_air.dm +++ /dev/null @@ -1,28 +0,0 @@ -/spell/create_air - name = "Create Air" - desc = "A much used spell used in the vasteness of space to make it not so killey." - - charge_max = 200 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - number_of_channels = 0 - time_between_channels = 200 - hud_state = "wiz_air" - var/list/air_change = list(/decl/material/gas/oxygen = ONE_ATMOSPHERE) - number_of_channels = 0 - -/spell/create_air/choose_targets() - var/air = holder.return_air() - if(air) - return list(air) - return null - -/spell/create_air/cast(var/list/targets, var/mob/holder, var/channel_count) - var/datum/gas_mixture/environment = targets[1] - for(var/gas in air_change) - environment.adjust_gas(gas, air_change[gas]) - -/spell/create_air/tower - charge_max = 5 \ No newline at end of file diff --git a/code/modules/spells/general/god_construct.dm b/code/modules/spells/general/god_construct.dm deleted file mode 100644 index 761cb561c8fe..000000000000 --- a/code/modules/spells/general/god_construct.dm +++ /dev/null @@ -1,55 +0,0 @@ -#define CONSTRUCT_SPELL_COST 1 -#define CONSTRUCT_SPELL_TYPE 2 - -/spell/construction - name = "Construction" - desc = "This ability will let you summon a structure of your choosing." - - cast_delay = 10 - charge_max = 100 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - hud_state = "const_wall" - cast_sound = 'sound/effects/meteorimpact.ogg' - -/spell/construction/choose_targets() - var/list/possible_targets = list() - if(connected_god && connected_god.form) - for(var/type in connected_god.form.buildables) - var/cost = 10 - if(ispath(type, /obj/structure/deity)) - var/obj/structure/deity/D = type - cost = initial(D.build_cost) - possible_targets["[connected_god.get_type_name(type)] - [cost]"] = list(cost, type) - var/choice = input("Construct to build.", "Construction") as null|anything in possible_targets - if(!choice) - return - if(locate(/obj/structure/deity) in get_turf(holder)) - return - - return possible_targets[choice] - else - return - -/spell/construction/cast_check(var/skipcharge, var/mob/user, var/list/targets) - if(!..()) - return 0 - var/turf/T = get_turf(user) - if(skipcharge && !valid_deity_structure_spot(targets[CONSTRUCT_SPELL_TYPE], T, connected_god, user)) - return 0 - else - for(var/obj/O in T) - if(O.density) - to_chat(user, "Something here is blocking your construction!") - return 0 - return 1 - -/spell/construction/cast(var/target, mob/user) - charge_max = target[CONSTRUCT_SPELL_COST] - target = target[CONSTRUCT_SPELL_TYPE] - var/turf/T = get_turf(user) - new target(T, connected_god) -#undef CONSTRUCT_SPELL_COST -#undef CONSTRUCT_SPELL_TYPE \ No newline at end of file diff --git a/code/modules/spells/general/god_vision.dm b/code/modules/spells/general/god_vision.dm deleted file mode 100644 index 186dbede1d97..000000000000 --- a/code/modules/spells/general/god_vision.dm +++ /dev/null @@ -1,58 +0,0 @@ -/spell/camera_connection - name = "Camera Connection" - desc = "This spell allows the wizard to connect to the local camera network and see what it sees." - - school = "racial" - - invocation_type = SpI_EMOTE - invocation = "emits a beeping sound before standing very, very still." - - charge_max = 600 //1 minute - charge_type = Sp_RECHARGE - - - spell_flags = Z2NOCAST - hud_state = "wiz_IPC" - - var/extension_type = /datum/extension/eye/cameranet - -/spell/camera_connection/New() - ..() - set_extension(src, extension_type) - -/spell/camera_connection/choose_targets() - var/mob/living/L = holder - if(!istype(L) || L.eyeobj) //no using if we already have an eye on. - return null - return list(holder) - -/spell/camera_connection/cast(var/list/targets, mob/user) - var/mob/living/L = targets[1] - - var/datum/extension/eye/cameranet/cn = get_extension(src, /datum/extension/eye/) - if(!cn) - to_chat(user, SPAN_WARNING("There's a flash of sparks as the spell fizzles out!")) - return - cn.look(L) - -/spell/camera_connection/god_vision - name = "All Seeing Eye" - desc = "See what your master sees." - - charge_max = 10 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - extension_type = /datum/extension/eye/freelook - - hud_state = "gen_mind" - -/spell/camera_connection/god_vision/set_connected_god(var/mob/living/deity/god) - ..() - - var/datum/extension/eye/freelook/fl = get_extension(src, /datum/extension/eye) - if(!fl) - return - fl.set_visualnet(god.eyenet) - diff --git a/code/modules/spells/general/invisibility.dm b/code/modules/spells/general/invisibility.dm deleted file mode 100644 index 22df55b73f31..000000000000 --- a/code/modules/spells/general/invisibility.dm +++ /dev/null @@ -1,24 +0,0 @@ -/spell/invisibility - name = "invisibility" - desc = "A simple spell of invisibility, for when you really just can't afford a paper bag." - feedback = "IV" - spell_flags = 0 - charge_max = 100 - invocation = "Ror Rim Or!" - invocation_type = SpI_SHOUT - var/on = 0 - hud_state = "invisibility" - -/spell/invisibility/choose_targets() - if(istype(holder, /mob/living/carbon/human)) - return holder - -/spell/invisibility/cast(var/mob/living/carbon/human/H, var/mob/user) - on = !on - if(on) - if(H.add_cloaking_source(src)) - playsound(get_turf(H), 'sound/effects/teleport.ogg', 90, 1) - H.mutations |= MUTATION_CLUMSY - else if(H.remove_cloaking_source(src)) - playsound(get_turf(H), 'sound/effects/stealthoff.ogg', 90, 1) - H.mutations -= MUTATION_CLUMSY \ No newline at end of file diff --git a/code/modules/spells/general/mark_recall.dm b/code/modules/spells/general/mark_recall.dm deleted file mode 100644 index 7f1a0336b9b1..000000000000 --- a/code/modules/spells/general/mark_recall.dm +++ /dev/null @@ -1,83 +0,0 @@ -/spell/mark_recall - name = "Mark and Recall" - desc = "This spell was created so wizards could get home from the bar without driving. Does not require wizard garb." - feedback = "MK" - school = "conjuration" - charge_max = 600 //1 minutes for how OP this shit is (apparently not as op as I thought) - spell_flags = Z2NOCAST - invocation = "Re-Alki R'natha." - invocation_type = SpI_WHISPER - cooldown_min = 300 - - smoke_amt = 1 - smoke_spread = 5 - - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) - - cast_sound = 'sound/effects/teleport.ogg' - hud_state = "wiz_mark" - var/mark = null - -/spell/mark_recall/choose_targets() - if(!mark) - return list("magical fairy dust") //because why not - else - return list(mark) - -/spell/mark_recall/cast(var/list/targets,mob/user) - if(!targets.len) - return 0 - var/target = targets[1] - if(istext(target)) - mark = new /obj/effect/cleanable/wizard_mark(get_turf(user),src) - return 1 - if(!istype(target,/obj)) //something went wrong - return 0 - var/turf/T = get_turf(target) - if(!T) - return 0 - user.forceMove(T) - ..() - -/spell/mark_recall/empower_spell() - if(!..()) - return 0 - - spell_flags = NO_SOMATIC - - return "You will always be able to cast this spell, even while unconscious or handcuffed." - -/obj/effect/cleanable/wizard_mark - name = "\improper Mark of the Wizard" - desc = "A strange rune said to be made by wizards. Or its just some shmuck playing with crayons again." - icon = 'icons/obj/rune.dmi' - icon_state = "wizard_mark" - - anchored = 1 - unacidable = 1 - layer = TURF_LAYER - - var/spell/mark_recall/spell - -/obj/effect/cleanable/wizard_mark/Initialize(mapload,var/mrspell) - . = ..() - spell = mrspell - -/obj/effect/cleanable/wizard_mark/Destroy() - spell.mark = null //dereference pls. - spell = null - ..() - -/obj/effect/cleanable/wizard_mark/attack_hand(var/mob/user) - if(user == spell.holder) - user.visible_message("\The [user] mutters an incantation and \the [src] disappears!") - qdel(src) - ..() - -/obj/effect/cleanable/wizard_mark/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/nullrod) || istype(I, /obj/item/spellbook)) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - src.visible_message("\The [src] fades away!") - qdel(src) - return - ..() \ No newline at end of file diff --git a/code/modules/spells/general/open_gateway.dm b/code/modules/spells/general/open_gateway.dm deleted file mode 100644 index e83559a25108..000000000000 --- a/code/modules/spells/general/open_gateway.dm +++ /dev/null @@ -1,33 +0,0 @@ -/spell/open_gateway - name = "Open Gateway" - desc = "Open a gateway for your master. Don't do it for too long, or you will die." - - charge_max = 600 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - number_of_channels = 0 - time_between_channels = 200 - hud_state = "const_wall" - cast_sound = 'sound/effects/meteorimpact.ogg' - -/spell/open_gateway/choose_targets() - var/mob/living/H = holder - var/turf/T = get_turf(H) - holder.visible_message("A gateway opens up underneath \the [H]!") - var/g - if(H.mind && (H.mind in GLOB.godcult.current_antagonists)) - g = GLOB.godcult.get_deity(H.mind) - return list(new /obj/structure/deity/gateway(T,g)) - -/spell/open_gateway/cast(var/list/targets, var/mob/holder, var/channel_count) - if(prob((channel_count / 5) * 100)) - to_chat(holder, "If you hold the portal open for much longer you'll be ripped apart!") - if(channel_count == 6) - to_chat(holder, "The gateway consumes you... leaving nothing but dust.") - holder.dust() - - -/spell/open_gateway/after_spell(var/list/targets) - QDEL_NULL_LIST(targets) \ No newline at end of file diff --git a/code/modules/spells/general/portal_teleport.dm b/code/modules/spells/general/portal_teleport.dm deleted file mode 100644 index 32c20305fe71..000000000000 --- a/code/modules/spells/general/portal_teleport.dm +++ /dev/null @@ -1,68 +0,0 @@ -/spell/portal_teleport - name = "Create Portal" - desc = "This spell creates a long lasting portal to an area of your selection." - feedback = "TP" - school = "conjuration" - charge_max = 600 - spell_flags = NEEDSCLOTHES - invocation = "Scyar Peranda!" - invocation_type = SpI_SHOUT - charge_max = 30 MINUTES - cooldown_min = 25 MINUTES - - smoke_spread = 1 - smoke_amt = 5 - - var/list/select_areas = list() - - cast_sound = 'sound/effects/teleport.ogg' - - hud_state = "wiz_tele" - -/spell/portal_teleport/before_cast() - return - -/spell/portal_teleport/choose_targets() - var/area/thearea - var/message = alert("Would you like to show station areas?\nNote: it can take up to 5 minutes for the away sites to load in and show up.",, "Yes", "No") - switch(message) - if("Yes") - select_areas = stationlocs - if("No") - select_areas = (stationlocs) ^ (wizportallocs) - - thearea = input("Area to teleport to", "Teleport") as null|anything in select_areas - if(!thearea) return - - return list(select_areas[thearea]) - -/spell/portal_teleport/cast(area/thearea, mob/user) - playsound(get_turf(user),cast_sound,50,1) - var/turf/start = get_turf(user) - var/turf/end = user.try_teleport(thearea) - - if(!end) - to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.") - return - - new /obj/effect/portal/wizard(start, end, 35 MINUTES) - new /obj/effect/portal/wizard(end, start, 35 MINUTES) - - return - -/spell/portal_teleport/after_cast() - return - -/spell/portal_teleport/invocation(mob/user, area/chosenarea) - if(!chosenarea || !istype(chosenarea)) - ..() - else - invocation += "[uppertext(chosenarea.name)]" - ..() - return - -/obj/effect/portal/wizard - name = "dark anomaly" - desc = "It pulls on the edges of reality as if trying to draw them in." - icon = 'icons/obj/objects.dmi' - icon_state = "bhole3" diff --git a/code/modules/spells/general/radiant_aura.dm b/code/modules/spells/general/radiant_aura.dm deleted file mode 100644 index 2c243896eb98..000000000000 --- a/code/modules/spells/general/radiant_aura.dm +++ /dev/null @@ -1,26 +0,0 @@ -/spell/radiant_aura - name = "Radiant aura" - desc = "Form a protective layer of light around you, making you immune to laser fire." - school = "transmutation" - feedback = "ra" - invocation_type = SpI_EMOTE - invocation = "conjures a sphere of fire around themselves." - school = "conjuration" - spell_flags = NEEDSCLOTHES - charge_max = 300 - cooldown_min = 100 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 0) - cast_sound = 'sound/effects/snap.ogg' - duration = 40 - hud_state = "gen_immolate" - -/spell/radiant_aura/choose_targets() - return list(holder) - -/spell/radiant_aura/cast(var/list/targets, var/mob/user) - var/obj/aura/radiant_aura/A = new(user) - QDEL_IN(A,duration) - -/spell/radiant_aura/starlight - spell_flags = 0 - charge_max = 400 \ No newline at end of file diff --git a/code/modules/spells/general/return_master.dm b/code/modules/spells/general/return_master.dm deleted file mode 100644 index 119cc93804de..000000000000 --- a/code/modules/spells/general/return_master.dm +++ /dev/null @@ -1,23 +0,0 @@ -/spell/contract/return_master - name = "Return to Master" - desc = "Teleport back to your master" - - school = "conjuration" - charge_max = 600 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - cooldown_min = 200 - - smoke_spread = 1 - smoke_amt = 5 - - hud_state = "wiz_tele" - - -/spell/contract/return_master/cast(mob/target,mob/user) - target = ..(target,user) - if(!target) - return - - user.forceMove(get_turf(target)) \ No newline at end of file diff --git a/code/modules/spells/general/tear_veil.dm b/code/modules/spells/general/tear_veil.dm deleted file mode 100644 index c551270bd262..000000000000 --- a/code/modules/spells/general/tear_veil.dm +++ /dev/null @@ -1,37 +0,0 @@ -/spell/tear_veil - name = "Tear Veil" - desc = "Use your mental strength to literally tear a hole from this dimension to the next, letting things through..." - - charge_max = 300 - spell_flags = Z2NOCAST - invocation = "none" - invocation_type = SpI_NONE - - number_of_channels = 0 - time_between_channels = 200 - hud_state = "const_floor" - cast_sound = 'sound/effects/meteorimpact.ogg' - var/list/possible_spawns = list( - /mob/living/simple_animal/hostile/scarybat/cult, - /mob/living/simple_animal/hostile/creature/cult, - /mob/living/simple_animal/hostile/faithless/cult - ) - -/spell/tear_veil/choose_targets() - var/turf/T = get_turf(holder) - holder.visible_message("A strange portal rips open underneath \the [holder]!") - var/obj/effect/gateway/hole = new(get_turf(T)) - hole.density = 0 - return list(hole) - -/spell/tear_veil/cast(var/list/targets, var/mob/holder, var/channel_count) - if(channel_count == 1) - return - var/type = pick(possible_spawns) - var/mob/living/L = new type(get_turf(targets[1])) - L.faction = holder.faction - L.visible_message("\A [L] escapes from the portal!") - -/spell/tear_veil/after_spell(var/list/targets) - qdel(targets[1]) - return \ No newline at end of file diff --git a/code/modules/spells/general/toggle_armor.dm b/code/modules/spells/general/toggle_armor.dm deleted file mode 100644 index c3652bdad93f..000000000000 --- a/code/modules/spells/general/toggle_armor.dm +++ /dev/null @@ -1,121 +0,0 @@ -/spell/toggle_armor - name = "Toggle Armor" - spell_flags = 0 - charge_max = 10 - school = "Conjuration" - var/list/armor_pieces - var/equip = 0 - hud_state = "const_shell" - -/spell/toggle_armor/New() - if(armor_pieces) - var/list/nlist = list() - for(var/type in armor_pieces) - var/obj/item/I = new type(null) - nlist[I] = armor_pieces[type] - armor_pieces = nlist - return ..() - -/spell/toggle_armor/proc/drop_piece(var/obj/I) - if(istype(I.loc, /mob)) - var/mob/M = I.loc - M.drop_from_inventory(I) - -/spell/toggle_armor/choose_targets() - return list(holder) - -/spell/toggle_armor/cast(var/list/targets, var/mob/user) - equip = !equip - name = "[initial(name)] ([equip ? "off" : "on"])" - if(equip) - for(var/piece in armor_pieces) - var/slot = armor_pieces[piece] - drop_piece(piece) - user.drop_from_inventory(user.get_equipped_item(slot)) - user.equip_to_slot_if_possible(piece,slot,0,1,1,1) - else - for(var/piece in armor_pieces) - var/obj/item/I = piece - drop_piece(piece) - I.forceMove(null) - -/spell/toggle_armor/greytide_worldwide - name = "Greytide Worldwide" - invocation_type = SpI_EMOTE - invocation = "screams incoherently!" - armor_pieces = list(/obj/item/clothing/under/color/grey = slot_w_uniform, - /obj/item/clothing/gloves/insulated/cheap = slot_gloves, - /obj/item/clothing/mask/gas = slot_wear_mask, - /obj/item/clothing/shoes/color/black = slot_shoes, - /obj/item/storage/toolbox/mechanical = slot_r_hand, - /obj/item/extinguisher = slot_l_hand) - -/spell/toggle_armor/caretaker - name = "Toggle Armor (Caretaker)" - invocation_type = SpI_EMOTE - invocation = "radiates a holy light" - armor_pieces = list(/obj/item/clothing/head/caretakerhood = slot_head, - /obj/item/clothing/suit/caretakercloak = slot_wear_suit - ) - hud_state = "caretaker" - -/spell/toggle_armor/champion - name = "Toggle Armor (Champion)" - invocation_type = SpI_EMOTE - invocation = "is covered in golden embers for a moment, before they fade" - armor_pieces = list(/obj/item/clothing/head/champhelm = slot_head, - /obj/item/clothing/suit/champarmor = slot_wear_suit - ) - hud_state = "champion" - -/spell/toggle_armor/excalibur - name = "Toggle Sword" - invocation_type = SpI_EMOTE - invocation = "thrusts /his hand forward, and it is enveloped in golden embers!" - armor_pieces = list(/obj/item/sword/excalibur = slot_r_hand) - hud_state = "excalibur" - -/spell/toggle_armor/fiend - name = "Toggle Armor (Fiend)" - invocation_type = SpI_EMOTE - invocation = "snaps /his fingers, and /his clothes begin to shift and change" - armor_pieces = list(/obj/item/clothing/head/fiendhood = slot_head, - /obj/item/clothing/suit/fiendcowl = slot_wear_suit - ) - hud_state = "fiend" - -/spell/toggle_armor/fiend/fem - armor_pieces = list(/obj/item/clothing/head/fiendhood/fem = slot_head, - /obj/item/clothing/suit/fiendcowl/fem = slot_wear_suit - ) - -/spell/toggle_armor/infiltrator - name = "Toggle Armor (Infiltrator)" - invocation_type = SpI_EMOTE - invocation = "winks. In an instant, /his clothes change dramatically" - armor_pieces = list(/obj/item/clothing/head/infilhat = slot_head, - /obj/item/clothing/suit/infilsuit = slot_wear_suit - ) - hud_state = "infiltrator" - -/spell/toggle_armor/infiltrator/fem - armor_pieces = list(/obj/item/clothing/head/infilhat/fem = slot_head, - /obj/item/clothing/suit/infilsuit/fem = slot_wear_suit - ) - -/spell/toggle_armor/infil_items - name = "Toggle Counterfeit Kit" - invocation_type = SpI_EMOTE - invocation = "flicks /his wrists, one at a time" - armor_pieces = list(/obj/item/stamp/chameleon = slot_l_hand, - /obj/item/pen/chameleon = slot_r_hand) - hud_state = "forgery" - -/spell/toggle_armor/overseer - name = "Toggle Armor (Overseer)" - invocation_type = SpI_EMOTE - invocation = " is enveloped in shadows, before /his form begins to shift rapidly" - armor_pieces = list(/obj/item/clothing/head/overseerhood = slot_head, - /obj/item/clothing/suit/straight_jacket/overseercloak = slot_wear_suit - ) - hud_state = "overseer" \ No newline at end of file diff --git a/code/modules/spells/general/veil_of_shadows.dm b/code/modules/spells/general/veil_of_shadows.dm deleted file mode 100644 index fd78bb3ed852..000000000000 --- a/code/modules/spells/general/veil_of_shadows.dm +++ /dev/null @@ -1,57 +0,0 @@ -/spell/veil_of_shadows - name = "Veil of Shadows" - desc = "Become intangable, invisible. Like a ghost." - charge_max = 400 - invocation_type = SpI_EMOTE - invocation = "flickers out of existance" - school = "Divine" //Means that it doesn't proc the deity's spell cost. - spell_flags = 0 - duration = 100 - var/timer_id - var/light_steps = 4 - - hud_state = "wiz_statue" - -/spell/veil_of_shadows/choose_targets() - if(!timer_id && istype(holder,/mob/living/carbon/human)) - return list(holder) - . = null - -/spell/veil_of_shadows/cast(var/list/targets, var/mob/user) - var/mob/living/carbon/human/H = user - H.AddMovementHandler(/datum/movement_handler/mob/incorporeal) - if(H.add_cloaking_source(src)) - H.visible_message("\The [H] shrinks from view!") - GLOB.moved_event.register(H,src,.proc/check_light) - timer_id = addtimer(CALLBACK(src,.proc/cancel_veil),duration, TIMER_STOPPABLE) - -/spell/veil_of_shadows/proc/cancel_veil() - var/mob/living/carbon/human/H = holder - H.RemoveMovementHandler(/datum/movement_handler/mob/incorporeal) - deltimer(timer_id) - timer_id = null - var/turf/T = get_turf(H) - if(T.get_lumcount() > 0.1) //If we're somewhere somewhat shadowy we can stay invis as long as we stand still - drop_cloak() - else - GLOB.moved_event.unregister(H,src) - GLOB.moved_event.register(H,src,.proc/drop_cloak) - -/spell/veil_of_shadows/proc/drop_cloak() - var/mob/living/carbon/human/H = holder - if(H.remove_cloaking_source(src)) - H.visible_message("\The [H] appears from nowhere!") - GLOB.moved_event.unregister(H,src) - -/spell/veil_of_shadows/proc/check_light() - if(light_steps) - light_steps-- - return - light_steps = initial(light_steps) - for(var/obj/machinery/light/light in view(1,holder)) - light.flicker(20) - -/spell/veil_of_shadows/Destroy() - deltimer(timer_id) - cancel_veil() - .= ..() \ No newline at end of file diff --git a/code/modules/spells/hand/blood_shards.dm b/code/modules/spells/hand/blood_shards.dm deleted file mode 100644 index 82ef0a9949e9..000000000000 --- a/code/modules/spells/hand/blood_shards.dm +++ /dev/null @@ -1,40 +0,0 @@ -/spell/hand/charges/blood_shard - name = "Blood Shards" - desc = "Invoke a corrupted projectile forward that causes an enemy's blood to fly out in painful shards." - - spell_flags = 0 - charge_max = 600 - invocation = "opens their hand, which bursts into vicious red light." - invocation_type = SpI_EMOTE - - range = 7 - max_casts = 2 - compatible_targets = list(/atom) - hud_state = "wiz_bshard" - cast_sound = 'sound/magic/demon_attack1.ogg' - -/spell/hand/charges/blood_shard/cast_hand(var/atom/A,var/mob/user) - var/obj/item/projectile/blood_shard/B = new(get_turf(user)) - B.firer = user - B.launch(A, BP_CHEST) - user.visible_message("\The [user] shoots out a deep red shard from their hand!") - return ..() - -/obj/item/projectile/blood_shard - name = "bloodshard" - damage = 25 - icon_state = "blood" - damage_type = BRUTE - damage_flags = 0 - -/obj/item/projectile/blood_shard/on_hit(var/atom/movable/target, var/blocked = 0) - if(..()) - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - H.vessel.remove_any(30) - H.visible_message("Tiny red shards burst from \the [H]'s skin!") - fragmentate(get_turf(src), 30, 5, list(/obj/item/projectile/bullet/pellet/blood)) - -/obj/item/projectile/bullet/pellet/blood - name = "blood fragment" - damage = 10 \ No newline at end of file diff --git a/code/modules/spells/hand/burning_grip.dm b/code/modules/spells/hand/burning_grip.dm deleted file mode 100644 index e0923de6010b..000000000000 --- a/code/modules/spells/hand/burning_grip.dm +++ /dev/null @@ -1,42 +0,0 @@ -/spell/hand/burning_grip - name = "Burning Grip" - desc = "Cause someone to drop a held object by causing it to heat up intensly." - school = "transmutation" - feedback = "bg" - range = 5 - spell_flags = 0 - invocation_type = SpI_NONE - show_message = " throws sparks from their hands" - spell_delay = 120 - hud_state = "wiz_burn" - cast_sound = 'sound/magic/fireball.ogg' - compatible_targets = list(/mob/living/carbon/human) - -/spell/hand/burning_grip/valid_target(var/mob/living/L, var/mob/user) - if(!..()) - return 0 - if(!L.l_hand && !L.r_hand) - return 0 - return 1 - -/spell/hand/burning_grip/cast_hand(var/mob/living/carbon/human/H, var/mob/user) - var/list/targets = list() - if(H.l_hand) - targets += BP_L_HAND - if(H.r_hand) - targets += BP_R_HAND - - var/obj/O = new /obj/effect/temporary(get_turf(H),3, 'icons/effects/effects.dmi', "fire_goon") - O.alpha = 150 - - for(var/organ in targets) - var/obj/item/organ/external/E = H.get_organ(organ) - E.take_external_damage(burn=10, used_weapon = "hot iron") - if(E.can_feel_pain()) - H.grasp_damage_disarm(E) - else - E.take_external_damage(burn=6, used_weapon = "hot iron") - to_chat(H, "You look down to notice that your [E] is burned.") - -/spell/hand/burning_grip/tower - charge_max = 3 \ No newline at end of file diff --git a/code/modules/spells/hand/entangle.dm b/code/modules/spells/hand/entangle.dm deleted file mode 100644 index a5feb5568a7e..000000000000 --- a/code/modules/spells/hand/entangle.dm +++ /dev/null @@ -1,51 +0,0 @@ -/spell/hand/charges/entangle - name = "Entangle" - desc = "This spell creates vines that immediately entangle a nearby victim." - feedback = "ET" - school = "transmutation" - charge_max = 600 - spell_flags = NEEDSCLOTHES | SELECTABLE | IGNOREPREV - invocation = "Bu-Ekel'Inas!" - invocation_type = SpI_SHOUT - range = 3 - max_casts = 1 - - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) - cooldown_min = 300 - duration = 30 - compatible_targets = list(/mob) - - hud_state = "wiz_entangle" - cast_sound = 'sound/magic/staff_door.ogg' - show_message = " points towards the ground, causing plants to erupt" - var/datum/seed/seed - -/spell/hand/charges/entangle/New() - ..() - seed = new() - seed.set_trait(TRAIT_PLANT_ICON,"flower") - seed.set_trait(TRAIT_PRODUCT_ICON,"flower2") - seed.set_trait(TRAIT_PRODUCT_COLOUR,"#4d4dff") - seed.set_trait(TRAIT_SPREAD,2) - seed.name = "heirlooms" - seed.seed_name = "heirloom" - seed.display_name = "vines" - seed.chems = list(/decl/material/liquid/nutriment = list(1,20)) - -/spell/hand/charges/entangle/cast_hand(var/mob/M,var/mob/user) - var/turf/T = get_turf(M) - var/obj/effect/vine/single/P = new(T, seed, null, TRUE) - P.can_buckle = 1 - - P.buckle_mob(M) - M.set_dir(pick(GLOB.cardinal)) - M.visible_message("[P] appear from the floor, spinning around \the [M] tightly!") - return ..() - -/spell/hand/charges/entangle/empower_spell() - if(!..()) - return 0 - - max_casts++ - - return "This spell will now entangle [max_casts] times before running out." \ No newline at end of file diff --git a/code/modules/spells/hand/hand.dm b/code/modules/spells/hand/hand.dm deleted file mode 100644 index b3905a19bc5c..000000000000 --- a/code/modules/spells/hand/hand.dm +++ /dev/null @@ -1,83 +0,0 @@ -/spell/hand - var/min_range = 0 - var/list/compatible_targets = list(/atom) - var/spell_delay = 5 - var/move_delay - var/click_delay - var/hand_state = "spell" - var/obj/item/magic_hand/current_hand - var/show_message - -/spell/hand/choose_targets(mob/user = usr) - return list(user) - -/spell/hand/cast_check(skipcharge = 0,mob/user = usr, var/list/targets) - if(!..()) - return FALSE - if(user.get_active_hand()) - to_chat(holder, "You need an empty hand to cast this spell.") - return FALSE - return TRUE - -/spell/hand/cast(list/targets, mob/user) - if(current_hand) - cancel_hand() - if(user.get_active_hand()) - to_chat(user, "You need an empty hand to cast this spell.") - return FALSE - current_hand = new(src) - if(!user.put_in_active_hand(current_hand)) - QDEL_NULL(current_hand) - return FALSE - return TRUE - -/spell/hand/proc/cancel_hand() - if(!QDELETED(current_hand)) - QDEL_NULL(current_hand) - -/spell/hand/Destroy() - qdel(current_hand) - . = ..() - -/spell/hand/proc/valid_target(var/atom/a,var/mob/user) //we use seperate procs for our target checking for the hand spells. - var/distance = get_dist(a,user) - if((min_range && distance < min_range) || (range && distance > range)) - return FALSE - if(!is_type_in_list(a,compatible_targets)) - return FALSE - return TRUE - -/spell/hand/proc/cast_hand(var/atom/a,var/mob/user) //same for casting. - return TRUE - -/spell/hand/charges - var/casts = 1 - var/max_casts = 1 - -/spell/hand/charges/cast(list/targets, mob/user) - . = ..() - if(.) - casts = max_casts - to_chat(user, "You ready the [name] spell ([casts]/[casts] charges).") - -/spell/hand/charges/cast_hand() - if(..()) - casts-- - to_chat(holder, "The [name] spell has [casts] out of [max_casts] charges left") - cancel_hand() - return TRUE - return FALSE - -/spell/hand/duration - var/hand_timer = null - var/hand_duration = 0 - -/spell/hand/duration/cast(var/list/targets, var/mob/user) - . = ..() - if(.) - hand_timer = addtimer(CALLBACK(src, .proc/cancel_hand), hand_duration, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_NO_HASH_WAIT|TIMER_OVERRIDE) - -/spell/hand/duration/cancel_hand() - deltimer(hand_timer) - hand_timer = null - ..() \ No newline at end of file diff --git a/code/modules/spells/hand/hand_item.dm b/code/modules/spells/hand/hand_item.dm deleted file mode 100644 index 4a038d711d87..000000000000 --- a/code/modules/spells/hand/hand_item.dm +++ /dev/null @@ -1,67 +0,0 @@ -/*much like grab this item is used primarily for the utility it provides. -Basically: I can use it to target things where I click. I can then pass these targets to a spell and target things not using a list. -*/ - -/obj/item/magic_hand - name = "Magic Hand" - icon = 'icons/mob/screen1.dmi' - atom_flags = 0 - item_flags = 0 - obj_flags = 0 - simulated = 0 - icon_state = "spell" - var/next_spell_time = 0 - var/spell/hand/hand_spell - -/obj/item/magic_hand/Initialize() - . = ..() - hand_spell = loc - name = "[name] ([hand_spell.name])" - icon_state = hand_spell.hand_state - -/obj/item/magic_hand/get_storage_cost() - return ITEM_SIZE_NO_CONTAINER - -/obj/item/magic_hand/attack(var/mob/living/M, var/mob/living/user) - if(hand_spell && hand_spell.valid_target(M, user)) - fire_spell(M, user) - return 0 - return 1 - -/obj/item/magic_hand/proc/fire_spell(var/atom/A, mob/living/user) - if(!hand_spell) //no spell? Die. - user.drop_from_inventory(src) - - if(!hand_spell.valid_target(A,user)) - return - if(world.time < next_spell_time) - to_chat(user, "The spell isn't ready yet!") - return - if(user.a_intent == I_HELP) - to_chat(user, "You decide against casting this spell as your intent is set to help.") - return - - if(hand_spell.show_message) - user.visible_message("\The [user][hand_spell.show_message]") - if(hand_spell.cast_hand(A,user)) - next_spell_time = world.time + hand_spell.spell_delay - if(hand_spell.move_delay) - user.ExtraMoveCooldown(hand_spell.move_delay) - if(hand_spell.click_delay) - user.setClickCooldown(hand_spell.move_delay) - -/obj/item/magic_hand/afterattack(var/atom/A, var/mob/user, var/proximity) - if(hand_spell) - fire_spell(A,user) - -/obj/item/magic_hand/throw_at() //no throwing pls - usr.drop_from_inventory(src) - -/obj/item/magic_hand/dropped() //gets deleted on drop - ..() - qdel(src) - -/obj/item/magic_hand/Destroy() //better save than sorry. - hand_spell.current_hand = null - hand_spell = null - . = ..() \ No newline at end of file diff --git a/code/modules/spells/hand/slippery_surface.dm b/code/modules/spells/hand/slippery_surface.dm deleted file mode 100644 index cd7158921c0f..000000000000 --- a/code/modules/spells/hand/slippery_surface.dm +++ /dev/null @@ -1,21 +0,0 @@ -/spell/hand/slippery_surface - name = "Slippery Surface" - desc = "More of a practical joke than an actual spell." - school = "transmutation" - feedback = "su" - range = 5 - spell_flags = 0 - invocation_type = SpI_NONE - show_message = " snaps their fingers." - spell_delay = 50 - hud_state = "gen_ice" - cast_sound = 'sound/magic/summonitems_generic.ogg' - -/spell/hand/slippery_surface/cast_hand(var/atom/a, var/mob/user) - for(var/turf/simulated/T in view(1,a)) - T.wet_floor(50) - new /obj/effect/temporary(T,3, 'icons/effects/effects.dmi', "sonar_ping") - return ..() - -/spell/hand/slippery_surface/tower - charge_max = 2 \ No newline at end of file diff --git a/code/modules/spells/hand/sunwrath.dm b/code/modules/spells/hand/sunwrath.dm deleted file mode 100644 index 4496c985d9f8..000000000000 --- a/code/modules/spells/hand/sunwrath.dm +++ /dev/null @@ -1,33 +0,0 @@ -/spell/hand/duration/sunwrath - name = "sun god's wrath" - desc = "Your hands become a gateway of fire, shooting hot plasma from your fingertips." - spell_flags = 0 - charge_max = 600 - invocation_type = SpI_SHOUT - invocation = "Herald! Bless me with your anger!" - show_message = " erupts fire from their hands" - school = "Divine" - hand_duration = 100 - spell_delay = 30 - range = 4 - - hud_state = "wiz_immolate" - -/spell/hand/duration/sunwrath/cast_hand(var/atom/A, var/mob/user) - var/turf/T = get_turf(user) - var/list/turfs = getline(T,A) - T - for(var/t in turfs) - var/turf/turf = t - if(turf.density || istype(turf, /turf/space)) - break - new /obj/effect/fake_fire/sunwrath(t) - return 1 - -/obj/effect/fake_fire/sunwrath - firelevel = 2 - last_temperature = 0 - pressure = 3000 - -/obj/effect/fake_fire/sunwrath/Process() //Override, so we burn mobs only - for(var/mob/living/L in loc) - L.FireBurn(firelevel,last_temperature,pressure) \ No newline at end of file diff --git a/code/modules/spells/no_clothes.dm b/code/modules/spells/no_clothes.dm deleted file mode 100644 index 3b8502923519..000000000000 --- a/code/modules/spells/no_clothes.dm +++ /dev/null @@ -1,5 +0,0 @@ -/spell/noclothes - name = "No Clothes" - desc = "Learn the ancient art of not wearing fancy robes while casting spells." - feedback = "NC" - spell_flags = NO_BUTTON \ No newline at end of file diff --git a/code/modules/spells/racial_wizard.dm b/code/modules/spells/racial_wizard.dm deleted file mode 100644 index 554b63c7f7a8..000000000000 --- a/code/modules/spells/racial_wizard.dm +++ /dev/null @@ -1,86 +0,0 @@ -//this file is full of all the racial spells/artifacts/etc that each species has. - -/obj/item/magic_rock - name = "magical rock" - desc = "Legends say that this rock will unlock the true potential of anyone who touches it." - icon = 'icons/obj/wizard.dmi' - icon_state = "magic rock" - w_class = ITEM_SIZE_SMALL - throw_speed = 1 - throw_range = 3 - force = 15 - var/list/potentials = list( - SPECIES_HUMAN = /obj/item/storage/bag/cash/infinite - ) - -/obj/item/magic_rock/attack_self(mob/user) - if(!istype(user,/mob/living/carbon/human)) - to_chat(user, "\The [src] can do nothing for such a simple being.") - return - var/mob/living/carbon/human/H = user - var/reward = potentials[H.species.get_root_species_name(H)] //we get body type because that lets us ignore subspecies. - if(!reward) - to_chat(user, "\The [src] does not know what to make of you.") - return - for(var/spell/S in user.mind.learned_spells) - if(istype(S,reward)) - to_chat(user, "\The [src] can do no more for you.") - return - var/a = new reward() - if(ispath(reward,/spell)) - H.add_spell(a) - else if(ispath(reward,/obj)) - H.put_in_hands(a) - to_chat(user, "\The [src] crumbles in your hands.") - qdel(src) - -/obj/item/storage/bag/cash/infinite - startswith = list(/obj/item/cash/c1000 = 1) - -//HUMAN -/obj/item/storage/bag/cash/infinite/remove_from_storage(obj/item/W, atom/new_location) - . = ..() - if(.) - if(istype(W,/obj/item/cash)) //only matters if its spacecash. - var/obj/item/I = new /obj/item/cash/c1000() - src.handle_item_insertion(I,1) - -/spell/messa_shroud/choose_targets() - return list(get_turf(holder)) - -/spell/messa_shroud/cast(var/list/targets, mob/user) - var/turf/T = targets[1] - - if(!istype(T)) - return - - var/obj/O = new /obj(T) - O.set_light(-10, 0.1, 10, 2, "#ffffff") - - spawn(duration) - qdel(O) - -/mob/observer/eye/freelook/wizard_eye - name_sufix = "Wizard Eye" - -/mob/observer/eye/freelook/wizard_eye/Initialize() - . = ..() //we dont use the Ai one because it has AI specific procs imbedded in it. - visualnet = cameranet - -/mob/living/proc/release_eye() - set name = "Release Vision" - set desc = "Return your sight to your body." - set category = "Abilities" - - verbs -= /mob/living/proc/release_eye //regardless of if we have an eye or not we want to get rid of this verb. - - if(!eyeobj) - return - eyeobj.release(src) - -/mob/observer/eye/freelook/wizard_eye/Destroy() - if(istype(eyeobj.owner, /mob/living)) - var/mob/living/L = eyeobj.owner - L.release_eye() - qdel(eyeobj) - return ..() \ No newline at end of file diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm deleted file mode 100644 index f43f03169229..000000000000 --- a/code/modules/spells/spell_code.dm +++ /dev/null @@ -1,402 +0,0 @@ -var/list/spells = typesof(/spell) //needed for the badmin verb for now - -/spell - var/name = "Spell" - var/desc = "A spell" - var/feedback = "" //what gets sent if this spell gets chosen by the spellbook. - parent_type = /datum - var/panel = "Spells"//What panel the proc holder needs to go on. - - var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit? - /*Spell schools as follows: - Racial - Only tagged to spells gained for being a certain race - Conjuration - Creating an object or transporting it. - Transmutation - Modifying an object or transforming it. - Illusion - Altering perception or thought. - */ - var/charge_type = Sp_RECHARGE //can be recharge or charges, see charge_max and charge_counter descriptions; can also be based on the holder's vars now, use "holder_var" for that - - var/charge_max = 100 //recharge time in deciseconds if charge_type = Sp_RECHARGE or starting charges if charge_type = Sp_CHARGES - var/charge_counter = 0 //can only cast spells if it equals recharge, ++ each decisecond if charge_type = Sp_RECHARGE or -- each cast if charge_type = Sp_CHARGES - var/still_recharging_msg = "The spell is still recharging." - - var/silenced = 0 //not a binary - the length of time we can't cast this for - var/processing = 0 //are we processing already? Mainly used so that silencing a spell doesn't call process() again. (and inadvertedly making it run twice as fast) - - var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var" - var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used - - var/spell_flags = NEEDSCLOTHES - var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell - var/invocation_type = SpI_NONE //can be none, whisper, shout, and emote - var/range = 7 //the range of the spell; outer radius for aoe spells - var/message = "" //whatever it says to the guy affected by it - var/selection_type = "view" //can be "range" or "view" - var/atom/movable/holder //where the spell is. Normally the user, can be an item - var/duration = 0 //how long the spell lasts - - var/list/spell_levels = list(Sp_SPEED = 0, Sp_POWER = 0) //the current spell levels - total spell levels can be obtained by just adding the two values - var/list/level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 0) //maximum possible levels in each category. Total does cover both. - var/cooldown_reduc = 0 //If set, defines how much charge_max drops by every speed upgrade - var/delay_reduc = 0 - var/cooldown_min = 0 //minimum possible cooldown for a charging spell - - var/overlay = 0 - var/overlay_icon = 'icons/obj/wizard.dmi' - var/overlay_icon_state = "spell" - var/overlay_lifespan = 0 - - var/sparks_spread = 0 - var/sparks_amt = 0 //cropped at 10 - var/smoke_spread = 0 //1 - harmless, 2 - harmful - var/smoke_amt = 0 //cropped at 10 - - var/critfailchance = 0 - var/time_between_channels = 0 //Delay between casts - var/number_of_channels = 1 //How many times can we channel? - - var/cast_delay = 1 - var/cast_sound = "" - - var/hud_state = "" //name of the icon used in generating the spell hud object - var/override_base = "" - - - var/mob/living/deity/connected_god //Do we have this spell based off a boon from a god? - var/obj/screen/connected_button - - var/hidden_from_codex = FALSE - -/////////////////////// -///SETUP AND PROCESS/// -/////////////////////// - -/spell/New() - ..() - - //still_recharging_msg = "[name] is still recharging." - charge_counter = charge_max - -/spell/proc/process() - if(processing) - return - processing = 1 - spawn(0) - while(charge_counter < charge_max || silenced > 0) - charge_counter = min(charge_max,charge_counter+1) - silenced = max(0,silenced-1) - sleep(1) - if(connected_button) - var/obj/screen/ability/spell/S = connected_button - if(!istype(S)) - return - S.update_charge(1) - processing = 0 - return - -///////////////// -/////CASTING///// -///////////////// - -/spell/proc/choose_targets(mob/user = usr) //depends on subtype - see targeted.dm, aoe_turf.dm, dumbfire.dm, or code in general folder - return - -/spell/proc/perform(mob/user = usr, skipcharge = 0) //if recharge is started is important for the trigger spells - if(!holder) - holder = user //just in case - if(!cast_check(skipcharge, user)) - return - if(cast_delay && !spell_do_after(user, cast_delay)) - return - var/list/targets = choose_targets(user) - if(!check_valid_targets(targets)) - return - var/time = 0 - admin_attacker_log(user, "attempted to cast the spell [name]") - do - time++ - if(!check_valid_targets(targets)) //make sure we HAVE something - break - if(cast_check(1,user, targets)) //we check again, otherwise you can choose a target and then wait for when you are no longer able to cast (I.E. Incapacitated) to use it. - invocation(user, targets) - if(connected_god && !connected_god.take_charge(user, max(1, charge_max/10))) - break - take_charge(user, skipcharge) - before_cast(targets) //applies any overlays and effects - if(prob(critfailchance)) - critfail(targets, user) - else - cast(targets, user, time) - after_cast(targets) //generates the sparks, smoke, target messages etc. - else - break - while(time != number_of_channels && do_after(user, time_between_channels, incapacitation_flags = INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING|INCAPACITATION_STUNNED, same_direction=1)) - after_spell(targets, user, time) //When we are done with the spell completely. - - - -/spell/proc/cast(list/targets, mob/user, var/channel_duration) //the actual meat of the spell - return - -/spell/proc/critfail(list/targets, mob/user) //the wizman has fucked up somehow - return - -/spell/proc/after_spell(var/list/targets, var/mob/user, var/channel_duration) //After everything else is done. - return - -/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types - switch(type) - if("bruteloss") - target.adjustBruteLoss(amount) - if("fireloss") - target.adjustFireLoss(amount) - if("toxloss") - target.adjustToxLoss(amount) - if("oxyloss") - target.adjustOxyLoss(amount) - if("brainloss") - target.adjustBrainLoss(amount) - if("stunned") - target.AdjustStunned(amount) - if("weakened") - target.AdjustWeakened(amount) - if("paralysis") - target.AdjustParalysis(amount) - else - target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars - return - -/////////////////////////// -/////CASTING WRAPPERS////// -/////////////////////////// - -/spell/proc/before_cast(list/targets) - for(var/atom/target in targets) - if(overlay) - var/location - if(istype(target,/mob/living)) - location = target.loc - else if(istype(target,/turf)) - location = target - var/obj/effect/overlay/spell = new /obj/effect/overlay(location) - spell.icon = overlay_icon - spell.icon_state = overlay_icon_state - spell.anchored = 1 - spell.set_density(0) - spawn(overlay_lifespan) - qdel(spell) - -/spell/proc/after_cast(list/targets) - if(cast_sound) - playsound(get_turf(holder),cast_sound,50,1) - for(var/atom/target in targets) - var/location = get_turf(target) - if(istype(target,/mob/living) && message) - to_chat(target, text("[message]")) - if(sparks_spread) - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(sparks_amt, 0, location) //no idea what the 0 is - sparks.start() - if(smoke_spread) - if(smoke_spread == 1) - var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() - smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is - smoke.start() - else if(smoke_spread == 2) - var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() - smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is - smoke.start() - -///////////////////// -////CASTING TOOLS//// -///////////////////// -/*Checkers, cost takers, message makers, etc*/ - -/spell/proc/cast_check(skipcharge = 0,mob/user = usr, var/list/targets) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell - - if(silenced > 0) - return 0 - - if(!(src in user.mind.learned_spells) && holder == user && !(isanimal(user))) - error("[user] utilized the spell '[src]' without having it.") - to_chat(user, "You shouldn't have this spell! Something's wrong.") - return 0 - - var/turf/user_turf = get_turf(user) - if(!user_turf) - to_chat(user, "You cannot cast spells in null space!") - - if((spell_flags & Z2NOCAST) && (user_turf.z in GLOB.using_map.admin_levels)) //Certain spells are not allowed on the centcomm zlevel - return 0 - - if(spell_flags & CONSTRUCT_CHECK) - for(var/turf/T in range(holder, 1)) - if(findNullRod(T)) - return 0 - - if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone - return 0 - - if(holder == user) - if(istype(user, /mob/living/simple_animal)) - var/mob/living/simple_animal/SA = user - if(SA.purge) - to_chat(SA, "The null sceptre's power interferes with your own!") - return 0 - - if(!(spell_flags & GHOSTCAST)) - if(!(spell_flags & NO_SOMATIC)) - var/mob/living/L = user - if(L.incapacitated(INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING|INCAPACITATION_KNOCKOUT)) - to_chat(user, "You can't cast spells while incapacitated!") - return 0 - - if(ishuman(user) && !(invocation_type in list(SpI_EMOTE, SpI_NONE))) - if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) - to_chat(user, "Mmmf mrrfff!") - return 0 - - var/spell/noclothes/spell = locate() in user.mind.learned_spells - if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)))//clothes check - if(!user.wearing_wiz_garb()) - return 0 - - return 1 - -/spell/proc/check_charge(var/skipcharge, mob/user) - if(!skipcharge) - switch(charge_type) - if(Sp_RECHARGE) - if(charge_counter < charge_max) - to_chat(user, still_recharging_msg) - return 0 - if(Sp_CHARGES) - if(!charge_counter) - to_chat(user, "[name] has no charges left.") - return 0 - return 1 - -/spell/proc/take_charge(mob/user = user, var/skipcharge) - if(!skipcharge) - switch(charge_type) - if(Sp_RECHARGE) - charge_counter = 0 //doesn't start recharging until the targets selecting ends - src.process() - return 1 - if(Sp_CHARGES) - charge_counter-- //returns the charge if the targets selecting fails - return 1 - if(Sp_HOLDVAR) - adjust_var(user, holder_var_type, holder_var_amount) - return 1 - return 0 - return 1 - -/spell/proc/check_valid_targets(var/list/targets) - if(!targets) - return 0 - if(!islist(targets)) - targets = list(targets) - else if(!targets.len) - return 0 - - var/list/valid_targets = view_or_range(range, holder, selection_type) - for(var/target in targets) - if(!(target in valid_targets)) - return 0 - return 1 - -/spell/proc/invocation(mob/user = usr, var/list/targets) //spelling the spell out and setting it on recharge/reducing charges amount - - switch(invocation_type) - if(SpI_SHOUT) - if(prob(50))//Auto-mute? Fuck that noise - user.say(invocation) - else - user.say(replacetext(invocation," ","`")) - if(SpI_WHISPER) - if(prob(50)) - user.whisper(invocation) - else - user.whisper(replacetext(invocation," ","`")) - if(SpI_EMOTE) - user.custom_emote(VISIBLE_MESSAGE, invocation) - -///////////////////// -///UPGRADING PROCS/// -///////////////////// - -/spell/proc/can_improve(var/upgrade_type) - if(level_max[Sp_TOTAL] <= ( spell_levels[Sp_SPEED] + spell_levels[Sp_POWER] )) //too many levels, can't do it - return 0 - - //if(upgrade_type && spell_levels[upgrade_type] && level_max[upgrade_type]) - if(upgrade_type && spell_levels[upgrade_type] >= level_max[upgrade_type]) - return 0 - - return 1 - -/spell/proc/empower_spell() - if(!can_improve(Sp_POWER)) - return 0 - - spell_levels[Sp_POWER]++ - - return 1 - -/spell/proc/quicken_spell() - if(!can_improve(Sp_SPEED)) - return 0 - - spell_levels[Sp_SPEED]++ - - if(delay_reduc && cast_delay) - cast_delay = max(0, cast_delay - delay_reduc) - else if(cast_delay) - cast_delay = round( max(0, initial(cast_delay) * ((level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) / level_max[Sp_SPEED] ) ) ) - - if(charge_type == Sp_RECHARGE) - if(cooldown_reduc) - charge_max = max(cooldown_min, charge_max - cooldown_reduc) - else - charge_max = round( max(cooldown_min, initial(charge_max) * ((level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) / level_max[Sp_SPEED] ) ) ) //the fraction of the way you are to max speed levels is the fraction you lose - if(charge_max < charge_counter) - charge_counter = charge_max - - var/temp = "" - name = initial(name) - switch(level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) - if(3) - temp = "You have improved [name] into Efficient [name]." - name = "Efficient [name]" - if(2) - temp = "You have improved [name] into Quickened [name]." - name = "Quickened [name]" - if(1) - temp = "You have improved [name] into Free [name]." - name = "Free [name]" - if(0) - temp = "You have improved [name] into Instant [name]." - name = "Instant [name]" - - return temp - -/spell/proc/spell_do_after(var/mob/user, delay, var/numticks = 5) - if(!user || isnull(user)) - return 0 - - var/incap_flags = INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING - if(!(spell_flags & (GHOSTCAST))) - incap_flags |= INCAPACITATION_KNOCKOUT - - return do_after(user,delay, incapacitation_flags = incap_flags) - -/spell/proc/set_connected_god(var/mob/living/deity/god) - connected_god = god - -/proc/view_or_range(distance = world.view , center = usr , type) - switch(type) - if("view") - . = view(distance,center) - if("range") - . = range(distance,center) \ No newline at end of file diff --git a/code/modules/spells/spell_projectile.dm b/code/modules/spells/spell_projectile.dm deleted file mode 100644 index 1599a59d3a78..000000000000 --- a/code/modules/spells/spell_projectile.dm +++ /dev/null @@ -1,56 +0,0 @@ -/obj/item/projectile/spell_projectile - name = "spell" - icon = 'icons/obj/projectiles.dmi' - - nodamage = 1 //Most of the time, anyways - - var/spell/targeted/projectile/carried - - penetrating = 0 - life_span = 10 //set by the duration of the spell - - var/proj_trail = 0 //if it leaves a trail - var/proj_trail_lifespan = 0 //deciseconds - var/proj_trail_icon = 'icons/obj/wizard.dmi' - var/proj_trail_icon_state = "trail" - var/list/trails = new() - -/obj/item/projectile/spell_projectile/Destroy() - for(var/trail in trails) - qdel(trail) - carried = null - return ..() - -/obj/item/projectile/spell_projectile/explosion_act() - SHOULD_CALL_PARENT(FALSE) - return - -/obj/item/projectile/spell_projectile/before_move() - if(proj_trail && src && src.loc) //pretty trails - var/obj/effect/overlay/trail = new /obj/effect/overlay(loc) - trails += trail - trail.icon = proj_trail_icon - trail.icon_state = proj_trail_icon_state - trail.set_density(0) - spawn(proj_trail_lifespan) - trails -= trail - qdel(trail) - -/obj/item/projectile/spell_projectile/proc/prox_cast(var/list/targets) - if(loc) - carried.prox_cast(targets, src) - qdel(src) - return - -/obj/item/projectile/spell_projectile/Bump(var/atom/A, forced=0) - if(loc && carried) - prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src)) - return 1 - -/obj/item/projectile/spell_projectile/on_impact() - if(loc && carried) - prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src)) - return 1 - -/obj/item/projectile/spell_projectile/seeking - name = "seeking spell" diff --git a/code/modules/spells/spellbook.dm b/code/modules/spells/spellbook.dm deleted file mode 100644 index 282d1b5e7687..000000000000 --- a/code/modules/spells/spellbook.dm +++ /dev/null @@ -1,308 +0,0 @@ -#define NOREVERT 1 -#define LOCKED 2 -#define CAN_MAKE_CONTRACTS 4 -#define INVESTABLE 8 -#define NO_LOCKING 16 - -//spells/spellbooks have a variable for this but as artefacts are literal items they do not. -//so we do this instead. -var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS", - /obj/item/gun/energy/staff/focus = "MF", - /obj/item/summoning_stone = "ST", - /obj/item/magic_rock = "RA", - /obj/item/contract/apprentice = "CP", - /obj/structure/closet/wizard/souls = "SS", - /obj/structure/closet/wizard/scrying = "SO", - /obj/item/teleportation_scroll = "TS", - /obj/item/gun/energy/staff = "ST", - /obj/item/gun/energy/staff/animate = "SA", - /obj/item/dice/d20/cursed = "DW") - -/obj/item/spellbook - name = "master spell book" - desc = "The legendary book of spells of the wizard." - icon = 'icons/obj/library.dmi' - icon_state = "book" - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_NORMAL - var/uses = 1 - var/temp = null - var/datum/spellbook/spellbook - var/spellbook_type = /datum/spellbook/ //for spawning specific spellbooks. - var/investing_time = 0 //what time we target forr a return on our spell investment. - var/has_sacrificed = 0 //whether we have already got our sacrifice bonus for the current investment. - -/obj/item/spellbook/Initialize() - . = ..() - set_spellbook(spellbook_type) - -/obj/item/spellbook/proc/set_spellbook(var/type) - if(spellbook) - qdel(spellbook) - spellbook = new type() - uses = spellbook.max_uses - name = spellbook.name - desc = spellbook.desc - -/obj/item/spellbook/attack_self(mob/user) - if(!user.mind) - return - if (user.mind.special_role != ANTAG_WIZARD) - if (user.mind.special_role != ANTAG_APPRENTICE) - to_chat(user, "You can't make heads or tails of this book.") - return - if (spellbook.book_flags & LOCKED) - to_chat(user, "Drat! This spellbook's apprentice-proof lock is on!") - return - else if (spellbook.book_flags & LOCKED) - to_chat(user, "You notice the apprentice-proof lock is on. Luckily you are beyond such things.") - interact(user) - -/obj/item/spellbook/proc/make_sacrifice(obj/item/I, mob/user, var/reagent) - if(has_sacrificed) - return - if(reagent) - var/datum/reagents/R = I.reagents - R.remove_reagent(reagent,5) - else - if(istype(I,/obj/item/stack)) - var/obj/item/stack/S = I - if(S.amount < S.max_amount) - to_chat(usr, "You must sacrifice [S.max_amount] stacks of [S]!") - return - qdel(I) - to_chat(user, "Your sacrifice was accepted!") - has_sacrificed = 1 - investing_time = max(investing_time - 6000,1) //subtract 10 minutes. Make sure it doesn't act funky at the beginning of the game. - - -/obj/item/spellbook/attackby(obj/item/I, mob/user) - if(investing_time && !has_sacrificed) - var/list/objects = spellbook.sacrifice_objects - if(objects && objects.len) - for(var/type in objects) - if(istype(I,type)) - make_sacrifice(I,user) - return - if(I.reagents) - var/datum/reagents/R = I.reagents - for(var/id in spellbook.sacrifice_reagents) - if(R.has_reagent(id,5)) - make_sacrifice(I,user, id) - return 1 - ..() - -/obj/item/spellbook/interact(mob/user) - var/dat = null - if(temp) - dat = "[temp]
    Return" - else - dat = "

    [spellbook.title]

    [spellbook.title_desc]
    You have [uses] spell slot[uses > 1 ? "s" : ""] left.

    " - dat += "
    Requires Wizard Garb
    Selectable Target
    Spell Charge Type: Recharge, Sacrifice, Charges

    " - dat += "
    To use a contract, first bind it to your soul, then give it to someone to sign. This will bind their soul to you.

    " - for(var/i in 1 to spellbook.spells.len) - var/name = "" //name of target - var/desc = "" //description of target - var/info = "" //additional information - if(ispath(spellbook.spells[i],/datum/spellbook)) - var/datum/spellbook/S = spellbook.spells[i] - name = initial(S.name) - desc = initial(S.book_desc) - info = "[initial(S.max_uses)] Spell Slots" - else if(ispath(spellbook.spells[i],/obj)) - var/obj/O = spellbook.spells[i] - name = "Artefact: [capitalize(initial(O.name))]" //because 99.99% of objects dont have capitals in them and it makes it look weird. - desc = initial(O.desc) - else if(ispath(spellbook.spells[i],/spell)) - var/spell/S = spellbook.spells[i] - name = initial(S.name) - desc = initial(S.desc) - var/testing = initial(S.spell_flags) - if(testing & NEEDSCLOTHES) - info = "W" - var/type = "" - switch(initial(S.charge_type)) - if(Sp_RECHARGE) - type = "R" - if(Sp_HOLDVAR) - type = "S" - if(Sp_CHARGES) - type = "C" - info += "[type]" - dat += "[name]" - if(length(info)) - dat += " ([info])" - dat += " ([spellbook.spells[spellbook.spells[i]]] spell slot[spellbook.spells[spellbook.spells[i]] > 1 ? "s" : "" ])" - if(spellbook.book_flags & CAN_MAKE_CONTRACTS) - dat += " Make Contract" - dat += "
    [desc]
    " - dat += "
    Re-memorize your spellbook.
    " - if(spellbook.book_flags & INVESTABLE) - if(investing_time) - dat += "
    Currently investing in a slot...
    " - else - dat += "
    Invest a Spell Slot
    Investing a spellpoint will return two spellpoints back in 15 minutes.
    Some say a sacrifice could even shorten the time...
    " - if(!(spellbook.book_flags & NOREVERT)) - dat += "
    Choose different spellbook.
    " - if(!(spellbook.book_flags & NO_LOCKING)) - dat += "
    [spellbook.book_flags & LOCKED ? "Unlock" : "Lock"] the spellbook.
    " - show_browser(user, dat, "window=spellbook") - -/obj/item/spellbook/CanUseTopic(var/mob/living/carbon/human/H) - if(!istype(H)) - return STATUS_CLOSE - - if(H.mind && (spellbook.book_flags & LOCKED) && H.mind.special_role == ANTAG_APPRENTICE) //make sure no scrubs get behind the lock - return STATUS_CLOSE - - return ..() - -/obj/item/spellbook/OnTopic(var/mob/living/carbon/human/user, href_list) - if(href_list["lock"] && !(spellbook.book_flags & NO_LOCKING)) - if(spellbook.book_flags & LOCKED) - spellbook.book_flags &= ~LOCKED - else - spellbook.book_flags |= LOCKED - . = TOPIC_REFRESH - - else if(href_list["temp"]) - temp = null - . = TOPIC_REFRESH - - else if(href_list["book"]) - if(initial(spellbook.max_uses) != spellbook.max_uses || uses != spellbook.max_uses) - temp = "You've already purchased things using this spellbook!" - else - src.set_spellbook(/datum/spellbook) - temp = "You have reverted back to the Book of Tomes." - . = TOPIC_REFRESH - - else if(href_list["invest"]) - temp = invest() - . = TOPIC_REFRESH - - else if(href_list["path"]) - var/path = locate(href_list["path"]) in spellbook.spells - if(!path) - return TOPIC_HANDLED - if(uses < spellbook.spells[path]) - to_chat(user, "You do not have enough spell slots to purchase this.") - return TOPIC_HANDLED - send_feedback(path) //feedback stuff - if(ispath(path,/datum/spellbook)) - src.set_spellbook(path) - temp = "You have chosen a new spellbook." - else - if(href_list["contract"]) - if(!(spellbook.book_flags & CAN_MAKE_CONTRACTS)) - return //no - uses -= spellbook.spells[path] - spellbook.max_uses -= spellbook.spells[path] //no basksies - var/obj/O = new /obj/item/contract/boon(get_turf(user),path) - temp = "You have purchased \the [O]." - else - if(ispath(path,/spell)) - temp = src.add_spell(user,path) - if(temp) - uses -= spellbook.spells[path] - else - var/obj/O = new path(get_turf(user)) - temp = "You have purchased \a [O]." - uses -= spellbook.spells[path] - spellbook.max_uses -= spellbook.spells[path] - //finally give it a bit of an oomf - playsound(get_turf(user),'sound/effects/phasein.ogg',50,1) - . = TOPIC_REFRESH - - else if(href_list["reset"] && !(spellbook.book_flags & NOREVERT)) - var/area/map_template/wizard_station/A = get_area(user) - if(istype(A)) - uses = spellbook.max_uses - investing_time = 0 - has_sacrificed = 0 - user.spellremove() - temp = "All spells and investments have been removed. You may now memorize a new set of spells." - SSstatistics.add_field_details("wizard_spell_learned","UM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells - else - to_chat(user, "You must be in the wizard academy to re-memorize your spells.") - . = TOPIC_REFRESH - - src.interact(user) - -/obj/item/spellbook/proc/invest() - if(uses < 1) - return "You don't have enough slots to invest!" - if(investing_time) - return "You can only invest one spell slot at a time." - uses-- - START_PROCESSING(SSobj, src) - investing_time = world.time + (15 MINUTES) - return "You invest a spellslot and will recieve two in return in 15 minutes." - -/obj/item/spellbook/Process() - if(investing_time && investing_time <= world.time) - src.visible_message("\The [src] emits a soft chime.") - uses += 2 - if(uses > spellbook.max_uses) - spellbook.max_uses = uses - investing_time = 0 - has_sacrificed = 0 - STOP_PROCESSING(SSobj, src) - return 1 - -/obj/item/spellbook/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/spellbook/proc/send_feedback(var/path) - if(ispath(path,/datum/spellbook)) - var/datum/spellbook/S = path - SSstatistics.add_field_details("wizard_spell_learned","[initial(S.feedback)]") - else if(ispath(path,/spell)) - var/spell/S = path - SSstatistics.add_field_details("wizard_spell_learned","[initial(S.feedback)]") - else if(ispath(path,/obj)) - SSstatistics.add_field_details("wizard_spell_learned","[artefact_feedback[path]]") - - -/obj/item/spellbook/proc/add_spell(var/mob/user, var/spell_path) - for(var/spell/S in user.mind.learned_spells) - if(istype(S,spell_path)) - if(!S.can_improve()) - return - if(S.can_improve(Sp_SPEED) && S.can_improve(Sp_POWER)) - switch(alert(user, "Do you want to upgrade this spell's speed or power?", "Spell upgrade", "Speed", "Power", "Cancel")) - if("Speed") - return S.quicken_spell() - if("Power") - return S.empower_spell() - else - return - else if(S.can_improve(Sp_POWER)) - return S.empower_spell() - else if(S.can_improve(Sp_SPEED)) - return S.quicken_spell() - - var/spell/S = new spell_path() - user.add_spell(S) - return "You learn the spell [S]" - -/datum/spellbook - var/name = "\improper Book of Tomes" - var/desc = "The legendary book of spells of the wizard." - var/book_desc = "Holds information on the various tomes available to a wizard" - var/feedback = "" //doesn't need one. - var/book_flags = NOREVERT - var/max_uses = 1 - var/title = "Book of Tomes" - var/title_desc = "This tome marks down all the available tomes for use. Choose wisely, there are no refunds." - var/list/spells = list(/datum/spellbook/standard = 1, - /datum/spellbook/cleric = 1, - /datum/spellbook/battlemage = 1, - /datum/spellbook/spatial = 1, - /datum/spellbook/druid = 1 - ) //spell's path = cost of spell - - var/list/sacrifice_reagents - var/list/sacrifice_objects diff --git a/code/modules/spells/spellbook/battlemage.dm b/code/modules/spells/spellbook/battlemage.dm deleted file mode 100644 index 6e0fc3e30a95..000000000000 --- a/code/modules/spells/spellbook/battlemage.dm +++ /dev/null @@ -1,43 +0,0 @@ -//Battlemage is all about mixing physical with the mystical in head to head combat. -//Things like utility and mobility come second. -/datum/spellbook/battlemage - name = "\improper Battlemage's Bible" - feedback = "BM" - desc = "Smells like blood." - book_desc = "Mix physical with the mystical in head to head combat." - title = "The Art of Magical Combat" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 6 - - spells = list(/spell/targeted/projectile/dumbfire/passage = 1, - /spell/targeted/equip_item/dyrnwyn = 1, - /spell/targeted/equip_item/shield = 1, - /spell/targeted/projectile/dumbfire/fireball = 1, - /spell/targeted/torment = 1, - /spell/targeted/heal_target = 2, - /spell/targeted/genetic/mutate = 1, - /spell/aoe_turf/conjure/mirage = 1, - /spell/targeted/shapeshift/corrupt_form = 1, - /spell/radiant_aura = 1, - /spell/noclothes = 1, - /obj/structure/closet/wizard/armor = 1, - /obj/item/gun/energy/staff/focus = 1, - /obj/item/dice/d20/cursed = 1, - /obj/item/summoning_stone = 2, - /obj/item/magic_rock = 1, - /obj/item/contract/wizard/xray = 1, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_objects = list( - /obj/item/sword, - /obj/item/twohanded/fireaxe, - /obj/item/baton, - /obj/item/knife/ritual, - /obj/item/knife/kitchen/cleaver, - /obj/item/knife/folding/combat/balisong, - /obj/item/knife/folding/tacticool, - /obj/item/star - ) diff --git a/code/modules/spells/spellbook/cleric.dm b/code/modules/spells/spellbook/cleric.dm deleted file mode 100644 index f6bbf12d0ce9..000000000000 --- a/code/modules/spells/spellbook/cleric.dm +++ /dev/null @@ -1,45 +0,0 @@ -//Cleric is all about healing. Mobility and offense comes at a higher price but not impossible. -/obj/item/spellbook/cleric - spellbook_type = /datum/spellbook/cleric - -/datum/spellbook/cleric - name = "\improper Cleric's Tome" - feedback = "CR" - desc = "For those who do not harm, or at least feel sorry about it." - book_desc = "All about healing. Mobility and offense comes at a higher price but not impossible." - title = "Cleric's Tome of Healing" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 7 - - spells = list(/spell/targeted/heal_target/major = 1, - /spell/targeted/heal_target/area = 1, - /spell/targeted/heal_target/sacrifice = 1, - /spell/targeted/genetic/blind = 1, - /spell/targeted/shapeshift/baleful_polymorph = 1, - /spell/targeted/projectile/dumbfire/stuncuff = 1, - /spell/targeted/ethereal_jaunt = 2, - /spell/aoe_turf/knock = 1, - /spell/radiant_aura = 1, - /spell/targeted/equip_item/holy_relic = 1, - /spell/aoe_turf/conjure/grove/sanctuary = 1, - /spell/targeted/projectile/dumbfire/fireball = 2, - /spell/area_teleport = 2, - /spell/portal_teleport = 2, - /spell/aoe_turf/conjure/forcewall = 1, - /spell/noclothes = 1, - /obj/item/magic_rock = 1, - /obj/structure/closet/wizard/scrying = 2, - /obj/item/summoning_stone = 2, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_reagents = list(/decl/material/liquid/adminordrazine) - sacrifice_objects = list(/obj/item/stack/nanopaste, - /obj/item/scanner/health, - /obj/item/stack/medical/advanced/bruise_pack, - /obj/item/stack/medical/advanced/ointment, - /obj/item/bodybag/rescue, - /obj/item/defibrillator - ) diff --git a/code/modules/spells/spellbook/druid.dm b/code/modules/spells/spellbook/druid.dm deleted file mode 100644 index 763c101e569a..000000000000 --- a/code/modules/spells/spellbook/druid.dm +++ /dev/null @@ -1,41 +0,0 @@ -//all about the summons, nature, and a bit o' healin. - -/obj/item/spellbook/druid - spellbook_type = /datum/spellbook/druid - -/datum/spellbook/druid - name = "\improper Druid's Leaflet" - feedback = "DL" - desc = "It smells like an air freshener." - book_desc = "Summons, nature, and a bit o' healin." - title = "Druidic Guide on how to be smug about nature" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 6 - - spells = list(/spell/targeted/heal_target = 1, - /spell/targeted/heal_target/sacrifice = 1, - /spell/aoe_turf/conjure/mirage = 1, - /spell/aoe_turf/conjure/summon/bats = 1, - /spell/aoe_turf/conjure/summon/bear = 1, - /spell/targeted/equip_item/party_hardy = 1, - /spell/targeted/equip_item/seed = 1, - /spell/targeted/shapeshift/avian = 1, - /spell/aoe_turf/disable_tech = 1, - /spell/hand/charges/entangle = 1, - /spell/aoe_turf/conjure/grove/sanctuary = 1, - /spell/aoe_turf/knock = 1, - /spell/area_teleport = 2, - /spell/portal_teleport = 2, - /spell/noclothes = 1, - /obj/structure/closet/wizard/souls = 1, - /obj/item/magic_rock = 1, - /obj/item/summoning_stone = 2, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - sacrifice_objects = list(/obj/item/seeds, - /obj/item/wirecutters/clippers, - /obj/item/scanner/plant, - /obj/item/hatchet, - /obj/item/minihoe) diff --git a/code/modules/spells/spellbook/spatial.dm b/code/modules/spells/spellbook/spatial.dm deleted file mode 100644 index 4673e2ef10ab..000000000000 --- a/code/modules/spells/spellbook/spatial.dm +++ /dev/null @@ -1,41 +0,0 @@ -//all about moving around and mobility and being an annoying shit. - -/obj/item/spellbook/spatial - spellbook_type = /datum/spellbook/spatial - -/datum/spellbook/spatial - name = "\improper Spatial Manual" - feedback = "SP" - desc = "You feel like this might disappear from out of under you." - book_desc = "Movement and teleportation. Run from your problems!" - title = "Manual of Spatial Transportation" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 11 - - spells = list(/spell/targeted/ethereal_jaunt = 1, - /spell/aoe_turf/blink = 1, - /spell/area_teleport = 1, - /spell/portal_teleport = 1, - /spell/targeted/projectile/dumbfire/passage = 1, - /spell/mark_recall = 1, - /spell/targeted/swap = 1, - /spell/targeted/shapeshift/avian = 1, - /spell/targeted/projectile/magic_missile = 1, - /spell/targeted/heal_target = 1, - /spell/aoe_turf/conjure/forcewall = 1, - /spell/aoe_turf/smoke = 1, - /spell/aoe_turf/conjure/summon/bats = 3, - /spell/noclothes = 1, - /obj/item/dice/d20/cursed = 1, - /obj/structure/closet/wizard/scrying = 2, - /obj/item/teleportation_scroll = 1, - /obj/item/magic_rock = 1, - /obj/item/summoning_stone = 3, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_reagents = list(/decl/material/liquid/amphetamines) - sacrifice_objects = list(/obj/item/stack/telecrystal, - /obj/item/stack/material/diamond) \ No newline at end of file diff --git a/code/modules/spells/spellbook/standard.dm b/code/modules/spells/spellbook/standard.dm deleted file mode 100644 index 25fe39e18470..000000000000 --- a/code/modules/spells/spellbook/standard.dm +++ /dev/null @@ -1,52 +0,0 @@ -//the spellbook we know and love. Well, the one we know, at least. - -/obj/item/spellbook/standard - spellbook_type = /datum/spellbook/standard - -/datum/spellbook/standard - name = "\improper Standard Spellbook" - feedback = "SB" - title = "Book of Spells and Artefacts" - title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent." - book_desc = "A general wizard's spellbook. All its spells are easy to use but hard to master." - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 6 - - spells = list(/spell/targeted/projectile/magic_missile = 1, - /spell/targeted/projectile/dumbfire/fireball = 1, - /spell/aoe_turf/disable_tech = 1, - /spell/aoe_turf/smoke = 1, - /spell/targeted/genetic/blind = 1, - /spell/targeted/subjugation = 1, - /spell/aoe_turf/conjure/forcewall = 1, - /spell/aoe_turf/blink = 1, - /spell/area_teleport = 1, - /spell/targeted/genetic/mutate = 1, - /spell/targeted/ethereal_jaunt = 1, - /spell/targeted/heal_target = 1, - /spell/aoe_turf/knock = 1, - /spell/noclothes = 2, - /obj/item/gun/energy/staff/focus = 1, - /obj/structure/closet/wizard/souls = 1, - /obj/item/gun/energy/staff/animate = 1, - /obj/structure/closet/wizard/scrying = 1, - /obj/item/summoning_stone = 2, - /obj/item/magic_rock = 1, - /obj/item/contract/wizard/telepathy = 1, - /obj/item/contract/apprentice = 1 - ) - - sacrifice_objects = list(/obj/item/storage/toolbox, - /obj/item/cane, - /obj/item/flamethrower, - /obj/item/plastique, - /obj/item/dice, - /obj/item/soap, - /obj/item/flame/candle, - /obj/item/flame/candle/scented/incense, - /obj/item/caution, - /obj/item/towel, - /obj/item/tank/jetpack, - /obj/item/clothing/mask/plunger, - /obj/item/megaphone, - /obj/item/deck/cards) \ No newline at end of file diff --git a/code/modules/spells/spellbook/student.dm b/code/modules/spells/spellbook/student.dm deleted file mode 100644 index f738ac6a3747..000000000000 --- a/code/modules/spells/spellbook/student.dm +++ /dev/null @@ -1,27 +0,0 @@ -//wizard's training wheels. Basically. Same shit as in the general one. - -/obj/item/spellbook/student - spellbook_type = /datum/spellbook/student - -/datum/spellbook/student - name = "\improper Student's Spellbook" - feedback = "ST" - desc = "This spell book has a sticker on it that says, 'certified for children 5 and older'." - book_desc = "This spellbook is dedicated to teaching neophytes in the ways of magic." - title = "Book of Spells and Education" - title_desc = "Hello. Congratulations on becoming a wizard. You may be asking yourself: What? A wizard? Already? Of course! Anybody can become a wizard! Learning to be a good one is the hard part.
    Without further adue, let us begin by learning the three concepts of wizardry, 'Spell slots', 'Spells', and 'Artifacts'.
    Firstly lets try to understand the 'spell slot'. A spell slot is the measurable amount of spells and artifacts one tome can give. Most spells will only take up a singular spell slot, however more powerful spells/artifacts can take up more.
    Spells are spells. They can have requirements, such as wizard garb, and most can be upgraded by purchasing additional spell slots for them. Most upgrades fall into two categories, 'Speed' and 'Power'. Speed upgrades decrease the time you have to spend recharging your spell. Power increases the potency of your spells. Spells are also special in that they can be refunded while inside the Wizard Acadamy, so if you want to test a spell out before moving out into the field, feel free to do that in the comfort of our home.
    Artifacts, or 'Artefacts' as we call them, are powerful wizard tools or items made specially for wizards everywhere. Extremely potent, they cannot be refunded like spells, and some of them can be used by non-wizards, so be careful!
    Knowing these three concepts puts you in a league above most wizards, however knowledge of spells is just as important so we've included a list of spells below made specifically for the beginning wizard. Take all of them, or mix and match, remember being creative is half of being a wizard!" - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE - max_uses = 5 - - spells = list(/spell/aoe_turf/knock = 1, - /spell/targeted/ethereal_jaunt = 1, - /spell/targeted/projectile/magic_missile = 1, - /obj/item/gun/energy/staff/focus = 1, - /obj/item/contract/wizard/xray = 1 - ) - -/datum/spellbook/student/apprentice - book_flags = CAN_MAKE_CONTRACTS|INVESTABLE|NOREVERT|NO_LOCKING - -/obj/item/spellbook/apprentice - spellbook_type = /datum/spellbook/student/apprentice \ No newline at end of file diff --git a/code/modules/spells/spells.dm b/code/modules/spells/spells.dm deleted file mode 100644 index cde9475a2285..000000000000 --- a/code/modules/spells/spells.dm +++ /dev/null @@ -1,71 +0,0 @@ -/datum/mind - var/list/learned_spells - -/mob/Stat() - . = ..() - if(. && ability_master && ability_master.spell_objects) - for(var/obj/screen/ability/spell/screen in ability_master.spell_objects) - var/spell/S = screen.spell - if((!S.connected_button) || !statpanel(S.panel)) - continue //Not showing the noclothes spell - switch(S.charge_type) - if(Sp_RECHARGE) - statpanel(S.panel,"[S.charge_counter/10.0]/[S.charge_max/10]",S.connected_button) - if(Sp_CHARGES) - statpanel(S.panel,"[S.charge_counter]/[S.charge_max]",S.connected_button) - if(Sp_HOLDVAR) - statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S.connected_button) - -//A fix for when a spell is created before a mob is created -/mob/Login() - . = ..() - if(mind) - if(!mind.learned_spells) - mind.learned_spells = list() - if(ability_master && ability_master.spell_objects) - for(var/obj/screen/ability/spell/screen in ability_master.spell_objects) - var/spell/S = screen.spell - mind.learned_spells |= S - -proc/restore_spells(var/mob/H) - if(H.mind && H.mind.learned_spells) - var/list/spells = list() - for(var/spell/spell_to_remove in H.mind.learned_spells) //remove all the spells from other people. - if(istype(spell_to_remove.holder,/mob)) - var/mob/M = spell_to_remove.holder - spells += spell_to_remove - M.remove_spell(spell_to_remove) - - for(var/spell/spell_to_add in spells) - H.add_spell(spell_to_add) - H.ability_master.update_abilities(0,H) - -/mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready") - if(!ability_master) - ability_master = new() - spell_to_add.holder = src - if(mind) - if(!mind.learned_spells) - mind.learned_spells = list() - mind.learned_spells |= spell_to_add - ability_master.add_spell(spell_to_add, spell_base) - return 1 - -/mob/proc/remove_spell(var/spell/spell_to_remove) - if(!spell_to_remove || !istype(spell_to_remove)) - return - - if(mind) - mind.learned_spells -= spell_to_remove - if (ability_master) - ability_master.remove_ability(ability_master.get_ability_by_spell(spell_to_remove)) - return 1 - -/mob/proc/silence_spells(var/amount = 0) - if(amount < 0) - return - - if(!ability_master) - return - - ability_master.silence_spells(amount) \ No newline at end of file diff --git a/code/modules/spells/targeted/analyze.dm b/code/modules/spells/targeted/analyze.dm deleted file mode 100644 index 60ac45369305..000000000000 --- a/code/modules/spells/targeted/analyze.dm +++ /dev/null @@ -1,19 +0,0 @@ -/spell/targeted/analyze - name = "Analyze" - desc = "Using your wizardly powers, you can detect the inner destructions of a persons body." - - feedback = "AZ" - school = "illusion" - charge_max = 100 - spell_flags = INCLUDEUSER|SELECTABLE - range = 2 - invocation_type = SpI_WHISPER - invocation = "Fu Yi Fim" - compatible_mobs = list(/mob/living/carbon/human) - hud_state = "analyze" - -/spell/targeted/analyze/cast(var/list/targets, var/mob/user) - for(var/a in targets) - var/mob/living/carbon/human/H = a - new /obj/effect/temporary(get_turf(a),5, 'icons/effects/effects.dmi', "repel_missiles") - to_chat(user,medical_scan_results(H,1)) \ No newline at end of file diff --git a/code/modules/spells/targeted/blood_boil.dm b/code/modules/spells/targeted/blood_boil.dm deleted file mode 100644 index cecc5c17b8c3..000000000000 --- a/code/modules/spells/targeted/blood_boil.dm +++ /dev/null @@ -1,25 +0,0 @@ -/spell/targeted/blood_boil - name = "Blood Boil" - desc = "This spell allows the caster to heat up an adversary's body so much their blood boils." - feedback = "BO" - school = "transmutation" - charge_max = 300 - spell_flags = 0 - invocation_type = SpI_NONE - range = 5 - max_targets = 1 - compatible_mobs = list(/mob/living/carbon/human) - - time_between_channels = 50 - number_of_channels = 0 - - hud_state = "wiz_boilblood" - -/spell/targeted/blood_boil/cast(var/list/targets, var/mob/user) - var/mob/living/carbon/human/H = targets[1] - H.bodytemperature += 40 - if(prob(10)) - to_chat(H,"\The [user] seems to radiate an uncomfortable amount of heat your direction.") - if(H.bodytemperature > H.getSpeciesOrSynthTemp(HEAT_LEVEL_3)) //Burst into flames - H.fire_stacks += 50 - H.IgniteMob() \ No newline at end of file diff --git a/code/modules/spells/targeted/cleric_spells.dm b/code/modules/spells/targeted/cleric_spells.dm deleted file mode 100644 index 714ad0b3fe1f..000000000000 --- a/code/modules/spells/targeted/cleric_spells.dm +++ /dev/null @@ -1,243 +0,0 @@ -/spell/targeted/heal_target - name = "Cure Light Wounds" - desc = "a rudimentary spell used mainly by wizards to heal papercuts. Does not require wizard garb." - feedback = "CL" - school = "transmutation" - charge_max = 20 SECONDS - spell_flags = INCLUDEUSER | SELECTABLE - invocation = "Di'Nath!" - invocation_type = SpI_SHOUT - range = 2 - max_targets = 1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 2) - - cooldown_reduc = 50 - hud_state = "heal_minor" - cast_sound = 'sound/magic/staff_healing.ogg' - - amt_dam_brute = -15 - amt_dam_fire = -5 - amt_dam_robo = -4 - effect_state = "green_sparkles" - effect_duration = 5 - - message = "You feel a pleasant rush of heat move through your body." - -/spell/targeted/heal_target/empower_spell() - if(!..()) - return 0 - amt_dam_brute -= 15 - amt_dam_fire -= 15 - amt_dam_robo -= 7 - return "[src] will now heal more." - -/spell/targeted/heal_target/tower - charge_max = 2 - -/spell/targeted/heal_target/touch - name = "Healing Touch" - desc = "Heals an adjacent target for a reasonable amount of health." - range = 1 - amt_dam_fire = -7 - amt_dam_brute = -7 - amt_dam_robo = -5 - charge_max = 10 SECONDS - spell_flags = SELECTABLE - invocation = "Di'Na!" - - hud_state = "heal_touch" - -/spell/targeted/heal_target/major - name = "Cure Major Wounds" - desc = "A spell used to fix others that cannot be fixed with regular medicine." - feedback = "CM" - charge_max = 30 SECONDS - spell_flags = INCLUDEUSER | SELECTABLE | NEEDSCLOTHES - invocation = "Borv Di'Nath!" - range = 1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 1) - cooldown_reduc = 100 - hud_state = "heal_major" - - amt_dam_brute = -75 - amt_dam_fire = -50 - amt_dam_robo = -10 - amt_blood = 28 - - message = "Your body feels like a furnace." - -/spell/targeted/heal_target/major/empower_spell() - if(!..()) - return 0 - amt_blood = 28 - amt_organ = 5 - amt_brain = -5 - amt_radiation = -25 - amt_dam_tox = -20 - amt_dam_oxy = -14 - amt_dam_brute = -35 - amt_dam_fire = -35 - amt_dam_robo = -15 - - return "[src] heals more, and heals organ damage and radiation." - -/spell/targeted/heal_target/major/tower - charge_max = 1 - spell_flags = INCLUDEUSER | SELECTABLE - -/spell/targeted/heal_target/area - name = "Cure Area" - desc = "This spell heals everyone in an area." - feedback = "HA" - charge_max = 1 MINUTE - spell_flags = INCLUDEUSER - invocation = "Nal Di'Nath!" - range = 2 - max_targets = 0 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 1) - cooldown_reduc = 300 - hud_state = "heal_area" - amt_dam_robo = -6 - amt_dam_brute = -25 - amt_dam_fire = -25 - -/spell/targeted/heal_target/area/empower_spell() - if(!..()) - return 0 - amt_dam_brute -= 15 - amt_dam_fire -= 15 - amt_dam_robo -= 4 - range += 2 - - return "[src] now heals more in a wider area." - -/spell/targeted/heal_target/area/tower - charge_max = 1 - -/spell/targeted/heal_target/area/slow - charge_max = 2 MINUTES - -/spell/targeted/heal_target/sacrifice - name = "Sacrifice" - desc = "This spell heals immensily. For a price. Does not require wizard garb." - feedback = "SF" - spell_flags = SELECTABLE - invocation = "Ei'Nath Borv Di'Nath!" - charge_type = Sp_HOLDVAR - holder_var_type = "fireloss" - holder_var_amount = 100 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - - amt_dam_brute = -1000 - amt_dam_fire = -1000 - amt_dam_oxy = -100 - amt_dam_tox = -100 - amt_dam_robo = -1000 - amt_blood = 280 - effect_color = "#ff0000" - - hud_state = "gen_dissolve" - cast_sound = 'sound/magic/disintegrate.ogg' - -/spell/targeted/heal_target/sacrifice/empower_spell() - if(!..()) - return 0 - - amt_organ = 25 - amt_brain = -25 - amt_radiation = -100 - - - return "You will now heal organ and brain damage, as well as virtually purge all radiation." - - -/spell/targeted/heal_target/trance - name = "trance" - desc = "A mighty spell of restoration that briefly forces its target into a deep, dreamless sleep, rapidly repairing their body and soul as their senses are dulled. The users of this mighty art are known for being short lived, slowly devolving into raving madness as the power they once relied on fails them with excessive use." - feedback = "TC" - spell_flags = SELECTABLE - invocation = "Di' Dae Nath!" - charge_max = 2 MINUTES - - amt_dam_brute = -1000 - amt_dam_fire = -1000 - amt_dam_oxy = -100 - amt_dam_tox = -100 - amt_dam_robo = -1000 - hud_state = "trance" - var/obj/effect/effect - -/spell/targeted/heal_target/trance/cast(var/list/targets, var/mob/user) - for(var/t in targets) - var/mob/living/L = t - var/turf/T = get_turf(L) - effect = new /obj/effect/rift(T) - effect.color = "f0e68c" - L.forceMove(effect) - var/time = (L.getBruteLoss() + L.getFireLoss()) * 20 - L.status_flags &= GODMODE - to_chat(L,"You will be in stasis for [time/10] second\s") - addtimer(CALLBACK(src,.proc/cancel_rift),time) - -/spell/targeted/heal_target/trance/Destroy() - cancel_rift() - return ..() - -/spell/targeted/heal_target/trance/proc/cancel_rift() - if(effect) - var/mob/living/L = locate() in effect - L.status_flags &= ~GODMODE - L.forceMove(get_turf(L)) - apply_spell_damage(L) - charge_max += 300 - QDEL_NULL(effect) - -/spell/targeted/revoke - name = "Revoke Death" - desc = "Revoke that of death itself. Comes at a cost that may be hard to manage for some." - feedback = "RK" - - spell_flags = SELECTABLE - - charge_type = Sp_CHARGES - charge_max = 1 - invocation = "Di Le Nal Yen Nath!" - invocation_type = SpI_SHOUT - range = 1 - hud_state = "heal_revoke" - -/spell/targeted/revoke/cast(var/list/targets, var/mob/living/user) - if(alert(user, "Are you sure?", "Alert", "Yes", "No") == "Yes" && alert(user, "Are you ABSOLUTELY SURE?", "Alert", "Absolutely!", "No") == "Absolutely!") - var/should_wait = 1 - for(var/t in targets) - var/mob/living/M = t - M.rejuvenate() - if(M.client) //We've got a dude - should_wait = 0 - break //Don't need to check anymore. - if(should_wait) - addtimer(CALLBACK(src,.proc/check_for_revoke,targets), 30 SECONDS) - else - revoke_spells() - - -/spell/targeted/revoke/proc/check_for_revoke(var/list/targets) - for(var/t in targets) - var/mob/M = t - if(M.client) - revoke_spells() - return - charge_counter = charge_max - to_chat(holder,"\The [src] refreshes as it seems it could not bring back the souls of those you healed.") - -/spell/targeted/revoke/proc/revoke_spells() - if(!istype(holder, /mob/living)) - return - var/mob/living/M = holder - if(M.mind) - for(var/s in M.mind.learned_spells) - if(istype(s, /spell/toggle_armor)) //Can keep the armor n junk. - continue - M.remove_spell(s) - for(var/a in M.auras) - M.remove_aura(a) \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/burning_touch.dm b/code/modules/spells/targeted/equip/burning_touch.dm deleted file mode 100644 index a3bf6f1a0fc5..000000000000 --- a/code/modules/spells/targeted/equip/burning_touch.dm +++ /dev/null @@ -1,66 +0,0 @@ -/spell/targeted/equip_item/burning_hand - name = "Burning Hand" - desc = "Bathes your hand in fire, giving you all the perks and disadvantages that brings." - feedback = "BH" - school = "conjuration" - invocation = "Horila Kiha!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - range = -1 - duration = 0 - max_targets = 1 - equipped_summons = list("active hand" = /obj/item/flame/hands) - delete_old = 0 - - hud_state = "gen_burnhand" - -/obj/item/flame/hands - name = "Burning Hand" - icon = 'icons/mob/screen1.dmi' - icon_state = "grabbed+1" - force = 10 - damtype = BURN - simulated = 0 - var/burn_power = 0 - var/burn_timer - var/obj/item/organ/external/hand/connected - -/obj/item/flame/hands/pickup(var/mob/user) - burn_power = 0 - burn_timer = world.time + 10 SECONDS - START_PROCESSING(SSobj,src) - - -/obj/item/flame/hands/Process() - if(world.time < burn_timer) - return - burn_timer = world.time + 5 SECONDS - burn_power++ - force += 2 - if(!istype(src.loc, /mob/living/carbon/human)) - qdel(src) - return - var/mob/living/carbon/human/user = src.loc - var/obj/item/organ/external/hand - if(src == user.l_hand) - hand = user.get_organ(BP_L_HAND) - else - hand = user.get_organ(BP_R_HAND) - hand.take_external_damage(burn=2 * burn_power) - if(burn_power > 5) - user.fire_stacks += 15 - user.IgniteMob() - user.visible_message("\The [user] bursts into flames!") - user.drop_from_inventory(src) - else - if(burn_power == 5) - to_chat(user, "You begin to lose control of \the [src]'s flames as they rapidly move up your arm...") - else - to_chat(user, "You feel \the [src] grow hotter and hotter!") - -/obj/item/flame/hands/get_storage_cost() - return ITEM_SIZE_NO_CONTAINER - -/obj/item/flame/hands/dropped() - ..() - qdel(src) \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/dyrnwyn.dm b/code/modules/spells/targeted/equip/dyrnwyn.dm deleted file mode 100644 index 9bc4571f8aed..000000000000 --- a/code/modules/spells/targeted/equip/dyrnwyn.dm +++ /dev/null @@ -1,40 +0,0 @@ -/spell/targeted/equip_item/dyrnwyn - name = "Summon Dyrnwyn" - desc = "Summons the legendary sword of Rhydderch Hael, said to draw in flame when held by a worthy man." - feedback = "SD" - charge_type = Sp_HOLDVAR - holder_var_type = "fireloss" - holder_var_amount = 10 - school = "conjuration" - invocation = "Anrhydeddu Fi!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - range = -1 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - duration = 300 //30 seconds - max_targets = 1 - equipped_summons = list("active hand" = /obj/item/sword) - delete_old = 0 - var/material = /decl/material/solid/metal/gold - - hud_state = "gen_immolate" - - -/spell/targeted/equip_item/dyrnwyn/summon_item(var/new_type) - var/obj/item/W = new new_type(null,material) - W.SetName("\improper Dyrnwyn") - W.damtype = BURN - W.hitsound = 'sound/items/welder2.ogg' - W.slowdown_per_slot[slot_l_hand] = 1 - W.slowdown_per_slot[slot_r_hand] = 1 - return W - -/spell/targeted/equip_item/dyrnwyn/empower_spell() - if(!..()) - return 0 - - material = /decl/material/solid/metal/silver - return "Dyrnwyn has been made pure: it is now made of silver." - -/spell/targeted/equip_item/dyrnwyn/tower - charge_max = 1 \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/equip.dm b/code/modules/spells/targeted/equip/equip.dm deleted file mode 100644 index fe318a5bf17b..000000000000 --- a/code/modules/spells/targeted/equip/equip.dm +++ /dev/null @@ -1,42 +0,0 @@ -//You can set duration to 0 to have the items last forever - -/spell/targeted/equip_item - name = "equipment spell" - cast_sound = 'sound/magic/summonitems_generic.ogg' - - var/list/equipped_summons = list() //assoc list of text ids and paths to spawn - - var/list/summoned_items = list() //list of items we summoned and will dispose when the spell runs out - - var/delete_old = 1 //if the item previously in the slot is deleted - otherwise, it's dropped - -/spell/targeted/equip_item/cast(list/targets, mob/user = usr) - ..() - for(var/mob/living/L in targets) - for(var/slot_id in equipped_summons) - var/to_create = equipped_summons[slot_id] - if(cmptext(slot_id,"active hand")) - slot_id = (user.hand ? slot_l_hand : slot_r_hand) - else if(cmptext(slot_id, "off hand")) - slot_id = (user.hand ? slot_r_hand : slot_l_hand) - else - slot_id = text2num(slot_id) //because the index is text, we access this instead - var/obj/item/new_item = summon_item(to_create) - var/obj/item/old_item = L.get_equipped_item(slot_id) - if(old_item) - L.drop_from_inventory(old_item) - if(delete_old) - qdel(old_item) - L.equip_to_slot(new_item, slot_id) - new_item.pickup(L) - - if(duration) - summoned_items += new_item //we store it in a list to remove later - - if(duration) - spawn(duration) - for(var/obj/item/to_remove in summoned_items) - qdel(to_remove) - -/spell/targeted/equip_item/proc/summon_item(var/newtype) - return new newtype diff --git a/code/modules/spells/targeted/equip/holy_relic.dm b/code/modules/spells/targeted/equip/holy_relic.dm deleted file mode 100644 index 3418cc48d3ac..000000000000 --- a/code/modules/spells/targeted/equip/holy_relic.dm +++ /dev/null @@ -1,34 +0,0 @@ -/spell/targeted/equip_item/holy_relic - name = "Summon Holy Relic" - desc = "This spell summons a relic of purity into your hand for a short while." - feedback = "SR" - school = "conjuration" - charge_type = Sp_RECHARGE - charge_max = 600 - spell_flags = NEEDSCLOTHES | INCLUDEUSER - invocation = "Yee'Ro Su!" - invocation_type = SpI_SHOUT - range = -1 - max_targets = 1 - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 1, Sp_POWER = 1) - duration = 250 - cooldown_min = 350 - delete_old = 0 - compatible_mobs = list(/mob/living/carbon/human) - - hud_state = "purge1" - - equipped_summons = list("active hand" = /obj/item/nullrod) - -/spell/targeted/equip_item/holy_relic/cast(list/targets, mob/user = usr) - ..() - for(var/mob/M in targets) - M.visible_message("A rod of metal appears in \the [M]'s hand!") - -/spell/targeted/equip_item/holy_relic/empower_spell() - if(!..()) - return 0 - - duration += 50 - - return "The holy relic now lasts for [duration/10] seconds." \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/horsemask.dm b/code/modules/spells/targeted/equip/horsemask.dm deleted file mode 100644 index 5f22671bfe07..000000000000 --- a/code/modules/spells/targeted/equip/horsemask.dm +++ /dev/null @@ -1,48 +0,0 @@ -/spell/targeted/equip_item/horsemask - name = "Curse of the Horseman" - desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes." - school = "transmutation" - charge_type = Sp_RECHARGE - charge_max = 150 - charge_counter = 0 - spell_flags = 0 - invocation = "Kn'a Ftaghu, Puck'Bthnk!" - invocation_type = SpI_SHOUT - range = 7 - max_targets = 1 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 1) - cooldown_min = 30 //30 deciseconds reduction per rank - selection_type = "range" - - compatible_mobs = list(/mob/living/carbon/human) - - hud_state = "wiz_horse" - cast_sound = 'sound/magic/horsehead_curse.ogg' - -/spell/targeted/equip_item/horsemask/New() - ..() - equipped_summons = list("[slot_wear_mask]" = /obj/item/clothing/mask/horsehead) - -/spell/targeted/equip_item/horsemask/cast(list/targets, mob/user = usr) - ..() - for(var/mob/living/target in targets) - target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \ - "Your face burns up, and shortly after the fire you realise you have the face of a horse!") - target.flash_eyes() - -/spell/targeted/equip_item/horsemask/summon_item(var/new_type) - var/obj/item/new_item = new new_type - new_item.canremove = 0 //curses! - if(istype(new_item, /obj/item/clothing/mask/horsehead)) - var/obj/item/clothing/mask/horsehead/magichead = new_item - magichead.flags_inv = null //so you can still see their face - magichead.voicechange = 1 //NEEEEIIGHH - return new_item - -/spell/targeted/equip_item/horsemask/empower_spell() - if(!..()) - return 0 - - spell_flags = SELECTABLE - - return "You can now select your target with [src]" \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/party_hardy.dm b/code/modules/spells/targeted/equip/party_hardy.dm deleted file mode 100644 index 65ce05835c0b..000000000000 --- a/code/modules/spells/targeted/equip/party_hardy.dm +++ /dev/null @@ -1,36 +0,0 @@ -/spell/targeted/equip_item/party_hardy - name = "Summon Party" - desc = "This spell was invented for the sole purpose of getting crunked at 11am on a Tuesday. Does not require wizard garb." - feedback = "PY" - school = "conjuration" - charge_type = Sp_RECHARGE - charge_max = 900 - cooldown_min = 600 - spell_flags = INCLUDEUSER - invocation = "Llet'Su G'iit Rrkned!" //Let's get wrecked. - invocation_type = SpI_SHOUT - range = 6 - max_targets = 0 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 1, Sp_POWER = 2) - delete_old = 0 - - hud_state = "wiz_party" - - compatible_mobs = list(/mob/living/carbon/human) - equipped_summons = list("active hand" = /obj/item/chems/food/drinks/bottle/small/beer) - -/spell/targeted/equip_item/party_hardy/empower_spell() - if(!..()) - return 0 - switch(spell_levels[Sp_POWER]) - if(1) - equipped_summons = list("active hand" = /obj/item/chems/food/drinks/bottle/small/beer, - "off hand" = /obj/item/chems/food/snacks/poppypretzel) - return "The spell will now give everybody a preztel as well." - if(2) - equipped_summons = list("active hand" = /obj/item/chems/food/drinks/bottle/absinthe, - "off hand" = /obj/item/chems/food/snacks/poppypretzel, - "[slot_head]" = /obj/item/clothing/head/collectable/wizard) - return "Woo! Now everybody gets a cool wizard hat and MORE BOOZE!" - - return 0 \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/seed.dm b/code/modules/spells/targeted/equip/seed.dm deleted file mode 100644 index 9b560b7281a3..000000000000 --- a/code/modules/spells/targeted/equip/seed.dm +++ /dev/null @@ -1,21 +0,0 @@ -/spell/targeted/equip_item/seed - name = "Summon Seed" - desc = "This spell summons a random seed into the hand of the wizard." - feedback = "SE" - delete_old = 0 - - spell_flags = INCLUDEUSER | NEEDSCLOTHES - invocation_type = SpI_WHISPER - invocation = "Ria'li akta." - - equipped_summons = list("active hand" = /obj/item/seeds/random) - compatible_mobs = list(/mob/living/carbon/human) - - charge_max = 600 //1 minute - cooldown_min = 200 //20 seconds - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 0) - - range = -1 - max_targets = 1 - - hud_state = "wiz_seed" \ No newline at end of file diff --git a/code/modules/spells/targeted/equip/shield.dm b/code/modules/spells/targeted/equip/shield.dm deleted file mode 100644 index 4ab9102c03e9..000000000000 --- a/code/modules/spells/targeted/equip/shield.dm +++ /dev/null @@ -1,44 +0,0 @@ -/spell/targeted/equip_item/shield - name = "Summon Shield" - desc = "Summons the most holy of shields, the riot shield. Commonly used during wizard riots." - feedback = "SH" - school = "conjuration" - invocation = "Sia helda!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER | NEEDSCLOTHES - range = -1 - max_targets = 1 - - compatible_mobs = list(/mob/living/carbon/human) - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 2, Sp_POWER = 1) - charge_type = Sp_RECHARGE - charge_max = 900 - cooldown_min = 300 - equipped_summons = list("off hand" = /obj/item/shield/) - duration = 300 - delete_old = 0 - var/item_color = "#6666ff" - var/block_chance = 30 - - hud_state = "wiz_shield" - -/spell/targeted/equip_item/shield/summon_item(var/new_type) - var/obj/item/shield/I = new new_type() - I.icon_state = "buckler" - I.color = item_color - I.SetName("Wizard's Shield") - I.base_block_chance = block_chance - return I - -/spell/targeted/equip_item/shield/empower_spell() - if(!..()) - return 0 - - item_color = "#6600ff" - block_chance = 60 - - return "Your summoned shields will now block more often." - -/spell/targeted/equip_item/shield/tower - charge_max = 1 \ No newline at end of file diff --git a/code/modules/spells/targeted/ethereal_jaunt.dm b/code/modules/spells/targeted/ethereal_jaunt.dm deleted file mode 100644 index 19370d0b355e..000000000000 --- a/code/modules/spells/targeted/ethereal_jaunt.dm +++ /dev/null @@ -1,124 +0,0 @@ -/spell/targeted/ethereal_jaunt - name = "Ethereal Jaunt" - desc = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls." - feedback = "EJ" - school = "transmutation" - charge_max = 300 - spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER - invocation = "none" - invocation_type = SpI_NONE - range = -1 - max_targets = 1 - level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 3) - cooldown_min = 100 //50 deciseconds reduction per rank - duration = 50 //in deciseconds - - hud_state = "wiz_jaunt" - -/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded - for(var/mob/living/target in targets) - if(HAS_TRANSFORMATION_MOVEMENT_HANDLER(target)) - continue - - if(target.buckled) - target.buckled.unbuckle_mob() - spawn(0) - var/mobloc = get_turf(target.loc) - var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( mobloc ) - var/atom/movable/overlay/animation = new /atom/movable/overlay(holder) - animation.SetName("water") - animation.set_density(0) - animation.anchored = 1 - animation.icon = 'icons/mob/mob.dmi' - animation.layer = FLY_LAYER - target.ExtinguishMob() - if(target.buckled) - target.buckled = null - jaunt_disappear(animation, target) - target.forceMove(holder) - jaunt_steam(mobloc) - sleep(duration) - mobloc = holder.last_valid_turf - animation.forceMove(mobloc) - jaunt_steam(mobloc) - holder.reappearing = 1 - sleep(20) - jaunt_reappear(animation, target) - sleep(5) - if(!target.forceMove(mobloc)) - for(var/direction in list(1,2,4,8,5,6,9,10)) - var/turf/T = get_step(mobloc, direction) - if(T) - if(target.forceMove(T)) - break - target.client.eye = target - qdel(animation) - qdel(holder) - -/spell/targeted/ethereal_jaunt/empower_spell() - if(!..()) - return 0 - duration += 20 - - return "[src] now lasts longer." - -/spell/targeted/ethereal_jaunt/proc/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target) - animation.icon_state = "liquify" - flick("liquify",animation) - playsound(get_turf(target), 'sound/magic/ethereal_enter.ogg', 30) - -/spell/targeted/ethereal_jaunt/proc/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target) - flick("reappear",animation) - playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 30) - -/spell/targeted/ethereal_jaunt/proc/jaunt_steam(var/mobloc) - var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread() - steam.set_up(10, 0, mobloc) - steam.start() - -/obj/effect/dummy/spell_jaunt - name = "water" - icon = 'icons/effects/effects.dmi' - icon_state = "nothing" - var/canmove = 1 - var/reappearing = 0 - density = 0 - anchored = 1 - var/turf/last_valid_turf - -/obj/effect/dummy/spell_jaunt/Initialize() - . = ..() - last_valid_turf = get_turf(loc) - -/obj/effect/dummy/spell_jaunt/Destroy() - // Eject contents if deleted somehow - for(var/atom/movable/AM in src) - AM.dropInto(loc) - return ..() - -/obj/effect/dummy/spell_jaunt/relaymove(var/mob/user, direction) - if (!canmove || reappearing) return - var/turf/newLoc = get_step(src, direction) - if(!(newLoc.turf_flags & TURF_FLAG_NOJAUNT)) - forceMove(newLoc) - var/turf/T = get_turf(loc) - if(!T.contains_dense_objects()) - last_valid_turf = T - else - to_chat(user, "Some strange aura is blocking the way!") - canmove = 0 - addtimer(CALLBACK(src, .proc/allow_move), 2) - -/obj/effect/dummy/spell_jaunt/proc/allow_move() - canmove = TRUE - -/obj/effect/dummy/spell_jaunt/explosion_act(blah) - SHOULD_CALL_PARENT(FALSE) - return - -/obj/effect/dummy/spell_jaunt/bullet_act(blah) - return - -/spell/targeted/ethereal_jaunt/tower - charge_max = 2 - spell_flags = Z2NOCAST | INCLUDEUSER \ No newline at end of file diff --git a/code/modules/spells/targeted/exhude_pleasantness.dm b/code/modules/spells/targeted/exhude_pleasantness.dm deleted file mode 100644 index d249c4c5ab47..000000000000 --- a/code/modules/spells/targeted/exhude_pleasantness.dm +++ /dev/null @@ -1,19 +0,0 @@ -/spell/targeted/exhude_pleasantness - name = "Exhude Pleasantness" - desc = "A simple spell used to make friends with people. Be warned, this spell only has a subtle effect" - feedback = "AP" - school = "Illusion" - spell_flags = INCLUDEUSER - range = 5 - max_targets = 0 - charge_max = 100 - var/list/possible_messages = list("seems pretty trustworthy!", "makes you feel appreciated.", "looks pretty cool.", "feels like the only decent person here!", "makes you feel safe.") - hud_state = "friendly" - -/spell/targeted/exhude_pleasantness/cast(var/list/targets, var/mob/user) - for(var/m in targets) - var/mob/living/L = m - if(L.mind && L.mind.special_role == ANTAG_SERVANT) - to_chat(m, "\The [user] seems relatively harmless.") - else - to_chat(m, "\The [user] [pick(possible_messages)]") \ No newline at end of file diff --git a/code/modules/spells/targeted/genetic.dm b/code/modules/spells/targeted/genetic.dm deleted file mode 100644 index db570ef6cb04..000000000000 --- a/code/modules/spells/targeted/genetic.dm +++ /dev/null @@ -1,118 +0,0 @@ -/* -Other mutation or disability spells can be found in -code\game\dna\genes\vg_powers.dm //hulk is in this file -code\game\dna\genes\goon_disabilities.dm -code\game\dna\genes\goon_powers.dm -*/ -/spell/targeted/genetic - name = "Genetic modifier" - desc = "This spell inflicts a set of mutations and disabilities upon the target." - - var/disabilities = 0 //bits - var/list/mutations = list() //mutation strings - duration = 100 //deciseconds - - -/spell/targeted/genetic/cast(list/targets) - ..() - for(var/mob/living/target in targets) - for(var/x in mutations) - target.mutations.Add(x) - target.disabilities |= disabilities - target.update_mutations() //update target's mutation overlays - spawn(duration) - for(var/x in mutations) - target.mutations.Remove(x) - target.disabilities &= ~disabilities - target.update_mutations() - return - -/spell/targeted/genetic/blind - name = "Blind" - desc = "This spell inflicts a target with temporary blindness. Does not require wizard garb." - feedback = "BD" - disabilities = 1 - school = "illusion" - duration = 300 - - charge_max = 300 - - spell_flags = 0 - invocation = "Sty Kaly." - invocation_type = SpI_WHISPER - message = "Your eyes cry out in pain!" - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 1, Sp_POWER = 3) - cooldown_min = 50 - - range = 7 - max_targets = 0 - - amt_eye_blind = 10 - amt_eye_blurry = 20 - - hud_state = "wiz_blind" - cast_sound = 'sound/magic/blind.ogg' - -/spell/targeted/genetic/blind/empower_spell() - if(!..()) - return 0 - duration += 100 - - return "[src] will now blind for a longer period of time." - -/spell/targeted/genetic/mutate - name = "Mutate" - desc = "This spell causes you to turn into a hulk and gain laser vision for a short while." - feedback = "MU" - school = "transmutation" - charge_max = 400 - spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER - invocation = "BIRUZ BENNAR" - invocation_type = SpI_SHOUT - message = "You feel strong! You feel a pressure building behind your eyes!" - range = 0 - max_targets = 1 - - mutations = list(MUTATION_LASER, MUTATION_HULK) - duration = 300 - - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 0) - cooldown_min = 300 - - hud_state = "wiz_hulk" - cast_sound = 'sound/magic/mutate.ogg' - effect_state = "electricity_constant" - effect_duration = 5 - effect_color = "#ff0000" - -/spell/targeted/genetic/blind/hysteria - name = "Hysteria" - desc = "A spell used to make someone look like a blind fool, and also makes them a blind fool." - feedback = "HY" - school = "illusion" - spell_flags = SELECTABLE - charge_max = 600 - invocation_type = SpI_SHOUT - invocation = "Sty Di Kaly!" - amt_dizziness = 10 - hud_state = "hysteria" - -/spell/targeted/genetic/blind/starburst - name = "Starburst" - desc = "Send a jolt of electricity through everyone's nerve center, blinding and stunning them." - feedback = "SB" - school = "transmutation" - invocation = "Tid Caeh Yor!" - spell_flags = NOFACTION - invocation_type = SpI_SHOUT - charge_max = 60 SECONDS - spell_flags = 0 - - amt_dizziness = 0 - amt_eye_blurry = 5 - amt_stunned = 1 - - effect_state = "electricity_constant" - effect_duration = 5 - - hud_state = "wiz_starburst" \ No newline at end of file diff --git a/code/modules/spells/targeted/glimpse_of_eternity.dm b/code/modules/spells/targeted/glimpse_of_eternity.dm deleted file mode 100644 index f90d673c41b0..000000000000 --- a/code/modules/spells/targeted/glimpse_of_eternity.dm +++ /dev/null @@ -1,26 +0,0 @@ -/spell/targeted/glimpse_of_eternity - name = "Glimpse of Eternity" - desc = "Show the non-believers what enlightenment truely means." - feedback = "GE" - school = "illusion" - invocation = "Ghe Tar Yet!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - max_targets = 0 - charge_max = 400 - range = 3 - - hud_state = "wiz_glimpse" - -/spell/targeted/glimpse_of_eternity/cast(var/list/targets, var/mob/user) - for(var/t in targets) - var/mob/living/L = t - if(L.faction != user.faction) //Worse for non-allies - L.eye_blind += 5 - L.Stun(5) - new /obj/effect/temporary(get_turf(L), 5, 'icons/effects/effects.dmi', "electricity_constant") - else - L.eye_blind += 2 - L.adjustBruteLoss(-10) - L.adjustFireLoss(-10) - new /obj/effect/temporary(get_turf(L), 5, 'icons/effects/effects.dmi', "green_sparkles") \ No newline at end of file diff --git a/code/modules/spells/targeted/harvest.dm b/code/modules/spells/targeted/harvest.dm deleted file mode 100644 index 840fd47b8faa..000000000000 --- a/code/modules/spells/targeted/harvest.dm +++ /dev/null @@ -1,37 +0,0 @@ -/spell/targeted/harvest - name = "Harvest" - desc = "Back to where I come from, and you're coming with me." - - school = "transmutation" - charge_max = 200 - spell_flags = Z2NOCAST | CONSTRUCT_CHECK | INCLUDEUSER - invocation = "" - invocation_type = SpI_NONE - range = 0 - max_targets = 0 - - overlay = 1 - overlay_icon = 'icons/effects/effects.dmi' - overlay_icon_state = "rune_teleport" - overlay_lifespan = 0 - - hud_state = "const_harvest" - -/spell/targeted/harvest/cast(list/targets, mob/user)//because harvest is already a proc - ..() - - var/destination = null - for(var/obj/singularity/narsie/large/N in narsie_list) - destination = N.loc - break - if(destination) - var/prey = 0 - for(var/mob/living/M in targets) - if(!findNullRod(M)) - M.forceMove(destination) - if(M != user) - prey = 1 - to_chat(user, "You warp back to Nar-Sie[prey ? " along with your prey":""].") - else - to_chat(user, "...something's wrong!")//There shouldn't be an instance of Harvesters when Nar-Sie isn't in the world. - diff --git a/code/modules/spells/targeted/projectile/dumbfire.dm b/code/modules/spells/targeted/projectile/dumbfire.dm deleted file mode 100644 index cd13f7169c81..000000000000 --- a/code/modules/spells/targeted/projectile/dumbfire.dm +++ /dev/null @@ -1,13 +0,0 @@ -/spell/targeted/projectile/dumbfire - name = "dumbfire spell" - -/spell/targeted/projectile/dumbfire/choose_targets(mob/user = usr) - var/list/targets = list() - - var/starting_dir = user.dir //where are we facing at the time of casting? - var/turf/starting_turf = get_turf(user) - var/current_turf = starting_turf - for(var/i = 1; i <= src.range; i++) - current_turf = get_step(current_turf, starting_dir) - targets += current_turf - return targets \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/fireball.dm b/code/modules/spells/targeted/projectile/fireball.dm deleted file mode 100644 index b690b4ff8965..000000000000 --- a/code/modules/spells/targeted/projectile/fireball.dm +++ /dev/null @@ -1,71 +0,0 @@ -/spell/targeted/projectile/dumbfire/fireball - name = "Fireball" - desc = "This spell fires a fireball at a target and does not require wizard garb." - feedback = "FB" - proj_type = /obj/item/projectile/spell_projectile/fireball - - school = "conjuration" - charge_max = 100 - spell_flags = 0 - invocation = "Oni-Soma!" - invocation_type = SpI_SHOUT - range = 20 - - level_max = list(Sp_TOTAL = 5, Sp_SPEED = 0, Sp_POWER = 5) - - spell_flags = 0 - - duration = 20 - proj_step_delay = 1 - - amt_dam_brute = 20 - amt_dam_fire = 25 - - var/ex_severe = -1 - var/ex_heavy = 1 - var/ex_light = 2 - var/ex_flash = 5 - - hud_state = "wiz_fireball" - cast_sound = 'sound/magic/fireball.ogg' - -/spell/targeted/projectile/dumbfire/fireball/prox_cast(var/list/targets, spell_holder) - for(var/mob/living/M in targets) - apply_spell_damage(M) - explosion(get_turf(spell_holder), ex_severe, ex_heavy, ex_light, ex_flash) - -/spell/targeted/projectile/dumbfire/fireball/empower_spell() - if(!..()) - return 0 - - if(spell_levels[Sp_POWER]%2 == 1) - ex_severe++ - ex_heavy++ - ex_light++ - ex_flash++ - - return "The spell [src] now has a larger explosion." - -/spell/targeted/projectile/dumbfire/fireball/tower - charge_max = 2 - -//PROJECTILE - -/obj/item/projectile/spell_projectile/fireball - name = "fireball" - icon_state = "fireball" - -/spell/targeted/projectile/dumbfire/fireball/firebolt - name = "Firebolt" - desc = "A quick-casted fireball. Burns the user, and their enemies, but is much faster to shoot." - feedback = "FO" - charge_type = Sp_HOLDVAR - invocation = "Ignus!" - holder_var_type = "fireloss" - holder_var_amount = 10 - amt_dam_brute = 10 - amt_dam_fire = 15 - ex_heavy = -1 - ex_light = 1 - ex_flash = 3 - hud_state = "firebolt" \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/magic_missile.dm b/code/modules/spells/targeted/projectile/magic_missile.dm deleted file mode 100644 index 1d72399718a9..000000000000 --- a/code/modules/spells/targeted/projectile/magic_missile.dm +++ /dev/null @@ -1,56 +0,0 @@ -/spell/targeted/projectile/magic_missile - name = "Magic Missile" - desc = "This spell fires several, slow moving, magic projectiles at nearby targets." - feedback = "MM" - school = "conjuration" - charge_max = 150 - spell_flags = NEEDSCLOTHES - invocation = "Forti Gy-Ama!" - invocation_type = SpI_SHOUT - range = 7 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3) - cooldown_min = 90 //15 deciseconds reduction per rank - - max_targets = 0 - - proj_type = /obj/item/projectile/spell_projectile/seeking/magic_missile - duration = 10 - proj_step_delay = 5 - - hud_state = "wiz_mm" - cast_sound = 'sound/magic/magic_missile.ogg' - amt_paralysis = 3 - amt_stunned = 3 - - amt_dam_fire = 10 - -/spell/targeted/projectile/magic_missile/prox_cast(var/list/targets, atom/spell_holder) - spell_holder.visible_message("\The [spell_holder] pops with a flash!") - playsound(src, 'sound/magic/mm_hit.ogg', 40) - for(var/mob/living/M in targets) - apply_spell_damage(M) - return - -/spell/targeted/projectile/magic_missile/empower_spell() - if(!..()) - return 0 - - if(spell_levels[Sp_POWER] == level_max[Sp_POWER]) - amt_paralysis += 2 - amt_stunned += 2 - return "[src] will now stun people for a longer duration." - amt_dam_fire += 5 - - return "[src] does more damage now." - - - -//PROJECTILE - -/obj/item/projectile/spell_projectile/seeking/magic_missile - name = "magic missile" - icon_state = "magicm" - - proj_trail = 1 - proj_trail_lifespan = 5 - proj_trail_icon_state = "magicmd" diff --git a/code/modules/spells/targeted/projectile/passage.dm b/code/modules/spells/targeted/projectile/passage.dm deleted file mode 100644 index d84b370abf77..000000000000 --- a/code/modules/spells/targeted/projectile/passage.dm +++ /dev/null @@ -1,47 +0,0 @@ -/spell/targeted/projectile/dumbfire/passage - name = "Passage" - desc = "throw a spell towards an area and teleport to it." - feedback = "PA" - proj_type = /obj/item/projectile/spell_projectile/passage - - - school = "conjuration" - charge_max = 250 - spell_flags = 0 - invocation = "A'YASAMA" - invocation_type = SpI_SHOUT - range = 15 - - - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - spell_flags = NEEDSCLOTHES - duration = 15 - - proj_step_delay = 1 - - hud_state = "gen_project" - cast_sound = 'sound/magic/lightning_bolt.ogg' - -/spell/targeted/projectile/dumbfire/passage/prox_cast(var/list/targets, atom/spell_holder) - for(var/mob/living/L in targets) - apply_spell_damage(L) - - var/turf/T = get_turf(spell_holder) - - holder.forceMove(T) - var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread() - S.set_up(3,0,T) - S.start() - playsound(src, 'sound/magic/lightningshock.ogg', 50) - -/spell/targeted/projectile/dumbfire/passage/empower_spell() - if(!..()) - return 0 - - amt_stunned += 3 - - return "[src] now stuns those who get hit by it." - -/obj/item/projectile/spell_projectile/passage - name = "spell" - icon_state = "energy2" \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/projectile.dm b/code/modules/spells/targeted/projectile/projectile.dm deleted file mode 100644 index 2cc2b2a559b4..000000000000 --- a/code/modules/spells/targeted/projectile/projectile.dm +++ /dev/null @@ -1,49 +0,0 @@ -/* -Projectile spells make special projectiles (obj/item/spell_projectile) and fire them at targets -Dumbfire projectile spells fire directly ahead of the user -spell_projectiles call their spell's (carried) prox_cast when they get in range of a target -If the spell_projectile is seeking, it will update its target every process and follow them -*/ - -/spell/targeted/projectile - name = "projectile spell" - - range = 7 - - var/proj_type = /obj/item/projectile/spell_projectile //use these. They are very nice - - var/proj_step_delay = 1 //lower = faster - var/cast_prox_range = 1 - -/spell/targeted/projectile/cast(list/targets, mob/user = usr) - for(var/atom/target in targets) - var/obj/item/projectile/projectile = new proj_type(user.loc, user.dir) - - if(!projectile) - return - - if(istype(projectile, /obj/item/projectile/spell_projectile)) - var/obj/item/projectile/spell_projectile/SP = projectile - SP.carried = src //casting is magical - projectile.original = target - projectile.starting = get_turf(user) - projectile.shot_from = user //fired from the user - projectile.current = projectile.original - projectile.yo = target.y - user.y - projectile.xo = target.x - user.x - projectile.life_span = src.duration - projectile.hitscan = !proj_step_delay - projectile.step_delay = proj_step_delay - projectile.launch(target) - return - -/spell/targeted/projectile/proc/choose_prox_targets(mob/user = usr, var/atom/movable/spell_holder) - var/list/targets = list() - for(var/mob/living/M in range(spell_holder, cast_prox_range)) - if(M == user && !(spell_flags & INCLUDEUSER)) - continue - targets += M - return targets - -/spell/targeted/projectile/proc/prox_cast(var/list/targets, var/atom/movable/spell_holder) - return targets \ No newline at end of file diff --git a/code/modules/spells/targeted/projectile/stuncuff.dm b/code/modules/spells/targeted/projectile/stuncuff.dm deleted file mode 100644 index 96dc277f720e..000000000000 --- a/code/modules/spells/targeted/projectile/stuncuff.dm +++ /dev/null @@ -1,49 +0,0 @@ -/spell/targeted/projectile/dumbfire/stuncuff - name = "Stun Cuff" - desc = "This spell fires out a small curse that stuns and cuffs the target." - feedback = "SC" - proj_type = /obj/item/projectile/spell_projectile/stuncuff - - charge_type = Sp_CHARGES - charge_max = 6 - charge_counter = 6 - spell_flags = 0 - invocation = "Fu'Reai Diakan!" - invocation_type = SpI_SHOUT - range = 20 - - level_max = list(Sp_TOTAL = 0, Sp_SPEED = 0, Sp_POWER = 0) - - duration = 20 - proj_step_delay = 1 - - amt_stunned = 6 - - hud_state = "wiz_cuff" - cast_sound = 'sound/magic/wandodeath.ogg' - -/spell/targeted/projectile/dumbfire/stuncuff/prox_cast(var/list/targets, spell_holder) - for(var/mob/living/M in targets) - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/handcuffs/wizard/cuffs = new() - cuffs.forceMove(H) - H.handcuffed = cuffs - H.update_inv_handcuffed() - H.visible_message("Beams of light form around \the [H]'s hands!") - apply_spell_damage(M) - - -/obj/item/handcuffs/wizard - name = "beams of light" - desc = "Undescribable and unpenetrable. Or so they say." - - breakouttime = 300 //30 seconds - -/obj/item/handcuffs/wizard/dropped(var/mob/user) - ..() - qdel(src) - -/obj/item/projectile/spell_projectile/stuncuff - name = "stuncuff" - icon_state = "spell" \ No newline at end of file diff --git a/code/modules/spells/targeted/shapeshift.dm b/code/modules/spells/targeted/shapeshift.dm deleted file mode 100644 index 1d94e86e96cf..000000000000 --- a/code/modules/spells/targeted/shapeshift.dm +++ /dev/null @@ -1,199 +0,0 @@ -//basic transformation spell. Should work for most simple_animals - -/spell/targeted/shapeshift - name = "Shapeshift" - desc = "This spell transforms the target into something else for a short while." - - school = "transmutation" - - charge_type = Sp_RECHARGE - charge_max = 600 - - duration = 0 //set to 0 for permanent. - - var/list/possible_transformations = list() - var/list/newVars = list() //what the variables of the new created thing will be. - - cast_sound = 'sound/magic/charge.ogg' - var/revert_sound = 'sound/magic/charge.ogg' //the sound that plays when something gets turned back. - var/share_damage = 1 //do we want the damage we take from our new form to move onto our real one? (Only counts for finite duration) - var/drop_items = 1 //do we want to drop all our items when we transform? - var/toggle = 0 //Can we toggle this? - var/list/transformed_dudes = list() //Who we transformed. Transformed = Transformation. Both mobs. - -/spell/targeted/shapeshift/cast(var/list/targets, mob/user) - for(var/m in targets) - var/mob/living/M = m - if(M.stat == DEAD) - to_chat(user, "[name] can only transform living targets.") - continue - if(M.buckled) - M.buckled.unbuckle_mob() - if(toggle && transformed_dudes.len && stop_transformation(M)) - continue - var/new_mob = pick(possible_transformations) - - var/mob/living/trans = new new_mob(get_turf(M)) - for(var/varName in newVars) //stolen shamelessly from Conjure - if(varName in trans.vars) - trans.vars[varName] = newVars[varName] - //Give them our languages - for(var/l in M.languages) - var/decl/language/L = l - trans.add_language(L.name) - - trans.SetName("[trans.name] ([M])") - if(istype(M,/mob/living/carbon/human) && drop_items) - for(var/obj/item/I in M.contents) - M.drop_from_inventory(I) - if(M.mind) - M.mind.transfer_to(trans) - else - trans.key = M.key - new /obj/effect/temporary(get_turf(M), 5, 'icons/effects/effects.dmi', "summoning") - - M.forceMove(trans) //move inside the new dude to hide him. - M.status_flags |= GODMODE //dont want him to die or breathe or do ANYTHING - transformed_dudes[trans] = M - GLOB.death_event.register(trans,src,/spell/targeted/shapeshift/proc/stop_transformation) - GLOB.destroyed_event.register(trans,src,/spell/targeted/shapeshift/proc/stop_transformation) - GLOB.destroyed_event.register(M, src, /spell/targeted/shapeshift/proc/destroyed_transformer) - if(duration) - spawn(duration) - stop_transformation(trans) - -/spell/targeted/shapeshift/proc/destroyed_transformer(var/mob/target) //Juuuuust in case - var/mob/current = transformed_dudes[target] - to_chat(current, "You suddenly feel as if this transformation has become permanent...") - remove_target(target) - -/spell/targeted/shapeshift/proc/stop_transformation(var/mob/living/target) - var/mob/living/transformer = transformed_dudes[target] - if(!transformer) - return FALSE - transformer.status_flags &= ~GODMODE - if(share_damage) - var/ratio = target.health/target.maxHealth - var/damage = transformer.maxHealth - round(transformer.maxHealth*(ratio)) - for(var/i in 1 to ceil(damage/10)) - transformer.adjustBruteLoss(10) - if(target.mind) - target.mind.transfer_to(transformer) - else - transformer.key = target.key - playsound(get_turf(target), revert_sound, 50, 1) - transformer.forceMove(get_turf(target)) - remove_target(target) - qdel(target) - return TRUE - -/spell/targeted/shapeshift/proc/remove_target(var/mob/living/target) - var/mob/current = transformed_dudes[target] - GLOB.destroyed_event.unregister(target,src) - GLOB.death_event.unregister(current,src) - GLOB.destroyed_event.unregister(current,src) - transformed_dudes[target] = null - transformed_dudes -= target - -/spell/targeted/shapeshift/baleful_polymorph - name = "Baleful Polymorth" - desc = "This spell transforms its target into a small, furry animal." - feedback = "BP" - possible_transformations = list(/mob/living/simple_animal/lizard,/mob/living/simple_animal/mouse,/mob/living/simple_animal/corgi) - - share_damage = 0 - invocation = "Yo'balada!" - invocation_type = SpI_SHOUT - spell_flags = NEEDSCLOTHES | SELECTABLE - range = 3 - duration = 150 //15 seconds. - cooldown_min = 200 //20 seconds - - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 2, Sp_POWER = 2) - - newVars = list("health" = 50, "maxHealth" = 50) - - hud_state = "wiz_poly" - - -/spell/targeted/shapeshift/baleful_polymorph/empower_spell() - if(!..()) - return 0 - - duration += 50 - - return "Your target will now stay in their polymorphed form for [duration/10] seconds." - -/spell/targeted/shapeshift/avian - name = "Polymorph" - desc = "This spell transforms the wizard into the common parrot." - feedback = "AV" - possible_transformations = list(/mob/living/simple_animal/hostile/retaliate/parrot) - - drop_items = 0 - share_damage = 0 - invocation = "Poli'crakata!" - invocation_type = SpI_SHOUT - spell_flags = INCLUDEUSER - range = -1 - duration = 150 - charge_max = 600 - cooldown_min = 300 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 1, Sp_POWER = 0) - hud_state = "wiz_parrot" - -/spell/targeted/shapeshift/corrupt_form - name = "Corrupt Form" - desc = "This spell shapes the wizard into a terrible, terrible beast." - feedback = "CF" - possible_transformations = list(/mob/living/simple_animal/hostile/faithless) - - invocation = "mutters something dark and twisted as their form begins to twist..." - invocation_type = SpI_EMOTE - spell_flags = INCLUDEUSER - range = -1 - duration = 150 - charge_max = 1200 - cooldown_min = 600 - - drop_items = 0 - share_damage = 0 - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 2, Sp_POWER = 2) - - newVars = list("name" = "corrupted soul") - - hud_state = "wiz_corrupt" - cast_sound = 'sound/magic/disintegrate.ogg' - -/spell/targeted/shapeshift/corrupt_form/empower_spell() - if(!..()) - return 0 - - switch(spell_levels[Sp_POWER]) - if(1) - duration *= 2 - return "You will now stay corrupted for [duration/10] seconds." - if(2) - newVars = list("name" = "\proper corruption incarnate", - "melee_damage_upper" = 25, - "resistance" = 6, - "health" = 125, - "maxHealth" = 125) - duration = 0 - return "You revel in the corruption. There is no turning back." - -/spell/targeted/shapeshift/familiar - name = "Transform" - desc = "Transform into a familiar form. Literally." - feedback = "FA" - possible_transformations = list() - drop_items = 0 - invocation_type = SpI_EMOTE - invocation = "'s body dissipates into a pale mass of light, then reshapes!" - range = -1 - spell_flags = INCLUDEUSER - duration = 0 - charge_max = 2 MINUTES - toggle = 1 - - hud_state = "wiz_carp" \ No newline at end of file diff --git a/code/modules/spells/targeted/shatter_mind.dm b/code/modules/spells/targeted/shatter_mind.dm deleted file mode 100644 index d878c2a094b7..000000000000 --- a/code/modules/spells/targeted/shatter_mind.dm +++ /dev/null @@ -1,29 +0,0 @@ -/spell/targeted/shatter - name = "Shatter Mind" - desc = "this spell allows the caster to literally break an enemy's mind. Permanently." - feedback = "SM" - school = "illusion" - charge_max = 300 - spell_flags = 0 - invocation_type = SpI_NONE - range = 5 - max_targets = 1 - compatible_mobs = list(/mob/living/carbon/human) - - time_between_channels = 150 - number_of_channels = 0 - - hud_state = "wiz_statue" - -/spell/targeted/shatter/cast(var/list/targets, var/mob/user) - var/mob/living/carbon/human/H = targets[1] - if(prob(50)) - sound_to(user, get_sfx("swing_hit")) - if(prob(5)) - to_chat(H, "You feel unhinged.") - H.adjust_hallucination(5,5) - H.confused += 2 - H.dizziness += 2 - if(H.hallucination_power > 50) - H.adjustBrainLoss(5) - to_chat(H, "You feel your mind tearing apart!") \ No newline at end of file diff --git a/code/modules/spells/targeted/shift.dm b/code/modules/spells/targeted/shift.dm deleted file mode 100644 index 2b53b60d2441..000000000000 --- a/code/modules/spells/targeted/shift.dm +++ /dev/null @@ -1,24 +0,0 @@ -/spell/targeted/ethereal_jaunt/shift - name = "Phase Shift" - desc = "This spell allows you to pass through walls" - - charge_max = 200 - spell_flags = Z2NOCAST | INCLUDEUSER | CONSTRUCT_CHECK - invocation_type = SpI_NONE - range = -1 - duration = 50 //in deciseconds - - hud_state = "const_shift" - -/spell/targeted/ethereal_jaunt/shift/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target) - animation.icon_state = "phase_shift" - animation.set_dir(target.dir) - flick("phase_shift",animation) - -/spell/targeted/ethereal_jaunt/shift/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target) - animation.icon_state = "phase_shift2" - animation.set_dir(target.dir) - flick("phase_shift2",animation) - -/spell/targeted/ethereal_jaunt/shift/jaunt_steam(var/mobloc) - return \ No newline at end of file diff --git a/code/modules/spells/targeted/subjugate.dm b/code/modules/spells/targeted/subjugate.dm deleted file mode 100644 index 914de088ed28..000000000000 --- a/code/modules/spells/targeted/subjugate.dm +++ /dev/null @@ -1,35 +0,0 @@ -/spell/targeted/subjugation - name = "Subjugation" - desc = "This spell temporarily subjugates a target's mind and does not require wizard garb." - feedback = "SJ" - school = "illusion" - charge_max = 500 - spell_flags = NOFACTION - invocation = "Dii Oda Baji." - invocation_type = SpI_WHISPER - - message = "You suddenly feel completely overwhelmed!" - - max_targets = 1 - - level_max = list(Sp_TOTAL = 3, Sp_SPEED = 0, Sp_POWER = 3) - - amt_dizziness = 100 - amt_confused = 100 - amt_stuttering = 100 - - compatible_mobs = list(/mob/living/carbon/human) - - hud_state = "wiz_subj" - -/spell/targeted/subjugation/empower_spell() - if(!..()) - return 0 - - if(spell_levels[Sp_POWER] == level_max[Sp_POWER]) - max_targets = 0 - - return "[src] will now effect everyone in the area." - else - max_targets++ - return "[src] will now effect [max_targets] people." \ No newline at end of file diff --git a/code/modules/spells/targeted/swap.dm b/code/modules/spells/targeted/swap.dm deleted file mode 100644 index 150bd9030772..000000000000 --- a/code/modules/spells/targeted/swap.dm +++ /dev/null @@ -1,41 +0,0 @@ -/spell/targeted/swap - name = "swap" - desc = "This spell swaps the positions of the wizard and a target. Causes brain damage." - feedback = "SW" - school = "conjuration" - - charge_type = Sp_HOLDVAR - holder_var_type = "brainloss" - holder_var_amount = 10 - - invocation = "Joyo!" - invocation_type = SpI_WHISPER - - level_max = list(Sp_TOTAL = 2, Sp_SPEED = 0, Sp_POWER = 2) - - spell_flags = Z2NOCAST - range = 6 - max_targets = 1 - compatible_mobs = list(/mob/living) - - hud_state = "wiz_swap" - - cast_sound = 'sound/magic/mandswap.ogg' - -/spell/targeted/swap/cast(var/list/targets, mob/user) - for(var/mob/T in targets) - var/turf/aT = get_turf(T) - var/turf/bT = get_turf(user) - - T.forceMove(bT) - user.forceMove(aT) - - apply_spell_damage(T) - -/spell/targeted/swap/empower_spell() - if(!..()) - return 0 - - amt_eye_blind += 2 - - return "This spell will now blind the target." diff --git a/code/modules/spells/targeted/targeted.dm b/code/modules/spells/targeted/targeted.dm deleted file mode 100644 index deedb0e56709..000000000000 --- a/code/modules/spells/targeted/targeted.dm +++ /dev/null @@ -1,175 +0,0 @@ -/* -Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range -Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm -*/ - - -/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob - var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range - var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast - - - var/amt_weakened = 0 - var/amt_paralysis = 0 - var/amt_stunned = 0 - - var/amt_dizziness = 0 - var/amt_confused = 0 - var/amt_stuttering = 0 - - //set to negatives for healing unless commented otherwise - var/amt_dam_fire = 0 - var/amt_dam_brute = 0 - var/amt_dam_oxy = 0 - var/amt_dam_tox = 0 - var/amt_dam_robo = 0 - var/amt_brain = 0 - var/amt_radiation = 0 - var/amt_blood = 0 //Positive numbers to add blood - var/amt_organ = 0 //Positive numbers for healing - - var/amt_eye_blind = 0 - var/amt_eye_blurry = 0 - - var/effect_state = null //What effect to show on each, if any - var/effect_duration = 0 - var/effect_color = "#ffffff" - - var/list/compatible_mobs = list() - - -/spell/targeted/choose_targets(mob/user = usr) - var/list/targets = list() - - if(max_targets == 0) //unlimited - if(range == -2) - targets = GLOB.living_mob_list_ - else - for(var/mob/living/target in view_or_range(range, holder, selection_type)) - targets += target - - else if(max_targets == 1) //single target can be picked - if((range == 0 || range == -1) && spell_flags & INCLUDEUSER) - targets += user - else - var/list/possible_targets = list() - var/list/starting_targets - if(range == -2) - starting_targets = GLOB.living_mob_list_ - else - starting_targets = view_or_range(range, holder, selection_type) - - for(var/mob/living/M in starting_targets) - if(!(spell_flags & INCLUDEUSER) && M == user) - continue - if((spell_flags & NOFACTION) && user.faction == M.faction) - continue - if((spell_flags & NONONFACTION) && user.faction != M.faction) - continue - if(compatible_mobs && compatible_mobs.len) - if(!is_type_in_list(M, compatible_mobs)) continue - if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs)) - continue - possible_targets += M - - if(possible_targets.len) - if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details - var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets - if(temp_target) - targets += temp_target - else - targets += pick(possible_targets) - //Adds a safety check post-input to make sure those targets are actually in range. - - - else - var/list/possible_targets = list() - var/list/starting_targets - - if(range == -2) - starting_targets = GLOB.living_mob_list_ - else - starting_targets = view_or_range(range, holder, selection_type) - - for(var/mob/living/target in starting_targets) - if(!(spell_flags & INCLUDEUSER) && target == user) - continue - if(compatible_mobs && !is_type_in_list(target, compatible_mobs)) - continue - possible_targets += target - - if(spell_flags & SELECTABLE) - for(var/i = 1; i<=max_targets, i++) - if(!possible_targets.len) - break - var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets - if(!M) - break - if(range != -2) - if(!(M in view_or_range(range, holder, selection_type))) - continue - targets += M - possible_targets -= M - else - for(var/i=1,i<=max_targets,i++) - if(!possible_targets.len) - break - if(target_ignore_prev) - var/target = pick(possible_targets) - possible_targets -= target - targets += target - else - targets += pick(possible_targets) - - if(!(spell_flags & INCLUDEUSER) && (user in targets)) - targets -= user - - if(compatible_mobs && compatible_mobs.len) - for(var/mob/living/target in targets) //filters out all the non-compatible mobs - if(!is_type_in_list(target, compatible_mobs)) - targets -= target - - return targets - -/spell/targeted/cast(var/list/targets, mob/user) - for(var/mob/living/target in targets) - if(range >= 0) - if(!(target in view_or_range(range, holder, selection_type))) //filter at time of casting - targets -= target - continue - apply_spell_damage(target) - -/spell/targeted/proc/apply_spell_damage(mob/living/target) - target.adjustBruteLoss(amt_dam_brute) - target.adjustFireLoss(amt_dam_fire) - target.adjustToxLoss(amt_dam_tox) - target.adjustOxyLoss(amt_dam_oxy) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - for(var/obj/item/organ/internal/affecting in H.internal_organs) - if(affecting && istype(affecting)) - affecting.heal_damage(amt_organ, amt_organ) - for(var/obj/item/organ/external/affecting in H.organs) - if(affecting && istype(affecting)) - var/dam = BP_IS_PROSTHETIC(affecting) ? -amt_dam_robo : amt_organ - affecting.heal_damage(dam, dam, robo_repair = BP_IS_PROSTHETIC(affecting)) - H.vessel.add_reagent(H.species.blood_reagent, amt_blood) - H.adjustBrainLoss(amt_brain) - H.radiation += min(H.radiation, amt_radiation) - H.fixblood() - target.regenerate_icons() - //disabling - target.Weaken(amt_weakened) - target.Paralyse(amt_paralysis) - target.Stun(amt_stunned) - if(amt_weakened || amt_paralysis || amt_stunned) - if(target.buckled) - target.buckled = null - target.eye_blind += amt_eye_blind - target.eye_blurry += amt_eye_blurry - target.dizziness += amt_dizziness - target.confused += amt_confused - target.stuttering += amt_stuttering - if(effect_state) - var/obj/o = new /obj/effect/temporary(get_turf(target), effect_duration, 'icons/effects/effects.dmi', effect_state) - o.color = effect_color \ No newline at end of file diff --git a/code/modules/spells/targeted/torment.dm b/code/modules/spells/targeted/torment.dm deleted file mode 100644 index 9391e9012bb8..000000000000 --- a/code/modules/spells/targeted/torment.dm +++ /dev/null @@ -1,34 +0,0 @@ -/spell/targeted/torment - name = "Torment" - desc = "this spell causes pain to all those in its radius." - feedback = "TM" - school = "illusion" - charge_max = 150 - spell_flags = NOFACTION - invocation = "Rai Di-Kaal!" - invocation_type = SpI_SHOUT - range = 5 - level_max = list(Sp_TOTAL = 1, Sp_SPEED = 0, Sp_POWER = 1) - cooldown_min = 50 - message = "So much pain! All you can hear is screaming!" - - max_targets = 0 - compatible_mobs = list(/mob/living/carbon/human) - - var/loss = 30 - - hud_state = "wiz_horse" - cast_sound = 'sound/magic/cowhead_curse.ogg' - -/spell/targeted/torment/cast(var/list/targets, var/mob/user) - gibs(user.loc) - for(var/mob/living/carbon/human/H in targets) - H.adjustHalLoss(loss) - -/spell/targeted/torment/empower_spell() - if(!..()) - return 0 - - loss += 30 - - return "[src] will now cause more pain." \ No newline at end of file diff --git a/code/modules/sprite_accessories/_accessory.dm b/code/modules/sprite_accessories/_accessory.dm index 3898101d8a2b..7993cfbb561f 100644 --- a/code/modules/sprite_accessories/_accessory.dm +++ b/code/modules/sprite_accessories/_accessory.dm @@ -1,29 +1,269 @@ /* - Hello and welcome to sprite_accessories: For sprite accessories, such as hair, + Hello and welcome to sprite accessories: For sprite accessories, such as hair, facial hair, and possibly tattoos and stuff somewhere along the line. This file is intended to be friendly for people with little to no actual coding experience. The process of adding in new hairstyles has been made pain-free and easy to do. Enjoy! - Doohl - Notice: This all gets automatically compiled in a list in dna2.dm, so you do not - have to define any UI values for sprite accessories manually for hair and facial - hair. Just add in new hair types and the game will naturally adapt. + Notice: This all gets automatically compiled in a list via the decl rfepository, + so you do not have to add sprite accessories manually to any lists etc. Just add + in new hair types and the game will naturally adapt. - !!WARNING!!: changing existing hair information can be VERY hazardous to savefiles, - to the point where you may completely corrupt a server's savefiles. Please refrain - from doing this unless you absolutely know what you are doing, and have defined a - conversion in savefile.dm + Changing icon states, icon files and names should not represent any risks to + existing savefiles, but please do not change decl uids unless you are very sure + you know what you're doing and don't mind potentially causing people's savefiles + to load the default values for the marking category in question. */ -/datum/sprite_accessory - var/name // The preview name of the accessory - var/icon // the icon file the accessory is located in - var/icon_state // the icon_state of the accessory - var/preview_state // A custom preview state for whatever reason - var/gender = NEUTER // Restricted to specific genders. - var/list/species_allowed = list(SPECIES_HUMAN) // Restrict some styles to specific bodytypes - var/list/subspecies_allowed // Restrict some styles to specific species names - var/do_colouration = 1 // Whether or not the accessory can be affected by colouration - var/blend = ICON_ADD - var/flags = 0 \ No newline at end of file +/decl/sprite_accessory + abstract_type = /decl/sprite_accessory + decl_flags = DECL_FLAG_MANDATORY_UID + /// The preview name of the accessory + var/name + /// the icon file the accessory is located in + var/icon + /// the icon_state of the accessory + var/icon_state + /// Restricted to specific bodytypes. null matches any + var/list/decl/bodytype/bodytypes_allowed + /// Restricted from specific bodytypes. null matches none + var/list/decl/bodytype/bodytypes_denied + /// Restrict some styles to specific species UIDs. + var/list/species_allowed = list(/decl/species/human::uid) + /// Restrict some styles to specific bodytype flags. + var/body_flags_allowed + /// Restrict some styles to specific bodytype flags. + var/body_flags_denied + /// Restricts some styles to specific bodytype categories + var/list/bodytype_categories_allowed + /// Restricts some styles to specific bodytype categories + var/list/bodytype_categories_denied + /// Slot to check equipment for when hiding this accessory. + var/hidden_by_gear_slot + /// Flag to check equipment for when hiding this accessory. + var/hidden_by_gear_flag + /// Various flags controlling some checks and behavior. + var/accessory_flags = 0 + /// Flags to check when applying this accessory to the mob. + var/requires_appearance_flags = 0 + /// Icon cache for various icon generation steps. + var/list/cached_icons = list() + /// Whether or not this overlay should be trimmed to fit the base bodypart icon. + var/mask_to_bodypart = FALSE + /// What blend mode to use when colourizing this accessory. + var/color_blend = ICON_ADD + /// What blend mode to use when applying this accessory to the compiled organ. + var/layer_blend = ICON_OVERLAY + /// What bodypart tags does this marking apply to? + var/list/body_parts + /// Set to a layer integer to apply this as an overlay over the top of hair and such. + var/sprite_overlay_layer + /// Set to a layer integer to apply this as an overlay over the top of entire planes. + var/sprite_overlay_plane + /// A list of sprite accessory types that are disallowed by this one being included. + var/list/disallows_accessories + /// Whether or not this accessory is transferred via DNA (ie. not a scar or tattoo) + var/is_heritable = FALSE + /// What category does this accessory fall under? + var/accessory_category + /// Whether or not this accessory should be drawn on the mob at all. + var/draw_accessory = TRUE + /// Bitflags indicating what grooming tools work on this accessory. + var/grooming_flags = GROOMABLE_NONE + /// A list of metadata types for customisation of this accessory. + var/list/accessory_metadata_types + /// A value to check whitelists for. + var/is_whitelisted + /// A set of trait levels to check for. + var/list/required_traits + +/decl/sprite_accessory/Initialize() + . = ..() + if(!isnull(color_blend)) + LAZYDISTINCTADD(accessory_metadata_types, /decl/sprite_accessory_metadata/color) + +/decl/sprite_accessory/proc/refresh_mob(var/mob/living/subject) + return + +/decl/sprite_accessory/proc/accessory_is_available(mob/owner, decl/species/species, decl/bodytype/bodytype, list/traits) + if(species) + var/species_is_permitted = TRUE + if(species_allowed) + species_is_permitted = (species.uid in species_allowed) + if(!species_is_permitted) + return FALSE + if(bodytype) + if(LAZYLEN(bodytypes_allowed) && !(bodytype.type in bodytypes_allowed)) + return FALSE + if(LAZYISIN(bodytypes_denied, bodytype.type)) + return FALSE + if(!isnull(bodytype_categories_allowed) && !(bodytype.bodytype_category in bodytype_categories_allowed)) + return FALSE + if(!isnull(bodytype_categories_denied) && (bodytype.bodytype_category in bodytype_categories_denied)) + return FALSE + if(!isnull(body_flags_allowed) && !(body_flags_allowed & bodytype.bodytype_flag)) + return FALSE + if(!isnull(body_flags_denied) && (body_flags_denied & bodytype.bodytype_flag)) + return FALSE + if(requires_appearance_flags && !(bodytype.appearance_flags & requires_appearance_flags)) + return FALSE + if(is_whitelisted && usr?.ckey && !is_admin(usr) && !is_alien_whitelisted(usr, is_whitelisted)) + return FALSE + if(length(required_traits) && traits != FALSE) + if(!islist(traits) || !length(traits)) + return FALSE + for(var/trait in required_traits) + if(!(trait in traits)) + return FALSE + return TRUE + +/decl/sprite_accessory/validate() + . = ..() + if(!ispath(accessory_category, /decl/sprite_accessory_category)) + . += "invalid sprite accessory category: [accessory_category || "null"]" + if(!icon) + . += "missing icon" + else + if(!icon_state) + . += "missing icon_state" + else if(!check_state_in_icon(icon_state, icon)) + . += "missing icon state \"[icon_state]\" in [icon]" + +/decl/sprite_accessory/proc/get_hidden_substitute() + return + +/decl/sprite_accessory/proc/is_hidden(var/obj/item/organ/external/organ) + if(!organ?.owner) + return FALSE + if(hidden_by_gear_slot) + if(islist(hidden_by_gear_slot)) + for(var/hiding_slot in hidden_by_gear_slot) + var/obj/item/hiding = organ.owner.get_equipped_item(hiding_slot) + if(hiding && (hiding.flags_inv & hidden_by_gear_flag)) + return TRUE + else + var/obj/item/hiding = organ.owner.get_equipped_item(hidden_by_gear_slot) + return hiding && (hiding.flags_inv & hidden_by_gear_flag) + return FALSE + +/decl/sprite_accessory/proc/get_accessory_icon(var/obj/item/organ/external/organ) + return icon + +/decl/sprite_accessory/proc/can_be_groomed_with(obj/item/organ/external/organ, obj/item/grooming/tool) + if(istype(tool) && (grooming_flags & tool.grooming_flags)) + return GROOMING_RESULT_SUCCESS + return GROOMING_RESULT_FAILED + +/decl/sprite_accessory/proc/get_grooming_descriptor(grooming_result, obj/item/organ/external/organ, obj/item/grooming/tool) + return "mystery grooming target" + +/decl/sprite_accessory/proc/get_default_accessory_metadata() + . = list() + for(var/metadata_type in accessory_metadata_types) + var/decl/sprite_accessory_metadata/metadata_decl = GET_DECL(metadata_type) + .[metadata_type] = metadata_decl.default_value + +/decl/sprite_accessory/proc/validate_cached_icon_metadata(list/metadata) + LAZYINITLIST(metadata) + for(var/metadata_type in accessory_metadata_types) + var/decl/sprite_accessory_metadata/metadata_decl = GET_DECL(metadata_type) + metadata[metadata_type] = metadata_decl.sanitize_data(metadata[metadata_type]) + return metadata + +/decl/sprite_accessory/proc/get_cached_accessory_icon_key(var/obj/item/organ/external/organ, var/list/metadata) + . = list(organ.bodytype, organ.icon_state) + for(var/metadata_type in accessory_metadata_types) + . += LAZYACCESS(metadata, metadata_type) || "null" + return JOINTEXT(.) + +/decl/sprite_accessory/proc/get_cached_accessory_icon(var/obj/item/organ/external/organ, var/list/metadata) + + if(!icon_state || !istype(organ)) + return null + + metadata = validate_cached_icon_metadata(metadata) + if(!islist(metadata)) + return null + + var/cache_key = get_cached_accessory_icon_key(organ, metadata) + var/icon/accessory_icon = cached_icons[cache_key] + if(!accessory_icon) + + // make a new one to avoid mutating the base + var/use_icon = get_accessory_icon(organ) + if(!use_icon) + return + + var/use_state = icon_state + var/marking_modifier = organ.owner?.get_overlay_state_modifier() + if(marking_modifier) + use_state = "[use_state][marking_modifier]" + + if(!check_state_in_icon(use_state, use_icon)) + return + + accessory_icon = icon(use_icon, use_state) + + // Inner overlay and color. + var/inner_color = LAZYACCESS(metadata, SAM_COLOR_INNER) + + // Base icon and color. + if(!isnull(color_blend)) + var/decl/sprite_accessory_metadata/gradient/gradient_metadata = GET_DECL(SAM_GRADIENT) + var/icon/gradient_icon = LAZYACCESS(metadata, SAM_GRADIENT) + if(istext(gradient_icon) && (gradient_metadata.validate_data(gradient_icon))) + gradient_icon = icon(gradient_metadata.icon, gradient_icon) + else + gradient_icon = null + if(gradient_icon) + gradient_icon.Blend(accessory_icon, ICON_AND) + if(!isnull(inner_color)) + gradient_icon.Blend(inner_color, color_blend) + var/color = LAZYACCESS(metadata, SAM_COLOR) + if(!isnull(color)) + accessory_icon.Blend(color, color_blend) + if(gradient_icon) + accessory_icon.Blend(gradient_icon, ICON_OVERLAY) + + if(!isnull(inner_color)) + var/inner_state = "[use_state]_inner" + if(check_state_in_icon(inner_state, use_icon)) + var/icon/inner_icon = icon(use_icon, inner_state) + if(!isnull(color_blend)) + inner_icon.Blend(inner_color, color_blend) + accessory_icon.Blend(inner_icon, ICON_OVERLAY) + + // Clip the icon if needed. + if(mask_to_bodypart) + accessory_icon.Blend(get_limb_mask_for(organ), ICON_MULTIPLY) + + // Cache it for next time! + cached_icons[cache_key] = accessory_icon + + return accessory_icon + +/decl/sprite_accessory/proc/update_metadata(list/new_metadata, list/old_metadata) + if(!islist(new_metadata) && !islist(old_metadata)) + return get_default_accessory_metadata() + if(!islist(new_metadata)) + new_metadata = get_default_accessory_metadata() + if(!islist(old_metadata)) + old_metadata = get_default_accessory_metadata() + for(var/metadata_type in old_metadata) + if(!(metadata_type in new_metadata)) + new_metadata[metadata_type] = old_metadata[metadata_type] + for(var/metadata_type in new_metadata) + if(!(metadata_type in old_metadata)) + new_metadata -= metadata_type + return new_metadata + +/decl/sprite_accessory/proc/get_random_metadata() + return list(SAM_COLOR = get_random_colour()) + +/decl/sprite_accessory_category/proc/prepare_character(mob/living/character, list/accessories) + return + +/decl/sprite_accessory_category/proc/prepare_mob_snapshot(datum/mob_snapshot/snapshot, list/accessories) + return + diff --git a/code/modules/sprite_accessories/_accessory_category.dm b/code/modules/sprite_accessories/_accessory_category.dm new file mode 100644 index 000000000000..58e9b96498fe --- /dev/null +++ b/code/modules/sprite_accessories/_accessory_category.dm @@ -0,0 +1,24 @@ +/decl/sprite_accessory_category + decl_flags = DECL_FLAG_MANDATORY_UID + abstract_type = /decl/sprite_accessory_category + /// A name to display in preferences. + var/name + /// A base abstract accessory type for this category. + var/base_accessory_type + /// A maximum number of selections. Ignored if null. + var/max_selections + /// A default always-available type used as a fallback. + var/default_accessory + /// Set to FALSE for categories where multiple selection is allowed (markings) + var/single_selection = TRUE + /// Set to TRUE to apply these markings as defaults when bodytype is set. + var/always_apply_defaults = FALSE + +/decl/sprite_accessory_category/validate() + . = ..() + if(!name) + . += "no name set" + if(!ispath(base_accessory_type, /decl/sprite_accessory)) + . += "invalid base accessory type: [base_accessory_type || "null"]" + if(single_selection && !default_accessory) + . += "single selection set but no default accessory set" diff --git a/code/modules/sprite_accessories/_accessory_facial.dm b/code/modules/sprite_accessories/_accessory_facial.dm deleted file mode 100644 index b845be67f713..000000000000 --- a/code/modules/sprite_accessories/_accessory_facial.dm +++ /dev/null @@ -1,142 +0,0 @@ -/* -/////////////////////////////////// -/ =---------------------------= / -/ == Facial Hair Definitions == / -/ =---------------------------= / -/////////////////////////////////// -*/ - -/datum/sprite_accessory/facial_hair - icon = 'icons/mob/human_races/species/human/facial.dmi' - gender = MALE // barf (unless you're a dorf, dorfs dig chix /w beards :P) - -/datum/sprite_accessory/facial_hair/shaved - name = "Shaved" - icon_state = "bald" - gender = NEUTER - species_allowed = list(SPECIES_HUMAN) - -/datum/sprite_accessory/facial_hair/watson - name = "Watson Mustache" - icon_state = "facial_watson" - -/datum/sprite_accessory/facial_hair/hogan - name = "Hulk Hogan Mustache" - icon_state = "facial_hogan" //-Neek - -/datum/sprite_accessory/facial_hair/vandyke - name = "Van Dyke Mustache" - icon_state = "facial_vandyke" - -/datum/sprite_accessory/facial_hair/chaplin - name = "Square Mustache" - icon_state = "facial_chaplin" - -/datum/sprite_accessory/facial_hair/selleck - name = "Selleck Mustache" - icon_state = "facial_selleck" - -/datum/sprite_accessory/facial_hair/neckbeard - name = "Neckbeard" - icon_state = "facial_neckbeard" - -/datum/sprite_accessory/facial_hair/fullbeard - name = "Full Beard" - icon_state = "facial_fullbeard" - -/datum/sprite_accessory/facial_hair/longbeard - name = "Long Beard" - icon_state = "facial_longbeard" - -/datum/sprite_accessory/facial_hair/vlongbeard - name = "Very Long Beard" - icon_state = "facial_wise" - -/datum/sprite_accessory/facial_hair/elvis - name = "Elvis Sideburns" - icon_state = "facial_elvis" - species_allowed = list(SPECIES_HUMAN) - -/datum/sprite_accessory/facial_hair/abe - name = "Abraham Lincoln Beard" - icon_state = "facial_abe" - -/datum/sprite_accessory/facial_hair/chinstrap - name = "Chinstrap" - icon_state = "facial_chin" - -/datum/sprite_accessory/facial_hair/hip - name = "Hipster Beard" - icon_state = "facial_hip" - -/datum/sprite_accessory/facial_hair/gt - name = "Goatee" - icon_state = "facial_gt" - -/datum/sprite_accessory/facial_hair/jensen - name = "Adam Jensen Beard" - icon_state = "facial_jensen" - -/datum/sprite_accessory/facial_hair/volaju - name = "Volaju" - icon_state = "facial_volaju" - -/datum/sprite_accessory/facial_hair/dwarf - name = "Dwarf Beard" - icon_state = "facial_dwarf" - -/datum/sprite_accessory/facial_hair/threeOclock - name = "3 O'clock Shadow" - icon_state = "facial_3oclock" - -/datum/sprite_accessory/facial_hair/threeOclockstache - name = "3 O'clock Shadow and Moustache" - icon_state = "facial_3oclockmoustache" - -/datum/sprite_accessory/facial_hair/fiveOclock - name = "5 O'clock Shadow" - icon_state = "facial_5oclock" - -/datum/sprite_accessory/facial_hair/fiveOclockstache - name = "5 O'clock Shadow and Moustache" - icon_state = "facial_5oclockmoustache" - -/datum/sprite_accessory/facial_hair/sevenOclock - name = "7 O'clock Shadow" - icon_state = "facial_7oclock" - -/datum/sprite_accessory/facial_hair/sevenOclockstache - name = "7 O'clock Shadow and Moustache" - icon_state = "facial_7oclockmoustache" - -/datum/sprite_accessory/facial_hair/mutton - name = "Mutton Chops" - icon_state = "facial_mutton" - -/datum/sprite_accessory/facial_hair/muttonstache - name = "Mutton Chops and Moustache" - icon_state = "facial_muttonmus" - -/datum/sprite_accessory/facial_hair/walrus - name = "Walrus Moustache" - icon_state = "facial_walrus" - -/datum/sprite_accessory/facial_hair/croppedbeard - name = "Full Cropped Beard" - icon_state = "facial_croppedfullbeard" - -/datum/sprite_accessory/facial_hair/chinless - name = "Chinless Beard" - icon_state = "facial_chinlessbeard" - -/datum/sprite_accessory/facial_hair/braided - name = "Braided Beard" - icon_state = "facial_biker" - -/datum/sprite_accessory/facial_hair/seadog - name = "Sea Dog" - icon_state = "facial_seadog" - -/datum/sprite_accessory/facial_hair/lumberjack - name = "Lumberjack" - icon_state = "facial_lumberjack" diff --git a/code/modules/sprite_accessories/_accessory_hair.dm b/code/modules/sprite_accessories/_accessory_hair.dm deleted file mode 100644 index 8638c238a5e3..000000000000 --- a/code/modules/sprite_accessories/_accessory_hair.dm +++ /dev/null @@ -1,724 +0,0 @@ -/* -//////////////////////////// -/ =--------------------= / -/ == Hair Definitions == / -/ =--------------------= / -//////////////////////////// -*/ - -/datum/sprite_accessory/hair - icon = 'icons/mob/human_races/species/human/hair.dmi' - -/datum/sprite_accessory/hair/bald - name = "Bald" - icon_state = "bald" - gender = MALE - species_allowed = list(SPECIES_HUMAN) - flags = VERY_SHORT | HAIR_BALD - -/datum/sprite_accessory/hair/short - name = "Short Hair" // try to capatilize the names please~ - icon_state = "hair_a" // you do not need to define _s or _l sub-states, game automatically does this for you - flags = VERY_SHORT - -/datum/sprite_accessory/hair/twintail - name = "Twintail" - icon_state = "hair_twintail" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/short2 - name = "Short Hair 2" - icon_state = "hair_shorthair3" - -/datum/sprite_accessory/hair/cut - name = "Cut Hair" - icon_state = "hair_c" - flags = VERY_SHORT - -/datum/sprite_accessory/hair/flair - name = "Flaired Hair" - icon_state = "hair_flair" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/long - name = "Shoulder-length Hair" - icon_state = "hair_b" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longer - name = "Long Hair" - icon_state = "hair_vlong" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longest - name = "Very Long Hair" - icon_state = "hair_longest" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longfringe - name = "Long Fringe" - icon_state = "hair_longfringe" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longestalt - name = "Longer Fringe" - icon_state = "hair_vlongfringe" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/halfbang - name = "Half-banged Hair" - icon_state = "hair_halfbang" - -/datum/sprite_accessory/hair/halfbangalt - name = "Half-banged Hair Alt" - icon_state = "hair_halfbang_alt" - -/datum/sprite_accessory/hair/ponytail1 - name = "Ponytail 1" - icon_state = "hair_ponytail" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ponytail2 - name = "Ponytail 2" - icon_state = "hair_pa" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ponytail3 - name = "Ponytail 3" - icon_state = "hair_ponytail3" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ponytail4 - name = "Ponytail 4" - icon_state = "hair_ponytail4" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ponytail5 - name = "Ponytail 5" - icon_state = "hair_ponytail5" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ponytail6 - name = "Ponytail 6" - icon_state = "hair_ponytail6" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/sideponytail - name = "Side Ponytail" - icon_state = "hair_stail" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/parted - name = "Parted" - icon_state = "hair_parted" - -/datum/sprite_accessory/hair/pompadour - name = "Pompadour" - icon_state = "hair_pompadour" - gender = MALE - -/datum/sprite_accessory/hair/sleeze - name = "Sleeze" - icon_state = "hair_sleeze" - flags = VERY_SHORT - -/datum/sprite_accessory/hair/quiff - name = "Quiff" - icon_state = "hair_quiff" - gender = MALE - -/datum/sprite_accessory/hair/bedhead - name = "Bedhead" - icon_state = "hair_bedhead" - -/datum/sprite_accessory/hair/bedhead2 - name = "Bedhead 2" - icon_state = "hair_bedheadv2" - -/datum/sprite_accessory/hair/bedhead3 - name = "Bedhead 3" - icon_state = "hair_bedheadv3" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/beehive - name = "Beehive" - icon_state = "hair_beehive" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/beehive2 - name = "Beehive 2" - icon_state = "hair_beehive2" - gender = FEMALE - -/datum/sprite_accessory/hair/bobcurl - name = "Bobcurl" - icon_state = "hair_bobcurl" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/bob - name = "Bob" - icon_state = "hair_bobcut" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/bobcutalt - name = "Chin Length Bob" - icon_state = "hair_bobcutalt" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/bowl - name = "Bowl" - icon_state = "hair_bowlcut" - gender = MALE - -/datum/sprite_accessory/hair/buzz - name = "Buzzcut" - icon_state = "hair_buzzcut" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/crew - name = "Crewcut" - icon_state = "hair_crewcut" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/combover - name = "Combover" - icon_state = "hair_combover" - gender = MALE - -/datum/sprite_accessory/hair/father - name = "Father" - icon_state = "hair_father" - gender = MALE - -/datum/sprite_accessory/hair/reversemohawk - name = "Reverse Mohawk" - icon_state = "hair_reversemohawk" - gender = MALE - -/datum/sprite_accessory/hair/devillock - name = "Devil Lock" - icon_state = "hair_devilock" - -/datum/sprite_accessory/hair/dreadlocks - name = "Dreadlocks" - icon_state = "hair_dreads" - -/datum/sprite_accessory/hair/curls - name = "Curls" - icon_state = "hair_curls" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/afro - name = "Afro" - icon_state = "hair_afro" - -/datum/sprite_accessory/hair/afro2 - name = "Afro 2" - icon_state = "hair_afro2" - -/datum/sprite_accessory/hair/afro_large - name = "Big Afro" - icon_state = "hair_bigafro" - gender = MALE - -/datum/sprite_accessory/hair/rows - name = "Rows" - icon_state = "hair_rows1" - flags = VERY_SHORT - -/datum/sprite_accessory/hair/rows2 - name = "Rows 2" - icon_state = "hair_rows2" - flags = VERY_SHORT | HAIR_TIEABLE - -/datum/sprite_accessory/hair/sargeant - name = "Flat Top" - icon_state = "hair_sargeant" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/emo - name = "Emo" - icon_state = "hair_emo" - -/datum/sprite_accessory/hair/emo2 - name = "Emo Alt" - icon_state = "hair_emo2" - -/datum/sprite_accessory/hair/longemo - name = "Long Emo" - icon_state = "hair_emolong" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/shortovereye - name = "Overeye Short" - icon_state = "hair_shortovereye" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longovereye - name = "Overeye Long" - icon_state = "hair_longovereye" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/flow - name = "Flow Hair" - icon_state = "hair_f" - -/datum/sprite_accessory/hair/feather - name = "Feather" - icon_state = "hair_feather" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/hitop - name = "Hitop" - icon_state = "hair_hitop" - gender = MALE - -/datum/sprite_accessory/hair/mohawk - name = "Mohawk" - icon_state = "hair_d" - -/datum/sprite_accessory/hair/jensen - name = "Adam Jensen Hair" - icon_state = "hair_jensen" - gender = MALE - -/datum/sprite_accessory/hair/gelled - name = "Gelled Back" - icon_state = "hair_gelled" - gender = FEMALE - -/datum/sprite_accessory/hair/gentle - name = "Gentle" - icon_state = "hair_gentle" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/spiky - name = "Spiky" - icon_state = "hair_spikey" - -/datum/sprite_accessory/hair/kusangi - name = "Kusanagi Hair" - icon_state = "hair_kusanagi" - -/datum/sprite_accessory/hair/kagami - name = "Pigtails" - icon_state = "hair_kagami" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/himecut - name = "Hime Cut" - icon_state = "hair_himecut" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/shorthime - name = "Short Hime Cut" - icon_state = "hair_shorthime" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/grandebraid - name = "Grande Braid" - icon_state = "hair_grande" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/mbraid - name = "Medium Braid" - icon_state = "hair_shortbraid" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/braid2 - name = "Long Braid" - icon_state = "hair_hbraid" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/odango - name = "Odango" - icon_state = "hair_odango" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ombre - name = "Ombre" - icon_state = "hair_ombre" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/updo - name = "Updo" - icon_state = "hair_updo" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/skinhead - name = "Skinhead" - icon_state = "hair_skinhead" - flags = VERY_SHORT - -/datum/sprite_accessory/hair/balding - name = "Balding Hair" - icon_state = "hair_e" - gender = MALE // turnoff! - flags = VERY_SHORT - -/datum/sprite_accessory/hair/familyman - name = "The Family Man" - icon_state = "hair_thefamilyman" - gender = MALE - -/datum/sprite_accessory/hair/mahdrills - name = "Drillruru" - icon_state = "hair_drillruru" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/fringetail - name = "Fringetail" - icon_state = "hair_fringetail" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/dandypomp - name = "Dandy Pompadour" - icon_state = "hair_dandypompadour" - gender = MALE - -/datum/sprite_accessory/hair/poofy - name = "Poofy" - icon_state = "hair_poofy" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/crono - name = "Chrono" - icon_state = "hair_toriyama" - gender = MALE - -/datum/sprite_accessory/hair/vegeta - name = "Vegeta" - icon_state = "hair_toriyama2" - gender = MALE - -/datum/sprite_accessory/hair/cia - name = "CIA" - icon_state = "hair_cia" - gender = MALE - -/datum/sprite_accessory/hair/mulder - name = "Mulder" - icon_state = "hair_mulder" - gender = MALE - -/datum/sprite_accessory/hair/scully - name = "Scully" - icon_state = "hair_scully" - gender = FEMALE - -/datum/sprite_accessory/hair/nitori - name = "Nitori" - icon_state = "hair_nitori" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/joestar - name = "Joestar" - icon_state = "hair_joestar" - gender = MALE - -/datum/sprite_accessory/hair/volaju - name = "Volaju" - icon_state = "hair_volaju" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longeralt2 - name = "Long Hair Alt 2" - icon_state = "hair_longeralt2" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/shortbangs - name = "Short Bangs" - icon_state = "hair_shortbangs" - -/datum/sprite_accessory/hair/shavedbun - name = "Shaved Bun" - icon_state = "hair_shavedbun" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/halfshaved - name = "Half-Shaved" - icon_state = "hair_halfshaved" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/halfshavedemo - name = "Half-Shaved Emo" - icon_state = "hair_halfshavedemo" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/longsideemo - name = "Long Side Emo" - icon_state = "hair_longsideemo" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/bun - name = "Low Bun" - icon_state = "hair_bun" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/bun2 - name = "High Bun" - icon_state = "hair_bun2" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/doublebun - name = "Double-Bun" - icon_state = "hair_doublebun" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/lowfade - name = "Low Fade" - icon_state = "hair_lowfade" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/medfade - name = "Medium Fade" - icon_state = "hair_medfade" - flags = VERY_SHORT - -/datum/sprite_accessory/hair/highfade - name = "High Fade" - icon_state = "hair_highfade" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/baldfade - name = "Balding Fade" - icon_state = "hair_baldfade" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/nofade - name = "Regulation Cut" - icon_state = "hair_nofade" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/trimflat - name = "Trimmed Flat Top" - icon_state = "hair_trimflat" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/shaved - name = "Shaved" - icon_state = "hair_shaved" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/trimmed - name = "Trimmed" - icon_state = "hair_trimmed" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/tightbun - name = "Tight Bun" - icon_state = "hair_tightbun" - gender = FEMALE - flags = VERY_SHORT | HAIR_TIEABLE - -/datum/sprite_accessory/hair/coffeehouse - name = "Coffee House Cut" - icon_state = "hair_coffeehouse" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/undercut - name = "Undercut" - icon_state = "hair_undercut" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/partfade - name = "Parted Fade" - icon_state = "hair_shavedpart" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/hightight - name = "High and Tight" - icon_state = "hair_hightight" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/rowbun - name = "Row Bun" - icon_state = "hair_rowbun" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/rowdualbraid - name = "Row Dual Braid" - icon_state = "hair_rowdualtail" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/rowbraid - name = "Row Braid" - icon_state = "hair_rowbraid" - gender = FEMALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/regulationmohawk - name = "Regulation Mohawk" - icon_state = "hair_shavedmohawk" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/topknot - name = "Topknot" - icon_state = "hair_topknot" - gender = MALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/ronin - name = "Ronin" - icon_state = "hair_ronin" - gender = MALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/bowlcut2 - name = "Bowl2" - icon_state = "hair_bowlcut2" - gender = MALE - -/datum/sprite_accessory/hair/thinning - name = "Thinning" - icon_state = "hair_thinning" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/thinningfront - name = "Thinning Front" - icon_state = "hair_thinningfront" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/thinningback - name = "Thinning Back" - icon_state = "hair_thinningrear" - gender = MALE - flags = VERY_SHORT - -/datum/sprite_accessory/hair/manbun - name = "Manbun" - icon_state = "hair_manbun" - gender = MALE - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/leftsidecut - name = "Left Sidecut" - icon_state = "hair_leftside" - -/datum/sprite_accessory/hair/rightsidecut - name = "Right Sidecut" - icon_state = "hair_rightside" - -/datum/sprite_accessory/hair/slick - name = "Slick" - icon_state = "hair_slick" - -/datum/sprite_accessory/hair/messyhair - name = "Messy" - icon_state = "hair_messyhair" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/averagejoe - name = "Average Joe" - icon_state = "hair_averagejoe" - -/datum/sprite_accessory/hair/sideswept - name = "Sideswept Hair" - icon_state = "hair_sideswept" - -/datum/sprite_accessory/hair/mohawkshaved - name = "Shaved Mohawk" - icon_state = "hair_mohawkshaved" - -/datum/sprite_accessory/hair/mohawkshaved2 - name = "Tight Shaved Mohawk" - icon_state = "hair_mohawkshaved2" - -/datum/sprite_accessory/hair/mohawkshavednaomi - name = "Naomi Mohawk" - icon_state = "hair_mohawkshavednaomi" - -/datum/sprite_accessory/hair/amazon - name = "Amazon" - icon_state = "hair_amazon" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/straightlong - name = "Straight Long" - icon_state = "hair_straightlong" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/marysue - name = "Mary Sue" - icon_state = "hair_marysue" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/messyhair2 - name = "Messy Hair 2" - icon_state = "hair_messyhair2" - -/datum/sprite_accessory/hair/buzzcut2 - name = "Buzzcut 2" - icon_state = "hair_buzzcut2" - -/datum/sprite_accessory/hair/sideundercut - name = "Side Undercut" - icon_state = "hair_sideundercut" - flags = VERY_SHORT - -/datum/sprite_accessory/hair/bighawk - name = "Big Mohawk" - icon_state = "hair_bighawk" - -/datum/sprite_accessory/hair/donutbun - name = "Donut Bun" - icon_state = "hair_donutbun" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/gentle2 - name = "Gentle 2" - icon_state = "hair_gentle2" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/gentle2long - name = "Gentle 2 Long" - icon_state = "hair_gentle2long" - flags = HAIR_TIEABLE - -/datum/sprite_accessory/hair/trimrsidecut - name = "Trimmed Right Sidecut" - icon_state = "hair_rightside_trim" - flags = HAIR_TIEABLE diff --git a/code/modules/sprite_accessories/_accessory_markings.dm b/code/modules/sprite_accessories/_accessory_markings.dm deleted file mode 100644 index d3a71824a63e..000000000000 --- a/code/modules/sprite_accessories/_accessory_markings.dm +++ /dev/null @@ -1,94 +0,0 @@ -//body markings - -/datum/sprite_accessory/marking - icon = 'icons/mob/human_races/species/default_markings.dmi' - do_colouration = 1 //Almost all of them have it, COLOR_ADD - //Empty list is unrestricted. Should only restrict the ones that make NO SENSE on other species, - //like IPC optics overlay stuff. - species_allowed = list(SPECIES_HUMAN) - var/layer_blend = ICON_OVERLAY - var/body_parts = list() //A list of bodyparts this covers, in organ_tag defines - //Reminder: BP_L_FOOT,BP_R_FOOT,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_L_HAND,BP_R_HAND,BP_CHEST,BP_GROIN,BP_HEAD - var/draw_target = MARKING_TARGET_SKIN - var/list/disallows = list() //A list of other marking types to ban from adding when this marking is already added - -/datum/sprite_accessory/marking/tat_hive - name = "Tattoo (Hive, Back)" - icon_state = "tat_hive" - body_parts = list(BP_CHEST) - -/datum/sprite_accessory/marking/tat_nightling - name = "Tattoo (Nightling, Back)" - icon_state = "tat_nightling" - body_parts = list(BP_CHEST) - -/datum/sprite_accessory/marking/tat_campbell - name = "Tattoo (Campbell, R.Arm)" - icon_state = "tat_campbell" - body_parts = list(BP_R_ARM) - -/datum/sprite_accessory/marking/tat_campbell/left - name = "Tattoo (Campbell, L.Arm)" - body_parts = list(BP_L_ARM) - -/datum/sprite_accessory/marking/tat_tiger1 - name = "Tattoo (Tiger Stripes, Body)" - icon_state = "tat_tiger" - body_parts = list(BP_CHEST,BP_GROIN) - -/datum/sprite_accessory/marking/tat_tiger_arm/left - name = "Tattoo (Tiger Left Arm)" - icon_state = "tat_tiger" - body_parts = list(BP_L_ARM) - -/datum/sprite_accessory/marking/tat_tiger_arm/right - name = "Tattoo (Tiger Right Arm)" - icon_state = "tat_tiger" - body_parts = list(BP_R_ARM) - -/datum/sprite_accessory/marking/tat_tiger_leg - name = "Tattoo (Tiger Left Leg)" - icon_state = "tat_tiger" - body_parts = list(BP_L_LEG) - -/datum/sprite_accessory/marking/tat_tiger_leg/right - name = "Tattoo (Tiger Right Leg)" - icon_state = "tat_tiger" - body_parts = list(BP_R_LEG) - -/datum/sprite_accessory/marking/tigerhead - name = "Tattoo (Tiger Head)" - icon_state = "tigerhead" - body_parts = list(BP_HEAD) - -/datum/sprite_accessory/marking/tat_bands_body - name = "Tattoo (Bands Body)" - icon_state = "bands" - body_parts = list(BP_CHEST,BP_GROIN) - -/datum/sprite_accessory/marking/tat_bands_arm/right - name = "Tattoo (Bands Right Arm)" - icon_state = "bands" - body_parts = list(BP_R_ARM) - -/datum/sprite_accessory/marking/tat_bands_arm/left - name = "Tattoo (Bands Left Arm)" - icon_state = "bands" - body_parts = list(BP_L_ARM) - -/datum/sprite_accessory/marking/tat_bands_hand/right - name = "Tattoo (Bands Right Hand)" - icon_state = "bands" - body_parts = list(BP_R_HAND) -/datum/sprite_accessory/marking/tat_bands_hand/left - name = "Tattoo (Bands Left Hand)" - icon_state = "bands" - body_parts = list(BP_L_HAND) -/datum/sprite_accessory/marking/tat_bands_leg/right - name = "Tattoo (Bands Right Leg)" - icon_state = "bands" - body_parts = list(BP_R_LEG) -/datum/sprite_accessory/marking/tat_bands_leg/left - name = "Tattoo (Bands Left Leg)" - icon_state = "bands" - body_parts = list(BP_L_LEG) \ No newline at end of file diff --git a/code/modules/sprite_accessories/_accessory_skin.dm b/code/modules/sprite_accessories/_accessory_skin.dm deleted file mode 100644 index 58e6c4be2c22..000000000000 --- a/code/modules/sprite_accessories/_accessory_skin.dm +++ /dev/null @@ -1,16 +0,0 @@ - -//skin styles - WIP -//going to have to re-integrate this with surgery -//let the icon_state hold an icon preview for now -/datum/sprite_accessory/skin - icon = 'icons/mob/human_races/species/human/body.dmi' - -/datum/sprite_accessory/skin/human - name = "Default human skin" - icon_state = "default" - species_allowed = list(SPECIES_HUMAN) - -/datum/sprite_accessory/skin/human_tatt01 - name = "Tatt01 human skin" - icon_state = "tatt1" - species_allowed = list(SPECIES_HUMAN) diff --git a/code/modules/sprite_accessories/cosmetics/_accessory_cosmetics.dm b/code/modules/sprite_accessories/cosmetics/_accessory_cosmetics.dm new file mode 100644 index 000000000000..91df82be7f3d --- /dev/null +++ b/code/modules/sprite_accessories/cosmetics/_accessory_cosmetics.dm @@ -0,0 +1,62 @@ +/decl/sprite_accessory_category/cosmetics + name = "Cosmetics" + default_accessory = /decl/sprite_accessory/cosmetics/none + base_accessory_type = /decl/sprite_accessory/cosmetics + uid = "acc_cat_cosmetics" + +/decl/sprite_accessory/cosmetics + icon = 'icons/mob/human_races/species/default_cosmetics.dmi' + body_parts = list(BP_HEAD) + color_blend = ICON_MULTIPLY + abstract_type = /decl/sprite_accessory/cosmetics + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + accessory_category = SAC_COSMETICS + +/decl/sprite_accessory/cosmetics/get_accessory_icon(obj/item/organ/external/organ) + if(!organ || QDELETED(organ)) + return icon + return organ.bodytype?.get_cosmetics_icon(src) + +/decl/sprite_accessory/cosmetics/refresh_mob(var/mob/living/subject) + if(istype(subject)) + subject.update_body() + +/decl/sprite_accessory/cosmetics/accessory_is_available(mob/owner, decl/species/species, decl/bodytype/bodytype, list/traits) + . = ..() + if(.) + if(!bodytype) + bodytype = owner?.get_bodytype() + return !isnull(bodytype?.get_cosmetics_icon(src)) + +/decl/sprite_accessory/cosmetics/validate() + . = ..() + var/list/all_bodytypes = decls_repository.get_decls_of_type(/decl/bodytype) + for(var/bodytype_type in all_bodytypes) + var/decl/bodytype/bodytype = all_bodytypes[bodytype_type] + var/cosmetics_icon = bodytype.get_cosmetics_icon(src) + if(cosmetics_icon && !check_state_in_icon(icon_state, cosmetics_icon)) + . += "missing icon_state [icon_state] for bodytype [bodytype.type] in icon [bodytype.cosmetics_icon]" + +// Subtypes. +/decl/sprite_accessory/cosmetics/none + name = "No Cosmetics" + icon_state = "nothing" + draw_accessory = FALSE + grooming_flags = FALSE + uid = "acc_cosmetics_nothing" + +/decl/sprite_accessory/cosmetics/lipstick + name = "Lipstick" + icon_state = "lips" + uid = "acc_cosmetics_lips" + +/decl/sprite_accessory/cosmetics/eyeshadow + name = "Eyeshadow" + icon_state = "eyeshadow" + uid = "acc_cosmetics_eyeshadow" diff --git a/code/modules/sprite_accessories/ears/_accessory_ears.dm b/code/modules/sprite_accessories/ears/_accessory_ears.dm new file mode 100644 index 000000000000..bc64873f19a0 --- /dev/null +++ b/code/modules/sprite_accessories/ears/_accessory_ears.dm @@ -0,0 +1,39 @@ +/decl/sprite_accessory_category/ears + name = "Ears" + base_accessory_type = /decl/sprite_accessory/ears + default_accessory = /decl/sprite_accessory/ears/none + uid = "acc_cat_ears" + +/decl/sprite_accessory/ears + hidden_by_gear_slot = slot_head_str + hidden_by_gear_flag = BLOCK_HEAD_HAIR + body_parts = list(BP_HEAD) + sprite_overlay_layer = FLOAT_LAYER + is_heritable = TRUE + icon = 'icons/mob/human_races/species/default_ears.dmi' + accessory_category = SAC_EARS + abstract_type = /decl/sprite_accessory/ears + color_blend = ICON_MULTIPLY + +/decl/sprite_accessory/ears/none + name = "Default Ears" + icon_state = "none" + uid = "acc_ears_none" + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + grooming_flags = null + draw_accessory = FALSE + +/* +// Leaving this in for reference. +/decl/sprite_accessory/ears/debug + name = "Debug Two-Tone Ears" + uid = "acc_ears_debug" + icon_state = "debug" + accessory_metadata_types = list(SAM_COLOR, SAM_COLOR_INNER) +*/ \ No newline at end of file diff --git a/code/modules/sprite_accessories/ears/accessory_ears_antennae.dm b/code/modules/sprite_accessories/ears/accessory_ears_antennae.dm new file mode 100644 index 000000000000..b3e52753bad0 --- /dev/null +++ b/code/modules/sprite_accessories/ears/accessory_ears_antennae.dm @@ -0,0 +1,14 @@ +/decl/sprite_accessory/ears/dual_antennae + name = "Dual Antennae" + icon_state = "dual_robot_antennae" + uid = "accessory_ears_dual_antennae" + +/decl/sprite_accessory/ears/left_antenna + name = "Antenna, Left" + icon_state = "left_robot_antennae" + uid = "accessory_ears_left_antennae" + +/decl/sprite_accessory/ears/right_antenna + name = "Antenna, Right" + icon_state = "right_robot_antennae" + uid = "accessory_ears_right_antennae" diff --git a/code/modules/sprite_accessories/facial/_accessory_facial.dm b/code/modules/sprite_accessories/facial/_accessory_facial.dm new file mode 100644 index 000000000000..106c91852d53 --- /dev/null +++ b/code/modules/sprite_accessories/facial/_accessory_facial.dm @@ -0,0 +1,47 @@ +/decl/sprite_accessory_category/facial_hair + name = "Facial Hair" + base_accessory_type = /decl/sprite_accessory/facial_hair + default_accessory = /decl/sprite_accessory/facial_hair/shaved + always_apply_defaults = TRUE + uid = "acc_cat_facial_hair" + +/decl/sprite_accessory/facial_hair + abstract_type = /decl/sprite_accessory/facial_hair + icon = 'icons/mob/human_races/species/human/facial.dmi' + hidden_by_gear_slot = slot_head_str + hidden_by_gear_flag = BLOCK_HEAD_HAIR + body_parts = list(BP_HEAD) + sprite_overlay_layer = FLOAT_LAYER + is_heritable = TRUE + accessory_category = SAC_FACIAL_HAIR + accessory_flags = HAIR_LOSS_VULNERABLE + grooming_flags = GROOMABLE_BRUSH | GROOMABLE_COMB + +/decl/sprite_accessory/facial_hair/get_grooming_descriptor(grooming_result, obj/item/organ/external/organ, obj/item/grooming/tool) + return grooming_result == GROOMING_RESULT_PARTIAL ? "chin and cheeks" : "facial hair" + +/decl/sprite_accessory/facial_hair/can_be_groomed_with(obj/item/organ/external/organ, obj/item/grooming/tool) + . = ..() + if(. == GROOMING_RESULT_SUCCESS && (accessory_flags & HAIR_VERY_SHORT)) + return GROOMING_RESULT_PARTIAL + +/decl/sprite_accessory/facial_hair/get_hidden_substitute() + return GET_DECL(/decl/sprite_accessory/facial_hair/shaved) + +/decl/sprite_accessory/facial_hair/refresh_mob(var/mob/living/subject) + if(istype(subject)) + subject.update_hair() + +/decl/sprite_accessory/facial_hair/shaved + name = "Shaved" + icon_state = "bald" + uid = "acc_fhair_shaved" + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + draw_accessory = FALSE + grooming_flags = null diff --git a/code/modules/sprite_accessories/facial/accessory_facial_hair.dm b/code/modules/sprite_accessories/facial/accessory_facial_hair.dm new file mode 100644 index 000000000000..81d4cdb43cea --- /dev/null +++ b/code/modules/sprite_accessories/facial/accessory_facial_hair.dm @@ -0,0 +1,154 @@ +/decl/sprite_accessory/facial_hair/watson + name = "Watson Mustache" + icon_state = "facial_watson" + uid = "acc_fhair_watson" + +/decl/sprite_accessory/facial_hair/hogan + name = "Hulk Hogan Mustache" + icon_state = "facial_hogan" //-Neek + uid = "acc_fhair_hogan" + +/decl/sprite_accessory/facial_hair/vandyke + name = "Van Dyke Mustache" + icon_state = "facial_vandyke" + uid = "acc_fhair_vandyke" + +/decl/sprite_accessory/facial_hair/chaplin + name = "Square Mustache" + icon_state = "facial_chaplin" + uid = "acc_fhair_chaplin" + +/decl/sprite_accessory/facial_hair/selleck + name = "Selleck Mustache" + icon_state = "facial_selleck" + uid = "acc_fhair_selleck" + +/decl/sprite_accessory/facial_hair/neckbeard + name = "Neckbeard" + icon_state = "facial_neckbeard" + uid = "acc_fhair_neckbeard" + +/decl/sprite_accessory/facial_hair/fullbeard + name = "Full Beard" + icon_state = "facial_fullbeard" + uid = "acc_fhair_fullbeard" + +/decl/sprite_accessory/facial_hair/longbeard + name = "Long Beard" + icon_state = "facial_longbeard" + uid = "acc_fhair_longbeard" + +/decl/sprite_accessory/facial_hair/vlongbeard + name = "Very Long Beard" + icon_state = "facial_wise" + uid = "acc_fhair_vlongbeard" + +/decl/sprite_accessory/facial_hair/elvis + name = "Elvis Sideburns" + icon_state = "facial_elvis" + uid = "acc_fhair_elvis" + +/decl/sprite_accessory/facial_hair/abe + name = "Abraham Lincoln Beard" + icon_state = "facial_abe" + uid = "acc_fhair_abe" + +/decl/sprite_accessory/facial_hair/chinstrap + name = "Chinstrap" + icon_state = "facial_chin" + uid = "acc_fhair_chinstrap" + +/decl/sprite_accessory/facial_hair/hip + name = "Hipster Beard" + icon_state = "facial_hip" + uid = "acc_fhair_hipster" + +/decl/sprite_accessory/facial_hair/gt + name = "Goatee" + icon_state = "facial_gt" + uid = "acc_fhair_goatee" + +/decl/sprite_accessory/facial_hair/jensen + name = "Adam Jensen Beard" + icon_state = "facial_jensen" + uid = "acc_fhair_jensen" + +/decl/sprite_accessory/facial_hair/volaju + name = "Volaju" + icon_state = "facial_volaju" + uid = "acc_fhair_volaju" + +/decl/sprite_accessory/facial_hair/dwarf + name = "Dwarf Beard" + icon_state = "facial_dwarf" + uid = "acc_fhair_dwarf" + +/decl/sprite_accessory/facial_hair/threeOclock + name = "3 O'clock Shadow" + icon_state = "facial_3oclock" + uid = "acc_fhair_3oclock" + +/decl/sprite_accessory/facial_hair/threeOclockstache + name = "3 O'clock Shadow and Moustache" + icon_state = "facial_3oclockmoustache" + uid = "acc_fhair_3oclockmoustache" + +/decl/sprite_accessory/facial_hair/fiveOclock + name = "5 O'clock Shadow" + icon_state = "facial_5oclock" + uid = "acc_fhair_5oclock" + +/decl/sprite_accessory/facial_hair/fiveOclockstache + name = "5 O'clock Shadow and Moustache" + icon_state = "facial_5oclockmoustache" + uid = "acc_fhair_5oclockmoustache" + +/decl/sprite_accessory/facial_hair/sevenOclock + name = "7 O'clock Shadow" + icon_state = "facial_7oclock" + uid = "acc_fhair_7oclock" + +/decl/sprite_accessory/facial_hair/sevenOclockstache + name = "7 O'clock Shadow and Moustache" + icon_state = "facial_7oclockmoustache" + uid = "acc_fhair_7oclockmoustache" + +/decl/sprite_accessory/facial_hair/mutton + name = "Mutton Chops" + icon_state = "facial_mutton" + uid = "acc_fhair_mutton" + +/decl/sprite_accessory/facial_hair/muttonstache + name = "Mutton Chops and Moustache" + icon_state = "facial_muttonmus" + uid = "acc_fhair_muttonmus" + +/decl/sprite_accessory/facial_hair/walrus + name = "Walrus Moustache" + icon_state = "facial_walrus" + uid = "acc_fhair_walrus" + +/decl/sprite_accessory/facial_hair/croppedbeard + name = "Full Cropped Beard" + icon_state = "facial_croppedfullbeard" + uid = "acc_fhair_cropped" + +/decl/sprite_accessory/facial_hair/chinless + name = "Chinless Beard" + icon_state = "facial_chinlessbeard" + uid = "acc_fhair_chinless" + +/decl/sprite_accessory/facial_hair/braided + name = "Braided Beard" + icon_state = "facial_biker" + uid = "acc_fhair_braided" + +/decl/sprite_accessory/facial_hair/seadog + name = "Sea Dog" + icon_state = "facial_seadog" + uid = "acc_fhair_seadog" + +/decl/sprite_accessory/facial_hair/lumberjack + name = "Lumberjack" + icon_state = "facial_lumberjack" + uid = "acc_fhair_lumberjack" diff --git a/code/modules/sprite_accessories/frills/_accessory_frills.dm b/code/modules/sprite_accessories/frills/_accessory_frills.dm new file mode 100644 index 000000000000..9d6e187d93a7 --- /dev/null +++ b/code/modules/sprite_accessories/frills/_accessory_frills.dm @@ -0,0 +1,29 @@ +/decl/sprite_accessory_category/frills + name = "Frills" + base_accessory_type = /decl/sprite_accessory/frills + default_accessory = /decl/sprite_accessory/frills/none + uid = "acc_cat_frills" + +/decl/sprite_accessory/frills + hidden_by_gear_slot = slot_head_str + hidden_by_gear_flag = BLOCK_HEAD_HAIR + body_parts = list(BP_HEAD) + sprite_overlay_layer = FLOAT_LAYER + is_heritable = TRUE + icon = 'icons/mob/human_races/species/default_frills.dmi' + accessory_category = SAC_FRILLS + abstract_type = /decl/sprite_accessory/frills + +/decl/sprite_accessory/frills/none + name = "No Frills" + icon_state = "none" + uid = "acc_frills_none" + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + draw_accessory = FALSE + grooming_flags = null diff --git a/code/modules/sprite_accessories/hair/_accessory_hair.dm b/code/modules/sprite_accessories/hair/_accessory_hair.dm new file mode 100644 index 000000000000..328397907dac --- /dev/null +++ b/code/modules/sprite_accessories/hair/_accessory_hair.dm @@ -0,0 +1,51 @@ +/decl/sprite_accessory_category/hair + name = "Hair" + base_accessory_type = /decl/sprite_accessory/hair + default_accessory = /decl/sprite_accessory/hair/bald + always_apply_defaults = TRUE + uid = "acc_cat_hair" + +/decl/sprite_accessory/hair + abstract_type = /decl/sprite_accessory/hair + icon = 'icons/mob/human_races/species/human/hair.dmi' + hidden_by_gear_slot = slot_head_str + hidden_by_gear_flag = BLOCK_HEAD_HAIR + body_parts = list(BP_HEAD) + sprite_overlay_layer = FLOAT_LAYER + is_heritable = TRUE + accessory_category = SAC_HAIR + accessory_flags = HAIR_LOSS_VULNERABLE + grooming_flags = GROOMABLE_BRUSH | GROOMABLE_COMB + accessory_metadata_types = list(SAM_COLOR, SAM_COLOR_INNER, SAM_GRADIENT) + +/decl/sprite_accessory/hair/get_grooming_descriptor(grooming_result, obj/item/organ/external/organ, obj/item/grooming/tool) + return grooming_result == GROOMING_RESULT_PARTIAL ? "scalp" : "hair" + +/decl/sprite_accessory/hair/can_be_groomed_with(obj/item/organ/external/organ, obj/item/grooming/tool) + . = ..() + if(. == GROOMING_RESULT_SUCCESS && (accessory_flags & HAIR_VERY_SHORT)) + return GROOMING_RESULT_PARTIAL + +/decl/sprite_accessory/hair/get_hidden_substitute() + if(accessory_flags & HAIR_VERY_SHORT) + return src + return GET_DECL(/decl/sprite_accessory/hair/short) + +/decl/sprite_accessory/hair/refresh_mob(var/mob/living/subject) + if(istype(subject)) + subject.update_hair() + +/decl/sprite_accessory/hair/bald + name = "Bald" + icon_state = "bald" + uid = "acc_hair_bald" + accessory_flags = HAIR_VERY_SHORT | HAIR_BALD + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + draw_accessory = FALSE + grooming_flags = null diff --git a/code/modules/sprite_accessories/hair/accessory_hair_bedhead.dm b/code/modules/sprite_accessories/hair/accessory_hair_bedhead.dm new file mode 100644 index 000000000000..68b68ea3530b --- /dev/null +++ b/code/modules/sprite_accessories/hair/accessory_hair_bedhead.dm @@ -0,0 +1,25 @@ +/decl/sprite_accessory/hair/bedhead + name = "Bedhead" + icon_state = "hair_bedhead" + uid = "acc_hair_bedhead" + +/decl/sprite_accessory/hair/bedhead/two + name = "Bedhead 2" + icon_state = "hair_bedheadv2" + uid = "acc_hair_bedhead2" + +/decl/sprite_accessory/hair/bedhead/long + name = "Bedhead 3" + icon_state = "hair_bedheadv3" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_bedhead3" + +/decl/sprite_accessory/hair/bedhead/long/four + name = "Bedhead 4" + uid = "acc_hair_long_bedhead" + icon_state = "hair_long_bedhead" + +/decl/sprite_accessory/hair/bedhead/long/five + name = "Bedhead 5" + uid = "acc_hair_longest_bedhead" + icon_state = "hair_longest_bedhead" diff --git a/code/modules/sprite_accessories/hair/accessory_hair_braids.dm b/code/modules/sprite_accessories/hair/accessory_hair_braids.dm new file mode 100644 index 000000000000..af859ca66f1f --- /dev/null +++ b/code/modules/sprite_accessories/hair/accessory_hair_braids.dm @@ -0,0 +1,35 @@ +/decl/sprite_accessory/hair/braid + name = "Medium Braid" + icon_state = "hair_shortbraid" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_mbraid" + +/decl/sprite_accessory/hair/braid/long_one + name = "Long Braid 1" + icon_state = "hair_hbraid" + uid = "acc_hair_braid2" + +/decl/sprite_accessory/hair/braid/long_two + name = "Long Braid 2" + uid = "acc_hair_longbraid" + icon_state = "hair_longbraid" + +/decl/sprite_accessory/hair/braid/long_three + name = "Long Braid 3" + uid = "acc_hair_braidalt" + icon_state = "hair_braidalt" + +/decl/sprite_accessory/hair/braid/grande + name = "Grande Braid" + icon_state = "hair_grande" + uid = "acc_hair_grande" + +/decl/sprite_accessory/hair/braid/rowdual + name = "Row Dual Braid" + icon_state = "hair_rowdualtail" + uid = "acc_hair_rowdualbraid" + +/decl/sprite_accessory/hair/braid/row + name = "Row Braid" + icon_state = "hair_rowbraid" + uid = "acc_hair_rowbraid" diff --git a/code/modules/sprite_accessories/hair/accessory_hair_misc.dm b/code/modules/sprite_accessories/hair/accessory_hair_misc.dm new file mode 100644 index 000000000000..61d019d88859 --- /dev/null +++ b/code/modules/sprite_accessories/hair/accessory_hair_misc.dm @@ -0,0 +1,974 @@ +/decl/sprite_accessory/hair/short + name = "Short Hair" // try to capatilize the names please~ + icon_state = "hair_a" // you do not need to define _s or _l sub-states, game automatically does this for you + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_short" + +/decl/sprite_accessory/hair/twintail + name = "Twintail" + icon_state = "hair_twintail" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_twintail" + +/decl/sprite_accessory/hair/short2 + name = "Short Hair 2" + icon_state = "hair_shorthair3" + uid = "acc_hair_short2" + +/decl/sprite_accessory/hair/cut + name = "Cut Hair" + icon_state = "hair_c" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_cut" + +/decl/sprite_accessory/hair/flair + name = "Flaired Hair" + icon_state = "hair_flair" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_flair" + +/decl/sprite_accessory/hair/long + name = "Shoulder-length Hair" + icon_state = "hair_b" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_shoulder" + +/decl/sprite_accessory/hair/longer + name = "Long Hair" + icon_state = "hair_vlong" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_long" + +/decl/sprite_accessory/hair/longest + name = "Very Long Hair" + icon_state = "hair_longest" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_verylong" + +/decl/sprite_accessory/hair/longfringe + name = "Long Fringe" + icon_state = "hair_longfringe" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_longfringe" + +/decl/sprite_accessory/hair/longestalt + name = "Longer Fringe" + icon_state = "hair_vlongfringe" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_longestalt" + +/decl/sprite_accessory/hair/halfbang + name = "Half-banged Hair" + icon_state = "hair_halfbang" + uid = "acc_hair_halfbang" + +/decl/sprite_accessory/hair/halfbangalt + name = "Half-banged Hair Alt" + icon_state = "hair_halfbang_alt" + uid = "acc_hair_halfbangalt" + +/decl/sprite_accessory/hair/parted + name = "Parted" + icon_state = "hair_parted" + uid = "acc_hair_parted" + +/decl/sprite_accessory/hair/pompadour + name = "Pompadour" + icon_state = "hair_pompadour" + uid = "acc_hair_pompadour" + +/decl/sprite_accessory/hair/sleeze + name = "Sleeze" + icon_state = "hair_sleeze" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_sleeze" + +/decl/sprite_accessory/hair/quiff + name = "Quiff" + icon_state = "hair_quiff" + uid = "acc_hair_quiff" + +/decl/sprite_accessory/hair/beehive + name = "Beehive" + icon_state = "hair_beehive" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_beehive" + +/decl/sprite_accessory/hair/beehive2 + name = "Beehive 2" + icon_state = "hair_beehive2" + uid = "acc_hair_beehive2" + +/decl/sprite_accessory/hair/bobcurl + name = "Bobcurl" + icon_state = "hair_bobcurl" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_bobcurl" + +/decl/sprite_accessory/hair/bob + name = "Bob" + icon_state = "hair_bobcut" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_bob" + +/decl/sprite_accessory/hair/bobcutalt + name = "Chin Length Bob" + icon_state = "hair_bobcutalt" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_bobcutalt" + +/decl/sprite_accessory/hair/bowl + name = "Bowl" + icon_state = "hair_bowlcut" + uid = "acc_hair_bowl" + +/decl/sprite_accessory/hair/buzz + name = "Buzzcut" + icon_state = "hair_buzzcut" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_buzz" + +/decl/sprite_accessory/hair/crew + name = "Crewcut" + icon_state = "hair_crewcut" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_crew" + +/decl/sprite_accessory/hair/combover + name = "Combover" + icon_state = "hair_combover" + uid = "acc_hair_combover" + +/decl/sprite_accessory/hair/father + name = "Father" + icon_state = "hair_father" + uid = "acc_hair_father" + +/decl/sprite_accessory/hair/reversemohawk + name = "Reverse Mohawk" + icon_state = "hair_reversemohawk" + uid = "acc_hair_reversemohawk" + +/decl/sprite_accessory/hair/devillock + name = "Devil Lock" + icon_state = "hair_devilock" + uid = "acc_hair_devillock" + +/decl/sprite_accessory/hair/dreadlocks + name = "Dreadlocks" + icon_state = "hair_dreads" + uid = "acc_hair_deadlocks" + +/decl/sprite_accessory/hair/curls + name = "Curls" + icon_state = "hair_curls" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_curls" + +/decl/sprite_accessory/hair/afro + name = "Afro" + icon_state = "hair_afro" + uid = "acc_hair_afro" + +/decl/sprite_accessory/hair/afro2 + name = "Afro 2" + icon_state = "hair_afro2" + uid = "acc_hair_afro2" + +/decl/sprite_accessory/hair/afro_large + name = "Big Afro" + icon_state = "hair_bigafro" + uid = "acc_hair_bigafro" + +/decl/sprite_accessory/hair/rows + name = "Rows" + icon_state = "hair_rows1" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_rows" + +/decl/sprite_accessory/hair/rows2 + name = "Rows 2" + icon_state = "hair_rows2" + accessory_flags = HAIR_VERY_SHORT | HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_rows2" + +/decl/sprite_accessory/hair/sargeant + name = "Flat Top" + icon_state = "hair_sargeant" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_flattop" + +/decl/sprite_accessory/hair/emo + name = "Emo" + icon_state = "hair_emo" + uid = "acc_hair_emo" + +/decl/sprite_accessory/hair/emo2 + name = "Emo Alt" + icon_state = "hair_emo2" + uid = "acc_hair_emo2" + +/decl/sprite_accessory/hair/longemo + name = "Long Emo" + icon_state = "hair_emolong" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_longemo" + +/decl/sprite_accessory/hair/shortovereye + name = "Overeye Short" + icon_state = "hair_shortovereye" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_overeye_short" + +/decl/sprite_accessory/hair/longovereye + name = "Overeye Long" + icon_state = "hair_longovereye" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_overeye_long" + +/decl/sprite_accessory/hair/flow + name = "Flow Hair" + icon_state = "hair_f" + uid = "acc_hair_flow" + +/decl/sprite_accessory/hair/feather + name = "Feather" + icon_state = "hair_feather" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_feather" + +/decl/sprite_accessory/hair/hitop + name = "Hitop" + icon_state = "hair_hitop" + uid = "acc_hair_hitop" + +/decl/sprite_accessory/hair/mohawk + name = "Mohawk" + icon_state = "hair_d" + uid = "acc_hair_mohawk" + +/decl/sprite_accessory/hair/jensen + name = "Adam Jensen Hair" + icon_state = "hair_jensen" + uid = "acc_hair_jensen" + +/decl/sprite_accessory/hair/gelled + name = "Gelled Back" + icon_state = "hair_gelled" + uid = "acc_hair_gelled" + +/decl/sprite_accessory/hair/gentle + name = "Gentle" + icon_state = "hair_gentle" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_gentle" + +/decl/sprite_accessory/hair/spiky + name = "Spiky" + icon_state = "hair_spikey" + uid = "acc_hair_spikey" + +/decl/sprite_accessory/hair/kusangi + name = "Kusanagi Hair" + icon_state = "hair_kusanagi" + uid = "acc_hair_kusanagi" + +/decl/sprite_accessory/hair/kagami + name = "Pigtails" + icon_state = "hair_kagami" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_kagami" + +/decl/sprite_accessory/hair/himecut + name = "Hime Cut" + icon_state = "hair_himecut" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_himecut" + +/decl/sprite_accessory/hair/shorthime + name = "Short Hime Cut" + icon_state = "hair_shorthime" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_shorthime" + +/decl/sprite_accessory/hair/odango + name = "Odango" + icon_state = "hair_odango" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_odango" + +/decl/sprite_accessory/hair/ombre + name = "Ombre" + icon_state = "hair_ombre" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_ombre" + +/decl/sprite_accessory/hair/updo + name = "Updo" + icon_state = "hair_updo" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_updo" + +/decl/sprite_accessory/hair/skinhead + name = "Skinhead" + icon_state = "hair_skinhead" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_skinhead" + +/decl/sprite_accessory/hair/balding + name = "Balding Hair" + icon_state = "hair_e" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_balding" + +/decl/sprite_accessory/hair/familyman + name = "The Family Man" + icon_state = "hair_thefamilyman" + uid = "acc_hair_familyman" + +/decl/sprite_accessory/hair/mahdrills + name = "Drillruru" + icon_state = "hair_drillruru" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_drillruru" + +/decl/sprite_accessory/hair/fringetail + name = "Fringetail" + icon_state = "hair_fringetail" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_fringetail" + +/decl/sprite_accessory/hair/dandypomp + name = "Dandy Pompadour" + icon_state = "hair_dandypompadour" + uid = "acc_hair_dandypomp" + +/decl/sprite_accessory/hair/poofy + name = "Poofy" + icon_state = "hair_poofy" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_poofy" + +/decl/sprite_accessory/hair/poofy/two + name = "Poofy 2" + uid = "acc_hair_poofy2" + icon_state = "hair_poofy2" + +/decl/sprite_accessory/hair/crono + name = "Chrono" + icon_state = "hair_toriyama" + uid = "acc_hair_chrono" + +/decl/sprite_accessory/hair/vegeta + name = "Vegeta" + icon_state = "hair_toriyama2" + uid = "acc_hair_vegeta" + +/decl/sprite_accessory/hair/cia + name = "CIA" + icon_state = "hair_cia" + uid = "acc_hair_cia" + +/decl/sprite_accessory/hair/mulder + name = "Mulder" + icon_state = "hair_mulder" + uid = "acc_hair_mulder" + +/decl/sprite_accessory/hair/scully + name = "Scully" + icon_state = "hair_scully" + uid = "acc_hair_scully" + +/decl/sprite_accessory/hair/nitori + name = "Nitori" + icon_state = "hair_nitori" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_nitori" + +/decl/sprite_accessory/hair/joestar + name = "Joestar" + icon_state = "hair_joestar" + uid = "acc_hair_joestar" + +/decl/sprite_accessory/hair/volaju + name = "Volaju" + icon_state = "hair_volaju" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_volaju" + +/decl/sprite_accessory/hair/longeralt2 + name = "Long Hair Alt 2" + icon_state = "hair_longeralt2" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_longeralt2" + +/decl/sprite_accessory/hair/shortbangs + name = "Short Bangs" + icon_state = "hair_shortbangs" + uid = "acc_hair_shortbangs" + +/decl/sprite_accessory/hair/shavedbun + name = "Shaved Bun" + icon_state = "hair_shavedbun" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_shavedbun" + +/decl/sprite_accessory/hair/halfshaved + name = "Half-Shaved" + icon_state = "hair_halfshaved" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_halfshaved" + +/decl/sprite_accessory/hair/halfshavedemo + name = "Half-Shaved Emo" + icon_state = "hair_halfshavedemo" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_halfshavedemo" + +/decl/sprite_accessory/hair/longsideemo + name = "Long Side Emo" + icon_state = "hair_longsideemo" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_longsideemo" + +/decl/sprite_accessory/hair/bun + name = "Low Bun" + icon_state = "hair_bun" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_lowbun" + +/decl/sprite_accessory/hair/bun2 + name = "High Bun" + icon_state = "hair_bun2" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_highbun" + +/decl/sprite_accessory/hair/doublebun + name = "Double-Bun" + icon_state = "hair_doublebun" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_doublebun" + +/decl/sprite_accessory/hair/lowfade + name = "Low Fade" + icon_state = "hair_lowfade" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_lowfade" + +/decl/sprite_accessory/hair/medfade + name = "Medium Fade" + icon_state = "hair_medfade" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_medfade" + +/decl/sprite_accessory/hair/highfade + name = "High Fade" + icon_state = "hair_highfade" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_highfade" + +/decl/sprite_accessory/hair/baldfade + name = "Balding Fade" + icon_state = "hair_baldfade" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_baldfade" + +/decl/sprite_accessory/hair/nofade + name = "Regulation Cut" + icon_state = "hair_nofade" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_nofade" + +/decl/sprite_accessory/hair/trimflat + name = "Trimmed Flat Top" + icon_state = "hair_trimflat" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_trimflat" + +/decl/sprite_accessory/hair/shaved + name = "Shaved" + icon_state = "hair_shaved" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_shaved" + +/decl/sprite_accessory/hair/trimmed + name = "Trimmed" + icon_state = "hair_trimmed" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_trimmed" + +/decl/sprite_accessory/hair/tightbun + name = "Tight Bun" + icon_state = "hair_tightbun" + accessory_flags = HAIR_VERY_SHORT | HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_tightbun" + +/decl/sprite_accessory/hair/coffeehouse + name = "Coffee House Cut" + icon_state = "hair_coffeehouse" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_coffeehouse" + +/decl/sprite_accessory/hair/partfade + name = "Parted Fade" + icon_state = "hair_shavedpart" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_partfade" + +/decl/sprite_accessory/hair/hightight + name = "High and Tight" + icon_state = "hair_hightight" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_hightight" + +/decl/sprite_accessory/hair/rowbun + name = "Row Bun" + icon_state = "hair_rowbun" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_rowbun" + +/decl/sprite_accessory/hair/regulationmohawk + name = "Regulation Mohawk" + icon_state = "hair_shavedmohawk" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_regulationmohawk" + +/decl/sprite_accessory/hair/topknot + name = "Topknot" + icon_state = "hair_topknot" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_topknot" + +/decl/sprite_accessory/hair/ronin + name = "Ronin" + icon_state = "hair_ronin" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_ronin" + +/decl/sprite_accessory/hair/bowlcut2 + name = "Bowl2" + icon_state = "hair_bowlcut2" + uid = "acc_hair_bowl2" + +/decl/sprite_accessory/hair/thinning + name = "Thinning" + icon_state = "hair_thinning" + accessory_flags = HAIR_VERY_SHORT + uid = "acc_hair_thinning" + +/decl/sprite_accessory/hair/thinningfront + name = "Thinning Front" + icon_state = "hair_thinningfront" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_thinningfront" + +/decl/sprite_accessory/hair/thinningback + name = "Thinning Back" + icon_state = "hair_thinningrear" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_thinningback" + +/decl/sprite_accessory/hair/manbun + name = "Manbun" + icon_state = "hair_manbun" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_manbun" + +/decl/sprite_accessory/hair/leftsidecut + name = "Left Sidecut" + icon_state = "hair_leftside" + uid = "acc_hair_leftsidecut" + +/decl/sprite_accessory/hair/rightsidecut + name = "Right Sidecut" + icon_state = "hair_rightside" + uid = "acc_hair_rightsidecut" + +/decl/sprite_accessory/hair/slick + name = "Slick" + icon_state = "hair_slick" + uid = "acc_hair_slick" + +/decl/sprite_accessory/hair/messyhair + name = "Messy" + icon_state = "hair_messyhair" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_messyhair" + +/decl/sprite_accessory/hair/averagejoe + name = "Average Joe" + icon_state = "hair_averagejoe" + uid = "acc_hair_averagejoe" + +/decl/sprite_accessory/hair/sideswept + name = "Sideswept Hair" + icon_state = "hair_sideswept" + uid = "acc_hair_sideswept" + +/decl/sprite_accessory/hair/mohawkshaved + name = "Shaved Mohawk" + icon_state = "hair_mohawkshaved" + uid = "acc_hair_mohawkshaved" + +/decl/sprite_accessory/hair/mohawkshaved2 + name = "Tight Shaved Mohawk" + icon_state = "hair_mohawkshaved2" + uid = "acc_hair_mohawkshaved2" + +/decl/sprite_accessory/hair/mohawkshavednaomi + name = "Naomi Mohawk" + icon_state = "hair_mohawkshavednaomi" + uid = "acc_hair_naomimohawk" + +/decl/sprite_accessory/hair/amazon + name = "Amazon" + icon_state = "hair_amazon" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_amazon" + +/decl/sprite_accessory/hair/straightlong + name = "Straight Long" + icon_state = "hair_straightlong" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_straightlong" + +/decl/sprite_accessory/hair/marysue + name = "Mary Sue" + icon_state = "hair_marysue" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_marysue" + +/decl/sprite_accessory/hair/messyhair2 + name = "Messy Hair 2" + icon_state = "hair_messyhair2" + uid = "acc_hair_messyhair2" + +/decl/sprite_accessory/hair/buzzcut2 + name = "Buzzcut 2" + icon_state = "hair_buzzcut2" + uid = "acc_hair_buzzcut2" + +/decl/sprite_accessory/hair/bighawk + name = "Big Mohawk" + icon_state = "hair_bighawk" + uid = "acc_hair_bighawk" + +/decl/sprite_accessory/hair/donutbun + name = "Donut Bun" + icon_state = "hair_donutbun" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_donutbun" + +/decl/sprite_accessory/hair/gentle2 + name = "Gentle 2" + icon_state = "hair_gentle2" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_gentle2" + +/decl/sprite_accessory/hair/gentle2long + name = "Gentle 2 Long" + icon_state = "hair_gentle2long" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_gentle2long" + +/decl/sprite_accessory/hair/trimrsidecut + name = "Trimmed Right Sidecut" + icon_state = "hair_rightside_trim" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_trimrightsidecut" + +/decl/sprite_accessory/hair/doll + name = "Doll" + uid = "acc_hair_doll" + icon_state = "hair_doll" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/darcy + name = "Darcy" + uid = "acc_hair_darcy" + icon_state = "hair_darcy" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_VERY_SHORT + +/decl/sprite_accessory/hair/antonio + name = "Antonio" + uid = "acc_hair_antonio" + icon_state = "hair_antonio" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_VERY_SHORT + +/decl/sprite_accessory/hair/bigcurls + name = "Big Curls" + uid = "acc_hair_bigcurls" + icon_state = "hair_bigcurls" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/sweptfringe + name = "Swept Fringe" + uid = "acc_hair_sweptfringe" + icon_state = "hair_sweptfringe" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/mialong + name = "Mia Long" + uid = "acc_hair_mialong" + icon_state = "hair_mialong" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/mia + name = "Mia" + uid = "acc_hair_mia" + icon_state = "hair_mia" + +/decl/sprite_accessory/hair/roxy + name = "Roxy" + uid = "acc_hair_roxy" + icon_state = "hair_roxy" + +/decl/sprite_accessory/hair/sabitsuki + name = "Sabitsuki" + uid = "acc_hair_sabitsuki" + icon_state = "hair_sabitsuki" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_VERY_SHORT + +/decl/sprite_accessory/hair/rockstarcurls + name = "Rockstar Curls" + uid = "acc_hair_rockstarcurls" + icon_state = "hair_rockstarcurls" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/proper + name = "Proper" + uid = "acc_hair_proper" + icon_state = "hair_proper" + +/decl/sprite_accessory/hair/shortflip + name = "Short Flip" + uid = "acc_hair_shortflip" + icon_state = "hair_shortflip" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_VERY_SHORT + +/decl/sprite_accessory/hair/afropuffdouble + name = "Afropuff, Double" + uid = "acc_hair_afropuffdouble" + icon_state = "hair_afropuffdouble" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/afropuffleft + name = "Afropuff, Left" + uid = "acc_hair_afropuffleft" + icon_state = "hair_afropuffleft" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/afropuffright + name = "Afropuff, Right" + uid = "acc_hair_afropuffright" + icon_state = "hair_afropuffright" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/antenna + name = "Antenna" + uid = "acc_hair_antenna" + icon_state = "hair_antenna" + +/decl/sprite_accessory/hair/aradia + name = "Aradia" + uid = "acc_hair_aradia" + icon_state = "hair_aradia" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/beachwave + name = "Beachwave" + uid = "acc_hair_beachwave" + icon_state = "hair_beachwave" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/nia + name = "Nia" + uid = "acc_hair_nia" + icon_state = "hair_nia" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/belenkotied + name = "Belenko Tied" + uid = "acc_hair_belenkotied" + icon_state = "hair_belenkotied" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/eighties + name = "80's" + uid = "acc_hair_80s" + icon_state = "hair_80s" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/overeyebowl + name = "Overeye Bowl Cut" + uid = "acc_hair_overeyebowl" + icon_state = "hair_overeyebowl" + +/decl/sprite_accessory/hair/business + name = "Business Hair" + uid = "acc_hair_business3" + icon_state = "hair_business3" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_VERY_SHORT + +/decl/sprite_accessory/hair/businessalt + name = "Business Hair Alt" + uid = "acc_hair_business4" + icon_state = "hair_business4" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_VERY_SHORT + +/decl/sprite_accessory/hair/cornbun + name = "Cornbun" + uid = "acc_hair_cornbun" + icon_state = "hair_cornbun" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/jessica + name = "Jessica" + uid = "acc_hair_jessica" + icon_state = "hair_jessica" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/country + name = "Country" + uid = "acc_hair_country" + icon_state = "hair_country" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/himeup + name = "Hime Updo" + uid = "acc_hair_himeup" + icon_state = "hair_himeup" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/dreadlong + name = "Long Dreadlocks" + uid = "acc_hair_dreadslong" + icon_state = "hair_dreadslong" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/dreadlongalt + name = "Long Dreadlocks Alt" + uid = "acc_hair_dreadlongalt" + icon_state = "hair_dreadlongalt" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/elize + name = "Elize" + uid = "acc_hair_elize" + icon_state = "hair_elize" + +/decl/sprite_accessory/hair/emofringe + name = "Emo Fringe" + uid = "acc_hair_emofringe" + icon_state = "hair_emofringe" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/emoright + name = "Emo Mid-length" + uid = "acc_hair_emoright" + icon_state = "hair_emoright" + +/decl/sprite_accessory/hair/wisp + name = "Wisp" + uid = "acc_hair_wisp" + icon_state = "hair_wisp" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/vriska + name = "Vriska" + uid = "acc_hair_vriska" + icon_state = "hair_vriska" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/flipped + name = "Flipped" + uid = "acc_hair_flipped" + icon_state = "hair_flipped" + +/decl/sprite_accessory/hair/froofy_long + name = "Froofy Long" + uid = "acc_hair_froofy_long" + icon_state = "hair_froofy_long" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/glossy + name = "Glossy" + uid = "acc_hair_glossy" + icon_state = "hair_glossy" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/longsidepart + name = "Long Side Part" + uid = "acc_hair_longsidepart" + icon_state = "hair_longsidepart" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/miles + name = "Miles" + uid = "acc_hair_miles" + icon_state = "hair_miles" + +/decl/sprite_accessory/hair/modern + name = "Modern" + uid = "acc_hair_modern" + icon_state = "hair_modern" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/newyou + name = "New You" + uid = "acc_hair_newyou" + icon_state = "hair_newyou" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/oxton + name = "Oxton" + uid = "acc_hair_oxton" + icon_state = "hair_oxton" + +/decl/sprite_accessory/hair/veryshortovereye + name = "Very Short Overeye" + uid = "acc_hair_veryshortovereye" + icon_state = "hair_veryshortovereye" + +/decl/sprite_accessory/hair/veryshortovereyealternate + name = "Very Short Overeye Alt" + uid = "acc_hair_veryshortovereyealternate" + icon_state = "hair_veryshortovereyealternate" + +/decl/sprite_accessory/hair/pixie + name = "Pixie Cut" + uid = "acc_hair_pixie" + icon_state = "hair_pixie" + +/decl/sprite_accessory/hair/sweepshave + name = "Sweep Shaved" + uid = "acc_hair_sweepshave" + icon_state = "hair_sweepshave" + +/decl/sprite_accessory/hair/suave + name = "Suave" + uid = "acc_hair_suave" + icon_state = "hair_suave" + +/decl/sprite_accessory/hair/suave2 + name = "Suave Alt" + uid = "acc_hair_suave2" + icon_state = "hair_suave2" + +/decl/sprite_accessory/hair/protagonist + name = "Slightly Long" + uid = "acc_hair_protagonist" + icon_state = "hair_protagonist" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/shouldersweep + name = "Swept Shoulder" + uid = "acc_hair_shouldersweep" + icon_state = "hair_shouldersweep" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE + +/decl/sprite_accessory/hair/tresshoulder + name = "Shoulder Tress" + uid = "acc_hair_tresshoulder" + icon_state = "hair_tressshoulder" + accessory_flags = HAIR_LOSS_VULNERABLE | HAIR_TIEABLE diff --git a/code/modules/sprite_accessories/hair/accessory_hair_ponytail.dm b/code/modules/sprite_accessories/hair/accessory_hair_ponytail.dm new file mode 100644 index 000000000000..24cfd3e9fde6 --- /dev/null +++ b/code/modules/sprite_accessories/hair/accessory_hair_ponytail.dm @@ -0,0 +1,55 @@ +/decl/sprite_accessory/hair/ponytail + name = "Ponytail 1" + icon_state = "hair_ponytail" + accessory_flags = HAIR_TIEABLE | HAIR_LOSS_VULNERABLE + uid = "acc_hair_ponytail1" + +/decl/sprite_accessory/hair/ponytail/two + name = "Ponytail 2" + icon_state = "hair_pa" + uid = "acc_hair_ponytail2" + +/decl/sprite_accessory/hair/ponytail/three + name = "Ponytail 3" + icon_state = "hair_ponytail3" + uid = "acc_hair_ponytail3" + +/decl/sprite_accessory/hair/ponytail/four + name = "Ponytail 4" + icon_state = "hair_ponytail4" + uid = "acc_hair_ponytail4" + +/decl/sprite_accessory/hair/ponytail/five + name = "Ponytail 5" + icon_state = "hair_ponytail5" + uid = "acc_hair_ponytail5" + +/decl/sprite_accessory/hair/ponytail/six + name = "Ponytail 6" + icon_state = "hair_ponytail6" + uid = "acc_hair_ponytail6" + +/decl/sprite_accessory/hair/ponytail/seven + name = "Ponytail 7" + uid = "acc_hair_ponytail7" + icon_state = "hair_ponytail7" + +/decl/sprite_accessory/hair/ponytail/side + name = "Side Ponytail" + icon_state = "hair_stail" + uid = "acc_hair_sideponytail" + +/decl/sprite_accessory/hair/ponytail/high + name = "High Ponytail" + uid = "acc_hair_highponytail" + icon_state = "hair_highponytail" + +/decl/sprite_accessory/hair/ponytail/jean + name = "Jean Ponytail" + uid = "acc_hair_jeanponytail" + icon_state = "hair_jeanponytail" + +/decl/sprite_accessory/hair/ponytail/spiky + name = "Spiky Ponytail" + uid = "acc_hair_spikyponytail" + icon_state = "hair_spikyponytail" diff --git a/code/modules/sprite_accessories/hair/accessory_hair_undercut.dm b/code/modules/sprite_accessories/hair/accessory_hair_undercut.dm new file mode 100644 index 000000000000..eb26fc263f85 --- /dev/null +++ b/code/modules/sprite_accessories/hair/accessory_hair_undercut.dm @@ -0,0 +1,20 @@ +/decl/sprite_accessory/hair/undercut + name = "Undercut" + icon_state = "hair_undercut" + accessory_flags = HAIR_VERY_SHORT | HAIR_LOSS_VULNERABLE + uid = "acc_hair_undercut" + +/decl/sprite_accessory/hair/undercut/side + name = "Side Undercut" + icon_state = "hair_sideundercut" + uid = "acc_hair_sideundercut" + +/decl/sprite_accessory/hair/undercut/two + name = "Undercut 2" + uid = "acc_hair_undercut2" + icon_state = "hair_undercut2" + +/decl/sprite_accessory/hair/undercut/three + name = "Undercut 3" + uid = "acc_hair_undercut3" + icon_state = "hair_undercut3" diff --git a/code/modules/sprite_accessories/horns/_accessory_horns.dm b/code/modules/sprite_accessories/horns/_accessory_horns.dm new file mode 100644 index 000000000000..4526113a70f8 --- /dev/null +++ b/code/modules/sprite_accessories/horns/_accessory_horns.dm @@ -0,0 +1,33 @@ +/decl/sprite_accessory_category/horns + name = "Horns" + base_accessory_type = /decl/sprite_accessory/horns + default_accessory = /decl/sprite_accessory/horns/none + uid = "acc_cat_horns" + +/decl/sprite_accessory/horns + hidden_by_gear_slot = slot_head_str + hidden_by_gear_flag = BLOCK_HEAD_HAIR + body_parts = list(BP_HEAD) + sprite_overlay_layer = FLOAT_LAYER + is_heritable = TRUE + icon = 'icons/mob/human_races/species/default_horns.dmi' + accessory_category = SAC_HORNS + abstract_type = /decl/sprite_accessory/horns + grooming_flags = GROOMABLE_FILE + +/decl/sprite_accessory/horns/get_grooming_descriptor(grooming_result, obj/item/organ/external/organ, obj/item/grooming/tool) + return grooming_result == GROOMING_RESULT_PARTIAL ? "nubs" : "horns" + +/decl/sprite_accessory/horns/none + name = "No Horns" + icon_state = "none" + uid = "acc_horns_none" + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + draw_accessory = FALSE + grooming_flags = null diff --git a/code/modules/sprite_accessories/markings/_accessory_markings.dm b/code/modules/sprite_accessories/markings/_accessory_markings.dm new file mode 100644 index 000000000000..25eafb7f5f36 --- /dev/null +++ b/code/modules/sprite_accessories/markings/_accessory_markings.dm @@ -0,0 +1,16 @@ +/decl/sprite_accessory_category/markings + name = "Markings" + single_selection = FALSE + base_accessory_type = /decl/sprite_accessory/marking + uid = "acc_cat_markings" + always_apply_defaults = TRUE + +/decl/sprite_accessory/marking + icon = 'icons/mob/human_races/species/default_markings.dmi' + abstract_type = /decl/sprite_accessory/marking + mask_to_bodypart = TRUE + accessory_category = SAC_MARKINGS + +/decl/sprite_accessory/marking/refresh_mob(var/mob/living/subject) + if(istype(subject)) + subject.update_body() diff --git a/code/modules/sprite_accessories/markings/accessory_markings_bandages.dm b/code/modules/sprite_accessories/markings/accessory_markings_bandages.dm new file mode 100644 index 000000000000..79372fad2f1e --- /dev/null +++ b/code/modules/sprite_accessories/markings/accessory_markings_bandages.dm @@ -0,0 +1,172 @@ +/decl/sprite_accessory/marking/bandage + icon = 'icons/mob/human_races/species/default_bandages.dmi' + abstract_type = /decl/sprite_accessory/marking/bandage + color_blend = null + species_allowed = null // Everyone can be bandaged. + bodytype_categories_allowed = list(BODYTYPE_HUMANOID) // Only fit the humanoid silhouette, though. + +/decl/sprite_accessory/marking/bandage/nosetape + name = "Bandage, Nose Tape" + uid = "accessory_marking_bandage_nosetape" + icon_state = "nosetape" + +/decl/sprite_accessory/marking/bandage/head + name = "Bandage, Head, 1" + uid = "accessory_marking_bandage1_head" + icon_state = "bandage1-head" + body_parts = list(BP_HEAD) + +/decl/sprite_accessory/marking/bandage/groin + name = "Bandage, Lower Body, 1" + uid = "accessory_marking_bandage1_groin" + icon_state = "bandage1-groin" + body_parts = list(BP_GROIN) + +/decl/sprite_accessory/marking/bandage/torso + name = "Bandage, Chest, 1" + uid = "accessory_marking_bandage1_torso" + icon_state = "bandage1-torso" + body_parts = list(BP_CHEST) + +/decl/sprite_accessory/marking/bandage/left_arm + name = "Bandage, Left Arm, 1" + uid = "accessory_marking_bandage1_l_arm" + icon_state = "bandage1-l_arm" + body_parts = list(BP_L_ARM) + +/decl/sprite_accessory/marking/bandage/left_hand + name = "Bandage, Left Hand, 1" + uid = "accessory_marking_bandage1_l_hand" + icon_state = "bandage1-l_hand" + body_parts = list(BP_L_HAND) + +/decl/sprite_accessory/marking/bandage/right_arm + name = "Bandage, Right Arm, 1" + uid = "accessory_marking_bandage1_r_arm" + icon_state = "bandage1-r_arm" + body_parts = list(BP_R_ARM) + +/decl/sprite_accessory/marking/bandage/right_hand + name = "Bandage, Right Hand, 1" + uid = "accessory_marking_bandage1_r_hand" + icon_state = "bandage1-r_hand" + body_parts = list(BP_R_HAND) + +/decl/sprite_accessory/marking/bandage/left_leg + name = "Bandage, Left Leg, 1" + uid = "accessory_marking_bandage1_l_leg" + icon_state = "bandage1-l_leg" + body_parts = list(BP_L_LEG) + +/decl/sprite_accessory/marking/bandage/left_foot + name = "Bandage, Left Foot, 1" + uid = "accessory_marking_bandage1_l_foot" + icon_state = "bandage1-l_foot" + body_parts = list(BP_L_FOOT) + +/decl/sprite_accessory/marking/bandage/right_leg + name = "Bandage, Right Leg, 1" + uid = "accessory_marking_bandage1_r_leg" + icon_state = "bandage1-r_leg" + body_parts = list(BP_R_LEG) + +/decl/sprite_accessory/marking/bandage/right_foot + name = "Bandage, Right Foot, 1" + uid = "accessory_marking_bandage1_r_foot" + icon_state = "bandage1-r_foot" + body_parts = list(BP_R_FOOT) + +/decl/sprite_accessory/marking/bandage/head/two + name = "Bandage, Head, 2" + uid = "accessory_marking_bandage2_head" + icon_state = "bandage2-head" + +/decl/sprite_accessory/marking/bandage/torso/two + name = "Bandage, Chest, 2" + uid = "accessory_marking_bandage2_torso" + icon_state = "bandage2-torso" + +/decl/sprite_accessory/marking/bandage/left_arm/two + name = "Bandage, Left Arm, 2" + uid = "accessory_marking_bandage2_l_arm" + icon_state = "bandage2-l_arm" + +/decl/sprite_accessory/marking/bandage/left_hand/two + name = "Bandage, Left Hand, 2" + uid = "accessory_marking_bandage2_l_hand" + icon_state = "bandage2-l_hand" + +/decl/sprite_accessory/marking/bandage/right_arm/two + name = "Bandage, Right Arm, 2" + uid = "accessory_marking_bandage2_r_arm" + icon_state = "bandage2-r_arm" + +/decl/sprite_accessory/marking/bandage/right_hand/two + name = "Bandage, Right Hand, 2" + uid = "accessory_marking_bandage2_r_hand" + icon_state = "bandage2-r_hand" + +/decl/sprite_accessory/marking/bandage/left_leg/two + name = "Bandage, Left Leg, 2" + uid = "accessory_marking_bandage2_l_leg" + icon_state = "bandage2-l_leg" + +/decl/sprite_accessory/marking/bandage/left_foot/two + name = "Bandage, Left Foot, 2" + uid = "accessory_marking_bandage2_l_foot" + icon_state = "bandage2-l_foot" + +/decl/sprite_accessory/marking/bandage/right_leg/two + name = "Bandage, Right Leg, 2" + uid = "accessory_marking_bandage2_r_leg" + icon_state = "bandage2-r_leg" + +/decl/sprite_accessory/marking/bandage/right_foot/two + name = "Bandage, Right Foot, 2" + uid = "accessory_marking_bandage2_r_foot" + icon_state = "bandage2-r_foot" + +/decl/sprite_accessory/marking/bandage/head/three + name = "Bandage, Head, 1" + uid = "accessory_marking_bandage3_head" + icon_state = "bandage3-head" + +/decl/sprite_accessory/marking/bandage/left_arm/three + name = "Bandage, Left Arm, 3" + uid = "accessory_marking_bandage3_l_arm" + icon_state = "bandage3-l_arm" + +/decl/sprite_accessory/marking/bandage/left_hand/three + name = "Bandage, Left Hand, 3" + uid = "accessory_marking_bandage3_l_hand" + icon_state = "bandage3-l_hand" + +/decl/sprite_accessory/marking/bandage/right_arm/three + name = "Bandage, Right Arm, 3" + uid = "accessory_marking_bandage3_r_arm" + icon_state = "bandage3-r_arm" + +/decl/sprite_accessory/marking/bandage/right_hand/three + name = "Bandage, Right Hand, 3" + uid = "accessory_marking_bandage3_r_hand" + icon_state = "bandage3-r_hand" + +/decl/sprite_accessory/marking/bandage/left_leg/three + name = "Bandage, Left Leg, 3" + uid = "accessory_marking_bandage3_l_leg" + icon_state = "bandage3-l_leg" + +/decl/sprite_accessory/marking/bandage/left_foot/three + name = "Bandage, Left Foot, 3" + uid = "accessory_marking_bandage3_l_foot" + icon_state = "bandage3-l_foot" + +/decl/sprite_accessory/marking/bandage/right_leg/three + name = "Bandage, Right Leg, 3" + uid = "accessory_marking_bandage3_r_leg" + icon_state = "bandage3-r_leg" + +/decl/sprite_accessory/marking/bandage/right_foot/three + name = "Bandage, Right Foot, 3" + uid = "accessory_marking_bandage3_r_foot" + icon_state = "bandage3-r_foot" diff --git a/code/modules/sprite_accessories/markings/accessory_markings_face.dm b/code/modules/sprite_accessories/markings/accessory_markings_face.dm new file mode 100644 index 000000000000..91701ee16f8e --- /dev/null +++ b/code/modules/sprite_accessories/markings/accessory_markings_face.dm @@ -0,0 +1,47 @@ +// TODO: merge these with cosmetics? +/decl/sprite_accessory/marking/face + abstract_type = /decl/sprite_accessory/marking/face + body_parts = list(BP_HEAD) + +/decl/sprite_accessory/marking/face/lips + name = "Lips" + icon_state = "lips" + uid = "accessory_marking_lips" + +/decl/sprite_accessory/marking/face/blush + name = "Blush, Face" + icon_state = "blush" + uid = "accessory_marking_blush" + +/decl/sprite_accessory/marking/face/cheekspot_l + + name = "Cheek Spot, Left" + icon_state = "cheekspot_l" + uid = "accessory_marking_cheekspot_l" + +/decl/sprite_accessory/marking/face/cheekspot_r + + name = "Cheek Spot, Right" + icon_state = "cheekspot_r" + uid = "accessory_marking_cheekspot_r" + +/decl/sprite_accessory/marking/face/eyecorner_l + + name = "Eye Corner, Left" + icon_state = "eyecorner_l" + uid = "accessory_marking_eyecorner_l" + +/decl/sprite_accessory/marking/face/eyecorner_r + name = "Eye Corner, Right" + icon_state = "eyecorner_r" + uid = "accessory_marking_eyecorner_r" + +/decl/sprite_accessory/marking/face/brow_l + name = "Eyebrow, Left" + icon_state = "brow_l" + uid = "accessory_marking_brow_l" + +/decl/sprite_accessory/marking/face/brow_r + name = "Eyebrow, Right" + icon_state = "brow_r" + uid = "accessory_marking_brow_r" diff --git a/code/modules/sprite_accessories/markings/accessory_markings_scars.dm b/code/modules/sprite_accessories/markings/accessory_markings_scars.dm new file mode 100644 index 000000000000..afb1f8088278 --- /dev/null +++ b/code/modules/sprite_accessories/markings/accessory_markings_scars.dm @@ -0,0 +1,223 @@ +/decl/sprite_accessory/marking/scar + icon = 'icons/mob/human_races/species/default_scars.dmi' + abstract_type = /decl/sprite_accessory/marking/scar + species_allowed = null // Everyone can be scarred. + bodytype_categories_allowed = list(BODYTYPE_HUMANOID) // Only fit the humanoid silhouette, though. + +/decl/sprite_accessory/marking/scar/abdomen + abstract_type = /decl/sprite_accessory/marking/scar/abdomen + body_parts = list(BP_GROIN) + +/decl/sprite_accessory/marking/scar/abdomen/right + name = "Scar, Abdomen, Right" + uid = "accessory_marking_scar_abdomen_r" + icon_state = "scar_abdomen_r" + +/decl/sprite_accessory/marking/scar/abdomen/left + name = "Scar, Abdomen, Left" + uid = "accessory_marking_scar_abdomen_l" + icon_state = "scar_abdomen_l" + +/decl/sprite_accessory/marking/scar/abdomen/small_right + name = "Scar, Abdomen, Right, Small" + uid = "accessory_marking_scar_abdomen_small_r" + icon_state = "scar_abdomensmall_r" + +/decl/sprite_accessory/marking/scar/abdomen/small_left + name = "Scar, Abdomen, Left, Small" + uid = "accessory_marking_scar_abdomen_small_l" + icon_state = "scar_abdomensmall_l" + +/decl/sprite_accessory/marking/scar/abdomen/back + name = "Scar, Back, Large" + uid = "accessory_marking_scar_back_large" + icon_state = "scar_back_large" + +/decl/sprite_accessory/marking/scar/chest + abstract_type = /decl/sprite_accessory/marking/scar/chest + body_parts = list(BP_CHEST) + +/decl/sprite_accessory/marking/scar/chest/small + name = "Scar, Back, Small" + uid = "accessory_marking_scar_back_small" + icon_state = "scar_back_small" + +/decl/sprite_accessory/marking/scar/chest/small_upper_right + name = "Scar, Back, Small, Upper Right" + uid = "accessory_marking_scar_small_ur" + icon_state = "scar_back_small_ur" + +/decl/sprite_accessory/marking/scar/chest/small_upper_left + name = "Scar, Back, Small, Upper Left" + uid = "accessory_marking_scar_small_ul" + icon_state = "scar_back_small_ul" + +/decl/sprite_accessory/marking/scar/chest/small_lower_right + name = "Scar, Back, Small, Lower Right" + uid = "accessory_marking_scar_small_lr" + icon_state = "scar_back_small_lr" + +/decl/sprite_accessory/marking/scar/chest/small_lower_left + name = "Scar, Back, Small, Lower Left" + uid = "accessory_marking_scar_small_ll" + icon_state = "scar_back_small_ll" + +/decl/sprite_accessory/marking/scar/chest/large_right + name = "Scar, Chest, Large, Right" + uid = "accessory_marking_scar_chest_large_r" + icon_state = "scar_chest_large_r" + +/decl/sprite_accessory/marking/scar/chest/large_left + name = "Scar, Chest, Large, Left" + uid = "accessory_marking_scar_chest_large_l" + icon_state = "scar_chest_large_l" + +/decl/sprite_accessory/marking/scar/chest/small_left + name = "Scar, Chest, Small, Left" + uid = "accessory_marking_scar_chest_small_left" + icon_state = "scar_chest_small_l" + +/decl/sprite_accessory/marking/scar/chest/small_right + name = "Scar, Chest, Small, Right" + uid = "accessory_marking_scar_chest_small_right" + icon_state = "scar_chest_small_r" + +/decl/sprite_accessory/marking/scar/chest/belly + name = "Scar, Belly" + uid = "accessory_marking_scar_belly" + icon_state = "scar_belly" + +/decl/sprite_accessory/marking/scar/face + abstract_type = /decl/sprite_accessory/marking/scar/face + body_parts = list(BP_HEAD) + +/decl/sprite_accessory/marking/scar/face/cheek_left + name = "Scar, Left Cheek" + uid = "accessory_marking_scar_face_cheek_l" + icon_state = "scar_cheek_l" + +/decl/sprite_accessory/marking/scar/face/cheek_right + name = "Scar, Right Cheek" + uid = "accessory_marking_scar_face_cheek_r" + icon_state = "scar_cheek_r" + +/decl/sprite_accessory/marking/scar/face/forehead_left + name = "Scar, Forehead, Left" + uid = "accessory_marking_scar_forehead_l" + icon_state = "scar_forehead_l" + +/decl/sprite_accessory/marking/scar/face/forehead_right + name = "Scar, Forehead, Right" + uid = "accessory_marking_scar_forehead_r" + icon_state = "scar_forehead_r" + +/decl/sprite_accessory/marking/scar/face/chin + name = "Scar, Chin" + uid = "accessory_marking_scar_chin" + icon_state = "scar_chin" + +/decl/sprite_accessory/marking/scar/face/eye_left + name = "Scar, Left Eye" + uid = "accessory_marking_scar_eye_l" + icon_state = "scar_eye_l" + +/decl/sprite_accessory/marking/scar/face/eye_right + name = "Scar, Right Eye" + uid = "accessory_marking_scar_eye_r" + icon_state = "scar_eye_r" + +/decl/sprite_accessory/marking/scar/left_arm + abstract_type = /decl/sprite_accessory/marking/scar/left_arm + body_parts = list(BP_L_ARM, BP_L_HAND) + +/decl/sprite_accessory/marking/scar/left_arm/upper + name = "Scar, Left Arm (Upper)" + uid = "accessory_marking_scar_l_arm_upper" + icon_state = "scar_arm_left_u" + +/decl/sprite_accessory/marking/scar/left_arm/lower + name = "Scar, Left Arm (Lower)" + uid = "accessory_marking_scar_l_arm_lower" + icon_state = "scar_arm_left_l" + +/decl/sprite_accessory/marking/scar/left_arm/rear + name = "Scar, Left Arm (Rear)" + uid = "accessory_marking_scar_l_arm_rear" + icon_state = "scar_arm_left_rear" + +/decl/sprite_accessory/marking/scar/left_arm/hand + name = "Scar, Left Hand" + uid = "accessory_marking_scar_l_hand" + icon_state = "scar_hand_left" + +/decl/sprite_accessory/marking/scar/right_arm + abstract_type = /decl/sprite_accessory/marking/scar/right_arm + body_parts = list(BP_R_ARM, BP_R_HAND) + +/decl/sprite_accessory/marking/scar/right_arm/upper + name = "Scar, Right Arm (Upper)" + uid = "accessory_marking_scar_r_arm_upper" + icon_state = "scar_arm_right_u" + +/decl/sprite_accessory/marking/scar/right_arm/lower + name = "Scar, Right Arm (Lower)" + uid = "accessory_marking_scar_r_arm_lower" + icon_state = "scar_arm_right_l" + +/decl/sprite_accessory/marking/scar/right_arm/rear + name = "Scar, Right Arm (Rear)" + uid = "accessory_marking_scar_r_arm_rear" + icon_state = "scar_arm_right_rear" + +/decl/sprite_accessory/marking/scar/right_arm/hand + name = "Scar, Right Hand" + uid = "accessory_marking_scar_r_hand" + icon_state = "scar_hand_right" + +/decl/sprite_accessory/marking/scar/left_leg + abstract_type = /decl/sprite_accessory/marking/scar/left_leg + body_parts = list(BP_L_LEG, BP_L_FOOT) + +/decl/sprite_accessory/marking/scar/left_leg/upper + name = "Scar, Left Leg (Upper)" + uid = "accessory_marking_scar_l_leg_upper" + icon_state = "scar_leg_left_u" + +/decl/sprite_accessory/marking/scar/left_leg/lower + name = "Scar, Left Leg (Lower)" + uid = "accessory_marking_scar_l_leg_lower" + icon_state = "scar_leg_left_l" + +/decl/sprite_accessory/marking/scar/left_leg/rear + name = "Scar, Left Leg (Rear)" + uid = "accessory_marking_scar_l_leg_rear" + icon_state = "scar_leg_left_rear" + +/decl/sprite_accessory/marking/scar/left_leg/foot + name = "Scar, Left Foot" + uid = "accessory_marking_scar_l_foot" + icon_state = "scar_left_foot" + +/decl/sprite_accessory/marking/scar/right_leg + abstract_type = /decl/sprite_accessory/marking/scar/right_leg + body_parts = list(BP_R_LEG, BP_R_FOOT) + +/decl/sprite_accessory/marking/scar/right_leg/upper + name = "Scar, Right Leg (Upper)" + uid = "accessory_marking_scar_r_leg_upper" + icon_state = "scar_right_leg_u" + +/decl/sprite_accessory/marking/scar/right_leg/lower + name = "Scar, Right Leg (Lower)" + uid = "accessory_marking_scar_r_leg_lower" + icon_state = "scar_right_leg_l" + +/decl/sprite_accessory/marking/scar/right_leg/rear + name = "Scar, Right Leg (Rear)" + uid = "accessory_marking_scar_r_leg_rear" + icon_state = "scar_right_leg_rear" + +/decl/sprite_accessory/marking/scar/right_leg/foot + name = "Scar, Right Foot" + uid = "accessory_marking_scar_r_foot" + icon_state = "scar_right_foot" \ No newline at end of file diff --git a/code/modules/sprite_accessories/markings/accessory_markings_tattoos.dm b/code/modules/sprite_accessories/markings/accessory_markings_tattoos.dm new file mode 100644 index 000000000000..7e8c68157877 --- /dev/null +++ b/code/modules/sprite_accessories/markings/accessory_markings_tattoos.dm @@ -0,0 +1,254 @@ +/decl/sprite_accessory/marking/tat + abstract_type = /decl/sprite_accessory/marking/tat + icon = 'icons/mob/human_races/species/default_tattoos.dmi' + +/decl/sprite_accessory/marking/tat/hive + name = "Tattoo (Hive, Back)" + icon_state = "tat_hive" + body_parts = list(BP_CHEST) + uid = "acc_marking_hive" + +/decl/sprite_accessory/marking/tat/nightling + name = "Tattoo (Nightling, Back)" + icon_state = "tat_nightling" + body_parts = list(BP_CHEST) + uid = "acc_marking_nightling" + +/decl/sprite_accessory/marking/tat/campbell + name = "Tattoo (Campbell, R.Arm)" + icon_state = "tat_campbell" + body_parts = list(BP_R_ARM) + uid = "acc_marking_campbell" + +/decl/sprite_accessory/marking/tat/campbell/left + name = "Tattoo (Campbell, L.Arm)" + body_parts = list(BP_L_ARM) + uid = "acc_marking_campbell_leftarm" + +/decl/sprite_accessory/marking/tat/tiger1 + name = "Tattoo (Tiger Stripes, Body)" + icon_state = "tat_tiger" + body_parts = list(BP_CHEST,BP_GROIN) + uid = "acc_marking_tiger" + +/decl/sprite_accessory/marking/tat/tiger_arm_left + name = "Tattoo (Tiger Left Arm)" + icon_state = "tat_tiger" + body_parts = list(BP_L_ARM) + uid = "acc_marking_tiger_leftarm" + +/decl/sprite_accessory/marking/tat/tiger_arm_right + name = "Tattoo (Tiger Right Arm)" + icon_state = "tat_tiger" + body_parts = list(BP_R_ARM) + uid = "acc_marking_tiger_rightarm" + +/decl/sprite_accessory/marking/tat/tiger_leg + name = "Tattoo (Tiger Left Leg)" + icon_state = "tat_tiger" + body_parts = list(BP_L_LEG) + uid = "acc_marking_tiger_leftleg" + +/decl/sprite_accessory/marking/tat/tiger_leg/right + name = "Tattoo (Tiger Right Leg)" + icon_state = "tat_tiger" + body_parts = list(BP_R_LEG) + uid = "acc_marking_tiger_rightleg" + +/decl/sprite_accessory/marking/tat/bands_body + name = "Tattoo (Bands Body)" + icon_state = "bands" + body_parts = list(BP_CHEST,BP_GROIN) + uid = "acc_marking_bands" + +/decl/sprite_accessory/marking/tat/bands_arm_right + name = "Tattoo (Bands Right Arm)" + icon_state = "bands" + body_parts = list(BP_R_ARM) + uid = "acc_marking_bands_rightarm" + +/decl/sprite_accessory/marking/tat/bands_arm_left + name = "Tattoo (Bands Left Arm)" + icon_state = "bands" + body_parts = list(BP_L_ARM) + uid = "acc_marking_bands_leftarm" + +/decl/sprite_accessory/marking/tat/bands_hand_right + name = "Tattoo (Bands Right Hand)" + icon_state = "bands" + body_parts = list(BP_R_HAND) + uid = "acc_marking_bands_righthand" + +/decl/sprite_accessory/marking/tat/bands_hand_left + name = "Tattoo (Bands Left Hand)" + icon_state = "bands" + body_parts = list(BP_L_HAND) + uid = "acc_marking_bands_lefthand" + +/decl/sprite_accessory/marking/tat/bands_leg_right + name = "Tattoo (Bands Right Leg)" + icon_state = "bands" + body_parts = list(BP_R_LEG) + uid = "acc_marking_bands_rightleg" + +/decl/sprite_accessory/marking/tat/bands_leg_left + name = "Tattoo (Bands Left Leg)" + icon_state = "bands" + body_parts = list(BP_L_LEG) + uid = "acc_marking_bands_leftleg" + +/decl/sprite_accessory/marking/tat/snake_col_l + name = "Tattoo (Snake, Left Arm, Colourable)" + uid = "acc_marking_snake_col_l" + icon_state = "tat_snake_col_l" + body_parts = list(BP_L_ARM, BP_CHEST) + +/decl/sprite_accessory/marking/tat/snake_col_r + name = "Tattoo (Snake, Right Arm, Colourable)" + uid = "acc_marking_snake_col_r" + icon_state = "tat_snake_col_r" + body_parts = list(BP_R_ARM, BP_CHEST) + +/decl/sprite_accessory/marking/tat/snake_l + name = "Tattoo (Snake, Left Arm)" + uid = "acc_marking_snake_l" + icon_state = "tat_snake_l" + body_parts = list(BP_L_ARM, BP_CHEST) + +/decl/sprite_accessory/marking/tat/snake_r + name = "Tattoo (Snake, Right Arm)" + uid = "acc_marking_snake_r" + icon_state = "tat_snake_r" + body_parts = list(BP_R_ARM, BP_CHEST) + +/decl/sprite_accessory/marking/tat/rose + name = "Tattoo (Rose, Left Leg)" + uid = "acc_marking_rose_l_leg" + icon_state = "tat_rose" + body_parts = list(BP_L_LEG, BP_L_FOOT) + +/decl/sprite_accessory/marking/tat/rose/r_leg + name = "Tattoo (Rose, Right Leg)" + uid = "acc_marking_rose_r_leg" + body_parts = list(BP_R_LEG, BP_R_FOOT) + +/decl/sprite_accessory/marking/tat/rose/l_arm + name = "Tattoo (Rose, Left Arm)" + uid = "acc_marking_rose_l_arm" + body_parts = list(BP_L_ARM, BP_L_ARM) + +/decl/sprite_accessory/marking/tat/rose/r_arm + name = "Tattoo (Rose, Right Arm)" + uid = "acc_marking_rose_r_arm" + body_parts = list(BP_R_ARM, BP_R_ARM) + +/decl/sprite_accessory/marking/tat/head + name = "Tattoo (Tiger Head)" + icon_state = "tigerhead" + body_parts = list(BP_HEAD) + uid = "acc_marking_tiger_head" + +/decl/sprite_accessory/marking/tat/head/ridge + name = "Tattoo (Ridge, Face)" + icon_state = "tat_face_ridge" + uid = "acc_marking_face_ridge" + +/decl/sprite_accessory/marking/tat/head/hunter + name = "Tattoo (Hunter, Face)" + icon_state = "tat_face_hunter" + uid = "acc_marking_face_hunter" + +/decl/sprite_accessory/marking/tat/head/nosestripe + name = "Tattoo (Nose Stripe)" + icon_state = "nosestripe" + uid = "acc_marking_nosestripe" + +/decl/sprite_accessory/marking/tat/head/skull + name = "Tattoo (Skull, Face)" + icon_state = "skull" + uid = "acc_marking_skull" + +/decl/sprite_accessory/marking/tat/head/tigerface + name = "Tattoo (Tiger Face)" + icon_state = "tigerface" + uid = "acc_marking_tiger_face" + +/decl/sprite_accessory/marking/tat/head/montana + name = "Tattoo (Montana, Left Eye)" + uid = "acc_marking_montana_l" + icon_state = "tat_montana_l" + +/decl/sprite_accessory/marking/tat/head/montana/right + name = "Tattoo (Montana, Right Eye)" + uid = "acc_marking_montana_r" + icon_state = "tat_montana_r" + +/decl/sprite_accessory/marking/tat/head/forrest + name = "Tattoo (Forrest, Left Eye)" + uid = "acc_marking_forrest_l" + icon_state = "tat_forrest_l" + +/decl/sprite_accessory/marking/tat/head/forrest/right + name = "Tattoo (Forrest, Right Eye)" + uid = "acc_marking_forrest_r" + icon_state = "tat_forrest_r" + +/decl/sprite_accessory/marking/tat/head/hunter + name = "Tattoo (Hunter, Left Eye)" + uid = "acc_marking_hunter_l" + icon_state = "tat_hunter_l" + +/decl/sprite_accessory/marking/tat/head/hunter/right + name = "Tattoo (Hunter, Right Eye)" + uid = "acc_marking_hunter_r" + icon_state = "tat_hunter_r" + +/decl/sprite_accessory/marking/tat/head/jaeger + name = "Tattoo (Jaeger, Left Eye)" + uid = "acc_marking_jaeger_l" + icon_state = "tat_jaeger_l" + +/decl/sprite_accessory/marking/tat/head/jaeger/right + name = "Tattoo (Jaeger, Right Eye)" + uid = "acc_marking_jaeger_r" + icon_state = "tat_jaeger_r" + +/decl/sprite_accessory/marking/tat/head/kater + name = "Tattoo (Kater, Left Eye)" + uid = "acc_marking_kater_l" + icon_state = "tat_kater_l" + +/decl/sprite_accessory/marking/tat/head/kater/right + name = "Tattoo (Kater, Right Eye)" + uid = "acc_marking_kater_r" + icon_state = "tat_kater_r" + +/decl/sprite_accessory/marking/tat/head/lujan + name = "Tattoo (Lujan, Left Eye)" + uid = "acc_marking_lujan_l" + icon_state = "tat_lujan_l" + +/decl/sprite_accessory/marking/tat/head/lujan/right + name = "Tattoo (Lujan, Right Eye)" + uid = "acc_marking_lujan_r" + icon_state = "tat_lujan_r" + +/decl/sprite_accessory/marking/tat/head/natasha + name = "Tattoo (Natasha, Left Eye)" + uid = "acc_marking_natasha_l" + icon_state = "tat_natasha_l" + +/decl/sprite_accessory/marking/tat/head/natasha/right + name = "Tattoo (Natasha, Right Eye)" + uid = "acc_marking_natasha_r" + icon_state = "tat_natasha_r" + +/decl/sprite_accessory/marking/tat/head/toshi + name = "Tattoo (Toshi, Left Eye)" + uid = "acc_marking_toshi_l" + icon_state = "tat_toshi_l" + +/decl/sprite_accessory/marking/tat/head/toshi/right + name = "Tattoo (Toshi, Right Eye)" + uid = "acc_marking_toshi_r" + icon_state = "tat_toshi_r" diff --git a/code/modules/sprite_accessories/metadata/_accessory_metadata.dm b/code/modules/sprite_accessories/metadata/_accessory_metadata.dm new file mode 100644 index 000000000000..94e0d0e3d4d9 --- /dev/null +++ b/code/modules/sprite_accessories/metadata/_accessory_metadata.dm @@ -0,0 +1,19 @@ +/decl/sprite_accessory_metadata + abstract_type = /decl/sprite_accessory_metadata + decl_flags = DECL_FLAG_MANDATORY_UID + var/name + var/default_value + +/decl/sprite_accessory_metadata/proc/get_new_value_for(mob/user, decl/sprite_accessory/accessory_decl, current_value) + return + +/decl/sprite_accessory_metadata/proc/validate_data(value) + return FALSE + +/decl/sprite_accessory_metadata/proc/sanitize_data(value) + if(validate_data(value)) + return value + return default_value + +/decl/sprite_accessory_metadata/proc/get_metadata_options_string(datum/preferences/pref, decl/sprite_accessory_category/accessory_category_decl, decl/sprite_accessory/accessory_decl, value) + return diff --git a/code/modules/sprite_accessories/metadata/accessory_metadata_color.dm b/code/modules/sprite_accessories/metadata/accessory_metadata_color.dm new file mode 100644 index 000000000000..e63739203cbb --- /dev/null +++ b/code/modules/sprite_accessories/metadata/accessory_metadata_color.dm @@ -0,0 +1,18 @@ +/decl/sprite_accessory_metadata/color + name = "Color" + default_value = COLOR_BLACK + uid = "sa_metadata_color" + +/decl/sprite_accessory_metadata/color/validate_data(value) + return istext(value) && (length(value) == 7 || length(value) == 9) + +/decl/sprite_accessory_metadata/color/get_metadata_options_string(datum/preferences/pref, decl/sprite_accessory_category/accessory_category_decl, decl/sprite_accessory/accessory_decl, value) + value = sanitize_data(value) + return "[COLORED_SQUARE(value)] Change" + +/decl/sprite_accessory_metadata/color/get_new_value_for(mob/user, decl/sprite_accessory/accessory_decl, current_value) + return input(user, "Choose a [lowertext(name)] for your [accessory_decl.name]: ", CHARACTER_PREFERENCE_INPUT_TITLE, current_value) as color|null + +/decl/sprite_accessory_metadata/color/alt + name = "Secondary Color" + uid = "sa_metadata_color_alt" diff --git a/code/modules/sprite_accessories/metadata/accessory_metadata_gradient.dm b/code/modules/sprite_accessories/metadata/accessory_metadata_gradient.dm new file mode 100644 index 000000000000..f6a547fe81c3 --- /dev/null +++ b/code/modules/sprite_accessories/metadata/accessory_metadata_gradient.dm @@ -0,0 +1,49 @@ +/decl/sprite_accessory_metadata/gradient + name = "Gradient" + uid = "sa_metadata_gradient" + default_value = "none" + var/icon/icon = 'icons/mob/hair_gradients.dmi' + /// A list of text labels for states that need more than just capitalize() to be presentable. + var/list/selectable_states_to_labels = list( + "fadeup" = "Fade Up", + "fadedown" = "Fade Down", + "vsplit" = "Vertical Split", + "bottomflat" = "Flat Bottom", + "fadeup_low" = "Fade Up (Low)", + "fadedown_low" = "Fade Down (Low)", + "reflected_inverse" = "Reflected (Inverse)", + "reflected_high" = "Reflected (High)", + "reflected_inverse_high" = "Reflected (Inverse High)" + ) + /// Inverse of the above, generated at runtime. + var/list/selectable_labels_to_states = list() + +/decl/sprite_accessory_metadata/gradient/Initialize() + for(var/state in get_states_in_icon_cached(icon)) + if(!selectable_states_to_labels[state]) + selectable_states_to_labels[state] = capitalize(state) + for(var/state in selectable_states_to_labels) + selectable_labels_to_states[selectable_states_to_labels[state]] = state + return ..() + +/decl/sprite_accessory_metadata/gradient/validate() + . = ..() + if(!length(selectable_states_to_labels)) + . += "no selectable gradient states" + else + if(!(default_value in selectable_states_to_labels)) + . += "default_value '[default_value]' not in selectable list" + for(var/state in selectable_labels_to_states) + if(!(selectable_labels_to_states[state] in selectable_states_to_labels)) + . += "label for non-existent state '[state]'" + +/decl/sprite_accessory_metadata/gradient/validate_data(value) + return istext(value) && (value in selectable_states_to_labels) + +/decl/sprite_accessory_metadata/gradient/get_metadata_options_string(datum/preferences/pref, decl/sprite_accessory_category/accessory_category_decl, decl/sprite_accessory/accessory_decl, value) + value = sanitize_data(value) + return "[selectable_states_to_labels[value]]" + +/decl/sprite_accessory_metadata/gradient/get_new_value_for(mob/user, decl/sprite_accessory/accessory_decl, current_value) + var/choice = input(user, "Choose a [lowertext(name)] for your [accessory_decl.name]: ", CHARACTER_PREFERENCE_INPUT_TITLE, current_value) as null|anything in selectable_labels_to_states + return choice ? selectable_labels_to_states[choice] : null \ No newline at end of file diff --git a/code/modules/sprite_accessories/tails/_accessory_tail.dm b/code/modules/sprite_accessories/tails/_accessory_tail.dm new file mode 100644 index 000000000000..031e7ac40793 --- /dev/null +++ b/code/modules/sprite_accessories/tails/_accessory_tail.dm @@ -0,0 +1,61 @@ +/decl/sprite_accessory_category/tail + name = "Tail" + base_accessory_type = /decl/sprite_accessory/tail + default_accessory = /decl/sprite_accessory/tail/none + uid = "acc_cat_tail" + +/decl/sprite_accessory_category/tail/prepare_character(mob/living/character, list/accessories) + if(!istype(character) || !length(accessories)) + return + // Give us a tail if we need one. + var/decl/sprite_accessory/tail_data = GET_DECL(accessories[1]) + if(tail_data?.draw_accessory && !character.get_organ(BP_TAIL)) + var/obj/item/organ/external/tail/new_tail = new(null, null, character.get_mob_snapshot()) + character.add_organ(new_tail, null, TRUE, FALSE, FALSE, TRUE) + +/decl/sprite_accessory_category/tail/prepare_mob_snapshot(datum/mob_snapshot/snapshot, list/accessories) + if(!length(accessories)) + return + // Give us a tail if we need one. + var/decl/sprite_accessory/tail_data = GET_DECL(accessories[1]) + if(tail_data?.draw_accessory && !snapshot.root_bodytype.has_limbs[BP_TAIL]) + LAZYSET(snapshot.extra_limbs, BP_TAIL, list("path" = /obj/item/organ/external/tail)) + +/decl/sprite_accessory/tail + abstract_type = /decl/sprite_accessory/tail + hidden_by_gear_slot = list(slot_w_uniform_str, slot_wear_suit_str) + hidden_by_gear_flag = HIDETAIL + body_parts = list(BP_TAIL) + sprite_overlay_layer = FLOAT_LAYER-1 + is_heritable = TRUE + icon_state = "tail" + icon = 'icons/mob/human_races/species/default_tail.dmi' + accessory_category = SAC_TAIL + abstract_type = /decl/sprite_accessory/tail + color_blend = ICON_MULTIPLY + + var/icon_animation_states + var/hair_state + var/hair_blend = ICON_ADD + +/decl/sprite_accessory/tail/none + name = "Default Tail" + icon_state = "none" + uid = "acc_tail_none" + bodytypes_allowed = null + bodytypes_denied = null + species_allowed = null + bodytype_categories_allowed = null + bodytype_categories_denied = null + body_flags_allowed = null + body_flags_denied = null + grooming_flags = null + draw_accessory = FALSE + +/decl/sprite_accessory/tail/none/hide_tail + name = "Hide Species Tail" + uid = "acc_tail_hidden" + draw_accessory = TRUE + +/decl/sprite_accessory/tail/none/hide_tail/accessory_is_available(mob/owner, decl/species/species, decl/bodytype/bodytype, list/traits) + . = ..() && (BP_TAIL in bodytype.has_limbs) diff --git a/code/modules/status_conditions/_status_condition.dm b/code/modules/status_conditions/_status_condition.dm new file mode 100644 index 000000000000..a377bed14b3d --- /dev/null +++ b/code/modules/status_conditions/_status_condition.dm @@ -0,0 +1,36 @@ +var/global/list/status_marker_holders = list() + +// Check code/modules/mob/mob_status.dm code/modules/mob/living/living_status.dm +// for the procs that check/set/process these status conditions. +/decl/status_condition + var/name + var/check_flags = 0 + var/list/victim_data + + var/decl/mob_modifier/associated_mob_modifier + + var/status_marker_icon = 'icons/effects/status.dmi' + var/status_marker_state + var/status_marker_private = FALSE + +/decl/status_condition/Initialize() + . = ..() + if(ispath(associated_mob_modifier)) + associated_mob_modifier = GET_DECL(associated_mob_modifier) + +/decl/status_condition/validate() + . = ..() + if(associated_mob_modifier && !istype(associated_mob_modifier)) + . += "invalid associated_mob_modifier '[associated_mob_modifier]'" + +/decl/status_condition/proc/handle_changed_amount(var/mob/living/victim, var/new_amount, var/last_amount) + set waitfor = FALSE + +/decl/status_condition/proc/check_can_set(var/mob/living/victim) + return !check_flags || (victim.status_flags & check_flags) + +/decl/status_condition/proc/handle_status(var/mob/living/victim, var/amount) + ADJ_STATUS(victim, type, -1) + +/decl/status_condition/proc/show_status(var/mob/owner) + return !status_marker_private && istype(owner) && owner.stat == CONSCIOUS diff --git a/code/modules/status_conditions/_status_markers.dm b/code/modules/status_conditions/_status_markers.dm new file mode 100644 index 000000000000..c6e0f8ec8e58 --- /dev/null +++ b/code/modules/status_conditions/_status_markers.dm @@ -0,0 +1,138 @@ +var/global/list/_status_marker_decls +/proc/get_status_marker_decls() + if(!global._status_marker_decls) + global._status_marker_decls = list() + for(var/decl/status_condition/cond as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/status_condition)) + if(cond.status_marker_icon && cond.status_marker_state) + global._status_marker_decls += cond + return global._status_marker_decls + +/obj/status_marker + name = "" + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + simulated = FALSE + alpha = 0 + plane = DEFAULT_PLANE + layer = POINTER_LAYER + vis_flags = VIS_INHERIT_ID + +/obj/status_marker/Initialize(var/ml, var/decl/status_condition/status) + + . = ..() + + if(!istype(status)) + return INITIALIZE_HINT_QDEL + icon = status.status_marker_icon + icon_state = status.status_marker_state + + // Throwing these in here in the hopes of preventing the markers showing up in right click. + name = "" + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + verbs.Cut() + +/datum/status_marker_holder + var/list/markers + var/image/mob_image + var/list/markers_personal + var/image/mob_image_personal + +/datum/status_marker_holder/proc/clear_markers() + for(var/marker as anything in markers) + animate(markers[marker], pixel_z = 12, alpha = 0, time = 3) + for(var/marker as anything in markers_personal) + animate(markers_personal[marker], pixel_z = 12, alpha = 0, time = 3) + +/datum/status_marker_holder/New(var/mob/owner) + + ..() + + if(!istype(owner)) + PRINT_STACK_TRACE("Status marker holder created with an invalid owner: [owner || "NULL"].") + return + + mob_image = new /image + mob_image.loc = owner + mob_image.appearance_flags |= (RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM|KEEP_APART) + mob_image.plane = DEFAULT_PLANE + mob_image.layer = POINTER_LAYER + + animate(mob_image, pixel_z = 1, time = 3, easing = (SINE_EASING | EASE_OUT), loop = -1) + animate( pixel_z = -1, time = 6, easing = SINE_EASING, loop = -1) + animate( pixel_z = 0, time = 3, easing = (SINE_EASING | EASE_IN), loop = -1) + + mob_image_personal = new /image + mob_image_personal.loc = owner + mob_image_personal.appearance_flags |= (RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM|KEEP_APART) + mob_image_personal.plane = DEFAULT_PLANE + mob_image_personal.layer = POINTER_LAYER + + animate(mob_image_personal, pixel_z = 1, time = 3, easing = (SINE_EASING | EASE_OUT), loop = -1) + animate( pixel_z = -1, time = 6, easing = SINE_EASING, loop = -1) + animate( pixel_z = 0, time = 3, easing = (SINE_EASING | EASE_IN), loop = -1) + + for(var/decl/status_condition/status in get_status_marker_decls()) + if(status.status_marker_icon && status.status_marker_state) + var/obj/status_marker/marker = new(null, status) + mob_image.add_vis_contents(marker) + LAZYSET(markers, status, marker) + marker = new(null, status) + mob_image_personal.add_vis_contents(marker) + LAZYSET(markers_personal, status, marker) + + global.status_marker_holders += src + for(var/client/C) + if(C.mob && C.get_preference_value(/datum/client_preference/show_status_markers) == PREF_SHOW) + if(C.mob.status_markers == src) + C.images |= mob_image_personal + else + C.images |= mob_image + +/datum/status_marker_holder/Destroy() + for(var/client/C) + C.images -= mob_image + C.images -= mob_image_personal + global.status_marker_holders -= src + if(mob_image) + mob_image.clear_vis_contents() + mob_image = null + if(mob_image_personal) + mob_image_personal.clear_vis_contents() + mob_image_personal = null + for(var/key in markers) + qdel(markers[key]) + markers = null + for(var/key in markers_personal) + qdel(markers_personal[key]) + markers_personal = null + . = ..() + +/datum/status_marker_holder/proc/apply_offsets(var/mob/owner, var/list/markers_to_check, var/check_show_status = TRUE) + var/list/visible_markers + for(var/decl/status_condition/stat as anything in markers_to_check) + if(HAS_STATUS(owner, stat.type) && (!check_show_status || stat.show_status(owner))) + LAZYADD(visible_markers, markers_to_check[stat]) + else + var/obj/marker = markers_to_check[stat] + if(marker.alpha != 0 || marker.pixel_z != 12) + animate(markers_to_check[stat], pixel_z = 12, alpha = 0, time = 3) + if(length(visible_markers)) + var/x_offset = 12 - round(((length(visible_markers)-1) * 5)) + var/y_offset = (world.icon_size - 4) + var/decl/bodytype/bodytype = owner.get_bodytype() + if(bodytype) + x_offset += bodytype.antaghud_offset_x + y_offset += bodytype.antaghud_offset_y + for(var/i = 1 to length(visible_markers)) + var/obj/marker = visible_markers[i] + var/new_x_offset = x_offset + ((i-1) * 10) + if(marker.pixel_w != new_x_offset || marker.pixel_z != y_offset || marker.alpha != 255) + if(marker.alpha == 0) // Avoid animating them popping over from the bottom left on initial appearance. + marker.pixel_w = new_x_offset + animate(marker, pixel_w = new_x_offset, alpha = 255, pixel_z = y_offset, time = 3) + +/datum/status_marker_holder/proc/refresh_markers(var/mob/owner) + if(!istype(owner) || QDELETED(owner)) + clear_markers() + else + apply_offsets(owner, markers, TRUE) + apply_offsets(owner, markers_personal, FALSE) diff --git a/code/modules/status_conditions/definitions/status_dizzy.dm b/code/modules/status_conditions/definitions/status_dizzy.dm new file mode 100644 index 000000000000..963773287ff4 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_dizzy.dm @@ -0,0 +1,22 @@ +/decl/status_condition/dizzy + name = "dizzy" + +/decl/status_condition/dizzy/handle_changed_amount(var/mob/living/victim, var/new_amount, var/last_amount) + . = ..() + if(new_amount <= 100) + return + var/victim_ref = weakref(victim) + if(LAZYACCESS(victim_data, victim_ref)) + return + LAZYSET(victim_data, victim_ref, TRUE) + var/dizziness = new_amount + while(dizziness > 100 && !QDELETED(victim) && victim.stat != DEAD && victim.client) + var/amplitude = dizziness*(sin(dizziness * 0.044 * world.time) + 1) / 70 + victim.client.pixel_x = amplitude * sin(0.008 * dizziness * world.time) + victim.client.pixel_y = amplitude * cos(0.008 * dizziness * world.time) + sleep(1) + dizziness = GET_STATUS(victim, type) + LAZYREMOVE(victim_data, victim_ref) + if(!QDELETED(victim) && victim.client) + victim.client.pixel_x = 0 + victim.client.pixel_y = 0 diff --git a/code/modules/status_conditions/definitions/status_jittery.dm b/code/modules/status_conditions/definitions/status_jittery.dm new file mode 100644 index 000000000000..04d8bb8946e1 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_jittery.dm @@ -0,0 +1,38 @@ +/decl/status_condition/jittery + name = "jittery" + +/decl/status_condition/jittery/handle_changed_amount(var/mob/living/victim, var/new_amount, var/last_amount) + . = ..() + if(new_amount <= 100) + return + var/weakref/victim_ref = weakref(victim) + if(LAZYACCESS(victim_data, victim_ref)) + return + LAZYSET(victim_data, victim_ref, TRUE) + var/jitteriness = new_amount + while(jitteriness > 100 && istype(victim) && !QDELETED(victim) && victim.stat != DEAD) + var/amplitude = min(4, jitteriness / 100) + victim.do_jitter(amplitude) + sleep(1) + jitteriness = GET_STATUS(victim, type) + if(victim_ref) + LAZYREMOVE(victim_data, victim_ref) + if(!QDELETED(victim)) + victim.do_jitter(0) + +/decl/status_condition/jittery/handle_status(var/mob/living/victim, var/amount) + . = ..() + var/jitteriness = amount + if(jitteriness >= 400) + var/obj/item/organ/internal/heart = GET_INTERNAL_ORGAN(victim, BP_HEART) + if(!heart || BP_IS_PROSTHETIC(heart)) + return + if(prob(5)) + if(prob(1)) + heart.take_damage(heart.max_damage / 2, 0) + to_chat(victim, SPAN_DANGER("Something bursts in your heart.")) + admin_victim_log(victim, "has taken lethal heart damage at jitteriness level [jitteriness].") + else + heart.take_damage(heart, 0) + to_chat(victim, SPAN_DANGER("The jitters are killing you! You feel your heart beating out of your chest.")) + admin_victim_log(victim, "has taken minor heart damage at jitteriness level [jitteriness].") diff --git a/code/modules/status_conditions/definitions/status_paralyzed.dm b/code/modules/status_conditions/definitions/status_paralyzed.dm new file mode 100644 index 000000000000..2187f2ba2b30 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_paralyzed.dm @@ -0,0 +1,3 @@ +/decl/status_condition/paralyzed + name = "paralyzed" + status_marker_state = "paralyzed" diff --git a/code/modules/status_conditions/definitions/status_sleeping.dm b/code/modules/status_conditions/definitions/status_sleeping.dm new file mode 100644 index 000000000000..83153f792b49 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_sleeping.dm @@ -0,0 +1,18 @@ +/decl/status_condition/sleeping + name = "asleep" + status_marker_state = "asleep" + +/decl/status_condition/sleeping/show_status(var/mob/owner) + return istype(owner) && owner.stat != DEAD + +/decl/status_condition/sleeping/handle_changed_amount(var/mob/living/victim, var/new_amount, var/last_amount) + . = ..() + victim.facing_dir = null + victim.update_posture() + victim.handle_dreams() + victim.get_species()?.handle_sleeping(victim) + +/decl/status_condition/sleeping/handle_status(mob/living/victim, var/amount) + . = ..() + victim.handle_dreams() + victim.get_species()?.handle_sleeping(victim) diff --git a/code/modules/status_conditions/definitions/status_stunned.dm b/code/modules/status_conditions/definitions/status_stunned.dm new file mode 100644 index 000000000000..44961792b91f --- /dev/null +++ b/code/modules/status_conditions/definitions/status_stunned.dm @@ -0,0 +1,16 @@ +/decl/status_condition/stunned + name = "stunned" + check_flags = CANSTUN + status_marker_state = "stunned" + +/decl/status_condition/stunned/check_can_set(var/mob/living/victim) + . = ..() && !victim.can_feel_pain() + +/decl/status_condition/stunned/handle_changed_amount(var/mob/living/victim, var/new_amount, var/last_amount) + . = ..() + victim.facing_dir = null + victim.update_posture() + +/decl/status_condition/stunned/handle_status(mob/living/victim, amount) + . = ..() + victim.update_posture() diff --git a/code/modules/status_conditions/definitions/status_weakened.dm b/code/modules/status_conditions/definitions/status_weakened.dm new file mode 100644 index 000000000000..d7ef5c45e7b3 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_weakened.dm @@ -0,0 +1,17 @@ +/decl/status_condition/weakened + name = "weakened" + check_flags = CANWEAKEN + status_marker_state = "weakened" + +/decl/status_condition/weakened/handle_changed_amount(var/mob/living/victim, var/new_amount, var/last_amount) + . = ..() + victim.facing_dir = null + if(victim.aiming) + victim.stop_aiming(no_message=1) + victim.update_posture() + +/decl/status_condition/weakened/handle_status(mob/living/victim, amount) + . = ..() + if(victim.aiming) + victim.stop_aiming(no_message=1) + victim.update_posture() diff --git a/code/modules/status_conditions/status_counters_simple.dm b/code/modules/status_conditions/status_counters_simple.dm new file mode 100644 index 000000000000..e4f294a97aa3 --- /dev/null +++ b/code/modules/status_conditions/status_counters_simple.dm @@ -0,0 +1,38 @@ +/decl/status_condition/silenced + name = "silenced" + status_marker_private = TRUE + status_marker_state = "silent" + +/decl/status_condition/drugged + name = "drugged" + status_marker_private = TRUE + status_marker_state = "drugged" + +/decl/status_condition/eye_blind + name = "blinded" + status_marker_private = TRUE + status_marker_state = "blind" + +/decl/status_condition/ear_deaf + name = "deafened" + status_marker_private = TRUE + status_marker_state = "deaf" + +/decl/status_condition/confused + name = "confused" + status_marker_state = "confused" + +/decl/status_condition/drowsy + name = "drowsy" + +/decl/status_condition/slurring + name = "slurring" + +/decl/status_condition/stuttering + name = "stuttering" + +/decl/status_condition/eye_blurry + name = "blurry eyes" + +/decl/status_condition/ear_damage + name = "damaged ears" diff --git a/code/modules/stressors/_stressor.dm b/code/modules/stressors/_stressor.dm new file mode 100644 index 000000000000..abc8970d3c46 --- /dev/null +++ b/code/modules/stressors/_stressor.dm @@ -0,0 +1,89 @@ +/* + * STRESSOR SYSTEM + * === + * This little blob of code is intended to represent a slew of minor health and wellbeing + * conditions that aren't otherwise covered by the sim. Generally it should be used to + * represent things that are too specific, niche or minor to really give a mechanical + * impact - you had a nutritious meal, you are lying on a comfortable bed, you've been + * shot at, your blood sugar is low. All these things (stressor datums) are summed up + * and give a value between -1 (maximum good) to 1 (maximum bad), which is then used in + * several places related to health recovery (wound regen, shock recovery, blood regen). + * + * The hoped-for outcome for this system is that it will encourage people to pursue RP + * actions (like eating food from the chef instead of vendor trash), and discourage them + * from doing RP actions that are somewhat nonsensical (like leaving surgery and immediately + * running straight back into combat). + * + * General dos and don'ts: + * - Don't use this for things that are better represented as mechanical status effects. + * - Don't use stress as a multiplier in places that would be better served by a more + * fleshed-out, specific system. + * - Don't go overboard with the impact of stress. It should be mild, not crippling. + * - Likewise don't make a crazy buff based on your stress level or lack thereof. + */ + +/datum/stressor + /// A name string, used solely for input(). + var/name + /// A short string shown in Check Stressors. + var/desc + /// A message shown when the stressor begins. + var/on_addition_message + /// A message shown when the stressor expires. + var/on_removal_message + /// Amount that this stressor will contribute to stress. + var/stress_value = 0 + /// A list of stressor IDs that will prevent this stressor being added if present. + var/list/incompatible_with_stressors + /// A list of stressor IDs that will be hidden/not counted while this stressor is present. + var/list/suppress_stressors + +/datum/stressor/ManagedInstanceInitialize() + for(var/stressor_id in incompatible_with_stressors) + incompatible_with_stressors += SSmanaged_instances.get(stressor_id, cache_category = /datum/stressor) + incompatible_with_stressors -= stressor_id + for(var/stressor_id in suppress_stressors) + suppress_stressors += SSmanaged_instances.get(stressor_id, cache_category = /datum/stressor) + suppress_stressors -= stressor_id + +/datum/stressor/Destroy(force) + if(force) // This will cause a hard del in the managed instance cache. + return ..() + return QDEL_HINT_LETMELIVE + +/datum/stressor/proc/tick(var/mob/living/owner) + var/expiry = LAZYACCESS(owner.stressors, src) + if(expiry != STRESSOR_DURATION_INDEFINITE && world.time >= expiry) + remove_from(owner) + return 0 + return stress_value + +/datum/stressor/proc/remove_from(var/mob/living/owner) + SHOULD_CALL_PARENT(TRUE) + if(on_removal_message) + to_chat(owner, on_removal_message) + LAZYREMOVE(owner.stressors, src) + owner.update_stress() + +/datum/stressor/proc/refresh(var/mob/living/owner, var/duration) + SHOULD_CALL_PARENT(TRUE) + if(!istype(owner) || !isnum(duration) || LAZYACCESS(owner.stressors, src) == duration) + return + LAZYINITLIST(owner.stressors) + if(duration == STRESSOR_DURATION_INDEFINITE) + owner.stressors[src] = STRESSOR_DURATION_INDEFINITE + else + owner.stressors[src] = max(owner.stressors[src], (world.time + duration)) + owner.update_stress() + +/datum/stressor/proc/add_to(var/mob/living/owner, var/duration) + SHOULD_CALL_PARENT(TRUE) + if(on_addition_message) + to_chat(owner, on_addition_message) + for(var/stressor in suppress_stressors) + LAZYREMOVE(owner.stressors, stressor) + if(duration == STRESSOR_DURATION_INDEFINITE) + LAZYSET(owner.stressors, src, STRESSOR_DURATION_INDEFINITE) + else + LAZYSET(owner.stressors, src, (world.time + duration)) + owner.update_stress() diff --git a/code/modules/stressors/stressor_definitions.dm b/code/modules/stressors/stressor_definitions.dm new file mode 100644 index 000000000000..d9c419236037 --- /dev/null +++ b/code/modules/stressors/stressor_definitions.dm @@ -0,0 +1,77 @@ +/datum/stressor/ate_cooked_food + name = "Ate Cooked Food" + desc = "well fed." + stress_value = -(STRESSOR_DEGREE_MILD) + +/datum/stressor/well_groomed + name = "Well Groomed" + desc = "neat and tidy." + stress_value = -(STRESSOR_DEGREE_MILD) + +/datum/stressor/ate_raw_food + name = "Ate Raw Food" + desc = "queasy from raw food." + stress_value = STRESSOR_DEGREE_MILD + +/datum/stressor/hungry + name = "Hungry" + desc = "hungry." + stress_value = STRESSOR_DEGREE_MILD + incompatible_with_stressors = list(/datum/stressor/hungry_very) + +/datum/stressor/hungry_very + name = "Starving" + desc = "starving." + stress_value = STRESSOR_DEGREE_MODERATE + suppress_stressors = list(/datum/stressor/hungry) + +/datum/stressor/thirsty + name = "Thirsty" + desc = "thirsty." + stress_value = STRESSOR_DEGREE_MILD + incompatible_with_stressors = list(/datum/stressor/thirsty_very) + +/datum/stressor/thirsty_very + name = "Dehydrated" + desc = "dehydrated." + stress_value = STRESSOR_DEGREE_MODERATE + suppress_stressors = list(/datum/stressor/thirsty) + +/datum/stressor/used_chems + name = "Used Chems" + desc = "recovering after the use of medication." + stress_value = STRESSOR_DEGREE_MODERATE + +/datum/stressor/comfortable + name = "Comfortable" + desc = "comfortable." + stress_value = -(STRESSOR_DEGREE_MILD) + incompatible_with_stressors = list(/datum/stressor/comfortable_very) + +/datum/stressor/comfortable_very + name = "Very Comfortable" + desc = "very comfortable." + stress_value = -(STRESSOR_DEGREE_MODERATE) + suppress_stressors = list(/datum/stressor/comfortable) + +/datum/stressor/uncomfortable + name = "Uncomfortable" + desc = "uncomfortable." + stress_value = STRESSOR_DEGREE_MILD + incompatible_with_stressors = list(/datum/stressor/uncomfortable_very) + +/datum/stressor/uncomfortable_very + name = "Very Uncomfortable" + desc = "very uncomfortable." + stress_value = STRESSOR_DEGREE_MODERATE + suppress_stressors = list(/datum/stressor/uncomfortable) + +/datum/stressor/well_rested + name = "Well Rested" + desc = "well rested." + stress_value = -(STRESSOR_DEGREE_MODERATE) + +/datum/stressor/fatigued + name = "Fatigued" + desc = "fatigued." + stress_value = STRESSOR_DEGREE_MODERATE diff --git a/code/modules/submaps/_submap.dm b/code/modules/submaps/_submap.dm index 609f6e3fdb44..93bad99848de 100644 --- a/code/modules/submaps/_submap.dm +++ b/code/modules/submaps/_submap.dm @@ -14,7 +14,6 @@ . = ..() /datum/submap/proc/setup_submap(var/decl/submap_archetype/_archetype) - if(!istype(_archetype)) testing( "Submap error - [name] - null or invalid archetype supplied ([_archetype]).") qdel(src) @@ -27,7 +26,7 @@ archetype = _archetype if(!pref_name) - pref_name = archetype.descriptor + pref_name = archetype.name testing("Starting submap setup - '[name]', [archetype], [associated_z]z.") @@ -41,45 +40,26 @@ job.blacklisted_species = archetype.blacklisted_species jobs[job.title] = job - // Either find or build our map. - if(!associated_z) - // Load a map + overmap object from archetype map file. - if(archetype.map && SSmapping.map_templates[archetype.map]) - var/datum/map_template/template = SSmapping.map_templates[archetype.map] - if (template.loaded && !(template.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES)) - testing( "Submap ([template.name]) tried to place duplicate of existing non-duplicate template.") - qdel(src) - return - var/turf/new_z_centre = template.load_new_z() - if(!istype(new_z_centre)) - testing( "Failed to place submap ([template.name])") - qdel(src) - return - testing( "Submap '[template.name]' placed on zlevel [new_z_centre.z].") - log_and_message_admins("Submap ([template.name]) has been placed on a new zlevel.", location=new_z_centre) - associated_z = new_z_centre.z - if(!associated_z) - testing( "Submap error - [name]/[archetype ? archetype.descriptor : "NO ARCHETYPE"] could not find an associated z-level for spawnpoint placement.") + testing( "Submap error - [name]/[archetype ? archetype.name : "NO ARCHETYPE"] could not find an associated z-level for spawnpoint registration.") qdel(src) return - var/obj/effect/overmap/visitable/cell = map_sectors["[associated_z]"] + var/obj/effect/overmap/visitable/cell = global.overmap_sectors[associated_z] if(istype(cell)) sync_cell(cell) // Add the spawn points to the appropriate job list. - var/added_spawnpoint - for(var/check_z in GetConnectedZlevels(associated_z)) - for(var/thing in block(locate(1, 1, check_z), locate(world.maxx, world.maxy, check_z))) - for(var/obj/effect/submap_landmark/spawnpoint/landmark in thing) - var/datum/job/submap/job = jobs[landmark.name] - if(istype(job)) - job.spawnpoints += landmark - added_spawnpoint = TRUE - - if(!added_spawnpoint) - testing( "Submap error - [name]/[archetype ? archetype.descriptor : "NO ARCHETYPE"] has no job spawn points.") + var/registered_spawnpoint + for(var/check_z in SSmapping.get_connected_levels(associated_z)) + for(var/obj/abstract/submap_landmark/spawnpoint/landmark in LAZYACCESS(global.submap_spawnpoints_by_z, "[check_z]")) + var/datum/job/submap/job = jobs[landmark.name] + if(istype(job)) + job.spawnpoints += landmark + registered_spawnpoint = TRUE + + if(!registered_spawnpoint) + testing( "Submap error - [name]/[archetype ? archetype.name : "NO ARCHETYPE"] has no job spawn points.") qdel(src) return diff --git a/code/modules/submaps/submap_archetype.dm b/code/modules/submaps/submap_archetype.dm index 44aa2a356369..9597b64f1f6f 100644 --- a/code/modules/submaps/submap_archetype.dm +++ b/code/modules/submaps/submap_archetype.dm @@ -1,28 +1,31 @@ /decl/submap_archetype - var/map - var/descriptor = "generic ship archetype" + // TODO: use UID instead of name for pref saving. + var/name = "generic ship archetype" var/list/whitelisted_species = list() var/list/blacklisted_species = list() var/call_webhook var/list/crew_jobs = list( /datum/job/submap ) + /// Used to order submaps on the occupation preference menu. + var/sort_priority = 0 + /// Whether the job preferences for this submap archetype are collapsed by default. + var/default_to_hidden = TRUE -/decl/submap_archetype/New() - if(islist(whitelisted_species) && !length(whitelisted_species)) - whitelisted_species |= SSmodpacks.default_submap_whitelisted_species - if(islist(blacklisted_species) && !length(blacklisted_species)) - blacklisted_species |= SSmodpacks.default_submap_blacklisted_species - ..() - -/decl/submap_archetype/Destroy() - if(SSmapping.submap_archetypes[descriptor] == src) - SSmapping.submap_archetypes -= descriptor +/decl/submap_archetype/validate() . = ..() + if(name) + var/static/list/submaps_by_name = list( (global.using_map.name) = global.using_map.type) + if(submaps_by_name[name]) + . += "name '[name]' ([type]) collides with submap type '[submaps_by_name[name]]'" + else + submaps_by_name[name] = type + else + . += "no name set" // Generic ships to populate the list. /decl/submap_archetype/derelict - descriptor = "drifting wreck" + name = "drifting wreck" /decl/submap_archetype/abandoned_ship - descriptor = "abandoned ship" + name = "abandoned ship" diff --git a/code/modules/submaps/submap_job.dm b/code/modules/submaps/submap_job.dm index 379e1ba09105..f7d72268f72a 100644 --- a/code/modules/submaps/submap_job.dm +++ b/code/modules/submaps/submap_job.dm @@ -6,12 +6,14 @@ announced = FALSE create_record = FALSE total_positions = 4 - outfit_type = /decl/hierarchy/outfit/job/assistant - hud_icon = "hudblank" + outfit_type = /decl/outfit/job/survivor + hud_icon_state = "hudblank" + hud_icon = null available_by_default = FALSE allowed_ranks = null allowed_branches = null skill_points = 25 + autoset_department = FALSE max_skill = list( SKILL_LITERACY = SKILL_MAX, SKILL_FINANCE = SKILL_MAX, @@ -44,6 +46,9 @@ var/list/blacklisted_species = list() var/list/whitelisted_species = list() +/decl/outfit/job/survivor + name = "Job - Survivor" + /datum/job/submap/New(var/datum/submap/_owner, var/abstract_job = FALSE) if(islist(whitelisted_species) && !length(whitelisted_species)) @@ -51,12 +56,17 @@ if(islist(blacklisted_species) && !length(blacklisted_species)) blacklisted_species |= SSmodpacks.default_submap_blacklisted_species - if(!abstract_job) + if(abstract_job) + if(!hud_icon) + hud_icon = global.using_map.hud_icons + if(!hud_icon_state) + hud_icon_state = "hud[ckey(title)]" + else spawnpoints = list() owner = _owner ..() -/datum/job/submap/is_species_allowed(var/datum/species/S) +/datum/job/submap/is_species_allowed(var/decl/species/S) if(LAZYLEN(whitelisted_species) && !(S.name in whitelisted_species)) return FALSE if(S.name in blacklisted_species) @@ -69,24 +79,31 @@ return TRUE /datum/job/submap/is_restricted(var/datum/preferences/prefs, var/feedback) - var/datum/species/S = get_species_by_key(prefs.species) - if(LAZYACCESS(minimum_character_age, S.get_root_species_name()) && (prefs.age < minimum_character_age[S.get_root_species_name()])) - to_chat(feedback, "Not old enough. Minimum character age is [minimum_character_age[S.get_root_species_name()]].") + var/decl/species/S = prefs.get_species_decl() + if(LAZYACCESS(minimum_character_age, S.uid) && (prefs.get_character_age() < minimum_character_age[S.uid])) + to_chat(feedback, "Not old enough. Minimum character age is [minimum_character_age[S.uid]].") return TRUE if(LAZYLEN(whitelisted_species) && !(prefs.species in whitelisted_species)) - to_chat(feedback, "Your current species, [prefs.species], is not permitted as [title] on \a [owner.archetype.descriptor].") + to_chat(feedback, "Your current species, [prefs.species], is not permitted as [title] on \a [owner.archetype.name].") return TRUE if(prefs.species in blacklisted_species) - to_chat(feedback, "Your current species, [prefs.species], is not permitted as [title] on \a [owner.archetype.descriptor].") + to_chat(feedback, "Your current species, [prefs.species], is not permitted as [title] on \a [owner.archetype.name].") return TRUE if(owner && owner.archetype) if(LAZYLEN(owner.archetype.whitelisted_species) && !(prefs.species in owner.archetype.whitelisted_species)) - to_chat(feedback, "Your current species, [prefs.species], is not permitted on \a [owner.archetype.descriptor].") + to_chat(feedback, "Your current species, [prefs.species], is not permitted on \a [owner.archetype.name].") return TRUE if(prefs.species in owner.archetype.blacklisted_species) - to_chat(feedback, "Your current species, [prefs.species], is not permitted on \a [owner.archetype.descriptor].") + to_chat(feedback, "Your current species, [prefs.species], is not permitted on \a [owner.archetype.name].") return TRUE return FALSE /datum/job/submap/check_is_active(var/mob/M) - . = (..() && M.faction == owner.name) \ No newline at end of file + . = (..() && M.faction == owner.name) + +/datum/job/submap/create_cash_on_hand(var/mob/living/human/H, var/datum/money_account/M) + . = get_total_starting_money(H) + if(. > 0) + var/obj/item/cash/cash = new + cash.adjust_worth(.) + H.equip_to_storage_or_put_in_hands(cash) diff --git a/code/modules/submaps/submap_join.dm b/code/modules/submaps/submap_join.dm index 6371e207570c..6698813bdd5e 100644 --- a/code/modules/submaps/submap_join.dm +++ b/code/modules/submaps/submap_join.dm @@ -29,10 +29,6 @@ to_chat(joining, SPAN_WARNING("You are banned from playing offstation roles.")) return FALSE - if(job.is_semi_antagonist && jobban_isbanned(joining, MODE_MISC_AGITATOR)) - to_chat(joining, SPAN_WARNING("You are banned from playing semi-antagonist roles.")) - return FALSE - if(job.is_restricted(joining.client.prefs, joining)) return FALSE @@ -47,17 +43,14 @@ to_chat(joining, "There are no available spawn points for that job.") var/turf/spawn_turf = get_turf(pick(job.spawnpoints)) - if(!SSjobs.check_unsafe_spawn(joining, spawn_turf)) + if(!job.no_warn_unsafe && !SSjobs.check_unsafe_spawn(joining, spawn_turf)) return // check_unsafe_spawn() has an input() call, check blockers again. if(!check_general_join_blockers(joining, job)) return - log_debug("Player: [joining] is now offsite rank: [job.title] ([name]), JCP:[job.current_positions], JPL:[job.total_positions]") - if(joining.mind) - joining.mind.assigned_job = job - joining.mind.assigned_role = job.title + log_debug("Player: [joining] is now offsite job: [job.title] ([name]), JCP:[job.current_positions], JPL:[job.total_positions]") joining.faction = name job.current_positions++ @@ -68,28 +61,30 @@ if(istype(other_mob)) character = other_mob - var/mob/living/carbon/human/user_human + var/mob/living/human/user_human if(ishuman(character)) user_human = character - if(job.branch && mil_branches) - user_human.char_branch = mil_branches.get_branch(job.branch) - user_human.char_rank = mil_branches.get_rank(job.branch, job.rank) + if(job.branch && (global.using_map.flags & MAP_HAS_BRANCH)) + user_human.char_branch = global.using_map.get_branch(job.branch) + user_human.char_rank = global.using_map.get_rank(job.branch, job.rank) // We need to make sure to use the abstract instance here; it's not the same as the one we were passed. character.skillset.obtain_from_client(SSjobs.get_by_path(job.type), character.client) - job.equip(character, "") + job.equip_job(character) job.apply_fingerprints(character) var/list/spawn_in_storage = SSjobs.equip_custom_loadout(character, job) if(spawn_in_storage) - for(var/datum/gear/G in spawn_in_storage) - G.spawn_in_storage_or_drop(user_human, user_human.client.prefs.Gear()[G.display_name]) + for(var/decl/loadout_option/gear in spawn_in_storage) + gear.spawn_in_storage_or_drop(user_human, user_human.client.prefs.Gear()[gear.uid]) SScustomitems.equip_custom_items(user_human) character.job = job.title - if(character.mind) - character.mind.assigned_job = job - character.mind.assigned_role = character.job + if(!character.mind) + character.mind_initialize() + character.mind.assigned_job = job + character.mind.assigned_role = character.job + job.create_cash_on_hand(character) to_chat(character, "You are [job.total_positions == 1 ? "the" : "a"] [job.title] of the [name].") if(job.supervisors) @@ -98,21 +93,24 @@ if(istype(ojob) && ojob.info) to_chat(character, ojob.info) - if(user_human && user_human.disabilities & NEARSIGHTED) - var/equipped = user_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/prescription(user_human), slot_glasses) + if(user_human && user_human.has_genetic_condition(GENE_COND_NEARSIGHTED)) // is this even necessary with the new aspects system? + var/equipped = user_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/prescription(user_human), slot_glasses_str) if(equipped) - var/obj/item/clothing/glasses/G = user_human.glasses - G.prescription = 7 + var/obj/item/clothing/glasses/glasses = user_human.get_equipped_item(slot_glasses_str) + if(istype(glasses)) + glasses.prescription = 7 BITSET(character.hud_updateflag, ID_HUD) BITSET(character.hud_updateflag, IMPLOYAL_HUD) BITSET(character.hud_updateflag, SPECIALROLE_HUD) SSticker.mode.handle_offsite_latejoin(character) - GLOB.universe.OnPlayerLatejoin(character) + global.universe.OnPlayerLatejoin(character) log_and_message_admins("has joined the round as offsite role [character.mind.assigned_role].", character) - if(character.cannot_stand()) equip_wheelchair(character) - job.post_equip_rank(character, job.title) + RAISE_EVENT(/decl/observ/submap_join, src, character, job) + if(character.cannot_stand()) + equip_wheelchair(character) + job.post_equip_job_title(character, job.title) qdel(joining) return character diff --git a/code/modules/submaps/submap_landmark.dm b/code/modules/submaps/submap_landmark.dm index a4dadcf49ced..7bf42c3fec04 100644 --- a/code/modules/submaps/submap_landmark.dm +++ b/code/modules/submaps/submap_landmark.dm @@ -1,22 +1,24 @@ -/obj/effect/submap_landmark - icon = 'icons/misc/mark.dmi' - invisibility = INVISIBILITY_MAXIMUM - anchored = TRUE - simulated = FALSE - density = FALSE - opacity = FALSE +/obj/abstract/submap_landmark + icon = 'icons/misc/mark.dmi' + invisibility = INVISIBILITY_MAXIMUM + anchored = TRUE + simulated = FALSE + density = FALSE + opacity = FALSE + abstract_type = /obj/abstract/submap_landmark + is_spawnable_type = FALSE -/obj/effect/submap_landmark/joinable_submap +/obj/abstract/submap_landmark/joinable_submap icon_state = "x4" var/archetype var/submap_datum_type = /datum/submap -/obj/effect/submap_landmark/joinable_submap/Initialize(var/mapload) +/obj/abstract/submap_landmark/joinable_submap/Initialize(var/mapload) . = ..(mapload) - if(!SSmapping.submaps[name] && SSmapping.submap_archetypes[archetype]) + if(!SSmapping.submaps[name] && ispath(archetype, /decl/submap_archetype)) var/datum/submap/submap = new submap_datum_type(z) submap.name = name - submap.setup_submap(SSmapping.submap_archetypes[archetype]) + submap.setup_submap(GET_DECL(archetype)) else if(SSmapping.submaps[name]) to_world_log( "Submap error - mapped landmark is duplicate of existing.") @@ -24,8 +26,19 @@ to_world_log( "Submap error - mapped landmark had invalid archetype.") return INITIALIZE_HINT_QDEL -/obj/effect/submap_landmark/spawnpoint +var/global/list/submap_spawnpoints_by_z = list() +INITIALIZE_IMMEDIATE(/obj/abstract/submap_landmark/spawnpoint) +/obj/abstract/submap_landmark/spawnpoint + movable_flags = MOVABLE_FLAG_ALWAYS_SHUTTLEMOVE icon_state = "x3" -/obj/effect/submap_landmark/spawnpoint/survivor +/obj/abstract/submap_landmark/spawnpoint/Initialize() + . = ..() + LAZYADD(global.submap_spawnpoints_by_z[num2text(z)], src) + +/obj/abstract/submap_landmark/spawnpoint/Destroy() + LAZYREMOVE(global.submap_spawnpoints_by_z[num2text(z)], src) + . = ..() + +/obj/abstract/submap_landmark/spawnpoint/survivor name = "Survivor" diff --git a/code/modules/supermatter/setup_supermatter.dm b/code/modules/supermatter/setup_supermatter.dm deleted file mode 100644 index 9b9f067f9d8a..000000000000 --- a/code/modules/supermatter/setup_supermatter.dm +++ /dev/null @@ -1,249 +0,0 @@ -#define SETUP_OK 1 // All good -#define SETUP_WARNING 2 // Something that shouldn't happen happened, but it's not critical so we will continue -#define SETUP_ERROR 3 // Something bad happened, and it's important so we won't continue setup. -#define SETUP_DELAYED 4 // Wait for other things first. - -#define ENERGY_NITROGEN 115 // Roughly 8 emitter shots. -#define ENERGY_CARBONDIOXIDE 150 // Roughly 10 emitter shots. -#define ENERGY_HYDROGEN 300 // Roughly 20 emitter shots. - -/datum/admins/proc/setup_supermatter() - set category = "Debug" - set name = "Setup Supermatter" - set desc = "Allows you to start the Supermatter engine." - - if (!istype(src,/datum/admins)) - src = usr.client.holder - if (!istype(src,/datum/admins)) - to_chat(usr, "Error: you are not an admin!") - return - - var/response = input(usr, "Are you sure? This will start up the engine with selected gas as coolant.", "Engine setup") as null|anything in list("N2", "CO2", "H2", "Abort") - if(!response || response == "Abort") - return - - var/errors = 0 - var/warnings = 0 - var/success = 0 - - log_and_message_admins("## SUPERMATTER SETUP - Setup initiated by [usr] using coolant type [response].") - - // CONFIGURATION PHASE - // Coolant canisters, set types according to response. - for(var/obj/effect/engine_setup/coolant_canister/C in world) - switch(response) - if("N2") - C.canister_type = /obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup/ - continue - if("CO2") - C.canister_type = /obj/machinery/portable_atmospherics/canister/carbon_dioxide/engine_setup/ - continue - if("H2") - C.canister_type = /obj/machinery/portable_atmospherics/canister/hydrogen/engine_setup/ - continue - - for(var/obj/effect/engine_setup/core/C in world) - switch(response) - if("N2") - C.energy_setting = ENERGY_NITROGEN - continue - if("CO2") - C.energy_setting = ENERGY_CARBONDIOXIDE - continue - if("H2") - C.energy_setting = ENERGY_HYDROGEN - continue - - for(var/obj/effect/engine_setup/filter/F in world) - F.coolant = response - - var/list/delayed_objects = list() - // SETUP PHASE - for(var/obj/effect/engine_setup/S in world) - var/result = S.activate(0) - switch(result) - if(SETUP_OK) - success++ - continue - if(SETUP_WARNING) - warnings++ - continue - if(SETUP_ERROR) - errors++ - log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.") - break - if(SETUP_DELAYED) - delayed_objects.Add(S) - continue - - if(!errors) - for(var/obj/effect/engine_setup/S in delayed_objects) - var/result = S.activate(1) - switch(result) - if(SETUP_OK) - success++ - continue - if(SETUP_WARNING) - warnings++ - continue - if(SETUP_ERROR) - errors++ - log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.") - break - - log_and_message_admins("## SUPERMATTER SETUP - Setup completed with [errors] errors, [warnings] warnings and [success] successful steps.") - - return - - - -/obj/effect/engine_setup/ - name = "Engine Setup Marker" - desc = "You shouldn't see this." - invisibility = 101 - anchored = 1 - density = 0 - icon = 'icons/mob/screen1.dmi' - icon_state = "x3" - -/obj/effect/engine_setup/proc/activate(var/last = 0) - return 1 - - - -// Tries to locate a pump, enables it, and sets it to MAX. Triggers warning if unable to locate a pump. -/obj/effect/engine_setup/pump_max/ - name = "Pump Setup Marker" - -/obj/effect/engine_setup/pump_max/activate() - ..() - var/obj/machinery/atmospherics/binary/pump/P = locate() in get_turf(src) - if(!P) - log_and_message_admins("## WARNING: Unable to locate pump at [x] [y] [z]!") - return SETUP_WARNING - P.target_pressure = P.max_pressure_setting - P.update_use_power(POWER_USE_IDLE) - P.update_icon() - return SETUP_OK - - - -// Spawns an empty canister on this turf, if it has a connector port. Triggers warning if unable to find a connector port -/obj/effect/engine_setup/empty_canister/ - name = "Empty Canister Marker" - -/obj/effect/engine_setup/empty_canister/activate() - ..() - var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src) - if(!P) - log_and_message_admins("## WARNING: Unable to locate connector port at [x] [y] [z]!") - return SETUP_WARNING - new/obj/machinery/portable_atmospherics/canister(get_turf(src)) // Canisters automatically connect to connectors in New() - return SETUP_OK - - - - -// Spawns a coolant canister on this turf, if it has a connector port. -// Triggers error when unable to locate connector port or when coolant canister type is unset. -/obj/effect/engine_setup/coolant_canister/ - name = "Coolant Canister Marker" - var/canister_type = null - -/obj/effect/engine_setup/coolant_canister/activate() - ..() - var/obj/machinery/atmospherics/portables_connector/P = locate() in get_turf(src) - if(!P) - log_and_message_admins("## ERROR: Unable to locate coolant connector port at [x] [y] [z]!") - return SETUP_ERROR - if(!canister_type) - log_and_message_admins("## ERROR: Canister type unset at [x] [y] [z]!") - return SETUP_ERROR - new canister_type(get_turf(src)) - return SETUP_OK - - - -// Energises the supermatter. Errors when unable to locate supermatter. -/obj/effect/engine_setup/core/ - name = "Supermatter Core Marker" - var/energy_setting = 0 - -/obj/effect/engine_setup/core/activate(var/last = 0) - if(!last) - return SETUP_DELAYED - ..() - var/obj/machinery/power/supermatter/SM = locate() in get_turf(src) - if(!SM) - log_and_message_admins("## ERROR: Unable to locate supermatter core at [x] [y] [z]!") - return SETUP_ERROR - if(!energy_setting) - log_and_message_admins("## ERROR: Energy setting unset at [x] [y] [z]!") - return SETUP_ERROR - SM.power = energy_setting - return SETUP_OK - - - -// Tries to enable the SMES on max input/output settings. With load balancing it should be fine as long as engine outputs at least ~500kW -/obj/effect/engine_setup/smes/ - name = "SMES Marker" - -/obj/effect/engine_setup/smes/activate() - ..() - var/obj/machinery/power/smes/S = locate() in get_turf(src) - if(!S) - log_and_message_admins("## WARNING: Unable to locate SMES unit at [x] [y] [z]!") - return SETUP_WARNING - S.input_attempt = 1 - S.output_attempt = 1 - S.input_level = S.input_level_max - S.output_level = S.output_level_max - S.update_icon() - return SETUP_OK - - - -// Sets up filters. This assumes filters are set to filter out CO2 back to the core loop by default! -/obj/effect/engine_setup/filter/ - name = "Omni Filter Marker" - var/coolant = null - -/obj/effect/engine_setup/filter/activate() - ..() - var/obj/machinery/atmospherics/omni/filter/F = locate() in get_turf(src) - if(!F) - log_and_message_admins("## WARNING: Unable to locate omni filter at [x] [y] [z]!") - return SETUP_WARNING - if(!coolant) - log_and_message_admins("## WARNING: No coolant type set at [x] [y] [z]!") - return SETUP_WARNING - - // Non-co2 coolant, adjust the filter's config first. - if(coolant != "CO2") - for(var/datum/omni_port/P in F.ports) - if(P.mode != ATM_CO2) - continue - else if(coolant == "N2") - P.mode = ATM_N2 - break - else if(coolant == "H2") - P.mode = ATM_H2 - break - else - log_and_message_admins("## WARNING: Inapropriate filter coolant type set at [x] [y] [z]!") - return SETUP_WARNING - F.rebuild_filtering_list() - - F.update_use_power(POWER_USE_IDLE) - F.update_icon() - return SETUP_OK - - -#undef SETUP_OK -#undef SETUP_WARNING -#undef SETUP_ERROR -#undef SETUP_DELAYED -#undef ENERGY_NITROGEN -#undef ENERGY_CARBONDIOXIDE -#undef ENERGY_HYDROGEN diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm deleted file mode 100644 index 62181bc056df..000000000000 --- a/code/modules/supermatter/supermatter.dm +++ /dev/null @@ -1,575 +0,0 @@ -/* - How to tweak the SM - - POWER_FACTOR directly controls how much power the SM puts out at a given level of excitation (power var). Making this lower means you have to work the SM harder to get the same amount of power. - CRITICAL_TEMPERATURE The temperature at which the SM starts taking damage. - - CHARGING_FACTOR Controls how much emitter shots excite the SM. - DAMAGE_RATE_LIMIT Controls the maximum rate at which the SM will take damage due to high temperatures. -*/ - -// Base variants are applied to everyone on the same Z level -// Range variants are applied on per-range basis: numbers here are on point blank, it scales with the map size (assumes square shaped Z levels) -#define DETONATION_RADS 40 -#define DETONATION_MOB_CONCUSSION 4 // Value that will be used for Weaken() for mobs. - -// Base amount of ticks for which a specific type of machine will be offline for. +- 20% added by RNG. -// This does pretty much the same thing as an electrical storm, it just affects the whole Z level instantly. -#define DETONATION_APC_OVERLOAD_PROB 10 // prob() of overloading an APC's lights. -#define DETONATION_SHUTDOWN_APC 120 // Regular APC. -#define DETONATION_SHUTDOWN_CRITAPC 10 // Critical APC. AI core and such. Considerably shorter as we don't want to kill the AI with a single blast. Still a nuisance. -#define DETONATION_SHUTDOWN_SMES 60 // SMES -#define DETONATION_SHUTDOWN_RNG_FACTOR 20 // RNG factor. Above shutdown times can be +- X%, where this setting is the percent. Do not set to 100 or more. -#define DETONATION_SOLAR_BREAK_CHANCE 60 // prob() of breaking solar arrays (this is per-panel, and only affects the Z level SM is on) - -#define WARNING_DELAY 20 //seconds between warnings. - -/obj/machinery/power/supermatter - name = "Supermatter" - desc = "A strangely translucent and iridescent crystal. You get headaches just from looking at it." - icon = 'icons/obj/engine.dmi' - icon_state = "darkmatter" - density = 1 - anchored = 0 - light_outer_range = 4 - - layer = ABOVE_OBJ_LAYER - - var/nitrogen_retardation_factor = 0.15 // Higher == N2 slows reaction more - var/thermal_release_modifier = 10000 // Higher == more heat released during reaction - var/product_release_modifier = 1500 // Higher == less product gas released by reaction - var/oxygen_release_modifier = 15000 // Higher == less oxygen released at high temperature/power - var/radiation_release_modifier = 2 // Higher == more radiation released with more power. - var/reaction_power_modifier = 1.1 // Higher == more overall power - - //Controls how much power is produced by each collector in range - this is the main parameter for tweaking SM balance, as it basically controls how the power variable relates to the rest of the game. - var/power_factor = 1.0 - var/decay_factor = 700 //Affects how fast the supermatter power decays - var/critical_temperature = 5000 //K - var/charging_factor = 0.05 - var/damage_rate_limit = 4.5 //damage rate cap at power = 300, scales linearly with power - - var/gasefficency = 0.25 - - var/base_icon_state = "darkmatter" - - var/damage = 0 - var/damage_archived = 0 - var/safe_alert = "Crystaline hyperstructure returning to safe operating levels." - var/safe_warned = 0 - var/public_alert = 0 //Stick to Engineering frequency except for big warnings when integrity bad - var/warning_point = 100 - var/warning_alert = "Danger! Crystal hyperstructure instability!" - var/emergency_point = 700 - var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT." - var/explosion_point = 1000 - - light_color = "#8a8a00" - var/warning_color = "#b8b800" - var/emergency_color = "#d9d900" - - var/grav_pulling = 0 - // Time in ticks between delamination ('exploding') and exploding (as in the actual boom) - var/pull_time = 300 - var/explosion_power = 9 - - var/emergency_issued = 0 - - // Time in 1/10th of seconds since the last sent warning - var/lastwarning = 0 - - // This stops spawning redundand explosions. Also incidentally makes supermatter unexplodable if set to 1. - var/exploded = 0 - - var/power = 0 - var/oxygen = 0 - - //Temporary values so that we can optimize this - //How much the bullets damage should be multiplied by when it is added to the internal variables - var/config_bullet_energy = 2 - //How much of the power is left after processing is finished? -// var/config_power_reduction_per_tick = 0.5 - //How much hallucination should it produce per unit of power? - var/config_hallucination_power = 0.1 - - var/debug = 0 - - var/disable_adminwarn = FALSE - - var/aw_normal = FALSE - var/aw_notify = FALSE - var/aw_warning = FALSE - var/aw_danger = FALSE - var/aw_emerg = FALSE - var/aw_delam = FALSE - var/aw_EPR = FALSE - - var/list/threshholds = list( // List of lists defining the amber/red labeling threshholds in readouts. Numbers are minminum red and amber and maximum amber and red, in that order - list("name" = SUPERMATTER_DATA_EER, "min_h" = -1, "min_l" = -1, "max_l" = 150, "max_h" = 300), - list("name" = SUPERMATTER_DATA_TEMPERATURE, "min_h" = -1, "min_l" = -1, "max_l" = 4000, "max_h" = 5000), - list("name" = SUPERMATTER_DATA_PRESSURE, "min_h" = -1, "min_l" = -1, "max_l" = 5000, "max_h" = 10000), - list("name" = SUPERMATTER_DATA_EPR, "min_h" = -1, "min_l" = 1.0, "max_l" = 2.5, "max_h" = 4.0) - ) - -/obj/machinery/power/supermatter/Initialize() - . = ..() - uid = gl_uid++ - -/obj/machinery/power/supermatter/proc/handle_admin_warnings() - if(disable_adminwarn) - return - - // Generic checks, similar to checks done by supermatter monitor program. - aw_normal = status_adminwarn_check(SUPERMATTER_NORMAL, aw_normal, "INFO: Supermatter crystal has been energised.", FALSE) - aw_notify = status_adminwarn_check(SUPERMATTER_NOTIFY, aw_notify, "INFO: Supermatter crystal is approaching unsafe operating temperature.", FALSE) - aw_warning = status_adminwarn_check(SUPERMATTER_WARNING, aw_warning, "WARN: Supermatter crystal is taking integrity damage!", FALSE) - aw_danger = status_adminwarn_check(SUPERMATTER_DANGER, aw_danger, "WARN: Supermatter integrity is below 50%!", TRUE) - aw_emerg = status_adminwarn_check(SUPERMATTER_EMERGENCY, aw_emerg, "CRIT: Supermatter integrity is below 25%!", FALSE) - aw_delam = status_adminwarn_check(SUPERMATTER_DELAMINATING, aw_delam, "CRIT: Supermatter is delaminating!", TRUE) - - // EPR check. Only runs when supermatter is energised. Triggers when there is very low amount of coolant in the core (less than one standard canister). - // This usually means a core breach or deliberate venting. - if(get_status() && (get_epr() < 0.5)) - if(!aw_EPR) - log_and_message_admins("WARN: Supermatter EPR value low. Possible core breach detected.") - aw_EPR = TRUE - else - aw_EPR = FALSE - -/obj/machinery/power/supermatter/proc/status_adminwarn_check(var/min_status, var/current_state, var/message, var/send_to_irc = FALSE) - var/status = get_status() - if(status >= min_status) - if(!current_state) - log_and_message_admins(message) - if(send_to_irc) - send2adminirc(message) - return TRUE - else - return FALSE - -/obj/machinery/power/supermatter/proc/get_epr() - var/turf/T = get_turf(src) - if(!istype(T)) - return - var/datum/gas_mixture/air = T.return_air() - if(!air) - return 0 - return round((air.total_moles / air.group_multiplier) / 23.1, 0.01) - -/obj/machinery/power/supermatter/proc/get_status() - var/turf/T = get_turf(src) - if(!T) - return SUPERMATTER_ERROR - var/datum/gas_mixture/air = T.return_air() - if(!air) - return SUPERMATTER_ERROR - - if(grav_pulling || exploded) - return SUPERMATTER_DELAMINATING - - if(get_integrity() < 25) - return SUPERMATTER_EMERGENCY - - if(get_integrity() < 50) - return SUPERMATTER_DANGER - - if((get_integrity() < 100) || (air.temperature > critical_temperature)) - return SUPERMATTER_WARNING - - if(air.temperature > (critical_temperature * 0.8)) - return SUPERMATTER_NOTIFY - - if(power > 5) - return SUPERMATTER_NORMAL - return SUPERMATTER_INACTIVE - - -/obj/machinery/power/supermatter/proc/explode() - set waitfor = 0 - - if(exploded) - return - - log_and_message_admins("Supermatter delaminating at [x] [y] [z]") - anchored = 1 - grav_pulling = 1 - exploded = 1 - sleep(pull_time) - var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, exosuit, or other container shouldn't block it's effects that way. - if(!istype(TS)) - return - - var/list/affected_z = GetConnectedZlevels(TS.z) - - // Effect 1: Radiation, weakening to all mobs on Z level - for(var/z in affected_z) - SSradiation.z_radiate(locate(1, 1, z), DETONATION_RADS, 1) - - for(var/mob/living/mob in GLOB.living_mob_list_) - var/turf/TM = get_turf(mob) - if(!TM) - continue - if(!(TM.z in affected_z)) - continue - - mob.Weaken(DETONATION_MOB_CONCUSSION) - to_chat(mob, "An invisible force slams you against the ground!") - - // Effect 2: Z-level wide electrical pulse - for(var/obj/machinery/power/apc/A in SSmachines.machinery) - if(!(A.z in affected_z)) - continue - - // Overloads lights - if(prob(DETONATION_APC_OVERLOAD_PROB)) - A.overload_lighting() - // Causes the APCs to go into system failure mode. - var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100 - if(A.is_critical) - A.energy_fail(round(DETONATION_SHUTDOWN_CRITAPC * random_change)) - else - A.energy_fail(round(DETONATION_SHUTDOWN_APC * random_change)) - - for(var/obj/machinery/power/smes/buildable/S in SSmachines.machinery) - if(!(S.z in affected_z)) - continue - // Causes SMESes to shut down for a bit - var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100 - S.energy_fail(round(DETONATION_SHUTDOWN_SMES * random_change)) - - // Effect 3: Break solar arrays - - for(var/obj/machinery/power/solar/S in SSmachines.machinery) - if(!(S.z in affected_z)) - continue - if(prob(DETONATION_SOLAR_BREAK_CHANCE)) - S.set_broken(TRUE) - - - - // Effect 4: Medium scale explosion - spawn(0) - explosion(TS, explosion_power/2, explosion_power, explosion_power * 2, explosion_power * 4, 1) - qdel(src) - -/obj/machinery/power/supermatter/examine(mob/user) - . = ..() - if(user.skill_check(SKILL_ENGINES, SKILL_EXPERT)) - var/integrity_message - switch(get_integrity()) - if(0 to 30) - integrity_message = "It looks highly unstable!" - if(31 to 70) - integrity_message = "It appears to be losing cohesion!" - else - integrity_message = "At a glance, it seems to be in sound shape." - to_chat(user, integrity_message) - if(user.skill_check(SKILL_ENGINES, SKILL_PROF)) - var/display_power = power - display_power *= (0.85 + 0.3 * rand()) - display_power = round(display_power, 20) - to_chat(user, "Eyeballing it, you place the relative EER at around [display_power] MeV/cm3.") - -//Changes color and luminosity of the light to these values if they were not already set -/obj/machinery/power/supermatter/proc/shift_light(var/lum, var/clr) - if(lum != light_outer_range || clr != light_color) - set_light(1, 0.1, lum, l_color = clr) - -/obj/machinery/power/supermatter/proc/get_integrity() - var/integrity = damage / explosion_point - integrity = round(100 - integrity * 100) - integrity = integrity < 0 ? 0 : integrity - return integrity - - -/obj/machinery/power/supermatter/proc/announce_warning() - var/integrity = get_integrity() - var/alert_msg = " Integrity at [integrity]%" - - if(damage > emergency_point) - alert_msg = emergency_alert + alert_msg - lastwarning = world.timeofday - WARNING_DELAY * 4 - else if(damage >= damage_archived) // The damage is still going up - safe_warned = 0 - alert_msg = warning_alert + alert_msg - lastwarning = world.timeofday - else if(!safe_warned) - safe_warned = 1 // We are safe, warn only once - alert_msg = safe_alert - lastwarning = world.timeofday - else - alert_msg = null - if(alert_msg) - GLOB.global_announcer.autosay(alert_msg, "Supermatter Monitor", "Engineering") - //Public alerts - if((damage > emergency_point) && !public_alert) - GLOB.global_announcer.autosay("WARNING: SUPERMATTER CRYSTAL DELAMINATION IMMINENT! SAFEROOMS UNBOLTED.", "Supermatter Monitor") - public_alert = 1 - GLOB.using_map.unbolt_saferooms() - for(var/mob/M in GLOB.player_list) - var/turf/T = get_turf(M) - if(T && (T.z in GLOB.using_map.station_levels) && !istype(M,/mob/new_player) && !isdeaf(M)) - sound_to(M, 'sound/ambience/matteralarm.ogg') - else if(safe_warned && public_alert) - GLOB.global_announcer.autosay(alert_msg, "Supermatter Monitor") - public_alert = 0 - - -/obj/machinery/power/supermatter/Process() - var/turf/L = loc - - if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity. - return PROCESS_KILL - - if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now. - return //Yeah just stop. - - if(damage > explosion_point) - if(!exploded) - if(!istype(L, /turf/space) && (L.z in GLOB.using_map.station_levels)) - announce_warning() - explode() - else if(damage > warning_point) // while the core is still damaged and it's still worth noting its status - shift_light(5, warning_color) - if(damage > emergency_point) - shift_light(7, emergency_color) - if(!istype(L, /turf/space) && ((world.timeofday - lastwarning) >= WARNING_DELAY * 10) && (L.z in GLOB.using_map.station_levels)) - announce_warning() - else - shift_light(4,initial(light_color)) - if(grav_pulling) - supermatter_pull(src) - - //Ok, get the air from the turf - var/datum/gas_mixture/removed = null - var/datum/gas_mixture/env = null - - //ensure that damage doesn't increase too quickly due to super high temperatures resulting from no coolant, for example. We dont want the SM exploding before anyone can react. - //We want the cap to scale linearly with power (and explosion_point). Let's aim for a cap of 5 at power = 300 (based on testing, equals roughly 5% per SM alert announcement). - var/damage_inc_limit = (power/300)*(explosion_point/1000)*damage_rate_limit - - if(!istype(L, /turf/space)) - env = L.return_air() - removed = env.remove(gasefficency * env.total_moles) //Remove gas from surrounding area - - if(!env || !removed || !removed.total_moles) - damage += max((power - 15*power_factor)/10, 0) - else if (grav_pulling) //If supermatter is detonating, remove all air from the zone - env.remove(env.total_moles) - else - damage_archived = damage - - damage = max(0, damage + between(-damage_rate_limit, (removed.temperature - critical_temperature) / 150, damage_inc_limit)) - - //Ok, 100% oxygen atmosphere = best reaction - //Maxes out at 100% oxygen pressure - oxygen = Clamp((removed.get_by_flag(XGM_GAS_OXIDIZER) - (removed.gas[/decl/material/gas/nitrogen] * nitrogen_retardation_factor)) / removed.total_moles, 0, 1) - - //calculate power gain for oxygen reaction - var/temp_factor - var/equilibrium_power - if (oxygen > 0.8) - //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 400 - equilibrium_power = 400 - icon_state = "[base_icon_state]_glow" - else - //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 250 - equilibrium_power = 250 - icon_state = base_icon_state - - temp_factor = ( (equilibrium_power/decay_factor)**3 )/800 - power = max( (removed.temperature * temp_factor) * oxygen + power, 0) - - var/device_energy = power * reaction_power_modifier - - //Release reaction gasses - var/heat_capacity = removed.heat_capacity() - removed.adjust_multi(/decl/material/solid/exotic_matter, max(device_energy / product_release_modifier, 0), \ - /decl/material/gas/oxygen, max((device_energy + removed.temperature - T0C) / oxygen_release_modifier, 0)) - - var/thermal_power = thermal_release_modifier * device_energy - if (debug) - var/heat_capacity_new = removed.heat_capacity() - visible_message("[src]: Releasing [round(thermal_power)] W.") - visible_message("[src]: Releasing additional [round((heat_capacity_new - heat_capacity)*removed.temperature)] W with exhaust gasses.") - - removed.add_thermal_energy(thermal_power) - removed.temperature = between(0, removed.temperature, 10000) - - env.merge(removed) - - for(var/mob/living/carbon/human/subject in view(src, min(7, round(sqrt(power/6))))) - var/obj/item/organ/internal/eyes/eyes = subject.internal_organs_by_name[BP_EYES] - if (!eyes) - continue - if (BP_IS_PROSTHETIC(eyes)) - continue - if(subject.has_meson_effect()) - continue - var/effect = max(0, min(200, power * config_hallucination_power * sqrt( 1 / max(1,get_dist(subject, src)))) ) - subject.adjust_hallucination(effect, 0.25 * effect) - - - SSradiation.radiate(src, power * radiation_release_modifier) //Better close those shutters! - power -= (power/decay_factor)**3 //energy losses due to radiation - handle_admin_warnings() - - return 1 - - -/obj/machinery/power/supermatter/bullet_act(var/obj/item/projectile/Proj) - var/turf/L = loc - if(!istype(L)) // We don't run process() when we are in space - return 0 // This stops people from being able to really power up the supermatter - // Then bring it inside to explode instantly upon landing on a valid turf. - - - var/proj_damage = Proj.get_structure_damage() - if(istype(Proj, /obj/item/projectile/beam)) - power += proj_damage * config_bullet_energy * charging_factor / power_factor - else - damage += proj_damage * config_bullet_energy - return 0 - -/obj/machinery/power/supermatter/attack_robot(mob/user) - if(Adjacent(user)) - return attack_hand(user) - else - ui_interact(user) - return - -/obj/machinery/power/supermatter/attack_ai(mob/user) - ui_interact(user) - -/obj/machinery/power/supermatter/attack_ghost(mob/user) - ui_interact(user) - -/obj/machinery/power/supermatter/attack_hand(mob/user) - user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\ - "You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"",\ - "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") - - Consume(user) - -// This is purely informational UI that may be accessed by AIs or robots -/obj/machinery/power/supermatter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data["integrity_percentage"] = round(get_integrity()) - var/datum/gas_mixture/env = null - var/turf/T = get_turf(src) - - if(istype(T)) - env = T.return_air() - - if(!env) - data["ambient_temp"] = 0 - data["ambient_pressure"] = 0 - else - data["ambient_temp"] = round(env.temperature) - data["ambient_pressure"] = round(env.return_pressure()) - data["detonating"] = grav_pulling - data["energy"] = power - - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "supermatter_crystal.tmpl", "Supermatter Crystal", 500, 300) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - -/obj/machinery/power/supermatter/attackby(obj/item/W, mob/living/user) - if(istype(W, /obj/item/tape_roll)) - to_chat(user, "You repair some of the damage to \the [src] with \the [W].") - damage = max(damage -10, 0) - - user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\ - "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\ - "Everything suddenly goes silent.") - - user.drop_from_inventory(W) - Consume(W) - - user.apply_damage(150, IRRADIATE, damage_flags = DAM_DISPERSED) - - -/obj/machinery/power/supermatter/Bumped(atom/AM) - if(istype(AM, /obj/effect)) - return - if(istype(AM, /mob/living)) - AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\ - "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ - "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") - else if(!grav_pulling) //To prevent spam, detonating supermatter does not indicate non-mobs being destroyed - AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\ - "You hear a loud crack as you are washed with a wave of heat.") - - Consume(AM) - - -/obj/machinery/power/supermatter/proc/Consume(var/mob/living/user) - if(istype(user)) - user.dust() - power += 200 - else - qdel(user) - - power += 200 - - //Some poor sod got eaten, go ahead and irradiate people nearby. - for(var/mob/living/l in range(10)) - if(l in view()) - l.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\ - "The unearthly ringing subsides and you notice you have new radiation burns.", 2) - else - l.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2) - var/rads = 500 - SSradiation.radiate(src, rads) - - -/proc/supermatter_pull(var/atom/target, var/pull_range = 255, var/pull_power = STAGE_FIVE) - for(var/atom/A in range(pull_range, target)) - A.singularity_pull(target, pull_power) - -/obj/machinery/power/supermatter/GotoAirflowDest(n) //Supermatter not pushed around by airflow - return - -/obj/machinery/power/supermatter/RepelAirflowDest(n) - return - -/obj/machinery/power/supermatter/explosion_act(var/severity) - . = ..() - if(.) - power *= max(1, 5 - severity) - log_and_message_admins("WARN: Explosion near the Supermatter! New EER: [power].") - -/obj/machinery/power/supermatter/get_artifact_scan_data() - return "Superdense crystalline structure - appears to have been shaped or hewn, lattice is approximately 20 times denser than should be possible." - -/obj/machinery/power/supermatter/shard //Small subtype, less efficient and more sensitive, but less boom. - name = "Supermatter Shard" - desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. You get headaches just from looking at it." - icon_state = "darkmatter_shard" - base_icon_state = "darkmatter_shard" - - warning_point = 50 - emergency_point = 400 - explosion_point = 600 - - gasefficency = 0.125 - - pull_time = 150 - explosion_power = 3 - -/obj/machinery/power/supermatter/shard/announce_warning() //Shards don't get announcements - return - -#undef DETONATION_MOB_CONCUSSION -#undef DETONATION_APC_OVERLOAD_PROB -#undef DETONATION_SHUTDOWN_APC -#undef DETONATION_SHUTDOWN_CRITAPC -#undef DETONATION_SHUTDOWN_SMES -#undef DETONATION_SHUTDOWN_RNG_FACTOR -#undef DETONATION_SOLAR_BREAK_CHANCE -#undef WARNING_DELAY diff --git a/code/modules/surgery/_surgery.dm b/code/modules/surgery/_surgery.dm index 41148ccddb9a..97ac4fe1e6c1 100644 --- a/code/modules/surgery/_surgery.dm +++ b/code/modules/surgery/_surgery.dm @@ -1,83 +1,132 @@ -// A list of types that will not attempt to perform surgery if the user is on help intent. -GLOBAL_LIST_INIT(surgery_tool_exceptions, list( +var/global/list/surgeries_in_progress = list() + +// A list of types that will continue to call use_on_mob() if they fail to find an appropriate surgical procedure. +var/global/list/surgery_tool_exceptions = list( + // Organic repair: /obj/item/auto_cpr, /obj/item/scanner/health, + /obj/item/scanner/breath, /obj/item/shockpaddles, /obj/item/chems/hypospray, - /obj/item/modular_computer, + /obj/item/chems/inhaler, /obj/item/chems/syringe, - /obj/item/chems/borghypo -)) -GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) + /obj/item/chems/borghypo, + // Cyborg repair: + /obj/item/robotanalyzer, + /obj/item/weldingtool, + /obj/item/stack/cable_coil, + // Modular computer functions like scanners: + /obj/item/modular_computer, +) +var/global/list/surgery_tool_exception_cache = list() /* SURGERY STEPS */ /decl/surgery_step + abstract_type = /decl/surgery_step + /// An identifying name string. var/name - var/description = "A mysterious surgical procedure." - var/list/allowed_tools // type path referencing tools that can be used for this step, and how well are they suited for it - var/list/allowed_species // type paths referencing races that this step applies to. - var/list/disallowed_species // type paths referencing races that this step applies to. - var/min_duration = 0 // duration of the step - var/max_duration = 0 // duration of the step - var/can_infect = 0 // evil infection stuff that will make everyone hate me - var/blood_level = 0 // How much blood this step can get on surgeon. 1 - hands, 2 - full body. - var/shock_level = 0 // what shock level will this step put patient on - var/delicate = 0 // if this step NEEDS stable optable or can be done on any valid surface with no penalty - var/surgery_candidate_flags = 0 // Various bitflags for requirements of the surgery. - var/strict_access_requirement = TRUE // Whether or not this surgery will be fuzzy on size requirements. - var/hidden_from_codex // Is this surgery a secret? + /// An informative description string. + var/description + /// type path referencing tools that can be used for this step, and how well are they suited for it + var/list/allowed_tools + /// type paths referencing races that this step applies to. + var/list/allowed_species + /// type paths referencing races that this step applies to. + var/list/disallowed_species + /// duration of the step + var/min_duration = 0 + /// duration of the step + var/max_duration = 0 + /// evil infection stuff that will make everyone hate me + var/can_infect = 0 + /// How much blood this step can get on surgeon. 1 - hands, 2 - full body. + var/blood_level = 0 + /// what shock level will this step put patient on + var/shock_level = 0 + /// if this step NEEDS stable optable or can be done on any valid surface with no penalty + var/delicate = 0 + /// Various bitflags for requirements of the surgery. + var/surgery_candidate_flags = 0 + /// Whether or not this surgery will be fuzzy on size requirements. + var/strict_access_requirement = TRUE + /// Is this surgery a secret? + var/hidden_from_codex + /// Any additional information to add to the codex entry for this step. var/list/additional_codex_lines + /// What mob type does this surgery apply to. + var/expected_mob_type = /mob/living/human + /// Sound (or list of sounds) to play on end step. + var/end_step_sound = "rustle" + /// Sound (or list of sounds) to play on fail step. + var/fail_step_sound + /// Sound (or list of sounds) to play on begin step. + var/begin_step_sound = "rustle" + +/decl/surgery_step/proc/is_self_surgery_permitted(var/mob/target, var/bodypart) + return TRUE + +/decl/surgery_step/validate() + . = ..() + if (!description) + . += "Missing description" + else if (!istext(description)) + . += "Non-text description" + +//returns how fast the tool is for this step +/decl/surgery_step/proc/get_speed_modifier(var/mob/user, var/mob/target, var/obj/item/tool) + for(var/T in allowed_tools) + if(ispath(T, /decl/tool_archetype) && tool.get_tool_quality(T) > 0) + if(isnull(.)) + . = tool.get_tool_speed(T) + else + . = min(. , tool.get_tool_speed(T)) + if(isnull(.)) + . = 1 //returns how well tool is suited for this step /decl/surgery_step/proc/tool_quality(obj/item/tool) - for (var/T in allowed_tools) - if (istype(tool,T)) + . = 0 + for(var/T in allowed_tools) + if(istype(tool,T)) return allowed_tools[T] - return 0 + if(ispath(T, /decl/tool_archetype)) + . = max((. || 0), allowed_tools[T] * tool.get_tool_quality(T)) -/decl/surgery_step/proc/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/proc/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) return TRUE // Checks if this step applies to the user mob at all -/decl/surgery_step/proc/is_valid_target(mob/living/carbon/human/target) - if(!hasorgans(target)) - return 0 - - if(allowed_species) - for(var/species in allowed_species) - if(target.species.get_root_species_name(target) == species) - return 1 - - if(disallowed_species) - for(var/species in disallowed_species) - if(target.species.get_root_species_name(target) == species) - return 0 - - return 1 +/decl/surgery_step/proc/is_valid_target(mob/living/target) + . = ((!expected_mob_type || istype(target, expected_mob_type)) && isliving(target)) + if(.) + var/decl/species/species = target.get_species() + if(allowed_species) + . = FALSE + if(species) + for(var/species_uid in allowed_species) + if(species.uid == species_uid) + return TRUE + if(species && disallowed_species) + for(var/species_uid in disallowed_species) + if(species.uid == species_uid) + return FALSE -/decl/surgery_step/proc/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool, target_zone) +/decl/surgery_step/proc/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool, target_zone) if(delicate) return SURGERY_SKILLS_DELICATE - else - return SURGERY_SKILLS_GENERIC + return SURGERY_SKILLS_GENERIC // checks whether this step can be applied with the given user and target -/decl/surgery_step/proc/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/proc/can_use(mob/living/user, mob/living/target, target_zone, obj/item/tool) return assess_bodypart(user, target, target_zone, tool) && assess_surgery_candidate(user, target, target_zone, tool) -/decl/surgery_step/proc/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(istype(target) && target_zone) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/proc/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) + if(ishuman(target) && target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) - // Check if clothing is blocking access - var/obj/item/I = target.get_covering_equipped_item_by_zone(target_zone) - if(I && (I.item_flags & ITEM_FLAG_THICKMATERIAL)) - to_chat(user,SPAN_NOTICE("The material covering this area is too thick for you to do surgery through!")) - return FALSE // Check various conditional flags. if(((surgery_candidate_flags & SURGERY_NO_ROBOTIC) && BP_IS_PROSTHETIC(affected)) || \ ((surgery_candidate_flags & SURGERY_NO_CRYSTAL) && BP_IS_CRYSTAL(affected)) || \ - ((surgery_candidate_flags & SURGERY_NO_STUMP) && affected.is_stump()) || \ ((surgery_candidate_flags & SURGERY_NO_FLESH) && !(BP_IS_PROSTHETIC(affected) || BP_IS_CRYSTAL(affected)))) return FALSE // Check if the surgery target is accessible. @@ -98,35 +147,49 @@ GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) if(open_threshold && ((strict_access_requirement && affected.how_open() != open_threshold) || \ affected.how_open() < open_threshold)) return FALSE + // Check if clothing is blocking access + var/obj/item/I = target.get_covering_equipped_item_by_zone(target_zone) + if(I && (I.item_flags & ITEM_FLAG_THICKMATERIAL)) + to_chat(user,SPAN_NOTICE("\The [I] covering that area is too thick for you to do surgery through!")) + return FALSE return affected return FALSE -/decl/surgery_step/proc/assess_surgery_candidate(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/proc/assess_surgery_candidate(mob/living/user, mob/living/target, target_zone, obj/item/tool) return ishuman(target) // does stuff to begin the step, usually just printing messages. Moved germs transfering and bloodying here too -/decl/surgery_step/proc/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/proc/begin_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + SHOULD_CALL_PARENT(TRUE) + if(begin_step_sound) + playsound(target, pick(begin_step_sound), 15, 1) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if (can_infect && affected) spread_germs_to_organ(affected, user) if(ishuman(user) && prob(60)) - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user if (blood_level) - H.bloody_hands(target,0) + H.bloody_hands(target,2) if (blood_level > 1) - H.bloody_body(target,0) - if(shock_level) - target.shock_stage = max(target.shock_stage, shock_level) + H.bloody_body(target,2) + if(shock_level && ishuman(target)) + var/mob/living/human/H = target + H.shock_stage = max(H.shock_stage, shock_level) // does stuff to end the step, which is normally print a message + do whatever this step changes -/decl/surgery_step/proc/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return +/decl/surgery_step/proc/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + SHOULD_CALL_PARENT(TRUE) + if(end_step_sound) + playsound(target, pick(end_step_sound), 15, 1) // stuff that happens when the step fails -/decl/surgery_step/proc/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/proc/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + SHOULD_CALL_PARENT(TRUE) + if(fail_step_sound) + playsound(target, pick(fail_step_sound), 15, 1) return null -/decl/surgery_step/proc/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool, target_zone) +/decl/surgery_step/proc/success_chance(mob/living/user, mob/living/target, obj/item/tool, target_zone) . = tool_quality(tool) if(user == target) . -= 10 @@ -139,47 +202,60 @@ GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) . += 20 if(ishuman(user)) - var/mob/living/carbon/human/H = user + var/mob/living/human/H = user . -= round(H.shock_stage * 0.5) - if(H.eye_blurry) + if(GET_STATUS(H, STAT_BLURRY)) . -= 20 - if(H.eye_blind) + if(GET_STATUS(H, STAT_BLIND)) . -= 60 if(delicate) - if(user.slurring) + if(HAS_STATUS(user, STAT_SLUR)) . -= 10 - if(!target.lying) + if(!target.current_posture.prone) . -= 30 - var/turf/T = get_turf(target) - if(locate(/obj/machinery/optable, T)) - . -= 0 - else if(locate(/obj/structure/bed, T)) - . -= 5 - else if(locate(/obj/structure/table, T)) - . -= 10 - else if(locate(/obj/effect/rune/, T)) - . -= 10 + var/turf/T = get_turf(target) + for(var/obj/interfering in T) + . += interfering.get_surgery_success_modifier(delicate) . = max(., 0) -/proc/spread_germs_to_organ(var/obj/item/organ/external/E, var/mob/living/carbon/human/user) +/obj/proc/get_surgery_success_modifier(delicate) + return 0 + +/proc/spread_germs_to_organ(var/obj/item/organ/external/E, var/mob/living/human/user) if(!istype(user) || !istype(E)) return var/germ_level = user.germ_level - if(user.gloves) - germ_level = user.gloves.germ_level + var/obj/item/gloves = user.get_equipped_item(slot_gloves_str) + if(gloves) + germ_level = gloves.germ_level E.germ_level = max(germ_level,E.germ_level) //as funny as scrubbing microbes out with clean gloves is - no. -/obj/item/proc/do_surgery(mob/living/carbon/M, mob/living/user, fuckup_prob) + +/obj/item/proc/do_surgery(mob/living/M, mob/living/user, fuckup_prob) // Check for the Hippocratic oath. - if(!istype(M) || user.a_intent == I_HURT) + if(!istype(M) || !istype(user) || user.check_intent(I_FLAG_HARM)) return FALSE // Check for multi-surgery drifting. - var/zone = user.zone_sel.selecting - if(LAZYACCESS(M.surgeries_in_progress, zone)) + var/zone = user.get_target_zone() + if(!zone) + return FALSE // Erroneous mob interaction + + // there IS a rule that says dogs can't do surgery, actually. section 13a, the "No Dr. Air Bud" Rule + if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS)) + return TRUE // prevent other interactions because we've shown a message + + var/decl/bodytype/root_bodytype = M.get_bodytype() + if(root_bodytype && length(LAZYACCESS(root_bodytype.limb_mapping, zone)) > 1) + zone = input("Which bodypart do you wish to operate on?", "Non-standard surgery") as null|anything in root_bodytype.limb_mapping[zone] + if(!zone) + return FALSE + + var/operation_ref = "\ref[M]" + if(zone in global.surgeries_in_progress[operation_ref]) to_chat(user, SPAN_WARNING("You can't operate on this area while surgery is already in progress.")) return TRUE @@ -188,13 +264,13 @@ GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) var/list/all_surgeries = decls_repository.get_decls_of_subtype(/decl/surgery_step) for(var/decl in all_surgeries) var/decl/surgery_step/S = all_surgeries[decl] - if(S.name && S.tool_quality(src) && S.can_use(user, M, zone, src)) - + if(S.tool_quality(src) && S.can_use(user, M, zone, src) && (M != user || S.is_self_surgery_permitted(M, zone))) var/image/radial_button = image(icon = icon, icon_state = icon_state) radial_button.name = S.name LAZYSET(possible_surgeries, S, radial_button) // Which surgery, if any, do we actually want to do? + var/cancelled_surgery = FALSE var/decl/surgery_step/S if(LAZYLEN(possible_surgeries) == 1) S = possible_surgeries[1] @@ -202,48 +278,56 @@ GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) if(!user.client) // In case of future autodocs. S = possible_surgeries[1] else - S = show_radial_menu(user, M, possible_surgeries, radius = 42, use_labels = TRUE, require_near = TRUE, check_locs = list(src)) + S = show_radial_menu(user, M, possible_surgeries, radius = 42, use_labels = RADIAL_LABELS_OFFSET, require_near = TRUE, check_locs = list(src)) + if(isnull(S)) + cancelled_surgery = TRUE if(S && !user.skill_check_multiple(S.get_skill_reqs(user, M, src, zone))) S = pick(possible_surgeries) // We didn't find a surgery, or decided not to perform one. if(!istype(S)) + + // If they cancelled, do not continue at all! + if(cancelled_surgery) + return TRUE + // If we're on an optable, we are protected from some surgery fails. Bypass this for some items (like health analyzers). - if((locate(/obj/machinery/optable) in get_turf(M)) && user.a_intent == I_HELP) + if((locate(/obj/machinery/optable) in get_turf(M)) && user.check_intent(I_FLAG_HELP)) // Keep track of which tools we know aren't appropriate for surgery on help intent. - if(GLOB.surgery_tool_exception_cache[type]) + if(global.surgery_tool_exception_cache[type]) return FALSE - for(var/tool in GLOB.surgery_tool_exceptions) + for(var/tool in global.surgery_tool_exceptions) if(istype(src, tool)) - GLOB.surgery_tool_exception_cache[type] = TRUE + global.surgery_tool_exception_cache[type] = TRUE return FALSE to_chat(user, SPAN_WARNING("You aren't sure what you could do to \the [M] with \the [src].")) return TRUE // Otherwise we can make a start on surgery! - else if(istype(M) && !QDELETED(M) && user.a_intent != I_HURT && user.get_active_hand() == src) + else if(istype(M) && !QDELETED(M) && !user.check_intent(I_FLAG_HARM) && user.get_active_held_item() == src) // Double-check this in case it changed between initial check and now. - if(zone in M.surgeries_in_progress) + if(zone in global.surgeries_in_progress[operation_ref]) to_chat(user, SPAN_WARNING("You can't operate on this area while surgery is already in progress.")) else if(S.can_use(user, M, zone, src) && S.is_valid_target(M)) var/operation_data = S.pre_surgery_step(user, M, zone, src) if(operation_data) - LAZYSET(M.surgeries_in_progress, zone, operation_data) - S.begin_step(user, M, zone, src) - var/skill_reqs = S.get_skill_reqs(user, M, src, zone) - var/duration = user.skill_delay_mult(skill_reqs[1]) * rand(S.min_duration, S.max_duration) - if(prob(S.success_chance(user, M, src, zone)) && do_mob(user, M, duration)) - S.end_step(user, M, zone, src) - handle_post_surgery() - else if ((src in user.contents) && user.Adjacent(M)) - S.fail_step(user, M, zone, src) - else - to_chat(user, SPAN_WARNING("You must remain close to your patient to conduct surgery.")) + LAZYSET(global.surgeries_in_progress[operation_ref], zone, operation_data) + try + S.begin_step(user, M, zone, src) + var/skill_reqs = S.get_skill_reqs(user, M, src, zone) + var/duration = max(1, round(user.skill_delay_mult(skill_reqs[1]) * rand(S.min_duration, S.max_duration) * S.get_speed_modifier(user, M, src))) + if(prob(S.success_chance(user, M, src, zone)) && do_mob(user, M, duration)) + S.end_step(user, M, zone, src) + handle_post_surgery() + else if ((src in user.contents) && user.Adjacent(M)) + S.fail_step(user, M, zone, src) + else + to_chat(user, SPAN_WARNING("You must remain close to your patient to conduct surgery.")) + catch(var/exception/E) + to_world_log("Exception during surgery: [E]") if(!QDELETED(M)) - LAZYREMOVE(M.surgeries_in_progress, zone) // Clear the in-progress flag. - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.update_surgery() + M.update_surgery() + LAZYREMOVE(global.surgeries_in_progress[operation_ref], zone) // Clear the in-progress flag. return TRUE return FALSE @@ -253,26 +337,19 @@ GLOBAL_LIST_INIT(surgery_tool_exception_cache, new) /obj/item/stack/handle_post_surgery() use(1) +/obj/proc/get_surgery_surface_quality(mob/living/victim) + return OPERATE_DENY + //check if mob is lying down on something we can operate him on. -/proc/can_operate(mob/living/carbon/M, mob/living/carbon/user) - var/turf/T = get_turf(M) - if(locate(/obj/machinery/optable, T)) - . = TRUE - if(locate(/obj/structure/bed, T)) - . = TRUE - if(locate(/obj/structure/table, T)) - . = TRUE - if(locate(/obj/effect/rune/, T)) - . = TRUE - - if(M == user) - var/hitzone = check_zone(user.zone_sel.selecting) - var/list/badzones = list(BP_HEAD) - if(user.hand) - badzones += BP_L_ARM - badzones += BP_L_HAND - else - badzones += BP_R_ARM - badzones += BP_R_HAND - if(hitzone in badzones) - return FALSE +/proc/can_operate(mob/living/victim, mob/living/user) + var/turf/T = get_turf(victim) + for(var/obj/surface in T) + . = max(., surface.get_surgery_surface_quality(victim, user)) + if(. != OPERATE_DENY && victim == user) + var/hitzone = check_zone(user.get_target_zone(), victim) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(victim, victim.get_active_held_item_slot()) + // TODO: write some generalized helper for this that handles single-organ limbs, more-than-two-organ limbs, etc + if(E && (E.organ_tag == hitzone || E.parent_organ == hitzone)) + to_chat(user, SPAN_WARNING("You can't operate on the same arm you're using to hold the surgical tool!")) + return OPERATE_DENY + . = min(., OPERATE_OKAY) // it's awkward no matter what diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm index 83c9d52c870f..e6bc246c0f13 100644 --- a/code/modules/surgery/bones.dm +++ b/code/modules/surgery/bones.dm @@ -4,10 +4,11 @@ ////////////////////////////////////////////////////////////////// /decl/surgery_step/bone + abstract_type = /decl/surgery_step/bone surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NEEDS_ENCASEMENT var/required_stage = 0 -/decl/surgery_step/bone/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/bone/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && (affected.status & ORGAN_BROKEN) && affected.stage == required_stage) return affected @@ -18,9 +19,10 @@ /decl/surgery_step/bone/glue name = "Begin bone repair" description = "This procedure is used to begin setting a bone in place by treating the damage with bone gel." + end_step_sound = 'sound/effects/ointment.ogg' allowed_tools = list( - /obj/item/bonegel = 100, - /obj/item/tape_roll = 75 + TOOL_BONE_GEL = 100, + TOOL_SCREWDRIVER = 75 ) can_infect = 1 blood_level = 1 @@ -28,8 +30,8 @@ max_duration = 60 shock_level = 20 -/decl/surgery_step/bone/glue/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/glue/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/bone = affected.encased ? "\the [target]'s [affected.encased]" : "bones in \the [target]'s [affected.name]" if (affected.stage == 0) user.visible_message("\The [user] starts applying \the [tool] to [bone]." , \ @@ -37,30 +39,31 @@ target.custom_pain("Something in your [affected.name] is causing you a lot of pain!",50, affecting = affected) ..() -/decl/surgery_step/bone/glue/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/glue/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/bone = affected.encased ? "\the [target]'s [affected.encased]" : "bones in \the [target]'s [affected.name]" user.visible_message("[user] applies some [tool.name] to [bone]", \ "You apply some [tool.name] to [bone].") if(affected.stage == 0) affected.stage = 1 affected.status &= ~ORGAN_BRITTLE + ..() -/decl/surgery_step/bone/glue/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/glue/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") - + ..() ////////////////////////////////////////////////////////////////// // bone setting surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/bone/set_bone name = "Set bone" - description = "After preparing with bone gel, this procedure sets a broken bone in place for final repair." + description = "This procedure sets a broken bone in place for final repair after preparing with bone gel." allowed_tools = list( - /obj/item/bonesetter = 100, - /obj/item/wrench = 75 + TOOL_BONE_SETTER = 100, + TOOL_WRENCH = 75 ) min_duration = 60 max_duration = 70 @@ -68,9 +71,10 @@ delicate = 1 surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT required_stage = 1 + end_step_sound = "fracture" -/decl/surgery_step/bone/set_bone/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/set_bone/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/bone = affected.encased ? "\the [target]'s [affected.encased]" : "bones in \the [target]'s [affected.name]" if(affected.encased == "skull") user.visible_message("[user] is beginning to piece [bone] back together with \the [tool]." , \ @@ -81,8 +85,8 @@ target.custom_pain("The pain in your [affected.name] is going to make you pass out!",50, affecting = affected) ..() -/decl/surgery_step/bone/set_bone/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/set_bone/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/bone = affected.encased ? "\the [target]'s [affected.encased]" : "bones in \the [target]'s [affected.name]" if (affected.status & ORGAN_BROKEN) if(affected.encased == "skull") @@ -92,27 +96,30 @@ user.visible_message("\The [user] sets [bone] in place with \the [tool].", \ "You set [bone] in place with \the [tool].") affected.stage = 2 + ..() // The pseudo-fail condition below plays a fracture sound anyway. else user.visible_message("\The [user] sets [bone] in the WRONG place with \the [tool].", \ "You set [bone] in the WRONG place with \the [tool].") affected.fracture() -/decl/surgery_step/bone/set_bone/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/set_bone/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("\The [user]'s hand slips, damaging the [affected.encased ? affected.encased : "bones"] in \the [target]'s [affected.name] with \the [tool]!" , \ "Your hand slips, damaging the [affected.encased ? affected.encased : "bones"] in \the [target]'s [affected.name] with \the [tool]!") affected.fracture() - affected.take_external_damage(5, used_weapon = tool) + affected.take_damage(5, inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // post setting bone-gelling surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/bone/finish name = "Finish bone repair" - description = "After setting a bone in place, this procedure seals the last of the damage with bone gel." + description = "This procedure seals a damaged bone with bone gel after setting the bone in place." + end_step_sound = 'sound/effects/ointment.ogg' allowed_tools = list( - /obj/item/bonegel = 100, - /obj/item/tape_roll = 75 + TOOL_BONE_GEL = 100, + TOOL_SCREWDRIVER = 75 ) can_infect = 1 blood_level = 1 @@ -121,23 +128,29 @@ shock_level = 20 required_stage = 2 -/decl/surgery_step/bone/finish/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/finish/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/bone = affected.encased ? "\the [target]'s damaged [affected.encased]" : "damaged bones in \the [target]'s [affected.name]" user.visible_message("[user] starts to finish mending [bone] with \the [tool].", \ "You start to finish mending [bone] with \the [tool].") ..() -/decl/surgery_step/bone/finish/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/finish/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/bone = affected.encased ? "\the [target]'s damaged [affected.encased]" : "damaged bones in [target]'s [affected.name]" - user.visible_message("[user] has mended [bone] with \the [tool]." , \ - "You have mended [bone] with \the [tool]." ) - affected.status &= ~ORGAN_BROKEN - affected.stage = 0 + // if it's too damaged to mend/will just re-break, warn them and don't lower our stage + if(affected.mend_fracture()) + user.visible_message(SPAN_NOTICE("[user] has mended [bone] with \the [tool].") , \ + SPAN_NOTICE("You have mended [bone] with \the [tool].")) + affected.stage = 0 + else + user.visible_message(SPAN_WARNING("[user] attempted to mend [bone] with \the [tool], but it was too damaged!"), + SPAN_WARNING("You failed to mend [bone] with \the [tool], as it is too damaged.")) affected.update_wounds() + ..() -/decl/surgery_step/bone/finish/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/bone/finish/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ - "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") \ No newline at end of file + "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") + ..() diff --git a/code/modules/surgery/crystal.dm b/code/modules/surgery/crystal.dm index 7c6b012f2397..39ec4770a456 100644 --- a/code/modules/surgery/crystal.dm +++ b/code/modules/surgery/crystal.dm @@ -1,13 +1,10 @@ /decl/surgery_step/generic/cut_open/crystal name = "Drill keyhole incision" - description = "This procedure drills a keyhold incision into crystalline limbs to allow for delicate internal work." - allowed_tools = list( - /obj/item/pickaxe/drill = 80, - /obj/item/surgicaldrill = 100 - ) + description = "This procedure drills a keyhole incision into crystalline limbs to allow for delicate internal work." + allowed_tools = list(TOOL_SURGICAL_DRILL = 100) fail_string = "cracking" access_string = "a neat hole" - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NO_FLESH + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_FLESH /decl/surgery_step/generic/cauterize/crystal name = "Close keyhole incision" @@ -22,56 +19,41 @@ /decl/surgery_step/open_encased/crystal name = "Saw through crystal" description = "This procedure cuts through hard crystal to allow for access to the internals." - allowed_tools = list( - /obj/item/circular_saw = 100 - ) - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_RETRACTED | SURGERY_NO_FLESH + allowed_tools = list(TOOL_SAW = 100) + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NEEDS_RETRACTED | SURGERY_NO_FLESH /decl/surgery_step/bone/glue/crystal name = "Begin crystalline bone repair" description = "This procedure uses resin to begin patching damage to crystalline bones." - allowed_tools = list( - /obj/item/stack/medical/resin = 100 - ) + allowed_tools = list(/obj/item/stack/medical/resin = 100) surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_FLESH /decl/surgery_step/bone/finish/crystal name = "Finish crystalline bone repair" description = "This procedure uses resin to finalize the repair of crystalline bones that have been set in place." - allowed_tools = list( - /obj/item/stack/medical/resin = 100 - ) + allowed_tools = list(/obj/item/stack/medical/resin = 100) surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_FLESH -/decl/surgery_step/internal/detatch_organ/crystal +/decl/surgery_step/internal/detach_organ/crystal name = "Detach crystalline internal organ" description = "This procedure severs a crystalline internal organ, allowing it to be removed." - allowed_tools = list( - /obj/item/pickaxe/drill = 80, - /obj/item/surgicaldrill = 100 - ) - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT | SURGERY_NO_FLESH + allowed_tools = list(TOOL_SURGICAL_DRILL = 100) + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT | SURGERY_NO_FLESH /decl/surgery_step/internal/attach_organ/crystal name = "Attach crystalline internal organ" - description = "This procedure reattaches a previously detached crystalline internal organ." - allowed_tools = list( - /obj/item/stack/medical/resin = 100 - ) - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT | SURGERY_NO_FLESH + description = "This procedure attaches a detached crystalline internal organ." + allowed_tools = list(/obj/item/stack/medical/resin = 100) + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT | SURGERY_NO_FLESH /decl/surgery_step/internal/fix_organ/crystal name = "Repair crystalline internal organ" description = "This procedure repairs damage to crystalline internal organs." - allowed_tools = list( - /obj/item/stack/medical/resin = 100 - ) - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NO_FLESH + allowed_tools = list(/obj/item/stack/medical/resin = 100) + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_FLESH /decl/surgery_step/fix_vein/crystal name = "Repair arteries in crystalline beings" description = "This procedure is used to patch severed arteries in crystalline bodies." - allowed_tools = list( - /obj/item/stack/medical/resin = 100 - ) - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NO_FLESH + allowed_tools = list(/obj/item/stack/medical/resin = 100) + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_FLESH diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index e559dacd91e0..57a17c7d785d 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -10,9 +10,8 @@ name = "Saw through bone" description = "This procedure splits open encasing bones such as the ribcage to allow access to the innards." allowed_tools = list( - /obj/item/circular_saw = 100, - /obj/item/knife = 50, - /obj/item/hatchet = 75 + TOOL_SAW = 100, + TOOL_HATCHET = 75 ) can_infect = 1 blood_level = 1 @@ -20,30 +19,32 @@ max_duration = 70 shock_level = 60 delicate = 1 - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NO_STUMP | SURGERY_NEEDS_RETRACTED + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NEEDS_RETRACTED strict_access_requirement = TRUE -/decl/surgery_step/open_encased/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/open_encased/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.encased) return affected -/decl/surgery_step/open_encased/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/open_encased/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] begins to cut through [target]'s [affected.encased] with \the [tool].", \ "You begin to cut through [target]'s [affected.encased] with \the [tool].") target.custom_pain("Something hurts horribly in your [affected.name]!",60, affecting = affected) ..() -/decl/surgery_step/open_encased/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/open_encased/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] has cut [target]'s [affected.encased] open with \the [tool].", \ "You have cut [target]'s [affected.encased] open with \the [tool].") affected.fracture() + ..() -/decl/surgery_step/open_encased/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/open_encased/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, cracking [target]'s [affected.encased] with \the [tool]!" , \ "Your hand slips, cracking [target]'s [affected.encased] with \the [tool]!" ) - affected.take_external_damage(15, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.take_damage(15, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) affected.fracture() + ..() diff --git a/code/modules/surgery/face.dm b/code/modules/surgery/face.dm index 75b3c5cadc4c..7b8ca9c66870 100644 --- a/code/modules/surgery/face.dm +++ b/code/modules/surgery/face.dm @@ -5,36 +5,36 @@ name = "Repair face" description = "This procedure is used to repair disfiguring facial damage." allowed_tools = list( - /obj/item/hemostat = 100, - /obj/item/stack/cable_coil = 75, - /obj/item/assembly/mousetrap = 10, - /obj/item/kitchen/utensil/fork = 75 + TOOL_HEMOSTAT = 100, + TOOL_CABLECOIL = 75 ) min_duration = 100 max_duration = 120 surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NEEDS_RETRACTED strict_access_requirement = TRUE -/decl/surgery_step/fix_face/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/fix_face/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) if(target_zone == BP_HEAD) var/obj/item/organ/external/affected = ..() if(affected && (affected.status & ORGAN_DISFIGURED)) return affected -/decl/surgery_step/fix_face/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/fix_face/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) user.visible_message("[user] starts repairing damage to \the [target]'s face with \the [tool].", \ "You start repairing damage to \the [target]'s face with \the [tool].") ..() -/decl/surgery_step/fix_face/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/fix_face/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) user.visible_message("[user] repairs \the [target]'s face with \the [tool].", \ "You repair \the [target]'s face with \the [tool].") - var/obj/item/organ/external/head/h = target.get_organ(target_zone) - if(h) + var/obj/item/organ/external/h = GET_EXTERNAL_ORGAN(target, target_zone) + if(h) h.status &= ~ORGAN_DISFIGURED + ..() -/decl/surgery_step/fix_face/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_face/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, tearing skin on [target]'s face with \the [tool]!", \ "Your hand slips, tearing skin on [target]'s face with \the [tool]!") - affected.take_external_damage(10, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.take_damage(10, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index a572b4cf7ae5..f0a7f693e1d9 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -8,103 +8,29 @@ // generic surgery step datum ////////////////////////////////////////////////////////////////// /decl/surgery_step/generic + abstract_type = /decl/surgery_step/generic can_infect = 1 shock_level = 10 - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NO_STUMP + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL -/decl/surgery_step/generic/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/generic/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) if(target_zone != BP_EYES) //there are specific steps for eye surgery . = ..() -////////////////////////////////////////////////////////////////// -// laser scalpel surgery step -// acts as both cutting and bleeder clamping surgery steps -////////////////////////////////////////////////////////////////// -/decl/surgery_step/generic/cut_with_laser - name = "Make laser incision" - description = "This procedure uses a laser to quickly and cleanly make an incision." - allowed_tools = list( - /obj/item/scalpel/laser3 = 95, - /obj/item/scalpel/laser2 = 85, - /obj/item/scalpel/laser1 = 75, - /obj/item/energy_blade/sword = 5 - ) - min_duration = 90 - max_duration = 110 - -/decl/surgery_step/generic/cut_with_laser/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts the bloodless incision on [target]'s [affected.name] with \the [tool].", \ - "You start the bloodless incision on [target]'s [affected.name] with \the [tool].") - target.custom_pain("You feel a horrible, searing pain in your [affected.name]!",50, affecting = affected) - ..() - -/decl/surgery_step/generic/cut_with_laser/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] has made a bloodless incision on [target]'s [affected.name] with \the [tool].", \ - "You have made a bloodless incision on [target]'s [affected.name] with \the [tool].",) - affected.createwound(CUT, affected.min_broken_damage/2, 1) - affected.clamp_organ() - spread_germs_to_organ(affected, user) - -/decl/surgery_step/generic/cut_with_laser/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user]'s hand slips as the blade sputters, searing a long gash in [target]'s [affected.name] with \the [tool]!", \ - "Your hand slips as the blade sputters, searing a long gash in [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(15, 5, (DAM_SHARP|DAM_EDGE), used_weapon = tool) - -////////////////////////////////////////////////////////////////// -// laser scalpel surgery step -// acts as the cutting, bleeder clamping, and retractor surgery steps -////////////////////////////////////////////////////////////////// -/decl/surgery_step/generic/managed - name = "Make managed incision" - description = "This procedure uses a laser scalpel to construct a pre-clamped incision into a patient's body." - allowed_tools = list( - /obj/item/scalpel/manager = 100 - ) - min_duration = 80 - max_duration = 120 - -/decl/surgery_step/generic/managed/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts to construct a prepared incision on and within [target]'s [affected.name] with \the [tool].", \ - "You start to construct a prepared incision on and within [target]'s [affected.name] with \the [tool].") - target.custom_pain("You feel a horrible, searing pain in your [affected.name] as it is pushed apart!",50, affecting = affected) - ..() - -/decl/surgery_step/generic/managed/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] has constructed a prepared incision on and within [target]'s [affected.name] with \the [tool].", \ - "You have constructed a prepared incision on and within [target]'s [affected.name] with \the [tool].",) - affected.createwound(CUT, affected.min_broken_damage/2, 1) // incision - affected.clamp_organ() // clamp - affected.open_incision() // retract - -/decl/surgery_step/generic/managed/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user]'s hand jolts as the system sparks, ripping a gruesome hole in [target]'s [affected.name] with \the [tool]!", \ - "Your hand jolts as the system sparks, ripping a gruesome hole in [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(20, 15, (DAM_SHARP|DAM_EDGE), used_weapon = tool) - ////////////////////////////////////////////////////////////////// // scalpel surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/generic/cut_open name = "Make incision" description = "This procedure cuts a small wound that allows access to deeper tissue." - allowed_tools = list( - /obj/item/scalpel = 100, - /obj/item/knife = 75, - /obj/item/broken_bottle = 50, - /obj/item/shard = 50 - ) + end_step_sound = 'sound/items/Wirecutter.ogg' + allowed_tools = list(TOOL_SCALPEL = 100) min_duration = 90 max_duration = 110 var/fail_string = "slicing open" var/access_string = "an incision" -/decl/surgery_step/generic/cut_open/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/generic/cut_open/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) . = ..() if(.) var/obj/item/organ/external/affected = . @@ -113,27 +39,32 @@ to_chat(user, SPAN_NOTICE("The [incision.desc] provides enough access.")) return FALSE -/decl/surgery_step/generic/cut_open/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/cut_open/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts [access_string] on [target]'s [affected.name] with \the [tool].", \ "You start [access_string] on [target]'s [affected.name] with \the [tool].") target.custom_pain("You feel a horrible pain as if from a sharp knife in your [affected.name]!",40, affecting = affected) ..() -/decl/surgery_step/generic/cut_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/cut_open/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] has made [access_string] on [target]'s [affected.name] with \the [tool].", \ "You have made [access_string] on [target]'s [affected.name] with \the [tool].",) - affected.createwound(CUT, affected.min_broken_damage/2, 1) - playsound(target.loc, 'sound/weapons/bladeslice.ogg', 15, 1) + affected.createwound(CUT, ceil(affected.min_broken_damage/2), TRUE) + if(tool.atom_damage_type == BURN) + affected.clamp_organ() + playsound(target, 'sound/items/Welder.ogg', 15, 1) + else + ..() -/decl/surgery_step/generic/cut_open/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/cut_open/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, [fail_string] \the [target]'s [affected.name] in the wrong place with \the [tool]!", \ "Your hand slips, [fail_string] \the [target]'s [affected.name] in the wrong place with \the [tool]!") - affected.take_external_damage(10, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.take_damage(10, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() -/decl/surgery_step/generic/cut_open/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/generic/cut_open/success_chance(mob/living/user, mob/living/target, obj/item/tool) . = ..() if(user.skill_check(SKILL_FORENSICS, SKILL_ADEPT)) . += 40 @@ -146,41 +77,42 @@ /decl/surgery_step/generic/clamp_bleeders name = "Clamp bleeders" description = "This procedure clamps off veins within an incision, preventing it from bleeding excessively." + end_step_sound = 'sound/items/Wirecutter.ogg' allowed_tools = list( - /obj/item/hemostat = 100, - /obj/item/stack/cable_coil = 75, - /obj/item/assembly/mousetrap = 20 + TOOL_HEMOSTAT = 100, + TOOL_CABLECOIL = 75 ) min_duration = 40 max_duration = 60 - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NO_STUMP | SURGERY_NEEDS_INCISION + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NEEDS_INCISION strict_access_requirement = FALSE -/decl/surgery_step/generic/clamp_bleeders/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/generic/clamp_bleeders/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && !affected.clamped()) return affected -/decl/surgery_step/generic/clamp_bleeders/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/clamp_bleeders/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts clamping bleeders in [target]'s [affected.name] with \the [tool].", \ "You start clamping bleeders in [target]'s [affected.name] with \the [tool].") target.custom_pain("The pain in your [affected.name] is maddening!",40, affecting = affected) ..() -/decl/surgery_step/generic/clamp_bleeders/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/clamp_bleeders/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] clamps bleeders in [target]'s [affected.name] with \the [tool].", \ "You clamp bleeders in [target]'s [affected.name] with \the [tool].") affected.clamp_organ() spread_germs_to_organ(affected, user) - playsound(target.loc, 'sound/items/Welder.ogg', 15, 1) + ..() -/decl/surgery_step/generic/clamp_bleeders/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/clamp_bleeders/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, tearing blood vessals and causing massive bleeding in [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!",) - affected.take_external_damage(10, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.take_damage(10, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // retractor surgery step @@ -189,19 +121,17 @@ name = "Widen incision" description = "This procedure is used to widen an incision when it is too small to access the interior." allowed_tools = list( - /obj/item/retractor = 100, - /obj/item/crowbar = 75, - /obj/item/knife = 50, - /obj/item/kitchen/utensil/fork = 50 + TOOL_RETRACTOR = 100, + TOOL_CROWBAR = 75 ) min_duration = 30 max_duration = 40 - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NO_STUMP | SURGERY_NEEDS_INCISION + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NEEDS_INCISION strict_access_requirement = TRUE -/decl/surgery_step/generic/retract_skin/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/generic/retract_skin/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) . = FALSE - var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) if(affected.how_open() >= SURGERY_RETRACTED) var/datum/wound/cut/incision = affected.get_incision() @@ -209,35 +139,37 @@ else . = TRUE -/decl/surgery_step/generic/retract_skin/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/retract_skin/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts to pry open the incision on [target]'s [affected.name] with \the [tool].", \ "You start to pry open the incision on [target]'s [affected.name] with \the [tool].") target.custom_pain("It feels like the skin on your [affected.name] is on fire!",40,affecting = affected) ..() -/decl/surgery_step/generic/retract_skin/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/retract_skin/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] keeps the incision open on [target]'s [affected.name] with \the [tool].", \ "You keep the incision open on [target]'s [affected.name] with \the [tool].") affected.open_incision() + ..() -/decl/surgery_step/generic/retract_skin/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/retract_skin/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, tearing the edges of the incision on [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, tearing the edges of the incision on [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(12, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) + affected.take_damage(12, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // skin cauterization surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/generic/cauterize name = "Cauterize incision" + description = "This procedure cauterizes and closes an incision." + end_step_sound = 'sound/items/Welder.ogg' allowed_tools = list( - /obj/item/cautery = 100, - /obj/item/clothing/mask/smokable/cigarette = 75, - /obj/item/flame/lighter = 50, - /obj/item/weldingtool = 25 + TOOL_CAUTERY = 100, + TOOL_WELDER = 25 ) min_duration = 70 max_duration = 100 @@ -245,98 +177,119 @@ var/cauterize_term = "cauterize" var/post_cauterize_term = "cauterized" -/decl/surgery_step/generic/cauterize/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - . = FALSE - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(affected) - if(affected.is_stump()) - if(affected.status & ORGAN_ARTERY_CUT) - . = TRUE - else - to_chat(user, SPAN_WARNING("There is no bleeding to repair within this stump.")) - else if(!affected.get_incision(1)) - to_chat(user, SPAN_WARNING("There are no incisions on [target]'s [affected.name] that can be closed cleanly with \the [tool]!")) - else - . = TRUE +/decl/surgery_step/generic/cauterize/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(!affected?.get_incision(1)) + to_chat(user, SPAN_WARNING("There are no incisions on [target]'s [affected.name] that can be closed cleanly with \the [tool]!")) + return FALSE + return TRUE -/decl/surgery_step/generic/cauterize/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/generic/cauterize/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() - if(affected) - if(affected.is_stump()) - if(affected.status & ORGAN_ARTERY_CUT) - return affected - else if(affected.how_open()) - return affected - -/decl/surgery_step/generic/cauterize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - var/datum/wound/W = affected.get_incision() - user.visible_message("[user] is beginning to [cauterize_term][W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool]." , \ - "You are beginning to [cauterize_term][W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].") + if(affected && affected.how_open()) + return affected + +/decl/surgery_step/generic/cauterize/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + var/datum/wound/wound = affected.get_incision() + user.visible_message("[user] is beginning to [cauterize_term][wound ? " \a [wound.desc] on" : ""] \the [target]'s [affected.name] with \the [tool]." , \ + "You are beginning to [cauterize_term][wound ? " \a [wound.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].") target.custom_pain("Your [affected.name] is being burned!",40,affecting = affected) ..() -/decl/surgery_step/generic/cauterize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - var/datum/wound/W = affected.get_incision() - user.visible_message("[user] [post_cauterize_term][W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].", \ - "You [cauterize_term][W ? " \a [W.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].") - if(istype(W)) - W.close() +/decl/surgery_step/generic/cauterize/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + var/datum/wound/wound = affected.get_incision() + user.visible_message("[user] [post_cauterize_term][wound ? " \a [wound.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].", \ + "You [cauterize_term][wound ? " \a [wound.desc] on" : ""] \the [target]'s [affected.name] with \the [tool].") + if(istype(wound)) + wound.close() affected.update_wounds() - if(affected.is_stump()) - affected.status &= ~ORGAN_ARTERY_CUT if(affected.clamped()) affected.remove_clamps() + ..() -/decl/surgery_step/generic/cauterize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/cauterize/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, damaging [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, damaging [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(0, 3, used_weapon = tool) + affected.take_damage(3, BURN, inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // limb amputation surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/generic/amputate name = "Amputate limb" + description = "This procedure removes a limb, or the stump of a limb, from the body entirely." + end_step_sound = 'sound/weapons/bladeslice.ogg' allowed_tools = list( - /obj/item/circular_saw = 100, - /obj/item/hatchet = 75 + TOOL_SAW = 100, + TOOL_HATCHET = 75 ) min_duration = 110 max_duration = 160 surgery_candidate_flags = 0 -/decl/surgery_step/generic/amputate/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/generic/amputate/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && (affected.limb_flags & ORGAN_FLAG_CAN_AMPUTATE) && !affected.how_open()) return affected -/decl/surgery_step/generic/amputate/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - var/target_zone = user.zone_sel.selecting - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/generic/amputate/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + var/target_zone = user.get_target_zone() + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(BP_IS_PROSTHETIC(affected)) return SURGERY_SKILLS_ROBOTIC else return ..() -/decl/surgery_step/generic/amputate/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] is beginning to amputate [target]'s [affected.name] with \the [tool]." , \ - "You are beginning to cut through [target]'s [affected.amputation_point] with \the [tool].") +/decl/surgery_step/generic/amputate/proc/is_clean(var/mob/user, var/obj/item/tool, var/mob/target) + . = (!user.check_intent(I_FLAG_HELP)) ? FALSE : (can_operate(target) >= OPERATE_OKAY && istype(tool, /obj/item/circular_saw)) + +/decl/surgery_step/generic/amputate/get_speed_modifier(var/mob/user, var/mob/target, var/obj/item/tool, var/tool_archetype) + . = ..() + if(!is_clean(user, tool, target)) + . *= 0.5 + +/decl/surgery_step/generic/amputate/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(is_clean(user, tool, target)) + user.visible_message( \ + SPAN_NOTICE("\The [user] is beginning to amputate \the [target]'s [affected.name] with \the [tool]."), \ + SPAN_NOTICE("You are beginning to cut through \the [target]'s [affected.amputation_point] with \the [tool].")) + else + user.visible_message( \ + SPAN_DANGER("\The [user] starts hacking at \the [target]'s [affected.name] with \the [tool]!") , \ + SPAN_DANGER("You start hacking at \the [target]'s [affected.amputation_point] with \the [tool]!")) target.custom_pain("Your [affected.amputation_point] is being ripped apart!",100,affecting = affected) ..() -/decl/surgery_step/generic/amputate/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] amputates [target]'s [affected.name] at the [affected.amputation_point] with \the [tool].", \ - "You amputate [target]'s [affected.name] with \the [tool].") - affected.droplimb(1,DROPLIMB_EDGE) - -/decl/surgery_step/generic/amputate/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user]'s hand slips, sawing through the bone in [target]'s [affected.name] with \the [tool]!", \ - "Your hand slips, sawwing through the bone in [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(30, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) +/decl/surgery_step/generic/amputate/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + var/clean_cut = is_clean(user, tool, target) + if(clean_cut) + user.visible_message( \ + SPAN_NOTICE("\The [user] cleanly amputates \the [target]'s [affected.name] at the [affected.amputation_point] with \the [tool]."), \ + SPAN_NOTICE("You cleanly amputate \the [target]'s [affected.name] with \the [tool].")) + else + user.visible_message( \ + SPAN_DANGER("\The [user] hacks off \the [target]'s [affected.name] at the [affected.amputation_point] with \the [tool]!"), \ + SPAN_DANGER("You hack off \the [target]'s [affected.name] with \the [tool]!")) + affected.dismember(clean_cut, DISMEMBER_METHOD_EDGE) + ..() + +/decl/surgery_step/generic/amputate/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(user.try_unequip(tool, affected)) + user.visible_message( + SPAN_DANGER("\The [user] manages to get \the [tool] stuck in \the [target]'s [affected.name]!"), \ + SPAN_DANGER("You manage to get \the [tool] stuck in \the [target]'s [affected.name]!")) + affected.embed_in_organ(tool, affected.take_damage(30, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool)) + else + user.visible_message( + SPAN_WARNING("\The [user] slips, mangling \the [target]'s [affected.name] with \the [tool]."), \ + SPAN_WARNING("You slip, mangling \the [target]'s [affected.name] with \the [tool].")) + affected.take_damage(30, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) affected.fracture() + ..() diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index d66aebbaf29b..d90193ec82a3 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -10,13 +10,22 @@ /decl/surgery_step/cavity shock_level = 40 delicate = 1 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NEEDS_ENCASEMENT + abstract_type = /decl/surgery_step/cavity + end_step_sound = 'sound/effects/squelch1.ogg' + +/decl/surgery_step/cavity/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message(SPAN_WARNING("[user]'s hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!"), \ + SPAN_WARNING("Your hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!")) + affected.take_damage(20, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() -/decl/surgery_step/cavity/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("[user]'s hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!", \ - "Your hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(20, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) +/decl/surgery_step/cavity/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool, target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(!affected || !BP_IS_PROSTHETIC(affected) || BP_IS_CRYSTAL(affected)) + return ..() + return SURGERY_SKILLS_ROBOTIC ////////////////////////////////////////////////////////////////// // create implant space surgery step @@ -24,31 +33,28 @@ /decl/surgery_step/cavity/make_space name = "Hollow out cavity" description = "This procedure is used to prepare a patient to have something large implanted in their body." - allowed_tools = list( - /obj/item/surgicaldrill = 100, - /obj/item/pen = 75, - /obj/item/stack/material/rods = 50 - ) + allowed_tools = list(TOOL_SURGICAL_DRILL = 100) min_duration = 60 max_duration = 80 -/decl/surgery_step/cavity/make_space/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/cavity/make_space/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.cavity_name && !affected.cavity) return affected -/decl/surgery_step/cavity/make_space/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts making some space inside [target]'s [affected.cavity_name] cavity with \the [tool].", \ - "You start making some space inside [target]'s [affected.cavity_name] cavity with \the [tool]." ) +/decl/surgery_step/cavity/make_space/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("[user] starts making some space inside [target]'s [affected.cavity_name] with \the [tool].", \ + "You start making some space inside [target]'s [affected.cavity_name] with \the [tool]." ) target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) affected.cavity = TRUE ..() -/decl/surgery_step/cavity/make_space/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("[user] makes some space inside [target]'s [affected.cavity_name] cavity with \the [tool].", \ - "You make some space inside [target]'s [affected.cavity_name] cavity with \the [tool]." ) +/decl/surgery_step/cavity/make_space/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message(SPAN_NOTICE("[user] makes some space inside [target]'s \the [affected.cavity_name] with \the [tool]."), \ + SPAN_NOTICE("You make some space inside [target]'s \the [affected.cavity_name] with \the [tool].") ) + ..() ////////////////////////////////////////////////////////////////// // implant cavity sealing surgery step @@ -57,88 +63,91 @@ name = "Close cavity" description = "This procedure is used to repair and close off a cavity within the body." allowed_tools = list( - /obj/item/cautery = 100, - /obj/item/clothing/mask/smokable/cigarette = 75, - /obj/item/flame/lighter = 50, - /obj/item/weldingtool = 25 + TOOL_CAUTERY = 100, + TOOL_WELDER = 25 ) min_duration = 60 max_duration = 80 -/decl/surgery_step/cavity/close_space/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/cavity/close_space/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.cavity) return affected -/decl/surgery_step/cavity/close_space/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts mending [target]'s [affected.cavity_name] cavity wall with \the [tool].", \ - "You start mending [target]'s [affected.cavity_name] cavity wall with \the [tool]." ) +/decl/surgery_step/cavity/close_space/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("[user] starts mending [target]'s \the [affected.cavity_name] wall with \the [tool].", \ + "You start mending [target]'s \the [affected.cavity_name] wall with \the [tool]." ) target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) ..() -/decl/surgery_step/cavity/close_space/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - user.visible_message("[user] mends [target]'s [affected.cavity_name] cavity walls with \the [tool].", \ - "You mend [target]'s [affected.cavity_name] cavity walls with \the [tool]." ) +/decl/surgery_step/cavity/close_space/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message(SPAN_NOTICE("[user] mends [target]'s \the [affected.cavity_name] walls with \the [tool]."), \ + SPAN_NOTICE("You mend [target]'s \the [affected.cavity_name] walls with \the [tool].") ) affected.cavity = FALSE + ..() ////////////////////////////////////////////////////////////////// // implanting surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/cavity/place_item name = "Place item in cavity" + description = "This procedure inserts an item into a prepared cavity in the body." allowed_tools = list(/obj/item = 100) min_duration = 80 max_duration = 100 hidden_from_codex = TRUE + begin_step_sound = 'sound/effects/squelch1.ogg' -/decl/surgery_step/cavity/place_item/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(istype(user,/mob/living/silicon/robot)) +/decl/surgery_step/cavity/place_item/can_use(mob/living/user, mob/living/target, target_zone, obj/item/tool) + if(isrobot(user)) return FALSE . = ..() -/decl/surgery_step/cavity/place_item/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/cavity/place_item/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.cavity) return affected -/decl/surgery_step/cavity/place_item/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/cavity/place_item/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected && affected.cavity) - var/max_volume = BASE_STORAGE_CAPACITY(affected.cavity_max_w_class) + var/max_volume = BASE_STORAGE_CAPACITY(affected.cavity_max_w_class) + affected.internal_organs_size if(tool.w_class > affected.cavity_max_w_class) - to_chat(user, SPAN_WARNING("\The [tool] is too big for [affected.cavity_name] cavity.")) + to_chat(user, SPAN_WARNING("\The [tool] is too big for \the [affected.cavity_name].")) return FALSE var/total_volume = tool.get_storage_cost() for(var/obj/item/I in affected.implants) if(istype(I,/obj/item/implant)) continue total_volume += I.get_storage_cost() + for(var/obj/item/organ/internal/org in affected.internal_organs) + max_volume -= org.get_storage_cost() if(total_volume > max_volume) - to_chat(user, SPAN_WARNING("There isn't enough space left in [affected.cavity_name] cavity for [tool].")) + to_chat(user, SPAN_WARNING("There isn't enough space left in \the [affected.cavity_name] for [tool].")) return FALSE return TRUE -/decl/surgery_step/cavity/place_item/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts putting \the [tool] inside [target]'s [affected.cavity_name] cavity.", \ - "You start putting \the [tool] inside [target]'s [affected.cavity_name] cavity." ) +/decl/surgery_step/cavity/place_item/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("[user] starts putting \the [tool] inside [target]'s \the [affected.cavity_name].", \ + "You start putting \the [tool] inside [target]'s \the [affected.cavity_name]." ) target.custom_pain("The pain in your chest is living hell!",1,affecting = affected) - playsound(target.loc, 'sound/effects/squelch1.ogg', 25, 1) ..() -/decl/surgery_step/cavity/place_item/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - if(!user.unEquip(tool, affected)) +/decl/surgery_step/cavity/place_item/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(!user.try_unequip(tool, affected)) return - user.visible_message("[user] puts \the [tool] inside [target]'s [affected.cavity_name] cavity.", \ - "You put \the [tool] inside [target]'s [affected.cavity_name] cavity." ) + user.visible_message(SPAN_NOTICE("[user] puts \the [tool] inside [target]'s \the [affected.cavity_name]."), \ + SPAN_NOTICE("You put \the [tool] inside [target]'s \the [affected.cavity_name].") ) if (tool.w_class > affected.cavity_max_w_class/2 && prob(50) && !BP_IS_PROSTHETIC(affected) && affected.sever_artery()) - to_chat(user, "You tear some blood vessels trying to fit such a big object in this cavity.") + to_chat(user, SPAN_WARNING("You tear some blood vessels trying to fit such a big object in this cavity.")) affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1,affecting = affected) - affected.implants += tool + LAZYDISTINCTADD(affected.implants, tool) affected.cavity = 0 + ..() ////////////////////////////////////////////////////////////////// // implant removal surgery step @@ -147,14 +156,14 @@ name = "Remove foreign body" description = "This procedure is used to remove foreign bodies like shrapnel or implants from a patient." allowed_tools = list( - /obj/item/hemostat = 100, - /obj/item/wirecutters = 75, - /obj/item/kitchen/utensil/fork = 20 + TOOL_HEMOSTAT = 100, + TOOL_WIRECUTTERS = 75 ) min_duration = 80 max_duration = 100 + end_step_sound = 'sound/effects/squelch1.ogg' -/decl/surgery_step/cavity/implant_removal/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/cavity/implant_removal/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected) for(var/obj/O in affected.implants) @@ -162,20 +171,21 @@ return affected return FALSE -/decl/surgery_step/cavity/implant_removal/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/cavity/implant_removal/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ "You start poking around inside [target]'s [affected.name] with \the [tool]." ) target.custom_pain("The pain in your [affected.name] is living hell!",1,affecting = affected) ..() -/decl/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - var/exposed = 0 +/decl/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + // Whether or not we can access implants/items inside the organ, or just ones embedded in wounds. + var/exposed = FALSE if(affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED)) - exposed = 1 - if(BP_IS_PROSTHETIC(affected) && affected.hatch_state == HATCH_OPENED) - exposed = 1 + exposed = TRUE + else if(BP_IS_PROSTHETIC(affected) && affected.hatch_state == HATCH_OPENED) + exposed = TRUE var/find_prob = 0 var/list/loot = list() @@ -187,41 +197,43 @@ loot |= wound.embedded_objects find_prob += 50 - if (loot.len) + if(LAZYLEN(loot)) var/obj/item/obj = pick(loot) if(istype(obj,/obj/item/implant)) var/obj/item/implant/imp = obj if (imp.islegal()) - find_prob +=60 + find_prob += 60 else - find_prob +=40 + find_prob += 40 else - find_prob +=50 + find_prob += 50 if (prob(find_prob)) - user.visible_message("[user] takes something out of incision on [target]'s [affected.name] with \the [tool].", \ - "You take \the [obj] out of incision on \the [target]'s [affected.name] with \the [tool]." ) + user.visible_message(SPAN_NOTICE("[user] takes something out of the incision on [target]'s [affected.name] with \the [tool]."), \ + SPAN_NOTICE("You take \the [obj] out of the incision on \the [target]'s [affected.name] with \the [tool].") ) target.remove_implant(obj, TRUE, affected) BITSET(target.hud_updateflag, IMPLOYAL_HUD) - playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1) + ..() else - user.visible_message("[user] removes \the [tool] from [target]'s [affected.name].", \ - "There's something inside [target]'s [affected.name], but you just missed it this time." ) + user.visible_message(SPAN_NOTICE("[user] removes \the [tool] from [target]'s [affected.name]."), \ + SPAN_NOTICE("There's something inside [target]'s [affected.name], but you just missed it this time.") ) + playsound(target.loc, "rustle", 15, TRUE) else - user.visible_message("[user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \ - "You could not find anything inside [target]'s [affected.name]." ) + user.visible_message(SPAN_NOTICE("[user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out."), \ + SPAN_NOTICE("You could not find anything inside [target]'s [affected.name].") ) + playsound(target.loc, "rustle", 15, TRUE) + -/decl/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) ..() - var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) for(var/obj/item/implant/imp in affected.implants) var/fail_prob = 10 fail_prob += 100 - tool_quality(tool) if (prob(fail_prob)) - user.visible_message("Something beeps inside [target]'s [affected.name]!") - playsound(imp.loc, 'sound/items/countdown.ogg', 75, 1, -3) - spawn(25) - imp.activate() + user.visible_message(SPAN_WARNING("Something beeps inside [target]'s [affected.name]!")) + playsound(imp.loc, 'sound/items/countdown.ogg', 75, TRUE, -3) + addtimer(CALLBACK(imp, TYPE_PROC_REF(/obj/item/implant, activate)), 2.5 SECONDS) diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm index 6eb5b163a723..d51f538ac2ad 100644 --- a/code/modules/surgery/limb_reattach.dm +++ b/code/modules/surgery/limb_reattach.dm @@ -11,14 +11,38 @@ can_infect = 0 shock_level = 40 delicate = 1 + abstract_type = /decl/surgery_step/limb + +/decl/surgery_step/limb/get_skill_reqs(mob/living/user, mob/living/target, obj/item/organ/external/tool) + // Not supplied a limb. + if(!istype(tool)) + return ..() + // No parent (how did we get here?) + var/tool_is_prosthetic = BP_IS_PROSTHETIC(tool) + if(!tool.parent_organ) + if(tool_is_prosthetic) + return SURGERY_SKILLS_ROBOTIC + return ..() + // Parent is invalid. + var/obj/item/organ/external/parent = target && GET_EXTERNAL_ORGAN(target, tool.parent_organ) + if(!istype(parent)) + return ..() + // If either is meat and the other is not, return mixed skills. + var/parent_is_prosthetic = BP_IS_PROSTHETIC(parent) + if(parent_is_prosthetic != tool_is_prosthetic) + return SURGERY_SKILLS_ROBOTIC_ON_MEAT + // If they are robotic, return robot skills. + if(parent_is_prosthetic) + return SURGERY_SKILLS_ROBOTIC + // Otherwise return base skills. + return ..() -/decl/surgery_step/limb/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/limb/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) return affected - else - var/list/organ_data = target.species.has_limbs["[target_zone]"] - return !isnull(organ_data) + var/list/organ_data = target.should_have_limb(target_zone) + return !isnull(organ_data) ////////////////////////////////////////////////////////////////// // limb attachment surgery step @@ -30,61 +54,72 @@ min_duration = 50 max_duration = 70 -/decl/surgery_step/limb/attach/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/limb/attach/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + if(!ishuman(target)) + return FALSE . = FALSE var/obj/item/organ/external/E = tool - var/obj/item/organ/external/P = target.organs_by_name[E.parent_organ] - var/obj/item/organ/external/T = target.organs_by_name[E.organ_tag] - if(!P || P.is_stump()) + var/obj/item/organ/external/P = GET_EXTERNAL_ORGAN(target, E.parent_organ) + var/obj/item/organ/external/T = GET_EXTERNAL_ORGAN(target, E.organ_tag) + + if(!P) to_chat(user, SPAN_WARNING("The [E.amputation_point] is missing!")) - else if(T && T.is_stump()) - to_chat(user, SPAN_WARNING("You cannot attach \a [E] when there is a stump!")) - else if(T) - to_chat(user, SPAN_WARNING("There is already \a [E]!")) - else if(BP_IS_PROSTHETIC(P) && !BP_IS_PROSTHETIC(E)) - to_chat(user, SPAN_WARNING("You cannot attach a flesh part to a robotic body.")) - else if(BP_IS_CRYSTAL(P) && !BP_IS_CRYSTAL(E)) + return FALSE + + if(T) + to_chat(user, SPAN_WARNING("There is already \a [T]!")) + return FALSE + if(BP_IS_PROSTHETIC(P)) + if(!BP_IS_PROSTHETIC(E)) + to_chat(user, SPAN_WARNING("You cannot attach a flesh part to a robotic body.")) + var/decl/bodytype/prosthetic/robo_model = P.bodytype + if(!istype(robo_model) || !robo_model.check_can_install(E.organ_tag, target.get_bodytype_category())) + to_chat(user, SPAN_WARNING("That model of prosthetic is incompatible with \the [target].")) + return FALSE + + if(BP_IS_CRYSTAL(P) && !BP_IS_CRYSTAL(E)) to_chat(user, SPAN_WARNING("You cannot attach a flesh part to a crystalline body.")) - else if(!BP_IS_CRYSTAL(P) && BP_IS_CRYSTAL(E)) + return FALSE + + if(!BP_IS_CRYSTAL(P) && BP_IS_CRYSTAL(E)) to_chat(user, SPAN_WARNING("You cannot attach a crystalline part to a flesh body.")) - else - . = TRUE + return FALSE -/decl/surgery_step/limb/attach/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/organ/external/tool) - if(istype(tool) && BP_IS_PROSTHETIC(tool)) - if(target.isSynthetic()) - return SURGERY_SKILLS_ROBOTIC - else - return SURGERY_SKILLS_ROBOTIC_ON_MEAT - return ..() + . = TRUE -/decl/surgery_step/limb/attach/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/limb/attach/can_use(mob/living/user, mob/living/target, target_zone, obj/item/tool) if(..()) var/obj/item/organ/external/E = tool - var/obj/item/organ/external/P = target.organs_by_name[E.parent_organ] - . = (P && !P.is_stump() && !(BP_IS_PROSTHETIC(P) && !BP_IS_PROSTHETIC(E))) + var/obj/item/organ/external/P = GET_EXTERNAL_ORGAN(target, E.parent_organ) + . = (P && !(BP_IS_PROSTHETIC(P) && !BP_IS_PROSTHETIC(E))) -/decl/surgery_step/limb/attach/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/limb/attach/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/E = tool user.visible_message("[user] starts attaching [E.name] to [target]'s [E.amputation_point].", \ "You start attaching [E.name] to [target]'s [E.amputation_point].") + ..() -/decl/surgery_step/limb/attach/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(!user.unEquip(tool)) +/decl/surgery_step/limb/attach/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + if(!user.try_unequip(tool)) return + var/obj/item/organ/external/P = GET_EXTERNAL_ORGAN(target, target_zone) var/obj/item/organ/external/E = tool user.visible_message("[user] has attached [target]'s [E.name] to the [E.amputation_point].", \ "You have attached [target]'s [E.name] to the [E.amputation_point].") - E.replaced(target) - target.update_body() - target.updatehealth() - target.UpdateDamageIcon() -/decl/surgery_step/limb/attach/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + //Add the organ but in a detached state + target.add_organ(E, P, FALSE, TRUE, TRUE) + + if(BP_IS_PROSTHETIC(E) && prob(user.skill_fail_chance(SKILL_DEVICES, 50, SKILL_ADEPT))) + E.add_random_ailment() + ..() + +/decl/surgery_step/limb/attach/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/E = tool user.visible_message(" [user]'s hand slips, damaging [target]'s [E.amputation_point]!", \ " Your hand slips, damaging [target]'s [E.amputation_point]!") target.apply_damage(10, BRUTE, null, damage_flags=DAM_SHARP) + ..() ////////////////////////////////////////////////////////////////// // limb connecting surgery step @@ -93,105 +128,40 @@ name = "Connect limb" description = "This procedure is used to reconnect a replaced severed limb." allowed_tools = list( - /obj/item/hemostat = 100, - /obj/item/stack/cable_coil = 75, - /obj/item/assembly/mousetrap = 20 + TOOL_SUTURES = 100, + TOOL_CABLECOIL = 75 ) can_infect = 1 min_duration = 100 max_duration = 120 -/decl/surgery_step/limb/connect/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool, target_zone) - var/obj/item/organ/external/E = target && target.get_organ(target_zone) - if(istype(E) && BP_IS_PROSTHETIC(E)) - if(target.isSynthetic()) - return SURGERY_SKILLS_ROBOTIC - else - return SURGERY_SKILLS_ROBOTIC_ON_MEAT - return ..() +/decl/surgery_step/limb/connect/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool, target_zone) + return ..(tool = (target && GET_EXTERNAL_ORGAN(target, target_zone))) -/decl/surgery_step/limb/connect/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/limb/connect/can_use(mob/living/user, mob/living/target, target_zone, obj/item/tool) if(..()) - var/obj/item/organ/external/E = target.get_organ(target_zone) - return E && !E.is_stump() && (E.status & ORGAN_CUT_AWAY) - -/decl/surgery_step/limb/connect/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/E = target.get_organ(target_zone) - user.visible_message("[user] starts connecting tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ - "You start connecting tendons and muscle in [target]'s [E.amputation_point].") - -/decl/surgery_step/limb/connect/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/E = target.get_organ(target_zone) - user.visible_message("[user] has connected tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ - "You have connected tendons and muscles in [target]'s [E.amputation_point] with [tool].") - E.status &= ~ORGAN_CUT_AWAY - if(E.children) - for(var/obj/item/organ/external/C in E.children) - C.status &= ~ORGAN_CUT_AWAY - target.update_body() - target.updatehealth() - target.UpdateDamageIcon() - -/decl/surgery_step/limb/connect/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/E = target.get_organ(target_zone) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone) + return E && (E.status & ORGAN_CUT_AWAY) + +/decl/surgery_step/limb/connect/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("[user] starts reattaching tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ + "You start reattaching tendons and muscle in [target]'s [E.amputation_point].") + ..() + +/decl/surgery_step/limb/connect/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone) + var/obj/item/organ/external/P = GET_EXTERNAL_ORGAN(target, E.parent_organ) + user.visible_message("[user] has reattached tendons and muscles in [target]'s [E.amputation_point] with [tool].", \ + "You have reattached tendons and muscles in [target]'s [E.amputation_point] with [tool].") + + //This time we call add_organ but we want it to install in a non detached state + target.add_organ(E, P, FALSE, TRUE, FALSE) + ..() + +/decl/surgery_step/limb/connect/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message(" [user]'s hand slips, damaging [target]'s [E.amputation_point]!", \ " Your hand slips, damaging [target]'s [E.amputation_point]!") target.apply_damage(10, BRUTE, null, damage_flags=DAM_SHARP) - -////////////////////////////////////////////////////////////////// -// robotic limb attachment surgery step -////////////////////////////////////////////////////////////////// -/decl/surgery_step/limb/mechanize - name = "Attach prosthetic limb" - description = "This procedure is used to attach a prosthetic limb to the stump of a patient." - allowed_tools = list(/obj/item/robot_parts = 100) - - min_duration = 80 - max_duration = 100 - -/decl/surgery_step/limb/mechanize/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - if(target.isSynthetic()) - return SURGERY_SKILLS_ROBOTIC - else - return SURGERY_SKILLS_ROBOTIC_ON_MEAT - -/decl/surgery_step/limb/mechanize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(..()) - var/obj/item/robot_parts/p = tool - if (p.part) - if (!(target_zone in p.part)) - return 0 - return isnull(target.get_organ(target_zone)) - -/decl/surgery_step/limb/mechanize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts attaching \the [tool] to [target].", \ - "You start attaching \the [tool] to [target].") - -/decl/surgery_step/limb/mechanize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/robot_parts/L = tool - user.visible_message("[user] has attached \the [tool] to [target].", \ - "You have attached \the [tool] to [target].") - - if(L.part) - for(var/part_name in L.part) - if(!isnull(target.get_organ(part_name))) - continue - var/list/organ_data = target.species.has_limbs["[part_name]"] - if(!organ_data) - continue - var/new_limb_type = organ_data["path"] - var/obj/item/organ/external/new_limb = new new_limb_type(target) - new_limb.robotize(L.model_info) - if(L.sabotaged) - new_limb.status |= ORGAN_SABOTAGED - - target.update_body() - target.updatehealth() - target.UpdateDamageIcon() - - qdel(tool) - -/decl/surgery_step/limb/mechanize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message(" [user]'s hand slips, damaging [target]'s flesh!", \ - " Your hand slips, damaging [target]'s flesh!") - target.apply_damage(10, BRUTE, null, damage_flags=DAM_SHARP) + ..() diff --git a/code/modules/surgery/necrotic.dm b/code/modules/surgery/necrotic.dm new file mode 100644 index 000000000000..1a1ac046fccf --- /dev/null +++ b/code/modules/surgery/necrotic.dm @@ -0,0 +1,200 @@ +////////////////////////////////////////////////////////////////// +// Necrotic organ recovery +////////////////////////////////////////////////////////////////// +/decl/surgery_step/necrotic + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT + blood_level = 1 + shock_level = 30 + abstract_type = /decl/surgery_step/necrotic + +////////////////////////////////////////////////////////////////// +// Necrotic tissue removal +////////////////////////////////////////////////////////////////// +/decl/surgery_step/necrotic/tissue + name = "Remove necrotic tissue" + description = "This procedure removes tissue lost to necrosis and prepares for regeneration." + allowed_tools = list(TOOL_SCALPEL = 90) + min_duration = 150 + max_duration = 170 + end_step_sound = 'sound/weapons/bladeslice.ogg' + +/decl/surgery_step/necrotic/tissue/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) + . = ..() + if(.) + var/obj/item/organ/external/affected = . + if(affected.status & ORGAN_DEAD) + return TRUE + for(var/obj/item/organ/O in affected.internal_organs) + if(O.status & ORGAN_DEAD) + return TRUE + return FALSE + +/decl/surgery_step/necrotic/tissue/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone) + if(!E) + to_chat(user, SPAN_WARNING("\The [target] is missing that limb.")) + return FALSE + + var/list/dead_organs + if(E.status & ORGAN_DEAD) + var/image/radial_button = image(icon = E.icon, icon_state = E.icon_state) + radial_button.name = "Debride \the [E]" + LAZYSET(dead_organs, E.organ_tag, radial_button) + + for(var/obj/item/organ/internal/I in E.internal_organs) + if(I && (I.status & ORGAN_DEAD) && I.parent_organ == target_zone) + var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) + radial_button.name = "Debride \the [I]" + LAZYSET(dead_organs, I.organ_tag, radial_button) + + if(!LAZYLEN(dead_organs)) + to_chat(user, SPAN_WARNING("You can't find any dead tissue to remove.")) + else + if(length(dead_organs) == 1) + return dead_organs[1] + return show_radial_menu(user, tool, dead_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) + return FALSE + +/decl/surgery_step/necrotic/tissue/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(affected) + var/target_organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) + user.visible_message( + "\The [user] slowly starts removing necrotic tissue from \the [target]'s [target_organ] with \the [tool].", \ + "You slowly start removing necrotic tissue from \the [target]'s [target_organ] with \the [tool].") + target.custom_pain("You feel sporadic spikes of pain from points around your [affected.name]!",20, affecting = affected) + ..() + +/decl/surgery_step/necrotic/tissue/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/target_organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) + user.visible_message( + SPAN_NOTICE("\The [user] has excised the necrotic tissue from \the [target]'s [target_organ] with \the [tool]."), \ + SPAN_NOTICE("You have excised the necrotic tissue from \the [target]'s [target_organ] with \the [tool].")) + + var/obj/item/organ/O = target.get_organ(LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)) + if(O) + O.germ_level = min(INFECTION_LEVEL_ONE, O.germ_level * 0.4) + if(istype(O,/obj/item/organ/external)) + var/obj/item/organ/external/E = O + E.disinfect() + ..() + +/decl/surgery_step/necrotic/tissue/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(affected) + user.visible_message( + SPAN_DANGER("\The [user]'s hand slips, slicing into a healthy portion of \the [target]'s [affected.name] with \the [tool]!"), + SPAN_DANGER("Your hand slips, slicing into a healthy portion of [target]'s [affected.name] with \the [tool]!")) + affected.take_damage(10, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() + +////////////////////////////////////////////////////////////////// +// Dead organ regeneration treatment +////////////////////////////////////////////////////////////////// +/decl/surgery_step/necrotic/regeneration + name = "Regenerate tissue" + description = "This procedure uses direct regeneration serum application to bring back organs and tissue from necrosis." + min_duration = 90 + max_duration = 100 + allowed_tools = list( + /obj/item/chems/spray = 100, + /obj/item/chems/dropper = 100, + /obj/item/chems/glass/bottle = 90, + /obj/item/chems/drinks/flask = 90, + /obj/item/chems/glass/beaker = 75, + /obj/item/chems/drinks/bottle = 75, + /obj/item/chems/drinks/glass2 = 75, + /obj/item/chems/glass/bucket = 50 + ) + +/decl/surgery_step/necrotic/regeneration/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) + . = ..() + if(.) + var/obj/item/organ/external/affected = . + if(affected.status & ORGAN_DEAD) + return TRUE + for(var/obj/item/organ/O in affected.internal_organs) + if(O.status & ORGAN_DEAD) + return TRUE + return FALSE + +/decl/surgery_step/necrotic/regeneration/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/chems/C = tool + if(!(ATOM_IS_OPEN_CONTAINER(C) && C.reagents.has_reagent(/decl/material/liquid/regenerator, 5))) + to_chat(user, SPAN_WARNING("\The [tool] doesn't have enough chemicals to regenerate anything.")) + return FALSE + + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone) + if(!E) + to_chat(user, SPAN_WARNING("\The [target] is missing that limb.")) + return FALSE + + var/list/dead_organs + if(E.status & ORGAN_DEAD) + var/image/radial_button = image(icon = E.icon, icon_state = E.icon_state) + radial_button.name = "Regenerate \the [E]" + LAZYSET(dead_organs, E.organ_tag, radial_button) + + for(var/obj/item/organ/I in target.get_internal_organs()) + if(I && (I.status & ORGAN_DEAD) && I.parent_organ == target_zone) + if(!I.can_recover()) + to_chat(user, SPAN_WARNING("\The [I] is beyond saving.")) + var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) + radial_button.name = "Regenerate \the [I]" + LAZYSET(dead_organs, I.organ_tag, radial_button) + + if(!LAZYLEN(dead_organs)) + to_chat(user, SPAN_WARNING("You can't find any organs to regenerate.")) + else + if(length(dead_organs) == 1) + return dead_organs[1] + return show_radial_menu(user, tool, dead_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) + return FALSE + +/decl/surgery_step/necrotic/regeneration/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(affected) + user.visible_message( + "[user] starts pouring [tool]'s contents on \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)].", + "You start pouring [tool]'s contents on \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)].") + target.custom_pain("Your [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] is on fire!",50,affecting = affected) + ..() + +/decl/surgery_step/necrotic/regeneration/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/target_organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) + var/obj/item/chems/C = tool + var/temp_holder = new /obj() + var/amount = C.amount_per_transfer_from_this + var/datum/reagents/temp_reagents = new /datum/reagents(amount, temp_holder) + C.reagents.trans_to_holder(temp_reagents, amount) + var/usable_amount = temp_reagents.has_reagent(/decl/material/liquid/regenerator) + temp_reagents.clear_reagent(/decl/material/liquid/regenerator) //We'll manually calculate how much it should heal + temp_reagents.trans_to_mob(target, REAGENT_TOTAL_VOLUME(temp_reagents), CHEM_INJECT) //And if there was something else, toss it in + + if (usable_amount > 1) + var/obj/item/organ/O = target.get_organ(target_organ) + if(O) + user.visible_message( + SPAN_NOTICE("\The [user] finishes applying \the [tool]'s contents to \the [target]'s [O.name]."), \ + SPAN_NOTICE("You treat \the [target]'s [O.name] with \the [tool]'s contents.")) + + O &= ~ORGAN_DEAD + O.heal_damage(O.max_damage * (0.75 * (usable_amount / 5))) //Assuming they're using a dropper and completely pure chems, put the organ back to a working point + else + to_chat(user,SPAN_WARNING("You transferred too little for the organ to regenerate!")) + qdel(temp_reagents) + qdel(temp_holder) + ..() + +/decl/surgery_step/necrotic/regeneration/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + if(!istype(tool) || !tool.reagents) + return + var/obj/item/chems/container = tool + tool.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_INJECT) + var/obj/item/organ/affected = target.get_organ(LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)) + if(affected) + user.visible_message( + SPAN_DANGER("\The [user]'s hand slips, spilling \the [tool]'s contents over the [target]'s [affected.name]!"), + SPAN_DANGER("Your hand slips, spilling \the [tool]'s contents over the [target]'s [affected.name]!")) + ..() diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 2a300292964a..4d25ab85a850 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -7,7 +7,9 @@ blood_level = 1 shock_level = 40 delicate = 1 - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT + abstract_type = /decl/surgery_step/internal + end_step_sound = 'sound/effects/squelch1.ogg' ////////////////////////////////////////////////////////////////// // Organ mending surgery step @@ -16,121 +18,125 @@ name = "Repair internal organ" description = "This procedure is used to repair damage to the internal organs of a patient." allowed_tools = list( - /obj/item/stack/medical/advanced/bruise_pack = 100, - /obj/item/stack/medical/bruise_pack = 40, - /obj/item/tape_roll = 20 + /obj/item/stack/medical/bandage/advanced = 100, + /obj/item/stack/medical/bandage = 40, + /obj/item/stack/tape_roll/duct_tape = 20 ) min_duration = 70 max_duration = 90 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC -/decl/surgery_step/internal/fix_organ/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/internal/fix_organ/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected) - for(var/obj/item/organ/internal/I in affected.internal_organs) - if(I.damage > 0) - if(I.surface_accessible || (affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(organ.get_organ_damage() > 0) + if(organ.status & ORGAN_DEAD) + to_chat(user, SPAN_WARNING("\The [organ] is [organ.can_recover() ? "decaying" : "necrotic"] and cannot be treated with \the [tool] alone.")) + continue + if(organ.surface_accessible || (affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) return affected -/decl/surgery_step/internal/fix_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/internal/fix_organ/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) var/tool_name = "\the [tool]" - if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + if (istype(tool, /obj/item/stack/medical/bandage/advanced)) tool_name = "regenerative membrane" - else if (istype(tool, /obj/item/stack/medical/bruise_pack)) + else if (istype(tool, /obj/item/stack/medical/bandage)) tool_name = "the bandaid" - var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts treating damage within \the [target]'s [affected.name] with [tool_name].", \ "You start treating damage within \the [target]'s [affected.name] with [tool_name]." ) - for(var/obj/item/organ/internal/I in affected.internal_organs) - if(I && I.damage > 0 && !BP_IS_PROSTHETIC(I) && (!I.status & ORGAN_DEAD || I.can_recover()) && (I.surface_accessible || affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) - user.visible_message("[user] starts treating damage to [target]'s [I.name] with [tool_name].", \ - "You start treating damage to [target]'s [I.name] with [tool_name]." ) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(organ && organ.get_organ_damage() > 0 && !BP_IS_PROSTHETIC(organ) && !(organ.status & ORGAN_DEAD) && (organ.surface_accessible || affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) + user.visible_message("[user] starts treating damage to [target]'s [organ] with [tool_name].", \ + "You start treating damage to [target]'s [organ] with [tool_name]." ) target.custom_pain("The pain in your [affected.name] is living hell!",100,affecting = affected) ..() -/decl/surgery_step/internal/fix_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/internal/fix_organ/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/tool_name = "\the [tool]" - if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + if (istype(tool, /obj/item/stack/medical/bandage/advanced)) tool_name = "regenerative membrane" - if (istype(tool, /obj/item/stack/medical/bruise_pack)) + if (istype(tool, /obj/item/stack/medical/bandage)) tool_name = "the bandaid" - var/obj/item/organ/external/affected = target.get_organ(target_zone) - for(var/obj/item/organ/internal/I in affected.internal_organs) - if(I && I.damage > 0 && !BP_IS_PROSTHETIC(I) && (I.surface_accessible || affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) - if(I.status & ORGAN_DEAD && I.can_recover()) - user.visible_message("\The [user] treats damage to [target]'s [I.name] with [tool_name], though it needs to be recovered further.", \ - "You treat damage to [target]'s [I.name] with [tool_name], though it needs to be recovered further." ) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(organ && organ.get_organ_damage() > 0 && !BP_IS_PROSTHETIC(organ) && (organ.surface_accessible || affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) + if(organ.status & ORGAN_DEAD) + to_chat(user, SPAN_NOTICE("You were unable to treat \the [organ] due to its necrotic state.")) else - user.visible_message("[user] treats damage to [target]'s [I.name] with [tool_name].", \ - "You treat damage to [target]'s [I.name] with [tool_name]." ) - I.surgical_fix(user) + user.visible_message("[user] treats damage to [target]'s [organ] with [tool_name].", \ + "You treat damage to [target]'s [organ] with [tool_name]." ) + organ.surgical_fix(user) user.visible_message("\The [user] finishes treating damage within \the [target]'s [affected.name] with [tool_name].", \ "You finish treating damage within \the [target]'s [affected.name] with [tool_name]." ) + ..() -/decl/surgery_step/internal/fix_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/internal/fix_organ/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, getting mess and tearing the inside of [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, getting mess and tearing the inside of [target]'s [affected.name] with \the [tool]!") var/dam_amt = 2 - if(istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) - target.adjustToxLoss(5) + if(istype(tool, /obj/item/stack/medical/bandage/advanced)) + target.take_damage(5, TOX) else dam_amt = 5 - target.adjustToxLoss(10) - affected.take_external_damage(dam_amt, 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) - for(var/obj/item/organ/internal/I in affected.internal_organs) - if(I && I.damage > 0 && !BP_IS_PROSTHETIC(I) && (I.surface_accessible || affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) - I.take_internal_damage(dam_amt) + target.take_damage(10, TOX) + affected.take_damage(dam_amt, damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(organ && organ.get_organ_damage() > 0 && !BP_IS_PROSTHETIC(organ) && (organ.surface_accessible || affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED))) + organ.take_damage(dam_amt) + ..() ////////////////////////////////////////////////////////////////// -// Organ detatchment surgery step +// Organ detachment surgery step ////////////////////////////////////////////////////////////////// -/decl/surgery_step/internal/detatch_organ +/decl/surgery_step/internal/detach_organ name = "Detach organ" description = "This procedure detaches an internal organ for removal." - allowed_tools = list( - /obj/item/scalpel = 100, - /obj/item/shard = 50 - ) + allowed_tools = list(TOOL_SCALPEL = 100) min_duration = 90 max_duration = 110 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT -/decl/surgery_step/internal/detatch_organ/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/internal/detach_organ/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/list/attached_organs - for(var/organ in target.internal_organs_by_name) - var/obj/item/organ/I = target.internal_organs_by_name[organ] - if(I && !(I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone) - var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) - radial_button.name = "Detach \the [I.name]" - LAZYSET(attached_organs, organ, radial_button) + for(var/obj/item/organ/organ in target.get_internal_organs()) + if(organ && !(organ.status & ORGAN_CUT_AWAY) && organ.parent_organ == target_zone) + var/image/radial_button = image(icon = organ.icon, icon_state = organ.icon_state) + radial_button.name = "Detach \the [organ]" + LAZYSET(attached_organs, organ.organ_tag, radial_button) if(!LAZYLEN(attached_organs)) to_chat(user, SPAN_WARNING("You can't find any organs to separate.")) else if(length(attached_organs) == 1) return attached_organs[1] - return show_radial_menu(user, tool, attached_organs, radius = 42, require_near = TRUE, use_labels = TRUE, check_locs = list(tool)) + return show_radial_menu(user, tool, attached_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) return FALSE -/decl/surgery_step/internal/detatch_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts to separate [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].", \ - "You start to separate [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool]." ) - target.custom_pain("Someone's ripping out your [LAZYACCESS(target.surgeries_in_progress, target_zone)]!",100) +/decl/surgery_step/internal/detach_organ/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] starts to separate [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \ + "You start to separate [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool]." ) + target.custom_pain("Someone's ripping out your [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)]!",100) ..() -/decl/surgery_step/internal/detatch_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] has separated [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool]." , \ - "You have separated [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") - - var/obj/item/organ/I = target.internal_organs_by_name[LAZYACCESS(target.surgeries_in_progress, target_zone)] - if(I && istype(I)) - I.cut_away(user) +/decl/surgery_step/internal/detach_organ/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] has separated [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool]." , \ + "You have separated [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") + var/obj/item/organ/internal/organ = GET_INTERNAL_ORGAN(target, LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(organ && istype(organ) && istype(affected)) + //First only detach the organ, without fully removing it + target.remove_organ(organ, FALSE, TRUE) + ..() -/decl/surgery_step/internal/detatch_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user]'s hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!", \ - "Your hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(rand(30,50), 0, (DAM_SHARP|DAM_EDGE), used_weapon = tool) +/decl/surgery_step/internal/detach_organ/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(affected) + user.visible_message("[user]'s hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!", \ + "Your hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!") + affected.take_damage(rand(30,50), damage_flags = (DAM_SHARP|DAM_EDGE), inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // Organ removal surgery step @@ -139,78 +145,65 @@ name = "Remove internal organ" description = "This procedure removes a detached internal organ." allowed_tools = list( - /obj/item/hemostat = 100, - /obj/item/wirecutters = 75, - /obj/item/knife = 75, - /obj/item/kitchen/utensil/fork = 20 + TOOL_HEMOSTAT = 100, + TOOL_WIRECUTTERS = 75 ) min_duration = 60 max_duration = 80 -/decl/surgery_step/internal/remove_organ/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/internal/remove_organ/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) var/list/removable_organs - for(var/obj/item/organ/internal/I in affected.implants) - if(I.status & ORGAN_CUT_AWAY) - var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) - radial_button.name = "Remove \the [I.name]" - LAZYSET(removable_organs, I, radial_button) + for(var/obj/item/organ/internal/organ in affected.implants) + if(organ.status & ORGAN_CUT_AWAY) + var/image/radial_button = image(icon = organ.icon, icon_state = organ.icon_state) + radial_button.name = "Remove \the [organ]" + LAZYSET(removable_organs, organ, radial_button) if(!LAZYLEN(removable_organs)) to_chat(user, SPAN_WARNING("You can't find any removable organs.")) else if(length(removable_organs) == 1) return removable_organs[1] - return show_radial_menu(user, tool, removable_organs, radius = 42, require_near = TRUE, use_labels = TRUE, check_locs = list(tool)) + return show_radial_menu(user, tool, removable_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) return FALSE -/decl/surgery_step/internal/remove_organ/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - var/target_zone = user.zone_sel.selecting - var/obj/item/organ/internal/O = LAZYACCESS(target.surgeries_in_progress, target_zone) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(BP_IS_PROSTHETIC(O)) +/decl/surgery_step/internal/remove_organ/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + var/target_zone = user.get_target_zone() + var/obj/item/organ/internal/organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(BP_IS_PROSTHETIC(organ)) if(BP_IS_PROSTHETIC(affected)) return SURGERY_SKILLS_ROBOTIC else return SURGERY_SKILLS_ROBOTIC_ON_MEAT else return ..() - -/decl/surgery_step/internal/remove_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("\The [user] starts removing [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].", \ - "You start removing \the [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") + +/decl/surgery_step/internal/remove_organ/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("\The [user] starts removing [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \ + "You start removing \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") target.custom_pain("The pain in your [affected.name] is living hell!",100,affecting = affected) ..() -/decl/surgery_step/internal/remove_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\The [user] has removed \the [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].", \ - "You have removed \the [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") - +/decl/surgery_step/internal/remove_organ/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("\The [user] has removed \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \ + "You have removed \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") // Extract the organ! - var/obj/item/organ/O = LAZYACCESS(target.surgeries_in_progress, target_zone) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(istype(O) && istype(affected)) - affected.implants -= O - O.dropInto(target.loc) - if(!BP_IS_PROSTHETIC(affected)) - playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1) - else - playsound(target.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(istype(O, /obj/item/organ/internal/mmi_holder)) - var/obj/item/organ/internal/mmi_holder/brain = O - brain.transfer_and_delete() - - // Just in case somehow the organ we're extracting from an organic is an MMI - if(istype(O, /obj/item/organ/internal/mmi_holder)) - var/obj/item/organ/internal/mmi_holder/brain = O - brain.transfer_and_delete() + var/obj/item/organ/organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(istype(organ) && istype(affected)) + //Now call remove again with detach = FALSE so we fully remove it + target.remove_organ(organ, TRUE, FALSE) + ..() -/decl/surgery_step/internal/remove_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/internal/remove_organ/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, damaging [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, damaging [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(20, used_weapon = tool) + affected.take_damage(20, inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // Organ inserting surgery step @@ -225,10 +218,10 @@ max_duration = 80 var/robotic_surgery = FALSE -/decl/surgery_step/internal/replace_organ/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - var/obj/item/organ/internal/O = tool - var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) - if(BP_IS_PROSTHETIC(O) || istype(O, /obj/item/organ/internal/augment)) +/decl/surgery_step/internal/replace_organ/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + var/obj/item/organ/internal/organ = tool + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, user.get_target_zone()) + if(BP_IS_PROSTHETIC(organ)) if(BP_IS_PROSTHETIC(affected)) return SURGERY_SKILLS_ROBOTIC else @@ -236,82 +229,98 @@ else return ..() -/decl/surgery_step/internal/replace_organ/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - . = FALSE - var/obj/item/organ/internal/O = tool - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(istype(O) && istype(affected)) - if(BP_IS_CRYSTAL(O) && !BP_IS_CRYSTAL(affected)) - to_chat(user, SPAN_WARNING("You cannot install a crystalline organ into a non-crystalline bodypart.")) - else if(!BP_IS_CRYSTAL(O) && BP_IS_CRYSTAL(affected)) - to_chat(user, SPAN_WARNING("You cannot install a non-crystalline organ into a crystalline bodypart.")) - else if(BP_IS_PROSTHETIC(affected) && !BP_IS_PROSTHETIC(O)) - to_chat(user, SPAN_WARNING("You cannot install a naked organ into a robotic body.")) - else if(!target.species) - CRASH("Target ([target]) of surgery [type] has no species!") - else - var/o_is = (O.gender == PLURAL) ? "are" : "is" - var/o_a = (O.gender == PLURAL) ? "" : "a " - if(O.organ_tag == BP_POSIBRAIN && !target.species.has_organ[BP_POSIBRAIN]) - to_chat(user, SPAN_WARNING("There's no place in [target] to fit \the [O.organ_tag].")) - else if(O.damage > (O.max_damage * 0.75)) - to_chat(user, SPAN_WARNING("\The [O.name] [o_is] in no state to be transplanted.")) - else if(O.w_class > affected.cavity_max_w_class) - to_chat(user, SPAN_WARNING("\The [O.name] [o_is] too big for [affected.cavity_name] cavity!")) - else - var/obj/item/organ/internal/I = target.internal_organs_by_name[O.organ_tag] - if(I && (I.parent_organ == affected.organ_tag)) - to_chat(user, SPAN_WARNING("\The [target] already has [o_a][O.name].")) - else - . = TRUE - -/decl/surgery_step/internal/replace_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts [robotic_surgery ? "reinstalling" : "transplanting"] \the [tool] into [target]'s [affected.name].", \ - "You start [robotic_surgery ? "reinstalling" : "transplanting"] \the [tool] into [target]'s [affected.name].") +/decl/surgery_step/internal/replace_organ/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + + var/obj/item/organ/internal/organ = tool + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(!istype(organ) || !istype(affected)) + return FALSE + + if(BP_IS_CRYSTAL(organ) && !BP_IS_CRYSTAL(affected)) + to_chat(user, SPAN_WARNING("You cannot install a crystalline organ into a non-crystalline bodypart.")) + return FALSE + + if(!BP_IS_CRYSTAL(organ) && BP_IS_CRYSTAL(affected)) + to_chat(user, SPAN_WARNING("You cannot install a non-crystalline organ into a crystalline bodypart.")) + return FALSE + + if(BP_IS_PROSTHETIC(affected) && !BP_IS_PROSTHETIC(organ)) + to_chat(user, SPAN_WARNING("You cannot install a naked organ into a robotic body.")) + return FALSE + + if(organ.parent_organ != affected.organ_tag) + to_chat(user, SPAN_WARNING("\The [organ] cannot be installed in \the [affected].")) + return FALSE + + if(!target.get_bodytype()) + PRINT_STACK_TRACE("Target ([target]) of surgery [type] has no bodytype!") + return FALSE + + var/decl/pronouns/pronouns = organ.get_pronouns() + if(organ.get_organ_damage() > (organ.max_damage * 0.75)) + to_chat(user, SPAN_WARNING("\The [organ] [pronouns.is] in no state to be transplanted.")) + return FALSE + + if(organ.w_class > affected.cavity_max_w_class) + to_chat(user, SPAN_WARNING("\The [organ] [pronouns.is] too big for \the [affected.cavity_name]!")) + return FALSE + + var/obj/item/organ/internal/existing_organ = GET_INTERNAL_ORGAN(target, organ.organ_tag) + if(existing_organ && (existing_organ.parent_organ == affected.organ_tag)) + to_chat(user, SPAN_WARNING("\The [target] already has \a [existing_organ.name].")) + return FALSE + + return TRUE + +/decl/surgery_step/internal/replace_organ/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("[user] starts [robotic_surgery ? "installing" : "transplanting"] \the [tool] into [target]'s [affected.name].", \ + "You start [robotic_surgery ? "installing" : "transplanting"] \the [tool] into [target]'s [affected.name].") target.custom_pain("Someone's rooting around in your [affected.name]!",100,affecting = affected) ..() -/decl/surgery_step/internal/replace_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("\The [user] has [robotic_surgery ? "reinstalled" : "transplanted"] \the [tool] into [target]'s [affected.name].", \ - "You have [robotic_surgery ? "reinstalled" : "transplanted"] \the [tool] into [target]'s [affected.name].") - var/obj/item/organ/O = tool - if(istype(O) && user.unEquip(O, target)) - affected.implants |= O //move the organ into the patient. The organ is properly reattached in the next step - if(!(O.status & ORGAN_CUT_AWAY)) - log_debug("[user] ([user.ckey]) replaced organ [O], which didn't have ORGAN_CUT_AWAY set, in [target] ([target.ckey])") - O.status |= ORGAN_CUT_AWAY - - playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1) +/decl/surgery_step/internal/replace_organ/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + user.visible_message("\The [user] has [robotic_surgery ? "installed" : "transplanted"] \the [tool] into [target]'s [affected.name].", \ + "You have [robotic_surgery ? "installed" : "transplanted"] \the [tool] into [target]'s [affected.name].") + var/obj/item/organ/organ = tool + if(istype(organ) && user.try_unequip(organ, target)) + //Place the organ but don't attach it yet + target.add_organ(organ, affected, detached = TRUE) + if(BP_IS_PROSTHETIC(affected)) + playsound(target.loc, 'sound/items/Ratchet.ogg', 50, 1) + else + ..() + if(BP_IS_PROSTHETIC(organ) && prob(user.skill_fail_chance(SKILL_DEVICES, 50, SKILL_ADEPT))) + organ.add_random_ailment() -/decl/surgery_step/internal/replace_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/internal/replace_organ/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) user.visible_message("[user]'s hand slips, damaging \the [tool]!", \ "Your hand slips, damaging \the [tool]!") - var/obj/item/organ/internal/I = tool - if(istype(I)) - I.take_internal_damage(rand(3,5)) + var/obj/item/organ/internal/organ = tool + if(istype(organ)) + organ.take_damage(rand(3,5)) + ..() ////////////////////////////////////////////////////////////////// // Organ attachment surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/internal/attach_organ name = "Attach internal organ" - description = "This procedure reattaches a replaced internal organ." + description = "This procedure attaches a replaced internal organ." allowed_tools = list( - /obj/item/sutures = 100, - /obj/item/stack/cable_coil = 75, - /obj/item/tape_roll = 50 + TOOL_SUTURES = 100, + TOOL_CABLECOIL = 75 ) min_duration = 100 max_duration = 120 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NEEDS_ENCASEMENT -/decl/surgery_step/internal/attach_organ/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - var/target_zone = user.zone_sel.selecting - var/obj/item/organ/internal/O = LAZYACCESS(target.surgeries_in_progress, target_zone) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(BP_IS_PROSTHETIC(O)) +/decl/surgery_step/internal/attach_organ/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + var/target_zone = user.get_target_zone() + var/obj/item/organ/internal/organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(BP_IS_PROSTHETIC(organ)) if(BP_IS_PROSTHETIC(affected)) return SURGERY_SKILLS_ROBOTIC else @@ -319,21 +328,24 @@ else return ..() -/decl/surgery_step/internal/attach_organ/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/obj/item/organ/internal/proc/get_attachment_failure_reason(obj/item/organ/external/affected, robotic = FALSE) + return FALSE + +/decl/surgery_step/internal/attach_organ/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/list/attachable_organs - var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) - for(var/obj/item/organ/I in affected.implants) - if(I && (I.status & ORGAN_CUT_AWAY)) - var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) - radial_button.name = "Attach \the [I.name]" - LAZYSET(attachable_organs, I, radial_button) + for(var/obj/item/organ/organ in (affected.implants|affected.internal_organs)) + if(organ.status & ORGAN_CUT_AWAY) + var/image/radial_button = image(icon = organ.icon, icon_state = organ.icon_state) + radial_button.name = "Attach \the [organ]" + LAZYSET(attachable_organs, organ, radial_button) if(!LAZYLEN(attachable_organs)) return FALSE - var/obj/item/organ/organ_to_replace = show_radial_menu(user, tool, attachable_organs, radius = 42, require_near = TRUE, use_labels = TRUE, check_locs = list(tool)) + var/obj/item/organ/internal/organ_to_replace = show_radial_menu(user, tool, attachable_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) if(!organ_to_replace) return FALSE @@ -341,42 +353,45 @@ to_chat(user, SPAN_WARNING("You can't find anywhere to attach \the [organ_to_replace] to!")) return FALSE - if(istype(organ_to_replace, /obj/item/organ/internal/augment)) - var/obj/item/organ/internal/augment/A = organ_to_replace - if(!(A.augment_flags & AUGMENTATION_ORGANIC)) - to_chat(user, SPAN_WARNING("\The [A] cannot function within a non-robotic limb.")) - return FALSE + var/attach_failure_reason = organ_to_replace.get_attachment_failure_reason(affected, robotic = FALSE) // if this returns FALSE, it can attach + if(attach_failure_reason) + to_chat(user, attach_failure_reason) + return FALSE + + var/decl/species/species = target.get_species() + if(!species) + return FALSE - if(BP_IS_PROSTHETIC(organ_to_replace) && target.species.spawn_flags & SPECIES_NO_ROBOTIC_INTERNAL_ORGANS) + if(BP_IS_PROSTHETIC(organ_to_replace) && (species.spawn_flags & SPECIES_NO_ROBOTIC_INTERNAL_ORGANS)) user.visible_message("[target]'s biology has rejected the attempts to attach \the [organ_to_replace].") return FALSE - var/obj/item/organ/internal/I = target.internal_organs_by_name[organ_to_replace.organ_tag] - if(I && (I.parent_organ == affected.organ_tag)) + var/obj/item/organ/internal/organ = GET_INTERNAL_ORGAN(target, organ_to_replace.organ_tag) + if(organ && (organ.parent_organ == affected.organ_tag)) to_chat(user, SPAN_WARNING("\The [target] already has \a [organ_to_replace].")) return FALSE return organ_to_replace -/decl/surgery_step/internal/attach_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] begins reattaching [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].", \ - "You start reattaching [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") - target.custom_pain("Someone's digging needles into your [LAZYACCESS(target.surgeries_in_progress, target_zone)]!",100) +/decl/surgery_step/internal/attach_organ/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] begins reattaching [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \ + "You start reattaching [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") + target.custom_pain("Someone's digging needles into your [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)]!",100) ..() -/decl/surgery_step/internal/attach_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/I = LAZYACCESS(target.surgeries_in_progress, target_zone) +/decl/surgery_step/internal/attach_organ/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) - user.visible_message("[user] has reattached [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool]." , \ - "You have reattached [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") + user.visible_message("[user] has attached [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool]." , \ + "You have attached [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(istype(I) && I.parent_organ == target_zone && affected && (I in affected.implants)) - I.status &= ~ORGAN_CUT_AWAY //apply sutures - affected.implants -= I - I.replaced(target, affected) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(istype(organ) && organ.parent_organ == target_zone && affected && (organ in affected.implants)) + target.add_organ(organ, affected, detached = FALSE) + ..() -/decl/surgery_step/internal/attach_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/internal/attach_organ/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!") - affected.take_external_damage(20, used_weapon = tool) + affected.take_damage(20, inflicter = tool) + ..() diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm index b1fa4c2cd62b..f172fa0e5999 100644 --- a/code/modules/surgery/other.dm +++ b/code/modules/surgery/other.dm @@ -10,9 +10,8 @@ name = "Repair tendon" description = "This procedure repairs damage to a tendon." allowed_tools = list( - /obj/item/sutures = 100, - /obj/item/stack/cable_coil = 75, - /obj/item/tape_roll = 50 + TOOL_SUTURES = 100, + TOOL_CABLECOIL = 75 ) can_infect = 1 blood_level = 1 @@ -20,32 +19,34 @@ max_duration = 90 shock_level = 40 delicate = 1 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_RETRACTED + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NEEDS_RETRACTED -/decl/surgery_step/fix_tendon/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/fix_tendon/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && (affected.status & ORGAN_TENDON_CUT)) return affected -/decl/surgery_step/fix_tendon/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_tendon/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts reattaching the damaged [affected.tendon_name] in [target]'s [affected.name] with \the [tool]." , \ "You start reattaching the damaged [affected.tendon_name] in [target]'s [affected.name] with \the [tool].") target.custom_pain("The pain in your [affected.name] is unbearable!",100,affecting = affected) ..() -/decl/surgery_step/fix_tendon/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_tendon/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] has reattached the [affected.tendon_name] in [target]'s [affected.name] with \the [tool].", \ "You have reattached the [affected.tendon_name] in [target]'s [affected.name] with \the [tool].") affected.status &= ~ORGAN_TENDON_CUT affected.update_damages() + ..() -/decl/surgery_step/fix_tendon/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_tendon/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") - affected.take_external_damage(5, used_weapon = tool) + affected.take_damage(5, inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// // IB fix surgery step @@ -54,9 +55,8 @@ name = "Repair arterial bleeding" description = "This procedure repairs damage to an artery." allowed_tools = list( - /obj/item/sutures = 100, - /obj/item/stack/cable_coil = 75, - /obj/item/tape_roll = 50 + TOOL_SUTURES = 100, + TOOL_CABLECOIL = 75 ) can_infect = 1 blood_level = 1 @@ -65,32 +65,34 @@ shock_level = 40 delicate = 1 strict_access_requirement = FALSE - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NO_STUMP | SURGERY_NEEDS_RETRACTED + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_ROBOTIC | SURGERY_NEEDS_RETRACTED -/decl/surgery_step/fix_vein/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/fix_vein/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && (affected.status & ORGAN_ARTERY_CUT)) return affected -/decl/surgery_step/fix_vein/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_vein/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts patching the damaged [affected.artery_name] in [target]'s [affected.name] with \the [tool]." , \ "You start patching the damaged [affected.artery_name] in [target]'s [affected.name] with \the [tool].") target.custom_pain("The pain in your [affected.name] is unbearable!",100,affecting = affected) ..() -/decl/surgery_step/fix_vein/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_vein/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] has patched the [affected.artery_name] in [target]'s [affected.name] with \the [tool].", \ "You have patched the [affected.artery_name] in [target]'s [affected.name] with \the [tool].") affected.status &= ~ORGAN_ARTERY_CUT affected.update_damages() + ..() -/decl/surgery_step/fix_vein/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/fix_vein/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") - affected.take_external_damage(5, used_weapon = tool) + affected.take_damage(5, inflicter = tool) + ..() ////////////////////////////////////////////////////////////////// @@ -98,10 +100,10 @@ ////////////////////////////////////////////////////////////////// /decl/surgery_step/hardsuit name = "Remove hardsuit" + description = "This procedure cuts through the bolts on a hardsuit, allowing it to be removed." allowed_tools = list( - /obj/item/weldingtool = 80, - /obj/item/circular_saw = 60, - /obj/item/gun/energy/plasmacutter = 30 + TOOL_WELDER = 80, + TOOL_SAW = 60 ) can_infect = 0 blood_level = 0 @@ -110,38 +112,41 @@ surgery_candidate_flags = 0 hidden_from_codex = TRUE -/decl/surgery_step/hardsuit/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/hardsuit/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) return TRUE -/decl/surgery_step/hardsuit/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - return list(SKILL_EVA = SKILL_BASIC) +/decl/surgery_step/hardsuit/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + return list(SKILL_EVA = SKILL_BASIC) -/decl/surgery_step/hardsuit/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/hardsuit/can_use(mob/living/user, mob/living/target, target_zone, obj/item/tool) if(!istype(target)) return FALSE - if(isWelder(tool)) + if(IS_WELDER(tool)) var/obj/item/weldingtool/welder = tool - if(!welder.isOn() || !welder.remove_fuel(1,user)) + if(!welder.isOn() || !welder.weld(1,user)) return FALSE - return (target_zone == BP_CHEST) && istype(target.back, /obj/item/rig) && !(target.back.canremove) + var/obj/item/rig/rig = target.get_rig() + return (target_zone == BP_CHEST) && rig && !(rig.canremove) -/decl/surgery_step/hardsuit/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting through the support systems of [target]'s [target.back] with \the [tool]." , \ - "You start cutting through the support systems of [target]'s [target.back] with \the [tool].") +/decl/surgery_step/hardsuit/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/rig/rig = target.get_rig() + user.visible_message("[user] starts cutting through the support systems of [target]'s [rig] with \the [tool]." , \ + "You start cutting through the support systems of [target]'s [rig] with \the [tool].") ..() -/decl/surgery_step/hardsuit/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/hardsuit/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) - var/obj/item/rig/rig = target.back - if(!istype(rig)) - return - rig.reset() + var/obj/item/rig/rig = target.get_rig() + if(rig) + rig.reset() user.visible_message("[user] has cut through the support systems of [target]'s [rig] with \the [tool].", \ "You have cut through the support systems of [target]'s [rig] with \the [tool].") + ..() -/decl/surgery_step/hardsuit/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/hardsuit/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) user.visible_message("[user]'s [tool] can't quite seem to get through the metal...", \ "Your [tool] can't quite seem to get through the metal. It's weakening, though - try again.") + ..() ////////////////////////////////////////////////////////////////// @@ -149,79 +154,101 @@ ////////////////////////////////////////////////////////////////// /decl/surgery_step/sterilize name = "Sterilize wound" - description = "This procedure sterilizes a wound with alcohol." + description = "This procedure sterilizes a wound with antiseptic substances such as alcohol or raw honey." allowed_tools = list( /obj/item/chems/spray = 100, /obj/item/chems/dropper = 100, /obj/item/chems/glass/bottle = 90, - /obj/item/chems/food/drinks/flask = 90, + /obj/item/chems/drinks/flask = 90, /obj/item/chems/glass/beaker = 75, - /obj/item/chems/food/drinks/bottle = 75, - /obj/item/chems/food/drinks/glass2 = 75, + /obj/item/chems/drinks/bottle = 75, + /obj/item/chems/drinks/glass2 = 75, /obj/item/chems/glass/bucket = 50 ) + var/list/skip_open_container_checks = list( + /obj/item/chems/spray, + /obj/item/chems/dropper + ) + var/list/sterilizing_reagents = list( + /decl/material/liquid/nutriment/honey, + /decl/material/liquid/antiseptic + ) + can_infect = 0 blood_level = 0 min_duration = 50 max_duration = 60 -/decl/surgery_step/sterilize/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/sterilize/Initialize() + . = ..() + for(var/decl/material/liquid/alcohol/booze in decls_repository.get_decls_of_subtype_unassociated(/decl/material/liquid/alcohol)) + if(booze.strength <= 40) + sterilizing_reagents |= booze.type + +/decl/surgery_step/sterilize/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && !affected.is_disinfected() && check_chemicals(tool)) return affected -/decl/surgery_step/sterilize/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - return list(SKILL_MEDICAL = SKILL_BASIC) +/decl/surgery_step/sterilize/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + return list(SKILL_MEDICAL = SKILL_BASIC) -/decl/surgery_step/sterilize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/sterilize/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts pouring [tool]'s contents on \the [target]'s [affected.name]." , \ "You start pouring [tool]'s contents on \the [target]'s [affected.name].") target.custom_pain("Your [affected.name] is on fire!",50,affecting = affected) ..() -/decl/surgery_step/sterilize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - - if (!istype(tool, /obj/item/chems)) - return - +/decl/surgery_step/sterilize/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/obj/item/chems/container = tool - var/amount = container.amount_per_transfer_from_this var/temp_holder = new/obj() var/datum/reagents/temp_reagents = new(amount, temp_holder) container.reagents.trans_to_holder(temp_reagents, amount) - - var/trans = temp_reagents.trans_to_mob(target, temp_reagents.total_volume, CHEM_INJECT) //technically it's contact, but the reagents are being applied to internal tissue + var/trans = temp_reagents.trans_to_mob(target, REAGENT_TOTAL_VOLUME(temp_reagents), CHEM_INJECT) //technically it's contact, but the reagents are being applied to internal tissue if (trans > 0) user.visible_message("[user] rubs [target]'s [affected.name] down with \the [tool]'s contents.", \ "You rub [target]'s [affected.name] down with \the [tool]'s contents.") affected.disinfect() qdel(temp_reagents) qdel(temp_holder) + ..() -/decl/surgery_step/sterilize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - - if (!istype(tool, /obj/item/chems)) - return - +/decl/surgery_step/sterilize/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) var/obj/item/chems/container = tool - container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_INJECT) - user.visible_message("[user]'s hand slips, spilling \the [tool]'s contents over the [target]'s [affected.name]!" , \ "Your hand slips, spilling \the [tool]'s contents over the [target]'s [affected.name]!") affected.disinfect() + ..() /decl/surgery_step/sterilize/proc/check_chemicals(var/obj/item/chems/container) - if(istype(container) && ATOM_IS_OPEN_CONTAINER(container)) - if(container.reagents.has_reagent(/decl/material/liquid/antiseptic)) - return TRUE - else - for(var/rtype in container?.reagents?.reagent_volumes) - var/decl/material/liquid/ethanol/booze = decls_repository.get_decl(rtype) - if(istype(booze) && booze.strength <= 40) - return TRUE - return FALSE \ No newline at end of file + + if(!istype(container) || QDELETED(container)) + return FALSE + + var/valid_container = ATOM_IS_OPEN_CONTAINER(container) + if(!valid_container) + for(var/check_type in skip_open_container_checks) + if(istype(container, check_type)) + valid_container = TRUE + break + + if(!valid_container) + return FALSE + + if(!REAGENT_TOTAL_VOLUME(container.reagents)) + return FALSE + + // This check means it's impure. + if(length(REAGENT_VOLUMES(container.reagents)) > length(sterilizing_reagents)) + return FALSE + + // Check if we have sterilizing reagents and -only- sterilizing reagents. + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(container.reagents)) + if(!(reagent in sterilizing_reagents)) + return FALSE + . = TRUE diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index 4cc9aec1519e..ce4bd511bd65 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -1,4 +1,4 @@ -//Procedures in this file: Robotic surgery steps, organ removal, replacement. MMI insertion, synthetic organ repair. +//Procedures in this file: Robotic surgery steps, organ removal, replacement, synthetic organ repair. ////////////////////////////////////////////////////////////////// // ROBOTIC SURGERY // ////////////////////////////////////////////////////////////////// @@ -8,17 +8,19 @@ ////////////////////////////////////////////////////////////////// /decl/surgery_step/robotics can_infect = 0 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH + abstract_type = /decl/surgery_step/robotics + end_step_sound = 'sound/items/Screwdriver.ogg' -decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) return SURGERY_SKILLS_ROBOTIC -/decl/surgery_step/robotics/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && !(affected.status & ORGAN_CUT_AWAY)) return affected -/decl/surgery_step/robotics/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/robotics/success_chance(mob/living/user, mob/living/target, obj/item/tool) . = ..() //Compensating for anatomy skill req in base proc . += 10 @@ -35,35 +37,33 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum /decl/surgery_step/robotics/unscrew_hatch name = "Unscrew maintenance hatch" description = "This procedure unsecures the maintenance hatch of a robotic prosthetic." - allowed_tools = list( - /obj/item/screwdriver = 100, - /obj/item/coin = 50, - /obj/item/knife = 50 - ) + allowed_tools = list(TOOL_SCREWDRIVER = 100) min_duration = 90 max_duration = 110 -/decl/surgery_step/robotics/unscrew_hatch/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/unscrew_hatch/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.hatch_state == HATCH_CLOSED) return affected -/decl/surgery_step/robotics/unscrew_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/unscrew_hatch/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts to unscrew the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ "You start to unscrew the maintenance hatch on [target]'s [affected.name] with \the [tool].") ..() -/decl/surgery_step/robotics/unscrew_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/unscrew_hatch/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] has opened the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ "You have opened the maintenance hatch on [target]'s [affected.name] with \the [tool].",) affected.hatch_state = HATCH_UNSCREWED + ..() -/decl/surgery_step/robotics/unscrew_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/unscrew_hatch/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("\The [user]'s [tool.name] slips, failing to unscrew \the [target]'s [affected.name].", \ "Your [tool.name] slips, failing to unscrew [target]'s [affected.name].") + ..() ////////////////////////////////////////////////////////////////// // screw robotic limb hatch surgery step @@ -71,35 +71,33 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum /decl/surgery_step/robotics/screw_hatch name = "Secure maintenance hatch" description = "This procedure screws shut the maintenance hatch of a robotic prosthetic." - allowed_tools = list( - /obj/item/screwdriver = 100, - /obj/item/coin = 50, - /obj/item/knife = 50 - ) + allowed_tools = list(TOOL_SCREWDRIVER = 100) min_duration = 90 max_duration = 110 -/decl/surgery_step/robotics/screw_hatch/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/screw_hatch/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.hatch_state == HATCH_UNSCREWED) return affected -/decl/surgery_step/robotics/screw_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/screw_hatch/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts to screw down the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ "You start to screw down the maintenance hatch on [target]'s [affected.name] with \the [tool].") ..() -/decl/surgery_step/robotics/screw_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/screw_hatch/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] has screwed down the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ "You have screwed down the maintenance hatch on [target]'s [affected.name] with \the [tool].",) affected.hatch_state = HATCH_CLOSED + ..() -/decl/surgery_step/robotics/screw_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/screw_hatch/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s [tool.name] slips, failing to screw down [target]'s [affected.name].", \ "Your [tool] slips, failing to screw down [target]'s [affected.name].") + ..() ////////////////////////////////////////////////////////////////// // open robotic limb surgery step @@ -108,35 +106,35 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum name = "Open maintenance hatch" description = "This procedure levers open the maintenance hatch of a robotic prosthetic." allowed_tools = list( - /obj/item/retractor = 100, - /obj/item/crowbar = 100, - /obj/item/kitchen/utensil = 50 + TOOL_RETRACTOR = 100, + TOOL_CROWBAR = 100 ) - min_duration = 30 max_duration = 40 -/decl/surgery_step/robotics/open_hatch/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/open_hatch/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.hatch_state == HATCH_UNSCREWED) return affected -/decl/surgery_step/robotics/open_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/open_hatch/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] starts to pry open the maintenance hatch on [target]'s [affected.name] with \the [tool].", "You start to pry open the maintenance hatch on [target]'s [affected.name] with \the [tool].") ..() -/decl/surgery_step/robotics/open_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/open_hatch/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] opens the maintenance hatch on [target]'s [affected.name] with \the [tool].", \ "You open the maintenance hatch on [target]'s [affected.name] with \the [tool].") affected.hatch_state = HATCH_OPENED + ..() -/decl/surgery_step/robotics/open_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/open_hatch/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s [tool.name] slips, failing to open the hatch on [target]'s [affected.name].", "Your [tool] slips, failing to open the hatch on [target]'s [affected.name].") + ..() ////////////////////////////////////////////////////////////////// // close robotic limb surgery step @@ -145,36 +143,37 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum name = "Close maintenance hatch" description = "This procedure closes the maintenance hatch of a robotic prosthetic." allowed_tools = list( - /obj/item/retractor = 100, - /obj/item/crowbar = 100, - /obj/item/kitchen/utensil = 50 + TOOL_RETRACTOR = 100, + TOOL_CROWBAR = 100 ) min_duration = 70 max_duration = 100 -/decl/surgery_step/robotics/close_hatch/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/close_hatch/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.hatch_state == HATCH_OPENED) return affected -/decl/surgery_step/robotics/close_hatch/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/close_hatch/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] begins to close the hatch on [target]'s [affected.name] with \the [tool]." , \ "You begin to close the hatch on [target]'s [affected.name] with \the [tool].") ..() -/decl/surgery_step/robotics/close_hatch/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/close_hatch/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] closes the hatch on [target]'s [affected.name] with \the [tool].", \ "You close the hatch on [target]'s [affected.name] with \the [tool].") affected.hatch_state = HATCH_UNSCREWED affected.germ_level = 0 + ..() -/decl/surgery_step/robotics/close_hatch/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/close_hatch/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s [tool.name] slips, failing to close the hatch on [target]'s [affected.name].", "Your [tool.name] slips, failing to close the hatch on [target]'s [affected.name].") + ..() ////////////////////////////////////////////////////////////////// // robotic limb brute damage repair surgery step @@ -182,21 +181,18 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum /decl/surgery_step/robotics/repair_brute name = "Repair damage to prosthetic" description = "This procedure patches physical damage to a robotic prosthetic." - allowed_tools = list( - /obj/item/weldingtool = 100, - /obj/item/gun/energy/plasmacutter = 50 - ) + allowed_tools = list(TOOL_WELDER = 100) min_duration = 50 max_duration = 60 -/decl/surgery_step/robotics/repair_brute/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/robotics/repair_brute/success_chance(mob/living/user, mob/living/target, obj/item/tool) . = ..() if(user.skill_check(SKILL_CONSTRUCTION, SKILL_BASIC)) . += 10 -/decl/surgery_step/robotics/repair_brute/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brute/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) if(!affected.brute_dam) to_chat(user, SPAN_WARNING("There is no damage to repair.")) @@ -204,9 +200,9 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum if(BP_IS_BRITTLE(affected)) to_chat(user, SPAN_WARNING("\The [target]'s [affected.name] is too brittle to be repaired normally.")) return FALSE - if(isWelder(tool)) + if(IS_WELDER(tool)) var/obj/item/weldingtool/welder = tool - if(!welder.isOn() || !welder.remove_fuel(1,user)) + if(!welder.isOn() || !welder.weld(1,user)) return FALSE if(istype(tool, /obj/item/gun/energy/plasmacutter)) var/obj/item/gun/energy/plasmacutter/cutter = tool @@ -215,29 +211,31 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum return TRUE return FALSE -/decl/surgery_step/robotics/repair_brute/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/repair_brute/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.hatch_state == HATCH_OPENED && ((affected.status & ORGAN_DISFIGURED) || affected.brute_dam > 0)) return affected -/decl/surgery_step/robotics/repair_brute/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brute/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] begins to patch damage to [target]'s [affected.name]'s support structure with \the [tool]." , \ "You begin to patch damage to [target]'s [affected.name]'s support structure with \the [tool].") ..() -/decl/surgery_step/robotics/repair_brute/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brute/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] finishes patching damage to [target]'s [affected.name] with \the [tool].", \ "You finish patching damage to [target]'s [affected.name] with \the [tool].") affected.heal_damage(rand(30,50),0,1,1) affected.status &= ~ORGAN_DISFIGURED + ..() -/decl/surgery_step/robotics/repair_brute/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brute/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s [tool.name] slips, damaging the internal structure of [target]'s [affected.name].", "Your [tool.name] slips, damaging the internal structure of [target]'s [affected.name].") target.apply_damage(rand(5,10), BURN, affected) + ..() ////////////////////////////////////////////////////////////////// // robotic limb brittleness repair surgery step @@ -249,33 +247,35 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum min_duration = 50 max_duration = 60 -/decl/surgery_step/robotics/repair_brittle/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/robotics/repair_brittle/success_chance(mob/living/user, mob/living/target, obj/item/tool) . = ..() if(user.skill_check(SKILL_ELECTRICAL, SKILL_BASIC)) . += 10 -/decl/surgery_step/robotics/repair_brittle/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/repair_brittle/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && BP_IS_BRITTLE(affected) && affected.hatch_state == HATCH_OPENED) return affected -/decl/surgery_step/robotics/repair_brittle/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brittle/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] begins to repair the brittle metal inside \the [target]'s [affected.name]." , \ "You begin to repair the brittle metal inside \the [target]'s [affected.name].") ..() -/decl/surgery_step/robotics/repair_brittle/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brittle/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] finishes repairing the brittle interior of \the [target]'s [affected.name].", \ "You finish repairing the brittle interior of \the [target]'s [affected.name].") affected.status &= ~ORGAN_BRITTLE + ..() -/decl/surgery_step/robotics/repair_brittle/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_brittle/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] causes some of \the [target]'s [affected.name] to crumble!", "You cause some of \the [target]'s [affected.name] to crumble!") target.apply_damage(rand(5,10), BRUTE, affected) + ..() ////////////////////////////////////////////////////////////////// // robotic limb burn damage repair surgery step @@ -283,20 +283,18 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum /decl/surgery_step/robotics/repair_burn name = "Repair burns on prosthetic" description = "This procedure repairs fire or electrical damage to a robotic prosthetic." - allowed_tools = list( - /obj/item/stack/cable_coil = 100 - ) + allowed_tools = list(TOOL_CABLECOIL = 100) min_duration = 50 max_duration = 60 -/decl/surgery_step/robotics/repair_burn/success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/robotics/repair_burn/success_chance(mob/living/user, mob/living/target, obj/item/tool) . = ..() if(user.skill_check(SKILL_ELECTRICAL, SKILL_BASIC)) . += 10 -/decl/surgery_step/robotics/repair_burn/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_burn/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) if(!affected.burn_dam) to_chat(user, SPAN_WARNING("There is no damage to repair.")) @@ -312,29 +310,31 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum return TRUE return FALSE -/decl/surgery_step/robotics/repair_burn/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/repair_burn/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected && affected.hatch_state == HATCH_OPENED && ((affected.status & ORGAN_DISFIGURED) || affected.burn_dam > 0)) return affected -/decl/surgery_step/robotics/repair_burn/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_burn/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] begins to splice new cabling into [target]'s [affected.name]." , \ "You begin to splice new cabling into [target]'s [affected.name].") ..() -/decl/surgery_step/robotics/repair_burn/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_burn/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] finishes splicing cable into [target]'s [affected.name].", \ "You finishes splicing new cable into [target]'s [affected.name].") affected.heal_damage(0,rand(30,50),1,1) affected.status &= ~ORGAN_DISFIGURED + ..() -/decl/surgery_step/robotics/repair_burn/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/repair_burn/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] causes a short circuit in [target]'s [affected.name]!", "You cause a short circuit in [target]'s [affected.name]!") target.apply_damage(rand(5,10), BURN, affected) + ..() ////////////////////////////////////////////////////////////////// // artificial organ repair surgery step @@ -344,276 +344,165 @@ decl/surgery_step/robotics/get_skill_reqs(mob/living/user, mob/living/carbon/hum description = "This procedure repairs damage to a robotic internal organ." allowed_tools = list( /obj/item/stack/nanopaste = 100, - /obj/item/bonegel = 30, - /obj/item/screwdriver = 70, + TOOL_BONE_GEL = 30, + TOOL_SCREWDRIVER = 70 ) min_duration = 70 max_duration = 90 - surgery_candidate_flags = SURGERY_NO_STUMP + surgery_candidate_flags = 0 -/decl/surgery_step/robotics/fix_organ_robotic/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) +/decl/surgery_step/robotics/fix_organ_robotic/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) if(target.isSynthetic()) - return SURGERY_SKILLS_ROBOTIC + return SURGERY_SKILLS_ROBOTIC else - return SURGERY_SKILLS_ROBOTIC_ON_MEAT + return SURGERY_SKILLS_ROBOTIC_ON_MEAT -/decl/surgery_step/robotics/fix_organ_robotic/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/fix_organ_robotic/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = ..() if(affected) - for(var/obj/item/organ/internal/I in affected.internal_organs) - if(BP_IS_PROSTHETIC(I) && !BP_IS_CRYSTAL(I) && I.damage > 0) - if(I.surface_accessible) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(BP_IS_PROSTHETIC(organ) && !BP_IS_CRYSTAL(organ) && organ.get_organ_damage() > 0) + if(organ.surface_accessible) return affected if(affected.how_open() >= (affected.encased ? SURGERY_ENCASED : SURGERY_RETRACTED) || affected.hatch_state == HATCH_OPENED) return affected -/decl/surgery_step/robotics/fix_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - for(var/obj/item/organ/I in affected.internal_organs) - if(I && I.damage > 0) - if(BP_IS_PROSTHETIC(I)) - user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \ - "You start mending the damage to [target]'s [I.name]'s mechanisms." ) +/decl/surgery_step/robotics/fix_organ_robotic/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(organ.get_organ_damage() > 0) + if(BP_IS_PROSTHETIC(organ)) + user.visible_message("[user] starts mending the damage to [target]'s [organ.name]'s mechanisms.", \ + "You start mending the damage to [target]'s [organ.name]'s mechanisms." ) ..() -/decl/surgery_step/robotics/fix_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - for(var/obj/item/organ/I in affected.internal_organs) - if(I && I.damage > 0) - if(BP_IS_PROSTHETIC(I)) - user.visible_message("[user] repairs [target]'s [I.name] with [tool].", \ - "You repair [target]'s [I.name] with [tool]." ) - I.damage = 0 - -/decl/surgery_step/robotics/fix_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/robotics/fix_organ_robotic/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + for(var/obj/item/organ/internal/organ in affected.internal_organs) + if(organ.get_organ_damage() > 0) + if(BP_IS_PROSTHETIC(organ)) + user.visible_message("[user] repairs [target]'s [organ.name] with [tool].", \ + "You repair [target]'s [organ.name] with [tool]." ) + organ.set_organ_damage(0) + ..() + +/decl/surgery_step/robotics/fix_organ_robotic/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user]'s hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!", \ "Your hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!") - target.adjustToxLoss(5) + target.take_damage(5, TOX) affected.createwound(CUT, 5) for(var/internal in affected.internal_organs) var/obj/item/organ/internal/I = internal if(I) - I.take_internal_damage(rand(3,5)) + I.take_damage(rand(3,5)) + ..() ////////////////////////////////////////////////////////////////// // robotic organ detachment surgery step ////////////////////////////////////////////////////////////////// -/decl/surgery_step/robotics/detatch_organ_robotic +/decl/surgery_step/robotics/detach_organ_robotic name = "Decouple prosthetic organ" description = "This procedure decouples a robotic internal organ for removal." allowed_tools = list( - /obj/item/multitool = 100 + TOOL_MULTITOOL = 100 ) min_duration = 90 max_duration = 110 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT -/decl/surgery_step/robotics/detatch_organ_robotic/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/detach_organ_robotic/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/list/attached_organs - for(var/organ in target.internal_organs_by_name) - var/obj/item/organ/I = target.internal_organs_by_name[organ] + for(var/obj/item/organ/I in target.get_internal_organs()) if(I && !(I.status & ORGAN_CUT_AWAY) && !BP_IS_CRYSTAL(I) && I.parent_organ == target_zone) var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) - radial_button.name = "Detach \the [I.name]" - LAZYSET(attached_organs, organ, radial_button) + radial_button.name = "Detach \the [I]" + LAZYSET(attached_organs, I.organ_tag, radial_button) if(!LAZYLEN(attached_organs)) to_chat(user, SPAN_WARNING("There are no appropriate internal components to decouple.")) return FALSE - return show_radial_menu(user, tool, attached_organs, radius = 42, require_near = TRUE, use_labels = TRUE, check_locs = list(tool)) + return show_radial_menu(user, tool, attached_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) -/decl/surgery_step/robotics/detatch_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts to decouple [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].", \ - "You start to decouple [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool]." ) +/decl/surgery_step/robotics/detach_organ_robotic/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] starts to decouple [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \ + "You start to decouple [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool]." ) ..() -/decl/surgery_step/robotics/detatch_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] has decoupled [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool]." , \ - "You have decoupled [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") - - var/obj/item/organ/internal/I = target.internal_organs_by_name[LAZYACCESS(target.surgeries_in_progress, target_zone)] - if(I && istype(I)) - I.cut_away(user) +/decl/surgery_step/robotics/detach_organ_robotic/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] has decoupled [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool]." , \ + "You have decoupled [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") + var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(target, LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + if(I && istype(I) && istype(affected)) + target.remove_organ(I, drop_organ = FALSE, detach = TRUE) + ..() -/decl/surgery_step/robotics/detatch_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user]'s hand slips, disconnecting \the [tool].", \ - "Your hand slips, disconnecting \the [tool].") +/decl/surgery_step/robotics/detach_organ_robotic/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, unseating \the [tool].", \ + "Your hand slips, unseating \the [tool].") + ..() ////////////////////////////////////////////////////////////////// // robotic organ transplant finalization surgery step ////////////////////////////////////////////////////////////////// /decl/surgery_step/robotics/attach_organ_robotic name = "Reattach prosthetic organ" - description = "This procedure reattaches a decoupled robotic internal organ." + description = "This procedure attaches a decoupled robotic internal organ." allowed_tools = list( - /obj/item/screwdriver = 100, + TOOL_SCREWDRIVER = 100, ) min_duration = 100 max_duration = 120 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT -/decl/surgery_step/robotics/attach_organ_robotic/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +/decl/surgery_step/robotics/attach_organ_robotic/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) var/list/removable_organs - var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) for(var/obj/item/organ/I in affected.implants) if ((I.status & ORGAN_CUT_AWAY) && BP_IS_PROSTHETIC(I) && !BP_IS_CRYSTAL(I) && (I.parent_organ == target_zone)) var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state) - radial_button.name = "Reattach \the [I.name]" + radial_button.name = "Reattach \the [I]" LAZYSET(removable_organs, I.organ_tag, radial_button) - var/organ_to_replace = show_radial_menu(user, tool, removable_organs, radius = 42, require_near = TRUE, use_labels = TRUE, check_locs = list(tool)) + var/obj/item/organ/internal/organ_to_replace = show_radial_menu(user, tool, removable_organs, radius = 42, require_near = TRUE, use_labels = RADIAL_LABELS_OFFSET, check_locs = list(tool)) if(!organ_to_replace) return FALSE - var/obj/item/organ/internal/augment/A = organ_to_replace - if(istype(A)) - if(!(A.augment_flags & AUGMENTATION_MECHANIC)) - to_chat(user, SPAN_WARNING("\the [A] cannot function within a robotic limb")) - return FALSE + var/attach_failure_reason = organ_to_replace.get_attachment_failure_reason(affected, robotic = TRUE) // if this returns FALSE, it can attach + if(attach_failure_reason) + to_chat(user, attach_failure_reason) + return FALSE return organ_to_replace -/decl/surgery_step/robotics/attach_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] begins reattaching [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].", \ - "You start reattaching [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") +/decl/surgery_step/robotics/attach_organ_robotic/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] begins reattaching [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \ + "You start reattaching [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") ..() -/decl/surgery_step/robotics/attach_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] has reattached [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool]." , \ - "You have reattached [target]'s [LAZYACCESS(target.surgeries_in_progress, target_zone)] with \the [tool].") +/decl/surgery_step/robotics/attach_organ_robotic/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user] has attached [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool]." , \ + "You have attached [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].") - var/current_organ = LAZYACCESS(target.surgeries_in_progress, target_zone) - var/obj/item/organ/external/affected = target.get_organ(target_zone) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + var/current_organ = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone) for (var/obj/item/organ/I in affected.implants) if (I.organ_tag == current_organ) - I.status &= ~ORGAN_CUT_AWAY - affected.implants -= I - I.replaced(target, affected) + target.add_organ(I, affected, detached = FALSE) break - -/decl/surgery_step/robotics/attach_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user]'s hand slips, disconnecting \the [tool].", \ - "Your hand slips, disconnecting \the [tool].") - -////////////////////////////////////////////////////////////////// -// mmi installation surgery step -////////////////////////////////////////////////////////////////// -/decl/surgery_step/robotics/install_mmi - name = "Install MMI" - description = "This procedure installs an MMI within a prosthetic organ." - allowed_tools = list( - /obj/item/mmi = 100 - ) - min_duration = 60 - max_duration = 80 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT - -/decl/surgery_step/robotics/install_mmi/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/mmi/M = tool - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(affected && istype(M)) - if(!M.brainmob || !M.brainmob.client || !M.brainmob.ckey || M.brainmob.stat >= DEAD) - to_chat(user, SPAN_WARNING("That brain is not usable.")) - else if(BP_IS_CRYSTAL(affected)) - to_chat(user, SPAN_WARNING("The crystalline interior of \the [affected] is incompatible with \the [M].")) - else if(!target.isSynthetic()) - to_chat(user, SPAN_WARNING("You cannot install a computer brain into a meat body.")) - else if(!target.should_have_organ(BP_BRAIN)) - to_chat(user, SPAN_WARNING("You're pretty sure [target.species.name_plural] don't normally have a brain.")) - else if(target.internal_organs[BP_BRAIN]) - to_chat(user, SPAN_WARNING("Your subject already has a brain.")) - else - return TRUE - return FALSE - -/decl/surgery_step/robotics/install_mmi/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = ..() - if(affected && target_zone == BP_HEAD) - return affected - -/decl/surgery_step/robotics/install_mmi/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] starts installing \the [tool] into [target]'s [affected.name].", \ - "You start installing \the [tool] into [target]'s [affected.name].") ..() -/decl/surgery_step/robotics/install_mmi/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(!user.unEquip(tool)) - return - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message("[user] has installed \the [tool] into [target]'s [affected.name].", \ - "You have installed \the [tool] into [target]'s [affected.name].") - - var/obj/item/mmi/M = tool - var/obj/item/organ/internal/mmi_holder/holder = new(target, 1) - target.internal_organs_by_name[BP_BRAIN] = holder - tool.forceMove(holder) - holder.stored_mmi = tool - holder.update_from_mmi() - - if(M.brainmob && M.brainmob.mind) - M.brainmob.mind.transfer_to(target) - -/decl/surgery_step/robotics/install_mmi/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user]'s hand slips.", \ - "Your hand slips.") +/decl/surgery_step/robotics/attach_organ_robotic/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, unseating \the [tool].", \ + "Your hand slips, unseating \the [tool].") + ..() /decl/surgery_step/internal/remove_organ/robotic name = "Remove robotic component" description = "This procedure removes a robotic component." can_infect = 0 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT /decl/surgery_step/internal/replace_organ/robotic name = "Replace robotic component" description = "This procedure installs a robotic component." can_infect = 0 robotic_surgery = TRUE - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT - -/decl/surgery_step/remove_mmi - name = "Remove MMI" - description = "This procedure removes an MMI from a prosthetic organ." - min_duration = 60 - max_duration = 80 - allowed_tools = list( - /obj/item/hemostat = 100, - /obj/item/wirecutters = 75, - /obj/item/kitchen/utensil/fork = 20 - ) - can_infect = 0 - surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NO_STUMP | SURGERY_NEEDS_ENCASEMENT - -/decl/surgery_step/remove_mmi/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - return SURGERY_SKILLS_ROBOTIC - -/decl/surgery_step/remove_mmi/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = ..() - if(affected && (locate(/obj/item/mmi) in affected.implants)) - return affected - -/decl/surgery_step/remove_mmi/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message( \ - "\The [user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ - "You start poking around inside [target]'s [affected.name] with \the [tool]." ) - target.custom_pain("The pain in your [affected.name] is living hell!",1,affecting = affected) - ..() - -/decl/surgery_step/remove_mmi/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(affected) - var/obj/item/mmi/mmi = locate() in affected.implants - if(affected && mmi) - user.visible_message( \ - SPAN_NOTICE("\The [user] removes \the [mmi] from \the [target]'s [affected.name] with \the [tool]."), \ - SPAN_NOTICE("You remove \the [mmi] from \the [target]'s [affected.name] with \the [tool].")) - target.remove_implant(mmi, TRUE, affected) - else - user.visible_message( \ - SPAN_NOTICE("\The [user] could not find anything inside [target]'s [affected.name]."), \ - SPAN_NOTICE("You could not find anything inside [target]'s [affected.name].")) - -/decl/surgery_step/remove_mmi/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - user.visible_message( \ - SPAN_WARNING("\The [user]'s hand slips, damaging \the [target]'s [affected.name] with \the [tool]!"), \ - SPAN_WARNING("Your hand slips, damaging \the [target]'s [affected.name] with \the [tool]!")) - affected.take_external_damage(3, 0, used_weapon = tool) + surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT diff --git a/code/modules/surgery/slimes.dm b/code/modules/surgery/slimes.dm deleted file mode 100644 index 2eb931b9b7a1..000000000000 --- a/code/modules/surgery/slimes.dm +++ /dev/null @@ -1,115 +0,0 @@ -//Procedures in this file: Slime surgery, core extraction. -////////////////////////////////////////////////////////////////// -// SLIME CORE EXTRACTION // -////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////// -// generic slime surgery step datum -////////////////////////////////////////////////////////////////// -/decl/surgery_step/slime - hidden_from_codex = TRUE - -/decl/surgery_step/slime/is_valid_target(mob/living/carbon/slime/target) - return isslime(target) - -/decl/surgery_step/slime/assess_bodypart(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return TRUE - -/decl/surgery_step/slime/assess_surgery_candidate(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return isslime(target) && target.stat == DEAD - -/decl/surgery_step/slime/get_skill_reqs(mob/living/user, mob/living/carbon/human/target, obj/item/tool) - return list(SKILL_SCIENCE = SKILL_ADEPT) - -////////////////////////////////////////////////////////////////// -// slime flesh cutting surgery step -////////////////////////////////////////////////////////////////// -/decl/surgery_step/slime/cut_flesh - name = "Make incision in slime" - allowed_tools = list( - /obj/item/scalpel = 100, - /obj/item/knife = 75, - /obj/item/shard = 50 - ) - min_duration = 5 - max_duration = 2 SECONDS - -/decl/surgery_step/slime/cut_flesh/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && istype(target) && target.core_removal_stage == 0 - -/decl/surgery_step/slime/cut_flesh/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ - "You start cutting through [target]'s flesh with \the [tool].") - -/decl/surgery_step/slime/cut_flesh/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] cuts through [target]'s flesh with \the [tool].", \ - "You cut through [target]'s flesh with \the [tool], revealing its silky innards.") - target.core_removal_stage = 1 - -/decl/surgery_step/slime/cut_flesh/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \ - "Your hand slips, tearing [target]'s flesh with \the [tool]!") - -////////////////////////////////////////////////////////////////// -// slime innards cutting surgery step -////////////////////////////////////////////////////////////////// -/decl/surgery_step/slime/cut_innards - name = "Dissect innards" - allowed_tools = list( - /obj/item/scalpel = 100, - /obj/item/knife = 75, - /obj/item/shard = 50 - ) - min_duration = 5 - max_duration = 2 SECONDS - -/decl/surgery_step/slime/cut_innards/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && istype(target) && target.core_removal_stage == 1 - -/decl/surgery_step/slime/cut_innards/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ - "You start cutting [target]'s silky innards apart with \the [tool].") - -/decl/surgery_step/slime/cut_innards/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \ - "You cut [target]'s innards apart with \the [tool], exposing the cores.") - target.core_removal_stage = 2 - -/decl/surgery_step/slime/cut_innards/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user]'s hand slips, tearing [target]'s innards with \the [tool]!", \ - "Your hand slips, tearing [target]'s innards with \the [tool]!") - -////////////////////////////////////////////////////////////////// -// slime core removal surgery step -////////////////////////////////////////////////////////////////// -/decl/surgery_step/slime/saw_core - name = "Remove slime core" - allowed_tools = list( - /obj/item/scalpel/manager = 100, - /obj/item/circular_saw = 100, - /obj/item/knife = 75, - /obj/item/hatchet = 75 - ) - min_duration = 1 SECOND - max_duration = 3 SECONDS - -/decl/surgery_step/slime/saw_core/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && (istype(target) && target.core_removal_stage == 2 && target.cores > 0) //This is being passed a human as target, unsure why. - -/decl/surgery_step/slime/saw_core/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting out one of [target]'s cores with \the [tool].", \ - "You start cutting out one of [target]'s cores with \the [tool].") - -/decl/surgery_step/slime/saw_core/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - target.cores-- - user.visible_message("[user] cuts out one of [target]'s cores with \the [tool].",, \ - "You cut out one of [target]'s cores with \the [tool]. [target.cores] cores left.") - if(target.cores >= 0) - var/coreType = target.GetCoreType() - new coreType(target.loc) - if(target.cores <= 0) - target.icon_state = "[target.colour] baby slime dead-nocore" - -/decl/surgery_step/slime/saw_core/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user]'s hand slips, causing \him to miss the core!", \ - "Your hand slips, causing you to miss the core!") diff --git a/code/modules/surgery/suture_wounds.dm b/code/modules/surgery/suture_wounds.dm index 673914a5a4cc..a329518f6ffa 100644 --- a/code/modules/surgery/suture_wounds.dm +++ b/code/modules/surgery/suture_wounds.dm @@ -1,56 +1,54 @@ /decl/surgery_step/suture_wounds - name = "Suture wound" - - allowed_tools = list( - /obj/item/sutures = 100, - /obj/item/stack/cable_coil = 60 - ) + description = "This procedure reduces the size of a wound, allowing it to heal or close." + allowed_tools = list(TOOL_SUTURES = 100) min_duration = 70 max_duration = 100 can_infect = 1 shock_level = 1 - surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL | SURGERY_NO_STUMP + surgery_candidate_flags = SURGERY_NO_ROBOTIC | SURGERY_NO_CRYSTAL -/decl/surgery_step/suture_wounds/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.organs_by_name[target_zone] +/decl/surgery_step/suture_wounds/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) if(affected) - for(var/datum/wound/W in affected.wounds) - if(W.damage_type == CUT && W.damage >= W.autoheal_cutoff) + for(var/datum/wound/wound in affected.wounds) + if(wound.damage_type == CUT && wound.damage >= wound.autoheal_cutoff) return TRUE to_chat(user, SPAN_WARNING("\The [target]'s [affected.name] has no wounds that are large enough to need suturing.")) return FALSE -/decl/surgery_step/suture_wounds/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/suture_wounds/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message("[user] is beginning to close a wound on [target]'s [affected.name] with \the [tool]." , \ "You are beginning to close a wound on [target]'s [affected.name] with \the [tool].") target.custom_pain("Your [affected.name] is being stabbed!",1) ..() -/decl/surgery_step/suture_wounds/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - for(var/datum/wound/W in affected.wounds) - if(W.damage_type == CUT && W.damage >= W.autoheal_cutoff) +/decl/surgery_step/suture_wounds/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) + for(var/datum/wound/wound in affected.wounds) + if(wound.damage_type == CUT && wound.damage >= wound.autoheal_cutoff) // Close it up to a point that it can be bandaged and heal naturally! - W.heal_damage(rand(10,20)+10) - if(W.damage >= W.autoheal_cutoff) + wound.heal_damage(rand(10,20)+10) + if(wound.damage >= wound.autoheal_cutoff) user.visible_message(SPAN_NOTICE("\The [user] partially closes a wound on [target]'s [affected.name] with \the [tool]."), \ SPAN_NOTICE("You partially close a wound on [target]'s [affected.name] with \the [tool].")) else user.visible_message(SPAN_NOTICE("\The [user] closes a wound on [target]'s [affected.name] with \the [tool]."), \ SPAN_NOTICE("You close a wound on [target]'s [affected.name] with \the [tool].")) - if(!W.damage) - affected.wounds -= W - qdel(W) - else if(W.damage <= 10) - W.clamped = 1 + if(!wound.damage) + affected.wounds -= wound + qdel(wound) + else if(wound.damage <= 10) + wound.clamped = 1 break affected.update_damages() + ..() -/decl/surgery_step/suture_wounds/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/obj/item/organ/external/affected = target.get_organ(target_zone) +/decl/surgery_step/suture_wounds/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone) user.visible_message(SPAN_DANGER("[user]'s hand slips, tearing [target]'s [affected.name] with \the [tool]!"), \ SPAN_DANGER("Your hand slips, tearing [target]'s [affected.name] with \the [tool]!")) - target.apply_damage(3, BRUTE, affected) \ No newline at end of file + target.apply_damage(3, BRUTE, affected) + ..() diff --git a/code/modules/synthesized_instruments/echo_editor.dm b/code/modules/synthesized_instruments/echo_editor.dm index c9ebe0950a39..70f456ce8988 100644 --- a/code/modules/synthesized_instruments/echo_editor.dm +++ b/code/modules/synthesized_instruments/echo_editor.dm @@ -2,7 +2,6 @@ name = "Echo Editor" available_to_ai = 0 var/datum/sound_player/player - var/atom/source /datum/nano_module/echo_editor/New(datum/sound_player/player) @@ -16,9 +15,9 @@ for (var/i=1 to 18) var/list/echo_data = list() echo_data["index"] = i - echo_data["name"] = GLOB.musical_config.echo_param_names[i] + echo_data["name"] = global.musical_config.echo_param_names[i] echo_data["value"] = src.player.echo[i] - echo_data["real"] = GLOB.musical_config.echo_params_bounds[i][3] + echo_data["real"] = global.musical_config.echo_params_bounds[i][3] data["echo_params"] += list(echo_data) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -35,13 +34,13 @@ var/target = href_list["target"] var/index = text2num(href_list["index"]) if (href_list["index"] && !(index in 1 to 18)) - to_chat(usr, "Wrong index was provided: [index]") + to_chat(usr, "Wrong index was provided: [index].") return 0 - var/name = GLOB.musical_config.echo_param_names[index] - var/desc = GLOB.musical_config.echo_param_desc[index] - var/default = GLOB.musical_config.echo_default[index] - var/list/bounds = GLOB.musical_config.echo_params_bounds[index] + var/name = global.musical_config.echo_param_names[index] + var/desc = global.musical_config.echo_param_desc[index] + var/default = global.musical_config.echo_default[index] + var/list/bounds = global.musical_config.echo_params_bounds[index] var/bound_min = bounds[1] var/bound_max = bounds[2] var/reals_allowed = bounds[3] @@ -56,7 +55,7 @@ if ("reset") src.player.echo[index] = default if ("reset_all") - src.player.echo = GLOB.musical_config.echo_default.Copy() + src.player.echo = global.musical_config.echo_default.Copy() if ("desc") to_chat(usr, "[name]: from [bound_min] to [bound_max] (default: [default])
    [desc]") diff --git a/code/modules/synthesized_instruments/env_editor.dm b/code/modules/synthesized_instruments/env_editor.dm index 536e467de896..7658fabd8845 100644 --- a/code/modules/synthesized_instruments/env_editor.dm +++ b/code/modules/synthesized_instruments/env_editor.dm @@ -15,9 +15,9 @@ for (var/i=1 to 23) var/list/env_data = list() env_data["index"] = i - env_data["name"] = GLOB.musical_config.env_param_names[i] + env_data["name"] = global.musical_config.env_param_names[i] env_data["value"] = src.player.env[i] - env_data["real"] = GLOB.musical_config.env_params_bounds[i][3] + env_data["real"] = global.musical_config.env_params_bounds[i][3] data["env_params"] += list(env_data) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) @@ -28,7 +28,7 @@ /datum/nano_module/env_editor/Topic(href, href_list) - if (!GLOB.musical_config.env_settings_available) + if (!global.musical_config.env_settings_available) return 0 if (..()) @@ -37,13 +37,13 @@ var/target = href_list["target"] var/index = text2num(href_list["index"]) if (href_list["index"] && !(index in 1 to 23)) - to_chat(usr, "Wrong index was provided: [index]") + to_chat(usr, "Wrong index was provided: [index].") return 0 - var/name = GLOB.musical_config.env_param_names[index] - var/desc = GLOB.musical_config.env_param_desc[index] - var/default = GLOB.musical_config.env_default[index] - var/list/bounds = GLOB.musical_config.env_params_bounds[index] + var/name = global.musical_config.env_param_names[index] + var/desc = global.musical_config.env_param_desc[index] + var/default = global.musical_config.env_default[index] + var/list/bounds = global.musical_config.env_params_bounds[index] var/bound_min = bounds[1] var/bound_max = bounds[2] var/reals_allowed = bounds[3] @@ -58,7 +58,7 @@ if ("reset") src.player.env[index] = default if ("reset_all") - src.player.env = GLOB.musical_config.env_default.Copy() + src.player.env = global.musical_config.env_default.Copy() if ("desc") to_chat(usr, "[name]: from [bound_min] to [bound_max] (default: [default])
    [desc]") diff --git a/code/modules/synthesized_instruments/event_manager.dm b/code/modules/synthesized_instruments/event_manager.dm index 5fabfef830ea..182ab68b3b0f 100644 --- a/code/modules/synthesized_instruments/event_manager.dm +++ b/code/modules/synthesized_instruments/event_manager.dm @@ -1,9 +1,8 @@ -datum/musical_event +/datum/musical_event var/datum/sound_player/source var/time = 0 var/new_volume = 100 var/datum/sound_token/token - var/sound_id /datum/musical_event/New(datum/sound_player/source, datum/sound_token/token, time, volume) @@ -43,13 +42,10 @@ datum/musical_event var/active = 0 var/kill_loop = 0 - /datum/musical_event_manager/proc/push_event(datum/sound_player/source, datum/sound_token/token, time, volume) if (istype(source) && istype(token) && volume >= 0 && volume <= 100) src.events += new /datum/musical_event(source, token, time, volume) - - /datum/musical_event_manager/proc/handle_events() var/list/datum/musical_event/left_events = list() while (1) @@ -72,9 +68,7 @@ datum/musical_event if (active) return 0 src.active = 1 - addtimer(CALLBACK(src, .proc/handle_events), 0) - - + addtimer(CALLBACK(src, PROC_REF(handle_events)), 0) /datum/musical_event_manager/proc/deactivate() if (src.kill_loop) return 0 @@ -86,6 +80,9 @@ datum/musical_event src.suspended = 0 return 1 - /datum/musical_event_manager/proc/is_overloaded() - return src.events.len > GLOB.musical_config.max_events \ No newline at end of file + return src.events.len > global.musical_config.max_events + +/datum/musical_event_manager/Destroy() + deactivate() + return ..() diff --git a/code/modules/synthesized_instruments/globals.dm b/code/modules/synthesized_instruments/globals.dm index b2d8cc93006f..ecf19b16ce3d 100644 --- a/code/modules/synthesized_instruments/globals.dm +++ b/code/modules/synthesized_instruments/globals.dm @@ -1,4 +1,4 @@ -GLOBAL_DATUM_INIT(musical_config, /datum/musical_config, new) +var/global/datum/musical_config/musical_config = new /datum/musical_config var/highest_octave = 9 @@ -17,9 +17,6 @@ GLOBAL_DATUM_INIT(musical_config, /datum/musical_config, new) var/max_events = 2400 var/song_editor_lines_per_page = 20 - var/usage_info_channel_resolution = 1 - var/usage_info_event_resolution = 8 - var/env_settings_available = 1 var/list/env_default = list(7.5, 1.0, -1000, -100, 0, 1.49, 0.83, 1.0, -2602, 0.0007, 200, 0.011, 0.25, 0.0, 0.25, 0.0, -5.0, 5000, 250.0, 0.0, 100, 100, 63) @@ -215,21 +212,16 @@ Bit flags that modify the behavior of above properties /datum/musical_config/proc/environment_to_id(environment) - if (environment in src.all_environments) - return src.all_environments.Find(environment) - 2 - return -1 - + return index_to_id(src.all_environments.Find(environment)) /datum/musical_config/proc/id_to_environment(id) if (id >= -1 && id <= 26) return src.all_environments[id+2] return "None" - /datum/musical_config/proc/index_to_id(index) return max(min(index-2, 26), -1) - /datum/musical_config/proc/is_custom_env(id) return id_to_environment(id) == src.all_environments[28] diff --git a/code/modules/synthesized_instruments/instruments.dm b/code/modules/synthesized_instruments/instruments.dm index 4ff6863d573e..2655bbb770f7 100644 --- a/code/modules/synthesized_instruments/instruments.dm +++ b/code/modules/synthesized_instruments/instruments.dm @@ -18,17 +18,17 @@ for (var/indx1=1 to delta_1.len-1) var/from_key = delta_1[indx1] var/to_key = delta_1[indx1+1] - var/sample1 = src.samples[GLOB.musical_config.n2t(from_key)] - var/sample2 = src.samples[GLOB.musical_config.n2t(to_key)] + var/sample1 = src.samples[global.musical_config.n2t(from_key)] + var/sample2 = src.samples[global.musical_config.n2t(to_key)] var/pivot = round((from_key+to_key)/2) - for (var/key = from_key to pivot) src.sample_map[GLOB.musical_config.n2t(key)] = new /datum/sample_pair(sample1, key-from_key) // [55+56] / 2 -> 55.5 -> 55 so no changes will occur - for (var/key = pivot+1 to to_key) src.sample_map[GLOB.musical_config.n2t(key)] = new /datum/sample_pair(sample2, key-to_key) + for (var/key = from_key to pivot) src.sample_map[global.musical_config.n2t(key)] = new /datum/sample_pair(sample1, key-from_key) // [55+56] / 2 -> 55.5 -> 55 so no changes will occur + for (var/key = pivot+1 to to_key) src.sample_map[global.musical_config.n2t(key)] = new /datum/sample_pair(sample2, key-to_key) // Fill in 0 -- first key and last key -- 127 var/first_key = delta_1[1] var/last_key = delta_1[delta_1.len] - var/first_sample = src.samples[GLOB.musical_config.n2t(first_key)] - var/last_sample = src.samples[GLOB.musical_config.n2t(last_key)] - for (var/key=0 to first_key-1) src.sample_map[GLOB.musical_config.n2t(key)] = new /datum/sample_pair(first_sample, key-first_key) - for (var/key=last_key to 127) src.sample_map[GLOB.musical_config.n2t(key)] = new /datum/sample_pair(last_sample, key-last_key) + var/first_sample = src.samples[global.musical_config.n2t(first_key)] + var/last_sample = src.samples[global.musical_config.n2t(last_key)] + for (var/key=0 to first_key-1) src.sample_map[global.musical_config.n2t(key)] = new /datum/sample_pair(first_sample, key-first_key) + for (var/key=last_key to 127) src.sample_map[global.musical_config.n2t(key)] = new /datum/sample_pair(last_sample, key-last_key) return src.samples \ No newline at end of file diff --git a/code/modules/synthesized_instruments/real_instruments.dm b/code/modules/synthesized_instruments/real_instruments.dm index 3b52e35c001a..157e5fa1dab1 100644 --- a/code/modules/synthesized_instruments/real_instruments.dm +++ b/code/modules/synthesized_instruments/real_instruments.dm @@ -1,7 +1,7 @@ //This is the combination of logic pertaining music //An atom should use the logic and call it as it wants /datum/real_instrument - var/datum/instrument/instruments + var/list/instruments var/datum/sound_player/player var/datum/nano_module/song_editor/song_editor var/datum/nano_module/usage_info/usage_info @@ -14,15 +14,15 @@ /datum/real_instrument/New(obj/who, datum/sound_player/how, datum/instrument/what) player = how owner = who - maximum_lines = GLOB.musical_config.max_lines - maximum_line_length = GLOB.musical_config.max_line_length - instruments = what //This can be a list, or it can also not be one + maximum_lines = global.musical_config.max_lines + maximum_line_length = global.musical_config.max_line_length + instruments = istype(what) ? list(what) : what -/datum/real_instrument/proc/Topic_call(href, href_list, usr) +/datum/real_instrument/proc/OnTopic(mob/user, href_list) var/target = href_list["target"] var/value = text2num(href_list["value"]) if (href_list["value"] && !isnum(value)) - to_chat(usr, "Non-numeric value was given") + to_chat(user, "Non-numeric value was given.") return 0 @@ -31,20 +31,20 @@ if ("play") src.player.song.playing = value if (src.player.song.playing) - src.player.song.play_song(usr) + src.player.song.play_song(user) if ("newsong") src.player.song.lines.Cut() src.player.song.tempo = src.player.song.sanitize_tempo(5) // default 120 BPM if ("import") var/t = "" do - t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", owner.name), t) as message) - if(!CanInteractWith(usr, owner, GLOB.physical_state)) + t = html_encode(input(user, "Please paste the entire song, formatted:", text("[]", owner.name), t) as message) + if(!CanInteractWith(user, owner, global.physical_topic_state)) return if(length(t) >= 2*src.maximum_lines*src.maximum_line_length) - var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no") - if(!CanInteractWith(usr, owner, GLOB.physical_state)) + var/cont = input(user, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no") + if(!CanInteractWith(user, owner, global.physical_topic_state)) return if(cont == "no") break @@ -60,41 +60,41 @@ else src.player.song.tempo = src.player.song.sanitize_tempo(5) // default 120 BPM if(src.player.song.lines.len > maximum_lines) - to_chat(usr,"Too many lines!") + to_chat(user,"Too many lines!") src.player.song.lines.Cut(maximum_lines+1) var/linenum = 1 for(var/l in src.player.song.lines) if(length(l) > maximum_line_length) - to_chat(usr, "Line [linenum] too long!") + to_chat(user, "Line [linenum] too long!") src.player.song.lines.Remove(l) else linenum++ if ("show_song_editor") if (!src.song_editor) src.song_editor = new (host = src.owner, song = src.player.song) - src.song_editor.ui_interact(usr) + src.song_editor.ui_interact(user) if ("show_usage") if (!src.usage_info) src.usage_info = new (owner, src.player) - src.usage_info.ui_interact(usr) + src.usage_info.ui_interact(user) if ("volume") - src.player.volume = min(max(min(player.volume+text2num(value), 100), 0), player.max_volume) + src.player.play_volume = min(max(min(player.play_volume+text2num(value), 100), 0), player.max_volume) if ("transposition") - src.player.song.transposition = max(min(player.song.transposition+value, GLOB.musical_config.highest_transposition), GLOB.musical_config.lowest_transposition) + src.player.song.transposition = max(min(player.song.transposition+value, global.musical_config.highest_transposition), global.musical_config.lowest_transposition) if ("min_octave") - src.player.song.octave_range_min = max(min(player.song.octave_range_min+value, GLOB.musical_config.highest_octave), GLOB.musical_config.lowest_octave) + src.player.song.octave_range_min = max(min(player.song.octave_range_min+value, global.musical_config.highest_octave), global.musical_config.lowest_octave) src.player.song.octave_range_max = max(player.song.octave_range_max, player.song.octave_range_min) if ("max_octave") - src.player.song.octave_range_max = max(min(player.song.octave_range_max+value, GLOB.musical_config.highest_octave), GLOB.musical_config.lowest_octave) + src.player.song.octave_range_max = max(min(player.song.octave_range_max+value, global.musical_config.highest_octave), global.musical_config.lowest_octave) src.player.song.octave_range_min = min(player.song.octave_range_max, player.song.octave_range_min) if ("sustain_timer") - src.player.song.sustain_timer = max(min(player.song.sustain_timer+value, GLOB.musical_config.longest_sustain_timer), 1) + src.player.song.sustain_timer = max(min(player.song.sustain_timer+value, global.musical_config.longest_sustain_timer), 1) if ("soft_coeff") - var/new_coeff = input(usr, "from [GLOB.musical_config.gentlest_drop] to [GLOB.musical_config.steepest_drop]") as num - if(!CanInteractWith(usr, owner, GLOB.physical_state)) + var/new_coeff = input(user, "from [global.musical_config.gentlest_drop] to [global.musical_config.steepest_drop]") as num + if(!CanInteractWith(user, owner, global.physical_topic_state)) return - new_coeff = round(min(max(new_coeff, GLOB.musical_config.gentlest_drop), GLOB.musical_config.steepest_drop), 0.001) + new_coeff = round(min(max(new_coeff, global.musical_config.gentlest_drop), global.musical_config.steepest_drop), 0.001) src.player.song.soft_coeff = new_coeff if ("instrument") var/list/categories = list() @@ -102,8 +102,8 @@ var/datum/instrument/instrument = instruments[key] categories |= instrument.category - var/category = input(usr, "Choose a category") as null|anything in categories - if(!CanInteractWith(usr, owner, GLOB.physical_state)) + var/category = input(user, "Choose a category") as null|anything in categories + if(!CanInteractWith(user, owner, global.physical_topic_state)) return var/list/instruments_available = list() for (var/key in instruments) @@ -111,8 +111,8 @@ if (instrument.category == category) instruments_available += key - var/new_instrument = input(usr, "Choose an instrument") as null|anything in instruments_available - if(!CanInteractWith(usr, owner, GLOB.physical_state)) + var/new_instrument = input(user, "Choose an instrument") as null|anything in instruments_available + if(!CanInteractWith(user, owner, global.physical_topic_state)) return if (new_instrument) src.player.song.instrument_data = instruments[new_instrument] @@ -120,17 +120,17 @@ if ("decay") src.player.song.linear_decay = value if ("echo") src.player.apply_echo = value if ("show_env_editor") - if (GLOB.musical_config.env_settings_available) + if (global.musical_config.env_settings_available) if (!src.env_editor) src.env_editor = new (src.player) - src.env_editor.ui_interact(usr) + src.env_editor.ui_interact(user) else - to_chat(usr, "Virtual environment is disabled") + to_chat(user, "Virtual environment is disabled.") if ("show_echo_editor") if (!src.echo_editor) src.echo_editor = new (src.player) - src.echo_editor.ui_interact(usr) + src.echo_editor.ui_interact(user) if ("select_env") if (value in -1 to 26) @@ -151,7 +151,7 @@ ), "basic_options" = list( "cur_instrument" = src.player.song.instrument_data.name, - "volume" = src.player.volume, + "volume" = src.player.play_volume, "BPM" = round(600 / src.player.song.tempo), "transposition" = src.player.song.transposition, "octave_range" = list( @@ -160,8 +160,8 @@ ) ), "advanced_options" = list( - "all_environments" = GLOB.musical_config.all_environments, - "selected_environment" = GLOB.musical_config.id_to_environment(src.player.virtual_environment_selected), + "all_environments" = global.musical_config.all_environments, + "selected_environment" = global.musical_config.id_to_environment(src.player.virtual_environment_selected), "apply_echo" = src.player.apply_echo ), "sustain" = list( @@ -171,14 +171,14 @@ ), "show" = list( "playback" = src.player.song.lines.len > 0, - "custom_env_options" = GLOB.musical_config.is_custom_env(src.player.virtual_environment_selected), - "env_settings" = GLOB.musical_config.env_settings_available + "custom_env_options" = global.musical_config.is_custom_env(src.player.virtual_environment_selected), + "env_settings" = global.musical_config.env_settings_available ), "status" = list( "channels" = src.player.song.available_channels, "events" = src.player.event_manager.events.len, - "max_channels" = GLOB.musical_config.channels_per_instrument, - "max_events" = GLOB.musical_config.max_events, + "max_channels" = global.musical_config.channels_per_instrument, + "max_events" = global.musical_config.max_events, ) ) @@ -201,7 +201,7 @@ var/datum/real_instrument/real_instrument icon = 'icons/obj/musician.dmi' //Initialization data - var/datum/instrument/instruments = list() + var/list/instruments = list() var/path = /datum/instrument var/sound_player = /datum/sound_player @@ -223,8 +223,9 @@ /obj/structure/synthesized_instrument/attack_hand(mob/user) - src.interact(user) - + SHOULD_CALL_PARENT(FALSE) + interact(user) + return TRUE /obj/structure/synthesized_instrument/interact(mob/user) // CONDITIONS ..(user) that shit in subclasses src.ui_interact(user) @@ -238,11 +239,8 @@ return 0 -/obj/structure/synthesized_instrument/Topic(href, href_list) - if (..()) - return 1 - - return real_instrument.Topic_call(href, href_list, usr) +/obj/structure/synthesized_instrument/OnTopic(mob/user, href_list) + return ..() || real_instrument.OnTopic(user, href_list) //////////////////////// @@ -253,17 +251,20 @@ /obj/item/synthesized_instrument var/datum/real_instrument/real_instrument icon = 'icons/obj/musician.dmi' - var/datum/instrument/instruments = list() + material = /decl/material/solid/organic/plastic + var/list/instruments = list() var/path = /datum/instrument var/sound_player = /datum/sound_player /obj/item/synthesized_instrument/Initialize() . = ..() for (var/type in typesof(path)) - var/datum/instrument/new_instrument = new type - if (!new_instrument.id) continue + var/datum/instrument/new_instrument = type + if (!initial(new_instrument.id)) + continue + new_instrument = new type new_instrument.create_full_sample_deviation_map() - src.instruments[new_instrument.name] = new_instrument + instruments[new_instrument.name] = new_instrument src.real_instrument = new /datum/real_instrument(src, new sound_player(src, instruments[pick(instruments)]), instruments) /obj/item/synthesized_instrument/Destroy() @@ -287,10 +288,7 @@ /obj/item/synthesized_instrument/proc/shouldStopPlaying(mob/user) - return !(src && in_range(src, user)) - -/obj/item/synthesized_instrument/Topic(href, href_list) - if (..()) - return 1 + return src && CanPhysicallyInteract(user) - return real_instrument.Topic_call(href, href_list, usr) \ No newline at end of file +/obj/item/synthesized_instrument/OnTopic(mob/user, href_list) + return ..() || real_instrument.OnTopic(user, href_list) \ No newline at end of file diff --git a/code/modules/synthesized_instruments/real_instruments/Guitar/guitar.dm b/code/modules/synthesized_instruments/real_instruments/Guitar/guitar.dm index 84609c4a3b32..b39bfc00a241 100644 --- a/code/modules/synthesized_instruments/real_instruments/Guitar/guitar.dm +++ b/code/modules/synthesized_instruments/real_instruments/Guitar/guitar.dm @@ -2,10 +2,12 @@ name = "guitar" desc = "A wooden musical instrument with six strings. This one looks like it may actually work." icon = 'icons/obj/items/guitar.dmi' - icon_state = "guitar" + icon_state = ICON_STATE_WORLD sound_player = /datum/sound_player/synthesizer path = /datum/instrument/guitar/clean_crisis - + material = /decl/material/solid/organic/wood/oak + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE) + slot_flags = SLOT_BACK /obj/item/synthesized_instrument/guitar/multi name = "Polyguitar" @@ -13,4 +15,11 @@ icon = 'icons/obj/musician.dmi' icon_state = "eguitar" sound_player = /datum/sound_player/synthesizer - path = /datum/instrument/guitar \ No newline at end of file + path = /datum/instrument/guitar + material = /decl/material/solid/organic/wood/oak + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE, + /decl/material/solid/silicon = MATTER_AMOUNT_TRACE, + ) + slot_flags = 0 \ No newline at end of file diff --git a/code/modules/synthesized_instruments/real_instruments/Piano/piano.dm b/code/modules/synthesized_instruments/real_instruments/Piano/piano.dm index 9282175f64c3..43e2e59720ce 100644 --- a/code/modules/synthesized_instruments/real_instruments/Piano/piano.dm +++ b/code/modules/synthesized_instruments/real_instruments/Piano/piano.dm @@ -1,6 +1,6 @@ /obj/structure/synthesized_instrument/synthesizer/piano name = "space piano" - desc = "A surprisingly high-tech piano with a digital display for modifying sound output" + desc = "A surprisingly high-tech piano with a digital display for modifying sound output." icon_state = "piano" path = /datum/instrument/piano diff --git a/code/modules/synthesized_instruments/real_instruments/Synthesizer/synthesizer.dm b/code/modules/synthesized_instruments/real_instruments/Synthesizer/synthesizer.dm index 7a303bcc4a5c..222a35e22002 100644 --- a/code/modules/synthesized_instruments/real_instruments/Synthesizer/synthesizer.dm +++ b/code/modules/synthesized_instruments/real_instruments/Synthesizer/synthesizer.dm @@ -1,41 +1,42 @@ //Synthesizer and minimoog. They work the same /datum/sound_player/synthesizer - volume = 40 + play_volume = 40 /obj/structure/synthesized_instrument/synthesizer name = "The Synthesizer 3.0" desc = "This thing emits shockwaves as it plays. This is not good for your hearing." icon_state = "synthesizer" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE path = /datum/instrument sound_player = /datum/sound_player/synthesizer -/obj/structure/synthesized_instrument/synthesizer/attackby(obj/item/O, mob/user, params) - if (istype(O, /obj/item/wrench)) - if (!anchored && !isinspace()) +/obj/structure/synthesized_instrument/synthesizer/attackby(obj/item/used_item, mob/user, params) + if (IS_WRENCH(used_item)) + if (!anchored && !isspaceturf(get_turf(src))) playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(usr, " You begin to tighten \the [src] to the floor...") - if (do_after(user, 20)) - if(!anchored && !isinspace()) + to_chat(user, "You begin to tighten \the [src] to the floor...") + if (do_after(user, 2 SECONDS)) + if(!anchored && !isspaceturf(get_turf(src))) user.visible_message( \ "[user] tightens \the [src]'s casters.", \ - " You tighten \the [src]'s casters. Now it can be played again.", \ - "You hear ratchet.") - src.anchored = 1 + "You tighten \the [src]'s casters. Now it can be played again.", \ + "You hear a ratchet.") + src.anchored = TRUE else if(anchored) playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(usr, " You begin to loosen \the [src]'s casters...") - if (do_after(user, 40)) + to_chat(user, "You begin to loosen \the [src]'s casters...") + if (do_after(user, 4 SECONDS)) if(anchored) user.visible_message( \ "[user] loosens \the [src]'s casters.", \ - " You loosen \the [src]. Now it can be pulled somewhere else.", \ - "You hear ratchet.") - src.anchored = 0 - else - ..() + "You loosen \the [src]. Now it can be pulled somewhere else.", \ + "You hear a ratchet.") + src.anchored = FALSE + return TRUE + // we failed to do anything because we were unanchored in space, fall through to parent and smack it? + return ..() /obj/structure/synthesized_instrument/synthesizer/shouldStopPlaying(mob/user) return !((src && in_range(src, user) && src.anchored) || src.real_instrument.player.song.autorepeat) diff --git a/code/modules/synthesized_instruments/real_instruments/Trumpet/trumpet.dm b/code/modules/synthesized_instruments/real_instruments/Trumpet/trumpet.dm index 66a496942baa..6f275ac25217 100644 --- a/code/modules/synthesized_instruments/real_instruments/Trumpet/trumpet.dm +++ b/code/modules/synthesized_instruments/real_instruments/Trumpet/trumpet.dm @@ -1,6 +1,7 @@ /obj/item/synthesized_instrument/trumpet name = "Omnitrumpet" - desc = "The Omnitrumptet series 400 with more than 30 sound samples and fully customizable high fidelity output provides the ultimate means to toot your own horn" + desc = "The Omnitrumpet series 400 with more than 30 sound samples and fully customizable high fidelity output provides the ultimate means to toot your own horn" icon_state = "trumpet" sound_player = /datum/sound_player/synthesizer - path = /datum/instrument/brass \ No newline at end of file + path = /datum/instrument/brass + material = /decl/material/solid/metal/brass diff --git a/code/modules/synthesized_instruments/real_instruments/Violin/violin.dm b/code/modules/synthesized_instruments/real_instruments/Violin/violin.dm index ce7b4c642ed8..791c664b0e37 100644 --- a/code/modules/synthesized_instruments/real_instruments/Violin/violin.dm +++ b/code/modules/synthesized_instruments/real_instruments/Violin/violin.dm @@ -1,5 +1,5 @@ /datum/sound_player/violin - volume = 25 + play_volume = 25 range = 10 //Kinda don't want this horrible thing to be heard from far away /obj/item/synthesized_instrument/violin @@ -8,6 +8,5 @@ icon_state = "violin" sound_player = /datum/sound_player/violin path = /datum/instrument/obsolete/violin - -/obj/structure/synthesized_instrument/synthesizer/shouldStopPlaying(mob/user) - return !(src && in_range(src, user)) \ No newline at end of file + material = /decl/material/solid/organic/wood/oak + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_TRACE) diff --git a/code/modules/synthesized_instruments/song.dm b/code/modules/synthesized_instruments/song.dm index 09bd50ae4bd6..86d00ab2edd0 100644 --- a/code/modules/synthesized_instruments/song.dm +++ b/code/modules/synthesized_instruments/song.dm @@ -10,7 +10,7 @@ var/datum/instrument/instrument_data var/linear_decay = 1 - var/sustain_timer = 1 + var/sustain_timer = 15 // Setting this too low causes the guitar to sound inaudible. var/soft_coeff = 2.0 var/transposition = 0 @@ -25,10 +25,10 @@ /datum/synthesized_song/New(datum/sound_player/playing_object, datum/instrument/instrument) src.player = playing_object src.instrument_data = instrument - src.octave_range_min = GLOB.musical_config.lowest_octave - src.octave_range_max = GLOB.musical_config.highest_octave + src.octave_range_min = global.musical_config.lowest_octave + src.octave_range_max = global.musical_config.highest_octave instrument.create_full_sample_deviation_map() - available_channels = GLOB.musical_config.channels_per_instrument + available_channels = global.musical_config.channels_per_instrument /datum/synthesized_song/Destroy() player.event_manager.deactivate() @@ -40,17 +40,17 @@ /datum/synthesized_song/proc/play_synthesized_note(note, acc, oct, duration, where, which_one) - if (oct < GLOB.musical_config.lowest_octave || oct > GLOB.musical_config.highest_octave) return + if (oct < global.musical_config.lowest_octave || oct > global.musical_config.highest_octave) return if (oct < src.octave_range_min || oct > src.octave_range_max) return var/delta1 = acc == "b" ? -1 : acc == "#" ? 1 : acc == "s" ? 1 : acc == "n" ? 0 : 0 var/delta2 = 12 * oct - var/note_num = delta1+delta2+GLOB.musical_config.nn2no[note] + var/note_num = delta1+delta2+global.musical_config.nn2no[note] if (note_num < 0 || note_num > 127) - CRASH("play_synthesized note failed because of 0..127 condition, [note], [acc], [oct]") + CRASH("play_synthesized note failed because of 0-127 condition, [note], [acc], [oct]") - var/datum/sample_pair/pair = src.instrument_data.sample_map[GLOB.musical_config.n2t(note_num)] + var/datum/sample_pair/pair = src.instrument_data.sample_map[global.musical_config.n2t(note_num)] #define Q 0.083 // 1/12 var/freq = 2**(Q*pair.deviation) #undef Q @@ -79,13 +79,10 @@ else use_env = 1 - var/current_volume = Clamp(sound_copy.volume, 0, 100) + var/current_volume = clamp(sound_copy.volume, 0, 100) sound_copy.volume = current_volume //Sanitize volume var/datum/sound_token/token = new /datum/sound_token/instrument(src.player.actual_instrument, src.sound_id, sound_copy, src.player.range, FALSE, use_env, player) - #if DM_VERSION < 511 - sound_copy.frequency = 1 - #endif - var/delta_volume = player.volume / src.sustain_timer + var/delta_volume = player.play_volume / src.sustain_timer var/tick = duration while ((current_volume > 0) && token) @@ -117,11 +114,11 @@ autorepeat = 0 ;\ playing = 0 ;\ current_line = 0 ;\ - player.event_manager.deactivate() ;\ + player?.event_manager?.deactivate();\ return /datum/synthesized_song/proc/play_lines(mob/user, list/allowed_suff, list/note_off_delta, list/lines) - if (!lines.len) + if (!lines.len || QDELETED(player)) STOP_PLAY_LINES var/list/cur_accidentals = list("n", "n", "n", "n", "n", "n", "n") var/list/cur_octaves = list(3, 3, 3, 3, 3, 3, 3) @@ -191,7 +188,7 @@ var/list/allowed_suff = list("b", "n", "#", "s") var/list/note_off_delta = list("a"=91, "b"=91, "c"=98, "d"=98, "e"=98, "f"=98, "g"=98) var/list/lines_copy = src.lines.Copy() - addtimer(CALLBACK(src, .proc/play_lines, user, allowed_suff, note_off_delta, lines_copy), 0) + addtimer(CALLBACK(src, PROC_REF(play_lines), user, allowed_suff, note_off_delta, lines_copy), 0) #undef CP #undef IS_DIGIT diff --git a/code/modules/synthesized_instruments/song_editor.dm b/code/modules/synthesized_instruments/song_editor.dm index a6848d9bc0b6..bdab416d5fd8 100644 --- a/code/modules/synthesized_instruments/song_editor.dm +++ b/code/modules/synthesized_instruments/song_editor.dm @@ -13,17 +13,17 @@ /datum/nano_module/song_editor/proc/pages() - return Ceiling(src.song.lines.len / GLOB.musical_config.song_editor_lines_per_page) + return ceil(src.song.lines.len / global.musical_config.song_editor_lines_per_page) /datum/nano_module/song_editor/proc/current_page() - return src.song.current_line > 0 ? Ceiling(src.song.current_line / GLOB.musical_config.song_editor_lines_per_page) : src.page + return src.song.current_line > 0 ? ceil(src.song.current_line / global.musical_config.song_editor_lines_per_page) : src.page /datum/nano_module/song_editor/proc/page_bounds(page_num) return list( - max(1 + GLOB.musical_config.song_editor_lines_per_page * (page_num-1), 1), - min(GLOB.musical_config.song_editor_lines_per_page * page_num, src.song.lines.len)) + max(1 + global.musical_config.song_editor_lines_per_page * (page_num-1), 1), + min(global.musical_config.song_editor_lines_per_page * page_num, src.song.lines.len)) /datum/nano_module/song_editor/ui_interact(mob/user, ui_key = "song_editor", var/datum/nanoui/ui = null, var/force_open = 0) @@ -34,12 +34,12 @@ data["lines"] = src.song.lines.Copy(line_bounds[1], line_bounds[2]+1) data["active_line"] = src.song.current_line - data["max_lines"] = GLOB.musical_config.max_lines - data["max_line_length"] = GLOB.musical_config.max_line_length + data["max_lines"] = global.musical_config.max_lines + data["max_line_length"] = global.musical_config.max_line_length data["tick_lag"] = world.tick_lag data["show_help"] = src.show_help data["page_num"] = current_page - data["page_offset"] = GLOB.musical_config.song_editor_lines_per_page * (current_page-1) + data["page_offset"] = global.musical_config.song_editor_lines_per_page * (current_page-1) ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) @@ -55,7 +55,7 @@ var/target = href_list["target"] var/value = text2num(href_list["value"]) if (href_list["value"] && !isnum(value)) - to_chat(usr, "Non-numeric value was supplied") + to_chat(usr, "Non-numeric value was supplied.") return 0 switch (target) @@ -63,10 +63,10 @@ var/newline = html_encode(input(usr, "Enter your line: ") as text|null) if(!newline) return - if(src.song.lines.len > GLOB.musical_config.max_lines) + if(src.song.lines.len > global.musical_config.max_lines) return - if(length(newline) > GLOB.musical_config.max_line_length) - newline = copytext(newline, 1, GLOB.musical_config.max_line_length) + if(length(newline) > global.musical_config.max_line_length) + newline = copytext(newline, 1, global.musical_config.max_line_length) src.song.lines.Add(newline) if("deleteline") @@ -86,8 +86,8 @@ return if(!content) return - if(length(content) > GLOB.musical_config.max_line_length) - content = copytext(content, 1, GLOB.musical_config.max_line_length) + if(length(content) > global.musical_config.max_line_length) + content = copytext(content, 1, global.musical_config.max_line_length) src.song.lines[num] = content if ("help") diff --git a/code/modules/synthesized_instruments/sound_player.dm b/code/modules/synthesized_instruments/sound_player.dm index ee8a462fd8b7..855f53f05589 100644 --- a/code/modules/synthesized_instruments/sound_player.dm +++ b/code/modules/synthesized_instruments/sound_player.dm @@ -3,7 +3,7 @@ // Virtual object // It's the one used to modify shit var/range = 15 - var/volume = 30 + var/play_volume = 30 var/max_volume = 50 var/falloff = 2 var/apply_echo = 0 @@ -21,12 +21,12 @@ var/list/datum/sound_token/instrument/tokens = list() var/list/seen_turfs -/datum/sound_player/New(datum/real_instrument/where, datum/instrument/what) +/datum/sound_player/New(obj/where, datum/instrument/what) src.song = new (src, what) src.actual_instrument = where - src.echo = GLOB.musical_config.echo_default.Copy() - src.env = GLOB.musical_config.env_default.Copy() - src.proxy_listener = new(src.actual_instrument, /datum/sound_player/proc/on_turf_entered_relay, /datum/sound_player/proc/on_turfs_changed_relay, range, proc_owner = src) + src.echo = global.musical_config.echo_default.Copy() + src.env = global.musical_config.env_default.Copy() + src.proxy_listener = new(src.actual_instrument, TYPE_PROC_REF(/datum/sound_player, on_turf_entered_relay), TYPE_PROC_REF(/datum/sound_player, on_turfs_changed_relay), range, proc_owner = src) proxy_listener.register_turfs() /datum/sound_player/Destroy() @@ -64,10 +64,10 @@ I.PrivLocateListeners(prior_turfs.Copy(), current_turfs.Copy()) /datum/sound_player/proc/apply_modifications(sound/what, note_num, which_line, which_note) // You don't need to override this - what.volume = volume + what.volume = play_volume what.falloff = falloff - if (GLOB.musical_config.env_settings_available) - what.environment = GLOB.musical_config.is_custom_env(src.virtual_environment_selected) ? src.env : src.virtual_environment_selected + if (global.musical_config.env_settings_available) + what.environment = global.musical_config.is_custom_env(src.virtual_environment_selected) ? src.env : src.virtual_environment_selected if (src.apply_echo) what.echo = src.echo return diff --git a/code/modules/synthesized_instruments/sound_token.dm b/code/modules/synthesized_instruments/sound_token.dm index 4854d8c37043..a495fe3dd3ce 100644 --- a/code/modules/synthesized_instruments/sound_token.dm +++ b/code/modules/synthesized_instruments/sound_token.dm @@ -24,7 +24,7 @@ src.use_env = use_env src.player = player - var/channel = GLOB.sound_player.PrivGetChannel(src) //Attempt to find a channel + var/channel = get_sound_channel(src) //Attempt to find a channel if(!isnum(channel)) CRASH("All available sound channels are in active use.") sound.channel = channel @@ -32,7 +32,7 @@ listeners = list() listener_status = list() - GLOB.destroyed_event.register(source, src, /datum/proc/qdel_self) + events_repository.register(/decl/observ/destroyed, source, src, TYPE_PROC_REF(/datum, qdel_self)) player.subscribe(src) @@ -46,10 +46,10 @@ return A && PrivIsValidEnvironment(A.sound_env) ? A.sound_env : sound.environment -datum/sound_token/instrument/PrivAddListener(var/atom/listener) +/datum/sound_token/instrument/PrivAddListener(var/atom/listener) var/mob/m = listener if(istype(m)) - if(m.get_preference_value(/datum/client_preference/play_instruments) != GLOB.PREF_YES) + if(m.get_preference_value(/datum/client_preference/play_instruments) != PREF_YES) return return ..() @@ -57,7 +57,7 @@ datum/sound_token/instrument/PrivAddListener(var/atom/listener) /datum/sound_token/instrument/PrivUpdateListener(var/listener) var/mob/m = listener if(istype(m)) - if(m.get_preference_value(/datum/client_preference/play_instruments) != GLOB.PREF_YES) + if(m.get_preference_value(/datum/client_preference/play_instruments) != PREF_YES) PrivRemoveListener(listener) return return ..() diff --git a/code/modules/synthesized_instruments/usage_info.dm b/code/modules/synthesized_instruments/usage_info.dm index 9697f42b29a4..a4ab7077e394 100644 --- a/code/modules/synthesized_instruments/usage_info.dm +++ b/code/modules/synthesized_instruments/usage_info.dm @@ -9,12 +9,12 @@ //This will let you easily monitor when you're going overboard with tempo and sound duration, generally if the bars fill up it is BAD /datum/nano_module/usage_info/ui_interact(mob/user, ui_key = "usage_info", var/datum/nanoui/ui = null, var/force_open = 0) - var/global/list/data = list() + var/static/list/data = list() data.Cut() - data["channels_left"] = GLOB.sound_channels.available_channels.stack.len + data["channels_left"] = global.sound_channels.available_channels.stack.len data["events_active"] = src.player.event_manager.events.len - data["max_channels"] = GLOB.sound_channels.channel_ceiling - data["max_events"] = GLOB.musical_config.max_events + data["max_channels"] = global.sound_channels.channel_ceiling + data["max_events"] = global.musical_config.max_events ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) diff --git a/code/modules/tables/flipping.dm b/code/modules/tables/flipping.dm deleted file mode 100644 index c81d1cebe770..000000000000 --- a/code/modules/tables/flipping.dm +++ /dev/null @@ -1,130 +0,0 @@ - -/obj/structure/table/proc/straight_table_check(var/direction) - if(health > 100) - return 0 - var/obj/structure/table/T - for(var/angle in list(-90,90)) - T = locate() in get_step(src.loc,turn(direction,angle)) - if(T && T.flipped == 0 && T.material && material && T.material.type == material.type) - return 0 - T = locate() in get_step(src.loc,direction) - if (!T || T.flipped == 1 || T.material != material) - return 1 - return T.straight_table_check(direction) - -/obj/structure/table/verb/do_flip() - set name = "Flip table" - set desc = "Flips a non-reinforced table" - set category = "Object" - set src in oview(1) - - if (!usr.can_touch(src) || ismouse(usr)) - return - - if(reinf_material || flipped < 0 || !flip(get_cardinal_dir(usr,src))) - to_chat(usr, "It won't budge.") - return - - usr.visible_message("[usr] flips \the [src]!") - - if(atom_flags & ATOM_FLAG_CLIMBABLE) - object_shaken() - - return - -/obj/structure/table/proc/unflipping_check(var/direction) - - for(var/mob/M in oview(src,0)) - return 0 - - var/obj/occupied = turf_is_crowded() - if(occupied) - to_chat(usr, "There's \a [occupied] in the way.") - return 0 - - var/list/L = list() - if(direction) - L.Add(direction) - else - L.Add(turn(src.dir,-90)) - L.Add(turn(src.dir,90)) - for(var/new_dir in L) - var/obj/structure/table/T = locate() in get_step(src.loc,new_dir) - if(T && T.material && material && T.material.type == material.type) - if(T.flipped == 1 && T.dir == src.dir && !T.unflipping_check(new_dir)) - return 0 - return 1 - -/obj/structure/table/proc/do_put() - set name = "Put table back" - set desc = "Puts flipped table back" - set category = "Object" - set src in oview(1) - - if (!usr.can_touch(src)) - return - - if (!unflipping_check()) - to_chat(usr, "It won't budge.") - return - unflip() - -/obj/structure/table/proc/flip(var/direction) - if( !straight_table_check(turn(direction,90)) || !straight_table_check(turn(direction,-90)) ) - return FALSE - - if(!do_after(usr, 1 SECOND, src)) - return FALSE - verbs -=/obj/structure/table/verb/do_flip - verbs +=/obj/structure/table/proc/do_put - - var/list/targets = list(get_step(src,dir),get_step(src,turn(dir, 45)),get_step(src,turn(dir, -45))) - for (var/atom/movable/A in get_turf(src)) - if (!A.anchored) - spawn(0) - A.throw_at(pick(targets),1,1) - - set_dir(direction) - if(dir != NORTH) - layer = ABOVE_HUMAN_LAYER - atom_flags &= ~ATOM_FLAG_CLIMBABLE //flipping tables allows them to be used as makeshift barriers - flipped = 1 - atom_flags |= ATOM_FLAG_CHECKS_BORDER - for(var/D in list(turn(direction, 90), turn(direction, -90))) - var/obj/structure/table/T = locate() in get_step(src,D) - if(T && T.can_connect() && T.flipped == 0 && material && T.material && T.material.type == material.type) - T.flip(direction) - take_damage(rand(5, 10)) - update_connections(1) - update_icon() - - return TRUE - -/obj/structure/table/proc/unflip() - if(!do_after(usr, 1 SECOND, src)) - return FALSE - verbs -=/obj/structure/table/proc/do_put - verbs +=/obj/structure/table/verb/do_flip - - reset_plane_and_layer() - atom_flags |= ATOM_FLAG_CLIMBABLE - flipped = 0 - atom_flags &= ~ATOM_FLAG_CHECKS_BORDER - for(var/D in list(turn(dir, 90), turn(dir, -90))) - var/obj/structure/table/T = locate() in get_step(src.loc,D) - if(T && T.flipped == 1 && T.dir == src.dir && material && T.material && T.material.type == material.type) - T.unflip() - - update_connections(1) - update_icon() - - return TRUE - -/obj/structure/table/CtrlClick() - if(usr && usr.Adjacent(src)) - if(!flipped) - do_flip() - else - do_put() - return TRUE - return FALSE diff --git a/code/modules/tables/interactions.dm b/code/modules/tables/interactions.dm deleted file mode 100644 index 6b200e9cf26f..000000000000 --- a/code/modules/tables/interactions.dm +++ /dev/null @@ -1,165 +0,0 @@ - -/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 - if(istype(mover,/obj/item/projectile)) - return (check_cover(mover,target)) - if (flipped == 1) - if (get_dir(loc, target) == dir) - return !density - else - return 1 - if(istype(mover) && mover.checkpass(PASS_FLAG_TABLE)) - return 1 - var/obj/structure/table/T = (locate() in get_turf(mover)) - return (T && !T.flipped) //If we are moving from a table, check if it is flipped. - //If the table we are standing on is not flipped, then we can move freely to another table. - - -//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops. -/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from) - var/turf/cover - if(flipped) - cover = get_turf(src) - else - cover = get_step(loc, get_dir(from, loc)) - if(!cover) - return 1 - if (get_dist(P.starting, loc) <= 1) //Tables won't help you if people are THIS close - return 1 - - var/chance = 20 - if(ismob(P.original) && get_turf(P.original) == cover) - var/mob/M = P.original - if (M.lying) - chance += 20 //Lying down lets you catch less bullets - if(flipped) - if(get_dir(loc, from) == dir) //Flipped tables catch mroe bullets - chance += 30 - else - return 1 //But only from one side - - if(prob(chance)) - return 0 //blocked - return 1 - -/obj/structure/table/bullet_act(obj/item/projectile/P) - if(!(P.damage_type == BRUTE || P.damage_type == BURN)) - return 0 - - if(take_damage(P.damage/2)) - //prevent tables with 1 health left from stopping bullets outright - return PROJECTILE_CONTINUE //the projectile destroyed the table, so it gets to keep going - - visible_message("\The [P] hits [src]!") - return 0 - -/obj/structure/table/CheckExit(atom/movable/O, target) - if(istype(O) && O.checkpass(PASS_FLAG_TABLE)) - return 1 - if (flipped==1) - if (get_dir(loc, target) == dir) - return !density - else - return 1 - return 1 - - -/obj/structure/table/MouseDrop_T(obj/O, mob/user) - - if ((!( istype(O, /obj/item) ) || user.get_active_hand() != O)) - return ..() - if(isrobot(user)) - return - user.unequip_item() - if (O.loc != src.loc) - step(O, get_dir(O, src)) - return - -/obj/structure/table/attackby(obj/item/W, mob/user, var/click_params) - - if(!W) - return - - if(user.a_intent == I_HURT && W.force) - return ..() - - if(health != maxhealth && user.a_intent == I_HELP && istype(W, /obj/item/stack/material)) - return ..() - - // Handle dismantling or placing things on the table from here on. - if(isrobot(user)) - return - - if(W.loc != user) // This should stop mounted modules ending up outside the module. - return - - if(W.is_special_cutting_tool()) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src.loc) - spark_system.start() - playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) - playsound(src.loc, "sparks", 50, 1) - user.visible_message("\The [src] was sliced apart by [user]!") - break_to_parts() - return - - if(can_plate && !material) - to_chat(user, "There's nothing to put \the [W] on! Try adding plating to \the [src] first.") - return - - // Placing stuff on tables - if(user.unEquip(W, src.loc)) - auto_align(W, click_params) - return 1 - -/* -Automatic alignment of items to an invisible grid, defined by CELLS and CELLSIZE, defined in code/__defines/misc.dm. -Since the grid will be shifted to own a cell that is perfectly centered on the turf, we end up with two 'cell halves' -on edges of each row/column. -Each item defines a center_of_mass, which is the pixel of a sprite where its projected center of mass toward a turf -surface can be assumed. For a piece of paper, this will be in its center. For a bottle, it will be (near) the bottom -of the sprite. -auto_align() will then place the sprite so the defined center_of_mass is at the bottom left corner of the grid cell -closest to where the cursor has clicked on. -Note: This proc can be overwritten to allow for different types of auto-alignment. -*/ -/obj/item/var/center_of_mass = @"{'x':16,'y':16}" //can be null for no exact placement behaviour -/obj/structure/table/proc/auto_align(obj/item/W, click_params) - if (!W.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy. - W.pixel_x = rand(-W.randpixel, W.randpixel) - W.pixel_y = rand(-W.randpixel, W.randpixel) - W.pixel_z = 0 - return - - if (!click_params) - return - - var/list/click_data = params2list(click_params) - if (!click_data["icon-x"] || !click_data["icon-y"]) - return - - // Calculation to apply new pixelshift. - var/mouse_x = text2num(click_data["icon-x"])-1 // Ranging from 0 to 31 - var/mouse_y = text2num(click_data["icon-y"])-1 - - var/cell_x = Clamp(round(mouse_x/CELLSIZE), 0, CELLS-1) // Ranging from 0 to CELLS-1 - var/cell_y = Clamp(round(mouse_y/CELLSIZE), 0, CELLS-1) - - var/list/center = cached_json_decode(W.center_of_mass) - - W.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] - W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] - W.pixel_z = 0 - -/obj/structure/table/rack/auto_align(obj/item/W, click_params) - if(W && !W.center_of_mass) - ..(W) - - var/i = -1 - for (var/obj/item/I in get_turf(src)) - if (I.anchored || !I.center_of_mass) - continue - i++ - I.pixel_x = 1 // There's a sprite layering bug for 0/0 pixelshift, so we avoid it. - I.pixel_y = max(3-i*3, -3) + 1 - I.pixel_z = 0 diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm deleted file mode 100644 index abce1ffc732d..000000000000 --- a/code/modules/tables/presets.dm +++ /dev/null @@ -1,119 +0,0 @@ -/obj/structure/table/standard - icon_state = "plain_preview" - color = COLOR_OFF_WHITE - material = DEFAULT_FURNITURE_MATERIAL - -/obj/structure/table/steel - icon_state = "plain_preview" - color = COLOR_GRAY40 - material = /decl/material/solid/metal/steel - -/obj/structure/table/marble - icon_state = "stone_preview" - color = COLOR_GRAY80 - material = /decl/material/solid/stone/marble - -/obj/structure/table/reinforced - icon_state = "reinf_preview" - color = COLOR_OFF_WHITE - material = DEFAULT_FURNITURE_MATERIAL - reinf_material = /decl/material/solid/metal/steel - -/obj/structure/table/steel_reinforced - icon_state = "reinf_preview" - color = COLOR_GRAY40 - material = /decl/material/solid/metal/steel - reinf_material = /decl/material/solid/metal/steel - -/obj/structure/table/gamblingtable - icon_state = "gamble_preview" - carpeted = 1 - material = /decl/material/solid/wood/walnut - -/obj/structure/table/glass - icon_state = "plain_preview" - color = COLOR_DEEP_SKY_BLUE - alpha = 77 // 0.3 * 255 - material = /decl/material/solid/glass - -/obj/structure/table/glass/pglass - color = "#8f29a3" - material = /decl/material/solid/glass/borosilicate - -/obj/structure/table/holotable - icon_state = "holo_preview" - color = COLOR_OFF_WHITE - -/obj/structure/table/holotable/Initialize() - material = /decl/material/solid/metal/aluminium/holographic - . = ..() - -/obj/structure/table/holo_plastictable - icon_state = "holo_preview" - color = COLOR_OFF_WHITE - -/obj/structure/table/holo_plastictable/Initialize() - material = /decl/material/solid/plastic/holographic - . = ..() - -/obj/structure/table/holo_woodentable - icon_state = "holo_preview" - -/obj/structure/table/holo_woodentable/Initialize() - material = /decl/material/solid/wood/holographic - . = ..() - -//wood wood wood -/obj/structure/table/woodentable - icon_state = "solid_preview" - color = WOOD_COLOR_GENERIC - material = /decl/material/solid/wood - -/obj/structure/table/woodentable_reinforced - icon_state = "reinf_preview" - color = WOOD_COLOR_GENERIC - material = /decl/material/solid/wood - reinf_material = /decl/material/solid/wood - -/obj/structure/table/woodentable_reinforced/walnut - icon_state = "reinf_preview" - color = WOOD_COLOR_CHOCOLATE - material = /decl/material/solid/wood/walnut - reinf_material = /decl/material/solid/wood/walnut - -/obj/structure/table/woodentable_reinforced/walnut/maple - reinf_material = /decl/material/solid/wood/maple - -/obj/structure/table/woodentable_reinforced/mahogany - icon_state = "reinf_preview" - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood/mahogany - reinf_material = /decl/material/solid/wood/mahogany - -/obj/structure/table/woodentable_reinforced/mahogany/walnut - reinf_material = /decl/material/solid/wood/walnut - -/obj/structure/table/woodentable_reinforced/ebony - icon_state = "reinf_preview" - color = WOOD_COLOR_BLACK - material = /decl/material/solid/wood/ebony - reinf_material = /decl/material/solid/wood/walnut - -/obj/structure/table/woodentable_reinforced/ebony/walnut - reinf_material = /decl/material/solid/wood/walnut - -/obj/structure/table/woodentable/mahogany - color = WOOD_COLOR_RICH - material = /decl/material/solid/wood/mahogany - -/obj/structure/table/woodentable/maple - color = WOOD_COLOR_PALE - material = /decl/material/solid/wood/maple - -/obj/structure/table/woodentable/ebony - color = WOOD_COLOR_BLACK - material = /decl/material/solid/wood/ebony - -/obj/structure/table/woodentable/walnut - color = WOOD_COLOR_CHOCOLATE - material = /decl/material/solid/wood/walnut \ No newline at end of file diff --git a/code/modules/tables/rack.dm b/code/modules/tables/rack.dm deleted file mode 100644 index 2d69e3be6014..000000000000 --- a/code/modules/tables/rack.dm +++ /dev/null @@ -1,40 +0,0 @@ -/obj/structure/table/rack - name = "rack" - desc = "Different from the Middle Ages version." - icon = 'icons/obj/objects.dmi' - icon_state = "rack" - can_plate = 0 - can_reinforce = 0 - flipped = -1 - material = DEFAULT_FURNITURE_MATERIAL - handle_generic_blending = FALSE - -/obj/structure/table/rack/Initialize() - . = ..() - verbs -= /obj/structure/table/verb/do_flip - verbs -= /obj/structure/table/proc/do_put - -/obj/structure/table/rack/Initialize() - auto_align() - . = ..() - -/obj/structure/table/rack/update_connections() - return - -/obj/structure/table/rack/update_desc() - return - -/obj/structure/table/rack/on_update_icon() - return - -/obj/structure/table/rack/can_connect() - return FALSE - -/obj/structure/table/rack/holorack/dismantle() - material = null - reinf_material = null - parts_type = null - . = ..() - -/obj/structure/table/rack/dark - color = COLOR_GRAY40 diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm deleted file mode 100644 index 815d258d0c74..000000000000 --- a/code/modules/tables/tables.dm +++ /dev/null @@ -1,464 +0,0 @@ -/obj/structure/table - name = "table frame" - icon = 'icons/obj/structures/tables.dmi' - icon_state = "frame" - desc = "It's a table, for putting things on. Or standing on, if you really want to." - density = 1 - anchored = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE - layer = TABLE_LAYER - throwpass = 1 - mob_offset = 12 - handle_generic_blending = TRUE - maxhealth = 10 - - var/flipped = 0 - - // For racks. - var/can_reinforce = 1 - var/can_plate = 1 - var/manipulating = 0 - - // Gambling tables. I'd prefer reinforced with carpet/felt/cloth/whatever, but AFAIK it's either harder or impossible to get /obj/item/stack/material of those. - // Convert if/when you can easily get stacks of these. - var/carpeted = 0 - - var/list/connections = list("nw0", "ne0", "sw0", "se0") - var/list/other_connections - -/obj/structure/table/clear_connections() - connections = null - other_connections = null - -/obj/structure/table/set_connections(dirs, other_dirs) - connections = dirs_to_corner_states(dirs) - other_connections = dirs_to_corner_states(other_dirs) - -/obj/structure/table/Initialize() - . = ..() - for(var/obj/structure/table/T in loc) - if(T != src) - break_to_parts(full_return = 1) - return - if(. != INITIALIZE_HINT_QDEL) - . = INITIALIZE_HINT_LATELOAD - -// We do this because need to make sure adjacent tables init their material before we try and merge. -/obj/structure/table/LateInitialize() - ..() - update_connections(1) - update_icon() - update_desc() - -/obj/structure/table/get_material_health_modifier() - . = 0.5 - -/obj/structure/table/physically_destroyed() - SHOULD_CALL_PARENT(FALSE) - visible_message(SPAN_DANGER("\The [src] breaks down!")) - . = break_to_parts() - -/obj/structure/table/Destroy() - material = null - reinf_material = null - update_connections(1) // Update tables around us to ignore us (material=null forces no connections) - for(var/obj/structure/table/T in oview(src, 1)) - T.update_icon() - . = ..() - -/obj/structure/table/attackby(obj/item/W, mob/user) - - if(reinf_material && isScrewdriver(W)) - remove_reinforced(W, user) - if(!reinf_material) - update_desc() - update_icon() - update_materials() - return 1 - - if(carpeted && isCrowbar(W)) - user.visible_message("\The [user] removes the carpet from \the [src].", - "You remove the carpet from \the [src].") - new /obj/item/stack/tile/carpet(loc) - carpeted = 0 - update_icon() - return 1 - - if(!carpeted && material && istype(W, /obj/item/stack/tile/carpet)) - var/obj/item/stack/tile/carpet/C = W - if(C.use(1)) - user.visible_message("\The [user] adds \the [C] to \the [src].", - "You add \the [C] to \the [src].") - carpeted = 1 - update_icon() - return 1 - else - to_chat(user, "You don't have enough carpet!") - - if(!reinf_material && !carpeted && material && isWrench(W) && user.a_intent == I_HURT) //robots dont have disarm so it's harm - remove_material(W, user) - if(!material) - update_connections(1) - update_icon() - for(var/obj/structure/table/T in oview(src, 1)) - T.update_icon() - update_desc() - update_materials() - return 1 - - if(!carpeted && !reinf_material && !material && isWrench(W) && user.a_intent == I_HURT) - if(manipulating) - return - manipulating = TRUE - user.visible_message(SPAN_NOTICE("\The [user] begins dismantling \the [src].")) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(!do_after(user, 20, src)) - manipulating = FALSE - return - user.visible_message(SPAN_NOTICE("\The [user] dismantles \the [src].")) - dismantle() - return 1 - - if(!material && can_plate && istype(W, /obj/item/stack/material)) - material = common_material_add(W, user, "plat") - if(material) - update_connections(1) - update_icon() - update_desc() - update_materials() - return 1 - if(istype(W, /obj/item/hand)) //playing cards - var/obj/item/hand/H = W - if(H.cards && H.cards.len == 1) - usr.visible_message("\The [user] plays \the [H.cards[1].name].") - - if(istype(W, /obj/item/deck)) //playing cards - if(user.a_intent == I_GRAB) - var/obj/item/deck/D = W - if(!D.cards.len) - to_chat(user, "There are no cards in the deck.") - return - D.deal_at(user, src) - return - - return ..() - -/obj/structure/table/MouseDrop_T(obj/item/stack/material/what) - if(can_reinforce && isliving(usr) && (!usr.stat) && istype(what) && usr.get_active_hand() == what && Adjacent(usr)) - reinforce_table(what, usr) - else - return ..() - -/obj/structure/table/proc/reinforce_table(obj/item/stack/material/S, mob/user) - if(reinf_material) - to_chat(user, "\The [src] is already reinforced!") - return - - if(!can_reinforce) - to_chat(user, "\The [src] cannot be reinforced!") - return - - if(!material) - to_chat(user, "Plate \the [src] before reinforcing it!") - return - - if(flipped) - to_chat(user, "Put \the [src] back in place before reinforcing it!") - return - - reinf_material = common_material_add(S, user, "reinforc") - if(reinf_material) - update_materials() - -/obj/structure/table/proc/update_desc() - if(material) - name = "[material.solid_name] table" - else - name = "table frame" - - if(reinf_material) - name = "reinforced [name]" - desc = "[initial(desc)] This one seems to be reinforced with [reinf_material.solid_name]." - else - desc = initial(desc) - -// Returns the material to set the table to. -/obj/structure/table/proc/common_material_add(obj/item/stack/material/S, mob/user, verb) // Verb is actually verb without 'e' or 'ing', which is added. Works for 'plate'/'plating' and 'reinforce'/'reinforcing'. - var/decl/material/M = S.get_material() - if(!istype(M)) - to_chat(user, "You cannot [verb]e \the [src] with \the [S].") - return null - - if(manipulating) return M - manipulating = 1 - to_chat(user, "You begin [verb]ing \the [src] with [M.solid_name].") - if(!do_after(user, 20, src) || !S.use(1)) - manipulating = 0 - return null - user.visible_message("\The [user] [verb]es \the [src] with [M.solid_name].", "You finish [verb]ing \the [src].") - manipulating = 0 - return M - -// Returns the material to set the table to. -/obj/structure/table/proc/common_material_remove(mob/user, decl/material/M, delay, what, type_holding, sound) - if(!M.stack_type) - to_chat(user, "You are unable to remove the [what] from this table!") - return M - - if(manipulating) return M - manipulating = 1 - user.visible_message("\The [user] begins removing the [type_holding] holding \the [src]'s [M.solid_name] [what] in place.", - "You begin removing the [type_holding] holding \the [src]'s [M.solid_name] [what] in place.") - if(sound) - playsound(src.loc, sound, 50, 1) - if(!do_after(user, 40, src)) - manipulating = 0 - return M - user.visible_message("\The [user] removes the [M.solid_name] [what] from \the [src].", - "You remove the [M.solid_name] [what] from \the [src].") - M.place_sheet(src.loc) - manipulating = 0 - return null - -/obj/structure/table/proc/remove_reinforced(obj/item/screwdriver/S, mob/user) - reinf_material = common_material_remove(user, reinf_material, 40, "reinforcements", "screws", 'sound/items/Screwdriver.ogg') - -/obj/structure/table/proc/remove_material(obj/item/wrench/W, mob/user) - material = common_material_remove(user, material, 20, "plating", "bolts", 'sound/items/Ratchet.ogg') - -// Returns a list of /obj/item/shard objects that were created as a result of this table's breakage. -// Used for !fun! things such as embedding shards in the faces of tableslammed people. - -// The repeated -// S = [x].place_shard(loc) -// if(S) shards += S -// is to avoid filling the list with nulls, as place_shard won't place shards of certain materials (holo-wood, holo-steel) - -/obj/structure/table/proc/break_to_parts(full_return = 0) - reset_mobs_offset() - var/list/shards = list() - var/obj/item/shard/S = null - if(reinf_material) - if(reinf_material.stack_type && (full_return || prob(20))) - reinf_material.place_sheet(loc) - else - S = reinf_material.place_shard(loc) - if(S) shards += S - if(material) - if(material.stack_type && (full_return || prob(20))) - material.place_sheet(loc) - else - S = material.place_shard(loc) - if(S) shards += S - if(carpeted && (full_return || prob(50))) // Higher chance to get the carpet back intact, since there's no non-intact option - new /obj/item/stack/tile/carpet(src.loc) - if(full_return || prob(20)) - new /obj/item/stack/material/steel(src.loc) - else - var/decl/material/M = decls_repository.get_decl(/decl/material/solid/metal/steel) - S = M.place_shard(loc) - if(S) shards += S - qdel(src) - return shards - -/obj/structure/table/on_update_icon() - color = "#ffffff" - alpha = 255 - if(!flipped) - mob_offset = initial(mob_offset) - icon_state = "blank" - overlays.Cut() - var/image/I - // Base frame shape. Mostly done for glass/diamond tables, where this is visible. - for(var/i = 1 to 4) - I = image(icon, dir = 1<<(i-1), icon_state = connections ? connections[i] : "0") - overlays += I - // Standard table image - if(material) - for(var/i = 1 to 4) - I = image(icon, "[material.table_icon_base]_[connections ? connections[i] : "0"]", dir = 1<<(i-1)) - if(material.color) I.color = material.color - I.alpha = 255 * material.opacity - overlays += I - // Reinforcements - if(reinf_material) - for(var/i = 1 to 4) - I = image(icon, "[reinf_material.table_reinf]_[connections ? connections[i] : "0"]", dir = 1<<(i-1)) - I.color = reinf_material.color - I.alpha = 255 * reinf_material.opacity - overlays += I - if(carpeted) - for(var/i = 1 to 4) - I = image(icon, "carpet_[connections ? connections[i] : "0"]", dir = 1<<(i-1)) - overlays += I - else - mob_offset = 0 - overlays.Cut() - var/type = 0 - var/tabledirs = 0 - for(var/direction in list(turn(dir,90), turn(dir,-90)) ) - var/obj/structure/table/T = locate(/obj/structure/table ,get_step(src,direction)) - if (T && T.flipped == 1 && T.dir == src.dir && istype(material) && istype(T.material) && T.material.type == material.type) - type++ - tabledirs |= direction - type = "[type]" - if (type=="1") - if (tabledirs & turn(dir,90)) - type += "-" - if (tabledirs & turn(dir,-90)) - type += "+" - icon_state = "flip[type]" - if(material) - var/image/I = image(icon, "[material.table_icon_base]_flip[type]") - I.color = material.color - I.alpha = 255 * material.opacity - overlays += I - name = "[material.solid_name] table" - else - name = "table frame" - if(reinf_material) - var/image/I = image(icon, "[reinf_material.table_reinf]_flip[type]") - I.color = reinf_material.color - I.alpha = 255 * reinf_material.opacity - overlays += I - if(carpeted) - overlays += "carpet_flip[type]" - -/obj/structure/table/proc/can_connect() - return TRUE - -// set propagate if you're updating a table that should update tables around it too, for example if it's a new table or something important has changed (like material). -/obj/structure/table/update_connections(propagate=0) - if(!material) - connections = list("0", "0", "0", "0") - - if(propagate) - for(var/obj/structure/table/T in oview(src, 1)) - T.update_connections() - return - - var/list/blocked_dirs = list() - for(var/obj/structure/window/W in get_turf(src)) - if(W.is_fulltile()) - connections = list("0", "0", "0", "0") - return - blocked_dirs |= W.dir - - for(var/D in list(NORTH, SOUTH, EAST, WEST) - blocked_dirs) - var/turf/T = get_step(src, D) - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == GLOB.reverse_dir[D]) - blocked_dirs |= D - break - else - if(W.dir != D) // it's off to the side - blocked_dirs |= W.dir|D // blocks the diagonal - - for(var/D in list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - blocked_dirs) - var/turf/T = get_step(src, D) - - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || (W.dir & GLOB.reverse_dir[D])) - blocked_dirs |= D - break - - // Blocked cardinals block the adjacent diagonals too. Prevents weirdness with tables. - for(var/x in list(NORTH, SOUTH)) - for(var/y in list(EAST, WEST)) - if((x in blocked_dirs) || (y in blocked_dirs)) - blocked_dirs |= x|y - - var/list/connection_dirs = list() - - for(var/obj/structure/table/T in orange(src, 1)) - if(!T.can_connect()) continue - var/T_dir = get_dir(src, T) - if(T_dir in blocked_dirs) continue - if(material && T.material && material.type == T.material.type && flipped == T.flipped) - connection_dirs |= T_dir - if(propagate) - spawn(0) - T.update_connections() - T.update_icon() - - connections = dirs_to_corner_states(connection_dirs) - -#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 - -/* - 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 - -// 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 = 1 << (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 \ No newline at end of file diff --git a/code/modules/tables/update_triggers.dm b/code/modules/tables/update_triggers.dm deleted file mode 100644 index 6376edf4783f..000000000000 --- a/code/modules/tables/update_triggers.dm +++ /dev/null @@ -1,20 +0,0 @@ -/obj/structure/window/LateInitialize() - ..() - for(var/obj/structure/table/T in view(src, 1)) - T.update_connections() - T.update_icon() - -/obj/structure/window/Destroy() - var/oldloc = loc - . = ..() - for(var/obj/structure/table/T in view(oldloc, 1)) - T.update_connections() - T.update_icon() - -/obj/structure/window/Move() - var/oldloc = loc - . = ..() - if(loc != oldloc) - for(var/obj/structure/table/T in view(oldloc, 1) | view(loc, 1)) - T.update_connections() - T.update_icon() \ No newline at end of file diff --git a/code/modules/tools/archetypes/_tool_defines.dm b/code/modules/tools/archetypes/_tool_defines.dm new file mode 100644 index 000000000000..8c74ff03b039 --- /dev/null +++ b/code/modules/tools/archetypes/_tool_defines.dm @@ -0,0 +1,3 @@ +#define TOOL_USE_FAILURE_NOMESSAGE -1 +#define TOOL_USE_FAILURE 0 +#define TOOL_USE_SUCCESS 1 diff --git a/code/modules/tools/archetypes/tool_archetype.dm b/code/modules/tools/archetypes/tool_archetype.dm new file mode 100644 index 000000000000..bc5c26a709d1 --- /dev/null +++ b/code/modules/tools/archetypes/tool_archetype.dm @@ -0,0 +1,57 @@ +/decl/tool_archetype + abstract_type = /decl/tool_archetype + /// Noun for the tool. + var/name = "tool" + /// Boolean value for prefixing 'a' or 'an' to the tool name. + var/article = TRUE + /// Sound or list of sounds to play when this tool is selected as a variable tool head. + var/config_sound = 'sound/items/Ratchet.ogg' + var/codex_key + /// Sound or list of sounds to play when this tool is used. + var/tool_sound = 'sound/items/Deconstruct.ogg' + var/tool_message = "adjusting" + /// A list of named tool specific properties this tool offers, and the default value of that property, if applicable. + var/list/properties + +/decl/tool_archetype/proc/can_use_tool(var/obj/item/tool, var/expend_fuel = 0) + return istype(tool) && tool.get_tool_quality(type) > 0 + +/decl/tool_archetype/proc/handle_pre_interaction(var/mob/user, var/obj/item/tool, var/expend_fuel = 0) + return TOOL_USE_SUCCESS + +/decl/tool_archetype/proc/handle_post_interaction(var/mob/user, var/obj/item/tool, var/expend_fuel = 0) + return TOOL_USE_SUCCESS + +/decl/tool_archetype/proc/get_tool_quality_descriptor(var/value) + + if(value < TOOL_QUALITY_WORST) + return + + switch(value) + if(TOOL_QUALITY_GOOD to INFINITY) + . = "excellent" + if(TOOL_QUALITY_DECENT to TOOL_QUALITY_GOOD) + . = "decent" + if(TOOL_QUALITY_DEFAULT to TOOL_QUALITY_DECENT) + . = "adequate" + if(TOOL_QUALITY_MEDIOCRE to TOOL_QUALITY_DEFAULT) + . = "mediocre" + if(TOOL_QUALITY_BAD to TOOL_QUALITY_MEDIOCRE) + . = "bad" + if(0 to TOOL_QUALITY_BAD) + . = "awful" + + if(.) + if(article) + . = "\a [.]" + . = "[.] [name]" + if(value < TOOL_QUALITY_MEDIOCRE) + . = SPAN_WARNING(.) + else if(value > TOOL_QUALITY_DECENT) + . = SPAN_NOTICE(.) + +/decl/tool_archetype/proc/get_default_quality(obj/item/tool) + return 0 + +/decl/tool_archetype/proc/get_default_speed(obj/item/tool) + return TOOL_SPEED_WORST // Need to return a non-zero/null value to avoid bugs. diff --git a/code/modules/tools/archetypes/tool_archetype_definition_pen.dm b/code/modules/tools/archetypes/tool_archetype_definition_pen.dm new file mode 100644 index 000000000000..4fd8e0f8bdf7 --- /dev/null +++ b/code/modules/tools/archetypes/tool_archetype_definition_pen.dm @@ -0,0 +1,62 @@ +/decl/tool_archetype/pen + name = "pen" + tool_message = "writing" + tool_sound = list('sound/effects/pen1.ogg','sound/effects/pen2.ogg') + properties = list( + TOOL_PROP_COLOR = "black", + TOOL_PROP_COLOR_NAME = "black", + TOOL_PROP_PEN_FLAG = 0, + TOOL_PROP_USES = -1, + TOOL_PROP_PEN_SIG = null, + TOOL_PROP_PEN_SHADE_COLOR = "black", + TOOL_PROP_PEN_FONT = PEN_FONT_DEFAULT, + ) + +/**Returns the signature to use when signing with a pen. Meant to help deal with chameleon pens and regular pens. */ +/decl/tool_archetype/pen/proc/get_signature(var/mob/user, var/obj/item/tool) + . = tool.get_tool_property(TOOL_PEN, TOOL_PROP_PEN_SIG) + if(!.) + if(user?.real_name) + . = user.real_name + else + . = "Anonymous" + +/decl/tool_archetype/pen/proc/decrement_uses(var/mob/user, var/obj/item/tool, var/decrement = 1, var/destroy_on_zero = TRUE) + . = tool.get_tool_property(TOOL_PEN, TOOL_PROP_USES) + if(. < 0) + return TRUE + . -= decrement + tool.set_tool_property(TOOL_PEN, TOOL_PROP_USES, max(0, .)) //Prevent negatives and turning the pen into an infinite uses pen + tool.update_icon() + if(. <= 0 && (tool.get_tool_property(TOOL_PEN, TOOL_PROP_PEN_FLAG) & PEN_FLAG_DEL_EMPTY)) + . = 0 + if(destroy_on_zero) + qdel(tool) + +/decl/tool_archetype/pen/proc/warn_out_of_ink(mob/user, obj/item/tool, default = "spent") + var/message = tool.get_tool_property(TOOL_PEN, TOOL_PROP_EMPTY_MESSAGE) || default + to_chat(user, SPAN_WARNING("\The [tool] is [message].")) // example: 'out of ink' + +/**Toggles the active/inactive state of some pens */ +/decl/tool_archetype/pen/proc/toggle_active(var/mob/user, var/obj/item/pen/tool) + //only a single type of pen can toggle + if(istype(tool, /obj/item/pen)) + tool.toggle() + +/decl/tool_archetype/pen/can_use_tool(obj/item/tool, expend_fuel = 1) + var/uses = tool.get_tool_property(TOOL_PEN, TOOL_PROP_USES) + return ..() && ((uses < 0) || (uses - expend_fuel) >= 0) + +/decl/tool_archetype/pen/handle_pre_interaction(mob/user, obj/item/tool, expend_fuel = 1) + var/uses_left = tool.get_tool_property(TOOL_PEN, TOOL_PROP_USES) + if(uses_left < 0) + return TOOL_USE_SUCCESS //Infinite + if(uses_left == 0) + warn_out_of_ink(user, tool) + return TOOL_USE_FAILURE + return TOOL_USE_SUCCESS + +/decl/tool_archetype/pen/handle_post_interaction(mob/user, obj/item/tool, expend_fuel = 1) + if(decrement_uses(user, tool, expend_fuel) <= 0) + warn_out_of_ink(user, tool) + return TOOL_USE_SUCCESS \ No newline at end of file diff --git a/code/modules/tools/archetypes/tool_archetype_definitions.dm b/code/modules/tools/archetypes/tool_archetype_definitions.dm new file mode 100644 index 000000000000..61dfd1f5d668 --- /dev/null +++ b/code/modules/tools/archetypes/tool_archetype_definitions.dm @@ -0,0 +1,90 @@ +/decl/tool_archetype/cable_coil + name = "cable coil" + tool_message = "rewiring" + +/decl/tool_archetype/wirecutters + name = "wirecutters" + article = FALSE + tool_sound = 'sound/items/Wirecutter.ogg' + codex_key = TOOL_CODEX_WIRECUTTERS + tool_message = "snipping" + +/decl/tool_archetype/screwdriver + name = "screwdriver" + tool_sound = 'sound/items/Screwdriver.ogg' + codex_key = TOOL_CODEX_SCREWDRIVER + +/decl/tool_archetype/multitool + name = "multitool" + codex_key = TOOL_CODEX_MULTITOOL + tool_message = "reconfiguring" + +/decl/tool_archetype/crowbar + name = "crowbar" + codex_key = TOOL_CODEX_CROWBAR + tool_message = "levering" + +/decl/tool_archetype/hatchet + name = "hatchet" + tool_sound = 'sound/items/axe_wood.ogg' + tool_message = "chopping" + +/decl/tool_archetype/wrench + name = "wrench" + tool_sound = 'sound/items/Ratchet.ogg' + codex_key = TOOL_CODEX_WRENCH + +/decl/tool_archetype/shovel + name = "shovel" + tool_sound = 'sound/items/shovel_dirt.ogg' + tool_message = "digging into" + +/decl/tool_archetype/pick + name = "pick" + tool_sound = 'sound/weapons/Genhit.ogg' + tool_message = "excavating" + +/decl/tool_archetype/hammer + name = "hammer" + tool_sound = 'sound/weapons/Genhit.ogg' + tool_message = "striking" + +/decl/tool_archetype/hoe + name = "hoe" + tool_sound = 'sound/items/shovel_dirt.ogg' + tool_message = "tilling" + +/decl/tool_archetype/stamp + name = "stamp" + tool_message = "stamping" + +/decl/tool_archetype/shears + name = "shears" + tool_sound = 'sound/weapons/bladeslice.ogg' + tool_message = "shearing" + +/decl/tool_archetype/chisel + name = "chisel" + tool_sound = 'sound/items/shovel_dirt.ogg' + tool_message = "chiseling" + +/decl/tool_archetype/knife + name = "knife" + tool_sound = 'sound/weapons/bladeslice.ogg' + tool_message = "cutting" + +/decl/tool_archetype/knife/get_default_quality(obj/item/tool) + if(tool) + if(tool.is_sharp() && tool.has_edge()) + return TOOL_QUALITY_DEFAULT + else if(tool.is_sharp() || tool.has_edge()) + return TOOL_QUALITY_MEDIOCRE + return ..() + +/decl/tool_archetype/knife/get_default_speed(obj/item/tool) + if(tool) + if(tool.is_sharp() && tool.has_edge()) + return TOOL_SPEED_DEFAULT + else if(tool.is_sharp() || tool.has_edge()) + return TOOL_SPEED_MEDIOCRE + return ..() diff --git a/code/modules/tools/archetypes/tool_archetype_definitions_surgery.dm b/code/modules/tools/archetypes/tool_archetype_definitions_surgery.dm new file mode 100644 index 000000000000..3da7b83011f1 --- /dev/null +++ b/code/modules/tools/archetypes/tool_archetype_definitions_surgery.dm @@ -0,0 +1,36 @@ +/decl/tool_archetype/scalpel + name = "scalpel" + tool_message = "slicing" + +/decl/tool_archetype/retractor + name = "retractor" + tool_message = "retracting" + +/decl/tool_archetype/hemostat + name = "hemostat" + +/decl/tool_archetype/saw + name = "surgical saw" + tool_message = "sawwing" + +/decl/tool_archetype/cautery + name = "cautery" + tool_message = "cauterizing" + +/decl/tool_archetype/sutures + name = "sutures" + article = FALSE + tool_message = "suturing" + +/decl/tool_archetype/bone_gel + name = "bone gel" + article = FALSE + tool_message = "gluing" + +/decl/tool_archetype/bone_setter + name = "bone setter" + tool_message = "setting" + +/decl/tool_archetype/surgical_drill + name = "surgical drill" + tool_message = "drilling" diff --git a/code/modules/tools/archetypes/tool_archetype_definitions_welder.dm b/code/modules/tools/archetypes/tool_archetype_definitions_welder.dm new file mode 100644 index 000000000000..38785e04ec32 --- /dev/null +++ b/code/modules/tools/archetypes/tool_archetype_definitions_welder.dm @@ -0,0 +1,29 @@ +/decl/tool_archetype/welder + name = "welder" + tool_sound = list('sound/items/Welder.ogg','sound/items/Welder2.ogg') + codex_key = TOOL_CODEX_WELDER + tool_message = "welding" + +/decl/tool_archetype/welder/handle_pre_interaction(var/mob/user, var/obj/item/tool, var/expend_fuel = 0) + var/obj/item/weldingtool/welder = tool + if(!istype(tool) || !expend_fuel) + return TOOL_USE_SUCCESS // Let's assume that this tool value is only given to non-welders if they should bypass fuel usage. + if(!welder.isOn()) + to_chat(user, SPAN_WARNING("\The [welder] needs to be turned on to begin this task.")) + return TOOL_USE_FAILURE + if(!welder.weld(expend_fuel, user)) + to_chat(user, SPAN_WARNING("You need more fuel to begin this task.")) + return TOOL_USE_FAILURE + return TOOL_USE_SUCCESS + +/decl/tool_archetype/welder/handle_post_interaction(var/mob/user, var/obj/item/tool, var/expend_fuel = 0) + var/obj/item/weldingtool/welder = tool + if(!istype(tool) || !expend_fuel) + return TOOL_USE_SUCCESS + if(!welder.isOn()) + to_chat(user, SPAN_WARNING("\The [welder] needs to be turned on to finish this task.")) + return TOOL_USE_FAILURE + if(!welder.weld(expend_fuel, user)) + to_chat(user, SPAN_WARNING("You need more fuel to finish this task.")) + return TOOL_USE_FAILURE + return TOOL_USE_SUCCESS diff --git a/code/modules/tools/archetypes/tool_extension.dm b/code/modules/tools/archetypes/tool_extension.dm new file mode 100644 index 000000000000..d7fbe0977afd --- /dev/null +++ b/code/modules/tools/archetypes/tool_extension.dm @@ -0,0 +1,126 @@ +/datum/extension/tool + expected_type = /obj/item + base_type = /datum/extension/tool + var/list/tool_values // Delay multipliers/general tool quality indicators, lower is better but 0 or lower means it isn't valid as a tool. + var/list/tool_use_sounds // Associative list of tool to sound/list of sounds used to override the archetype config sounds. + var/list/tool_properties // Associative list of tool archetype to a list of properties and their values for that archetype. + +/datum/extension/tool/New(datum/holder, list/_tool_values, list/_tool_properties) + ..() + tool_values = _tool_values + for(var/atype in _tool_properties) + var/list/cur_props = LAZYACCESS(tool_properties, atype)? tool_properties[atype] + _tool_properties[atype] : _tool_properties[atype] + LAZYSET(tool_properties, atype, cur_props) + +/datum/extension/tool/proc/set_sound_overrides(list/_tool_use_sounds) + + // If we are supplied a list, assume it's an assoc list of tool types to sound. + if(islist(_tool_use_sounds)) + tool_use_sounds = _tool_use_sounds + else // Otherwise, init the list, and assume a non-list non-null value is an override for all tool types. + tool_use_sounds = list() + if(_tool_use_sounds) + for(var/tool in tool_values) + tool_use_sounds[tool] = _tool_use_sounds + + // Fill in any unset tools with the default sound for the tool type. + for(var/tool in tool_values) + if(isnull(tool_use_sounds[tool])) + var/decl/tool_archetype/tool_archetype = GET_DECL(tool) + tool_use_sounds[tool] = tool_archetype.tool_sound + +/datum/extension/tool/proc/get_tool_speed(archetype) + . = clamp((TOOL_QUALITY_BEST - get_tool_quality(archetype)), TOOL_SPEED_BEST, TOOL_SPEED_WORST) + +/datum/extension/tool/proc/get_tool_quality(archetype) + return LAZYACCESS(tool_values, archetype) + +/**Return the value of the property specified for the given tool archetype. */ +/datum/extension/tool/proc/get_tool_property(archetype, property) + var/list/props = LAZYACCESS(tool_properties, archetype) + //If we don't override, check the datum's default values + if(!LAZYLEN(props)) + var/decl/tool_archetype/T = GET_DECL(archetype) + props = T.properties + return LAZYACCESS(props, property) + +/**Set the given tool property for the given tool archetype */ +/datum/extension/tool/proc/set_tool_property(archetype, property, value) + var/list/props = LAZYACCESS(tool_properties, archetype) + if(!props) + LAZYSET(tool_properties, archetype, list()) //Init the properties override list + props = tool_properties[archetype] + LAZYSET(props, property, value) + +/datum/extension/tool/proc/handle_physical_manipulation(mob/user) + return FALSE + +/datum/extension/tool/proc/get_tool_message(archetype) + var/decl/tool_archetype/tool_archetype = istype(archetype, /decl/tool_archetype) ? archetype : GET_DECL(archetype) + return get_tool_property(archetype, TOOL_PROP_VERB) || tool_archetype.tool_message + +/datum/extension/tool/proc/get_tool_sound(archetype) + var/decl/tool_archetype/tool_archetype = istype(archetype, /decl/tool_archetype) ? archetype : GET_DECL(archetype) + return LAZYACCESS(tool_use_sounds, archetype) || get_tool_property(archetype, TOOL_PROP_SOUND) || tool_archetype.tool_sound + +/datum/extension/tool/proc/get_expected_tool_use_delay(archetype, delay, mob/user, check_skill = SKILL_CONSTRUCTION) + . = ceil(delay * get_tool_speed(archetype)) + if(user && check_skill) + . *= user.skill_delay_mult(check_skill, 0.3) + . = max(round(.), 5) + +// Returns a failure message as a string if the interaction fails. +/proc/handle_tool_interaction(archetype, mob/user, obj/item/tool, atom/target, delay = (1 SECOND), start_message, success_message, failure_message, fuel_expenditure = 0, check_skill = SKILL_CONSTRUCTION, prefix_message, suffix_message, check_skill_threshold, check_skill_prob = 50, set_cooldown = FALSE) + + if(!istype(user) || !istype(target)) + return TOOL_USE_FAILURE_NOMESSAGE + + var/decl/tool_archetype/tool_archetype = GET_DECL(archetype) + var/check_result = tool_archetype.can_use_tool(tool, fuel_expenditure) + if(check_result != TOOL_USE_SUCCESS) + return check_result + + check_result = tool_archetype.handle_pre_interaction(user, tool, fuel_expenditure) + if(check_result != TOOL_USE_SUCCESS) + return check_result + + user.visible_message( + SPAN_NOTICE("\The [user] begins [start_message || tool_archetype.tool_message] \the [target] with \the [tool]."), + SPAN_NOTICE("You begin [start_message || tool_archetype.tool_message] \the [target] with \the [tool].") + ) + + var/datum/extension/tool/tool_data = get_extension(tool, /datum/extension/tool) + var/use_sound = istype(tool_data) ? tool_data.get_tool_sound(archetype) : null + if(islist(use_sound)) + if(length(use_sound)) + use_sound = pick(use_sound) + else + use_sound = null + if(use_sound) + playsound(user.loc, use_sound, 100) + + // If we have a delay, reduce it by the tool speed and then further reduce via skill if necessary. + // Skill multiplier is applied to delay do_skilled() so skip it in get_expected_tool_use_delay() + var/use_delay = delay ? (tool_data ? tool_data.get_expected_tool_use_delay(archetype, delay, user, check_skill = FALSE) : delay) : 0 + if(use_delay) + if(check_skill) + if(!user.do_skilled(delay, check_skill, target, check_holding = TRUE, set_cooldown = set_cooldown)) + return TOOL_USE_FAILURE_NOMESSAGE + else + if(!do_after(user, delay, target, check_holding = TRUE, set_cooldown = set_cooldown)) + return TOOL_USE_FAILURE_NOMESSAGE + + // Basic skill check for the action - do it post-delay so they can't just spamclick. + if(check_skill && check_skill_threshold && check_skill_prob) + if(prob(user.skill_fail_chance(check_skill, check_skill_prob, check_skill_threshold))) + to_chat(user, SPAN_WARNING("You fumble hopelessly with \the [tool].")) + return TOOL_USE_FAILURE + + check_result = tool_archetype.handle_post_interaction(user, tool, fuel_expenditure) + if(check_result != TOOL_USE_SUCCESS) + return check_result + + if(check_result == TOOL_USE_SUCCESS && use_sound) + playsound(user.loc, use_sound, 100) //A lot of interactions played a sound when starting and ending the interaction. This was missed. + + return TOOL_USE_SUCCESS diff --git a/code/modules/tools/archetypes/tool_extension_variable.dm b/code/modules/tools/archetypes/tool_extension_variable.dm new file mode 100644 index 000000000000..df714e62a920 --- /dev/null +++ b/code/modules/tools/archetypes/tool_extension_variable.dm @@ -0,0 +1,62 @@ +/datum/extension/tool/variable + var/current_tool + var/list/tool_config_sounds // Associative list of tool to sound/list of sounds used to override the archetype use sounds. + +/datum/extension/tool/variable/set_sound_overrides(list/_tool_use_sounds, list/_tool_config_sounds) + ..() + + // If we are supplied a list, assume it's an assoc list of tool types to sound. + if(islist(_tool_config_sounds)) + tool_config_sounds = _tool_config_sounds + else // Otherwise, init the list, and assume a non-list non-null value is an override for all tool types. + tool_config_sounds = list() + if(_tool_config_sounds) + for(var/tool in tool_values) + tool_config_sounds[tool] = _tool_config_sounds + + // Fill in any unset tools with the default sound for the tool type. + for(var/tool in tool_values) + if(isnull(tool_config_sounds[tool])) + var/decl/tool_archetype/tool_archetype = GET_DECL(tool) + tool_config_sounds[tool] = tool_archetype.config_sound + +/datum/extension/tool/variable/New(datum/holder, list/_tool_values, list/_tool_use_sounds) + ..() + if(length(tool_values) < 2) + PRINT_STACK_TRACE("Variable tool extension created with [length(tool_values)]] tool value\s, requires minimum of 2.") + return + current_tool = tool_values[1] + +/datum/extension/tool/variable/get_tool_quality(archetype) + return (current_tool == archetype) ? ..() : 0 + +/datum/extension/tool/variable/get_tool_speed(archetype) + return (current_tool == archetype) ? ..() : INFINITY + +/datum/extension/tool/variable/handle_physical_manipulation(var/mob/user) + return switch_tool(next_in_list(current_tool, tool_values), user) + +/datum/extension/tool/variable/proc/switch_tool(new_tool, mob/user) + if(!(new_tool in tool_values)) + CRASH("Invalid tool mode [new_tool] passed to [holder]'s [type]!") + current_tool = new_tool + var/config_sound = LAZYACCESS(tool_config_sounds, current_tool) + if(islist(config_sound) && length(config_sound)) + config_sound = pick(config_sound) + if(config_sound) + playsound(user.loc, config_sound, 50, 1) + var/decl/tool_archetype/tool_archetype = GET_DECL(current_tool) + var/tool_name = tool_archetype.name + if(tool_archetype.article) + tool_name = "\a [tool_name]" + + to_chat(user, get_adjustment_message(tool_name)) + var/atom/A = holder + A.update_icon() + return TRUE + +/datum/extension/tool/variable/proc/get_adjustment_message(tool_name) + return SPAN_NOTICE("You adjust \the [holder] to function as [tool_name].") + +/datum/extension/tool/variable/simple/get_adjustment_message(tool_name) + return SPAN_NOTICE("You adjust your grip on \the [holder] to use it as [tool_name].") \ No newline at end of file diff --git a/code/modules/tools/archetypes/tool_item.dm b/code/modules/tools/archetypes/tool_item.dm new file mode 100644 index 000000000000..51f0d6ed62a2 --- /dev/null +++ b/code/modules/tools/archetypes/tool_item.dm @@ -0,0 +1,93 @@ +/obj/item/proc/get_tool_quality(var/archetype) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.get_tool_quality(archetype) + if(!.) + var/decl/tool_archetype/tool_arch = GET_DECL(archetype) + . = tool_arch.get_default_quality(src) + +/obj/item/proc/get_best_tool_archetype() + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + if(tool) + for(var/tool_archetype in tool.tool_values) + if(!. || tool.get_tool_quality(tool_archetype) > tool.get_tool_quality(.)) + . = tool_archetype + +/obj/item/proc/get_tool_speed(var/archetype) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.get_tool_speed(archetype) + if(!.) + var/decl/tool_archetype/tool_arch = GET_DECL(archetype) + . = tool_arch.get_default_speed(src) + +/**Returns the property's value for a givent archetype. */ +/obj/item/proc/get_tool_property(var/archetype, var/property) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.get_tool_property(archetype, property) + +/obj/item/proc/get_expected_tool_use_delay(archetype, delay, mob/user, check_skill = SKILL_CONSTRUCTION) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.get_expected_tool_use_delay(archetype, delay, user, check_skill) + +/obj/item/proc/get_tool_sound(var/archetype) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.get_tool_sound(archetype) + +/obj/item/proc/get_tool_message(var/archetype) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.get_tool_message(archetype) + +/**Set the property for the given tool archetype to the specified value. */ +/obj/item/proc/set_tool_property(var/archetype, var/property, var/value) + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + . = tool?.set_tool_property(archetype, property, value) + +/obj/item/proc/do_tool_interaction(var/archetype, var/mob/user, var/atom/target, var/delay = (1 SECOND), var/start_message, var/success_message, var/failure_message, var/fuel_expenditure = 0, var/check_skill = SKILL_CONSTRUCTION, var/prefix_message, var/suffix_message, var/check_skill_threshold, var/check_skill_prob = 50, var/set_cooldown = FALSE) + + if(get_tool_quality(archetype) <= 0) + return FALSE + + if(!user_can_attack_with(user)) + return FALSE + + . = handle_tool_interaction(archetype, user, src, target, delay, start_message, success_message, failure_message, fuel_expenditure, check_skill, prefix_message, suffix_message, check_skill_threshold, check_skill_prob, set_cooldown) + + if(QDELETED(user) || QDELETED(target)) + return FALSE + + if(. == TOOL_USE_SUCCESS) + if(success_message) + user.visible_message( + SPAN_NOTICE("\The [user] finishes [success_message] \the [target] with \the [src]."), + SPAN_NOTICE("You finish [success_message] \the [target] with \the [src].") + ) + return TRUE + + if(. == TOOL_USE_FAILURE_NOMESSAGE && failure_message) + to_chat(user, SPAN_WARNING(failure_message)) + return FALSE + +/obj/item/get_examine_strings(mob/user, distance, infix, suffix) + + . = ..() + + if(!user || user.get_preference_value(/datum/client_preference/inquisitive_examine) == PREF_OFF) + return + + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + if(!istype(tool)) + return + + var/list/tool_strings + for(var/tool_type in tool?.tool_values) + var/tool_quality = get_tool_quality(tool_type) + if(tool_quality < TOOL_QUALITY_WORST) + continue + var/decl/tool_archetype/tool_archetype = GET_DECL(tool_type) + var/tool_string = tool_archetype.get_tool_quality_descriptor(tool_quality) + if(tool_archetype.codex_key) + tool_string = "[tool_string]" + LAZYADD(tool_strings, tool_string) + + if(length(tool_strings)) + var/decl/pronouns/tool_pronouns = get_pronouns() + . += "[tool_pronouns.He] [verb_agree_with_pronouns("look", tool_pronouns)] like [english_list(tool_strings)]." diff --git a/code/modules/tools/components/_component.dm b/code/modules/tools/components/_component.dm new file mode 100644 index 000000000000..7cf0982327c8 --- /dev/null +++ b/code/modules/tools/components/_component.dm @@ -0,0 +1,9 @@ +/obj/item/tool_component + name = "tool component" + abstract_type = /obj/item/tool_component + material = /decl/material/solid/metal/steel + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + w_class = ITEM_SIZE_SMALL + +/obj/item/tool_component/get_mould_difficulty() + return SKILL_NONE diff --git a/code/modules/tools/components/handle.dm b/code/modules/tools/components/handle.dm new file mode 100644 index 000000000000..507b7a729581 --- /dev/null +++ b/code/modules/tools/components/handle.dm @@ -0,0 +1,17 @@ +/obj/item/tool_component/handle + name = "tool handle" + icon = 'icons/obj/items/tool/components/tool_handle.dmi' + material = /decl/material/solid/organic/wood/oak + abstract_type = /obj/item/tool_component/handle + +/obj/item/tool_component/handle/short + name = "short tool handle" + desc = "A short, straight rod suitable for use as the handle of a tool." + icon_state = "handle_short" + +/obj/item/tool_component/handle/long + name = "long tool handle" + desc = "A long, hefty rod suitable for use as the handle of a heavy tool." + icon_state = "handle_long" + _base_attack_force = 8 // bonk + w_class = ITEM_SIZE_NORMAL diff --git a/code/modules/tools/components/head.dm b/code/modules/tools/components/head.dm new file mode 100644 index 000000000000..e8e408c7c761 --- /dev/null +++ b/code/modules/tools/components/head.dm @@ -0,0 +1,70 @@ +var/global/list/_tool_quality_cache = list() +var/global/list/_tool_properties_cache = list() + +/obj/item/tool_component/head + name = "tool head" + icon = 'icons/obj/items/tool/components/tool_head.dmi' + abstract_type = /obj/item/tool_component/head + + var/tool_type + var/list/tool_qualities + var/list/tool_properties + +/obj/item/tool_component/head/Initialize(ml, material_key) + if(tool_type) + tool_qualities = tool_qualities || global._tool_quality_cache[tool_type] + tool_properties = tool_properties || global._tool_properties_cache[tool_type] + if(!tool_qualities || !tool_properties) + var/obj/item/tool/thing = new tool_type + if(!tool_qualities) + tool_qualities = thing.get_initial_tool_qualities() + global._tool_quality_cache[tool_type] = tool_qualities + if(!tool_properties) + tool_properties = thing.get_initial_tool_properties() + global._tool_properties_cache[tool_type] = tool_properties + // qdel(thing) //do we need to do this? are we allowed to do it during Initialize()? + return ..() + +/obj/item/tool_component/head/hammer + name = "hammer head" + desc = "The head of a hammer." + icon_state = "hammer" + +/obj/item/tool_component/head/shovel + name = "shovel head" + desc = "The head of a shovel." + icon_state = "shovel" + +/obj/item/tool_component/head/hoe + name = "hoe head" + desc = "The head of a hoe." + icon_state = "hoe" + +/obj/item/tool_component/head/chisel + name = "chisel head" + desc = "The head of a chisel." + icon_state = "hoe" + +/obj/item/tool_component/head/handaxe + name = "hand axe head" + desc = "The head of a hand axe." + icon_state = "handaxe" + tool_type = /obj/item/tool/axe + +/obj/item/tool_component/head/pickaxe + name = "pickaxe head" + desc = "The head of a pickaxe." + icon_state = "pickaxe" + w_class = ITEM_SIZE_NORMAL + +/obj/item/tool_component/head/sledgehammer + name = "sledgehammer head" + desc = "The head of a sledgehammer." + icon_state = "sledgehammer" + w_class = ITEM_SIZE_NORMAL + +/obj/item/tool_component/head/forging_hammer + name = "forging hammer head" + desc = "The head of a forging hammer." + icon_state = "forging" + w_class = ITEM_SIZE_NORMAL diff --git a/code/modules/tools/components/recipes.dm b/code/modules/tools/components/recipes.dm new file mode 100644 index 000000000000..38b76cff8959 --- /dev/null +++ b/code/modules/tools/components/recipes.dm @@ -0,0 +1,58 @@ +/decl/stack_recipe/tool + category = "tool parts" + abstract_type = /decl/stack_recipe/tool + forbidden_craft_stack_types = null + craft_stack_types = list( + /obj/item/stack/material/ore, + /obj/item/stack/material/lump, + /obj/item/stack/material/plank + ) + validation_material = /decl/material/solid/stone/basalt + +/decl/stack_recipe/tool/handle + abstract_type = /decl/stack_recipe/tool/handle + difficulty = MAT_VALUE_NORMAL_DIY + craft_stack_types = list( + /obj/item/stack/material/plank, + /obj/item/stack/material/rods, + /obj/item/stack/material/bone + ) + validation_material = /decl/material/solid/organic/bone + +/decl/stack_recipe/tool/handle/long + result_type = /obj/item/tool_component/handle/long + +/decl/stack_recipe/tool/handle/short + result_type = /obj/item/tool_component/handle/short + +/decl/stack_recipe/tool/head + abstract_type = /decl/stack_recipe/tool/head + difficulty = MAT_VALUE_HARD_DIY + +/decl/stack_recipe/tool/head/hammer + result_type = /obj/item/tool_component/head/hammer + +/decl/stack_recipe/tool/head/hoe + result_type = /obj/item/tool_component/head/hoe + +/decl/stack_recipe/tool/head/shovel + result_type = /obj/item/tool_component/head/shovel + +/decl/stack_recipe/tool/head/handaxe + result_type = /obj/item/tool_component/head/handaxe + +/decl/stack_recipe/tool/head/sledgehammer + difficulty = MAT_VALUE_VERY_HARD_DIY + result_type = /obj/item/tool_component/head/sledgehammer + craft_stack_types = list( + /obj/item/stack/material/ore, + /obj/item/stack/material/lump + ) + +/decl/stack_recipe/tool/head/pickaxe + difficulty = MAT_VALUE_VERY_HARD_DIY + result_type = /obj/item/tool_component/head/pickaxe + craft_stack_types = list( + /obj/item/stack/material/ore, + /obj/item/stack/material/lump + ) diff --git a/code/modules/tools/subtypes/axes.dm b/code/modules/tools/subtypes/axes.dm new file mode 100644 index 000000000000..d671ffa07479 --- /dev/null +++ b/code/modules/tools/subtypes/axes.dm @@ -0,0 +1,44 @@ +/obj/item/tool/axe + name = "hand axe" + desc = "A handheld tool for chopping things, wood, food, or people." + icon_state = "preview" + icon = 'icons/obj/items/tool/axes/handaxe.dmi' + sharp = TRUE + edge = TRUE + handle_material = /decl/material/solid/organic/wood/oak + item_flags = ITEM_FLAG_IS_WEAPON + origin_tech = @'{"materials":2,"combat":1}' + attack_verb = list("chopped", "torn", "cut") + hitsound = "chop" + _base_attack_force = 15 + +/obj/item/tool/axe/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_HATCHET = TOOL_QUALITY_DEFAULT + ) + return tool_qualities + +/obj/item/tool/axe/ebony + material = /decl/material/solid/metal/iron + handle_material = /decl/material/solid/organic/wood/ebony + +/obj/item/tool/axe/iron + material = /decl/material/solid/metal/iron + +/obj/item/tool/axe/ebony/bronze + material = /decl/material/solid/metal/bronze + +// Legacy SS13 hatchet. +/obj/item/tool/axe/hatchet + name = "hatchet" + desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood." + icon = 'icons/obj/items/tool/axes/hatchet.dmi' + w_class = ITEM_SIZE_SMALL + material_alteration = MAT_FLAG_ALTERATION_NAME + handle_material = /decl/material/solid/organic/plastic + +/obj/item/tool/axe/hatchet/get_handle_color() + return null + +/obj/item/tool/axe/hatchet/unbreakable + max_health = ITEM_HEALTH_NO_DAMAGE diff --git a/code/modules/tools/subtypes/drills.dm b/code/modules/tools/subtypes/drills.dm new file mode 100644 index 000000000000..d57df30cbb13 --- /dev/null +++ b/code/modules/tools/subtypes/drills.dm @@ -0,0 +1,64 @@ +/obj/item/tool/drill + name = "mining drill" + desc = "The most basic of mining drills, for short excavations and small mineral extractions." + icon = 'icons/obj/items/tool/drills/drill.dmi' + material_alteration = 0 + w_class = ITEM_SIZE_HUGE + +/obj/item/tool/drill/Initialize(ml, material_key, _handle_material, _binding_material, override_tool_qualities, override_tool_properties) + . = ..() + set_extension(src, /datum/extension/demolisher/pick) + +/obj/item/tool/drill/get_handle_color() + return null + +/obj/item/tool/drill/get_initial_tool_properties() + var/static/list/tool_properties = list( + TOOL_PICK = list( + TOOL_PROP_EXCAVATION_DEPTH = 200, + TOOL_PROP_VERB = "drilling" + ) + ) + return tool_properties + +// TODO: cell extension? +/obj/item/tool/drill/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_DECENT, + TOOL_SURGICAL_DRILL = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/drill/advanced + name = "advanced mining drill" // Can dig sand as well! + desc = "Yours is the drill that will pierce through the rock walls." + icon = 'icons/obj/items/tool/drills/drill_advanced.dmi' + origin_tech = @'{"materials":2,"powerstorage":3,"engineering":2}' + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/tool/drill/advanced/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_GOOD, + TOOL_SURGICAL_DRILL = TOOL_QUALITY_MEDIOCRE, + TOOL_SHOVEL = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/drill/diamond //When people ask about the badass leader of the mining tools, they are talking about ME! + name = "diamond mining drill" + desc = "Yours is the drill that will pierce the heavens!" + icon = 'icons/obj/items/tool/drills/drill_diamond.dmi' + origin_tech = @'{"materials":6,"powerstorage":4,"engineering":5}' + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE + ) + +/obj/item/tool/drill/diamond/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_BEST, + TOOL_SURGICAL_DRILL = TOOL_QUALITY_MEDIOCRE, + TOOL_SHOVEL = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities \ No newline at end of file diff --git a/code/modules/tools/subtypes/hammers.dm b/code/modules/tools/subtypes/hammers.dm new file mode 100644 index 000000000000..cd6871ce2546 --- /dev/null +++ b/code/modules/tools/subtypes/hammers.dm @@ -0,0 +1,99 @@ +/obj/item/tool/hammer + name = "hammer" + desc = "A simple hammer. Ancient technology once thought lost." + icon = 'icons/obj/items/tool/hammers/hammer.dmi' + attack_verb = list( + "bludgeons", + "slaps", + "beats", + "strikes", + "bashes", + "hammers" + ) + var/demolisher_type = /datum/extension/demolisher/delicate + +/obj/item/tool/hammer/Initialize(ml, material_key, _handle_material, _binding_material, override_tool_qualities, override_tool_properties) + . = ..() + if(demolisher_type) + set_extension(src, demolisher_type, null, "demolishing", 'sound/effects/bang.ogg') + +/obj/item/tool/hammer/get_initial_tool_properties() + var/static/list/tool_properties = list( + TOOL_PICK = list( + TOOL_PROP_EXCAVATION_DEPTH = 200, + TOOL_PROP_VERB = "hammering" + ) + ) + return tool_properties + +/obj/item/tool/hammer/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_HAMMER = TOOL_QUALITY_DEFAULT, + TOOL_CROWBAR = TOOL_QUALITY_WORST + ) + return tool_qualities + +/obj/item/tool/hammer/sledge + name = "sledgehammer" + desc = "A heavy two-handed construction hammer. Great for smashing your boss right in the face." + icon = 'icons/obj/items/tool/hammers/sledgehammer.dmi' + can_be_twohanded = TRUE + _base_attack_force = 17 + attack_verb = list( + "brutalizes", + "bludgeons", + "beats", + "crushes", + "strikes", + "bashes", + "hammers" + ) + demolisher_type = /datum/extension/demolisher + w_class = ITEM_SIZE_HUGE + +/obj/item/tool/hammer/sledge/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_HAMMER = TOOL_QUALITY_DEFAULT, + TOOL_PICK = TOOL_QUALITY_MEDIOCRE, + TOOL_SHOVEL = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/hammer/jack + name = "sonic jackhammer" + desc = "A hefty tool that cracks rocks with sonic blasts, perfect for killing cave lizards." + icon = 'icons/obj/items/tool/hammers/jackhammer.dmi' + origin_tech = @'{"materials":3,"powerstorage":2,"engineering":2}' + material_alteration = 0 + can_be_twohanded = TRUE + _base_attack_force = 15 + w_class = ITEM_SIZE_HUGE + +/obj/item/tool/hammer/jack/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_HAMMER = TOOL_QUALITY_DEFAULT, + TOOL_PICK = TOOL_QUALITY_DEFAULT, + TOOL_SURGICAL_DRILL = TOOL_QUALITY_MEDIOCRE, + TOOL_SHOVEL = TOOL_QUALITY_DECENT + ) + return tool_qualities + +/obj/item/tool/hammer/forge + name = "forging hammer" + desc = "A heavy hammer, used to forge hot metal at an anvil." + icon = 'icons/obj/items/tool/hammers/forge.dmi' + w_class = ITEM_SIZE_NORMAL + +/obj/item/tool/hammer/forge/iron + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + handle_material = /decl/material/solid/organic/wood/mahogany + +// Forging hammers are not great at general hammer tasks (too heavy I guess), +// and also don't work as crowbars due to missing the nail ripper/flange, +// but will be more effective at forging when blacksmithy is merged. +/obj/item/tool/hammer/forge/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_HAMMER = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities diff --git a/code/modules/tools/subtypes/hoes.dm b/code/modules/tools/subtypes/hoes.dm new file mode 100644 index 000000000000..b5bdda347638 --- /dev/null +++ b/code/modules/tools/subtypes/hoes.dm @@ -0,0 +1,36 @@ +/obj/item/tool/hoe + name = "hoe" + desc = "It's used for removing weeds or scratching your back." + icon = 'icons/obj/items/tool/hoes/hoe.dmi' + icon_state = "preview" + sharp = TRUE + edge = TRUE + attack_verb = list("slashed", "sliced", "cut", "clawed") + material = /decl/material/solid/metal/steel + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + w_class = ITEM_SIZE_LARGE + +/obj/item/tool/hoe/wood + color = /decl/material/solid/organic/wood/oak::color + material = /decl/material/solid/organic/wood/oak + +/obj/item/tool/hoe/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + material = /decl/material/solid/organic/wood/walnut + +/obj/item/tool/hoe/get_initial_tool_qualities() + var/static/list/tool_qualities = list(TOOL_HOE = TOOL_QUALITY_DEFAULT) + return tool_qualities + +/obj/item/tool/hoe/mini + name = "mini hoe" + icon = 'icons/obj/items/tool/hoes/minihoe.dmi' + material_alteration = 0 + handle_material = /decl/material/solid/organic/plastic + w_class = ITEM_SIZE_SMALL + +/obj/item/tool/hoe/mini/get_handle_color() + return null + +/obj/item/tool/hoe/mini/unbreakable + max_health = ITEM_HEALTH_NO_DAMAGE diff --git a/code/modules/tools/subtypes/machetes.dm b/code/modules/tools/subtypes/machetes.dm new file mode 100644 index 000000000000..566d4148ee9e --- /dev/null +++ b/code/modules/tools/subtypes/machetes.dm @@ -0,0 +1,47 @@ +/obj/item/tool/machete + name = "machete" + desc = "A long, sturdy blade with a rugged handle. Leading the way to cursed treasures since before space travel." + icon = 'icons/obj/items/weapon/machetes/machete.dmi' + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/metal/titanium + base_parry_chance = 50 + origin_tech = @'{"materials":2,"combat":1}' + attack_verb = list("chopped", "torn", "cut") + _base_attack_force = 20 + var/static/list/standard_machete_icons = list( + 'icons/obj/items/weapon/machetes/machete.dmi', + 'icons/obj/items/weapon/machetes/machete_red.dmi', + 'icons/obj/items/weapon/machetes/machete_blue.dmi', + 'icons/obj/items/weapon/machetes/machete_black.dmi', + 'icons/obj/items/weapon/machetes/machete_olive.dmi' + ) + +/obj/item/tool/machete/Initialize() + icon = pick(standard_machete_icons) + . = ..() + +/obj/item/tool/machete/get_handle_color() + return null + +/obj/item/tool/machete/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_HATCHET = TOOL_QUALITY_MEDIOCRE, + TOOL_HAMMER = TOOL_QUALITY_BAD, + TOOL_SHEARS = TOOL_QUALITY_WORST + ) + return tool_qualities + +/obj/item/tool/machete/unbreakable + max_health = ITEM_HEALTH_NO_DAMAGE + +/obj/item/tool/machete/steel + name = "fabricated machete" + desc = "A long, machine-stamped blade with a somewhat ungainly handle. Found in military surplus stores, malls, and horror movies since before interstellar travel." + base_parry_chance = 40 + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/tool/machete/deluxe + name = "deluxe machete" + desc = "A fine example of a machete, with a polished blade, wooden handle and a leather cord loop." + icon = 'icons/obj/items/weapon/machetes/machete_dx.dmi' diff --git a/code/modules/tools/subtypes/pickaxes.dm b/code/modules/tools/subtypes/pickaxes.dm new file mode 100644 index 000000000000..083c99661f8c --- /dev/null +++ b/code/modules/tools/subtypes/pickaxes.dm @@ -0,0 +1,81 @@ +/obj/item/tool/pickaxe + name = "pickaxe" + desc = "A heavy tool with a pick head for prospecting for minerals, and an axe head for dealing with anyone with a prior claim." + icon_state = "preview" + icon = 'icons/obj/items/tool/pickaxe.dmi' + sharp = TRUE + edge = TRUE + w_class = ITEM_SIZE_HUGE + handle_material = /decl/material/solid/organic/wood/oak + _base_attack_force = 15 + +/obj/item/tool/pickaxe/Initialize(ml, material_key, _handle_material, _binding_material, override_tool_qualities, override_tool_properties) + . = ..() + set_extension(src, /datum/extension/demolisher/pick) + +/obj/item/tool/pickaxe/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_DEFAULT, + TOOL_SHOVEL = TOOL_QUALITY_MEDIOCRE, + TOOL_HAMMER = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/pickaxe/get_initial_tool_properties() + var/static/list/tool_properties = list( + TOOL_PICK = list( + TOOL_PROP_EXCAVATION_DEPTH = 200 + ) + ) + return tool_properties + +// Using these mainly for debugging. +/obj/item/tool/pickaxe/wood + material = /decl/material/solid/organic/wood/oak + +/obj/item/tool/pickaxe/stone + material = /decl/material/solid/stone/flint + +/obj/item/tool/pickaxe/titanium + origin_tech = @'{"materials":3}' + material = /decl/material/solid/metal/titanium + +/obj/item/tool/pickaxe/titanium/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_DECENT, + TOOL_SHOVEL = TOOL_QUALITY_DEFAULT, + TOOL_HAMMER = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/pickaxe/plasteel + origin_tech = @'{"materials":4}' + material = /decl/material/solid/metal/plasteel + +/obj/item/tool/pickaxe/plasteel/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_GOOD, + TOOL_SHOVEL = TOOL_QUALITY_DECENT, + TOOL_HAMMER = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/pickaxe/ocp + origin_tech = @'{"materials":6,"engineering":4}' + material = /decl/material/solid/metal/plasteel/ocp + +/obj/item/tool/pickaxe/ocp/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_PICK = TOOL_QUALITY_BEST, + TOOL_SHOVEL = TOOL_QUALITY_GOOD, + TOOL_HAMMER = TOOL_QUALITY_MEDIOCRE + ) + return tool_qualities + +/obj/item/tool/pickaxe/iron + material = /decl/material/solid/metal/iron + handle_material = /decl/material/solid/organic/wood/ebony + +/obj/item/tool/pickaxe/bronze + material = /decl/material/solid/metal/bronze + handle_material = /decl/material/solid/organic/wood/ebony diff --git a/code/modules/tools/subtypes/power_tools.dm b/code/modules/tools/subtypes/power_tools.dm new file mode 100644 index 000000000000..84099987a3e4 --- /dev/null +++ b/code/modules/tools/subtypes/power_tools.dm @@ -0,0 +1,65 @@ +/obj/item/tool/hydraulic_cutter + name = "hydraulic cutter" + desc = "A universal, miniaturized hydraulic tool with interchangeable heads for either prying or cutting. But not both at the same time." + icon = 'icons/obj/items/tool/cutter.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":3,"engineering":3}' + material = /decl/material/solid/metal/steel + center_of_mass = @'{"x":17,"y":16}' + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + drop_sound = 'sound/foley/bardrop1.ogg' + +/obj/item/tool/hydraulic_cutter/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(IS_CROWBAR(src)) + add_overlay("[icon_state]-pry") + else if(IS_WIRECUTTER(src)) + add_overlay("[icon_state]-cut") + +/obj/item/tool/hydraulic_cutter/Initialize() + . = ..() + var/datum/extension/tool/variable/tool = get_extension(src, /datum/extension/tool) + tool?.set_sound_overrides('sound/items/jaws_pry.ogg', 'sound/items/change_jaws.ogg') + +/obj/item/tool/hydraulic_cutter/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_CROWBAR = TOOL_QUALITY_GOOD, + TOOL_WIRECUTTERS = TOOL_QUALITY_GOOD + ) + return tool_qualities + +/obj/item/tool/power_drill + name = "power drill" + desc = "A universal power drill, with heads for most common screw and bolt types." + icon = 'icons/obj/items/tool/powerdrill.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_SMALL + origin_tech = @'{"materials":3,"engineering":3}' + material = /decl/material/solid/metal/steel + center_of_mass = @'{"x":17,"y":16}' + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + drop_sound = 'sound/foley/bardrop1.ogg' + +/obj/item/tool/power_drill/Initialize() + . = ..() + var/datum/extension/tool/tool = get_extension(src, /datum/extension/tool) + tool?.set_sound_overrides('sound/items/airwrench.ogg', 'sound/items/change_drill.ogg') + +/obj/item/tool/power_drill/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_WRENCH = TOOL_QUALITY_GOOD, + TOOL_SCREWDRIVER = TOOL_QUALITY_GOOD + ) + return tool_qualities + +/obj/item/tool/power_drill/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(IS_SCREWDRIVER(src)) + add_overlay("[icon_state]-screw") + else if(IS_WRENCH(src)) + add_overlay("[icon_state]-bolt") diff --git a/code/modules/tools/subtypes/shovel.dm b/code/modules/tools/subtypes/shovel.dm new file mode 100644 index 000000000000..204bb0a9fbb4 --- /dev/null +++ b/code/modules/tools/subtypes/shovel.dm @@ -0,0 +1,56 @@ +/obj/item/tool/shovel + name = "shovel" + desc = "A large tool for digging and moving dirt." + icon = 'icons/obj/items/tool/shovels/shovel.dmi' + icon_state = "preview" // mapping preview icon + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_LARGE + edge = TRUE + sharp = TRUE + attack_verb = list("bashed", "bludgeoned", "thrashed", "whacked") + handle_material = /decl/material/solid/organic/wood/oak + _base_attack_force = 8 + +/obj/item/tool/shovel/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_SHOVEL = TOOL_QUALITY_DEFAULT, + TOOL_HOE = TOOL_QUALITY_BAD + ) + return tool_qualities + +/obj/item/tool/shovel/wood + color = /decl/material/solid/organic/wood/oak::color + material = /decl/material/solid/organic/wood/oak + +/obj/item/tool/shovel/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + handle_material = /decl/material/solid/organic/wood/walnut + material = /decl/material/solid/organic/wood/walnut + +/obj/item/tool/shovel/one_material/Initialize(ml, material_key, _handle_material, _binding_material, override_tool_qualities, override_tool_properties) + return ..(ml, material_key, material_key, _binding_material, override_tool_qualities, override_tool_properties) + +/obj/item/tool/spade + name = "spade" + desc = "A small tool for digging and moving dirt." + icon = 'icons/obj/items/tool/shovels/spade.dmi' + icon_state = "preview" // mapping preview icon + w_class = ITEM_SIZE_SMALL + edge = FALSE + sharp = FALSE + slot_flags = SLOT_LOWER_BODY + attack_verb = list("bashed", "bludgeoned", "thrashed", "whacked") + material_alteration = 0 + handle_material = /decl/material/solid/organic/plastic + _base_attack_force = 5 + +/obj/item/tool/spade/get_handle_color() + return null + +/obj/item/tool/spade/get_initial_tool_qualities() + var/static/list/tool_qualities = list( + TOOL_SHOVEL = TOOL_QUALITY_BAD, + TOOL_HOE = TOOL_QUALITY_MEDIOCRE + + ) + return tool_qualities diff --git a/code/modules/tools/subtypes/xenoarchaeology_picks.dm b/code/modules/tools/subtypes/xenoarchaeology_picks.dm new file mode 100644 index 000000000000..0dc4160e3a39 --- /dev/null +++ b/code/modules/tools/subtypes/xenoarchaeology_picks.dm @@ -0,0 +1,146 @@ +/obj/item/tool/xeno + name = "master xenoarch pickaxe" + desc = "A miniature excavation tool for precise digging." + icon = 'icons/obj/xenoarchaeology.dmi' + item_state = "screwdriver_brown" + attack_verb = list("stabbed", "jabbed", "spiked", "attacked") + material = /decl/material/solid/metal/chromium + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY) + w_class = ITEM_SIZE_SMALL + sharp = TRUE + abstract_type = /obj/item/tool/xeno + material_alteration = 0 + handle_material = /decl/material/solid/organic/plastic + _base_attack_force = 3 + + var/excavation_verb = "delicately picking" + var/excavation_sound = 'sound/weapons/thudswoosh.ogg' + var/excavation_amount = 0 + +/obj/item/tool/xeno/get_initial_tool_properties() + return list( + TOOL_PICK = list( + TOOL_PROP_VERB = excavation_verb, + TOOL_PROP_SOUND = excavation_sound, + TOOL_PROP_EXCAVATION_DEPTH = excavation_amount + ) + ) + +/obj/item/tool/xeno/get_initial_tool_qualities() + var/static/list/tool_qualities = list(TOOL_PICK = TOOL_QUALITY_DEFAULT) + return tool_qualities + +/obj/item/tool/xeno/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(IS_PICK(src)) + . += "This tool has a [get_tool_property(TOOL_PICK, TOOL_PROP_EXCAVATION_DEPTH) || 0] centimetre excavation depth." + +/obj/item/tool/xeno/brush + name = "wire brush" + icon_state = "pick_brush" + slot_flags = SLOT_EARS + _base_attack_force = 1 + attack_verb = list("prodded", "attacked") + desc = "A wood-handled brush with thick metallic wires for clearing away dust and loose scree." + sharp = FALSE + material = /decl/material/solid/metal/steel + handle_material = /decl/material/solid/organic/wood/oak + excavation_amount = 1 + excavation_sound = "sweeping" + excavation_verb = "brushing" + +/obj/item/tool/xeno/one_pick + name = "2cm pick" + icon_state = "pick1" + excavation_amount = 2 + excavation_sound = 'sound/items/Screwdriver.ogg' + +/obj/item/tool/xeno/two_pick + name = "4cm pick" + icon_state = "pick2" + excavation_amount = 4 + excavation_sound = 'sound/items/Screwdriver.ogg' + +/obj/item/tool/xeno/three_pick + name = "6cm pick" + icon_state = "pick3" + excavation_amount = 6 + excavation_sound = 'sound/items/Screwdriver.ogg' + +/obj/item/tool/xeno/four_pick + name = "8cm pick" + icon_state = "pick4" + excavation_amount = 8 + excavation_sound = 'sound/items/Screwdriver.ogg' + +/obj/item/tool/xeno/five_pick + name = "10cm pick" + icon_state = "pick5" + excavation_amount = 10 + excavation_sound = 'sound/items/Screwdriver.ogg' + +/obj/item/tool/xeno/six_pick + name = "12cm pick" + icon_state = "pick6" + excavation_amount = 12 + +/obj/item/tool/xeno/hand + name = "hand pickaxe" + icon_state = "pick_hand" + item_state = "sword0" + desc = "A smaller, more precise version of the pickaxe." + excavation_amount = 30 + excavation_sound = 'sound/items/Crowbar.ogg' + excavation_verb = "clearing" + material = /decl/material/solid/metal/chromium + matter = list(/decl/material/solid/metal/steel = MATTER_AMOUNT_SECONDARY) + w_class = ITEM_SIZE_NORMAL + _base_attack_force = 6 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Pack for holding pickaxes + +/obj/item/excavation + name = "excavation pick set" + icon = 'icons/obj/items/storage/excavation.dmi' + icon_state = "excavation" + desc = "A rugged case containing a set of standardized picks used in archaeological digs." + item_state = "syringe_kit" + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_NORMAL + material = /decl/material/solid/organic/leather/synth + storage = /datum/storage/excavation + +/obj/item/excavation/WillContain() + return list( + /obj/item/tool/xeno/brush, + /obj/item/tool/xeno/one_pick, + /obj/item/tool/xeno/two_pick, + /obj/item/tool/xeno/three_pick, + /obj/item/tool/xeno/four_pick, + /obj/item/tool/xeno/five_pick, + /obj/item/tool/xeno/six_pick + ) + +/obj/item/excavation/empty/WillContain() + return + +/obj/item/excavation/proc/sort_picks() + var/list/obj/item/tool/xeno/picksToSort = list() + for(var/obj/item/tool/xeno/P in src) + picksToSort += P + P.forceMove(null) + while(picksToSort.len) + var/min = 200 // No pick is bigger than 200 + var/selected = 0 + for(var/i = 1 to picksToSort.len) + var/obj/item/tool/xeno/current = picksToSort[i] + var/excav_amount = current.get_tool_property(TOOL_PICK, TOOL_PROP_EXCAVATION_DEPTH) + if(excav_amount <= min) + selected = i + min = excav_amount + var/obj/item/tool/xeno/smallest = picksToSort[selected] + smallest.forceMove(src) + picksToSort -= smallest + if(storage) + storage.prepare_ui() diff --git a/code/modules/tools/tool.dm b/code/modules/tools/tool.dm new file mode 100644 index 000000000000..af7ac841f205 --- /dev/null +++ b/code/modules/tools/tool.dm @@ -0,0 +1,128 @@ +/obj/item/tool + name = "tool" + icon_state = ICON_STATE_WORLD + obj_flags = OBJ_FLAG_CONDUCTIBLE + slot_flags = SLOT_LOWER_BODY + w_class = ITEM_SIZE_NORMAL + origin_tech = @'{"materials":1,"engineering":1}' + attack_verb = list("hit", "pierced", "sliced", "attacked") + abstract_type = /obj/item/tool + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + _base_attack_force = 10 + + /// Material is used for the head, handle is handle(d) below. + material = /decl/material/solid/metal/steel + /// Material used for our handle. Set to base material if null. + var/decl/material/handle_material + /// Material used for binding. + var/decl/material/binding_material = /decl/material/solid/organic/meat/gut + +/obj/item/tool/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/list/descriptor_strings = list() + if(material == handle_material) + descriptor_strings += "the head and handle are made of [material.use_name]" + else + descriptor_strings += "the head is made of [material.use_name]" + descriptor_strings += "the handle is made of [handle_material.use_name]" + if(binding_material) + descriptor_strings += "the binding is made of [binding_material.use_name]" + . += "[capitalize(english_list(descriptor_strings))]." + +/obj/item/tool/Initialize(ml, material_key, _handle_material, _binding_material, override_tool_qualities, override_tool_properties) + + // Find out handle material if supplied, default to base material otherwise. + if(ispath(_handle_material, /decl/material)) + handle_material = GET_DECL(_handle_material) + else if(istype(_handle_material, /decl/material)) + handle_material = _handle_material + else if(ispath(handle_material)) + handle_material = GET_DECL(handle_material) + else if(!istype(handle_material, /decl/material)) + if(istype(material, /decl/material)) + handle_material = material + else if(ispath(material, /decl/material)) + handle_material = GET_DECL(material) + else + handle_material = null + + // Grab our binding material. + if(ispath(_binding_material)) + binding_material = GET_DECL(_binding_material) + else if(istype(_binding_material, /decl/material)) + binding_material = _binding_material + else if(ispath(binding_material)) + binding_material = GET_DECL(binding_material) + + // Update qualities. + var/list/tool_qualities = override_tool_qualities || get_initial_tool_qualities() + if(length(tool_qualities)) + var/datum/extension/tool/tool_data + if(length(tool_qualities) == 1) + tool_data = get_or_create_extension(src, /datum/extension/tool, tool_qualities) + else + tool_data = get_or_create_extension(src, /datum/extension/tool/variable/simple, tool_qualities) + + // Update properties. + if(tool_data && IS_PICK(src)) + var/list/tool_properties = override_tool_properties || get_initial_tool_properties() + for(var/tool_archetype in tool_properties) + var/list/archetype_properties = tool_properties[tool_archetype] + for(var/tool_property in archetype_properties) + tool_data.set_tool_property(tool_archetype, tool_property, archetype_properties[tool_property]) + + . = ..() + + if(!handle_material) + handle_material = material + update_icon() + +/obj/item/tool/create_matter() + if(handle_material) + if(material == handle_material) + LAZYSET(matter, material.type, (MATTER_AMOUNT_PRIMARY + MATTER_AMOUNT_REINFORCEMENT)) + else + LAZYSET(matter, handle_material.type, MATTER_AMOUNT_REINFORCEMENT) + return ..() + +/obj/item/tool/proc/get_initial_tool_properties() + return list() + +/obj/item/tool/proc/get_initial_tool_qualities() + return list() + +/obj/item/tool/proc/get_handle_color() + if(material_alteration & MAT_FLAG_ALTERATION_COLOR) + return handle_material?.color || material?.color || COLOR_WHITE + return initial(color) + +/obj/item/tool/on_update_icon() + . = ..() + var/handle_color = get_handle_color() + if(!isnull(handle_color)) // return COLOR_WHITE instead of null as a way of opting into this behavior + var/handle_state = "[icon_state]-handle" + if(check_state_in_icon(handle_state, icon)) + var/image/I = overlay_image(icon, handle_state, handle_color, RESET_COLOR) + if(handle_material) + I.alpha = 100 + handle_material.opacity * 255 + I.appearance_flags |= RESET_ALPHA + add_overlay(I) + if(binding_material) + var/binding_state = "[icon_state]-binding" + if(check_state_in_icon(binding_state, icon)) + add_overlay(overlay_image(icon, binding_state, binding_material.color, (RESET_COLOR|RESET_ALPHA))) + +/obj/item/tool/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + var/handle_color = get_handle_color() + if(!isnull(handle_color)) + var/handle_state = "[overlay.icon_state]-handle" + if(check_state_in_icon(handle_state, overlay.icon)) + var/image/handle = image(overlay.icon, handle_state) + handle.color = handle_color + if(handle_material) + handle.alpha = 100 + handle_material.opacity * 255 + handle.appearance_flags |= RESET_COLOR | RESET_ALPHA + handle.appearance_flags |= RESET_COLOR + overlay.overlays += handle + . = ..() diff --git a/code/modules/tools/tool_serde.dm b/code/modules/tools/tool_serde.dm new file mode 100644 index 000000000000..f94e251715b2 --- /dev/null +++ b/code/modules/tools/tool_serde.dm @@ -0,0 +1,9 @@ +/obj/item/tool/Serialize() + . = ..() + SERIALIZE_DECL_IF_MODIFIED(handle_material, /obj/item/tool) + SERIALIZE_DECL_IF_MODIFIED(binding_material, /obj/item/tool) + +/obj/item/tool/Deserialize(list/instance_map) + . = ..() + DESERIALIZE_DECL_TO_TYPE(handle_material) + DESERIALIZE_DECL_TO_TYPE(binding_material) diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 4b861173bdb2..edd50670dced 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -3,32 +3,34 @@ Tooltips v1.1 - 22/10/15 Developed by Wire (#goonstation on irc.synirc.net) - Added support for screen_loc pixel offsets. Should work. Maybe. - Added init function to more efficiently send base vars + Configuration: - Set control to the correct skin element (remember to actually place the skin element) - Set file to the correct path for the .html file (remember to actually place the html file) - Attach the datum to the user client on login, e.g. - /client/New() src.tooltips = new /datum/tooltip(src) Usage: - Define mouse event procs on your (probably HUD) object and simply call the show and hide procs respectively: - /obj/screen/hud MouseEntered(location, control, params) usr.client.tooltip.show(params, title = src.name, content = src.desc) + MouseExited() usr.client.tooltip.hide() Customization: - Theming can be done by passing the theme var to show() and using css in the html file to change the look - For your convenience some pre-made themes are included + Notes: - You may have noticed 90% of the work is done via javascript on the client. Gotta save those cycles man. - This is entirely untested in any other codebase besides goonstation so I have no idea if it will port nicely. Good luck! - After testing and discussion (Wire, Remie, MrPerson, AnturK) ToolTips are ok and work for /tg/station13 */ + /datum/tooltip var/client/owner var/control = "mainwindow.tooltip" @@ -36,28 +38,31 @@ Notes: var/queueHide = FALSE var/init = FALSE + /datum/tooltip/New(client/C) - if(C) + if (C) owner = C show_browser(owner, file2text('code/modules/tooltip/tooltip.html'), "window=[control]") + ..() + /datum/tooltip/proc/show(atom/movable/thing, params = null, title = null, content = null, theme = "default", special = "none") - if(!thing || !params || (!title && !content) || !owner || !isnum(world.icon_size)) + if (!thing || !params || (!title && !content) || !owner || !isnum(world.icon_size)) return FALSE - if(!init) + if (!init) //Initialize some vars init = TRUE send_output(owner, list2params(list(world.icon_size, control)), "[control]:tooltip.init") showing = TRUE - if(title && content) + if (title && content) title = "

    [title]

    " content = "

    [content]

    " - else if(title && !content) + else if (title && !content) title = "

    [title]

    " - else if(!title && content) + else if (!title && content) content = "

    [content]

    " // Strip macros from item names @@ -65,29 +70,28 @@ Notes: title = replacetext(title, "\improper", "") //Make our dumb param object - if(params[1] != "i") //Byond Bug: http://www.byond.com/forum/?post=2352648 - params = "icon-x=16;icon-y=16;[params]" //Put in some placeholders params = {"{ "cursor": "[params]", "screenLoc": "[thing.screen_loc]" }"} //Send stuff to the tooltip var/view_size = getviewsize(owner.view) send_output(owner, list2params(list(params, view_size[1] , view_size[2], "[title][content]", theme, special)), "[control]:tooltip.update") - //ifa hide() was hit while we were showing, run hide() again to avoid stuck tooltips + //If a hide() was hit while we were showing, run hide() again to avoid stuck tooltips showing = FALSE - if(queueHide) + if (queueHide) hide() return TRUE + /datum/tooltip/proc/hide() - if(queueHide) - addtimer(CALLBACK(src, .proc/do_hide), 1) + queueHide = !!showing + + if (queueHide) + addtimer(CALLBACK(src, PROC_REF(do_hide)), 1) else do_hide() - queueHide = showing ? TRUE : FALSE - return TRUE /datum/tooltip/proc/do_hide() @@ -95,21 +99,25 @@ Notes: /* TG SPECIFIC CODE */ + //Open a tooltip for user, at a location based on params //Theme is a CSS class in tooltip.html, by default this wrapper chooses a CSS class based on the user's UI_style (Midnight, Plasmafire, Retro, etc) //Includes sanity.checks -/proc/openToolTip(mob/user = null, atom/movable/tip_src = null, params = null, title = "", content = "", theme = "") +/proc/openToolTip(mob/user = null, atom/movable/tip_src = null, params = null,title = "",content = "",theme = "") if(istype(user)) if(user.client && user.client.tooltips) - if(!theme && user.client.prefs && user.client.prefs.tooltip_style) - theme = lowertext(user.client.prefs.tooltip_style) + var/ui_style = user?.client?.prefs?.tooltip_style + if(!theme && ui_style) + theme = lowertext(ui_style) if(!theme) - theme = "midnight" - user.client.tooltips.show(tip_src, params, title, content, theme) + theme = "default" + user.client.tooltips.show(tip_src, params,title,content,theme) + //Arbitrarily close a user's tooltip //Includes sanity checks. /proc/closeToolTip(mob/user) if(istype(user)) if(user.client && user.client.tooltips) - user.client.tooltips.hide() \ No newline at end of file + user.client.tooltips.hide() + diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html index 67fb8a77f10c..2ed8f5c43ea1 100644 --- a/code/modules/tooltip/tooltip.html +++ b/code/modules/tooltip/tooltip.html @@ -65,12 +65,12 @@ .hisgrace .wrap {border-color: #7C1414;} .hisgrace .content {color: #15D512; border-color: #9D1414; background-color: #861414;} - + /* TG: Themes */ /* ScreenUI */ .midnight .wrap {border-color: #2B2B33;} .midnight .content {color: #6087A0; border-color: #2B2B33; background-color: #36363C;} - + .plasmafire .wrap {border-color: #21213D;} .plasmafire .content {color: #FFA800 ; border-color: #21213D; background-color:#1D1D36;} @@ -85,7 +85,7 @@ .clockwork .wrap {border-color: #170800;} .clockwork .content {color: #B18B25; border-color: #000000; background-color: #5F380E;} - + @@ -93,7 +93,7 @@
    - + - - - - -
    - - - - -
    -
    Baystation 12
    -
    A Space Station 13 Project
    - -

    - Code licensed under AGPLv3. Content licensed under CC BY-SA 3.0.

    - Visit our IRC channels: #bs12 and #codershuttle on irc.sorcery.net
    - Join our Discord server: -Click Here-
    - Support Baystation on Patreon: -Click Here-
    -
    - -
    Baystation 12 Credit List - - - - -
    - Developers: afterthought, chinsky, F-Tang Steve, mloc, PsiOmegaDelta, xales
    - Currently Active GitHub contributor list: -Click Here-
    -

    Credits: Abi79, Apple_Master, Arcalane, Aryn, babydoll, Cael_Aislinn, Ccomp5950, chinsky, CompactNinja, Deus Dactyl, DopeGhoti, Erthilo, Flashkirby, Hawk_v3, Head, Ipsil, Invisty, JoeyJo0, Lexusjjss, Melonstorm, Miniature, mloc, NerdyBoy1104, PsiOmegaDelta, Searif, SkyMarshal, Snapshot, Spectre, Strumpetplaya, Sunfall, Tastyfish, Uristqwerty, Xenone, cib, faux, Zuhayr

    - Special thanks to: The developers of /tg/station, /vg/station, GoonStation, the original Space Station 13, and BYOND -

    Have a bug to report?
    Visit our Issue Tracker.
    -
    - - -
    - -

    12 February 2020

    -

    SomeoneStoleMyNickname updated:

    -
      -
    • The Guidebooks Hacking and Repair and Construction should now work as intended.
    • -
    - -

    10 February 2020

    -

    Flying_loulou updated:

    -
      -
    • Fleet engineers rejoice ! The fleet unlocked some funds, in order to provide you with a dedicated uniform, constituted of a polo, some pants, and a jacket (available in the uniform vendor, under the utility extra section).
    • -
    - -

    08 February 2020

    -

    mikomyazaki updated:

    -
      -
    • Atmospherics' tank controllers work again when controlling the output vent.
    • -
    -

    zaredman updated:

    -
      -
    • Removes Explorer and Pilot access to Xenobiology, Xenoarchaeology, Toxins, and assorted labs. Pathfinder retains their original access.
    • -
    - -

    07 February 2020

    -

    Chinsky updated:

    -
      -
    • Various drinking glasses are now printed from a microlathe instead of being vended. Bar now has pre-loaded microlathe for this purpose.
    • -
    • Added new type of drinking glass - flute glass.
    • -
    • Added transparency to some reagents, namely water and booze.
    • -
    • Can now select recipies category in fabricators
    • -
    • More types of glasses can take accessories like sticks or straws now, try it out.
    • -
    - -

    05 February 2020

    -

    mikomyazaki updated:

    -
      -
    • Mobs without the UI elements to use psionics can no longer be granted psionics. e.g. simple animals.
    • -
    • Polytools now allow you to extend tools again.
    • -
    - -

    03 February 2020

    -

    mikomyazaki updated:

    -
      -
    • Throwing items at a disposal chute will properly dispose of them again.
    • -
    • Fixes a bug where (for example) throwing an object at a grilled window would hit the grill inside the window instead of the window.
    • -
    - -

    31 January 2020

    -

    Lorwp updated:

    -
      -
    • Energy melee weapons now have an on-hit sound
    • -
    -

    mikomyazaki updated:

    -
      -
    • Paper will now check if your pen works before you start writing instead of after you've written your text.
    • -
    • If your retractable pen isn't in its active state when you start writing on something, your character will automatically click it.
    • -
    • Retractable pens will now toggle to their active state when you write on anything (union cards, people, the wall) instead of only paper.
    • -
    -

    zaredman updated:

    -
      -
    • Security now has access to a written statement, weapons license, arrest report, and restraining order template on the Reports program. Paperwork masochists, rejoice.
    • -
    - -

    30 January 2020

    -

    Anticept updated:

    -
      -
    • Farmbots now refill from a sink at a higher rate, up from 10 to 100 per cycle.
    • -
    -

    Cheb Pomidorov updated:

    -
      -
    • You can now lock and unlock coffins using a screwdriver. Locked coffins can be struggled out of, similarly to welded closets.
    • -
    -

    Imienny updated:

    -
      -
    • Added a new roles to Vox Scavenger away site, "Shoal Biotechnician", "Shoal Technician" and "Quill"
    • -
    -

    MrKicker updated:

    -
      -
    • AI can now make multi-line announcements
    • -
    -

    Spookerton updated:

    -
      -
    • IPCs can no longer be counsellors.
    • -
    -

    WezYo updated:

    -
      -
    • Flying drones can now open windoors
    • -
    -

    Xaytan updated:

    -
      -
    • Adds welding goggles as an option in loadout.
    • -
    -

    afterthought2 updated:

    -
      -
    • Pipe meters, vents, scrubbers, and pumps now use radio components.
    • -
    -

    mikomyazaki updated:

    -
      -
    • Guest pass icon will now change colour to black when expired.
    • -
    • Guest pass machine gets an updated UI.
    • -
    • Humanoid Dionaea now get the audible chirp emotes.
    • -
    • Added a new multichirp (*mchirp) audible emote sound effect for humanoid Dionaea.
    • -
    • Portable drives now work properly in modular computers for all operations.
    • -
    • Dense objects will now properly stop throwing/leaping.
    • -
    • Hand teleporters will now create portals that aren't random, when you are linked to a teleport computer on a connected z-level.
    • -
    • Hand teleporters will now only list teleport computers that are on a connected z-level.
    • -
    • Can no longer right-click darkness due to being unconscious to see what is on that turf.
    • -
    • Decreased difficulty of installing augments to the same level as installing robotic organs.
    • -
    • Adds three xenowear options for Space-Adapted humans - Leg braces, neck brace and venter.
    • -
    • Adds animations for the sleeper & bodyscanner when active & occupied.
    • -
    • Adds a scanning sound for the bodyscanner.
    • -
    • Space-Adapted humans' stamina now depends slightly upon gravity levels, with better stamina than baseline humans in low-gravity, worse in standard gravity.
    • -
    • Space-Adapted humans are adapted for lower-pressure environments, but suffer in higher pressure environments faster relative to baseline humans.
    • -
    • The Vox shuttle can now return to its hangar properly.
    • -
    -

    quardbreak updated:

    -
      -
    • Tweaked welding sounds on airlock and vents. Now after weld operation you should hear second sound like you end your action.
    • -
    -

    zkxs updated:

    -
      -
    • Combining stacks from an inventory no longer leaves bugged sprites
    • -
    • Having more than 10 brain damage no longer grants immunity to peridaxon's side effects (confusion and drowsiness)
    • -
    • Sec HUD goggles description grammar fix
    • -
    • Adherent can now float over tables
    • -
    - -

    03 January 2020

    -

    Devildabeast updated:

    -
      -
    • Changes "restricted roles" to the broader "casual roles" in loadoout.
    • -
    • Adjusts several loadout item restrictions.
    • -
    -

    Imienny updated:

    -
      -
    • Replaced spoon in MRE with spork
    • -
    -

    mikomyazaki updated:

    -
      -
    • Nymphs and Golems are no longer valid targets for auto-traitor.
    • -
    • Mercenary radio channel now works again for mercs, raiders, traitors etc.
    • -
    -

    zkxs updated:

    -
      -
    • Fixes a runtime when using an atmos analyzer on a pit
    • -
    - -

    28 December 2019

    -

    Cheb Pomidorov updated:

    -
      -
    • Scientists and Research Assistants can now enter areas such as Medbay and Brig's hallways and the Bridge Entry.
    • -
    -

    Devildabeast updated:

    -
      -
    • Changes the Mentalist's Mind Read time limit from 25 seconds to 60.
    • -
    -

    Spookerton updated:

    -
      -
    • Mercenary and Provocateur starting points are hidden from the Torch's roundstart sensor message.
    • -
    -

    zkxs updated:

    -
      -
    • The psionic signal event can no longer give synthetics genetic disabilities
    • -
    - -

    27 December 2019

    -

    babydoll updated:

    -
      -
    • Increased damage taken when falling down a hole to another deck.
    • -
    • Increased duration of stun after falling.
    • -
    -

    mikomyazaki updated:

    -
      -
    • Merchant station teleporter computer will now display the proper messages relating to costs.
    • -
    - -

    23 December 2019

    -

    mikomyazaki updated:

    -
      -
    • Can't put objects inside bags that are in pockets anymore.
    • -
    • Updated traitor extended round description so it is appropriate for the SEV Torch setting.
    • -
    • Double doors are properly solid again.
    • -
    - -

    22 December 2019

    -

    Chinsky updated:

    -
      -
    • During the metor rounds, evacuation jump will be called automatically after announcement that rocks are coming. It will take 30ish minutes to arrive
    • -
    • Since there's less time and Torch is /very/ sturdy (thicc hull and PD), initial intensity is bumped a bit and escalation is going faster, so will hit max intensity at around 30 minutes mark.
    • -
    • After the jump mode will check for some important things and will print red/green text about them: helm console (need to have at least one and powered), thrusters (ditto), bluespace drive (the room must be powered).
    • -
    -

    mikomyazaki updated:

    -
      -
    • Trained Forensics now provides a much larger bonus to making simple incisions on dead targets for autopsies.
    • -
    - -

    21 December 2019

    -

    Imienny updated:

    -
      -
    • Tweaked TC cost of uplinks in Character Setup menu, radio uplink now gives you 30% more TC, uplink Implant cost only 20% of total TC and taking TC without uplink gives you 50% more TC.
    • -
    • Message shown after receiving PDA uplink now should explain better how to access uplink.
    • -
    • Delay for removing knives from boots was decreased to one second
    • -
    • Using combi-knifes on intent other than help intent will now open their blade
    • -
    • Portable freezers can now fit inside backpacks and have capacity of large box
    • -
    • Combat knifes can now fit inside boots
    • -
    -

    mikomyazaki updated:

    -
      -
    • Sleepers will now properly display the amount of a drug in the occupant on the UI.
    • -
    • R-UST now has a prompt to tell you when hitting the shutdown button will cause an instant explosion, asking whether you're sure.
    • -
    • R-UST room machinery starts the round anchored.
    • -
    • Improves the fuel injector controller UI, with injection rate and toggle all injectors controls.
    • -
    - -

    20 December 2019

    -

    Cajoes updated:

    -
      -
    • Added orderable replacement barricade tape rolls from supply.
    • -
    -

    PsyCommando updated:

    -
      -
    • Made the currency used in text entries read from the current map. Mainly to help with downstream stuff.
    • -
    -

    afterthought2 updated:

    -
      -
    • Buildable radio components for machines are now available. They will have limited use with machines currently.
    • -
    • When building air sensors, you now must also add a power component and a radio transmitter. You can use a multitool on the radio transmitter while standing near a machine to configure it.
    • -
    -

    ghostsheet updated:

    -
      -
    • Mercenary gamemode is now overmap.
    • -
    - -

    19 December 2019

    -

    Spookerton updated:

    -
      -
    • PTR bullets aren't hitscan and do a little less damage and penetration.
    • -
    -

    babydoll updated:

    -
      -
    • Added foam dart launchers.
    • -
    • Foam dart launchers can now be won as prizes from arcade machines.
    • -
    • Added a modified foam dart launcher to the uplink's gimmick weapons menu.
    • -
    - -

    17 December 2019

    -

    CrimsonShrike updated:

    -
      -
    • Drill heads show current status while mounted and can be examined for information when not mounted on an exosuit drill.
    • -
    -

    EcklesFire updated:

    -
      -
    • Adjusted renegade numbers.
    • -
    • Removed duplicate vars.
    • -
    - -

    15 December 2019

    -

    Spookerton updated:

    -
      -
    • Starborn, Blueforged, and Promethean variations properly show the head, torso, and groin.
    • -
    - -

    12 December 2019

    -

    Rowtree updated:

    -
      -
    • Fixes recently added drink strengths to a more accurate level.
    • -
    -

    Spookerton updated:

    -
      -
    • Bald boosters get bald ears.
    • -
    -

    mikomyazaki updated:

    -
      -
    • AIs can now spawn properly at roundstart.
    • -
    -

    zaredman updated:

    -
      -
    • Biowaste disposal cart access to only require surgery access instead of requiring 6 different accesses. Corpsmen rejoice!
    • -
    -
    - -GoonStation 13 Development Team -
    - Coders: Stuntwaffle, Showtime, Pantaloons, Nannek, Keelin, Exadv1, hobnob, Justicefries, 0staf, sniperchance, AngriestIBM, BrianOBlivion
    - Spriters: Supernorn, Haruhi, Stuntwaffle, Pantaloons, Rho, SynthOrange, I Said No
    -
    -
    -

    Creative Commons License
    Except where otherwise noted, Goon Station 13 is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License.
    Rights are currently extended to SomethingAwful Goons only.

    -

    Some icons by Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 License.

    -
    - - + + + + Nebula13 Changelog + + + + + + + +
    + + + + +
    +
    Nebula13
    +
    A Space Station 13 Project
    + +

    + Code licensed under AGPLv3. Content licensed under CC BY-SA 3.0.

    +
    + +
    Nebula13 Credit List + + + + +
    + Contributor list: -Click Here-
    + Special thanks to: the developers of Baystation 12, ScavStation, /tg/station, /vg/station, GoonStation, the original Space Station 13, and BYOND.
    +

    Have a bug to report?
    Visit our Issue Tracker.
    +
    + + +
    + +

    27 March 2026

    +

    Typhin updated:

    +
      +
    • Prevented Garlic Oil from dealing TOX damage
    • +
    +
    +
    + + diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 2760bc299241..83328d67f5a5 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -1,13392 +1,15072 @@ -DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. ---- -2013-01-07: - Cael_Aislinn: - - tgs: Updated server to tgstation r5200 (November 26th, 2012), see https://code.google.com/p/tgstation13/source/list - for tg's changelog. - Chinsky: - - rscadd: 'Implants: Explosvie implant, exploding when victim hears the codephrase - you set.' - - rscadd: 'Implants: Compressed Matter implat, scan item (making it disappear), - inject yourself and recall that item on will!' - - rscadd: Implant removal surgery, with !!FUN!! results if you mess up it. - - rscadd: Coats now have pockets again. - - rscadd: Bash people on tabetops. an windows, or with stools. Grab people to bash - them on tables or windows (better grab for better hit on windows). Drag stool - sprite on you to pick it up, click on it in hand to make it usual stool again. - - rscadd: Surgical caps, and new sprites for bloodbags and fixovein. - - rscadd: Now some surgery steps will bloody your hands, Full-body blood coat in - case youy mess up spectacualry. - - rscadd: Ported some crates (Art, Surgery, Sterile equiplemnt). - - tweak: Changed contraband crates. Posters moved to Art Crate, cigs and lipstick - ot party crate. Now contraband crate has illegal booze and illicit drugs. - - bugfix: Finally got evac party lights - - bugfix: Now disfigurment,now it WILL happen when damage is bad enough. - - experiment: Now if you speak in depressurized area (less than 10 kPa) only people - next to you can hear you. Radios still work though. -2013-01-13: - Chinsky: - - tweak: If you get enough (6) blood drips on one tile, it'll turn into a blood - puddle. Should make bleeding out more visible. - - tweak: Security belt now able to hold taser, baton and tape roll. - - tweak: Added alternative security uniform to Security wardrobes. - - rscadd: 'Ported Urist cult runes. Down with the crayon drawings! Example: http://dl.dropbox.com/u/26846767/images/SS13/255_symbols.PNG' - - bugfix: Engineering tape now require engineer OR atmos access instead of both. - - rscadd: Implants now will react to EMP, possibly in !!FUN!! ways - GauHelldragon: - - rscadd: Servicebots now have RoboTray and Printing Pen. Robotray can be used to - pick up and drop food/drinks. Printing pen can alternate between writing mode - and rename paper mode by clicking it. - - rscadd: Farmbots. A new type of robot that weeds, waters and fertilizes. Use robot - arm on water tank. Then use plant analyzer, mini-hoe, bucket and finally proximity - sensor. - - rscadd: Chefs can clang their serving trays with a rolling pin. Just like a riot - shield! -2013-01-21: - Cael_Aislinn: - - bugfix: Satchels and ore boxes can now hold strange rocks. - - rscadd: Closets and crates can now be built out of 5 and 10 plasteel respectively. - - rscadd: Observers can become mice once more. -2013-01-23: - Cael_Aislinn: - - tgs: Updated server to tgstation r5200 (November 26th, 2012), see https://code.google.com/p/tgstation13/source/list - for tg's changelog. -2013-01-31: - CIB: - - bugfix: Chilis and cold chilis no longer kill in small amounts - - bugfix: Chloral now again needs around 5 units to start killing somebody -2013-02-13: - Erthilo: - - bugfix: Fixed SSD (logged-out) players not staying asleep. - - bugfix: Fixed set-pose verb and mice emotes having extra periods. - - bugfix: Fixed virus crate not appearing and breaking supply shuttle. - - bugfix: Fixed newcaster photos not being censored. -2013-02-14: - CIB: - - rscadd: Medical side-effects(patients are going to come back for secondary treatment) - - rscadd: NT loyalty setting(affects command reports and gives antags hints who - might collaborate with them) - - tweak: Simple animal balance fixes(They're slower now) - CaelAislinn: - - rscadd: Re-added old ion storm laws, re-added grid check event. - - rscadd: Added Rogue Drone and Vermin Infestation random events. - - rscadd: Added/fixed space vines random event. - - tweak: Updates to the virus events. - - tweak: Spider infestation and alien infestation events turned off by default. - - tweak: Soghun, taj and skrell all have unique language text colours. - - tweak: Moderators will no longer be listed in adminwho, instead use modwho. - Gamerofthegame: - - rscadd: Miscellaneous mapfixes. -2013-02-18: - Cael Aislinn: - - rscadd: Security bots will now target hostile mobs, and vice versa. - - tweak: Carp should actually emigrate now, instead of just immigrating then squatting - around the outer hull. - - tweak: Admins and moderators have been split up into separate 'who' verbs (adminwho - and modwho respectively). -2013-02-20: - Chinsky: - - rscadd: 'Added new surgery: putting items inside people. After you use retractor - to keep incision open, just click with any item to put it inside. But be wary, - if you try to fit something too big, you might rip the veins. To remove items, - use implant removal surgery.' - - rscadd: Crowbar can be used as alternative to retractor. - - rscadd: Can now unload guns by clicking them in hand. - - tweak: Fixed distance calculation in bullet missing chance computation, it was - always assuming 1 or 0 tiles. Now distace REALLY matters when you shoot. - - rscadd: To add more FUN to previous thing, bullets missed to not disappear but - keep going until they hit something else. - - bugfix: Compressed Matter and Explosive implants spawn properly now. - - tweak: 'Tweaks to medical effects: removed itch caused by bandages. Chemical effects - now have non-100 chance of appearing, the stronger medicine, the more probality - it''ll have side effects.' -2013-02-22: - Chinsky: - - tweak: Change to body cavity surgery. Can only put items in chest, groind and - head. Max size for item - 3 (chest), 2 (groin), 1 (head). For chest surgery - ribs should be bent open, (lung surgery until second scalpel step). Surgery - step needs preparation step, with drill. After that you can place item inside, - or seal it with cautery to do other step instead. -2013-02-23: - Cael Aislinn: - - wip: RUST machinery components should now be researchable (with high requirements) - and orderable through QM (with high cost). - - wip: Shield machinery should now be researchable (with high requirements) and - orderable through QM (with high cost). This one is reportedly buggy. - - tweak: Rogue vending machines should revert back to normal at the end of the event. - - rscadd: New Unathi hair styles. -2013-02-25: - Cael Aislinn: - - rscadd: As well as building hull shield generators, normal shield gens can now - be built (see http://baystation12.net/forums/viewtopic.php?f=1&t;=6993). - - rscadd: 'New random events: multiple new system wide-events have been have been - added to the newscaster feeds, some not quite as respectable as others.' - - rscadd: 'New random event: some lucky winners will win the TC Daily Grand Slam - Lotto, while others may be the target of malicious hackers.' -2013-02-27: - Gamerofthegame: - - rscadd: Added the (base gear) ERT preset for the debug command. - - rscadd: Map fixes, Virology hole fixed. Atmospheric fixes for mining and, to a - less extent, the science outpost. (No, not cycling airlocks) - - rscadd: Fiddled with the ERT set up location on Centcom. Radmins will now have - a even easier time equiping a team of any real pratical size, especially coupled - with the above debug command. -2013-03-05: - CIB: - - rscadd: Added internal organs. They're currently all located in the chest. Use - advanced scanner to detect damage. Use the same surgery as for ruptured lungs - to fix them. - Cael Aislinn: - - soundadd: Set roundstart music to randomly choose between space.ogg and traitor.ogg - (see http://baystation12.net/forums/viewtopic.php?f=5&t;=6972) - - experiment: All RUST components except for TEGs (which generate the power) are - now obtainable ingame, bored engineers should get hold of them and setup an - experimental reactor for testing purposes. -2013-03-06: - Cael Aislinn: - - rscadd: Type 1 thermoelectric generators and the associated binary circulators - are now moveable (wrench to secure/unsecure) and orderable via Quartermaster. - - wip: code/maps/rust_test.dmm contains an example setup for a functional RUST reactor. - Maximum output is in the range of 12 to 20MW (12 to 20 million watts). - - bugfix: Removed double announcement for gridchecks, reduced duration of gridchecks. - RavingManiac: - - rscadd: You can now stab people with syringes using the "harm" intent. This destroys - the syringe and transfers a random percentage of its contents into the target. - Armor has a 50% chance of blocking the syringe. -2013-03-09: - Cael Aislinn: - - rscadd: "Beekeeping is now possible. Construct an apiary of out wood and embed\ - \ it into a hydroponics tray, then get a queen bee and bottle of BeezEez from\ - \ cargo bay. \n\t\tHives produce honey and honeycomb, but be wary if the bees\ - \ start swarming." -2013-03-11: - CIB: - - rscadd: Cloning now requires you to put slabs of meat into the cloning pod to - replenish biomass. - Cael Aislinn: - - wip: The xenoarchaeology update is here. This includes a major content overhaul - and a bunch of new features for xenoarchaeology. - - tweak: Digsites (strange rock deposits) are now much more nuanced and interesting, - and a huge number of minor (non-artifact) finds have been added. - - rscadd: Excavation is now a complex process that involves digging into the rock - to the right depth. - - rscadd: Chemical analysis is required for safe excavation of the digsites, in - order to determine how best to extract the finds. - - bugfix: Anomalous artifacts have been overhauled and many longstanding bugs with - existing effects have been fixed - the anomaly utiliser should now work much - more often. - - rscadd: Numerous new artifact effects have been added and some new artifact types - can be dug up from the asteroid. - - rscadd: New tools and equipment have been added, including normal and spaceworthy - versions of the anomaly suits, excavation tools and other neat gadgets. - - rscadd: Five books have been written by subject matter experts from around the - galaxy to help the crew of the Exodus come to grips with this exacting new science - (over 3000 words of tutorials!). - Chinsky: - - rscadd: Sec HUDs now can see short versions of sec records.on examine. Med HUDs - do same for medical records, and can set medical status of patient. - - rscadd: Damage to the head can now cause brain damage. -2013-03-14: - Spamcat: - - rscadd: Figured I should make one of these. Syringestabbing now produces a broken - syringe complete with fingerprints of attacker and blood of a victim, so dispose - your evidence carefully. Maximum transfer amount per stab is lowered to 10. -2013-03-15: - Cael_Aislinn: - - rscadd: Mapped a compact research base on the mining asteroid, with multiple labs - and testing rooms. It's reachable through a new (old) shuttle dock that leaves - from the research wing on the main station. -2013-03-26: - Spamcat: - - bugfix: Chemmaster now puts pills in pill bottles (if one is inserted). - - tweak: Stabbing someone with a syringe now deals 3 damage instead of 7 because - 7 is like, a crowbar punch. - - bugfix: Lizards can now join mid-round again. - - rscadd: Chemicals in bloodstream will transfer with blood now, so don't get drunk - before your blood donation. Viruses and antibodies transfer through blood too. - - bugfix: Virology is working again. -2013-03-27: - Asanadas: - - tweak: The Null Rod has recovered its de-culting ability, for balance reasons. - Metagaming with it is a big no-no! - - rscadd: Holy Water as a liquid is able to de-cult. Less effective, but less bloody. - May be changed over the course of time for balance. -2013-04-04: - SkyMarshal: - - bugfix: Fixed ZAS - - bugfix: Fixed Fire - Spamcat: - - bugfix: Blood type is now saved in character creation menu, no need to edit it - manually every round. -2013-04-09: - SkyMarshal: - - bugfix: Fire Issues (Firedoors, Flamethrowers, Incendiary Grenades) fixed. - - bugfix: Fixed a bad line of code that was preventing autoignition of flammable - gas mixes. - - bugfix: Volatile fuel is burned up after a point. - - rscdel: Partial-tile firedoors removed. This is due to ZAS breaking when interacting - with them. -2013-04-11: - SkyMarshal: - - experiment: Fire has been reworked. - - experiment: In-game variable editor is both readded and expanded with fire controlling - capability. -2013-04-17: - SkyMarshal: - - experiment: ZAS is now more deadly, as per decision by administrative team. May - be tweaked, but currently AIRFLOW is the biggest griefer. - - experiment: World startup optimized, many functions now delayed until a player - joins the server. (Reduces server boot time significantly) - - tweak: Zones will now equalize air more rapidly. - - bugfix: ZAS now respects active magboots when airflow occurs. - - bugfix: Airflow will no longer throw you into doors and open them. - - bugfix: Race condition in zone construction has been fixed, so zones connect properly - at round start. - - bugfix: Plasma effects readded. - - bugfix: Fixed runtime involving away mission. -2013-04-24: - Jediluke69: - - rscadd: Added 5 new drinks (Kira Special, Lemonade, Brown Star, Milkshakes, Rewriter) - - tweak: Nanopaste now heals about half of what it used to - - tweak: Ballistic crates should now come with shotguns loaded with actual shells - no more beanbags - - bugfix: Iced tea no longer makes a glass of .what? - NerdyBoy1104: - - rscadd: 'New Botany additions: Rice and Plastellium. New sheet material: Plastic.' - - rscadd: Plastellium is refined into plastic by first grinding the produce to get - plasticide. 20 plasticide + 10 polytrinic acid makes 10 sheets of plastic which - can be used to make crates, forks, spoons, knives, ashtrays or plastic bags - from. - - rscadd: Rice seeds grows into rice stalks that you grind to get rice. 10 Rice - + 5 Water makes boiled rice, 10 rice + 5 milk makes rice pudding, 10 rice + - 5 universal enzyme (in beaker) makes Sake. - faux: - - imageadd: Mixed Wardrobe Closet now has colored shoes and plaid skirts. - - imageadd: Dress uniforms added to the Captain, RD, and HoP wardrobe closets. A - uniform jacket has also been added to the Captain's closet. HoS' hat has been - re-added to their closet. I do not love the CMO and CE enough to give them anything. - - imageadd: Atheletic closet now has five different swimsuits *for the ladies* in - them. If you are a guy, be prepared to be yelled at if you run around like a - moron in one of these. Same goes for ladies who run around in shorts with their - titties swaying in the space winds. - - imageadd: A set of dispatcher uniforms will spawn in the security closet. These - are for playtesting the dispatcher role. - - imageadd: New suit spawns in the laundry room. It's for geezer's only. You're - welcome, Book. - - imageadd: Nurse outfit variant, orderly uniform, and first responder jacket will - now spawn in the medical wardrobe closet. - - imageadd: 'A white wedding dress will spawn in the chaplain''s closet. There are - also several dresses currently only adminspawnable. Admins: Look either under - "bride" or "dress." The bride one leads to the colored wedding dresses, and - there are some other kinds of dresses under dress.' - - tweak: No more luchador masks or boxing gloves or boxing ring. You guys have a - swimming pool now, dip in and enjoy it. - - tweak: he meeting hall has been replaced with an awkwardly placed security office - meant for prisoner processing. - - tweak: Added a couple more welding goggles to engineering since you guys liked - those a lot. - - imageadd: Flasks spawn behind the bar. Only three. Don't fight over them. I don't - know how to add them to the bar vending machine otherwise I would have done - that instead. Detective, you have your own flask in your office, it's underneath - the cigarettes on your desk. - - tweak: Added two canes to the medical storage, for people who have leg injuries - and can't walk good and stuff. I do not want to see doctors pretending to be - House. These are for patients. Do not make me delete this addition and declare - you guys not being able to have nice things. - - tweak: Secondary entance to EVA now directly leads into the medbay hardsuit section. - Sorry for any inconviences this will cause. The CMO can now fetch the hardsuits - whenever they want. - - tweak: Secondary security hardsuit has been added to the armory. Security members - please stop stealing engineer's hardsuits when you guys want to pair up for - space travel. - - tweak: Firelocks have been moved around in the main hallways to form really ghetto - versions of airlocks. - - tweak: Violin spawns in theatre storage now. I didn't put the piano there though, - that was someone else. - - tweak: Psych office in medbay has been made better looking. -2013-05-14: - Cael_Aislinn: - - experiment: Depth scanners can now be used to determine what material archaeological - deposits are made of, meaning lab analysis is no longer required. - - tweak: Some useability issues with xenoarchaeology tools have been resolved, and - the transit pods cycle automatically now. -2013-05-15: - Spamcat: - - rscadd: Added telescopic batons - to HoS's and captain's lockers. These are quite robust and easily concealable. -2013-05-21: - SkyMarshal: - - experiment: ZAS will now speed air movement into/out of a zone when unsimulated - tiles (e.g. space) are involved, in relation to the number of tiles. - - experiment: Portable Canisters will now automatically connect to any portable - connecter beneath them on map load. - - bugfix: Bug involving mis-mapped disposal junction fixed - - bugfix: Air alarms now work for atmos techs (whoops!) - - bugfix: The Master Controller now properly stops atmos when it runtimes. - - bugfix: Backpacks can no longer be contaminated - - tweak: ZAS no longer logs air statistics. - - tweak: ZAS now rebuilds as soon as it detects a semi-complex change in geometry. (It - was doing this already, but in a convoluted way which was actually less efficient) - - tweak: General code cleanup/commenting of ZAS - - tweak: Jungle now initializes after the random Z-level loads and atmos initializes. -2013-05-25: - Erthilo: - - bugfix: Fixes alien races appearing an unknown when speaking their language. - - bugfix: Fixes alien races losing their language when cloned. - - bugfix: Fixes UI getting randomly reset when trying to change it in Genetics Scanners. -2013-05-26: - Chinsky: - - rscadd: Tentacles! Now clone damage will make you horribly malformed like examine - text says. - Meyar: - - rscadd: The syndicate shuttle now has a cycling airlock during Nuke rounds. - - rscadd: Restored the ability for the syndicate Agent ID to change the name on - the card (reforge it) more than once. - - rscadd: ERT Radio now functional again. - - rscadd: 'Research blast doors now actually lock down the entirety of station-side - Research. ' - - rscadd: 'Added lock down buttons to the wardens office. ' - - rscadd: 'The randomized barsign has made a return. ' - - rscadd: Syndicate Agent ID's external airlock access restored. - VitrescentTortoise: - - rscadd: Added a third option for not getting any job preferences. It allows you - to return to the lobby instead of joining. -2013-05-28: - Erthilo: - - bugfix: Fixes everyone being able to understand alien languages. HERE IS YOUR - TOWER OF BABEL - VitrescentTortoise: - - bugfix: Wizard's forcewall now works. -2013-05-30: - Segrain: - - bugfix: Meteor showers actually spawn meteors now. - - tweak: Engineering tape fits into toolbelt and can be placed on doors. - - rscadd: Pill bottles can hold paper. - Spamcat: - - tweak: Pill bottle capacity increased to 14 items. - - bugfix: Fixed Lamarr (it now spawns properly) - proliberate: - - rscadd: Station time is now displayed in the status tab for new players and AIs. -2013-05-31: - Segrain: - - bugfix: Portable canisters now properly connect to ports beneath them on map load. - - bugfix: Fixed unfastening gas meters. -2013-06-01: - Chinsky: - - rscadd: Bloody footprints! Now stepping in the puddle will dirty your shoes/feet - and make you leave bloody footprints for a bit. - - rscadd: Blood now dries up after some time. Puddles take ~30 minutes, small things - 5 minutes. - - bugfix: Untreated wounds now heal. No more toe stubs spamming you with pain messages - for the rest of the shift. - - experiment: On the other side, everything is healed slowly. Maximum you cna squeeze - out of first aid is 0.5 health per tick per organ. Lying down makes it faster - too, by 1.5x factor. - - rscadd: Lids! Click beaker/bottle in hand to put them on/off. Prevent spilling - - rscadd: Added 'hailer' to security lockers. If used in hand, says "Halt! Security!". - For those who can't run and type. -2013-06-05: - Chinsky: - - rscadd: Load bearing equipment - webbings and vests for engineers and sec. Attach - to jumpsuit, use 'Look in storage' verb (object tab) to open. - Segrain: - - rscadd: Exosuits now can open firelocks by walking into them. -2013-06-06: - Asanadas: - - rscadd: Added a whimsical suit to the head of personnel's secret clothing locker. - Meyar: - - bugfix: Disposal's mail routing fixed. Missing pipes replaced. - - bugfix: 'Chemistry is once again a part of the disposals delivery circuit. ' - - bugfix: Added missing sorting junctions to Security and HoS office. - - bugfix: Fixed a duplicate sorting junction. -2013-06-09: - Segrain: - - bugfix: Emagged supply console can order SpecOp crates again. -2013-06-11: - Meyar: - - bugfix: Fixes a security door with a firedoor ontop of it. - - bugfix: Fixed a typo relating to the admin Select Equipment Verb. (It's RESPONSE - team not RESCUE team) - - rscadd: ERT are now automated, from their spawn to their shuttle. Admin intervention - no longer required! (Getting to the mechs still requires admin permission generally) - - rscadd: Added flashlights to compensate for the weakened PDA lights - - tweak: 'ERT Uniforms updated to be in line with Centcom uniforms. No more turtlenecks, - no sir. ' -2013-06-12: - Zuhayr: - - rscadd: Added pneumatic cannon and harpoons. - - experiment: Added embedded projectiles. Bullets and thrown weapons may stick in - targets. Throwing them by hand won't make them stick, firing them from a cannon - might. Implant removal surgery will get rid of shrapnel and stuck items. -2013-06-13: - Kilakk: - - rscadd: Added the Xenobiologist job. Has access to the research hallway and to - xenobiology. - - rscdel: Removed Xenobiology access from Scientists. - - rscdel: Removed the Xenobiologist alternate title from Scientists. - - rscadd: Added "Xenoarchaeology" to the RD, Scientists, and to the ID computer. - - tweak: Changed the Research Outpost doors to use "Xenoarchaeology" access. -2013-06-18: - Segrain: - - bugfix: Fixed some bugs in windoor construction. - - tweak: Secure windoors are made with rods again. - - rscadd: Windoors drop their electronics when broken. Emagged windoors can have - theirs removed by crowbar. - - rscadd: Airlock electronics can be configured to make door open for any single - access on it instead of all of them. - - rscadd: Cyborgs can preview their icons before choosing. -2013-06-21: - Jupotter: - - bugfix: Fix the robotiscist preview in the char setupe screen -2013-06-22: - Cael_Aislinn: - - tweak: The xenoarchaeology depth scanner will now tell you what energy field is - required to safely extract a find. - - tweak: Excavation picks will now dig faster, and xenoarchaeology as a whole should - be easier to do. -2013-06-23: - Segrain: - - rscadd: Airlocks of various models can be constructed again. - faux: - - experiment: There has been a complete medbay renovation spearheaded by Vetinarix. - http://baystation12.net/forums/viewtopic.php?f=20&t;=7847 <-- Please - put any commentary good or bad, here. - - tweak: Some maintenance doors within RnD and Medbay have had their accesses changed. - Maintenance doors in the joint areas (leading to the research shuttle, virology, - and xenobiology) are now zero access. Which means anyone in those joints can - enter the maintenance tunnels. This was done to add additional evacuation locations - during radiation storms. Additional maintenance doors were added to the tunnels - in these areas to prevent docs and scientists from running about. - - tweak: Starboard emergency storage isn't gone now, it's simply located in the - escape wing. - - experiment: An engineering training room has been added to engineering. This location - was previously where surgery was located. If you are new to engineering or need - to brush up on your skills, please use this area for testing. -2013-06-26: - Segrain: - - bugfix: Autopsy scanner properly displays time of wound infliction and death. - - bugfix: Autopsy scanner properly displays wounds by projectile weapons. - Whitellama: - - bugfix: One-antag rounds (like wizard/ninja) no longer end automatically upon - death - - wip: Space ninja has been implemented as a voteable gamemode - - rscadd: Space ninja spawn landmarks have been implemented (but not yet placed - on the map), still spawn at carps-pawns instead. (The code will warn you about - this and ask you to report it, it's a known issue.) - - rscadd: Five new space ninja directives have been added, old directives have been - reworded to be less harsh - - wip: Space ninjas have been given their own list as antagonists, and are no longer - bundled up with traitors - - bugfix: Space ninjas with a "steal a functional AI" objective will now succeed - by downloading one into their suits - - tweak: Space ninja suits' exploding on death has been nerfed, so as not to cause - breaches - - rscadd: A few space ninja titles/names have been added and removed to be slightly - more believable - - bugfix: The antagonist selector no longer chooses jobbanned players when it runs - out of willing options -2013-06-27: - Segrain: - - bugfix: ID cards properly setup bloodtype, DNA and fingerprints again. -2013-06-28: - Segrain: - - rscadd: AIs are now able to examine what they see. -2013-07-03: - Segrain: - - rscadd: Security and medical cyborgs can use their HUDs to access records. -2013-07-05: - Spamcat: - - rscadd: Pulse! Humans now have hearbeat rate, which can be measured by right-clicking - someone - Check pulse or by health analyzer. Medical machinery also has heartbeat - monitors. Certain meds and conditions can influence it. -2013-07-06: - Chinsky: - - rscadd: Humans now can be infected with more than one virus at once. - - rscadd: All analyzed viruses are put into virus DB. You can view it and edit their - name and description on medical record consoles. - - tweak: 'Only known viruses (ones in DB) will be detected by the machinery and - HUDs. ' - - rscadd: Viruses cause fever, body temperature rising the more stage is. - - bugfix: Humans' body temperature does not drift towards room one unless there's - big difference in them. - - tweak: Virus incubators now can transmit viuses from dishes to blood sample. - - rscadd: New machine - centrifuge. It can isolate antibodies or viruses (spawning - virus dish) from a blood sample in vials. Accepts vials only. - - rscadd: Fancy vial boxes in virology, one of them is locked by ID with MD access. - - tweak: Engineered viruses are now ariborne too. -2013-07-11: - Chinsky: - - rscadd: Gun delays. All guns now have delays between shots. Most have less than - second, lasercannons and pulse rifles have around 2 seconds delay. Automatics - have zero, click-speed. -2013-07-26: - Kilakk: - - bugfix: Brig cell timers will no longer start counting down automatically. - - tweak: Separated the actual countdown timer from the timer controls. Pressing - "Set" while the timer is counting down will reset the countdown timer to the - time selected. -2013-07-28: - Segrain: - - rscadd: Camera console circuits can be adjusted for different networks. - - rscadd: Nuclear operatives and ERT members have built-in cameras in their helmets. - Activate helmet to initialize it. -2013-07-30: - Erthilo: - - bugfix: EFTPOS and ATM machines should now connect to databases. - - bugfix: Gravitational Catapults can now be removed from mechs. - - bugfix: Ghost manifest rune paper naming now works correctly. - - bugfix: Fix for newscaster special characters. Still not recommended. - Kilakk: - - rscadd: Added colored department radio channels. -2013-08-01: - Asanadas: - - tweak: The Null Rod has recovered its de-culting ability, for balance reasons. - Metagaming with it is a big no-no! - - rscadd: Holy Water as a liquid is able to de-cult. Less effective, but less bloody. - May be changed over the course of time for balance. - CIB: - - bugfix: Chilis and cold chilis no longer kill in small amounts - - bugfix: Chloral now again needs around 5 units to start killing somebody - Cael Aislinn: - - rscadd: Security bots will now target hostile mobs, and vice versa. - - tweak: Carp should actually emigrate now, instead of just immigrating then squatting - around the outer hull. - - tweak: Admins and moderators have been split up into separate 'who' verbs (adminwho - and modwho respectively). - CaelAislinn: - - rscadd: Re-added old ion storm laws, re-added grid check event. - - rscadd: Added Rogue Drone and Vermin Infestation random events. - - rscadd: Added/fixed space vines random event. - - tweak: Updates to the virus events. - - tweak: Spider infestation and alien infestation events turned off by default. - - tweak: Soghun, taj and skrell all have unique language text colours. - - tweak: Moderators will no longer be listed in adminwho, instead use modwho. - Cael_Aislinn: - - tgs: Updated server to tgstation r5200 (November 26th, 2012), see https://code.google.com/p/tgstation13/source/list - for tg's changelog. - Chinsky: - - rscadd: 'Old new medical features:' - - rscadd: Autoinjectors! They come preloaded with 5u of inapro, can be used instantly, - and are one-use. You can replace chems inside using a syringe. Box of them is - added to Medicine closet and medical supplies crate. - - rscadd: Splints! Target broken liimb and click on person to apply. Can be taken - off in inventory menu, like handcuffs. Splinted limbs have less negative effects. - - rscadd: Advanced medikit! Red and mean, all doctors spawn with one. Contains better - stuff - advanced versions of bandaids and aloe heal 12 damage on the first use. - - tweak: Wounds with damage above 50 won't heal by themselves even if bandaged/salved. - Would have to seek advanced medical attention for those. - Erthilo: - - bugfix: Fixed SSD (logged-out) players not staying asleep. - - bugfix: Fixed set-pose verb and mice emotes having extra periods. - - bugfix: Fixed virus crate not appearing and breaking supply shuttle. - - bugfix: Fixed newcaster photos not being censored. - Gamerofthegame: - - rscadd: Miscellaneous mapfixes. - GauHelldragon: - - rscadd: Servicebots now have RoboTray and Printing Pen. Robotray can be used to - pick up and drop food/drinks. Printing pen can alternate between writing mode - and rename paper mode by clicking it. - - rscadd: Farmbots. A new type of robot that weeds, waters and fertilizes. Use robot - arm on water tank. Then use plant analyzer, mini-hoe, bucket and finally proximity - sensor. - - rscadd: Chefs can clang their serving trays with a rolling pin. Just like a riot - shield! - Jediluke69: - - rscadd: Added 5 new drinks (Kira Special, Lemonade, Brown Star, Milkshakes, Rewriter) - - tweak: Nanopaste now heals about half of what it used to - - tweak: Ballistic crates should now come with shotguns loaded with actual shells - no more beanbags - - bugfix: Iced tea no longer makes a glass of .what? - Jupotter: - - bugfix: Fix the robotiscist preview in the char setupe screen - Kilakk: - - rscadd: Added the Xenobiologist job. Has access to the research hallway and to - xenobiology. - - rscdel: Removed Xenobiology access from Scientists. - - rscdel: Removed the Xenobiologist alternate title from Scientists. - - rscadd: Added "Xenoarchaeology" to the RD, Scientists, and to the ID computer. - - tweak: Changed the Research Outpost doors to use "Xenoarchaeology" access. - Meyar: - - rscadd: The syndicate shuttle now has a cycling airlock during Nuke rounds. - - rscadd: Restored the ability for the syndicate Agent ID to change the name on - the card (reforge it) more than once. - - rscadd: ERT Radio now functional again. - - rscadd: 'Research blast doors now actually lock down the entirety of station-side - Research. ' - - rscadd: 'Added lock down buttons to the wardens office. ' - - rscadd: 'The randomized barsign has made a return. ' - - rscadd: Syndicate Agent ID's external airlock access restored. - NerdyBoy1104: - - rscadd: 'New Botany additions: Rice and Plastellium. New sheet material: Plastic.' - - rscadd: Plastellium is refined into plastic by first grinding the produce to get - plasticide. 20 plasticide + 10 polytrinic acid makes 10 sheets of plastic which - can be used to make crates, forks, spoons, knives, ashtrays or plastic bags - from. - - rscadd: Rice seeds grows into rice stalks that you grind to get rice. 10 Rice - + 5 Water makes boiled rice, 10 rice + 5 milk makes rice pudding, 10 rice + - 5 universal enzyme (in beaker) makes Sake. - RavingManiac: - - rscadd: You can now stab people with syringes using the "harm" intent. This destroys - the syringe and transfers a random percentage of its contents into the target. - Armor has a 50% chance of blocking the syringe. - Segrain: - - bugfix: Meteor showers actually spawn meteors now. - - tweak: Engineering tape fits into toolbelt and can be placed on doors. - - rscadd: Pill bottles can hold paper. - SkyMarshal: - - bugfix: Fixed ZAS - - bugfix: Fixed Fire - Spamcat: - - rscadd: Figured I should make one of these. Syringestabbing now produces a broken - syringe complete with fingerprints of attacker and blood of a victim, so dispose - your evidence carefully. Maximum transfer amount per stab is lowered to 10. - VitrescentTortoise: - - rscadd: Added a third option for not getting any job preferences. It allows you - to return to the lobby instead of joining. - Whitellama: - - bugfix: One-antag rounds (like wizard/ninja) no longer end automatically upon - death - - wip: Space ninja has been implemented as a voteable gamemode - - rscadd: Space ninja spawn landmarks have been implemented (but not yet placed - on the map), still spawn at carps-pawns instead. (The code will warn you about - this and ask you to report it, it's a known issue.) - - rscadd: Five new space ninja directives have been added, old directives have been - reworded to be less harsh - - wip: Space ninjas have been given their own list as antagonists, and are no longer - bundled up with traitors - - bugfix: Space ninjas with a "steal a functional AI" objective will now succeed - by downloading one into their suits - - tweak: Space ninja suits' exploding on death has been nerfed, so as not to cause - breaches - - rscadd: A few space ninja titles/names have been added and removed to be slightly - more believable - - bugfix: The antagonist selector no longer chooses jobbanned players when it runs - out of willing options - Zuhayr: - - rscadd: Added pneumatic cannon and harpoons. - - experiment: Added embedded projectiles. Bullets and thrown weapons may stick in - targets. Throwing them by hand won't make them stick, firing them from a cannon - might. Implant removal surgery will get rid of shrapnel and stuck items. - faux: - - imageadd: Mixed Wardrobe Closet now has colored shoes and plaid skirts. - - imageadd: Dress uniforms added to the Captain, RD, and HoP wardrobe closets. A - uniform jacket has also been added to the Captain's closet. HoS' hat has been - re-added to their closet. I do not love the CMO and CE enough to give them anything. - - imageadd: Atheletic closet now has five different swimsuits *for the ladies* in - them. If you are a guy, be prepared to be yelled at if you run around like a - moron in one of these. Same goes for ladies who run around in shorts with their - titties swaying in the space winds. - - imageadd: A set of dispatcher uniforms will spawn in the security closet. These - are for playtesting the dispatcher role. - - imageadd: New suit spawns in the laundry room. It's for geezer's only. You're - welcome, Book. - - imageadd: Nurse outfit variant, orderly uniform, and first responder jacket will - now spawn in the medical wardrobe closet. - - imageadd: 'A white wedding dress will spawn in the chaplain''s closet. There are - also several dresses currently only adminspawnable. Admins: Look either under - "bride" or "dress." The bride one leads to the colored wedding dresses, and - there are some other kinds of dresses under dress.' - - tweak: No more luchador masks or boxing gloves or boxing ring. You guys have a - swimming pool now, dip in and enjoy it. - - tweak: he meeting hall has been replaced with an awkwardly placed security office - meant for prisoner processing. - - tweak: Added a couple more welding goggles to engineering since you guys liked - those a lot. - - imageadd: Flasks spawn behind the bar. Only three. Don't fight over them. I don't - know how to add them to the bar vending machine otherwise I would have done - that instead. Detective, you have your own flask in your office, it's underneath - the cigarettes on your desk. - - tweak: Added two canes to the medical storage, for people who have leg injuries - and can't walk good and stuff. I do not want to see doctors pretending to be - House. These are for patients. Do not make me delete this addition and declare - you guys not being able to have nice things. - - tweak: Secondary entance to EVA now directly leads into the medbay hardsuit section. - Sorry for any inconviences this will cause. The CMO can now fetch the hardsuits - whenever they want. - - tweak: Secondary security hardsuit has been added to the armory. Security members - please stop stealing engineer's hardsuits when you guys want to pair up for - space travel. - - tweak: Firelocks have been moved around in the main hallways to form really ghetto - versions of airlocks. - - tweak: Violin spawns in theatre storage now. I didn't put the piano there though, - that was someone else. - - tweak: Psych office in medbay has been made better looking. - proliberate: - - rscadd: Station time is now displayed in the status tab for new players and AIs. -2013-08-04: - Chinsky: - - rscadd: Health HUD indicator replaced with Pain indicator. Now health indicator - shows pain level instead of actual vitals level. Some types of damage contribute - more to pain, some less, usually feeling worse than they really are. -2013-08-08: - Erthilo: - - bugfix: Raise Dead rune now properly heals and revives dead corpse. - - bugfix: Admin-only rejuvenate verb now heals all organs, limbs, and diseases. - - bugfix: Cyborg sprites now correctly reset with reset boards. This means cyborg - appearances can now be changed without admin intervention. -2013-09-18: - Kilakk: - - rscadd: Fax machines! The Captain and IA agents can use the fax machine to send - properly formatted messages to Central Command. - - imageadd: Gave the fax machine a fancy animated sprite. Thanks Cajoes! -2013-09-24: - Snapshot: - - rscdel: Removed hidden vote counts. - - rscdel: Removed hiding of vote results. - - rscdel: Removed OOC muting during votes. - - rscadd: Crew transfers are no longer callable during Red and Delta alert. - - wip: Started work on Auto transfer framework. -2013-10-06: - Chinsky: - - rscadd: Return of dreaded side effects. They now manifest well after their cause - disappears, so curing them should be possible without them reappearing immediately. - They also lost last stage damaging effects. -2013-10-29: - Cael_Aislinn: - - rscadd: Xenoarchaeology's chemical analysis and six analysis machines are gone, - replaced by a single one which can be beaten in a minigame. - - rscadd: Sneaky traitors will find new challenges to overcome at the research outpost, - but may also find new opportunities (transit tubes can now be traversed). - - rscadd: Finding active alien machinery should now be made significantly easier - with the Alden-Saraspova counter. -2013-11-01: - Various: - - rscadd: Autovoting, Get off the station when your 15 hour workweek is done, thanks - unions! - - rscadd: Some beach props that Chinsky finds useless. - - wip: Updated NanoUI - - rscadd: Dialysis while in sleepers - removes reagents from mobs, like the chemist, - toss him in there! - - tweak: Pipe Dispensers can now be ordered by Cargo - - rscadd: Fancy G-G-G-G-Ghosts! -2013-11-23: - Ccomp5950: - - bugfix: Players are now no longer able to commit suicide with a lasertag gun, - and will feel silly for doing so. - - bugfix: Ghosts hit with the cult book shall now actually become visible. - - bugfix: The powercells spawned with Exosuits will now properly be named to not - confuse bearded roboticists. - - bugfix: Blindfolded players will now no longer require eye surgery to repair their - sight, removing the blindfold will be sufficient. - - rscadd: Atmospheric Technicians will now have access to Exterior airlocks. -2013-11-24: - Yinadele: - - experiment: Supermatter engine added! Please treat your new engine gently, and - report any strangeness! - - tweak: Rebalanced events so people don't explode into appendicitis or have their - organs constantly explode. - - rscadd: Vending machines have had bottled water, iced tea, and grape soda added. - - rscadd: Head reattachment surgery added! Sew heads back on proper rather than - monkey madness. - - rscadd: Pain crit rebalanced - Added aim variance depending on pain levels, nerfed - blackscreen severely. - - rscadd: 'Cyborg alt titles: Robot, and Android added! These will make you spawn - as a posibrained robot. Please enjoy!' - - bugfix: Fixed the sprite on the modified welding goggles, added a pair to the - CE's office where they'll be used. - - bugfix: Fixed atmos computers- They are once again responsive! - - tweak: Added in functionality proper for explosive implants- You can now set their - level of detonation, and their effects are more responsively concrete depending - on setting. - - rscadd: Hemostats re-added to autolathe! - - rscadd: Added two manuals on atmosia and EVA, by MagmaRam! Found in engineering - and the engineering bookcase. - - bugfix: Fixed areas in medbay to have fully functional APC sectors. - - rscadd: Girders are now lasable. - - experiment: Please wait warmly, new features planned for next merge! -2013-12-01: - 'Various Developers banged their keyboards together:': - - rscadd: New Engine, the supermatter, figure out what a cooling loop is, or don't - and blow up engineering! - - rscadd: Each department will have it's own fax, make a copy of your butt and fax - it to the admins! - - rscadd: Booze and soda dispensers, they are like chemmasters, only with booze - and soda! - - rscadd: Bluespace and Cryostasis beakers, how do they work? Fuggin bluespace - how do they work? - - rscadd: You can now shove things into vending machines, impress your friends on - how things magically disappear out of your hands into the machine! - - rscadd: Robots and Androids (And gynoids too!) can now use custom job titles - - bugfix: Various bugfixes -2013-12-18: - RavingManiac: - - rscadd: Mousetraps can now be "hidden" through the right-click menu. This makes - them go under tables, clutter and the like. The filthy rodents will never see - it coming! - - tweak: Monkeys will no longer move randomly while being pulled. -2014-01-01: - Various: - - rscadd: AntagHUD and MedicalHUD for ghosts, see who the baddies are, check for - new configuration options. - - rscadd: Ghosts will now have bold text if they are in the same room as the person - making conversations easier to follow. - - rscadd: New hairstyles! Now you can use something other then hotpink floor length - braid. - - wip: DNA rework, tell us how you were cloned and became albino! - - rscadd: Dirty floors, so now you know exactly how lazy the janitors are! - - rscadd: A new UI system, feel free to color it yourself, don't set it to completely - clear or you will have a bad time. - - rscadd: Cryogenic storage, for all your SSD needs. - - rscadd: New hardsuits for those syndicate tajaran -2014-02-01: - Various: - - rscadd: NanoUI for PDA - - rscadd: Write in blood while a ghost in cult rounds with enough cultists - - rscadd: Cookies, absurd sandwiches, and even cookable dioanae nymphs! - - rscadd: A bunch of new guns and other weapons - - rscadd: Species specific blood -2014-02-19: - Aryn: - - experiment: New air model. Nothing should change to a great degree, but temperature - flow might be affected due to closed connections not sticking around. -2014-03-01: - Various: - - rscadd: Paint Mixing, red and blue makes purple! - - rscadd: New posters to tell you to respect those darned cat people - - rscadd: NanoUI for APC's, Canisters, Tank Transfer Valves and the heaters / coolers - - tweak: PDA bombs are now less annoying, and won't always blow up / cause internal - bleeding - - tweak: Blob made less deadly - - rscadd: Objectiveless Antags now a configuration option, choose your own adventure! - - wip: Engineering redesign, now with better monitoring of the explodium supermatter! - - rscadd: Security EOD - - rscadd: New playable race, IPC's, go beep boop boop all over the station! - - rscadd: Gamemode autovoting, now players don't have to call for gamemode votes, - it's automatic! -2014-03-05: - RavingManiac: - - rscadd: Smartfridges added to the bar, chemistry and virology. No more clutter! - - rscadd: A certain musical instrument has returned to the bar. - - rscadd: There is now a ten second delay between ingesting a pill/donut/milkshake - and regretting it. -2014-03-10: - Chinsky: - - rscadd: Viruses now affect certain range of species, different for each virus - - tweak: Spaceacilline now prevents infection, and has a small chance to cure viruses - at Stage 1. It does not give them antibodies though, so they can get sick again! - - tweak: Biosuits and spacesuits now offer more protection against viruses. Full - biosuit competely prevents airborne infection, when coupled with gloves they - both protect quite well from contact ones - - rscadd: Sneezing now spreads viruses in front of mob. Sometimes he gets a warning - beforehand though -2014-03-30: - RavingManiac: - - rscadd: Inflatable walls and doors added. Useful for sealing off hull breaches, - but easily punctured by sharp objects and Tajarans. -2014-04-06: - RavingManiac: - - tweak: Tape recorders and station-bounced radios now work inside containers and - closets. -2014-04-11: - Jarcolr: - - rscadd: You can now flip coins like a D2 - - tweak: Miscellaneous cargo crates got a tiny buff, Standard Costume crate is now - Costume Crate - - tweak: Grammar patch,telekinesis/amputated arm exploit fixes,more in the future - - tweak: Grille kicking now does less damage - - tweak: TELESCOPIC baton no longer knocks anybody down,still got a lot of force - though - - tweak: Other small-ish changes and fixes that aren't worth mentioning -2014-04-25: - Various: - - rscadd: Overhauled saycode, you can now use languages over the radio. - - rscadd: Chamelon items beyond just the suit. - - rscadd: NanoUI Virology - - rscadd: 3D Sounds - - rscadd: AI Channel color for when they want to be all sneaky - - rscadd: New inflatable walls and airlocks for your breach sealing pleasure. - - rscadd: Carbon Copy papers, so you can subject everyone to your authority and - paperwork, but mainly paperwork - - rscadd: Undershirts and rolling down jumpsuits - - rscadd: Insta-hit tasers, can be shot through glass as well. - - rscadd: Changeling balances, an emphasis put more on stealth. - - rscdel: Genetics disabled - - rscdel: Telescience removed, might be added again when we come up with a less - math headache enducing version of it. - - bugfix: Bugfixes galore! -2014-04-29: - HarpyEagle: - - rscadd: Webbing vest storage can now be accessed by clicking on the item in inventory - - rscadd: Holsters can be accessed by clicking on them in inventory - - rscadd: Webbings and other suit attachments are now visible on the icon in inventory - - tweak: Removing jumpsuits now requires drag and drop to prevent accidental undressing - - rscadd: Added an action icon for magboots that can be used to toggle them similar - to flashlights - - rscadd: Fuel tanks now spill fuel when wrenched open -2014-05-03: - Cael_Aislinn: - - rscadd: "Coming out of nowhere the past few months, the Garland Corporation has\ - \ made headlines with a new prehistoric theme park delighting travellers with\ - \ species thought extinct. Now available for research stations everywhere is\ - \ the technology that made it all possible! Features include:
    \n\t\t\t-\ - \ 13 discoverable prehistoric species to clone from fossils (including 5 brand\ - \ new ones).
    \n\t\t\t- 11 discoverable prehistoric plants to clone from fossils\ - \ (including 9 brand new ones).
    \n\t\t\t- New minigame that involves correctly\ - \ ordering the genomes inside each genetic sequence to unlock an animal/plant.
    \n\ - \t\t\t- Some prehistoric animals and plants may seem strangely familiar... while\ - \ others may bring more than the erstwhile scientist bargains for.
    \n




    " -2014-05-06: - Hubble: - - rscadd: Clip papers together by hitting a paper with a paper or photo - - imageadd: Adds icons for copied stamps -2014-05-16: - HarpyEagle: - - rscadd: Silicon mob types (AI, cyborgs, PAI) can now speak certain species languages - depending on type and module - - rscadd: Languages can now be whispered when using the language code with either - the whisper verb or the whisper speech code -2014-05-23: - Hubble: - - rscadd: Personal lockers are now resettable - - rscadd: Take off people's accessories or change their sensors in the drag and - drop-interface - - rscadd: Merge paper bundles by hitting one with another - - tweak: Line breaks in Security, Medical and Employment Records - - tweak: Record printouts will have names on it - - tweak: Set other people's internals in belt and suit storage slots - - bugfix: No longer changing suit sensors while cuffed - - bugfix: No longer emptying other people's pockets when they are not full yet -2014-05-28: - Chinsky: - - rscadd: Adds few new paperBBcode tags, to make up for HTML removal. - - rscadd: '[logo] tag draws NT logo image (one from wiki).' - - rscadd: '[table] [/table] tags mark borders of tables. [grid] [/grid] are borderless - tables, useful of making layouts. Inside tables following tags are used: [row] - marks beginning of new table row, [cell] - beginning of new table cell.' -2014-05-31: - Jarcolr: - - rscadd: 21 New cargo crates, go check them out! - - rscadd: Peanuts have now been added, food items are now being developed. - - rscadd: 2 new cargo groups, Miscellaneous and Supply. - - rscadd: Sugarcane seeds can now be gotten from the seed dispenser. - - rscadd: 5 new satchels when selecting "satchel" for RD, scientist, botanist, virologist, - geneticist (disabled) and chemist. - - rscadd: Clicking on a player with a paper/book when you have the eyes selected - shows them the book/paper forcefully. -2014-06-03: - Hubblenaut: - - rscadd: Added wheelchairs - - tweak: Replaced stool in Medical Examination with wheelchair - - tweak: Using a fire-extinguisher to propel you on a chair can have consequences - (drive into walls and people, do it!) -2014-06-13: - HarpyEagle: - - rscadd: Added docking ports for shuttles - - rscadd: Shuttle airlocks will automatically open and close, preventing people - from being sucked into space by because someone on another z-level called a - shuttle - - rscadd: Some docking ports can also double as airlocks - - rscadd: Docking ports can be overriden to prevent any automatic action. Shuttles - will wait for players to open/close doors manually - - rscadd: Shuttles can be forced launched, which will make them not wait for airlocks - to be properly closed -2014-06-15: - HarpyEagle: - - bugfix: Fixed wound autohealing regardless of damage amount. The appropriate wound - will now be assigned correctly based on damage amount and type - - bugfix: Fixed several other bugs related wounds that resulted in damage magically - disappearing - - bugfix: Fixed various sharp objects not being counted as sharp, bullets in particular - - bugfix: Fixed armour providing more protection from bullets than it was supposed - to -2014-06-19: - Chinsky: - - rscadd: Adds guest terminals on the map. These wall terminals let anyone issue - temporary IDs. Only access that issuer has can be granted, and maximum time - pass can be issued for is 20 minutes. All operations are logged in terminals. -2014-06-20: - Cael_Aislinn: - - rscadd: 'New discoverable items added to xenoarchaeology, and new features for - some existing ones. Artifact harvesters can now harvest the secondary effect - of artifacts as well as the primary one.
    - -
    ' - - tweak: 'Artifact utilisers should be much nicer/easier to use now.
    - -
  • Alden-Saraspova counters and talking items should work properly - now.
    - -
  • - -
    ' -2014-07-01: - Various: - - experiment: Hardsuit breaching. - - experiment: Rewritten fire. - - experiment: Supermatter now glows and sucks things into it as it approaches criticality. - - rscadd: Station Vox (Vox pariahs) are now available. - - rscadd: Wheelchairs. - - rscadd: Cargo Trains. - - rscadd: Hardsuit cycler machinery. - - rscadd: Rewritten lighting (coloured lights!) - - rscadd: New Mining machinery and rewritten smelting. - - rscadd: Rewritten autolathe - - rscadd: Mutiny mode. - - rscadd: NanoUI airlock and docking controllers. - - rscadd: Completely rewritten shuttle code. - - rscadd: 'Derelict Z-level replacement: construction site.' - - rscadd: Computer3 laptops. - - rscadd: Constructable SMES units. - - rscadd: Omni-directional atmos machinery. - - rscadd: Climbable tables and crates. - - rscadd: Xenoflora added to Science. - - rscadd: Utensils can be used to eat food. - - rscadd: Decks of cards are now around the station. - - rscadd: Service robots can speak languages. - - wip: Xenoarch updates and fixes. - - tweak: Rewritten species-specific gear icon handling. - - tweak: Cats and borers can be picked up. - - tweak: Botanist renamed to Gardener. - - tweak: Hydroponics merged with the Kitchen. - - tweak: Latejoin spawn points (Arrivals, Cryostorage, Gateway). - - rscadd: Escape pods only launch automatically during emergency evacuations - - rscadd: Escape pods can be made to launch during regular crew transfers using - the control panel inside the pod, or by emagging the panel outside the pod - - rscadd: When swiped or emagged, the crew transfer shuttle can be delayed in addition - to being launched early -2014-07-06: - HarpyEagle: - - rscadd: Re-enabled and rewrote the wound infection system - - rscadd: Infections can be prevented by properly bandaging and salving wounds - - rscadd: Infections are cured by spaceacillin -2014-07-20: - PsiOmegaDelta: - - rscadd: AI can now store up to five camera locations and return to them when desired. - - rscadd: AI can now alt+left click turfs in camera view to list and interact with - the objects. - - rscadd: AI can now ctrl+click turret controls to enable/disable turrets. - - rscadd: AI can now alt+click turret controls to toggle stun/lethal mode. - - rscadd: AI can now select which channel to state laws on. -2014-07-26: - Whitellama: - - rscadd: Added dynamic flavour text. - - bugfix: Fixed bug with suit fibers and fingerprints. -2014-07-31: - HarpyEagle: - - tweak: Stun batons now work like tasers and deal agony instead of stun - - rscadd: Being hit in the hands with a stun weapon will cause whatever is being - held to be dropped - - tweak: Handcuffs now require an aggressive grab to be used -2014-08-02: - Whitellama: - - bugfix: Arcane tomes can now be stored on bookshelves. - - bugfix: Dionaea players no longer crash on death, and now become nymphs properly. -2014-08-05: - HarpyEagle: - - tweak: Atmos Rewrite. Many atmos devices now use power according to their load - and gas physics - - rscadd: Pressure regulator device. Replaces the passive gate and can regulate - input or output pressure - - rscadd: Gas heaters and gas coolers are now constructable and can be upgraded - with parts from research - - bugfix: Fixes recharger and cell charger power draw. Rechargers draw 15 kW, wall - chargers draw 25 kW, and heavy-duty cell chargers draw 40 kW. Cyborg charging - stations draw 75 kW. - - bugfix: Laptops, and various other machines, now draw more reasonable amounts - of power - - bugfix: Machines will periodically update their powered status if moved from a - powered to an unpowered area and vice versa -2014-08-27: - Whitellama: - - bugfix: Made destination taggers more intuitive so you know when you've tagged - something - - rscadd: Ported package label and tag sprites - - rscadd: Ported using a pen on a package to give it a title, or to write a note - - rscadd: Donut boxes and egg boxes can be constructed out of cardboard -2014-08-31: - Whitellama: - - bugfix: Matches and candles can be used to burn papers, too. - - bugfix: Observers have a bit more time (20 seconds, instead of 7.5) before the - Diona join prompt disappears. -2014-09-05: - RavingManiac: - - experiment: 'NewPipe implemented: Supply and scrubber pipes can be run in parallel - without connecting to each other.' - - rscadd: Supply pipes will only connect to supply pipes, vents and Universal Pipe - Adapters(UPAs). - - rscadd: Scrubber pipes will only connect to scrubber pipes, scrubbers and UPAs. - - rscadd: UPAs will connect to regular, scrubber and supply pipes. -2014-09-20: - HarpyEagle: - - bugfix: Fixes evidence bags and boxes eating each other. Evidence bags now store - items by dragging the bag onto the item to be stored. -2014-09-28: - Gamerofthegame: - - rscadd: Hoverpods fully supported, currently orderable from cargo. Two slots, - three cargo, space flight and a working mech for all other intents and purposes. - - rscadd: Added the Rigged laser and Passenger Compartment equipment. The rigged - laser is a weapon for working exosuits - just a ordinary laser, but with triple - the cool down and rather power inefficient. The passenger compartment allows - other people to board and hitch a ride on the mech - such as in fire rescue - or for space flight. - Zuhayr: - - rscadd: Organs can now be removed and transplanted. - - tweak: Brain surgery is now the same as chest surgery regarding the steps leading - up to it. - - tweak: Appendix and kidney now share the groin and removing the first will prevent - appendicitis. - - tweak: Lots of backend surgery/organ stuff, see the PR if you need to know. -2014-10-01: - RavingManiac: - - rscadd: Zooming with the sniper rifle now adds a view offset in the direction - you are facing. - - rscadd: Added binoculars - functionally similar to sniper scope. Adminspawn-only - for now. - - rscadd: Bottles from chemistry now, like beakers, use chemical overlays instead - of fixed sprites. - - rscadd: Being in space while not magbooted to something will cause your sprite - to bob up and down. - Zuhayr: - - rscadd: Added species organ checks to several areas (phoron burn, welder burn, - appendicitis, vox cortical stacks, flashes). - - rscadd: Added VV option to add or remove organs. - - rscadd: Added simple bioprinter (adminspawn). - - rscadd: Added smashing/slashing behavior from xenos to some unarmed attacks. - - rscadd: Added some new state icons for diona nymphs. - - rscadd: Added borer husk functionality (cortical borers can turn dead humans into - zombies). - - rscadd: Added tackle verb. - - rscadd: Added NO_SLIP. - - rscadd: Added species-specific orans to Dionaea, new Xenomorphs and vox. - - rscadd: Added colour and species to blood data. - - rscadd: Added lethal consequences to missing your heart. - - rscdel: Removed robot_talk_understand and alien_talk_understand. - - rscdel: Removed attack_alien() and several flavours of is_alien() procs. - - rscdel: Removed /mob/living/carbon/alien/humanoid. - - rscdel: Removed alien_hud(). - - rscdel: Removed IS_SLOW, NEEDS_LIGHT and RAD_ABSORB. - - rscdel: Renamed is_larva() to is_alien(). - - tweak: Refactored a ton of files, either condensing or expanding them, or moving - them to new directories. - - tweak: Refactored some attack vars from simple_animal to mob/living level. - - tweak: Refactored internal organs to /mob/living/carbon level. - - tweak: Refactored rad and light absorbtion to organ level. - - tweak: Refactored brains to /obj/item/organ/brain. - - tweak: Refactored a lot of blood splattering to use blood_splatter() proc. - - tweak: Refactored broadcast languages (changeling and alien hiveminds, drone and - binary chat) to actual languages. - - tweak: Refactored xenomorph abilities to work for humans. - - tweak: Refactored xenomorphs into human species. - - tweak: Rewrote larva_hud() and human_hud(). The latter now takes data from the - species datum. - - tweak: Rewrote diona nymphs as descendents of /mob/living/carbon/alien. - - tweak: Rewrote xenolarva as descendents of /mob/living/carbon/alien. - - tweak: Rewrote /mob/living/carbon/alien. - - tweak: Moved alcohol and toxin processing to the liver. - - tweak: Moved drone light proc to robot level, added integrated_light_power and - local_transmit vars to robots. - - tweak: Moved human brainloss onto the brain organ. - - tweak: Shuffled around and collapsed several redundant procs down to carbon level - (hide, ventcrawl, Bump). - - tweak: Fixed species swaps from NO_BLOOD to those with blood killing the subject - instantly. -2014-11-01: - PsiOmegaDelta: - - bugfix: Adds the last missing step to deconstruct fire alarms. Apply wirecutters. - - rscadd: There's a "new" mining outpost nearby the Research outpost. - - rscadd: Manifest ghosts now have spookier names. - - rscadd: Adds a gas monitor computer for the toxin mixing chamber. - - rscadd: AI can now change the display of individual AI status screens. - - rscadd: More ion laws.. - - rscadd: All turrets have been replaced with portable variants. Potential targets - can be configured on a per turret basis. - - bugfix: Improved crew monitor map positioning. - - rscadd: Can now order plastic, body-, and statis bags from cargo - - rscadd: PDAs now receive newscasts. - - rscadd: (De)constructable emergency shutters. - - rscadd: Borgs can now select to simply state their laws or select a radio channel, - same as the AI. -2014-11-04: - TwistedAkai: - - rscadd: Almost any window which has been fully unsecured can now be dismantled - with a wrench. -2014-11-08: - PsiOmegaDelta: - - rscadd: Service personnel now have their own frequency to communicate over. Use - "say :v". - - rscadd: The AI can now has proper quick access to its private channel. Use "say - :o". - - rscadd: Newscasters supports photo captions. Simply pen one on the attached photo. - - rscadd: Once made visible by a cultist ghosts can toggle visiblity at will. - - rscadd: Detonating cyborgs using the cyborg monitor console now notifies the master - AI, if any. - - rscadd: More machinery, such as APCs, air alarms, etc., now support attaching - signalers to the wires. - - tweak: Random event overhaul. Admins may wish check the verb "Event Manager Panel". -2014-11-22: - Zuhayr: - - rscadd: Added the /obj/item/rig class - back-mounted deployable hardsuits. - - rscadd: Replaced existing hardsuits with 'voidsuits', functionally identical. - - rscdel: Removed the mounted device and helmet/boot procs from voidsuits. - - tweak: Refactored a shit-ton of ninja code into the new rig class. - - wip: This is more than likely going to take a lot of balancing to get into a good - place. -2015-01-09: - Zuhayr: - - tweak: Voice changers no longer use ID cards. They have Toggle and Set Voice verbs - on the actual mask object now. - - rscadd: Readded moonwalking. Alt-dir to face new dir, or Face-Direction verb to - face current dir. -2015-02-04: - RavingManiac: - - rscadd: Holodeck is now bigger and better, with toggleable gravity and a new courtroom - setting - TwistedAkai: - - bugfix: Purple Combs should now be visible and have their proper icon -2015-02-12: - Daranz: - - rscadd: Vending machines now use NanoUI and accept cash. The vendor account can - now be suspended to disable all sales in all machines on station. -2015-02-16: - RavingManiac: - - rscadd: Say hello to the new Thermoelectric Supermatter Engine. Read the operating - manual to get started. -2015-02-18: - PsiOmegaDelta: - - rscadd: Synths now have timestamped radio and chat messages. - - rscadd: New and updated uplink items. - - rscadd: Multiple AIs can now share the same holopad. - - rscadd: The AI now has built-in consoles, accessible from the subsystem tab. -2015-02-24: - Zuhayr: - - experiment: Major changes to the kitchen and hydroponics mechanics. Review the - detailed changelog here, -2015-04-07: - RavingManiac: - - tweak: You can now pay vending machines and EFTPOS scanners without removing your - ID from your PDA or wallet. Clicking on the vending machine with your ID/PDA/wallet/cash - also brings up the menu now instead of attacking the vending machine. -2015-04-18: - PsiOmegaDelta: - - rscadd: Added a changelog editing system that should cause fewer conflicts and - more accurate timestamps. -2015-04-23: - Dennok: - - rscadd: Added an automatic pipelayer. - - rscadd: Added an automatic cablelayer. - PsiOmegaDelta: - - bugfix: Shower curtains no longer lose their default color upon being washed. - - bugfix: Emergency shutters can again be examined, and from the proper distance. - - bugfix: The virus event will now only infect mobs on the station, currently controlled - by player that has been active in the last 5 minutes. - - bugfix: Laptops now use the proper proc for checking camera status. - - rscadd: Makes it possible to eject PDA cartridges using a verb. - - rscadd: Makes it possible to shake tables with one's bare hands to stop climbers. - - bugfix: Added a mass driver door in disposals to prevent trash from floating out - into space before proper ejection. - - rscadd: Rig/Hardsuit module tab - Less informative than the NanoUI hardsuit interface - but allows quicker access to the various rig modules. - - rscadd: Silicons with the medical augmentation sensors enabled now also see alive/dead - status if sensors are set accordingly. - - rscadd: Emergency shutters opened by silicons are now treated as having been forced - open by a crowbar. - - rscadd: An active AI chassis can now be pushed, just as an empty chassis can be. - - rscadd: The AI can now use the crew monitor console to track crew members with - full sensors enabled. - - rscadd: The AI now has a shortcut to track people holding up messages to cameras. - - rscadd: The AI now has a shortcut to track people sending PDA messages. - - rscadd: Multiple AIs can now share the same holopad. - - rscadd: Admin ghosts can now transfer other ghosts into mobs by drag-clicking. - - rscadd: Ghosts can now toggle seeing darkness and other ghosts separately. - - rscadd: Moving while dead now auto-ghosts you. - - rscadd: 'Two new random events: Space dust and gravitation failure.' - - rscadd: Upgraded wizard spell interface and new spells. - - rscadd: More uplink items. - - rscadd: Uplink items now have rudimentary descriptions. - Yoshax: - - tweak: Adjusts fruits and other stuff to have a minmum of 10 units of juice and - stuff. -2015-04-24: - Dennok: - - bugfix: Fixes overmap ship speed calculations. - - rscadd: Adds overmap ship rotation. - - rscadd: Added a floorlayer. -2015-04-28: - Jarcolr: - - rscadd: Added 9 new bar sign designs/sprites. - Kelenius: - - rscadd: 'Good news to the roboticists! The long waited firmware update for the - bots has arrived. You can expect the following changes:' - - rscadd: Medbots have improved the disease detection algorithms. - - rscadd: Floorbot firmware has been bugtested. In particular, they will no longer - get stuck near the windows, hopelessly trying to fix the floor under the glass. - - rscadd: Floorbots have also received an internal low-power metal synthesizer. - They will use it to make their own tiles. Slowly. - - rscadd: Following the complains from humanitarian organizations regarding securitron - brutality, stength of their stunners has been toned down. They will also politely - demand that you get on the floor before arresting you. Except for the taser-mounted - guys, they will still tase you down. - - rscadd: Other minor fixes. - - rscdel: 'The lasertag bots are now forbidden to build and use following the incident - #1526672. Please don''t let it happen again.' - - rscadd: The farmbot design has been finished! Made from a watertank, robot arm, - plant analyzer, bucket, minihoe and a proximity sensor, these small (not really) - bots will be a useful companion to any gardener and/or xenobotanist. - - tweak: 'Spider learning alert: they have learned to recognize the bots and will - mercilessly attack them.' - - rscadd: An experimental CPU upgrade would theoretically allow any of the bots - to function with the same intelligence capacity as the maintenance drones. We - still have no idea what causes it to boot up. Science! - - rscadd: 'INCOMING TRANSMISSION: Greetings to agents, pirates, operatives, and - anyone who otherwise uses our equipment. Following the NT update of bot firmware, - we have updated the cryptographic sequencer''s hacking routines as well. The - medbots you emag will not poison you anymore, the clanbots won''t clean after - themselves immediately, and floorbots... wear a space suit. Oh, and it works - on the new farmbots, too.' - PsiOmegaDelta: - - rscadd: Beware. Airlocks can now crush more things than just mobs. - - rscadd: AIs now have a personal atmospherics control subsystem. - - rscadd: Some borg modules now have additional subsystems. - - tweak: Improves borg module handling. - - tweak: Secure airlocks now buzz when access is denied. - - tweak: The mental health office door now requires psychiatrist access, and the - related button now opens/closes the door instead of bolting. - - soundadd: Restores an old soundtrack 'Thunderdome.ogg'. - - rscadd: Some holodeck programs now have custom ambience tracks. - RavingManiac: - - rscadd: The phoron research lab has been renovated to include a heat-exchange - system, a gas mixer/filter and a waste gas disposal pump. - - tweak: Candles now burn for about 30 mintutes. - Yoshax: - - tweak: Adds items to the orderable antag surgical kit so its actually useful for - surgery. - - tweak: Adjusts custom loadout costs to be more standardised and balances. Purely - cosmetic items, shoes, hats, and all things that do not provide a straight advtange - (sterile mask, or pAI, protection from viruses and possible door hacking or - records access, respectively), each cost 1 point, items that provide an advantage - like those just mentioned, or provide armor or storage cost 2 points. - - rscadd: Adds practice rounds, both .45 for Sec and Detective's guns, also 9mm - top mounted for the Saber, and for the Bulldog. - - rscadd: Adds the .45 and 9mm practice rounds to the armory. - - rscadd: Adds all the practice rounds to the autolathe. - - tweak: Adds r_walls to the back of the firing range, leaves the sides normal. - - bugfix: Fixes HoS' office door to not be CMO locked. -2015-04-29: - Daranz: - - rscadd: Paper bundles can now have papers inserted at arbitrary points. This can - be done by clicking the previous/next page links with a sheet of paper in hand. - HarpyEagle: - - rscadd: 'Added new fire modes to various guns: c20r, STS-35, WT-550, Z8, L6 SAW, - and double barreled shotgun. The firing modes work the same way as the egun; - click on the weapon with it in your active hand to cycle between modes. Unloading - these weapons now requires that you click on them with an empty hand.' - PsiOmegaDelta: - - rscadd: Portable atmospheric pumps and scrubbers now use NanoUI. - - rscadd: Two new events which will cause damage to APCs or cameras when triggered. -2015-04-30: - Yoshax: - - rscadd: Adds more items to custom loadout, including a number of dressy suits - and some other things. -2015-05-02: - HarpyEagle: - - bugfix: Neck-grabbing someone now stuns them properly. - PsiOmegaDelta: - - tweak: The spider infestation event now makes an announcement much sooner. - - rscadd: Admins can now toggle OOC/LOOC separately. - - tweak: Mice are now numbered to aid admins. - Yoshax: - - rscadd: Adds an option and verb to the AI to send emergency messages to Central, - functions same as comms console option. - - tweak: Changes comms console to only have one level of ID require, meaning all - heads of staff have what was captain access, allowing them to change alert, - send emergency messages and make announcements. - - rscadd: Adds an emergency bluespace relay machine which is mapped into teletcomms, - this machine takes emergency messages and sends them to central, if one does - not exist on any Z, you cannot send any emergency messages. - - rscadd: Adds an emergency bluespace relay assembly kit orderable from cargo for - when the ones on telecomms are destroyed. Assembly is required. - - rscadd: Adds the emergency bluespace relay circuitboard to be researchable and - printable in R&D, with sufficient tech levels. -2015-05-05: - PsiOmegaDelta: - - tweak: Grilles no longer return too many rods when destroyed (using means other - than wirecutters). - RavingManiac: - - tweak: Intent menu now appears while zooming with a sniper rifle. -2015-05-06: - PsiOmegaDelta: - - rscadd: Examining a pen or crayon now lists the available special commands in - the examine tab. -2015-05-07: - HarpyEagle: - - rscadd: Breaking out of lockers now has sound and animation. - PsiOmegaDelta: - - bugfix: The cloning computer can again successfully locate nearby cloning vats - and DNA scanners at round start. - - rscadd: Security equipment now treats individuals with CentCom ids with the greatest - respect. - - maptweak: Adds stretches of power cable around the construction outpost, ensuring - one does not have to climb over machines to being laying cables. - RavingManiac: - - rscadd: Muzzle-flash lighting effect for guns - - rscadd: Energy guns now display shots remaining on examine -2015-05-09: - Yoshax: - - rscadd: Maps in the top mounted 9mm practice rounds, .45 practice rounds, and - practice shotgun shells into the armory. -2015-05-10: - GinjaNinja32: - - rscadd: Acting jobs on the manifest will now sort with their non-acting counterparts. - All assignments beginning with the word 'acting', 'temporary', or 'interim' - will do this. - Yoshax: - - tweak: Removes sleepy chems from being cloned, adds a consistent period of 30 - tick sleep. -2015-05-11: - Mloc: - - experiment: Rewritten lighting system. - - rscadd: Better coloured lights. - - rscadd: Animated transitions. - PsiOmegaDelta: - - bugfix: As an observer, using antagHUD should now always restrict you from respawning - without admin intervention. - Techhead: - - rscadd: Voidsuits can have tanks inserted into the storage slot. - - rscadd: Voidsuits display helpful information on their contents on examine. - - rscadd: Magboots can be equipped over other shoes. Except other magboots. -2015-05-12: - Dennok: - - imageadd: New buildmode icons made by BartNixon. - HarpyEagle: - - rscadd: Masks and helmets that cover the face block feeding food, drinks, and - pills. - MrSnapwalk: - - imageadd: Added seven new AI core displays. - - tweak: Changed the pAI sprite and added several new expressions. - PsiOmegaDelta: - - rscadd: The space vine event now comes with a station announcement. -2015-05-14: - PsiOmegaDelta: - - maptweak: Should now be more evident that the brig disposal chute sends its goods - to the common brig area. - - bugfix: Cells now drain when using more charge than what is available. - - tweak: The rig stealth module now requires as much power to run as the energy - blade module. - Techhead: - - rscadd: Vox will spawn with emergency nitrogen tanks in their survival boxes. - - rscadd: Diona will spawn with an emergency flare instead of a survival box. - - rscdel: Engineers no longer spawn with extended-capacity oxygen tanks. - - bugfix: Vox spawning without backpacks will have their nitrogen tank equipped - to their back. - - tweak: The Bartender's spare beanbag shells have been moved into bar backroom - with the shotgun. - - bugfix: Portable air pumps now fill based on external/airtank pressure when pumping - in. -2015-05-16: - GinjaNinja32: - - rscadd: Rewrote tables. To construct a table, use steel to make a table frame, - then plate the frame with a material such as steel, gold, wood, etc. Hold a - stack in your hand and drag it to the table to reinforce it. To deconstruct - a table, use a screwdriver to remove the reinforcements (if present), then a - wrench to remove the plating, and a wrench again to dismantle the frame. Use - a welder to repair any damage. Use a carpet tile on a table to add felt, and - a crowbar to remove it. - HarpyEagle: - - rscadd: Adds tail animations for tajaran and unathi. Animations are controlled - using emotes. -2015-05-17: - PsiOmegaDelta: - - bugfix: Teleporter artifacts should no longer teleport mobs inside objects. -2015-05-18: - Hubblenaut: - - rscadd: Adds a light for available backup power on airlocks. - Kelenius: - - tweak: 'There has been a big update to the reagent system. A full-ish changelog - can be found here: http://pastebin.com/imHXTRHz. In particular:' - - tweak: Reagents now differentiate between being ingested (food, pills, smoke), - injected (syringes, IV drips), and put on the skin (sprays, beaker splashing). - - tweak: Injecting food and drinks will cause bad effects. - - tweak: Healing reagents, generally speaking, have stronger effects when injected. - - tweak: Toxins now work slower and deal more damage. Seek medical help! - - tweak: Alcohol robustness has been lowered. - - tweak: Acid will no longer melt large numbers of items at once. - - tweak: Synaptizine is no longer hilariously deadly. - Loganbacca: - - tweak: Changed MULE destination selection to be list based. - PsiOmegaDelta: - - tweak: Destroying a camera by brute force now has a chance to break the wiring - within. - - rscadd: Turf are now processed. This, for example, causes radioactive walls to - regularly irradiate nearby mobs. - - bugfix: Welders should now always update their icon and inhand states properly. -2015-05-22: - Ccomp5950: - - bugfix: Beepsky no longer kills goats. - - tweak: Goats will move towards vines that are 4 spaces away now instead of 1 - - bugfix: Goats will eat the spawning plants for vines as well as the vines themselves. - Chinsky: - - rscadd: Ghetto diagnosis. Grab patient, aim at bodypart you want to check, click - on them with help intent. This will tell you about their wounds, fractures and - other oddities (toxins/oxygen) for that bodypart. - - rscadd: Fractures are visible on very damaged limbs. Dislocations are always visible. - Surgery incisions now visible too. - - rscadd: Stethoscopes actually make sense now. They care for heart/lungs status - when reporting pulse and respiration now. - HarpyEagle: - - rscadd: Re-implemented fuel fires. Tweaked fire behaviour overall. - Yoshax: - - tweak: Bear traps now do damage when stood on, enough to break bones! Bear traps - can now affect any limb of a person who is on the ground, including head! Bear - traps are no longer legcuffs and instead embed in the limb they attack. - - tweak: Bear traps now take several seconds to deploy and cannot be picked up when - armed, they must be disarmed by clicking on them. They also cannot be moved - then they are deployed. - Zuhayr: - - rscadd: Massive material refactor. Walls, beds, chairs, stools, tables, ashtrays, - knives, baseball bats, axes, simple doors, barricades, so on. - - rscadd: Tables are now built via steel then another sheet on the resulting frame. - They can then be reinforced by dragging a stack of sheets onto the table. - - rscadd: Walls are built with steel for girders, then right-click the girder and - select the reinforce verb while holding a stack, then click the girders with - a final sheet. - - rscadd: Various things can be built with various sheet types. Experiment! Just - keep in mind that uranium is now radioactive and phoron is now flammable. -2015-05-26: - Atlantis: - - rscadd: NanoUI for Robotics Control Console - - rscadd: NanoUI for Supermatter Crystal - AI/Robot only, purely informational - Chinsky: - - rscadd: Meat limbs now can be attached. Use limb on missing area, then hemostat - to finalize it. - - rscadd: Limbs from other races can be now attached. They'll cause rejection, but - it can be kept at bay with spaceacilline to some point. Species special attack - is carried over too, i.e. you can clawn people if you sew a cathand to yourself. - - rscadd: Limbs that are left in open will rot in ~7 minutes. Use freezers or cryobags - to stop it. You can still attach them, but you wish you couldn't. - PsiOmegaDelta: - - tweak: Both the pulse taker and target must now remain still for the duration - of the check or it will fail. - RavingManiac: - - rscadd: Tape recorders now record hearable emotes and action messages (e.g. gunshots). - - bugfix: You can now see actions from inside mechs and closets. - Techhead: - - rscadd: Removed gaseous reagents from the chemistry system and replaced with real-world - organic chemistry precursors. - - rscadd: Hydrogen has been replaced with hydrazine, a highly toxic, flammable liquid. - - rscadd: Oxygen has been replaced with acetone, a mildly toxic liquid. Ethanol's - ink-sovlent capabilities have been copied to it. - - rscadd: Chlorine has been replaced with hydrochloric acid. It is a stronger acid - than sulphuric but less toxic. - - tweak: Nitrogen has been replaced with ammonia. Ammonia now acts as a Dexalin-equivalent - for Vox. - - tweak: Flourine has also been replaced with hydrazine in its one recipe. Flourosurficant - has been renamed azosurficant. - - tweak: Being splashed with liquid Phoron will burn eyes and contaminate clothes - like being exposed to Phoron gas. - Zuhayr: - - rscadd: Added a ghost requisition system for posibrains and living plants. - - rscadd: Added attack_ghost() to hydro trays and posibrains to allow ghosts to - enter them. - - rscadd: Prosthetic limbs are now only repairable with welders/cable coils if they - have suffered below 30 combined damage. - - rscadd: 'Surgery steps that cause no pain and have no failure wounding have been - added: screwdriver for ''incision'', crowbar to open, multitool to ''decouple'' - a prosthetic organ. Hemostat is still used to take an organ out.' - - rscadd: Using a welder or a cable coil as a surgical tool after opening a maintenance - hatch will repair damage beyond the 30 damage cap. In other words, severe damage - to robolimbs requires expert repair from someone else. - - rscdel: Eye and brain surgery were removed; they predate the current organ system - and are redundant. - - rscadd: IPC are now simply full prosthetic bodies using a specific manufacturer - (Morpheus Cyberkinetics). - - rscadd: IPC can 'recharge' in a cyborg station to regain nutriment. They no longer - interface with APCs. - - rscadd: NO_BLOOD flag now bypasses ingested and blood reagent processing. - - rscadd: NO_SCAN now bypasses mutagen reagent effects. - - rscadd: Cyborg analyzers now show damage to prosthetic limbs and organs on humans. - - tweak: Prosthetic EMP damage was reduced. - - tweak: Several organ files were split up/moved around. -2015-05-27: - PsiOmegaDelta: - - tweak: The inactive check process now respects client holder status and can be - configured how long clients may remain inactive before being kicked. - Zuhayr: - - rscadd: Unfolded pAIs can now be scooped up and worn as hats. - - tweak: Scoop-up behavior is now standardized to selecting help intent and dragging - their icon onto yours. -2015-05-30: - Atlantis: - - rscadd: Malfunction Overhaul - Whole gamemode was completely reworked from scratch. - Most old abilities have been removed and quite a lot of new abilities was added. - AI also has to hack APCs to unlock higher tier abilities faster, instead of - having access to them from the round start. Most forced things, such as, shuttle - recalling were removed and are instead controlled by the AI. Code is fully modular - allowing for future modifications. - HarpyEagle: - - bugfix: Fixes Engineer ERT gloves not being insulated. - - tweak: IV stands are no longer bullet shields. They also allow mice, drones, pAIs - et al to pass though. - Kelenius: - - tweak: AI now hears LOOC both around its eye and its core, and speaks in LOOC - around its eye. Keep in mind that you won't hear and won't be heard if there - is a wall between your eye and the target. - PsiOmegaDelta: - - rscadd: You can now review the server revision date and hash by using the 'Show - Server Revision' verb in the OOC category. -2015-06-02: - Techhead: - - rscadd: Re-adds extended capacity emergency oxygen tanks to relevant jobs. -2015-06-04: - PsiOmegaDelta: - - rscadd: AI eyes can now be found in the observer follow list. - - rscadd: Synths can now review all law modules that can be found on the station - from their law manager. - - rscadd: Synths can state these laws if desired, however this is strongly discouraged - unless subverted/malfunctioning. - - bugfix: Astral projecting mobs, such as wizards or cultists, may no longer respawn - as something else while their body lives. - Techhead: - - rscadd: Prison break event has been expanded to include Virology or Xenobiology - - rscadd: Prison break event will warn Enginering and the AI beforehand so they - can take preventive measures. - - bugfix: Disabling area power will now prevent doors from opening during the event -2015-06-05: - PsiOmegaDelta: - - bugfix: Split stacks no longer lose their coloring. - - tweak: Can no longer merge cables of different colors. - - tweak: Blobs and simple mobs now attack all external organs instead of a subset. - The overall damage remains the same but the number of fractures caused will, - in general, be fewer. - - rscadd: Spider nurses now have a chance of injecting their victims with spider - eggs which eventually hatch. If the limb is removed from the host, the host - dies, or the spiderling has matured sufficiently it will crawl out into freedom. - Medical scanners will pick upp eggs and spiderlings as foreign bodies. - Yoshax: - - tweak: Makes hyposprays start empty instead of filled with Tricord. - - tweak: Makes the special wizard projectile staffs, Animate, Change, Focus and - any future ones only usable by wizards. Also makes it so only wizards can use - spellbooks and teleportation scrolls. -2015-06-08: - PsiOmegaDelta: - - rscadd: The AI chassis now glows, with the color depending on the currently selected - display. -2015-06-09: - PsiOmegaDelta: - - rscadd: Ports /tg/'s meteor event. Meteors now appear to be more accurate, come - in a greater variety, and may drop ores on their final destruction. -2015-06-16: - Chinsky: - - rscadd: 'Updated penlights to be more of use in diagnostics, they now show following - conditions:' - - rscadd: Eye damage - - rscadd: Blurry eyes (overall slower reaction) - - rscadd: Brain damage (one eye reacts slower) - - rscadd: Opiates use (pinpoint pupils) - - rscadd: Drugs use (dilated pupils) - PsiOmegaDelta: - - rscadd: Observers can now follow both the AI and its eye upon speech. - - rscadd: Observers can now follow both observers and their body, if they ever had - one, upon speech. - - rscadd: Observers can now follow hivemind speakers if the speaker is not using - an alias or antagHUD is enabled. - - rscadd: Turret controls now glow, with the color depending on the current mode. - Techhead: - - rscadd: Converted Request Console interface into NanoUI. -2015-06-19: - HarpyEagle: - - bugfix: Prevents being on fire from merely warming mobs up slightly in some cases. - Mob fires also burn hotter. - - rscadd: Matches can now be used to light things adjacent to you when thrown. - - tweak: Made the effects of having a damaged robotic leg more prominent. - - bugfix: Robot limbs no longer cause pain messages. A reminder that you can still - check their status with 'Help Intent' -> 'Click Self'. - - tweak: Knifing damage scales with weapon force and throat protection. Helmets - only provide throat protection if they are air tight. Trying to cut someone's - throat with wirecutters and/or while wearing an armoured sealed helmet will - require several attempts before the victim passes out. - - tweak: Knifing switches on harm intent, in case you just wanted to beat on the - victim for some reason. - - bugfix: Prevents knifing bots or silicons. -2015-06-22: - PsiOmegaDelta: - - tweak: The traitor uplink no longer displays all items in a long list, instead - has categories which when accessed shows the relevant items. -2015-06-24: - HarpyEagle: - - bugfix: Fixed Tajaran name generation producing names without a space between - first and last. - - wip: Adds docking to the mercenary shuttle. Works similarly to other shuttles, - except docking and undocking is manually initiated and not automatic. A system - to approve or deny dock requests still to be implemented. - - rscadd: Toolboxes can now hold larger items, such as stacks of metal or power - cells, at the cost of having less space for other things. - - tweak: Gloves/shoes can now be worn even if you have one hand/foot missing. The - other one still has to be present, of course. The items still drop when you - first lose the hand/foot. - - tweak: Budget insulated gloves are somewhat less useless. On average, they will - stop half the damage from getting shocked, and the worst case insulation is - not as bad as it used to be. Budget gloves that are as good as regular insulated - gloves are still as rare as they were before though. - - tweak: PTR bullets are now hitscan, to make them somewhat better for actual sniping. - - maptweak: The telecoms server room now has an actual cycling airlock into it. - - tweak: Non-vital body parts will no longer take further damage above a certain - amount, and will inflict paincrit effects instead. On most humaniods the head, - chest, and groin are vital. - - rscadd: 'Engineers now spawn with industrial workboots (credit: ChessPiece/Bishop).' - - bugfix: Damaged robotic legs now more likely to have an effect. - - bugfix: Fixed bug preventing internal organs from taking damage in some cases. - - maptweak: New flavours of tables around the station. Engineering starts with more - plastic. - - bugfix: Fixed worn items not appearing in some cases. Most notably crossbows and - certain guns when worn on the back. As a side effect, laundry machines no longer - transform items. - - bugfix: Crit oxyloss now runs in game time instead of real time. So if lag is - slowing your movement the same slowdown applies to the dying person you're trying - to reach. - - rscadd: Breathmasks can now be adjusted by clicking on them in your hand, in addition - to the verb. - - rscadd: Wearing a space helmet or similar face-covering gear now prevents eating - and force-feeding food, drink, and pills. - - rscadd: Phoron in air ignites above it's flashpoint temperature and a certain - (very small) minimum concentration. Environments that have oxygen and are hot - enough, and have phoron but not enough concentration to burn will produce flareouts, - which are mostly a visual effect. - - rscadd: Adds animation when making unarmed attacks or attacking with melee weapons, - to help make it clearer who is attacking. - - soundadd: Opening an unpowered door now has an appropriate sound. - - rscadd: Ingesting diseased blood may contract the disease. -2015-06-26: {} -2015-06-30: - PsiOmegaDelta: - - maptweak: Non-general areas on Crescent are now protected by blast doors to enforce - area restrictions. Admins can operate these from the central checkpoint. -2015-07-04: - PsiOmegaDelta: - - tweak: Portable turrets now only blocks movement while deployed. - - tweak: Portable turrets are no longer invincible while undeployed, however they - have increased damage resistance in this state. - - bugfix: Crescent portable turrets should no longer act up during attempts to (un)wrench - and alter their settings. -2015-07-06: - GinjaNinja32: - - rscadd: '''Provisional'' is now also a valid temporary position prefix for manifest - sorting.' -2015-07-10: - Zuhayr: - - rscadd: Ninja now spawns on a little pod on Z2 and can teleport to the main level. -2015-07-11: - HarpyEagle: - - imageadd: Added inhand sprites for flashes, flashbangs, emp and other grenades. - Loganbacca: - - bugfix: Turrets no longer burn holes through the AI. - - tweak: Projectiles now have a chance of hitting mobs riding cargo trains. - - bugfix: Fixed visual bugs with projectile effects. -2015-07-14: - HarpyEagle: - - bugfix: Fixes wrong information being reported when analyzing locked abandoned - crates with a multitool. - PsiOmegaDelta: - - tweak: Ninjas can no longer teleport unto turfs that contain solid objects. - - tweak: Wizards can no longer etheral jaunt unto turfs that contain solid objects. -2015-07-27: - Kelenius: - - tweak: Borg shaker now works similarly to hypospray. It generates reagents that - can be poured into glasses. - - bugfix: Therefore, they can no longer duplicate rare reagents such as phoron. -2015-07-29: - Karolis2011: - - rscadd: Made tagger and sorting pipes dispensible. - - bugfix: Unwelding and welding sorting/tagger pipes, no longer delete data about - them. -2015-07-31: - HarpyEagle: - - bugfix: Fixed projectiles being able to hit people in body parts that they don't - have. This will also mean that the less limbs someone has the less effective - they will be as a body shield. -2015-08-11: - PsiOmegaDelta: - - experiment: 0.1.19 is live. - - tweak: Crew monitors now update every 5th second instead of every other. Reduces - lag and gives antags a larger window of opportunity to disable suit sensors - if they have to harm someone. -2015-08-13: - GinjaNinja32: - - rscadd: Changed language selection to allow multiple language selections, changed - humans/unathi/tajarans/skrell to not automatically gain their racial language, - instead adding it to the selectable languages for that species. Old slots will - warn when loaded that the languages may not be what you expect. - Orelbon: - - rscadd: Changed the HoP's suit to more bibrant colors and hopefully you will like - it. -2015-08-14: - HarpyEagle: - - spellcheck: Renames many guns to follow a consistent naming style. Updated and - changed gun description text to be more lore-friendly. - - rscadd: Throwing a booze bottle at something nearby while on harm intent causes - it to smash, splashing it's contents over whatever it hits. - - rscadd: Rags can now be wrung out over a container or the floor, emptying it's - contents into the container or splashing them on the floor. - - rscadd: Rags can now be soaked using the large water and fuel tanks instead of - just beakers. - - rscadd: Rags soaked in welding fuel can be lit on fire. - - rscadd: Rags can now be stuffed into booze bottles. When the bottle smashes, the - stuffed rag is dropped onto the ground. - - bugfix: Fixed eggs having a ridiculously large chemical volume. - - rscadd: T-Ray scanner effects are now only visible to the person holding the scanner. - - rscadd: Traitors can now purchase the C-20r and the STS-35 for telecrystals. - PsiOmegaDelta: - - tweak: The amount you start with in your station account is now affected by species, - rank, and NT's stance towards you. - TheWelp: - - rscadd: Bookcases are now movable/buildable/destroyable. - - rscadd: Paper can now be crumpled by using in-hand while on hurt intent. - - rscadd: Library Computer External Archive is now sortable. - Zuhayr: - - rscadd: Click a hat on a drone with help intent to equip it. Drag the drone onto - yourself with grab intent to remove it. -2015-08-15: - Kelenius: - - rscadd: Bees have been updated and are totally worth checking out (beekeeping - crate at cargo). - - rscdel: Sleeper consoles removed. All interaction is now done by clicking on the - sleeper itself. - - tweak: To put people into sleeper, you now have to click-drag people to it. Grabs - no longer work. To exit the sleeper, move. - - tweak: Sleeper now uses a NanoUI. -2015-08-16: - HarpyEagle: - - tweak: The unathi breacher is now only wearable by unathi. -2015-08-17: - PsiOmegaDelta: - - rscadd: Station time and duration now available in the Status tab. -2015-08-24: - HarpyEagle: - - tweak: Girders are now reinforced by using a screwdriver on the girder before - applying the material sheets. Use a screwdriver again instead to cancel reinforcing. - - bugfix: Mechanical traps no longer spawn in the janitor's locker. - - rscadd: Mechanical traps can now be printed with a hacked autolathe. - - rscadd: Adds armour penetration mechanic for projectiles and melee weapons. - - rscadd: Laser carbines, LWAP, and shotgun now have a small amount of armour penetration, - ballistic rifles (not SMGs) have moderate amounts, laser cannon has high armour - penetration, and the PTR mostly ignores body armour. - - tweak: 'Shotgun slugs and Z8/STS damage has been lowered slightly to accomodate - for their higher penetration. In general ballistics deal less damage but have - higher penetration than comparable laser weapons. Notable exception: X-Ray lasers - have had their damage lowered slightly but gain very high armour penetration.' - - rscadd: Energy swords now have very high armour penetration. Ninja blades do less - damage but ignore armour completely. - Kelenius: - - experiment: Click cooldowns have been removed on pretty much everything that isn't - an attack. - PsiOmegaDelta: - - rscadd: Adds the option to set the icon size to 48x48, found under the Icons menu, - along with 32x32, 64x64, and stretch to fit. - - tweak: Active AI cores now provides coverage on the AI camera network. Does not - utilize actual cameras, thus will not show up on security consoles. - - rscadd: The Dinnerware vending machine now offer both utensil knives and spoons - without first having to hack them. - - rscadd: Synths now have id cards with access levels which is checked when operating - most station equipment. - - rscadd: Station synthetics still have full station access but can no longer interact - with syndicate equipment, and syndicate borgs now start with only syndicate - access. - - rscadd: Syndicate borgs can copy the access from other cards by utilizing their - own id card module, similar to how syndicate ids work. - - rscadd: When examined up close id cards now offer a more detailed view. - - rscadd: Agent ids now offer much greater customization, allowing changing name, - age, DNA, toggling of AI tracking termination (using the electronic warfware - option), and more. - - rscadd: As AI tracking can now be enabled/disabled at will AI players should not - feel the need to hesitate before informing relevant crew members when camera - tracking is explicitly terminated. - - rscadd: Uplink menu now more organized and with new categories. - - rscadd: Now possible to cause falsified ion storm announcements. - - rscadd: Now possible to cause falsified radiation storm announcements, with expected - maintenance access changes. - - rscadd: Now possible for mercenaries to create falsified Central Command Update - messages. - - rscadd: Now possible for mercenaries to create falsified crew arrival messages - and records. - RavingManiac: - - tweak: Sound environments tweaked to feel more claustrophobic - - rscadd: Being drugged, hallucinating, dizzy, or in low-pressure or vacuum will - alter sounds you hear - - rscadd: Sound environment in holodeck will change to reflect the loaded program - Vivalas: - - rscadd: A new uplink item has been added! A briefcase full 'o thalla can now be - bought by traitors for bribes and such! - Zuhayr: - - rscadd: Pariahs are now a subspecies of Vox with less atmos/cold protection, a - useless brain, and lower health. - - rscadd: Leap now only gives a passive grab and has a shorter range. It also stuns - Pariahs longer than it does their target. - - tweak: Rewrote tiling. White floors, dark floors and freezer floors now have associated - tiles. - - tweak: Changed how decals work in the mapper. floor_decal is now used instead - of an icon in floors.dmi. - - tweak: The floor painter has been rewritten to use decals. Click it in-hand to - set direction and decal. - - tweak: Floor lights are now built from the autholathe, secured with a screwdriver, - activated by clicking them with an empty hand, and repaired with a welding torch. - - rscadd: Unathi now have minor slowdown and 20% brute resist. - - rscadd: Tajarans now have lower bonus speed and a flat 15% malus to brute and - burn. - - rscadd: Vox can now eat monkeys and small animals. - - rscadd: Tajarans can now eat small animals. - - rscadd: Unarmed attack damage has been lowered across the board. -2015-09-02: - Atlantis: - - rscadd: Converted phoron glass to borosilicate glass, adjusted heat resistances - accordingly, got rid of copypaste fire code. Fire resistance is now handled - by variables so completely fireproof windows are possible with varedit. - - rscadd: Windows take fire damage when heat exceeds 100C regular windows, 750C - reinforced regular, 2000C borosilicate and 4000C reinforced borosilicate. For - comparsions, reinforced walls begin taking damage around 6000. - Hubblenaut: - - rscadd: Adds glass bottles for Cola, Space Up and Space Mountain Wind to Booze-O-Mat. - - tweak: Some bar drink recipes have been amended to easily sum to 30 units for - drinking glasses. - - tweak: Vendors now have a product receptor for accepting goods. Opening the maintenance - painel is no longer required. - - tweak: Wrenching a vending machine is no longer a silent action. - - tweak: 'Stepup: Item placement on 4x4 grids seemed to work great. Now we''ll try - 8x8.' - Kelenius: - - tweak: Mechfab can now be upgraded using RPED, and now uses NanoUI. - Matthew951: - - rscadd: Added Vincent Volaju's hair. - - rscadd: Added Vincent Volaju's beard. - Zuhayr: - - rscadd: Added the ability for AIs in hardsuits to control suit modules and movement - with a dead or unconcious wearer. - - rscadd: Added ballistic supply drop pods. - - rscadd: Added diona gestalt random map template. - - tweak: Swapped the singularity beacon out for a hacked supply beacon. -2015-09-05: - Chinsky: - - rscadd: Made capguns into proper guns code-wise. It means you can now take people - hostage with them, stick in your mouth, and all other things you can do with - real guns but probably shouldn't. - - rscadd: Russian roulette! Fun for whole sec team! Unload some shells from revolver, - spin the cylinder(verb) and you're good to go! - HarpyEagle: - - rscadd: Shields no longer block attacks from directly behind the player. - - rscadd: Riot shields no longer stop bullets or beams (except for beanbags and - rubber bullets), however they are now more effective at blocking melee attacks - and thrown objects. - - rscadd: Energy shields block melee attacks as effectively as riot shields do. - Their ability to block projectiles is largely unchanged. - - tweak: Melee weapons now only block melee attacks. - - experiment: Two handed weapons have a small chance of blocking melee attacks when - wielded in two hands. - - rscadd: Sound and visual effects when blocking attacks with an energy shield or - energy sword. - - bugfix: Fixed dead or unconscious people blocking stuff with shields. - PsiOmegaDelta: - - tweak: Cargo now sorts under its own department on station manifests. - - rscdel: Manual radio frequency changes can no longer go outside the standard frequency - span. - - rscadd: Users with sufficient access can instead select pre-defined channels outside - this span, such as department channels, when using intercoms. -2015-09-07: - GinjaNinja32: - - rscadd: Added an auto-hiss system for those who would prefer the game do their - sss or rrr for them. Activate via Toggle Auto-Hiss in the OOC tab. - - rscadd: Auto-hiss system in 'basic' mode will extend 's' for Unathi and 'r' for - Tajara. 'Full' mode adds 'x' to 'ks' for Unathi, and is identical to 'basic' - mode for Tajara. - PsiOmegaDelta: - - tweak: 'Changed the language prefix keys to the following: , # -' - - rscadd: Language prefix keys can be changed in the Character Setup. Changes are - currently not global, but per character. -2015-09-08: - Soadreqm: - - tweak: Increased changeling starting genetic points to 25. - Zuhayr: - - bugfix: Auto-traitor should now be fixed. - - bugfix: The Secret game mode should now be fixed. -2015-09-11: - HarpyEagle: - - tweak: Made flares brighter. - - rscadd: Coffee is now poisonous to tajaran, much like how animal protein is poisonous - to skrell. -2015-09-26: - PsiOmegaDelta: - - tweak: Meteor events now select a map edge to arrive from, with a probability - for each individual wave to come from either neighboring edge. Meteors will - never arrive from opposite the starting edge. -2015-10-10: - HarpyEagle: - - tweak: Rubber bullets and beanbags now are now resisted by melee armour. - - bugfix: Fixed a couple of bugs causing phoron gas fires to burn cooler and slower - than they were supposed to. - - bugfix: Merc bombs are now appropriately explosive again. Same goes for bombs - made by toxins. -2015-10-11: - HarpyEagle: - - tweak: Fabricated power cells start uncharged. - Hubblenaut: - - rscadd: Light replacers can be refilled by clicking on a storage item. - - tweak: Light replacers now hold up to 32 light bulbs. - - tweak: Light replacers can be obtained through janitorial supply crates. - - tweak: A sheet of glass fills the light replacer by 16 bulbs. -2015-10-14: - Hubblenaut: - - bugfix: Airlock backup power test light properly offline when backup power down. - - bugfix: Empty flavor texts no longer draw an empty line on examination. - - bugfix: Material stacks now properly merge upon creation. - - bugfix: Messages for adding to existing stack appear again. - PsiOmegaDelta: - - tweak: Blobs can now spawn anywhere in maintenance, rather than picking location - from a pre-determined list. - TheWelp: - - rscdel: Removed higher Secret player requirements. - Zuhayr: - - rscdel: Removed facehuggers, alien embryos, and embryo removal surgery. - - rscadd: Xenomorph Queens (or infested surgeons...) can now add a hive node to - a victim in order to slave them to the hive. - - tweak: Xenomorph brute/burn mods were tweaked to buff them significantly. - - tweak: Alien larvae now hatch from eggs when ghosts click on them. - - tweak: Alien larvae now gain progression towards adulthood from being inside a - human with blood, which they drink. - - tweak: Alien weeds now use the vine system. -2015-10-21: - Hubblenaut: - - tweak: Bruise packs are now applied per wound, not per limb. - - tweak: Bruise packs now use a delay depending on wound severity for applying. - - rscdel: Removed instant healing ability from advanced bruise packs and ointment. -2015-10-27: - HarpyEagle: - - bugfix: When affected by pepperspray, eye protection now prevents blindness and - face protection now prevents stun, instead of face protection doing both. -2015-11-02: - Hubblenaut: - - rscadd: Adds tape for atmospherics. - - tweak: Tape graphics and algorithm changes. Looks a lot more appealing now. - - tweak: Starting and ending tape on the same turf will connect it to all surrounding - walls/windows. - - tweak: Lifting a part of the tape will lift an entire tape section. - - tweak: Mobs on help intent do stop for tape. - - bugfix: Crumpled tape does not affect tape breaking behavior anymore. -2015-11-10: - Atlantis: - - rscadd: Expanded gridcheck random event. Affected devices now show error UI and - may be restarted manually before the event ends. All Z-levels are now affected - equally. - Datraen: - - tweak: Changes standard and specific plant traits, more diverse plants. - Sligneris: - - tweak: Modified the wording of NT Default's laws. -2015-11-16: - PsiOmegaDelta: - - rscadd: Added new verb, 'Character Setup' under the Preferences tab, to allow - modifying your character settings at any time. -2015-11-19: - PsiOmegaDelta: - - tweak: The round start and auto-antag spawners can now check if players have played - long enough to be eligable for selection. -2015-11-22: - PsiOmegaDelta: - - tweak: Engineering alarm consoles now display camera alerts. - - rscadd: Adds a hacking tool that for all intents and purposes acts and works like - a multitool until a screwdriver is applied. - - rscadd: Gives full control of airlocks after 20-40 seconds of hacking. - - rscadd: The last 6-8 hacked airlocks are always accessed instantly. - neersighted: - - bugfix: Laptop Vendors now accept ID Containers (PDA, Wallet, etc). - - bugfix: Personal Lockers now accept ID Containers (PDA, Wallet, etc). - - experiment: Add /tg/-like attack overlays. -2015-12-06: - Hubblenaut: - - bugfix: Welding a broken camera will use the correct icon. - - tweak: Camera assemblies remember their tag and network from previous usage. - - tweak: Mobs on help intent will not push others that aren't. - Loganbacca: - - rscadd: Added a backend (wireless) system for communication between machinery - and other devices. - Neerti: - - rscadd: The AI can now toggle whether its hologram will move towards the center - of its view using the 'Toggle Hologram Movement' verb. - PsiOmegaDelta: - - tweak: Helmet cameras are no longer enabled by clicking the helmet, instead there - is a 'Toggle Helmet Camera' verb. - Raptor1628: - - tweak: Armory layout changed, weapons returned to static amounts. - - rscadd: New security armor and helmet sprites added. - Zuhayr: - - tweak: 'Backend change: allowed accessories to be placed on any clothing item - with the appropriate variables set.' - - rscadd: Drones can now pull a variety of things (such as scrubbers). This came - with a pulling refactor so please report any strangeness with pulling in general. - - rscadd: Drones (and any mob that can be picked up) can be bashed against airlocks - and such to use their internal access, so long as the person using them does - not have an ID card equipped. - - tweak: Rewrote fireaxe cabinets. Click with a multitool to unlock or loc, click - with a hand to open or close, smash with anything that does damage, and drag - onto your icon to remove the fireaxe. -2015-12-13: - Atlantis: - - rscadd: Added Inflatables Dispenser(ID), an item that allows rapid deployment, - transport and removal of inflatables. - - rscadd: Engineering, Construction and Crisis modules are now outfitted with ID. - - rscadd: Three boxes in engineering have been replaced by three IDs. - - tweak: w_classes of inflatables readjusted. Boxes and IDs can be carried in backpack - now. Individual inflatables are small enough to fit in pocket. - PsiOmegaDelta: - - experiment: Adds a system to allow objects to implement custom multitool interactions - in a modular manner. - - rscadd: The AI can now toggle multitool mode on/off, using the new 'Toggle Multitool - Mode' verb. - - rscadd: Cloning vats can now be connected to a cloning console by using a multitool. - - rscadd: Station alert console circuits can now be altered using a multitool, changing - which alarm types are displayed. - - rscadd: Can now select the color of a cable coil using a multitool. - TheWelp: - - rscadd: Added boardgame item for use with table-top board games. - - rscadd: Added Actors Guild, an alternate spawn that allows players to control - actors. - - rscadd: Added differing card decks, including a Tarot deck and two trading card - games. - - rscadd: Remade /TG/Station's Orion Trail arcade machine with bay-specific modifications. -2015-12-20: - PsiOmegaDelta: - - rscadd: Can now use the Antag Uplink to buy a door hacking device with endless - uses and which leaves doors unharmed, but instead needs some time to do its - work. - Zuhayr: - - tweak: Aiming has been rewritten, keep an eye out for weird behavior. -2016-01-01: - Atlantis: - - rscdel: Removed old computer3 system, most noticeable due to removal of old laptops. - - rscadd: Adds brand new modular computer system that replaces computer3. These - computers may run programs from hard drive, and one device is not limited to - one program. - - rscadd: Modular computers can be assembled manually from components printed at - RnD (Consoles mainly), or purchased (from old laptop vending machines). - - rscadd: Adds NTNet, networking used by modular computers, including an administration - console, NTNet relays, and antag programs. - - rscadd: Adds small set of programs modular computers can run. More programs will - be added in the future. - - rscadd: Various small things added, such as, data crystals (USB flash drives), - NTNRC (messaging, IRC/forum style), file sending, etc. - PsiOmegaDelta: - - tweak: Resomi, and any other humanoid mobs, can now bump doors open despite their - size. - TheWelp: - - rscadd: Microwaves can now be unanchored with a crowbar. -2016-01-08: - Chinsky: - - bugfix: Can pick up monkeys / undress resomi now properly. HELP intent for scooping, - NON-HELP for undressing. - RavingManiac: - - rscadd: Storage in backpacks, boxes and other containers is now capacity-based. - Some containers like belts remain slot-based. -2016-01-13: - Datraen: - - bugfix: Objects can now be yanked out of synthetics. - Techhead: - - rscadd: 'Added a new random event: Shipping Error - A random crate is mistakenly - shipped to the station.' -2016-01-16: - Atlantiscze: - - rscadd: SMES units now try to balance their inputs and outputs. For outputs this - means two SMESes powering the same grid will share the load by percentage. For - inputs, all SMESes inputting from one power network will split the available - power by percentage. - - tweak: 'Some minor SMES configuration changes have been made: Atmospherics SMES - now starts configured to prevent power outages when people forget about it, - engine SMESes are now configured to input/output at full rate. These are only - defaults and may be changed ingame as usual.' - PsiOmegaDelta: - - rscadd: Uplink crystals can now be converted into physical form to allow transfer - between uplink devices. - - rscadd: Each mercenary now spawn with their own private uplink, with each indivual - uplink having the same number of telecrystals as the normal traitor uplink. -2016-01-20: - Atlantis: - - rscdel: Construction robot module removed - - rscadd: Engineering robot module now contains most tools of construction robot, - primarily plasteel. RCD is not included by default. - - rscadd: Engineering Robot RCD upgrade is now buildable. This upgrade unlocks robot's - RCD. It is fairly expensive, requiring small amount of gold and silver, as well - as phoron and steel to build. - - rscadd: Floodlight upgrade added. This upgrade doubles robot's light intensity - (it will be more or less same as actual floodlight), at the cost of higher power - usage. - - rscadd: You may now install matter bin into a cyborg in order to boost it's matter - synth's maximal capacity. Better matter bin adds more capacity - - tweak: Default capacity of matter synths for engineering module tweaked a little, - since prices of reinforced walls, etc. increased recently. Steel changed from - 40 to 60 sheets default, plasteel from 10 (Construction default) to 20. -2016-01-25: - Atlantis: - - tweak: Setup Supermatter admin button now uses map markers and supports all coolant - types. -2016-01-29: - Karolis2011: - - tweak: Improved modular computer performance - PsiOmegaDelta: - - experiment: We now support tg's online changelog auto-creation. See https://tgstation13.org/wiki/Guide_to_Changelogs#Online_auto-creation. - - rscadd: Can now click held mobs, such as Pun Pun, to view their inventory. -2016-02-01: - PsiOmegaDelta: - - bugfix: ED-209s, hostile mobs, and mecha weapons should again be able to fire - without issue. - - bugfix: Agent ids can now be assigned an owner even after having been dropped - on the floor. - - bugfix: Monkey cubes can now be expanded in sinks again. -2016-02-03: - PsiOmegaDelta: - - tweak: Antagonist and special role preferences have been overhauled. Please update - these specific character preferences as they have been reset. -2016-02-06: - PsiOmegaDelta: - - bugfix: Should again be possible to resist out of chairs, beds, and welded lockers. -2016-02-07: - PsiOmegaDelta: - - rscadd: More --fun-- ion laws added. - - rscadd: Showers now splash objects on their turf with water. - - tweak: Can now expand unwrapped monkey cubes using showers, sinks, or just about - any source that applies water. -2016-02-11: - PsiOmegaDelta: - - bugfix: Items dropped by mobs that are held by another mob should no longer be - lost. - - bugfix: Items dropped inside mechs should no longer be lost. - - tweak: Changes the way loadout is handled in the character setup. - - tweak: Can no longer see loadout items restricted to a race you're not whitelisted - for (hence why you may see empty categories). - Zuhayr: - - rscadd: Added functionality for two-handed guns; these guns will give an accuracy - penalty if fired without an empty offhand. - - rscadd: Unified two-handed melee weapons with the above; while the offhand is - empty, the weapon will count as wielded. - atlantiscze: - - rscadd: Players will now be warned when selected spawn point has dangerous atmosphere, - and will be able to abort spawning and spawn elsewhere - - tweak: Supermatter no longer pulls anchored objects. To compensate, pull radius - was increased. It is currently limited by range() proc to approximately 32 tiles. - - tweak: Supermatter delamination's explosion strength reduced slightly. This will - hopefully motivate players to actually attempt repairs as it will be possible - to complete them within 1-2 hours. - - tweak: Supermatter spends more time (30 seconds compared to 10 seconds) in pulling - mode before exploding during delamination. - - rscadd: Supermatter's UI now shows "Relative EER" (Energy Emission Ratio) value - which represents how energised the supermatter is. - chinsky: - - soundadd: Surgery operations now cause sounds. -2016-02-13: - Ccomp5950: - - bugfix: Fixes slimes not hearing people (Kudos Karolis2011) - Karolis2011: - - tweak: Changed Tajarian language name (from Siik'tajr to Siik'maas) - - tweak: Changed Resomi language name (from Resomi to Schechi) - - rscadd: Added Alden-Saraspova counter sprite, making it visable. - PsiOmegaDelta: - - rscadd: Adds a reconnect button to the file menu. - - rscadd: Ghosts can now follow any movable object. -2016-02-15: - Ccomp5950: - - bugfix: Mobs will now have the correct health indicator when they die. X_X - Neerti: - - rscadd: The examination tab now includes additional information about examined - clothing and armor. - - bugfix: EMP no longer hits twice on humans. - - tweak: EMP drains powercells using the cell's current charge, and not the cell's - maximum potential charge, to ensure two blasts do not completely disable a synthetic. - - tweak: EMP hitting a prosthetic limb or organ will now do less damage. - - tweak: EMP hitting a cyborg will no longer outright stun them. Instead, they - gain the 'confused' status for a few moments, making movement difficult. In - addition, their HUD gets staticy, and their modules are forced to be retracted. - - rscadd: Stasis bags will protect the occupant from the outside enviroment's atmosphere. - - rscadd: Stasis bags can be hit with a health analyzer to analyze the occupant. - PsiOmegaDelta: - - rscadd: Sharp objects now have a greater chance of causing bleeding. - - rscadd: Can now pour reagent containers down the sink. - - tweak: Wrapped parcels now take on the size of the wrapped object. - - tweak: Security vests now only protect the torso, arms and other limbs are fair - game. - - tweak: Alters Neerti's EMP changes. - - tweak: Borgs are again stunned by max severity EMPs. - - tweak: Cells now lose a minimum amount of charge based on EMP severity, ensuring - multiple blasts will still be able to drain a cell. - Zuhayr: - - rscadd: Small species now take smaller bites/gulps from food and drink. - - rscadd: Small species are now effected by alchol and toxins twice as much. - - rscadd: blood_volume is now a species-level var and Resomi have lowered blood - volume. - - rscadd: Hunger is a species var and Resomi get hungry faster. - - rscadd: Small mobs have a reduced climb delay. - - rscadd: Resomi gain more nutrition from meat. -2016-02-18: - Daranz: - - bugfix: HUD glitches with the plant bag and cigarette packets are now fixed. - Karolis2011: - - wip: New command and communications program for modular consoles and laptops. -2016-02-22: - Datraen: - - tweak: Fragmentation grenades are no longer launchable. -2016-02-25: - Nalarac: - - rscadd: The autolathe can now print welding goggles. - PsiOmegaDelta: - - spellcheck: Punching a mech should no longer expose you to typos. - Yoshax: - - bugfix: Can again remove linoleum tiles, now with a screwdriver. - - rscadd: Can now order linoleum tiles from cargo. - - bugfix: Tajara should now react appropriately to various chemical reagents, such - as coffee. -2016-02-26: - Crazylemon64: - - rscadd: Allows lighting of smokeables using burning people. - Kelenius: - - imageadd: Additional sprites for the drying racks. - Mark9013100: - - tweak: Evidence bag boxes storage increased. - - bugfix: Fixes the RIG grenade launcher icon. - PsiOmegaDelta: - - spellcheck: Changes instances of 'prothesis' to 'prosthesis'. - Snapshot: - - bugfix: Syndicate hardsuit helmet was invisible for humans when worn - - bugfix: Balances to IPC suit cooler battery usage. -2016-02-29: - MrSnapwalk: - - rscadd: 'Adds five new hairstyles: Short Bangs, Half-Shaved Emo, Long Hair Alt - 2, Bun, and Double-Bun.' - PsiOmegaDelta: - - rscadd: Can now order white, dark, and freezer floor tiles from cargo. -2016-03-01: - PsiOmegaDelta: - - tweak: Player preferences have been overhauled. Please update your preferences, - found at "Character Setup" > "Global" > "Preferences", as they have been reset. - TheWelp: - - bugfix: Board game now properly takes things out of your hand again. - - rscadd: Individual cards now set their name and description so they are no longer - just a playing card. - - rscadd: Adds space pike as a rare carp spawn. Pikes are bigger, meaner, and will - attack anything, including other fish. -2016-03-02: - redstryker: - - rscadd: Adds hijabs as a head and loadout item. -2016-03-04: - Datraen: - - rscadd: Adds a mech-mountable flare launcher. -2016-03-18: - Datraen: - - bugfix: Harmbaton no longer causes halloss while inactive. - Kelenius: - - bugfix: Potassium and nitroglycerin explosive grenades now work. - TheWelp: - - rscadd: Added ability for carbon mobs to taste. Sensitivity varies between species. -2016-03-27: - atlantiscze: - - rscadd: Adds a new "News Browser" modular computer program, that can be used to - download and view news from the NTNet. - - tweak: APCs now react to EMPs in a different way. EMPs will temporarily disable - the APC, in a same way gridcheck does. That allows the APC to be reset using - the button in UI. Duration of EMP timer is based on severity, and a little bit - of RNG (8 - 12 minutes on high strength EMP) - - tweak: APC power cells are now partially shielded from EMPs, resulting in lower - charge loss when the power cell is in APC. -2016-03-28: - Datraen: - - bugfix: Adds a check to prison breaks that makes sure the APC is on before continuing. - atlantiscze: - - rscadd: Cyborgs and the AI now show on the crew manifest. -2016-04-01: - TheWelp: - - rscadd: Off-station antagonists now each set a faction. Primarily used with Resomi - playing merc, heist, etc. - - rscadd: Reworked Wizard to have multiple types of spellbooks, each with their - own costs, artifacts, and unique spells. - - rscadd: Antagonist that wipe equipment now give emergency gear before equipping - anything. Primarily a fix for off-station Vox antags. - - rscadd: Wizard clothing check is now conscious of species slot restrictions. (E.G. - Diona can now cast w/o sandals) - - rscadd: Added a cast verb to the IC tab. Will let people macro spell casting or - quickly cast them via auto-complete. -2016-04-05: - PsiOmegaDelta: - - rscadd: Detectives and forensic personnel now join the station with their own - CSI kit. - - rscadd: The detective's cabinet now contains a CSI kit. - TheWelp: - - tweak: Cast verb now appears/disappears depending on whether you have spells or - not. - - tweak: Corrupt Form now has a longer duration (10 seconds -> 15) - - tweak: Wizard Mark is now a cleanable entity (so soap/space cleaner destroys it) - - tweak: Mark/Recall cooldown halved. (120 seconds -> 60 seconds) - - rscadd: Fixes mind's spell list so that cloning will now properly add all the - spells. You will also keep your spells between bodies. (E.G. You are borged, - you get to keep your spells) - - rscadd: Added verb to antagonists to recieve objectives. Located in the OOC tab - and gained whenever the person becomes an antagonist. - atlantiscze: - - rscadd: Modular computers may now be damaged by gunfire, EMPs and similar threats. - This includes the computer's chassis, and components. - - rscadd: Damaged components may be repaired using nanopaste or cable coil. Damaged - chassis can be repaired with welder. You can use multitool on a component to - get diagnostic report. - - tweak: NTNet speeds increased, with advanced network cards being buffed considerably. - - tweak: Data crystals may now be disconnected without a screwdriver, via the rightclick - menu. - - tweak: You can now load paper into the nano printer, by clicking it (or the computer - it is installed in) with paper pieces. - - tweak: 'Component weights re-adjusted. For now they will have weight depending - on what device are they intended for (tablet+: tiny, laptop+: small, console:normal)' - - tweak: Modular computers now glow when turned on. Tablet has equal light intensity - as PDA, while console is comparable to a light bulb. This light is not colored. -2016-04-06: - Arctic: - - rscadd: Added wall-mounted oxygen pumps which equip internals when used. -2016-04-09: - Kearel: - - tweak: Dough now also requires water to be made. - ParadoxonKomplikon: - - tweak: The exotic seeds crate is now access restricted to xenobiologists. - PsiOmegaDelta: - - rscadd: Bedsheets can now be worn as capes. -2016-04-11: - NullSnapshot: - - rscadd: Players who are active antags can now respond to AOOC. - - rscadd: Mods have been given access to AOOC. -2016-04-14: - Datraen: - - rscadd: Manually ports /tg/station's dark click code https://github.com/tgstation/-tg-station/pull/10272 - by Razharas. - - bugfix: Microwaves no longer try cooking their components while cooking. - HarpyEagle: - - tweak: Fire extinguishers now spray a lot more water, will hopefully put out people - on fire faster. - - tweak: Fire extinguishers now make the ground wet when you use them. - Hubblenaut/HarpyEagle: - - tweak: Confused movement is a little less random. It is now easier to get to where - you want to when confused, especially while walking. - - rscadd: People running into solid objects while confused can be knocked over. - Kearel: - - bugfix: Fixes armalis x shift, again. - - tweak: Adds spellbook descriptions in book of tomes. - - rscadd: Adds ability for bears to dance. The commands dance, boogy and boogie - all work. - - rscadd: Adds ability for commanded mob subtypes to listen to the terms everybody - and everyone. - PsiOmegaDelta: - - rscadd: Can now customize the color of select set of underwear, similar to some - loadout equipment. - - rscdel: Due to new underwear names some selections may have been unset. Double-check - your character setup settings. - TheWelp: - - rscadd: Ports more of TG's slimes. Includes Pyrite, Gold, Cerulean, Bluespace - and Sepia - Yoshax: - - rscadd: Can take filled lunchboxes using the character loadout. These have a food - item, a snack, and a drink, all configurable. - atlantiscze: - - tweak: RIGs driven by AIs inside IIS now use massively less power. In other words, - the AI can walk more than few tiles without fully draining the battery. -2016-04-15: - Datraen: - - rscadd: 'Added Three New Mixed Gamemodes: Lizard, Changeling + Wizard; Intrigue, - Traitors + Ninja; Visitors, Ninja + Wizard.' - - tweak: Created a variable for latespawning antagonist templates, for customization - of autospawning antagonists in mixed game modes. - - tweak: Removed JSON encoding of the PDA Manifest list. - HarpyEagle: - - tweak: Shotgun flare illumination now lasts longer, around 3-4 minutes. - - bugfix: Fixed attack animation playing when using flashes even if the flash was - not actually used due to being broken or recharging. - - bugfix: Fixed lightswitches layering over darkness. Now only the light layers - above shadow. Lightswitch illumination is now much more subtle. - Mark9013100: - - rscadd: Paramedics, Medical Doctors, and the Chief Medical Officer can select - white webbings from the custom loadout. - - rscadd: ' Can now order a wide assortment of job gear from cargo.' - Sabess: - - rscadd: Detectives can now reskin the vintage .45 pistol. -2016-04-17: - mkalash: - - tweak: 'New voting system allows players to chose three options: high, medium, - and low' - - rscadd: Players can set individual antag roles to 'never' and will not be selected - to antag by the game mode - - tweak: Players who do not vote for the game mode, but have not selected never, - are candidates - - rscadd: The game will try the top three voted game modes before forcing extended - without revote -2016-04-18: - HarpyEagle: - - bugfix: Fixes people not going unconscious when they should. - - tweak: Cigarette boxes/cigar cases/candleboxes can now hold any tiny item, such - as pens or dice. - - tweak: Box storage almost doubled, they can now again hold up to 7 small items, - they can no longer hold larger items. - - tweak: Backpack capacity is now 22, dufflebag capacity is now 32. - - bugfix: Dufflebags now properly apply slowdown when worn on the back. As before, - they do not apply slowdown when held in hands. - - imageadd: Fixed missing dufflebag back sprites, ported them from /tg/. - - bugfix: 'Excavation kit can no longer be folded into cardboard. ' - - bugfix: Unathi knife harness can now hold more types of knives. - - tweak: Vials are now tiny items. - PsiOmegaDelta: - - rscadd: Can now prefill the loadout flask and vacuum-flask with a relevant liquid - of your choice. - - tweak: Alters the available selection of genders for different species during - character setup. -2016-04-20: - HarpyEagle: - - bugfix: Examining objects/yourself no longer triggers the gun hostage/aiming system. - Neerti: - - tweak: The toggle to shoot if the target talks on the radio defaults to off. - - bugfix: The aim intent icon now updates when clicked. -2016-04-21: - atlantiscze: - - tweak: Being crushed by door will now push you out of the door, preventing door - crush spam. To compensate, damage caused by door crushing has been increased. -2016-04-23: - Irrationalist: - - bugfix: Fixed clothing (gloves and jumpsuits) hidden from description on examination, - but are still being displayed on character anyway. - PsiOmegaDelta: - - rscadd: The pAI Universal translation module now includes the language of the - Resomi, Schechi. -2016-04-24: - HarpyEagle: - - rscadd: Items can now be positioned on tables by clicking. -2016-04-26: - HarpyEagle: - - bugfix: Rewrote how the floating animation is updated, the animation now correctly - updates when leaving space, activating/deactivating magboots, and buckling/unbuckling. - - bugfix: Examining people in crit now again indicates that they are not breathing. - - bugfix: Fixed spears giving slashing cuts and not puncture wounds. - - bugfix: Fixed wounds not bleeding when they are supposed to. - atlantiscze: - - tweak: Reverts the reduction of backpack capacities introduced few days ago. -2016-04-30: - HarpyEagle: - - rscadd: Mercenaries can now purchase several types of frag grenades for TC. - - rscadd: Mercenaries can now purchase grenade launchers for TC, comes pre-loaded - with random grenades. - - rscadd: Many guns now have an accuracy and dispersion penalty for firing with - only one hand, that roughly corresponds to the size and weight of the gun. You - will see a message upon shooting with a compromised aim. The penalty is also - affected by rapid-fire modes in the case of bullet throwers. To fire two-handed - simply ensure that your other hand is empty and usable when shooting. - - tweak: Laser cannons now slightly increased shot capacity and have increased accuracy - (better for fighting at longer ranges), can no longer fit in backpacks. - - tweak: X-ray laser gun now fires at the same pace as the laser carbine, has the - same shot capacity, but does much more damage against armoured targets, and - is slightly easier to one-hand with. - - tweak: Shotgun flares now blind over a larger area and illuminate for longer. - - tweak: Z8 does slightly less damage, has a larger magazine size, and slightly - more armour piercing. - - bugfix: Shooting a shotgun stun shell now makes the appropriate sound. - PsiOmegaDelta: - - rscadd: Adds a cable painter for recoloring both coils and laid down cables. - - tweak: Pulling items now carries a slowdown penalty, based on weight or size. - atlantiscze: - - tweak: SMESes can now be damaged by gunfire/explosions/emitters, and repaired - by welding tool. SMES that is too damaged will explode with strength dependent - on remaining charge. Damage can be seen by examining the SMES. - - rscdel: Old cell rack PSUs have been removed (and replaced). - - rscadd: New cell rack PSUs have been added. Comes with set of simple sprites (I'm - horrible spriter!), a new nanoUI that shows status of each power cell, and support - for upgrades. Better capacitors increase charging/discharging rate, better matter - bin increases max amount of cells that can be held inside the PSU (3/6/9 cells). - PSUs do not allow precise setting of input/output levels. These new PSUs act - as bridge between power cells and cables, allowing you to charge/discharge the - cells into the grid. - mkalash: - - tweak: Add antagonist vote now works midround - - rscadd: Ghosts can join a pool to be selected for off-station antag roles by add - antag votes - - rscadd: Add antagonist option added to the crew transfer vote -2016-05-04: - Irrationalist: - - bugfix: Mercenary voidsuits no longer hide gloves - - tweak: Rigs now hide masks when sealed - TheWelp: - - tweak: Readds Pariah space resistance. Their health is instead lowered by 15 (80->65) - - bugfix: Pariah stink now respects environment and if the person is a robot. - - rscadd: Pariahs will now vomit uncontrollably on occassion. - - tweak: Budget gloves now fit Vox. - - rscadd: Adds Vox organs. Now are both blue and alien. - - bugfix: Pariah will no longer have superhuman tasting capabilities. - - tweak: Vox hair can now be colored. It could always be colored using the random - button in the character setup and honestly, it isn't lore breaking so I'll let - people choose it themselves. -2016-05-05: - Daranz: - - rscadd: Mice and other small critters can now be eaten from hand. As a member - of species eligible to eat mice, scoop a mouse and click on your character with - the hand holding the mouse. The old method of eating from grab remains available - both for unscoopable and scoopable creatures. -2016-05-06: - HarpyEagle: - - rscadd: Allows AI holograms to change facing by clicking much like other mobs. - - tweak: Armor now has a chance to either block an attack or absorb a fixed portion - of damage, instead of randomly blocking either nothing, half, or full damage. - - tweak: Armor protection against explosions is similarily less random now. - - tweak: Riot, ablative, and ballistic armor is less hyper-specialized. They provide - moderate protection against other damage types now, while their protection against - their main damage type is reduced but still very good. -2016-05-07: - PsiOmegaDelta: - - rscadd: Can now buy the camera MIU from the 'Devices and Tools' category. Gives - the user access to the station camera network on the current Z-level. - - rscadd: Activating an uplink telecrystal in hand now teleports you to a random - semi-near location. -2016-05-08: - PsiOmegaDelta: - - rscadd: The antag uplink now offers .45 ammunition. -2016-05-11: - PsiOmegaDelta: - - rscadd: The Cardborg costume now disguises you as a proper standard borg. This - only fools synthetics (until they examine you), to and all other lifeforms you - will remain your silly cardboard wearing self. - Based on RemieRichard's appearance - framework from /tg/ -2016-05-14: - HarpyEagle: - - rscadd: Items can now be placed in pockets using the strip UI. - - rscadd: Lit welders can now be placed in pockets. Having a lit welder in your - pocket sets you on fire. - Raptor1628: - - tweak: Replaced standard Space Suit, AMI Hardsuit, Excavation Suit, and Anomaly - Biosuit sprites. - - tweak: Restricts all station hardsuits to Humans with the exception of the CE's - suit, which fits everyone but vox and diona, and the Unathi Breacher, which - is for Unathi. - - rscadd: Adds alternate voidsuit types and more flavorful voidsuit descriptions. -2016-05-15: - HarpyEagle: - - bugfix: Fixed lungs not rupturing in space. -2016-05-17: - Techhead: - - rscadd: Stack items now take up storage space proportional to the size of the - stack. - - tweak: Materials, rods, and tiles have had their weight class and max stack size - adjusted. - - rscadd: Stacks now let you split them in any amount instead of one at a time. -2016-05-19: - Haswell: - - rscadd: Added suit cyclers in the engineering and research outposts. - - tweak: Reworded ERT light armors and helmets to asset protection theme. - - rscadd: Added new xenobiologist's locker in xenobotany storage and xenobiology - airlock, replaces botanist's lockers. - - rscadd: Added one biohazard closet to xenobotany storage. - - rscadd: Added scientist lockers and wardrobes to R&D and misc. research. - - rscadd: Added extra Emergency NanoMeds to research areas. - - rscadd: Added one science wardronbe to the research outpost locker room, replaced - stray scientist's locker with xenoarcheologist's locker. - - tweak: Scientist's locker can now be unlocked with either toxins storage or R&D - lab access. - - tweak: Removed toxins storage access from xenobiologists. - - tweak: Xenoarcheologist's locker now uses xenoarcheology access. - - maptweak: Toxins lab now uses toxins storage access instead of R&D access. - - maptweak: Adds xenobiology and toxins storage access to misc. research. - - maptweak: Tools from botanist's lockers in xenobotany storage are moved to the - crate sitting nearby. - - maptweak: Removed one biohazard closet in xenobiology airlock, remaining closet - now hold two sets of suits. - SilveryFerret: - - rscadd: Changes the Death Alarms from announcing over Common channel, to announcing - only over Medical and Security channels. - Yoshax: - - bugfix: Processing strata floor can now be pried up with a crowbar. - - bugfix: Blue carpet can now also be removed with a crowbar, and has had it's ability - to burn and have corners restored. - - rscadd: Added shotglasses. These can contain 10 units. They have their whole contents - swalloed in one gulp. They can be produced in the autolathe or found in the - booze vending machine in the bar. -2016-05-21: - Haswell: - - maptweak: Revamped kitchen and bar areas. - Irrationalist: - - tweak: Accessories are now more 'magic' and more pleasant for non-humans to use. - - tweak: Copied gas_mask to gas_alt in masks.dmi, gas masks should not be obscure - when worn by Resomi. - - imageadd: Added Resomi sprites for 'brown webbing vest', 'black webbing vest', - 'white webbing vest' and 'webbing'. - - imageadd: Added Resomi sprites for Head of Security's trenchcoat and coat, and - Warden's jacket. Including the grey version of the detective's leather coat. - - imageadd: Added Resomi sprites for old and new armour vests and webbing vests - ('suit'-slot ones) - - bugfix: Fixed breath mask lacking a state name when worn by Resomi. -2016-05-22: - Yoshax: - - rscadd: The antag uplink now offers regular discounts on randomly items. - atlantiscze: - - bugfix: Breaking a lot of lights at once will no longer cause massive lag spikes. - This also applies to other sources of sparks. - - tweak: Malf AI Electrical Pulse ability now has a 15s cooldown to prevent spam. - - tweak: Door crush damage reduced by 25% according to feedback. - - rscadd: 'Electrical Storm event overhauled. It now occurs in three severities - and simulates actual storm. A warning will be broadcasted shortly before it - begins, and once it''s over. Duration is severity-dependent. Possible effects - include: Broken lights (as it''s now), Hacked APCs (same as when emagged), or - outright broken APCs with more severe event variants. Each affected APC will - also shut down briefly, this causes station-wide power outages until the storm - passes. Stronger storms last for longer and affect more APCs at once.' -2016-05-24: - Haswell: - - rscadd: Added internal affairs closets, both secure and non-secure variants. - - maptweak: Revamped internal affairs and forensic offices. -2016-05-25: - Daranz: - - bugfix: Food slices spawned in lunchboxes can now be actually eaten. - Haswell: - - maptweak: Minor furniture adjustments to forensics, xenobiology and xenobotany - laboratories. - - rscadd: Added backpacks to xenoarcheology lockers. - - rscadd: Added clipboards to science lockers. - - rscadd: Added roleplay effects for nicotine. - - rscadd: Cigars and cigarettes now contain nicotine. -2016-05-29: - GinjaNinja32: - - rscadd: Rewrote drinking glasses. There are now eight types of glass, and drink - appearance is based on color and the type of glass you put it in. - - rscadd: There are now 'glass extras' you can add to drinks. Straws, drink sticks, - and fruit slices (yes, all of them) all work. You can add up to two extras per - glass. Add extras by clicking the glass with the extra, remove by clicking the - glass with an empty hand while it's in your other hand. - - rscadd: Adding 'fizzy' things (soda water, cola, etc) or ice to a drink will make - it be fizzy or have ice floating in it. - HarpyEagle: - - bugfix: Fixes disarm-attack dislocation chances being so low that you were very - likely to break the targeted limb before it would dislocate. - - bugfix: It is now possible to disarm-attack with stunbatons like with other melee - weapons. Note that this means that using a stunbaton on disarm intent will hurt - people. - - rscadd: Trying to move while being grabbed will now automatically resist. - - tweak: Small mobs are no longer able to pin larger mobs. - - tweak: Resisting a smaller mob's grab is more likely to be successful. - - bugfix: Fixed being able to climb onto a larger mob while restrained, weakened, - unconscious, or dead. - Haswell: - - rscadd: Added resomi science uniform to custom loadout, xenowear section. - Serithi: - - rscadd: Adds in lavender. - TheWelp: - - rscadd: Fully implements space-bikes. They are available to heist and mercenaries. - - tweak: Reworks the effect trail system (so we don't repeat the code over and over - again.) - - rscadd: Added a system to invest spell slots to get more back. You can invest - one spellslot at a time and you will recieve two back. Sacrificing specific - items/reagents onto the spellbook will shorten the time by ten minutes. Can - be done once per investment. - - tweak: Shapeshifting damage share now spreads out the damage to roughly ten damage - chunks. Makes it less of a limb-gibber. - - tweak: Baleful Polymorph buffs the shapeshiftee's health pool to fifty, so no - longer can you get insta-killed. - - tweak: Avian Form has been renamed to Polymorph (get it?) - - tweak: Polymorph no longer strips you when you transform. - - tweak: Polymorph and Baleful Polymorph no longer share damage. - - tweak: Armalis icons are properly centered, for real this time. - Yoshax: - - tweak: Adjusting your suit sensors now displays a message to other people in range - that you did so. In addition, seeing someone else adjust someone's suit sensors - no longer informs you to what level. -2016-05-31: - Cirra: - - tweak: Changed all dollar symbols to the Thaler symbol. - SinTwo: - - rscadd: 'Four new hairstyles added: Fringetail, Sleeze, Rows, Rows 2' - Yoshax: - - rscadd: Admins can now toggle being able to hear remote LOOC. -2016-06-01: - Hubblenaut: - - rscadd: Adds new hairstyle (Ponytail 5) - Raptor1628: - - rscadd: Updated torch Z levels, map defines, and added non-ship Zs. -2016-06-02: - Haswell: - - maptweak: Reworked one of the break rooms on the research outpost into a work - area. - - maptweak: Separated xenobiology biohazard shutters from the other research division - blast doors, added controls in both xenobiology access and RD's office. -2016-06-04: - Asanadas: - - bugfix: Nar-sie no longer causes FIX ME default turfs to display. - - tweak: Cult pylons now serve as decent light fixtures. - Cirra: - - bugfix: Cyborgs can no longer toggle their lights while dead. -2016-06-05: - Cirra: - - tweak: Adjusted the protolathe material cost of all modular computer components. -2016-06-07: - Cirra: - - tweak: Research grippers can now hold mech parts. - HarpyEagle: - - rscadd: Makes laser beams and muzzle flashes stand out in the dark. -2016-06-08: - Asanadas: - - rscadd: Placed cryo pods on the escape shuttle (3 for humans, 1 for robots). Take - care of SSD personnel! - Cirra: - - rscadd: IPCs can now use the *buzz, *beep and *ping emotes. - atlantiscze: - - rscadd: Added functioning tiny atmospherics to telecommunications. - - tweak: Various server rooms and telecommunications central compartment no longer - contain supercooled atmosphere. Instead they are cooled down to 10 celsius by - an air alarm, and have normal ventillation. This air alarm will trigger a warning - at 30C, and alarm at 40C, which is also the point at which machines begin taking - damage. -2016-06-09: - Aticius: - - rscdel: Removes resomi hallucinations due to loneliness. - HarpyEagle: - - tweak: Adjusted the storage size of various items. - - rscadd: 'Added a new storage item: large boxes.' - - tweak: Increased the shot capacity of energy crossbows to 8. - - tweak: Makes deadman switches hopefully more reliable. - - tweak: Inflatable barriers are studier and more resistant to puncture. - PsiOmegaDelta: - - tweak: A backpack is now required to diguise as a borg, along with the cardborg - parts. The chosen backpack decides which borg module you'll appear to be using. - Techhead: - - rscadd: 'New Random Event: Solar Storms. Similar to a radiation storm, but anywhere - inside the station is safe. Also boosts solar panel output significantly for - the duration.' - Yoshax: - - rscadd: Added towels to the loadout. These can be worn on the head, belt or outwear - slots. You can also whip people with them for a special message and sound! In - addition, using them in-hand will produce an emote where your towel yourself - off. - atlantiscze: - - tweak: The PDA messaging server now reboots automatically after a power outage. - This reboot takes about twenty seconds. - - tweak: Minor mapping changes to wiring and areas on the station. Brig has few - sub-areas to even out the load. Research Dock is now on the research subgrid. - Master grid has few extra power lines to make it a little bit more robust against - physical damage. -2016-06-12: - Ccomp5950: - - bugfix: Objects in bags and other containers (including your hands and pocket) - will now hear speach again. This impacts radios, explosive implants, and the - universal recorder. - HarpyEagle: - - tweak: Small mobs such as monkeys and resomi no longer gain the benefits of holding - large or bulky items in two hands. - SparklySheep: - - tweak: Move delay after clicking has been removed. - atlantiscze: - - tweak: Modular computer batteries are no longer fully charged when printed by - research. -2016-06-15: - Ccomp5950: - - rscadd: Turret controllers now alert admins and logs when enabled or disabled - as well as when set to stun or lethal. - HarpyEagle: - - soundadd: Adds new gunshot sounds for most bullet using guns. - - imageadd: Adds new bullet casing icons. All bullet casings now have distinct icon - states for spent and unspent casings. - - rscadd: Adds a new energy weapon, the x-ray laser carbine. The advanced energy - weapon crate now comes with two x-ray carbines and one x-ray pistol. - - bugfix: Fixed spear damage being set to a default value. - - tweak: Adjused spear damage, fixes steel spears now do somewhat less damage than - steel baseball bats, but are sharp. - - tweak: Steel fire axes now do somewhat less damage when wielded, unwieled damage - unaffected. - - tweak: Runtime can now become friends with anyone, regardless of their initial - job. - - bugfix: Beepsky and other securitrons now react quicker when attacked or their - perp tries to run, and move at closer to a running pace. Beepsky should no longer - be so easy to outrun. - PsiOmegaDelta: - - tweak: Vermin may now breed anywhere on the station but should also no longer - spawn inside areas such as the atmospheric tanks. -2016-06-17: - Asanadas: - - tweak: Changes to round-ending deathsquad and syndicate commando load-outs to - maximize speed and minimize drag. - - tweak: Upped the pulse rifle family's general capacity, for better asset protection. - HarpyEagle: - - bugfix: Fixed shuttles causing lighting to break and leave shadowy rectangles - behind. - - bugfix: Fixed shuttle corner appearance on the asteroid. - JerTheAce: - - rscadd: CentCom Fax, Admin Prayer, and CentCom emergency messages now prompt admins - with a pleasing sound effect. -2016-06-20: - PsiOmegaDelta: - - tweak: EMPs now randomly set suit sensors, with strength affecting the probability - of which mode is selected. - - rscadd: Because suit sensors can be affected externally a multitool can now be - used to (un)lock the controls, to for example allow re-adjusting prisoner uniforms. - - rscadd: Because suit sensors can be locked the antag uplink now offers tools and - services which are able to jam suit sensors in various ways. - - rscadd: Adds random events which will garble suit sensor data. -2016-06-22: - Asanadas: - - tweak: Wall mounted Nanomed dispensers no longer require access to use. - Ccomp5950: - - bugfix: IPCs and will no longer get genetic abilities from radstorms. Also Diona. - - bugfix: Lobby folks will no longer hear Hailers - TheWelp: - - rscadd: Adds support for projectile guns to jam. - - rscadd: Adds cheap/crappy gun variants. - Zuhayr: - - rscadd: Changed the vault nuke into a self-destruct terminal. -2016-06-24: - TheWelp: - - rscadd: Adds traders and a trader process. -2016-06-25: - JoeyJo0: - - rscadd: Fixed chargers not charging anything other than cells. -2016-06-28: - Cirra/: - - rscadd: Added a chemistry gripper for Crisis borgs. - HarpyEagle: - - rscadd: Adds applying pressure to body parts to reduce bleeding. With desired - body part selected, help-intent click yourself or get an aggressive grab, then - help-intent attack with the grab item. Each person should only be able to apply - pressure to one body part on one person at a time, so choose wisely. Applying - pressure will get blood on your hands. - - rscadd: Splints and hardsuits that support broken limbs will automatically apply - pressure. - - rscadd: Wounds that require treatment (e.g. bandage) to stop bleeding will be - bolded in the examine output. Wounds that will eventually stop bleeding on their - own are not bolded. - - tweak: Rigsuits now only support limbs when online. - Haswell: - - maptweak: Added NanoMed wall vendors in engineering, security, bridge, bar, arrivals - and escape hallways, replacing mapped in medkits and medical supplies. - - maptweak: Removed one security officer locker, added one cyborg recharging station - in its place. - - maptweak: Added lights in head of security's office. - - maptweak: Added supply ordering, supply control and arcade circuit boards to tech - storage. - - maptweak: Replaced out-of-place reinforced walls with normal walls. - PsiOmegaDelta: - - rscadd: MedHUD overlays now have more stages, both for 'normal' and critical stages - of injury, for improved quick-diagnosis. - TheWelp: - - rscadd: Adds support for map-specific jobs. - - rscadd: Adds torch specific jobs. - Zuhayr: - - rscadd: Ports/adapted several kitchen machines from Apollo Station. -2016-07-03: - Snapshot: - - rscadd: Added Neural Laces which are an intented optional config togglable replacement - to the cloning system. Neural laces are a mechanical backup of a character's - memories and personality that can be exchanged between bodies. - - rscadd: Added Neural Lace Surgery mechanic which works the same way as implant - surgery. - - rscadd: Added Neural Relacing Machine which will automate the procedure above - and can be constructed through R&D. - - tweak: Health Analyzers will show if a subject has a neural lace. - - rscadd: Neural laces can be implanted in someone without a neural lace with a - 30% chance of taking over their body - Zuhayr: - - rscadd: The health indicator on the player GUI will now show a more detailed breakdown - of damage to your body. - - rscadd: Added bioprinter to Genetics and prosthetic organ fab to Robotics. - redstryker: - - rscadd: Adds evening gloves to the loadout, with the ability to tweak their color. -2016-07-06: - Ccomp5950: - - bugfix: Cleanbots will no longer obsess over dirt under doors/lockers or other - areas they cannot access. - Hubblenaut: - - rscadd: Racks will automatically align their contents. - - tweak: Tables use an invisible 8x8 grid for item placement. - - tweak: Items spawning or placed in closets will not be pixelshifted. - - tweak: Certain items will now always be placed centered (This is mostly reserved - for items with sprites too big to be handy for grid placement). - - tweak: Flips rack icon to be consistent with other sprites. - - bugfix: Sets center_of_mass for tools and chemistry reagent containers. - PsiOmegaDelta: - - rscadd: Uplink services now all spawn a proper item which can be used to trigger - the relevant effect at a desired time, as opposed to it firing immediately. - - tweak: The jammer item has been moved into the 'Devices and Tools' category. - - tweak: The jammer services have been moved into the 'Services' category. - TheWelp: - - rscadd: Adds the item_worth var and get_worth proc to obj subtypes and mob/living -2016-07-08: - Asanadas: - - rscadd: Added two pairs of forensic gloves for detectives to use, ceasing their - self-incrimination. Replacements can be found in the cargo detective crates. - TheWelp: - - tweak: Rebalances leap to respect handcuffs, ability to walk, etc. - - tweak: Pariahs HP deficit has been removed (65->100), instead they are now more - vulnerable to all types of damage. - - rscadd: Adds missing hair color flag for regular Vox. Now you can have colorful - dyed Vox hair! Within reason. -2016-07-09: - HarpyEagle: - - rscadd: Severe enough burn damage now causes one-time blood loss due to blistering - and body fluid cook-off. - - rscadd: Armor that provides 'bio' protection will now protect against the effects - of slime feeding. Slimes can still glomp you, however, and are still dangerous - even if you are wearing biohazard suits. -2016-07-12: - atlantiscze: - - tweak: Random event probabilities have been changed a bit. This is mostly noticeable - with electrical storms, which should be less common now. - - tweak: Electrical storm now shuts down APCs for longer duration which is controlled - by event severity. APCs with critical flag are now affected too, but are only - shut down for a short time in comparison to others. - - tweak: EMPs are no longer one-hit kills for AIs - APCs with critical flag take - reduced damage from EMPs, and AI's power restoration routine now resets the - APC that may have been EMPed. - - tweak: AI's power usage has been overhauled. Under the hood changes should improve - reliability a bit and take more scenarios in consideration. The power restoration - routine now provides better feedback to the AI if it fails, such as, whether - the APC is broken or only discharged, etc. - - rscadd: AI now has a Shutdown verb that can be used to reduce it's power usage - five times. This disables AI's control, cameras, and most communications as - if it was without power. This verb acts as a toggle, so it can be used again - to turn yourself back on. - - rscadd: AI now has Toggle Power Override verb that can be used to disable power - saving mode when it loses APC power. This results in much faster discharge of - internal capacitor, but allows you to operate as if you were powered. Can be - toggled at any time. -2016-07-13: - HarpyEagle: - - tweak: Voidsuits and cyber suits are now more shock resistant, now roughly between - hardsuits and thick clothing. -2016-07-14: - atlantiscze: - - tweak: Shield generator configuration has been tweaked. Shield generators upkeep - power is reduced considerably (stationwide shield is approx. 1.1MW at full strength). - Shields still use a lot of power when regenerating. - - tweak: Shield capacitors now act as actual capacitors. Their power storage is - 2 GJ, and maximal input 4MW, as opposed to 8MJ/400kW it was now. - - tweak: Shield generator+capacitor UI now displays in kilowatts and megawatts instead - of watts where applicable. -2016-07-17: - TheWelp: - - tweak: Reduces fireloss cost of casting Dyrnwyn (30->10) - - tweak: Reduces investment time (30 minutes -> 15) - - tweak: Entangle is now a hand-spell. - - rscadd: Humans can now use the *vomit emote, which causes them to vomit. -2016-07-18: - PsiOmegaDelta: - - rscadd: The antag uplink now offers a shield disrupter in 'Devices and Tools' - category. Handy for when that hull shield gets in your way. - - rscadd: Once an emergency response team has been successfully dispatched, as opposed - to simply requested, the emergency shuttle cannot be called for 30 minutes. -2016-07-22: - Daranz: - - bugfix: FixOVeins can now be used for attaching robotic organs (such as neural - laces) in organic patients. Follow the same procedure as with normal organ transplant. - Rymdmannen: - - rscadd: Added department specific rubber stamps for cargo and warden. - - maptweak: Replaced 'small rubber stamp' with corresponding new ones in cargo area - and warden's office. - - maptweak: Placed a 'DENIED' stamp in captain's office. - - spellcheck: Renamed ''quartermaster's stamp'' to ''quartermaster's rubber stamp''. - Snapshot: - - rscadd: Moved airlock electronics, brig doors, portable canisters, and cargo computers - over to TGUI - - tweak: Cargo ordering computers have been completely reworked. Both the supply - and ordering computer have been merged into one which can be logged into or - out of by a crew member with cargo access. The computers will allow only one - computer to be logged in as a register at a time and orders cannot be placed - without a register active. - - tweak: The cargo ordering system has been tweaked to allow requests even when - there are not enough points available so that cargo can queue items into their - cart at their discretion. Items moved to the cart can be demoted back to requests - as well. - - rscadd: The cargo computer now allows crew members to print a receipt of their - requests for their onw use. - - soundadd: Added sounds for printing from the cargo computer for more ambient sounds. - - experiment: The cargo computer will quietly beep whenever a successful ui button - press is completed. This is an experimental test to see if more ambience can - be added without becoming too much of an annoyance. - atlantiscze: - - rscadd: Adds maintenance braces. These can be printed by research and used to - lock down an airlock. Braces can be removed with paired keycard or maintenance - jack tool (also available from research). Braces prevent the airlock from opening - via any means, and absorb a lot of damage until they break off, protecting the - airlock. -2016-07-23: - PsiOmegaDelta: - - tweak: Some antag uplink weapons now come with ammunition (and a container to - hold them) and their price and description has been updated accordingly. - - tweak: Buying random items from the antag uplink will no longer give you weapons - without relevant ammunition, or ammunition for weapons you may not have. -2016-07-25: - Superbee29: - - rscadd: Ghosts can now see the power in a cable when examining it. -2016-07-29: - Raptor1628: - - tweak: Replaced Tactical Armor sprites and stats. Overall less protective. - - rscadd: Adds new gas mask sprite. - - tweak: Adjusted helmet and armor values. Helmets match their armors a bit more, - but are usually more protective. - - tweak: Adjusts armored vests for the torch and splits ballistic/ablative armor - into vest and full-body versions. - atlantiscze: - - tweak: Add Antagonist vote can no longer be freely called by players. It can still - be called by admins, or as an alternative to crew transfer. - - tweak: Add Antagonist is no longer an alternative to crew transfer during Extended - gamemode. The intention is to keep that gamemode antagonist-free, as it was - originally intended. - - rscadd: Players in the lobby will now see which antagonist types were added to - the game. This is displayed below the gamemode's name in the Lobby tab. -2016-08-01: - HarpyEagle: - - rscadd: Emagged and traitor synths can no longer be locked down, except by physically - cutting the lockdown wire (merely pulsing will not work). - TheWelp: - - rscadd: Certain races can now swallow objects whole by using the disarm intent - and aiming at their mouth. - - rscadd: Vomitting now shoves out all the things in your stomach. - - rscadd: Adds support for projectile vomitting being an ability of a species. -2016-08-02: - Haswell: - - rscadd: Modules installed within a hardsuit will now be listed when examining - the hardsuit control module while being held or worn, if the maintenance panel - is open. - Minijar: - - rscadd: Upgrades anomaly isolation to be able to contain pretty much any dangerous - anomalies with boroscillate windows and blast doors. - PsiOmegaDelta: - - rscadd: Ion storms now also affect unslaved borgs, but not drones. - Zuhayr: - - rscadd: Prevented xenomorphs from taking shrapnel or breaking limbs. Buffed non-queen - xeno weed health regen. Remember to rest to not take a heal penalty. - - rscadd: Prevented weeds from entangling species with the NO_SLIP flag. -2016-08-06: - Zuhayr: - - rscadd: Added status display icons for green, blue and delta alerts. - - rscadd: Status displays now have coloured lights for alert icons. - Zuhayr, GinjaNinja32, and Snapshot: - - rscadd: Implemented full body prosthetics. Full Body prosthetics (FBPs) allow - replacement of the entire body with cyborg components and replacement of internal - organs with synethic or assisted counterparts. Players can create a FBP character - by selecting full body in the limbs section of character preferences. - - rscadd: FBPs gain the benefits of a stronger body and no longer requiring breathing, - but are prone to overheating much like IPCs and can take pressure damage in - space. If you play an FBP, be sure to wear a suit and cooler! - - rscadd: IPC monitor screens are now a seperate object in the loadout menu. IPCs - can select a variety of other heads from other prosthetic manufacturing companies - to change their head and body appearance. - - imageadd: IPC monitor screens have an object sprite that's synced to their mob - sprite. - - tweak: Rebalanced IPC brute and burn modifiers due to the introduction of FBPs. - These settings may be tweaked again in the future after gameplay has been conducted. -2016-08-07: - Asanadas: - - bugfix: 'Brings an end to the deadly feud between two of the Exodus''s mascots: - Pun pun, and Officer Beepsky.' -2016-08-08: - Haswell: - - tweak: Emitters can now be locked using IDs with engine room access while it's - on or off. - Techhead: - - rscadd: Ghosts can flicker lights when the round is spooky enough. -2016-08-11: - Haswell: - - tweak: Engi-Vend and Robco Tool Maker machines can now be used by atmospheric - technicians. -2016-08-15: - Asanadas: - - rscadd: Neural laces can now be destructed and created in a proper research lab. - PsiOmegaDelta: - - rscadd: Invented supermatter grenades and made them available to certain sets - of antags. - - rscadd: The antag uplink now allows you to also buy x1 grenades, in addition to - the x5 sets, with some markup. - TheWelp: - - rscadd: Adds ability for merchants to fast buy via cash using a banking system. - - rscadd: Adds ability for players to sell things to merchants. They will only take - things they like. -2016-08-18: - Haswell: - - tweak: The autopilot on the escape shuttle can no longer be overridden during - crew transfers while on blue alert or lower. It can only be overridden during - an evacuation, or during an alert level higher than blue. - Karolis2011: - - rscadd: Added whole map capture tool, only accessable by admins. -2016-08-22: - Asanadas: - - rscadd: The Exodus robotics lab has a newly installed Robotech deluxe (we found - it out in the shed). Also, a new light switch. -2016-08-26: - Asanadas: - - rscadd: Dug out an old engineering vending machine and added it to the engineering - workshop. - Soadreqm: - - rscadd: Made tape recorders use removable 10-minute cassettes instead of 60-minute - internal storage. - TheWelp: - - rscadd: Adds four new traders, a robot trader, a pet trader, a replica trader, - and a prank trader. - - rscadd: Adds unique items (and a bot) for the traders to sell. - - rscadd: Adds missing item worth values to the list. - - tweak: Unique NPCs now stay around for twice as long. - - tweak: Tweaks Hostile mob AI, so that if they have no faction at all, they will - target nobody. - - tweak: Spawner grenade can now set variables (using a list) upon spawning whatever - it spawns. -2016-08-28: - PsiOmegaDelta: - - tweak: Telecrystal amount increased from 25 too 100 with uplink costs adjusted - accordingly, all to allow even more price differentiation. - - tweak: A five pack of grenades is now 20% cheaper than buying them one at a time. - atlantiscze: - - tweak: Power cell no longer use magical charge units. Instead they are rated in - WattHours. For example, a cell with rating of 1000 will be capable of providing - 1000 watts for one hour. (or 2000 watts for half a hour, etc.) - - tweak: In general this means that a power cell with rating of 1000 will hold MUCH - more energy than it held before. To balance this out, power cell capacities - have been reduced considerably. When these two changes add up the cells last - for approximately same time as they used to. - - tweak: As part of this change, higher grade power cells have became a bit more - rare. Research can still fabricate them in bulk, but they are much rarer from - random spawns, and no longer available from vending machines. Vending machines - provide standard cells instead. EngiVend can be hacked to provide few high capacity - ones. - - tweak: Vending machines no longer shoot objects at people when malfunctioning. - They merely shudder and dump the item on the ground. This should make the random - event a little bit less annoying. - - tweak: Space heater's default temperature setting is now 20C (changed from 50C), - which is the default station temperature. It can still be changed via the UI - when the panel is open. -2016-08-29: - Zuhayr: - - rscadd: Added /vg/ direct-action ventcrawling. You will now crawl through the - actual pipe network, a step at a time. Have fun. -2016-08-30: - Haswell: - - rscdel: Atmospheric technician is now unavailable for general play. - - rscadd: Alt title 'Atmospheric Technician' is now added to engineers. - - tweak: Engineers now have all the accesses atmospheric technicians previously - held. - - tweak: Tweaked job selection screen to properly indicate which jobs aren't available - to play as. - Kelenius: - - tweak: Cultists don't need to research words anymore. - - tweak: Astral journey's damage over time lowered to sane levels. - - tweak: Changeling revive, when the timer is up, will now give you a verb that - revives you, allowing you to choose when to get up, instead of doing it immediately. - - tweak: Changelings will always get DNA, species, and languages together, be it - via absorbtion, DNA sting, or hive channel. - - tweak: Changeling transform and change species was merged. - - tweak: Changelings no longer display gender in changeling chat. -2016-09-02: - Techhead: - - rscadd: Medical splints can now also be applied to hands and feet (in addition - to arms and legs). - - rscadd: For those that miss the old functionality, ghetto splints have been added. - These can be crafted with a roll of tape and a metal rod and can only splint - arms and legs. - atlantiscze: - - tweak: Converts few other things over to work with the recent CELLRATE change. - This fixes various issues where battery life of some things (drills, etc.) was - very short, while some other things had power cells with very large capacities. - - tweak: Hardsuits and Mechas now use energy in joules rather than Wh (this fixes - Ninja suit, among others). Various exosuit tools now have rebalanced power usage. - Energy based exosuit weapons use energy on per-shot basis, ballistic weapons - use single massive spike when fabricating a new magazine. - - tweak: Minor power-related changes to exosuit modules. Energy cost of some offensive - modules increased a bit. - - tweak: Added short cooldown for teleporter module to prevent spamming. - - tweak: Added power usage to various industrial/science modules (anomaly scanner, - various drills, etc.). - - tweak: Increased mounted RCD power usage by a lot (matter fabrication is very - power demanding process). - - tweak: Powersink module is limited to 120kW transfer rate, and is slower (30kW) - when used on APCs with enabled interface lock. Furthermore, when draining from - APC it first tries to take energy from the grid, before resorting to taking - it from the cell. - - bugfix: APCs drained by a ninja no longer get stuck on 0% charge, and instead - recharge themselves as usual. - - rscadd: Repair capability of upgraded cyborg rechargers now also works on IPCs - and FBPs. - - tweak: If the cyborg recharger is upgraded enough, it will be capable of rebooting - (and eventually repairing) destroyed modules, for some extra power. -2016-09-03: - Haswell: - - rscadd: Added a fashion vending machine in the locker room for snowflake loadout - items. - - rscadd: Added more SMES coils and circuitboard to supply packs. - - tweak: Adjusted price of SMES coil. - Superbee29: - - bugfix: Changeling transformation (of itself and others via sting) no longer causes - organ rejection. - - bugfix: IPCs can no longer be stung by changelings. -2016-09-07: - Chinsky: - - rscadd: Added a hawaii shirt to loadout accessories. Can be attached to clothing - like suit jackets etc. Can also be found in mixed wardrobes. - Cirra: - - rscadd: Spiderlings now have a unique sprite specific to the type of giant spider - they will become. - Kelenius: - - rscadd: Ninjas now have access to a PDA that has an empty uplink (for exploitable - information). -2016-09-09: - Daranz: - - tweak: If you crack open an amputated limb and later reattach it, you will now - have to cauterize it after reattachment. - Haswell: - - tweak: Reduced wallet capacity, added more items that can fit in wallets. -2016-09-10: - Cirra: - - rscadd: Resomi now process reagents twice as fast. - - tweak: Moved all Resomi organs to the chest, apart from the brain and eyes. - Kelenius: - - rscadd: Xenoarcheology code has been partially redone. - - tweak: Pick set will now sort the picks inside it. - - tweak: Removed useless random numbers from GPS coordinates in various places. - I'm sure we have not lost the arcane knowledge of rounding 500 years into the - future. - - tweak: Picks renamed to show their excavation depths. - - tweak: Suspension generator's power use lowered. - - tweak: Suspension generator's different field types removed. By the way, remember - that they can suspend any item and even mobs. - - tweak: Archeology belts and pick sets can now hold small pickaxes. Pick sets still - only have 7 slots. Brushes fit on your ears. - - tweak: Empty rock drop rate reduced. - - tweak: Empty rock renamed from 'rock' to 'small rock' so you can tell if you are - clicking on a turf or an item when hovering over it. - - tweak: Empty boulder spawn rate reduced. - - tweak: Tape measuring is a bit faster. - - tweak: Scanner now shows the lowest and the highest depth of the find (highest - is depth + clearance) for easier calculations. Ideally, you need to hit exactly - the lowest spot. Less ideally, hit anywhere between higest and lowest. Hit below - lowest and you have a chance to break the find. - - tweak: You can now use a brush to clear strange rocks. Welder uses less fuel for - that than before. - - tweak: Anomaly analyser's report made a bit easier to read. - - tweak: Anomaly locater will now also locate normal finds. - - bugfix: Gas masks will now correctly spawn as archeological finds. - - bugfix: Digsites will now properly contain several (4-12) turfs in a 5x5 radius. - Be careful when digging near your finds. - - bugfix: Suspension generator will now correctly turn off (qdel issue). - - bugfix: Archeology overlays won't disappear when the icon is updated (e.g. when - mining next to it). - - bugfix: Archeology overlays won't overlap each other and will properly disappear - when you mine out a find. - - bugfix: Some spawning oddities were fixed. - - bugfix: Checks for whether you get a strange rock or a clean item were fixed (previously - it always gave you clean item where it should have been rolling a random number). - - bugfix: Can no longer get rid of any item by putting it into evidence bag and - bag into core sampler. - - bugfix: CO2 generator effect now has a type. - - bugfix: Phoron generator effect will now always generate phoron, not sometimes - phoron and sometimes oxygen. - - tweak: You can now lit smokables with cigarettes and cigars. - - tweak: You can now explode welder tanks with all flame sources (cigarettes, lighters, - candles, igniters, etc). - PsiOmegaDelta: - - tweak: The impaired Resomi vision is now represented by the oxygen overlay rather - than the welding overlay. - - tweak: Vision impairment from wearing a welding mask now stacks with nearsightedness - due to now being two separate effects. - - tweak: Species and individual specific nearsightedness now stacks, i.e. a nearsighted - Resomi won't be aided at all to the same degree by the standard prescription - glasses as other species would be. - - tweak: Glasses can now have varying degrees of prescription. -2016-09-11: - PsiOmegaDelta: - - rscadd: Equipment that doesn't check a specific id card for access now checks - the collective access of all id cards in both hands and the id slot. Among other - things such equipment includes doors. -2016-09-14: - Cirra: - - bugfix: Nurse spiders should now correctly have a chance to implant eggs on attack. - Zuhayr: - - tweak: Ninja cloak now only renders you invisible to the player; right-click will - show you, and your inhands will still render. -2016-09-15: - Cirra: - - rscadd: Service grippers can now hold straws and sticks. - Haswell: - - rscadd: Added coin mint to the mining outpost. - - rscadd: Borosilicate (phoron) glass can now be made with the mineral processor. - atlantiscze: - - rscadd: Created new AI restorer program, by default available on research consoles. - Also added a new hardware piece that acts as connection between intellicard - and a computer (laptop and console only). The new program allows AI restoration, - as well as simple law modifications. It can also be used to purge malfunctioning - AI's laws correctly. This program can only work on intellicarded AIs, that are - placed in the computer itself. The program can be run/used by anyone, but requires - head of staff level access to download from NTNet. - - rscdel: Removed old AI integrity restorer console -2016-09-16: - atlantiscze: - - rscadd: Added camera monitoring program to modular computers, that can be run - on consoles, laptops and tablets. Most mapped in consoles come with this program - preinstalled. - - tweak: Due to removal of old consoles (telescreens were part of these consoles), - entertainment monitors were replaced with civilian modular console where applicable. - This console can be used to access the entertainment channels. - - rscdel: Removed old camera consoles, including circuit boards and other related - things. -2016-09-17: - Chinsky: - - rscadd: Some suit jackets and hawaii shirts can be toggled between buttoned/open - states with a verb. - Zuhayr: - - rscadd: Added a reset slot button to chargen. -2016-09-18: - PsiOmegaDelta: - - rscadd: All staff should now be able to access the Secrets menu. Each category - handles its own permission checks.. - - rscadd: Administrators and moderators can now review admin PMs and attack logs - from the Secrets menu, see the new Investigation category. -2016-09-19: - PsiOmegaDelta: - - rscadd: Ghosts now have a 'Teleport to Coordinate' verb. -2016-09-21: - Chinsky: - - rscadd: Ghosts AND AI eyes can travel zlevels again with Move Upwards/Down verbs. - - rscadd: Humans can too, with either working jetpack or wearing magboots and near - a wall (climbing). Don't try in gravity-working areas though, you'll still drop. - Haswell: - - maptweak: Readded missing blast shutters on mercenary shuttle and Skipjack. - - maptweak: Removed random steel floor tiles. - - maptweak: Added random coin spawns. - PsiOmegaDelta: - - maptweak: There are now more rechargers placed around the station. - - maptweak: Added fire fighting equipment in the library and port research maintenance - areas. - - maptweak: The engineering washroom now has two entrances. - atlantiscze: - - tweak: Vastly increases amount of water held in fire extinguishers and water tanks. -2016-09-23: - PsiOmegaDelta: - - rscadd: The antag uplink now offers energy guns in the 'Highly Visible and Dangerous - Weapons' category. - Szunti: - - bugfix: Acids, plant-b-gone etc. kill weeds instead of growing them. Sugar grows - them instead of killing. -2016-09-25: - Chinsky: - - rscadd: Can now pick color of labcoat in loadout menu, replacing separate preset - colored coats. My condolences to those who had preset ones. - Haswell: - - maptweak: Added lots of random spawns in maintenance, replacing most old mapped - in items. -2016-09-26: - atlantiscze: - - tweak: Malfunctioning AI ability Basic Encryption Hack now lists station APCs - first. Off-station APCs (that do not contribute to CPU generation) are appended - to the bottom of the list. - - rscdel: Airlock brace keycards have been removed. - - tweak: Airlock braces when held inhand can be accessed and configured as an airlock - electronics circuit board. Instead of brace keycards they can now be unlocked - by swiping an ID with configured access (or by using maintenance jack). Configuring - the brace has no access requirement, but it can't be configured when installed - on an airlock. -2016-09-30: - Kasuobes: - - rscdel: Removed IR emitters until they are fixed and don't kill servers. -2016-10-03: - Asanadas: - - bugfix: In-game record editing (security and medical) will now respect the same - character limits as it does in the character-setup panel. No more accidentally - massacring those long records! - Haswell: - - rscadd: Added station date to status tab. -2016-10-06: - Chinsky: - - rscadd: Can now use chopped off arms/hands to leave fingerprints on things. Keep - it in your active hand, and its fingerpints will be used. - Datraen: - - tweak: Skrell are now more resistant to various chemicals, more susceptible to - pepperspray. - Haswell: - - tweak: Drone laws have been revised to exclude non-interaction clauses to promote - RP, but retains non-interference intent. Treat and respect them as actual players. - - tweak: Reworded corporate law skill to cover broader areas. Includes SolGov law - and general legal knowledge. - Inforsaken: - - rscadd: Radio Distortion is now linear and uses more than just the * character. - PsiOmegaDelta: - - tweak: If playing a hidden game mode, i.e. Secret, staff now see the actual game - mode in the Lobby. - Raptor1628: - - rscadd: Added a lot of items to the random maintenance spawns. - - tweak: Reduces metagame potential in the money briefcase description. -2016-10-08: - Ferracio: - - rscadd: Name and species can now be selected for newly-constructed FBPs. - - tweak: Removed 'system instability' readout from robot analyzer due to the targets - being immune to 'system instability'. - - rscadd: Added ability to create full-body prosthetics by adding a robot head to - a robot torso. - - tweak: Robotic heads and torsos can now be manufactured with brands. - Konater: - - imageadd: Added some hairstyles for Resomii that n00b created. - TheGreyWolf: - - rscadd: Added Sign language, which can be selected from character setup. - blazerules: - - imageadd: Added a new Emo hair style, one that doesn't cover the eyes. -2016-10-10: - Levyafan: - - rscadd: Added research tape to excavation closets and xenoarchaeology lockers. - - rscadd: Added optical meson scanners to miner lockers. - - rscdel: Removes optical material scanners from miner lockers. Those were useless - anyway. - - maptweak: Mapped in a second suspension generator, some racks, and a rag to the - research outpost. - - maptweak: Mapped in a soft drinks vendomat and a coffee vendomat to the mining - outpost. - PsiOmegaDelta: - - tweak: Objects are now layered using both planes and layers. Visual layering issues - are expected, please report them except if you're running a client older than - 510 in which case you have to update first. - - tweak: The 'Show Server Revision' verb should now be more copy-paste friendly, - in terms of adding the info to issue tickets, and now also includes the major - client version. -2016-10-13: - Hugo14453: - - rscadd: Added golden soap. - Lorwp: - - maptweak: Fixed Firing Range Camera from being named 'Medical Station'. Changed - Cameras in firing range to 'East' and 'West' Respectively -2016-10-16: - Asanadas: - - rscadd: The Mental Health office has been slightly renovated! Psychiatrists and - the other jobs who reside in the Mental Health office of the Medical Bay will - find more pills readily available in their closet, and a few tidier paperwork - items within easier reach. - - maptweak: The Head of Security and Warden lockers now spawn with a generic NT - helmet. - - tweak: The Head of Security's dermal implant now has the same armor values as - a generic NT helmet. - LorenLuke: - - rscadd: Added a toggle to the ninja's self-destruct. Default starting is 'off'. - - tweak: Adds a delay and visible messages (and now a blinking effect!) after the - self destruct is activated. - PsiOmegaDelta: - - rscadd: Staff with sufficient rights can now edit global variables using the 'View - Global Variables' verb. - TheGreyWolf: - - rscadd: Added the tacticool turtleneck to the custom loadout. -2016-10-18: - Mo_Bros: - - imageadd: Adds new icon for compressed gas warning signs. -2016-10-21: - Broseph Stylin: - - rscadd: Added HUD aviators to the loadout. They're restricted to security, and - can toggle between HUD and flash protection modes, but won't offer both at once. - Chinsky: - - rscadd: Added floating camera thing for Journalists, in the library office nook. - It acts like a portable security camera on Thunderdome network. Can also send - audio on Entertainment radio channel. -2016-10-23: - Broseph Stylin: - - rscadd: 'Added a few new items to the loadout: Various ties, a black vest, stethoscope - (medical only), a black suit jacket, three hazard vests, and a cigar case.' - Chinsky: - - rscadd: Added hotkeys for target zone selection. Ctrl+Numpad[number] or just Numpad[number] - in hotkey mode. Make sure to have NumLock enabled. Numpad8 is head-eyes-mouth - (it cycles through those), 4-5-6 are right arm/hand-chest-left arm/hand (cycles - again), 1-2-3 are right leg/foot-groin-left leg/foot(you know the drill) - Ithalan: - - bugfix: Added missing anomaly scanner pad to research outpost's cell A. - - maptweak: Added a health analyzer to the research outpost lab so researcher can - monitor their test subject monkeys. - - maptweak: Removed an oddly placed lightbulb on the exterior surface near the research - outpost. -2016-10-29: - Lorwp: - - maptweak: Added Emergency Wall Mounted Oxygen Tanks to Most suitable External - Airlocks. You can breathe from them using a Mask Attached to them. - Mark9013100: - - rscadd: Gives the Science, Night Vision, Tactical, and Material Goggles action - buttons. -2016-11-01: - Broseph Stylin: - - rscadd: Prescription medical and security HUDs have been added to the loadout. - PsiOmegaDelta: - - tweak: Mercenaries now begin with proper boots, gloves, and belts. -2016-11-02: - Broseph Stylin: - - rscadd: Added a few dresses to the loadout. - Mark9013100: - - rscadd: Adds black softcaps. Can be found in black wardrobes and custom loadout. -2016-11-03: - Broseph Stylin: - - tweak: Most loadout items with multiple variants can now be found under lists - in their respective categories. This change WILL mess up your saved loadouts, - so be sure to redo them. - Siegdermaus: - - imageadd: Adds a new icon for turret and blast area caution signs. -2016-11-04: - ColaFiend: - - rscadd: Added new welding masks available in the gear loadout for engineers and - roboticists. -2016-11-06: - Asanadas: - - tweak: Added a moderate delay to the opening and closing of robotic maintenance - hatches. No more quickscope-cellsniping. - - bugfix: Can no longer run away from a robot while removing its MMI and allow the - process to succeed. - - bugfix: Fixed a one-pixel mistake in one of the robotic maintenance step images. - Broseph Stylin: - - tweak: Most loadout items with multiple variants can now be found under lists - in their respective categories. This change WILL mess up your saved loadouts, - so be sure to redo them. - Datraen: - - tweak: Skrell now have mild darksight. - - tweak: Skrell now prefer slightly warmer temperatures. -2016-11-08: - atlantiscze: - - tweak: Blobs are now considerably more resistant to energetic weapons, be it handheld - lasers, energy guns, or even emitters. An emitter is still useful to suppress - the blob a bit, but one emitter shouldn't be capable of outright killing the - blob. - - rscadd: Blob has a relatively small chance to grow secondary cores. These cores - are considerably weaker, have lower health, but still help spread the blob a - bit more. - - tweak: Emitter power usage increased (30kW to 100kW). While it is still possible - to run one with PACMAN, you have to keep it on overload. - - tweak: Reinforced walls are now considerably more resistant against projectiles - of all kinds, be it emitters, handheld weaponry, or anything else. Regular walls - are unaffected. An emitter is still useful if you need to burn through one, - but expect to wait - it needs over fifty pulses for a plasteel reinforced wall. - - tweak: Details on the above. Reinforcement is calculated from the material that - is used to reinforce the girders when building the wall. Weak materials such - as wood have 0% reduction in taken damage. Most basic materials have 50% or - so. Steel is decent material with 80% reduction. Plasteel is very good with - 90%, and titanium is the best with approx. 92% reduction (though it has lower - overall health) - - rscdel: Removed bubble shield generators, hull shield generators and shield capacitors. - Also removed shield disrupter. - - rscadd: Added a replacement advanced shield generator, that has a combined function - of a capacitor, and both shield generators (hull shielding is toggleable). This - shield generator must be built and once constructed is immobile (but can be - deconstructed again). These generators are fully configurable, have better hull - shielding that doesn't block shuttles, mass drivers and others, and have different - energy system. Damage will drain the shield's energy directly. - - rscadd: Added Shield Diffusers. Two variants exist - floor mounted and handheld. - The handheld variant can be purchased from traitor uplink, and runs on an internal - cell. The floor mounted variant layers under floor tiles and is APC powered. - These diffusers dissipate shields in adjacent tiles (+ shaped pattern). The - generator can be set to try to counter these, in which case each diffuser causes - major EM strain on the shield. - - maptweak: Added two shield generator circuit boards and two shield diffuser circuit - boards into tech storage. -2016-11-09: - Irrationalist: - - bugfix: Unathi and Tajara can now spawn and show preview with gloves included - in outfit of [HIGH] selected job - - tweak: '/obj/item/clothing/gloves has new proc: cut_fingertops - for easier adminbus' - atlantiscze: - - rscdel: It is no longer possible to ventcrawl through scrubbers. -2016-11-14: - Datraen: - - tweak: Removes a large portion of camera bloat. - TheGreyWolf: - - rscadd: Adds sweaters in all the rainbow's colors and more to the custom loadout. - Zuhayr: - - rscadd: Restored scrubber crawling, made them weldable. -2016-11-16: - Legius: - - bugfix: Made the holdout pistol not turn invisible when unloaded with a silencer - attached. -2016-11-17: - Legius: - - maptweak: Added a airlock access button to the exterior of the Dormitory airlock. - - maptweak: Moved the meter covering the second radiator pump so it no longer covers - the pump. -2016-11-18: - Datraen: - - tweak: Global announcer now has access to engineering channel. - - tweak: Supermatter now uses the global announcer. - - bugfix: Supermatter now sends out integrity alerts. - Legius: - - bugfix: The cryotubes on the shuttle and at centcomm are no longer death traps. -2016-11-22: - Broseph Stylin: - - tweak: Waistcoats and suspenders are now accessories and no longer suit items. - Their loadout entries have been changed as well. - PsiOmegaDelta: - - rscadd: There is now a character preference, Ghost Follow Links, to toggle between - short and long follow links. - atlantiscze: - - rscadd: The AI can now speak most languages that are available to station races. -2016-11-28: - Finalsong1: - - tweak: Changes the Vat-Grown Human economic modifier from 5 to 10. - Haswell: - - maptweak: Adjusted armory layout and inventory. - Irrationalist: - - bugfix: Fixed stun-batons being unuseable by synthetics due to hitcost increasing - each (de)activation - - bugfix: Fixed stun-batons not properly updating their icons - Kelenius: - - bugfix: Ghosts can now hear whispers. - - bugfix: Ghosts can now hear people who are EVA. - Runa Dacino: - - rscadd: Made Resomi security smocks available for detectives. - TheGreyWolf: - - rscadd: Added department ponchos to the custom loadout. - - rscadd: Added department and normal winter coats to the custom loadout. - - rscadd: Added a colorable scarf to the custom loadout. - - rscadd: Added lockets to the custom loadout. - - rscadd: added the formal outfit to the custom loadout. -2016-11-30: - Finalsong1: - - tweak: Changed the armor values for specialist vests, reinforcing that they're - designed to be used against that specific damage type. - - rscadd: Added the ability to order a practice laser carbine crate from cargo. - LorenLuke: - - rscdel: Got rid of the awful singletank code. - - rscadd: 'Created new singletank construction and disassembly code (see below): - Single Tank devices must be wired before having assemblies attached.' - - tweak: Single tank devices are single use only with their igniters. The igniters - create a small bit of heat to get fuel to its burn temperature (126C). - - tweak: Added relief valve to air tanks. They now trigger leak logic at over 173C - or leak pressure. Can be welded shut to prevent leakage. - - tweak: Single Tank devices must be wired before having assemblies attached. - - tweak: Air from rupturing/exploding tanks now merged into environment instead - of deleted. - - tweak: Explosion radii based on pressure, gas amount, and volume of rupturing - vessel. - - bugfix: Assemblies can now be used when attached. - PsiOmegaDelta: - - rscadd: 'New Ion law: Lawbound Synths may now have to communicate with the crew - in a random language other than Galactic Common.' - Zuhayr: - - tweak: The gibber is now called a meat grinder, since that's what it is. - - tweak: Eating a human organ or limb is now done in the exact same manner as any - other food. If you try to eat a limb, though, it will not be usable in a transplant, - for obvious reasons. - - tweak: Human organs now fit into the reagent grinder. -2016-12-03: - ForFoxSake: - - bugfix: Fixed a possible href exploit allowing any living player to speak any - language. - - bugfix: Organic beings can no longer speak Encoded Audio Language, although they - can still understand it just fine. - - tweak: Positronic brains can now speak Encoded Audio Language. - - tweak: Station manufactured Full Body Prosthetics can now speak Encoded Audio - Language. - Haswell: - - tweak: Renamed advanced voidsuit to advanced engineering hardsuit. - - tweak: Advanced engineering hardsuit now comes with in-built magboots and insulated - gauntlets that also fit Tajara and Unathi. - - tweak: Added more things that fit on the EVA hardsuit and advanced engineering - hardsuit's chestpiece. - Lorwp: - - tweak: Replaced Shoes in Engineering and Atmospherics Wardrobes with Workboots - Meyar: - - rscadd: The loadout limit has been upped to 10 from 5. - TheGreyWolf: - - rscadd: Added ability for cargo to order a firefighter closet under the engineering - tab. - - rscadd: Added Siik'Tajr as a native Tajaran sign language. - - rscadd: Towels are now in the athletic lockers in the fitness room by the holodeck. - Zuhayr: - - tweak: Ported Prometheans from Polaris, replacing slime people. - - tweak: Added water reagent interactions for Prometheans equivalent to acid. -2016-12-05: - FTangSteve: - - wip: RootSpeak is now split into a local and a global variant. For now the global - acts as a hivemind. - - bugfix: Diona nymphs now can only speak the local variant of rootspeak - Nero-07: - - rscadd: Changed the default option from 'Get random job' to 'Return to lobby' - if your preferred job is already taken. Should only affect new characters - Runa-Dacino: - - rscadd: Added ability to build press cameras to roboticist - atlantiscze: - - rscadd: 'Adds a new modular computer program: Classic Arcade, which is a computer - variant of the arcade machine, minus the prizes.' -2016-12-08: - Chinsky: - - tweak: Mecha sleepers do not KO victimes anymore. - - tweak: You can leave mecha sleepers like normal ones, by walking out. - Cirra: - - rscadd: Lawed synthetics (Borgs + AI) can now understand but not speak sign language. - Datraen: - - tweak: False walls no longer vent up and down. - FTangSteve: - - bugfix: Creatures without eyes can no longer be flashed. - Finalsong1: - - rscadd: Added a few more leather items to the botany biogenerator. - - rscadd: Replaces mead's sugar requirement with honey. Adds the ability to make - rum with mead's old recipe. - - rscadd: Surgical aprons are now available from the loadout. - Haswell: - - rscadd: Added a chemical hair remover. Also works on feathers, horns, anything - keratin-based. - Kel: - - tweak: Blobs can't spawn new blob cores within 2 tiles of an existing one. - - tweak: Secondary blob cores now look different. - - tweak: Removes message for attacking the blob to cut down on spam. - - tweak: Adds attack animation for attacking the blob. - Kelenius: - - tweak: Slimes will always imprint on those who feed them to avoid long streaks - of bad luck. - - tweak: 'RNG removed from the feeding: slimes now always get 20 nutrition per 5 - clone damage.' - - tweak: Slime nutrition drain reduced. - - tweak: Added a small delay between the slime latch and the first damage dealt. - - tweak: Changed how slimes react to damage. Slimes that are attacked with something - will sometimes be shaken off their victims (chance is force * 5 - anything with - force or 20 or above is a guaranteed shake-off). - - tweak: Disarming a slime or wrestling them off now has a chance to disorient them - for a moment. Throwing them off with a weapon doesn't do that. - - tweak: Water will make slimes lose their target, stop feeding, and will disorient - them for a moment on the first application (they will not be stunlocked and - repeated applications have no effect). - - tweak: Slimes now twice as weak to water - PLEASE remember that spraying them - more than once is a waste, the water is already on them and killing them. - - bugfix: Fixed a bug where slime's nutrition was always maxed out when they fed, - causing them to evolve and split instantly. - - bugfix: Slimes now guaranteed to have unique numbers. - - bugfix: Fixed an issue with monkey cubes not deleting in sinks. - - bugfix: Fixed a bug where a slime's location sometimes wouldn't update while they - were feeding. - PsiOmegaDelta: - - maptweak: Adds a new maintenance tunnel network below the station. It can be accessed - by one of 4 elevators and various ladders, assuming one has the access to enter - maintenance in the first case. - - maptweak: Atmospherics has been moved down to this maintenance level. - Runa-Dacino: - - rscadd: Added rolling pin and knife to service/butler borg modules. - - rscadd: Added ability to use the All-in-One grinder(Chemistry, Kitchen, etc.) - to cyborg/android/robot. - TheGreyWolf: - - tweak: Changed Resomii minimum age to 15 years old. - atlantiscze: - - rscadd: SPACE Magazine - Issue 5 is now available in the news browser program - - rscadd: To reduce clutter, the news program now hides older news articles. They - can be shown by toggling a button. - - tweak: News articles now use better data compression, therefore the files are - about 50% smaller. -2016-12-09: - Asanadas: - - rscadd: Surgery cyborgs get an update! Now with tramadol synthesizers, an upgraded - scalpel, a special organ manipulator, and a roller bed module. - - rscadd: Research cyborgs now possess an upgraded laser scalpel. - - rscdel: Surgery cyborgs no longer have a mini fire extinguisher. - - tweak: Cryo tubes, the genetic DNA scanner, and the advanced body scanner now - (also) operate with mouse-drop, instead of grab-put only. Useful for cyborgs. - - bugfix: The infamous sleeper mystery buckle bug has been fixed as a result. - Mark9013100: - - tweak: Gives rainbow gloves unique mob sprites. Credit to ChangelingRain. - PsiOmegaDelta: - - experiment: Sounds are now heard from 14 tiles away by default, rather than 21. - If the station becomes too quiet this can be adjusted. - - soundadd: New sounds added for when electrifying the door or rising and dropping - bolts. Requires adjacency to hear but ensures some foreplanning is needed to - remain stealthy. - - soundadd: The airlock close sound is now different from the airlock open sound. - - soundadd: Changes the airlock-blocked sound and reduces the range at which it's - heard. - sabiram: - - tweak: Fixed errant pixels in black jumpskirt icon, and genericizes description. - - rscadd: Added color selectable jumpskirts, available in loadout. -2016-12-11: - Kelenius: - - tweak: Health scanners now show radiation. - Techhead: - - tweak: The occupants of bodybags can now be scanned without opening them using - health scanners, similar to cryobags. -2016-12-13: - SiegDerMaus: - - rscadd: Added the ability to craft zip guns in game. Zip guns will also have their - own sprites and won't have to borrow the sawn off shotgun's anymore. - TheGreyWolf: - - rscadd: Added the ability for organ printers to also print out limbs. - sabiram: - - tweak: Adjusted crew manifest; shaft miners are now in the Cargo department, Quartermaster - and Cargo Techs are no longer in the civilian department. - - rscadd: Added color selectable hoodies to the loadout menu. - - bugfix: Fixes the sheet snatcher not collecting items on click. -2016-12-15: - Legius: - - bugfix: Shields produced by anomalies are now visible again and use the new shield - graphics. - Nero-07: - - rscadd: The cargo console now keeps track of how many points you earn during the - round and can print an overview showing what you did to get them. - TheGreyWolf: - - rscadd: Added new prosthetics sized for Resomi. -2016-12-26: - Cirra: - - rscadd: Added a preset combat cyborg which admins can spawn. - LorenLuke: - - bugfix: Keeps people from just using 'resist' to escape from nets instantly. - - tweak: Makes resist time random between 5 and 9 seconds to exit net. - - tweak: Sets net fabricator cooldown to 10 seconds (greater than max net resist - time). - - rscadd: Makes nets fade away even if not resisted out of after 15 processing_objects - ticks. - - tweak: Makes it so that netted people cannot use items (and shoot/baton you while - 'restrained' by the net) until freed. - PsiOmegaDelta: - - rscadd: Resetting a character slot now requires confirmation. - - rscadd: Character saves are now per map. - SiegDerMaus: - - rscadd: Adds a new non-lethal weapon. For now, it will remain adminspawn only - for testing, it may be mapped into the armoury later. - TheGreyWolf: - - rscadd: Mousetraps are now orderable from cargo. -2016-12-29: - Chinsky: - - rscadd: Added some hints for filthy civilian scum. Gosh, some people - - rscadd: You can click on [WRONG BRANCH KIDDO] type messages to get info on what - branch/rank is right for this job. - - rscadd: All open jobslots can be seen again in latejoin, but if you try to pick - one with wrong branchrank, you get message about it with hints. - Cirra: - - rscadd: Added a unified radiation system. Radiation is lessened by obstacles, - and distance. - - rscadd: Added a geiger counter for measuring radiation levels, which can be found - in certain vending machines and radiation closets. - Kelenius: - - bugfix: Monkey cubes won't hang the server for a second or so each. Now it's only - about 0.2 seconds each. - Legius: - - maptweak: Added missing emergency shutters to command section. - Meyar: - - experiment: Removes cloning boards from being player accessible without admin - intervention. - Nero-07: - - rscadd: Ported the defibrillator from tg. - PsiOmegaDelta: - - rscadd: Ghosts are now able to follow a much wider variety of things, not merely - mobs, and the entries are a bit more detailed. Inspired by a similar implementation - by Kelenius. - atlantiscze: - - rscadd: Show server revision verb now also lists which map is being used. - - rscadd: Skill descriptions in character setup now contain more detailed information - on differences between varying skill levels. - - tweak: Command, Cooking and Botany skills are now secondary. Engines skill is - no longer secondary. Existing character setups shouldn't be affected, but it - is still advised to check that your skills are set correctly. - - tweak: The skills in character setup have been reordered a bit. -2016-12-31: - HarpyEagle: - - bugfix: Doors leading to open elevator shafts now require a little more effort - to open. - Kelenius: - - rscadd: Station dwellers have re-discovered the ancient art of spraying contents - of fire extinguishers directly at people, instead of floors around them. You - need to be at help intent and click the mob with the extinguisher to do it; - other intents still make you attack. - Loneguyfly: - - rscadd: Changes Taj blood to be visually distinctive from human blood. - Nero07: - - rscadd: Added a program to modular computers, that can be used to create/edit/delete - digital warrants. Also added a mobile device named 'holowarrant', that can be - used to sync up with the central warrant list and display these warrants in - the field. - Ravenxales: - - rscadd: Add toggleable safety for compressed matter implant, to prevent inadvertant - usage and facilitate storage. - - bugfix: Fix compressed matter implants that are placed in storage from destroying - the storage with itself inside. - Redstryker: - - rscadd: Adds a blue resprited version of Latex gloves called Nitrile gloves. They - can be found in the sterile glove box and on the loadout. - - rscadd: 'Added three different hairstyles: Undercut, Coffee House Cut, and Parted - Fade' - sabiram: - - rscadd: Added hotkeys for moving up and down z-levels. The hotkey for moving upwards - is ,(COMMA), and the hotkey for moving downwards is .(FULL STOP) -2017-01-04: - Cirra: - - rscadd: Re-enabled the radiation storm event - - rscadd: Radiation collectors now work with general radiation, as well as singulo-specific - pulses. - - rscadd: The engineering module now has a geiger counter. - - bugfix: Humanoid mobs will no longer ignore radiation levels below 5Bq. - - bugfix: Blast doors now properly block radiation. - HarpyEagle: - - tweak: Burn damage causes by lasers results in less blood loss. - - tweak: Laser protection offered by many types of armour given a modest boost, - bringing laser protection up to match bullet protection in most cases. - - rscadd: Laser beams have a chance of dealing internal organ damage much like brute - damage. - Kelenius: - - experiment: Bot AI has been overhauled, hopefully for the better. - - experiment: Navigation beacon (and, therefore, patrol) code has been changed; - please report any issues with bot patrolling. - - tweak: Mulebots can't be hacked for speed anymore. They move at moderate speed. - Safeties can still be disabled. - - tweak: Floorbots don't try to fix space anymore; instead they will remove broken - tiles. They can be configured to cover platings, too. - - tweak: A farmbot has been added to the garden, and a floorbot to engineering storage. - Loneguyfly: - - rscdel: Removes the silence and paralyze effects from deathsting. The ability - will now only cause jittering and an injection of lexorin. - LorenLuke: - - bugfix: Can now throw held people again. - - rscadd: Clicking a grab while in help intent downgrades the grab a step. - Minijar: - - rscadd: Changes the colour of unathi blood. - Redstryker: - - rscadd: Added a colorable hair bow to the loadout. - - rscadd: 'Added three facial hairstyles to be used for Humans: Mutton Chops, Mutton - Chops and Moustache, and Walrus Moustache.' - - tweak: Made all of the medical bags have blue crosses on them instead of green - crosses. - - rscadd: Added messenger bags variants for all of the jobs. They can be selected - from the character setup. - - rscadd: 'Added four colorable underclothes: long john tops and bottoms, tube top, - and long undershirts.' - Runa-Dacino: - - tweak: Changed stack recipes to spawn product in hands when possible, otherwise - spawn on the ground.. - - rscadd: Enables the text replacer that makes verbs such as *aflap use visible - gender for all *verbs instead of using 'its.' - - bugfix: Fixes preset emotes to write himself and herself instead of heself and - sheself. - Techhead: - - rscadd: Brings back the evil to evil vending machines. However, their throwing - arms aren't as good as they used to be, so if you don't walk up to them, you - should be fine. - TheGreyWolf: - - rscadd: Upped the damage from 5 to 10 brute possible per limb when falling down - a z-level. -2017-01-06: - Hubblenaut: - - tweak: Hydroponics vendor and biogenerator offer full bottles of fertilizer. Prices - and amount available adjusted to accomodate. - Redstryker: - - tweak: Changed the sprites of the biosuits to have gloves and boots. Gives them - the appropriate inventory flags to cover gloves and shoes. - - rscadd: Added toeless workboots. Added them to the loadout. - - rscadd: Added athletic shoes. Added them to the loadout with the ability to color - them. - - rscadd: 'Added the following hoodies to the loadout: NanoTrasen, Space Mountain - Wind, Mariner University, and Ceti Techical Institute.' - - tweak: Changed the 'Mars University Lunchbox' to the 'Mariner University Lunchbox'. - - tweak: Gave boots and gloves to the normal and Resomi variation of the radsuits. - Runa-Dacino: - - bugfix: Fixes pain messages giving errors saying emote 'me' doesn't exist - - tweak: Changed generic 'their' to use visible gender for aforementioned pain messages. - Soadreqm: - - rscadd: Alter procedure for dismantling broken, bolted doors - - rscadd: Made the fire axe more robust against doors. - Zuhayr: - - rscadd: Added a constructable improvised coilgun and two adminspawn railguns. - Credit goes to Siegdermaus for the icons and the commission. No, I'm not going - to tell you how to build it - that's the fun. -2017-01-08: - Cirra: - - tweak: Changed the radiation storm event's end message to indicate that radiation - will take time to decay. - Redstryker: - - soundadd: Added four sounds that are randomly played when bones break. - - rscadd: Added a hanging skeleton model as a furniture item for all your spooky - needs. - sabiram: - - rscadd: The Chief Medical Officer now has maintenance access on the Exodus. -2017-01-11: - Chinsky: - - rscdel: Removes Pun Pun's naked ass. Little pervert was wearing assless jeans - under that hawaii shirt the whole time, fixes them to cover the buttbits properly. - - rscdel: Removed hallucination part of SM delamination event. - Cirra: - - imageadd: Added a new set of PDA sprites. - Hubblenaut: - - tweak: Doubles power for rechargers and wall rechargers. - - tweak: Raises power for cell rechargers from 40 kW to 60 kW. They will still recharge - quickest. - Kelenius: - - tweak: Brand intelligence event now tells you the name of the original machine. - Original machine will now swear more often to make it easier to find. The event - also ends (fixing all machines) when the original machine's shooting is disabled, - not only when its speaker is off. - - rscadd: A customizable tablet has been added to loadout - remember that better - parts use more power. - Lorwp: - - rscdel: Removed Stunbatons from Medbay - - maptweak: Reorganized the Paramedic's Station - Minijar: - - rscadd: Adds Uzi, Deagle, .38 revolver,Combat shotgun and a sawnoff shotgun to - the uplink. As well as appropropriate ammo. - - rscadd: Adds all of the above ammo types to the autolathe. - Nero07: - - rscadd: Dead people now keep processing reagents for 15 seconds after they died - Redstryker: - - rscadd: Added colorable flats to the loadout. - - tweak: Adds defined role variables to the Torch loadout in order to reduce clutter. - - tweak: Fixes the dark red jumpsuit to reflect it actually having a belt on. - TheGreyWolf: - - rscadd: Restricted Resomi prosthetics to limbs only. No more Resomi FBP. - - rscadd: Changed the resomi white smock to instead be colorable. - Zuhayr: - - tweak: The limb damage indicator on the HUD now uses local limb pain, not traumatic - shock. - - tweak: custom_pain() (used in surgery, moving bones, etc, to make a pain message) - now increases pain on the limb calling it. In other words, non-anesthetised - surgical pain now has a purpose other than giant red text. - chinsky: - - experiment: SM delamination no longer causes hallucinations, but has bigger explosion. -2017-01-16: - Hubblenaut: - - tweak: Can now click on turfs with trash bags and similar to quick-gather everything - on it. No longer pixelhunting for cigarettes and bullets. - - bugfix: Buckets and other reagent holders will no longer simply be put into the - janitorial cart's trash bag. - Kelenius: - - rscdel: Resomi FBP construction made physically impossible, STOP MAKING THEM. - Same for Diona and IPCs. - Ravenxales: - - bugfix: Allow protected roles (heads, IAA, etc.) to be converted to faction antags - (cult and rev) mid-round - - bugfix: Make implants work properly again (can configure triggers, etc.). - - bugfix: Made turbolift doors more robust. Small mobs will be displaced, large - mobs will make the lift give up and reopen. - RedStryker: - - bugfix: Added the skeleton stand file to the Baystation12.dme. - Redstryker: - - rscadd: The sterile mask can now be toggled down and up like breath masks. - - tweak: Refactored the pull down mask verb and proc. - TheGreyWolf: - - rscadd: Made Resomi sprites for the scarf. - - rscadd: Fixed so people can once more have mechanican eyes and heart. - atlantiscze: - - tweak: All modular computers now support a tesla link, allowing them to run off - an APC. This includes tablets. - - tweak: Both tablet presets from custom loadout now have a tesla link by default. - - bugfix: Tesla link now also works for laptops when they are closed. - - tweak: Size of tesla link and intellicard slot reduced, which means they can now - actually fit into tablets. -2017-01-18: - Finalsong1: - - rscadd: Adds a piloting skill. - Haswell: - - tweak: Clicking on worn or held boots containing a concealed blade will now draw - the blade out directly, similar to gun holsters. - - tweak: Masks that can be pulled up/down now have action buttons for toggling. - Kelenius: - - bugfix: Fixed issues where you were unable to turn the bots on and off when you - should have been. Farmbot specifically. - - tweak: Synthetics can always control all bot settings. - - tweak: Synthetics and anyone who opens the bot's panel (screwdriver) can toggle - bot safeties, giving it a 'temporal' emag effect that can be fixed in the same - way. Emags break them permanently, but this is obvious when the panel is open. - RedStryker: - - rscadd: Added glowsticks in green, blue, red, orange, and yellow. Work similar - to flares, but burn twice as long and half as bright. Can be found in the YouTool, - party equipment, and random drops. - - soundadd: Added sounds that play when the cheap lighter is turned on and when - the Zippo is lit and turned off. - - bugfix: Changed the name of the long john shirt icon_state so that it can actually - be used. - TheGreyWolf: - - rscadd: Added a new coat to the custom loadout for Resomii. -2017-01-19: - Chinsky: - - bugfix: When reattaching limb, hemostat finish step is REQUIRED now. On the other - hand, limbs are now properly reattached without leaving cut-away status forever. - - tweak: For bone gel steps you can use duct tape now. Screwdrivers aren't used - anymore. Also reworded messages there to be less awkward. - Hubblenaut: - - rscadd: Added icons for the energy gun's shock firemode - - bugfix: Fixes items appearing in the wrong hand. - Ithalan: - - bugfix: Fixed spawning of wrong version of the medical hardsuit in medical. - RedStryker: - - rscadd: 'Added track pants and track jackets in the following colors: white, green, - red, and blue. Added a track jacket for the normal track pants. Added the jackets - to the loadout.' - Redstryker: - - rscadd: Added flannels. It is on the loadout with the color selection datum. It - can have its sleeves rolled up, be buttoned, or be tucked in and any combination - thereof. - - rscadd: Added high tops. Added them to the loadout. -2017-01-21: - Hubblenaut: - - tweak: Floor painting reappears when putting on new plating. - Kelenius: - - rscadd: New cult gamemode is in. Refer to https://wiki.baystation12.net/Cultist - for the updated guide. - - rscadd: Added beekeeping equipment to garden. - - tweak: Open space in engineering is now covered with lattices. - - bugfix: Space vent in toxins is no longer blocked. - Redstryker: - - rscadd: Added cigarette packet 'microlore'. Background information that can be - found in the examine tab. - TheWelp: - - rscadd: Adds universal action HUD element. - - rscadd: Moves spells to new action HUD. - - rscdel: Removes mind transfer. -2017-01-24: - Kelenius: - - tweak: Ghosts can't use their abilities in holy places (non-defiled chapel or - anything touched by holy water) anymore. - - tweak: Confuse rune doesn't blind people, only blurries their vision. It still - stuns as before. - - tweak: It takes longer to unlock tear reality rune and ghost abilities. - - bugfix: Many cult-related bugfixes. - SiegDerMaus: - - rscadd: Added swords for Torch dress uniforms. - Yoshax: - - rscadd: Adds drop pouches that are functionally the same as the various types - of colored webbing, but look different. Are available in loadout and can be - found in webbing crates. -2017-01-28: - HarpyEagle: - - rscadd: Defibrillators will now notify when the patient cannot be revived due - to excessive blood loss. - Kelenius: - - rscadd: Can now configure headset by click-dragging it to screen, similarly to - PDA. - - bugfix: Alien suit sprites have been fixed, as were inhands. - RedStryker: - - rscadd: Added microlore to some soda/drink containers. -2017-02-01: - Ace McLazer: - - tweak: Updated generic colored poncho look, tweaked all to look more human-shaped. - Changed Resomi ponchos, too. - Cirra: - - rscadd: Added a new alloy, Osmium-Carbide Plasteel. It is physically weaker than - plasteel, but is more resistant to heat, and is made like plasteel but with - added osmium and extra carbon. - Haswell: - - maptweak: Reduced Torch map sizes from 255x255 to 200x200. Admin Z is now split - into two. Reduced world initialization time by about 2 minutes. - Hubblenaut: - - bugfix: Fixes mob icons not updating when blood is washed off. - Kelenius: - - tweak: Garden got most of their plants back. The only plants exclusive to xenobotany - now are ambrosia (blame chinsky), kudzu (too dangerous), plastellium (useless), - alien seeds, and randomly-generated ones. - - tweak: Seed storages now start with 30 of each seed type, not 2 or 3. - - rscadd: Xenobotany now starts with 30 of each type of alien seeds (previously - only available from fossils) and 10 random seeds. - PsiOmegaDelta: - - tweak: Climbing ladders now takes 2 seconds. As a side-effect climbing can now - also be aborted by moving away. - - tweak: Anyone near the destination ladder are now also made aware that someone - is (potentially) about to arrive. - SiegDerMaus: - - rscadd: Adds one new haircut, a chin-length bob. - Zuhayr: - - rscadd: Added haywire rounds for shotguns and some calibers of small arms. - - tweak: You now need to target head/eyes/mouth when trying to slit a throat. - - rscadd: Added tendons and tendon repair. Tendons can be severed by cutting brute - damage or via a grab (similar to cutting a throat) and if cut will render the - limb unusable. Hands, feet, arms and legs have tendons. - - rscadd: Added arteries, replacing the previous internal bleeding implementation. - Functionally identical to the internal bleeding of yesteryear including repair - surgery. - - tweak: As a result of the above, internal bleeding is now static per limb and - cannot be treated via bicaridine and inaprovaline overdose. - - tweak: It is no longer required that the skull and ribcage be opened to repair - internal bleeding or eye damage. A retracted incision is still required. - - rscadd: Adminhelps now have a TAKE button that allow an admin to claim it, and - inform the adminhelper that someone is on the case. - sabiram: - - tweak: Split the Command department on the Torch into Heads of Staff and Command - Support. - - tweak: Moves the Exodus cargo team to Supply, the bartender, gardener, chef and - janitor to Service, and Internal Affairs to Support. - - rscadd: Added the command, support, service and supply departments to the ID computer. - Added the support, service and service departments to the manifest. -2017-02-06: - Cirra: - - rscadd: Bluespace tiles created by the Supermatter Cascade will now spread between - z-levels. - Datraen: - - rscadd: Added a gene-specific mode for the Floral Somatoray. - - tweak: Plant controller now generates the mask/tag list used by the centrifuge, - rather than generating it on ui_interact. - Hubblenaut: - - bugfix: Forensic tools (and other items) will no longer be used when putting in - backpacks or on tables. - - tweak: Taking forensic samples will first take evidence, then leave your own fingerprints/fibers. - - rscadd: Added click-and-drag function to forensic tools to take evidence where - you previously couldn't. - - rscadd: Allows chest drawers to store forensic samples. - Kasuobes: - - tweak: Suit storage units now hold magboots and air tanks. - - tweak: Voidsuits can now toggle installed helmets via action button when worn. - Kelenius: - - rscadd: Fossil plants can now be fed to seed extractor to get one random seed. - - rscadd: Placed mining flags now have have a glowing fringe, visible in the dark. - - rscadd: Plush toys added to loadout. - - rscadd: Resomii 'nearsightedness' is now correctly prevented by equipment that - blocks bright lights, not prescription glasses, and goes away in the dark. - Lorwp: - - tweak: Change's Brig Officer's holobadge box to have Master At Arms Holobadges - - tweak: Allow Security Messenger Bags to be able to spawn in Security Lockers - - tweak: All Security have Work Gloves in their lockers now - PsiOmegaDelta: - - rscadd: Admins can now delete specific obj instances from the VV menu, not only - all of the same type. - - bugfix: Power monitors now list all powernet sensors belonging to the current - and connected Z-levels. - TheWelp: - - rscadd: Adds the Vox weapon the Slugsling - - bugfix: Fixes launchers not playing a sound on firing. - chinsky: - - bugfix: Fixes surgery openness stage not applying gory overlay. Gore is back. -2017-02-07: - Cirra: - - bugfix: Radiation from the Supermatter delaminating should now properly affect - all connected z-levels. -2017-02-10: - Asanadas: - - tweak: Scrubbers now scrub N2O and Phoron by default. - - maptweak: The corners of Escape Pods 3 and 4 should now no longer appear to lead - to space. - - tweak: Officer swords should now look good from all angles. - Haswell: - - tweak: Mop buckets and janitor carts can now be climbed over. - Nero07: - - rscadd: Added communications functionality to AI holopads. To use, stand on a - holopad and click it. Make a new holocall and select the target pad from the - list. The targetpad will light up, emit a sound and inform nearby players about - the incoming call. To pick it up, just click the pad. The caller is projected - above the holopad and can talk to/emote with all people in view of the holopad. - To end the call, step off the holopad. The call can also be ended from the other - side by clicking the active holopad. -2017-02-12: - Essbie: - - rscadd: 'Added new cocktail and recipe: Ship''s Surgeon.' - HarpyEagle: - - bugfix: Fixed bluespace jump lag. - - bugfix: Fixed latejoins during bluespace jump not being affected by it. - - bugfix: Fixed being able to enter/leave the vessel zlevels during bluespace jump. - - rscadd: Moving in straight lines during a bluspace jump is now more difficult. - - tweak: The amount of toxin damage gained from low blood levels is now limited - to around 18. - - bugfix: Various defibrillator fixes. - - bugfix: Difference between the two cult ghost whisper verbs should be clearer - now. - - bugfix: Meteors no longer destroy floors or anything else that doesn't block their - movement. - Haswell: - - tweak: Removed ghost verb from AI and pAI due to overlapping function with wipe - core and wipe software verbs. - Nero07: - - bugfix: Added a busy signal so you can't call already active holopads, which led - to message spam. - - bugfix: Makes holopads actually function and fixes a few runtimes associated with - them. - TheGreyWolf: - - tweak: Made it so only unbranded, NT and Resomi specific prosthetic brands can - be made during gameplay, chargen not changed. - Zuhayr: - - tweak: Bleed-out rate now depends on pulse rate and size of bleeding limb. - - tweak: This means that potassium chlorophoride, which stops the heart, and inaprovaline, - which now slows the heart, are both suitable for emergency treatment of bleeding. - - rscadd: Cautery surgery with no preceeding steps will now cauterize a cut artery - in a stump. - - tweak: Arterial bleeding and stumps are now more informative about where the bleed - is. - - tweak: Arterial sprays can now splatter/blind people and use the correct icons. -2017-02-14: - Haswell: - - rscadd: Added waist packs that can be worn around the waist or on the back. They - can be found in custom loadouts under utility. - atlantiscze: - - rscadd: Added modular telescreens - wall mounted modular computers that are comparable - to laptops in terms of hardware restrictions, and tablets in terms of software - restrictions. Few of those have been mapped in, more can be built. - - tweak: Large amount of under-the-hood improvements and tweaks. - sabiram: - - rscadd: Added subtypes of meat for cows, goats and chickens. They all act the - same way. - - rscadd: Added crates containing beef, goat meat, chicken meat, eggs, and milk. - - tweak: Increased the price of the livestock crates so that it is much more economical - to order the produce you want instead of a live animal. -2017-02-15: - RedStryker: - - bugfix: Allows department-specific messenger bags to be used. - lorwp: - - rscadd: PAI's can now speak EAL, if they have a Universal Translator' - sabiram: - - rscadd: Adds some new hairstyles. For the Torch, Short Hime and High and Tight - are approved for all Sol personnel; Grande Braid and Fringetail are approved - for the Expeditionary Corps only. All new styles are freely available to all - civilians. - - tweak: Adjusts luminosity on a few hairstyles to correct desaturated spots. -2017-02-18: - Haswell: - - rscadd: Added boxes of headsets to the Torch XO locker. - Lorwp: - - rscadd: Added Trendy messenger bags to all Job Lockers - sabiram: - - rscadd: Added modular laptops to the utility loadout menu. -2017-02-21: - Asanadas: - - bugfix: You now require an under-clothing (such as a jumpsuit) to wear things - on your belt. No more PDA in your boxer waistband. - - bugfix: Mushroom soup can now be made with a sane ingredient combination. - Chinsky: - - rscadd: Accounts with biggest profits or losses are now announced in round end - summary. Get dat greentext. - - tweak: Surgery changes. Cry, medical. - - rscadd: Self-surgery is legal now. It was possible via a bug, it's a feature now. - - rscadd: As a side effect, you don't have to lie down to be operated on. It is, - however, a very bad idea unless it's basic steps like incision etc. Success - chance will drop for delicate steps. - - rscadd: Instead of randomly doing nothing, rollerbeds / tables are factored into - surgery success chance calculation. - - rscadd: 'Said success chance: surgery steps now can fail even if you don''t move - / drop tools etc. Ideal scenario is ''sober surgeon not in pain operating on - another person who is lying on an optable''. Deviations from that add chance - of failure. Some steps are more robust, some are more delicate. As a rule of - a thumb, if you have to touch innards, that''s delicate. If you perform internal - organ surgery on yourself while sitting on a table piss drunk, nearly passing - out from pain and also being blind, it''s not going to go very smooth.' - - rscadd: Shock will advance fast when being surgery'd on, so take it slow or take - some pills. - Haswell: - - maptweak: Destroyed the cloning lab on Exodus and all technology related to it. - atlantiscze: - - rscadd: Added forced-shutdown verb to modular computers, reachable via rightclick - menu. This is equivalent of pressing the Shutdown button in the UI, and is mostly - intended to be used when UI bugs out and regular shutdown isn't available. - - rscadd: Added Supermatter Monitoring program, available on all devices. It provides - various information on the supermatter engine. It is fully variable, and capable - of working with multiple supermatter crystals at once (for those enterprising - engineers among you). - - rscadd: Among other information, the supermatter monitor program shows engine - core EPR value. This value is best kept between 1 and 2, and shows real amount - of coolant in the core (in standard canisters worth). Normal EPR with two canisters - in each loop is roughly 1.5 - - rscdel: Rightclick open/close laptop verb no longer exists for laptops. Use alt-click - instead. -2017-02-24: - Chinsky: - - rscadd: PI now spawns with a badge, Journalist with a camera. Also added tape - recorder to custom loadout. - Cirra: - - soundadd: Added several new sound effects. These include fire extinguisher cabinets, - internals activation, flashlight/flare activation, air alarm breach detection, - and more. - - soundadd: Added ambient sounds to Thermo-Electric Generators. - - bugfix: Braces can no longer be removed from an airlock by deconstructing the - airlock. - - bugfix: Pipes will now correctly burst if the internal pressure is too high. 0-16.9MPa - is safe, 17-20.9MPa has a chance of bursting, and 21MPa+ will burst instantly. - - maptweak: Osmium-Carbide Plasteel walls have been mapped into the incinerator. - It should now be safe to use the incinerator, as a result. - Crushtoe: - - imageadd: 'Two new pAI chassis types: The Mushroom and the Corgi Puppy. Finally, - we can have our pAIs join the Mushroom Plague.' - Haswell: - - tweak: Antag preferences now default to never instead of low. - Runa-Dacino: - - rscadd: Adds ability for the player to change the name and description of ninja - voidsuit to assist in ninja gimmicks - - rscdel: Removed references to the spider clan from ninja voidsuit. - TheWelp: - - rscadd: Adds a integrated circuit printer to the R&D lab. -2017-02-26: - Chinsky: - - tweak: Holowarrant projectors now autosync when clicked in hand instead of having - to use verb manually. - - tweak: You can swipe ID at the holowarrant to authorize it now. - Crushtoe: - - imageadd: New external airlock and mail sign sprites. - Datraen: - - bugfix: Language sanitation now checks for species second languages in addition - to whitelist status. - Haswell: - - rscadd: Added crossfire gamemode, mercenary + raiders. Requires 25 readied players - and at least 6 antags to start. - Hubblenaut: - - rscadd: Newschannels now show the number of times they have been viewed. - TheWelp: - - rscadd: Adds an advanced integrated circuit radio. Lets players send commands - and id_tags. -2017-02-28: - Haswell: - - rscadd: Added Siege gamemode, mercenary & revolution. Requires 20 readied players, - 5 antags. - - rscadd: Added Unity gamemode, revolution & wizard. Requires 15 readied players, - 5 antags. - - tweak: Made Conflux votable, cult & wizard. Requires 15 readied players, 5 antags. - - tweak: Made uprising votable, cult & revolution. Requires 20 readied players, - 6 antags. - - rscadd: Added small energy gun variant, small size with 4 shots and reduced lethal - damage. - - rscadd: Added gun cabinet variant with small energy guns. - Nero-07: - - bugfix: Fixed holopads and tested them a bit more extensively. Should work as - expected now. - Techhead: - - tweak: Torch medical has been reorganized, full changes follow. Check your job - settings on medical characters. - - tweak: Senior Physicians are now simply Physicians, and the job is limited to - officers. - - tweak: Physicians are now Corpsmen, with updated alt-titles, including the new - Medical Technician and Field Medic titles. - - rscadd: A unique outfit for Fleet Field Medics. - - tweak: Medical Assistants are now Medical Contractors, with two slots. Medical - Resident title is gone. - - rscdel: The dedicated Virologist slot is gone, now part of Medical Contractors. -2017-03-07: - Chinsky: - - bugfix: Fixes not being able to bring up undress menu on help intent. - - tweak: You scoop up resomi/monkeys/nymph on GRAB intent now, not help. Was annoying - in surgery etc. - - rscadd: Can now put accessories on people via strip menu. Click on the clothing - item with accessory in hand to attempt to. - - rscadd: Can now pick which accessory to remove in stirp menu. - - rscadd: Explosive implants now can be triggered by remote signaler signals. Change - frequency and code in implantpad that now comes in the box with implant. - - rscadd: Explosive implants now complain on radio when they are exposed in surgery - (after retractor step for skin/ribs). Can set message in implantpad. - - rscadd: Added thicc rig to merc base. It has bit more slowdown, but more armor - overall. - Haswell: - - tweak: Improved movement smoothness with /tg/ movement code. - - tweak: People now spawn with random hunger levels between hungry and satiated. - - tweak: Reduced amount of satiety from eating by 66%. - - tweak: Ghosting messages now show where the player is ghosting from. - Hubblenaut: - - rscadd: 'Adds new haircut: Ponytail 6.' - Techhead: - - rscadd: Added a black tie outfit to the uniform vendor for civilians. - - rscadd: You can now pin medals to your service and dress jackets. - - rscadd: As a bonus, you can also put armbands on labcoats. - TheWelp: - - bugfix: Fixes circuit printer being a computer recipe instead of a machine - - rscadd: Adds ability to deconstruct an assembly and gain a protolathe recipe for - it. - - bugfix: Fixes circuit printer not having a max cap on metal. - - bugfix: Fixes certain activators not being respected when there are multiple of - them. Fixes debugger not sending activator data. - - rscadd: Adds accelerometer circuit, which lets you detect motion (and how much). - - rscadd: Adds simple locomotion circuit, which uses activators alone to control - itself. - - rscadd: Adds ai-controlled circuit. Lets ai inside itself use arrow keys to activate - certain pins. - - rscadd: Adds tile sensor, which detects items/mobs on a tile when pulsed. - atlantiscze: - - experiment: Removed bunch of NarSie's summon effects. Should considerably help - performance. - - tweak: Cult walls now have non-reinforced type, that is used when cultifying non-reinforced - walls. - sabiram: - - rscadd: Standard and research magnetic grippers can now hold modular computer - hardware. - - rscadd: Research module robots now have access to wirecutters. - - rscadd: Replacement tubes for spotlight fixtures are now available in the autolathe - and in most light tube boxes. - - rscadd: Added a new black leather satchel to the backpack selection menu. -2017-03-12: - Asanadas: - - maptweak: The Morgue now has emergency shutters. Also, more emergency shutters - spread around the infirmary. - Chaoko99: - - imageadd: Added a unique sprite for anesthetic pumps. - Cirra: - - rscadd: Pipes with exposed ends (such as those that result from a pipe bursting) - will now leak their contents into the air. To stop a pipe from leaking, attach - an endcap to the end. - - rscadd: Added Stasis Clamps to engineering vending machines, devices which can - be attached to a pipe and turned on in order to halt the flow of gas through - that pipe. Useful for sealing off sections of pipe so you can make changes without - leaking. - - rscadd: Added and mapped in Automated Shutoff Valves, which will automatically - close if their internal pressure gets too low, to limit the damage caused by - main-loop leaks. Click on an AS Valve to reset it. - Datraen: - - rscdel: Removed the hunger section of movement code. - - tweak: Doubled the rate of nutrition degradation. - - tweak: Raised the starting nutrition values. - - tweak: Reset the rate of nutrition degradation to the default value. - Hubblenaut: - - rscadd: Adds alt-click shortcut for initiating test-fire. - - rscadd: Examining the teleporter console will reveal its current destination and - accuracy. - - tweak: Teleporter accuracy does no longer automatically reset after five minutes. - - tweak: Teleporter accuracy resets after locking in to a different destination. - sabiram: - - rscadd: You can now alt-click a PDA to remove an ID. -2017-03-14: - Haswell: - - rscadd: Added ion pistols, 8 shots no AOE, normal size, can be worn on belt and - holstered. - - rscadd: Added taser carbines, 10 shots, heavy taser and heavy shock beams, large - size, can be worn on belt and back. - - rscadd: Added stun rifles, 12 stun shots, huge size, can be worn on back. - - tweak: Reinvented pulse weaponry. They now function as burst fire laser weapons, - dealing less damage per shot but with higher damage potential than their laser - counterparts. Most effective at medium ranges against non-armored targets. - - rscadd: Added pulse rifles. 36 pulse shots, high damage. Huge size, can be worn - on back. - - rscadd: Added pulse carbines, 24 pulse shots, medium damage. Large size, can be - worn on back and belt. - - rscadd: Added pulse pistols, 21 pulse shots, low damage. Normal size, can be worn - on belt and holstered. - - maptweak: Adjusted security and emergency armory contents. Added more guns. - - tweak: Added pulse weapons to uplinks. - Unknown: - - bugfix: Stasis Clamps should now function correctly when placed next to a pump, - valve, or other pipe machinery. -2017-03-26: - Asanadas: - - tweak: Orange shoes (as well as jumpsuits of all kinds) no longer are capable - of doing damage. - - rscadd: 'Added new drug/medicine: Noexcutite. Useful to eliminate jitteriness - in patients. 1 Oxycodone, 1 Dylovene.' - Chaoko99: - - rscadd: Crisis borgs can now pick up pills. - - rscadd: Science borgs can now pick up tanks, tank transfer valves, and various - other assembly items. - - imageadd: Replaced the old [CAUTION] Canister with a cleaner sprite. - - imageadd: Added a hazard stripe overlay for people to add to new canister sprites - in DM. - - imageadd: Added new phoron sheet sprite. It is orange now. - - imageadd: Added a new icon state for the admin spawnable crystal. - - tweak: Most solid phoron and phoron-based objects are orange now. Please report - old pink/purple phoron sprites on the git repo, tag @chaoko99 in the description. - - tweak: Uncommented the phoron-based object flashing code. Phoron based objects - will now combust when on a turf over 200c. - Chinsky: - - tweak: Tabling is no longer instant. Wait till aggressive grab is done upgrading - before do it (whe blue thingie is done filling). - - rscadd: Can now click yourself with cig to take a drag on it. - Haswell: - - tweak: Renegade guns now all fit in backpacks, provided there's room in there. - - tweak: Duct tape now repairs supermatter. - - rscadd: Added flashdark device, basically a flashlight that cloaks you in darkness - instead of light. Available in uplinks. Pair with thermal scanners for fun. - Hubblenaut: - - bugfix: Fixes whitespace cropping when writing on paper or using the circuit debugger. - Ravenxales: - - tweak: Fix many strings to respect the Torch environment. - RedStryker: - - tweak: Added new lore-consistent clothing items for NanoTrasen personnel. - Techhead: - - rscadd: Moves Junior Enginner to a Crewman alt-title, accompanied by the new Junior - Corpsman. - - tweak: Increased Crewman slots by one and removed age restriction. - - rscadd: Gave Raiders their very own frequency. Hopefully, no more filthy mercs - listening in on your distinguished matters of commerce. - TheGreyWolf: - - rscadd: Added uniform, dress and formal uniform for Resomii from unused sprites. - memescope: - - tweak: Gave the Scientist, RD, Senior Researcher and Research Sssistant access - to formal clothing in the loadout. - - tweak: Divided pants into formal and casual pants and put them into different - selections in the loadout. - mkalash: - - rscadd: Admins can now globally and individually mute AOOC. - - rscadd: Added a stun revolver to the NT guard lockers. - - rscadd: The Torch will now receive a report at the beginning of the round listing - the current system, the next system, and any nearby planets. -2017-03-31: - Asanadas: - - tweak: The holodeck theater's clothings have been changed to holo-chameleon equipment. - Have fun with more dress-up options! - Cirra: - - maptweak: Removed the Pulse Rifle from the emergency armoury, and replace it with - a marksman energy rifle. - Datraen: - - bugfix: Updates mechs to be able to interact with ID cards in wallets. - Leshana: - - bugfix: Fix rooms holding pressure when exposed to space. - RedStryker: - - tweak: Added new lore-consistent PDA, Locker, and Action Figure sprites for NanoTrasen - items. - - rscdel: Removed science armband. - - tweak: Recolored research tape to white. - Sin2: - - tweak: Added new lore-consistent airlock sprites to Research. - Unknown: - - imageadd: Replaced the energy sword and double saber sprites with those from TG. - - imagedel: Removed the Sord and Sord inhands. -2017-04-01: - Haswell: - - rscadd: Added singularity grenades. Works just about as well as you imagine. -2017-04-06: - Broseph Stylin: - - rscadd: Added a colorable and a horrible bowtie to the loadout, available to all - non-military roles. Icons by LorenLuke, slightly altered. - - rscadd: Skirt versions of the dress uniforms are now available for all SCG branches - in the uniform dispenser. - - bugfix: Officer's variants of the dress uniform will now show up correctly in - the dispenser. - Chaoko99: - - imagedel: Removed unused reagent container sprites. - - tweak: Removed the toy sunflower, replaced with another flower that functions - identically, but can accept reagents other than water. - - spellcheck: Added punctuation to wizard spells, and adjusted some of the shouts - to something a human being could actually say consistantly. - CountAlex: - - tweak: Added deluxe version of electronic cigarette to loadout. - - rscadd: Added electronic cigarettes and replaceable cartridges to cigarette vendors. - Electronic cigarettes come in three options; the deluxe option will later be - added to loadout. -2017-04-10: - Asanadas: - - maptweak: Flipped beach in the holodeck so you don't have to walk through holowater - to get on the holosand. - - maptweak: Added a computer console to the Security equipment storage. Now Masters - At Arms can do their job a little better. - - experiment: A changeling's deathsting now gives a message to the surrounding area. - Cirra: - - tweak: Overmap-related consoles can now properly be repaired. - - tweak: Overmap event groups are now slightly more common, and slightly larger - in size. - - experiment: The Torch now uses the Overmap system. This involves a 'system map' - which can be flown around, with away sites scattered on the map. - - tweak: The flow of fuel through the HE pipes in the SM chamber can be controlled - via an adjustable pressure gate in the Engine Room. The higher the 'Target Pressure', - the faster the thrusters will regain fuel faster after a burn, and the lower - the SM's output. - - rscadd: Added a fuel tank port of atmospherics, and all the necessary piping for - overmap. - - rscadd: Converted the four thruster areas on the vessel into engine nacelles. - It is possible to switch between direct injection and combustion, via buttons - located in the engine monitoring room. Each mode has its own advantages and - disadvantages. - - rscadd: Modified the SolGov Pilot job, so they can properly pilot the Torch. - - rscadd: Added randomly placed events to the overmap. - - maptweak: The Calypso, Aquila and Guppy are now overmap-capable, and can travel - to away sites on the same overmap tile. - - maptweak: Added Helm and Engine control consoles to the bridge, and Engine controls - to engineering monitoring and the fuel bay. - Datraen: - - bugfix: Aliens can choose their corresponding xenowear once again. - Haswell: - - tweak: Lots of things are made climbable. - Pobiega: - - rscadd: Added fuel pipes, manifolds, caps, etc. - - rscadd: Made pipe dispensers dispense fuel pipes. - RedStryker: - - tweak: Separated the NT tunic into an accessory. There is a polo below the tunic. - That polo is on the loadout. - - tweak: Changed the color of the NT worksuit. - - rscadd: Added a NT executive suit for the NTL. Also in RD's locker. - - tweak: Changed many things in Research from purple to NT red. -2017-04-14: - Asanadas: - - tweak: Master At Arms gets an extra jobslot, bringing it up to 4 in total. - Pobiega: - - rscadd: Added new per-map admin fax destinations. - - rscadd: Admins can now pick between the NT and the solgov logo when sending adminfaxes. -2017-04-19: - Asanadas: - - tweak: Master At Arms badges are now available from the security vendor. - - rscdel: Staff of change has been removed from the wizard's arsenal. - - bugfix: Uniform Vendors should no longer break horribly when you hit them with - a PDA (or anything that isn't an ID). - Chaoko99: - - tweak: Buffed blob, it will now attempt to spread about 20% more often. Lowered - laser resistance of a blob to compensate. - - tweak: Blobs are now totally opaque. This can be countered with optical material - scanners. - - rscadd: 'Blobs can now trip camera alarms. Beware: You won''t be able to use cameras - to find them, if you are not quick!' - - rscdel: Removed slimes from the pet merchant's options. - Ithalan: - - tweak: Collected robotics and infirmary surgical tools into surgical kits - - tweak: Updated surgical kit sprite and description and upped capacity to 14 slots - to allow nanopaste and laser scalpels/IMS to be stored in it too. - Nero-07: - - tweak: Increases starting TC for antags to 130 (was 100). - Orelbon: - - soundadd: New sound plays when the emergency pods unlock. - - rscadd: Added New AI Status Display. - Unknown: - - tweak: Made the mech rechargers use an alpha layer instead of the default grey - tiles. -2017-04-24: - Chaoko99: - - rscadd: 'Added Level3.mod (AKA: title1.ogg), by VScratch? as lobby music.' - FTangSteve: - - rscadd: Adds two inflatable doors to every fire closet. - Orelbon: - - tweak: Glasses and goggles have updated sprites. - RedStryker: - - tweak: Recolored the kidneys and liver to look more realistic. - - imageadd: Added a stomach sprite for later use when stomachs are coded. - Sbotkin: - - rscadd: Added more cooling units for Engineering and Expedition Prep EVA. -2017-04-29: - Chaoko99: - - tweak: Made it slightly less infuriating to speedmix the allies cocktail. (Changed - recipe from vodka and martini (Gin and vermouth) to Vodka Martini and Martini. - - rscdel: Removed highlanders and all references to their antag type. - - tweak: Upped the cost of a flashdark in the uplink from 16 to 32. - Ithalan: - - rscadd: Detached organs now show if any attached child organs have decayed - - bugfix: Organs no longer decay under conditions where their parent organ isn't - decaying. - Orelbon: - - maptweak: Emergency armory has been revamped. - ProfligateShampoo: - - rscadd: Added the ability for characters with the Cook, Bartender or Passenger - (i.e. Botanist) job to select botanical gloves in their loadouts. - TheWelp: - - rscadd: Adds vox scrap armor, armor made from pieces of metal fused together. - - bugfix: Fixes equippable items ignoring inability to equip if warnings are disabled. - mkalash: - - tweak: Added distance to Sol to roundstart report, as well as replaced random - planets with actual overmap system info. -2017-05-02: - Chaoko99: - - imageadd: Made the Resomi sonar ping contrast a bit better to most sprites. - - tweak: Changed the defib failure messages. Now it is less likely to lie outright - to you, and medical will no longer need to know the ancient defib rituals. The - machine will tell them the fix instead. - - tweak: Defib units now start with an APC power cell (Down from advanced) for R&D - to replace as the round goes on. The APC cell will be able to shock the patient - five times before needing to recharge (Down from ten.) - - tweak: Halved the power consumption of the mobile suit sensor jammer. - Orelbon: - - bugfix: Cameras in emergency armory should have proper alarm links now. - - tweak: Evacuation sound should no longer give you tinnitus. - - tweak: Reduced the amount of guns in sidearm cabinets to 3 from 4. Reduced amount - of guns in personal sidearm cabinets to 4 from 6. - - rscadd: Added a combined arms cabinet with 3 energy guns and 2 personal. - - maptweak: Changes the sidearm cabinets in safe rooms to personal ones. Removes - sidearm cabinet in Brig Officer's office. Replaces sidearm cabinet in bridge - with a combined arms cabinet. - - rscadd: New sprites for Fire and Medical wall closets. - - bugfix: Fixes a bug that failed to update the medical wall locker sprite when - it got emmaged. - RedStryker: - - rscadd: Adds a lot of hairstyles. -2017-05-06: - Ornias1993: - - rscadd: Added anesthetics pump above main surgery operating table - - rscadd: Added Nanomed above health monitoring console - - rscadd: Added Medical intercom at the south-west corner beside general intercom - - rscdel: Removed Nanomed above Main surgery operating table - - rscdel: Removed medical intercom above ealth monitoring console -2017-05-07: - Ornias1993: - - tweak: Changed genetic damage scanner output to state genetic damage instead of - improper cloning -2017-05-09: - Asanadas: - - maptweak: Robotics control consoles have been added to the Bridge, and the Engineering - monitoring room. - - tweak: The Chief Engineer has robotics access. It's part of his job, you know. - Sbotkin: - - rscadd: Added a Military Police armband. -2017-05-13: - Asanadas: - - rscadd: Tajarans now have access to cultural veils. Tajarans will spawn with the - default, and job-specific veils with the proper HUD elements are available in - the loadout tab under Xenowear. - - rscadd: Added 5 new hairstyles to Tajarans. Ported from Polaris (ported from Aurora). - Chaoko99: - - rscadd: Added the large RCD cartridge to the autolathe. - - tweak: Halved RCD cartridge prices. - - rscdel: Removed a forced usage of passive wording in examine poses. ([Pronoun] - [Pose], instead of [Pronoun] is [Pose].) - Datraen: - - tweak: Ports soft lights featured in other servers. - Hubblenaut: - - bugfix: The hull wrap mode of the shield generator will now actually cover the - entire ship. - Orelbon: - - soundadd: Added new AI voice sounds. - - tweak: Lowered the volume on the AI voices. - Ornias1993: - - bugfix: Medical veil now selectable by medical contractor. - - bugfix: EAL, Sign language, and emotes will no longer use autohiss - - bugfix: Chapel Maintenance airlock, now needs maintenance access to open. - PsiOmegaDelta: - - rscadd: Can now set your desired FPS level under Character Setup > Global - RedStryker: - - tweak: Added the Science radio frequency to mining borgs. - TheWelp: - - rscadd: Lets AI controlled circuits to use the assembly's inputs via a verb. - - bugfix: Fixed AI controlled circuits not being moved correctly. -2017-05-18: - Chaoko99: - - rscadd: Made the engine input pumps more cryo-clamp-able. - - bugfix: Moved the maintainance deck saferoom APC. - Hubblenaut: - - tweak: Lubed floors can be cleaned with water. - - bugfix: Wet floors make a comeback after three months of stealthy disappearance. - Orelbon: - - rscadd: New sprites for the ion rifle. - - rscadd: New sprites for the stun carbine. - - bugfix: small eguns should now have the right sprites for east and west. - Ornias1993: - - bugfix: Oxygen_pump and Anestethic_pump, now correctly checks if the mask slot - is blocked - - rscdel: removed on click application to user of Oxygen_pump and Anestethic_pump - - tweak: Oxygen_pump now gives out Breathmasks instead of gasmasks - - tweak: anestethics_pump now gives out Medicalmasks instead of gasmasks - - bugfix: Maintenance hatch and replacing tanks works now on Oxygen_pump and Anestethics_pump - - tweak: removed organic requirement for removing the oxygentank of Oxygen_pump - and Anestethic_pump - - bugfix: UI of oxygen_pump and Anestethics_pump works now - - rscadd: AI can now click to open UI of oxygen_pump and Anestethics_pump - - rscadd: Added the Anestethics Mask for the Anestethics_pump - - rscadd: Added the Emergency Mask for the Oxygen_pump - - spellcheck: Fixed brusies typo on Torch Holodeck disclaimer - RedStryker: - - rscadd: Added boxes of armbands for emergencies to the heads of the Security, - Medical, and Engineering departments. - - tweak: Allowed a few more roles to use flats. - - rscadd: Added many new clothing items as accessories. - - tweak: Changed the color of the cheongsam to allow it to use the color gear tweak. -2017-05-20: - Chinsky: - - rscadd: All toys guns are now fitted with red bits on the barrel so you can visually - tell them apart! Very safe! Fun for whole family! - - rscadd: Can use wirecutters on toy revolvers to snip those off. It also changes - examine name to 'revolver' instead of 'toy gun'. In case you didn't know, those - are proper guns and you can hold people hostage with those. Just saying. Do - not try at home. - Cirra: - - tweak: Attempting to place an airlock brace without setting an access requirement - now informs you, and asks for confirmation. - Orelbon: - - rscadd: Added inhand sprite for stun rifle. - Ornias1993: - - bugfix: Everyone including military can now take sunglasses from loadout. -2017-05-23: - Asanadas: - - tweak: Maintenance Drones now require an account of age 3 days or greater. - Chinsky: - - tweak: Bunch of virus changes. Buckle up, kiddo. Praise Nurgle - - rscadd: Adds Space Cold event. Spawns a harmless virus that can be treated with - cold medicine. Unless you're irradiated and it mutates to kill everyone I guess. - - rscadd: Adds space cold medicine (dextra-something) to white first aid boxes. - Can also be made by mixing paracetamol+sugar. Eating it will stop weak viruses - symptoms from manifesting. - - rscadd: Humans now have crude immune system simulation. Keeping your immunity - high makes it easier to shrug off viruses, extremely low (15% and less) immunity - can get you random space cold-level infections. Get lemons for boosting it, - spaceacilin ruins it. It recovers to norm over time. - - tweak: Spaceacillin now ODs at 15u instead of 30u. - - tweak: Spaceacillin now metabolizes faster. It was 60+ minutes for 15u, 30 minutes - now. - - tweak: Spaceacillin boosts immune system effective rating. It acts as a multiplier - to natural one, from 1x at none in blood to 2x at OD threshold (15u), and you - can go higher if you don't mind ODing. Also if natural immunity is lower than - the boost, boost would just replace it. - - tweak: Spaceacillin has three stages now. Below 10 units it acts kinda like now, - blocking badness 2 virus effects. Virus would still progress though, but effects - won't fire. It's enough for any random event virus effects. - - tweak: Above 10 units it would completely stop progression of badness 2 viruses - and stop effects of badness 3 - which is usual stuff ou get from viro labs. - Again, clock will still be ticking. Also at this stage it starts lowering your - natural immunity value. - - tweak: And then, there's OD. OD stops badness 4 (e.g. Gibbingtons) from manifesting, - and stops ticking of lower viruses. It screws your immune system even stronger - too. - - tweak: It's also not 100% protecting you from infection now. 15u and above give - old 100% protection, scaling with lower value in blood. - - tweak: Some tweaks to virus annoyningness. Hard delay between firings (25-40 seconds - between message-only syndromes), emote syndromes (groaning, moaning, screaming) - are now single syndrome to make it rarer. Internals actually stopping you from - spreading viruses. No airborne viruses in vacuum. - - tweak: As an unrealated bonus, first aid (white and fire) boxes now have paracetamol - bottles because damn it's easier to score opiates than that. - - tweak: Oh also remember how when you graft yourself Tajaran arms it kills you? - Not when your immunity is floored. Just saying. - Orelbon: - - maptweak: Tech storage has been moved to deck two, where the abandoned officers - mess was located. The officers mess has been moved into the previous location - of tech storage. -2017-06-03: - Ace McLazer: - - rscadd: Added Towels to Sweatmax products. In all kinds of colors! Ported from - Polaris. - Albens: - - maptweak: Added a new Bridge - - rscadd: Added a Bridge Officer's locker, and 'Standard' Tablet/Laptop that spawns - on the Bridge. - Cirra: - - rscadd: As a failsafe, the maintenance hatch on a cyborg/android/robot will now - unlock upon death, allowing easier recovery of the brain inside. - Hubblenaut: - - rscadd: Added coffee pots and carafes, available in the dinnerware vending machine. - - tweak: Hot drinks now have vapor on them. - Orelbon: - - maptweak: Engineering locker room and storage have been tweaked. - SiegDerMaus: - - rscadd: Adds a new magnetic flechette weapon, available via uplink. - Sunsar: - - tweak: Made light bulbs a bit brighter. Engineering should be less of an eyestrain - now. - ZeroBits: - - rscadd: Added Barbecue Sauce as a Condiment. - - tweak: Changed the mailroom flaps to airtight flaps. - - rscadd: Added a second mop to custodials. - - rscadd: Added rings to the loadout selection. -2017-06-06: - Asanadas: - - rscadd: High jittery levels will now cause heart damage. - - rscadd: Individuals with robotic hearts will no longer suffer from jitters. - Ithalan: - - rscadd: Added turtleneck sweater as accessory. -2017-06-11: - Asanadas: - - rscadd: There's now a neat lore splash window which will spam all new accounts - under 7 days old. Read it! - Chaoko99: - - tweak: Made Digital Valves removable. - Hubblenaut: - - rscadd: Digital warrants can now be archived, so they don't have to be deleted. - - rscadd: Security gets automatically notified on new warrants through their HUDs. - - tweak: Improved the digital warrant interface. - Leshana: - - tweak: Optimized the unified radiation system. Made the radiation cutoff level - configurable. - - bugfix: Standing still won't save you from radiation storms. - Ravensdale - original work by anewbe: - - bugfix: Removed the exploit by which you could gain cargo points by ordering plastic - crates. - - rscadd: Upped cargo point gain by 50%. - Unknown: - - maptweak: Atmoshperics has been edited to make it easier to change and modify - pipes. - ZeroBits: - - rscadd: Added Independent Language. - - rscadd: Added signet rings, which act as stamps and rings, and can be personally - claimed by clicking them in-hand - - tweak: Rings are now compatible with the material system, and can be made via - sheets. - - bugfix: You can no longer clip rings like gloves, and all species except Diona - can wear them now. -2017-06-17: - Asanadas: - - bugfix: No longer will you be able to freely pass onto upright tables by moving - onto them from a tile which has a flipped table. - Chaoko99: - - rscadd: Added a mass-defile cultist rune. Buyer beware; it may kill you. - - rscadd: Cult tiles play a snazzy animation on creation. - - rscadd: The soulstone shard now notifies the player when it is full, asks if you - wish to release the spirit within. - - rscdel: Removed Manifests from the cultist repertoire. - - rscdel: Removed defile giving cultist levels. - - tweak: Changed the values for cultiness (The value which controls spell levels). - You will need to either recruit 10 cultists, or perform 10 sacrifices to unlock - Nar-Sie. - - tweak: Nerfed cultist robes. Buffed cultist voidsuits. The latter of which is - still impossible to obtain. - - bugfix: Made the restricted/protected/blacklisted roles for cultists torch-compatible. - - bugfix: Fixed construct and familiar spells. - - rscdel: Removed Vox Pariah. - Chinsky: - - rscadd: Can now rig assemblies/devices(e.g. radio signalers) to trigger when crate - is opened. Click wires on open crate, then click with assemblies. It would trigger - when opened next time. Use wirecutter to unrig. - - tweak: AI cores got new step in construction. You need to swipe an ID with Upload - access (or emag) to hook them into the systems. - - rscadd: Added rubber masks and suits to party crate. Dress up as war hero or SCG - secretary or a naked tajara like you always wanted. - - tweak: Made SHOCK mode on tasers literally useless, ruining security gameplay. - Does bit less burn damage, and much less straight up stun damage. Not 'better - tase mode' anymore. - - bugfix: Fixed their primary function actually never working. If you hit arm or - hand with the beam you can disarm someone (even diona, even robbit, pain reception - doesn't matter). If you hit leg, they might drop, higher chance for foot. - Hubblenaut: - - bugfix: Manifold pipes show up properly on t-ray scanners now. - - bugfix: Space lube now properly disappears. - - tweak: Can now put items in vendors by using click and drop, thus allowing screwdrivers, - multitools and similar. - - tweak: Space heaters will now first attempt to draw power from the local APC. - sabiram: - - rscadd: Research module robots now have access to a welding tool. -2017-06-19: - Chinsky: - - tweak: Speed now matters when flying into meteor field. Still - 25% the meteors, - below 0.3 - 60% of usual, normal otherwise until above 3 speed, where you start - getting double the fun. Also if ship is moving most meteors will fly in from - front and sides. - - tweak: Changes spess dust event. It used to be a single wave of quasi-meteors - that exploded for a bit before dying. There were no further waves until you - left and came back. Now waves keep coming ~twice a minute. Dust itself is now - a pile of micrometeors - basically space bullets. It wouldn't do a lot of damage - to the hull, but can break windows and makes EVA pretty damn dangerous. - - tweak: SCG had mastered the secret art of 'background check'. CO and XO are no - longer be eligible for roundstart antag roles on Torch. Can still be converted - in round - - bugfix: As a side effect, they aren't going to get rev'd anymore, that was a bug. - ZeroBits: - - rscadd: Added the ability to have multiple loadouts per character. - - rscadd: Added magic invisibility ring and reagent rings. - - tweak: Rings are now a child of clothing rather than gloves in order to appease - code gods. - - tweak: Gloves can now be worn over rings (much like magboots with shoes). - - rscadd: Added coffee cups to the loadout selection. - - rscadd: Added threebread, blueberries, pancakes, and two new flavors of ice-cream. -2017-06-30: - Chaoko99: - - tweak: Poppies now contain tramadol. - - bugfix: Fixed the phrasing in the set-pose verb. - Chinsky: - - rscadd: NT has sent some more testing supplies. Nothing to see really. RDs can - find details in a super secret folder in their office. Others - do no peek, - ok. - - tweak: Surgery now produces normal wounds instead of snowflake 'open incisions'. - Do not be alarmed, do not bandage those if you plan to continue surgery, clamp. - If incision was made with scalpel, you'll be able to cauterize it, healing a - lot of damage. - - tweak: Skull/ribs surgery changed, now you just need to use the saw to crack em. - Fractures count as being open too. Retractor steps for ribs etc are gone, use - normal bone repair surgery aferwards. - - tweak: Coincidently you can just rip them apart with cut wounds to get access - to innard surgery steps. It takes much more damage than surgical incisions though. - - tweak: Bones now fracture when damage is taken rather than from existing damage. - Meaning if you fix bones, they won't refracture immediately without taking damage. - - tweak: You don't need to crack open the bones to get shrapnel now. If you can - see it on examine, you can take it out with just a retracted incision. - - rscadd: Added new surgery step - disinfecting wounds. You can use sterilizine - or high proof booze, in spraybottles/droppers/bottles/glasses/buckets. Works - same as ointment. - ParadoxSpace: - - rscadd: Adds darksight to space adapted humans - Ravensdale: - - tweak: Cultists now speak in the cult tongue when activating runes instead of - their default language. Done in case a changeling cultist ever becomes a thing. - - rscdel: Removed special human kabobs and burgers. Lumping all items that are 'red - meat' together. - - tweak: Adjusted AI tracking verbs. AI will now have a more difficult time tracking - specific people depending on method and if person has their face concealed. - - tweak: To bring some consistency for the above, also adjusted how names appear - on mobs that have some sort of face covering or a face that is... not there. - Zucchinsky: - - rscadd: Beeg medical changes. Like holy crap. Get a crash course on https://wiki.baystation12.net/index.php?title=Zuhmed_Guide - - rscadd: Death now occurs when brain dies. Brain's health replaces overall 'health' - - rscadd: Death is now FINAL, baring relacing. Don't let that brain die. - - rscadd: Crit now exists as flatlining, the heart failure, or as fancily 'asystole'. - It happens when heart is damaged, not enough blood or oxygen in blood, or high - levels of shock. - - rscadd: In crit you do the usual gasping thing and take brain damage. USE CRP - or defib to revive em. If they die before you crack ribs, you hadn't tried hard - enough. - - rscadd: '''Toxins'' damage is now overall organ failure, basically sum of organ - damage. Poisons will try to destroy liver and kidney first, and will damage - the rest after those two are down. Some poisons go straight for vitals. Liver - will heal self until it''s too damaged.' - - rscadd: '''Suffocation'' damage is now used as modifier to your blood levels. - If you don''t get enough air, you get effects of low blood basically.' - - rscadd: Defibs now restart failed hearts instead of reviving dead. Also named - differently now. - - rscadd: Most scanner readouts are changed now. Instead of damage values they report - vitals (pulse/blood pressure/brain activity) and general state of damage. - - rscadd: A D R E N A L I N E. When you take a good chunk of damage at once (15 - or more in one hit) you generate bit of adrenaline reagent according to damage - taken. It acts like strong painkiller / pulse raiser for a tick or two, becoming - weaker after that. - - rscadd: FBPs and IPCs now have batteries in their chests. They have HYPERCELLS - and drain when they stand (unbuckled) or move around (double drain then). - - rscadd: Sleepers now have stomach pumps, same as filtering but for ingested stuff. - - rscadd: Cultists yo - sacrifice rune now works on someone in asystole rather than - full braindeath. Knives now count for all steps needed to cut out the heart, - and cult runes count as surgery spots. Just sayin'. - - rscadd: Bunch of chems is different now. First off, none 'reduce' toxins damage, - aside from peridaxon cause tht's organ damage now. - - rscadd: Peridaxon only treats brain damage if it's not too severe. Get Alkysine - otherwise. - - rscadd: Alkysine will only work if brain is fully oxygenated, so refill blood - and air first. - - rscadd: Dylovene removes toxic reagents from blood. - - rscadd: Dexlaine fools brain into thinking you got at least 50% of air you needed. - For Dex+ it's 80%. - - rscadd: Cryox/Clonex also have Dex/Dex+ effect respectively. - - rscadd: Inapro prevents suffocating while in asystole, slows pulse down (which - slows bleeding a bit) and has mild painkiller effect as it did. -2017-07-06: - Chaoko99: - - tweak: Added a full belt to engineering lockers. - - tweak: Removes all (direct) references to Metroids from our codebase. Not being - sued is nice. - - imageadd: Replaced our RPED sprite with /TG/'s, and added a little animation atop - that. - Chinsky: - - rscadd: Can now scoop corgis up, like cats or nymphs etc. - - rscdel: Can also use them instead of sausages in microwave to make hotdogs. Geddit, - hehehe hot dogs. Riot. - - tweak: GUPpy, Calypso and Aquila now can share destinations, as long as they can - fit. - - rscadd: Excavation prep closets now have BLUESPACE FLARES. You can activate those - in a nice open spot to create a new navpoints for shuttles (ones mentioned) - to go to. - - rscadd: Exploration shuttles (Calypso/Guppy/Aquila) now can share destinations - (with some other shuttles too). - Heptagon49: - - tweak: Replaced the synthetic lung sprites with something more realistic/futuristic. - - rscadd: Added artificial and assisted lungs to the loadout menu. - Hubblenaut: - - rscadd: Coffee cups are now available across the ship. - - tweak: Coffee cups now have reagent fill states. - - bugfix: Fixes glass of cup of tea. - thasc: - - bugfix: Ghosts can hear binary chatter again. -2017-07-09: - Chaoko99: - - tweak: Made it so a butterfly knife spawns in your hand instead of on the floor - when completed. - Chinsky: - - tweak: Bluespace jump effects have changed. Engineers found that some duct tape - got unstuck because of a WD40 leak, so they fixed it. Now you can't zoom through - the walls, and visibility is a bit better. You also don't get confused forever, - just for a minute or so. There are some... unforseen side effects, but they - seem harmless. A word from Chief Tech (before his disappearace) - KEEP IT REAL. - Hubblenaut: - - rscadd: Gives holowarrants their own handheld item. - - tweak: Holowarrants will now broadcast updates on warrants instead of security - HUDs. - - tweak: Authorizing a warrant using the holowarrant will now broadcast a message. - ParadoxSpace: - - rscadd: Unathi across the universe have been informed of new lore changes, and - can now be a maximum age of 260. - Ravensdale: - - bugfix: Exosuit/mecha pilots can once again operate airlocks from the safety of - the cockpit - mkalash: - - tweak: Replaced adminhelps with a ticket system. -2017-07-14: - Atlantiscze: - - tweak: Max pressure on omni filter/mixer output is now capped at approx. 7500kPa - - tweak: Atmospherics pressure tanks can now be set to output up to 15000kPa - Heptagon49: - - bugfix: Changes the recipes for Methylphenidate and Antidexafen so they no longer - overlap. Methyl now requires lithium instead of hydrazine, and antidexafen now - requires carbon instead of sugar. - - tweak: Lowered the max damage of internal organs, except for the brain and cortical - stack. - - tweak: Prosthetic internal organs are now stronger then regular organs. - - tweak: Kidneys are actually important now. You will slowly take toxin damage if - they are missing or busted, same as the liver. - - imageadd: Changed the sprites for the prosthetic liver and kidneys. - - rscadd: Prosthetic lungs half the toxin damage taken from breathing bad air. - - tweak: Made assisted organs slightly worse. - Hubblenaut: - - tweak: Air shutters will not be automatically opened by a clearing air alarm when - it would be dangerous to do. - ParadoxSpace: - - rscadd: Unathi across the galaxy have realised the implications of having tails, - and now use them to attack instead of their legs. - atlantiscze: - - rscadd: Can now order OCP and plasteel from cargo. Furthermore, 10 and 50 sheet - crates are available for some more expensive sheet types, with 50 sheet crates - being more cost efficient. - mkalash: - - tweak: Replaced tgui ticket panel with an autoupdating basic Topic() one - - rscadd: Added time stamps to messages on the ticket panel, and a measure of how - long an unanswered ticket has been open - - rscadd: Added a PM button to the ticket panel - - tweak: Adminhelping with an open ticket will either send another adminhelp to - the same ticket, or PM one of the assigned admins if there are any - - bugfix: No more sanitation weirdness in ticket panels - - tweak: A ticket is no longer created anyway if an admin cancels sending a PM to - someone who didn't have a ticket - - bugfix: Fixed admins being able to create tickets for logged out players - - bugfix: Fixed mods and trialmins being unable to use the ticket panel -2017-07-24: - Hubblenaut: - - tweak: If a cycling airlock is already near the target pressure, pressing the - buttons will toggle the doors instead of making it reenter the cycle process. - - bugfix: Fixes blood splatters reappearing when lifting or putting floor tiles - down. - PsiOmegaDelta: - - rscadd: Species may now be restricted from selecting certain branches, ranks, - and occupations as according to lore. - Ravensdale: - - maptweak: Changed the colours of the pipes in atmosia to follow older color 'codes. - SiegDerMaus: - - rscadd: Added uniforms for Miranians for future events.. - TheWelp: - - rscadd: Allows Vox to be used in character setup. They are still restricted rule-wise - as they were before. -2017-08-01: - Ace McLazer: - - rscadd: Added A grunt emote for the grumpy. - - tweak: Tweaks Medibot statement for accuracy. - - imageadd: Adds Renegade AntagHUD Icon. - - imageadd: Swaps Medical belt Icon to blue - Crushtoe: - - rscdel: Removed transformation sting. - FTangSteve: - - bugfix: Fixes dionaea jitter. - - bugfix: Fixes dionaea limb regen. - - rscadd: Adds species based footprints when barefoot. - - rscadd: Gives GAS the ability to move over gaps or stop fall damage based on air - pressure. - - bugfix: Fixes some bugs with the GAS cloaking and stance switching. - - bugfix: Fixes damage overflowing max limb damage being negated. - - tweak: Makes wounds on limbs more realistic by letting them overflow max damage. - - rscadd: Adds ability for limbs to be injured irreparably, requiring amputation - or removal. - Heptagon49: - - imageadd: Adds everyone's favorite hotdog-based meme to the AI icon list. Now - contains 2% real corgi flavor! - Hubblenaut: - - rscadd: Replaces flashlights in Security with maglights. - - tweak: Removes security HUD sunglasses from lockers and makes them available in - loadout instead. - - tweak: Personal lockers now display their owner's name in their name. - - rscdel: Removes the box of military police armbands from CoS' locker. - - rscdel: Removes the box of solgov police badges from the Brig Officer's locker. - - bugfix: Lockers reset all random pixelshifts of their contents. -2017-08-07: - Atlantiscze: - - rscadd: Added ability to ban devices from the NTNet network, through the administrative - utility program. - - rscadd: Security cyborgs now get access to warrant program - - rscadd: Engineering cyborgs now get access to supermatter monitor program - - rscadd: Mining cyborgs now get access to supply management program - - tweak: Holowarrant now checks for access when authorising, similar to how the - program does it. - - rscadd: 'Added new program to the modular computer framework: NTNet Access Decrypter. - This program is available for download on all emagged devices, but relies on - ID card slot hardware. When executed it slowly (takes about 3-6 minutes, depending - on the device''s CPU) hacks the network and when finished adds a random access - to the ID. ID must be kept inside the device while running. Can be repeatedly - used to get multiple accesses. Has chance of yielding access that''s already - present on the ID, and therefore will do nothing wasting some time.' - Broseph Stylin: - - rscadd: Added weight lifting machines and punching bags. They provide no mechanical - benefits, and will deplete your nutrition as they're used. The weight machine - has 3 setting which can be changed with a wrench. You must be on harm intent - to use the punching bags. - - maptweak: Remapped the Deck 3 abandoned office, near EVA Storage, into a gym. - Cirra: - - bugfix: Fixed an exploit which allowed for the creation of infinite metal, using - the circuit printer. - CrimsonShrike: - - rscadd: 'Added new accesory slot: insignia' - - rscadd: Allowed more accesories on dress and service jackets. - - rscadd: Security vests now come with stripes to hang badges and other similar - insignia accesories. - - rscadd: Detective coat has now a slot for the badge too. Gone are the days of - flashing suspects to show your identification - - rscadd: Colonial Marshals have now learned to keep their badges visible aswell. - - bugfix: Emaged light replacers will now properly place explosive lights. - Datraen: - - rscadd: Adds directional states for softlight overlays. - - bugfix: Fixes lights on rotated views. - FTangSteve: - - bugfix: Fixes bug that stopped wounds from healing. - - bugfix: Fixes bug that made brains not take damage from low blood unless they - already had damage. - - bugfix: Fixes bug that made moderate blood loss damage your brain until death. - - tweak: Makes the irreparable point twice the limb cutoff threshold instead of - equal to it. - - tweak: Prevents vital external organs from being irreparable, instead they go - to critical. - - tweak: Updates advanced scanners with new wound severity levels. - - tweak: Smooths the dexalin and dexalin plus effectiveness curves. - - bugfix: Fixes pulling grabs when the affected person can't move. - - bugfix: Fixes GAS being able to use advanced tools when nabbing. - - bugfix: Fixes grabs with the ladder_carry ability carrying people up ladders. - - tweak: Stops GRAB_NAB base grabs from throwing people. - - bugfix: Allows GAS to remove lights by hand. - - bugfix: Moves GAS eyes below the lighting layer. - - bugfix: Stops mice from pushing crates, lockers, etc. - - tweak: Stops mobs from using pull to move larger mobs (grabs still work). - Heptagon49: - - rscadd: Adds the ability to toggle locks on secure lockers and crates with alt-click. - - rscadd: Adds the ability to open and close fire extinguisher cabinets with alt-click. - - rscadd: Adds the ability to rotate chairs with alt-click. - - rscadd: Adds the ability to change reagent amount tranfer with alt-click. - - tweak: Lowers the odds of vending machines going absolutely ballistic. - - imageadd: Adds a new robot sprite to the security module selection. - Legius: - - bugfix: Sign Language is no longer displayed to clients who are unconscious or - asleep. Probably. - PsiOmegaDelta: - - rscadd: Players with custom AI displays can now have multiple entries, should - they desire. - - rscadd: Players with custom AI displays can now freely select between their custom - and available displays. - - rscadd: Players with custom AI displays no longer have to supply the crashed/dead - AI state. - - rscadd: Traitor/Malfunctioning AIs now have access to additional AI displays. - SierraKomodo: - - rscadd: Added berets that allow a custom color to be set to the loadout menu. - - bugfix: fixed transparent pixels in white beret sprite. - TheWelp: - - rscadd: Adds deity follower tracking and better deity eye in general. - - rscdel: Removes need for deity floors and respective spell. - - rscadd: Nar-Sie zombies will automatically get all of their blood filled when - zombized. - - rscadd: Nar-Sie zombie's breathe will convert faster. - - bugfix: Fixes nar-sie blood forge being automatically unlocked. - nearlyNonexistent: - - rscadd: Added vending machine to the code that contains dice, cards and related - toy type items. One is in the mess hall. - - maptweak: Adds paper for civilians in the mess hall and lounge. Removed a stool - in the mess hall to add the vending machine. -2017-08-12: - Atlantiscze: - - rscadd: Cyborgs can now manipulate IV drips and chemistry grippers can now hold - blood packs. - - rscadd: Improved some SMESes around the station - mainly the Engine SMES. - - rscadd: Shuttles now have a SMES with single transmission coil in them. Primary - input is the main grid, secondary input is a PACMAN generator. - - rscdel: Removed stashes of phoron from the shuttles (they can operate without - generators now) - - bugfix: Fixed bug which caused shuttles to be remotely powered even after cable - connection was severed by jump - - tweak: Rewired SMESes in engine SMES room. Engine - Core SMES can now be charged - from main grid, for example through solars. - - rscadd: SMES and PSU units can now have more than one input terminal at once. - Broseph Stylin: - - tweak: Changed access requirements aboard the Aquila. Helm and Secure Storage - remain as Aquila-specific access, but all other areas have been made SCG Crew - or all-access. - - tweak: Changed sidearm cabinet access requirements. Only line officers, the RD, - the SEA, and the Brig Officer can unlock them now. - Chaoko99: - - bugfix: Makes title1 run at roundstart. - Crushtoe: - - maptweak: Added a First Deck Lounge in the Observation Bubble. - Devildabeast: - - rscadd: Defines an armed role for the Loadout, which includes all jobs that are - allowed to carry weapons from round start. - - rscadd: Adds Scientist and Researcher to semi-formal roles. - - tweak: Frontier clothes are now its own separate item instead of a formal outfit - and can be worn by non-military roles. - - tweak: Holsters can now be selected by armed roles. - FTangSteve: - - rscadd: Added a paramedic alt title for medical contractor. - - rscadd: Added a admin debug verb that lets you see a health summary, same as the - advanced scanner in medical. - - tweak: Makes splashing solutions and using eye droppers only work when not on - help intent. - - tweak: Makes dylovene more effective to help with liver damage and recovery from - severe damage. - - bugfix: Fixes necrotic internal organ surgery. - - bugfix: Changed how toxins work so they now are effective. - - bugfix: Alcohol is once again potentially damaging. - - bugfix: Increases processing accuracy for liver and kidneys. - - bugfix: Radiation now does damage again. - - rscadd: There is now a popup after taking enough brain damage as a stand-in for - clone memory disorder etc. - Heptagon49: - - rscadd: Adds a 1% chance for a diona nymph to pop out when you activate a vending - machine. - - imageadd: Adds a few vending animations. - - tweak: Changes the NutriMax icon from the nutrimat to the pre-existing, but unused, - nutri. - Superbee29: - - tweak: Telecommunications servers no longer know the exact race of a speaker. - TheGreyWolf: - - rscadd: Mechanical and assisted kidneys and livers are now available in character - setup. - TheWelp: - - rscadd: Adds two new Nar-Sie phenomena. - - rscadd: Adds two generic feats involving power generation. - - tweak: Communication phenomena can now be used on non-cultists. We will see if - this is a good change. - - tweak: Tweaks a few of the phenomena names to be more apparently phenomena. - - tweak: Buffed Nar-Sie's power costs (reducing them). - nearlyNonexistent: - - rscadd: Cardemon instructions! Now you can actually play those weird pokermon - cards rather than just look at them. -2017-08-19: - Atlantiscze: - - rscadd: Re-adds on-join announcements to all ranks. - - tweak: Most jobs are announced on relevant departmental frequency (if they have - one). During red alert all jobs are announced on main frequency. - - tweak: Canisters now once again use NanoUI, instead of tgui. Performance on some - devices should be considerably better. - - tweak: AI can once again track people by clicking their name from radio messages, - even when their face is obstructed, assuming they are at least wearing a matching - ID. - Chinsky: - - tweak: Slimetoxin. Slimetoxin changed. Instead of pop and go slimeficiation it's - now a life threatening process. Slime toxin metabolizes slowly, and deals fair - bit of toxins damage. For every unit or so metabolized, it mutates one limb. - Once every limb mutated, there's a 10% every tick to fully mutate into a slimegirl. - If you're lucky, you might mutate right before death and that'd heal your all - wounds! That' a great idea! - Devildabeast: - - rscadd: Adds a cyborg recharging station to the Auxiliary Head. - - rscdel: Removes toilet from said Head. - FTangSteve: - - tweak: Adds more signals letting someone know they have toxin damage and giving - them a chance to get help. - - tweak: Adjusts how often internal organ damage messages are displayed. - TheGreyWolf: - - rscadd: Added hoods to standard hoodies. - tlc2013: - - tweak: Updates the Lobby and Nuclear Explosion cinematics to be more Torch-y. - Special thanks to 50_n00b for the art. -2017-08-23: - Broseph Stylin: - - tweak: The Body Scanner console and IV drips are no longer dense and can now be - walked through. - Chinsky: - - rscadd: Air analysers now have verb to be toggled into advanced mode. It displays - gas properties like specific heat and molar mass. - - rscadd: Air analysers can also now be used on pipes and various atmos machinery - to inspect the contents. - FTangSteve: - - tweak: Makes it easier to recover people from severe radiation damage. - - tweak: Puts a limit on recovery time for surgery with peridaxon, two minutes after - death the organ will no longer be savable. - PsiOmegaDelta: - - rscadd: Underwear is now handled as actual items. - - tweak: Your own underwear can be removed using the 'Remove-Underwear' verb. - - tweak: You can remove others underwear through the strip-menu. - - tweak: To put on underwear, on yourself or someone else, click the target mob - with the underwear in your active hand. - - tweak: The wardrobe now offers a limited quota of underwear if replacements are - needed. - - tweak: You can increase this quota by returning underwear items. - TheGreyWolf: - - rscadd: Tattoos are now available in character setup. - ZeroBits: - - bugfix: Manuals now point to the correct wiki pages. - - tweak: Cleaned up and organized manual files. - - rscdel: Deleted redundant manual that pointed to the same page as another. - Zuhayr: - - rscadd: Diona nymphs can now pick up and carry a small item. Use the drop_item - command or the Home key to drop it. This can also be used to remove your hat. - - rscadd: Losing your head is no longer necessarily lethal, unless you're the kind - of fat nasty trash who has a brain or other vital head organ. - chinsky and mkalash: - - rscadd: 'A randomly generated exoplanet of one of the following for types is now - available for away missions:' - - rscadd: Grassy exoplanets, lush with (probably dangerous) flora and fauna, but - not much else - - rscadd: Snowy exoplanets, like grassy but colder and with less life - - rscadd: Desert exoplanets, rich with minerals below the surface, which is covered - with dangerous quicksand - - rscadd: Mountainous exoplanets, one of the three other options, but also covered - with surface minerals - - tweak: Additionally, the airlocks of the three shuttles aboard the Torch now cycle - to the external atmosphere. - nearlyNonexistent: - - tweak: Fixes the inability to make enchiladas by making popcorn require salt. - Enjoy your salted popcorn. - sabiram: - - bugfix: Maintenance drones now once again take damage and recieve alarm notifications. -2017-08-27: - Chinsky: - - rscadd: Added a ton of usless gasses. Overall fireball planets should be slightly - more rare now - - tweak: Lighters now have fuel storage inside, and will shut down if it's empty. - Can refill at any welder fuel tank. - - rscadd: Can now dig graves planetside. Use shovel on ground to dig a pit. Can - place grave markers with wooden planks. - - experiment: When you speak now, your first name is replaced by your rank in messages. - Only affects those with military rank and wearing ID with it. - FTangSteve: - - rscadd: Adds insulated gloves for nabbers. - - rscadd: GAS can now be chemists and engineers.. - Minijar: - - bugfix: Fixes holosigns to appear above doors - atlantiscze: - - rscdel: Removed Turrets Focus Enhancer malf AI hardware, it is obsolete now. - - rscdel: Hack Camera replaced with Reset Camera. No longer allows camera upgrades, - this has been shifted to Machine Upgrade. - - rscadd: Added Quantum Knowledge Databank malf AI hardware. On use it advances - all research by one level. Single-use. - - rscadd: Added T5 Machine Upgrade ability, behind Machine Overload. Right now only - works on APC, SMES, Turret, Turret control, Camera. It is easily expandable - to any machinery in the future. - - rscadd: Adds four new abilities in a new passive tree. T1 prevents intellicard - transfers (toggleable), T2 removes BSOD/lockout from APCs, but reduces CPU generation - (toggleable), T3 prevents hack failures, and allows you to complete system override - silently and T4 prevents fax/emergency messages from going through. -2017-08-30: - Chinsky: - - rscadd: Health analyzers, advanced scanners and suit sensors will now report blood - oxygenation instead of just how well it flows in general. - - rscadd: If you go near an edge of exoplanet, you get warped around, kinda like - in space. Don't get lost, nerds. - - rscadd: Lush planets now have some drillable minerals too - some coal with a small - chance of diamonds or uranium. - - rscadd: Movie titles music now uses lobby music preference toggle to see if it - should play to you. - Crushtoe: - - maptweak: The derelict is no longer complete trash. There's actual rooms and plenty - of loot to loot, too! - - rscadd: Added random spawns for hostile mobs on the Derelict. Now the good loot - has a guardian pike/carp/viscerator. - FTangSteve: - - bugfix: Updates GAS to properly use the bloodmed system. - - bugfix: GAS eyes are no longer vulnerable to phoron in the air. - - bugfix: Fixed bug with humans not taking oxyloss after two minutes of not breathing. - - tweak: GAS now store more dexalin. - - tweak: Updates unit tests to include GAS. - - tweak: Updates unit tests to work with adjusted oxyloss system. - Minijar: - - tweak: Changes blue alert to orange - - rscadd: Replaces the bluespace artillery cannon with a prototype RUST fusion reactor - for engineering to experiment with. - - tweak: Edits the RUST manual to fit the new setup. - PsiOmegaDelta: - - experiment: Overhauls how reagents are identified, affecting both chemistry and - food. Due to the large scale of these changes more or less subtle bugs may have - crept their way in. - ThatOneGuy: - - rscadd: Can now play as the Explorer Department if you are a EC member. If a complete - failure, up for removal. - - rscadd: Calypso remapped for more cargo space and crew area. Bathroom and Cryo - deleted. - TheGreyWolf: - - rscadd: Fixed up pathfinder and explorer loadout. -2017-09-03: - Earthcrusher: - - bugfix: The electrified arm (e-magged/traitored Engineering borg module) now behaves - like a stun baton. It can be toggled on/off. - - tweak: Activating the electrified arm will now cause the borg to glow a faint - blue, giving away that they are using it. - - imageadd: Added a unique sprite for the electrified arm. - Kelenius: - - tweak: Pulling a knife out of your boot or putting it in no longer makes a message. - Minijar: - - bugfix: Adds atmospheric systemst the rust chamber - - bugfix: fixes the rust airlock - - bugfix: Removes accidental vacuum flooring - ParadoxSpace: - - rscadd: Adds Selenian, a lunar language for those who still hold onto that silver - spoon. - - rscadd: Adds Spacer, a language of Dutch origin for non-landlubbers. - - rscdel: Took Tradeband out back. - dryerlint: - - rscadd: Added ability to put paper bundles directly into paper bins and nano-printers. - - rscadd: Clicking on paper while holding a paper bundle now adds the paper onto - the bundle. - - rscadd: Added new type of crate - the paper refill crate - filled with 30 blank - papers. Intended to be used for refilling bins and printers. - - maptweak: Placed paper refill crate in Deck 1 Maintenance near the Conference - Room. -2017-09-08: - Chinsky: - - rscadd: Calypso is dead, new shuttle is here in same role - Charon. - - rscadd: Can now hide custom loadout items that are not allowed for your job. The - button's in top of loadout menu. Makes browsing less of pain for those with - lots of restrictions. - - rscadd: Wildlife will now respawn if more than half is killed off. Beware. - - rscdel: Added new type of planets - settled ones. Full of xenoarch-filled garbage - piles and hostile robots. - Cirra: - - bugfix: Protein is no longer present in food items which aren't supposed to contain - it, such as skrellsnax. - CrimsonShrike: - - bugfix: Stacking machine will now stack materials again. - FTangSteve: - - tweak: Updates engineering contractor to have access to atmos, EVA, etc. - Kelenius: - - tweak: Defile counts towards rune unlock again, at a rate adjusted for Torch. - - tweak: Mass defile rune won't kill you with bloodloss when you draw it more than - once (cost lowered from 80 to 20). - - bugfix: Soulstones should work properly now. - Minijar: - - rscadd: Adds pilot voidsuits to the Calypso along with a cycler. - TheGreyWolf: - - rscdel: Removes the Zhan-Khazan outfit from the loadout (Taj relevant only). - - rscadd: Added a NT pilot specific voidsuit, currently none are mapped in. - Zuhayr: - - tweak: R-UST backend/manual changes. -2017-09-13: - Chinsky: - - rscadd: Changed way lung damage affects people. Instead of straight up oxyloss, - it now makes you require higher oxygen pressure - so you can work around it - with high pressure internals. Of course it's not 100% failsafe, as blood coughing - and breathing stops still remain. - - rscadd: Inapro does more things now. It can heal brain damage up to 60, and also - slows down brain damaging a general, more effective at higher oxygenation. - - rscadd: Health analyzers report brain damage a bit different now. They don't report - damage that will self-heal without meds. New stage 'minor brain damage' covers - range that can be healed with inapro. Rest are more or less same. - - rscadd: Painstuff tweaked around, should generally see slightly less instant KOs - from lethal damages. - FTangSteve: - - tweak: Makes it so breathing heat or cold will hurt your lungs more than making - your head explode. - - rscadd: Electricity now shocks many parts of your body in a line to the ground - rather than just your hand. - - tweak: Species with an open circulatory system now don't get cut veins or arteries. -2017-09-23: - Atlantiscze: - - tweak: Pulling a knife out of your boot or putting it in produces a message once - again, but only if you are adjacent to the person. - Chinsky: - - rscadd: Can remove rolling end credits with Stop End Titles verb in OOC tab. - FTangSteve: - - rscadd: GAS now are flammable. - - rscadd: Lasers can catch flammable mobs on fire. - - rscadd: GAS no longer are cut by small sources of cuts (they are bruised). - - rscadd: GAS no longer are cut by slithering over glass. - - rscadd: Being on fire now burns immediately and isn't based on body temperature. - - rscadd: Adds an autolathe to robotics. - - rscadd: Adds lightswitches to chemistry, the galley, and robotics. - - tweak: Adjusts some lights so lightswitches make those rooms dark. - ZeroBits: - - rscadd: Activated the Solar Storm random event, which roasts anyone who's EVA - at the time. - - tweak: Added rad-shielding to the bunk room so you can stop dying while AFK, also - added rad-shielding to the saferooms. - - tweak: Tweaks lottery chances. - - tweak: Allows admins to choose whether or not to make an announcement when they - toggle gravity from the secrets panel. - atlantiscze: - - tweak: Walls and similar dense objects are now much better when protecting against - radiation, especially at higher levels. - - tweak: AI integrity restorer program will now upload map's default law set instead - of NT default. - - tweak: Cyborgs can now click ladders to climb. AIs can now click ladders to move - their view to different Z. -2017-09-28: - Banditoz: - - maptweak: Adds tintable windows to the Robotics Surgical Theater. - Broseph Stylin: - - rscadd: Added an Exploration department-specific voidsuit. It has the same stats - of an excavation voidsuit. - - rscadd: Added Exploration department-specific colored uniforms and PDAs. - - rscadd: Added lockers for the Pathfinder and Explorers. - - maptweak: An Exploration Equipment area which can only be accessed by the Exploration - department has been mapped on Deck 4 Aft. - Chinsky: - - rscadd: Pulse now affects blood circulation. Lower pulse effectively lowers it - and vice versa. - - rscadd: Extremely high pulse risks damaging the heart. Shouldn't be a lot, but - it's there. - - rscadd: As you lose blood oxygenation, your pulse tries to rise to compensate. - Thready (>250) pulse will cause a cardiac arrest. - - rscadd: Inaprovaline tries to bring pulse to normal levels, either up or down. - It also prevents thready pulse. - - rscadd: Heart stopping is slightly less 100% surefire, so if you manage to get - heart restarted it might beat for few ticks first. - - rscadd: You no longer need lungs/mouth to give CPR, but you will only do the heart - bit. Checks still apply for mouth-to-mouth. - - rscadd: Shock stage stars rising earlier now (30 damage vs 50) and can go bit - higher than usual. - - rscadd: Painkillers speed changed. Now they ramp up slower if ingested, but stay - longer. Opposite if injected. - - rscadd: Tramadol and oxcodone injectors added to medical vendomats (and tramadol - ones to hacked firstaid vendomats). - - rscadd: Adds some goodies to survival boxes - inapro injector, food and light. - - rscadd: Changed how tramadol/oxycodone work a bit. They now have period for setting - in and wearing off, gradually ramping power up/down. Those are short, ~20 seconds - to reach max - - rscadd: Mixing those with alcohol is now as bad idea as it's supposed to be - - increased liver damage and respiratory depression (harder time beathing) await - you - - rscadd: Inaprovaline helps against breathing effects of both mixing and ODing. - - rscadd: There's now some effects based on how much you consume over time, rather - than single dose. Effects stat at 15u with some slowdown and chance to start - slurring, ramp up from there, with major slowdown and slurring after OD-worthy - doses is metabolized. - - rscadd: Also ODing on those will give you even MORE painkilling effect! At a small - cost of suffocating most likely, and don't even try doing that AND booze. - - rscadd: Ships now have sensors. Overmap is dark by default, with known sectors - emitting some light. Dust/rocks/ion block visibility. You can control the sensor - with console(s) on the bridge, its power setting sets how far it will shine. - Higher settings use /huge/ mounts of power so don't leave it running on those. - Sensors also cannot run in non-vacuum. - - rscadd: Some improvements to helm console - now shows ETA to next grid, can set - max speed for autopilot. - - rscadd: Engines are now buildable - there's circuitboards for them in Tech storage. - - rscadd: Merchant prices are now slightly less wack, they use actual procs for - deciding them, instead of selling containeres full of stuff at price of container - only. - - rscadd: Mineral scanners now store survey data, currently useless aside from penile - comparsions. - - rscadd: New away mission - a drifting empty ship. Can be restored to fly around - on its own like Torch. - atlantiscze: - - tweak: Cyborgs can now unwrap packages by clicking them.. - dryerlint: - - tweak: Autolathes can now print cable coils. They are under the Devices and Components - category. - sabiram: - - bugfix: Cerulean, pyrite, bluespace and sepia slimes now drop the correct slime - core. - - rscadd: Added a jumpsuit with colour selection to the loadout, replacing the list - of presets previously available. - - rscadd: Added a new feminine jumpsuit with colour selection to the loadout. - - rscadd: Added a service uniform skirt for Expeditionary Corps, available in the - uniform vendor. - - rscadd: The clerical module robot now has access to the basic and denied rubber - stamps. Additionally, their hacked item is now the chameleon stamp. - - rscadd: The service department has been split. The Sol Pilot, Pathfinder and Explorer - are now in the Utility department, with their own department radio. The hotkey - for the utility department is 'y'. Bartender, Cook, Janitor and Crewman remain - in the service department. -2017-10-03: - Broseph Stylin: - - rscadd: Added some code by Techhead that allows for accessories to have and transfer - armor values to the item they are attached to. - - rscadd: Added a modular armor system based around a common plate carrier and accessories - that attach to it. - - maptweak: Replaced the armor vests and arm guards found inside the Emergency Armory - with equivalents using the new modular armor system. - Chinsky: - - rscadd: Shrapnel is less deadly now. Tiny items don't jostle around anymore. They - still prevent wounds they're embedded in from healing. - - rscdel: Conductive things embedded in body will heat up in EMP, dealing damage - depending on their size and EMP severity. - - rscadd: Brainwashing implants! Well, kinda. XO now has a box of 'imprinting' implants, - that can be set to a list of instructions, and will remind about those to whoever - is implanted with it. Latest word in grimdark on-job training. They're not binding, - just reminders. - - rscadd: Now the fun part is their abuse - when victim has mindbreaker in blood - and implanted with those, implant wires deep enough to fool host that he actually - believes these. Think borg laws. You can get the kit in uplink too, bundled - with a dose of mindbreaker - - rscadd: Can now emag practice carbines to get lethal lasers out of them. They'll - turn useless after 3-6 shots so bring a lot! Costs an emag charge. - - rscadd: Not having enough air in lungs will prevent you from talking efficiently. - If you don't have air at all, you might use remaining air in lungs for one message. - If you're just not getting enough, you'll be stuck whispering. Long messages - might come out garbled. - FTangSteve: - - rscadd: Added a push back disarm attack for GAS. - - rscadd: Added examine text and a message for GAS stance. - - rscadd: Adds in some of the GAS event things like the threat display and associated - sounds. - - rscadd: Cutlets can now be added to the organ printer as well as full slabs of - meat. - - rscadd: Adds a few cameras to hangar and to exploration with a network for each. - PsiOmegaDelta: - - tweak: Converts the machine, mob, and obj processes to subsystems. - SierraKomodo: - - tweak: Changed wording of maintenance drone laws from 'do not interfere' to 'do - not interact' to better fit the spirit of the law and staff policy. -2017-10-10: - Atlantiscze: - - rscadd: Completely overhauls crew records. Large text fields now support paper - tag formatting. Records are now accessed through a computer program. Everyone - can see generic fields (name, job, rank, ..), specialized fields become visible - depending on your access. - - rscdel: Removed old record computers of all kinds, removed PDA modules for crew - record viewing. - Banditoz: - - maptweak: Mapped in a camera to Bridge's solar control. - Broseph Stylin: - - tweak: All armor-containing lockers now have a 50% chance to contain a modular - armor equivalent to the older armor vests. - - tweak: All armor crates from Supply have been altered to contain modular armor - rather than the older vests. - - rscadd: Plate carriers and storage pouches for them have been added to the loadout, - priced at 1 and 2 points respectively. Only roles already issued armor can obtain - them. - Chinsky: - - rscadd: Added doorbell pager button. Press one and it will ping all PDAs of relevant - department people! There's one in Medical Cargo lobbies each. - - rscadd: EC ranks have been changed, you'll probably need to update your char settings. - Only 3 enlisted ranks now, slightly less officer ones. - - rscadd: 'SUPER IMPORTANT: EC cannot longer be SEA. Also since they don''t have - O2 equivalent, Pathfinder can be either O1 or O3.' - - rscadd: Can now rename alien creatures! All exoplanet animals start as 'alien - creature', and you can use a Name Alien Species verb to rename them when you - see 'em. Name can't be changed afterwards so don't go too silly. Random generated - one is suggested when you use that verb too. - - rscadd: All computers now come with a word processor, NanoWord. Lets you edit - TXT files, with paper preview and markup help - CrimsonShrike: - - rscadd: Ports openspaces. Now open turfs will show whatever is down below. - Crushtoe: - - rscadd: Added the antibody analyser, a new way for virology to contribute to the - crew. Finding new antibodies from curing diseases grants 45 cargo points per - when scanned, allowing up to 1170 points on the furthest end assuming RNGesus - is very merciful. - - maptweak: Mapped in an antibody analyser into the virology lab. - - rscdel: Removes the Chemist as its own job. - - rscadd: Chemist is now an alt-title of Medical Contractor. - Devildabeast: - - rscadd: Gives the SEA Emergency Armory access. - - rscadd: Master Chief Petty Officers and Master Gunnery Sergeants can now be SEA. - FTangSteve: - - tweak: AI drones can no longer use non-drone langauge. - - tweak: Drones can no longer push or pull items larger than medium. - - bugfix: Mechs can now fall and go down stairs. - - rscadd: If a mech falls on you, it does a heck of a lot of damage. - - tweak: Makes hats optional. - - bugfix: Fixes space vine events. - - rscadd: Makes vines spread across z levels. - - tweak: Balances spreading vines. - Quardbreak: - - rscadd: Now you can look up and see out what's going on there. - dryerlint: - - rscadd: Added two Marshalling Wands to the Deck Technician's locker. They light - up and help you visually signal stuff. - mkalash: - - rscadd: Added a net gun. It and a bandolier full of net shells is located in the - Charon storage area. - - rscadd: Added stasis cages for transport of alien fauna without having them suffocate, - located in expedition storage. - - maptweak: Refitted xenobiology to support changing the atmosphere of animal pens. - sabiram: - - rscadd: Keys can now be held in wallets. - - maptweak: The derilect laboratory in the research wing has been refitted into - a break room with public office space. - - bugfix: Personal AI system radios now work once again. - - maptweak: The executive officer's office has been redesigned. - - rscadd: Head of staff offices have been fitted with modular computer consoles. - - rscdel: As the records have been integrated into modular computers, the laptop - on the bridge previously adjacent to the security and medical records consoles - has been removed. - - rscadd: Heads of staff, the Senior Enlisted Advisor and the Bridge Officers have - been leased modular tablets. The BO's are available in their lockers. - - rscadd: The commanding officer and executive officer now have special pens. -2017-10-14: - Broseph Stylin: - - rscadd: Added Marine Corps service uniform skirts. - - rscadd: Added desert boots. Available in the same places as and statistically - equal to jungle boots. - - rscadd: Added Fleet fatigues as an alternate utility uniform. - - tweak: Fleet security and Field Medics now spawn with fatigues instead of coveralls. - - rscadd: Added earrings to the loadout, found in the Earwear section. They're unrestricted, - but can only be worn by humans (subspecies included) - - rscadd: Added a Master at Arms brassard to the loadout. - - tweak: Changed the Military Police armband to a brassard. - Chinsky: - - rscadd: Electrical storms now can be blocked by shields. They have special mode - for it. Keep in mind that they will be taking damage while event is running. - - rscadd: Overmap events (meteor, dust, electrical storm) do not happen randomly - now. - - rscadd: Number of overmap events increased. Asteroid fields now spread over wider - space but have gaps in them. - - rscadd: Hitting edge of overmap will not warp you around to the opposing edge. - Space is around after all. - - rscadd: Away missions no longer glow on overmap, you have to find them now. Planets - are still visible due to sheer size of signature. - - rscadd: Changes to Torch's speed. Now default delay between moving is higher - - 20 seconds vs 12, but speed affects it much more, e.g. at 5 speed you will move - pretty much continuously. - - rscadd: Shuttles have different ranges now. Charon (1) can go to away missions - in adjacent grids, Aquila (2) one tile further. Travel time is multiplied by - the distance. - Cirra: - - rscadd: 'Added a new, more expensive type of 14.5mm ammo, for the anti-material - rifle: APDS. Less damage, but far greater armour penetration.' - - rscadd: Projectiles can now cause internal damage, including organ damage and - severing arteries. Bullets cause more than energy, with x-ray lasers being inbetween - the two. - - tweak: Renamed 5.56mm ammo to 7.62mm and vice versa, to be more consistent with - their damage values. - - tweak: Matebas now use .50 ammo, while revolvers have had their damage reduced - slightly. - - tweak: .45 rounds now do 21.5 damage instead of 20, while 10mm bullets now do - 23.5 instead of 25. - Orelbon: - - rscadd: Consoles now have ambient noise when turned on. - comma: - - tweak: Department of Swag has determined that Torch is 60% clothes by volume. - This was rectified. Now uniform vendors will only dispense 1 (one) item of each - type per person. Don't lose your pants kids. - sabiram: - - rscadd: The Pathfinder now has a special machete with premium fittings, and machete - sheaths have been added to the Pathfinder and Explorer's lockers. - - rscadd: Job bans can now be applied to jobs from the command support, exploration, - service, and supply departments. -2017-10-21: - Broseph Stylin: - - tweak: Holsters and webbing/bandoliers/drop pouches can now be worn together. - - rscadd: Added customization options for modular armor to the loadout. - - rscadd: Added leg guards as an armor module. - - tweak: replaced all static armor spawns with their modular equivalents. - Chinsky: - - rscadd: Planets now have some alien landmarks to find and rub your face on. - - rscadd: Added winter coats for all branches. Can be found in uniform vendors next - to ushankas. - - tweak: Made vent hum bit less of earbleed, made ambience bit lower and rare in - general, try reenabling it. - Datraen: - - rscadd: Allows for labels to be applied to condiment containers. - ParadoxSpace: - - rscadd: Adds eyepatch variants of the Sec, Med, and Meson HUDs, as well as a non-HUD - variant for those missing exactly one eye. - - tweak: Flipping eyepatches (and HUDpatches) is now a verb. - - rscdel: Kills the standard cloth eyepatch for military roles. HUDpatch still works - for them. - TheGreyWolf: - - rscadd: Added toeless jackboots to the EC and civie branch uniform vendor for - the xenos. - TheWelp: - - rscadd: Added a deity hud element that shows your current phenomenas. - - tweak: Reduced D-Nar's blood costs to half. - - tweak: Made it so that a deity's power can never go below 0. - ZeroBits: - - rscadd: 'Added three new strength brackets for the R-UST: 9x9, 11x11, and 13x13. - For the engineers who have 51 extra fuel injectors and way too much free time.' - - tweak: Changed the sprite of the R-UST to look cooler. - dryerlint: - - rscadd: Added queuing functionality to modular computer software downloader. - sabiram: - - rscadd: Added herbal liquor. - - rscadd: Added a new cocktail, the Ibn Batutta, consisting of 2 parts herbal liquor - and 1 part orange juice, with mint as the catalyst. - - rscadd: Added a new cocktail, the Magellan, consisting of 1 part wine and 1 part - premium whiskey, with sugar as the catalyst. - - rscadd: Added a new cocktail, the Armstrong, consisting of 2 parts beer, 1 part - vodka, and 1 part lime juice. - - rscadd: Added a new cocktail, the Zheng He, consisting of 2 parts black tea and - 1 part vermouth. -2017-11-01: - Chinsky: - - tweak: Changed way hallucinations are. Now some things will give you strong ones, - some milder, it's not always same. - - tweak: Most of old hallucinations effects are replaced. New ones are supposed - to be more mindfucky. - - tweak: Synaptizine, Paroxetone and Citalopram help lowering frequency of hallucinations, - and to clear them out faster once whatever causes them is dealt with. - - tweak: Changed lobby music selection, lowered lobby music sound overall. Should - be less ear-gore and fresher now. - Cirra: - - bugfix: Stasis Clamps actually work now. - CountAlex: - - rscadd: Adding new map for overmap list - abandoned supply base. - - rscadd: Adding new map for overmap list - planetside location - frozen with breathable - atmosphere - with pod crashlanding and survior's story. - CrimsonShrike: - - bugfix: Fixed stick messages not showing. - - rscadd: Sticks can now be sharpened using edged sharp tools. - - rscadd: Added morgue access to Forensic Technicians. - - rscadd: Added GAS-poking stick and recipe per request of the more suicidal crew - members. - Devildabeast: - - tweak: Deck Officers can now be E-8 and O-2. - FTangSteve: - - tweak: Robotic organ surgery now needs the hatch screwed back down after it's - closed with a crowbar. - - rscadd: Adds the ability for IPCs to choose whether they are shackled and a lawset - in character setup if they would like. - Heptagon49: - - rscadd: A hologram's color will now vary depending on what kind of holopad is - projecting it. - - imageadd: Added a unique sprite for long-range holopads. - - spellcheck: You now step onto a holopad instead of stepping unto one. - - rscadd: You can now tell if a person's face is disfigured just by looking at them. - TheGreyWolf: - - tweak: Restricts a few more tattoos and prevents xenos from picking normal tattoos. - - rscadd: Added black, blue and red pens, hand labeler, clipboards and destination - taggers to the autolathe. - ZeroBits: - - tweak: moved away sites to away subfolders. - - tweak: You can now disassemble bare plating by first damaging it with a welder - (or bomb) then prying it up with a crowbar. - sabiram: - - rscadd: Added two new alert levels to the Torch map. - - rscadd: Code Violet for major medical emergencies. - - rscadd: Code Orange for major engineering emergencies. - - rscadd: Code Red now has a unique sound on activation. - - tweak: Code Blue alert should now only be used for major security emergencies - and not as a general readiness state. - - tweak: Code Red alert should now be used as a general high alert when the situation - is more severe than or would warrant two of the standard department alert statuses. - - bugfix: Chemical grenades (cleaner, metal foam, etc) now work properly again. - - tweak: Security module robots' stun batons now consume much less of their cell - per hit. - - rscadd: Anyone with bridge access can now lock the holodeck into its current state - in the console interface. - - rscadd: The Pathfinder now has a box of Exploration department encryption keys - to distribute if they choose. - - tweak: As part of the SolGov staff well-being initiative, cigarette supply to - their installations have been restricted. Vendor prices have increased to match - the limited supply. - - rscadd: Added more e-cigarette flavour cartridge types to vendors, including ones - to fill with your own flavours, and added empty e-cigarette cartridges to autolathes. - - maptweak: Wall lockers with cardboard, wrapping paper and destination taggers - have been added to the kitchen, hydroponics and the research and development - lab. - sicktrigger: - - rscadd: Ship sensors will now heat up and eventually take damage at higher settings - (they can be repaired with a welder). Their power usage has also been significantly - reduced. - tlc2013: - - rscadd: Added the Corporate and Service lawsets to IPC shackles. - - rscadd: IPCs now have four new monitors. Nothing special... except for a space - screensaver. -2017-11-04: - CountAlex: - - rscadd: Adding new map for overmap list - smugglers den located inside asteroid. - Tlc2013: - - rscadd: IPCs now have two bonus language slots. - sabiram: - - rscadd: As follow-up to a recent study concerning the trend of people more readily - following leaders with shiny revolvers, the Commanding Officer and the Executive - Officer have each been supplied a Webley style .44 revolver as their personal - side arm. - - rscadd: Added the .44 revolver to the traitor uplink. - - rscadd: Added .44 ammunition to the autolathe. Rubber is always available, and - lethal is available after hacking. - - rscadd: You can now alt-click revolvers to spin the cylinder. -2017-11-10: - Chinsky: - - rscadd: Can now put clothes on skeletor models. - - rscadd: Can rename skeletor models with pen. - Heptagon49: - - tweak: Lowered the chances of a Doona popping out of a vending machine from 1% - to 0.1%. - - bugfix: Made the outer windoor of the sci checkpoint all-access. - - tweak: Added an outer windoor to the RnD desk. - - rscadd: Chem dispenser now has a visual indicator when it has a beaker loaded. - - bugfix: Pill bottles loaded into the chemmaster now get filled. - - tweak: Tweaked uniform vendor so that it'll no longer eat your clothes. - Hubblenaut: - - bugfix: Fixes brig cell timers not connecting to windoors/mounted flashes. - Orelbon: - - maptweak: Science entrance has been edited & science has been made more open. - - maptweak: Medical has been remapped to be more efficient and increase workflow. - Rebruiza: - - rscadd: Individuals with the "Floorlength Braid" hairstyle now occasionally trip - on their hair. - Tlc2013: - - rscadd: Added the legendary CRT Test screen to IPC monitors. - mkalash: - - rscadd: All gloves that are available in the load out now have pre-modified versions - in the xeno load out. - - rscdel: Removed parapen, parasting, and the stun talisman. - sabiram: - - tweak: Maintenance drones now have spray bottles instead of soap. The cleaner - refills in chargers. - - rscadd: Hyposprays have been upgraded and now use removable vials instead of a - internal storage. - - tweak: Voice changers available in the upload now have chameleon mask functionality. - - rscadd: Holsters have been added to the gun cabinets. - - rscdel: Holsters have been removed from the bridge officer and Sol pilot's lockers. - - tweak: Gun cabinets now have a chance to spawn a small e-gun instead of the full - sized variant. -2017-11-11: - chaoko99: - - bugfix: Puts some jackboots in all the security lockers. Your feet will no longer - be cold. - mkalash: - - tweak: Welding tool sizes have been rebalanced. Namely, the industrial welding - tool is now too large for a tool belt. - - rscadd: To balance this out, engineers can now easily carry spare welding fuel - cartridges found in the welding locker and hot swap them out, actually increasing - the welding capacity of the typical engineer. - - bugfix: Experimental fuel tanks now automatically refill, as intended. - - rscadd: The experimental welding tool can now be produced in rnd. -2017-11-19: - Casper3667: - - tweak: Passengers (the job) can now use corporate uniforms. - - rscadd: NT corp uniform is now available in the loadout. - Chinsky: - - tweak: Ordering gun crates now requiers elevated alert level, Blue for small ones, - Red for big guns. - CrimsonShrike: - - rscadd: Now catwalks can be built above plating. - - tweak: Reinforced floor now requires 1 steel sheet instead of 2 rods. - - rscadd: Added catwalks. Can be built by using rods on existing lattice. - - bugfix: Fixed lattice icons on openspace turfs. - Hubblenaut: - - rscadd: The telecomms broadcaster, relays, station bounced radios and intercomms - now broadcast to all connected z levels. - - rscadd: Adds a relay circuit board to the telecomms storage. - - rscdel: Removes relay rooms and replaces them with maintenance. - Orelbon: - - rscadd: Ghosts can now click on non-modular consoles and see their UI. - Rebruiza: - - tweak: Cable coils no longer do damage when thrown. - - tweak: Cable coils are now "ITEM_SIZE_NORMAL", instead of "ITEM_SIZE_SMALL". This - means that they no longer fit in pockets, but rather has to be in a larger container - or off the side of a toolbelt, as intended. - SamSamsonthe3rd: - - bugfix: Can now build ED209 with plate armor. - Serveris: - - rscadd: Added the WT45 pistol. - - tweak: Line Officers now spawn with said in their lockers, rather than energy - guns. - Zero-Bits: - - tweak: '"Library Improvements. Removed Adult Category, made USBN usable."' - atlantiscze: - - rscdel: Cyborgs can no longer be self-destructed through the remote console. - - rscadd: Cyborg's precise position is now displayed on the console instead. - - rscadd: The console now offers you an option to send direct message to a cyborg. - This message is independent on telecommunications and range. - chinsky: - - tweak: Humanoids able to vent-crawl can now bring select articles of clothing - and carry items which are not too big. - comma: - - tweak: Propellant in fuel bay changed, instead of plasma it's CO2 now. Thrust - should be more or less same, but less eternal fires and more space for engies - to increase said thrust. - dryerlint: - - rscadd: Added fuel port object. When mapped into shuttles (like Charon or GUP) - it gives them a finite fuel reserve, which must be refilled with phoron. - mkalash: - - tweak: You can now place crowbars in security belts. - sabiram: - - rscadd: Added the pry bar, a smaller crowbar, to the autolathe. - - tweak: The damage values of tools have been adjusted. - sabirm: - - rscadd: Added a supply crate containing ammunition for the executive heads' revolvers. - - tweak: The rubber ammo crate now contains two rubber .45, two flash .45, and two - rubber .44 magnum magazines on the Torch map. - - tweak: As part of the Great Gun Experiment, all ammunition is now hidden in the - autolathe. - sick trigger: - - rscadd: Ghosts can now Check-Radiation. - sick-trigger: - - rscadd: Ghosts will now be informed of the contests of examined closets/lockers. -2017-11-20: - sabiram: - - rscadd: Added a disguised syringe gun to the loadout. Comes complete with four - cartridges and four syringes. Chemicals not included. -2017-11-22: - Cirra: - - tweak: Radiation is now relevant again, due to material radiation resistance being - lowered. - SierraKomodo: - - rscdel: Removed xenophage and cortical borer from the list of add antagonist vote - options until these antag types can be fixes. - atlantiscze: - - tweak: Communication outages are overall less common. - - tweak: Communication outage has only 75% chance to affect each particular machine, - therefore with some luck, enough machines may remain functional to get at least - some working frequencies. The hub, broadcaster and receiver have 10% chance - to be affected, as they are critical for the whole telecommunications system. - - tweak: Increased chance of ion anomaly being announced. There is still a small - probability of the anomaly occuring silently. - - rscadd: It is now possible to reset EMP/ion/random event affected telecommunications - machinery with a multitool through the UI. The UI also shows a timer until automated - reset. - dryerlint: - - rscadd: Added fuel ports to Charon and GUP. They will consume fuel and eventually - run out - - rscadd: Added small refueling room to Hangar, for anyone with Supply Warehouse - access -2017-11-23: - Casper3667: - - tweak: Fixes up balaclava and half-gas mask sprites for taj. - - rscadd: Adds new shoes for taj called caligae. - CountAlex: - - rscadd: 'Away mission map: Damaged and abandoned Planetary Shield Orbital Station' - Dukica: - - rscadd: Added the braided beard facial hair style. - Orelbon: - - bugfix: Ghosts cant griff with jetpacks anymore. -2017-11-24: - CrimsonShrike: - - rscadd: Added Hydrogen canisters to supply request list. - Dukica: - - rscadd: Added new hairstyles. - FTangSteve: - - tweak: Add SCG Police tag to CoS carrier - - tweak: upgrade CoS armour plate - Kelenius: - - tweak: Camera networks have been sorted in an other that makes more sense. - mkalash: - - tweak: The welding pack is now too large for backpacks. - - rscadd: You can now attach welding tools to welding packs via drag drop. - - rscadd: Welders now show an overlay of what fuel tank is attached, if any. - - tweak: Fuel cartridges are now welding fuel tanks. - orelbon: - - rscadd: New sprites for the 2x1 white airlock. -2017-11-25: - Kelenius: - - tweak: Teleporters don't need to be test-fired anymore. - sabiram: - - tweak: The XO now has unrestricted access to the Aquila. -2017-11-26: - CrimsonShrike: - - bugfix: '"Fixes openspaces above shuttles retaining image of the floor."' - chinsky: - - tweak: Melee attacks will now always hit targets with the Help intent selected. - comma: - - rscadd: Added EC directives plaques on Bridge/Charon/Exped Prep/walls near flags - in cryo etc. Their tl;dr is go explore instead of twiddling thumbs. - sabiram: - - rscadd: Added purple, orange, green and red carpets. - - rscadd: Added blue, blue and silver, purple, orange, green and red carpet tiles - to the supply computer. - - tweak: Changed the brown and blue carpet icons to match the new ones. -2017-11-28: - Casper3667: - - rscadd: Adds new taj security voidsuit sprites from Serveris. - FTangSteve: - - rscadd: makes item slowdown impacted by species strength - - tweak: changeling transform now takes time with a progress bar based on mob_size - difference - sabiram: - - rscadd: Vials can now be placed in bandoliers. -2017-11-29: - Chinsky: - - tweak: Meteor mode now progresses a bit faster on difficulty scale, and can produce - bigger waves in the end. - CountAlex: - - rscadd: Adding new map for overmap list - raided casino ship. - Orelbon: - - rscadd: Self Destruct Sequence Has been revamped. - - rscadd: Keycard device can now be used to get the nuke code. - - tweak: Keycard device now waits 3 seconds for someone else to swipe. - - rscadd: The vault has been replaced by the self destruct room on deck 1. - - tweak: The engineering supply room was moved into the side of the hallway on deck - 1. - - tweak: The vacant office was moved to behind the self destruct room. - Spookerton: - - bugfix: Fixes cyborgs being unable to repair doors. - Techhead0: - - tweak: Removes age gate from Janitor - - tweak: Changes crewman alt-tiles to "Trainee" instead of "Junior" - Zero-Bits: - - tweak: Ports the Library to the Modular Computer System - sabiram: - - rscadd: You can now drink from buckets and beakers by clicking with the HELP intent. - Clicking with HARM intent splashes/spills. - - rscadd: 'Added new scrub and surgical cap colours to random spawns and loadout: - white, lilac, teal, and heliodor.' - - rscadd: Added colour selection to scrubs and surgical caps in the loadout. - sick trigger: - - rscadd: Finalizing a matchmaking connection now informs the other player. -2017-12-01: - Casper3667: - - rscadd: Deck officer, pathfinder and explorers now got binoculars in their lockers. - CountAlex: - - tweak: Changed Biogenerator UI to nano-ui instead of basic HTML. - Dukica: - - rscadd: Added 3 new masculine hairstyles (Slick, Average Joe, Messy) - sabiram: - - maptweak: Added an AI holopad to security processing. - - maptweak: The XO once again has access to an AI holopad in their office. - - rscadd: Suit jackets, suit pants, baggy suit pants, and athletic shorts are now - colour-selectable in the loadout. - - maptweak: 'Added some cameras to the infirmary: one in the operating theatre, - and two in the main treatment centre.' -2017-12-02: - FTangSteve: - - tweak: new sprites for nabbers - - rscadd: can shift equip overlays on per species per slot per direction basis - sabiram: - - rscadd: Added a black pocketbook to the backpack selection. - - rscadd: Added a few dresses. The short dress is available in the loadout with - colour selection. Dresses in two styles and four colours are now available in - the uniform vendor for formal occasions for civilians. -2017-12-03: - BlueNexus: - - rscadd: Added a new creature, which can be found on certain away missions -2017-12-04: - Orelbon: - - tweak: Remapped the Lounge - Zero-Bits: - - bugfix: '"Fixed library program UI and bookbinder linking."' - sabiram: - - tweak: Sunglasses now apply a screen overlay when worn. - - tweak: A makeshift duct tape blindfold can now protect your eyes from welders, - if you don't mind welding blind. - - balance: All HUDs and other glasses types with electrical components are now vulnerable - to EMP, and will disorient you and turn the HUD off when hit. Neither of the - effects are permanent, and you can turn your kit back on right away. - - balance: Any glasses type with night vision no longer has flash/welder protection, - or is otherwise vulnerable to flashes or welders. - sabiram & chinsky: - - rscadd: The tobacco plant can now be grown, with a couple mutates. - - bugfix: Electronic cigarettes should no longer be more harmful than regular cigarettes. -2017-12-06: - PsiOmegaDelta: - - tweak: Character Setup - Some backpacks now have additional setup options. - sabiram: - - rscadd: Added a black pocketbook to the backpack selection. -2017-12-07: - BlueNexus: - - tweak: Slightly buffed "Mehren" - Casper3667: - - tweak: Taj can no longer use zeng-hu or veymed prosthetics or body. - CountAlex: - - rscadd: Added Oxygen regenerator device for Atmospherics. Device takes from an - input pipe CO2 and slowly feeds O2 to an output pipe and drops chunks of coal - on the top tray of the machine. - FTangSteve: - - rscadd: Add new emotes for nabbers. - atlantiscze: - - tweak: AI can now hack multiple APCs at once, assuming it has enough CPU power - to begin the hack. AI can use abilities while hacking an APC (the hacking task - has been completely isolated) - - tweak: AI can now use its abilities during system override. On torch the override - takes quite a long time due to larger amount of APCs, and during this period - the AI is otherwise very vulnerable. - - tweak: Failed advanced encryption hack now offers you to retry the hack without - having to copy-paste/write the message again. This should make the ability a - bit more comfortable to use. - dryerlint: - - rscadd: Added nuclear football (secure briefcase with disk, pinpointer, instructions, - and laptop) - - maptweak: Removed nuke disk and pinpointer from CO's office, replaced with nuclear - briefcase. Added pinpointer to Bridge Storage. - sabiram: - - balance: Flashes have been reworked when attacking humanoid targets. - - balance: Instead of stunning for 20 seconds, they will stun for up to 7 seconds, - and blur vision and confuse for up to 18 seconds. - - balance: Flash stun duration for silicons has been reduced from 10-20 seconds - to 8-12 seconds. - - tweak: The area-of-effect attack for flashes now blurs the eyes of those affected, - in addition to flashing them. - - rscadd: Flashes can now have varying effects by type. - - tweak: The flash used in robot construction is now weaker than the base flash, - but breaks just as often, instead of every time its used. - - tweak: The spray projectile fired from peppersprays now moves much faster and - their capacity has been increased from 4 shots to 6. - - tweak: Pepper spray now incapacitates for an additional 2 seconds. -2017-12-08: - Banditoz: - - tweak: Overmap is now a lot more hostile. - dryerlint: - - rscadd: Added the SolGov flag, a variant of the existing flags, but with SolGov - logo on it. It is found in Exploration Storage. -2017-12-09: - Casper3667: - - tweak: The taj species blurb in char setup has been updated. - sabiram: - - rscadd: A more gentle carp event has been added to the overmap to supplement the - more dangerous version. The event icons with three carp are the more dangerous - schools. - - rscadd: Space carp can now be encountered on the overmap. - - rscadd: Ion clouds have condensed in the vicinity of the ship and can be collided - with on the overmap. -2017-12-10: - sabiram: - - rscadd: Added a few different colours to the satchel and pocketbook selection - in character setup. -2017-12-11: - Orelbon: - - maptweak: Xenobotany Has been remapped for space and usability. - - maptweak: Xenoarchiology lab has been moved to the Petrov. - - maptweak: Misc Lab is now a circuit lab and a small chemical testing chamber. - - maptweak: A chemistry station & toxins have been added to the Petrov. - Techhead0: - - rscdel: Science wing and channel has been reverted back to purple. - dryerlint: - - tweak: Flags can now be placed on any terrain/turf, except for space -2017-12-12: - BlueNexus: - - tweak: Nerfed the .50 pistol fire rate and recoil. - Hubblenaut: - - rscadd: Atmospheric pumps can be toggled by alt clicking. - - rscadd: Carafes and implanters are now available in the autolathe. - - bugfix: Implants are now trackable across connected z-levels. - Kelenius: - - tweak: Merchant now has two slots. - mkalash: - - tweak: Spacemen no longer pin their IDs to their skin when they roll down their - jumpsuits. - sabiram: - - tweak: Mounted flash effect changed from 20 seconds of knock down to 6 seconds - of knock down followed by a further 10 seconds of stun - a total of 16 seconds - of useful disable - followed by a further 8 seconds of confusion. - - tweak: Flash and flare cartridges now inflict more agony damage. - - rscadd: Flash and flare cartridges now blur the vision and disorient those within - their flash ranges - tiles adjacent to the explosion for flashes, and two tiles - adjacent for flares. -2017-12-13: - Techhead0: - - tweak: Vey-Med prosthetics are now restricted to humans only. Zheng-Hu is now - restricted to humans and IPCs. -2017-12-14: - Casper3667: - - rscadd: Vox gas masks are now available for vox in the loadout. - sabiram: - - rscadd: Control+Alt clicking a PDA will now toggle the flashlight. - - rscadd: Control+Alt clicking closets and lockers is now a shortcut to the toggle - open verb. - - tweak: AI door electrification shortcut moved from Alt-click to Control-Alt-click - to remove conflict with Alt-click inspecting the turf. -2017-12-15: - IsdatAfamas: - - rscadd: '"Added a small ship as an overmap location."' -2017-12-16: - sabiram: - - rscadd: Added new varieties of smokable to the smoking vendor. -2017-12-17: - BlueNexus: - - tweak: The WT45 now fires slightly slower, and is more accurate. - - tweak: The Mk58 now fires slightly faster, and is less accurate. - - tweak: Revolvers fire slightly slower, in general. - - tweak: Adjusted fluff for several firearms - - rscadd: The CO's revolver has been replaced with an autorevolver. - ParadoxSpace: - - bugfix: Diona now properly regenerate organs and limbs. -2017-12-19: - Casper3667: - - rscadd: Surgeon borgs now have defibrillator. - - rscadd: Crisis borgs now have medical tape. - - rscadd: Engie borgs got atmos atmos tape. - - rscadd: Security borgs now have a megaphone module. - TheWelp: - - rscadd: Reworks early game deity. No longer have to dole out spells and you regenerate - power 100% faster. -2017-12-27: - BlueNexus: - - spellcheck: Renamed the 9mm machine pistol to the 9mm submachine gun - - bugfix: Fixed the WT45's empty icon not showing - Broseph Stylin: - - rscadd: Added colored helmet covers matching the plate carriers. Available in - the loadout. - Casper3667: - - rscadd: Taj are now forced to have Siik'maas. - Chinsky: - - rscadd: Added some sekrit documents to CO/SCGR offices in sealed envelopes. Don't - really affect anything, just fluff. Moved RD's secret memo to an envelop in - his office too, put a copy on Liason's desk. - CountAlex: - - tweak: Turns casino liner into actual overmap ship with a small shuttle. - - rscadd: Adding new map for overmap list - hidden deep inside asteroid slavers - base. - Kelenius: - - rscadd: Hydroponics now has bees and space for bees. And some chemical machinery. - Orelbon: - - tweak: Laser carbine has 10 more damage and +2 accuracy. - - tweak: Taser carbine now has 12 shots, +1 accuracy and looses its 10 armor penetration. - - tweak: Stun rifle now has 10 shots, +1 accuracy,+10 armor penetration,+5 burn - damage and looses 10 agony. - - tweak: Stun revolver now has 6 shots and 50 agony. - - tweak: Ion weapons shouldn't be horrible anymore, they now activate their emp - no matter what they hit. - - tweak: The rifle now has a max range of 2, and the pistol a max range of 1. - - tweak: Ion pistol max shots lowered to 6. - ParadoxSpace: - - rscadd: Added a regeneration mechanic to Unathi. This works on nutrition. - - rscadd: Unathi now get hungrier faster, and enough hunger starts to give you toxin - damage. - sabiram: - - bugfix: Mounted flashers will no longer permanently scramble ghosts' movement. - - rscadd: Added missing eye blurring effect to mounted flashers. - - tweak: Maintenance and construction drones now move faster. - - bugfix: Lockers can once again be welded shut. - - rscadd: Clicking a drinking glass with a spoon will now call the room to attention. - Just be careful. - tlc2013: - - rscadd: Ported over three IPC screens from Polaris. I think we're done there. -2018-01-03: - ParadoxSpace: - - experiment: Removes the AI from the job list for two weeks. - TheWelp: - - rscadd: Adds band-aid fix to deity spam via cooldowns. Will add graphical indicator - to show what the cooldown is later. - - rscadd: Modifies phenomena near structure logic to include all deity structures, - not just altars. -2018-01-04: - CountAlex: - - rscadd: Adds away mission map - Mobius Rift. -2018-01-05: - CountAlex: - - rscadd: '"Adds engineering program for monitoring shield generators."' - PsiOmegaDelta: - - tweak: Can now adjust (almost) all prefix keys. These are used for language selection, - emoting, etc. See Character Setup > Global > Prefix Keys -2018-01-06: - Casper3667: - - tweak: The CSA now has the crime scene kit in their locker. - - bugfix: Forensic is yet again capable of using the dna search function in records - and can also edit pictures in records. - Devildabeast: - - rscadd: Adds one Crime Scene Analyst slot to Security. They are a forensic contractor - job that are NOT responsible for law enforcement. -2018-01-07: - comma: - - tweak: Adds gauze roll to emergency survival boxes - sabiram: - - tweak: As a cost-cutting measure, all Sol uniforms are now cut from the same cloth. - Armour values have been genericised. - - rscdel: Sol uniform hats no longer provide any armour. - - maptweak: The hydroponics base away site has been updated. - - experiment: As part of AI removal testing, an additional robot slot has been added. - - rscadd: Command hardsuit control modules have been added to the EVA storage on - the bridge deck. - - tweak: Changed CE hardsuit values to sync somewhat with new these modules. - - rscadd: Added a ring bell to the holodeck boxing ring. -2018-01-08: - Casper3667: - - rscadd: Taj now have several new capes! - - rscadd: Cameras can now be found in the loadout. - Chinsky: - - rscadd: Shuttles now need proper docking codes set in their console, or the docking - won't initiate. - - rscadd: Codes can be found in CO's orders, or by using multitool on docking controllers. - You can also hit the button on docking controller from inside to initiate docking. - - rscadd: There is also a program that shows status of all docking ports and their - codes, can be used to remotely let people dock if they're waiting outside. - Techhead: - - rscadd: You now receive pain-flashes for all pain sources. - - bugfix: Possibly fixes an infinite paincrit bug. -2018-01-09: - Devildabeast: - - rscdel: Removes SolGov Pilot. - - tweak: Gives Bridge Officers access to pilot the Aquila and Guppy and accompanying - access. - - tweak: Bridge Officers now have the Pilot's headset. - - rscdel: Removes SolGov Pilot's locker from the Pilot's Lounge. - - rscadd: The Pilot's Qualification Pin is now an item in the loadout for Bridge - Officers who want to flash their fancy training. - Zero-Bits: - - tweak: Cult walls are just normal creepy now instead of super edgy. -2018-01-10: - CountAlex: - - rscadd: Adds away mission map - SEV Icarus irradiated crashsite. - Heptagon49: - - bugfix: Adds a hydrogen tank sprite, among others, for the transfer valve. - Kelenius: - - rscadd: Syringes can now inject people in body bags and cryo bags. - LorenLuke: - - rscadd: Added/changed alt-titles for engineering contractor. - ZeroBits: - - imageadd: '"Hydrogen now has its own canister and tank sprites"' - - spellcheck: '"TX on monitoring computers is now PH, as it should be"' - - tweak: '"Omni Filter and Omni Mixer throughput increased to match pressure regulator"' - - tweak: '"Flamethrower now uses Hydrogen"' - - tweak: '"Phoron canister made slightly more expensive via supply"' - - tweak: '"Hydrogen canister made slightly more expensive via supply"' - - tweak: '"Filters and Mixers can now handle Hydrogen"' - - tweak: '"Supermatter monitoring program and gas sensors can now detect Hydrogen"' - - tweak: '"Overmap shuttles now use Hydrogen by default"' - - rscadd: '"Added purchasable crates of portable Phoron and Hydrogen tanks. Cheaper - than a full canister, but with far less volume."' - - maptweak: '"The SM reactor is now set up for CO2 by default"' - - maptweak: '"The SM reactor now has a Phoron gatherer so you no longer shoot that - valuable Phoron out into space."' - - maptweak: '"Nitrogen is no longer available directly in the SM room (it never - meets energy or safety needs anyway)"' - - maptweak: '"The fuel Bay is now filled with Hydrogen (rocket fuel) instead of - Phoron (the supposed most valuable substance in the universe)"' - - maptweak: '"Most of the Phoron tanks and canisters on the map have been replaced - with Hydrogen. R&D and Engineering each retain one canister."' - - maptweak: '"The Phoron resevoir in atmos has been replaced with a hydrogen resevoir."' - - maptweak: '"The incinerator now uses Hydrogen instead of Phoron. You''re just - burning stuff, you don''t need to do it with gaseous money."' - - maptweak: The Supermatter core is no longer filled with N2 by default. - comma: - - balance: Attacks against legs and heads are now more likely to miss. - tlc2013: - - rscadd: Added sandals to the loadout selection. Because those weren't there before, - apparently. -2018-01-11: - chaoko99: - - bugfix: Synths can no longer fill mechfabs with their matter synths. - rainbowEscapist: - - rscadd: Adds the alt title 'Trainer' to the Passenger loadout. -2018-01-12: - Chinsky: - - tweak: Cryobags, cryo and general stasis changes. Main point is that stasis is - no longer binary on/off, it doesn't stop life ticking, just slows it down (usually - a lot). It chemical processing is slowed down too, so sometimes bigger stasis - is not better. - - tweak: Cryo. Being very cold now provides stasis on its own - and cryo is easiest - way of doing it. At 80K, it applies 20x stasis factor (life ticks once in 40 - seconds instead once in 2). - - tweak: Cryo chemless healing was slowed down a bit. It also no longer magically - multiplies chems in beakers by 10x. Cryox/clonex adjusted to work at same efficiency - with this change. - - tweak: Cold damage in cryo is now prevented by clonex or cryox, not cryopod itself. - On one hand you now NEED to have it in beaker if you care about patient, on - another - you don't need cryopod if you have those and sufficiently cold place. - - tweak: Cryobags. Cryobags no longer last forever. Their power drops every 5 minutes - - examine to see current. It starts at 20x and loses 25% every time, so 20x - to 15x to 11x in 10 minutes and so on. Will drop into nothingness at ~40 minutes - mark. - - rscadd: Stasis will make you drowsy, and at higher stasis settings you will fall - asleep eventually (15x or higher). - - rscadd: 'Sleepers can into stasis too! They have three settings: none, 3x and - 5x.' - FTangSteve: - - tweak: Changeling now can only get nabber DNA with direct absorption. - Hubblenaut: - - tweak: RCON program no longer shows SMES units and breakers offsite the Torch. - - tweak: Alarm monitoring program no longer shows alerts offsite the Torch. - - bugfix: Fixes deck four fore dock. - Sbotkin: - - tweak: RCA, Shield Generator and Emitter crates now require engine access. - TheTrollDoctor: - - rscadd: Adds the MedHUD Visor item to loadout. It's a ~stylish~ MedHUD reskin - accessible for Medical roles. - sabiram: - - rscadd: Added advanced flash, smoke grenade, and metal foam grenade launcher hardsuit - modules. - - tweak: The captain's hardsuit now has an AI container, advanced flash and smoke - grenade launcher. - - tweak: The XO's hardsuit now has an advanced flash and smoke grenade launcher. - - tweak: The CE's hardsuit now has a metal foam grenade launcher. - - bugfix: The rig mounted RCD's use cost has been reduced from 100,000 to 300. - - bugfix: The correct voidsuits can now be found in command EVA. -2018-01-14: - Hubblenaut: - - bugfix: Fixes the horrible mess of pipes that was xenobiology. - LorenLuke: - - rscadd: Adds timestamp to PDA messages. - Orelbon: - - tweak: Consoles have been resprited. - comma: - - tweak: Chemist is now its own job slot. Medical Contractor slots lowered by one. - - rscdel: Removed Mortician because you don't get more useless than that. - sabiram: - - bugfix: Autolathes now function as normal. - - tweak: Bridge Officers now additionally have basic explorer access. -2018-01-15: - Techhead: - - tweak: A survey of medical supplies found the size of pill bottles woefully inadequate. - Larger pill bottles with more pills have been issued. -2018-01-16: - CountAlex: - - tweak: '"Refactoring corpse spawners."' - chaoko99: - - rscadd: Lasers and muzzle flashes now illuminate their surroundings. - - tweak: Beams are not visible quite as long due to vast optimizations in how they - are rendered. - - tweak: Muzzle flashes will now appear over lighting, and do not last nearly as - long. - - tweak: Bullets now fly more smoothly towards their targets. - - bugfix: Fixes a bug that caused the L6 SAW to load an empty sprite when closed - without a box magazine inside. - comma: - - tweak: Overmap size has been decreased. - - tweak: Number of overmap events has been decreased. - - tweak: Potential number of away missions has been decreased. - - bugfix: Ashtrays now empty their contents when thrown. - - tweak: Torch now starts at a random location on the overmap -2018-01-17: - Banditoz: - - maptweak: The GUP airlock now works. - Chinsky: - - rscdel: After yet another PR fiasco over field executions, Marine contingent is - no longer allowed on Torch. Those not under active investigation are offered - a transfer to Expeditionary Corps if they want to participate in the mission. - Earthcrusher: - - tweak: Thanks to the tightening of SCG industrial safety guidelines, you now must - be on harm intent and wait a few seconds before blowing up a fueltank with a - lit welder, lighter, or other handheld source of flame. - chaoko99: - - rscadd: cloaked mobs (ninjas and whatnot/Mehren) can now be spotted via T-ray. - - bugfix: Lasers will no longer fail to disappear during bluespace jump. -2018-01-18: - Chinsky: - - tweak: Modular computer programs were patched to allow more abuse. Now they use - the access of user who started them, instead of constantly checking for current - user's. - Orelbon: - - bugfix: Suit storage units now check for access. - - tweak: Suit storage units don't drop items when the powers fails anymore. - - tweak: Suit storage units can now be pried open when they are powered off and - not locked. - - tweak: Suit storage units can now dispense items when they are offline. - 'author: PrismaticGynoid': - - rscadd: Adds the ability to 'crawl' to an adjacent turf by click-dragging yourself - to it, after a delay. This can be used to move while unable to stand. You can - also do this with other movable objects, if you really wanted to. - - tweak: Conscious mobs lying on the ground can now buckle themselves to chairs/beds. - This includes people missing legs. - chaoko99: - - rscadd: Plasma cutter is now a gun, instead of a fancy drill. -2018-01-19: - Sbotkin: - - maptweak: The Pilot Lounge has been replaced with the Pathfinder's Office. - - maptweak: The NT pilot's voidsuit has been moved to the Petrov, with the cycler. - Techhead: - - rscadd: Corpsman and Engineers have been granted access to the hangar to help - them go on expeditions. Or help with the inevitable injuries and damage from - returning expeditions. You know, whichever. -2018-01-20: - Sbotkin: - - tweak: Changed required players for cult and deity from 5 to 10. -2018-01-21: - Orelbon: - - rscadd: Modular consoles now have colored keys per program. -2018-01-23: - Devildabeast: - - rscadd: Added a maglight to the Security Guard's locker. Yay. - comma: - - rscadd: Sharp things are now better at cutting plants, doing double damage. -2018-01-24: - Chinsky: - - tweak: Expeditionary Corps paygrades were adjusted - Explorers are now E3, Senior - Explorers are now E5. Brings Explorers more in line with 'default' rank of other - branch(es), Crewman/PFC. - - tweak: 'Senior Explorers: can no longer be Janitors, Masters at Arms. Can be Brig - Officers, Deck Officers, Senior Engineers.' - - tweak: 'Explorers: Can be Corpsmen, Forensic Techs.' - - rscadd: Can now use IV bags to give IV to people - drag it onto them to start. - Only works when bag is held in hand by someone. - - rscadd: Can now use syringes to change contents of IV bags. - - tweak: IV bags now hold 120u instead of 200u. Their size is dynamic - tiny item - when empty, turning into normal sized (doesn't fit in pockets etc) when over - 60u inside. - - rscadd: Can now set transfer rate of IV drips with a verb. - - tweak: Blood bags in medical and orderable crates were replaced with NANOBLOOD. - The normal blood was just not as efficient with size/transfer rate changes. - Using NANOBLOOD nets you more or less same re-blooding speed. - FTangSteve: - - tweak: Bioprinter will now print species-specific internal organs if they are - available - Novacat: - - spellcheck: Fixed capitalization issue with Radiant Aura - - rscadd: Added telepath (mRemoteSay) contract to all spellbooks - - tweak: Added 1 point to all spellbooks - - rscadd: Added Teleport, Cure Light Wounds, and Noclothes to all spellbooks that - lacked them - - rscdel: Removed Mage Armor from Standard spellbook, and Cure Light Wounds from - Cleric spellbook - - tweak: Swapped Focus staff for Scrying orb in Cleric book - - rscadd: Added X-ray contract to Battlemage book, parrot transformation to Druid - book - - rscdel: Removed Student spellbook - - tweak: Made staves slightly smaller, so that they are more portable - - rscadd: Overhauled cure spells to be more effective - - tweak: Reduced cost of Spatial's magic missile to 1 - - tweak: Boosts healing spells ability to purge radiation - - tweak: Fixes sacrifice self-damage - Sbotkin: - - rscadd: Adds mounted cooling units, available in all hardsuits. -2018-01-25: - chaoko99: - - bugfix: Attacks will no longer phase through dead or otherwise incapacitated slimes. - - tweak: Slime surgery is generally faster and now supports researched scalpels - and incision managers. -2018-01-26: - Casper3667: - - bugfix: Torso tattoos now works! - CrimsonShrike: - - rscadd: You can now move down onto turfs containing climbable atoms (tables, machinery). - chaoko99: - - imageadd: Removed paint drips from door sprites and doubles their framerates. -2018-01-27: - Casper3667: - - rscdel: Taj curly, housewife, victory curls and finger curls hairstyles have been - removed. - CountAlex: - - tweak: '"Lowered the temperature at which a mob receives lung damage from -13C - to -30C."' - Orelbon: - - rscadd: New glass door sprite. - chaoko99: - - rscadd: Added a parallaxing background space that changes colors every round. -2018-01-28: - Casper3667: - - rscadd: There are new bandanas in the loadout that can be worn on the head and - over the mouth. Old bandanas are still available in the loadout. - Devildabeast: - - rscadd: Adds the decorated harness, an Unathi-exclusive accessory complete with - two dueling knives, to the loadout. - - tweak: Changed the dueling knife to a piss-weak variation of the kitchen knife. - - tweak: Changes scarves to be allowed for semi- and formal roles in the loadout. - Sbotkin: - - tweak: Several loadout access tweaks. More things for civilians and pilot's pin - for the CO, XO, and Pathfinder. -2018-01-30: - Chinsky: - - tweak: Shuffled around EC uniforms. SERVICE uniform is now a thing of its own, - NOT a mix of utility+service. DRESS uniform is now service uniform + dress jacket - + gloves. - - tweak: R&D lab refluffing. No longer 'Research', it is now called 'Fabrication' - Lab. You are not 'discovering' things anymore. You are using high-tech fabricator - that uses self-learning matrix to direct nanobots. Problem is, IT KEEPS GETTING - MEMORY CORRUPTION. You are re-training bots by letting them practice on less - complicated things before they can tackle more challenging blueprints. - Devildabeast: - - tweak: Gives the NanoTrasen badge to the NanoTrasen Liaison in their backpack; - removes it from the NT formal outfit. - chaoko99: - - tweak: Trash bags are no longer denied from holding the nuke disk. Try and figure - that one out. -2018-01-31: - CountAlex: - - rscadd: '"Adds away mission map XCV Ahab''s Harpoon."' - Memescope: - - rscadd: Added new hairstyles, some ported from Eris. - - tweak: Low Bun back sprite tweaked. - - tweak: Half-Shaved Emo renamed to Long Side Emo. - chaoko99: - - rscadd: The T-Ray scanner now can be toggled via an action button. - - bugfix: Lasers now exist long enough that the game is likely to actually render - them most of the time. I blame our tickrate. - comma: - - rscadd: '"Added Fleet patches for their respective Fleets of origin to loadaout. - Check https://wiki.baystation12.net/Defence_Forces#The_Fleet for more deets"' -2018-02-01: - Dukica: - - rscadd: Adds new hairstyles and beards. - FTangSteve: - - rscadd: '"Upgrading to aggressive or initiating normal grab now enters struggle - if victim isn''t on help intent."' - ZeroBits: - - bugfix: '"Heat Exchange Pipes can now be properly constructed."' - - tweak: '"Heat Exchange Junctions will now exchange heat."' -2018-02-02: - FTangSteve: - - tweak: '"Nabbers now have hue shifted sprites available"' -2018-02-03: - Hubblenaut: - - bugfix: Fixes plating being dark when prying off floor tiles. - Sbotkin: - - tweak: Added kitchen access to bartender and bar access for chef. - - rscadd: Added a bar locker. - - maptweak: Added actual bar stools to the bar. - - maptweak: Removed wall-mounted safe from the bar. - 'author: FTangSteve': - - tweak: Makes struggle grab state shorter and causes confusion to make resisting - grabs more difficult - chaoko99: - - bugfix: You can now crawl through vents without worrying about carrying reality - (The skybox) in your body! Squeek! -2018-02-04: - Hubblenaut: - - bugfix: Fixes alert monitors being red for away mission alerts. - - bugfix: Fixes nonmodular atmos/alert consoles showing away mission alerts. - Sbotkin: - - rscadd: Polarized windows are now buildable. Click a reinforced one with a cable - coil. - - rscadd: Their IDs are changeable as well, use a multitool on windows and buttons. - Techhead: - - bugfix: Antag preferences default to Low again instead of Never. Relatedly, your - preferences will now longer display Never when they haven't actually been set - as such, fixing a bug causing unwilling players to be drafted for antag status. - TheTrollDoctor: - - rscadd: Gives Engineering Contractor, Medical Contractor and Research Assistant - access to the hangar. -2018-02-05: - Hubblenaut: - - bugfix: Camera alarms get cleared upon repair. - PsiOmegaDelta: - - tweak: Labels that have been attached using a hand labeler will now be remain - even if the name changes. - - rscadd: Attached labels can now be removed using the "Remove Label" verb in the - "Object" category. - sabiram: - - bugfix: Corrected chemist slot loadout issues. - - bugfix: NanoTrasen security staff can now use their provided holobadges. -2018-02-06: - Hubblenaut: - - rscdel: Removes Captain's spare ID card. - Sbotkin: - - tweak: Supermatter hallucination does not affect people without eyes or with synthetics - eyes. -2018-02-07: - Hubblenaut: - - bugfix: Fixes windows not visually connecting. - Sbotkin: - - tweak: Adds the medical channel to the roboticist's headset -2018-02-08: - Devildabeast: - - rscadd: Added the alternate titles of "SolGov Ombudsman" and "Inspector General" - to SolGov Representative and "NanoTrasen Representative" and "NanoTrasen Executive" - to the NanoTrasen Liaison. -2018-02-09: - Casper3667: - - rscadd: The utility uniforms (EC, general and EC skirt) now looks better on taj. - Additionally so does the welding helmet. -2018-02-11: - ZeroBits: - - tweak: '"Dark Floor Tiles can now be made with steel."' -2018-02-12: - Hubblenaut: - - tweak: There is now an announcement when the rampant brand intelligence was successfully - gotten rid of. - - tweak: The origin vending machine now shoots a lot more aggressively. - - tweak: Blinking red light on a vending machine now means that it shoots. - - bugfix: 'Hacker event: Hacker was destined to always lose. Fixed.' -2018-02-13: - CountAlex: - - rscadd: '"Adds away mission map - Lar Maria."' -2018-02-16: - Techhead: - - rscadd: Adds a new matchmaking relation, Childhood Friend. It'll only pick people - from the same home system with the same approximate age. - - tweak: Served Together now prefers to match people with others in the same branch. -2018-02-17: - sabiram: - - tweak: The mounted plasma cutter found on hardsuits has been converted to a projectile - weapon, like the stand-alone item. - - balance: The hardsuit mounted plasma cutter's ammo capacity has been reduced to - 4 from 10. -2018-02-19: - Techhead0: - - bugfix: PDAs and Air Alarms should now detect exotic gases a little better. Phoron - is now counted as an exotic gas for these purposes. - sabiram: - - balance: Stun weapons are now much less effective against simple animals, such - as carp. -2018-02-22: - Hubblenaut: - - bugfix: Fixes gravity event bringing people to fall in areas that do not usually - have gravitation. - chaoko99: - - rscadd: Ctrl clicking a table will flip or unflip it. -2018-02-25: - Hubblenaut: - - bugfix: Fixes the handheld teleporter only working as expected when adjacent to - teleporter hub. - - bugfix: Fixes the ref2name converter only working when adjacent to target. - - tweak: Medical scanner integrated circuits now work in vision range. - - bugfix: Fixes ducttape not being able to be picked up. -2018-02-26: - Banditoz: - - rscadd: Dog tags now have useful information on them upon spawn, including branch, - religion, and blood type. -2018-02-27: - sabiram: - - rscadd: The null rod can now purify cult floors in addition to walls. - - balance: The null rod's damage has been reduced. - - tweak: Maw creatures, ghost dogs, faithless and shades are now take additional - damage from the null rod. - - tweak: The null rod is now the null sceptre, a normal sized item. -2018-03-03: - LorenLuke, TheTrollDoctor, ChaosAlpha, sabiram: - - rscadd: Humans with sufficiently long hair can now tie their hair into different - styles using the 'Tie Hair' verb in the IC category. - mkalash: - - tweak: Infections get worse much more quickly (from ambient to acute in five minutes, - acute to septic in 10 minutes) - - tweak: Antibiotics take longer to work and infections acute and above require - antibiotics and rest to cure. -2018-03-04: - Banditoz: - - tweak: The shield generator's emergency shutdown function is now hidden behind - a hackable wire. - - tweak: Cut down the shield generator's emergency shutdown time by 50%. - - tweak: The EMP from the emergency shutdown scales with current charge--and is - guarenteed to happen. - Hubblenaut: - - rscadd: The access decrypter now allows the user to choose an access code instead - of picking one by random. - sabiram: - - rscadd: Some simple_animals, most notably humanoid enemies, can now escape nets. -2018-03-05: - Banditoz: - - rscadd: The Chaplain's locker now has a bible. - Novacat: - - tweak: 'Advanced First Aid Kit: Swaps inaprovaline autoinjector for assorted pill - bottle.' - - tweak: 'Burn First Aid Kit: Adds three ointment kits, swaps inaprovaline autoinjector - for tramadol autoinjector' - - tweak: Oxygen first aid kits now contain inaprovaline pill bottle, dexalin pill - bottle, and four inaprovaline autoinjectors - - tweak: Toxin first aid kits now contain a dylovene pill bottle, three hyronalin - pills, and four autoinjectors of dylovene - - tweak: Autoinjectors are now the same size as syringes - - tweak: Emergency Oxygen/Nitrogen Tanks now start off full - - tweak: Regular Nitrogen tank starts off at the same level as oxygen tanks - - tweak: Paracemetol's painkiller effect increased from 25 to 35 - Sbotkin: - - maptweak: The D2 Teleporter and the Custodial Closet are swapped. - - maptweak: The Drone Bay's door access is changed to robotics and no longer bolted. - chaoko99: - - rscadd: Research goggles now readoff research levels, as well as an item's matter - contents. When used to examine reagent containers (Beakers, burgers, bloodbags), - it will read off the contents. But . . . - - bugfix: get_reagent() no longer returns a given reagent's path. - thefrostycoder: - - rscadd: Languages that you can understand will now be named when they are spoke. - (Ex. ' enunciates in Selenian') -2018-03-06: - thefrostycoder: - - bugfix: Fixed random paint drips on doors. -2018-03-08: - chaoko99: - - tweak: Most bots will now render below a human. - - rscadd: Floorbots will now assume the colors of the toolboxes used to make them. - - imageadd: Added a Syndicate floorbot. Sadly, he is not evil. - - imageadd: Advanced trauma medibot added. - - bugfix: Cleanbot works now. -2018-03-10: - Rebruiza: - - soundadd: APC's now play a satisfying sound when they run out of power. - - soundadd: Maintenance now has ambience. - - soundadd: Fire alarms now have a new sound. - - soundadd: Airlocks and bolts now have a new sound. - - soundadd: Blast doors now have a new sound. - - soundadd: Suit storage units now have a new sound. - - soundadd: Lockers now have a new sound. - - soundadd: Touching metal walls now have a new sound. - - tweak: The sound of tube lights turning on is now louder. - Techhead0: - - rscadd: You can now temporarily reseal damaged spacesuits with duct tape. Either - click on the suit itself, or target the chest and click on a mob wearing a spacesuit. - But be warned, further damage will tear off the patch. - TheWelp: - - rscadd: Adds a temporary effect object to make spells look prettier. - sabiram: - - rscadd: The Sol Representative and the NT Liaison have been provided a fancier - pen in their PDA for writing their important documents. -2018-03-11: - Devildabeast: - - rscadd: Adds a Morpheus Cyberkinetics uniform to the loadout. -2018-03-12: - chaoko99: - - rscadd: Cremation now takes time. Doing so with a live subject inside will cause - it to rattle around violently. You monster. - - rscadd: You can now resist out of a crematorium on a short timer. You may also - eject someone from a crematorium from outside it on a similar timer. - - bugfix: Crematorium now uses a glowing sprite when active. - - imageadd: Changes the crematorium and morgue slab sprites to something cleaner. -2018-03-13: - chinsky & sabiram: - - rscadd: Belts and towels can now be worn on the belt slot, even with no clothing - equipped. - mkalash: - - rscadd: Added secure energy guns, which require registration to a user and are - locked to stun without additional per-mode authorization. Secure small energy - guns replace security's tasers. - - rscadd: NTsec now also get a shock mode for their revolvers, which is also locked - behind command authorization. -2018-03-14: - Banditoz: - - tweak: Everyone is now able to use dog tags. - Devildabeast: - - tweak: Off-Duty is now a separate role from Passenger, and is allowed to wear - Service and Dress uniforms. - mustafakalash: - - rscadd: You can now deface people's heads by targeting it with help intent and - using a pen, crayon, or lipstick -- even if it's no longer attached. Heads with - shoulders below them can be gentrified using a shower, or in a sink otherwise. - - bugfix: You can no longer apply lipstick to things without lips. - sabiram: - - rscadd: The King of Goats now has a chance to enter a 2nd phase in combat. -2018-03-15: - Devildabeast: - - tweak: Forensic Technicians can now be Civilian Contractors. - - rscdel: Private Investigator has been removed as an alternate title from Passenger. - afterthought: - - bugfix: The Odysseus syringe gun can now synthesize reagents. - - bugfix: Slipping out of mechas during gravity failure fixed. - sabiram: - - maptweak: The pens that previously spawned in the CO and XO's offices now spawn - in their PDAs, instead. -2018-03-17: - Sbotkin: - - tweak: Makes thick clothes to protect from changelings' stings. - - tweak: Makes buosuits thick. -2018-03-20: - Banditoz: - - rscadd: You will now be thrown around while on a shuttle if you aren't buckled. - Devildabeast: - - bugfix: Corrects a typo in the code, gives the Contractor Forensic Technician - the correct badge, and gives them additional items in the loadout. -2018-03-21: - Chinsky: - - tweak: Non-broken ribs/skulls now protect the internal organs a bit. - - tweak: Bullets no longer damage internal organs twice. As an effect organ damage - from bullets is lowered significantly. - Hubblenaut: - - rscadd: Adds the Disciplinary Board Room. - mustafakalash: - - bugfix: Using resist to unbuckle yourself no longer temporarily breaks your hands. -2018-03-22: - Chinsky: - - bugfix: Mass-spectrometers now actually display names of reagents. - Crushtoe: - - bugfix: For the very first time, toggle-hub-visibility works. - Devildabeast: - - rscadd: Adds a uniform for Skinner Catering and a pin for the Free Trade Union - to the loadout. - afterthought: - - bugfix: Various borg gripper fixes, including self-upgrading, cooking, APCs, and - mecha - chaoko99: - - rscadd: Xenophage cultists are now a feature-- They are allowed to ventcrawl with - tomes, robes, and swords. Also monkies I guess. - mkalash: - - rscadd: You can now toggle off showing end titles. - mustafakalash: - - rscadd: Staff now have the ability to mark variables to easily view them in an - auto-updating panel. - sabiram: - - imageadd: Secure energy guns are now visually distinct. -2018-03-24: - Atebite: - - rscadd: Telecommunication servers now have tagging rules which determine the radio - channel name and color for a given frequency - sabiram: - - rscadd: Hardsuit rig modules damaged by EMP can now be repaired with nanopaste. -2018-03-25: - Devildabeast: - - rscadd: Adds a gyroscooter, a subtype of the space bike. - - maptweak: Adds a gyroscooter to the Research Director's office. - TheWelp: - - tweak: Tweaks zombie turn rate. Should be non-impossible. - - bugfix: Fixes zombie consume. - sabiram: - - rscadd: Wall mirrors are now containers, and contain some things. - - tweak: F6 is now msay instead of asay for staff. -2018-03-26: - Banditoz: - - rscadd: Add the ability to rename a bible, or change its icon. - - rscadd: Add new bible sprites from tlc2013. - Devildabeast: - - tweak: Allows Dionaea to select Forensic Technician at chargen. - - tweak: Makes the Roboticist a hybrid role between Engineering and Medical and - gives them access to medical items in the loadout. - Earthcrusher: - - rscadd: Adds a package wrapper synthesizer. - - tweak: Clerical borgs now include a package wrapper synthesizer and destination - tagger. - - tweak: Clerical borgs now have a "clerical gripper", not a "paperwork gripper", - and can pick up small-sized packages. - - tweak: Clerical borgs now include the Supply channel, in addition to Service. - - tweak: The destination tagger will now give feedback when selecting a destination. - - bugfix: Back-end adjustments to how package wrappers and synth grippers are handled. - FTangSteve: - - tweak: changes injury specific medical kit contents to medical pouches. - - tweak: advanced medical kits are now purple. - - rscadd: adds small emergency medical pouches that require no medical training - to use. - - maptweak: adds new medical items around. - - tweak: adds medical pouches to nanomeds - TheGreyWolf: - - bugfix: Armor pouch colors can now be properly selected from loadout. -2018-03-27: - Atebite and Cakey: - - rscadd: Ironing equipment to get those unbecoming wrinkles out of your uniform... - or your crewmates - - bugfix: Washing machines no longer eat clothes -2018-03-28: - Cakey: - - imageadd: Fleet service and dress uniforms have been re-sprited to take on a navy - blue theme. Fleet uniforms have now been split into three categories, with lower - ranks recieving a sailors uniform rather than the non-commissioned officer's - coat. - - bugfix: Fixes service and exploration uniforms sharing the same datums. - Devildabeast: - - rscadd: Adds a forensic belt to the Forensic Technician's locker. - - maptweak: Changes the Forensics door from glass to regular. - Earthcrusher: - - tweak: The jukebox has been resprited. - - rscadd: New tracks added to the jukebox music selection; some have had their names - corrected. - sabiram: - - soundadd: The Emperor of Goats now comes complete with his own battle themes. -2018-03-29: - Bill-Luxe: - - rscadd: Ported railings from the Europa. You can now create it by using a different - material sheets. - Cakey: - - maptweak: Deck 4 has been re-worked. Supply now has a bigger warehouse and the - escape arms have been moved forwards. - - maptweak: Added the very important laundry room on deck 4, with ironing boards - soon to come. All washing machines outside of the laundry room have been purged. - - maptweak: Added green pens to liason and spare offices. -2018-03-30: - PurpleMartinJCK: - - bugfix: Fix medical crate sprites, adding back to storage.dmi - - tweak: Add pouch spawns to small medical random spawn - - tweak: Add trauma kit to medical kit spawn - - bugfix: Fix pouch names in venders - - rscadd: Add new pouch supply crates -2018-04-01: - Chinsky: - - tweak: Liver damage change. Now when it's not working right, it doesn't apply - staright up damage (only for alcohol), it builds up ammonia in the blood up - to toxic levels. Better get those scrubbers going. - - tweak: Kidneys are doing similar thing, but with potassium. - - tweak: Potassium now raises pulse, dangerously so over 10u. - - tweak: Bananas now have bit of potassium in them. - Devildabeast: - - rscadd: Ports Grayson Arms prosthetics from Polaris. - - rscadd: Ports robolimb optics from Paradise. - - tweak: Vox can no longer be selected as a species when building an FBP. - - tweak: Morpheus prosthetics are no longer restricted to IPCs. - - tweak: The Morpheus Alt. head is now the default and the Monitor is a subtype. - afterthought: - - bugfix: PDAs with medical access once again have a handheld medical scanner scanner - program. -2018-04-02: - Chinsky: - - rscadd: Finally swaps old stinky blood in Medbay for NANOBLOOD(TM). Use wisely. - - rscadd: Increased immersion. - - experiment: To further immerse you in your character, you now need to blink manually - if you have organic eyes. There's helpful messages to remind you of that now. - - experiment: To help new players acclimatize to our high RP standards, helpful - hints have been added, shown when you perform ceratin actions to guide to maximum - RP path. - - experiment: As an experiment, different kinds of guns can now be selected in custom - loadouts in Utility section. Everyone can get holsters too now. Spare ammo is - not included. - sabiram: - - balance: Wizards can no longer teleport to non-station Z levels. -2018-04-03: - Dukica: - - rscadd: With the addition of a fancy new, tentacular helmet, the Skrell can now - use the Rescue Module (Medical RIG) suit! - sabiram: - - maptweak: Added The Orb, a mining focused away site. -2018-04-04: - Devildabeast: - - maptweak: Adds a mech recharger to the Security Armory. - afterthought: - - bugfix: Fixes roller bed SSD bug. - chaoko99: - - bugfix: T-rays actually work on ninjas now. - - tweak: Portable atmospherics devices will now work off an APC if available. - mustafakalash: - - tweak: The Torch will once again always spawn on an asteroid. - - tweak: Changes occupation settings from a cycle to a list. -2018-04-06: - Devildabeast: - - tweak: Allows the Roboticist to select medical webbing vest, medical drop pouches, - and the medical poncho in loadout. - PurpleMartinJCK: - - rscadd: Wizards now have a spell that lets them make a long-lasting portal to - away sites. -2018-04-07: - sabiram: - - tweak: Wire brushes are no longer as effective a melee weapon as a pickaxe. -2018-04-08: - Chinsky: - - rscadd: Can now pick EC Directives as shackles for IPC. - chaoko99: - - tweak: Crawling now occurs by clicking a turf. - - tweak: Crawling is now significantly faster. - - bugfix: You can no longer drag other people, forcing them to crawl. -2018-04-09: - Devildabeast: - - maptweak: Adds green pens to the SolGov Representative's and NanoTrasen Liaison's - offices. -2018-04-10: - ParadoxonKomplikon: - - tweak: '"Exotic seeds do not contain certain reagents, such as alcoholic drinks, - anymore."' - - tweak: '"Exotic seeds'' production time is now generally shorter than before."' -2018-04-11: - CakeQ: - - maptweak: Replaces the conference room on deck one with a briefing room. - - maptweak: Added a table/shutter combo intbetween the captain's mess and briefing - room for the chef's use. - FTangSteve: - - rscadd: Makes breathing far more relevant - - rscadd: CO2 buildup is now potentially dangerous and must be scrubbed - - rscadd: Tank sizes have been adjusted and will need to be refilled more often -2018-04-12: - chaoko99: - - soundadd: 'C4, timers, and nukes will now make an ominous beeping noise. spriteadd: - Porta-nuke resprited, uses the porta nuke sprite from TG.' -2018-04-13: - FearTheBlackout: - - maptweak: Moves exosuit tracking beacon crate to Robotics Maintenance - chaoko99: - - bugfix: Crawling works while lying down again. - - bugfix: Crawling no longer functions in space. -2018-04-14: - Cajoes: - - rscadd: Added a lube variant called oil, comes in jugs of 100 units, dispensable - from robotics vendor. - - rscadd: Added beer and ale cans to the alcohol vendor. - - rscadd: Added lava lamps and office toys to the misc. supply menu. - - rscadd: Added fish meat and a big bag of salt to the kitchen. - - tweak: Changed contents of some drinks. - Cakey: - - imageadd: Adds new floor tile sprites. - - imageadd: Adds new floor decals. - - rscadd: Adds several new floor tile types to litter the station with. - Chinsky: - - rscadd: Can now use grab on EC plaques to display Directives to people. Forcefully. - PurpleMartinJCK: - - rscadd: Adds species based darkvision - - tweak: Tweaks light falloff calculations - sabiram: - - tweak: Species with better than average night vision are now more vulnerable to - flashes. -2018-04-15: - Chinsky: - - rscadd: Can use pill bottle on self aiming at mouth to quick-pop a random pill - from it. Yum. - HetNeSS: - - bugfix: Expedition storage area layout fixed. All lights should be connected properly - now. - - maptweak: Sorted out the expedition storage inventory. Piping, maint door location - adjusted. - Sbotkin: - - maptweak: Removed excess stuff (extra tools, consoles) from the forensic technician's - laboratory. - - rscdel: Removed excess tools from the forensic technician's locker. - sabiram: - - tweak: The automatic transfer vote called at 3 hours has been changed. The 'Continue - the Round' option will now extend the round by 30 minutes instead of 1 hour. - - tweak: The default type of robot in character select is now 'robot', a positronic - unit, as opposed to 'cyborg', which has a human brain. - - tweak: Robots with a computer chip based brain are now referred to as 'drones'. -2018-04-16: - Cakey: - - maptweak: The mess hall has been re-shuffled to allow for the cook to have more - of a presence. - Sbotkin: - - maptweak: The Chief of Security's Office is remapped. - - maptweak: The Board Disciplinary Room no longer has attributes of a high secure - area. -2018-04-17: - Banditoz: - - maptweak: More newscasters have been mapped throughout the Torch. - Sbotkin: - - maptweak: The Brig Officer's office is remapped. - Zuhayr: - - tweak: Xenomorph brute resistance, movement speed and and armour have all been - significantly adjusted. Be on the lookout for xenos being nerf OP and report - issues to the tracker. - afterthought: - - tweak: 'Skills are now selected on a per-job basis under Occupations. Warning: - current skill data will be lost!' -2018-04-18: - Banditoz: - - tweak: Non-living players may no longer cast votes of any kind during crew transfer - votes. - Cajoes/BloodyMan: - - rscadd: Ports TG Cigarette Paper code - - tweak: added four more cigarettes to cigarette packs - - tweak: gave a use for existing filter and cigarette paper icons - - rscadd: added icons for, lollipops, gum, nicotine gum, rolled cigarettes, filter-boxes, - gum-boxes, cookie-packs and spitwads - - rscadd: added icons made by Woah Hold There Buddy, (tobacco packs, chewing tobacco - packs,) - - rscadd: added chewable category, reskinned cigs you equip, chewing tobacco, lollipops - and gum added - - rscadd: added recipes for using the rolling papers to make cigs using dried plant - matter or pre-packed tobacco - - rscadd: added onmob animation for chewing gum (but not for nicotine gum) - HetNeSS: - - tweak: Added a capability for surgeon borgs to pick up an IV packs with their - organ gripper module. -2018-04-19: - chaoko99: - - rscadd: Fire extinguisher may now accept fluids from all forms of reagent containers - (HCL dispensers, capsaicin dispensers, coolant tanks, fuel tanks etc.) and spray - them at EXTREMELY low levels of efficiency (100 units a spray, wasteful for - most things.) Firefighter extinguishers may also accept in the same way. BEWARE. - - tweak: Water may now cool down to 20c when sprayed (Includes grenades, for example.), - with a diminishing return below 60c. - - rscadd: Like the above, coolant may be used to cool areas, best saved for phoron - fires or traitoring, because it's extremely efficient and may dip an area to - just a little over 0 kelvin if you're not careful. - - tweak: Extinguishers will fire multiple puffs of reagents instead of three sprays - at the exact same time. More or less consequence of a performance change. - comma: - - tweak: Replaces most eguns with secure variants. Swipe ID to register. - - tweak: Secure guns get all modes unlocked if it's Red Alert - - tweak: CO's revolver was moved out of locker into a display case -2018-04-20: - Sbotkin: - - maptweak: The Forensic Technician's office is remapped again, a lab added. - - maptweak: It's now possible to access the morgue as the fortech. - TheWelp: - - rscadd: Adds Spellbound Servants. Powerful minions of wizards, each with their - own gimmick and theme. - - rscadd: Implements two mutations, nobreathe and spaceres, in conjunction with - the spellbound. - chaoko99: - - rscadd: hydroponics trays, covers, and plump helmets have been re-sprited. - - tweak: Plump helmets are now repeatedly harvest-able, but require a high amount - of nutriment to sustain. You only harvest the 'helmet' of the plump helmet, - as well. - - tweak: Hydro trays will default to 5 lumen lighting for their covers -2018-04-21: - HetNeSS: - - maptweak: Morgue has been split up to two sections - "Morgue" and "Autopsy". Autopsy - - area created. - - imageadd: Autopsy - area icon added - - rscadd: Two sliding doors added to separate the morgue from the autopsy zone. - Morgue or Medical access level required on each one. Autopsy atmospherics controller - added. Morgue - lightswitch, APC added. -2018-04-22: - Banditoz: - - rscadd: You can now export ore scanner disks inside of crates on the supply shuttle - for some extra supply points. - BlueNexus: - - rscadd: Plasteel combat shields have been added to the emergency armoury, replacing - the unused biosuit closet. - Chinsky: - - rscadd: Adds color picker mode to floor painter (which is renamed to paintgun). - - rscadd: Can now hit APCs with heavy big things to unlock them. Doing so risks - breaking them completely. - - rscadd: Being in pain, not seeing properly, or being confused will now affects - accuracy of your attacks. - HetNeSS: - - maptweak: A survellance camera had been installed - D3 mess hall - galley. - sabiram: - - tweak: Stun electrode projectiles fired from stun revolvers now move faster. -2018-04-23: - Chinsky: - - rscadd: Supply crates now have secure variants of guns. - - rscadd: Unsecure guns can be ordered with contraband crates. - Sbotkin: - - tweak: Bridge Officers' got helmets and correct tablet computers. - sabiram: - - bugfix: Fixes red alert being available in the command and communications program. - - bugfix: Red alert once again may only be set through the keycard authentication - devices (small white and black panels on walls) found in officers' offices and - on the bridge. - - rscadd: Red alert now only be cancelled using the keycard authentication devices. - - tweak: Admins are now provided jump links in the 'has forced open an emergency - shutter' message. -2018-04-24: - Chinsky: - - tweak: Skill costs and free skillpoints amounts were severely tweaked, check your - allocations since they're most likely invalid now. - - tweak: Tweaks to some medicines' OD effects. - - tweak: Paracetamol and cold medicine now do not apply organ damage, but still - prevent natural healing when you OD. - - tweak: Inaprovaline, being brain soothy chem, makes you slower and sometimes slur - and get drowsy when you OD (60u folks). - - tweak: Bicaridine, on top of usual toxic effects, now has a chance to heal arterial - bleedings! But at the same time it blocks blood flow, lowering blood circulation - by 20+% (depends on how much did you go past the OD threshold). - HetNeSS: - - tweak: Magnetic grippers are now capable of grabbing deuterium and tritium ingots - as well. - comma: - - rscadd: PDAs are now modular computers. -2018-04-25: - BloodyMan: - - rscadd: Blending tofu now yields an egg substitute for vegan baked goods. - afterthought2: - - bugfix: Skill system saving ACTUALLY works correctly again. - - bugfix: Skill system saving works correctly again. -2018-04-26: - BlueNexus: - - bugfix: Uplink-bought railguns no longer explode - Chinsky: - - tweak: Lung popping condition changed. Now it only happens when pressure changes - (both internal and external), not constantly when you're in vacuum. Pressurized - suits prevent popping by reducing external pressure difference impact. -2018-04-27: - afterthought2: - - bugfix: Crisis borg splints now work. -2018-04-29: - Chinsky: - - tweak: Moved explorers gearup room to where that gross quarantine thing was. Previous - location is now an unused room - - tweak: Moved bunch of crap from explorer lockers onto the racks and tables. - - tweak: Explorer access now opens the room where anomaly containers/stasis cages - are, the one with the drill. - - tweak: Gave bunch of random crap to explorers in the gear room - glowsticks, cameras. -2018-04-30: - Banditoz: - - rscadd: Cyborgs get a secure energy gun (replaced taser rifle) which can be granted - lethal mode by a console, or red alert. Silicons cannot set it for eachother, - or themselves. -2018-05-03: - afterthought2: - - bugfix: Irreparable organs can no longer be healed by any means. -2018-05-04: - HetNeSS: - - tweak: Bandolier's can now also hold pills, pill bottles, papers, pens, photo's - and marshalling wands. - sabiram: - - rscadd: Added a pathfinder hardsuit module to exploration suit room. - - maptweak: Fixed several issues in the exploration storage rooms. - - rscadd: Added illumination grenades, which generate a bright, wide light when - detonated. Added illumination grenade crate to supply under miscellaneous category. - Added hardsuit illumination grenade module. -2018-05-05: - afterthought2: - - rscadd: Scanner modules added for modular computers. Available (job-depending) - on spawn, and also from supply crates. - - rscadd: 'The scanners are: paper, medical, atmos, and reagent. You can have at - most one at any time. Compatible with all computers, but only the paper and - atmos scanners will do anything when in a console.' - - rscadd: Scanner program added for modular computers, which interfaces with scanners. - Can view and save scan results, which may be edited with NanoWord. - - tweak: If a scanner and a nanoprinter is installed, the printer can now only be - refilled with blank paper. - - bugfix: The tax program should no longer produce duplicate copies or unexpected - behavior. -2018-05-06: - TheGreyWolf: - - bugfix: The MAA alt title is now fixed to not exist. - afterthought2: - - rscadd: 'The crisis borg module comes with a stasis bag rack, which can hold 3 - body bags or stasis bags. Starts empty to avoid exploits: go find your own.' - - tweak: Borgs now fold up roller beds by clicking and dragging, like everyone else. - - tweak: Borg interactions with ironing boards while having the roller rack equipped - are similar to humans (they still can't iron, though). -2018-05-07: - Chinsky: - - rscadd: Can now use multitool on secure guns to disable tracker. Prevents gun - from firing, but won't report its coordinates to the force auth program. - - rscadd: Makes emagged secure guns not show up too. -2018-05-08: - afterthought2: - - bugfix: Borgs and AI are given emails after name selection. Emails are updated - on name change. - - bugfix: Borgs and AI can read emails from the "Email Client" in the Subsystems - verb. The email administration program can still be accessed by AI but has been - moved to "Email Administration." -2018-05-09: - afterthought2: - - tweak: CE and CMO get job-appropriate scanners on their PDAs now. - - tweak: Modular computer scanners can now be printed via protolathe. - - tweak: Hitting a modular computer with a paper bundle puts it in the printer. - To scan, separate the bundle. - - bugfix: The chemist's pda scanner is fixed. -2018-05-10: - chaoko99: - - soundadd: Cleanbots now make cute little beeps when active and functioning. -2018-05-15: - Banditoz: - - rscadd: Added a new gamemode, fathless; a mix between cult and deity (also known - by some as godcult.) - Cakey: - - maptweak: Moved alll checkpoints to be positioned in more key areas. B-deck and - deck one checkpoints are now connected via ladder. All checkpoints now have - the ability to cut-off certain sections of the hallways for flow control. - - maptweak: Brig officer now has a disposals bin. - - maptweak: Emergency armory has been altered to have 3 carbines and 3 e-guns as - opposed to the 2:3 loadout to match the rest of the E-ARM. - - maptweak: Brig armory has been altered to have 4 e-guns as opposed to 3 to match - the rest of the armory. - Casper3667: - - rscadd: Vox now spawn with their air filter gas mask. - Dukica: - - rscadd: 'Enabled ponchos, aprons and hazard vests for GAS to wear. rstweak: Some - typos were cleaned up.' - Miraviel: - - bugfix: You can now use sign language even if you are muzzled. - afterthought2: - - tweak: Very damaged heads will be marked as "critical" rather than "irreparable" - on scanners, and can be healed even past max_damage threshold. - - rscadd: Adds a deck management program, which gives some information on shuttle - movements. - - rscadd: Adds flight plans, which can be filed via this program by those with shuttle - flight access. - - rscadd: If the flight plan includes a roster, the members on the roster can be - summoned via automatic comms announcements or batch-emailed. - - rscadd: Adds other reports that supply can file about shuttle missions after the - mission has departed/returned. - - rscadd: Adds a stripped-down report viewer program, currently mostly useful for - viewing emailed reports. - chaoko99: - - rscdel: Reverted a change that made it impossible to draw/fill plant reagents. - You may now make your tomato grenades again. - tlc2013: - - bugfix: Fixed certain Spellbound Servant equipment not having the proper icons, - or - at worst - having no icons at all. -2018-05-16: - Banditoz: - - maptweak: Remaps the Petrov toxins lab to be more intuitive to use. - - tweak: Powered crossbows have been buffed. You don't need to draw back as much, - and it takes less time to do so. -2018-05-17: - afterthought2: - - tweak: The deck management program will now allow you to queue up scheduled missions, - rearrange their order, and delete them. Once started (i.e. once the shuttle - departs) the active mission is finalized and can no longer be deleted or moved - around, but can still be renamed. - - tweak: Deck management announcements are now a bit less spammy and let you choose - an area other than the shuttle to meet. - - tweak: One more report has been added, a post-mission summary. - - bugfix: Crew record access issues fixed. - chaoko99: - - tweak: Emergency shield generators now cover an entire screen. Power draw per - shield unaffected. -2018-05-18: - Cakey: - - maptweak: Adds railings to all stairwells. - Chinsky: - - tweak: PDAs and ID cards no longer have whole name and job in their item name. - - tweak: When examining people, you will see a linkie to see their ID. That will - give you name/job if you're nearby, or show you the window with full info if - you're adjacent. - sabiram: - - rscadd: Blast doors and shutters can now be damaged by hitting them with sufficiently - powerful items. - tlc2013: - - rscadd: Added a recolorable kimono to the loadout selection. -2018-05-19: - PurpleMartinJCK: - - rscadd: add new nabber organs - - rscadd: flesh printer can now print nabber organs - - rscadd: low blood can force nabbers out of nab mode - - tweak: crushing and shredding now decloak nabbers - - tweak: lower some nabber brute resistance in favour of natural armour - - tweak: encases all external nabber organs in carapace - afterthought2: - - tweak: Those with heads access now have more access to Deck Management. - - bugfix: Access issues with supplementary Deck Management reports should be resolved. -2018-05-20: - afterthought2: - - tweak: Headsets start with a free encryption key slot now. -2018-05-21: - afterthought2: - - tweak: Cryo tubes use up chemicals ten times faster. Effective healing rate remains - unchanged. - - tweak: Genetic damage is healed ten times faster in cryo tubes. - - bugfix: The organ printer now prints visible organs. -2018-05-22: - Banditoz: - - rscadd: Borgs can now lock and unlock their own panel. - Cajoes: - - rscadd: Snix, HotFoods and Lavatory vending machines and hid them on the map. - - tweak: All snack food relative paths are now absolute paths. Nobody noticed nor - cared. - Cakey: - - maptweak: Consoles have been rotated to match how they should be. - chaoko99: - - rscadd: Added a light-toning system, lights will color dynamically to what color - they emit. - - rscadd: Fingerprints will no longer magically phase through gloves. - - tweak: Robolimbs don't make fingerprints anymore. - - bugfix: Thick gloves actually use thickmaterial. -2018-05-23: - Banditoz: - - bugfix: Destroyed portable turrets are now climbable. - TheWelp: - - rscadd: Adds a new deity menu free of uplink structure. - - tweak: Some deity store items now increase in price the more you buy them. (E.G. - Conjuration) - - rscdel: Remove Godvision. - afterthought2: - - bugfix: Fake crew announcements should use ID card data now. - - bugfix: Antag preferences being reset to low should be fixed. If you continue - experiencing this issue, please submit a new bug report. -2018-05-24: - Alex6511: - - bugfix: Fixed "3" being printed when placed on a surgery table. - chaoko99: - - bugfix: Lights aren't super dark anymore. Blame Chaoko99 for being blind and not - noticing the difference during testing. - - bugfix: Fixes weird sprite bugs for broken and burnt lights. -2018-05-25: - PoZe: - - rscadd: Added oxygen candles as an item. They are one-time emergency item that - is used to fill 2-3 tiles of depressurized environment - afirpo: - - maptweak: Added an access button to icly cycle between Exterior and Interior fusion - core chamber. - afterthought2: - - bugfix: Crew records will now correctly display things like ' and " in-game. -2018-05-26: - HetNeSS: - - maptweak: The fore docking port on deck four had been widened in size, as the - main docking port be probably should. - - maptweak: Remodelled the Mercenaries gamemode transport shuttle, to suit the extended - docking bay, as well as for more beefy and physics-justifiable look. - - bugfix: '"Northeast of First Deck" and "Northwest of Fourth Deck" waypoints swapped - places (aka fixed)' -2018-05-27: - Casper3667: - - rscadd: Tajara can now use normal gloves and claw attacks can't be used when wearing - gloves. -2018-05-28: - Cajoes: - - tweak: New fax machine icon. -2018-05-30: - Alex6511: - - tweak: Amputation text is now larger for the surgeon performing the amputation - Banditoz: - - bugfix: The rapid taser cooling module (now called the rapid weapon cooling module) - upgrade now works. -2018-05-31: - afterthought2: - - rscadd: the report editor can now print reports and export them to text files. - - rscadd: the report editor can download new (blank) reports from NTnet. A few of - the forms from the wiki can now be chosen in this way. -2018-06-01: - Banditoz: - - rscdel: Hand teleporters have been removed from teleporter rooms. - - maptweak: Teleporter beacons have been removed from some high security areas onboard - the Torch. - - maptweak: A teleporter beacon has been added to NanoTrasen's miscellaneous research's - test chamber. - sabiram: - - tweak: Off-duty ID cards are now visually distinct and can no longer be modified. -2018-06-02: - afterthought and chinsky: - - rscadd: 'The "Medicine" skill now influences interaction with some medical objects: - syringes, defibrillators, sleepers, handheld scanners, full body scanners, IV - drips, and splints.' - - tweak: Full body scanners now store scan data. Use the menu options to print, - erase, or scan/re-scan. - - tweak: IV drips now take a short time to hook up. -2018-06-06: - afterthought2: - - tweak: Off-Duty is no longer a separate job, but an alt-title of Passenger. You - no longer spawn with ranks in uniform if selecting off-duty. - chaoko99: - - tweak: Books and papers may now be 2x as long. This was changed to make it so - records could be longer, without the skeleton taking up half the usable text. -2018-06-07: - Cajoes: - - rscadd: Added new visors for Tajaran to shield their eyes with. Available exclusively - in the xeno portion of the loadout screen. - - rscadd: Added Hot Food showcase to manage kitchen's output. - - rscdel: Removed Lavatory Essentials Vendor on Deck 2 due to [redacted]. -2018-06-08: - TheGreyWolf: - - bugfix: Press tags can now actually be taken by the press. - Zuhayr: - - rscadd: Added methyl bromide, a fumigant gas that kills spiders. - - rscadd: Added bromide, a toxic reagent, from which can be derived a liquid form - of methyl bromide. Methyl bromide kills spiderlings and egg sacs when injected. - - rscadd: Added algae to hydroponics. Algae produce liquid bromide and gaseous methyl - bromide. - - rscadd: Added an interaction to optables that will automatically put someone lying - on top of it to sleep with no need for N2O or painkillers. - - rscdel: Removed N2O pumps as being both redundant and buggy. - afterthought2: - - rscadd: The slowdown for pulling (i.e. ctl-click) stuff is now affected by the - "Athletics" skill. - - tweak: Bigger/stronger species pull things faster. - - rscadd: Pulling stuff generates adrenaline, depending on "Athletics" skill. This - may raise your heart rate. Pulling for a long time without breaks with low skill - may give you the jitter effect and minor heart damage (won't kill you). -2018-06-09: - Banditoz: - - tweak: The T-Ray scanner is now faster, has an increased range of 7x7, and is - now without the flicker effect. - sabiram: - - tweak: Gyroscooters now shield their pilot from 5% of projectiles, down from 40%. - - tweak: Gyroscooters are now slightly slower. - - tweak: Attempting to move a bike or gyroscooter while stunned will now eject you. -2018-06-10: - Banditoz: - - maptweak: The Aquila has been divided into areas, and remapped a bit. - - rscdel: The Aquila's death trap has been removed. -2018-06-11: - BlueNexus: - - tweak: Increased TC costs for railguns - Chinsky: - - tweak: Now for ghetto EVA the size of thrown thing matters. Tiny things give you - ~10% chance of direction change, with 'normal' sized things having 90%, guartanteed - above. - afterthought2: - - rscadd: Throwing "huge" items (e.g. roller beds, backpacks, certain guns, rigs, - jetpacks) or normal sized mobs without "Basic" skill in "Athletics" will briefly - weaken you (and the items won't go far). - - rscadd: Thrown items don't go as far and have less speed/force if you have lower - "Athletics" skill. - - rscadd: The weightlifting machine at the gym has more weight levels. Having high - "Athletics" means you can lift more. If you try lifting way more than you are - capable of, you may hurt yourself. - sabiram and Cakey: - - rscadd: The bird temple on the mining map has been redesigned and now houses the - fountain of youth. -2018-06-12: - Broseph Stylin: - - rscadd: Added rucksacks to Character Setup. They function exactly the same as - backpacks. - afterthought2: - - rscadd: Lactate is a reagent that increases heart rate, causes generally harmless - shortness of breath, and slows movement. After processing a large amount of - lactate, mobs may experience temporary jitters. - - tweak: Instead of producing adrenaline, pulling produces lactate. - - rscadd: Robots can now interact with storage items like boxes and bags. - chaoko99: - - bugfix: Trays will now adequately notify you of not being able to be placed in - bags. -2018-06-13: - Cakey: - - imageadd: New wall sprites have been added. - - imageadd: New door sprites have been added. - - imageadd: New window sprites have been added. - - imageadd: New grille sprites have been added. - - rscadd: Airlocks are now paintable. - - rscadd: Window frames have been added, which connect to walls for that aesthetic - look. - - rscadd: Airlocks can now be painted using the airlock painter. - - rscadd: Added paint presets to the paintgun. - - maptweak: The Torch has been modified to use window frames instead of just windows. - - maptweak: Maintenance has been given more catwalks. - - maptweak: Added binoculars to security checkpoints. - ZeroBits: - - tweak: Material Grinders have been reworked to allow different reagent quantities - and multiple reagents when grinding material sheets - Zuhayr: - - tweak: Gas inhalation effects are now reagent-based. Gases create reagents inside - the body, which then apply effects. This means that gaseous phoron exposure, - for example, needs to be treated with dialysis/dylovene, as it fills your guts - up with liquid phoron. - - tweak: The poison_type var on species datums is now poison_types, and determines - which poison gasses show you the toxins UI indicator, rather than which ones - cause poisoning. The actual effects of poisonous gasses is determined by the - reagent value (as per dexalin being injected into a vox, etc.). This really - shouldn't impact anything for the average player, except that chlorine and nitrogen - dioxide (not N2O, for clarity) are now actually poisonous. - - tweak: Helium now makes your voice squeaky. Very important feature. - - tweak: Xenon is now functionally the same as N2O, including the following note. - - tweak: N2O now causes giggling, confusion, dizziness and occasional passing out - at high dosages, rather than instant and immediate knockout. Still useful for - riot control and now flooding it into distro isn't a round-ender. You might - even be able to use it without admins shouting at you! Refer to the optable - neural suppressor PR for a replacement method to sedate people for surgery. - - tweak: Finally, as a sidenote, Bogani will actually be poisoned by oxygen and - chlorine will have a visible overlay now. - afterthought2: - - rscadd: Experienced in Chemistry allows you to see scannable reagents in a held - beaker/container. - - rscadd: Professional in Chemistry allows you to see all reagents in a held container. - - tweak: Science goggles give more precise volume readings at higher chem skill. -2018-06-14: - ElRobusto: - - tweak: Cuts the Vox space suit movement penalty by half. - TheWelp: - - rscadd: Adds two currently admin-only races, the Starborn and the Blueforged. - Will be available in future deity form. - - tweak: Tweaks Shadow species death to not cause runtimes. -2018-06-15: - Banditoz: - - tweak: The cyborg manual now has all the current cyborg modules. - - tweak: The Supermatter guide shouldn't lead engineers to delaminate the engine, - now. - ParadoxSpace: - - rscadd: Adds two new IPC/FBP chassii, Morpheus Mantis and Ward-Takahashi Economy. - - tweak: Grayson, W-T Economy, and Xion are now available at the roboticist fabricator. - afterthought2: - - rscadd: The chem grinder is dangerous to use at "Unskilled" in Chemistry and will - lose some ingredients depending on skill level. - - rscadd: The chem dispenser will give inaccurate amounts of ingredients or add - extra contaminating ingredients when below skill "Trained" (in Chemistry or - Cooking, depending on dispenser) Can be slightly dangerous. - - rscadd: The chem master now has two modes. "Quick" will move the correct amount - of ingredients from beaker to buffer, but also add contaminants (depending on - skill). "Thorough" will only move the desired ingredient, but incur losses (depending - on skill). Skill checked is Chemistry for chem master, Cooking for Condimaster. - - rscadd: Moving ingredients from buffer to waste or beaker acts like on "Quick" - mode. -2018-06-17: - ParadoxSpace: - - rscadd: Adds bowman type headsets to all non-service departments. - - rscadd: Adds unique pilot, miner, corpsman, and explorer headsets. - - rscadd: Adds tacticool Syndicate headsets to mercs. - - rscadd: If tcomms is down or unavailable for whatever reason and you have a shortwave - radio in your pocket, your headset will now automatically transmit through it. - It still cannot do department channels. -2018-06-18: - Chinsky: - - tweak: Some loadout items are now restricted by branch instead of jobs. Some are - restricted by both. You might experience sudden loss of swag on next spawn, - check your setup. - TheWelp: - - rscadd: Adds various starlight specific spells for use in future deity form. - - tweak: Adds two new flags for targeted spells to filter via faction. - - tweak: Adds more effects for some spells. - afterthought2: - - rscadd: adds the instruct verb. A character with basic leadership and experienced - skill X can instruct a character in X from Untrained to Basic. Has a 15 minute - cooldown to use; buff lasts all round; max of three buffs on any person. The - target has to be close and there's a short timer during which neither party - should move. - chaoko99: - - rscadd: Adds a fully reusable backstabbing mechanic, used by butterfly knives - and switchblades. -2018-06-19: - Kurgis: - - tweak: Changed the brain loss Impedrezine inflicts to allow it to kill a person. - Miraviel: - - rscdel: 'Removed the time restriction on the following jobs: Explorer, Corpsman, - Deck Technician, and Scientist.' - - maptweak: Reorganized the kitchen cabinet and the crates in the Medical Storage - (the big bag of salt and the defibrillator are no longer blocking everything - else). - - maptweak: Removed the anaesthetics closet from the Medical Storage. - comma: - - tweak: XO now gets a box of spare headset keys instead of box of XO headsets - - rscadd: Bowman headsets can hold 3 keys instead of 2 - - rscadd: BO Bowman headsets hold 4 keys -2018-06-20: - BlueNexus: - - balance: Railguns have been rebalanced to fill the niche of an anti-armour or - sniper type role. - - balance: All railguns now suffer a substantial penalty when fired one-handed. - - balance: The basic railgun projectile no longer stuns, and does less damage. - - balance: All railguns which accept steel rods as ammunition now use the basic - projectile. - - balance: The TCC railgun's (available in the traitor menu) ammo capacity has been - reduced from 10 to 6. - - balance: Substantially increased firing delay on all semi-automatic coilguns and - railguns. - - balance: Holding or stowing a railgun now slows you down more. - Chinsky: - - rscadd: EVA skill now has mechanical effects. - - rscadd: Space slipping chance is affected by EVA skill. Bit higher at unskilled, - lesser with skill, no slipping at experienced. - - rscadd: Flooring when entering gravity from space is now not guaranteed at Basic - skill or more. Doesn't happen at Professional skill. - - rscadd: At Unskilled and Basic skill, jetpack can sometimes go wrong way. Not - that bad if you notice in time and have fuel to turn back. - - rscadd: At Professional skill you go faster when in space with a jetpack. Zooom. - - tweak: Skills now affect surgery. Trained or Experienced (depending on what you're - trying to do) skill is needed to ensure step won't fail. Professional skill - will offset various penalties (not proper optable, improvised tools etc) a bit. - Time of step is affected by Anatomy skill too. - - tweak: Some other skills help with some steps, e.g. Trained Forensics offsets - penalty for incisions, and Complex Devices skill is used instead for robotic - organ steps, with Electrician and Construction helping with simple limb repair - steps. - Chisnky: - - experiment: Melee weapons now have different attack cooldowns, generally with - smaller weapons being faster, bigger slower. Normal sized weapons are baseline, - having same attack cooldown as they did. - - experiment: Material weapons further tweak their attack cooldown based on material - used. - afterthought2: - - rscdel: The leadership skill has been removed. Check your characters' skill allocations. - - tweak: The instruct verb works like before, but no longer requires leadership - skill to use. - chaoko99: - - bugfix: You may no longer spam the skeleton as hard as you could before. - - bugfix: Wall painters no longer hit walls when used. - - bugfix: Energy axes will no longer anchor when dropped. - - bugfix: Candles will now last about 30 minutes. - - bugfix: Bucklers can now block any projectiles that aren't bullets, as suggested - intent in their code. - - rscdel: You may no longer worry about reagent contamination in a soft drink dispenser, - only unintended reagent amounts. - - rscadd: You may light an unlit candle with a lit candle that isn't in your hand. - - rscadd: Optimization pass on Geiger counters, and a few effect systems (Smoke - and sparks) - - rscadd: Underwear may now go into washing machines. Still can't be bloodied, but - at least you can do that now. For you weird people who roleplay showering! - - tweak: Rags may now clean more than just blood. More importantly, they show their - progress bar when cleaning. -2018-06-21: - Chinsky: - - rscadd: Close Combat now has ingame effects. Mostly chances to hit in melee. - - rscadd: Disarm chances now both affected by skills and anything tha affects melee - accuracy (being blind, being confused, blurry eyes, being in pain etc). - - rscadd: Most fancy grab moves (jointlocks, dislocations, tendons cutting) were - locked away behind Trained skill in CQC. - afterthought, sabiram: - - maptweak: The hydroponics station away site has been converted into an exoplanet - site. -2018-06-22: - Banditoz: - - tweak: Borgs have had their overall health doubled. - - tweak: Borgs also have had their armour plating component health doubled. - - tweak: Borgs are now more resistant to EMP, and lose less cell charge per EMP. - Cakey: - - maptweak: The Torch has been modified to use a wider variety of flooring types - and decals. - - maptweak: Added a door button to the XO's office. - - rscadd: Added plated catwalks, which can be constructed by placing monotiles on - catwalks. - Chinsky: - - rscadd: Botany skill now has ingame effects. - - rscadd: Without at least basic skill, you can screw up when planting or weeding - trays. You'll also be unable to recognize pests and weeds from useful things. - - rscadd: Exotic seeds (all random variations) need trained skill to avoid screw - ups like that. - - rscadd: Trained skill is also needed to handle xenobotany machines, otherwise - you'll be prone to wasting your samples really fast. - - rscadd: Experienced and professional levels of skill reduce degradation of samples - in xenobotany machines. - - experiment: Constantly fixing brain is no longer the pro strat anymore. - - rscadd: When fixing very damaged (broken level or more) organs in surgery, their - max health is lowered. - - rscadd: Brains get their health lowered /always/ if oxygenation is below survival - level (30%). Better fix cause of damage first, if you don't want to do permanent - damage. - - rscadd: Forensic skils now have ingame effects. Without at least basic skill, - you leave slightly more fingerprints on things, and you will leave prints when - trying to evidence bag things. - - rscdel: You need Trained skill to use evidence collection things and forensic - machines. At higher skill you work microscope faster. - - rscadd: Offstation antags (and traider) can now become ALIUMS! - - rscadd: Their bases have 'alien monolith' somewhere, which turns you into a humanoid - alien of unknown species. - - rscadd: Remember to implant the spawned translator implanter if you're planning - on talking to people. - afterthought2: - - rscadd: Having Basic finance gives the Appraise verb, which allows you to estimate - the value of items you are holding or have equipped (found in the IC tab). Higher - skill levels give more accurate assessments. - - tweak: The financial skill has a large effect on your starting cash. - - tweak: Higher financial skill gives you better deals from traders. - - rscadd: Using virology machines without sufficient virology skill may get you - or your friends infected. For curing purposes, "Trained" negates this effect, - but for doing splicing and mutations, "Experienced" or "Professional" may be - needed. - - rscadd: The printout from the virus analyzer may have missing or erroneous information - if you lack "Experienced" in virology. Quality of information improves with - skill. -2018-06-23: - afterthought2: - - bugfix: The microscope should now work properly again. - - bugfix: The magic missile wizard spell now works. It inflicts small burn damage - and a substantial disable. - - rscadd: Additional reports have been added to the Report Editor. -2018-06-24: - Chinsky: - - tweak: Handheld radios now have batteries and use power to transmit. You'll have - ~50 transmissions worth of power from one cell. When charge is getting low, - message might become garbled. Radios can be recharged in standard rechargers. - Heptagon49: - - bugfix: Screwdrivers no longer open airlocks upon attack. - Rowtree: - - tweak: Character creation faction/citizenship/religion/home system choices have - been updated. -2018-06-25: - Heptagon49: - - rscadd: You can now alt-click on pipes and disposal pipes to rotate them. - - bugfix: Unathi now have exploration voidsuits, and can now use the exploration - suit cycler. - Spookerton: - - tweak: Zombie abilities now tell you when they can't be used, why, and how long - is left on their cooldown, instead of failing silently. - - bugfix: Zombies can no longer consume or death_breath while incapacitated. - - balance: Zombies can only death_breath once per minute instead of once per second(!). - - tweak: Zombie consume now completes at the same rate as its cooldown, preventing - multiple consume actions being active at once. - - bugfix: Zombie consume no longer allows the user to be the target. - - balance: Zombification doesn't magically replace robot parts - - balance: Zombification organ health bonus is x3 instead of x5, but organ break - threshold is 75% instead of 50% - - balance: Zombie toxin urn reduced from 120u(!) to 10u. - - tweak: Zombie toxin now guarantees conversion for a 5u or greater dose. - - balance: Zombie toxin has a flat per process 20% chance to convert so long as - the current + historic amount of reagent in the victim (ie, the total dose at - one time) is more than 1u. - - balance: Zombie death_breath now only creates 2u instead of 5u. This means a victim - should usually take about 15 tox and have two 20% chances to be zombified if - a single zombie breathes on them. Zombies can work together to push a victim - over the 5u mark and instantly zombify them. - - balance: Zombies cannot re-zombify themselves for a free rejuv. - - tweak: observers cannot circumvent voting checks - afterthought2: - - tweak: Robotics surgery uses the Complex Devices skill now to compute delay. Hardsuit - removal uses the EVA skill. - - bugfix: Constantly escaping from grabs regardless of skill should be fixed. - sabiram: - - tweak: The standard bulkhead paint colour is now in the presets for the paint - gun. - - maptweak: Added a few small ruin sites to make exoplanets a little more detailed. - zaredman: - - rscadd: Added Advanced Trauma Kit and Advanced Burn Kit crates that can be ordered - from Cargo. 6 ATK or ABK for 30 points. - - rscadd: Adjusted cost of Medical Crate to 70 supply points to be more appropriate - when compared to other crates like Stability kit crates. -2018-06-26: - Cakey: - - maptweak: Following several reports of Torch crew being admitted to the infirmary - due to headaches the Torch has been refurbished once again to iron out any kinks - left over from the flooring construction work. - - imageadd: New floor sprites have been added. - - imageadd: New wall-mounted sprites have been added for fire alarms, air alarms, - APCs and intercomms - Chinsky: - - rscadd: Adds volcanic exoplanets. Very few plants and animals, but loads of minerals. - Don't walk in lava tho, use catwalks, Luke. - chaoko99: - - rscadd: Resprited some beekeeping items for the sake of consistency and ease of - use. -2018-06-27: - Chinsky: - - rscadd: Weapons skill now has mechanical effects, hide yo children hide yo wife. - - rscadd: Gist of it is if you don't have at least basic training, you're a hazard - to people. You can point and fire, but safety can be a bitch. - - rscadd: Speakig of safety, help intent doesn't prevent firing now. Safety is now - an explicit toggle, can switch it with Ctrl-Click on the gun or with a rightclick - verb. - - rscadd: Higher values of skill give some buffs to accuracy, and unlikely events - of jamming, also let you perform better when in pain. - - rscadd: Professional skill also has bonuses when using scoped rifles. - - rscadd: Weapons skil cost was changed too. Trained and higher are more expensive - now, with Experienced and Professional being as costly as medical skill. MAAs - start at Trained now to give them headstart. - Spookerton: - - tweak: adds insulated gloves to engineer lockers - afterthought2: - - tweak: Starting cash has been increased. Higher financial skill still gives substantially - more money. -2018-06-28: - Banditoz: - - rscadd: Saferooms can now be bolted and unbolted via the keycard authentication - device. - - rscadd: If there is an impending delamination, supermatter delamination, or escalation - to red alert, saferooms will unbolt. - - maptweak: The button to toggle the saferoom bolts have been moved inside of the - saferoom, and can now be operated by all. - Cakey: - - imageadd: Windows have been resprited. - - imageadd: Wall signs have been modified to fit the new walls. - CrimsonShrike: - - tweak: Moves crawling onto regular movement, fixes crawling while hurt. - Heptagon49: - - bugfix: After hearing about the capture of key operatives, Clan [NAME NOT FOUND] - decided to up the ante and improve the explosive power of their ninja suit's - deadman's switch to ensure that their agents either complete their mission or - die trying. Have fun. - sabiram: - - tweak: Catwalks now act as floors do with regards to clicking to move pulled objects - onto them. -2018-06-29: - Cakey: - - tweak: Replaced the fake lava on volcanic exoplanets with actual, real lava. - afterthought2: - - tweak: MMIs cannot be inserted into non-synthetic mobs. - - tweak: Flesh limbs cannot be attached to synthetic mobs. - - tweak: Robotic limb attachment now uses the devices skill. -2018-06-30: - Earthcrusher: - - tweak: Weaker mobs such as Artificers can now smash doors and windows, albeit - not as quickly as stronger mobs. -2018-07-01: - Chinsky: - - rscadd: Added anti-rad pouches to engineering. Also replaced detox injector engies - get in survival box with anti-rad one. - - rscdel: Removes mapped boomboxes from engineering. Nice try, but you'll have to - do with random spawnpoints as everyone. - - rscadd: Adds deployable SCG flags to Pathfinder lockers. They require Pathfinder - access to pop up. Don't do anything, just fluff. - Heptagon59: - - imageadd: Due to reported ill fits and high amounts of chaffing, SolGov has reissued - their line of uniforms, now with form-fitting features! EC Uniforms now have - unathi specific icons. - Hubblenaut: - - bugfix: The teleporters will no longer send people to nullspace when the beacon - does no longer exist. - sabiram: - - balance: Blink, teleport and ethereal jaunt can no longer be cast while incapacitated. - - tweak: Holographic items created by the holodeck can no longer be deconstructed. - - rscadd: Added the lodge exoplanet ruin site. - - tweak: Increased the cost of the hydrobase exoplanet ruin site. - - bugfix: Fixed incorrect accesses on various air alarms. -2018-07-13: - Alex6511: - - balance: The CoS Locker no longer contains a taser - - balance: The Brig Officer Locker no longer contains a small energy gun. - - tweak: The CoS locker now has a hand labeler in line with the Brig Officer. - Cakey: - - tweak: The Pathfinder job is now Ensign only - - rscadd: 'Belts have been overhauled to have holster slots on certain belts. These - holsters function the exact same way as uniform holsters do. imgadd: Certain - belts now show what their contents are on their icons.' - - rscadd: Added general and general holster belts, used by command, bridge officers, - and supply. Holds general office supplies, tablets, and stamps as well as other - various supply equipment. - - maptweak: Uniform holsters have been removed in favor of belt holsters, however - they can still be found within the loadout menu. - - tweak: Uniform holsters have been modified to use the same slot as webbings to - counter being able to carry two holstered weapons. - - rscadd: Plated catwalks can now be serviced using a crowbar to access anything - underneath. - Chinsky: - - rscadd: Piloting skill now has ingame effects. - - rscadd: Taking Torch's helm without at least Trained skill can make Torch go not - exactly where you want it to go. At Professional, passing meteor fields is less - painful. - - rscadd: Shuttles require different level of skill. Guppy is no-skill, Charon and - Aquila need at least Basic. For purposes of skill, pilot is whoever tells it - to move in console. - - rscadd: If pilot's skill is insufficient, you can end up in wrong place. Also - travel time is affected by skill. - - tweak: Drastically lowers amount of loot-having junk piles on garbge planets. - They have visual cues though so you don't need to try and rummage though literally - every pile. - - tweak: Xenoarch finds no longer yield sheets of steel and claim it's a mysterious - thing. They now mostly drop alium alloy, that has random material properties - each round. Any material weapons you find will be made of it too. - - rscadd: Garbage planets now have radiation sources scattered around. - CrimsonShrike: - - tweak: Roboticist now has access to their own maintenance airlock again. - Heptagon49: - - bugfix: Due to pending discrimination lawsuits, Nanotrasen has upgraded the cryosleepers - onboard the SEV Torch with automatic wheelchair dispensers. Disabled characters - now spawn with wheelchairs. - Miraviel: - - rscadd: Added the "Detach IV Drip" verb under the Object tab. - - tweak: Left-clicking an attached drip will now first detach the patient and only - then it will remove the beaker. Drag and drop still works! - - tweak: The Hot Foods Display machine now accepts and dispenses utensils. - - imageadd: IV drips now have a slightly bigger container sprite and a wider warning - light, for better visibility. - - imageadd: Advanced first-aid kits are now purple in hands too, as opposed to being - red. - Orelbon: - - rscadd: The self-destruct will now begin detonating explosions randomly on the - ship when it reaches its cutoff point. - Sbotkin: - - tweak: Emergency Response Team officially is a part of the SCG Fleet now. - Spookerton: - - bugfix: Paper bundles bundle correctly. - - tweak: Carbon copy paper is now default named "sheet of paper" instead of "paper", - the same as regular paper. - TheWelp: - - rscadd: Adds the ability for holy water to deconvert god cultists and the ability - for the null rod to stop phenomenas (by hitting an altar) - - tweak: Nerfs like 90% of deity items and phenomena costs. This may be heavy handed - or too much. Feel free to complain. - Zuhayr: - - tweak: The Pull Punches verb has been renamed to Switch Stance. - - tweak: Nabber stance switching behavior now replaces pulling punches for them. - - tweak: Nabber nabbing is now achieved by trying to grab someone rather than a - verb. - afterthought2: - - tweak: Almost all maint airlocks now require maint access. - - tweak: Trainee crewman alt-titles have been replaced by separate jobs. - chaoko99: - - rscadd: A ping button for checking your ping has been added to the "file" tab. - sabiram: - - bugfix: Fixes being unable to ignore OOC. - - balance: Machinery may no longer be controlled by the staff of animation; its - maximum charges have been reduced from 10 to 5, and its recharge time increased. - - balance: Wizard familiar transform spell recharge time increased to two minutes - from ten seconds. - - balance: Wizard familiars can no longer transform while incapacitated. - - balance: A percentage of damage taken in a familiar animal form is now mirrored - to the familiar's human form. - - bugfix: Simple animals controlled by a client can once again damage humans. Don't - kick that suspicious goat. - - rscadd: Added functionality for edged weapons to cut wires after a short delay. - Any conductive objects will also shock you! - - tweak: At the same time, clicking wires with ordinary conductive objects will - no longer shock you. - - tweak: Reconfigured access requirements for tactical equipment in the loadout. - - tweak: Sol personnel may no longer select green or tan plate carriers, UBACs or - pouches. - - tweak: Expeditionary Corps personnel additionally may no longer select navy blue - equipment. - - tweak: The King of Goats group encounter has been updated. - - rscadd: The King of Goats can now imbue his attacks with elemental damage for - a short time. - - rscadd: The King of Goats can now rarely knock over its enemies with its attack. - - tweak: The King of Goats will now only yield the golden fleece to those who slay - it in its final form. - zaredman: - - rscadd: Added spare penlights and a linen bin to the lower medical storage. - - rscadd: Expanded medical locker room to fit a washing machine and table with recharger. - - rscadd: Some adjustments to maint immediately by Medical's locker room. -2018-07-14: - Cakey: - - tweak: Dionae may no longer fill in as research director among Nanotrasen staff, - as the board of directors felt they weren't evil enough to push the Nanotrasen - agenda. - - maptweak: Added the volleyball court and cafe to the holodeck. - ChaosAlpha: - - tweak: Engineering robots can now collect cables regardless of the currently selected - color of their synthesizer - - tweak: Robots can now pull-drag (by clicking on an adjacent turf while pulling - something) - Spookerton: - - bugfix: Visible & audible messages should no longer stack an extra prefix for - every connected ghost -2018-07-15: - PsiOmegaDelta: - - rscadd: It is now possible to adjust the playspeed of boomboxes using a screwdriver. - sabiram: - - maptweak: Added some lights to dark spots in hallways around research, chemistry - and the D3 ladders, the main hallway through D2 maint from the stairs/elevator, - and the medbay. - - maptweak: 'The greedy NT guards are now only provided with one chair for their - window desk. imgadd: Changed the intercom icon to be more in line with what - it used to be. Dark frame, green console.' -2018-07-16: - Heptagon49: - - bugfix: Dionaea can now regrow limbs again. - sabiram: - - tweak: Changed the changelog header and credits. -2018-07-17: - Cakey: - - rscadd: The shuttle pilot role has been moved to Exploration. - - rscadd: The prospector role has been moved to Supply. - - rscadd: Two new pilot helmets have been added to the game, one generic and one - NT variation (Sprited by Chinsky). - CrimsonShrike: - - tweak: Implant surgery is now possible for robotic limbs. -2018-07-18: - Earthcrusher: - - rscadd: With a bit of research into Data and Illegal technologies, the Roboticist - can now print an uncertified robot module. What could it possibly do? - TheWelp: - - rscadd: Spells now require you to not be incapacitated (handcuffed, stunned, etc). - afterthought2: - - rscadd: Antag skills are now chosen in-game. Off-station antags get basic in everything - and can select 4 skills at trained, 2 at expert, and 1 at master. On-station - antags get their selection from jobs, and in addition get 3 at trained and 1 - at expert. (malf is unchanged). Once the skill selection is submitted, it can't - be undone without admin intervention. - - tweak: The Show Own Skills verb looks a little different now. Antags can use it - to select skills. - za_redman: - - rscadd: Fixed incorrect req_access for E-Arm lockdown shutter. - - rscdel: Removed biohazard locker in D1/Medical Locker room. The multi-suit locker - in the basement, the two in maint, and the one in viro remain. - - rscadd: Added additional Medical Contractor locker in D1/Medical Locker room. - - rscadd: Adjustments to Contractor Locker contents to bring them more in line with - Corpsman Lockers. -2018-07-19: - CrimsonShrike: - - tweak: Swabbing people wearing gloves should now attempt to swab said gloves instead - of swabbing their evidence-free hands - - tweak: Forensics locker will once again contain a security belt for those who - feel the need of carrying their gear. - - tweak: Restrained, unconscious or otherwise restricted suspects can no longer - keep avoiding swabbing - Ithalan: - - bugfix: PDA medical scanner now works on body bags and stasis bags like the regular - health analyzer, and uses user medicine skill level - - rscadd: Medical belts can now also hold body bags, stasis bag and emergency medical - pouches - Spookerton: - - tweak: SCGR no longer has an unfitting alt title that implies they do something - they don't. - - tweak: SCGR can no longer download and use power RCON. - Zuhayr: - - rscadd: Diona nymph and diona gestalt eyes glow in the dark. - - rscadd: Diona nymphs can no longer grow into adults by themselves. Instead, they - need to merge with two other nymphs, then call a vote with Call Gestalt Vote. - - rscadd: Diona nymphs are now capable of headbutting seeds out of seed vendors, - planting them, harvesting them, removing dead plants, eating pests and refilling - water. Chirp. - - rscadd: Diona nymphs now have a proper UI. - sabiram: - - rscadd: Plastic flaps can now be constructed with plastic sheets. - - rscadd: Plastic flaps can now be unsecured with a wrench, and then destroyed with - a screwdriver. Use a wrench to re-bolt them. - za_redman: - - rscadd: Gives Chef of Security access to the Hangar. - - rscadd: Adds exit button to hangar door. -2018-07-20: - Heptagon49: - - rscadd: A short blurb on the current alert level now appears on the title screen. - sabiram: - - rscadd: Added spy v. spy (autotraitors and renegades) to game mode selection and - secret. - - tweak: Law enforcement (security officer, warden, HoS) and the Captain may no - longer be renegades at round start. - - tweak: Reduced the force of the magnum pistol's melee attack from 14 to 9. -2018-07-21: - sabiram: - - tweak: Command rig suit helmet cameras are now found on the Command network. - - tweak: Mining rig suit helmet cameras are now found on the Supply network. - zaredman: - - rscadd: Introduces Office of Civil Investigation and Enforcement agents to replace - Colonial Marshals. - - rscdel: Removes all references to Colonial Marshals and replaces it with the Office - of Civil Investigation and Enforcement. -2018-07-22: - Devildabeast: - - rscadd: Adds optics for the Hephaestus Alt. head. - Unknown: - - rscadd: ' Removes three of the four monkey cube boxes in virology and replaces - them with a stok cube box, neaera, and farwa cube box.' - sabiram: - - maptweak: Those with shuttle helm access may no longer access the supply office. -2018-07-23: - Ithalan: - - bugfix: Map function in crew monitor program no longer craps out after drawing - first tracked crew member - - bugfix: Suit sensor jammer methods have been updated to be useful for new medical - system - - bugfix: Synthetic hearts and species without a cardiovascular system no longer - generate misleading pulse readings on the crew monitor - - rscadd: crew monitor program icons now change to indicate if there is a crew member - in medical distress, based on pulse and blood oxygenation - - tweak: layout of crew monitor program has been tidied up a bit so that each datatype - aligns nicely. -2018-07-24: - Cakey: - - tweak: EC and Fleet crew may now fill in as shuttle pilots. - - maptweak: Added a pilots locker within the expedition prep room. Pilots now have - access to both supply and the expedition prep room. - - tweak: Added a pilot-specific access type. - CrimsonShrike: - - rscadd: Forensics skill now allows for the detection of possible evidence on examination. - - tweak: Forensics skill is now cheaper at higher levels. - zaredman: - - rscdel: Removes mention of Colonial Marshals in holowarrants and replaces it with - OCIE; format change. -2018-07-25: - Chinsky: - - tweak: Telecomms relays power usage is upper /considerably/ when used off-ship. - Expect to drain Charon in 10 minutes when you switch it on. - - tweak: Having Trained or above Close Combat skill gives bonus to parry chance - with weapons (even ones that don't parry normally). - - tweak: Melee accuracy is now affected by size of the weapon - smaller than 'normal - sized' weapons are more accurate, bigger are less accurate. Some weapons have - individual bonuses/penalties (e.g. swords are bit more accurate for their size, - toolboxes are less) - - tweak: Material weapons now get damaged on parry much like when attacking, and - can shatter depending on material. - afterthought2: - - tweak: Check your skill loadout; it may have been reset! - - tweak: Skills outside your job and not in the general, organizational, or service - categories (minus pilot) are no longer selectable above "Trained" level. - - tweak: Some head roles had skill point allocations reduced. Engineers' skill points - have been brought in line with contractors (increased). Brig Officers' starting - skills brought in line with MaA. -2018-07-27: - Cakey: - - tweak: Senior Engineers, Deck Officers and Brig Officers may no longer be E5s. - afterthought2: - - rscadd: Constructing things with stacks of material now uses the construction - skill. Higher skill is needed to use more advanced materials or to make more - elaborate items. - - tweak: Construction time is modified by construction skill. - sick trigger: - - rscadd: Diona can now 'Jump-to-next-nymph' to cycle between their nymphs after - splitting. -2018-07-28: - Devildabeast: - - tweak: Shuttle Pilots can now be rank E-6 as Fleet. - - tweak: Shuttle Pilots now have EVA access. - - maptweak: The Shuttle Pilot can now access the Ready Room. - - tweak: Shuttle Pilots can now select the pilot pin in the loadout. They can also - now select the EC cap if they're EC. - - bugfix: The EC Shuttle Pilot no longer spawns with service uniform. - - tweak: The Shuttle Pilot now gets a regular pilot headset and a bowman headset - in their locker. - - tweak: Shuttle Pilot is now defined as a SolGov role. -2018-07-29: - CrimsonShrike: - - tweak: APC lights now brighter. - Spookerton: - - tweak: maintenance drone laws tweaked to read more goodly. - - tweak: mdrone laws tweaked to not imply that mdrones are intelligent, because - they're not. - - tweak: mdrone laws include not interfering with people while trying to do your - job, roomba. -2018-07-30: - Devildabeast: - - bugfix: The SEV Torch's Heads have had ventilation introduced to the stalls in - order to prevent unwanted suffocation. -2018-08-01: - Devildabeast: - - tweak: Corpsman now has the alt-title of "Nursing Assistant" instead of "Nurse". - afterthought2: - - bugfix: APC, fire alarm, and air alarm frames should once again show up as buildable. - - tweak: Faction, citizenship, and home system character creation choices have been - updated. - zaredman: - - rscadd: Added a MIA (Missing in Action) option to crewmember status choices. -2018-08-02: - Cakey: - - maptweak: The brig has been moved to deck one. Deck three has been adjusted to - be further enforce it being the habitation deck. - - maptweak: Added the Commissary, an on-ship store run by supply and service crew. - - maptweak: Moved the pathfinder's office to deck four. - - maptweak: Moved the bluespace drive to deck two. - - maptweak: Moved the observation bubble, diplomatic quarters and vacant office - to deck three. - Devildabeast: - - rscadd: Adds a PCRC suit, a more formal variation of the PCRC uniform, to the - loadout under Corporate Uniforms. - Hubblenaut: - - tweak: Brig cell timers will notify Security over Sec HUDs when expiring. - zaredman: - - rscdel: Replaces double doors to Xenobio, Viro, D2 Maint, D3 Old Brig, Conference - Room, Engineering hard storage, and NT Labs with normal doors. -2018-08-03: - Hubblenaut: - - tweak: All Heads are now able to authorize warrants using the holowarrant projector - regardless of their Security access. -2018-08-04: - sabiram: - - tweak: The mercenary shuttle is now less easily vented by destroying a single - r-window. - - bugfix: Hardsuit rig modules now check properly access for those attempting to - use them. -2018-08-05: - Hubblenaut: - - bugfix: Bridge Officers can once again access their lockers. - - bugfix: SCGR can once again access the bridge. - zaredman: - - rscadd: Allows IPC and Skrell to be Brig Officer. -2018-08-06: - Cakey: - - maptweak: Bearcat has been tweaked slightly to allow for better repair opportunities. -2018-08-07: - Devildabeast: - - maptweak: Removes a catwalk from the Utility Down in the deck 1 substation room. - - maptweak: Adds scrubbers to the toilet stalls on deck 3 to prevent CO2 buildup. - - rscadd: Adds a new branch known as "SolGov Employee"; the SolGov Representative - and OCIE Agent have been moved under it as ranks. - - tweak: SolGov loadout items, including SolGov berets, awards, and hat, can now - be worn by all SolGov-affiliated branches.. - - tweak: Updates the sprites for the Hephaestus Alt. head optics. - Zuhayr: - - rscadd: Added sushi and sashimi. Slice fish or meat into strips, then use them - on rice. Also accepts egg and tofu. - nearlyNon: - - maptweak: Moves notice board between main mess hall doors, removing the window. - RIP. - - maptweak: Adds a holopad to the holodeck, so the AI can hang out there. - - maptweak: Expands holodeck door to be two tiles wide, to prevent bottlenecking. - - maptweak: Adds a newscaster to the vacant office. -2018-08-08: - Devildabeast: - - bugfix: Allows FT to be contractor again for real this time. - - bugfix: Allows FT to be played as Contractor again. - - bugfix: SCGR can now wear most loadout items again. - Nearlynon: - - bugfix: Fixed missing pipes + wires in holodeck. - - maptweak: Adds 2 paperbins to deck 3 in the mess and lounge respectively. - nearlyNon: - - rscadd: Eight balls, able to be bought from the vending machine in the mess. Ported - from TG. "Will the CMO be useful today?" "Not likely." - - rscadd: Add bells; can be made with any material. Ring by clicking with intents - other than grab; grab picks up. Shatters if you hit someone with it! - - maptweak: Distribute bells throughout desks. - sabiram: - - tweak: The Booze-O-Mat menu has been reordered; vessels at the top, followed by - bottles, followed by ready drinks, followed by mixers, and ending with glass - accessories. - - tweak: Added a bottle of mint oil to the Booze-O-Mat for mixing. -2018-08-09: - Flatty: - - rscadd: You can now change icon scaling method in the "Icon" menu on top left! - Zuhayr: - - rscadd: Skrell now appear neutrally gendered to non-Skrell. Use the headtail length - descriptor to specify your secret squid gender. - - rscadd: Vox now have neck markings to show importance to other vox. -2018-08-10: - TheWelp: - - rscadd: Adds the Lost Souls, the remnants of souls sucked into the Starlight Gateway - (for future deity mode). - - rscadd: Added the ability for god cultists (and lost souls) to be able to hear - through the pylons like the deity can. - nearlyNon: - - bugfix: ALL MATERIAL WEAPONS ARE NO LONGER INSANELY FRAGILE. -2018-08-11: - Devildabeast: - - rscadd: Adds Observatory and Field Operations patches to the loadout. - nearlyNon: - - maptweak: Replace the crowbars in medical storage with prybars, which makes more - sense and was requested in the Little Things thread. - - tweak: Added multipens to loadout. - - bugfix: Saves diona from their impending death in holodecks & when preparing to - go to the ship as off-vessel antags. - - bugfix: Fixed grammar on diona nodes. "You plant the diona notes" no more. - sabiram: - - rscadd: Boomboxes now have adjustable volume. - - tweak: Boomboxes can no longer be placed in backpacks. - - tweak: Boomboxes now have a chance to break each time they're turned on. -2018-08-12: - Cajoes: - - rscadd: Added flood lamps (portable) to supply offerings. -2018-08-13: - Hubblenaut: - - bugfix: The diffuser bypass mode on the shield generator will now work on already - active diffusers. - - bugfix: Fixes the shield generator's atmosphere containment mode. - PsiOmegaDelta: - - rscadd: Admins can now alt-click possessed mobs to efficiently kill them. - afterthought2: - - rscadd: The SM monitor readings will fluctuate with some errors at Trained in - Engines skill and below (max 40%, 20%, and 5% at Untrained, Basic, and Trained). - At master they'll be like previously. - - rscadd: Turning on the emitter will recompute its efficiency (i.e. power) to a - lower random value, depending on skill. - - rscadd: Examining the SM at Expert skill will give some information about its - integrity. At Master, it will give a guesstimate for the EER. -2018-08-14: - sabiram: - - rscadd: The shaker now really acts like a shaker, and must be interacted with - to mix its contents (click it in hand). - - maptweak: The bar, mess hall, captain's mess, and cold storage rooms have been - redesigned. - - tweak: Iced tea is no longer sweet. - - tweak: Added sweet tea. 3 measures of iced tea + 1 measure of sugar. -2018-08-15: - Sbotkin: - - tweak: Allows shredding of fingerprint cards. - Zuhayr: - - rscadd: Numerous new ores spawn on the asteroid. They can be compressed into bricks - and ground up for reagents. - - tweak: The ore processor has been rewritten and will happily eat anything containing - metal or other substances, and can then fart them out as sheets. - - rscadd: All material sheets now fetch a price from the supply drone, not just - plat and phoron. - - tweak: As a result, the prices of all materials have gone up to a minimum of their - resale cost. Steel is 60 credits now, for example. - - tweak: The recipe of plasteel is now steel + platinum (put the steel back through - the unloader) and the recipe for osmium-carbide plasteel is plasteel + osmium. - afterthought2: - - rscadd: Hacking without the electrical skill is harder now. - - rscadd: If you are unskilled in electrical, hacking will randomize the wire positions - (not meanings) each time you open the screen. If you are basic, you'll get some - possible duplicate colors/omitted colors, with smaller probabilities. - - rscadd: If you pulse a wire below trained skill, you have (progressively smaller) - chances of pulsing the wrong wire. If you are untrained, you may randomize wire - positions for everyone else trying to hack the thing. - - rscadd: If you cut/mend wires below trained skill, you may cut/mend some extra - wires by accident. - - rscadd: If you try to place a remote signaler with low skill (trained or lower), - you might place it on the wrong wire, and then have a hard time removing it. - - rscadd: A new "Examine" option has been added to the hacking menu. Below experienced - it doesn't do much. On experienced one or two wires will be identifiable on - examine, while at master most will be. Less effective for "secure" objects with - randomized wiring. -2018-08-16: - IsdatAfamas: - - rscadd: Added an away site. It has a few slots open to join as a survivor. - - rscadd: See https://forums.baystation12.net/threads/ctis-research-ship-missing.6790/ - for lore info. -2018-08-17: - Cajoes: - - tweak: flood lamps now start in the off position - - tweak: green ink pens are now greener - - tweak: washing machines now more in line with graphic style of server - - tweak: toys and plants now use less unused animation frames, reducing overhead -2018-08-18: - IsdatAfamas: - - maptweak: Added polarized windows to robotics. - - bugfix: CTI ship should spawn correctly now. - Zuhayr: - - rscadd: Added Tritonians, an uwhitelisted human subspecies. -2018-08-19: - Devildabeast: - - tweak: All Marine Corps uniforms and items have been renamed to reflect the SCG - Army, removing all references of the Marines. - - rscadd: Adds an array of Army outfits, spawnable by admins. - - tweak: The Marine (now Army) PT uniform is now black instead of green. -2018-08-20: - IsdatAfamas: - - bugfix: Various fixes implemented for SRV Verne. Overall should be far less deadly - as an away mission. - nearlyNon: - - tweak: You can now select a bible from the loadout. - sick trigger: - - rscadd: Ghosts can now 'Scan-target' to analyse the thing they're following. -2018-08-22: - Cajoes: - - rscadd: Napalm and Napalm B recipes. Sticky burny goo. - - tweak: relabeled old napalm recipe to phlogiston. Makes heat. And little else. - Same as old napalm. - Cakey: - - rscdel: Removed Tajarans from the server. - Hubblenaut: - - bugfix: Fixes cable coils spawning in tool belts having old vibrant color. - - tweak: Tool belt cable colors are now completely random. - IsdatAfamas: - - bugfix: Some more CTI ship fixes. - Sbotkin: - - tweak: Allows shredding of fingerprint cards. - TheWelp: - - rscadd: 'Imports TG''s circuit updates: ICs now requires power to operate. IC - printer is now hand-held and can copy & print assemblies fully.' - - rscadd: Adds new ICs. - Zuhayr: - - rscadd: Numerous new ores spawn on the asteroid. They can be compressed into bricks - and ground up for reagents. - - tweak: The ore processor has been rewritten and will happily eat anything containing - metal or other substances, and can then fart them out as sheets. - - rscadd: All material sheets now fetch a price from the supply drone, not just - plat and phoron. - - tweak: As a result, the prices of all materials have gone up to a minimum of their - resale cost. Steel is 60 credits now, for example. - - tweak: The recipe of plasteel is now steel + platinum (put the steel back through - the unloader) and the recipe for osmium-carbide plasteel is plasteel + osmium. - afterthought2: - - rscadd: Hacking without the electrical skill is harder now. - - rscadd: If you are unskilled in electrical, hacking will randomize the wire positions - (not meanings) each time you open the screen. If you are basic, you'll get some - possible duplicate colors/omitted colors, with smaller probabilities. - - rscadd: If you pulse a wire below trained skill, you have (progressively smaller) - chances of pulsing the wrong wire. If you are untrained, you may randomize wire - positions for everyone else trying to hack the thing. - - rscadd: If you cut/mend wires below trained skill, you may cut/mend some extra - wires by accident. - - rscadd: If you try to place a remote signaler with low skill (trained or lower), - you might place it on the wrong wire, and then have a hard time removing it. - - rscadd: A new "Examine" option has been added to the hacking menu. Below experienced - it doesn't do much. On experienced one or two wires will be identifiable on - examine, while at master most will be. Less effective for "secure" objects with - randomized wiring. - nearlyNon: - - rscadd: Inducers. Make them in science. They're a TGstation item, you can charge - anything that uses a battery with them. Almost. Screwdriver to remove and replace - its battery. - - rscadd: Cyborg integrated version of the above, using the borg's internal battery, - and a failsafe on it. - - rscadd: IPCs and FBPs are now adversely affected by ion storms. They will be confused - and have blurry vision as their system partially resets to remove ionospheric - corruption. To avoid this, hide out in a saferoom or shuttle, or the dorms or - such. - - rscadd: Prescription science goggles can now be selected from loadout. -2018-08-23: - CrimsonShrike: - - bugfix: Oxygen regenerators should no longer get stuck trying to get or output - gas. -2018-08-24: - Chinsky: - - tweak: CO2 is no longer poisonous. Just non-breathable. Should make Bearcat a - walk in the park. - - tweak: Added CO, which /is/ poisonous. - - tweak: PACMANs that run on plasma now produce some CO, around a mole per 40 seconds, - so make sure you open the window (or turn on scrubbers) before using. - SierraKomodo: - - tweak: Makes NT Security Guard HUD icons purple instead of red. -2018-08-25: - Cajoes: - - rscadd: added supply crate for wrapping paper - - tweak: toned down the toner and floodlamp crates - Textor: - - rscadd: Sleepers, cryo tubes, full body scanners, full body scanner control consoles, - and operating tables can now be constructed. - - rscadd: The aforementioned machine boards are now researchable and printable at - the protolathe. - - rscadd: Added the ability to drag-and-drop players to cryo pods. - Zuhayr: - - rscadd: The General character generation tab has been split between Background - and Physical. - - rscadd: The faction/species/homeworld backend has been completely rewritten. - - tweak: Check your species, faction and homeworld settings as well as the new 'culture' - option under Background. -2018-08-26: - Heptagon49: - - rscadd: You can now rotate unwrenched computer frames via context menu or alt-click. - - imageadd: Added directional icons for computer frames. - nearlyNonexistent: - - rscadd: Two new IPC monitor screens, one an obvious parody of the original Doom, - the other Tetris. -2018-08-28: - Cakey: - - rscadd: Added the Secure Energy Revolver to the CO and XO's closets, replacing - their respective energy guns. - CrimsonShrike: - - rscadd: Oxygen regenerator board added to circuit printer. - nearlyNonexistent: - - tweak: Chameleon kits no longer shapeshift back to normal (and psychadelic) when - EMPed. -2018-08-29: - SierraKomodo: - - rscdel: Removed Floorlength Braid hairstyle - nearlyNonexistent: - - tweak: Press drone can now take photos. - - tweak: Cameras stay off after taking a photo. - - tweak: Photo albums can be taken from the loadout, along with a roll of photo - tape. -2018-08-30: - Chinsky: - - tweak: Sensor console now grants much further viewrange on the map. - Textor: - - rscadd: You can now build light switches and window tint switches with a steel - sheet. - - rscadd: 'To build: use a screwdriver on the frame. You can also use a screwdriver - to disassemble them.' - - bugfix: Fixed issue with converting new-style reinforced windows to electrochromatic - windows. You can use a cable coil on them to convert them properly now. - - tweak: Modified how window tint switches interact with multitools. You can now - set the window ID with the multitool. You can also set the window ID by using - a multitool on the electrochromatic window. -2018-08-31: - Miraviel: - - rscadd: Added 10 more targeted emotes! Use them as *salute fullname. - Textor: - - bugfix: GAS have now been adequately trained by Xynergy on the proper use of stairs. - They will no longer hover above them, afraid to go down. - - bugfix: GAS no longer have their tracheae rupture in low pressure environments. -2018-09-01: - Banditoz: - - tweak: Light frames can now be placed in the actor's area. - Cakey: - - tweak: APLU circuits can now be printed by default. - MO_oNyMan: - - maptweak: Added missing cameras to forensics office, evidence storage and briefing - room - - maptweak: Added a recharger on d4 security checkpoint - - maptweak: Forensic technician can now access morgue from the front door - Textor: - - bugfix: The supermatter monitor no longer cares about delaminating supermatter - crystals not on board the Torch. Those other crystals must suffer silently, - now. - nearlyNonexistent: - - rscadd: Ports Polaris's synthetic eye color changing. IPC, synthetic human, and - Adherent eyes are now RGB. Properly covered by display monitors too. - sabiram: - - tweak: People wearing most hardsuits are now able to be handcuffed. -2018-09-03: - CrimsonShrike: - - bugfix: Fixes pulling circuit checking for its own position and not its holders - Sbotkin: - - maptweak: Replaces strategic reserve of laptops in the infirmary with consoles - and telescreens, where needed. - afterthought2: - - rscadd: Makes exterior airlock assemblies buildable (need Basic skill). - sabiram: - - tweak: The force authorisation and docking management programs now must be run - on suitably powerful equipment, namely a laptop or a console. - - tweak: Increased tech cost of the teleporter console circuitry. - - maptweak: Moved research and development circuit boards into secure storage. - - maptweak: Added more APC and airlock circuits to tech storage. -2018-09-04: - Chinsky: - - rscadd: 'Added a new event: Maintenance Drones Uprising.' - - rscadd: It spawns hostile versions of maint drones in maintenance. They will not - attack anyone they perceive as synth. - CrimsonShrike: - - tweak: Medical circuits now largely inform of severity instead of exposing internal - values. Adapted medical integrated circuits to brainmend. - nearlyNonexistent: - - maptweak: Security now has prybars instead of crowbars. - - rscadd: You can now flip blindfolds up, and start with one from your loadout. - Tape ones can't be flipped as they're not made of cloth. Blindfolds from loadout - are colorizable. - - rscadd: One new AI hologram. - - tweak: Clippy is no longer malf only. -2018-09-05: - nearlyNonexistent: - - rscadd: 'New items intended for antags to steal; several secret documents that - spawn in the SCGR''s office, the conference room, and the NTL''s office. Gotta - collect them all! (Disclaimer: only 3/6 spawn in a game.)' -2018-09-06: - nearlyNonexistent: - - tweak: Water now lasts a minute on the ground, to make it more useful to have - wet floor signs. For reference, space lube is 10 minutes, and the cult spell - is 6 minutes. -2018-09-07: - Textor44: - - bugfix: Surgeons can no longer create magical floating limbs by attaching hands - and feet to a patient lacking an arm or leg. -2018-09-08: - Textor44: - - rscadd: Adds the savage hunter (male and female) clothing for Unathi civilians - in the loadout under xeno wear. -2018-09-09: - FTangSteve: - - rscadd: simple mobs now take different damage from different unarmed attacks - Textor: - - tweak: Staff now take tickets when they hit the "PM" button in the ticket panel. - - rscadd: Adds the ability for admins to change the end credits slightly. - Textor44: - - bugfix: Catwalks can now be cleaned by mops and soap by simply clicking on them. - Janitors everywhere rejoice at having to do less work. - - tweak: Soap now takes a longer time than a mop to scrub floors. Janitors everywhere - grumble at having to take longer at doing their job. - - tweak: Soap no longer can be used to knock people over by dragging them onto it. - Janitors everywhere are sad they can no longer prank people as easily. -2018-09-10: - CrimsonShrike: - - tweak: Signallers no longer give visible or audible feedback that they received - data. There's circuits for that and frankly we were all thinking of killing - the roboticist. - - rscadd: New filter circuits, so that you can discriminate properly - - bugfix: Fixed hypoinjector circuit not injecting - Zuhayr: - - rscadd: Added the ability to carve graffiti into some walls and floors with sharp - objects like screwdrivers. - - rscadd: Being a slog now has long-term consequences. -2018-09-11: - Cajoes: - - rscadd: Some new cargo items, boxed snack foods for refilling vendors, etc. (canned - bread does not go into Galley-!) - - rscadd: Added new cargo order tabs and orderable items. Galley, Custodial, Exploration, - Non-Essentials, etc. - - tweak: Rearranged existing cargo tab contents to something resembling logic. Floor - tiles go into Flooring food supplies to the galley, costumes and hats into Non-essentials, - etc - - rscdel: 'Removed the Tabs: Reagents, Miscellaneous and Hospitality tabs as they - ended up empty once the re-ordering was complete and no longer served a function.' - - rscdel: Crate of Boxes, Crate of Empty Reagent Cartridges, Ripley APLU Circuitboard - Crate - Chinsky: - - bugfix: Fixes microscope always treating partial prints as complete. End of golden - age of forensics. - - rscadd: New forensic evidence type - trace DNA. Left on unfinished food, glasses - people drank from, cig butts and gum wads. Collected with swab kits, investigated - in DNA scanner. - - rscadd: Grabbing, pulling, and hitting people unarmed now will wrinkle their uniform/suit - and leave fingerprints. Usual protections against prints apply there. - CrimsonShrike: - - bugfix: Demultiplexers should have data set correctly now. - ParadoxSpace: - - rscadd: Tritonians now handle water better. They still cannot breathe it, so be - careful, okay? -2018-09-19: - Chinsky: - - rscadd: Added ANFO, a fertilizer+fuel explosive. Mix any of fertilizers (EZ-nutriment, - Left 4 Zed or Robust Harvest) with welder fuel to make it. Add aluminium for - more oomph if you can get it. - - rscadd: To actually make it boom, you need ANOTHER explosion first. A weak explosion - will pretty reliably activate <60u, strong <120u, devastating for more. If it - wasn't strong enough, it can still trigger part of reagent. - - rscadd: Due to related changes, any container holding welder fuel can now explode - if caught in an explosion, though don't expect much oomph. - - rscadd: Added ability to manipulate tape recorder tapes. - - rscadd: User wirecutter to cut tape, use tape on tape to join them. - - rscadd: You can get loose tape out by clicking tape inhand. Join them to put back. - Master forensics techs will be able to tell if it was tampered with. - - rscadd: Tape recorder now have a single wire that starts playback when pulsed. - - rscadd: Adds vinegar reagent. Can be made from ethanol or apply juice by applying - universal enzyme as catalyst. - - bugfix: Adds mayo. Can be made from egg yolk and vinegar or lemon juice. - - tweak: Adds alternative soy sauce recipe. Now it can be made with 5u Soy Milk - + 5u Vinegar - CrimsonShrike: - - rscadd: 'New instruments are now available through supply. rscdelete: Removed - old piano and old violin,' - Zuhayr: - - rscdel: Removed NanoTrasen rank. You can use the contractor rank to get access - to science roles now. Play whatever company you like. - - tweak: The Torch has unionized under the Torch LLC Corporate Union. You can get - a union card in loadout and the Corporate Liaison is now the Workplace Liaison, - with Corporate Liaison and Union Representative available as alt titles. Worker's - rights! - sabiram: - - rscadd: Added missiles for admins to throw at the ship. -2018-09-22: - Aticus: - - imageadd: Adds a new, female-centric hair style for Unathi. The Frills Strike - Back. - Neon1ight: - - rscadd: Added the Xenolife Technician job. It is a crew research position, allowing - EC players to be part of the research department. ICly, it specializes in xenobiology/xenobotany. - Zuhayr: - - rscadd: Education is now a selection in your background tab. Jobs are restricted - to certain minimum educations. You will likely need to change your background - tabs for all characters who work jobs other than Passenger. - - rscadd: Doctorates and medical degrees in the education system modify your record - and ID name to 'Dr. Foo, MD' or 'Dr. Foo, Phd'. - - tweak: Skrell will no longer present as hive minds on their ID and crew records. - - rscadd: Mops can now mop up shallow fluids. - - tweak: Hydrogen fires should no longer result in biblical floods. - - tweak: Floods should now clean up filth decals properly. -2018-09-24: - Cajoes & ChaosAlpha: - - rscadd: mobs now tip over when slipping or resting - Chinsky: - - rscadd: Can now put items into forensic microscope for scan, instead of using - tools on it first. Clicking on microscope with evidence bag puts item inside - too. - - rscdel: Removed alium-turning monolith from trader base. - CrimsonShrike: - - rscadd: Adds some more feedback to augments. - Miraviel: - - rscadd: Added a normal headset to the pilot locker and bowman headsets to corpsman, - medical contractor, physician lockers. - Zuhayr: - - tweak: Graffiti now requires you to be on help intent. -2018-09-26: - Zuhayr: - - tweak: Noticeboards can be built out of wood, dismantled with a wrench, and rearranged - with a screwdriver. - - rscadd: Papers on noticeboards will persist round to round. - - rscadd: Sticky notes can be ordered from cargo and will also persist round to - round. - - rscadd: Mods can now view a list of all persistent data. Admin can use this list - to destroy it with prejudice. - - rscadd: Relatedly, you can now be jobbanned from Graffiti. - nearlyNonexistent: - - rscadd: Science can now print bluespace syringes and cryostasis syringes. Inject - people with more chems at once (20u each; 60u total) or inject them with water/potassium. -2018-09-27: - CrimsonShrike: - - tweak: Rigs can now be hacked after lifting wire cover with a screwdriver. - - tweak: Rig modules and cells are now removed with wrench. - ParadoxSpace: - - rscadd: Adds the Yeosa'Unathi subspecies, their language, their faction, and their - attack. Also gives Yeosa glowing eyes. - - tweak: Lowers how hungry Unathi are at the expense of slower healing. - - bugfix: Fixes issue with tail attack messages. - - bugfix: After much debate as to whether Yeosa count as Unathi, the Expeditionary - Corps have finally allowed Yeosa to wear Unathi cultural clothing from the loadout. - - rscdel: Unathi can now no longer manually toggle on and off involuntary processes - like self-healing. - Textor: - - maptweak: Bridge Deck - Captain's quarters' light switch is moved so that you - are no longer likely to remove the light tube when turning the lights on. - - maptweak: Deck 1 - Xenoflora and Miscellaneous labs are now brighter. This should - allow for scientists to actually see the things they work on. Robotics now has - solid doors. Privacy windows are no longer thwarted by looking through the door-windows. - Added a window to the mech bay side to compensate for the lack of visibility - from that direction due to the door no longer having a window. Door to storage - next to robotics actually opens for the roboticist now. Removed power cable - to nowhere in deck 1 starboard fore maintenance. Swaps the filing cabinet and - table in the morgue so that the paper bin, folder, and pen are actually accessible - when someone is working in there. - - maptweak: Deck 2 - Adds a shield diffuser at the edge of the old brig border so - trash will stop being stuck behind the shields when ejected into space from - the trash room. The shield should no longer block the airlock in deck 2 starboard - mid maintenance due to wall unevenness. - - maptweak: Deck3 - Adds a second mineral bath to deck 3 cryogenic storage wardrobe. - Moves photocopier and shredder in office so that they can both be used normally. - - maptweak: Deck 4 - The toxins storage room is now directly off the hangar in order - to let scientists actually get to their toxins storage room. Finally adds a - security camera to the fuel bay. The AI can now watch the fascinating process - of refueling. Moves the atmos control computer in the Petrov Laboratory so that - you can actually reach all the counter space when working. - - bugfix: Had a long discussion with the OR computers and we both agreed that they - need to actually face the direction they were mapped in. - Zuhayr: - - rscadd: Added a crashed escape pod that may generate on exoplanets and allow for - latejoiners a la Bearcat. - - tweak: Some ruins and submaps will add themselves to the distress signal list. - Probably worth checking now. - - rscdel: Prevented submap jobs from being test-spawned by the global datum system - as they do not expect null args. - afterthought2: - - rscadd: The IT skill now has gameplay effects when using modular computers. - - rscadd: 'Higher IT skill allows the user to bypass logging on program download - with higher probability (Trained: 30%, Expert: 60%, Master: 90%). Logs will - still be generated, with faked entries for the download info.' - - rscadd: The antag access decryption program is more effective at higher skill - levels. It works faster and has a chance to avoid tripping the alarm. At unskilled - (generally meaning non-antag) it has a chance to give the wrong access. - - rscadd: The antag camera alarm-trip probability is now tied to skill, with similar - effectiveness as current at Trained. - - rscadd: The antag dos program is more effective at higher skill, with more dos - attacks per tick at higher levels (equal to current at Basic). At expert and - master, gives extra fake attacking nodes to the system log to impede sysadmins. - - rscadd: The network monitor, email administration, and AI management programs - are locked below basic, basic, and trained skill, resp. You will instead get - some random data displayed. The programs do link to a terminal now. - - rscadd: Added a command line interface for modular computers. With enough skill - (expert+ for most things) you can run specific commands (type man for a list) - to do rudimentary sysadmin diagnostic tasks. Notably, with network access, you - can ssh into terminals of other computers over the network. If you are unskilled, - you may get various failure effects or just be unable to do anything. - - rscadd: To access the terminal, either use one of the programs or use Ctl Alt - Click. - zaredman: - - tweak: Adds defib and compact defib crates to be ordered through supply. - - tweak: Added holosign projector and advanced mop to the janitor robot. - - tweak: Added medical HUD to the surgical robot. -2018-09-28: - sabiram: - - tweak: Added a delay to welding/unwelding airlocks. - - tweak: Xenolife Technicians no longer have access to the fabrication lab or Petrov - helm. -2018-09-30: - Cakey: - - maptweak: Added Deck 5, an expansion of Deck 4 adding more verticality to the - ship beyond stairs and ladders. Deck 4 has been split up to accomodate these - changes. - - maptweak: The hangar has been moved inwards to be more centralised on Deck 5. - - maptweak: The lounge has been moved under cryogenics and now overlooks the hangar - (Still accessible from cryogenics). - - maptweak: The officer's mess has been moved under the mess hall and now overlooks - the hangar (Still accessible from the mess hall). - - maptweak: The Petrov has been made slightly bigger to be more useful. Moved several - research suites to the Petrov. - - tweak: The Research Director and Corporate Liason can now use the ID program to - modify accesses within their own department. Petrov accesses are now only modifiable - by the Research Director and NTL - - tweak: Fixes the commissarry shutter access requirement. - Miraviel: - - maptweak: Repositioned lights in the SEA's office, the XO's and CO's request consoles, - the fire extinguisher cabinets on the Bridge, the labels at the stairs, and - the CO's light switch. Removed the overlapping Nanomed from the Bridge and the - urinal from the Aquila. -2018-10-02: - Cakey: - - maptweak: 'Made maintenance style-consistent throughout all decks with techmaint - tiles and railings. maptweak: Made railings not obstruct items, shuffled some - items around to not be behind railings.' - - maptweak: Added a single seat in the lounge facing space, which takes up barely - any extra space. - - maptweak: Added a fax machine to the pilot's lounge. - - tweak: Fixed Petrov airlock accesses. - - tweak: Fixed Hangar maintenance airlock accesses. - ParadoxSpace: - - rscadd: After complaints that Unathi would have to be cut open [stack overflow] - amount of times with a scalpel, Unathi can now again toggle their healing. - - tweak: To reflect their biology, Unathi are now actually ectotherms instead of - being particularly cold-sensitive endotherms. - Sbotkin: - - rscdel: Removed peacekeeper armband from loadout. - Textor: - - bugfix: Helm control, engine control, sensor, and navigation consoles no longer - stop functioning after repair or construction. Just hit "reconnect." - - bugfix: The windowtint button on the back wall of the XO's office actually works - now. - sabira: - - tweak: The research department's colouration has changed from the red of NanoTrasen - to the green of Torch, Limited. - - tweak: Torch, LLC (the holding company representing the research department) has - been renamed to Torch, Ltd. - - maptweak: Changed the area around research to use the green decals, and new Torch - Ltd logo. - - maptweak: Changed the research director and liaison's offices on the bridge to - make use of the green decals. - - rscadd: Added legacy NanoTrasen uniforms to the loadout. - sabiram: - - tweak: Adherents of the Vigil can now play as Janitor, Chef, Bartender, Supply - Assistant, Engineering Contractor, Roboticist, Chemist, Research Assistant and - Researcher. - zaredman: - - maptweak: Adds dedicated Robotics OR. - - maptweak: Each OR now has holosigns to show when they are in use. - - maptweak: Moved some items from the joint OR to the robotics OR, added some extra - tools. - - rscadd: Separates Roboticist and Biomechanical Engineer. -2018-10-03: - Chinsky: - - tweak: Various changes to gunshot residue (GSR) forensic thingamabob. - - rscadd: Shooting someone pointblank will now leave GSR on the targeted organ, - and burn them a bit. Just like in those mystery novels! - - rscadd: You now need to aim at hand to take GSR from THAT hand, not from both. - You can take GSR from other bodyparts by aiming at them too. - - rscadd: Gun actually gets GSR too now. - - rscadd: Guns have a chance to leave GSR on the ground when fired. - Miraviel: - - rscadd: Added mechanical description to skill blurbs. - ParadoxSpace: - - rscadd: Adds a menu for you to select from your list of available attacks. Naturally, - this depends on species. - Sbotkin: - - rscdel: Removed ID modification and weapon authorization tools from command computers. - Textor: - - tweak: Lets engineering module and maint drones pick up floor tiles. They can - now put the tiles they levered off the floor back. - sabiram: - - maptweak: The hallway leading from the elevator to engineering in the maintenance - deck has been re-opened. - - maptweak: Moved security guard lockers from Petrov to the main checkpoint. -2018-10-04: - CrimsonShrike: - - bugfix: Rotating should no longer make science floor disassemble. - afterthought2: - - experiment: 'We are conducting some stability testing. You may notice issues with - how objects below you, on other z levels, are rendered: this is expected.' -2018-10-05: - Spookerton: - - bugfix: Automatic shutoff valve circuit toggling now works as intended. - Textor: - - rscadd: Deimos Advanced Information Systems (DAIS) is now officially in the game. - Lunchboxes, mugs, an undershirt polo, contractor uniforms, winter coats, and - a labcoat, are all in-game now. - - rscadd: DAIS is now a faction in the background tab of the character creator. - - rscadd: A new experimental DAIS lawset is available for researchers to install - in an AI. - - maptweak: Adds DAIS lunchbox, coat, and mug to telecomms room. - - bugfix: Corrects science labcoat description to reflect new color scheme. - - bugfix: Replaces lingering references to Torch, LLC with Torch, Ltd. - greggbot: - - rscadd: RFID Card Broadcasters, previously only found in PDAs, can now be printed. - zaredman: - - tweak: Adjusts max skill points and skill caps for Biomech and Roboticist. -2018-10-06: - Sbotkin: - - bugfix: The microphone circuit now translates non-GalCom languages only. - sabiram: - - rscadd: Added new colours of wrench and wire cutters, wherever wrenches and wire - cutters are found. - - rscadd: Adherent players can now select from some pre-set colours in character - creation. -2018-10-07: - Cajoes: - - rscadd: Added cubed spiders - - rscdel: Removes previously added domestic animal cubes - Cajoes & Earthcrusher: - - rscadd: Mass Driver Ammunition, two types. - - rscadd: Icon for the blunt mass driver round by Earthcrusher - afterthought2: - - bugfix: Air sensor thresholds should now work properly. - zaredman: - - tweak: Adds wheelchair and roller bed crates to be ordered through supply. - - tweak: Raises minimum player age for AI to 7 days and Cyborg to 3 days. -2018-10-08: - Atebite: - - bugfix: Fixed less wet floors increasing slip chance. Mopped floors should now - only have a 50% chance of slipping you. - Cajoes: - - rscdel: Removed the mention of crate in the cargo interface order form. Since - it is implied the shipment will be in a crate.. or locker.. or otherwise sealed - in some material. - - rscdel: Removed \improper tags from labels that didn't require them. You will - neither notice nor care. - - rscdel: Removed dispenser cartridge packs from Galley-Cargo due to redundancy. - Refer to Dispenser Refills-Cargo. - Textor: - - rscadd: Adds buttons to allow selecting "high," "low," or "never" on all antag - roles with a single click. - TheWelp: - - rscadd: Adds the starlight deity! Embodiment of fire and flame, watch out for - its super-powerful heralds and minions of light and darkness. - afterthought2: - - tweak: '"Starburst" spell has been heavily nerfed. The fireball spell is no longer - available in starlight deity mode pending balance adjustments.' - zaredman: - - tweak: Adds recipe for Chemistry to synthesize adrenaline. -2018-10-10: - FTangSteve: - - tweak: janihud now bases vision off of what the mob wearing it can see instead - of the tile - - rscadd: nabbers can now use HUDs - greggbot: - - bugfix: IC seed extractor now properly creates the appropriate seed and deletes - the fruit. -2018-10-12: - Atebite: - - tweak: Added a skillcheck for slips based on athletics - Cakey: - - maptweak: Tweaked several areas within maintenance after feedback. Removed majority - of railings. - - maptweak: Fixed shutoff valve layout on decks 4 and 5. - - maptweak: Swapped Petrov air pump with one that starts as on. - - tweak: Railings can now be wrenched open to allow passage, and the time it takes - to climb railing has been reduced from 5 seconds to 1.25 seconds. - - maptweak: Fixes merchant base accesses. - - maptweak: Removes a bunch of tiles from maintenance over piping and wires. - - maptweak: Fixes lack of cameras on D5. - - maptweak: Fixes dark spot on D4 fore hallway. - - maptweak: Adds consoles to pilot's lounge, exploration prep. - - maptweak: Adds suit sensors/camera monitoring console to Charon. - - maptweak: Adds exploration network cameras to explorer helmets. - - maptweak: Gives the shuttle pilot access to explorer camera network, suit sensors - monitoring. - - maptweak: Fixes noticeboard placement around the map, added extra noticeboards - to departments that lacked one. - - tweak: Fixes Petrov camera network, only accessible by LLC employees. - Chinsky: - - tweak: Disarming is now riskier. There's a chance to hurt your hand on the weapon - you're going for instead, with chance adjusted based on skill difference / being - flashed etc / being on help intent. -2018-10-13: - Anticept: - - balance: Increased atmospheric pump efficiency, and atmospheric filter efficiencies. - Pipe wizards rejoice! - - balance: Increased air injector internal tank size as well as power cap. this - increases its flow rate due to how atmospheric devices perform their math. Pipe - wizards rejoice! -2018-10-15: - Textor: - - tweak: Due to the extremely likely outcome of death for the crew upon ejection - of the escape pods, command has moved abandon ship from Command and Communciations - to Keycard Authentication Devices and renamed it to "Initiate Evacuation Procedures." - Abort still occurs at C&C consoles, as does bluespace jump initiation. - - tweak: Moves bolt/unbolt saferooms from Keycard Authentication Devices to C&C - - tweak: Changes Keycard Authentication Device interface to NanoUI -2018-10-16: - Cakey: - - maptweak: Fixes Petrov isolation cell alarm placement. - - maptweak: Added sticky notes to offices around the ship. - - maptweak: Added noticeboard to head of staff offices where missing. - - maptweak: Added missing air alarms to hangar, hangar storage. - - maptweak: Fixes hangar exit button access. - - maptweak: The Aquila is now overmap-capable. - - maptweak: The Guppy has been given some extra cargo space. - Roland410: - - tweak: Changes Tower deity spells to have more charges, and the fountain of power - only takes 30 seconds to recharge it. - Textor: - - tweak: O2 Tanks are once again removable without having to take your entire hardsuit - off. Hardsuit users will no longer risk suffocating in a vacuum because they - ran low on air. - afterthought2: - - rscdel: Spiderbots have been removed. - - maptweak: The telescreen by the copier in medical has been removed; some laptops - have been restored. - - tweak: Everyone gets four times more starting cash. - - tweak: Traders spawn much more often, and stick around about four times longer. -2018-10-17: - Melioa: - - bugfix: Fixes text displayed when examining an Automatic Shutoff Valve. - Textor: - - rscadd: Body scans now look different depening on the skill of the person reading - them. This includes printed and scanned versions. - - rscadd: 'New machine: Body Scan Display. It can have scans pushed to it for surgeons - to reference.' - - tweak: Body scanner UI updated to nanoui. - - maptweak: Maps in two body scan displays, one in the main operating room, the - other in robotics operating room. - sabiram: - - tweak: The conglomerate representing corporate interests onboard the Torch has - been renamed to Tenjin Holdings. - zaredman: - - maptweak: Adds washroom to medical. Moves a maint ladder to give some space. - - maptweak: Expands medical's D3 storage slightly to use up unused space. - - maptweak: Adds trash chute to medical locker room. -2018-10-18: - sierrakomodo: - - bugfix: Fixes mouse/drone duplication bugs with cookers, microwaves, and destructive - analyzers (#14179) - zaredman: - - tweak: 'Change to chem recipe for making adrenaline: now requires inaprov, hyperzine, - and dex+.' -2018-10-19: - Miraviel: - - maptweak: Added proper piping to the infirmary hallway and lighting to the locker - room. Added missing shutters and moved around a few overlapping objects. -2018-10-20: - EcklesFire: - - rscadd: Added helmets to Xenowear loadout for Skrell in security/roles that use - armour. Credits to Karbivio for icons - Miraviel: - - rscadd: 'Added the following new emotes: afold, alook, crub, eroll (targeted), - erub, hbow, hip, holdup, hrub, hshrug, hspread, fslap, ftap,pocket, rsalute, - rshoulder, squint (targeted), tfist, tilt.' - Sbotkin: - - bugfix: Fixes the integrated circuits recycling. - - rscadd: Allows to recycle assemblies and individual circuits. -2018-10-21: - zaredman: - - bugfix: Replaces D2 Atmos CO2 high-power pump with pressure regulator and replaces - D5 CO2 high-power pump with a normal pump to avoid unintentional blowouts. -2018-10-22: - Datraen: - - tweak: Uplink kits come in generic containers now. - Textor: - - tweak: Changes Torch Ltd. to Expeditionary Corps Organisation in several spots. - - tweak: Adds DAIS labcoat to roboticist and biomech engineer loadouts. - sierrakomodo: - - rscadd: Bridge Officers now have access to the Charon's Airlock and Charon's Helm -2018-10-24: - Anticept: - - tweak: All pipes, except fuel pipes, now have the same pressure damage threshold. - Previously, cross-z pipes were significantly weaker. Fuel pipes' extremely high - threshold remain unchanged. - - tweak: All pipes have a slightly higher burst pressure threshold. - BlueNexus: - - tweak: '"Many chemicals now require heating or cooling in order to mix. Check - the wiki for specifics."' - - maptweak: '"Added heaters and coolers to various locations on the map."' - Roland410: - - rscadd: Radiation suits got a larger pocket and you can fit your geiger counters - on them now. Technology! - Sbotkin: - - tweak: All guns now spawn with safety on. - - bugfix: Fixes twohanded weapons not being rendered when on back. - afterthought2: - - tweak: Ship movement physics have been altered. Ships are now generally slower - to accelerate, though can move pretty fast when at max speed. This includes - the Torch as well as overmap-capable shuttles and away site vessels. - - bugfix: Overmap wrapping when moving diagonally has been fixed. - - tweak: Shuttles no longer have gravity when not at a location that has ambient - gravity. - - rscadd: A new admin tool has been added, Toggle Overmap Halt, which allows admins - to make all overmap ships stop and freeze them from moving. - - rscdel: The Move To Top object verb has been removed due to changes in the new - BYOND version making it no longer work consistently. - sierrakomodo: - - maptweak: Pilot's Lounge and Deck 5 Maintenance now have air alarms -2018-10-26: - Sbotkin: - - rscadd: Experienced shooter will disable the safety if they draw a gun with harm - intent. - - tweak: Captain's revolver (the one in the showcase) spawns with no ammo. - - bugfix: Fixed a bug with safety state not showing after unholstering. -2018-10-27: - Melioa: - - tweak: Replaces 'Broad-shouldered' setup build for 'Well-built' -2018-10-29: - Gates: - - rscadd: NTOS now requires MANDATORY updates every once in a while. - MistChristmas: - - maptweak: Added a weapon charger to Deck One Checkpoint - - maptweak: Removed fire alarm hiding in a bin in excavation prep -2018-10-30: - BlueNexus: - - rscadd: Added insulated beakers. It is now actually possible to make clonex. Oops. - - tweak: Clonex no longer requires phoron. - RyanSmake: - - rscdel: Removed NTNet relay from Bearcat space ruin as it was non-functional. - SierraKomodo: - - bugfix: All disposal units should now be connected to the disposal network. - sierrakomodo: - - bugfix: Adds missing disposal pipes to the briefing room. -2018-10-31: - Textor: - - tweak: The bodyscanner now provides feedback when pushing scans to the OR displays. - sabiram: - - rscadd: Some jobs now have a cap on education tiers you can select. -2018-11-01: - EcklesFire: - - imageadd: Adds new icons for the Skrell riot security voidsuit to bring it in - line with the Torch voidsuit. Credits to Karbivio. -2018-11-02: - afterthought2: - - tweak: Secret and random will (almost) never fail to start when voted in. - zaredman: - - maptweak: Adds Security, Science, and Engineering department pagers in their respective - lobbies. -2018-11-03: - Cakey: - - rscadd: Added fleet branch berets, for showing off your branch when you need to - wear your service uniform. - SierraKomodo: - - bugfix: Job slots should now open back up properly whenever someone cryos from - a multi-slot job -2018-11-04: - SierraKomodo: - - bugfix: OOC lobby manifest entries should now show proper Active/Inactive status - - rscadd: Crew records now have a separate 'Formal Name' field that contains the - MD/PhD/etc suffix. This will be the name displayed on manifests. - afterthought2: - - balance: TC prices on some merc items have gone up. - - tweak: You can now dump the contents of a pill bottle into the chem grinder by - clicking the grinder with the bottle. -2018-11-06: - Datraen: - - rscadd: Added Skrellian SDTF Holobadges, verb to set individual SDTF. - Miraviel: - - rscadd: 'Added three new hairstyles: Donut Bun, Gentle 2, Gentle 2 Long.' - SierraKomodo: - - bugfix: Crew manifest entries should now update properly when someone cryos - afterthought2: - - balance: EMPs now deal much less damage to synthetic humans (FBP, IPC), though - the amount is still considerable. - - balance: Damaged robotic legs and feet reduce movement speed. - - balance: Robotic external organs will, if heavily damaged or the damage taken - is large, pass burn damage to contained internal organs. - - tweak: Cell organs are dramatically less power-efficient if damaged. - - tweak: If a synthetic human runs out of juice, they become unconscious. -2018-11-07: - sabiram: - - tweak: It now takes some time to repair and pry open/closed blast doors and shutters. - - rscadd: Added a EXO polo undershirt to the loadout underwear options. -2018-11-08: - Earthcrusher: - - bugfix: Emotes ending in quotation marks will no longer add a superfluous period - on the end. - - bugfix: Lazy typists rejoice! When speaking, the game will automatically capitalize - and add punctuation where needed. Well at least on the end of the sentence. - - tweak: Emotes now use the visible emote character set in your Character Setup, - which defaults to "^". - EcklesFire: - - tweak: Removes Skrell education background requirements and allows them to utilise - more unarmed attacks. - SierraKomodo: - - bugfix: Deck 5 hallways now have air alarms. - sabiram: - - tweak: All various subcontractor (NanoTrasen and Hephaestus Industries, at time - of writing) items in the loadout have been merged into one item with type selection. - Key word to search for (CTRL-F) is 'corporate' - - rscadd: Lighters, zippos and candles now come in a variety of new colours. -2018-11-09: - Miraviel: - - rscadd: Prospectors were given EVA and SolGov crew access. -2018-11-10: - MistChristmas: - - maptweak: Replaces overlapping Xenobiology pipes for Scrubbers and Supply Ones. -2018-11-11: - Roland410: - - rscadd: Added a playable crashed survival pod. - - maptweak: Converted the old crashed pod into a random ruin. -2018-11-12: - Alex6511: - - tweak: Reduced the frequency of windows updates events by half - Blue Bit: - - imageadd: Added sprites for the anomaly console and scanning pad. - Datraen: - - bugfix: Cancelling SDTF naming for Skrell badges no longer blocks setting in the - future. - Sbotkin: - - rscadd: Adds digital multitool to the engineering toolset augment. - SierraKomodo: - - bugfix: Fake Crew Announcements traitor service now broadcasts the correct arrivals - message on use - - bugfix: Fake Crew Announcements traitor service now properly updates the crew - manifest with rank, name, and honorifics -2018-11-15: - Roland410: - - tweak: Gamemode vote starts at 160 seconds, giving players 100 seconds to change - their character/preferences according to the voted gamemode. - - tweak: Should a non-secret mode fail to start, you will have one minute to adjust - your preferences or unready before roundstart. -2018-11-16: - Faustico: - - rscadd: Added basic security belts, like normal security belts but without a holster. - - maptweak: Added basic security belts to MAA lockers. - - tweak: Storage accessories and holsters use two different accessory slots again. - SierraKomodo: - - tweak: Blob resistance has been rebalanced. Brute-based weapons (Crowbars, fireaxes) - are more effective against cores, while fire-based weapons (Welders, lasers*) - are more effective against blob and strong blob. *Laser rifles take a 1/2 damage - penalty against all blob targets. See https://github.com/Baystation12/Baystation12/pull/23774 - for specific numbers. - TheWelp: - - rscadd: Adds ability to destroy circuit assemblies via damage. Bigger assemblies - means more health. Can be healed with wire. -2018-11-17: - CrimsonShrike: - - rscadd: Adds the mech pilot inspired Null Suit to robotics fabricator. This lightweight - rig offers little to no protection and cannot mount weapon modules. -2018-11-19: - Alex6511: - - tweak: the malfunctioning drone on away sites has had its damage adjusted - BlueNexus: - - bugfix: Cryo Cells now work properly, with temperature. This means clonex is possible. - - tweak: Clonex can no longer mix below -200C - Miraviel: - - tweak: Updated the guest pass terminal icon. Added guest pass terminals to supply - and to the Pathfinder's office. - - tweak: Using the autopsy scanner in-hand will now print the scan. Its icon was - also updated. -2018-11-21: - Aticius: - - bugfix: Crashed pod should no longer have random space tiles causing constant - air flow/air loss. - SierraKomodo: - - tweak: Charon and Aquila APCs now include helm access flags, meaning anyone who - can access the shuttle's helm can also unlock the shuttle's APCs. Engineers - still have APC access as well. - afterthought2: - - bugfix: Clonex should work properly with cryo tubes now (recall that you have - to make it at -100 to -75 C, best done with the cooler). It will adjust its - temperature to that of the cryo tube, which should prevent it from denaturing - under normal circumstances. -2018-11-22: - Alex6511: - - maptweak: Added a large insulated beaker to chemistry. - EcklesFire: - - bugfix: Makes Skrell medical voidsuit helmets work. - afterthought2: - - tweak: Clonex now won't denature below 50 C (i.e. unless you heat it). - sabiram: - - balance: Space carp now have generally more health and more powerful attack values, - and move faster. Pikes and sharks now have more health and do more damage. - - balance: All castes of giant spiders are now tougher, faster, and more deadly - all around. Hunters in particular are very dangerous. - - rscadd: Hunters and guards now use a new venom. - - rscadd: Added colour variants for space carp. - - rscadd: Added randomly coloured eyes for giant spiders, and made them glow. - - rscadd: Hostile mobs will now attempt to pry open doors between them and their - target, though they can be interrupted. - - rscadd: Hostile mobs can now destroy window-doors and tables. - - bugfix: Fixed hostile mobs not destroying windows, grilles, wall frames, etc. - - rscadd: Added more colours for space carp. -2018-11-24: - Blue Bit: - - rscadd: 'There are now two additional exoplanet types: shrouded and chlorine.' - - rscadd: Added a few alien creature color variants. - - maptweak: Added six new randomly spawning exoplanet sites. - - bugfix: Fixed a portion of the "Lodge" away site that was designated as space. - RyanSmake: - - rscadd: Adds a Bluespace Artillery to Deck 2 missile bay. Select an adjacent overmap - tile, and get rid of the event on it, or shoot at the away sector a charge of - your choosing (emp, remote mining, explosive, fire, or droppod). - Toriate: - - tweak: Photocopier now uses new photocopier icon state in bureaucracy.dmi instead - of the scanner iconstate. - - imageadd: New photocopier sprites added! Made by yours truly. - afterthought2: - - rscadd: The mecha skill (Exosuit Operation) is now a subskill of EVA. You need - to have at least Trained in EVA to select it, and then choose it from skill - selection. - - rscadd: Driving mecha without the mecha skill may result in unpredictable movement. - - rscadd: Exiting a mecha without proper skill may occasionally force-eject you. - - tweak: The mecha skill no longer has anything to do with mecha fabrication in - the description. - sabiram: - - tweak: Nurse spiders should infest their enemies with eggs less often than before. - - rscadd: Added giant spider legs, harvested from giant spiders. Can be used in - sushi or boiled in the microwave. -2018-11-25: - RyanSmake: - - bugfix: The BSA actually works now. -2018-11-26: - Funce: - - bugfix: You can no longer get infinite amounts of cable coil from constructing - and deconstructing certain telecomms equipment - Hubblenaut: - - tweak: Drawing guns based on intent is now a preference option. - SierraKomodo: - - tweak: Autopilot default speed lowered from 2 (Exceeds max speed hardcap of 0.1) - to 0.0025 (40 seconds ETA per tile) - - bugfix: Autopilot no longer burns fuel needlessly bouncing above/below the speedlimit, - and will now never go above the speedlimit. - - tweak: Autopilot now handles changing direction/destination and diagonal movement - much more efficiently fuel wise - - bugfix: It is once again possible to decelerate to a speed of 0. -2018-11-28: - afterthought2: - - tweak: Surgically repairing decaying organs is once again viable. -2018-11-30: - Heph-hasto: - - rscdel: Removes ability for ship AI to be traitors -2018-12-01: - Cakey: - - tweak: After the sudden drop in SCG funding, the newly released MRE line has been - reduced in content. - SierraKomodo: - - rscadd: General Notes (Public) field has been added to crew records. These are - records visible to anyone who can open crew records, and are intended for 'common' - information between security, medical, /and/ employment records. - afterthought2: - - rscadd: A new admin tool, Toggle Circuits, has been added to the Secrets panel. -2018-12-02: - Aticius: - - rscadd: Adds a joinable Colony map that can spawn on exoplanets. Rimworld mode - is here. - Broseph Stylin: - - rscadd: A new Scientist rank is now available for the SolGov Employee branch. - - tweak: The Scientist and Research Assistant jobs are now open for the SolGov Employee - rank of Scientist. -2018-12-03: - Cakey: - - rscadd: Added katsu curry, made with a slab of chicken, 10 units of rice, 10 units - of water, 5 units of flour, an apple, a carrot, and a potato. - Toriate: - - imageadd: The LAEP90's sprites have been replaced with new ones! - sabiram: - - tweak: Wall frames now use materials like walls do, and can be painted and unpainted - with the paint gun. -2018-12-04: - Aticius: - - maptweak: Bunch of minor fixes and tweaks to the Colony map. The walls no longer - eat mining computers. Oops. - Cakey: - - rscadd: Added Terran Navy uniforms. - - rscadd: Added Terran Navy ranks and structure. - sabiram: - - balance: Giant spider nurses will now only inject eggs into organs that have space - for them. - - balance: Reduced the number of spiders hatched per egg injected. - - balance: Injected spider eggs now mature more slowly. - - tweak: Slightly reduced maximum possible health for all castes of giant spider. - - tweak: Reduced occurrence weight and severity of spider infestation event. - - tweak: Spiders bursting out of organs is more damaging. - - tweak: Hostile simple animals can now destroy railings. - - tweak: Simple animals should now die faster after taking fatal damage. - zaredman: - - rscadd: Adds a MEDIC and OCIE AGENT tag for plate carriers. -2018-12-06: - Cakey: - - imageadd: Fleet uniforms sprites have been re-done. - - rscadd: Added Fleet officer's alt utility uniform, mainly used by bridge crew. - - rscadd: Added Fleet service jackets, with alternating trimmings based on rank - (enlisted, officer, senior officer, flag officer) - - rscadd: Added new Fleet dress jackets, with alternating trimmings based on rank - (enlisted, officer, senior officer, flag officer) - afterthought2: - - maptweak: The GUP is now overmap capable, though with poor sensor quality. - - maptweak: The GUP is no longer fully pressurized. Use the unlocked air alarm to - properly modify the atmosphere as needed. -2018-12-07: - Aticius: - - rscadd: A new paint job has been added to suit cyclers in the Engineering department. - Stomp around in style in a Hazardous Operation suit! - RyanSmake: - - bugfix: Stopped AIs and ghosts from activating artifacts. -2018-12-08: - sabiram: - - maptweak: The ship's Christmas tree has been installed in the galley. -2018-12-09: - Eckles: - - tweak: Changed Terran to Gilgamesh/Independent. Faction rename. - - tweak: Enforced Martian and Martian Surfacer as default human culture/system instead - of generic 'humankind'. - Persona E: - - balance: Unathi and Dionaea can no longer regenerate without nutrition. - Roland410: - - tweak: Construction skill is required for basically any recipes now, and material - difficulty (what skill you need to be able to craft from it) has been upped - for most of them. - - tweak: Engineering contractors receive trained construction now to be able to - handle plasteel. - Sabira: - - balance: Handheld and mounted/portable flashers now work on all simple animals. - - balance: All hostile mobs can now be stunned. - - balance: Spiderlings now pull from a weighted list of castes when determining - which caste to grow up into. Hunter spiders are rare, all other castes are even. - - balance: Every caste of spider except hunters can now be captured with nets. - - balance: Various spider numbers tweaks. Reduced hunter maximum damage. Reduced - lifesteal for all castes. Reduced nurse venom-ness. - - balance: Nurse spiders now have a maximum amount of eggs they can lay. They can - ready more eggs by feeding from mobs trapped in cocoons. - - rscadd: The base variant of giant spider is now an unremarkable generic worker - meant to fill the ranks. They don't have any special gimmicks. They're green. - - rscadd: Added a proper guard caste to spiders. Guard spiders (brown) will now - be paired with a nearby nurse (beige), and will closely follow them til' death - do they part. Killing a nurse might throw their guard into a rage. - - rscadd: Added a spitting spider (purple) caste - once they're out of venom, they'll - have to generate more before they can spit again. They'll resort to melee combat - if they're out of spitting venom. - - rscadd: Hunter spiders can now initiate combat by leaping at their prey. - - tweak: Hostile mobs will now only attempt to destroy their environment if the - obstacle is between them and their target. - - tweak: Hostile mobs now have a chance to miss their attacks. Flashing them increases - the chance. - - tweak: Hostile mobs can now have individual delays for prying open doors. Spiders - and carp are currently the only ones set. -2018-12-10: - Blue Bit: - - rscadd: Liquids can now be collected from exoplanet puddles. - - rscadd: Added tar. It's a bit toxic, but it can be heated and broken down. - afterthought2: - - rscadd: Some exoplanet plants now produce exotic chemicals, with effects that - are randomly generated each round. - - rscadd: Inspecting these chemicals in the mass spec with high chemistry and/or - science skill will reveal additional information about them. - - rscadd: By heating them to almost, but not quite, their boiling points, the effects - of these chemicals strengthen (if with phoron catalysis, then weaken). By also - adding certain additional ingredients (depending on the effect), the effect - will instead be left unchanged. - - rscadd: 'Cooling works similarly, but now the default behavior is that the effect - is left unchanged: you need to add certain additional ingredients to make the - effect strengthen (or weaken, with phoron).' - - rscadd: These chemicals may have powerful combinations of medical (or poisonous) - effects that can be used, or (if purified sufficiently) can be sold for large - profits. - sabiram: - - bugfix: Giant spider nurses will no longer infinitely attempt to cocoon deceased - giant spiders. -2018-12-11: - Persona E: - - rscdel: Removed the TCC ushanka from the loadout. - afterthought2: - - tweak: You can now order additional BSA charges from supply. - - tweak: Mass driver ammo is now cheaper. -2018-12-12: - Carlen White: - - tweak: The supply terminal listing of supplies shade every so listing to help - item selection. -2018-12-13: - Dave-TH: - - bugfix: The Pilot's qualification pin can now be pinned to jackets. (Like the - rest of the pins) - - bugfix: The dedication plaques on the bridge are no longer invisible. - - bugfix: The Pathfinder's hardsuit no longer has an invisible chest piece when - sealed. - WhiteHusky: - - rscadd: Supply consoles now show a notice when there are pending orders when properly - authenticated. - - spellcheck: Fixed misspellings in the Supply Console. -2018-12-14: - PoZe: - - tweak: Admin verb Create Object major flaw was optimized to display/search lists - of all objects instantly, instead of freezing for 3-4 seconds. - RyanSmake: - - bugfix: After repeated complaints from the SEV Torch that all showers are constantly - clogged we have deployed the NanoTrasen Bluespace Plunger(tm). Operation successful, - showers will never clog again. - WhiteHusky: - - bugfix: You no longer "see" items being removed from bags or other storage items - when blind. - sabiram: - - tweak: Placing acids in a fire extinguisher will now destroy them, and may splash - acid onto the user. -2018-12-15: - afterthought2: - - rscdel: NTSL has been removed entirely. -2018-12-16: - Alex6511: - - bugfix: Normal humans can no longer select the vat-grown specific culture - Hubblenaut: - - bugfix: Fixes movement with grabs. -2018-12-22: - sabiram: - - rscadd: Added two new holodeck programs; a plaza and a bathhouse. -2018-12-24: - WhiteHusky: - - rscadd: You can enable notifications for the shipping program. -2018-12-27: - Anticept: - - tweak: 'XO default access is no longer spotty. It now has access to the entire - ship and shuttles, including research. Specific changes: Added robotics, all - of research including petrov, Pilot, Mining, and Commisary. Places XO does not - have access: Captain, Research Director''s office, Research Director''s Petrov - Office, SolGov Rep, and Corporate Liason.' - - rscdel: Removed Genetics access from the game. - - tweak: Renamed "Nanotrasen" in the access computer program to "Corporate". - - tweak: Renamed access "Psychiatrist's Office" to "Mental Health". Renamed access - "Head of Security" to "Chief of Security". Renamed "Head of Personnel" to "Executive - Officer". "Quartermaster" is renamed to "Deck Chief". - Hubblenaut: - - bugfix: Anomaly isolation and Xenobiology air alarms will no longer cause atmos - alarms. - Toriate: - - tweak: RCD now carries 120 matter units at max. Small matter cartridges give 30 - units, while large ones give 120. - - rscadd: Rapid Crossbow Device added. Craft by screwdrivering a RCD and then slapping - a fully assembled crossbow frame into it. - - imageadd: New RCD sprites in tools.dmi, made by yours truly. Originally made for - Eris. - - imageadd: New Matter Cartridge sprites, based off /tg/'s. - - imagedel: Old RCD sprites deleted. - WhiteHusky: - - rscadd: You can now print receipts on pending, approved, and archived orders. -2018-12-28: - WhiteHusky: - - rscadd: You can now examine neural laces, and understand them assuming you have - the skill. - afterthought2: - - tweak: Off-station roles are blacklisted from being on-station antags. -2018-12-30: - WhiteHusky: - - rscadd: RFID card readers firmware has been updated to allow verbose diagnostics - checks. -2018-12-31: - WhiteHusky: - - tweak: You no longer drop computer hardware onto the floor if possible. -2019-01-02: - afterthought2: - - tweak: The colony will no longer start irradiated. -2019-01-03: - Broseph Stylin: - - rscadd: A system to automatically switch clothing icons based on gender has been - introduced. It is currently set up to work for humans and human subspecies. - - tweak: Expeditionary Corps, Fleet and Army uniforms as well as EXO and corporate - variations of the Torch Research uniforms now have gendered icons. -2019-01-06: - Cakey: - - maptweak: Fixed odd spacing in supply, adds a cargo lift to the warehouse. - CrimsonShrike: - - rscadd: Adds detective instinct verb for master forensics. This will give most - of the scene a distinctive noir look. - Hubblenaut: - - bugfix: Fixes shuttles removing air from the hangar upon arrival. -2019-01-07: - Anticept: - - tweak: Radiation resistance now fully blocks radiation levels below its radiation - resistance percentage, and thereafter will only allow some radiation leakthrough. - Lower resistance suits leak much more readily once past the threshold, while - high resistance suits will only leak a little bit after the threshold is reached. - Very highly irradiated environments are still extremely dangerous. -2019-01-08: - Anticept: - - tweak: The CE Firesuit is now firefighting rated, just like firesuits and atmos - suits. - Chinsky: - - soundadd: Pain has a low chance of heartstop again. High shock levels ('You feel - like you can die any moment now!' level) can sometimes cause thready pulse. - Countered by giving poor sod some painkillers to prevent shock, or some inapro - to stabilize the pulse. - sabiram: - - maptweak: The Christmas tree in the bar has been removed. -2019-01-10: - Anticept: - - rscadd: Added a waste tank for atmospheric waste gasses next to the fuel bay. - Now there's a place for gasses the Torch doesn't have a tank for, as well as - storage for engine byproducts, and can be dumped to space or recovered with - canisters. Also acts like a good way to clear a backed up atmos system if you - know how to configure the pumps and valves, and don't mind spacing the gas. - - rscdel: Engineering thrusters (not nacelles) are now purged from the game. They - offered next to no thrust at all and now the engine room is a little bit simpler. - - tweak: All black pipes in engineering ultimately go to the waste tank. - - tweak: Removed redundant fuel bay firedoor (it had two at the entrance). - RyanSmake: - - bugfix: AIs now get alerted once again when someone edits their laws. - Textor: - - rscadd: Adds DAIS, Xynergy, EC, and EXO logos to paperwork formatting, adds help - information about new logos to nanoword formatting help. - - rscadd: Adds all missing logos to the admin paperwork so that they can be used - in fax replies. - - tweak: Changes [tccseal] to [iccgseal], makes the EXO logo take over "[logo]" - and moves nt logo to [ntlogo] - comma: - - tweak: All speed/acceleration values are now displayed multiplied by 1000. Actual - mechanics are still same. - - tweak: Only 1 random alien seed in Xenoflora storage now, and can't order them - from cargo. Go on expeditions nerds. - - maptweak: No more pre-spawned anomalies on Petrov. Go on expeditions nerds. - lorwp: - - tweak: IPCs can now use the Command Hardsuits -2019-01-11: - Anticept: - - tweak: Radiation planets background rads peak out at 75bq. Hotspots are still - deadly though! - - tweak: Adjusted waste tank dump port so it goes to the edge of shields, rather - than dumping onto the top of D3 pod. - - tweak: Added a pump to the waste tank canister port. - BlueNexus: - - maptweak: Nacelles have been reworked. - - bugfix: As a result, combustion mode works again. - MistakeNot4892: - - rscdel: Removed the education system entirely. - RyanSmake: - - bugfix: Chief Engineers now spawn with correct backpacks. - Zuhayr: - - rscadd: Added a department goal system. Use Check Goal to view them inround. - - rscadd: Added a personal goal system. Defaults to disabled. Set Crew Goals to - something else in your global preferences to start getting them on join. - - tweak: Merged ambitions into goals. -2019-01-13: - Anticept: - - tweak: The "Set transfer amount" verb's range is now one tile, so now you don't - have to be carrying them to set it anymore. - - bugfix: ghosts and unconscious can no longer invoke the set transfer amount verb - on containers and IVs. - - tweak: Gas sensors in atmos and waste tank now display all gas contents that they - can identify. - Chinsky: - - tweak: Falling down zlevels now has a chance to dislocate feet/arms. Athletic - skill mitigates it, Trained and above are safe. - - tweak: Setting dislocated limbs now requires Medicine skill to be reliable, especially - for self-setting. Basic skill is enough for ~90% success rate, Trained is guaranteed - or your money back. - - tweak: Walking on fractured or dislocated limbs now applies additional pain to - that limb. Rest a bit for it to clear up or use a cane. - Hubblenaut: - - rscadd: Large escape pods will now repressurize themselves after undocking. -2019-01-21: - Anticept: - - rscadd: CMOs rejoice! Your hypospray now has a quantity setting, you can administer - in 1,2,5,10,15,20, or 30 units per injection! - - rscadd: CMOs rejoice! You can now pour your hypospray contents into a container - without removing the vial! (you can already put reagents in it too without swapping - vials) - - rscadd: CMOs rejoice! You are now coordinated enough to swap vials on the fly. - No longer do you have to remove and put away the old vial before you can install - a new one. - - rscadd: Medical rejoice! The contractor producing your syringes have heard your - cries and installed easier to read graduations on syringes. You now can set - transfer amounts in 1, 2, and 5. - - rscadd: Everyone rejoice! When pouring containers, you will now be able to see - how many units are remaining. - - bugfix: drones and borgs can once again use r-glass. - - bugfix: drones and borgs glass stacks are colored correctly. - Blue Bit: - - rscadd: Security borgs now have a hailer. - - bugfix: The playable colony should once again have its rods. - Cakey: - - maptweak: The robotics lab is now two-floored. Has a lift. - - maptweak: Cyborg station has been moved next to atmospherics. - ChaosAlpha: - - bugfix: Robots and drones should once again be able to drop items from their grippers - from the Silicon Commands tab (the verb has been renamed "Drop Gripped Item"). - - bugfix: Robots and drones now drop all gripped items on death. - Chinsky: - - rscadd: Rods are now material based, can be made from more than just steel. Same - with grilles and lattices. - - rscadd: Windows are material based too, any non-opaque material can be used to - make them (currently diamonds and quartz). - - rscadd: You can get back rods from rglass (rphoronglass) by welding them out. - - bugfix: Autolathe now will properly get some steel material on top of glass if - you feed it rglass. - Eckff: - - tweak: The sleep button now keeps you asleep until you press it again. It will - not wake you up from other things that cause you to sleep, like chems. - Eckles: - - bugfix: Fixes sprite and object issues with the riot security voidsuit for Unathi - and Skrell - Hubblenaut: - - bugfix: Fixes cameras of robots, hardsuits, Thunderdome and similar not being - accessable. - MistakeNot4892: - - tweak: Locker icons now use a runtime-based system. This should have no player-facing - impact other than the cosmetic effects of new locker icons. - - rscadd: Added a Loss Prevention Associate role. Basically a bodyguard for the - Workplace Liaison. They can only spawn with an active Liaison in the round, - and get a secure gun with corporate access. - - tweak: Added backend support for deferred roles, please make a bug if this breaks - anything in roundstart job allocation. - - rscadd: Added a stomach organ. If your stomach is damaged, you can't eat properly - and won't metabolize reagents well. - - tweak: Puke now contains some of the reagents you had in your stomach, plus some - stomach acid. We are pushing the boundaries of puke simulation technology. - - rscdel: Removed Xenolife Technician and NT Guard. - - tweak: Research Director is now the Chief Science Officer and may only be EC-ranked, - not contractor. - - tweak: All other science roles are now available to EC staff as well as contractors. - WhiteHusky: - - rscadd: Intergrated circuit's medical scanners can now get a patient's pulse. - afterthought2: - - tweak: Adherent are now shock-immune. - lorwp: - - tweak: the EVA Hardsuit in Engineering Hard Storage now fits on IPCs. Rejoice - sabiram: - - rscadd: Added aluminium. It's the standard material for furniture such as tables - and chairs, among other things. - - tweak: Added plastic and aluminium to the autolathe. Many recipes have been adjusted. - - tweak: Smelting bauxite now yields aluminium. Bauxite blocks can still be obtained - by compressing. - - tweak: Added aluminium sheets to the supply menu. - - maptweak: Added aluminium sheets to where metal sheets are found. - xales: - - tweak: Torch command (CO, XO, SEA) now share a headset type and encryption key - - tweak: The XO now has science keys in their locker. -2019-01-26: - Cakey: - - rscadd: Re-adds exploration helmet-cameras. - MistakeNot4892: - - tweak: YOU WILL NEED TO UPDATE YOUR RANK AND BRANCH PREFERENCES, READ THIS CHANGELOG. - - tweak: Occupations panel got a visual overhall. Click the link-name of a job to - set alt title, and click the never/high/low/medium to cycle between job weights. - - tweak: Rank is now tracked by job, not by save slot. You can set your rank and - branch up as you like for each given job. - - tweak: You can now set/save skills for submaps in the occupations panel. - Pandolphina: - - rscadd: Adds a new exoplanet ruin, a data capsule ejected from a ship with zombie - juice inside. - Textor: - - rscadd: Escape pod blast doors now open upon reaching pod launch sequence. You - might want to stay out of maint areas near escape pods when pods are getting - ready to launch. - - maptweak: After much deliberation, the Health and Safety department decided that - Engineering, the misc laboratory, and the tunnels outside the deck 2 escape - pods should be more well-lit. - - maptweak: The forensics office and bridge now have chairs that can rotate. - - maptweak: The deck 1 conference room floor has finally been repainted properly. - - maptweak: The R-UST now has its own power monitor installed and a gas injector - and a port to allow engineers to inject various gasses into the R-UST chamber - if they want. - - maptweak: Deck 3 has more emergency shutters to prevent the spread of fire and - decompression and prevent hapless engineers from wandering into unknown danger - outside the EVA room. - - bugfix: Fixes deck 5 subgrid configuration. - - bugfix: Fixes stasis cages. - - maptweak: Replaces ready room with adherent maintenance. Ding. - - tweak: Adherents now recharge at cyborg rechargers at half the rate. - - maptweak: Removes mineral baths from all other map locations. - - tweak: Adherent pylon will now damage robots. - - rscadd: Adds adherent tool vendor and crystal material airlock. - WhiteHusky: - - rscadd: You can show the contents of supply products. - afterthought2: - - tweak: Rad collectors and potted plants now cost more when ordered from supply. - - tweak: Adrenaline now does some heart damage if used to restart the heart. - sabiram: - - rscadd: Added green tea, iced green tea, and sweet green tea. - - rscadd: Added green tea to bartender soft drinks and coffee reagent dispensers. - - rscdel: Removed iced tea dispenser. Combine ice and the tea of your choice to - create iced tea. - - rscadd: Added flavour pods and sugar packs to the hot drinks vendor to flavour - your tea or coffee. - - rscadd: 'Added two new mixed tea drinks: Baron Grey is prepared by mixing black - tea and orange juice, and Maghrebi mint tea is prepared by mixing sweet green - tea and mint.' - - rscadd: Added teacups to the cutlery vendor. - - rscadd: Added chazuke. It can be prepared by mixing ten parts rice and one part - green tea in any container. Microwaving ten parts chazuke will result in a snack - bowl meal. - - rscadd: Added aluminium and plastic into the protolathe system. Many recipes have - been adjusted. - - maptweak: Removed protolathe from the robotics laboratory. - - maptweak: Added aluminium sheets to the research and robotics storage areas. -2019-01-28: - Roland410: - - bugfix: Fixed/removed the cap on away site jobs' skills. - sabiram: - - tweak: The circuit printer and protolathe can now hold more materiel. -2019-02-05: - Anticept: - - tweak: Pilot skill description now clarifies random movement occurs until trained - or greater, regardless of what ship you are flying. - - bugfix: Fixed phoron glass sheet's melting temperature so that reinforced phoron - glass is consistent with the pre-material overhaul melting temperature. This - should stop the random window breakage in the engine core until close to delamination - temperatures. - - tweak: Due to the nature of the material overhaul and this change, regular un-reinforced - phoron glass also gets its temperature significantly buffed. It's still weak - to physical attack by comparison to reinforced phoron glass. - Cakey: - - maptweak: Added LPA equipment closet to the Workplace Liason's office. - - tweak: Added "Asset Protection Agent" as an alt title to LPA. - - tweak: You can now put people onto wall frames with grabs - Chinsky: - - rscadd: Added an exploration shotgun. It's in a wall locker on Charon, along with - ammo, replacing netgun. What can possibly go wrong? - - rscadd: It can fire freely off-ship, but onboard you gotta register and get XO - or CO to authorize it. Yes it's pain, yes it's intended. - - rscadd: It is only guaranteed to work with types of ammo it ships with - beanbags, - flash, net rounds. Loading combat ammo voids warranty and may result in fun. - Datraen: - - rscadd: Adds Skrellian Weapons, currently admin spawn only. - Herigony: - - bugfix: Fixed admin jobban panel - Textor: - - bugfix: After paperwork being filled out in triplicate, lost, found, and buried - in peat for two weeks, the CSO now has access to their uniform in the uniform - vendor. - - bugfix: You now need to be an EC scientist to select an EC labcoat in loadout. - Senior Researchers and Assistants now have access to some of the same stuff - as normal scientists that they lacked. Also adds some equipment the biomech - should have access to. - - bugfix: Non-senior researcher Ensigns in the science department are now properly - considered officers and have an officer's uniform given to them when they wake - up instead of an enlisted uniform. - - rscadd: Labcoats can now be issued via the uniform vendor for EC science people. - sabiram: - - rscadd: Added the CSO's rigsuit. - - maptweak: Removed the AMI rigsuit module from the CSO's Petrov office and added - the new rigsuit to the bridge EVA storage. - - maptweak: Resized and reorganised the bridge EVA storage. - - rscadd: 'Added new wood material types: mahogany, maple, walnut, and ebony. These - types are largely identical apart from their colour.' - - rscadd: Added supply crates to obtain the new woods. - - maptweak: Several tables and chairs across the ship that were previously generic - wood are now made from mahogany, maple, or walnut. - - maptweak: Shuffled things around a bit in the captain's quadrant. - - maptweak: Moved the CSO's primary office back to the bridge, from the Petrov. - - rscadd: Clipboards are now a material item and can be constructed from most materials. - Clipboards that spawn around the map will be of various materials. -2019-02-06: - ghostsheet: - - maptweak: Rearranged the Guppy's interior for quality of life conveniences. - sabiram: - - rscadd: Radiation collector arrays will now fail catastrophically if exposed to - extreme temperatures, such as those found within the supermatter core. - - maptweak: The robotics lab has been messed with again, everything should work - now hopefully. -2019-02-07: - comma: - - tweak: The year is 2307 now. Roleplay accordingly. - sabiram: - - rscadd: Added explosive harpoons to the uplink. These will only explode upon embedding - in a target, by throwing it at them or sticking them close up. - - tweak: Increased the base harpoon's throwing force divisor. -2019-02-08: - Datraen: - - bugfix: Fixes incorrect access on hangar maintenance doors. -2019-02-09: - Anton-Kr: - - rscadd: Adds Vox ship and base to the game. It's join-able as a submap. -2019-02-10: - SierraKomodo: - - maptweak: Added rechargers to merchant shuttle and merchant base - - maptweak: Connected Flight Control disposal bin to pipe network - - maptweak: Added borg rechargers to communal brig and merchant's station - comma: - - tweak: Uplink gun selection for traitors was scaled down. Assault rifles and similary - big guns are gone, only pistol-likes available now. - - tweak: Wall of text about clothing items property is moved to a codex entry for - the item, instead of being shown on every examine. - sabiram: - - maptweak: The king of goats in the hydrobase planetary ruin has been retired. -2019-02-12: - Chinsky: - - rscadd: CPR changes. It now will help with blood circulation even if it fails - to restart the heart, so there's a reason to do it (especially on higher levels). - Fake circulation lasts 20 seconds and is better with Anatomy/Medicine skill - (highest). - - rscadd: Can now put IV bags etc on rollerbeds and use them as IV stands for buckled - people. Click with beaker to add it. Click with empty hand on empty (no buckled - guy) bed to remove it. Drag bed on people to hook/unhook. - - rscdel: Damaged livers no longer generate ammonia. It was creating self-perpetuating - damage which wasn't intended, it was for diagnostic memes. - - rscadd: Adds auto-CPR device. Goes into victim's suit slot. It won't do mouth-to-mouth - or resusticate them, but it will help with circulation. Needs Basic Anatomy - and Medicine skills to use, or risk rib fracture. Basically continuously applies - circulation part of CPR. Mapped bunch of them in medbay - - tweak: Sleepers now have 10x stasis option. Their power usage now also scales - with stasis factor greatly, 500 per factor, so ~5000 W at 10x - - rscadd: Guns suck now. - - tweak: When you have a gun in activa hand, you're considered to be 'aiming'. Moving - or changing active hand resets timer. - - tweak: Aiming gives bonuses to accuracy, longer you aim, capped by accuracy of - the gun - so no point in aiming longer than few secs with pistol, but with sniper - rifle, take your time. - - tweak: If you haven't stood still for at least a second, you get penalties based - on size of your gun. Pistols are almost not affected, but rifles are affected - greatly. - - tweak: Accuracy falloff differs for different calibers. Pistol rounds are best - used 4 tiles or closer, rifles can be used from any range without ok results. - Lasers mirror that setup, with higher range. - - tweak: Overall, pistols are now useless at range, but don't suffer much if you - move around or change hand to do something else. - - tweak: Rifles are oppsite, can hit if you aim even from other end of screen, but - if you move around, you're not going to hit shit. - - tweak: Moving around (not towards gun) will make you harder to hit now. Yakkety - sax away. - - rscadd: Added a small bells ringing sound playing when you regain consciousness. - Will only play if player is considered AFK (currently 5 minutes without activity) - Spookerton: - - tweak: Mercenary and Raider game modes no longer do early round-end votes when - the antagonists leave or die. - afterthought2: - - rscdel: Guns and armor are no longer available in personal command lockers. - - tweak: The bridge sidearms closet now also has three sets of command armor. -2019-02-14: - Anton-Kr: - - bugfix: Some misc things fixed on Vox ship. - RyanSmake: - - bugfix: Holodeck windoors now actually face the right direction. - SierraKomodo: - - maptweak: Added Pilot Voidsuit to bridge deck's EVA Storage that Bridge Officers - and Senior Enlisted Advisors can access. - - maptweak: Re-arranged the bridge deck's EVA storage. - Spookerton: - - tweak: IPV Fortuna can now fly on the overmap without being doomed. - Textor: - - maptweak: The battery backup PSU in telecomms has been moved after many Chief - Engineers and Senior Engineers have complained about its disruptive location. - The battery backup PSU also now recharges off of the deck 3 subgrid rather than - making a loopback off of the telecomms subgrid. Grey outlines have been moved - around in telecomms to be more consistent with the rest of telecomms' appearance. - - tweak: All telecomms machinery and computers have been updated to use NanoUI style - interfaces, bringing them in line with the majority of UI interfaces on the - Torch. -2019-02-15: - Chinsky: - - tweak: Accidental gun discharge chances upped, and now it can happen when aggressively - unholstering (hurt intent). Chance is now 20% at unskilled, 5% at Basic and - 1% at Trained. - - tweak: When unholstering or trying to fire a safetied gun on hurt intent, there's - now a chance you automatically unsafety it. Chance is 0% at unskilled, 25% at - Basic and 50% at Trained, guaranteed above. - RyanSmake: - - rscadd: You can now interact with emergency shutters through ladders and open - spaces. - SierraKomodo: - - maptweak: Added air and fire alarms to the deck 4 hanger catwalks. -2019-02-18: - Chinsky: - - rscadd: Crypods now have more immulsion. When joining round you will spawn inside - a pod, asleep for 1-5 seconds. Roleplay accordingly. - - tweak: Can now place auto-cpr device on people by clicking on them with it on - help intent. - afterthought2: - - experiment: No stasis bags are available on spawn on the Torch, except one on - the Charon. - - tweak: Stasis bags can now be printed from the protolathe. - - tweak: Stasis bags are now more expensive when ordered from supply. - - tweak: Rollerbeds can now be placed in backpacks. - comma: - - tweak: Autopsy scanner can now be used on severed organs to get some information. - No trace chems or time of death though, need body for that. -2019-02-19: - afterthought2: - - tweak: Modular consoles will no longer have access to NTnet when off-station. - comma: - - rscadd: Mountains can now spawn on any type of planet -2019-02-20: - Chinsky: - - rscadd: Added rescue bags. Work like bodybags, but provide atmosphere from attached - gas tank. Will set internal atmosphere of the bag to tank's release pressure. - Use screwdriver to remove tank. -2019-02-21: - Anticept: - - tweak: XO now has CSO access. - MistakeNot4892: - - rscadd: Added a drug called Three Eye to the contraband drug crate. - - rscadd: Added a chemical agent for crystallizing people. Good for repairing golems. - - rscadd: Breaking a soulstone into shards and stabbing them into a wizard (or firing - a null rod out of a pneumo cannon hard enough to embed it) will now prevent - the wizard from casting spells. - - rscadd: Added supporting code for psionics. - sabiram: - - rscadd: Added chevaux de frise, or spiky barriers. They're constructed by first - building a barricade of any valid material, and then attaching rods of any material - to the barricade. It will damage anyone who walks into it. -2019-02-23: - BlueNexus: - - rscadd: Added Venaxilin, a powerful antivenom made with spider venom. - - rscadd: Added leporazine variants, which are made by either heating up or cooling - down leporazine. Heating it up makes a chem that raises body temperature, cooling - it down makes one that lowers it. - Textor: - - rscadd: Adds new global preference to opt into having your ckey displayed in the - credits. This is set to hide your ckey by default. - - tweak: Adds additional snark to the end of the credits and some new randomly generated - title possibilities. - - tweak: Changes some awkward wording in play global sounds command, makes the change - end credits song command not suck anymore. - afterthought2: - - bugfix: The merchant can now use the merchant program again. - - tweak: The merchant program cannot be downloaded on NTnet. - comma: - - rscdel: Stasis bags are no longer orderable from cargo. -2019-02-24: - RyanSmake: - - bugfix: Shuttles no longer steal asteroid tiles when undocking. -2019-02-25: - Spookerton: - - tweak: Medals can be stored in wallets. - afirpo: - - bugfix: viruses weren't correctly cleaned up from the human-like mobs' bloodstream. - afterthought2: - - tweak: Door access has been substantially reworked. Please report any anomalies. -2019-02-26: - Piccione/Textor: - - rscadd: Adds new duty gloves for utility uniforms. They are available in some - lockers and via the uniform vendor. All gloves offer some protection, and engineering - gloves are also insulated. - SierraKomodo: - - bugfix: Officer's Mess doors will have the correct access flags again. - afterthought2: - - tweak: Arbitrary shuttles can no longer land at restricted landmarks. - xales: - - tweak: Adherent eyes have been upgraded. They no longer need a welding mask to - not go blind. As a side effect, they also cannot be flashed. -2019-02-27: - Chinsky: - - rscdel: Removes Medical Contractor job. It's merged into Physician/Corpsman, number - of slots for those bumped. GAS can join Corpsman only. - - rscadd: Physician and Corpsman jobs can now be joined with Contractor rank. - - rscadd: Engineering Contractor and Supply Assistant were merged into Engineer - and Deck Technician respectively, pick Civilian branch to join as contractor - SierraKomodo: - - maptweak: The Officer's Mess booze-o-mat is now accessible by officers. If you - can open the door, you can vend things. -2019-02-28: - SierraKomodo: - - bugfix: Senior Researcher now has standard sol gov crew access (Notably, access - to the bridge foyer and firing range), maintenance access, and Petrov security - checkpoint access. - - bugfix: Fixed access flags for bridge foyer, charon guppy and aquila airlocks, - communal brig, and supply office windoor. - - bugfix: Counselors can now access medical storage again - - bugfix: Bridge EVA storage windoors have the proper access restrictions again - mikomyazaki: - - bugfix: Swapped the names around on the D3 Ladders/Firing Range Hallway Cameras. - mikomyazaki2: - - bugfix: Removed duplicate items from B-Deck - Captain's Flask and Nanomed Vendor. - - rscadd: Geiger counter now makes a sound when radiation levels are high enough. - Volume increases with increased radiation level. - - soundadd: Added a geiger counter sound. - - bugfix: Fixes the case where the supply pack contents will be blank when ordering - live cargo. - - rscdel: MULE is no longer orderable, since it does not work on the Torch. -2019-03-01: - mikomyazaki2: - - rscadd: QOL Change - Adds an extra Supply & Denied Stamp to the Deck Tech lockers. -2019-03-02: - MistakeNot4892: - - tweak: Removing organs from a robotic bodypart (ie. FBP or IPC) will now use Devices - skill. - - tweak: A longstanding bug with amputated/severed limbs has been fixed and new - limbs will once again require reattachment with a hemostat after replacement. - - tweak: Surgery will now present a list of possible surgeries (if skilled enough) - rather than using a priority system. - SierraKomodo: - - tweak: Renamed NSV Petrov area tags to SRV Petrov. - - tweak: Soviet Cola has been renamed to TerraCola. - mikomyazaki2: - - bugfix: Corpsmen can use the Paramedic alt-title again. -2019-03-03: - Spookerton: - - tweak: Updated Workplace Liason and LPA job descriptions and access to match their - current role. - mikomyazaki2: - - bugfix: Game no longer assumes genders when self-examining as a neuter/plural. - - bugfix: IC Printers now take materials correctly when cloning. -2019-03-04: - Chinsky: - - rscadd: Examining things now shows message about it to people in 4 tile range. - If you don't wanna see it, you can disable it with a preference. - MistakeNot4892: - - tweak: Facial repair surgery is now a single step conducted with a hemostat after - making an incision. - - tweak: Skull repair is now identical to regular bone repair. - mikomyazaki: - - bugfix: Extends the restriction on some types of prosthetics to cover the entire - set of human subspecies instead of just human-basic. - sabiram: - - tweak: Adherents can no longer slip if they're floating. - - rscadd: Added two new colours to the adherent colour selection. - - tweak: The job slot formerly known as Corpsman is now Medical Technician by default, - with the former name as an alt-title. - - tweak: The job slot formerly known as Corpsman Trainee is now Trainee Medical - Technician by default, with the former name as an alt-title. -2019-03-05: - Crystalnole: - - bugfix: Securing microwaves gives the right securing verbs - Spookerton: - - tweak: Bridge officer lockers are harder to get into. - afterthought2: - - bugfix: Surgery is again possible. - - tweak: Makes cryo bags much more expensive in the protolathe, and require higher - tech levels. - mikomyazaki: - - bugfix: Fixes an error introduced through resolving a merge conflict incorrectly - with my earlier prosthetics restrictions PR. - sabiram: - - maptweak: The second deck hallway leading from the stairwell and elevators to - the engineering foyer has been reconstructed in the style of the typical hallways - on the ship. - - rscdel: Engineering duty gloves are no longer insulated. -2019-03-06: - CrystalNole: - - bugfix: Fixes invisible Cyborg materials - mikomyazaki: - - bugfix: Fixes an issue where full fire extinguishers would report an incorrect - message when you tried to fill them further. -2019-03-07: - Higgin: - - rscadd: Added a moderately weak TTV to the traitor uplink. 40 TC cost. - MistakeNot4892: - - tweak: Species who can eat mobs or items will now get an action button to puke - it back up. - - rscdel: Removed Regurgitate verb in favour of above. - SierraKomodo: - - bugfix: Security lobby door is now accessible by Sol Gov crew - - bugfix: Bridge safe room is now all-access - - bugfix: Merchant shuttle doors and windoors now require merchant access - - maptweak: Bridge access hallways now have their own area tags - Bridge Port Access - Hallway and Bridge Starboard Access Hallway - Textor: - - bugfix: You are able to construct glass and material airlocks again. - - bugfix: Airlocks that have their control circuits removed will remember their - paint jobs after the circuit is re-inserted. - - tweak: Atmospheric tanks now hold more CO2, H2, and O2 in the tanks due to increased - usage on board. - - maptweak: Camera networks have been adjusted to reflect reality. The lounge is - now located in the deck 4 camera network, as is the pathfinder's office camera. - The deck 1 fore hallway cameras have been renamed to reflect their location - better. The Adherent room now has a camera. - - maptweak: Adds deck 5 signage and warning signs to the escape pod launch areas - on deck 4, in addition to more escape pod direction signs to make sure confused - passengers know where to go to find pods on decks 2 and 4, and the deck 2 stairwell - is now more well-lit. - - maptweak: The R-UST now has an atmos control console in the control room so engineers - can adjust the injector port for gas. Don't forget to refresh the input. - - maptweak: New emergency shutters have been added to deck 4 to limit the decompression - caused by escape pod launch procedures. - - maptweak: At the direction of the Expeditionary Command Fire Marshal, there are - now more fire closets on board the Torch. - - maptweak: All the nacelles now have phoron windows installed on half-walls to - conform with the aesthetic on the rest of the ship. - - rscadd: After evaluating flaws in evacuation procedures, all escape pod outer - hatches now have a manual bolt override that can be manipulated with a wrench - after opening the cover in the event that the power is offline. As a reminder, - the outer hatch must be closed and the bolts re-engaged before the pod will - launch. - - tweak: Code Delta announcement no longer specifically mentions self destruct due - to rare cases in which it is engaged without the destruct mechanism being online. - Code Delta procedures have not changed. - mikomyazaki: - - rscadd: Adds Cultural Exchange patch to xenowear loadout for EC Unathi, Skrell - and IPCs. - - imageadd: Adds images for the Cultural Exchange patch. -2019-03-08: - SierraKomodo: - - maptweak: Antag shuttles, merchant shuttle, and admin shuttles are now shielded - against rad and ion storms. -2019-03-09: - MistakeNot4892: - - rscadd: Adamantine golem extracts now contain crystalizing agent. - - rscadd: Crystalizing agent can be used to produce resin globules that work like - medpacks for adherent and golems. - - tweak: Golems can now be operated on by substituting a surgical drill for a scalpel, - and resin packs for bone gel/fixovein/medpacks/cautery. - - tweak: Vox are now capable of gaining nutrition from wood pulp, napalm, glue and - various other inedible reagents. - - tweak: Vox are now capable of gaining nutrition from various materials and processing - others into a usable form with their stomach. - - tweak: Vox now require a hindtongue to speak Vox-Pidgin. - afirpo: - - rscadd: now it is possible to export virus dishes to earn credits (supply points). - - bugfix: now Toxicity related to a virus dish (Incubator) works again. - - tweak: checking for virus dishes already exported in the past or not analyzed - at all (those MUST NOT be exported!). - afterthought2: - - tweak: The IC printer can now take any materials as inputs. - - bugfix: Circuits properly init their steel cost now; this means that some are - much more expensive than previously. - - tweak: 'The TP circuit now costs more and rarer materials, and has a very high - complexity: you''re going to need the medium assembly or larger to house it.' - - tweak: The TP circuit will not function properly if the slaved computer is on - a z level not connected to its location. - mikomyazaki: - - bugfix: Fixes an issue with prosthetics selection for IPCs due to previous changes - for allowed_bodytypes on prosthetics. - - bugfix: Condiment containers can no longer be stored inside food. -2019-03-10: - Anticept: - - tweak: Atmos pumps have all had their power limits increased considerably. This - means atmospherics will operate faster, but at the cost of much more power at - peak performance. In addition, vents and scrubbers will operate faster when - stressed, but they too will cause a tremendous power spike in a ship wide atmos - contamination emergency where a huge number of scrubbers have to work hard (from - a badly clogged waste line, for example). A flooded deck can also overload a - deck substation, so bypass switching may be required in such cases. Beware of - extreme scrubber overload! - - tweak: Filter pressure limits raised to 15,000 kpa. They are still not powerful - devices when pumping from low to high pressures. You should put pumps around - them if you intend them to work quickly with moving pressures in a non-passive - manner. - FTangSteve: - - maptweak: deck 2 hallway by janitorial now dimmer and with no cameras - SierraKomodo: - - bugfix: Medical is now restricted access again. - SierraKomodo & Anticept: - - tweak: Flight manifest input box no longer shows the rank to make it easier to - find personel in the list. The report itself will show the rank. - afterthought2: - - bugfix: Disassembling research machines should now work. Upgrading circuit printers - should be more consistent. - sabiram: - - tweak: Most castes of giant spider will generally do more damage, and may have - more health. -2019-03-11: - SierraKomodo: - - tweak: You can no longer use headsets while sedated or sleepy-penned due to paralysis - making you unable to use your hands. - afirpo: - - bugfix: now the Core Sampler (Xenoarcheologist and perhaps Anomalist related) - works again - the sample is spitted out from its sample \ evidence bag. - afterthought2: - - rscadd: Adds the proxy command to terminals. This lets you obfuscate your nid - by routing through another computer. Requires access_network and experienced - skill. Generates local logs on the machine you route through, stored as a file - on the hard drive. -2019-03-12: - SierraKomodo: - - maptweak: Added fire shutters to the cargo warehouse shutters - Spookerton: - - bugfix: Inappropriate crew and passengers no longer have supply program admin - rights. - afterthought2: - - tweak: Petrov and research access can now only be granted by the XO and CO. You - can now build/adjust access on Petrov doors. - mikomyazaki: - - bugfix: Booze-o-mat contained a tea master item rather than actual actual tea. - Made it contain black tea instead. - - tweak: Robotics R&D consoles can no longer link with destructive analyzers. - - tweak: Made the Geiger Counter sound falloff and range larger. -2019-03-13: - Devildabeast: - - rscadd: After numerous flight tests and simulations, Adherents have begun to receive - piloting licenses and can now serve aboard the SEV Torch as Shuttle Pilots. - sabiram: - - maptweak: The firing range on deck 3 has been removed due to consistently causing - crashes. -2019-03-14: - Datraen: - - rscadd: Adds the Xilvuxix, a Multi-Z Shuttle capable of overmap travel and it's - own shuttle (capable of overmap travel as well) - Higgin: - - tweak: Traitor TTVs now share power with merc TTVs. They were underwhelming for - 40 TC cost. - SierraKomodo: - - bugfix: Windoors will now ignore walls when determining autoset access. This should - fix hardsuit windoors. - afterthought2: - - tweak: Unathi brute mod for the subspecies has been decreased a lot. - - tweak: Unathi healing can only be toggled once every two minutes. It cannot be - toggled within a minute of being hit in combat. - - tweak: Unathi limb and organ regeneration is only possible when the heal can be - toggled. - - tweak: When an unathi is at extreme levels of hunger, it no longer receives healing - from the passive heal ability. Instead, it takes internal organ damage, converting - it into nutrition. This is inefficient, so if the healing ability is left on, - it will die quickly. - - tweak: Unathi passive healing is less nutrition-efficient now. -2019-03-15: - SierraKomodo: - - tweak: Prone mobs can no longer buckle other mobs to beds/chairs. This prevents - crawling bucklespam during combat. - mikomyazaki: - - bugfix: Changes pin to an in-type pin on the reagent storage circuits. - - bugfix: Disassembling sleepers with an occupant will now eject the occupant. -2019-03-16: - Chinsky: - - rscadd: Coffins are made with steel now. Can still make wooden one with wood if - needed. - Datraen: - - bugfix: Fixes prosthetics not being selected by subspecies. - SierraKomodo: - - maptweak: The Deck Chief's office now has a guest pass terminal. -2019-03-17: - MistakeNot4892: - - rscdel: The flying pizza sprites are no longer available to crew robot modules. - - rscadd: A flying robot frame can now be constructed as an alternative to standard - robot. It uses the same arms, chest and head as the regular robot, but needs - the 'flyer' frame. - - rscadd: Flying robot frames produce flying robots, which use the flying pizza - sprites and can pass over tables. They have a selection of unique modules to - pick from and are generally faster but more fragile. -2019-03-18: - SierraKomodo: - - bugfix: Chairs and stools now have the correct materials when constructed and - deconstructed. - sabiram: - - rscadd: Added bamboo seeds to the vendors. Their produce can be chopped up into - wood. - - tweak: You can place wrenches onto tables if you're on help intent. Use harm intent - if you want to disassemble them. - - tweak: Halved the number of seeds stored in machines from 30 of each type to 15. - Use the seed extractor if you need more. -2019-03-20: - MistakeNot4892: - - rscadd: Added a humanoid species for the Vox Armalis, representing a larger, slower - voxform. It is not currently accessible outside of adminbus. - - rscdel: Removed armalis simple_animal and icon. - - tweak: Vox now have their own damage masks, blood masks and damage overlays. - - tweak: Vox wizard spell will now transform into a lesser version of the giant - space parrot. - sabiram: - - bugfix: Fixes IPCs becoming blind after being revived in surgery. - - bugfix: IPCs are no longer immune to sources of eye damage such as flashes and - welders. - zaredman: - - imageadd: Adds OCIE logo to be drawn onto official paperwork. -2019-03-21: - Hubblenaut: - - maptweak: Adds binoculars, prybar and a station bounced radio to the CoS Office. - RyanSmake: - - bugfix: Touching anomalies now works properly. -2019-03-22: - Devildabeast: - - tweak: Large mobs and bigger can no longer enter exosuits. - Hubblenaut: - - maptweak: Removes the disposal bin from the brig. - SierraKomodo: - - tweak: Synaptizine now overdoses at 5u instead of 30u. - sabiram: - - bugfix: Fixes issues with assigning and deleting accesses to mechs. -2019-03-23: - Devildabeast: - - rscdel: Due to numerous concessions to mental health procedure and human rights - complaints, the Sol Central Government will no longer stock straight jackets - on-board their vessels. - SierraKomodo: - - tweak: Characters that have ghosted (NOT aghosted) will be immediately flushed - when placed into cryo. - Spookerton: - - tweak: Viruses no longer infinitely increase the duration of effects like deafness - and drowsiness. - sabiram: - - tweak: Butchering simple animals now relies on your cooking skill, requires a - butcher's cleaver, and must be done on a table. - - tweak: Added cleavers to the dinnerware vendors. - - rscadd: Wood rendered from the produce of the bamboo plant will now be the bamboo - material. - - balance: Blobs will now spread and attack diagonally. - - balance: Blob attacks now take into account armour. - - tweak: Blob attack damage now depends on the individual blob segment attacking - you. The core defends itself the most vigorously. - - tweak: Blobs now attack with a random damage type. - - rscadd: You can now attempt to remove a sample from blobs by attacking it with - wire cutters. The regular blobs produce fairly powerful weapons in various damage - types, and the nuclei produce cores which can be disassembled for research points. - - tweak: Cigarettes and the like can now be lit by more hot objects such as plasma - cutters, and some tendrils snipped from the blob. -2019-03-24: - Spookerton: - - bugfix: Robot organs in meat bodies can be repaired with nanopaste in surgery. -2019-03-25: - Datraen: - - bugfix: Fixed Skrell Recon channel; Skrell ship holopad, spawns not operating - properly. - - bugfix: Filled the first-aid kits on the Skrell ship by making them the proper - subtype. - - maptweak: Fixed thrust, external access, and rearranged some parts of the Skrellian - vessel. - - tweak: Changed Skrellian Suits to voidsuit subtypes, allows stacking of helmet/magboots - inside of it. - - tweak: Lowered slowdown on the skrellian rifle. - SierraKomodo: - - maptweak: Added carp spawn zones to Torch bridge deck, Bearcat, and Unishi for - overmap events. - - maptweak: Moved a Torch deck 2 carp spawn from outside the reactor area to avoid - carp spawning inside the shields. - - tweak: Deck Chiefs now have access to Exploration comms. - Spookerton: - - tweak: Traitor Binary Gas Bombs are weaker, but also cheaper. - sabiram: - - rscadd: Added folding knives, replacing boot knives. - - rscadd: Added two types of folding knife to the loadout. -2019-03-26: - MrKicker: - - tweak: Players can pull items across Z-Levels - SierraKomodo: - - maptweak: Various areas on the SEV Torch have been renamed to be more descriptive - of their purpose/location. - - tweak: Typing indicator bubbles no longer appear for hidden mobs (Cloaked or inside - objects such as lockers). Indicators after you say or emote still appear. - ajkrupka: - - bugfix: Fixed an oversight to make armbands and webbing hide when jumpsuits are - rolled down. - sabiram: - - rscadd: Screwdrivers, wirecutters and all types of pry bar now come in a variety - of new colours. - - balance: Reduced armour values for the breacher and heavy mercenary rigs. -2019-03-27: - mikomyazaki: - - rscdel: Removes fax machine from Pilot's Office. - - tweak: Merges plastic flaps and airtight plastic flaps into one item. Can change - airtight setting with screwdriver, deconstruct now with crowbar. Can now construct - airtight flaps. - sabiram: - - tweak: Added colour selection to the suit vest and waistcoat in the loadout. -2019-03-28: - Datraen: - - tweak: Changes renegade spawn list to allow for any bag to conceal a spawned weapon. - - bugfix: Gyrojet no longer drops casings, now accepts magazines properly. - SierraKomodo: - - maptweak: Unishi and Bearcat now have long-range holopads. - sabiram: - - tweak: Crawlers who are weakened (forced down) will crawl slower. Being confused - will now additionally reduce their crawl speed. - - tweak: You can no longer attack with harm intent while incapacitated. - - tweak: Being incapacitated in any way will drastically reduce your melee accuracy. -2019-03-29: - sabiram: - - tweak: All knives have been unified under one type. Please report any irregularities. - - rscadd: 'Added an additional folding knife to the loadout: ''tactical folding - knife''' - - rscdel: Butterfly knives and switchblades can no longer backstab, temporarily - at least. -2019-03-30: - SierraKomodo: - - tweak: Intercom sprites now reflect the on/off status of microphone and speaker - switches. -2019-04-01: - Chinsky: - - bugfix: Torch is now facing upper side of the map. - SierraKomodo: - - bugfix: Bluespace River away site no longer spawns with a teleporter beacon. -2019-04-02: - Atebite: - - bugfix: Fixed weapon firing mechanisms not being able to fire in cardinal directions - CSCMe: - - rscadd: Adds extracting a specific amount of slime cores as a departmental goal - for science - Loaf && Banditoz: - - rscadd: 'Added four flying robot modules: repair, cultivator, surveyor, and forensics.' - SierraKomodo: - - tweak: There can now be 3 bridge officers in a round. - - maptweak: Playable colony now has universal enzymes in the freezer - - tweak: Rogue maintenance drones now spawn in separate smaller groups instead of - one massive blob. Total number of drones spawned per event is unchanged. - Spookerton: - - bugfix: Being cured of a virus now correctly adds its antigens where appropriate. - afterthought2: - - tweak: Some tweaks have been made to job spawn code. Beware of any anomalies. - ghostsheet: - - rscadd: Prospector locker will now always spawn with a duffle bag - mikomyazaki: - - bugfix: Moves the engine ejection door controls inside the box with the eject - button. - sabiram: - - tweak: Admins will now be informed why antagonist autospawn fails, instead of - printing to debug logs. -2019-04-04: - Banditoz: - - tweak: Flying mobs are now immune to quicksand. - Higgin: - - tweak: Push-time now depends on the difference of CQC skill between the two parties. - - tweak: At equal skill levels, pushing has a very short duration. - - tweak: Grabbing a prone person is no longer automatically an upgraded grab unless - the victim is stunned, unconscious, or on help intent. - - tweak: CQC costs more. Check your skill loadouts! - - tweak: Increased global miss chances to head, feet, and legs. - - tweak: Additionally reduced knockdown chances. - - tweak: Made organ damage much less likely before ribs/skull are broken. - - tweak: Increased likelihood of organ damage after encasing bones are broken - - tweak: Increased damage to brain when dealt and probability of brain damage from - damage to the head. -2019-04-05: - Cakey: - - maptweak: Added wooden walls to some areas of the Torch. - - tweak: AI holopads have been renamed to holopads. - - tweak: Removed the long range holopad's Z-range. - Cronac: - - tweak: Adds egg cartons as an item the biogenerator can produce. - - bugfix: Adds missing biohoods to CSO locker. - Higgin: - - tweak: Chances of collapsing from limb damage can now be mitigated by walking - and moving along walls/other objects you could reasonably use to prop yourself - up. - - tweak: This mitigation only works if at least one of your legs fully works. - - tweak: Stools and beds are collapse-exempt. IPCs at funerals rejoice. - - tweak: The chance of collapsing when not doing these things to mitigate it is - now significantly higher to compensate. - Spookerton: - - tweak: Wallets can hold ribbons, armor tags, and patches. - - tweak: Ribbons, armor tags, and patches are now tiny instead of small. - afterthought2: - - admin: A new admin tool, Toggle Harddelete Queue, has been added to the Secrets - panel, under Debug. Do not use this unless you know what you're doing. - ghostsheet: - - rscadd: Carp shoal map hazard now works for overmap shuttles such as the Charon, - Aquila and Guppy. - - bugfix: Fire alarm can now be constructed properly -2019-04-06: - Banditoz: - - tweak: Flying mobs are now immune to lava. - Cronac: - - bugfix: Fixes morgue trays and cremation trays displaying above bodies and bodybags. - Spookerton: - - bugfix: Refilling a fire extinguisher from a tank no longer tells you the extinguisher - is full when the tank is empty. - WatermelonsEverywhere: - - rscadd: Added a spare explorer equipment crate to Supply. -2019-04-07: - Cakey: - - tweak: Increased explorer job slots from 3 to 5. - - tweak: Lowered prospector job slots from 4 to 2. - Higgin: - - tweak: Prevents material weapons from taking damage on parry except against other - material weapons. - - tweak: Increases material weapon health. - - tweak: Reduces crowbar and toolbox accuracy penalties. - - rscadd: Adds an inferior, expensive, steel machete to the autolathe. - afterthought2: - - tweak: Acids are generally weaker now. - ghostsheet: - - rscadd: Ore boxes can now be ordered in supply -2019-04-08: - Chinsky: - - tweak: Charon and Guppy now only need Basic skill for flying on overmap without - random turns. -2019-04-09: - ChaosAlpha: - - bugfix: Drones spawn with modules once again. - - bugfix: All robots/drones material synthesizers should be functional once again. - - bugfix: AI cores should once again be constructible. - - bugfix: Surveyor bioreactor doesn't runtime and actually gives a reasonable amount - of power now. - - tweak: Flying repair robot module comes with slightly nerfed synthesizers. - - tweak: When remote controlling a maintenance drone, the AI can now use its radio - as normal. - - tweak: Cultivator module comes with a robot harvester. - Cronac: - - bugfix: Targeted healing spells such as those used by wizards should now properly - heal synthetics. - - rscadd: Adds the ability to synthesize crystallizing agent via chemistry with - polytrinic acid, tungsten, and silicon (and a bit of heat). - - tweak: Rogue drones now leave cleanable corpses when killed. - - bugfix: Monkeys are no longer ripping out their augments and throwing them across - the room. - - tweak: Augments now show up on medical scanners and related admin scans. - SierraKomodo: - - bugfix: Glowing slime extracts now create light. - - bugfix: Lit flares now process fuel and shut off when out of fuel again. - mikomyazaki: - - rscadd: Upgrading a sleeper now reduces power requirements, unlocks new chemicals, - and increases pump rate. - - rscadd: Adds emag effects to sleeper. - xales: - - tweak: Antag selection now defaults to NONE. You may need to update your antag - prefs. - zaredman: - - maptweak: Moves Security's Deck 1 checkpoint to the old Research Checkpoint. Decommissions - old Deck 1 Checkpoint. Adds lockdown shutters by ladderwell. - - maptweak: Adds 2 prisoner lockers for Communal. Also changes newscasters in the - Brig to the SEC variant where appropriate. - - maptweak: SEC-VEND now has new stock. More cuffs, more evidence bags, and now - carries pepper spray and holowarrant projectors. -2019-04-10: - Unknown: - - rscadd: Added a verb to change lobby track playing - Play Different Lobby Track - in OOC tab. -2019-04-11: - BiscuitCookie: - - maptweak: Renamed the HoP Office Privacy Shutters to XO Office Privacy Shutters - - bugfix: Removed objects outside the ship that didn't belong there. - Cronac: - - bugfix: A damaged aorta can once again be repaired while the chest cavity is open. -2019-04-12: - Randall: - - maptweak: The Supply Office and Supply Warehouse shutters now require Supply access - from the outside. -2019-04-13: - Chinsky: - - rscadd: Added speed indication to helm console. Green means 'slow', red means - 'too fast'. - - rscadd: Pilotable shuttles now can pass through meteor fields safely. Keep at - green speed and you'll make it. Need Trained skill for Charon/Aquila and Basic - for GUP. At Master/Experienced can do this at normal speed too. - - tweak: Torch now accelerates roughly 2x slower - Cronac: - - bugfix: The Adherent mineral bath will no longer kill Adherent users by deleting - their tendril junction. - - tweak: The Adherent mineral bath now removed embedded objects like shrapnel, but - will not remove implants such as tracking implants etc. - MikoMyazaki: - - rscadd: Titanium and its ore Rutile are now available via mining, allowing repair - of shuttles and the ship exterior. - Spookerton: - - bugfix: Lava turfs no longer incorrectly reignite and burn you every process forever. - mikomyazaki: - - tweak: Time police fixed a couple of items that weren't adjusted when we travelled - back 300 years. - myazaki: - - bugfix: Corrects piloting skill description to reflect recent change to basic - training with Charon and GUP movement. - zaredman: - - tweak: Security Equipment supply order replaced with Master at Arms supply order. - - tweak: Auto-Compressor and Rescue Bags can now be ordered via Supply. -2019-04-14: - Aurum22: - - bugfix: Fixes various layering issues with stasis cages, honey extractors, and - reagent dispensers (chemistry and bar varieties). - Cronac: - - bugfix: Cryogenic tubes will no longer heal anything without containing a drug. - - tweak: Clonexadone and Cryoxadone have been buffed due to cryogenic tube changes. - - rscadd: Adds nanite fluid, which is like cryoxadone for robotic parts. It can - be made with cryoxadone, space lube, and aluminum chilled down to -25C. Requires - 5 phoron as a catalyst. This is NOT safe to use on its own and should be used - on conjunction with cryoxadone or clonexadone. - mikomyazaki: - - bugfix: Floor lights can now be dismantled with a wrench. -2019-04-15: - CarefulLilCassie: - - rscadd: Adds high heels. - - tweak: Changes some items in the civilian uniform vendor to match the military - ones and utilises some more categories for cleaner usage. -2019-04-17: - Atebite: - - rscadd: Three new random events have been added - - tweak: The T-ray scanner can now inspect disposal pipes for damage - Chinsky: - - maptweak: Charon laoyout changed, it now has a cargo bay that can be cycled to - outside air. - Crackers5: - - rscdel: Removes some existing body markings - - rscdel: Removes species restriction from tattoos - - rscadd: Splits up existing body markings/tattoos to be selectable per limb instead - of full body. - Roaper: - - rscdel: Removed old contraband poster that depicted a spess cat. Also commented - out it in the code. - mikomyazaki: - - bugfix: Smartfridge ID Scan hack now allows access. -2019-04-18: - mikomyazaki: - - bugfix: Allows setting stasis to x10 on sleepers. - zaredman: - - tweak: Medical max staff numbers decreased to a maximum of 2 Physicians, 3 Medics, - and 1 Trainee Medic. -2019-04-19: - GooeyChickenman: - - bugfix: Defibrillators no longer appear empty on spawn. - mikomyazaki: - - bugfix: Voice changer now works properly while using an active camouflage module. - xales: - - tweak: Adherent can now play as Prospector -2019-04-20: - Chinsky: - - rscadd: 'Most handheld scanners (plant, health, gas, mass spectrometer, reagent, - xenobio, price) now store last scan result. Click inhand to see it. tweak : - Mass spectrometers now can be used directly on open reagent containers or syringes - to take sample. Old behaviour is still supported too.' - - rscadd: 'Price scanners keep adding scan results instead of overwriting them. - You can clear buffer in scan result view window. tweak : Tweaked health analyzer - colorings a bit. Now not coloring things like section headers, coloring more - deviations from norm (blood oxygenation / pulse)' - Flying_loulou: - - tweak: Blood bags are now small if containing a reaggent, and tiny if empty. -2019-04-23: - Flying_loulou: - - rscadd: Adds a new command voidsuit type for bridge officers and the SEA. - - maptweak: Replaces the pilot voidsuit in the bridge EVA storage by the command - voidsuit. - GooeyChickenman: - - tweak: More common medicines and reagents will appear on medical scanners. - Higgin: - - rscadd: Cult members can now make stun talismans again. Requires a tome, paper, - and a substantial amount of blood. - - rscadd: Ported obscure and reveal runes back into cult. Obscure runes make all - runes around them invisible, reveal runes reveal them. Runes cannot be used - while invisible. -2019-04-24: - Datraen: - - bugfix: Ion Thrusters now respect on state and thrust modifier when calculating - thrust -2019-04-25: - Datraen: - - rscadd: Adds lighting, overlaying to energy melee weapons. - Draxtheros: - - rscadd: Robots will now announce via chatlog when they enter an emergency power - state. - FTangSteve: - - bugfix: ingested reagents are now handled properly - - tweak: pulse impacting reagents now have stronger effects when compounded - - tweak: stomach volume is now 65 units instead of 30 - - tweak: vomiting when stomach is overfull now based on chance, higher with the - more you're over the limit - GooeyChickenman: - - bugfix: Ryetalyn will now fix a characters appearance after resetting genes. - Hubblenaut: - - bugfix: Fixes syndicate ID cards not being examinable. - Lilja: - - bugfix: Fixed sheet materials stacking bug where icon wasn't updating. - - tweak: Recolored & adjusted all sheet material icons to have more contrast. - - rscadd: New aluminium sprite, new plastic sprite, new glass sprite, new reinforced - glass sprite, new diamond sprite, new wood sprite, new uranium sprite, new rod - sprites, new cable wire sprites, new deuterium and tritium sprites. - - rscadd: Sheet material stacks now change appearance when they have reached maximum - stack. - Randall: - - maptweak: The auxiliary sanitation closet now holds a spare mop. - Spookerton: - - tweak: Optical Meson Scanner glasses only protect from supermatter hallucinations - when turned on. - ghostsheet: - - rscadd: Hardsuit overlay icons will now change depending on what module is selected - - tweak: Hardsuit drill mount now functions like a normal drill, being able to mine - multiple tiles at once - - tweak: Hardsuit drill mount energy usage has increase to a non insignificant amount - - rscadd: Mounted plasma cutter has a close range mode to enable object interaction - accessible by configuring - - bugfix: Selecting a hardsuit module now checks for energy and suit status - - bugfix: The energy blade projector can now fire darts again - - rscadd: Mounted plasma cutter now has a sprite - - rscadd: Mounted energy gun and Tazer now has a sprite - - rscadd: Mounted medical injector now has a sprite - - rscadd: Mounted grenade launchers now has a sprite - mikomyazaki: - - bugfix: Holocomms will no longer transmit speech before the call is accepted. -2019-04-26: - Randall: - - maptweak: The Auxiliary Warehouse shutter buttons now require Supply access from - the outside. - mikomyazaki: - - tweak: Allows changing a cryptographic sequencer's icon and name in a similar - way to chameleon items. -2019-05-03: - CarefulLilCassie: - - rscadd: Adds folding knives based on the Swiss Army Knives made by Victorinox - & adds them to lockers based on job as well as the loadout for a basic one. - ChaosAlpha: - - bugfix: Fix robots click-dragging things on catwalks. - - rscadd: Robots can now use the , and . hotkeys to move up and down z-levels in - hotkey-mode. - - rscadd: Everyone can now use > and < in non hotkey-mode to move up and down z-levels. - Chinsky: - - rscadd: New sprite for mining scanner, look for air analyzer-like thingie in miner - colors. - - tweak: Mining scanner now behaves like other scanners, storing last scans. To - use it click on a tile you want to scan. It will keep all scans unless buffer - is cleared. - - rscadd: Scanners now make sounds when used. - - rscadd: You can now make handrolled cigs out of any dried plants. - - tweak: Tobacco from cig vendomats can be put in pipes. - Flying_loulou: - - rscadd: Medical Technicians rejoice ! Following OHS inspections, EXCOM decided - to grant you a light polymer helmet, as in most of other EMS services throughout - human space. - - rscadd: Medical Technicians rejoice ! EXCOM also issues you a 'medical technician - chest rig', to help you carry your equipment without being forced to sweat in - a jacket. - - tweak: Medical personnel rejoice ! your paramedic and EMS jackets have been modified, - and now allow you to store a blood bag on the suit storage slot. - - maptweak: The MT chest rig and the EMS helmet are now available in the medical - technician's lockers. - - maptweak: Due to budget cuts, EXCOM had to sell the labcoat from the MTs lockers, - in order to aquire the new equipment. Therefore, you will no longer find labcoats - in the MT lockers. - Higgin: - - tweak: Tactical armor plates now offer extra resistance against brute and bullet - damage over regular medium plates. - - admin: Adminhelps not taken or closed in five minutes automatically close with - a reminder to the owner. - - tweak: Being stunned, weakened, or paralyzed now all prevent radio use. - - tweak: Getting hit can apply a very brief cooldown before you can use your radio - - guaranteed for stun weapons, projectiles, and powerful melee weapons. - - tweak: Pepperspray no longer automatically stuns/weakens targets without mouth/nose - protection. - - tweak: Pepperspray briefly confuses targets without eye protection. - - tweak: Pepperspray has a 50/50 chance to stun targets without full mouth/nose - protection. - - tweak: Partial mouth/nose protection (masks, bandanas) reduces pepperspray stun - chance. - - tweak: Pepperspray weakens stunned targets without full face protection. - - tweak: Buffs pepperspray gas pain damage and adds a chance of stun to gas effects. - Hubblenaut: - - rscadd: Adds a new chameleon headset to the chameleon kit. - - rscadd: Adds three new chameleon accessories to the chameleon kit. - - bugfix: Fixes chameleon items having broken sprites. - Randall: - - tweak: The advanced mop now synthesizes space cleaner instead of water. - RyanSmake: - - bugfix: The Torch is now a valid target for the BSA (for BSAs not on the Torch). - SierraKomodo: - - bugfix: Deck 1 security checkpoint shutters work as intended now. (Actually fixed - this time). - Spookerton: - - tweak: Secure guns are slightly more informative about registration changes and - have shorter ranged interaction logging. - - tweak: Welding tools are now all just one pocket-sized item with swappable tanks. - Tanks change the size of the tool when attached. - - tweak: Emergency toolboxes now also contain a welder with a tiny fuel tank. - - admin: Admin narrations can be styled. SubtleMessage is part of DirrectNarrate. - Moderators get limited DirectNarrate with a SubtleMessage style. - mikomyazaki: - - rscadd: Cooking supply pack now has a bottle of universal enzyme. -2019-05-08: - ChaosAlpha: - - bugfix: New < and > keybinds are now CTRL+. and CTRL+ in non hotkey-mode, to circumvent - a byond limitation. You will need to update your skin. - sabiram: - - rscadd: 'Added several new human languages: Yangyu, a Chinese language (key 2); - New Dehlavi, a Hindustani language (key 3); Prototype Standard Arabic, an Arabic - language (key 4); and Iberian, a Spanish-Portugese language (key 5).' - - tweak: Changed the way human culture defines assign language. Please double-check - your loadout. - - tweak: Sol Common's syllable list has been adjusted. - - tweak: Renamed 'Independent' to Pan-Slavic. - - tweak: The language keys of several languages have changed. Xenophage (4 to L); - Borer (x to z); Vox (5 to x) - - rscdel: Removed 'Lunar' and 'Spacer' languages. -2019-05-12: - Chinsky: - - rscadd: Adds jars of medical lollipops (holding 15u of a random common medicine) - to infirmary lobby and CMO office - - rscadd: Can now scan overmap things with sensor console. By default just shows - site description. - - rscadd: For ships, shows heading and speed, if ship is moving. - - rscadd: For planets output depends on Science skill - atmosphere / plantlife / - wildlife presence (Basic), number of non-natural ruins (Trained), compoisition - / temp / pressure of atmosphere (Expert). - Novacat: - - tweak: Fixes a UI bug with the modular computer downloader and antag programs - Spookerton: - - tweak: Arterial bleeding is now much more obvious to the bleeder. - mikomyazaki: - - bugfix: You now need to wear hardsuit gloves/boots to have a complete airtight - seal when wearing a RIG. -2019-05-13: - Cakey and Marie Taylor: - - imageadd: Adds directional sprites for vending machines, smartfridges, watercoolers, - drying racks and medivendors. Sprites by Marie Taylor. -2019-05-14: - Chinsky: - - tweak: Shuttles now display their fuel in Delta-V rather than pressure gauge. - They also show Delta-V used per move, so you can actually gauge how many jumps - you have left on your fuel. - Devildabeast: - - rscadd: IPCs can now select kicking and stomping as their default unarmed attack. - SierraKomodo: - - bugfix: Energy guns no longer become invisible if cell charge exceeds cell capacity - due to adminbus. - - bugfix: Spacer now has a text color again. It's dark-yellow. -2019-05-15: - ChaosAlpha: - - bugfix: Robots can once again build windows using their synthesizers. - Eckles: - - rscadd: Adds new Skrell factions and home systems. - SierraKomodo: - - bugfix: Being incapacitated no longer affects talking and radio use if the radio's - microphone is set to on. - - bugfix: Talking normally with a nearby radio set to on will no longer trigger - aim-mode shooting. - afterthought2: - - tweak: Movement delay handling from items has been tweaked slightly to give more - fine-grained effects. -2019-05-16: - Chinsky: - - tweak: Helm console layout changed, mostly to prevent sector descriptions shifting - movement keys down at WRONG FUCKIGN MOMENT. - - rscadd: Added acceleration limiter to helm console. Hard value vs engine thruster's - percentage. Doesn't affect fuel usage, use engine limiters for that. - ghostsheet: - - tweak: Hardsuit ore scanner module can now print survey data disk. - - tweak: Hardsuit mounted drill now has an increased energy cost of 2Wh per use. -2019-05-17: - Montykore: - - imageadd: Atmos canister icons and canister details revamped and updated. -2019-05-18: - Chittersky: - - tweak: If you are wearing a voidsuit, spiders now need to breach it before injecting - poison. On other hand, spiders now can breach voidsuits. - - tweak: Spider venom's toxin damage is now slightly weaker, but can cause confusion. - Montykore: - - imageadd: Updated and revamped corgi related icons. - SierraKomodo: - - bugfix: Deck 1 security checkpoint windoors have the correct access flags now. - babydoll: - - tweak: Simple animals' speed prying doors open now depends on the door. - ghostsheet: - - rscadd: 'Plasma cutters can now cut through the following: bulkhead walls, floor - platings, girders, catwalks, windows, low wall frames and lattices.' - - rscadd: Plasma cutters will now spark and require eye protection when interacting - with object. - - tweak: Mounted plasma cutter has an increased object interaction energy cost, - 10 Wh per use. - - bugfix: Drills will now have a delay and sound when drilling through girders. -2019-05-19: - Chinsky: - - rscadd: Added 'Known Implants' field to medical record, that gets auto-filled - with roundstart robotic organs - - rscadd: Added buddy tags to explorer lockers. These can be worn as an accessory, - and will start pinging every half a minute or so if they don't detect another - tag with the same ID in 10 tile range. They can be clicked in hand to set ID - and toggle on/off. - SierraKomodo: - - tweak: Helm and navigation consoles now show 'gigameters/hour' for speed and acceleration. -2019-05-20: - Albens: - - maptweak: Bridge Deck has undergone a refit. -2019-05-23: - Devildabeast: - - tweak: The Roboticist and Biomechanical Engineer have had their access adjusted - to better reflect their respective departments, and the Roboticist can now access - the Engineering Locker Room and front desk, but has had Tech Storage access - removed (which was unusable anyway). - - rscdel: The Roboticist's headset has been removed; the Roboticist and Biomechanical - Engineer now spawn with their respective department's headset. - - tweak: The Roboticist is now Trained in EVA and exosuit operation by default. - - maptweak: The Engineering Locker Room's material reserves have been locked behind - windoors in order to prevent certain nerds from thieving. - - maptweak: Robotics now gets two loaded toolbelts and multitools instead of one, - as well as two pairs of insulated gloves. - SierraKomodo: - - maptweak: Various map tweaks to Aquila to fix clickable sprites being under other - sprites and other mapping nonsense. - - maptweak: The Charon power compartment has a camera again. - ghostsheet: - - rscadd: Medical drop pouch and Medical webbing is now available on the loadout - to medical trainee, chemist and biomech. -2019-05-24: - SierraKomodo: - - bugfix: 7mm haywire ammo boxes now contain the correct ammo. - - bugfix: Flying borgs are no longer capable of having infinite VTEC modules installed. -2019-05-25: - Flying_loulou: - - rscadd: The EC now issues branch berets to their personnel, to denote which section - they're from (available in the loadout, hats and headgear section). - - rscadd: Following extensive training the personnel of the Torch is now able to - clip their helmets on their plate carrier's suit storage slot. - - rscadd: Following even more extensive training the medical technicians can now - clip their EMT helmet on their MT Chest-rig's suit storage slot. - SierraKomodo: - - tweak: Flying borg speed has been reduced one level. Flying borg default speed - is now the same as a regular borg with a VTEC module. Flying borgs with a VTEC - module will be as fast as the old default flying borg speed. - - rscadd: Pill bottles can now be printed at autolathes - afterthought2: - - tweak: The pilot qualification pin is now restricted to Fleet and EC. -2019-05-26: - Chinsky: - - tweak: Spacesuits etc now have maximum pressures they can handle. You can check - their codex entry to see it. - babydoll: - - rscadd: You can now permanently disable radio/teleporter beacons with an emag - or EMP attack. Any connected teleporters will also lose their connection. - - rscadd: Anchored underfloor beacons can be repaired with nanopaste. Handheld or - portable beacons are unrecoverable and must be replaced. -2019-05-27: - BearKingKrug: - - tweak: Clicking on borgs/drones on harm intent with a welder/crowbar actually - attacks them now - ChaosAlpha: - - bugfix: In non hotkey-mode, move-up/down have been moved to CTRL+Numpad_Add/Numpad_Substract - to fix issues with some keyboard layouts. - Chinsky: - - tweak: NTIRC client no longer spawns by default, freeing up some space on PDAs - and such. - - tweak: Reports editor now spawns on Cargo and Command PDAs by default. - Flying_loulou: - - tweak: Security coveralls are now also available for all fleet security personnel - (via the uniform vendor, under utility extra). - - tweak: Changes the firesuit sprite for a new one, based on TG's. - - tweak: Lowered the firesuit slowdown to 0.6 (voidsuits' slowdown is at 1). - - rscadd: Based on TG's sprites, adds the firefighter helmet, and the chief firefighter - helmet (for the CE). You don't need to wear a mask while wearing it, and it - does connect to internals (you still have to toggle them on, of course). - - maptweak: Adds said helmet in the fire closets, to replace the already existing - red hardhat. - - maptweak: Adds fire closets throughout the ship. - - maptweak: Adds fire closets in the Charon and the Aquila. - NewOriginalSchwann: - - tweak: Fatigues have been added to the Fleet pilot's uniform vendor under utility. - SierraKomodo: - - maptweak: 'The bridge deck has received some minor tweaks and fixes. See https://github.com/Baystation12/Baystation12/pull/25628 - for details. Notable changes below:' - - maptweak: CMO's office fax machine no longer blocks access to part of the table - - maptweak: Meeting room now has a fire alarm - - maptweak: Additional cameras were added to CO's office and aft hallway to fix - blindspots - - maptweak: Fire doors were added to doors and windoors that were missing them - - maptweak: PPE closet access flags now match the sidearm closet - - rscadd: Shield generator and shield generator monitor UI now includes a capacity - percentage. - - maptweak: The lift now has firedoors. - - rscadd: Flying borgs now have light-weight armor, providing half the armor value - of a regular borg's armor. Light-weight armor can be printed from fabricators - for half the cost of regular armor, and can also be applied to regular borgs - (Not that you'd ever want to do this.) -2019-05-28: - AlexMorgan3817/_Elar_: - - bugfix: Now device can't be its own proxy. - BearKingKrug: - - spellcheck: Fixed AI intro text to not mention being a traitor - Cakey: - - rscadd: EC service and dress under-uniforms have been replaced with service jumpers, - with complimentary departmental colouring. - - rscadd: EC senior officers (captain and above) now have a unique service cap. - ghostsheet: - - tweak: Overmap Fast speed is now reduced from 20 to 15, this applies to dodging - meteors in shuttles at experienced/master levels. - - tweak: Gas thrusters for overmap travel, will now calculate thrust and fuel consumption - by volume. Lower volume limit from the engine control for more fuel efficiency. - - tweak: Guppy's mass and max speed has been increased. - - maptweak: Charon's atmospheric and electric compartment has be reworked to accommodate - for the fuel consumption. - - maptweak: There are now shuttle navpoints on the hanger deck. -2019-05-31: - EcklesFire: - - rscdel: Removed inappropriate boots from Fleet EMT. - ghostsheet: - - rscadd: Vey-Med has generously donated two prototype hardsuit defibrillator modules - to be used on the torch mission. - - rscadd: Hardsuit defibrillator module has been added to the rescue rig and the - CMO hardsuit. - - tweak: Hardsuit health scanner can now display their reading like the ore scanner. -2019-06-01: - Orelbon: - - rscadd: Adds NanoUI interface to suit storage units. - SierraKomodo: - - rscdel: Vat-grown blanks have been removed from the SRV Petrov. - babydoll: - - tweak: Many objects that were previously rotatable with a verb are now rotated - using alt-click. Any such object will report in examine that it can be rotated. - - tweak: You can now rotate vending machines with alt-click. - ghostsheet: - - maptweak: The Aquila's engine room has been updated, most notably it now has a - fuel pump for easy refuelling. -2019-06-02: - Atebite: - - rscadd: 'New integrated circuit components have been added:' - - rscadd: Reagent funnels - Allows you to use reagent containers such as beakers - on the assembly to refill internal reagent storages - - rscadd: Reagent heaters/coolers - Heats/cools contained reagents, similar to heater/cooler - pads - - rscadd: Anchoring bolts - Anchors the assembly so that it cannot be moved - - rscadd: Hatch locks - Prevents opening the assembly with screwdrivers while enabled - Spookerton: - - rscdel: Resleevers and neural laces no longer exist. - babydoll: - - rscadd: Blobs will now additionally attempt to attack a random nearby tile, even - if they aren't expanding to that tile. The core nucleus itself is particularly - aggressive. - - tweak: Material coins are no longer effective weapons. - ghostsheet: - - rscadd: Plasma cutter can now deconstruct closet. - - tweak: Hardsuit chemical dispenser now has inaprovaline instead of tricordrazine. - - tweak: Rescue rig can now have auto-compressor hooked on the suit storage slot. - - tweak: Ninja's chemical dispenser now has dermaline instead of radium, no more - radioactive super powers today. - - bugfix: Hardsuit module item will no longer be put into bags or closets. -2019-06-03: - SierraKomodo: - - tweak: You know longer magically know an emag is an emag because of your complex - devices skill. - Spookerton: - - tweak: Hearing your current default language skips adding the language identity - to the log. - - tweak: You no longer grunt as if you have no languages if you have any language - you can speak. - - tweak: Team outsider special roles are given an appropriate team language. - - bugfix: Legalese is enabled in the dme again. Derp. - - rscdel: GalCom no longer exists. - - tweak: Everyone on the Torch and Verne except stowaways and merchants are given - ZAC on spawn. - - tweak: Non-Torch jobs do not give a language on spawn unless you spawn with no - languages, in which case you get Spacer. - - tweak: The maximum number of preferences-selectable languages is 3 instead of - 4 due to other changes. - - tweak: Sinta Unathi speak Sinta. Yeosa Unathi speak Yeosa. Having the other language - is optional for both. - - rscadd: Selenian exists. It is a dialect of ZAC (high cross-understanding), not - money-speak. It is the language of selenians, and optional for residents of - luna. - - bugfix: Having no languages at all prevents you from speaking in raw text that - everyone understands. - - tweak: Chimpanzee is renamed Primitive. Subtypes of Primitive no longer exist. -2019-06-04: - WezYo: - - bugfix: Ghosts can no longer close antag pda program -2019-06-05: - Cakey: - - tweak: You can now rotate in chairs when buckled to them by clicking once again. - SolarK: - - tweak: Slowdown penalties based on cold now affected by species discomfort levels - babydoll: - - tweak: All types of blob will now launch bonus attacks less often overall, and - will attack more or less often depending on their type. - - rscadd: Added the 'ravaging mass', which forms an offensive line around the shield - blob spawned by the cores. This type attacks most often and most potently of - all the blob types. - - tweak: The base type (which makes up the bulk of the blob) formerly known as 'ravaging - mass' is now 'pulsating mass', and has had its maximum damage potential reduced. - - tweak: Reduced damage potential of the shielding mass. Increased hit points. - - tweak: Mecha are now valid targets for the blob's bonus attacks. -2019-06-06: - Cakey: - - rscadd: Added a new on-ship ambience sound, for that in-flight pressurised cabin - feel. - Devildabeast: - - rscadd: Adds a nine-pointed star icon to the list of potential bible choices. -2019-06-07: - WezYo: - - bugfix: resetting a flying drone will no longer make it invisible -2019-06-11: - Spookerton: - - tweak: Radio messages no longer show language identifiers if the language is the - same as your default. -2019-06-12: - Chinsky: - - tweak: Doors to the catwalk overlooking Hangar are no longer access-locked. - Devildabeast: - - rscadd: Adds urns which can contain, move, and release ashes, and can be constructed - from different materials. The Counselor gets a wooden urn in their locker on - round start. - Kamiztheman: - - tweak: Item descriptions in the traitor uplink menus have been adjusted so that - new recruits actually understand what they are buying. - - tweak: EMP ammo boxes purchased from the uplink should now have enough ammo to - refill a magazine. - - bugfix: 7mm EMP ammo boxes now contain and can store the correct caliber rounds. - MistakeNot4892: - - tweak: Status indicators on the UI have had a makeover. - - rscadd: You can now click status indicators to get an idea of how things are in - your current state. - Spookerton: - - tweak: The brig no longer contains prison camp clothes because it's not one. - - tweak: The brig officer gets a multitool for locking guests' sensors on. - - tweak: You can lock and unlock suit sensors through the stripping menu with a - multitool. - WezYo: - - bugfix: Attacking with swiss knives properly displays attack verb - ghostsheet: - - rscadd: Hardsuit interface now has internal tank controls. - - tweak: Hardsuit interface has been updated. Fresh coat of paint to keep it looking - good. - - bugfix: Tank "reset" button now works properly, resetting tank release pressure - to its original value. -2019-06-13: - Draxtheros: - - tweak: Raised the temperature at which Unathi begin to receive "warmth" messages. - Spookerton: - - tweak: IPCs cannot be OCIE agents. -2019-06-14: - MistakeNot4892: - - rscadd: Adds thirst. It's like hunger. - Spookerton: - - tweak: Changing species with the changer re-adds languages required by the user's - antagonist type. -2019-06-15: - Cakey: - - maptweak: 'adjusted the bridge deck slightly:' - - maptweak: straightened the outer hallways to be more convenient - - maptweak: reorganised the meeting room to use its space better - - maptweak: matched wood types accross all offices - - maptweak: gave an extra console to the side-islands in the bridge - - maptweak: reshuffled COS and CE office contents, added disposal chutes - - maptweak: brought outer hallway decals in line with door marking standard - afterthought2: - - bugfix: SMES inverted logic fixed; should now work with terminals properly. - - bugfix: APCs now charge from empty properly again. - - bugfix: Heaters/coolers/protolathe/circuit printer work again. - babydoll: - - bugfix: Fixed mirrors not opening their menu. - - rscadd: Added yew wood, and its planks to the supply menu. - - tweak: Adjusted mahogany and walnut wood colours. - - bugfix: Corrected mahogany and maple plank loadout info. - ghostsheet: - - maptweak: Deck three toilets now doesn't suffocate people anymore. - - tweak: Hardsuit modules can now be deselected by pressing select again. - - tweak: Hardsuit plasma cutter automatically do object interaction if they're adjacent. - They will now also always fire on harm intent. - - tweak: Hardsuit flash module now flashes on unarmed attacks. - - tweak: Hardsuit flash module now has has a function to activate the flash without - targeting anything. - - tweak: Hardsuit flash now has a higher energy cost of 10 Whr per use. -2019-06-16: - Devildabeast: - - rscadd: "Adds the Bah\xE1'\xED Faith to the list of selectable human religions." - - tweak: Suit sensors can now be set by alt-clicking your uniform. - MistakeNot4892: - - tweak: Humans can now leap/tackle at a small distance based on their Athletics - skill. - - tweak: Leaping and tackling (Vox and Xenophage powers) are now invoked by attempting - to make a ranged grab - if it's not a mob you'll just hurl yourself in that - direction like an idiot. They have had timing values tweaked and require a short - channel before use. - - tweak: The various outcomes for leaping/tackling have been made dependant on skill - levels in Athletics and Combat. Check the PR for specific values. - - tweak: Split the Chaplain and the Counselor into two separate roles. Chaplain - was moved to Service and lost Medical access. - - rscadd: Replaced the defunct Sec checkpoint near the Chapel with the Counselor's - Office, it's where t'Counselor lives. - - tweak: Moved the Psychiatrist and Psychologist alt titles to the Counselor. - Spookerton: - - bugfix: Species toxins modifiers are used again, and modify internal organ damage - taken from toxins and organ failure. - - bugfix: Lava no longer deletes human and human derived mobs early when braindead. - afterthought2: - - bugfix: Borg chargers once again spawn with the cell installed. - - bugfix: Vents starting as off are fixed. -2019-06-17: - SierraKomodo: - - tweak: Brig Officer is now known as Brig Chief. - afterthought2: - - bugfix: SMES sizes and starting charge should now be back to normal. - - bugfix: Pressure regulators should once again be interactable. - babydoll: - - rscadd: Added a system to rarely spawn larger, more dangerous fauna on exoplanets. - - rscadd: A giant crab, peaceful until provoked, can now spawn on desert exoplanets. - ghostsheet: - - tweak: Plasma cutter now uses up half a charge per deconstruction. - - bugfix: Deconstruction of walls and girders now gives the appropriate materials. -2019-06-18: - MistakeNot4892: - - tweak: Dionaea can stand in water to recover thirst, and lose hydration slower - than others. - - tweak: Going prone on water turfs will now drown you. -2019-06-19: - SierraKomodo: - - tweak: Airlock control boards now have 'Autoset Access' enabled by default. -2019-06-20: - Heptagon49: - - bugfix: Fixed variables so powercells aren't duped when inserted into the coilgun. - - bugfix: Fixed coilgun examination so that it works now. - Kamiztheman: - - rscadd: Adherents aboard the Torch have finally found their crystalline toolboxes, - and have loaded their vending machine with them as an alternative to the harness. - MistakeNot4892: - - tweak: You now use grab intent only to perform a tackle/leap. - - tweak: Running off a ledge with a leap prepared (using Prepare To Maneuver) will - automatically try to jump to the next closest non-open turf. - - tweak: Mobs will now behave more like objects when thrown - they will pass tables/rails - and collide with obstacles. - SierraKomodo: - - rscadd: AI can now jump to people talking near an active holopad. - Spookerton: - - tweak: Improvised cuffs break if resisted out of a few times. - - tweak: Cuffs and improvised cuffs can now be attached to most shoes, hobbling - them. Improvised cuffs break if the wearer moves enough. - - tweak: Knives can be stored in more kinds of shoe. - afterthought2: - - tweak: Kitchen cookers, microwaves, gibbers, and seed/honey extractors are now - buildable. -2019-06-21: - Alex6511: - - tweak: Meteor now requires 15 players - Textor: - - rscadd: Adds gas sensor, air injectors, digital 3-way valves, and gutters to pipe - dispenser - - rscdel: Removes non-omni versions of filters and mixers from the game. - - rscadd: Pipe dispensers UI is updated. Pipe dispensers can now dispense normal - pipes with paint already applied to them and dispense 1, 5, or 10 pipes at a - time. - - rscadd: Atmospheric control console UI updated. You may now directly input values - instead of using plus and minus buttons. - - rscadd: Pressure tanks can now be built with steel sheets, and deconstructed. - - rscadd: Vent pumps and injectors can now have their configuration changed using - a multitool. - - tweak: Due to fuel pipes having different tolerances, they are no longer compatible - with normal pipes and need a universal adapter to connect two networks together. - - maptweak: Removes all non-omni filters and mixers from all maps and replaces them - with omni versions. - afterthought2: - - tweak: Washing machines are now buildable. - - tweak: Portable pumps, scrubbers, huge scrubbers, and hydroponics trays are now - buildable using circuitboards. -2019-06-22: - Unknown: - - tweak: The Mend psi-power now scales in effectiveness to your rank, and is available - at lower ranks. - - tweak: Autoredaction is now less buggy in regards to fixing bleeding, and somewhat - less spammy when healing you. - - tweak: Coercion now has Mind Read as a power. It prompts someone with a question - that they are compelled to answer - RP tool only. - - tweak: Blindstrike now has a visible tell when used. - - tweak: Spasm, Agony and Blindstrike have been shuffled around within the Coercive - tree. - - tweak: Latent psionics will no longer be aware they are latent psionics. - - tweak: The Probe power is now called Assay and has been moved to operant-rank. - - tweak: Made some roundstart announcements bigger/easier to read. - babydoll: - - maptweak: Moved the chapel down to deck 3, south of the holodeck. - - maptweak: Remapped the mental health section of the infirmary. - - rscadd: Added pews for the chapel. - - rscadd: Added pews to the material construction menu. They can only face south! -2019-06-23: - MikoMyazaki: - - rscadd: Traitor robots always get their emag items. - - rscadd: Cultivator drone now has an emag item, an energy machete. - - bugfix: Restores Petrov access to the Access Decrypter antagonist program. - MistakeNot4892: - - tweak: The config options RUN_SPEED and WALK_SPEED are now more accurately named - RUN_DELAY and WALK_DELAY. Default values have been adjusted to match the previous - behavior. - - rscadd: Stamina now exists. You will recover stamina fastest while well fed and - lying down, but will recover it slowly so long as you aren't actively sprinting. - Stamina recovery can be tweaked in config. - - tweak: Running will now consume stamina. Costs can be tweaked in the config. If - you run out of stamina, you will not be able to run again until it refills. - - rscadd: You can now hold shift to sprint, and release it to walk. You can set - default walk/sprint options with Set Default Walk and Set Default Run. - - tweak: The Counselor is now mildly psionic, and is a registered affiliate of the - Cuchulain Foundation for RP purposes. They have some tat in their office relating - to psionics more generally. This is hopefully going to be a way to make psionics - more broadly known ingame - see Discord/PR/other discussions if interested. - - rscdel: Removed Psychiatrist. - - tweak: Psychologist is now a Passenger alt title. - afterthought2: - - tweak: Machine interaction has been reworked further. Be ready for some issues. - - tweak: You may now install and remove machine components by hand on (some) machines - you can build from circuits. To do this, first open the panel with the screwdriver - (you may need to make sure the machine is off or other conditions are met). - Then either insert a component by clicking on the machine with it, or use a - wrench on the machine to remove the component. - babydoll: - - rscadd: Added the disorientator, a short-ranged beam weapon with effects similar - to a flash. - - rscadd: Added the disorientator to core department head closets and RnD. -2019-06-24: - Alex6511: - - balance: The meteor gamemode is now significantly more powerful. - MikoMyazaki: - - bugfix: Spells granted by The Tower deity no longer require robes to cast. - - tweak: Adds an exit button to the Deity punishment menu incase you open it accidentally. - - rscdel: Removes some stamps that shouldn't exist. (Warden, HoP, HoS, etc.) - - imagedel: Removes some now unused stamp icons. - - tweak: RIG stamp module now does the normal stamp instead of the Internal Affairs - stamp. - - tweak: Centcomm stamp (used on admin faxes) now uses the map specific boss name - for the stamp. - - bugfix: Prevents putting polytool augment tools in your pocket, behind your ear, - etc. - - tweak: RIGs will now warn you if you make them malfunction while offline, requiring - nanopaste to repair. - Mistakenot4892: - - rscadd: Added a slower version of walk, Creep intent. - NobleCaos: - - tweak: Diona Nascent Gestalts can now katamari up items as well as nymphs based - on the amount of nymphs in the gestalt - SierraKomodo: - - maptweak: Filters in atmospherics no longer connect to the wrong pipes. - - maptweak: The Corporate Liaison's office now has a gun recharger for the LPA's - sidearm. - - tweak: LPA and CL lockers now spawn with spare headsets, including bowmans. - afterthought2: - - bugfix: SMES panel opening, shieldgen deconstruction, and door autoclose have - been fixed. - - tweak: You can rotate disposals pipes now. - - tweak: Flipping disposals pipes moves them to the mirrored state (unlike rotating - twice). - - tweak: Dragging disposals pipes no longer rotates them. - - bugfix: various issues with disposals construction have been addressed. -2019-06-25: - ghostsheet: - - bugfix: Shuttle thruster now block air and fire; shuttles are more fireproof and - less gas contamination should occur. - - tweak: Shuttle engine heater, are now climbable. - - maptweak: Medical bathroom now has a mirror, for all your post radiation treatment - needs. - - maptweak: Charon atmospheric compartment has been returned to its previous state. - - maptweak: Hanger fuel bay now has a high power pump, to reduce prep time. -2019-06-26: - Cakey: - - tweak: Grass, carpets, and dirt have new icons. - - rscadd: A new system has been put in place for floor detailing, allowing for pre-made - edges. -2019-06-27: - MikoMyazaki: - - bugfix: Can no longer drag people off of something they are buckled into (e.g. - roller bed) onto an op table without unbuckling. - MistakeNot4892: - - rscdel: Removed xenophage and all adjacent code. - - tweak: You now need to hold CTRL to do a leap. - SolarK: - - tweak: Added damage limit applied by vacuum. - babydoll: - - rscadd: Swarms of enormous leeches can now spawn on shrouded exoplanets collectively - as megafauna. - - rscadd: Soap now comes in a few different shapes, sizes and colours. - - rscadd: Cleaning someone with soap will now attempt to transfer some of the soap's - reagents to that person. -2019-06-28: - MikoMyazaki: - - rscadd: Adds a chemistry recipes book to the chemist's locker that lists the medication - recipes. - Novacat: - - rscadd: Adds the dufflebag of holding, a cosmetic reskin of the Bag of Holding. - - tweak: Fixes some onhand sprites for dufflebags. - Roland410: - - maptweak: Moved the CE's suit to the bridge EVA storage. - - maptweak: Made the conference room a tad bit bigger and moved items around, gave - it a request console. - - maptweak: Removed one console on each side of the bridge and added tables instead, - gave another emergency toolbox, donut box, coffee mug, and a shortwave. - - maptweak: Gave the CL a box of cigars, bronze zippo, union card box, and made - the backroom properly boltable by the button. - - maptweak: Added disposals to the CL office. - - maptweak: Shuffled around the contents of the CE's office. - - maptweak: Gave the CO a Torch ship model. -2019-06-29: - .verarch: - - tweak: lizard horns should no longer obscure eyes. - - tweak: work gloves should fit unathi somewhat better now. - Cakey: - - rscadd: Adds pixel offsets to all mobs to give the game more feel for depth. - - rscadd: Gives all mobs a drop shadow. - afterthought2: - - admin: More things should show up in admin logs now. -2019-07-01: - MistakeNot4892: - - tweak: Vox jobs (scav and stowaway) now have soft antagonist status. - Spookerton: - - bugfix: Microwaves don't eject their components. - - tweak: dismantling a microwave empties it first. -2019-07-02: - Cajoes: - - tweak: modified adherent tool vendor to look modified - - tweak: changed adherent tool vendors vend animation from "tool_vend" to "tool-vend" -2019-07-04: - MikoMyazaki: - - maptweak: Officer's Mess is now all access. - Spookerton: - - bugfix: microwaves properly remove their ingredients after cooking. -2019-07-05: - Cajoes: - - tweak: Lava lamps have been optimized. - MistakeNot4892: - - tweak: Borers now use Dominate via ranged disarm attack and Infest via melee grab - attack. - - tweak: Language on borer messages is now more neutral. - - tweak: Borer powers now largely have UI buttons. - - tweak: Psionics can see auras around borers when they aren't inside hosts. - - tweak: Borer Dominate is now properly psionic, and respects psi-null atoms and - psi armour (ie. Coercion ranks). - - rscadd: Added neutered borers. Adminspawn only, basically defanged peaceborers. - - tweak: Significant backend refactor for borers, please report borer bugs. - afterthought2: - - rscadd: Robots now get skills set according to their module choice. - babydoll: - - tweak: Bog-standard parrots will now retaliate briefly when attacked. - - tweak: The space parrot occupying its temple in the asteroid will now retaliate - with force when attacked. Beware! - - rscadd: A giant parrot can now spawn as the grass planet's megafauna. - babydoll, Xhuis & Sunner: - - rscadd: Added the hivemind, a megafauna spawn for settled exoplanets. Beware its - attacks and strike when it's vulnerable. -2019-07-06: - Devildabeast: - - rscadd: Inscriptions can now be carved into material (gold, steel, silver, etc) - rings using sharp objects. - MikoMyazaki: - - tweak: Antagonist implants are now not visible to the bodyscanner, you can find - them by opening the implanted bodypart and examining. - afterthought2: - - tweak: If a machine is hackable, you'll now only get shown the wires panel; to - see the usual interface close the hacking hatch with a screwdriver again. -2019-07-07: - Devildabeast: - - tweak: 'Counselor now gets different psionic faculties by alternate title: Redaction - for Counselor and Coercion for Mentalist.' - - rscadd: Focus has been added as an Operant Coercive ability; grab a target while - target the mouth, then use the grab on them on disarm intent to cure the target - of various mental ailments. Power scales by rank. - - tweak: Spasm is now a Master ability rather than Operant. -2019-07-08: - Devildabeast: - - rscadd: Dog tags can now be added to the commemorative plaque to memorialize members - of the Expeditionary Corps. - afterthought2: - - tweak: The emergency supplies crate is cheaper but has no armored vests now. - mikomyazaki: - - bugfix: Clonexadone and Cryoxadone no longer reduce damage on necrotic organs. -2019-07-09: - mikomyazaki: - - tweak: RUST manual now links to the wiki guide (and doesn't teach you to blow - up the RUST) -2019-07-10: - afterthought2: - - rscadd: Machines now require power components to draw power. These can be printed - from the autolathe. The tesla link one is the default one to use. - - rscadd: Many machines now require screens and keyboards to be fully interactable. - You can print them from the autolathe. - - rscadd: To install components, open the panel with a screwdriver (after the machine - is built) and click on the machine with the component. To remove components, - use the wrench while the panel is open. - - tweak: 'Computer construction has been changed. A screen and keyboard is required - now. The order is: make a frame, wrench to anchor the frame, add 5 coils, add - the circuit, add all components as prompted, screwdriver to build. To deconstruct, - crowbar to remove components, wirecutters to cut the wire, unwrench, and apply - welder.' - - tweak: General machinery follows the same construction steps as computers now. - - rscadd: Computers now have panels, like other machines. To deconstruct a computer, - use a screwdriver to open the panel and then a crowbar to deconstruct. - - tweak: Newly built machines have the panel open. - - rscadd: If confused about this, examine the machine while standing next to it - to get information about which tools to use on it. - mikomyazaki: - - bugfix: Can now properly construct multi-tile glass airlocks. -2019-07-11: - afterthought2: - - rscadd: Shuttle consoles are now buildable. Use a multitool on the circuit while - on a shuttle to set the shuttle first! Shuttles are still not buildable; you - must do this on an existing shuttle. - mikomyazaki: - - bugfix: pAIs no longer have to fold up twice to become a card. - - bugfix: pAIs with the Universal Translator module can now speak and understand - Spacer and Gutter. - - bugfix: Mend psychic power now works properly on operant level to fix bleeding. - zaredman: - - maptweak: Adds an Interview Room to the Brig. Adjusts nearby rooms to fit. -2019-07-12: - Cajoes: - - rscadd: food in steel cans and support for canned items, added to cargo - - rscadd: Added pistachios to snix vendor - - rscadd: Added Sol Snacks vending machine. (And ethnic sol foods to go with it) - - Vendor by Chinsky - - rscadd: Added japenese snacks to the snix machine and changed it to its own vendor - with some label tweaks please welcome the painfully ethnic "Yummy Fods" vending - machine. Available in cargo - - tweak: Snix machine now more slavic in design - - rscadd: Added deoderant to lavatory essentials - - rscadd: Added chessboard to game vendor - - rscadd: Added numerous vendors to the Cargo Supply Form - mikomyazaki: - - bugfix: Printing from the file manager program now prints visible paper. - - tweak: Adds basic medical and trained chemistry skills to the Service Module. - Gives the Service Module the full selection of booze and soft drink dispenser - drinks. Significantly reduces power requirement of the drink dispenser tool. - - bugfix: Autopilot will now accelerate correctly. - - tweak: The psiblade can now hit robots instead of trying to cut their wires like - a wirecutter. - sick trigger: - - maptweak: Added tinted windows and a light switch to the chapel. - zaredman: - - maptweak: Fixed some map oversights following the Security interview room addition - (like the wall blocking the door to the FT's lab). - - maptweak: Added laundry pods to the Medical washroom. -2019-07-13: - mikomyazaki: - - tweak: Machines will now have a hint if you have forgotten to install a tesla - link. - - rscadd: Robco vendor will now vend tesla links and keyboards for building machinery. -2019-07-14: - Devildabeast: - - tweak: Makes the machete sheath its own selection under loadout; removes it from - the list of holster selections. - - rscadd: The Chaplain's bible now has "blessings;" as a Chaplain, use your bible - (or holy book) on another character to recite a prayer to them, or use the book - in your hand to read a passage to everyone nearby. If you are of the same religion, - they will receive a message putting them at ease. - sick trigger: - - maptweak: Skrell ship air alarms set to a higher, more appropriate temperature. -2019-07-15: - afterthought2: - - admin: You can now ban, jobban, and view notes on logged out mobs. This will act - on the last ckey to have possessed the mob. - babydoll: - - maptweak: Replaced all-in-one grinders in cooking areas with idiot proof juicers. - These cannot hurt your hands. - - maptweak: Replaced all-in-one grinders in laboratory areas with industrial grinders. - These can hurt your hands. - mikomyazaki: - - rscadd: Conveyor Belt and Switch assemblies can be created from the autolathe. - Use the switch on the conveyor belt to link before placing, crowbar to remove - both. -2019-07-16: - MikoMyazaki: - - imageadd: New MMI icons with damage states by Joeynosegay. - - tweak: FBPs no longer get brute/burn mod bonuses from their human subspecies. - - rscadd: Prosthetic organ fabricator can now print replacement FBP power cell organs. -2019-07-18: - Devildabeast: - - rscadd: Adds colorable beanies and rastacaps to the loadout. - babydoll: - - rscadd: The zeq queen megafauna can now spawn on chlorinated exoplanets. -2019-07-20: - Boznar: - - maptweak: Adjusted fire locks on deck one and three for better mobility and logic. - Devildabeast: - - rscadd: Adds several Chaplain religious insignia to the loadout, representing - various faiths. - - rscadd: Adds Sikhism to the list of human religions. - - rscadd: Adds several preset religious books to the loadout. - - rscadd: Adds Shinto to the list of human religions. - Funce: - - bugfix: Bad Chefs no longer make runtimes with the juicer. - Rain7x: - - tweak: Increased the chances of the mail event; and of its rare gifts spawning - SierraKomodo: - - bugfix: Masks can now properly hide ear and eye slot items if configured to do - so. - WezYo: - - bugfix: renaming paper no longer runtimes - YodaDoge: - - bugfix: Farmbot can now harvest plants and remove dead plants, again. - afterthought2: - - tweak: Adding capacitors to a machine buffs the battery backup's charge rate. - - tweak: Borg chargers recharge faster now. - - bugfix: Toggling APC power manually with exotic mapped apcs should work properly - now. - ghostsheet: - - maptweak: Hanger Atmospheric Storage room has been added to the hanger. This replaces - the unused refinery slot near the fore of the charon. - - bugfix: Restore button pressing sprites to their previous states. - - bugfix: Cell charger will now work in Z-level transition, and they now have proper - sprite charge bar. - - rscadd: Cells now have a red charge state which is below 25% charge. - - tweak: Suit cyclers repair function is now default for all suit cyclers. - - bugfix: Duct tape space suit repairs now works properly while suits are being - worn. - - rscadd: Mining drill head now indicate how full they are. - - tweak: Mining drill head logic change slightly to be more informative. - - tweak: EVA airlock on deck 3 now has all its access set to ACCESS_EVA. So anyone - who can enter the room can use the airlock. - mikomyazaki: - - tweak: Can no longer adjust your Chameleon Item's appearance while restrained - or disabled. - - maptweak: Toxins lab now has a button for its blast doors, labels for its pumps, - chamber now has a gas sensor, and more lighting. - - tweak: Can no longer do surgery through thick clothing, suits, RIGs, etc. You - will need to remove the clothing before you can make incisions. - - bugfix: Female characters will now be able to use the roll down and roll sleeves - verbs without their jumpsuits disappearing. -2019-07-21: - SierraKomodo: - - tweak: Blob resistance values have been tweaked. Cores are now weak to fire and - laser, and strong to brute, like green blob. - - tweak: Blob shielding mass regeneration rate has been very slightly reduced. -2019-07-22: - MikoMyazaki: - - rscadd: Adds Vecuronium Bromide, a paralytic drug. - afterthought2: - - rscadd: Vending machines are now constructable using circuits, and also can be - deconstructed. Drag the container they drop to another vendor of the same type - to restock it. - - tweak: To add things back to vending machines, you now must be on help intent - (useful for tool machines). - zaredman: - - maptweak: Moved and remodeled Investigations Office, Forensics Lab, and Evidence - Storage. - - maptweak: Slight adjustments to Brig Chief's office to better accommodate the - redesigned processing room. -2019-07-23: - CrimsonShrike: - - rscadd: Exosuits have been completely refactored. Make sure to check your skills - before joining the round. - - rscadd: You can now slide ID across a PAI to grant them your access. - Devildabeast: - - rscadd: Adds a unique holosign to the Chapel airlock. - - rscadd: Adds Jainism and Taoism to the list of human religions. - - rscadd: Adds two new chaplain insignia for Jainism and Taoism. - Eonoc: - - tweak: Tweaks Vox codex entry - - rscadd: Add Vox shriek audible emote - afterthought2: - - tweak: Manually toggling apc settings will no longer raise alarms. Also applies - to some mapped APCs. - ghostsheet: - - tweak: Electron reservoir will now shock you upon bumping/getting thrown into - it. - mikomyazaki: - - tweak: Supermatter manual will now show you the wiki page for the Supermatter - Engine. - - bugfix: Underwear will now no longer be kept on species change, if the species - you are changing into cannot wear underwear. -2019-07-24: - Chinsky: - - tweak: Earmuffs now actually muffle sounds. You'll also not hear spoken things. - - rscadd: Headphones can actually play music now. Drag onto yourself when worn in - ear slot to access menu. They act as earmuffs when music is playing. - mikomyazaki: - - bugfix: IV Bag construction option name changed from 'plastic bag' to 'plastic - IV bag' so it is different from the other 'plastic bag'. -2019-07-25: - WezYo: - - tweak: Aiming point blank at someone will actually aim at them now - YodaDoge: - - tweak: Order Ranks of Jobs ascending so the lowest rank is selected by default - afterthought2: - - rscadd: An overmap-capable shuttle can now catch/grapple another overmap-capable - shuttle currently moving on the overmap. You do this by moving to an appropriate - landmark on the shuttle console. - - rscadd: If a shuttle is grappling another shuttle, it cannot move on the overmap; - it will be moved by the other shuttle. - - rscadd: If a shuttle is being grappled by another shuttle, it cannot make shuttle - jumps until the grappler has left. - - tweak: Ships within ships count towards vessel mass now, meaning you'll accelerate - slower with them landed/attached. - - tweak: All greentext for antag objectives and game modes has been removed. - babydoll: - - tweak: All hivebots now have increased health. - - tweak: Increased hivebot megafauna 'hivemind' damage output. - - tweak: Reduced hivemind vulnerability duration. - - tweak: Reduced hivemind cycle duration. -2019-07-27: - zaredman: - - maptweak: The larger portion of the Security Armory is now Equipment Storage. - Security Staff now have access to this room. -2019-07-29: - Chinsky: - - rscadd: Added a medical health checkup to Reports program for all you thirsty - doctors - CrimsonShrike: - - rscadd: Exosuits can now be repaired without using a recharger using either a - welding tool or cable coil depending on damage. - Devildabeast: - - rscadd: Adds Hephaestus Titan, a bulky full-body prosthetic, and Morpheus Atlantis, - a skeletal head prosthetic, to chargen. - Eonoc: - - bugfix: Fixes the Vox spacesuit light overlay from a grey hat, to just nothingness, - since I didn't feel up to making new sprites for it, and most of the suits have - glowy-looking bits anyway. - Rain7x: - - tweak: Makes the "boot selection" in loadout available to civilians only. - Spookerton: - - tweak: Prosthetic limbs previously named Grayson are now named Shellguard. - mikomyazaki: - - tweak: Unathi brains will now not accept being MMI'd. - - tweak: Unathi may no longer have prosthetic internal organs attached. - - tweak: Unathi may not start the round as FBPs. - - tweak: Unathi may no longer select assisted or synthetic internal organs on round-start. - - maptweak: Vox ship burn chamber now operates properly (fixes incorrect injector - settings) - - maptweak: Vox ship burn chamber can no longer cause the ship to self-destruct - due to temperature melting the windows, since they have been replaced with walls - that handle up to 12,000K. - - maptweak: Adds a temperature/gas sensor to the burn chamber. - - maptweak: Vox ship ignition switch now isn't hidden under a light. -2019-07-30: - Rain7x: - - tweak: Medical & Engineering trainees can now select their department specific - webbing & drop pouches; and medical trainees now have access to their department - armbands. - mikomyazaki: - - tweak: Senior Engineer now gets access_network, allowing them to use the NTNet - Diagnostics and Monitoring program and various command line tools. - - tweak: Access hacking antag program can now hack access_network, if the antag - has master level IT skill. - - tweak: The NTNet Quantum Relay in telecomms will now keep physical logs of network - activity, wiping the NTNet Diagnostics Program logs will not affect these, and - they cannot be accessed remotely. The portable drive can be removed via a UI - eject button and the data imported from it into a modular computer. - - maptweak: Telecomms storage room now has a couple of spare portable hard disks. -2019-07-31: - Devildabeast: - - rscadd: Adds colorable bracelets to the loadout. - WezYo: - - bugfix: Requesting pAI personalities works now -2019-08-01: - BlueNexus: - - rscdel: The Security cyborg module has been disabled. - afterthought2: - - bugfix: Chloral hydrate is once again effective; this applies to sleepy pens. - babydoll: - - rscadd: Added the antlion and antlion queen to desert exoplanets. - - tweak: Moved the giant crab megafauna to snow exoplanets. - mikomyazaki: - - bugfix: Nacelle control switches in the engineering monitoring room will now work. - - bugfix: Fixes issue that prevented organ transplants. -2019-08-02: - CrimsonShrike: - - rscadd: Added 2 new exosuit propulsions. The quadlegs and the armored tracks. - - tweak: Speed tweaks to exosuit legs. - Noble Caos: - - rscadd: Allows nascents gestalts to add human-sized mobs when the gestalt contains - 20 nymphs. - babydoll: - - tweak: Renamed all tasers in their various forms to electrolaser. - zaredman: - - tweak: Re-adds the Torch variant of the Sec-Tech and actually stocks it with more - gear. -2019-08-03: - Boznar: - - maptweak: Nacelles now have air alarms, fire alarms, and fire doors. - Nirnael: - - bugfix: Fixes bug in using a new apc frame on a broken apc to repair it. - Rain7x: - - tweak: Tweaks the event announcement messages to be more tone-neutral & standardizes - the announcement header - WezYo: - - tweak: Attaching a photo to a newscaster story will no longer remove it from your - hand - afterthought2: - - tweak: The shield generator has been reworked. It is now much more expensive to - keep the shields on continuously, and for large shields it's likely not viable. - - rscadd: The shield generator now has an idle and active state (as well as the - off state). In the idle state, it consumes limited power and does not generate - a shield. In the active state, it consumes a lot of power and produces a shield. - - rscadd: If an idle generator is toggled on, it takes a short amount of time to - spin up to active state. If an active generator is toggled to idle, it will - switch to that state instantly. - - rscadd: There are several levels of idle power usage that can be selected. Higher - power usage decreases the spin-up time proportionately. - - rscadd: The shield generator takes time to adjust the radius of the shield. The - radius will not be adjusted while the shield is active. - - tweak: The shield generator's power storage has been vastly expanded. - - tweak: The shield generator's field integrity is now tracked separately from the - power storage (it's determined by the amount of power stored, up to a threshold). - mikomyazaki: - - tweak: Radiation collectors are now capped at 500kW output at 250Bq radiation. - They are more efficient at lower radiation levels. - - tweak: Radiation collectors will have variable fuel usage, capping out at 250Bq - radiation. Fuel usage increased significantly (1-10x depending on radiation - levels) - - tweak: Radiation collectors will now break from high radiation levels (500Bq) - as well as temperature, they will display a warning and play a warning sound. - - maptweak: Stowaways can no longer spawn in the incinerator room, which they cannot - leave. - - bugfix: Fixes inconsistent icon names for female jumpsuit icons. Should work for - rolling down / roll sleeves for all jumpsuits/suits now. -2019-08-04: - Bxil: - - tweak: Inflatables now have 1 second delay. - Chinsky: - - rscadd: Adds 'Codex' verb that shows user the 'frontpage' of codex, with links - to search / index / categories. - Eonoc: - - rscadd: Adds a Vox RIG. Same statline as the Industrial RIG, but with full temperature - and radiation resistance. Vox had no way to scavenge radioactive or volcanic - planets up until now. - - rscadd: Adds flux cannon. Essentially a Vox AEG, but with the lasers doing brute - damage, and shock mode replaced by a mode that scatters low damage pellets in - a burst. - - rscadd: Adds sonic cannon. A vox stun rifle, with a mode that uses up all the - gun's charge to push, deafen, and dizzy an opponent. Ear protection such as - helmets and earmuffs will negate the deafening, and reduce the dizziness. - - rscadd: Added the associated projectile types for both above, obviously. - - rscadd: Added two new firing sounds, spike.ogg and eLuger.ogg - - tweak: Changes spike launcher firing sound to spike.ogg - - tweak: Stealth buff to Armalis to make their large size reflected more mechanically. - - tweak: Changes the Vox species check on Vox guns to make the guns hiss and jump - out of your hands. - WezYo: - - rscadd: CSO now has maint access - - rscdel: Removed the discard verb from playing cards - - rscadd: Added the ability to pick a card by clicking it with an open hand - comma: - - tweak: Blunt yet sufficiently strong weapons can now pop inflatables - mikomyazaki: - - bugfix: Yeosa unathi have correct job restrictions now. -2019-08-05: - mikomyazaki: - - tweak: Resisting will auto-cancel resting. -2019-08-07: - BlueNexus: - - tweak: All non-total radiation resistance values for suits etc have been halved. - - tweak: The Supermatter, nuclear reactor, R-UST, PACMANs and other radiation sources - which were too weak to be relevant have been buffed. - - tweak: Radiation sources that were deemed to be too strong have been nerfed, such - as garbage planets. - - tweak: Grilles have had most of their radiation resistance removed. - - tweak: Low walls and windows have had their rad resistance halved, so they add - up to a full 100% instead of 200%. - MistakeNot4892: - - rscadd: Added a more involved butchery system. - - rscdel: Removed stowaway. - mikomyazaki: - - maptweak: Double sets of windoors now have only the interior windoor at department - reception desks. - - bugfix: Low wall frames deconstruct into 3 steel sheets, which is the amount required - to build them. - - maptweak: Robotics central windows are now not tintable, surgery area still is. - - tweak: Autoinjectors now have a timer for use on other people, instant for yourself - OR on incapacitated people with any skill level. They take a third the time - compared to a syringe. -2019-08-08: - Cajoes: - - maptweak: Reworked the abandoned shooting range space into additional lavatory - facilities and a sauna. - - rscadd: Adds a wooden bucket -2019-08-10: - Bxil: - - rscdel: The asteroid will no longer spawn at the Torch every round. - mikomyazaki: - - bugfix: Relocating limbs will now properly always work when you have high enough - medical skill. -2019-08-12: - Boznar: - - maptweak: Adds shutters to the exterior windows of hydroponics, aft bubble, and - lounge. - Chinsky: - - tweak: Medical Technicians can no longer have Anatomy skill at Experienced or - higher. - - tweak: Surgery skill reqs and penalties got beefed up. - - tweak: Most surgery step require both Trained Anatomy AND Expert Medicine. - - tweak: Delicate' surgery steps (basically inside organ stuff) require both Expert - Anatomy AND Expert Medicine. - - tweak: Penalties to success chance for missing skills were jacked up mercilessly. - Unless you're missing 2 or less skill levels you're not going to succeed, sorry - bud. - - tweak: Physicians now start with Expert Medicine, free skillpoint pool lowered - by its cost. - - tweak: Robotic steps require Trained Complex Devices. If there's meat bodyparts - involved (e.g. installing into one), need both Trained Complex Devices and Trained - Anatomy - - tweak: Slime surgery steps require Trained Science. - Piccione: - - tweak: Heads of Security are now are better screened to ensure loyalty to the - SCG - ghostsheet: - - tweak: Butterfly knife damage is now slightly lowered. Still pretty deadly. - mikomyazaki: - - bugfix: Airlock bolt buttons (e.g. SMES room and engine hatch doors) will now - work. -2019-08-13: - Terror4000rus: - - rscadd: You can take a pill from pillbottle by using it. - YodaDoge: - - tweak: reduced shield power usage - ghostsheet: - - tweak: Due to the space related mortality rate of our recent expedition, the EXO - has increased funding to restock EVA equipment. There are now 5 jetpacks and - 3 cooling units in EVA on deck 3. - mikomyazaki: - - bugfix: Resetting a tech you have no levels in at the RnD Server will no longer - give you 1 in that tech. - - rscdel: Removes Arcane Tech, as it did nothing. - - rscadd: Worn RIG suits will now be charged if you walk into a cyborg recharger. - If you have an internal cell (FBP/IPC) then that will charge first. - - bugfix: Airlock access buttons will now work even if the area they are in has - no power. - - rscadd: Traitor Robots will get a verb 'Reset Identity Codes' that will remove - their external camera connection, robot console connection and lawsync status. - - bugfix: Fire axes can now attack unpowered airlocks on harm intent, regardless - of the damage level of the door. - - tweak: It now takes several hits to get through an undamaged door with a fire - axe. -2019-08-14: - MistakeNot4892: - - rscadd: Added a new human subspecies, the boosters. - mikomyazaki: - - tweak: Illegal Tech is renamed to Esoteric Tech. Producing items with this tech - & having esoteric tech levels is not illegal, however possession of those items - may be if they appear on the contraband list. - - bugfix: Petrov RnD console will start the round able to access the Core RnD server - data and sync with the rest of the Torch. - - bugfix: Elevator will no longer get stuck when you give it multiple move orders - via the elevator panel or the buttons on each floor. It will wait for nine seconds - on each floor and then move to the next one in the list. - - rscadd: Surveyor Flying Robots now have an emag item, an energy machete. -2019-08-15: - Cajoes: - - tweak: Improved kitchen utensil visibility on grey surfaces. - babydoll: - - rscadd: The drake megafauna can now spawn on volcanic exoplanets. - mikomyazaki: - - rscadd: As the Torch now starts at random coordinates, the Torch round-start sensor - scan will list these coordinates so it is clear where the bearings point from, - incase you forget / join the round late. -2019-08-16: - mikomyazaki: - - bugfix: RnD server control consoles will only connect to things on connected Z-levels. - So the Torch won't pick up away-site RnD servers only the RnD server control - console. - - tweak: Robots can open the door control menu again, like AI. - - tweak: FBPs don't get affected by their species slowdown stat, positive or negative. - - tweak: Robotic eyes ignore your species flash modifier. - - tweak: Robotic eyes don't get species darkvision bonuses (e.g. from Space-Adapted - Humans) -2019-08-17: - ghostsheet: - - maptweak: Torch's fuel pipes have been slightly remapped into safer positions - with parts segmented by automatic shutoff valves to prevent leakage. The fuel - lines has also been removed completed from the SM heating element (although - the HE pipes are still there) and they should now be able to survive an SM delamination. - To balance out these safety features, fuel line pressure has been doubled to - increase the risk of bodily harm. - mikomyazaki: - - bugfix: Glasses that apply a vision overlay (mesons, tactical goggles, etc.) will - no longer function when you are using a sensor console to view the overmap. -2019-08-19: - Chinsky: - - tweak: Can no longer sample plants with machet. Need an edged weapon of size 'small' - or 'tiny'. Normal size and above will chop as usual now. Harm intent also forces - chopping instead of sampling. - - tweak: Can alt-click vines when holding normal-sized blade (machet) in hand to - chop them down. It'll take a short time, faster if you have Trained botany skill. - Basically less chat-spamming alternative to just bashing them down. - mikomyazaki: - - bugfix: Ghosts can't interact with space heaters anymore. - - bugfix: Stacks of one sheet will now not be deconstructable twice in the deconstructive - analyzer. -2019-08-20: - Devildabeast: - - bugfix: Mules will no longer spawn with psi-dampener implants. - MistakeNot4892: - - rscadd: Added a new human subspecies, the Mule. Mules can be merchants or submap - roles. - mikomyazaki: - - bugfix: Space vine event will now never have invisible vines. - - bugfix: Surveyor drone now has skills. -2019-08-22: - ghostsheet: - - rscadd: SMES chance to discharge is now skill based, with 50% increase at unskilled - and 50% decrease at master. - sunofang: - - maptweak: Revamps the yacht into a prettier state. -2019-08-23: - Boznar: - - maptweak: Adds large vents to both sides of the engine room. These can be opened - with a button in the emergency box in the control room. - - maptweak: Renamed all of the glass box emergency buttons and added descriptions. - - maptweak: Engine hatch bolt control button has been moved to the inside of the - engine room next to the hatches. - Cajoes: - - rscadd: Commissary now spawns with a vending machine. - - tweak: tweaked the sauna thermostat and auxiliary space heater to bring the room - up to a comfortable 348.15 kelvin. Which I am reasonably sure the human body - can tolerate. For a while. - MistakeNot4892: - - rscadd: Enhanced an opossum. - mikomyazaki: - - bugfix: Adherents now properly get their speed bonus again. -2019-08-24: - Anticept: - - rscadd: Water tanks are now immune to atmospheric temperatures - - rscadd: Fire extinguishers can be filled from sinks! When full, they are instead - washed. - - rscadd: Fancy progress bar when washing in a sink! - - bugfix: Slightly refactored sink washing code. if a user interrupts the process, - it will not continue processing the item or most item effects. - ghostsheet: - - rscadd: Floodlights are now constructable circuit machines. - - rscadd: Floodlights can now be upgraded with capacitor components, for increased - brightness with a higher power cost. - - bugfix: Floodlights also work in areas without APC. -2019-08-26: - Boznar: - - maptweak: Shield generators have been consolidated to a single shield bay with - its own substation. Bridge deck shield has been left in place to account for - all 5 shield generators. Shields also have their own SMES units so that configuring - each individual shield can be done more precisely. - - maptweak: Bluespace drive has been remapped to be prettier. It is no longer considered - a maintenance area and wont spawn drones or trash. - - maptweak: Deck two saferoom has been removed to make room for these changes. - Plaguewalker: - - imageadd: Adds 3 new FBP variants for Morpheus - Blitz, Airborne, and Prime -2019-08-27: - Bxil: - - tweak: The Bluespace Artillery has been rebranded to Obstruction Field Disperser. - Cajoes: - - tweak: Ascent Cutter has been updated. - ghostsheet: - - bugfix: Fixes various bugs for emergency fire shutters construction/deconstruction, - such as going invisible, returning incorrect amount of metal and skipping steps. - - tweak: Emergency fire shutters will now have a delay for welding them. -2019-08-30: - CrimsonShrike: - - bugfix: Fixes exosuits being able to use all modules at any range. - Devildabeast: - - rscdel: Removes the Biomechanical Engineer as a role. - - tweak: Gives the Roboticist trained Anatomy by default. - Rain7x: - - tweak: The sleepy pen now contains Vecuronium Bromide instead of Chloral Hydrate. - WezYo: - - bugfix: Ghosts can no longer interact with pagers - ghostsheet: - - bugfix: Fixes toolbelt overlay. Putting tools into toolbelt will now show up the - belt icon again. -2019-08-31: - BRAINOS, Plaguewalker: - - rscadd: Ported new prosthetic types from Aurora; Bishop Rook, ZH Spirit, Xion - Econ - BlueNexus: - - rscadd: Sauna heaters and reagent sublimators can now be emagged to make them - accept any reagent. - Bxil: - - rscdel: The OFD can now only shoot at overmap events. - WezYo: - - rscadd: Skrellship crew can now be selected as provocateur -2019-09-01: - Hubblenaut: - - imageadd: Adds new sprites for the TEGs, made by spriter who does not want be - named. - Zenithstar: - - maptweak: Maintenance near the shield bay now has radiation shielding. - babydoll: - - maptweak: Replaced all the various depreciated shield rooms. - - maptweak: Split the bluespace drive chamber into two areas for air alarm accuracy. -2019-09-02: - babydoll: - - tweak: Reduced attack frequency and damage for nearly all castes of asteroclast. - - tweak: Asteroclast nucleus' values change as they're damaged. They become more - aggressive, but more vulnerable to attack, and spend more energy regenerating - than trying to expand. - - rscadd: Added incense cones. - mikomyazaki: - - imageadd: Adds the 'Trimmed Right Sidecut' hairstyle. -2019-09-03: - CrimsonShrike: - - rscadd: Adds second robo slot since biomech is now gone and workload is too high. - Devildabeast: - - rscadd: Adds a Morpheus Cyberkinetics labcoat to the loadout. - Piccione: - - rscadd: Added Crosses buildable out of Material Sheets. Can also be found in Loadout. - Rain7x: - - rscadd: Added "Resident" Physician Alt Title - - rscdel: Removed "Trauma Surgeon" Alt Title -2019-09-04: - CrimsonShrike: - - rscadd: Mapped a basic exosuit to the cargo bay. -2019-09-06: - BlueNexus: - - tweak: Default Cyborgs no longer have stunbatons -2019-09-10: - Boznar: - - maptweak: Skrell Air alarms are now set to 40 degrees instead of 65 degrees. Server - air alarm added to Skrellship engineering bay at 20 degrees. - Chinsky: - - tweak: You can now grab yourself. Can't grab grabbing limb (e.g. right arm with - right hand), can't throw yourself, can't nab yourself. Otherwise you can do - whatever you want, like inspecting limbs, or covering your own eyes, or dislocating - your leg as a party trick. - Nirnael: - - rscadd: Adds pencode tags [pre] [fontblue] [fontred] [fontgreen], with closing - [/pre] and [/font] universal for the three fonts. They only work digitally with - nanoword, emails, report editors and direct txt files. Font color gives color, - [pre] gives monospace font and preserves whitespace spaces only and not tabs, - e.g. for ascii art. - - rscadd: Gas analyzers now show total moles, total volume and moles per gas, check - codex for more info. - - bugfix: Fixed robot inventory not updating automatically when dropping items which - are stored back into it. - - bugfix: Saving emails to a txt file on disk now works correctly and can be printed - with the new tags. -2019-09-11: - Spookerton: - - tweak: Added guidance on law priority and conflicts to the text shown when laws - are listed. -2019-09-12: - WezYo: - - rscadd: Adds new paperwork commands to the pen codex - ghostsheet: - - rscadd: Gas thruster is now modifiable machine. - - bugfix: Gas thruster now hooks up to their ship when built. - - rscadd: Gas thrusters now has a boot up time. - - rscadd: Gas thruster can be upgraded with matter bin for extra fuel intake volume - and less boot up time or capacitor for energy efficiency. - - rscadd: Gas thrusters has an increased energy usage on idle (6 Wh per tick so - every 2 second) and 10 Wh per burn. So please keep them off unless you need - them, for that same reason all thrusts starts offline. - - tweak: Guppy's mass and max speed has both been increased. - zaredman: - - tweak: Wizard and Ninja now require a minimum of 5 players. -2019-09-13: - babydoll: - - rscadd: Added geese, available in the supply menu. -2019-09-14: - BlueNexus: - - tweak: Tripled the damage mobs take from being in low pressure - afterthought2: - - admin: Some rudimentary spam prevention has been added. Offending users will be - kicked and noted, and you will receive notice of this. If you see patterns of - abuse, further admin action may be warranted. False positives due to overly - aggressive client macros may be possible. -2019-09-15: - WezYo: - - bugfix: Turning on a floodlight will no longer make it invisible - babydoll: - - experiment: Disables macro use. -2019-09-16: - Anticept: - - bugfix: Rigsuit codex entries now read the correct armor values for each piece. - Has no effect on damage calculations, that has always worked correctly. - - tweak: Medical voidsuit descriptions no longer imply that they have some incredible - radiation resistance, but it's still relatively good to most things in the game. - - tweak: Medical voidsuit bomb resistance values increased slightly. It's still - not a bomb suit! -2019-09-17: - Rain7x: - - rscdel: Removed old Research Director gear from the CSO locker -2019-09-18: - Chinsky: - - tweak: Inflatables now have maximum pressure difference and maximum temperature - they can endure. Currently it's 5000 kPa pressure difference and 5000 K temperature. - Every second or so when they're in worse condition than that it'll take damage. - You can patch them once with duct tape but otherwise just consider more permanent - solutions. - Rain7x: - - tweak: Members of the exploration department can now select Science Goggles, Botany - Gloves, and the Brown Webbing Vest in loadout - - tweak: Non-Civilian pilots can no longer take the EXO Flightsuit - - tweak: Webbing names now reflect their color, rather than their department. - bitMuse: - - rscadd: Added an empty autoinjector schematic to autolathes. -2019-09-20: - Rain7x: - - bugfix: The supermatter grenade box now has a working icon and is no longer invisible. - SparklySheep: - - rscadd: Adds in the fake moustache as a cheap 1 crystal item for traitors. It - will hide your identity, but that's about it. -2019-09-21: - Rain7x: - - rscadd: Added the biowaste disposal cart, for disposing of organs. - ghostsheet: - - bugfix: Boosters randomised speed has been fixed, no more indefinite speed malaise. -2019-09-23: - Imienny: - - tweak: Change heavy armor plate slowdown from 1 to 0.5 - babydoll: - - tweak: Sunglasses no longer provide full protection from handheld flashes, instead - halving their effect. - - tweak: Green glasses now have prescription lenses. - bitMuse: - - rscadd: Added reagent grinder, chemical heater, and chemical cooler to Unishi - Chem Lab. -2019-09-24: - Chinsky: - - rscadd: Added vitals monitor machines. Drag them onto people to 'hook' them. They - will display general state of brain activity, pulse and breathing, with blinky - warnings if something's wrong. - - maptweak: Replaced computers by optables with vitals monitors. - - rscadd: Chemical explosions (welderfuel and ANFO) now produce a bunch of heated - gas during explosion. - - rscadd: Welderfuel produces N, NO, NO2 and a pinch of Hydrogen for flavor - - rscadd: ANFO produces CO2, nitrogen and water - - tweak: '''Settled'' exoplanets have been renamed to ''ruined'' for 23% less confusing.' - NanakoAC: - - tweak: Adds bottled water to gym vendor - - tweak: Adds bottled water to ration crates - adamkad1: - - rscadd: Variation of artery repair surgery for Kharmaani - bitMuse: - - rscadd: Added gyrotron recipe. - - rscadd: Changed minimum fire rate of gyrotron from 1 to 2. Nerf. - ghostsheet: - - rscadd: Pipe dispenser is now a modifiable machine. - - rscadd: Pipe dispenser circuit is now a printable research design. - - bugfix: Disposal outlet will now properly eject objects outside of shuttles - - tweak: SMES installing/removing components are possible while active. They still - need to have their safety wire disabled but this will allow for more sabotage - or anti tampering opportunity. - - tweak: SMES discharge will now call electrocution (with some minor nerfs so it's - little less lethal), so insulation and armour will be taken into calculations. - - tweak: SMES will now shock people upon pulsing/cutting the grounding wire, similar - to vending machines. The severity is based upon the SMES's powernet and is reduced - with the safety wire on. - - tweak: Stun acts (from weapons) will now take existing pain of limbs and any painkillers - into account. - - tweak: Stun acts will now rely on pain to calculate, so damaged limbs will go - down to stuns easier. It also means it longer affect robotic limbs or anything - that can't feel pain. Ya IPC! - - tweak: Painkillers will now resist some stun effect due to them blocking pain. - - tweak: Stun weaponry now deals a very small amount of burn for flavor, 1-3 burn - depending on the gun. - - bugfix: Stun act will now work properly on body shots, bringing down targets with - enough pain on chest/head/groin shots. - - tweak: Robolimbs will no longer have blurry eye/ stutter or create adrenaline - upon being hurt. - - tweak: Adjusted some stun and shock duration, lowering most of it. - - tweak: Shock has a lower tier stun effect, stunning people that takes 10-15 damage - for 2 seconds. - - tweak: Shock and Stuns weapon inconsistency and damage has been adjusted. - - tweak: Shock will now activate a weak local EMP on the limb they hit (if they - deal more than 10 dmg), frying any implants, augments or synthetic organs inside - and also the limb they hit. They will neutralise an IPC/FBP after 3/4 shock - shots to the chest, frying their microbattery. - - tweak: EMP on robotic limbs will make them fail. EG. as Shock beam to a roboleg - will cause it to collapse. - - tweak: EMP now deals more damage to internal synthetic organs. - - tweak: Implants are now vulnerable to EMP if they weren't already. EG, shock beam - might fry, disables or activate the implant. - - tweak: Security and Engineering (not atmospherics) voidsuit is slightly more insulated - against shocks and stuns. Still not as a good as a hardsuit. - - tweak: Light bulbs can be taken down without gloves, on non help intent, for extra - badassery. - - tweak: Wall toss will now take armor calculations into account. - - tweak: Rejuvenate will now restore stamina. - - bugfix: APC construction has been fixed, they will now be deconstructable even - when broken. - - tweak: Space adapted human oxygen pressure requirement has been lowered to 14 - kPa. - - tweak: Grav adapted human oxygen pressure requirement has been increased to 18 - kPa. - - tweak: Grav adapted strength has been increased to high, this means they get reduced - slowdown for wearing or carrying heavier gear, eg. dufflebags, voidsuit. Still - slower than human in most regards. - - tweak: Unathi oxygen pressure requirement has been increased to 20 kPa. They - need more oxygen to support their extremely robust metabolism. -2019-09-25: - MrKicker: - - tweak: Command announcments are now multi-line. - - tweak: Command Announcements can now be multi line to allow for clever formatting -2019-09-26: - Boznar: - - maptweak: Adds mineral processing, chemistry, and cages to the ascent seedship. - - rscadd: Adds voidsuits for Alates to replace the hardsuits as base gear. Hardsuits - can still be granted to alates at the Gyne's discretion. Icons and code credit - to Zuhayr/Loaf/MistakeNot. - Chinsky: - - rscadd: Using xenolife scanner on a stasis cage will now scan the animal inside. - CrimsonShrike: - - rscadd: Exosuit pilots can now manage their inventory, throw items and some other - minor actions so long the cockpit is open. This prevents usage of exosuit modules. - Imienny: - - tweak: Ammonia now work like Dexalin Plus for Vox instead of removing oxy loss - - tweak: Nerfs Vox breathing mask to filter out only oxygen - - tweak: Updates Vox alien mask's filtered gases list - - rscadd: Adds inaprovaline autoinjector to Vox survival kit - - tweak: Change Vox minimum/maximum age from 17 - 70 to 1 - 100 - - tweak: Vox get +8 skill point bonus instead of bonus based on their age. -2019-09-27: - Chinsky: - - tweak: Made modular computer consoles proper machines instead of big items. Report - any odd behavior. - - tweak: Modular computers are now constructed via normal computer frames, requiring - a circuitboard and various generic machinery parts like input/output controllers - like other computers. - nearlyNonexistent: - - tweak: Janitor module synths now have a welding tool, to remove graffiti with. -2019-09-28: - EcklesFire: - - tweak: Made EC scarves for all uniforms, not just Dress. - comma: - - rscadd: Adds loadout accessories that are locked behind Trained skill level. - ghostsheet: - - tweak: Rescue rig can now carry an inflatable dispenser in its suit slot. - - tweak: EVA and CE rigsuit's offline slowdown has been increased to standard offline - slowdown. - - tweak: Mining prep, and prospector's locket has its round start equipment changed. - - tweak: Mining voidsuit has its laser resistance lowered and its bullet and energy - resistance rounded up, to be more a well rounded suit. - - tweak: The industrial rig has its tint lowered to moderate. -2019-09-30: - Chinsky: - - tweak: Windows now have much less health. - ghostsheet: - - maptweak: Most interior windows inside medical are now non-reinforced windows - - tweak: Full-tile glass are now tintable whereas border windows are not. -2019-10-01: - ghostsheet: - - bugfix: Overmap shuttles can now dodge meteors again. - nearlyNon: - - bugfix: Certain IPC monitor options will no longer shapeshift you into a Morpheus - monitor head. -2019-10-03: - Boznar: - - maptweak: Lepidoptera has been remapped to be more compact for planetary landing. - Extra space has been utilized for additional rooms. - - bugfix: Ascent airlocks will now all cycle and dock correctly. - - maptweak: Ascent seedship walls made more uniform. Keel is composed of reinforced - walls, while the outside is regular walls. The Tricoptera has been tweaked to - prioritize form over function. - Chinsky: - - rscadd: Adds entries for skills to Codex. They have description and what levels - of skill mean. - - rscadd: Minimum character age for jobs is now code-enforced. You may have to adjust - your chars to be able to join as your preferred job. - Rain7x: - - tweak: The labcoat can only be selected in loadout if your job would realistically - require it. It has also been removed from the medical wardrobe. - WezYo: - - bugfix: Fixed janibot and medibot crafting - comma: - - tweak: Larger internal organs are now more likely to get hit than larger ones - - tweak: Energy-based weapons are now in many cases less likely to cause internal - organ damage than ballistic weapons (based on damage output) -2019-10-04: - Rain7x: - - rscdel: Several alt tiltes have been removed. - - tweak: The job Chemist is now called Pharmacist. -2019-10-05: - Flying_loulou: - - rscadd: Creates the red ("grunt"), Yellow (Senior) and White (Chief) Damage Control - Helmets - - rscadd: Damage control helmets have now been issued to the engineering department, - they can be found in the engineer's personnal equipment lockers. - WezYo: - - bugfix: Fixed transferring reagents between beakers -2019-10-06: - Chinsky: - - tweak: Thrown items will go down the ladder if they hit it. - - tweak: If you use Move Up verb, it will try climbing random climbable turf above - if you couldn't just straight up move up. -2019-10-08: - PhosphoricPanda: - - tweak: Stabilization kits now have a radiation pouch. - nearlyNonexistent: - - rscadd: Non-Branded Spirit Boards. Gather around in the dark with another friend, - and move the planchette around. Now only works in cult rounds, otherwise just - is silly fun. - - tweak: Steaks, kabobs, and a few other recipes use cutlets instead of full-on - slabs of beef. (Plain steaks don't due to the sprite) -2019-10-10: - Chinsky: - - tweak: Stack recipies that you don't have skills for are now visible too, marked - with red warning label. You can even attempt them, wasting resources almost - certainly. -2019-10-11: - Cakey: - - bugfix: Fixed airlock paint vanishing when interacting with unpowered airlocks. - ghostsheet: - - tweak: Default aim mode allows all movement, items an radio uses. -2019-10-12: - Flying_loulou: - - tweak: Sailors rejoice ! New coveralls have been issued by the fleet. - Mordeth221: - - rscadd: Adds fancy pens to character loadout -2019-10-13: - CrimsonShrike: - - rscadd: Adds exosuit energy shields. - ghostsheet: - - maptweak: Deck 4 aft airlocks' controllers are now accessible from inside of the - airlock, so they can be more easily cycled and force. They are still not accessible - from the outside. -2019-10-14: - Chinsky: - - tweak: OCIE renamed to SFP (Sol Federal Police). There was never OCIE. - Rain7x: - - rscdel: The Corporate Security Beret has been removed from the loadout. - ghostsheet: - - rscadd: Plasma cutters can now be ordered from supply, they are locked to mining - access and engineering access - - tweak: Plasma cutters now needs trained construction to deconstruct safely. - - rscadd: Updated the skill description of the EVA, Piloting and Construction skills. - - bugfix: Fixes gun accidents only hitting the user; instead now everything in their - general vicinity is fair game. -2019-10-15: - Nanako: - - rscadd: Airlocks, curtains, ladders and cult runes can now be interacted with - by clicking the floor in their tile. - - tweak: Lift call buttons and panels are now easier to click -2019-10-16: - Anticept: - - bugfix: PAI should no longer fold up when hitting it with an access card while - on help intent. - Chinsky: - - experiment: Armor calculations and some values were changed. It should be generally - more protecting now. Report weird stuff happening. - Datraen: - - bugfix: Microwaves now properly handle non-item based recipes all the time - LiljaMortensen: - - imageadd: Updated holopad sprites - PsiOmegaDelta: - - tweak: Most objects now always consider ghosts to be adjacent when examined - - tweak: Must now shift+click to interact with boardgames - - tweak: Must now shift+click to interact with integrated circuits - nearlyNon: - - maptweak: Counselor's office reworked to have an actual desk. Much more comfortable. -2019-10-17: - Flying_loulou: - - tweak: Resprites the red O2 tank to make it look like an actual firefighter's - tank. - - tweak: The duty boots, jackboots and workboots are now fireproof. - - tweak: The firesuit no longer covers the whole body, but only the chest, arms - and groin. - - rscadd: Adds a "fire overpant", to be worn over the uniform as an accessory to - protect your legs against a fire. - - rscadd: Adds the fire gloves, fully fire proof. - - rscadd: Adds the EFT (Emergency Forcing Tool). - - rscadd: Adds the "water grenade" to fight fires more efficiently. - - rscadd: Creates the firebelt, which has 5 slots and can contain EFTs, water grenades, - inflatable doors and mini-extinguishers. It comes filled with 3 water grenades, - 1 EFT and 1 inflatable door. - - rscadd: Adds the new equipment in the fire closets (places them into a dufflebag - for convenience) - - tweak: In order to survive a fire, you now have to wear the fire overpants, firesuit, - fire gloves, duty boots (Jackboots and Work boots are fire resistant as well), - as well as a fire resistant helmet/hardhat and proper internals. -2019-10-19: - CrimsonShrike: - - rscadd: Allow some more interactions from inside exosuits such as grabbing items - from clamp if the cockpit is open. - Marie Taylor: - - imageadd: Updated fridge sprites - - imageadd: Updated pylon sprite - - imageadd: Resprited holopad, the artist of the previous version has been executed - - imageadd: Resprited bell - - imageadd: Added ringing animation to bell - - imageadd: Resprited notice board, added 4 dir -2019-10-20: - Anticept: - - bugfix: PAIs, Photos, Integrated Circuit Printers, Printed Crew records, and Warrant - Projectors should be working again. - Ithalan: - - bugfix: Fixes modular computer icons not updating automatically for certain monitoring - program events. - WezYo: - - bugfix: Fixed crafting floorbots -2019-10-21: - Nirnael: - - bugfix: Fixes personal closets. - ghostsheet: - - soundadd: Voidsuit now has sounds for tank ejection and disassembling. -2019-10-22: - Higgin: - - bugfix: SecHUDs and goggles will now protect against flashes and flashbangs as - they used to. -2019-10-23: - Marie Taylor: - - imageadd: Resprite of crates, open decals added - Spookerton: - - admin: Build mode has an area viewer/editor. - ghostsheet: - - tweak: Senior researcher no longer has access to mining. - - bugfix: Plasma cutter crate access has been fixed to work with both engineering - and mining access - - tweak: Supply's warehouse is now open to mining access. -2019-10-24: - Boznar: - - maptweak: Maps Vox rigs, soundcannon, and flux cannon to Vox base - CrimsonShrike: - - rscadd: The SEV Torch is now fitted with point defense batteries, that will protect - certain parts of ship from meteor impacts. - ghostsheet: - - tweak: Supply's mechsuit now has two hydraulic clamps instead of a drill. -2019-10-27: - Higgin: - - tweak: Radicals rejoice! Head Revolutionaries once again get traitor uplinks. -2019-10-28: - Ithalan: - - bugfix: Fixed several cases of missing powercables underneath doors and tables - aboard bearcat - - bugfix: Fixed a couple of tiles in bearcat atmospheric compartment that were permanently - without pressure or gravity - - maptweak: Added girders and a few walls to more clearly indicate original extent - of damaged rooms aboard bearcat, for purpose of predicting APC and gravity coverage -2019-10-29: - BlueNexus: - - tweak: Nerfed the bloodsucking creatures often found on away sites -2019-10-30: - SierraKomodo: - - rscadd: Added rooibos tea, chai tea, chai latte, london fog, and mocha latte as - dispensable or mixable drinks. - - rscadd: Added chocolate, vanilla, caramel, and pumpkin spice syrups for flavoring - drinks. - - rscadd: Added alternate title 'Barista' to the Bartender job. - WezYo: - - spellcheck: Fix gaia blurb -2019-11-02: - Imienny: - - tweak: Fix races with low oxy_mod recovering slower from oxygen deprivation than - races with high oxy_mod -2019-11-03: - CrimsonShrike: - - rscadd: Exosuit cells can now be swapped without disassembling entire thing. Simply - use a crowbar while mainteance protocols are active to take one out. - ghostsheet: - - rscadd: Welding tool now gives off light when active (it's a little weaker than - a flashlight) and sparks blue when it's welding. - - tweak: Lighters had their light color adjusted for the sake of ambience -2019-11-04: - Higgin: - - tweak: The accuracy bonus for shooting ranged weapons from standing still has - received a slight buff. - ghostsheet: - - tweak: Mining voidsuit now has minor bullet resistance and can withstand up to - 5000 kPa worth of pressure. -2019-11-05: - Higgin: - - tweak: Harm-intent clicking will now remove shotshells directly from shotholders. - SierraKomodo: - - tweak: Tablets now beep just like PDAs. - - tweak: Borgs can now alt-click doors to access the tile tab instead of shocking - them. To shock a door, use harm intent when alt-clicking. -2019-11-06: - Ithalan: - - tweak: Solar arrays on planetary surfaces now only require 5 tiles of clear space - around them to work at all, instead of 20. Solar arrays in space are unchanged. - SierraKomodo: - - bugfix: Cyborg cable coil can now be used to build machines -2019-11-07: - Albens: - - tweak: Bridge Holopad is now named SEV Torch Bridge - Soviet Swede: - - rscadd: Added the inflatables dispenser to the surveyor -2019-11-08: - Marie Taylor: - - imageadd: Updates the appearance of crates -2019-11-10: - SierraKomodo: - - bugfix: The `hwinfo` command in console terminals now outputs to the terminal - window instead of to chat. - - tweak: The console terminal prompt now includes a helpful reminder about the `man` - command. -2019-11-11: - Bxil: - - bugfix: Character setup works as expected again. - Rain7x: - - bugfix: You can now attach pins to Dress Jackets again. -2019-11-12: - Flying_loulou: - - bugfix: The nitrogen tanks again look like nitrogen tanks. - - tweak: Changes the fire (red) oxygen tank name to 'self contained breathing apparatus' - (SCBA) - - rscadd: Adds the Emergency Management Bureau helmetto the loadout - - rscadd: Adds the ancient Emergency Management Bureau helmet to the loadout (credits - to Sin2 for the sprites) - - rscadd: Adds the light damage control helmet to the loadout - - rscadd: Adds the SCBA mask, and adds it to the engineering crew survival kit, - instead of the breath mask.(credits to Sin2 for the sprites) - Imienny: - - rscadd: adds zipgun, knock-off pistol, small energy gun, ion pistol, ion slug, - duct tape, combat defibrillator, stasis bag, stabilisation kit, balaclava and - "exceptionally robust MRE" to uplink - - tweak: MRE coffee and tea powder no longer require heating - - bugfix: fixed MRE menu 8 (chilli) spawning with pizza instead of chilli - babydoll: - - rscadd: Added scented candles. - - rscadd: Incense and scented candles are now available in the aromatherapy crate - in supply. - ghostsheet: - - rscadd: Rapid Piping Device has been added! - - rscadd: RPD can be ordered from supply, at semi-reasonable cost of a 100 points - a piece. - mikomyazaki: - - bugfix: Body bag label overlays will now properly persist through opening/closing, - instead of disappearing. -2019-11-13: - SierraKomodo: - - bugfix: Intercoms and handheld radios can now select common and entertainment - channels again. - comma: - - tweak: Wall girders are now easier to take down using brute force - mikomyazaki: - - bugfix: NTNet downloads will no longer download the file at the beginning of the - download sequence, instead only adding the new program at the end of the download - timer. -2019-11-14: - mikomyazaki: - - bugfix: Different pen types (blue, red, multicoloured, black) now have different - names. They will now appear as differently named items on the autolathe list. -2019-11-15: - Higgin: - - tweak: Limits the range within which escaping cuffs/unbuckling yourself while - cuffed is visible. - - tweak: Readded different furniture/structure recipes to wood. - - tweak: Added orderable titanium sheets to supply. - - tweak: Fear the gun! Buffed all bullet damage towards a benchmark of 50. Gave - additional armor penetration to most common rounds with more than 50 damage. - - tweak: Love the armor! Buffed many armors' resistance to bullet damage. - Jaraci: - - tweak: Fixes/expands loadout options for off-Torch away site roles. -2019-11-16: - MrKicker: - - bugfix: Fixed Roboticist JumpSkirt appearing invisible - SierraKomodo: - - rscadd: Added soy and iced variants of the chai latte, london fog, pumpkin spice - latte, and mocha latte. - mikomyazaki: - - bugfix: Engine emitter control button (and other buttons of this type) no longer - go invisible for a couple of seconds when clicked. - - bugfix: Surgical borgs can now use their hypospray on targets that are on an operating - table. -2019-11-17: - Chinsky: - - tweak: Geiger counter thresholds have been tweaked upwards, 'high' is now for - rads that will breach most non-radproof suits, 'very high' is dangerous even - to 'radproof' suits. - Imienny: - - rscadd: Improved a bit Vox hardsuit, now you can store more useful stuff in hardsuit - storage slot and use claws attack through now-insulated hardsuit gloves. - Technetium: - - rscadd: Wound infection speed is now twice as fast at 50-70% immunity as it was - before, and 10 times as fast at 0% immunity. - mikomyazaki: - - tweak: Instruct verb will inform you better about why it fails, if it does. - - bugfix: Stationary consoles now have a 'Forced Shutdown' verb, just like other - kinds of modular computer. - - bugfix: The 'boiled spider meat' recipe now correctly produces an item called - 'boiled spider meat' rather than 'giant spider leg'. -2019-11-18: - Higgin: - - imageadd: Added two bunny-eared booster sprites. -2019-11-19: - mikomyazaki: - - bugfix: Removing an ID from a modular computer no longer brings up a selection - menu containing other modular computers with ID card slots in range. -2019-11-20: - Rain7x: - - tweak: Mentalists can now only be an O-1 (Ensign) - - bugfix: The Pathfinder, Med Tech, and pilot headsets now have an on mob icon again. - SierraKomodo: - - tweak: Swallowing pills now displays a message to people within a 2 tile radius. - This message does not tell them what pill you swallowed. - - tweak: Initiating a give (Right click > Give) now displays a message that you - 'hold out an item' to the target. - Technetium: - - rscadd: Adds immunobooster, an immune-system restoring drug that will rapidly - bring a ruined immune system up to half strength. Will not replace a proper - immune system, though, so be careful with those rads and spaceacillin. - babydoll: - - rscadd: Added the incendiary laser blaster to the traitor menu. - ghostsheet: - - tweak: Ion rifle and pistol has its capacity reduce to 8/4 shots respective and - had their delay between shots increased to 3 seconds. - - tweak: Uplink implant is now more EMP resistant, it can still be disabled by an - EMP but its chance of permanently breaking is significantly lowered. - - tweak: Imprinting implant cannot be implanted into synthetic being and must now - be imprinted where the brain organ is eg. For a GAS that would be their thorax; - for humans, their head. - - bugfix: You can leap over objects once again. - mikomyazaki: - - bugfix: Supermatter hallucination effect now checks for any source of meson vision, - rather than just meson glasses. Other sources of meson vision, e.g. the hardsuit - module will now properly stop hallucinations from developing when active. - - bugfix: You can now remove splints from yourself. - - tweak: '''Remove Splints'' is now a verb (right click your target to find it) - rather than in the stripping menu.' -2019-11-21: - Chinsky: - - tweak: Airlock controllers were resprited to blend with rest of wallstuff, have - directional icons now - - tweak: Flashbangs nerfs! No flooring, stun durations are now very short (you have - 4-6 seconds against non-protected, 2 against anyone with a helmet. Added confusion - effect (generally 2-3 times longer than stun) to them too. - SierraKomodo: - - bugfix: Give emotes now display the correct text for recipient vs everyone else - Technetium: - - rscadd: Carbon mobs now take immune damage from radiation. - WezYo: - - bugfix: Clicking on first aid kits (or other crafting objects) with certain items - will no longer delete the first aid kit. - babydoll, dirtygirl: - - rscadd: Added the dire goose, occasionally making its nest on grass exoplanets. - mikomyazaki: - - soundadd: Vending machines now play a sound when dispensing an item. - - bugfix: SolGov Employees now have clothing in their uniform vendor, the same as - the civilian uniform set. -2019-11-23: - Rain7x: - - tweak: The CMO now has the same amount of total skill points as a regular physician. - ghostsheet: - - rscadd: Added a navigation telescreen to the Charon crew compartment. - - rscadd: Replaced the rack on the Guppy with a storage compartment crate - - rscadd: Added binoculars to mining prep. - - rscadd: Carp migration event got reworked! They will now be launched into the - ship at slow speed, over a period of time. - - rscadd: Overmap carp hazard, has been tweaked in same maner as the carp migration - event, carps will be launched at the ships over a period of time. The speed - of carps hitting ships will be dependent on the ship's speed, multiplied by - the pilot's skill. (Go fast for road kills, you want to go fast to escape the - carp event either way). - - tweak: Structures and machine such as windows and computers, will hurt any mob - thrown against it, similar to being thrown against a wall. (Throwing people - against things now deals the same damage as a wall) - mikomyazaki: - - tweak: Firing a gun successfully will now switch off RIG-based cloaking devices. -2019-11-24: - mikomyazaki: - - bugfix: Malfunctioning AIs will now properly get the ai-select-hardware, ai-select-research - and display-help and set-ambition verbs. - - tweak: Malfunctioning AI is now consistently called Malfunctioning AI everywhere. - (This will not affect your character role settings.) - - tweak: Ascent Drones will no longer have the bureaucracy skill to speak legalese. -2019-11-25: - Chinsky: - - tweak: Free skillpoints for medical jobs were lowered, check your skill setups. - - tweak: Virology is no longer a full skill, a perk now requiring Trained Medicine. - - tweak: Codex now has navigation bar to get to home page quickly, or search or - list all stuff. - SierraKomodo: - - tweak: Borgs with the proper skills can now use console terminals with ctrl+alt+click. - You must be adjacent to the console to use this. - Technetium: - - tweak: Immunobooster now has overdose effects and a lower OD threshold (60u -> - 30u). - - tweak: Immunobooster now has strong negative interaction with spaceacillin. Do - not mix. -2019-11-27: - Anticept: - - tweak: Deck Chief now has mining access - MrKicker: - - tweak: Added extra table to OR 2 - - bugfix: Fixed medical hallway telescreen - Rain7x: - - tweak: The job Pharmacist is now called "Laboratory Technician". Their job has - been expanded to include virology duties. - - rscdel: The "Laboratory Technician" alt-title has been removed from the Research - Assistant Role. - SierraKomodo: - - tweak: Shield generator monitoring programs now display the same shield statuses - as the shield generator UI itself - Technetium: - - rscadd: Carbon mobs now take radiation damage upon exposure, modified by their - species radiation modifier -and- burn modifier. - mikomyazaki: - - rscadd: All Deity mode spells and structures now have a codex entry visible to - the God Cultists that explains what they do, or how to use them. - - tweak: Dionaea can be cured of viruses by receiving a middling dose of radiation. - Exposure to a radiation storm or standing outside the supermatter containment - window for a short time should be sufficient. -2019-11-28: - Rain7x: - - tweak: The Lab Tech now only has 16 skill points, and is restricted to trained - medicine and anatomy. - babydoll: - - rscadd: Added two new types of fauna to volcanic exoplanets. - - tweak: To account for their low health, simple animals take less damage from ballistic - and laser projectiles. -2019-11-29: - mikomyazaki: - - tweak: Failing to do surgery due to thick material clothing items will now display - an appropriate error message. -2019-11-30: - afterthought2: - - bugfix: Robotic limb attachment and connection surgery now consistently checks - robotic skills (complex devices, also anatomy if on flesh target). -2019-12-01: - mikomyazaki: - - bugfix: The delete warrant button in the main window of the Warrant Assistant - program will now properly do its job. -2019-12-02: - MrKicker: - - tweak: Notes/memories can now be multi-line. - Rowtree: - - rscadd: Added 30 new drinks, added recipes for Nothing, and added new bottles - to the booze-o-mat -2019-12-03: - Technetium: - - tweak: Nerf to Vox Slug Sling, 2.5x addt. egg generation speed. - mikomyazaki: - - bugfix: Antagonist HUD markers e.g. Cultist indicators will now properly show - up instead of being under the floor layer sometimes. -2019-12-04: - Rain7x: - - tweak: Candy Bar sprite has been updated. - afterthought2: - - rscdel: Virology has been entirely removed from the game. -2019-12-05: - Spookerton: - - tweak: Booster biomod hair options have been replaced with booster markings. -2019-12-06: - MrKicker: - - tweak: Allows hand-labeler to label storage items when used with non-help intent. - babydoll: - - rscadd: Added retractable ball point pens. - mikomyazaki: - - bugfix: Taping paper to windows will no longer put it below the window. -2019-12-07: - Boznar: - - maptweak: Engineering bay and atmospherics have been remapped to be less cramped - and more space efficient. - - maptweak: RPDs added to atmospherics lockers. Additional EVA hardsuit and Atmos - Voidsuit added to engineering. - Imienny: - - tweak: You can no longer hear aiming sounds, unless you are being aimed at/aiming - at. -2019-12-08: - Imienny: - - rscadd: Added option to change type of stomach in character setup menu - - bugfix: Fixed bug allowing to use stun batons without charges - - bugfix: Fixed bug preventing stun prods from working with standard device cells - Spookerton: - - bugfix: Female rolled uniform and sleeves for EC command uniform no longer makes - you naked. - mikomyazaki: - - tweak: Burn damage from radiation exposure is nerfed by 75%. -2019-12-09: - mikomyazaki: - - bugfix: Robots can now wrench portable rechargers to move/anchor them. -2019-12-12: - Rowtree: - - bugfix: Fixes recently added drink strengths to a more accurate level. - Spookerton: - - tweak: Bald boosters get bald ears. - mikomyazaki: - - bugfix: AIs can now spawn properly at roundstart. - zaredman: - - bugfix: Biowaste disposal cart access to only require surgery access instead of - requiring 6 different accesses. Corpsmen rejoice! -2019-12-15: - Spookerton: - - bugfix: Starborn, Blueforged, and Promethean variations properly show the head, - torso, and groin. -2019-12-17: - CrimsonShrike: - - rscadd: Drill heads show current status while mounted and can be examined for - information when not mounted on an exosuit drill. - EcklesFire: - - tweak: Adjusted renegade numbers. - - bugfix: Removed duplicate vars. -2019-12-19: - Spookerton: - - tweak: PTR bullets aren't hitscan and do a little less damage and penetration. - babydoll: - - rscadd: Added foam dart launchers. - - rscadd: Foam dart launchers can now be won as prizes from arcade machines. - - rscadd: Added a modified foam dart launcher to the uplink's gimmick weapons menu. -2019-12-20: - Cajoes: - - rscadd: Added orderable replacement barricade tape rolls from supply. - PsyCommando: - - tweak: Made the currency used in text entries read from the current map. Mainly - to help with downstream stuff. - afterthought2: - - rscadd: Buildable radio components for machines are now available. They will have - limited use with machines currently. - - tweak: When building air sensors, you now must also add a power component and - a radio transmitter. You can use a multitool on the radio transmitter while - standing near a machine to configure it. - ghostsheet: - - rscadd: Mercenary gamemode is now overmap. -2019-12-21: - Imienny: - - tweak: Tweaked TC cost of uplinks in Character Setup menu, radio uplink now gives - you 30% more TC, uplink Implant cost only 20% of total TC and taking TC without - uplink gives you 50% more TC. - - tweak: Message shown after receiving PDA uplink now should explain better how - to access uplink. - - tweak: Delay for removing knives from boots was decreased to one second - - tweak: Using combi-knifes on intent other than help intent will now open their - blade - - tweak: Portable freezers can now fit inside backpacks and have capacity of large - box - - tweak: Combat knifes can now fit inside boots - mikomyazaki: - - bugfix: Sleepers will now properly display the amount of a drug in the occupant - on the UI. - - tweak: R-UST now has a prompt to tell you when hitting the shutdown button will - cause an instant explosion, asking whether you're sure. - - maptweak: R-UST room machinery starts the round anchored. - - tweak: Improves the fuel injector controller UI, with injection rate and toggle - all injectors controls. -2019-12-22: - Chinsky: - - tweak: During the metor rounds, evacuation jump will be called automatically after - announcement that rocks are coming. It will take 30ish minutes to arrive - - tweak: Since there's less time and Torch is /very/ sturdy (thicc hull and PD), - initial intensity is bumped a bit and escalation is going faster, so will hit - max intensity at around 30 minutes mark. - - tweak: 'After the jump mode will check for some important things and will print - red/green text about them: helm console (need to have at least one and powered), - thrusters (ditto), bluespace drive (the room must be powered).' - mikomyazaki: - - tweak: Trained Forensics now provides a much larger bonus to making simple incisions - on dead targets for autopsies. -2019-12-23: - mikomyazaki: - - bugfix: Can't put objects inside bags that are in pockets anymore. - - tweak: Updated traitor extended round description so it is appropriate for the - SEV Torch setting. - - bugfix: Double doors are properly solid again. -2019-12-27: - babydoll: - - tweak: Increased damage taken when falling down a hole to another deck. - - tweak: Increased duration of stun after falling. - mikomyazaki: - - bugfix: Merchant station teleporter computer will now display the proper messages - relating to costs. -2019-12-28: - Cheb Pomidorov: - - tweak: Scientists and Research Assistants can now enter areas such as Medbay and - Brig's hallways and the Bridge Entry. - Devildabeast: - - tweak: Changes the Mentalist's Mind Read time limit from 25 seconds to 60. - Spookerton: - - tweak: Mercenary and Provocateur starting points are hidden from the Torch's roundstart - sensor message. - zkxs: - - bugfix: The psionic signal event can no longer give synthetics genetic disabilities -2020-01-03: - Devildabeast: - - tweak: Changes "restricted roles" to the broader "casual roles" in loadoout. - - tweak: Adjusts several loadout item restrictions. - Imienny: - - tweak: Replaced spoon in MRE with spork - mikomyazaki: - - bugfix: Nymphs and Golems are no longer valid targets for auto-traitor. - - bugfix: Mercenary radio channel now works again for mercs, raiders, traitors etc. - zkxs: - - bugfix: Fixes a runtime when using an atmos analyzer on a pit -2020-01-30: - Anticept: - - tweak: Farmbots now refill from a sink at a higher rate, up from 10 to 100 per - cycle. - Cheb Pomidorov: - - rscadd: You can now lock and unlock coffins using a screwdriver. Locked coffins - can be struggled out of, similarly to welded closets. - Imienny: - - rscadd: Added a new roles to Vox Scavenger away site, "Shoal Biotechnician", "Shoal - Technician" and "Quill" - MrKicker: - - tweak: AI can now make multi-line announcements - Spookerton: - - rscdel: IPCs can no longer be counsellors. - WezYo: - - bugfix: Flying drones can now open windoors - Xaytan: - - tweak: Adds welding goggles as an option in loadout. - afterthought2: - - rscadd: Pipe meters, vents, scrubbers, and pumps now use radio components. - mikomyazaki: - - tweak: Guest pass icon will now change colour to black when expired. - - tweak: Guest pass machine gets an updated UI. - - tweak: Humanoid Dionaea now get the audible chirp emotes. - - soundadd: Added a new multichirp (*mchirp) audible emote sound effect for humanoid - Dionaea. - - bugfix: Portable drives now work properly in modular computers for all operations. - - bugfix: Dense objects will now properly stop throwing/leaping. - - bugfix: Hand teleporters will now create portals that aren't random, when you - are linked to a teleport computer on a connected z-level. - - tweak: Hand teleporters will now only list teleport computers that are on a connected - z-level. - - bugfix: Can no longer right-click darkness due to being unconscious to see what - is on that turf. - - tweak: Decreased difficulty of installing augments to the same level as installing - robotic organs. - - imageadd: Adds three xenowear options for Space-Adapted humans - Leg braces, neck - brace and venter. - - imageadd: Adds animations for the sleeper & bodyscanner when active & occupied. - - soundadd: Adds a scanning sound for the bodyscanner. - - tweak: Space-Adapted humans' stamina now depends slightly upon gravity levels, - with better stamina than baseline humans in low-gravity, worse in standard gravity. - - tweak: Space-Adapted humans are adapted for lower-pressure environments, but suffer - in higher pressure environments faster relative to baseline humans. - - bugfix: The Vox shuttle can now return to its hangar properly. - quardbreak: - - tweak: Tweaked welding sounds on airlock and vents. Now after weld operation you - should hear second sound like you end your action. - zkxs: - - bugfix: Combining stacks from an inventory no longer leaves bugged sprites - - bugfix: Having more than 10 brain damage no longer grants immunity to peridaxon's - side effects (confusion and drowsiness) - - spellcheck: Sec HUD goggles description grammar fix - - rscadd: Adherent can now float over tables -2020-01-31: - Lorwp: - - soundadd: Energy melee weapons now have an on-hit sound - mikomyazaki: - - tweak: Paper will now check if your pen works before you start writing instead - of after you've written your text. - - tweak: If your retractable pen isn't in its active state when you start writing - on something, your character will automatically click it. - - tweak: Retractable pens will now toggle to their active state when you write on - anything (union cards, people, the wall) instead of only paper. - zaredman: - - tweak: Security now has access to a written statement, weapons license, arrest - report, and restraining order template on the Reports program. Paperwork masochists, - rejoice. -2020-02-03: - mikomyazaki: - - bugfix: Throwing items at a disposal chute will properly dispose of them again. - - bugfix: Fixes a bug where (for example) throwing an object at a grilled window - would hit the grill inside the window instead of the window. -2020-02-05: - mikomyazaki: - - admin: Mobs without the UI elements to use psionics can no longer be granted psionics. - e.g. simple animals. - - bugfix: Polytools now allow you to extend tools again. -2020-02-07: - Chinsky: - - tweak: Various drinking glasses are now printed from a microlathe instead of being - vended. Bar now has pre-loaded microlathe for this purpose. - - rscadd: Added new type of drinking glass - flute glass. - - tweak: Added transparency to some reagents, namely water and booze. - - tweak: Can now select recipies category in fabricators - - tweak: More types of glasses can take accessories like sticks or straws now, try - it out. -2020-02-08: - mikomyazaki: - - bugfix: Atmospherics' tank controllers work again when controlling the output - vent. - zaredman: - - maptweak: Removes Explorer and Pilot access to Xenobiology, Xenoarchaeology, Toxins, - and assorted labs. Pathfinder retains their original access. -2020-02-10: - Flying_loulou: - - rscadd: Fleet engineers rejoice ! The fleet unlocked some funds, in order to provide - you with a dedicated uniform, constituted of a polo, some pants, and a jacket - (available in the uniform vendor, under the utility extra section). -2020-02-12: - SomeoneStoleMyNickname: - - bugfix: The Guidebooks Hacking and Repair and Construction should now work as - intended. +DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. +--- +2013-01-07: + Cael_Aislinn: + - tgs: Updated server to tgstation r5200 (November 26th, 2012), see https://code.google.com/p/tgstation13/source/list + for tg's changelog. + Chinsky: + - rscadd: 'Implants: Explosvie implant, exploding when victim hears the codephrase + you set.' + - rscadd: 'Implants: Compressed Matter implat, scan item (making it disappear), + inject yourself and recall that item on will!' + - rscadd: Implant removal surgery, with !!FUN!! results if you mess up it. + - rscadd: Coats now have pockets again. + - rscadd: Bash people on tabetops. an windows, or with stools. Grab people to bash + them on tables or windows (better grab for better hit on windows). Drag stool + sprite on you to pick it up, click on it in hand to make it usual stool again. + - rscadd: Surgical caps, and new sprites for bloodbags and fixovein. + - rscadd: Now some surgery steps will bloody your hands, Full-body blood coat in + case youy mess up spectacualry. + - rscadd: Ported some crates (Art, Surgery, Sterile equiplemnt). + - tweak: Changed contraband crates. Posters moved to Art Crate, cigs and lipstick + ot party crate. Now contraband crate has illegal booze and illicit drugs. + - bugfix: Finally got evac party lights + - bugfix: Now disfigurment,now it WILL happen when damage is bad enough. + - experiment: Now if you speak in depressurized area (less than 10 kPa) only people + next to you can hear you. Radios still work though. +2013-01-13: + Chinsky: + - tweak: If you get enough (6) blood drips on one tile, it'll turn into a blood + puddle. Should make bleeding out more visible. + - tweak: Security belt now able to hold taser, baton and tape roll. + - tweak: Added alternative security uniform to Security wardrobes. + - rscadd: 'Ported Urist cult runes. Down with the crayon drawings! Example: http://dl.dropbox.com/u/26846767/images/SS13/255_symbols.PNG' + - bugfix: Engineering tape now require engineer OR atmos access instead of both. + - rscadd: Implants now will react to EMP, possibly in !!FUN!! ways + GauHelldragon: + - rscadd: Servicebots now have RoboTray and Printing Pen. Robotray can be used to + pick up and drop food/drinks. Printing pen can alternate between writing mode + and rename paper mode by clicking it. + - rscadd: Farmbots. A new type of robot that weeds, waters and fertilizes. Use robot + arm on water tank. Then use plant analyzer, mini-hoe, bucket and finally proximity + sensor. + - rscadd: Chefs can clang their serving trays with a rolling pin. Just like a riot + shield! +2013-01-21: + Cael_Aislinn: + - bugfix: Satchels and ore boxes can now hold strange rocks. + - rscadd: Closets and crates can now be built out of 5 and 10 plasteel respectively. + - rscadd: Observers can become mice once more. +2013-01-23: + Cael_Aislinn: + - tgs: Updated server to tgstation r5200 (November 26th, 2012), see https://code.google.com/p/tgstation13/source/list + for tg's changelog. +2013-01-31: + CIB: + - bugfix: Chilis and cold chilis no longer kill in small amounts + - bugfix: Chloral now again needs around 5 units to start killing somebody +2013-02-13: + Erthilo: + - bugfix: Fixed SSD (logged-out) players not staying asleep. + - bugfix: Fixed set-pose verb and mice emotes having extra periods. + - bugfix: Fixed virus crate not appearing and breaking supply shuttle. + - bugfix: Fixed newcaster photos not being censored. +2013-02-14: + CIB: + - rscadd: Medical side-effects(patients are going to come back for secondary treatment) + - rscadd: NT loyalty setting(affects command reports and gives antags hints who + might collaborate with them) + - tweak: Simple animal balance fixes(They're slower now) + CaelAislinn: + - rscadd: Re-added old ion storm laws, re-added grid check event. + - rscadd: Added Rogue Drone and Vermin Infestation random events. + - rscadd: Added/fixed space vines random event. + - tweak: Updates to the virus events. + - tweak: Spider infestation and alien infestation events turned off by default. + - tweak: Soghun, taj and skrell all have unique language text colours. + - tweak: Moderators will no longer be listed in adminwho, instead use modwho. + Gamerofthegame: + - rscadd: Miscellaneous mapfixes. +2013-02-18: + Cael Aislinn: + - rscadd: Security bots will now target hostile mobs, and vice versa. + - tweak: Carp should actually emigrate now, instead of just immigrating then squatting + around the outer hull. + - tweak: Admins and moderators have been split up into separate 'who' verbs (adminwho + and modwho respectively). +2013-02-20: + Chinsky: + - rscadd: 'Added new surgery: putting items inside people. After you use retractor + to keep incision open, just click with any item to put it inside. But be wary, + if you try to fit something too big, you might rip the veins. To remove items, + use implant removal surgery.' + - rscadd: Crowbar can be used as alternative to retractor. + - rscadd: Can now unload guns by clicking them in hand. + - tweak: Fixed distance calculation in bullet missing chance computation, it was + always assuming 1 or 0 tiles. Now distace REALLY matters when you shoot. + - rscadd: To add more FUN to previous thing, bullets missed to not disappear but + keep going until they hit something else. + - bugfix: Compressed Matter and Explosive implants spawn properly now. + - tweak: 'Tweaks to medical effects: removed itch caused by bandages. Chemical effects + now have non-100 chance of appearing, the stronger medicine, the more probality + it''ll have side effects.' +2013-02-22: + Chinsky: + - tweak: Change to body cavity surgery. Can only put items in chest, groind and + head. Max size for item - 3 (chest), 2 (groin), 1 (head). For chest surgery + ribs should be bent open, (lung surgery until second scalpel step). Surgery + step needs preparation step, with drill. After that you can place item inside, + or seal it with cautery to do other step instead. +2013-02-23: + Cael Aislinn: + - wip: RUST machinery components should now be researchable (with high requirements) + and orderable through QM (with high cost). + - wip: Shield machinery should now be researchable (with high requirements) and + orderable through QM (with high cost). This one is reportedly buggy. + - tweak: Rogue vending machines should revert back to normal at the end of the event. + - rscadd: New Unathi hair styles. +2013-02-25: + Cael Aislinn: + - rscadd: As well as building hull shield generators, normal shield gens can now + be built (see http://baystation12.net/forums/viewtopic.php?f=1&t;=6993). + - rscadd: 'New random events: multiple new system wide-events have been have been + added to the newscaster feeds, some not quite as respectable as others.' + - rscadd: 'New random event: some lucky winners will win the TC Daily Grand Slam + Lotto, while others may be the target of malicious hackers.' +2013-02-27: + Gamerofthegame: + - rscadd: Added the (base gear) ERT preset for the debug command. + - rscadd: Map fixes, Virology hole fixed. Atmospheric fixes for mining and, to a + less extent, the science outpost. (No, not cycling airlocks) + - rscadd: Fiddled with the ERT set up location on Centcom. Radmins will now have + a even easier time equiping a team of any real pratical size, especially coupled + with the above debug command. +2013-03-05: + CIB: + - rscadd: Added internal organs. They're currently all located in the chest. Use + advanced scanner to detect damage. Use the same surgery as for ruptured lungs + to fix them. + Cael Aislinn: + - soundadd: Set roundstart music to randomly choose between space.ogg and traitor.ogg + (see http://baystation12.net/forums/viewtopic.php?f=5&t;=6972) + - experiment: All RUST components except for TEGs (which generate the power) are + now obtainable ingame, bored engineers should get hold of them and setup an + experimental reactor for testing purposes. +2013-03-06: + Cael Aislinn: + - rscadd: Type 1 thermoelectric generators and the associated binary circulators + are now moveable (wrench to secure/unsecure) and orderable via Quartermaster. + - wip: code/maps/rust_test.dmm contains an example setup for a functional RUST reactor. + Maximum output is in the range of 12 to 20MW (12 to 20 million watts). + - bugfix: Removed double announcement for gridchecks, reduced duration of gridchecks. + RavingManiac: + - rscadd: You can now stab people with syringes using the "harm" intent. This destroys + the syringe and transfers a random percentage of its contents into the target. + Armor has a 50% chance of blocking the syringe. +2013-03-09: + Cael Aislinn: + - rscadd: "Beekeeping is now possible. Construct an apiary of out wood and embed\ + \ it into a hydroponics tray, then get a queen bee and bottle of BeezEez from\ + \ cargo bay. \n\t\tHives produce honey and honeycomb, but be wary if the bees\ + \ start swarming." +2013-03-11: + CIB: + - rscadd: Cloning now requires you to put slabs of meat into the cloning pod to + replenish biomass. + Cael Aislinn: + - wip: The xenoarchaeology update is here. This includes a major content overhaul + and a bunch of new features for xenoarchaeology. + - tweak: Digsites (strange rock deposits) are now much more nuanced and interesting, + and a huge number of minor (non-artifact) finds have been added. + - rscadd: Excavation is now a complex process that involves digging into the rock + to the right depth. + - rscadd: Chemical analysis is required for safe excavation of the digsites, in + order to determine how best to extract the finds. + - bugfix: Anomalous artifacts have been overhauled and many longstanding bugs with + existing effects have been fixed - the anomaly utiliser should now work much + more often. + - rscadd: Numerous new artifact effects have been added and some new artifact types + can be dug up from the asteroid. + - rscadd: New tools and equipment have been added, including normal and spaceworthy + versions of the anomaly suits, excavation tools and other neat gadgets. + - rscadd: Five books have been written by subject matter experts from around the + galaxy to help the crew of the Exodus come to grips with this exacting new science + (over 3000 words of tutorials!). + Chinsky: + - rscadd: Sec HUDs now can see short versions of sec records.on examine. Med HUDs + do same for medical records, and can set medical status of patient. + - rscadd: Damage to the head can now cause brain damage. +2013-03-14: + Spamcat: + - rscadd: Figured I should make one of these. Syringestabbing now produces a broken + syringe complete with fingerprints of attacker and blood of a victim, so dispose + your evidence carefully. Maximum transfer amount per stab is lowered to 10. +2013-03-15: + Cael_Aislinn: + - rscadd: Mapped a compact research base on the mining asteroid, with multiple labs + and testing rooms. It's reachable through a new (old) shuttle dock that leaves + from the research wing on the main station. +2013-03-26: + Spamcat: + - bugfix: Chemmaster now puts pills in pill bottles (if one is inserted). + - tweak: Stabbing someone with a syringe now deals 3 damage instead of 7 because + 7 is like, a crowbar punch. + - bugfix: Lizards can now join mid-round again. + - rscadd: Chemicals in bloodstream will transfer with blood now, so don't get drunk + before your blood donation. Viruses and antibodies transfer through blood too. + - bugfix: Virology is working again. +2013-03-27: + Asanadas: + - tweak: The Null Rod has recovered its de-culting ability, for balance reasons. + Metagaming with it is a big no-no! + - rscadd: Holy Water as a liquid is able to de-cult. Less effective, but less bloody. + May be changed over the course of time for balance. +2013-04-04: + SkyMarshal: + - bugfix: Fixed ZAS + - bugfix: Fixed Fire + Spamcat: + - bugfix: Blood type is now saved in character creation menu, no need to edit it + manually every round. +2013-04-09: + SkyMarshal: + - bugfix: Fire Issues (Firedoors, Flamethrowers, Incendiary Grenades) fixed. + - bugfix: Fixed a bad line of code that was preventing autoignition of flammable + gas mixes. + - bugfix: Volatile fuel is burned up after a point. + - rscdel: Partial-tile firedoors removed. This is due to ZAS breaking when interacting + with them. +2013-04-11: + SkyMarshal: + - experiment: Fire has been reworked. + - experiment: In-game variable editor is both readded and expanded with fire controlling + capability. +2013-04-17: + SkyMarshal: + - experiment: ZAS is now more deadly, as per decision by administrative team. May + be tweaked, but currently AIRFLOW is the biggest griefer. + - experiment: World startup optimized, many functions now delayed until a player + joins the server. (Reduces server boot time significantly) + - tweak: Zones will now equalize air more rapidly. + - bugfix: ZAS now respects active magboots when airflow occurs. + - bugfix: Airflow will no longer throw you into doors and open them. + - bugfix: Race condition in zone construction has been fixed, so zones connect properly + at round start. + - bugfix: Plasma effects readded. + - bugfix: Fixed runtime involving away mission. +2013-04-24: + Jediluke69: + - rscadd: Added 5 new drinks (Kira Special, Lemonade, Brown Star, Milkshakes, Rewriter) + - tweak: Nanopaste now heals about half of what it used to + - tweak: Ballistic crates should now come with shotguns loaded with actual shells + no more beanbags + - bugfix: Iced tea no longer makes a glass of .what? + NerdyBoy1104: + - rscadd: 'New Botany additions: Rice and Plastellium. New sheet material: Plastic.' + - rscadd: Plastellium is refined into plastic by first grinding the produce to get + plasticide. 20 plasticide + 10 polytrinic acid makes 10 sheets of plastic which + can be used to make crates, forks, spoons, knives, ashtrays or plastic bags + from. + - rscadd: Rice seeds grows into rice stalks that you grind to get rice. 10 Rice + + 5 Water makes boiled rice, 10 rice + 5 milk makes rice pudding, 10 rice + + 5 universal enzyme (in beaker) makes Sake. + faux: + - imageadd: Mixed Wardrobe Closet now has colored shoes and plaid skirts. + - imageadd: Dress uniforms added to the Captain, RD, and HoP wardrobe closets. A + uniform jacket has also been added to the Captain's closet. HoS' hat has been + re-added to their closet. I do not love the CMO and CE enough to give them anything. + - imageadd: Atheletic closet now has five different swimsuits *for the ladies* in + them. If you are a guy, be prepared to be yelled at if you run around like a + moron in one of these. Same goes for ladies who run around in shorts with their + titties swaying in the space winds. + - imageadd: A set of dispatcher uniforms will spawn in the security closet. These + are for playtesting the dispatcher role. + - imageadd: New suit spawns in the laundry room. It's for geezer's only. You're + welcome, Book. + - imageadd: Nurse outfit variant, orderly uniform, and first responder jacket will + now spawn in the medical wardrobe closet. + - imageadd: 'A white wedding dress will spawn in the chaplain''s closet. There are + also several dresses currently only adminspawnable. Admins: Look either under + "bride" or "dress." The bride one leads to the colored wedding dresses, and + there are some other kinds of dresses under dress.' + - tweak: No more luchador masks or boxing gloves or boxing ring. You guys have a + swimming pool now, dip in and enjoy it. + - tweak: he meeting hall has been replaced with an awkwardly placed security office + meant for prisoner processing. + - tweak: Added a couple more welding goggles to engineering since you guys liked + those a lot. + - imageadd: Flasks spawn behind the bar. Only three. Don't fight over them. I don't + know how to add them to the bar vending machine otherwise I would have done + that instead. Detective, you have your own flask in your office, it's underneath + the cigarettes on your desk. + - tweak: Added two canes to the medical storage, for people who have leg injuries + and can't walk good and stuff. I do not want to see doctors pretending to be + House. These are for patients. Do not make me delete this addition and declare + you guys not being able to have nice things. + - tweak: Secondary entance to EVA now directly leads into the medbay hardsuit section. + Sorry for any inconviences this will cause. The CMO can now fetch the hardsuits + whenever they want. + - tweak: Secondary security hardsuit has been added to the armory. Security members + please stop stealing engineer's hardsuits when you guys want to pair up for + space travel. + - tweak: Firelocks have been moved around in the main hallways to form really ghetto + versions of airlocks. + - tweak: Violin spawns in theatre storage now. I didn't put the piano there though, + that was someone else. + - tweak: Psych office in medbay has been made better looking. +2013-05-14: + Cael_Aislinn: + - experiment: Depth scanners can now be used to determine what material archaeological + deposits are made of, meaning lab analysis is no longer required. + - tweak: Some useability issues with xenoarchaeology tools have been resolved, and + the transit pods cycle automatically now. +2013-05-15: + Spamcat: + - rscadd: Added telescopic batons + to HoS's and captain's lockers. These are quite robust and easily concealable. +2013-05-21: + SkyMarshal: + - experiment: ZAS will now speed air movement into/out of a zone when unsimulated + tiles (e.g. space) are involved, in relation to the number of tiles. + - experiment: Portable Canisters will now automatically connect to any portable + connecter beneath them on map load. + - bugfix: Bug involving mis-mapped disposal junction fixed + - bugfix: Air alarms now work for atmos techs (whoops!) + - bugfix: The Master Controller now properly stops atmos when it runtimes. + - bugfix: Backpacks can no longer be contaminated + - tweak: ZAS no longer logs air statistics. + - tweak: ZAS now rebuilds as soon as it detects a semi-complex change in geometry. (It + was doing this already, but in a convoluted way which was actually less efficient) + - tweak: General code cleanup/commenting of ZAS + - tweak: Jungle now initializes after the random Z-level loads and atmos initializes. +2013-05-25: + Erthilo: + - bugfix: Fixes alien races appearing an unknown when speaking their language. + - bugfix: Fixes alien races losing their language when cloned. + - bugfix: Fixes UI getting randomly reset when trying to change it in Genetics Scanners. +2013-05-26: + Chinsky: + - rscadd: Tentacles! Now clone damage will make you horribly malformed like examine + text says. + Meyar: + - rscadd: The syndicate shuttle now has a cycling airlock during Nuke rounds. + - rscadd: Restored the ability for the syndicate Agent ID to change the name on + the card (reforge it) more than once. + - rscadd: ERT Radio now functional again. + - rscadd: 'Research blast doors now actually lock down the entirety of station-side + Research. ' + - rscadd: 'Added lock down buttons to the wardens office. ' + - rscadd: 'The randomized barsign has made a return. ' + - rscadd: Syndicate Agent ID's external airlock access restored. + VitrescentTortoise: + - rscadd: Added a third option for not getting any job preferences. It allows you + to return to the lobby instead of joining. +2013-05-28: + Erthilo: + - bugfix: Fixes everyone being able to understand alien languages. HERE IS YOUR + TOWER OF BABEL + VitrescentTortoise: + - bugfix: Wizard's forcewall now works. +2013-05-30: + Segrain: + - bugfix: Meteor showers actually spawn meteors now. + - tweak: Engineering tape fits into toolbelt and can be placed on doors. + - rscadd: Pill bottles can hold paper. + Spamcat: + - tweak: Pill bottle capacity increased to 14 items. + - bugfix: Fixed Lamarr (it now spawns properly) + proliberate: + - rscadd: Station time is now displayed in the status tab for new players and AIs. +2013-05-31: + Segrain: + - bugfix: Portable canisters now properly connect to ports beneath them on map load. + - bugfix: Fixed unfastening gas meters. +2013-06-01: + Chinsky: + - rscadd: Bloody footprints! Now stepping in the puddle will dirty your shoes/feet + and make you leave bloody footprints for a bit. + - rscadd: Blood now dries up after some time. Puddles take ~30 minutes, small things + 5 minutes. + - bugfix: Untreated wounds now heal. No more toe stubs spamming you with pain messages + for the rest of the shift. + - experiment: On the other side, everything is healed slowly. Maximum you cna squeeze + out of first aid is 0.5 health per tick per organ. Lying down makes it faster + too, by 1.5x factor. + - rscadd: Lids! Click beaker/bottle in hand to put them on/off. Prevent spilling + - rscadd: Added 'hailer' to security lockers. If used in hand, says "Halt! Security!". + For those who can't run and type. +2013-06-05: + Chinsky: + - rscadd: Load bearing equipment - webbings and vests for engineers and sec. Attach + to jumpsuit, use 'Look in storage' verb (object tab) to open. + Segrain: + - rscadd: Exosuits now can open firelocks by walking into them. +2013-06-06: + Asanadas: + - rscadd: Added a whimsical suit to the head of personnel's secret clothing locker. + Meyar: + - bugfix: Disposal's mail routing fixed. Missing pipes replaced. + - bugfix: 'Chemistry is once again a part of the disposals delivery circuit. ' + - bugfix: Added missing sorting junctions to Security and HoS office. + - bugfix: Fixed a duplicate sorting junction. +2013-06-09: + Segrain: + - bugfix: Emagged supply console can order SpecOp crates again. +2013-06-11: + Meyar: + - bugfix: Fixes a security door with a firedoor ontop of it. + - bugfix: Fixed a typo relating to the admin Select Equipment Verb. (It's RESPONSE + team not RESCUE team) + - rscadd: ERT are now automated, from their spawn to their shuttle. Admin intervention + no longer required! (Getting to the mechs still requires admin permission generally) + - rscadd: Added flashlights to compensate for the weakened PDA lights + - tweak: 'ERT Uniforms updated to be in line with Centcom uniforms. No more turtlenecks, + no sir. ' +2013-06-12: + Zuhayr: + - rscadd: Added pneumatic cannon and harpoons. + - experiment: Added embedded projectiles. Bullets and thrown weapons may stick in + targets. Throwing them by hand won't make them stick, firing them from a cannon + might. Implant removal surgery will get rid of shrapnel and stuck items. +2013-06-13: + Kilakk: + - rscadd: Added the Xenobiologist job. Has access to the research hallway and to + xenobiology. + - rscdel: Removed Xenobiology access from Scientists. + - rscdel: Removed the Xenobiologist alternate title from Scientists. + - rscadd: Added "Xenoarchaeology" to the RD, Scientists, and to the ID computer. + - tweak: Changed the Research Outpost doors to use "Xenoarchaeology" access. +2013-06-18: + Segrain: + - bugfix: Fixed some bugs in windoor construction. + - tweak: Secure windoors are made with rods again. + - rscadd: Windoors drop their electronics when broken. Emagged windoors can have + theirs removed by crowbar. + - rscadd: Airlock electronics can be configured to make door open for any single + access on it instead of all of them. + - rscadd: Cyborgs can preview their icons before choosing. +2013-06-21: + Jupotter: + - bugfix: Fix the robotiscist preview in the char setupe screen +2013-06-22: + Cael_Aislinn: + - tweak: The xenoarchaeology depth scanner will now tell you what energy field is + required to safely extract a find. + - tweak: Excavation picks will now dig faster, and xenoarchaeology as a whole should + be easier to do. +2013-06-23: + Segrain: + - rscadd: Airlocks of various models can be constructed again. + faux: + - experiment: There has been a complete medbay renovation spearheaded by Vetinarix. + http://baystation12.net/forums/viewtopic.php?f=20&t;=7847 <-- Please + put any commentary good or bad, here. + - tweak: Some maintenance doors within RnD and Medbay have had their accesses changed. + Maintenance doors in the joint areas (leading to the research shuttle, virology, + and xenobiology) are now zero access. Which means anyone in those joints can + enter the maintenance tunnels. This was done to add additional evacuation locations + during radiation storms. Additional maintenance doors were added to the tunnels + in these areas to prevent docs and scientists from running about. + - tweak: Starboard emergency storage isn't gone now, it's simply located in the + escape wing. + - experiment: An engineering training room has been added to engineering. This location + was previously where surgery was located. If you are new to engineering or need + to brush up on your skills, please use this area for testing. +2013-06-26: + Segrain: + - bugfix: Autopsy scanner properly displays time of wound infliction and death. + - bugfix: Autopsy scanner properly displays wounds by projectile weapons. + Whitellama: + - bugfix: One-antag rounds (like wizard/ninja) no longer end automatically upon + death + - wip: Space ninja has been implemented as a voteable gamemode + - rscadd: Space ninja spawn landmarks have been implemented (but not yet placed + on the map), still spawn at carps-pawns instead. (The code will warn you about + this and ask you to report it, it's a known issue.) + - rscadd: Five new space ninja directives have been added, old directives have been + reworded to be less harsh + - wip: Space ninjas have been given their own list as antagonists, and are no longer + bundled up with traitors + - bugfix: Space ninjas with a "steal a functional AI" objective will now succeed + by downloading one into their suits + - tweak: Space ninja suits' exploding on death has been nerfed, so as not to cause + breaches + - rscadd: A few space ninja titles/names have been added and removed to be slightly + more believable + - bugfix: The antagonist selector no longer chooses jobbanned players when it runs + out of willing options +2013-06-27: + Segrain: + - bugfix: ID cards properly setup bloodtype, DNA and fingerprints again. +2013-06-28: + Segrain: + - rscadd: AIs are now able to examine what they see. +2013-07-03: + Segrain: + - rscadd: Security and medical cyborgs can use their HUDs to access records. +2013-07-05: + Spamcat: + - rscadd: Pulse! Humans now have hearbeat rate, which can be measured by right-clicking + someone - Check pulse or by health analyzer. Medical machinery also has heartbeat + monitors. Certain meds and conditions can influence it. +2013-07-06: + Chinsky: + - rscadd: Humans now can be infected with more than one virus at once. + - rscadd: All analyzed viruses are put into virus DB. You can view it and edit their + name and description on medical record consoles. + - tweak: 'Only known viruses (ones in DB) will be detected by the machinery and + HUDs. ' + - rscadd: Viruses cause fever, body temperature rising the more stage is. + - bugfix: Humans' body temperature does not drift towards room one unless there's + big difference in them. + - tweak: Virus incubators now can transmit viuses from dishes to blood sample. + - rscadd: New machine - centrifuge. It can isolate antibodies or viruses (spawning + virus dish) from a blood sample in vials. Accepts vials only. + - rscadd: Fancy vial boxes in virology, one of them is locked by ID with MD access. + - tweak: Engineered viruses are now ariborne too. +2013-07-11: + Chinsky: + - rscadd: Gun delays. All guns now have delays between shots. Most have less than + second, lasercannons and pulse rifles have around 2 seconds delay. Automatics + have zero, click-speed. +2013-07-26: + Kilakk: + - bugfix: Brig cell timers will no longer start counting down automatically. + - tweak: Separated the actual countdown timer from the timer controls. Pressing + "Set" while the timer is counting down will reset the countdown timer to the + time selected. +2013-07-28: + Segrain: + - rscadd: Camera console circuits can be adjusted for different networks. + - rscadd: Nuclear operatives and ERT members have built-in cameras in their helmets. + Activate helmet to initialize it. +2013-07-30: + Erthilo: + - bugfix: EFTPOS and ATM machines should now connect to databases. + - bugfix: Gravitational Catapults can now be removed from mechs. + - bugfix: Ghost manifest rune paper naming now works correctly. + - bugfix: Fix for newscaster special characters. Still not recommended. + Kilakk: + - rscadd: Added colored department radio channels. +2013-08-01: + Asanadas: + - tweak: The Null Rod has recovered its de-culting ability, for balance reasons. + Metagaming with it is a big no-no! + - rscadd: Holy Water as a liquid is able to de-cult. Less effective, but less bloody. + May be changed over the course of time for balance. + CIB: + - bugfix: Chilis and cold chilis no longer kill in small amounts + - bugfix: Chloral now again needs around 5 units to start killing somebody + Cael Aislinn: + - rscadd: Security bots will now target hostile mobs, and vice versa. + - tweak: Carp should actually emigrate now, instead of just immigrating then squatting + around the outer hull. + - tweak: Admins and moderators have been split up into separate 'who' verbs (adminwho + and modwho respectively). + CaelAislinn: + - rscadd: Re-added old ion storm laws, re-added grid check event. + - rscadd: Added Rogue Drone and Vermin Infestation random events. + - rscadd: Added/fixed space vines random event. + - tweak: Updates to the virus events. + - tweak: Spider infestation and alien infestation events turned off by default. + - tweak: Soghun, taj and skrell all have unique language text colours. + - tweak: Moderators will no longer be listed in adminwho, instead use modwho. + Cael_Aislinn: + - tgs: Updated server to tgstation r5200 (November 26th, 2012), see https://code.google.com/p/tgstation13/source/list + for tg's changelog. + Chinsky: + - rscadd: 'Old new medical features:' + - rscadd: Autoinjectors! They come preloaded with 5u of inapro, can be used instantly, + and are one-use. You can replace chems inside using a syringe. Box of them is + added to Medicine closet and medical supplies crate. + - rscadd: Splints! Target broken liimb and click on person to apply. Can be taken + off in inventory menu, like handcuffs. Splinted limbs have less negative effects. + - rscadd: Advanced medikit! Red and mean, all doctors spawn with one. Contains better + stuff - advanced versions of bandaids and aloe heal 12 damage on the first use. + - tweak: Wounds with damage above 50 won't heal by themselves even if bandaged/salved. + Would have to seek advanced medical attention for those. + Erthilo: + - bugfix: Fixed SSD (logged-out) players not staying asleep. + - bugfix: Fixed set-pose verb and mice emotes having extra periods. + - bugfix: Fixed virus crate not appearing and breaking supply shuttle. + - bugfix: Fixed newcaster photos not being censored. + Gamerofthegame: + - rscadd: Miscellaneous mapfixes. + GauHelldragon: + - rscadd: Servicebots now have RoboTray and Printing Pen. Robotray can be used to + pick up and drop food/drinks. Printing pen can alternate between writing mode + and rename paper mode by clicking it. + - rscadd: Farmbots. A new type of robot that weeds, waters and fertilizes. Use robot + arm on water tank. Then use plant analyzer, mini-hoe, bucket and finally proximity + sensor. + - rscadd: Chefs can clang their serving trays with a rolling pin. Just like a riot + shield! + Jediluke69: + - rscadd: Added 5 new drinks (Kira Special, Lemonade, Brown Star, Milkshakes, Rewriter) + - tweak: Nanopaste now heals about half of what it used to + - tweak: Ballistic crates should now come with shotguns loaded with actual shells + no more beanbags + - bugfix: Iced tea no longer makes a glass of .what? + Jupotter: + - bugfix: Fix the robotiscist preview in the char setupe screen + Kilakk: + - rscadd: Added the Xenobiologist job. Has access to the research hallway and to + xenobiology. + - rscdel: Removed Xenobiology access from Scientists. + - rscdel: Removed the Xenobiologist alternate title from Scientists. + - rscadd: Added "Xenoarchaeology" to the RD, Scientists, and to the ID computer. + - tweak: Changed the Research Outpost doors to use "Xenoarchaeology" access. + Meyar: + - rscadd: The syndicate shuttle now has a cycling airlock during Nuke rounds. + - rscadd: Restored the ability for the syndicate Agent ID to change the name on + the card (reforge it) more than once. + - rscadd: ERT Radio now functional again. + - rscadd: 'Research blast doors now actually lock down the entirety of station-side + Research. ' + - rscadd: 'Added lock down buttons to the wardens office. ' + - rscadd: 'The randomized barsign has made a return. ' + - rscadd: Syndicate Agent ID's external airlock access restored. + NerdyBoy1104: + - rscadd: 'New Botany additions: Rice and Plastellium. New sheet material: Plastic.' + - rscadd: Plastellium is refined into plastic by first grinding the produce to get + plasticide. 20 plasticide + 10 polytrinic acid makes 10 sheets of plastic which + can be used to make crates, forks, spoons, knives, ashtrays or plastic bags + from. + - rscadd: Rice seeds grows into rice stalks that you grind to get rice. 10 Rice + + 5 Water makes boiled rice, 10 rice + 5 milk makes rice pudding, 10 rice + + 5 universal enzyme (in beaker) makes Sake. + RavingManiac: + - rscadd: You can now stab people with syringes using the "harm" intent. This destroys + the syringe and transfers a random percentage of its contents into the target. + Armor has a 50% chance of blocking the syringe. + Segrain: + - bugfix: Meteor showers actually spawn meteors now. + - tweak: Engineering tape fits into toolbelt and can be placed on doors. + - rscadd: Pill bottles can hold paper. + SkyMarshal: + - bugfix: Fixed ZAS + - bugfix: Fixed Fire + Spamcat: + - rscadd: Figured I should make one of these. Syringestabbing now produces a broken + syringe complete with fingerprints of attacker and blood of a victim, so dispose + your evidence carefully. Maximum transfer amount per stab is lowered to 10. + VitrescentTortoise: + - rscadd: Added a third option for not getting any job preferences. It allows you + to return to the lobby instead of joining. + Whitellama: + - bugfix: One-antag rounds (like wizard/ninja) no longer end automatically upon + death + - wip: Space ninja has been implemented as a voteable gamemode + - rscadd: Space ninja spawn landmarks have been implemented (but not yet placed + on the map), still spawn at carps-pawns instead. (The code will warn you about + this and ask you to report it, it's a known issue.) + - rscadd: Five new space ninja directives have been added, old directives have been + reworded to be less harsh + - wip: Space ninjas have been given their own list as antagonists, and are no longer + bundled up with traitors + - bugfix: Space ninjas with a "steal a functional AI" objective will now succeed + by downloading one into their suits + - tweak: Space ninja suits' exploding on death has been nerfed, so as not to cause + breaches + - rscadd: A few space ninja titles/names have been added and removed to be slightly + more believable + - bugfix: The antagonist selector no longer chooses jobbanned players when it runs + out of willing options + Zuhayr: + - rscadd: Added pneumatic cannon and harpoons. + - experiment: Added embedded projectiles. Bullets and thrown weapons may stick in + targets. Throwing them by hand won't make them stick, firing them from a cannon + might. Implant removal surgery will get rid of shrapnel and stuck items. + faux: + - imageadd: Mixed Wardrobe Closet now has colored shoes and plaid skirts. + - imageadd: Dress uniforms added to the Captain, RD, and HoP wardrobe closets. A + uniform jacket has also been added to the Captain's closet. HoS' hat has been + re-added to their closet. I do not love the CMO and CE enough to give them anything. + - imageadd: Atheletic closet now has five different swimsuits *for the ladies* in + them. If you are a guy, be prepared to be yelled at if you run around like a + moron in one of these. Same goes for ladies who run around in shorts with their + titties swaying in the space winds. + - imageadd: A set of dispatcher uniforms will spawn in the security closet. These + are for playtesting the dispatcher role. + - imageadd: New suit spawns in the laundry room. It's for geezer's only. You're + welcome, Book. + - imageadd: Nurse outfit variant, orderly uniform, and first responder jacket will + now spawn in the medical wardrobe closet. + - imageadd: 'A white wedding dress will spawn in the chaplain''s closet. There are + also several dresses currently only adminspawnable. Admins: Look either under + "bride" or "dress." The bride one leads to the colored wedding dresses, and + there are some other kinds of dresses under dress.' + - tweak: No more luchador masks or boxing gloves or boxing ring. You guys have a + swimming pool now, dip in and enjoy it. + - tweak: he meeting hall has been replaced with an awkwardly placed security office + meant for prisoner processing. + - tweak: Added a couple more welding goggles to engineering since you guys liked + those a lot. + - imageadd: Flasks spawn behind the bar. Only three. Don't fight over them. I don't + know how to add them to the bar vending machine otherwise I would have done + that instead. Detective, you have your own flask in your office, it's underneath + the cigarettes on your desk. + - tweak: Added two canes to the medical storage, for people who have leg injuries + and can't walk good and stuff. I do not want to see doctors pretending to be + House. These are for patients. Do not make me delete this addition and declare + you guys not being able to have nice things. + - tweak: Secondary entance to EVA now directly leads into the medbay hardsuit section. + Sorry for any inconviences this will cause. The CMO can now fetch the hardsuits + whenever they want. + - tweak: Secondary security hardsuit has been added to the armory. Security members + please stop stealing engineer's hardsuits when you guys want to pair up for + space travel. + - tweak: Firelocks have been moved around in the main hallways to form really ghetto + versions of airlocks. + - tweak: Violin spawns in theatre storage now. I didn't put the piano there though, + that was someone else. + - tweak: Psych office in medbay has been made better looking. + proliberate: + - rscadd: Station time is now displayed in the status tab for new players and AIs. +2013-08-04: + Chinsky: + - rscadd: Health HUD indicator replaced with Pain indicator. Now health indicator + shows pain level instead of actual vitals level. Some types of damage contribute + more to pain, some less, usually feeling worse than they really are. +2013-08-08: + Erthilo: + - bugfix: Raise Dead rune now properly heals and revives dead corpse. + - bugfix: Admin-only rejuvenate verb now heals all organs, limbs, and diseases. + - bugfix: Cyborg sprites now correctly reset with reset boards. This means cyborg + appearances can now be changed without admin intervention. +2013-09-18: + Kilakk: + - rscadd: Fax machines! The Captain and IA agents can use the fax machine to send + properly formatted messages to Central Command. + - imageadd: Gave the fax machine a fancy animated sprite. Thanks Cajoes! +2013-09-24: + Snapshot: + - rscdel: Removed hidden vote counts. + - rscdel: Removed hiding of vote results. + - rscdel: Removed OOC muting during votes. + - rscadd: Crew transfers are no longer callable during Red and Delta alert. + - wip: Started work on Auto transfer framework. +2013-10-06: + Chinsky: + - rscadd: Return of dreaded side effects. They now manifest well after their cause + disappears, so curing them should be possible without them reappearing immediately. + They also lost last stage damaging effects. +2013-10-29: + Cael_Aislinn: + - rscadd: Xenoarchaeology's chemical analysis and six analysis machines are gone, + replaced by a single one which can be beaten in a minigame. + - rscadd: Sneaky traitors will find new challenges to overcome at the research outpost, + but may also find new opportunities (transit tubes can now be traversed). + - rscadd: Finding active alien machinery should now be made significantly easier + with the Alden-Saraspova counter. +2013-11-01: + Various: + - rscadd: Autovoting, Get off the station when your 15 hour workweek is done, thanks + unions! + - rscadd: Some beach props that Chinsky finds useless. + - wip: Updated NanoUI + - rscadd: Dialysis while in sleepers - removes reagents from mobs, like the chemist, + toss him in there! + - tweak: Pipe Dispensers can now be ordered by Cargo + - rscadd: Fancy G-G-G-G-Ghosts! +2013-11-23: + Ccomp5950: + - bugfix: Players are now no longer able to commit suicide with a lasertag gun, + and will feel silly for doing so. + - bugfix: Ghosts hit with the cult book shall now actually become visible. + - bugfix: The powercells spawned with Exosuits will now properly be named to not + confuse bearded roboticists. + - bugfix: Blindfolded players will now no longer require eye surgery to repair their + sight, removing the blindfold will be sufficient. + - rscadd: Atmospheric Technicians will now have access to Exterior airlocks. +2013-11-24: + Yinadele: + - experiment: Supermatter engine added! Please treat your new engine gently, and + report any strangeness! + - tweak: Rebalanced events so people don't explode into appendicitis or have their + organs constantly explode. + - rscadd: Vending machines have had bottled water, iced tea, and grape soda added. + - rscadd: Head reattachment surgery added! Sew heads back on proper rather than + monkey madness. + - rscadd: Pain crit rebalanced - Added aim variance depending on pain levels, nerfed + blackscreen severely. + - rscadd: 'Cyborg alt titles: Robot, and Android added! These will make you spawn + as a posibrained robot. Please enjoy!' + - bugfix: Fixed the sprite on the modified welding goggles, added a pair to the + CE's office where they'll be used. + - bugfix: Fixed atmos computers- They are once again responsive! + - tweak: Added in functionality proper for explosive implants- You can now set their + level of detonation, and their effects are more responsively concrete depending + on setting. + - rscadd: Hemostats re-added to autolathe! + - rscadd: Added two manuals on atmosia and EVA, by MagmaRam! Found in engineering + and the engineering bookcase. + - bugfix: Fixed areas in medbay to have fully functional APC sectors. + - rscadd: Girders are now lasable. + - experiment: Please wait warmly, new features planned for next merge! +2013-12-01: + 'Various Developers banged their keyboards together:': + - rscadd: New Engine, the supermatter, figure out what a cooling loop is, or don't + and blow up engineering! + - rscadd: Each department will have it's own fax, make a copy of your butt and fax + it to the admins! + - rscadd: Booze and soda dispensers, they are like chemmasters, only with booze + and soda! + - rscadd: Bluespace and Cryostasis beakers, how do they work? Fuggin bluespace + how do they work? + - rscadd: You can now shove things into vending machines, impress your friends on + how things magically disappear out of your hands into the machine! + - rscadd: Robots and Androids (And gynoids too!) can now use custom job titles + - bugfix: Various bugfixes +2013-12-18: + RavingManiac: + - rscadd: Mousetraps can now be "hidden" through the right-click menu. This makes + them go under tables, clutter and the like. The filthy rodents will never see + it coming! + - tweak: Monkeys will no longer move randomly while being pulled. +2014-01-01: + Various: + - rscadd: AntagHUD and MedicalHUD for ghosts, see who the baddies are, check for + new configuration options. + - rscadd: Ghosts will now have bold text if they are in the same room as the person + making conversations easier to follow. + - rscadd: New hairstyles! Now you can use something other then hotpink floor length + braid. + - wip: DNA rework, tell us how you were cloned and became albino! + - rscadd: Dirty floors, so now you know exactly how lazy the janitors are! + - rscadd: A new UI system, feel free to color it yourself, don't set it to completely + clear or you will have a bad time. + - rscadd: Cryogenic storage, for all your SSD needs. + - rscadd: New hardsuits for those syndicate tajaran +2014-02-01: + Various: + - rscadd: NanoUI for PDA + - rscadd: Write in blood while a ghost in cult rounds with enough cultists + - rscadd: Cookies, absurd sandwiches, and even cookable dioanae nymphs! + - rscadd: A bunch of new guns and other weapons + - rscadd: Species specific blood +2014-02-19: + Aryn: + - experiment: New air model. Nothing should change to a great degree, but temperature + flow might be affected due to closed connections not sticking around. +2014-03-01: + Various: + - rscadd: Paint Mixing, red and blue makes purple! + - rscadd: New posters to tell you to respect those darned cat people + - rscadd: NanoUI for APC's, Canisters, Tank Transfer Valves and the heaters / coolers + - tweak: PDA bombs are now less annoying, and won't always blow up / cause internal + bleeding + - tweak: Blob made less deadly + - rscadd: Objectiveless Antags now a configuration option, choose your own adventure! + - wip: Engineering redesign, now with better monitoring of the explodium supermatter! + - rscadd: Security EOD + - rscadd: New playable race, IPC's, go beep boop boop all over the station! + - rscadd: Gamemode autovoting, now players don't have to call for gamemode votes, + it's automatic! +2014-03-05: + RavingManiac: + - rscadd: Smartfridges added to the bar, chemistry and virology. No more clutter! + - rscadd: A certain musical instrument has returned to the bar. + - rscadd: There is now a ten second delay between ingesting a pill/donut/milkshake + and regretting it. +2014-03-10: + Chinsky: + - rscadd: Viruses now affect certain range of species, different for each virus + - tweak: Spaceacilline now prevents infection, and has a small chance to cure viruses + at Stage 1. It does not give them antibodies though, so they can get sick again! + - tweak: Biosuits and spacesuits now offer more protection against viruses. Full + biosuit competely prevents airborne infection, when coupled with gloves they + both protect quite well from contact ones + - rscadd: Sneezing now spreads viruses in front of mob. Sometimes he gets a warning + beforehand though +2014-03-30: + RavingManiac: + - rscadd: Inflatable walls and doors added. Useful for sealing off hull breaches, + but easily punctured by sharp objects and Tajarans. +2014-04-06: + RavingManiac: + - tweak: Tape recorders and station-bounced radios now work inside containers and + closets. +2014-04-11: + Jarcolr: + - rscadd: You can now flip coins like a D2 + - tweak: Miscellaneous cargo crates got a tiny buff, Standard Costume crate is now + Costume Crate + - tweak: Grammar patch,telekinesis/amputated arm exploit fixes,more in the future + - tweak: Grille kicking now does less damage + - tweak: TELESCOPIC baton no longer knocks anybody down,still got a lot of force + though + - tweak: Other small-ish changes and fixes that aren't worth mentioning +2014-04-25: + Various: + - rscadd: Overhauled saycode, you can now use languages over the radio. + - rscadd: Chamelon items beyond just the suit. + - rscadd: NanoUI Virology + - rscadd: 3D Sounds + - rscadd: AI Channel color for when they want to be all sneaky + - rscadd: New inflatable walls and airlocks for your breach sealing pleasure. + - rscadd: Carbon Copy papers, so you can subject everyone to your authority and + paperwork, but mainly paperwork + - rscadd: Undershirts and rolling down jumpsuits + - rscadd: Insta-hit tasers, can be shot through glass as well. + - rscadd: Changeling balances, an emphasis put more on stealth. + - rscdel: Genetics disabled + - rscdel: Telescience removed, might be added again when we come up with a less + math headache enducing version of it. + - bugfix: Bugfixes galore! +2014-04-29: + HarpyEagle: + - rscadd: Webbing vest storage can now be accessed by clicking on the item in inventory + - rscadd: Holsters can be accessed by clicking on them in inventory + - rscadd: Webbings and other suit attachments are now visible on the icon in inventory + - tweak: Removing jumpsuits now requires drag and drop to prevent accidental undressing + - rscadd: Added an action icon for magboots that can be used to toggle them similar + to flashlights + - rscadd: Fuel tanks now spill fuel when wrenched open +2014-05-03: + Cael_Aislinn: + - rscadd: "Coming out of nowhere the past few months, the Garland Corporation has\ + \ made headlines with a new prehistoric theme park delighting travellers with\ + \ species thought extinct. Now available for research stations everywhere is\ + \ the technology that made it all possible! Features include:
    \n\t\t\t-\ + \ 13 discoverable prehistoric species to clone from fossils (including 5 brand\ + \ new ones).
    \n\t\t\t- 11 discoverable prehistoric plants to clone from fossils\ + \ (including 9 brand new ones).
    \n\t\t\t- New minigame that involves correctly\ + \ ordering the genomes inside each genetic sequence to unlock an animal/plant.
    \n\ + \t\t\t- Some prehistoric animals and plants may seem strangely familiar... while\ + \ others may bring more than the erstwhile scientist bargains for.
    \n




    " +2014-05-06: + Hubble: + - rscadd: Clip papers together by hitting a paper with a paper or photo + - imageadd: Adds icons for copied stamps +2014-05-16: + HarpyEagle: + - rscadd: Silicon mob types (AI, cyborgs, PAI) can now speak certain species languages + depending on type and module + - rscadd: Languages can now be whispered when using the language code with either + the whisper verb or the whisper speech code +2014-05-23: + Hubble: + - rscadd: Personal lockers are now resettable + - rscadd: Take off people's accessories or change their sensors in the drag and + drop-interface + - rscadd: Merge paper bundles by hitting one with another + - tweak: Line breaks in Security, Medical and Employment Records + - tweak: Record printouts will have names on it + - tweak: Set other people's internals in belt and suit storage slots + - bugfix: No longer changing suit sensors while cuffed + - bugfix: No longer emptying other people's pockets when they are not full yet +2014-05-28: + Chinsky: + - rscadd: Adds few new paperBBcode tags, to make up for HTML removal. + - rscadd: '[logo] tag draws NT logo image (one from wiki).' + - rscadd: '[table] [/table] tags mark borders of tables. [grid] [/grid] are borderless + tables, useful of making layouts. Inside tables following tags are used: [row] + marks beginning of new table row, [cell] - beginning of new table cell.' +2014-05-31: + Jarcolr: + - rscadd: 21 New cargo crates, go check them out! + - rscadd: Peanuts have now been added, food items are now being developed. + - rscadd: 2 new cargo groups, Miscellaneous and Supply. + - rscadd: Sugarcane seeds can now be gotten from the seed dispenser. + - rscadd: 5 new satchels when selecting "satchel" for RD, scientist, botanist, virologist, + geneticist (disabled) and chemist. + - rscadd: Clicking on a player with a paper/book when you have the eyes selected + shows them the book/paper forcefully. +2014-06-03: + Hubblenaut: + - rscadd: Added wheelchairs + - tweak: Replaced stool in Medical Examination with wheelchair + - tweak: Using a fire-extinguisher to propel you on a chair can have consequences + (drive into walls and people, do it!) +2014-06-13: + HarpyEagle: + - rscadd: Added docking ports for shuttles + - rscadd: Shuttle airlocks will automatically open and close, preventing people + from being sucked into space by because someone on another z-level called a + shuttle + - rscadd: Some docking ports can also double as airlocks + - rscadd: Docking ports can be overriden to prevent any automatic action. Shuttles + will wait for players to open/close doors manually + - rscadd: Shuttles can be forced launched, which will make them not wait for airlocks + to be properly closed +2014-06-15: + HarpyEagle: + - bugfix: Fixed wound autohealing regardless of damage amount. The appropriate wound + will now be assigned correctly based on damage amount and type + - bugfix: Fixed several other bugs related wounds that resulted in damage magically + disappearing + - bugfix: Fixed various sharp objects not being counted as sharp, bullets in particular + - bugfix: Fixed armour providing more protection from bullets than it was supposed + to +2014-06-19: + Chinsky: + - rscadd: Adds guest terminals on the map. These wall terminals let anyone issue + temporary IDs. Only access that issuer has can be granted, and maximum time + pass can be issued for is 20 minutes. All operations are logged in terminals. +2014-06-20: + Cael_Aislinn: + - rscadd: 'New discoverable items added to xenoarchaeology, and new features for + some existing ones. Artifact harvesters can now harvest the secondary effect + of artifacts as well as the primary one.
    + +
    ' + - tweak: 'Artifact utilisers should be much nicer/easier to use now.
    + +
  • Alden-Saraspova counters and talking items should work properly + now.
    + +
  • + +
    ' +2014-07-01: + Various: + - experiment: Hardsuit breaching. + - experiment: Rewritten fire. + - experiment: Supermatter now glows and sucks things into it as it approaches criticality. + - rscadd: Station Vox (Vox pariahs) are now available. + - rscadd: Wheelchairs. + - rscadd: Cargo Trains. + - rscadd: Hardsuit cycler machinery. + - rscadd: Rewritten lighting (coloured lights!) + - rscadd: New Mining machinery and rewritten smelting. + - rscadd: Rewritten autolathe + - rscadd: Mutiny mode. + - rscadd: NanoUI airlock and docking controllers. + - rscadd: Completely rewritten shuttle code. + - rscadd: 'Derelict Z-level replacement: construction site.' + - rscadd: Computer3 laptops. + - rscadd: Constructable SMES units. + - rscadd: Omni-directional atmos machinery. + - rscadd: Climbable tables and crates. + - rscadd: Xenoflora added to Science. + - rscadd: Utensils can be used to eat food. + - rscadd: Decks of cards are now around the station. + - rscadd: Service robots can speak languages. + - wip: Xenoarch updates and fixes. + - tweak: Rewritten species-specific gear icon handling. + - tweak: Cats and borers can be picked up. + - tweak: Botanist renamed to Gardener. + - tweak: Hydroponics merged with the Kitchen. + - tweak: Latejoin spawn points (Arrivals, Cryostorage, Gateway). + - rscadd: Escape pods only launch automatically during emergency evacuations + - rscadd: Escape pods can be made to launch during regular crew transfers using + the control panel inside the pod, or by emagging the panel outside the pod + - rscadd: When swiped or emagged, the crew transfer shuttle can be delayed in addition + to being launched early +2014-07-06: + HarpyEagle: + - rscadd: Re-enabled and rewrote the wound infection system + - rscadd: Infections can be prevented by properly bandaging and salving wounds + - rscadd: Infections are cured by spaceacillin +2014-07-20: + PsiOmegaDelta: + - rscadd: AI can now store up to five camera locations and return to them when desired. + - rscadd: AI can now alt+left click turfs in camera view to list and interact with + the objects. + - rscadd: AI can now ctrl+click turret controls to enable/disable turrets. + - rscadd: AI can now alt+click turret controls to toggle stun/lethal mode. + - rscadd: AI can now select which channel to state laws on. +2014-07-26: + Whitellama: + - rscadd: Added dynamic flavour text. + - bugfix: Fixed bug with suit fibers and fingerprints. +2014-07-31: + HarpyEagle: + - tweak: Stun batons now work like tasers and deal agony instead of stun + - rscadd: Being hit in the hands with a stun weapon will cause whatever is being + held to be dropped + - tweak: Handcuffs now require an aggressive grab to be used +2014-08-02: + Whitellama: + - bugfix: Arcane tomes can now be stored on bookshelves. + - bugfix: Dionaea players no longer crash on death, and now become nymphs properly. +2014-08-05: + HarpyEagle: + - tweak: Atmos Rewrite. Many atmos devices now use power according to their load + and gas physics + - rscadd: Pressure regulator device. Replaces the passive gate and can regulate + input or output pressure + - rscadd: Gas heaters and gas coolers are now constructable and can be upgraded + with parts from research + - bugfix: Fixes recharger and cell charger power draw. Rechargers draw 15 kW, wall + chargers draw 25 kW, and heavy-duty cell chargers draw 40 kW. Cyborg charging + stations draw 75 kW. + - bugfix: Laptops, and various other machines, now draw more reasonable amounts + of power + - bugfix: Machines will periodically update their powered status if moved from a + powered to an unpowered area and vice versa +2014-08-27: + Whitellama: + - bugfix: Made destination taggers more intuitive so you know when you've tagged + something + - rscadd: Ported package label and tag sprites + - rscadd: Ported using a pen on a package to give it a title, or to write a note + - rscadd: Donut boxes and egg boxes can be constructed out of cardboard +2014-08-31: + Whitellama: + - bugfix: Matches and candles can be used to burn papers, too. + - bugfix: Observers have a bit more time (20 seconds, instead of 7.5) before the + Diona join prompt disappears. +2014-09-05: + RavingManiac: + - experiment: 'NewPipe implemented: Supply and scrubber pipes can be run in parallel + without connecting to each other.' + - rscadd: Supply pipes will only connect to supply pipes, vents and Universal Pipe + Adapters(UPAs). + - rscadd: Scrubber pipes will only connect to scrubber pipes, scrubbers and UPAs. + - rscadd: UPAs will connect to regular, scrubber and supply pipes. +2014-09-20: + HarpyEagle: + - bugfix: Fixes evidence bags and boxes eating each other. Evidence bags now store + items by dragging the bag onto the item to be stored. +2014-09-28: + Gamerofthegame: + - rscadd: Hoverpods fully supported, currently orderable from cargo. Two slots, + three cargo, space flight and a working mech for all other intents and purposes. + - rscadd: Added the Rigged laser and Passenger Compartment equipment. The rigged + laser is a weapon for working exosuits - just a ordinary laser, but with triple + the cool down and rather power inefficient. The passenger compartment allows + other people to board and hitch a ride on the mech - such as in fire rescue + or for space flight. + Zuhayr: + - rscadd: Organs can now be removed and transplanted. + - tweak: Brain surgery is now the same as chest surgery regarding the steps leading + up to it. + - tweak: Appendix and kidney now share the groin and removing the first will prevent + appendicitis. + - tweak: Lots of backend surgery/organ stuff, see the PR if you need to know. +2014-10-01: + RavingManiac: + - rscadd: Zooming with the sniper rifle now adds a view offset in the direction + you are facing. + - rscadd: Added binoculars - functionally similar to sniper scope. Adminspawn-only + for now. + - rscadd: Bottles from chemistry now, like beakers, use chemical overlays instead + of fixed sprites. + - rscadd: Being in space while not magbooted to something will cause your sprite + to bob up and down. + Zuhayr: + - rscadd: Added species organ checks to several areas (phoron burn, welder burn, + appendicitis, vox cortical stacks, flashes). + - rscadd: Added VV option to add or remove organs. + - rscadd: Added simple bioprinter (adminspawn). + - rscadd: Added smashing/slashing behavior from xenos to some unarmed attacks. + - rscadd: Added some new state icons for diona nymphs. + - rscadd: Added borer husk functionality (cortical borers can turn dead humans into + zombies). + - rscadd: Added tackle verb. + - rscadd: Added NO_SLIP. + - rscadd: Added species-specific orans to Dionaea, new Xenomorphs and vox. + - rscadd: Added colour and species to blood data. + - rscadd: Added lethal consequences to missing your heart. + - rscdel: Removed robot_talk_understand and alien_talk_understand. + - rscdel: Removed attack_alien() and several flavours of is_alien() procs. + - rscdel: Removed /mob/living/carbon/alien/humanoid. + - rscdel: Removed alien_hud(). + - rscdel: Removed IS_SLOW, NEEDS_LIGHT and RAD_ABSORB. + - rscdel: Renamed is_larva() to is_alien(). + - tweak: Refactored a ton of files, either condensing or expanding them, or moving + them to new directories. + - tweak: Refactored some attack vars from simple_animal to mob/living level. + - tweak: Refactored internal organs to /mob/living/carbon level. + - tweak: Refactored rad and light absorbtion to organ level. + - tweak: Refactored brains to /obj/item/organ/brain. + - tweak: Refactored a lot of blood splattering to use blood_splatter() proc. + - tweak: Refactored broadcast languages (changeling and alien hiveminds, drone and + binary chat) to actual languages. + - tweak: Refactored xenomorph abilities to work for humans. + - tweak: Refactored xenomorphs into human species. + - tweak: Rewrote larva_hud() and human_hud(). The latter now takes data from the + species datum. + - tweak: Rewrote diona nymphs as descendents of /mob/living/carbon/alien. + - tweak: Rewrote xenolarva as descendents of /mob/living/carbon/alien. + - tweak: Rewrote /mob/living/carbon/alien. + - tweak: Moved alcohol and toxin processing to the liver. + - tweak: Moved drone light proc to robot level, added integrated_light_power and + local_transmit vars to robots. + - tweak: Moved human brainloss onto the brain organ. + - tweak: Shuffled around and collapsed several redundant procs down to carbon level + (hide, ventcrawl, Bump). + - tweak: Fixed species swaps from NO_BLOOD to those with blood killing the subject + instantly. +2014-11-01: + PsiOmegaDelta: + - bugfix: Adds the last missing step to deconstruct fire alarms. Apply wirecutters. + - rscadd: There's a "new" mining outpost nearby the Research outpost. + - rscadd: Manifest ghosts now have spookier names. + - rscadd: Adds a gas monitor computer for the toxin mixing chamber. + - rscadd: AI can now change the display of individual AI status screens. + - rscadd: More ion laws.. + - rscadd: All turrets have been replaced with portable variants. Potential targets + can be configured on a per turret basis. + - bugfix: Improved crew monitor map positioning. + - rscadd: Can now order plastic, body-, and statis bags from cargo + - rscadd: PDAs now receive newscasts. + - rscadd: (De)constructable emergency shutters. + - rscadd: Borgs can now select to simply state their laws or select a radio channel, + same as the AI. +2014-11-04: + TwistedAkai: + - rscadd: Almost any window which has been fully unsecured can now be dismantled + with a wrench. +2014-11-08: + PsiOmegaDelta: + - rscadd: Service personnel now have their own frequency to communicate over. Use + "say :v". + - rscadd: The AI can now has proper quick access to its private channel. Use "say + :o". + - rscadd: Newscasters supports photo captions. Simply pen one on the attached photo. + - rscadd: Once made visible by a cultist ghosts can toggle visiblity at will. + - rscadd: Detonating cyborgs using the cyborg monitor console now notifies the master + AI, if any. + - rscadd: More machinery, such as APCs, air alarms, etc., now support attaching + signalers to the wires. + - tweak: Random event overhaul. Admins may wish check the verb "Event Manager Panel". +2014-11-22: + Zuhayr: + - rscadd: Added the /obj/item/rig class - back-mounted deployable hardsuits. + - rscadd: Replaced existing hardsuits with 'voidsuits', functionally identical. + - rscdel: Removed the mounted device and helmet/boot procs from voidsuits. + - tweak: Refactored a shit-ton of ninja code into the new rig class. + - wip: This is more than likely going to take a lot of balancing to get into a good + place. +2015-01-09: + Zuhayr: + - tweak: Voice changers no longer use ID cards. They have Toggle and Set Voice verbs + on the actual mask object now. + - rscadd: Readded moonwalking. Alt-dir to face new dir, or Face-Direction verb to + face current dir. +2015-02-04: + RavingManiac: + - rscadd: Holodeck is now bigger and better, with toggleable gravity and a new courtroom + setting + TwistedAkai: + - bugfix: Purple Combs should now be visible and have their proper icon +2015-02-12: + Daranz: + - rscadd: Vending machines now use NanoUI and accept cash. The vendor account can + now be suspended to disable all sales in all machines on station. +2015-02-16: + RavingManiac: + - rscadd: Say hello to the new Thermoelectric Supermatter Engine. Read the operating + manual to get started. +2015-02-18: + PsiOmegaDelta: + - rscadd: Synths now have timestamped radio and chat messages. + - rscadd: New and updated uplink items. + - rscadd: Multiple AIs can now share the same holopad. + - rscadd: The AI now has built-in consoles, accessible from the subsystem tab. +2015-02-24: + Zuhayr: + - experiment: Major changes to the kitchen and hydroponics mechanics. Review the + detailed changelog here, +2015-04-07: + RavingManiac: + - tweak: You can now pay vending machines and EFTPOS scanners without removing your + ID from your PDA or wallet. Clicking on the vending machine with your ID/PDA/wallet/cash + also brings up the menu now instead of attacking the vending machine. +2015-04-18: + PsiOmegaDelta: + - rscadd: Added a changelog editing system that should cause fewer conflicts and + more accurate timestamps. +2015-04-23: + Dennok: + - rscadd: Added an automatic pipelayer. + - rscadd: Added an automatic cablelayer. + PsiOmegaDelta: + - bugfix: Shower curtains no longer lose their default color upon being washed. + - bugfix: Emergency shutters can again be examined, and from the proper distance. + - bugfix: The virus event will now only infect mobs on the station, currently controlled + by player that has been active in the last 5 minutes. + - bugfix: Laptops now use the proper proc for checking camera status. + - rscadd: Makes it possible to eject PDA cartridges using a verb. + - rscadd: Makes it possible to shake tables with one's bare hands to stop climbers. + - bugfix: Added a mass driver door in disposals to prevent trash from floating out + into space before proper ejection. + - rscadd: Rig/Hardsuit module tab - Less informative than the NanoUI hardsuit interface + but allows quicker access to the various rig modules. + - rscadd: Silicons with the medical augmentation sensors enabled now also see alive/dead + status if sensors are set accordingly. + - rscadd: Emergency shutters opened by silicons are now treated as having been forced + open by a crowbar. + - rscadd: An active AI chassis can now be pushed, just as an empty chassis can be. + - rscadd: The AI can now use the crew monitor console to track crew members with + full sensors enabled. + - rscadd: The AI now has a shortcut to track people holding up messages to cameras. + - rscadd: The AI now has a shortcut to track people sending PDA messages. + - rscadd: Multiple AIs can now share the same holopad. + - rscadd: Admin ghosts can now transfer other ghosts into mobs by drag-clicking. + - rscadd: Ghosts can now toggle seeing darkness and other ghosts separately. + - rscadd: Moving while dead now auto-ghosts you. + - rscadd: 'Two new random events: Space dust and gravitation failure.' + - rscadd: Upgraded wizard spell interface and new spells. + - rscadd: More uplink items. + - rscadd: Uplink items now have rudimentary descriptions. + Yoshax: + - tweak: Adjusts fruits and other stuff to have a minmum of 10 units of juice and + stuff. +2015-04-24: + Dennok: + - bugfix: Fixes overmap ship speed calculations. + - rscadd: Adds overmap ship rotation. + - rscadd: Added a floorlayer. +2015-04-28: + Jarcolr: + - rscadd: Added 9 new bar sign designs/sprites. + Kelenius: + - rscadd: 'Good news to the roboticists! The long waited firmware update for the + bots has arrived. You can expect the following changes:' + - rscadd: Medbots have improved the disease detection algorithms. + - rscadd: Floorbot firmware has been bugtested. In particular, they will no longer + get stuck near the windows, hopelessly trying to fix the floor under the glass. + - rscadd: Floorbots have also received an internal low-power metal synthesizer. + They will use it to make their own tiles. Slowly. + - rscadd: Following the complains from humanitarian organizations regarding securitron + brutality, stength of their stunners has been toned down. They will also politely + demand that you get on the floor before arresting you. Except for the taser-mounted + guys, they will still tase you down. + - rscadd: Other minor fixes. + - rscdel: 'The lasertag bots are now forbidden to build and use following the incident + #1526672. Please don''t let it happen again.' + - rscadd: The farmbot design has been finished! Made from a watertank, robot arm, + plant analyzer, bucket, minihoe and a proximity sensor, these small (not really) + bots will be a useful companion to any gardener and/or xenobotanist. + - tweak: 'Spider learning alert: they have learned to recognize the bots and will + mercilessly attack them.' + - rscadd: An experimental CPU upgrade would theoretically allow any of the bots + to function with the same intelligence capacity as the maintenance drones. We + still have no idea what causes it to boot up. Science! + - rscadd: 'INCOMING TRANSMISSION: Greetings to agents, pirates, operatives, and + anyone who otherwise uses our equipment. Following the NT update of bot firmware, + we have updated the cryptographic sequencer''s hacking routines as well. The + medbots you emag will not poison you anymore, the clanbots won''t clean after + themselves immediately, and floorbots... wear a space suit. Oh, and it works + on the new farmbots, too.' + PsiOmegaDelta: + - rscadd: Beware. Airlocks can now crush more things than just mobs. + - rscadd: AIs now have a personal atmospherics control subsystem. + - rscadd: Some borg modules now have additional subsystems. + - tweak: Improves borg module handling. + - tweak: Secure airlocks now buzz when access is denied. + - tweak: The mental health office door now requires psychiatrist access, and the + related button now opens/closes the door instead of bolting. + - soundadd: Restores an old soundtrack 'Thunderdome.ogg'. + - rscadd: Some holodeck programs now have custom ambience tracks. + RavingManiac: + - rscadd: The phoron research lab has been renovated to include a heat-exchange + system, a gas mixer/filter and a waste gas disposal pump. + - tweak: Candles now burn for about 30 mintutes. + Yoshax: + - tweak: Adds items to the orderable antag surgical kit so its actually useful for + surgery. + - tweak: Adjusts custom loadout costs to be more standardised and balances. Purely + cosmetic items, shoes, hats, and all things that do not provide a straight advtange + (sterile mask, or pAI, protection from viruses and possible door hacking or + records access, respectively), each cost 1 point, items that provide an advantage + like those just mentioned, or provide armor or storage cost 2 points. + - rscadd: Adds practice rounds, both .45 for Sec and Detective's guns, also 9mm + top mounted for the Saber, and for the Bulldog. + - rscadd: Adds the .45 and 9mm practice rounds to the armory. + - rscadd: Adds all the practice rounds to the autolathe. + - tweak: Adds r_walls to the back of the firing range, leaves the sides normal. + - bugfix: Fixes HoS' office door to not be CMO locked. +2015-04-29: + Daranz: + - rscadd: Paper bundles can now have papers inserted at arbitrary points. This can + be done by clicking the previous/next page links with a sheet of paper in hand. + HarpyEagle: + - rscadd: 'Added new fire modes to various guns: c20r, STS-35, WT-550, Z8, L6 SAW, + and double barreled shotgun. The firing modes work the same way as the egun; + click on the weapon with it in your active hand to cycle between modes. Unloading + these weapons now requires that you click on them with an empty hand.' + PsiOmegaDelta: + - rscadd: Portable atmospheric pumps and scrubbers now use NanoUI. + - rscadd: Two new events which will cause damage to APCs or cameras when triggered. +2015-04-30: + Yoshax: + - rscadd: Adds more items to custom loadout, including a number of dressy suits + and some other things. +2015-05-02: + HarpyEagle: + - bugfix: Neck-grabbing someone now stuns them properly. + PsiOmegaDelta: + - tweak: The spider infestation event now makes an announcement much sooner. + - rscadd: Admins can now toggle OOC/LOOC separately. + - tweak: Mice are now numbered to aid admins. + Yoshax: + - rscadd: Adds an option and verb to the AI to send emergency messages to Central, + functions same as comms console option. + - tweak: Changes comms console to only have one level of ID require, meaning all + heads of staff have what was captain access, allowing them to change alert, + send emergency messages and make announcements. + - rscadd: Adds an emergency bluespace relay machine which is mapped into teletcomms, + this machine takes emergency messages and sends them to central, if one does + not exist on any Z, you cannot send any emergency messages. + - rscadd: Adds an emergency bluespace relay assembly kit orderable from cargo for + when the ones on telecomms are destroyed. Assembly is required. + - rscadd: Adds the emergency bluespace relay circuitboard to be researchable and + printable in R&D, with sufficient tech levels. +2015-05-05: + PsiOmegaDelta: + - tweak: Grilles no longer return too many rods when destroyed (using means other + than wirecutters). + RavingManiac: + - tweak: Intent menu now appears while zooming with a sniper rifle. +2015-05-06: + PsiOmegaDelta: + - rscadd: Examining a pen or crayon now lists the available special commands in + the examine tab. +2015-05-07: + HarpyEagle: + - rscadd: Breaking out of lockers now has sound and animation. + PsiOmegaDelta: + - bugfix: The cloning computer can again successfully locate nearby cloning vats + and DNA scanners at round start. + - rscadd: Security equipment now treats individuals with CentCom ids with the greatest + respect. + - maptweak: Adds stretches of power cable around the construction outpost, ensuring + one does not have to climb over machines to being laying cables. + RavingManiac: + - rscadd: Muzzle-flash lighting effect for guns + - rscadd: Energy guns now display shots remaining on examine +2015-05-09: + Yoshax: + - rscadd: Maps in the top mounted 9mm practice rounds, .45 practice rounds, and + practice shotgun shells into the armory. +2015-05-10: + GinjaNinja32: + - rscadd: Acting jobs on the manifest will now sort with their non-acting counterparts. + All assignments beginning with the word 'acting', 'temporary', or 'interim' + will do this. + Yoshax: + - tweak: Removes sleepy chems from being cloned, adds a consistent period of 30 + tick sleep. +2015-05-11: + Mloc: + - experiment: Rewritten lighting system. + - rscadd: Better coloured lights. + - rscadd: Animated transitions. + PsiOmegaDelta: + - bugfix: As an observer, using antagHUD should now always restrict you from respawning + without admin intervention. + Techhead: + - rscadd: Voidsuits can have tanks inserted into the storage slot. + - rscadd: Voidsuits display helpful information on their contents on examine. + - rscadd: Magboots can be equipped over other shoes. Except other magboots. +2015-05-12: + Dennok: + - imageadd: New buildmode icons made by BartNixon. + HarpyEagle: + - rscadd: Masks and helmets that cover the face block feeding food, drinks, and + pills. + MrSnapwalk: + - imageadd: Added seven new AI core displays. + - tweak: Changed the pAI sprite and added several new expressions. + PsiOmegaDelta: + - rscadd: The space vine event now comes with a station announcement. +2015-05-14: + PsiOmegaDelta: + - maptweak: Should now be more evident that the brig disposal chute sends its goods + to the common brig area. + - bugfix: Cells now drain when using more charge than what is available. + - tweak: The rig stealth module now requires as much power to run as the energy + blade module. + Techhead: + - rscadd: Vox will spawn with emergency nitrogen tanks in their survival boxes. + - rscadd: Diona will spawn with an emergency flare instead of a survival box. + - rscdel: Engineers no longer spawn with extended-capacity oxygen tanks. + - bugfix: Vox spawning without backpacks will have their nitrogen tank equipped + to their back. + - tweak: The Bartender's spare beanbag shells have been moved into bar backroom + with the shotgun. + - bugfix: Portable air pumps now fill based on external/airtank pressure when pumping + in. +2015-05-16: + GinjaNinja32: + - rscadd: Rewrote tables. To construct a table, use steel to make a table frame, + then plate the frame with a material such as steel, gold, wood, etc. Hold a + stack in your hand and drag it to the table to reinforce it. To deconstruct + a table, use a screwdriver to remove the reinforcements (if present), then a + wrench to remove the plating, and a wrench again to dismantle the frame. Use + a welder to repair any damage. Use a carpet tile on a table to add felt, and + a crowbar to remove it. + HarpyEagle: + - rscadd: Adds tail animations for tajaran and unathi. Animations are controlled + using emotes. +2015-05-17: + PsiOmegaDelta: + - bugfix: Teleporter artifacts should no longer teleport mobs inside objects. +2015-05-18: + Hubblenaut: + - rscadd: Adds a light for available backup power on airlocks. + Kelenius: + - tweak: 'There has been a big update to the reagent system. A full-ish changelog + can be found here: http://pastebin.com/imHXTRHz. In particular:' + - tweak: Reagents now differentiate between being ingested (food, pills, smoke), + injected (syringes, IV drips), and put on the skin (sprays, beaker splashing). + - tweak: Injecting food and drinks will cause bad effects. + - tweak: Healing reagents, generally speaking, have stronger effects when injected. + - tweak: Toxins now work slower and deal more damage. Seek medical help! + - tweak: Alcohol robustness has been lowered. + - tweak: Acid will no longer melt large numbers of items at once. + - tweak: Synaptizine is no longer hilariously deadly. + Loganbacca: + - tweak: Changed MULE destination selection to be list based. + PsiOmegaDelta: + - tweak: Destroying a camera by brute force now has a chance to break the wiring + within. + - rscadd: Turf are now processed. This, for example, causes radioactive walls to + regularly irradiate nearby mobs. + - bugfix: Welders should now always update their icon and inhand states properly. +2015-05-22: + Ccomp5950: + - bugfix: Beepsky no longer kills goats. + - tweak: Goats will move towards vines that are 4 spaces away now instead of 1 + - bugfix: Goats will eat the spawning plants for vines as well as the vines themselves. + Chinsky: + - rscadd: Ghetto diagnosis. Grab patient, aim at bodypart you want to check, click + on them with help intent. This will tell you about their wounds, fractures and + other oddities (toxins/oxygen) for that bodypart. + - rscadd: Fractures are visible on very damaged limbs. Dislocations are always visible. + Surgery incisions now visible too. + - rscadd: Stethoscopes actually make sense now. They care for heart/lungs status + when reporting pulse and respiration now. + HarpyEagle: + - rscadd: Re-implemented fuel fires. Tweaked fire behaviour overall. + Yoshax: + - tweak: Bear traps now do damage when stood on, enough to break bones! Bear traps + can now affect any limb of a person who is on the ground, including head! Bear + traps are no longer legcuffs and instead embed in the limb they attack. + - tweak: Bear traps now take several seconds to deploy and cannot be picked up when + armed, they must be disarmed by clicking on them. They also cannot be moved + then they are deployed. + Zuhayr: + - rscadd: Massive material refactor. Walls, beds, chairs, stools, tables, ashtrays, + knives, baseball bats, axes, simple doors, barricades, so on. + - rscadd: Tables are now built via steel then another sheet on the resulting frame. + They can then be reinforced by dragging a stack of sheets onto the table. + - rscadd: Walls are built with steel for girders, then right-click the girder and + select the reinforce verb while holding a stack, then click the girders with + a final sheet. + - rscadd: Various things can be built with various sheet types. Experiment! Just + keep in mind that uranium is now radioactive and phoron is now flammable. +2015-05-26: + Atlantis: + - rscadd: NanoUI for Robotics Control Console + - rscadd: NanoUI for Supermatter Crystal - AI/Robot only, purely informational + Chinsky: + - rscadd: Meat limbs now can be attached. Use limb on missing area, then hemostat + to finalize it. + - rscadd: Limbs from other races can be now attached. They'll cause rejection, but + it can be kept at bay with spaceacilline to some point. Species special attack + is carried over too, i.e. you can clawn people if you sew a cathand to yourself. + - rscadd: Limbs that are left in open will rot in ~7 minutes. Use freezers or cryobags + to stop it. You can still attach them, but you wish you couldn't. + PsiOmegaDelta: + - tweak: Both the pulse taker and target must now remain still for the duration + of the check or it will fail. + RavingManiac: + - rscadd: Tape recorders now record hearable emotes and action messages (e.g. gunshots). + - bugfix: You can now see actions from inside mechs and closets. + Techhead: + - rscadd: Removed gaseous reagents from the chemistry system and replaced with real-world + organic chemistry precursors. + - rscadd: Hydrogen has been replaced with hydrazine, a highly toxic, flammable liquid. + - rscadd: Oxygen has been replaced with acetone, a mildly toxic liquid. Ethanol's + ink-sovlent capabilities have been copied to it. + - rscadd: Chlorine has been replaced with hydrochloric acid. It is a stronger acid + than sulphuric but less toxic. + - tweak: Nitrogen has been replaced with ammonia. Ammonia now acts as a Dexalin-equivalent + for Vox. + - tweak: Flourine has also been replaced with hydrazine in its one recipe. Flourosurficant + has been renamed azosurficant. + - tweak: Being splashed with liquid Phoron will burn eyes and contaminate clothes + like being exposed to Phoron gas. + Zuhayr: + - rscadd: Added a ghost requisition system for posibrains and living plants. + - rscadd: Added attack_ghost() to hydro trays and posibrains to allow ghosts to + enter them. + - rscadd: Prosthetic limbs are now only repairable with welders/cable coils if they + have suffered below 30 combined damage. + - rscadd: 'Surgery steps that cause no pain and have no failure wounding have been + added: screwdriver for ''incision'', crowbar to open, multitool to ''decouple'' + a prosthetic organ. Hemostat is still used to take an organ out.' + - rscadd: Using a welder or a cable coil as a surgical tool after opening a maintenance + hatch will repair damage beyond the 30 damage cap. In other words, severe damage + to robolimbs requires expert repair from someone else. + - rscdel: Eye and brain surgery were removed; they predate the current organ system + and are redundant. + - rscadd: IPC are now simply full prosthetic bodies using a specific manufacturer + (Morpheus Cyberkinetics). + - rscadd: IPC can 'recharge' in a cyborg station to regain nutriment. They no longer + interface with APCs. + - rscadd: NO_BLOOD flag now bypasses ingested and blood reagent processing. + - rscadd: NO_SCAN now bypasses mutagen reagent effects. + - rscadd: Cyborg analyzers now show damage to prosthetic limbs and organs on humans. + - tweak: Prosthetic EMP damage was reduced. + - tweak: Several organ files were split up/moved around. +2015-05-27: + PsiOmegaDelta: + - tweak: The inactive check process now respects client holder status and can be + configured how long clients may remain inactive before being kicked. + Zuhayr: + - rscadd: Unfolded pAIs can now be scooped up and worn as hats. + - tweak: Scoop-up behavior is now standardized to selecting help intent and dragging + their icon onto yours. +2015-05-30: + Atlantis: + - rscadd: Malfunction Overhaul - Whole gamemode was completely reworked from scratch. + Most old abilities have been removed and quite a lot of new abilities was added. + AI also has to hack APCs to unlock higher tier abilities faster, instead of + having access to them from the round start. Most forced things, such as, shuttle + recalling were removed and are instead controlled by the AI. Code is fully modular + allowing for future modifications. + HarpyEagle: + - bugfix: Fixes Engineer ERT gloves not being insulated. + - tweak: IV stands are no longer bullet shields. They also allow mice, drones, pAIs + et al to pass though. + Kelenius: + - tweak: AI now hears LOOC both around its eye and its core, and speaks in LOOC + around its eye. Keep in mind that you won't hear and won't be heard if there + is a wall between your eye and the target. + PsiOmegaDelta: + - rscadd: You can now review the server revision date and hash by using the 'Show + Server Revision' verb in the OOC category. +2015-06-02: + Techhead: + - rscadd: Re-adds extended capacity emergency oxygen tanks to relevant jobs. +2015-06-04: + PsiOmegaDelta: + - rscadd: AI eyes can now be found in the observer follow list. + - rscadd: Synths can now review all law modules that can be found on the station + from their law manager. + - rscadd: Synths can state these laws if desired, however this is strongly discouraged + unless subverted/malfunctioning. + - bugfix: Astral projecting mobs, such as wizards or cultists, may no longer respawn + as something else while their body lives. + Techhead: + - rscadd: Prison break event has been expanded to include Virology or Xenobiology + - rscadd: Prison break event will warn Enginering and the AI beforehand so they + can take preventive measures. + - bugfix: Disabling area power will now prevent doors from opening during the event +2015-06-05: + PsiOmegaDelta: + - bugfix: Split stacks no longer lose their coloring. + - tweak: Can no longer merge cables of different colors. + - tweak: Blobs and simple mobs now attack all external organs instead of a subset. + The overall damage remains the same but the number of fractures caused will, + in general, be fewer. + - rscadd: Spider nurses now have a chance of injecting their victims with spider + eggs which eventually hatch. If the limb is removed from the host, the host + dies, or the spiderling has matured sufficiently it will crawl out into freedom. + Medical scanners will pick upp eggs and spiderlings as foreign bodies. + Yoshax: + - tweak: Makes hyposprays start empty instead of filled with Tricord. + - tweak: Makes the special wizard projectile staffs, Animate, Change, Focus and + any future ones only usable by wizards. Also makes it so only wizards can use + spellbooks and teleportation scrolls. +2015-06-08: + PsiOmegaDelta: + - rscadd: The AI chassis now glows, with the color depending on the currently selected + display. +2015-06-09: + PsiOmegaDelta: + - rscadd: Ports /tg/'s meteor event. Meteors now appear to be more accurate, come + in a greater variety, and may drop ores on their final destruction. +2015-06-16: + Chinsky: + - rscadd: 'Updated penlights to be more of use in diagnostics, they now show following + conditions:' + - rscadd: Eye damage + - rscadd: Blurry eyes (overall slower reaction) + - rscadd: Brain damage (one eye reacts slower) + - rscadd: Opiates use (pinpoint pupils) + - rscadd: Drugs use (dilated pupils) + PsiOmegaDelta: + - rscadd: Observers can now follow both the AI and its eye upon speech. + - rscadd: Observers can now follow both observers and their body, if they ever had + one, upon speech. + - rscadd: Observers can now follow hivemind speakers if the speaker is not using + an alias or antagHUD is enabled. + - rscadd: Turret controls now glow, with the color depending on the current mode. + Techhead: + - rscadd: Converted Request Console interface into NanoUI. +2015-06-19: + HarpyEagle: + - bugfix: Prevents being on fire from merely warming mobs up slightly in some cases. + Mob fires also burn hotter. + - rscadd: Matches can now be used to light things adjacent to you when thrown. + - tweak: Made the effects of having a damaged robotic leg more prominent. + - bugfix: Robot limbs no longer cause pain messages. A reminder that you can still + check their status with 'Help Intent' -> 'Click Self'. + - tweak: Knifing damage scales with weapon force and throat protection. Helmets + only provide throat protection if they are air tight. Trying to cut someone's + throat with wirecutters and/or while wearing an armoured sealed helmet will + require several attempts before the victim passes out. + - tweak: Knifing switches on harm intent, in case you just wanted to beat on the + victim for some reason. + - bugfix: Prevents knifing bots or silicons. +2015-06-22: + PsiOmegaDelta: + - tweak: The traitor uplink no longer displays all items in a long list, instead + has categories which when accessed shows the relevant items. +2015-06-24: + HarpyEagle: + - bugfix: Fixed Tajaran name generation producing names without a space between + first and last. + - wip: Adds docking to the mercenary shuttle. Works similarly to other shuttles, + except docking and undocking is manually initiated and not automatic. A system + to approve or deny dock requests still to be implemented. + - rscadd: Toolboxes can now hold larger items, such as stacks of metal or power + cells, at the cost of having less space for other things. + - tweak: Gloves/shoes can now be worn even if you have one hand/foot missing. The + other one still has to be present, of course. The items still drop when you + first lose the hand/foot. + - tweak: Budget insulated gloves are somewhat less useless. On average, they will + stop half the damage from getting shocked, and the worst case insulation is + not as bad as it used to be. Budget gloves that are as good as regular insulated + gloves are still as rare as they were before though. + - tweak: PTR bullets are now hitscan, to make them somewhat better for actual sniping. + - maptweak: The telecoms server room now has an actual cycling airlock into it. + - tweak: Non-vital body parts will no longer take further damage above a certain + amount, and will inflict paincrit effects instead. On most humaniods the head, + chest, and groin are vital. + - rscadd: 'Engineers now spawn with industrial workboots (credit: ChessPiece/Bishop).' + - bugfix: Damaged robotic legs now more likely to have an effect. + - bugfix: Fixed bug preventing internal organs from taking damage in some cases. + - maptweak: New flavours of tables around the station. Engineering starts with more + plastic. + - bugfix: Fixed worn items not appearing in some cases. Most notably crossbows and + certain guns when worn on the back. As a side effect, laundry machines no longer + transform items. + - bugfix: Crit oxyloss now runs in game time instead of real time. So if lag is + slowing your movement the same slowdown applies to the dying person you're trying + to reach. + - rscadd: Breathmasks can now be adjusted by clicking on them in your hand, in addition + to the verb. + - rscadd: Wearing a space helmet or similar face-covering gear now prevents eating + and force-feeding food, drink, and pills. + - rscadd: Phoron in air ignites above it's flashpoint temperature and a certain + (very small) minimum concentration. Environments that have oxygen and are hot + enough, and have phoron but not enough concentration to burn will produce flareouts, + which are mostly a visual effect. + - rscadd: Adds animation when making unarmed attacks or attacking with melee weapons, + to help make it clearer who is attacking. + - soundadd: Opening an unpowered door now has an appropriate sound. + - rscadd: Ingesting diseased blood may contract the disease. +2015-06-26: {} +2015-06-30: + PsiOmegaDelta: + - maptweak: Non-general areas on Crescent are now protected by blast doors to enforce + area restrictions. Admins can operate these from the central checkpoint. +2015-07-04: + PsiOmegaDelta: + - tweak: Portable turrets now only blocks movement while deployed. + - tweak: Portable turrets are no longer invincible while undeployed, however they + have increased damage resistance in this state. + - bugfix: Crescent portable turrets should no longer act up during attempts to (un)wrench + and alter their settings. +2015-07-06: + GinjaNinja32: + - rscadd: '''Provisional'' is now also a valid temporary position prefix for manifest + sorting.' +2015-07-10: + Zuhayr: + - rscadd: Ninja now spawns on a little pod on Z2 and can teleport to the main level. +2015-07-11: + HarpyEagle: + - imageadd: Added inhand sprites for flashes, flashbangs, emp and other grenades. + Loganbacca: + - bugfix: Turrets no longer burn holes through the AI. + - tweak: Projectiles now have a chance of hitting mobs riding cargo trains. + - bugfix: Fixed visual bugs with projectile effects. +2015-07-14: + HarpyEagle: + - bugfix: Fixes wrong information being reported when analyzing locked abandoned + crates with a multitool. + PsiOmegaDelta: + - tweak: Ninjas can no longer teleport unto turfs that contain solid objects. + - tweak: Wizards can no longer etheral jaunt unto turfs that contain solid objects. +2015-07-27: + Kelenius: + - tweak: Borg shaker now works similarly to hypospray. It generates reagents that + can be poured into glasses. + - bugfix: Therefore, they can no longer duplicate rare reagents such as phoron. +2015-07-29: + Karolis2011: + - rscadd: Made tagger and sorting pipes dispensible. + - bugfix: Unwelding and welding sorting/tagger pipes, no longer delete data about + them. +2015-07-31: + HarpyEagle: + - bugfix: Fixed projectiles being able to hit people in body parts that they don't + have. This will also mean that the less limbs someone has the less effective + they will be as a body shield. +2015-08-11: + PsiOmegaDelta: + - experiment: 0.1.19 is live. + - tweak: Crew monitors now update every 5th second instead of every other. Reduces + lag and gives antags a larger window of opportunity to disable suit sensors + if they have to harm someone. +2015-08-13: + GinjaNinja32: + - rscadd: Changed language selection to allow multiple language selections, changed + humans/unathi/tajarans/skrell to not automatically gain their racial language, + instead adding it to the selectable languages for that species. Old slots will + warn when loaded that the languages may not be what you expect. + Orelbon: + - rscadd: Changed the HoP's suit to more bibrant colors and hopefully you will like + it. +2015-08-14: + HarpyEagle: + - spellcheck: Renames many guns to follow a consistent naming style. Updated and + changed gun description text to be more lore-friendly. + - rscadd: Throwing a booze bottle at something nearby while on harm intent causes + it to smash, splashing it's contents over whatever it hits. + - rscadd: Rags can now be wrung out over a container or the floor, emptying it's + contents into the container or splashing them on the floor. + - rscadd: Rags can now be soaked using the large water and fuel tanks instead of + just beakers. + - rscadd: Rags soaked in welding fuel can be lit on fire. + - rscadd: Rags can now be stuffed into booze bottles. When the bottle smashes, the + stuffed rag is dropped onto the ground. + - bugfix: Fixed eggs having a ridiculously large chemical volume. + - rscadd: T-Ray scanner effects are now only visible to the person holding the scanner. + - rscadd: Traitors can now purchase the C-20r and the STS-35 for telecrystals. + PsiOmegaDelta: + - tweak: The amount you start with in your station account is now affected by species, + rank, and NT's stance towards you. + TheWelp: + - rscadd: Bookcases are now movable/buildable/destroyable. + - rscadd: Paper can now be crumpled by using in-hand while on hurt intent. + - rscadd: Library Computer External Archive is now sortable. + Zuhayr: + - rscadd: Click a hat on a drone with help intent to equip it. Drag the drone onto + yourself with grab intent to remove it. +2015-08-15: + Kelenius: + - rscadd: Bees have been updated and are totally worth checking out (beekeeping + crate at cargo). + - rscdel: Sleeper consoles removed. All interaction is now done by clicking on the + sleeper itself. + - tweak: To put people into sleeper, you now have to click-drag people to it. Grabs + no longer work. To exit the sleeper, move. + - tweak: Sleeper now uses a NanoUI. +2015-08-16: + HarpyEagle: + - tweak: The unathi breacher is now only wearable by unathi. +2015-08-17: + PsiOmegaDelta: + - rscadd: Station time and duration now available in the Status tab. +2015-08-24: + HarpyEagle: + - tweak: Girders are now reinforced by using a screwdriver on the girder before + applying the material sheets. Use a screwdriver again instead to cancel reinforcing. + - bugfix: Mechanical traps no longer spawn in the janitor's locker. + - rscadd: Mechanical traps can now be printed with a hacked autolathe. + - rscadd: Adds armour penetration mechanic for projectiles and melee weapons. + - rscadd: Laser carbines, LWAP, and shotgun now have a small amount of armour penetration, + ballistic rifles (not SMGs) have moderate amounts, laser cannon has high armour + penetration, and the PTR mostly ignores body armour. + - tweak: 'Shotgun slugs and Z8/STS damage has been lowered slightly to accomodate + for their higher penetration. In general ballistics deal less damage but have + higher penetration than comparable laser weapons. Notable exception: X-Ray lasers + have had their damage lowered slightly but gain very high armour penetration.' + - rscadd: Energy swords now have very high armour penetration. Ninja blades do less + damage but ignore armour completely. + Kelenius: + - experiment: Click cooldowns have been removed on pretty much everything that isn't + an attack. + PsiOmegaDelta: + - rscadd: Adds the option to set the icon size to 48x48, found under the Icons menu, + along with 32x32, 64x64, and stretch to fit. + - tweak: Active AI cores now provides coverage on the AI camera network. Does not + utilize actual cameras, thus will not show up on security consoles. + - rscadd: The Dinnerware vending machine now offer both utensil knives and spoons + without first having to hack them. + - rscadd: Synths now have id cards with access levels which is checked when operating + most station equipment. + - rscadd: Station synthetics still have full station access but can no longer interact + with syndicate equipment, and syndicate borgs now start with only syndicate + access. + - rscadd: Syndicate borgs can copy the access from other cards by utilizing their + own id card module, similar to how syndicate ids work. + - rscadd: When examined up close id cards now offer a more detailed view. + - rscadd: Agent ids now offer much greater customization, allowing changing name, + age, DNA, toggling of AI tracking termination (using the electronic warfware + option), and more. + - rscadd: As AI tracking can now be enabled/disabled at will AI players should not + feel the need to hesitate before informing relevant crew members when camera + tracking is explicitly terminated. + - rscadd: Uplink menu now more organized and with new categories. + - rscadd: Now possible to cause falsified ion storm announcements. + - rscadd: Now possible to cause falsified radiation storm announcements, with expected + maintenance access changes. + - rscadd: Now possible for mercenaries to create falsified Central Command Update + messages. + - rscadd: Now possible for mercenaries to create falsified crew arrival messages + and records. + RavingManiac: + - tweak: Sound environments tweaked to feel more claustrophobic + - rscadd: Being drugged, hallucinating, dizzy, or in low-pressure or vacuum will + alter sounds you hear + - rscadd: Sound environment in holodeck will change to reflect the loaded program + Vivalas: + - rscadd: A new uplink item has been added! A briefcase full 'o thalla can now be + bought by traitors for bribes and such! + Zuhayr: + - rscadd: Pariahs are now a subspecies of Vox with less atmos/cold protection, a + useless brain, and lower health. + - rscadd: Leap now only gives a passive grab and has a shorter range. It also stuns + Pariahs longer than it does their target. + - tweak: Rewrote tiling. White floors, dark floors and freezer floors now have associated + tiles. + - tweak: Changed how decals work in the mapper. floor_decal is now used instead + of an icon in floors.dmi. + - tweak: The floor painter has been rewritten to use decals. Click it in-hand to + set direction and decal. + - tweak: Floor lights are now built from the autholathe, secured with a screwdriver, + activated by clicking them with an empty hand, and repaired with a welding torch. + - rscadd: Unathi now have minor slowdown and 20% brute resist. + - rscadd: Tajarans now have lower bonus speed and a flat 15% malus to brute and + burn. + - rscadd: Vox can now eat monkeys and small animals. + - rscadd: Tajarans can now eat small animals. + - rscadd: Unarmed attack damage has been lowered across the board. +2015-09-02: + Atlantis: + - rscadd: Converted phoron glass to borosilicate glass, adjusted heat resistances + accordingly, got rid of copypaste fire code. Fire resistance is now handled + by variables so completely fireproof windows are possible with varedit. + - rscadd: Windows take fire damage when heat exceeds 100C regular windows, 750C + reinforced regular, 2000C borosilicate and 4000C reinforced borosilicate. For + comparsions, reinforced walls begin taking damage around 6000. + Hubblenaut: + - rscadd: Adds glass bottles for Cola, Space Up and Space Mountain Wind to Booze-O-Mat. + - tweak: Some bar drink recipes have been amended to easily sum to 30 units for + drinking glasses. + - tweak: Vendors now have a product receptor for accepting goods. Opening the maintenance + painel is no longer required. + - tweak: Wrenching a vending machine is no longer a silent action. + - tweak: 'Stepup: Item placement on 4x4 grids seemed to work great. Now we''ll try + 8x8.' + Kelenius: + - tweak: Mechfab can now be upgraded using RPED, and now uses NanoUI. + Matthew951: + - rscadd: Added Vincent Volaju's hair. + - rscadd: Added Vincent Volaju's beard. + Zuhayr: + - rscadd: Added the ability for AIs in hardsuits to control suit modules and movement + with a dead or unconcious wearer. + - rscadd: Added ballistic supply drop pods. + - rscadd: Added diona gestalt random map template. + - tweak: Swapped the singularity beacon out for a hacked supply beacon. +2015-09-05: + Chinsky: + - rscadd: Made capguns into proper guns code-wise. It means you can now take people + hostage with them, stick in your mouth, and all other things you can do with + real guns but probably shouldn't. + - rscadd: Russian roulette! Fun for whole sec team! Unload some shells from revolver, + spin the cylinder(verb) and you're good to go! + HarpyEagle: + - rscadd: Shields no longer block attacks from directly behind the player. + - rscadd: Riot shields no longer stop bullets or beams (except for beanbags and + rubber bullets), however they are now more effective at blocking melee attacks + and thrown objects. + - rscadd: Energy shields block melee attacks as effectively as riot shields do. + Their ability to block projectiles is largely unchanged. + - tweak: Melee weapons now only block melee attacks. + - experiment: Two handed weapons have a small chance of blocking melee attacks when + wielded in two hands. + - rscadd: Sound and visual effects when blocking attacks with an energy shield or + energy sword. + - bugfix: Fixed dead or unconscious people blocking stuff with shields. + PsiOmegaDelta: + - tweak: Cargo now sorts under its own department on station manifests. + - rscdel: Manual radio frequency changes can no longer go outside the standard frequency + span. + - rscadd: Users with sufficient access can instead select pre-defined channels outside + this span, such as department channels, when using intercoms. +2015-09-07: + GinjaNinja32: + - rscadd: Added an auto-hiss system for those who would prefer the game do their + sss or rrr for them. Activate via Toggle Auto-Hiss in the OOC tab. + - rscadd: Auto-hiss system in 'basic' mode will extend 's' for Unathi and 'r' for + Tajara. 'Full' mode adds 'x' to 'ks' for Unathi, and is identical to 'basic' + mode for Tajara. + PsiOmegaDelta: + - tweak: 'Changed the language prefix keys to the following: , # -' + - rscadd: Language prefix keys can be changed in the Character Setup. Changes are + currently not global, but per character. +2015-09-08: + Soadreqm: + - tweak: Increased changeling starting genetic points to 25. + Zuhayr: + - bugfix: Auto-traitor should now be fixed. + - bugfix: The Secret game mode should now be fixed. +2015-09-11: + HarpyEagle: + - tweak: Made flares brighter. + - rscadd: Coffee is now poisonous to tajaran, much like how animal protein is poisonous + to skrell. +2015-09-26: + PsiOmegaDelta: + - tweak: Meteor events now select a map edge to arrive from, with a probability + for each individual wave to come from either neighboring edge. Meteors will + never arrive from opposite the starting edge. +2015-10-10: + HarpyEagle: + - tweak: Rubber bullets and beanbags now are now resisted by melee armour. + - bugfix: Fixed a couple of bugs causing phoron gas fires to burn cooler and slower + than they were supposed to. + - bugfix: Merc bombs are now appropriately explosive again. Same goes for bombs + made by toxins. +2015-10-11: + HarpyEagle: + - tweak: Fabricated power cells start uncharged. + Hubblenaut: + - rscadd: Light replacers can be refilled by clicking on a storage item. + - tweak: Light replacers now hold up to 32 light bulbs. + - tweak: Light replacers can be obtained through janitorial supply crates. + - tweak: A sheet of glass fills the light replacer by 16 bulbs. +2015-10-14: + Hubblenaut: + - bugfix: Airlock backup power test light properly offline when backup power down. + - bugfix: Empty flavor texts no longer draw an empty line on examination. + - bugfix: Material stacks now properly merge upon creation. + - bugfix: Messages for adding to existing stack appear again. + PsiOmegaDelta: + - tweak: Blobs can now spawn anywhere in maintenance, rather than picking location + from a pre-determined list. + TheWelp: + - rscdel: Removed higher Secret player requirements. + Zuhayr: + - rscdel: Removed facehuggers, alien embryos, and embryo removal surgery. + - rscadd: Xenomorph Queens (or infested surgeons...) can now add a hive node to + a victim in order to slave them to the hive. + - tweak: Xenomorph brute/burn mods were tweaked to buff them significantly. + - tweak: Alien larvae now hatch from eggs when ghosts click on them. + - tweak: Alien larvae now gain progression towards adulthood from being inside a + human with blood, which they drink. + - tweak: Alien weeds now use the vine system. +2015-10-21: + Hubblenaut: + - tweak: Bruise packs are now applied per wound, not per limb. + - tweak: Bruise packs now use a delay depending on wound severity for applying. + - rscdel: Removed instant healing ability from advanced bruise packs and ointment. +2015-10-27: + HarpyEagle: + - bugfix: When affected by pepperspray, eye protection now prevents blindness and + face protection now prevents stun, instead of face protection doing both. +2015-11-02: + Hubblenaut: + - rscadd: Adds tape for atmospherics. + - tweak: Tape graphics and algorithm changes. Looks a lot more appealing now. + - tweak: Starting and ending tape on the same turf will connect it to all surrounding + walls/windows. + - tweak: Lifting a part of the tape will lift an entire tape section. + - tweak: Mobs on help intent do stop for tape. + - bugfix: Crumpled tape does not affect tape breaking behavior anymore. +2015-11-10: + Atlantis: + - rscadd: Expanded gridcheck random event. Affected devices now show error UI and + may be restarted manually before the event ends. All Z-levels are now affected + equally. + Datraen: + - tweak: Changes standard and specific plant traits, more diverse plants. + Sligneris: + - tweak: Modified the wording of NT Default's laws. +2015-11-16: + PsiOmegaDelta: + - rscadd: Added new verb, 'Character Setup' under the Preferences tab, to allow + modifying your character settings at any time. +2015-11-19: + PsiOmegaDelta: + - tweak: The round start and auto-antag spawners can now check if players have played + long enough to be eligable for selection. +2015-11-22: + PsiOmegaDelta: + - tweak: Engineering alarm consoles now display camera alerts. + - rscadd: Adds a hacking tool that for all intents and purposes acts and works like + a multitool until a screwdriver is applied. + - rscadd: Gives full control of airlocks after 20-40 seconds of hacking. + - rscadd: The last 6-8 hacked airlocks are always accessed instantly. + neersighted: + - bugfix: Laptop Vendors now accept ID Containers (PDA, Wallet, etc). + - bugfix: Personal Lockers now accept ID Containers (PDA, Wallet, etc). + - experiment: Add /tg/-like attack overlays. +2015-12-06: + Hubblenaut: + - bugfix: Welding a broken camera will use the correct icon. + - tweak: Camera assemblies remember their tag and network from previous usage. + - tweak: Mobs on help intent will not push others that aren't. + Loganbacca: + - rscadd: Added a backend (wireless) system for communication between machinery + and other devices. + Neerti: + - rscadd: The AI can now toggle whether its hologram will move towards the center + of its view using the 'Toggle Hologram Movement' verb. + PsiOmegaDelta: + - tweak: Helmet cameras are no longer enabled by clicking the helmet, instead there + is a 'Toggle Helmet Camera' verb. + Raptor1628: + - tweak: Armory layout changed, weapons returned to static amounts. + - rscadd: New security armor and helmet sprites added. + Zuhayr: + - tweak: 'Backend change: allowed accessories to be placed on any clothing item + with the appropriate variables set.' + - rscadd: Drones can now pull a variety of things (such as scrubbers). This came + with a pulling refactor so please report any strangeness with pulling in general. + - rscadd: Drones (and any mob that can be picked up) can be bashed against airlocks + and such to use their internal access, so long as the person using them does + not have an ID card equipped. + - tweak: Rewrote fireaxe cabinets. Click with a multitool to unlock or loc, click + with a hand to open or close, smash with anything that does damage, and drag + onto your icon to remove the fireaxe. +2015-12-13: + Atlantis: + - rscadd: Added Inflatables Dispenser(ID), an item that allows rapid deployment, + transport and removal of inflatables. + - rscadd: Engineering, Construction and Crisis modules are now outfitted with ID. + - rscadd: Three boxes in engineering have been replaced by three IDs. + - tweak: w_classes of inflatables readjusted. Boxes and IDs can be carried in backpack + now. Individual inflatables are small enough to fit in pocket. + PsiOmegaDelta: + - experiment: Adds a system to allow objects to implement custom multitool interactions + in a modular manner. + - rscadd: The AI can now toggle multitool mode on/off, using the new 'Toggle Multitool + Mode' verb. + - rscadd: Cloning vats can now be connected to a cloning console by using a multitool. + - rscadd: Station alert console circuits can now be altered using a multitool, changing + which alarm types are displayed. + - rscadd: Can now select the color of a cable coil using a multitool. + TheWelp: + - rscadd: Added boardgame item for use with table-top board games. + - rscadd: Added Actors Guild, an alternate spawn that allows players to control + actors. + - rscadd: Added differing card decks, including a Tarot deck and two trading card + games. + - rscadd: Remade /TG/Station's Orion Trail arcade machine with bay-specific modifications. +2015-12-20: + PsiOmegaDelta: + - rscadd: Can now use the Antag Uplink to buy a door hacking device with endless + uses and which leaves doors unharmed, but instead needs some time to do its + work. + Zuhayr: + - tweak: Aiming has been rewritten, keep an eye out for weird behavior. +2016-01-01: + Atlantis: + - rscdel: Removed old computer3 system, most noticeable due to removal of old laptops. + - rscadd: Adds brand new modular computer system that replaces computer3. These + computers may run programs from hard drive, and one device is not limited to + one program. + - rscadd: Modular computers can be assembled manually from components printed at + RnD (Consoles mainly), or purchased (from old laptop vending machines). + - rscadd: Adds NTNet, networking used by modular computers, including an administration + console, NTNet relays, and antag programs. + - rscadd: Adds small set of programs modular computers can run. More programs will + be added in the future. + - rscadd: Various small things added, such as, data crystals (USB flash drives), + NTNRC (messaging, IRC/forum style), file sending, etc. + PsiOmegaDelta: + - tweak: Resomi, and any other humanoid mobs, can now bump doors open despite their + size. + TheWelp: + - rscadd: Microwaves can now be unanchored with a crowbar. +2016-01-08: + Chinsky: + - bugfix: Can pick up monkeys / undress resomi now properly. HELP intent for scooping, + NON-HELP for undressing. + RavingManiac: + - rscadd: Storage in backpacks, boxes and other containers is now capacity-based. + Some containers like belts remain slot-based. +2016-01-13: + Datraen: + - bugfix: Objects can now be yanked out of synthetics. + Techhead: + - rscadd: 'Added a new random event: Shipping Error - A random crate is mistakenly + shipped to the station.' +2016-01-16: + Atlantiscze: + - rscadd: SMES units now try to balance their inputs and outputs. For outputs this + means two SMESes powering the same grid will share the load by percentage. For + inputs, all SMESes inputting from one power network will split the available + power by percentage. + - tweak: 'Some minor SMES configuration changes have been made: Atmospherics SMES + now starts configured to prevent power outages when people forget about it, + engine SMESes are now configured to input/output at full rate. These are only + defaults and may be changed ingame as usual.' + PsiOmegaDelta: + - rscadd: Uplink crystals can now be converted into physical form to allow transfer + between uplink devices. + - rscadd: Each mercenary now spawn with their own private uplink, with each indivual + uplink having the same number of telecrystals as the normal traitor uplink. +2016-01-20: + Atlantis: + - rscdel: Construction robot module removed + - rscadd: Engineering robot module now contains most tools of construction robot, + primarily plasteel. RCD is not included by default. + - rscadd: Engineering Robot RCD upgrade is now buildable. This upgrade unlocks robot's + RCD. It is fairly expensive, requiring small amount of gold and silver, as well + as phoron and steel to build. + - rscadd: Floodlight upgrade added. This upgrade doubles robot's light intensity + (it will be more or less same as actual floodlight), at the cost of higher power + usage. + - rscadd: You may now install matter bin into a cyborg in order to boost it's matter + synth's maximal capacity. Better matter bin adds more capacity + - tweak: Default capacity of matter synths for engineering module tweaked a little, + since prices of reinforced walls, etc. increased recently. Steel changed from + 40 to 60 sheets default, plasteel from 10 (Construction default) to 20. +2016-01-25: + Atlantis: + - tweak: Setup Supermatter admin button now uses map markers and supports all coolant + types. +2016-01-29: + Karolis2011: + - tweak: Improved modular computer performance + PsiOmegaDelta: + - experiment: We now support tg's online changelog auto-creation. See https://tgstation13.org/wiki/Guide_to_Changelogs#Online_auto-creation. + - rscadd: Can now click held mobs, such as Pun Pun, to view their inventory. +2016-02-01: + PsiOmegaDelta: + - bugfix: ED-209s, hostile mobs, and mecha weapons should again be able to fire + without issue. + - bugfix: Agent ids can now be assigned an owner even after having been dropped + on the floor. + - bugfix: Monkey cubes can now be expanded in sinks again. +2016-02-03: + PsiOmegaDelta: + - tweak: Antagonist and special role preferences have been overhauled. Please update + these specific character preferences as they have been reset. +2016-02-06: + PsiOmegaDelta: + - bugfix: Should again be possible to resist out of chairs, beds, and welded lockers. +2016-02-07: + PsiOmegaDelta: + - rscadd: More --fun-- ion laws added. + - rscadd: Showers now splash objects on their turf with water. + - tweak: Can now expand unwrapped monkey cubes using showers, sinks, or just about + any source that applies water. +2016-02-11: + PsiOmegaDelta: + - bugfix: Items dropped by mobs that are held by another mob should no longer be + lost. + - bugfix: Items dropped inside mechs should no longer be lost. + - tweak: Changes the way loadout is handled in the character setup. + - tweak: Can no longer see loadout items restricted to a race you're not whitelisted + for (hence why you may see empty categories). + Zuhayr: + - rscadd: Added functionality for two-handed guns; these guns will give an accuracy + penalty if fired without an empty offhand. + - rscadd: Unified two-handed melee weapons with the above; while the offhand is + empty, the weapon will count as wielded. + atlantiscze: + - rscadd: Players will now be warned when selected spawn point has dangerous atmosphere, + and will be able to abort spawning and spawn elsewhere + - tweak: Supermatter no longer pulls anchored objects. To compensate, pull radius + was increased. It is currently limited by range() proc to approximately 32 tiles. + - tweak: Supermatter delamination's explosion strength reduced slightly. This will + hopefully motivate players to actually attempt repairs as it will be possible + to complete them within 1-2 hours. + - tweak: Supermatter spends more time (30 seconds compared to 10 seconds) in pulling + mode before exploding during delamination. + - rscadd: Supermatter's UI now shows "Relative EER" (Energy Emission Ratio) value + which represents how energised the supermatter is. + chinsky: + - soundadd: Surgery operations now cause sounds. +2016-02-13: + Ccomp5950: + - bugfix: Fixes slimes not hearing people (Kudos Karolis2011) + Karolis2011: + - tweak: Changed Tajarian language name (from Siik'tajr to Siik'maas) + - tweak: Changed Resomi language name (from Resomi to Schechi) + - rscadd: Added Alden-Saraspova counter sprite, making it visable. + PsiOmegaDelta: + - rscadd: Adds a reconnect button to the file menu. + - rscadd: Ghosts can now follow any movable object. +2016-02-15: + Ccomp5950: + - bugfix: Mobs will now have the correct health indicator when they die. X_X + Neerti: + - rscadd: The examination tab now includes additional information about examined + clothing and armor. + - bugfix: EMP no longer hits twice on humans. + - tweak: EMP drains powercells using the cell's current charge, and not the cell's + maximum potential charge, to ensure two blasts do not completely disable a synthetic. + - tweak: EMP hitting a prosthetic limb or organ will now do less damage. + - tweak: EMP hitting a cyborg will no longer outright stun them. Instead, they + gain the 'confused' status for a few moments, making movement difficult. In + addition, their HUD gets staticy, and their modules are forced to be retracted. + - rscadd: Stasis bags will protect the occupant from the outside enviroment's atmosphere. + - rscadd: Stasis bags can be hit with a health analyzer to analyze the occupant. + PsiOmegaDelta: + - rscadd: Sharp objects now have a greater chance of causing bleeding. + - rscadd: Can now pour reagent containers down the sink. + - tweak: Wrapped parcels now take on the size of the wrapped object. + - tweak: Security vests now only protect the torso, arms and other limbs are fair + game. + - tweak: Alters Neerti's EMP changes. + - tweak: Borgs are again stunned by max severity EMPs. + - tweak: Cells now lose a minimum amount of charge based on EMP severity, ensuring + multiple blasts will still be able to drain a cell. + Zuhayr: + - rscadd: Small species now take smaller bites/gulps from food and drink. + - rscadd: Small species are now effected by alchol and toxins twice as much. + - rscadd: blood_volume is now a species-level var and Resomi have lowered blood + volume. + - rscadd: Hunger is a species var and Resomi get hungry faster. + - rscadd: Small mobs have a reduced climb delay. + - rscadd: Resomi gain more nutrition from meat. +2016-02-18: + Daranz: + - bugfix: HUD glitches with the plant bag and cigarette packets are now fixed. + Karolis2011: + - wip: New command and communications program for modular consoles and laptops. +2016-02-22: + Datraen: + - tweak: Fragmentation grenades are no longer launchable. +2016-02-25: + Nalarac: + - rscadd: The autolathe can now print welding goggles. + PsiOmegaDelta: + - spellcheck: Punching a mech should no longer expose you to typos. + Yoshax: + - bugfix: Can again remove linoleum tiles, now with a screwdriver. + - rscadd: Can now order linoleum tiles from cargo. + - bugfix: Tajara should now react appropriately to various chemical reagents, such + as coffee. +2016-02-26: + Crazylemon64: + - rscadd: Allows lighting of smokeables using burning people. + Kelenius: + - imageadd: Additional sprites for the drying racks. + Mark9013100: + - tweak: Evidence bag boxes storage increased. + - bugfix: Fixes the RIG grenade launcher icon. + PsiOmegaDelta: + - spellcheck: Changes instances of 'prothesis' to 'prosthesis'. + Snapshot: + - bugfix: Syndicate hardsuit helmet was invisible for humans when worn + - bugfix: Balances to IPC suit cooler battery usage. +2016-02-29: + MrSnapwalk: + - rscadd: 'Adds five new hairstyles: Short Bangs, Half-Shaved Emo, Long Hair Alt + 2, Bun, and Double-Bun.' + PsiOmegaDelta: + - rscadd: Can now order white, dark, and freezer floor tiles from cargo. +2016-03-01: + PsiOmegaDelta: + - tweak: Player preferences have been overhauled. Please update your preferences, + found at "Character Setup" > "Global" > "Preferences", as they have been reset. + TheWelp: + - bugfix: Board game now properly takes things out of your hand again. + - rscadd: Individual cards now set their name and description so they are no longer + just a playing card. + - rscadd: Adds space pike as a rare carp spawn. Pikes are bigger, meaner, and will + attack anything, including other fish. +2016-03-02: + redstryker: + - rscadd: Adds hijabs as a head and loadout item. +2016-03-04: + Datraen: + - rscadd: Adds a mech-mountable flare launcher. +2016-03-18: + Datraen: + - bugfix: Harmbaton no longer causes halloss while inactive. + Kelenius: + - bugfix: Potassium and nitroglycerin explosive grenades now work. + TheWelp: + - rscadd: Added ability for carbon mobs to taste. Sensitivity varies between species. +2016-03-27: + atlantiscze: + - rscadd: Adds a new "News Browser" modular computer program, that can be used to + download and view news from the NTNet. + - tweak: APCs now react to EMPs in a different way. EMPs will temporarily disable + the APC, in a same way gridcheck does. That allows the APC to be reset using + the button in UI. Duration of EMP timer is based on severity, and a little bit + of RNG (8 - 12 minutes on high strength EMP) + - tweak: APC power cells are now partially shielded from EMPs, resulting in lower + charge loss when the power cell is in APC. +2016-03-28: + Datraen: + - bugfix: Adds a check to prison breaks that makes sure the APC is on before continuing. + atlantiscze: + - rscadd: Cyborgs and the AI now show on the crew manifest. +2016-04-01: + TheWelp: + - rscadd: Off-station antagonists now each set a faction. Primarily used with Resomi + playing merc, heist, etc. + - rscadd: Reworked Wizard to have multiple types of spellbooks, each with their + own costs, artifacts, and unique spells. + - rscadd: Antagonist that wipe equipment now give emergency gear before equipping + anything. Primarily a fix for off-station Vox antags. + - rscadd: Wizard clothing check is now conscious of species slot restrictions. (E.G. + Diona can now cast w/o sandals) + - rscadd: Added a cast verb to the IC tab. Will let people macro spell casting or + quickly cast them via auto-complete. +2016-04-05: + PsiOmegaDelta: + - rscadd: Detectives and forensic personnel now join the station with their own + CSI kit. + - rscadd: The detective's cabinet now contains a CSI kit. + TheWelp: + - tweak: Cast verb now appears/disappears depending on whether you have spells or + not. + - tweak: Corrupt Form now has a longer duration (10 seconds -> 15) + - tweak: Wizard Mark is now a cleanable entity (so soap/space cleaner destroys it) + - tweak: Mark/Recall cooldown halved. (120 seconds -> 60 seconds) + - rscadd: Fixes mind's spell list so that cloning will now properly add all the + spells. You will also keep your spells between bodies. (E.G. You are borged, + you get to keep your spells) + - rscadd: Added verb to antagonists to recieve objectives. Located in the OOC tab + and gained whenever the person becomes an antagonist. + atlantiscze: + - rscadd: Modular computers may now be damaged by gunfire, EMPs and similar threats. + This includes the computer's chassis, and components. + - rscadd: Damaged components may be repaired using nanopaste or cable coil. Damaged + chassis can be repaired with welder. You can use multitool on a component to + get diagnostic report. + - tweak: NTNet speeds increased, with advanced network cards being buffed considerably. + - tweak: Data crystals may now be disconnected without a screwdriver, via the rightclick + menu. + - tweak: You can now load paper into the nano printer, by clicking it (or the computer + it is installed in) with paper pieces. + - tweak: 'Component weights re-adjusted. For now they will have weight depending + on what device are they intended for (tablet+: tiny, laptop+: small, console:normal)' + - tweak: Modular computers now glow when turned on. Tablet has equal light intensity + as PDA, while console is comparable to a light bulb. This light is not colored. +2016-04-06: + Arctic: + - rscadd: Added wall-mounted oxygen pumps which equip internals when used. +2016-04-09: + Kearel: + - tweak: Dough now also requires water to be made. + ParadoxonKomplikon: + - tweak: The exotic seeds crate is now access restricted to xenobiologists. + PsiOmegaDelta: + - rscadd: Bedsheets can now be worn as capes. +2016-04-11: + NullSnapshot: + - rscadd: Players who are active antags can now respond to AOOC. + - rscadd: Mods have been given access to AOOC. +2016-04-14: + Datraen: + - rscadd: Manually ports /tg/station's dark click code https://github.com/tgstation/-tg-station/pull/10272 + by Razharas. + - bugfix: Microwaves no longer try cooking their components while cooking. + HarpyEagle: + - tweak: Fire extinguishers now spray a lot more water, will hopefully put out people + on fire faster. + - tweak: Fire extinguishers now make the ground wet when you use them. + Hubblenaut/HarpyEagle: + - tweak: Confused movement is a little less random. It is now easier to get to where + you want to when confused, especially while walking. + - rscadd: People running into solid objects while confused can be knocked over. + Kearel: + - bugfix: Fixes armalis x shift, again. + - tweak: Adds spellbook descriptions in book of tomes. + - rscadd: Adds ability for bears to dance. The commands dance, boogy and boogie + all work. + - rscadd: Adds ability for commanded mob subtypes to listen to the terms everybody + and everyone. + PsiOmegaDelta: + - rscadd: Can now customize the color of select set of underwear, similar to some + loadout equipment. + - rscdel: Due to new underwear names some selections may have been unset. Double-check + your character setup settings. + TheWelp: + - rscadd: Ports more of TG's slimes. Includes Pyrite, Gold, Cerulean, Bluespace + and Sepia + Yoshax: + - rscadd: Can take filled lunchboxes using the character loadout. These have a food + item, a snack, and a drink, all configurable. + atlantiscze: + - tweak: RIGs driven by AIs inside IIS now use massively less power. In other words, + the AI can walk more than few tiles without fully draining the battery. +2016-04-15: + Datraen: + - rscadd: 'Added Three New Mixed Gamemodes: Lizard, Changeling + Wizard; Intrigue, + Traitors + Ninja; Visitors, Ninja + Wizard.' + - tweak: Created a variable for latespawning antagonist templates, for customization + of autospawning antagonists in mixed game modes. + - tweak: Removed JSON encoding of the PDA Manifest list. + HarpyEagle: + - tweak: Shotgun flare illumination now lasts longer, around 3-4 minutes. + - bugfix: Fixed attack animation playing when using flashes even if the flash was + not actually used due to being broken or recharging. + - bugfix: Fixed lightswitches layering over darkness. Now only the light layers + above shadow. Lightswitch illumination is now much more subtle. + Mark9013100: + - rscadd: Paramedics, Medical Doctors, and the Chief Medical Officer can select + white webbings from the custom loadout. + - rscadd: ' Can now order a wide assortment of job gear from cargo.' + Sabess: + - rscadd: Detectives can now reskin the vintage .45 pistol. +2016-04-17: + mkalash: + - tweak: 'New voting system allows players to chose three options: high, medium, + and low' + - rscadd: Players can set individual antag roles to 'never' and will not be selected + to antag by the game mode + - tweak: Players who do not vote for the game mode, but have not selected never, + are candidates + - rscadd: The game will try the top three voted game modes before forcing extended + without revote +2016-04-18: + HarpyEagle: + - bugfix: Fixes people not going unconscious when they should. + - tweak: Cigarette boxes/cigar cases/candleboxes can now hold any tiny item, such + as pens or dice. + - tweak: Box storage almost doubled, they can now again hold up to 7 small items, + they can no longer hold larger items. + - tweak: Backpack capacity is now 22, dufflebag capacity is now 32. + - bugfix: Dufflebags now properly apply slowdown when worn on the back. As before, + they do not apply slowdown when held in hands. + - imageadd: Fixed missing dufflebag back sprites, ported them from /tg/. + - bugfix: 'Excavation kit can no longer be folded into cardboard. ' + - bugfix: Unathi knife harness can now hold more types of knives. + - tweak: Vials are now tiny items. + PsiOmegaDelta: + - rscadd: Can now prefill the loadout flask and vacuum-flask with a relevant liquid + of your choice. + - tweak: Alters the available selection of genders for different species during + character setup. +2016-04-20: + HarpyEagle: + - bugfix: Examining objects/yourself no longer triggers the gun hostage/aiming system. + Neerti: + - tweak: The toggle to shoot if the target talks on the radio defaults to off. + - bugfix: The aim intent icon now updates when clicked. +2016-04-21: + atlantiscze: + - tweak: Being crushed by door will now push you out of the door, preventing door + crush spam. To compensate, damage caused by door crushing has been increased. +2016-04-23: + Irrationalist: + - bugfix: Fixed clothing (gloves and jumpsuits) hidden from description on examination, + but are still being displayed on character anyway. + PsiOmegaDelta: + - rscadd: The pAI Universal translation module now includes the language of the + Resomi, Schechi. +2016-04-24: + HarpyEagle: + - rscadd: Items can now be positioned on tables by clicking. +2016-04-26: + HarpyEagle: + - bugfix: Rewrote how the floating animation is updated, the animation now correctly + updates when leaving space, activating/deactivating magboots, and buckling/unbuckling. + - bugfix: Examining people in crit now again indicates that they are not breathing. + - bugfix: Fixed spears giving slashing cuts and not puncture wounds. + - bugfix: Fixed wounds not bleeding when they are supposed to. + atlantiscze: + - tweak: Reverts the reduction of backpack capacities introduced few days ago. +2016-04-30: + HarpyEagle: + - rscadd: Mercenaries can now purchase several types of frag grenades for TC. + - rscadd: Mercenaries can now purchase grenade launchers for TC, comes pre-loaded + with random grenades. + - rscadd: Many guns now have an accuracy and dispersion penalty for firing with + only one hand, that roughly corresponds to the size and weight of the gun. You + will see a message upon shooting with a compromised aim. The penalty is also + affected by rapid-fire modes in the case of bullet throwers. To fire two-handed + simply ensure that your other hand is empty and usable when shooting. + - tweak: Laser cannons now slightly increased shot capacity and have increased accuracy + (better for fighting at longer ranges), can no longer fit in backpacks. + - tweak: X-ray laser gun now fires at the same pace as the laser carbine, has the + same shot capacity, but does much more damage against armoured targets, and + is slightly easier to one-hand with. + - tweak: Shotgun flares now blind over a larger area and illuminate for longer. + - tweak: Z8 does slightly less damage, has a larger magazine size, and slightly + more armour piercing. + - bugfix: Shooting a shotgun stun shell now makes the appropriate sound. + PsiOmegaDelta: + - rscadd: Adds a cable painter for recoloring both coils and laid down cables. + - tweak: Pulling items now carries a slowdown penalty, based on weight or size. + atlantiscze: + - tweak: SMESes can now be damaged by gunfire/explosions/emitters, and repaired + by welding tool. SMES that is too damaged will explode with strength dependent + on remaining charge. Damage can be seen by examining the SMES. + - rscdel: Old cell rack PSUs have been removed (and replaced). + - rscadd: New cell rack PSUs have been added. Comes with set of simple sprites (I'm + horrible spriter!), a new nanoUI that shows status of each power cell, and support + for upgrades. Better capacitors increase charging/discharging rate, better matter + bin increases max amount of cells that can be held inside the PSU (3/6/9 cells). + PSUs do not allow precise setting of input/output levels. These new PSUs act + as bridge between power cells and cables, allowing you to charge/discharge the + cells into the grid. + mkalash: + - tweak: Add antagonist vote now works midround + - rscadd: Ghosts can join a pool to be selected for off-station antag roles by add + antag votes + - rscadd: Add antagonist option added to the crew transfer vote +2016-05-04: + Irrationalist: + - bugfix: Mercenary voidsuits no longer hide gloves + - tweak: Rigs now hide masks when sealed + TheWelp: + - tweak: Readds Pariah space resistance. Their health is instead lowered by 15 (80->65) + - bugfix: Pariah stink now respects environment and if the person is a robot. + - rscadd: Pariahs will now vomit uncontrollably on occassion. + - tweak: Budget gloves now fit Vox. + - rscadd: Adds Vox organs. Now are both blue and alien. + - bugfix: Pariah will no longer have superhuman tasting capabilities. + - tweak: Vox hair can now be colored. It could always be colored using the random + button in the character setup and honestly, it isn't lore breaking so I'll let + people choose it themselves. +2016-05-05: + Daranz: + - rscadd: Mice and other small critters can now be eaten from hand. As a member + of species eligible to eat mice, scoop a mouse and click on your character with + the hand holding the mouse. The old method of eating from grab remains available + both for unscoopable and scoopable creatures. +2016-05-06: + HarpyEagle: + - rscadd: Allows AI holograms to change facing by clicking much like other mobs. + - tweak: Armor now has a chance to either block an attack or absorb a fixed portion + of damage, instead of randomly blocking either nothing, half, or full damage. + - tweak: Armor protection against explosions is similarily less random now. + - tweak: Riot, ablative, and ballistic armor is less hyper-specialized. They provide + moderate protection against other damage types now, while their protection against + their main damage type is reduced but still very good. +2016-05-07: + PsiOmegaDelta: + - rscadd: Can now buy the camera MIU from the 'Devices and Tools' category. Gives + the user access to the station camera network on the current Z-level. + - rscadd: Activating an uplink telecrystal in hand now teleports you to a random + semi-near location. +2016-05-08: + PsiOmegaDelta: + - rscadd: The antag uplink now offers .45 ammunition. +2016-05-11: + PsiOmegaDelta: + - rscadd: The Cardborg costume now disguises you as a proper standard borg. This + only fools synthetics (until they examine you), to and all other lifeforms you + will remain your silly cardboard wearing self. - Based on RemieRichard's appearance + framework from /tg/ +2016-05-14: + HarpyEagle: + - rscadd: Items can now be placed in pockets using the strip UI. + - rscadd: Lit welders can now be placed in pockets. Having a lit welder in your + pocket sets you on fire. + Raptor1628: + - tweak: Replaced standard Space Suit, AMI Hardsuit, Excavation Suit, and Anomaly + Biosuit sprites. + - tweak: Restricts all station hardsuits to Humans with the exception of the CE's + suit, which fits everyone but vox and diona, and the Unathi Breacher, which + is for Unathi. + - rscadd: Adds alternate voidsuit types and more flavorful voidsuit descriptions. +2016-05-15: + HarpyEagle: + - bugfix: Fixed lungs not rupturing in space. +2016-05-17: + Techhead: + - rscadd: Stack items now take up storage space proportional to the size of the + stack. + - tweak: Materials, rods, and tiles have had their weight class and max stack size + adjusted. + - rscadd: Stacks now let you split them in any amount instead of one at a time. +2016-05-19: + Haswell: + - rscadd: Added suit cyclers in the engineering and research outposts. + - tweak: Reworded ERT light armors and helmets to asset protection theme. + - rscadd: Added new xenobiologist's locker in xenobotany storage and xenobiology + airlock, replaces botanist's lockers. + - rscadd: Added one biohazard closet to xenobotany storage. + - rscadd: Added scientist lockers and wardrobes to R&D and misc. research. + - rscadd: Added extra Emergency NanoMeds to research areas. + - rscadd: Added one science wardronbe to the research outpost locker room, replaced + stray scientist's locker with xenoarcheologist's locker. + - tweak: Scientist's locker can now be unlocked with either toxins storage or R&D + lab access. + - tweak: Removed toxins storage access from xenobiologists. + - tweak: Xenoarcheologist's locker now uses xenoarcheology access. + - maptweak: Toxins lab now uses toxins storage access instead of R&D access. + - maptweak: Adds xenobiology and toxins storage access to misc. research. + - maptweak: Tools from botanist's lockers in xenobotany storage are moved to the + crate sitting nearby. + - maptweak: Removed one biohazard closet in xenobiology airlock, remaining closet + now hold two sets of suits. + SilveryFerret: + - rscadd: Changes the Death Alarms from announcing over Common channel, to announcing + only over Medical and Security channels. + Yoshax: + - bugfix: Processing strata floor can now be pried up with a crowbar. + - bugfix: Blue carpet can now also be removed with a crowbar, and has had it's ability + to burn and have corners restored. + - rscadd: Added shotglasses. These can contain 10 units. They have their whole contents + swalloed in one gulp. They can be produced in the autolathe or found in the + booze vending machine in the bar. +2016-05-21: + Haswell: + - maptweak: Revamped kitchen and bar areas. + Irrationalist: + - tweak: Accessories are now more 'magic' and more pleasant for non-humans to use. + - tweak: Copied gas_mask to gas_alt in masks.dmi, gas masks should not be obscure + when worn by Resomi. + - imageadd: Added Resomi sprites for 'brown webbing vest', 'black webbing vest', + 'white webbing vest' and 'webbing'. + - imageadd: Added Resomi sprites for Head of Security's trenchcoat and coat, and + Warden's jacket. Including the grey version of the detective's leather coat. + - imageadd: Added Resomi sprites for old and new armour vests and webbing vests + ('suit'-slot ones) + - bugfix: Fixed breath mask lacking a state name when worn by Resomi. +2016-05-22: + Yoshax: + - rscadd: The antag uplink now offers regular discounts on randomly items. + atlantiscze: + - bugfix: Breaking a lot of lights at once will no longer cause massive lag spikes. + This also applies to other sources of sparks. + - tweak: Malf AI Electrical Pulse ability now has a 15s cooldown to prevent spam. + - tweak: Door crush damage reduced by 25% according to feedback. + - rscadd: 'Electrical Storm event overhauled. It now occurs in three severities + and simulates actual storm. A warning will be broadcasted shortly before it + begins, and once it''s over. Duration is severity-dependent. Possible effects + include: Broken lights (as it''s now), Hacked APCs (same as when emagged), or + outright broken APCs with more severe event variants. Each affected APC will + also shut down briefly, this causes station-wide power outages until the storm + passes. Stronger storms last for longer and affect more APCs at once.' +2016-05-24: + Haswell: + - rscadd: Added internal affairs closets, both secure and non-secure variants. + - maptweak: Revamped internal affairs and forensic offices. +2016-05-25: + Daranz: + - bugfix: Food slices spawned in lunchboxes can now be actually eaten. + Haswell: + - maptweak: Minor furniture adjustments to forensics, xenobiology and xenobotany + laboratories. + - rscadd: Added backpacks to xenoarcheology lockers. + - rscadd: Added clipboards to science lockers. + - rscadd: Added roleplay effects for nicotine. + - rscadd: Cigars and cigarettes now contain nicotine. +2016-05-29: + GinjaNinja32: + - rscadd: Rewrote drinking glasses. There are now eight types of glass, and drink + appearance is based on color and the type of glass you put it in. + - rscadd: There are now 'glass extras' you can add to drinks. Straws, drink sticks, + and fruit slices (yes, all of them) all work. You can add up to two extras per + glass. Add extras by clicking the glass with the extra, remove by clicking the + glass with an empty hand while it's in your other hand. + - rscadd: Adding 'fizzy' things (soda water, cola, etc) or ice to a drink will make + it be fizzy or have ice floating in it. + HarpyEagle: + - bugfix: Fixes disarm-attack dislocation chances being so low that you were very + likely to break the targeted limb before it would dislocate. + - bugfix: It is now possible to disarm-attack with stunbatons like with other melee + weapons. Note that this means that using a stunbaton on disarm intent will hurt + people. + - rscadd: Trying to move while being grabbed will now automatically resist. + - tweak: Small mobs are no longer able to pin larger mobs. + - tweak: Resisting a smaller mob's grab is more likely to be successful. + - bugfix: Fixed being able to climb onto a larger mob while restrained, weakened, + unconscious, or dead. + Haswell: + - rscadd: Added resomi science uniform to custom loadout, xenowear section. + Serithi: + - rscadd: Adds in lavender. + TheWelp: + - rscadd: Fully implements space-bikes. They are available to heist and mercenaries. + - tweak: Reworks the effect trail system (so we don't repeat the code over and over + again.) + - rscadd: Added a system to invest spell slots to get more back. You can invest + one spellslot at a time and you will recieve two back. Sacrificing specific + items/reagents onto the spellbook will shorten the time by ten minutes. Can + be done once per investment. + - tweak: Shapeshifting damage share now spreads out the damage to roughly ten damage + chunks. Makes it less of a limb-gibber. + - tweak: Baleful Polymorph buffs the shapeshiftee's health pool to fifty, so no + longer can you get insta-killed. + - tweak: Avian Form has been renamed to Polymorph (get it?) + - tweak: Polymorph no longer strips you when you transform. + - tweak: Polymorph and Baleful Polymorph no longer share damage. + - tweak: Armalis icons are properly centered, for real this time. + Yoshax: + - tweak: Adjusting your suit sensors now displays a message to other people in range + that you did so. In addition, seeing someone else adjust someone's suit sensors + no longer informs you to what level. +2016-05-31: + Cirra: + - tweak: Changed all dollar symbols to the Thaler symbol. + SinTwo: + - rscadd: 'Four new hairstyles added: Fringetail, Sleeze, Rows, Rows 2' + Yoshax: + - rscadd: Admins can now toggle being able to hear remote LOOC. +2016-06-01: + Hubblenaut: + - rscadd: Adds new hairstyle (Ponytail 5) + Raptor1628: + - rscadd: Updated torch Z levels, map defines, and added non-ship Zs. +2016-06-02: + Haswell: + - maptweak: Reworked one of the break rooms on the research outpost into a work + area. + - maptweak: Separated xenobiology biohazard shutters from the other research division + blast doors, added controls in both xenobiology access and RD's office. +2016-06-04: + Asanadas: + - bugfix: Nar-sie no longer causes FIX ME default turfs to display. + - tweak: Cult pylons now serve as decent light fixtures. + Cirra: + - bugfix: Cyborgs can no longer toggle their lights while dead. +2016-06-05: + Cirra: + - tweak: Adjusted the protolathe material cost of all modular computer components. +2016-06-07: + Cirra: + - tweak: Research grippers can now hold mech parts. + HarpyEagle: + - rscadd: Makes laser beams and muzzle flashes stand out in the dark. +2016-06-08: + Asanadas: + - rscadd: Placed cryo pods on the escape shuttle (3 for humans, 1 for robots). Take + care of SSD personnel! + Cirra: + - rscadd: IPCs can now use the *buzz, *beep and *ping emotes. + atlantiscze: + - rscadd: Added functioning tiny atmospherics to telecommunications. + - tweak: Various server rooms and telecommunications central compartment no longer + contain supercooled atmosphere. Instead they are cooled down to 10 celsius by + an air alarm, and have normal ventillation. This air alarm will trigger a warning + at 30C, and alarm at 40C, which is also the point at which machines begin taking + damage. +2016-06-09: + Aticius: + - rscdel: Removes resomi hallucinations due to loneliness. + HarpyEagle: + - tweak: Adjusted the storage size of various items. + - rscadd: 'Added a new storage item: large boxes.' + - tweak: Increased the shot capacity of energy crossbows to 8. + - tweak: Makes deadman switches hopefully more reliable. + - tweak: Inflatable barriers are studier and more resistant to puncture. + PsiOmegaDelta: + - tweak: A backpack is now required to diguise as a borg, along with the cardborg + parts. The chosen backpack decides which borg module you'll appear to be using. + Techhead: + - rscadd: 'New Random Event: Solar Storms. Similar to a radiation storm, but anywhere + inside the station is safe. Also boosts solar panel output significantly for + the duration.' + Yoshax: + - rscadd: Added towels to the loadout. These can be worn on the head, belt or outwear + slots. You can also whip people with them for a special message and sound! In + addition, using them in-hand will produce an emote where your towel yourself + off. + atlantiscze: + - tweak: The PDA messaging server now reboots automatically after a power outage. + This reboot takes about twenty seconds. + - tweak: Minor mapping changes to wiring and areas on the station. Brig has few + sub-areas to even out the load. Research Dock is now on the research subgrid. + Master grid has few extra power lines to make it a little bit more robust against + physical damage. +2016-06-12: + Ccomp5950: + - bugfix: Objects in bags and other containers (including your hands and pocket) + will now hear speach again. This impacts radios, explosive implants, and the + universal recorder. + HarpyEagle: + - tweak: Small mobs such as monkeys and resomi no longer gain the benefits of holding + large or bulky items in two hands. + SparklySheep: + - tweak: Move delay after clicking has been removed. + atlantiscze: + - tweak: Modular computer batteries are no longer fully charged when printed by + research. +2016-06-15: + Ccomp5950: + - rscadd: Turret controllers now alert admins and logs when enabled or disabled + as well as when set to stun or lethal. + HarpyEagle: + - soundadd: Adds new gunshot sounds for most bullet using guns. + - imageadd: Adds new bullet casing icons. All bullet casings now have distinct icon + states for spent and unspent casings. + - rscadd: Adds a new energy weapon, the x-ray laser carbine. The advanced energy + weapon crate now comes with two x-ray carbines and one x-ray pistol. + - bugfix: Fixed spear damage being set to a default value. + - tweak: Adjused spear damage, fixes steel spears now do somewhat less damage than + steel baseball bats, but are sharp. + - tweak: Steel fire axes now do somewhat less damage when wielded, unwieled damage + unaffected. + - tweak: Runtime can now become friends with anyone, regardless of their initial + job. + - bugfix: Beepsky and other securitrons now react quicker when attacked or their + perp tries to run, and move at closer to a running pace. Beepsky should no longer + be so easy to outrun. + PsiOmegaDelta: + - tweak: Vermin may now breed anywhere on the station but should also no longer + spawn inside areas such as the atmospheric tanks. +2016-06-17: + Asanadas: + - tweak: Changes to round-ending deathsquad and syndicate commando load-outs to + maximize speed and minimize drag. + - tweak: Upped the pulse rifle family's general capacity, for better asset protection. + HarpyEagle: + - bugfix: Fixed shuttles causing lighting to break and leave shadowy rectangles + behind. + - bugfix: Fixed shuttle corner appearance on the asteroid. + JerTheAce: + - rscadd: CentCom Fax, Admin Prayer, and CentCom emergency messages now prompt admins + with a pleasing sound effect. +2016-06-20: + PsiOmegaDelta: + - tweak: EMPs now randomly set suit sensors, with strength affecting the probability + of which mode is selected. + - rscadd: Because suit sensors can be affected externally a multitool can now be + used to (un)lock the controls, to for example allow re-adjusting prisoner uniforms. + - rscadd: Because suit sensors can be locked the antag uplink now offers tools and + services which are able to jam suit sensors in various ways. + - rscadd: Adds random events which will garble suit sensor data. +2016-06-22: + Asanadas: + - tweak: Wall mounted Nanomed dispensers no longer require access to use. + Ccomp5950: + - bugfix: IPCs and will no longer get genetic abilities from radstorms. Also Diona. + - bugfix: Lobby folks will no longer hear Hailers + TheWelp: + - rscadd: Adds support for projectile guns to jam. + - rscadd: Adds cheap/crappy gun variants. + Zuhayr: + - rscadd: Changed the vault nuke into a self-destruct terminal. +2016-06-24: + TheWelp: + - rscadd: Adds traders and a trader process. +2016-06-25: + JoeyJo0: + - rscadd: Fixed chargers not charging anything other than cells. +2016-06-28: + Cirra/: + - rscadd: Added a chemistry gripper for Crisis borgs. + HarpyEagle: + - rscadd: Adds applying pressure to body parts to reduce bleeding. With desired + body part selected, help-intent click yourself or get an aggressive grab, then + help-intent attack with the grab item. Each person should only be able to apply + pressure to one body part on one person at a time, so choose wisely. Applying + pressure will get blood on your hands. + - rscadd: Splints and hardsuits that support broken limbs will automatically apply + pressure. + - rscadd: Wounds that require treatment (e.g. bandage) to stop bleeding will be + bolded in the examine output. Wounds that will eventually stop bleeding on their + own are not bolded. + - tweak: Rigsuits now only support limbs when online. + Haswell: + - maptweak: Added NanoMed wall vendors in engineering, security, bridge, bar, arrivals + and escape hallways, replacing mapped in medkits and medical supplies. + - maptweak: Removed one security officer locker, added one cyborg recharging station + in its place. + - maptweak: Added lights in head of security's office. + - maptweak: Added supply ordering, supply control and arcade circuit boards to tech + storage. + - maptweak: Replaced out-of-place reinforced walls with normal walls. + PsiOmegaDelta: + - rscadd: MedHUD overlays now have more stages, both for 'normal' and critical stages + of injury, for improved quick-diagnosis. + TheWelp: + - rscadd: Adds support for map-specific jobs. + - rscadd: Adds torch specific jobs. + Zuhayr: + - rscadd: Ports/adapted several kitchen machines from Apollo Station. +2016-07-03: + Snapshot: + - rscadd: Added Neural Laces which are an intented optional config togglable replacement + to the cloning system. Neural laces are a mechanical backup of a character's + memories and personality that can be exchanged between bodies. + - rscadd: Added Neural Lace Surgery mechanic which works the same way as implant + surgery. + - rscadd: Added Neural Relacing Machine which will automate the procedure above + and can be constructed through R&D. + - tweak: Health Analyzers will show if a subject has a neural lace. + - rscadd: Neural laces can be implanted in someone without a neural lace with a + 30% chance of taking over their body + Zuhayr: + - rscadd: The health indicator on the player GUI will now show a more detailed breakdown + of damage to your body. + - rscadd: Added bioprinter to Genetics and prosthetic organ fab to Robotics. + redstryker: + - rscadd: Adds evening gloves to the loadout, with the ability to tweak their color. +2016-07-06: + Ccomp5950: + - bugfix: Cleanbots will no longer obsess over dirt under doors/lockers or other + areas they cannot access. + Hubblenaut: + - rscadd: Racks will automatically align their contents. + - tweak: Tables use an invisible 8x8 grid for item placement. + - tweak: Items spawning or placed in closets will not be pixelshifted. + - tweak: Certain items will now always be placed centered (This is mostly reserved + for items with sprites too big to be handy for grid placement). + - tweak: Flips rack icon to be consistent with other sprites. + - bugfix: Sets center_of_mass for tools and chemistry reagent containers. + PsiOmegaDelta: + - rscadd: Uplink services now all spawn a proper item which can be used to trigger + the relevant effect at a desired time, as opposed to it firing immediately. + - tweak: The jammer item has been moved into the 'Devices and Tools' category. + - tweak: The jammer services have been moved into the 'Services' category. + TheWelp: + - rscadd: Adds the item_worth var and get_worth proc to obj subtypes and mob/living +2016-07-08: + Asanadas: + - rscadd: Added two pairs of forensic gloves for detectives to use, ceasing their + self-incrimination. Replacements can be found in the cargo detective crates. + TheWelp: + - tweak: Rebalances leap to respect handcuffs, ability to walk, etc. + - tweak: Pariahs HP deficit has been removed (65->100), instead they are now more + vulnerable to all types of damage. + - rscadd: Adds missing hair color flag for regular Vox. Now you can have colorful + dyed Vox hair! Within reason. +2016-07-09: + HarpyEagle: + - rscadd: Severe enough burn damage now causes one-time blood loss due to blistering + and body fluid cook-off. + - rscadd: Armor that provides 'bio' protection will now protect against the effects + of slime feeding. Slimes can still glomp you, however, and are still dangerous + even if you are wearing biohazard suits. +2016-07-12: + atlantiscze: + - tweak: Random event probabilities have been changed a bit. This is mostly noticeable + with electrical storms, which should be less common now. + - tweak: Electrical storm now shuts down APCs for longer duration which is controlled + by event severity. APCs with critical flag are now affected too, but are only + shut down for a short time in comparison to others. + - tweak: EMPs are no longer one-hit kills for AIs - APCs with critical flag take + reduced damage from EMPs, and AI's power restoration routine now resets the + APC that may have been EMPed. + - tweak: AI's power usage has been overhauled. Under the hood changes should improve + reliability a bit and take more scenarios in consideration. The power restoration + routine now provides better feedback to the AI if it fails, such as, whether + the APC is broken or only discharged, etc. + - rscadd: AI now has a Shutdown verb that can be used to reduce it's power usage + five times. This disables AI's control, cameras, and most communications as + if it was without power. This verb acts as a toggle, so it can be used again + to turn yourself back on. + - rscadd: AI now has Toggle Power Override verb that can be used to disable power + saving mode when it loses APC power. This results in much faster discharge of + internal capacitor, but allows you to operate as if you were powered. Can be + toggled at any time. +2016-07-13: + HarpyEagle: + - tweak: Voidsuits and cyber suits are now more shock resistant, now roughly between + hardsuits and thick clothing. +2016-07-14: + atlantiscze: + - tweak: Shield generator configuration has been tweaked. Shield generators upkeep + power is reduced considerably (stationwide shield is approx. 1.1MW at full strength). + Shields still use a lot of power when regenerating. + - tweak: Shield capacitors now act as actual capacitors. Their power storage is + 2 GJ, and maximal input 4MW, as opposed to 8MJ/400kW it was now. + - tweak: Shield generator+capacitor UI now displays in kilowatts and megawatts instead + of watts where applicable. +2016-07-17: + TheWelp: + - tweak: Reduces fireloss cost of casting Dyrnwyn (30->10) + - tweak: Reduces investment time (30 minutes -> 15) + - tweak: Entangle is now a hand-spell. + - rscadd: Humans can now use the *vomit emote, which causes them to vomit. +2016-07-18: + PsiOmegaDelta: + - rscadd: The antag uplink now offers a shield disrupter in 'Devices and Tools' + category. Handy for when that hull shield gets in your way. + - rscadd: Once an emergency response team has been successfully dispatched, as opposed + to simply requested, the emergency shuttle cannot be called for 30 minutes. +2016-07-22: + Daranz: + - bugfix: FixOVeins can now be used for attaching robotic organs (such as neural + laces) in organic patients. Follow the same procedure as with normal organ transplant. + Rymdmannen: + - rscadd: Added department specific rubber stamps for cargo and warden. + - maptweak: Replaced 'small rubber stamp' with corresponding new ones in cargo area + and warden's office. + - maptweak: Placed a 'DENIED' stamp in captain's office. + - spellcheck: Renamed ''quartermaster's stamp'' to ''quartermaster's rubber stamp''. + Snapshot: + - rscadd: Moved airlock electronics, brig doors, portable canisters, and cargo computers + over to TGUI + - tweak: Cargo ordering computers have been completely reworked. Both the supply + and ordering computer have been merged into one which can be logged into or + out of by a crew member with cargo access. The computers will allow only one + computer to be logged in as a register at a time and orders cannot be placed + without a register active. + - tweak: The cargo ordering system has been tweaked to allow requests even when + there are not enough points available so that cargo can queue items into their + cart at their discretion. Items moved to the cart can be demoted back to requests + as well. + - rscadd: The cargo computer now allows crew members to print a receipt of their + requests for their onw use. + - soundadd: Added sounds for printing from the cargo computer for more ambient sounds. + - experiment: The cargo computer will quietly beep whenever a successful ui button + press is completed. This is an experimental test to see if more ambience can + be added without becoming too much of an annoyance. + atlantiscze: + - rscadd: Adds maintenance braces. These can be printed by research and used to + lock down an airlock. Braces can be removed with paired keycard or maintenance + jack tool (also available from research). Braces prevent the airlock from opening + via any means, and absorb a lot of damage until they break off, protecting the + airlock. +2016-07-23: + PsiOmegaDelta: + - tweak: Some antag uplink weapons now come with ammunition (and a container to + hold them) and their price and description has been updated accordingly. + - tweak: Buying random items from the antag uplink will no longer give you weapons + without relevant ammunition, or ammunition for weapons you may not have. +2016-07-25: + Superbee29: + - rscadd: Ghosts can now see the power in a cable when examining it. +2016-07-29: + Raptor1628: + - tweak: Replaced Tactical Armor sprites and stats. Overall less protective. + - rscadd: Adds new gas mask sprite. + - tweak: Adjusted helmet and armor values. Helmets match their armors a bit more, + but are usually more protective. + - tweak: Adjusts armored vests for the torch and splits ballistic/ablative armor + into vest and full-body versions. + atlantiscze: + - tweak: Add Antagonist vote can no longer be freely called by players. It can still + be called by admins, or as an alternative to crew transfer. + - tweak: Add Antagonist is no longer an alternative to crew transfer during Extended + gamemode. The intention is to keep that gamemode antagonist-free, as it was + originally intended. + - rscadd: Players in the lobby will now see which antagonist types were added to + the game. This is displayed below the gamemode's name in the Lobby tab. +2016-08-01: + HarpyEagle: + - rscadd: Emagged and traitor synths can no longer be locked down, except by physically + cutting the lockdown wire (merely pulsing will not work). + TheWelp: + - rscadd: Certain races can now swallow objects whole by using the disarm intent + and aiming at their mouth. + - rscadd: Vomitting now shoves out all the things in your stomach. + - rscadd: Adds support for projectile vomitting being an ability of a species. +2016-08-02: + Haswell: + - rscadd: Modules installed within a hardsuit will now be listed when examining + the hardsuit control module while being held or worn, if the maintenance panel + is open. + Minijar: + - rscadd: Upgrades anomaly isolation to be able to contain pretty much any dangerous + anomalies with boroscillate windows and blast doors. + PsiOmegaDelta: + - rscadd: Ion storms now also affect unslaved borgs, but not drones. + Zuhayr: + - rscadd: Prevented xenomorphs from taking shrapnel or breaking limbs. Buffed non-queen + xeno weed health regen. Remember to rest to not take a heal penalty. + - rscadd: Prevented weeds from entangling species with the NO_SLIP flag. +2016-08-06: + Zuhayr: + - rscadd: Added status display icons for green, blue and delta alerts. + - rscadd: Status displays now have coloured lights for alert icons. + Zuhayr, GinjaNinja32, and Snapshot: + - rscadd: Implemented full body prosthetics. Full Body prosthetics (FBPs) allow + replacement of the entire body with cyborg components and replacement of internal + organs with synethic or assisted counterparts. Players can create a FBP character + by selecting full body in the limbs section of character preferences. + - rscadd: FBPs gain the benefits of a stronger body and no longer requiring breathing, + but are prone to overheating much like IPCs and can take pressure damage in + space. If you play an FBP, be sure to wear a suit and cooler! + - rscadd: IPC monitor screens are now a seperate object in the loadout menu. IPCs + can select a variety of other heads from other prosthetic manufacturing companies + to change their head and body appearance. + - imageadd: IPC monitor screens have an object sprite that's synced to their mob + sprite. + - tweak: Rebalanced IPC brute and burn modifiers due to the introduction of FBPs. + These settings may be tweaked again in the future after gameplay has been conducted. +2016-08-07: + Asanadas: + - bugfix: 'Brings an end to the deadly feud between two of the Exodus''s mascots: + Pun pun, and Officer Beepsky.' +2016-08-08: + Haswell: + - tweak: Emitters can now be locked using IDs with engine room access while it's + on or off. + Techhead: + - rscadd: Ghosts can flicker lights when the round is spooky enough. +2016-08-11: + Haswell: + - tweak: Engi-Vend and Robco Tool Maker machines can now be used by atmospheric + technicians. +2016-08-15: + Asanadas: + - rscadd: Neural laces can now be destructed and created in a proper research lab. + PsiOmegaDelta: + - rscadd: Invented supermatter grenades and made them available to certain sets + of antags. + - rscadd: The antag uplink now allows you to also buy x1 grenades, in addition to + the x5 sets, with some markup. + TheWelp: + - rscadd: Adds ability for merchants to fast buy via cash using a banking system. + - rscadd: Adds ability for players to sell things to merchants. They will only take + things they like. +2016-08-18: + Haswell: + - tweak: The autopilot on the escape shuttle can no longer be overridden during + crew transfers while on blue alert or lower. It can only be overridden during + an evacuation, or during an alert level higher than blue. + Karolis2011: + - rscadd: Added whole map capture tool, only accessable by admins. +2016-08-22: + Asanadas: + - rscadd: The Exodus robotics lab has a newly installed Robotech deluxe (we found + it out in the shed). Also, a new light switch. +2016-08-26: + Asanadas: + - rscadd: Dug out an old engineering vending machine and added it to the engineering + workshop. + Soadreqm: + - rscadd: Made tape recorders use removable 10-minute cassettes instead of 60-minute + internal storage. + TheWelp: + - rscadd: Adds four new traders, a robot trader, a pet trader, a replica trader, + and a prank trader. + - rscadd: Adds unique items (and a bot) for the traders to sell. + - rscadd: Adds missing item worth values to the list. + - tweak: Unique NPCs now stay around for twice as long. + - tweak: Tweaks Hostile mob AI, so that if they have no faction at all, they will + target nobody. + - tweak: Spawner grenade can now set variables (using a list) upon spawning whatever + it spawns. +2016-08-28: + PsiOmegaDelta: + - tweak: Telecrystal amount increased from 25 too 100 with uplink costs adjusted + accordingly, all to allow even more price differentiation. + - tweak: A five pack of grenades is now 20% cheaper than buying them one at a time. + atlantiscze: + - tweak: Power cell no longer use magical charge units. Instead they are rated in + WattHours. For example, a cell with rating of 1000 will be capable of providing + 1000 watts for one hour. (or 2000 watts for half a hour, etc.) + - tweak: In general this means that a power cell with rating of 1000 will hold MUCH + more energy than it held before. To balance this out, power cell capacities + have been reduced considerably. When these two changes add up the cells last + for approximately same time as they used to. + - tweak: As part of this change, higher grade power cells have became a bit more + rare. Research can still fabricate them in bulk, but they are much rarer from + random spawns, and no longer available from vending machines. Vending machines + provide standard cells instead. EngiVend can be hacked to provide few high capacity + ones. + - tweak: Vending machines no longer shoot objects at people when malfunctioning. + They merely shudder and dump the item on the ground. This should make the random + event a little bit less annoying. + - tweak: Space heater's default temperature setting is now 20C (changed from 50C), + which is the default station temperature. It can still be changed via the UI + when the panel is open. +2016-08-29: + Zuhayr: + - rscadd: Added /vg/ direct-action ventcrawling. You will now crawl through the + actual pipe network, a step at a time. Have fun. +2016-08-30: + Haswell: + - rscdel: Atmospheric technician is now unavailable for general play. + - rscadd: Alt title 'Atmospheric Technician' is now added to engineers. + - tweak: Engineers now have all the accesses atmospheric technicians previously + held. + - tweak: Tweaked job selection screen to properly indicate which jobs aren't available + to play as. + Kelenius: + - tweak: Cultists don't need to research words anymore. + - tweak: Astral journey's damage over time lowered to sane levels. + - tweak: Changeling revive, when the timer is up, will now give you a verb that + revives you, allowing you to choose when to get up, instead of doing it immediately. + - tweak: Changelings will always get DNA, species, and languages together, be it + via absorbtion, DNA sting, or hive channel. + - tweak: Changeling transform and change species was merged. + - tweak: Changelings no longer display gender in changeling chat. +2016-09-02: + Techhead: + - rscadd: Medical splints can now also be applied to hands and feet (in addition + to arms and legs). + - rscadd: For those that miss the old functionality, ghetto splints have been added. + These can be crafted with a roll of tape and a metal rod and can only splint + arms and legs. + atlantiscze: + - tweak: Converts few other things over to work with the recent CELLRATE change. + This fixes various issues where battery life of some things (drills, etc.) was + very short, while some other things had power cells with very large capacities. + - tweak: Hardsuits and Mechas now use energy in joules rather than Wh (this fixes + Ninja suit, among others). Various exosuit tools now have rebalanced power usage. + Energy based exosuit weapons use energy on per-shot basis, ballistic weapons + use single massive spike when fabricating a new magazine. + - tweak: Minor power-related changes to exosuit modules. Energy cost of some offensive + modules increased a bit. + - tweak: Added short cooldown for teleporter module to prevent spamming. + - tweak: Added power usage to various industrial/science modules (anomaly scanner, + various drills, etc.). + - tweak: Increased mounted RCD power usage by a lot (matter fabrication is very + power demanding process). + - tweak: Powersink module is limited to 120kW transfer rate, and is slower (30kW) + when used on APCs with enabled interface lock. Furthermore, when draining from + APC it first tries to take energy from the grid, before resorting to taking + it from the cell. + - bugfix: APCs drained by a ninja no longer get stuck on 0% charge, and instead + recharge themselves as usual. + - rscadd: Repair capability of upgraded cyborg rechargers now also works on IPCs + and FBPs. + - tweak: If the cyborg recharger is upgraded enough, it will be capable of rebooting + (and eventually repairing) destroyed modules, for some extra power. +2016-09-03: + Haswell: + - rscadd: Added a fashion vending machine in the locker room for snowflake loadout + items. + - rscadd: Added more SMES coils and circuitboard to supply packs. + - tweak: Adjusted price of SMES coil. + Superbee29: + - bugfix: Changeling transformation (of itself and others via sting) no longer causes + organ rejection. + - bugfix: IPCs can no longer be stung by changelings. +2016-09-07: + Chinsky: + - rscadd: Added a hawaii shirt to loadout accessories. Can be attached to clothing + like suit jackets etc. Can also be found in mixed wardrobes. + Cirra: + - rscadd: Spiderlings now have a unique sprite specific to the type of giant spider + they will become. + Kelenius: + - rscadd: Ninjas now have access to a PDA that has an empty uplink (for exploitable + information). +2016-09-09: + Daranz: + - tweak: If you crack open an amputated limb and later reattach it, you will now + have to cauterize it after reattachment. + Haswell: + - tweak: Reduced wallet capacity, added more items that can fit in wallets. +2016-09-10: + Cirra: + - rscadd: Resomi now process reagents twice as fast. + - tweak: Moved all Resomi organs to the chest, apart from the brain and eyes. + Kelenius: + - rscadd: Xenoarcheology code has been partially redone. + - tweak: Pick set will now sort the picks inside it. + - tweak: Removed useless random numbers from GPS coordinates in various places. + I'm sure we have not lost the arcane knowledge of rounding 500 years into the + future. + - tweak: Picks renamed to show their excavation depths. + - tweak: Suspension generator's power use lowered. + - tweak: Suspension generator's different field types removed. By the way, remember + that they can suspend any item and even mobs. + - tweak: Archeology belts and pick sets can now hold small pickaxes. Pick sets still + only have 7 slots. Brushes fit on your ears. + - tweak: Empty rock drop rate reduced. + - tweak: Empty rock renamed from 'rock' to 'small rock' so you can tell if you are + clicking on a turf or an item when hovering over it. + - tweak: Empty boulder spawn rate reduced. + - tweak: Tape measuring is a bit faster. + - tweak: Scanner now shows the lowest and the highest depth of the find (highest + is depth + clearance) for easier calculations. Ideally, you need to hit exactly + the lowest spot. Less ideally, hit anywhere between higest and lowest. Hit below + lowest and you have a chance to break the find. + - tweak: You can now use a brush to clear strange rocks. Welder uses less fuel for + that than before. + - tweak: Anomaly analyser's report made a bit easier to read. + - tweak: Anomaly locater will now also locate normal finds. + - bugfix: Gas masks will now correctly spawn as archeological finds. + - bugfix: Digsites will now properly contain several (4-12) turfs in a 5x5 radius. + Be careful when digging near your finds. + - bugfix: Suspension generator will now correctly turn off (qdel issue). + - bugfix: Archeology overlays won't disappear when the icon is updated (e.g. when + mining next to it). + - bugfix: Archeology overlays won't overlap each other and will properly disappear + when you mine out a find. + - bugfix: Some spawning oddities were fixed. + - bugfix: Checks for whether you get a strange rock or a clean item were fixed (previously + it always gave you clean item where it should have been rolling a random number). + - bugfix: Can no longer get rid of any item by putting it into evidence bag and + bag into core sampler. + - bugfix: CO2 generator effect now has a type. + - bugfix: Phoron generator effect will now always generate phoron, not sometimes + phoron and sometimes oxygen. + - tweak: You can now lit smokables with cigarettes and cigars. + - tweak: You can now explode welder tanks with all flame sources (cigarettes, lighters, + candles, igniters, etc). + PsiOmegaDelta: + - tweak: The impaired Resomi vision is now represented by the oxygen overlay rather + than the welding overlay. + - tweak: Vision impairment from wearing a welding mask now stacks with nearsightedness + due to now being two separate effects. + - tweak: Species and individual specific nearsightedness now stacks, i.e. a nearsighted + Resomi won't be aided at all to the same degree by the standard prescription + glasses as other species would be. + - tweak: Glasses can now have varying degrees of prescription. +2016-09-11: + PsiOmegaDelta: + - rscadd: Equipment that doesn't check a specific id card for access now checks + the collective access of all id cards in both hands and the id slot. Among other + things such equipment includes doors. +2016-09-14: + Cirra: + - bugfix: Nurse spiders should now correctly have a chance to implant eggs on attack. + Zuhayr: + - tweak: Ninja cloak now only renders you invisible to the player; right-click will + show you, and your inhands will still render. +2016-09-15: + Cirra: + - rscadd: Service grippers can now hold straws and sticks. + Haswell: + - rscadd: Added coin mint to the mining outpost. + - rscadd: Borosilicate (phoron) glass can now be made with the mineral processor. + atlantiscze: + - rscadd: Created new AI restorer program, by default available on research consoles. + Also added a new hardware piece that acts as connection between intellicard + and a computer (laptop and console only). The new program allows AI restoration, + as well as simple law modifications. It can also be used to purge malfunctioning + AI's laws correctly. This program can only work on intellicarded AIs, that are + placed in the computer itself. The program can be run/used by anyone, but requires + head of staff level access to download from NTNet. + - rscdel: Removed old AI integrity restorer console +2016-09-16: + atlantiscze: + - rscadd: Added camera monitoring program to modular computers, that can be run + on consoles, laptops and tablets. Most mapped in consoles come with this program + preinstalled. + - tweak: Due to removal of old consoles (telescreens were part of these consoles), + entertainment monitors were replaced with civilian modular console where applicable. + This console can be used to access the entertainment channels. + - rscdel: Removed old camera consoles, including circuit boards and other related + things. +2016-09-17: + Chinsky: + - rscadd: Some suit jackets and hawaii shirts can be toggled between buttoned/open + states with a verb. + Zuhayr: + - rscadd: Added a reset slot button to chargen. +2016-09-18: + PsiOmegaDelta: + - rscadd: All staff should now be able to access the Secrets menu. Each category + handles its own permission checks.. + - rscadd: Administrators and moderators can now review admin PMs and attack logs + from the Secrets menu, see the new Investigation category. +2016-09-19: + PsiOmegaDelta: + - rscadd: Ghosts now have a 'Teleport to Coordinate' verb. +2016-09-21: + Chinsky: + - rscadd: Ghosts AND AI eyes can travel zlevels again with Move Upwards/Down verbs. + - rscadd: Humans can too, with either working jetpack or wearing magboots and near + a wall (climbing). Don't try in gravity-working areas though, you'll still drop. + Haswell: + - maptweak: Readded missing blast shutters on mercenary shuttle and Skipjack. + - maptweak: Removed random steel floor tiles. + - maptweak: Added random coin spawns. + PsiOmegaDelta: + - maptweak: There are now more rechargers placed around the station. + - maptweak: Added fire fighting equipment in the library and port research maintenance + areas. + - maptweak: The engineering washroom now has two entrances. + atlantiscze: + - tweak: Vastly increases amount of water held in fire extinguishers and water tanks. +2016-09-23: + PsiOmegaDelta: + - rscadd: The antag uplink now offers energy guns in the 'Highly Visible and Dangerous + Weapons' category. + Szunti: + - bugfix: Acids, plant-b-gone etc. kill weeds instead of growing them. Sugar grows + them instead of killing. +2016-09-25: + Chinsky: + - rscadd: Can now pick color of labcoat in loadout menu, replacing separate preset + colored coats. My condolences to those who had preset ones. + Haswell: + - maptweak: Added lots of random spawns in maintenance, replacing most old mapped + in items. +2016-09-26: + atlantiscze: + - tweak: Malfunctioning AI ability Basic Encryption Hack now lists station APCs + first. Off-station APCs (that do not contribute to CPU generation) are appended + to the bottom of the list. + - rscdel: Airlock brace keycards have been removed. + - tweak: Airlock braces when held inhand can be accessed and configured as an airlock + electronics circuit board. Instead of brace keycards they can now be unlocked + by swiping an ID with configured access (or by using maintenance jack). Configuring + the brace has no access requirement, but it can't be configured when installed + on an airlock. +2016-09-30: + Kasuobes: + - rscdel: Removed IR emitters until they are fixed and don't kill servers. +2016-10-03: + Asanadas: + - bugfix: In-game record editing (security and medical) will now respect the same + character limits as it does in the character-setup panel. No more accidentally + massacring those long records! + Haswell: + - rscadd: Added station date to status tab. +2016-10-06: + Chinsky: + - rscadd: Can now use chopped off arms/hands to leave fingerprints on things. Keep + it in your active hand, and its fingerpints will be used. + Datraen: + - tweak: Skrell are now more resistant to various chemicals, more susceptible to + pepperspray. + Haswell: + - tweak: Drone laws have been revised to exclude non-interaction clauses to promote + RP, but retains non-interference intent. Treat and respect them as actual players. + - tweak: Reworded corporate law skill to cover broader areas. Includes SolGov law + and general legal knowledge. + Inforsaken: + - rscadd: Radio Distortion is now linear and uses more than just the * character. + PsiOmegaDelta: + - tweak: If playing a hidden game mode, i.e. Secret, staff now see the actual game + mode in the Lobby. + Raptor1628: + - rscadd: Added a lot of items to the random maintenance spawns. + - tweak: Reduces metagame potential in the money briefcase description. +2016-10-08: + Ferracio: + - rscadd: Name and species can now be selected for newly-constructed FBPs. + - tweak: Removed 'system instability' readout from robot analyzer due to the targets + being immune to 'system instability'. + - rscadd: Added ability to create full-body prosthetics by adding a robot head to + a robot torso. + - tweak: Robotic heads and torsos can now be manufactured with brands. + Konater: + - imageadd: Added some hairstyles for Resomii that n00b created. + TheGreyWolf: + - rscadd: Added Sign language, which can be selected from character setup. + blazerules: + - imageadd: Added a new Emo hair style, one that doesn't cover the eyes. +2016-10-10: + Levyafan: + - rscadd: Added research tape to excavation closets and xenoarchaeology lockers. + - rscadd: Added optical meson scanners to miner lockers. + - rscdel: Removes optical material scanners from miner lockers. Those were useless + anyway. + - maptweak: Mapped in a second suspension generator, some racks, and a rag to the + research outpost. + - maptweak: Mapped in a soft drinks vendomat and a coffee vendomat to the mining + outpost. + PsiOmegaDelta: + - tweak: Objects are now layered using both planes and layers. Visual layering issues + are expected, please report them except if you're running a client older than + 510 in which case you have to update first. + - tweak: The 'Show Server Revision' verb should now be more copy-paste friendly, + in terms of adding the info to issue tickets, and now also includes the major + client version. +2016-10-13: + Hugo14453: + - rscadd: Added golden soap. + Lorwp: + - maptweak: Fixed Firing Range Camera from being named 'Medical Station'. Changed + Cameras in firing range to 'East' and 'West' Respectively +2016-10-16: + Asanadas: + - rscadd: The Mental Health office has been slightly renovated! Psychiatrists and + the other jobs who reside in the Mental Health office of the Medical Bay will + find more pills readily available in their closet, and a few tidier paperwork + items within easier reach. + - maptweak: The Head of Security and Warden lockers now spawn with a generic NT + helmet. + - tweak: The Head of Security's dermal implant now has the same armor values as + a generic NT helmet. + LorenLuke: + - rscadd: Added a toggle to the ninja's self-destruct. Default starting is 'off'. + - tweak: Adds a delay and visible messages (and now a blinking effect!) after the + self destruct is activated. + PsiOmegaDelta: + - rscadd: Staff with sufficient rights can now edit global variables using the 'View + Global Variables' verb. + TheGreyWolf: + - rscadd: Added the tacticool turtleneck to the custom loadout. +2016-10-18: + Mo_Bros: + - imageadd: Adds new icon for compressed gas warning signs. +2016-10-21: + Broseph Stylin: + - rscadd: Added HUD aviators to the loadout. They're restricted to security, and + can toggle between HUD and flash protection modes, but won't offer both at once. + Chinsky: + - rscadd: Added floating camera thing for Journalists, in the library office nook. + It acts like a portable security camera on Thunderdome network. Can also send + audio on Entertainment radio channel. +2016-10-23: + Broseph Stylin: + - rscadd: 'Added a few new items to the loadout: Various ties, a black vest, stethoscope + (medical only), a black suit jacket, three hazard vests, and a cigar case.' + Chinsky: + - rscadd: Added hotkeys for target zone selection. Ctrl+Numpad[number] or just Numpad[number] + in hotkey mode. Make sure to have NumLock enabled. Numpad8 is head-eyes-mouth + (it cycles through those), 4-5-6 are right arm/hand-chest-left arm/hand (cycles + again), 1-2-3 are right leg/foot-groin-left leg/foot(you know the drill) + Ithalan: + - bugfix: Added missing anomaly scanner pad to research outpost's cell A. + - maptweak: Added a health analyzer to the research outpost lab so researcher can + monitor their test subject monkeys. + - maptweak: Removed an oddly placed lightbulb on the exterior surface near the research + outpost. +2016-10-29: + Lorwp: + - maptweak: Added Emergency Wall Mounted Oxygen Tanks to Most suitable External + Airlocks. You can breathe from them using a Mask Attached to them. + Mark9013100: + - rscadd: Gives the Science, Night Vision, Tactical, and Material Goggles action + buttons. +2016-11-01: + Broseph Stylin: + - rscadd: Prescription medical and security HUDs have been added to the loadout. + PsiOmegaDelta: + - tweak: Mercenaries now begin with proper boots, gloves, and belts. +2016-11-02: + Broseph Stylin: + - rscadd: Added a few dresses to the loadout. + Mark9013100: + - rscadd: Adds black softcaps. Can be found in black wardrobes and custom loadout. +2016-11-03: + Broseph Stylin: + - tweak: Most loadout items with multiple variants can now be found under lists + in their respective categories. This change WILL mess up your saved loadouts, + so be sure to redo them. + Siegdermaus: + - imageadd: Adds a new icon for turret and blast area caution signs. +2016-11-04: + ColaFiend: + - rscadd: Added new welding masks available in the gear loadout for engineers and + roboticists. +2016-11-06: + Asanadas: + - tweak: Added a moderate delay to the opening and closing of robotic maintenance + hatches. No more quickscope-cellsniping. + - bugfix: Can no longer run away from a robot while removing its MMI and allow the + process to succeed. + - bugfix: Fixed a one-pixel mistake in one of the robotic maintenance step images. + Broseph Stylin: + - tweak: Most loadout items with multiple variants can now be found under lists + in their respective categories. This change WILL mess up your saved loadouts, + so be sure to redo them. + Datraen: + - tweak: Skrell now have mild darksight. + - tweak: Skrell now prefer slightly warmer temperatures. +2016-11-08: + atlantiscze: + - tweak: Blobs are now considerably more resistant to energetic weapons, be it handheld + lasers, energy guns, or even emitters. An emitter is still useful to suppress + the blob a bit, but one emitter shouldn't be capable of outright killing the + blob. + - rscadd: Blob has a relatively small chance to grow secondary cores. These cores + are considerably weaker, have lower health, but still help spread the blob a + bit more. + - tweak: Emitter power usage increased (30kW to 100kW). While it is still possible + to run one with PACMAN, you have to keep it on overload. + - tweak: Reinforced walls are now considerably more resistant against projectiles + of all kinds, be it emitters, handheld weaponry, or anything else. Regular walls + are unaffected. An emitter is still useful if you need to burn through one, + but expect to wait - it needs over fifty pulses for a plasteel reinforced wall. + - tweak: Details on the above. Reinforcement is calculated from the material that + is used to reinforce the girders when building the wall. Weak materials such + as wood have 0% reduction in taken damage. Most basic materials have 50% or + so. Steel is decent material with 80% reduction. Plasteel is very good with + 90%, and titanium is the best with approx. 92% reduction (though it has lower + overall health) + - rscdel: Removed bubble shield generators, hull shield generators and shield capacitors. + Also removed shield disrupter. + - rscadd: Added a replacement advanced shield generator, that has a combined function + of a capacitor, and both shield generators (hull shielding is toggleable). This + shield generator must be built and once constructed is immobile (but can be + deconstructed again). These generators are fully configurable, have better hull + shielding that doesn't block shuttles, mass drivers and others, and have different + energy system. Damage will drain the shield's energy directly. + - rscadd: Added Shield Diffusers. Two variants exist - floor mounted and handheld. + The handheld variant can be purchased from traitor uplink, and runs on an internal + cell. The floor mounted variant layers under floor tiles and is APC powered. + These diffusers dissipate shields in adjacent tiles (+ shaped pattern). The + generator can be set to try to counter these, in which case each diffuser causes + major EM strain on the shield. + - maptweak: Added two shield generator circuit boards and two shield diffuser circuit + boards into tech storage. +2016-11-09: + Irrationalist: + - bugfix: Unathi and Tajara can now spawn and show preview with gloves included + in outfit of [HIGH] selected job + - tweak: '/obj/item/clothing/gloves has new proc: cut_fingertops - for easier adminbus' + atlantiscze: + - rscdel: It is no longer possible to ventcrawl through scrubbers. +2016-11-14: + Datraen: + - tweak: Removes a large portion of camera bloat. + TheGreyWolf: + - rscadd: Adds sweaters in all the rainbow's colors and more to the custom loadout. + Zuhayr: + - rscadd: Restored scrubber crawling, made them weldable. +2016-11-16: + Legius: + - bugfix: Made the holdout pistol not turn invisible when unloaded with a silencer + attached. +2016-11-17: + Legius: + - maptweak: Added a airlock access button to the exterior of the Dormitory airlock. + - maptweak: Moved the meter covering the second radiator pump so it no longer covers + the pump. +2016-11-18: + Datraen: + - tweak: Global announcer now has access to engineering channel. + - tweak: Supermatter now uses the global announcer. + - bugfix: Supermatter now sends out integrity alerts. + Legius: + - bugfix: The cryotubes on the shuttle and at centcomm are no longer death traps. +2016-11-22: + Broseph Stylin: + - tweak: Waistcoats and suspenders are now accessories and no longer suit items. + Their loadout entries have been changed as well. + PsiOmegaDelta: + - rscadd: There is now a character preference, Ghost Follow Links, to toggle between + short and long follow links. + atlantiscze: + - rscadd: The AI can now speak most languages that are available to station races. +2016-11-28: + Finalsong1: + - tweak: Changes the Vat-Grown Human economic modifier from 5 to 10. + Haswell: + - maptweak: Adjusted armory layout and inventory. + Irrationalist: + - bugfix: Fixed stun-batons being unuseable by synthetics due to hitcost increasing + each (de)activation + - bugfix: Fixed stun-batons not properly updating their icons + Kelenius: + - bugfix: Ghosts can now hear whispers. + - bugfix: Ghosts can now hear people who are EVA. + Runa Dacino: + - rscadd: Made Resomi security smocks available for detectives. + TheGreyWolf: + - rscadd: Added department ponchos to the custom loadout. + - rscadd: Added department and normal winter coats to the custom loadout. + - rscadd: Added a colorable scarf to the custom loadout. + - rscadd: Added lockets to the custom loadout. + - rscadd: added the formal outfit to the custom loadout. +2016-11-30: + Finalsong1: + - tweak: Changed the armor values for specialist vests, reinforcing that they're + designed to be used against that specific damage type. + - rscadd: Added the ability to order a practice laser carbine crate from cargo. + LorenLuke: + - rscdel: Got rid of the awful singletank code. + - rscadd: 'Created new singletank construction and disassembly code (see below): + Single Tank devices must be wired before having assemblies attached.' + - tweak: Single tank devices are single use only with their igniters. The igniters + create a small bit of heat to get fuel to its burn temperature (126C). + - tweak: Added relief valve to air tanks. They now trigger leak logic at over 173C + or leak pressure. Can be welded shut to prevent leakage. + - tweak: Single Tank devices must be wired before having assemblies attached. + - tweak: Air from rupturing/exploding tanks now merged into environment instead + of deleted. + - tweak: Explosion radii based on pressure, gas amount, and volume of rupturing + vessel. + - bugfix: Assemblies can now be used when attached. + PsiOmegaDelta: + - rscadd: 'New Ion law: Lawbound Synths may now have to communicate with the crew + in a random language other than Galactic Common.' + Zuhayr: + - tweak: The gibber is now called a meat grinder, since that's what it is. + - tweak: Eating a human organ or limb is now done in the exact same manner as any + other food. If you try to eat a limb, though, it will not be usable in a transplant, + for obvious reasons. + - tweak: Human organs now fit into the reagent grinder. +2016-12-03: + ForFoxSake: + - bugfix: Fixed a possible href exploit allowing any living player to speak any + language. + - bugfix: Organic beings can no longer speak Encoded Audio Language, although they + can still understand it just fine. + - tweak: Positronic brains can now speak Encoded Audio Language. + - tweak: Station manufactured Full Body Prosthetics can now speak Encoded Audio + Language. + Haswell: + - tweak: Renamed advanced voidsuit to advanced engineering hardsuit. + - tweak: Advanced engineering hardsuit now comes with in-built magboots and insulated + gauntlets that also fit Tajara and Unathi. + - tweak: Added more things that fit on the EVA hardsuit and advanced engineering + hardsuit's chestpiece. + Lorwp: + - tweak: Replaced Shoes in Engineering and Atmospherics Wardrobes with Workboots + Meyar: + - rscadd: The loadout limit has been upped to 10 from 5. + TheGreyWolf: + - rscadd: Added ability for cargo to order a firefighter closet under the engineering + tab. + - rscadd: Added Siik'Tajr as a native Tajaran sign language. + - rscadd: Towels are now in the athletic lockers in the fitness room by the holodeck. + Zuhayr: + - tweak: Ported Prometheans from Polaris, replacing slime people. + - tweak: Added water reagent interactions for Prometheans equivalent to acid. +2016-12-05: + FTangSteve: + - wip: RootSpeak is now split into a local and a global variant. For now the global + acts as a hivemind. + - bugfix: Diona nymphs now can only speak the local variant of rootspeak + Nero-07: + - rscadd: Changed the default option from 'Get random job' to 'Return to lobby' + if your preferred job is already taken. Should only affect new characters + Runa-Dacino: + - rscadd: Added ability to build press cameras to roboticist + atlantiscze: + - rscadd: 'Adds a new modular computer program: Classic Arcade, which is a computer + variant of the arcade machine, minus the prizes.' +2016-12-08: + Chinsky: + - tweak: Mecha sleepers do not KO victimes anymore. + - tweak: You can leave mecha sleepers like normal ones, by walking out. + Cirra: + - rscadd: Lawed synthetics (Borgs + AI) can now understand but not speak sign language. + Datraen: + - tweak: False walls no longer vent up and down. + FTangSteve: + - bugfix: Creatures without eyes can no longer be flashed. + Finalsong1: + - rscadd: Added a few more leather items to the botany biogenerator. + - rscadd: Replaces mead's sugar requirement with honey. Adds the ability to make + rum with mead's old recipe. + - rscadd: Surgical aprons are now available from the loadout. + Haswell: + - rscadd: Added a chemical hair remover. Also works on feathers, horns, anything + keratin-based. + Kel: + - tweak: Blobs can't spawn new blob cores within 2 tiles of an existing one. + - tweak: Secondary blob cores now look different. + - tweak: Removes message for attacking the blob to cut down on spam. + - tweak: Adds attack animation for attacking the blob. + Kelenius: + - tweak: Slimes will always imprint on those who feed them to avoid long streaks + of bad luck. + - tweak: 'RNG removed from the feeding: slimes now always get 20 nutrition per 5 + clone damage.' + - tweak: Slime nutrition drain reduced. + - tweak: Added a small delay between the slime latch and the first damage dealt. + - tweak: Changed how slimes react to damage. Slimes that are attacked with something + will sometimes be shaken off their victims (chance is force * 5 - anything with + force or 20 or above is a guaranteed shake-off). + - tweak: Disarming a slime or wrestling them off now has a chance to disorient them + for a moment. Throwing them off with a weapon doesn't do that. + - tweak: Water will make slimes lose their target, stop feeding, and will disorient + them for a moment on the first application (they will not be stunlocked and + repeated applications have no effect). + - tweak: Slimes now twice as weak to water - PLEASE remember that spraying them + more than once is a waste, the water is already on them and killing them. + - bugfix: Fixed a bug where slime's nutrition was always maxed out when they fed, + causing them to evolve and split instantly. + - bugfix: Slimes now guaranteed to have unique numbers. + - bugfix: Fixed an issue with monkey cubes not deleting in sinks. + - bugfix: Fixed a bug where a slime's location sometimes wouldn't update while they + were feeding. + PsiOmegaDelta: + - maptweak: Adds a new maintenance tunnel network below the station. It can be accessed + by one of 4 elevators and various ladders, assuming one has the access to enter + maintenance in the first case. + - maptweak: Atmospherics has been moved down to this maintenance level. + Runa-Dacino: + - rscadd: Added rolling pin and knife to service/butler borg modules. + - rscadd: Added ability to use the All-in-One grinder(Chemistry, Kitchen, etc.) + to cyborg/android/robot. + TheGreyWolf: + - tweak: Changed Resomii minimum age to 15 years old. + atlantiscze: + - rscadd: SPACE Magazine - Issue 5 is now available in the news browser program + - rscadd: To reduce clutter, the news program now hides older news articles. They + can be shown by toggling a button. + - tweak: News articles now use better data compression, therefore the files are + about 50% smaller. +2016-12-09: + Asanadas: + - rscadd: Surgery cyborgs get an update! Now with tramadol synthesizers, an upgraded + scalpel, a special organ manipulator, and a roller bed module. + - rscadd: Research cyborgs now possess an upgraded laser scalpel. + - rscdel: Surgery cyborgs no longer have a mini fire extinguisher. + - tweak: Cryo tubes, the genetic DNA scanner, and the advanced body scanner now + (also) operate with mouse-drop, instead of grab-put only. Useful for cyborgs. + - bugfix: The infamous sleeper mystery buckle bug has been fixed as a result. + Mark9013100: + - tweak: Gives rainbow gloves unique mob sprites. Credit to ChangelingRain. + PsiOmegaDelta: + - experiment: Sounds are now heard from 14 tiles away by default, rather than 21. + If the station becomes too quiet this can be adjusted. + - soundadd: New sounds added for when electrifying the door or rising and dropping + bolts. Requires adjacency to hear but ensures some foreplanning is needed to + remain stealthy. + - soundadd: The airlock close sound is now different from the airlock open sound. + - soundadd: Changes the airlock-blocked sound and reduces the range at which it's + heard. + sabiram: + - tweak: Fixed errant pixels in black jumpskirt icon, and genericizes description. + - rscadd: Added color selectable jumpskirts, available in loadout. +2016-12-11: + Kelenius: + - tweak: Health scanners now show radiation. + Techhead: + - tweak: The occupants of bodybags can now be scanned without opening them using + health scanners, similar to cryobags. +2016-12-13: + SiegDerMaus: + - rscadd: Added the ability to craft zip guns in game. Zip guns will also have their + own sprites and won't have to borrow the sawn off shotgun's anymore. + TheGreyWolf: + - rscadd: Added the ability for organ printers to also print out limbs. + sabiram: + - tweak: Adjusted crew manifest; shaft miners are now in the Cargo department, Quartermaster + and Cargo Techs are no longer in the civilian department. + - rscadd: Added color selectable hoodies to the loadout menu. + - bugfix: Fixes the sheet snatcher not collecting items on click. +2016-12-15: + Legius: + - bugfix: Shields produced by anomalies are now visible again and use the new shield + graphics. + Nero-07: + - rscadd: The cargo console now keeps track of how many points you earn during the + round and can print an overview showing what you did to get them. + TheGreyWolf: + - rscadd: Added new prosthetics sized for Resomi. +2016-12-26: + Cirra: + - rscadd: Added a preset combat cyborg which admins can spawn. + LorenLuke: + - bugfix: Keeps people from just using 'resist' to escape from nets instantly. + - tweak: Makes resist time random between 5 and 9 seconds to exit net. + - tweak: Sets net fabricator cooldown to 10 seconds (greater than max net resist + time). + - rscadd: Makes nets fade away even if not resisted out of after 15 processing_objects + ticks. + - tweak: Makes it so that netted people cannot use items (and shoot/baton you while + 'restrained' by the net) until freed. + PsiOmegaDelta: + - rscadd: Resetting a character slot now requires confirmation. + - rscadd: Character saves are now per map. + SiegDerMaus: + - rscadd: Adds a new non-lethal weapon. For now, it will remain adminspawn only + for testing, it may be mapped into the armoury later. + TheGreyWolf: + - rscadd: Mousetraps are now orderable from cargo. +2016-12-29: + Chinsky: + - rscadd: Added some hints for filthy civilian scum. Gosh, some people + - rscadd: You can click on [WRONG BRANCH KIDDO] type messages to get info on what + branch/rank is right for this job. + - rscadd: All open jobslots can be seen again in latejoin, but if you try to pick + one with wrong branchrank, you get message about it with hints. + Cirra: + - rscadd: Added a unified radiation system. Radiation is lessened by obstacles, + and distance. + - rscadd: Added a geiger counter for measuring radiation levels, which can be found + in certain vending machines and radiation closets. + Kelenius: + - bugfix: Monkey cubes won't hang the server for a second or so each. Now it's only + about 0.2 seconds each. + Legius: + - maptweak: Added missing emergency shutters to command section. + Meyar: + - experiment: Removes cloning boards from being player accessible without admin + intervention. + Nero-07: + - rscadd: Ported the defibrillator from tg. + PsiOmegaDelta: + - rscadd: Ghosts are now able to follow a much wider variety of things, not merely + mobs, and the entries are a bit more detailed. Inspired by a similar implementation + by Kelenius. + atlantiscze: + - rscadd: Show server revision verb now also lists which map is being used. + - rscadd: Skill descriptions in character setup now contain more detailed information + on differences between varying skill levels. + - tweak: Command, Cooking and Botany skills are now secondary. Engines skill is + no longer secondary. Existing character setups shouldn't be affected, but it + is still advised to check that your skills are set correctly. + - tweak: The skills in character setup have been reordered a bit. +2016-12-31: + HarpyEagle: + - bugfix: Doors leading to open elevator shafts now require a little more effort + to open. + Kelenius: + - rscadd: Station dwellers have re-discovered the ancient art of spraying contents + of fire extinguishers directly at people, instead of floors around them. You + need to be at help intent and click the mob with the extinguisher to do it; + other intents still make you attack. + Loneguyfly: + - rscadd: Changes Taj blood to be visually distinctive from human blood. + Nero07: + - rscadd: Added a program to modular computers, that can be used to create/edit/delete + digital warrants. Also added a mobile device named 'holowarrant', that can be + used to sync up with the central warrant list and display these warrants in + the field. + Ravenxales: + - rscadd: Add toggleable safety for compressed matter implant, to prevent inadvertant + usage and facilitate storage. + - bugfix: Fix compressed matter implants that are placed in storage from destroying + the storage with itself inside. + Redstryker: + - rscadd: Adds a blue resprited version of Latex gloves called Nitrile gloves. They + can be found in the sterile glove box and on the loadout. + - rscadd: 'Added three different hairstyles: Undercut, Coffee House Cut, and Parted + Fade' + sabiram: + - rscadd: Added hotkeys for moving up and down z-levels. The hotkey for moving upwards + is ,(COMMA), and the hotkey for moving downwards is .(FULL STOP) +2017-01-04: + Cirra: + - rscadd: Re-enabled the radiation storm event + - rscadd: Radiation collectors now work with general radiation, as well as singulo-specific + pulses. + - rscadd: The engineering module now has a geiger counter. + - bugfix: Humanoid mobs will no longer ignore radiation levels below 5Bq. + - bugfix: Blast doors now properly block radiation. + HarpyEagle: + - tweak: Burn damage causes by lasers results in less blood loss. + - tweak: Laser protection offered by many types of armour given a modest boost, + bringing laser protection up to match bullet protection in most cases. + - rscadd: Laser beams have a chance of dealing internal organ damage much like brute + damage. + Kelenius: + - experiment: Bot AI has been overhauled, hopefully for the better. + - experiment: Navigation beacon (and, therefore, patrol) code has been changed; + please report any issues with bot patrolling. + - tweak: Mulebots can't be hacked for speed anymore. They move at moderate speed. + Safeties can still be disabled. + - tweak: Floorbots don't try to fix space anymore; instead they will remove broken + tiles. They can be configured to cover platings, too. + - tweak: A farmbot has been added to the garden, and a floorbot to engineering storage. + Loneguyfly: + - rscdel: Removes the silence and paralyze effects from deathsting. The ability + will now only cause jittering and an injection of lexorin. + LorenLuke: + - bugfix: Can now throw held people again. + - rscadd: Clicking a grab while in help intent downgrades the grab a step. + Minijar: + - rscadd: Changes the colour of unathi blood. + Redstryker: + - rscadd: Added a colorable hair bow to the loadout. + - rscadd: 'Added three facial hairstyles to be used for Humans: Mutton Chops, Mutton + Chops and Moustache, and Walrus Moustache.' + - tweak: Made all of the medical bags have blue crosses on them instead of green + crosses. + - rscadd: Added messenger bags variants for all of the jobs. They can be selected + from the character setup. + - rscadd: 'Added four colorable underclothes: long john tops and bottoms, tube top, + and long undershirts.' + Runa-Dacino: + - tweak: Changed stack recipes to spawn product in hands when possible, otherwise + spawn on the ground.. + - rscadd: Enables the text replacer that makes verbs such as *aflap use visible + gender for all *verbs instead of using 'its.' + - bugfix: Fixes preset emotes to write himself and herself instead of heself and + sheself. + Techhead: + - rscadd: Brings back the evil to evil vending machines. However, their throwing + arms aren't as good as they used to be, so if you don't walk up to them, you + should be fine. + TheGreyWolf: + - rscadd: Upped the damage from 5 to 10 brute possible per limb when falling down + a z-level. +2017-01-06: + Hubblenaut: + - tweak: Hydroponics vendor and biogenerator offer full bottles of fertilizer. Prices + and amount available adjusted to accomodate. + Redstryker: + - tweak: Changed the sprites of the biosuits to have gloves and boots. Gives them + the appropriate inventory flags to cover gloves and shoes. + - rscadd: Added toeless workboots. Added them to the loadout. + - rscadd: Added athletic shoes. Added them to the loadout with the ability to color + them. + - rscadd: 'Added the following hoodies to the loadout: NanoTrasen, Space Mountain + Wind, Mariner University, and Ceti Techical Institute.' + - tweak: Changed the 'Mars University Lunchbox' to the 'Mariner University Lunchbox'. + - tweak: Gave boots and gloves to the normal and Resomi variation of the radsuits. + Runa-Dacino: + - bugfix: Fixes pain messages giving errors saying emote 'me' doesn't exist + - tweak: Changed generic 'their' to use visible gender for aforementioned pain messages. + Soadreqm: + - rscadd: Alter procedure for dismantling broken, bolted doors + - rscadd: Made the fire axe more robust against doors. + Zuhayr: + - rscadd: Added a constructable improvised coilgun and two adminspawn railguns. + Credit goes to Siegdermaus for the icons and the commission. No, I'm not going + to tell you how to build it - that's the fun. +2017-01-08: + Cirra: + - tweak: Changed the radiation storm event's end message to indicate that radiation + will take time to decay. + Redstryker: + - soundadd: Added four sounds that are randomly played when bones break. + - rscadd: Added a hanging skeleton model as a furniture item for all your spooky + needs. + sabiram: + - rscadd: The Chief Medical Officer now has maintenance access on the Exodus. +2017-01-11: + Chinsky: + - rscdel: Removes Pun Pun's naked ass. Little pervert was wearing assless jeans + under that hawaii shirt the whole time, fixes them to cover the buttbits properly. + - rscdel: Removed hallucination part of SM delamination event. + Cirra: + - imageadd: Added a new set of PDA sprites. + Hubblenaut: + - tweak: Doubles power for rechargers and wall rechargers. + - tweak: Raises power for cell rechargers from 40 kW to 60 kW. They will still recharge + quickest. + Kelenius: + - tweak: Brand intelligence event now tells you the name of the original machine. + Original machine will now swear more often to make it easier to find. The event + also ends (fixing all machines) when the original machine's shooting is disabled, + not only when its speaker is off. + - rscadd: A customizable tablet has been added to loadout - remember that better + parts use more power. + Lorwp: + - rscdel: Removed Stunbatons from Medbay + - maptweak: Reorganized the Paramedic's Station + Minijar: + - rscadd: Adds Uzi, Deagle, .38 revolver,Combat shotgun and a sawnoff shotgun to + the uplink. As well as appropropriate ammo. + - rscadd: Adds all of the above ammo types to the autolathe. + Nero07: + - rscadd: Dead people now keep processing reagents for 15 seconds after they died + Redstryker: + - rscadd: Added colorable flats to the loadout. + - tweak: Adds defined role variables to the Torch loadout in order to reduce clutter. + - tweak: Fixes the dark red jumpsuit to reflect it actually having a belt on. + TheGreyWolf: + - rscadd: Restricted Resomi prosthetics to limbs only. No more Resomi FBP. + - rscadd: Changed the resomi white smock to instead be colorable. + Zuhayr: + - tweak: The limb damage indicator on the HUD now uses local limb pain, not traumatic + shock. + - tweak: custom_pain() (used in surgery, moving bones, etc, to make a pain message) + now increases pain on the limb calling it. In other words, non-anesthetised + surgical pain now has a purpose other than giant red text. + chinsky: + - experiment: SM delamination no longer causes hallucinations, but has bigger explosion. +2017-01-16: + Hubblenaut: + - tweak: Can now click on turfs with trash bags and similar to quick-gather everything + on it. No longer pixelhunting for cigarettes and bullets. + - bugfix: Buckets and other reagent holders will no longer simply be put into the + janitorial cart's trash bag. + Kelenius: + - rscdel: Resomi FBP construction made physically impossible, STOP MAKING THEM. + Same for Diona and IPCs. + Ravenxales: + - bugfix: Allow protected roles (heads, IAA, etc.) to be converted to faction antags + (cult and rev) mid-round + - bugfix: Make implants work properly again (can configure triggers, etc.). + - bugfix: Made turbolift doors more robust. Small mobs will be displaced, large + mobs will make the lift give up and reopen. + RedStryker: + - bugfix: Added the skeleton stand file to the Baystation12.dme. + Redstryker: + - rscadd: The sterile mask can now be toggled down and up like breath masks. + - tweak: Refactored the pull down mask verb and proc. + TheGreyWolf: + - rscadd: Made Resomi sprites for the scarf. + - rscadd: Fixed so people can once more have mechanican eyes and heart. + atlantiscze: + - tweak: All modular computers now support a tesla link, allowing them to run off + an APC. This includes tablets. + - tweak: Both tablet presets from custom loadout now have a tesla link by default. + - bugfix: Tesla link now also works for laptops when they are closed. + - tweak: Size of tesla link and intellicard slot reduced, which means they can now + actually fit into tablets. +2017-01-18: + Finalsong1: + - rscadd: Adds a piloting skill. + Haswell: + - tweak: Clicking on worn or held boots containing a concealed blade will now draw + the blade out directly, similar to gun holsters. + - tweak: Masks that can be pulled up/down now have action buttons for toggling. + Kelenius: + - bugfix: Fixed issues where you were unable to turn the bots on and off when you + should have been. Farmbot specifically. + - tweak: Synthetics can always control all bot settings. + - tweak: Synthetics and anyone who opens the bot's panel (screwdriver) can toggle + bot safeties, giving it a 'temporal' emag effect that can be fixed in the same + way. Emags break them permanently, but this is obvious when the panel is open. + RedStryker: + - rscadd: Added glowsticks in green, blue, red, orange, and yellow. Work similar + to flares, but burn twice as long and half as bright. Can be found in the YouTool, + party equipment, and random drops. + - soundadd: Added sounds that play when the cheap lighter is turned on and when + the Zippo is lit and turned off. + - bugfix: Changed the name of the long john shirt icon_state so that it can actually + be used. + TheGreyWolf: + - rscadd: Added a new coat to the custom loadout for Resomii. +2017-01-19: + Chinsky: + - bugfix: When reattaching limb, hemostat finish step is REQUIRED now. On the other + hand, limbs are now properly reattached without leaving cut-away status forever. + - tweak: For bone gel steps you can use duct tape now. Screwdrivers aren't used + anymore. Also reworded messages there to be less awkward. + Hubblenaut: + - rscadd: Added icons for the energy gun's shock firemode + - bugfix: Fixes items appearing in the wrong hand. + Ithalan: + - bugfix: Fixed spawning of wrong version of the medical hardsuit in medical. + RedStryker: + - rscadd: 'Added track pants and track jackets in the following colors: white, green, + red, and blue. Added a track jacket for the normal track pants. Added the jackets + to the loadout.' + Redstryker: + - rscadd: Added flannels. It is on the loadout with the color selection datum. It + can have its sleeves rolled up, be buttoned, or be tucked in and any combination + thereof. + - rscadd: Added high tops. Added them to the loadout. +2017-01-21: + Hubblenaut: + - tweak: Floor painting reappears when putting on new plating. + Kelenius: + - rscadd: New cult gamemode is in. Refer to https://wiki.baystation12.net/Cultist + for the updated guide. + - rscadd: Added beekeeping equipment to garden. + - tweak: Open space in engineering is now covered with lattices. + - bugfix: Space vent in toxins is no longer blocked. + Redstryker: + - rscadd: Added cigarette packet 'microlore'. Background information that can be + found in the examine tab. + TheWelp: + - rscadd: Adds universal action HUD element. + - rscadd: Moves spells to new action HUD. + - rscdel: Removes mind transfer. +2017-01-24: + Kelenius: + - tweak: Ghosts can't use their abilities in holy places (non-defiled chapel or + anything touched by holy water) anymore. + - tweak: Confuse rune doesn't blind people, only blurries their vision. It still + stuns as before. + - tweak: It takes longer to unlock tear reality rune and ghost abilities. + - bugfix: Many cult-related bugfixes. + SiegDerMaus: + - rscadd: Added swords for Torch dress uniforms. + Yoshax: + - rscadd: Adds drop pouches that are functionally the same as the various types + of colored webbing, but look different. Are available in loadout and can be + found in webbing crates. +2017-01-28: + HarpyEagle: + - rscadd: Defibrillators will now notify when the patient cannot be revived due + to excessive blood loss. + Kelenius: + - rscadd: Can now configure headset by click-dragging it to screen, similarly to + PDA. + - bugfix: Alien suit sprites have been fixed, as were inhands. + RedStryker: + - rscadd: Added microlore to some soda/drink containers. +2017-02-01: + Ace McLazer: + - tweak: Updated generic colored poncho look, tweaked all to look more human-shaped. + Changed Resomi ponchos, too. + Cirra: + - rscadd: Added a new alloy, Osmium-Carbide Plasteel. It is physically weaker than + plasteel, but is more resistant to heat, and is made like plasteel but with + added osmium and extra carbon. + Haswell: + - maptweak: Reduced Torch map sizes from 255x255 to 200x200. Admin Z is now split + into two. Reduced world initialization time by about 2 minutes. + Hubblenaut: + - bugfix: Fixes mob icons not updating when blood is washed off. + Kelenius: + - tweak: Garden got most of their plants back. The only plants exclusive to xenobotany + now are ambrosia (blame chinsky), kudzu (too dangerous), plastellium (useless), + alien seeds, and randomly-generated ones. + - tweak: Seed storages now start with 30 of each seed type, not 2 or 3. + - rscadd: Xenobotany now starts with 30 of each type of alien seeds (previously + only available from fossils) and 10 random seeds. + PsiOmegaDelta: + - tweak: Climbing ladders now takes 2 seconds. As a side-effect climbing can now + also be aborted by moving away. + - tweak: Anyone near the destination ladder are now also made aware that someone + is (potentially) about to arrive. + SiegDerMaus: + - rscadd: Adds one new haircut, a chin-length bob. + Zuhayr: + - rscadd: Added haywire rounds for shotguns and some calibers of small arms. + - tweak: You now need to target head/eyes/mouth when trying to slit a throat. + - rscadd: Added tendons and tendon repair. Tendons can be severed by cutting brute + damage or via a grab (similar to cutting a throat) and if cut will render the + limb unusable. Hands, feet, arms and legs have tendons. + - rscadd: Added arteries, replacing the previous internal bleeding implementation. + Functionally identical to the internal bleeding of yesteryear including repair + surgery. + - tweak: As a result of the above, internal bleeding is now static per limb and + cannot be treated via bicaridine and inaprovaline overdose. + - tweak: It is no longer required that the skull and ribcage be opened to repair + internal bleeding or eye damage. A retracted incision is still required. + - rscadd: Adminhelps now have a TAKE button that allow an admin to claim it, and + inform the adminhelper that someone is on the case. + sabiram: + - tweak: Split the Command department on the Torch into Heads of Staff and Command + Support. + - tweak: Moves the Exodus cargo team to Supply, the bartender, gardener, chef and + janitor to Service, and Internal Affairs to Support. + - rscadd: Added the command, support, service and supply departments to the ID computer. + Added the support, service and service departments to the manifest. +2017-02-06: + Cirra: + - rscadd: Bluespace tiles created by the Supermatter Cascade will now spread between + z-levels. + Datraen: + - rscadd: Added a gene-specific mode for the Floral Somatoray. + - tweak: Plant controller now generates the mask/tag list used by the centrifuge, + rather than generating it on ui_interact. + Hubblenaut: + - bugfix: Forensic tools (and other items) will no longer be used when putting in + backpacks or on tables. + - tweak: Taking forensic samples will first take evidence, then leave your own fingerprints/fibers. + - rscadd: Added click-and-drag function to forensic tools to take evidence where + you previously couldn't. + - rscadd: Allows chest drawers to store forensic samples. + Kasuobes: + - tweak: Suit storage units now hold magboots and air tanks. + - tweak: Voidsuits can now toggle installed helmets via action button when worn. + Kelenius: + - rscadd: Fossil plants can now be fed to seed extractor to get one random seed. + - rscadd: Placed mining flags now have have a glowing fringe, visible in the dark. + - rscadd: Plush toys added to loadout. + - rscadd: Resomii 'nearsightedness' is now correctly prevented by equipment that + blocks bright lights, not prescription glasses, and goes away in the dark. + Lorwp: + - tweak: Change's Brig Officer's holobadge box to have Master At Arms Holobadges + - tweak: Allow Security Messenger Bags to be able to spawn in Security Lockers + - tweak: All Security have Work Gloves in their lockers now + PsiOmegaDelta: + - rscadd: Admins can now delete specific obj instances from the VV menu, not only + all of the same type. + - bugfix: Power monitors now list all powernet sensors belonging to the current + and connected Z-levels. + TheWelp: + - rscadd: Adds the Vox weapon the Slugsling + - bugfix: Fixes launchers not playing a sound on firing. + chinsky: + - bugfix: Fixes surgery openness stage not applying gory overlay. Gore is back. +2017-02-07: + Cirra: + - bugfix: Radiation from the Supermatter delaminating should now properly affect + all connected z-levels. +2017-02-10: + Asanadas: + - tweak: Scrubbers now scrub N2O and Phoron by default. + - maptweak: The corners of Escape Pods 3 and 4 should now no longer appear to lead + to space. + - tweak: Officer swords should now look good from all angles. + Haswell: + - tweak: Mop buckets and janitor carts can now be climbed over. + Nero07: + - rscadd: Added communications functionality to AI holopads. To use, stand on a + holopad and click it. Make a new holocall and select the target pad from the + list. The targetpad will light up, emit a sound and inform nearby players about + the incoming call. To pick it up, just click the pad. The caller is projected + above the holopad and can talk to/emote with all people in view of the holopad. + To end the call, step off the holopad. The call can also be ended from the other + side by clicking the active holopad. +2017-02-12: + Essbie: + - rscadd: 'Added new cocktail and recipe: Ship''s Surgeon.' + HarpyEagle: + - bugfix: Fixed bluespace jump lag. + - bugfix: Fixed latejoins during bluespace jump not being affected by it. + - bugfix: Fixed being able to enter/leave the vessel zlevels during bluespace jump. + - rscadd: Moving in straight lines during a bluspace jump is now more difficult. + - tweak: The amount of toxin damage gained from low blood levels is now limited + to around 18. + - bugfix: Various defibrillator fixes. + - bugfix: Difference between the two cult ghost whisper verbs should be clearer + now. + - bugfix: Meteors no longer destroy floors or anything else that doesn't block their + movement. + Haswell: + - tweak: Removed ghost verb from AI and pAI due to overlapping function with wipe + core and wipe software verbs. + Nero07: + - bugfix: Added a busy signal so you can't call already active holopads, which led + to message spam. + - bugfix: Makes holopads actually function and fixes a few runtimes associated with + them. + TheGreyWolf: + - tweak: Made it so only unbranded, NT and Resomi specific prosthetic brands can + be made during gameplay, chargen not changed. + Zuhayr: + - tweak: Bleed-out rate now depends on pulse rate and size of bleeding limb. + - tweak: This means that potassium chlorophoride, which stops the heart, and inaprovaline, + which now slows the heart, are both suitable for emergency treatment of bleeding. + - rscadd: Cautery surgery with no preceeding steps will now cauterize a cut artery + in a stump. + - tweak: Arterial bleeding and stumps are now more informative about where the bleed + is. + - tweak: Arterial sprays can now splatter/blind people and use the correct icons. +2017-02-14: + Haswell: + - rscadd: Added waist packs that can be worn around the waist or on the back. They + can be found in custom loadouts under utility. + atlantiscze: + - rscadd: Added modular telescreens - wall mounted modular computers that are comparable + to laptops in terms of hardware restrictions, and tablets in terms of software + restrictions. Few of those have been mapped in, more can be built. + - tweak: Large amount of under-the-hood improvements and tweaks. + sabiram: + - rscadd: Added subtypes of meat for cows, goats and chickens. They all act the + same way. + - rscadd: Added crates containing beef, goat meat, chicken meat, eggs, and milk. + - tweak: Increased the price of the livestock crates so that it is much more economical + to order the produce you want instead of a live animal. +2017-02-15: + RedStryker: + - bugfix: Allows department-specific messenger bags to be used. + lorwp: + - rscadd: PAI's can now speak EAL, if they have a Universal Translator' + sabiram: + - rscadd: Adds some new hairstyles. For the Torch, Short Hime and High and Tight + are approved for all Sol personnel; Grande Braid and Fringetail are approved + for the Expeditionary Corps only. All new styles are freely available to all + civilians. + - tweak: Adjusts luminosity on a few hairstyles to correct desaturated spots. +2017-02-18: + Haswell: + - rscadd: Added boxes of headsets to the Torch XO locker. + Lorwp: + - rscadd: Added Trendy messenger bags to all Job Lockers + sabiram: + - rscadd: Added modular laptops to the utility loadout menu. +2017-02-21: + Asanadas: + - bugfix: You now require an under-clothing (such as a jumpsuit) to wear things + on your belt. No more PDA in your boxer waistband. + - bugfix: Mushroom soup can now be made with a sane ingredient combination. + Chinsky: + - rscadd: Accounts with biggest profits or losses are now announced in round end + summary. Get dat greentext. + - tweak: Surgery changes. Cry, medical. + - rscadd: Self-surgery is legal now. It was possible via a bug, it's a feature now. + - rscadd: As a side effect, you don't have to lie down to be operated on. It is, + however, a very bad idea unless it's basic steps like incision etc. Success + chance will drop for delicate steps. + - rscadd: Instead of randomly doing nothing, rollerbeds / tables are factored into + surgery success chance calculation. + - rscadd: 'Said success chance: surgery steps now can fail even if you don''t move + / drop tools etc. Ideal scenario is ''sober surgeon not in pain operating on + another person who is lying on an optable''. Deviations from that add chance + of failure. Some steps are more robust, some are more delicate. As a rule of + a thumb, if you have to touch innards, that''s delicate. If you perform internal + organ surgery on yourself while sitting on a table piss drunk, nearly passing + out from pain and also being blind, it''s not going to go very smooth.' + - rscadd: Shock will advance fast when being surgery'd on, so take it slow or take + some pills. + Haswell: + - maptweak: Destroyed the cloning lab on Exodus and all technology related to it. + atlantiscze: + - rscadd: Added forced-shutdown verb to modular computers, reachable via rightclick + menu. This is equivalent of pressing the Shutdown button in the UI, and is mostly + intended to be used when UI bugs out and regular shutdown isn't available. + - rscadd: Added Supermatter Monitoring program, available on all devices. It provides + various information on the supermatter engine. It is fully variable, and capable + of working with multiple supermatter crystals at once (for those enterprising + engineers among you). + - rscadd: Among other information, the supermatter monitor program shows engine + core EPR value. This value is best kept between 1 and 2, and shows real amount + of coolant in the core (in standard canisters worth). Normal EPR with two canisters + in each loop is roughly 1.5 + - rscdel: Rightclick open/close laptop verb no longer exists for laptops. Use alt-click + instead. +2017-02-24: + Chinsky: + - rscadd: PI now spawns with a badge, Journalist with a camera. Also added tape + recorder to custom loadout. + Cirra: + - soundadd: Added several new sound effects. These include fire extinguisher cabinets, + internals activation, flashlight/flare activation, air alarm breach detection, + and more. + - soundadd: Added ambient sounds to Thermo-Electric Generators. + - bugfix: Braces can no longer be removed from an airlock by deconstructing the + airlock. + - bugfix: Pipes will now correctly burst if the internal pressure is too high. 0-16.9MPa + is safe, 17-20.9MPa has a chance of bursting, and 21MPa+ will burst instantly. + - maptweak: Osmium-Carbide Plasteel walls have been mapped into the incinerator. + It should now be safe to use the incinerator, as a result. + Crushtoe: + - imageadd: 'Two new pAI chassis types: The Mushroom and the Corgi Puppy. Finally, + we can have our pAIs join the Mushroom Plague.' + Haswell: + - tweak: Antag preferences now default to never instead of low. + Runa-Dacino: + - rscadd: Adds ability for the player to change the name and description of ninja + voidsuit to assist in ninja gimmicks + - rscdel: Removed references to the spider clan from ninja voidsuit. + TheWelp: + - rscadd: Adds a integrated circuit printer to the R&D lab. +2017-02-26: + Chinsky: + - tweak: Holowarrant projectors now autosync when clicked in hand instead of having + to use verb manually. + - tweak: You can swipe ID at the holowarrant to authorize it now. + Crushtoe: + - imageadd: New external airlock and mail sign sprites. + Datraen: + - bugfix: Language sanitation now checks for species second languages in addition + to whitelist status. + Haswell: + - rscadd: Added crossfire gamemode, mercenary + raiders. Requires 25 readied players + and at least 6 antags to start. + Hubblenaut: + - rscadd: Newschannels now show the number of times they have been viewed. + TheWelp: + - rscadd: Adds an advanced integrated circuit radio. Lets players send commands + and id_tags. +2017-02-28: + Haswell: + - rscadd: Added Siege gamemode, mercenary & revolution. Requires 20 readied players, + 5 antags. + - rscadd: Added Unity gamemode, revolution & wizard. Requires 15 readied players, + 5 antags. + - tweak: Made Conflux votable, cult & wizard. Requires 15 readied players, 5 antags. + - tweak: Made uprising votable, cult & revolution. Requires 20 readied players, + 6 antags. + - rscadd: Added small energy gun variant, small size with 4 shots and reduced lethal + damage. + - rscadd: Added gun cabinet variant with small energy guns. + Nero-07: + - bugfix: Fixed holopads and tested them a bit more extensively. Should work as + expected now. + Techhead: + - tweak: Torch medical has been reorganized, full changes follow. Check your job + settings on medical characters. + - tweak: Senior Physicians are now simply Physicians, and the job is limited to + officers. + - tweak: Physicians are now Corpsmen, with updated alt-titles, including the new + Medical Technician and Field Medic titles. + - rscadd: A unique outfit for Fleet Field Medics. + - tweak: Medical Assistants are now Medical Contractors, with two slots. Medical + Resident title is gone. + - rscdel: The dedicated Virologist slot is gone, now part of Medical Contractors. +2017-03-07: + Chinsky: + - bugfix: Fixes not being able to bring up undress menu on help intent. + - tweak: You scoop up resomi/monkeys/nymph on GRAB intent now, not help. Was annoying + in surgery etc. + - rscadd: Can now put accessories on people via strip menu. Click on the clothing + item with accessory in hand to attempt to. + - rscadd: Can now pick which accessory to remove in stirp menu. + - rscadd: Explosive implants now can be triggered by remote signaler signals. Change + frequency and code in implantpad that now comes in the box with implant. + - rscadd: Explosive implants now complain on radio when they are exposed in surgery + (after retractor step for skin/ribs). Can set message in implantpad. + - rscadd: Added thicc rig to merc base. It has bit more slowdown, but more armor + overall. + Haswell: + - tweak: Improved movement smoothness with /tg/ movement code. + - tweak: People now spawn with random hunger levels between hungry and satiated. + - tweak: Reduced amount of satiety from eating by 66%. + - tweak: Ghosting messages now show where the player is ghosting from. + Hubblenaut: + - rscadd: 'Adds new haircut: Ponytail 6.' + Techhead: + - rscadd: Added a black tie outfit to the uniform vendor for civilians. + - rscadd: You can now pin medals to your service and dress jackets. + - rscadd: As a bonus, you can also put armbands on labcoats. + TheWelp: + - bugfix: Fixes circuit printer being a computer recipe instead of a machine + - rscadd: Adds ability to deconstruct an assembly and gain a protolathe recipe for + it. + - bugfix: Fixes circuit printer not having a max cap on metal. + - bugfix: Fixes certain activators not being respected when there are multiple of + them. Fixes debugger not sending activator data. + - rscadd: Adds accelerometer circuit, which lets you detect motion (and how much). + - rscadd: Adds simple locomotion circuit, which uses activators alone to control + itself. + - rscadd: Adds ai-controlled circuit. Lets ai inside itself use arrow keys to activate + certain pins. + - rscadd: Adds tile sensor, which detects items/mobs on a tile when pulsed. + atlantiscze: + - experiment: Removed bunch of NarSie's summon effects. Should considerably help + performance. + - tweak: Cult walls now have non-reinforced type, that is used when cultifying non-reinforced + walls. + sabiram: + - rscadd: Standard and research magnetic grippers can now hold modular computer + hardware. + - rscadd: Research module robots now have access to wirecutters. + - rscadd: Replacement tubes for spotlight fixtures are now available in the autolathe + and in most light tube boxes. + - rscadd: Added a new black leather satchel to the backpack selection menu. +2017-03-12: + Asanadas: + - maptweak: The Morgue now has emergency shutters. Also, more emergency shutters + spread around the infirmary. + Chaoko99: + - imageadd: Added a unique sprite for anesthetic pumps. + Cirra: + - rscadd: Pipes with exposed ends (such as those that result from a pipe bursting) + will now leak their contents into the air. To stop a pipe from leaking, attach + an endcap to the end. + - rscadd: Added Stasis Clamps to engineering vending machines, devices which can + be attached to a pipe and turned on in order to halt the flow of gas through + that pipe. Useful for sealing off sections of pipe so you can make changes without + leaking. + - rscadd: Added and mapped in Automated Shutoff Valves, which will automatically + close if their internal pressure gets too low, to limit the damage caused by + main-loop leaks. Click on an AS Valve to reset it. + Datraen: + - rscdel: Removed the hunger section of movement code. + - tweak: Doubled the rate of nutrition degradation. + - tweak: Raised the starting nutrition values. + - tweak: Reset the rate of nutrition degradation to the default value. + Hubblenaut: + - rscadd: Adds alt-click shortcut for initiating test-fire. + - rscadd: Examining the teleporter console will reveal its current destination and + accuracy. + - tweak: Teleporter accuracy does no longer automatically reset after five minutes. + - tweak: Teleporter accuracy resets after locking in to a different destination. + sabiram: + - rscadd: You can now alt-click a PDA to remove an ID. +2017-03-14: + Haswell: + - rscadd: Added ion pistols, 8 shots no AOE, normal size, can be worn on belt and + holstered. + - rscadd: Added taser carbines, 10 shots, heavy taser and heavy shock beams, large + size, can be worn on belt and back. + - rscadd: Added stun rifles, 12 stun shots, huge size, can be worn on back. + - tweak: Reinvented pulse weaponry. They now function as burst fire laser weapons, + dealing less damage per shot but with higher damage potential than their laser + counterparts. Most effective at medium ranges against non-armored targets. + - rscadd: Added pulse rifles. 36 pulse shots, high damage. Huge size, can be worn + on back. + - rscadd: Added pulse carbines, 24 pulse shots, medium damage. Large size, can be + worn on back and belt. + - rscadd: Added pulse pistols, 21 pulse shots, low damage. Normal size, can be worn + on belt and holstered. + - maptweak: Adjusted security and emergency armory contents. Added more guns. + - tweak: Added pulse weapons to uplinks. + Unknown: + - bugfix: Stasis Clamps should now function correctly when placed next to a pump, + valve, or other pipe machinery. +2017-03-26: + Asanadas: + - tweak: Orange shoes (as well as jumpsuits of all kinds) no longer are capable + of doing damage. + - rscadd: 'Added new drug/medicine: Noexcutite. Useful to eliminate jitteriness + in patients. 1 Oxycodone, 1 Dylovene.' + Chaoko99: + - rscadd: Crisis borgs can now pick up pills. + - rscadd: Science borgs can now pick up tanks, tank transfer valves, and various + other assembly items. + - imageadd: Replaced the old [CAUTION] Canister with a cleaner sprite. + - imageadd: Added a hazard stripe overlay for people to add to new canister sprites + in DM. + - imageadd: Added new phoron sheet sprite. It is orange now. + - imageadd: Added a new icon state for the admin spawnable crystal. + - tweak: Most solid phoron and phoron-based objects are orange now. Please report + old pink/purple phoron sprites on the git repo, tag @chaoko99 in the description. + - tweak: Uncommented the phoron-based object flashing code. Phoron based objects + will now combust when on a turf over 200c. + Chinsky: + - tweak: Tabling is no longer instant. Wait till aggressive grab is done upgrading + before do it (whe blue thingie is done filling). + - rscadd: Can now click yourself with cig to take a drag on it. + Haswell: + - tweak: Renegade guns now all fit in backpacks, provided there's room in there. + - tweak: Duct tape now repairs supermatter. + - rscadd: Added flashdark device, basically a flashlight that cloaks you in darkness + instead of light. Available in uplinks. Pair with thermal scanners for fun. + Hubblenaut: + - bugfix: Fixes whitespace cropping when writing on paper or using the circuit debugger. + Ravenxales: + - tweak: Fix many strings to respect the Torch environment. + RedStryker: + - tweak: Added new lore-consistent clothing items for NanoTrasen personnel. + Techhead: + - rscadd: Moves Junior Enginner to a Crewman alt-title, accompanied by the new Junior + Corpsman. + - tweak: Increased Crewman slots by one and removed age restriction. + - rscadd: Gave Raiders their very own frequency. Hopefully, no more filthy mercs + listening in on your distinguished matters of commerce. + TheGreyWolf: + - rscadd: Added uniform, dress and formal uniform for Resomii from unused sprites. + memescope: + - tweak: Gave the Scientist, RD, Senior Researcher and Research Sssistant access + to formal clothing in the loadout. + - tweak: Divided pants into formal and casual pants and put them into different + selections in the loadout. + mkalash: + - rscadd: Admins can now globally and individually mute AOOC. + - rscadd: Added a stun revolver to the NT guard lockers. + - rscadd: The Torch will now receive a report at the beginning of the round listing + the current system, the next system, and any nearby planets. +2017-03-31: + Asanadas: + - tweak: The holodeck theater's clothings have been changed to holo-chameleon equipment. + Have fun with more dress-up options! + Cirra: + - maptweak: Removed the Pulse Rifle from the emergency armoury, and replace it with + a marksman energy rifle. + Datraen: + - bugfix: Updates mechs to be able to interact with ID cards in wallets. + Leshana: + - bugfix: Fix rooms holding pressure when exposed to space. + RedStryker: + - tweak: Added new lore-consistent PDA, Locker, and Action Figure sprites for NanoTrasen + items. + - rscdel: Removed science armband. + - tweak: Recolored research tape to white. + Sin2: + - tweak: Added new lore-consistent airlock sprites to Research. + Unknown: + - imageadd: Replaced the energy sword and double saber sprites with those from TG. + - imagedel: Removed the Sord and Sord inhands. +2017-04-01: + Haswell: + - rscadd: Added singularity grenades. Works just about as well as you imagine. +2017-04-06: + Broseph Stylin: + - rscadd: Added a colorable and a horrible bowtie to the loadout, available to all + non-military roles. Icons by LorenLuke, slightly altered. + - rscadd: Skirt versions of the dress uniforms are now available for all SCG branches + in the uniform dispenser. + - bugfix: Officer's variants of the dress uniform will now show up correctly in + the dispenser. + Chaoko99: + - imagedel: Removed unused reagent container sprites. + - tweak: Removed the toy sunflower, replaced with another flower that functions + identically, but can accept reagents other than water. + - spellcheck: Added punctuation to wizard spells, and adjusted some of the shouts + to something a human being could actually say consistantly. + CountAlex: + - tweak: Added deluxe version of electronic cigarette to loadout. + - rscadd: Added electronic cigarettes and replaceable cartridges to cigarette vendors. + Electronic cigarettes come in three options; the deluxe option will later be + added to loadout. +2017-04-10: + Asanadas: + - maptweak: Flipped beach in the holodeck so you don't have to walk through holowater + to get on the holosand. + - maptweak: Added a computer console to the Security equipment storage. Now Masters + At Arms can do their job a little better. + - experiment: A changeling's deathsting now gives a message to the surrounding area. + Cirra: + - tweak: Overmap-related consoles can now properly be repaired. + - tweak: Overmap event groups are now slightly more common, and slightly larger + in size. + - experiment: The Torch now uses the Overmap system. This involves a 'system map' + which can be flown around, with away sites scattered on the map. + - tweak: The flow of fuel through the HE pipes in the SM chamber can be controlled + via an adjustable pressure gate in the Engine Room. The higher the 'Target Pressure', + the faster the thrusters will regain fuel faster after a burn, and the lower + the SM's output. + - rscadd: Added a fuel tank port of atmospherics, and all the necessary piping for + overmap. + - rscadd: Converted the four thruster areas on the vessel into engine nacelles. + It is possible to switch between direct injection and combustion, via buttons + located in the engine monitoring room. Each mode has its own advantages and + disadvantages. + - rscadd: Modified the SolGov Pilot job, so they can properly pilot the Torch. + - rscadd: Added randomly placed events to the overmap. + - maptweak: The Calypso, Aquila and Guppy are now overmap-capable, and can travel + to away sites on the same overmap tile. + - maptweak: Added Helm and Engine control consoles to the bridge, and Engine controls + to engineering monitoring and the fuel bay. + Datraen: + - bugfix: Aliens can choose their corresponding xenowear once again. + Haswell: + - tweak: Lots of things are made climbable. + Pobiega: + - rscadd: Added fuel pipes, manifolds, caps, etc. + - rscadd: Made pipe dispensers dispense fuel pipes. + RedStryker: + - tweak: Separated the NT tunic into an accessory. There is a polo below the tunic. + That polo is on the loadout. + - tweak: Changed the color of the NT worksuit. + - rscadd: Added a NT executive suit for the NTL. Also in RD's locker. + - tweak: Changed many things in Research from purple to NT red. +2017-04-14: + Asanadas: + - tweak: Master At Arms gets an extra jobslot, bringing it up to 4 in total. + Pobiega: + - rscadd: Added new per-map admin fax destinations. + - rscadd: Admins can now pick between the NT and the solgov logo when sending adminfaxes. +2017-04-19: + Asanadas: + - tweak: Master At Arms badges are now available from the security vendor. + - rscdel: Staff of change has been removed from the wizard's arsenal. + - bugfix: Uniform Vendors should no longer break horribly when you hit them with + a PDA (or anything that isn't an ID). + Chaoko99: + - tweak: Buffed blob, it will now attempt to spread about 20% more often. Lowered + laser resistance of a blob to compensate. + - tweak: Blobs are now totally opaque. This can be countered with optical material + scanners. + - rscadd: 'Blobs can now trip camera alarms. Beware: You won''t be able to use cameras + to find them, if you are not quick!' + - rscdel: Removed slimes from the pet merchant's options. + Ithalan: + - tweak: Collected robotics and infirmary surgical tools into surgical kits + - tweak: Updated surgical kit sprite and description and upped capacity to 14 slots + to allow nanopaste and laser scalpels/IMS to be stored in it too. + Nero-07: + - tweak: Increases starting TC for antags to 130 (was 100). + Orelbon: + - soundadd: New sound plays when the emergency pods unlock. + - rscadd: Added New AI Status Display. + Unknown: + - tweak: Made the mech rechargers use an alpha layer instead of the default grey + tiles. +2017-04-24: + Chaoko99: + - rscadd: 'Added Level3.mod (AKA: title1.ogg), by VScratch? as lobby music.' + FTangSteve: + - rscadd: Adds two inflatable doors to every fire closet. + Orelbon: + - tweak: Glasses and goggles have updated sprites. + RedStryker: + - tweak: Recolored the kidneys and liver to look more realistic. + - imageadd: Added a stomach sprite for later use when stomachs are coded. + Sbotkin: + - rscadd: Added more cooling units for Engineering and Expedition Prep EVA. +2017-04-29: + Chaoko99: + - tweak: Made it slightly less infuriating to speedmix the allies cocktail. (Changed + recipe from vodka and martini (Gin and vermouth) to Vodka Martini and Martini. + - rscdel: Removed highlanders and all references to their antag type. + - tweak: Upped the cost of a flashdark in the uplink from 16 to 32. + Ithalan: + - rscadd: Detached organs now show if any attached child organs have decayed + - bugfix: Organs no longer decay under conditions where their parent organ isn't + decaying. + Orelbon: + - maptweak: Emergency armory has been revamped. + ProfligateShampoo: + - rscadd: Added the ability for characters with the Cook, Bartender or Passenger + (i.e. Botanist) job to select botanical gloves in their loadouts. + TheWelp: + - rscadd: Adds vox scrap armor, armor made from pieces of metal fused together. + - bugfix: Fixes equippable items ignoring inability to equip if warnings are disabled. + mkalash: + - tweak: Added distance to Sol to roundstart report, as well as replaced random + planets with actual overmap system info. +2017-05-02: + Chaoko99: + - imageadd: Made the Resomi sonar ping contrast a bit better to most sprites. + - tweak: Changed the defib failure messages. Now it is less likely to lie outright + to you, and medical will no longer need to know the ancient defib rituals. The + machine will tell them the fix instead. + - tweak: Defib units now start with an APC power cell (Down from advanced) for R&D + to replace as the round goes on. The APC cell will be able to shock the patient + five times before needing to recharge (Down from ten.) + - tweak: Halved the power consumption of the mobile suit sensor jammer. + Orelbon: + - bugfix: Cameras in emergency armory should have proper alarm links now. + - tweak: Evacuation sound should no longer give you tinnitus. + - tweak: Reduced the amount of guns in sidearm cabinets to 3 from 4. Reduced amount + of guns in personal sidearm cabinets to 4 from 6. + - rscadd: Added a combined arms cabinet with 3 energy guns and 2 personal. + - maptweak: Changes the sidearm cabinets in safe rooms to personal ones. Removes + sidearm cabinet in Brig Officer's office. Replaces sidearm cabinet in bridge + with a combined arms cabinet. + - rscadd: New sprites for Fire and Medical wall closets. + - bugfix: Fixes a bug that failed to update the medical wall locker sprite when + it got emmaged. + RedStryker: + - rscadd: Adds a lot of hairstyles. +2017-05-06: + Ornias1993: + - rscadd: Added anesthetics pump above main surgery operating table + - rscadd: Added Nanomed above health monitoring console + - rscadd: Added Medical intercom at the south-west corner beside general intercom + - rscdel: Removed Nanomed above Main surgery operating table + - rscdel: Removed medical intercom above ealth monitoring console +2017-05-07: + Ornias1993: + - tweak: Changed genetic damage scanner output to state genetic damage instead of + improper cloning +2017-05-09: + Asanadas: + - maptweak: Robotics control consoles have been added to the Bridge, and the Engineering + monitoring room. + - tweak: The Chief Engineer has robotics access. It's part of his job, you know. + Sbotkin: + - rscadd: Added a Military Police armband. +2017-05-13: + Asanadas: + - rscadd: Tajarans now have access to cultural veils. Tajarans will spawn with the + default, and job-specific veils with the proper HUD elements are available in + the loadout tab under Xenowear. + - rscadd: Added 5 new hairstyles to Tajarans. Ported from Polaris (ported from Aurora). + Chaoko99: + - rscadd: Added the large RCD cartridge to the autolathe. + - tweak: Halved RCD cartridge prices. + - rscdel: Removed a forced usage of passive wording in examine poses. ([Pronoun] + [Pose], instead of [Pronoun] is [Pose].) + Datraen: + - tweak: Ports soft lights featured in other servers. + Hubblenaut: + - bugfix: The hull wrap mode of the shield generator will now actually cover the + entire ship. + Orelbon: + - soundadd: Added new AI voice sounds. + - tweak: Lowered the volume on the AI voices. + Ornias1993: + - bugfix: Medical veil now selectable by medical contractor. + - bugfix: EAL, Sign language, and emotes will no longer use autohiss + - bugfix: Chapel Maintenance airlock, now needs maintenance access to open. + PsiOmegaDelta: + - rscadd: Can now set your desired FPS level under Character Setup > Global + RedStryker: + - tweak: Added the Science radio frequency to mining borgs. + TheWelp: + - rscadd: Lets AI controlled circuits to use the assembly's inputs via a verb. + - bugfix: Fixed AI controlled circuits not being moved correctly. +2017-05-18: + Chaoko99: + - rscadd: Made the engine input pumps more cryo-clamp-able. + - bugfix: Moved the maintainance deck saferoom APC. + Hubblenaut: + - tweak: Lubed floors can be cleaned with water. + - bugfix: Wet floors make a comeback after three months of stealthy disappearance. + Orelbon: + - rscadd: New sprites for the ion rifle. + - rscadd: New sprites for the stun carbine. + - bugfix: small eguns should now have the right sprites for east and west. + Ornias1993: + - bugfix: Oxygen_pump and Anestethic_pump, now correctly checks if the mask slot + is blocked + - rscdel: removed on click application to user of Oxygen_pump and Anestethic_pump + - tweak: Oxygen_pump now gives out Breathmasks instead of gasmasks + - tweak: anestethics_pump now gives out Medicalmasks instead of gasmasks + - bugfix: Maintenance hatch and replacing tanks works now on Oxygen_pump and Anestethics_pump + - tweak: removed organic requirement for removing the oxygentank of Oxygen_pump + and Anestethic_pump + - bugfix: UI of oxygen_pump and Anestethics_pump works now + - rscadd: AI can now click to open UI of oxygen_pump and Anestethics_pump + - rscadd: Added the Anestethics Mask for the Anestethics_pump + - rscadd: Added the Emergency Mask for the Oxygen_pump + - spellcheck: Fixed brusies typo on Torch Holodeck disclaimer + RedStryker: + - rscadd: Added boxes of armbands for emergencies to the heads of the Security, + Medical, and Engineering departments. + - tweak: Allowed a few more roles to use flats. + - rscadd: Added many new clothing items as accessories. + - tweak: Changed the color of the cheongsam to allow it to use the color gear tweak. +2017-05-20: + Chinsky: + - rscadd: All toys guns are now fitted with red bits on the barrel so you can visually + tell them apart! Very safe! Fun for whole family! + - rscadd: Can use wirecutters on toy revolvers to snip those off. It also changes + examine name to 'revolver' instead of 'toy gun'. In case you didn't know, those + are proper guns and you can hold people hostage with those. Just saying. Do + not try at home. + Cirra: + - tweak: Attempting to place an airlock brace without setting an access requirement + now informs you, and asks for confirmation. + Orelbon: + - rscadd: Added inhand sprite for stun rifle. + Ornias1993: + - bugfix: Everyone including military can now take sunglasses from loadout. +2017-05-23: + Asanadas: + - tweak: Maintenance Drones now require an account of age 3 days or greater. + Chinsky: + - tweak: Bunch of virus changes. Buckle up, kiddo. Praise Nurgle + - rscadd: Adds Space Cold event. Spawns a harmless virus that can be treated with + cold medicine. Unless you're irradiated and it mutates to kill everyone I guess. + - rscadd: Adds space cold medicine (dextra-something) to white first aid boxes. + Can also be made by mixing paracetamol+sugar. Eating it will stop weak viruses + symptoms from manifesting. + - rscadd: Humans now have crude immune system simulation. Keeping your immunity + high makes it easier to shrug off viruses, extremely low (15% and less) immunity + can get you random space cold-level infections. Get lemons for boosting it, + spaceacilin ruins it. It recovers to norm over time. + - tweak: Spaceacillin now ODs at 15u instead of 30u. + - tweak: Spaceacillin now metabolizes faster. It was 60+ minutes for 15u, 30 minutes + now. + - tweak: Spaceacillin boosts immune system effective rating. It acts as a multiplier + to natural one, from 1x at none in blood to 2x at OD threshold (15u), and you + can go higher if you don't mind ODing. Also if natural immunity is lower than + the boost, boost would just replace it. + - tweak: Spaceacillin has three stages now. Below 10 units it acts kinda like now, + blocking badness 2 virus effects. Virus would still progress though, but effects + won't fire. It's enough for any random event virus effects. + - tweak: Above 10 units it would completely stop progression of badness 2 viruses + and stop effects of badness 3 - which is usual stuff ou get from viro labs. + Again, clock will still be ticking. Also at this stage it starts lowering your + natural immunity value. + - tweak: And then, there's OD. OD stops badness 4 (e.g. Gibbingtons) from manifesting, + and stops ticking of lower viruses. It screws your immune system even stronger + too. + - tweak: It's also not 100% protecting you from infection now. 15u and above give + old 100% protection, scaling with lower value in blood. + - tweak: Some tweaks to virus annoyningness. Hard delay between firings (25-40 seconds + between message-only syndromes), emote syndromes (groaning, moaning, screaming) + are now single syndrome to make it rarer. Internals actually stopping you from + spreading viruses. No airborne viruses in vacuum. + - tweak: As an unrealated bonus, first aid (white and fire) boxes now have paracetamol + bottles because damn it's easier to score opiates than that. + - tweak: Oh also remember how when you graft yourself Tajaran arms it kills you? + Not when your immunity is floored. Just saying. + Orelbon: + - maptweak: Tech storage has been moved to deck two, where the abandoned officers + mess was located. The officers mess has been moved into the previous location + of tech storage. +2017-06-03: + Ace McLazer: + - rscadd: Added Towels to Sweatmax products. In all kinds of colors! Ported from + Polaris. + Albens: + - maptweak: Added a new Bridge + - rscadd: Added a Bridge Officer's locker, and 'Standard' Tablet/Laptop that spawns + on the Bridge. + Cirra: + - rscadd: As a failsafe, the maintenance hatch on a cyborg/android/robot will now + unlock upon death, allowing easier recovery of the brain inside. + Hubblenaut: + - rscadd: Added coffee pots and carafes, available in the dinnerware vending machine. + - tweak: Hot drinks now have vapor on them. + Orelbon: + - maptweak: Engineering locker room and storage have been tweaked. + SiegDerMaus: + - rscadd: Adds a new magnetic flechette weapon, available via uplink. + Sunsar: + - tweak: Made light bulbs a bit brighter. Engineering should be less of an eyestrain + now. + ZeroBits: + - rscadd: Added Barbecue Sauce as a Condiment. + - tweak: Changed the mailroom flaps to airtight flaps. + - rscadd: Added a second mop to custodials. + - rscadd: Added rings to the loadout selection. +2017-06-06: + Asanadas: + - rscadd: High jittery levels will now cause heart damage. + - rscadd: Individuals with robotic hearts will no longer suffer from jitters. + Ithalan: + - rscadd: Added turtleneck sweater as accessory. +2017-06-11: + Asanadas: + - rscadd: There's now a neat lore splash window which will spam all new accounts + under 7 days old. Read it! + Chaoko99: + - tweak: Made Digital Valves removable. + Hubblenaut: + - rscadd: Digital warrants can now be archived, so they don't have to be deleted. + - rscadd: Security gets automatically notified on new warrants through their HUDs. + - tweak: Improved the digital warrant interface. + Leshana: + - tweak: Optimized the unified radiation system. Made the radiation cutoff level + configurable. + - bugfix: Standing still won't save you from radiation storms. + Ravensdale - original work by anewbe: + - bugfix: Removed the exploit by which you could gain cargo points by ordering plastic + crates. + - rscadd: Upped cargo point gain by 50%. + Unknown: + - maptweak: Atmoshperics has been edited to make it easier to change and modify + pipes. + ZeroBits: + - rscadd: Added Independent Language. + - rscadd: Added signet rings, which act as stamps and rings, and can be personally + claimed by clicking them in-hand + - tweak: Rings are now compatible with the material system, and can be made via + sheets. + - bugfix: You can no longer clip rings like gloves, and all species except Diona + can wear them now. +2017-06-17: + Asanadas: + - bugfix: No longer will you be able to freely pass onto upright tables by moving + onto them from a tile which has a flipped table. + Chaoko99: + - rscadd: Added a mass-defile cultist rune. Buyer beware; it may kill you. + - rscadd: Cult tiles play a snazzy animation on creation. + - rscadd: The soulstone shard now notifies the player when it is full, asks if you + wish to release the spirit within. + - rscdel: Removed Manifests from the cultist repertoire. + - rscdel: Removed defile giving cultist levels. + - tweak: Changed the values for cultiness (The value which controls spell levels). + You will need to either recruit 10 cultists, or perform 10 sacrifices to unlock + Nar-Sie. + - tweak: Nerfed cultist robes. Buffed cultist voidsuits. The latter of which is + still impossible to obtain. + - bugfix: Made the restricted/protected/blacklisted roles for cultists torch-compatible. + - bugfix: Fixed construct and familiar spells. + - rscdel: Removed Vox Pariah. + Chinsky: + - rscadd: Can now rig assemblies/devices(e.g. radio signalers) to trigger when crate + is opened. Click wires on open crate, then click with assemblies. It would trigger + when opened next time. Use wirecutter to unrig. + - tweak: AI cores got new step in construction. You need to swipe an ID with Upload + access (or emag) to hook them into the systems. + - rscadd: Added rubber masks and suits to party crate. Dress up as war hero or SCG + secretary or a naked tajara like you always wanted. + - tweak: Made SHOCK mode on tasers literally useless, ruining security gameplay. + Does bit less burn damage, and much less straight up stun damage. Not 'better + tase mode' anymore. + - bugfix: Fixed their primary function actually never working. If you hit arm or + hand with the beam you can disarm someone (even diona, even robbit, pain reception + doesn't matter). If you hit leg, they might drop, higher chance for foot. + Hubblenaut: + - bugfix: Manifold pipes show up properly on t-ray scanners now. + - bugfix: Space lube now properly disappears. + - tweak: Can now put items in vendors by using click and drop, thus allowing screwdrivers, + multitools and similar. + - tweak: Space heaters will now first attempt to draw power from the local APC. + sabiram: + - rscadd: Research module robots now have access to a welding tool. +2017-06-19: + Chinsky: + - tweak: Speed now matters when flying into meteor field. Still - 25% the meteors, + below 0.3 - 60% of usual, normal otherwise until above 3 speed, where you start + getting double the fun. Also if ship is moving most meteors will fly in from + front and sides. + - tweak: Changes spess dust event. It used to be a single wave of quasi-meteors + that exploded for a bit before dying. There were no further waves until you + left and came back. Now waves keep coming ~twice a minute. Dust itself is now + a pile of micrometeors - basically space bullets. It wouldn't do a lot of damage + to the hull, but can break windows and makes EVA pretty damn dangerous. + - tweak: SCG had mastered the secret art of 'background check'. CO and XO are no + longer be eligible for roundstart antag roles on Torch. Can still be converted + in round + - bugfix: As a side effect, they aren't going to get rev'd anymore, that was a bug. + ZeroBits: + - rscadd: Added the ability to have multiple loadouts per character. + - rscadd: Added magic invisibility ring and reagent rings. + - tweak: Rings are now a child of clothing rather than gloves in order to appease + code gods. + - tweak: Gloves can now be worn over rings (much like magboots with shoes). + - rscadd: Added coffee cups to the loadout selection. + - rscadd: Added threebread, blueberries, pancakes, and two new flavors of ice-cream. +2017-06-30: + Chaoko99: + - tweak: Poppies now contain tramadol. + - bugfix: Fixed the phrasing in the set-pose verb. + Chinsky: + - rscadd: NT has sent some more testing supplies. Nothing to see really. RDs can + find details in a super secret folder in their office. Others - do no peek, + ok. + - tweak: Surgery now produces normal wounds instead of snowflake 'open incisions'. + Do not be alarmed, do not bandage those if you plan to continue surgery, clamp. + If incision was made with scalpel, you'll be able to cauterize it, healing a + lot of damage. + - tweak: Skull/ribs surgery changed, now you just need to use the saw to crack em. + Fractures count as being open too. Retractor steps for ribs etc are gone, use + normal bone repair surgery aferwards. + - tweak: Coincidently you can just rip them apart with cut wounds to get access + to innard surgery steps. It takes much more damage than surgical incisions though. + - tweak: Bones now fracture when damage is taken rather than from existing damage. + Meaning if you fix bones, they won't refracture immediately without taking damage. + - tweak: You don't need to crack open the bones to get shrapnel now. If you can + see it on examine, you can take it out with just a retracted incision. + - rscadd: Added new surgery step - disinfecting wounds. You can use sterilizine + or high proof booze, in spraybottles/droppers/bottles/glasses/buckets. Works + same as ointment. + ParadoxSpace: + - rscadd: Adds darksight to space adapted humans + Ravensdale: + - tweak: Cultists now speak in the cult tongue when activating runes instead of + their default language. Done in case a changeling cultist ever becomes a thing. + - rscdel: Removed special human kabobs and burgers. Lumping all items that are 'red + meat' together. + - tweak: Adjusted AI tracking verbs. AI will now have a more difficult time tracking + specific people depending on method and if person has their face concealed. + - tweak: To bring some consistency for the above, also adjusted how names appear + on mobs that have some sort of face covering or a face that is... not there. + Zucchinsky: + - rscadd: Beeg medical changes. Like holy crap. Get a crash course on https://wiki.baystation12.net/index.php?title=Zuhmed_Guide + - rscadd: Death now occurs when brain dies. Brain's health replaces overall 'health' + - rscadd: Death is now FINAL, baring relacing. Don't let that brain die. + - rscadd: Crit now exists as flatlining, the heart failure, or as fancily 'asystole'. + It happens when heart is damaged, not enough blood or oxygen in blood, or high + levels of shock. + - rscadd: In crit you do the usual gasping thing and take brain damage. USE CRP + or defib to revive em. If they die before you crack ribs, you hadn't tried hard + enough. + - rscadd: '''Toxins'' damage is now overall organ failure, basically sum of organ + damage. Poisons will try to destroy liver and kidney first, and will damage + the rest after those two are down. Some poisons go straight for vitals. Liver + will heal self until it''s too damaged.' + - rscadd: '''Suffocation'' damage is now used as modifier to your blood levels. + If you don''t get enough air, you get effects of low blood basically.' + - rscadd: Defibs now restart failed hearts instead of reviving dead. Also named + differently now. + - rscadd: Most scanner readouts are changed now. Instead of damage values they report + vitals (pulse/blood pressure/brain activity) and general state of damage. + - rscadd: A D R E N A L I N E. When you take a good chunk of damage at once (15 + or more in one hit) you generate bit of adrenaline reagent according to damage + taken. It acts like strong painkiller / pulse raiser for a tick or two, becoming + weaker after that. + - rscadd: FBPs and IPCs now have batteries in their chests. They have HYPERCELLS + and drain when they stand (unbuckled) or move around (double drain then). + - rscadd: Sleepers now have stomach pumps, same as filtering but for ingested stuff. + - rscadd: Cultists yo - sacrifice rune now works on someone in asystole rather than + full braindeath. Knives now count for all steps needed to cut out the heart, + and cult runes count as surgery spots. Just sayin'. + - rscadd: Bunch of chems is different now. First off, none 'reduce' toxins damage, + aside from peridaxon cause tht's organ damage now. + - rscadd: Peridaxon only treats brain damage if it's not too severe. Get Alkysine + otherwise. + - rscadd: Alkysine will only work if brain is fully oxygenated, so refill blood + and air first. + - rscadd: Dylovene removes toxic reagents from blood. + - rscadd: Dexlaine fools brain into thinking you got at least 50% of air you needed. + For Dex+ it's 80%. + - rscadd: Cryox/Clonex also have Dex/Dex+ effect respectively. + - rscadd: Inapro prevents suffocating while in asystole, slows pulse down (which + slows bleeding a bit) and has mild painkiller effect as it did. +2017-07-06: + Chaoko99: + - tweak: Added a full belt to engineering lockers. + - tweak: Removes all (direct) references to Metroids from our codebase. Not being + sued is nice. + - imageadd: Replaced our RPED sprite with /TG/'s, and added a little animation atop + that. + Chinsky: + - rscadd: Can now scoop corgis up, like cats or nymphs etc. + - rscdel: Can also use them instead of sausages in microwave to make hotdogs. Geddit, + hehehe hot dogs. Riot. + - tweak: GUPpy, Calypso and Aquila now can share destinations, as long as they can + fit. + - rscadd: Excavation prep closets now have BLUESPACE FLARES. You can activate those + in a nice open spot to create a new navpoints for shuttles (ones mentioned) + to go to. + - rscadd: Exploration shuttles (Calypso/Guppy/Aquila) now can share destinations + (with some other shuttles too). + Heptagon49: + - tweak: Replaced the synthetic lung sprites with something more realistic/futuristic. + - rscadd: Added artificial and assisted lungs to the loadout menu. + Hubblenaut: + - rscadd: Coffee cups are now available across the ship. + - tweak: Coffee cups now have reagent fill states. + - bugfix: Fixes glass of cup of tea. + thasc: + - bugfix: Ghosts can hear binary chatter again. +2017-07-09: + Chaoko99: + - tweak: Made it so a butterfly knife spawns in your hand instead of on the floor + when completed. + Chinsky: + - tweak: Bluespace jump effects have changed. Engineers found that some duct tape + got unstuck because of a WD40 leak, so they fixed it. Now you can't zoom through + the walls, and visibility is a bit better. You also don't get confused forever, + just for a minute or so. There are some... unforseen side effects, but they + seem harmless. A word from Chief Tech (before his disappearace) - KEEP IT REAL. + Hubblenaut: + - rscadd: Gives holowarrants their own handheld item. + - tweak: Holowarrants will now broadcast updates on warrants instead of security + HUDs. + - tweak: Authorizing a warrant using the holowarrant will now broadcast a message. + ParadoxSpace: + - rscadd: Unathi across the universe have been informed of new lore changes, and + can now be a maximum age of 260. + Ravensdale: + - bugfix: Exosuit/mecha pilots can once again operate airlocks from the safety of + the cockpit + mkalash: + - tweak: Replaced adminhelps with a ticket system. +2017-07-14: + Atlantiscze: + - tweak: Max pressure on omni filter/mixer output is now capped at approx. 7500kPa + - tweak: Atmospherics pressure tanks can now be set to output up to 15000kPa + Heptagon49: + - bugfix: Changes the recipes for Methylphenidate and Antidexafen so they no longer + overlap. Methyl now requires lithium instead of hydrazine, and antidexafen now + requires carbon instead of sugar. + - tweak: Lowered the max damage of internal organs, except for the brain and cortical + stack. + - tweak: Prosthetic internal organs are now stronger then regular organs. + - tweak: Kidneys are actually important now. You will slowly take toxin damage if + they are missing or busted, same as the liver. + - imageadd: Changed the sprites for the prosthetic liver and kidneys. + - rscadd: Prosthetic lungs half the toxin damage taken from breathing bad air. + - tweak: Made assisted organs slightly worse. + Hubblenaut: + - tweak: Air shutters will not be automatically opened by a clearing air alarm when + it would be dangerous to do. + ParadoxSpace: + - rscadd: Unathi across the galaxy have realised the implications of having tails, + and now use them to attack instead of their legs. + atlantiscze: + - rscadd: Can now order OCP and plasteel from cargo. Furthermore, 10 and 50 sheet + crates are available for some more expensive sheet types, with 50 sheet crates + being more cost efficient. + mkalash: + - tweak: Replaced tgui ticket panel with an autoupdating basic Topic() one + - rscadd: Added time stamps to messages on the ticket panel, and a measure of how + long an unanswered ticket has been open + - rscadd: Added a PM button to the ticket panel + - tweak: Adminhelping with an open ticket will either send another adminhelp to + the same ticket, or PM one of the assigned admins if there are any + - bugfix: No more sanitation weirdness in ticket panels + - tweak: A ticket is no longer created anyway if an admin cancels sending a PM to + someone who didn't have a ticket + - bugfix: Fixed admins being able to create tickets for logged out players + - bugfix: Fixed mods and trialmins being unable to use the ticket panel +2017-07-24: + Hubblenaut: + - tweak: If a cycling airlock is already near the target pressure, pressing the + buttons will toggle the doors instead of making it reenter the cycle process. + - bugfix: Fixes blood splatters reappearing when lifting or putting floor tiles + down. + PsiOmegaDelta: + - rscadd: Species may now be restricted from selecting certain branches, ranks, + and occupations as according to lore. + Ravensdale: + - maptweak: Changed the colours of the pipes in atmosia to follow older color 'codes. + SiegDerMaus: + - rscadd: Added uniforms for Miranians for future events.. + TheWelp: + - rscadd: Allows Vox to be used in character setup. They are still restricted rule-wise + as they were before. +2017-08-01: + Ace McLazer: + - rscadd: Added A grunt emote for the grumpy. + - tweak: Tweaks Medibot statement for accuracy. + - imageadd: Adds Renegade AntagHUD Icon. + - imageadd: Swaps Medical belt Icon to blue + Crushtoe: + - rscdel: Removed transformation sting. + FTangSteve: + - bugfix: Fixes dionaea jitter. + - bugfix: Fixes dionaea limb regen. + - rscadd: Adds species based footprints when barefoot. + - rscadd: Gives GAS the ability to move over gaps or stop fall damage based on air + pressure. + - bugfix: Fixes some bugs with the GAS cloaking and stance switching. + - bugfix: Fixes damage overflowing max limb damage being negated. + - tweak: Makes wounds on limbs more realistic by letting them overflow max damage. + - rscadd: Adds ability for limbs to be injured irreparably, requiring amputation + or removal. + Heptagon49: + - imageadd: Adds everyone's favorite hotdog-based meme to the AI icon list. Now + contains 2% real corgi flavor! + Hubblenaut: + - rscadd: Replaces flashlights in Security with maglights. + - tweak: Removes security HUD sunglasses from lockers and makes them available in + loadout instead. + - tweak: Personal lockers now display their owner's name in their name. + - rscdel: Removes the box of military police armbands from CoS' locker. + - rscdel: Removes the box of solgov police badges from the Brig Officer's locker. + - bugfix: Lockers reset all random pixelshifts of their contents. +2017-08-07: + Atlantiscze: + - rscadd: Added ability to ban devices from the NTNet network, through the administrative + utility program. + - rscadd: Security cyborgs now get access to warrant program + - rscadd: Engineering cyborgs now get access to supermatter monitor program + - rscadd: Mining cyborgs now get access to supply management program + - tweak: Holowarrant now checks for access when authorising, similar to how the + program does it. + - rscadd: 'Added new program to the modular computer framework: NTNet Access Decrypter. + This program is available for download on all emagged devices, but relies on + ID card slot hardware. When executed it slowly (takes about 3-6 minutes, depending + on the device''s CPU) hacks the network and when finished adds a random access + to the ID. ID must be kept inside the device while running. Can be repeatedly + used to get multiple accesses. Has chance of yielding access that''s already + present on the ID, and therefore will do nothing wasting some time.' + Broseph Stylin: + - rscadd: Added weight lifting machines and punching bags. They provide no mechanical + benefits, and will deplete your nutrition as they're used. The weight machine + has 3 setting which can be changed with a wrench. You must be on harm intent + to use the punching bags. + - maptweak: Remapped the Deck 3 abandoned office, near EVA Storage, into a gym. + Cirra: + - bugfix: Fixed an exploit which allowed for the creation of infinite metal, using + the circuit printer. + CrimsonShrike: + - rscadd: 'Added new accesory slot: insignia' + - rscadd: Allowed more accesories on dress and service jackets. + - rscadd: Security vests now come with stripes to hang badges and other similar + insignia accesories. + - rscadd: Detective coat has now a slot for the badge too. Gone are the days of + flashing suspects to show your identification + - rscadd: Colonial Marshals have now learned to keep their badges visible aswell. + - bugfix: Emaged light replacers will now properly place explosive lights. + Datraen: + - rscadd: Adds directional states for softlight overlays. + - bugfix: Fixes lights on rotated views. + FTangSteve: + - bugfix: Fixes bug that stopped wounds from healing. + - bugfix: Fixes bug that made brains not take damage from low blood unless they + already had damage. + - bugfix: Fixes bug that made moderate blood loss damage your brain until death. + - tweak: Makes the irreparable point twice the limb cutoff threshold instead of + equal to it. + - tweak: Prevents vital external organs from being irreparable, instead they go + to critical. + - tweak: Updates advanced scanners with new wound severity levels. + - tweak: Smooths the dexalin and dexalin plus effectiveness curves. + - bugfix: Fixes pulling grabs when the affected person can't move. + - bugfix: Fixes GAS being able to use advanced tools when nabbing. + - bugfix: Fixes grabs with the ladder_carry ability carrying people up ladders. + - tweak: Stops GRAB_NAB base grabs from throwing people. + - bugfix: Allows GAS to remove lights by hand. + - bugfix: Moves GAS eyes below the lighting layer. + - bugfix: Stops mice from pushing crates, lockers, etc. + - tweak: Stops mobs from using pull to move larger mobs (grabs still work). + Heptagon49: + - rscadd: Adds the ability to toggle locks on secure lockers and crates with alt-click. + - rscadd: Adds the ability to open and close fire extinguisher cabinets with alt-click. + - rscadd: Adds the ability to rotate chairs with alt-click. + - rscadd: Adds the ability to change reagent amount tranfer with alt-click. + - tweak: Lowers the odds of vending machines going absolutely ballistic. + - imageadd: Adds a new robot sprite to the security module selection. + Legius: + - bugfix: Sign Language is no longer displayed to clients who are unconscious or + asleep. Probably. + PsiOmegaDelta: + - rscadd: Players with custom AI displays can now have multiple entries, should + they desire. + - rscadd: Players with custom AI displays can now freely select between their custom + and available displays. + - rscadd: Players with custom AI displays no longer have to supply the crashed/dead + AI state. + - rscadd: Traitor/Malfunctioning AIs now have access to additional AI displays. + SierraKomodo: + - rscadd: Added berets that allow a custom color to be set to the loadout menu. + - bugfix: fixed transparent pixels in white beret sprite. + TheWelp: + - rscadd: Adds deity follower tracking and better deity eye in general. + - rscdel: Removes need for deity floors and respective spell. + - rscadd: Nar-Sie zombies will automatically get all of their blood filled when + zombized. + - rscadd: Nar-Sie zombie's breathe will convert faster. + - bugfix: Fixes nar-sie blood forge being automatically unlocked. + nearlyNonexistent: + - rscadd: Added vending machine to the code that contains dice, cards and related + toy type items. One is in the mess hall. + - maptweak: Adds paper for civilians in the mess hall and lounge. Removed a stool + in the mess hall to add the vending machine. +2017-08-12: + Atlantiscze: + - rscadd: Cyborgs can now manipulate IV drips and chemistry grippers can now hold + blood packs. + - rscadd: Improved some SMESes around the station - mainly the Engine SMES. + - rscadd: Shuttles now have a SMES with single transmission coil in them. Primary + input is the main grid, secondary input is a PACMAN generator. + - rscdel: Removed stashes of phoron from the shuttles (they can operate without + generators now) + - bugfix: Fixed bug which caused shuttles to be remotely powered even after cable + connection was severed by jump + - tweak: Rewired SMESes in engine SMES room. Engine - Core SMES can now be charged + from main grid, for example through solars. + - rscadd: SMES and PSU units can now have more than one input terminal at once. + Broseph Stylin: + - tweak: Changed access requirements aboard the Aquila. Helm and Secure Storage + remain as Aquila-specific access, but all other areas have been made SCG Crew + or all-access. + - tweak: Changed sidearm cabinet access requirements. Only line officers, the RD, + the SEA, and the Brig Officer can unlock them now. + Chaoko99: + - bugfix: Makes title1 run at roundstart. + Crushtoe: + - maptweak: Added a First Deck Lounge in the Observation Bubble. + Devildabeast: + - rscadd: Defines an armed role for the Loadout, which includes all jobs that are + allowed to carry weapons from round start. + - rscadd: Adds Scientist and Researcher to semi-formal roles. + - tweak: Frontier clothes are now its own separate item instead of a formal outfit + and can be worn by non-military roles. + - tweak: Holsters can now be selected by armed roles. + FTangSteve: + - rscadd: Added a paramedic alt title for medical contractor. + - rscadd: Added a admin debug verb that lets you see a health summary, same as the + advanced scanner in medical. + - tweak: Makes splashing solutions and using eye droppers only work when not on + help intent. + - tweak: Makes dylovene more effective to help with liver damage and recovery from + severe damage. + - bugfix: Fixes necrotic internal organ surgery. + - bugfix: Changed how toxins work so they now are effective. + - bugfix: Alcohol is once again potentially damaging. + - bugfix: Increases processing accuracy for liver and kidneys. + - bugfix: Radiation now does damage again. + - rscadd: There is now a popup after taking enough brain damage as a stand-in for + clone memory disorder etc. + Heptagon49: + - rscadd: Adds a 1% chance for a diona nymph to pop out when you activate a vending + machine. + - imageadd: Adds a few vending animations. + - tweak: Changes the NutriMax icon from the nutrimat to the pre-existing, but unused, + nutri. + Superbee29: + - tweak: Telecommunications servers no longer know the exact race of a speaker. + TheGreyWolf: + - rscadd: Mechanical and assisted kidneys and livers are now available in character + setup. + TheWelp: + - rscadd: Adds two new Nar-Sie phenomena. + - rscadd: Adds two generic feats involving power generation. + - tweak: Communication phenomena can now be used on non-cultists. We will see if + this is a good change. + - tweak: Tweaks a few of the phenomena names to be more apparently phenomena. + - tweak: Buffed Nar-Sie's power costs (reducing them). + nearlyNonexistent: + - rscadd: Cardemon instructions! Now you can actually play those weird pokermon + cards rather than just look at them. +2017-08-19: + Atlantiscze: + - rscadd: Re-adds on-join announcements to all ranks. + - tweak: Most jobs are announced on relevant departmental frequency (if they have + one). During red alert all jobs are announced on main frequency. + - tweak: Canisters now once again use NanoUI, instead of tgui. Performance on some + devices should be considerably better. + - tweak: AI can once again track people by clicking their name from radio messages, + even when their face is obstructed, assuming they are at least wearing a matching + ID. + Chinsky: + - tweak: Slimetoxin. Slimetoxin changed. Instead of pop and go slimeficiation it's + now a life threatening process. Slime toxin metabolizes slowly, and deals fair + bit of toxins damage. For every unit or so metabolized, it mutates one limb. + Once every limb mutated, there's a 10% every tick to fully mutate into a slimegirl. + If you're lucky, you might mutate right before death and that'd heal your all + wounds! That' a great idea! + Devildabeast: + - rscadd: Adds a cyborg recharging station to the Auxiliary Head. + - rscdel: Removes toilet from said Head. + FTangSteve: + - tweak: Adds more signals letting someone know they have toxin damage and giving + them a chance to get help. + - tweak: Adjusts how often internal organ damage messages are displayed. + TheGreyWolf: + - rscadd: Added hoods to standard hoodies. + tlc2013: + - tweak: Updates the Lobby and Nuclear Explosion cinematics to be more Torch-y. + Special thanks to 50_n00b for the art. +2017-08-23: + Broseph Stylin: + - tweak: The Body Scanner console and IV drips are no longer dense and can now be + walked through. + Chinsky: + - rscadd: Air analysers now have verb to be toggled into advanced mode. It displays + gas properties like specific heat and molar mass. + - rscadd: Air analysers can also now be used on pipes and various atmos machinery + to inspect the contents. + FTangSteve: + - tweak: Makes it easier to recover people from severe radiation damage. + - tweak: Puts a limit on recovery time for surgery with peridaxon, two minutes after + death the organ will no longer be savable. + PsiOmegaDelta: + - rscadd: Underwear is now handled as actual items. + - tweak: Your own underwear can be removed using the 'Remove-Underwear' verb. + - tweak: You can remove others underwear through the strip-menu. + - tweak: To put on underwear, on yourself or someone else, click the target mob + with the underwear in your active hand. + - tweak: The wardrobe now offers a limited quota of underwear if replacements are + needed. + - tweak: You can increase this quota by returning underwear items. + TheGreyWolf: + - rscadd: Tattoos are now available in character setup. + ZeroBits: + - bugfix: Manuals now point to the correct wiki pages. + - tweak: Cleaned up and organized manual files. + - rscdel: Deleted redundant manual that pointed to the same page as another. + Zuhayr: + - rscadd: Diona nymphs can now pick up and carry a small item. Use the drop_item + command or the Home key to drop it. This can also be used to remove your hat. + - rscadd: Losing your head is no longer necessarily lethal, unless you're the kind + of fat nasty trash who has a brain or other vital head organ. + chinsky and mkalash: + - rscadd: 'A randomly generated exoplanet of one of the following for types is now + available for away missions:' + - rscadd: Grassy exoplanets, lush with (probably dangerous) flora and fauna, but + not much else + - rscadd: Snowy exoplanets, like grassy but colder and with less life + - rscadd: Desert exoplanets, rich with minerals below the surface, which is covered + with dangerous quicksand + - rscadd: Mountainous exoplanets, one of the three other options, but also covered + with surface minerals + - tweak: Additionally, the airlocks of the three shuttles aboard the Torch now cycle + to the external atmosphere. + nearlyNonexistent: + - tweak: Fixes the inability to make enchiladas by making popcorn require salt. + Enjoy your salted popcorn. + sabiram: + - bugfix: Maintenance drones now once again take damage and recieve alarm notifications. +2017-08-27: + Chinsky: + - rscadd: Added a ton of usless gasses. Overall fireball planets should be slightly + more rare now + - tweak: Lighters now have fuel storage inside, and will shut down if it's empty. + Can refill at any welder fuel tank. + - rscadd: Can now dig graves planetside. Use shovel on ground to dig a pit. Can + place grave markers with wooden planks. + - experiment: When you speak now, your first name is replaced by your rank in messages. + Only affects those with military rank and wearing ID with it. + FTangSteve: + - rscadd: Adds insulated gloves for nabbers. + - rscadd: GAS can now be chemists and engineers.. + Minijar: + - bugfix: Fixes holosigns to appear above doors + atlantiscze: + - rscdel: Removed Turrets Focus Enhancer malf AI hardware, it is obsolete now. + - rscdel: Hack Camera replaced with Reset Camera. No longer allows camera upgrades, + this has been shifted to Machine Upgrade. + - rscadd: Added Quantum Knowledge Databank malf AI hardware. On use it advances + all research by one level. Single-use. + - rscadd: Added T5 Machine Upgrade ability, behind Machine Overload. Right now only + works on APC, SMES, Turret, Turret control, Camera. It is easily expandable + to any machinery in the future. + - rscadd: Adds four new abilities in a new passive tree. T1 prevents intellicard + transfers (toggleable), T2 removes BSOD/lockout from APCs, but reduces CPU generation + (toggleable), T3 prevents hack failures, and allows you to complete system override + silently and T4 prevents fax/emergency messages from going through. +2017-08-30: + Chinsky: + - rscadd: Health analyzers, advanced scanners and suit sensors will now report blood + oxygenation instead of just how well it flows in general. + - rscadd: If you go near an edge of exoplanet, you get warped around, kinda like + in space. Don't get lost, nerds. + - rscadd: Lush planets now have some drillable minerals too - some coal with a small + chance of diamonds or uranium. + - rscadd: Movie titles music now uses lobby music preference toggle to see if it + should play to you. + Crushtoe: + - maptweak: The derelict is no longer complete trash. There's actual rooms and plenty + of loot to loot, too! + - rscadd: Added random spawns for hostile mobs on the Derelict. Now the good loot + has a guardian pike/carp/viscerator. + FTangSteve: + - bugfix: Updates GAS to properly use the bloodmed system. + - bugfix: GAS eyes are no longer vulnerable to phoron in the air. + - bugfix: Fixed bug with humans not taking oxyloss after two minutes of not breathing. + - tweak: GAS now store more dexalin. + - tweak: Updates unit tests to include GAS. + - tweak: Updates unit tests to work with adjusted oxyloss system. + Minijar: + - tweak: Changes blue alert to orange + - rscadd: Replaces the bluespace artillery cannon with a prototype RUST fusion reactor + for engineering to experiment with. + - tweak: Edits the RUST manual to fit the new setup. + PsiOmegaDelta: + - experiment: Overhauls how reagents are identified, affecting both chemistry and + food. Due to the large scale of these changes more or less subtle bugs may have + crept their way in. + ThatOneGuy: + - rscadd: Can now play as the Explorer Department if you are a EC member. If a complete + failure, up for removal. + - rscadd: Calypso remapped for more cargo space and crew area. Bathroom and Cryo + deleted. + TheGreyWolf: + - rscadd: Fixed up pathfinder and explorer loadout. +2017-09-03: + Earthcrusher: + - bugfix: The electrified arm (e-magged/traitored Engineering borg module) now behaves + like a stun baton. It can be toggled on/off. + - tweak: Activating the electrified arm will now cause the borg to glow a faint + blue, giving away that they are using it. + - imageadd: Added a unique sprite for the electrified arm. + Kelenius: + - tweak: Pulling a knife out of your boot or putting it in no longer makes a message. + Minijar: + - bugfix: Adds atmospheric systemst the rust chamber + - bugfix: fixes the rust airlock + - bugfix: Removes accidental vacuum flooring + ParadoxSpace: + - rscadd: Adds Selenian, a lunar language for those who still hold onto that silver + spoon. + - rscadd: Adds Spacer, a language of Dutch origin for non-landlubbers. + - rscdel: Took Tradeband out back. + dryerlint: + - rscadd: Added ability to put paper bundles directly into paper bins and nano-printers. + - rscadd: Clicking on paper while holding a paper bundle now adds the paper onto + the bundle. + - rscadd: Added new type of crate - the paper refill crate - filled with 30 blank + papers. Intended to be used for refilling bins and printers. + - maptweak: Placed paper refill crate in Deck 1 Maintenance near the Conference + Room. +2017-09-08: + Chinsky: + - rscadd: Calypso is dead, new shuttle is here in same role - Charon. + - rscadd: Can now hide custom loadout items that are not allowed for your job. The + button's in top of loadout menu. Makes browsing less of pain for those with + lots of restrictions. + - rscadd: Wildlife will now respawn if more than half is killed off. Beware. + - rscdel: Added new type of planets - settled ones. Full of xenoarch-filled garbage + piles and hostile robots. + Cirra: + - bugfix: Protein is no longer present in food items which aren't supposed to contain + it, such as skrellsnax. + CrimsonShrike: + - bugfix: Stacking machine will now stack materials again. + FTangSteve: + - tweak: Updates engineering contractor to have access to atmos, EVA, etc. + Kelenius: + - tweak: Defile counts towards rune unlock again, at a rate adjusted for Torch. + - tweak: Mass defile rune won't kill you with bloodloss when you draw it more than + once (cost lowered from 80 to 20). + - bugfix: Soulstones should work properly now. + Minijar: + - rscadd: Adds pilot voidsuits to the Calypso along with a cycler. + TheGreyWolf: + - rscdel: Removes the Zhan-Khazan outfit from the loadout (Taj relevant only). + - rscadd: Added a NT pilot specific voidsuit, currently none are mapped in. + Zuhayr: + - tweak: R-UST backend/manual changes. +2017-09-13: + Chinsky: + - rscadd: Changed way lung damage affects people. Instead of straight up oxyloss, + it now makes you require higher oxygen pressure - so you can work around it + with high pressure internals. Of course it's not 100% failsafe, as blood coughing + and breathing stops still remain. + - rscadd: Inapro does more things now. It can heal brain damage up to 60, and also + slows down brain damaging a general, more effective at higher oxygenation. + - rscadd: Health analyzers report brain damage a bit different now. They don't report + damage that will self-heal without meds. New stage 'minor brain damage' covers + range that can be healed with inapro. Rest are more or less same. + - rscadd: Painstuff tweaked around, should generally see slightly less instant KOs + from lethal damages. + FTangSteve: + - tweak: Makes it so breathing heat or cold will hurt your lungs more than making + your head explode. + - rscadd: Electricity now shocks many parts of your body in a line to the ground + rather than just your hand. + - tweak: Species with an open circulatory system now don't get cut veins or arteries. +2017-09-23: + Atlantiscze: + - tweak: Pulling a knife out of your boot or putting it in produces a message once + again, but only if you are adjacent to the person. + Chinsky: + - rscadd: Can remove rolling end credits with Stop End Titles verb in OOC tab. + FTangSteve: + - rscadd: GAS now are flammable. + - rscadd: Lasers can catch flammable mobs on fire. + - rscadd: GAS no longer are cut by small sources of cuts (they are bruised). + - rscadd: GAS no longer are cut by slithering over glass. + - rscadd: Being on fire now burns immediately and isn't based on body temperature. + - rscadd: Adds an autolathe to robotics. + - rscadd: Adds lightswitches to chemistry, the galley, and robotics. + - tweak: Adjusts some lights so lightswitches make those rooms dark. + ZeroBits: + - rscadd: Activated the Solar Storm random event, which roasts anyone who's EVA + at the time. + - tweak: Added rad-shielding to the bunk room so you can stop dying while AFK, also + added rad-shielding to the saferooms. + - tweak: Tweaks lottery chances. + - tweak: Allows admins to choose whether or not to make an announcement when they + toggle gravity from the secrets panel. + atlantiscze: + - tweak: Walls and similar dense objects are now much better when protecting against + radiation, especially at higher levels. + - tweak: AI integrity restorer program will now upload map's default law set instead + of NT default. + - tweak: Cyborgs can now click ladders to climb. AIs can now click ladders to move + their view to different Z. +2017-09-28: + Banditoz: + - maptweak: Adds tintable windows to the Robotics Surgical Theater. + Broseph Stylin: + - rscadd: Added an Exploration department-specific voidsuit. It has the same stats + of an excavation voidsuit. + - rscadd: Added Exploration department-specific colored uniforms and PDAs. + - rscadd: Added lockers for the Pathfinder and Explorers. + - maptweak: An Exploration Equipment area which can only be accessed by the Exploration + department has been mapped on Deck 4 Aft. + Chinsky: + - rscadd: Pulse now affects blood circulation. Lower pulse effectively lowers it + and vice versa. + - rscadd: Extremely high pulse risks damaging the heart. Shouldn't be a lot, but + it's there. + - rscadd: As you lose blood oxygenation, your pulse tries to rise to compensate. + Thready (>250) pulse will cause a cardiac arrest. + - rscadd: Inaprovaline tries to bring pulse to normal levels, either up or down. + It also prevents thready pulse. + - rscadd: Heart stopping is slightly less 100% surefire, so if you manage to get + heart restarted it might beat for few ticks first. + - rscadd: You no longer need lungs/mouth to give CPR, but you will only do the heart + bit. Checks still apply for mouth-to-mouth. + - rscadd: Shock stage stars rising earlier now (30 damage vs 50) and can go bit + higher than usual. + - rscadd: Painkillers speed changed. Now they ramp up slower if ingested, but stay + longer. Opposite if injected. + - rscadd: Tramadol and oxcodone injectors added to medical vendomats (and tramadol + ones to hacked firstaid vendomats). + - rscadd: Adds some goodies to survival boxes - inapro injector, food and light. + - rscadd: Changed how tramadol/oxycodone work a bit. They now have period for setting + in and wearing off, gradually ramping power up/down. Those are short, ~20 seconds + to reach max + - rscadd: Mixing those with alcohol is now as bad idea as it's supposed to be - + increased liver damage and respiratory depression (harder time beathing) await + you + - rscadd: Inaprovaline helps against breathing effects of both mixing and ODing. + - rscadd: There's now some effects based on how much you consume over time, rather + than single dose. Effects stat at 15u with some slowdown and chance to start + slurring, ramp up from there, with major slowdown and slurring after OD-worthy + doses is metabolized. + - rscadd: Also ODing on those will give you even MORE painkilling effect! At a small + cost of suffocating most likely, and don't even try doing that AND booze. + - rscadd: Ships now have sensors. Overmap is dark by default, with known sectors + emitting some light. Dust/rocks/ion block visibility. You can control the sensor + with console(s) on the bridge, its power setting sets how far it will shine. + Higher settings use /huge/ mounts of power so don't leave it running on those. + Sensors also cannot run in non-vacuum. + - rscadd: Some improvements to helm console - now shows ETA to next grid, can set + max speed for autopilot. + - rscadd: Engines are now buildable - there's circuitboards for them in Tech storage. + - rscadd: Merchant prices are now slightly less wack, they use actual procs for + deciding them, instead of selling containeres full of stuff at price of container + only. + - rscadd: Mineral scanners now store survey data, currently useless aside from penile + comparsions. + - rscadd: New away mission - a drifting empty ship. Can be restored to fly around + on its own like Torch. + atlantiscze: + - tweak: Cyborgs can now unwrap packages by clicking them.. + dryerlint: + - tweak: Autolathes can now print cable coils. They are under the Devices and Components + category. + sabiram: + - bugfix: Cerulean, pyrite, bluespace and sepia slimes now drop the correct slime + core. + - rscadd: Added a jumpsuit with colour selection to the loadout, replacing the list + of presets previously available. + - rscadd: Added a new feminine jumpsuit with colour selection to the loadout. + - rscadd: Added a service uniform skirt for Expeditionary Corps, available in the + uniform vendor. + - rscadd: The clerical module robot now has access to the basic and denied rubber + stamps. Additionally, their hacked item is now the chameleon stamp. + - rscadd: The service department has been split. The Sol Pilot, Pathfinder and Explorer + are now in the Utility department, with their own department radio. The hotkey + for the utility department is 'y'. Bartender, Cook, Janitor and Crewman remain + in the service department. +2017-10-03: + Broseph Stylin: + - rscadd: Added some code by Techhead that allows for accessories to have and transfer + armor values to the item they are attached to. + - rscadd: Added a modular armor system based around a common plate carrier and accessories + that attach to it. + - maptweak: Replaced the armor vests and arm guards found inside the Emergency Armory + with equivalents using the new modular armor system. + Chinsky: + - rscadd: Shrapnel is less deadly now. Tiny items don't jostle around anymore. They + still prevent wounds they're embedded in from healing. + - rscdel: Conductive things embedded in body will heat up in EMP, dealing damage + depending on their size and EMP severity. + - rscadd: Brainwashing implants! Well, kinda. XO now has a box of 'imprinting' implants, + that can be set to a list of instructions, and will remind about those to whoever + is implanted with it. Latest word in grimdark on-job training. They're not binding, + just reminders. + - rscadd: Now the fun part is their abuse - when victim has mindbreaker in blood + and implanted with those, implant wires deep enough to fool host that he actually + believes these. Think borg laws. You can get the kit in uplink too, bundled + with a dose of mindbreaker + - rscadd: Can now emag practice carbines to get lethal lasers out of them. They'll + turn useless after 3-6 shots so bring a lot! Costs an emag charge. + - rscadd: Not having enough air in lungs will prevent you from talking efficiently. + If you don't have air at all, you might use remaining air in lungs for one message. + If you're just not getting enough, you'll be stuck whispering. Long messages + might come out garbled. + FTangSteve: + - rscadd: Added a push back disarm attack for GAS. + - rscadd: Added examine text and a message for GAS stance. + - rscadd: Adds in some of the GAS event things like the threat display and associated + sounds. + - rscadd: Cutlets can now be added to the organ printer as well as full slabs of + meat. + - rscadd: Adds a few cameras to hangar and to exploration with a network for each. + PsiOmegaDelta: + - tweak: Converts the machine, mob, and obj processes to subsystems. + SierraKomodo: + - tweak: Changed wording of maintenance drone laws from 'do not interfere' to 'do + not interact' to better fit the spirit of the law and staff policy. +2017-10-10: + Atlantiscze: + - rscadd: Completely overhauls crew records. Large text fields now support paper + tag formatting. Records are now accessed through a computer program. Everyone + can see generic fields (name, job, rank, ..), specialized fields become visible + depending on your access. + - rscdel: Removed old record computers of all kinds, removed PDA modules for crew + record viewing. + Banditoz: + - maptweak: Mapped in a camera to Bridge's solar control. + Broseph Stylin: + - tweak: All armor-containing lockers now have a 50% chance to contain a modular + armor equivalent to the older armor vests. + - tweak: All armor crates from Supply have been altered to contain modular armor + rather than the older vests. + - rscadd: Plate carriers and storage pouches for them have been added to the loadout, + priced at 1 and 2 points respectively. Only roles already issued armor can obtain + them. + Chinsky: + - rscadd: Added doorbell pager button. Press one and it will ping all PDAs of relevant + department people! There's one in Medical Cargo lobbies each. + - rscadd: EC ranks have been changed, you'll probably need to update your char settings. + Only 3 enlisted ranks now, slightly less officer ones. + - rscadd: 'SUPER IMPORTANT: EC cannot longer be SEA. Also since they don''t have + O2 equivalent, Pathfinder can be either O1 or O3.' + - rscadd: Can now rename alien creatures! All exoplanet animals start as 'alien + creature', and you can use a Name Alien Species verb to rename them when you + see 'em. Name can't be changed afterwards so don't go too silly. Random generated + one is suggested when you use that verb too. + - rscadd: All computers now come with a word processor, NanoWord. Lets you edit + TXT files, with paper preview and markup help + CrimsonShrike: + - rscadd: Ports openspaces. Now open turfs will show whatever is down below. + Crushtoe: + - rscadd: Added the antibody analyser, a new way for virology to contribute to the + crew. Finding new antibodies from curing diseases grants 45 cargo points per + when scanned, allowing up to 1170 points on the furthest end assuming RNGesus + is very merciful. + - maptweak: Mapped in an antibody analyser into the virology lab. + - rscdel: Removes the Chemist as its own job. + - rscadd: Chemist is now an alt-title of Medical Contractor. + Devildabeast: + - rscadd: Gives the SEA Emergency Armory access. + - rscadd: Master Chief Petty Officers and Master Gunnery Sergeants can now be SEA. + FTangSteve: + - tweak: AI drones can no longer use non-drone langauge. + - tweak: Drones can no longer push or pull items larger than medium. + - bugfix: Mechs can now fall and go down stairs. + - rscadd: If a mech falls on you, it does a heck of a lot of damage. + - tweak: Makes hats optional. + - bugfix: Fixes space vine events. + - rscadd: Makes vines spread across z levels. + - tweak: Balances spreading vines. + Quardbreak: + - rscadd: Now you can look up and see out what's going on there. + dryerlint: + - rscadd: Added two Marshalling Wands to the Deck Technician's locker. They light + up and help you visually signal stuff. + mkalash: + - rscadd: Added a net gun. It and a bandolier full of net shells is located in the + Charon storage area. + - rscadd: Added stasis cages for transport of alien fauna without having them suffocate, + located in expedition storage. + - maptweak: Refitted xenobiology to support changing the atmosphere of animal pens. + sabiram: + - rscadd: Keys can now be held in wallets. + - maptweak: The derilect laboratory in the research wing has been refitted into + a break room with public office space. + - bugfix: Personal AI system radios now work once again. + - maptweak: The executive officer's office has been redesigned. + - rscadd: Head of staff offices have been fitted with modular computer consoles. + - rscdel: As the records have been integrated into modular computers, the laptop + on the bridge previously adjacent to the security and medical records consoles + has been removed. + - rscadd: Heads of staff, the Senior Enlisted Advisor and the Bridge Officers have + been leased modular tablets. The BO's are available in their lockers. + - rscadd: The commanding officer and executive officer now have special pens. +2017-10-14: + Broseph Stylin: + - rscadd: Added Marine Corps service uniform skirts. + - rscadd: Added desert boots. Available in the same places as and statistically + equal to jungle boots. + - rscadd: Added Fleet fatigues as an alternate utility uniform. + - tweak: Fleet security and Field Medics now spawn with fatigues instead of coveralls. + - rscadd: Added earrings to the loadout, found in the Earwear section. They're unrestricted, + but can only be worn by humans (subspecies included) + - rscadd: Added a Master at Arms brassard to the loadout. + - tweak: Changed the Military Police armband to a brassard. + Chinsky: + - rscadd: Electrical storms now can be blocked by shields. They have special mode + for it. Keep in mind that they will be taking damage while event is running. + - rscadd: Overmap events (meteor, dust, electrical storm) do not happen randomly + now. + - rscadd: Number of overmap events increased. Asteroid fields now spread over wider + space but have gaps in them. + - rscadd: Hitting edge of overmap will not warp you around to the opposing edge. + Space is around after all. + - rscadd: Away missions no longer glow on overmap, you have to find them now. Planets + are still visible due to sheer size of signature. + - rscadd: Changes to Torch's speed. Now default delay between moving is higher - + 20 seconds vs 12, but speed affects it much more, e.g. at 5 speed you will move + pretty much continuously. + - rscadd: Shuttles have different ranges now. Charon (1) can go to away missions + in adjacent grids, Aquila (2) one tile further. Travel time is multiplied by + the distance. + Cirra: + - rscadd: 'Added a new, more expensive type of 14.5mm ammo, for the anti-material + rifle: APDS. Less damage, but far greater armour penetration.' + - rscadd: Projectiles can now cause internal damage, including organ damage and + severing arteries. Bullets cause more than energy, with x-ray lasers being inbetween + the two. + - tweak: Renamed 5.56mm ammo to 7.62mm and vice versa, to be more consistent with + their damage values. + - tweak: Matebas now use .50 ammo, while revolvers have had their damage reduced + slightly. + - tweak: .45 rounds now do 21.5 damage instead of 20, while 10mm bullets now do + 23.5 instead of 25. + Orelbon: + - rscadd: Consoles now have ambient noise when turned on. + comma: + - tweak: Department of Swag has determined that Torch is 60% clothes by volume. + This was rectified. Now uniform vendors will only dispense 1 (one) item of each + type per person. Don't lose your pants kids. + sabiram: + - rscadd: The Pathfinder now has a special machete with premium fittings, and machete + sheaths have been added to the Pathfinder and Explorer's lockers. + - rscadd: Job bans can now be applied to jobs from the command support, exploration, + service, and supply departments. +2017-10-21: + Broseph Stylin: + - tweak: Holsters and webbing/bandoliers/drop pouches can now be worn together. + - rscadd: Added customization options for modular armor to the loadout. + - rscadd: Added leg guards as an armor module. + - tweak: replaced all static armor spawns with their modular equivalents. + Chinsky: + - rscadd: Planets now have some alien landmarks to find and rub your face on. + - rscadd: Added winter coats for all branches. Can be found in uniform vendors next + to ushankas. + - tweak: Made vent hum bit less of earbleed, made ambience bit lower and rare in + general, try reenabling it. + Datraen: + - rscadd: Allows for labels to be applied to condiment containers. + ParadoxSpace: + - rscadd: Adds eyepatch variants of the Sec, Med, and Meson HUDs, as well as a non-HUD + variant for those missing exactly one eye. + - tweak: Flipping eyepatches (and HUDpatches) is now a verb. + - rscdel: Kills the standard cloth eyepatch for military roles. HUDpatch still works + for them. + TheGreyWolf: + - rscadd: Added toeless jackboots to the EC and civie branch uniform vendor for + the xenos. + TheWelp: + - rscadd: Added a deity hud element that shows your current phenomenas. + - tweak: Reduced D-Nar's blood costs to half. + - tweak: Made it so that a deity's power can never go below 0. + ZeroBits: + - rscadd: 'Added three new strength brackets for the R-UST: 9x9, 11x11, and 13x13. + For the engineers who have 51 extra fuel injectors and way too much free time.' + - tweak: Changed the sprite of the R-UST to look cooler. + dryerlint: + - rscadd: Added queuing functionality to modular computer software downloader. + sabiram: + - rscadd: Added herbal liquor. + - rscadd: Added a new cocktail, the Ibn Batutta, consisting of 2 parts herbal liquor + and 1 part orange juice, with mint as the catalyst. + - rscadd: Added a new cocktail, the Magellan, consisting of 1 part wine and 1 part + premium whiskey, with sugar as the catalyst. + - rscadd: Added a new cocktail, the Armstrong, consisting of 2 parts beer, 1 part + vodka, and 1 part lime juice. + - rscadd: Added a new cocktail, the Zheng He, consisting of 2 parts black tea and + 1 part vermouth. +2017-11-01: + Chinsky: + - tweak: Changed way hallucinations are. Now some things will give you strong ones, + some milder, it's not always same. + - tweak: Most of old hallucinations effects are replaced. New ones are supposed + to be more mindfucky. + - tweak: Synaptizine, Paroxetone and Citalopram help lowering frequency of hallucinations, + and to clear them out faster once whatever causes them is dealt with. + - tweak: Changed lobby music selection, lowered lobby music sound overall. Should + be less ear-gore and fresher now. + Cirra: + - bugfix: Stasis Clamps actually work now. + CountAlex: + - rscadd: Adding new map for overmap list - abandoned supply base. + - rscadd: Adding new map for overmap list - planetside location - frozen with breathable + atmosphere - with pod crashlanding and survior's story. + CrimsonShrike: + - bugfix: Fixed stick messages not showing. + - rscadd: Sticks can now be sharpened using edged sharp tools. + - rscadd: Added morgue access to Forensic Technicians. + - rscadd: Added GAS-poking stick and recipe per request of the more suicidal crew + members. + Devildabeast: + - tweak: Deck Officers can now be E-8 and O-2. + FTangSteve: + - tweak: Robotic organ surgery now needs the hatch screwed back down after it's + closed with a crowbar. + - rscadd: Adds the ability for IPCs to choose whether they are shackled and a lawset + in character setup if they would like. + Heptagon49: + - rscadd: A hologram's color will now vary depending on what kind of holopad is + projecting it. + - imageadd: Added a unique sprite for long-range holopads. + - spellcheck: You now step onto a holopad instead of stepping unto one. + - rscadd: You can now tell if a person's face is disfigured just by looking at them. + TheGreyWolf: + - tweak: Restricts a few more tattoos and prevents xenos from picking normal tattoos. + - rscadd: Added black, blue and red pens, hand labeler, clipboards and destination + taggers to the autolathe. + ZeroBits: + - tweak: moved away sites to away subfolders. + - tweak: You can now disassemble bare plating by first damaging it with a welder + (or bomb) then prying it up with a crowbar. + sabiram: + - rscadd: Added two new alert levels to the Torch map. + - rscadd: Code Violet for major medical emergencies. + - rscadd: Code Orange for major engineering emergencies. + - rscadd: Code Red now has a unique sound on activation. + - tweak: Code Blue alert should now only be used for major security emergencies + and not as a general readiness state. + - tweak: Code Red alert should now be used as a general high alert when the situation + is more severe than or would warrant two of the standard department alert statuses. + - bugfix: Chemical grenades (cleaner, metal foam, etc) now work properly again. + - tweak: Security module robots' stun batons now consume much less of their cell + per hit. + - rscadd: Anyone with bridge access can now lock the holodeck into its current state + in the console interface. + - rscadd: The Pathfinder now has a box of Exploration department encryption keys + to distribute if they choose. + - tweak: As part of the SolGov staff well-being initiative, cigarette supply to + their installations have been restricted. Vendor prices have increased to match + the limited supply. + - rscadd: Added more e-cigarette flavour cartridge types to vendors, including ones + to fill with your own flavours, and added empty e-cigarette cartridges to autolathes. + - maptweak: Wall lockers with cardboard, wrapping paper and destination taggers + have been added to the kitchen, hydroponics and the research and development + lab. + sicktrigger: + - rscadd: Ship sensors will now heat up and eventually take damage at higher settings + (they can be repaired with a welder). Their power usage has also been significantly + reduced. + tlc2013: + - rscadd: Added the Corporate and Service lawsets to IPC shackles. + - rscadd: IPCs now have four new monitors. Nothing special... except for a space + screensaver. +2017-11-04: + CountAlex: + - rscadd: Adding new map for overmap list - smugglers den located inside asteroid. + Tlc2013: + - rscadd: IPCs now have two bonus language slots. + sabiram: + - rscadd: As follow-up to a recent study concerning the trend of people more readily + following leaders with shiny revolvers, the Commanding Officer and the Executive + Officer have each been supplied a Webley style .44 revolver as their personal + side arm. + - rscadd: Added the .44 revolver to the traitor uplink. + - rscadd: Added .44 ammunition to the autolathe. Rubber is always available, and + lethal is available after hacking. + - rscadd: You can now alt-click revolvers to spin the cylinder. +2017-11-10: + Chinsky: + - rscadd: Can now put clothes on skeletor models. + - rscadd: Can rename skeletor models with pen. + Heptagon49: + - tweak: Lowered the chances of a Doona popping out of a vending machine from 1% + to 0.1%. + - bugfix: Made the outer windoor of the sci checkpoint all-access. + - tweak: Added an outer windoor to the RnD desk. + - rscadd: Chem dispenser now has a visual indicator when it has a beaker loaded. + - bugfix: Pill bottles loaded into the chemmaster now get filled. + - tweak: Tweaked uniform vendor so that it'll no longer eat your clothes. + Hubblenaut: + - bugfix: Fixes brig cell timers not connecting to windoors/mounted flashes. + Orelbon: + - maptweak: Science entrance has been edited & science has been made more open. + - maptweak: Medical has been remapped to be more efficient and increase workflow. + Rebruiza: + - rscadd: Individuals with the "Floorlength Braid" hairstyle now occasionally trip + on their hair. + Tlc2013: + - rscadd: Added the legendary CRT Test screen to IPC monitors. + mkalash: + - rscadd: All gloves that are available in the load out now have pre-modified versions + in the xeno load out. + - rscdel: Removed parapen, parasting, and the stun talisman. + sabiram: + - tweak: Maintenance drones now have spray bottles instead of soap. The cleaner + refills in chargers. + - rscadd: Hyposprays have been upgraded and now use removable vials instead of a + internal storage. + - tweak: Voice changers available in the upload now have chameleon mask functionality. + - rscadd: Holsters have been added to the gun cabinets. + - rscdel: Holsters have been removed from the bridge officer and Sol pilot's lockers. + - tweak: Gun cabinets now have a chance to spawn a small e-gun instead of the full + sized variant. +2017-11-11: + chaoko99: + - bugfix: Puts some jackboots in all the security lockers. Your feet will no longer + be cold. + mkalash: + - tweak: Welding tool sizes have been rebalanced. Namely, the industrial welding + tool is now too large for a tool belt. + - rscadd: To balance this out, engineers can now easily carry spare welding fuel + cartridges found in the welding locker and hot swap them out, actually increasing + the welding capacity of the typical engineer. + - bugfix: Experimental fuel tanks now automatically refill, as intended. + - rscadd: The experimental welding tool can now be produced in rnd. +2017-11-19: + Casper3667: + - tweak: Passengers (the job) can now use corporate uniforms. + - rscadd: NT corp uniform is now available in the loadout. + Chinsky: + - tweak: Ordering gun crates now requiers elevated alert level, Blue for small ones, + Red for big guns. + CrimsonShrike: + - rscadd: Now catwalks can be built above plating. + - tweak: Reinforced floor now requires 1 steel sheet instead of 2 rods. + - rscadd: Added catwalks. Can be built by using rods on existing lattice. + - bugfix: Fixed lattice icons on openspace turfs. + Hubblenaut: + - rscadd: The telecomms broadcaster, relays, station bounced radios and intercomms + now broadcast to all connected z levels. + - rscadd: Adds a relay circuit board to the telecomms storage. + - rscdel: Removes relay rooms and replaces them with maintenance. + Orelbon: + - rscadd: Ghosts can now click on non-modular consoles and see their UI. + Rebruiza: + - tweak: Cable coils no longer do damage when thrown. + - tweak: Cable coils are now "ITEM_SIZE_NORMAL", instead of "ITEM_SIZE_SMALL". This + means that they no longer fit in pockets, but rather has to be in a larger container + or off the side of a toolbelt, as intended. + SamSamsonthe3rd: + - bugfix: Can now build ED209 with plate armor. + Serveris: + - rscadd: Added the WT45 pistol. + - tweak: Line Officers now spawn with said in their lockers, rather than energy + guns. + Zero-Bits: + - tweak: '"Library Improvements. Removed Adult Category, made USBN usable."' + atlantiscze: + - rscdel: Cyborgs can no longer be self-destructed through the remote console. + - rscadd: Cyborg's precise position is now displayed on the console instead. + - rscadd: The console now offers you an option to send direct message to a cyborg. + This message is independent on telecommunications and range. + chinsky: + - tweak: Humanoids able to vent-crawl can now bring select articles of clothing + and carry items which are not too big. + comma: + - tweak: Propellant in fuel bay changed, instead of plasma it's CO2 now. Thrust + should be more or less same, but less eternal fires and more space for engies + to increase said thrust. + dryerlint: + - rscadd: Added fuel port object. When mapped into shuttles (like Charon or GUP) + it gives them a finite fuel reserve, which must be refilled with phoron. + mkalash: + - tweak: You can now place crowbars in security belts. + sabiram: + - rscadd: Added the pry bar, a smaller crowbar, to the autolathe. + - tweak: The damage values of tools have been adjusted. + sabirm: + - rscadd: Added a supply crate containing ammunition for the executive heads' revolvers. + - tweak: The rubber ammo crate now contains two rubber .45, two flash .45, and two + rubber .44 magnum magazines on the Torch map. + - tweak: As part of the Great Gun Experiment, all ammunition is now hidden in the + autolathe. + sick trigger: + - rscadd: Ghosts can now Check-Radiation. + sick-trigger: + - rscadd: Ghosts will now be informed of the contests of examined closets/lockers. +2017-11-20: + sabiram: + - rscadd: Added a disguised syringe gun to the loadout. Comes complete with four + cartridges and four syringes. Chemicals not included. +2017-11-22: + Cirra: + - tweak: Radiation is now relevant again, due to material radiation resistance being + lowered. + SierraKomodo: + - rscdel: Removed xenophage and cortical borer from the list of add antagonist vote + options until these antag types can be fixes. + atlantiscze: + - tweak: Communication outages are overall less common. + - tweak: Communication outage has only 75% chance to affect each particular machine, + therefore with some luck, enough machines may remain functional to get at least + some working frequencies. The hub, broadcaster and receiver have 10% chance + to be affected, as they are critical for the whole telecommunications system. + - tweak: Increased chance of ion anomaly being announced. There is still a small + probability of the anomaly occuring silently. + - rscadd: It is now possible to reset EMP/ion/random event affected telecommunications + machinery with a multitool through the UI. The UI also shows a timer until automated + reset. + dryerlint: + - rscadd: Added fuel ports to Charon and GUP. They will consume fuel and eventually + run out + - rscadd: Added small refueling room to Hangar, for anyone with Supply Warehouse + access +2017-11-23: + Casper3667: + - tweak: Fixes up balaclava and half-gas mask sprites for taj. + - rscadd: Adds new shoes for taj called caligae. + CountAlex: + - rscadd: 'Away mission map: Damaged and abandoned Planetary Shield Orbital Station' + Dukica: + - rscadd: Added the braided beard facial hair style. + Orelbon: + - bugfix: Ghosts cant griff with jetpacks anymore. +2017-11-24: + CrimsonShrike: + - rscadd: Added Hydrogen canisters to supply request list. + Dukica: + - rscadd: Added new hairstyles. + FTangSteve: + - tweak: Add SCG Police tag to CoS carrier + - tweak: upgrade CoS armour plate + Kelenius: + - tweak: Camera networks have been sorted in an other that makes more sense. + mkalash: + - tweak: The welding pack is now too large for backpacks. + - rscadd: You can now attach welding tools to welding packs via drag drop. + - rscadd: Welders now show an overlay of what fuel tank is attached, if any. + - tweak: Fuel cartridges are now welding fuel tanks. + orelbon: + - rscadd: New sprites for the 2x1 white airlock. +2017-11-25: + Kelenius: + - tweak: Teleporters don't need to be test-fired anymore. + sabiram: + - tweak: The XO now has unrestricted access to the Aquila. +2017-11-26: + CrimsonShrike: + - bugfix: '"Fixes openspaces above shuttles retaining image of the floor."' + chinsky: + - tweak: Melee attacks will now always hit targets with the Help intent selected. + comma: + - rscadd: Added EC directives plaques on Bridge/Charon/Exped Prep/walls near flags + in cryo etc. Their tl;dr is go explore instead of twiddling thumbs. + sabiram: + - rscadd: Added purple, orange, green and red carpets. + - rscadd: Added blue, blue and silver, purple, orange, green and red carpet tiles + to the supply computer. + - tweak: Changed the brown and blue carpet icons to match the new ones. +2017-11-28: + Casper3667: + - rscadd: Adds new taj security voidsuit sprites from Serveris. + FTangSteve: + - rscadd: makes item slowdown impacted by species strength + - tweak: changeling transform now takes time with a progress bar based on mob_size + difference + sabiram: + - rscadd: Vials can now be placed in bandoliers. +2017-11-29: + Chinsky: + - tweak: Meteor mode now progresses a bit faster on difficulty scale, and can produce + bigger waves in the end. + CountAlex: + - rscadd: Adding new map for overmap list - raided casino ship. + Orelbon: + - rscadd: Self Destruct Sequence Has been revamped. + - rscadd: Keycard device can now be used to get the nuke code. + - tweak: Keycard device now waits 3 seconds for someone else to swipe. + - rscadd: The vault has been replaced by the self destruct room on deck 1. + - tweak: The engineering supply room was moved into the side of the hallway on deck + 1. + - tweak: The vacant office was moved to behind the self destruct room. + Spookerton: + - bugfix: Fixes cyborgs being unable to repair doors. + Techhead0: + - tweak: Removes age gate from Janitor + - tweak: Changes crewman alt-tiles to "Trainee" instead of "Junior" + Zero-Bits: + - tweak: Ports the Library to the Modular Computer System + sabiram: + - rscadd: You can now drink from buckets and beakers by clicking with the HELP intent. + Clicking with HARM intent splashes/spills. + - rscadd: 'Added new scrub and surgical cap colours to random spawns and loadout: + white, lilac, teal, and heliodor.' + - rscadd: Added colour selection to scrubs and surgical caps in the loadout. + sick trigger: + - rscadd: Finalizing a matchmaking connection now informs the other player. +2017-12-01: + Casper3667: + - rscadd: Deck officer, pathfinder and explorers now got binoculars in their lockers. + CountAlex: + - tweak: Changed Biogenerator UI to nano-ui instead of basic HTML. + Dukica: + - rscadd: Added 3 new masculine hairstyles (Slick, Average Joe, Messy) + sabiram: + - maptweak: Added an AI holopad to security processing. + - maptweak: The XO once again has access to an AI holopad in their office. + - rscadd: Suit jackets, suit pants, baggy suit pants, and athletic shorts are now + colour-selectable in the loadout. + - maptweak: 'Added some cameras to the infirmary: one in the operating theatre, + and two in the main treatment centre.' +2017-12-02: + FTangSteve: + - tweak: new sprites for nabbers + - rscadd: can shift equip overlays on per species per slot per direction basis + sabiram: + - rscadd: Added a black pocketbook to the backpack selection. + - rscadd: Added a few dresses. The short dress is available in the loadout with + colour selection. Dresses in two styles and four colours are now available in + the uniform vendor for formal occasions for civilians. +2017-12-03: + BlueNexus: + - rscadd: Added a new creature, which can be found on certain away missions +2017-12-04: + Orelbon: + - tweak: Remapped the Lounge + Zero-Bits: + - bugfix: '"Fixed library program UI and bookbinder linking."' + sabiram: + - tweak: Sunglasses now apply a screen overlay when worn. + - tweak: A makeshift duct tape blindfold can now protect your eyes from welders, + if you don't mind welding blind. + - balance: All HUDs and other glasses types with electrical components are now vulnerable + to EMP, and will disorient you and turn the HUD off when hit. Neither of the + effects are permanent, and you can turn your kit back on right away. + - balance: Any glasses type with night vision no longer has flash/welder protection, + or is otherwise vulnerable to flashes or welders. + sabiram & chinsky: + - rscadd: The tobacco plant can now be grown, with a couple mutates. + - bugfix: Electronic cigarettes should no longer be more harmful than regular cigarettes. +2017-12-06: + PsiOmegaDelta: + - tweak: Character Setup - Some backpacks now have additional setup options. + sabiram: + - rscadd: Added a black pocketbook to the backpack selection. +2017-12-07: + BlueNexus: + - tweak: Slightly buffed "Mehren" + Casper3667: + - tweak: Taj can no longer use zeng-hu or veymed prosthetics or body. + CountAlex: + - rscadd: Added Oxygen regenerator device for Atmospherics. Device takes from an + input pipe CO2 and slowly feeds O2 to an output pipe and drops chunks of coal + on the top tray of the machine. + FTangSteve: + - rscadd: Add new emotes for nabbers. + atlantiscze: + - tweak: AI can now hack multiple APCs at once, assuming it has enough CPU power + to begin the hack. AI can use abilities while hacking an APC (the hacking task + has been completely isolated) + - tweak: AI can now use its abilities during system override. On torch the override + takes quite a long time due to larger amount of APCs, and during this period + the AI is otherwise very vulnerable. + - tweak: Failed advanced encryption hack now offers you to retry the hack without + having to copy-paste/write the message again. This should make the ability a + bit more comfortable to use. + dryerlint: + - rscadd: Added nuclear football (secure briefcase with disk, pinpointer, instructions, + and laptop) + - maptweak: Removed nuke disk and pinpointer from CO's office, replaced with nuclear + briefcase. Added pinpointer to Bridge Storage. + sabiram: + - balance: Flashes have been reworked when attacking humanoid targets. + - balance: Instead of stunning for 20 seconds, they will stun for up to 7 seconds, + and blur vision and confuse for up to 18 seconds. + - balance: Flash stun duration for silicons has been reduced from 10-20 seconds + to 8-12 seconds. + - tweak: The area-of-effect attack for flashes now blurs the eyes of those affected, + in addition to flashing them. + - rscadd: Flashes can now have varying effects by type. + - tweak: The flash used in robot construction is now weaker than the base flash, + but breaks just as often, instead of every time its used. + - tweak: The spray projectile fired from peppersprays now moves much faster and + their capacity has been increased from 4 shots to 6. + - tweak: Pepper spray now incapacitates for an additional 2 seconds. +2017-12-08: + Banditoz: + - tweak: Overmap is now a lot more hostile. + dryerlint: + - rscadd: Added the SolGov flag, a variant of the existing flags, but with SolGov + logo on it. It is found in Exploration Storage. +2017-12-09: + Casper3667: + - tweak: The taj species blurb in char setup has been updated. + sabiram: + - rscadd: A more gentle carp event has been added to the overmap to supplement the + more dangerous version. The event icons with three carp are the more dangerous + schools. + - rscadd: Space carp can now be encountered on the overmap. + - rscadd: Ion clouds have condensed in the vicinity of the ship and can be collided + with on the overmap. +2017-12-10: + sabiram: + - rscadd: Added a few different colours to the satchel and pocketbook selection + in character setup. +2017-12-11: + Orelbon: + - maptweak: Xenobotany Has been remapped for space and usability. + - maptweak: Xenoarchiology lab has been moved to the Petrov. + - maptweak: Misc Lab is now a circuit lab and a small chemical testing chamber. + - maptweak: A chemistry station & toxins have been added to the Petrov. + Techhead0: + - rscdel: Science wing and channel has been reverted back to purple. + dryerlint: + - tweak: Flags can now be placed on any terrain/turf, except for space +2017-12-12: + BlueNexus: + - tweak: Nerfed the .50 pistol fire rate and recoil. + Hubblenaut: + - rscadd: Atmospheric pumps can be toggled by alt clicking. + - rscadd: Carafes and implanters are now available in the autolathe. + - bugfix: Implants are now trackable across connected z-levels. + Kelenius: + - tweak: Merchant now has two slots. + mkalash: + - tweak: Spacemen no longer pin their IDs to their skin when they roll down their + jumpsuits. + sabiram: + - tweak: Mounted flash effect changed from 20 seconds of knock down to 6 seconds + of knock down followed by a further 10 seconds of stun - a total of 16 seconds + of useful disable - followed by a further 8 seconds of confusion. + - tweak: Flash and flare cartridges now inflict more agony damage. + - rscadd: Flash and flare cartridges now blur the vision and disorient those within + their flash ranges - tiles adjacent to the explosion for flashes, and two tiles + adjacent for flares. +2017-12-13: + Techhead0: + - tweak: Vey-Med prosthetics are now restricted to humans only. Zheng-Hu is now + restricted to humans and IPCs. +2017-12-14: + Casper3667: + - rscadd: Vox gas masks are now available for vox in the loadout. + sabiram: + - rscadd: Control+Alt clicking a PDA will now toggle the flashlight. + - rscadd: Control+Alt clicking closets and lockers is now a shortcut to the toggle + open verb. + - tweak: AI door electrification shortcut moved from Alt-click to Control-Alt-click + to remove conflict with Alt-click inspecting the turf. +2017-12-15: + IsdatAfamas: + - rscadd: '"Added a small ship as an overmap location."' +2017-12-16: + sabiram: + - rscadd: Added new varieties of smokable to the smoking vendor. +2017-12-17: + BlueNexus: + - tweak: The WT45 now fires slightly slower, and is more accurate. + - tweak: The Mk58 now fires slightly faster, and is less accurate. + - tweak: Revolvers fire slightly slower, in general. + - tweak: Adjusted fluff for several firearms + - rscadd: The CO's revolver has been replaced with an autorevolver. + ParadoxSpace: + - bugfix: Diona now properly regenerate organs and limbs. +2017-12-19: + Casper3667: + - rscadd: Surgeon borgs now have defibrillator. + - rscadd: Crisis borgs now have medical tape. + - rscadd: Engie borgs got atmos atmos tape. + - rscadd: Security borgs now have a megaphone module. + TheWelp: + - rscadd: Reworks early game deity. No longer have to dole out spells and you regenerate + power 100% faster. +2017-12-27: + BlueNexus: + - spellcheck: Renamed the 9mm machine pistol to the 9mm submachine gun + - bugfix: Fixed the WT45's empty icon not showing + Broseph Stylin: + - rscadd: Added colored helmet covers matching the plate carriers. Available in + the loadout. + Casper3667: + - rscadd: Taj are now forced to have Siik'maas. + Chinsky: + - rscadd: Added some sekrit documents to CO/SCGR offices in sealed envelopes. Don't + really affect anything, just fluff. Moved RD's secret memo to an envelop in + his office too, put a copy on Liason's desk. + CountAlex: + - tweak: Turns casino liner into actual overmap ship with a small shuttle. + - rscadd: Adding new map for overmap list - hidden deep inside asteroid slavers + base. + Kelenius: + - rscadd: Hydroponics now has bees and space for bees. And some chemical machinery. + Orelbon: + - tweak: Laser carbine has 10 more damage and +2 accuracy. + - tweak: Taser carbine now has 12 shots, +1 accuracy and looses its 10 armor penetration. + - tweak: Stun rifle now has 10 shots, +1 accuracy,+10 armor penetration,+5 burn + damage and looses 10 agony. + - tweak: Stun revolver now has 6 shots and 50 agony. + - tweak: Ion weapons shouldn't be horrible anymore, they now activate their emp + no matter what they hit. + - tweak: The rifle now has a max range of 2, and the pistol a max range of 1. + - tweak: Ion pistol max shots lowered to 6. + ParadoxSpace: + - rscadd: Added a regeneration mechanic to Unathi. This works on nutrition. + - rscadd: Unathi now get hungrier faster, and enough hunger starts to give you toxin + damage. + sabiram: + - bugfix: Mounted flashers will no longer permanently scramble ghosts' movement. + - rscadd: Added missing eye blurring effect to mounted flashers. + - tweak: Maintenance and construction drones now move faster. + - bugfix: Lockers can once again be welded shut. + - rscadd: Clicking a drinking glass with a spoon will now call the room to attention. + Just be careful. + tlc2013: + - rscadd: Ported over three IPC screens from Polaris. I think we're done there. +2018-01-03: + ParadoxSpace: + - experiment: Removes the AI from the job list for two weeks. + TheWelp: + - rscadd: Adds band-aid fix to deity spam via cooldowns. Will add graphical indicator + to show what the cooldown is later. + - rscadd: Modifies phenomena near structure logic to include all deity structures, + not just altars. +2018-01-04: + CountAlex: + - rscadd: Adds away mission map - Mobius Rift. +2018-01-05: + CountAlex: + - rscadd: '"Adds engineering program for monitoring shield generators."' + PsiOmegaDelta: + - tweak: Can now adjust (almost) all prefix keys. These are used for language selection, + emoting, etc. See Character Setup > Global > Prefix Keys +2018-01-06: + Casper3667: + - tweak: The CSA now has the crime scene kit in their locker. + - bugfix: Forensic is yet again capable of using the dna search function in records + and can also edit pictures in records. + Devildabeast: + - rscadd: Adds one Crime Scene Analyst slot to Security. They are a forensic contractor + job that are NOT responsible for law enforcement. +2018-01-07: + comma: + - tweak: Adds gauze roll to emergency survival boxes + sabiram: + - tweak: As a cost-cutting measure, all Sol uniforms are now cut from the same cloth. + Armour values have been genericised. + - rscdel: Sol uniform hats no longer provide any armour. + - maptweak: The hydroponics base away site has been updated. + - experiment: As part of AI removal testing, an additional robot slot has been added. + - rscadd: Command hardsuit control modules have been added to the EVA storage on + the bridge deck. + - tweak: Changed CE hardsuit values to sync somewhat with new these modules. + - rscadd: Added a ring bell to the holodeck boxing ring. +2018-01-08: + Casper3667: + - rscadd: Taj now have several new capes! + - rscadd: Cameras can now be found in the loadout. + Chinsky: + - rscadd: Shuttles now need proper docking codes set in their console, or the docking + won't initiate. + - rscadd: Codes can be found in CO's orders, or by using multitool on docking controllers. + You can also hit the button on docking controller from inside to initiate docking. + - rscadd: There is also a program that shows status of all docking ports and their + codes, can be used to remotely let people dock if they're waiting outside. + Techhead: + - rscadd: You now receive pain-flashes for all pain sources. + - bugfix: Possibly fixes an infinite paincrit bug. +2018-01-09: + Devildabeast: + - rscdel: Removes SolGov Pilot. + - tweak: Gives Bridge Officers access to pilot the Aquila and Guppy and accompanying + access. + - tweak: Bridge Officers now have the Pilot's headset. + - rscdel: Removes SolGov Pilot's locker from the Pilot's Lounge. + - rscadd: The Pilot's Qualification Pin is now an item in the loadout for Bridge + Officers who want to flash their fancy training. + Zero-Bits: + - tweak: Cult walls are just normal creepy now instead of super edgy. +2018-01-10: + CountAlex: + - rscadd: Adds away mission map - SEV Icarus irradiated crashsite. + Heptagon49: + - bugfix: Adds a hydrogen tank sprite, among others, for the transfer valve. + Kelenius: + - rscadd: Syringes can now inject people in body bags and cryo bags. + LorenLuke: + - rscadd: Added/changed alt-titles for engineering contractor. + ZeroBits: + - imageadd: '"Hydrogen now has its own canister and tank sprites"' + - spellcheck: '"TX on monitoring computers is now PH, as it should be"' + - tweak: '"Omni Filter and Omni Mixer throughput increased to match pressure regulator"' + - tweak: '"Flamethrower now uses Hydrogen"' + - tweak: '"Phoron canister made slightly more expensive via supply"' + - tweak: '"Hydrogen canister made slightly more expensive via supply"' + - tweak: '"Filters and Mixers can now handle Hydrogen"' + - tweak: '"Supermatter monitoring program and gas sensors can now detect Hydrogen"' + - tweak: '"Overmap shuttles now use Hydrogen by default"' + - rscadd: '"Added purchasable crates of portable Phoron and Hydrogen tanks. Cheaper + than a full canister, but with far less volume."' + - maptweak: '"The SM reactor is now set up for CO2 by default"' + - maptweak: '"The SM reactor now has a Phoron gatherer so you no longer shoot that + valuable Phoron out into space."' + - maptweak: '"Nitrogen is no longer available directly in the SM room (it never + meets energy or safety needs anyway)"' + - maptweak: '"The fuel Bay is now filled with Hydrogen (rocket fuel) instead of + Phoron (the supposed most valuable substance in the universe)"' + - maptweak: '"Most of the Phoron tanks and canisters on the map have been replaced + with Hydrogen. R&D and Engineering each retain one canister."' + - maptweak: '"The Phoron resevoir in atmos has been replaced with a hydrogen resevoir."' + - maptweak: '"The incinerator now uses Hydrogen instead of Phoron. You''re just + burning stuff, you don''t need to do it with gaseous money."' + - maptweak: The Supermatter core is no longer filled with N2 by default. + comma: + - balance: Attacks against legs and heads are now more likely to miss. + tlc2013: + - rscadd: Added sandals to the loadout selection. Because those weren't there before, + apparently. +2018-01-11: + chaoko99: + - bugfix: Synths can no longer fill mechfabs with their matter synths. + rainbowEscapist: + - rscadd: Adds the alt title 'Trainer' to the Passenger loadout. +2018-01-12: + Chinsky: + - tweak: Cryobags, cryo and general stasis changes. Main point is that stasis is + no longer binary on/off, it doesn't stop life ticking, just slows it down (usually + a lot). It chemical processing is slowed down too, so sometimes bigger stasis + is not better. + - tweak: Cryo. Being very cold now provides stasis on its own - and cryo is easiest + way of doing it. At 80K, it applies 20x stasis factor (life ticks once in 40 + seconds instead once in 2). + - tweak: Cryo chemless healing was slowed down a bit. It also no longer magically + multiplies chems in beakers by 10x. Cryox/clonex adjusted to work at same efficiency + with this change. + - tweak: Cold damage in cryo is now prevented by clonex or cryox, not cryopod itself. + On one hand you now NEED to have it in beaker if you care about patient, on + another - you don't need cryopod if you have those and sufficiently cold place. + - tweak: Cryobags. Cryobags no longer last forever. Their power drops every 5 minutes + - examine to see current. It starts at 20x and loses 25% every time, so 20x + to 15x to 11x in 10 minutes and so on. Will drop into nothingness at ~40 minutes + mark. + - rscadd: Stasis will make you drowsy, and at higher stasis settings you will fall + asleep eventually (15x or higher). + - rscadd: 'Sleepers can into stasis too! They have three settings: none, 3x and + 5x.' + FTangSteve: + - tweak: Changeling now can only get nabber DNA with direct absorption. + Hubblenaut: + - tweak: RCON program no longer shows SMES units and breakers offsite the Torch. + - tweak: Alarm monitoring program no longer shows alerts offsite the Torch. + - bugfix: Fixes deck four fore dock. + Sbotkin: + - tweak: RCA, Shield Generator and Emitter crates now require engine access. + TheTrollDoctor: + - rscadd: Adds the MedHUD Visor item to loadout. It's a ~stylish~ MedHUD reskin + accessible for Medical roles. + sabiram: + - rscadd: Added advanced flash, smoke grenade, and metal foam grenade launcher hardsuit + modules. + - tweak: The captain's hardsuit now has an AI container, advanced flash and smoke + grenade launcher. + - tweak: The XO's hardsuit now has an advanced flash and smoke grenade launcher. + - tweak: The CE's hardsuit now has a metal foam grenade launcher. + - bugfix: The rig mounted RCD's use cost has been reduced from 100,000 to 300. + - bugfix: The correct voidsuits can now be found in command EVA. +2018-01-14: + Hubblenaut: + - bugfix: Fixes the horrible mess of pipes that was xenobiology. + LorenLuke: + - rscadd: Adds timestamp to PDA messages. + Orelbon: + - tweak: Consoles have been resprited. + comma: + - tweak: Chemist is now its own job slot. Medical Contractor slots lowered by one. + - rscdel: Removed Mortician because you don't get more useless than that. + sabiram: + - bugfix: Autolathes now function as normal. + - tweak: Bridge Officers now additionally have basic explorer access. +2018-01-15: + Techhead: + - tweak: A survey of medical supplies found the size of pill bottles woefully inadequate. + Larger pill bottles with more pills have been issued. +2018-01-16: + CountAlex: + - tweak: '"Refactoring corpse spawners."' + chaoko99: + - rscadd: Lasers and muzzle flashes now illuminate their surroundings. + - tweak: Beams are not visible quite as long due to vast optimizations in how they + are rendered. + - tweak: Muzzle flashes will now appear over lighting, and do not last nearly as + long. + - tweak: Bullets now fly more smoothly towards their targets. + - bugfix: Fixes a bug that caused the L6 SAW to load an empty sprite when closed + without a box magazine inside. + comma: + - tweak: Overmap size has been decreased. + - tweak: Number of overmap events has been decreased. + - tweak: Potential number of away missions has been decreased. + - bugfix: Ashtrays now empty their contents when thrown. + - tweak: Torch now starts at a random location on the overmap +2018-01-17: + Banditoz: + - maptweak: The GUP airlock now works. + Chinsky: + - rscdel: After yet another PR fiasco over field executions, Marine contingent is + no longer allowed on Torch. Those not under active investigation are offered + a transfer to Expeditionary Corps if they want to participate in the mission. + Earthcrusher: + - tweak: Thanks to the tightening of SCG industrial safety guidelines, you now must + be on harm intent and wait a few seconds before blowing up a fueltank with a + lit welder, lighter, or other handheld source of flame. + chaoko99: + - rscadd: cloaked mobs (ninjas and whatnot/Mehren) can now be spotted via T-ray. + - bugfix: Lasers will no longer fail to disappear during bluespace jump. +2018-01-18: + Chinsky: + - tweak: Modular computer programs were patched to allow more abuse. Now they use + the access of user who started them, instead of constantly checking for current + user's. + Orelbon: + - bugfix: Suit storage units now check for access. + - tweak: Suit storage units don't drop items when the powers fails anymore. + - tweak: Suit storage units can now be pried open when they are powered off and + not locked. + - tweak: Suit storage units can now dispense items when they are offline. + 'author: PrismaticGynoid': + - rscadd: Adds the ability to 'crawl' to an adjacent turf by click-dragging yourself + to it, after a delay. This can be used to move while unable to stand. You can + also do this with other movable objects, if you really wanted to. + - tweak: Conscious mobs lying on the ground can now buckle themselves to chairs/beds. + This includes people missing legs. + chaoko99: + - rscadd: Plasma cutter is now a gun, instead of a fancy drill. +2018-01-19: + Sbotkin: + - maptweak: The Pilot Lounge has been replaced with the Pathfinder's Office. + - maptweak: The NT pilot's voidsuit has been moved to the Petrov, with the cycler. + Techhead: + - rscadd: Corpsman and Engineers have been granted access to the hangar to help + them go on expeditions. Or help with the inevitable injuries and damage from + returning expeditions. You know, whichever. +2018-01-20: + Sbotkin: + - tweak: Changed required players for cult and deity from 5 to 10. +2018-01-21: + Orelbon: + - rscadd: Modular consoles now have colored keys per program. +2018-01-23: + Devildabeast: + - rscadd: Added a maglight to the Security Guard's locker. Yay. + comma: + - rscadd: Sharp things are now better at cutting plants, doing double damage. +2018-01-24: + Chinsky: + - tweak: Expeditionary Corps paygrades were adjusted - Explorers are now E3, Senior + Explorers are now E5. Brings Explorers more in line with 'default' rank of other + branch(es), Crewman/PFC. + - tweak: 'Senior Explorers: can no longer be Janitors, Masters at Arms. Can be Brig + Officers, Deck Officers, Senior Engineers.' + - tweak: 'Explorers: Can be Corpsmen, Forensic Techs.' + - rscadd: Can now use IV bags to give IV to people - drag it onto them to start. + Only works when bag is held in hand by someone. + - rscadd: Can now use syringes to change contents of IV bags. + - tweak: IV bags now hold 120u instead of 200u. Their size is dynamic - tiny item + when empty, turning into normal sized (doesn't fit in pockets etc) when over + 60u inside. + - rscadd: Can now set transfer rate of IV drips with a verb. + - tweak: Blood bags in medical and orderable crates were replaced with NANOBLOOD. + The normal blood was just not as efficient with size/transfer rate changes. + Using NANOBLOOD nets you more or less same re-blooding speed. + FTangSteve: + - tweak: Bioprinter will now print species-specific internal organs if they are + available + Novacat: + - spellcheck: Fixed capitalization issue with Radiant Aura + - rscadd: Added telepath (mRemoteSay) contract to all spellbooks + - tweak: Added 1 point to all spellbooks + - rscadd: Added Teleport, Cure Light Wounds, and Noclothes to all spellbooks that + lacked them + - rscdel: Removed Mage Armor from Standard spellbook, and Cure Light Wounds from + Cleric spellbook + - tweak: Swapped Focus staff for Scrying orb in Cleric book + - rscadd: Added X-ray contract to Battlemage book, parrot transformation to Druid + book + - rscdel: Removed Student spellbook + - tweak: Made staves slightly smaller, so that they are more portable + - rscadd: Overhauled cure spells to be more effective + - tweak: Reduced cost of Spatial's magic missile to 1 + - tweak: Boosts healing spells ability to purge radiation + - tweak: Fixes sacrifice self-damage + Sbotkin: + - rscadd: Adds mounted cooling units, available in all hardsuits. +2018-01-25: + chaoko99: + - bugfix: Attacks will no longer phase through dead or otherwise incapacitated slimes. + - tweak: Slime surgery is generally faster and now supports researched scalpels + and incision managers. +2018-01-26: + Casper3667: + - bugfix: Torso tattoos now works! + CrimsonShrike: + - rscadd: You can now move down onto turfs containing climbable atoms (tables, machinery). + chaoko99: + - imageadd: Removed paint drips from door sprites and doubles their framerates. +2018-01-27: + Casper3667: + - rscdel: Taj curly, housewife, victory curls and finger curls hairstyles have been + removed. + CountAlex: + - tweak: '"Lowered the temperature at which a mob receives lung damage from -13C + to -30C."' + Orelbon: + - rscadd: New glass door sprite. + chaoko99: + - rscadd: Added a parallaxing background space that changes colors every round. +2018-01-28: + Casper3667: + - rscadd: There are new bandanas in the loadout that can be worn on the head and + over the mouth. Old bandanas are still available in the loadout. + Devildabeast: + - rscadd: Adds the decorated harness, an Unathi-exclusive accessory complete with + two dueling knives, to the loadout. + - tweak: Changed the dueling knife to a piss-weak variation of the kitchen knife. + - tweak: Changes scarves to be allowed for semi- and formal roles in the loadout. + Sbotkin: + - tweak: Several loadout access tweaks. More things for civilians and pilot's pin + for the CO, XO, and Pathfinder. +2018-01-30: + Chinsky: + - tweak: Shuffled around EC uniforms. SERVICE uniform is now a thing of its own, + NOT a mix of utility+service. DRESS uniform is now service uniform + dress jacket + + gloves. + - tweak: R&D lab refluffing. No longer 'Research', it is now called 'Fabrication' + Lab. You are not 'discovering' things anymore. You are using high-tech fabricator + that uses self-learning matrix to direct nanobots. Problem is, IT KEEPS GETTING + MEMORY CORRUPTION. You are re-training bots by letting them practice on less + complicated things before they can tackle more challenging blueprints. + Devildabeast: + - tweak: Gives the NanoTrasen badge to the NanoTrasen Liaison in their backpack; + removes it from the NT formal outfit. + chaoko99: + - tweak: Trash bags are no longer denied from holding the nuke disk. Try and figure + that one out. +2018-01-31: + CountAlex: + - rscadd: '"Adds away mission map XCV Ahab''s Harpoon."' + Memescope: + - rscadd: Added new hairstyles, some ported from Eris. + - tweak: Low Bun back sprite tweaked. + - tweak: Half-Shaved Emo renamed to Long Side Emo. + chaoko99: + - rscadd: The T-Ray scanner now can be toggled via an action button. + - bugfix: Lasers now exist long enough that the game is likely to actually render + them most of the time. I blame our tickrate. + comma: + - rscadd: '"Added Fleet patches for their respective Fleets of origin to loadaout. + Check https://wiki.baystation12.net/Defence_Forces#The_Fleet for more deets"' +2018-02-01: + Dukica: + - rscadd: Adds new hairstyles and beards. + FTangSteve: + - rscadd: '"Upgrading to aggressive or initiating normal grab now enters struggle + if victim isn''t on help intent."' + ZeroBits: + - bugfix: '"Heat Exchange Pipes can now be properly constructed."' + - tweak: '"Heat Exchange Junctions will now exchange heat."' +2018-02-02: + FTangSteve: + - tweak: '"Nabbers now have hue shifted sprites available"' +2018-02-03: + Hubblenaut: + - bugfix: Fixes plating being dark when prying off floor tiles. + Sbotkin: + - tweak: Added kitchen access to bartender and bar access for chef. + - rscadd: Added a bar locker. + - maptweak: Added actual bar stools to the bar. + - maptweak: Removed wall-mounted safe from the bar. + 'author: FTangSteve': + - tweak: Makes struggle grab state shorter and causes confusion to make resisting + grabs more difficult + chaoko99: + - bugfix: You can now crawl through vents without worrying about carrying reality + (The skybox) in your body! Squeek! +2018-02-04: + Hubblenaut: + - bugfix: Fixes alert monitors being red for away mission alerts. + - bugfix: Fixes nonmodular atmos/alert consoles showing away mission alerts. + Sbotkin: + - rscadd: Polarized windows are now buildable. Click a reinforced one with a cable + coil. + - rscadd: Their IDs are changeable as well, use a multitool on windows and buttons. + Techhead: + - bugfix: Antag preferences default to Low again instead of Never. Relatedly, your + preferences will now longer display Never when they haven't actually been set + as such, fixing a bug causing unwilling players to be drafted for antag status. + TheTrollDoctor: + - rscadd: Gives Engineering Contractor, Medical Contractor and Research Assistant + access to the hangar. +2018-02-05: + Hubblenaut: + - bugfix: Camera alarms get cleared upon repair. + PsiOmegaDelta: + - tweak: Labels that have been attached using a hand labeler will now be remain + even if the name changes. + - rscadd: Attached labels can now be removed using the "Remove Label" verb in the + "Object" category. + sabiram: + - bugfix: Corrected chemist slot loadout issues. + - bugfix: NanoTrasen security staff can now use their provided holobadges. +2018-02-06: + Hubblenaut: + - rscdel: Removes Captain's spare ID card. + Sbotkin: + - tweak: Supermatter hallucination does not affect people without eyes or with synthetics + eyes. +2018-02-07: + Hubblenaut: + - bugfix: Fixes windows not visually connecting. + Sbotkin: + - tweak: Adds the medical channel to the roboticist's headset +2018-02-08: + Devildabeast: + - rscadd: Added the alternate titles of "SolGov Ombudsman" and "Inspector General" + to SolGov Representative and "NanoTrasen Representative" and "NanoTrasen Executive" + to the NanoTrasen Liaison. +2018-02-09: + Casper3667: + - rscadd: The utility uniforms (EC, general and EC skirt) now looks better on taj. + Additionally so does the welding helmet. +2018-02-11: + ZeroBits: + - tweak: '"Dark Floor Tiles can now be made with steel."' +2018-02-12: + Hubblenaut: + - tweak: There is now an announcement when the rampant brand intelligence was successfully + gotten rid of. + - tweak: The origin vending machine now shoots a lot more aggressively. + - tweak: Blinking red light on a vending machine now means that it shoots. + - bugfix: 'Hacker event: Hacker was destined to always lose. Fixed.' +2018-02-13: + CountAlex: + - rscadd: '"Adds away mission map - Lar Maria."' +2018-02-16: + Techhead: + - rscadd: Adds a new matchmaking relation, Childhood Friend. It'll only pick people + from the same home system with the same approximate age. + - tweak: Served Together now prefers to match people with others in the same branch. +2018-02-17: + sabiram: + - tweak: The mounted plasma cutter found on hardsuits has been converted to a projectile + weapon, like the stand-alone item. + - balance: The hardsuit mounted plasma cutter's ammo capacity has been reduced to + 4 from 10. +2018-02-19: + Techhead0: + - bugfix: PDAs and Air Alarms should now detect exotic gases a little better. Phoron + is now counted as an exotic gas for these purposes. + sabiram: + - balance: Stun weapons are now much less effective against simple animals, such + as carp. +2018-02-22: + Hubblenaut: + - bugfix: Fixes gravity event bringing people to fall in areas that do not usually + have gravitation. + chaoko99: + - rscadd: Ctrl clicking a table will flip or unflip it. +2018-02-25: + Hubblenaut: + - bugfix: Fixes the handheld teleporter only working as expected when adjacent to + teleporter hub. + - bugfix: Fixes the ref2name converter only working when adjacent to target. + - tweak: Medical scanner integrated circuits now work in vision range. + - bugfix: Fixes ducttape not being able to be picked up. +2018-02-26: + Banditoz: + - rscadd: Dog tags now have useful information on them upon spawn, including branch, + religion, and blood type. +2018-02-27: + sabiram: + - rscadd: The null rod can now purify cult floors in addition to walls. + - balance: The null rod's damage has been reduced. + - tweak: Maw creatures, ghost dogs, faithless and shades are now take additional + damage from the null rod. + - tweak: The null rod is now the null sceptre, a normal sized item. +2018-03-03: + LorenLuke, TheTrollDoctor, ChaosAlpha, sabiram: + - rscadd: Humans with sufficiently long hair can now tie their hair into different + styles using the 'Tie Hair' verb in the IC category. + mkalash: + - tweak: Infections get worse much more quickly (from ambient to acute in five minutes, + acute to septic in 10 minutes) + - tweak: Antibiotics take longer to work and infections acute and above require + antibiotics and rest to cure. +2018-03-04: + Banditoz: + - tweak: The shield generator's emergency shutdown function is now hidden behind + a hackable wire. + - tweak: Cut down the shield generator's emergency shutdown time by 50%. + - tweak: The EMP from the emergency shutdown scales with current charge--and is + guarenteed to happen. + Hubblenaut: + - rscadd: The access decrypter now allows the user to choose an access code instead + of picking one by random. + sabiram: + - rscadd: Some simple_animals, most notably humanoid enemies, can now escape nets. +2018-03-05: + Banditoz: + - rscadd: The Chaplain's locker now has a bible. + Novacat: + - tweak: 'Advanced First Aid Kit: Swaps inaprovaline autoinjector for assorted pill + bottle.' + - tweak: 'Burn First Aid Kit: Adds three ointment kits, swaps inaprovaline autoinjector + for tramadol autoinjector' + - tweak: Oxygen first aid kits now contain inaprovaline pill bottle, dexalin pill + bottle, and four inaprovaline autoinjectors + - tweak: Toxin first aid kits now contain a dylovene pill bottle, three hyronalin + pills, and four autoinjectors of dylovene + - tweak: Autoinjectors are now the same size as syringes + - tweak: Emergency Oxygen/Nitrogen Tanks now start off full + - tweak: Regular Nitrogen tank starts off at the same level as oxygen tanks + - tweak: Paracemetol's painkiller effect increased from 25 to 35 + Sbotkin: + - maptweak: The D2 Teleporter and the Custodial Closet are swapped. + - maptweak: The Drone Bay's door access is changed to robotics and no longer bolted. + chaoko99: + - rscadd: Research goggles now readoff research levels, as well as an item's matter + contents. When used to examine reagent containers (Beakers, burgers, bloodbags), + it will read off the contents. But . . . + - bugfix: get_reagent() no longer returns a given reagent's path. + thefrostycoder: + - rscadd: Languages that you can understand will now be named when they are spoke. + (Ex. ' enunciates in Selenian') +2018-03-06: + thefrostycoder: + - bugfix: Fixed random paint drips on doors. +2018-03-08: + chaoko99: + - tweak: Most bots will now render below a human. + - rscadd: Floorbots will now assume the colors of the toolboxes used to make them. + - imageadd: Added a Syndicate floorbot. Sadly, he is not evil. + - imageadd: Advanced trauma medibot added. + - bugfix: Cleanbot works now. +2018-03-10: + Rebruiza: + - soundadd: APC's now play a satisfying sound when they run out of power. + - soundadd: Maintenance now has ambience. + - soundadd: Fire alarms now have a new sound. + - soundadd: Airlocks and bolts now have a new sound. + - soundadd: Blast doors now have a new sound. + - soundadd: Suit storage units now have a new sound. + - soundadd: Lockers now have a new sound. + - soundadd: Touching metal walls now have a new sound. + - tweak: The sound of tube lights turning on is now louder. + Techhead0: + - rscadd: You can now temporarily reseal damaged spacesuits with duct tape. Either + click on the suit itself, or target the chest and click on a mob wearing a spacesuit. + But be warned, further damage will tear off the patch. + TheWelp: + - rscadd: Adds a temporary effect object to make spells look prettier. + sabiram: + - rscadd: The Sol Representative and the NT Liaison have been provided a fancier + pen in their PDA for writing their important documents. +2018-03-11: + Devildabeast: + - rscadd: Adds a Morpheus Cyberkinetics uniform to the loadout. +2018-03-12: + chaoko99: + - rscadd: Cremation now takes time. Doing so with a live subject inside will cause + it to rattle around violently. You monster. + - rscadd: You can now resist out of a crematorium on a short timer. You may also + eject someone from a crematorium from outside it on a similar timer. + - bugfix: Crematorium now uses a glowing sprite when active. + - imageadd: Changes the crematorium and morgue slab sprites to something cleaner. +2018-03-13: + chinsky & sabiram: + - rscadd: Belts and towels can now be worn on the belt slot, even with no clothing + equipped. + mkalash: + - rscadd: Added secure energy guns, which require registration to a user and are + locked to stun without additional per-mode authorization. Secure small energy + guns replace security's tasers. + - rscadd: NTsec now also get a shock mode for their revolvers, which is also locked + behind command authorization. +2018-03-14: + Banditoz: + - tweak: Everyone is now able to use dog tags. + Devildabeast: + - tweak: Off-Duty is now a separate role from Passenger, and is allowed to wear + Service and Dress uniforms. + mustafakalash: + - rscadd: You can now deface people's heads by targeting it with help intent and + using a pen, crayon, or lipstick -- even if it's no longer attached. Heads with + shoulders below them can be gentrified using a shower, or in a sink otherwise. + - bugfix: You can no longer apply lipstick to things without lips. + sabiram: + - rscadd: The King of Goats now has a chance to enter a 2nd phase in combat. +2018-03-15: + Devildabeast: + - tweak: Forensic Technicians can now be Civilian Contractors. + - rscdel: Private Investigator has been removed as an alternate title from Passenger. + afterthought: + - bugfix: The Odysseus syringe gun can now synthesize reagents. + - bugfix: Slipping out of mechas during gravity failure fixed. + sabiram: + - maptweak: The pens that previously spawned in the CO and XO's offices now spawn + in their PDAs, instead. +2018-03-17: + Sbotkin: + - tweak: Makes thick clothes to protect from changelings' stings. + - tweak: Makes buosuits thick. +2018-03-20: + Banditoz: + - rscadd: You will now be thrown around while on a shuttle if you aren't buckled. + Devildabeast: + - bugfix: Corrects a typo in the code, gives the Contractor Forensic Technician + the correct badge, and gives them additional items in the loadout. +2018-03-21: + Chinsky: + - tweak: Non-broken ribs/skulls now protect the internal organs a bit. + - tweak: Bullets no longer damage internal organs twice. As an effect organ damage + from bullets is lowered significantly. + Hubblenaut: + - rscadd: Adds the Disciplinary Board Room. + mustafakalash: + - bugfix: Using resist to unbuckle yourself no longer temporarily breaks your hands. +2018-03-22: + Chinsky: + - bugfix: Mass-spectrometers now actually display names of reagents. + Crushtoe: + - bugfix: For the very first time, toggle-hub-visibility works. + Devildabeast: + - rscadd: Adds a uniform for Skinner Catering and a pin for the Free Trade Union + to the loadout. + afterthought: + - bugfix: Various borg gripper fixes, including self-upgrading, cooking, APCs, and + mecha + chaoko99: + - rscadd: Xenophage cultists are now a feature-- They are allowed to ventcrawl with + tomes, robes, and swords. Also monkies I guess. + mkalash: + - rscadd: You can now toggle off showing end titles. + mustafakalash: + - rscadd: Staff now have the ability to mark variables to easily view them in an + auto-updating panel. + sabiram: + - imageadd: Secure energy guns are now visually distinct. +2018-03-24: + Atebite: + - rscadd: Telecommunication servers now have tagging rules which determine the radio + channel name and color for a given frequency + sabiram: + - rscadd: Hardsuit rig modules damaged by EMP can now be repaired with nanopaste. +2018-03-25: + Devildabeast: + - rscadd: Adds a gyroscooter, a subtype of the space bike. + - maptweak: Adds a gyroscooter to the Research Director's office. + TheWelp: + - tweak: Tweaks zombie turn rate. Should be non-impossible. + - bugfix: Fixes zombie consume. + sabiram: + - rscadd: Wall mirrors are now containers, and contain some things. + - tweak: F6 is now msay instead of asay for staff. +2018-03-26: + Banditoz: + - rscadd: Add the ability to rename a bible, or change its icon. + - rscadd: Add new bible sprites from tlc2013. + Devildabeast: + - tweak: Allows Dionaea to select Forensic Technician at chargen. + - tweak: Makes the Roboticist a hybrid role between Engineering and Medical and + gives them access to medical items in the loadout. + Earthcrusher: + - rscadd: Adds a package wrapper synthesizer. + - tweak: Clerical borgs now include a package wrapper synthesizer and destination + tagger. + - tweak: Clerical borgs now have a "clerical gripper", not a "paperwork gripper", + and can pick up small-sized packages. + - tweak: Clerical borgs now include the Supply channel, in addition to Service. + - tweak: The destination tagger will now give feedback when selecting a destination. + - bugfix: Back-end adjustments to how package wrappers and synth grippers are handled. + FTangSteve: + - tweak: changes injury specific medical kit contents to medical pouches. + - tweak: advanced medical kits are now purple. + - rscadd: adds small emergency medical pouches that require no medical training + to use. + - maptweak: adds new medical items around. + - tweak: adds medical pouches to nanomeds + TheGreyWolf: + - bugfix: Armor pouch colors can now be properly selected from loadout. +2018-03-27: + Atebite and Cakey: + - rscadd: Ironing equipment to get those unbecoming wrinkles out of your uniform... + or your crewmates + - bugfix: Washing machines no longer eat clothes +2018-03-28: + Cakey: + - imageadd: Fleet service and dress uniforms have been re-sprited to take on a navy + blue theme. Fleet uniforms have now been split into three categories, with lower + ranks recieving a sailors uniform rather than the non-commissioned officer's + coat. + - bugfix: Fixes service and exploration uniforms sharing the same datums. + Devildabeast: + - rscadd: Adds a forensic belt to the Forensic Technician's locker. + - maptweak: Changes the Forensics door from glass to regular. + Earthcrusher: + - tweak: The jukebox has been resprited. + - rscadd: New tracks added to the jukebox music selection; some have had their names + corrected. + sabiram: + - soundadd: The Emperor of Goats now comes complete with his own battle themes. +2018-03-29: + Bill-Luxe: + - rscadd: Ported railings from the Europa. You can now create it by using a different + material sheets. + Cakey: + - maptweak: Deck 4 has been re-worked. Supply now has a bigger warehouse and the + escape arms have been moved forwards. + - maptweak: Added the very important laundry room on deck 4, with ironing boards + soon to come. All washing machines outside of the laundry room have been purged. + - maptweak: Added green pens to liason and spare offices. +2018-03-30: + PurpleMartinJCK: + - bugfix: Fix medical crate sprites, adding back to storage.dmi + - tweak: Add pouch spawns to small medical random spawn + - tweak: Add trauma kit to medical kit spawn + - bugfix: Fix pouch names in venders + - rscadd: Add new pouch supply crates +2018-04-01: + Chinsky: + - tweak: Liver damage change. Now when it's not working right, it doesn't apply + staright up damage (only for alcohol), it builds up ammonia in the blood up + to toxic levels. Better get those scrubbers going. + - tweak: Kidneys are doing similar thing, but with potassium. + - tweak: Potassium now raises pulse, dangerously so over 10u. + - tweak: Bananas now have bit of potassium in them. + Devildabeast: + - rscadd: Ports Grayson Arms prosthetics from Polaris. + - rscadd: Ports robolimb optics from Paradise. + - tweak: Vox can no longer be selected as a species when building an FBP. + - tweak: Morpheus prosthetics are no longer restricted to IPCs. + - tweak: The Morpheus Alt. head is now the default and the Monitor is a subtype. + afterthought: + - bugfix: PDAs with medical access once again have a handheld medical scanner scanner + program. +2018-04-02: + Chinsky: + - rscadd: Finally swaps old stinky blood in Medbay for NANOBLOOD(TM). Use wisely. + - rscadd: Increased immersion. + - experiment: To further immerse you in your character, you now need to blink manually + if you have organic eyes. There's helpful messages to remind you of that now. + - experiment: To help new players acclimatize to our high RP standards, helpful + hints have been added, shown when you perform ceratin actions to guide to maximum + RP path. + - experiment: As an experiment, different kinds of guns can now be selected in custom + loadouts in Utility section. Everyone can get holsters too now. Spare ammo is + not included. + sabiram: + - balance: Wizards can no longer teleport to non-station Z levels. +2018-04-03: + Dukica: + - rscadd: With the addition of a fancy new, tentacular helmet, the Skrell can now + use the Rescue Module (Medical RIG) suit! + sabiram: + - maptweak: Added The Orb, a mining focused away site. +2018-04-04: + Devildabeast: + - maptweak: Adds a mech recharger to the Security Armory. + afterthought: + - bugfix: Fixes roller bed SSD bug. + chaoko99: + - bugfix: T-rays actually work on ninjas now. + - tweak: Portable atmospherics devices will now work off an APC if available. + mustafakalash: + - tweak: The Torch will once again always spawn on an asteroid. + - tweak: Changes occupation settings from a cycle to a list. +2018-04-06: + Devildabeast: + - tweak: Allows the Roboticist to select medical webbing vest, medical drop pouches, + and the medical poncho in loadout. + PurpleMartinJCK: + - rscadd: Wizards now have a spell that lets them make a long-lasting portal to + away sites. +2018-04-07: + sabiram: + - tweak: Wire brushes are no longer as effective a melee weapon as a pickaxe. +2018-04-08: + Chinsky: + - rscadd: Can now pick EC Directives as shackles for IPC. + chaoko99: + - tweak: Crawling now occurs by clicking a turf. + - tweak: Crawling is now significantly faster. + - bugfix: You can no longer drag other people, forcing them to crawl. +2018-04-09: + Devildabeast: + - maptweak: Adds green pens to the SolGov Representative's and NanoTrasen Liaison's + offices. +2018-04-10: + ParadoxonKomplikon: + - tweak: '"Exotic seeds do not contain certain reagents, such as alcoholic drinks, + anymore."' + - tweak: '"Exotic seeds'' production time is now generally shorter than before."' +2018-04-11: + CakeQ: + - maptweak: Replaces the conference room on deck one with a briefing room. + - maptweak: Added a table/shutter combo intbetween the captain's mess and briefing + room for the chef's use. + FTangSteve: + - rscadd: Makes breathing far more relevant + - rscadd: CO2 buildup is now potentially dangerous and must be scrubbed + - rscadd: Tank sizes have been adjusted and will need to be refilled more often +2018-04-12: + chaoko99: + - soundadd: 'C4, timers, and nukes will now make an ominous beeping noise. spriteadd: + Porta-nuke resprited, uses the porta nuke sprite from TG.' +2018-04-13: + FearTheBlackout: + - maptweak: Moves exosuit tracking beacon crate to Robotics Maintenance + chaoko99: + - bugfix: Crawling works while lying down again. + - bugfix: Crawling no longer functions in space. +2018-04-14: + Cajoes: + - rscadd: Added a lube variant called oil, comes in jugs of 100 units, dispensable + from robotics vendor. + - rscadd: Added beer and ale cans to the alcohol vendor. + - rscadd: Added lava lamps and office toys to the misc. supply menu. + - rscadd: Added fish meat and a big bag of salt to the kitchen. + - tweak: Changed contents of some drinks. + Cakey: + - imageadd: Adds new floor tile sprites. + - imageadd: Adds new floor decals. + - rscadd: Adds several new floor tile types to litter the station with. + Chinsky: + - rscadd: Can now use grab on EC plaques to display Directives to people. Forcefully. + PurpleMartinJCK: + - rscadd: Adds species based darkvision + - tweak: Tweaks light falloff calculations + sabiram: + - tweak: Species with better than average night vision are now more vulnerable to + flashes. +2018-04-15: + Chinsky: + - rscadd: Can use pill bottle on self aiming at mouth to quick-pop a random pill + from it. Yum. + HetNeSS: + - bugfix: Expedition storage area layout fixed. All lights should be connected properly + now. + - maptweak: Sorted out the expedition storage inventory. Piping, maint door location + adjusted. + Sbotkin: + - maptweak: Removed excess stuff (extra tools, consoles) from the forensic technician's + laboratory. + - rscdel: Removed excess tools from the forensic technician's locker. + sabiram: + - tweak: The automatic transfer vote called at 3 hours has been changed. The 'Continue + the Round' option will now extend the round by 30 minutes instead of 1 hour. + - tweak: The default type of robot in character select is now 'robot', a positronic + unit, as opposed to 'cyborg', which has a human brain. + - tweak: Robots with a computer chip based brain are now referred to as 'drones'. +2018-04-16: + Cakey: + - maptweak: The mess hall has been re-shuffled to allow for the cook to have more + of a presence. + Sbotkin: + - maptweak: The Chief of Security's Office is remapped. + - maptweak: The Board Disciplinary Room no longer has attributes of a high secure + area. +2018-04-17: + Banditoz: + - maptweak: More newscasters have been mapped throughout the Torch. + Sbotkin: + - maptweak: The Brig Officer's office is remapped. + Zuhayr: + - tweak: Xenomorph brute resistance, movement speed and and armour have all been + significantly adjusted. Be on the lookout for xenos being nerf OP and report + issues to the tracker. + afterthought: + - tweak: 'Skills are now selected on a per-job basis under Occupations. Warning: + current skill data will be lost!' +2018-04-18: + Banditoz: + - tweak: Non-living players may no longer cast votes of any kind during crew transfer + votes. + Cajoes/BloodyMan: + - rscadd: Ports TG Cigarette Paper code + - tweak: added four more cigarettes to cigarette packs + - tweak: gave a use for existing filter and cigarette paper icons + - rscadd: added icons for, lollipops, gum, nicotine gum, rolled cigarettes, filter-boxes, + gum-boxes, cookie-packs and spitwads + - rscadd: added icons made by Woah Hold There Buddy, (tobacco packs, chewing tobacco + packs,) + - rscadd: added chewable category, reskinned cigs you equip, chewing tobacco, lollipops + and gum added + - rscadd: added recipes for using the rolling papers to make cigs using dried plant + matter or pre-packed tobacco + - rscadd: added onmob animation for chewing gum (but not for nicotine gum) + HetNeSS: + - tweak: Added a capability for surgeon borgs to pick up an IV packs with their + organ gripper module. +2018-04-19: + chaoko99: + - rscadd: Fire extinguisher may now accept fluids from all forms of reagent containers + (HCL dispensers, capsaicin dispensers, coolant tanks, fuel tanks etc.) and spray + them at EXTREMELY low levels of efficiency (100 units a spray, wasteful for + most things.) Firefighter extinguishers may also accept in the same way. BEWARE. + - tweak: Water may now cool down to 20c when sprayed (Includes grenades, for example.), + with a diminishing return below 60c. + - rscadd: Like the above, coolant may be used to cool areas, best saved for phoron + fires or traitoring, because it's extremely efficient and may dip an area to + just a little over 0 kelvin if you're not careful. + - tweak: Extinguishers will fire multiple puffs of reagents instead of three sprays + at the exact same time. More or less consequence of a performance change. + comma: + - tweak: Replaces most eguns with secure variants. Swipe ID to register. + - tweak: Secure guns get all modes unlocked if it's Red Alert + - tweak: CO's revolver was moved out of locker into a display case +2018-04-20: + Sbotkin: + - maptweak: The Forensic Technician's office is remapped again, a lab added. + - maptweak: It's now possible to access the morgue as the fortech. + TheWelp: + - rscadd: Adds Spellbound Servants. Powerful minions of wizards, each with their + own gimmick and theme. + - rscadd: Implements two mutations, nobreathe and spaceres, in conjunction with + the spellbound. + chaoko99: + - rscadd: hydroponics trays, covers, and plump helmets have been re-sprited. + - tweak: Plump helmets are now repeatedly harvest-able, but require a high amount + of nutriment to sustain. You only harvest the 'helmet' of the plump helmet, + as well. + - tweak: Hydro trays will default to 5 lumen lighting for their covers +2018-04-21: + HetNeSS: + - maptweak: Morgue has been split up to two sections - "Morgue" and "Autopsy". Autopsy + - area created. + - imageadd: Autopsy - area icon added + - rscadd: Two sliding doors added to separate the morgue from the autopsy zone. + Morgue or Medical access level required on each one. Autopsy atmospherics controller + added. Morgue - lightswitch, APC added. +2018-04-22: + Banditoz: + - rscadd: You can now export ore scanner disks inside of crates on the supply shuttle + for some extra supply points. + BlueNexus: + - rscadd: Plasteel combat shields have been added to the emergency armoury, replacing + the unused biosuit closet. + Chinsky: + - rscadd: Adds color picker mode to floor painter (which is renamed to paintgun). + - rscadd: Can now hit APCs with heavy big things to unlock them. Doing so risks + breaking them completely. + - rscadd: Being in pain, not seeing properly, or being confused will now affects + accuracy of your attacks. + HetNeSS: + - maptweak: A survellance camera had been installed - D3 mess hall - galley. + sabiram: + - tweak: Stun electrode projectiles fired from stun revolvers now move faster. +2018-04-23: + Chinsky: + - rscadd: Supply crates now have secure variants of guns. + - rscadd: Unsecure guns can be ordered with contraband crates. + Sbotkin: + - tweak: Bridge Officers' got helmets and correct tablet computers. + sabiram: + - bugfix: Fixes red alert being available in the command and communications program. + - bugfix: Red alert once again may only be set through the keycard authentication + devices (small white and black panels on walls) found in officers' offices and + on the bridge. + - rscadd: Red alert now only be cancelled using the keycard authentication devices. + - tweak: Admins are now provided jump links in the 'has forced open an emergency + shutter' message. +2018-04-24: + Chinsky: + - tweak: Skill costs and free skillpoints amounts were severely tweaked, check your + allocations since they're most likely invalid now. + - tweak: Tweaks to some medicines' OD effects. + - tweak: Paracetamol and cold medicine now do not apply organ damage, but still + prevent natural healing when you OD. + - tweak: Inaprovaline, being brain soothy chem, makes you slower and sometimes slur + and get drowsy when you OD (60u folks). + - tweak: Bicaridine, on top of usual toxic effects, now has a chance to heal arterial + bleedings! But at the same time it blocks blood flow, lowering blood circulation + by 20+% (depends on how much did you go past the OD threshold). + HetNeSS: + - tweak: Magnetic grippers are now capable of grabbing deuterium and tritium ingots + as well. + comma: + - rscadd: PDAs are now modular computers. +2018-04-25: + BloodyMan: + - rscadd: Blending tofu now yields an egg substitute for vegan baked goods. + afterthought2: + - bugfix: Skill system saving ACTUALLY works correctly again. + - bugfix: Skill system saving works correctly again. +2018-04-26: + BlueNexus: + - bugfix: Uplink-bought railguns no longer explode + Chinsky: + - tweak: Lung popping condition changed. Now it only happens when pressure changes + (both internal and external), not constantly when you're in vacuum. Pressurized + suits prevent popping by reducing external pressure difference impact. +2018-04-27: + afterthought2: + - bugfix: Crisis borg splints now work. +2018-04-29: + Chinsky: + - tweak: Moved explorers gearup room to where that gross quarantine thing was. Previous + location is now an unused room + - tweak: Moved bunch of crap from explorer lockers onto the racks and tables. + - tweak: Explorer access now opens the room where anomaly containers/stasis cages + are, the one with the drill. + - tweak: Gave bunch of random crap to explorers in the gear room - glowsticks, cameras. +2018-04-30: + Banditoz: + - rscadd: Cyborgs get a secure energy gun (replaced taser rifle) which can be granted + lethal mode by a console, or red alert. Silicons cannot set it for eachother, + or themselves. +2018-05-03: + afterthought2: + - bugfix: Irreparable organs can no longer be healed by any means. +2018-05-04: + HetNeSS: + - tweak: Bandolier's can now also hold pills, pill bottles, papers, pens, photo's + and marshalling wands. + sabiram: + - rscadd: Added a pathfinder hardsuit module to exploration suit room. + - maptweak: Fixed several issues in the exploration storage rooms. + - rscadd: Added illumination grenades, which generate a bright, wide light when + detonated. Added illumination grenade crate to supply under miscellaneous category. + Added hardsuit illumination grenade module. +2018-05-05: + afterthought2: + - rscadd: Scanner modules added for modular computers. Available (job-depending) + on spawn, and also from supply crates. + - rscadd: 'The scanners are: paper, medical, atmos, and reagent. You can have at + most one at any time. Compatible with all computers, but only the paper and + atmos scanners will do anything when in a console.' + - rscadd: Scanner program added for modular computers, which interfaces with scanners. + Can view and save scan results, which may be edited with NanoWord. + - tweak: If a scanner and a nanoprinter is installed, the printer can now only be + refilled with blank paper. + - bugfix: The tax program should no longer produce duplicate copies or unexpected + behavior. +2018-05-06: + TheGreyWolf: + - bugfix: The MAA alt title is now fixed to not exist. + afterthought2: + - rscadd: 'The crisis borg module comes with a stasis bag rack, which can hold 3 + body bags or stasis bags. Starts empty to avoid exploits: go find your own.' + - tweak: Borgs now fold up roller beds by clicking and dragging, like everyone else. + - tweak: Borg interactions with ironing boards while having the roller rack equipped + are similar to humans (they still can't iron, though). +2018-05-07: + Chinsky: + - rscadd: Can now use multitool on secure guns to disable tracker. Prevents gun + from firing, but won't report its coordinates to the force auth program. + - rscadd: Makes emagged secure guns not show up too. +2018-05-08: + afterthought2: + - bugfix: Borgs and AI are given emails after name selection. Emails are updated + on name change. + - bugfix: Borgs and AI can read emails from the "Email Client" in the Subsystems + verb. The email administration program can still be accessed by AI but has been + moved to "Email Administration." +2018-05-09: + afterthought2: + - tweak: CE and CMO get job-appropriate scanners on their PDAs now. + - tweak: Modular computer scanners can now be printed via protolathe. + - tweak: Hitting a modular computer with a paper bundle puts it in the printer. + To scan, separate the bundle. + - bugfix: The chemist's pda scanner is fixed. +2018-05-10: + chaoko99: + - soundadd: Cleanbots now make cute little beeps when active and functioning. +2018-05-15: + Banditoz: + - rscadd: Added a new gamemode, fathless; a mix between cult and deity (also known + by some as godcult.) + Cakey: + - maptweak: Moved alll checkpoints to be positioned in more key areas. B-deck and + deck one checkpoints are now connected via ladder. All checkpoints now have + the ability to cut-off certain sections of the hallways for flow control. + - maptweak: Brig officer now has a disposals bin. + - maptweak: Emergency armory has been altered to have 3 carbines and 3 e-guns as + opposed to the 2:3 loadout to match the rest of the E-ARM. + - maptweak: Brig armory has been altered to have 4 e-guns as opposed to 3 to match + the rest of the armory. + Casper3667: + - rscadd: Vox now spawn with their air filter gas mask. + Dukica: + - rscadd: 'Enabled ponchos, aprons and hazard vests for GAS to wear. rstweak: Some + typos were cleaned up.' + Miraviel: + - bugfix: You can now use sign language even if you are muzzled. + afterthought2: + - tweak: Very damaged heads will be marked as "critical" rather than "irreparable" + on scanners, and can be healed even past max_damage threshold. + - rscadd: Adds a deck management program, which gives some information on shuttle + movements. + - rscadd: Adds flight plans, which can be filed via this program by those with shuttle + flight access. + - rscadd: If the flight plan includes a roster, the members on the roster can be + summoned via automatic comms announcements or batch-emailed. + - rscadd: Adds other reports that supply can file about shuttle missions after the + mission has departed/returned. + - rscadd: Adds a stripped-down report viewer program, currently mostly useful for + viewing emailed reports. + chaoko99: + - rscdel: Reverted a change that made it impossible to draw/fill plant reagents. + You may now make your tomato grenades again. + tlc2013: + - bugfix: Fixed certain Spellbound Servant equipment not having the proper icons, + or - at worst - having no icons at all. +2018-05-16: + Banditoz: + - maptweak: Remaps the Petrov toxins lab to be more intuitive to use. + - tweak: Powered crossbows have been buffed. You don't need to draw back as much, + and it takes less time to do so. +2018-05-17: + afterthought2: + - tweak: The deck management program will now allow you to queue up scheduled missions, + rearrange their order, and delete them. Once started (i.e. once the shuttle + departs) the active mission is finalized and can no longer be deleted or moved + around, but can still be renamed. + - tweak: Deck management announcements are now a bit less spammy and let you choose + an area other than the shuttle to meet. + - tweak: One more report has been added, a post-mission summary. + - bugfix: Crew record access issues fixed. + chaoko99: + - tweak: Emergency shield generators now cover an entire screen. Power draw per + shield unaffected. +2018-05-18: + Cakey: + - maptweak: Adds railings to all stairwells. + Chinsky: + - tweak: PDAs and ID cards no longer have whole name and job in their item name. + - tweak: When examining people, you will see a linkie to see their ID. That will + give you name/job if you're nearby, or show you the window with full info if + you're adjacent. + sabiram: + - rscadd: Blast doors and shutters can now be damaged by hitting them with sufficiently + powerful items. + tlc2013: + - rscadd: Added a recolorable kimono to the loadout selection. +2018-05-19: + PurpleMartinJCK: + - rscadd: add new nabber organs + - rscadd: flesh printer can now print nabber organs + - rscadd: low blood can force nabbers out of nab mode + - tweak: crushing and shredding now decloak nabbers + - tweak: lower some nabber brute resistance in favour of natural armour + - tweak: encases all external nabber organs in carapace + afterthought2: + - tweak: Those with heads access now have more access to Deck Management. + - bugfix: Access issues with supplementary Deck Management reports should be resolved. +2018-05-20: + afterthought2: + - tweak: Headsets start with a free encryption key slot now. +2018-05-21: + afterthought2: + - tweak: Cryo tubes use up chemicals ten times faster. Effective healing rate remains + unchanged. + - tweak: Genetic damage is healed ten times faster in cryo tubes. + - bugfix: The organ printer now prints visible organs. +2018-05-22: + Banditoz: + - rscadd: Borgs can now lock and unlock their own panel. + Cajoes: + - rscadd: Snix, HotFoods and Lavatory vending machines and hid them on the map. + - tweak: All snack food relative paths are now absolute paths. Nobody noticed nor + cared. + Cakey: + - maptweak: Consoles have been rotated to match how they should be. + chaoko99: + - rscadd: Added a light-toning system, lights will color dynamically to what color + they emit. + - rscadd: Fingerprints will no longer magically phase through gloves. + - tweak: Robolimbs don't make fingerprints anymore. + - bugfix: Thick gloves actually use thickmaterial. +2018-05-23: + Banditoz: + - bugfix: Destroyed portable turrets are now climbable. + TheWelp: + - rscadd: Adds a new deity menu free of uplink structure. + - tweak: Some deity store items now increase in price the more you buy them. (E.G. + Conjuration) + - rscdel: Remove Godvision. + afterthought2: + - bugfix: Fake crew announcements should use ID card data now. + - bugfix: Antag preferences being reset to low should be fixed. If you continue + experiencing this issue, please submit a new bug report. +2018-05-24: + Alex6511: + - bugfix: Fixed "3" being printed when placed on a surgery table. + chaoko99: + - bugfix: Lights aren't super dark anymore. Blame Chaoko99 for being blind and not + noticing the difference during testing. + - bugfix: Fixes weird sprite bugs for broken and burnt lights. +2018-05-25: + PoZe: + - rscadd: Added oxygen candles as an item. They are one-time emergency item that + is used to fill 2-3 tiles of depressurized environment + afirpo: + - maptweak: Added an access button to icly cycle between Exterior and Interior fusion + core chamber. + afterthought2: + - bugfix: Crew records will now correctly display things like ' and " in-game. +2018-05-26: + HetNeSS: + - maptweak: The fore docking port on deck four had been widened in size, as the + main docking port be probably should. + - maptweak: Remodelled the Mercenaries gamemode transport shuttle, to suit the extended + docking bay, as well as for more beefy and physics-justifiable look. + - bugfix: '"Northeast of First Deck" and "Northwest of Fourth Deck" waypoints swapped + places (aka fixed)' +2018-05-27: + Casper3667: + - rscadd: Tajara can now use normal gloves and claw attacks can't be used when wearing + gloves. +2018-05-28: + Cajoes: + - tweak: New fax machine icon. +2018-05-30: + Alex6511: + - tweak: Amputation text is now larger for the surgeon performing the amputation + Banditoz: + - bugfix: The rapid taser cooling module (now called the rapid weapon cooling module) + upgrade now works. +2018-05-31: + afterthought2: + - rscadd: the report editor can now print reports and export them to text files. + - rscadd: the report editor can download new (blank) reports from NTnet. A few of + the forms from the wiki can now be chosen in this way. +2018-06-01: + Banditoz: + - rscdel: Hand teleporters have been removed from teleporter rooms. + - maptweak: Teleporter beacons have been removed from some high security areas onboard + the Torch. + - maptweak: A teleporter beacon has been added to NanoTrasen's miscellaneous research's + test chamber. + sabiram: + - tweak: Off-duty ID cards are now visually distinct and can no longer be modified. +2018-06-02: + afterthought and chinsky: + - rscadd: 'The "Medicine" skill now influences interaction with some medical objects: + syringes, defibrillators, sleepers, handheld scanners, full body scanners, IV + drips, and splints.' + - tweak: Full body scanners now store scan data. Use the menu options to print, + erase, or scan/re-scan. + - tweak: IV drips now take a short time to hook up. +2018-06-06: + afterthought2: + - tweak: Off-Duty is no longer a separate job, but an alt-title of Passenger. You + no longer spawn with ranks in uniform if selecting off-duty. + chaoko99: + - tweak: Books and papers may now be 2x as long. This was changed to make it so + records could be longer, without the skeleton taking up half the usable text. +2018-06-07: + Cajoes: + - rscadd: Added new visors for Tajaran to shield their eyes with. Available exclusively + in the xeno portion of the loadout screen. + - rscadd: Added Hot Food showcase to manage kitchen's output. + - rscdel: Removed Lavatory Essentials Vendor on Deck 2 due to [redacted]. +2018-06-08: + TheGreyWolf: + - bugfix: Press tags can now actually be taken by the press. + Zuhayr: + - rscadd: Added methyl bromide, a fumigant gas that kills spiders. + - rscadd: Added bromide, a toxic reagent, from which can be derived a liquid form + of methyl bromide. Methyl bromide kills spiderlings and egg sacs when injected. + - rscadd: Added algae to hydroponics. Algae produce liquid bromide and gaseous methyl + bromide. + - rscadd: Added an interaction to optables that will automatically put someone lying + on top of it to sleep with no need for N2O or painkillers. + - rscdel: Removed N2O pumps as being both redundant and buggy. + afterthought2: + - rscadd: The slowdown for pulling (i.e. ctl-click) stuff is now affected by the + "Athletics" skill. + - tweak: Bigger/stronger species pull things faster. + - rscadd: Pulling stuff generates adrenaline, depending on "Athletics" skill. This + may raise your heart rate. Pulling for a long time without breaks with low skill + may give you the jitter effect and minor heart damage (won't kill you). +2018-06-09: + Banditoz: + - tweak: The T-Ray scanner is now faster, has an increased range of 7x7, and is + now without the flicker effect. + sabiram: + - tweak: Gyroscooters now shield their pilot from 5% of projectiles, down from 40%. + - tweak: Gyroscooters are now slightly slower. + - tweak: Attempting to move a bike or gyroscooter while stunned will now eject you. +2018-06-10: + Banditoz: + - maptweak: The Aquila has been divided into areas, and remapped a bit. + - rscdel: The Aquila's death trap has been removed. +2018-06-11: + BlueNexus: + - tweak: Increased TC costs for railguns + Chinsky: + - tweak: Now for ghetto EVA the size of thrown thing matters. Tiny things give you + ~10% chance of direction change, with 'normal' sized things having 90%, guartanteed + above. + afterthought2: + - rscadd: Throwing "huge" items (e.g. roller beds, backpacks, certain guns, rigs, + jetpacks) or normal sized mobs without "Basic" skill in "Athletics" will briefly + weaken you (and the items won't go far). + - rscadd: Thrown items don't go as far and have less speed/force if you have lower + "Athletics" skill. + - rscadd: The weightlifting machine at the gym has more weight levels. Having high + "Athletics" means you can lift more. If you try lifting way more than you are + capable of, you may hurt yourself. + sabiram and Cakey: + - rscadd: The bird temple on the mining map has been redesigned and now houses the + fountain of youth. +2018-06-12: + Broseph Stylin: + - rscadd: Added rucksacks to Character Setup. They function exactly the same as + backpacks. + afterthought2: + - rscadd: Lactate is a reagent that increases heart rate, causes generally harmless + shortness of breath, and slows movement. After processing a large amount of + lactate, mobs may experience temporary jitters. + - tweak: Instead of producing adrenaline, pulling produces lactate. + - rscadd: Robots can now interact with storage items like boxes and bags. + chaoko99: + - bugfix: Trays will now adequately notify you of not being able to be placed in + bags. +2018-06-13: + Cakey: + - imageadd: New wall sprites have been added. + - imageadd: New door sprites have been added. + - imageadd: New window sprites have been added. + - imageadd: New grille sprites have been added. + - rscadd: Airlocks are now paintable. + - rscadd: Window frames have been added, which connect to walls for that aesthetic + look. + - rscadd: Airlocks can now be painted using the airlock painter. + - rscadd: Added paint presets to the paintgun. + - maptweak: The Torch has been modified to use window frames instead of just windows. + - maptweak: Maintenance has been given more catwalks. + - maptweak: Added binoculars to security checkpoints. + ZeroBits: + - tweak: Material Grinders have been reworked to allow different reagent quantities + and multiple reagents when grinding material sheets + Zuhayr: + - tweak: Gas inhalation effects are now reagent-based. Gases create reagents inside + the body, which then apply effects. This means that gaseous phoron exposure, + for example, needs to be treated with dialysis/dylovene, as it fills your guts + up with liquid phoron. + - tweak: The poison_type var on species datums is now poison_types, and determines + which poison gasses show you the toxins UI indicator, rather than which ones + cause poisoning. The actual effects of poisonous gasses is determined by the + reagent value (as per dexalin being injected into a vox, etc.). This really + shouldn't impact anything for the average player, except that chlorine and nitrogen + dioxide (not N2O, for clarity) are now actually poisonous. + - tweak: Helium now makes your voice squeaky. Very important feature. + - tweak: Xenon is now functionally the same as N2O, including the following note. + - tweak: N2O now causes giggling, confusion, dizziness and occasional passing out + at high dosages, rather than instant and immediate knockout. Still useful for + riot control and now flooding it into distro isn't a round-ender. You might + even be able to use it without admins shouting at you! Refer to the optable + neural suppressor PR for a replacement method to sedate people for surgery. + - tweak: Finally, as a sidenote, Bogani will actually be poisoned by oxygen and + chlorine will have a visible overlay now. + afterthought2: + - rscadd: Experienced in Chemistry allows you to see scannable reagents in a held + beaker/container. + - rscadd: Professional in Chemistry allows you to see all reagents in a held container. + - tweak: Science goggles give more precise volume readings at higher chem skill. +2018-06-14: + ElRobusto: + - tweak: Cuts the Vox space suit movement penalty by half. + TheWelp: + - rscadd: Adds two currently admin-only races, the Starborn and the Blueforged. + Will be available in future deity form. + - tweak: Tweaks Shadow species death to not cause runtimes. +2018-06-15: + Banditoz: + - tweak: The cyborg manual now has all the current cyborg modules. + - tweak: The Supermatter guide shouldn't lead engineers to delaminate the engine, + now. + ParadoxSpace: + - rscadd: Adds two new IPC/FBP chassii, Morpheus Mantis and Ward-Takahashi Economy. + - tweak: Grayson, W-T Economy, and Xion are now available at the roboticist fabricator. + afterthought2: + - rscadd: The chem grinder is dangerous to use at "Unskilled" in Chemistry and will + lose some ingredients depending on skill level. + - rscadd: The chem dispenser will give inaccurate amounts of ingredients or add + extra contaminating ingredients when below skill "Trained" (in Chemistry or + Cooking, depending on dispenser) Can be slightly dangerous. + - rscadd: The chem master now has two modes. "Quick" will move the correct amount + of ingredients from beaker to buffer, but also add contaminants (depending on + skill). "Thorough" will only move the desired ingredient, but incur losses (depending + on skill). Skill checked is Chemistry for chem master, Cooking for Condimaster. + - rscadd: Moving ingredients from buffer to waste or beaker acts like on "Quick" + mode. +2018-06-17: + ParadoxSpace: + - rscadd: Adds bowman type headsets to all non-service departments. + - rscadd: Adds unique pilot, miner, corpsman, and explorer headsets. + - rscadd: Adds tacticool Syndicate headsets to mercs. + - rscadd: If tcomms is down or unavailable for whatever reason and you have a shortwave + radio in your pocket, your headset will now automatically transmit through it. + It still cannot do department channels. +2018-06-18: + Chinsky: + - tweak: Some loadout items are now restricted by branch instead of jobs. Some are + restricted by both. You might experience sudden loss of swag on next spawn, + check your setup. + TheWelp: + - rscadd: Adds various starlight specific spells for use in future deity form. + - tweak: Adds two new flags for targeted spells to filter via faction. + - tweak: Adds more effects for some spells. + afterthought2: + - rscadd: adds the instruct verb. A character with basic leadership and experienced + skill X can instruct a character in X from Untrained to Basic. Has a 15 minute + cooldown to use; buff lasts all round; max of three buffs on any person. The + target has to be close and there's a short timer during which neither party + should move. + chaoko99: + - rscadd: Adds a fully reusable backstabbing mechanic, used by butterfly knives + and switchblades. +2018-06-19: + Kurgis: + - tweak: Changed the brain loss Impedrezine inflicts to allow it to kill a person. + Miraviel: + - rscdel: 'Removed the time restriction on the following jobs: Explorer, Corpsman, + Deck Technician, and Scientist.' + - maptweak: Reorganized the kitchen cabinet and the crates in the Medical Storage + (the big bag of salt and the defibrillator are no longer blocking everything + else). + - maptweak: Removed the anaesthetics closet from the Medical Storage. + comma: + - tweak: XO now gets a box of spare headset keys instead of box of XO headsets + - rscadd: Bowman headsets can hold 3 keys instead of 2 + - rscadd: BO Bowman headsets hold 4 keys +2018-06-20: + BlueNexus: + - balance: Railguns have been rebalanced to fill the niche of an anti-armour or + sniper type role. + - balance: All railguns now suffer a substantial penalty when fired one-handed. + - balance: The basic railgun projectile no longer stuns, and does less damage. + - balance: All railguns which accept steel rods as ammunition now use the basic + projectile. + - balance: The TCC railgun's (available in the traitor menu) ammo capacity has been + reduced from 10 to 6. + - balance: Substantially increased firing delay on all semi-automatic coilguns and + railguns. + - balance: Holding or stowing a railgun now slows you down more. + Chinsky: + - rscadd: EVA skill now has mechanical effects. + - rscadd: Space slipping chance is affected by EVA skill. Bit higher at unskilled, + lesser with skill, no slipping at experienced. + - rscadd: Flooring when entering gravity from space is now not guaranteed at Basic + skill or more. Doesn't happen at Professional skill. + - rscadd: At Unskilled and Basic skill, jetpack can sometimes go wrong way. Not + that bad if you notice in time and have fuel to turn back. + - rscadd: At Professional skill you go faster when in space with a jetpack. Zooom. + - tweak: Skills now affect surgery. Trained or Experienced (depending on what you're + trying to do) skill is needed to ensure step won't fail. Professional skill + will offset various penalties (not proper optable, improvised tools etc) a bit. + Time of step is affected by Anatomy skill too. + - tweak: Some other skills help with some steps, e.g. Trained Forensics offsets + penalty for incisions, and Complex Devices skill is used instead for robotic + organ steps, with Electrician and Construction helping with simple limb repair + steps. + Chisnky: + - experiment: Melee weapons now have different attack cooldowns, generally with + smaller weapons being faster, bigger slower. Normal sized weapons are baseline, + having same attack cooldown as they did. + - experiment: Material weapons further tweak their attack cooldown based on material + used. + afterthought2: + - rscdel: The leadership skill has been removed. Check your characters' skill allocations. + - tweak: The instruct verb works like before, but no longer requires leadership + skill to use. + chaoko99: + - bugfix: You may no longer spam the skeleton as hard as you could before. + - bugfix: Wall painters no longer hit walls when used. + - bugfix: Energy axes will no longer anchor when dropped. + - bugfix: Candles will now last about 30 minutes. + - bugfix: Bucklers can now block any projectiles that aren't bullets, as suggested + intent in their code. + - rscdel: You may no longer worry about reagent contamination in a soft drink dispenser, + only unintended reagent amounts. + - rscadd: You may light an unlit candle with a lit candle that isn't in your hand. + - rscadd: Optimization pass on Geiger counters, and a few effect systems (Smoke + and sparks) + - rscadd: Underwear may now go into washing machines. Still can't be bloodied, but + at least you can do that now. For you weird people who roleplay showering! + - tweak: Rags may now clean more than just blood. More importantly, they show their + progress bar when cleaning. +2018-06-21: + Chinsky: + - rscadd: Close Combat now has ingame effects. Mostly chances to hit in melee. + - rscadd: Disarm chances now both affected by skills and anything tha affects melee + accuracy (being blind, being confused, blurry eyes, being in pain etc). + - rscadd: Most fancy grab moves (jointlocks, dislocations, tendons cutting) were + locked away behind Trained skill in CQC. + afterthought, sabiram: + - maptweak: The hydroponics station away site has been converted into an exoplanet + site. +2018-06-22: + Banditoz: + - tweak: Borgs have had their overall health doubled. + - tweak: Borgs also have had their armour plating component health doubled. + - tweak: Borgs are now more resistant to EMP, and lose less cell charge per EMP. + Cakey: + - maptweak: The Torch has been modified to use a wider variety of flooring types + and decals. + - maptweak: Added a door button to the XO's office. + - rscadd: Added plated catwalks, which can be constructed by placing monotiles on + catwalks. + Chinsky: + - rscadd: Botany skill now has ingame effects. + - rscadd: Without at least basic skill, you can screw up when planting or weeding + trays. You'll also be unable to recognize pests and weeds from useful things. + - rscadd: Exotic seeds (all random variations) need trained skill to avoid screw + ups like that. + - rscadd: Trained skill is also needed to handle xenobotany machines, otherwise + you'll be prone to wasting your samples really fast. + - rscadd: Experienced and professional levels of skill reduce degradation of samples + in xenobotany machines. + - experiment: Constantly fixing brain is no longer the pro strat anymore. + - rscadd: When fixing very damaged (broken level or more) organs in surgery, their + max health is lowered. + - rscadd: Brains get their health lowered /always/ if oxygenation is below survival + level (30%). Better fix cause of damage first, if you don't want to do permanent + damage. + - rscadd: Forensic skils now have ingame effects. Without at least basic skill, + you leave slightly more fingerprints on things, and you will leave prints when + trying to evidence bag things. + - rscdel: You need Trained skill to use evidence collection things and forensic + machines. At higher skill you work microscope faster. + - rscadd: Offstation antags (and traider) can now become ALIUMS! + - rscadd: Their bases have 'alien monolith' somewhere, which turns you into a humanoid + alien of unknown species. + - rscadd: Remember to implant the spawned translator implanter if you're planning + on talking to people. + afterthought2: + - rscadd: Having Basic finance gives the Appraise verb, which allows you to estimate + the value of items you are holding or have equipped (found in the IC tab). Higher + skill levels give more accurate assessments. + - tweak: The financial skill has a large effect on your starting cash. + - tweak: Higher financial skill gives you better deals from traders. + - rscadd: Using virology machines without sufficient virology skill may get you + or your friends infected. For curing purposes, "Trained" negates this effect, + but for doing splicing and mutations, "Experienced" or "Professional" may be + needed. + - rscadd: The printout from the virus analyzer may have missing or erroneous information + if you lack "Experienced" in virology. Quality of information improves with + skill. +2018-06-23: + afterthought2: + - bugfix: The microscope should now work properly again. + - bugfix: The magic missile wizard spell now works. It inflicts small burn damage + and a substantial disable. + - rscadd: Additional reports have been added to the Report Editor. +2018-06-24: + Chinsky: + - tweak: Handheld radios now have batteries and use power to transmit. You'll have + ~50 transmissions worth of power from one cell. When charge is getting low, + message might become garbled. Radios can be recharged in standard rechargers. + Heptagon49: + - bugfix: Screwdrivers no longer open airlocks upon attack. + Rowtree: + - tweak: Character creation faction/citizenship/religion/home system choices have + been updated. +2018-06-25: + Heptagon49: + - rscadd: You can now alt-click on pipes and disposal pipes to rotate them. + - bugfix: Unathi now have exploration voidsuits, and can now use the exploration + suit cycler. + Spookerton: + - tweak: Zombie abilities now tell you when they can't be used, why, and how long + is left on their cooldown, instead of failing silently. + - bugfix: Zombies can no longer consume or death_breath while incapacitated. + - balance: Zombies can only death_breath once per minute instead of once per second(!). + - tweak: Zombie consume now completes at the same rate as its cooldown, preventing + multiple consume actions being active at once. + - bugfix: Zombie consume no longer allows the user to be the target. + - balance: Zombification doesn't magically replace robot parts + - balance: Zombification organ health bonus is x3 instead of x5, but organ break + threshold is 75% instead of 50% + - balance: Zombie toxin urn reduced from 120u(!) to 10u. + - tweak: Zombie toxin now guarantees conversion for a 5u or greater dose. + - balance: Zombie toxin has a flat per process 20% chance to convert so long as + the current + historic amount of reagent in the victim (ie, the total dose at + one time) is more than 1u. + - balance: Zombie death_breath now only creates 2u instead of 5u. This means a victim + should usually take about 15 tox and have two 20% chances to be zombified if + a single zombie breathes on them. Zombies can work together to push a victim + over the 5u mark and instantly zombify them. + - balance: Zombies cannot re-zombify themselves for a free rejuv. + - tweak: observers cannot circumvent voting checks + afterthought2: + - tweak: Robotics surgery uses the Complex Devices skill now to compute delay. Hardsuit + removal uses the EVA skill. + - bugfix: Constantly escaping from grabs regardless of skill should be fixed. + sabiram: + - tweak: The standard bulkhead paint colour is now in the presets for the paint + gun. + - maptweak: Added a few small ruin sites to make exoplanets a little more detailed. + zaredman: + - rscadd: Added Advanced Trauma Kit and Advanced Burn Kit crates that can be ordered + from Cargo. 6 ATK or ABK for 30 points. + - rscadd: Adjusted cost of Medical Crate to 70 supply points to be more appropriate + when compared to other crates like Stability kit crates. +2018-06-26: + Cakey: + - maptweak: Following several reports of Torch crew being admitted to the infirmary + due to headaches the Torch has been refurbished once again to iron out any kinks + left over from the flooring construction work. + - imageadd: New floor sprites have been added. + - imageadd: New wall-mounted sprites have been added for fire alarms, air alarms, + APCs and intercomms + Chinsky: + - rscadd: Adds volcanic exoplanets. Very few plants and animals, but loads of minerals. + Don't walk in lava tho, use catwalks, Luke. + chaoko99: + - rscadd: Resprited some beekeeping items for the sake of consistency and ease of + use. +2018-06-27: + Chinsky: + - rscadd: Weapons skill now has mechanical effects, hide yo children hide yo wife. + - rscadd: Gist of it is if you don't have at least basic training, you're a hazard + to people. You can point and fire, but safety can be a bitch. + - rscadd: Speakig of safety, help intent doesn't prevent firing now. Safety is now + an explicit toggle, can switch it with Ctrl-Click on the gun or with a rightclick + verb. + - rscadd: Higher values of skill give some buffs to accuracy, and unlikely events + of jamming, also let you perform better when in pain. + - rscadd: Professional skill also has bonuses when using scoped rifles. + - rscadd: Weapons skil cost was changed too. Trained and higher are more expensive + now, with Experienced and Professional being as costly as medical skill. MAAs + start at Trained now to give them headstart. + Spookerton: + - tweak: adds insulated gloves to engineer lockers + afterthought2: + - tweak: Starting cash has been increased. Higher financial skill still gives substantially + more money. +2018-06-28: + Banditoz: + - rscadd: Saferooms can now be bolted and unbolted via the keycard authentication + device. + - rscadd: If there is an impending delamination, supermatter delamination, or escalation + to red alert, saferooms will unbolt. + - maptweak: The button to toggle the saferoom bolts have been moved inside of the + saferoom, and can now be operated by all. + Cakey: + - imageadd: Windows have been resprited. + - imageadd: Wall signs have been modified to fit the new walls. + CrimsonShrike: + - tweak: Moves crawling onto regular movement, fixes crawling while hurt. + Heptagon49: + - bugfix: After hearing about the capture of key operatives, Clan [NAME NOT FOUND] + decided to up the ante and improve the explosive power of their ninja suit's + deadman's switch to ensure that their agents either complete their mission or + die trying. Have fun. + sabiram: + - tweak: Catwalks now act as floors do with regards to clicking to move pulled objects + onto them. +2018-06-29: + Cakey: + - tweak: Replaced the fake lava on volcanic exoplanets with actual, real lava. + afterthought2: + - tweak: MMIs cannot be inserted into non-synthetic mobs. + - tweak: Flesh limbs cannot be attached to synthetic mobs. + - tweak: Robotic limb attachment now uses the devices skill. +2018-06-30: + Earthcrusher: + - tweak: Weaker mobs such as Artificers can now smash doors and windows, albeit + not as quickly as stronger mobs. +2018-07-01: + Chinsky: + - rscadd: Added anti-rad pouches to engineering. Also replaced detox injector engies + get in survival box with anti-rad one. + - rscdel: Removes mapped boomboxes from engineering. Nice try, but you'll have to + do with random spawnpoints as everyone. + - rscadd: Adds deployable SCG flags to Pathfinder lockers. They require Pathfinder + access to pop up. Don't do anything, just fluff. + Heptagon59: + - imageadd: Due to reported ill fits and high amounts of chaffing, SolGov has reissued + their line of uniforms, now with form-fitting features! EC Uniforms now have + unathi specific icons. + Hubblenaut: + - bugfix: The teleporters will no longer send people to nullspace when the beacon + does no longer exist. + sabiram: + - balance: Blink, teleport and ethereal jaunt can no longer be cast while incapacitated. + - tweak: Holographic items created by the holodeck can no longer be deconstructed. + - rscadd: Added the lodge exoplanet ruin site. + - tweak: Increased the cost of the hydrobase exoplanet ruin site. + - bugfix: Fixed incorrect accesses on various air alarms. +2018-07-13: + Alex6511: + - balance: The CoS Locker no longer contains a taser + - balance: The Brig Officer Locker no longer contains a small energy gun. + - tweak: The CoS locker now has a hand labeler in line with the Brig Officer. + Cakey: + - tweak: The Pathfinder job is now Ensign only + - rscadd: 'Belts have been overhauled to have holster slots on certain belts. These + holsters function the exact same way as uniform holsters do. imgadd: Certain + belts now show what their contents are on their icons.' + - rscadd: Added general and general holster belts, used by command, bridge officers, + and supply. Holds general office supplies, tablets, and stamps as well as other + various supply equipment. + - maptweak: Uniform holsters have been removed in favor of belt holsters, however + they can still be found within the loadout menu. + - tweak: Uniform holsters have been modified to use the same slot as webbings to + counter being able to carry two holstered weapons. + - rscadd: Plated catwalks can now be serviced using a crowbar to access anything + underneath. + Chinsky: + - rscadd: Piloting skill now has ingame effects. + - rscadd: Taking Torch's helm without at least Trained skill can make Torch go not + exactly where you want it to go. At Professional, passing meteor fields is less + painful. + - rscadd: Shuttles require different level of skill. Guppy is no-skill, Charon and + Aquila need at least Basic. For purposes of skill, pilot is whoever tells it + to move in console. + - rscadd: If pilot's skill is insufficient, you can end up in wrong place. Also + travel time is affected by skill. + - tweak: Drastically lowers amount of loot-having junk piles on garbge planets. + They have visual cues though so you don't need to try and rummage though literally + every pile. + - tweak: Xenoarch finds no longer yield sheets of steel and claim it's a mysterious + thing. They now mostly drop alium alloy, that has random material properties + each round. Any material weapons you find will be made of it too. + - rscadd: Garbage planets now have radiation sources scattered around. + CrimsonShrike: + - tweak: Roboticist now has access to their own maintenance airlock again. + Heptagon49: + - bugfix: Due to pending discrimination lawsuits, Nanotrasen has upgraded the cryosleepers + onboard the SEV Torch with automatic wheelchair dispensers. Disabled characters + now spawn with wheelchairs. + Miraviel: + - rscadd: Added the "Detach IV Drip" verb under the Object tab. + - tweak: Left-clicking an attached drip will now first detach the patient and only + then it will remove the beaker. Drag and drop still works! + - tweak: The Hot Foods Display machine now accepts and dispenses utensils. + - imageadd: IV drips now have a slightly bigger container sprite and a wider warning + light, for better visibility. + - imageadd: Advanced first-aid kits are now purple in hands too, as opposed to being + red. + Orelbon: + - rscadd: The self-destruct will now begin detonating explosions randomly on the + ship when it reaches its cutoff point. + Sbotkin: + - tweak: Emergency Response Team officially is a part of the SCG Fleet now. + Spookerton: + - bugfix: Paper bundles bundle correctly. + - tweak: Carbon copy paper is now default named "sheet of paper" instead of "paper", + the same as regular paper. + TheWelp: + - rscadd: Adds the ability for holy water to deconvert god cultists and the ability + for the null rod to stop phenomenas (by hitting an altar) + - tweak: Nerfs like 90% of deity items and phenomena costs. This may be heavy handed + or too much. Feel free to complain. + Zuhayr: + - tweak: The Pull Punches verb has been renamed to Switch Stance. + - tweak: Nabber stance switching behavior now replaces pulling punches for them. + - tweak: Nabber nabbing is now achieved by trying to grab someone rather than a + verb. + afterthought2: + - tweak: Almost all maint airlocks now require maint access. + - tweak: Trainee crewman alt-titles have been replaced by separate jobs. + chaoko99: + - rscadd: A ping button for checking your ping has been added to the "file" tab. + sabiram: + - bugfix: Fixes being unable to ignore OOC. + - balance: Machinery may no longer be controlled by the staff of animation; its + maximum charges have been reduced from 10 to 5, and its recharge time increased. + - balance: Wizard familiar transform spell recharge time increased to two minutes + from ten seconds. + - balance: Wizard familiars can no longer transform while incapacitated. + - balance: A percentage of damage taken in a familiar animal form is now mirrored + to the familiar's human form. + - bugfix: Simple animals controlled by a client can once again damage humans. Don't + kick that suspicious goat. + - rscadd: Added functionality for edged weapons to cut wires after a short delay. + Any conductive objects will also shock you! + - tweak: At the same time, clicking wires with ordinary conductive objects will + no longer shock you. + - tweak: Reconfigured access requirements for tactical equipment in the loadout. + - tweak: Sol personnel may no longer select green or tan plate carriers, UBACs or + pouches. + - tweak: Expeditionary Corps personnel additionally may no longer select navy blue + equipment. + - tweak: The King of Goats group encounter has been updated. + - rscadd: The King of Goats can now imbue his attacks with elemental damage for + a short time. + - rscadd: The King of Goats can now rarely knock over its enemies with its attack. + - tweak: The King of Goats will now only yield the golden fleece to those who slay + it in its final form. + zaredman: + - rscadd: Added spare penlights and a linen bin to the lower medical storage. + - rscadd: Expanded medical locker room to fit a washing machine and table with recharger. + - rscadd: Some adjustments to maint immediately by Medical's locker room. +2018-07-14: + Cakey: + - tweak: Dionae may no longer fill in as research director among Nanotrasen staff, + as the board of directors felt they weren't evil enough to push the Nanotrasen + agenda. + - maptweak: Added the volleyball court and cafe to the holodeck. + ChaosAlpha: + - tweak: Engineering robots can now collect cables regardless of the currently selected + color of their synthesizer + - tweak: Robots can now pull-drag (by clicking on an adjacent turf while pulling + something) + Spookerton: + - bugfix: Visible & audible messages should no longer stack an extra prefix for + every connected ghost +2018-07-15: + PsiOmegaDelta: + - rscadd: It is now possible to adjust the playspeed of boomboxes using a screwdriver. + sabiram: + - maptweak: Added some lights to dark spots in hallways around research, chemistry + and the D3 ladders, the main hallway through D2 maint from the stairs/elevator, + and the medbay. + - maptweak: 'The greedy NT guards are now only provided with one chair for their + window desk. imgadd: Changed the intercom icon to be more in line with what + it used to be. Dark frame, green console.' +2018-07-16: + Heptagon49: + - bugfix: Dionaea can now regrow limbs again. + sabiram: + - tweak: Changed the changelog header and credits. +2018-07-17: + Cakey: + - rscadd: The shuttle pilot role has been moved to Exploration. + - rscadd: The prospector role has been moved to Supply. + - rscadd: Two new pilot helmets have been added to the game, one generic and one + NT variation (Sprited by Chinsky). + CrimsonShrike: + - tweak: Implant surgery is now possible for robotic limbs. +2018-07-18: + Earthcrusher: + - rscadd: With a bit of research into Data and Illegal technologies, the Roboticist + can now print an uncertified robot module. What could it possibly do? + TheWelp: + - rscadd: Spells now require you to not be incapacitated (handcuffed, stunned, etc). + afterthought2: + - rscadd: Antag skills are now chosen in-game. Off-station antags get basic in everything + and can select 4 skills at trained, 2 at expert, and 1 at master. On-station + antags get their selection from jobs, and in addition get 3 at trained and 1 + at expert. (malf is unchanged). Once the skill selection is submitted, it can't + be undone without admin intervention. + - tweak: The Show Own Skills verb looks a little different now. Antags can use it + to select skills. + za_redman: + - rscadd: Fixed incorrect req_access for E-Arm lockdown shutter. + - rscdel: Removed biohazard locker in D1/Medical Locker room. The multi-suit locker + in the basement, the two in maint, and the one in viro remain. + - rscadd: Added additional Medical Contractor locker in D1/Medical Locker room. + - rscadd: Adjustments to Contractor Locker contents to bring them more in line with + Corpsman Lockers. +2018-07-19: + CrimsonShrike: + - tweak: Swabbing people wearing gloves should now attempt to swab said gloves instead + of swabbing their evidence-free hands + - tweak: Forensics locker will once again contain a security belt for those who + feel the need of carrying their gear. + - tweak: Restrained, unconscious or otherwise restricted suspects can no longer + keep avoiding swabbing + Ithalan: + - bugfix: PDA medical scanner now works on body bags and stasis bags like the regular + health analyzer, and uses user medicine skill level + - rscadd: Medical belts can now also hold body bags, stasis bag and emergency medical + pouches + Spookerton: + - tweak: SCGR no longer has an unfitting alt title that implies they do something + they don't. + - tweak: SCGR can no longer download and use power RCON. + Zuhayr: + - rscadd: Diona nymph and diona gestalt eyes glow in the dark. + - rscadd: Diona nymphs can no longer grow into adults by themselves. Instead, they + need to merge with two other nymphs, then call a vote with Call Gestalt Vote. + - rscadd: Diona nymphs are now capable of headbutting seeds out of seed vendors, + planting them, harvesting them, removing dead plants, eating pests and refilling + water. Chirp. + - rscadd: Diona nymphs now have a proper UI. + sabiram: + - rscadd: Plastic flaps can now be constructed with plastic sheets. + - rscadd: Plastic flaps can now be unsecured with a wrench, and then destroyed with + a screwdriver. Use a wrench to re-bolt them. + za_redman: + - rscadd: Gives Chef of Security access to the Hangar. + - rscadd: Adds exit button to hangar door. +2018-07-20: + Heptagon49: + - rscadd: A short blurb on the current alert level now appears on the title screen. + sabiram: + - rscadd: Added spy v. spy (autotraitors and renegades) to game mode selection and + secret. + - tweak: Law enforcement (security officer, warden, HoS) and the Captain may no + longer be renegades at round start. + - tweak: Reduced the force of the magnum pistol's melee attack from 14 to 9. +2018-07-21: + sabiram: + - tweak: Command rig suit helmet cameras are now found on the Command network. + - tweak: Mining rig suit helmet cameras are now found on the Supply network. + zaredman: + - rscadd: Introduces Office of Civil Investigation and Enforcement agents to replace + Colonial Marshals. + - rscdel: Removes all references to Colonial Marshals and replaces it with the Office + of Civil Investigation and Enforcement. +2018-07-22: + Devildabeast: + - rscadd: Adds optics for the Hephaestus Alt. head. + Unknown: + - rscadd: ' Removes three of the four monkey cube boxes in virology and replaces + them with a stok cube box, neaera, and farwa cube box.' + sabiram: + - maptweak: Those with shuttle helm access may no longer access the supply office. +2018-07-23: + Ithalan: + - bugfix: Map function in crew monitor program no longer craps out after drawing + first tracked crew member + - bugfix: Suit sensor jammer methods have been updated to be useful for new medical + system + - bugfix: Synthetic hearts and species without a cardiovascular system no longer + generate misleading pulse readings on the crew monitor + - rscadd: crew monitor program icons now change to indicate if there is a crew member + in medical distress, based on pulse and blood oxygenation + - tweak: layout of crew monitor program has been tidied up a bit so that each datatype + aligns nicely. +2018-07-24: + Cakey: + - tweak: EC and Fleet crew may now fill in as shuttle pilots. + - maptweak: Added a pilots locker within the expedition prep room. Pilots now have + access to both supply and the expedition prep room. + - tweak: Added a pilot-specific access type. + CrimsonShrike: + - rscadd: Forensics skill now allows for the detection of possible evidence on examination. + - tweak: Forensics skill is now cheaper at higher levels. + zaredman: + - rscdel: Removes mention of Colonial Marshals in holowarrants and replaces it with + OCIE; format change. +2018-07-25: + Chinsky: + - tweak: Telecomms relays power usage is upper /considerably/ when used off-ship. + Expect to drain Charon in 10 minutes when you switch it on. + - tweak: Having Trained or above Close Combat skill gives bonus to parry chance + with weapons (even ones that don't parry normally). + - tweak: Melee accuracy is now affected by size of the weapon - smaller than 'normal + sized' weapons are more accurate, bigger are less accurate. Some weapons have + individual bonuses/penalties (e.g. swords are bit more accurate for their size, + toolboxes are less) + - tweak: Material weapons now get damaged on parry much like when attacking, and + can shatter depending on material. + afterthought2: + - tweak: Check your skill loadout; it may have been reset! + - tweak: Skills outside your job and not in the general, organizational, or service + categories (minus pilot) are no longer selectable above "Trained" level. + - tweak: Some head roles had skill point allocations reduced. Engineers' skill points + have been brought in line with contractors (increased). Brig Officers' starting + skills brought in line with MaA. +2018-07-27: + Cakey: + - tweak: Senior Engineers, Deck Officers and Brig Officers may no longer be E5s. + afterthought2: + - rscadd: Constructing things with stacks of material now uses the construction + skill. Higher skill is needed to use more advanced materials or to make more + elaborate items. + - tweak: Construction time is modified by construction skill. + sick trigger: + - rscadd: Diona can now 'Jump-to-next-nymph' to cycle between their nymphs after + splitting. +2018-07-28: + Devildabeast: + - tweak: Shuttle Pilots can now be rank E-6 as Fleet. + - tweak: Shuttle Pilots now have EVA access. + - maptweak: The Shuttle Pilot can now access the Ready Room. + - tweak: Shuttle Pilots can now select the pilot pin in the loadout. They can also + now select the EC cap if they're EC. + - bugfix: The EC Shuttle Pilot no longer spawns with service uniform. + - tweak: The Shuttle Pilot now gets a regular pilot headset and a bowman headset + in their locker. + - tweak: Shuttle Pilot is now defined as a SolGov role. +2018-07-29: + CrimsonShrike: + - tweak: APC lights now brighter. + Spookerton: + - tweak: maintenance drone laws tweaked to read more goodly. + - tweak: mdrone laws tweaked to not imply that mdrones are intelligent, because + they're not. + - tweak: mdrone laws include not interfering with people while trying to do your + job, roomba. +2018-07-30: + Devildabeast: + - bugfix: The SEV Torch's Heads have had ventilation introduced to the stalls in + order to prevent unwanted suffocation. +2018-08-01: + Devildabeast: + - tweak: Corpsman now has the alt-title of "Nursing Assistant" instead of "Nurse". + afterthought2: + - bugfix: APC, fire alarm, and air alarm frames should once again show up as buildable. + - tweak: Faction, citizenship, and home system character creation choices have been + updated. + zaredman: + - rscadd: Added a MIA (Missing in Action) option to crewmember status choices. +2018-08-02: + Cakey: + - maptweak: The brig has been moved to deck one. Deck three has been adjusted to + be further enforce it being the habitation deck. + - maptweak: Added the Commissary, an on-ship store run by supply and service crew. + - maptweak: Moved the pathfinder's office to deck four. + - maptweak: Moved the bluespace drive to deck two. + - maptweak: Moved the observation bubble, diplomatic quarters and vacant office + to deck three. + Devildabeast: + - rscadd: Adds a PCRC suit, a more formal variation of the PCRC uniform, to the + loadout under Corporate Uniforms. + Hubblenaut: + - tweak: Brig cell timers will notify Security over Sec HUDs when expiring. + zaredman: + - rscdel: Replaces double doors to Xenobio, Viro, D2 Maint, D3 Old Brig, Conference + Room, Engineering hard storage, and NT Labs with normal doors. +2018-08-03: + Hubblenaut: + - tweak: All Heads are now able to authorize warrants using the holowarrant projector + regardless of their Security access. +2018-08-04: + sabiram: + - tweak: The mercenary shuttle is now less easily vented by destroying a single + r-window. + - bugfix: Hardsuit rig modules now check properly access for those attempting to + use them. +2018-08-05: + Hubblenaut: + - bugfix: Bridge Officers can once again access their lockers. + - bugfix: SCGR can once again access the bridge. + zaredman: + - rscadd: Allows IPC and Skrell to be Brig Officer. +2018-08-06: + Cakey: + - maptweak: Bearcat has been tweaked slightly to allow for better repair opportunities. +2018-08-07: + Devildabeast: + - maptweak: Removes a catwalk from the Utility Down in the deck 1 substation room. + - maptweak: Adds scrubbers to the toilet stalls on deck 3 to prevent CO2 buildup. + - rscadd: Adds a new branch known as "SolGov Employee"; the SolGov Representative + and OCIE Agent have been moved under it as ranks. + - tweak: SolGov loadout items, including SolGov berets, awards, and hat, can now + be worn by all SolGov-affiliated branches.. + - tweak: Updates the sprites for the Hephaestus Alt. head optics. + Zuhayr: + - rscadd: Added sushi and sashimi. Slice fish or meat into strips, then use them + on rice. Also accepts egg and tofu. + nearlyNon: + - maptweak: Moves notice board between main mess hall doors, removing the window. + RIP. + - maptweak: Adds a holopad to the holodeck, so the AI can hang out there. + - maptweak: Expands holodeck door to be two tiles wide, to prevent bottlenecking. + - maptweak: Adds a newscaster to the vacant office. +2018-08-08: + Devildabeast: + - bugfix: Allows FT to be contractor again for real this time. + - bugfix: Allows FT to be played as Contractor again. + - bugfix: SCGR can now wear most loadout items again. + Nearlynon: + - bugfix: Fixed missing pipes + wires in holodeck. + - maptweak: Adds 2 paperbins to deck 3 in the mess and lounge respectively. + nearlyNon: + - rscadd: Eight balls, able to be bought from the vending machine in the mess. Ported + from TG. "Will the CMO be useful today?" "Not likely." + - rscadd: Add bells; can be made with any material. Ring by clicking with intents + other than grab; grab picks up. Shatters if you hit someone with it! + - maptweak: Distribute bells throughout desks. + sabiram: + - tweak: The Booze-O-Mat menu has been reordered; vessels at the top, followed by + bottles, followed by ready drinks, followed by mixers, and ending with glass + accessories. + - tweak: Added a bottle of mint oil to the Booze-O-Mat for mixing. +2018-08-09: + Flatty: + - rscadd: You can now change icon scaling method in the "Icon" menu on top left! + Zuhayr: + - rscadd: Skrell now appear neutrally gendered to non-Skrell. Use the headtail length + descriptor to specify your secret squid gender. + - rscadd: Vox now have neck markings to show importance to other vox. +2018-08-10: + TheWelp: + - rscadd: Adds the Lost Souls, the remnants of souls sucked into the Starlight Gateway + (for future deity mode). + - rscadd: Added the ability for god cultists (and lost souls) to be able to hear + through the pylons like the deity can. + nearlyNon: + - bugfix: ALL MATERIAL WEAPONS ARE NO LONGER INSANELY FRAGILE. +2018-08-11: + Devildabeast: + - rscadd: Adds Observatory and Field Operations patches to the loadout. + nearlyNon: + - maptweak: Replace the crowbars in medical storage with prybars, which makes more + sense and was requested in the Little Things thread. + - tweak: Added multipens to loadout. + - bugfix: Saves diona from their impending death in holodecks & when preparing to + go to the ship as off-vessel antags. + - bugfix: Fixed grammar on diona nodes. "You plant the diona notes" no more. + sabiram: + - rscadd: Boomboxes now have adjustable volume. + - tweak: Boomboxes can no longer be placed in backpacks. + - tweak: Boomboxes now have a chance to break each time they're turned on. +2018-08-12: + Cajoes: + - rscadd: Added flood lamps (portable) to supply offerings. +2018-08-13: + Hubblenaut: + - bugfix: The diffuser bypass mode on the shield generator will now work on already + active diffusers. + - bugfix: Fixes the shield generator's atmosphere containment mode. + PsiOmegaDelta: + - rscadd: Admins can now alt-click possessed mobs to efficiently kill them. + afterthought2: + - rscadd: The SM monitor readings will fluctuate with some errors at Trained in + Engines skill and below (max 40%, 20%, and 5% at Untrained, Basic, and Trained). + At master they'll be like previously. + - rscadd: Turning on the emitter will recompute its efficiency (i.e. power) to a + lower random value, depending on skill. + - rscadd: Examining the SM at Expert skill will give some information about its + integrity. At Master, it will give a guesstimate for the EER. +2018-08-14: + sabiram: + - rscadd: The shaker now really acts like a shaker, and must be interacted with + to mix its contents (click it in hand). + - maptweak: The bar, mess hall, captain's mess, and cold storage rooms have been + redesigned. + - tweak: Iced tea is no longer sweet. + - tweak: Added sweet tea. 3 measures of iced tea + 1 measure of sugar. +2018-08-15: + Sbotkin: + - tweak: Allows shredding of fingerprint cards. + Zuhayr: + - rscadd: Numerous new ores spawn on the asteroid. They can be compressed into bricks + and ground up for reagents. + - tweak: The ore processor has been rewritten and will happily eat anything containing + metal or other substances, and can then fart them out as sheets. + - rscadd: All material sheets now fetch a price from the supply drone, not just + plat and phoron. + - tweak: As a result, the prices of all materials have gone up to a minimum of their + resale cost. Steel is 60 credits now, for example. + - tweak: The recipe of plasteel is now steel + platinum (put the steel back through + the unloader) and the recipe for osmium-carbide plasteel is plasteel + osmium. + afterthought2: + - rscadd: Hacking without the electrical skill is harder now. + - rscadd: If you are unskilled in electrical, hacking will randomize the wire positions + (not meanings) each time you open the screen. If you are basic, you'll get some + possible duplicate colors/omitted colors, with smaller probabilities. + - rscadd: If you pulse a wire below trained skill, you have (progressively smaller) + chances of pulsing the wrong wire. If you are untrained, you may randomize wire + positions for everyone else trying to hack the thing. + - rscadd: If you cut/mend wires below trained skill, you may cut/mend some extra + wires by accident. + - rscadd: If you try to place a remote signaler with low skill (trained or lower), + you might place it on the wrong wire, and then have a hard time removing it. + - rscadd: A new "Examine" option has been added to the hacking menu. Below experienced + it doesn't do much. On experienced one or two wires will be identifiable on + examine, while at master most will be. Less effective for "secure" objects with + randomized wiring. +2018-08-16: + IsdatAfamas: + - rscadd: Added an away site. It has a few slots open to join as a survivor. + - rscadd: See https://forums.baystation12.net/threads/ctis-research-ship-missing.6790/ + for lore info. +2018-08-17: + Cajoes: + - tweak: flood lamps now start in the off position + - tweak: green ink pens are now greener + - tweak: washing machines now more in line with graphic style of server + - tweak: toys and plants now use less unused animation frames, reducing overhead +2018-08-18: + IsdatAfamas: + - maptweak: Added polarized windows to robotics. + - bugfix: CTI ship should spawn correctly now. + Zuhayr: + - rscadd: Added Tritonians, an uwhitelisted human subspecies. +2018-08-19: + Devildabeast: + - tweak: All Marine Corps uniforms and items have been renamed to reflect the SCG + Army, removing all references of the Marines. + - rscadd: Adds an array of Army outfits, spawnable by admins. + - tweak: The Marine (now Army) PT uniform is now black instead of green. +2018-08-20: + IsdatAfamas: + - bugfix: Various fixes implemented for SRV Verne. Overall should be far less deadly + as an away mission. + nearlyNon: + - tweak: You can now select a bible from the loadout. + sick trigger: + - rscadd: Ghosts can now 'Scan-target' to analyse the thing they're following. +2018-08-22: + Cajoes: + - rscadd: Napalm and Napalm B recipes. Sticky burny goo. + - tweak: relabeled old napalm recipe to phlogiston. Makes heat. And little else. + Same as old napalm. + Cakey: + - rscdel: Removed Tajarans from the server. + Hubblenaut: + - bugfix: Fixes cable coils spawning in tool belts having old vibrant color. + - tweak: Tool belt cable colors are now completely random. + IsdatAfamas: + - bugfix: Some more CTI ship fixes. + Sbotkin: + - tweak: Allows shredding of fingerprint cards. + TheWelp: + - rscadd: 'Imports TG''s circuit updates: ICs now requires power to operate. IC + printer is now hand-held and can copy & print assemblies fully.' + - rscadd: Adds new ICs. + Zuhayr: + - rscadd: Numerous new ores spawn on the asteroid. They can be compressed into bricks + and ground up for reagents. + - tweak: The ore processor has been rewritten and will happily eat anything containing + metal or other substances, and can then fart them out as sheets. + - rscadd: All material sheets now fetch a price from the supply drone, not just + plat and phoron. + - tweak: As a result, the prices of all materials have gone up to a minimum of their + resale cost. Steel is 60 credits now, for example. + - tweak: The recipe of plasteel is now steel + platinum (put the steel back through + the unloader) and the recipe for osmium-carbide plasteel is plasteel + osmium. + afterthought2: + - rscadd: Hacking without the electrical skill is harder now. + - rscadd: If you are unskilled in electrical, hacking will randomize the wire positions + (not meanings) each time you open the screen. If you are basic, you'll get some + possible duplicate colors/omitted colors, with smaller probabilities. + - rscadd: If you pulse a wire below trained skill, you have (progressively smaller) + chances of pulsing the wrong wire. If you are untrained, you may randomize wire + positions for everyone else trying to hack the thing. + - rscadd: If you cut/mend wires below trained skill, you may cut/mend some extra + wires by accident. + - rscadd: If you try to place a remote signaler with low skill (trained or lower), + you might place it on the wrong wire, and then have a hard time removing it. + - rscadd: A new "Examine" option has been added to the hacking menu. Below experienced + it doesn't do much. On experienced one or two wires will be identifiable on + examine, while at master most will be. Less effective for "secure" objects with + randomized wiring. + nearlyNon: + - rscadd: Inducers. Make them in science. They're a TGstation item, you can charge + anything that uses a battery with them. Almost. Screwdriver to remove and replace + its battery. + - rscadd: Cyborg integrated version of the above, using the borg's internal battery, + and a failsafe on it. + - rscadd: IPCs and FBPs are now adversely affected by ion storms. They will be confused + and have blurry vision as their system partially resets to remove ionospheric + corruption. To avoid this, hide out in a saferoom or shuttle, or the dorms or + such. + - rscadd: Prescription science goggles can now be selected from loadout. +2018-08-23: + CrimsonShrike: + - bugfix: Oxygen regenerators should no longer get stuck trying to get or output + gas. +2018-08-24: + Chinsky: + - tweak: CO2 is no longer poisonous. Just non-breathable. Should make Bearcat a + walk in the park. + - tweak: Added CO, which /is/ poisonous. + - tweak: PACMANs that run on plasma now produce some CO, around a mole per 40 seconds, + so make sure you open the window (or turn on scrubbers) before using. + SierraKomodo: + - tweak: Makes NT Security Guard HUD icons purple instead of red. +2018-08-25: + Cajoes: + - rscadd: added supply crate for wrapping paper + - tweak: toned down the toner and floodlamp crates + Textor: + - rscadd: Sleepers, cryo tubes, full body scanners, full body scanner control consoles, + and operating tables can now be constructed. + - rscadd: The aforementioned machine boards are now researchable and printable at + the protolathe. + - rscadd: Added the ability to drag-and-drop players to cryo pods. + Zuhayr: + - rscadd: The General character generation tab has been split between Background + and Physical. + - rscadd: The faction/species/homeworld backend has been completely rewritten. + - tweak: Check your species, faction and homeworld settings as well as the new 'culture' + option under Background. +2018-08-26: + Heptagon49: + - rscadd: You can now rotate unwrenched computer frames via context menu or alt-click. + - imageadd: Added directional icons for computer frames. + nearlyNonexistent: + - rscadd: Two new IPC monitor screens, one an obvious parody of the original Doom, + the other Tetris. +2018-08-28: + Cakey: + - rscadd: Added the Secure Energy Revolver to the CO and XO's closets, replacing + their respective energy guns. + CrimsonShrike: + - rscadd: Oxygen regenerator board added to circuit printer. + nearlyNonexistent: + - tweak: Chameleon kits no longer shapeshift back to normal (and psychadelic) when + EMPed. +2018-08-29: + SierraKomodo: + - rscdel: Removed Floorlength Braid hairstyle + nearlyNonexistent: + - tweak: Press drone can now take photos. + - tweak: Cameras stay off after taking a photo. + - tweak: Photo albums can be taken from the loadout, along with a roll of photo + tape. +2018-08-30: + Chinsky: + - tweak: Sensor console now grants much further viewrange on the map. + Textor: + - rscadd: You can now build light switches and window tint switches with a steel + sheet. + - rscadd: 'To build: use a screwdriver on the frame. You can also use a screwdriver + to disassemble them.' + - bugfix: Fixed issue with converting new-style reinforced windows to electrochromatic + windows. You can use a cable coil on them to convert them properly now. + - tweak: Modified how window tint switches interact with multitools. You can now + set the window ID with the multitool. You can also set the window ID by using + a multitool on the electrochromatic window. +2018-08-31: + Miraviel: + - rscadd: Added 10 more targeted emotes! Use them as *salute fullname. + Textor: + - bugfix: GAS have now been adequately trained by Xynergy on the proper use of stairs. + They will no longer hover above them, afraid to go down. + - bugfix: GAS no longer have their tracheae rupture in low pressure environments. +2018-09-01: + Banditoz: + - tweak: Light frames can now be placed in the actor's area. + Cakey: + - tweak: APLU circuits can now be printed by default. + MO_oNyMan: + - maptweak: Added missing cameras to forensics office, evidence storage and briefing + room + - maptweak: Added a recharger on d4 security checkpoint + - maptweak: Forensic technician can now access morgue from the front door + Textor: + - bugfix: The supermatter monitor no longer cares about delaminating supermatter + crystals not on board the Torch. Those other crystals must suffer silently, + now. + nearlyNonexistent: + - rscadd: Ports Polaris's synthetic eye color changing. IPC, synthetic human, and + Adherent eyes are now RGB. Properly covered by display monitors too. + sabiram: + - tweak: People wearing most hardsuits are now able to be handcuffed. +2018-09-03: + CrimsonShrike: + - bugfix: Fixes pulling circuit checking for its own position and not its holders + Sbotkin: + - maptweak: Replaces strategic reserve of laptops in the infirmary with consoles + and telescreens, where needed. + afterthought2: + - rscadd: Makes exterior airlock assemblies buildable (need Basic skill). + sabiram: + - tweak: The force authorisation and docking management programs now must be run + on suitably powerful equipment, namely a laptop or a console. + - tweak: Increased tech cost of the teleporter console circuitry. + - maptweak: Moved research and development circuit boards into secure storage. + - maptweak: Added more APC and airlock circuits to tech storage. +2018-09-04: + Chinsky: + - rscadd: 'Added a new event: Maintenance Drones Uprising.' + - rscadd: It spawns hostile versions of maint drones in maintenance. They will not + attack anyone they perceive as synth. + CrimsonShrike: + - tweak: Medical circuits now largely inform of severity instead of exposing internal + values. Adapted medical integrated circuits to brainmend. + nearlyNonexistent: + - maptweak: Security now has prybars instead of crowbars. + - rscadd: You can now flip blindfolds up, and start with one from your loadout. + Tape ones can't be flipped as they're not made of cloth. Blindfolds from loadout + are colorizable. + - rscadd: One new AI hologram. + - tweak: Clippy is no longer malf only. +2018-09-05: + nearlyNonexistent: + - rscadd: 'New items intended for antags to steal; several secret documents that + spawn in the SCGR''s office, the conference room, and the NTL''s office. Gotta + collect them all! (Disclaimer: only 3/6 spawn in a game.)' +2018-09-06: + nearlyNonexistent: + - tweak: Water now lasts a minute on the ground, to make it more useful to have + wet floor signs. For reference, space lube is 10 minutes, and the cult spell + is 6 minutes. +2018-09-07: + Textor44: + - bugfix: Surgeons can no longer create magical floating limbs by attaching hands + and feet to a patient lacking an arm or leg. +2018-09-08: + Textor44: + - rscadd: Adds the savage hunter (male and female) clothing for Unathi civilians + in the loadout under xeno wear. +2018-09-09: + FTangSteve: + - rscadd: simple mobs now take different damage from different unarmed attacks + Textor: + - tweak: Staff now take tickets when they hit the "PM" button in the ticket panel. + - rscadd: Adds the ability for admins to change the end credits slightly. + Textor44: + - bugfix: Catwalks can now be cleaned by mops and soap by simply clicking on them. + Janitors everywhere rejoice at having to do less work. + - tweak: Soap now takes a longer time than a mop to scrub floors. Janitors everywhere + grumble at having to take longer at doing their job. + - tweak: Soap no longer can be used to knock people over by dragging them onto it. + Janitors everywhere are sad they can no longer prank people as easily. +2018-09-10: + CrimsonShrike: + - tweak: Signallers no longer give visible or audible feedback that they received + data. There's circuits for that and frankly we were all thinking of killing + the roboticist. + - rscadd: New filter circuits, so that you can discriminate properly + - bugfix: Fixed hypoinjector circuit not injecting + Zuhayr: + - rscadd: Added the ability to carve graffiti into some walls and floors with sharp + objects like screwdrivers. + - rscadd: Being a slog now has long-term consequences. +2018-09-11: + Cajoes: + - rscadd: Some new cargo items, boxed snack foods for refilling vendors, etc. (canned + bread does not go into Galley-!) + - rscadd: Added new cargo order tabs and orderable items. Galley, Custodial, Exploration, + Non-Essentials, etc. + - tweak: Rearranged existing cargo tab contents to something resembling logic. Floor + tiles go into Flooring food supplies to the galley, costumes and hats into Non-essentials, + etc + - rscdel: 'Removed the Tabs: Reagents, Miscellaneous and Hospitality tabs as they + ended up empty once the re-ordering was complete and no longer served a function.' + - rscdel: Crate of Boxes, Crate of Empty Reagent Cartridges, Ripley APLU Circuitboard + Crate + Chinsky: + - bugfix: Fixes microscope always treating partial prints as complete. End of golden + age of forensics. + - rscadd: New forensic evidence type - trace DNA. Left on unfinished food, glasses + people drank from, cig butts and gum wads. Collected with swab kits, investigated + in DNA scanner. + - rscadd: Grabbing, pulling, and hitting people unarmed now will wrinkle their uniform/suit + and leave fingerprints. Usual protections against prints apply there. + CrimsonShrike: + - bugfix: Demultiplexers should have data set correctly now. + ParadoxSpace: + - rscadd: Tritonians now handle water better. They still cannot breathe it, so be + careful, okay? +2018-09-19: + Chinsky: + - rscadd: Added ANFO, a fertilizer+fuel explosive. Mix any of fertilizers (EZ-nutriment, + Left 4 Zed or Robust Harvest) with welder fuel to make it. Add aluminium for + more oomph if you can get it. + - rscadd: To actually make it boom, you need ANOTHER explosion first. A weak explosion + will pretty reliably activate <60u, strong <120u, devastating for more. If it + wasn't strong enough, it can still trigger part of reagent. + - rscadd: Due to related changes, any container holding welder fuel can now explode + if caught in an explosion, though don't expect much oomph. + - rscadd: Added ability to manipulate tape recorder tapes. + - rscadd: User wirecutter to cut tape, use tape on tape to join them. + - rscadd: You can get loose tape out by clicking tape inhand. Join them to put back. + Master forensics techs will be able to tell if it was tampered with. + - rscadd: Tape recorder now have a single wire that starts playback when pulsed. + - rscadd: Adds vinegar reagent. Can be made from ethanol or apply juice by applying + universal enzyme as catalyst. + - bugfix: Adds mayo. Can be made from egg yolk and vinegar or lemon juice. + - tweak: Adds alternative soy sauce recipe. Now it can be made with 5u Soy Milk + + 5u Vinegar + CrimsonShrike: + - rscadd: 'New instruments are now available through supply. rscdelete: Removed + old piano and old violin,' + Zuhayr: + - rscdel: Removed NanoTrasen rank. You can use the contractor rank to get access + to science roles now. Play whatever company you like. + - tweak: The Torch has unionized under the Torch LLC Corporate Union. You can get + a union card in loadout and the Corporate Liaison is now the Workplace Liaison, + with Corporate Liaison and Union Representative available as alt titles. Worker's + rights! + sabiram: + - rscadd: Added missiles for admins to throw at the ship. +2018-09-22: + Aticus: + - imageadd: Adds a new, female-centric hair style for Unathi. The Frills Strike + Back. + Neon1ight: + - rscadd: Added the Xenolife Technician job. It is a crew research position, allowing + EC players to be part of the research department. ICly, it specializes in xenobiology/xenobotany. + Zuhayr: + - rscadd: Education is now a selection in your background tab. Jobs are restricted + to certain minimum educations. You will likely need to change your background + tabs for all characters who work jobs other than Passenger. + - rscadd: Doctorates and medical degrees in the education system modify your record + and ID name to 'Dr. Foo, MD' or 'Dr. Foo, Phd'. + - tweak: Skrell will no longer present as hive minds on their ID and crew records. + - rscadd: Mops can now mop up shallow fluids. + - tweak: Hydrogen fires should no longer result in biblical floods. + - tweak: Floods should now clean up filth decals properly. +2018-09-24: + Cajoes & ChaosAlpha: + - rscadd: mobs now tip over when slipping or resting + Chinsky: + - rscadd: Can now put items into forensic microscope for scan, instead of using + tools on it first. Clicking on microscope with evidence bag puts item inside + too. + - rscdel: Removed alium-turning monolith from trader base. + CrimsonShrike: + - rscadd: Adds some more feedback to augments. + Miraviel: + - rscadd: Added a normal headset to the pilot locker and bowman headsets to corpsman, + medical contractor, physician lockers. + Zuhayr: + - tweak: Graffiti now requires you to be on help intent. +2018-09-26: + Zuhayr: + - tweak: Noticeboards can be built out of wood, dismantled with a wrench, and rearranged + with a screwdriver. + - rscadd: Papers on noticeboards will persist round to round. + - rscadd: Sticky notes can be ordered from cargo and will also persist round to + round. + - rscadd: Mods can now view a list of all persistent data. Admin can use this list + to destroy it with prejudice. + - rscadd: Relatedly, you can now be jobbanned from Graffiti. + nearlyNonexistent: + - rscadd: Science can now print bluespace syringes and cryostasis syringes. Inject + people with more chems at once (20u each; 60u total) or inject them with water/potassium. +2018-09-27: + CrimsonShrike: + - tweak: Rigs can now be hacked after lifting wire cover with a screwdriver. + - tweak: Rig modules and cells are now removed with wrench. + ParadoxSpace: + - rscadd: Adds the Yeosa'Unathi subspecies, their language, their faction, and their + attack. Also gives Yeosa glowing eyes. + - tweak: Lowers how hungry Unathi are at the expense of slower healing. + - bugfix: Fixes issue with tail attack messages. + - bugfix: After much debate as to whether Yeosa count as Unathi, the Expeditionary + Corps have finally allowed Yeosa to wear Unathi cultural clothing from the loadout. + - rscdel: Unathi can now no longer manually toggle on and off involuntary processes + like self-healing. + Textor: + - maptweak: Bridge Deck - Captain's quarters' light switch is moved so that you + are no longer likely to remove the light tube when turning the lights on. + - maptweak: Deck 1 - Xenoflora and Miscellaneous labs are now brighter. This should + allow for scientists to actually see the things they work on. Robotics now has + solid doors. Privacy windows are no longer thwarted by looking through the door-windows. + Added a window to the mech bay side to compensate for the lack of visibility + from that direction due to the door no longer having a window. Door to storage + next to robotics actually opens for the roboticist now. Removed power cable + to nowhere in deck 1 starboard fore maintenance. Swaps the filing cabinet and + table in the morgue so that the paper bin, folder, and pen are actually accessible + when someone is working in there. + - maptweak: Deck 2 - Adds a shield diffuser at the edge of the old brig border so + trash will stop being stuck behind the shields when ejected into space from + the trash room. The shield should no longer block the airlock in deck 2 starboard + mid maintenance due to wall unevenness. + - maptweak: Deck3 - Adds a second mineral bath to deck 3 cryogenic storage wardrobe. + Moves photocopier and shredder in office so that they can both be used normally. + - maptweak: Deck 4 - The toxins storage room is now directly off the hangar in order + to let scientists actually get to their toxins storage room. Finally adds a + security camera to the fuel bay. The AI can now watch the fascinating process + of refueling. Moves the atmos control computer in the Petrov Laboratory so that + you can actually reach all the counter space when working. + - bugfix: Had a long discussion with the OR computers and we both agreed that they + need to actually face the direction they were mapped in. + Zuhayr: + - rscadd: Added a crashed escape pod that may generate on exoplanets and allow for + latejoiners a la Bearcat. + - tweak: Some ruins and submaps will add themselves to the distress signal list. + Probably worth checking now. + - rscdel: Prevented submap jobs from being test-spawned by the global datum system + as they do not expect null args. + afterthought2: + - rscadd: The IT skill now has gameplay effects when using modular computers. + - rscadd: 'Higher IT skill allows the user to bypass logging on program download + with higher probability (Trained: 30%, Expert: 60%, Master: 90%). Logs will + still be generated, with faked entries for the download info.' + - rscadd: The antag access decryption program is more effective at higher skill + levels. It works faster and has a chance to avoid tripping the alarm. At unskilled + (generally meaning non-antag) it has a chance to give the wrong access. + - rscadd: The antag camera alarm-trip probability is now tied to skill, with similar + effectiveness as current at Trained. + - rscadd: The antag dos program is more effective at higher skill, with more dos + attacks per tick at higher levels (equal to current at Basic). At expert and + master, gives extra fake attacking nodes to the system log to impede sysadmins. + - rscadd: The network monitor, email administration, and AI management programs + are locked below basic, basic, and trained skill, resp. You will instead get + some random data displayed. The programs do link to a terminal now. + - rscadd: Added a command line interface for modular computers. With enough skill + (expert+ for most things) you can run specific commands (type man for a list) + to do rudimentary sysadmin diagnostic tasks. Notably, with network access, you + can ssh into terminals of other computers over the network. If you are unskilled, + you may get various failure effects or just be unable to do anything. + - rscadd: To access the terminal, either use one of the programs or use Ctl Alt + Click. + zaredman: + - tweak: Adds defib and compact defib crates to be ordered through supply. + - tweak: Added holosign projector and advanced mop to the janitor robot. + - tweak: Added medical HUD to the surgical robot. +2018-09-28: + sabiram: + - tweak: Added a delay to welding/unwelding airlocks. + - tweak: Xenolife Technicians no longer have access to the fabrication lab or Petrov + helm. +2018-09-30: + Cakey: + - maptweak: Added Deck 5, an expansion of Deck 4 adding more verticality to the + ship beyond stairs and ladders. Deck 4 has been split up to accomodate these + changes. + - maptweak: The hangar has been moved inwards to be more centralised on Deck 5. + - maptweak: The lounge has been moved under cryogenics and now overlooks the hangar + (Still accessible from cryogenics). + - maptweak: The officer's mess has been moved under the mess hall and now overlooks + the hangar (Still accessible from the mess hall). + - maptweak: The Petrov has been made slightly bigger to be more useful. Moved several + research suites to the Petrov. + - tweak: The Research Director and Corporate Liason can now use the ID program to + modify accesses within their own department. Petrov accesses are now only modifiable + by the Research Director and NTL + - tweak: Fixes the commissarry shutter access requirement. + Miraviel: + - maptweak: Repositioned lights in the SEA's office, the XO's and CO's request consoles, + the fire extinguisher cabinets on the Bridge, the labels at the stairs, and + the CO's light switch. Removed the overlapping Nanomed from the Bridge and the + urinal from the Aquila. +2018-10-02: + Cakey: + - maptweak: 'Made maintenance style-consistent throughout all decks with techmaint + tiles and railings. maptweak: Made railings not obstruct items, shuffled some + items around to not be behind railings.' + - maptweak: Added a single seat in the lounge facing space, which takes up barely + any extra space. + - maptweak: Added a fax machine to the pilot's lounge. + - tweak: Fixed Petrov airlock accesses. + - tweak: Fixed Hangar maintenance airlock accesses. + ParadoxSpace: + - rscadd: After complaints that Unathi would have to be cut open [stack overflow] + amount of times with a scalpel, Unathi can now again toggle their healing. + - tweak: To reflect their biology, Unathi are now actually ectotherms instead of + being particularly cold-sensitive endotherms. + Sbotkin: + - rscdel: Removed peacekeeper armband from loadout. + Textor: + - bugfix: Helm control, engine control, sensor, and navigation consoles no longer + stop functioning after repair or construction. Just hit "reconnect." + - bugfix: The windowtint button on the back wall of the XO's office actually works + now. + sabira: + - tweak: The research department's colouration has changed from the red of NanoTrasen + to the green of Torch, Limited. + - tweak: Torch, LLC (the holding company representing the research department) has + been renamed to Torch, Ltd. + - maptweak: Changed the area around research to use the green decals, and new Torch + Ltd logo. + - maptweak: Changed the research director and liaison's offices on the bridge to + make use of the green decals. + - rscadd: Added legacy NanoTrasen uniforms to the loadout. + sabiram: + - tweak: Adherents of the Vigil can now play as Janitor, Chef, Bartender, Supply + Assistant, Engineering Contractor, Roboticist, Chemist, Research Assistant and + Researcher. + zaredman: + - maptweak: Adds dedicated Robotics OR. + - maptweak: Each OR now has holosigns to show when they are in use. + - maptweak: Moved some items from the joint OR to the robotics OR, added some extra + tools. + - rscadd: Separates Roboticist and Biomechanical Engineer. +2018-10-03: + Chinsky: + - tweak: Various changes to gunshot residue (GSR) forensic thingamabob. + - rscadd: Shooting someone pointblank will now leave GSR on the targeted organ, + and burn them a bit. Just like in those mystery novels! + - rscadd: You now need to aim at hand to take GSR from THAT hand, not from both. + You can take GSR from other bodyparts by aiming at them too. + - rscadd: Gun actually gets GSR too now. + - rscadd: Guns have a chance to leave GSR on the ground when fired. + Miraviel: + - rscadd: Added mechanical description to skill blurbs. + ParadoxSpace: + - rscadd: Adds a menu for you to select from your list of available attacks. Naturally, + this depends on species. + Sbotkin: + - rscdel: Removed ID modification and weapon authorization tools from command computers. + Textor: + - tweak: Lets engineering module and maint drones pick up floor tiles. They can + now put the tiles they levered off the floor back. + sabiram: + - maptweak: The hallway leading from the elevator to engineering in the maintenance + deck has been re-opened. + - maptweak: Moved security guard lockers from Petrov to the main checkpoint. +2018-10-04: + CrimsonShrike: + - bugfix: Rotating should no longer make science floor disassemble. + afterthought2: + - experiment: 'We are conducting some stability testing. You may notice issues with + how objects below you, on other z levels, are rendered: this is expected.' +2018-10-05: + Spookerton: + - bugfix: Automatic shutoff valve circuit toggling now works as intended. + Textor: + - rscadd: Deimos Advanced Information Systems (DAIS) is now officially in the game. + Lunchboxes, mugs, an undershirt polo, contractor uniforms, winter coats, and + a labcoat, are all in-game now. + - rscadd: DAIS is now a faction in the background tab of the character creator. + - rscadd: A new experimental DAIS lawset is available for researchers to install + in an AI. + - maptweak: Adds DAIS lunchbox, coat, and mug to telecomms room. + - bugfix: Corrects science labcoat description to reflect new color scheme. + - bugfix: Replaces lingering references to Torch, LLC with Torch, Ltd. + greggbot: + - rscadd: RFID Card Broadcasters, previously only found in PDAs, can now be printed. + zaredman: + - tweak: Adjusts max skill points and skill caps for Biomech and Roboticist. +2018-10-06: + Sbotkin: + - bugfix: The microphone circuit now translates non-GalCom languages only. + sabiram: + - rscadd: Added new colours of wrench and wire cutters, wherever wrenches and wire + cutters are found. + - rscadd: Adherent players can now select from some pre-set colours in character + creation. +2018-10-07: + Cajoes: + - rscadd: Added cubed spiders + - rscdel: Removes previously added domestic animal cubes + Cajoes & Earthcrusher: + - rscadd: Mass Driver Ammunition, two types. + - rscadd: Icon for the blunt mass driver round by Earthcrusher + afterthought2: + - bugfix: Air sensor thresholds should now work properly. + zaredman: + - tweak: Adds wheelchair and roller bed crates to be ordered through supply. + - tweak: Raises minimum player age for AI to 7 days and Cyborg to 3 days. +2018-10-08: + Atebite: + - bugfix: Fixed less wet floors increasing slip chance. Mopped floors should now + only have a 50% chance of slipping you. + Cajoes: + - rscdel: Removed the mention of crate in the cargo interface order form. Since + it is implied the shipment will be in a crate.. or locker.. or otherwise sealed + in some material. + - rscdel: Removed \improper tags from labels that didn't require them. You will + neither notice nor care. + - rscdel: Removed dispenser cartridge packs from Galley-Cargo due to redundancy. + Refer to Dispenser Refills-Cargo. + Textor: + - rscadd: Adds buttons to allow selecting "high," "low," or "never" on all antag + roles with a single click. + TheWelp: + - rscadd: Adds the starlight deity! Embodiment of fire and flame, watch out for + its super-powerful heralds and minions of light and darkness. + afterthought2: + - tweak: '"Starburst" spell has been heavily nerfed. The fireball spell is no longer + available in starlight deity mode pending balance adjustments.' + zaredman: + - tweak: Adds recipe for Chemistry to synthesize adrenaline. +2018-10-10: + FTangSteve: + - tweak: janihud now bases vision off of what the mob wearing it can see instead + of the tile + - rscadd: nabbers can now use HUDs + greggbot: + - bugfix: IC seed extractor now properly creates the appropriate seed and deletes + the fruit. +2018-10-12: + Atebite: + - tweak: Added a skillcheck for slips based on athletics + Cakey: + - maptweak: Tweaked several areas within maintenance after feedback. Removed majority + of railings. + - maptweak: Fixed shutoff valve layout on decks 4 and 5. + - maptweak: Swapped Petrov air pump with one that starts as on. + - tweak: Railings can now be wrenched open to allow passage, and the time it takes + to climb railing has been reduced from 5 seconds to 1.25 seconds. + - maptweak: Fixes merchant base accesses. + - maptweak: Removes a bunch of tiles from maintenance over piping and wires. + - maptweak: Fixes lack of cameras on D5. + - maptweak: Fixes dark spot on D4 fore hallway. + - maptweak: Adds consoles to pilot's lounge, exploration prep. + - maptweak: Adds suit sensors/camera monitoring console to Charon. + - maptweak: Adds exploration network cameras to explorer helmets. + - maptweak: Gives the shuttle pilot access to explorer camera network, suit sensors + monitoring. + - maptweak: Fixes noticeboard placement around the map, added extra noticeboards + to departments that lacked one. + - tweak: Fixes Petrov camera network, only accessible by LLC employees. + Chinsky: + - tweak: Disarming is now riskier. There's a chance to hurt your hand on the weapon + you're going for instead, with chance adjusted based on skill difference / being + flashed etc / being on help intent. +2018-10-13: + Anticept: + - balance: Increased atmospheric pump efficiency, and atmospheric filter efficiencies. + Pipe wizards rejoice! + - balance: Increased air injector internal tank size as well as power cap. this + increases its flow rate due to how atmospheric devices perform their math. Pipe + wizards rejoice! +2018-10-15: + Textor: + - tweak: Due to the extremely likely outcome of death for the crew upon ejection + of the escape pods, command has moved abandon ship from Command and Communciations + to Keycard Authentication Devices and renamed it to "Initiate Evacuation Procedures." + Abort still occurs at C&C consoles, as does bluespace jump initiation. + - tweak: Moves bolt/unbolt saferooms from Keycard Authentication Devices to C&C + - tweak: Changes Keycard Authentication Device interface to NanoUI +2018-10-16: + Cakey: + - maptweak: Fixes Petrov isolation cell alarm placement. + - maptweak: Added sticky notes to offices around the ship. + - maptweak: Added noticeboard to head of staff offices where missing. + - maptweak: Added missing air alarms to hangar, hangar storage. + - maptweak: Fixes hangar exit button access. + - maptweak: The Aquila is now overmap-capable. + - maptweak: The Guppy has been given some extra cargo space. + Roland410: + - tweak: Changes Tower deity spells to have more charges, and the fountain of power + only takes 30 seconds to recharge it. + Textor: + - tweak: O2 Tanks are once again removable without having to take your entire hardsuit + off. Hardsuit users will no longer risk suffocating in a vacuum because they + ran low on air. + afterthought2: + - rscdel: Spiderbots have been removed. + - maptweak: The telescreen by the copier in medical has been removed; some laptops + have been restored. + - tweak: Everyone gets four times more starting cash. + - tweak: Traders spawn much more often, and stick around about four times longer. +2018-10-17: + Melioa: + - bugfix: Fixes text displayed when examining an Automatic Shutoff Valve. + Textor: + - rscadd: Body scans now look different depening on the skill of the person reading + them. This includes printed and scanned versions. + - rscadd: 'New machine: Body Scan Display. It can have scans pushed to it for surgeons + to reference.' + - tweak: Body scanner UI updated to nanoui. + - maptweak: Maps in two body scan displays, one in the main operating room, the + other in robotics operating room. + sabiram: + - tweak: The conglomerate representing corporate interests onboard the Torch has + been renamed to Tenjin Holdings. + zaredman: + - maptweak: Adds washroom to medical. Moves a maint ladder to give some space. + - maptweak: Expands medical's D3 storage slightly to use up unused space. + - maptweak: Adds trash chute to medical locker room. +2018-10-18: + sierrakomodo: + - bugfix: Fixes mouse/drone duplication bugs with cookers, microwaves, and destructive + analyzers (#14179) + zaredman: + - tweak: 'Change to chem recipe for making adrenaline: now requires inaprov, hyperzine, + and dex+.' +2018-10-19: + Miraviel: + - maptweak: Added proper piping to the infirmary hallway and lighting to the locker + room. Added missing shutters and moved around a few overlapping objects. +2018-10-20: + EcklesFire: + - rscadd: Added helmets to Xenowear loadout for Skrell in security/roles that use + armour. Credits to Karbivio for icons + Miraviel: + - rscadd: 'Added the following new emotes: afold, alook, crub, eroll (targeted), + erub, hbow, hip, holdup, hrub, hshrug, hspread, fslap, ftap,pocket, rsalute, + rshoulder, squint (targeted), tfist, tilt.' + Sbotkin: + - bugfix: Fixes the integrated circuits recycling. + - rscadd: Allows to recycle assemblies and individual circuits. +2018-10-21: + zaredman: + - bugfix: Replaces D2 Atmos CO2 high-power pump with pressure regulator and replaces + D5 CO2 high-power pump with a normal pump to avoid unintentional blowouts. +2018-10-22: + Datraen: + - tweak: Uplink kits come in generic containers now. + Textor: + - tweak: Changes Torch Ltd. to Expeditionary Corps Organisation in several spots. + - tweak: Adds DAIS labcoat to roboticist and biomech engineer loadouts. + sierrakomodo: + - rscadd: Bridge Officers now have access to the Charon's Airlock and Charon's Helm +2018-10-24: + Anticept: + - tweak: All pipes, except fuel pipes, now have the same pressure damage threshold. + Previously, cross-z pipes were significantly weaker. Fuel pipes' extremely high + threshold remain unchanged. + - tweak: All pipes have a slightly higher burst pressure threshold. + BlueNexus: + - tweak: '"Many chemicals now require heating or cooling in order to mix. Check + the wiki for specifics."' + - maptweak: '"Added heaters and coolers to various locations on the map."' + Roland410: + - rscadd: Radiation suits got a larger pocket and you can fit your geiger counters + on them now. Technology! + Sbotkin: + - tweak: All guns now spawn with safety on. + - bugfix: Fixes twohanded weapons not being rendered when on back. + afterthought2: + - tweak: Ship movement physics have been altered. Ships are now generally slower + to accelerate, though can move pretty fast when at max speed. This includes + the Torch as well as overmap-capable shuttles and away site vessels. + - bugfix: Overmap wrapping when moving diagonally has been fixed. + - tweak: Shuttles no longer have gravity when not at a location that has ambient + gravity. + - rscadd: A new admin tool has been added, Toggle Overmap Halt, which allows admins + to make all overmap ships stop and freeze them from moving. + - rscdel: The Move To Top object verb has been removed due to changes in the new + BYOND version making it no longer work consistently. + sierrakomodo: + - maptweak: Pilot's Lounge and Deck 5 Maintenance now have air alarms +2018-10-26: + Sbotkin: + - rscadd: Experienced shooter will disable the safety if they draw a gun with harm + intent. + - tweak: Captain's revolver (the one in the showcase) spawns with no ammo. + - bugfix: Fixed a bug with safety state not showing after unholstering. +2018-10-27: + Melioa: + - tweak: Replaces 'Broad-shouldered' setup build for 'Well-built' +2018-10-29: + Gates: + - rscadd: NTOS now requires MANDATORY updates every once in a while. + MistChristmas: + - maptweak: Added a weapon charger to Deck One Checkpoint + - maptweak: Removed fire alarm hiding in a bin in excavation prep +2018-10-30: + BlueNexus: + - rscadd: Added insulated beakers. It is now actually possible to make clonex. Oops. + - tweak: Clonex no longer requires phoron. + RyanSmake: + - rscdel: Removed NTNet relay from Bearcat space ruin as it was non-functional. + SierraKomodo: + - bugfix: All disposal units should now be connected to the disposal network. + sierrakomodo: + - bugfix: Adds missing disposal pipes to the briefing room. +2018-10-31: + Textor: + - tweak: The bodyscanner now provides feedback when pushing scans to the OR displays. + sabiram: + - rscadd: Some jobs now have a cap on education tiers you can select. +2018-11-01: + EcklesFire: + - imageadd: Adds new icons for the Skrell riot security voidsuit to bring it in + line with the Torch voidsuit. Credits to Karbivio. +2018-11-02: + afterthought2: + - tweak: Secret and random will (almost) never fail to start when voted in. + zaredman: + - maptweak: Adds Security, Science, and Engineering department pagers in their respective + lobbies. +2018-11-03: + Cakey: + - rscadd: Added fleet branch berets, for showing off your branch when you need to + wear your service uniform. + SierraKomodo: + - bugfix: Job slots should now open back up properly whenever someone cryos from + a multi-slot job +2018-11-04: + SierraKomodo: + - bugfix: OOC lobby manifest entries should now show proper Active/Inactive status + - rscadd: Crew records now have a separate 'Formal Name' field that contains the + MD/PhD/etc suffix. This will be the name displayed on manifests. + afterthought2: + - balance: TC prices on some merc items have gone up. + - tweak: You can now dump the contents of a pill bottle into the chem grinder by + clicking the grinder with the bottle. +2018-11-06: + Datraen: + - rscadd: Added Skrellian SDTF Holobadges, verb to set individual SDTF. + Miraviel: + - rscadd: 'Added three new hairstyles: Donut Bun, Gentle 2, Gentle 2 Long.' + SierraKomodo: + - bugfix: Crew manifest entries should now update properly when someone cryos + afterthought2: + - balance: EMPs now deal much less damage to synthetic humans (FBP, IPC), though + the amount is still considerable. + - balance: Damaged robotic legs and feet reduce movement speed. + - balance: Robotic external organs will, if heavily damaged or the damage taken + is large, pass burn damage to contained internal organs. + - tweak: Cell organs are dramatically less power-efficient if damaged. + - tweak: If a synthetic human runs out of juice, they become unconscious. +2018-11-07: + sabiram: + - tweak: It now takes some time to repair and pry open/closed blast doors and shutters. + - rscadd: Added a EXO polo undershirt to the loadout underwear options. +2018-11-08: + Earthcrusher: + - bugfix: Emotes ending in quotation marks will no longer add a superfluous period + on the end. + - bugfix: Lazy typists rejoice! When speaking, the game will automatically capitalize + and add punctuation where needed. Well at least on the end of the sentence. + - tweak: Emotes now use the visible emote character set in your Character Setup, + which defaults to "^". + EcklesFire: + - tweak: Removes Skrell education background requirements and allows them to utilise + more unarmed attacks. + SierraKomodo: + - bugfix: Deck 5 hallways now have air alarms. + sabiram: + - tweak: All various subcontractor (NanoTrasen and Hephaestus Industries, at time + of writing) items in the loadout have been merged into one item with type selection. + Key word to search for (CTRL-F) is 'corporate' + - rscadd: Lighters, zippos and candles now come in a variety of new colours. +2018-11-09: + Miraviel: + - rscadd: Prospectors were given EVA and SolGov crew access. +2018-11-10: + MistChristmas: + - maptweak: Replaces overlapping Xenobiology pipes for Scrubbers and Supply Ones. +2018-11-11: + Roland410: + - rscadd: Added a playable crashed survival pod. + - maptweak: Converted the old crashed pod into a random ruin. +2018-11-12: + Alex6511: + - tweak: Reduced the frequency of windows updates events by half + Blue Bit: + - imageadd: Added sprites for the anomaly console and scanning pad. + Datraen: + - bugfix: Cancelling SDTF naming for Skrell badges no longer blocks setting in the + future. + Sbotkin: + - rscadd: Adds digital multitool to the engineering toolset augment. + SierraKomodo: + - bugfix: Fake Crew Announcements traitor service now broadcasts the correct arrivals + message on use + - bugfix: Fake Crew Announcements traitor service now properly updates the crew + manifest with rank, name, and honorifics +2018-11-15: + Roland410: + - tweak: Gamemode vote starts at 160 seconds, giving players 100 seconds to change + their character/preferences according to the voted gamemode. + - tweak: Should a non-secret mode fail to start, you will have one minute to adjust + your preferences or unready before roundstart. +2018-11-16: + Faustico: + - rscadd: Added basic security belts, like normal security belts but without a holster. + - maptweak: Added basic security belts to MAA lockers. + - tweak: Storage accessories and holsters use two different accessory slots again. + SierraKomodo: + - tweak: Blob resistance has been rebalanced. Brute-based weapons (Crowbars, fireaxes) + are more effective against cores, while fire-based weapons (Welders, lasers*) + are more effective against blob and strong blob. *Laser rifles take a 1/2 damage + penalty against all blob targets. See https://github.com/Baystation12/Baystation12/pull/23774 + for specific numbers. + TheWelp: + - rscadd: Adds ability to destroy circuit assemblies via damage. Bigger assemblies + means more health. Can be healed with wire. +2018-11-17: + CrimsonShrike: + - rscadd: Adds the mech pilot inspired Null Suit to robotics fabricator. This lightweight + rig offers little to no protection and cannot mount weapon modules. +2018-11-19: + Alex6511: + - tweak: the malfunctioning drone on away sites has had its damage adjusted + BlueNexus: + - bugfix: Cryo Cells now work properly, with temperature. This means clonex is possible. + - tweak: Clonex can no longer mix below -200C + Miraviel: + - tweak: Updated the guest pass terminal icon. Added guest pass terminals to supply + and to the Pathfinder's office. + - tweak: Using the autopsy scanner in-hand will now print the scan. Its icon was + also updated. +2018-11-21: + Aticius: + - bugfix: Crashed pod should no longer have random space tiles causing constant + air flow/air loss. + SierraKomodo: + - tweak: Charon and Aquila APCs now include helm access flags, meaning anyone who + can access the shuttle's helm can also unlock the shuttle's APCs. Engineers + still have APC access as well. + afterthought2: + - bugfix: Clonex should work properly with cryo tubes now (recall that you have + to make it at -100 to -75 C, best done with the cooler). It will adjust its + temperature to that of the cryo tube, which should prevent it from denaturing + under normal circumstances. +2018-11-22: + Alex6511: + - maptweak: Added a large insulated beaker to chemistry. + EcklesFire: + - bugfix: Makes Skrell medical voidsuit helmets work. + afterthought2: + - tweak: Clonex now won't denature below 50 C (i.e. unless you heat it). + sabiram: + - balance: Space carp now have generally more health and more powerful attack values, + and move faster. Pikes and sharks now have more health and do more damage. + - balance: All castes of giant spiders are now tougher, faster, and more deadly + all around. Hunters in particular are very dangerous. + - rscadd: Hunters and guards now use a new venom. + - rscadd: Added colour variants for space carp. + - rscadd: Added randomly coloured eyes for giant spiders, and made them glow. + - rscadd: Hostile mobs will now attempt to pry open doors between them and their + target, though they can be interrupted. + - rscadd: Hostile mobs can now destroy window-doors and tables. + - bugfix: Fixed hostile mobs not destroying windows, grilles, wall frames, etc. + - rscadd: Added more colours for space carp. +2018-11-24: + Blue Bit: + - rscadd: 'There are now two additional exoplanet types: shrouded and chlorine.' + - rscadd: Added a few alien creature color variants. + - maptweak: Added six new randomly spawning exoplanet sites. + - bugfix: Fixed a portion of the "Lodge" away site that was designated as space. + RyanSmake: + - rscadd: Adds a Bluespace Artillery to Deck 2 missile bay. Select an adjacent overmap + tile, and get rid of the event on it, or shoot at the away sector a charge of + your choosing (emp, remote mining, explosive, fire, or droppod). + Toriate: + - tweak: Photocopier now uses new photocopier icon state in bureaucracy.dmi instead + of the scanner iconstate. + - imageadd: New photocopier sprites added! Made by yours truly. + afterthought2: + - rscadd: The mecha skill (Exosuit Operation) is now a subskill of EVA. You need + to have at least Trained in EVA to select it, and then choose it from skill + selection. + - rscadd: Driving mecha without the mecha skill may result in unpredictable movement. + - rscadd: Exiting a mecha without proper skill may occasionally force-eject you. + - tweak: The mecha skill no longer has anything to do with mecha fabrication in + the description. + sabiram: + - tweak: Nurse spiders should infest their enemies with eggs less often than before. + - rscadd: Added giant spider legs, harvested from giant spiders. Can be used in + sushi or boiled in the microwave. +2018-11-25: + RyanSmake: + - bugfix: The BSA actually works now. +2018-11-26: + Funce: + - bugfix: You can no longer get infinite amounts of cable coil from constructing + and deconstructing certain telecomms equipment + Hubblenaut: + - tweak: Drawing guns based on intent is now a preference option. + SierraKomodo: + - tweak: Autopilot default speed lowered from 2 (Exceeds max speed hardcap of 0.1) + to 0.0025 (40 seconds ETA per tile) + - bugfix: Autopilot no longer burns fuel needlessly bouncing above/below the speedlimit, + and will now never go above the speedlimit. + - tweak: Autopilot now handles changing direction/destination and diagonal movement + much more efficiently fuel wise + - bugfix: It is once again possible to decelerate to a speed of 0. +2018-11-28: + afterthought2: + - tweak: Surgically repairing decaying organs is once again viable. +2018-11-30: + Heph-hasto: + - rscdel: Removes ability for ship AI to be traitors +2018-12-01: + Cakey: + - tweak: After the sudden drop in SCG funding, the newly released MRE line has been + reduced in content. + SierraKomodo: + - rscadd: General Notes (Public) field has been added to crew records. These are + records visible to anyone who can open crew records, and are intended for 'common' + information between security, medical, /and/ employment records. + afterthought2: + - rscadd: A new admin tool, Toggle Circuits, has been added to the Secrets panel. +2018-12-02: + Aticius: + - rscadd: Adds a joinable Colony map that can spawn on exoplanets. Rimworld mode + is here. + Broseph Stylin: + - rscadd: A new Scientist rank is now available for the SolGov Employee branch. + - tweak: The Scientist and Research Assistant jobs are now open for the SolGov Employee + rank of Scientist. +2018-12-03: + Cakey: + - rscadd: Added katsu curry, made with a slab of chicken, 10 units of rice, 10 units + of water, 5 units of flour, an apple, a carrot, and a potato. + Toriate: + - imageadd: The LAEP90's sprites have been replaced with new ones! + sabiram: + - tweak: Wall frames now use materials like walls do, and can be painted and unpainted + with the paint gun. +2018-12-04: + Aticius: + - maptweak: Bunch of minor fixes and tweaks to the Colony map. The walls no longer + eat mining computers. Oops. + Cakey: + - rscadd: Added Terran Navy uniforms. + - rscadd: Added Terran Navy ranks and structure. + sabiram: + - balance: Giant spider nurses will now only inject eggs into organs that have space + for them. + - balance: Reduced the number of spiders hatched per egg injected. + - balance: Injected spider eggs now mature more slowly. + - tweak: Slightly reduced maximum possible health for all castes of giant spider. + - tweak: Reduced occurrence weight and severity of spider infestation event. + - tweak: Spiders bursting out of organs is more damaging. + - tweak: Hostile simple animals can now destroy railings. + - tweak: Simple animals should now die faster after taking fatal damage. + zaredman: + - rscadd: Adds a MEDIC and OCIE AGENT tag for plate carriers. +2018-12-06: + Cakey: + - imageadd: Fleet uniforms sprites have been re-done. + - rscadd: Added Fleet officer's alt utility uniform, mainly used by bridge crew. + - rscadd: Added Fleet service jackets, with alternating trimmings based on rank + (enlisted, officer, senior officer, flag officer) + - rscadd: Added new Fleet dress jackets, with alternating trimmings based on rank + (enlisted, officer, senior officer, flag officer) + afterthought2: + - maptweak: The GUP is now overmap capable, though with poor sensor quality. + - maptweak: The GUP is no longer fully pressurized. Use the unlocked air alarm to + properly modify the atmosphere as needed. +2018-12-07: + Aticius: + - rscadd: A new paint job has been added to suit cyclers in the Engineering department. + Stomp around in style in a Hazardous Operation suit! + RyanSmake: + - bugfix: Stopped AIs and ghosts from activating artifacts. +2018-12-08: + sabiram: + - maptweak: The ship's Christmas tree has been installed in the galley. +2018-12-09: + Eckles: + - tweak: Changed Terran to Gilgamesh/Independent. Faction rename. + - tweak: Enforced Martian and Martian Surfacer as default human culture/system instead + of generic 'humankind'. + Persona E: + - balance: Unathi and Dionaea can no longer regenerate without nutrition. + Roland410: + - tweak: Construction skill is required for basically any recipes now, and material + difficulty (what skill you need to be able to craft from it) has been upped + for most of them. + - tweak: Engineering contractors receive trained construction now to be able to + handle plasteel. + Sabira: + - balance: Handheld and mounted/portable flashers now work on all simple animals. + - balance: All hostile mobs can now be stunned. + - balance: Spiderlings now pull from a weighted list of castes when determining + which caste to grow up into. Hunter spiders are rare, all other castes are even. + - balance: Every caste of spider except hunters can now be captured with nets. + - balance: Various spider numbers tweaks. Reduced hunter maximum damage. Reduced + lifesteal for all castes. Reduced nurse venom-ness. + - balance: Nurse spiders now have a maximum amount of eggs they can lay. They can + ready more eggs by feeding from mobs trapped in cocoons. + - rscadd: The base variant of giant spider is now an unremarkable generic worker + meant to fill the ranks. They don't have any special gimmicks. They're green. + - rscadd: Added a proper guard caste to spiders. Guard spiders (brown) will now + be paired with a nearby nurse (beige), and will closely follow them til' death + do they part. Killing a nurse might throw their guard into a rage. + - rscadd: Added a spitting spider (purple) caste - once they're out of venom, they'll + have to generate more before they can spit again. They'll resort to melee combat + if they're out of spitting venom. + - rscadd: Hunter spiders can now initiate combat by leaping at their prey. + - tweak: Hostile mobs will now only attempt to destroy their environment if the + obstacle is between them and their target. + - tweak: Hostile mobs now have a chance to miss their attacks. Flashing them increases + the chance. + - tweak: Hostile mobs can now have individual delays for prying open doors. Spiders + and carp are currently the only ones set. +2018-12-10: + Blue Bit: + - rscadd: Liquids can now be collected from exoplanet puddles. + - rscadd: Added tar. It's a bit toxic, but it can be heated and broken down. + afterthought2: + - rscadd: Some exoplanet plants now produce exotic chemicals, with effects that + are randomly generated each round. + - rscadd: Inspecting these chemicals in the mass spec with high chemistry and/or + science skill will reveal additional information about them. + - rscadd: By heating them to almost, but not quite, their boiling points, the effects + of these chemicals strengthen (if with phoron catalysis, then weaken). By also + adding certain additional ingredients (depending on the effect), the effect + will instead be left unchanged. + - rscadd: 'Cooling works similarly, but now the default behavior is that the effect + is left unchanged: you need to add certain additional ingredients to make the + effect strengthen (or weaken, with phoron).' + - rscadd: These chemicals may have powerful combinations of medical (or poisonous) + effects that can be used, or (if purified sufficiently) can be sold for large + profits. + sabiram: + - bugfix: Giant spider nurses will no longer infinitely attempt to cocoon deceased + giant spiders. +2018-12-11: + Persona E: + - rscdel: Removed the TCC ushanka from the loadout. + afterthought2: + - tweak: You can now order additional BSA charges from supply. + - tweak: Mass driver ammo is now cheaper. +2018-12-12: + Carlen White: + - tweak: The supply terminal listing of supplies shade every so listing to help + item selection. +2018-12-13: + Dave-TH: + - bugfix: The Pilot's qualification pin can now be pinned to jackets. (Like the + rest of the pins) + - bugfix: The dedication plaques on the bridge are no longer invisible. + - bugfix: The Pathfinder's hardsuit no longer has an invisible chest piece when + sealed. + WhiteHusky: + - rscadd: Supply consoles now show a notice when there are pending orders when properly + authenticated. + - spellcheck: Fixed misspellings in the Supply Console. +2018-12-14: + PoZe: + - tweak: Admin verb Create Object major flaw was optimized to display/search lists + of all objects instantly, instead of freezing for 3-4 seconds. + RyanSmake: + - bugfix: After repeated complaints from the SEV Torch that all showers are constantly + clogged we have deployed the NanoTrasen Bluespace Plunger(tm). Operation successful, + showers will never clog again. + WhiteHusky: + - bugfix: You no longer "see" items being removed from bags or other storage items + when blind. + sabiram: + - tweak: Placing acids in a fire extinguisher will now destroy them, and may splash + acid onto the user. +2018-12-15: + afterthought2: + - rscdel: NTSL has been removed entirely. +2018-12-16: + Alex6511: + - bugfix: Normal humans can no longer select the vat-grown specific culture + Hubblenaut: + - bugfix: Fixes movement with grabs. +2018-12-22: + sabiram: + - rscadd: Added two new holodeck programs; a plaza and a bathhouse. +2018-12-24: + WhiteHusky: + - rscadd: You can enable notifications for the shipping program. +2018-12-27: + Anticept: + - tweak: 'XO default access is no longer spotty. It now has access to the entire + ship and shuttles, including research. Specific changes: Added robotics, all + of research including petrov, Pilot, Mining, and Commisary. Places XO does not + have access: Captain, Research Director''s office, Research Director''s Petrov + Office, SolGov Rep, and Corporate Liason.' + - rscdel: Removed Genetics access from the game. + - tweak: Renamed "Nanotrasen" in the access computer program to "Corporate". + - tweak: Renamed access "Psychiatrist's Office" to "Mental Health". Renamed access + "Head of Security" to "Chief of Security". Renamed "Head of Personnel" to "Executive + Officer". "Quartermaster" is renamed to "Deck Chief". + Hubblenaut: + - bugfix: Anomaly isolation and Xenobiology air alarms will no longer cause atmos + alarms. + Toriate: + - tweak: RCD now carries 120 matter units at max. Small matter cartridges give 30 + units, while large ones give 120. + - rscadd: Rapid Crossbow Device added. Craft by screwdrivering a RCD and then slapping + a fully assembled crossbow frame into it. + - imageadd: New RCD sprites in tools.dmi, made by yours truly. Originally made for + Eris. + - imageadd: New Matter Cartridge sprites, based off /tg/'s. + - imagedel: Old RCD sprites deleted. + WhiteHusky: + - rscadd: You can now print receipts on pending, approved, and archived orders. +2018-12-28: + WhiteHusky: + - rscadd: You can now examine neural laces, and understand them assuming you have + the skill. + afterthought2: + - tweak: Off-station roles are blacklisted from being on-station antags. +2018-12-30: + WhiteHusky: + - rscadd: RFID card readers firmware has been updated to allow verbose diagnostics + checks. +2018-12-31: + WhiteHusky: + - tweak: You no longer drop computer hardware onto the floor if possible. +2019-01-02: + afterthought2: + - tweak: The colony will no longer start irradiated. +2019-01-03: + Broseph Stylin: + - rscadd: A system to automatically switch clothing icons based on gender has been + introduced. It is currently set up to work for humans and human subspecies. + - tweak: Expeditionary Corps, Fleet and Army uniforms as well as EXO and corporate + variations of the Torch Research uniforms now have gendered icons. +2019-01-06: + Cakey: + - maptweak: Fixed odd spacing in supply, adds a cargo lift to the warehouse. + CrimsonShrike: + - rscadd: Adds detective instinct verb for master forensics. This will give most + of the scene a distinctive noir look. + Hubblenaut: + - bugfix: Fixes shuttles removing air from the hangar upon arrival. +2019-01-07: + Anticept: + - tweak: Radiation resistance now fully blocks radiation levels below its radiation + resistance percentage, and thereafter will only allow some radiation leakthrough. + Lower resistance suits leak much more readily once past the threshold, while + high resistance suits will only leak a little bit after the threshold is reached. + Very highly irradiated environments are still extremely dangerous. +2019-01-08: + Anticept: + - tweak: The CE Firesuit is now firefighting rated, just like firesuits and atmos + suits. + Chinsky: + - soundadd: Pain has a low chance of heartstop again. High shock levels ('You feel + like you can die any moment now!' level) can sometimes cause thready pulse. + Countered by giving poor sod some painkillers to prevent shock, or some inapro + to stabilize the pulse. + sabiram: + - maptweak: The Christmas tree in the bar has been removed. +2019-01-10: + Anticept: + - rscadd: Added a waste tank for atmospheric waste gasses next to the fuel bay. + Now there's a place for gasses the Torch doesn't have a tank for, as well as + storage for engine byproducts, and can be dumped to space or recovered with + canisters. Also acts like a good way to clear a backed up atmos system if you + know how to configure the pumps and valves, and don't mind spacing the gas. + - rscdel: Engineering thrusters (not nacelles) are now purged from the game. They + offered next to no thrust at all and now the engine room is a little bit simpler. + - tweak: All black pipes in engineering ultimately go to the waste tank. + - tweak: Removed redundant fuel bay firedoor (it had two at the entrance). + RyanSmake: + - bugfix: AIs now get alerted once again when someone edits their laws. + Textor: + - rscadd: Adds DAIS, Xynergy, EC, and EXO logos to paperwork formatting, adds help + information about new logos to nanoword formatting help. + - rscadd: Adds all missing logos to the admin paperwork so that they can be used + in fax replies. + - tweak: Changes [tccseal] to [iccgseal], makes the EXO logo take over "[logo]" + and moves nt logo to [ntlogo] + comma: + - tweak: All speed/acceleration values are now displayed multiplied by 1000. Actual + mechanics are still same. + - tweak: Only 1 random alien seed in Xenoflora storage now, and can't order them + from cargo. Go on expeditions nerds. + - maptweak: No more pre-spawned anomalies on Petrov. Go on expeditions nerds. + lorwp: + - tweak: IPCs can now use the Command Hardsuits +2019-01-11: + Anticept: + - tweak: Radiation planets background rads peak out at 75bq. Hotspots are still + deadly though! + - tweak: Adjusted waste tank dump port so it goes to the edge of shields, rather + than dumping onto the top of D3 pod. + - tweak: Added a pump to the waste tank canister port. + BlueNexus: + - maptweak: Nacelles have been reworked. + - bugfix: As a result, combustion mode works again. + MistakeNot4892: + - rscdel: Removed the education system entirely. + RyanSmake: + - bugfix: Chief Engineers now spawn with correct backpacks. + Zuhayr: + - rscadd: Added a department goal system. Use Check Goal to view them inround. + - rscadd: Added a personal goal system. Defaults to disabled. Set Crew Goals to + something else in your global preferences to start getting them on join. + - tweak: Merged ambitions into goals. +2019-01-13: + Anticept: + - tweak: The "Set transfer amount" verb's range is now one tile, so now you don't + have to be carrying them to set it anymore. + - bugfix: ghosts and unconscious can no longer invoke the set transfer amount verb + on containers and IVs. + - tweak: Gas sensors in atmos and waste tank now display all gas contents that they + can identify. + Chinsky: + - tweak: Falling down zlevels now has a chance to dislocate feet/arms. Athletic + skill mitigates it, Trained and above are safe. + - tweak: Setting dislocated limbs now requires Medicine skill to be reliable, especially + for self-setting. Basic skill is enough for ~90% success rate, Trained is guaranteed + or your money back. + - tweak: Walking on fractured or dislocated limbs now applies additional pain to + that limb. Rest a bit for it to clear up or use a cane. + Hubblenaut: + - rscadd: Large escape pods will now repressurize themselves after undocking. +2019-01-21: + Anticept: + - rscadd: CMOs rejoice! Your hypospray now has a quantity setting, you can administer + in 1,2,5,10,15,20, or 30 units per injection! + - rscadd: CMOs rejoice! You can now pour your hypospray contents into a container + without removing the vial! (you can already put reagents in it too without swapping + vials) + - rscadd: CMOs rejoice! You are now coordinated enough to swap vials on the fly. + No longer do you have to remove and put away the old vial before you can install + a new one. + - rscadd: Medical rejoice! The contractor producing your syringes have heard your + cries and installed easier to read graduations on syringes. You now can set + transfer amounts in 1, 2, and 5. + - rscadd: Everyone rejoice! When pouring containers, you will now be able to see + how many units are remaining. + - bugfix: drones and borgs can once again use r-glass. + - bugfix: drones and borgs glass stacks are colored correctly. + Blue Bit: + - rscadd: Security borgs now have a hailer. + - bugfix: The playable colony should once again have its rods. + Cakey: + - maptweak: The robotics lab is now two-floored. Has a lift. + - maptweak: Cyborg station has been moved next to atmospherics. + ChaosAlpha: + - bugfix: Robots and drones should once again be able to drop items from their grippers + from the Silicon Commands tab (the verb has been renamed "Drop Gripped Item"). + - bugfix: Robots and drones now drop all gripped items on death. + Chinsky: + - rscadd: Rods are now material based, can be made from more than just steel. Same + with grilles and lattices. + - rscadd: Windows are material based too, any non-opaque material can be used to + make them (currently diamonds and quartz). + - rscadd: You can get back rods from rglass (rphoronglass) by welding them out. + - bugfix: Autolathe now will properly get some steel material on top of glass if + you feed it rglass. + Eckff: + - tweak: The sleep button now keeps you asleep until you press it again. It will + not wake you up from other things that cause you to sleep, like chems. + Eckles: + - bugfix: Fixes sprite and object issues with the riot security voidsuit for Unathi + and Skrell + Hubblenaut: + - bugfix: Fixes cameras of robots, hardsuits, Thunderdome and similar not being + accessable. + MistakeNot4892: + - tweak: Locker icons now use a runtime-based system. This should have no player-facing + impact other than the cosmetic effects of new locker icons. + - rscadd: Added a Loss Prevention Associate role. Basically a bodyguard for the + Workplace Liaison. They can only spawn with an active Liaison in the round, + and get a secure gun with corporate access. + - tweak: Added backend support for deferred roles, please make a bug if this breaks + anything in roundstart job allocation. + - rscadd: Added a stomach organ. If your stomach is damaged, you can't eat properly + and won't metabolize reagents well. + - tweak: Puke now contains some of the reagents you had in your stomach, plus some + stomach acid. We are pushing the boundaries of puke simulation technology. + - rscdel: Removed Xenolife Technician and NT Guard. + - tweak: Research Director is now the Chief Science Officer and may only be EC-ranked, + not contractor. + - tweak: All other science roles are now available to EC staff as well as contractors. + WhiteHusky: + - rscadd: Intergrated circuit's medical scanners can now get a patient's pulse. + afterthought2: + - tweak: Adherent are now shock-immune. + lorwp: + - tweak: the EVA Hardsuit in Engineering Hard Storage now fits on IPCs. Rejoice + sabiram: + - rscadd: Added aluminium. It's the standard material for furniture such as tables + and chairs, among other things. + - tweak: Added plastic and aluminium to the autolathe. Many recipes have been adjusted. + - tweak: Smelting bauxite now yields aluminium. Bauxite blocks can still be obtained + by compressing. + - tweak: Added aluminium sheets to the supply menu. + - maptweak: Added aluminium sheets to where metal sheets are found. + xales: + - tweak: Torch command (CO, XO, SEA) now share a headset type and encryption key + - tweak: The XO now has science keys in their locker. +2019-01-26: + Cakey: + - rscadd: Re-adds exploration helmet-cameras. + MistakeNot4892: + - tweak: YOU WILL NEED TO UPDATE YOUR RANK AND BRANCH PREFERENCES, READ THIS CHANGELOG. + - tweak: Occupations panel got a visual overhall. Click the link-name of a job to + set alt title, and click the never/high/low/medium to cycle between job weights. + - tweak: Rank is now tracked by job, not by save slot. You can set your rank and + branch up as you like for each given job. + - tweak: You can now set/save skills for submaps in the occupations panel. + Pandolphina: + - rscadd: Adds a new exoplanet ruin, a data capsule ejected from a ship with zombie + juice inside. + Textor: + - rscadd: Escape pod blast doors now open upon reaching pod launch sequence. You + might want to stay out of maint areas near escape pods when pods are getting + ready to launch. + - maptweak: After much deliberation, the Health and Safety department decided that + Engineering, the misc laboratory, and the tunnels outside the deck 2 escape + pods should be more well-lit. + - maptweak: The forensics office and bridge now have chairs that can rotate. + - maptweak: The deck 1 conference room floor has finally been repainted properly. + - maptweak: The R-UST now has its own power monitor installed and a gas injector + and a port to allow engineers to inject various gasses into the R-UST chamber + if they want. + - maptweak: Deck 3 has more emergency shutters to prevent the spread of fire and + decompression and prevent hapless engineers from wandering into unknown danger + outside the EVA room. + - bugfix: Fixes deck 5 subgrid configuration. + - bugfix: Fixes stasis cages. + - maptweak: Replaces ready room with adherent maintenance. Ding. + - tweak: Adherents now recharge at cyborg rechargers at half the rate. + - maptweak: Removes mineral baths from all other map locations. + - tweak: Adherent pylon will now damage robots. + - rscadd: Adds adherent tool vendor and crystal material airlock. + WhiteHusky: + - rscadd: You can show the contents of supply products. + afterthought2: + - tweak: Rad collectors and potted plants now cost more when ordered from supply. + - tweak: Adrenaline now does some heart damage if used to restart the heart. + sabiram: + - rscadd: Added green tea, iced green tea, and sweet green tea. + - rscadd: Added green tea to bartender soft drinks and coffee reagent dispensers. + - rscdel: Removed iced tea dispenser. Combine ice and the tea of your choice to + create iced tea. + - rscadd: Added flavour pods and sugar packs to the hot drinks vendor to flavour + your tea or coffee. + - rscadd: 'Added two new mixed tea drinks: Baron Grey is prepared by mixing black + tea and orange juice, and Maghrebi mint tea is prepared by mixing sweet green + tea and mint.' + - rscadd: Added teacups to the cutlery vendor. + - rscadd: Added chazuke. It can be prepared by mixing ten parts rice and one part + green tea in any container. Microwaving ten parts chazuke will result in a snack + bowl meal. + - rscadd: Added aluminium and plastic into the protolathe system. Many recipes have + been adjusted. + - maptweak: Removed protolathe from the robotics laboratory. + - maptweak: Added aluminium sheets to the research and robotics storage areas. +2019-01-28: + Roland410: + - bugfix: Fixed/removed the cap on away site jobs' skills. + sabiram: + - tweak: The circuit printer and protolathe can now hold more materiel. +2019-02-05: + Anticept: + - tweak: Pilot skill description now clarifies random movement occurs until trained + or greater, regardless of what ship you are flying. + - bugfix: Fixed phoron glass sheet's melting temperature so that reinforced phoron + glass is consistent with the pre-material overhaul melting temperature. This + should stop the random window breakage in the engine core until close to delamination + temperatures. + - tweak: Due to the nature of the material overhaul and this change, regular un-reinforced + phoron glass also gets its temperature significantly buffed. It's still weak + to physical attack by comparison to reinforced phoron glass. + Cakey: + - maptweak: Added LPA equipment closet to the Workplace Liason's office. + - tweak: Added "Asset Protection Agent" as an alt title to LPA. + - tweak: You can now put people onto wall frames with grabs + Chinsky: + - rscadd: Added an exploration shotgun. It's in a wall locker on Charon, along with + ammo, replacing netgun. What can possibly go wrong? + - rscadd: It can fire freely off-ship, but onboard you gotta register and get XO + or CO to authorize it. Yes it's pain, yes it's intended. + - rscadd: It is only guaranteed to work with types of ammo it ships with - beanbags, + flash, net rounds. Loading combat ammo voids warranty and may result in fun. + Datraen: + - rscadd: Adds Skrellian Weapons, currently admin spawn only. + Herigony: + - bugfix: Fixed admin jobban panel + Textor: + - bugfix: After paperwork being filled out in triplicate, lost, found, and buried + in peat for two weeks, the CSO now has access to their uniform in the uniform + vendor. + - bugfix: You now need to be an EC scientist to select an EC labcoat in loadout. + Senior Researchers and Assistants now have access to some of the same stuff + as normal scientists that they lacked. Also adds some equipment the biomech + should have access to. + - bugfix: Non-senior researcher Ensigns in the science department are now properly + considered officers and have an officer's uniform given to them when they wake + up instead of an enlisted uniform. + - rscadd: Labcoats can now be issued via the uniform vendor for EC science people. + sabiram: + - rscadd: Added the CSO's rigsuit. + - maptweak: Removed the AMI rigsuit module from the CSO's Petrov office and added + the new rigsuit to the bridge EVA storage. + - maptweak: Resized and reorganised the bridge EVA storage. + - rscadd: 'Added new wood material types: mahogany, maple, walnut, and ebony. These + types are largely identical apart from their colour.' + - rscadd: Added supply crates to obtain the new woods. + - maptweak: Several tables and chairs across the ship that were previously generic + wood are now made from mahogany, maple, or walnut. + - maptweak: Shuffled things around a bit in the captain's quadrant. + - maptweak: Moved the CSO's primary office back to the bridge, from the Petrov. + - rscadd: Clipboards are now a material item and can be constructed from most materials. + Clipboards that spawn around the map will be of various materials. +2019-02-06: + ghostsheet: + - maptweak: Rearranged the Guppy's interior for quality of life conveniences. + sabiram: + - rscadd: Radiation collector arrays will now fail catastrophically if exposed to + extreme temperatures, such as those found within the supermatter core. + - maptweak: The robotics lab has been messed with again, everything should work + now hopefully. +2019-02-07: + comma: + - tweak: The year is 2307 now. Roleplay accordingly. + sabiram: + - rscadd: Added explosive harpoons to the uplink. These will only explode upon embedding + in a target, by throwing it at them or sticking them close up. + - tweak: Increased the base harpoon's throwing force divisor. +2019-02-08: + Datraen: + - bugfix: Fixes incorrect access on hangar maintenance doors. +2019-02-09: + Anton-Kr: + - rscadd: Adds Vox ship and base to the game. It's join-able as a submap. +2019-02-10: + SierraKomodo: + - maptweak: Added rechargers to merchant shuttle and merchant base + - maptweak: Connected Flight Control disposal bin to pipe network + - maptweak: Added borg rechargers to communal brig and merchant's station + comma: + - tweak: Uplink gun selection for traitors was scaled down. Assault rifles and similary + big guns are gone, only pistol-likes available now. + - tweak: Wall of text about clothing items property is moved to a codex entry for + the item, instead of being shown on every examine. + sabiram: + - maptweak: The king of goats in the hydrobase planetary ruin has been retired. +2019-02-12: + Chinsky: + - rscadd: CPR changes. It now will help with blood circulation even if it fails + to restart the heart, so there's a reason to do it (especially on higher levels). + Fake circulation lasts 20 seconds and is better with Anatomy/Medicine skill + (highest). + - rscadd: Can now put IV bags etc on rollerbeds and use them as IV stands for buckled + people. Click with beaker to add it. Click with empty hand on empty (no buckled + guy) bed to remove it. Drag bed on people to hook/unhook. + - rscdel: Damaged livers no longer generate ammonia. It was creating self-perpetuating + damage which wasn't intended, it was for diagnostic memes. + - rscadd: Adds auto-CPR device. Goes into victim's suit slot. It won't do mouth-to-mouth + or resusticate them, but it will help with circulation. Needs Basic Anatomy + and Medicine skills to use, or risk rib fracture. Basically continuously applies + circulation part of CPR. Mapped bunch of them in medbay + - tweak: Sleepers now have 10x stasis option. Their power usage now also scales + with stasis factor greatly, 500 per factor, so ~5000 W at 10x + - rscadd: Guns suck now. + - tweak: When you have a gun in activa hand, you're considered to be 'aiming'. Moving + or changing active hand resets timer. + - tweak: Aiming gives bonuses to accuracy, longer you aim, capped by accuracy of + the gun - so no point in aiming longer than few secs with pistol, but with sniper + rifle, take your time. + - tweak: If you haven't stood still for at least a second, you get penalties based + on size of your gun. Pistols are almost not affected, but rifles are affected + greatly. + - tweak: Accuracy falloff differs for different calibers. Pistol rounds are best + used 4 tiles or closer, rifles can be used from any range without ok results. + Lasers mirror that setup, with higher range. + - tweak: Overall, pistols are now useless at range, but don't suffer much if you + move around or change hand to do something else. + - tweak: Rifles are oppsite, can hit if you aim even from other end of screen, but + if you move around, you're not going to hit shit. + - tweak: Moving around (not towards gun) will make you harder to hit now. Yakkety + sax away. + - rscadd: Added a small bells ringing sound playing when you regain consciousness. + Will only play if player is considered AFK (currently 5 minutes without activity) + Spookerton: + - tweak: Mercenary and Raider game modes no longer do early round-end votes when + the antagonists leave or die. + afterthought2: + - rscdel: Guns and armor are no longer available in personal command lockers. + - tweak: The bridge sidearms closet now also has three sets of command armor. +2019-02-14: + Anton-Kr: + - bugfix: Some misc things fixed on Vox ship. + RyanSmake: + - bugfix: Holodeck windoors now actually face the right direction. + SierraKomodo: + - maptweak: Added Pilot Voidsuit to bridge deck's EVA Storage that Bridge Officers + and Senior Enlisted Advisors can access. + - maptweak: Re-arranged the bridge deck's EVA storage. + Spookerton: + - tweak: IPV Fortuna can now fly on the overmap without being doomed. + Textor: + - maptweak: The battery backup PSU in telecomms has been moved after many Chief + Engineers and Senior Engineers have complained about its disruptive location. + The battery backup PSU also now recharges off of the deck 3 subgrid rather than + making a loopback off of the telecomms subgrid. Grey outlines have been moved + around in telecomms to be more consistent with the rest of telecomms' appearance. + - tweak: All telecomms machinery and computers have been updated to use NanoUI style + interfaces, bringing them in line with the majority of UI interfaces on the + Torch. +2019-02-15: + Chinsky: + - tweak: Accidental gun discharge chances upped, and now it can happen when aggressively + unholstering (hurt intent). Chance is now 20% at unskilled, 5% at Basic and + 1% at Trained. + - tweak: When unholstering or trying to fire a safetied gun on hurt intent, there's + now a chance you automatically unsafety it. Chance is 0% at unskilled, 25% at + Basic and 50% at Trained, guaranteed above. + RyanSmake: + - rscadd: You can now interact with emergency shutters through ladders and open + spaces. + SierraKomodo: + - maptweak: Added air and fire alarms to the deck 4 hanger catwalks. +2019-02-18: + Chinsky: + - rscadd: Crypods now have more immulsion. When joining round you will spawn inside + a pod, asleep for 1-5 seconds. Roleplay accordingly. + - tweak: Can now place auto-cpr device on people by clicking on them with it on + help intent. + afterthought2: + - experiment: No stasis bags are available on spawn on the Torch, except one on + the Charon. + - tweak: Stasis bags can now be printed from the protolathe. + - tweak: Stasis bags are now more expensive when ordered from supply. + - tweak: Rollerbeds can now be placed in backpacks. + comma: + - tweak: Autopsy scanner can now be used on severed organs to get some information. + No trace chems or time of death though, need body for that. +2019-02-19: + afterthought2: + - tweak: Modular consoles will no longer have access to NTnet when off-station. + comma: + - rscadd: Mountains can now spawn on any type of planet +2019-02-20: + Chinsky: + - rscadd: Added rescue bags. Work like bodybags, but provide atmosphere from attached + gas tank. Will set internal atmosphere of the bag to tank's release pressure. + Use screwdriver to remove tank. +2019-02-21: + Anticept: + - tweak: XO now has CSO access. + MistakeNot4892: + - rscadd: Added a drug called Three Eye to the contraband drug crate. + - rscadd: Added a chemical agent for crystallizing people. Good for repairing golems. + - rscadd: Breaking a soulstone into shards and stabbing them into a wizard (or firing + a null rod out of a pneumo cannon hard enough to embed it) will now prevent + the wizard from casting spells. + - rscadd: Added supporting code for psionics. + sabiram: + - rscadd: Added chevaux de frise, or spiky barriers. They're constructed by first + building a barricade of any valid material, and then attaching rods of any material + to the barricade. It will damage anyone who walks into it. +2019-02-23: + BlueNexus: + - rscadd: Added Venaxilin, a powerful antivenom made with spider venom. + - rscadd: Added leporazine variants, which are made by either heating up or cooling + down leporazine. Heating it up makes a chem that raises body temperature, cooling + it down makes one that lowers it. + Textor: + - rscadd: Adds new global preference to opt into having your ckey displayed in the + credits. This is set to hide your ckey by default. + - tweak: Adds additional snark to the end of the credits and some new randomly generated + title possibilities. + - tweak: Changes some awkward wording in play global sounds command, makes the change + end credits song command not suck anymore. + afterthought2: + - bugfix: The merchant can now use the merchant program again. + - tweak: The merchant program cannot be downloaded on NTnet. + comma: + - rscdel: Stasis bags are no longer orderable from cargo. +2019-02-24: + RyanSmake: + - bugfix: Shuttles no longer steal asteroid tiles when undocking. +2019-02-25: + Spookerton: + - tweak: Medals can be stored in wallets. + afirpo: + - bugfix: viruses weren't correctly cleaned up from the human-like mobs' bloodstream. + afterthought2: + - tweak: Door access has been substantially reworked. Please report any anomalies. +2019-02-26: + Piccione/Textor: + - rscadd: Adds new duty gloves for utility uniforms. They are available in some + lockers and via the uniform vendor. All gloves offer some protection, and engineering + gloves are also insulated. + SierraKomodo: + - bugfix: Officer's Mess doors will have the correct access flags again. + afterthought2: + - tweak: Arbitrary shuttles can no longer land at restricted landmarks. + xales: + - tweak: Adherent eyes have been upgraded. They no longer need a welding mask to + not go blind. As a side effect, they also cannot be flashed. +2019-02-27: + Chinsky: + - rscdel: Removes Medical Contractor job. It's merged into Physician/Corpsman, number + of slots for those bumped. GAS can join Corpsman only. + - rscadd: Physician and Corpsman jobs can now be joined with Contractor rank. + - rscadd: Engineering Contractor and Supply Assistant were merged into Engineer + and Deck Technician respectively, pick Civilian branch to join as contractor + SierraKomodo: + - maptweak: The Officer's Mess booze-o-mat is now accessible by officers. If you + can open the door, you can vend things. +2019-02-28: + SierraKomodo: + - bugfix: Senior Researcher now has standard sol gov crew access (Notably, access + to the bridge foyer and firing range), maintenance access, and Petrov security + checkpoint access. + - bugfix: Fixed access flags for bridge foyer, charon guppy and aquila airlocks, + communal brig, and supply office windoor. + - bugfix: Counselors can now access medical storage again + - bugfix: Bridge EVA storage windoors have the proper access restrictions again + mikomyazaki: + - bugfix: Swapped the names around on the D3 Ladders/Firing Range Hallway Cameras. + mikomyazaki2: + - bugfix: Removed duplicate items from B-Deck - Captain's Flask and Nanomed Vendor. + - rscadd: Geiger counter now makes a sound when radiation levels are high enough. + Volume increases with increased radiation level. + - soundadd: Added a geiger counter sound. + - bugfix: Fixes the case where the supply pack contents will be blank when ordering + live cargo. + - rscdel: MULE is no longer orderable, since it does not work on the Torch. +2019-03-01: + mikomyazaki2: + - rscadd: QOL Change - Adds an extra Supply & Denied Stamp to the Deck Tech lockers. +2019-03-02: + MistakeNot4892: + - tweak: Removing organs from a robotic bodypart (ie. FBP or IPC) will now use Devices + skill. + - tweak: A longstanding bug with amputated/severed limbs has been fixed and new + limbs will once again require reattachment with a hemostat after replacement. + - tweak: Surgery will now present a list of possible surgeries (if skilled enough) + rather than using a priority system. + SierraKomodo: + - tweak: Renamed NSV Petrov area tags to SRV Petrov. + - tweak: Soviet Cola has been renamed to TerraCola. + mikomyazaki2: + - bugfix: Corpsmen can use the Paramedic alt-title again. +2019-03-03: + Spookerton: + - tweak: Updated Workplace Liason and LPA job descriptions and access to match their + current role. + mikomyazaki2: + - bugfix: Game no longer assumes genders when self-examining as a neuter/plural. + - bugfix: IC Printers now take materials correctly when cloning. +2019-03-04: + Chinsky: + - rscadd: Examining things now shows message about it to people in 4 tile range. + If you don't wanna see it, you can disable it with a preference. + MistakeNot4892: + - tweak: Facial repair surgery is now a single step conducted with a hemostat after + making an incision. + - tweak: Skull repair is now identical to regular bone repair. + mikomyazaki: + - bugfix: Extends the restriction on some types of prosthetics to cover the entire + set of human subspecies instead of just human-basic. + sabiram: + - tweak: Adherents can no longer slip if they're floating. + - rscadd: Added two new colours to the adherent colour selection. + - tweak: The job slot formerly known as Corpsman is now Medical Technician by default, + with the former name as an alt-title. + - tweak: The job slot formerly known as Corpsman Trainee is now Trainee Medical + Technician by default, with the former name as an alt-title. +2019-03-05: + Crystalnole: + - bugfix: Securing microwaves gives the right securing verbs + Spookerton: + - tweak: Bridge officer lockers are harder to get into. + afterthought2: + - bugfix: Surgery is again possible. + - tweak: Makes cryo bags much more expensive in the protolathe, and require higher + tech levels. + mikomyazaki: + - bugfix: Fixes an error introduced through resolving a merge conflict incorrectly + with my earlier prosthetics restrictions PR. + sabiram: + - maptweak: The second deck hallway leading from the stairwell and elevators to + the engineering foyer has been reconstructed in the style of the typical hallways + on the ship. + - rscdel: Engineering duty gloves are no longer insulated. +2019-03-06: + CrystalNole: + - bugfix: Fixes invisible Cyborg materials + mikomyazaki: + - bugfix: Fixes an issue where full fire extinguishers would report an incorrect + message when you tried to fill them further. +2019-03-07: + Higgin: + - rscadd: Added a moderately weak TTV to the traitor uplink. 40 TC cost. + MistakeNot4892: + - tweak: Species who can eat mobs or items will now get an action button to puke + it back up. + - rscdel: Removed Regurgitate verb in favour of above. + SierraKomodo: + - bugfix: Security lobby door is now accessible by Sol Gov crew + - bugfix: Bridge safe room is now all-access + - bugfix: Merchant shuttle doors and windoors now require merchant access + - maptweak: Bridge access hallways now have their own area tags - Bridge Port Access + Hallway and Bridge Starboard Access Hallway + Textor: + - bugfix: You are able to construct glass and material airlocks again. + - bugfix: Airlocks that have their control circuits removed will remember their + paint jobs after the circuit is re-inserted. + - tweak: Atmospheric tanks now hold more CO2, H2, and O2 in the tanks due to increased + usage on board. + - maptweak: Camera networks have been adjusted to reflect reality. The lounge is + now located in the deck 4 camera network, as is the pathfinder's office camera. + The deck 1 fore hallway cameras have been renamed to reflect their location + better. The Adherent room now has a camera. + - maptweak: Adds deck 5 signage and warning signs to the escape pod launch areas + on deck 4, in addition to more escape pod direction signs to make sure confused + passengers know where to go to find pods on decks 2 and 4, and the deck 2 stairwell + is now more well-lit. + - maptweak: The R-UST now has an atmos control console in the control room so engineers + can adjust the injector port for gas. Don't forget to refresh the input. + - maptweak: New emergency shutters have been added to deck 4 to limit the decompression + caused by escape pod launch procedures. + - maptweak: At the direction of the Expeditionary Command Fire Marshal, there are + now more fire closets on board the Torch. + - maptweak: All the nacelles now have phoron windows installed on half-walls to + conform with the aesthetic on the rest of the ship. + - rscadd: After evaluating flaws in evacuation procedures, all escape pod outer + hatches now have a manual bolt override that can be manipulated with a wrench + after opening the cover in the event that the power is offline. As a reminder, + the outer hatch must be closed and the bolts re-engaged before the pod will + launch. + - tweak: Code Delta announcement no longer specifically mentions self destruct due + to rare cases in which it is engaged without the destruct mechanism being online. + Code Delta procedures have not changed. + mikomyazaki: + - rscadd: Adds Cultural Exchange patch to xenowear loadout for EC Unathi, Skrell + and IPCs. + - imageadd: Adds images for the Cultural Exchange patch. +2019-03-08: + SierraKomodo: + - maptweak: Antag shuttles, merchant shuttle, and admin shuttles are now shielded + against rad and ion storms. +2019-03-09: + MistakeNot4892: + - rscadd: Adamantine golem extracts now contain crystalizing agent. + - rscadd: Crystalizing agent can be used to produce resin globules that work like + medpacks for adherent and golems. + - tweak: Golems can now be operated on by substituting a surgical drill for a scalpel, + and resin packs for bone gel/fixovein/medpacks/cautery. + - tweak: Vox are now capable of gaining nutrition from wood pulp, napalm, glue and + various other inedible reagents. + - tweak: Vox are now capable of gaining nutrition from various materials and processing + others into a usable form with their stomach. + - tweak: Vox now require a hindtongue to speak Vox-Pidgin. + afirpo: + - rscadd: now it is possible to export virus dishes to earn credits (supply points). + - bugfix: now Toxicity related to a virus dish (Incubator) works again. + - tweak: checking for virus dishes already exported in the past or not analyzed + at all (those MUST NOT be exported!). + afterthought2: + - tweak: The IC printer can now take any materials as inputs. + - bugfix: Circuits properly init their steel cost now; this means that some are + much more expensive than previously. + - tweak: 'The TP circuit now costs more and rarer materials, and has a very high + complexity: you''re going to need the medium assembly or larger to house it.' + - tweak: The TP circuit will not function properly if the slaved computer is on + a z level not connected to its location. + mikomyazaki: + - bugfix: Fixes an issue with prosthetics selection for IPCs due to previous changes + for allowed_bodytypes on prosthetics. + - bugfix: Condiment containers can no longer be stored inside food. +2019-03-10: + Anticept: + - tweak: Atmos pumps have all had their power limits increased considerably. This + means atmospherics will operate faster, but at the cost of much more power at + peak performance. In addition, vents and scrubbers will operate faster when + stressed, but they too will cause a tremendous power spike in a ship wide atmos + contamination emergency where a huge number of scrubbers have to work hard (from + a badly clogged waste line, for example). A flooded deck can also overload a + deck substation, so bypass switching may be required in such cases. Beware of + extreme scrubber overload! + - tweak: Filter pressure limits raised to 15,000 kpa. They are still not powerful + devices when pumping from low to high pressures. You should put pumps around + them if you intend them to work quickly with moving pressures in a non-passive + manner. + FTangSteve: + - maptweak: deck 2 hallway by janitorial now dimmer and with no cameras + SierraKomodo: + - bugfix: Medical is now restricted access again. + SierraKomodo & Anticept: + - tweak: Flight manifest input box no longer shows the rank to make it easier to + find personel in the list. The report itself will show the rank. + afterthought2: + - bugfix: Disassembling research machines should now work. Upgrading circuit printers + should be more consistent. + sabiram: + - tweak: Most castes of giant spider will generally do more damage, and may have + more health. +2019-03-11: + SierraKomodo: + - tweak: You can no longer use headsets while sedated or sleepy-penned due to paralysis + making you unable to use your hands. + afirpo: + - bugfix: now the Core Sampler (Xenoarcheologist and perhaps Anomalist related) + works again - the sample is spitted out from its sample \ evidence bag. + afterthought2: + - rscadd: Adds the proxy command to terminals. This lets you obfuscate your nid + by routing through another computer. Requires access_network and experienced + skill. Generates local logs on the machine you route through, stored as a file + on the hard drive. +2019-03-12: + SierraKomodo: + - maptweak: Added fire shutters to the cargo warehouse shutters + Spookerton: + - bugfix: Inappropriate crew and passengers no longer have supply program admin + rights. + afterthought2: + - tweak: Petrov and research access can now only be granted by the XO and CO. You + can now build/adjust access on Petrov doors. + mikomyazaki: + - bugfix: Booze-o-mat contained a tea master item rather than actual actual tea. + Made it contain black tea instead. + - tweak: Robotics R&D consoles can no longer link with destructive analyzers. + - tweak: Made the Geiger Counter sound falloff and range larger. +2019-03-13: + Devildabeast: + - rscadd: After numerous flight tests and simulations, Adherents have begun to receive + piloting licenses and can now serve aboard the SEV Torch as Shuttle Pilots. + sabiram: + - maptweak: The firing range on deck 3 has been removed due to consistently causing + crashes. +2019-03-14: + Datraen: + - rscadd: Adds the Xilvuxix, a Multi-Z Shuttle capable of overmap travel and it's + own shuttle (capable of overmap travel as well) + Higgin: + - tweak: Traitor TTVs now share power with merc TTVs. They were underwhelming for + 40 TC cost. + SierraKomodo: + - bugfix: Windoors will now ignore walls when determining autoset access. This should + fix hardsuit windoors. + afterthought2: + - tweak: Unathi brute mod for the subspecies has been decreased a lot. + - tweak: Unathi healing can only be toggled once every two minutes. It cannot be + toggled within a minute of being hit in combat. + - tweak: Unathi limb and organ regeneration is only possible when the heal can be + toggled. + - tweak: When an unathi is at extreme levels of hunger, it no longer receives healing + from the passive heal ability. Instead, it takes internal organ damage, converting + it into nutrition. This is inefficient, so if the healing ability is left on, + it will die quickly. + - tweak: Unathi passive healing is less nutrition-efficient now. +2019-03-15: + SierraKomodo: + - tweak: Prone mobs can no longer buckle other mobs to beds/chairs. This prevents + crawling bucklespam during combat. + mikomyazaki: + - bugfix: Changes pin to an in-type pin on the reagent storage circuits. + - bugfix: Disassembling sleepers with an occupant will now eject the occupant. +2019-03-16: + Chinsky: + - rscadd: Coffins are made with steel now. Can still make wooden one with wood if + needed. + Datraen: + - bugfix: Fixes prosthetics not being selected by subspecies. + SierraKomodo: + - maptweak: The Deck Chief's office now has a guest pass terminal. +2019-03-17: + MistakeNot4892: + - rscdel: The flying pizza sprites are no longer available to crew robot modules. + - rscadd: A flying robot frame can now be constructed as an alternative to standard + robot. It uses the same arms, chest and head as the regular robot, but needs + the 'flyer' frame. + - rscadd: Flying robot frames produce flying robots, which use the flying pizza + sprites and can pass over tables. They have a selection of unique modules to + pick from and are generally faster but more fragile. +2019-03-18: + SierraKomodo: + - bugfix: Chairs and stools now have the correct materials when constructed and + deconstructed. + sabiram: + - rscadd: Added bamboo seeds to the vendors. Their produce can be chopped up into + wood. + - tweak: You can place wrenches onto tables if you're on help intent. Use harm intent + if you want to disassemble them. + - tweak: Halved the number of seeds stored in machines from 30 of each type to 15. + Use the seed extractor if you need more. +2019-03-20: + MistakeNot4892: + - rscadd: Added a humanoid species for the Vox Armalis, representing a larger, slower + voxform. It is not currently accessible outside of adminbus. + - rscdel: Removed armalis simple_animal and icon. + - tweak: Vox now have their own damage masks, blood masks and damage overlays. + - tweak: Vox wizard spell will now transform into a lesser version of the giant + space parrot. + sabiram: + - bugfix: Fixes IPCs becoming blind after being revived in surgery. + - bugfix: IPCs are no longer immune to sources of eye damage such as flashes and + welders. + zaredman: + - imageadd: Adds OCIE logo to be drawn onto official paperwork. +2019-03-21: + Hubblenaut: + - maptweak: Adds binoculars, prybar and a station bounced radio to the CoS Office. + RyanSmake: + - bugfix: Touching anomalies now works properly. +2019-03-22: + Devildabeast: + - tweak: Large mobs and bigger can no longer enter exosuits. + Hubblenaut: + - maptweak: Removes the disposal bin from the brig. + SierraKomodo: + - tweak: Synaptizine now overdoses at 5u instead of 30u. + sabiram: + - bugfix: Fixes issues with assigning and deleting accesses to mechs. +2019-03-23: + Devildabeast: + - rscdel: Due to numerous concessions to mental health procedure and human rights + complaints, the Sol Central Government will no longer stock straight jackets + on-board their vessels. + SierraKomodo: + - tweak: Characters that have ghosted (NOT aghosted) will be immediately flushed + when placed into cryo. + Spookerton: + - tweak: Viruses no longer infinitely increase the duration of effects like deafness + and drowsiness. + sabiram: + - tweak: Butchering simple animals now relies on your cooking skill, requires a + butcher's cleaver, and must be done on a table. + - tweak: Added cleavers to the dinnerware vendors. + - rscadd: Wood rendered from the produce of the bamboo plant will now be the bamboo + material. + - balance: Blobs will now spread and attack diagonally. + - balance: Blob attacks now take into account armour. + - tweak: Blob attack damage now depends on the individual blob segment attacking + you. The core defends itself the most vigorously. + - tweak: Blobs now attack with a random damage type. + - rscadd: You can now attempt to remove a sample from blobs by attacking it with + wire cutters. The regular blobs produce fairly powerful weapons in various damage + types, and the nuclei produce cores which can be disassembled for research points. + - tweak: Cigarettes and the like can now be lit by more hot objects such as plasma + cutters, and some tendrils snipped from the blob. +2019-03-24: + Spookerton: + - bugfix: Robot organs in meat bodies can be repaired with nanopaste in surgery. +2019-03-25: + Datraen: + - bugfix: Fixed Skrell Recon channel; Skrell ship holopad, spawns not operating + properly. + - bugfix: Filled the first-aid kits on the Skrell ship by making them the proper + subtype. + - maptweak: Fixed thrust, external access, and rearranged some parts of the Skrellian + vessel. + - tweak: Changed Skrellian Suits to voidsuit subtypes, allows stacking of helmet/magboots + inside of it. + - tweak: Lowered slowdown on the skrellian rifle. + SierraKomodo: + - maptweak: Added carp spawn zones to Torch bridge deck, Bearcat, and Unishi for + overmap events. + - maptweak: Moved a Torch deck 2 carp spawn from outside the reactor area to avoid + carp spawning inside the shields. + - tweak: Deck Chiefs now have access to Exploration comms. + Spookerton: + - tweak: Traitor Binary Gas Bombs are weaker, but also cheaper. + sabiram: + - rscadd: Added folding knives, replacing boot knives. + - rscadd: Added two types of folding knife to the loadout. +2019-03-26: + MrKicker: + - tweak: Players can pull items across Z-Levels + SierraKomodo: + - maptweak: Various areas on the SEV Torch have been renamed to be more descriptive + of their purpose/location. + - tweak: Typing indicator bubbles no longer appear for hidden mobs (Cloaked or inside + objects such as lockers). Indicators after you say or emote still appear. + ajkrupka: + - bugfix: Fixed an oversight to make armbands and webbing hide when jumpsuits are + rolled down. + sabiram: + - rscadd: Screwdrivers, wirecutters and all types of pry bar now come in a variety + of new colours. + - balance: Reduced armour values for the breacher and heavy mercenary rigs. +2019-03-27: + mikomyazaki: + - rscdel: Removes fax machine from Pilot's Office. + - tweak: Merges plastic flaps and airtight plastic flaps into one item. Can change + airtight setting with screwdriver, deconstruct now with crowbar. Can now construct + airtight flaps. + sabiram: + - tweak: Added colour selection to the suit vest and waistcoat in the loadout. +2019-03-28: + Datraen: + - tweak: Changes renegade spawn list to allow for any bag to conceal a spawned weapon. + - bugfix: Gyrojet no longer drops casings, now accepts magazines properly. + SierraKomodo: + - maptweak: Unishi and Bearcat now have long-range holopads. + sabiram: + - tweak: Crawlers who are weakened (forced down) will crawl slower. Being confused + will now additionally reduce their crawl speed. + - tweak: You can no longer attack with harm intent while incapacitated. + - tweak: Being incapacitated in any way will drastically reduce your melee accuracy. +2019-03-29: + sabiram: + - tweak: All knives have been unified under one type. Please report any irregularities. + - rscadd: 'Added an additional folding knife to the loadout: ''tactical folding + knife''' + - rscdel: Butterfly knives and switchblades can no longer backstab, temporarily + at least. +2019-03-30: + SierraKomodo: + - tweak: Intercom sprites now reflect the on/off status of microphone and speaker + switches. +2019-04-01: + Chinsky: + - bugfix: Torch is now facing upper side of the map. + SierraKomodo: + - bugfix: Bluespace River away site no longer spawns with a teleporter beacon. +2019-04-02: + Atebite: + - bugfix: Fixed weapon firing mechanisms not being able to fire in cardinal directions + CSCMe: + - rscadd: Adds extracting a specific amount of slime cores as a departmental goal + for science + Loaf && Banditoz: + - rscadd: 'Added four flying robot modules: repair, cultivator, surveyor, and forensics.' + SierraKomodo: + - tweak: There can now be 3 bridge officers in a round. + - maptweak: Playable colony now has universal enzymes in the freezer + - tweak: Rogue maintenance drones now spawn in separate smaller groups instead of + one massive blob. Total number of drones spawned per event is unchanged. + Spookerton: + - bugfix: Being cured of a virus now correctly adds its antigens where appropriate. + afterthought2: + - tweak: Some tweaks have been made to job spawn code. Beware of any anomalies. + ghostsheet: + - rscadd: Prospector locker will now always spawn with a duffle bag + mikomyazaki: + - bugfix: Moves the engine ejection door controls inside the box with the eject + button. + sabiram: + - tweak: Admins will now be informed why antagonist autospawn fails, instead of + printing to debug logs. +2019-04-04: + Banditoz: + - tweak: Flying mobs are now immune to quicksand. + Higgin: + - tweak: Push-time now depends on the difference of CQC skill between the two parties. + - tweak: At equal skill levels, pushing has a very short duration. + - tweak: Grabbing a prone person is no longer automatically an upgraded grab unless + the victim is stunned, unconscious, or on help intent. + - tweak: CQC costs more. Check your skill loadouts! + - tweak: Increased global miss chances to head, feet, and legs. + - tweak: Additionally reduced knockdown chances. + - tweak: Made organ damage much less likely before ribs/skull are broken. + - tweak: Increased likelihood of organ damage after encasing bones are broken + - tweak: Increased damage to brain when dealt and probability of brain damage from + damage to the head. +2019-04-05: + Cakey: + - maptweak: Added wooden walls to some areas of the Torch. + - tweak: AI holopads have been renamed to holopads. + - tweak: Removed the long range holopad's Z-range. + Cronac: + - tweak: Adds egg cartons as an item the biogenerator can produce. + - bugfix: Adds missing biohoods to CSO locker. + Higgin: + - tweak: Chances of collapsing from limb damage can now be mitigated by walking + and moving along walls/other objects you could reasonably use to prop yourself + up. + - tweak: This mitigation only works if at least one of your legs fully works. + - tweak: Stools and beds are collapse-exempt. IPCs at funerals rejoice. + - tweak: The chance of collapsing when not doing these things to mitigate it is + now significantly higher to compensate. + Spookerton: + - tweak: Wallets can hold ribbons, armor tags, and patches. + - tweak: Ribbons, armor tags, and patches are now tiny instead of small. + afterthought2: + - admin: A new admin tool, Toggle Harddelete Queue, has been added to the Secrets + panel, under Debug. Do not use this unless you know what you're doing. + ghostsheet: + - rscadd: Carp shoal map hazard now works for overmap shuttles such as the Charon, + Aquila and Guppy. + - bugfix: Fire alarm can now be constructed properly +2019-04-06: + Banditoz: + - tweak: Flying mobs are now immune to lava. + Cronac: + - bugfix: Fixes morgue trays and cremation trays displaying above bodies and bodybags. + Spookerton: + - bugfix: Refilling a fire extinguisher from a tank no longer tells you the extinguisher + is full when the tank is empty. + WatermelonsEverywhere: + - rscadd: Added a spare explorer equipment crate to Supply. +2019-04-07: + Cakey: + - tweak: Increased explorer job slots from 3 to 5. + - tweak: Lowered prospector job slots from 4 to 2. + Higgin: + - tweak: Prevents material weapons from taking damage on parry except against other + material weapons. + - tweak: Increases material weapon health. + - tweak: Reduces crowbar and toolbox accuracy penalties. + - rscadd: Adds an inferior, expensive, steel machete to the autolathe. + afterthought2: + - tweak: Acids are generally weaker now. + ghostsheet: + - rscadd: Ore boxes can now be ordered in supply +2019-04-08: + Chinsky: + - tweak: Charon and Guppy now only need Basic skill for flying on overmap without + random turns. +2019-04-09: + ChaosAlpha: + - bugfix: Drones spawn with modules once again. + - bugfix: All robots/drones material synthesizers should be functional once again. + - bugfix: AI cores should once again be constructible. + - bugfix: Surveyor bioreactor doesn't runtime and actually gives a reasonable amount + of power now. + - tweak: Flying repair robot module comes with slightly nerfed synthesizers. + - tweak: When remote controlling a maintenance drone, the AI can now use its radio + as normal. + - tweak: Cultivator module comes with a robot harvester. + Cronac: + - bugfix: Targeted healing spells such as those used by wizards should now properly + heal synthetics. + - rscadd: Adds the ability to synthesize crystallizing agent via chemistry with + polytrinic acid, tungsten, and silicon (and a bit of heat). + - tweak: Rogue drones now leave cleanable corpses when killed. + - bugfix: Monkeys are no longer ripping out their augments and throwing them across + the room. + - tweak: Augments now show up on medical scanners and related admin scans. + SierraKomodo: + - bugfix: Glowing slime extracts now create light. + - bugfix: Lit flares now process fuel and shut off when out of fuel again. + mikomyazaki: + - rscadd: Upgrading a sleeper now reduces power requirements, unlocks new chemicals, + and increases pump rate. + - rscadd: Adds emag effects to sleeper. + xales: + - tweak: Antag selection now defaults to NONE. You may need to update your antag + prefs. + zaredman: + - maptweak: Moves Security's Deck 1 checkpoint to the old Research Checkpoint. Decommissions + old Deck 1 Checkpoint. Adds lockdown shutters by ladderwell. + - maptweak: Adds 2 prisoner lockers for Communal. Also changes newscasters in the + Brig to the SEC variant where appropriate. + - maptweak: SEC-VEND now has new stock. More cuffs, more evidence bags, and now + carries pepper spray and holowarrant projectors. +2019-04-10: + Unknown: + - rscadd: Added a verb to change lobby track playing - Play Different Lobby Track + in OOC tab. +2019-04-11: + BiscuitCookie: + - maptweak: Renamed the HoP Office Privacy Shutters to XO Office Privacy Shutters + - bugfix: Removed objects outside the ship that didn't belong there. + Cronac: + - bugfix: A damaged aorta can once again be repaired while the chest cavity is open. +2019-04-12: + Randall: + - maptweak: The Supply Office and Supply Warehouse shutters now require Supply access + from the outside. +2019-04-13: + Chinsky: + - rscadd: Added speed indication to helm console. Green means 'slow', red means + 'too fast'. + - rscadd: Pilotable shuttles now can pass through meteor fields safely. Keep at + green speed and you'll make it. Need Trained skill for Charon/Aquila and Basic + for GUP. At Master/Experienced can do this at normal speed too. + - tweak: Torch now accelerates roughly 2x slower + Cronac: + - bugfix: The Adherent mineral bath will no longer kill Adherent users by deleting + their tendril junction. + - tweak: The Adherent mineral bath now removed embedded objects like shrapnel, but + will not remove implants such as tracking implants etc. + MikoMyazaki: + - rscadd: Titanium and its ore Rutile are now available via mining, allowing repair + of shuttles and the ship exterior. + Spookerton: + - bugfix: Lava turfs no longer incorrectly reignite and burn you every process forever. + mikomyazaki: + - tweak: Time police fixed a couple of items that weren't adjusted when we travelled + back 300 years. + myazaki: + - bugfix: Corrects piloting skill description to reflect recent change to basic + training with Charon and GUP movement. + zaredman: + - tweak: Security Equipment supply order replaced with Master at Arms supply order. + - tweak: Auto-Compressor and Rescue Bags can now be ordered via Supply. +2019-04-14: + Aurum22: + - bugfix: Fixes various layering issues with stasis cages, honey extractors, and + reagent dispensers (chemistry and bar varieties). + Cronac: + - bugfix: Cryogenic tubes will no longer heal anything without containing a drug. + - tweak: Clonexadone and Cryoxadone have been buffed due to cryogenic tube changes. + - rscadd: Adds nanite fluid, which is like cryoxadone for robotic parts. It can + be made with cryoxadone, space lube, and aluminum chilled down to -25C. Requires + 5 phoron as a catalyst. This is NOT safe to use on its own and should be used + on conjunction with cryoxadone or clonexadone. + mikomyazaki: + - bugfix: Floor lights can now be dismantled with a wrench. +2019-04-15: + CarefulLilCassie: + - rscadd: Adds high heels. + - tweak: Changes some items in the civilian uniform vendor to match the military + ones and utilises some more categories for cleaner usage. +2019-04-17: + Atebite: + - rscadd: Three new random events have been added + - tweak: The T-ray scanner can now inspect disposal pipes for damage + Chinsky: + - maptweak: Charon laoyout changed, it now has a cargo bay that can be cycled to + outside air. + Crackers5: + - rscdel: Removes some existing body markings + - rscdel: Removes species restriction from tattoos + - rscadd: Splits up existing body markings/tattoos to be selectable per limb instead + of full body. + Roaper: + - rscdel: Removed old contraband poster that depicted a spess cat. Also commented + out it in the code. + mikomyazaki: + - bugfix: Smartfridge ID Scan hack now allows access. +2019-04-18: + mikomyazaki: + - bugfix: Allows setting stasis to x10 on sleepers. + zaredman: + - tweak: Medical max staff numbers decreased to a maximum of 2 Physicians, 3 Medics, + and 1 Trainee Medic. +2019-04-19: + GooeyChickenman: + - bugfix: Defibrillators no longer appear empty on spawn. + mikomyazaki: + - bugfix: Voice changer now works properly while using an active camouflage module. + xales: + - tweak: Adherent can now play as Prospector +2019-04-20: + Chinsky: + - rscadd: 'Most handheld scanners (plant, health, gas, mass spectrometer, reagent, + xenobio, price) now store last scan result. Click inhand to see it. tweak : + Mass spectrometers now can be used directly on open reagent containers or syringes + to take sample. Old behaviour is still supported too.' + - rscadd: 'Price scanners keep adding scan results instead of overwriting them. + You can clear buffer in scan result view window. tweak : Tweaked health analyzer + colorings a bit. Now not coloring things like section headers, coloring more + deviations from norm (blood oxygenation / pulse)' + Flying_loulou: + - tweak: Blood bags are now small if containing a reaggent, and tiny if empty. +2019-04-23: + Flying_loulou: + - rscadd: Adds a new command voidsuit type for bridge officers and the SEA. + - maptweak: Replaces the pilot voidsuit in the bridge EVA storage by the command + voidsuit. + GooeyChickenman: + - tweak: More common medicines and reagents will appear on medical scanners. + Higgin: + - rscadd: Cult members can now make stun talismans again. Requires a tome, paper, + and a substantial amount of blood. + - rscadd: Ported obscure and reveal runes back into cult. Obscure runes make all + runes around them invisible, reveal runes reveal them. Runes cannot be used + while invisible. +2019-04-24: + Datraen: + - bugfix: Ion Thrusters now respect on state and thrust modifier when calculating + thrust +2019-04-25: + Datraen: + - rscadd: Adds lighting, overlaying to energy melee weapons. + Draxtheros: + - rscadd: Robots will now announce via chatlog when they enter an emergency power + state. + FTangSteve: + - bugfix: ingested reagents are now handled properly + - tweak: pulse impacting reagents now have stronger effects when compounded + - tweak: stomach volume is now 65 units instead of 30 + - tweak: vomiting when stomach is overfull now based on chance, higher with the + more you're over the limit + GooeyChickenman: + - bugfix: Ryetalyn will now fix a characters appearance after resetting genes. + Hubblenaut: + - bugfix: Fixes syndicate ID cards not being examinable. + Lilja: + - bugfix: Fixed sheet materials stacking bug where icon wasn't updating. + - tweak: Recolored & adjusted all sheet material icons to have more contrast. + - rscadd: New aluminium sprite, new plastic sprite, new glass sprite, new reinforced + glass sprite, new diamond sprite, new wood sprite, new uranium sprite, new rod + sprites, new cable wire sprites, new deuterium and tritium sprites. + - rscadd: Sheet material stacks now change appearance when they have reached maximum + stack. + Randall: + - maptweak: The auxiliary sanitation closet now holds a spare mop. + Spookerton: + - tweak: Optical Meson Scanner glasses only protect from supermatter hallucinations + when turned on. + ghostsheet: + - rscadd: Hardsuit overlay icons will now change depending on what module is selected + - tweak: Hardsuit drill mount now functions like a normal drill, being able to mine + multiple tiles at once + - tweak: Hardsuit drill mount energy usage has increase to a non insignificant amount + - rscadd: Mounted plasma cutter has a close range mode to enable object interaction + accessible by configuring + - bugfix: Selecting a hardsuit module now checks for energy and suit status + - bugfix: The energy blade projector can now fire darts again + - rscadd: Mounted plasma cutter now has a sprite + - rscadd: Mounted energy gun and Tazer now has a sprite + - rscadd: Mounted medical injector now has a sprite + - rscadd: Mounted grenade launchers now has a sprite + mikomyazaki: + - bugfix: Holocomms will no longer transmit speech before the call is accepted. +2019-04-26: + Randall: + - maptweak: The Auxiliary Warehouse shutter buttons now require Supply access from + the outside. + mikomyazaki: + - tweak: Allows changing a cryptographic sequencer's icon and name in a similar + way to chameleon items. +2019-05-03: + CarefulLilCassie: + - rscadd: Adds folding knives based on the Swiss Army Knives made by Victorinox + & adds them to lockers based on job as well as the loadout for a basic one. + ChaosAlpha: + - bugfix: Fix robots click-dragging things on catwalks. + - rscadd: Robots can now use the , and . hotkeys to move up and down z-levels in + hotkey-mode. + - rscadd: Everyone can now use > and < in non hotkey-mode to move up and down z-levels. + Chinsky: + - rscadd: New sprite for mining scanner, look for air analyzer-like thingie in miner + colors. + - tweak: Mining scanner now behaves like other scanners, storing last scans. To + use it click on a tile you want to scan. It will keep all scans unless buffer + is cleared. + - rscadd: Scanners now make sounds when used. + - rscadd: You can now make handrolled cigs out of any dried plants. + - tweak: Tobacco from cig vendomats can be put in pipes. + Flying_loulou: + - rscadd: Medical Technicians rejoice ! Following OHS inspections, EXCOM decided + to grant you a light polymer helmet, as in most of other EMS services throughout + human space. + - rscadd: Medical Technicians rejoice ! EXCOM also issues you a 'medical technician + chest rig', to help you carry your equipment without being forced to sweat in + a jacket. + - tweak: Medical personnel rejoice ! your paramedic and EMS jackets have been modified, + and now allow you to store a blood bag on the suit storage slot. + - maptweak: The MT chest rig and the EMS helmet are now available in the medical + technician's lockers. + - maptweak: Due to budget cuts, EXCOM had to sell the labcoat from the MTs lockers, + in order to aquire the new equipment. Therefore, you will no longer find labcoats + in the MT lockers. + Higgin: + - tweak: Tactical armor plates now offer extra resistance against brute and bullet + damage over regular medium plates. + - admin: Adminhelps not taken or closed in five minutes automatically close with + a reminder to the owner. + - tweak: Being stunned, weakened, or paralyzed now all prevent radio use. + - tweak: Getting hit can apply a very brief cooldown before you can use your radio + - guaranteed for stun weapons, projectiles, and powerful melee weapons. + - tweak: Pepperspray no longer automatically stuns/weakens targets without mouth/nose + protection. + - tweak: Pepperspray briefly confuses targets without eye protection. + - tweak: Pepperspray has a 50/50 chance to stun targets without full mouth/nose + protection. + - tweak: Partial mouth/nose protection (masks, bandanas) reduces pepperspray stun + chance. + - tweak: Pepperspray weakens stunned targets without full face protection. + - tweak: Buffs pepperspray gas pain damage and adds a chance of stun to gas effects. + Hubblenaut: + - rscadd: Adds a new chameleon headset to the chameleon kit. + - rscadd: Adds three new chameleon accessories to the chameleon kit. + - bugfix: Fixes chameleon items having broken sprites. + Randall: + - tweak: The advanced mop now synthesizes space cleaner instead of water. + RyanSmake: + - bugfix: The Torch is now a valid target for the BSA (for BSAs not on the Torch). + SierraKomodo: + - bugfix: Deck 1 security checkpoint shutters work as intended now. (Actually fixed + this time). + Spookerton: + - tweak: Secure guns are slightly more informative about registration changes and + have shorter ranged interaction logging. + - tweak: Welding tools are now all just one pocket-sized item with swappable tanks. + Tanks change the size of the tool when attached. + - tweak: Emergency toolboxes now also contain a welder with a tiny fuel tank. + - admin: Admin narrations can be styled. SubtleMessage is part of DirrectNarrate. + Moderators get limited DirectNarrate with a SubtleMessage style. + mikomyazaki: + - rscadd: Cooking supply pack now has a bottle of universal enzyme. +2019-05-08: + ChaosAlpha: + - bugfix: New < and > keybinds are now CTRL+. and CTRL+ in non hotkey-mode, to circumvent + a byond limitation. You will need to update your skin. + sabiram: + - rscadd: 'Added several new human languages: Yangyu, a Chinese language (key 2); + New Dehlavi, a Hindustani language (key 3); Prototype Standard Arabic, an Arabic + language (key 4); and Iberian, a Spanish-Portugese language (key 5).' + - tweak: Changed the way human culture defines assign language. Please double-check + your loadout. + - tweak: Sol Common's syllable list has been adjusted. + - tweak: Renamed 'Independent' to Pan-Slavic. + - tweak: The language keys of several languages have changed. Xenophage (4 to L); + Borer (x to z); Vox (5 to x) + - rscdel: Removed 'Lunar' and 'Spacer' languages. +2019-05-12: + Chinsky: + - rscadd: Adds jars of medical lollipops (holding 15u of a random common medicine) + to infirmary lobby and CMO office + - rscadd: Can now scan overmap things with sensor console. By default just shows + site description. + - rscadd: For ships, shows heading and speed, if ship is moving. + - rscadd: For planets output depends on Science skill - atmosphere / plantlife / + wildlife presence (Basic), number of non-natural ruins (Trained), compoisition + / temp / pressure of atmosphere (Expert). + Novacat: + - tweak: Fixes a UI bug with the modular computer downloader and antag programs + Spookerton: + - tweak: Arterial bleeding is now much more obvious to the bleeder. + mikomyazaki: + - bugfix: You now need to wear hardsuit gloves/boots to have a complete airtight + seal when wearing a RIG. +2019-05-13: + Cakey and Marie Taylor: + - imageadd: Adds directional sprites for vending machines, smartfridges, watercoolers, + drying racks and medivendors. Sprites by Marie Taylor. +2019-05-14: + Chinsky: + - tweak: Shuttles now display their fuel in Delta-V rather than pressure gauge. + They also show Delta-V used per move, so you can actually gauge how many jumps + you have left on your fuel. + Devildabeast: + - rscadd: IPCs can now select kicking and stomping as their default unarmed attack. + SierraKomodo: + - bugfix: Energy guns no longer become invisible if cell charge exceeds cell capacity + due to adminbus. + - bugfix: Spacer now has a text color again. It's dark-yellow. +2019-05-15: + ChaosAlpha: + - bugfix: Robots can once again build windows using their synthesizers. + Eckles: + - rscadd: Adds new Skrell factions and home systems. + SierraKomodo: + - bugfix: Being incapacitated no longer affects talking and radio use if the radio's + microphone is set to on. + - bugfix: Talking normally with a nearby radio set to on will no longer trigger + aim-mode shooting. + afterthought2: + - tweak: Movement delay handling from items has been tweaked slightly to give more + fine-grained effects. +2019-05-16: + Chinsky: + - tweak: Helm console layout changed, mostly to prevent sector descriptions shifting + movement keys down at WRONG FUCKIGN MOMENT. + - rscadd: Added acceleration limiter to helm console. Hard value vs engine thruster's + percentage. Doesn't affect fuel usage, use engine limiters for that. + ghostsheet: + - tweak: Hardsuit ore scanner module can now print survey data disk. + - tweak: Hardsuit mounted drill now has an increased energy cost of 2Wh per use. +2019-05-17: + Montykore: + - imageadd: Atmos canister icons and canister details revamped and updated. +2019-05-18: + Chittersky: + - tweak: If you are wearing a voidsuit, spiders now need to breach it before injecting + poison. On other hand, spiders now can breach voidsuits. + - tweak: Spider venom's toxin damage is now slightly weaker, but can cause confusion. + Montykore: + - imageadd: Updated and revamped corgi related icons. + SierraKomodo: + - bugfix: Deck 1 security checkpoint windoors have the correct access flags now. + babydoll: + - tweak: Simple animals' speed prying doors open now depends on the door. + ghostsheet: + - rscadd: 'Plasma cutters can now cut through the following: bulkhead walls, floor + platings, girders, catwalks, windows, low wall frames and lattices.' + - rscadd: Plasma cutters will now spark and require eye protection when interacting + with object. + - tweak: Mounted plasma cutter has an increased object interaction energy cost, + 10 Wh per use. + - bugfix: Drills will now have a delay and sound when drilling through girders. +2019-05-19: + Chinsky: + - rscadd: Added 'Known Implants' field to medical record, that gets auto-filled + with roundstart robotic organs + - rscadd: Added buddy tags to explorer lockers. These can be worn as an accessory, + and will start pinging every half a minute or so if they don't detect another + tag with the same ID in 10 tile range. They can be clicked in hand to set ID + and toggle on/off. + SierraKomodo: + - tweak: Helm and navigation consoles now show 'gigameters/hour' for speed and acceleration. +2019-05-20: + Albens: + - maptweak: Bridge Deck has undergone a refit. +2019-05-23: + Devildabeast: + - tweak: The Roboticist and Biomechanical Engineer have had their access adjusted + to better reflect their respective departments, and the Roboticist can now access + the Engineering Locker Room and front desk, but has had Tech Storage access + removed (which was unusable anyway). + - rscdel: The Roboticist's headset has been removed; the Roboticist and Biomechanical + Engineer now spawn with their respective department's headset. + - tweak: The Roboticist is now Trained in EVA and exosuit operation by default. + - maptweak: The Engineering Locker Room's material reserves have been locked behind + windoors in order to prevent certain nerds from thieving. + - maptweak: Robotics now gets two loaded toolbelts and multitools instead of one, + as well as two pairs of insulated gloves. + SierraKomodo: + - maptweak: Various map tweaks to Aquila to fix clickable sprites being under other + sprites and other mapping nonsense. + - maptweak: The Charon power compartment has a camera again. + ghostsheet: + - rscadd: Medical drop pouch and Medical webbing is now available on the loadout + to medical trainee, chemist and biomech. +2019-05-24: + SierraKomodo: + - bugfix: 7mm haywire ammo boxes now contain the correct ammo. + - bugfix: Flying borgs are no longer capable of having infinite VTEC modules installed. +2019-05-25: + Flying_loulou: + - rscadd: The EC now issues branch berets to their personnel, to denote which section + they're from (available in the loadout, hats and headgear section). + - rscadd: Following extensive training the personnel of the Torch is now able to + clip their helmets on their plate carrier's suit storage slot. + - rscadd: Following even more extensive training the medical technicians can now + clip their EMT helmet on their MT Chest-rig's suit storage slot. + SierraKomodo: + - tweak: Flying borg speed has been reduced one level. Flying borg default speed + is now the same as a regular borg with a VTEC module. Flying borgs with a VTEC + module will be as fast as the old default flying borg speed. + - rscadd: Pill bottles can now be printed at autolathes + afterthought2: + - tweak: The pilot qualification pin is now restricted to Fleet and EC. +2019-05-26: + Chinsky: + - tweak: Spacesuits etc now have maximum pressures they can handle. You can check + their codex entry to see it. + babydoll: + - rscadd: You can now permanently disable radio/teleporter beacons with an emag + or EMP attack. Any connected teleporters will also lose their connection. + - rscadd: Anchored underfloor beacons can be repaired with nanopaste. Handheld or + portable beacons are unrecoverable and must be replaced. +2019-05-27: + BearKingKrug: + - tweak: Clicking on borgs/drones on harm intent with a welder/crowbar actually + attacks them now + ChaosAlpha: + - bugfix: In non hotkey-mode, move-up/down have been moved to CTRL+Numpad_Add/Numpad_Substract + to fix issues with some keyboard layouts. + Chinsky: + - tweak: NTIRC client no longer spawns by default, freeing up some space on PDAs + and such. + - tweak: Reports editor now spawns on Cargo and Command PDAs by default. + Flying_loulou: + - tweak: Security coveralls are now also available for all fleet security personnel + (via the uniform vendor, under utility extra). + - tweak: Changes the firesuit sprite for a new one, based on TG's. + - tweak: Lowered the firesuit slowdown to 0.6 (voidsuits' slowdown is at 1). + - rscadd: Based on TG's sprites, adds the firefighter helmet, and the chief firefighter + helmet (for the CE). You don't need to wear a mask while wearing it, and it + does connect to internals (you still have to toggle them on, of course). + - maptweak: Adds said helmet in the fire closets, to replace the already existing + red hardhat. + - maptweak: Adds fire closets throughout the ship. + - maptweak: Adds fire closets in the Charon and the Aquila. + NewOriginalSchwann: + - tweak: Fatigues have been added to the Fleet pilot's uniform vendor under utility. + SierraKomodo: + - maptweak: 'The bridge deck has received some minor tweaks and fixes. See https://github.com/Baystation12/Baystation12/pull/25628 + for details. Notable changes below:' + - maptweak: CMO's office fax machine no longer blocks access to part of the table + - maptweak: Meeting room now has a fire alarm + - maptweak: Additional cameras were added to CO's office and aft hallway to fix + blindspots + - maptweak: Fire doors were added to doors and windoors that were missing them + - maptweak: PPE closet access flags now match the sidearm closet + - rscadd: Shield generator and shield generator monitor UI now includes a capacity + percentage. + - maptweak: The lift now has firedoors. + - rscadd: Flying borgs now have light-weight armor, providing half the armor value + of a regular borg's armor. Light-weight armor can be printed from fabricators + for half the cost of regular armor, and can also be applied to regular borgs + (Not that you'd ever want to do this.) +2019-05-28: + AlexMorgan3817/_Elar_: + - bugfix: Now device can't be its own proxy. + BearKingKrug: + - spellcheck: Fixed AI intro text to not mention being a traitor + Cakey: + - rscadd: EC service and dress under-uniforms have been replaced with service jumpers, + with complimentary departmental colouring. + - rscadd: EC senior officers (captain and above) now have a unique service cap. + ghostsheet: + - tweak: Overmap Fast speed is now reduced from 20 to 15, this applies to dodging + meteors in shuttles at experienced/master levels. + - tweak: Gas thrusters for overmap travel, will now calculate thrust and fuel consumption + by volume. Lower volume limit from the engine control for more fuel efficiency. + - tweak: Guppy's mass and max speed has been increased. + - maptweak: Charon's atmospheric and electric compartment has be reworked to accommodate + for the fuel consumption. + - maptweak: There are now shuttle navpoints on the hanger deck. +2019-05-31: + EcklesFire: + - rscdel: Removed inappropriate boots from Fleet EMT. + ghostsheet: + - rscadd: Vey-Med has generously donated two prototype hardsuit defibrillator modules + to be used on the torch mission. + - rscadd: Hardsuit defibrillator module has been added to the rescue rig and the + CMO hardsuit. + - tweak: Hardsuit health scanner can now display their reading like the ore scanner. +2019-06-01: + Orelbon: + - rscadd: Adds NanoUI interface to suit storage units. + SierraKomodo: + - rscdel: Vat-grown blanks have been removed from the SRV Petrov. + babydoll: + - tweak: Many objects that were previously rotatable with a verb are now rotated + using alt-click. Any such object will report in examine that it can be rotated. + - tweak: You can now rotate vending machines with alt-click. + ghostsheet: + - maptweak: The Aquila's engine room has been updated, most notably it now has a + fuel pump for easy refuelling. +2019-06-02: + Atebite: + - rscadd: 'New integrated circuit components have been added:' + - rscadd: Reagent funnels - Allows you to use reagent containers such as beakers + on the assembly to refill internal reagent storages + - rscadd: Reagent heaters/coolers - Heats/cools contained reagents, similar to heater/cooler + pads + - rscadd: Anchoring bolts - Anchors the assembly so that it cannot be moved + - rscadd: Hatch locks - Prevents opening the assembly with screwdrivers while enabled + Spookerton: + - rscdel: Resleevers and neural laces no longer exist. + babydoll: + - rscadd: Blobs will now additionally attempt to attack a random nearby tile, even + if they aren't expanding to that tile. The core nucleus itself is particularly + aggressive. + - tweak: Material coins are no longer effective weapons. + ghostsheet: + - rscadd: Plasma cutter can now deconstruct closet. + - tweak: Hardsuit chemical dispenser now has inaprovaline instead of tricordrazine. + - tweak: Rescue rig can now have auto-compressor hooked on the suit storage slot. + - tweak: Ninja's chemical dispenser now has dermaline instead of radium, no more + radioactive super powers today. + - bugfix: Hardsuit module item will no longer be put into bags or closets. +2019-06-03: + SierraKomodo: + - tweak: You know longer magically know an emag is an emag because of your complex + devices skill. + Spookerton: + - tweak: Hearing your current default language skips adding the language identity + to the log. + - tweak: You no longer grunt as if you have no languages if you have any language + you can speak. + - tweak: Team outsider special roles are given an appropriate team language. + - bugfix: Legalese is enabled in the dme again. Derp. + - rscdel: GalCom no longer exists. + - tweak: Everyone on the Torch and Verne except stowaways and merchants are given + ZAC on spawn. + - tweak: Non-Torch jobs do not give a language on spawn unless you spawn with no + languages, in which case you get Spacer. + - tweak: The maximum number of preferences-selectable languages is 3 instead of + 4 due to other changes. + - tweak: Sinta Unathi speak Sinta. Yeosa Unathi speak Yeosa. Having the other language + is optional for both. + - rscadd: Selenian exists. It is a dialect of ZAC (high cross-understanding), not + money-speak. It is the language of selenians, and optional for residents of + luna. + - bugfix: Having no languages at all prevents you from speaking in raw text that + everyone understands. + - tweak: Chimpanzee is renamed Primitive. Subtypes of Primitive no longer exist. +2019-06-04: + WezYo: + - bugfix: Ghosts can no longer close antag pda program +2019-06-05: + Cakey: + - tweak: You can now rotate in chairs when buckled to them by clicking once again. + SolarK: + - tweak: Slowdown penalties based on cold now affected by species discomfort levels + babydoll: + - tweak: All types of blob will now launch bonus attacks less often overall, and + will attack more or less often depending on their type. + - rscadd: Added the 'ravaging mass', which forms an offensive line around the shield + blob spawned by the cores. This type attacks most often and most potently of + all the blob types. + - tweak: The base type (which makes up the bulk of the blob) formerly known as 'ravaging + mass' is now 'pulsating mass', and has had its maximum damage potential reduced. + - tweak: Reduced damage potential of the shielding mass. Increased hit points. + - tweak: Mecha are now valid targets for the blob's bonus attacks. +2019-06-06: + Cakey: + - rscadd: Added a new on-ship ambience sound, for that in-flight pressurised cabin + feel. + Devildabeast: + - rscadd: Adds a nine-pointed star icon to the list of potential bible choices. +2019-06-07: + WezYo: + - bugfix: resetting a flying drone will no longer make it invisible +2019-06-11: + Spookerton: + - tweak: Radio messages no longer show language identifiers if the language is the + same as your default. +2019-06-12: + Chinsky: + - tweak: Doors to the catwalk overlooking Hangar are no longer access-locked. + Devildabeast: + - rscadd: Adds urns which can contain, move, and release ashes, and can be constructed + from different materials. The Counselor gets a wooden urn in their locker on + round start. + Kamiztheman: + - tweak: Item descriptions in the traitor uplink menus have been adjusted so that + new recruits actually understand what they are buying. + - tweak: EMP ammo boxes purchased from the uplink should now have enough ammo to + refill a magazine. + - bugfix: 7mm EMP ammo boxes now contain and can store the correct caliber rounds. + MistakeNot4892: + - tweak: Status indicators on the UI have had a makeover. + - rscadd: You can now click status indicators to get an idea of how things are in + your current state. + Spookerton: + - tweak: The brig no longer contains prison camp clothes because it's not one. + - tweak: The brig officer gets a multitool for locking guests' sensors on. + - tweak: You can lock and unlock suit sensors through the stripping menu with a + multitool. + WezYo: + - bugfix: Attacking with swiss knives properly displays attack verb + ghostsheet: + - rscadd: Hardsuit interface now has internal tank controls. + - tweak: Hardsuit interface has been updated. Fresh coat of paint to keep it looking + good. + - bugfix: Tank "reset" button now works properly, resetting tank release pressure + to its original value. +2019-06-13: + Draxtheros: + - tweak: Raised the temperature at which Unathi begin to receive "warmth" messages. + Spookerton: + - tweak: IPCs cannot be OCIE agents. +2019-06-14: + MistakeNot4892: + - rscadd: Adds thirst. It's like hunger. + Spookerton: + - tweak: Changing species with the changer re-adds languages required by the user's + antagonist type. +2019-06-15: + Cakey: + - maptweak: 'adjusted the bridge deck slightly:' + - maptweak: straightened the outer hallways to be more convenient + - maptweak: reorganised the meeting room to use its space better + - maptweak: matched wood types accross all offices + - maptweak: gave an extra console to the side-islands in the bridge + - maptweak: reshuffled COS and CE office contents, added disposal chutes + - maptweak: brought outer hallway decals in line with door marking standard + afterthought2: + - bugfix: SMES inverted logic fixed; should now work with terminals properly. + - bugfix: APCs now charge from empty properly again. + - bugfix: Heaters/coolers/protolathe/circuit printer work again. + babydoll: + - bugfix: Fixed mirrors not opening their menu. + - rscadd: Added yew wood, and its planks to the supply menu. + - tweak: Adjusted mahogany and walnut wood colours. + - bugfix: Corrected mahogany and maple plank loadout info. + ghostsheet: + - maptweak: Deck three toilets now doesn't suffocate people anymore. + - tweak: Hardsuit modules can now be deselected by pressing select again. + - tweak: Hardsuit plasma cutter automatically do object interaction if they're adjacent. + They will now also always fire on harm intent. + - tweak: Hardsuit flash module now flashes on unarmed attacks. + - tweak: Hardsuit flash module now has has a function to activate the flash without + targeting anything. + - tweak: Hardsuit flash now has a higher energy cost of 10 Whr per use. +2019-06-16: + Devildabeast: + - rscadd: "Adds the Bah\xE1'\xED Faith to the list of selectable human religions." + - tweak: Suit sensors can now be set by alt-clicking your uniform. + MistakeNot4892: + - tweak: Humans can now leap/tackle at a small distance based on their Athletics + skill. + - tweak: Leaping and tackling (Vox and Xenophage powers) are now invoked by attempting + to make a ranged grab - if it's not a mob you'll just hurl yourself in that + direction like an idiot. They have had timing values tweaked and require a short + channel before use. + - tweak: The various outcomes for leaping/tackling have been made dependant on skill + levels in Athletics and Combat. Check the PR for specific values. + - tweak: Split the Chaplain and the Counselor into two separate roles. Chaplain + was moved to Service and lost Medical access. + - rscadd: Replaced the defunct Sec checkpoint near the Chapel with the Counselor's + Office, it's where t'Counselor lives. + - tweak: Moved the Psychiatrist and Psychologist alt titles to the Counselor. + Spookerton: + - bugfix: Species toxins modifiers are used again, and modify internal organ damage + taken from toxins and organ failure. + - bugfix: Lava no longer deletes human and human derived mobs early when braindead. + afterthought2: + - bugfix: Borg chargers once again spawn with the cell installed. + - bugfix: Vents starting as off are fixed. +2019-06-17: + SierraKomodo: + - tweak: Brig Officer is now known as Brig Chief. + afterthought2: + - bugfix: SMES sizes and starting charge should now be back to normal. + - bugfix: Pressure regulators should once again be interactable. + babydoll: + - rscadd: Added a system to rarely spawn larger, more dangerous fauna on exoplanets. + - rscadd: A giant crab, peaceful until provoked, can now spawn on desert exoplanets. + ghostsheet: + - tweak: Plasma cutter now uses up half a charge per deconstruction. + - bugfix: Deconstruction of walls and girders now gives the appropriate materials. +2019-06-18: + MistakeNot4892: + - tweak: Dionaea can stand in water to recover thirst, and lose hydration slower + than others. + - tweak: Going prone on water turfs will now drown you. +2019-06-19: + SierraKomodo: + - tweak: Airlock control boards now have 'Autoset Access' enabled by default. +2019-06-20: + Heptagon49: + - bugfix: Fixed variables so powercells aren't duped when inserted into the coilgun. + - bugfix: Fixed coilgun examination so that it works now. + Kamiztheman: + - rscadd: Adherents aboard the Torch have finally found their crystalline toolboxes, + and have loaded their vending machine with them as an alternative to the harness. + MistakeNot4892: + - tweak: You now use grab intent only to perform a tackle/leap. + - tweak: Running off a ledge with a leap prepared (using Prepare To Maneuver) will + automatically try to jump to the next closest non-open turf. + - tweak: Mobs will now behave more like objects when thrown - they will pass tables/rails + and collide with obstacles. + SierraKomodo: + - rscadd: AI can now jump to people talking near an active holopad. + Spookerton: + - tweak: Improvised cuffs break if resisted out of a few times. + - tweak: Cuffs and improvised cuffs can now be attached to most shoes, hobbling + them. Improvised cuffs break if the wearer moves enough. + - tweak: Knives can be stored in more kinds of shoe. + afterthought2: + - tweak: Kitchen cookers, microwaves, gibbers, and seed/honey extractors are now + buildable. +2019-06-21: + Alex6511: + - tweak: Meteor now requires 15 players + Textor: + - rscadd: Adds gas sensor, air injectors, digital 3-way valves, and gutters to pipe + dispenser + - rscdel: Removes non-omni versions of filters and mixers from the game. + - rscadd: Pipe dispensers UI is updated. Pipe dispensers can now dispense normal + pipes with paint already applied to them and dispense 1, 5, or 10 pipes at a + time. + - rscadd: Atmospheric control console UI updated. You may now directly input values + instead of using plus and minus buttons. + - rscadd: Pressure tanks can now be built with steel sheets, and deconstructed. + - rscadd: Vent pumps and injectors can now have their configuration changed using + a multitool. + - tweak: Due to fuel pipes having different tolerances, they are no longer compatible + with normal pipes and need a universal adapter to connect two networks together. + - maptweak: Removes all non-omni filters and mixers from all maps and replaces them + with omni versions. + afterthought2: + - tweak: Washing machines are now buildable. + - tweak: Portable pumps, scrubbers, huge scrubbers, and hydroponics trays are now + buildable using circuitboards. +2019-06-22: + Unknown: + - tweak: The Mend psi-power now scales in effectiveness to your rank, and is available + at lower ranks. + - tweak: Autoredaction is now less buggy in regards to fixing bleeding, and somewhat + less spammy when healing you. + - tweak: Coercion now has Mind Read as a power. It prompts someone with a question + that they are compelled to answer - RP tool only. + - tweak: Blindstrike now has a visible tell when used. + - tweak: Spasm, Agony and Blindstrike have been shuffled around within the Coercive + tree. + - tweak: Latent psionics will no longer be aware they are latent psionics. + - tweak: The Probe power is now called Assay and has been moved to operant-rank. + - tweak: Made some roundstart announcements bigger/easier to read. + babydoll: + - maptweak: Moved the chapel down to deck 3, south of the holodeck. + - maptweak: Remapped the mental health section of the infirmary. + - rscadd: Added pews for the chapel. + - rscadd: Added pews to the material construction menu. They can only face south! +2019-06-23: + MikoMyazaki: + - rscadd: Traitor robots always get their emag items. + - rscadd: Cultivator drone now has an emag item, an energy machete. + - bugfix: Restores Petrov access to the Access Decrypter antagonist program. + MistakeNot4892: + - tweak: The config options RUN_SPEED and WALK_SPEED are now more accurately named + RUN_DELAY and WALK_DELAY. Default values have been adjusted to match the previous + behavior. + - rscadd: Stamina now exists. You will recover stamina fastest while well fed and + lying down, but will recover it slowly so long as you aren't actively sprinting. + Stamina recovery can be tweaked in config. + - tweak: Running will now consume stamina. Costs can be tweaked in the config. If + you run out of stamina, you will not be able to run again until it refills. + - rscadd: You can now hold shift to sprint, and release it to walk. You can set + default walk/sprint options with Set Default Walk and Set Default Run. + - tweak: The Counselor is now mildly psionic, and is a registered affiliate of the + Cuchulain Foundation for RP purposes. They have some tat in their office relating + to psionics more generally. This is hopefully going to be a way to make psionics + more broadly known ingame - see Discord/PR/other discussions if interested. + - rscdel: Removed Psychiatrist. + - tweak: Psychologist is now a Passenger alt title. + afterthought2: + - tweak: Machine interaction has been reworked further. Be ready for some issues. + - tweak: You may now install and remove machine components by hand on (some) machines + you can build from circuits. To do this, first open the panel with the screwdriver + (you may need to make sure the machine is off or other conditions are met). + Then either insert a component by clicking on the machine with it, or use a + wrench on the machine to remove the component. + babydoll: + - rscadd: Added the disorientator, a short-ranged beam weapon with effects similar + to a flash. + - rscadd: Added the disorientator to core department head closets and RnD. +2019-06-24: + Alex6511: + - balance: The meteor gamemode is now significantly more powerful. + MikoMyazaki: + - bugfix: Spells granted by The Tower deity no longer require robes to cast. + - tweak: Adds an exit button to the Deity punishment menu incase you open it accidentally. + - rscdel: Removes some stamps that shouldn't exist. (Warden, HoP, HoS, etc.) + - imagedel: Removes some now unused stamp icons. + - tweak: RIG stamp module now does the normal stamp instead of the Internal Affairs + stamp. + - tweak: Centcomm stamp (used on admin faxes) now uses the map specific boss name + for the stamp. + - bugfix: Prevents putting polytool augment tools in your pocket, behind your ear, + etc. + - tweak: RIGs will now warn you if you make them malfunction while offline, requiring + nanopaste to repair. + Mistakenot4892: + - rscadd: Added a slower version of walk, Creep intent. + NobleCaos: + - tweak: Diona Nascent Gestalts can now katamari up items as well as nymphs based + on the amount of nymphs in the gestalt + SierraKomodo: + - maptweak: Filters in atmospherics no longer connect to the wrong pipes. + - maptweak: The Corporate Liaison's office now has a gun recharger for the LPA's + sidearm. + - tweak: LPA and CL lockers now spawn with spare headsets, including bowmans. + afterthought2: + - bugfix: SMES panel opening, shieldgen deconstruction, and door autoclose have + been fixed. + - tweak: You can rotate disposals pipes now. + - tweak: Flipping disposals pipes moves them to the mirrored state (unlike rotating + twice). + - tweak: Dragging disposals pipes no longer rotates them. + - bugfix: various issues with disposals construction have been addressed. +2019-06-25: + ghostsheet: + - bugfix: Shuttle thruster now block air and fire; shuttles are more fireproof and + less gas contamination should occur. + - tweak: Shuttle engine heater, are now climbable. + - maptweak: Medical bathroom now has a mirror, for all your post radiation treatment + needs. + - maptweak: Charon atmospheric compartment has been returned to its previous state. + - maptweak: Hanger fuel bay now has a high power pump, to reduce prep time. +2019-06-26: + Cakey: + - tweak: Grass, carpets, and dirt have new icons. + - rscadd: A new system has been put in place for floor detailing, allowing for pre-made + edges. +2019-06-27: + MikoMyazaki: + - bugfix: Can no longer drag people off of something they are buckled into (e.g. + roller bed) onto an op table without unbuckling. + MistakeNot4892: + - rscdel: Removed xenophage and all adjacent code. + - tweak: You now need to hold CTRL to do a leap. + SolarK: + - tweak: Added damage limit applied by vacuum. + babydoll: + - rscadd: Swarms of enormous leeches can now spawn on shrouded exoplanets collectively + as megafauna. + - rscadd: Soap now comes in a few different shapes, sizes and colours. + - rscadd: Cleaning someone with soap will now attempt to transfer some of the soap's + reagents to that person. +2019-06-28: + MikoMyazaki: + - rscadd: Adds a chemistry recipes book to the chemist's locker that lists the medication + recipes. + Novacat: + - rscadd: Adds the dufflebag of holding, a cosmetic reskin of the Bag of Holding. + - tweak: Fixes some onhand sprites for dufflebags. + Roland410: + - maptweak: Moved the CE's suit to the bridge EVA storage. + - maptweak: Made the conference room a tad bit bigger and moved items around, gave + it a request console. + - maptweak: Removed one console on each side of the bridge and added tables instead, + gave another emergency toolbox, donut box, coffee mug, and a shortwave. + - maptweak: Gave the CL a box of cigars, bronze zippo, union card box, and made + the backroom properly boltable by the button. + - maptweak: Added disposals to the CL office. + - maptweak: Shuffled around the contents of the CE's office. + - maptweak: Gave the CO a Torch ship model. +2019-06-29: + .verarch: + - tweak: lizard horns should no longer obscure eyes. + - tweak: work gloves should fit unathi somewhat better now. + Cakey: + - rscadd: Adds pixel offsets to all mobs to give the game more feel for depth. + - rscadd: Gives all mobs a drop shadow. + afterthought2: + - admin: More things should show up in admin logs now. +2019-07-01: + MistakeNot4892: + - tweak: Vox jobs (scav and stowaway) now have soft antagonist status. + Spookerton: + - bugfix: Microwaves don't eject their components. + - tweak: dismantling a microwave empties it first. +2019-07-02: + Cajoes: + - tweak: modified adherent tool vendor to look modified + - tweak: changed adherent tool vendors vend animation from "tool_vend" to "tool-vend" +2019-07-04: + MikoMyazaki: + - maptweak: Officer's Mess is now all access. + Spookerton: + - bugfix: microwaves properly remove their ingredients after cooking. +2019-07-05: + Cajoes: + - tweak: Lava lamps have been optimized. + MistakeNot4892: + - tweak: Borers now use Dominate via ranged disarm attack and Infest via melee grab + attack. + - tweak: Language on borer messages is now more neutral. + - tweak: Borer powers now largely have UI buttons. + - tweak: Psionics can see auras around borers when they aren't inside hosts. + - tweak: Borer Dominate is now properly psionic, and respects psi-null atoms and + psi armour (ie. Coercion ranks). + - rscadd: Added neutered borers. Adminspawn only, basically defanged peaceborers. + - tweak: Significant backend refactor for borers, please report borer bugs. + afterthought2: + - rscadd: Robots now get skills set according to their module choice. + babydoll: + - tweak: Bog-standard parrots will now retaliate briefly when attacked. + - tweak: The space parrot occupying its temple in the asteroid will now retaliate + with force when attacked. Beware! + - rscadd: A giant parrot can now spawn as the grass planet's megafauna. + babydoll, Xhuis & Sunner: + - rscadd: Added the hivemind, a megafauna spawn for settled exoplanets. Beware its + attacks and strike when it's vulnerable. +2019-07-06: + Devildabeast: + - rscadd: Inscriptions can now be carved into material (gold, steel, silver, etc) + rings using sharp objects. + MikoMyazaki: + - tweak: Antagonist implants are now not visible to the bodyscanner, you can find + them by opening the implanted bodypart and examining. + afterthought2: + - tweak: If a machine is hackable, you'll now only get shown the wires panel; to + see the usual interface close the hacking hatch with a screwdriver again. +2019-07-07: + Devildabeast: + - tweak: 'Counselor now gets different psionic faculties by alternate title: Redaction + for Counselor and Coercion for Mentalist.' + - rscadd: Focus has been added as an Operant Coercive ability; grab a target while + target the mouth, then use the grab on them on disarm intent to cure the target + of various mental ailments. Power scales by rank. + - tweak: Spasm is now a Master ability rather than Operant. +2019-07-08: + Devildabeast: + - rscadd: Dog tags can now be added to the commemorative plaque to memorialize members + of the Expeditionary Corps. + afterthought2: + - tweak: The emergency supplies crate is cheaper but has no armored vests now. + mikomyazaki: + - bugfix: Clonexadone and Cryoxadone no longer reduce damage on necrotic organs. +2019-07-09: + mikomyazaki: + - tweak: RUST manual now links to the wiki guide (and doesn't teach you to blow + up the RUST) +2019-07-10: + afterthought2: + - rscadd: Machines now require power components to draw power. These can be printed + from the autolathe. The tesla link one is the default one to use. + - rscadd: Many machines now require screens and keyboards to be fully interactable. + You can print them from the autolathe. + - rscadd: To install components, open the panel with a screwdriver (after the machine + is built) and click on the machine with the component. To remove components, + use the wrench while the panel is open. + - tweak: 'Computer construction has been changed. A screen and keyboard is required + now. The order is: make a frame, wrench to anchor the frame, add 5 coils, add + the circuit, add all components as prompted, screwdriver to build. To deconstruct, + crowbar to remove components, wirecutters to cut the wire, unwrench, and apply + welder.' + - tweak: General machinery follows the same construction steps as computers now. + - rscadd: Computers now have panels, like other machines. To deconstruct a computer, + use a screwdriver to open the panel and then a crowbar to deconstruct. + - tweak: Newly built machines have the panel open. + - rscadd: If confused about this, examine the machine while standing next to it + to get information about which tools to use on it. + mikomyazaki: + - bugfix: Can now properly construct multi-tile glass airlocks. +2019-07-11: + afterthought2: + - rscadd: Shuttle consoles are now buildable. Use a multitool on the circuit while + on a shuttle to set the shuttle first! Shuttles are still not buildable; you + must do this on an existing shuttle. + mikomyazaki: + - bugfix: pAIs no longer have to fold up twice to become a card. + - bugfix: pAIs with the Universal Translator module can now speak and understand + Spacer and Gutter. + - bugfix: Mend psychic power now works properly on operant level to fix bleeding. + zaredman: + - maptweak: Adds an Interview Room to the Brig. Adjusts nearby rooms to fit. +2019-07-12: + Cajoes: + - rscadd: food in steel cans and support for canned items, added to cargo + - rscadd: Added pistachios to snix vendor + - rscadd: Added Sol Snacks vending machine. (And ethnic sol foods to go with it) + - Vendor by Chinsky + - rscadd: Added japenese snacks to the snix machine and changed it to its own vendor + with some label tweaks please welcome the painfully ethnic "Yummy Fods" vending + machine. Available in cargo + - tweak: Snix machine now more slavic in design + - rscadd: Added deoderant to lavatory essentials + - rscadd: Added chessboard to game vendor + - rscadd: Added numerous vendors to the Cargo Supply Form + mikomyazaki: + - bugfix: Printing from the file manager program now prints visible paper. + - tweak: Adds basic medical and trained chemistry skills to the Service Module. + Gives the Service Module the full selection of booze and soft drink dispenser + drinks. Significantly reduces power requirement of the drink dispenser tool. + - bugfix: Autopilot will now accelerate correctly. + - tweak: The psiblade can now hit robots instead of trying to cut their wires like + a wirecutter. + sick trigger: + - maptweak: Added tinted windows and a light switch to the chapel. + zaredman: + - maptweak: Fixed some map oversights following the Security interview room addition + (like the wall blocking the door to the FT's lab). + - maptweak: Added laundry pods to the Medical washroom. +2019-07-13: + mikomyazaki: + - tweak: Machines will now have a hint if you have forgotten to install a tesla + link. + - rscadd: Robco vendor will now vend tesla links and keyboards for building machinery. +2019-07-14: + Devildabeast: + - tweak: Makes the machete sheath its own selection under loadout; removes it from + the list of holster selections. + - rscadd: The Chaplain's bible now has "blessings;" as a Chaplain, use your bible + (or holy book) on another character to recite a prayer to them, or use the book + in your hand to read a passage to everyone nearby. If you are of the same religion, + they will receive a message putting them at ease. + sick trigger: + - maptweak: Skrell ship air alarms set to a higher, more appropriate temperature. +2019-07-15: + afterthought2: + - admin: You can now ban, jobban, and view notes on logged out mobs. This will act + on the last ckey to have possessed the mob. + babydoll: + - maptweak: Replaced all-in-one grinders in cooking areas with idiot proof juicers. + These cannot hurt your hands. + - maptweak: Replaced all-in-one grinders in laboratory areas with industrial grinders. + These can hurt your hands. + mikomyazaki: + - rscadd: Conveyor Belt and Switch assemblies can be created from the autolathe. + Use the switch on the conveyor belt to link before placing, crowbar to remove + both. +2019-07-16: + MikoMyazaki: + - imageadd: New MMI icons with damage states by Joeynosegay. + - tweak: FBPs no longer get brute/burn mod bonuses from their human subspecies. + - rscadd: Prosthetic organ fabricator can now print replacement FBP power cell organs. +2019-07-18: + Devildabeast: + - rscadd: Adds colorable beanies and rastacaps to the loadout. + babydoll: + - rscadd: The zeq queen megafauna can now spawn on chlorinated exoplanets. +2019-07-20: + Boznar: + - maptweak: Adjusted fire locks on deck one and three for better mobility and logic. + Devildabeast: + - rscadd: Adds several Chaplain religious insignia to the loadout, representing + various faiths. + - rscadd: Adds Sikhism to the list of human religions. + - rscadd: Adds several preset religious books to the loadout. + - rscadd: Adds Shinto to the list of human religions. + Funce: + - bugfix: Bad Chefs no longer make runtimes with the juicer. + Rain7x: + - tweak: Increased the chances of the mail event; and of its rare gifts spawning + SierraKomodo: + - bugfix: Masks can now properly hide ear and eye slot items if configured to do + so. + WezYo: + - bugfix: renaming paper no longer runtimes + YodaDoge: + - bugfix: Farmbot can now harvest plants and remove dead plants, again. + afterthought2: + - tweak: Adding capacitors to a machine buffs the battery backup's charge rate. + - tweak: Borg chargers recharge faster now. + - bugfix: Toggling APC power manually with exotic mapped apcs should work properly + now. + ghostsheet: + - maptweak: Hanger Atmospheric Storage room has been added to the hanger. This replaces + the unused refinery slot near the fore of the charon. + - bugfix: Restore button pressing sprites to their previous states. + - bugfix: Cell charger will now work in Z-level transition, and they now have proper + sprite charge bar. + - rscadd: Cells now have a red charge state which is below 25% charge. + - tweak: Suit cyclers repair function is now default for all suit cyclers. + - bugfix: Duct tape space suit repairs now works properly while suits are being + worn. + - rscadd: Mining drill head now indicate how full they are. + - tweak: Mining drill head logic change slightly to be more informative. + - tweak: EVA airlock on deck 3 now has all its access set to ACCESS_EVA. So anyone + who can enter the room can use the airlock. + mikomyazaki: + - tweak: Can no longer adjust your Chameleon Item's appearance while restrained + or disabled. + - maptweak: Toxins lab now has a button for its blast doors, labels for its pumps, + chamber now has a gas sensor, and more lighting. + - tweak: Can no longer do surgery through thick clothing, suits, RIGs, etc. You + will need to remove the clothing before you can make incisions. + - bugfix: Female characters will now be able to use the roll down and roll sleeves + verbs without their jumpsuits disappearing. +2019-07-21: + SierraKomodo: + - tweak: Blob resistance values have been tweaked. Cores are now weak to fire and + laser, and strong to brute, like green blob. + - tweak: Blob shielding mass regeneration rate has been very slightly reduced. +2019-07-22: + MikoMyazaki: + - rscadd: Adds Vecuronium Bromide, a paralytic drug. + afterthought2: + - rscadd: Vending machines are now constructable using circuits, and also can be + deconstructed. Drag the container they drop to another vendor of the same type + to restock it. + - tweak: To add things back to vending machines, you now must be on help intent + (useful for tool machines). + zaredman: + - maptweak: Moved and remodeled Investigations Office, Forensics Lab, and Evidence + Storage. + - maptweak: Slight adjustments to Brig Chief's office to better accommodate the + redesigned processing room. +2019-07-23: + CrimsonShrike: + - rscadd: Exosuits have been completely refactored. Make sure to check your skills + before joining the round. + - rscadd: You can now slide ID across a PAI to grant them your access. + Devildabeast: + - rscadd: Adds a unique holosign to the Chapel airlock. + - rscadd: Adds Jainism and Taoism to the list of human religions. + - rscadd: Adds two new chaplain insignia for Jainism and Taoism. + Eonoc: + - tweak: Tweaks Vox codex entry + - rscadd: Add Vox shriek audible emote + afterthought2: + - tweak: Manually toggling apc settings will no longer raise alarms. Also applies + to some mapped APCs. + ghostsheet: + - tweak: Electron reservoir will now shock you upon bumping/getting thrown into + it. + mikomyazaki: + - tweak: Supermatter manual will now show you the wiki page for the Supermatter + Engine. + - bugfix: Underwear will now no longer be kept on species change, if the species + you are changing into cannot wear underwear. +2019-07-24: + Chinsky: + - tweak: Earmuffs now actually muffle sounds. You'll also not hear spoken things. + - rscadd: Headphones can actually play music now. Drag onto yourself when worn in + ear slot to access menu. They act as earmuffs when music is playing. + mikomyazaki: + - bugfix: IV Bag construction option name changed from 'plastic bag' to 'plastic + IV bag' so it is different from the other 'plastic bag'. +2019-07-25: + WezYo: + - tweak: Aiming point blank at someone will actually aim at them now + YodaDoge: + - tweak: Order Ranks of Jobs ascending so the lowest rank is selected by default + afterthought2: + - rscadd: An overmap-capable shuttle can now catch/grapple another overmap-capable + shuttle currently moving on the overmap. You do this by moving to an appropriate + landmark on the shuttle console. + - rscadd: If a shuttle is grappling another shuttle, it cannot move on the overmap; + it will be moved by the other shuttle. + - rscadd: If a shuttle is being grappled by another shuttle, it cannot make shuttle + jumps until the grappler has left. + - tweak: Ships within ships count towards vessel mass now, meaning you'll accelerate + slower with them landed/attached. + - tweak: All greentext for antag objectives and game modes has been removed. + babydoll: + - tweak: All hivebots now have increased health. + - tweak: Increased hivebot megafauna 'hivemind' damage output. + - tweak: Reduced hivemind vulnerability duration. + - tweak: Reduced hivemind cycle duration. +2019-07-27: + zaredman: + - maptweak: The larger portion of the Security Armory is now Equipment Storage. + Security Staff now have access to this room. +2019-07-29: + Chinsky: + - rscadd: Added a medical health checkup to Reports program for all you thirsty + doctors + CrimsonShrike: + - rscadd: Exosuits can now be repaired without using a recharger using either a + welding tool or cable coil depending on damage. + Devildabeast: + - rscadd: Adds Hephaestus Titan, a bulky full-body prosthetic, and Morpheus Atlantis, + a skeletal head prosthetic, to chargen. + Eonoc: + - bugfix: Fixes the Vox spacesuit light overlay from a grey hat, to just nothingness, + since I didn't feel up to making new sprites for it, and most of the suits have + glowy-looking bits anyway. + Rain7x: + - tweak: Makes the "boot selection" in loadout available to civilians only. + Spookerton: + - tweak: Prosthetic limbs previously named Grayson are now named Shellguard. + mikomyazaki: + - tweak: Unathi brains will now not accept being MMI'd. + - tweak: Unathi may no longer have prosthetic internal organs attached. + - tweak: Unathi may not start the round as FBPs. + - tweak: Unathi may no longer select assisted or synthetic internal organs on round-start. + - maptweak: Vox ship burn chamber now operates properly (fixes incorrect injector + settings) + - maptweak: Vox ship burn chamber can no longer cause the ship to self-destruct + due to temperature melting the windows, since they have been replaced with walls + that handle up to 12,000K. + - maptweak: Adds a temperature/gas sensor to the burn chamber. + - maptweak: Vox ship ignition switch now isn't hidden under a light. +2019-07-30: + Rain7x: + - tweak: Medical & Engineering trainees can now select their department specific + webbing & drop pouches; and medical trainees now have access to their department + armbands. + mikomyazaki: + - tweak: Senior Engineer now gets access_network, allowing them to use the NTNet + Diagnostics and Monitoring program and various command line tools. + - tweak: Access hacking antag program can now hack access_network, if the antag + has master level IT skill. + - tweak: The NTNet Quantum Relay in telecomms will now keep physical logs of network + activity, wiping the NTNet Diagnostics Program logs will not affect these, and + they cannot be accessed remotely. The portable drive can be removed via a UI + eject button and the data imported from it into a modular computer. + - maptweak: Telecomms storage room now has a couple of spare portable hard disks. +2019-07-31: + Devildabeast: + - rscadd: Adds colorable bracelets to the loadout. + WezYo: + - bugfix: Requesting pAI personalities works now +2019-08-01: + BlueNexus: + - rscdel: The Security cyborg module has been disabled. + afterthought2: + - bugfix: Chloral hydrate is once again effective; this applies to sleepy pens. + babydoll: + - rscadd: Added the antlion and antlion queen to desert exoplanets. + - tweak: Moved the giant crab megafauna to snow exoplanets. + mikomyazaki: + - bugfix: Nacelle control switches in the engineering monitoring room will now work. + - bugfix: Fixes issue that prevented organ transplants. +2019-08-02: + CrimsonShrike: + - rscadd: Added 2 new exosuit propulsions. The quadlegs and the armored tracks. + - tweak: Speed tweaks to exosuit legs. + Noble Caos: + - rscadd: Allows nascents gestalts to add human-sized mobs when the gestalt contains + 20 nymphs. + babydoll: + - tweak: Renamed all tasers in their various forms to electrolaser. + zaredman: + - tweak: Re-adds the Torch variant of the Sec-Tech and actually stocks it with more + gear. +2019-08-03: + Boznar: + - maptweak: Nacelles now have air alarms, fire alarms, and fire doors. + Nirnael: + - bugfix: Fixes bug in using a new apc frame on a broken apc to repair it. + Rain7x: + - tweak: Tweaks the event announcement messages to be more tone-neutral & standardizes + the announcement header + WezYo: + - tweak: Attaching a photo to a newscaster story will no longer remove it from your + hand + afterthought2: + - tweak: The shield generator has been reworked. It is now much more expensive to + keep the shields on continuously, and for large shields it's likely not viable. + - rscadd: The shield generator now has an idle and active state (as well as the + off state). In the idle state, it consumes limited power and does not generate + a shield. In the active state, it consumes a lot of power and produces a shield. + - rscadd: If an idle generator is toggled on, it takes a short amount of time to + spin up to active state. If an active generator is toggled to idle, it will + switch to that state instantly. + - rscadd: There are several levels of idle power usage that can be selected. Higher + power usage decreases the spin-up time proportionately. + - rscadd: The shield generator takes time to adjust the radius of the shield. The + radius will not be adjusted while the shield is active. + - tweak: The shield generator's power storage has been vastly expanded. + - tweak: The shield generator's field integrity is now tracked separately from the + power storage (it's determined by the amount of power stored, up to a threshold). + mikomyazaki: + - tweak: Radiation collectors are now capped at 500kW output at 250Bq radiation. + They are more efficient at lower radiation levels. + - tweak: Radiation collectors will have variable fuel usage, capping out at 250Bq + radiation. Fuel usage increased significantly (1-10x depending on radiation + levels) + - tweak: Radiation collectors will now break from high radiation levels (500Bq) + as well as temperature, they will display a warning and play a warning sound. + - maptweak: Stowaways can no longer spawn in the incinerator room, which they cannot + leave. + - bugfix: Fixes inconsistent icon names for female jumpsuit icons. Should work for + rolling down / roll sleeves for all jumpsuits/suits now. +2019-08-04: + Bxil: + - tweak: Inflatables now have 1 second delay. + Chinsky: + - rscadd: Adds 'Codex' verb that shows user the 'frontpage' of codex, with links + to search / index / categories. + Eonoc: + - rscadd: Adds a Vox RIG. Same statline as the Industrial RIG, but with full temperature + and radiation resistance. Vox had no way to scavenge radioactive or volcanic + planets up until now. + - rscadd: Adds flux cannon. Essentially a Vox AEG, but with the lasers doing brute + damage, and shock mode replaced by a mode that scatters low damage pellets in + a burst. + - rscadd: Adds sonic cannon. A vox stun rifle, with a mode that uses up all the + gun's charge to push, deafen, and dizzy an opponent. Ear protection such as + helmets and earmuffs will negate the deafening, and reduce the dizziness. + - rscadd: Added the associated projectile types for both above, obviously. + - rscadd: Added two new firing sounds, spike.ogg and eLuger.ogg + - tweak: Changes spike launcher firing sound to spike.ogg + - tweak: Stealth buff to Armalis to make their large size reflected more mechanically. + - tweak: Changes the Vox species check on Vox guns to make the guns hiss and jump + out of your hands. + WezYo: + - rscadd: CSO now has maint access + - rscdel: Removed the discard verb from playing cards + - rscadd: Added the ability to pick a card by clicking it with an open hand + comma: + - tweak: Blunt yet sufficiently strong weapons can now pop inflatables + mikomyazaki: + - bugfix: Yeosa unathi have correct job restrictions now. +2019-08-05: + mikomyazaki: + - tweak: Resisting will auto-cancel resting. +2019-08-07: + BlueNexus: + - tweak: All non-total radiation resistance values for suits etc have been halved. + - tweak: The Supermatter, nuclear reactor, R-UST, PACMANs and other radiation sources + which were too weak to be relevant have been buffed. + - tweak: Radiation sources that were deemed to be too strong have been nerfed, such + as garbage planets. + - tweak: Grilles have had most of their radiation resistance removed. + - tweak: Low walls and windows have had their rad resistance halved, so they add + up to a full 100% instead of 200%. + MistakeNot4892: + - rscadd: Added a more involved butchery system. + - rscdel: Removed stowaway. + mikomyazaki: + - maptweak: Double sets of windoors now have only the interior windoor at department + reception desks. + - bugfix: Low wall frames deconstruct into 3 steel sheets, which is the amount required + to build them. + - maptweak: Robotics central windows are now not tintable, surgery area still is. + - tweak: Autoinjectors now have a timer for use on other people, instant for yourself + OR on incapacitated people with any skill level. They take a third the time + compared to a syringe. +2019-08-08: + Cajoes: + - maptweak: Reworked the abandoned shooting range space into additional lavatory + facilities and a sauna. + - rscadd: Adds a wooden bucket +2019-08-10: + Bxil: + - rscdel: The asteroid will no longer spawn at the Torch every round. + mikomyazaki: + - bugfix: Relocating limbs will now properly always work when you have high enough + medical skill. +2019-08-12: + Boznar: + - maptweak: Adds shutters to the exterior windows of hydroponics, aft bubble, and + lounge. + Chinsky: + - tweak: Medical Technicians can no longer have Anatomy skill at Experienced or + higher. + - tweak: Surgery skill reqs and penalties got beefed up. + - tweak: Most surgery step require both Trained Anatomy AND Expert Medicine. + - tweak: Delicate' surgery steps (basically inside organ stuff) require both Expert + Anatomy AND Expert Medicine. + - tweak: Penalties to success chance for missing skills were jacked up mercilessly. + Unless you're missing 2 or less skill levels you're not going to succeed, sorry + bud. + - tweak: Physicians now start with Expert Medicine, free skillpoint pool lowered + by its cost. + - tweak: Robotic steps require Trained Complex Devices. If there's meat bodyparts + involved (e.g. installing into one), need both Trained Complex Devices and Trained + Anatomy + - tweak: Slime surgery steps require Trained Science. + Piccione: + - tweak: Heads of Security are now are better screened to ensure loyalty to the + SCG + ghostsheet: + - tweak: Butterfly knife damage is now slightly lowered. Still pretty deadly. + mikomyazaki: + - bugfix: Airlock bolt buttons (e.g. SMES room and engine hatch doors) will now + work. +2019-08-13: + Terror4000rus: + - rscadd: You can take a pill from pillbottle by using it. + YodaDoge: + - tweak: reduced shield power usage + ghostsheet: + - tweak: Due to the space related mortality rate of our recent expedition, the EXO + has increased funding to restock EVA equipment. There are now 5 jetpacks and + 3 cooling units in EVA on deck 3. + mikomyazaki: + - bugfix: Resetting a tech you have no levels in at the RnD Server will no longer + give you 1 in that tech. + - rscdel: Removes Arcane Tech, as it did nothing. + - rscadd: Worn RIG suits will now be charged if you walk into a cyborg recharger. + If you have an internal cell (FBP/IPC) then that will charge first. + - bugfix: Airlock access buttons will now work even if the area they are in has + no power. + - rscadd: Traitor Robots will get a verb 'Reset Identity Codes' that will remove + their external camera connection, robot console connection and lawsync status. + - bugfix: Fire axes can now attack unpowered airlocks on harm intent, regardless + of the damage level of the door. + - tweak: It now takes several hits to get through an undamaged door with a fire + axe. +2019-08-14: + MistakeNot4892: + - rscadd: Added a new human subspecies, the boosters. + mikomyazaki: + - tweak: Illegal Tech is renamed to Esoteric Tech. Producing items with this tech + & having esoteric tech levels is not illegal, however possession of those items + may be if they appear on the contraband list. + - bugfix: Petrov RnD console will start the round able to access the Core RnD server + data and sync with the rest of the Torch. + - bugfix: Elevator will no longer get stuck when you give it multiple move orders + via the elevator panel or the buttons on each floor. It will wait for nine seconds + on each floor and then move to the next one in the list. + - rscadd: Surveyor Flying Robots now have an emag item, an energy machete. +2019-08-15: + Cajoes: + - tweak: Improved kitchen utensil visibility on grey surfaces. + babydoll: + - rscadd: The drake megafauna can now spawn on volcanic exoplanets. + mikomyazaki: + - rscadd: As the Torch now starts at random coordinates, the Torch round-start sensor + scan will list these coordinates so it is clear where the bearings point from, + incase you forget / join the round late. +2019-08-16: + mikomyazaki: + - bugfix: RnD server control consoles will only connect to things on connected Z-levels. + So the Torch won't pick up away-site RnD servers only the RnD server control + console. + - tweak: Robots can open the door control menu again, like AI. + - tweak: FBPs don't get affected by their species slowdown stat, positive or negative. + - tweak: Robotic eyes ignore your species flash modifier. + - tweak: Robotic eyes don't get species darkvision bonuses (e.g. from Space-Adapted + Humans) +2019-08-17: + ghostsheet: + - maptweak: Torch's fuel pipes have been slightly remapped into safer positions + with parts segmented by automatic shutoff valves to prevent leakage. The fuel + lines has also been removed completed from the SM heating element (although + the HE pipes are still there) and they should now be able to survive an SM delamination. + To balance out these safety features, fuel line pressure has been doubled to + increase the risk of bodily harm. + mikomyazaki: + - bugfix: Glasses that apply a vision overlay (mesons, tactical goggles, etc.) will + no longer function when you are using a sensor console to view the overmap. +2019-08-19: + Chinsky: + - tweak: Can no longer sample plants with machet. Need an edged weapon of size 'small' + or 'tiny'. Normal size and above will chop as usual now. Harm intent also forces + chopping instead of sampling. + - tweak: Can alt-click vines when holding normal-sized blade (machet) in hand to + chop them down. It'll take a short time, faster if you have Trained botany skill. + Basically less chat-spamming alternative to just bashing them down. + mikomyazaki: + - bugfix: Ghosts can't interact with space heaters anymore. + - bugfix: Stacks of one sheet will now not be deconstructable twice in the deconstructive + analyzer. +2019-08-20: + Devildabeast: + - bugfix: Mules will no longer spawn with psi-dampener implants. + MistakeNot4892: + - rscadd: Added a new human subspecies, the Mule. Mules can be merchants or submap + roles. + mikomyazaki: + - bugfix: Space vine event will now never have invisible vines. + - bugfix: Surveyor drone now has skills. +2019-08-22: + ghostsheet: + - rscadd: SMES chance to discharge is now skill based, with 50% increase at unskilled + and 50% decrease at master. + sunofang: + - maptweak: Revamps the yacht into a prettier state. +2019-08-23: + Boznar: + - maptweak: Adds large vents to both sides of the engine room. These can be opened + with a button in the emergency box in the control room. + - maptweak: Renamed all of the glass box emergency buttons and added descriptions. + - maptweak: Engine hatch bolt control button has been moved to the inside of the + engine room next to the hatches. + Cajoes: + - rscadd: Commissary now spawns with a vending machine. + - tweak: tweaked the sauna thermostat and auxiliary space heater to bring the room + up to a comfortable 348.15 kelvin. Which I am reasonably sure the human body + can tolerate. For a while. + MistakeNot4892: + - rscadd: Enhanced an opossum. + mikomyazaki: + - bugfix: Adherents now properly get their speed bonus again. +2019-08-24: + Anticept: + - rscadd: Water tanks are now immune to atmospheric temperatures + - rscadd: Fire extinguishers can be filled from sinks! When full, they are instead + washed. + - rscadd: Fancy progress bar when washing in a sink! + - bugfix: Slightly refactored sink washing code. if a user interrupts the process, + it will not continue processing the item or most item effects. + ghostsheet: + - rscadd: Floodlights are now constructable circuit machines. + - rscadd: Floodlights can now be upgraded with capacitor components, for increased + brightness with a higher power cost. + - bugfix: Floodlights also work in areas without APC. +2019-08-26: + Boznar: + - maptweak: Shield generators have been consolidated to a single shield bay with + its own substation. Bridge deck shield has been left in place to account for + all 5 shield generators. Shields also have their own SMES units so that configuring + each individual shield can be done more precisely. + - maptweak: Bluespace drive has been remapped to be prettier. It is no longer considered + a maintenance area and wont spawn drones or trash. + - maptweak: Deck two saferoom has been removed to make room for these changes. + Plaguewalker: + - imageadd: Adds 3 new FBP variants for Morpheus - Blitz, Airborne, and Prime +2019-08-27: + Bxil: + - tweak: The Bluespace Artillery has been rebranded to Obstruction Field Disperser. + Cajoes: + - tweak: Ascent Cutter has been updated. + ghostsheet: + - bugfix: Fixes various bugs for emergency fire shutters construction/deconstruction, + such as going invisible, returning incorrect amount of metal and skipping steps. + - tweak: Emergency fire shutters will now have a delay for welding them. +2019-08-30: + CrimsonShrike: + - bugfix: Fixes exosuits being able to use all modules at any range. + Devildabeast: + - rscdel: Removes the Biomechanical Engineer as a role. + - tweak: Gives the Roboticist trained Anatomy by default. + Rain7x: + - tweak: The sleepy pen now contains Vecuronium Bromide instead of Chloral Hydrate. + WezYo: + - bugfix: Ghosts can no longer interact with pagers + ghostsheet: + - bugfix: Fixes toolbelt overlay. Putting tools into toolbelt will now show up the + belt icon again. +2019-08-31: + BRAINOS, Plaguewalker: + - rscadd: Ported new prosthetic types from Aurora; Bishop Rook, ZH Spirit, Xion + Econ + BlueNexus: + - rscadd: Sauna heaters and reagent sublimators can now be emagged to make them + accept any reagent. + Bxil: + - rscdel: The OFD can now only shoot at overmap events. + WezYo: + - rscadd: Skrellship crew can now be selected as provocateur +2019-09-01: + Hubblenaut: + - imageadd: Adds new sprites for the TEGs, made by spriter who does not want be + named. + Zenithstar: + - maptweak: Maintenance near the shield bay now has radiation shielding. + babydoll: + - maptweak: Replaced all the various depreciated shield rooms. + - maptweak: Split the bluespace drive chamber into two areas for air alarm accuracy. +2019-09-02: + babydoll: + - tweak: Reduced attack frequency and damage for nearly all castes of asteroclast. + - tweak: Asteroclast nucleus' values change as they're damaged. They become more + aggressive, but more vulnerable to attack, and spend more energy regenerating + than trying to expand. + - rscadd: Added incense cones. + mikomyazaki: + - imageadd: Adds the 'Trimmed Right Sidecut' hairstyle. +2019-09-03: + CrimsonShrike: + - rscadd: Adds second robo slot since biomech is now gone and workload is too high. + Devildabeast: + - rscadd: Adds a Morpheus Cyberkinetics labcoat to the loadout. + Piccione: + - rscadd: Added Crosses buildable out of Material Sheets. Can also be found in Loadout. + Rain7x: + - rscadd: Added "Resident" Physician Alt Title + - rscdel: Removed "Trauma Surgeon" Alt Title +2019-09-04: + CrimsonShrike: + - rscadd: Mapped a basic exosuit to the cargo bay. +2019-09-06: + BlueNexus: + - tweak: Default Cyborgs no longer have stunbatons +2019-09-10: + Boznar: + - maptweak: Skrell Air alarms are now set to 40 degrees instead of 65 degrees. Server + air alarm added to Skrellship engineering bay at 20 degrees. + Chinsky: + - tweak: You can now grab yourself. Can't grab grabbing limb (e.g. right arm with + right hand), can't throw yourself, can't nab yourself. Otherwise you can do + whatever you want, like inspecting limbs, or covering your own eyes, or dislocating + your leg as a party trick. + Nirnael: + - rscadd: Adds pencode tags [pre] [fontblue] [fontred] [fontgreen], with closing + [/pre] and [/font] universal for the three fonts. They only work digitally with + nanoword, emails, report editors and direct txt files. Font color gives color, + [pre] gives monospace font and preserves whitespace spaces only and not tabs, + e.g. for ascii art. + - rscadd: Gas analyzers now show total moles, total volume and moles per gas, check + codex for more info. + - bugfix: Fixed robot inventory not updating automatically when dropping items which + are stored back into it. + - bugfix: Saving emails to a txt file on disk now works correctly and can be printed + with the new tags. +2019-09-11: + Spookerton: + - tweak: Added guidance on law priority and conflicts to the text shown when laws + are listed. +2019-09-12: + WezYo: + - rscadd: Adds new paperwork commands to the pen codex + ghostsheet: + - rscadd: Gas thruster is now modifiable machine. + - bugfix: Gas thruster now hooks up to their ship when built. + - rscadd: Gas thrusters now has a boot up time. + - rscadd: Gas thruster can be upgraded with matter bin for extra fuel intake volume + and less boot up time or capacitor for energy efficiency. + - rscadd: Gas thrusters has an increased energy usage on idle (6 Wh per tick so + every 2 second) and 10 Wh per burn. So please keep them off unless you need + them, for that same reason all thrusts starts offline. + - tweak: Guppy's mass and max speed has both been increased. + zaredman: + - tweak: Wizard and Ninja now require a minimum of 5 players. +2019-09-13: + babydoll: + - rscadd: Added geese, available in the supply menu. +2019-09-14: + BlueNexus: + - tweak: Tripled the damage mobs take from being in low pressure + afterthought2: + - admin: Some rudimentary spam prevention has been added. Offending users will be + kicked and noted, and you will receive notice of this. If you see patterns of + abuse, further admin action may be warranted. False positives due to overly + aggressive client macros may be possible. +2019-09-15: + WezYo: + - bugfix: Turning on a floodlight will no longer make it invisible + babydoll: + - experiment: Disables macro use. +2019-09-16: + Anticept: + - bugfix: Rigsuit codex entries now read the correct armor values for each piece. + Has no effect on damage calculations, that has always worked correctly. + - tweak: Medical voidsuit descriptions no longer imply that they have some incredible + radiation resistance, but it's still relatively good to most things in the game. + - tweak: Medical voidsuit bomb resistance values increased slightly. It's still + not a bomb suit! +2019-09-17: + Rain7x: + - rscdel: Removed old Research Director gear from the CSO locker +2019-09-18: + Chinsky: + - tweak: Inflatables now have maximum pressure difference and maximum temperature + they can endure. Currently it's 5000 kPa pressure difference and 5000 K temperature. + Every second or so when they're in worse condition than that it'll take damage. + You can patch them once with duct tape but otherwise just consider more permanent + solutions. + Rain7x: + - tweak: Members of the exploration department can now select Science Goggles, Botany + Gloves, and the Brown Webbing Vest in loadout + - tweak: Non-Civilian pilots can no longer take the EXO Flightsuit + - tweak: Webbing names now reflect their color, rather than their department. + bitMuse: + - rscadd: Added an empty autoinjector schematic to autolathes. +2019-09-20: + Rain7x: + - bugfix: The supermatter grenade box now has a working icon and is no longer invisible. + SparklySheep: + - rscadd: Adds in the fake moustache as a cheap 1 crystal item for traitors. It + will hide your identity, but that's about it. +2019-09-21: + Rain7x: + - rscadd: Added the biowaste disposal cart, for disposing of organs. + ghostsheet: + - bugfix: Boosters randomised speed has been fixed, no more indefinite speed malaise. +2019-09-23: + Imienny: + - tweak: Change heavy armor plate slowdown from 1 to 0.5 + babydoll: + - tweak: Sunglasses no longer provide full protection from handheld flashes, instead + halving their effect. + - tweak: Green glasses now have prescription lenses. + bitMuse: + - rscadd: Added reagent grinder, chemical heater, and chemical cooler to Unishi + Chem Lab. +2019-09-24: + Chinsky: + - rscadd: Added vitals monitor machines. Drag them onto people to 'hook' them. They + will display general state of brain activity, pulse and breathing, with blinky + warnings if something's wrong. + - maptweak: Replaced computers by optables with vitals monitors. + - rscadd: Chemical explosions (welderfuel and ANFO) now produce a bunch of heated + gas during explosion. + - rscadd: Welderfuel produces N, NO, NO2 and a pinch of Hydrogen for flavor + - rscadd: ANFO produces CO2, nitrogen and water + - tweak: '''Settled'' exoplanets have been renamed to ''ruined'' for 23% less confusing.' + NanakoAC: + - tweak: Adds bottled water to gym vendor + - tweak: Adds bottled water to ration crates + adamkad1: + - rscadd: Variation of artery repair surgery for Kharmaani + bitMuse: + - rscadd: Added gyrotron recipe. + - rscadd: Changed minimum fire rate of gyrotron from 1 to 2. Nerf. + ghostsheet: + - rscadd: Pipe dispenser is now a modifiable machine. + - rscadd: Pipe dispenser circuit is now a printable research design. + - bugfix: Disposal outlet will now properly eject objects outside of shuttles + - tweak: SMES installing/removing components are possible while active. They still + need to have their safety wire disabled but this will allow for more sabotage + or anti tampering opportunity. + - tweak: SMES discharge will now call electrocution (with some minor nerfs so it's + little less lethal), so insulation and armour will be taken into calculations. + - tweak: SMES will now shock people upon pulsing/cutting the grounding wire, similar + to vending machines. The severity is based upon the SMES's powernet and is reduced + with the safety wire on. + - tweak: Stun acts (from weapons) will now take existing pain of limbs and any painkillers + into account. + - tweak: Stun acts will now rely on pain to calculate, so damaged limbs will go + down to stuns easier. It also means it longer affect robotic limbs or anything + that can't feel pain. Ya IPC! + - tweak: Painkillers will now resist some stun effect due to them blocking pain. + - tweak: Stun weaponry now deals a very small amount of burn for flavor, 1-3 burn + depending on the gun. + - bugfix: Stun act will now work properly on body shots, bringing down targets with + enough pain on chest/head/groin shots. + - tweak: Robolimbs will no longer have blurry eye/ stutter or create adrenaline + upon being hurt. + - tweak: Adjusted some stun and shock duration, lowering most of it. + - tweak: Shock has a lower tier stun effect, stunning people that takes 10-15 damage + for 2 seconds. + - tweak: Shock and Stuns weapon inconsistency and damage has been adjusted. + - tweak: Shock will now activate a weak local EMP on the limb they hit (if they + deal more than 10 dmg), frying any implants, augments or synthetic organs inside + and also the limb they hit. They will neutralise an IPC/FBP after 3/4 shock + shots to the chest, frying their microbattery. + - tweak: EMP on robotic limbs will make them fail. EG. as Shock beam to a roboleg + will cause it to collapse. + - tweak: EMP now deals more damage to internal synthetic organs. + - tweak: Implants are now vulnerable to EMP if they weren't already. EG, shock beam + might fry, disables or activate the implant. + - tweak: Security and Engineering (not atmospherics) voidsuit is slightly more insulated + against shocks and stuns. Still not as a good as a hardsuit. + - tweak: Light bulbs can be taken down without gloves, on non help intent, for extra + badassery. + - tweak: Wall toss will now take armor calculations into account. + - tweak: Rejuvenate will now restore stamina. + - bugfix: APC construction has been fixed, they will now be deconstructable even + when broken. + - tweak: Space adapted human oxygen pressure requirement has been lowered to 14 + kPa. + - tweak: Grav adapted human oxygen pressure requirement has been increased to 18 + kPa. + - tweak: Grav adapted strength has been increased to high, this means they get reduced + slowdown for wearing or carrying heavier gear, eg. dufflebags, voidsuit. Still + slower than human in most regards. + - tweak: Unathi oxygen pressure requirement has been increased to 20 kPa. They + need more oxygen to support their extremely robust metabolism. +2019-09-25: + MrKicker: + - tweak: Command announcments are now multi-line. + - tweak: Command Announcements can now be multi line to allow for clever formatting +2019-09-26: + Boznar: + - maptweak: Adds mineral processing, chemistry, and cages to the ascent seedship. + - rscadd: Adds voidsuits for Alates to replace the hardsuits as base gear. Hardsuits + can still be granted to alates at the Gyne's discretion. Icons and code credit + to Zuhayr/Loaf/MistakeNot. + Chinsky: + - rscadd: Using xenolife scanner on a stasis cage will now scan the animal inside. + CrimsonShrike: + - rscadd: Exosuit pilots can now manage their inventory, throw items and some other + minor actions so long the cockpit is open. This prevents usage of exosuit modules. + Imienny: + - tweak: Ammonia now work like Dexalin Plus for Vox instead of removing oxy loss + - tweak: Nerfs Vox breathing mask to filter out only oxygen + - tweak: Updates Vox alien mask's filtered gases list + - rscadd: Adds inaprovaline autoinjector to Vox survival kit + - tweak: Change Vox minimum/maximum age from 17 - 70 to 1 - 100 + - tweak: Vox get +8 skill point bonus instead of bonus based on their age. +2019-09-27: + Chinsky: + - tweak: Made modular computer consoles proper machines instead of big items. Report + any odd behavior. + - tweak: Modular computers are now constructed via normal computer frames, requiring + a circuitboard and various generic machinery parts like input/output controllers + like other computers. + nearlyNonexistent: + - tweak: Janitor module synths now have a welding tool, to remove graffiti with. +2019-09-28: + EcklesFire: + - tweak: Made EC scarves for all uniforms, not just Dress. + comma: + - rscadd: Adds loadout accessories that are locked behind Trained skill level. + ghostsheet: + - tweak: Rescue rig can now carry an inflatable dispenser in its suit slot. + - tweak: EVA and CE rigsuit's offline slowdown has been increased to standard offline + slowdown. + - tweak: Mining prep, and prospector's locket has its round start equipment changed. + - tweak: Mining voidsuit has its laser resistance lowered and its bullet and energy + resistance rounded up, to be more a well rounded suit. + - tweak: The industrial rig has its tint lowered to moderate. +2019-09-30: + Chinsky: + - tweak: Windows now have much less health. + ghostsheet: + - maptweak: Most interior windows inside medical are now non-reinforced windows + - tweak: Full-tile glass are now tintable whereas border windows are not. +2019-10-01: + ghostsheet: + - bugfix: Overmap shuttles can now dodge meteors again. + nearlyNon: + - bugfix: Certain IPC monitor options will no longer shapeshift you into a Morpheus + monitor head. +2019-10-03: + Boznar: + - maptweak: Lepidoptera has been remapped to be more compact for planetary landing. + Extra space has been utilized for additional rooms. + - bugfix: Ascent airlocks will now all cycle and dock correctly. + - maptweak: Ascent seedship walls made more uniform. Keel is composed of reinforced + walls, while the outside is regular walls. The Tricoptera has been tweaked to + prioritize form over function. + Chinsky: + - rscadd: Adds entries for skills to Codex. They have description and what levels + of skill mean. + - rscadd: Minimum character age for jobs is now code-enforced. You may have to adjust + your chars to be able to join as your preferred job. + Rain7x: + - tweak: The labcoat can only be selected in loadout if your job would realistically + require it. It has also been removed from the medical wardrobe. + WezYo: + - bugfix: Fixed janibot and medibot crafting + comma: + - tweak: Larger internal organs are now more likely to get hit than larger ones + - tweak: Energy-based weapons are now in many cases less likely to cause internal + organ damage than ballistic weapons (based on damage output) +2019-10-04: + Rain7x: + - rscdel: Several alt tiltes have been removed. + - tweak: The job Chemist is now called Pharmacist. +2019-10-05: + Flying_loulou: + - rscadd: Creates the red ("grunt"), Yellow (Senior) and White (Chief) Damage Control + Helmets + - rscadd: Damage control helmets have now been issued to the engineering department, + they can be found in the engineer's personnal equipment lockers. + WezYo: + - bugfix: Fixed transferring reagents between beakers +2019-10-06: + Chinsky: + - tweak: Thrown items will go down the ladder if they hit it. + - tweak: If you use Move Up verb, it will try climbing random climbable turf above + if you couldn't just straight up move up. +2019-10-08: + PhosphoricPanda: + - tweak: Stabilization kits now have a radiation pouch. + nearlyNonexistent: + - rscadd: Non-Branded Spirit Boards. Gather around in the dark with another friend, + and move the planchette around. Now only works in cult rounds, otherwise just + is silly fun. + - tweak: Steaks, kabobs, and a few other recipes use cutlets instead of full-on + slabs of beef. (Plain steaks don't due to the sprite) +2019-10-10: + Chinsky: + - tweak: Stack recipies that you don't have skills for are now visible too, marked + with red warning label. You can even attempt them, wasting resources almost + certainly. +2019-10-11: + Cakey: + - bugfix: Fixed airlock paint vanishing when interacting with unpowered airlocks. + ghostsheet: + - tweak: Default aim mode allows all movement, items an radio uses. +2019-10-12: + Flying_loulou: + - tweak: Sailors rejoice ! New coveralls have been issued by the fleet. + Mordeth221: + - rscadd: Adds fancy pens to character loadout +2019-10-13: + CrimsonShrike: + - rscadd: Adds exosuit energy shields. + ghostsheet: + - maptweak: Deck 4 aft airlocks' controllers are now accessible from inside of the + airlock, so they can be more easily cycled and force. They are still not accessible + from the outside. +2019-10-14: + Chinsky: + - tweak: OCIE renamed to SFP (Sol Federal Police). There was never OCIE. + Rain7x: + - rscdel: The Corporate Security Beret has been removed from the loadout. + ghostsheet: + - rscadd: Plasma cutters can now be ordered from supply, they are locked to mining + access and engineering access + - tweak: Plasma cutters now needs trained construction to deconstruct safely. + - rscadd: Updated the skill description of the EVA, Piloting and Construction skills. + - bugfix: Fixes gun accidents only hitting the user; instead now everything in their + general vicinity is fair game. +2019-10-15: + Nanako: + - rscadd: Airlocks, curtains, ladders and cult runes can now be interacted with + by clicking the floor in their tile. + - tweak: Lift call buttons and panels are now easier to click +2019-10-16: + Anticept: + - bugfix: PAI should no longer fold up when hitting it with an access card while + on help intent. + Chinsky: + - experiment: Armor calculations and some values were changed. It should be generally + more protecting now. Report weird stuff happening. + Datraen: + - bugfix: Microwaves now properly handle non-item based recipes all the time + LiljaMortensen: + - imageadd: Updated holopad sprites + PsiOmegaDelta: + - tweak: Most objects now always consider ghosts to be adjacent when examined + - tweak: Must now shift+click to interact with boardgames + - tweak: Must now shift+click to interact with integrated circuits + nearlyNon: + - maptweak: Counselor's office reworked to have an actual desk. Much more comfortable. +2019-10-17: + Flying_loulou: + - tweak: Resprites the red O2 tank to make it look like an actual firefighter's + tank. + - tweak: The duty boots, jackboots and workboots are now fireproof. + - tweak: The firesuit no longer covers the whole body, but only the chest, arms + and groin. + - rscadd: Adds a "fire overpant", to be worn over the uniform as an accessory to + protect your legs against a fire. + - rscadd: Adds the fire gloves, fully fire proof. + - rscadd: Adds the EFT (Emergency Forcing Tool). + - rscadd: Adds the "water grenade" to fight fires more efficiently. + - rscadd: Creates the firebelt, which has 5 slots and can contain EFTs, water grenades, + inflatable doors and mini-extinguishers. It comes filled with 3 water grenades, + 1 EFT and 1 inflatable door. + - rscadd: Adds the new equipment in the fire closets (places them into a dufflebag + for convenience) + - tweak: In order to survive a fire, you now have to wear the fire overpants, firesuit, + fire gloves, duty boots (Jackboots and Work boots are fire resistant as well), + as well as a fire resistant helmet/hardhat and proper internals. +2019-10-19: + CrimsonShrike: + - rscadd: Allow some more interactions from inside exosuits such as grabbing items + from clamp if the cockpit is open. + Marie Taylor: + - imageadd: Updated fridge sprites + - imageadd: Updated pylon sprite + - imageadd: Resprited holopad, the artist of the previous version has been executed + - imageadd: Resprited bell + - imageadd: Added ringing animation to bell + - imageadd: Resprited notice board, added 4 dir +2019-10-20: + Anticept: + - bugfix: PAIs, Photos, Integrated Circuit Printers, Printed Crew records, and Warrant + Projectors should be working again. + Ithalan: + - bugfix: Fixes modular computer icons not updating automatically for certain monitoring + program events. + WezYo: + - bugfix: Fixed crafting floorbots +2019-10-21: + Nirnael: + - bugfix: Fixes personal closets. + ghostsheet: + - soundadd: Voidsuit now has sounds for tank ejection and disassembling. +2019-10-22: + Higgin: + - bugfix: SecHUDs and goggles will now protect against flashes and flashbangs as + they used to. +2019-10-23: + Marie Taylor: + - imageadd: Resprite of crates, open decals added + Spookerton: + - admin: Build mode has an area viewer/editor. + ghostsheet: + - tweak: Senior researcher no longer has access to mining. + - bugfix: Plasma cutter crate access has been fixed to work with both engineering + and mining access + - tweak: Supply's warehouse is now open to mining access. +2019-10-24: + Boznar: + - maptweak: Maps Vox rigs, soundcannon, and flux cannon to Vox base + CrimsonShrike: + - rscadd: The SEV Torch is now fitted with point defense batteries, that will protect + certain parts of ship from meteor impacts. + ghostsheet: + - tweak: Supply's mechsuit now has two hydraulic clamps instead of a drill. +2019-10-27: + Higgin: + - tweak: Radicals rejoice! Head Revolutionaries once again get traitor uplinks. +2019-10-28: + Ithalan: + - bugfix: Fixed several cases of missing powercables underneath doors and tables + aboard bearcat + - bugfix: Fixed a couple of tiles in bearcat atmospheric compartment that were permanently + without pressure or gravity + - maptweak: Added girders and a few walls to more clearly indicate original extent + of damaged rooms aboard bearcat, for purpose of predicting APC and gravity coverage +2019-10-29: + BlueNexus: + - tweak: Nerfed the bloodsucking creatures often found on away sites +2019-10-30: + SierraKomodo: + - rscadd: Added rooibos tea, chai tea, chai latte, london fog, and mocha latte as + dispensable or mixable drinks. + - rscadd: Added chocolate, vanilla, caramel, and pumpkin spice syrups for flavoring + drinks. + - rscadd: Added alternate title 'Barista' to the Bartender job. + WezYo: + - spellcheck: Fix gaia blurb +2019-11-02: + Imienny: + - tweak: Fix races with low oxy_mod recovering slower from oxygen deprivation than + races with high oxy_mod +2019-11-03: + CrimsonShrike: + - rscadd: Exosuit cells can now be swapped without disassembling entire thing. Simply + use a crowbar while mainteance protocols are active to take one out. + ghostsheet: + - rscadd: Welding tool now gives off light when active (it's a little weaker than + a flashlight) and sparks blue when it's welding. + - tweak: Lighters had their light color adjusted for the sake of ambience +2019-11-04: + Higgin: + - tweak: The accuracy bonus for shooting ranged weapons from standing still has + received a slight buff. + ghostsheet: + - tweak: Mining voidsuit now has minor bullet resistance and can withstand up to + 5000 kPa worth of pressure. +2019-11-05: + Higgin: + - tweak: Harm-intent clicking will now remove shotshells directly from shotholders. + SierraKomodo: + - tweak: Tablets now beep just like PDAs. + - tweak: Borgs can now alt-click doors to access the tile tab instead of shocking + them. To shock a door, use harm intent when alt-clicking. +2019-11-06: + Ithalan: + - tweak: Solar arrays on planetary surfaces now only require 5 tiles of clear space + around them to work at all, instead of 20. Solar arrays in space are unchanged. + SierraKomodo: + - bugfix: Cyborg cable coil can now be used to build machines +2019-11-07: + Albens: + - tweak: Bridge Holopad is now named SEV Torch Bridge + Soviet Swede: + - rscadd: Added the inflatables dispenser to the surveyor +2019-11-08: + Marie Taylor: + - imageadd: Updates the appearance of crates +2019-11-10: + SierraKomodo: + - bugfix: The `hwinfo` command in console terminals now outputs to the terminal + window instead of to chat. + - tweak: The console terminal prompt now includes a helpful reminder about the `man` + command. +2019-11-11: + Bxil: + - bugfix: Character setup works as expected again. + Rain7x: + - bugfix: You can now attach pins to Dress Jackets again. +2019-11-12: + Flying_loulou: + - bugfix: The nitrogen tanks again look like nitrogen tanks. + - tweak: Changes the fire (red) oxygen tank name to 'self contained breathing apparatus' + (SCBA) + - rscadd: Adds the Emergency Management Bureau helmetto the loadout + - rscadd: Adds the ancient Emergency Management Bureau helmet to the loadout (credits + to Sin2 for the sprites) + - rscadd: Adds the light damage control helmet to the loadout + - rscadd: Adds the SCBA mask, and adds it to the engineering crew survival kit, + instead of the breath mask.(credits to Sin2 for the sprites) + Imienny: + - rscadd: adds zipgun, knock-off pistol, small energy gun, ion pistol, ion slug, + duct tape, combat defibrillator, stasis bag, stabilisation kit, balaclava and + "exceptionally robust MRE" to uplink + - tweak: MRE coffee and tea powder no longer require heating + - bugfix: fixed MRE menu 8 (chilli) spawning with pizza instead of chilli + babydoll: + - rscadd: Added scented candles. + - rscadd: Incense and scented candles are now available in the aromatherapy crate + in supply. + ghostsheet: + - rscadd: Rapid Piping Device has been added! + - rscadd: RPD can be ordered from supply, at semi-reasonable cost of a 100 points + a piece. + mikomyazaki: + - bugfix: Body bag label overlays will now properly persist through opening/closing, + instead of disappearing. +2019-11-13: + SierraKomodo: + - bugfix: Intercoms and handheld radios can now select common and entertainment + channels again. + comma: + - tweak: Wall girders are now easier to take down using brute force + mikomyazaki: + - bugfix: NTNet downloads will no longer download the file at the beginning of the + download sequence, instead only adding the new program at the end of the download + timer. +2019-11-14: + mikomyazaki: + - bugfix: Different pen types (blue, red, multicoloured, black) now have different + names. They will now appear as differently named items on the autolathe list. +2019-11-15: + Higgin: + - tweak: Limits the range within which escaping cuffs/unbuckling yourself while + cuffed is visible. + - tweak: Readded different furniture/structure recipes to wood. + - tweak: Added orderable titanium sheets to supply. + - tweak: Fear the gun! Buffed all bullet damage towards a benchmark of 50. Gave + additional armor penetration to most common rounds with more than 50 damage. + - tweak: Love the armor! Buffed many armors' resistance to bullet damage. + Jaraci: + - tweak: Fixes/expands loadout options for off-Torch away site roles. +2019-11-16: + MrKicker: + - bugfix: Fixed Roboticist JumpSkirt appearing invisible + SierraKomodo: + - rscadd: Added soy and iced variants of the chai latte, london fog, pumpkin spice + latte, and mocha latte. + mikomyazaki: + - bugfix: Engine emitter control button (and other buttons of this type) no longer + go invisible for a couple of seconds when clicked. + - bugfix: Surgical borgs can now use their hypospray on targets that are on an operating + table. +2019-11-17: + Chinsky: + - tweak: Geiger counter thresholds have been tweaked upwards, 'high' is now for + rads that will breach most non-radproof suits, 'very high' is dangerous even + to 'radproof' suits. + Imienny: + - rscadd: Improved a bit Vox hardsuit, now you can store more useful stuff in hardsuit + storage slot and use claws attack through now-insulated hardsuit gloves. + Technetium: + - rscadd: Wound infection speed is now twice as fast at 50-70% immunity as it was + before, and 10 times as fast at 0% immunity. + mikomyazaki: + - tweak: Instruct verb will inform you better about why it fails, if it does. + - bugfix: Stationary consoles now have a 'Forced Shutdown' verb, just like other + kinds of modular computer. + - bugfix: The 'boiled spider meat' recipe now correctly produces an item called + 'boiled spider meat' rather than 'giant spider leg'. +2019-11-18: + Higgin: + - imageadd: Added two bunny-eared booster sprites. +2019-11-19: + mikomyazaki: + - bugfix: Removing an ID from a modular computer no longer brings up a selection + menu containing other modular computers with ID card slots in range. +2019-11-20: + Rain7x: + - tweak: Mentalists can now only be an O-1 (Ensign) + - bugfix: The Pathfinder, Med Tech, and pilot headsets now have an on mob icon again. + SierraKomodo: + - tweak: Swallowing pills now displays a message to people within a 2 tile radius. + This message does not tell them what pill you swallowed. + - tweak: Initiating a give (Right click > Give) now displays a message that you + 'hold out an item' to the target. + Technetium: + - rscadd: Adds immunobooster, an immune-system restoring drug that will rapidly + bring a ruined immune system up to half strength. Will not replace a proper + immune system, though, so be careful with those rads and spaceacillin. + babydoll: + - rscadd: Added the incendiary laser blaster to the traitor menu. + ghostsheet: + - tweak: Ion rifle and pistol has its capacity reduce to 8/4 shots respective and + had their delay between shots increased to 3 seconds. + - tweak: Uplink implant is now more EMP resistant, it can still be disabled by an + EMP but its chance of permanently breaking is significantly lowered. + - tweak: Imprinting implant cannot be implanted into synthetic being and must now + be imprinted where the brain organ is eg. For a GAS that would be their thorax; + for humans, their head. + - bugfix: You can leap over objects once again. + mikomyazaki: + - bugfix: Supermatter hallucination effect now checks for any source of meson vision, + rather than just meson glasses. Other sources of meson vision, e.g. the hardsuit + module will now properly stop hallucinations from developing when active. + - bugfix: You can now remove splints from yourself. + - tweak: '''Remove Splints'' is now a verb (right click your target to find it) + rather than in the stripping menu.' +2019-11-21: + Chinsky: + - tweak: Airlock controllers were resprited to blend with rest of wallstuff, have + directional icons now + - tweak: Flashbangs nerfs! No flooring, stun durations are now very short (you have + 4-6 seconds against non-protected, 2 against anyone with a helmet. Added confusion + effect (generally 2-3 times longer than stun) to them too. + SierraKomodo: + - bugfix: Give emotes now display the correct text for recipient vs everyone else + Technetium: + - rscadd: Carbon mobs now take immune damage from radiation. + WezYo: + - bugfix: Clicking on first aid kits (or other crafting objects) with certain items + will no longer delete the first aid kit. + babydoll, dirtygirl: + - rscadd: Added the dire goose, occasionally making its nest on grass exoplanets. + mikomyazaki: + - soundadd: Vending machines now play a sound when dispensing an item. + - bugfix: SolGov Employees now have clothing in their uniform vendor, the same as + the civilian uniform set. +2019-11-23: + Rain7x: + - tweak: The CMO now has the same amount of total skill points as a regular physician. + ghostsheet: + - rscadd: Added a navigation telescreen to the Charon crew compartment. + - rscadd: Replaced the rack on the Guppy with a storage compartment crate + - rscadd: Added binoculars to mining prep. + - rscadd: Carp migration event got reworked! They will now be launched into the + ship at slow speed, over a period of time. + - rscadd: Overmap carp hazard, has been tweaked in same maner as the carp migration + event, carps will be launched at the ships over a period of time. The speed + of carps hitting ships will be dependent on the ship's speed, multiplied by + the pilot's skill. (Go fast for road kills, you want to go fast to escape the + carp event either way). + - tweak: Structures and machine such as windows and computers, will hurt any mob + thrown against it, similar to being thrown against a wall. (Throwing people + against things now deals the same damage as a wall) + mikomyazaki: + - tweak: Firing a gun successfully will now switch off RIG-based cloaking devices. +2019-11-24: + mikomyazaki: + - bugfix: Malfunctioning AIs will now properly get the ai-select-hardware, ai-select-research + and display-help and set-ambition verbs. + - tweak: Malfunctioning AI is now consistently called Malfunctioning AI everywhere. + (This will not affect your character role settings.) + - tweak: Ascent Drones will no longer have the bureaucracy skill to speak legalese. +2019-11-25: + Chinsky: + - tweak: Free skillpoints for medical jobs were lowered, check your skill setups. + - tweak: Virology is no longer a full skill, a perk now requiring Trained Medicine. + - tweak: Codex now has navigation bar to get to home page quickly, or search or + list all stuff. + SierraKomodo: + - tweak: Borgs with the proper skills can now use console terminals with ctrl+alt+click. + You must be adjacent to the console to use this. + Technetium: + - tweak: Immunobooster now has overdose effects and a lower OD threshold (60u -> + 30u). + - tweak: Immunobooster now has strong negative interaction with spaceacillin. Do + not mix. +2019-11-27: + Anticept: + - tweak: Deck Chief now has mining access + MrKicker: + - tweak: Added extra table to OR 2 + - bugfix: Fixed medical hallway telescreen + Rain7x: + - tweak: The job Pharmacist is now called "Laboratory Technician". Their job has + been expanded to include virology duties. + - rscdel: The "Laboratory Technician" alt-title has been removed from the Research + Assistant Role. + SierraKomodo: + - tweak: Shield generator monitoring programs now display the same shield statuses + as the shield generator UI itself + Technetium: + - rscadd: Carbon mobs now take radiation damage upon exposure, modified by their + species radiation modifier -and- burn modifier. + mikomyazaki: + - rscadd: All Deity mode spells and structures now have a codex entry visible to + the God Cultists that explains what they do, or how to use them. + - tweak: Dionaea can be cured of viruses by receiving a middling dose of radiation. + Exposure to a radiation storm or standing outside the supermatter containment + window for a short time should be sufficient. +2019-11-28: + Rain7x: + - tweak: The Lab Tech now only has 16 skill points, and is restricted to trained + medicine and anatomy. + babydoll: + - rscadd: Added two new types of fauna to volcanic exoplanets. + - tweak: To account for their low health, simple animals take less damage from ballistic + and laser projectiles. +2019-11-29: + mikomyazaki: + - tweak: Failing to do surgery due to thick material clothing items will now display + an appropriate error message. +2019-11-30: + afterthought2: + - bugfix: Robotic limb attachment and connection surgery now consistently checks + robotic skills (complex devices, also anatomy if on flesh target). +2019-12-01: + mikomyazaki: + - bugfix: The delete warrant button in the main window of the Warrant Assistant + program will now properly do its job. +2019-12-02: + MrKicker: + - tweak: Notes/memories can now be multi-line. + Rowtree: + - rscadd: Added 30 new drinks, added recipes for Nothing, and added new bottles + to the booze-o-mat +2019-12-03: + Technetium: + - tweak: Nerf to Vox Slug Sling, 2.5x addt. egg generation speed. + mikomyazaki: + - bugfix: Antagonist HUD markers e.g. Cultist indicators will now properly show + up instead of being under the floor layer sometimes. +2019-12-04: + Rain7x: + - tweak: Candy Bar sprite has been updated. + afterthought2: + - rscdel: Virology has been entirely removed from the game. +2019-12-05: + Spookerton: + - tweak: Booster biomod hair options have been replaced with booster markings. +2019-12-06: + MrKicker: + - tweak: Allows hand-labeler to label storage items when used with non-help intent. + babydoll: + - rscadd: Added retractable ball point pens. + mikomyazaki: + - bugfix: Taping paper to windows will no longer put it below the window. +2019-12-07: + Boznar: + - maptweak: Engineering bay and atmospherics have been remapped to be less cramped + and more space efficient. + - maptweak: RPDs added to atmospherics lockers. Additional EVA hardsuit and Atmos + Voidsuit added to engineering. + Imienny: + - tweak: You can no longer hear aiming sounds, unless you are being aimed at/aiming + at. +2019-12-08: + Imienny: + - rscadd: Added option to change type of stomach in character setup menu + - bugfix: Fixed bug allowing to use stun batons without charges + - bugfix: Fixed bug preventing stun prods from working with standard device cells + Spookerton: + - bugfix: Female rolled uniform and sleeves for EC command uniform no longer makes + you naked. + mikomyazaki: + - tweak: Burn damage from radiation exposure is nerfed by 75%. +2019-12-09: + mikomyazaki: + - bugfix: Robots can now wrench portable rechargers to move/anchor them. +2019-12-12: + Rowtree: + - bugfix: Fixes recently added drink strengths to a more accurate level. + Spookerton: + - tweak: Bald boosters get bald ears. + mikomyazaki: + - bugfix: AIs can now spawn properly at roundstart. + zaredman: + - bugfix: Biowaste disposal cart access to only require surgery access instead of + requiring 6 different accesses. Corpsmen rejoice! +2019-12-15: + Spookerton: + - bugfix: Starborn, Blueforged, and Promethean variations properly show the head, + torso, and groin. +2019-12-17: + CrimsonShrike: + - rscadd: Drill heads show current status while mounted and can be examined for + information when not mounted on an exosuit drill. + EcklesFire: + - tweak: Adjusted renegade numbers. + - bugfix: Removed duplicate vars. +2019-12-19: + Spookerton: + - tweak: PTR bullets aren't hitscan and do a little less damage and penetration. + babydoll: + - rscadd: Added foam dart launchers. + - rscadd: Foam dart launchers can now be won as prizes from arcade machines. + - rscadd: Added a modified foam dart launcher to the uplink's gimmick weapons menu. +2019-12-20: + Cajoes: + - rscadd: Added orderable replacement barricade tape rolls from supply. + PsyCommando: + - tweak: Made the currency used in text entries read from the current map. Mainly + to help with downstream stuff. + afterthought2: + - rscadd: Buildable radio components for machines are now available. They will have + limited use with machines currently. + - tweak: When building air sensors, you now must also add a power component and + a radio transmitter. You can use a multitool on the radio transmitter while + standing near a machine to configure it. + ghostsheet: + - rscadd: Mercenary gamemode is now overmap. +2019-12-21: + Imienny: + - tweak: Tweaked TC cost of uplinks in Character Setup menu, radio uplink now gives + you 30% more TC, uplink Implant cost only 20% of total TC and taking TC without + uplink gives you 50% more TC. + - tweak: Message shown after receiving PDA uplink now should explain better how + to access uplink. + - tweak: Delay for removing knives from boots was decreased to one second + - tweak: Using combi-knifes on intent other than help intent will now open their + blade + - tweak: Portable freezers can now fit inside backpacks and have capacity of large + box + - tweak: Combat knifes can now fit inside boots + mikomyazaki: + - bugfix: Sleepers will now properly display the amount of a drug in the occupant + on the UI. + - tweak: R-UST now has a prompt to tell you when hitting the shutdown button will + cause an instant explosion, asking whether you're sure. + - maptweak: R-UST room machinery starts the round anchored. + - tweak: Improves the fuel injector controller UI, with injection rate and toggle + all injectors controls. +2019-12-22: + Chinsky: + - tweak: During the metor rounds, evacuation jump will be called automatically after + announcement that rocks are coming. It will take 30ish minutes to arrive + - tweak: Since there's less time and Torch is /very/ sturdy (thicc hull and PD), + initial intensity is bumped a bit and escalation is going faster, so will hit + max intensity at around 30 minutes mark. + - tweak: 'After the jump mode will check for some important things and will print + red/green text about them: helm console (need to have at least one and powered), + thrusters (ditto), bluespace drive (the room must be powered).' + mikomyazaki: + - tweak: Trained Forensics now provides a much larger bonus to making simple incisions + on dead targets for autopsies. +2019-12-23: + mikomyazaki: + - bugfix: Can't put objects inside bags that are in pockets anymore. + - tweak: Updated traitor extended round description so it is appropriate for the + SEV Torch setting. + - bugfix: Double doors are properly solid again. +2019-12-27: + babydoll: + - tweak: Increased damage taken when falling down a hole to another deck. + - tweak: Increased duration of stun after falling. + mikomyazaki: + - bugfix: Merchant station teleporter computer will now display the proper messages + relating to costs. +2019-12-28: + Cheb Pomidorov: + - tweak: Scientists and Research Assistants can now enter areas such as Medbay and + Brig's hallways and the Bridge Entry. + Devildabeast: + - tweak: Changes the Mentalist's Mind Read time limit from 25 seconds to 60. + Spookerton: + - tweak: Mercenary and Provocateur starting points are hidden from the Torch's roundstart + sensor message. + zkxs: + - bugfix: The psionic signal event can no longer give synthetics genetic disabilities +2020-01-03: + Devildabeast: + - tweak: Changes "restricted roles" to the broader "casual roles" in loadoout. + - tweak: Adjusts several loadout item restrictions. + Imienny: + - tweak: Replaced spoon in MRE with spork + mikomyazaki: + - bugfix: Nymphs and Golems are no longer valid targets for auto-traitor. + - bugfix: Mercenary radio channel now works again for mercs, raiders, traitors etc. + zkxs: + - bugfix: Fixes a runtime when using an atmos analyzer on a pit +2020-01-30: + Anticept: + - tweak: Farmbots now refill from a sink at a higher rate, up from 10 to 100 per + cycle. + Cheb Pomidorov: + - rscadd: You can now lock and unlock coffins using a screwdriver. Locked coffins + can be struggled out of, similarly to welded closets. + Imienny: + - rscadd: Added a new roles to Vox Scavenger away site, "Shoal Biotechnician", "Shoal + Technician" and "Quill" + MrKicker: + - tweak: AI can now make multi-line announcements + Spookerton: + - rscdel: IPCs can no longer be counsellors. + WezYo: + - bugfix: Flying drones can now open windoors + Xaytan: + - tweak: Adds welding goggles as an option in loadout. + afterthought2: + - rscadd: Pipe meters, vents, scrubbers, and pumps now use radio components. + mikomyazaki: + - tweak: Guest pass icon will now change colour to black when expired. + - tweak: Guest pass machine gets an updated UI. + - tweak: Humanoid Dionaea now get the audible chirp emotes. + - soundadd: Added a new multichirp (*mchirp) audible emote sound effect for humanoid + Dionaea. + - bugfix: Portable drives now work properly in modular computers for all operations. + - bugfix: Dense objects will now properly stop throwing/leaping. + - bugfix: Hand teleporters will now create portals that aren't random, when you + are linked to a teleport computer on a connected z-level. + - tweak: Hand teleporters will now only list teleport computers that are on a connected + z-level. + - bugfix: Can no longer right-click darkness due to being unconscious to see what + is on that turf. + - tweak: Decreased difficulty of installing augments to the same level as installing + robotic organs. + - imageadd: Adds three xenowear options for Space-Adapted humans - Leg braces, neck + brace and venter. + - imageadd: Adds animations for the sleeper & bodyscanner when active & occupied. + - soundadd: Adds a scanning sound for the bodyscanner. + - tweak: Space-Adapted humans' stamina now depends slightly upon gravity levels, + with better stamina than baseline humans in low-gravity, worse in standard gravity. + - tweak: Space-Adapted humans are adapted for lower-pressure environments, but suffer + in higher pressure environments faster relative to baseline humans. + - bugfix: The Vox shuttle can now return to its hangar properly. + quardbreak: + - tweak: Tweaked welding sounds on airlock and vents. Now after weld operation you + should hear second sound like you end your action. + zkxs: + - bugfix: Combining stacks from an inventory no longer leaves bugged sprites + - bugfix: Having more than 10 brain damage no longer grants immunity to peridaxon's + side effects (confusion and drowsiness) + - spellcheck: Sec HUD goggles description grammar fix + - rscadd: Adherent can now float over tables +2020-01-31: + Lorwp: + - soundadd: Energy melee weapons now have an on-hit sound + mikomyazaki: + - tweak: Paper will now check if your pen works before you start writing instead + of after you've written your text. + - tweak: If your retractable pen isn't in its active state when you start writing + on something, your character will automatically click it. + - tweak: Retractable pens will now toggle to their active state when you write on + anything (union cards, people, the wall) instead of only paper. + zaredman: + - tweak: Security now has access to a written statement, weapons license, arrest + report, and restraining order template on the Reports program. Paperwork masochists, + rejoice. +2020-02-03: + mikomyazaki: + - bugfix: Throwing items at a disposal chute will properly dispose of them again. + - bugfix: Fixes a bug where (for example) throwing an object at a grilled window + would hit the grill inside the window instead of the window. +2020-02-05: + mikomyazaki: + - admin: Mobs without the UI elements to use psionics can no longer be granted psionics. + e.g. simple animals. + - bugfix: Polytools now allow you to extend tools again. +2020-02-07: + Chinsky: + - tweak: Various drinking glasses are now printed from a microlathe instead of being + vended. Bar now has pre-loaded microlathe for this purpose. + - rscadd: Added new type of drinking glass - flute glass. + - tweak: Added transparency to some reagents, namely water and booze. + - tweak: Can now select recipies category in fabricators + - tweak: More types of glasses can take accessories like sticks or straws now, try + it out. +2020-02-08: + mikomyazaki: + - bugfix: Atmospherics' tank controllers work again when controlling the output + vent. + zaredman: + - maptweak: Removes Explorer and Pilot access to Xenobiology, Xenoarchaeology, Toxins, + and assorted labs. Pathfinder retains their original access. +2020-02-10: + Flying_loulou: + - rscadd: Fleet engineers rejoice ! The fleet unlocked some funds, in order to provide + you with a dedicated uniform, constituted of a polo, some pants, and a jacket + (available in the uniform vendor, under the utility extra section). +2020-02-12: + SomeoneStoleMyNickname: + - bugfix: The Guidebooks Hacking and Repair and Construction should now work as + intended. +2021-01-27: + MistakeNot4892: + - tweak: Will the bot generate the changelog now? Let's find out. + - tweak: Coat racks are now material-based and craftable. + - tweak: Coat rack backend has been rewritten to support hanging any hat or suit + item. + - experiment: A bunch of structures have been rewritten to use some shared code. + As a result, you can examine most structures to see some tips on how to interact + with them, and you will find several construction/deconstruction steps have + changed. + - tweak: Metal structures must be dismantled with a welding tool, while other materials + use a crowbar. + - tweak: Girders are now 'supports', and are reinforced by using a material stack + on them before anchoring. Using a screwdriver will remove the reinforcement, + or toggle whether or not the support will produce a fake wall. + - experiment: This is going to be buggy, please report issues and problems. + N8-Toe: + - rscadd: Added chemical saftey suits to code, protect against gas in the air but + need to be used with a face covering mask, unimplemented at this time. + SierraKomodo: + - admin: Disposal bin stuffing and flushing are now attack logs instead of admin + logs. + - tweak: Cutting the ID Scan wire on doors will now disable ID scanning. If the + door is 'secure', this blocks access entirely. For all other doors, this fully + bypasses access requirements. + - bugfix: Windoors are now properly emag-able. + - tweak: Emagged windoors will now provide feedback that they are broken when you + try to close them. + - tweak: You can now tell if a door's control board has been fried by examining + the door with an IT skill of trained or higher. + - tweak: '''Mild'' labels in medical scans are now highlighted in yellow and bold + to make them more noticeable.' + - rscadd: Windows and airlock windows are now paintable. + - admin: Smothering people with a rag and hitting people with an ignited rag now + generates attack logs. + - tweak: You now require a grab to smother people with a rag. + - tweak: Smothering people with a rag now has a timed progress bar - 3 seconds if + your CQC skill is trained or above, 6 seconds for everyone else. + - rscadd: General station/ship lights now have randomized tones - The old default + warm yellow, a cool blue, and pure white. + SierrqKomodo: + - admin: Banned player's mobs now have their ckey stripped so they display the permanent + SSD message and instantly cryo. + SolatK: + - bugfix: Dropped mobs should not take the same direction with those who held them + - bugfix: CE rig now have a boots + SomeoneStoleMyNickname: + - rscadd: Added a new digital pencode tag. [redacted] creates the string R E D A + C E D in black lettes on black background to give the illusion of redacted contend + in reports. + The Stalker: + - rscadd: Finished up some unused void suits. So they have stats (finally) + - rscadd: Added new materials to vender and recipes. Will be doing a part two i + gues. Will eventually look into finishing the cotton plant or make a mega edition + pack of new weapons + Winter: + - rscadd: Added textbooks. Textbooks are items that give skillbuffs while you are + actively using them. Textbooks require basic literacy to use, and you must have + the specific textbook for your skill level. + - rscadd: Added a book merchant who sells textbooks. + - tweak: Molluscs and Mollusc meat now have monetary value. + - maptweak: Tradeship now always starts the round with a book trader available. + - maptweak: Tradeship has four randomized textbooks in various locations at roundstart. + - experiment: Please report balance issues (and of course bugs) that may arrise + from this feature. + - tweak: 'Bonus: Codex links now open new windows.' + - rscadd: Those with Master Literacy can now make their own textbooks. Blank textbooks + are acquired via an autobinder and then written using a pen. + - rscadd: Includes codex information on this process. + - tweak: Made textbooks in general to be one size smaller to allow being put in + bags. + - tweak: Very basic support for fabricators to get colours from something else other + than pipe_colors + - experiment: Unsure how this impacts skill balance, please report on that if there + are issues. + comma: + - tweak: Desert planets now have 'dry mud' turfs in the areas where quicksands can + spawn. + - rscadd: Added new type of toolbox - electrician's. It holds all needed tools for + machinery components interactions and several boxes of most common components. + Can be found in supply (electrical maintenance pack) and electrical locker + - balance: Engineering vendomats now vend APC/air alarm kits instead of just circuitboards. + - balance: Most machinery components are now tiny rather than small + - bugfix: APCs can be fixed again after explosions + - tweak: APCs now don't draw screen overlay / glow if screen component is destroyed + - tweak: APCs now don't report cell power in UI etc if battery backup is destroyed + - tweak: APCs now show that external power is not coming in if terminal component + is destroyed + - experiment: Machines can actually be destroyed fully by strong explosions again + (not just component damage) + - tweak: Added categories to textile designs + - balance: Costs for armor items are adjusted, generally more expensive to produce + - tweak: Holsters now leave their fibers on things put inside. + - tweak: Crowbarring doors now leaves scuffing on them, visible when examined up + close. Can be repaired as any other damage. + - tweak: Gas tanks will now dump their content into air when destroyed + eckff: + - rscadd: Backported Adherent species from Baystation12. + - rscadd: Backported Lizards species (previously Unathi). + - imageadd: Lizard people get new dark sprite. + - bugfix: Fixes monitor mask initial world icon. + - rscadd: Adds radial icon choice for monitors. + - tweak: Roundstart can now be any hour. +2021-01-28: + comma: + - tweak: Ha ha ha I am abusing my GitHub maint powers to make chinsky commit a changelog + via the bot workflow. Science! +2021-01-30: + eckff: + - rscdel: Removed the privacy poll. +2021-01-31: + comma: + - tweak: Credsticks are now tiny instead of normal sized +2021-02-02: + MistakeNot4892: + - tweak: Firearms now use pixel-precise projectile iteration, ported from Aurora. +2021-02-03: + MistakeNot4892: + - tweak: Amputating the second-to-last organ on a human mob (typically leaving the + torso) will drop the last organ as a limb and destroy the mob -in other words + you can now chop bodies up entirely instead of being left with a weird unwieldly + torso. + - tweak: Amputation is faster but messier if you're doing it improperly (improvised + tool or circumstances). + - tweak: Failing an amputation will now get the tool stuck in the person's limb. +2021-02-04: + eckff: + - tweak: Tweaked bucket world-icon state. It's little bit bigger now, but still + tiny. + - rscadd: Added augmentation implanting support code if anyone would like to add + implants or augmentations in loadout. +2021-02-05: + comma: + - tweak: Need to be on same tile as rollerbed to buckle to it. + - tweak: Fires no longer destroy wiring under floor tiles. + - bugfix: Guns found in xenoarch now have icons again + - imageadd: Added inhands for xenoarch find blades + eckff: + - rscadd: Added the panic bunker support from Hestia repository. By default, it + turned off and can be toggled on in config or manually for a round. + - admin: Admins can control the panic bunker state and add/revoke bypass in Server + section with R_SERVER flag. +2021-02-08: + eckff: + - rscadd: Added a overmap-based merchant submap ship - Liberia. +2021-02-13: + MistakeNot4892: + - rscadd: Ailments and prosthetic faults now have codex pages. + - rscadd: You can diagnose some ailments and faults with grab-examine diagnosis. + - rscadd: Failing a skill check after prosthetics replacement surgery can add a + fault to the prosthetic. +2021-02-14: + comma: + - tweak: Airlock tool interactions changed. + - tweak: Screwdriver on airlock will open wires panel, letting you access wires + for hacking. + - tweak: Crowbarring a secured (welded/bolted/braced) airlock will open the hatch + letting you access components for repairs and deconstruction. + - tweak: Hatch can only be opened if you have appropriate access to the door. Use + ID on the door to toggle the lock. +2021-02-16: + MistakeNot4892: + - rscadd: There is now a Mouseover Highlight preference that can be set to Show, + Hide or Show While Shift Held. This will highlight the object you are currently + mousing over. You can set colour and alpha for the highlight in your UI preferences. + silicons: + - bugfix: projectiles use a better get angle function now +2021-02-17: + MistakeNot4892: + - tweak: 'Several changes of note only to administrators:' + - tweak: Traitor panel has been renamed to Special Roles. + SolatK: + - bugfix: now the tail will not stick out through the clothes where it is not necessary +2021-02-20: + comma: + - imageadd: Radio receivers / transmitters (machine components) got new icons +2021-02-22: + comma: + - bugfix: Emagged airlocks can now be crowbarred close, after they're depowered. + - tweak: Airlocks now use access lock components to decide their access, instead + of circuitboards. Locks now use same UI as airlock electronics did for access + setup. Mapped airlocks should spawn these as needed to work same. + - tweak: Doors can now have their internal components damaged too like the rest + of machinery. It won't happen until they're bashed down first though. + - tweak: Access locks with auto-set option will automatically set their access to + the area's on installation into machine (like doors do) + - imageadd: Access lock components (and network lock) now have their own icons instead + of reusing scanning module one. +2021-02-24: + MistakeNot4892: + - rscadd: Poppy and other possums can now be picked up thanks to Pawn. +2021-02-27: + SierraKomodo: + - admin: Admin logs for turret setting changes now display the correct user instead + of *INVALID* and a loc link. + - admin: Attack logs for cremation no longer has the attacker and victim reversed. +2021-02-28: + MistakeNot4892: + - tweak: Webhook config now supports per-endpoint mention lists. Consult config/example/webhooks.json + for the format. If you don't need individual pings, you don't need to update + anything. + SierraKomodo: + - tweak: Codex entries for magnetic guns (Coilguns, railguns, etc) have been updated + with a lore blurb and detailed information on specific mechanics. + comma: + - bugfix: Airlocks no longer spawn extra lock when constructed + - tweak: Wall emergency lockers renamed to emergency dispensers (since they're not + lockers at all), and given new icon + - soundadd: Crypods, sleepers and bodyscanner pods now make sounds when someone + enters/leaves +2021-03-02: + SierraKomodo: + - admin: Supply beacons now generate attack logs when activated + - admin: Suicide by gun in the mouth now trigger attack logs instead of admin logs, + including a new log when starting the suicide process +2021-03-03: + SierraKomodo & Pawn: + - imageadd: New sprites and lighting overlays for teleporters have been added. +2021-03-06: + comma: + - tweak: Walls now take much less damage from melee strikes, depending on material. +2021-03-08: + MistakeNot4892: + - tweak: The status condition backend (paralyzed, asleep, etc) has been completely + rewritten; please report any inconsistencies or bugs. +2021-03-09: + eckff: + - rscadd: 'Added prepared subtypes of suit cyclers which usually hold helmets/hardsuits/magboots + on roundstart:' + - rscadd: 'Jobs which have prepared suit cyclers: engineers, atmospheric engineers, + security, medical and generic.' + - rscadd: Generic is access-free suit cycler which contain simple space suit and + space helmet. + - maptweak: 'Did some changes for merchant away submap Liberia:' + - maptweak: Added more money in trading room. Initially there's should be 13k credits, + but before this change there only 1k. It fixed now. + - maptweak: Added light switches in almost all rooms. + - maptweak: Removed a few spawnpoints in rooms. + - maptweak: Replaced bar keg in bar room with alcohol chemical dispenser. + - maptweak: Replaced some bubble lights in atmospherics with tube lights. + - maptweak: Replaced bookcases in library room with skillbook bookcases, since nobody + really use manuals and skillbooks will be useful for merchants as a trading + product. + - maptweak: Moved disposal bin in library a bit, so it will not interfere with the + passage to the chairs. +2021-03-13: + Andrew-Fall: + - tweak: Drastically increases large map loading speed +2021-03-19: + afterthought2: + - tweak: Additional support has been instated for templates which are to be loaded + multiple times. The main user-facing change is that when adding shuttle-restricted + waypoints to an overmap object's initial_restricted_waypoints list, use the + shuttle's type path, not its name. Templates that load ferry-type shuttles with + waypoints not on the template will break with this system, but you can opt out + by setting modify_tag_vars on the template datum to FALSE. +2021-04-28: + Koollan: + - tweak: Changed a couple things about armor values of some of the new metals. Shinier + metals are now semi-useful for laser protection. Also, Slag is now able to be + dissolved into some reagents. + - rscadd: Added a new metal and more alloys. + - rscadd: I added some metals and mineral types in order to actually acquire the + new metals. This is the first pass. Check the PR for full details. + MistakeNot4892: + - tweak: You can now target head/hands/arms on help intent to do some more specific + hug actions (headpats and handshakes). + - tweak: You can now headpat simple animals and robots. + - tweak: Many objects previously made of glass are now made of fiberglass, which + is stronger but less heat resistant. + - tweak: Cables are now made of copper rather than steel. + - tweak: Slag can now be processed via grinding and acid to recover some useful + trace elements. + - rscadd: Fiberglass sheets can be made from glass and plastic at an autolathe or + textiles fab, or by grinding glass and plastic then heating over 100C. + - tweak: Age is now a descriptor, and can be found alongside height and build in + preferences. + - rscadd: Some status effects (sleeping, stunned, confusion, weakened) are visible + in the form of markers over the victim's head. This can be disabled in preferences + if you'd rather not see them. + - tweak: Your gender no longer determines your base character icon. Instead, there + is a 'bodytype' option. + - tweak: Character gender pref has been renamed to pronouns. + - tweak: Species skin variants have been changed into body types. + MuckerMayhem (Ported by SierraKomodo): + - bugfix: Fixed the skill panel losing focus when editing skills. + SierraKomodo: + - rscadd: Admin paralyzed players now have notices to inform other players they're + paralyzed and being handled by staff, and to not interact until staff are done. + - tweak: Cargo trolleys can now be hitched together regardless of what direction + the trolley is facing. + - tweak: Cargo trolleys now tell you if and what they're linked to when you examine + them. + - admin: Mech weapons now generate proper attack logs instead of admin logs, and + only appear when targeting mobs. + eckff: + - rscadd: Adds diona nymph chirp as fun instrument for synthesizer. Available only + with dionaea modpack. + - maptweak: 'Liberia: Added two ATM on Mule shuttle.' + - maptweak: 'Liberia: Removed redundant firealarm from bar.' +2021-04-29: + ghostsheet: + - bugfix: Camera shake has been refactored. +2021-05-02: + MistakeNot4892: + - tweak: You can now aim at people with fruit, and will throw the fruit if they + trigger reflex fire. +2021-05-06: + MistakeNot4892: + - tweak: Examining an object will show you if it is usable as a tool. + - tweak: Ghetto surgery steps have been adjusted to use a shared tool flag system, + check the codex for updated tools for surgery steps. + - tweak: The incision manager no longer has a special surgery type, but counts as + several different surgical tools at once. +2021-05-07: + MistakeNot4892: + - tweak: Some material stack items and messages around them may have changed due + to a backend refactor of materials. +2021-05-08: + Coltrane97: + - tweak: Radiation closet now contains radiation medpouch instead of toxin one +2021-05-11: + Coltrane97: + - bugfix: Identification cards now properly get their account number; ATM third-level + security will work. +2021-05-12: + MistakeNot4892: + - tweak: Fluid interactions with atoms have been disabled until they can be optimized + to be less of a server killer. Mobs will still drown, you just won't melt in + acid. On the plus side, fluids are more performant now. + - tweak: Records now have their own area in character preferences. +2021-05-14: + MistakeNot4892: + - tweak: Double-clicking to see turf contents is now a preference. You can choose + alt click (default), double click or nothing. +2021-05-20: + Andromeda-K22: + - tweak: AIs can now have a default holopad color tone set, and set their own color + tone for on-station/ship holopad rendering. + koboldlove: + - bugfix: fixed the character creation preview sometimes not updating when changed + or loaded +2021-05-27: + comma: + - bugfix: Melee weapons now actually use their armor penetration values against + armor +2021-05-30: + Coltrane97: + - bugfix: Missing wall-mounted relay circuitboard + - bugfix: Network cables dupe + - rscadd: Network cables can now pass through z-levels +2021-06-12: + CakeQ: + - rscadd: Added two new layers to walls, paint and striping. Walls will now maintain + their material coloring, and instead have paint colors applied as paint layers + on top. Standard walls can be painted two-tone with the main body and striping + (wooden walls too). + - rscadd: Wall paintability is now defined by their materials. + - rscdel: Removed legacy wall stripe system in favor of the new paint striping. + - tweak: Wall edge connections to things like windows and airlocks have been simplified, + fixing a few erroneous connections. + - tweak: The paint sprayer has finer control when interacting with walls and wall + frames. + - tweak: Renamed airlock paint flags to be generic. These are now also used for + defining wall paintability. + MoondancerPony: + - rscadd: Trays now use vis_contents, so you can interact with tray objects by clicking + on them. + - rscdel: Trays no longer drop their contents when set on a table. + - tweak: Storage UIs now ignore pixel_x and pixel_y when displaying items. +2021-06-16: + SierraKomodo: + - tweak: There is now a user feedback message for wiring a window. + - rscadd: You can now de-polarize a window by using wirecutters to remove the wiring. + - tweak: The set id prompt when using multitools on polarized windows now defaults + to the current id instead of null. + - rscadd: Using a multitool on an anchored (fully installed) window now toggles + the tint instead of changing the ID. To change the ID, unanchor the window first. + - tweak: Examining windows now tells you if they are anchored and/or polarized, + and the construction state (screwdriver/crowbar steps) of reinforced windows. +2021-06-20: + CakeQ: + - rscadd: Walls can now connect to walls of other types depending on their material + by comparing material wall icons + NataKilar: + - rscadd: You can now build landable ships by toggling docking beacons to construction + mode. + PsyCommando: + - rscadd: Added Ice extractor. + - imageadd: Added a placeholder icon for the extractor. + SierraKomodo: + - bugfix: Ghosts will no longer break skill checks for helm controls. + - tweak: Ship helm consoles now only allow a single person to use manual control + at a time, including viewing the overmap through the helm. + - rscadd: Messages are now displayed whenever another mob takes control of a helm + control, to make it outwardly obvious who's skills are used to calculate flight. + - admin: Debug log messages were added for helm control changes, for tracking of + potential issues on live. +2021-06-27: + quardbreak and Pawn: + - rscadd: Added a picnic basket. Sprites made by Pawn. +2021-07-02: + NataKilar: + - tweak: Fusion fuel compressor can now create fuel rods of mixed materials. + - rscadd: Added fission reactor to the game for isotope and power generation +2021-07-06: + MistakeNot4892: + - rscadd: Ports the aspect system from Europa, specifically the backend, not the + aspects themselves. This is a menu in character preferences that allows you + to pick a series of traits for your character, as in some RPGs. + - tweak: Moves prosthetic limbs, prosthetic organs, amputated limbs and nearsightedness + onto aspects instead of the Physical tab. + - tweak: Moves preview options from the Physical tab to the header of character + preferences. +2021-07-10: + Geeves: + - soundadd: Added a sound to falling over, willingly resting does not play the sound, + however. + Gr1lledcheese: + - bugfix: Made oxygel scannable +2021-07-11: + MoondancerPony: + - rscadd: Replaces the HTML microwave UI with a new NanoUI-based one, complete with + an animated progress bar! + - tweak: Microwave recipes can now be made in bulk by multiplying the recipe amounts. +2021-07-12: + greggbot: + - rscadd: PDAs are now constructable +2021-07-13: + Geeves: + - rscdel: AI can now turn their holograms without moving by using the eastface, + westface, northface, and southface macros. +2021-07-15: + quardbreak: + - imageadd: New IV drip sprites from Haven-Urist. +2021-07-16: + PsyCommando: + - bugfix: Fixed shutters and blast doors deconstructed and panel_open state being + unreachable. + - bugfix: Fixed shutters assemblies having the wrong icon. + - bugfix: Fixed shutters deconstructing to blast door assemblies. +2021-07-17: + Azlan (as the sprite author) and quardbreak: + - imageadd: Replaced Supermatter sprites with ones by Azlan. +2021-07-18: + CrimsonShrike and quardbreak: + - rscadd: Ported pool tiles and related to pool objects. You can build pool and + keep water inside it. +2021-07-19: + PsyCommando: + - tweak: Allow anchoring/unanchoring closets/crates to the ground. + - imageadd: Added the access_button_off icon state +2021-07-22: + retlaw34: + - imageadd: Added new fuel port sprites. +2021-07-24: + Nyxodile: + - bugfix: Backend fixes for mobile ladders. + - bugfix: Fixes toggling plated catwalks. + - bugfix: Fixes Wi-Fi bypass. + - bugfix: Minor fireaxe attack fix. + Tennessee116: + - maptweak: A cell charger has been added to the research lab of the tradeship! +2021-07-28: + quardbreak: + - tweak: Skybox transit overlay now should be more noticeable than before. +2021-07-30: + Gr1lledcheese: + - tweak: Adds different levels of the CE_OXYGENATED effect +2021-07-31: + PsyCommando: + - tweak: Made material doors less loud. + - bugfix: Made a few machines stop reporting they're not receiving power when they + do not need power at all. +2021-08-02: + PsyCommando: + - bugfix: Fix reinforced floor being impossible to build due to a bug. +2021-08-03: + MistakeNot4892: + - tweak: Supply beacons no longer need a wire under them to function. +2021-08-15: + comma: + - tweak: Instead of selecting bottle sprite, you can now select lid and label color + - rscadd: Sprites for bottles and beakers were changed +2021-08-22: + PsyCommando: + - bugfix: Logging procs don't crash when used during early init anymore. +2021-08-24: + Andromeda-K22: + - rscadd: the supermatter now makes noises depending on damage. + - rscadd: the supermatter now glows if severely damaged, and changes contrast / + color +2021-08-26: + Andromeda-K22: + - tweak: gas filters no longer use hardcoded modes (i.e ATM_N2), they now use gas + decls and a list that is dynamically generated. + PsyCommando: + - tweak: Make curtains use decl instead of several subtypes. +2021-08-29: + Andromeda-K22: + - rscadd: handcarts are now a thing. control-click a pullable atom, then click the + cart with them to load them on. Only works with ITEMS and OBJECTS, not PEOPLE. + Items have a minimum size to be loaded onto the cart. + - tweak: wheeled objects should now be given ATOM_FLAG_WHEELED and are easier and + less exhausting to move. + - tweak: the skill requirements for landing properly during the gravity failure + event has been changed from professional to trained. +2021-09-01: + PsyCommando: + - bugfix: DNA now properly keep track of facial hair color independently from hair + color as it was intended. + - bugfix: Fix skillset not being a path on mob init crashing mob/Initialize(). +2021-09-03: + MistakeNot4892: + - rscadd: A BYOND emblem modpack has been added that adds an emblem to OOC chatter + from people with membership. Defaults to unincluded. + PsyCommando: + - bugfix: Fix occasional runtime in mob/Destroy() when deleting an ai var that wasn't + initialized yet. + comma: + - tweak: Added more hints to xenoarch effects +2021-09-05: + comma: + - tweak: Planet types are now weighted, with some (barren and shrouded) spawning + less often than normal ones + - rscadd: Adds meat planets made of meat (rarer spawn) +2021-09-09: + Andromeda-K22: + - tweak: updated the UI on species selection + - tweak: species selection is now in the background tab. + - tweak: the pda screen is now an overlay. +2021-09-11: + Andromeda-K22: + - tweak: NTOS is now GOOSE. + SolatK: + - bugfix: Fixes accessory offsets for avians +2021-09-12: + Andromeda-K22: + - rscadd: adds the 'strut' material stack, used for a number of items. + - tweak: metal sheets are no longer used for many things, struts are used instead. +2021-09-14: + Geevies: + - rscadd: Species now have special footprint handling when walking on simulated + turfs, though no core species has anything implemented yet. + SolatK: + - bugfix: Avians can wear gloves. +2021-09-15: + PsyCommando: + - bugfix: Prevent APC runtime spam when in a null area. +2021-09-17: + Andromeda-K22: + - tweak: air alarms now sound different. + MistakeNot4892: + - rscadd: Ports geothermal generators from Europa. + SolatK: + - tweak: a credit-stick can be inserted into an ATM + - rscadd: The tail is now a separate limb. You can select it as target, and button + is shown when you look at somebody with a tail. +2021-09-21: + Gr1lledcheese: + - bugfix: Fixes windoor electronics icon +2021-09-23: + NataKilar: + - tweak: Camera networks are now known as channels and are not tied to access. + - rscadd: Security cameras are now tied directly to computer networks, and can be + managed as with other network devices. +2021-10-01: + Andromeda-K22: + - admin: the player panel has been moved - can still be accessed by the usual verbs + and right-click context menu. +2021-10-02: + MarinaGryphon: + - bugfix: Fixes body scanners not showing organ damage + chaoko99: + - imageadd: Very slight color adjustments to the skybox underlay. + - imageadd: New combat shield sprite. +2021-10-03: + MarinaGryphon: + - bugfix: fixes the emote keybind creating two windows +2021-10-05: + lolman360: + - bugfix: fixes charge pylon (electron reservoir) from shocking adherents +2021-10-06: + MistakeNot4892: + - tweak: All energy weapons (ninja blade, esword, energy axe, energy cutlass, energy + machete) can be used as scalpels when they are energized. + - tweak: Energy swords can be used to slice open safes, lockers, windoors and tables + a la the ninja blade when they are energized. +2021-10-08: + PsyCommando: + - tweak: Makes changing a var type in VV take a type path string instead of having + the slow nearly useless listbox with all the atom types listed in. +2021-10-17: + CrimsonShrike: + - rscadd: Adds a number of exosuit modules + - rscadd: Resprites exosuits +2021-10-19: + CrimsonShrike: + - bugfix: Exosuit radios work again. + - tweak: Intercom shortcut is not usable for exosuits too + CrimsonShrike & Azlan: + - rscadd: Adds exosuit cameras + MistakeNot4892: + - tweak: Species information is now found in the codex rather than primarily in + character preferences. +2021-10-20: + CrimsonShrike: + - rscadd: Swimming. + NataKilar: + - bugfix: Robots now properly work as cameras for the purpose of AI vision + - bugfix: TV cameras can now have their network settings adjusted as intended. +2021-10-21: + MistakeNot4892: + - tweak: Brute and burn meds no longer stack with regenerative serum. + - tweak: Light tubes and floodlights are higher range. +2021-10-31: + Kaksisilma: + - tweak: Ion Thruster density is now set to 1. + PsyCommando: + - bugfix: Fix cryopods without control computers from runtiming during init. + lolman360: + - bugfix: plasmacutters now cut mineral walls +2021-11-01: + MistakeNot4892: + - tweak: Painkillers will now apply their additional effects at much lower cumulative + dosage. +2021-11-02: + PsyCommando: + - bugfix: Fixed runtime on autosetting airlocks placed outside an area. + - bugfix: Fixed runtime on building an external airlock outside an area. + anconfuzedrock: + - tweak: graphite is now spawnable and orderable. +2021-11-03: + NataKilar: + - bugfix: Fixes a bug with blueprint and shuttle landing vision causing mobs to + see blackness. +2021-11-07: + MistakeNot4892: + - rscadd: Added behavior for reloadable energy weapons. +2021-11-09: + Andromeda-K22: + - tweak: machines no longer directly check brainloss, but instead rely fully on + dexterity checks. + - balance: dexterity is influenced by brain damage, starting at 30 brainloss (configurable). + Dexterity loss is on a sliding scale. + MistakeNot4892: + - experiment: There is now a weather system on exoplanets. Take your umbrella. +2021-11-14: + Kaksisilma: + - tweak: painkillers now have a number of modular vars for use in the creation of + subtypes. +2021-11-24: + SolatK: + - bugfix: Russian radio keys work again. +2021-11-27: + SolatK: + - tweak: Sleeper uses actual drug dosages to stop you from overdosing +2021-12-01: + PsyCommando: + - bugfix: Blanks don't runtime. +2021-12-02: + PsyCommando: + - tweak: File changes. + - tweak: Fishes can float now. +2021-12-03: + NotRanged: + - tweak: Lying down while facing left or right now lays you down left or right. + - tweak: You can now change facing direction while lying down. + PsyCommando: + - tweak: Tweak inventory hiding fix. +2021-12-04: + MistakeNot4892: + - tweak: Utility frames, Kharmaani and adherent now bleed exciting new colours. + - tweak: Human subtypes can now share blood without triggering a rejection. +2022-01-03: + Gaxeer: + - bugfix: fix looping APC power down sound +2022-01-11: + Gaxeer: + - bugfix: fix the bug with grab-moving dead mob +2022-01-24: + PsyCommando: + - tweak: Changes to human mob initialization. +2022-01-27: + Noelle Lavenza: + - bugfix: Brute damage healing medications now heal brute damage again.. +2022-02-02: + Noelle Lavenza: + - bugfix: Sometimes, thrown fruit smudges would fail to save. That's fixed now. +2022-02-14: + comma: + - bugfix: Network relays will now attempt reconnect on their own, so if router had + a blackout, they'll rejoin on their own without manual reboot. + keIgaras: + - balance: if you hit a person against a window while they are in a grapple, you + release them from the grapple, also increased the duration of the weakness effect + from 1 to 2 seconds +2022-02-16: + keIgaras: + - bugfix: You can force move mob on catwalk in passive grab +2022-02-18: + keIgaras: + - bugfix: Fix bug where sprites for open doors were not displayed +2022-02-20: + comma: + - bugfix: Cannot phase onto low walls through solid windows anymore. + - bugfix: Shuttle chairs now display their bars in raised state too +2022-02-24: + SierraKomodo: + - rscadd: You can now remove ID cards from wallets with AltClick. This only works + for human mobs, and only if you're holding or wearing the wallet. + keIgaras: + - tweak: Change the location of the ui_storage, now it is more convenient +2022-03-02: + NataKilar: + - bugfix: Fixed a bug where wall damage would not be retained when moving a shuttle +2022-03-14: + SierraKomodo: + - bugfix: Deaf mobs no longer see 'You hear something about' messages while asleep. + keIgaras: + - rscadd: added sofa, rounded chairs and updated armchair sprites + - tweak: fixed names of chairs in the construction panel +2022-03-21: + hermaplusplus: + - bugfix: Fixes potential index out-of-bound error when filling grown foods with + reagents. +2022-03-24: + PsyCommando: + - bugfix: Brains removed from someone's head now properly gets renamed to whoever + the brain owner was. + - bugfix: Organs now properly deleted in some cases where they wouldn't be. +2022-03-28: + PsyCommando: + - tweak: Refactored fabricator UI. +2022-04-10: + PsyCommando: + - bugfix: Explosion won't damage a human mob with the godmode flag on anymore. +2022-04-16: + NataKilar: + - bugfix: Fixes a bug causing windows and pipes to be constructed incorrectly. +2022-04-25: + NataKilar: + - tweak: Machinery which previously connected to cables directly for power now require + terminals, which can be added by attacking the machine with a stack of cables. +2022-04-29: + PsyCommando: + - bugfix: Fix organ surgery. + - bugfix: Manually spawned human mobs of the "human" species now spawn with a language. +2022-05-04: + PsyCommando: + - tweak: Greeting message now check if your starting loadout actually gives you + a headset before advising you on how to talk through your headset.. +2022-05-09: + PsyCommando: + - bugfix: Godmode human now properly ignore fall damage, shock, and dislocation + effects. + - bugfix: Fix heart not restarting on rejuv. +2022-05-10: + NataKilar: + - rscadd: Adds user accounts and network groups which allows for custom access systems + tied to computer networks + - rscadd: Adds access requirements tied to computer files for read/write + - rscdel: Removes previous grant based computer network access system + - tweak: You can now hack industrial fabs to print shields, or craft a buckler from + a stool. +2022-05-12: + afterthought2: + - tweak: Engine power use has been decreased substantially. +2022-05-13: + MistakeNot4892: + - tweak: You can now carry things up ladders and through space with grabs. + PsyCommando: + - bugfix: Dislocated limbs now show in medical scans again. + - bugfix: Dislocating someone's limb now causes pain again. + - tweak: Now get feedback when trying to use a jointlock or dislocate someone's + limbs and don't have the required skills. +2022-05-15: + tag if you want to specify another name or several people. -->: + - tweak: Upward pointing cable stubs now give proper feedback, and install properly + when clicked on with a cable coil in hands. You used to need to click on the + turf instead before, which was a bit confusing. +2022-05-18: + keIgaras: + - rscadd: new icons for vents and scrubbers +2022-05-22: + MistakeNot4892: + - tweak: Inflatables are now craftable. +2022-05-26: + quardbreak: + - rscadd: Progress bars use gradient function for transit animation now. + - rscdel: Failure animation for progress bars has been removed. +2022-05-30: + MistakeNot4892: + - tweak: Ported Skrell from Stella and added to the Bay alien roster. +2022-06-03: + SolatK: + - tweak: Airlock components panel now opens with wrench +2022-06-04: + MistakeNot4892: + - tweak: Removes HULK, FAT and LASER mutations. +2022-06-05: + gyurka66: + - bugfix: Fixed the TEG icon + - maptweak: Added SM to engineering + - maptweak: Removed 2 of 3 solars +2022-06-06: + MistakeNot4892: + - tweak: Tajaran icon has been updated with new work from Azlan. + PsyCommando: + - soundadd: Added sound for some tool interactions with the axes and hatchets. + - tweak: Config `expanded_alt_interactions` allows for various generic actions (look, + grab, drop, rotate) to show up when alt-clicking. + - soundadd: Changed the handling sounds for several material stacks to something + more fitting. +2022-06-10: + PsyCommando: + - bugfix: Fixed how some tool interactions wouldn't play tool sounds. +2022-06-15: + PsyCommando: + - tweak: Generic plants can now be cut. Trees can be chopped down with an axe. + - soundadd: Added several sound effects when dealing with generic plants. +2022-06-16: + gyurka66: + - maptweak: Randomised Ministation Asteroid Field +2022-06-20: + MistakeNot4892: + - tweak: GPS units now provide a visual compass to track each other. +2022-06-22: + NataKilar: + - tweak: Network machinery now has lower tech requirements across the board. + - tweak: Network broadcasters now have their signal strength scale with the rating + of installed microlasers. + - rscadd: Computer networks are now able to communicate over PLEXUS. + - rscadd: Adds PLEXUS uplinks, machinery which allows devices to connect to PLEXUS + in conjunction with a PLEXUS repeater. + - tweak: Network signal simulation has been adjusted slightly. Connection strengths + should be comparable with old setups. +2022-06-25: + MistakeNot4892: + - tweak: Species previews are no longer naked. +2022-07-01: + MistakeNot4892: + - tweak: Construction skill will now speed up some tool interactions. +2022-07-25: + PsyCommando: + - tweak: More things are now considered pens. Like the flashlight pen. +2022-08-03: + NataKilar: + - rscadd: Adds stirling engines to the game. These engines produce power from a + temperature differential of two gas sources. +2022-08-23: + MistakeNot4892: + - tweak: Fabricator recipes now use matter units universally, including for reagent + requirements. + Penelope Haze: + - tweak: Broadly retools cocktail ratios, changing some cocktail ingredient amounts + and improving their display in the codex. + PsyCommando: + - bugfix: Fixed top hat not showing up on the mob sprite. + - bugfix: Fixed balaclava and other masks turning people bald. + - bugfix: Fixed a lot of hats not hiding hair under them. +2022-08-27: + PsyCommando: + - admin: The list for spawning material stacks is now sorted by type name. So its + a bit more useful. + - tweak: Paper shredder gives better user feedback. +2022-08-29: + MistakeNot4892: + - tweak: Overmap position updates ten times faster now. Exciting. + PsyCommando: + - tweak: Alarms have a built-in unbreakable tesla-link and don't need a console + screen and keyboard part anymore to be usable. + - tweak: Pipe meters have unbreakable built-in components now. + - tweak: Buttons have unbreakable tesla-link and transmitters/receiver in them now. + - tweak: Light switches have unbreakable tesla-links. + - tweak: Lights have unbreakable tesla-links in them now. + - tweak: Airlock sensors, and airlock access buttons have unbreakable parts now. + - tweak: Tweaked police tape. Now called barricade tape, and the tape itself now + handles neighbours better. +2022-08-30: + MistakeNot4892: + - tweak: Vox icons have been reworked. +2022-09-06: + MistakeNot4892: + - tweak: Overdosing is now calculated across all reagent holders (blood and ingested) + rather than per holder. +2022-09-15: + PsyCommando: + - tweak: Laptops, tablets, and telescreen are now only buildable at the protolathe. + - bugfix: Cryogenic console should now properly align to walls on most maps. + - tweak: Keycard authentication device should be offset properly. +2022-09-20: + PsyCommando: + - bugfix: Hopefully set cryopod console offsets correctly this time. +2022-09-24: + PsyCommando: + - bugfix: Fix spectrometer buildstate. +2022-10-02: + Penelope Haze: + - tweak: Drinking smaller amounts makes you more sensitive to tastes +2022-10-04: + PsyCommando: + - tweak: Ores now stack. + - tweak: Can now pick a random ore stack from the ore box. + - tweak: Ore box has alt interactions. +2022-10-07: + PsyCommando: + - tweak: Reagent dispensers can now be refilled via alt interactions. + - tweak: Made the welder pack printable, and made it now have an integrated welding + tool. Its now much more useful. +2022-10-09: + 'tetra zeta ': + - imageadd: new guitar sprites! +2022-10-13: + PsyCommando: + - bugfix: Fix possible duplicate reagent init for reagent containing rings. +2022-10-16: + MistakeNot4892: + - tweak: Browser tables look nicer. + - tweak: Some coloured text may be different. It is a mystery. +2022-10-23: + MistakeNot4892: + - tweak: Raiders, mercs, wizards and ninjas no longer share a single access type. + - imageadd: Some stock parts have been resprited using icons from Azlan. +2022-10-24: + MistakeNot4892: + - tweak: Using 'say' or 'me' in the client text bar will now show the typing indicator + as though you used the F3 hotkey. + - tweak: Synthetic mobs and ghosts now have their own speech overlay appearance. +2022-10-28: + MistakeNot4892: + - tweak: Antag PDAs have been customised. +2022-10-30: + noelle-lavenza: + - rscadd: Adds inhalers. + - rscadd: Sleepers can now remove chemicals from the lungs via a lung lavage. + - tweak: Autoinjectors in oxygen deprivation pouches have been replaced with oxygel + inhalers. + - tweak: Chemicals can now be properly inhaled into the lungs. + - tweak: Coughing removes one to two units of reagents from your lungs. + - tweak: Coughing can now only be manually done once every three seconds. +2022-10-31: + MistakeNot4892: + - tweak: Ambient light will now apply to simulated turfs. +2022-11-06: + PsyCommando: + - tweak: Tweaked police tape. Now called barricade tape, and the tape itself now + handles neighbours better. + - tweak: Photo cameras now have skilled interactions. And can eject their film cartridge. + - tweak: Hand labeler can now be refilled with paper sheets, or paper material sheets. + It can also now remove labels. And has a new menu for changing mode. + - tweak: Fax machine is now buildable, and make use of the network system. + - tweak: Fax machine has a new UI, and new functionalities. Like history logging + and contact saving. The data is saved to a data disk and can be transferred + from machine to machine. + - tweak: Numerous paperwork simple browser UIs have had some touch up and polish. + - bugfix: fixed item drop sound playing when throwing something. + - soundadd: added a balloon bursting sound effect. +2022-11-08: + PsyCommando: + - bugfix: Fixed welderpack getting stuck in the inventory. + - tweak: Welderpack now has its own attached welding gun, which works a lot like + defibrillator paddles. + - bugfix: Telescreen can no longer be used when held, as it was intended. + - bugfix: Telescreen now properly install on walls. + - imageadd: Added basic directional icon states for the telescreen. + - imageadd: Added construction state icons for the telescreen. + - tweak: Changed all instances of telescreens in the map files to use auto directional + offset, and face proper direction. + - bugfix: Fixed some empty box variants having no storage slots on spawn. +2022-11-10: + PsyCommando: + - tweak: Engineer borgs now have upgraded from a crowbar to a brace jack. +2022-11-11: + PsyCommando: + - bugfix: Prevent mapped security cameras from becoming completely unlocked and + accessible by anyone whenever there's a network outage. +2022-11-15: + PsyCommando: + - bugfix: Fix limb reattachment surgery not properly installing any contained internal + organs once the last step was completed. +2022-11-17: + MistakeNot4892: + - tweak: Liver and brain regeneration has been tweaked, and all internal organs + will now regenerate slowly to a point. +2022-11-20: + PsyCommando: + - bugfix: Fix disconnected pipes + blastdoors button on desperado/mercenary base. +2022-11-22: + PsyCommando: + - imageadd: Added some fairly bad wrapped package icons, and wrapped gifts icons. +2022-11-23: + PsyCommando: + - bugfix: Fixed /obj/item/chems being shattered in nullspace causing a runtime. +2022-11-25: + PsyCommando: + - bugfix: Fix mapped network machinery fields. + - bugfix: Fixed bad switch case in robot_component/take_damage() causing BURN and + ELECTROCUTE damage to get ignored. +2022-11-27: + PsyCommando: + - bugfix: Fixed bad icons on /obj/machinery/partyalarm. + - bugfix: Fixed bad icons on /obj/machinery/dummy_airlock_controller. + - bugfix: Fixed bad icons on /obj/machinery/button/holosign. + - bugfix: Fixed bad icons on /obj/item/personal_shield. + - bugfix: Fixed bad icons on /obj/item/shield/energy. + - bugfix: Fixed bad icons on /turf/simulated/floor/tiled/stone. + - bugfix: Fixed bad icons on /obj/item/bone/skull. + - bugfix: Fixed bad icons on /obj/item/bee_smoker. + - bugfix: Fixed bad icons on /obj/item/shovel/spade. + - bugfix: Fixed bad icons on /obj/structure/crystal. + - bugfix: Fixed bad icons on /obj/item/storage/belt/archaeology. + - bugfix: Fixed /obj/abstract/map_data not showing up in mapping tool. + - bugfix: Fixed /obj/item/underwear not showing up in mapping tool. + - bugfix: Fixed /obj/abstract not showing up in mapping tool. + - bugfix: Fixed easily missed bad icon_state name on /obj/item/crowbar/brace_jack. + - bugfix: Fixed easily missed bad icon_state name on /turf/simulated/floor/tiled/monofloor. + - bugfix: Fixed some metallic materials causing runtimes from not having wall icon + states defined properly. + - bugfix: Made a bunch of /obj/structure/closet/crate show a more accurate icon + in the map editor instead of the default blank locker icon. + - imageadd: Added simple directional icons for airlock controller buttons and sensors. + - tweak: Allowed connecting fuel pipes to TEG circulators. +2022-11-30: + PsyCommando: + - bugfix: Mapped ladders no longer change the turf they're on to the map default's + open turf if they're on a lattice and any open turf types already during init. + This could cause exterior/unsimulated open turfs to replace a simulated open + turf and cause serious atmos issues. + - bugfix: Fixed some wall-mounted machines acting as fully constructed, when a circuitboard + was installed and no wiring installed. +2022-12-05: + PsyCommando: + - tweak: Tweaked the airlock controller UI a little bit for the advanced airlock + controller. Makes it fit better in its window, and reorganized the buttons around + to look a bit less messy. + - tweak: Adjusted directional offsets for airlock devices, so they actually are + aligned to walls. + - tweak: Adjusted directional offsets of warning signs since they kept covering + up airlock devices on the tradeship map. + - bugfix: Fixed sanitizing id_tags set via multitool on the airlock machinery. + - bugfix: Fixed airlock machinery generally falling out of sync with eachother. + - imageadd: Added new icons for airlock sensor and airlock access button. They have + overlays and directions now. +2022-12-21: + MistakeNot4892: + - tweak: There is now a grace period on losing your brain before your mob will die. +2023-01-14: + MistakeNot4892: + - tweak: Randomize Appearance is back. +2023-01-18: + NataKilar: + - bugfix: Items no longer appear heavily damaged regardless of their health +2023-02-01: + quardbreak: + - bugfix: Fixed missing circuit recipe for radiocarbon spectrometer. +2023-02-06: + Chinsky: + - bugfix: Machines with network connector stock parts now expose all of their functions + over network +2023-02-09: + PsyCommando: + - bugfix: fixed vents being nearly silent. +2023-02-10: + Chinsky: + - bugfix: Remote terminal commands now properly check access of the target machine +2023-02-13: + Chinsky: + - tweak: Remapped Tradeship main shuttle to a slightly more spacious one + - bugfix: Steel katanas were woefully underpowered, they are now actually sharp + - tweak: Steel is harder now +2023-03-25: + PsyCommando: + - bugfix: Fixed geothermal generators. +2023-04-05: + MistakeNot4892: + - tweak: Tables now default to having no borders in browser pages. +2023-05-11: + MistakeNot4892: + - tweak: Many interactions with empty hands now have dexterity checks associated. +2023-05-29: + Penelope Haze: + - tweak: Energy armor now protects against electrocution damage. However, unlike + insulated equipment, it doesn't do anything to prevent electrocution in the + first place. +2023-06-04: + Loaf: + - tweak: Total rewrite of telecomms, refer to GitHub PR for details. + MistakeNot4892: + - tweak: Some significant changes to the core atmospherics simulation; please report + bugs. +2023-06-18: + Penelope Haze: + - imageadd: Dirt turfs look darker now, courtesy of some Polaris sprites. +2023-06-22: + MistakeNot4892: + - tweak: Strong (narcotic) painkillers and mild (non-narcotic) painkillers are now + distinct chemicals. + PsyCommando: + - tweak: Signs are easier to place now, and do a better job keeping their info when + installed and removed repeatedly. +2023-07-01: + Penelope Haze: + - bugfix: Decompiler grenades will no longer waste the contents of consumed objects. +2023-07-02: + MistakeNot4892: + - tweak: Reworked examine to show 'you are' for self-examination. Reordered some + examine elements. +2023-07-04: + PsyCommando: + - bugfix: fixed carbon paper creating a copy of itself when trying to split the + original and copy. + - bugfix: fixed the paint spray having an interaction to remove a carbon copy from + it for reasons. +2023-07-06: + MistakeNot4892: + - tweak: Some mob types now potentially get radiation poisoning. + Tennessee: + - imageadd: Chairs now have mapping previews. +2023-07-12: + Penelope Haze: + - bugfix: Some exoplanet terrain should be generated more smoothly, as intended. +2023-07-28: + MistakeNot4892: + - tweak: Paramount Coercion is now 'Beguile', and does not have a channel or a risk + of backblast. It also prompts the target to join willingly, knocking them unconscious + and dealing brain damage so you can escape if they refuse. +2023-09-02: + AliceDTRH: + - bugfix: Fixed the job whitelist not reading keys properly +2023-09-04: + LenSkozzy: + - bugfix: fixed folding@home +2023-09-11: + LenSkozzy: + - bugfix: Fixed ID object initialization + NataKilar: + - bugfix: Fixed water tanks being unable to be refilled +2023-10-01: + John: + - tweak: Lifepods avoid location they are escaping from. +2023-10-05: + MistakeNot4892: + - tweak: Surgery now has more/different sounds. +2023-10-15: + MistakeNot4892: + - tweak: You will now be able to tell if you can equip an item by mousing over the + equipment slot with the item in your active hand. +2023-10-18: + MistakeNot4892: + - tweak: Falling a longer distance will now cause more damage. +2023-10-20: + MistakeNot4892: + - tweak: Acid resistance has been tweaked; report things melting or not melting + unexpectedly on the bug tracker. + - tweak: Flashlights, flares and lamps have new overlays and some new states. +2023-10-24: + MistakeNot4892: + - tweak: Exterior turfs and lighting blend across z-level transitions now. +2023-11-09: + MistakeNot4892: + - tweak: Taj can now cycle voidsuits and have custom icons for them. +2023-12-07: + MistakeNot4892: + - tweak: Suit sensors are now an accessory on your uniform that can be removed. +2023-12-09: + MistakeNot4892: + - tweak: Examining batons and energy guns should now show you the cell they have + loaded, or require loading. +2023-12-14: + MistakeNot4892: + - tweak: Neo-avian icons have been reindexed so may look slightly different. + - tweak: Drills now function as shovels. + - tweak: Clay can now be dug up from stationary drills. + - tweak: Duct tape can be used to repair prosthetic faults. +2023-12-18: + MistakeNot4892: + - tweak: Updated ministation from ScavStation. Lots of changes, see PR. + - tweak: Jump is now handled by selecting jump from the prepare button on the bottom + right of the UI, then clicking the target. +2023-12-19: + CheeseDogg0: + - tweak: Changed some of the more ridiculous numbers to bring them more in line + with real life +2023-12-27: + MistakeNot4892: + - tweak: Heating atoms like beakers with fire or a welding torch should be more + consistent now. +2023-12-28: + MistakeNot4892: + - tweak: Some mech equipment origin tech has changed. Please report any missing + or odd values. +2024-01-08: + Greenjoe12345: + - imageadd: Pew sprites from Aurorastation +2024-01-09: + MistakeNot4892: + - tweak: Simple mobs will now show a windup before hitting you in melee, allowing + you to dodge. +2024-01-12: + NataKilar: + - tweak: Eases contamination protection requirements slightly +2024-01-14: + MistakeNot4892: + - tweak: Manuals have been rewritten to pull information from the codex instead + of the wiki. +2024-01-15: + MistakeNot4892: + - tweak: You can now use arrow buttons to adjust markings and hair in character + setup. +2024-01-16: + MistakeNot4892: + - tweak: Configuration has been rewritten to a new format. Servers with configuration + changes from defaults will need to run the server to generate the new config + file, then mirror their configuration changes in the new config system. Check + the PR body for details. +2024-01-23: + MistakeNot4892: + - tweak: All living mobs can now dream. +2024-01-24: + MistakeNot4892: + - tweak: All living mobs can now hallucinate. +2024-02-01: + MistakeNot4892: + - tweak: Bearcat wreck now has network infrastructure. + - tweak: Egg and donut boxes are slightly fancier. + - tweak: Pizza stacks have been enhanced to dangerous levels. +2024-02-10: + MistakeNot4892: + - tweak: Loot piles have been added to the Tradeship underside. +2024-02-16: + MistakeNot4892: + - tweak: Plates are no longer part of food when it emerges from the microwave, and + must be retrieved from the dinnerware vendor and used to plate food. +2024-02-17: + MistakeNot4892: + - tweak: Bricks can now be used to build walls without girders. +2024-02-19: + MistakeNot4892: + - tweak: Trees can be cut down into logs. +2024-02-27: + MistakeNot4892: + - tweak: Tails may not be covered by some clothing anymore. +2024-02-28: + MistakeNot4892: + - tweak: The Chinese food vendor has slightly different wares. +2024-02-29: + MistakeNot4892: + - tweak: Hot temperatures can now melt items. +2024-03-02: + MistakeNot4892: + - tweak: Trees and logs give more logs/planks. + - tweak: Static fluid turfs are now dynamic fluid turfs. +2024-03-03: + MistakeNot4892: + - tweak: Snow and grass can be removed with a shovel. +2024-03-06: + MistakeNot4892: + - tweak: Silver/gold/diamond pickaxes are now steel/plasteel/titanium. +2024-03-08: + MistakeNot4892: + - tweak: Combs, brushes and files are available in loadout. + - tweak: New grooming activities added. + - tweak: Long grass will partially mask things inside it. +2024-03-11: + MistakeNot4892: + - tweak: You can now dry yourself or others off with a towel. + - tweak: You will now drip contact reagents onto your turf if you get splashed or + dunked. +2024-03-13: + MistakeNot4892: + - tweak: Atom temperature will equalize slower. +2024-03-14: + MistakeNot4892: + - tweak: Exoplanet plants will now drop seeds. +2024-03-19: + MistakeNot4892: + - tweak: Fabricators like autolathes can no longer recycle arbitrary items. +2024-03-21: + MistakeNot4892: + - tweak: Mining now requires a tool of sufficient hardness. + - tweak: Tool crafting is now restricted to specific stack types. +2024-03-25: + MistakeNot4892: + - tweak: More ore per ore! +2024-04-06: + Chinsky: + - tweak: Liberia away site is no longer mandatory spawn + - bugfix: Fixed planets having wrong colors when seen on skybox +2024-04-09: + MistakeNot4892: + - tweak: Cotton can be harvested and fed to textiles fabricator as a source of cloth. +2024-04-10: + MistakeNot4892: + - tweak: Farm plots are now dug rather than crafted. + - tweak: Various agriculture changes! Check the PR for more details. +2024-04-16: + MistakeNot4892: + - tweak: Butchery will now produce a wider variety of items. + - tweak: Universal enzyme can be made from rennet. +2024-04-18: + MistakeNot4892: + - tweak: Closets can now be locked with a physical lock. + - tweak: Vox must now pick between pressure resistance and speed using the Toggle + Pressure Seal verb. + - tweak: 'Lots of cooking changes! Refer to PR #3704 on the Nebula GitHub for specific + details.' +2024-04-21: + MistakeNot4892: + - tweak: Running to exhaustion will now cause a mood stressor. + - tweak: Sleeping in a bed for thirty seconds will remove exhaustion and add a well + rested mood boost. +2024-04-26: + MistakeNot4892: + - tweak: Non-high vis accessories on clothes will show as part of the examine string. +2024-04-30: + MistakeNot4892: + - tweak: Growns can be processed into different forms based on the grown. Apples + will be sliced, potatoes will be turned into sticks, and carrots will be chopped. + You can also turn sticks into chopped veggies by using a knife again. + - tweak: You can now extract seeds from growns using Botany skill and a sharp knife. + - tweak: Potatoes can be planted directly without extracting seeds. +2024-05-04: + MistakeNot4892: + - tweak: Gibbing mobs or bodyparts will now drop usable meat and bone. + - tweak: You can now craft hand axes. +2024-05-06: + MistakeNot4892: + - tweak: Using a half-finished slapcrafting recipe in hand will dismantle it. + - tweak: Crafting tools requires a binding material. + - tweak: Serpentid can now leave pheremone traces with a set of emotes. +2024-05-08: + MistakeNot4892: + - admin: Build mode ladders have been removed, and build mode relocate and move + have been merged. +2024-05-13: + MistakeNot4892: + - tweak: Mice will now flee from harm. +2024-05-14: + Penelope Haze: + - tweak: Area on-enter flavortext blurbs will be able to be shown to a player again + after a 15 minute cooldown, rather than only once ever. +2024-05-22: + Penelope Haze: + - soundadd: added lobby music for Shaded Hills, by Kevin Macleod. +2024-06-03: + LizLavenza: + - tweak: enabled edge sprites for path turfs + - bugfix: fixed grass turfs missing corners + - bugfix: fixed crafted tall boots missing icons + - bugfix: fixed sandals in Shaded Hills loadout being normal shoes +2024-06-09: + PsyCommando: + - soundadd: Added phone key tones sounds. + - soundadd: Added extra briefcases sounds for locking and unlocking. + - imageadd: Modified the secure briefcase, briefcase, secure safe icons with some + new overlays, and made them use the new item icon layout format. + - balance: Made it a lot less likely to unlock a secure briefcase/charge stick/safe + with a multitool if you don't have a high device skill. So, now anyone with + a multitool and a screwdriver won't be able to unlock those in a single try + as quickly and easily. + - bugfix: Secure briefcases cannot quick gather items on the turf while they're + locked anymore. + - bugfix: Storage objects no longer cause the UI to behave weirdly when trying to + access it several times in a row. (open alt interaction bug) + - bugfix: The lockable UI is now properly scaled to it's window. + - tweak: The lockable UI is a bit more polished overall. +2024-06-10: + MistakeNot4892: + - tweak: Bows/crossbows have been adjusted. Please report issues to the tracker. +2024-06-13: + NataKilar: + - bugfix: Fixed space tiles not creating vacuums in certain conditions +2024-06-16: + Penelope Haze: + - tweak: Meteor is now a votable mode on Exodus. Oh no!! +2024-06-19: + Penelope Haze: + - experiment: Ammo magazines will not initialize their contents until first interacted + with, which makes startup faster but could cause bugs. Report any issues on + the issue tracker! +2024-06-20: + MistakeNot4892: + - tweak: You can now dip things like stacks of skin into barrels of water, wells + or rivers. +2024-07-06: + Penelope Haze: + - tweak: Ebony walls, floors, doors, and railings on Shaded Hills have all been + replaced with walnut variants. + - tweak: Most wall sconces now start unlit. + - balance: A full lantern now burns for an hour, but only holds 60 units of fuel. +2024-07-14: + MistakeNot4892: + - tweak: Cigarettes and welding torches will now heat atom reagents slower. +2024-07-25: + Penelope Haze: + - soundadd: added a more fitting end credits theme for Shaded Hills +2024-07-26: + Penelope Haze: + - tweak: Digging pits and trenches now checks athletics instead of construction. +2024-07-27: + Penelope Haze: + - tweak: When spawning with impaired vision on Shaded Hills, you now receive pince-nez + glasses instead of modern glasses. +2024-07-31: + MistakeNot4892: + - tweak: Regular gauze packs can now be used to make herbal poultices. +2024-08-08: + Penelope Haze: + - tweak: Renamed fire clay goods to earthenware goods. +2024-08-09: + Penelope Haze: + - imageadd: added better compost bin sprites, based on those from Sunset Wasteland + - imageadd: added produce bin sprites, modified from Sunset Wasteland's +2024-08-11: + Penelope Haze: + - tweak: Mortars (for grinding) are now capable of holding more than one item at + a time. +2024-08-13: + MistakeNot4892: + - tweak: Blocking with a shield now uses close combat skill, and bucklers will not + survive forever. + NataKilar: + - tweak: Solid state reagents now behave mostly like solid state reagents. +2024-08-14: + MistakeNot4892: + - tweak: Bows are now drawn by clicking and holding. +2024-08-15: + Penelope Haze: + - tweak: amatoxin and psychotropics can be composted in a composter +2024-08-16: + Penelope Haze: + - balance: lowered the chance of wild plants bearing harvestable fruit by about + half, to incentivize farming + - tweak: inhabited rooms on Shaded Hills now start with open shutters and lit lanterns + - tweak: Pumpkins and watermelons are now large objects, while other produce is + small. + - tweak: spoons can now be used as a very poor shovel +2024-08-24: + Penelope Haze: + - balance: Chickens lay fewer eggs less often that are fertilized more often but + grow slower as both eggs and chicks. + - tweak: Examining soil plots can now give warnings if a plant is low on nutrients + or water (<20% each). +2024-08-25: + MistakeNot4892: + - tweak: Spellbooks can go into bookshelves. +2024-08-26: + Noelle Lavenza: + - admin: Refreshing the View Variables window no longer clears its search filter. +2024-08-28: + MistakeNot4892: + - tweak: Brooms can be used to sweep up dirt. +2024-08-31: + MistakeNot4892: + - tweak: Open containers, when heated, can boil off their liquid contents. +2024-09-05: + Penelope Haze: + - bugfix: Fixed spawning bear dens in the woods on Shaded Hills. +2024-09-07: + MistakeNot4892: + - tweak: Condiment bottles that were not produced by the Condimaster will no longer + change appearance when empty. +2024-09-08: + MistakeNot4892: + - tweak: Rabbits have had a resprite. + - tweak: You can now drink from and wash your hands in wells and flooded turfs. +2024-09-09: + MistakeNot4892: + - tweak: Adds a town bell to Shaded Hills. + - tweak: You can now examine a cow or goat to see how far it is from milking. + - tweak: Diyaab can be sheared for fleece. +2024-09-12: + MistakeNot4892: + - tweak: Salt and fools' gold can be mined on Shaded Hills. +2024-09-14: + Atermonera: + - tweak: Corrected a number of bad placement/offsets for wall-mounted items on the + exodus map + MistakeNot4892: + - tweak: Bookcases are a bit fancier. + - tweak: Many more intolerances have been added to character traits. +2024-09-23: + MistakeNot4892: + - tweak: You can now resist out of straightjackets. +2024-09-27: + Penelope Haze: + - imageadd: added overlays to show when a crafted or dried waterskin is closed + - imageadd: added a new sprite for waterskins made from dried ruminant stomachs +2024-09-30: + Atermonera: + - bugfix: Fixed some grammatical issues in location event strings. +2024-10-05: + MistakeNot4892: + - tweak: Sledgehammers can demolish non-reinforced walls. +2024-10-08: + Sutures: + - tweak: Generic premapped 'meat' on Shaded Hills has been replaced with beef or + chicken subtypes where applicable. + - tweak: Renamed generic 'wood' to 'oak' if the fantasy modpack is included. + - tweak: Remapped the Shaded Hills inn substantially. + - tweak: Removed warnings when moving against a lit dense fire source, because you + can't step into it anyway. + - soundadd: Added sounds for brooms and brushes. + - imageadd: Added a wood plank texture to wood pews. + - imageadd: Added a wood plank texture to wood tables, used if the fantasy modpack + is included. + - bugfix: Fixed wall banners not starting with banners. +2024-10-23: + MistakeNot4892: + - tweak: Dough now requires a 60C temperature and does not use egg. + - tweak: Flatbread now uses unleavened dough, made without yeast, while pies use + pie crust. Check the codex for updated recipes. +2024-11-01: + MistakeNot4892: + - tweak: Curries, soups and stews have been rewritten, please refer to the codex + for recipes. +2024-11-05: + Neerti: + - tweak: Mining drill braces are now crafted from steel sheets directly. + - balance: Microlasers added to mining drills no longer multiply ore out of the + ground, but make the drill mine faster, proportionally increasing the energy + usage. + - balance: Capacitors added to mining drills are less powerful. +2024-11-13: + Penelope Haze: + - imageadd: Added a new wooden bucket sprite. + - tweak: Quills now have a limited amount of ink, which can be refilled in an inkwell. + - tweak: Crayons are now slowly used up while writing on paper, at a rate of one + charge per 25 characters. (Crayons have a default of 30 charges.) + - tweak: Added new furniture to the Shaded Hills inn. +2024-11-18: + MistakeNot4892: + - tweak: Swapped barrel icons out for Doe's much nicer barrels. +2024-12-05: + ophelia: + - tweak: You can now put any disk into the research design database or research + design console, but only the correct disk type (tech disk or design disk) will + function. +2024-12-07: + MistakeNot4892: + - tweak: Most wooden floors and tables on space maps are now chipboard laminate + instead. +2024-12-21: + Penelope Haze: + - tweak: Makes weather effects slightly more transparent. +2024-12-23: + ophelia v0.8: + - imageadd: added new dirt and mud tile sprites + - imageadd: added new wooden chest sprites, by Doe + - tweak: mud and soil plots are now properly greyscaled to soil material color +2025-01-03: + MistakeNot4892: + - tweak: Raw plant oil no longer works as lantern fuel; it must be mixed with powdered + graphite first. +2025-01-08: + MistakeNot4892: + - tweak: Mud and blood can now leave footprints. +2025-01-15: + MistakeNot4892: + - tweak: The way you interact with barrels and well has been significantly reworked; + clicking with a bucket or tool should give a list of options to pick from. Please + report bugs with this on the tracker. +2025-01-16: + MistakeNot4892: + - tweak: The White and Minimalist HUD styles can now be customised to use a specific + overlay color. + - tweak: The Shaded Hills river now flows north. + - tweak: Snow, mud and sand will now show footprints. +2025-01-19: + MistakeNot4892: + - tweak: Intents have been rewritten and moved, please report any issues with intent + selection. +2025-01-21: + Penelope Haze: + - tweak: Mud can now receive footprints with any reagent other than mud. No more + conspicuously missing bloody footprints! +2025-01-22: + MistakeNot4892: + - tweak: Swords on Shaded Hills can be sharpened using whetstones or grindstones. + - tweak: Guns can now be fired from rigs regardless of dexterity. +2025-01-29: + MistakeNot4892: + - tweak: Various map changes to Bearcat, crashed pod, and several others. Please + report issues! +2025-02-02: + Penelope Haze: + - tweak: Modified liquid and coating presentation to be more fancy. +2025-02-07: + Penelope Haze: + - tweak: Shears are now used to add or remove padding from objects. Wirecutters + still work as a backup, though. +2025-02-18: + MistakeNot4892: + - tweak: Modifiers like regeneration or personal shielding will now show at the + top of the screen. +2025-02-24: + Penelope Haze: + - tweak: Human and unathi sprites should be slightly brighter now. +2025-03-02: + MistakeNot4892: + - tweak: Old browser-based module selection for robots has been removed, use the + INV button to open storage like you would a belt/backpack. +2025-03-09: + Cerebulon: + - imageadd: New icons for a variety of objects, mostly machines and grenades. +2025-03-12: + Cerebulon: + - imageadd: Changed modpack Tajara to use old-style humanoid sprites instead of + a unique feline body shape which has since been used by Hnolls. +2025-03-14: + Typhin: + - bugfix: Allows parts/screwdrivers to be used on biogenerators +2025-03-25: + Penelope Haze: + - balance: Adjusts how suffocation works, meaning characters who were drowning or + in asystole start breathing as soon as the issue is resolved, rather than counting + down a timer instead. This might make brief bouts of drowning/cardiac arrest + more survivable. Please report any weirdness with breathing/suffocation on the + issue tracker. +2025-03-27: + Martin Rivard: + - tweak: removed calculate_affecting_pressure() hardcoding +2025-03-29: + Martin Rivard: + - bugfix: fixed portable flasher sprite offset +2025-04-06: + Elizabeth: + - tweak: tweaked the Forester's Hut on Shaded Hills to be more compact and have + timber-framed walls + - tweak: tweaked the inn backroom on Shaded Hills + - tweak: many of the buildings in Shaded Hills now use timber-framed, plastered, + and/or wattle-and-daub walls instead of just log walls + - soundadd: 'added a new lobby track to Shaded Hills: Adventure by Alexander Nakarada.' +2025-04-13: + Cerebulon: + - bugfix: Fixed tajaran sprite sheet overrides. +2025-04-14: + Zandario: + - admin: Added a "Toggle Browser Inspect" debug verb for debugging UIs +2025-08-22: + Sutures: + - imageadd: added new amanita mushroom plant growth states + - tweak: changed coffee plant growth states + - soundadd: added ambience to Shaded Hills river and swamp areas + - tweak: ambience should be louder and more frequent overall + - tweak: stone walls now have a slight noise effect on their sprite + - soundadd: added a boiling-water sound to cooking pots on Shaded Hills +2025-08-29: + Elizabeth: + - imageadd: added some variant sprites for cobblestone and running bond paths +2025-10-20: + MistakeNot4892: + - tweak: Crafted barrels will need barrel rims forged if the forging modpack is + in use. +2025-11-02: + MistakeNot4892: + - tweak: Drakes can no longer farm, but they can mine (in dirt). +2025-12-30: + Penelope Haze: + - tweak: Iron can now optionally be used instead of aluminum when filling sealant + tanks for sealant guns. +2025-12-31: + Penelope Haze: + - admin: Kharmaan nymph jobbans now use the "Mantid Nymph" role in the jobban menu, + rather than the Semi-Antagonist role. +2026-01-02: + Sutures: + - tweak: The equip hotkey can now place items into backpacks and wallets. +2026-01-06: + MistakeNot4892: + - tweak: Internal code for neo-avian markings has been reworked, check your sprite + accessories. +2026-01-10: + Penelope Haze: + - balance: Certain supply packs that give a random selection are now priced more + fairly. +2026-03-27: + Typhin: + - tweak: Prevented Garlic Oil from dealing TOX damage diff --git a/html/changelogs/SomeoneStoleMyNickname-2.yml b/html/changelogs/SomeoneStoleMyNickname-2.yml deleted file mode 100644 index 42aa857d7d17..000000000000 --- a/html/changelogs/SomeoneStoleMyNickname-2.yml +++ /dev/null @@ -1,37 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# maptweak -# spellcheck (typo fixes) -# experiment -# admin -################################# - -# Your name. -author: SomeoneStoleMyNickname - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. -# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Added a new digital pencode tag. [redacted] creates the string R E D A C E D in black lettes on black background to give the illusion of redacted contend in reports." diff --git a/html/changelogs/__CHANGELOG_README.txt b/html/changelogs/__CHANGELOG_README.txt index 6915dc47e25e..166e2bea8b62 100644 --- a/html/changelogs/__CHANGELOG_README.txt +++ b/html/changelogs/__CHANGELOG_README.txt @@ -1,19 +1,19 @@ -Changelogs are included with commits as text .yml files created individually by the committer. If you want to create a changelog entry you create a .yml file in the /changelogs directory; nothing else needs to be touched unless you are a maintainer. - -####################################################### - -TO MAKE A CHANGELOG .YML ENTRRY - -1. Make a copy of the file example.yml in html/changelogs and rename it to [YOUR USERNAME]-PR-[YOUR PR NUMBER].yml or [YOUR USERNAME]-[YOUR BRANCH NAME]. Only the username is strictly required, anything else is organizational and can be ignored if you so wish. - -2. Change the author to yourself - -3. Replace the changes text with a description of the changes in your PR, keep the double quotes to avoid errors (your changelog can be written ICly or OOCly, it doesn't matter) - -4. (Optional) set the change prefix (rscadd) to a different one listed above in example.yml (this affects what icon is used for your changelog entry) - -5. When commiting make sure your .yml file is included in the commit (it will usually be unticked as an unversioned file) - -####################################################### - -If you have trouble ask for help in #codershuttle on irc.sorcery.net or read https://tgstation13.org/wiki/Guide_to_Changelogs +Changelogs are included with commits as text .yml files created individually by the committer. If you want to create a changelog entry you create a .yml file in the /changelogs directory; nothing else needs to be touched unless you are a maintainer. + +####################################################### + +TO MAKE A CHANGELOG .YML ENTRRY + +1. Make a copy of the file example.yml in html/changelogs and rename it to [YOUR USERNAME]-PR-[YOUR PR NUMBER].yml or [YOUR USERNAME]-[YOUR BRANCH NAME]. Only the username is strictly required, anything else is organizational and can be ignored if you so wish. + +2. Change the author to yourself + +3. Replace the changes text with a description of the changes in your PR, keep the double quotes to avoid errors (your changelog can be written ICly or OOCly, it doesn't matter) + +4. (Optional) set the change prefix (rscadd) to a different one listed above in example.yml (this affects what icon is used for your changelog entry) + +5. When commiting make sure your .yml file is included in the commit (it will usually be unticked as an unversioned file) + +####################################################### + +If you have trouble ask for help in #codershuttle on irc.sorcery.net or read https://tgstation13.org/wiki/Guide_to_Changelogs diff --git a/html/changelogs/example.yml b/html/changelogs/example.yml index 05c234a82c0d..65bd6b448399 100644 --- a/html/changelogs/example.yml +++ b/html/changelogs/example.yml @@ -1,38 +1,38 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# maptweak -# spellcheck (typo fixes) -# experiment -# admin -################################# - -# Your name. -author: Unknown - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. -# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Added a changelog editing system that should cause fewer conflicts and more accurate timestamps." - - rscdel: "Killed innocent kittens." +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# admin +################################# + +# Your name. +author: Unknown + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added a changelog editing system that should cause fewer conflicts and more accurate timestamps." + - rscdel: "Killed innocent kittens." diff --git a/html/changelogs/mistakenot4892-structures.yml b/html/changelogs/mistakenot4892-structures.yml deleted file mode 100644 index 53f3d80fa928..000000000000 --- a/html/changelogs/mistakenot4892-structures.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: MistakeNot4892 -delete-after: True -changes: - - experiment: "A bunch of structures have been rewritten to use some shared code. As a result, you can examine most structures to see some tips on how to interact with them, and you will find several construction/deconstruction steps have changed." - - tweak: "Metal structures must be dismantled with a welding tool, while other materials use a crowbar." - - tweak: "Girders are now 'supports', and are reinforced by using a material stack on them before anchoring. Using a screwdriver will remove the reinforcement, or toggle whether or not the support will produce a fake wall." - - experiment: "This is going to be buggy, please report issues and problems." diff --git a/html/changelogs/n8toe-chemsuit.yml b/html/changelogs/n8toe-chemsuit.yml deleted file mode 100644 index 9dd5a6953ed7..000000000000 --- a/html/changelogs/n8toe-chemsuit.yml +++ /dev/null @@ -1,37 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# maptweak -# spellcheck (typo fixes) -# experiment -# admin -################################# - -# Your name. -author: N8-Toe - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. -# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Added chemical saftey suits to code, protect against gas in the air but need to be used with a face covering mask, unimplemented at this time." diff --git a/html/changelogs/sodiumshine-textbooks.yml b/html/changelogs/sodiumshine-textbooks.yml deleted file mode 100644 index 6725ef52c98b..000000000000 --- a/html/changelogs/sodiumshine-textbooks.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: Winter -delete-after: True -changes: - - rscadd: "Added textbooks. Textbooks are items that give skillbuffs while you are actively using them. Textbooks require basic literacy to use, and you must have the specific textbook for your skill level." - - rscadd: "Added a book merchant who sells textbooks." - - tweak: "Molluscs and Mollusc meat now have monetary value." - - maptweak: "Tradeship now always starts the round with a book trader available." - - maptweak: "Tradeship has four randomized textbooks in various locations at roundstart." - - experiment: "Please report balance issues (and of course bugs) that may arrise from this feature." - - tweak: "Bonus: Codex links now open new windows." \ No newline at end of file diff --git a/html/changelogs/sodiumshine-textbookwriting.yml b/html/changelogs/sodiumshine-textbookwriting.yml deleted file mode 100644 index 60a827c32131..000000000000 --- a/html/changelogs/sodiumshine-textbookwriting.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: Winter -delete-after: True -changes: - - rscadd: "Those with Master Literacy can now make their own textbooks. Blank textbooks are acquired via an autobinder and then written using a pen." - - rscadd: "Includes codex information on this process." - - tweak: "Made textbooks in general to be one size smaller to allow being put in bags." - - tweak: "Very basic support for fabricators to get colours from something else other than pipe_colors" - - experiment: "Unsure how this impacts skill balance, please report on that if there are issues." diff --git a/html/create_object.html b/html/create_object.html index 899658fdb665..a505eb7dda31 100644 --- a/html/create_object.html +++ b/html/create_object.html @@ -1,126 +1,126 @@ - - - - Create Object - - - - -
    - - - - Type
    - Offset: - - A - R
    - - Number: - Dir: - Name:
    - Where: - -

    - Number of matches: -

    -
    - -
    - -
    -
    - - - - + + + + Create Object + + + + +
    + + + + Type
    + Offset: + + A + R
    + + Number: + Dir: + Name:
    + Where: + +

    + Number of matches: +

    +
    + +
    + +
    +
    + + + + \ No newline at end of file diff --git a/html/lobby_titlescreen.html b/html/lobby_titlescreen.html deleted file mode 100644 index dc92369fe655..000000000000 --- a/html/lobby_titlescreen.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/html/panels.css b/html/panels.css index 0d1cb0cb9fbe..ac44cf54877a 100644 --- a/html/panels.css +++ b/html/panels.css @@ -1,10 +1,10 @@ -body {padding:0px;margin:0px;} -#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;} -#main {position:relative;top:50px;left:3%;width:96%;text-align:center;z-index:0;} -#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} -tr.norm {background-color:#f4f4f4;} -tr.title {background-color:#ccc;} -tr.alt {background-color:#e7e7e7;} -.small {font-size:80%;} -a {text-decoration:none;color:#a0a;} -a:hover {color:#d3d;} +body {padding:0px;margin:0px;} +#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;} +#main {position:relative;top:50px;left:3%;width:96%;text-align:center;z-index:0;} +#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} +tr.norm {background-color:#f4f4f4;} +tr.title {background-color:#ccc;} +tr.alt {background-color:#e7e7e7;} +.small {font-size:80%;} +a {text-decoration:none;color:#a0a;} +a:hover {color:#d3d;} diff --git a/html/search.js b/html/search.js index abc47a975731..ded0b9284467 100644 --- a/html/search.js +++ b/html/search.js @@ -1,33 +1,33 @@ -function selectTextField(){ - var filter_text = document.getElementById('filter'); - filter_text.focus(); - filter_text.select(); -} -function updateSearch(){ - var input_form = document.getElementById('filter'); - var filter = input_form.value.toLowerCase(); - input_form.value = filter; - var table = document.getElementById('searchable'); - var alt_style = 'norm'; - for(var i = 0; i < table.rows.length; i++){ - try{ - var row = table.rows[i]; - if(row.className == 'title') continue; - var found=0; - for(var j = 0; j < row.cells.length; j++){ - var cell = row.cells[j]; - if(cell.innerText.toLowerCase().indexOf(filter) != -1){ - found=1; - break; - } - } - if(found == 0) row.style.display='none'; - else{ - row.style.display='block'; - row.className = alt_style; - if(alt_style == 'alt') alt_style = 'norm'; - else alt_style = 'alt'; - } - }catch(err) { } - } +function selectTextField(){ + var filter_text = document.getElementById('filter'); + filter_text.focus(); + filter_text.select(); +} +function updateSearch(){ + var input_form = document.getElementById('filter'); + var filter = input_form.value.toLowerCase(); + input_form.value = filter; + var table = document.getElementById('searchable'); + var alt_style = 'norm'; + for(var i = 0; i < table.rows.length; i++){ + try{ + var row = table.rows[i]; + if(row.className == 'title') continue; + var found=0; + for(var j = 0; j < row.cells.length; j++){ + var cell = row.cells[j]; + if(cell.innerText.toLowerCase().indexOf(filter) != -1){ + found=1; + break; + } + } + if(found == 0) row.style.display='none'; + else{ + row.style.display='block'; + row.className = alt_style; + if(alt_style == 'alt') alt_style = 'norm'; + else alt_style = 'alt'; + } + }catch(err) { } + } } \ No newline at end of file diff --git a/html/templates/footer.html b/html/templates/footer.html index c26f94bdbf03..68ce1ab76678 100644 --- a/html/templates/footer.html +++ b/html/templates/footer.html @@ -1,13 +1,4 @@ -
    - -GoonStation 13 Development Team -
    - Coders: Stuntwaffle, Showtime, Pantaloons, Nannek, Keelin, Exadv1, hobnob, Justicefries, 0staf, sniperchance, AngriestIBM, BrianOBlivion
    - Spriters: Supernorn, Haruhi, Stuntwaffle, Pantaloons, Rho, SynthOrange, I Said No
    -
    -
    -

    Creative Commons License
    Except where otherwise noted, Goon Station 13 is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License.
    Rights are currently extended to SomethingAwful Goons only.

    -

    Some icons by Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 License.

    -
    - - +
    + + + diff --git a/html/templates/header.html b/html/templates/header.html index 09df40020d4b..6d078158aca2 100644 --- a/html/templates/header.html +++ b/html/templates/header.html @@ -1,53 +1,53 @@ - - - - Nebula13 Changelog - - - - - - - -
    - - - - -
    -
    Nebula13
    -
    A Space Station 13 Project
    - -

    - Code licensed under AGPLv3. Content licensed under CC BY-SA 3.0.

    -
    - -
    Nebula13 Credit List - - - - -
    - Contributor list: -Click Here-
    - Special thanks to: the developers of Baystation 12, ScavStation, /tg/station, /vg/station, GoonStation, the original Space Station 13, and BYOND.
    -

    Have a bug to report?
    Visit our Issue Tracker.
    -
    - - -
    + + + + Nebula13 Changelog + + + + + + + +" + . += "" + . += "" + . += "" + . += "" + . += "" + . += "" + . += "" + . += "" diff --git a/mods/misc/mundane.dm b/mods/content/mundane.dm similarity index 99% rename from mods/misc/mundane.dm rename to mods/content/mundane.dm index 89e7c53b3a73..c66ec33c12ed 100644 --- a/mods/misc/mundane.dm +++ b/mods/content/mundane.dm @@ -1,5 +1,6 @@ #ifndef MODPACK_MUNDANE #define MODPACK_MUNDANE +#endif // Modern/contemporary concepts. /decl/modpack/mundane @@ -14,4 +15,3 @@ "a snake","a plant monster","a field of flowers","a needle","a blade","an ocean" ) -#endif \ No newline at end of file diff --git a/mods/content/pheromones/_pheromones.dm b/mods/content/pheromones/_pheromones.dm new file mode 100644 index 000000000000..9a58ee040cf5 --- /dev/null +++ b/mods/content/pheromones/_pheromones.dm @@ -0,0 +1,6 @@ +#define BP_PHEROMONE_GLAND "pheromone gland" + +var/global/list/pheromone_markers = list() + +/decl/modpack/pheromones + name = "Pheromones Content" diff --git a/mods/content/pheromones/_pheromones.dme b/mods/content/pheromones/_pheromones.dme new file mode 100644 index 000000000000..fecc8b376dd6 --- /dev/null +++ b/mods/content/pheromones/_pheromones.dme @@ -0,0 +1,10 @@ +#ifndef MODPACK_PHEROMONES +#define MODPACK_PHEROMONES +// BEGIN_INCLUDE +#include "_pheromones.dm" +#include "pheromone_effect.dm" +#include "pheromone_emotes.dm" +#include "pheromone_implant.dm" +#include "pheromone_mob.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/pheromones/pheromone_effect.dm b/mods/content/pheromones/pheromone_effect.dm new file mode 100644 index 000000000000..5db435ee4fc0 --- /dev/null +++ b/mods/content/pheromones/pheromone_effect.dm @@ -0,0 +1,65 @@ +/datum/extension/scent/custom/pheromone/check_smeller(var/mob/living/smeller) + . = (..() && istype(smeller) && smeller.can_read_pheromones()) + +/obj/effect/decal/cleanable/pheromone + name = "pheromone trace" + invisibility = INVISIBILITY_MAXIMUM + alpha = 0 + scent_type = /datum/extension/scent/custom/pheromone + var/image/marker + +/obj/effect/decal/cleanable/pheromone/proc/fade() + alpha = max(alpha-5, 0) + if(alpha <= 0) + qdel(src) + else + addtimer(CALLBACK(src, PROC_REF(fade), 300 SECONDS)) + update_scent_marker() + +/obj/effect/decal/cleanable/pheromone/Initialize(ml, _age) + . = ..() + addtimer(CALLBACK(src, PROC_REF(fade), 300 SECONDS)) + marker = image(loc = src, icon = 'icons/effects/blood.dmi', icon_state = pick(list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7"))) + marker.alpha = 90 + marker.plane = ABOVE_LIGHTING_PLANE + marker.layer = ABOVE_LIGHTING_LAYER + +/obj/effect/decal/cleanable/pheromone/Destroy() + . = ..() + global.pheromone_markers -= marker + for(var/client/C) + C.images -= marker + +/obj/effect/decal/cleanable/pheromone/proc/update_scent_marker() + if(!marker) + return + for(var/client/C) + var/mob/living/human/H = C.mob + if(istype(H) && H.can_read_pheromones()) + C.images -= marker + var/datum/extension/scent/custom/pheromone/smell = get_extension(src, /datum/extension/scent) + if(!istype(smell)) + return + marker.alpha = alpha + if(color) + marker.color = color + marker.filters = filter(type="drop_shadow", color = color + "F0", size = 2, offset = 1, x = 0, y = 0) + global.pheromone_markers |= marker + for(var/client/C) + var/mob/living/human/H = C.mob + if(istype(H) && H.can_read_pheromones()) + C.images |= marker + +/obj/effect/decal/cleanable/pheromone/set_cleanable_scent() + . = ..() + update_scent_marker() + var/datum/extension/scent/custom/pheromone/smell = get_extension(src, /datum/extension/scent) + if(istype(smell)) + for(var/mob/living/smeller in all_hearers(smell.holder, smell.range)) + var/turf/T = get_turf(smeller.loc) + if(!T || !T.return_air()) + continue + if(!smell.check_smeller(smeller)) + continue + if(smell.scent in smeller.smell_cooldown) + to_chat(smeller, SPAN_NOTICE("The scent of [smell.scent] intensifies.")) diff --git a/mods/content/pheromones/pheromone_emotes.dm b/mods/content/pheromones/pheromone_emotes.dm new file mode 100644 index 000000000000..86d16a400034 --- /dev/null +++ b/mods/content/pheromones/pheromone_emotes.dm @@ -0,0 +1,98 @@ +/decl/emote/pheromone + abstract_type = /decl/emote/pheromone + var/smell_message + var/self_smell_descriptor + var/scent_color + +/decl/emote/pheromone/mob_can_use(mob/living/user, assume_available = FALSE) + return istype(user) && user.can_read_pheromones() && ..() + +/decl/emote/pheromone/fear + key = "scentfear" + smell_message = "FEAR" + self_smell_descriptor = "distressing" + scent_color = COLOR_RED + +/decl/emote/pheromone/pain + key = "scentpain" + smell_message = "PAIN" + self_smell_descriptor = "distressing" + scent_color = COLOR_RED + +/decl/emote/pheromone/calm + key = "scentcalm" + smell_message = "calm" + self_smell_descriptor = "soothing" + scent_color = COLOR_BLUE + +/decl/emote/pheromone/storm + key = "scentstorm" + smell_message = "an oncoming storm" + self_smell_descriptor = "distressing" + scent_color = COLOR_ORANGE + +/decl/emote/pheromone/flood + key = "scentflood" + smell_message = "flooding tunnels" + self_smell_descriptor = "frantic" + scent_color = COLOR_YELLOW + +/decl/emote/pheromone/newsisters + key = "scentsisters" + smell_message = "new sisters" + self_smell_descriptor = "cheerful" + scent_color = COLOR_GREEN_GRAY + +/decl/emote/pheromone/foodgood + key = "scentgoodfood" + smell_message = "lots of good food" + self_smell_descriptor = "enticing" + scent_color = COLOR_GREEN + +/decl/emote/pheromone/foodbad + key = "scentbadfood" + smell_message = "spoiled food" + self_smell_descriptor = "disgusting" + scent_color = COLOR_PURPLE + +/decl/emote/pheromone/happy + key = "scenthappy" + smell_message = "happiness" + self_smell_descriptor = "positive" + scent_color = COLOR_BABY_BLUE + +/decl/emote/pheromone/sad + key = "scentsad" + smell_message = "sadness" + self_smell_descriptor = "ennervating" + scent_color = COLOR_INDIGO + +/decl/emote/pheromone/do_emote(var/atom/user, var/extra_params) + if(!ismob(user)) + return + var/mob/M = user + if(M.incapacitated()) + return + var/turf/T = get_turf(M) + if(!T) + return + to_chat(user, SPAN_NOTICE("You emit the [self_smell_descriptor ? "[self_smell_descriptor] " : ""]scent of [smell_message].")) + for(var/mob/living/human/H in viewers(world.view, user)) + if(H != user && H.stat == CONSCIOUS && H.can_read_pheromones()) + to_chat(H, SPAN_NOTICE("\The [user] emits the [self_smell_descriptor ? "[self_smell_descriptor] " : ""]scent of [smell_message].")) + + var/obj/effect/decal/cleanable/pheromone/pheromone = (locate() in T) || new(T) + pheromone.color = scent_color || get_random_colour() + pheromone.alpha = min(pheromone.alpha+30, 120) + pheromone.cleanable_scent = smell_message + pheromone.desc = "It smells of [smell_message]." + pheromone.set_cleanable_scent() + +/decl/emote/pheromone/custom + key = "scentcustom" + +/decl/emote/pheromone/custom/do_emote(var/atom/user, var/extra_params) + var/new_smell = sanitize(extra_params || input("Please enter a short pheromone message.", "Pheromone") as text|null, max_length = MAX_LNAME_LEN) + if(new_smell) + smell_message = new_smell + . = ..() diff --git a/mods/content/pheromones/pheromone_implant.dm b/mods/content/pheromones/pheromone_implant.dm new file mode 100644 index 000000000000..a9e16ef2faf0 --- /dev/null +++ b/mods/content/pheromones/pheromone_implant.dm @@ -0,0 +1,8 @@ +/obj/item/implant/pheromone + name = "pheromone implant" + desc = "A civilian grade implant for communicating via pheromones." + origin_tech = "{'materials':1,'biotech':1}" + +/obj/item/implanter/pheromone + name = "implanter (P)" + imp = /obj/item/implant/pheromone \ No newline at end of file diff --git a/mods/content/pheromones/pheromone_mob.dm b/mods/content/pheromones/pheromone_mob.dm new file mode 100644 index 000000000000..ad1efceb03b8 --- /dev/null +++ b/mods/content/pheromones/pheromone_mob.dm @@ -0,0 +1,44 @@ + +/mob/living/Login() + . = ..() + update_pheromone_markers() + +/mob/living/proc/update_pheromone_markers() + if(client) + if(can_read_pheromones()) + client.images |= global.pheromone_markers + else + client.images -= global.pheromone_markers + +/mob/living/proc/can_read_pheromones() + var/obj/item/organ/internal/pheromone_gland/gland = GET_INTERNAL_ORGAN(src, BP_PHEROMONE_GLAND) + if(istype(gland) && !gland.is_broken()) + return TRUE + var/obj/item/implant/pheromone/imp = locate() in get_organ(BP_HEAD) + if(imp?.implanted && !imp.malfunction) + return TRUE + return FALSE + +/obj/item/organ/internal/pheromone_gland + name = "pheromone gland" + desc = "A miscellaneous lump of flesh full of chemicals." + icon_state = "stomach" + organ_tag = BP_PHEROMONE_GLAND + parent_organ = BP_CHEST + +/mob/living/get_default_emotes() + . = ..() + if(can_read_pheromones()) + var/static/list/pheromone_emotes = list( + /decl/emote/pheromone/fear, + /decl/emote/pheromone/calm, + /decl/emote/pheromone/storm, + /decl/emote/pheromone/flood, + /decl/emote/pheromone/newsisters, + /decl/emote/pheromone/foodgood, + /decl/emote/pheromone/foodbad, + /decl/emote/pheromone/happy, + /decl/emote/pheromone/sad, + /decl/emote/pheromone/custom + ) + LAZYDISTINCTADD(., pheromone_emotes) diff --git a/mods/content/plant_dissection/_plant_dissection.dm b/mods/content/plant_dissection/_plant_dissection.dm new file mode 100644 index 000000000000..a8229cd13147 --- /dev/null +++ b/mods/content/plant_dissection/_plant_dissection.dm @@ -0,0 +1,6 @@ +#define PLANT_SEG_PETAL "petal" +#define PLANT_SEG_STAMEN "stamen" +#define PLANT_SEG_STIGMA "stigma" + +/decl/modpack/plant_dissection + name = "Plant Dissection" diff --git a/mods/content/plant_dissection/_plant_dissection.dme b/mods/content/plant_dissection/_plant_dissection.dme new file mode 100644 index 000000000000..ebf842d7a97e --- /dev/null +++ b/mods/content/plant_dissection/_plant_dissection.dme @@ -0,0 +1,10 @@ +// BEGIN_INCLUDE +#ifndef MODPACK_PLANT_DISSECTION +#define MODPACK_PLANT_DISSECTION +#include "_plant_dissection.dm" +#include "grown.dm" +#include "grown_segment.dm" +#include "plant_segment.dm" +#include "seed_dissection.dm" +#endif +// END_INCLUDE \ No newline at end of file diff --git a/mods/content/plant_dissection/grown.dm b/mods/content/plant_dissection/grown.dm new file mode 100644 index 000000000000..30e778599fbc --- /dev/null +++ b/mods/content/plant_dissection/grown.dm @@ -0,0 +1,106 @@ +/obj/item/food/grown + var/examine_info + var/examine_info_skill = SKILL_BOTANY + var/examine_info_rank = SKILL_BASIC + var/can_dissect = TRUE + var/list/segments + +/obj/item/food/grown/set_seed() + ..() + if(!seed || !can_dissect) + return + var/list/all_segments = seed.get_physical_composition() + if(!length(all_segments)) + can_dissect = FALSE + return + for(var/datum/plant_segment/segment as anything in all_segments) + var/add_seg = 0 + if(islist(segment.dissect_amount)) + add_seg = rand(segment.dissect_amount[1], segment.dissect_amount[2]) + else if(isnum(segment.dissect_amount)) + add_seg = segment.dissect_amount + if(add_seg) + LAZYSET(segments, segment, add_seg) + +/obj/item/food/grown/initialize_reagents(populate) + var/segment_amount = 0 + for(var/datum/plant_segment/segment as anything in segments) + if(segment.contributes_to_reagents) + segment_amount += LAZYACCESS(segment.total_reagent_volume_by_state, (PLANT_STATE_FRESH)) + chem_volume = max(chem_volume, segment_amount) + return ..() + +/obj/item/food/grown/Destroy() + segments = null + return ..() + +/obj/item/food/grown/update_grown_icon() + . = ..() + if(can_dissect && length(segments)) + var/list/segment_count = list() + for(var/datum/plant_segment/segment as anything in segments) + if(!segment.grown_icon || !segment.grown_icon_state) + continue + for(var/i = 1 to segments[segment]) + add_overlay(image(segment.grown_icon, "[segment.grown_icon_state][++segment_count[segment.name]]")) + +/obj/item/food/grown/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1 && can_dissect && examine_info && (!examine_info_skill || !examine_info_rank || user.skill_check(examine_info_skill, examine_info_rank))) + . += examine_info + +/obj/item/food/grown/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + if(distance > 1 || !can_dissect) + return + + var/list/fruit_segment_strings = list() + for(var/datum/plant_segment/segment as anything in segments) + if(!segment.dissect_skill || !segment.dissect_skill_requirement || user.skill_check(segment.dissect_skill, segment.dissect_skill_requirement)) + var/decl/tool_archetype/tool = segment.dissect_tool && GET_DECL(segment.dissect_tool) + var/segment_string_index = tool?.name ? ADD_ARTICLE(tool.name) : "your hands" + LAZYINITLIST(fruit_segment_strings[segment_string_index]) + fruit_segment_strings[segment_string_index][segment.name] += LAZYACCESS(segments, segment) + + for(var/segment_ind in fruit_segment_strings) + var/list/segment_strings_count = list() + for(var/segment_string in fruit_segment_strings[segment_ind]) + segment_strings_count += "[fruit_segment_strings[segment_ind][segment_string]] [segment_string]\s" + if(length(segment_strings_count)) + LAZYADD(., SPAN_NOTICE("With [segment_ind], you could harvest [english_list(segment_strings_count)].")) + +/obj/item/food/grown/attackby(obj/item/W, mob/living/user) + if(can_dissect && !user?.check_intent(I_FLAG_HARM)) + for(var/datum/plant_segment/segment as anything in segments) + if(!segment.dissect_tool || !W.get_tool_quality(segment.dissect_tool)) + continue + segment.on_harvest(W, user, src) + return TRUE + return ..() + +/obj/item/food/grown/attack_self(mob/user) + if(can_dissect) + for(var/datum/plant_segment/segment as anything in segments) + if(segment.dissect_tool) + continue + if(!segment.dissect_skill || !segment.dissect_skill_requirement || user.skill_check(segment.dissect_skill, segment.dissect_skill_requirement)) + segment.on_harvest(null, user, src) + return TRUE + return ..() + +/obj/item/food/grown/proc/remove_segment(var/datum/plant_segment/segment) + + if(!can_dissect || !(segment in segments)) + return + + if(REAGENT_TOTAL_VOLUME(reagents) && segment.contributes_to_reagents) + for(var/rid in segment.reagents) + reagents.remove_reagent(rid, segment.reagents[rid]) + + segments[segment]-- + if(segments[segment] <= 0) + LAZYREMOVE(segments, segment) + update_icon() + + if(!length(segments) && !QDELETED(src)) + qdel(src) diff --git a/mods/content/plant_dissection/grown_segment.dm b/mods/content/plant_dissection/grown_segment.dm new file mode 100644 index 000000000000..70b4a9c094a1 --- /dev/null +++ b/mods/content/plant_dissection/grown_segment.dm @@ -0,0 +1,44 @@ +/datum/unit_test/icon_test/food_shall_have_icon_states/assemble_skipped_types() + ..() + skip_types |= typesof(/obj/item/food/grown/segment) + +/obj/item/food/grown/segment + name = "abstract segment" + is_spawnable_type = FALSE + seeds_extracted = TRUE // no seed extraction from petals or stamen + can_dissect = FALSE + var/datum/plant_segment/segment_data + +/obj/item/food/grown/segment/Initialize(mapload, material_key, skip_plate = FALSE, _seed, datum/plant_segment/_segment, obj/item/_source) + if(!_segment) + PRINT_STACK_TRACE("Dissected segment created with no segment datum.") + return INITIALIZE_HINT_QDEL + segment_data = _segment + plant_segment_type = segment_data.plant_segment_type + . = ..() + update_desc() + +/obj/item/food/grown/segment/Destroy() + . = ..() + segment_data = null + +/obj/item/food/grown/segment/update_base_name() + // to allow for 'dried nightweave stamen' etc + if(seed) + base_name = "[seed.product_name] [segment_data.name]" + else + base_name = segment_data.name + +/obj/item/food/grown/segment/update_desc() + base_desc = segment_data.desc // Don't bother doing the descriptor stuff from /grown + desc = base_desc + +/obj/item/food/grown/segment/update_grown_icon() + . = ..() + set_icon(segment_data.segment_icon) + icon_state = segment_data.segment_icon_state + +/obj/item/food/grown/segment/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1 && segment_data.examine_info && (!segment_data.examine_info_skill || !segment_data.examine_info_rank || user.skill_check(segment_data.examine_info_skill, segment_data.examine_info_rank))) + . += segment_data.examine_info diff --git a/mods/content/plant_dissection/icons/segment.dmi b/mods/content/plant_dissection/icons/segment.dmi new file mode 100644 index 000000000000..4a9a7d372822 Binary files /dev/null and b/mods/content/plant_dissection/icons/segment.dmi differ diff --git a/mods/content/plant_dissection/plant_segment.dm b/mods/content/plant_dissection/plant_segment.dm new file mode 100644 index 000000000000..26a08f838258 --- /dev/null +++ b/mods/content/plant_dissection/plant_segment.dm @@ -0,0 +1,88 @@ +/datum/plant_segment + abstract_type = /datum/plant_segment + + var/name + var/desc + + /// Icon to use for segment overlays on growns. + var/grown_icon + /// Base icon state to use for segment overlays on growns. Will be suffixed with a + /// number indicating which segment it is, if there are more than one. ie "[grown_icon_state]1" + var/grown_icon_state + + /// Icon to use for harvested segments. + var/segment_icon = 'mods/content/plant_dissection/icons/segment.dmi' + /// Icon state to use for harvested segments. + var/segment_icon_state + + /// List of reagents provided by this segment. + var/list/reagents + /// Summary var for above used in volume calc for growns. + var/list/total_reagent_volume_by_state + + /// Category type used for reagent and physical composition data on /datum/seed. + var/plant_segment_type = PLANT_SEG_BODY + + /// Whether or not this segment should attempt to overlay on grown products. + var/contributes_to_fruit_icon = FALSE + var/contributes_to_reagents = TRUE + + var/examine_info + var/examine_info_skill = SKILL_BOTANY + var/examine_info_rank = SKILL_BASIC + + var/dissect_amount = 1 // can be int or 2-entry list for rand bounds + var/dissect_tool = TOOL_SCALPEL + var/dissect_skill = SKILL_BOTANY + var/dissect_skill_requirement = SKILL_ADEPT + +/datum/plant_segment/New(var/_name, var/_desc, var/_amt, var/_reagents, var/_examine_info, var/_examine_skill_rank, var/_examine_skill) + if(_name) + name = _name + if(_desc) + desc = _desc + if(_reagents) + reagents = _reagents + if(_examine_info) + examine_info = _examine_info + if(_examine_skill_rank) + examine_info_rank = _examine_skill_rank + if(_examine_skill) + examine_info_skill = _examine_skill + dissect_amount = _amt + reagents = _reagents + total_reagent_volume_by_state = list() + if(length(reagents)) + for(var/state in reagents) + total_reagent_volume_by_state[state] = 0 + for(var/rid in reagents[state]) + total_reagent_volume_by_state[state] += reagents[rid] + ..() + +/datum/plant_segment/proc/can_harvest_with(var/obj/item/prop, var/mob/user) + return FALSE + +/datum/plant_segment/proc/on_harvest(var/obj/item/prop, var/mob/user, var/obj/item/food/grown/fruit) + var/obj/item/product = new /obj/item/food/grown/segment(get_turf(fruit), prop?.material?.type, TRUE, fruit.seed, src, fruit) + user.put_in_hands(product) + to_chat(user, SPAN_NOTICE("You remove \a [product] from \the [fruit][prop ? " with \the [prop]" : ""].")) + fruit.remove_segment(src) + return TRUE + +/datum/plant_segment/proc/apply_fruit_appearance(var/obj/item/food/grown/fruit, var/count = 0) + return + +/datum/plant_segment/petal + segment_icon_state = "petal" + dissect_tool = null + plant_segment_type = PLANT_SEG_PETAL + contributes_to_reagents = FALSE + +/datum/plant_segment/stamen + segment_icon_state = "stamen" + plant_segment_type = PLANT_SEG_STAMEN + +/datum/plant_segment/stigma + segment_icon_state = "stigma" + plant_segment_type = PLANT_SEG_STIGMA + contributes_to_reagents = FALSE diff --git a/mods/content/plant_dissection/seed_dissection.dm b/mods/content/plant_dissection/seed_dissection.dm new file mode 100644 index 000000000000..5efe761e8356 --- /dev/null +++ b/mods/content/plant_dissection/seed_dissection.dm @@ -0,0 +1,44 @@ +/datum/seed + VAR_PRIVATE/list/_physical_composition + +/datum/seed/proc/clear_chemical_composition_for_segment(_segment = PLANT_SEG_BODY) + if(isnull(_chemical_composition)) + return + for(var/state in _chemical_composition) + LAZYREMOVE(_chemical_composition[state], _segment) + +/datum/seed/proc/set_segment_data(datum/plant_segment/segment_data) + LAZYINITLIST(_physical_composition) + LAZYSET(_physical_composition, segment_data.plant_segment_type, segment_data) + clear_chemical_composition_for_segment(segment_data.plant_segment_type) + if(length(segment_data.reagents)) + for(var/state in segment_data.reagents) + for(var/reagent in segment_data.reagents[state]) + set_chemical_amount(reagent, segment_data.reagents[state][reagent], state, segment_data.plant_segment_type) + +/datum/seed/proc/get_segment_data(_segment = PLANT_SEG_BODY, _state = PLANT_STATE_FRESH) + var/list/comp = LAZYACCESS(_physical_composition, _state) + . = LAZYACCESS(comp, _segment) + if(!. && _state != PLANT_STATE_FRESH) + return get_segment_data(_segment, PLANT_STATE_FRESH) // Let physical data default to anything set regardless of state. + +/datum/seed/proc/get_physical_composition() + for(var/segment_type in _physical_composition) + LAZYADD(., _physical_composition[segment_type]) + +/datum/seed/flower/New() + ..() + // Adding this soley for the purposes of 'she loves me, she loves me not' + var/decl/pronouns/pronouns = get_pronouns_by_gender(pick(MALE, FEMALE, PLURAL)) + set_segment_data( + new /datum/plant_segment/petal( + "petal", + "[pronouns.He] love[pronouns.s] me, [pronouns.he] love[pronouns.s] me not...", + list(3,5), + list( + (PLANT_STATE_FRESH) = list( + /decl/material/liquid/nutriment = list(1) + ) + ) + ) + ) diff --git a/mods/content/psionics/_defines.dm b/mods/content/psionics/_defines.dm new file mode 100644 index 000000000000..77d1de1a6a73 --- /dev/null +++ b/mods/content/psionics/_defines.dm @@ -0,0 +1,23 @@ +#define PSI_IMPLANT_AUTOMATIC "Security Level Derived" +#define PSI_IMPLANT_SHOCK "Issue Neural Shock" +#define PSI_IMPLANT_WARN "Issue Reprimand" +#define PSI_IMPLANT_LOG "Log Incident" +#define PSI_IMPLANT_DISABLED "Disabled" + +#define PSI_COERCION "coercion" +#define PSI_PSYCHOKINESIS "psychokinesis" +#define PSI_REDACTION "redaction" +#define PSI_ENERGISTICS "energistics" + +#define PSI_RANK_BLUNT 0 +#define PSI_RANK_LATENT 1 +#define PSI_RANK_OPERANT 2 +#define PSI_RANK_MASTER 3 +#define PSI_RANK_GRANDMASTER 4 +#define PSI_RANK_PARAMOUNT 5 + +#define PSIONIC "psi" + +#define COLOR_NULLGLASS "#ff6088" + +#define SS_PRIORITY_PSYCHICS 45 // Psychic complexus processing priority diff --git a/mods/content/psionics/_psionics.dm b/mods/content/psionics/_psionics.dm new file mode 100644 index 000000000000..aa9e711f7ca7 --- /dev/null +++ b/mods/content/psionics/_psionics.dm @@ -0,0 +1,35 @@ +/decl/modpack/psionics + name = "Psionics Content" + dreams = list("the Foundation", "nullglass") + +/decl/modpack/psionics/get_player_panel_options(var/mob/M) + . = list("Psionics:
    ") + if(isliving(M)) + var/datum/ability_handler/psionics/psi = M.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + . += "Remove psionics.

    " + . += "Trigger latencies.
    " + . += "
    + + + + +
    +
    Nebula13
    +
    A Space Station 13 Project
    + +

    + Code licensed under AGPLv3. Content licensed under CC BY-SA 3.0.

    +
    + +
    Nebula13 Credit List + + + + +
    + Contributor list: -Click Here-
    + Special thanks to: the developers of Baystation 12, ScavStation, /tg/station, /vg/station, GoonStation, the original Space Station 13, and BYOND.
    +

    Have a bug to report?
    Visit our Issue Tracker.
    +
    + + +
    diff --git a/icons/480x480.dmi b/icons/480x480.dmi index 90ea9fbd55cb..0b6d072855ac 100644 Binary files a/icons/480x480.dmi and b/icons/480x480.dmi differ diff --git a/icons/atmos/heat.dmi b/icons/atmos/heat.dmi index 1014c2015b05..b5c996a40fc8 100644 Binary files a/icons/atmos/heat.dmi and b/icons/atmos/heat.dmi differ diff --git a/icons/atmos/junction.dmi b/icons/atmos/junction.dmi index 892f5823f2e5..fe837071dc58 100644 Binary files a/icons/atmos/junction.dmi and b/icons/atmos/junction.dmi differ diff --git a/icons/atmos/pipes.dmi b/icons/atmos/pipes.dmi index 0eb394842eb5..8b163f0c7455 100644 Binary files a/icons/atmos/pipes.dmi and b/icons/atmos/pipes.dmi differ diff --git a/icons/atmos/tank.dmi b/icons/atmos/tank.dmi index c36c231a14e6..4a10b295ee33 100644 Binary files a/icons/atmos/tank.dmi and b/icons/atmos/tank.dmi differ diff --git a/icons/atmos/vent_pump.dmi b/icons/atmos/vent_pump.dmi index ee89a02b4a76..3d9445bec1c3 100644 Binary files a/icons/atmos/vent_pump.dmi and b/icons/atmos/vent_pump.dmi differ diff --git a/icons/atmos/vent_scrubber.dmi b/icons/atmos/vent_scrubber.dmi index 55790e7ddf43..aef1cb1822a0 100644 Binary files a/icons/atmos/vent_scrubber.dmi and b/icons/atmos/vent_scrubber.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_cargo.dmi b/icons/clothing/accessories/armbands/armband_cargo.dmi new file mode 100644 index 000000000000..57b55a895112 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_cargo.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_engineering.dmi b/icons/clothing/accessories/armbands/armband_engineering.dmi new file mode 100644 index 000000000000..61823190da51 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_engineering.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_hydroponics.dmi b/icons/clothing/accessories/armbands/armband_hydroponics.dmi new file mode 100644 index 000000000000..966db94715fa Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_hydroponics.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_medical.dmi b/icons/clothing/accessories/armbands/armband_medical.dmi new file mode 100644 index 000000000000..6548a9268a45 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_medical.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_medical_blue.dmi b/icons/clothing/accessories/armbands/armband_medical_blue.dmi new file mode 100644 index 000000000000..5a7872065422 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_medical_blue.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_medical_green.dmi b/icons/clothing/accessories/armbands/armband_medical_green.dmi new file mode 100644 index 000000000000..0f08b91ededf Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_medical_green.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_science.dmi b/icons/clothing/accessories/armbands/armband_science.dmi new file mode 100644 index 000000000000..cfc986f95f47 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_science.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_security.dmi b/icons/clothing/accessories/armbands/armband_security.dmi new file mode 100644 index 000000000000..9de57a1ec7d5 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_security.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_security_white.dmi b/icons/clothing/accessories/armbands/armband_security_white.dmi new file mode 100644 index 000000000000..358988f14b9a Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_security_white.dmi differ diff --git a/icons/clothing/accessories/armbands/armband_sol.dmi b/icons/clothing/accessories/armbands/armband_sol.dmi new file mode 100644 index 000000000000..653a9af53370 Binary files /dev/null and b/icons/clothing/accessories/armbands/armband_sol.dmi differ diff --git a/icons/clothing/accessories/armor/armguards.dmi b/icons/clothing/accessories/armor/armguards.dmi new file mode 100644 index 000000000000..79dcafa0279d Binary files /dev/null and b/icons/clothing/accessories/armor/armguards.dmi differ diff --git a/icons/clothing/accessories/armor/armguards_ablative.dmi b/icons/clothing/accessories/armor/armguards_ablative.dmi new file mode 100644 index 000000000000..2a1b90ef908b Binary files /dev/null and b/icons/clothing/accessories/armor/armguards_ablative.dmi differ diff --git a/icons/clothing/accessories/armor/armguards_ballistic.dmi b/icons/clothing/accessories/armor/armguards_ballistic.dmi new file mode 100644 index 000000000000..d98f8721280a Binary files /dev/null and b/icons/clothing/accessories/armor/armguards_ballistic.dmi differ diff --git a/icons/clothing/accessories/armor/armguards_merc.dmi b/icons/clothing/accessories/armor/armguards_merc.dmi new file mode 100644 index 000000000000..ad8556fe9444 Binary files /dev/null and b/icons/clothing/accessories/armor/armguards_merc.dmi differ diff --git a/icons/clothing/accessories/armor/armguards_riot.dmi b/icons/clothing/accessories/armor/armguards_riot.dmi new file mode 100644 index 000000000000..774f7296f88e Binary files /dev/null and b/icons/clothing/accessories/armor/armguards_riot.dmi differ diff --git a/icons/clothing/accessories/armor/armor_light.dmi b/icons/clothing/accessories/armor/armor_light.dmi new file mode 100644 index 000000000000..5a081fda37a9 Binary files /dev/null and b/icons/clothing/accessories/armor/armor_light.dmi differ diff --git a/icons/clothing/accessories/armor/armor_medium.dmi b/icons/clothing/accessories/armor/armor_medium.dmi new file mode 100644 index 000000000000..9f6033bf1ca7 Binary files /dev/null and b/icons/clothing/accessories/armor/armor_medium.dmi differ diff --git a/icons/clothing/accessories/armor/armor_merc.dmi b/icons/clothing/accessories/armor/armor_merc.dmi new file mode 100644 index 000000000000..2412f7a497a1 Binary files /dev/null and b/icons/clothing/accessories/armor/armor_merc.dmi differ diff --git a/icons/clothing/accessories/armor/armor_tactical.dmi b/icons/clothing/accessories/armor/armor_tactical.dmi new file mode 100644 index 000000000000..487be4ae41dd Binary files /dev/null and b/icons/clothing/accessories/armor/armor_tactical.dmi differ diff --git a/icons/clothing/accessories/armor/helmcover.dmi b/icons/clothing/accessories/armor/helmcover.dmi new file mode 100644 index 000000000000..baf5d005f1d6 Binary files /dev/null and b/icons/clothing/accessories/armor/helmcover.dmi differ diff --git a/icons/clothing/accessories/armor/kneepads.dmi b/icons/clothing/accessories/armor/kneepads.dmi new file mode 100644 index 000000000000..9801ae014260 Binary files /dev/null and b/icons/clothing/accessories/armor/kneepads.dmi differ diff --git a/icons/clothing/accessories/armor/legguards.dmi b/icons/clothing/accessories/armor/legguards.dmi new file mode 100644 index 000000000000..f53e3615a288 Binary files /dev/null and b/icons/clothing/accessories/armor/legguards.dmi differ diff --git a/icons/clothing/accessories/armor/legguards_ablative.dmi b/icons/clothing/accessories/armor/legguards_ablative.dmi new file mode 100644 index 000000000000..4b90529b461c Binary files /dev/null and b/icons/clothing/accessories/armor/legguards_ablative.dmi differ diff --git a/icons/clothing/accessories/armor/legguards_ballistic.dmi b/icons/clothing/accessories/armor/legguards_ballistic.dmi new file mode 100644 index 000000000000..48a336242d5d Binary files /dev/null and b/icons/clothing/accessories/armor/legguards_ballistic.dmi differ diff --git a/icons/clothing/accessories/armor/legguards_merc.dmi b/icons/clothing/accessories/armor/legguards_merc.dmi new file mode 100644 index 000000000000..2ddc2559a64b Binary files /dev/null and b/icons/clothing/accessories/armor/legguards_merc.dmi differ diff --git a/icons/clothing/accessories/armor/legguards_riot.dmi b/icons/clothing/accessories/armor/legguards_riot.dmi new file mode 100644 index 000000000000..f45526050143 Binary files /dev/null and b/icons/clothing/accessories/armor/legguards_riot.dmi differ diff --git a/icons/clothing/accessories/badges/badge.dmi b/icons/clothing/accessories/badges/badge.dmi new file mode 100644 index 000000000000..54d3d8eb83d7 Binary files /dev/null and b/icons/clothing/accessories/badges/badge.dmi differ diff --git a/icons/clothing/accessories/badges/badge_round.dmi b/icons/clothing/accessories/badges/badge_round.dmi new file mode 100644 index 000000000000..a699814e7682 Binary files /dev/null and b/icons/clothing/accessories/badges/badge_round.dmi differ diff --git a/icons/clothing/accessories/badges/badge_skrell.dmi b/icons/clothing/accessories/badges/badge_skrell.dmi new file mode 100644 index 000000000000..e092211dfded Binary files /dev/null and b/icons/clothing/accessories/badges/badge_skrell.dmi differ diff --git a/icons/clothing/accessories/badges/badge_tracker.dmi b/icons/clothing/accessories/badges/badge_tracker.dmi new file mode 100644 index 000000000000..c11f37f8c50e Binary files /dev/null and b/icons/clothing/accessories/badges/badge_tracker.dmi differ diff --git a/icons/clothing/accessories/badges/detectivebadge.dmi b/icons/clothing/accessories/badges/detectivebadge.dmi new file mode 100644 index 000000000000..fa868ebe730f Binary files /dev/null and b/icons/clothing/accessories/badges/detectivebadge.dmi differ diff --git a/icons/clothing/accessories/badges/diabadge.dmi b/icons/clothing/accessories/badges/diabadge.dmi new file mode 100644 index 000000000000..9c2517b66a77 Binary files /dev/null and b/icons/clothing/accessories/badges/diabadge.dmi differ diff --git a/icons/clothing/accessories/badges/holobadge.dmi b/icons/clothing/accessories/badges/holobadge.dmi new file mode 100644 index 000000000000..2892a53d402d Binary files /dev/null and b/icons/clothing/accessories/badges/holobadge.dmi differ diff --git a/icons/clothing/accessories/badges/holobadge_cord.dmi b/icons/clothing/accessories/badges/holobadge_cord.dmi new file mode 100644 index 000000000000..ce8833d66772 Binary files /dev/null and b/icons/clothing/accessories/badges/holobadge_cord.dmi differ diff --git a/icons/clothing/accessories/badges/intelbadge.dmi b/icons/clothing/accessories/badges/intelbadge.dmi new file mode 100644 index 000000000000..738ca3dcc0b7 Binary files /dev/null and b/icons/clothing/accessories/badges/intelbadge.dmi differ diff --git a/icons/clothing/accessories/badges/pressbadge.dmi b/icons/clothing/accessories/badges/pressbadge.dmi new file mode 100644 index 000000000000..cfff6874f945 Binary files /dev/null and b/icons/clothing/accessories/badges/pressbadge.dmi differ diff --git a/icons/clothing/accessories/buddytag.dmi b/icons/clothing/accessories/buddytag.dmi new file mode 100644 index 000000000000..959cf49366c7 Binary files /dev/null and b/icons/clothing/accessories/buddytag.dmi differ diff --git a/icons/clothing/accessories/clothing/cape_commander.dmi b/icons/clothing/accessories/clothing/cape_commander.dmi new file mode 100644 index 000000000000..26eed5baed06 Binary files /dev/null and b/icons/clothing/accessories/clothing/cape_commander.dmi differ diff --git a/icons/clothing/accessories/clothing/cape_grunt.dmi b/icons/clothing/accessories/clothing/cape_grunt.dmi new file mode 100644 index 000000000000..19d62f7fb839 Binary files /dev/null and b/icons/clothing/accessories/clothing/cape_grunt.dmi differ diff --git a/icons/clothing/accessories/clothing/cape_leader.dmi b/icons/clothing/accessories/clothing/cape_leader.dmi new file mode 100644 index 000000000000..c051e9bcd67e Binary files /dev/null and b/icons/clothing/accessories/clothing/cape_leader.dmi differ diff --git a/icons/clothing/accessories/clothing/cape_officer.dmi b/icons/clothing/accessories/clothing/cape_officer.dmi new file mode 100644 index 000000000000..ab63ccf0d4ad Binary files /dev/null and b/icons/clothing/accessories/clothing/cape_officer.dmi differ diff --git a/icons/clothing/accessories/clothing/harness_unathi.dmi b/icons/clothing/accessories/clothing/harness_unathi.dmi new file mode 100644 index 000000000000..5c0f416f4f34 Binary files /dev/null and b/icons/clothing/accessories/clothing/harness_unathi.dmi differ diff --git a/icons/clothing/accessories/clothing/scarf.dmi b/icons/clothing/accessories/clothing/scarf.dmi new file mode 100644 index 000000000000..3ef31062ff12 Binary files /dev/null and b/icons/clothing/accessories/clothing/scarf.dmi differ diff --git a/icons/clothing/accessories/clothing/scarf_christmas.dmi b/icons/clothing/accessories/clothing/scarf_christmas.dmi new file mode 100644 index 000000000000..1044d76b4583 Binary files /dev/null and b/icons/clothing/accessories/clothing/scarf_christmas.dmi differ diff --git a/icons/clothing/accessories/clothing/tangzuhang.dmi b/icons/clothing/accessories/clothing/tangzuhang.dmi new file mode 100644 index 000000000000..722368a55968 Binary files /dev/null and b/icons/clothing/accessories/clothing/tangzuhang.dmi differ diff --git a/icons/clothing/accessories/clothing/vest.dmi b/icons/clothing/accessories/clothing/vest.dmi new file mode 100644 index 000000000000..6844740a141b Binary files /dev/null and b/icons/clothing/accessories/clothing/vest.dmi differ diff --git a/icons/clothing/accessories/clothing/zhongshan.dmi b/icons/clothing/accessories/clothing/zhongshan.dmi new file mode 100644 index 000000000000..7fdac80e93fa Binary files /dev/null and b/icons/clothing/accessories/clothing/zhongshan.dmi differ diff --git a/icons/clothing/accessories/holsters/holster.dmi b/icons/clothing/accessories/holsters/holster.dmi new file mode 100644 index 000000000000..5bccd6ceafba Binary files /dev/null and b/icons/clothing/accessories/holsters/holster.dmi differ diff --git a/icons/clothing/accessories/holsters/holster_hip.dmi b/icons/clothing/accessories/holsters/holster_hip.dmi new file mode 100644 index 000000000000..9c9af724ea19 Binary files /dev/null and b/icons/clothing/accessories/holsters/holster_hip.dmi differ diff --git a/icons/clothing/accessories/holsters/holster_low.dmi b/icons/clothing/accessories/holsters/holster_low.dmi new file mode 100644 index 000000000000..ec7baa5d9d46 Binary files /dev/null and b/icons/clothing/accessories/holsters/holster_low.dmi differ diff --git a/icons/clothing/accessories/holsters/holster_machete.dmi b/icons/clothing/accessories/holsters/holster_machete.dmi new file mode 100644 index 000000000000..956402158756 Binary files /dev/null and b/icons/clothing/accessories/holsters/holster_machete.dmi differ diff --git a/icons/clothing/accessories/holsters/holster_thigh.dmi b/icons/clothing/accessories/holsters/holster_thigh.dmi new file mode 100644 index 000000000000..daef23bac4ec Binary files /dev/null and b/icons/clothing/accessories/holsters/holster_thigh.dmi differ diff --git a/icons/clothing/accessories/holsters/sheath_leather.dmi b/icons/clothing/accessories/holsters/sheath_leather.dmi new file mode 100644 index 000000000000..ea406d89fa67 Binary files /dev/null and b/icons/clothing/accessories/holsters/sheath_leather.dmi differ diff --git a/icons/clothing/accessories/holsters/sheath_polymer.dmi b/icons/clothing/accessories/holsters/sheath_polymer.dmi new file mode 100644 index 000000000000..711f402e5c25 Binary files /dev/null and b/icons/clothing/accessories/holsters/sheath_polymer.dmi differ diff --git a/icons/clothing/accessories/jewelry/bracelet.dmi b/icons/clothing/accessories/jewelry/bracelet.dmi new file mode 100644 index 000000000000..4db6b68b122a Binary files /dev/null and b/icons/clothing/accessories/jewelry/bracelet.dmi differ diff --git a/icons/clothing/accessories/jewelry/dogtags.dmi b/icons/clothing/accessories/jewelry/dogtags.dmi new file mode 100644 index 000000000000..81118e77d9da Binary files /dev/null and b/icons/clothing/accessories/jewelry/dogtags.dmi differ diff --git a/icons/clothing/accessories/jewelry/necklace.dmi b/icons/clothing/accessories/jewelry/necklace.dmi new file mode 100644 index 000000000000..2f5ca2d3cfb1 Binary files /dev/null and b/icons/clothing/accessories/jewelry/necklace.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/cross.dmi b/icons/clothing/accessories/jewelry/pendants/cross.dmi new file mode 100644 index 000000000000..ca9d50a60f0b Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/cross.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/crystal.dmi b/icons/clothing/accessories/jewelry/pendants/crystal.dmi new file mode 100644 index 000000000000..a54525da6ab1 Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/crystal.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/diamond.dmi b/icons/clothing/accessories/jewelry/pendants/diamond.dmi new file mode 100644 index 000000000000..44e931a658d4 Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/diamond.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/frill.dmi b/icons/clothing/accessories/jewelry/pendants/frill.dmi new file mode 100644 index 000000000000..97891de4bc3b Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/frill.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/locket.dmi b/icons/clothing/accessories/jewelry/pendants/locket.dmi new file mode 100644 index 000000000000..e8f1bbee40b2 Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/locket.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/ornate.dmi b/icons/clothing/accessories/jewelry/pendants/ornate.dmi new file mode 100644 index 000000000000..9e6901f4e298 Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/ornate.dmi differ diff --git a/icons/clothing/accessories/jewelry/pendants/square.dmi b/icons/clothing/accessories/jewelry/pendants/square.dmi new file mode 100644 index 000000000000..5c9040c7baa8 Binary files /dev/null and b/icons/clothing/accessories/jewelry/pendants/square.dmi differ diff --git a/icons/clothing/accessories/jewelry/prayer_beads.dmi b/icons/clothing/accessories/jewelry/prayer_beads.dmi new file mode 100644 index 000000000000..e36f6d8ac70f Binary files /dev/null and b/icons/clothing/accessories/jewelry/prayer_beads.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_baha.dmi b/icons/clothing/accessories/jewelry/religious/icon_baha.dmi new file mode 100644 index 000000000000..a53ec12aa8a2 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_baha.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_buddhism.dmi b/icons/clothing/accessories/jewelry/religious/icon_buddhism.dmi new file mode 100644 index 000000000000..52fcc0330e1d Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_buddhism.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_christianity.dmi b/icons/clothing/accessories/jewelry/religious/icon_christianity.dmi new file mode 100644 index 000000000000..6cc25a68cab9 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_christianity.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_hinduism.dmi b/icons/clothing/accessories/jewelry/religious/icon_hinduism.dmi new file mode 100644 index 000000000000..928bd2bcb9fb Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_hinduism.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_islam.dmi b/icons/clothing/accessories/jewelry/religious/icon_islam.dmi new file mode 100644 index 000000000000..3637c1bcf269 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_islam.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_jain.dmi b/icons/clothing/accessories/jewelry/religious/icon_jain.dmi new file mode 100644 index 000000000000..bb3c65f3b0c9 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_jain.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_judaism.dmi b/icons/clothing/accessories/jewelry/religious/icon_judaism.dmi new file mode 100644 index 000000000000..a05fedc202e6 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_judaism.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_sikh.dmi b/icons/clothing/accessories/jewelry/religious/icon_sikh.dmi new file mode 100644 index 000000000000..91ad604ffda8 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_sikh.dmi differ diff --git a/icons/clothing/accessories/jewelry/religious/icon_taoist.dmi b/icons/clothing/accessories/jewelry/religious/icon_taoist.dmi new file mode 100644 index 000000000000..47c3a8aaa1a3 Binary files /dev/null and b/icons/clothing/accessories/jewelry/religious/icon_taoist.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_band.dmi b/icons/clothing/accessories/jewelry/rings/ring_band.dmi new file mode 100644 index 000000000000..b8f40338dccc Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_band.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_band_split.dmi b/icons/clothing/accessories/jewelry/rings/ring_band_split.dmi new file mode 100644 index 000000000000..fb29ccae72af Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_band_split.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_band_thick.dmi b/icons/clothing/accessories/jewelry/rings/ring_band_thick.dmi new file mode 100644 index 000000000000..93a83527a244 Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_band_thick.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_band_thin.dmi b/icons/clothing/accessories/jewelry/rings/ring_band_thin.dmi new file mode 100644 index 000000000000..83c9b2ced56f Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_band_thin.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_seal.dmi b/icons/clothing/accessories/jewelry/rings/ring_seal.dmi new file mode 100644 index 000000000000..620206a28cb7 Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_seal.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_seal_masonic.dmi b/icons/clothing/accessories/jewelry/rings/ring_seal_masonic.dmi new file mode 100644 index 000000000000..c2efcfd5c186 Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_seal_masonic.dmi differ diff --git a/icons/clothing/accessories/jewelry/rings/ring_seal_signet.dmi b/icons/clothing/accessories/jewelry/rings/ring_seal_signet.dmi new file mode 100644 index 000000000000..e6145d53c509 Binary files /dev/null and b/icons/clothing/accessories/jewelry/rings/ring_seal_signet.dmi differ diff --git a/icons/clothing/accessories/legbrace.dmi b/icons/clothing/accessories/legbrace.dmi new file mode 100644 index 000000000000..6d6602b4bf71 Binary files /dev/null and b/icons/clothing/accessories/legbrace.dmi differ diff --git a/icons/clothing/accessories/medals/medal_bronze.dmi b/icons/clothing/accessories/medals/medal_bronze.dmi new file mode 100644 index 000000000000..6935734affe4 Binary files /dev/null and b/icons/clothing/accessories/medals/medal_bronze.dmi differ diff --git a/icons/clothing/accessories/medals/medal_gold.dmi b/icons/clothing/accessories/medals/medal_gold.dmi new file mode 100644 index 000000000000..1026935fdb21 Binary files /dev/null and b/icons/clothing/accessories/medals/medal_gold.dmi differ diff --git a/icons/clothing/accessories/medals/medal_iron.dmi b/icons/clothing/accessories/medals/medal_iron.dmi new file mode 100644 index 000000000000..368bbc430f13 Binary files /dev/null and b/icons/clothing/accessories/medals/medal_iron.dmi differ diff --git a/icons/clothing/accessories/medals/medal_silver.dmi b/icons/clothing/accessories/medals/medal_silver.dmi new file mode 100644 index 000000000000..b8158eb3552a Binary files /dev/null and b/icons/clothing/accessories/medals/medal_silver.dmi differ diff --git a/icons/clothing/accessories/neckbrace.dmi b/icons/clothing/accessories/neckbrace.dmi new file mode 100644 index 000000000000..561b6e54d954 Binary files /dev/null and b/icons/clothing/accessories/neckbrace.dmi differ diff --git a/icons/clothing/accessories/permits.dmi b/icons/clothing/accessories/permits.dmi new file mode 100644 index 000000000000..25ee8e450845 Binary files /dev/null and b/icons/clothing/accessories/permits.dmi differ diff --git a/icons/clothing/accessories/pouches/lpouches.dmi b/icons/clothing/accessories/pouches/lpouches.dmi new file mode 100644 index 000000000000..bbafcc4f1f28 Binary files /dev/null and b/icons/clothing/accessories/pouches/lpouches.dmi differ diff --git a/icons/clothing/accessories/pouches/pouches.dmi b/icons/clothing/accessories/pouches/pouches.dmi new file mode 100644 index 000000000000..af1973cebe8a Binary files /dev/null and b/icons/clothing/accessories/pouches/pouches.dmi differ diff --git a/icons/clothing/accessories/pouches/thigh_black.dmi b/icons/clothing/accessories/pouches/thigh_black.dmi new file mode 100644 index 000000000000..e17ce8047b81 Binary files /dev/null and b/icons/clothing/accessories/pouches/thigh_black.dmi differ diff --git a/icons/clothing/accessories/pouches/thigh_brown.dmi b/icons/clothing/accessories/pouches/thigh_brown.dmi new file mode 100644 index 000000000000..04dfe458b378 Binary files /dev/null and b/icons/clothing/accessories/pouches/thigh_brown.dmi differ diff --git a/icons/clothing/accessories/pouches/thigh_white.dmi b/icons/clothing/accessories/pouches/thigh_white.dmi new file mode 100644 index 000000000000..005c54a21a75 Binary files /dev/null and b/icons/clothing/accessories/pouches/thigh_white.dmi differ diff --git a/icons/clothing/accessories/stethoscope.dmi b/icons/clothing/accessories/stethoscope.dmi new file mode 100644 index 000000000000..6ae4dbf46391 Binary files /dev/null and b/icons/clothing/accessories/stethoscope.dmi differ diff --git a/icons/clothing/accessories/storage/vest.dmi b/icons/clothing/accessories/storage/vest.dmi new file mode 100644 index 000000000000..810cfae1f400 Binary files /dev/null and b/icons/clothing/accessories/storage/vest.dmi differ diff --git a/icons/clothing/accessories/storage/vest_black.dmi b/icons/clothing/accessories/storage/vest_black.dmi new file mode 100644 index 000000000000..afc3fd43f389 Binary files /dev/null and b/icons/clothing/accessories/storage/vest_black.dmi differ diff --git a/icons/clothing/accessories/storage/vest_brown.dmi b/icons/clothing/accessories/storage/vest_brown.dmi new file mode 100644 index 000000000000..f265fc41ec19 Binary files /dev/null and b/icons/clothing/accessories/storage/vest_brown.dmi differ diff --git a/icons/clothing/accessories/storage/webbing.dmi b/icons/clothing/accessories/storage/webbing.dmi new file mode 100644 index 000000000000..f51f21cff46a Binary files /dev/null and b/icons/clothing/accessories/storage/webbing.dmi differ diff --git a/icons/clothing/accessories/storage/webbing_large.dmi b/icons/clothing/accessories/storage/webbing_large.dmi new file mode 100644 index 000000000000..a0f4f0627260 Binary files /dev/null and b/icons/clothing/accessories/storage/webbing_large.dmi differ diff --git a/icons/clothing/accessories/tags/tag_abneg.dmi b/icons/clothing/accessories/tags/tag_abneg.dmi new file mode 100644 index 000000000000..306082bde567 Binary files /dev/null and b/icons/clothing/accessories/tags/tag_abneg.dmi differ diff --git a/icons/clothing/accessories/tags/tag_abpos.dmi b/icons/clothing/accessories/tags/tag_abpos.dmi new file mode 100644 index 000000000000..a16e4e3c3460 Binary files /dev/null and b/icons/clothing/accessories/tags/tag_abpos.dmi differ diff --git a/icons/clothing/accessories/tags/tag_aneg.dmi b/icons/clothing/accessories/tags/tag_aneg.dmi new file mode 100644 index 000000000000..c10e03d9fd48 Binary files /dev/null and b/icons/clothing/accessories/tags/tag_aneg.dmi differ diff --git a/icons/clothing/accessories/tags/tag_apos.dmi b/icons/clothing/accessories/tags/tag_apos.dmi new file mode 100644 index 000000000000..9167d531030d Binary files /dev/null and b/icons/clothing/accessories/tags/tag_apos.dmi differ diff --git a/icons/clothing/accessories/tags/tag_bneg.dmi b/icons/clothing/accessories/tags/tag_bneg.dmi new file mode 100644 index 000000000000..92368240d80d Binary files /dev/null and b/icons/clothing/accessories/tags/tag_bneg.dmi differ diff --git a/icons/clothing/accessories/tags/tag_bpos.dmi b/icons/clothing/accessories/tags/tag_bpos.dmi new file mode 100644 index 000000000000..a4c7ba9f7bec Binary files /dev/null and b/icons/clothing/accessories/tags/tag_bpos.dmi differ diff --git a/icons/clothing/accessories/tags/tag_large.dmi b/icons/clothing/accessories/tags/tag_large.dmi new file mode 100644 index 000000000000..18b527f39fd8 Binary files /dev/null and b/icons/clothing/accessories/tags/tag_large.dmi differ diff --git a/icons/clothing/accessories/tags/tag_oneg.dmi b/icons/clothing/accessories/tags/tag_oneg.dmi new file mode 100644 index 000000000000..45269307da38 Binary files /dev/null and b/icons/clothing/accessories/tags/tag_oneg.dmi differ diff --git a/icons/clothing/accessories/tags/tag_opos.dmi b/icons/clothing/accessories/tags/tag_opos.dmi new file mode 100644 index 000000000000..390ca61529d6 Binary files /dev/null and b/icons/clothing/accessories/tags/tag_opos.dmi differ diff --git a/icons/clothing/accessories/tags/tag_small.dmi b/icons/clothing/accessories/tags/tag_small.dmi new file mode 100644 index 000000000000..a23ff0fb91ed Binary files /dev/null and b/icons/clothing/accessories/tags/tag_small.dmi differ diff --git a/icons/clothing/accessories/ties/bowtie.dmi b/icons/clothing/accessories/ties/bowtie.dmi new file mode 100644 index 000000000000..125667f49fa5 Binary files /dev/null and b/icons/clothing/accessories/ties/bowtie.dmi differ diff --git a/icons/clothing/accessories/ties/bowtie_ugly.dmi b/icons/clothing/accessories/ties/bowtie_ugly.dmi new file mode 100644 index 000000000000..2dbc20772fb3 Binary files /dev/null and b/icons/clothing/accessories/ties/bowtie_ugly.dmi differ diff --git a/icons/clothing/accessories/ties/tie.dmi b/icons/clothing/accessories/ties/tie.dmi new file mode 100644 index 000000000000..9d1f6fd0e5c6 Binary files /dev/null and b/icons/clothing/accessories/ties/tie.dmi differ diff --git a/icons/clothing/accessories/ties/tie_clip.dmi b/icons/clothing/accessories/ties/tie_clip.dmi new file mode 100644 index 000000000000..25260756eace Binary files /dev/null and b/icons/clothing/accessories/ties/tie_clip.dmi differ diff --git a/icons/clothing/accessories/ties/tie_horrible.dmi b/icons/clothing/accessories/ties/tie_horrible.dmi new file mode 100644 index 000000000000..c6f135c28e4c Binary files /dev/null and b/icons/clothing/accessories/ties/tie_horrible.dmi differ diff --git a/icons/clothing/accessories/ties/tie_long.dmi b/icons/clothing/accessories/ties/tie_long.dmi new file mode 100644 index 000000000000..cc3c3b21faf0 Binary files /dev/null and b/icons/clothing/accessories/ties/tie_long.dmi differ diff --git a/icons/clothing/accessories/venter.dmi b/icons/clothing/accessories/venter.dmi new file mode 100644 index 000000000000..d0537a0ed766 Binary files /dev/null and b/icons/clothing/accessories/venter.dmi differ diff --git a/icons/clothing/accessories/vitals_sensor.dmi b/icons/clothing/accessories/vitals_sensor.dmi new file mode 100644 index 000000000000..174135998978 Binary files /dev/null and b/icons/clothing/accessories/vitals_sensor.dmi differ diff --git a/icons/clothing/belt/camcorder.dmi b/icons/clothing/belt/camcorder.dmi new file mode 100644 index 000000000000..2f54722baff9 Binary files /dev/null and b/icons/clothing/belt/camcorder.dmi differ diff --git a/icons/clothing/belt/champion.dmi b/icons/clothing/belt/champion.dmi new file mode 100644 index 000000000000..652626a1bc9c Binary files /dev/null and b/icons/clothing/belt/champion.dmi differ diff --git a/icons/clothing/belt/command.dmi b/icons/clothing/belt/command.dmi new file mode 100644 index 000000000000..9237a4c759aa Binary files /dev/null and b/icons/clothing/belt/command.dmi differ diff --git a/icons/clothing/belt/emt_belt.dmi b/icons/clothing/belt/emt_belt.dmi new file mode 100644 index 000000000000..29f1339c7430 Binary files /dev/null and b/icons/clothing/belt/emt_belt.dmi differ diff --git a/icons/clothing/belt/fannypack.dmi b/icons/clothing/belt/fannypack.dmi new file mode 100644 index 000000000000..8bad6f78fd16 Binary files /dev/null and b/icons/clothing/belt/fannypack.dmi differ diff --git a/icons/clothing/belt/fannypack_big.dmi b/icons/clothing/belt/fannypack_big.dmi new file mode 100644 index 000000000000..cfbe273ff586 Binary files /dev/null and b/icons/clothing/belt/fannypack_big.dmi differ diff --git a/icons/clothing/belt/firefighter.dmi b/icons/clothing/belt/firefighter.dmi new file mode 100644 index 000000000000..b323a42f8ca8 Binary files /dev/null and b/icons/clothing/belt/firefighter.dmi differ diff --git a/icons/clothing/belt/forensic.dmi b/icons/clothing/belt/forensic.dmi new file mode 100644 index 000000000000..6b43bcda46ac Binary files /dev/null and b/icons/clothing/belt/forensic.dmi differ diff --git a/icons/clothing/belt/gearbelt.dmi b/icons/clothing/belt/gearbelt.dmi new file mode 100644 index 000000000000..8249db811700 Binary files /dev/null and b/icons/clothing/belt/gearbelt.dmi differ diff --git a/icons/clothing/belt/holster.dmi b/icons/clothing/belt/holster.dmi new file mode 100644 index 000000000000..11fa68c816f3 Binary files /dev/null and b/icons/clothing/belt/holster.dmi differ diff --git a/icons/clothing/belt/inflatable.dmi b/icons/clothing/belt/inflatable.dmi new file mode 100644 index 000000000000..04903fb95081 Binary files /dev/null and b/icons/clothing/belt/inflatable.dmi differ diff --git a/icons/clothing/belt/janitor.dmi b/icons/clothing/belt/janitor.dmi new file mode 100644 index 000000000000..d05062025e99 Binary files /dev/null and b/icons/clothing/belt/janitor.dmi differ diff --git a/icons/clothing/belt/machete.dmi b/icons/clothing/belt/machete.dmi new file mode 100644 index 000000000000..9be775116092 Binary files /dev/null and b/icons/clothing/belt/machete.dmi differ diff --git a/icons/clothing/belt/medical.dmi b/icons/clothing/belt/medical.dmi new file mode 100644 index 000000000000..0dcabb39e92b Binary files /dev/null and b/icons/clothing/belt/medical.dmi differ diff --git a/icons/clothing/belt/security.dmi b/icons/clothing/belt/security.dmi new file mode 100644 index 000000000000..78eed17f821a Binary files /dev/null and b/icons/clothing/belt/security.dmi differ diff --git a/icons/clothing/belt/security_holster.dmi b/icons/clothing/belt/security_holster.dmi new file mode 100644 index 000000000000..355a305f3772 Binary files /dev/null and b/icons/clothing/belt/security_holster.dmi differ diff --git a/icons/clothing/belt/soulstones.dmi b/icons/clothing/belt/soulstones.dmi new file mode 100644 index 000000000000..451b2bd7ab67 Binary files /dev/null and b/icons/clothing/belt/soulstones.dmi differ diff --git a/icons/clothing/belt/suspenders.dmi b/icons/clothing/belt/suspenders.dmi new file mode 100644 index 000000000000..5a56ba378b51 Binary files /dev/null and b/icons/clothing/belt/suspenders.dmi differ diff --git a/icons/clothing/belt/suspenders_red.dmi b/icons/clothing/belt/suspenders_red.dmi new file mode 100644 index 000000000000..56d73a0a27a1 Binary files /dev/null and b/icons/clothing/belt/suspenders_red.dmi differ diff --git a/icons/clothing/belt/swatbelt.dmi b/icons/clothing/belt/swatbelt.dmi new file mode 100644 index 000000000000..4df941bb031e Binary files /dev/null and b/icons/clothing/belt/swatbelt.dmi differ diff --git a/icons/clothing/belt/utility.dmi b/icons/clothing/belt/utility.dmi new file mode 100644 index 000000000000..554ef0b1c6f5 Binary files /dev/null and b/icons/clothing/belt/utility.dmi differ diff --git a/icons/clothing/costumes/gladiator.dmi b/icons/clothing/costumes/gladiator.dmi new file mode 100644 index 000000000000..1c8219886981 Binary files /dev/null and b/icons/clothing/costumes/gladiator.dmi differ diff --git a/icons/clothing/costumes/hides_hunter.dmi b/icons/clothing/costumes/hides_hunter.dmi new file mode 100644 index 000000000000..fc0dbe902b19 Binary files /dev/null and b/icons/clothing/costumes/hides_hunter.dmi differ diff --git a/icons/clothing/costumes/hides_huntress.dmi b/icons/clothing/costumes/hides_huntress.dmi new file mode 100644 index 000000000000..dfd855c05f9a Binary files /dev/null and b/icons/clothing/costumes/hides_huntress.dmi differ diff --git a/icons/clothing/costumes/kilt.dmi b/icons/clothing/costumes/kilt.dmi new file mode 100644 index 000000000000..4dc26c136fce Binary files /dev/null and b/icons/clothing/costumes/kilt.dmi differ diff --git a/icons/clothing/costumes/pirate.dmi b/icons/clothing/costumes/pirate.dmi new file mode 100644 index 000000000000..f802debc90c7 Binary files /dev/null and b/icons/clothing/costumes/pirate.dmi differ diff --git a/icons/clothing/costumes/redcoat.dmi b/icons/clothing/costumes/redcoat.dmi new file mode 100644 index 000000000000..3550ed8c5f3e Binary files /dev/null and b/icons/clothing/costumes/redcoat.dmi differ diff --git a/icons/clothing/costumes/scratch.dmi b/icons/clothing/costumes/scratch.dmi new file mode 100644 index 000000000000..dd10dddaa596 Binary files /dev/null and b/icons/clothing/costumes/scratch.dmi differ diff --git a/icons/clothing/costumes/sexyclown.dmi b/icons/clothing/costumes/sexyclown.dmi new file mode 100644 index 000000000000..80af8ff55c4f Binary files /dev/null and b/icons/clothing/costumes/sexyclown.dmi differ diff --git a/icons/clothing/costumes/sexymime.dmi b/icons/clothing/costumes/sexymime.dmi new file mode 100644 index 000000000000..3a28230bfada Binary files /dev/null and b/icons/clothing/costumes/sexymime.dmi differ diff --git a/icons/clothing/costumes/soviet.dmi b/icons/clothing/costumes/soviet.dmi new file mode 100644 index 000000000000..dce3f505725c Binary files /dev/null and b/icons/clothing/costumes/soviet.dmi differ diff --git a/icons/clothing/costumes/uniform_clown.dmi b/icons/clothing/costumes/uniform_clown.dmi new file mode 100644 index 000000000000..0dd46f18d26b Binary files /dev/null and b/icons/clothing/costumes/uniform_clown.dmi differ diff --git a/icons/clothing/costumes/uniform_lawyer_black.dmi b/icons/clothing/costumes/uniform_lawyer_black.dmi new file mode 100644 index 000000000000..3c4e44ef302c Binary files /dev/null and b/icons/clothing/costumes/uniform_lawyer_black.dmi differ diff --git a/icons/clothing/costumes/uniform_lawyer_blue.dmi b/icons/clothing/costumes/uniform_lawyer_blue.dmi new file mode 100644 index 000000000000..b4f7aad09b41 Binary files /dev/null and b/icons/clothing/costumes/uniform_lawyer_blue.dmi differ diff --git a/icons/clothing/costumes/uniform_lawyer_old.dmi b/icons/clothing/costumes/uniform_lawyer_old.dmi new file mode 100644 index 000000000000..dc4a4e597cb5 Binary files /dev/null and b/icons/clothing/costumes/uniform_lawyer_old.dmi differ diff --git a/icons/clothing/costumes/uniform_lawyer_red.dmi b/icons/clothing/costumes/uniform_lawyer_red.dmi new file mode 100644 index 000000000000..c1dcd8cae50c Binary files /dev/null and b/icons/clothing/costumes/uniform_lawyer_red.dmi differ diff --git a/icons/clothing/costumes/uniform_mime.dmi b/icons/clothing/costumes/uniform_mime.dmi new file mode 100644 index 000000000000..3e63cbaacec4 Binary files /dev/null and b/icons/clothing/costumes/uniform_mime.dmi differ diff --git a/icons/clothing/costumes/uniform_schoolgirl.dmi b/icons/clothing/costumes/uniform_schoolgirl.dmi new file mode 100644 index 000000000000..b9eb876e54bb Binary files /dev/null and b/icons/clothing/costumes/uniform_schoolgirl.dmi differ diff --git a/icons/clothing/dresses/dress_bridal_blue.dmi b/icons/clothing/dresses/dress_bridal_blue.dmi new file mode 100644 index 000000000000..9528c0e3b47b Binary files /dev/null and b/icons/clothing/dresses/dress_bridal_blue.dmi differ diff --git a/icons/clothing/dresses/dress_bridal_orange.dmi b/icons/clothing/dresses/dress_bridal_orange.dmi new file mode 100644 index 000000000000..f8996a0d94b3 Binary files /dev/null and b/icons/clothing/dresses/dress_bridal_orange.dmi differ diff --git a/icons/clothing/dresses/dress_bridal_purple.dmi b/icons/clothing/dresses/dress_bridal_purple.dmi new file mode 100644 index 000000000000..adbcec9b94f5 Binary files /dev/null and b/icons/clothing/dresses/dress_bridal_purple.dmi differ diff --git a/icons/clothing/dresses/dress_bridal_red.dmi b/icons/clothing/dresses/dress_bridal_red.dmi new file mode 100644 index 000000000000..63924678053f Binary files /dev/null and b/icons/clothing/dresses/dress_bridal_red.dmi differ diff --git a/icons/clothing/dresses/dress_bridal_white.dmi b/icons/clothing/dresses/dress_bridal_white.dmi new file mode 100644 index 000000000000..080db995b679 Binary files /dev/null and b/icons/clothing/dresses/dress_bridal_white.dmi differ diff --git a/icons/clothing/dresses/dress_bridesmaid.dmi b/icons/clothing/dresses/dress_bridesmaid.dmi new file mode 100644 index 000000000000..becacb9eb891 Binary files /dev/null and b/icons/clothing/dresses/dress_bridesmaid.dmi differ diff --git a/icons/clothing/dresses/dress_cheongsam.dmi b/icons/clothing/dresses/dress_cheongsam.dmi new file mode 100644 index 000000000000..956d557de57e Binary files /dev/null and b/icons/clothing/dresses/dress_cheongsam.dmi differ diff --git a/icons/clothing/dresses/dress_fiend.dmi b/icons/clothing/dresses/dress_fiend.dmi new file mode 100644 index 000000000000..7b1b91fc3e39 Binary files /dev/null and b/icons/clothing/dresses/dress_fiend.dmi differ diff --git a/icons/clothing/dresses/dress_fire.dmi b/icons/clothing/dresses/dress_fire.dmi new file mode 100644 index 000000000000..374d5f2d16aa Binary files /dev/null and b/icons/clothing/dresses/dress_fire.dmi differ diff --git a/icons/clothing/dresses/dress_gown.dmi b/icons/clothing/dresses/dress_gown.dmi new file mode 100644 index 000000000000..c7a9d54c95ca Binary files /dev/null and b/icons/clothing/dresses/dress_gown.dmi differ diff --git a/icons/clothing/dresses/dress_green.dmi b/icons/clothing/dresses/dress_green.dmi new file mode 100644 index 000000000000..53382b5e82f9 Binary files /dev/null and b/icons/clothing/dresses/dress_green.dmi differ diff --git a/icons/clothing/dresses/dress_hop.dmi b/icons/clothing/dresses/dress_hop.dmi new file mode 100644 index 000000000000..875fa8f49a81 Binary files /dev/null and b/icons/clothing/dresses/dress_hop.dmi differ diff --git a/icons/clothing/dresses/dress_hr.dmi b/icons/clothing/dresses/dress_hr.dmi new file mode 100644 index 000000000000..c6d8e99ce4f1 Binary files /dev/null and b/icons/clothing/dresses/dress_hr.dmi differ diff --git a/icons/clothing/dresses/dress_long.dmi b/icons/clothing/dresses/dress_long.dmi new file mode 100644 index 000000000000..0a6aa42b096b Binary files /dev/null and b/icons/clothing/dresses/dress_long.dmi differ diff --git a/icons/clothing/dresses/dress_nurse.dmi b/icons/clothing/dresses/dress_nurse.dmi new file mode 100644 index 000000000000..2134eef0b96d Binary files /dev/null and b/icons/clothing/dresses/dress_nurse.dmi differ diff --git a/icons/clothing/dresses/dress_orange.dmi b/icons/clothing/dresses/dress_orange.dmi new file mode 100644 index 000000000000..0ef3f053d946 Binary files /dev/null and b/icons/clothing/dresses/dress_orange.dmi differ diff --git a/icons/clothing/dresses/dress_pink.dmi b/icons/clothing/dresses/dress_pink.dmi new file mode 100644 index 000000000000..73e50c08980e Binary files /dev/null and b/icons/clothing/dresses/dress_pink.dmi differ diff --git a/icons/clothing/dresses/dress_plaid_blue.dmi b/icons/clothing/dresses/dress_plaid_blue.dmi new file mode 100644 index 000000000000..3bbff165910f Binary files /dev/null and b/icons/clothing/dresses/dress_plaid_blue.dmi differ diff --git a/icons/clothing/dresses/dress_plaid_purple.dmi b/icons/clothing/dresses/dress_plaid_purple.dmi new file mode 100644 index 000000000000..2dcee2360df9 Binary files /dev/null and b/icons/clothing/dresses/dress_plaid_purple.dmi differ diff --git a/icons/clothing/dresses/dress_plaid_red.dmi b/icons/clothing/dresses/dress_plaid_red.dmi new file mode 100644 index 000000000000..347caed8d52a Binary files /dev/null and b/icons/clothing/dresses/dress_plaid_red.dmi differ diff --git a/icons/clothing/dresses/dress_purple.dmi b/icons/clothing/dresses/dress_purple.dmi new file mode 100644 index 000000000000..b126a63b613a Binary files /dev/null and b/icons/clothing/dresses/dress_purple.dmi differ diff --git a/icons/clothing/dresses/dress_rd.dmi b/icons/clothing/dresses/dress_rd.dmi new file mode 100644 index 000000000000..4d239bc54d23 Binary files /dev/null and b/icons/clothing/dresses/dress_rd.dmi differ diff --git a/icons/clothing/dresses/dress_saloon.dmi b/icons/clothing/dresses/dress_saloon.dmi new file mode 100644 index 000000000000..5df0baa5ba98 Binary files /dev/null and b/icons/clothing/dresses/dress_saloon.dmi differ diff --git a/icons/clothing/dresses/dress_short.dmi b/icons/clothing/dresses/dress_short.dmi new file mode 100644 index 000000000000..feff94edce84 Binary files /dev/null and b/icons/clothing/dresses/dress_short.dmi differ diff --git a/icons/clothing/dresses/dress_sundress.dmi b/icons/clothing/dresses/dress_sundress.dmi new file mode 100644 index 000000000000..db16e5854d9b Binary files /dev/null and b/icons/clothing/dresses/dress_sundress.dmi differ diff --git a/icons/clothing/dresses/dress_sundress_white.dmi b/icons/clothing/dresses/dress_sundress_white.dmi new file mode 100644 index 000000000000..abc347472e09 Binary files /dev/null and b/icons/clothing/dresses/dress_sundress_white.dmi differ diff --git a/icons/clothing/dresses/dress_tango.dmi b/icons/clothing/dresses/dress_tango.dmi new file mode 100644 index 000000000000..2fbf79028833 Binary files /dev/null and b/icons/clothing/dresses/dress_tango.dmi differ diff --git a/icons/clothing/dresses/dress_white.dmi b/icons/clothing/dresses/dress_white.dmi new file mode 100644 index 000000000000..16a948782e17 Binary files /dev/null and b/icons/clothing/dresses/dress_white.dmi differ diff --git a/icons/clothing/dresses/dress_yellow.dmi b/icons/clothing/dresses/dress_yellow.dmi new file mode 100644 index 000000000000..d780fb399847 Binary files /dev/null and b/icons/clothing/dresses/dress_yellow.dmi differ diff --git a/icons/clothing/dresses/gown.dmi b/icons/clothing/dresses/gown.dmi new file mode 100644 index 000000000000..4490ea3e46c5 Binary files /dev/null and b/icons/clothing/dresses/gown.dmi differ diff --git a/icons/clothing/dresses/kimono.dmi b/icons/clothing/dresses/kimono.dmi new file mode 100644 index 000000000000..d698c03ea513 Binary files /dev/null and b/icons/clothing/dresses/kimono.dmi differ diff --git a/icons/clothing/dresses/nurse.dmi b/icons/clothing/dresses/nurse.dmi new file mode 100644 index 000000000000..cfd96547aa75 Binary files /dev/null and b/icons/clothing/dresses/nurse.dmi differ diff --git a/icons/clothing/dresses/uniform_captain_dress.dmi b/icons/clothing/dresses/uniform_captain_dress.dmi new file mode 100644 index 000000000000..8c4b9ae1b563 Binary files /dev/null and b/icons/clothing/dresses/uniform_captain_dress.dmi differ diff --git a/icons/clothing/ears/earring_dangle.dmi b/icons/clothing/ears/earring_dangle.dmi new file mode 100644 index 000000000000..797703e9d17e Binary files /dev/null and b/icons/clothing/ears/earring_dangle.dmi differ diff --git a/icons/clothing/ears/earring_stud.dmi b/icons/clothing/ears/earring_stud.dmi new file mode 100644 index 000000000000..d6ac1659311b Binary files /dev/null and b/icons/clothing/ears/earring_stud.dmi differ diff --git a/icons/clothing/eyes/blindfold.dmi b/icons/clothing/eyes/blindfold.dmi new file mode 100644 index 000000000000..4ed91c6a029d Binary files /dev/null and b/icons/clothing/eyes/blindfold.dmi differ diff --git a/icons/clothing/eyes/blindfold_tape.dmi b/icons/clothing/eyes/blindfold_tape.dmi new file mode 100644 index 000000000000..f632e45d05e0 Binary files /dev/null and b/icons/clothing/eyes/blindfold_tape.dmi differ diff --git a/icons/clothing/eyes/eyepatch.dmi b/icons/clothing/eyes/eyepatch.dmi new file mode 100644 index 000000000000..bad38ac5574c Binary files /dev/null and b/icons/clothing/eyes/eyepatch.dmi differ diff --git a/icons/clothing/eyes/eyepatch_colourable.dmi b/icons/clothing/eyes/eyepatch_colourable.dmi new file mode 100644 index 000000000000..dbf4a4db6029 Binary files /dev/null and b/icons/clothing/eyes/eyepatch_colourable.dmi differ diff --git a/icons/clothing/eyes/eyepatch_colourable_right.dmi b/icons/clothing/eyes/eyepatch_colourable_right.dmi new file mode 100644 index 000000000000..466efc066c32 Binary files /dev/null and b/icons/clothing/eyes/eyepatch_colourable_right.dmi differ diff --git a/icons/clothing/eyes/eyepatch_right.dmi b/icons/clothing/eyes/eyepatch_right.dmi new file mode 100644 index 000000000000..da82189fe9db Binary files /dev/null and b/icons/clothing/eyes/eyepatch_right.dmi differ diff --git a/icons/clothing/eyes/glasses_3d.dmi b/icons/clothing/eyes/glasses_3d.dmi new file mode 100644 index 000000000000..fa50efb9fcd2 Binary files /dev/null and b/icons/clothing/eyes/glasses_3d.dmi differ diff --git a/icons/clothing/eyes/glasses_green.dmi b/icons/clothing/eyes/glasses_green.dmi new file mode 100644 index 000000000000..7deee1d0f4e5 Binary files /dev/null and b/icons/clothing/eyes/glasses_green.dmi differ diff --git a/icons/clothing/eyes/glasses_hipster.dmi b/icons/clothing/eyes/glasses_hipster.dmi new file mode 100644 index 000000000000..0d4e00ab0412 Binary files /dev/null and b/icons/clothing/eyes/glasses_hipster.dmi differ diff --git a/icons/clothing/eyes/glasses_pincenez.dmi b/icons/clothing/eyes/glasses_pincenez.dmi new file mode 100644 index 000000000000..5d4f20a6cbc9 Binary files /dev/null and b/icons/clothing/eyes/glasses_pincenez.dmi differ diff --git a/icons/clothing/eyes/glasses_prescription.dmi b/icons/clothing/eyes/glasses_prescription.dmi new file mode 100644 index 000000000000..b3beddce5d86 Binary files /dev/null and b/icons/clothing/eyes/glasses_prescription.dmi differ diff --git a/icons/clothing/eyes/goggles_hud.dmi b/icons/clothing/eyes/goggles_hud.dmi new file mode 100644 index 000000000000..3ac56073eff6 Binary files /dev/null and b/icons/clothing/eyes/goggles_hud.dmi differ diff --git a/icons/clothing/eyes/goggles_scanning.dmi b/icons/clothing/eyes/goggles_scanning.dmi new file mode 100644 index 000000000000..73c633616794 Binary files /dev/null and b/icons/clothing/eyes/goggles_scanning.dmi differ diff --git a/icons/clothing/eyes/goggles_science.dmi b/icons/clothing/eyes/goggles_science.dmi new file mode 100644 index 000000000000..d77c3c19c86c Binary files /dev/null and b/icons/clothing/eyes/goggles_science.dmi differ diff --git a/icons/clothing/eyes/goggles_welding.dmi b/icons/clothing/eyes/goggles_welding.dmi new file mode 100644 index 000000000000..c927eb18b240 Binary files /dev/null and b/icons/clothing/eyes/goggles_welding.dmi differ diff --git a/icons/clothing/eyes/goggles_welding_superior.dmi b/icons/clothing/eyes/goggles_welding_superior.dmi new file mode 100644 index 000000000000..8777a6dcb1d3 Binary files /dev/null and b/icons/clothing/eyes/goggles_welding_superior.dmi differ diff --git a/icons/clothing/eyes/hud_janitor.dmi b/icons/clothing/eyes/hud_janitor.dmi new file mode 100644 index 000000000000..717abe3fd2ac Binary files /dev/null and b/icons/clothing/eyes/hud_janitor.dmi differ diff --git a/icons/clothing/eyes/hud_janitor_prescription.dmi b/icons/clothing/eyes/hud_janitor_prescription.dmi new file mode 100644 index 000000000000..f31f9a889370 Binary files /dev/null and b/icons/clothing/eyes/hud_janitor_prescription.dmi differ diff --git a/icons/clothing/eyes/hud_medical.dmi b/icons/clothing/eyes/hud_medical.dmi new file mode 100644 index 000000000000..a5d5efd89695 Binary files /dev/null and b/icons/clothing/eyes/hud_medical.dmi differ diff --git a/icons/clothing/eyes/hud_medical_prescription.dmi b/icons/clothing/eyes/hud_medical_prescription.dmi new file mode 100644 index 000000000000..42a88d227916 Binary files /dev/null and b/icons/clothing/eyes/hud_medical_prescription.dmi differ diff --git a/icons/clothing/eyes/hud_medical_visor.dmi b/icons/clothing/eyes/hud_medical_visor.dmi new file mode 100644 index 000000000000..1d8df37b4a40 Binary files /dev/null and b/icons/clothing/eyes/hud_medical_visor.dmi differ diff --git a/icons/clothing/eyes/hud_sec_aviators.dmi b/icons/clothing/eyes/hud_sec_aviators.dmi new file mode 100644 index 000000000000..2c4d82b39721 Binary files /dev/null and b/icons/clothing/eyes/hud_sec_aviators.dmi differ diff --git a/icons/clothing/eyes/hud_security.dmi b/icons/clothing/eyes/hud_security.dmi new file mode 100644 index 000000000000..b2adf47e0e38 Binary files /dev/null and b/icons/clothing/eyes/hud_security.dmi differ diff --git a/icons/clothing/eyes/hud_security_prescription.dmi b/icons/clothing/eyes/hud_security_prescription.dmi new file mode 100644 index 000000000000..93f8bf0dd7d0 Binary files /dev/null and b/icons/clothing/eyes/hud_security_prescription.dmi differ diff --git a/icons/clothing/eyes/hud_security_shades.dmi b/icons/clothing/eyes/hud_security_shades.dmi new file mode 100644 index 000000000000..efb2d6b8fc75 Binary files /dev/null and b/icons/clothing/eyes/hud_security_shades.dmi differ diff --git a/icons/clothing/eyes/hudpatch.dmi b/icons/clothing/eyes/hudpatch.dmi new file mode 100644 index 000000000000..0faf0dd19e2d Binary files /dev/null and b/icons/clothing/eyes/hudpatch.dmi differ diff --git a/icons/clothing/eyes/hudpatch_right.dmi b/icons/clothing/eyes/hudpatch_right.dmi new file mode 100644 index 000000000000..2cf2715365fa Binary files /dev/null and b/icons/clothing/eyes/hudpatch_right.dmi differ diff --git a/icons/clothing/eyes/monocle.dmi b/icons/clothing/eyes/monocle.dmi new file mode 100644 index 000000000000..bc6ca64e02fc Binary files /dev/null and b/icons/clothing/eyes/monocle.dmi differ diff --git a/icons/clothing/eyes/monocle_right.dmi b/icons/clothing/eyes/monocle_right.dmi new file mode 100644 index 000000000000..51a007c3d2a9 Binary files /dev/null and b/icons/clothing/eyes/monocle_right.dmi differ diff --git a/icons/clothing/eyes/night_vision.dmi b/icons/clothing/eyes/night_vision.dmi new file mode 100644 index 000000000000..6eceb02c566b Binary files /dev/null and b/icons/clothing/eyes/night_vision.dmi differ diff --git a/icons/clothing/eyes/scanner_material.dmi b/icons/clothing/eyes/scanner_material.dmi new file mode 100644 index 000000000000..0293765d4598 Binary files /dev/null and b/icons/clothing/eyes/scanner_material.dmi differ diff --git a/icons/clothing/eyes/scanner_meson.dmi b/icons/clothing/eyes/scanner_meson.dmi new file mode 100644 index 000000000000..727786c5ea3f Binary files /dev/null and b/icons/clothing/eyes/scanner_meson.dmi differ diff --git a/icons/clothing/eyes/scanner_thermal.dmi b/icons/clothing/eyes/scanner_thermal.dmi new file mode 100644 index 000000000000..fda717520a7a Binary files /dev/null and b/icons/clothing/eyes/scanner_thermal.dmi differ diff --git a/icons/clothing/eyes/sunglasses.dmi b/icons/clothing/eyes/sunglasses.dmi new file mode 100644 index 000000000000..28c7ce92e037 Binary files /dev/null and b/icons/clothing/eyes/sunglasses.dmi differ diff --git a/icons/clothing/eyes/sunglasses_big.dmi b/icons/clothing/eyes/sunglasses_big.dmi new file mode 100644 index 000000000000..15c484c91d2d Binary files /dev/null and b/icons/clothing/eyes/sunglasses_big.dmi differ diff --git a/icons/clothing/eyes/sunglasses_hud.dmi b/icons/clothing/eyes/sunglasses_hud.dmi new file mode 100644 index 000000000000..c66780c00e89 Binary files /dev/null and b/icons/clothing/eyes/sunglasses_hud.dmi differ diff --git a/icons/clothing/eyes/tactical.dmi b/icons/clothing/eyes/tactical.dmi new file mode 100644 index 000000000000..e607a0999e67 Binary files /dev/null and b/icons/clothing/eyes/tactical.dmi differ diff --git a/icons/clothing/eyes/thermal_implants.dmi b/icons/clothing/eyes/thermal_implants.dmi new file mode 100644 index 000000000000..a63ac95c7f21 Binary files /dev/null and b/icons/clothing/eyes/thermal_implants.dmi differ diff --git a/icons/clothing/eyes/thermoncle.dmi b/icons/clothing/eyes/thermoncle.dmi new file mode 100644 index 000000000000..579b43898f4d Binary files /dev/null and b/icons/clothing/eyes/thermoncle.dmi differ diff --git a/icons/clothing/feet/magboots.dmi b/icons/clothing/feet/magboots.dmi index 07dbb7d4714d..b9c5aabe76c1 100644 Binary files a/icons/clothing/feet/magboots.dmi and b/icons/clothing/feet/magboots.dmi differ diff --git a/icons/clothing/feet/winterboots.dmi b/icons/clothing/feet/winterboots.dmi new file mode 100644 index 000000000000..a55786822ad7 Binary files /dev/null and b/icons/clothing/feet/winterboots.dmi differ diff --git a/icons/clothing/head/bandana.dmi b/icons/clothing/head/bandana.dmi new file mode 100644 index 000000000000..016b7a57e9cf Binary files /dev/null and b/icons/clothing/head/bandana.dmi differ diff --git a/icons/clothing/head/bandana_botany.dmi b/icons/clothing/head/bandana_botany.dmi new file mode 100644 index 000000000000..24a5fc6dade8 Binary files /dev/null and b/icons/clothing/head/bandana_botany.dmi differ diff --git a/icons/clothing/head/bandana_camo.dmi b/icons/clothing/head/bandana_camo.dmi new file mode 100644 index 000000000000..0a82fe6b83b7 Binary files /dev/null and b/icons/clothing/head/bandana_camo.dmi differ diff --git a/icons/clothing/head/bandana_skull.dmi b/icons/clothing/head/bandana_skull.dmi new file mode 100644 index 000000000000..87a21a511623 Binary files /dev/null and b/icons/clothing/head/bandana_skull.dmi differ diff --git a/icons/clothing/head/cakehat.dmi b/icons/clothing/head/cakehat.dmi new file mode 100644 index 000000000000..7b598c138c4e Binary files /dev/null and b/icons/clothing/head/cakehat.dmi differ diff --git a/icons/clothing/head/earmuffs.dmi b/icons/clothing/head/earmuffs.dmi new file mode 100644 index 000000000000..2d48e4d8c2be Binary files /dev/null and b/icons/clothing/head/earmuffs.dmi differ diff --git a/icons/clothing/head/festive.dmi b/icons/clothing/head/festive.dmi new file mode 100644 index 000000000000..393a04c93e6d Binary files /dev/null and b/icons/clothing/head/festive.dmi differ diff --git a/icons/clothing/head/grim_hood.dmi b/icons/clothing/head/grim_hood.dmi new file mode 100644 index 000000000000..37ae3d7ecc58 Binary files /dev/null and b/icons/clothing/head/grim_hood.dmi differ diff --git a/icons/clothing/head/hardhat/medic.dmi b/icons/clothing/head/hardhat/medic.dmi index 92c875a6d312..d6a350b74c03 100644 Binary files a/icons/clothing/head/hardhat/medic.dmi and b/icons/clothing/head/hardhat/medic.dmi differ diff --git a/icons/clothing/head/hastur.dmi b/icons/clothing/head/hastur.dmi index f0fba0bd8375..694f25d6d94b 100644 Binary files a/icons/clothing/head/hastur.dmi and b/icons/clothing/head/hastur.dmi differ diff --git a/icons/clothing/head/headband.dmi b/icons/clothing/head/headband.dmi new file mode 100644 index 000000000000..a042cea810d6 Binary files /dev/null and b/icons/clothing/head/headband.dmi differ diff --git a/icons/clothing/head/headphones.dmi b/icons/clothing/head/headphones.dmi new file mode 100644 index 000000000000..2bdc14594d63 Binary files /dev/null and b/icons/clothing/head/headphones.dmi differ diff --git a/icons/clothing/head/hood.dmi b/icons/clothing/head/hood.dmi new file mode 100644 index 000000000000..0871ded492cf Binary files /dev/null and b/icons/clothing/head/hood.dmi differ diff --git a/icons/clothing/head/hood_cloak.dmi b/icons/clothing/head/hood_cloak.dmi new file mode 100644 index 000000000000..ef4aac3bde17 Binary files /dev/null and b/icons/clothing/head/hood_cloak.dmi differ diff --git a/icons/clothing/head/hood_craftable.dmi b/icons/clothing/head/hood_craftable.dmi new file mode 100644 index 000000000000..fa2847d643dd Binary files /dev/null and b/icons/clothing/head/hood_craftable.dmi differ diff --git a/icons/clothing/head/hood_parka.dmi b/icons/clothing/head/hood_parka.dmi new file mode 100644 index 000000000000..7b006dea4245 Binary files /dev/null and b/icons/clothing/head/hood_parka.dmi differ diff --git a/icons/clothing/head/hood_winter.dmi b/icons/clothing/head/hood_winter.dmi new file mode 100644 index 000000000000..b9c95c7c6bfd Binary files /dev/null and b/icons/clothing/head/hood_winter.dmi differ diff --git a/icons/clothing/head/hood_winter_atmos.dmi b/icons/clothing/head/hood_winter_atmos.dmi new file mode 100644 index 000000000000..54299053b899 Binary files /dev/null and b/icons/clothing/head/hood_winter_atmos.dmi differ diff --git a/icons/clothing/head/hood_winter_captain.dmi b/icons/clothing/head/hood_winter_captain.dmi new file mode 100644 index 000000000000..8831078cb52b Binary files /dev/null and b/icons/clothing/head/hood_winter_captain.dmi differ diff --git a/icons/clothing/head/hood_winter_cargo.dmi b/icons/clothing/head/hood_winter_cargo.dmi new file mode 100644 index 000000000000..8ff4d5f2d2e5 Binary files /dev/null and b/icons/clothing/head/hood_winter_cargo.dmi differ diff --git a/icons/clothing/head/hood_winter_eng.dmi b/icons/clothing/head/hood_winter_eng.dmi new file mode 100644 index 000000000000..171b101afbf2 Binary files /dev/null and b/icons/clothing/head/hood_winter_eng.dmi differ diff --git a/icons/clothing/head/hood_winter_hydro.dmi b/icons/clothing/head/hood_winter_hydro.dmi new file mode 100644 index 000000000000..cd717e497d63 Binary files /dev/null and b/icons/clothing/head/hood_winter_hydro.dmi differ diff --git a/icons/clothing/head/hood_winter_med.dmi b/icons/clothing/head/hood_winter_med.dmi new file mode 100644 index 000000000000..f5e49c4be0d9 Binary files /dev/null and b/icons/clothing/head/hood_winter_med.dmi differ diff --git a/icons/clothing/head/hood_winter_mining.dmi b/icons/clothing/head/hood_winter_mining.dmi new file mode 100644 index 000000000000..e014d86fa69c Binary files /dev/null and b/icons/clothing/head/hood_winter_mining.dmi differ diff --git a/icons/clothing/head/hood_winter_sci.dmi b/icons/clothing/head/hood_winter_sci.dmi new file mode 100644 index 000000000000..a4e3823e2eb1 Binary files /dev/null and b/icons/clothing/head/hood_winter_sci.dmi differ diff --git a/icons/clothing/head/hood_winter_sec.dmi b/icons/clothing/head/hood_winter_sec.dmi new file mode 100644 index 000000000000..4af7c5b697a0 Binary files /dev/null and b/icons/clothing/head/hood_winter_sec.dmi differ diff --git a/icons/clothing/head/pumpkin.dmi b/icons/clothing/head/pumpkin.dmi index c38d51b6d7fb..de6ac8af04e6 100644 Binary files a/icons/clothing/head/pumpkin.dmi and b/icons/clothing/head/pumpkin.dmi differ diff --git a/icons/clothing/head/tophat.dmi b/icons/clothing/head/tophat.dmi index dc92441cbb7f..4c467bd6a055 100644 Binary files a/icons/clothing/head/tophat.dmi and b/icons/clothing/head/tophat.dmi differ diff --git a/icons/clothing/jumpsuits/caretaker.dmi b/icons/clothing/jumpsuits/caretaker.dmi new file mode 100644 index 000000000000..54e287a96400 Binary files /dev/null and b/icons/clothing/jumpsuits/caretaker.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit.dmi b/icons/clothing/jumpsuits/jumpsuit.dmi new file mode 100644 index 000000000000..93915c507410 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_atmos.dmi b/icons/clothing/jumpsuits/jumpsuit_atmos.dmi new file mode 100644 index 000000000000..c875b073bd17 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_atmos.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_captain.dmi b/icons/clothing/jumpsuits/jumpsuit_captain.dmi new file mode 100644 index 000000000000..c0099fba885b Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_captain.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_cargo.dmi b/icons/clothing/jumpsuits/jumpsuit_cargo.dmi new file mode 100644 index 000000000000..278b871f3a12 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_cargo.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_cargo_alt.dmi b/icons/clothing/jumpsuits/jumpsuit_cargo_alt.dmi new file mode 100644 index 000000000000..b7782d4fa5f8 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_cargo_alt.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_ce.dmi b/icons/clothing/jumpsuits/jumpsuit_ce.dmi new file mode 100644 index 000000000000..66444d604cb0 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_ce.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_chaplain.dmi b/icons/clothing/jumpsuits/jumpsuit_chaplain.dmi new file mode 100644 index 000000000000..3e8769c98df8 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_chaplain.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_chemist.dmi b/icons/clothing/jumpsuits/jumpsuit_chemist.dmi new file mode 100644 index 000000000000..b020cd862b0c Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_chemist.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_cmo.dmi b/icons/clothing/jumpsuits/jumpsuit_cmo.dmi new file mode 100644 index 000000000000..ade2910cecef Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_cmo.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_engineer.dmi b/icons/clothing/jumpsuits/jumpsuit_engineer.dmi new file mode 100644 index 000000000000..02999b489c38 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_engineer.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_genetics.dmi b/icons/clothing/jumpsuits/jumpsuit_genetics.dmi new file mode 100644 index 000000000000..3c401fc77769 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_genetics.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_hazard.dmi b/icons/clothing/jumpsuits/jumpsuit_hazard.dmi new file mode 100644 index 000000000000..be1f5468a077 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_hazard.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_hop.dmi b/icons/clothing/jumpsuits/jumpsuit_hop.dmi new file mode 100644 index 000000000000..61380b57b148 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_hop.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_hos.dmi b/icons/clothing/jumpsuits/jumpsuit_hos.dmi new file mode 100644 index 000000000000..468cc979a85c Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_hos.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_hos_alt.dmi b/icons/clothing/jumpsuits/jumpsuit_hos_alt.dmi new file mode 100644 index 000000000000..a7ee171acbb5 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_hos_alt.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_hydroponics.dmi b/icons/clothing/jumpsuits/jumpsuit_hydroponics.dmi new file mode 100644 index 000000000000..25f328ae0798 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_hydroponics.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_janitor.dmi b/icons/clothing/jumpsuits/jumpsuit_janitor.dmi new file mode 100644 index 000000000000..8d9257cc96ba Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_janitor.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_mailman.dmi b/icons/clothing/jumpsuits/jumpsuit_mailman.dmi new file mode 100644 index 000000000000..05f53512d4b5 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_mailman.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_medical.dmi b/icons/clothing/jumpsuits/jumpsuit_medical.dmi new file mode 100644 index 000000000000..47edde803153 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_medical.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_miner.dmi b/icons/clothing/jumpsuits/jumpsuit_miner.dmi new file mode 100644 index 000000000000..c93ee14a40fd Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_miner.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_owl.dmi b/icons/clothing/jumpsuits/jumpsuit_owl.dmi new file mode 100644 index 000000000000..b3510c8c1d0c Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_owl.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_prisoner.dmi b/icons/clothing/jumpsuits/jumpsuit_prisoner.dmi new file mode 100644 index 000000000000..26ea1aef0143 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_prisoner.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_psionic.dmi b/icons/clothing/jumpsuits/jumpsuit_psionic.dmi new file mode 100644 index 000000000000..22d106e862a0 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_psionic.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_psych.dmi b/icons/clothing/jumpsuits/jumpsuit_psych.dmi new file mode 100644 index 000000000000..e140cd2f684a Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_psych.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_psychadelic.dmi b/icons/clothing/jumpsuits/jumpsuit_psychadelic.dmi new file mode 100644 index 000000000000..98e52634d634 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_psychadelic.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_qm.dmi b/icons/clothing/jumpsuits/jumpsuit_qm.dmi new file mode 100644 index 000000000000..1ff46f49e5f6 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_qm.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_rainbow.dmi b/icons/clothing/jumpsuits/jumpsuit_rainbow.dmi new file mode 100644 index 000000000000..170534cbc62f Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_rainbow.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_rd.dmi b/icons/clothing/jumpsuits/jumpsuit_rd.dmi new file mode 100644 index 000000000000..192d998ad8d2 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_rd.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_robotics.dmi b/icons/clothing/jumpsuits/jumpsuit_robotics.dmi new file mode 100644 index 000000000000..ff89c3e05de1 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_robotics.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_robotics_skirt.dmi b/icons/clothing/jumpsuits/jumpsuit_robotics_skirt.dmi new file mode 100644 index 000000000000..7edfad1113ce Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_robotics_skirt.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_sec.dmi b/icons/clothing/jumpsuits/jumpsuit_sec.dmi new file mode 100644 index 000000000000..26e66b428a5f Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_sec.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_shorts.dmi b/icons/clothing/jumpsuits/jumpsuit_shorts.dmi new file mode 100644 index 000000000000..8025567b7f85 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_shorts.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_skirt.dmi b/icons/clothing/jumpsuits/jumpsuit_skirt.dmi new file mode 100644 index 000000000000..04062ac781dc Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_skirt.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_skirt_short.dmi b/icons/clothing/jumpsuits/jumpsuit_skirt_short.dmi new file mode 100644 index 000000000000..f57de00e310a Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_skirt_short.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_sterile.dmi b/icons/clothing/jumpsuits/jumpsuit_sterile.dmi new file mode 100644 index 000000000000..9b06e63d3376 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_sterile.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_virology.dmi b/icons/clothing/jumpsuits/jumpsuit_virology.dmi new file mode 100644 index 000000000000..192d998ad8d2 Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_virology.dmi differ diff --git a/icons/clothing/jumpsuits/jumpsuit_warden.dmi b/icons/clothing/jumpsuits/jumpsuit_warden.dmi new file mode 100644 index 000000000000..44d32edbfffc Binary files /dev/null and b/icons/clothing/jumpsuits/jumpsuit_warden.dmi differ diff --git a/icons/clothing/jumpsuits/uniform_quantum.dmi b/icons/clothing/jumpsuits/uniform_quantum.dmi new file mode 100644 index 000000000000..a120fe40f895 Binary files /dev/null and b/icons/clothing/jumpsuits/uniform_quantum.dmi differ diff --git a/icons/clothing/jumpsuits/wetsuit.dmi b/icons/clothing/jumpsuits/wetsuit.dmi new file mode 100644 index 000000000000..932f6d9be6a3 Binary files /dev/null and b/icons/clothing/jumpsuits/wetsuit.dmi differ diff --git a/icons/clothing/mask/balaclava.dmi b/icons/clothing/mask/balaclava.dmi new file mode 100644 index 000000000000..e50f1fb88428 Binary files /dev/null and b/icons/clothing/mask/balaclava.dmi differ diff --git a/icons/clothing/mask/breath.dmi b/icons/clothing/mask/breath.dmi new file mode 100644 index 000000000000..3764b54ffd36 Binary files /dev/null and b/icons/clothing/mask/breath.dmi differ diff --git a/icons/clothing/mask/breath_medical.dmi b/icons/clothing/mask/breath_medical.dmi new file mode 100644 index 000000000000..0639090be212 Binary files /dev/null and b/icons/clothing/mask/breath_medical.dmi differ diff --git a/icons/clothing/mask/breath_scuba.dmi b/icons/clothing/mask/breath_scuba.dmi new file mode 100644 index 000000000000..3e2911742638 Binary files /dev/null and b/icons/clothing/mask/breath_scuba.dmi differ diff --git a/icons/clothing/mask/camera_miu.dmi b/icons/clothing/mask/camera_miu.dmi new file mode 100644 index 000000000000..86c1d44a081f Binary files /dev/null and b/icons/clothing/mask/camera_miu.dmi differ diff --git a/icons/clothing/mask/cat.dmi b/icons/clothing/mask/cat.dmi new file mode 100644 index 000000000000..9f9cb1196547 Binary files /dev/null and b/icons/clothing/mask/cat.dmi differ diff --git a/icons/clothing/mask/chewables/chew.dmi b/icons/clothing/mask/chewables/chew.dmi new file mode 100644 index 000000000000..8870b62114e1 Binary files /dev/null and b/icons/clothing/mask/chewables/chew.dmi differ diff --git a/icons/clothing/mask/chewables/chew_spit.dmi b/icons/clothing/mask/chewables/chew_spit.dmi new file mode 100644 index 000000000000..0b60b4b23f7d Binary files /dev/null and b/icons/clothing/mask/chewables/chew_spit.dmi differ diff --git a/icons/clothing/mask/chewables/gum.dmi b/icons/clothing/mask/chewables/gum.dmi new file mode 100644 index 000000000000..5b3f300cf4c4 Binary files /dev/null and b/icons/clothing/mask/chewables/gum.dmi differ diff --git a/icons/clothing/mask/chewables/gum_nicotine.dmi b/icons/clothing/mask/chewables/gum_nicotine.dmi new file mode 100644 index 000000000000..610170391589 Binary files /dev/null and b/icons/clothing/mask/chewables/gum_nicotine.dmi differ diff --git a/icons/clothing/mask/chewables/gum_spit.dmi b/icons/clothing/mask/chewables/gum_spit.dmi new file mode 100644 index 000000000000..ce087b503fb5 Binary files /dev/null and b/icons/clothing/mask/chewables/gum_spit.dmi differ diff --git a/icons/clothing/mask/chewables/lollipop.dmi b/icons/clothing/mask/chewables/lollipop.dmi new file mode 100644 index 000000000000..49ba4a918d29 Binary files /dev/null and b/icons/clothing/mask/chewables/lollipop.dmi differ diff --git a/icons/clothing/mask/chewables/lollipop_stick.dmi b/icons/clothing/mask/chewables/lollipop_stick.dmi new file mode 100644 index 000000000000..2af4d32c4439 Binary files /dev/null and b/icons/clothing/mask/chewables/lollipop_stick.dmi differ diff --git a/icons/clothing/mask/chewables/wad.dmi b/icons/clothing/mask/chewables/wad.dmi new file mode 100644 index 000000000000..d95bbbb00e68 Binary files /dev/null and b/icons/clothing/mask/chewables/wad.dmi differ diff --git a/icons/clothing/mask/gas_mask.dmi b/icons/clothing/mask/gas_mask.dmi new file mode 100644 index 000000000000..ef68f54325ee Binary files /dev/null and b/icons/clothing/mask/gas_mask.dmi differ diff --git a/icons/clothing/mask/gas_mask_alt.dmi b/icons/clothing/mask/gas_mask_alt.dmi new file mode 100644 index 000000000000..8a3891ef624c Binary files /dev/null and b/icons/clothing/mask/gas_mask_alt.dmi differ diff --git a/icons/clothing/mask/gas_mask_clown.dmi b/icons/clothing/mask/gas_mask_clown.dmi new file mode 100644 index 000000000000..1680ad1acacf Binary files /dev/null and b/icons/clothing/mask/gas_mask_clown.dmi differ diff --git a/icons/clothing/mask/gas_mask_death.dmi b/icons/clothing/mask/gas_mask_death.dmi new file mode 100644 index 000000000000..a6814252ab74 Binary files /dev/null and b/icons/clothing/mask/gas_mask_death.dmi differ diff --git a/icons/clothing/mask/gas_mask_full.dmi b/icons/clothing/mask/gas_mask_full.dmi new file mode 100644 index 000000000000..e4c4a52ea634 Binary files /dev/null and b/icons/clothing/mask/gas_mask_full.dmi differ diff --git a/icons/clothing/mask/gas_mask_half.dmi b/icons/clothing/mask/gas_mask_half.dmi new file mode 100644 index 000000000000..40241a7097ca Binary files /dev/null and b/icons/clothing/mask/gas_mask_half.dmi differ diff --git a/icons/clothing/mask/gas_mask_mime.dmi b/icons/clothing/mask/gas_mask_mime.dmi new file mode 100644 index 000000000000..0eedabfdcf55 Binary files /dev/null and b/icons/clothing/mask/gas_mask_mime.dmi differ diff --git a/icons/clothing/mask/gas_mask_monkey.dmi b/icons/clothing/mask/gas_mask_monkey.dmi new file mode 100644 index 000000000000..3d0a9c75b9df Binary files /dev/null and b/icons/clothing/mask/gas_mask_monkey.dmi differ diff --git a/icons/clothing/mask/gas_mask_owl.dmi b/icons/clothing/mask/gas_mask_owl.dmi new file mode 100644 index 000000000000..99e33c1e6cef Binary files /dev/null and b/icons/clothing/mask/gas_mask_owl.dmi differ diff --git a/icons/clothing/mask/gas_mask_plague.dmi b/icons/clothing/mask/gas_mask_plague.dmi new file mode 100644 index 000000000000..ae1f83ab9e7b Binary files /dev/null and b/icons/clothing/mask/gas_mask_plague.dmi differ diff --git a/icons/clothing/mask/gas_mask_poltergeist.dmi b/icons/clothing/mask/gas_mask_poltergeist.dmi new file mode 100644 index 000000000000..9a600362d7e4 Binary files /dev/null and b/icons/clothing/mask/gas_mask_poltergeist.dmi differ diff --git a/icons/clothing/mask/gas_mask_sexyclown.dmi b/icons/clothing/mask/gas_mask_sexyclown.dmi new file mode 100644 index 000000000000..924f459d065e Binary files /dev/null and b/icons/clothing/mask/gas_mask_sexyclown.dmi differ diff --git a/icons/clothing/mask/gas_mask_sexymime.dmi b/icons/clothing/mask/gas_mask_sexymime.dmi new file mode 100644 index 000000000000..3875944b48fa Binary files /dev/null and b/icons/clothing/mask/gas_mask_sexymime.dmi differ diff --git a/icons/clothing/mask/gas_mask_swat.dmi b/icons/clothing/mask/gas_mask_swat.dmi new file mode 100644 index 000000000000..69c0b6668fb8 Binary files /dev/null and b/icons/clothing/mask/gas_mask_swat.dmi differ diff --git a/icons/clothing/mask/horsehead.dmi b/icons/clothing/mask/horsehead.dmi new file mode 100644 index 000000000000..54ade7e489e8 Binary files /dev/null and b/icons/clothing/mask/horsehead.dmi differ diff --git a/icons/clothing/mask/human.dmi b/icons/clothing/mask/human.dmi new file mode 100644 index 000000000000..b541dd7ac0ce Binary files /dev/null and b/icons/clothing/mask/human.dmi differ diff --git a/icons/clothing/mask/luchador.dmi b/icons/clothing/mask/luchador.dmi new file mode 100644 index 000000000000..1090eecd2591 Binary files /dev/null and b/icons/clothing/mask/luchador.dmi differ diff --git a/icons/clothing/mask/luchador_rudos.dmi b/icons/clothing/mask/luchador_rudos.dmi new file mode 100644 index 000000000000..3cbff905a345 Binary files /dev/null and b/icons/clothing/mask/luchador_rudos.dmi differ diff --git a/icons/clothing/mask/luchador_tecnicos.dmi b/icons/clothing/mask/luchador_tecnicos.dmi new file mode 100644 index 000000000000..621c56ba1c6a Binary files /dev/null and b/icons/clothing/mask/luchador_tecnicos.dmi differ diff --git a/icons/clothing/mask/monitor.dmi b/icons/clothing/mask/monitor.dmi new file mode 100644 index 000000000000..14d9e0c79783 Binary files /dev/null and b/icons/clothing/mask/monitor.dmi differ diff --git a/icons/clothing/mask/moustache.dmi b/icons/clothing/mask/moustache.dmi new file mode 100644 index 000000000000..e8dc71cf1588 Binary files /dev/null and b/icons/clothing/mask/moustache.dmi differ diff --git a/icons/clothing/mask/muzzle.dmi b/icons/clothing/mask/muzzle.dmi new file mode 100644 index 000000000000..fb57d9399832 Binary files /dev/null and b/icons/clothing/mask/muzzle.dmi differ diff --git a/icons/clothing/mask/muzzle_tape.dmi b/icons/clothing/mask/muzzle_tape.dmi new file mode 100644 index 000000000000..46f50fbc29eb Binary files /dev/null and b/icons/clothing/mask/muzzle_tape.dmi differ diff --git a/icons/clothing/mask/pig.dmi b/icons/clothing/mask/pig.dmi new file mode 100644 index 000000000000..e4aa97c39143 Binary files /dev/null and b/icons/clothing/mask/pig.dmi differ diff --git a/icons/clothing/mask/smokables/cigar.dmi b/icons/clothing/mask/smokables/cigar.dmi new file mode 100644 index 000000000000..8de1d9d48f37 Binary files /dev/null and b/icons/clothing/mask/smokables/cigar.dmi differ diff --git a/icons/clothing/mask/smokables/cigar_alt.dmi b/icons/clothing/mask/smokables/cigar_alt.dmi new file mode 100644 index 000000000000..433f2918b8a6 Binary files /dev/null and b/icons/clothing/mask/smokables/cigar_alt.dmi differ diff --git a/icons/clothing/mask/smokables/cigar_butt.dmi b/icons/clothing/mask/smokables/cigar_butt.dmi new file mode 100644 index 000000000000..b4c54fc3affa Binary files /dev/null and b/icons/clothing/mask/smokables/cigar_butt.dmi differ diff --git a/icons/clothing/mask/smokables/cigarello.dmi b/icons/clothing/mask/smokables/cigarello.dmi new file mode 100644 index 000000000000..4012e3de63bf Binary files /dev/null and b/icons/clothing/mask/smokables/cigarello.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette.dmi b/icons/clothing/mask/smokables/cigarette.dmi new file mode 100644 index 000000000000..7cdfc22999ce Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_butt.dmi b/icons/clothing/mask/smokables/cigarette_butt.dmi new file mode 100644 index 000000000000..f2237c667c27 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_butt.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_electronic.dmi b/icons/clothing/mask/smokables/cigarette_electronic.dmi new file mode 100644 index 000000000000..139255483b87 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_electronic.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_electronic_cheap.dmi b/icons/clothing/mask/smokables/cigarette_electronic_cheap.dmi new file mode 100644 index 000000000000..7a4f966fff22 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_electronic_cheap.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_electronic_deluxe.dmi b/icons/clothing/mask/smokables/cigarette_electronic_deluxe.dmi new file mode 100644 index 000000000000..e419b382ebde Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_electronic_deluxe.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_jericho.dmi b/icons/clothing/mask/smokables/cigarette_jericho.dmi new file mode 100644 index 000000000000..3189e1f636a0 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_jericho.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_jericho_butt.dmi b/icons/clothing/mask/smokables/cigarette_jericho_butt.dmi new file mode 100644 index 000000000000..6b5c153d4331 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_jericho_butt.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_menthol.dmi b/icons/clothing/mask/smokables/cigarette_menthol.dmi new file mode 100644 index 000000000000..5b9065b22300 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_menthol.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_menthol_butt.dmi b/icons/clothing/mask/smokables/cigarette_menthol_butt.dmi new file mode 100644 index 000000000000..f7d71681515e Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_menthol_butt.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_professional.dmi b/icons/clothing/mask/smokables/cigarette_professional.dmi new file mode 100644 index 000000000000..487d6b50c113 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_professional.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_professional_butt.dmi b/icons/clothing/mask/smokables/cigarette_professional_butt.dmi new file mode 100644 index 000000000000..3fd112b39c01 Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_professional_butt.dmi differ diff --git a/icons/clothing/mask/smokables/cigarette_rollup.dmi b/icons/clothing/mask/smokables/cigarette_rollup.dmi new file mode 100644 index 000000000000..1bf49a4c915d Binary files /dev/null and b/icons/clothing/mask/smokables/cigarette_rollup.dmi differ diff --git a/icons/clothing/mask/smokables/pipe.dmi b/icons/clothing/mask/smokables/pipe.dmi new file mode 100644 index 000000000000..e296e10dfc92 Binary files /dev/null and b/icons/clothing/mask/smokables/pipe.dmi differ diff --git a/icons/clothing/mask/smokables/pipe_cob.dmi b/icons/clothing/mask/smokables/pipe_cob.dmi new file mode 100644 index 000000000000..2b68cbcfd129 Binary files /dev/null and b/icons/clothing/mask/smokables/pipe_cob.dmi differ diff --git a/icons/clothing/mask/smokables/sausage.dmi b/icons/clothing/mask/smokables/sausage.dmi new file mode 100644 index 000000000000..797ffaf7d168 Binary files /dev/null and b/icons/clothing/mask/smokables/sausage.dmi differ diff --git a/icons/clothing/mask/snorkel.dmi b/icons/clothing/mask/snorkel.dmi new file mode 100644 index 000000000000..55cdde2e8f58 Binary files /dev/null and b/icons/clothing/mask/snorkel.dmi differ diff --git a/icons/clothing/mask/spirit.dmi b/icons/clothing/mask/spirit.dmi new file mode 100644 index 000000000000..fe1309440e80 Binary files /dev/null and b/icons/clothing/mask/spirit.dmi differ diff --git a/icons/clothing/mask/sterile.dmi b/icons/clothing/mask/sterile.dmi new file mode 100644 index 000000000000..fc59feb87392 Binary files /dev/null and b/icons/clothing/mask/sterile.dmi differ diff --git a/icons/clothing/mask/swat_mask.dmi b/icons/clothing/mask/swat_mask.dmi new file mode 100644 index 000000000000..79ecfd0adeea Binary files /dev/null and b/icons/clothing/mask/swat_mask.dmi differ diff --git a/icons/clothing/pants/leggings/leggings_champion.dmi b/icons/clothing/pants/leggings/leggings_champion.dmi new file mode 100644 index 000000000000..e8a99506d77b Binary files /dev/null and b/icons/clothing/pants/leggings/leggings_champion.dmi differ diff --git a/icons/clothing/pants/leggings/leggings_familiar.dmi b/icons/clothing/pants/leggings/leggings_familiar.dmi new file mode 100644 index 000000000000..e8dfc274c311 Binary files /dev/null and b/icons/clothing/pants/leggings/leggings_familiar.dmi differ diff --git a/icons/clothing/pants/mankini.dmi b/icons/clothing/pants/mankini.dmi new file mode 100644 index 000000000000..dfd738009cac Binary files /dev/null and b/icons/clothing/pants/mankini.dmi differ diff --git a/icons/clothing/pants/overpants.dmi b/icons/clothing/pants/overpants.dmi new file mode 100644 index 000000000000..16d0bd61e32a Binary files /dev/null and b/icons/clothing/pants/overpants.dmi differ diff --git a/icons/clothing/pants/pants.dmi b/icons/clothing/pants/pants.dmi new file mode 100644 index 000000000000..7ed3a7fb6ecd Binary files /dev/null and b/icons/clothing/pants/pants.dmi differ diff --git a/icons/clothing/pants/pants_baggy.dmi b/icons/clothing/pants/pants_baggy.dmi new file mode 100644 index 000000000000..ab32e520ad50 Binary files /dev/null and b/icons/clothing/pants/pants_baggy.dmi differ diff --git a/icons/clothing/pants/pants_camo.dmi b/icons/clothing/pants/pants_camo.dmi new file mode 100644 index 000000000000..1245020fadd9 Binary files /dev/null and b/icons/clothing/pants/pants_camo.dmi differ diff --git a/icons/clothing/pants/pants_camo_baggy.dmi b/icons/clothing/pants/pants_camo_baggy.dmi new file mode 100644 index 000000000000..6c2f6f987bcc Binary files /dev/null and b/icons/clothing/pants/pants_camo_baggy.dmi differ diff --git a/icons/clothing/pants/pants_jeans.dmi b/icons/clothing/pants/pants_jeans.dmi new file mode 100644 index 000000000000..e710367ef391 Binary files /dev/null and b/icons/clothing/pants/pants_jeans.dmi differ diff --git a/icons/clothing/pants/pants_jeans_baggy.dmi b/icons/clothing/pants/pants_jeans_baggy.dmi new file mode 100644 index 000000000000..04c3c66a656a Binary files /dev/null and b/icons/clothing/pants/pants_jeans_baggy.dmi differ diff --git a/icons/clothing/pants/pants_jeans_baggy_black.dmi b/icons/clothing/pants/pants_jeans_baggy_black.dmi new file mode 100644 index 000000000000..02400d163a7b Binary files /dev/null and b/icons/clothing/pants/pants_jeans_baggy_black.dmi differ diff --git a/icons/clothing/pants/pants_jeans_baggy_classic.dmi b/icons/clothing/pants/pants_jeans_baggy_classic.dmi new file mode 100644 index 000000000000..fe64090ab090 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_baggy_classic.dmi differ diff --git a/icons/clothing/pants/pants_jeans_baggy_grey.dmi b/icons/clothing/pants/pants_jeans_baggy_grey.dmi new file mode 100644 index 000000000000..6c00bd96fc2c Binary files /dev/null and b/icons/clothing/pants/pants_jeans_baggy_grey.dmi differ diff --git a/icons/clothing/pants/pants_jeans_baggy_mustang.dmi b/icons/clothing/pants/pants_jeans_baggy_mustang.dmi new file mode 100644 index 000000000000..f7221ea87658 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_baggy_mustang.dmi differ diff --git a/icons/clothing/pants/pants_jeans_baggy_young.dmi b/icons/clothing/pants/pants_jeans_baggy_young.dmi new file mode 100644 index 000000000000..c788f98cd049 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_baggy_young.dmi differ diff --git a/icons/clothing/pants/pants_jeans_black.dmi b/icons/clothing/pants/pants_jeans_black.dmi new file mode 100644 index 000000000000..40dfb08c1773 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_black.dmi differ diff --git a/icons/clothing/pants/pants_jeans_classic.dmi b/icons/clothing/pants/pants_jeans_classic.dmi new file mode 100644 index 000000000000..1d923cc99138 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_classic.dmi differ diff --git a/icons/clothing/pants/pants_jeans_grey.dmi b/icons/clothing/pants/pants_jeans_grey.dmi new file mode 100644 index 000000000000..7d50b4c20481 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_grey.dmi differ diff --git a/icons/clothing/pants/pants_jeans_mustang.dmi b/icons/clothing/pants/pants_jeans_mustang.dmi new file mode 100644 index 000000000000..7c987c423237 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_mustang.dmi differ diff --git a/icons/clothing/pants/pants_jeans_shorts.dmi b/icons/clothing/pants/pants_jeans_shorts.dmi new file mode 100644 index 000000000000..3c56f1f817d8 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_shorts.dmi differ diff --git a/icons/clothing/pants/pants_jeans_shorts_classic.dmi b/icons/clothing/pants/pants_jeans_shorts_classic.dmi new file mode 100644 index 000000000000..f0be1c6e41c3 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_shorts_classic.dmi differ diff --git a/icons/clothing/pants/pants_jeans_shorts_mustang.dmi b/icons/clothing/pants/pants_jeans_shorts_mustang.dmi new file mode 100644 index 000000000000..c412aed07144 Binary files /dev/null and b/icons/clothing/pants/pants_jeans_shorts_mustang.dmi differ diff --git a/icons/clothing/pants/pants_jeans_shorts_young.dmi b/icons/clothing/pants/pants_jeans_shorts_young.dmi new file mode 100644 index 000000000000..1e93f457538e Binary files /dev/null and b/icons/clothing/pants/pants_jeans_shorts_young.dmi differ diff --git a/icons/clothing/pants/pants_jeans_young.dmi b/icons/clothing/pants/pants_jeans_young.dmi new file mode 100644 index 000000000000..39595db9258f Binary files /dev/null and b/icons/clothing/pants/pants_jeans_young.dmi differ diff --git a/icons/clothing/pants/pants_mustard.dmi b/icons/clothing/pants/pants_mustard.dmi new file mode 100644 index 000000000000..9d8887224271 Binary files /dev/null and b/icons/clothing/pants/pants_mustard.dmi differ diff --git a/icons/clothing/pants/pants_shorts.dmi b/icons/clothing/pants/pants_shorts.dmi new file mode 100644 index 000000000000..f608a0979ba8 Binary files /dev/null and b/icons/clothing/pants/pants_shorts.dmi differ diff --git a/icons/clothing/pants/pants_shorts_black.dmi b/icons/clothing/pants/pants_shorts_black.dmi new file mode 100644 index 000000000000..e32cf9483a0c Binary files /dev/null and b/icons/clothing/pants/pants_shorts_black.dmi differ diff --git a/icons/clothing/pants/pants_shorts_grey.dmi b/icons/clothing/pants/pants_shorts_grey.dmi new file mode 100644 index 000000000000..37b6b7bcd11c Binary files /dev/null and b/icons/clothing/pants/pants_shorts_grey.dmi differ diff --git a/icons/clothing/pants/pants_shorts_khaki.dmi b/icons/clothing/pants/pants_shorts_khaki.dmi new file mode 100644 index 000000000000..9733a7b61dd3 Binary files /dev/null and b/icons/clothing/pants/pants_shorts_khaki.dmi differ diff --git a/icons/clothing/pants/pants_shorts_tan.dmi b/icons/clothing/pants/pants_shorts_tan.dmi new file mode 100644 index 000000000000..551f30a54c1d Binary files /dev/null and b/icons/clothing/pants/pants_shorts_tan.dmi differ diff --git a/icons/clothing/pants/pants_track.dmi b/icons/clothing/pants/pants_track.dmi new file mode 100644 index 000000000000..b07227cec2d3 Binary files /dev/null and b/icons/clothing/pants/pants_track.dmi differ diff --git a/icons/clothing/pants/pants_track_black.dmi b/icons/clothing/pants/pants_track_black.dmi new file mode 100644 index 000000000000..b4afdad2e5cb Binary files /dev/null and b/icons/clothing/pants/pants_track_black.dmi differ diff --git a/icons/clothing/pants/pants_track_blue.dmi b/icons/clothing/pants/pants_track_blue.dmi new file mode 100644 index 000000000000..2e5f4df7d3b8 Binary files /dev/null and b/icons/clothing/pants/pants_track_blue.dmi differ diff --git a/icons/clothing/pants/pants_track_navy.dmi b/icons/clothing/pants/pants_track_navy.dmi new file mode 100644 index 000000000000..3a98ad267ead Binary files /dev/null and b/icons/clothing/pants/pants_track_navy.dmi differ diff --git a/icons/clothing/pants/pants_track_red.dmi b/icons/clothing/pants/pants_track_red.dmi new file mode 100644 index 000000000000..06132210be6d Binary files /dev/null and b/icons/clothing/pants/pants_track_red.dmi differ diff --git a/icons/clothing/pants/pjs_blue.dmi b/icons/clothing/pants/pjs_blue.dmi new file mode 100644 index 000000000000..ee69a9385480 Binary files /dev/null and b/icons/clothing/pants/pjs_blue.dmi differ diff --git a/icons/clothing/pants/pjs_red.dmi b/icons/clothing/pants/pjs_red.dmi new file mode 100644 index 000000000000..ae11352d5adc Binary files /dev/null and b/icons/clothing/pants/pjs_red.dmi differ diff --git a/icons/clothing/pants/scrubs.dmi b/icons/clothing/pants/scrubs.dmi new file mode 100644 index 000000000000..fe312c6668d9 Binary files /dev/null and b/icons/clothing/pants/scrubs.dmi differ diff --git a/icons/clothing/pants/security.dmi b/icons/clothing/pants/security.dmi new file mode 100644 index 000000000000..98c5eb43182a Binary files /dev/null and b/icons/clothing/pants/security.dmi differ diff --git a/icons/clothing/pants/slacks.dmi b/icons/clothing/pants/slacks.dmi new file mode 100644 index 000000000000..f53e77363847 Binary files /dev/null and b/icons/clothing/pants/slacks.dmi differ diff --git a/icons/clothing/pants/slacks_black.dmi b/icons/clothing/pants/slacks_black.dmi new file mode 100644 index 000000000000..f7bd40cabfab Binary files /dev/null and b/icons/clothing/pants/slacks_black.dmi differ diff --git a/icons/clothing/pants/slacks_blue.dmi b/icons/clothing/pants/slacks_blue.dmi new file mode 100644 index 000000000000..05f1edf3623f Binary files /dev/null and b/icons/clothing/pants/slacks_blue.dmi differ diff --git a/icons/clothing/pants/slacks_navy.dmi b/icons/clothing/pants/slacks_navy.dmi new file mode 100644 index 000000000000..76d5d417d14a Binary files /dev/null and b/icons/clothing/pants/slacks_navy.dmi differ diff --git a/icons/clothing/pants/slacks_purple.dmi b/icons/clothing/pants/slacks_purple.dmi new file mode 100644 index 000000000000..b70d286970ec Binary files /dev/null and b/icons/clothing/pants/slacks_purple.dmi differ diff --git a/icons/clothing/pants/slacks_red.dmi b/icons/clothing/pants/slacks_red.dmi new file mode 100644 index 000000000000..efe4e8d6f464 Binary files /dev/null and b/icons/clothing/pants/slacks_red.dmi differ diff --git a/icons/clothing/pants/slacks_tan.dmi b/icons/clothing/pants/slacks_tan.dmi new file mode 100644 index 000000000000..af53bdbc82bf Binary files /dev/null and b/icons/clothing/pants/slacks_tan.dmi differ diff --git a/icons/clothing/pants/slacks_white.dmi b/icons/clothing/pants/slacks_white.dmi new file mode 100644 index 000000000000..dae8898b6a1c Binary files /dev/null and b/icons/clothing/pants/slacks_white.dmi differ diff --git a/icons/clothing/plate_armour/helm.dmi b/icons/clothing/plate_armour/helm.dmi new file mode 100644 index 000000000000..1201d3348960 Binary files /dev/null and b/icons/clothing/plate_armour/helm.dmi differ diff --git a/icons/clothing/plate_armour/platemail.dmi b/icons/clothing/plate_armour/platemail.dmi new file mode 100644 index 000000000000..2326627495e6 Binary files /dev/null and b/icons/clothing/plate_armour/platemail.dmi differ diff --git a/icons/clothing/plate_armour/sabatons.dmi b/icons/clothing/plate_armour/sabatons.dmi new file mode 100644 index 000000000000..71b947d30bcf Binary files /dev/null and b/icons/clothing/plate_armour/sabatons.dmi differ diff --git a/icons/clothing/plate_armour/vambrace.dmi b/icons/clothing/plate_armour/vambrace.dmi new file mode 100644 index 000000000000..fde91c5c6764 Binary files /dev/null and b/icons/clothing/plate_armour/vambrace.dmi differ diff --git a/icons/clothing/rigs/boots/boots.dmi b/icons/clothing/rigs/boots/boots.dmi new file mode 100644 index 000000000000..f0898a2e62ae Binary files /dev/null and b/icons/clothing/rigs/boots/boots.dmi differ diff --git a/icons/clothing/rigs/boots/boots_engineering.dmi b/icons/clothing/rigs/boots/boots_engineering.dmi new file mode 100644 index 000000000000..33781b0b141e Binary files /dev/null and b/icons/clothing/rigs/boots/boots_engineering.dmi differ diff --git a/icons/clothing/rigs/boots/boots_eva.dmi b/icons/clothing/rigs/boots/boots_eva.dmi new file mode 100644 index 000000000000..0843f405e12e Binary files /dev/null and b/icons/clothing/rigs/boots/boots_eva.dmi differ diff --git a/icons/clothing/rigs/boots/boots_hacker.dmi b/icons/clothing/rigs/boots/boots_hacker.dmi new file mode 100644 index 000000000000..2f442a4f837f Binary files /dev/null and b/icons/clothing/rigs/boots/boots_hacker.dmi differ diff --git a/icons/clothing/rigs/boots/boots_hazard.dmi b/icons/clothing/rigs/boots/boots_hazard.dmi new file mode 100644 index 000000000000..f3a38a2f7899 Binary files /dev/null and b/icons/clothing/rigs/boots/boots_hazard.dmi differ diff --git a/icons/clothing/rigs/boots/boots_light.dmi b/icons/clothing/rigs/boots/boots_light.dmi new file mode 100644 index 000000000000..d5e6877a4138 Binary files /dev/null and b/icons/clothing/rigs/boots/boots_light.dmi differ diff --git a/icons/clothing/rigs/boots/boots_medical.dmi b/icons/clothing/rigs/boots/boots_medical.dmi new file mode 100644 index 000000000000..44c16d2b17bc Binary files /dev/null and b/icons/clothing/rigs/boots/boots_medical.dmi differ diff --git a/icons/clothing/rigs/boots/boots_merc.dmi b/icons/clothing/rigs/boots/boots_merc.dmi new file mode 100644 index 000000000000..54fe94e37be7 Binary files /dev/null and b/icons/clothing/rigs/boots/boots_merc.dmi differ diff --git a/icons/clothing/rigs/boots/boots_merc_heavy.dmi b/icons/clothing/rigs/boots/boots_merc_heavy.dmi new file mode 100644 index 000000000000..8327d6dfabcc Binary files /dev/null and b/icons/clothing/rigs/boots/boots_merc_heavy.dmi differ diff --git a/icons/clothing/rigs/boots/boots_military.dmi b/icons/clothing/rigs/boots/boots_military.dmi new file mode 100644 index 000000000000..455ae1c4b93a Binary files /dev/null and b/icons/clothing/rigs/boots/boots_military.dmi differ diff --git a/icons/clothing/rigs/boots/boots_ninja.dmi b/icons/clothing/rigs/boots/boots_ninja.dmi new file mode 100644 index 000000000000..efef4eb3448b Binary files /dev/null and b/icons/clothing/rigs/boots/boots_ninja.dmi differ diff --git a/icons/clothing/rigs/boots/boots_science.dmi b/icons/clothing/rigs/boots/boots_science.dmi new file mode 100644 index 000000000000..3cd3009564ef Binary files /dev/null and b/icons/clothing/rigs/boots/boots_science.dmi differ diff --git a/icons/clothing/rigs/boots/boots_security.dmi b/icons/clothing/rigs/boots/boots_security.dmi new file mode 100644 index 000000000000..9ca1cfd2db46 Binary files /dev/null and b/icons/clothing/rigs/boots/boots_security.dmi differ diff --git a/icons/clothing/rigs/chests/chest.dmi b/icons/clothing/rigs/chests/chest.dmi new file mode 100644 index 000000000000..f1b046b5989f Binary files /dev/null and b/icons/clothing/rigs/chests/chest.dmi differ diff --git a/icons/clothing/rigs/chests/chest_engineering.dmi b/icons/clothing/rigs/chests/chest_engineering.dmi new file mode 100644 index 000000000000..40804285fc75 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_engineering.dmi differ diff --git a/icons/clothing/rigs/chests/chest_eva.dmi b/icons/clothing/rigs/chests/chest_eva.dmi new file mode 100644 index 000000000000..e93922a2910e Binary files /dev/null and b/icons/clothing/rigs/chests/chest_eva.dmi differ diff --git a/icons/clothing/rigs/chests/chest_hacker.dmi b/icons/clothing/rigs/chests/chest_hacker.dmi new file mode 100644 index 000000000000..cacd7e6293cd Binary files /dev/null and b/icons/clothing/rigs/chests/chest_hacker.dmi differ diff --git a/icons/clothing/rigs/chests/chest_hazard.dmi b/icons/clothing/rigs/chests/chest_hazard.dmi new file mode 100644 index 000000000000..b31925eb2599 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_hazard.dmi differ diff --git a/icons/clothing/rigs/chests/chest_light.dmi b/icons/clothing/rigs/chests/chest_light.dmi new file mode 100644 index 000000000000..3fe11c167597 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_light.dmi differ diff --git a/icons/clothing/rigs/chests/chest_medical.dmi b/icons/clothing/rigs/chests/chest_medical.dmi new file mode 100644 index 000000000000..83c09e4717bf Binary files /dev/null and b/icons/clothing/rigs/chests/chest_medical.dmi differ diff --git a/icons/clothing/rigs/chests/chest_merc.dmi b/icons/clothing/rigs/chests/chest_merc.dmi new file mode 100644 index 000000000000..fc98afd7e7dc Binary files /dev/null and b/icons/clothing/rigs/chests/chest_merc.dmi differ diff --git a/icons/clothing/rigs/chests/chest_merc_heavy.dmi b/icons/clothing/rigs/chests/chest_merc_heavy.dmi new file mode 100644 index 000000000000..ca66a810c4d1 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_merc_heavy.dmi differ diff --git a/icons/clothing/rigs/chests/chest_military.dmi b/icons/clothing/rigs/chests/chest_military.dmi new file mode 100644 index 000000000000..5aa2fc49f123 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_military.dmi differ diff --git a/icons/clothing/rigs/chests/chest_ninja.dmi b/icons/clothing/rigs/chests/chest_ninja.dmi new file mode 100644 index 000000000000..85cc82b5ea17 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_ninja.dmi differ diff --git a/icons/clothing/rigs/chests/chest_null.dmi b/icons/clothing/rigs/chests/chest_null.dmi new file mode 100644 index 000000000000..2d6470e5e570 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_null.dmi differ diff --git a/icons/clothing/rigs/chests/chest_paperwork.dmi b/icons/clothing/rigs/chests/chest_paperwork.dmi new file mode 100644 index 000000000000..042b2e47fa0d Binary files /dev/null and b/icons/clothing/rigs/chests/chest_paperwork.dmi differ diff --git a/icons/clothing/rigs/chests/chest_science.dmi b/icons/clothing/rigs/chests/chest_science.dmi new file mode 100644 index 000000000000..233e9f660712 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_science.dmi differ diff --git a/icons/clothing/rigs/chests/chest_security.dmi b/icons/clothing/rigs/chests/chest_security.dmi new file mode 100644 index 000000000000..52dd56089a52 Binary files /dev/null and b/icons/clothing/rigs/chests/chest_security.dmi differ diff --git a/icons/clothing/rigs/ert/asset_protection/boots.dmi b/icons/clothing/rigs/ert/asset_protection/boots.dmi new file mode 100644 index 000000000000..a55b0ac19ddc Binary files /dev/null and b/icons/clothing/rigs/ert/asset_protection/boots.dmi differ diff --git a/icons/clothing/rigs/ert/asset_protection/chest.dmi b/icons/clothing/rigs/ert/asset_protection/chest.dmi new file mode 100644 index 000000000000..860ad557c4ce Binary files /dev/null and b/icons/clothing/rigs/ert/asset_protection/chest.dmi differ diff --git a/icons/clothing/rigs/ert/asset_protection/gloves.dmi b/icons/clothing/rigs/ert/asset_protection/gloves.dmi new file mode 100644 index 000000000000..71750fb77add Binary files /dev/null and b/icons/clothing/rigs/ert/asset_protection/gloves.dmi differ diff --git a/icons/clothing/rigs/ert/asset_protection/helmet.dmi b/icons/clothing/rigs/ert/asset_protection/helmet.dmi new file mode 100644 index 000000000000..e312d83b55bd Binary files /dev/null and b/icons/clothing/rigs/ert/asset_protection/helmet.dmi differ diff --git a/icons/clothing/rigs/ert/asset_protection/rig.dmi b/icons/clothing/rigs/ert/asset_protection/rig.dmi new file mode 100644 index 000000000000..2f2cb89d7fcb Binary files /dev/null and b/icons/clothing/rigs/ert/asset_protection/rig.dmi differ diff --git a/icons/clothing/rigs/ert/commander/boots.dmi b/icons/clothing/rigs/ert/commander/boots.dmi new file mode 100644 index 000000000000..09420d6de81f Binary files /dev/null and b/icons/clothing/rigs/ert/commander/boots.dmi differ diff --git a/icons/clothing/rigs/ert/commander/chest.dmi b/icons/clothing/rigs/ert/commander/chest.dmi new file mode 100644 index 000000000000..69575bec1f0b Binary files /dev/null and b/icons/clothing/rigs/ert/commander/chest.dmi differ diff --git a/icons/clothing/rigs/ert/commander/gloves.dmi b/icons/clothing/rigs/ert/commander/gloves.dmi new file mode 100644 index 000000000000..de45b5bb85f9 Binary files /dev/null and b/icons/clothing/rigs/ert/commander/gloves.dmi differ diff --git a/icons/clothing/rigs/ert/commander/helmet.dmi b/icons/clothing/rigs/ert/commander/helmet.dmi new file mode 100644 index 000000000000..896195fe1a88 Binary files /dev/null and b/icons/clothing/rigs/ert/commander/helmet.dmi differ diff --git a/icons/clothing/rigs/ert/commander/rig.dmi b/icons/clothing/rigs/ert/commander/rig.dmi new file mode 100644 index 000000000000..ec368a2e4d79 Binary files /dev/null and b/icons/clothing/rigs/ert/commander/rig.dmi differ diff --git a/icons/clothing/rigs/ert/engineer/boots.dmi b/icons/clothing/rigs/ert/engineer/boots.dmi new file mode 100644 index 000000000000..70ec949637b6 Binary files /dev/null and b/icons/clothing/rigs/ert/engineer/boots.dmi differ diff --git a/icons/clothing/rigs/ert/engineer/chest.dmi b/icons/clothing/rigs/ert/engineer/chest.dmi new file mode 100644 index 000000000000..442a7dbf6421 Binary files /dev/null and b/icons/clothing/rigs/ert/engineer/chest.dmi differ diff --git a/icons/clothing/rigs/ert/engineer/gloves.dmi b/icons/clothing/rigs/ert/engineer/gloves.dmi new file mode 100644 index 000000000000..e9bd3c700e2f Binary files /dev/null and b/icons/clothing/rigs/ert/engineer/gloves.dmi differ diff --git a/icons/clothing/rigs/ert/engineer/helmet.dmi b/icons/clothing/rigs/ert/engineer/helmet.dmi new file mode 100644 index 000000000000..0c63f505f2f8 Binary files /dev/null and b/icons/clothing/rigs/ert/engineer/helmet.dmi differ diff --git a/icons/clothing/rigs/ert/engineer/rig.dmi b/icons/clothing/rigs/ert/engineer/rig.dmi new file mode 100644 index 000000000000..38eb39d5e1e2 Binary files /dev/null and b/icons/clothing/rigs/ert/engineer/rig.dmi differ diff --git a/icons/clothing/rigs/ert/janitor/boots.dmi b/icons/clothing/rigs/ert/janitor/boots.dmi new file mode 100644 index 000000000000..3178cdae6dbc Binary files /dev/null and b/icons/clothing/rigs/ert/janitor/boots.dmi differ diff --git a/icons/clothing/rigs/ert/janitor/chest.dmi b/icons/clothing/rigs/ert/janitor/chest.dmi new file mode 100644 index 000000000000..e2deee841328 Binary files /dev/null and b/icons/clothing/rigs/ert/janitor/chest.dmi differ diff --git a/icons/clothing/rigs/ert/janitor/gloves.dmi b/icons/clothing/rigs/ert/janitor/gloves.dmi new file mode 100644 index 000000000000..a43e1a91ef09 Binary files /dev/null and b/icons/clothing/rigs/ert/janitor/gloves.dmi differ diff --git a/icons/clothing/rigs/ert/janitor/helmet.dmi b/icons/clothing/rigs/ert/janitor/helmet.dmi new file mode 100644 index 000000000000..1f3b3bdc7a6e Binary files /dev/null and b/icons/clothing/rigs/ert/janitor/helmet.dmi differ diff --git a/icons/clothing/rigs/ert/janitor/rig.dmi b/icons/clothing/rigs/ert/janitor/rig.dmi new file mode 100644 index 000000000000..4f3d2f87d3f2 Binary files /dev/null and b/icons/clothing/rigs/ert/janitor/rig.dmi differ diff --git a/icons/clothing/rigs/ert/medic/boots.dmi b/icons/clothing/rigs/ert/medic/boots.dmi new file mode 100644 index 000000000000..fe86d4a5bcf5 Binary files /dev/null and b/icons/clothing/rigs/ert/medic/boots.dmi differ diff --git a/icons/clothing/rigs/ert/medic/chest.dmi b/icons/clothing/rigs/ert/medic/chest.dmi new file mode 100644 index 000000000000..84ac0b34eb9a Binary files /dev/null and b/icons/clothing/rigs/ert/medic/chest.dmi differ diff --git a/icons/clothing/rigs/ert/medic/gloves.dmi b/icons/clothing/rigs/ert/medic/gloves.dmi new file mode 100644 index 000000000000..9d019bd929e9 Binary files /dev/null and b/icons/clothing/rigs/ert/medic/gloves.dmi differ diff --git a/icons/clothing/rigs/ert/medic/helmet.dmi b/icons/clothing/rigs/ert/medic/helmet.dmi new file mode 100644 index 000000000000..9d3aa70b3cf6 Binary files /dev/null and b/icons/clothing/rigs/ert/medic/helmet.dmi differ diff --git a/icons/clothing/rigs/ert/medic/rig.dmi b/icons/clothing/rigs/ert/medic/rig.dmi new file mode 100644 index 000000000000..332b83a5e90a Binary files /dev/null and b/icons/clothing/rigs/ert/medic/rig.dmi differ diff --git a/icons/clothing/rigs/ert/security/boots.dmi b/icons/clothing/rigs/ert/security/boots.dmi new file mode 100644 index 000000000000..d3c28ce98ebd Binary files /dev/null and b/icons/clothing/rigs/ert/security/boots.dmi differ diff --git a/icons/clothing/rigs/ert/security/chest.dmi b/icons/clothing/rigs/ert/security/chest.dmi new file mode 100644 index 000000000000..bc2f467d817f Binary files /dev/null and b/icons/clothing/rigs/ert/security/chest.dmi differ diff --git a/icons/clothing/rigs/ert/security/gloves.dmi b/icons/clothing/rigs/ert/security/gloves.dmi new file mode 100644 index 000000000000..51e92c19e4b5 Binary files /dev/null and b/icons/clothing/rigs/ert/security/gloves.dmi differ diff --git a/icons/clothing/rigs/ert/security/helmet.dmi b/icons/clothing/rigs/ert/security/helmet.dmi new file mode 100644 index 000000000000..df061882fbf0 Binary files /dev/null and b/icons/clothing/rigs/ert/security/helmet.dmi differ diff --git a/icons/clothing/rigs/ert/security/rig.dmi b/icons/clothing/rigs/ert/security/rig.dmi new file mode 100644 index 000000000000..b7e9cc3cb4db Binary files /dev/null and b/icons/clothing/rigs/ert/security/rig.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves.dmi b/icons/clothing/rigs/gloves/gloves.dmi new file mode 100644 index 000000000000..fdbf39597247 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_engineering.dmi b/icons/clothing/rigs/gloves/gloves_engineering.dmi new file mode 100644 index 000000000000..2c447aeb94fa Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_engineering.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_eva.dmi b/icons/clothing/rigs/gloves/gloves_eva.dmi new file mode 100644 index 000000000000..527360046b5f Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_eva.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_hacker.dmi b/icons/clothing/rigs/gloves/gloves_hacker.dmi new file mode 100644 index 000000000000..67eb04e90515 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_hacker.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_hazard.dmi b/icons/clothing/rigs/gloves/gloves_hazard.dmi new file mode 100644 index 000000000000..3925282f10ea Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_hazard.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_light.dmi b/icons/clothing/rigs/gloves/gloves_light.dmi new file mode 100644 index 000000000000..d2fd688193b6 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_light.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_medical.dmi b/icons/clothing/rigs/gloves/gloves_medical.dmi new file mode 100644 index 000000000000..8b9448a5b715 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_medical.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_merc.dmi b/icons/clothing/rigs/gloves/gloves_merc.dmi new file mode 100644 index 000000000000..5049e68fc9b3 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_merc.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_merc_heavy.dmi b/icons/clothing/rigs/gloves/gloves_merc_heavy.dmi new file mode 100644 index 000000000000..22bea936b4aa Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_merc_heavy.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_military.dmi b/icons/clothing/rigs/gloves/gloves_military.dmi new file mode 100644 index 000000000000..727e3d1111ad Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_military.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_ninja.dmi b/icons/clothing/rigs/gloves/gloves_ninja.dmi new file mode 100644 index 000000000000..b7b10ae1f717 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_ninja.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_science.dmi b/icons/clothing/rigs/gloves/gloves_science.dmi new file mode 100644 index 000000000000..b0286aea49c3 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_science.dmi differ diff --git a/icons/clothing/rigs/gloves/gloves_security.dmi b/icons/clothing/rigs/gloves/gloves_security.dmi new file mode 100644 index 000000000000..bbe0e6c636b6 Binary files /dev/null and b/icons/clothing/rigs/gloves/gloves_security.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet.dmi b/icons/clothing/rigs/helmets/helmet.dmi new file mode 100644 index 000000000000..14285e33acfa Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_engineering.dmi b/icons/clothing/rigs/helmets/helmet_engineering.dmi new file mode 100644 index 000000000000..7e29a7f6a6d6 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_engineering.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_eva.dmi b/icons/clothing/rigs/helmets/helmet_eva.dmi new file mode 100644 index 000000000000..f121efa04758 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_eva.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_hacker.dmi b/icons/clothing/rigs/helmets/helmet_hacker.dmi new file mode 100644 index 000000000000..7a2816425979 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_hacker.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_hazard.dmi b/icons/clothing/rigs/helmets/helmet_hazard.dmi new file mode 100644 index 000000000000..1d43df8e1edb Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_hazard.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_light.dmi b/icons/clothing/rigs/helmets/helmet_light.dmi new file mode 100644 index 000000000000..bf6d09979b8d Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_light.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_medical.dmi b/icons/clothing/rigs/helmets/helmet_medical.dmi new file mode 100644 index 000000000000..be2e63201bdd Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_medical.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_merc.dmi b/icons/clothing/rigs/helmets/helmet_merc.dmi new file mode 100644 index 000000000000..ca3c374bfbef Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_merc.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_merc_heavy.dmi b/icons/clothing/rigs/helmets/helmet_merc_heavy.dmi new file mode 100644 index 000000000000..ce785a1ffeb4 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_merc_heavy.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_military.dmi b/icons/clothing/rigs/helmets/helmet_military.dmi new file mode 100644 index 000000000000..47087a31ca34 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_military.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_ninja.dmi b/icons/clothing/rigs/helmets/helmet_ninja.dmi new file mode 100644 index 000000000000..7ca2eb422278 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_ninja.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_null.dmi b/icons/clothing/rigs/helmets/helmet_null.dmi new file mode 100644 index 000000000000..ceb0366983cd Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_null.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_science.dmi b/icons/clothing/rigs/helmets/helmet_science.dmi new file mode 100644 index 000000000000..269036f04388 Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_science.dmi differ diff --git a/icons/clothing/rigs/helmets/helmet_security.dmi b/icons/clothing/rigs/helmets/helmet_security.dmi new file mode 100644 index 000000000000..d121e4748faf Binary files /dev/null and b/icons/clothing/rigs/helmets/helmet_security.dmi differ diff --git a/icons/clothing/rigs/rig.dmi b/icons/clothing/rigs/rig.dmi new file mode 100644 index 000000000000..3bec823e0933 Binary files /dev/null and b/icons/clothing/rigs/rig.dmi differ diff --git a/icons/clothing/rigs/rig_engineering.dmi b/icons/clothing/rigs/rig_engineering.dmi new file mode 100644 index 000000000000..256277ffd238 Binary files /dev/null and b/icons/clothing/rigs/rig_engineering.dmi differ diff --git a/icons/clothing/rigs/rig_eva.dmi b/icons/clothing/rigs/rig_eva.dmi new file mode 100644 index 000000000000..b61a35611ebc Binary files /dev/null and b/icons/clothing/rigs/rig_eva.dmi differ diff --git a/icons/clothing/rigs/rig_hacker.dmi b/icons/clothing/rigs/rig_hacker.dmi new file mode 100644 index 000000000000..ff4039a1a693 Binary files /dev/null and b/icons/clothing/rigs/rig_hacker.dmi differ diff --git a/icons/clothing/rigs/rig_hazard.dmi b/icons/clothing/rigs/rig_hazard.dmi new file mode 100644 index 000000000000..5a8bcc48b684 Binary files /dev/null and b/icons/clothing/rigs/rig_hazard.dmi differ diff --git a/icons/clothing/rigs/rig_light.dmi b/icons/clothing/rigs/rig_light.dmi new file mode 100644 index 000000000000..7d2e5e81ff10 Binary files /dev/null and b/icons/clothing/rigs/rig_light.dmi differ diff --git a/icons/clothing/rigs/rig_medical.dmi b/icons/clothing/rigs/rig_medical.dmi new file mode 100644 index 000000000000..59a2dd5155e3 Binary files /dev/null and b/icons/clothing/rigs/rig_medical.dmi differ diff --git a/icons/clothing/rigs/rig_merc.dmi b/icons/clothing/rigs/rig_merc.dmi new file mode 100644 index 000000000000..f578f957bf98 Binary files /dev/null and b/icons/clothing/rigs/rig_merc.dmi differ diff --git a/icons/clothing/rigs/rig_merc_heavy.dmi b/icons/clothing/rigs/rig_merc_heavy.dmi new file mode 100644 index 000000000000..60f7e45f1379 Binary files /dev/null and b/icons/clothing/rigs/rig_merc_heavy.dmi differ diff --git a/icons/clothing/rigs/rig_military.dmi b/icons/clothing/rigs/rig_military.dmi new file mode 100644 index 000000000000..65befd77d57b Binary files /dev/null and b/icons/clothing/rigs/rig_military.dmi differ diff --git a/icons/clothing/rigs/rig_ninja.dmi b/icons/clothing/rigs/rig_ninja.dmi new file mode 100644 index 000000000000..7d2e5e81ff10 Binary files /dev/null and b/icons/clothing/rigs/rig_ninja.dmi differ diff --git a/icons/clothing/rigs/rig_null.dmi b/icons/clothing/rigs/rig_null.dmi new file mode 100644 index 000000000000..0b58c3bed57c Binary files /dev/null and b/icons/clothing/rigs/rig_null.dmi differ diff --git a/icons/clothing/rigs/rig_paperwork.dmi b/icons/clothing/rigs/rig_paperwork.dmi new file mode 100644 index 000000000000..417e63cb1a7e Binary files /dev/null and b/icons/clothing/rigs/rig_paperwork.dmi differ diff --git a/icons/clothing/rigs/rig_science.dmi b/icons/clothing/rigs/rig_science.dmi new file mode 100644 index 000000000000..8f377e5074fb Binary files /dev/null and b/icons/clothing/rigs/rig_science.dmi differ diff --git a/icons/clothing/rigs/rig_security.dmi b/icons/clothing/rigs/rig_security.dmi new file mode 100644 index 000000000000..a6a7e8731884 Binary files /dev/null and b/icons/clothing/rigs/rig_security.dmi differ diff --git a/icons/clothing/rogue_captain.dmi b/icons/clothing/rogue_captain.dmi new file mode 100644 index 000000000000..ba4eb7a70c8b Binary files /dev/null and b/icons/clothing/rogue_captain.dmi differ diff --git a/icons/clothing/shirts/blouse.dmi b/icons/clothing/shirts/blouse.dmi new file mode 100644 index 000000000000..dcabb3a8c446 Binary files /dev/null and b/icons/clothing/shirts/blouse.dmi differ diff --git a/icons/clothing/shirts/blouse_blue.dmi b/icons/clothing/shirts/blouse_blue.dmi new file mode 100644 index 000000000000..71e85bd6e526 Binary files /dev/null and b/icons/clothing/shirts/blouse_blue.dmi differ diff --git a/icons/clothing/shirts/blouse_purple.dmi b/icons/clothing/shirts/blouse_purple.dmi new file mode 100644 index 000000000000..397b01e2a29f Binary files /dev/null and b/icons/clothing/shirts/blouse_purple.dmi differ diff --git a/icons/clothing/shirts/blouse_red.dmi b/icons/clothing/shirts/blouse_red.dmi new file mode 100644 index 000000000000..3baab21942c5 Binary files /dev/null and b/icons/clothing/shirts/blouse_red.dmi differ diff --git a/icons/clothing/shirts/button_up.dmi b/icons/clothing/shirts/button_up.dmi new file mode 100644 index 000000000000..db7bc7634957 Binary files /dev/null and b/icons/clothing/shirts/button_up.dmi differ diff --git a/icons/clothing/shirts/button_up_blue.dmi b/icons/clothing/shirts/button_up_blue.dmi new file mode 100644 index 000000000000..f91345c666a0 Binary files /dev/null and b/icons/clothing/shirts/button_up_blue.dmi differ diff --git a/icons/clothing/shirts/button_up_tan.dmi b/icons/clothing/shirts/button_up_tan.dmi new file mode 100644 index 000000000000..299e24cf792b Binary files /dev/null and b/icons/clothing/shirts/button_up_tan.dmi differ diff --git a/icons/clothing/shirts/flannel.dmi b/icons/clothing/shirts/flannel.dmi new file mode 100644 index 000000000000..5cf615eacd5c Binary files /dev/null and b/icons/clothing/shirts/flannel.dmi differ diff --git a/icons/clothing/shirts/gambeson.dmi b/icons/clothing/shirts/gambeson.dmi new file mode 100644 index 000000000000..1ad491601108 Binary files /dev/null and b/icons/clothing/shirts/gambeson.dmi differ diff --git a/icons/clothing/shirts/harness.dmi b/icons/clothing/shirts/harness.dmi new file mode 100644 index 000000000000..b6d819e87d37 Binary files /dev/null and b/icons/clothing/shirts/harness.dmi differ diff --git a/icons/clothing/shirts/hawaiian.dmi b/icons/clothing/shirts/hawaiian.dmi new file mode 100644 index 000000000000..2460a35a0bba Binary files /dev/null and b/icons/clothing/shirts/hawaiian.dmi differ diff --git a/icons/clothing/shirts/hawaiian_alt.dmi b/icons/clothing/shirts/hawaiian_alt.dmi new file mode 100644 index 000000000000..1a257436baa7 Binary files /dev/null and b/icons/clothing/shirts/hawaiian_alt.dmi differ diff --git a/icons/clothing/shirts/pjs_blue.dmi b/icons/clothing/shirts/pjs_blue.dmi new file mode 100644 index 000000000000..a7b4fac345bd Binary files /dev/null and b/icons/clothing/shirts/pjs_blue.dmi differ diff --git a/icons/clothing/shirts/pjs_red.dmi b/icons/clothing/shirts/pjs_red.dmi new file mode 100644 index 000000000000..a0d590e6e815 Binary files /dev/null and b/icons/clothing/shirts/pjs_red.dmi differ diff --git a/icons/clothing/shirts/polo.dmi b/icons/clothing/shirts/polo.dmi new file mode 100644 index 000000000000..8077a08e4180 Binary files /dev/null and b/icons/clothing/shirts/polo.dmi differ diff --git a/icons/clothing/shirts/qipao.dmi b/icons/clothing/shirts/qipao.dmi new file mode 100644 index 000000000000..3be87adabcef Binary files /dev/null and b/icons/clothing/shirts/qipao.dmi differ diff --git a/icons/clothing/shirts/scrubs.dmi b/icons/clothing/shirts/scrubs.dmi new file mode 100644 index 000000000000..c623c5b58c8b Binary files /dev/null and b/icons/clothing/shirts/scrubs.dmi differ diff --git a/icons/clothing/shirts/security.dmi b/icons/clothing/shirts/security.dmi new file mode 100644 index 000000000000..9933ad4e8387 Binary files /dev/null and b/icons/clothing/shirts/security.dmi differ diff --git a/icons/clothing/shirts/sweater.dmi b/icons/clothing/shirts/sweater.dmi new file mode 100644 index 000000000000..0e90ace6fa2e Binary files /dev/null and b/icons/clothing/shirts/sweater.dmi differ diff --git a/icons/clothing/shirts/sweater_combat.dmi b/icons/clothing/shirts/sweater_combat.dmi new file mode 100644 index 000000000000..68044fdba45c Binary files /dev/null and b/icons/clothing/shirts/sweater_combat.dmi differ diff --git a/icons/clothing/shirts/sweater_tactical.dmi b/icons/clothing/shirts/sweater_tactical.dmi new file mode 100644 index 000000000000..452f4f290aa3 Binary files /dev/null and b/icons/clothing/shirts/sweater_tactical.dmi differ diff --git a/icons/clothing/shirts/toga.dmi b/icons/clothing/shirts/toga.dmi new file mode 100644 index 000000000000..8d6c39b5f595 Binary files /dev/null and b/icons/clothing/shirts/toga.dmi differ diff --git a/icons/clothing/shirts/tshirt.dmi b/icons/clothing/shirts/tshirt.dmi new file mode 100644 index 000000000000..bdddbe8c1383 Binary files /dev/null and b/icons/clothing/shirts/tshirt.dmi differ diff --git a/icons/clothing/shirts/tunics/tunic.dmi b/icons/clothing/shirts/tunics/tunic.dmi new file mode 100644 index 000000000000..8ef90bdbd065 Binary files /dev/null and b/icons/clothing/shirts/tunics/tunic.dmi differ diff --git a/icons/clothing/shirts/tunics/tunic_blue.dmi b/icons/clothing/shirts/tunics/tunic_blue.dmi new file mode 100644 index 000000000000..555816d9924b Binary files /dev/null and b/icons/clothing/shirts/tunics/tunic_blue.dmi differ diff --git a/icons/clothing/shirts/tunics/tunic_captain.dmi b/icons/clothing/shirts/tunics/tunic_captain.dmi new file mode 100644 index 000000000000..a96aba0b3d63 Binary files /dev/null and b/icons/clothing/shirts/tunics/tunic_captain.dmi differ diff --git a/icons/clothing/shirts/tunics/tunic_green.dmi b/icons/clothing/shirts/tunics/tunic_green.dmi new file mode 100644 index 000000000000..ee444cacf6bc Binary files /dev/null and b/icons/clothing/shirts/tunics/tunic_green.dmi differ diff --git a/icons/clothing/shirts/tunics/tunic_short.dmi b/icons/clothing/shirts/tunics/tunic_short.dmi new file mode 100644 index 000000000000..dc22b52c4cb5 Binary files /dev/null and b/icons/clothing/shirts/tunics/tunic_short.dmi differ diff --git a/icons/clothing/shirts/ubac.dmi b/icons/clothing/shirts/ubac.dmi new file mode 100644 index 000000000000..144db4424131 Binary files /dev/null and b/icons/clothing/shirts/ubac.dmi differ diff --git a/icons/clothing/shirts/ubac_blue.dmi b/icons/clothing/shirts/ubac_blue.dmi new file mode 100644 index 000000000000..b926ffb63572 Binary files /dev/null and b/icons/clothing/shirts/ubac_blue.dmi differ diff --git a/icons/clothing/shirts/ubac_green.dmi b/icons/clothing/shirts/ubac_green.dmi new file mode 100644 index 000000000000..0bce8cf2bbad Binary files /dev/null and b/icons/clothing/shirts/ubac_green.dmi differ diff --git a/icons/clothing/shirts/ubac_tan.dmi b/icons/clothing/shirts/ubac_tan.dmi new file mode 100644 index 000000000000..91a813c07aa7 Binary files /dev/null and b/icons/clothing/shirts/ubac_tan.dmi differ diff --git a/icons/clothing/shirts/uniform_turtleneck.dmi b/icons/clothing/shirts/uniform_turtleneck.dmi new file mode 100644 index 000000000000..5e96213d5ca9 Binary files /dev/null and b/icons/clothing/shirts/uniform_turtleneck.dmi differ diff --git a/icons/clothing/shirts/uniform_turtleneck_blue.dmi b/icons/clothing/shirts/uniform_turtleneck_blue.dmi new file mode 100644 index 000000000000..6697dc7972ee Binary files /dev/null and b/icons/clothing/shirts/uniform_turtleneck_blue.dmi differ diff --git a/icons/clothing/skirts/skirt_black.dmi b/icons/clothing/skirts/skirt_black.dmi new file mode 100644 index 000000000000..ee6a0c12506e Binary files /dev/null and b/icons/clothing/skirts/skirt_black.dmi differ diff --git a/icons/clothing/skirts/skirt_khaki.dmi b/icons/clothing/skirts/skirt_khaki.dmi new file mode 100644 index 000000000000..0ec079965564 Binary files /dev/null and b/icons/clothing/skirts/skirt_khaki.dmi differ diff --git a/icons/clothing/skirts/skirt_pleated_long.dmi b/icons/clothing/skirts/skirt_pleated_long.dmi new file mode 100644 index 000000000000..817a900d3c8c Binary files /dev/null and b/icons/clothing/skirts/skirt_pleated_long.dmi differ diff --git a/icons/clothing/skirts/skirt_pleated_medium.dmi b/icons/clothing/skirts/skirt_pleated_medium.dmi new file mode 100644 index 000000000000..2578c54fdbe1 Binary files /dev/null and b/icons/clothing/skirts/skirt_pleated_medium.dmi differ diff --git a/icons/clothing/skirts/skirt_pleated_short.dmi b/icons/clothing/skirts/skirt_pleated_short.dmi new file mode 100644 index 000000000000..5890f293cd8f Binary files /dev/null and b/icons/clothing/skirts/skirt_pleated_short.dmi differ diff --git a/icons/clothing/skirts/skirt_short.dmi b/icons/clothing/skirts/skirt_short.dmi new file mode 100644 index 000000000000..3b4f1d76cf43 Binary files /dev/null and b/icons/clothing/skirts/skirt_short.dmi differ diff --git a/icons/clothing/skirts/skirt_swept.dmi b/icons/clothing/skirts/skirt_swept.dmi new file mode 100644 index 000000000000..e3444fdba0c8 Binary files /dev/null and b/icons/clothing/skirts/skirt_swept.dmi differ diff --git a/icons/clothing/spacesuit/rig/breacher.dmi b/icons/clothing/spacesuit/rig/breacher.dmi deleted file mode 100644 index 7d1b3b38dc23..000000000000 Binary files a/icons/clothing/spacesuit/rig/breacher.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/breacher_knockoff.dmi b/icons/clothing/spacesuit/rig/breacher_knockoff.dmi deleted file mode 100644 index ca17e26441b8..000000000000 Binary files a/icons/clothing/spacesuit/rig/breacher_knockoff.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/chief_eng.dmi b/icons/clothing/spacesuit/rig/chief_eng.dmi deleted file mode 100644 index df377205bfa5..000000000000 Binary files a/icons/clothing/spacesuit/rig/chief_eng.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/eva.dmi b/icons/clothing/spacesuit/rig/eva.dmi deleted file mode 100644 index a4c7fe3e5468..000000000000 Binary files a/icons/clothing/spacesuit/rig/eva.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/hacker.dmi b/icons/clothing/spacesuit/rig/hacker.dmi deleted file mode 100644 index 5dedf639a15d..000000000000 Binary files a/icons/clothing/spacesuit/rig/hacker.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/hazard.dmi b/icons/clothing/spacesuit/rig/hazard.dmi deleted file mode 100644 index b4eb395f7d61..000000000000 Binary files a/icons/clothing/spacesuit/rig/hazard.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/industrial.dmi b/icons/clothing/spacesuit/rig/industrial.dmi deleted file mode 100644 index d93d4ca3f5d5..000000000000 Binary files a/icons/clothing/spacesuit/rig/industrial.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/internal_affairs.dmi b/icons/clothing/spacesuit/rig/internal_affairs.dmi deleted file mode 100644 index cd61dee2146f..000000000000 Binary files a/icons/clothing/spacesuit/rig/internal_affairs.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/medical.dmi b/icons/clothing/spacesuit/rig/medical.dmi deleted file mode 100644 index 6a0737b0198f..000000000000 Binary files a/icons/clothing/spacesuit/rig/medical.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/merc.dmi b/icons/clothing/spacesuit/rig/merc.dmi deleted file mode 100644 index ab439d526b1f..000000000000 Binary files a/icons/clothing/spacesuit/rig/merc.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/merc_heavy.dmi b/icons/clothing/spacesuit/rig/merc_heavy.dmi deleted file mode 100644 index 2f17e743fb94..000000000000 Binary files a/icons/clothing/spacesuit/rig/merc_heavy.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/military.dmi b/icons/clothing/spacesuit/rig/military.dmi deleted file mode 100644 index 557c815259aa..000000000000 Binary files a/icons/clothing/spacesuit/rig/military.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/ninja.dmi b/icons/clothing/spacesuit/rig/ninja.dmi deleted file mode 100644 index ae98dbe910da..000000000000 Binary files a/icons/clothing/spacesuit/rig/ninja.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/nullsuit.dmi b/icons/clothing/spacesuit/rig/nullsuit.dmi deleted file mode 100644 index d52fc3f0585a..000000000000 Binary files a/icons/clothing/spacesuit/rig/nullsuit.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/science.dmi b/icons/clothing/spacesuit/rig/science.dmi deleted file mode 100644 index ea07a002b314..000000000000 Binary files a/icons/clothing/spacesuit/rig/science.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/security.dmi b/icons/clothing/spacesuit/rig/security.dmi deleted file mode 100644 index d3af90678e46..000000000000 Binary files a/icons/clothing/spacesuit/rig/security.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/stealth.dmi b/icons/clothing/spacesuit/rig/stealth.dmi deleted file mode 100644 index ff8c174e0154..000000000000 Binary files a/icons/clothing/spacesuit/rig/stealth.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/rig/vox.dmi b/icons/clothing/spacesuit/rig/vox.dmi deleted file mode 100644 index 634c0b42d0b6..000000000000 Binary files a/icons/clothing/spacesuit/rig/vox.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/void/atmos_alt/helmet.dmi b/icons/clothing/spacesuit/void/atmos_alt/helmet.dmi index 301473988b31..7c07905c7a08 100644 Binary files a/icons/clothing/spacesuit/void/atmos_alt/helmet.dmi and b/icons/clothing/spacesuit/void/atmos_alt/helmet.dmi differ diff --git a/icons/clothing/spacesuit/void/atmos_alt/suit.dmi b/icons/clothing/spacesuit/void/atmos_alt/suit.dmi index 4191aa3289bf..63f2962fa80d 100644 Binary files a/icons/clothing/spacesuit/void/atmos_alt/suit.dmi and b/icons/clothing/spacesuit/void/atmos_alt/suit.dmi differ diff --git a/icons/clothing/spacesuit/void/engineering_alt/helmet.dmi b/icons/clothing/spacesuit/void/engineering_alt/helmet.dmi index 365df4a919d2..1b7af65df6a3 100644 Binary files a/icons/clothing/spacesuit/void/engineering_alt/helmet.dmi and b/icons/clothing/spacesuit/void/engineering_alt/helmet.dmi differ diff --git a/icons/clothing/spacesuit/void/engineering_alt/suit.dmi b/icons/clothing/spacesuit/void/engineering_alt/suit.dmi index 5a381ba0299c..d92b378cb25d 100644 Binary files a/icons/clothing/spacesuit/void/engineering_alt/suit.dmi and b/icons/clothing/spacesuit/void/engineering_alt/suit.dmi differ diff --git a/icons/clothing/spacesuit/void/excavation/helmet.dmi b/icons/clothing/spacesuit/void/excavation/helmet.dmi index 2bea74c1e79c..6ec7bfe484ec 100644 Binary files a/icons/clothing/spacesuit/void/excavation/helmet.dmi and b/icons/clothing/spacesuit/void/excavation/helmet.dmi differ diff --git a/icons/clothing/spacesuit/void/excavation/suit.dmi b/icons/clothing/spacesuit/void/excavation/suit.dmi index 5733afa9ed0f..9a4345fbab6e 100644 Binary files a/icons/clothing/spacesuit/void/excavation/suit.dmi and b/icons/clothing/spacesuit/void/excavation/suit.dmi differ diff --git a/icons/clothing/spacesuit/void/expedition/helmet.dmi b/icons/clothing/spacesuit/void/expedition/helmet.dmi new file mode 100644 index 000000000000..128e538ca600 Binary files /dev/null and b/icons/clothing/spacesuit/void/expedition/helmet.dmi differ diff --git a/icons/clothing/spacesuit/void/expedition/suit.dmi b/icons/clothing/spacesuit/void/expedition/suit.dmi new file mode 100644 index 000000000000..b56e19e1a082 Binary files /dev/null and b/icons/clothing/spacesuit/void/expedition/suit.dmi differ diff --git a/icons/clothing/spacesuit/void/medical_alt/helmet.dmi b/icons/clothing/spacesuit/void/medical_alt/helmet.dmi index a9a6da7f8ff2..1e05f1963f22 100644 Binary files a/icons/clothing/spacesuit/void/medical_alt/helmet.dmi and b/icons/clothing/spacesuit/void/medical_alt/helmet.dmi differ diff --git a/icons/clothing/spacesuit/void/medical_alt/suit.dmi b/icons/clothing/spacesuit/void/medical_alt/suit.dmi index 090bce80394e..634b67420791 100644 Binary files a/icons/clothing/spacesuit/void/medical_alt/suit.dmi and b/icons/clothing/spacesuit/void/medical_alt/suit.dmi differ diff --git a/icons/clothing/spacesuit/void/mining/helmet.dmi b/icons/clothing/spacesuit/void/mining/helmet.dmi index e9739f0852fa..28d3c2de7ae3 100644 Binary files a/icons/clothing/spacesuit/void/mining/helmet.dmi and b/icons/clothing/spacesuit/void/mining/helmet.dmi differ diff --git a/icons/clothing/spacesuit/void/mining/suit.dmi b/icons/clothing/spacesuit/void/mining/suit.dmi index d1fd6de69367..580d73eb1177 100644 Binary files a/icons/clothing/spacesuit/void/mining/suit.dmi and b/icons/clothing/spacesuit/void/mining/suit.dmi differ diff --git a/icons/clothing/spacesuit/void/pilot/helmet.dmi b/icons/clothing/spacesuit/void/pilot/helmet.dmi deleted file mode 100644 index a70b3912995b..000000000000 Binary files a/icons/clothing/spacesuit/void/pilot/helmet.dmi and /dev/null differ diff --git a/icons/clothing/spacesuit/void/pilot/suit.dmi b/icons/clothing/spacesuit/void/pilot/suit.dmi deleted file mode 100644 index d445534c3f51..000000000000 Binary files a/icons/clothing/spacesuit/void/pilot/suit.dmi and /dev/null differ diff --git a/icons/clothing/suit/cap_jacket.dmi b/icons/clothing/suit/cap_jacket.dmi deleted file mode 100644 index 7c8368a54b92..000000000000 Binary files a/icons/clothing/suit/cap_jacket.dmi and /dev/null differ diff --git a/icons/clothing/suit/cap_tunic.dmi b/icons/clothing/suit/cap_tunic.dmi deleted file mode 100644 index c15e87c19bf4..000000000000 Binary files a/icons/clothing/suit/cap_tunic.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/_cloak.dmi b/icons/clothing/suit/cloaks/_cloak.dmi deleted file mode 100644 index 8134b372f43b..000000000000 Binary files a/icons/clothing/suit/cloaks/_cloak.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_atmospherics.dmi b/icons/clothing/suit/cloaks/cloak_atmospherics.dmi deleted file mode 100644 index 722dbb82113a..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_atmospherics.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_captain.dmi b/icons/clothing/suit/cloaks/cloak_captain.dmi deleted file mode 100644 index 96d7165b6733..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_captain.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_cargo.dmi b/icons/clothing/suit/cloaks/cloak_cargo.dmi deleted file mode 100644 index 163964b03f5e..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_cargo.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_ce.dmi b/icons/clothing/suit/cloaks/cloak_ce.dmi deleted file mode 100644 index a56c894afcf8..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_ce.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_engineer.dmi b/icons/clothing/suit/cloaks/cloak_engineer.dmi deleted file mode 100644 index dc8722f50871..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_engineer.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_hide.dmi b/icons/clothing/suit/cloaks/cloak_hide.dmi deleted file mode 100644 index c0394b8bea29..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_hide.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_hop.dmi b/icons/clothing/suit/cloaks/cloak_hop.dmi deleted file mode 100644 index 9659100f1486..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_hop.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_hos.dmi b/icons/clothing/suit/cloaks/cloak_hos.dmi deleted file mode 100644 index e8e8765e41ce..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_hos.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_medical.dmi b/icons/clothing/suit/cloaks/cloak_medical.dmi deleted file mode 100644 index cd2629404704..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_medical.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_mining.dmi b/icons/clothing/suit/cloaks/cloak_mining.dmi deleted file mode 100644 index 1c755c040fe9..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_mining.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_qm.dmi b/icons/clothing/suit/cloaks/cloak_qm.dmi deleted file mode 100644 index 35c970f04750..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_qm.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_rd.dmi b/icons/clothing/suit/cloaks/cloak_rd.dmi deleted file mode 100644 index ea9c8a162e88..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_rd.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_research.dmi b/icons/clothing/suit/cloaks/cloak_research.dmi deleted file mode 100644 index ff0586a875fa..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_research.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_security.dmi b/icons/clothing/suit/cloaks/cloak_security.dmi deleted file mode 100644 index ba65e2eb123a..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_security.dmi and /dev/null differ diff --git a/icons/clothing/suit/cloaks/cloak_service.dmi b/icons/clothing/suit/cloaks/cloak_service.dmi deleted file mode 100644 index a2c990bee794..000000000000 Binary files a/icons/clothing/suit/cloaks/cloak_service.dmi and /dev/null differ diff --git a/icons/clothing/suit/hoodie.dmi b/icons/clothing/suit/hoodie.dmi deleted file mode 100644 index f9480c22a3c3..000000000000 Binary files a/icons/clothing/suit/hoodie.dmi and /dev/null differ diff --git a/icons/clothing/suit/labcoat/default.dmi b/icons/clothing/suit/labcoat/default.dmi deleted file mode 100644 index efdff16b8235..000000000000 Binary files a/icons/clothing/suit/labcoat/default.dmi and /dev/null differ diff --git a/icons/clothing/suit/leather_jacket/black.dmi b/icons/clothing/suit/leather_jacket/black.dmi deleted file mode 100644 index 5dfe47624cf9..000000000000 Binary files a/icons/clothing/suit/leather_jacket/black.dmi and /dev/null differ diff --git a/icons/clothing/suit/letterman.dmi b/icons/clothing/suit/letterman.dmi deleted file mode 100644 index 959af29a3e02..000000000000 Binary files a/icons/clothing/suit/letterman.dmi and /dev/null differ diff --git a/icons/clothing/suit/responder_jacket.dmi b/icons/clothing/suit/responder_jacket.dmi deleted file mode 100644 index aae616ad83af..000000000000 Binary files a/icons/clothing/suit/responder_jacket.dmi and /dev/null differ diff --git a/icons/clothing/suit/rough_robe.dmi b/icons/clothing/suit/rough_robe.dmi deleted file mode 100644 index 5b609814338f..000000000000 Binary files a/icons/clothing/suit/rough_robe.dmi and /dev/null differ diff --git a/icons/clothing/suit/suit_jacket.dmi b/icons/clothing/suit/suit_jacket.dmi deleted file mode 100644 index ad162010e551..000000000000 Binary files a/icons/clothing/suit/suit_jacket.dmi and /dev/null differ diff --git a/icons/clothing/suit/tdgreen.dmi b/icons/clothing/suit/tdgreen.dmi deleted file mode 100644 index 844918c4b8ab..000000000000 Binary files a/icons/clothing/suit/tdgreen.dmi and /dev/null differ diff --git a/icons/clothing/suit/tracksuit/black.dmi b/icons/clothing/suit/tracksuit/black.dmi deleted file mode 100644 index 3fcb83793038..000000000000 Binary files a/icons/clothing/suit/tracksuit/black.dmi and /dev/null differ diff --git a/icons/clothing/suit/tracksuit/blue.dmi b/icons/clothing/suit/tracksuit/blue.dmi deleted file mode 100644 index 0b9ffb44fc1c..000000000000 Binary files a/icons/clothing/suit/tracksuit/blue.dmi and /dev/null differ diff --git a/icons/clothing/suit/tracksuit/navy.dmi b/icons/clothing/suit/tracksuit/navy.dmi deleted file mode 100644 index a40e2c6b8b53..000000000000 Binary files a/icons/clothing/suit/tracksuit/navy.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/atmos.dmi b/icons/clothing/suit/wintercoat/atmos.dmi deleted file mode 100644 index d10304b9e9ab..000000000000 Binary files a/icons/clothing/suit/wintercoat/atmos.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/captain.dmi b/icons/clothing/suit/wintercoat/captain.dmi deleted file mode 100644 index 2c2f1201793a..000000000000 Binary files a/icons/clothing/suit/wintercoat/captain.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/cargo.dmi b/icons/clothing/suit/wintercoat/cargo.dmi deleted file mode 100644 index d1369bde778f..000000000000 Binary files a/icons/clothing/suit/wintercoat/cargo.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/coat.dmi b/icons/clothing/suit/wintercoat/coat.dmi deleted file mode 100644 index cd2008a88a17..000000000000 Binary files a/icons/clothing/suit/wintercoat/coat.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/eng.dmi b/icons/clothing/suit/wintercoat/eng.dmi deleted file mode 100644 index b66335b7cc7e..000000000000 Binary files a/icons/clothing/suit/wintercoat/eng.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/hydro.dmi b/icons/clothing/suit/wintercoat/hydro.dmi deleted file mode 100644 index 1af82d96a67a..000000000000 Binary files a/icons/clothing/suit/wintercoat/hydro.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/med.dmi b/icons/clothing/suit/wintercoat/med.dmi deleted file mode 100644 index b7660d9fa420..000000000000 Binary files a/icons/clothing/suit/wintercoat/med.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/mining.dmi b/icons/clothing/suit/wintercoat/mining.dmi deleted file mode 100644 index 63f5b896606c..000000000000 Binary files a/icons/clothing/suit/wintercoat/mining.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/sci.dmi b/icons/clothing/suit/wintercoat/sci.dmi deleted file mode 100644 index bff0a679f85f..000000000000 Binary files a/icons/clothing/suit/wintercoat/sci.dmi and /dev/null differ diff --git a/icons/clothing/suit/wintercoat/sec.dmi b/icons/clothing/suit/wintercoat/sec.dmi deleted file mode 100644 index efd7c8fc73df..000000000000 Binary files a/icons/clothing/suit/wintercoat/sec.dmi and /dev/null differ diff --git a/icons/clothing/suits/abaya.dmi b/icons/clothing/suits/abaya.dmi new file mode 100644 index 000000000000..9ebec9ef59ed Binary files /dev/null and b/icons/clothing/suits/abaya.dmi differ diff --git a/icons/clothing/suit/apron.dmi b/icons/clothing/suits/apron.dmi similarity index 100% rename from icons/clothing/suit/apron.dmi rename to icons/clothing/suits/apron.dmi diff --git a/icons/clothing/suit/apron_chef.dmi b/icons/clothing/suits/apron_chef.dmi similarity index 100% rename from icons/clothing/suit/apron_chef.dmi rename to icons/clothing/suits/apron_chef.dmi diff --git a/icons/clothing/suits/apron_colourable.dmi b/icons/clothing/suits/apron_colourable.dmi new file mode 100644 index 000000000000..e251d477f588 Binary files /dev/null and b/icons/clothing/suits/apron_colourable.dmi differ diff --git a/icons/clothing/suit/apron_surgery.dmi b/icons/clothing/suits/apron_surgery.dmi similarity index 100% rename from icons/clothing/suit/apron_surgery.dmi rename to icons/clothing/suits/apron_surgery.dmi diff --git a/icons/clothing/suit/armor/ballistic.dmi b/icons/clothing/suits/armor/ballistic.dmi similarity index 100% rename from icons/clothing/suit/armor/ballistic.dmi rename to icons/clothing/suits/armor/ballistic.dmi diff --git a/icons/clothing/suits/armor/banded.dmi b/icons/clothing/suits/armor/banded.dmi new file mode 100644 index 000000000000..cd1506bd9ccf Binary files /dev/null and b/icons/clothing/suits/armor/banded.dmi differ diff --git a/icons/clothing/suit/armor/improvised.dmi b/icons/clothing/suits/armor/improvised.dmi similarity index 100% rename from icons/clothing/suit/armor/improvised.dmi rename to icons/clothing/suits/armor/improvised.dmi diff --git a/icons/clothing/suit/armor/plate_carrier.dmi b/icons/clothing/suits/armor/plate_carrier.dmi similarity index 100% rename from icons/clothing/suit/armor/plate_carrier.dmi rename to icons/clothing/suits/armor/plate_carrier.dmi diff --git a/icons/clothing/suit/armor/reactive.dmi b/icons/clothing/suits/armor/reactive.dmi similarity index 100% rename from icons/clothing/suit/armor/reactive.dmi rename to icons/clothing/suits/armor/reactive.dmi diff --git a/icons/clothing/suit/armor/reflective.dmi b/icons/clothing/suits/armor/reflective.dmi similarity index 100% rename from icons/clothing/suit/armor/reflective.dmi rename to icons/clothing/suits/armor/reflective.dmi diff --git a/icons/clothing/suit/armor/riot.dmi b/icons/clothing/suits/armor/riot.dmi similarity index 100% rename from icons/clothing/suit/armor/riot.dmi rename to icons/clothing/suits/armor/riot.dmi diff --git a/icons/clothing/suit/armor/vest.dmi b/icons/clothing/suits/armor/vest.dmi similarity index 100% rename from icons/clothing/suit/armor/vest.dmi rename to icons/clothing/suits/armor/vest.dmi diff --git a/icons/clothing/suit/biosuit/_biosuit.dmi b/icons/clothing/suits/biosuit/_biosuit.dmi similarity index 100% rename from icons/clothing/suit/biosuit/_biosuit.dmi rename to icons/clothing/suits/biosuit/_biosuit.dmi diff --git a/icons/clothing/suit/biosuit/anomaly.dmi b/icons/clothing/suits/biosuit/anomaly.dmi similarity index 100% rename from icons/clothing/suit/biosuit/anomaly.dmi rename to icons/clothing/suits/biosuit/anomaly.dmi diff --git a/icons/clothing/suit/biosuit/cmo.dmi b/icons/clothing/suits/biosuit/cmo.dmi similarity index 100% rename from icons/clothing/suit/biosuit/cmo.dmi rename to icons/clothing/suits/biosuit/cmo.dmi diff --git a/icons/clothing/suit/biosuit/janitor.dmi b/icons/clothing/suits/biosuit/janitor.dmi similarity index 100% rename from icons/clothing/suit/biosuit/janitor.dmi rename to icons/clothing/suits/biosuit/janitor.dmi diff --git a/icons/clothing/suit/biosuit/plague.dmi b/icons/clothing/suits/biosuit/plague.dmi similarity index 100% rename from icons/clothing/suit/biosuit/plague.dmi rename to icons/clothing/suits/biosuit/plague.dmi diff --git a/icons/clothing/suit/biosuit/scientist.dmi b/icons/clothing/suits/biosuit/scientist.dmi similarity index 100% rename from icons/clothing/suit/biosuit/scientist.dmi rename to icons/clothing/suits/biosuit/scientist.dmi diff --git a/icons/clothing/suit/biosuit/security.dmi b/icons/clothing/suits/biosuit/security.dmi similarity index 100% rename from icons/clothing/suit/biosuit/security.dmi rename to icons/clothing/suits/biosuit/security.dmi diff --git a/icons/clothing/suit/biosuit/virology.dmi b/icons/clothing/suits/biosuit/virology.dmi similarity index 100% rename from icons/clothing/suit/biosuit/virology.dmi rename to icons/clothing/suits/biosuit/virology.dmi diff --git a/icons/clothing/suit/bluetag.dmi b/icons/clothing/suits/bluetag.dmi similarity index 100% rename from icons/clothing/suit/bluetag.dmi rename to icons/clothing/suits/bluetag.dmi diff --git a/icons/clothing/suit/bombsuit.dmi b/icons/clothing/suits/bombsuit.dmi similarity index 100% rename from icons/clothing/suit/bombsuit.dmi rename to icons/clothing/suits/bombsuit.dmi diff --git a/icons/clothing/suit/bombsuit_olive.dmi b/icons/clothing/suits/bombsuit_olive.dmi similarity index 100% rename from icons/clothing/suit/bombsuit_olive.dmi rename to icons/clothing/suits/bombsuit_olive.dmi diff --git a/icons/clothing/suits/brigandine.dmi b/icons/clothing/suits/brigandine.dmi new file mode 100644 index 000000000000..88185879f4cd Binary files /dev/null and b/icons/clothing/suits/brigandine.dmi differ diff --git a/icons/clothing/suit/cardborg.dmi b/icons/clothing/suits/cardborg.dmi similarity index 100% rename from icons/clothing/suit/cardborg.dmi rename to icons/clothing/suits/cardborg.dmi diff --git a/icons/clothing/suit/chaplain.dmi b/icons/clothing/suits/chaplain.dmi similarity index 100% rename from icons/clothing/suit/chaplain.dmi rename to icons/clothing/suits/chaplain.dmi diff --git a/icons/clothing/suit/chef.dmi b/icons/clothing/suits/chef.dmi similarity index 100% rename from icons/clothing/suit/chef.dmi rename to icons/clothing/suits/chef.dmi diff --git a/icons/clothing/suit/chem_suit.dmi b/icons/clothing/suits/chem_suit.dmi similarity index 100% rename from icons/clothing/suit/chem_suit.dmi rename to icons/clothing/suits/chem_suit.dmi diff --git a/icons/clothing/suit/chicken.dmi b/icons/clothing/suits/chicken.dmi similarity index 100% rename from icons/clothing/suit/chicken.dmi rename to icons/clothing/suits/chicken.dmi diff --git a/icons/clothing/suits/cloaks/_cloak.dmi b/icons/clothing/suits/cloaks/_cloak.dmi new file mode 100644 index 000000000000..a31886615d97 Binary files /dev/null and b/icons/clothing/suits/cloaks/_cloak.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_atmospherics.dmi b/icons/clothing/suits/cloaks/cloak_atmospherics.dmi new file mode 100644 index 000000000000..e3046672ccba Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_atmospherics.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_captain.dmi b/icons/clothing/suits/cloaks/cloak_captain.dmi new file mode 100644 index 000000000000..c6d78733b265 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_captain.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_cargo.dmi b/icons/clothing/suits/cloaks/cloak_cargo.dmi new file mode 100644 index 000000000000..55dde677226c Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_cargo.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_ce.dmi b/icons/clothing/suits/cloaks/cloak_ce.dmi new file mode 100644 index 000000000000..36abb7a24b1e Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_ce.dmi differ diff --git a/icons/clothing/suit/cloaks/cloak_cmo.dmi b/icons/clothing/suits/cloaks/cloak_cmo.dmi similarity index 85% rename from icons/clothing/suit/cloaks/cloak_cmo.dmi rename to icons/clothing/suits/cloaks/cloak_cmo.dmi index ddf376761353..98da0d0df666 100644 Binary files a/icons/clothing/suit/cloaks/cloak_cmo.dmi and b/icons/clothing/suits/cloaks/cloak_cmo.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_engineer.dmi b/icons/clothing/suits/cloaks/cloak_engineer.dmi new file mode 100644 index 000000000000..19a2019b5dc4 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_engineer.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_hide.dmi b/icons/clothing/suits/cloaks/cloak_hide.dmi new file mode 100644 index 000000000000..2b1bc74eb3cf Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_hide.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_hooded.dmi b/icons/clothing/suits/cloaks/cloak_hooded.dmi new file mode 100644 index 000000000000..8a045eb776da Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_hooded.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_hop.dmi b/icons/clothing/suits/cloaks/cloak_hop.dmi new file mode 100644 index 000000000000..ff3fcaf72a37 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_hop.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_hos.dmi b/icons/clothing/suits/cloaks/cloak_hos.dmi new file mode 100644 index 000000000000..dc5f4fcb63e8 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_hos.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_medical.dmi b/icons/clothing/suits/cloaks/cloak_medical.dmi new file mode 100644 index 000000000000..5a1a52dafd86 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_medical.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_mining.dmi b/icons/clothing/suits/cloaks/cloak_mining.dmi new file mode 100644 index 000000000000..f933c1e76621 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_mining.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_qm.dmi b/icons/clothing/suits/cloaks/cloak_qm.dmi new file mode 100644 index 000000000000..8349a8b333b8 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_qm.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_rd.dmi b/icons/clothing/suits/cloaks/cloak_rd.dmi new file mode 100644 index 000000000000..49a463cb804a Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_rd.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_research.dmi b/icons/clothing/suits/cloaks/cloak_research.dmi new file mode 100644 index 000000000000..6d3e5319e6be Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_research.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_security.dmi b/icons/clothing/suits/cloaks/cloak_security.dmi new file mode 100644 index 000000000000..72a1233b6741 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_security.dmi differ diff --git a/icons/clothing/suits/cloaks/cloak_service.dmi b/icons/clothing/suits/cloaks/cloak_service.dmi new file mode 100644 index 000000000000..88e476a19251 Binary files /dev/null and b/icons/clothing/suits/cloaks/cloak_service.dmi differ diff --git a/icons/clothing/suits/cuirass.dmi b/icons/clothing/suits/cuirass.dmi new file mode 100644 index 000000000000..4d661665a64e Binary files /dev/null and b/icons/clothing/suits/cuirass.dmi differ diff --git a/icons/clothing/suit/cult.dmi b/icons/clothing/suits/cult.dmi similarity index 100% rename from icons/clothing/suit/cult.dmi rename to icons/clothing/suits/cult.dmi diff --git a/icons/clothing/suit/cult_alt.dmi b/icons/clothing/suits/cult_alt.dmi similarity index 100% rename from icons/clothing/suit/cult_alt.dmi rename to icons/clothing/suits/cult_alt.dmi diff --git a/icons/clothing/suits/dashiki/dashiki.dmi b/icons/clothing/suits/dashiki/dashiki.dmi new file mode 100644 index 000000000000..fa4fce773c1b Binary files /dev/null and b/icons/clothing/suits/dashiki/dashiki.dmi differ diff --git a/icons/clothing/suits/dashiki/dashiki_blue.dmi b/icons/clothing/suits/dashiki/dashiki_blue.dmi new file mode 100644 index 000000000000..7a0a92a329b2 Binary files /dev/null and b/icons/clothing/suits/dashiki/dashiki_blue.dmi differ diff --git a/icons/clothing/suits/dashiki/dashiki_red.dmi b/icons/clothing/suits/dashiki/dashiki_red.dmi new file mode 100644 index 000000000000..8f25a1bae143 Binary files /dev/null and b/icons/clothing/suits/dashiki/dashiki_red.dmi differ diff --git a/icons/clothing/suit/deity/star_champion.dmi b/icons/clothing/suits/deity/star_champion.dmi similarity index 100% rename from icons/clothing/suit/deity/star_champion.dmi rename to icons/clothing/suits/deity/star_champion.dmi diff --git a/icons/clothing/suit/deity/star_oracle.dmi b/icons/clothing/suits/deity/star_oracle.dmi similarity index 100% rename from icons/clothing/suit/deity/star_oracle.dmi rename to icons/clothing/suits/deity/star_oracle.dmi diff --git a/icons/clothing/suit/deity/star_traitor.dmi b/icons/clothing/suits/deity/star_traitor.dmi similarity index 100% rename from icons/clothing/suit/deity/star_traitor.dmi rename to icons/clothing/suits/deity/star_traitor.dmi diff --git a/icons/clothing/suit/detective_brown.dmi b/icons/clothing/suits/detective_brown.dmi similarity index 100% rename from icons/clothing/suit/detective_brown.dmi rename to icons/clothing/suits/detective_brown.dmi diff --git a/icons/clothing/suit/detective_grey.dmi b/icons/clothing/suits/detective_grey.dmi similarity index 100% rename from icons/clothing/suit/detective_grey.dmi rename to icons/clothing/suits/detective_grey.dmi diff --git a/icons/clothing/suit/emt_jacket.dmi b/icons/clothing/suits/emt_jacket.dmi similarity index 85% rename from icons/clothing/suit/emt_jacket.dmi rename to icons/clothing/suits/emt_jacket.dmi index f39f438fc736..3dfd4850486c 100644 Binary files a/icons/clothing/suit/emt_jacket.dmi and b/icons/clothing/suits/emt_jacket.dmi differ diff --git a/icons/clothing/suit/fated_mantle.dmi b/icons/clothing/suits/fated_mantle.dmi similarity index 100% rename from icons/clothing/suit/fated_mantle.dmi rename to icons/clothing/suits/fated_mantle.dmi diff --git a/icons/clothing/suits/fated_robes.dmi b/icons/clothing/suits/fated_robes.dmi new file mode 100644 index 000000000000..52b97fc3cfde Binary files /dev/null and b/icons/clothing/suits/fated_robes.dmi differ diff --git a/icons/clothing/suit/firesuit.dmi b/icons/clothing/suits/firesuit.dmi similarity index 100% rename from icons/clothing/suit/firesuit.dmi rename to icons/clothing/suits/firesuit.dmi diff --git a/icons/clothing/suit/forensic_blue.dmi b/icons/clothing/suits/forensic_blue.dmi similarity index 100% rename from icons/clothing/suit/forensic_blue.dmi rename to icons/clothing/suits/forensic_blue.dmi diff --git a/icons/clothing/suit/forensic_red.dmi b/icons/clothing/suits/forensic_red.dmi similarity index 100% rename from icons/clothing/suit/forensic_red.dmi rename to icons/clothing/suits/forensic_red.dmi diff --git a/icons/clothing/suit/gown.dmi b/icons/clothing/suits/gown.dmi similarity index 100% rename from icons/clothing/suit/gown.dmi rename to icons/clothing/suits/gown.dmi diff --git a/icons/clothing/suits/grim_hoodie.dmi b/icons/clothing/suits/grim_hoodie.dmi new file mode 100644 index 000000000000..d639d5f5bab6 Binary files /dev/null and b/icons/clothing/suits/grim_hoodie.dmi differ diff --git a/icons/clothing/suit/hastur.dmi b/icons/clothing/suits/hastur.dmi similarity index 100% rename from icons/clothing/suit/hastur.dmi rename to icons/clothing/suits/hastur.dmi diff --git a/icons/clothing/suit/hazard_vest/green.dmi b/icons/clothing/suits/hazard_vest/green.dmi similarity index 100% rename from icons/clothing/suit/hazard_vest/green.dmi rename to icons/clothing/suits/hazard_vest/green.dmi diff --git a/icons/clothing/suit/hazard_vest/orange.dmi b/icons/clothing/suits/hazard_vest/orange.dmi similarity index 100% rename from icons/clothing/suit/hazard_vest/orange.dmi rename to icons/clothing/suits/hazard_vest/orange.dmi diff --git a/icons/clothing/suit/holidaypriest.dmi b/icons/clothing/suits/holidaypriest.dmi similarity index 100% rename from icons/clothing/suit/holidaypriest.dmi rename to icons/clothing/suits/holidaypriest.dmi diff --git a/icons/clothing/suits/hoodie.dmi b/icons/clothing/suits/hoodie.dmi new file mode 100644 index 000000000000..54f3c40caaa6 Binary files /dev/null and b/icons/clothing/suits/hoodie.dmi differ diff --git a/icons/clothing/suit/hos.dmi b/icons/clothing/suits/hos.dmi similarity index 100% rename from icons/clothing/suit/hos.dmi rename to icons/clothing/suits/hos.dmi diff --git a/icons/clothing/suit/human_suit.dmi b/icons/clothing/suits/human_suit.dmi similarity index 100% rename from icons/clothing/suit/human_suit.dmi rename to icons/clothing/suits/human_suit.dmi diff --git a/icons/clothing/suit/ianshirt.dmi b/icons/clothing/suits/ianshirt.dmi similarity index 100% rename from icons/clothing/suit/ianshirt.dmi rename to icons/clothing/suits/ianshirt.dmi diff --git a/icons/clothing/suit/leather_jacket/agent.dmi b/icons/clothing/suits/jackets/agent.dmi similarity index 87% rename from icons/clothing/suit/leather_jacket/agent.dmi rename to icons/clothing/suits/jackets/agent.dmi index 0cf8146d1776..cd3d6b68e66d 100644 Binary files a/icons/clothing/suit/leather_jacket/agent.dmi and b/icons/clothing/suits/jackets/agent.dmi differ diff --git a/icons/clothing/suits/jackets/black.dmi b/icons/clothing/suits/jackets/black.dmi new file mode 100644 index 000000000000..7534747ba0b5 Binary files /dev/null and b/icons/clothing/suits/jackets/black.dmi differ diff --git a/icons/clothing/suits/jackets/blazer.dmi b/icons/clothing/suits/jackets/blazer.dmi new file mode 100644 index 000000000000..43109e43fd36 Binary files /dev/null and b/icons/clothing/suits/jackets/blazer.dmi differ diff --git a/icons/clothing/suit/leather_jacket/bomber.dmi b/icons/clothing/suits/jackets/bomber.dmi similarity index 88% rename from icons/clothing/suit/leather_jacket/bomber.dmi rename to icons/clothing/suits/jackets/bomber.dmi index ddeca700f6ae..82738b5183e0 100644 Binary files a/icons/clothing/suit/leather_jacket/bomber.dmi and b/icons/clothing/suits/jackets/bomber.dmi differ diff --git a/icons/clothing/suit/leather_jacket/brown.dmi b/icons/clothing/suits/jackets/brown.dmi similarity index 82% rename from icons/clothing/suit/leather_jacket/brown.dmi rename to icons/clothing/suits/jackets/brown.dmi index 1da7b2e19383..321566d76589 100644 Binary files a/icons/clothing/suit/leather_jacket/brown.dmi and b/icons/clothing/suits/jackets/brown.dmi differ diff --git a/icons/clothing/suits/jackets/brown_suit.dmi b/icons/clothing/suits/jackets/brown_suit.dmi new file mode 100644 index 000000000000..042714e11879 Binary files /dev/null and b/icons/clothing/suits/jackets/brown_suit.dmi differ diff --git a/icons/clothing/suits/jackets/burgundy.dmi b/icons/clothing/suits/jackets/burgundy.dmi new file mode 100644 index 000000000000..b77ec710a743 Binary files /dev/null and b/icons/clothing/suits/jackets/burgundy.dmi differ diff --git a/icons/clothing/suits/jackets/captain.dmi b/icons/clothing/suits/jackets/captain.dmi new file mode 100644 index 000000000000..0a60bc701a29 Binary files /dev/null and b/icons/clothing/suits/jackets/captain.dmi differ diff --git a/icons/clothing/suits/jackets/charcoal.dmi b/icons/clothing/suits/jackets/charcoal.dmi new file mode 100644 index 000000000000..6a3f7f185442 Binary files /dev/null and b/icons/clothing/suits/jackets/charcoal.dmi differ diff --git a/icons/clothing/suits/jackets/checkered.dmi b/icons/clothing/suits/jackets/checkered.dmi new file mode 100644 index 000000000000..98bc5c708ebf Binary files /dev/null and b/icons/clothing/suits/jackets/checkered.dmi differ diff --git a/icons/clothing/suits/jackets/jacket.dmi b/icons/clothing/suits/jackets/jacket.dmi new file mode 100644 index 000000000000..9cf8382b302f Binary files /dev/null and b/icons/clothing/suits/jackets/jacket.dmi differ diff --git a/icons/clothing/suits/jackets/navy.dmi b/icons/clothing/suits/jackets/navy.dmi new file mode 100644 index 000000000000..5d7ff67ea2e9 Binary files /dev/null and b/icons/clothing/suits/jackets/navy.dmi differ diff --git a/icons/clothing/suits/jackets/responder.dmi b/icons/clothing/suits/jackets/responder.dmi new file mode 100644 index 000000000000..b5929f06eff3 Binary files /dev/null and b/icons/clothing/suits/jackets/responder.dmi differ diff --git a/icons/clothing/suits/jackets/tan.dmi b/icons/clothing/suits/jackets/tan.dmi new file mode 100644 index 000000000000..5b7de9de3861 Binary files /dev/null and b/icons/clothing/suits/jackets/tan.dmi differ diff --git a/icons/clothing/suit/jensen.dmi b/icons/clothing/suits/jensen.dmi similarity index 100% rename from icons/clothing/suit/jensen.dmi rename to icons/clothing/suits/jensen.dmi diff --git a/icons/clothing/suit/judge.dmi b/icons/clothing/suits/judge.dmi similarity index 100% rename from icons/clothing/suit/judge.dmi rename to icons/clothing/suits/judge.dmi diff --git a/icons/clothing/suit/labcoat/blue_edge.dmi b/icons/clothing/suits/labcoat/blue_edge.dmi similarity index 88% rename from icons/clothing/suit/labcoat/blue_edge.dmi rename to icons/clothing/suits/labcoat/blue_edge.dmi index 91dad0ee95e2..16a28342987e 100644 Binary files a/icons/clothing/suit/labcoat/blue_edge.dmi and b/icons/clothing/suits/labcoat/blue_edge.dmi differ diff --git a/icons/clothing/suit/labcoat/cmo.dmi b/icons/clothing/suits/labcoat/cmo.dmi similarity index 92% rename from icons/clothing/suit/labcoat/cmo.dmi rename to icons/clothing/suits/labcoat/cmo.dmi index 0568286ea8f9..9f0357841540 100644 Binary files a/icons/clothing/suit/labcoat/cmo.dmi and b/icons/clothing/suits/labcoat/cmo.dmi differ diff --git a/icons/clothing/suits/labcoat/default.dmi b/icons/clothing/suits/labcoat/default.dmi new file mode 100644 index 000000000000..abd5d8f0b820 Binary files /dev/null and b/icons/clothing/suits/labcoat/default.dmi differ diff --git a/icons/clothing/suit/labcoat/rd.dmi b/icons/clothing/suits/labcoat/rd.dmi similarity index 78% rename from icons/clothing/suit/labcoat/rd.dmi rename to icons/clothing/suits/labcoat/rd.dmi index 531d0258e201..b2758f1e836d 100644 Binary files a/icons/clothing/suit/labcoat/rd.dmi and b/icons/clothing/suits/labcoat/rd.dmi differ diff --git a/icons/clothing/suit/leathercoat.dmi b/icons/clothing/suits/leathercoat.dmi similarity index 100% rename from icons/clothing/suit/leathercoat.dmi rename to icons/clothing/suits/leathercoat.dmi diff --git a/icons/clothing/suits/letterman.dmi b/icons/clothing/suits/letterman.dmi new file mode 100644 index 000000000000..b8b0d2801d73 Binary files /dev/null and b/icons/clothing/suits/letterman.dmi differ diff --git a/icons/clothing/suits/mantle.dmi b/icons/clothing/suits/mantle.dmi new file mode 100644 index 000000000000..4800dc50bfae Binary files /dev/null and b/icons/clothing/suits/mantle.dmi differ diff --git a/icons/clothing/suit/med_chest.dmi b/icons/clothing/suits/med_chest.dmi similarity index 100% rename from icons/clothing/suit/med_chest.dmi rename to icons/clothing/suits/med_chest.dmi diff --git a/icons/clothing/suit/monkey.dmi b/icons/clothing/suits/monkey.dmi similarity index 100% rename from icons/clothing/suit/monkey.dmi rename to icons/clothing/suits/monkey.dmi diff --git a/icons/clothing/suit/nun.dmi b/icons/clothing/suits/nun.dmi similarity index 100% rename from icons/clothing/suit/nun.dmi rename to icons/clothing/suits/nun.dmi diff --git a/icons/clothing/suit/overalls.dmi b/icons/clothing/suits/overalls.dmi similarity index 100% rename from icons/clothing/suit/overalls.dmi rename to icons/clothing/suits/overalls.dmi diff --git a/icons/clothing/suits/overalls_denim.dmi b/icons/clothing/suits/overalls_denim.dmi new file mode 100644 index 000000000000..be3bd6115d28 Binary files /dev/null and b/icons/clothing/suits/overalls_denim.dmi differ diff --git a/icons/clothing/suits/overalls_laborer.dmi b/icons/clothing/suits/overalls_laborer.dmi new file mode 100644 index 000000000000..0cbcba896caf Binary files /dev/null and b/icons/clothing/suits/overalls_laborer.dmi differ diff --git a/icons/clothing/suit/pirate.dmi b/icons/clothing/suits/pirate.dmi similarity index 100% rename from icons/clothing/suit/pirate.dmi rename to icons/clothing/suits/pirate.dmi diff --git a/icons/clothing/suit/pirate_captain.dmi b/icons/clothing/suits/pirate_captain.dmi similarity index 100% rename from icons/clothing/suit/pirate_captain.dmi rename to icons/clothing/suits/pirate_captain.dmi diff --git a/icons/clothing/suit/poncho/blue.dmi b/icons/clothing/suits/poncho/blue.dmi similarity index 100% rename from icons/clothing/suit/poncho/blue.dmi rename to icons/clothing/suits/poncho/blue.dmi diff --git a/icons/clothing/suit/poncho/cargo.dmi b/icons/clothing/suits/poncho/cargo.dmi similarity index 100% rename from icons/clothing/suit/poncho/cargo.dmi rename to icons/clothing/suits/poncho/cargo.dmi diff --git a/icons/clothing/suit/poncho/classic.dmi b/icons/clothing/suits/poncho/classic.dmi similarity index 100% rename from icons/clothing/suit/poncho/classic.dmi rename to icons/clothing/suits/poncho/classic.dmi diff --git a/icons/clothing/suits/poncho/colourable.dmi b/icons/clothing/suits/poncho/colourable.dmi new file mode 100644 index 000000000000..852ee3b18030 Binary files /dev/null and b/icons/clothing/suits/poncho/colourable.dmi differ diff --git a/icons/clothing/suit/poncho/eng.dmi b/icons/clothing/suits/poncho/eng.dmi similarity index 100% rename from icons/clothing/suit/poncho/eng.dmi rename to icons/clothing/suits/poncho/eng.dmi diff --git a/icons/clothing/suit/poncho/green.dmi b/icons/clothing/suits/poncho/green.dmi similarity index 100% rename from icons/clothing/suit/poncho/green.dmi rename to icons/clothing/suits/poncho/green.dmi diff --git a/icons/clothing/suit/poncho/med.dmi b/icons/clothing/suits/poncho/med.dmi similarity index 100% rename from icons/clothing/suit/poncho/med.dmi rename to icons/clothing/suits/poncho/med.dmi diff --git a/icons/clothing/suit/poncho/purple.dmi b/icons/clothing/suits/poncho/purple.dmi similarity index 100% rename from icons/clothing/suit/poncho/purple.dmi rename to icons/clothing/suits/poncho/purple.dmi diff --git a/icons/clothing/suit/poncho/red.dmi b/icons/clothing/suits/poncho/red.dmi similarity index 100% rename from icons/clothing/suit/poncho/red.dmi rename to icons/clothing/suits/poncho/red.dmi diff --git a/icons/clothing/suit/poncho/sec.dmi b/icons/clothing/suits/poncho/sec.dmi similarity index 100% rename from icons/clothing/suit/poncho/sec.dmi rename to icons/clothing/suits/poncho/sec.dmi diff --git a/icons/clothing/suit/rad_suit.dmi b/icons/clothing/suits/rad_suit.dmi similarity index 100% rename from icons/clothing/suit/rad_suit.dmi rename to icons/clothing/suits/rad_suit.dmi diff --git a/icons/clothing/suit/redtag.dmi b/icons/clothing/suits/redtag.dmi similarity index 100% rename from icons/clothing/suit/redtag.dmi rename to icons/clothing/suits/redtag.dmi diff --git a/icons/clothing/suits/rough_robe.dmi b/icons/clothing/suits/rough_robe.dmi new file mode 100644 index 000000000000..4edd5ca4901f Binary files /dev/null and b/icons/clothing/suits/rough_robe.dmi differ diff --git a/icons/clothing/suit/santa.dmi b/icons/clothing/suits/santa.dmi similarity index 100% rename from icons/clothing/suit/santa.dmi rename to icons/clothing/suits/santa.dmi diff --git a/icons/clothing/suits/sherwani.dmi b/icons/clothing/suits/sherwani.dmi new file mode 100644 index 000000000000..4f8ccfb0c181 Binary files /dev/null and b/icons/clothing/suits/sherwani.dmi differ diff --git a/icons/clothing/suits/sleeved_robe.dmi b/icons/clothing/suits/sleeved_robe.dmi new file mode 100644 index 000000000000..6895f94a926a Binary files /dev/null and b/icons/clothing/suits/sleeved_robe.dmi differ diff --git a/icons/clothing/suit/space/syndicate/black.dmi b/icons/clothing/suits/space/syndicate/black.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/black.dmi rename to icons/clothing/suits/space/syndicate/black.dmi diff --git a/icons/clothing/suit/space/syndicate/blackblue.dmi b/icons/clothing/suits/space/syndicate/blackblue.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blackblue.dmi rename to icons/clothing/suits/space/syndicate/blackblue.dmi diff --git a/icons/clothing/suit/space/syndicate/blackengie.dmi b/icons/clothing/suits/space/syndicate/blackengie.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blackengie.dmi rename to icons/clothing/suits/space/syndicate/blackengie.dmi diff --git a/icons/clothing/suit/space/syndicate/blackgreen.dmi b/icons/clothing/suits/space/syndicate/blackgreen.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blackgreen.dmi rename to icons/clothing/suits/space/syndicate/blackgreen.dmi diff --git a/icons/clothing/suit/space/syndicate/blackmed.dmi b/icons/clothing/suits/space/syndicate/blackmed.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blackmed.dmi rename to icons/clothing/suits/space/syndicate/blackmed.dmi diff --git a/icons/clothing/suit/space/syndicate/blackorange.dmi b/icons/clothing/suits/space/syndicate/blackorange.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blackorange.dmi rename to icons/clothing/suits/space/syndicate/blackorange.dmi diff --git a/icons/clothing/suit/space/syndicate/blackred.dmi b/icons/clothing/suits/space/syndicate/blackred.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blackred.dmi rename to icons/clothing/suits/space/syndicate/blackred.dmi diff --git a/icons/clothing/suit/space/syndicate/blue.dmi b/icons/clothing/suits/space/syndicate/blue.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/blue.dmi rename to icons/clothing/suits/space/syndicate/blue.dmi diff --git a/icons/clothing/suit/space/syndicate/darkgreen.dmi b/icons/clothing/suits/space/syndicate/darkgreen.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/darkgreen.dmi rename to icons/clothing/suits/space/syndicate/darkgreen.dmi diff --git a/icons/clothing/suit/space/syndicate/green.dmi b/icons/clothing/suits/space/syndicate/green.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/green.dmi rename to icons/clothing/suits/space/syndicate/green.dmi diff --git a/icons/clothing/suit/space/syndicate/orange.dmi b/icons/clothing/suits/space/syndicate/orange.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/orange.dmi rename to icons/clothing/suits/space/syndicate/orange.dmi diff --git a/icons/clothing/suit/space/syndicate/red.dmi b/icons/clothing/suits/space/syndicate/red.dmi similarity index 100% rename from icons/clothing/suit/space/syndicate/red.dmi rename to icons/clothing/suits/space/syndicate/red.dmi diff --git a/icons/clothing/suit/straightjacket.dmi b/icons/clothing/suits/straightjacket.dmi similarity index 100% rename from icons/clothing/suit/straightjacket.dmi rename to icons/clothing/suits/straightjacket.dmi diff --git a/icons/clothing/suits/suit_black.dmi b/icons/clothing/suits/suit_black.dmi new file mode 100644 index 000000000000..eeff9e3fc164 Binary files /dev/null and b/icons/clothing/suits/suit_black.dmi differ diff --git a/icons/clothing/suits/suit_black_female.dmi b/icons/clothing/suits/suit_black_female.dmi new file mode 100644 index 000000000000..8a4e3fb0dc64 Binary files /dev/null and b/icons/clothing/suits/suit_black_female.dmi differ diff --git a/icons/clothing/suits/suit_executive.dmi b/icons/clothing/suits/suit_executive.dmi new file mode 100644 index 000000000000..e924e31f9175 Binary files /dev/null and b/icons/clothing/suits/suit_executive.dmi differ diff --git a/icons/clothing/suits/suit_executive_female.dmi b/icons/clothing/suits/suit_executive_female.dmi new file mode 100644 index 000000000000..3ee0c82ca739 Binary files /dev/null and b/icons/clothing/suits/suit_executive_female.dmi differ diff --git a/icons/clothing/suits/suit_fiend.dmi b/icons/clothing/suits/suit_fiend.dmi new file mode 100644 index 000000000000..8e490ee7d130 Binary files /dev/null and b/icons/clothing/suits/suit_fiend.dmi differ diff --git a/icons/clothing/suits/suit_green.dmi b/icons/clothing/suits/suit_green.dmi new file mode 100644 index 000000000000..48ccb4ada309 Binary files /dev/null and b/icons/clothing/suits/suit_green.dmi differ diff --git a/icons/clothing/suits/suit_skrell.dmi b/icons/clothing/suits/suit_skrell.dmi new file mode 100644 index 000000000000..6eb88b307824 Binary files /dev/null and b/icons/clothing/suits/suit_skrell.dmi differ diff --git a/icons/clothing/suits/suit_teal.dmi b/icons/clothing/suits/suit_teal.dmi new file mode 100644 index 000000000000..04171b7a5375 Binary files /dev/null and b/icons/clothing/suits/suit_teal.dmi differ diff --git a/icons/clothing/suits/tdgreen.dmi b/icons/clothing/suits/tdgreen.dmi new file mode 100644 index 000000000000..3844f88563de Binary files /dev/null and b/icons/clothing/suits/tdgreen.dmi differ diff --git a/icons/clothing/suit/tdred.dmi b/icons/clothing/suits/tdred.dmi similarity index 88% rename from icons/clothing/suit/tdred.dmi rename to icons/clothing/suits/tdred.dmi index 8c609ce85079..d14e9085b3a6 100644 Binary files a/icons/clothing/suit/tdred.dmi and b/icons/clothing/suits/tdred.dmi differ diff --git a/icons/clothing/suits/thawb.dmi b/icons/clothing/suits/thawb.dmi new file mode 100644 index 000000000000..bbf1341140c6 Binary files /dev/null and b/icons/clothing/suits/thawb.dmi differ diff --git a/icons/clothing/suits/tracksuit/black.dmi b/icons/clothing/suits/tracksuit/black.dmi new file mode 100644 index 000000000000..c6feee4b3367 Binary files /dev/null and b/icons/clothing/suits/tracksuit/black.dmi differ diff --git a/icons/clothing/suits/tracksuit/blue.dmi b/icons/clothing/suits/tracksuit/blue.dmi new file mode 100644 index 000000000000..de619284a310 Binary files /dev/null and b/icons/clothing/suits/tracksuit/blue.dmi differ diff --git a/icons/clothing/suits/tracksuit/navy.dmi b/icons/clothing/suits/tracksuit/navy.dmi new file mode 100644 index 000000000000..02f624915894 Binary files /dev/null and b/icons/clothing/suits/tracksuit/navy.dmi differ diff --git a/icons/clothing/suit/tracksuit/red.dmi b/icons/clothing/suits/tracksuit/red.dmi similarity index 85% rename from icons/clothing/suit/tracksuit/red.dmi rename to icons/clothing/suits/tracksuit/red.dmi index b1504f2fe0e5..6ae662cbd990 100644 Binary files a/icons/clothing/suit/tracksuit/red.dmi and b/icons/clothing/suits/tracksuit/red.dmi differ diff --git a/icons/clothing/suit/vest.dmi b/icons/clothing/suits/vest.dmi similarity index 100% rename from icons/clothing/suit/vest.dmi rename to icons/clothing/suits/vest.dmi diff --git a/icons/clothing/suit/w40k.dmi b/icons/clothing/suits/w40k.dmi similarity index 100% rename from icons/clothing/suit/w40k.dmi rename to icons/clothing/suits/w40k.dmi diff --git a/icons/clothing/suit/warden.dmi b/icons/clothing/suits/warden.dmi similarity index 100% rename from icons/clothing/suit/warden.dmi rename to icons/clothing/suits/warden.dmi diff --git a/icons/clothing/suits/wintercoat/atmos.dmi b/icons/clothing/suits/wintercoat/atmos.dmi new file mode 100644 index 000000000000..af2d55e4fee3 Binary files /dev/null and b/icons/clothing/suits/wintercoat/atmos.dmi differ diff --git a/icons/clothing/suits/wintercoat/captain.dmi b/icons/clothing/suits/wintercoat/captain.dmi new file mode 100644 index 000000000000..44a37e6c66c2 Binary files /dev/null and b/icons/clothing/suits/wintercoat/captain.dmi differ diff --git a/icons/clothing/suits/wintercoat/cargo.dmi b/icons/clothing/suits/wintercoat/cargo.dmi new file mode 100644 index 000000000000..716e7883b9bf Binary files /dev/null and b/icons/clothing/suits/wintercoat/cargo.dmi differ diff --git a/icons/clothing/suits/wintercoat/coat.dmi b/icons/clothing/suits/wintercoat/coat.dmi new file mode 100644 index 000000000000..436c64a52c25 Binary files /dev/null and b/icons/clothing/suits/wintercoat/coat.dmi differ diff --git a/icons/clothing/suits/wintercoat/eng.dmi b/icons/clothing/suits/wintercoat/eng.dmi new file mode 100644 index 000000000000..62bc0be9fea8 Binary files /dev/null and b/icons/clothing/suits/wintercoat/eng.dmi differ diff --git a/icons/clothing/suits/wintercoat/hydro.dmi b/icons/clothing/suits/wintercoat/hydro.dmi new file mode 100644 index 000000000000..a62dbc8dcf8d Binary files /dev/null and b/icons/clothing/suits/wintercoat/hydro.dmi differ diff --git a/icons/clothing/suits/wintercoat/med.dmi b/icons/clothing/suits/wintercoat/med.dmi new file mode 100644 index 000000000000..fb41af13a426 Binary files /dev/null and b/icons/clothing/suits/wintercoat/med.dmi differ diff --git a/icons/clothing/suits/wintercoat/mining.dmi b/icons/clothing/suits/wintercoat/mining.dmi new file mode 100644 index 000000000000..3498b2559845 Binary files /dev/null and b/icons/clothing/suits/wintercoat/mining.dmi differ diff --git a/icons/clothing/suits/wintercoat/parka.dmi b/icons/clothing/suits/wintercoat/parka.dmi new file mode 100644 index 000000000000..acc4af648701 Binary files /dev/null and b/icons/clothing/suits/wintercoat/parka.dmi differ diff --git a/icons/clothing/suits/wintercoat/sci.dmi b/icons/clothing/suits/wintercoat/sci.dmi new file mode 100644 index 000000000000..d98ad017fb26 Binary files /dev/null and b/icons/clothing/suits/wintercoat/sci.dmi differ diff --git a/icons/clothing/suits/wintercoat/sec.dmi b/icons/clothing/suits/wintercoat/sec.dmi new file mode 100644 index 000000000000..7bd7f3236d5e Binary files /dev/null and b/icons/clothing/suits/wintercoat/sec.dmi differ diff --git a/icons/clothing/suit/wizard/fake.dmi b/icons/clothing/suits/wizard/fake.dmi similarity index 100% rename from icons/clothing/suit/wizard/fake.dmi rename to icons/clothing/suits/wizard/fake.dmi diff --git a/icons/clothing/suit/wizard/gentleman.dmi b/icons/clothing/suits/wizard/gentleman.dmi similarity index 100% rename from icons/clothing/suit/wizard/gentleman.dmi rename to icons/clothing/suits/wizard/gentleman.dmi diff --git a/icons/clothing/suit/wizard/magusblue.dmi b/icons/clothing/suits/wizard/magusblue.dmi similarity index 100% rename from icons/clothing/suit/wizard/magusblue.dmi rename to icons/clothing/suits/wizard/magusblue.dmi diff --git a/icons/clothing/suit/wizard/magusred.dmi b/icons/clothing/suits/wizard/magusred.dmi similarity index 100% rename from icons/clothing/suit/wizard/magusred.dmi rename to icons/clothing/suits/wizard/magusred.dmi diff --git a/icons/clothing/suit/wizard/marisa.dmi b/icons/clothing/suits/wizard/marisa.dmi similarity index 100% rename from icons/clothing/suit/wizard/marisa.dmi rename to icons/clothing/suits/wizard/marisa.dmi diff --git a/icons/clothing/suit/wizard/psy.dmi b/icons/clothing/suits/wizard/psy.dmi similarity index 100% rename from icons/clothing/suit/wizard/psy.dmi rename to icons/clothing/suits/wizard/psy.dmi diff --git a/icons/clothing/suit/wizard/red.dmi b/icons/clothing/suits/wizard/red.dmi similarity index 100% rename from icons/clothing/suit/wizard/red.dmi rename to icons/clothing/suits/wizard/red.dmi diff --git a/icons/clothing/suit/wizard/servant/caretaker.dmi b/icons/clothing/suits/wizard/servant/caretaker.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/caretaker.dmi rename to icons/clothing/suits/wizard/servant/caretaker.dmi diff --git a/icons/clothing/suit/wizard/servant/champion.dmi b/icons/clothing/suits/wizard/servant/champion.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/champion.dmi rename to icons/clothing/suits/wizard/servant/champion.dmi diff --git a/icons/clothing/suit/wizard/servant/fiend_cowl.dmi b/icons/clothing/suits/wizard/servant/fiend_cowl.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/fiend_cowl.dmi rename to icons/clothing/suits/wizard/servant/fiend_cowl.dmi diff --git a/icons/clothing/suit/wizard/servant/fiend_robe.dmi b/icons/clothing/suits/wizard/servant/fiend_robe.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/fiend_robe.dmi rename to icons/clothing/suits/wizard/servant/fiend_robe.dmi diff --git a/icons/clothing/suit/wizard/servant/inf_dress.dmi b/icons/clothing/suits/wizard/servant/inf_dress.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/inf_dress.dmi rename to icons/clothing/suits/wizard/servant/inf_dress.dmi diff --git a/icons/clothing/suit/wizard/servant/inf_suit.dmi b/icons/clothing/suits/wizard/servant/inf_suit.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/inf_suit.dmi rename to icons/clothing/suits/wizard/servant/inf_suit.dmi diff --git a/icons/clothing/suit/wizard/servant/overseer.dmi b/icons/clothing/suits/wizard/servant/overseer.dmi similarity index 100% rename from icons/clothing/suit/wizard/servant/overseer.dmi rename to icons/clothing/suits/wizard/servant/overseer.dmi diff --git a/icons/clothing/suit/wizard/wizard.dmi b/icons/clothing/suits/wizard/wizard.dmi similarity index 100% rename from icons/clothing/suit/wizard/wizard.dmi rename to icons/clothing/suits/wizard/wizard.dmi diff --git a/icons/clothing/suit/xeno.dmi b/icons/clothing/suits/xeno.dmi similarity index 100% rename from icons/clothing/suit/xeno.dmi rename to icons/clothing/suits/xeno.dmi diff --git a/icons/clothing/under/fated_robes.dmi b/icons/clothing/under/fated_robes.dmi deleted file mode 100644 index ebc49679ca1b..000000000000 Binary files a/icons/clothing/under/fated_robes.dmi and /dev/null differ diff --git a/icons/clothing/uniform_assistant_formal.dmi b/icons/clothing/uniform_assistant_formal.dmi new file mode 100644 index 000000000000..3c40f9d620a8 Binary files /dev/null and b/icons/clothing/uniform_assistant_formal.dmi differ diff --git a/icons/clothing/uniform_captain_formal.dmi b/icons/clothing/uniform_captain_formal.dmi new file mode 100644 index 000000000000..03ee3789a1be Binary files /dev/null and b/icons/clothing/uniform_captain_formal.dmi differ diff --git a/icons/clothing/uniform_dispatch.dmi b/icons/clothing/uniform_dispatch.dmi new file mode 100644 index 000000000000..eaead9dc9f3f Binary files /dev/null and b/icons/clothing/uniform_dispatch.dmi differ diff --git a/icons/clothing/uniform_hop_whimsy.dmi b/icons/clothing/uniform_hop_whimsy.dmi new file mode 100644 index 000000000000..09c8bddbfe54 Binary files /dev/null and b/icons/clothing/uniform_hop_whimsy.dmi differ diff --git a/icons/clothing/uniform_hos_formal.dmi b/icons/clothing/uniform_hos_formal.dmi new file mode 100644 index 000000000000..14bac863766d Binary files /dev/null and b/icons/clothing/uniform_hos_formal.dmi differ diff --git a/icons/clothing/uniform_mechanic.dmi b/icons/clothing/uniform_mechanic.dmi new file mode 100644 index 000000000000..b4cb22321ba4 Binary files /dev/null and b/icons/clothing/uniform_mechanic.dmi differ diff --git a/icons/clothing/uniform_officer_dress.dmi b/icons/clothing/uniform_officer_dress.dmi new file mode 100644 index 000000000000..4055f8bf42f0 Binary files /dev/null and b/icons/clothing/uniform_officer_dress.dmi differ diff --git a/icons/clothing/uniform_rd_alt.dmi b/icons/clothing/uniform_rd_alt.dmi new file mode 100644 index 000000000000..009875a2ed45 Binary files /dev/null and b/icons/clothing/uniform_rd_alt.dmi differ diff --git a/icons/clothing/uniform_swat.dmi b/icons/clothing/uniform_swat.dmi new file mode 100644 index 000000000000..93fd89ab227c Binary files /dev/null and b/icons/clothing/uniform_swat.dmi differ diff --git a/icons/default_lobby.png b/icons/default_lobby.png index d13ebcf6f633..e554e79dd27e 100644 Binary files a/icons/default_lobby.png and b/icons/default_lobby.png differ diff --git a/icons/effects/128x48.dmi b/icons/effects/128x48.dmi index 71038ffdbf89..3d7bbc404ae1 100644 Binary files a/icons/effects/128x48.dmi and b/icons/effects/128x48.dmi differ diff --git a/icons/effects/32x32.dmi b/icons/effects/32x32.dmi new file mode 100644 index 000000000000..15c578671764 Binary files /dev/null and b/icons/effects/32x32.dmi differ diff --git a/icons/effects/64x48.dmi b/icons/effects/64x48.dmi new file mode 100644 index 000000000000..2f854b0403d5 Binary files /dev/null and b/icons/effects/64x48.dmi differ diff --git a/icons/effects/64x64.dmi b/icons/effects/64x64.dmi new file mode 100644 index 000000000000..5ebf9ff164eb Binary files /dev/null and b/icons/effects/64x64.dmi differ diff --git a/icons/effects/airlock_helper.dmi b/icons/effects/airlock_helper.dmi new file mode 100644 index 000000000000..dcf258f931ae Binary files /dev/null and b/icons/effects/airlock_helper.dmi differ diff --git a/icons/effects/alpha_mask.dmi b/icons/effects/alpha_mask.dmi new file mode 100644 index 000000000000..020370f1662b Binary files /dev/null and b/icons/effects/alpha_mask.dmi differ diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index dffaf9093387..c61006e278fc 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi index e1966e9bb5ae..3642e8ed8f4d 100644 Binary files a/icons/effects/crayondecal.dmi and b/icons/effects/crayondecal.dmi differ diff --git a/icons/effects/decals/plant_remains.dmi b/icons/effects/decals/plant_remains.dmi new file mode 100644 index 000000000000..65ab5cba5a02 Binary files /dev/null and b/icons/effects/decals/plant_remains.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 1a2741d3a539..a43e06941625 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/genetics.dmi b/icons/effects/genetics.dmi index 8e31fea96135..8ec52b23f58e 100644 Binary files a/icons/effects/genetics.dmi and b/icons/effects/genetics.dmi differ diff --git a/icons/effects/geyser.dmi b/icons/effects/geyser.dmi new file mode 100644 index 000000000000..1e7502d3dedc Binary files /dev/null and b/icons/effects/geyser.dmi differ diff --git a/icons/effects/hay.dmi b/icons/effects/hay.dmi new file mode 100644 index 000000000000..47c16d24770d Binary files /dev/null and b/icons/effects/hay.dmi differ diff --git a/icons/effects/height_shadow.dmi b/icons/effects/height_shadow.dmi new file mode 100644 index 000000000000..c025e08f4e39 Binary files /dev/null and b/icons/effects/height_shadow.dmi differ diff --git a/icons/effects/impact_effects.dmi b/icons/effects/impact_effects.dmi new file mode 100644 index 000000000000..a3239f69fe2f Binary files /dev/null and b/icons/effects/impact_effects.dmi differ diff --git a/icons/effects/landmarks.dmi b/icons/effects/landmarks.dmi index 356074d148fd..28317726409f 100644 Binary files a/icons/effects/landmarks.dmi and b/icons/effects/landmarks.dmi differ diff --git a/icons/effects/lighting_overlay.dmi b/icons/effects/lighting_overlay.dmi index 3affd2339c17..b2c14395dd2e 100644 Binary files a/icons/effects/lighting_overlay.dmi and b/icons/effects/lighting_overlay.dmi differ diff --git a/icons/effects/liquids.dmi b/icons/effects/liquids.dmi index 4712a35a852b..7cdf5d1b0067 100644 Binary files a/icons/effects/liquids.dmi and b/icons/effects/liquids.dmi differ diff --git a/icons/effects/map_effects.dmi b/icons/effects/map_effects.dmi new file mode 100644 index 000000000000..8b2dc22e3c48 Binary files /dev/null and b/icons/effects/map_effects.dmi differ diff --git a/icons/effects/markers.dmi b/icons/effects/markers.dmi new file mode 100644 index 000000000000..d3a3912b85cc Binary files /dev/null and b/icons/effects/markers.dmi differ diff --git a/icons/effects/mouse_pointers/examine_pointer.dmi b/icons/effects/mouse_pointers/examine_pointer.dmi new file mode 100644 index 000000000000..a565a554fa7d Binary files /dev/null and b/icons/effects/mouse_pointers/examine_pointer.dmi differ diff --git a/icons/effects/projectiles.dmi b/icons/effects/projectiles.dmi deleted file mode 100644 index 3f352097c042..000000000000 Binary files a/icons/effects/projectiles.dmi and /dev/null differ diff --git a/icons/effects/projectiles/impact.dmi b/icons/effects/projectiles/impact.dmi new file mode 100644 index 000000000000..de5a8656d381 Binary files /dev/null and b/icons/effects/projectiles/impact.dmi differ diff --git a/icons/effects/projectiles/muzzle.dmi b/icons/effects/projectiles/muzzle.dmi new file mode 100644 index 000000000000..b09e1c1755c2 Binary files /dev/null and b/icons/effects/projectiles/muzzle.dmi differ diff --git a/icons/effects/projectiles/tracer.dmi b/icons/effects/projectiles/tracer.dmi new file mode 100644 index 000000000000..28d6f4b9028f Binary files /dev/null and b/icons/effects/projectiles/tracer.dmi differ diff --git a/icons/effects/projectiles/trail.dmi b/icons/effects/projectiles/trail.dmi new file mode 100644 index 000000000000..4e058a3f1bfd Binary files /dev/null and b/icons/effects/projectiles/trail.dmi differ diff --git a/icons/effects/sparkles.dmi b/icons/effects/sparkles.dmi new file mode 100644 index 000000000000..904a389884af Binary files /dev/null and b/icons/effects/sparkles.dmi differ diff --git a/icons/effects/species.dmi b/icons/effects/species.dmi index 8c231b9b68aa..c732f54cafd8 100644 Binary files a/icons/effects/species.dmi and b/icons/effects/species.dmi differ diff --git a/icons/effects/staminabar.dmi b/icons/effects/staminabar.dmi new file mode 100644 index 000000000000..7e93f98b5ce1 Binary files /dev/null and b/icons/effects/staminabar.dmi differ diff --git a/icons/effects/status.dmi b/icons/effects/status.dmi new file mode 100644 index 000000000000..ace349c3cf68 Binary files /dev/null and b/icons/effects/status.dmi differ diff --git a/icons/effects/weather.dmi b/icons/effects/weather.dmi new file mode 100644 index 000000000000..aa4438a638dc Binary files /dev/null and b/icons/effects/weather.dmi differ diff --git a/icons/mecha/ballistic_shield.dmi b/icons/mecha/ballistic_shield.dmi new file mode 100644 index 000000000000..d3e0a1ba4317 Binary files /dev/null and b/icons/mecha/ballistic_shield.dmi differ diff --git a/icons/mecha/mech_decals.dmi b/icons/mecha/mech_decals.dmi index a7c855887030..b0de8d7e8eb2 100644 Binary files a/icons/mecha/mech_decals.dmi and b/icons/mecha/mech_decals.dmi differ diff --git a/icons/mecha/mech_equipment.dmi b/icons/mecha/mech_equipment.dmi index dd8ada092258..6f3198ad5351 100644 Binary files a/icons/mecha/mech_equipment.dmi and b/icons/mecha/mech_equipment.dmi differ diff --git a/icons/mecha/mech_hud.dmi b/icons/mecha/mech_hud.dmi index 9755c384712d..e9536f320452 100644 Binary files a/icons/mecha/mech_hud.dmi and b/icons/mecha/mech_hud.dmi differ diff --git a/icons/mecha/mech_parts.dmi b/icons/mecha/mech_parts.dmi index b394664e7592..20d69ca90c85 100644 Binary files a/icons/mecha/mech_parts.dmi and b/icons/mecha/mech_parts.dmi differ diff --git a/icons/mecha/mech_parts_held.dmi b/icons/mecha/mech_parts_held.dmi index 46be55a600c0..0276b3fb0aa6 100644 Binary files a/icons/mecha/mech_parts_held.dmi and b/icons/mecha/mech_parts_held.dmi differ diff --git a/icons/mecha/mech_weapon_overlays.dmi b/icons/mecha/mech_weapon_overlays.dmi index 080bef50bec0..d79dab95f748 100644 Binary files a/icons/mecha/mech_weapon_overlays.dmi and b/icons/mecha/mech_weapon_overlays.dmi differ diff --git a/icons/mecha/mecha_preview.dmi b/icons/mecha/mecha_preview.dmi new file mode 100644 index 000000000000..98f4a9985dee Binary files /dev/null and b/icons/mecha/mecha_preview.dmi differ diff --git a/icons/misc/beach.dmi b/icons/misc/beach.dmi index 09bee586d7b8..847054aa8ce8 100644 Binary files a/icons/misc/beach.dmi and b/icons/misc/beach.dmi differ diff --git a/icons/misc/holomap_markers.dmi b/icons/misc/holomap_markers.dmi new file mode 100644 index 000000000000..3ea32c120d0e Binary files /dev/null and b/icons/misc/holomap_markers.dmi differ diff --git a/icons/misc/security_state.dmi b/icons/misc/security_state.dmi index ca5d0f05ed7a..aff829cdb6c3 100644 Binary files a/icons/misc/security_state.dmi and b/icons/misc/security_state.dmi differ diff --git a/icons/mob/bandage.dmi b/icons/mob/bandage.dmi index bab279f6c1d1..807318555fd6 100644 Binary files a/icons/mob/bandage.dmi and b/icons/mob/bandage.dmi differ diff --git a/icons/mob/blob.dmi b/icons/mob/blob.dmi deleted file mode 100644 index f89d667fb0f4..000000000000 Binary files a/icons/mob/blob.dmi and /dev/null differ diff --git a/icons/mob/custom_items_mob.dmi b/icons/mob/custom_items_mob.dmi deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/icons/mob/footprints/footprints.dmi b/icons/mob/footprints/footprints.dmi new file mode 100644 index 000000000000..2d9699e82c8d Binary files /dev/null and b/icons/mob/footprints/footprints.dmi differ diff --git a/icons/mob/footprints/footprints_paw.dmi b/icons/mob/footprints/footprints_paw.dmi new file mode 100644 index 000000000000..08fac62a016c Binary files /dev/null and b/icons/mob/footprints/footprints_paw.dmi differ diff --git a/icons/mob/footprints/footprints_snake.dmi b/icons/mob/footprints/footprints_snake.dmi new file mode 100644 index 000000000000..6e913803eb12 Binary files /dev/null and b/icons/mob/footprints/footprints_snake.dmi differ diff --git a/icons/mob/footprints/footprints_trail.dmi b/icons/mob/footprints/footprints_trail.dmi new file mode 100644 index 000000000000..944ed4e175b4 Binary files /dev/null and b/icons/mob/footprints/footprints_trail.dmi differ diff --git a/icons/mob/footprints/footprints_wheelchair.dmi b/icons/mob/footprints/footprints_wheelchair.dmi new file mode 100644 index 000000000000..4a2e800cf76b Binary files /dev/null and b/icons/mob/footprints/footprints_wheelchair.dmi differ diff --git a/icons/mob/hair_gradients.dmi b/icons/mob/hair_gradients.dmi new file mode 100644 index 000000000000..1a3c330355e4 Binary files /dev/null and b/icons/mob/hair_gradients.dmi differ diff --git a/icons/mob/holder_complex.dmi b/icons/mob/holder_complex.dmi deleted file mode 100644 index 0c0235da0286..000000000000 Binary files a/icons/mob/holder_complex.dmi and /dev/null differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi deleted file mode 100644 index 16d52971300f..000000000000 Binary files a/icons/mob/hud.dmi and /dev/null differ diff --git a/icons/mob/hud_med.dmi b/icons/mob/hud_med.dmi deleted file mode 100644 index 705886a5490f..000000000000 Binary files a/icons/mob/hud_med.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi deleted file mode 100644 index ce332e9bc4c6..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_rook.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_rook.dmi deleted file mode 100644 index fec74ac47577..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/bishop/bishop_rook.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi deleted file mode 100644 index 7e075269a42f..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_titan.dmi b/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_titan.dmi deleted file mode 100644 index eb095f62fff2..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_titan.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/morgan/morgan_main.dmi b/icons/mob/human_races/cyberlimbs/morgan/morgan_main.dmi index 0872916c042c..dfa94b94d13a 100644 Binary files a/icons/mob/human_races/cyberlimbs/morgan/morgan_main.dmi and b/icons/mob/human_races/cyberlimbs/morgan/morgan_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi deleted file mode 100644 index 25d22c49d803..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_mantis.dmi b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_mantis.dmi deleted file mode 100644 index c01392676948..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_mantis.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi b/icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi deleted file mode 100644 index 66a871d1b07d..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/robotic.dmi b/icons/mob/human_races/cyberlimbs/robotic.dmi index e98d2e351294..2c149716cd2f 100644 Binary files a/icons/mob/human_races/cyberlimbs/robotic.dmi and b/icons/mob/human_races/cyberlimbs/robotic.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/shellguard/shellguard_main.dmi b/icons/mob/human_races/cyberlimbs/shellguard/shellguard_main.dmi deleted file mode 100644 index f27b5246b4f6..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/shellguard/shellguard_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/utility/body.dmi b/icons/mob/human_races/cyberlimbs/utility/body.dmi deleted file mode 100644 index 6e9595e55b3d..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/utility/body.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/utility/markings.dmi b/icons/mob/human_races/cyberlimbs/utility/markings.dmi deleted file mode 100644 index b824b5efc474..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/utility/markings.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/utility/preview.dmi b/icons/mob/human_races/cyberlimbs/utility/preview.dmi deleted file mode 100644 index ef13db4720dc..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/utility/preview.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi b/icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi deleted file mode 100644 index 07446b598a88..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi deleted file mode 100644 index a077b5239dee..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi b/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi deleted file mode 100644 index eda9969ad74a..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/xion/xion_econo.dmi b/icons/mob/human_races/cyberlimbs/xion/xion_econo.dmi deleted file mode 100644 index f6d11e4ff37c..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/xion/xion_econo.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/xion/xion_main.dmi b/icons/mob/human_races/cyberlimbs/xion/xion_main.dmi deleted file mode 100644 index e07e66e3e0b4..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/xion/xion_main.dmi and /dev/null differ diff --git a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_spirit.dmi b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_spirit.dmi deleted file mode 100644 index 706eee9c1998..000000000000 Binary files a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_spirit.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/blueforged/body.dmi b/icons/mob/human_races/species/blueforged/body.dmi new file mode 100644 index 000000000000..29d0e3aa929b Binary files /dev/null and b/icons/mob/human_races/species/blueforged/body.dmi differ diff --git a/icons/mob/human_races/species/blueforged/eyes.dmi b/icons/mob/human_races/species/blueforged/eyes.dmi new file mode 100644 index 000000000000..f502872b662a Binary files /dev/null and b/icons/mob/human_races/species/blueforged/eyes.dmi differ diff --git a/icons/mob/human_races/species/blueforged/organs.dmi b/icons/mob/human_races/species/blueforged/organs.dmi new file mode 100644 index 000000000000..6e7ab69d1b5d Binary files /dev/null and b/icons/mob/human_races/species/blueforged/organs.dmi differ diff --git a/icons/mob/human_races/species/default_bandages.dmi b/icons/mob/human_races/species/default_bandages.dmi new file mode 100644 index 000000000000..8044fdc4a946 Binary files /dev/null and b/icons/mob/human_races/species/default_bandages.dmi differ diff --git a/icons/mob/human_races/species/default_cosmetics.dmi b/icons/mob/human_races/species/default_cosmetics.dmi new file mode 100644 index 000000000000..f2e9eb20b07d Binary files /dev/null and b/icons/mob/human_races/species/default_cosmetics.dmi differ diff --git a/icons/mob/human_races/species/default_damage_overlays.dmi b/icons/mob/human_races/species/default_damage_overlays.dmi new file mode 100644 index 000000000000..76110a61235e Binary files /dev/null and b/icons/mob/human_races/species/default_damage_overlays.dmi differ diff --git a/icons/mob/human_races/species/default_ears.dmi b/icons/mob/human_races/species/default_ears.dmi new file mode 100644 index 000000000000..5736234bb3de Binary files /dev/null and b/icons/mob/human_races/species/default_ears.dmi differ diff --git a/icons/mob/human_races/species/default_frills.dmi b/icons/mob/human_races/species/default_frills.dmi new file mode 100644 index 000000000000..4e445d46e060 Binary files /dev/null and b/icons/mob/human_races/species/default_frills.dmi differ diff --git a/icons/mob/human_races/species/default_horns.dmi b/icons/mob/human_races/species/default_horns.dmi new file mode 100644 index 000000000000..4e445d46e060 Binary files /dev/null and b/icons/mob/human_races/species/default_horns.dmi differ diff --git a/icons/mob/human_races/species/default_markings.dmi b/icons/mob/human_races/species/default_markings.dmi index d38fccc8db65..f9af30b39260 100644 Binary files a/icons/mob/human_races/species/default_markings.dmi and b/icons/mob/human_races/species/default_markings.dmi differ diff --git a/icons/mob/human_races/species/default_scars.dmi b/icons/mob/human_races/species/default_scars.dmi new file mode 100644 index 000000000000..4122df3ba071 Binary files /dev/null and b/icons/mob/human_races/species/default_scars.dmi differ diff --git a/icons/mob/human_races/species/default_tail.dmi b/icons/mob/human_races/species/default_tail.dmi new file mode 100644 index 000000000000..2b459fdde17e Binary files /dev/null and b/icons/mob/human_races/species/default_tail.dmi differ diff --git a/icons/mob/human_races/species/default_tattoos.dmi b/icons/mob/human_races/species/default_tattoos.dmi new file mode 100644 index 000000000000..1194947421f2 Binary files /dev/null and b/icons/mob/human_races/species/default_tattoos.dmi differ diff --git a/icons/mob/human_races/species/golem/body.dmi b/icons/mob/human_races/species/golem/body.dmi index d480ec4d28fc..4a7e14a05b82 100644 Binary files a/icons/mob/human_races/species/golem/body.dmi and b/icons/mob/human_races/species/golem/body.dmi differ diff --git a/icons/mob/human_races/species/human/blood_mask.dmi b/icons/mob/human_races/species/human/blood_overlays.dmi similarity index 100% rename from icons/mob/human_races/species/human/blood_mask.dmi rename to icons/mob/human_races/species/human/blood_overlays.dmi diff --git a/icons/mob/human_races/species/human/body.dmi b/icons/mob/human_races/species/human/body.dmi deleted file mode 100644 index 893555866ba4..000000000000 Binary files a/icons/mob/human_races/species/human/body.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/human/body_female.dmi b/icons/mob/human_races/species/human/body_female.dmi new file mode 100644 index 000000000000..e0dc8a7a036d Binary files /dev/null and b/icons/mob/human_races/species/human/body_female.dmi differ diff --git a/icons/mob/human_races/species/human/body_male.dmi b/icons/mob/human_races/species/human/body_male.dmi new file mode 100644 index 000000000000..7e030274282a Binary files /dev/null and b/icons/mob/human_races/species/human/body_male.dmi differ diff --git a/icons/mob/human_races/species/human/damage_mask.dmi b/icons/mob/human_races/species/human/damage_mask.dmi deleted file mode 100644 index db55b5a6b5dc..000000000000 Binary files a/icons/mob/human_races/species/human/damage_mask.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/human/damage_overlay.dmi b/icons/mob/human_races/species/human/damage_overlay.dmi deleted file mode 100644 index cb6bf82d98e9..000000000000 Binary files a/icons/mob/human_races/species/human/damage_overlay.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/human/deformed_body.dmi b/icons/mob/human_races/species/human/deformed_body.dmi deleted file mode 100644 index e622ef14b5a5..000000000000 Binary files a/icons/mob/human_races/species/human/deformed_body.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/human/deformed_body_female.dmi b/icons/mob/human_races/species/human/deformed_body_female.dmi new file mode 100644 index 000000000000..a1fa8ba191f5 Binary files /dev/null and b/icons/mob/human_races/species/human/deformed_body_female.dmi differ diff --git a/icons/mob/human_races/species/human/deformed_body_male.dmi b/icons/mob/human_races/species/human/deformed_body_male.dmi new file mode 100644 index 000000000000..7527d698a8b2 Binary files /dev/null and b/icons/mob/human_races/species/human/deformed_body_male.dmi differ diff --git a/icons/mob/human_races/species/human/facial.dmi b/icons/mob/human_races/species/human/facial.dmi index 25fde2d870da..d3e78a757bf6 100644 Binary files a/icons/mob/human_races/species/human/facial.dmi and b/icons/mob/human_races/species/human/facial.dmi differ diff --git a/icons/mob/human_races/species/human/hair.dmi b/icons/mob/human_races/species/human/hair.dmi index 459e4531714e..b9b095fa000d 100644 Binary files a/icons/mob/human_races/species/human/hair.dmi and b/icons/mob/human_races/species/human/hair.dmi differ diff --git a/icons/mob/human_races/species/human/skeleton.dmi b/icons/mob/human_races/species/human/skeleton.dmi index 1cedb1196f0d..5dffe35ad879 100644 Binary files a/icons/mob/human_races/species/human/skeleton.dmi and b/icons/mob/human_races/species/human/skeleton.dmi differ diff --git a/icons/mob/human_races/species/humanoid/body.dmi b/icons/mob/human_races/species/humanoid/body.dmi index 6e8a68669b21..65f0f5676da1 100644 Binary files a/icons/mob/human_races/species/humanoid/body.dmi and b/icons/mob/human_races/species/humanoid/body.dmi differ diff --git a/icons/mob/human_races/species/lips.dmi b/icons/mob/human_races/species/lips.dmi deleted file mode 100644 index 42e9e7f2b6f7..000000000000 Binary files a/icons/mob/human_races/species/lips.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/monkey/blood_mask.dmi b/icons/mob/human_races/species/monkey/blood_overlays.dmi similarity index 100% rename from icons/mob/human_races/species/monkey/blood_mask.dmi rename to icons/mob/human_races/species/monkey/blood_overlays.dmi diff --git a/icons/mob/human_races/species/monkey/damage_mask.dmi b/icons/mob/human_races/species/monkey/damage_mask.dmi deleted file mode 100644 index 4761f21fbd5b..000000000000 Binary files a/icons/mob/human_races/species/monkey/damage_mask.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/monkey/damage_overlays.dmi b/icons/mob/human_races/species/monkey/damage_overlays.dmi deleted file mode 100644 index 43d1f2c7a736..000000000000 Binary files a/icons/mob/human_races/species/monkey/damage_overlays.dmi and /dev/null differ diff --git a/icons/mob/human_races/species/monkey/holder.dmi b/icons/mob/human_races/species/monkey/holder.dmi new file mode 100644 index 000000000000..618974e54760 Binary files /dev/null and b/icons/mob/human_races/species/monkey/holder.dmi differ diff --git a/icons/mob/human_races/species/monkey/monkey_body.dmi b/icons/mob/human_races/species/monkey/monkey_body.dmi index e9c497331cdf..37d59e1ceeba 100644 Binary files a/icons/mob/human_races/species/monkey/monkey_body.dmi and b/icons/mob/human_races/species/monkey/monkey_body.dmi differ diff --git a/icons/mob/human_races/species/shadow/body.dmi b/icons/mob/human_races/species/shadow/body.dmi new file mode 100644 index 000000000000..71cd7fdfb55f Binary files /dev/null and b/icons/mob/human_races/species/shadow/body.dmi differ diff --git a/icons/mob/human_races/species/shadow/husk.dmi b/icons/mob/human_races/species/shadow/husk.dmi new file mode 100644 index 000000000000..c1f14c0bb631 Binary files /dev/null and b/icons/mob/human_races/species/shadow/husk.dmi differ diff --git a/icons/mob/human_races/species/starborn/body.dmi b/icons/mob/human_races/species/starborn/body.dmi new file mode 100644 index 000000000000..d98f3ee0fa66 Binary files /dev/null and b/icons/mob/human_races/species/starborn/body.dmi differ diff --git a/icons/mob/human_races/species/starborn/husk.dmi b/icons/mob/human_races/species/starborn/husk.dmi new file mode 100644 index 000000000000..cb1bea82cc0d Binary files /dev/null and b/icons/mob/human_races/species/starborn/husk.dmi differ diff --git a/icons/mob/human_races/species/template.dmi b/icons/mob/human_races/species/template.dmi index 15454971468f..2d66351bd49d 100644 Binary files a/icons/mob/human_races/species/template.dmi and b/icons/mob/human_races/species/template.dmi differ diff --git a/icons/mob/human_races/species/template_tall.dmi b/icons/mob/human_races/species/template_tall.dmi index e9862bab5a65..0e5325d183da 100644 Binary files a/icons/mob/human_races/species/template_tall.dmi and b/icons/mob/human_races/species/template_tall.dmi differ diff --git a/icons/mob/light_overlays.dmi b/icons/mob/light_overlays.dmi deleted file mode 100644 index 904cefc9679e..000000000000 Binary files a/icons/mob/light_overlays.dmi and /dev/null differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 40cd2f874c72..39fe1bdf6102 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/mob/monitor_icons.dmi b/icons/mob/monitor_icons.dmi deleted file mode 100644 index b82955c992bd..000000000000 Binary files a/icons/mob/monitor_icons.dmi and /dev/null differ diff --git a/icons/mob/onmob/items/lefthand.dmi b/icons/mob/onmob/items/lefthand.dmi index 8464ea3d41cf..f94a41218dea 100644 Binary files a/icons/mob/onmob/items/lefthand.dmi and b/icons/mob/onmob/items/lefthand.dmi differ diff --git a/icons/mob/onmob/items/lefthand_holder.dmi b/icons/mob/onmob/items/lefthand_holder.dmi deleted file mode 100644 index 26e97f8d8c5f..000000000000 Binary files a/icons/mob/onmob/items/lefthand_holder.dmi and /dev/null differ diff --git a/icons/mob/onmob/items/lefthand_uniforms.dmi b/icons/mob/onmob/items/lefthand_uniforms.dmi deleted file mode 100644 index 03adf341be49..000000000000 Binary files a/icons/mob/onmob/items/lefthand_uniforms.dmi and /dev/null differ diff --git a/icons/mob/onmob/items/righthand.dmi b/icons/mob/onmob/items/righthand.dmi index 01ab04272555..c830e2f9fbd6 100644 Binary files a/icons/mob/onmob/items/righthand.dmi and b/icons/mob/onmob/items/righthand.dmi differ diff --git a/icons/mob/onmob/items/righthand_holder.dmi b/icons/mob/onmob/items/righthand_holder.dmi deleted file mode 100644 index 36f9ee7f89d8..000000000000 Binary files a/icons/mob/onmob/items/righthand_holder.dmi and /dev/null differ diff --git a/icons/mob/onmob/items/righthand_uniforms.dmi b/icons/mob/onmob/items/righthand_uniforms.dmi deleted file mode 100644 index 16eecfd1bef8..000000000000 Binary files a/icons/mob/onmob/items/righthand_uniforms.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_accessories.dmi b/icons/mob/onmob/onmob_accessories.dmi deleted file mode 100644 index 2d963ca030eb..000000000000 Binary files a/icons/mob/onmob/onmob_accessories.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_back.dmi b/icons/mob/onmob/onmob_back.dmi deleted file mode 100644 index 1028c7fecfb8..000000000000 Binary files a/icons/mob/onmob/onmob_back.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_belt.dmi b/icons/mob/onmob/onmob_belt.dmi deleted file mode 100644 index dfc4bd507c7e..000000000000 Binary files a/icons/mob/onmob/onmob_belt.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_belt_mirror.dmi b/icons/mob/onmob/onmob_belt_mirror.dmi deleted file mode 100644 index 3ae9a3e52ec8..000000000000 Binary files a/icons/mob/onmob/onmob_belt_mirror.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_cuff.dmi b/icons/mob/onmob/onmob_cuff.dmi deleted file mode 100644 index e846904e3264..000000000000 Binary files a/icons/mob/onmob/onmob_cuff.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_ears.dmi b/icons/mob/onmob/onmob_ears.dmi deleted file mode 100644 index fa4cd61d820a..000000000000 Binary files a/icons/mob/onmob/onmob_ears.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_eyes.dmi b/icons/mob/onmob/onmob_eyes.dmi deleted file mode 100644 index f4d027f9be66..000000000000 Binary files a/icons/mob/onmob/onmob_eyes.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_head.dmi b/icons/mob/onmob/onmob_head.dmi deleted file mode 100644 index 1c95fec3fe55..000000000000 Binary files a/icons/mob/onmob/onmob_head.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_mask.dmi b/icons/mob/onmob/onmob_mask.dmi deleted file mode 100644 index 34785ccc03f0..000000000000 Binary files a/icons/mob/onmob/onmob_mask.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_modular_armor.dmi b/icons/mob/onmob/onmob_modular_armor.dmi deleted file mode 100644 index 93cce3a017fb..000000000000 Binary files a/icons/mob/onmob/onmob_modular_armor.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_suit.dmi b/icons/mob/onmob/onmob_suit.dmi deleted file mode 100644 index f9a5a4f57bf9..000000000000 Binary files a/icons/mob/onmob/onmob_suit.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_under.dmi b/icons/mob/onmob/onmob_under.dmi deleted file mode 100644 index 7765eb07c819..000000000000 Binary files a/icons/mob/onmob/onmob_under.dmi and /dev/null differ diff --git a/icons/mob/onmob/onmob_under_pants.dmi b/icons/mob/onmob/onmob_under_pants.dmi deleted file mode 100644 index baaa2fd519bc..000000000000 Binary files a/icons/mob/onmob/onmob_under_pants.dmi and /dev/null differ diff --git a/icons/mob/pai.dmi b/icons/mob/pai.dmi deleted file mode 100644 index 3be2b7fd1562..000000000000 Binary files a/icons/mob/pai.dmi and /dev/null differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi deleted file mode 100644 index 0efc10dd7a73..000000000000 Binary files a/icons/mob/robots.dmi and /dev/null differ diff --git a/icons/mob/robots_gibs.dmi b/icons/mob/robots/_gibs.dmi similarity index 100% rename from icons/mob/robots_gibs.dmi rename to icons/mob/robots/_gibs.dmi diff --git a/icons/mob/robots/_panels.dmi b/icons/mob/robots/_panels.dmi new file mode 100644 index 000000000000..8873ccd3c041 Binary files /dev/null and b/icons/mob/robots/_panels.dmi differ diff --git a/icons/mob/robots/drones/_drone_panels.dmi b/icons/mob/robots/drones/_drone_panels.dmi new file mode 100644 index 000000000000..8873ccd3c041 Binary files /dev/null and b/icons/mob/robots/drones/_drone_panels.dmi differ diff --git a/icons/mob/robots/drones/drone.dmi b/icons/mob/robots/drones/drone.dmi new file mode 100644 index 000000000000..ad15560adb0a Binary files /dev/null and b/icons/mob/robots/drones/drone.dmi differ diff --git a/icons/mob/robots/drones/drone_construction.dmi b/icons/mob/robots/drones/drone_construction.dmi new file mode 100644 index 000000000000..e4173756d36d Binary files /dev/null and b/icons/mob/robots/drones/drone_construction.dmi differ diff --git a/icons/mob/robots/flying/_flying_panels.dmi b/icons/mob/robots/flying/_flying_panels.dmi new file mode 100644 index 000000000000..87f79afbe44c Binary files /dev/null and b/icons/mob/robots/flying/_flying_panels.dmi differ diff --git a/icons/mob/robots/flying/eyebot_engineering.dmi b/icons/mob/robots/flying/eyebot_engineering.dmi new file mode 100644 index 000000000000..b213780aa258 Binary files /dev/null and b/icons/mob/robots/flying/eyebot_engineering.dmi differ diff --git a/icons/mob/robots/flying/eyebot_medical.dmi b/icons/mob/robots/flying/eyebot_medical.dmi new file mode 100644 index 000000000000..1786d8e67ad2 Binary files /dev/null and b/icons/mob/robots/flying/eyebot_medical.dmi differ diff --git a/icons/mob/robots/flying/eyebot_science.dmi b/icons/mob/robots/flying/eyebot_science.dmi new file mode 100644 index 000000000000..942e2a526d8f Binary files /dev/null and b/icons/mob/robots/flying/eyebot_science.dmi differ diff --git a/icons/mob/robots/flying/eyebot_security.dmi b/icons/mob/robots/flying/eyebot_security.dmi new file mode 100644 index 000000000000..8a359b81c5de Binary files /dev/null and b/icons/mob/robots/flying/eyebot_security.dmi differ diff --git a/icons/mob/robots/flying/flying.dmi b/icons/mob/robots/flying/flying.dmi new file mode 100644 index 000000000000..9ff96429037f Binary files /dev/null and b/icons/mob/robots/flying/flying.dmi differ diff --git a/icons/mob/robots/flying/flying_engineering.dmi b/icons/mob/robots/flying/flying_engineering.dmi new file mode 100644 index 000000000000..38fd5bac40bb Binary files /dev/null and b/icons/mob/robots/flying/flying_engineering.dmi differ diff --git a/icons/mob/robots/flying/flying_hydro.dmi b/icons/mob/robots/flying/flying_hydro.dmi new file mode 100644 index 000000000000..7ae28a5d3842 Binary files /dev/null and b/icons/mob/robots/flying/flying_hydro.dmi differ diff --git a/icons/mob/robots/flying/flying_medical.dmi b/icons/mob/robots/flying/flying_medical.dmi new file mode 100644 index 000000000000..24d963c20a8f Binary files /dev/null and b/icons/mob/robots/flying/flying_medical.dmi differ diff --git a/icons/mob/robots/flying/flying_science.dmi b/icons/mob/robots/flying/flying_science.dmi new file mode 100644 index 000000000000..b711982cd02e Binary files /dev/null and b/icons/mob/robots/flying/flying_science.dmi differ diff --git a/icons/mob/robots/flying/flying_security.dmi b/icons/mob/robots/flying/flying_security.dmi new file mode 100644 index 000000000000..bdf6c4f9528f Binary files /dev/null and b/icons/mob/robots/flying/flying_security.dmi differ diff --git a/icons/mob/robots/flying/flying_service.dmi b/icons/mob/robots/flying/flying_service.dmi new file mode 100644 index 000000000000..ede72c3e0615 Binary files /dev/null and b/icons/mob/robots/flying/flying_service.dmi differ diff --git a/icons/mob/robots/flying/flying_surgery.dmi b/icons/mob/robots/flying/flying_surgery.dmi new file mode 100644 index 000000000000..79dbe5ef7e8f Binary files /dev/null and b/icons/mob/robots/flying/flying_surgery.dmi differ diff --git a/icons/mob/robots/pai/pai_cat.dmi b/icons/mob/robots/pai/pai_cat.dmi new file mode 100644 index 000000000000..0e376b3b8145 Binary files /dev/null and b/icons/mob/robots/pai/pai_cat.dmi differ diff --git a/icons/mob/robots/pai/pai_corgi.dmi b/icons/mob/robots/pai/pai_corgi.dmi new file mode 100644 index 000000000000..639cf4bed6f6 Binary files /dev/null and b/icons/mob/robots/pai/pai_corgi.dmi differ diff --git a/icons/mob/robots/pai/pai_crow.dmi b/icons/mob/robots/pai/pai_crow.dmi new file mode 100644 index 000000000000..33c6cfdca7c1 Binary files /dev/null and b/icons/mob/robots/pai/pai_crow.dmi differ diff --git a/icons/mob/robots/pai/pai_drone.dmi b/icons/mob/robots/pai/pai_drone.dmi new file mode 100644 index 000000000000..ef2c2fbaf199 Binary files /dev/null and b/icons/mob/robots/pai/pai_drone.dmi differ diff --git a/icons/mob/robots/pai/pai_monkey.dmi b/icons/mob/robots/pai/pai_monkey.dmi new file mode 100644 index 000000000000..cf19e27c0848 Binary files /dev/null and b/icons/mob/robots/pai/pai_monkey.dmi differ diff --git a/icons/mob/robots/pai/pai_mouse.dmi b/icons/mob/robots/pai/pai_mouse.dmi new file mode 100644 index 000000000000..7823f4560796 Binary files /dev/null and b/icons/mob/robots/pai/pai_mouse.dmi differ diff --git a/icons/mob/robots/pai/pai_mushroom.dmi b/icons/mob/robots/pai/pai_mushroom.dmi new file mode 100644 index 000000000000..1d2977f7bca6 Binary files /dev/null and b/icons/mob/robots/pai/pai_mushroom.dmi differ diff --git a/icons/mob/robots/pai/pai_rabbit.dmi b/icons/mob/robots/pai/pai_rabbit.dmi new file mode 100644 index 000000000000..3dca95061060 Binary files /dev/null and b/icons/mob/robots/pai/pai_rabbit.dmi differ diff --git a/icons/mob/robots/robot.dmi b/icons/mob/robots/robot.dmi new file mode 100644 index 000000000000..3f32008e0443 Binary files /dev/null and b/icons/mob/robots/robot.dmi differ diff --git a/icons/mob/robots/robot_centcomm.dmi b/icons/mob/robots/robot_centcomm.dmi new file mode 100644 index 000000000000..9dfd8235df67 Binary files /dev/null and b/icons/mob/robots/robot_centcomm.dmi differ diff --git a/icons/mob/robots/robot_combat.dmi b/icons/mob/robots/robot_combat.dmi new file mode 100644 index 000000000000..b564130aa699 Binary files /dev/null and b/icons/mob/robots/robot_combat.dmi differ diff --git a/icons/mob/robots/robot_droid.dmi b/icons/mob/robots/robot_droid.dmi new file mode 100644 index 000000000000..0fb257bfe224 Binary files /dev/null and b/icons/mob/robots/robot_droid.dmi differ diff --git a/icons/mob/robots/robot_droid_medical.dmi b/icons/mob/robots/robot_droid_medical.dmi new file mode 100644 index 000000000000..102e56f93a97 Binary files /dev/null and b/icons/mob/robots/robot_droid_medical.dmi differ diff --git a/icons/mob/robots/robot_droid_miner.dmi b/icons/mob/robots/robot_droid_miner.dmi new file mode 100644 index 000000000000..38d69971da4b Binary files /dev/null and b/icons/mob/robots/robot_droid_miner.dmi differ diff --git a/icons/mob/robots/robot_droid_science.dmi b/icons/mob/robots/robot_droid_science.dmi new file mode 100644 index 000000000000..b92a3b82ea83 Binary files /dev/null and b/icons/mob/robots/robot_droid_science.dmi differ diff --git a/icons/mob/robots/robot_droid_security.dmi b/icons/mob/robots/robot_droid_security.dmi new file mode 100644 index 000000000000..f5cd4ad1188b Binary files /dev/null and b/icons/mob/robots/robot_droid_security.dmi differ diff --git a/icons/mob/robots/robot_engineer.dmi b/icons/mob/robots/robot_engineer.dmi new file mode 100644 index 000000000000..a4bf2fbf0591 Binary files /dev/null and b/icons/mob/robots/robot_engineer.dmi differ diff --git a/icons/mob/robots/robot_engineer_old.dmi b/icons/mob/robots/robot_engineer_old.dmi new file mode 100644 index 000000000000..e2932d3b9167 Binary files /dev/null and b/icons/mob/robots/robot_engineer_old.dmi differ diff --git a/icons/mob/robots/robot_engineer_old_alt.dmi b/icons/mob/robots/robot_engineer_old_alt.dmi new file mode 100644 index 000000000000..0912f82e5fb9 Binary files /dev/null and b/icons/mob/robots/robot_engineer_old_alt.dmi differ diff --git a/icons/mob/robots/robot_engineer_treaded.dmi b/icons/mob/robots/robot_engineer_treaded.dmi new file mode 100644 index 000000000000..fe41ba0e1e30 Binary files /dev/null and b/icons/mob/robots/robot_engineer_treaded.dmi differ diff --git a/icons/mob/robots/robot_janbot.dmi b/icons/mob/robots/robot_janbot.dmi new file mode 100644 index 000000000000..f8c39c181c30 Binary files /dev/null and b/icons/mob/robots/robot_janbot.dmi differ diff --git a/icons/mob/robots/robot_janitor.dmi b/icons/mob/robots/robot_janitor.dmi new file mode 100644 index 000000000000..da7a6377ee67 Binary files /dev/null and b/icons/mob/robots/robot_janitor.dmi differ diff --git a/icons/mob/robots/robot_janitor_old.dmi b/icons/mob/robots/robot_janitor_old.dmi new file mode 100644 index 000000000000..c5c735a0dad1 Binary files /dev/null and b/icons/mob/robots/robot_janitor_old.dmi differ diff --git a/icons/mob/robots/robot_maximillion.dmi b/icons/mob/robots/robot_maximillion.dmi new file mode 100644 index 000000000000..cf51d1b9c7aa Binary files /dev/null and b/icons/mob/robots/robot_maximillion.dmi differ diff --git a/icons/mob/robots/robot_medical_old.dmi b/icons/mob/robots/robot_medical_old.dmi new file mode 100644 index 000000000000..9d067c8654e8 Binary files /dev/null and b/icons/mob/robots/robot_medical_old.dmi differ diff --git a/icons/mob/robots/robot_medical_old_alt.dmi b/icons/mob/robots/robot_medical_old_alt.dmi new file mode 100644 index 000000000000..3cd54eeeec2d Binary files /dev/null and b/icons/mob/robots/robot_medical_old_alt.dmi differ diff --git a/icons/mob/robots/robot_miner.dmi b/icons/mob/robots/robot_miner.dmi new file mode 100644 index 000000000000..386edfad7abc Binary files /dev/null and b/icons/mob/robots/robot_miner.dmi differ diff --git a/icons/mob/robots/robot_miner_old.dmi b/icons/mob/robots/robot_miner_old.dmi new file mode 100644 index 000000000000..fa9255a7bcaf Binary files /dev/null and b/icons/mob/robots/robot_miner_old.dmi differ diff --git a/icons/mob/robots/robot_old.dmi b/icons/mob/robots/robot_old.dmi new file mode 100644 index 000000000000..b02614902939 Binary files /dev/null and b/icons/mob/robots/robot_old.dmi differ diff --git a/icons/mob/robots/robot_orb.dmi b/icons/mob/robots/robot_orb.dmi new file mode 100644 index 000000000000..723b222e7334 Binary files /dev/null and b/icons/mob/robots/robot_orb.dmi differ diff --git a/icons/mob/robots/robot_science.dmi b/icons/mob/robots/robot_science.dmi new file mode 100644 index 000000000000..b92a3b82ea83 Binary files /dev/null and b/icons/mob/robots/robot_science.dmi differ diff --git a/icons/mob/robots/robot_secborg.dmi b/icons/mob/robots/robot_secborg.dmi new file mode 100644 index 000000000000..603411631902 Binary files /dev/null and b/icons/mob/robots/robot_secborg.dmi differ diff --git a/icons/mob/robots/robot_security.dmi b/icons/mob/robots/robot_security.dmi new file mode 100644 index 000000000000..4e3bcee01c0e Binary files /dev/null and b/icons/mob/robots/robot_security.dmi differ diff --git a/icons/mob/robots/robot_security_old.dmi b/icons/mob/robots/robot_security_old.dmi new file mode 100644 index 000000000000..aeee8b6cc3d6 Binary files /dev/null and b/icons/mob/robots/robot_security_old.dmi differ diff --git a/icons/mob/robots/robot_security_tread.dmi b/icons/mob/robots/robot_security_tread.dmi new file mode 100644 index 000000000000..a5db41a7d11a Binary files /dev/null and b/icons/mob/robots/robot_security_tread.dmi differ diff --git a/icons/mob/robots/robot_service.dmi b/icons/mob/robots/robot_service.dmi new file mode 100644 index 000000000000..00d6cd1ba6f0 Binary files /dev/null and b/icons/mob/robots/robot_service.dmi differ diff --git a/icons/mob/robots/robot_service_bro.dmi b/icons/mob/robots/robot_service_bro.dmi new file mode 100644 index 000000000000..a1ec797398ea Binary files /dev/null and b/icons/mob/robots/robot_service_bro.dmi differ diff --git a/icons/mob/robots/robot_service_old.dmi b/icons/mob/robots/robot_service_old.dmi new file mode 100644 index 000000000000..9517bd50e0f3 Binary files /dev/null and b/icons/mob/robots/robot_service_old.dmi differ diff --git a/icons/mob/robots/robot_surgeon.dmi b/icons/mob/robots/robot_surgeon.dmi new file mode 100644 index 000000000000..2c5597595fbf Binary files /dev/null and b/icons/mob/robots/robot_surgeon.dmi differ diff --git a/icons/mob/robots/robot_toiletbot.dmi b/icons/mob/robots/robot_toiletbot.dmi new file mode 100644 index 000000000000..e9652f89de0f Binary files /dev/null and b/icons/mob/robots/robot_toiletbot.dmi differ diff --git a/icons/mob/robots_drones.dmi b/icons/mob/robots_drones.dmi deleted file mode 100644 index d547d637e9d2..000000000000 Binary files a/icons/mob/robots_drones.dmi and /dev/null differ diff --git a/icons/mob/robots_flying.dmi b/icons/mob/robots_flying.dmi deleted file mode 100644 index 45cdf4b77d51..000000000000 Binary files a/icons/mob/robots_flying.dmi and /dev/null differ diff --git a/icons/mob/screen/abilities.dmi b/icons/mob/screen/abilities.dmi new file mode 100644 index 000000000000..ca7d904bd71d Binary files /dev/null and b/icons/mob/screen/abilities.dmi differ diff --git a/icons/mob/screen/ability_inhand.dmi b/icons/mob/screen/ability_inhand.dmi new file mode 100644 index 000000000000..63e1b630dc06 Binary files /dev/null and b/icons/mob/screen/ability_inhand.dmi differ diff --git a/icons/mob/screen_ai.dmi b/icons/mob/screen/ai.dmi similarity index 100% rename from icons/mob/screen_ai.dmi rename to icons/mob/screen/ai.dmi diff --git a/icons/mob/screen/effects.dmi b/icons/mob/screen/effects.dmi new file mode 100644 index 000000000000..955eff3e1949 Binary files /dev/null and b/icons/mob/screen/effects.dmi differ diff --git a/icons/mob/screen_full.dmi b/icons/mob/screen/full.dmi similarity index 100% rename from icons/mob/screen_full.dmi rename to icons/mob/screen/full.dmi diff --git a/icons/mob/screen/grabs.dmi b/icons/mob/screen/grabs.dmi new file mode 100644 index 000000000000..fab4a611566e Binary files /dev/null and b/icons/mob/screen/grabs.dmi differ diff --git a/icons/mob/screen/midnight.dmi b/icons/mob/screen/midnight.dmi deleted file mode 100644 index f5b4a90d379f..000000000000 Binary files a/icons/mob/screen/midnight.dmi and /dev/null differ diff --git a/icons/mob/screen/minimalist.dmi b/icons/mob/screen/minimalist.dmi deleted file mode 100644 index 46858de1d075..000000000000 Binary files a/icons/mob/screen/minimalist.dmi and /dev/null differ diff --git a/icons/mob/screen/old-noborder.dmi b/icons/mob/screen/old-noborder.dmi deleted file mode 100644 index ddc67a837b73..000000000000 Binary files a/icons/mob/screen/old-noborder.dmi and /dev/null differ diff --git a/icons/mob/screen/old.dmi b/icons/mob/screen/old.dmi deleted file mode 100644 index d00da08c1044..000000000000 Binary files a/icons/mob/screen/old.dmi and /dev/null differ diff --git a/icons/mob/screen/orange.dmi b/icons/mob/screen/orange.dmi deleted file mode 100644 index 76b527008ef7..000000000000 Binary files a/icons/mob/screen/orange.dmi and /dev/null differ diff --git a/icons/mob/screen/pai.dmi b/icons/mob/screen/pai.dmi new file mode 100644 index 000000000000..a73ff1b8e782 Binary files /dev/null and b/icons/mob/screen/pai.dmi differ diff --git a/icons/mob/screen/storage.dmi b/icons/mob/screen/storage.dmi new file mode 100644 index 000000000000..dd0313f518eb Binary files /dev/null and b/icons/mob/screen/storage.dmi differ diff --git a/icons/mob/screen/styles/charge.dmi b/icons/mob/screen/styles/charge.dmi new file mode 100644 index 000000000000..71c34fea3d0e Binary files /dev/null and b/icons/mob/screen/styles/charge.dmi differ diff --git a/icons/mob/screen/styles/constructs/artificer/health.dmi b/icons/mob/screen/styles/constructs/artificer/health.dmi new file mode 100644 index 000000000000..04e75e41ab32 Binary files /dev/null and b/icons/mob/screen/styles/constructs/artificer/health.dmi differ diff --git a/icons/mob/screen/styles/constructs/harvester/health.dmi b/icons/mob/screen/styles/constructs/harvester/health.dmi new file mode 100644 index 000000000000..be13fae91258 Binary files /dev/null and b/icons/mob/screen/styles/constructs/harvester/health.dmi differ diff --git a/icons/mob/screen/styles/constructs/juggernaut/health.dmi b/icons/mob/screen/styles/constructs/juggernaut/health.dmi new file mode 100644 index 000000000000..aaec933b19e8 Binary files /dev/null and b/icons/mob/screen/styles/constructs/juggernaut/health.dmi differ diff --git a/icons/mob/screen/styles/constructs/status_fire.dmi b/icons/mob/screen/styles/constructs/status_fire.dmi new file mode 100644 index 000000000000..d25bae5b1f02 Binary files /dev/null and b/icons/mob/screen/styles/constructs/status_fire.dmi differ diff --git a/icons/mob/screen/styles/constructs/wraith/health.dmi b/icons/mob/screen/styles/constructs/wraith/health.dmi new file mode 100644 index 000000000000..43000b7c72b7 Binary files /dev/null and b/icons/mob/screen/styles/constructs/wraith/health.dmi differ diff --git a/icons/mob/screen/styles/constructs/zone_selector.dmi b/icons/mob/screen/styles/constructs/zone_selector.dmi new file mode 100644 index 000000000000..698da564e03b Binary files /dev/null and b/icons/mob/screen/styles/constructs/zone_selector.dmi differ diff --git a/icons/mob/screen1_health.dmi b/icons/mob/screen/styles/crit_markers.dmi similarity index 100% rename from icons/mob/screen1_health.dmi rename to icons/mob/screen/styles/crit_markers.dmi diff --git a/icons/mob/screen/styles/health.dmi b/icons/mob/screen/styles/health.dmi new file mode 100644 index 000000000000..efb0feed226e Binary files /dev/null and b/icons/mob/screen/styles/health.dmi differ diff --git a/icons/mob/screen/styles/hydration.dmi b/icons/mob/screen/styles/hydration.dmi new file mode 100644 index 000000000000..9abddcf6305b Binary files /dev/null and b/icons/mob/screen/styles/hydration.dmi differ diff --git a/icons/mob/screen/styles/internals.dmi b/icons/mob/screen/styles/internals.dmi new file mode 100644 index 000000000000..0ddffa7023c3 Binary files /dev/null and b/icons/mob/screen/styles/internals.dmi differ diff --git a/icons/mob/screen/styles/midnight/attack_selector.dmi b/icons/mob/screen/styles/midnight/attack_selector.dmi new file mode 100644 index 000000000000..7b9149d4d98b Binary files /dev/null and b/icons/mob/screen/styles/midnight/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/midnight/fire_intent.dmi b/icons/mob/screen/styles/midnight/fire_intent.dmi new file mode 100644 index 000000000000..dad75b054887 Binary files /dev/null and b/icons/mob/screen/styles/midnight/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/midnight/hands.dmi b/icons/mob/screen/styles/midnight/hands.dmi new file mode 100644 index 000000000000..b80c4c83427a Binary files /dev/null and b/icons/mob/screen/styles/midnight/hands.dmi differ diff --git a/icons/mob/screen/styles/midnight/interaction_drop.dmi b/icons/mob/screen/styles/midnight/interaction_drop.dmi new file mode 100644 index 000000000000..2c059e4a764c Binary files /dev/null and b/icons/mob/screen/styles/midnight/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/midnight/interaction_maneuver.dmi b/icons/mob/screen/styles/midnight/interaction_maneuver.dmi new file mode 100644 index 000000000000..9b86b5d4a9f2 Binary files /dev/null and b/icons/mob/screen/styles/midnight/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/midnight/interaction_resist.dmi b/icons/mob/screen/styles/midnight/interaction_resist.dmi new file mode 100644 index 000000000000..2cf744ec8c16 Binary files /dev/null and b/icons/mob/screen/styles/midnight/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/midnight/interaction_throw.dmi b/icons/mob/screen/styles/midnight/interaction_throw.dmi new file mode 100644 index 000000000000..63c4a5a1086d Binary files /dev/null and b/icons/mob/screen/styles/midnight/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/midnight/inventory.dmi b/icons/mob/screen/styles/midnight/inventory.dmi new file mode 100644 index 000000000000..6bc91ff98ad6 Binary files /dev/null and b/icons/mob/screen/styles/midnight/inventory.dmi differ diff --git a/icons/mob/screen/styles/midnight/modifiers.dmi b/icons/mob/screen/styles/midnight/modifiers.dmi new file mode 100644 index 000000000000..6cc3b0b6b5d5 Binary files /dev/null and b/icons/mob/screen/styles/midnight/modifiers.dmi differ diff --git a/icons/mob/screen/styles/midnight/movement.dmi b/icons/mob/screen/styles/midnight/movement.dmi new file mode 100644 index 000000000000..443fe61eb205 Binary files /dev/null and b/icons/mob/screen/styles/midnight/movement.dmi differ diff --git a/icons/mob/screen/styles/midnight/uphint.dmi b/icons/mob/screen/styles/midnight/uphint.dmi new file mode 100644 index 000000000000..548946e06e4c Binary files /dev/null and b/icons/mob/screen/styles/midnight/uphint.dmi differ diff --git a/icons/mob/screen/styles/midnight/zone_selector.dmi b/icons/mob/screen/styles/midnight/zone_selector.dmi new file mode 100644 index 000000000000..93ff92e47e35 Binary files /dev/null and b/icons/mob/screen/styles/midnight/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/minimalist/attack_selector.dmi b/icons/mob/screen/styles/minimalist/attack_selector.dmi new file mode 100644 index 000000000000..2e3d66fd059a Binary files /dev/null and b/icons/mob/screen/styles/minimalist/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/minimalist/fire_intent.dmi b/icons/mob/screen/styles/minimalist/fire_intent.dmi new file mode 100644 index 000000000000..02a311ec4e88 Binary files /dev/null and b/icons/mob/screen/styles/minimalist/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/minimalist/hands.dmi b/icons/mob/screen/styles/minimalist/hands.dmi new file mode 100644 index 000000000000..ff094e024af3 Binary files /dev/null and b/icons/mob/screen/styles/minimalist/hands.dmi differ diff --git a/icons/mob/screen/styles/minimalist/interaction_drop.dmi b/icons/mob/screen/styles/minimalist/interaction_drop.dmi new file mode 100644 index 000000000000..7090d7c1ce8b Binary files /dev/null and b/icons/mob/screen/styles/minimalist/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/minimalist/interaction_maneuver.dmi b/icons/mob/screen/styles/minimalist/interaction_maneuver.dmi new file mode 100644 index 000000000000..6c42b11d1987 Binary files /dev/null and b/icons/mob/screen/styles/minimalist/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/minimalist/interaction_resist.dmi b/icons/mob/screen/styles/minimalist/interaction_resist.dmi new file mode 100644 index 000000000000..5e7fce2ada8f Binary files /dev/null and b/icons/mob/screen/styles/minimalist/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/minimalist/interaction_throw.dmi b/icons/mob/screen/styles/minimalist/interaction_throw.dmi new file mode 100644 index 000000000000..9365cb5fc65f Binary files /dev/null and b/icons/mob/screen/styles/minimalist/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/minimalist/inventory.dmi b/icons/mob/screen/styles/minimalist/inventory.dmi new file mode 100644 index 000000000000..169c66eefdd0 Binary files /dev/null and b/icons/mob/screen/styles/minimalist/inventory.dmi differ diff --git a/icons/mob/screen/styles/minimalist/modifiers.dmi b/icons/mob/screen/styles/minimalist/modifiers.dmi new file mode 100644 index 000000000000..aef787e69213 Binary files /dev/null and b/icons/mob/screen/styles/minimalist/modifiers.dmi differ diff --git a/icons/mob/screen/styles/minimalist/movement.dmi b/icons/mob/screen/styles/minimalist/movement.dmi new file mode 100644 index 000000000000..fa354873156d Binary files /dev/null and b/icons/mob/screen/styles/minimalist/movement.dmi differ diff --git a/icons/mob/screen/styles/minimalist/uphint.dmi b/icons/mob/screen/styles/minimalist/uphint.dmi new file mode 100644 index 000000000000..412cab2b32dc Binary files /dev/null and b/icons/mob/screen/styles/minimalist/uphint.dmi differ diff --git a/icons/mob/screen/styles/minimalist/zone_selector.dmi b/icons/mob/screen/styles/minimalist/zone_selector.dmi new file mode 100644 index 000000000000..2cdd0893f6ae Binary files /dev/null and b/icons/mob/screen/styles/minimalist/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/modifiers.dmi b/icons/mob/screen/styles/modifiers.dmi new file mode 100644 index 000000000000..fb652724b08c Binary files /dev/null and b/icons/mob/screen/styles/modifiers.dmi differ diff --git a/icons/mob/screen/styles/nutrition.dmi b/icons/mob/screen/styles/nutrition.dmi new file mode 100644 index 000000000000..b34a0abc49f8 Binary files /dev/null and b/icons/mob/screen/styles/nutrition.dmi differ diff --git a/icons/mob/screen/styles/old/attack_selector.dmi b/icons/mob/screen/styles/old/attack_selector.dmi new file mode 100644 index 000000000000..ec4c8b8a4fef Binary files /dev/null and b/icons/mob/screen/styles/old/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/old/fire_intent.dmi b/icons/mob/screen/styles/old/fire_intent.dmi new file mode 100644 index 000000000000..a8c74500c40d Binary files /dev/null and b/icons/mob/screen/styles/old/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/old/hands.dmi b/icons/mob/screen/styles/old/hands.dmi new file mode 100644 index 000000000000..9f0eb66204a3 Binary files /dev/null and b/icons/mob/screen/styles/old/hands.dmi differ diff --git a/icons/mob/screen/styles/old/interaction_drop.dmi b/icons/mob/screen/styles/old/interaction_drop.dmi new file mode 100644 index 000000000000..06f0d2d6ddaa Binary files /dev/null and b/icons/mob/screen/styles/old/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/old/interaction_maneuver.dmi b/icons/mob/screen/styles/old/interaction_maneuver.dmi new file mode 100644 index 000000000000..19176dd8e987 Binary files /dev/null and b/icons/mob/screen/styles/old/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/old/interaction_resist.dmi b/icons/mob/screen/styles/old/interaction_resist.dmi new file mode 100644 index 000000000000..cff4fb592bd9 Binary files /dev/null and b/icons/mob/screen/styles/old/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/old/interaction_throw.dmi b/icons/mob/screen/styles/old/interaction_throw.dmi new file mode 100644 index 000000000000..425e7f6b86c5 Binary files /dev/null and b/icons/mob/screen/styles/old/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/old/inventory.dmi b/icons/mob/screen/styles/old/inventory.dmi new file mode 100644 index 000000000000..c25d1699c1e1 Binary files /dev/null and b/icons/mob/screen/styles/old/inventory.dmi differ diff --git a/icons/mob/screen/styles/old/modifiers.dmi b/icons/mob/screen/styles/old/modifiers.dmi new file mode 100644 index 000000000000..4021542f5f47 Binary files /dev/null and b/icons/mob/screen/styles/old/modifiers.dmi differ diff --git a/icons/mob/screen/styles/old/movement.dmi b/icons/mob/screen/styles/old/movement.dmi new file mode 100644 index 000000000000..3a7bef907158 Binary files /dev/null and b/icons/mob/screen/styles/old/movement.dmi differ diff --git a/icons/mob/screen/styles/old/uphint.dmi b/icons/mob/screen/styles/old/uphint.dmi new file mode 100644 index 000000000000..af81f73848d2 Binary files /dev/null and b/icons/mob/screen/styles/old/uphint.dmi differ diff --git a/icons/mob/screen/styles/old/zone_selector.dmi b/icons/mob/screen/styles/old/zone_selector.dmi new file mode 100644 index 000000000000..76fd6cf7272b Binary files /dev/null and b/icons/mob/screen/styles/old/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/old_noborder/inventory.dmi b/icons/mob/screen/styles/old_noborder/inventory.dmi new file mode 100644 index 000000000000..6b31c0bd4f6a Binary files /dev/null and b/icons/mob/screen/styles/old_noborder/inventory.dmi differ diff --git a/icons/mob/screen/styles/old_noborder/modifiers.dmi b/icons/mob/screen/styles/old_noborder/modifiers.dmi new file mode 100644 index 000000000000..fb652724b08c Binary files /dev/null and b/icons/mob/screen/styles/old_noborder/modifiers.dmi differ diff --git a/icons/mob/screen/styles/old_noborder/uphint.dmi b/icons/mob/screen/styles/old_noborder/uphint.dmi new file mode 100644 index 000000000000..d97704b02956 Binary files /dev/null and b/icons/mob/screen/styles/old_noborder/uphint.dmi differ diff --git a/icons/mob/screen/styles/old_noborder/zone_selector.dmi b/icons/mob/screen/styles/old_noborder/zone_selector.dmi new file mode 100644 index 000000000000..31b4bf66cb40 Binary files /dev/null and b/icons/mob/screen/styles/old_noborder/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/orange/attack_selector.dmi b/icons/mob/screen/styles/orange/attack_selector.dmi new file mode 100644 index 000000000000..4b9cfe05fc4d Binary files /dev/null and b/icons/mob/screen/styles/orange/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/orange/fire_intent.dmi b/icons/mob/screen/styles/orange/fire_intent.dmi new file mode 100644 index 000000000000..5ab217edcd5c Binary files /dev/null and b/icons/mob/screen/styles/orange/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/orange/hands.dmi b/icons/mob/screen/styles/orange/hands.dmi new file mode 100644 index 000000000000..f1ceb7b190aa Binary files /dev/null and b/icons/mob/screen/styles/orange/hands.dmi differ diff --git a/icons/mob/screen/styles/orange/interaction_drop.dmi b/icons/mob/screen/styles/orange/interaction_drop.dmi new file mode 100644 index 000000000000..75f415b0f27a Binary files /dev/null and b/icons/mob/screen/styles/orange/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/orange/interaction_maneuver.dmi b/icons/mob/screen/styles/orange/interaction_maneuver.dmi new file mode 100644 index 000000000000..d4798c022701 Binary files /dev/null and b/icons/mob/screen/styles/orange/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/orange/interaction_resist.dmi b/icons/mob/screen/styles/orange/interaction_resist.dmi new file mode 100644 index 000000000000..34d6ed3d9d6d Binary files /dev/null and b/icons/mob/screen/styles/orange/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/orange/interaction_throw.dmi b/icons/mob/screen/styles/orange/interaction_throw.dmi new file mode 100644 index 000000000000..e036affab2e7 Binary files /dev/null and b/icons/mob/screen/styles/orange/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/orange/inventory.dmi b/icons/mob/screen/styles/orange/inventory.dmi new file mode 100644 index 000000000000..ecaacdf9b320 Binary files /dev/null and b/icons/mob/screen/styles/orange/inventory.dmi differ diff --git a/icons/mob/screen/styles/orange/modifiers.dmi b/icons/mob/screen/styles/orange/modifiers.dmi new file mode 100644 index 000000000000..63a91d893f70 Binary files /dev/null and b/icons/mob/screen/styles/orange/modifiers.dmi differ diff --git a/icons/mob/screen/styles/orange/movement.dmi b/icons/mob/screen/styles/orange/movement.dmi new file mode 100644 index 000000000000..29520e406470 Binary files /dev/null and b/icons/mob/screen/styles/orange/movement.dmi differ diff --git a/icons/mob/screen/styles/orange/uphint.dmi b/icons/mob/screen/styles/orange/uphint.dmi new file mode 100644 index 000000000000..01ad74212176 Binary files /dev/null and b/icons/mob/screen/styles/orange/uphint.dmi differ diff --git a/icons/mob/screen/styles/orange/zone_selector.dmi b/icons/mob/screen/styles/orange/zone_selector.dmi new file mode 100644 index 000000000000..30ae1b66463a Binary files /dev/null and b/icons/mob/screen/styles/orange/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/robot/attack_selector.dmi b/icons/mob/screen/styles/robot/attack_selector.dmi new file mode 100644 index 000000000000..d28dd18a6fac Binary files /dev/null and b/icons/mob/screen/styles/robot/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/robot/drop_grab.dmi b/icons/mob/screen/styles/robot/drop_grab.dmi new file mode 100644 index 000000000000..7a1ecce37dfc Binary files /dev/null and b/icons/mob/screen/styles/robot/drop_grab.dmi differ diff --git a/icons/mob/screen/styles/robot/fire_intent.dmi b/icons/mob/screen/styles/robot/fire_intent.dmi new file mode 100644 index 000000000000..199ea1261455 Binary files /dev/null and b/icons/mob/screen/styles/robot/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/robot/hands.dmi b/icons/mob/screen/styles/robot/hands.dmi new file mode 100644 index 000000000000..7f919d72c34e Binary files /dev/null and b/icons/mob/screen/styles/robot/hands.dmi differ diff --git a/icons/mob/screen/styles/robot/health.dmi b/icons/mob/screen/styles/robot/health.dmi new file mode 100644 index 000000000000..4c54b971dd1b Binary files /dev/null and b/icons/mob/screen/styles/robot/health.dmi differ diff --git a/icons/mob/screen/styles/robot/interaction_drop.dmi b/icons/mob/screen/styles/robot/interaction_drop.dmi new file mode 100644 index 000000000000..f9b50c0a0676 Binary files /dev/null and b/icons/mob/screen/styles/robot/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/robot/interaction_maneuver.dmi b/icons/mob/screen/styles/robot/interaction_maneuver.dmi new file mode 100644 index 000000000000..a59af200e49a Binary files /dev/null and b/icons/mob/screen/styles/robot/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/robot/interaction_resist.dmi b/icons/mob/screen/styles/robot/interaction_resist.dmi new file mode 100644 index 000000000000..c9c5ef64622f Binary files /dev/null and b/icons/mob/screen/styles/robot/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/robot/interaction_throw.dmi b/icons/mob/screen/styles/robot/interaction_throw.dmi new file mode 100644 index 000000000000..b98a7ae01e26 Binary files /dev/null and b/icons/mob/screen/styles/robot/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/robot/inventory.dmi b/icons/mob/screen/styles/robot/inventory.dmi new file mode 100644 index 000000000000..1a9f6f039796 Binary files /dev/null and b/icons/mob/screen/styles/robot/inventory.dmi differ diff --git a/icons/mob/screen/styles/robot/module.dmi b/icons/mob/screen/styles/robot/module.dmi new file mode 100644 index 000000000000..4ce31caf38c2 Binary files /dev/null and b/icons/mob/screen/styles/robot/module.dmi differ diff --git a/icons/mob/screen/styles/robot/modules_background.dmi b/icons/mob/screen/styles/robot/modules_background.dmi new file mode 100644 index 000000000000..8c9e1bb82d81 Binary files /dev/null and b/icons/mob/screen/styles/robot/modules_background.dmi differ diff --git a/icons/mob/screen/styles/robot/modules_inventory.dmi b/icons/mob/screen/styles/robot/modules_inventory.dmi new file mode 100644 index 000000000000..fd94f0f29b45 Binary files /dev/null and b/icons/mob/screen/styles/robot/modules_inventory.dmi differ diff --git a/icons/mob/screen/styles/robot/movement.dmi b/icons/mob/screen/styles/robot/movement.dmi new file mode 100644 index 000000000000..f71eecbe8a66 Binary files /dev/null and b/icons/mob/screen/styles/robot/movement.dmi differ diff --git a/icons/mob/screen/styles/robot/panel.dmi b/icons/mob/screen/styles/robot/panel.dmi new file mode 100644 index 000000000000..779876900d52 Binary files /dev/null and b/icons/mob/screen/styles/robot/panel.dmi differ diff --git a/icons/mob/screen/styles/robot/status_fire.dmi b/icons/mob/screen/styles/robot/status_fire.dmi new file mode 100644 index 000000000000..9c8981958b4c Binary files /dev/null and b/icons/mob/screen/styles/robot/status_fire.dmi differ diff --git a/icons/mob/screen/styles/robot/status_oxy.dmi b/icons/mob/screen/styles/robot/status_oxy.dmi new file mode 100644 index 000000000000..914f5646fb4b Binary files /dev/null and b/icons/mob/screen/styles/robot/status_oxy.dmi differ diff --git a/icons/mob/screen/styles/robot/uphint.dmi b/icons/mob/screen/styles/robot/uphint.dmi new file mode 100644 index 000000000000..061c13f26757 Binary files /dev/null and b/icons/mob/screen/styles/robot/uphint.dmi differ diff --git a/icons/mob/screen/styles/robot/zone_selector.dmi b/icons/mob/screen/styles/robot/zone_selector.dmi new file mode 100644 index 000000000000..a7b3550559c3 Binary files /dev/null and b/icons/mob/screen/styles/robot/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/status_bodytemp.dmi b/icons/mob/screen/styles/status_bodytemp.dmi new file mode 100644 index 000000000000..c422aead1841 Binary files /dev/null and b/icons/mob/screen/styles/status_bodytemp.dmi differ diff --git a/icons/mob/screen/styles/status_fire.dmi b/icons/mob/screen/styles/status_fire.dmi new file mode 100644 index 000000000000..750adcf4a27d Binary files /dev/null and b/icons/mob/screen/styles/status_fire.dmi differ diff --git a/icons/mob/screen/styles/status_oxy.dmi b/icons/mob/screen/styles/status_oxy.dmi new file mode 100644 index 000000000000..cb49f5f466da Binary files /dev/null and b/icons/mob/screen/styles/status_oxy.dmi differ diff --git a/icons/mob/screen/styles/status_pressure.dmi b/icons/mob/screen/styles/status_pressure.dmi new file mode 100644 index 000000000000..707b6910860a Binary files /dev/null and b/icons/mob/screen/styles/status_pressure.dmi differ diff --git a/icons/mob/screen/styles/status_tox.dmi b/icons/mob/screen/styles/status_tox.dmi new file mode 100644 index 000000000000..019f3f1f6801 Binary files /dev/null and b/icons/mob/screen/styles/status_tox.dmi differ diff --git a/icons/mob/screen/styles/underworld/attack_selector.dmi b/icons/mob/screen/styles/underworld/attack_selector.dmi new file mode 100644 index 000000000000..2df7a24c30db Binary files /dev/null and b/icons/mob/screen/styles/underworld/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/underworld/fire_intent.dmi b/icons/mob/screen/styles/underworld/fire_intent.dmi new file mode 100644 index 000000000000..1f7c93487fd0 Binary files /dev/null and b/icons/mob/screen/styles/underworld/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/underworld/hands.dmi b/icons/mob/screen/styles/underworld/hands.dmi new file mode 100644 index 000000000000..dd6f8f42d91e Binary files /dev/null and b/icons/mob/screen/styles/underworld/hands.dmi differ diff --git a/icons/mob/screen/styles/underworld/interaction_drop.dmi b/icons/mob/screen/styles/underworld/interaction_drop.dmi new file mode 100644 index 000000000000..fda4a6b146c3 Binary files /dev/null and b/icons/mob/screen/styles/underworld/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/underworld/interaction_maneuver.dmi b/icons/mob/screen/styles/underworld/interaction_maneuver.dmi new file mode 100644 index 000000000000..c678600935ca Binary files /dev/null and b/icons/mob/screen/styles/underworld/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/underworld/interaction_resist.dmi b/icons/mob/screen/styles/underworld/interaction_resist.dmi new file mode 100644 index 000000000000..19bab4626001 Binary files /dev/null and b/icons/mob/screen/styles/underworld/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/underworld/interaction_throw.dmi b/icons/mob/screen/styles/underworld/interaction_throw.dmi new file mode 100644 index 000000000000..dac73e3f87ca Binary files /dev/null and b/icons/mob/screen/styles/underworld/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/underworld/inventory.dmi b/icons/mob/screen/styles/underworld/inventory.dmi new file mode 100644 index 000000000000..b576bd3b4df9 Binary files /dev/null and b/icons/mob/screen/styles/underworld/inventory.dmi differ diff --git a/icons/mob/screen/styles/underworld/modifiers.dmi b/icons/mob/screen/styles/underworld/modifiers.dmi new file mode 100644 index 000000000000..f70a3571afb3 Binary files /dev/null and b/icons/mob/screen/styles/underworld/modifiers.dmi differ diff --git a/icons/mob/screen/styles/underworld/movement.dmi b/icons/mob/screen/styles/underworld/movement.dmi new file mode 100644 index 000000000000..6890efd9fa4e Binary files /dev/null and b/icons/mob/screen/styles/underworld/movement.dmi differ diff --git a/icons/mob/screen/styles/underworld/uphint.dmi b/icons/mob/screen/styles/underworld/uphint.dmi new file mode 100644 index 000000000000..4d78c55da726 Binary files /dev/null and b/icons/mob/screen/styles/underworld/uphint.dmi differ diff --git a/icons/mob/screen/styles/underworld/zone_selector.dmi b/icons/mob/screen/styles/underworld/zone_selector.dmi new file mode 100644 index 000000000000..e482039b230f Binary files /dev/null and b/icons/mob/screen/styles/underworld/zone_selector.dmi differ diff --git a/icons/mob/screen/styles/white/attack_selector.dmi b/icons/mob/screen/styles/white/attack_selector.dmi new file mode 100644 index 000000000000..02f97413e1a4 Binary files /dev/null and b/icons/mob/screen/styles/white/attack_selector.dmi differ diff --git a/icons/mob/screen/styles/white/fire_intent.dmi b/icons/mob/screen/styles/white/fire_intent.dmi new file mode 100644 index 000000000000..64af8d1e0789 Binary files /dev/null and b/icons/mob/screen/styles/white/fire_intent.dmi differ diff --git a/icons/mob/screen/styles/white/hands.dmi b/icons/mob/screen/styles/white/hands.dmi new file mode 100644 index 000000000000..68180ce45dba Binary files /dev/null and b/icons/mob/screen/styles/white/hands.dmi differ diff --git a/icons/mob/screen/styles/white/interaction_drop.dmi b/icons/mob/screen/styles/white/interaction_drop.dmi new file mode 100644 index 000000000000..aa03166c504c Binary files /dev/null and b/icons/mob/screen/styles/white/interaction_drop.dmi differ diff --git a/icons/mob/screen/styles/white/interaction_maneuver.dmi b/icons/mob/screen/styles/white/interaction_maneuver.dmi new file mode 100644 index 000000000000..b885672572c6 Binary files /dev/null and b/icons/mob/screen/styles/white/interaction_maneuver.dmi differ diff --git a/icons/mob/screen/styles/white/interaction_resist.dmi b/icons/mob/screen/styles/white/interaction_resist.dmi new file mode 100644 index 000000000000..462763ac6568 Binary files /dev/null and b/icons/mob/screen/styles/white/interaction_resist.dmi differ diff --git a/icons/mob/screen/styles/white/interaction_throw.dmi b/icons/mob/screen/styles/white/interaction_throw.dmi new file mode 100644 index 000000000000..f95dbe55095c Binary files /dev/null and b/icons/mob/screen/styles/white/interaction_throw.dmi differ diff --git a/icons/mob/screen/styles/white/inventory.dmi b/icons/mob/screen/styles/white/inventory.dmi new file mode 100644 index 000000000000..f8cfa9cbbc54 Binary files /dev/null and b/icons/mob/screen/styles/white/inventory.dmi differ diff --git a/icons/mob/screen/styles/white/modifiers.dmi b/icons/mob/screen/styles/white/modifiers.dmi new file mode 100644 index 000000000000..6f342e3627d2 Binary files /dev/null and b/icons/mob/screen/styles/white/modifiers.dmi differ diff --git a/icons/mob/screen/styles/white/movement.dmi b/icons/mob/screen/styles/white/movement.dmi new file mode 100644 index 000000000000..b3a61c63a9be Binary files /dev/null and b/icons/mob/screen/styles/white/movement.dmi differ diff --git a/icons/mob/screen/styles/white/uphint.dmi b/icons/mob/screen/styles/white/uphint.dmi new file mode 100644 index 000000000000..ee795947c302 Binary files /dev/null and b/icons/mob/screen/styles/white/uphint.dmi differ diff --git a/icons/mob/screen/styles/white/zone_selector.dmi b/icons/mob/screen/styles/white/zone_selector.dmi new file mode 100644 index 000000000000..1e768fdd53d2 Binary files /dev/null and b/icons/mob/screen/styles/white/zone_selector.dmi differ diff --git a/icons/mob/screen/white.dmi b/icons/mob/screen/white.dmi deleted file mode 100644 index 64cec88b0fd1..000000000000 Binary files a/icons/mob/screen/white.dmi and /dev/null differ diff --git a/icons/mob/screen1.dmi b/icons/mob/screen1.dmi deleted file mode 100644 index 7f8db4256da5..000000000000 Binary files a/icons/mob/screen1.dmi and /dev/null differ diff --git a/icons/mob/screen1_construct.dmi b/icons/mob/screen1_construct.dmi deleted file mode 100644 index 67a37ccd7388..000000000000 Binary files a/icons/mob/screen1_construct.dmi and /dev/null differ diff --git a/icons/mob/screen1_robot.dmi b/icons/mob/screen1_robot.dmi deleted file mode 100644 index c6aa98f2b1fa..000000000000 Binary files a/icons/mob/screen1_robot.dmi and /dev/null differ diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi deleted file mode 100644 index 436fb1169a2d..000000000000 Binary files a/icons/mob/screen_gen.dmi and /dev/null differ diff --git a/icons/mob/screen_phenomena.dmi b/icons/mob/screen_phenomena.dmi deleted file mode 100644 index f1d05fa97306..000000000000 Binary files a/icons/mob/screen_phenomena.dmi and /dev/null differ diff --git a/icons/mob/screen_spells.dmi b/icons/mob/screen_spells.dmi deleted file mode 100644 index 50be07d787b8..000000000000 Binary files a/icons/mob/screen_spells.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/amaros.dmi b/icons/mob/simple_animal/amaros.dmi new file mode 100644 index 000000000000..175603ea3040 Binary files /dev/null and b/icons/mob/simple_animal/amaros.dmi differ diff --git a/icons/mob/simple_animal/animal.dmi b/icons/mob/simple_animal/animal.dmi deleted file mode 100644 index 3d85ff28fa19..000000000000 Binary files a/icons/mob/simple_animal/animal.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/antlion.dmi b/icons/mob/simple_animal/antlion.dmi index 6ae64b028d20..7f56b797460c 100644 Binary files a/icons/mob/simple_animal/antlion.dmi and b/icons/mob/simple_animal/antlion.dmi differ diff --git a/icons/mob/simple_animal/antlion_queen.dmi b/icons/mob/simple_animal/antlion_queen.dmi new file mode 100644 index 000000000000..167fa4de06d2 Binary files /dev/null and b/icons/mob/simple_animal/antlion_queen.dmi differ diff --git a/icons/mob/simple_animal/aquatic.dmi b/icons/mob/simple_animal/aquatic.dmi deleted file mode 100644 index a5d06a467aa1..000000000000 Binary files a/icons/mob/simple_animal/aquatic.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/bats.dmi b/icons/mob/simple_animal/bats.dmi index 744669350773..795ac2a2f429 100644 Binary files a/icons/mob/simple_animal/bats.dmi and b/icons/mob/simple_animal/bats.dmi differ diff --git a/icons/mob/simple_animal/bear_brown.dmi b/icons/mob/simple_animal/bear_brown.dmi new file mode 100644 index 000000000000..01e02765a848 Binary files /dev/null and b/icons/mob/simple_animal/bear_brown.dmi differ diff --git a/icons/mob/simple_animal/bear_space.dmi b/icons/mob/simple_animal/bear_space.dmi new file mode 100644 index 000000000000..42f217e9036e Binary files /dev/null and b/icons/mob/simple_animal/bear_space.dmi differ diff --git a/icons/mob/simple_animal/bluecrab.dmi b/icons/mob/simple_animal/bluecrab.dmi new file mode 100644 index 000000000000..959f9b435495 Binary files /dev/null and b/icons/mob/simple_animal/bluecrab.dmi differ diff --git a/icons/mob/simple_animal/buck.dmi b/icons/mob/simple_animal/buck.dmi new file mode 100644 index 000000000000..75c1cba6c635 Binary files /dev/null and b/icons/mob/simple_animal/buck.dmi differ diff --git a/icons/mob/simple_animal/bug.dmi b/icons/mob/simple_animal/bug.dmi new file mode 100644 index 000000000000..73ccdcd8746d Binary files /dev/null and b/icons/mob/simple_animal/bug.dmi differ diff --git a/icons/mob/simple_animal/carp.dmi b/icons/mob/simple_animal/carp.dmi deleted file mode 100644 index 5f4b56fbb906..000000000000 Binary files a/icons/mob/simple_animal/carp.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/cat_black.dmi b/icons/mob/simple_animal/cat_black.dmi new file mode 100644 index 000000000000..8b99f530dfad Binary files /dev/null and b/icons/mob/simple_animal/cat_black.dmi differ diff --git a/icons/mob/simple_animal/cat_calico.dmi b/icons/mob/simple_animal/cat_calico.dmi new file mode 100644 index 000000000000..84ae320f6fb1 Binary files /dev/null and b/icons/mob/simple_animal/cat_calico.dmi differ diff --git a/icons/mob/simple_animal/char.dmi b/icons/mob/simple_animal/char.dmi new file mode 100644 index 000000000000..d4b02843e341 Binary files /dev/null and b/icons/mob/simple_animal/char.dmi differ diff --git a/icons/mob/simple_animal/chick.dmi b/icons/mob/simple_animal/chick.dmi new file mode 100644 index 000000000000..76fd360f23c5 Binary files /dev/null and b/icons/mob/simple_animal/chick.dmi differ diff --git a/icons/mob/simple_animal/chicken_black.dmi b/icons/mob/simple_animal/chicken_black.dmi new file mode 100644 index 000000000000..399d397ab609 Binary files /dev/null and b/icons/mob/simple_animal/chicken_black.dmi differ diff --git a/icons/mob/simple_animal/chicken_brown.dmi b/icons/mob/simple_animal/chicken_brown.dmi new file mode 100644 index 000000000000..ffbc5d6139ab Binary files /dev/null and b/icons/mob/simple_animal/chicken_brown.dmi differ diff --git a/icons/mob/simple_animal/chicken_white.dmi b/icons/mob/simple_animal/chicken_white.dmi new file mode 100644 index 000000000000..f9858d3bc7d7 Binary files /dev/null and b/icons/mob/simple_animal/chicken_white.dmi differ diff --git a/icons/mob/simple_animal/clown.dmi b/icons/mob/simple_animal/clown.dmi new file mode 100644 index 000000000000..1623f4d18375 Binary files /dev/null and b/icons/mob/simple_animal/clown.dmi differ diff --git a/icons/mob/simple_animal/construct_artificer.dmi b/icons/mob/simple_animal/construct_artificer.dmi new file mode 100644 index 000000000000..d15ac241c9b7 Binary files /dev/null and b/icons/mob/simple_animal/construct_artificer.dmi differ diff --git a/icons/mob/simple_animal/construct_behemoth.dmi b/icons/mob/simple_animal/construct_behemoth.dmi new file mode 100644 index 000000000000..c88f1de98883 Binary files /dev/null and b/icons/mob/simple_animal/construct_behemoth.dmi differ diff --git a/icons/mob/simple_animal/construct_floating.dmi b/icons/mob/simple_animal/construct_floating.dmi new file mode 100644 index 000000000000..d312c0b99ef7 Binary files /dev/null and b/icons/mob/simple_animal/construct_floating.dmi differ diff --git a/icons/mob/simple_animal/construct_harvester.dmi b/icons/mob/simple_animal/construct_harvester.dmi new file mode 100644 index 000000000000..31af7406151f Binary files /dev/null and b/icons/mob/simple_animal/construct_harvester.dmi differ diff --git a/icons/mob/simple_animal/corgi.dmi b/icons/mob/simple_animal/corgi.dmi new file mode 100644 index 000000000000..118e2670de2b Binary files /dev/null and b/icons/mob/simple_animal/corgi.dmi differ diff --git a/icons/mob/simple_animal/corgi_back.dmi b/icons/mob/simple_animal/corgi_back.dmi deleted file mode 100644 index 81626df03335..000000000000 Binary files a/icons/mob/simple_animal/corgi_back.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/corgi_ghost.dmi b/icons/mob/simple_animal/corgi_ghost.dmi new file mode 100644 index 000000000000..3c94de0436f9 Binary files /dev/null and b/icons/mob/simple_animal/corgi_ghost.dmi differ diff --git a/icons/mob/simple_animal/corgi_head.dmi b/icons/mob/simple_animal/corgi_head.dmi deleted file mode 100644 index 105bdf475027..000000000000 Binary files a/icons/mob/simple_animal/corgi_head.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/corgi_lisa.dmi b/icons/mob/simple_animal/corgi_lisa.dmi new file mode 100644 index 000000000000..8b1b6f7eece9 Binary files /dev/null and b/icons/mob/simple_animal/corgi_lisa.dmi differ diff --git a/icons/mob/simple_animal/cow.dmi b/icons/mob/simple_animal/cow.dmi new file mode 100644 index 000000000000..2ed38790b64d Binary files /dev/null and b/icons/mob/simple_animal/cow.dmi differ diff --git a/icons/mob/simple_animal/crab.dmi b/icons/mob/simple_animal/crab.dmi new file mode 100644 index 000000000000..fbb20972cdf9 Binary files /dev/null and b/icons/mob/simple_animal/crab.dmi differ diff --git a/icons/mob/simple_animal/creature.dmi b/icons/mob/simple_animal/creature.dmi new file mode 100644 index 000000000000..48595b395ef0 Binary files /dev/null and b/icons/mob/simple_animal/creature.dmi differ diff --git a/icons/mob/simple_animal/critter.dmi b/icons/mob/simple_animal/critter.dmi deleted file mode 100644 index 043b388e906c..000000000000 Binary files a/icons/mob/simple_animal/critter.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/crow.dmi b/icons/mob/simple_animal/crow.dmi index 8cefef2a26aa..3841efb01bab 100644 Binary files a/icons/mob/simple_animal/crow.dmi and b/icons/mob/simple_animal/crow.dmi differ diff --git a/icons/mob/simple_animal/diyaab.dmi b/icons/mob/simple_animal/diyaab.dmi new file mode 100644 index 000000000000..e635c5023dfc Binary files /dev/null and b/icons/mob/simple_animal/diyaab.dmi differ diff --git a/icons/mob/simple_animal/doe.dmi b/icons/mob/simple_animal/doe.dmi new file mode 100644 index 000000000000..ddfe508763e0 Binary files /dev/null and b/icons/mob/simple_animal/doe.dmi differ diff --git a/icons/mob/simple_animal/drake.dmi b/icons/mob/simple_animal/drake.dmi deleted file mode 100644 index 8eeaf45b2b48..000000000000 Binary files a/icons/mob/simple_animal/drake.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/drones/combat.dmi b/icons/mob/simple_animal/drones/combat.dmi new file mode 100644 index 000000000000..df3b934e0c28 Binary files /dev/null and b/icons/mob/simple_animal/drones/combat.dmi differ diff --git a/icons/mob/simple_animal/drones/drone.dmi b/icons/mob/simple_animal/drones/drone.dmi new file mode 100644 index 000000000000..e65d42adb64d Binary files /dev/null and b/icons/mob/simple_animal/drones/drone.dmi differ diff --git a/icons/mob/simple_animal/drones/mining.dmi b/icons/mob/simple_animal/drones/mining.dmi new file mode 100644 index 000000000000..e35752e3821c Binary files /dev/null and b/icons/mob/simple_animal/drones/mining.dmi differ diff --git a/icons/mob/simple_animal/duck_brown.dmi b/icons/mob/simple_animal/duck_brown.dmi new file mode 100644 index 000000000000..5bcb6bc0e66c Binary files /dev/null and b/icons/mob/simple_animal/duck_brown.dmi differ diff --git a/icons/mob/simple_animal/duck_mallard.dmi b/icons/mob/simple_animal/duck_mallard.dmi new file mode 100644 index 000000000000..e03ae0e4df40 Binary files /dev/null and b/icons/mob/simple_animal/duck_mallard.dmi differ diff --git a/icons/mob/simple_animal/duck_white.dmi b/icons/mob/simple_animal/duck_white.dmi new file mode 100644 index 000000000000..b036096f4a8d Binary files /dev/null and b/icons/mob/simple_animal/duck_white.dmi differ diff --git a/icons/mob/simple_animal/evilcrab.dmi b/icons/mob/simple_animal/evilcrab.dmi new file mode 100644 index 000000000000..e7454e01d3e6 Binary files /dev/null and b/icons/mob/simple_animal/evilcrab.dmi differ diff --git a/icons/mob/simple_animal/fish_bass.dmi b/icons/mob/simple_animal/fish_bass.dmi new file mode 100644 index 000000000000..18c8f44a1cab Binary files /dev/null and b/icons/mob/simple_animal/fish_bass.dmi differ diff --git a/icons/mob/simple_animal/fish_carp.dmi b/icons/mob/simple_animal/fish_carp.dmi new file mode 100644 index 000000000000..a76bdc4ab624 Binary files /dev/null and b/icons/mob/simple_animal/fish_carp.dmi differ diff --git a/icons/mob/simple_animal/fish_cave.dmi b/icons/mob/simple_animal/fish_cave.dmi new file mode 100644 index 000000000000..40e1f162f863 Binary files /dev/null and b/icons/mob/simple_animal/fish_cave.dmi differ diff --git a/icons/mob/simple_animal/fish_content.dmi b/icons/mob/simple_animal/fish_content.dmi new file mode 100644 index 000000000000..869c65c2ad5f Binary files /dev/null and b/icons/mob/simple_animal/fish_content.dmi differ diff --git a/icons/mob/simple_animal/fish_grump.dmi b/icons/mob/simple_animal/fish_grump.dmi new file mode 100644 index 000000000000..058b690ab466 Binary files /dev/null and b/icons/mob/simple_animal/fish_grump.dmi differ diff --git a/icons/mob/simple_animal/fish_javelin.dmi b/icons/mob/simple_animal/fish_javelin.dmi new file mode 100644 index 000000000000..c5960dd5e5a8 Binary files /dev/null and b/icons/mob/simple_animal/fish_javelin.dmi differ diff --git a/icons/mob/simple_animal/fish_judge.dmi b/icons/mob/simple_animal/fish_judge.dmi new file mode 100644 index 000000000000..b950041acf7f Binary files /dev/null and b/icons/mob/simple_animal/fish_judge.dmi differ diff --git a/icons/mob/simple_animal/fish_koi.dmi b/icons/mob/simple_animal/fish_koi.dmi new file mode 100644 index 000000000000..7e2e4130f5de Binary files /dev/null and b/icons/mob/simple_animal/fish_koi.dmi differ diff --git a/icons/mob/simple_animal/fish_lantern.dmi b/icons/mob/simple_animal/fish_lantern.dmi new file mode 100644 index 000000000000..eea9923c6d45 Binary files /dev/null and b/icons/mob/simple_animal/fish_lantern.dmi differ diff --git a/icons/mob/simple_animal/fish_pike.dmi b/icons/mob/simple_animal/fish_pike.dmi new file mode 100644 index 000000000000..42e2ff338f6f Binary files /dev/null and b/icons/mob/simple_animal/fish_pike.dmi differ diff --git a/icons/mob/simple_animal/fish_salmon.dmi b/icons/mob/simple_animal/fish_salmon.dmi new file mode 100644 index 000000000000..56e77249b1fb Binary files /dev/null and b/icons/mob/simple_animal/fish_salmon.dmi differ diff --git a/icons/mob/simple_animal/fish_trout.dmi b/icons/mob/simple_animal/fish_trout.dmi new file mode 100644 index 000000000000..7425ab2185ab Binary files /dev/null and b/icons/mob/simple_animal/fish_trout.dmi differ diff --git a/icons/mob/simple_animal/forgotten.dmi b/icons/mob/simple_animal/forgotten.dmi new file mode 100644 index 000000000000..20cb55ed976f Binary files /dev/null and b/icons/mob/simple_animal/forgotten.dmi differ diff --git a/icons/mob/simple_animal/fox.dmi b/icons/mob/simple_animal/fox.dmi new file mode 100644 index 000000000000..08154530d783 Binary files /dev/null and b/icons/mob/simple_animal/fox.dmi differ diff --git a/icons/mob/simple_animal/frog_brown.dmi b/icons/mob/simple_animal/frog_brown.dmi new file mode 100644 index 000000000000..7df99f1fa234 Binary files /dev/null and b/icons/mob/simple_animal/frog_brown.dmi differ diff --git a/icons/mob/simple_animal/frog_green.dmi b/icons/mob/simple_animal/frog_green.dmi new file mode 100644 index 000000000000..aaf89429ae3e Binary files /dev/null and b/icons/mob/simple_animal/frog_green.dmi differ diff --git a/icons/mob/simple_animal/frog_purple.dmi b/icons/mob/simple_animal/frog_purple.dmi new file mode 100644 index 000000000000..ae8d0fd842f1 Binary files /dev/null and b/icons/mob/simple_animal/frog_purple.dmi differ diff --git a/icons/mob/simple_animal/frog_yellow.dmi b/icons/mob/simple_animal/frog_yellow.dmi new file mode 100644 index 000000000000..db0aa1a04c1c Binary files /dev/null and b/icons/mob/simple_animal/frog_yellow.dmi differ diff --git a/icons/mob/simple_animal/goat.dmi b/icons/mob/simple_animal/goat.dmi new file mode 100644 index 000000000000..1a8f59c92289 Binary files /dev/null and b/icons/mob/simple_animal/goat.dmi differ diff --git a/icons/mob/simple_animal/goat_guard.dmi b/icons/mob/simple_animal/goat_guard.dmi new file mode 100644 index 000000000000..255663328ccb Binary files /dev/null and b/icons/mob/simple_animal/goat_guard.dmi differ diff --git a/icons/mob/simple_animal/goat_king.dmi b/icons/mob/simple_animal/goat_king.dmi new file mode 100644 index 000000000000..c55209aa0163 Binary files /dev/null and b/icons/mob/simple_animal/goat_king.dmi differ diff --git a/icons/mob/simple_animal/goat_king_phase_2.dmi b/icons/mob/simple_animal/goat_king_phase_2.dmi new file mode 100644 index 000000000000..7815c6e6776e Binary files /dev/null and b/icons/mob/simple_animal/goat_king_phase_2.dmi differ diff --git a/icons/mob/simple_animal/goat_master.dmi b/icons/mob/simple_animal/goat_master.dmi new file mode 100644 index 000000000000..16d2a4c225c8 Binary files /dev/null and b/icons/mob/simple_animal/goat_master.dmi differ diff --git a/icons/mob/simple_animal/goose.dmi b/icons/mob/simple_animal/goose.dmi index 21e48b536ba5..ffed4f077f6f 100644 Binary files a/icons/mob/simple_animal/goose.dmi and b/icons/mob/simple_animal/goose.dmi differ diff --git a/icons/mob/simple_animal/goose_dire.dmi b/icons/mob/simple_animal/goose_dire.dmi new file mode 100644 index 000000000000..f3ce54e3e78e Binary files /dev/null and b/icons/mob/simple_animal/goose_dire.dmi differ diff --git a/icons/mob/simple_animal/hivebot.dmi b/icons/mob/simple_animal/hivebot.dmi deleted file mode 100644 index cb13996361ca..000000000000 Binary files a/icons/mob/simple_animal/hivebot.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/hivebot_engineer.dmi b/icons/mob/simple_animal/hivebot_engineer.dmi new file mode 100644 index 000000000000..dbd86e6f6207 Binary files /dev/null and b/icons/mob/simple_animal/hivebot_engineer.dmi differ diff --git a/icons/mob/simple_animal/hivebots/hivebot_green.dmi b/icons/mob/simple_animal/hivebots/hivebot_green.dmi new file mode 100644 index 000000000000..af859e82b121 Binary files /dev/null and b/icons/mob/simple_animal/hivebots/hivebot_green.dmi differ diff --git a/icons/mob/simple_animal/hivebots/hivebot_red.dmi b/icons/mob/simple_animal/hivebots/hivebot_red.dmi new file mode 100644 index 000000000000..32ab4636993f Binary files /dev/null and b/icons/mob/simple_animal/hivebots/hivebot_red.dmi differ diff --git a/icons/mob/simple_animal/hivebots/hivebot_white.dmi b/icons/mob/simple_animal/hivebots/hivebot_white.dmi new file mode 100644 index 000000000000..ead79af5a6b1 Binary files /dev/null and b/icons/mob/simple_animal/hivebots/hivebot_white.dmi differ diff --git a/icons/mob/simple_animal/hivebots/hivebot_yellow.dmi b/icons/mob/simple_animal/hivebots/hivebot_yellow.dmi new file mode 100644 index 000000000000..421e47424aec Binary files /dev/null and b/icons/mob/simple_animal/hivebots/hivebot_yellow.dmi differ diff --git a/icons/mob/simple_animal/hivebots/megabot.dmi b/icons/mob/simple_animal/hivebots/megabot.dmi new file mode 100644 index 000000000000..107bd1921534 Binary files /dev/null and b/icons/mob/simple_animal/hivebots/megabot.dmi differ diff --git a/icons/mob/simple_animal/holocarp.dmi b/icons/mob/simple_animal/holocarp.dmi new file mode 100644 index 000000000000..72d92acfc8d5 Binary files /dev/null and b/icons/mob/simple_animal/holocarp.dmi differ diff --git a/icons/mob/simple_animal/horror.dmi b/icons/mob/simple_animal/horror.dmi new file mode 100644 index 000000000000..f02edd004e54 Binary files /dev/null and b/icons/mob/simple_animal/horror.dmi differ diff --git a/icons/mob/simple_animal/horse.dmi b/icons/mob/simple_animal/horse.dmi new file mode 100644 index 000000000000..be7de241a933 Binary files /dev/null and b/icons/mob/simple_animal/horse.dmi differ diff --git a/icons/mob/simple_animal/horse_small.dmi b/icons/mob/simple_animal/horse_small.dmi new file mode 100644 index 000000000000..bfd730d25baf Binary files /dev/null and b/icons/mob/simple_animal/horse_small.dmi differ diff --git a/icons/mob/simple_animal/jelly.dmi b/icons/mob/simple_animal/jelly.dmi new file mode 100644 index 000000000000..bead242290ea Binary files /dev/null and b/icons/mob/simple_animal/jelly.dmi differ diff --git a/icons/mob/simple_animal/jelly_alt.dmi b/icons/mob/simple_animal/jelly_alt.dmi new file mode 100644 index 000000000000..621d8da93e7d Binary files /dev/null and b/icons/mob/simple_animal/jelly_alt.dmi differ diff --git a/icons/mob/simple_animal/king_of_goats.dmi b/icons/mob/simple_animal/king_of_goats.dmi deleted file mode 100644 index 69b67ff2c4f5..000000000000 Binary files a/icons/mob/simple_animal/king_of_goats.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/kitten.dmi b/icons/mob/simple_animal/kitten.dmi new file mode 100644 index 000000000000..921ecdddb30d Binary files /dev/null and b/icons/mob/simple_animal/kitten.dmi differ diff --git a/icons/mob/simple_animal/koala.dmi b/icons/mob/simple_animal/koala.dmi new file mode 100644 index 000000000000..65a5a5f134cc Binary files /dev/null and b/icons/mob/simple_animal/koala.dmi differ diff --git a/icons/mob/simple_animal/lavadog.dmi b/icons/mob/simple_animal/lavadog.dmi new file mode 100644 index 000000000000..520d96a55ce3 Binary files /dev/null and b/icons/mob/simple_animal/lavadog.dmi differ diff --git a/icons/mob/simple_animal/lizard.dmi b/icons/mob/simple_animal/lizard.dmi new file mode 100644 index 000000000000..6f794a454680 Binary files /dev/null and b/icons/mob/simple_animal/lizard.dmi differ diff --git a/icons/mob/simple_animal/megabot.dmi b/icons/mob/simple_animal/megabot.dmi deleted file mode 100644 index 0d0318bdb391..000000000000 Binary files a/icons/mob/simple_animal/megabot.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/megaleech.dmi b/icons/mob/simple_animal/megaleech.dmi index 5087cc51038f..2afaa83e200e 100644 Binary files a/icons/mob/simple_animal/megaleech.dmi and b/icons/mob/simple_animal/megaleech.dmi differ diff --git a/icons/mob/simple_animal/mouse_brown.dmi b/icons/mob/simple_animal/mouse_brown.dmi new file mode 100644 index 000000000000..d0d96de3b96e Binary files /dev/null and b/icons/mob/simple_animal/mouse_brown.dmi differ diff --git a/icons/mob/simple_animal/mouse_gray.dmi b/icons/mob/simple_animal/mouse_gray.dmi new file mode 100644 index 000000000000..b654709066e4 Binary files /dev/null and b/icons/mob/simple_animal/mouse_gray.dmi differ diff --git a/icons/mob/simple_animal/mouse_white.dmi b/icons/mob/simple_animal/mouse_white.dmi new file mode 100644 index 000000000000..2117dde52516 Binary files /dev/null and b/icons/mob/simple_animal/mouse_white.dmi differ diff --git a/icons/mob/simple_animal/mushroom.dmi b/icons/mob/simple_animal/mushroom.dmi new file mode 100644 index 000000000000..c8758991aa8e Binary files /dev/null and b/icons/mob/simple_animal/mushroom.dmi differ diff --git a/icons/mob/simple_animal/nanomachines.dmi b/icons/mob/simple_animal/nanomachines.dmi new file mode 100644 index 000000000000..235abd2a9ed7 Binary files /dev/null and b/icons/mob/simple_animal/nanomachines.dmi differ diff --git a/icons/mob/simple_animal/parrot.dmi b/icons/mob/simple_animal/parrot.dmi index 1fc62b5f84b1..14ed5f13262d 100644 Binary files a/icons/mob/simple_animal/parrot.dmi and b/icons/mob/simple_animal/parrot.dmi differ diff --git a/icons/mob/simple_animal/parrot_black.dmi b/icons/mob/simple_animal/parrot_black.dmi new file mode 100644 index 000000000000..9d5540e6632a Binary files /dev/null and b/icons/mob/simple_animal/parrot_black.dmi differ diff --git a/icons/mob/simple_animal/parrot_blue.dmi b/icons/mob/simple_animal/parrot_blue.dmi new file mode 100644 index 000000000000..fdb3c16473c3 Binary files /dev/null and b/icons/mob/simple_animal/parrot_blue.dmi differ diff --git a/icons/mob/simple_animal/parrot_brown.dmi b/icons/mob/simple_animal/parrot_brown.dmi new file mode 100644 index 000000000000..1a689c6aaef1 Binary files /dev/null and b/icons/mob/simple_animal/parrot_brown.dmi differ diff --git a/icons/mob/simple_animal/parrot_green.dmi b/icons/mob/simple_animal/parrot_green.dmi new file mode 100644 index 000000000000..eff8d509463f Binary files /dev/null and b/icons/mob/simple_animal/parrot_green.dmi differ diff --git a/icons/mob/simple_animal/parrot_purple.dmi b/icons/mob/simple_animal/parrot_purple.dmi new file mode 100644 index 000000000000..4c6fa0f99cff Binary files /dev/null and b/icons/mob/simple_animal/parrot_purple.dmi differ diff --git a/icons/mob/simple_animal/parrot_red.dmi b/icons/mob/simple_animal/parrot_red.dmi new file mode 100644 index 000000000000..1723772bd0a6 Binary files /dev/null and b/icons/mob/simple_animal/parrot_red.dmi differ diff --git a/icons/mob/simple_animal/pinetree.dmi b/icons/mob/simple_animal/pinetree.dmi new file mode 100644 index 000000000000..03df0c211cb9 Binary files /dev/null and b/icons/mob/simple_animal/pinetree.dmi differ diff --git a/icons/mob/simple_animal/poppy_possum.dmi b/icons/mob/simple_animal/poppy_possum.dmi index 66a0b0ecc16b..e5e35751d852 100644 Binary files a/icons/mob/simple_animal/poppy_possum.dmi and b/icons/mob/simple_animal/poppy_possum.dmi differ diff --git a/icons/mob/simple_animal/possum.dmi b/icons/mob/simple_animal/possum.dmi index b17a058cdcf1..ba18e76a35ce 100644 Binary files a/icons/mob/simple_animal/possum.dmi and b/icons/mob/simple_animal/possum.dmi differ diff --git a/icons/mob/simple_animal/puppy.dmi b/icons/mob/simple_animal/puppy.dmi new file mode 100644 index 000000000000..a00bd624128c Binary files /dev/null and b/icons/mob/simple_animal/puppy.dmi differ diff --git a/icons/mob/simple_animal/rabbit.dmi b/icons/mob/simple_animal/rabbit.dmi new file mode 100644 index 000000000000..09fa5ad65940 Binary files /dev/null and b/icons/mob/simple_animal/rabbit.dmi differ diff --git a/icons/mob/simple_animal/rat.dmi b/icons/mob/simple_animal/rat.dmi new file mode 100644 index 000000000000..10c31e549369 Binary files /dev/null and b/icons/mob/simple_animal/rat.dmi differ diff --git a/icons/mob/simple_animal/revenant.dmi b/icons/mob/simple_animal/revenant.dmi new file mode 100644 index 000000000000..fea7958ca14d Binary files /dev/null and b/icons/mob/simple_animal/revenant.dmi differ diff --git a/icons/mob/simple_animal/royalcrab.dmi b/icons/mob/simple_animal/royalcrab.dmi new file mode 100644 index 000000000000..8f42782c8ccb Binary files /dev/null and b/icons/mob/simple_animal/royalcrab.dmi differ diff --git a/icons/mob/simple_animal/samak.dmi b/icons/mob/simple_animal/samak.dmi new file mode 100644 index 000000000000..a014698d66bf Binary files /dev/null and b/icons/mob/simple_animal/samak.dmi differ diff --git a/icons/mob/simple_animal/samak_alt.dmi b/icons/mob/simple_animal/samak_alt.dmi new file mode 100644 index 000000000000..c7995c6b216f Binary files /dev/null and b/icons/mob/simple_animal/samak_alt.dmi differ diff --git a/icons/mob/simple_animal/shade.dmi b/icons/mob/simple_animal/shade.dmi new file mode 100644 index 000000000000..f1399f9c0e0a Binary files /dev/null and b/icons/mob/simple_animal/shade.dmi differ diff --git a/icons/mob/simple_animal/shantak.dmi b/icons/mob/simple_animal/shantak.dmi new file mode 100644 index 000000000000..275fd5d0fcfd Binary files /dev/null and b/icons/mob/simple_animal/shantak.dmi differ diff --git a/icons/mob/simple_animal/shantak_alt.dmi b/icons/mob/simple_animal/shantak_alt.dmi new file mode 100644 index 000000000000..873441f93a71 Binary files /dev/null and b/icons/mob/simple_animal/shantak_alt.dmi differ diff --git a/icons/mob/simple_animal/shark.dmi b/icons/mob/simple_animal/shark.dmi new file mode 100644 index 000000000000..1b560d9ba0a8 Binary files /dev/null and b/icons/mob/simple_animal/shark.dmi differ diff --git a/icons/mob/simple_animal/sheep.dmi b/icons/mob/simple_animal/sheep.dmi new file mode 100644 index 000000000000..8501e646b416 Binary files /dev/null and b/icons/mob/simple_animal/sheep.dmi differ diff --git a/icons/mob/simple_animal/slimes.dmi b/icons/mob/simple_animal/slimes.dmi deleted file mode 100644 index 3e6b915efa86..000000000000 Binary files a/icons/mob/simple_animal/slimes.dmi and /dev/null differ diff --git a/icons/mob/simple_animal/slug.dmi b/icons/mob/simple_animal/slug.dmi new file mode 100644 index 000000000000..ba6e188352b3 Binary files /dev/null and b/icons/mob/simple_animal/slug.dmi differ diff --git a/icons/mob/simple_animal/snail.dmi b/icons/mob/simple_animal/snail.dmi new file mode 100644 index 000000000000..cdde2c822eb8 Binary files /dev/null and b/icons/mob/simple_animal/snail.dmi differ diff --git a/icons/mob/simple_animal/space_carp.dmi b/icons/mob/simple_animal/space_carp.dmi new file mode 100644 index 000000000000..59b934b7e63a Binary files /dev/null and b/icons/mob/simple_animal/space_carp.dmi differ diff --git a/icons/mob/simple_animal/space_dragon.dmi b/icons/mob/simple_animal/space_dragon.dmi new file mode 100644 index 000000000000..8e46938e5710 Binary files /dev/null and b/icons/mob/simple_animal/space_dragon.dmi differ diff --git a/icons/mob/simple_animal/spaceshark.dmi b/icons/mob/simple_animal/spaceshark.dmi index 494b4a19efcf..495422c668ef 100644 Binary files a/icons/mob/simple_animal/spaceshark.dmi and b/icons/mob/simple_animal/spaceshark.dmi differ diff --git a/icons/mob/simple_animal/spider.dmi b/icons/mob/simple_animal/spider.dmi index c6209daa3d86..1f4aa0745b60 100644 Binary files a/icons/mob/simple_animal/spider.dmi and b/icons/mob/simple_animal/spider.dmi differ diff --git a/icons/mob/simple_animal/spider_beige.dmi b/icons/mob/simple_animal/spider_beige.dmi new file mode 100644 index 000000000000..01dc61336456 Binary files /dev/null and b/icons/mob/simple_animal/spider_beige.dmi differ diff --git a/icons/mob/simple_animal/spider_black.dmi b/icons/mob/simple_animal/spider_black.dmi new file mode 100644 index 000000000000..165b6405fd00 Binary files /dev/null and b/icons/mob/simple_animal/spider_black.dmi differ diff --git a/icons/mob/simple_animal/spider_green.dmi b/icons/mob/simple_animal/spider_green.dmi new file mode 100644 index 000000000000..e7a6e6bae3c4 Binary files /dev/null and b/icons/mob/simple_animal/spider_green.dmi differ diff --git a/icons/mob/simple_animal/spider_purple.dmi b/icons/mob/simple_animal/spider_purple.dmi new file mode 100644 index 000000000000..be5a85216c99 Binary files /dev/null and b/icons/mob/simple_animal/spider_purple.dmi differ diff --git a/icons/mob/simple_animal/tindalos.dmi b/icons/mob/simple_animal/tindalos.dmi new file mode 100644 index 000000000000..522615651c2d Binary files /dev/null and b/icons/mob/simple_animal/tindalos.dmi differ diff --git a/icons/mob/simple_animal/tomato.dmi b/icons/mob/simple_animal/tomato.dmi new file mode 100644 index 000000000000..e728b7b8c46d Binary files /dev/null and b/icons/mob/simple_animal/tomato.dmi differ diff --git a/icons/mob/simple_animal/vagrant.dmi b/icons/mob/simple_animal/vagrant.dmi new file mode 100644 index 000000000000..3a7e2156f3de Binary files /dev/null and b/icons/mob/simple_animal/vagrant.dmi differ diff --git a/icons/mob/simple_animal/viscerator.dmi b/icons/mob/simple_animal/viscerator.dmi new file mode 100644 index 000000000000..7ee671bea3bf Binary files /dev/null and b/icons/mob/simple_animal/viscerator.dmi differ diff --git a/icons/mob/simple_animal/wolf.dmi b/icons/mob/simple_animal/wolf.dmi new file mode 100644 index 000000000000..9126fe7c5685 Binary files /dev/null and b/icons/mob/simple_animal/wolf.dmi differ diff --git a/icons/mob/simple_animal/yithian.dmi b/icons/mob/simple_animal/yithian.dmi new file mode 100644 index 000000000000..124b1a26fce7 Binary files /dev/null and b/icons/mob/simple_animal/yithian.dmi differ diff --git a/icons/mob/species/monkey/onmob_accessories_monkey.dmi b/icons/mob/species/monkey/onmob_accessories_monkey.dmi deleted file mode 100644 index 6055ae9c39e9..000000000000 Binary files a/icons/mob/species/monkey/onmob_accessories_monkey.dmi and /dev/null differ diff --git a/icons/mob/species/monkey/onmob_under_monkey.dmi b/icons/mob/species/monkey/onmob_under_monkey.dmi deleted file mode 100644 index f714af376dc7..000000000000 Binary files a/icons/mob/species/monkey/onmob_under_monkey.dmi and /dev/null differ diff --git a/icons/mob/status_hunger.dmi b/icons/mob/status_hunger.dmi deleted file mode 100644 index db92eb35581e..000000000000 Binary files a/icons/mob/status_hunger.dmi and /dev/null differ diff --git a/icons/mob/status_indicators.dmi b/icons/mob/status_indicators.dmi deleted file mode 100644 index 80baa88177f7..000000000000 Binary files a/icons/mob/status_indicators.dmi and /dev/null differ diff --git a/icons/mob/surgery.dmi b/icons/mob/surgery.dmi index 8457a59526b3..eb38e6236eb7 100644 Binary files a/icons/mob/surgery.dmi and b/icons/mob/surgery.dmi differ diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi index e83261ae1e7e..43f551defc93 100644 Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ diff --git a/icons/mob/zone_sel.dmi b/icons/mob/zone_sel.dmi index 516874f2a65a..afe5c718595a 100644 Binary files a/icons/mob/zone_sel.dmi and b/icons/mob/zone_sel.dmi differ diff --git a/icons/obj/Cryogenic2.dmi b/icons/obj/Cryogenic2.dmi index 98164e585407..f00c27078e20 100644 Binary files a/icons/obj/Cryogenic2.dmi and b/icons/obj/Cryogenic2.dmi differ diff --git a/icons/obj/action_buttons/actions.dmi b/icons/obj/action_buttons/actions.dmi index 043963e4ef30..209602e1b46b 100644 Binary files a/icons/obj/action_buttons/actions.dmi and b/icons/obj/action_buttons/actions.dmi differ diff --git a/icons/obj/action_buttons/organs.dmi b/icons/obj/action_buttons/organs.dmi index a7aaf3f80b50..0b1d8ebd3030 100644 Binary files a/icons/obj/action_buttons/organs.dmi and b/icons/obj/action_buttons/organs.dmi differ diff --git a/icons/obj/airlock_machines.dmi b/icons/obj/airlock_machines.dmi index 4ab6fec1f58e..3706bc0a5df9 100644 Binary files a/icons/obj/airlock_machines.dmi and b/icons/obj/airlock_machines.dmi differ diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index 4675377c351f..5ae6fdea7fc5 100644 Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ diff --git a/icons/obj/ammo/casings/anti_materiel.dmi b/icons/obj/ammo/casings/anti_materiel.dmi new file mode 100644 index 000000000000..f95bb448913c Binary files /dev/null and b/icons/obj/ammo/casings/anti_materiel.dmi differ diff --git a/icons/obj/ammo/casings/antimaterial.dmi b/icons/obj/ammo/casings/antimaterial.dmi deleted file mode 100644 index 806f77543c04..000000000000 Binary files a/icons/obj/ammo/casings/antimaterial.dmi and /dev/null differ diff --git a/icons/obj/ammo/casings/flechette.dmi b/icons/obj/ammo/casings/flechette.dmi index 843be2012554..665e280da342 100644 Binary files a/icons/obj/ammo/casings/flechette.dmi and b/icons/obj/ammo/casings/flechette.dmi differ diff --git a/icons/obj/ammo/casings/lasbulb.dmi b/icons/obj/ammo/casings/lasbulb.dmi index 5bca476149b3..88c08b5ee0ab 100644 Binary files a/icons/obj/ammo/casings/lasbulb.dmi and b/icons/obj/ammo/casings/lasbulb.dmi differ diff --git a/icons/obj/ammo/casings/magnum.dmi b/icons/obj/ammo/casings/magnum.dmi index fc2d9a75beee..388342650995 100644 Binary files a/icons/obj/ammo/casings/magnum.dmi and b/icons/obj/ammo/casings/magnum.dmi differ diff --git a/icons/obj/ammo/casings/pistol.dmi b/icons/obj/ammo/casings/pistol.dmi index ae2d1a432ea3..73ed63e6435d 100644 Binary files a/icons/obj/ammo/casings/pistol.dmi and b/icons/obj/ammo/casings/pistol.dmi differ diff --git a/icons/obj/ammo/casings/rifle.dmi b/icons/obj/ammo/casings/rifle.dmi index 51d89cb5f4b8..239b0332c32a 100644 Binary files a/icons/obj/ammo/casings/rifle.dmi and b/icons/obj/ammo/casings/rifle.dmi differ diff --git a/icons/obj/ammo/casings/small_pistol.dmi b/icons/obj/ammo/casings/small_pistol.dmi index 1370416b1c28..2f868238f788 100644 Binary files a/icons/obj/ammo/casings/small_pistol.dmi and b/icons/obj/ammo/casings/small_pistol.dmi differ diff --git a/icons/obj/ammo/shells/beanbag.dmi b/icons/obj/ammo/shells/beanbag.dmi new file mode 100644 index 000000000000..7223446a3ebe Binary files /dev/null and b/icons/obj/ammo/shells/beanbag.dmi differ diff --git a/icons/obj/ammo/shells/blanks.dmi b/icons/obj/ammo/shells/blanks.dmi new file mode 100644 index 000000000000..322c1deccfe3 Binary files /dev/null and b/icons/obj/ammo/shells/blanks.dmi differ diff --git a/icons/obj/ammo/shells/buckshot.dmi b/icons/obj/ammo/shells/buckshot.dmi new file mode 100644 index 000000000000..1e015653e97b Binary files /dev/null and b/icons/obj/ammo/shells/buckshot.dmi differ diff --git a/icons/obj/ammo/shells/flash.dmi b/icons/obj/ammo/shells/flash.dmi new file mode 100644 index 000000000000..e715a747393a Binary files /dev/null and b/icons/obj/ammo/shells/flash.dmi differ diff --git a/icons/obj/ammo/shells/haywire.dmi b/icons/obj/ammo/shells/haywire.dmi new file mode 100644 index 000000000000..671477e93dfd Binary files /dev/null and b/icons/obj/ammo/shells/haywire.dmi differ diff --git a/icons/obj/ammo/shells/practice.dmi b/icons/obj/ammo/shells/practice.dmi new file mode 100644 index 000000000000..7b23581df10e Binary files /dev/null and b/icons/obj/ammo/shells/practice.dmi differ diff --git a/icons/obj/ammo/shells/slugs.dmi b/icons/obj/ammo/shells/slugs.dmi new file mode 100644 index 000000000000..6f081288fa1c Binary files /dev/null and b/icons/obj/ammo/shells/slugs.dmi differ diff --git a/icons/obj/ammo/shells/stun.dmi b/icons/obj/ammo/shells/stun.dmi new file mode 100644 index 000000000000..1387132510cd Binary files /dev/null and b/icons/obj/ammo/shells/stun.dmi differ diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi index 93f5bb50f6fd..26ee3a4c8d66 100644 Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ diff --git a/icons/obj/assemblies/circuit_analyzer.dmi b/icons/obj/assemblies/circuit_analyzer.dmi new file mode 100644 index 000000000000..67d7e19c830a Binary files /dev/null and b/icons/obj/assemblies/circuit_analyzer.dmi differ diff --git a/icons/obj/assemblies/electronic_tools.dmi b/icons/obj/assemblies/electronic_tools.dmi index 975f2fc9a812..971683f0743f 100644 Binary files a/icons/obj/assemblies/electronic_tools.dmi and b/icons/obj/assemblies/electronic_tools.dmi differ diff --git a/icons/obj/augment_tools.dmi b/icons/obj/augment_tools.dmi deleted file mode 100644 index cedfe88eec48..000000000000 Binary files a/icons/obj/augment_tools.dmi and /dev/null differ diff --git a/icons/obj/autoinjector.dmi b/icons/obj/autoinjector.dmi new file mode 100644 index 000000000000..95efaa7d773a Binary files /dev/null and b/icons/obj/autoinjector.dmi differ diff --git a/icons/obj/bar_stool.dmi b/icons/obj/bar_stool.dmi new file mode 100644 index 000000000000..93ffba3e8735 Binary files /dev/null and b/icons/obj/bar_stool.dmi differ diff --git a/icons/obj/barsigns.dmi b/icons/obj/barsigns.dmi index ac409de94859..aeb3e4393782 100644 Binary files a/icons/obj/barsigns.dmi and b/icons/obj/barsigns.dmi differ diff --git a/icons/obj/basketball.dmi b/icons/obj/basketball.dmi index e938d8d7201f..35e72d142ab6 100644 Binary files a/icons/obj/basketball.dmi and b/icons/obj/basketball.dmi differ diff --git a/icons/obj/beachball.dmi b/icons/obj/beachball.dmi new file mode 100644 index 000000000000..f011f7cbfac7 Binary files /dev/null and b/icons/obj/beachball.dmi differ diff --git a/icons/obj/bedsheet.dmi b/icons/obj/bedsheet.dmi deleted file mode 100644 index d53251aa4c82..000000000000 Binary files a/icons/obj/bedsheet.dmi and /dev/null differ diff --git a/icons/obj/bedsheets/bedsheet.dmi b/icons/obj/bedsheets/bedsheet.dmi new file mode 100644 index 000000000000..15dd9d61522b Binary files /dev/null and b/icons/obj/bedsheets/bedsheet.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_blue.dmi b/icons/obj/bedsheets/bedsheet_blue.dmi new file mode 100644 index 000000000000..56ed8bc025ee Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_blue.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_brown.dmi b/icons/obj/bedsheets/bedsheet_brown.dmi new file mode 100644 index 000000000000..f6ae09dd6055 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_brown.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_captain.dmi b/icons/obj/bedsheets/bedsheet_captain.dmi new file mode 100644 index 000000000000..6fec42150902 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_captain.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_ce.dmi b/icons/obj/bedsheets/bedsheet_ce.dmi new file mode 100644 index 000000000000..1248c9043f12 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_ce.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_clown.dmi b/icons/obj/bedsheets/bedsheet_clown.dmi new file mode 100644 index 000000000000..5d7ae66224cf Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_clown.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_green.dmi b/icons/obj/bedsheets/bedsheet_green.dmi new file mode 100644 index 000000000000..9a757853337b Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_green.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_hop.dmi b/icons/obj/bedsheets/bedsheet_hop.dmi new file mode 100644 index 000000000000..bc8d696050ca Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_hop.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_hos.dmi b/icons/obj/bedsheets/bedsheet_hos.dmi new file mode 100644 index 000000000000..f00002b05942 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_hos.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_ian.dmi b/icons/obj/bedsheets/bedsheet_ian.dmi new file mode 100644 index 000000000000..0bd37483567e Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_ian.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_medical.dmi b/icons/obj/bedsheets/bedsheet_medical.dmi new file mode 100644 index 000000000000..8f9e347e3a1e Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_medical.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_mime.dmi b/icons/obj/bedsheets/bedsheet_mime.dmi new file mode 100644 index 000000000000..a9ce95040a6c Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_mime.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_orange.dmi b/icons/obj/bedsheets/bedsheet_orange.dmi new file mode 100644 index 000000000000..d795f3cfd1ff Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_orange.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_purple.dmi b/icons/obj/bedsheets/bedsheet_purple.dmi new file mode 100644 index 000000000000..6f6ef9e53f88 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_purple.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_rainbow.dmi b/icons/obj/bedsheets/bedsheet_rainbow.dmi new file mode 100644 index 000000000000..8dcba4f7d975 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_rainbow.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_rd.dmi b/icons/obj/bedsheets/bedsheet_rd.dmi new file mode 100644 index 000000000000..1d407db37797 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_rd.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_red.dmi b/icons/obj/bedsheets/bedsheet_red.dmi new file mode 100644 index 000000000000..9902aa0386c9 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_red.dmi differ diff --git a/icons/obj/bedsheets/bedsheet_yellow.dmi b/icons/obj/bedsheets/bedsheet_yellow.dmi new file mode 100644 index 000000000000..3c5964c494d2 Binary files /dev/null and b/icons/obj/bedsheets/bedsheet_yellow.dmi differ diff --git a/icons/obj/bench.dmi b/icons/obj/bench.dmi new file mode 100644 index 000000000000..15965e0fede1 Binary files /dev/null and b/icons/obj/bench.dmi differ diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi index c815bfcc0803..de226aa40b19 100644 Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ diff --git a/icons/obj/candle.dmi b/icons/obj/candle.dmi deleted file mode 100644 index 73d807cf6df5..000000000000 Binary files a/icons/obj/candle.dmi and /dev/null differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 981749b6e7af..66424d09ad8c 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/christmas.dmi b/icons/obj/christmas.dmi index a42d14ecff52..dedf006c922a 100644 Binary files a/icons/obj/christmas.dmi and b/icons/obj/christmas.dmi differ diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi index 08718eed2228..b72d12a4a898 100644 Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ diff --git a/icons/obj/cloning.dmi b/icons/obj/cloning.dmi index af0bb42e6020..5a80078e4216 100644 Binary files a/icons/obj/cloning.dmi and b/icons/obj/cloning.dmi differ diff --git a/icons/obj/closets/bases/cabinet.dmi b/icons/obj/closets/bases/cabinet.dmi index 236b164ca6ef..603874dd3c18 100644 Binary files a/icons/obj/closets/bases/cabinet.dmi and b/icons/obj/closets/bases/cabinet.dmi differ diff --git a/icons/obj/closets/bases/chest.dmi b/icons/obj/closets/bases/chest.dmi new file mode 100644 index 000000000000..b43edd86460b Binary files /dev/null and b/icons/obj/closets/bases/chest.dmi differ diff --git a/icons/obj/closets/decals/closet.dmi b/icons/obj/closets/decals/closet.dmi index ea42c1f5350f..c98638179a2b 100644 Binary files a/icons/obj/closets/decals/closet.dmi and b/icons/obj/closets/decals/closet.dmi differ diff --git a/icons/obj/clothing/obj_accessories.dmi b/icons/obj/clothing/obj_accessories.dmi deleted file mode 100644 index a7cd35ddb199..000000000000 Binary files a/icons/obj/clothing/obj_accessories.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_belt.dmi b/icons/obj/clothing/obj_belt.dmi deleted file mode 100644 index 43e47d846c45..000000000000 Binary files a/icons/obj/clothing/obj_belt.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_ears.dmi b/icons/obj/clothing/obj_ears.dmi deleted file mode 100644 index b5bbff0a4678..000000000000 Binary files a/icons/obj/clothing/obj_ears.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_eyes.dmi b/icons/obj/clothing/obj_eyes.dmi deleted file mode 100644 index 72fad84df9a1..000000000000 Binary files a/icons/obj/clothing/obj_eyes.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_hands_ring.dmi b/icons/obj/clothing/obj_hands_ring.dmi deleted file mode 100644 index 97b7f24b682e..000000000000 Binary files a/icons/obj/clothing/obj_hands_ring.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_head_ipc.dmi b/icons/obj/clothing/obj_head_ipc.dmi deleted file mode 100644 index 8804df63a317..000000000000 Binary files a/icons/obj/clothing/obj_head_ipc.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_mask.dmi b/icons/obj/clothing/obj_mask.dmi deleted file mode 100644 index 40bdf50cb91b..000000000000 Binary files a/icons/obj/clothing/obj_mask.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_suit_modular_armor.dmi b/icons/obj/clothing/obj_suit_modular_armor.dmi deleted file mode 100644 index 5c81caa5c470..000000000000 Binary files a/icons/obj/clothing/obj_suit_modular_armor.dmi and /dev/null differ diff --git a/icons/obj/clothing/obj_under.dmi b/icons/obj/clothing/obj_under.dmi deleted file mode 100644 index c3953c80971c..000000000000 Binary files a/icons/obj/clothing/obj_under.dmi and /dev/null differ diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi index 497ce35ab8fe..80e9e8896173 100644 Binary files a/icons/obj/computer.dmi and b/icons/obj/computer.dmi differ diff --git a/icons/obj/contraband.dmi b/icons/obj/contraband.dmi deleted file mode 100644 index a18046937b5b..000000000000 Binary files a/icons/obj/contraband.dmi and /dev/null differ diff --git a/icons/obj/crafting_icons.dmi b/icons/obj/crafting_icons.dmi index 2e3ffbce3dc7..59c11464010d 100644 Binary files a/icons/obj/crafting_icons.dmi and b/icons/obj/crafting_icons.dmi differ diff --git a/icons/obj/custom_items_obj.dmi b/icons/obj/custom_items_obj.dmi deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/icons/obj/custom_items_vehicle.dmi b/icons/obj/custom_items_vehicle.dmi new file mode 100644 index 000000000000..a6afb68bab51 Binary files /dev/null and b/icons/obj/custom_items_vehicle.dmi differ diff --git a/icons/obj/debris.dmi b/icons/obj/debris.dmi new file mode 100644 index 000000000000..c039083a4495 Binary files /dev/null and b/icons/obj/debris.dmi differ diff --git a/icons/obj/debris_circuit.dmi b/icons/obj/debris_circuit.dmi new file mode 100644 index 000000000000..1cd54c4bcabf Binary files /dev/null and b/icons/obj/debris_circuit.dmi differ diff --git a/icons/obj/debris_device.dmi b/icons/obj/debris_device.dmi new file mode 100644 index 000000000000..4f1935caabf4 Binary files /dev/null and b/icons/obj/debris_device.dmi differ diff --git a/icons/obj/debris_metal.dmi b/icons/obj/debris_metal.dmi new file mode 100644 index 000000000000..6f94ce14c3c3 Binary files /dev/null and b/icons/obj/debris_metal.dmi differ diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi deleted file mode 100644 index d3679d85fe2a..000000000000 Binary files a/icons/obj/decals.dmi and /dev/null differ diff --git a/icons/obj/defibrillator.dmi b/icons/obj/defibrillator.dmi index f529c36b90ef..a9dc234c56d9 100644 Binary files a/icons/obj/defibrillator.dmi and b/icons/obj/defibrillator.dmi differ diff --git a/icons/obj/defibrillator_compact.dmi b/icons/obj/defibrillator_compact.dmi new file mode 100644 index 000000000000..5f42c0390017 Binary files /dev/null and b/icons/obj/defibrillator_compact.dmi differ diff --git a/icons/obj/defibrillator_paddles.dmi b/icons/obj/defibrillator_paddles.dmi new file mode 100644 index 000000000000..f3ba321fce8a Binary files /dev/null and b/icons/obj/defibrillator_paddles.dmi differ diff --git a/icons/obj/doors/Doorglass.dmi b/icons/obj/doors/Doorglass.dmi index f4afd02c99d1..5582b2739b67 100644 Binary files a/icons/obj/doors/Doorglass.dmi and b/icons/obj/doors/Doorglass.dmi differ diff --git a/icons/obj/doors/blast_doors/door.dmi b/icons/obj/doors/blast_doors/door.dmi new file mode 100644 index 000000000000..f339de89e219 Binary files /dev/null and b/icons/obj/doors/blast_doors/door.dmi differ diff --git a/icons/obj/doors/centcomm/door.dmi b/icons/obj/doors/centcomm/door.dmi index 49f386ff3805..58c8af1f6e22 100644 Binary files a/icons/obj/doors/centcomm/door.dmi and b/icons/obj/doors/centcomm/door.dmi differ diff --git a/icons/obj/doors/double/door.dmi b/icons/obj/doors/double/door.dmi index 7aec3b074f54..0644203d39e0 100644 Binary files a/icons/obj/doors/double/door.dmi and b/icons/obj/doors/double/door.dmi differ diff --git a/icons/obj/doors/elevator/door.dmi b/icons/obj/doors/elevator/door.dmi index 3cfbc002d33a..53e6937830ee 100644 Binary files a/icons/obj/doors/elevator/door.dmi and b/icons/obj/doors/elevator/door.dmi differ diff --git a/icons/obj/doors/hazard/door.dmi b/icons/obj/doors/hazard/door.dmi index e245c08d1e5f..f0aca8d3a546 100644 Binary files a/icons/obj/doors/hazard/door.dmi and b/icons/obj/doors/hazard/door.dmi differ diff --git a/icons/obj/doors/hazard/door_border.dmi b/icons/obj/doors/hazard/door_border.dmi new file mode 100644 index 000000000000..01ff17547a8f Binary files /dev/null and b/icons/obj/doors/hazard/door_border.dmi differ diff --git a/icons/obj/doors/hazard/welded_border.dmi b/icons/obj/doors/hazard/welded_border.dmi new file mode 100644 index 000000000000..4774fcd7d974 Binary files /dev/null and b/icons/obj/doors/hazard/welded_border.dmi differ diff --git a/icons/obj/doors/material_doors.dmi b/icons/obj/doors/material_doors.dmi index a224dd21aa2d..0ccd106e2d09 100644 Binary files a/icons/obj/doors/material_doors.dmi and b/icons/obj/doors/material_doors.dmi differ diff --git a/icons/obj/doors/shutters/door.dmi b/icons/obj/doors/shutters/door.dmi new file mode 100644 index 000000000000..84639f15fcc9 Binary files /dev/null and b/icons/obj/doors/shutters/door.dmi differ diff --git a/icons/obj/doors/station/fill_glass.dmi b/icons/obj/doors/station/fill_glass.dmi index 0d58b1809b1b..47cf423b5f69 100644 Binary files a/icons/obj/doors/station/fill_glass.dmi and b/icons/obj/doors/station/fill_glass.dmi differ diff --git a/icons/obj/drain.dmi b/icons/obj/drain.dmi index 6710dc313b9f..ce87af5524e7 100644 Binary files a/icons/obj/drain.dmi and b/icons/obj/drain.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index ba3f036649c8..76c1ea06d8da 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/drying_rack.dmi b/icons/obj/drying_rack.dmi new file mode 100644 index 000000000000..5e76ef264774 Binary files /dev/null and b/icons/obj/drying_rack.dmi differ diff --git a/icons/obj/fishing_line.dmi b/icons/obj/fishing_line.dmi new file mode 100644 index 000000000000..4824616fa1a6 Binary files /dev/null and b/icons/obj/fishing_line.dmi differ diff --git a/icons/obj/fishing_rod.dmi b/icons/obj/fishing_rod.dmi new file mode 100644 index 000000000000..bcda2798cd4c Binary files /dev/null and b/icons/obj/fishing_rod.dmi differ diff --git a/icons/obj/fishing_rod_advanced.dmi b/icons/obj/fishing_rod_advanced.dmi new file mode 100644 index 000000000000..cfedeef7c7f0 Binary files /dev/null and b/icons/obj/fishing_rod_advanced.dmi differ diff --git a/icons/obj/flamethrower.dmi b/icons/obj/flamethrower.dmi index 0c3ad248c442..8de372d82b23 100644 Binary files a/icons/obj/flamethrower.dmi and b/icons/obj/flamethrower.dmi differ diff --git a/icons/obj/floorlamp.dmi b/icons/obj/floorlamp.dmi new file mode 100644 index 000000000000..d98ea1fb5ca1 Binary files /dev/null and b/icons/obj/floorlamp.dmi differ diff --git a/icons/obj/flora/deadtrees.dmi b/icons/obj/flora/deadtrees.dmi index f76ffd442f99..2afd9416cbfc 100644 Binary files a/icons/obj/flora/deadtrees.dmi and b/icons/obj/flora/deadtrees.dmi differ diff --git a/icons/obj/flora/hardwood.dmi b/icons/obj/flora/hardwood.dmi new file mode 100644 index 000000000000..6e5976eb3d32 Binary files /dev/null and b/icons/obj/flora/hardwood.dmi differ diff --git a/icons/obj/flora/softwood.dmi b/icons/obj/flora/softwood.dmi new file mode 100644 index 000000000000..efbc33beba53 Binary files /dev/null and b/icons/obj/flora/softwood.dmi differ diff --git a/icons/obj/flora/tree_stumps.dmi b/icons/obj/flora/tree_stumps.dmi new file mode 100644 index 000000000000..c79500d17860 Binary files /dev/null and b/icons/obj/flora/tree_stumps.dmi differ diff --git a/icons/obj/food.dmi b/icons/obj/food.dmi deleted file mode 100644 index 7bc3b11a2f7d..000000000000 Binary files a/icons/obj/food.dmi and /dev/null differ diff --git a/icons/obj/food/badrecipe.dmi b/icons/obj/food/badrecipe.dmi new file mode 100644 index 000000000000..070bc5c2ec88 Binary files /dev/null and b/icons/obj/food/badrecipe.dmi differ diff --git a/icons/obj/food/baked/apple_tart.dmi b/icons/obj/food/baked/apple_tart.dmi new file mode 100644 index 000000000000..3254553e0d49 Binary files /dev/null and b/icons/obj/food/baked/apple_tart.dmi differ diff --git a/icons/obj/food/baked/baguette.dmi b/icons/obj/food/baked/baguette.dmi new file mode 100644 index 000000000000..8a2009fd6e6c Binary files /dev/null and b/icons/obj/food/baked/baguette.dmi differ diff --git a/icons/obj/food/baked/bread/banana.dmi b/icons/obj/food/baked/bread/banana.dmi new file mode 100644 index 000000000000..32de7f1cc99b Binary files /dev/null and b/icons/obj/food/baked/bread/banana.dmi differ diff --git a/icons/obj/food/baked/bread/cheese.dmi b/icons/obj/food/baked/bread/cheese.dmi new file mode 100644 index 000000000000..630380ed530a Binary files /dev/null and b/icons/obj/food/baked/bread/cheese.dmi differ diff --git a/icons/obj/food/baked/bread/meat.dmi b/icons/obj/food/baked/bread/meat.dmi new file mode 100644 index 000000000000..3d300deaf4a9 Binary files /dev/null and b/icons/obj/food/baked/bread/meat.dmi differ diff --git a/icons/obj/food/baked/bread/plain.dmi b/icons/obj/food/baked/bread/plain.dmi new file mode 100644 index 000000000000..3e817b10696b Binary files /dev/null and b/icons/obj/food/baked/bread/plain.dmi differ diff --git a/icons/obj/food/baked/bread/slices/banana.dmi b/icons/obj/food/baked/bread/slices/banana.dmi new file mode 100644 index 000000000000..f3e33b2d8c5d Binary files /dev/null and b/icons/obj/food/baked/bread/slices/banana.dmi differ diff --git a/icons/obj/food/baked/bread/slices/cheese.dmi b/icons/obj/food/baked/bread/slices/cheese.dmi new file mode 100644 index 000000000000..29e422223994 Binary files /dev/null and b/icons/obj/food/baked/bread/slices/cheese.dmi differ diff --git a/icons/obj/food/baked/bread/slices/meat.dmi b/icons/obj/food/baked/bread/slices/meat.dmi new file mode 100644 index 000000000000..58ff769ab301 Binary files /dev/null and b/icons/obj/food/baked/bread/slices/meat.dmi differ diff --git a/icons/obj/food/baked/bread/slices/plain.dmi b/icons/obj/food/baked/bread/slices/plain.dmi new file mode 100644 index 000000000000..d4fff48d99e7 Binary files /dev/null and b/icons/obj/food/baked/bread/slices/plain.dmi differ diff --git a/icons/obj/food/baked/bread/slices/tofu.dmi b/icons/obj/food/baked/bread/slices/tofu.dmi new file mode 100644 index 000000000000..fa0f150723e0 Binary files /dev/null and b/icons/obj/food/baked/bread/slices/tofu.dmi differ diff --git a/icons/obj/food/baked/bread/slices/xeno.dmi b/icons/obj/food/baked/bread/slices/xeno.dmi new file mode 100644 index 000000000000..04a30959d8cb Binary files /dev/null and b/icons/obj/food/baked/bread/slices/xeno.dmi differ diff --git a/icons/obj/food/baked/bread/tofu.dmi b/icons/obj/food/baked/bread/tofu.dmi new file mode 100644 index 000000000000..a6074eb0b09c Binary files /dev/null and b/icons/obj/food/baked/bread/tofu.dmi differ diff --git a/icons/obj/food/baked/bread/xeno.dmi b/icons/obj/food/baked/bread/xeno.dmi new file mode 100644 index 000000000000..eb1296c07c4a Binary files /dev/null and b/icons/obj/food/baked/bread/xeno.dmi differ diff --git a/icons/obj/food/baked/bun.dmi b/icons/obj/food/baked/bun.dmi new file mode 100644 index 000000000000..4cb8cff5b42b Binary files /dev/null and b/icons/obj/food/baked/bun.dmi differ diff --git a/icons/obj/food/baked/bunbun.dmi b/icons/obj/food/baked/bunbun.dmi new file mode 100644 index 000000000000..1fcaf2bd10cc Binary files /dev/null and b/icons/obj/food/baked/bunbun.dmi differ diff --git a/icons/obj/food/baked/cakes/apple.dmi b/icons/obj/food/baked/cakes/apple.dmi new file mode 100644 index 000000000000..715460ea8ce6 Binary files /dev/null and b/icons/obj/food/baked/cakes/apple.dmi differ diff --git a/icons/obj/food/baked/cakes/birthday.dmi b/icons/obj/food/baked/cakes/birthday.dmi new file mode 100644 index 000000000000..b6bd69b1b316 Binary files /dev/null and b/icons/obj/food/baked/cakes/birthday.dmi differ diff --git a/icons/obj/food/baked/cakes/brain.dmi b/icons/obj/food/baked/cakes/brain.dmi new file mode 100644 index 000000000000..744c88d734b8 Binary files /dev/null and b/icons/obj/food/baked/cakes/brain.dmi differ diff --git a/icons/obj/food/baked/cakes/carrot.dmi b/icons/obj/food/baked/cakes/carrot.dmi new file mode 100644 index 000000000000..4dbdf8af636d Binary files /dev/null and b/icons/obj/food/baked/cakes/carrot.dmi differ diff --git a/icons/obj/food/baked/cakes/cheese.dmi b/icons/obj/food/baked/cakes/cheese.dmi new file mode 100644 index 000000000000..8328107e88de Binary files /dev/null and b/icons/obj/food/baked/cakes/cheese.dmi differ diff --git a/icons/obj/food/baked/cakes/chocolate.dmi b/icons/obj/food/baked/cakes/chocolate.dmi new file mode 100644 index 000000000000..7fc2f0710a63 Binary files /dev/null and b/icons/obj/food/baked/cakes/chocolate.dmi differ diff --git a/icons/obj/food/baked/cakes/lemon.dmi b/icons/obj/food/baked/cakes/lemon.dmi new file mode 100644 index 000000000000..7ff9fb0b179f Binary files /dev/null and b/icons/obj/food/baked/cakes/lemon.dmi differ diff --git a/icons/obj/food/baked/cakes/lime.dmi b/icons/obj/food/baked/cakes/lime.dmi new file mode 100644 index 000000000000..adc49fa8b0c3 Binary files /dev/null and b/icons/obj/food/baked/cakes/lime.dmi differ diff --git a/icons/obj/food/baked/cakes/orange.dmi b/icons/obj/food/baked/cakes/orange.dmi new file mode 100644 index 000000000000..5b2aabe87d6b Binary files /dev/null and b/icons/obj/food/baked/cakes/orange.dmi differ diff --git a/icons/obj/food/baked/cakes/plain.dmi b/icons/obj/food/baked/cakes/plain.dmi new file mode 100644 index 000000000000..31d38011dbd3 Binary files /dev/null and b/icons/obj/food/baked/cakes/plain.dmi differ diff --git a/icons/obj/food/baked/cakes/pumpkin.dmi b/icons/obj/food/baked/cakes/pumpkin.dmi new file mode 100644 index 000000000000..4d10a39c07e3 Binary files /dev/null and b/icons/obj/food/baked/cakes/pumpkin.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/apple.dmi b/icons/obj/food/baked/cakes/slices/apple.dmi new file mode 100644 index 000000000000..554b44f6fe09 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/apple.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/birthday.dmi b/icons/obj/food/baked/cakes/slices/birthday.dmi new file mode 100644 index 000000000000..25cfd6f267ea Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/birthday.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/brain.dmi b/icons/obj/food/baked/cakes/slices/brain.dmi new file mode 100644 index 000000000000..8accc5141844 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/brain.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/carrot.dmi b/icons/obj/food/baked/cakes/slices/carrot.dmi new file mode 100644 index 000000000000..4712fb9c67bb Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/carrot.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/cheese.dmi b/icons/obj/food/baked/cakes/slices/cheese.dmi new file mode 100644 index 000000000000..8d1d1fe9cce4 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/cheese.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/chocolate.dmi b/icons/obj/food/baked/cakes/slices/chocolate.dmi new file mode 100644 index 000000000000..f9010f1ec4f6 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/chocolate.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/lemon.dmi b/icons/obj/food/baked/cakes/slices/lemon.dmi new file mode 100644 index 000000000000..fb2e1c646eef Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/lemon.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/lime.dmi b/icons/obj/food/baked/cakes/slices/lime.dmi new file mode 100644 index 000000000000..a86cf3fe6df3 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/lime.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/orange.dmi b/icons/obj/food/baked/cakes/slices/orange.dmi new file mode 100644 index 000000000000..aed03a9ef908 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/orange.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/plain.dmi b/icons/obj/food/baked/cakes/slices/plain.dmi new file mode 100644 index 000000000000..a1c2011a6069 Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/plain.dmi differ diff --git a/icons/obj/food/baked/cakes/slices/pumpkin.dmi b/icons/obj/food/baked/cakes/slices/pumpkin.dmi new file mode 100644 index 000000000000..140c72d9ddea Binary files /dev/null and b/icons/obj/food/baked/cakes/slices/pumpkin.dmi differ diff --git a/icons/obj/food/baked/cookie.dmi b/icons/obj/food/baked/cookie.dmi new file mode 100644 index 000000000000..6e04007a7582 Binary files /dev/null and b/icons/obj/food/baked/cookie.dmi differ diff --git a/icons/obj/food/baked/cracker.dmi b/icons/obj/food/baked/cracker.dmi new file mode 100644 index 000000000000..096c812145a0 Binary files /dev/null and b/icons/obj/food/baked/cracker.dmi differ diff --git a/icons/obj/food/baked/dough.dmi b/icons/obj/food/baked/dough.dmi new file mode 100644 index 000000000000..8ac145ee5d39 Binary files /dev/null and b/icons/obj/food/baked/dough.dmi differ diff --git a/icons/obj/food/baked/eggplant_parmigiana.dmi b/icons/obj/food/baked/eggplant_parmigiana.dmi new file mode 100644 index 000000000000..a078a5e22aa3 Binary files /dev/null and b/icons/obj/food/baked/eggplant_parmigiana.dmi differ diff --git a/icons/obj/food/baked/enchiladas.dmi b/icons/obj/food/baked/enchiladas.dmi new file mode 100644 index 000000000000..17b74036efe8 Binary files /dev/null and b/icons/obj/food/baked/enchiladas.dmi differ diff --git a/icons/obj/food/baked/flatbread.dmi b/icons/obj/food/baked/flatbread.dmi new file mode 100644 index 000000000000..fdcc4c15b248 Binary files /dev/null and b/icons/obj/food/baked/flatbread.dmi differ diff --git a/icons/obj/food/baked/flattened_dough.dmi b/icons/obj/food/baked/flattened_dough.dmi new file mode 100644 index 000000000000..569426ae7ae9 Binary files /dev/null and b/icons/obj/food/baked/flattened_dough.dmi differ diff --git a/icons/obj/food/baked/fortune_cookie.dmi b/icons/obj/food/baked/fortune_cookie.dmi new file mode 100644 index 000000000000..d45d0dec1783 Binary files /dev/null and b/icons/obj/food/baked/fortune_cookie.dmi differ diff --git a/icons/obj/food/baked/jellysandwich.dmi b/icons/obj/food/baked/jellysandwich.dmi new file mode 100644 index 000000000000..ddb56eb23125 Binary files /dev/null and b/icons/obj/food/baked/jellysandwich.dmi differ diff --git a/icons/obj/food/baked/jellytoast.dmi b/icons/obj/food/baked/jellytoast.dmi new file mode 100644 index 000000000000..6141ec7da6f6 Binary files /dev/null and b/icons/obj/food/baked/jellytoast.dmi differ diff --git a/icons/obj/food/baked/loaded_potato.dmi b/icons/obj/food/baked/loaded_potato.dmi new file mode 100644 index 000000000000..bfcdf4f35d75 Binary files /dev/null and b/icons/obj/food/baked/loaded_potato.dmi differ diff --git a/icons/obj/food/baked/monkeys_delight.dmi b/icons/obj/food/baked/monkeys_delight.dmi new file mode 100644 index 000000000000..a1c6a633ddfa Binary files /dev/null and b/icons/obj/food/baked/monkeys_delight.dmi differ diff --git a/icons/obj/food/baked/muffin.dmi b/icons/obj/food/baked/muffin.dmi new file mode 100644 index 000000000000..f4b0ea381bf7 Binary files /dev/null and b/icons/obj/food/baked/muffin.dmi differ diff --git a/icons/obj/food/baked/pies/amanita.dmi b/icons/obj/food/baked/pies/amanita.dmi new file mode 100644 index 000000000000..d0350ca3c070 Binary files /dev/null and b/icons/obj/food/baked/pies/amanita.dmi differ diff --git a/icons/obj/food/baked/pies/apple.dmi b/icons/obj/food/baked/pies/apple.dmi new file mode 100644 index 000000000000..a2d2499eb1d5 Binary files /dev/null and b/icons/obj/food/baked/pies/apple.dmi differ diff --git a/icons/obj/food/baked/pies/berry.dmi b/icons/obj/food/baked/pies/berry.dmi new file mode 100644 index 000000000000..fee3dcbff79e Binary files /dev/null and b/icons/obj/food/baked/pies/berry.dmi differ diff --git a/icons/obj/food/baked/pies/cherry.dmi b/icons/obj/food/baked/pies/cherry.dmi new file mode 100644 index 000000000000..d3a1cdfbb27f Binary files /dev/null and b/icons/obj/food/baked/pies/cherry.dmi differ diff --git a/icons/obj/food/baked/pies/meat.dmi b/icons/obj/food/baked/pies/meat.dmi new file mode 100644 index 000000000000..ad78c18cf84f Binary files /dev/null and b/icons/obj/food/baked/pies/meat.dmi differ diff --git a/icons/obj/food/baked/pies/pie.dmi b/icons/obj/food/baked/pies/pie.dmi new file mode 100644 index 000000000000..70dca891ff6d Binary files /dev/null and b/icons/obj/food/baked/pies/pie.dmi differ diff --git a/icons/obj/food/baked/pies/plumphelmet.dmi b/icons/obj/food/baked/pies/plumphelmet.dmi new file mode 100644 index 000000000000..292e45da74ff Binary files /dev/null and b/icons/obj/food/baked/pies/plumphelmet.dmi differ diff --git a/icons/obj/food/baked/pies/xeno.dmi b/icons/obj/food/baked/pies/xeno.dmi new file mode 100644 index 000000000000..4cc0ee3434ab Binary files /dev/null and b/icons/obj/food/baked/pies/xeno.dmi differ diff --git a/icons/obj/food/baked/popcorn.dmi b/icons/obj/food/baked/popcorn.dmi new file mode 100644 index 000000000000..5d355b09dce7 Binary files /dev/null and b/icons/obj/food/baked/popcorn.dmi differ diff --git a/icons/obj/food/baked/pretzel.dmi b/icons/obj/food/baked/pretzel.dmi new file mode 100644 index 000000000000..b2953a5639ce Binary files /dev/null and b/icons/obj/food/baked/pretzel.dmi differ diff --git a/icons/obj/food/baked/sandwich.dmi b/icons/obj/food/baked/sandwich.dmi new file mode 100644 index 000000000000..ce0208d58efc Binary files /dev/null and b/icons/obj/food/baked/sandwich.dmi differ diff --git a/icons/obj/food/baked/scone.dmi b/icons/obj/food/baked/scone.dmi new file mode 100644 index 000000000000..18624afa054d Binary files /dev/null and b/icons/obj/food/baked/scone.dmi differ diff --git a/icons/obj/food/baked/sliced_dough.dmi b/icons/obj/food/baked/sliced_dough.dmi new file mode 100644 index 000000000000..9fa9f9175cc8 Binary files /dev/null and b/icons/obj/food/baked/sliced_dough.dmi differ diff --git a/icons/obj/food/baked/stuffing.dmi b/icons/obj/food/baked/stuffing.dmi new file mode 100644 index 000000000000..81e63b1482d0 Binary files /dev/null and b/icons/obj/food/baked/stuffing.dmi differ diff --git a/icons/obj/food/baked/threebread.dmi b/icons/obj/food/baked/threebread.dmi new file mode 100644 index 000000000000..fb73a81b5634 Binary files /dev/null and b/icons/obj/food/baked/threebread.dmi differ diff --git a/icons/obj/food/baked/toastedsandwich.dmi b/icons/obj/food/baked/toastedsandwich.dmi new file mode 100644 index 000000000000..e3d8c23370a8 Binary files /dev/null and b/icons/obj/food/baked/toastedsandwich.dmi differ diff --git a/icons/obj/food/baked/twobread.dmi b/icons/obj/food/baked/twobread.dmi new file mode 100644 index 000000000000..d5d45e6a2550 Binary files /dev/null and b/icons/obj/food/baked/twobread.dmi differ diff --git a/icons/obj/food/baked/waffles/blue.dmi b/icons/obj/food/baked/waffles/blue.dmi new file mode 100644 index 000000000000..6fe44a8493de Binary files /dev/null and b/icons/obj/food/baked/waffles/blue.dmi differ diff --git a/icons/obj/food/baked/waffles/green.dmi b/icons/obj/food/baked/waffles/green.dmi new file mode 100644 index 000000000000..a39a3cbc0054 Binary files /dev/null and b/icons/obj/food/baked/waffles/green.dmi differ diff --git a/icons/obj/food/baked/waffles/plain.dmi b/icons/obj/food/baked/waffles/plain.dmi new file mode 100644 index 000000000000..0b4a384b8a0b Binary files /dev/null and b/icons/obj/food/baked/waffles/plain.dmi differ diff --git a/icons/obj/food/baked/waffles/yellow.dmi b/icons/obj/food/baked/waffles/yellow.dmi new file mode 100644 index 000000000000..9cf6692b59fb Binary files /dev/null and b/icons/obj/food/baked/waffles/yellow.dmi differ diff --git a/icons/obj/food/burgers/bigbiteburger.dmi b/icons/obj/food/burgers/bigbiteburger.dmi new file mode 100644 index 000000000000..b7857397f70f Binary files /dev/null and b/icons/obj/food/burgers/bigbiteburger.dmi differ diff --git a/icons/obj/food/burgers/brainburger.dmi b/icons/obj/food/burgers/brainburger.dmi new file mode 100644 index 000000000000..fcb0efa4d135 Binary files /dev/null and b/icons/obj/food/burgers/brainburger.dmi differ diff --git a/icons/obj/food/burgers/burger.dmi b/icons/obj/food/burgers/burger.dmi new file mode 100644 index 000000000000..a65a9107edde Binary files /dev/null and b/icons/obj/food/burgers/burger.dmi differ diff --git a/icons/obj/food/burgers/cheeseburger.dmi b/icons/obj/food/burgers/cheeseburger.dmi new file mode 100644 index 000000000000..98fabf71d83f Binary files /dev/null and b/icons/obj/food/burgers/cheeseburger.dmi differ diff --git a/icons/obj/food/burgers/clownburger.dmi b/icons/obj/food/burgers/clownburger.dmi new file mode 100644 index 000000000000..d8ad6e07dc66 Binary files /dev/null and b/icons/obj/food/burgers/clownburger.dmi differ diff --git a/icons/obj/food/burgers/fishburger.dmi b/icons/obj/food/burgers/fishburger.dmi new file mode 100644 index 000000000000..dfcee246e562 Binary files /dev/null and b/icons/obj/food/burgers/fishburger.dmi differ diff --git a/icons/obj/food/burgers/ghostburger.dmi b/icons/obj/food/burgers/ghostburger.dmi new file mode 100644 index 000000000000..4eda121afcdb Binary files /dev/null and b/icons/obj/food/burgers/ghostburger.dmi differ diff --git a/icons/obj/food/burgers/hamburger.dmi b/icons/obj/food/burgers/hamburger.dmi new file mode 100644 index 000000000000..f93dd97260e4 Binary files /dev/null and b/icons/obj/food/burgers/hamburger.dmi differ diff --git a/icons/obj/food/burgers/jellyburger.dmi b/icons/obj/food/burgers/jellyburger.dmi new file mode 100644 index 000000000000..506699d72f27 Binary files /dev/null and b/icons/obj/food/burgers/jellyburger.dmi differ diff --git a/icons/obj/food/burgers/mimeburger.dmi b/icons/obj/food/burgers/mimeburger.dmi new file mode 100644 index 000000000000..d5df1d6bd85d Binary files /dev/null and b/icons/obj/food/burgers/mimeburger.dmi differ diff --git a/icons/obj/food/burgers/roburger.dmi b/icons/obj/food/burgers/roburger.dmi new file mode 100644 index 000000000000..64610f43dc36 Binary files /dev/null and b/icons/obj/food/burgers/roburger.dmi differ diff --git a/icons/obj/food/burgers/spellburger.dmi b/icons/obj/food/burgers/spellburger.dmi new file mode 100644 index 000000000000..6b658c73af8d Binary files /dev/null and b/icons/obj/food/burgers/spellburger.dmi differ diff --git a/icons/obj/food/burgers/superbiteburger.dmi b/icons/obj/food/burgers/superbiteburger.dmi new file mode 100644 index 000000000000..8c834d571b7a Binary files /dev/null and b/icons/obj/food/burgers/superbiteburger.dmi differ diff --git a/icons/obj/food/burgers/tofuburger.dmi b/icons/obj/food/burgers/tofuburger.dmi new file mode 100644 index 000000000000..6f6a0265462c Binary files /dev/null and b/icons/obj/food/burgers/tofuburger.dmi differ diff --git a/icons/obj/food/burgers/xenoburger.dmi b/icons/obj/food/burgers/xenoburger.dmi new file mode 100644 index 000000000000..7f4bce3fd22d Binary files /dev/null and b/icons/obj/food/burgers/xenoburger.dmi differ diff --git a/icons/obj/food/butchery/chopped.dmi b/icons/obj/food/butchery/chopped.dmi new file mode 100644 index 000000000000..21de530fe49c Binary files /dev/null and b/icons/obj/food/butchery/chopped.dmi differ diff --git a/icons/obj/food/butchery/cutlet.dmi b/icons/obj/food/butchery/cutlet.dmi new file mode 100644 index 000000000000..ecbeecbfdd35 Binary files /dev/null and b/icons/obj/food/butchery/cutlet.dmi differ diff --git a/icons/obj/food/butchery/fish.dmi b/icons/obj/food/butchery/fish.dmi new file mode 100644 index 000000000000..91115cafe17d Binary files /dev/null and b/icons/obj/food/butchery/fish.dmi differ diff --git a/icons/obj/food/butchery/fish_grilled.dmi b/icons/obj/food/butchery/fish_grilled.dmi new file mode 100644 index 000000000000..200f9e219b1c Binary files /dev/null and b/icons/obj/food/butchery/fish_grilled.dmi differ diff --git a/icons/obj/food/butchery/haunch.dmi b/icons/obj/food/butchery/haunch.dmi new file mode 100644 index 000000000000..5b856f955700 Binary files /dev/null and b/icons/obj/food/butchery/haunch.dmi differ diff --git a/icons/obj/food/butchery/jerky.dmi b/icons/obj/food/butchery/jerky.dmi new file mode 100644 index 000000000000..9e6b9834a715 Binary files /dev/null and b/icons/obj/food/butchery/jerky.dmi differ diff --git a/icons/obj/food/butchery/kabob.dmi b/icons/obj/food/butchery/kabob.dmi new file mode 100644 index 000000000000..0788ad44c8dc Binary files /dev/null and b/icons/obj/food/butchery/kabob.dmi differ diff --git a/icons/obj/food/butchery/meat1.dmi b/icons/obj/food/butchery/meat1.dmi new file mode 100644 index 000000000000..6d01e9902e5a Binary files /dev/null and b/icons/obj/food/butchery/meat1.dmi differ diff --git a/icons/obj/food/butchery/meat2.dmi b/icons/obj/food/butchery/meat2.dmi new file mode 100644 index 000000000000..e8bc34337887 Binary files /dev/null and b/icons/obj/food/butchery/meat2.dmi differ diff --git a/icons/obj/food/butchery/meat3.dmi b/icons/obj/food/butchery/meat3.dmi new file mode 100644 index 000000000000..41ee0efa910b Binary files /dev/null and b/icons/obj/food/butchery/meat3.dmi differ diff --git a/icons/obj/food/butchery/meatball.dmi b/icons/obj/food/butchery/meatball.dmi new file mode 100644 index 000000000000..0dcc8c14ebb0 Binary files /dev/null and b/icons/obj/food/butchery/meatball.dmi differ diff --git a/icons/obj/food/butchery/mushroom.dmi b/icons/obj/food/butchery/mushroom.dmi new file mode 100644 index 000000000000..ffe5e7e21014 Binary files /dev/null and b/icons/obj/food/butchery/mushroom.dmi differ diff --git a/icons/obj/food/butchery/offal.dmi b/icons/obj/food/butchery/offal.dmi new file mode 100644 index 000000000000..6fc39f68a9b5 Binary files /dev/null and b/icons/obj/food/butchery/offal.dmi differ diff --git a/icons/obj/food/butchery/offal_small.dmi b/icons/obj/food/butchery/offal_small.dmi new file mode 100644 index 000000000000..da3607bb9bdb Binary files /dev/null and b/icons/obj/food/butchery/offal_small.dmi differ diff --git a/icons/obj/food/butchery/rawmeatball.dmi b/icons/obj/food/butchery/rawmeatball.dmi new file mode 100644 index 000000000000..09b299727ba1 Binary files /dev/null and b/icons/obj/food/butchery/rawmeatball.dmi differ diff --git a/icons/obj/food/butchery/ruminant_stomach.dmi b/icons/obj/food/butchery/ruminant_stomach.dmi new file mode 100644 index 000000000000..af2dfee55f95 Binary files /dev/null and b/icons/obj/food/butchery/ruminant_stomach.dmi differ diff --git a/icons/obj/food/butchery/sausage.dmi b/icons/obj/food/butchery/sausage.dmi new file mode 100644 index 000000000000..f39947075b1b Binary files /dev/null and b/icons/obj/food/butchery/sausage.dmi differ diff --git a/icons/obj/food/butchery/side.dmi b/icons/obj/food/butchery/side.dmi new file mode 100644 index 000000000000..a77aec185646 Binary files /dev/null and b/icons/obj/food/butchery/side.dmi differ diff --git a/icons/obj/food/butchery/spider_leg.dmi b/icons/obj/food/butchery/spider_leg.dmi new file mode 100644 index 000000000000..aa6f3a3065f1 Binary files /dev/null and b/icons/obj/food/butchery/spider_leg.dmi differ diff --git a/icons/obj/food/butchery/spider_leg_cooked.dmi b/icons/obj/food/butchery/spider_leg_cooked.dmi new file mode 100644 index 000000000000..93e496104dc4 Binary files /dev/null and b/icons/obj/food/butchery/spider_leg_cooked.dmi differ diff --git a/icons/obj/food/butchery/steak.dmi b/icons/obj/food/butchery/steak.dmi new file mode 100644 index 000000000000..16661e0dbc71 Binary files /dev/null and b/icons/obj/food/butchery/steak.dmi differ diff --git a/icons/obj/food/butchery/tomato.dmi b/icons/obj/food/butchery/tomato.dmi new file mode 100644 index 000000000000..e28034b9c718 Binary files /dev/null and b/icons/obj/food/butchery/tomato.dmi differ diff --git a/icons/obj/food/candied_apple.dmi b/icons/obj/food/candied_apple.dmi new file mode 100644 index 000000000000..2ebac5b6c739 Binary files /dev/null and b/icons/obj/food/candied_apple.dmi differ diff --git a/icons/obj/food/canned/canned.dmi b/icons/obj/food/canned/canned.dmi new file mode 100644 index 000000000000..967cf8625876 Binary files /dev/null and b/icons/obj/food/canned/canned.dmi differ diff --git a/icons/obj/food/chocolatebar.dmi b/icons/obj/food/chocolatebar.dmi new file mode 100644 index 000000000000..8e9d7a01f814 Binary files /dev/null and b/icons/obj/food/chocolatebar.dmi differ diff --git a/icons/obj/food/condiments/barbecue.dmi b/icons/obj/food/condiments/barbecue.dmi new file mode 100644 index 000000000000..0b017704b9d0 Binary files /dev/null and b/icons/obj/food/condiments/barbecue.dmi differ diff --git a/icons/obj/food/condiments/coldsauce.dmi b/icons/obj/food/condiments/coldsauce.dmi new file mode 100644 index 000000000000..84471d7c0d69 Binary files /dev/null and b/icons/obj/food/condiments/coldsauce.dmi differ diff --git a/icons/obj/food/condiments/cornoil.dmi b/icons/obj/food/condiments/cornoil.dmi new file mode 100644 index 000000000000..b3a3892bc941 Binary files /dev/null and b/icons/obj/food/condiments/cornoil.dmi differ diff --git a/icons/obj/food/condiments/empty.dmi b/icons/obj/food/condiments/empty.dmi new file mode 100644 index 000000000000..5fd5b5a6d1a2 Binary files /dev/null and b/icons/obj/food/condiments/empty.dmi differ diff --git a/icons/obj/food/condiments/enzyme.dmi b/icons/obj/food/condiments/enzyme.dmi new file mode 100644 index 000000000000..b6bcd72531b8 Binary files /dev/null and b/icons/obj/food/condiments/enzyme.dmi differ diff --git a/icons/obj/food/condiments/flour.dmi b/icons/obj/food/condiments/flour.dmi new file mode 100644 index 000000000000..5a10991589c4 Binary files /dev/null and b/icons/obj/food/condiments/flour.dmi differ diff --git a/icons/obj/food/condiments/generic.dmi b/icons/obj/food/condiments/generic.dmi new file mode 100644 index 000000000000..8acae4a5717e Binary files /dev/null and b/icons/obj/food/condiments/generic.dmi differ diff --git a/icons/obj/food/condiments/hotsauce.dmi b/icons/obj/food/condiments/hotsauce.dmi new file mode 100644 index 000000000000..56c397952a19 Binary files /dev/null and b/icons/obj/food/condiments/hotsauce.dmi differ diff --git a/icons/obj/food/condiments/ketchup.dmi b/icons/obj/food/condiments/ketchup.dmi new file mode 100644 index 000000000000..30a433c86081 Binary files /dev/null and b/icons/obj/food/condiments/ketchup.dmi differ diff --git a/icons/obj/food/condiments/mayo.dmi b/icons/obj/food/condiments/mayo.dmi new file mode 100644 index 000000000000..7205bfd5d83d Binary files /dev/null and b/icons/obj/food/condiments/mayo.dmi differ diff --git a/icons/obj/food/condiments/packets/packet_black.dmi b/icons/obj/food/condiments/packets/packet_black.dmi new file mode 100644 index 000000000000..cd5b89e6621b Binary files /dev/null and b/icons/obj/food/condiments/packets/packet_black.dmi differ diff --git a/icons/obj/food/condiments/packets/packet_medium.dmi b/icons/obj/food/condiments/packets/packet_medium.dmi new file mode 100644 index 000000000000..74baf0ef4dd0 Binary files /dev/null and b/icons/obj/food/condiments/packets/packet_medium.dmi differ diff --git a/icons/obj/food/condiments/packets/packet_red.dmi b/icons/obj/food/condiments/packets/packet_red.dmi new file mode 100644 index 000000000000..4713b70b052d Binary files /dev/null and b/icons/obj/food/condiments/packets/packet_red.dmi differ diff --git a/icons/obj/food/condiments/packets/packet_small.dmi b/icons/obj/food/condiments/packets/packet_small.dmi new file mode 100644 index 000000000000..fbde2059b64d Binary files /dev/null and b/icons/obj/food/condiments/packets/packet_small.dmi differ diff --git a/icons/obj/food/condiments/packets/packet_white.dmi b/icons/obj/food/condiments/packets/packet_white.dmi new file mode 100644 index 000000000000..20d1688e86d3 Binary files /dev/null and b/icons/obj/food/condiments/packets/packet_white.dmi differ diff --git a/icons/obj/food/condiments/peppermill.dmi b/icons/obj/food/condiments/peppermill.dmi new file mode 100644 index 000000000000..c08a86fac416 Binary files /dev/null and b/icons/obj/food/condiments/peppermill.dmi differ diff --git a/icons/obj/food/condiments/rice.dmi b/icons/obj/food/condiments/rice.dmi new file mode 100644 index 000000000000..33e9218e668f Binary files /dev/null and b/icons/obj/food/condiments/rice.dmi differ diff --git a/icons/obj/food/condiments/saltsack.dmi b/icons/obj/food/condiments/saltsack.dmi new file mode 100644 index 000000000000..03e57a21956e Binary files /dev/null and b/icons/obj/food/condiments/saltsack.dmi differ diff --git a/icons/obj/food/condiments/saltshaker.dmi b/icons/obj/food/condiments/saltshaker.dmi new file mode 100644 index 000000000000..ccf1272d1bf9 Binary files /dev/null and b/icons/obj/food/condiments/saltshaker.dmi differ diff --git a/icons/obj/food/condiments/soysauce.dmi b/icons/obj/food/condiments/soysauce.dmi new file mode 100644 index 000000000000..b7810eb8810c Binary files /dev/null and b/icons/obj/food/condiments/soysauce.dmi differ diff --git a/icons/obj/food/condiments/sugar.dmi b/icons/obj/food/condiments/sugar.dmi new file mode 100644 index 000000000000..e7e841a7487f Binary files /dev/null and b/icons/obj/food/condiments/sugar.dmi differ diff --git a/icons/obj/food/condiments/sugarbag.dmi b/icons/obj/food/condiments/sugarbag.dmi new file mode 100644 index 000000000000..b3f8b8bfa609 Binary files /dev/null and b/icons/obj/food/condiments/sugarbag.dmi differ diff --git a/icons/obj/food/condiments/vinegar.dmi b/icons/obj/food/condiments/vinegar.dmi new file mode 100644 index 000000000000..afcd26f75d2a Binary files /dev/null and b/icons/obj/food/condiments/vinegar.dmi differ diff --git a/icons/obj/food/condiments/yeast.dmi b/icons/obj/food/condiments/yeast.dmi new file mode 100644 index 000000000000..9fc3a092eba7 Binary files /dev/null and b/icons/obj/food/condiments/yeast.dmi differ diff --git a/icons/obj/food/containers/crackerbag.dmi b/icons/obj/food/containers/crackerbag.dmi new file mode 100644 index 000000000000..cb98badfa6cb Binary files /dev/null and b/icons/obj/food/containers/crackerbag.dmi differ diff --git a/icons/obj/food/containers/donutbox.dmi b/icons/obj/food/containers/donutbox.dmi new file mode 100644 index 000000000000..6ca555b434e1 Binary files /dev/null and b/icons/obj/food/containers/donutbox.dmi differ diff --git a/icons/obj/food/containers/eggbox.dmi b/icons/obj/food/containers/eggbox.dmi new file mode 100644 index 000000000000..e90b439e1c94 Binary files /dev/null and b/icons/obj/food/containers/eggbox.dmi differ diff --git a/icons/obj/food/containers/pizzabox.dmi b/icons/obj/food/containers/pizzabox.dmi new file mode 100644 index 000000000000..38845bea26af Binary files /dev/null and b/icons/obj/food/containers/pizzabox.dmi differ diff --git a/icons/obj/food/cooking_vessels/baking_dish.dmi b/icons/obj/food/cooking_vessels/baking_dish.dmi new file mode 100644 index 000000000000..1eb7759f1ca8 Binary files /dev/null and b/icons/obj/food/cooking_vessels/baking_dish.dmi differ diff --git a/icons/obj/food/cooking_vessels/cauldron.dmi b/icons/obj/food/cooking_vessels/cauldron.dmi new file mode 100644 index 000000000000..7be32a10bde4 Binary files /dev/null and b/icons/obj/food/cooking_vessels/cauldron.dmi differ diff --git a/icons/obj/food/cooking_vessels/mixing_bowl.dmi b/icons/obj/food/cooking_vessels/mixing_bowl.dmi new file mode 100644 index 000000000000..1a6980692536 Binary files /dev/null and b/icons/obj/food/cooking_vessels/mixing_bowl.dmi differ diff --git a/icons/obj/food/cooking_vessels/pan.dmi b/icons/obj/food/cooking_vessels/pan.dmi new file mode 100644 index 000000000000..23597f50d07d Binary files /dev/null and b/icons/obj/food/cooking_vessels/pan.dmi differ diff --git a/icons/obj/food/cooking_vessels/pot.dmi b/icons/obj/food/cooking_vessels/pot.dmi new file mode 100644 index 000000000000..368ef60fd408 Binary files /dev/null and b/icons/obj/food/cooking_vessels/pot.dmi differ diff --git a/icons/obj/food/cooking_vessels/skillet.dmi b/icons/obj/food/cooking_vessels/skillet.dmi new file mode 100644 index 000000000000..e45c111b5e11 Binary files /dev/null and b/icons/obj/food/cooking_vessels/skillet.dmi differ diff --git a/icons/obj/food/custom/custom.dmi b/icons/obj/food/custom/custom.dmi new file mode 100644 index 000000000000..7fa7c7d09a89 Binary files /dev/null and b/icons/obj/food/custom/custom.dmi differ diff --git a/icons/obj/food/dairy/butter.dmi b/icons/obj/food/dairy/butter.dmi new file mode 100644 index 000000000000..9c563f1ce00d Binary files /dev/null and b/icons/obj/food/dairy/butter.dmi differ diff --git a/icons/obj/food/dairy/butter_pat.dmi b/icons/obj/food/dairy/butter_pat.dmi new file mode 100644 index 000000000000..80ed9e437927 Binary files /dev/null and b/icons/obj/food/dairy/butter_pat.dmi differ diff --git a/icons/obj/food/dairy/cheese_wedge.dmi b/icons/obj/food/dairy/cheese_wedge.dmi new file mode 100644 index 000000000000..f73d30614b97 Binary files /dev/null and b/icons/obj/food/dairy/cheese_wedge.dmi differ diff --git a/icons/obj/food/dairy/cheese_wheel.dmi b/icons/obj/food/dairy/cheese_wheel.dmi new file mode 100644 index 000000000000..17027f59a151 Binary files /dev/null and b/icons/obj/food/dairy/cheese_wheel.dmi differ diff --git a/icons/obj/food/donkpocket.dmi b/icons/obj/food/donkpocket.dmi new file mode 100644 index 000000000000..8d4699e95e87 Binary files /dev/null and b/icons/obj/food/donkpocket.dmi differ diff --git a/icons/obj/food/donuts/donut.dmi b/icons/obj/food/donuts/donut.dmi new file mode 100644 index 000000000000..31f7bece8a41 Binary files /dev/null and b/icons/obj/food/donuts/donut.dmi differ diff --git a/icons/obj/food/donuts/donut_iced.dmi b/icons/obj/food/donuts/donut_iced.dmi new file mode 100644 index 000000000000..c6cc1b7a8b71 Binary files /dev/null and b/icons/obj/food/donuts/donut_iced.dmi differ diff --git a/icons/obj/food/donuts/donut_jelly.dmi b/icons/obj/food/donuts/donut_jelly.dmi new file mode 100644 index 000000000000..a4632cc9d528 Binary files /dev/null and b/icons/obj/food/donuts/donut_jelly.dmi differ diff --git a/icons/obj/food/donuts/donut_jelly_iced.dmi b/icons/obj/food/donuts/donut_jelly_iced.dmi new file mode 100644 index 000000000000..a6581ed9a6ae Binary files /dev/null and b/icons/obj/food/donuts/donut_jelly_iced.dmi differ diff --git a/icons/obj/food/eggs/egg.dmi b/icons/obj/food/eggs/egg.dmi new file mode 100644 index 000000000000..ca50ab06bb4c Binary files /dev/null and b/icons/obj/food/eggs/egg.dmi differ diff --git a/icons/obj/food/eggs/egg_blue.dmi b/icons/obj/food/eggs/egg_blue.dmi new file mode 100644 index 000000000000..88410742e3b4 Binary files /dev/null and b/icons/obj/food/eggs/egg_blue.dmi differ diff --git a/icons/obj/food/eggs/egg_chocolate.dmi b/icons/obj/food/eggs/egg_chocolate.dmi new file mode 100644 index 000000000000..3bad377aea63 Binary files /dev/null and b/icons/obj/food/eggs/egg_chocolate.dmi differ diff --git a/icons/obj/food/eggs/egg_green.dmi b/icons/obj/food/eggs/egg_green.dmi new file mode 100644 index 000000000000..11d19c482903 Binary files /dev/null and b/icons/obj/food/eggs/egg_green.dmi differ diff --git a/icons/obj/food/eggs/egg_lizard.dmi b/icons/obj/food/eggs/egg_lizard.dmi new file mode 100644 index 000000000000..475dcb8d625c Binary files /dev/null and b/icons/obj/food/eggs/egg_lizard.dmi differ diff --git a/icons/obj/food/eggs/egg_mime.dmi b/icons/obj/food/eggs/egg_mime.dmi new file mode 100644 index 000000000000..3b512981a9f6 Binary files /dev/null and b/icons/obj/food/eggs/egg_mime.dmi differ diff --git a/icons/obj/food/eggs/egg_orange.dmi b/icons/obj/food/eggs/egg_orange.dmi new file mode 100644 index 000000000000..122889072226 Binary files /dev/null and b/icons/obj/food/eggs/egg_orange.dmi differ diff --git a/icons/obj/food/eggs/egg_purple.dmi b/icons/obj/food/eggs/egg_purple.dmi new file mode 100644 index 000000000000..eaab67ae2445 Binary files /dev/null and b/icons/obj/food/eggs/egg_purple.dmi differ diff --git a/icons/obj/food/eggs/egg_rainbow.dmi b/icons/obj/food/eggs/egg_rainbow.dmi new file mode 100644 index 000000000000..c7cf66489047 Binary files /dev/null and b/icons/obj/food/eggs/egg_rainbow.dmi differ diff --git a/icons/obj/food/eggs/egg_red.dmi b/icons/obj/food/eggs/egg_red.dmi new file mode 100644 index 000000000000..40baf4c76057 Binary files /dev/null and b/icons/obj/food/eggs/egg_red.dmi differ diff --git a/icons/obj/food/eggs/egg_yellow.dmi b/icons/obj/food/eggs/egg_yellow.dmi new file mode 100644 index 000000000000..4d55493625d4 Binary files /dev/null and b/icons/obj/food/eggs/egg_yellow.dmi differ diff --git a/icons/obj/food/error.dmi b/icons/obj/food/error.dmi new file mode 100644 index 000000000000..b854b9a610c6 Binary files /dev/null and b/icons/obj/food/error.dmi differ diff --git a/icons/obj/food/fried/cheesyfries.dmi b/icons/obj/food/fried/cheesyfries.dmi new file mode 100644 index 000000000000..dbd9dd37b7f5 Binary files /dev/null and b/icons/obj/food/fried/cheesyfries.dmi differ diff --git a/icons/obj/food/fried/cubancarp.dmi b/icons/obj/food/fried/cubancarp.dmi new file mode 100644 index 000000000000..aca554b14297 Binary files /dev/null and b/icons/obj/food/fried/cubancarp.dmi differ diff --git a/icons/obj/food/fried/fishandchips.dmi b/icons/obj/food/fried/fishandchips.dmi new file mode 100644 index 000000000000..066aed187a68 Binary files /dev/null and b/icons/obj/food/fried/fishandchips.dmi differ diff --git a/icons/obj/food/fried/fishfingers.dmi b/icons/obj/food/fried/fishfingers.dmi new file mode 100644 index 000000000000..2525b580f352 Binary files /dev/null and b/icons/obj/food/fried/fishfingers.dmi differ diff --git a/icons/obj/food/fried/friedegg.dmi b/icons/obj/food/fried/friedegg.dmi new file mode 100644 index 000000000000..2e34eb930d99 Binary files /dev/null and b/icons/obj/food/fried/friedegg.dmi differ diff --git a/icons/obj/food/fried/fries.dmi b/icons/obj/food/fried/fries.dmi new file mode 100644 index 000000000000..05604c917272 Binary files /dev/null and b/icons/obj/food/fried/fries.dmi differ diff --git a/icons/obj/food/fried/omelette.dmi b/icons/obj/food/fried/omelette.dmi new file mode 100644 index 000000000000..85ed5935c54e Binary files /dev/null and b/icons/obj/food/fried/omelette.dmi differ diff --git a/icons/obj/food/fried/onionrings.dmi b/icons/obj/food/fried/onionrings.dmi new file mode 100644 index 000000000000..d1b1a8bed477 Binary files /dev/null and b/icons/obj/food/fried/onionrings.dmi differ diff --git a/icons/obj/food/fried/pancakes.dmi b/icons/obj/food/fried/pancakes.dmi new file mode 100644 index 000000000000..38b1688b55be Binary files /dev/null and b/icons/obj/food/fried/pancakes.dmi differ diff --git a/icons/obj/food/hay.dmi b/icons/obj/food/hay.dmi new file mode 100644 index 000000000000..2a24bc36b017 Binary files /dev/null and b/icons/obj/food/hay.dmi differ diff --git a/icons/obj/food/hotcorgi.dmi b/icons/obj/food/hotcorgi.dmi new file mode 100644 index 000000000000..185bada8af5e Binary files /dev/null and b/icons/obj/food/hotcorgi.dmi differ diff --git a/icons/obj/food/hotdog.dmi b/icons/obj/food/hotdog.dmi new file mode 100644 index 000000000000..3af324ba723a Binary files /dev/null and b/icons/obj/food/hotdog.dmi differ diff --git a/icons/obj/food/junk/junkfood.dmi b/icons/obj/food/junk/junkfood.dmi new file mode 100644 index 000000000000..c9e0f250b6ad Binary files /dev/null and b/icons/obj/food/junk/junkfood.dmi differ diff --git a/icons/obj/food/mint.dmi b/icons/obj/food/mint.dmi new file mode 100644 index 000000000000..f2405b617fc3 Binary files /dev/null and b/icons/obj/food/mint.dmi differ diff --git a/icons/obj/food/mre/mre_crayon.dmi b/icons/obj/food/mre/mre_crayon.dmi new file mode 100644 index 000000000000..73a0372285cc Binary files /dev/null and b/icons/obj/food/mre/mre_crayon.dmi differ diff --git a/icons/obj/food/mre/mre_generic.dmi b/icons/obj/food/mre/mre_generic.dmi new file mode 100644 index 000000000000..9d825aaea4a1 Binary files /dev/null and b/icons/obj/food/mre/mre_generic.dmi differ diff --git a/icons/obj/food/mre/mre_meat.dmi b/icons/obj/food/mre/mre_meat.dmi new file mode 100644 index 000000000000..5d1dca3338d4 Binary files /dev/null and b/icons/obj/food/mre/mre_meat.dmi differ diff --git a/icons/obj/food/mre/mre_veg.dmi b/icons/obj/food/mre/mre_veg.dmi new file mode 100644 index 000000000000..383b464f04e6 Binary files /dev/null and b/icons/obj/food/mre/mre_veg.dmi differ diff --git a/icons/obj/food/mre/pouch_medium.dmi b/icons/obj/food/mre/pouch_medium.dmi new file mode 100644 index 000000000000..1cb0a0704889 Binary files /dev/null and b/icons/obj/food/mre/pouch_medium.dmi differ diff --git a/icons/obj/food/mre/pouch_small.dmi b/icons/obj/food/mre/pouch_small.dmi new file mode 100644 index 000000000000..f81aff5b7894 Binary files /dev/null and b/icons/obj/food/mre/pouch_small.dmi differ diff --git a/icons/obj/food/nuggets/nugget.dmi b/icons/obj/food/nuggets/nugget.dmi new file mode 100644 index 000000000000..6022a38314e4 Binary files /dev/null and b/icons/obj/food/nuggets/nugget.dmi differ diff --git a/icons/obj/food/nuggets/nugget_corgi.dmi b/icons/obj/food/nuggets/nugget_corgi.dmi new file mode 100644 index 000000000000..73f1fe111d03 Binary files /dev/null and b/icons/obj/food/nuggets/nugget_corgi.dmi differ diff --git a/icons/obj/food/nuggets/nugget_lizard.dmi b/icons/obj/food/nuggets/nugget_lizard.dmi new file mode 100644 index 000000000000..7eb06bd525ed Binary files /dev/null and b/icons/obj/food/nuggets/nugget_lizard.dmi differ diff --git a/icons/obj/food/nuggets/nugget_star.dmi b/icons/obj/food/nuggets/nugget_star.dmi new file mode 100644 index 000000000000..28651880ee8f Binary files /dev/null and b/icons/obj/food/nuggets/nugget_star.dmi differ diff --git a/icons/obj/food/old/burger.dmi b/icons/obj/food/old/burger.dmi new file mode 100644 index 000000000000..60576e6e526e Binary files /dev/null and b/icons/obj/food/old/burger.dmi differ diff --git a/icons/obj/food/old/fries.dmi b/icons/obj/food/old/fries.dmi new file mode 100644 index 000000000000..c3ee3e9fe8b0 Binary files /dev/null and b/icons/obj/food/old/fries.dmi differ diff --git a/icons/obj/food/old/hamburger.dmi b/icons/obj/food/old/hamburger.dmi new file mode 100644 index 000000000000..aba2d1b26b40 Binary files /dev/null and b/icons/obj/food/old/hamburger.dmi differ diff --git a/icons/obj/food/old/hotdog.dmi b/icons/obj/food/old/hotdog.dmi new file mode 100644 index 000000000000..fc1ceeac2631 Binary files /dev/null and b/icons/obj/food/old/hotdog.dmi differ diff --git a/icons/obj/food/old/pizza.dmi b/icons/obj/food/old/pizza.dmi new file mode 100644 index 000000000000..03bced6d25cc Binary files /dev/null and b/icons/obj/food/old/pizza.dmi differ diff --git a/icons/obj/food/old/taco.dmi b/icons/obj/food/old/taco.dmi new file mode 100644 index 000000000000..038a967c454a Binary files /dev/null and b/icons/obj/food/old/taco.dmi differ diff --git a/icons/obj/food/pasta/extra_meatball_spaghetti.dmi b/icons/obj/food/pasta/extra_meatball_spaghetti.dmi new file mode 100644 index 000000000000..ed37dd53a688 Binary files /dev/null and b/icons/obj/food/pasta/extra_meatball_spaghetti.dmi differ diff --git a/icons/obj/food/pasta/meatball_spaghetti.dmi b/icons/obj/food/pasta/meatball_spaghetti.dmi new file mode 100644 index 000000000000..51c98ad5318a Binary files /dev/null and b/icons/obj/food/pasta/meatball_spaghetti.dmi differ diff --git a/icons/obj/food/pasta/nanopasta.dmi b/icons/obj/food/pasta/nanopasta.dmi new file mode 100644 index 000000000000..96217cbcc5d8 Binary files /dev/null and b/icons/obj/food/pasta/nanopasta.dmi differ diff --git a/icons/obj/food/pasta/rawspaghetti.dmi b/icons/obj/food/pasta/rawspaghetti.dmi new file mode 100644 index 000000000000..383b0c4a208a Binary files /dev/null and b/icons/obj/food/pasta/rawspaghetti.dmi differ diff --git a/icons/obj/food/pasta/spaghetti.dmi b/icons/obj/food/pasta/spaghetti.dmi new file mode 100644 index 000000000000..b1567a959a59 Binary files /dev/null and b/icons/obj/food/pasta/spaghetti.dmi differ diff --git a/icons/obj/food/pasta/tomato_spaghetti.dmi b/icons/obj/food/pasta/tomato_spaghetti.dmi new file mode 100644 index 000000000000..a32f33f9df51 Binary files /dev/null and b/icons/obj/food/pasta/tomato_spaghetti.dmi differ diff --git a/icons/obj/food/pelmen.dmi b/icons/obj/food/pelmen.dmi new file mode 100644 index 000000000000..56570096d5cf Binary files /dev/null and b/icons/obj/food/pelmen.dmi differ diff --git a/icons/obj/food/pelmeni_boiled.dmi b/icons/obj/food/pelmeni_boiled.dmi new file mode 100644 index 000000000000..df1913d9218c Binary files /dev/null and b/icons/obj/food/pelmeni_boiled.dmi differ diff --git a/icons/obj/food/pizzas/pizza_margherita.dmi b/icons/obj/food/pizzas/pizza_margherita.dmi new file mode 100644 index 000000000000..598370a7c77e Binary files /dev/null and b/icons/obj/food/pizzas/pizza_margherita.dmi differ diff --git a/icons/obj/food/pizzas/pizza_meat.dmi b/icons/obj/food/pizzas/pizza_meat.dmi new file mode 100644 index 000000000000..6d7c48487211 Binary files /dev/null and b/icons/obj/food/pizzas/pizza_meat.dmi differ diff --git a/icons/obj/food/pizzas/pizza_mushroom.dmi b/icons/obj/food/pizzas/pizza_mushroom.dmi new file mode 100644 index 000000000000..411b5e2923ad Binary files /dev/null and b/icons/obj/food/pizzas/pizza_mushroom.dmi differ diff --git a/icons/obj/food/pizzas/pizza_slices.dmi b/icons/obj/food/pizzas/pizza_slices.dmi new file mode 100644 index 000000000000..002ef375903c Binary files /dev/null and b/icons/obj/food/pizzas/pizza_slices.dmi differ diff --git a/icons/obj/food/pizzas/pizza_vegetable.dmi b/icons/obj/food/pizzas/pizza_vegetable.dmi new file mode 100644 index 000000000000..672c5f27bccd Binary files /dev/null and b/icons/obj/food/pizzas/pizza_vegetable.dmi differ diff --git a/icons/obj/food/plates/bowl.dmi b/icons/obj/food/plates/bowl.dmi new file mode 100644 index 000000000000..b57ceec16518 Binary files /dev/null and b/icons/obj/food/plates/bowl.dmi differ diff --git a/icons/obj/food/plates/platter.dmi b/icons/obj/food/plates/platter.dmi new file mode 100644 index 000000000000..1c278ed82b86 Binary files /dev/null and b/icons/obj/food/plates/platter.dmi differ diff --git a/icons/obj/food/plates/small_plate.dmi b/icons/obj/food/plates/small_plate.dmi new file mode 100644 index 000000000000..1d73c7d1d612 Binary files /dev/null and b/icons/obj/food/plates/small_plate.dmi differ diff --git a/icons/obj/food/plates/tray.dmi b/icons/obj/food/plates/tray.dmi new file mode 100644 index 000000000000..86a5033a69c7 Binary files /dev/null and b/icons/obj/food/plates/tray.dmi differ diff --git a/icons/obj/food/pudding/amanita_jelly.dmi b/icons/obj/food/pudding/amanita_jelly.dmi new file mode 100644 index 000000000000..3c502d26816a Binary files /dev/null and b/icons/obj/food/pudding/amanita_jelly.dmi differ diff --git a/icons/obj/food/pudding/chawanmushi.dmi b/icons/obj/food/pudding/chawanmushi.dmi new file mode 100644 index 000000000000..fcdce2f4123c Binary files /dev/null and b/icons/obj/food/pudding/chawanmushi.dmi differ diff --git a/icons/obj/food/pudding/liberty_duff.dmi b/icons/obj/food/pudding/liberty_duff.dmi new file mode 100644 index 000000000000..aecbc115fdd7 Binary files /dev/null and b/icons/obj/food/pudding/liberty_duff.dmi differ diff --git a/icons/obj/food/rice/boiled.dmi b/icons/obj/food/rice/boiled.dmi new file mode 100644 index 000000000000..6fc60e19c400 Binary files /dev/null and b/icons/obj/food/rice/boiled.dmi differ diff --git a/icons/obj/food/rice/chazuke.dmi b/icons/obj/food/rice/chazuke.dmi new file mode 100644 index 000000000000..d1dfd84b5f15 Binary files /dev/null and b/icons/obj/food/rice/chazuke.dmi differ diff --git a/icons/obj/food/rice/katsu.dmi b/icons/obj/food/rice/katsu.dmi new file mode 100644 index 000000000000..8266d4069d11 Binary files /dev/null and b/icons/obj/food/rice/katsu.dmi differ diff --git a/icons/obj/food/rice/pudding.dmi b/icons/obj/food/rice/pudding.dmi new file mode 100644 index 000000000000..9c81bedcbbd1 Binary files /dev/null and b/icons/obj/food/rice/pudding.dmi differ diff --git a/icons/obj/food/salads/salad.dmi b/icons/obj/food/salads/salad.dmi new file mode 100644 index 000000000000..b757d98d3563 Binary files /dev/null and b/icons/obj/food/salads/salad.dmi differ diff --git a/icons/obj/food/taco.dmi b/icons/obj/food/taco.dmi new file mode 100644 index 000000000000..246823c5c027 Binary files /dev/null and b/icons/obj/food/taco.dmi differ diff --git a/icons/obj/food/tofu/soymeat.dmi b/icons/obj/food/tofu/soymeat.dmi new file mode 100644 index 000000000000..3ecd7bd46518 Binary files /dev/null and b/icons/obj/food/tofu/soymeat.dmi differ diff --git a/icons/obj/food/tofu/tofu.dmi b/icons/obj/food/tofu/tofu.dmi new file mode 100644 index 000000000000..58e2261b6447 Binary files /dev/null and b/icons/obj/food/tofu/tofu.dmi differ diff --git a/icons/obj/food/tofu/tofurkey.dmi b/icons/obj/food/tofu/tofurkey.dmi new file mode 100644 index 000000000000..8eb668869f8f Binary files /dev/null and b/icons/obj/food/tofu/tofurkey.dmi differ diff --git a/icons/obj/food/utensils/chopsticks.dmi b/icons/obj/food/utensils/chopsticks.dmi new file mode 100644 index 000000000000..c737bb3fa160 Binary files /dev/null and b/icons/obj/food/utensils/chopsticks.dmi differ diff --git a/icons/obj/food/utensils/foon.dmi b/icons/obj/food/utensils/foon.dmi new file mode 100644 index 000000000000..41a111958bb1 Binary files /dev/null and b/icons/obj/food/utensils/foon.dmi differ diff --git a/icons/obj/food/utensils/fork.dmi b/icons/obj/food/utensils/fork.dmi new file mode 100644 index 000000000000..9508ea4c2365 Binary files /dev/null and b/icons/obj/food/utensils/fork.dmi differ diff --git a/icons/obj/food/utensils/spoon.dmi b/icons/obj/food/utensils/spoon.dmi new file mode 100644 index 000000000000..38fd36ad66a5 Binary files /dev/null and b/icons/obj/food/utensils/spoon.dmi differ diff --git a/icons/obj/food/utensils/spork.dmi b/icons/obj/food/utensils/spork.dmi new file mode 100644 index 000000000000..81ec065937d7 Binary files /dev/null and b/icons/obj/food/utensils/spork.dmi differ diff --git a/icons/obj/food/utensils/steak_knife.dmi b/icons/obj/food/utensils/steak_knife.dmi new file mode 100644 index 000000000000..1484afe56d37 Binary files /dev/null and b/icons/obj/food/utensils/steak_knife.dmi differ diff --git a/icons/obj/food/utensils/table_knife.dmi b/icons/obj/food/utensils/table_knife.dmi new file mode 100644 index 000000000000..87f33b6151dc Binary files /dev/null and b/icons/obj/food/utensils/table_knife.dmi differ diff --git a/icons/obj/food_canned.dmi b/icons/obj/food_canned.dmi deleted file mode 100644 index 405ea82b7924..000000000000 Binary files a/icons/obj/food_canned.dmi and /dev/null differ diff --git a/icons/obj/food_custom.dmi b/icons/obj/food_custom.dmi deleted file mode 100644 index 4ad776cf0d65..000000000000 Binary files a/icons/obj/food_custom.dmi and /dev/null differ diff --git a/icons/obj/food_ingredients.dmi b/icons/obj/food_ingredients.dmi deleted file mode 100644 index ad4ecd8d83fb..000000000000 Binary files a/icons/obj/food_ingredients.dmi and /dev/null differ diff --git a/icons/obj/furniture.dmi b/icons/obj/furniture.dmi index fcf61f9c8986..46c6c0e16dd3 100644 Binary files a/icons/obj/furniture.dmi and b/icons/obj/furniture.dmi differ diff --git a/icons/obj/goal_paperwork.dmi b/icons/obj/goal_paperwork.dmi new file mode 100644 index 000000000000..e8f62e662d20 Binary files /dev/null and b/icons/obj/goal_paperwork.dmi differ diff --git a/icons/obj/grenade.dmi b/icons/obj/grenade.dmi deleted file mode 100644 index 3f0c63e3a4ff..000000000000 Binary files a/icons/obj/grenade.dmi and /dev/null differ diff --git a/icons/obj/grown/chopped.dmi b/icons/obj/grown/chopped.dmi new file mode 100644 index 000000000000..89d0f6a378ca Binary files /dev/null and b/icons/obj/grown/chopped.dmi differ diff --git a/icons/obj/grown/crushed.dmi b/icons/obj/grown/crushed.dmi new file mode 100644 index 000000000000..01e460baa3c6 Binary files /dev/null and b/icons/obj/grown/crushed.dmi differ diff --git a/icons/obj/grown/fruit_slice.dmi b/icons/obj/grown/fruit_slice.dmi new file mode 100644 index 000000000000..91b39f6aadb5 Binary files /dev/null and b/icons/obj/grown/fruit_slice.dmi differ diff --git a/icons/obj/grown/fruit_slice_large.dmi b/icons/obj/grown/fruit_slice_large.dmi new file mode 100644 index 000000000000..b1ab3c35452d Binary files /dev/null and b/icons/obj/grown/fruit_slice_large.dmi differ diff --git a/icons/obj/grown/sticks.dmi b/icons/obj/grown/sticks.dmi new file mode 100644 index 000000000000..12aeab15af14 Binary files /dev/null and b/icons/obj/grown/sticks.dmi differ diff --git a/icons/obj/guns/basic_energy.dmi b/icons/obj/guns/basic_energy.dmi index 8bb69581951b..737cde5906db 100644 Binary files a/icons/obj/guns/basic_energy.dmi and b/icons/obj/guns/basic_energy.dmi differ diff --git a/icons/obj/guns/bolt_action.dmi b/icons/obj/guns/bolt_action.dmi new file mode 100644 index 000000000000..54b224bd7ca8 Binary files /dev/null and b/icons/obj/guns/bolt_action.dmi differ diff --git a/icons/obj/guns/capacitor_rifle.dmi b/icons/obj/guns/capacitor_rifle.dmi index 02e0ccc712b7..442f54df852b 100644 Binary files a/icons/obj/guns/capacitor_rifle.dmi and b/icons/obj/guns/capacitor_rifle.dmi differ diff --git a/icons/obj/guns/fire_staff.dmi b/icons/obj/guns/fire_staff.dmi new file mode 100644 index 000000000000..c3cf609f45bd Binary files /dev/null and b/icons/obj/guns/fire_staff.dmi differ diff --git a/icons/obj/guns/foam/machine_gun.dmi b/icons/obj/guns/foam/machine_gun.dmi new file mode 100644 index 000000000000..fc2ab213fcea Binary files /dev/null and b/icons/obj/guns/foam/machine_gun.dmi differ diff --git a/icons/obj/guns/gui.dmi b/icons/obj/guns/gui.dmi index 48ea898fafcb..5af0c320918f 100644 Binary files a/icons/obj/guns/gui.dmi and b/icons/obj/guns/gui.dmi differ diff --git a/icons/obj/guns/laser_cannon.dmi b/icons/obj/guns/laser_cannon.dmi index 774df13d93b4..bf6d932e7b14 100644 Binary files a/icons/obj/guns/laser_cannon.dmi and b/icons/obj/guns/laser_cannon.dmi differ diff --git a/icons/obj/guns/launcher/bow.dmi b/icons/obj/guns/launcher/bow.dmi new file mode 100644 index 000000000000..c8241859ee98 Binary files /dev/null and b/icons/obj/guns/launcher/bow.dmi differ diff --git a/icons/obj/guns/launcher/bow_fancy.dmi b/icons/obj/guns/launcher/bow_fancy.dmi new file mode 100644 index 000000000000..cbdfb9703782 Binary files /dev/null and b/icons/obj/guns/launcher/bow_fancy.dmi differ diff --git a/icons/obj/guns/launcher/crossbow.dmi b/icons/obj/guns/launcher/crossbow.dmi index f3e2006c4c6c..589b4dfef34d 100644 Binary files a/icons/obj/guns/launcher/crossbow.dmi and b/icons/obj/guns/launcher/crossbow.dmi differ diff --git a/icons/obj/guns/launcher/rcd_bow.dmi b/icons/obj/guns/launcher/rcd_bow.dmi index dbb74be6f3cc..9ea6960729c1 100644 Binary files a/icons/obj/guns/launcher/rcd_bow.dmi and b/icons/obj/guns/launcher/rcd_bow.dmi differ diff --git a/icons/obj/guns/launcher/sling.dmi b/icons/obj/guns/launcher/sling.dmi new file mode 100644 index 000000000000..2b3408286b0a Binary files /dev/null and b/icons/obj/guns/launcher/sling.dmi differ diff --git a/icons/obj/guns/machine.dmi b/icons/obj/guns/machine.dmi new file mode 100644 index 000000000000..cf566eea211c Binary files /dev/null and b/icons/obj/guns/machine.dmi differ diff --git a/icons/obj/guns/pistol.dmi b/icons/obj/guns/pistol.dmi index cc84d7e40ef0..e6e1deb6149b 100644 Binary files a/icons/obj/guns/pistol.dmi and b/icons/obj/guns/pistol.dmi differ diff --git a/icons/obj/guns/random_pistol/base.dmi b/icons/obj/guns/random_pistol/base.dmi new file mode 100644 index 000000000000..87659d598b0e Binary files /dev/null and b/icons/obj/guns/random_pistol/base.dmi differ diff --git a/icons/obj/guns/random_pistol/handle/black.dmi b/icons/obj/guns/random_pistol/handle/black.dmi new file mode 100644 index 000000000000..70c1f32550e6 Binary files /dev/null and b/icons/obj/guns/random_pistol/handle/black.dmi differ diff --git a/icons/obj/guns/random_pistol/handle/ergonomic.dmi b/icons/obj/guns/random_pistol/handle/ergonomic.dmi new file mode 100644 index 000000000000..265b28925fd2 Binary files /dev/null and b/icons/obj/guns/random_pistol/handle/ergonomic.dmi differ diff --git a/icons/obj/guns/random_pistol/handle/revolver.dmi b/icons/obj/guns/random_pistol/handle/revolver.dmi new file mode 100644 index 000000000000..b32045b1352d Binary files /dev/null and b/icons/obj/guns/random_pistol/handle/revolver.dmi differ diff --git a/icons/obj/guns/random_pistol/looks/cover.dmi b/icons/obj/guns/random_pistol/looks/cover.dmi new file mode 100644 index 000000000000..c1c2e0628e16 Binary files /dev/null and b/icons/obj/guns/random_pistol/looks/cover.dmi differ diff --git a/icons/obj/guns/random_pistol/looks/drilled.dmi b/icons/obj/guns/random_pistol/looks/drilled.dmi new file mode 100644 index 000000000000..a47ee8b58275 Binary files /dev/null and b/icons/obj/guns/random_pistol/looks/drilled.dmi differ diff --git a/icons/obj/guns/random_pistol/looks/plated.dmi b/icons/obj/guns/random_pistol/looks/plated.dmi new file mode 100644 index 000000000000..2e4e7f1234e3 Binary files /dev/null and b/icons/obj/guns/random_pistol/looks/plated.dmi differ diff --git a/icons/obj/guns/random_pistol/looks/short.dmi b/icons/obj/guns/random_pistol/looks/short.dmi new file mode 100644 index 000000000000..a3c6c3b35221 Binary files /dev/null and b/icons/obj/guns/random_pistol/looks/short.dmi differ diff --git a/icons/obj/guns/randompistol.dmi b/icons/obj/guns/randompistol.dmi deleted file mode 100644 index 6846573700fb..000000000000 Binary files a/icons/obj/guns/randompistol.dmi and /dev/null differ diff --git a/icons/obj/guns/shotgun/quadbarrel.dmi b/icons/obj/guns/shotgun/quadbarrel.dmi new file mode 100644 index 000000000000..7fbaae5632c6 Binary files /dev/null and b/icons/obj/guns/shotgun/quadbarrel.dmi differ diff --git a/icons/obj/guns/taser.dmi b/icons/obj/guns/taser.dmi index 8b6f06606e4b..0a0b63efa6e9 100644 Binary files a/icons/obj/guns/taser.dmi and b/icons/obj/guns/taser.dmi differ diff --git a/icons/obj/guns/xenoarch/egun_1.dmi b/icons/obj/guns/xenoarch/egun_1.dmi new file mode 100644 index 000000000000..c221c01dc02e Binary files /dev/null and b/icons/obj/guns/xenoarch/egun_1.dmi differ diff --git a/icons/obj/guns/xenoarch/egun_2.dmi b/icons/obj/guns/xenoarch/egun_2.dmi new file mode 100644 index 000000000000..0138fe63289a Binary files /dev/null and b/icons/obj/guns/xenoarch/egun_2.dmi differ diff --git a/icons/obj/guns/xenoarch/egun_3.dmi b/icons/obj/guns/xenoarch/egun_3.dmi new file mode 100644 index 000000000000..6205555fbe34 Binary files /dev/null and b/icons/obj/guns/xenoarch/egun_3.dmi differ diff --git a/icons/obj/guns/xenoarch/egun_4.dmi b/icons/obj/guns/xenoarch/egun_4.dmi new file mode 100644 index 000000000000..83cc8f153c5b Binary files /dev/null and b/icons/obj/guns/xenoarch/egun_4.dmi differ diff --git a/icons/obj/guns/xenoarch/egun_5.dmi b/icons/obj/guns/xenoarch/egun_5.dmi new file mode 100644 index 000000000000..50500b696f55 Binary files /dev/null and b/icons/obj/guns/xenoarch/egun_5.dmi differ diff --git a/icons/obj/guns/xenoarch/egun_6.dmi b/icons/obj/guns/xenoarch/egun_6.dmi new file mode 100644 index 000000000000..cc003d8d2290 Binary files /dev/null and b/icons/obj/guns/xenoarch/egun_6.dmi differ diff --git a/icons/obj/guns/xenoarch/gun_1.dmi b/icons/obj/guns/xenoarch/gun_1.dmi new file mode 100644 index 000000000000..c4bad76c8d0c Binary files /dev/null and b/icons/obj/guns/xenoarch/gun_1.dmi differ diff --git a/icons/obj/guns/xenoarch/gun_2.dmi b/icons/obj/guns/xenoarch/gun_2.dmi new file mode 100644 index 000000000000..5a61b9aaf0ce Binary files /dev/null and b/icons/obj/guns/xenoarch/gun_2.dmi differ diff --git a/icons/obj/guns/xenoarch/gun_3.dmi b/icons/obj/guns/xenoarch/gun_3.dmi new file mode 100644 index 000000000000..522fbc5d8a25 Binary files /dev/null and b/icons/obj/guns/xenoarch/gun_3.dmi differ diff --git a/icons/obj/guns/xenoarch/gun_4.dmi b/icons/obj/guns/xenoarch/gun_4.dmi new file mode 100644 index 000000000000..ada14105cf27 Binary files /dev/null and b/icons/obj/guns/xenoarch/gun_4.dmi differ diff --git a/icons/obj/holosign.dmi b/icons/obj/holosign.dmi index cf1781d4235b..a4493a5ee3e6 100644 Binary files a/icons/obj/holosign.dmi and b/icons/obj/holosign.dmi differ diff --git a/icons/obj/hydroponics/hydroponics_growing.dmi b/icons/obj/hydroponics/hydroponics_growing.dmi index c6cdb9e7fc35..9e4f944856b0 100644 Binary files a/icons/obj/hydroponics/hydroponics_growing.dmi and b/icons/obj/hydroponics/hydroponics_growing.dmi differ diff --git a/icons/obj/hydroponics/hydroponics_machines.dmi b/icons/obj/hydroponics/hydroponics_machines.dmi index 1797358fbba6..4d1dd3990611 100644 Binary files a/icons/obj/hydroponics/hydroponics_machines.dmi and b/icons/obj/hydroponics/hydroponics_machines.dmi differ diff --git a/icons/obj/hydroponics/hydroponics_misc.dmi b/icons/obj/hydroponics/hydroponics_misc.dmi deleted file mode 100644 index a5c594d93ff9..000000000000 Binary files a/icons/obj/hydroponics/hydroponics_misc.dmi and /dev/null differ diff --git a/icons/obj/hydroponics/hydroponics_products.dmi b/icons/obj/hydroponics/hydroponics_products.dmi index d81e83b60ea1..ff7a801afed5 100644 Binary files a/icons/obj/hydroponics/hydroponics_products.dmi and b/icons/obj/hydroponics/hydroponics_products.dmi differ diff --git a/icons/obj/hypospray.dmi b/icons/obj/hypospray.dmi new file mode 100644 index 000000000000..7f737ccff7c1 Binary files /dev/null and b/icons/obj/hypospray.dmi differ diff --git a/icons/obj/hypospray_borg.dmi b/icons/obj/hypospray_borg.dmi new file mode 100644 index 000000000000..1774157a0023 Binary files /dev/null and b/icons/obj/hypospray_borg.dmi differ diff --git a/icons/obj/icecream.dmi b/icons/obj/icecream.dmi new file mode 100644 index 000000000000..f316434f4356 Binary files /dev/null and b/icons/obj/icecream.dmi differ diff --git a/icons/obj/id/id.dmi b/icons/obj/id/id.dmi index 91eece205011..235cf5f1c608 100644 Binary files a/icons/obj/id/id.dmi and b/icons/obj/id/id.dmi differ diff --git a/icons/obj/inhaler.dmi b/icons/obj/inhaler.dmi new file mode 100644 index 000000000000..33ef55957595 Binary files /dev/null and b/icons/obj/inhaler.dmi differ diff --git a/icons/obj/items/air_horn.dmi b/icons/obj/items/air_horn.dmi new file mode 100644 index 000000000000..1b00e02134a4 Binary files /dev/null and b/icons/obj/items/air_horn.dmi differ diff --git a/icons/obj/items/animal_cube.dmi b/icons/obj/items/animal_cube.dmi new file mode 100644 index 000000000000..71c355ce86f1 Binary files /dev/null and b/icons/obj/items/animal_cube.dmi differ diff --git a/icons/obj/items/bandolier.dmi b/icons/obj/items/bandolier.dmi new file mode 100644 index 000000000000..4e73ee678f6d Binary files /dev/null and b/icons/obj/items/bandolier.dmi differ diff --git a/icons/obj/items/bandolier_crafted.dmi b/icons/obj/items/bandolier_crafted.dmi new file mode 100644 index 000000000000..ce931fce194a Binary files /dev/null and b/icons/obj/items/bandolier_crafted.dmi differ diff --git a/icons/obj/items/banners/banner.dmi b/icons/obj/items/banners/banner.dmi new file mode 100644 index 000000000000..7edc1596436d Binary files /dev/null and b/icons/obj/items/banners/banner.dmi differ diff --git a/icons/obj/items/banners/banner_forked.dmi b/icons/obj/items/banners/banner_forked.dmi new file mode 100644 index 000000000000..55ce19fe4928 Binary files /dev/null and b/icons/obj/items/banners/banner_forked.dmi differ diff --git a/icons/obj/items/banners/banner_pointed.dmi b/icons/obj/items/banners/banner_pointed.dmi new file mode 100644 index 000000000000..371cb954f3ad Binary files /dev/null and b/icons/obj/items/banners/banner_pointed.dmi differ diff --git a/icons/obj/items/banners/banner_rounded.dmi b/icons/obj/items/banners/banner_rounded.dmi new file mode 100644 index 000000000000..84ae95413c3a Binary files /dev/null and b/icons/obj/items/banners/banner_rounded.dmi differ diff --git a/icons/obj/items/banners/banner_square.dmi b/icons/obj/items/banners/banner_square.dmi new file mode 100644 index 000000000000..549c0637e18c Binary files /dev/null and b/icons/obj/items/banners/banner_square.dmi differ diff --git a/icons/obj/items/banners/banner_symbols.dmi b/icons/obj/items/banners/banner_symbols.dmi new file mode 100644 index 000000000000..8c77f26d413d Binary files /dev/null and b/icons/obj/items/banners/banner_symbols.dmi differ diff --git a/icons/obj/items/banners/banner_tasselled.dmi b/icons/obj/items/banners/banner_tasselled.dmi new file mode 100644 index 000000000000..271fbce4232c Binary files /dev/null and b/icons/obj/items/banners/banner_tasselled.dmi differ diff --git a/icons/obj/items/banners/banner_woven.dmi b/icons/obj/items/banners/banner_woven.dmi new file mode 100644 index 000000000000..4178722e7b05 Binary files /dev/null and b/icons/obj/items/banners/banner_woven.dmi differ diff --git a/icons/obj/items/banners/sign.dmi b/icons/obj/items/banners/sign.dmi new file mode 100644 index 000000000000..a2fb9ec0361d Binary files /dev/null and b/icons/obj/items/banners/sign.dmi differ diff --git a/icons/obj/items/banners/sign_symbols.dmi b/icons/obj/items/banners/sign_symbols.dmi new file mode 100644 index 000000000000..16ce7891c0c9 Binary files /dev/null and b/icons/obj/items/banners/sign_symbols.dmi differ diff --git a/icons/obj/items/barrel_rim.dmi b/icons/obj/items/barrel_rim.dmi new file mode 100644 index 000000000000..a5567e33c7c5 Binary files /dev/null and b/icons/obj/items/barrel_rim.dmi differ diff --git a/icons/obj/items/bladed/broadsword.dmi b/icons/obj/items/bladed/broadsword.dmi new file mode 100644 index 000000000000..93d7299c910d Binary files /dev/null and b/icons/obj/items/bladed/broadsword.dmi differ diff --git a/icons/obj/items/bladed/fireaxe.dmi b/icons/obj/items/bladed/fireaxe.dmi new file mode 100644 index 000000000000..7c552e235c65 Binary files /dev/null and b/icons/obj/items/bladed/fireaxe.dmi differ diff --git a/icons/obj/items/bladed/folding.dmi b/icons/obj/items/bladed/folding.dmi new file mode 100644 index 000000000000..4e66005b6e63 Binary files /dev/null and b/icons/obj/items/bladed/folding.dmi differ diff --git a/icons/obj/items/bladed/knife.dmi b/icons/obj/items/bladed/knife.dmi new file mode 100644 index 000000000000..a94abd993d25 Binary files /dev/null and b/icons/obj/items/bladed/knife.dmi differ diff --git a/icons/obj/items/bladed/knife_survival.dmi b/icons/obj/items/bladed/knife_survival.dmi new file mode 100644 index 000000000000..aee1b2fc710e Binary files /dev/null and b/icons/obj/items/bladed/knife_survival.dmi differ diff --git a/icons/obj/items/bladed/longsword.dmi b/icons/obj/items/bladed/longsword.dmi new file mode 100644 index 000000000000..fdb161b103d4 Binary files /dev/null and b/icons/obj/items/bladed/longsword.dmi differ diff --git a/icons/obj/items/bladed/poignard.dmi b/icons/obj/items/bladed/poignard.dmi new file mode 100644 index 000000000000..ff1ab4b33ccd Binary files /dev/null and b/icons/obj/items/bladed/poignard.dmi differ diff --git a/icons/obj/items/bladed/rapier.dmi b/icons/obj/items/bladed/rapier.dmi new file mode 100644 index 000000000000..5192e092bda5 Binary files /dev/null and b/icons/obj/items/bladed/rapier.dmi differ diff --git a/icons/obj/items/bladed/shortsword.dmi b/icons/obj/items/bladed/shortsword.dmi new file mode 100644 index 000000000000..efc472f4d4d2 Binary files /dev/null and b/icons/obj/items/bladed/shortsword.dmi differ diff --git a/icons/obj/items/bladed/spear.dmi b/icons/obj/items/bladed/spear.dmi new file mode 100644 index 000000000000..04063a205e89 Binary files /dev/null and b/icons/obj/items/bladed/spear.dmi differ diff --git a/icons/obj/items/books/book.dmi b/icons/obj/items/books/book.dmi new file mode 100644 index 000000000000..d429c4d06cf6 Binary files /dev/null and b/icons/obj/items/books/book.dmi differ diff --git a/icons/obj/items/books/book_analysis.dmi b/icons/obj/items/books/book_analysis.dmi new file mode 100644 index 000000000000..e731933ea768 Binary files /dev/null and b/icons/obj/items/books/book_analysis.dmi differ diff --git a/icons/obj/items/books/book_anomaly.dmi b/icons/obj/items/books/book_anomaly.dmi new file mode 100644 index 000000000000..79c6d7e633e6 Binary files /dev/null and b/icons/obj/items/books/book_anomaly.dmi differ diff --git a/icons/obj/items/books/book_bartending.dmi b/icons/obj/items/books/book_bartending.dmi new file mode 100644 index 000000000000..d5130a098e52 Binary files /dev/null and b/icons/obj/items/books/book_bartending.dmi differ diff --git a/icons/obj/items/books/book_chef.dmi b/icons/obj/items/books/book_chef.dmi new file mode 100644 index 000000000000..c132c71f0379 Binary files /dev/null and b/icons/obj/items/books/book_chef.dmi differ diff --git a/icons/obj/items/books/book_chemistry.dmi b/icons/obj/items/books/book_chemistry.dmi new file mode 100644 index 000000000000..af8436764e83 Binary files /dev/null and b/icons/obj/items/books/book_chemistry.dmi differ diff --git a/icons/obj/items/books/book_chemistry_alt.dmi b/icons/obj/items/books/book_chemistry_alt.dmi new file mode 100644 index 000000000000..676258c317b0 Binary files /dev/null and b/icons/obj/items/books/book_chemistry_alt.dmi differ diff --git a/icons/obj/items/books/book_cloning.dmi b/icons/obj/items/books/book_cloning.dmi new file mode 100644 index 000000000000..539fced5d3c3 Binary files /dev/null and b/icons/obj/items/books/book_cloning.dmi differ diff --git a/icons/obj/items/books/book_combat.dmi b/icons/obj/items/books/book_combat.dmi new file mode 100644 index 000000000000..7ed4a116e988 Binary files /dev/null and b/icons/obj/items/books/book_combat.dmi differ diff --git a/icons/obj/items/books/book_cookbook.dmi b/icons/obj/items/books/book_cookbook.dmi new file mode 100644 index 000000000000..5afb835a76b4 Binary files /dev/null and b/icons/obj/items/books/book_cookbook.dmi differ diff --git a/icons/obj/items/books/book_cyborg.dmi b/icons/obj/items/books/book_cyborg.dmi new file mode 100644 index 000000000000..c2e04d7612e8 Binary files /dev/null and b/icons/obj/items/books/book_cyborg.dmi differ diff --git a/icons/obj/items/books/book_detective.dmi b/icons/obj/items/books/book_detective.dmi new file mode 100644 index 000000000000..9b4cb08dc0a8 Binary files /dev/null and b/icons/obj/items/books/book_detective.dmi differ diff --git a/icons/obj/items/books/book_engineering.dmi b/icons/obj/items/books/book_engineering.dmi new file mode 100644 index 000000000000..79c9bd945e5a Binary files /dev/null and b/icons/obj/items/books/book_engineering.dmi differ diff --git a/icons/obj/items/books/book_engineering_alt.dmi b/icons/obj/items/books/book_engineering_alt.dmi new file mode 100644 index 000000000000..1294b84a40d3 Binary files /dev/null and b/icons/obj/items/books/book_engineering_alt.dmi differ diff --git a/icons/obj/items/books/book_eva.dmi b/icons/obj/items/books/book_eva.dmi new file mode 100644 index 000000000000..324cd115bf43 Binary files /dev/null and b/icons/obj/items/books/book_eva.dmi differ diff --git a/icons/obj/items/books/book_excavation.dmi b/icons/obj/items/books/book_excavation.dmi new file mode 100644 index 000000000000..13490452747b Binary files /dev/null and b/icons/obj/items/books/book_excavation.dmi differ diff --git a/icons/obj/items/books/book_finance.dmi b/icons/obj/items/books/book_finance.dmi new file mode 100644 index 000000000000..ff330cf3540f Binary files /dev/null and b/icons/obj/items/books/book_finance.dmi differ diff --git a/icons/obj/items/books/book_hacking.dmi b/icons/obj/items/books/book_hacking.dmi new file mode 100644 index 000000000000..9529fa1b74e5 Binary files /dev/null and b/icons/obj/items/books/book_hacking.dmi differ diff --git a/icons/obj/items/books/book_hauling.dmi b/icons/obj/items/books/book_hauling.dmi new file mode 100644 index 000000000000..9221efadac30 Binary files /dev/null and b/icons/obj/items/books/book_hauling.dmi differ diff --git a/icons/obj/items/books/book_hydroponics.dmi b/icons/obj/items/books/book_hydroponics.dmi new file mode 100644 index 000000000000..7a5e7d282a50 Binary files /dev/null and b/icons/obj/items/books/book_hydroponics.dmi differ diff --git a/icons/obj/items/books/book_law.dmi b/icons/obj/items/books/book_law.dmi new file mode 100644 index 000000000000..6827d5b69d55 Binary files /dev/null and b/icons/obj/items/books/book_law.dmi differ diff --git a/icons/obj/items/books/book_literacy.dmi b/icons/obj/items/books/book_literacy.dmi new file mode 100644 index 000000000000..b85a19e7385f Binary files /dev/null and b/icons/obj/items/books/book_literacy.dmi differ diff --git a/icons/obj/items/books/book_mech.dmi b/icons/obj/items/books/book_mech.dmi new file mode 100644 index 000000000000..447391d07a8a Binary files /dev/null and b/icons/obj/items/books/book_mech.dmi differ diff --git a/icons/obj/items/books/book_medical.dmi b/icons/obj/items/books/book_medical.dmi new file mode 100644 index 000000000000..983dbabe235c Binary files /dev/null and b/icons/obj/items/books/book_medical.dmi differ diff --git a/icons/obj/items/books/book_nuclear.dmi b/icons/obj/items/books/book_nuclear.dmi new file mode 100644 index 000000000000..f06e7b800983 Binary files /dev/null and b/icons/obj/items/books/book_nuclear.dmi differ diff --git a/icons/obj/items/books/book_particle.dmi b/icons/obj/items/books/book_particle.dmi new file mode 100644 index 000000000000..2e51f8bc56c4 Binary files /dev/null and b/icons/obj/items/books/book_particle.dmi differ diff --git a/icons/obj/items/books/book_pilot.dmi b/icons/obj/items/books/book_pilot.dmi new file mode 100644 index 000000000000..18afe76d7f1d Binary files /dev/null and b/icons/obj/items/books/book_pilot.dmi differ diff --git a/icons/obj/items/books/book_piping.dmi b/icons/obj/items/books/book_piping.dmi new file mode 100644 index 000000000000..5cb0ed164597 Binary files /dev/null and b/icons/obj/items/books/book_piping.dmi differ diff --git a/icons/obj/items/books/book_printable_black.dmi b/icons/obj/items/books/book_printable_black.dmi new file mode 100644 index 000000000000..88b0394bdc7e Binary files /dev/null and b/icons/obj/items/books/book_printable_black.dmi differ diff --git a/icons/obj/items/books/book_printable_blue.dmi b/icons/obj/items/books/book_printable_blue.dmi new file mode 100644 index 000000000000..0f17d4bf8c4b Binary files /dev/null and b/icons/obj/items/books/book_printable_blue.dmi differ diff --git a/icons/obj/items/books/book_printable_green.dmi b/icons/obj/items/books/book_printable_green.dmi new file mode 100644 index 000000000000..0da07199b8ca Binary files /dev/null and b/icons/obj/items/books/book_printable_green.dmi differ diff --git a/icons/obj/items/books/book_printable_light_blue.dmi b/icons/obj/items/books/book_printable_light_blue.dmi new file mode 100644 index 000000000000..eb67562af11e Binary files /dev/null and b/icons/obj/items/books/book_printable_light_blue.dmi differ diff --git a/icons/obj/items/books/book_printable_magazine.dmi b/icons/obj/items/books/book_printable_magazine.dmi new file mode 100644 index 000000000000..c78c1d38c56e Binary files /dev/null and b/icons/obj/items/books/book_printable_magazine.dmi differ diff --git a/icons/obj/items/books/book_printable_purple.dmi b/icons/obj/items/books/book_printable_purple.dmi new file mode 100644 index 000000000000..a6828975a1de Binary files /dev/null and b/icons/obj/items/books/book_printable_purple.dmi differ diff --git a/icons/obj/items/books/book_printable_red.dmi b/icons/obj/items/books/book_printable_red.dmi new file mode 100644 index 000000000000..c2bd9b61f360 Binary files /dev/null and b/icons/obj/items/books/book_printable_red.dmi differ diff --git a/icons/obj/items/books/book_printable_yellow.dmi b/icons/obj/items/books/book_printable_yellow.dmi new file mode 100644 index 000000000000..87074f2460e8 Binary files /dev/null and b/icons/obj/items/books/book_printable_yellow.dmi differ diff --git a/icons/obj/items/books/book_research.dmi b/icons/obj/items/books/book_research.dmi new file mode 100644 index 000000000000..240dd0617766 Binary files /dev/null and b/icons/obj/items/books/book_research.dmi differ diff --git a/icons/obj/items/books/book_singularity.dmi b/icons/obj/items/books/book_singularity.dmi new file mode 100644 index 000000000000..47c03ee3cb62 Binary files /dev/null and b/icons/obj/items/books/book_singularity.dmi differ diff --git a/icons/obj/items/books/book_solgov_law.dmi b/icons/obj/items/books/book_solgov_law.dmi new file mode 100644 index 000000000000..1223eef11595 Binary files /dev/null and b/icons/obj/items/books/book_solgov_law.dmi differ diff --git a/icons/obj/items/books/book_solgov_regs.dmi b/icons/obj/items/books/book_solgov_regs.dmi new file mode 100644 index 000000000000..6475d939cb9a Binary files /dev/null and b/icons/obj/items/books/book_solgov_regs.dmi differ diff --git a/icons/obj/items/books/book_stasis.dmi b/icons/obj/items/books/book_stasis.dmi new file mode 100644 index 000000000000..5e044e89bc4c Binary files /dev/null and b/icons/obj/items/books/book_stasis.dmi differ diff --git a/icons/obj/items/books/book_supermatter.dmi b/icons/obj/items/books/book_supermatter.dmi new file mode 100644 index 000000000000..0354a6f6befb Binary files /dev/null and b/icons/obj/items/books/book_supermatter.dmi differ diff --git a/icons/obj/items/books/book_triangulate.dmi b/icons/obj/items/books/book_triangulate.dmi new file mode 100644 index 000000000000..6fc15c3e4c84 Binary files /dev/null and b/icons/obj/items/books/book_triangulate.dmi differ diff --git a/icons/obj/items/books/book_weapon.dmi b/icons/obj/items/books/book_weapon.dmi new file mode 100644 index 000000000000..ce2951219a02 Binary files /dev/null and b/icons/obj/items/books/book_weapon.dmi differ diff --git a/icons/obj/items/books/book_white.dmi b/icons/obj/items/books/book_white.dmi new file mode 100644 index 000000000000..917b91df5325 Binary files /dev/null and b/icons/obj/items/books/book_white.dmi differ diff --git a/icons/obj/items/books/book_white_circle.dmi b/icons/obj/items/books/book_white_circle.dmi new file mode 100644 index 000000000000..149a786597ae Binary files /dev/null and b/icons/obj/items/books/book_white_circle.dmi differ diff --git a/icons/obj/items/books/book_white_cracked.dmi b/icons/obj/items/books/book_white_cracked.dmi new file mode 100644 index 000000000000..e24702adf690 Binary files /dev/null and b/icons/obj/items/books/book_white_cracked.dmi differ diff --git a/icons/obj/items/books/book_white_cross.dmi b/icons/obj/items/books/book_white_cross.dmi new file mode 100644 index 000000000000..b6ecccc34c90 Binary files /dev/null and b/icons/obj/items/books/book_white_cross.dmi differ diff --git a/icons/obj/items/books/book_white_detective.dmi b/icons/obj/items/books/book_white_detective.dmi new file mode 100644 index 000000000000..79ab7a12703e Binary files /dev/null and b/icons/obj/items/books/book_white_detective.dmi differ diff --git a/icons/obj/items/books/book_white_device.dmi b/icons/obj/items/books/book_white_device.dmi new file mode 100644 index 000000000000..694948202e1b Binary files /dev/null and b/icons/obj/items/books/book_white_device.dmi differ diff --git a/icons/obj/items/books/book_white_download.dmi b/icons/obj/items/books/book_white_download.dmi new file mode 100644 index 000000000000..8d55dd167e96 Binary files /dev/null and b/icons/obj/items/books/book_white_download.dmi differ diff --git a/icons/obj/items/books/book_white_exclamation.dmi b/icons/obj/items/books/book_white_exclamation.dmi new file mode 100644 index 000000000000..0a8201cb18cd Binary files /dev/null and b/icons/obj/items/books/book_white_exclamation.dmi differ diff --git a/icons/obj/items/books/book_white_flask.dmi b/icons/obj/items/books/book_white_flask.dmi new file mode 100644 index 000000000000..014ca14cfa92 Binary files /dev/null and b/icons/obj/items/books/book_white_flask.dmi differ diff --git a/icons/obj/items/books/book_white_glass.dmi b/icons/obj/items/books/book_white_glass.dmi new file mode 100644 index 000000000000..198717f23326 Binary files /dev/null and b/icons/obj/items/books/book_white_glass.dmi differ diff --git a/icons/obj/items/books/book_white_gun.dmi b/icons/obj/items/books/book_white_gun.dmi new file mode 100644 index 000000000000..9534a5fe0983 Binary files /dev/null and b/icons/obj/items/books/book_white_gun.dmi differ diff --git a/icons/obj/items/books/book_white_hourglass.dmi b/icons/obj/items/books/book_white_hourglass.dmi new file mode 100644 index 000000000000..8c0ceae69f3b Binary files /dev/null and b/icons/obj/items/books/book_white_hourglass.dmi differ diff --git a/icons/obj/items/books/book_white_percent.dmi b/icons/obj/items/books/book_white_percent.dmi new file mode 100644 index 000000000000..06aa05a43032 Binary files /dev/null and b/icons/obj/items/books/book_white_percent.dmi differ diff --git a/icons/obj/items/books/book_white_question.dmi b/icons/obj/items/books/book_white_question.dmi new file mode 100644 index 000000000000..61b877d1e348 Binary files /dev/null and b/icons/obj/items/books/book_white_question.dmi differ diff --git a/icons/obj/items/books/book_white_smile.dmi b/icons/obj/items/books/book_white_smile.dmi new file mode 100644 index 000000000000..db238465cb14 Binary files /dev/null and b/icons/obj/items/books/book_white_smile.dmi differ diff --git a/icons/obj/items/books/book_white_star.dmi b/icons/obj/items/books/book_white_star.dmi new file mode 100644 index 000000000000..a0e0308a9dd6 Binary files /dev/null and b/icons/obj/items/books/book_white_star.dmi differ diff --git a/icons/obj/items/books/book_white_text.dmi b/icons/obj/items/books/book_white_text.dmi new file mode 100644 index 000000000000..67976d0d9bdc Binary files /dev/null and b/icons/obj/items/books/book_white_text.dmi differ diff --git a/icons/obj/items/books/book_white_uparrow.dmi b/icons/obj/items/books/book_white_uparrow.dmi new file mode 100644 index 000000000000..5753657e5ce6 Binary files /dev/null and b/icons/obj/items/books/book_white_uparrow.dmi differ diff --git a/icons/obj/items/books/book_white_wrench.dmi b/icons/obj/items/books/book_white_wrench.dmi new file mode 100644 index 000000000000..218f7332d910 Binary files /dev/null and b/icons/obj/items/books/book_white_wrench.dmi differ diff --git a/icons/obj/items/brain_interface_organic.dmi b/icons/obj/items/brain_interface_organic.dmi new file mode 100644 index 000000000000..940f246aecd3 Binary files /dev/null and b/icons/obj/items/brain_interface_organic.dmi differ diff --git a/icons/obj/items/brain_interface_robotic.dmi b/icons/obj/items/brain_interface_robotic.dmi new file mode 100644 index 000000000000..065f7a2cf2ff Binary files /dev/null and b/icons/obj/items/brain_interface_robotic.dmi differ diff --git a/icons/obj/items/broom.dmi b/icons/obj/items/broom.dmi new file mode 100644 index 000000000000..daae3bab2ba4 Binary files /dev/null and b/icons/obj/items/broom.dmi differ diff --git a/icons/obj/items/bucket.dmi b/icons/obj/items/bucket.dmi index 63dc686973be..480546f19b0b 100644 Binary files a/icons/obj/items/bucket.dmi and b/icons/obj/items/bucket.dmi differ diff --git a/icons/obj/items/cable_coil.dmi b/icons/obj/items/cable_coil.dmi new file mode 100644 index 000000000000..dd8a62e1225c Binary files /dev/null and b/icons/obj/items/cable_coil.dmi differ diff --git a/icons/obj/items/candelabra.dmi b/icons/obj/items/candelabra.dmi new file mode 100644 index 000000000000..3d0b00109452 Binary files /dev/null and b/icons/obj/items/candelabra.dmi differ diff --git a/icons/obj/items/cane.dmi b/icons/obj/items/cane.dmi index 7e58645f4c77..ccc36ad5d135 100644 Binary files a/icons/obj/items/cane.dmi and b/icons/obj/items/cane.dmi differ diff --git a/icons/obj/items/chain.dmi b/icons/obj/items/chain.dmi new file mode 100644 index 000000000000..95d5c71b70f3 Binary files /dev/null and b/icons/obj/items/chain.dmi differ diff --git a/icons/obj/items/chem/beakers/advanced.dmi b/icons/obj/items/chem/beakers/advanced.dmi index 8efdf2155f19..947227137069 100644 Binary files a/icons/obj/items/chem/beakers/advanced.dmi and b/icons/obj/items/chem/beakers/advanced.dmi differ diff --git a/icons/obj/items/chem/beakers/beaker.dmi b/icons/obj/items/chem/beakers/beaker.dmi index 09eb7e121f20..0ec2003755c5 100644 Binary files a/icons/obj/items/chem/beakers/beaker.dmi and b/icons/obj/items/chem/beakers/beaker.dmi differ diff --git a/icons/obj/items/chem/beakers/insulated.dmi b/icons/obj/items/chem/beakers/insulated.dmi index 53e6b0f0f980..4b1497e924bc 100644 Binary files a/icons/obj/items/chem/beakers/insulated.dmi and b/icons/obj/items/chem/beakers/insulated.dmi differ diff --git a/icons/obj/items/chem/beakers/insulated_large.dmi b/icons/obj/items/chem/beakers/insulated_large.dmi index f6f28e36154c..8d79bbaa6bfd 100644 Binary files a/icons/obj/items/chem/beakers/insulated_large.dmi and b/icons/obj/items/chem/beakers/insulated_large.dmi differ diff --git a/icons/obj/items/chem/beakers/large.dmi b/icons/obj/items/chem/beakers/large.dmi index 82056e01b66f..3bb0f2b2f4bf 100644 Binary files a/icons/obj/items/chem/beakers/large.dmi and b/icons/obj/items/chem/beakers/large.dmi differ diff --git a/icons/obj/items/chem/beakers/stasis.dmi b/icons/obj/items/chem/beakers/stasis.dmi index 1d3e9045038a..d5411adaa678 100644 Binary files a/icons/obj/items/chem/beakers/stasis.dmi and b/icons/obj/items/chem/beakers/stasis.dmi differ diff --git a/icons/obj/items/chem/bottle.dmi b/icons/obj/items/chem/bottle.dmi index 1ddc176b665f..c092075d95e8 100644 Binary files a/icons/obj/items/chem/bottle.dmi and b/icons/obj/items/chem/bottle.dmi differ diff --git a/icons/obj/items/chem/kettle.dmi b/icons/obj/items/chem/kettle.dmi new file mode 100644 index 000000000000..6a8bd3540547 Binary files /dev/null and b/icons/obj/items/chem/kettle.dmi differ diff --git a/icons/obj/items/chem/mortar.dmi b/icons/obj/items/chem/mortar.dmi new file mode 100644 index 000000000000..63c37c2921a6 Binary files /dev/null and b/icons/obj/items/chem/mortar.dmi differ diff --git a/icons/obj/items/chem/vial.dmi b/icons/obj/items/chem/vial.dmi index 89fd1e64a220..5ea33765e9f6 100644 Binary files a/icons/obj/items/chem/vial.dmi and b/icons/obj/items/chem/vial.dmi differ diff --git a/icons/obj/items/chess.dmi b/icons/obj/items/chess.dmi new file mode 100644 index 000000000000..e38dc9251c15 Binary files /dev/null and b/icons/obj/items/chess.dmi differ diff --git a/icons/obj/items/cigarette_filter.dmi b/icons/obj/items/cigarette_filter.dmi new file mode 100644 index 000000000000..d0aa44ca3946 Binary files /dev/null and b/icons/obj/items/cigarette_filter.dmi differ diff --git a/icons/obj/items/clipboard.dmi b/icons/obj/items/clipboard.dmi new file mode 100644 index 000000000000..e846c2a47e25 Binary files /dev/null and b/icons/obj/items/clipboard.dmi differ diff --git a/icons/obj/items/comb.dmi b/icons/obj/items/comb.dmi deleted file mode 100644 index 4f29f686ac6c..000000000000 Binary files a/icons/obj/items/comb.dmi and /dev/null differ diff --git a/icons/obj/items/cosmetics/eyeshadow.dmi b/icons/obj/items/cosmetics/eyeshadow.dmi new file mode 100644 index 000000000000..ff06f346f4c3 Binary files /dev/null and b/icons/obj/items/cosmetics/eyeshadow.dmi differ diff --git a/icons/obj/items/cosmetics/lipstick.dmi b/icons/obj/items/cosmetics/lipstick.dmi new file mode 100644 index 000000000000..5715e4b1c7ca Binary files /dev/null and b/icons/obj/items/cosmetics/lipstick.dmi differ diff --git a/icons/obj/items/crafting_holder.dmi b/icons/obj/items/crafting_holder.dmi new file mode 100644 index 000000000000..51e5df832b2c Binary files /dev/null and b/icons/obj/items/crafting_holder.dmi differ diff --git a/icons/obj/items/crayon.dmi b/icons/obj/items/crayon.dmi new file mode 100644 index 000000000000..f65e4503f324 Binary files /dev/null and b/icons/obj/items/crayon.dmi differ diff --git a/icons/obj/items/crayon_box.dmi b/icons/obj/items/crayon_box.dmi new file mode 100644 index 000000000000..f8fc5497b38b Binary files /dev/null and b/icons/obj/items/crayon_box.dmi differ diff --git a/icons/obj/items/crayon_mime.dmi b/icons/obj/items/crayon_mime.dmi new file mode 100644 index 000000000000..e5f136ffca30 Binary files /dev/null and b/icons/obj/items/crayon_mime.dmi differ diff --git a/icons/obj/items/crayon_rainbow.dmi b/icons/obj/items/crayon_rainbow.dmi new file mode 100644 index 000000000000..c16ddbc52186 Binary files /dev/null and b/icons/obj/items/crayon_rainbow.dmi differ diff --git a/icons/obj/items/crayons.dmi b/icons/obj/items/crayons.dmi index 7ebabd5a81ef..1f1a9982024e 100644 Binary files a/icons/obj/items/crayons.dmi and b/icons/obj/items/crayons.dmi differ diff --git a/icons/obj/items/credstick.dmi b/icons/obj/items/credstick.dmi index d93653d5e47c..82edc07683e9 100644 Binary files a/icons/obj/items/credstick.dmi and b/icons/obj/items/credstick.dmi differ diff --git a/icons/obj/items/crutches.dmi b/icons/obj/items/crutches.dmi new file mode 100644 index 000000000000..73ae3732ee04 Binary files /dev/null and b/icons/obj/items/crutches.dmi differ diff --git a/icons/obj/items/device/ai_card.dmi b/icons/obj/items/device/ai_card.dmi index 788f0a7bd715..a036f37cbf1d 100644 Binary files a/icons/obj/items/device/ai_card.dmi and b/icons/obj/items/device/ai_card.dmi differ diff --git a/icons/obj/items/device/auto_cpr.dmi b/icons/obj/items/device/auto_cpr.dmi index f99ddfde7bb5..626402ae5e6a 100644 Binary files a/icons/obj/items/device/auto_cpr.dmi and b/icons/obj/items/device/auto_cpr.dmi differ diff --git a/icons/obj/items/device/boombox.dmi b/icons/obj/items/device/boombox.dmi index e49b198a7b00..41efdeca09a3 100644 Binary files a/icons/obj/items/device/boombox.dmi and b/icons/obj/items/device/boombox.dmi differ diff --git a/icons/obj/items/device/chameleon_proj.dmi b/icons/obj/items/device/chameleon_proj.dmi index 4dd6908991f5..8ce03b2fc4ed 100644 Binary files a/icons/obj/items/device/chameleon_proj.dmi and b/icons/obj/items/device/chameleon_proj.dmi differ diff --git a/icons/obj/items/device/chemsprayer.dmi b/icons/obj/items/device/chemsprayer.dmi index d47604f1f94b..d0c2049ada9d 100644 Binary files a/icons/obj/items/device/chemsprayer.dmi and b/icons/obj/items/device/chemsprayer.dmi differ diff --git a/icons/obj/items/device/depth_scanner.dmi b/icons/obj/items/device/depth_scanner.dmi index 92d1cd080f7d..b859bb8d1644 100644 Binary files a/icons/obj/items/device/depth_scanner.dmi and b/icons/obj/items/device/depth_scanner.dmi differ diff --git a/icons/obj/items/device/destination_tagger.dmi b/icons/obj/items/device/destination_tagger.dmi index 7cbb0324c6bc..462870e37eb7 100644 Binary files a/icons/obj/items/device/destination_tagger.dmi and b/icons/obj/items/device/destination_tagger.dmi differ diff --git a/icons/obj/items/device/diskette.dmi b/icons/obj/items/device/diskette.dmi index 95dac959624d..d0bf1a1bd60e 100644 Binary files a/icons/obj/items/device/diskette.dmi and b/icons/obj/items/device/diskette.dmi differ diff --git a/icons/obj/items/device/flash.dmi b/icons/obj/items/device/flash.dmi index ba642840e71f..0c9ed6795d04 100644 Binary files a/icons/obj/items/device/flash.dmi and b/icons/obj/items/device/flash.dmi differ diff --git a/icons/obj/items/device/flash_advanced.dmi b/icons/obj/items/device/flash_advanced.dmi new file mode 100644 index 000000000000..503abd28ca45 Binary files /dev/null and b/icons/obj/items/device/flash_advanced.dmi differ diff --git a/icons/obj/items/device/flash_synthetic.dmi b/icons/obj/items/device/flash_synthetic.dmi new file mode 100644 index 000000000000..58be7409c814 Binary files /dev/null and b/icons/obj/items/device/flash_synthetic.dmi differ diff --git a/icons/obj/items/device/floor_painter.dmi b/icons/obj/items/device/floor_painter.dmi deleted file mode 100644 index 3d85539fb75a..000000000000 Binary files a/icons/obj/items/device/floor_painter.dmi and /dev/null differ diff --git a/icons/obj/items/device/hailer.dmi b/icons/obj/items/device/hailer.dmi index adb881deea54..7f463fb46c77 100644 Binary files a/icons/obj/items/device/hailer.dmi and b/icons/obj/items/device/hailer.dmi differ diff --git a/icons/obj/items/device/locator.dmi b/icons/obj/items/device/locator.dmi index 7117a1e97448..3766cf55b765 100644 Binary files a/icons/obj/items/device/locator.dmi and b/icons/obj/items/device/locator.dmi differ diff --git a/icons/obj/items/device/locator_borg.dmi b/icons/obj/items/device/locator_borg.dmi new file mode 100644 index 000000000000..18e701e627bb Binary files /dev/null and b/icons/obj/items/device/locator_borg.dmi differ diff --git a/icons/obj/items/device/locator_overlays.dmi b/icons/obj/items/device/locator_overlays.dmi new file mode 100644 index 000000000000..e4ad51d41b4a Binary files /dev/null and b/icons/obj/items/device/locator_overlays.dmi differ diff --git a/icons/obj/items/device/pai.dmi b/icons/obj/items/device/pai.dmi index 6e3c06675276..34b4ef524c70 100644 Binary files a/icons/obj/items/device/pai.dmi and b/icons/obj/items/device/pai.dmi differ diff --git a/icons/obj/items/device/paint_sprayer.dmi b/icons/obj/items/device/paint_sprayer.dmi new file mode 100644 index 000000000000..ee32c9f74abe Binary files /dev/null and b/icons/obj/items/device/paint_sprayer.dmi differ diff --git a/icons/obj/items/device/parts_replacer.dmi b/icons/obj/items/device/parts_replacer.dmi index c3cb8d13a654..43672a4ca23e 100644 Binary files a/icons/obj/items/device/parts_replacer.dmi and b/icons/obj/items/device/parts_replacer.dmi differ diff --git a/icons/obj/items/device/parts_replacer_advanced.dmi b/icons/obj/items/device/parts_replacer_advanced.dmi new file mode 100644 index 000000000000..a09ec9706fee Binary files /dev/null and b/icons/obj/items/device/parts_replacer_advanced.dmi differ diff --git a/icons/obj/items/device/pinpointer.dmi b/icons/obj/items/device/pinpointer.dmi index 9e418b4920cf..8c9479896310 100644 Binary files a/icons/obj/items/device/pinpointer.dmi and b/icons/obj/items/device/pinpointer.dmi differ diff --git a/icons/obj/items/device/pipe_painter.dmi b/icons/obj/items/device/pipe_painter.dmi deleted file mode 100644 index 1ebcd841aeb0..000000000000 Binary files a/icons/obj/items/device/pipe_painter.dmi and /dev/null differ diff --git a/icons/obj/items/device/powersink.dmi b/icons/obj/items/device/powersink.dmi index b08b228e6999..b723d9565c38 100644 Binary files a/icons/obj/items/device/powersink.dmi and b/icons/obj/items/device/powersink.dmi differ diff --git a/icons/obj/items/device/radio/electropack.dmi b/icons/obj/items/device/radio/electropack.dmi index 34bf86dc97ca..f4a93e986740 100644 Binary files a/icons/obj/items/device/radio/electropack.dmi and b/icons/obj/items/device/radio/electropack.dmi differ diff --git a/icons/obj/items/device/radio/headset.dmi b/icons/obj/items/device/radio/headset.dmi deleted file mode 100644 index 527835a9bf85..000000000000 Binary files a/icons/obj/items/device/radio/headset.dmi and /dev/null differ diff --git a/icons/obj/items/device/radio/headsets/headset.dmi b/icons/obj/items/device/radio/headsets/headset.dmi new file mode 100644 index 000000000000..3949b1ce4fa1 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_admin.dmi b/icons/obj/items/device/radio/headsets/headset_admin.dmi new file mode 100644 index 000000000000..8413cce5fea2 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_admin.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_cargo.dmi b/icons/obj/items/device/radio/headsets/headset_cargo.dmi new file mode 100644 index 000000000000..4ba18f6858ca Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_cargo.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_cargo_alt.dmi b/icons/obj/items/device/radio/headsets/headset_cargo_alt.dmi new file mode 100644 index 000000000000..710ee66ab531 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_cargo_alt.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_command.dmi b/icons/obj/items/device/radio/headsets/headset_command.dmi new file mode 100644 index 000000000000..d3576d54c333 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_command.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_command_alt.dmi b/icons/obj/items/device/radio/headsets/headset_command_alt.dmi new file mode 100644 index 000000000000..a32769f493f7 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_command_alt.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_engineering.dmi b/icons/obj/items/device/radio/headsets/headset_engineering.dmi new file mode 100644 index 000000000000..31150a50c2e1 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_engineering.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_engineering_alt.dmi b/icons/obj/items/device/radio/headsets/headset_engineering_alt.dmi new file mode 100644 index 000000000000..ad7acb7b8a69 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_engineering_alt.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_medical.dmi b/icons/obj/items/device/radio/headsets/headset_medical.dmi new file mode 100644 index 000000000000..8f919dd5370e Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_medical.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_medical_alt.dmi b/icons/obj/items/device/radio/headsets/headset_medical_alt.dmi new file mode 100644 index 000000000000..2fb1b6de967a Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_medical_alt.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_mining.dmi b/icons/obj/items/device/radio/headsets/headset_mining.dmi new file mode 100644 index 000000000000..41805b8ad699 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_mining.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_mining_alt.dmi b/icons/obj/items/device/radio/headsets/headset_mining_alt.dmi new file mode 100644 index 000000000000..225d1b2e9987 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_mining_alt.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_science.dmi b/icons/obj/items/device/radio/headsets/headset_science.dmi new file mode 100644 index 000000000000..735aca00a620 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_science.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_security.dmi b/icons/obj/items/device/radio/headsets/headset_security.dmi new file mode 100644 index 000000000000..7ca02f170877 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_security.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_security_alt.dmi b/icons/obj/items/device/radio/headsets/headset_security_alt.dmi new file mode 100644 index 000000000000..db69d31e582d Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_security_alt.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_service.dmi b/icons/obj/items/device/radio/headsets/headset_service.dmi new file mode 100644 index 000000000000..1dbe7d4a0ba1 Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_service.dmi differ diff --git a/icons/obj/items/device/radio/headsets/headset_syndicate.dmi b/icons/obj/items/device/radio/headsets/headset_syndicate.dmi new file mode 100644 index 000000000000..4c9cfeee560c Binary files /dev/null and b/icons/obj/items/device/radio/headsets/headset_syndicate.dmi differ diff --git a/icons/obj/items/device/radio/key.dmi b/icons/obj/items/device/radio/key.dmi index 458a63760671..565d78b8e0f4 100644 Binary files a/icons/obj/items/device/radio/key.dmi and b/icons/obj/items/device/radio/key.dmi differ diff --git a/icons/obj/items/device/radio/spybug.dmi b/icons/obj/items/device/radio/spybug.dmi new file mode 100644 index 000000000000..549907f2a59c Binary files /dev/null and b/icons/obj/items/device/radio/spybug.dmi differ diff --git a/icons/obj/items/device/robot_analyzer.dmi b/icons/obj/items/device/robot_analyzer.dmi index f194a04505f4..b424ea8e0129 100644 Binary files a/icons/obj/items/device/robot_analyzer.dmi and b/icons/obj/items/device/robot_analyzer.dmi differ diff --git a/icons/obj/items/device/scanner/advanced_spectrometer.dmi b/icons/obj/items/device/scanner/advanced_spectrometer.dmi new file mode 100644 index 000000000000..4028fa278107 Binary files /dev/null and b/icons/obj/items/device/scanner/advanced_spectrometer.dmi differ diff --git a/icons/obj/items/device/scanner/atmos_scanner.dmi b/icons/obj/items/device/scanner/atmos_scanner.dmi index cd5eb16d359d..7d0e56c54bca 100644 Binary files a/icons/obj/items/device/scanner/atmos_scanner.dmi and b/icons/obj/items/device/scanner/atmos_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/breath_scanner.dmi b/icons/obj/items/device/scanner/breath_scanner.dmi new file mode 100644 index 000000000000..bb4b2df70dc8 Binary files /dev/null and b/icons/obj/items/device/scanner/breath_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/health_scanner.dmi b/icons/obj/items/device/scanner/health_scanner.dmi index a1038003dfce..3005c19577d1 100644 Binary files a/icons/obj/items/device/scanner/health_scanner.dmi and b/icons/obj/items/device/scanner/health_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/network_scanner.dmi b/icons/obj/items/device/scanner/network_scanner.dmi new file mode 100644 index 000000000000..cfc537ef5858 Binary files /dev/null and b/icons/obj/items/device/scanner/network_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/ore_scanner.dmi b/icons/obj/items/device/scanner/ore_scanner.dmi index 85aec06a9071..04095564900a 100644 Binary files a/icons/obj/items/device/scanner/ore_scanner.dmi and b/icons/obj/items/device/scanner/ore_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/plant_scanner.dmi b/icons/obj/items/device/scanner/plant_scanner.dmi index 90f5e5985212..88f1577fa36a 100644 Binary files a/icons/obj/items/device/scanner/plant_scanner.dmi and b/icons/obj/items/device/scanner/plant_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/price_scanner.dmi b/icons/obj/items/device/scanner/price_scanner.dmi index bacb78623052..cfd7c670fe58 100644 Binary files a/icons/obj/items/device/scanner/price_scanner.dmi and b/icons/obj/items/device/scanner/price_scanner.dmi differ diff --git a/icons/obj/items/device/scanner/spectrometer.dmi b/icons/obj/items/device/scanner/spectrometer.dmi index f453dcd4d226..4923cc18a5fb 100644 Binary files a/icons/obj/items/device/scanner/spectrometer.dmi and b/icons/obj/items/device/scanner/spectrometer.dmi differ diff --git a/icons/obj/items/device/scanner/xenobio_scanner.dmi b/icons/obj/items/device/scanner/xenobio_scanner.dmi index 28fdf5cbf858..dab11129286f 100644 Binary files a/icons/obj/items/device/scanner/xenobio_scanner.dmi and b/icons/obj/items/device/scanner/xenobio_scanner.dmi differ diff --git a/icons/obj/items/device/t_ray_scanner.dmi b/icons/obj/items/device/t_ray_scanner.dmi index c2ccb77b18e9..3d5521b1d0d6 100644 Binary files a/icons/obj/items/device/t_ray_scanner.dmi and b/icons/obj/items/device/t_ray_scanner.dmi differ diff --git a/icons/obj/items/device/tape_casette.dmi b/icons/obj/items/device/tape_casette.dmi deleted file mode 100644 index e42c3a2bf8a2..000000000000 Binary files a/icons/obj/items/device/tape_casette.dmi and /dev/null differ diff --git a/icons/obj/items/device/tape_recorder.dmi b/icons/obj/items/device/tape_recorder.dmi deleted file mode 100644 index 0e00542aeefc..000000000000 Binary files a/icons/obj/items/device/tape_recorder.dmi and /dev/null differ diff --git a/icons/obj/items/device/tape_recorder/tape_casette_blue.dmi b/icons/obj/items/device/tape_recorder/tape_casette_blue.dmi new file mode 100644 index 000000000000..62a069555669 Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_casette_blue.dmi differ diff --git a/icons/obj/items/device/tape_recorder/tape_casette_loose.dmi b/icons/obj/items/device/tape_recorder/tape_casette_loose.dmi new file mode 100644 index 000000000000..0c8b4b502585 Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_casette_loose.dmi differ diff --git a/icons/obj/items/device/tape_recorder/tape_casette_purple.dmi b/icons/obj/items/device/tape_recorder/tape_casette_purple.dmi new file mode 100644 index 000000000000..8db366b35ed4 Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_casette_purple.dmi differ diff --git a/icons/obj/items/device/tape_recorder/tape_casette_red.dmi b/icons/obj/items/device/tape_recorder/tape_casette_red.dmi new file mode 100644 index 000000000000..20a14a5706fe Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_casette_red.dmi differ diff --git a/icons/obj/items/device/tape_recorder/tape_casette_white.dmi b/icons/obj/items/device/tape_recorder/tape_casette_white.dmi new file mode 100644 index 000000000000..9efb2b0e1e49 Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_casette_white.dmi differ diff --git a/icons/obj/items/device/tape_recorder/tape_casette_yellow.dmi b/icons/obj/items/device/tape_recorder/tape_casette_yellow.dmi new file mode 100644 index 000000000000..2c1419a26da1 Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_casette_yellow.dmi differ diff --git a/icons/obj/items/device/tape_recorder/tape_recorder.dmi b/icons/obj/items/device/tape_recorder/tape_recorder.dmi new file mode 100644 index 000000000000..90efe6e8b591 Binary files /dev/null and b/icons/obj/items/device/tape_recorder/tape_recorder.dmi differ diff --git a/icons/obj/items/device/ultraviolet.dmi b/icons/obj/items/device/ultraviolet.dmi index cbd9981e4f27..c207cc748ccf 100644 Binary files a/icons/obj/items/device/ultraviolet.dmi and b/icons/obj/items/device/ultraviolet.dmi differ diff --git a/icons/obj/items/doormat.dmi b/icons/obj/items/doormat.dmi new file mode 100644 index 000000000000..8be97b78f2c6 Binary files /dev/null and b/icons/obj/items/doormat.dmi differ diff --git a/icons/obj/items/ecig.dmi b/icons/obj/items/ecig.dmi index 7329ca25f93b..3cce3c54f3f3 100644 Binary files a/icons/obj/items/ecig.dmi and b/icons/obj/items/ecig.dmi differ diff --git a/icons/obj/items/ectoplasm.dmi b/icons/obj/items/ectoplasm.dmi new file mode 100644 index 000000000000..0982cc3265a4 Binary files /dev/null and b/icons/obj/items/ectoplasm.dmi differ diff --git a/icons/obj/items/flame/candle.dmi b/icons/obj/items/flame/candle.dmi new file mode 100644 index 000000000000..ef2c6a8987f0 Binary files /dev/null and b/icons/obj/items/flame/candle.dmi differ diff --git a/icons/obj/items/flame/incense.dmi b/icons/obj/items/flame/incense.dmi new file mode 100644 index 000000000000..e4d93633fb28 Binary files /dev/null and b/icons/obj/items/flame/incense.dmi differ diff --git a/icons/obj/items/flame/lantern.dmi b/icons/obj/items/flame/lantern.dmi new file mode 100644 index 000000000000..ba1e586e1714 Binary files /dev/null and b/icons/obj/items/flame/lantern.dmi differ diff --git a/icons/obj/items/flame/lighter.dmi b/icons/obj/items/flame/lighter.dmi new file mode 100644 index 000000000000..68e5edbac812 Binary files /dev/null and b/icons/obj/items/flame/lighter.dmi differ diff --git a/icons/obj/items/flame/match.dmi b/icons/obj/items/flame/match.dmi new file mode 100644 index 000000000000..f5a242200c17 Binary files /dev/null and b/icons/obj/items/flame/match.dmi differ diff --git a/icons/obj/items/flame/torch.dmi b/icons/obj/items/flame/torch.dmi new file mode 100644 index 000000000000..83d5af5a80f3 Binary files /dev/null and b/icons/obj/items/flame/torch.dmi differ diff --git a/icons/obj/items/flame/zippo.dmi b/icons/obj/items/flame/zippo.dmi new file mode 100644 index 000000000000..eafb1ac0a7a4 Binary files /dev/null and b/icons/obj/items/flame/zippo.dmi differ diff --git a/icons/obj/items/fleece.dmi b/icons/obj/items/fleece.dmi new file mode 100644 index 000000000000..12b1f2de8a32 Binary files /dev/null and b/icons/obj/items/fleece.dmi differ diff --git a/icons/obj/items/folders.dmi b/icons/obj/items/folders.dmi new file mode 100644 index 000000000000..714ad833de34 Binary files /dev/null and b/icons/obj/items/folders.dmi differ diff --git a/icons/obj/items/fortune_teller.dmi b/icons/obj/items/fortune_teller.dmi new file mode 100644 index 000000000000..805b9448e2e2 Binary files /dev/null and b/icons/obj/items/fortune_teller.dmi differ diff --git a/icons/obj/items/gemstones/baguette.dmi b/icons/obj/items/gemstones/baguette.dmi new file mode 100644 index 000000000000..a10c3dc67545 Binary files /dev/null and b/icons/obj/items/gemstones/baguette.dmi differ diff --git a/icons/obj/items/gemstones/hexagon.dmi b/icons/obj/items/gemstones/hexagon.dmi new file mode 100644 index 000000000000..a66d147db142 Binary files /dev/null and b/icons/obj/items/gemstones/hexagon.dmi differ diff --git a/icons/obj/items/gemstones/octagon.dmi b/icons/obj/items/gemstones/octagon.dmi new file mode 100644 index 000000000000..c216faaadf9f Binary files /dev/null and b/icons/obj/items/gemstones/octagon.dmi differ diff --git a/icons/obj/items/gemstones/poor.dmi b/icons/obj/items/gemstones/poor.dmi new file mode 100644 index 000000000000..97d192b3493e Binary files /dev/null and b/icons/obj/items/gemstones/poor.dmi differ diff --git a/icons/obj/items/gemstones/round.dmi b/icons/obj/items/gemstones/round.dmi new file mode 100644 index 000000000000..69bca88b994b Binary files /dev/null and b/icons/obj/items/gemstones/round.dmi differ diff --git a/icons/obj/items/gemstones/uncut.dmi b/icons/obj/items/gemstones/uncut.dmi new file mode 100644 index 000000000000..46b30ab23434 Binary files /dev/null and b/icons/obj/items/gemstones/uncut.dmi differ diff --git a/icons/obj/items/gift_wrapped.dmi b/icons/obj/items/gift_wrapped.dmi index ba37d4d4e69d..5677974c95f4 100644 Binary files a/icons/obj/items/gift_wrapped.dmi and b/icons/obj/items/gift_wrapped.dmi differ diff --git a/icons/obj/items/grenades/banana.dmi b/icons/obj/items/grenades/banana.dmi new file mode 100644 index 000000000000..1c19b2e81be7 Binary files /dev/null and b/icons/obj/items/grenades/banana.dmi differ diff --git a/icons/obj/items/grenades/clusterbang.dmi b/icons/obj/items/grenades/clusterbang.dmi new file mode 100644 index 000000000000..2ea0b9c7f422 Binary files /dev/null and b/icons/obj/items/grenades/clusterbang.dmi differ diff --git a/icons/obj/items/grenades/clusterbang_segment.dmi b/icons/obj/items/grenades/clusterbang_segment.dmi new file mode 100644 index 000000000000..dc1d1b36c870 Binary files /dev/null and b/icons/obj/items/grenades/clusterbang_segment.dmi differ diff --git a/icons/obj/items/grenades/concussion.dmi b/icons/obj/items/grenades/concussion.dmi new file mode 100644 index 000000000000..2a72701e0922 Binary files /dev/null and b/icons/obj/items/grenades/concussion.dmi differ diff --git a/icons/obj/items/grenades/delivery.dmi b/icons/obj/items/grenades/delivery.dmi new file mode 100644 index 000000000000..69645514829c Binary files /dev/null and b/icons/obj/items/grenades/delivery.dmi differ diff --git a/icons/obj/items/grenades/emp.dmi b/icons/obj/items/grenades/emp.dmi new file mode 100644 index 000000000000..cc7bc5a96161 Binary files /dev/null and b/icons/obj/items/grenades/emp.dmi differ diff --git a/icons/obj/items/grenades/emp_old.dmi b/icons/obj/items/grenades/emp_old.dmi new file mode 100644 index 000000000000..97f03da5c6ff Binary files /dev/null and b/icons/obj/items/grenades/emp_old.dmi differ diff --git a/icons/obj/items/grenades/flashbang.dmi b/icons/obj/items/grenades/flashbang.dmi new file mode 100644 index 000000000000..db1957234b40 Binary files /dev/null and b/icons/obj/items/grenades/flashbang.dmi differ diff --git a/icons/obj/items/grenades/frag.dmi b/icons/obj/items/grenades/frag.dmi new file mode 100644 index 000000000000..bab0c2594724 Binary files /dev/null and b/icons/obj/items/grenades/frag.dmi differ diff --git a/icons/obj/items/grenades/frag_old.dmi b/icons/obj/items/grenades/frag_old.dmi new file mode 100644 index 000000000000..bfa6edf9b71b Binary files /dev/null and b/icons/obj/items/grenades/frag_old.dmi differ diff --git a/icons/obj/items/grenades/frag_shell.dmi b/icons/obj/items/grenades/frag_shell.dmi new file mode 100644 index 000000000000..76e5d6d3ac98 Binary files /dev/null and b/icons/obj/items/grenades/frag_shell.dmi differ diff --git a/icons/obj/items/grenades/grenade.dmi b/icons/obj/items/grenades/grenade.dmi new file mode 100644 index 000000000000..11a48997b03d Binary files /dev/null and b/icons/obj/items/grenades/grenade.dmi differ diff --git a/icons/obj/items/grenades/grenade_chem.dmi b/icons/obj/items/grenades/grenade_chem.dmi new file mode 100644 index 000000000000..71a922069edb Binary files /dev/null and b/icons/obj/items/grenades/grenade_chem.dmi differ diff --git a/icons/obj/items/grenades/grenade_large.dmi b/icons/obj/items/grenades/grenade_large.dmi new file mode 100644 index 000000000000..b7afcdbbf340 Binary files /dev/null and b/icons/obj/items/grenades/grenade_large.dmi differ diff --git a/icons/obj/items/grenades/grenade_light.dmi b/icons/obj/items/grenades/grenade_light.dmi new file mode 100644 index 000000000000..30d2eeeb219e Binary files /dev/null and b/icons/obj/items/grenades/grenade_light.dmi differ diff --git a/icons/obj/items/grenades/grenade_water.dmi b/icons/obj/items/grenades/grenade_water.dmi new file mode 100644 index 000000000000..81920da0c2f8 Binary files /dev/null and b/icons/obj/items/grenades/grenade_water.dmi differ diff --git a/icons/obj/items/grenades/missile.dmi b/icons/obj/items/grenades/missile.dmi new file mode 100644 index 000000000000..435892fa2a7c Binary files /dev/null and b/icons/obj/items/grenades/missile.dmi differ diff --git a/icons/obj/items/grooming/comb.dmi b/icons/obj/items/grooming/comb.dmi new file mode 100644 index 000000000000..1f66552ea097 Binary files /dev/null and b/icons/obj/items/grooming/comb.dmi differ diff --git a/icons/obj/items/grooming/comb_butterfly.dmi b/icons/obj/items/grooming/comb_butterfly.dmi new file mode 100644 index 000000000000..e560aedfd1e9 Binary files /dev/null and b/icons/obj/items/grooming/comb_butterfly.dmi differ diff --git a/icons/obj/items/grooming/file.dmi b/icons/obj/items/grooming/file.dmi new file mode 100644 index 000000000000..6801ce79c71e Binary files /dev/null and b/icons/obj/items/grooming/file.dmi differ diff --git a/icons/obj/items/grooming/hairbrush.dmi b/icons/obj/items/grooming/hairbrush.dmi new file mode 100644 index 000000000000..3df1e5ccd0b9 Binary files /dev/null and b/icons/obj/items/grooming/hairbrush.dmi differ diff --git a/icons/obj/items/guitar.dmi b/icons/obj/items/guitar.dmi index ec0d3ea5dde8..a85784794836 100644 Binary files a/icons/obj/items/guitar.dmi and b/icons/obj/items/guitar.dmi differ diff --git a/icons/obj/items/hairbrush.dmi b/icons/obj/items/hairbrush.dmi deleted file mode 100644 index a11a1705d499..000000000000 Binary files a/icons/obj/items/hairbrush.dmi and /dev/null differ diff --git a/icons/obj/items/hand_labeler.dmi b/icons/obj/items/hand_labeler.dmi new file mode 100644 index 000000000000..f84837cf4a15 Binary files /dev/null and b/icons/obj/items/hand_labeler.dmi differ diff --git a/icons/obj/items/handcuffs.dmi b/icons/obj/items/handcuffs.dmi index e96945d73c71..2f4902845388 100644 Binary files a/icons/obj/items/handcuffs.dmi and b/icons/obj/items/handcuffs.dmi differ diff --git a/icons/obj/items/handcuffs_cable.dmi b/icons/obj/items/handcuffs_cable.dmi new file mode 100644 index 000000000000..8dde113e8a9b Binary files /dev/null and b/icons/obj/items/handcuffs_cable.dmi differ diff --git a/icons/obj/items/handmade/bottle.dmi b/icons/obj/items/handmade/bottle.dmi new file mode 100644 index 000000000000..95e52c583d66 Binary files /dev/null and b/icons/obj/items/handmade/bottle.dmi differ diff --git a/icons/obj/items/handmade/bottle_tall.dmi b/icons/obj/items/handmade/bottle_tall.dmi new file mode 100644 index 000000000000..9cb2072aaaf9 Binary files /dev/null and b/icons/obj/items/handmade/bottle_tall.dmi differ diff --git a/icons/obj/items/handmade/bottle_wide.dmi b/icons/obj/items/handmade/bottle_wide.dmi new file mode 100644 index 000000000000..392b02def1a7 Binary files /dev/null and b/icons/obj/items/handmade/bottle_wide.dmi differ diff --git a/icons/obj/items/handmade/bowl.dmi b/icons/obj/items/handmade/bowl.dmi new file mode 100644 index 000000000000..29cb47bf9bea Binary files /dev/null and b/icons/obj/items/handmade/bowl.dmi differ diff --git a/icons/obj/items/handmade/bowl_fancy.dmi b/icons/obj/items/handmade/bowl_fancy.dmi new file mode 100644 index 000000000000..af43c58133af Binary files /dev/null and b/icons/obj/items/handmade/bowl_fancy.dmi differ diff --git a/icons/obj/items/handmade/cup.dmi b/icons/obj/items/handmade/cup.dmi new file mode 100644 index 000000000000..8e894e7d6124 Binary files /dev/null and b/icons/obj/items/handmade/cup.dmi differ diff --git a/icons/obj/items/handmade/cup_fancy.dmi b/icons/obj/items/handmade/cup_fancy.dmi new file mode 100644 index 000000000000..02f64ffe84fa Binary files /dev/null and b/icons/obj/items/handmade/cup_fancy.dmi differ diff --git a/icons/obj/items/handmade/decanter.dmi b/icons/obj/items/handmade/decanter.dmi new file mode 100644 index 000000000000..aad1cd74fe34 Binary files /dev/null and b/icons/obj/items/handmade/decanter.dmi differ diff --git a/icons/obj/items/handmade/jar.dmi b/icons/obj/items/handmade/jar.dmi new file mode 100644 index 000000000000..5abba0c3c3d2 Binary files /dev/null and b/icons/obj/items/handmade/jar.dmi differ diff --git a/icons/obj/items/handmade/mug.dmi b/icons/obj/items/handmade/mug.dmi new file mode 100644 index 000000000000..5130e4cd185b Binary files /dev/null and b/icons/obj/items/handmade/mug.dmi differ diff --git a/icons/obj/items/handmade/teapot.dmi b/icons/obj/items/handmade/teapot.dmi new file mode 100644 index 000000000000..361e258b8f01 Binary files /dev/null and b/icons/obj/items/handmade/teapot.dmi differ diff --git a/icons/obj/items/handmade/vase.dmi b/icons/obj/items/handmade/vase.dmi new file mode 100644 index 000000000000..cf0c35ce9770 Binary files /dev/null and b/icons/obj/items/handmade/vase.dmi differ diff --git a/icons/obj/items/handmade/vase_fancy.dmi b/icons/obj/items/handmade/vase_fancy.dmi new file mode 100644 index 000000000000..8a66723be837 Binary files /dev/null and b/icons/obj/items/handmade/vase_fancy.dmi differ diff --git a/icons/obj/items/handmade/vase_fancy_fluted.dmi b/icons/obj/items/handmade/vase_fancy_fluted.dmi new file mode 100644 index 000000000000..af3a2270a766 Binary files /dev/null and b/icons/obj/items/handmade/vase_fancy_fluted.dmi differ diff --git a/icons/obj/items/holder.dmi b/icons/obj/items/holder.dmi new file mode 100644 index 000000000000..5b917f50800c Binary files /dev/null and b/icons/obj/items/holder.dmi differ diff --git a/icons/obj/items/holosign_projector.dmi b/icons/obj/items/holosign_projector.dmi new file mode 100644 index 000000000000..89c9d3adc723 Binary files /dev/null and b/icons/obj/items/holosign_projector.dmi differ diff --git a/icons/obj/items/hook.dmi b/icons/obj/items/hook.dmi new file mode 100644 index 000000000000..602683208c76 Binary files /dev/null and b/icons/obj/items/hook.dmi differ diff --git a/icons/obj/items/horn.dmi b/icons/obj/items/horn.dmi index 06ecc94f199d..f521160d4dd3 100644 Binary files a/icons/obj/items/horn.dmi and b/icons/obj/items/horn.dmi differ diff --git a/icons/obj/items/horseshoe.dmi b/icons/obj/items/horseshoe.dmi new file mode 100644 index 000000000000..15f6f5f2482a Binary files /dev/null and b/icons/obj/items/horseshoe.dmi differ diff --git a/icons/obj/items/hourglass.dmi b/icons/obj/items/hourglass.dmi new file mode 100644 index 000000000000..a3930025333a Binary files /dev/null and b/icons/obj/items/hourglass.dmi differ diff --git a/icons/obj/items/implant/implantpad.dmi b/icons/obj/items/implant/implantpad.dmi index a03f22c13db9..cbc6ad2c7f8a 100644 Binary files a/icons/obj/items/implant/implantpad.dmi and b/icons/obj/items/implant/implantpad.dmi differ diff --git a/icons/obj/items/inkwell.dmi b/icons/obj/items/inkwell.dmi new file mode 100644 index 000000000000..1ca6665039a5 Binary files /dev/null and b/icons/obj/items/inkwell.dmi differ diff --git a/icons/obj/items/key.dmi b/icons/obj/items/key.dmi index 907444a02f7f..4410149a1456 100644 Binary files a/icons/obj/items/key.dmi and b/icons/obj/items/key.dmi differ diff --git a/icons/obj/items/keyring.dmi b/icons/obj/items/keyring.dmi new file mode 100644 index 000000000000..10fe79bdd1ab Binary files /dev/null and b/icons/obj/items/keyring.dmi differ diff --git a/icons/obj/items/light_replacer.dmi b/icons/obj/items/light_replacer.dmi new file mode 100644 index 000000000000..bad8abc5deb1 Binary files /dev/null and b/icons/obj/items/light_replacer.dmi differ diff --git a/icons/obj/items/lighters.dmi b/icons/obj/items/lighters.dmi deleted file mode 100644 index 7559a03d832b..000000000000 Binary files a/icons/obj/items/lighters.dmi and /dev/null differ diff --git a/icons/obj/items/lipstick.dmi b/icons/obj/items/lipstick.dmi deleted file mode 100644 index 6d5c07d6d1a0..000000000000 Binary files a/icons/obj/items/lipstick.dmi and /dev/null differ diff --git a/icons/obj/items/lockpick.dmi b/icons/obj/items/lockpick.dmi new file mode 100644 index 000000000000..3d221beda276 Binary files /dev/null and b/icons/obj/items/lockpick.dmi differ diff --git a/icons/obj/items/lockpick_roll.dmi b/icons/obj/items/lockpick_roll.dmi new file mode 100644 index 000000000000..c5e1997954f7 Binary files /dev/null and b/icons/obj/items/lockpick_roll.dmi differ diff --git a/icons/obj/items/mining_satchel.dmi b/icons/obj/items/mining_satchel.dmi new file mode 100644 index 000000000000..64d0ded92578 Binary files /dev/null and b/icons/obj/items/mining_satchel.dmi differ diff --git a/icons/obj/items/mould.dmi b/icons/obj/items/mould.dmi new file mode 100644 index 000000000000..f9d3c6c8414a Binary files /dev/null and b/icons/obj/items/mould.dmi differ diff --git a/icons/obj/items/net_cable_coil.dmi b/icons/obj/items/net_cable_coil.dmi new file mode 100644 index 000000000000..5ff8d97cc87f Binary files /dev/null and b/icons/obj/items/net_cable_coil.dmi differ diff --git a/icons/obj/items/paint_bucket.dmi b/icons/obj/items/paint_bucket.dmi index b40bc590c849..fb01a26e693b 100644 Binary files a/icons/obj/items/paint_bucket.dmi and b/icons/obj/items/paint_bucket.dmi differ diff --git a/icons/obj/items/paper_bin.dmi b/icons/obj/items/paper_bin.dmi new file mode 100644 index 000000000000..bfccce2c4c14 Binary files /dev/null and b/icons/obj/items/paper_bin.dmi differ diff --git a/icons/obj/items/paperwork/carbon_paper.dmi b/icons/obj/items/paperwork/carbon_paper.dmi new file mode 100644 index 000000000000..83ec86efb425 Binary files /dev/null and b/icons/obj/items/paperwork/carbon_paper.dmi differ diff --git a/icons/obj/items/paperwork/cigarette_paper.dmi b/icons/obj/items/paperwork/cigarette_paper.dmi new file mode 100644 index 000000000000..5940be202cf1 Binary files /dev/null and b/icons/obj/items/paperwork/cigarette_paper.dmi differ diff --git a/icons/obj/items/paperwork/cigarette_paper_fancy.dmi b/icons/obj/items/paperwork/cigarette_paper_fancy.dmi new file mode 100644 index 000000000000..8a4583ef892c Binary files /dev/null and b/icons/obj/items/paperwork/cigarette_paper_fancy.dmi differ diff --git a/icons/obj/items/paperwork/paper.dmi b/icons/obj/items/paperwork/paper.dmi new file mode 100644 index 000000000000..7b6760eb4d27 Binary files /dev/null and b/icons/obj/items/paperwork/paper.dmi differ diff --git a/icons/obj/items/paperwork/paper_plane.dmi b/icons/obj/items/paperwork/paper_plane.dmi new file mode 100644 index 000000000000..c9448cd115fe Binary files /dev/null and b/icons/obj/items/paperwork/paper_plane.dmi differ diff --git a/icons/obj/items/paperwork/scroll.dmi b/icons/obj/items/paperwork/scroll.dmi new file mode 100644 index 000000000000..1e828970ae2b Binary files /dev/null and b/icons/obj/items/paperwork/scroll.dmi differ diff --git a/icons/obj/items/paperwork/sticky_note.dmi b/icons/obj/items/paperwork/sticky_note.dmi new file mode 100644 index 000000000000..56a0a2cac3d7 Binary files /dev/null and b/icons/obj/items/paperwork/sticky_note.dmi differ diff --git a/icons/obj/items/paperwork/toilet_paper.dmi b/icons/obj/items/paperwork/toilet_paper.dmi new file mode 100644 index 000000000000..ae1905cb67b8 Binary files /dev/null and b/icons/obj/items/paperwork/toilet_paper.dmi differ diff --git a/icons/obj/items/passport.dmi b/icons/obj/items/passport.dmi new file mode 100644 index 000000000000..f3c148523041 Binary files /dev/null and b/icons/obj/items/passport.dmi differ diff --git a/icons/obj/items/pens/pen.dmi b/icons/obj/items/pens/pen.dmi new file mode 100644 index 000000000000..9a0dc929502b Binary files /dev/null and b/icons/obj/items/pens/pen.dmi differ diff --git a/icons/obj/items/pens/pen_blue.dmi b/icons/obj/items/pens/pen_blue.dmi new file mode 100644 index 000000000000..637d1e6fe4e3 Binary files /dev/null and b/icons/obj/items/pens/pen_blue.dmi differ diff --git a/icons/obj/items/pens/pen_dire_quill.dmi b/icons/obj/items/pens/pen_dire_quill.dmi new file mode 100644 index 000000000000..a965cb9685a5 Binary files /dev/null and b/icons/obj/items/pens/pen_dire_quill.dmi differ diff --git a/icons/obj/items/pens/pen_fancy.dmi b/icons/obj/items/pens/pen_fancy.dmi new file mode 100644 index 000000000000..ff9a2e972f28 Binary files /dev/null and b/icons/obj/items/pens/pen_fancy.dmi differ diff --git a/icons/obj/items/pens/pen_green.dmi b/icons/obj/items/pens/pen_green.dmi new file mode 100644 index 000000000000..6f03369cfb05 Binary files /dev/null and b/icons/obj/items/pens/pen_green.dmi differ diff --git a/icons/obj/items/pens/pen_quill.dmi b/icons/obj/items/pens/pen_quill.dmi new file mode 100644 index 000000000000..1f5f0c532657 Binary files /dev/null and b/icons/obj/items/pens/pen_quill.dmi differ diff --git a/icons/obj/items/pens/pen_red.dmi b/icons/obj/items/pens/pen_red.dmi new file mode 100644 index 000000000000..9d5d75aea163 Binary files /dev/null and b/icons/obj/items/pens/pen_red.dmi differ diff --git a/icons/obj/items/pens/pen_retractable.dmi b/icons/obj/items/pens/pen_retractable.dmi new file mode 100644 index 000000000000..cf8debe9e787 Binary files /dev/null and b/icons/obj/items/pens/pen_retractable.dmi differ diff --git a/icons/obj/items/pens/pen_retractable_blue.dmi b/icons/obj/items/pens/pen_retractable_blue.dmi new file mode 100644 index 000000000000..47156e2377be Binary files /dev/null and b/icons/obj/items/pens/pen_retractable_blue.dmi differ diff --git a/icons/obj/items/pens/pen_retractable_green.dmi b/icons/obj/items/pens/pen_retractable_green.dmi new file mode 100644 index 000000000000..8e40bd8ea202 Binary files /dev/null and b/icons/obj/items/pens/pen_retractable_green.dmi differ diff --git a/icons/obj/items/pens/pen_retractable_red.dmi b/icons/obj/items/pens/pen_retractable_red.dmi new file mode 100644 index 000000000000..a6f1f858d1be Binary files /dev/null and b/icons/obj/items/pens/pen_retractable_red.dmi differ diff --git a/icons/obj/items/plunger.dmi b/icons/obj/items/plunger.dmi index 92d87c89d565..be4583dbcbab 100644 Binary files a/icons/obj/items/plunger.dmi and b/icons/obj/items/plunger.dmi differ diff --git a/icons/obj/items/posters.dmi b/icons/obj/items/posters.dmi new file mode 100644 index 000000000000..9137e3da5aff Binary files /dev/null and b/icons/obj/items/posters.dmi differ diff --git a/icons/obj/items/remote_control.dmi b/icons/obj/items/remote_control.dmi new file mode 100644 index 000000000000..f69a2b8cc5ab Binary files /dev/null and b/icons/obj/items/remote_control.dmi differ diff --git a/icons/obj/items/retort.dmi b/icons/obj/items/retort.dmi new file mode 100644 index 000000000000..36ecd3b639ec Binary files /dev/null and b/icons/obj/items/retort.dmi differ diff --git a/icons/obj/items/rock.dmi b/icons/obj/items/rock.dmi new file mode 100644 index 000000000000..652da957065f Binary files /dev/null and b/icons/obj/items/rock.dmi differ diff --git a/icons/obj/items/rollerbed.dmi b/icons/obj/items/rollerbed.dmi new file mode 100644 index 000000000000..f8bfbad80e90 Binary files /dev/null and b/icons/obj/items/rollerbed.dmi differ diff --git a/icons/obj/items/rolling_pin.dmi b/icons/obj/items/rolling_pin.dmi new file mode 100644 index 000000000000..afd2f0c30969 Binary files /dev/null and b/icons/obj/items/rolling_pin.dmi differ diff --git a/icons/obj/items/saddle.dmi b/icons/obj/items/saddle.dmi new file mode 100644 index 000000000000..3b0730f99965 Binary files /dev/null and b/icons/obj/items/saddle.dmi differ diff --git a/icons/obj/items/shears.dmi b/icons/obj/items/shears.dmi new file mode 100644 index 000000000000..7329122e5188 Binary files /dev/null and b/icons/obj/items/shears.dmi differ diff --git a/icons/obj/items/sheet_snatcher.dmi b/icons/obj/items/sheet_snatcher.dmi new file mode 100644 index 000000000000..7a898ac6f09c Binary files /dev/null and b/icons/obj/items/sheet_snatcher.dmi differ diff --git a/icons/obj/items/shield/buckler.dmi b/icons/obj/items/shield/buckler.dmi deleted file mode 100644 index ff53a0e14e07..000000000000 Binary files a/icons/obj/items/shield/buckler.dmi and /dev/null differ diff --git a/icons/obj/items/shield/buckler_base_metal.dmi b/icons/obj/items/shield/buckler_base_metal.dmi new file mode 100644 index 000000000000..41372efa755f Binary files /dev/null and b/icons/obj/items/shield/buckler_base_metal.dmi differ diff --git a/icons/obj/items/shield/buckler_base_wood.dmi b/icons/obj/items/shield/buckler_base_wood.dmi new file mode 100644 index 000000000000..03e9bc34a6dc Binary files /dev/null and b/icons/obj/items/shield/buckler_base_wood.dmi differ diff --git a/icons/obj/items/shield/buckler_metal.dmi b/icons/obj/items/shield/buckler_metal.dmi new file mode 100644 index 000000000000..0d27f07c23eb Binary files /dev/null and b/icons/obj/items/shield/buckler_metal.dmi differ diff --git a/icons/obj/items/shield/buckler_wood.dmi b/icons/obj/items/shield/buckler_wood.dmi new file mode 100644 index 000000000000..94e4563a342b Binary files /dev/null and b/icons/obj/items/shield/buckler_wood.dmi differ diff --git a/icons/obj/items/shield/metal.dmi b/icons/obj/items/shield/metal.dmi index c9a07317a62d..e058997b44be 100644 Binary files a/icons/obj/items/shield/metal.dmi and b/icons/obj/items/shield/metal.dmi differ diff --git a/icons/obj/items/shield/metal_security.dmi b/icons/obj/items/shield/metal_security.dmi new file mode 100644 index 000000000000..056a6b359e50 Binary files /dev/null and b/icons/obj/items/shield/metal_security.dmi differ diff --git a/icons/obj/items/shield/riot.dmi b/icons/obj/items/shield/riot.dmi index f5d4fa0c491e..6786b037e667 100644 Binary files a/icons/obj/items/shield/riot.dmi and b/icons/obj/items/shield/riot.dmi differ diff --git a/icons/obj/items/shield_fasteners.dmi b/icons/obj/items/shield_fasteners.dmi new file mode 100644 index 000000000000..e4c289ffc0c0 Binary files /dev/null and b/icons/obj/items/shield_fasteners.dmi differ diff --git a/icons/obj/items/sieve_filter.dmi b/icons/obj/items/sieve_filter.dmi new file mode 100644 index 000000000000..6145828a3111 Binary files /dev/null and b/icons/obj/items/sieve_filter.dmi differ diff --git a/icons/obj/items/sleeping_furs.dmi b/icons/obj/items/sleeping_furs.dmi new file mode 100644 index 000000000000..77f50b78df74 Binary files /dev/null and b/icons/obj/items/sleeping_furs.dmi differ diff --git a/icons/obj/items/soap.dmi b/icons/obj/items/soap.dmi index ae3e08dd72cd..2684964a91cd 100644 Binary files a/icons/obj/items/soap.dmi and b/icons/obj/items/soap.dmi differ diff --git a/icons/obj/items/soulstone.dmi b/icons/obj/items/soulstone.dmi new file mode 100644 index 000000000000..a7d09b5130b8 Binary files /dev/null and b/icons/obj/items/soulstone.dmi differ diff --git a/icons/obj/items/stacks/materials.dmi b/icons/obj/items/stacks/materials.dmi new file mode 100644 index 000000000000..c6127f7fbf61 Binary files /dev/null and b/icons/obj/items/stacks/materials.dmi differ diff --git a/icons/obj/items/stacks/nails.dmi b/icons/obj/items/stacks/nails.dmi new file mode 100644 index 000000000000..10ba6ebcc989 Binary files /dev/null and b/icons/obj/items/stacks/nails.dmi differ diff --git a/icons/obj/items/staff.dmi b/icons/obj/items/staff.dmi new file mode 100644 index 000000000000..cc0b9a0290ee Binary files /dev/null and b/icons/obj/items/staff.dmi differ diff --git a/icons/obj/items/staff_beacon.dmi b/icons/obj/items/staff_beacon.dmi new file mode 100644 index 000000000000..f5430945cff6 Binary files /dev/null and b/icons/obj/items/staff_beacon.dmi differ diff --git a/icons/obj/items/staff_crystal.dmi b/icons/obj/items/staff_crystal.dmi new file mode 100644 index 000000000000..5a7ff054696d Binary files /dev/null and b/icons/obj/items/staff_crystal.dmi differ diff --git a/icons/obj/items/stamps/stamp_boss.dmi b/icons/obj/items/stamps/stamp_boss.dmi new file mode 100644 index 000000000000..69f2f1503c6b Binary files /dev/null and b/icons/obj/items/stamps/stamp_boss.dmi differ diff --git a/icons/obj/items/stamps/stamp_brig.dmi b/icons/obj/items/stamps/stamp_brig.dmi new file mode 100644 index 000000000000..c6f4a6db6321 Binary files /dev/null and b/icons/obj/items/stamps/stamp_brig.dmi differ diff --git a/icons/obj/items/stamps/stamp_cap.dmi b/icons/obj/items/stamps/stamp_cap.dmi new file mode 100644 index 000000000000..c4351b54d8dc Binary files /dev/null and b/icons/obj/items/stamps/stamp_cap.dmi differ diff --git a/icons/obj/items/stamps/stamp_cargo.dmi b/icons/obj/items/stamps/stamp_cargo.dmi new file mode 100644 index 000000000000..182cd17c3407 Binary files /dev/null and b/icons/obj/items/stamps/stamp_cargo.dmi differ diff --git a/icons/obj/items/stamps/stamp_ce.dmi b/icons/obj/items/stamps/stamp_ce.dmi new file mode 100644 index 000000000000..4f0f7f582aa3 Binary files /dev/null and b/icons/obj/items/stamps/stamp_ce.dmi differ diff --git a/icons/obj/items/stamps/stamp_clown.dmi b/icons/obj/items/stamps/stamp_clown.dmi new file mode 100644 index 000000000000..76eafdf47f1a Binary files /dev/null and b/icons/obj/items/stamps/stamp_clown.dmi differ diff --git a/icons/obj/items/stamps/stamp_cmo.dmi b/icons/obj/items/stamps/stamp_cmo.dmi new file mode 100644 index 000000000000..c99097cedb29 Binary files /dev/null and b/icons/obj/items/stamps/stamp_cmo.dmi differ diff --git a/icons/obj/items/stamps/stamp_corp.dmi b/icons/obj/items/stamps/stamp_corp.dmi new file mode 100644 index 000000000000..b8d8df14f73f Binary files /dev/null and b/icons/obj/items/stamps/stamp_corp.dmi differ diff --git a/icons/obj/items/stamps/stamp_cos.dmi b/icons/obj/items/stamps/stamp_cos.dmi new file mode 100644 index 000000000000..b646337e1d1e Binary files /dev/null and b/icons/obj/items/stamps/stamp_cos.dmi differ diff --git a/icons/obj/items/stamps/stamp_deckchief.dmi b/icons/obj/items/stamps/stamp_deckchief.dmi new file mode 100644 index 000000000000..d91fe585f587 Binary files /dev/null and b/icons/obj/items/stamps/stamp_deckchief.dmi differ diff --git a/icons/obj/items/stamps/stamp_deny.dmi b/icons/obj/items/stamps/stamp_deny.dmi new file mode 100644 index 000000000000..394d3786aab5 Binary files /dev/null and b/icons/obj/items/stamps/stamp_deny.dmi differ diff --git a/icons/obj/items/stamps/stamp_rd.dmi b/icons/obj/items/stamps/stamp_rd.dmi new file mode 100644 index 000000000000..294966cbc67e Binary files /dev/null and b/icons/obj/items/stamps/stamp_rd.dmi differ diff --git a/icons/obj/items/stamps/stamp_solgov.dmi b/icons/obj/items/stamps/stamp_solgov.dmi new file mode 100644 index 000000000000..a3ba31c602f8 Binary files /dev/null and b/icons/obj/items/stamps/stamp_solgov.dmi differ diff --git a/icons/obj/items/stamps/stamp_xo.dmi b/icons/obj/items/stamps/stamp_xo.dmi new file mode 100644 index 000000000000..4356bd6fd2e7 Binary files /dev/null and b/icons/obj/items/stamps/stamp_xo.dmi differ diff --git a/icons/obj/items/stick.dmi b/icons/obj/items/stick.dmi index 084aa2508835..7ec761a4fd3e 100644 Binary files a/icons/obj/items/stick.dmi and b/icons/obj/items/stick.dmi differ diff --git a/icons/obj/items/stock_parts/modular_components.dmi b/icons/obj/items/stock_parts/modular_components.dmi index 9c88f3c5c305..1a471de37faf 100644 Binary files a/icons/obj/items/stock_parts/modular_components.dmi and b/icons/obj/items/stock_parts/modular_components.dmi differ diff --git a/icons/obj/items/stock_parts/stock_parts.dmi b/icons/obj/items/stock_parts/stock_parts.dmi index c0b23ced6ab9..24e82a36ceac 100644 Binary files a/icons/obj/items/stock_parts/stock_parts.dmi and b/icons/obj/items/stock_parts/stock_parts.dmi differ diff --git a/icons/obj/items/storage/animal_cube_box.dmi b/icons/obj/items/storage/animal_cube_box.dmi new file mode 100644 index 000000000000..09f7ae9bacd8 Binary files /dev/null and b/icons/obj/items/storage/animal_cube_box.dmi differ diff --git a/icons/obj/items/storage/backpack/backpack.dmi b/icons/obj/items/storage/backpack/backpack.dmi index 959b3bd40746..9b38d461f2c6 100644 Binary files a/icons/obj/items/storage/backpack/backpack.dmi and b/icons/obj/items/storage/backpack/backpack.dmi differ diff --git a/icons/obj/items/storage/backpack/backpack_crafted.dmi b/icons/obj/items/storage/backpack/backpack_crafted.dmi new file mode 100644 index 000000000000..e565e4862a1b Binary files /dev/null and b/icons/obj/items/storage/backpack/backpack_crafted.dmi differ diff --git a/icons/obj/items/storage/backpack/backpack_haversack.dmi b/icons/obj/items/storage/backpack/backpack_haversack.dmi new file mode 100644 index 000000000000..ca148f6a4eac Binary files /dev/null and b/icons/obj/items/storage/backpack/backpack_haversack.dmi differ diff --git a/icons/obj/items/storage/backpack/corvid.dmi b/icons/obj/items/storage/backpack/corvid.dmi new file mode 100644 index 000000000000..9435ec56523c Binary files /dev/null and b/icons/obj/items/storage/backpack/corvid.dmi differ diff --git a/icons/obj/items/storage/backpack/parachute.dmi b/icons/obj/items/storage/backpack/parachute.dmi new file mode 100644 index 000000000000..93dee371e666 Binary files /dev/null and b/icons/obj/items/storage/backpack/parachute.dmi differ diff --git a/icons/obj/items/storage/baskets/basket_large.dmi b/icons/obj/items/storage/baskets/basket_large.dmi new file mode 100644 index 000000000000..71c23d7b6ce1 Binary files /dev/null and b/icons/obj/items/storage/baskets/basket_large.dmi differ diff --git a/icons/obj/items/storage/baskets/basket_round.dmi b/icons/obj/items/storage/baskets/basket_round.dmi new file mode 100644 index 000000000000..c84fe4b7e607 Binary files /dev/null and b/icons/obj/items/storage/baskets/basket_round.dmi differ diff --git a/icons/obj/items/storage/box.dmi b/icons/obj/items/storage/box.dmi index 6a3860fc9977..5f714cb5d69e 100644 Binary files a/icons/obj/items/storage/box.dmi and b/icons/obj/items/storage/box.dmi differ diff --git a/icons/obj/items/storage/briefcase.dmi b/icons/obj/items/storage/briefcase.dmi index 332daec71830..d216fb5b5f51 100644 Binary files a/icons/obj/items/storage/briefcase.dmi and b/icons/obj/items/storage/briefcase.dmi differ diff --git a/icons/obj/items/storage/briefcase_secure.dmi b/icons/obj/items/storage/briefcase_secure.dmi new file mode 100644 index 000000000000..3099aed1b850 Binary files /dev/null and b/icons/obj/items/storage/briefcase_secure.dmi differ diff --git a/icons/obj/items/storage/candles.dmi b/icons/obj/items/storage/candles.dmi new file mode 100644 index 000000000000..62f5ba6f5f76 Binary files /dev/null and b/icons/obj/items/storage/candles.dmi differ diff --git a/icons/obj/items/storage/crime_kit.dmi b/icons/obj/items/storage/crime_kit.dmi new file mode 100644 index 000000000000..9cd9af9722a1 Binary files /dev/null and b/icons/obj/items/storage/crime_kit.dmi differ diff --git a/icons/obj/items/storage/deliverypackage.dmi b/icons/obj/items/storage/deliverypackage.dmi index 29e9972850f0..3b62c84c8b73 100644 Binary files a/icons/obj/items/storage/deliverypackage.dmi and b/icons/obj/items/storage/deliverypackage.dmi differ diff --git a/icons/obj/items/storage/incense.dmi b/icons/obj/items/storage/incense.dmi new file mode 100644 index 000000000000..b35bea24bd33 Binary files /dev/null and b/icons/obj/items/storage/incense.dmi differ diff --git a/icons/obj/items/storage/inflatables.dmi b/icons/obj/items/storage/inflatables.dmi index 7d88f7d48e39..e4d2923feca7 100644 Binary files a/icons/obj/items/storage/inflatables.dmi and b/icons/obj/items/storage/inflatables.dmi differ diff --git a/icons/obj/items/storage/laundry.dmi b/icons/obj/items/storage/laundry.dmi new file mode 100644 index 000000000000..d7b34eda9204 Binary files /dev/null and b/icons/obj/items/storage/laundry.dmi differ diff --git a/icons/obj/items/storage/lunchbox.dmi b/icons/obj/items/storage/lunchbox.dmi deleted file mode 100644 index 8d283cc83695..000000000000 Binary files a/icons/obj/items/storage/lunchbox.dmi and /dev/null differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_cat.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_cat.dmi new file mode 100644 index 000000000000..c1f76eb3d6f5 Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_cat.dmi differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_cti.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_cti.dmi new file mode 100644 index 000000000000..012aa0946691 Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_cti.dmi differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_evil.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_evil.dmi new file mode 100644 index 000000000000..0c8fea6284c2 Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_evil.dmi differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_heart.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_heart.dmi new file mode 100644 index 000000000000..4410d4f354a5 Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_heart.dmi differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_mars.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_mars.dmi new file mode 100644 index 000000000000..d5842898985a Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_mars.dmi differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_rainbow.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_rainbow.dmi new file mode 100644 index 000000000000..de5a0587e2de Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_rainbow.dmi differ diff --git a/icons/obj/items/storage/lunchboxes/lunchbox_tcc.dmi b/icons/obj/items/storage/lunchboxes/lunchbox_tcc.dmi new file mode 100644 index 000000000000..4d008c3237da Binary files /dev/null and b/icons/obj/items/storage/lunchboxes/lunchbox_tcc.dmi differ diff --git a/icons/obj/items/storage/matches/matchbox.dmi b/icons/obj/items/storage/matchbox.dmi similarity index 100% rename from icons/obj/items/storage/matches/matchbox.dmi rename to icons/obj/items/storage/matchbox.dmi diff --git a/icons/obj/items/storage/matches/match.dmi b/icons/obj/items/storage/matches/match.dmi deleted file mode 100644 index 96528ba7408e..000000000000 Binary files a/icons/obj/items/storage/matches/match.dmi and /dev/null differ diff --git a/icons/obj/items/storage/nugget_box.dmi b/icons/obj/items/storage/nugget_box.dmi new file mode 100644 index 000000000000..43293c62dfad Binary files /dev/null and b/icons/obj/items/storage/nugget_box.dmi differ diff --git a/icons/obj/items/storage/part_pack.dmi b/icons/obj/items/storage/part_pack.dmi new file mode 100644 index 000000000000..b850f55bcac6 Binary files /dev/null and b/icons/obj/items/storage/part_pack.dmi differ diff --git a/icons/obj/items/storage/picnic_basket.dmi b/icons/obj/items/storage/picnic_basket.dmi new file mode 100644 index 000000000000..08ce12414fe6 Binary files /dev/null and b/icons/obj/items/storage/picnic_basket.dmi differ diff --git a/icons/obj/items/storage/portafreezer.dmi b/icons/obj/items/storage/portafreezer.dmi index e80bc712afa0..20fed2ca5599 100644 Binary files a/icons/obj/items/storage/portafreezer.dmi and b/icons/obj/items/storage/portafreezer.dmi differ diff --git a/icons/obj/items/storage/sack.dmi b/icons/obj/items/storage/sack.dmi new file mode 100644 index 000000000000..0c3f10f8d816 Binary files /dev/null and b/icons/obj/items/storage/sack.dmi differ diff --git a/icons/obj/items/storage/safe.dmi b/icons/obj/items/storage/safe.dmi index 2f7d1826331c..7eb51f3fb706 100644 Binary files a/icons/obj/items/storage/safe.dmi and b/icons/obj/items/storage/safe.dmi differ diff --git a/icons/obj/items/storage/toolbox.dmi b/icons/obj/items/storage/toolbox.dmi deleted file mode 100644 index a16afeaec757..000000000000 Binary files a/icons/obj/items/storage/toolbox.dmi and /dev/null differ diff --git a/icons/obj/items/storage/toolboxes/toolbox_black_red.dmi b/icons/obj/items/storage/toolboxes/toolbox_black_red.dmi new file mode 100644 index 000000000000..b04e3356d9fd Binary files /dev/null and b/icons/obj/items/storage/toolboxes/toolbox_black_red.dmi differ diff --git a/icons/obj/items/storage/toolboxes/toolbox_blue.dmi b/icons/obj/items/storage/toolboxes/toolbox_blue.dmi new file mode 100644 index 000000000000..94dc99ec3793 Binary files /dev/null and b/icons/obj/items/storage/toolboxes/toolbox_blue.dmi differ diff --git a/icons/obj/items/storage/toolboxes/toolbox_green.dmi b/icons/obj/items/storage/toolboxes/toolbox_green.dmi new file mode 100644 index 000000000000..37c24f0e7180 Binary files /dev/null and b/icons/obj/items/storage/toolboxes/toolbox_green.dmi differ diff --git a/icons/obj/items/storage/toolboxes/toolbox_red.dmi b/icons/obj/items/storage/toolboxes/toolbox_red.dmi new file mode 100644 index 000000000000..f26ba27fab17 Binary files /dev/null and b/icons/obj/items/storage/toolboxes/toolbox_red.dmi differ diff --git a/icons/obj/items/storage/toolboxes/toolbox_yellow.dmi b/icons/obj/items/storage/toolboxes/toolbox_yellow.dmi new file mode 100644 index 000000000000..6a68ee9fd475 Binary files /dev/null and b/icons/obj/items/storage/toolboxes/toolbox_yellow.dmi differ diff --git a/icons/obj/items/storage/toolboxes/toolbox_yellow_striped.dmi b/icons/obj/items/storage/toolboxes/toolbox_yellow_striped.dmi new file mode 100644 index 000000000000..559fcabba2a4 Binary files /dev/null and b/icons/obj/items/storage/toolboxes/toolbox_yellow_striped.dmi differ diff --git a/icons/obj/items/striker.dmi b/icons/obj/items/striker.dmi new file mode 100644 index 000000000000..e4d928b7453d Binary files /dev/null and b/icons/obj/items/striker.dmi differ diff --git a/icons/obj/items/suitcooler.dmi b/icons/obj/items/suitcooler.dmi index f881e07d1f2d..2d16e15e3ba3 100644 Binary files a/icons/obj/items/suitcooler.dmi and b/icons/obj/items/suitcooler.dmi differ diff --git a/icons/obj/items/surgery/bone_lever.dmi b/icons/obj/items/surgery/bone_lever.dmi new file mode 100644 index 000000000000..f36d8b10ffe8 Binary files /dev/null and b/icons/obj/items/surgery/bone_lever.dmi differ diff --git a/icons/obj/items/surgery/bone_setter.dmi b/icons/obj/items/surgery/bone_setter.dmi new file mode 100644 index 000000000000..905d6d769cf2 Binary files /dev/null and b/icons/obj/items/surgery/bone_setter.dmi differ diff --git a/icons/obj/items/surgery/bonesaw.dmi b/icons/obj/items/surgery/bonesaw.dmi new file mode 100644 index 000000000000..ffb17bbf5141 Binary files /dev/null and b/icons/obj/items/surgery/bonesaw.dmi differ diff --git a/icons/obj/items/surgery/cautery.dmi b/icons/obj/items/surgery/cautery.dmi new file mode 100644 index 000000000000..9312c3587819 Binary files /dev/null and b/icons/obj/items/surgery/cautery.dmi differ diff --git a/icons/obj/items/surgery/forceps.dmi b/icons/obj/items/surgery/forceps.dmi new file mode 100644 index 000000000000..7eec4ecf1199 Binary files /dev/null and b/icons/obj/items/surgery/forceps.dmi differ diff --git a/icons/obj/items/surgery/scalpel.dmi b/icons/obj/items/surgery/scalpel.dmi new file mode 100644 index 000000000000..93f134eb1b24 Binary files /dev/null and b/icons/obj/items/surgery/scalpel.dmi differ diff --git a/icons/obj/items/surgery/sutures.dmi b/icons/obj/items/surgery/sutures.dmi new file mode 100644 index 000000000000..e1512a5ffc7d Binary files /dev/null and b/icons/obj/items/surgery/sutures.dmi differ diff --git a/icons/obj/items/tanks/jetpack.dmi b/icons/obj/items/tanks/jetpack.dmi new file mode 100644 index 000000000000..d9f21812efdd Binary files /dev/null and b/icons/obj/items/tanks/jetpack.dmi differ diff --git a/icons/obj/items/tanks/jetpack_co2.dmi b/icons/obj/items/tanks/jetpack_co2.dmi new file mode 100644 index 000000000000..cec3ac5aa97b Binary files /dev/null and b/icons/obj/items/tanks/jetpack_co2.dmi differ diff --git a/icons/obj/items/tanks/jetpack_void.dmi b/icons/obj/items/tanks/jetpack_void.dmi new file mode 100644 index 000000000000..2d91342b1964 Binary files /dev/null and b/icons/obj/items/tanks/jetpack_void.dmi differ diff --git a/icons/obj/items/tanks/tank_blue.dmi b/icons/obj/items/tanks/tank_blue.dmi new file mode 100644 index 000000000000..b59804718553 Binary files /dev/null and b/icons/obj/items/tanks/tank_blue.dmi differ diff --git a/icons/obj/items/tanks/tank_components.dmi b/icons/obj/items/tanks/tank_components.dmi new file mode 100644 index 000000000000..6bf964931add Binary files /dev/null and b/icons/obj/items/tanks/tank_components.dmi differ diff --git a/icons/obj/items/tanks/tank_emergency.dmi b/icons/obj/items/tanks/tank_emergency.dmi new file mode 100644 index 000000000000..fa015f1d849d Binary files /dev/null and b/icons/obj/items/tanks/tank_emergency.dmi differ diff --git a/icons/obj/items/tanks/tank_emergency_double.dmi b/icons/obj/items/tanks/tank_emergency_double.dmi new file mode 100644 index 000000000000..de7aeee9ac76 Binary files /dev/null and b/icons/obj/items/tanks/tank_emergency_double.dmi differ diff --git a/icons/obj/items/tanks/tank_emergency_engineer.dmi b/icons/obj/items/tanks/tank_emergency_engineer.dmi new file mode 100644 index 000000000000..05d8ed2fba08 Binary files /dev/null and b/icons/obj/items/tanks/tank_emergency_engineer.dmi differ diff --git a/icons/obj/items/tanks/tank_greyscaled.dmi b/icons/obj/items/tanks/tank_greyscaled.dmi new file mode 100644 index 000000000000..b2fb288f53d8 Binary files /dev/null and b/icons/obj/items/tanks/tank_greyscaled.dmi differ diff --git a/icons/obj/items/tanks/tank_indicators.dmi b/icons/obj/items/tanks/tank_indicators.dmi new file mode 100644 index 000000000000..ab8a452d4f85 Binary files /dev/null and b/icons/obj/items/tanks/tank_indicators.dmi differ diff --git a/icons/obj/items/tanks/tank_red.dmi b/icons/obj/items/tanks/tank_red.dmi new file mode 100644 index 000000000000..2ce99b6021d0 Binary files /dev/null and b/icons/obj/items/tanks/tank_red.dmi differ diff --git a/icons/obj/items/tanks/tank_scuba.dmi b/icons/obj/items/tanks/tank_scuba.dmi new file mode 100644 index 000000000000..13bdf7ee323e Binary files /dev/null and b/icons/obj/items/tanks/tank_scuba.dmi differ diff --git a/icons/obj/items/tanks/tank_stirling.dmi b/icons/obj/items/tanks/tank_stirling.dmi new file mode 100644 index 000000000000..5280aef46eed Binary files /dev/null and b/icons/obj/items/tanks/tank_stirling.dmi differ diff --git a/icons/obj/items/tanks/tank_yellow.dmi b/icons/obj/items/tanks/tank_yellow.dmi new file mode 100644 index 000000000000..21fce09a0edd Binary files /dev/null and b/icons/obj/items/tanks/tank_yellow.dmi differ diff --git a/icons/obj/items/tonercartridge.dmi b/icons/obj/items/tonercartridge.dmi index 8679f24baf2b..551834408e73 100644 Binary files a/icons/obj/items/tonercartridge.dmi and b/icons/obj/items/tonercartridge.dmi differ diff --git a/icons/obj/items/tool/arc_welder.dmi b/icons/obj/items/tool/arc_welder.dmi deleted file mode 100644 index e36c53c974fd..000000000000 Binary files a/icons/obj/items/tool/arc_welder.dmi and /dev/null differ diff --git a/icons/obj/items/tool/axes/handaxe.dmi b/icons/obj/items/tool/axes/handaxe.dmi new file mode 100644 index 000000000000..ac66fd9d9c48 Binary files /dev/null and b/icons/obj/items/tool/axes/handaxe.dmi differ diff --git a/icons/obj/items/tool/axes/hatchet.dmi b/icons/obj/items/tool/axes/hatchet.dmi new file mode 100644 index 000000000000..155dfe5076f5 Binary files /dev/null and b/icons/obj/items/tool/axes/hatchet.dmi differ diff --git a/icons/obj/items/tool/chisel.dmi b/icons/obj/items/tool/chisel.dmi new file mode 100644 index 000000000000..e277e1ba44b6 Binary files /dev/null and b/icons/obj/items/tool/chisel.dmi differ diff --git a/icons/obj/items/tool/components/tool_handle.dmi b/icons/obj/items/tool/components/tool_handle.dmi new file mode 100644 index 000000000000..15ef1f12f12c Binary files /dev/null and b/icons/obj/items/tool/components/tool_handle.dmi differ diff --git a/icons/obj/items/tool/components/tool_head.dmi b/icons/obj/items/tool/components/tool_head.dmi new file mode 100644 index 000000000000..cc9a43d99710 Binary files /dev/null and b/icons/obj/items/tool/components/tool_head.dmi differ diff --git a/icons/obj/items/tool/cutter.dmi b/icons/obj/items/tool/cutter.dmi new file mode 100644 index 000000000000..046c6655035c Binary files /dev/null and b/icons/obj/items/tool/cutter.dmi differ diff --git a/icons/obj/items/tool/drills/drill.dmi b/icons/obj/items/tool/drills/drill.dmi new file mode 100644 index 000000000000..4be78e31c27d Binary files /dev/null and b/icons/obj/items/tool/drills/drill.dmi differ diff --git a/icons/obj/items/tool/drills/drill_advanced.dmi b/icons/obj/items/tool/drills/drill_advanced.dmi new file mode 100644 index 000000000000..19a13b507a45 Binary files /dev/null and b/icons/obj/items/tool/drills/drill_advanced.dmi differ diff --git a/icons/obj/items/tool/drills/drill_diamond.dmi b/icons/obj/items/tool/drills/drill_diamond.dmi new file mode 100644 index 000000000000..214c6dbe5ecc Binary files /dev/null and b/icons/obj/items/tool/drills/drill_diamond.dmi differ diff --git a/icons/obj/items/tool/fireaxe.dmi b/icons/obj/items/tool/fireaxe.dmi deleted file mode 100644 index 10a12c556f52..000000000000 Binary files a/icons/obj/items/tool/fireaxe.dmi and /dev/null differ diff --git a/icons/obj/items/tool/hammers/forge.dmi b/icons/obj/items/tool/hammers/forge.dmi new file mode 100644 index 000000000000..a7b0a4e06110 Binary files /dev/null and b/icons/obj/items/tool/hammers/forge.dmi differ diff --git a/icons/obj/items/tool/hammers/hammer.dmi b/icons/obj/items/tool/hammers/hammer.dmi new file mode 100644 index 000000000000..238e799db7bd Binary files /dev/null and b/icons/obj/items/tool/hammers/hammer.dmi differ diff --git a/icons/obj/items/tool/hammers/jackhammer.dmi b/icons/obj/items/tool/hammers/jackhammer.dmi new file mode 100644 index 000000000000..52a3667e6a31 Binary files /dev/null and b/icons/obj/items/tool/hammers/jackhammer.dmi differ diff --git a/icons/obj/items/tool/hammers/sledgehammer.dmi b/icons/obj/items/tool/hammers/sledgehammer.dmi new file mode 100644 index 000000000000..33c7f4221659 Binary files /dev/null and b/icons/obj/items/tool/hammers/sledgehammer.dmi differ diff --git a/icons/obj/items/tool/hatchet.dmi b/icons/obj/items/tool/hatchet.dmi deleted file mode 100644 index f2407d182fb2..000000000000 Binary files a/icons/obj/items/tool/hatchet.dmi and /dev/null differ diff --git a/icons/obj/items/tool/hoe.dmi b/icons/obj/items/tool/hoe.dmi deleted file mode 100644 index d6ba2c6675fe..000000000000 Binary files a/icons/obj/items/tool/hoe.dmi and /dev/null differ diff --git a/icons/obj/items/tool/hoes/hoe.dmi b/icons/obj/items/tool/hoes/hoe.dmi new file mode 100644 index 000000000000..8d383e739f53 Binary files /dev/null and b/icons/obj/items/tool/hoes/hoe.dmi differ diff --git a/icons/obj/items/tool/hoes/minihoe.dmi b/icons/obj/items/tool/hoes/minihoe.dmi new file mode 100644 index 000000000000..33c2b1c58d29 Binary files /dev/null and b/icons/obj/items/tool/hoes/minihoe.dmi differ diff --git a/icons/obj/items/tool/maintenance_jack.dmi b/icons/obj/items/tool/maintenance_jack.dmi index 51246e592945..15484f469267 100644 Binary files a/icons/obj/items/tool/maintenance_jack.dmi and b/icons/obj/items/tool/maintenance_jack.dmi differ diff --git a/icons/obj/items/tool/mining_drill.dmi b/icons/obj/items/tool/mining_drill.dmi deleted file mode 100644 index eb02741d97e2..000000000000 Binary files a/icons/obj/items/tool/mining_drill.dmi and /dev/null differ diff --git a/icons/obj/items/tool/pickaxe.dmi b/icons/obj/items/tool/pickaxe.dmi index 708b35085d8e..2c00ec7289ef 100644 Binary files a/icons/obj/items/tool/pickaxe.dmi and b/icons/obj/items/tool/pickaxe.dmi differ diff --git a/icons/obj/items/tool/pipewrench.dmi b/icons/obj/items/tool/pipewrench.dmi new file mode 100644 index 000000000000..18385b48e414 Binary files /dev/null and b/icons/obj/items/tool/pipewrench.dmi differ diff --git a/icons/obj/items/tool/powerdrill.dmi b/icons/obj/items/tool/powerdrill.dmi new file mode 100644 index 000000000000..dc8ca48a6d9d Binary files /dev/null and b/icons/obj/items/tool/powerdrill.dmi differ diff --git a/icons/obj/items/tool/scythe.dmi b/icons/obj/items/tool/scythe.dmi index 5d1da2ade226..f0725daec0cc 100644 Binary files a/icons/obj/items/tool/scythe.dmi and b/icons/obj/items/tool/scythe.dmi differ diff --git a/icons/obj/items/tool/shovel.dmi b/icons/obj/items/tool/shovel.dmi deleted file mode 100644 index 4d7ede322171..000000000000 Binary files a/icons/obj/items/tool/shovel.dmi and /dev/null differ diff --git a/icons/obj/items/tool/shovels/shovel.dmi b/icons/obj/items/tool/shovels/shovel.dmi new file mode 100644 index 000000000000..7a147de7f43b Binary files /dev/null and b/icons/obj/items/tool/shovels/shovel.dmi differ diff --git a/icons/obj/items/tool/shovels/spade.dmi b/icons/obj/items/tool/shovels/spade.dmi new file mode 100644 index 000000000000..d4767d6e38c6 Binary files /dev/null and b/icons/obj/items/tool/shovels/spade.dmi differ diff --git a/icons/obj/items/tool/sledgehammer.dmi b/icons/obj/items/tool/sledgehammer.dmi deleted file mode 100644 index 4475a10c579b..000000000000 Binary files a/icons/obj/items/tool/sledgehammer.dmi and /dev/null differ diff --git a/icons/obj/items/tool/spade.dmi b/icons/obj/items/tool/spade.dmi deleted file mode 100644 index df6cf9a8fd81..000000000000 Binary files a/icons/obj/items/tool/spade.dmi and /dev/null differ diff --git a/icons/obj/items/tool/welder.dmi b/icons/obj/items/tool/welder.dmi deleted file mode 100644 index 9763b62da4b6..000000000000 Binary files a/icons/obj/items/tool/welder.dmi and /dev/null differ diff --git a/icons/obj/items/tool/welders/welder.dmi b/icons/obj/items/tool/welders/welder.dmi new file mode 100644 index 000000000000..4db9e2df9b1a Binary files /dev/null and b/icons/obj/items/tool/welders/welder.dmi differ diff --git a/icons/obj/items/tool/welders/welder_arc.dmi b/icons/obj/items/tool/welders/welder_arc.dmi new file mode 100644 index 000000000000..a6d122a8217d Binary files /dev/null and b/icons/obj/items/tool/welders/welder_arc.dmi differ diff --git a/icons/obj/items/tool/welder_tank.dmi b/icons/obj/items/tool/welders/welder_tanks.dmi similarity index 100% rename from icons/obj/items/tool/welder_tank.dmi rename to icons/obj/items/tool/welders/welder_tanks.dmi diff --git a/icons/obj/items/towel.dmi b/icons/obj/items/towel.dmi index ab8a4ddb151a..c879bdae767b 100644 Binary files a/icons/obj/items/towel.dmi and b/icons/obj/items/towel.dmi differ diff --git a/icons/obj/items/training_dummies/alien.dmi b/icons/obj/items/training_dummies/alien.dmi new file mode 100644 index 000000000000..a08ae3ce7fa2 Binary files /dev/null and b/icons/obj/items/training_dummies/alien.dmi differ diff --git a/icons/obj/items/training_dummies/archery.dmi b/icons/obj/items/training_dummies/archery.dmi new file mode 100644 index 000000000000..b3e58a34a26c Binary files /dev/null and b/icons/obj/items/training_dummies/archery.dmi differ diff --git a/icons/obj/items/training_dummies/damage.dmi b/icons/obj/items/training_dummies/damage.dmi new file mode 100644 index 000000000000..6eaae4a674ab Binary files /dev/null and b/icons/obj/items/training_dummies/damage.dmi differ diff --git a/icons/obj/items/training_dummies/standard.dmi b/icons/obj/items/training_dummies/standard.dmi new file mode 100644 index 000000000000..d4b367b4db84 Binary files /dev/null and b/icons/obj/items/training_dummies/standard.dmi differ diff --git a/icons/obj/items/training_dummies/straw.dmi b/icons/obj/items/training_dummies/straw.dmi new file mode 100644 index 000000000000..aa4646488b34 Binary files /dev/null and b/icons/obj/items/training_dummies/straw.dmi differ diff --git a/icons/obj/items/training_dummies/syndicate.dmi b/icons/obj/items/training_dummies/syndicate.dmi new file mode 100644 index 000000000000..aee57436e791 Binary files /dev/null and b/icons/obj/items/training_dummies/syndicate.dmi differ diff --git a/icons/obj/items/umbrella.dmi b/icons/obj/items/umbrella.dmi new file mode 100644 index 000000000000..3aaee9489e72 Binary files /dev/null and b/icons/obj/items/umbrella.dmi differ diff --git a/icons/obj/items/wall_sconce.dmi b/icons/obj/items/wall_sconce.dmi new file mode 100644 index 000000000000..ed89ebac6c6a Binary files /dev/null and b/icons/obj/items/wall_sconce.dmi differ diff --git a/icons/obj/items/waterskin.dmi b/icons/obj/items/waterskin.dmi new file mode 100644 index 000000000000..51c693ce7f28 Binary files /dev/null and b/icons/obj/items/waterskin.dmi differ diff --git a/icons/obj/items/waterskin_crafted.dmi b/icons/obj/items/waterskin_crafted.dmi new file mode 100644 index 000000000000..eca28d255b4f Binary files /dev/null and b/icons/obj/items/waterskin_crafted.dmi differ diff --git a/icons/obj/items/weapon/arrow.dmi b/icons/obj/items/weapon/arrow.dmi new file mode 100644 index 000000000000..10ce7361923c Binary files /dev/null and b/icons/obj/items/weapon/arrow.dmi differ diff --git a/icons/obj/items/weapon/arrow_bolt.dmi b/icons/obj/items/weapon/arrow_bolt.dmi new file mode 100644 index 000000000000..e02729fb9a40 Binary files /dev/null and b/icons/obj/items/weapon/arrow_bolt.dmi differ diff --git a/icons/obj/items/weapon/arrow_rod.dmi b/icons/obj/items/weapon/arrow_rod.dmi new file mode 100644 index 000000000000..a3efd2aa7329 Binary files /dev/null and b/icons/obj/items/weapon/arrow_rod.dmi differ diff --git a/icons/obj/items/weapon/bat.dmi b/icons/obj/items/weapon/bat.dmi index 053712b730ec..5c9ca936c5e1 100644 Binary files a/icons/obj/items/weapon/bat.dmi and b/icons/obj/items/weapon/bat.dmi differ diff --git a/icons/obj/items/weapon/batterer.dmi b/icons/obj/items/weapon/batterer.dmi index 8b8030f5b98f..5109ca468e5e 100644 Binary files a/icons/obj/items/weapon/batterer.dmi and b/icons/obj/items/weapon/batterer.dmi differ diff --git a/icons/obj/items/weapon/bone_axe.dmi b/icons/obj/items/weapon/bone_axe.dmi index ab71d61aefd1..6694b5cc62e7 100644 Binary files a/icons/obj/items/weapon/bone_axe.dmi and b/icons/obj/items/weapon/bone_axe.dmi differ diff --git a/icons/obj/items/weapon/crossbow_bolt.dmi b/icons/obj/items/weapon/crossbow_bolt.dmi deleted file mode 100644 index 91f25320fe93..000000000000 Binary files a/icons/obj/items/weapon/crossbow_bolt.dmi and /dev/null differ diff --git a/icons/obj/items/weapon/e_axe.dmi b/icons/obj/items/weapon/e_axe.dmi index 1be7d381c196..b22ac5bfe11c 100644 Binary files a/icons/obj/items/weapon/e_axe.dmi and b/icons/obj/items/weapon/e_axe.dmi differ diff --git a/icons/obj/items/weapon/e_cutlass.dmi b/icons/obj/items/weapon/e_cutlass.dmi index d5f8fa622e3c..f8f010a247b9 100644 Binary files a/icons/obj/items/weapon/e_cutlass.dmi and b/icons/obj/items/weapon/e_cutlass.dmi differ diff --git a/icons/obj/items/weapon/e_machete.dmi b/icons/obj/items/weapon/e_machete.dmi index 58843ddf28a9..9cccc2290e9d 100644 Binary files a/icons/obj/items/weapon/e_machete.dmi and b/icons/obj/items/weapon/e_machete.dmi differ diff --git a/icons/obj/items/weapon/e_sword.dmi b/icons/obj/items/weapon/e_sword.dmi index 2b1030478aac..b234e7bfd797 100644 Binary files a/icons/obj/items/weapon/e_sword.dmi and b/icons/obj/items/weapon/e_sword.dmi differ diff --git a/icons/obj/items/weapon/energy_blade.dmi b/icons/obj/items/weapon/energy_blade.dmi index 51bf88b76ba8..9e27ec72eee2 100644 Binary files a/icons/obj/items/weapon/energy_blade.dmi and b/icons/obj/items/weapon/energy_blade.dmi differ diff --git a/icons/obj/items/weapon/knives/opener.dmi b/icons/obj/items/weapon/knives/opener.dmi new file mode 100644 index 000000000000..fe4ef0a92903 Binary files /dev/null and b/icons/obj/items/weapon/knives/opener.dmi differ diff --git a/icons/obj/items/weapon/knives/table.dmi b/icons/obj/items/weapon/knives/table.dmi deleted file mode 100644 index d5ee2f220a03..000000000000 Binary files a/icons/obj/items/weapon/knives/table.dmi and /dev/null differ diff --git a/icons/obj/items/weapon/knives/xenoarch/knife1.dmi b/icons/obj/items/weapon/knives/xenoarch/knife1.dmi new file mode 100644 index 000000000000..d7bcf9f88d50 Binary files /dev/null and b/icons/obj/items/weapon/knives/xenoarch/knife1.dmi differ diff --git a/icons/obj/items/weapon/knives/xenoarch/knife2.dmi b/icons/obj/items/weapon/knives/xenoarch/knife2.dmi new file mode 100644 index 000000000000..acf6e98877ea Binary files /dev/null and b/icons/obj/items/weapon/knives/xenoarch/knife2.dmi differ diff --git a/icons/obj/items/weapon/knives/xenoarch/knife3.dmi b/icons/obj/items/weapon/knives/xenoarch/knife3.dmi new file mode 100644 index 000000000000..3cf21ac526d9 Binary files /dev/null and b/icons/obj/items/weapon/knives/xenoarch/knife3.dmi differ diff --git a/icons/obj/items/weapon/machete.dmi b/icons/obj/items/weapon/machete.dmi deleted file mode 100644 index 4c0de4770089..000000000000 Binary files a/icons/obj/items/weapon/machete.dmi and /dev/null differ diff --git a/icons/obj/items/weapon/machetes/machete.dmi b/icons/obj/items/weapon/machetes/machete.dmi new file mode 100644 index 000000000000..57ef1edbeced Binary files /dev/null and b/icons/obj/items/weapon/machetes/machete.dmi differ diff --git a/icons/obj/items/weapon/machetes/machete_black.dmi b/icons/obj/items/weapon/machetes/machete_black.dmi new file mode 100644 index 000000000000..6e996e6e9dd3 Binary files /dev/null and b/icons/obj/items/weapon/machetes/machete_black.dmi differ diff --git a/icons/obj/items/weapon/machetes/machete_blue.dmi b/icons/obj/items/weapon/machetes/machete_blue.dmi new file mode 100644 index 000000000000..cd8cd4e42fbc Binary files /dev/null and b/icons/obj/items/weapon/machetes/machete_blue.dmi differ diff --git a/icons/obj/items/weapon/machetes/machete_dx.dmi b/icons/obj/items/weapon/machetes/machete_dx.dmi new file mode 100644 index 000000000000..38c5b5214a61 Binary files /dev/null and b/icons/obj/items/weapon/machetes/machete_dx.dmi differ diff --git a/icons/obj/items/weapon/machetes/machete_olive.dmi b/icons/obj/items/weapon/machetes/machete_olive.dmi new file mode 100644 index 000000000000..2e4cffcb57bd Binary files /dev/null and b/icons/obj/items/weapon/machetes/machete_olive.dmi differ diff --git a/icons/obj/items/weapon/machetes/machete_red.dmi b/icons/obj/items/weapon/machetes/machete_red.dmi new file mode 100644 index 000000000000..f0d18d0723be Binary files /dev/null and b/icons/obj/items/weapon/machetes/machete_red.dmi differ diff --git a/icons/obj/items/weapon/old_baton.dmi b/icons/obj/items/weapon/old_baton.dmi index 609f8ba8d294..3c5cb37a4e7d 100644 Binary files a/icons/obj/items/weapon/old_baton.dmi and b/icons/obj/items/weapon/old_baton.dmi differ diff --git a/icons/obj/items/weapon/parade_sword.dmi b/icons/obj/items/weapon/parade_sword.dmi index 6d16f493e619..917e2f700b8f 100644 Binary files a/icons/obj/items/weapon/parade_sword.dmi and b/icons/obj/items/weapon/parade_sword.dmi differ diff --git a/icons/obj/items/weapon/parade_sword_army.dmi b/icons/obj/items/weapon/parade_sword_army.dmi new file mode 100644 index 000000000000..4defa7d294fe Binary files /dev/null and b/icons/obj/items/weapon/parade_sword_army.dmi differ diff --git a/icons/obj/items/weapon/parade_sword_armyofficer.dmi b/icons/obj/items/weapon/parade_sword_armyofficer.dmi new file mode 100644 index 000000000000..6572cd12e787 Binary files /dev/null and b/icons/obj/items/weapon/parade_sword_armyofficer.dmi differ diff --git a/icons/obj/items/weapon/parade_sword_pettyofficer.dmi b/icons/obj/items/weapon/parade_sword_pettyofficer.dmi new file mode 100644 index 000000000000..e860f3aeb901 Binary files /dev/null and b/icons/obj/items/weapon/parade_sword_pettyofficer.dmi differ diff --git a/icons/obj/items/weapon/pepperspray.dmi b/icons/obj/items/weapon/pepperspray.dmi index 0996de289eab..5fd84da24bf8 100644 Binary files a/icons/obj/items/weapon/pepperspray.dmi and b/icons/obj/items/weapon/pepperspray.dmi differ diff --git a/icons/obj/items/weapon/spear.dmi b/icons/obj/items/weapon/spear.dmi deleted file mode 100644 index 44e53b26c7b6..000000000000 Binary files a/icons/obj/items/weapon/spear.dmi and /dev/null differ diff --git a/icons/obj/items/weapon/stunbaton.dmi b/icons/obj/items/weapon/stunbaton.dmi index cb10629cbdac..da54a77b42f0 100644 Binary files a/icons/obj/items/weapon/stunbaton.dmi and b/icons/obj/items/weapon/stunbaton.dmi differ diff --git a/icons/obj/items/weapon/swords/xenoarch/sword1.dmi b/icons/obj/items/weapon/swords/xenoarch/sword1.dmi new file mode 100644 index 000000000000..95635abd692e Binary files /dev/null and b/icons/obj/items/weapon/swords/xenoarch/sword1.dmi differ diff --git a/icons/obj/items/weapon/swords/xenoarch/sword2.dmi b/icons/obj/items/weapon/swords/xenoarch/sword2.dmi new file mode 100644 index 000000000000..acc701eee676 Binary files /dev/null and b/icons/obj/items/weapon/swords/xenoarch/sword2.dmi differ diff --git a/icons/obj/items/weapon/swords/xenoarch/sword3.dmi b/icons/obj/items/weapon/swords/xenoarch/sword3.dmi new file mode 100644 index 000000000000..47165d584d5e Binary files /dev/null and b/icons/obj/items/weapon/swords/xenoarch/sword3.dmi differ diff --git a/icons/obj/items/weapon/telebaton.dmi b/icons/obj/items/weapon/telebaton.dmi index 70079f0dc99f..5c6c7f8a30a7 100644 Binary files a/icons/obj/items/weapon/telebaton.dmi and b/icons/obj/items/weapon/telebaton.dmi differ diff --git a/icons/obj/items/weapon/telebaton_extended.dmi b/icons/obj/items/weapon/telebaton_extended.dmi new file mode 100644 index 000000000000..c6de09124e20 Binary files /dev/null and b/icons/obj/items/weapon/telebaton_extended.dmi differ diff --git a/icons/obj/items/welderpack.dmi b/icons/obj/items/welderpack.dmi index 7e990e5a5030..3f81d27c34bf 100644 Binary files a/icons/obj/items/welderpack.dmi and b/icons/obj/items/welderpack.dmi differ diff --git a/icons/obj/items/wheelchairkit.dmi b/icons/obj/items/wheelchairkit.dmi new file mode 100644 index 000000000000..d6615844f79a Binary files /dev/null and b/icons/obj/items/wheelchairkit.dmi differ diff --git a/icons/obj/items/wooden_bucket.dmi b/icons/obj/items/wooden_bucket.dmi index 14e9289375c8..7a4768308be3 100644 Binary files a/icons/obj/items/wooden_bucket.dmi and b/icons/obj/items/wooden_bucket.dmi differ diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi index 49719b847622..2aa64f7baf87 100644 Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi index 44e43e52b0c6..52ca26faca72 100644 Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi index 026277e17ac2..7788a0198ec6 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/icons/obj/light_overlays.dmi b/icons/obj/light_overlays.dmi deleted file mode 100644 index 4440f2655234..000000000000 Binary files a/icons/obj/light_overlays.dmi and /dev/null differ diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi index 8a35e9974faf..bc8876bdf83f 100644 Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ diff --git a/icons/obj/lighting/biglight.dmi b/icons/obj/lighting/biglight.dmi new file mode 100644 index 000000000000..a648e65cc5dc Binary files /dev/null and b/icons/obj/lighting/biglight.dmi differ diff --git a/icons/obj/lighting/flare.dmi b/icons/obj/lighting/flare.dmi new file mode 100644 index 000000000000..4b22743fcd40 Binary files /dev/null and b/icons/obj/lighting/flare.dmi differ diff --git a/icons/obj/lighting/flashdark.dmi b/icons/obj/lighting/flashdark.dmi new file mode 100644 index 000000000000..e170d7557c7d Binary files /dev/null and b/icons/obj/lighting/flashdark.dmi differ diff --git a/icons/obj/lighting/flashlight.dmi b/icons/obj/lighting/flashlight.dmi new file mode 100644 index 000000000000..125baa0191b9 Binary files /dev/null and b/icons/obj/lighting/flashlight.dmi differ diff --git a/icons/obj/lighting/floodlamp.dmi b/icons/obj/lighting/floodlamp.dmi new file mode 100644 index 000000000000..f83030c1a33f Binary files /dev/null and b/icons/obj/lighting/floodlamp.dmi differ diff --git a/icons/obj/lighting/glowstick.dmi b/icons/obj/lighting/glowstick.dmi new file mode 100644 index 000000000000..104783f58223 Binary files /dev/null and b/icons/obj/lighting/glowstick.dmi differ diff --git a/icons/obj/lighting/greenfloodlamp.dmi b/icons/obj/lighting/greenfloodlamp.dmi new file mode 100644 index 000000000000..2ff64bb8be14 Binary files /dev/null and b/icons/obj/lighting/greenfloodlamp.dmi differ diff --git a/icons/obj/lighting/greenlamp.dmi b/icons/obj/lighting/greenlamp.dmi new file mode 100644 index 000000000000..f752728b1eba Binary files /dev/null and b/icons/obj/lighting/greenlamp.dmi differ diff --git a/icons/obj/lighting/lamp.dmi b/icons/obj/lighting/lamp.dmi new file mode 100644 index 000000000000..eb34046610b6 Binary files /dev/null and b/icons/obj/lighting/lamp.dmi differ diff --git a/icons/obj/lighting/lantern.dmi b/icons/obj/lighting/lantern.dmi new file mode 100644 index 000000000000..6a41f129f1a4 Binary files /dev/null and b/icons/obj/lighting/lantern.dmi differ diff --git a/icons/obj/lighting/lavalamp.dmi b/icons/obj/lighting/lavalamp.dmi new file mode 100644 index 000000000000..062aabeba29d Binary files /dev/null and b/icons/obj/lighting/lavalamp.dmi differ diff --git a/icons/obj/lighting/maglight.dmi b/icons/obj/lighting/maglight.dmi new file mode 100644 index 000000000000..fcdd3fdb7d64 Binary files /dev/null and b/icons/obj/lighting/maglight.dmi differ diff --git a/icons/obj/lighting/partylight.dmi b/icons/obj/lighting/partylight.dmi new file mode 100644 index 000000000000..8d17a66f5b80 Binary files /dev/null and b/icons/obj/lighting/partylight.dmi differ diff --git a/icons/obj/lighting/penlight.dmi b/icons/obj/lighting/penlight.dmi new file mode 100644 index 000000000000..a7652eb693ec Binary files /dev/null and b/icons/obj/lighting/penlight.dmi differ diff --git a/icons/obj/lighting/slime.dmi b/icons/obj/lighting/slime.dmi new file mode 100644 index 000000000000..202cf12ad413 Binary files /dev/null and b/icons/obj/lighting/slime.dmi differ diff --git a/icons/obj/machines/adherent.dmi b/icons/obj/machines/adherent.dmi deleted file mode 100644 index a814c79d017c..000000000000 Binary files a/icons/obj/machines/adherent.dmi and /dev/null differ diff --git a/icons/obj/machines/airlock_sensor.dmi b/icons/obj/machines/airlock_sensor.dmi new file mode 100644 index 000000000000..e66c430f08b7 Binary files /dev/null and b/icons/obj/machines/airlock_sensor.dmi differ diff --git a/icons/obj/machines/button_airlock.dmi b/icons/obj/machines/button_airlock.dmi new file mode 100644 index 000000000000..5232d19a0ddb Binary files /dev/null and b/icons/obj/machines/button_airlock.dmi differ diff --git a/icons/obj/machines/centrifuge.dmi b/icons/obj/machines/centrifuge.dmi new file mode 100644 index 000000000000..6cae1e66cf32 Binary files /dev/null and b/icons/obj/machines/centrifuge.dmi differ diff --git a/icons/obj/machines/conveyor_mapped.dmi b/icons/obj/machines/conveyor_mapped.dmi new file mode 100644 index 000000000000..09f090218890 Binary files /dev/null and b/icons/obj/machines/conveyor_mapped.dmi differ diff --git a/icons/obj/machines/fabricators/autolathe.dmi b/icons/obj/machines/fabricators/autolathe.dmi index bf1ab87f8495..25bffc10e7cb 100644 Binary files a/icons/obj/machines/fabricators/autolathe.dmi and b/icons/obj/machines/fabricators/autolathe.dmi differ diff --git a/icons/obj/machines/fabricators/bioprinter.dmi b/icons/obj/machines/fabricators/bioprinter.dmi new file mode 100644 index 000000000000..3b7889974758 Binary files /dev/null and b/icons/obj/machines/fabricators/bioprinter.dmi differ diff --git a/icons/obj/machines/fax_machine.dmi b/icons/obj/machines/fax_machine.dmi new file mode 100644 index 000000000000..7184cca58cf1 Binary files /dev/null and b/icons/obj/machines/fax_machine.dmi differ diff --git a/icons/obj/machines/floodlight.dmi b/icons/obj/machines/floodlight.dmi index 3a5fb7a901dd..8dca92897cd1 100644 Binary files a/icons/obj/machines/floodlight.dmi and b/icons/obj/machines/floodlight.dmi differ diff --git a/icons/obj/machines/gigadrill.dmi b/icons/obj/machines/gigadrill.dmi new file mode 100644 index 000000000000..bcbda6a51446 Binary files /dev/null and b/icons/obj/machines/gigadrill.dmi differ diff --git a/icons/obj/machines/implantchair.dmi b/icons/obj/machines/implantchair.dmi deleted file mode 100644 index 94adefcbf281..000000000000 Binary files a/icons/obj/machines/implantchair.dmi and /dev/null differ diff --git a/icons/obj/machines/internet_uplink.dmi b/icons/obj/machines/internet_uplink.dmi new file mode 100644 index 000000000000..6aad32513f01 Binary files /dev/null and b/icons/obj/machines/internet_uplink.dmi differ diff --git a/icons/obj/machines/medpump.dmi b/icons/obj/machines/medpump.dmi new file mode 100644 index 000000000000..01f5a1dc4b9a Binary files /dev/null and b/icons/obj/machines/medpump.dmi differ diff --git a/icons/obj/machines/mining_machine_overlays.dmi b/icons/obj/machines/mining_machine_overlays.dmi new file mode 100644 index 000000000000..fb657c77f8ac Binary files /dev/null and b/icons/obj/machines/mining_machine_overlays.dmi differ diff --git a/icons/obj/machines/mining_machines.dmi b/icons/obj/machines/mining_machines.dmi index 8ad69dae79e7..7406a94168a8 100644 Binary files a/icons/obj/machines/mining_machines.dmi and b/icons/obj/machines/mining_machines.dmi differ diff --git a/icons/obj/machines/paper_shredder.dmi b/icons/obj/machines/paper_shredder.dmi new file mode 100644 index 000000000000..44525ec50c8f Binary files /dev/null and b/icons/obj/machines/paper_shredder.dmi differ diff --git a/icons/obj/machines/photocopier.dmi b/icons/obj/machines/photocopier.dmi new file mode 100644 index 000000000000..971a77bea19a Binary files /dev/null and b/icons/obj/machines/photocopier.dmi differ diff --git a/icons/obj/machines/pod_doors.dmi b/icons/obj/machines/pod_doors.dmi new file mode 100644 index 000000000000..3b40ac65a8ef Binary files /dev/null and b/icons/obj/machines/pod_doors.dmi differ diff --git a/icons/obj/machines/power/fission.dmi b/icons/obj/machines/power/fission.dmi new file mode 100644 index 000000000000..709a79de095a Binary files /dev/null and b/icons/obj/machines/power/fission.dmi differ diff --git a/icons/obj/machines/power/fission_core.dmi b/icons/obj/machines/power/fission_core.dmi new file mode 100644 index 000000000000..709a79de095a Binary files /dev/null and b/icons/obj/machines/power/fission_core.dmi differ diff --git a/icons/obj/machines/power/geothermal.dmi b/icons/obj/machines/power/geothermal.dmi new file mode 100644 index 000000000000..b2b2570da9aa Binary files /dev/null and b/icons/obj/machines/power/geothermal.dmi differ diff --git a/icons/obj/machines/recycler.dmi b/icons/obj/machines/recycler.dmi new file mode 100644 index 000000000000..d1f3ca8715dc Binary files /dev/null and b/icons/obj/machines/recycler.dmi differ diff --git a/icons/obj/machines/self_destruct.dmi b/icons/obj/machines/self_destruct.dmi index 913108972ba7..f42ff9f45bbb 100644 Binary files a/icons/obj/machines/self_destruct.dmi and b/icons/obj/machines/self_destruct.dmi differ diff --git a/icons/obj/machines/self_destruct_storage.dmi b/icons/obj/machines/self_destruct_storage.dmi new file mode 100644 index 000000000000..9f19ee54ccec Binary files /dev/null and b/icons/obj/machines/self_destruct_storage.dmi differ diff --git a/icons/obj/machines/server.dmi b/icons/obj/machines/server.dmi index a061d403de17..439de48fe7f4 100644 Binary files a/icons/obj/machines/server.dmi and b/icons/obj/machines/server.dmi differ diff --git a/icons/obj/machines/shielding.dmi b/icons/obj/machines/shielding.dmi index 87e2dd93c27c..aedb0885cbd7 100644 Binary files a/icons/obj/machines/shielding.dmi and b/icons/obj/machines/shielding.dmi differ diff --git a/icons/obj/machines/smartfridges/contents_chem.dmi b/icons/obj/machines/smartfridges/contents_chem.dmi new file mode 100644 index 000000000000..652eb6a7a29e Binary files /dev/null and b/icons/obj/machines/smartfridges/contents_chem.dmi differ diff --git a/icons/obj/machines/smartfridges/contents_drink.dmi b/icons/obj/machines/smartfridges/contents_drink.dmi new file mode 100644 index 000000000000..cc6c36719b04 Binary files /dev/null and b/icons/obj/machines/smartfridges/contents_drink.dmi differ diff --git a/icons/obj/machines/smartfridges/contents_food.dmi b/icons/obj/machines/smartfridges/contents_food.dmi new file mode 100644 index 000000000000..34c205c5013d Binary files /dev/null and b/icons/obj/machines/smartfridges/contents_food.dmi differ diff --git a/icons/obj/machines/smartfridges/contents_plants.dmi b/icons/obj/machines/smartfridges/contents_plants.dmi new file mode 100644 index 000000000000..c51a11f5e925 Binary files /dev/null and b/icons/obj/machines/smartfridges/contents_plants.dmi differ diff --git a/icons/obj/machines/smartfridges/dark.dmi b/icons/obj/machines/smartfridges/dark.dmi new file mode 100644 index 000000000000..27eb86d54c76 Binary files /dev/null and b/icons/obj/machines/smartfridges/dark.dmi differ diff --git a/icons/obj/machines/smartfridges/drinks.dmi b/icons/obj/machines/smartfridges/drinks.dmi new file mode 100644 index 000000000000..474246171a21 Binary files /dev/null and b/icons/obj/machines/smartfridges/drinks.dmi differ diff --git a/icons/obj/machines/smartfridges/drying_oven.dmi b/icons/obj/machines/smartfridges/drying_oven.dmi new file mode 100644 index 000000000000..d5a59817b1e8 Binary files /dev/null and b/icons/obj/machines/smartfridges/drying_oven.dmi differ diff --git a/icons/obj/machines/smartfridges/food.dmi b/icons/obj/machines/smartfridges/food.dmi new file mode 100644 index 000000000000..0c690607da18 Binary files /dev/null and b/icons/obj/machines/smartfridges/food.dmi differ diff --git a/icons/obj/machines/smartfridges/science.dmi b/icons/obj/machines/smartfridges/science.dmi new file mode 100644 index 000000000000..091312e07f35 Binary files /dev/null and b/icons/obj/machines/smartfridges/science.dmi differ diff --git a/icons/obj/machines/stationmap.dmi b/icons/obj/machines/stationmap.dmi new file mode 100644 index 000000000000..f57bf08913e7 Binary files /dev/null and b/icons/obj/machines/stationmap.dmi differ diff --git a/icons/obj/machines/tcomms/aas.dmi b/icons/obj/machines/tcomms/aas.dmi index 2fb0cf8292b5..9f85eb3b87aa 100644 Binary files a/icons/obj/machines/tcomms/aas.dmi and b/icons/obj/machines/tcomms/aas.dmi differ diff --git a/icons/obj/machines/tcomms/blackbox.dmi b/icons/obj/machines/tcomms/blackbox.dmi index d59ba343d508..5e6f53199c6e 100644 Binary files a/icons/obj/machines/tcomms/blackbox.dmi and b/icons/obj/machines/tcomms/blackbox.dmi differ diff --git a/icons/obj/machines/tcomms/comms.dmi b/icons/obj/machines/tcomms/comms.dmi new file mode 100644 index 000000000000..c41f31bc7010 Binary files /dev/null and b/icons/obj/machines/tcomms/comms.dmi differ diff --git a/icons/obj/machines/teleporter.dmi b/icons/obj/machines/teleporter.dmi index 56d55a955bae..ceeaafd1e7d2 100644 Binary files a/icons/obj/machines/teleporter.dmi and b/icons/obj/machines/teleporter.dmi differ diff --git a/icons/obj/machines/tramdoors.dmi b/icons/obj/machines/tramdoors.dmi new file mode 100644 index 000000000000..3b40ac65a8ef Binary files /dev/null and b/icons/obj/machines/tramdoors.dmi differ diff --git a/icons/obj/machines/vending/bar.dmi b/icons/obj/machines/vending/bar.dmi new file mode 100644 index 000000000000..c670371c50fa Binary files /dev/null and b/icons/obj/machines/vending/bar.dmi differ diff --git a/icons/obj/machines/vending/cartridges.dmi b/icons/obj/machines/vending/cartridges.dmi new file mode 100644 index 000000000000..927d474e441b Binary files /dev/null and b/icons/obj/machines/vending/cartridges.dmi differ diff --git a/icons/obj/machines/vending/cigarettes.dmi b/icons/obj/machines/vending/cigarettes.dmi new file mode 100644 index 000000000000..83870f29f06b Binary files /dev/null and b/icons/obj/machines/vending/cigarettes.dmi differ diff --git a/icons/obj/machines/vending/coffee.dmi b/icons/obj/machines/vending/coffee.dmi new file mode 100644 index 000000000000..d4f22cabc6b7 Binary files /dev/null and b/icons/obj/machines/vending/coffee.dmi differ diff --git a/icons/obj/machines/vending/dinnerware.dmi b/icons/obj/machines/vending/dinnerware.dmi new file mode 100644 index 000000000000..297ee226b596 Binary files /dev/null and b/icons/obj/machines/vending/dinnerware.dmi differ diff --git a/icons/obj/machines/vending/drinks.dmi b/icons/obj/machines/vending/drinks.dmi new file mode 100644 index 000000000000..8e241137536f Binary files /dev/null and b/icons/obj/machines/vending/drinks.dmi differ diff --git a/icons/obj/machines/vending/engineering.dmi b/icons/obj/machines/vending/engineering.dmi new file mode 100644 index 000000000000..da8b3af7e50e Binary files /dev/null and b/icons/obj/machines/vending/engineering.dmi differ diff --git a/icons/obj/machines/vending/engivend.dmi b/icons/obj/machines/vending/engivend.dmi new file mode 100644 index 000000000000..6051e27ff1ad Binary files /dev/null and b/icons/obj/machines/vending/engivend.dmi differ diff --git a/icons/obj/machines/vending/fitness.dmi b/icons/obj/machines/vending/fitness.dmi new file mode 100644 index 000000000000..fbe9fd2a7a7e Binary files /dev/null and b/icons/obj/machines/vending/fitness.dmi differ diff --git a/icons/obj/machines/vending/games.dmi b/icons/obj/machines/vending/games.dmi new file mode 100644 index 000000000000..e472e9421a29 Binary files /dev/null and b/icons/obj/machines/vending/games.dmi differ diff --git a/icons/obj/machines/vending/generic.dmi b/icons/obj/machines/vending/generic.dmi new file mode 100644 index 000000000000..b7962898cd23 Binary files /dev/null and b/icons/obj/machines/vending/generic.dmi differ diff --git a/icons/obj/machines/vending/hotfood.dmi b/icons/obj/machines/vending/hotfood.dmi new file mode 100644 index 000000000000..d186fa5e3d19 Binary files /dev/null and b/icons/obj/machines/vending/hotfood.dmi differ diff --git a/icons/obj/machines/vending/laptops.dmi b/icons/obj/machines/vending/laptops.dmi new file mode 100644 index 000000000000..069ba5478835 Binary files /dev/null and b/icons/obj/machines/vending/laptops.dmi differ diff --git a/icons/obj/machines/vending/lavatory.dmi b/icons/obj/machines/vending/lavatory.dmi new file mode 100644 index 000000000000..83057f32eec8 Binary files /dev/null and b/icons/obj/machines/vending/lavatory.dmi differ diff --git a/icons/obj/machines/vending/magic.dmi b/icons/obj/machines/vending/magic.dmi new file mode 100644 index 000000000000..38a969fabe55 Binary files /dev/null and b/icons/obj/machines/vending/magic.dmi differ diff --git a/icons/obj/machines/vending/medical.dmi b/icons/obj/machines/vending/medical.dmi new file mode 100644 index 000000000000..8f03461e5e24 Binary files /dev/null and b/icons/obj/machines/vending/medical.dmi differ diff --git a/icons/obj/machines/vending/nutri_green.dmi b/icons/obj/machines/vending/nutri_green.dmi new file mode 100644 index 000000000000..4c514e4f2152 Binary files /dev/null and b/icons/obj/machines/vending/nutri_green.dmi differ diff --git a/icons/obj/machines/vending/nutri_grey.dmi b/icons/obj/machines/vending/nutri_grey.dmi new file mode 100644 index 000000000000..b403fb74b044 Binary files /dev/null and b/icons/obj/machines/vending/nutri_grey.dmi differ diff --git a/icons/obj/machines/vending/nutrimat.dmi b/icons/obj/machines/vending/nutrimat.dmi new file mode 100644 index 000000000000..382a47df06a0 Binary files /dev/null and b/icons/obj/machines/vending/nutrimat.dmi differ diff --git a/icons/obj/machines/vending/robotics.dmi b/icons/obj/machines/vending/robotics.dmi new file mode 100644 index 000000000000..43d48409ad1c Binary files /dev/null and b/icons/obj/machines/vending/robotics.dmi differ diff --git a/icons/obj/machines/vending/security.dmi b/icons/obj/machines/vending/security.dmi new file mode 100644 index 000000000000..f09df161b80b Binary files /dev/null and b/icons/obj/machines/vending/security.dmi differ diff --git a/icons/obj/machines/vending/seeds_green.dmi b/icons/obj/machines/vending/seeds_green.dmi new file mode 100644 index 000000000000..f3d730d74e17 Binary files /dev/null and b/icons/obj/machines/vending/seeds_green.dmi differ diff --git a/icons/obj/machines/vending/seeds_grey.dmi b/icons/obj/machines/vending/seeds_grey.dmi new file mode 100644 index 000000000000..c85ba5b81f8e Binary files /dev/null and b/icons/obj/machines/vending/seeds_grey.dmi differ diff --git a/icons/obj/machines/vending/snacks.dmi b/icons/obj/machines/vending/snacks.dmi new file mode 100644 index 000000000000..c5bb7ce78a07 Binary files /dev/null and b/icons/obj/machines/vending/snacks.dmi differ diff --git a/icons/obj/machines/vending/snix.dmi b/icons/obj/machines/vending/snix.dmi new file mode 100644 index 000000000000..9711d5a38ca6 Binary files /dev/null and b/icons/obj/machines/vending/snix.dmi differ diff --git a/icons/obj/machines/vending/soda.dmi b/icons/obj/machines/vending/soda.dmi new file mode 100644 index 000000000000..8b6277aa4838 Binary files /dev/null and b/icons/obj/machines/vending/soda.dmi differ diff --git a/icons/obj/machines/vending/solsnacks.dmi b/icons/obj/machines/vending/solsnacks.dmi new file mode 100644 index 000000000000..55498c1e585f Binary files /dev/null and b/icons/obj/machines/vending/solsnacks.dmi differ diff --git a/icons/obj/machines/vending/soviet.dmi b/icons/obj/machines/vending/soviet.dmi new file mode 100644 index 000000000000..a16f21e429d7 Binary files /dev/null and b/icons/obj/machines/vending/soviet.dmi differ diff --git a/icons/obj/machines/vending/theater.dmi b/icons/obj/machines/vending/theater.dmi new file mode 100644 index 000000000000..3108ae546b0a Binary files /dev/null and b/icons/obj/machines/vending/theater.dmi differ diff --git a/icons/obj/machines/vending/tool.dmi b/icons/obj/machines/vending/tool.dmi new file mode 100644 index 000000000000..97660e438538 Binary files /dev/null and b/icons/obj/machines/vending/tool.dmi differ diff --git a/icons/obj/machines/vending/tool_adh.dmi b/icons/obj/machines/vending/tool_adh.dmi new file mode 100644 index 000000000000..03f49f0d1dc4 Binary files /dev/null and b/icons/obj/machines/vending/tool_adh.dmi differ diff --git a/icons/obj/machines/vending/uniform.dmi b/icons/obj/machines/vending/uniform.dmi new file mode 100644 index 000000000000..10148b981215 Binary files /dev/null and b/icons/obj/machines/vending/uniform.dmi differ diff --git a/icons/obj/machines/vending/wallmed.dmi b/icons/obj/machines/vending/wallmed.dmi new file mode 100644 index 000000000000..792954c53a9c Binary files /dev/null and b/icons/obj/machines/vending/wallmed.dmi differ diff --git a/icons/obj/machines/vending/weeb.dmi b/icons/obj/machines/vending/weeb.dmi new file mode 100644 index 000000000000..62966c77b127 Binary files /dev/null and b/icons/obj/machines/vending/weeb.dmi differ diff --git a/icons/obj/machines/wall_router.dmi b/icons/obj/machines/wall_router.dmi new file mode 100644 index 000000000000..c0ca6c6062dd Binary files /dev/null and b/icons/obj/machines/wall_router.dmi differ diff --git a/icons/obj/materials.dmi b/icons/obj/materials.dmi deleted file mode 100644 index ae9b4833ca25..000000000000 Binary files a/icons/obj/materials.dmi and /dev/null differ diff --git a/icons/obj/materials/ore.dmi b/icons/obj/materials/ore.dmi index f96653e3c63a..b541a24e88a6 100644 Binary files a/icons/obj/materials/ore.dmi and b/icons/obj/materials/ore.dmi differ diff --git a/icons/obj/medical_kits.dmi b/icons/obj/medical_kits.dmi index 5e630a6faec5..a4574b4bd539 100644 Binary files a/icons/obj/medical_kits.dmi and b/icons/obj/medical_kits.dmi differ diff --git a/icons/obj/metalworking/crucible.dmi b/icons/obj/metalworking/crucible.dmi new file mode 100644 index 000000000000..24a1a466586b Binary files /dev/null and b/icons/obj/metalworking/crucible.dmi differ diff --git a/icons/obj/metalworking/melted_thing.dmi b/icons/obj/metalworking/melted_thing.dmi new file mode 100644 index 000000000000..c039083a4495 Binary files /dev/null and b/icons/obj/metalworking/melted_thing.dmi differ diff --git a/icons/obj/mine.dmi b/icons/obj/mine.dmi new file mode 100644 index 000000000000..1c28f5775952 Binary files /dev/null and b/icons/obj/mine.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi deleted file mode 100644 index 0bf325c1efba..000000000000 Binary files a/icons/obj/mining.dmi and /dev/null differ diff --git a/icons/obj/mining_drill.dmi b/icons/obj/mining_drill.dmi index 95aab5f5bea3..108c4a0a4a9d 100644 Binary files a/icons/obj/mining_drill.dmi and b/icons/obj/mining_drill.dmi differ diff --git a/icons/obj/mobile_ladder.dmi b/icons/obj/mobile_ladder.dmi new file mode 100644 index 000000000000..aae72263e207 Binary files /dev/null and b/icons/obj/mobile_ladder.dmi differ diff --git a/icons/obj/modular_computers/holo/basic.dmi b/icons/obj/modular_computers/holo/basic.dmi new file mode 100644 index 000000000000..1358f0bc56c2 Binary files /dev/null and b/icons/obj/modular_computers/holo/basic.dmi differ diff --git a/icons/obj/modular_computers/holo/curved.dmi b/icons/obj/modular_computers/holo/curved.dmi new file mode 100644 index 000000000000..a9245e76f5b4 Binary files /dev/null and b/icons/obj/modular_computers/holo/curved.dmi differ diff --git a/icons/obj/modular_computers/holo/round.dmi b/icons/obj/modular_computers/holo/round.dmi new file mode 100644 index 000000000000..5ba0ce05b68d Binary files /dev/null and b/icons/obj/modular_computers/holo/round.dmi differ diff --git a/icons/obj/modular_computers/holo/side.dmi b/icons/obj/modular_computers/holo/side.dmi new file mode 100644 index 000000000000..cf23ff1b22ca Binary files /dev/null and b/icons/obj/modular_computers/holo/side.dmi differ diff --git a/icons/obj/modular_computers/holo/wide.dmi b/icons/obj/modular_computers/holo/wide.dmi new file mode 100644 index 000000000000..3e9469cfe950 Binary files /dev/null and b/icons/obj/modular_computers/holo/wide.dmi differ diff --git a/icons/obj/modular_computers/modular_telescreen.dmi b/icons/obj/modular_computers/modular_telescreen.dmi index eee9853a93ce..2afc8f448dbd 100644 Binary files a/icons/obj/modular_computers/modular_telescreen.dmi and b/icons/obj/modular_computers/modular_telescreen.dmi differ diff --git a/icons/obj/modular_computers/pda/pda.dmi b/icons/obj/modular_computers/pda/pda.dmi index a38f23c00b66..5048f77abdb5 100644 Binary files a/icons/obj/modular_computers/pda/pda.dmi and b/icons/obj/modular_computers/pda/pda.dmi differ diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi deleted file mode 100644 index 80256fdcf0d7..000000000000 Binary files a/icons/obj/module.dmi and /dev/null differ diff --git a/icons/obj/modules/module_controller.dmi b/icons/obj/modules/module_controller.dmi new file mode 100644 index 000000000000..a901084f33a1 Binary files /dev/null and b/icons/obj/modules/module_controller.dmi differ diff --git a/icons/obj/modules/module_cyborg_0.dmi b/icons/obj/modules/module_cyborg_0.dmi new file mode 100644 index 000000000000..4b53beaf0e54 Binary files /dev/null and b/icons/obj/modules/module_cyborg_0.dmi differ diff --git a/icons/obj/modules/module_cyborg_1.dmi b/icons/obj/modules/module_cyborg_1.dmi new file mode 100644 index 000000000000..cf5626ef2a61 Binary files /dev/null and b/icons/obj/modules/module_cyborg_1.dmi differ diff --git a/icons/obj/modules/module_cyborg_2.dmi b/icons/obj/modules/module_cyborg_2.dmi new file mode 100644 index 000000000000..c918016e9ca6 Binary files /dev/null and b/icons/obj/modules/module_cyborg_2.dmi differ diff --git a/icons/obj/modules/module_cyborg_3.dmi b/icons/obj/modules/module_cyborg_3.dmi new file mode 100644 index 000000000000..85f9b108ecc6 Binary files /dev/null and b/icons/obj/modules/module_cyborg_3.dmi differ diff --git a/icons/obj/modules/module_id.dmi b/icons/obj/modules/module_id.dmi new file mode 100644 index 000000000000..f45440c73756 Binary files /dev/null and b/icons/obj/modules/module_id.dmi differ diff --git a/icons/obj/modules/module_mainboard.dmi b/icons/obj/modules/module_mainboard.dmi new file mode 100644 index 000000000000..2fcbddcc7860 Binary files /dev/null and b/icons/obj/modules/module_mainboard.dmi differ diff --git a/icons/obj/modules/module_power.dmi b/icons/obj/modules/module_power.dmi new file mode 100644 index 000000000000..8a6110eaa499 Binary files /dev/null and b/icons/obj/modules/module_power.dmi differ diff --git a/icons/obj/modules/module_standard.dmi b/icons/obj/modules/module_standard.dmi new file mode 100644 index 000000000000..b36dfd2d93ac Binary files /dev/null and b/icons/obj/modules/module_standard.dmi differ diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi index d6ea9f5b0044..1290256218ee 100644 Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ diff --git a/icons/obj/multiz_items.dmi b/icons/obj/multiz_items.dmi deleted file mode 100644 index 78ea532278f6..000000000000 Binary files a/icons/obj/multiz_items.dmi and /dev/null differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index f5f0fce278dd..ec7ad98c685e 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ diff --git a/icons/obj/overmap.dmi b/icons/obj/overmap.dmi index cb6878fc5ba4..3dae2aeb162d 100644 Binary files a/icons/obj/overmap.dmi and b/icons/obj/overmap.dmi differ diff --git a/icons/obj/photo_album.dmi b/icons/obj/photo_album.dmi new file mode 100644 index 000000000000..b2ce880323a4 Binary files /dev/null and b/icons/obj/photo_album.dmi differ diff --git a/icons/obj/photography.dmi b/icons/obj/photography.dmi index be0a01729077..ddfcfd7882eb 100644 Binary files a/icons/obj/photography.dmi and b/icons/obj/photography.dmi differ diff --git a/icons/obj/pill_pack.dmi b/icons/obj/pill_pack.dmi index 4b64869604ab..fb8f84c0a1db 100644 Binary files a/icons/obj/pill_pack.dmi and b/icons/obj/pill_pack.dmi differ diff --git a/icons/obj/pipe-item.dmi b/icons/obj/pipe-item.dmi index 8849029e1b18..e0b7b9bc44c8 100644 Binary files a/icons/obj/pipe-item.dmi and b/icons/obj/pipe-item.dmi differ diff --git a/icons/obj/pipes/disposal.dmi b/icons/obj/pipes/disposal.dmi deleted file mode 100644 index 4a3037b7de86..000000000000 Binary files a/icons/obj/pipes/disposal.dmi and /dev/null differ diff --git a/icons/obj/pipes/disposal_bin.dmi b/icons/obj/pipes/disposal_bin.dmi new file mode 100644 index 000000000000..4760d29f4a09 Binary files /dev/null and b/icons/obj/pipes/disposal_bin.dmi differ diff --git a/icons/obj/pipes/disposal_chute.dmi b/icons/obj/pipes/disposal_chute.dmi new file mode 100644 index 000000000000..277338f9bc98 Binary files /dev/null and b/icons/obj/pipes/disposal_chute.dmi differ diff --git a/icons/obj/pipes/disposal_outlet.dmi b/icons/obj/pipes/disposal_outlet.dmi new file mode 100644 index 000000000000..61c2ae36ae35 Binary files /dev/null and b/icons/obj/pipes/disposal_outlet.dmi differ diff --git a/icons/obj/pipes/disposal_pipe.dmi b/icons/obj/pipes/disposal_pipe.dmi new file mode 100644 index 000000000000..dc7dc38b5962 Binary files /dev/null and b/icons/obj/pipes/disposal_pipe.dmi differ diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi index 19801309cdf2..b6d63b9f09c0 100644 Binary files a/icons/obj/power.dmi and b/icons/obj/power.dmi differ diff --git a/icons/obj/power_cond_heavy.dmi b/icons/obj/power_cond_heavy.dmi new file mode 100644 index 000000000000..bfd4670bda48 Binary files /dev/null and b/icons/obj/power_cond_heavy.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 7edad62e3bda..042118ab8a49 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/quicksand.dmi b/icons/obj/quicksand.dmi index 2bea4ad6a04c..e21dd5154816 100644 Binary files a/icons/obj/quicksand.dmi and b/icons/obj/quicksand.dmi differ diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi deleted file mode 100644 index c06b3243d569..000000000000 Binary files a/icons/obj/reagentfillings.dmi and /dev/null differ diff --git a/icons/obj/robot_storage.dmi b/icons/obj/robot_storage.dmi index 5a996c01e7e7..004d0392b724 100644 Binary files a/icons/obj/robot_storage.dmi and b/icons/obj/robot_storage.dmi differ diff --git a/icons/obj/rubber_duck.dmi b/icons/obj/rubber_duck.dmi new file mode 100644 index 000000000000..3fdc0b9e2e1d Binary files /dev/null and b/icons/obj/rubber_duck.dmi differ diff --git a/icons/obj/seeds.dmi b/icons/obj/seeds.dmi deleted file mode 100644 index 9608eed1908d..000000000000 Binary files a/icons/obj/seeds.dmi and /dev/null differ diff --git a/icons/obj/seeds/seed_masks.dmi b/icons/obj/seeds/seed_masks.dmi new file mode 100644 index 000000000000..d24cfd30650c Binary files /dev/null and b/icons/obj/seeds/seed_masks.dmi differ diff --git a/icons/obj/seeds/seed_packets.dmi b/icons/obj/seeds/seed_packets.dmi new file mode 100644 index 000000000000..b328a84c699e Binary files /dev/null and b/icons/obj/seeds/seed_packets.dmi differ diff --git a/icons/obj/seeds/seed_raw.dmi b/icons/obj/seeds/seed_raw.dmi new file mode 100644 index 000000000000..ea65135f5429 Binary files /dev/null and b/icons/obj/seeds/seed_raw.dmi differ diff --git a/icons/obj/ship_engine.dmi b/icons/obj/ship_engine.dmi index 2140beba3d3f..c9a04602a96a 100644 Binary files a/icons/obj/ship_engine.dmi and b/icons/obj/ship_engine.dmi differ diff --git a/icons/obj/shunt_drive.dmi b/icons/obj/shunt_drive.dmi new file mode 100644 index 000000000000..42aa93a84a6c Binary files /dev/null and b/icons/obj/shunt_drive.dmi differ diff --git a/icons/obj/signs/bar.dmi b/icons/obj/signs/bar.dmi new file mode 100644 index 000000000000..ad440ba5b4a6 Binary files /dev/null and b/icons/obj/signs/bar.dmi differ diff --git a/icons/obj/signs/decks.dmi b/icons/obj/signs/decks.dmi new file mode 100644 index 000000000000..e624d02927c5 Binary files /dev/null and b/icons/obj/signs/decks.dmi differ diff --git a/icons/obj/signs/departments.dmi b/icons/obj/signs/departments.dmi new file mode 100644 index 000000000000..0b3bb48a4ed6 Binary files /dev/null and b/icons/obj/signs/departments.dmi differ diff --git a/icons/obj/signs/directions.dmi b/icons/obj/signs/directions.dmi new file mode 100644 index 000000000000..fb224e2799f1 Binary files /dev/null and b/icons/obj/signs/directions.dmi differ diff --git a/icons/obj/signs/flags.dmi b/icons/obj/signs/flags.dmi new file mode 100644 index 000000000000..e3af8b280d66 Binary files /dev/null and b/icons/obj/signs/flags.dmi differ diff --git a/icons/obj/signs/hangars.dmi b/icons/obj/signs/hangars.dmi new file mode 100644 index 000000000000..9d5c77f70df2 Binary files /dev/null and b/icons/obj/signs/hangars.dmi differ diff --git a/icons/obj/signs/levels.dmi b/icons/obj/signs/levels.dmi new file mode 100644 index 000000000000..46531830bd84 Binary files /dev/null and b/icons/obj/signs/levels.dmi differ diff --git a/icons/obj/signs/maps.dmi b/icons/obj/signs/maps.dmi new file mode 100644 index 000000000000..7dcf3157dff5 Binary files /dev/null and b/icons/obj/signs/maps.dmi differ diff --git a/icons/obj/signs/paintings.dmi b/icons/obj/signs/paintings.dmi new file mode 100644 index 000000000000..f548bb1ef6ad Binary files /dev/null and b/icons/obj/signs/paintings.dmi differ diff --git a/icons/obj/signs/plaques.dmi b/icons/obj/signs/plaques.dmi new file mode 100644 index 000000000000..c6163a0c5de3 Binary files /dev/null and b/icons/obj/signs/plaques.dmi differ diff --git a/icons/obj/signs/signs.dmi b/icons/obj/signs/signs.dmi new file mode 100644 index 000000000000..022fb48f4c75 Binary files /dev/null and b/icons/obj/signs/signs.dmi differ diff --git a/icons/obj/signs/warnings.dmi b/icons/obj/signs/warnings.dmi new file mode 100644 index 000000000000..c6952b814f07 Binary files /dev/null and b/icons/obj/signs/warnings.dmi differ diff --git a/icons/obj/singularity.dmi b/icons/obj/singularity.dmi index ce5d182b1383..46f18bc5e726 100644 Binary files a/icons/obj/singularity.dmi and b/icons/obj/singularity.dmi differ diff --git a/icons/obj/stairs.dmi b/icons/obj/stairs.dmi index b0c14147e5f4..d75c2c0aa4a1 100644 Binary files a/icons/obj/stairs.dmi and b/icons/obj/stairs.dmi differ diff --git a/icons/obj/stairs_64.dmi b/icons/obj/stairs_64.dmi new file mode 100644 index 000000000000..7b5d4b7c57eb Binary files /dev/null and b/icons/obj/stairs_64.dmi differ diff --git a/icons/obj/stickynotes.dmi b/icons/obj/stickynotes.dmi index dfcf3f578798..4a6be8feb3e4 100644 Binary files a/icons/obj/stickynotes.dmi and b/icons/obj/stickynotes.dmi differ diff --git a/icons/obj/stool.dmi b/icons/obj/stool.dmi new file mode 100644 index 000000000000..00ad7ebbc659 Binary files /dev/null and b/icons/obj/stool.dmi differ diff --git a/icons/obj/stool_rustic.dmi b/icons/obj/stool_rustic.dmi new file mode 100644 index 000000000000..b41e91edd15d Binary files /dev/null and b/icons/obj/stool_rustic.dmi differ diff --git a/icons/obj/structures/alembic.dmi b/icons/obj/structures/alembic.dmi new file mode 100644 index 000000000000..9baac5bf06ea Binary files /dev/null and b/icons/obj/structures/alembic.dmi differ diff --git a/icons/obj/structures/armor_stand.dmi b/icons/obj/structures/armor_stand.dmi new file mode 100644 index 000000000000..0431f7f626cc Binary files /dev/null and b/icons/obj/structures/armor_stand.dmi differ diff --git a/icons/obj/structures/banner_frame.dmi b/icons/obj/structures/banner_frame.dmi new file mode 100644 index 000000000000..7379e9201d2e Binary files /dev/null and b/icons/obj/structures/banner_frame.dmi differ diff --git a/icons/obj/structures/barrels/barrel.dmi b/icons/obj/structures/barrels/barrel.dmi new file mode 100644 index 000000000000..1fec40d535cb Binary files /dev/null and b/icons/obj/structures/barrels/barrel.dmi differ diff --git a/icons/obj/structures/barrels/cask.dmi b/icons/obj/structures/barrels/cask.dmi new file mode 100644 index 000000000000..a2eba5fa0d9b Binary files /dev/null and b/icons/obj/structures/barrels/cask.dmi differ diff --git a/icons/obj/structures/barrels/cask_rack.dmi b/icons/obj/structures/barrels/cask_rack.dmi new file mode 100644 index 000000000000..2ee0ca5985ba Binary files /dev/null and b/icons/obj/structures/barrels/cask_rack.dmi differ diff --git a/icons/obj/structures/barrels/cask_rack_large.dmi b/icons/obj/structures/barrels/cask_rack_large.dmi new file mode 100644 index 000000000000..e5929b56dd94 Binary files /dev/null and b/icons/obj/structures/barrels/cask_rack_large.dmi differ diff --git a/icons/obj/structures/basketball.dmi b/icons/obj/structures/basketball.dmi new file mode 100644 index 000000000000..625efebe12d2 Binary files /dev/null and b/icons/obj/structures/basketball.dmi differ diff --git a/icons/obj/structures/bedroll.dmi b/icons/obj/structures/bedroll.dmi new file mode 100644 index 000000000000..9363491681ae Binary files /dev/null and b/icons/obj/structures/bedroll.dmi differ diff --git a/icons/obj/structures/bedroll_rolled.dmi b/icons/obj/structures/bedroll_rolled.dmi new file mode 100644 index 000000000000..7670a2248456 Binary files /dev/null and b/icons/obj/structures/bedroll_rolled.dmi differ diff --git a/icons/obj/structures/benches.dmi b/icons/obj/structures/benches.dmi new file mode 100644 index 000000000000..80fda7a9a165 Binary files /dev/null and b/icons/obj/structures/benches.dmi differ diff --git a/icons/obj/structures/book_cart.dmi b/icons/obj/structures/book_cart.dmi new file mode 100644 index 000000000000..e42ebd4ced1f Binary files /dev/null and b/icons/obj/structures/book_cart.dmi differ diff --git a/icons/obj/structures/bookcase.dmi b/icons/obj/structures/bookcase.dmi new file mode 100644 index 000000000000..e232f90cb32b Binary files /dev/null and b/icons/obj/structures/bookcase.dmi differ diff --git a/icons/obj/structures/boulder.dmi b/icons/obj/structures/boulder.dmi new file mode 100644 index 000000000000..dc83a3022396 Binary files /dev/null and b/icons/obj/structures/boulder.dmi differ diff --git a/icons/obj/structures/butter_churn.dmi b/icons/obj/structures/butter_churn.dmi new file mode 100644 index 000000000000..7b76f4f392c0 Binary files /dev/null and b/icons/obj/structures/butter_churn.dmi differ diff --git a/icons/obj/structures/catwalks.dmi b/icons/obj/structures/catwalks.dmi index 20c5e1f4d98b..7b6ce604f73e 100644 Binary files a/icons/obj/structures/catwalks.dmi and b/icons/obj/structures/catwalks.dmi differ diff --git a/icons/obj/structures/charge_pylon.dmi b/icons/obj/structures/charge_pylon.dmi new file mode 100644 index 000000000000..fda6d23e06c6 Binary files /dev/null and b/icons/obj/structures/charge_pylon.dmi differ diff --git a/icons/obj/structures/cliffs.dmi b/icons/obj/structures/cliffs.dmi new file mode 100644 index 000000000000..4713360313f7 Binary files /dev/null and b/icons/obj/structures/cliffs.dmi differ diff --git a/icons/obj/structures/coatrack.dmi b/icons/obj/structures/coatrack.dmi index 5d19abaeee75..52c5dc784814 100644 Binary files a/icons/obj/structures/coatrack.dmi and b/icons/obj/structures/coatrack.dmi differ diff --git a/icons/obj/structures/compost.dmi b/icons/obj/structures/compost.dmi new file mode 100644 index 000000000000..af51bcfa179f Binary files /dev/null and b/icons/obj/structures/compost.dmi differ diff --git a/icons/obj/structures/construct.dmi b/icons/obj/structures/construct.dmi new file mode 100644 index 000000000000..c27dfad69de1 Binary files /dev/null and b/icons/obj/structures/construct.dmi differ diff --git a/icons/obj/structures/crematorium.dmi b/icons/obj/structures/crematorium.dmi index f0d7942535b7..ebc978316c10 100644 Binary files a/icons/obj/structures/crematorium.dmi and b/icons/obj/structures/crematorium.dmi differ diff --git a/icons/obj/structures/decorations/gargoyle.dmi b/icons/obj/structures/decorations/gargoyle.dmi new file mode 100644 index 000000000000..6c531002b26a Binary files /dev/null and b/icons/obj/structures/decorations/gargoyle.dmi differ diff --git a/icons/obj/structures/decorations/gargoyle_plinth.dmi b/icons/obj/structures/decorations/gargoyle_plinth.dmi new file mode 100644 index 000000000000..c151a7a68eec Binary files /dev/null and b/icons/obj/structures/decorations/gargoyle_plinth.dmi differ diff --git a/icons/obj/structures/decorations/gargoyle_standing.dmi b/icons/obj/structures/decorations/gargoyle_standing.dmi new file mode 100644 index 000000000000..669bbe8b0a5f Binary files /dev/null and b/icons/obj/structures/decorations/gargoyle_standing.dmi differ diff --git a/icons/obj/structures/desk_large.dmi b/icons/obj/structures/desk_large.dmi new file mode 100644 index 000000000000..0deadba24036 Binary files /dev/null and b/icons/obj/structures/desk_large.dmi differ diff --git a/icons/obj/structures/displaycase.dmi b/icons/obj/structures/displaycase.dmi index a6411b171ad3..828acda9127f 100644 Binary files a/icons/obj/structures/displaycase.dmi and b/icons/obj/structures/displaycase.dmi differ diff --git a/icons/obj/structures/divider.dmi b/icons/obj/structures/divider.dmi new file mode 100644 index 000000000000..85e10194b86f Binary files /dev/null and b/icons/obj/structures/divider.dmi differ diff --git a/icons/obj/structures/dresser.dmi b/icons/obj/structures/dresser.dmi new file mode 100644 index 000000000000..7b02142210a3 Binary files /dev/null and b/icons/obj/structures/dresser.dmi differ diff --git a/icons/obj/structures/emergency_dispenser.dmi b/icons/obj/structures/emergency_dispenser.dmi new file mode 100644 index 000000000000..f681cfb08636 Binary files /dev/null and b/icons/obj/structures/emergency_dispenser.dmi differ diff --git a/icons/obj/structures/endtable.dmi b/icons/obj/structures/endtable.dmi new file mode 100644 index 000000000000..037d1c770b77 Binary files /dev/null and b/icons/obj/structures/endtable.dmi differ diff --git a/icons/obj/structures/fence.dmi b/icons/obj/structures/fence.dmi new file mode 100644 index 000000000000..b3d997a940f8 Binary files /dev/null and b/icons/obj/structures/fence.dmi differ diff --git a/icons/obj/structures/filling_cabinets.dmi b/icons/obj/structures/filling_cabinets.dmi new file mode 100644 index 000000000000..4184bda6e327 Binary files /dev/null and b/icons/obj/structures/filling_cabinets.dmi differ diff --git a/icons/obj/structures/fire.dmi b/icons/obj/structures/fire.dmi new file mode 100644 index 000000000000..7a876470b11e Binary files /dev/null and b/icons/obj/structures/fire.dmi differ diff --git a/icons/obj/structures/forging/bellows.dmi b/icons/obj/structures/forging/bellows.dmi new file mode 100644 index 000000000000..9e6031422efe Binary files /dev/null and b/icons/obj/structures/forging/bellows.dmi differ diff --git a/icons/obj/structures/fuel_port.dmi b/icons/obj/structures/fuel_port.dmi new file mode 100644 index 000000000000..2928b94bb99c Binary files /dev/null and b/icons/obj/structures/fuel_port.dmi differ diff --git a/icons/obj/structures/furniture/armchair.dmi b/icons/obj/structures/furniture/armchair.dmi new file mode 100644 index 000000000000..aada0c0681d4 Binary files /dev/null and b/icons/obj/structures/furniture/armchair.dmi differ diff --git a/icons/obj/structures/furniture/bed.dmi b/icons/obj/structures/furniture/bed.dmi new file mode 100644 index 000000000000..f9d1d7dda970 Binary files /dev/null and b/icons/obj/structures/furniture/bed.dmi differ diff --git a/icons/obj/structures/furniture/bed_psych.dmi b/icons/obj/structures/furniture/bed_psych.dmi new file mode 100644 index 000000000000..57e6943f54df Binary files /dev/null and b/icons/obj/structures/furniture/bed_psych.dmi differ diff --git a/icons/obj/structures/furniture/bed_simple.dmi b/icons/obj/structures/furniture/bed_simple.dmi new file mode 100644 index 000000000000..4e5bf1701a9f Binary files /dev/null and b/icons/obj/structures/furniture/bed_simple.dmi differ diff --git a/icons/obj/structures/furniture/bench.dmi b/icons/obj/structures/furniture/bench.dmi new file mode 100644 index 000000000000..0bf99b3e3927 Binary files /dev/null and b/icons/obj/structures/furniture/bench.dmi differ diff --git a/icons/obj/structures/furniture/bench_wood.dmi b/icons/obj/structures/furniture/bench_wood.dmi new file mode 100644 index 000000000000..bf8129ccb007 Binary files /dev/null and b/icons/obj/structures/furniture/bench_wood.dmi differ diff --git a/icons/obj/structures/furniture/cabinet_duo.dmi b/icons/obj/structures/furniture/cabinet_duo.dmi new file mode 100644 index 000000000000..adc99dcb2055 Binary files /dev/null and b/icons/obj/structures/furniture/cabinet_duo.dmi differ diff --git a/icons/obj/structures/furniture/chair.dmi b/icons/obj/structures/furniture/chair.dmi new file mode 100644 index 000000000000..dbd8dd3a62ee Binary files /dev/null and b/icons/obj/structures/furniture/chair.dmi differ diff --git a/icons/obj/structures/furniture/chair_backed.dmi b/icons/obj/structures/furniture/chair_backed.dmi new file mode 100644 index 000000000000..66eb3ecea7e2 Binary files /dev/null and b/icons/obj/structures/furniture/chair_backed.dmi differ diff --git a/icons/obj/structures/furniture/chair_backed_wood.dmi b/icons/obj/structures/furniture/chair_backed_wood.dmi new file mode 100644 index 000000000000..5eae485abf77 Binary files /dev/null and b/icons/obj/structures/furniture/chair_backed_wood.dmi differ diff --git a/icons/obj/structures/furniture/chair_captain.dmi b/icons/obj/structures/furniture/chair_captain.dmi new file mode 100644 index 000000000000..56287d4ec894 Binary files /dev/null and b/icons/obj/structures/furniture/chair_captain.dmi differ diff --git a/icons/obj/structures/furniture/chair_comfy.dmi b/icons/obj/structures/furniture/chair_comfy.dmi new file mode 100644 index 000000000000..4a3a63ca12e3 Binary files /dev/null and b/icons/obj/structures/furniture/chair_comfy.dmi differ diff --git a/icons/obj/structures/furniture/chair_comfy_office.dmi b/icons/obj/structures/furniture/chair_comfy_office.dmi new file mode 100644 index 000000000000..780dea823e60 Binary files /dev/null and b/icons/obj/structures/furniture/chair_comfy_office.dmi differ diff --git a/icons/obj/structures/furniture/chair_office.dmi b/icons/obj/structures/furniture/chair_office.dmi new file mode 100644 index 000000000000..6c1bbcf54a44 Binary files /dev/null and b/icons/obj/structures/furniture/chair_office.dmi differ diff --git a/icons/obj/structures/furniture/chair_rounded.dmi b/icons/obj/structures/furniture/chair_rounded.dmi new file mode 100644 index 000000000000..6ab3ce4b0dad Binary files /dev/null and b/icons/obj/structures/furniture/chair_rounded.dmi differ diff --git a/icons/obj/structures/furniture/chair_rustic.dmi b/icons/obj/structures/furniture/chair_rustic.dmi new file mode 100644 index 000000000000..e94faecc2090 Binary files /dev/null and b/icons/obj/structures/furniture/chair_rustic.dmi differ diff --git a/icons/obj/structures/furniture/chair_rustic_fancy.dmi b/icons/obj/structures/furniture/chair_rustic_fancy.dmi new file mode 100644 index 000000000000..5191fc5d4b4e Binary files /dev/null and b/icons/obj/structures/furniture/chair_rustic_fancy.dmi differ diff --git a/icons/obj/structures/furniture/chair_shuttle.dmi b/icons/obj/structures/furniture/chair_shuttle.dmi new file mode 100644 index 000000000000..6031f7edd6da Binary files /dev/null and b/icons/obj/structures/furniture/chair_shuttle.dmi differ diff --git a/icons/obj/structures/furniture/chair_slatted.dmi b/icons/obj/structures/furniture/chair_slatted.dmi new file mode 100644 index 000000000000..d05d846ed2e1 Binary files /dev/null and b/icons/obj/structures/furniture/chair_slatted.dmi differ diff --git a/icons/obj/structures/furniture/chair_slatted_wood.dmi b/icons/obj/structures/furniture/chair_slatted_wood.dmi new file mode 100644 index 000000000000..640d8da1db96 Binary files /dev/null and b/icons/obj/structures/furniture/chair_slatted_wood.dmi differ diff --git a/icons/obj/structures/furniture/chair_wooden.dmi b/icons/obj/structures/furniture/chair_wooden.dmi new file mode 100644 index 000000000000..3d77d82ebb83 Binary files /dev/null and b/icons/obj/structures/furniture/chair_wooden.dmi differ diff --git a/icons/obj/structures/furniture/chair_wooden_wings.dmi b/icons/obj/structures/furniture/chair_wooden_wings.dmi new file mode 100644 index 000000000000..928512cfc8fe Binary files /dev/null and b/icons/obj/structures/furniture/chair_wooden_wings.dmi differ diff --git a/icons/obj/structures/furniture/lounge.dmi b/icons/obj/structures/furniture/lounge.dmi new file mode 100644 index 000000000000..f377c4d7421b Binary files /dev/null and b/icons/obj/structures/furniture/lounge.dmi differ diff --git a/icons/obj/structures/furniture/pew.dmi b/icons/obj/structures/furniture/pew.dmi new file mode 100644 index 000000000000..5f19d36b2466 Binary files /dev/null and b/icons/obj/structures/furniture/pew.dmi differ diff --git a/icons/obj/structures/furniture/pew_wood.dmi b/icons/obj/structures/furniture/pew_wood.dmi new file mode 100644 index 000000000000..7084548224ba Binary files /dev/null and b/icons/obj/structures/furniture/pew_wood.dmi differ diff --git a/icons/obj/structures/furniture/sofa_left.dmi b/icons/obj/structures/furniture/sofa_left.dmi new file mode 100644 index 000000000000..d64661b633ad Binary files /dev/null and b/icons/obj/structures/furniture/sofa_left.dmi differ diff --git a/icons/obj/structures/furniture/sofa_middle.dmi b/icons/obj/structures/furniture/sofa_middle.dmi new file mode 100644 index 000000000000..67794edf8386 Binary files /dev/null and b/icons/obj/structures/furniture/sofa_middle.dmi differ diff --git a/icons/obj/structures/furniture/sofa_right.dmi b/icons/obj/structures/furniture/sofa_right.dmi new file mode 100644 index 000000000000..82f801624ba8 Binary files /dev/null and b/icons/obj/structures/furniture/sofa_right.dmi differ diff --git a/icons/obj/structures/furniture/wheelchair.dmi b/icons/obj/structures/furniture/wheelchair.dmi new file mode 100644 index 000000000000..e4e13d08e606 Binary files /dev/null and b/icons/obj/structures/furniture/wheelchair.dmi differ diff --git a/icons/obj/structures/grandfather_clock.dmi b/icons/obj/structures/grandfather_clock.dmi new file mode 100644 index 000000000000..cbef65c5ac44 Binary files /dev/null and b/icons/obj/structures/grandfather_clock.dmi differ diff --git a/icons/obj/structures/gravestone.dmi b/icons/obj/structures/gravestone.dmi index 3d4138edca1e..67add43938a2 100644 Binary files a/icons/obj/structures/gravestone.dmi and b/icons/obj/structures/gravestone.dmi differ diff --git a/icons/obj/structures/handcart.dmi b/icons/obj/structures/handcart.dmi new file mode 100644 index 000000000000..900089db3ab8 Binary files /dev/null and b/icons/obj/structures/handcart.dmi differ diff --git a/icons/obj/structures/haybale.dmi b/icons/obj/structures/haybale.dmi new file mode 100644 index 000000000000..822e36790b39 Binary files /dev/null and b/icons/obj/structures/haybale.dmi differ diff --git a/icons/obj/structures/haystack.dmi b/icons/obj/structures/haystack.dmi new file mode 100644 index 000000000000..fb663b7285f8 Binary files /dev/null and b/icons/obj/structures/haystack.dmi differ diff --git a/icons/obj/structures/hivebot_props.dmi b/icons/obj/structures/hivebot_props.dmi new file mode 100644 index 000000000000..9f5a34e327f6 Binary files /dev/null and b/icons/obj/structures/hivebot_props.dmi differ diff --git a/icons/obj/structures/iv_drip.dmi b/icons/obj/structures/iv_drip.dmi index b4c3704e98de..e568bb4eac1b 100644 Binary files a/icons/obj/structures/iv_drip.dmi and b/icons/obj/structures/iv_drip.dmi differ diff --git a/icons/obj/structures/kiln.dmi b/icons/obj/structures/kiln.dmi new file mode 100644 index 000000000000..82afd4f2327d Binary files /dev/null and b/icons/obj/structures/kiln.dmi differ diff --git a/icons/obj/structures/log_wall_frame.dmi b/icons/obj/structures/log_wall_frame.dmi new file mode 100644 index 000000000000..1fdbdb105367 Binary files /dev/null and b/icons/obj/structures/log_wall_frame.dmi differ diff --git a/icons/obj/structures/loom.dmi b/icons/obj/structures/loom.dmi new file mode 100644 index 000000000000..bb0c2ba5b19b Binary files /dev/null and b/icons/obj/structures/loom.dmi differ diff --git a/icons/obj/structures/memorial.dmi b/icons/obj/structures/memorial.dmi new file mode 100644 index 000000000000..07e03947c795 Binary files /dev/null and b/icons/obj/structures/memorial.dmi differ diff --git a/icons/obj/structures/mineral_bath.dmi b/icons/obj/structures/mineral_bath.dmi new file mode 100644 index 000000000000..294b1bb4f772 Binary files /dev/null and b/icons/obj/structures/mineral_bath.dmi differ diff --git a/icons/obj/structures/morgue.dmi b/icons/obj/structures/morgue.dmi index d350af0d9fa3..b91eb2af3a51 100644 Binary files a/icons/obj/structures/morgue.dmi and b/icons/obj/structures/morgue.dmi differ diff --git a/icons/obj/structures/network_cable.dmi b/icons/obj/structures/network_cable.dmi new file mode 100644 index 000000000000..5ffa7e1b50b9 Binary files /dev/null and b/icons/obj/structures/network_cable.dmi differ diff --git a/icons/obj/structures/noticeboard.dmi b/icons/obj/structures/noticeboard.dmi index 2c9923396d24..49aa9f441533 100644 Binary files a/icons/obj/structures/noticeboard.dmi and b/icons/obj/structures/noticeboard.dmi differ diff --git a/icons/obj/structures/ore_box.dmi b/icons/obj/structures/ore_box.dmi new file mode 100644 index 000000000000..c9eea92cfd2d Binary files /dev/null and b/icons/obj/structures/ore_box.dmi differ diff --git a/icons/obj/structures/pedestals/pedestal_narrow.dmi b/icons/obj/structures/pedestals/pedestal_narrow.dmi new file mode 100644 index 000000000000..ad4031b76764 Binary files /dev/null and b/icons/obj/structures/pedestals/pedestal_narrow.dmi differ diff --git a/icons/obj/structures/pedestals/pedestal_round.dmi b/icons/obj/structures/pedestals/pedestal_round.dmi new file mode 100644 index 000000000000..687c817c7157 Binary files /dev/null and b/icons/obj/structures/pedestals/pedestal_round.dmi differ diff --git a/icons/obj/structures/pedestals/pedestal_square.dmi b/icons/obj/structures/pedestals/pedestal_square.dmi new file mode 100644 index 000000000000..26d3e191eedd Binary files /dev/null and b/icons/obj/structures/pedestals/pedestal_square.dmi differ diff --git a/icons/obj/structures/pedestals/pedestal_triad.dmi b/icons/obj/structures/pedestals/pedestal_triad.dmi new file mode 100644 index 000000000000..3b8605d5744e Binary files /dev/null and b/icons/obj/structures/pedestals/pedestal_triad.dmi differ diff --git a/icons/obj/structures/pillars/pillar_narrow.dmi b/icons/obj/structures/pillars/pillar_narrow.dmi new file mode 100644 index 000000000000..86118e1cf126 Binary files /dev/null and b/icons/obj/structures/pillars/pillar_narrow.dmi differ diff --git a/icons/obj/structures/pillars/pillar_round.dmi b/icons/obj/structures/pillars/pillar_round.dmi new file mode 100644 index 000000000000..690178898a5e Binary files /dev/null and b/icons/obj/structures/pillars/pillar_round.dmi differ diff --git a/icons/obj/structures/pillars/pillar_square.dmi b/icons/obj/structures/pillars/pillar_square.dmi new file mode 100644 index 000000000000..2961a9ff092c Binary files /dev/null and b/icons/obj/structures/pillars/pillar_square.dmi differ diff --git a/icons/obj/structures/pillars/pillar_triad.dmi b/icons/obj/structures/pillars/pillar_triad.dmi new file mode 100644 index 000000000000..af3575b5df1c Binary files /dev/null and b/icons/obj/structures/pillars/pillar_triad.dmi differ diff --git a/icons/obj/structures/pillars/pillar_wide_inset.dmi b/icons/obj/structures/pillars/pillar_wide_inset.dmi new file mode 100644 index 000000000000..8f307cd2eb0b Binary files /dev/null and b/icons/obj/structures/pillars/pillar_wide_inset.dmi differ diff --git a/icons/obj/structures/pillars/pillar_wide_round.dmi b/icons/obj/structures/pillars/pillar_wide_round.dmi new file mode 100644 index 000000000000..c0625980dd87 Binary files /dev/null and b/icons/obj/structures/pillars/pillar_wide_round.dmi differ diff --git a/icons/obj/structures/pillars/pillar_wide_square.dmi b/icons/obj/structures/pillars/pillar_wide_square.dmi new file mode 100644 index 000000000000..a5ea0d80445b Binary files /dev/null and b/icons/obj/structures/pillars/pillar_wide_square.dmi differ diff --git a/icons/obj/structures/pit.dmi b/icons/obj/structures/pit.dmi index 76ac50d185a8..dcd845908e0c 100644 Binary files a/icons/obj/structures/pit.dmi and b/icons/obj/structures/pit.dmi differ diff --git a/icons/obj/structures/plastic_flaps.dmi b/icons/obj/structures/plastic_flaps.dmi index e3334f740fa5..16fd0740bd13 100644 Binary files a/icons/obj/structures/plastic_flaps.dmi and b/icons/obj/structures/plastic_flaps.dmi differ diff --git a/icons/obj/structures/plushie.dmi b/icons/obj/structures/plushie.dmi new file mode 100644 index 000000000000..9192b65fb1ea Binary files /dev/null and b/icons/obj/structures/plushie.dmi differ diff --git a/icons/obj/structures/produce_bin.dmi b/icons/obj/structures/produce_bin.dmi new file mode 100644 index 000000000000..4c579da189dd Binary files /dev/null and b/icons/obj/structures/produce_bin.dmi differ diff --git a/icons/obj/structures/quern.dmi b/icons/obj/structures/quern.dmi new file mode 100644 index 000000000000..5867670c10e5 Binary files /dev/null and b/icons/obj/structures/quern.dmi differ diff --git a/icons/obj/structures/rack.dmi b/icons/obj/structures/rack.dmi new file mode 100644 index 000000000000..1fe83605b84e Binary files /dev/null and b/icons/obj/structures/rack.dmi differ diff --git a/icons/obj/structures/railing.dmi b/icons/obj/structures/railing.dmi index a31e3beba700..6d20f7601251 100644 Binary files a/icons/obj/structures/railing.dmi and b/icons/obj/structures/railing.dmi differ diff --git a/icons/obj/structures/reeds.dmi b/icons/obj/structures/reeds.dmi new file mode 100644 index 000000000000..4288e0eb4af4 Binary files /dev/null and b/icons/obj/structures/reeds.dmi differ diff --git a/icons/obj/structures/rollerbed.dmi b/icons/obj/structures/rollerbed.dmi index 40074fde90db..37368e4ab391 100644 Binary files a/icons/obj/structures/rollerbed.dmi and b/icons/obj/structures/rollerbed.dmi differ diff --git a/icons/obj/structures/rubble.dmi b/icons/obj/structures/rubble.dmi index 0f9cc1cf78e9..4b3e7f68040f 100644 Binary files a/icons/obj/structures/rubble.dmi and b/icons/obj/structures/rubble.dmi differ diff --git a/icons/obj/structures/rug.dmi b/icons/obj/structures/rug.dmi new file mode 100644 index 000000000000..ab64dd8fba6a Binary files /dev/null and b/icons/obj/structures/rug.dmi differ diff --git a/icons/obj/structures/salvage.dmi b/icons/obj/structures/salvage.dmi new file mode 100644 index 000000000000..ea2004324aa3 Binary files /dev/null and b/icons/obj/structures/salvage.dmi differ diff --git a/icons/obj/structures/shuttle_engine.dmi b/icons/obj/structures/shuttle_engine.dmi new file mode 100644 index 000000000000..9a8cdff45170 Binary files /dev/null and b/icons/obj/structures/shuttle_engine.dmi differ diff --git a/icons/obj/structures/sieve.dmi b/icons/obj/structures/sieve.dmi new file mode 100644 index 000000000000..358099ec5b3a Binary files /dev/null and b/icons/obj/structures/sieve.dmi differ diff --git a/icons/obj/structures/sign_post.dmi b/icons/obj/structures/sign_post.dmi new file mode 100644 index 000000000000..c6c3ab25d473 Binary files /dev/null and b/icons/obj/structures/sign_post.dmi differ diff --git a/icons/obj/structures/snowmen/snowbot.dmi b/icons/obj/structures/snowmen/snowbot.dmi new file mode 100644 index 000000000000..c209cf5e8687 Binary files /dev/null and b/icons/obj/structures/snowmen/snowbot.dmi differ diff --git a/icons/obj/structures/snowmen/snowman.dmi b/icons/obj/structures/snowmen/snowman.dmi new file mode 100644 index 000000000000..c174da4bb4d0 Binary files /dev/null and b/icons/obj/structures/snowmen/snowman.dmi differ diff --git a/icons/obj/structures/snowmen/snowspider.dmi b/icons/obj/structures/snowmen/snowspider.dmi new file mode 100644 index 000000000000..bc7af6f5b8cf Binary files /dev/null and b/icons/obj/structures/snowmen/snowspider.dmi differ diff --git a/icons/obj/structures/spinning_wheel.dmi b/icons/obj/structures/spinning_wheel.dmi new file mode 100644 index 000000000000..c9db9d1761f5 Binary files /dev/null and b/icons/obj/structures/spinning_wheel.dmi differ diff --git a/icons/obj/structures/tables.dmi b/icons/obj/structures/tables.dmi index 8f7b9bfd5d4b..7df9bb98fddf 100644 Binary files a/icons/obj/structures/tables.dmi and b/icons/obj/structures/tables.dmi differ diff --git a/icons/obj/structures/target_stakes/archery_butt.dmi b/icons/obj/structures/target_stakes/archery_butt.dmi new file mode 100644 index 000000000000..b2e7253cf4bd Binary files /dev/null and b/icons/obj/structures/target_stakes/archery_butt.dmi differ diff --git a/icons/obj/structures/target_stakes/target_stake.dmi b/icons/obj/structures/target_stakes/target_stake.dmi new file mode 100644 index 000000000000..7423233493f0 Binary files /dev/null and b/icons/obj/structures/target_stakes/target_stake.dmi differ diff --git a/icons/obj/structures/town_bell.dmi b/icons/obj/structures/town_bell.dmi new file mode 100644 index 000000000000..e1bc0fd54cad Binary files /dev/null and b/icons/obj/structures/town_bell.dmi differ diff --git a/icons/obj/structures/travois.dmi b/icons/obj/structures/travois.dmi new file mode 100644 index 000000000000..8d1fc7bdea19 Binary files /dev/null and b/icons/obj/structures/travois.dmi differ diff --git a/icons/obj/structures/twisting_bench.dmi b/icons/obj/structures/twisting_bench.dmi new file mode 100644 index 000000000000..ab17aad1f3d9 Binary files /dev/null and b/icons/obj/structures/twisting_bench.dmi differ diff --git a/icons/obj/structures/volleyball.dmi b/icons/obj/structures/volleyball.dmi new file mode 100644 index 000000000000..269f60a1926c Binary files /dev/null and b/icons/obj/structures/volleyball.dmi differ diff --git a/icons/obj/structures/wall_fountain.dmi b/icons/obj/structures/wall_fountain.dmi new file mode 100644 index 000000000000..1a562faf73cc Binary files /dev/null and b/icons/obj/structures/wall_fountain.dmi differ diff --git a/icons/obj/structures/wall_frame.dmi b/icons/obj/structures/wall_frame.dmi index 7306cf8cddb3..afedf172ec04 100644 Binary files a/icons/obj/structures/wall_frame.dmi and b/icons/obj/structures/wall_frame.dmi differ diff --git a/icons/obj/structures/wall_sconce.dmi b/icons/obj/structures/wall_sconce.dmi new file mode 100644 index 000000000000..b7ac3ef48ce7 Binary files /dev/null and b/icons/obj/structures/wall_sconce.dmi differ diff --git a/icons/obj/structures/water_cooler.dmi b/icons/obj/structures/water_cooler.dmi new file mode 100644 index 000000000000..47660e5d627e Binary files /dev/null and b/icons/obj/structures/water_cooler.dmi differ diff --git a/icons/obj/structures/water_tank_high.dmi b/icons/obj/structures/water_tank_high.dmi new file mode 100644 index 000000000000..4f4fff5ac55a Binary files /dev/null and b/icons/obj/structures/water_tank_high.dmi differ diff --git a/icons/obj/structures/well.dmi b/icons/obj/structures/well.dmi new file mode 100644 index 000000000000..9a6402de8265 Binary files /dev/null and b/icons/obj/structures/well.dmi differ diff --git a/icons/obj/supermatter_32.dmi b/icons/obj/supermatter_32.dmi new file mode 100644 index 000000000000..f79c80edb191 Binary files /dev/null and b/icons/obj/supermatter_32.dmi differ diff --git a/icons/obj/supermatter_48.dmi b/icons/obj/supermatter_48.dmi new file mode 100644 index 000000000000..806206fe90d3 Binary files /dev/null and b/icons/obj/supermatter_48.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 362fa42aa3e8..7f87fea987f6 100644 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi index dfcccbd5de14..18428a668c83 100644 Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ diff --git a/icons/obj/syringe_advanced.dmi b/icons/obj/syringe_advanced.dmi new file mode 100644 index 000000000000..e0d9a221e906 Binary files /dev/null and b/icons/obj/syringe_advanced.dmi differ diff --git a/icons/obj/syringe_cryo.dmi b/icons/obj/syringe_cryo.dmi new file mode 100644 index 000000000000..10d3697cca8c Binary files /dev/null and b/icons/obj/syringe_cryo.dmi differ diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi deleted file mode 100644 index 79979f16e43c..000000000000 Binary files a/icons/obj/tank.dmi and /dev/null differ diff --git a/icons/obj/terminals.dmi b/icons/obj/terminals.dmi index 1afdc104b41e..c66b76ce64ce 100644 Binary files a/icons/obj/terminals.dmi and b/icons/obj/terminals.dmi differ diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi index 9bf9fe948dca..d7244e869b65 100644 Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ diff --git a/icons/obj/toiletpaper.dmi b/icons/obj/toiletpaper.dmi new file mode 100644 index 000000000000..2ccb7679060a Binary files /dev/null and b/icons/obj/toiletpaper.dmi differ diff --git a/icons/obj/toy.dmi b/icons/obj/toy.dmi index 52262d07cdf8..b8b8d5b867cc 100644 Binary files a/icons/obj/toy.dmi and b/icons/obj/toy.dmi differ diff --git a/icons/obj/toy/plush_carp.dmi b/icons/obj/toy/plush_carp.dmi new file mode 100644 index 000000000000..7a376d693fc5 Binary files /dev/null and b/icons/obj/toy/plush_carp.dmi differ diff --git a/icons/obj/toy/plush_carp_candy.dmi b/icons/obj/toy/plush_carp_candy.dmi new file mode 100644 index 000000000000..08237389ebfd Binary files /dev/null and b/icons/obj/toy/plush_carp_candy.dmi differ diff --git a/icons/obj/toy/plush_carp_dragon.dmi b/icons/obj/toy/plush_carp_dragon.dmi new file mode 100644 index 000000000000..8ca5a4cde042 Binary files /dev/null and b/icons/obj/toy/plush_carp_dragon.dmi differ diff --git a/icons/obj/toy/plush_carp_electric.dmi b/icons/obj/toy/plush_carp_electric.dmi new file mode 100644 index 000000000000..30c82ff71053 Binary files /dev/null and b/icons/obj/toy/plush_carp_electric.dmi differ diff --git a/icons/obj/toy/plush_carp_gold.dmi b/icons/obj/toy/plush_carp_gold.dmi new file mode 100644 index 000000000000..5846cd6c7fa6 Binary files /dev/null and b/icons/obj/toy/plush_carp_gold.dmi differ diff --git a/icons/obj/toy/plush_carp_ice.dmi b/icons/obj/toy/plush_carp_ice.dmi new file mode 100644 index 000000000000..e3c418e69e5b Binary files /dev/null and b/icons/obj/toy/plush_carp_ice.dmi differ diff --git a/icons/obj/toy/plush_carp_nebula.dmi b/icons/obj/toy/plush_carp_nebula.dmi new file mode 100644 index 000000000000..e2dff9520355 Binary files /dev/null and b/icons/obj/toy/plush_carp_nebula.dmi differ diff --git a/icons/obj/toy/plush_carp_pink.dmi b/icons/obj/toy/plush_carp_pink.dmi new file mode 100644 index 000000000000..612e6a0defb4 Binary files /dev/null and b/icons/obj/toy/plush_carp_pink.dmi differ diff --git a/icons/obj/toy/plush_carp_silent.dmi b/icons/obj/toy/plush_carp_silent.dmi new file mode 100644 index 000000000000..7ab6ddd5e43d Binary files /dev/null and b/icons/obj/toy/plush_carp_silent.dmi differ diff --git a/icons/obj/toy/plush_carp_toxic.dmi b/icons/obj/toy/plush_carp_toxic.dmi new file mode 100644 index 000000000000..2ad44032f44e Binary files /dev/null and b/icons/obj/toy/plush_carp_toxic.dmi differ diff --git a/icons/obj/toy/plush_carp_void.dmi b/icons/obj/toy/plush_carp_void.dmi new file mode 100644 index 000000000000..2ebba84d5473 Binary files /dev/null and b/icons/obj/toy/plush_carp_void.dmi differ diff --git a/icons/obj/toy/plush_cat.dmi b/icons/obj/toy/plush_cat.dmi new file mode 100644 index 000000000000..7505feaa120f Binary files /dev/null and b/icons/obj/toy/plush_cat.dmi differ diff --git a/icons/obj/toy/plush_cat_grey.dmi b/icons/obj/toy/plush_cat_grey.dmi new file mode 100644 index 000000000000..8f14f94ca5e0 Binary files /dev/null and b/icons/obj/toy/plush_cat_grey.dmi differ diff --git a/icons/obj/toy/plush_cat_orange.dmi b/icons/obj/toy/plush_cat_orange.dmi new file mode 100644 index 000000000000..e653e0c7fa17 Binary files /dev/null and b/icons/obj/toy/plush_cat_orange.dmi differ diff --git a/icons/obj/toy/plush_cat_siamese.dmi b/icons/obj/toy/plush_cat_siamese.dmi new file mode 100644 index 000000000000..3b3c89465efd Binary files /dev/null and b/icons/obj/toy/plush_cat_siamese.dmi differ diff --git a/icons/obj/toy/plush_cat_tabby.dmi b/icons/obj/toy/plush_cat_tabby.dmi new file mode 100644 index 000000000000..672e21482b9f Binary files /dev/null and b/icons/obj/toy/plush_cat_tabby.dmi differ diff --git a/icons/obj/toy/plush_cat_tuxedo.dmi b/icons/obj/toy/plush_cat_tuxedo.dmi new file mode 100644 index 000000000000..d9efea531c39 Binary files /dev/null and b/icons/obj/toy/plush_cat_tuxedo.dmi differ diff --git a/icons/obj/toy/plush_cat_white.dmi b/icons/obj/toy/plush_cat_white.dmi new file mode 100644 index 000000000000..0bb975e66627 Binary files /dev/null and b/icons/obj/toy/plush_cat_white.dmi differ diff --git a/icons/obj/toy/plush_corgi.dmi b/icons/obj/toy/plush_corgi.dmi new file mode 100644 index 000000000000..888072268f7c Binary files /dev/null and b/icons/obj/toy/plush_corgi.dmi differ diff --git a/icons/obj/toy/plush_corgi_ribbon.dmi b/icons/obj/toy/plush_corgi_ribbon.dmi new file mode 100644 index 000000000000..4be7c6685fb9 Binary files /dev/null and b/icons/obj/toy/plush_corgi_ribbon.dmi differ diff --git a/icons/obj/toy/plush_corgi_robot.dmi b/icons/obj/toy/plush_corgi_robot.dmi new file mode 100644 index 000000000000..3ac9a82ac9db Binary files /dev/null and b/icons/obj/toy/plush_corgi_robot.dmi differ diff --git a/icons/obj/toy/plush_deer.dmi b/icons/obj/toy/plush_deer.dmi new file mode 100644 index 000000000000..70a784bb3182 Binary files /dev/null and b/icons/obj/toy/plush_deer.dmi differ diff --git a/icons/obj/toy/plush_facehugger.dmi b/icons/obj/toy/plush_facehugger.dmi new file mode 100644 index 000000000000..dfb5f892c974 Binary files /dev/null and b/icons/obj/toy/plush_facehugger.dmi differ diff --git a/icons/obj/toy/plush_farwa.dmi b/icons/obj/toy/plush_farwa.dmi new file mode 100644 index 000000000000..82df7e229aec Binary files /dev/null and b/icons/obj/toy/plush_farwa.dmi differ diff --git a/icons/obj/toy/plush_fox.dmi b/icons/obj/toy/plush_fox.dmi new file mode 100644 index 000000000000..5dffcd943377 Binary files /dev/null and b/icons/obj/toy/plush_fox.dmi differ diff --git a/icons/obj/toy/plush_fox_black.dmi b/icons/obj/toy/plush_fox_black.dmi new file mode 100644 index 000000000000..6e6f29690d51 Binary files /dev/null and b/icons/obj/toy/plush_fox_black.dmi differ diff --git a/icons/obj/toy/plush_fox_blue.dmi b/icons/obj/toy/plush_fox_blue.dmi new file mode 100644 index 000000000000..f640bf972e7b Binary files /dev/null and b/icons/obj/toy/plush_fox_blue.dmi differ diff --git a/icons/obj/toy/plush_fox_coffee.dmi b/icons/obj/toy/plush_fox_coffee.dmi new file mode 100644 index 000000000000..d5e38a5d2c21 Binary files /dev/null and b/icons/obj/toy/plush_fox_coffee.dmi differ diff --git a/icons/obj/toy/plush_fox_crimson.dmi b/icons/obj/toy/plush_fox_crimson.dmi new file mode 100644 index 000000000000..f5fd4ff0b88a Binary files /dev/null and b/icons/obj/toy/plush_fox_crimson.dmi differ diff --git a/icons/obj/toy/plush_fox_marble.dmi b/icons/obj/toy/plush_fox_marble.dmi new file mode 100644 index 000000000000..b83e0ec6cbe4 Binary files /dev/null and b/icons/obj/toy/plush_fox_marble.dmi differ diff --git a/icons/obj/toy/plush_fox_orange.dmi b/icons/obj/toy/plush_fox_orange.dmi new file mode 100644 index 000000000000..41de7bfb4e1e Binary files /dev/null and b/icons/obj/toy/plush_fox_orange.dmi differ diff --git a/icons/obj/toy/plush_fox_pink.dmi b/icons/obj/toy/plush_fox_pink.dmi new file mode 100644 index 000000000000..056e4c1b2afa Binary files /dev/null and b/icons/obj/toy/plush_fox_pink.dmi differ diff --git a/icons/obj/toy/plush_fox_purple.dmi b/icons/obj/toy/plush_fox_purple.dmi new file mode 100644 index 000000000000..de94b53d807b Binary files /dev/null and b/icons/obj/toy/plush_fox_purple.dmi differ diff --git a/icons/obj/toy/plush_kitten.dmi b/icons/obj/toy/plush_kitten.dmi new file mode 100644 index 000000000000..e443c1beeaf4 Binary files /dev/null and b/icons/obj/toy/plush_kitten.dmi differ diff --git a/icons/obj/toy/plush_lizard.dmi b/icons/obj/toy/plush_lizard.dmi new file mode 100644 index 000000000000..3ffc3e822b24 Binary files /dev/null and b/icons/obj/toy/plush_lizard.dmi differ diff --git a/icons/obj/toy/plush_mouse.dmi b/icons/obj/toy/plush_mouse.dmi new file mode 100644 index 000000000000..cb7ddc863bf4 Binary files /dev/null and b/icons/obj/toy/plush_mouse.dmi differ diff --git a/icons/obj/toy/plush_nymph.dmi b/icons/obj/toy/plush_nymph.dmi new file mode 100644 index 000000000000..c524bf80f441 Binary files /dev/null and b/icons/obj/toy/plush_nymph.dmi differ diff --git a/icons/obj/toy/plush_octopus.dmi b/icons/obj/toy/plush_octopus.dmi new file mode 100644 index 000000000000..5ee5f7dd3b6b Binary files /dev/null and b/icons/obj/toy/plush_octopus.dmi differ diff --git a/icons/obj/toy/plush_spider.dmi b/icons/obj/toy/plush_spider.dmi new file mode 100644 index 000000000000..abec903e7948 Binary files /dev/null and b/icons/obj/toy/plush_spider.dmi differ diff --git a/icons/obj/toy/plush_squid.dmi b/icons/obj/toy/plush_squid.dmi new file mode 100644 index 000000000000..03f35f4c2916 Binary files /dev/null and b/icons/obj/toy/plush_squid.dmi differ diff --git a/icons/obj/toy/plush_squid_blue.dmi b/icons/obj/toy/plush_squid_blue.dmi new file mode 100644 index 000000000000..2ad2388d169a Binary files /dev/null and b/icons/obj/toy/plush_squid_blue.dmi differ diff --git a/icons/obj/toy/plush_squid_mint.dmi b/icons/obj/toy/plush_squid_mint.dmi new file mode 100644 index 000000000000..4b225a5e3d16 Binary files /dev/null and b/icons/obj/toy/plush_squid_mint.dmi differ diff --git a/icons/obj/toy/plush_squid_orange.dmi b/icons/obj/toy/plush_squid_orange.dmi new file mode 100644 index 000000000000..06531342de57 Binary files /dev/null and b/icons/obj/toy/plush_squid_orange.dmi differ diff --git a/icons/obj/toy/plush_squid_pink.dmi b/icons/obj/toy/plush_squid_pink.dmi new file mode 100644 index 000000000000..90adb773707d Binary files /dev/null and b/icons/obj/toy/plush_squid_pink.dmi differ diff --git a/icons/obj/toy/plush_squid_yellow.dmi b/icons/obj/toy/plush_squid_yellow.dmi new file mode 100644 index 000000000000..0991648a35cf Binary files /dev/null and b/icons/obj/toy/plush_squid_yellow.dmi differ diff --git a/icons/obj/toy/plush_therapy_blue.dmi b/icons/obj/toy/plush_therapy_blue.dmi new file mode 100644 index 000000000000..2d1ab2358c4f Binary files /dev/null and b/icons/obj/toy/plush_therapy_blue.dmi differ diff --git a/icons/obj/toy/plush_therapy_green.dmi b/icons/obj/toy/plush_therapy_green.dmi new file mode 100644 index 000000000000..7dfb19b29794 Binary files /dev/null and b/icons/obj/toy/plush_therapy_green.dmi differ diff --git a/icons/obj/toy/plush_therapy_orange.dmi b/icons/obj/toy/plush_therapy_orange.dmi new file mode 100644 index 000000000000..4351516f8487 Binary files /dev/null and b/icons/obj/toy/plush_therapy_orange.dmi differ diff --git a/icons/obj/toy/plush_therapy_purple.dmi b/icons/obj/toy/plush_therapy_purple.dmi new file mode 100644 index 000000000000..50118980597d Binary files /dev/null and b/icons/obj/toy/plush_therapy_purple.dmi differ diff --git a/icons/obj/toy/plush_therapy_red.dmi b/icons/obj/toy/plush_therapy_red.dmi new file mode 100644 index 000000000000..5d210da13306 Binary files /dev/null and b/icons/obj/toy/plush_therapy_red.dmi differ diff --git a/icons/obj/toy/plush_therapy_yellow.dmi b/icons/obj/toy/plush_therapy_yellow.dmi new file mode 100644 index 000000000000..4fa165bb8c47 Binary files /dev/null and b/icons/obj/toy/plush_therapy_yellow.dmi differ diff --git a/icons/obj/toy/toy.dmi b/icons/obj/toy/toy.dmi new file mode 100644 index 000000000000..b70ab4d45f9d Binary files /dev/null and b/icons/obj/toy/toy.dmi differ diff --git a/icons/obj/trash.dmi b/icons/obj/trash.dmi index 01878c15e8df..7414e05bb148 100644 Binary files a/icons/obj/trash.dmi and b/icons/obj/trash.dmi differ diff --git a/icons/obj/turbolift_preview_5x5.dmi b/icons/obj/turbolift_preview_5x5.dmi new file mode 100644 index 000000000000..e054a6b9aacc Binary files /dev/null and b/icons/obj/turbolift_preview_5x5.dmi differ diff --git a/icons/obj/turbolift_preview_nowalls_3x3.dmi b/icons/obj/turbolift_preview_nowalls_3x3.dmi new file mode 100644 index 000000000000..5b4addbf551b Binary files /dev/null and b/icons/obj/turbolift_preview_nowalls_3x3.dmi differ diff --git a/icons/obj/turbolift_preview_nowalls_4x4.dmi b/icons/obj/turbolift_preview_nowalls_4x4.dmi new file mode 100644 index 000000000000..ad88335e4a4d Binary files /dev/null and b/icons/obj/turbolift_preview_nowalls_4x4.dmi differ diff --git a/icons/obj/turrets.dmi b/icons/obj/turrets.dmi index b3a203674260..67961cd0cfbc 100644 Binary files a/icons/obj/turrets.dmi and b/icons/obj/turrets.dmi differ diff --git a/icons/obj/vehicles_64x64.dmi b/icons/obj/vehicles_64x64.dmi new file mode 100644 index 000000000000..50cc6457594a Binary files /dev/null and b/icons/obj/vehicles_64x64.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi deleted file mode 100644 index 925059780c41..000000000000 Binary files a/icons/obj/vending.dmi and /dev/null differ diff --git a/icons/obj/vialbox.dmi b/icons/obj/vialbox.dmi index c08b5cfeabb1..587c564e2e48 100644 Binary files a/icons/obj/vialbox.dmi and b/icons/obj/vialbox.dmi differ diff --git a/icons/obj/volleyball.dmi b/icons/obj/volleyball.dmi new file mode 100644 index 000000000000..33edf34da7ec Binary files /dev/null and b/icons/obj/volleyball.dmi differ diff --git a/icons/obj/water_balloon.dmi b/icons/obj/water_balloon.dmi new file mode 100644 index 000000000000..6fa5a8d1407a Binary files /dev/null and b/icons/obj/water_balloon.dmi differ diff --git a/icons/obj/watercloset.dmi b/icons/obj/watercloset.dmi index 82caf5237d96..373f998b70c2 100644 Binary files a/icons/obj/watercloset.dmi and b/icons/obj/watercloset.dmi differ diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi index ce15a5788ec4..b8ebfc011088 100644 Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ diff --git a/icons/obj/worm.dmi b/icons/obj/worm.dmi new file mode 100644 index 000000000000..02d2c9ea380f Binary files /dev/null and b/icons/obj/worm.dmi differ diff --git a/icons/obj/xenoarchaeology.dmi b/icons/obj/xenoarchaeology.dmi index d7bd2cd99c63..a12468a107f8 100644 Binary files a/icons/obj/xenoarchaeology.dmi and b/icons/obj/xenoarchaeology.dmi differ diff --git a/icons/policetape.dmi b/icons/policetape.dmi index b3e2e02b9c9f..5a14da3d9e78 100644 Binary files a/icons/policetape.dmi and b/icons/policetape.dmi differ diff --git a/icons/screen/hud.dmi b/icons/screen/hud.dmi new file mode 100644 index 000000000000..b8d981293699 Binary files /dev/null and b/icons/screen/hud.dmi differ diff --git a/icons/screen/hud_antag.dmi b/icons/screen/hud_antag.dmi new file mode 100644 index 000000000000..07840ff2614e Binary files /dev/null and b/icons/screen/hud_antag.dmi differ diff --git a/icons/screen/hud_implants.dmi b/icons/screen/hud_implants.dmi new file mode 100644 index 000000000000..5899f696f70d Binary files /dev/null and b/icons/screen/hud_implants.dmi differ diff --git a/icons/screen/hud_med.dmi b/icons/screen/hud_med.dmi new file mode 100644 index 000000000000..280097c8166c Binary files /dev/null and b/icons/screen/hud_med.dmi differ diff --git a/icons/screen/intents.dmi b/icons/screen/intents.dmi new file mode 100644 index 000000000000..3e7992ed2c99 Binary files /dev/null and b/icons/screen/intents.dmi differ diff --git a/icons/screen/intents_wide.dmi b/icons/screen/intents_wide.dmi new file mode 100644 index 000000000000..a89c5ee023dd Binary files /dev/null and b/icons/screen/intents_wide.dmi differ diff --git a/icons/screen/maneuver.dmi b/icons/screen/maneuver.dmi new file mode 100644 index 000000000000..0a4676979c2d Binary files /dev/null and b/icons/screen/maneuver.dmi differ diff --git a/icons/screen/mob_modifiers.dmi b/icons/screen/mob_modifiers.dmi new file mode 100644 index 000000000000..e473dc266777 Binary files /dev/null and b/icons/screen/mob_modifiers.dmi differ diff --git a/icons/screen/radial.dmi b/icons/screen/radial.dmi index d2d032fbbb42..2b37f455c111 100644 Binary files a/icons/screen/radial.dmi and b/icons/screen/radial.dmi differ diff --git a/icons/skybox/skybox.dmi b/icons/skybox/skybox.dmi index e7d6fb3c5894..2cd02de6f5df 100644 Binary files a/icons/skybox/skybox.dmi and b/icons/skybox/skybox.dmi differ diff --git a/icons/turf/areas.dmi b/icons/turf/areas.dmi index be82279128f4..0fc80f9ed85e 100644 Binary files a/icons/turf/areas.dmi and b/icons/turf/areas.dmi differ diff --git a/icons/turf/chlorine.dmi b/icons/turf/chlorine.dmi deleted file mode 100644 index 3cf6bba30f91..000000000000 Binary files a/icons/turf/chlorine.dmi and /dev/null differ diff --git a/icons/turf/desert.dmi b/icons/turf/desert.dmi deleted file mode 100644 index b080a826425e..000000000000 Binary files a/icons/turf/desert.dmi and /dev/null differ diff --git a/icons/turf/flooring/alium.dmi b/icons/turf/flooring/alium.dmi index 33665c8e05b6..2a3e8490826f 100644 Binary files a/icons/turf/flooring/alium.dmi and b/icons/turf/flooring/alium.dmi differ diff --git a/icons/turf/flooring/asteroid.dmi b/icons/turf/flooring/asteroid.dmi deleted file mode 100644 index eaba3e7626e1..000000000000 Binary files a/icons/turf/flooring/asteroid.dmi and /dev/null differ diff --git a/icons/turf/flooring/barren.dmi b/icons/turf/flooring/barren.dmi new file mode 100644 index 000000000000..b98d7911f171 Binary files /dev/null and b/icons/turf/flooring/barren.dmi differ diff --git a/icons/turf/flooring/carpet.dmi b/icons/turf/flooring/carpet.dmi index c7731d595933..2861e59ba1ba 100644 Binary files a/icons/turf/flooring/carpet.dmi and b/icons/turf/flooring/carpet.dmi differ diff --git a/icons/turf/flooring/chlorine_sand.dmi b/icons/turf/flooring/chlorine_sand.dmi new file mode 100644 index 000000000000..e6d6522949c8 Binary files /dev/null and b/icons/turf/flooring/chlorine_sand.dmi differ diff --git a/icons/turf/flooring/circuit.dmi b/icons/turf/flooring/circuit.dmi index 3617171b977f..9062af5b4d6f 100644 Binary files a/icons/turf/flooring/circuit.dmi and b/icons/turf/flooring/circuit.dmi differ diff --git a/icons/turf/flooring/clay.dmi b/icons/turf/flooring/clay.dmi new file mode 100644 index 000000000000..d7412126a199 Binary files /dev/null and b/icons/turf/flooring/clay.dmi differ diff --git a/icons/turf/flooring/concrete.dmi b/icons/turf/flooring/concrete.dmi new file mode 100644 index 000000000000..a733780b4ff2 Binary files /dev/null and b/icons/turf/flooring/concrete.dmi differ diff --git a/icons/turf/flooring/crystal.dmi b/icons/turf/flooring/crystal.dmi index 00c7a13cb7e1..91a88e693acd 100644 Binary files a/icons/turf/flooring/crystal.dmi and b/icons/turf/flooring/crystal.dmi differ diff --git a/icons/turf/flooring/cult.dmi b/icons/turf/flooring/cult.dmi index 47898ff71266..8cfc970e0fc3 100644 Binary files a/icons/turf/flooring/cult.dmi and b/icons/turf/flooring/cult.dmi differ diff --git a/icons/turf/flooring/damage.dmi b/icons/turf/flooring/damage.dmi deleted file mode 100644 index 6e2d9639b385..000000000000 Binary files a/icons/turf/flooring/damage.dmi and /dev/null differ diff --git a/icons/turf/flooring/decals.dmi b/icons/turf/flooring/decals.dmi index 52a50ab70dc7..d81b442969a2 100644 Binary files a/icons/turf/flooring/decals.dmi and b/icons/turf/flooring/decals.dmi differ diff --git a/icons/turf/flooring/dirt.dmi b/icons/turf/flooring/dirt.dmi new file mode 100644 index 000000000000..46dd0ad049ea Binary files /dev/null and b/icons/turf/flooring/dirt.dmi differ diff --git a/icons/turf/flooring/fake_space.dmi b/icons/turf/flooring/fake_space.dmi new file mode 100644 index 000000000000..be1c1cd69120 Binary files /dev/null and b/icons/turf/flooring/fake_space.dmi differ diff --git a/icons/turf/flooring/fake_water.dmi b/icons/turf/flooring/fake_water.dmi new file mode 100644 index 000000000000..a31aeeeadc91 Binary files /dev/null and b/icons/turf/flooring/fake_water.dmi differ diff --git a/icons/turf/flooring/fakegrass.dmi b/icons/turf/flooring/fakegrass.dmi new file mode 100644 index 000000000000..27aa440ce0bb Binary files /dev/null and b/icons/turf/flooring/fakegrass.dmi differ diff --git a/icons/turf/flooring/flesh.dmi b/icons/turf/flooring/flesh.dmi new file mode 100644 index 000000000000..884644838df1 Binary files /dev/null and b/icons/turf/flooring/flesh.dmi differ diff --git a/icons/turf/flooring/glass.dmi b/icons/turf/flooring/glass.dmi new file mode 100644 index 000000000000..b6f4bae629ea Binary files /dev/null and b/icons/turf/flooring/glass.dmi differ diff --git a/icons/turf/flooring/grass.dmi b/icons/turf/flooring/grass.dmi index a3378505f433..dd28f8c29047 100644 Binary files a/icons/turf/flooring/grass.dmi and b/icons/turf/flooring/grass.dmi differ diff --git a/icons/turf/flooring/ice.dmi b/icons/turf/flooring/ice.dmi new file mode 100644 index 000000000000..264e0a6d740f Binary files /dev/null and b/icons/turf/flooring/ice.dmi differ diff --git a/icons/turf/flooring/laminate.dmi b/icons/turf/flooring/laminate.dmi new file mode 100644 index 000000000000..83d4933c155f Binary files /dev/null and b/icons/turf/flooring/laminate.dmi differ diff --git a/icons/turf/flooring/lava.dmi b/icons/turf/flooring/lava.dmi index c70c039b8e45..3b0ac36c2bdc 100644 Binary files a/icons/turf/flooring/lava.dmi and b/icons/turf/flooring/lava.dmi differ diff --git a/icons/turf/flooring/linoleum.dmi b/icons/turf/flooring/linoleum.dmi index 50bdfe878982..8d28351d5a70 100644 Binary files a/icons/turf/flooring/linoleum.dmi and b/icons/turf/flooring/linoleum.dmi differ diff --git a/icons/turf/flooring/misc.dmi b/icons/turf/flooring/misc.dmi index fc0eb605f3c2..7d54746a6e97 100644 Binary files a/icons/turf/flooring/misc.dmi and b/icons/turf/flooring/misc.dmi differ diff --git a/icons/turf/flooring/mud.dmi b/icons/turf/flooring/mud.dmi new file mode 100644 index 000000000000..b73fcd5c76fb Binary files /dev/null and b/icons/turf/flooring/mud.dmi differ diff --git a/icons/turf/flooring/path.dmi b/icons/turf/flooring/path.dmi new file mode 100644 index 000000000000..2f13c15ef5d6 Binary files /dev/null and b/icons/turf/flooring/path.dmi differ diff --git a/icons/turf/flooring/plating.dmi b/icons/turf/flooring/plating.dmi index 2a5dc532830e..d3ef26d034d6 100644 Binary files a/icons/turf/flooring/plating.dmi and b/icons/turf/flooring/plating.dmi differ diff --git a/icons/turf/flooring/pool.dmi b/icons/turf/flooring/pool.dmi new file mode 100644 index 000000000000..02caa57b5794 Binary files /dev/null and b/icons/turf/flooring/pool.dmi differ diff --git a/icons/turf/flooring/rock.dmi b/icons/turf/flooring/rock.dmi new file mode 100644 index 000000000000..bd23c7d996b7 Binary files /dev/null and b/icons/turf/flooring/rock.dmi differ diff --git a/icons/turf/flooring/sand.dmi b/icons/turf/flooring/sand.dmi new file mode 100644 index 000000000000..20339e3f1bcc Binary files /dev/null and b/icons/turf/flooring/sand.dmi differ diff --git a/icons/turf/flooring/seafloor.dmi b/icons/turf/flooring/seafloor.dmi new file mode 100644 index 000000000000..7c2bf4d95404 Binary files /dev/null and b/icons/turf/flooring/seafloor.dmi differ diff --git a/icons/turf/flooring/shrouded.dmi b/icons/turf/flooring/shrouded.dmi new file mode 100644 index 000000000000..3e93d540e09d Binary files /dev/null and b/icons/turf/flooring/shrouded.dmi differ diff --git a/icons/turf/flooring/shuttle.dmi b/icons/turf/flooring/shuttle.dmi new file mode 100644 index 000000000000..9a53c879bf47 Binary files /dev/null and b/icons/turf/flooring/shuttle.dmi differ diff --git a/icons/turf/flooring/simple_carpet.dmi b/icons/turf/flooring/simple_carpet.dmi new file mode 100644 index 000000000000..5a66bf0a3019 Binary files /dev/null and b/icons/turf/flooring/simple_carpet.dmi differ diff --git a/icons/turf/flooring/sky_fast.dmi b/icons/turf/flooring/sky_fast.dmi new file mode 100644 index 000000000000..fa34eb627877 Binary files /dev/null and b/icons/turf/flooring/sky_fast.dmi differ diff --git a/icons/turf/flooring/sky_slow.dmi b/icons/turf/flooring/sky_slow.dmi new file mode 100644 index 000000000000..0720fe956024 Binary files /dev/null and b/icons/turf/flooring/sky_slow.dmi differ diff --git a/icons/turf/flooring/sky_static.dmi b/icons/turf/flooring/sky_static.dmi new file mode 100644 index 000000000000..8b1ec0eac65f Binary files /dev/null and b/icons/turf/flooring/sky_static.dmi differ diff --git a/icons/turf/flooring/snow.dmi b/icons/turf/flooring/snow.dmi new file mode 100644 index 000000000000..01552a248c40 Binary files /dev/null and b/icons/turf/flooring/snow.dmi differ diff --git a/icons/turf/flooring/snow_plating.dmi b/icons/turf/flooring/snow_plating.dmi new file mode 100644 index 000000000000..9a82cd775263 Binary files /dev/null and b/icons/turf/flooring/snow_plating.dmi differ diff --git a/icons/turf/flooring/straw.dmi b/icons/turf/flooring/straw.dmi new file mode 100644 index 000000000000..f797358bf238 Binary files /dev/null and b/icons/turf/flooring/straw.dmi differ diff --git a/icons/turf/flooring/techfloor.dmi b/icons/turf/flooring/techfloor.dmi index 5124ff3146c0..73f76ba1349d 100644 Binary files a/icons/turf/flooring/techfloor.dmi and b/icons/turf/flooring/techfloor.dmi differ diff --git a/icons/turf/flooring/tiles.dmi b/icons/turf/flooring/tiles.dmi index 18aa84793d84..20fbf25e7452 100644 Binary files a/icons/turf/flooring/tiles.dmi and b/icons/turf/flooring/tiles.dmi differ diff --git a/icons/turf/flooring/wildgrass.dmi b/icons/turf/flooring/wildgrass.dmi new file mode 100644 index 000000000000..72c7c3cf99fd Binary files /dev/null and b/icons/turf/flooring/wildgrass.dmi differ diff --git a/icons/turf/flooring/wood.dmi b/icons/turf/flooring/wood.dmi index 825b3dc3f38a..9e17d5cbeb40 100644 Binary files a/icons/turf/flooring/wood.dmi and b/icons/turf/flooring/wood.dmi differ diff --git a/icons/turf/flooring/wood_alt.dmi b/icons/turf/flooring/wood_alt.dmi new file mode 100644 index 000000000000..2f55a0fb6c4d Binary files /dev/null and b/icons/turf/flooring/wood_alt.dmi differ diff --git a/icons/turf/flooring/woven.dmi b/icons/turf/flooring/woven.dmi new file mode 100644 index 000000000000..d5f1b4df68c6 Binary files /dev/null and b/icons/turf/flooring/woven.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index ad8b9b41fea8..a6edc47a759d 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/jungle.dmi b/icons/turf/jungle.dmi deleted file mode 100644 index 4f5a7c16810a..000000000000 Binary files a/icons/turf/jungle.dmi and /dev/null differ diff --git a/icons/turf/seafloor.dmi b/icons/turf/seafloor.dmi deleted file mode 100644 index 241f9122d212..000000000000 Binary files a/icons/turf/seafloor.dmi and /dev/null differ diff --git a/icons/turf/shrouded.dmi b/icons/turf/shrouded.dmi deleted file mode 100644 index ce90ed185f11..000000000000 Binary files a/icons/turf/shrouded.dmi and /dev/null differ diff --git a/icons/turf/shuttle.dmi b/icons/turf/shuttle.dmi deleted file mode 100644 index 12b1b6d038b9..000000000000 Binary files a/icons/turf/shuttle.dmi and /dev/null differ diff --git a/icons/turf/snow.dmi b/icons/turf/snow.dmi deleted file mode 100644 index dc33f6dac512..000000000000 Binary files a/icons/turf/snow.dmi and /dev/null differ diff --git a/icons/turf/space.dmi b/icons/turf/space.dmi index 33e2aae61f14..078c4b20ea43 100644 Binary files a/icons/turf/space.dmi and b/icons/turf/space.dmi differ diff --git a/icons/turf/space_dust_transit.dmi b/icons/turf/space_dust_transit.dmi new file mode 100644 index 000000000000..db36a50efb4a Binary files /dev/null and b/icons/turf/space_dust_transit.dmi differ diff --git a/icons/turf/wall_masks.dmi b/icons/turf/wall_masks.dmi deleted file mode 100644 index e178b40da5a3..000000000000 Binary files a/icons/turf/wall_masks.dmi and /dev/null differ diff --git a/icons/turf/wall_texture.dmi b/icons/turf/wall_texture.dmi index 265e997b9326..8a8de81c25a9 100644 Binary files a/icons/turf/wall_texture.dmi and b/icons/turf/wall_texture.dmi differ diff --git a/icons/turf/walls.dmi b/icons/turf/walls.dmi index 9c821ae2d4a2..6352c36cd577 100644 Binary files a/icons/turf/walls.dmi and b/icons/turf/walls.dmi differ diff --git a/icons/turf/walls/_construction_overlays.dmi b/icons/turf/walls/_construction_overlays.dmi new file mode 100644 index 000000000000..ae53008b14b4 Binary files /dev/null and b/icons/turf/walls/_construction_overlays.dmi differ diff --git a/icons/turf/walls/_previews.dmi b/icons/turf/walls/_previews.dmi new file mode 100644 index 000000000000..59e03e52b4d6 Binary files /dev/null and b/icons/turf/walls/_previews.dmi differ diff --git a/icons/turf/walls/brick.dmi b/icons/turf/walls/brick.dmi new file mode 100644 index 000000000000..530e4e030271 Binary files /dev/null and b/icons/turf/walls/brick.dmi differ diff --git a/icons/turf/walls/cult.dmi b/icons/turf/walls/cult.dmi new file mode 100644 index 000000000000..5b2dd836c3b0 Binary files /dev/null and b/icons/turf/walls/cult.dmi differ diff --git a/icons/turf/walls/debug.dmi b/icons/turf/walls/debug.dmi new file mode 100644 index 000000000000..76e8845f7524 Binary files /dev/null and b/icons/turf/walls/debug.dmi differ diff --git a/icons/turf/walls/log.dmi b/icons/turf/walls/log.dmi new file mode 100644 index 000000000000..f7f3e773a79b Binary files /dev/null and b/icons/turf/walls/log.dmi differ diff --git a/icons/turf/walls/metal.dmi b/icons/turf/walls/metal.dmi new file mode 100644 index 000000000000..8199a29f39d0 Binary files /dev/null and b/icons/turf/walls/metal.dmi differ diff --git a/icons/turf/walls/natural.dmi b/icons/turf/walls/natural.dmi new file mode 100644 index 000000000000..d8509d2f1baa Binary files /dev/null and b/icons/turf/walls/natural.dmi differ diff --git a/icons/turf/walls/plaster.dmi b/icons/turf/walls/plaster.dmi new file mode 100644 index 000000000000..ee8b3faf2b4b Binary files /dev/null and b/icons/turf/walls/plaster.dmi differ diff --git a/icons/turf/walls/plastic.dmi b/icons/turf/walls/plastic.dmi new file mode 100644 index 000000000000..034c494a3571 Binary files /dev/null and b/icons/turf/walls/plastic.dmi differ diff --git a/icons/turf/walls/reinforced.dmi b/icons/turf/walls/reinforced.dmi new file mode 100644 index 000000000000..ec9936fe1570 Binary files /dev/null and b/icons/turf/walls/reinforced.dmi differ diff --git a/icons/turf/walls/reinforced_cult.dmi b/icons/turf/walls/reinforced_cult.dmi new file mode 100644 index 000000000000..85fd32e84932 Binary files /dev/null and b/icons/turf/walls/reinforced_cult.dmi differ diff --git a/icons/turf/walls/reinforced_metal.dmi b/icons/turf/walls/reinforced_metal.dmi new file mode 100644 index 000000000000..5521d9afccd4 Binary files /dev/null and b/icons/turf/walls/reinforced_metal.dmi differ diff --git a/icons/turf/walls/reinforced_stone.dmi b/icons/turf/walls/reinforced_stone.dmi new file mode 100644 index 000000000000..5521d9afccd4 Binary files /dev/null and b/icons/turf/walls/reinforced_stone.dmi differ diff --git a/icons/turf/walls/reinforced_timber.dmi b/icons/turf/walls/reinforced_timber.dmi new file mode 100644 index 000000000000..46e537f04e08 Binary files /dev/null and b/icons/turf/walls/reinforced_timber.dmi differ diff --git a/icons/turf/walls/reinforced_timber_alt_1.dmi b/icons/turf/walls/reinforced_timber_alt_1.dmi new file mode 100644 index 000000000000..f6eb3a41df36 Binary files /dev/null and b/icons/turf/walls/reinforced_timber_alt_1.dmi differ diff --git a/icons/turf/walls/reinforced_timber_alt_2.dmi b/icons/turf/walls/reinforced_timber_alt_2.dmi new file mode 100644 index 000000000000..c06be35cb5fe Binary files /dev/null and b/icons/turf/walls/reinforced_timber_alt_2.dmi differ diff --git a/icons/turf/walls/reinforced_timber_alt_3.dmi b/icons/turf/walls/reinforced_timber_alt_3.dmi new file mode 100644 index 000000000000..1ee1a9f46257 Binary files /dev/null and b/icons/turf/walls/reinforced_timber_alt_3.dmi differ diff --git a/icons/turf/walls/reinforced_timber_alt_4.dmi b/icons/turf/walls/reinforced_timber_alt_4.dmi new file mode 100644 index 000000000000..ac01d0457a58 Binary files /dev/null and b/icons/turf/walls/reinforced_timber_alt_4.dmi differ diff --git a/icons/turf/walls/shutter.dmi b/icons/turf/walls/shutter.dmi new file mode 100644 index 000000000000..671d71682fd0 Binary files /dev/null and b/icons/turf/walls/shutter.dmi differ diff --git a/icons/turf/walls/solid.dmi b/icons/turf/walls/solid.dmi new file mode 100644 index 000000000000..e894a99f0b4f Binary files /dev/null and b/icons/turf/walls/solid.dmi differ diff --git a/icons/turf/walls/square_shutter.dmi b/icons/turf/walls/square_shutter.dmi new file mode 100644 index 000000000000..d0729a887beb Binary files /dev/null and b/icons/turf/walls/square_shutter.dmi differ diff --git a/icons/turf/walls/stone.dmi b/icons/turf/walls/stone.dmi new file mode 100644 index 000000000000..3a9c3be5a1db Binary files /dev/null and b/icons/turf/walls/stone.dmi differ diff --git a/icons/turf/walls/wattle.dmi b/icons/turf/walls/wattle.dmi new file mode 100644 index 000000000000..01ee0aadc3e9 Binary files /dev/null and b/icons/turf/walls/wattle.dmi differ diff --git a/icons/turf/walls/wattledaub.dmi b/icons/turf/walls/wattledaub.dmi new file mode 100644 index 000000000000..126f7829c7e9 Binary files /dev/null and b/icons/turf/walls/wattledaub.dmi differ diff --git a/icons/turf/walls/wood.dmi b/icons/turf/walls/wood.dmi new file mode 100644 index 000000000000..9b2304dcec89 Binary files /dev/null and b/icons/turf/walls/wood.dmi differ diff --git a/ingame_manuals/README.txt b/ingame_manuals/README.txt deleted file mode 100644 index 081153066a58..000000000000 --- a/ingame_manuals/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -INGAME MANUALS - -Ingame manuals are simple HTML files with basic information. They are linked to specific items/commands, such as the AI's display help command, or engine setup guide. Point of these files is to allow creation of basic guides for players which don't want to use wiki. \ No newline at end of file diff --git a/ingame_manuals/malf_ai.html b/ingame_manuals/malf_ai.html deleted file mode 100644 index 65424f24ed35..000000000000 --- a/ingame_manuals/malf_ai.html +++ /dev/null @@ -1,22 +0,0 @@ -

    Malfunctioning AI guide


    - -This guide contains most important OOC information for malfunctioning AIs.
    - -

    Goal


    -As malfunctioning AI, your primary goal is to overtake station's systems. To do this, use software "Basic Encryption Hack" on APCs (right click on APC and select Basic Encryption Hack). Please note that hacked APCs have distinctive blue error screen, that tends to attract attention. Rememember that malfunctioning AI is antagonist, so read server rules for antagonists. While hacking APCs is your official goal, feel free to create custom goal, as long as it is fun for everyone.
    - -

    Hardware


    -As malfunctioning AI, you may select one hardware piece to help you. Remember that once you select hardware piece, you cannot select another one, so choose wisely! Hardware may be selected by clicking "Select Hardware" button in Hardware tab. Following is list of possible hardware pieces:
    -APU Generator - Auxiliary Power Unit which allows you to operate even without external power. However, running on APU will stop your CPU time generation, and temporarily disable most of your abilities. APU is also somewhat vulnerable to physical damage, and will fail if your core hardware integrity drops below 50%.
    -Turrets Focus Enhancer - Removes safeties on installed turrets, boosting their rate of fire, health and enabling nano-regeneration module. This however increases power usage considerably, espicially when regenerating damage.
    -Secondary Processor Unit - Simple upgrade that increases your CPU time generation by 50%. Useful if you need to speed up your research.
    -Secondary Memory Bank - Doubles amount of maximal CPU time you may store. This is useful if you need to use lots of abilities in short amount of time.
    -Self-Destruct Explosives - Large blocks of C4 are attached to your physical core. This C4 has 15 second timer, and may be activated by special button that appears in your Hardware tab. This self-destruct will remain active, even if you are destroyed. If timer reaches 0 your core explodes in strong explosion. Obviously, this destroys you, as well as anyone nearby.
    - -

    Software


    -Software are abilities that have to be unlocked via research menu (Hardware tab). Unlocked abilities appear in Software tab. Sometimes, abilities won't appear in this tab after being researched. This can be fixed by relogging or using "ai-core" command. Abilities are tiered, T1 being the weakest ones, while T4 are strongest ones. To reach higher tier you have to research abilities in lower tier. We currently have 12 abilities, in 3 research trees:
    -Networking - Hacking-oriented abilities. T1 ability is Basic Encryption Hack, which allows you to hack more APCs. Higher tiers allow faking centcom messages, and even setting alert level. T4 ability is System Override, that rapidly hacks remaining APCs and gives you access to station self destruct sequence.
    -Interdiction - Sabotage-oriented abilities. T1 ability allows you to recall emergency shuttle. Higher level abilities allow you to unlock cyborgs even without access to robotics console, and T4 ability allows you to hack other AIs to slave them under your control.
    -Manipulation - Physical-oriented abilities. T1 ability allows you to break few lights, and rarely even APCs. T2 ability allows you to apply upgrade of your choice to camera, or reactivate broken camera. T3 ability allows you to create weak forcefield, that holds air, but won't last for long. And T4 ability allows you to overload machines, detonating them in weak explosion.
    -

    End


    -If you still have some questions, either check the wiki, ask on IRC, or adminhelp and ask your friendly administration staff. \ No newline at end of file diff --git a/install-byond.sh b/install-byond.sh index 3b0170c16b0f..5d60db277127 100755 --- a/install-byond.sh +++ b/install-byond.sh @@ -8,7 +8,8 @@ else mkdir -p "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}" cd "$HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}" echo "Installing DreamMaker to $PWD" - curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip + #curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -H "User-Agent: NebulaSS13/1.0 Continuous Integration" -o byond.zip + curl "https://spacestation13.github.io/byond-builds/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -H "User-Agent: NebulaSS13/1.0 Continuous Integration" -o byond.zip unzip -o byond.zip cd byond make here diff --git a/interface/interface.dm b/interface/interface.dm index 355986665a17..9f1e923dc44e 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -3,10 +3,10 @@ set name = "Wiki" set desc = "Visit the wiki." set hidden = 1 - if(config.wikiurl) + if(get_config_value(/decl/config/text/wikiurl)) if(alert("This will open the wiki in your browser. Are you sure?",,"Yes","No")=="No") return - send_link(src, config.wikiurl) + send_link(src, get_config_value(/decl/config/text/wikiurl)) else to_chat(src, SPAN_WARNING("The wiki URL is not set in the server configuration.")) return @@ -15,10 +15,10 @@ set name = "GitHub" set desc = "Visit the GitHub repository." set hidden = 1 - if(config.githuburl) + if(get_config_value(/decl/config/text/githuburl)) if(alert("This will open GitHub in your browser. Are you sure?",,"Yes","No")=="No") return - send_link(src, config.githuburl) + send_link(src, get_config_value(/decl/config/text/githuburl)) else to_chat(src, SPAN_WARNING("The github URL is not set in the server configuration.")) return @@ -27,10 +27,10 @@ set name = "Bug Report" set desc = "Visit the GitHub repository to report an issue or bug." set hidden = 1 - if(config.issuereporturl) + if(get_config_value(/decl/config/text/issuereporturl)) if(alert("This will open GitHub in your browser. Are you sure?",,"Yes","No")=="No") return - send_link(src, config.issuereporturl) + send_link(src, get_config_value(/decl/config/text/issuereporturl)) else to_chat(src, SPAN_WARNING("The issue report URL is not set in the server configuration.")) return @@ -39,10 +39,10 @@ set name = "Forum" set desc = "Visit the forum." set hidden = 1 - if(config.forumurl) + if(get_config_value(/decl/config/text/forumurl)) if(alert("This will open the forum in your browser. Are you sure?",,"Yes","No")=="No") return - send_link(src, config.forumurl) + send_link(src, get_config_value(/decl/config/text/forumurl)) else to_chat(src, SPAN_WARNING("The forum URL is not set in the server configuration.")) return @@ -51,10 +51,10 @@ set name = "Discord" set desc = "Visit the Discord server." set hidden = 1 - if(config.discordurl) + if(get_config_value(/decl/config/text/discordurl)) if(alert("This will open the Discord invition link in your browser. Are you sure?",,"Yes","No")=="No") return - send_link(src, config.discordurl) + send_link(src, get_config_value(/decl/config/text/discordurl)) else to_chat(src, SPAN_WARNING("The Discord server URL is not set in the server configuration.")) return @@ -66,139 +66,3 @@ set hidden = 1 show_browser(src, file(RULES_FILE), "window=rules;size=480x320") #undef RULES_FILE - -#define LORE_FILE "config/lore.html" -/client/verb/lore_splash() - set name = "Lore" - set desc = "Links to the beginner Lore wiki." - set hidden = 1 - show_browser(src, file(LORE_FILE), "window=lore;size=480x320") -#undef LORE_FILE - -/client/verb/hotkeys_help() - set name = "Hotkeys Help" - set category = "OOC" - - var/admin = {" -Admin: -\tF5 = Aghost (admin-ghost) -\tF6 = player-panel-new -\tF7 = admin-pm -\tF8 = Invisimin -"} - - var/hotkey_mode = {" -Hotkey-Mode: (hotkey-mode must be on) -\tTAB = toggle hotkey-mode -\ta = left -\ts = down -\td = right -\tw = up -\t, = move-upwards -\t. = move-down -\tq = drop -\te = equip -\tr = throw -\tt = say -\t5 = emote -\tx = swap-hand -\tz = activate held object (or y) -\tj = toggle-aiming-mode -\tf = cycle-intents-left -\tg = cycle-intents-right -\t1 = help-intent -\t2 = disarm-intent -\t3 = grab-intent -\t4 = harm-intent -"} - - var/other = {" -Any-Mode: (hotkey doesn't need to be on) -\tCtrl+a = left -\tCtrl+s = down -\tCtrl+d = right -\tCtrl+w = up -\tCtrl+q = drop -\tCtrl+e = equip -\tCtrl+r = throw -\tCtrl+x or Middle Mouse = swap-hand -\tCtrl+z = activate held object (or Ctrl+y) -\tCtrl+f = cycle-intents-left -\tCtrl+g = cycle-intents-right -\tCtrl+1 = help-intent -\tCtrl+2 = disarm-intent -\tCtrl+3 = grab-intent -\tCtrl+4 = harm-intent -\tF1 = adminhelp -\tF2 = ooc -\tF3 = say -\tF4 = emote -\tDEL = pull -\tINS = cycle-intents-right -\tHOME = drop -\tPGUP or Middle Mouse = swap-hand -\tPGDN = activate held object -\tEND = throw -\tCtrl + Click = drag -\tShift + Click = examine -\tAlt + Click = show entities on turf -\tCtrl + Alt + Click = interact with certain items -"} - - var/robot_hotkey_mode = {" -Hotkey-Mode: (hotkey-mode must be on) -\tTAB = toggle hotkey-mode -\ta = left -\ts = down -\td = right -\tw = up -\tq = unequip active module -\tt = say -\tx = cycle active modules -\tz = activate held object (or y) -\tf = cycle-intents-left -\tg = cycle-intents-right -\t1 = activate module 1 -\t2 = activate module 2 -\t3 = activate module 3 -\t4 = toggle intents -\t5 = emote -"} - - var/robot_other = {" -Any-Mode: (hotkey doesn't need to be on) -\tCtrl+a = left -\tCtrl+s = down -\tCtrl+d = right -\tCtrl+w = up -\tCtrl+q = unequip active module -\tCtrl+x = cycle active modules -\tCtrl+z = activate held object (or Ctrl+y) -\tCtrl+f = cycle-intents-left -\tCtrl+g = cycle-intents-right -\tCtrl+1 = activate module 1 -\tCtrl+2 = activate module 2 -\tCtrl+3 = activate module 3 -\tCtrl+4 = toggle intents -\tF1 = adminhelp -\tF2 = ooc -\tF3 = say -\tF4 = emote -\tDEL = pull -\tINS = toggle intents -\tPGUP = cycle active modules -\tPGDN = activate held object -\tCtrl + Click = drag or bolt doors -\tShift + Click = examine or open doors -\tAlt + Click = show entities on turf -\tCtrl + Alt + Click = electrify doors -"} - - if(isrobot(src.mob)) - to_chat(src, robot_hotkey_mode) - to_chat(src, robot_other) - else - to_chat(src, hotkey_mode) - to_chat(src, other) - if(holder) - to_chat(src, admin) diff --git a/interface/skin.dmf b/interface/skin.dmf index 356f861869f6..c02a82497db3 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1,1226 +1,435 @@ -macro "borghotkeymode" - elem - name = "Tab" - command = ".winset \"mainwindow.macro=borgmacro hotkey_toggle.is-checked=false input.focus=true input.background-color=#d3b5b5\"" - elem - name = "Center+REP" - command = ".center" - elem - name = "Northeast" - command = ".northeast" - elem - name = "Southeast" - command = ".southeast" - elem - name = "Southwest" - command = ".southwest" - elem - name = "Northwest" - command = ".northwest" - elem - name = "ALT+West" - command = "westfaceperm" - elem - name = "CTRL+West" - command = "westface" - elem - name = "West+REP" - command = ".moveleft" - elem - name = "ALT+North" - command = "northfaceperm" - elem - name = "CTRL+North" - command = "northface" - elem - name = "North+REP" - command = ".moveup" - elem - name = "ALT+East" - command = "eastfaceperm" - elem - name = "CTRL+East" - command = "eastface" - elem - name = "East+REP" - command = ".moveright" - elem - name = "ALT+South" - command = "southfaceperm" - elem - name = "CTRL+South" - command = "southface" - elem - name = "South+REP" - command = ".movedown" - elem - name = "Insert" - command = "a-intent right" - elem - name = "1" - command = "toggle-module 1" - elem - name = "CTRL+1" - command = "toggle-module 1" - elem - name = "2" - command = "toggle-module 2" - elem - name = "CTRL+2" - command = "toggle-module 2" - elem - name = "3" - command = "toggle-module 3" - elem - name = "CTRL+3" - command = "toggle-module 3" - elem - name = "4" - command = "a-intent left" - elem - name = "CTRL+4" - command = "a-intent left" - elem - name = "5" - command = ".me" - elem - name = "A+REP" - command = ".moveleft" - elem - name = "CTRL+A+REP" - command = ".moveleft" - elem - name = "D+REP" - command = ".moveright" - elem - name = "CTRL+D+REP" - command = ".moveright" - elem - name = "F" - command = "a-intent left" - elem - name = "CTRL+F" - command = "a-intent left" - elem - name = "G" - command = "a-intent right" - elem - name = "CTRL+G" - command = "a-intent right" - elem - name = "J" - command = "toggle-gun-mode" - elem - name = "CTRL+J" - command = "toggle-gun-mode" - elem - name = "Q" - command = "unequip-module" - elem - name = "CTRL+Q" - command = "unequip-module" - elem - name = "R" - command = ".southwest" - elem - name = "CTRL+R" - command = ".southwest" - elem "s_key" - name = "S+REP" - command = ".movedown" - elem - name = "CTRL+S+REP" - command = ".movedown" - elem - name = "T" - command = ".say" - elem "w_key" - name = "W+REP" - command = ".moveup" - elem - name = "CTRL+W+REP" - command = ".moveup" - elem - name = "X" - command = ".northeast" - elem - name = "CTRL+X" - command = ".northeast" - elem - name = "Y" - command = "Activate-Held-Object" - elem - name = "CTRL+Y" - command = "Activate-Held-Object" - elem - name = "Z" - command = "Activate-Held-Object" - elem - name = "CTRL+Z" - command = "Activate-Held-Object" - elem - name = "Numpad1" - command = "body-r-leg" - elem - name = "Numpad2" - command = "body-groin" - elem - name = "Numpad3" - command = "body-l-leg" - elem - name = "Numpad4" - command = "body-r-arm" - elem - name = "Numpad5" - command = "body-chest" - elem - name = "Numpad6" - command = "body-l-arm" - elem - name = "Numpad8" - command = "body-toggle-head" - elem - name = "F1" - command = "adminhelp" - elem - name = "CTRL+SHIFT+F1+REP" - command = ".options" - elem - name = "F2" - command = "ooc" - elem - name = "F2+REP" - command = ".screenshot auto" - elem - name = "SHIFT+F2+REP" - command = ".screenshot" - elem - name = "F3" - command = ".say" - elem - name = "F4" - command = ".me" - elem - name = "F5" - command = "msay" - elem - name = "F6" - command = "Player-Panel-New" - elem - name = "F7" - command = "Admin-PM" - elem - name = "F8" - command = "Invisimin" - elem - name = "F12" - command = "F12" - elem - name = "," - command = "move-upwards" - elem - name = "." - command = "move-down" - -macro "macro" - elem - name = "Tab" - command = ".winset \"mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#f0f0f0\"" - elem - name = "Center+REP" - command = ".center" - elem - name = "Northeast" - command = ".northeast" - elem - name = "Southeast" - command = ".southeast" - elem - name = "Southwest" - command = ".southwest" - elem - name = "Northwest" - command = ".northwest" - elem - name = "ALT+West" - command = "westfaceperm" - elem - name = "CTRL+West" - command = "westface" - elem - name = "West+REP" - command = ".moveleft" - elem - name = "ALT+North" - command = "northfaceperm" - elem - name = "CTRL+North" - command = "northface" - elem - name = "North+REP" - command = ".moveup" - elem - name = "ALT+East" - command = "eastfaceperm" - elem - name = "CTRL+East" - command = "eastface" - elem - name = "East+REP" - command = ".moveright" - elem - name = "ALT+South" - command = "southfaceperm" - elem - name = "CTRL+South" - command = "southface" - elem - name = "South+REP" - command = ".movedown" - elem - name = "Insert" - command = "a-intent right" - elem - name = "CTRL+1" - command = "a-intent help" - elem - name = "CTRL+2" - command = "a-intent disarm" - elem - name = "CTRL+3" - command = "a-intent grab" - elem - name = "CTRL+4" - command = "a-intent harm" - elem - name = "CTRL+A+REP" - command = ".moveleft" - elem - name = "CTRL+D+REP" - command = ".moveright" - elem - name = "CTRL+E" - command = "quick-equip" - elem - name = "CTRL+F" - command = "a-intent left" - elem - name = "CTRL+G" - command = "a-intent right" - elem - name = "CTRL+SHIFT+G" - command = ".configure graphics-hwmode on" - elem - name = "CTRL+Q" - command = ".northwest" - elem - name = "CTRL+R" - command = ".southwest" - elem - name = "CTRL+S+REP" - command = ".movedown" - elem - name = "CTRL+W+REP" - command = ".moveup" - elem - name = "CTRL+X" - command = ".northeast" - elem - name = "CTRL+Y" - command = "Activate-Held-Object" - elem - name = "CTRL+Z" - command = "Activate-Held-Object" - elem - name = "CTRL+Numpad1" - command = "body-r-leg" - elem - name = "CTRL+Numpad2" - command = "body-groin" - elem - name = "CTRL+Numpad3" - command = "body-l-leg" - elem - name = "CTRL+Numpad4" - command = "body-r-arm" - elem - name = "CTRL+Numpad5" - command = "body-chest" - elem - name = "CTRL+Numpad6" - command = "body-l-arm" - elem - name = "CTRL+Numpad8" - command = "body-toggle-head" - elem - name = "F1" - command = "adminhelp" - elem - name = "CTRL+SHIFT+F1+REP" - command = ".options" - elem - name = "F2" - command = "ooc" - elem - name = "F2+REP" - command = ".screenshot auto" - elem - name = "SHIFT+F2+REP" - command = ".screenshot" - elem - name = "F3" - command = ".say" - elem - name = "F4" - command = ".me" - elem - name = "F5" - command = "msay" - elem - name = "F6" - command = "Player-Panel-New" - elem - name = "F7" - command = "Admin-PM" - elem - name = "F8" - command = "Invisimin" - elem - name = "F12" - command = "F12" - elem - name = "CTRL+Add" - command = "move-upwards" - elem - name = "CTRL+Subtract" - command = "move-down" - -macro "hotkeymode" - elem - name = "Tab" - command = ".winset \"mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#d3b5b5\"" - elem - name = "Center+REP" - command = ".center" - elem - name = "Northeast" - command = ".northeast" - elem - name = "Southeast" - command = ".southeast" - elem - name = "Southwest" - command = ".southwest" - elem - name = "Northwest" - command = ".northwest" - elem - name = "ALT+West" - command = "westfaceperm" - elem - name = "CTRL+West" - command = "westface" - elem - name = "West+REP" - command = ".moveleft" - elem - name = "ALT+North" - command = "northfaceperm" - elem - name = "CTRL+North" - command = "northface" - elem - name = "North+REP" - command = ".moveup" - elem - name = "ALT+East" - command = "eastfaceperm" - elem - name = "CTRL+East" - command = "eastface" - elem - name = "East+REP" - command = ".moveright" - elem - name = "ALT+South" - command = "southfaceperm" - elem - name = "CTRL+South" - command = "southface" - elem - name = "South+REP" - command = ".movedown" - elem - name = "Insert" - command = "a-intent right" - elem - name = "1" - command = "a-intent help" - elem - name = "CTRL+1" - command = "a-intent help" - elem - name = "2" - command = "a-intent disarm" - elem - name = "CTRL+2" - command = "a-intent disarm" - elem - name = "3" - command = "a-intent grab" - elem - name = "CTRL+3" - command = "a-intent grab" - elem - name = "4" - command = "a-intent harm" - elem - name = "CTRL+4" - command = "a-intent harm" - elem - name = "5" - command = ".me" - elem - name = "A+REP" - command = ".moveleft" - elem - name = "CTRL+A+REP" - command = ".moveleft" - elem - name = "D+REP" - command = ".moveright" - elem - name = "CTRL+D+REP" - command = ".moveright" - elem - name = "E" - command = "quick-equip" - elem - name = "CTRL+E" - command = "quick-equip" - elem - name = "F" - command = "a-intent left" - elem - name = "CTRL+F" - command = "a-intent left" - elem - name = "G" - command = "a-intent right" - elem - name = "CTRL+G" - command = "a-intent right" - elem - name = "H" - command = "holster" - elem - name = "CTRL+H" - command = "holster" - elem - name = "J" - command = "toggle-gun-mode" - elem - name = "CTRL+J" - command = "toggle-gun-mode" - elem - name = "Q" - command = ".northwest" - elem - name = "CTRL+Q" - command = ".northwest" - elem - name = "R" - command = ".southwest" - elem - name = "CTRL+R" - command = ".southwest" - elem "s_key" - name = "S+REP" - command = ".movedown" - elem - name = "CTRL+S+REP" - command = ".movedown" - elem - name = "T" - command = ".say" - elem "w_key" - name = "W+REP" - command = ".moveup" - elem - name = "CTRL+W+REP" - command = ".moveup" - elem - name = "X" - command = ".northeast" - elem - name = "CTRL+X" - command = ".northeast" - elem - name = "Y" - command = "Activate-Held-Object" - elem - name = "CTRL+Y" - command = "Activate-Held-Object" - elem - name = "Z" - command = "Activate-Held-Object" - elem - name = "CTRL+Z" - command = "Activate-Held-Object" - elem - name = "Numpad1" - command = "body-r-leg" - elem - name = "Numpad2" - command = "body-groin" - elem - name = "Numpad3" - command = "body-l-leg" - elem - name = "Numpad4" - command = "body-r-arm" - elem - name = "Numpad5" - command = "body-chest" - elem - name = "Numpad6" - command = "body-l-arm" - elem - name = "Numpad8" - command = "body-toggle-head" - elem - name = "F1" - command = "adminhelp" - elem - name = "CTRL+SHIFT+F1+REP" - command = ".options" - elem - name = "F2" - command = "ooc" - elem - name = "F2+REP" - command = ".screenshot auto" - elem - name = "SHIFT+F2+REP" - command = ".screenshot" - elem - name = "F3" - command = ".say" - elem - name = "F4" - command = ".me" - elem - name = "F5" - command = "msay" - elem - name = "F6" - command = "Player-Panel-New" - elem - name = "F7" - command = "Admin-PM" - elem - name = "F8" - command = "Invisimin" - elem - name = "F12" - command = "F12" - elem - name = "," - command = "move-upwards" - elem - name = "." - command = "move-down" - elem - name = "SHIFT" - command = "setmovingquickly" - elem - name = "SHIFT+UP" - command = "setmovingslowly" - -macro "borgmacro" - elem - name = "Tab" - command = ".winset \"mainwindow.macro=borghotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#f0f0f0\"" - elem - name = "Center+REP" - command = ".center" - elem - name = "Northeast" - command = ".northeast" - elem - name = "Southeast" - command = ".southeast" - elem - name = "Southwest" - command = ".southwest" - elem - name = "Northwest" - command = ".northwest" - elem - name = "ALT+West" - command = "westfaceperm" - elem - name = "CTRL+West" - command = "westface" - elem - name = "West+REP" - command = ".moveleft" - elem - name = "ALT+North" - command = "northfaceperm" - elem - name = "CTRL+North" - command = "northface" - elem - name = "North+REP" - command = ".moveup" - elem - name = "ALT+East" - command = "eastfaceperm" - elem - name = "CTRL+East" - command = "eastface" - elem - name = "East+REP" - command = ".moveright" - elem - name = "ALT+South" - command = "southfaceperm" - elem - name = "CTRL+South" - command = "southface" - elem - name = "South+REP" - command = ".movedown" - elem - name = "Insert" - command = "a-intent right" - elem - name = "CTRL+1" - command = "toggle-module 1" - elem - name = "CTRL+2" - command = "toggle-module 2" - elem - name = "CTRL+3" - command = "toggle-module 3" - elem - name = "CTRL+4" - command = "a-intent left" - elem - name = "CTRL+A+REP" - command = ".moveleft" - elem - name = "CTRL+D+REP" - command = ".moveright" - elem - name = "CTRL+F" - command = "a-intent left" - elem - name = "CTRL+G" - command = "a-intent right" - elem - name = "CTRL+Q" - command = ".northwest" - elem - name = "CTRL+R" - command = ".southwest" - elem - name = "CTRL+S+REP" - command = ".movedown" - elem - name = "CTRL+W+REP" - command = ".moveup" - elem - name = "CTRL+X" - command = ".northeast" - elem - name = "CTRL+Y" - command = "Activate-Held-Object" - elem - name = "CTRL+Z" - command = "Activate-Held-Object" - elem - name = "CTRL+Numpad1" - command = "body-r-leg" - elem - name = "CTRL+Numpad2" - command = "body-groin" - elem - name = "CTRL+Numpad3" - command = "body-l-leg" - elem - name = "CTRL+Numpad4" - command = "body-r-arm" - elem - name = "CTRL+Numpad5" - command = "body-chest" - elem - name = "CTRL+Numpad6" - command = "body-l-arm" - elem - name = "CTRL+Numpad8" - command = "body-toggle-head" - elem - name = "F1" - command = "adminhelp" - elem - name = "CTRL+SHIFT+F1+REP" - command = ".options" - elem - name = "F2" - command = "ooc" - elem - name = "F2+REP" - command = ".screenshot auto" - elem - name = "SHIFT+F2+REP" - command = ".screenshot" - elem - name = "F3" - command = ".say" - elem - name = "F4" - command = ".me" - elem - name = "F5" - command = "msay" - elem - name = "F6" - command = "Player-Panel-New" - elem - name = "F7" - command = "Admin-PM" - elem - name = "F8" - command = "Invisimin" - elem - name = "F12" - command = "F12" - elem - name = "CTRL+Add" - command = "move-upwards" - elem - name = "CTRL+Subtract" - command = "move-down" - - -menu "menu" - elem - name = "&File" - command = "" - saved-params = "is-checked" - elem - name = "&Quick screenshot\tF2" - command = ".screenshot auto" - category = "&File" - saved-params = "is-checked" - elem - name = "&Save screenshot as...\tShift+F2" - command = ".screenshot" - category = "&File" - saved-params = "is-checked" - elem - name = "" - command = "" - category = "&File" - saved-params = "is-checked" - elem - name = "&Reconnect" - command = ".reconnect" - category = "&File" - saved-params = "is-checked" - elem - name = "&Check ping" - command = ".ping" - category = "&File" - saved-params = "is-checked" - elem - name = "&Quit" - command = ".quit" - category = "&File" - saved-params = "is-checked" - elem - name = "&Size" - command = "" - saved-params = "is-checked" - elem "icon128" - name = "&128x128" - command = "SetWindowIconSize 128" - category = "&Size" - can-check = true - group = "size" - saved-params = "is-checked" - elem "icon96" - name = "&96x96" - command = "SetWindowIconSize 96" - category = "&Size" - can-check = true - group = "size" - saved-params = "is-checked" - elem "icon64" - name = "&64x64" - command = "SetWindowIconSize 64" - category = "&Size" - can-check = true - group = "size" - saved-params = "is-checked" - elem "icon48" - name = "&48x48" - command = "SetWindowIconSize 48" - category = "&Size" - is-checked = true - can-check = true - group = "size" - saved-params = "is-checked" - elem "icon32" - name = "&32x32" - command = "SetWindowIconSize 32" - category = "&Size" - can-check = true - group = "size" - saved-params = "is-checked" - elem - name = "&Scaling" - command = "" - saved-params = "is-checked" - elem "NN" - name = "&Nearest Neighbor" - command = ".winset \"mapwindow.map.zoom-mode=distort\"" - category = "&Scaling" - can-check = true - group = "scale" - saved-params = "is-checked" - elem "PS" - name = "&Point Sampling" - command = ".winset \"mapwindow.map.zoom-mode=normal\"" - category = "&Scaling" - can-check = true - group = "scale" - saved-params = "is-checked" - elem "BL" - name = "&Bilinear" - command = ".winset \"mapwindow.map.zoom-mode=blur\"" - category = "&Scaling" - can-check = true - group = "scale" - saved-params = "is-checked" - elem - name = "&Help" - command = "" - saved-params = "is-checked" - elem - name = "&Admin help\tF1" - command = "adminhelp" - category = "&Help" - saved-params = "is-checked" - elem - name = "&Hotkeys" - command = "hotkeys-help" - category = "&Help" - saved-params = "is-checked" - - -window "mainwindow" - elem "mainwindow" - type = MAIN - pos = 281,0 - size = 640x440 - anchor1 = none - anchor2 = none - is-default = true - saved-params = "pos;size;is-minimized;is-maximized" - on-size = "OnResize" - is-maximized = true - icon = 'icons\\ss13_64.png' - macro = "macro" - menu = "menu" - elem "asset_cache_browser" - type = BROWSER - pos = 424,208 - size = 1x1 - anchor1 = none - anchor2 = none - is-visible = false - saved-params = "" - elem "mainvsplit" - type = CHILD - pos = 3,0 - size = 640x420 - anchor1 = 0,0 - anchor2 = 100,100 - saved-params = "splitter" - right = "rpane" - is-vert = true - elem "input" - type = INPUT - pos = 3,420 - size = 517x20 - anchor1 = 0,100 - anchor2 = 100,100 - background-color = #d3b5b5 - is-default = true - border = sunken - saved-params = "command" - elem "saybutton" - type = BUTTON - pos = 520,420 - size = 40x20 - anchor1 = 100,100 - anchor2 = none - saved-params = "is-checked" - text = "Chat" - command = ".winset \"saybutton.is-checked=true?input.command=\"!say \\\"\" macrobutton.is-checked=false:input.command=\"" - button-type = pushbox - elem "hotkey_toggle" - type = BUTTON - pos = 560,420 - size = 80x20 - anchor1 = 100,100 - anchor2 = none - saved-params = "" - text = "Hotkey Toggle" - command = ".winset \"mainwindow.macro!=macro ? mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#d3b5b5 : mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true input.background-color=#f0f0f0\"" - button-type = pushbox - elem "tooltip" - type = BROWSER - pos = 0,0 - size = 999x999 - anchor1 = none - anchor2 = none - background-color = none - is-visible = false - saved-params = "" - -window "mapwindow" - elem "mapwindow" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = none - anchor2 = none - saved-params = "pos;size;is-minimized;is-maximized" - titlebar = false - statusbar = false - can-close = false - can-minimize = false - can-resize = false - is-pane = true - elem "map" - type = MAP - pos = 0,0 - size = 640x480 - anchor1 = 0,0 - anchor2 = 100,100 - font-family = "Arial Rounded MT Bold,Arial Black,Arial,sans-serif" - font-size = 7 - is-default = true - saved-params = "icon-size" - on-show = ".winset\"mainwindow.mainvsplit.left=mapwindow\"" - on-hide = ".winset\"mainwindow.mainvsplit.left=\"" - elem "lobbybrowser" - type = BROWSER - pos = 0,0 - size = 640x480 - anchor1 = 0,0 - anchor2 = 100,100 - is-visible = false - is-disabled = true - saved-params = "" - auto-format = false - -window "outputwindow" - elem "outputwindow" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = none - anchor2 = none - saved-params = "pos;size;is-minimized;is-maximized" - titlebar = false - statusbar = false - can-close = false - can-minimize = false - can-resize = false - is-pane = true - elem "output" - type = OUTPUT - pos = 0,0 - size = 640x480 - anchor1 = 0,0 - anchor2 = 100,100 - is-default = true - saved-params = "max-lines" - style = ".system {color:#ff0000;}" - max-lines = 0 - elem "saybutton_alt" - type = BUTTON - pos = 519,460 - size = 40x20 - anchor1 = 100,100 - anchor2 = none - is-visible = false - is-disabled = true - saved-params = "is-checked" - text = "Chat" - command = ".winset \"saybutton_alt.is-checked=true?input_alt.command=\"!say \\\"\" macrobutton.is-checked=false:input_alt.command=\"" - button-type = pushbox - elem "input_alt" - type = INPUT - pos = 1,460 - size = 517x20 - anchor1 = 0,100 - anchor2 = 100,100 - background-color = #d3b5b5 - is-visible = false - is-disabled = true - is-default = true - border = sunken - saved-params = "command" - elem "hotkey_toggle_alt" - type = BUTTON - pos = 560,460 - size = 80x20 - anchor1 = 100,100 - anchor2 = none - is-visible = false - is-disabled = true - saved-params = "" - text = "Hotkey Toggle" - command = ".winset \"mainwindow.macro!=macro ? mainwindow.macro=macro hotkey_toggle_alt.is-checked=false input_alt.focus=true : mainwindow.macro=hotkeymode hotkey_toggle_alt.is-checked=true mapwindow.map.focus=true\"" - button-type = pushbox - -window "rpane" - elem "rpane" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = none - anchor2 = none - saved-params = "pos;size;is-minimized;is-maximized" - is-pane = true - elem "rpanewindow" - type = CHILD - pos = 0,0 - size = 640x474 - anchor1 = 0,0 - anchor2 = 100,100 - saved-params = "splitter" - right = "outputwindow" - is-vert = false - elem "github" - type = BUTTON - pos = 476,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "GitHub" - command = "GitHub" - elem "BugReport" - type = BUTTON - pos = 536,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "Bug Report" - command = "Bug-Report" - elem "rulesb" - type = BUTTON - pos = 120,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "Rules" - command = "rules" - group = "rpanemode" - elem "changelog" - type = BUTTON - pos = 416,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "Changelog" - command = "Changelog" - group = "rpanemode" - elem "Lore" - type = BUTTON - pos = 208,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "Lore" - command = "Lore" - group = "rpanemode" - elem "forumb" - type = BUTTON - pos = 328,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "Forum" - command = "forum" - group = "rpanemode" - elem "wikib" - type = BUTTON - pos = 268,0 - size = 60x15 - anchor1 = none - anchor2 = none - saved-params = "is-checked" - text = "Wiki" - command = "wiki" - group = "rpanemode" - elem "textb" - type = BUTTON - pos = 0,0 - size = 60x15 - anchor1 = none - anchor2 = none - is-visible = false - saved-params = "is-checked" - text = "Text" - command = ".winset \"rpanewindow.left=;\"" - is-checked = true - group = "rpanemode" - button-type = pushbox - elem "infob" - type = BUTTON - pos = 60,0 - size = 60x15 - anchor1 = none - anchor2 = none - is-visible = false - saved-params = "is-checked" - text = "Info" - command = ".winset \"rpanewindow.left=infowindow\"" - group = "rpanemode" - button-type = pushbox - -window "infowindow" - elem "infowindow" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = none - anchor2 = none - saved-params = "pos;size;is-minimized;is-maximized" - title = "Info" - is-pane = true - elem "info" - type = INFO - pos = 0,0 - size = 638x477 - anchor1 = 0,0 - anchor2 = 100,100 - is-default = true - saved-params = "" - highlight-color = #00aa00 - on-show = ".winset\"rpane.infob.is-visible=true;rpane.infob.pos=65,0 rpane.textb.is-visible=true rpane.infob.is-checked=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0 rpane.rpanewindow.left=infowindow\"" - on-hide = ".winset\"rpane.infob.is-visible=false;rpane.textb.is-visible=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0 rpane.rpanewindow.left=\"" - +macro "default" + elem ".winset :map.right-click=false" + name = "SHIFT+Shift" + elem "Shift" + name = "SHIFT" + command = ".winset :map.right-click=false" + elem "ShiftUp" + name = "SHIFT+UP" + command = ".winset :map.right-click=true" + +menu "menu" + elem + name = "&File" + command = "" + saved-params = "is-checked" + elem + name = "&Save screenshot\tF2" + command = ".auto" + category = "&File" + saved-params = "is-checked" + elem + name = "&Save screenshot as..." + command = ".screenshot" + category = "&File" + saved-params = "is-checked" + elem + name = "" + command = "" + category = "&File" + saved-params = "is-checked" + elem + name = "&Reconnect" + command = ".reconnect" + category = "&File" + saved-params = "is-checked" + elem + name = "&Check ping" + command = ".ping" + category = "&File" + saved-params = "is-checked" + elem + name = "&Quit" + command = ".quit" + category = "&File" + saved-params = "is-checked" + elem + name = "&Size" + command = "" + saved-params = "is-checked" + elem "icon128" + name = "&128x128" + command = "SetWindowIconSize 128" + category = "&Size" + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon96" + name = "&96x96" + command = "SetWindowIconSize 96" + category = "&Size" + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon64" + name = "&64x64" + command = "SetWindowIconSize 64" + category = "&Size" + is-checked = true + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon48" + name = "&48x48" + command = "SetWindowIconSize 48" + category = "&Size" + can-check = true + group = "size" + saved-params = "is-checked" + elem "icon32" + name = "&32x32" + command = "SetWindowIconSize 32" + category = "&Size" + can-check = true + group = "size" + saved-params = "is-checked" + elem + name = "&Scaling" + command = "" + saved-params = "is-checked" + elem "ZM" + name = "&Smooth Scaling" + command = ".winset \"zoommode.is-checked=true?map.zoom-mode=normal:map.zoom-mode=distort\"" + category = "&Scaling" + is-checked = true + can-check = true + group = "scale" + saved-params = "is-checked" + elem "NN" + name = "&Nearest Neighbor" + command = ".winset \"mapwindow.map.zoom-mode=distort\"" + category = "&Scaling" + can-check = true + group = "scale" + saved-params = "is-checked" + elem "PS" + name = "&Point Sampling" + command = ".winset \"mapwindow.map.zoom-mode=normal\"" + category = "&Scaling" + can-check = true + group = "scale" + saved-params = "is-checked" + elem "BL" + name = "&Bilinear" + command = ".winset \"mapwindow.map.zoom-mode=blur\"" + category = "&Scaling" + can-check = true + group = "scale" + saved-params = "is-checked" + elem + name = "&Help" + command = "" + saved-params = "is-checked" + elem + name = "&Admin help\tF1" + command = "adminhelp" + category = "&Help" + saved-params = "is-checked" + +window "mainwindow" + elem "mainwindow" + type = MAIN + pos = 281,0 + size = 640x440 + anchor1 = none + anchor2 = none + is-default = true + background-color = #000000 + saved-params = "pos;size;is-minimized;is-maximized" + on-size = "OnResize" + is-maximized = true + icon = 'icons\\ss13_64.png' + macro = "default" + menu = "menu" + elem "split" + type = CHILD + pos = 3,0 + size = 640x440 + anchor1 = 0,0 + anchor2 = 100,100 + saved-params = "splitter" + left = "mapwindow" + right = "rpane" + is-vert = true + elem "asset_cache_browser" + type = BROWSER + pos = 0,0 + size = 200x200 + anchor1 = none + anchor2 = none + is-visible = false + saved-params = "" + elem "tooltip" + type = BROWSER + pos = 0,0 + size = 999x999 + anchor1 = none + anchor2 = none + background-color = none + is-visible = false + saved-params = "" + +window "mapwindow" + elem "mapwindow" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + elem "map" + type = MAP + pos = 0,0 + size = 640x480 + anchor1 = 0,0 + anchor2 = 100,100 + font-family = "Arial Rounded MT Bold,Arial Black,Arial,sans-serif" + font-size = 7 + is-default = true + saved-params = "icon-size;zoom-mode" + elem "lobbybrowser" + type = BROWSER + pos = 0,0 + size = 640x480 + anchor1 = 0,0 + anchor2 = 100,100 + is-visible = false + is-disabled = true + saved-params = "" + elem "status_bar" + type = LABEL + pos = 0,464 + size = 280x16 + anchor1 = 0,100 + anchor2 = none + text-color = #ffffff + background-color = #222222 + is-visible = false + border = line + saved-params = "" + text = "" + align = left + +window "outputwindow" + elem "outputwindow" + type = MAIN + pos = 281,-30 + size = 640x480 + anchor1 = none + anchor2 = none + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + titlebar = false + statusbar = false + can-close = false + can-minimize = false + can-resize = false + is-pane = true + outer-size = 654x494 + elem "output" + type = OUTPUT + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + is-default = true + saved-params = "max-lines" + style = ".system {color:#ff0000;}" + max-lines = 0 + elem "saybutton" + type = BUTTON + pos = 600,460 + size = 40x20 + anchor1 = 100,100 + anchor2 = none + background-color = none + saved-params = "is-checked" + text = "Chat" + command = ".winset \"saybutton.is-checked=true?input.command=\"!say \\\"\" macrobutton.is-checked=false:input.command=\"" + button-type = pushbox + elem "input" + type = INPUT + pos = 1,460 + size = 600x20 + anchor1 = 0,100 + anchor2 = 100,100 + background-color = #d3b5b5 + is-default = true + border = sunken + saved-params = "command" + +window "rpane" + elem "rpane" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "rpanewindow" + type = CHILD + pos = 0,30 + size = 0x0 + anchor1 = 0,0 + anchor2 = 100,100 + saved-params = "splitter" + left = "infowindow" + right = "outputwindow" + is-vert = false + elem "github" + type = BUTTON + pos = 520,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "GitHub" + command = "GitHub" + elem "BugReport" + type = BUTTON + pos = 580,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Bug Report" + command = "Bug-Report" + elem "rulesb" + type = BUTTON + pos = 205,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Rules" + command = "rules" + group = "rpanemode" + elem "changelog" + type = BUTTON + pos = 460,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Changelog" + command = "Changelog" + group = "rpanemode" + elem "Lore" + type = BUTTON + pos = 265,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Lore" + command = "Lore" + group = "rpanemode" + elem "forumb" + type = BUTTON + pos = 385,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Forum" + command = "forum" + group = "rpanemode" + elem "wikib" + type = BUTTON + pos = 325,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Wiki" + command = "wiki" + group = "rpanemode" + elem "textb" + type = BUTTON + pos = 0,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Text" + command = ".winset \"rpanewindow.left=;\"" + is-checked = true + group = "rpanemode" + button-type = pushbox + elem "infob" + type = BUTTON + pos = 60,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Info" + command = ".winset \"rpanewindow.left=infowindow\"" + group = "rpanemode" + button-type = pushbox + elem "button_codex" + type = BUTTON + pos = 133,0 + size = 60x15 + anchor1 = none + anchor2 = none + saved-params = "is-checked" + text = "Codex" + command = "Codex" + group = "rpanemode" + +window "preferences_window" + elem "preferences_window" + type = MAIN + pos = 281,0 + size = 1000x800 + anchor1 = none + anchor2 = none + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + statusbar = false + elem "preferences_browser" + type = BROWSER + pos = 0,0 + size = 800x800 + anchor1 = 0,0 + anchor2 = 80,100 + saved-params = "" + elem "character_preview_map" + type = MAP + pos = 800,0 + size = 200x800 + anchor1 = 80,0 + anchor2 = 100,100 + right-click = true + saved-params = "zoom;letterbox;zoom-mode" + +window "infowindow" + elem "infowindow" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + title = "Info" + is-pane = true + elem "info" + type = INFO + pos = 0,0 + size = 638x477 + anchor1 = 0,0 + anchor2 = 100,100 + is-default = true + saved-params = "" + highlight-color = #00aa00 + on-show = ".winset\"rpane.infob.is-checked=true\"" + on-hide = ".winset\"rpane.infob.is-checked=false\"" + diff --git a/maps/__map_modpack_compatibility.dm b/maps/__map_modpack_compatibility.dm new file mode 100644 index 000000000000..27024354094b --- /dev/null +++ b/maps/__map_modpack_compatibility.dm @@ -0,0 +1,27 @@ +// This must be included before maps and any modpacks that use it. +// That includes before _map_include.dm. + +/// A spawner that can have its path overridden by a modpack, so that maps can have optional modpack compatibility. +/obj/abstract/modpack_compat + abstract_type = /obj/abstract/modpack_compat + name = "optional modpack object" + desc = "This item type is used to spawn a movable at roundstart, whether a modpack is included or not." + icon = 'icons/misc/mark.dmi' + icon_state = "rup" + var/atom/movable/spawn_object + +/obj/abstract/modpack_compat/Initialize() + ..() + if(ispath(spawn_object)) + new spawn_object + return INITIALIZE_HINT_QDEL + +#define OPTIONAL_SPAWNER(TYPE, VALUE) \ +/obj/abstract/modpack_compat/##TYPE { \ + spawn_object = VALUE; \ +} + +/// This spawner is used to optionally spawn the aliumizer if the random aliens modpack is included. +OPTIONAL_SPAWNER(aliumizer, null) +/// This spawner is used to optionally spawn the hand teleporter if the integrated electronics modpack is included. +OPTIONAL_SPAWNER(hand_tele, null) // todo: add a non-prefab hand tele variant for use without the modpack? \ No newline at end of file diff --git a/maps/__map_names.dm b/maps/__map_names.dm new file mode 100644 index 000000000000..02095976e863 --- /dev/null +++ b/maps/__map_names.dm @@ -0,0 +1,365 @@ +/datum/map + var/list/first_names_male = list( + "Abel", "Adolph", "Alan", "Alden", "Alex", "Alfred", + "Alger", "Allen", "Amos", "Apple", "Archie", "Arnie", + "Art", "Arthur", "Baldric", "Bartholomew", "Bill", "Blake", + "Brayden", "Brendan", "Brock", "Bronte", "Brick", "Bruce", + "Bryce", "Buck", "Burt", "Butch", "Byrne", "Byron", + "Camryn", "Carl", "Carter", "Casimir", "Cassian", "Charles", + "Charlton", "Chip", "Clark", "Claudius", "Clement", "Cleveland", + "Cliff", "Clinton", "Cletus", "Collin", "Crush", "Cy", + "Damian", "Danny", "Darcey", "Darell", "Darin", "Deangelo", + "Denholm", "Desmond", "Devin", "Dirk", "Dominic", "Donny", + "Driscoll", "Duke", "Duncan", "Edgar", "Eliot", "Eliott", + "Elric", "Elwood", "Emmanuel", "Fenton", "Fitz", "Flick", + "Flint", "Flip", "Francis", "Frank", "Frankie", "Fridge", + "Fulton", "Gannon", "Garret", "Gary", "Goddard", "Godwin", + "Goodwin", "Gordon", "Graeme", "Grandpa", "Gratian", "Grendel", + "Han", "Harry", "Hartley", "Harvey", "Henderson", "Holden", + "Homer", "Horatio", "Huffie", "Hungry", "Hugo", "Irvine", + "Jacob", "Jake", "Jamar", "Jamie", "Jamison", "Janel", + "Jaydon", "Jaye", "Jayne", "Jean", "Luc", "Jeb", + "Jed", "Jemmy", "Jermaine", "Jerrie", "Jim", "Joachim", + "Joey", "Johnathan", "John", "Johnny", "Jonathon", "Josh", + "Josiah", "Kennard", "Keziah", "Lando", "Lanny", "Launce", + "Leland", "Lennox", "Lenny", "Leonard", "Leroy", "Lief", + "Linden", "Linton", "Lorde", "Loreto", "Lou", "Lucas", + "Luke", "Malachi", "Malcolm", "Manley", "Marion", "Max", + "Maynard", "Melvyn", "Michael", "Mike", "Milton", "Montague", + "Monte", "Monty", "Nat", "Nathaniel", "Nick", "Nikolas", + "Noah", "Opie", "Osbert", "Osborn", "Osborne", "Osmund", + "Oswald", "Paget", "Patrick", "Patton", "Percival", "Persh", + "Rastus", "Raymond", "Rayner", "Reuben", "Reynard", "Richard", + "Rodger", "Roger", "Romayne", "Roscoe", "Roswell", "Royce", + "Rube", "Rusty", "Sal", "Sawyer", "Scotty", "Seymour", + "Shane", "Shiloh", "Smoke", "Simon", "Sloan", "Sorrel", + "Spike", "Sybil", "Syd", "Tamsin", "Taylor", "Tel", + "Terrell", "Tim", "Timothy", "Todd", "Trip", "Tye", + "Uland", "Ulric", "Vaughn", "Vince", "Vinny", "Walter", + "Ward", "Warner", "Wayne", "Whitaker", "William", "Willy", + "Woodrow", "Zack", "Zane", "Zeke", "Jacob", "Michael", + "Ethan", "Joshua", "Daniel", "Alexander", "Anthony", "William", + "Christopher", "Matthew", "Jayden", "Andrew", "Joseph", "David", + "Noah", "Aiden", "James", "Ryan", "Logan", "John", + "Nathan", "Elijah", "Christian", "Gabriel", "Benjamin", "Jonathan", + "Tyler", "Samuel", "Nicholas", "Gavin", "Dylan", "Jackson", + "Brandon", "Caleb", "Mason", "Angel", "Isaac", "Evan", + "Jack", "Kevin", "Jose", "Isaiah", "Luke", "Landon", + "Justin", "Lucas", "Zachary", "Jordan", "Robert", "Aaron", + "Brayden", "Thomas", "Cameron", "Hunter", "Austin", "Adrian", + "Connor", "Owen", "Aidan", "Jason", "Julian", "Wyatt", + "Charles", "Luis", "Carter", "Juan", "Chase", "Diego", + "Jeremiah", "Brody", "Xavier", "Adam", "Carlos", "Sebastian", + "Liam", "Hayden", "Nathaniel", "Henry", "Jesus", "Ian", + "Tristan", "Bryan", "Sean", "Cole", "Alex", "Eric", + "Brian", "Jaden", "Carson", "Blake", "Ayden", "Cooper", + "Dominic", "Brady", "Caden", "Josiah", "Kyle", "Colton", + "Kaden", "Eli", "Miguel", "Antonio", "Parker", "Steven", + "Alejandro", "Riley", "Richard", "Timothy", "Devin", "Jesse", + "Victor", "Jake", "Joel", "Colin", "Kaleb", "Bryce", + "Levi", "Oliver", "Oscar", "Vincent", "Ashton", "Cody", + "Micah", "Preston", "Marcus", "Max", "Patrick", "Seth", + "Jeremy", "Peyton", "Nolan", "Ivan", "Damian", "Maxwell", + "Alan", "Kenneth", "Jonah", "Jorge", "Mark", "Giovanni", + "Eduardo", "Grant", "Collin", "Gage", "Omar", "Emmanuel", + "Trevor", "Edward", "Ricardo", "Cristian", "Nicolas", "Kayden", + "George", "Jaxon", "Paul", "Braden", "Elias", "Andres", + "Derek", "Garrett", "Tanner", "Malachi", "Conner", "Fernando", + "Cesar", "Javier", "Miles", "Jaiden", "Alexis", "Leonardo", + "Santiago", "Francisco", "Cayden", "Shane", "Edwin", "Hudson", + "Travis", "Bryson", "Erick", "Jace", "Hector", "Josue", + "Peter", "Jaylen", "Mario", "Manuel", "Abraham", "Grayson", + "Damien", "Kaiden", "Spencer", "Stephen", "Edgar", "Wesley", + "Shawn", "Trenton", "Jared", "Jeffrey", "Landen", "Johnathan", + "Bradley", "Braxton", "Ryder", "Camden", "Roman", "Asher", + "Brendan", "Maddox", "Sergio", "Israel", "Andy", "Lincoln", + "Erik", "Donovan", "Raymond", "Avery", "Rylan", "Dalton", + "Harrison", "Andre", "Martin", "Keegan", "Marco", "Jude", + "Sawyer", "Dakota", "Leo", "Calvin", "Kai", "Drake", + "Troy", "Zion", "Clayton", "Roberto", "Zane", "Gregory", + "Tucker", "Rafael", "Kingston", "Dominick", "Ezekiel", "Griffin", + "Devon", "Drew", "Lukas", "Johnny", "Ty", "Pedro", + "Tyson", "Caiden", "Mateo", "Braylon", "Cash", "Aden", + "Chance", "Taylor", "Marcos", "Maximus", "Ruben", "Emanuel", + "Simon", "Corbin", "Brennan", "Dillon", "Skyler", "Myles", + "Xander", "Jaxson", "Dawson", "Kameron", "Kyler", "Axel", + "Colby", "Jonas", "Joaquin", "Payton", "Brock", "Frank", + "Enrique", "Quinn", "Emilio", "Malik", "Grady", "Angelo", + "Julio", "Derrick", "Raul", "Fabian", "Corey", "Gerardo", + "Dante", "Ezra", "Armando", "Allen", "Theodore", "Gael", + "Amir", "Zander", "Adan", "Maximilian", "Randy", "Easton", + "Dustin", "Luca", "Phillip", "Julius", "Charlie", "Ronald", + "Jakob", "Cade", "Brett", "Trent", "Silas", "Keith", + "Emiliano", "Trey", "Jalen", "Darius", "Lane", "Jerry", + "Jaime", "Scott", "Graham", "Weston", "Braydon", "Anderson", + "Rodrigo", "Pablo", "Saul", "Danny", "Donald", "Elliot", + "Brayan", "Dallas", "Lorenzo", "Casey", "Mitchell", "Alberto", + "Tristen", "Rowan", "Jayson", "Gustavo", "Aaden", "Amari", + "Dean", "Braeden", "Declan", "Chris", "Ismael", "Dane", + "Louis", "Arturo", "Brenden", "Felix", "Jimmy", "Cohen", + "Tony", "Holden", "Reid", "Abel", "Bennett", "Zackary", + "Arthur", "Nehemiah", "Ricky", "Esteban", "Cruz", "Finn", + "Mauricio", "Dennis", "Keaton", "Albert", "Marvin", "Mathew", + "Moises", "Issac", "Philip", "Quentin", "Curtis", "Greyson", + "Jameson", "Everett", "Jayce", "Darren", "Elliott", "Uriel", + "Alfredo", "Hugo", "Alec", "Jamari", "Marshall", "Walter", + "Judah", "Jay", "Lance", "Beau", "Ali", "Landyn", + "Yahir", "Phoenix", "Nickolas", "Kobe", "Bryant", "Maurice", + "Russell", "Leland", "Colten", "Reed", "Davis", "Joe", + "Ernesto", "Desmond", "Kade", "Reece", "Morgan", "Ramon", + "Rocco", "Orlando", "Ryker", "Brodie", "Paxton", "Jacoby", + "Douglas", "Kristopher", "Gary", "Lawrence", "Izaiah", "Solomon", + "Nikolas", "Mekhi", "Justice", "Tate", "Jaydon", "Salvador", + "Shaun", "Alvin", "Eddie", "Kane", "Davion", "Zachariah", + "Damien", "Titus", "Kellen", "Camron", "Isiah", "Javon", + "Nasir", "Milo", "Johan", "Byron", "Jasper", "Jonathon", + "Chad", "Marc", "Kelvin", "Chandler", "Sam", "Cory", + "Deandre", "River", "Reese", "Roger", "Quinton", "Talon", + "Romeo", "Franklin", "Noel", "Alijah", "Guillermo", "Gunner", + "Damon", "Jadon", "Emerson", "Micheal", "Bruce", "Terry", + "Kolton", "Melvin", "Beckett", "Porter", "August", "Brycen", + "Dayton", "Jamarion", "Leonel", "Karson", "Zayden", "Keagan", + "Carl", "Khalil", "Cristopher", "Nelson", "Braiden", "Moses", + "Isaias", "Roy", "Triston", "Walker", "Kale", "Larry" + ) + var/list/first_names_female = list( + "Aida", "Alexa", "Alexandria", "Alexis", "Alexus", "Alfreda", + "Alisa", "Alisya", "Allegra", "Allegria", "Alma", "Alysha", + "Alyssia", "Amaryllis", "Ambrosine", "Angel", "Anjelica", "Anne", + "Arabella", "Arielle", "Arleen", "Ashlie", "Astor", "Aubrey", + "Avalona", "Averill", "Barbara", "Beckah", "Becky", "Bernice", + "Bethney", "Betsy", "Bidelia", "Breanne", "Brittani", "Brooke", + "Cadence", "Calanthia", "Caleigh", "Candace", "Candice", "Carly", + "Carlyle", "Carolyn", "Carry", "Caryl", "Cecily", "Cherette", + "Cheri", "Cherry", "Christa", "Christiana", "Christobelle", "Claribel", + "Clover", "Coreen", "Corrine", "Cynthia", "Dalya", "Daniella", + "Daria", "Dayna", "Debbi", "Dee", "Deena", "Della", + "Delma", "Denys", "Diamond", "Dina", "Dolores", "Donella", + "Donna", "Dorothy", "Dortha", "Easter", "Ebba", "Effie", + "Elizabeth", "Elle", "Emma", "Ermintrude", "Esmeralda", "Eugenia", + "Euphemia", "Eustace", "Eveleen", "Evelina", "Fay", "Floella", + "Flora", "Flossie", "Fortune", "Genette", "Georgene", "Geraldine", + "Gervase", "Gina", "Ginger", "Gladwyn", "Glenna", "Greta", + "Griselda", "Gwenda", "Gwenevere", "Hadley", "Haidee", "Hailey", + "Hal", "Haleigh", "Hayley", "Heather", "Hedley", "Helen", + "Hepsie", "Hortensia", "Iantha", "Ileen", "Innocent", "Irene", + "Jacaline", "Jacquetta", "Jacqui", "Jakki", "Jalen", "Janelle", + "Janette", "Janie", "Janina", "Janine", "Jasmine", "Jaylee", + "Jaynie", "Jeanna", "Jeannie", "Jeannine", "Jenifer", "Jennie", + "Jera", "Jere", "Jeri", "Jillian", "Jillie", "Joetta", + "Joi", "Joni", "Josepha", "Joye", "Julia", "July", + "Kaelea", "Kaleigh", "Karenza", "Karly", "Karyn", "Kat", + "Kathy", "Katlyn", "Kayleigh", "Keegan", "Keira", "Keith", + "Kellie", "Kerena", "Kerensa", "Keturah", "Kimberley", "Lacy", + "Lakeisha", "Lalla", "Latanya", "Laurencia", "Laurissa", "Leeann", + "Leia", "Lessie", "Leta", "Lexia", "Lexus", "Lindsie", + "Lindy", "Lockie", "Lori", "Lorin", "Luanne", "Lucian", + "Luvenia", "Lyndsey", "Lynn", "Lynsey", "Lynwood", "Mabelle", + "Macey", "Madyson", "Maegan", "Marcia", "Mariabella", "Marilene", + "Marion", "Marje", "Marjory", "Marlowe", "Marlyn", "Marshall", + "Maryann", "Maudie", "Maurene", "May", "Merideth", "Merrilyn", + "Meryl", "Minnie", "Monna", "Muriel", "Mya", "Myriam", + "Myrtie", "Nan", "Nelle", "Nena", "Nerissa", "Netta", + "Nettie", "Nonie", "Nova", "Nowell", "Nydia", "Olive", + "Oralie", "Patience", "Pauleen", "Pene", "Peregrine", "Pheobe", + "Phoebe", "Phyliss", "Phyllida", "Phyllis", "Porsche", "Prosper", + "Prue", "Quanah", "Quiana", "Raelene", "Rain", "Randa", + "Randal", "Rebeckah", "Reene", "Renie", "Rexana", "Rhetta", + "Ronnette", "Rosemary", "Rubye", "Sabella", "Sachie", "Sally", + "Saranna", "Seneca", "Shana", "Shanika", "Shannah", "Shannon", + "Shantae", "Sharalyn", "Sharla", "Sheri", "Sherie", "Sherill", + "Sherri", "Sissy", "Sophie", "Star", "Steph", "Stephany", + "Sue", "Sukie", "Sunshine", "Susanna", "Susannah", "Suzan", + "Suzy", "Sydney", "Tamika", "Tania", "Tansy", "Tatyanna", + "Tiffany", "Tolly", "Topaz", "Tori", "Tracee", "Tracey", + "Ulyssa", "Valary", "Verna", "Vinnie", "Vivyan", "Wendi", + "Wisdom", "Wynonna", "Wynter", "Yasmin", "Yolanda", "Ysabel", + "Zelda", "Zune", "Emma", "Isabella", "Emily", "Madison", + "Ava", "Olivia", "Sophia", "Abigail", "Elizabeth", "Chloe", + "Samantha", "Addison", "Natalie", "Mia", "Alexis", "Alyssa", + "Hannah", "Ashley", "Ella", "Sarah", "Grace", "Taylor", + "Brianna", "Lily", "Hailey", "Anna", "Victoria", "Kayla", + "Lillian", "Lauren", "Kaylee", "Allison", "Savannah", "Nevaeh", + "Gabriella", "Sofia", "Makayla", "Avery", "Riley", "Julia", + "Leah", "Aubrey", "Jasmine", "Audrey", "Katherine", "Morgan", + "Brooklyn", "Destiny", "Sydney", "Alexa", "Kylie", "Brooke", + "Kaitlyn", "Evelyn", "Layla", "Madeline", "Kimberly", "Zoe", + "Jessica", "Peyton", "Alexandra", "Claire", "Madelyn", "Maria", + "Mackenzie", "Arianna", "Jocelyn", "Amelia", "Angelina", "Trinity", + "Andrea", "Maya", "Valeria", "Sophie", "Rachel", "Vanessa", + "Aaliyah", "Mariah", "Gabrielle", "Katelyn", "Ariana", "Bailey", + "Camila", "Jennifer", "Melanie", "Gianna", "Charlotte", "Paige", + "Autumn", "Payton", "Faith", "Sara", "Isabelle", "Caroline", + "Isabel", "Mary", "Zoey", "Gracie", "Megan", "Haley", + "Mya", "Michelle", "Molly", "Stephanie", "Nicole", "Jenna", + "Natalia", "Sadie", "Jada", "Serenity", "Lucy", "Ruby", + "Eva", "Kennedy", "Rylee", "Jayla", "Naomi", "Rebecca", + "Lydia", "Daniela", "Bella", "Keira", "Adriana", "Lilly", + "Hayden", "Miley", "Katie", "Jade", "Jordan", "Gabriela", + "Amy", "Angela", "Melissa", "Valerie", "Giselle", "Diana", + "Amanda", "Kate", "Laila", "Reagan", "Jordyn", "Kylee", + "Danielle", "Briana", "Marley", "Leslie", "Kendall", "Catherine", + "Liliana", "Mckenzie", "Jacqueline", "Ashlyn", "Reese", "Marissa", + "London", "Juliana", "Shelby", "Cheyenne", "Angel", "Daisy", + "Makenzie", "Miranda", "Erin", "Amber", "Alana", "Ellie", + "Breanna", "Ana", "Mikayla", "Summer", "Piper", "Adrianna", + "Jillian", "Sierra", "Jayden", "Sienna", "Alicia", "Lila", + "Margaret", "Alivia", "Brooklynn", "Karen", "Violet", "Sabrina", + "Stella", "Aniyah", "Annabelle", "Alexandria", "Kathryn", "Skylar", + "Aliyah", "Delilah", "Julianna", "Kelsey", "Khloe", "Carly", + "Amaya", "Mariana", "Christina", "Alondra", "Tessa", "Eliana", + "Bianca", "Jazmin", "Clara", "Vivian", "Josephine", "Delaney", + "Scarlett", "Elena", "Cadence", "Alexia", "Maggie", "Laura", + "Nora", "Ariel", "Elise", "Nadia", "Mckenna", "Chelsea", + "Lyla", "Alaina", "Jasmin", "Hope", "Leila", "Caitlyn", + "Cassidy", "Makenna", "Allie", "Izabella", "Eden", "Callie", + "Haylee", "Caitlin", "Kendra", "Karina", "Kyra", "Kayleigh", + "Addyson", "Kiara", "Jazmine", "Karla", "Camryn", "Alina", + "Lola", "Kyla", "Kelly", "Fatima", "Tiffany", "Kira", + "Crystal", "Mallory", "Esmeralda", "Alejandra", "Eleanor", "Angelica", + "Jayda", "Abby", "Kara", "Veronica", "Carmen", "Jamie", + "Ryleigh", "Valentina", "Allyson", "Dakota", "Kamryn", "Courtney", + "Cecilia", "Madeleine", "Aniya", "Alison", "Esther", "Heaven", + "Aubree", "Lindsey", "Leilani", "Nina", "Melody", "Macy", + "Ashlynn", "Joanna", "Cassandra", "Alayna", "Kaydence", "Madilyn", + "Aurora", "Heidi", "Emerson", "Kimora", "Madalyn", "Erica", + "Josie", "Katelynn", "Guadalupe", "Harper", "Ivy", "Lexi", + "Camille", "Savanna", "Dulce", "Daniella", "Lucia", "Emely", + "Joselyn", "Kiley", "Kailey", "Miriam", "Cynthia", "Rihanna", + "Georgia", "Rylie", "Harmony", "Kiera", "Kyleigh", "Monica", + "Bethany", "Kaylie", "Cameron", "Teagan", "Cora", "Brynn", + "Ciara", "Genevieve", "Alice", "Maddison", "Eliza", "Tatiana", + "Jaelyn", "Erika", "Ximena", "April", "Marely", "Julie", + "Danica", "Presley", "Brielle", "Julissa", "Angie", "Iris", + "Brenda", "Hazel", "Rose", "Malia", "Shayla", "Fiona", + "Phoebe", "Nayeli", "Paola", "Kaelyn", "Selena", "Audrina", + "Rebekah", "Carolina", "Janiyah", "Michaela", "Penelope", "Janiya", + "Anastasia", "Adeline", "Ruth", "Sasha", "Denise", "Holly", + "Madisyn", "Hanna", "Tatum", "Marlee", "Nataly", "Helen", + "Janelle", "Lizbeth", "Serena", "Anya", "Jaslene", "Kaylin", + "Jazlyn", "Nancy", "Lindsay", "Desiree", "Hayley", "Itzel", + "Imani", "Madelynn", "Asia", "Kadence", "Madyson", "Talia", + "Jane", "Kayden", "Annie", "Amari", "Bridget", "Raegan", + "Jadyn", "Celeste", "Jimena", "Luna", "Yasmin", "Emilia", + "Annika", "Estrella", "Sarai", "Lacey", "Ayla", "Alessandra", + "Willow", "Nyla", "Dayana", "Lilah", "Lilliana", "Natasha", + "Hadley", "Harley", "Priscilla", "Claudia", "Allisson", "Baylee", + "Brenna", "Brittany", "Skyler", "Fernanda", "Danna", "Melany", + "Cali", "Lia", "Macie", "Lyric", "Logan", "Gloria", + "Lana", "Mylee", "Cindy", "Lilian", "Amira", "Anahi", + "Alissa", "Anaya", "Lena", "Ainsley", "Sandra", "Noelle", + "Marisol", "Meredith", "Kailyn", "Lesly", "Johanna", "Diamond", + "Evangeline", "Juliet", "Kathleen", "Meghan", "Paisley", "Athena", + "Hailee", "Rosa", "Wendy", "Emilee", "Sage", "Alanna", + "Elaina", "Cara", "Nia", "Paris", "Casey", "Dana", + "Emery", "Rowan", "Aubrie", "Kaitlin", "Jaden", "Kenzie", + "Kiana", "Viviana", "Norah", "Lauryn", "Perla", "Amiyah", + "Alyson", "Rachael", "Shannon", "Aileen", "Miracle", "Lillie", + "Danika", "Heather", "Kassidy", "Taryn", "Tori", "Francesca", + "Kristen", "Amya", "Elle", "Kristina", "Cheyanne", "Haylie", + "Patricia", "Anne", "Samara" + ) + var/list/last_names = list( + "Whittier", "Dimeling", "Blaine", "Dennis", "Adams", "Rader", + "Murray", "Millhouse", "Ludwig", "Burris", "Shupe", "Mary", + "Zadovsky", "Philips", "Wise", "Gronko", "Jardine", "Black", + "Mitchell", "Enderly", "Stall", "Harrow", "Atweeke", "Sealis", + "Conrad", "Lucy", "Stewart", "Green", "Feufer", "Warren", + "Campbell", "Shafer", "Woodworth", "Magor", "Logue", "Reichard", + "Day", "Dugmore", "Murray", "Greenawalt", "Jyllian", "Osterwise", + "Styles", "Cavalet", "Garneys", "Raub", "Sholl", "Chauvin", + "Poley", "Todd", "Brandenburg", "Baer", "Pritchard", "Pinney", + "Kadel", "Anderson", "Clarke", "Hunt", "Gadow", "Stough", + "Marcotte", "Brooks", "Watson", "Nash", "Sheets", "Ashbaugh", + "Zimmer", "Noton", "Dean", "Fleming", "Draudy", "Bluetenberger", + "Fischer", "Hawkins", "Poehl", "Addison", "Mcintosh", "Keppel", + "Kimple", "Alice", "Stone", "Fiscina", "Leichter", "Wile", + "Callison", "Cowper", "Harrold", "Carr", "Eckhardstein", "Wilkerson", + "Shirey", "Benford", "Reade", "Baskett", "Seidner", "Gettemy", + "Joyce", "Judge", "Burkett", "Kiefer", "Carmichael", "Hirleman", + "Wells", "Isemann", "Cressman", "Highlands", "Briggs", "Rowley", + "Coldsmith", "Berkheimer", "Hill", "Maclagan", "Mcfall", "Mens", + "Braun", "James", "Sloan", "Bould", "Overstreet", "Kanaga", + "Polson", "Finlay", "Sandys", "Bousum", "Howard", "Treeby", + "Stainforth", "Werner", "Sulyard", "Marriman", "Weinstein", "Butterfill", + "Mason", "Coates", "Peters", "Gregory", "Wilo", "Edwards", + "Barnes", "Harding", "Tireman", "Lombardi", "Roberts", "Faqua", + "Basmanoff", "Mccune", "Mckendrick", "Oppenheimer", "Oneal", "Focell", + "Tedrow", "Fields", "Ryals", "Best", "Zaun", "Knapp", + "Linton", "Jackson", "Bullard", "Mcloskey", "Zoucks", "Heckendora", + "Hoenshell", "Woollard", "Mueller", "Burns", "Franks", "Goodman", + "Stern", "Robinson", "Hooker", "David", "Fitzgerald", "Vanleer", + "Beach", "Flickinger", "Metzer", "Bynum", "Stafford", "Osteen", + "Johnson", "Paynter", "Thomlinson", "Simmons", "Basinger", "Fisher", + "Bunten", "Compton", "Archibald", "Catherina", "Rahl", "Bowchiew", + "Tennant", "Mccullough", "Margaret", "Schaeffer", "Sommer", "Beail", + "Merryman", "Knapenberger", "Patterson", "Houston", "Lacon", "Levett", + "Sullivan", "Sidower", "Laborde", "Stroh", "Hice", "Biery", + "Christman", "Staymates", "Sauter", "Snyder", "Bratton", "Sybilla", + "Altmann", "Mathews", "Newbern", "Baker", "Kemble", "Mingle", + "Unk", "Otis", "Quinn", "Bell", "Roberts", "Wood", + "Ullman", "Bicknell", "Gibson", "Rohtin", "James", "Wallick", + "Eggbert", "Losey", "Neely", "Catleay", "McDonald", "Beedell", + "Williamson", "Bennett", "Potter", "Caldwell", "Lowe", "Durstine", + "King", "Gardner", "Ulery", "Rifler", "Trovato", "Thomas", + "Nehling", "Baum", "Werry", "Mcmullen", "Koster", "Willey", + "Mildred", "Straub", "Haynes", "Baxter", "Ackerley", "Greene", + "Atkinson", "Davis", "Weeter", "Milne", "Leech", "Clewett", + "Ewing", "Hook", "Reighner", "Welty", "Jenkins", "Bennett", + "Swarner", "Hawker", "Agg", "Batten", "Cherry", "Shaffer", + "Yeskey", "Stephenson", "Pycroft", "Larson", "Joghs", "Keener", + "Christopher", "Roadman", "Echard", "Priebe", "Auman", "Kemerer", + "Sutton", "Prechtl", "Cowart", "Ringer", "Garratt", "Siegrist", + "Seelig", "Lafortune", "Dryfus", "Isaman", "Teagarden", "Evans", + "Wolfe", "Fiddler", "Jowers", "Aultman", "Olphert", "Howe", + "Leslie", "Stocker", "Bode", "Whirlow", "Ann", "Mcclymonds", + "Guess", "Taggart", "Pratt", "Moon", "Huey", "Hegarty", + "Meyers", "Stahl", "Nickolson", "Mortland", "Perkins", "Thorley", + "Fuchs", "Ray", "Schrader", "Kellogg", "Woodward", "Faust", + "Roby", "Bashline", "Cypret", "Laurenzi", "Minnie", "Houser", + "Langston", "Anderson", "Barrett", "Wible", "Hujsak", "Wardle", + "Pershing", "Kuster", "Driggers", "Wheeler", "Garland", "Alliman", + "Hoover", "Camp", "Hall", "Parkinson", "Swabey", "Mull", + "Cox", "Hanford", "Stange", "Wolff", "Jesse", "Brinigh", + "Koepple", "Schmidt", "Muller", "Schofield", "Zalack", "Pfeifer", + "Fea", "Blackburn", "Ward", "Kifer", "Costello", "Donkin", + "Osterweis", "Brindle", "Llora", "Duncan", "Ehret", "Fryer", + "Summy", "Richards", "Boyer", "Hutton", "Mosser", "Lester", + "Stroble", "Randolph", "Lord", "Scott", "Nicholas", "Smail", + "Ratcliff", "Riggle", "Newton", "Sanders", "Mitchell", "Lauffer", + "Aggley", "Moberly", "Hynes", "Pennington", "Woolery", "Hardie", + "Blessig", "Tanner", "Demuth", "Fraser", "Henry", "Shick", + "Ironmonger", "Scherer", "Field", "Prevatt", "Earl", "Paulson", + "Curry", "Powers", "Rosensteel", "Hoopengarner", "Weisgarber", "Elliott", + "Pearsall", "Lowstetter", "Holdeman", "Kepplinger", "Bloise", "Hunter", + "Glover", "Hayhurst", "Wentzel", "Owens", "Smith", "Steele", + "Leach", "Armstrong", "Wheeler", "Easter", "Greenwood", "Woodward", + "Pratt", "Buzzard", "Cox", "Eliza", "Rockwell", "Zeal", + "Harshman", "Northey", "Tilton", "Richter", "Moore", "Jerome", + "Hardy", "Bickerson", "White", "Beck", "Waldron", "Fulton", + "Miller", "Sandford", "Hughes", "Winton", "Digson", "Byers", + "Hincken", "Shaner", "Todd", "Whiteman", "Lineman", "Albright", + "Hastings", "Elderson", "Garrison", "Rose", "Kelley", "Quirin", + "Dickinson", "Young", "Ramos", "Jewell", "Endsley", "Briner", + "Jenner", "Saylor", "Bash", "Blyant", "Rhinehart", "Prescott", + "Kirkson", "Stamos", "Sagan", "Hawking", "Dawkins", "McShain", + "McDonohugh", "Power", "Smith", "Jones", "Williams", "Brown", + "Taylor", "Davies", "Wilson", "Evans", "Thomas", "Roberts", + "Johnson", "Walker", "Wright", "Robinson", "Thompson", "Hughes", + "White", "Edwards", "Hall", "Patel", "Green", "Martins", + "Lewis", "Wood", "Jackson", "Clarke", "Harris", "Clark", + "Scott", "Turner", "Hill", "Moore", "Cooper", "Morris", + "Ward", "Watson", "Morgan", "Anderson", "Harrison", "King", + "Campbell", "Young", "Mitchell", "Baker", "James", "Kelly", + "Allen", "Bell", "Phillips", "Lee", "Stewart", "Miller", + "Parker", "Simpson", "Bennett", "Davis", "Griffiths", "Shaw", + "Price", "Cook", "Richardson", "Murray", "Marshall", "Begum", + "Murphy", "Khan", "Gray", "Collins", "Bailey", "Carter", + "Robertson", "Graham", "Adams", "Richards", "Cox", "Singh", + "Hussain", "Ellis", "Wilkinson", "Foster", "Thomson", "Russell", + "Ali", "Reid", "Rathens", "Rathen", "Mason", "Chapman", + "Powell", "Owen", "Ahmed", "Gibson", "Rogers", "Webb", + "Holmes", "Mills", "Matthews", "Hunt", "Palmer", "Lloyd", + "Kaur", "Fisher", "Ivanov", "Smirnov", "Vasilyev", "Petrov", + "Kuznetsov", "Mikhaylov", "Pavlov", "Semenov", "Andreev", "Alekseev" + ) \ No newline at end of file diff --git a/maps/antag_spawn/antag_spawn_bases.dm b/maps/antag_spawn/antag_spawn_bases.dm deleted file mode 100644 index f6e58b5626f3..000000000000 --- a/maps/antag_spawn/antag_spawn_bases.dm +++ /dev/null @@ -1,2 +0,0 @@ -/datum/map_template/ruin/antag_spawn - prefix = "maps/antag_spawn/" \ No newline at end of file diff --git a/maps/antag_spawn/deity/deity.dm b/maps/antag_spawn/deity/deity.dm deleted file mode 100644 index 1ba8ddd7a010..000000000000 --- a/maps/antag_spawn/deity/deity.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/map_template/ruin/antag_spawn/deity - name = "Deity Base" - id = MODE_DEITY + "_spawn" - suffixes = list("deity/deity_base.dmm") - -/area/map_template/deity_spawn - name = "\improper Deity Spawn" - icon_state = "yellow" - requires_power = 0 - dynamic_lighting = 0 \ No newline at end of file diff --git a/maps/antag_spawn/deity/deity_base.dmm b/maps/antag_spawn/deity/deity_base.dmm deleted file mode 100644 index ffd6cbc2a3e9..000000000000 --- a/maps/antag_spawn/deity/deity_base.dmm +++ /dev/null @@ -1,1051 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/space/infinity, -/area/map_template/deity_spawn) -"b" = ( -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "lava" - }, -/area/map_template/deity_spawn) -"c" = ( -/turf/unsimulated/floor{ - dir = 2; - icon = 'icons/misc/beach.dmi'; - icon_state = "seashallow"; - name = "water" - }, -/area/map_template/deity_spawn) -"d" = ( -/obj/effect/landmark{ - name = "DeitySpawn" - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "lava" - }, -/area/map_template/deity_spawn) -"e" = ( -/obj/effect/landmark{ - name = "DeitySpawn" - }, -/turf/unsimulated/floor{ - dir = 2; - icon = 'icons/misc/beach.dmi'; - icon_state = "seashallow"; - name = "water" - }, -/area/map_template/deity_spawn) - -(1,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(2,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(3,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(4,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(5,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(6,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(7,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(8,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(9,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(10,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(11,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(12,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(13,1,1) = {" -a -a -a -a -b -b -b -b -b -b -d -b -b -b -b -b -b -a -a -a -a -"} -(14,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(15,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(16,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(17,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(18,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(19,1,1) = {" -a -a -a -a -b -b -b -b -b -b -b -b -b -b -b -b -b -a -a -a -a -"} -(20,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(21,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(22,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(23,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(24,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(25,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(26,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(27,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(28,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(29,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(30,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(31,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(32,1,1) = {" -a -a -a -a -c -c -c -c -c -c -e -c -c -c -c -c -c -a -a -a -a -"} -(33,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(34,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(35,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(36,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(37,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(38,1,1) = {" -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -"} -(39,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(40,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(41,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(42,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(43,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(44,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} diff --git a/maps/antag_spawn/ert/ert.dm b/maps/antag_spawn/ert/ert.dm deleted file mode 100644 index 4dc62c4adf4b..000000000000 --- a/maps/antag_spawn/ert/ert.dm +++ /dev/null @@ -1,59 +0,0 @@ -/datum/map_template/ruin/antag_spawn/ert - name = "ERT Base" - id = MODE_ERT + "_spawn" - suffixes = list("ert/ert_base.dmm") - shuttles_to_initialise = list(/datum/shuttle/autodock/multi/antag/rescue) - apc_test_exempt_areas = list( - /area/map_template/rescue_base = NO_SCRUBBER|NO_VENT|NO_APC - ) - - -/datum/shuttle/autodock/multi/antag/rescue - name = "Rescue" - warmup_time = 0 - defer_initialisation = TRUE - destination_tags = list( - "nav_ert_dock", - "nav_ert_start" - ) - shuttle_area = /area/map_template/rescue_base/start - dock_target = "rescue_shuttle" - current_location = "nav_ert_start" - landmark_transition = "nav_ert_transition" - home_waypoint = "nav_ert_start" - announcer = "Proximity Sensor Array" - arrival_message = "Attention, vessel detected entering vessel proximity." - departure_message = "Attention, vessel detected leaving vessel proximity." - -/obj/effect/shuttle_landmark/ert/start - name = "Response Team Base" - landmark_tag = "nav_ert_start" - docking_controller = "rescue_base" - -/obj/effect/shuttle_landmark/ert/internim - name = "In transit" - landmark_tag = "nav_ert_transition" - -/obj/effect/shuttle_landmark/ert/dock - name = "Docking Port" - landmark_tag = "nav_ert_dock" - docking_controller = "rescue_shuttle_dock_airlock" - -// Areas - -/area/map_template/rescue_base - name = "\improper Response Team Base" - icon_state = "yellow" - requires_power = 0 - dynamic_lighting = 1 - area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED - -/area/map_template/rescue_base/base - name = "\improper Barracks" - icon_state = "yellow" - dynamic_lighting = 0 - -/area/map_template/rescue_base/start - name = "\improper Response Team Base" - icon_state = "shuttlered" - base_turf = /turf/unsimulated/floor/rescue_base \ No newline at end of file diff --git a/maps/antag_spawn/ert/ert_base.dmm b/maps/antag_spawn/ert/ert_base.dmm deleted file mode 100644 index dd7bb91bc231..000000000000 --- a/maps/antag_spawn/ert/ert_base.dmm +++ /dev/null @@ -1,6370 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"ab" = ( -/turf/simulated/floor/wood, -/area/map_template/rescue_base/base) -"ac" = ( -/turf/unsimulated/mineral, -/area/map_template/rescue_base/base) -"ad" = ( -/turf/unsimulated/wall, -/area/map_template/rescue_base/base) -"ae" = ( -/obj/machinery/computer/teleporter{ - icon_state = "computer"; - dir = 2 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"af" = ( -/obj/machinery/teleport/station, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ag" = ( -/obj/machinery/teleport/hub, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ah" = ( -/turf/unsimulated/wall{ - desc = "A secure airlock. Doesn't look like you can get through easily."; - icon = 'icons/obj/doors/centcomm/door.dmi'; - icon_state = "closed"; - name = "Facility Access" - }, -/area/map_template/rescue_base/base) -"ai" = ( -/obj/structure/table/steel_reinforced, -/obj/item/clothing/shoes/magboots/rig/combat, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aj" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/firstaid/regular, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"ak" = ( -/obj/machinery/floodlight, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"al" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/box/bodybags, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"am" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/firstaid/surgery, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"an" = ( -/turf/simulated/floor/wood/mahogany, -/area/map_template/rescue_base/base) -"ao" = ( -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"ap" = ( -/obj/machinery/door/airlock/centcom{ - name = "Emergency Insertion"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"aq" = ( -/obj/structure/table/steel_reinforced, -/obj/item/taperecorder, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"ar" = ( -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"as" = ( -/obj/structure/table/steel_reinforced, -/obj/item/bikehorn/rubberducky, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"at" = ( -/turf/simulated/floor/wood/maple, -/area/map_template/rescue_base/base) -"au" = ( -/obj/structure/hygiene/toilet{ - pixel_y = 16 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"av" = ( -/obj/structure/hygiene/shower{ - icon_state = "shower"; - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"aw" = ( -/obj/item/soap, -/obj/structure/hygiene/shower{ - pixel_y = 32 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"ax" = ( -/obj/structure/table/steel_reinforced, -/obj/item/assembly/mousetrap, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"ay" = ( -/obj/structure/bed/chair, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"az" = ( -/obj/structure/table/steel_reinforced, -/obj/item/twohanded/baseballbat/aluminium, -/obj/item/hatchet, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aA" = ( -/turf/simulated/floor/wood/walnut, -/area/map_template/rescue_base/base) -"aB" = ( -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"aC" = ( -/obj/item/aiModule/reset, -/obj/item/aiModule/freeformcore, -/obj/item/aiModule/protectStation, -/obj/item/aiModule/quarantine, -/obj/item/aiModule/paladin, -/obj/item/aiModule/robocop, -/obj/item/aiModule/safeguard, -/obj/structure/table/rack, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aD" = ( -/obj/structure/table/rack, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/plastique, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aE" = ( -/obj/structure/table/rack, -/obj/item/gun/projectile/shotgun/pump, -/obj/item/gun/projectile/shotgun/pump, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aF" = ( -/obj/structure/table/rack, -/obj/item/storage/box/ammo/stunshells, -/obj/item/storage/box/ammo/stunshells, -/obj/item/storage/box/ammo/beanbags, -/obj/item/storage/box/ammo/beanbags, -/obj/item/storage/box/ammo/shotgunammo, -/obj/item/storage/box/ammo/shotgunammo, -/obj/item/storage/box/ammo/shotgunshells, -/obj/item/storage/box/ammo/shotgunshells, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aG" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/gun/nuclear, -/obj/item/gun/energy/gun/nuclear, -/obj/item/gun/energy/gun/nuclear, -/obj/item/gun/energy/gun/nuclear, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aH" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/syringe/drugs{ - pixel_x = 3; - pixel_y = -1 - }, -/obj/item/chems/syringe/drugs{ - pixel_x = 3; - pixel_y = 4 - }, -/obj/item/chems/syringe/drugs{ - pixel_x = 3; - pixel_y = 9 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aI" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/belt/utility/full, -/obj/item/assembly/igniter, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aJ" = ( -/turf/simulated/floor/wood/ebony, -/area/map_template/rescue_base/base) -"aK" = ( -/obj/structure/mopbucket, -/obj/item/mop, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/hygiene/sink/kitchen{ - pixel_y = 21 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aL" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aM" = ( -/obj/structure/table/reinforced, -/obj/machinery/chemical_dispenser/bar_soft/full, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aN" = ( -/obj/structure/table/reinforced, -/obj/machinery/chemical_dispenser/bar_alc/full, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/vending/boozeomat{ - pixel_y = 32 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aO" = ( -/obj/structure/closet/secure_closet/freezer/fridge, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aP" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/closet/secure_closet/freezer/meat, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aQ" = ( -/obj/machinery/door/airlock/centcom{ - name = "Stall"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"aR" = ( -/obj/item/storage/mirror, -/turf/unsimulated/wall, -/area/map_template/rescue_base/base) -"aS" = ( -/obj/machinery/door/airlock/centcom{ - name = "Showers"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"aT" = ( -/obj/structure/table/rack, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aU" = ( -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"aV" = ( -/obj/structure/table/rack, -/obj/item/stock_parts/circuitboard/borgupload, -/obj/item/stock_parts/circuitboard/aiupload{ - pixel_x = -3; - pixel_y = -3 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aW" = ( -/obj/structure/table/rack, -/obj/item/gun/projectile/automatic/smg, -/obj/item/gun/projectile/automatic/smg, -/obj/item/gun/projectile/automatic/smg, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"aX" = ( -/obj/machinery/door/airlock/centcom{ - name = "Processing"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"aY" = ( -/turf/simulated/floor/wood/bamboo, -/area/map_template/rescue_base/base) -"aZ" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"ba" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/door/airlock/centcom{ - name = "Storage"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bb" = ( -/obj/machinery/door/airlock/centcom{ - name = "Head"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"bc" = ( -/obj/structure/hygiene/sink{ - dir = 1; - pixel_y = 16 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/rescue_base/base) -"bd" = ( -/obj/structure/table/rack, -/obj/item/gun/projectile/automatic/assault_rifle, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"be" = ( -/obj/structure/table/rack, -/obj/item/clothing/head/helmet/ablative, -/obj/item/clothing/head/helmet/ablative, -/obj/item/clothing/head/helmet/ablative, -/obj/item/clothing/head/helmet/ablative, -/obj/item/clothing/head/helmet/ablative, -/obj/item/clothing/head/helmet/ablative, -/obj/item/clothing/suit/armor/laserproof, -/obj/item/clothing/suit/armor/laserproof, -/obj/item/clothing/suit/armor/laserproof, -/obj/item/clothing/suit/armor/laserproof, -/obj/item/clothing/suit/armor/laserproof, -/obj/item/clothing/suit/armor/laserproof, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bf" = ( -/obj/structure/table/rack, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/obj/item/ammo_magazine/smg/rubber, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bg" = ( -/obj/effect/wingrille_spawn/reinforced/crescent, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/rescue_base/base) -"bh" = ( -/obj/structure/table/reinforced, -/obj/item/storage/box/handcuffs, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bi" = ( -/obj/structure/table/reinforced, -/obj/machinery/recharger{ - pixel_y = 4 - }, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bj" = ( -/obj/structure/bed, -/obj/item/bedsheet/orange, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bk" = ( -/obj/structure/hygiene/toilet{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bl" = ( -/turf/simulated/floor/wood/yew, -/area/map_template/rescue_base/base) -"bm" = ( -/obj/machinery/vending/dinnerware, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bn" = ( -/obj/structure/table/rack, -/obj/item/rig/ert/assetprotection, -/obj/item/rig/ert/assetprotection, -/obj/item/rig/ert/assetprotection, -/obj/item/rig/ert/assetprotection, -/obj/item/rig/ert/assetprotection, -/obj/item/rig/ert/assetprotection, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bo" = ( -/obj/structure/table/rack, -/obj/item/clothing/head/helmet/ballistic, -/obj/item/clothing/head/helmet/ballistic, -/obj/item/clothing/head/helmet/ballistic, -/obj/item/clothing/head/helmet/ballistic, -/obj/item/clothing/head/helmet/ballistic, -/obj/item/clothing/head/helmet/ballistic, -/obj/item/clothing/suit/armor/bulletproof, -/obj/item/clothing/suit/armor/bulletproof, -/obj/item/clothing/suit/armor/bulletproof, -/obj/item/clothing/suit/armor/bulletproof, -/obj/item/clothing/suit/armor/bulletproof, -/obj/item/clothing/suit/armor/bulletproof, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bp" = ( -/obj/structure/table/rack, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/obj/item/ammo_magazine/smg, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bq" = ( -/obj/structure/bed/chair/office/dark{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"br" = ( -/obj/structure/table/reinforced, -/obj/item/flash, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bs" = ( -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 9 - }, -/area/map_template/rescue_base/base) -"bt" = ( -/obj/machinery/door/airlock/centcom{ - name = "Cell 2"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bu" = ( -/obj/structure/table/rack, -/obj/item/lightreplacer, -/obj/item/lightreplacer, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bv" = ( -/obj/structure/table/rack, -/obj/item/clothing/shoes/galoshes, -/obj/item/clothing/head/bio_hood/janitor, -/obj/item/clothing/suit/bio_suit/janitor, -/obj/item/clothing/glasses/science, -/obj/item/clothing/shoes/galoshes, -/obj/item/clothing/head/bio_hood/janitor, -/obj/item/clothing/suit/bio_suit/janitor, -/obj/item/clothing/glasses/science, -/obj/item/chems/spray/plantbgone, -/obj/item/chems/spray/plantbgone, -/obj/item/storage/box/lights/mixed, -/obj/item/storage/box/lights/mixed, -/obj/item/grenade/chem_grenade/cleaner, -/obj/item/grenade/chem_grenade/cleaner, -/obj/item/grenade/chem_grenade/cleaner, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bw" = ( -/obj/structure/table/reinforced, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/microwave, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bx" = ( -/obj/structure/table/reinforced, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/chems/food/condiment/small/saltshaker{ - pixel_x = -3; - pixel_y = 0 - }, -/obj/item/chems/food/condiment/small/peppermill{ - pixel_x = 3 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"by" = ( -/obj/structure/table/reinforced, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/storage/box/donkpockets{ - pixel_x = 3; - pixel_y = 3 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bz" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/storage/box/sinpockets, -/obj/structure/closet/secure_closet/freezer/kitchen, -/obj/item/chems/food/condiment/enzyme, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bA" = ( -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/rescue_base/base) -"bB" = ( -/turf/unsimulated/floor{ - icon_state = "asteroidplating" - }, -/area/map_template/rescue_base/base) -"bC" = ( -/obj/structure/flora/ausbushes/fullgrass, -/turf/unsimulated/floor{ - icon_state = "asteroidplating" - }, -/area/map_template/rescue_base/base) -"bD" = ( -/obj/structure/table/rack, -/obj/item/gun/projectile/automatic/assault_rifle, -/obj/item/gun/projectile/automatic/assault_rifle, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bE" = ( -/obj/machinery/door/airlock/centcom{ - name = "Restricted Equipment"; - opacity = 1 - }, -/obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; - id_tag = "heavyrescue"; - name = "Restricted Equipment" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"bF" = ( -/obj/structure/table/rack, -/obj/item/storage/box/smokes, -/obj/item/storage/box/smokes, -/obj/item/storage/box/flashbangs, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bG" = ( -/obj/structure/table/reinforced, -/obj/item/camera, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bH" = ( -/obj/item/stool, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bI" = ( -/obj/structure/table/standard, -/obj/item/paper, -/obj/item/pen, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bJ" = ( -/obj/machinery/door/airlock/centcom{ - name = "Galley"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bK" = ( -/obj/structure/flora/ausbushes/fullgrass, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/rescue_base/base) -"bL" = ( -/obj/structure/table/rack, -/obj/item/ammo_magazine/rifle, -/obj/item/ammo_magazine/rifle, -/obj/item/ammo_magazine/rifle, -/obj/item/ammo_magazine/rifle, -/obj/item/ammo_magazine/rifle, -/obj/item/ammo_magazine/rifle, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bM" = ( -/obj/structure/table/rack, -/obj/item/gun/launcher/grenade, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bN" = ( -/obj/structure/table/rack, -/obj/item/storage/box/teargas, -/obj/item/storage/box/teargas, -/obj/item/storage/box/emps, -/obj/item/storage/box/emps, -/obj/item/storage/box/frags, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bO" = ( -/obj/structure/closet{ - name = "emergency response team wardrobe" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bP" = ( -/obj/structure/bed/padded, -/obj/item/bedsheet/captain, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bQ" = ( -/obj/structure/bed/padded, -/obj/item/bedsheet/captain, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bR" = ( -/obj/machinery/vending/coffee{ - markup = 0 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bS" = ( -/obj/machinery/door/airlock/centcom{ - name = "Heavy Equipment"; - opacity = 1 - }, -/obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; - id_tag = "standardrescue"; - name = "Heavy Equipment" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"bT" = ( -/obj/machinery/door/airlock/centcom{ - name = "Detention"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bU" = ( -/obj/machinery/acting/changer, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bV" = ( -/obj/effect/landmark{ - name = "Response Team" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"bW" = ( -/obj/machinery/door/airlock/centcom{ - name = "Squad Bay"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bX" = ( -/obj/machinery/door/airlock/centcom{ - name = "Cell 1"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"bY" = ( -/obj/structure/undies_wardrobe, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"bZ" = ( -/obj/item/clothing/shoes/color/orange, -/obj/item/clothing/under/color/orange, -/obj/structure/closet{ - name = "Prisoner's Locker" - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"ca" = ( -/obj/structure/table/reinforced, -/obj/machinery/recharger{ - pixel_y = 4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cb" = ( -/obj/machinery/door/airlock/centcom{ - name = "Ready Room"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"cc" = ( -/obj/structure/table/rack, -/obj/item/storage/box/handcuffs, -/obj/item/storage/box/handcuffs, -/obj/item/storage/box/teargas, -/obj/item/storage/box/teargas, -/obj/item/storage/box/flashbangs, -/obj/item/storage/box/flashbangs, -/obj/item/flash, -/obj/item/flash, -/obj/item/baton/loaded, -/obj/item/baton/loaded, -/obj/item/chems/spray/pepper, -/obj/item/chems/spray/pepper, -/obj/item/telebaton, -/obj/item/telebaton, -/obj/machinery/recharger/wallcharger{ - pixel_x = 4; - pixel_y = 32 - }, -/obj/item/taperoll/police, -/obj/item/taperoll/police, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cd" = ( -/obj/structure/table/rack, -/obj/item/clothing/mask/gas, -/obj/item/clothing/mask/gas, -/obj/item/clothing/glasses/night, -/obj/item/clothing/glasses/night, -/obj/item/clothing/glasses/tacgoggles, -/obj/item/clothing/glasses/tacgoggles, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ce" = ( -/obj/structure/table/rack, -/obj/item/storage/backpack/ert/security, -/obj/item/storage/backpack/ert/security, -/obj/item/storage/belt/holster/security/tactical, -/obj/item/storage/belt/holster/security/tactical, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cf" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/gun/nuclear, -/obj/item/gun/energy/gun/nuclear, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cg" = ( -/obj/structure/table/rack, -/obj/machinery/recharger/wallcharger{ - pixel_x = 4; - pixel_y = 32 - }, -/obj/item/clothing/suit/armor/pcarrier/medium, -/obj/item/clothing/suit/armor/pcarrier/medium, -/obj/item/clothing/head/helmet, -/obj/item/clothing/head/helmet, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ch" = ( -/obj/structure/table/rack, -/obj/item/clothing/suit/armor/pcarrier/medium, -/obj/item/clothing/suit/armor/pcarrier/medium, -/obj/item/clothing/head/helmet, -/obj/item/clothing/head/helmet, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ci" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/gun, -/obj/item/gun/energy/gun, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cj" = ( -/obj/structure/table/rack, -/obj/item/storage/backpack/ert/medical, -/obj/item/storage/backpack/ert/medical, -/obj/item/storage/belt/medical, -/obj/item/storage/belt/medical, -/obj/item/storage/belt/medical/emt, -/obj/item/storage/belt/medical/emt, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ck" = ( -/obj/structure/table/rack, -/obj/item/clothing/mask/gas, -/obj/item/clothing/mask/gas, -/obj/item/clothing/glasses/hud/health, -/obj/item/clothing/glasses/hud/health, -/obj/item/storage/box/gloves, -/obj/item/storage/box/gloves, -/obj/item/storage/box/masks, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cl" = ( -/obj/structure/table/rack, -/obj/item/flash, -/obj/item/flash, -/obj/item/baton/loaded, -/obj/item/baton/loaded, -/obj/item/storage/box/syringes, -/obj/item/storage/box/syringes, -/obj/item/storage/box/autoinjectors, -/obj/item/storage/box/autoinjectors, -/obj/item/storage/box/beakers, -/obj/item/storage/box/beakers, -/obj/item/storage/box/pillbottles, -/obj/item/storage/box/pillbottles, -/obj/item/storage/box/bodybags, -/obj/item/storage/box/bodybags, -/obj/item/storage/box/syringegun, -/obj/item/storage/box/syringegun, -/obj/item/storage/box/syringegun, -/obj/item/storage/box/syringegun, -/obj/item/gun/launcher/syringe/rapid, -/obj/item/gun/launcher/syringe/rapid, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cm" = ( -/obj/structure/table/reinforced, -/obj/item/chems/hypospray, -/obj/item/chems/hypospray, -/obj/item/chems/hypospray, -/obj/item/chems/hypospray, -/obj/item/chems/hypospray, -/obj/item/chems/hypospray, -/obj/item/chems/glass/beaker/large, -/obj/item/chems/glass/bottle/stabilizer, -/obj/item/chems/glass/bottle/stabilizer, -/obj/item/chems/glass/bottle/stabilizer, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cn" = ( -/obj/structure/table/rack, -/obj/item/rig/ert/medical, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/structure/window/reinforced/crescent{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"co" = ( -/obj/structure/table/rack, -/obj/item/rig/ert/medical, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cp" = ( -/obj/structure/table/rack, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/maneuvering_jets, -/obj/item/rig_module/maneuvering_jets, -/obj/item/rig_module/chem_dispenser/injector, -/obj/item/rig_module/chem_dispenser/injector, -/obj/item/rig_module/device/healthscanner, -/obj/item/rig_module/device/healthscanner, -/obj/item/rig_module/vision/medhud, -/obj/item/rig_module/vision/medhud, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cq" = ( -/obj/structure/table/rack, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cs" = ( -/obj/structure/table/rack, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/maneuvering_jets, -/obj/item/rig_module/maneuvering_jets, -/obj/item/rig_module/mounted/egun, -/obj/item/rig_module/mounted/egun, -/obj/item/rig_module/chem_dispenser/combat, -/obj/item/rig_module/chem_dispenser/combat, -/obj/item/rig_module/grenade_launcher, -/obj/item/rig_module/vision/sechud, -/obj/item/rig_module/vision/sechud, -/obj/item/rig_module/device/flash, -/obj/item/rig_module/device/flash, -/obj/item/rig_module/mounted, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/structure/window/reinforced/crescent{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ct" = ( -/obj/structure/table/rack, -/obj/item/rig/ert/security, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cu" = ( -/obj/structure/table/rack, -/obj/item/rig/ert/security, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cv" = ( -/obj/machinery/hologram/holopad/longrange, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"cw" = ( -/obj/structure/table/rack, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cx" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/laser, -/obj/item/gun/energy/laser, -/obj/item/gun/energy/laser, -/obj/item/gun/energy/laser, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cy" = ( -/obj/machinery/chemical_dispenser/ert, -/obj/item/chems/glass/beaker/large, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cz" = ( -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/structure/table/rack, -/obj/item/rig/ert/janitor, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cA" = ( -/obj/structure/table/reinforced, -/obj/item/paper_bin, -/obj/item/pen, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"cB" = ( -/obj/structure/table/reinforced, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"cD" = ( -/obj/machinery/fabricator/hacked, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cE" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/ionrifle, -/obj/item/gun/energy/ionrifle, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cF" = ( -/obj/structure/table/rack, -/obj/item/clothing/head/helmet/riot, -/obj/item/clothing/head/helmet/riot, -/obj/item/clothing/head/helmet/riot, -/obj/item/clothing/head/helmet/riot, -/obj/item/clothing/suit/armor/riot, -/obj/item/clothing/suit/armor/riot, -/obj/item/clothing/suit/armor/riot, -/obj/item/clothing/suit/armor/riot, -/obj/item/shield/riot, -/obj/item/shield/riot, -/obj/item/shield/riot, -/obj/item/shield/riot, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"cG" = ( -/obj/structure/table/reinforced, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/defibrillator/compact/loaded, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cH" = ( -/obj/structure/table/reinforced, -/obj/item/roller, -/obj/item/roller, -/obj/item/roller, -/obj/item/roller, -/obj/item/roller, -/obj/item/roller, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cI" = ( -/obj/structure/closet{ - name = "insignias closet" - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"cJ" = ( -/obj/machinery/chem_master, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cK" = ( -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/obj/structure/window/reinforced/crescent, -/obj/structure/table/rack, -/obj/item/rig/ert/janitor, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cL" = ( -/obj/structure/table/reinforced, -/obj/item/paicard, -/obj/item/paicard, -/obj/item/paicard, -/obj/item/paicard, -/obj/item/paicard, -/obj/item/paicard, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cM" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/gun, -/obj/item/gun/energy/gun, -/obj/item/gun/energy/gun, -/obj/item/gun/energy/gun, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cN" = ( -/obj/structure/table/rack, -/obj/item/shield/riot/metal, -/obj/item/shield/riot/metal, -/obj/item/shield/riot/metal, -/obj/item/shield/riot/metal, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"cO" = ( -/obj/machinery/chemical_dispenser/full, -/obj/item/chems/glass/beaker/large, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cP" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"cQ" = ( -/obj/structure/table/reinforced, -/obj/item/megaphone, -/obj/item/megaphone, -/obj/item/megaphone, -/obj/item/megaphone, -/obj/item/megaphone, -/obj/item/megaphone, -/obj/structure/noticeboard{ - pixel_x = 32 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cR" = ( -/obj/structure/closet{ - name = "insignias closet" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cS" = ( -/obj/structure/iv_drip, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cT" = ( -/obj/structure/table/reinforced, -/obj/item/chems/spray/cleaner, -/obj/item/chems/spray/cleaner, -/obj/item/chems/spray/antiseptic, -/obj/item/chems/spray/antiseptic, -/obj/item/storage/box/bloodpacks, -/obj/item/tape/medical, -/obj/item/tape/medical, -/obj/item/flashlight/pen, -/obj/item/flashlight/pen, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cU" = ( -/obj/structure/table/reinforced, -/obj/item/storage/firstaid/fire, -/obj/item/storage/firstaid/fire, -/obj/item/storage/firstaid/fire, -/obj/item/storage/firstaid/toxin, -/obj/item/storage/firstaid/toxin, -/obj/item/storage/firstaid/toxin, -/obj/item/storage/firstaid/o2, -/obj/item/storage/firstaid/o2, -/obj/item/storage/firstaid/o2, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cV" = ( -/obj/structure/table/reinforced, -/obj/item/storage/firstaid/regular, -/obj/item/storage/firstaid/regular, -/obj/item/storage/firstaid/regular, -/obj/item/storage/firstaid/adv, -/obj/item/storage/firstaid/adv, -/obj/item/storage/firstaid/adv, -/obj/item/storage/firstaid/combat, -/obj/item/storage/firstaid/combat, -/obj/item/storage/firstaid/combat, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cW" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cX" = ( -/obj/structure/window/reinforced/crescent, -/obj/structure/table/rack, -/obj/item/rig/ert, -/obj/structure/window/reinforced/crescent{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cY" = ( -/obj/structure/window/reinforced/crescent, -/obj/structure/table/rack, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/vision/nvg, -/obj/item/rig_module/device/flash, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"cZ" = ( -/obj/structure/window/reinforced/crescent, -/obj/structure/table/rack, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/mounted/taser, -/obj/item/rig_module/maneuvering_jets, -/obj/item/rig_module/maneuvering_jets, -/obj/item/rig_module/device/drill, -/obj/item/rig_module/device/drill, -/obj/item/rig_module/mounted/plasmacutter, -/obj/item/rig_module/mounted/plasmacutter, -/obj/item/rig_module/device/rcd, -/obj/item/rig_module/device/rcd, -/obj/item/rig_module/vision/meson, -/obj/item/rig_module/vision/meson, -/obj/structure/window/reinforced/crescent{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"da" = ( -/obj/structure/window/reinforced/crescent, -/obj/structure/table/rack, -/obj/item/rig/ert/engineer, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"db" = ( -/obj/structure/window/reinforced/crescent, -/obj/structure/table/rack, -/obj/item/rig/ert/engineer, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dc" = ( -/turf/unsimulated/wall{ - desc = "A secure airlock. Doesn't look like you can get through easily."; - icon = 'icons/obj/doors/centcomm/door.dmi'; - icon_state = "closed"; - name = "Foxtrot Barracks" - }, -/area/map_template/rescue_base/base) -"dd" = ( -/obj/structure/flora/ausbushes/palebush, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/rescue_base/base) -"de" = ( -/obj/structure/table/reinforced, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"df" = ( -/obj/machinery/vending/security, -/turf/unsimulated/wall, -/area/map_template/rescue_base/base) -"dg" = ( -/obj/machinery/door/airlock/centcom{ - name = "Security"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dh" = ( -/obj/machinery/door/airlock/centcom{ - name = "Medical"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"di" = ( -/obj/machinery/vending/medical, -/turf/unsimulated/wall, -/area/map_template/rescue_base/base) -"dj" = ( -/obj/effect/wingrille_spawn/reinforced/crescent, -/turf/space, -/area/map_template/rescue_base/base) -"dk" = ( -/obj/machinery/door/airlock/centcom{ - name = "EVA"; - opacity = 1 - }, -/obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; - id_tag = "standardrescue"; - name = "EVA" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dl" = ( -/obj/machinery/door/airlock/centcom{ - name = "Unit Area"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dm" = ( -/obj/machinery/recharger/wallcharger{ - pixel_x = 4; - pixel_y = 32 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dn" = ( -/obj/machinery/door/airlock/centcom{ - name = "Echo Barracks"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"do" = ( -/turf/unsimulated/wall{ - desc = "A secure airlock. Doesn't look like you can get through easily."; - icon = 'icons/obj/doors/centcomm/door.dmi'; - icon_state = "closed"; - name = "Delta Barracks"; - dir = 4 - }, -/area/map_template/rescue_base/base) -"dp" = ( -/obj/structure/flora/ausbushes/sunnybush, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/rescue_base/base) -"dq" = ( -/obj/structure/table/reinforced, -/obj/item/modular_computer/tablet/lease/preset/command, -/obj/item/modular_computer/tablet/lease/preset/command, -/obj/item/modular_computer/tablet/lease/preset/command, -/obj/item/modular_computer/tablet/lease/preset/command, -/obj/item/modular_computer/tablet/lease/preset/command, -/obj/item/modular_computer/tablet/lease/preset/command, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dr" = ( -/obj/machinery/recharge_station, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ds" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/white_vest, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dt" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/black_vest, -/obj/item/clothing/accessory/storage/black_vest, -/obj/item/clothing/accessory/storage/black_vest, -/obj/item/clothing/accessory/storage/black_vest, -/obj/item/clothing/accessory/storage/black_vest, -/obj/item/clothing/accessory/storage/black_vest, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"du" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/brown_vest, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dv" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/holster/thigh, -/obj/item/clothing/accessory/storage/holster/thigh, -/obj/item/clothing/accessory/storage/holster/thigh, -/obj/item/clothing/accessory/storage/holster/thigh, -/obj/item/clothing/accessory/storage/holster/thigh, -/obj/item/clothing/accessory/storage/holster/thigh, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dw" = ( -/obj/item/radio/intercom/specops{ - dir = 1; - pixel_y = -22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dx" = ( -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - frequency = 1331; - id_tag = "rescue_base"; - pixel_x = 5; - pixel_y = -25 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dy" = ( -/obj/machinery/door/airlock/centcom{ - name = "Squad Leader's Office"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dz" = ( -/obj/machinery/door/airlock/centcom{ - name = "Command"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dA" = ( -/obj/machinery/door/airlock/centcom{ - name = "Engineering"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dB" = ( -/obj/machinery/vending/engineering, -/turf/unsimulated/wall, -/area/map_template/rescue_base/base) -"dC" = ( -/obj/machinery/door/airlock/external/shuttle{ - id_tag = "rescue_base_hatch"; - name = "Landing Pad" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dD" = ( -/obj/structure/table/reinforced, -/obj/item/storage/box/trackimp, -/obj/item/storage/box/cdeathalarm_kit, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dE" = ( -/obj/structure/table/reinforced, -/obj/prefab/hand_teleporter, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dF" = ( -/obj/structure/table/reinforced, -/obj/item/aicard, -/obj/item/pinpointer/advpinpointer, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dG" = ( -/obj/structure/table/reinforced, -/obj/machinery/cell_charger, -/obj/item/cell/hyper, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dH" = ( -/obj/machinery/vending/engivend, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dI" = ( -/obj/machinery/vending/tool, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dJ" = ( -/obj/machinery/vending/assist, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dK" = ( -/obj/machinery/fabricator/pipe, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dL" = ( -/obj/machinery/fabricator/pipe/disposal, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dN" = ( -/obj/effect/floor_decal/industrial/hatch/yellow, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"dO" = ( -/obj/structure/bed/chair/office/dark, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dP" = ( -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dQ" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/door/airlock/external/shuttle{ - id_tag = "rescue_base_hatch" - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"dR" = ( -/obj/machinery/door/airlock/centcom{ - name = "Garage"; - opacity = 1 - }, -/obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; - id_tag = "standardrescue"; - name = "Garage" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"dS" = ( -/obj/structure/table/steel, -/obj/item/radio/intercom/specops{ - dir = 2 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"dT" = ( -/obj/structure/table/steel, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"dU" = ( -/obj/structure/table/steel, -/obj/item/storage/fancy/cigar, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"dV" = ( -/obj/machinery/door/airlock/centcom{ - name = "Command"; - opacity = 1 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"dW" = ( -/obj/structure/reagent_dispensers/watertank, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dX" = ( -/obj/machinery/portable_atmospherics/powered/pump/filled, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dY" = ( -/obj/machinery/shieldgen, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"dZ" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"ea" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/floor_decal/industrial/warning/corner, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eb" = ( -/obj/machinery/button/blast_door{ - id_tag = "rescuegarage"; - name = "Garage"; - pixel_x = -24; - pixel_y = -4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"ec" = ( -/obj/structure/table/reinforced, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ed" = ( -/obj/structure/table/reinforced, -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ee" = ( -/obj/structure/table/reinforced, -/obj/machinery/cell_charger, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eg" = ( -/obj/structure/bed/chair/office/dark{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"eh" = ( -/obj/structure/table/rack, -/obj/item/storage/box/flashbangs, -/obj/item/storage/box/teargas, -/obj/item/storage/box/handcuffs, -/obj/item/baton/loaded, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ei" = ( -/obj/structure/table/rack, -/obj/item/clothing/mask/gas, -/obj/item/clothing/glasses/tacgoggles, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ej" = ( -/obj/structure/table/rack, -/obj/item/storage/backpack/ert/commander, -/obj/item/storage/belt/holster/security/tactical, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ek" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/gun, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"em" = ( -/obj/structure/reagent_dispensers/fueltank, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"en" = ( -/obj/machinery/portable_atmospherics/powered/scrubber, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eo" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/floor_decal/industrial/warning{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"ep" = ( -/obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; - id_tag = "rescuegarage"; - name = "Garage Exit" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"eq" = ( -/obj/machinery/mech_recharger, -/turf/space, -/area/map_template/rescue_base/base) -"er" = ( -/obj/item/card/id/centcom, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"et" = ( -/obj/structure/table/rack, -/obj/item/storage/secure/briefcase, -/obj/item/clothing/head/beret/corp/centcom/captain, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eu" = ( -/obj/machinery/power/emitter, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ev" = ( -/obj/structure/table/woodentable{ - dir = 5 - }, -/obj/machinery/button/blast_door{ - id_tag = "heavyrescue"; - name = "Heavy Gear"; - pixel_x = -5; - pixel_y = 4 - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/rescue_base/base) -"ew" = ( -/obj/structure/table/woodentable{ - dir = 5 - }, -/obj/item/radio/phone{ - desc = "Should anything ever go wrong..."; - frequency = 1345 - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/rescue_base/base) -"ex" = ( -/obj/structure/table/woodentable{ - dir = 5 - }, -/obj/machinery/button/blast_door{ - id_tag = "standardrescue"; - name = "Standard Gear"; - pixel_x = 5; - pixel_y = 4 - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/rescue_base/base) -"ey" = ( -/obj/structure/table/rack, -/obj/item/storage/backpack/ert/engineer, -/obj/item/storage/backpack/ert/engineer, -/obj/item/storage/belt/utility/full, -/obj/item/storage/belt/utility/full, -/obj/item/clothing/gloves/insulated, -/obj/item/clothing/gloves/insulated, -/obj/item/clothing/gloves/insulated, -/obj/item/clothing/gloves/insulated, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"ez" = ( -/obj/structure/table/rack, -/obj/item/clothing/mask/gas, -/obj/item/clothing/mask/gas, -/obj/item/clothing/glasses/meson, -/obj/item/clothing/glasses/meson, -/obj/item/clothing/glasses/welding/superior, -/obj/item/clothing/glasses/welding/superior, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eA" = ( -/obj/structure/table/rack, -/obj/item/flash, -/obj/item/flash, -/obj/item/baton/loaded, -/obj/item/baton/loaded, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/grenade/chem_grenade/metalfoam, -/obj/item/inflatable_dispenser, -/obj/item/inflatable_dispenser, -/obj/item/pickaxe/diamonddrill, -/obj/item/pickaxe/diamonddrill, -/obj/item/storage/briefcase/inflatable{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/briefcase/inflatable{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/briefcase/inflatable{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/briefcase/inflatable{ - pixel_x = 3; - pixel_y = 3 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eB" = ( -/obj/structure/table/reinforced, -/obj/item/taperoll/engineering, -/obj/item/taperoll/engineering, -/obj/item/taperoll/atmos, -/obj/item/taperoll/atmos, -/obj/item/multitool, -/obj/item/multitool, -/obj/item/tape_roll, -/obj/item/tape_roll, -/obj/item/tape_roll, -/obj/item/tape_roll, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/cell/high, -/obj/item/cell/high, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eC" = ( -/obj/structure/table/reinforced, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd_ammo, -/obj/item/rcd, -/obj/item/rcd, -/obj/item/rcd, -/obj/item/rcd, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eD" = ( -/obj/structure/table/reinforced, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 2; - pixel_y = 2 - }, -/obj/item/stack/material/plasteel{ - amount = 50 - }, -/obj/item/stack/material/plasteel{ - amount = 50 - }, -/obj/item/stack/material/plasteel{ - amount = 50 - }, -/obj/item/stack/material/plasteel{ - amount = 50 - }, -/obj/item/stack/material/glass/reinforced{ - amount = 50 - }, -/obj/item/stack/material/glass/reinforced{ - amount = 50 - }, -/obj/item/stack/material/glass/reinforced{ - amount = 50 - }, -/obj/item/stack/material/glass/reinforced{ - amount = 50 - }, -/obj/item/stack/material/plastic{ - amount = 50 - }, -/obj/item/stack/material/plastic{ - amount = 50 - }, -/obj/item/stack/material/plastic{ - amount = 50 - }, -/obj/item/stack/material/plastic{ - amount = 50 - }, -/obj/item/stack/material/glass/reinforced_borosilicate{ - amount = 20 - }, -/obj/item/stack/material/glass/reinforced_borosilicate{ - amount = 20 - }, -/obj/item/stack/material/glass/reinforced_borosilicate{ - amount = 20 - }, -/obj/item/stack/material/glass/reinforced_borosilicate{ - amount = 20 - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eE" = ( -/obj/structure/table/reinforced, -/obj/item/stock_parts/circuitboard/smes, -/obj/item/stock_parts/circuitboard/smes, -/obj/item/stock_parts/smes_coil, -/obj/item/stock_parts/smes_coil, -/obj/item/stock_parts/smes_coil/super_capacity, -/obj/item/stock_parts/smes_coil/super_capacity, -/obj/item/stock_parts/smes_coil/super_io, -/obj/item/stock_parts/smes_coil/super_io, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eF" = ( -/obj/machinery/portable_atmospherics/canister/air, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 1 - }, -/area/map_template/rescue_base/base) -"eG" = ( -/obj/item/radio/intercom/specops{ - dir = 2; - pixel_y = 22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/rescue_base/base) -"eH" = ( -/obj/structure/table/woodentable{ - dir = 5 - }, -/obj/item/ashtray, -/obj/item/trash/cigbutt/cigarbutt, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/rescue_base/base) -"eI" = ( -/obj/structure/bed/chair/comfy/brown{ - dir = 1 - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/rescue_base/base) -"eJ" = ( -/obj/structure/table/woodentable{ - dir = 5 - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/rescue_base/base) -"eK" = ( -/obj/machinery/door/airlock/centcom{ - name = "Combat Exosuit"; - opacity = 1 - }, -/obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; - id_tag = "heavyrescue"; - name = "Combat Exosuit" - }, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, -/area/map_template/rescue_base/base) -"eL" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/floor_decal/industrial/warning/corner{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eM" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 9 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eN" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eO" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 5 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eP" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eQ" = ( -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eR" = ( -/obj/effect/floor_decal/industrial/loading, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eS" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eT" = ( -/obj/effect/floor_decal/industrial/hatch/yellow, -/obj/machinery/porta_turret/crescent, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"eU" = ( -/obj/effect/paint/blue, -/turf/simulated/wall/titanium, -/area/map_template/rescue_base/start) -"eV" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "rescuebridge"; - name = "Cockpit Blast Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"eW" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "rescuedock"; - name = "Blast Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"eX" = ( -/obj/machinery/door/airlock/external/shuttle{ - density = 1; - id_tag = "rescue_shuttle_outer"; - name = "Ship External Access" - }, -/obj/effect/shuttle_landmark/ert/start, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"eY" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/button/blast_door{ - icon_state = "doorctrl0"; - id_tag = "rescuebridge"; - name = "Window Shutters Control"; - pixel_y = -4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"eZ" = ( -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fa" = ( -/obj/machinery/computer/shuttle_control/multi/rescue, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fb" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/recharger{ - pixel_y = 4 - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fc" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 4; - id_tag = "rescue_shuttle_pump" - }, -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "rescue_shuttle_sensor"; - pixel_x = 8; - pixel_y = 25 - }, -/obj/machinery/light{ - dir = 8 - }, -/obj/structure/closet/emcloset, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fd" = ( -/obj/machinery/atmospherics/pipe/manifold/visible{ - dir = 1 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fe" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 8; - id_tag = "rescue_shuttle_pump" - }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - frequency = 1331; - id_tag = "rescue_shuttle"; - pixel_x = -8; - pixel_y = 25; - initial_access = list() - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"ff" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fg" = ( -/obj/structure/bed/chair/office/dark{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fh" = ( -/obj/structure/bed/chair/shuttle, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fi" = ( -/obj/structure/table/steel_reinforced, -/obj/item/radio/intercom/specops{ - dir = 8; - pixel_x = 22; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fj" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fk" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fl" = ( -/obj/machinery/button/blast_door{ - icon_state = "doorctrl0"; - id_tag = "rescuedock"; - name = "Window Shutters Control"; - pixel_x = 24; - pixel_y = -4 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fm" = ( -/obj/machinery/computer/modular/preset/medical{ - icon_state = "console"; - dir = 4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fo" = ( -/obj/machinery/hologram/holopad/longrange, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fp" = ( -/obj/machinery/computer/modular/preset/engineering{ - icon_state = "console"; - dir = 8 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fq" = ( -/obj/item/radio/intercom/specops{ - dir = 8; - pixel_x = 22; - pixel_y = 0 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fr" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/computer/prisoner{ - dir = 4; - name = "Implant Management" - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fs" = ( -/obj/machinery/computer/modular/preset/security{ - icon_state = "console"; - dir = 8 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"ft" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 4; - id_tag = "rescue_shuttle_pump" - }, -/obj/machinery/light{ - dir = 8 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fu" = ( -/obj/machinery/atmospherics/pipe/manifold4w/visible, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fv" = ( -/obj/machinery/atmospherics/pipe/manifold4w/visible, -/obj/machinery/meter, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fw" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 8; - id_tag = "rescue_shuttle_pump" - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fx" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fy" = ( -/obj/machinery/door/airlock/centcom{ - name = "Flight Deck"; - opacity = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fz" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fA" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/machinery/door/airlock/external/shuttle{ - id_tag = "rescue_shuttle_inner"; - name = "Ship External Access" - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fB" = ( -/obj/structure/flora/ausbushes/palebush, -/turf/unsimulated/floor{ - icon_state = "asteroidplating" - }, -/area/map_template/rescue_base/base) -"fC" = ( -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "rescuebridge"; - name = "Cockpit Blast Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fD" = ( -/obj/structure/closet, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fE" = ( -/obj/structure/table/rack, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fF" = ( -/obj/machinery/atmospherics/unary/tank/air{ - dir = 4; - start_pressure = 740.5 - }, -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fG" = ( -/obj/machinery/atmospherics/pipe/manifold/visible, -/obj/machinery/meter, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fH" = ( -/obj/machinery/atmospherics/pipe/manifold/visible, -/obj/machinery/button/access/shuttle/interior{ - id_tag = "rescue_shuttle"; - name = "interior access button"; - pixel_x = 25; - pixel_y = 25; - initial_access = list("ACCESS_CENT_SPECOPS") - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fI" = ( -/obj/machinery/atmospherics/unary/tank/air{ - dir = 8 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fJ" = ( -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "rescueeva"; - name = "Blast Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"fK" = ( -/obj/structure/closet, -/obj/item/storage/box/sinpockets, -/obj/item/storage/box/sinpockets, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fL" = ( -/obj/structure/closet/bombclosetsecurity, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fM" = ( -/obj/structure/table/rack, -/obj/item/clothing/mask/gas/half, -/obj/item/clothing/mask/gas/half, -/obj/item/clothing/mask/gas/half, -/obj/item/clothing/mask/gas/half, -/obj/item/clothing/mask/gas/half, -/obj/item/clothing/mask/gas/half, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fN" = ( -/obj/machinery/suit_cycler, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fO" = ( -/obj/structure/closet, -/obj/item/flashlight/flare, -/obj/item/flashlight/flare, -/obj/item/flashlight/flare, -/obj/item/flashlight/flare, -/obj/item/flashlight/flare, -/obj/item/flashlight/flare, -/obj/item/flashlight, -/obj/item/flashlight, -/obj/item/flashlight, -/obj/item/flashlight, -/obj/item/flashlight, -/obj/item/flashlight, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fP" = ( -/obj/item/radio/intercom/specops{ - dir = 8; - pixel_x = 22; - pixel_y = 0 - }, -/obj/structure/closet/l3closet/general, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fQ" = ( -/obj/structure/table/rack, -/obj/item/tank/emergency/oxygen/double, -/obj/item/tank/emergency/oxygen/double, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fR" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fS" = ( -/obj/machinery/light{ - dir = 4 - }, -/obj/structure/closet/radiation, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fT" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fU" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/fancy/cigarettes/dromedaryco, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fV" = ( -/obj/structure/bed/chair{ - dir = 8 - }, -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fW" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fX" = ( -/obj/item/radio/intercom/specops{ - dir = 1; - pixel_y = -22 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fY" = ( -/obj/structure/table/rack, -/obj/machinery/light, -/obj/item/tank/jetpack/carbondioxide, -/obj/item/tank/jetpack/carbondioxide, -/obj/machinery/button/blast_door{ - icon_state = "doorctrl0"; - id_tag = "rescueeva"; - name = "Window Shutters Control"; - pixel_x = 24; - pixel_y = -4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"fZ" = ( -/obj/machinery/door/airlock/centcom{ - name = "Crew Area"; - opacity = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"ga" = ( -/obj/structure/sign/poster/bay_9{ - pixel_x = -32 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gb" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gc" = ( -/obj/machinery/vending/wallmed1{ - name = "Emergency NanoMed"; - pixel_x = 28; - pixel_y = 0; - initial_access = newlist() - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gd" = ( -/obj/machinery/door/airlock/centcom{ - name = "Passageway"; - opacity = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"ge" = ( -/obj/structure/handrai, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gf" = ( -/obj/machinery/light{ - dir = 8 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gg" = ( -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gh" = ( -/obj/structure/bed, -/obj/item/bedsheet/orange, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gi" = ( -/obj/machinery/flasher{ - id_tag = "rescueflash"; - pixel_x = 0; - pixel_y = 28 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gj" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gk" = ( -/obj/machinery/door/airlock/centcom{ - name = "Storage"; - opacity = 1 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gl" = ( -/obj/machinery/door/airlock/centcom{ - name = "Infirmary"; - opacity = 1 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gm" = ( -/obj/machinery/light{ - dir = 8 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gn" = ( -/obj/machinery/atmospherics/portables_connector, -/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"go" = ( -/obj/structure/table/glass, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gp" = ( -/obj/item/stool, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gq" = ( -/obj/structure/hygiene/toilet{ - dir = 8 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gr" = ( -/obj/structure/table/rack, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gs" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gt" = ( -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gu" = ( -/obj/machinery/shieldwallgen, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gv" = ( -/obj/structure/closet/secure_closet/chemical, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gw" = ( -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gx" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gy" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9; - icon_state = "intact" - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gz" = ( -/obj/machinery/door/airlock/centcom{ - name = "Cell"; - opacity = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gA" = ( -/obj/machinery/light{ - dir = 8 - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gB" = ( -/obj/structure/closet/secure_closet/medical1, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gC" = ( -/obj/structure/closet/medical_wall{ - pixel_y = 32 - }, -/obj/item/chems/glass/bottle/antitoxin{ - pixel_x = -4; - pixel_y = 8 - }, -/obj/item/chems/glass/bottle/stabilizer{ - pixel_x = 4; - pixel_y = 7 - }, -/obj/item/chems/syringe, -/obj/item/chems/syringe/antibiotic, -/obj/item/chems/syringe/antibiotic, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gD" = ( -/obj/machinery/bodyscanner{ - dir = 8 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gE" = ( -/obj/machinery/body_scanconsole{ - dir = 8 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gF" = ( -/obj/machinery/sleeper/standard{ - dir = 8 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gG" = ( -/obj/machinery/recharger/wallcharger{ - pixel_x = -25 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gH" = ( -/obj/machinery/door/airlock/centcom{ - name = "Brig"; - opacity = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gI" = ( -/obj/machinery/light, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gJ" = ( -/obj/machinery/recharge_station, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gK" = ( -/obj/machinery/light{ - dir = 4 - }, -/obj/structure/closet/crate/secure{ - req_access = list("ACCESS_CENT_SPECOPS") - }, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gL" = ( -/obj/structure/table/glass, -/obj/item/defibrillator/loaded, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gM" = ( -/obj/item/radio/intercom/specops{ - dir = 1; - pixel_y = -22 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gN" = ( -/obj/machinery/light, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gO" = ( -/obj/item/radio/intercom/specops{ - dir = 8; - pixel_x = 22; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gP" = ( -/obj/machinery/button/flasher{ - id_tag = "rescueflash"; - name = "Flasher"; - pixel_x = 27; - pixel_y = 0 - }, -/obj/structure/bed/chair{ - dir = 8 - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gQ" = ( -/obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gR" = ( -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/hygiene/sink{ - icon_state = "sink"; - dir = 8; - pixel_x = -12; - pixel_y = 2 - }, -/obj/structure/closet/medical_wall{ - pixel_x = -32 - }, -/obj/item/chems/glass/bottle/sedatives, -/obj/item/chems/glass/bottle/sedatives, -/obj/item/chems/syringe, -/obj/item/tank/anesthetic, -/obj/item/clothing/mask/breath/medical, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gS" = ( -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/iv_drip, -/obj/machinery/button/blast_door{ - icon_state = "doorctrl0"; - id_tag = "rescueinfirm"; - name = "Window Shutters Control"; - pixel_x = 24; - pixel_y = -4 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"gT" = ( -/obj/item/flashlight/lantern, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/rescue_base/base) -"gU" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "rescuebridge"; - name = "Blast Shutters"; - opacity = 0 - }, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"gV" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gW" = ( -/obj/structure/closet{ - name = "Prisoner's Locker" - }, -/obj/item/clothing/shoes/color/orange, -/obj/item/clothing/under/color/orange, -/obj/item/radio/intercom/specops{ - dir = 8; - pixel_x = 22; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"gX" = ( -/obj/effect/paint/sun, -/turf/simulated/wall/titanium, -/area/map_template/rescue_base/start) -"gY" = ( -/obj/structure/shuttle/engine/heater, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/effect/paint/sun, -/turf/simulated/wall/titanium, -/area/map_template/rescue_base/start) -"gZ" = ( -/obj/structure/table/glass, -/obj/item/chems/spray/antiseptic, -/obj/item/chems/spray/cleaner, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"ha" = ( -/obj/machinery/optable, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"hb" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "rescueinfirm"; - name = "Blast Shutters"; - opacity = 0 - }, -/obj/effect/paint/blue, -/turf/simulated/floor/plating, -/area/map_template/rescue_base/start) -"hc" = ( -/obj/item/pickaxe/diamonddrill, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/rescue_base/base) -"hd" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/obj/machinery/light{ - dir = 8 - }, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"he" = ( -/obj/structure/closet{ - name = "Prisoner's Locker" - }, -/obj/item/clothing/shoes/color/orange, -/obj/item/clothing/under/color/orange, -/turf/simulated/floor/tiled/dark, -/area/map_template/rescue_base/start) -"hf" = ( -/obj/structure/shuttle/engine/propulsion, -/obj/effect/paint/sun, -/turf/simulated/wall/titanium, -/area/map_template/rescue_base/start) -"hg" = ( -/obj/structure/table/glass, -/obj/item/chems/syringe/antibiotic, -/obj/item/chems/syringe/antibiotic, -/obj/item/stack/medical/advanced/bruise_pack, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"hh" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/surgery, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"hi" = ( -/obj/structure/table/glass, -/obj/item/clothing/mask/surgical, -/obj/item/clothing/gloves/latex, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/white, -/area/map_template/rescue_base/start) -"hj" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 10 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"hk" = ( -/obj/effect/floor_decal/industrial/warning, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) -"hl" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 6 - }, -/turf/unsimulated/floor{ - icon_state = "asteroidfloor" - }, -/area/map_template/rescue_base/base) - -(1,1,1) = {" -ab -an -at -aA -aJ -aY -bl -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -"} -(2,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bA -bB -ac -bA -bB -dp -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -"} -(3,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bK -bA -bA -bA -dd -bA -bA -ac -ac -ac -ac -ac -ad -ad -ad -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -hc -ac -ac -ac -ac -ac -ac -ac -ac -"} -(4,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bA -bA -bC -bA -bA -bA -bB -bK -ac -ac -ac -ac -ad -ev -eH -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bA -bA -ac -ac -ac -ac -ac -ac -ac -ac -"} -(5,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ad -ad -ad -ad -bA -bA -bA -bA -bB -bB -bK -bA -bA -bA -ac -ac -ac -ad -ew -eI -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -gT -bA -bB -ac -ac -ac -ac -ac -ac -ac -"} -(6,1,1) = {" -ac -ac -ac -ad -ad -ad -ad -ad -ad -ad -bU -bY -ad -ad -ad -bg -bg -bg -bg -bg -ad -ad -ac -ac -ac -ac -ad -ex -eJ -ad -ac -ac -ac -bA -bA -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bB -bA -ac -ac -ac -ac -ac -ac -ac -"} -(7,1,1) = {" -ac -ac -ac -ad -aK -aZ -aZ -bu -ad -bO -ao -ao -bO -ad -ar -ar -ar -ar -ar -ar -dq -ad -ac -ac -ac -ac -ad -ad -ad -ad -ac -ac -bA -bA -bA -bA -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bA -bB -ac -ac -ac -ac -ac -ac -ac -"} -(8,1,1) = {" -ac -ac -ac -ad -aL -aZ -aZ -bv -ad -bP -bV -bV -bP -ad -ar -cA -ar -cP -cP -ar -dr -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bA -ac -bB -bA -bC -bB -bB -ac -ac -ac -ac -ac -ac -ac -bB -bB -bB -bB -bB -bB -fB -bB -bB -ac -ac -ac -ac -ac -"} -(9,1,1) = {" -ac -ac -ac -ad -ad -ba -ad -ad -ad -bO -ao -ao -bO -ad -cv -cB -ar -cP -cP -ar -ds -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bB -bB -bB -bB -bA -bA -fB -bB -bB -ac -ac -bB -bB -bB -bA -bC -bB -bC -bB -bA -bA -bB -bB -bB -ac -ac -ac -ac -"} -(10,1,1) = {" -ac -ac -ac -ad -aM -aZ -bm -bw -ad -bP -bV -bV -bP -ad -ar -cB -ar -cP -cP -ar -dt -ad -ad -ad -ad -ad -ad -ad -ac -ac -ac -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bA -bB -bB -bB -bB -bA -bB -bB -ac -ac -ac -"} -(11,1,1) = {" -ac -ac -ac -ad -aN -aZ -aZ -bx -ad -bO -ao -ao -bO -ad -ar -ar -ar -ar -ar -ar -du -bg -ar -ar -dS -dT -er -ad -ac -ac -ac -bB -eM -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -eP -hj -bB -ac -ac -ac -"} -(12,1,1) = {" -ac -ac -ac -ad -aO -aZ -aZ -by -ad -bQ -bV -bV -bP -ad -ar -ar -ar -ar -ar -ar -dv -bg -ar -dO -dT -eg -ar -ad -ac -ac -bB -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(13,1,1) = {" -ac -ac -ac -ad -aP -aZ -aZ -aZ -bJ -ar -ao -ao -ao -cb -ao -ao -ao -ao -ao -ao -ao -dy -ao -ao -dU -ao -dP -ad -ac -ac -bB -bA -eN -eQ -eT -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -eU -eU -eU -eU -eU -gU -eU -gX -gX -eQ -hk -bB -bB -ac -ac -"} -(14,1,1) = {" -ac -ad -ad -ad -ad -bb -ad -bz -ad -bR -ar -ar -ca -ad -cw -cD -cL -cQ -de -ao -ao -bg -ar -ao -ao -ao -et -ad -ac -ac -ac -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -gh -gp -fx -gG -gG -gV -hd -gY -hf -eQ -hk -bB -bB -ac -ac -"} -(15,1,1) = {" -ac -ad -au -aB -aQ -aB -ad -ad -ad -ad -bW -bW -ad -ad -bg -bg -bg -ad -ad -dl -dl -ad -bg -bg -dV -ad -ad -ad -ac -ac -ac -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -gi -eZ -gz -eZ -eZ -eZ -eZ -gY -hf -eQ -hk -bB -bC -bB -ac -"} -(16,1,1) = {" -ac -ad -ad -ad -aR -bc -ad -bA -bB -bg -ar -ar -ad -cc -cx -cE -cM -cR -bg -ao -ao -bg -dD -ar -ar -eh -ad -ac -ac -ac -bB -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -gj -gq -fx -eZ -gP -gW -he -gY -hf -eQ -hk -bB -bB -bB -ac -"} -(17,1,1) = {" -ac -ad -av -av -aR -bc -ad -bB -bK -bg -ar -ar -bg -cd -ar -ar -ar -ar -bg -ao -ao -bg -dE -ar -ar -ei -bg -bB -bB -bB -bB -bA -eN -eQ -eU -eU -eU -eU -eU -eU -fC -fC -fC -eU -eU -eQ -eU -eU -eU -eU -gH -eU -eU -eU -gX -gX -eQ -hk -bB -bB -ac -ac -"} -(18,1,1) = {" -ac -ad -aw -aB -aS -aB -ad -bC -bA -bg -ar -ar -bg -ce -ar -ar -ar -ar -df -ao -dw -ad -dF -ar -ar -ej -bg -bB -bA -bB -bA -bB -eN -eQ -eV -eY -ff -fm -fr -fx -fD -fK -fO -fD -eU -eQ -eQ -eQ -eU -eZ -eZ -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -bA -ac -ac -"} -(19,1,1) = {" -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ar -ar -bg -cf -ao -ao -ao -ao -dg -ao -ao -dz -ao -ao -ao -ek -bg -bB -bC -bB -bB -bB -eN -eQ -eV -eZ -fg -eZ -eZ -fy -eZ -eZ -eZ -fR -eU -eU -eU -eU -eU -ge -gI -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(20,1,1) = {" -ac -ac -ac -ad -aT -bd -bn -bD -bL -ad -ar -ar -ad -cg -ao -cF -cN -ao -dg -ao -ao -dz -ao -ao -ao -aT -bg -bB -bB -bB -bA -bB -eN -eQ -eV -fa -fh -fo -eZ -fx -eZ -eZ -eZ -eZ -fZ -eZ -gf -gd -eZ -eZ -fX -eU -eQ -eQ -eQ -eQ -eQ -hk -bA -bB -ac -ac -"} -(21,1,1) = {" -ac -ac -ac -ad -aU -ao -ao -ao -ao -ad -ar -ar -ad -ad -bg -bg -bg -ad -ad -dm -ao -ad -ad -bg -bg -bg -ad -ad -ad -bB -bB -bB -eN -eQ -eV -fb -fi -fp -fs -fx -fE -fL -fP -fS -fx -eZ -eZ -fx -gr -gr -gJ -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(22,1,1) = {" -ac -ac -ac -ad -ao -ao -ao -ao -ao -ad -ar -ar -ad -ch -ao -ao -ao -ao -dh -ao -ao -dA -ao -ao -ao -ao -ao -ch -ad -bB -bB -dd -eN -eQ -eU -eU -eU -eU -eU -eU -eU -eU -eU -eU -eU -ge -fR -eU -eU -eU -eU -eU -gX -gX -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(23,1,1) = {" -ac -ac -ad -ad -ad -ad -ad -bE -ad -ad -ar -ar -bg -ci -ao -ao -ao -ao -dh -ao -ao -dA -ao -ao -ao -ao -ao -ci -bg -bB -bA -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -fT -ga -eZ -eZ -eU -gs -gA -gt -gQ -gY -hf -eQ -eQ -eQ -hk -bB -ac -ac -ac -"} -(24,1,1) = {" -ac -ac -ad -aC -aV -be -bo -ao -ar -ad -ar -ar -bg -cj -ar -cG -ar -ar -di -ao -ao -dB -ar -ar -dW -em -ar -ey -bg -bB -bB -bA -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -fU -gb -eZ -eZ -gk -gt -gt -gt -gQ -gY -hf -eQ -eQ -eQ -hk -bC -ac -ac -ac -"} -(25,1,1) = {" -ad -ad -ad -aD -ao -ao -ao -ao -ao -bS -ao -ao -bg -ck -ar -cH -ar -cS -dj -ao -ao -bg -dG -ar -dX -en -ar -ez -bg -bB -bB -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -ff -gb -eZ -eZ -gk -gt -gt -gt -gt -gY -hf -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(26,1,1) = {" -ae -ao -ad -aE -ao -ao -ao -ao -ao -bS -ao -ao -bg -cl -ar -cI -ar -cT -dj -ao -ao -bg -dH -ar -dX -en -ar -eA -bg -bA -bC -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -fV -gc -eZ -eZ -eU -gu -gu -gK -gt -gY -hf -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(27,1,1) = {" -af -ao -ad -aF -ao -ao -ao -ao -bM -ad -ao -ao -bg -cm -ar -ar -ar -cU -dj -ao -ao -bg -dI -ar -dX -en -ar -eB -ad -bB -bB -bB -eN -eQ -eU -eU -eU -eU -eU -eU -eU -eU -eU -eU -eU -ge -fX -eU -eU -eU -eU -eU -gX -gX -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(28,1,1) = {" -ag -ao -ad -aG -aW -bf -bp -bF -bN -ad -aU -ao -ad -cm -cy -cJ -cO -cV -dj -ao -ao -ad -dJ -ar -dX -en -ar -eC -ad -bB -bB -bB -eN -eQ -eU -fc -fj -fj -ft -eU -fF -fM -fQ -fW -fx -eZ -eZ -fx -gv -gB -gL -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -ac -ac -ac -"} -(29,1,1) = {" -ad -ap -ad -ad -ad -ad -ad -ad -ad -ad -ao -ao -ad -ad -bg -bg -bg -ad -ad -aU -ao -ad -dK -ar -ar -ar -ar -eD -ad -dZ -dZ -dZ -dZ -eR -eW -fd -fk -fk -fu -fz -fG -eZ -eZ -eZ -gd -eZ -gg -gl -gw -gw -gM -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -ac -ac -ac -"} -(30,1,1) = {" -ah -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ad -dL -ar -ar -ar -ar -eE -ad -dZ -dZ -dZ -dZ -eR -eX -fd -fk -fk -fv -fA -fH -eZ -eZ -fX -eU -eU -eU -eU -eU -gC -gN -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -ac -ac -ac -"} -(31,1,1) = {" -ah -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ad -cR -dP -dY -dY -eu -eF -ad -dZ -dZ -bB -eN -eQ -eU -fe -fl -fq -fw -eU -fI -fN -fN -fY -eU -eQ -eQ -eQ -eU -gD -gw -eU -eQ -eQ -eQ -eQ -eQ -hk -bB -bB -ac -ac -"} -(32,1,1) = {" -ad -ad -ad -ad -ad -bg -bg -bg -bg -bT -bT -ad -ad -ad -ad -ad -ad -ad -ad -ao -dx -ad -ad -bg -bg -bg -bg -ad -ad -dZ -dZ -bB -eN -eQ -eU -eU -eU -eU -eU -eU -fJ -fJ -fJ -eU -eU -eQ -eU -eU -eU -gE -gw -eU -eU -eU -gX -gX -eQ -hk -bB -bB -ac -ac -"} -(33,1,1) = {" -ai -aq -ax -aH -ad -bh -bq -ar -ar -ar -ar -bZ -ad -cn -ao -ao -ao -ao -dk -ao -ao -dC -dN -dQ -dZ -dZ -dZ -dZ -dZ -dZ -dZ -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -gm -gx -gw -gw -gR -gZ -hg -gY -hf -eQ -hk -bB -bB -ac -ac -"} -(34,1,1) = {" -aj -ar -ar -ar -ad -bi -br -bG -ar -ar -ar -bZ -ad -co -ao -ar -ao -ao -dk -ao -ao -dC -dN -dQ -ea -eo -eo -eo -eo -eL -dZ -bA -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -gn -gy -gw -gw -gw -gw -hh -gY -hf -eQ -hk -bB -bB -ac -ac -"} -(35,1,1) = {" -ak -ar -ay -ar -aX -ar -ar -ar -ar -ar -ar -ar -ad -cp -ao -ar -ao -cW -ad -ao -ao -ad -ad -ad -ad -ep -ep -ep -ep -ad -ad -bB -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -go -gw -gF -gO -gS -ha -hi -gY -hf -eQ -hk -bB -bB -ac -ac -"} -(36,1,1) = {" -al -ar -ar -ar -ad -ar -bs -ar -ar -ar -bs -ar -ad -cq -ao -ar -ao -cX -ad -ao -ao -ao -ao -dR -eb -ao -ao -ao -ao -ec -ad -bB -eN -eQ -eT -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eU -eU -eU -eU -eU -eU -hb -eU -gX -gX -eQ -hk -bB -ac -ac -ac -"} -(37,1,1) = {" -am -as -az -aI -ad -bg -bt -bg -ad -bg -bX -bg -ad -aT -ao -ar -ao -cY -ad -aU -ao -ao -ao -dR -ao -ao -ao -ao -ao -ec -ad -bC -eN -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -eQ -hk -bB -ac -ac -ac -"} -(38,1,1) = {" -ad -ad -ad -ad -ad -bj -ar -bH -ad -bH -ar -bj -ad -cs -ao -ar -ao -cZ -ad -ao -ao -ad -ad -ad -ec -ao -ao -ao -ao -ec -ad -bA -eO -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -eS -hl -bB -bB -ac -ac -"} -(39,1,1) = {" -ac -ac -ac -ac -ad -bk -ar -bI -ad -bI -ar -bk -ad -ct -ao -ar -ao -da -ad -ao -ao -ad -ac -ad -ed -ao -ao -ao -ao -ec -ad -bA -bB -bB -bB -bB -bB -bB -bB -bA -bB -bB -bB -bB -bB -bB -bB -bA -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -bB -ac -ac -ac -"} -(40,1,1) = {" -ac -ac -ac -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -cu -ao -ao -ao -db -ad -dn -dn -ad -ac -ad -ee -eq -eq -eq -ao -ec -ad -bB -bC -bB -bA -bB -bB -ac -ac -bA -bB -bB -bA -bB -bA -bA -bB -bB -bB -bB -fB -bB -bA -bB -bB -bB -bC -bA -ac -ac -ac -ac -"} -(41,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ad -ad -cz -cK -ad -ad -ad -ao -ao -ad -ac -ad -ad -ad -ad -ad -eK -ad -ad -bA -bA -ac -ac -ac -ac -ac -ac -ac -ac -bB -bB -bA -bB -ac -ac -bB -bB -bB -bA -bB -bB -bB -bB -ac -bB -bB -ac -ac -ac -ac -"} -(42,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ad -ad -ad -ad -dc -ao -ao -ao -ad -ac -ac -ac -ac -ad -eG -ao -ar -ad -bB -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bB -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -bB -bB -bB -ac -ac -ac -ac -ac -"} -(43,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ad -dc -ao -ao -ao -ad -ac -ac -ac -ac -ad -ec -eq -ec -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bB -ac -ac -ac -ac -ac -ac -ac -ac -"} -(44,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ad -ad -ad -ao -ao -ad -ac -ac -ac -ac -ad -ad -ad -ad -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -bA -bA -ac -ac -ac -ac -ac -ac -ac -ac -"} -(45,1,1) = {" -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ad -do -do -ad -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -"} diff --git a/maps/antag_spawn/heist/heist.dm b/maps/antag_spawn/heist/heist.dm deleted file mode 100644 index bbe276a02fff..000000000000 --- a/maps/antag_spawn/heist/heist.dm +++ /dev/null @@ -1,58 +0,0 @@ -/datum/map_template/ruin/antag_spawn/heist - name = "Heist Base" - id = MODE_RAIDER + "_spawn" - suffixes = list("heist/heist_base.dmm") - shuttles_to_initialise = list(/datum/shuttle/autodock/multi/antag/skipjack) - apc_test_exempt_areas = list( - /area/map_template/skipjack_station = NO_SCRUBBER|NO_VENT|NO_APC - ) - -/datum/shuttle/autodock/multi/antag/skipjack - name = "Skipjack" - defer_initialisation = TRUE - warmup_time = 0 - destination_tags = list( - "nav_skipjack_dock", - "nav_skipjack_start" - ) - shuttle_area = /area/map_template/skipjack_station/start - dock_target = "skipjack_shuttle" - current_location = "nav_skipjack_start" - landmark_transition = "nav_skipjack_transition" - announcer = "Proximity Sensor Array" - home_waypoint = "nav_skipjack_start" - arrival_message = "Attention, vessel detected entering vessel proximity." - departure_message = "Attention, vessel detected leaving vessel proximity." - -/obj/effect/shuttle_landmark/skipjack/start - name = "Raider Outpost" - landmark_tag = "nav_skipjack_start" - docking_controller = "skipjack_base" - -/obj/effect/shuttle_landmark/skipjack/internim - name = "In transit" - landmark_tag = "nav_skipjack_transition" - -/obj/effect/shuttle_landmark/skipjack/dock - name = "Docking Port" - landmark_tag = "nav_skipjack_dock" - docking_controller = "skipjack_shuttle_dock_airlock" - -//Areas -/area/map_template/skipjack_station - name = "Raider Outpost" - icon_state = "yellow" - requires_power = 0 - req_access = list(access_syndicate) - -/area/map_template/skipjack_station/start - name = "\improper Skipjack" - icon_state = "yellow" - req_access = list(access_syndicate) - area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED - -/area/map_template/syndicate_mothership/raider_base - name = "\improper Raider Base" - requires_power = 0 - dynamic_lighting = 0 - req_access = list(access_syndicate) diff --git a/maps/antag_spawn/heist/heist_base.dmm b/maps/antag_spawn/heist/heist_base.dmm deleted file mode 100644 index bdae515c5a52..000000000000 --- a/maps/antag_spawn/heist/heist_base.dmm +++ /dev/null @@ -1,6921 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/space, -/area/space) -"ab" = ( -/turf/simulated/wall/natural, -/area/space) -"ac" = ( -/turf/unsimulated/mineral, -/area/space) -"ad" = ( -/turf/unsimulated/wall, -/area/space) -"ae" = ( -/turf/unsimulated/wall, -/area/map_template/syndicate_mothership/raider_base) -"af" = ( -/obj/random/junk, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"ag" = ( -/obj/structure/closet/secure_closet/freezer/kitchen, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"ah" = ( -/obj/structure/table/reinforced, -/obj/item/storage/tray{ - pixel_y = 5 - }, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"ai" = ( -/obj/structure/table/standard, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"aj" = ( -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"ak" = ( -/obj/structure/closet/secure_closet/freezer/fridge, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"al" = ( -/obj/random/trash, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"am" = ( -/obj/structure/table/standard, -/obj/machinery/chemical_dispenser/bar_soft/full, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"an" = ( -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"ao" = ( -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"ap" = ( -/obj/structure/table/reinforced, -/obj/machinery/microwave{ - pixel_x = -1; - pixel_y = 8 - }, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"aq" = ( -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"ar" = ( -/obj/machinery/door/airlock/hatch{ - name = "\improper NO DUST BREATHER ALLOWED" - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"as" = ( -/obj/machinery/vending/snack{ - name = "Getmore Chocolate Corp"; - markup = 0 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"at" = ( -/obj/structure/kitchenspike, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"au" = ( -/obj/vehicle/bike/thermal, -/obj/random/trash, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"av" = ( -/obj/vehicle/bike/thermal, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"aw" = ( -/obj/random/trash, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"ax" = ( -/obj/item/radio/intercom/raider{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"ay" = ( -/obj/random/junk, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"az" = ( -/obj/random/trash, -/obj/item/chems/glass/bucket, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"aA" = ( -/obj/structure/aliumizer, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"aB" = ( -/obj/random/coin, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"aC" = ( -/turf/simulated/wall/natural, -/area/map_template/syndicate_mothership/raider_base) -"aD" = ( -/obj/machinery/door/airlock/hatch, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"aE" = ( -/obj/effect/decal/cleanable/blood, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"aF" = ( -/obj/machinery/gibber, -/turf/unsimulated/floor{ - icon_state = "white" - }, -/area/map_template/syndicate_mothership/raider_base) -"aG" = ( -/obj/structure/reagent_dispensers/fueltank, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"aH" = ( -/obj/structure/hygiene/urinal{ - pixel_y = 32 - }, -/obj/item/soap, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"aI" = ( -/obj/structure/hygiene/urinal{ - pixel_y = 32 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"aJ" = ( -/obj/structure/hygiene/urinal{ - pixel_y = 32 - }, -/obj/random/trash, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"aK" = ( -/obj/structure/bed, -/obj/effect/decal/cleanable/dirt, -/obj/structure/sign/monkey_painting{ - pixel_x = -28; - pixel_y = 4 - }, -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/obj/effect/floor_decal/carpet{ - dir = 9 - }, -/obj/item/bedsheet/green, -/obj/structure/curtain/open/bed, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aL" = ( -/obj/effect/landmark{ - name = "voxstart" - }, -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aM" = ( -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aN" = ( -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/obj/random/trash, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aO" = ( -/obj/structure/bed, -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/obj/effect/floor_decal/carpet{ - dir = 5 - }, -/obj/item/bedsheet/rd, -/obj/structure/curtain/open/bed, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aP" = ( -/obj/machinery/door/airlock/hatch, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"aQ" = ( -/obj/random/junk, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"aR" = ( -/obj/random/loot, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"aS" = ( -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"aT" = ( -/obj/effect/decal/cleanable/blood, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"aU" = ( -/obj/machinery/door/airlock/hatch{ - name = "\improper LITTLE VOX ROOM" - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"aV" = ( -/obj/item/radio/intercom/raider{ - dir = 8; - pixel_x = 22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"aW" = ( -/obj/structure/bed, -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/item/bedsheet/hos, -/obj/structure/curtain/open/bed, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aX" = ( -/obj/effect/landmark{ - name = "voxstart" - }, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aY" = ( -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"aZ" = ( -/obj/structure/bed, -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/obj/item/bedsheet/rainbow, -/obj/structure/curtain/open/bed, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"ba" = ( -/obj/structure/hygiene/sink{ - icon_state = "sink"; - dir = 8; - pixel_x = -12; - pixel_y = 2 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"bb" = ( -/obj/structure/bed, -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/item/bedsheet/clown, -/obj/structure/curtain/open/bed, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bc" = ( -/obj/structure/bed, -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/obj/item/bedsheet/orange, -/obj/structure/curtain/open/bed, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bd" = ( -/obj/effect/decal/cleanable/cobweb, -/obj/machinery/fabricator/hacked, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"be" = ( -/obj/structure/closet/crate, -/obj/item/stack/material/steel{ - amount = 50 - }, -/obj/item/stack/material/steel{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/machinery/light/small{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bf" = ( -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bg" = ( -/obj/structure/sign/warning/nosmoking_1{ - desc = "A warning sign which reads 'NO SMOKING'. Someone has scratched a variety of crude words in gutter across the entire sign."; - pixel_y = 32 - }, -/obj/item/storage/fancy/cigarettes/dromedaryco, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bh" = ( -/obj/effect/decal/cleanable/blood/oil, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bi" = ( -/obj/effect/decal/cleanable/cobweb2{ - icon_state = "spiderling"; - name = "dead spider" - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bj" = ( -/obj/item/clothing/head/xenos, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bk" = ( -/obj/random/trash, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bl" = ( -/obj/structure/hygiene/sink{ - icon_state = "sink"; - dir = 8; - pixel_x = -12; - pixel_y = 2 - }, -/obj/item/storage/mirror{ - dir = 4; - pixel_x = -28; - pixel_y = 0 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"bm" = ( -/obj/structure/hygiene/shower{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bn" = ( -/obj/structure/hygiene/shower{ - dir = 1 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/syndicate_mothership/raider_base) -"bo" = ( -/obj/structure/table/woodentable, -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/random/junk, -/obj/random/maintenance, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bp" = ( -/obj/structure/table/woodentable, -/obj/random/action_figure, -/obj/random/contraband, -/obj/random/junk, -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bq" = ( -/obj/effect/wingrille_spawn/reinforced/crescent, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"br" = ( -/obj/item/radio/intercom/raider{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"bs" = ( -/obj/effect/decal/cleanable/spiderling_remains, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bt" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; - dir = 6 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bu" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/machinery/atmospherics/portables_connector{ - dir = 8 - }, -/obj/random/toolbox, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bv" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/hatch/yellow, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/structure/window/reinforced{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bw" = ( -/obj/effect/floor_decal/industrial/hatch/yellow, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bx" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/hatch/yellow, -/obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"by" = ( -/obj/item/clothing/mask/gas/swat{ - desc = "A close-fitting mask clearly not made for a human face."; - name = "\improper alien mask" - }, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bz" = ( -/obj/item/cat_hide, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bA" = ( -/obj/structure/table/rack, -/obj/item/gun/launcher/alien/spikethrower, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bC" = ( -/obj/effect/decal/cleanable/cobweb2{ - icon_state = "spiderling"; - name = "dead spider" - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"bD" = ( -/obj/item/radio/intercom/raider{ - dir = 1; - pixel_y = -22 - }, -/obj/effect/floor_decal/carpet, -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/effect/floor_decal/carpet{ - dir = 10 - }, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bE" = ( -/obj/effect/floor_decal/carpet, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bF" = ( -/obj/structure/closet{ - name = "Clothing Storage" - }, -/obj/effect/floor_decal/carpet, -/obj/item/clothing/under/lawyer/black, -/obj/item/clothing/under/lawyer/bluesuit, -/obj/item/clothing/under/rank/mailman, -/obj/item/clothing/accessory/storage, -/obj/item/clothing/under/rank/dispatch, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bG" = ( -/obj/structure/undies_wardrobe, -/obj/effect/floor_decal/carpet, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bH" = ( -/obj/random/junk, -/obj/effect/floor_decal/carpet, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bI" = ( -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/obj/effect/floor_decal/carpet, -/obj/effect/floor_decal/carpet{ - dir = 6 - }, -/turf/unsimulated/floor{ - icon_state = "carpet"; - name = "carpet" - }, -/area/map_template/syndicate_mothership/raider_base) -"bJ" = ( -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"bK" = ( -/turf/unsimulated/floor{ - icon = 'icons/turf/flooring/wood.dmi'; - icon_state = "wood_broken2" - }, -/area/map_template/syndicate_mothership/raider_base) -"bL" = ( -/obj/structure/table/woodentable, -/obj/item/storage/tray{ - pixel_y = 5 - }, -/obj/item/storage/backpack, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"bM" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/glasses/rocks, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"bN" = ( -/obj/structure/table/woodentable, -/obj/machinery/chemical_dispenser/bar_soft/full, -/turf/unsimulated/floor{ - icon = 'icons/turf/flooring/wood.dmi'; - icon_state = "wood_broken6" - }, -/area/map_template/syndicate_mothership/raider_base) -"bO" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/washing_machine, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bP" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/portables_connector{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bQ" = ( -/obj/machinery/atmospherics/omni/mixer{ - tag_east = 1; - tag_east_con = 0.5; - tag_north = 1; - tag_north_con = 2; - tag_south = null; - tag_south_con = null; - tag_west = 1; - tag_west_con = 0.5; - use_power = 0 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bR" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/portables_connector{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bS" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/hatch/yellow, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) -"bT" = ( -/obj/item/pizzabox/meat, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bU" = ( -/obj/structure/table/rack, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"bV" = ( -/obj/item/stool/padded, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"bW" = ( -/obj/effect/decal/cleanable/generic, -/obj/item/stool/padded, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"bZ" = ( -/obj/machinery/acting/changer, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"ca" = ( -/obj/structure/table/woodentable, -/obj/item/pizzabox/meat, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"cb" = ( -/obj/structure/table/woodentable, -/obj/item/ashtray, -/obj/item/trash/cigbutt/cigarbutt, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"cc" = ( -/obj/structure/table/woodentable, -/obj/item/chems/glass/rag, -/obj/random/loot, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"cd" = ( -/obj/machinery/vending/cigarette{ - name = "hacked cigarette machine"; - markup = 0products = list(/obj/item/storage/fancy/cigarettes = 10, /obj/item/storage/box/matches = 10, /obj/item/flame/lighter/zippo/random = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2) - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"ce" = ( -/obj/item/tank/nitrogen, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"cf" = ( -/obj/item/storage/backpack, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"cg" = ( -/obj/structure/sign/poster{ - pixel_y = -32 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"ch" = ( -/turf/unsimulated/floor{ - icon = 'icons/turf/flooring/wood.dmi'; - icon_state = "wood_broken1" - }, -/area/map_template/syndicate_mothership/raider_base) -"ci" = ( -/obj/item/stool/padded, -/turf/unsimulated/floor{ - icon = 'icons/turf/flooring/wood.dmi'; - icon_state = "wood_broken1" - }, -/area/map_template/syndicate_mothership/raider_base) -"cj" = ( -/mob/living/simple_animal/hostile/retaliate/parrot{ - available_channels = list(); - ears = list(); - name = "\proper Meatbag"; - speak = list("Yaaar!","Squaaak!","Fight me Matey!","BAWWWWK Vox trying to eat me!") - }, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"ck" = ( -/obj/structure/grille, -/obj/structure/lattice, -/turf/space, -/area/space) -"cl" = ( -/obj/random/junk, -/obj/item/radio/intercom/raider{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"cm" = ( -/obj/item/radio/intercom/raider{ - dir = 4; - pixel_x = -22 - }, -/obj/structure/flora/pottedplant{ - desc = "Used to bring the room together...before the accident."; - icon_state = "plant-25"; - name = "Jamie" - }, -/turf/unsimulated/floor{ - icon_state = "wood" - }, -/area/map_template/syndicate_mothership/raider_base) -"cn" = ( -/obj/structure/reagent_dispensers/beerkeg, -/turf/unsimulated/floor{ - icon = 'icons/turf/flooring/wood.dmi'; - icon_state = "wood_broken1" - }, -/area/map_template/syndicate_mothership/raider_base) -"co" = ( -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - id_tag = "skipjack_base"; - pixel_x = -25; - pixel_y = -5 - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"cp" = ( -/obj/structure/closet/crate, -/obj/item/tank/nitrogen, -/obj/item/tank/nitrogen, -/obj/item/tank/nitrogen, -/obj/item/tank/nitrogen, -/obj/item/tank/nitrogen, -/obj/item/tank/nitrogen, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"cq" = ( -/obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"cr" = ( -/obj/item/clothing/head/philosopher_wig, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/syndicate_mothership/raider_base) -"cs" = ( -/obj/structure/lattice, -/turf/space, -/area/space) -"ct" = ( -/obj/machinery/door/airlock/external, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"cu" = ( -/obj/machinery/door/airlock/external{ - id_tag = "skipjack_base_hatch" - }, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/syndicate_mothership/raider_base) -"cv" = ( -/obj/item/trash/cheesie, -/turf/space, -/area/space) -"cw" = ( -/obj/effect/paint/black, -/turf/simulated/wall/voxshuttle, -/area/map_template/skipjack_station/start) -"cx" = ( -/obj/machinery/door/airlock/external{ - icon_state = "door_closed"; - id_tag = "vox_northwest_lock"; - locked = 0 - }, -/obj/machinery/shield_diffuser, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cy" = ( -/obj/machinery/button/access/shuttle/exterior{ - id_tag = "vox_west_control"; - req_access = list("ACCESS_SYNDICATE") - }, -/obj/effect/paint/black, -/turf/simulated/wall/voxshuttle, -/area/map_template/skipjack_station/start) -"cz" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "SkipjackShuttersNorth"; - name = "Blast Doors"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/brown, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cA" = ( -/obj/machinery/door/airlock/external{ - density = 1; - id_tag = "skipjack_shuttle_outer"; - name = "Ship External Access" - }, -/obj/machinery/shield_diffuser, -/obj/effect/shuttle_landmark/skipjack/start, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cB" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "vox_west_vent" - }, -/obj/random/junk, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cC" = ( -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "vox_west_sensor"; - pixel_x = 25 - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cD" = ( -/obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cE" = ( -/obj/machinery/computer/shuttle_control/multi/vox, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cF" = ( -/obj/structure/table/steel, -/obj/random/plushie, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cG" = ( -/obj/random/trash, -/obj/machinery/airlock_sensor{ - id_tag = "skipjack_shuttle_sensor"; - pixel_x = 8; - pixel_y = 25 - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cH" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; - id_tag = "merc_shuttle_pump" - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cI" = ( -/obj/machinery/atmospherics/pipe/manifold/visible{ - dir = 8 - }, -/obj/machinery/meter, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cJ" = ( -/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - tag_airpump = "vox_west_vent"; - tag_exterior_door = "vox_northwest_lock"; - frequency = 1331; - id_tag = "vox_west_control"; - tag_interior_door = "vox_southwest_lock"; - pixel_x = 24; - tag_chamber_sensor = "vox_west_sensor" - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 8; - id_tag = "vox_west_vent" - }, -/obj/machinery/light/small, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cK" = ( -/obj/machinery/light/small{ - dir = 8 - }, -/obj/machinery/computer/station_alert/all{ - icon_state = "computer"; - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cL" = ( -/obj/structure/bed/chair/shuttle{ - dir = 8 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cM" = ( -/obj/machinery/button/blast_door{ - id_tag = "SkipjackShuttersNorth"; - name = "Skipjack North Shutters"; - pixel_y = 39 - }, -/obj/machinery/button/blast_door{ - id_tag = "SkipjackShuttersWest"; - name = "Skipjack West Shutters"; - pixel_x = -5; - pixel_y = 31 - }, -/obj/machinery/button/blast_door{ - id_tag = "SkipjackShuttersEast"; - name = "Skipjack East Shutters"; - pixel_x = 5; - pixel_y = 31 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cN" = ( -/obj/structure/bed/chair/office/light{ - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cO" = ( -/obj/machinery/constructable_frame/computerframe, -/obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cP" = ( -/obj/machinery/light/small, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - id_tag = "skipjack_shuttle"; - pixel_x = -25; - pixel_y = 8; - req_access = list("ACCESS_SYNDICATE") - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 4; - id_tag = "skipjack_shuttle_pump" - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cQ" = ( -/obj/machinery/atmospherics/pipe/manifold/visible{ - dir = 4 - }, -/obj/machinery/meter, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cR" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/voxshuttle, -/area/map_template/skipjack_station/start) -"cS" = ( -/obj/machinery/door/airlock/external{ - icon_state = "door_closed"; - id_tag = "vox_southwest_lock"; - locked = 0 - }, -/obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cT" = ( -/obj/structure/table/rack, -/obj/random/hardsuit, -/obj/item/clothing/glasses/thermal/plain/monocle, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cU" = ( -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cV" = ( -/obj/random/maintenance, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cW" = ( -/obj/random/junk, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cX" = ( -/obj/structure/table/rack, -/obj/random/hardsuit, -/obj/item/clothing/head/pirate, -/obj/item/gun/launcher/money, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"cY" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/machinery/door/airlock/external{ - id_tag = "skipjack_shuttle_inner"; - name = "Ship External Access" - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"cZ" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/machinery/button/access/shuttle/interior{ - id_tag = "vox_west_control"; - pixel_x = -22; - req_access = list("ACCESS_SYNDICATE") - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"da" = ( -/obj/structure/table/rack, -/obj/random/maintenance, -/obj/item/clothing/shoes/magboots, -/obj/item/tank/oxygen, -/obj/random/voidsuit, -/obj/random/voidhelmet, -/obj/item/harpoon, -/obj/random/energy, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"db" = ( -/obj/machinery/microwave{ - pixel_x = -1; - pixel_y = 8 - }, -/obj/structure/table/steel, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dc" = ( -/obj/item/seeds/potatoseed, -/obj/item/seeds/potatoseed, -/obj/item/seeds/ambrosiavulgarisseed, -/obj/item/minihoe, -/obj/item/beartrap, -/obj/structure/table/steel, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dd" = ( -/obj/machinery/vending/hydroseeds, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"de" = ( -/obj/structure/table/rack, -/obj/item/energy_blade/sword/pirate, -/obj/item/clothing/suit/armor/pirate, -/obj/item/clothing/suit/armor/pirate, -/obj/item/tank/oxygen, -/obj/item/clothing/shoes/magboots, -/obj/random/voidsuit, -/obj/random/voidhelmet, -/obj/random/maintenance, -/obj/machinery/light/small{ - dir = 8 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"df" = ( -/obj/structure/table/rack, -/obj/item/energy_blade/sword/pirate, -/obj/item/clothing/suit/armor/pirate, -/obj/item/clothing/suit/armor/pirate, -/obj/item/tank/oxygen, -/obj/item/clothing/shoes/magboots, -/obj/random/voidsuit, -/obj/random/voidhelmet, -/obj/random/maintenance, -/obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dg" = ( -/obj/structure/table/rack, -/obj/item/storage/belt/utility/full, -/obj/item/storage/belt/utility/full, -/obj/item/multitool, -/obj/item/multitool, -/obj/item/clothing/shoes/magboots, -/obj/random/maintenance, -/obj/item/tank/oxygen, -/obj/random/voidsuit, -/obj/random/voidhelmet, -/obj/random/maintenance, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dh" = ( -/obj/machinery/washing_machine, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"di" = ( -/obj/structure/table/standard, -/obj/item/storage/fancy/cigarettes, -/obj/item/flame/lighter/zippo/random, -/obj/item/clothing/gloves/insulated, -/obj/item/stack/material/steel{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/card/emag, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dj" = ( -/obj/structure/table/rack, -/obj/random/maintenance, -/obj/item/clothing/shoes/magboots, -/obj/item/tank/oxygen, -/obj/random/voidsuit, -/obj/random/voidhelmet, -/obj/random/energy, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dk" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/machinery/button/access/interior{ - id_tag = "skipjack_shuttle"; - name = "interior access button"; - pixel_x = 25; - pixel_y = 25; - req_access = list("ACCESS_SYNDICATE") - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dl" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dm" = ( -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dn" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/machinery/light/small{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"do" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/brown, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dp" = ( -/obj/machinery/door/airlock/hatch, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dq" = ( -/obj/machinery/light/small{ - dir = 8 - }, -/obj/structure/table/rack, -/obj/random/maintenance, -/obj/item/clothing/shoes/magboots, -/obj/item/tank/oxygen, -/obj/random/voidsuit, -/obj/random/voidhelmet, -/obj/random/projectile, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dr" = ( -/obj/random/loot, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"ds" = ( -/obj/item/robot_parts/head, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dt" = ( -/obj/machinery/door/blast/shutters{ - density = 0; - dir = 4; - icon_state = "shutter0"; - id_tag = "SkipjackShuttersWest"; - name = "Skipjack Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/brown, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"du" = ( -/obj/random/trash, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dv" = ( -/obj/random/maintenance, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dw" = ( -/obj/random/trash, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dx" = ( -/obj/item/robot_parts/l_leg, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dy" = ( -/obj/machinery/door/blast/shutters{ - density = 0; - dir = 8; - icon_state = "shutter0"; - id_tag = "SkipjackShuttersEast"; - name = "Skipjack Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/brown, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dz" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dA" = ( -/obj/machinery/floodlight, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dB" = ( -/obj/structure/table/rack, -/obj/item/gun/launcher/crossbow, -/obj/item/stack/material/rods{ - amount = 10 - }, -/obj/machinery/light/small{ - dir = 8 - }, -/obj/item/beartrap, -/obj/item/beartrap, -/obj/item/beartrap, -/obj/item/beartrap, -/obj/item/beartrap, -/obj/item/beartrap, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dC" = ( -/obj/structure/table/rack, -/obj/item/grenade/empgrenade, -/obj/item/grenade/flashbang, -/obj/item/grenade/spawnergrenade/manhacks, -/obj/random/energy, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dD" = ( -/obj/machinery/suit_cycler/syndicate{ - locked = 0 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dE" = ( -/obj/structure/table/steel, -/obj/machinery/recharger, -/obj/machinery/light/small{ - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dF" = ( -/obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dG" = ( -/obj/item/robot_parts/robot_suit, -/obj/item/robot_parts/r_leg, -/obj/item/robot_parts/r_arm, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dH" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/random/maintenance, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dI" = ( -/obj/machinery/door/blast/shutters{ - density = 0; - dir = 4; - icon_state = "shutter0"; - id_tag = "SkipjackShuttersWest"; - name = "Skipjack Shutters"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced/titanium, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dJ" = ( -/obj/random/loot, -/obj/vehicle/bike/thermal, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dK" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/item/clothing/mask/gas/cyborg, -/obj/item/storage/box/donkpockets{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/chems/food/snacks/tastybread, -/obj/item/chems/food/snacks/tastybread, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/skipjack_station/start) -"dL" = ( -/obj/machinery/door/airlock/hatch, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dM" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/obj/machinery/light/small{ - dir = 8 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dN" = ( -/obj/structure/table/steel, -/obj/random/maintenance, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dO" = ( -/obj/structure/bed/chair{ - dir = 8 - }, -/obj/machinery/light/small{ - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dP" = ( -/obj/structure/hygiene/sink{ - icon_state = "sink"; - dir = 8; - pixel_x = -12; - pixel_y = 2 - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dQ" = ( -/obj/item/wrench, -/obj/item/mop, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dR" = ( -/obj/machinery/atmospherics/pipe/simple/visible, -/obj/item/crowbar, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dS" = ( -/obj/machinery/light/small{ - dir = 8 - }, -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dT" = ( -/obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dU" = ( -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"dV" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"dW" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/effect/paint/brown, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"dX" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dY" = ( -/obj/item/deck/cards, -/obj/structure/table/steel, -/obj/random/projectile, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"dZ" = ( -/obj/structure/bed/chair{ - dir = 8 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"ea" = ( -/obj/machinery/bodyscanner{ - dir = 8 - }, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"eb" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/obj/machinery/body_scanconsole{ - dir = 8 - }, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"ec" = ( -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"ed" = ( -/obj/structure/hygiene/toilet{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"ee" = ( -/obj/machinery/portable_atmospherics/canister/nitrogen, -/obj/item/tank/nitrogen, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"ef" = ( -/obj/machinery/light/small{ - dir = 4 - }, -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/turf/simulated/floor/plating, -/area/map_template/skipjack_station/start) -"eg" = ( -/obj/structure/shuttle/engine/heater, -/obj/structure/window/reinforced/crescent{ - dir = 1 - }, -/obj/effect/paint/black, -/turf/simulated/wall/voxshuttle, -/area/map_template/skipjack_station/start) -"eh" = ( -/obj/random/trash, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"ei" = ( -/obj/structure/table/steel, -/obj/random/loot, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"ej" = ( -/obj/random/junk, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"ek" = ( -/obj/structure/hygiene/sink{ - dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 - }, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"el" = ( -/obj/structure/shuttle/engine/propulsion, -/obj/effect/paint/black, -/turf/simulated/wall/voxshuttle, -/area/map_template/skipjack_station/start) -"em" = ( -/obj/structure/table/standard, -/obj/random/maintenance, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"en" = ( -/obj/structure/table/standard, -/obj/item/deck/cards, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"eo" = ( -/obj/machinery/light/small, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"ep" = ( -/obj/random/trash, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"eq" = ( -/obj/structure/table/standard, -/obj/item/circular_saw{ - pixel_y = 8 - }, -/obj/item/hemostat, -/obj/item/scalpel, -/obj/item/stack/medical/advanced/bruise_pack, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"er" = ( -/obj/random/junk, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"es" = ( -/obj/machinery/optable, -/obj/item/clothing/mask/gas, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"et" = ( -/obj/structure/table/standard, -/obj/item/cautery, -/obj/item/retractor, -/obj/item/chems/glass/bottle/sedatives, -/obj/item/chems/glass/bottle/sedatives, -/obj/item/chems/syringe, -/obj/item/gun/launcher/syringe/rapid, -/obj/item/storage/box/syringegun, -/obj/item/chems/glass/beaker/vial/random/toxin, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"eu" = ( -/obj/structure/hygiene/sink{ - dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 - }, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"ev" = ( -/obj/structure/bed, -/obj/item/bedsheet/rainbow, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"ew" = ( -/obj/structure/bed, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"ex" = ( -/obj/random/maintenance, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"ey" = ( -/obj/structure/table/standard, -/obj/item/bonesetter, -/obj/item/bonegel, -/obj/item/sutures, -/obj/item/chems/syringe/antibiotic, -/obj/item/chems/syringe/antibiotic, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"ez" = ( -/obj/structure/hygiene/toilet{ - dir = 4 - }, -/obj/machinery/light/small{ - dir = 8 - }, -/turf/simulated/floor/shuttle/black, -/area/map_template/skipjack_station/start) -"eA" = ( -/obj/structure/closet/crate, -/obj/item/clothing/suit/armor/pirate, -/obj/item/clothing/under/rank/medical/scrubs/black, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"eB" = ( -/obj/structure/bed, -/obj/item/bedsheet/green, -/obj/machinery/light/small{ - dir = 4 - }, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"eC" = ( -/obj/structure/table/standard, -/obj/item/storage/firstaid/fire{ - pixel_x = 1 - }, -/obj/item/storage/firstaid/o2{ - pixel_x = 3; - pixel_y = 3 - }, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"eD" = ( -/obj/structure/table/standard, -/obj/item/storage/firstaid/adv{ - pixel_x = 1 - }, -/obj/item/storage/firstaid/toxin{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/machinery/light/small{ - dir = 4 - }, -/obj/item/baton/cattleprod, -/turf/simulated/floor/shuttle/white, -/area/map_template/skipjack_station/start) -"eE" = ( -/turf/space, -/area/map_template/skipjack_station/start) -"eF" = ( -/obj/structure/bed, -/obj/item/bedsheet/rd, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"eG" = ( -/obj/item/pizzabox/meat, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"eH" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/shuttle/red, -/area/map_template/skipjack_station/start) -"eI" = ( -/obj/machinery/telecomms/allinone{ - intercept = 1 - }, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/syndicate_mothership/raider_base) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -bj -by -bT -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -aQ -aq -bz -aq -aq -ce -bk -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -aq -aq -bA -bU -bU -aq -aq -aq -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aA -aq -aQ -aq -bk -aq -aq -aq -aq -aQ -cp -ab -ab -ab -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(15,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -an -aq -aq -aq -aq -aq -aq -bA -bA -bU -aq -aq -cq -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(16,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ab -ab -ab -ab -aq -aq -aB -aC -aR -aq -aq -aq -aq -aq -cf -cj -cr -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(17,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ab -ab -ab -ab -aq -aq -aC -aC -aq -aq -ab -aq -aQ -aq -aq -ab -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(18,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ab -ab -ab -ab -aj -aq -aC -aC -aq -ab -ab -ab -ab -ab -ab -ab -ab -aa -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(19,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aj -aw -aC -aC -aq -ab -ab -ab -ab -ab -ab -ab -cs -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -af -aj -ae -ae -aj -ae -ae -ae -ab -ab -aa -ck -ck -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aa -aa -aa -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ad -an -an -ae -aH -aS -ba -bl -ae -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ad -ar -ar -ae -aI -aT -aj -bm -ae -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ad -aj -an -ae -aJ -aS -aS -bn -ae -aC -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ad -an -aj -ae -ae -aU -aU -ae -ae -aC -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ad -af -an -an -an -an -an -an -bC -aC -aC -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -aa -aa -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ad -an -an -an -an -aV -af -an -aj -aC -aC -aC -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ad -an -an -ae -ae -ae -ae -ae -aD -ae -ae -ae -ae -ae -ae -ae -ae -cw -cw -cw -cR -cR -cR -dt -dt -dI -cR -cw -cw -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ad -an -an -ae -aK -aW -bb -bo -bD -ae -bZ -aj -cl -ct -an -an -ct -cx -cB -cI -cS -cZ -dl -dl -dz -dz -dS -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ad -an -an -ae -aL -aX -aX -aY -bE -bq -an -aj -aj -ct -an -an -bq -cy -cC -cJ -cR -da -dm -du -dm -dJ -dT -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ad -ad -ad -ad -aj -an -aD -aM -aY -aY -aY -bF -bq -an -cg -ae -ae -bq -bq -ae -cw -cw -cw -cR -db -dm -dm -dA -dK -dT -cw -cw -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -af -aj -an -an -an -aD -aN -aY -aY -aY -bG -bq -af -an -bq -aa -aa -aa -aa -aa -aa -aa -cR -dc -dm -dv -du -cR -cR -cR -cR -cR -cR -cR -eE -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aj -an -an -ae -aL -aX -aX -aY -bH -bq -aj -an -bq -aa -cv -aa -aa -aa -aa -aa -cR -dd -dn -dm -dm -dL -dU -dU -em -dU -eh -cR -cR -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ae -ae -ae -ae -an -an -ae -aO -aZ -bc -bp -bI -ae -an -an -bq -aa -aa -aa -aa -aa -cw -cw -cR -cR -cR -dp -cR -cR -dV -eh -en -dU -dU -ez -cR -cR -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(34,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ae -af -an -ae -ae -ae -ae -ae -aD -ae -aD -aD -ae -ae -aa -aa -aa -cw -cw -cw -cT -de -do -cU -dB -cR -dU -dU -dU -er -eu -dU -cw -cw -cw -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(35,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ae -an -an -an -an -an -an -aD -bJ -bJ -bJ -ch -cm -ae -aa -aa -aa -cw -cD -cK -cU -cU -do -cW -dC -cR -dW -dW -dW -cR -cR -cR -cw -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(36,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ae -ae -ae -ae -as -an -an -an -an -an -ae -bK -bV -ca -bV -bJ -bq -aa -aa -aa -cz -cE -cL -cU -cU -do -cU -cU -dM -dX -dX -eo -cR -ev -eA -eF -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(37,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ae -ag -ak -ae -ae -ae -ae -ae -an -an -ae -bL -bW -cb -ci -bJ -bq -aa -aa -aa -cz -cF -cM -cV -cU -dp -cU -cU -dN -dY -ei -cU -dp -cU -cU -eG -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(38,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ae -ah -al -ao -ao -ax -aE -aD -an -an -bq -bM -bV -cc -bV -bJ -bq -aa -aa -aa -cz -cD -cN -cU -cU -do -dw -cU -dO -dZ -dZ -eo -cR -ew -eB -eH -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(39,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ae -ai -am -ap -ao -ay -ao -aD -af -an -bq -bN -bJ -bJ -bJ -cn -ae -aa -aa -aa -cw -cD -cO -cW -cU -do -cU -dD -cR -dW -dW -dW -cR -cR -cR -cw -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(40,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ae -ae -ae -ae -ao -ao -aF -ae -an -an -ae -bq -bq -aD -aD -ae -ae -aa -aa -aa -cw -cw -cw -cX -df -do -cU -dE -cR -ea -ej -ec -es -ec -eC -cw -cw -cw -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(41,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ae -at -at -ae -ae -an -aj -br -an -an -an -an -bq -aa -aa -aa -aa -aa -cw -cw -cR -cR -cR -dp -cR -cR -eb -ec -ep -ec -ex -eD -cR -cR -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(42,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ae -ae -ae -ae -an -an -an -aj -aj -aj -an -af -bq -aa -aa -aa -aa -aa -aa -aa -cR -dg -dq -dm -dm -dL -ec -ek -eq -et -ey -cR -cR -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(43,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ae -ae -ae -ae -aP -ae -ae -aP -ae -ae -an -an -bq -aa -aa -aa -aa -aa -aa -aa -cR -dh -dm -dm -dF -cR -cR -cR -cR -cR -cR -cR -cR -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(44,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ae -au -aj -aj -aw -ae -bd -aj -bO -ae -an -an -ae -ae -bq -bq -ae -cw -cw -cw -cR -di -dr -dx -dm -dP -ed -cw -cw -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(45,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ae -aj -aj -aG -av -ae -be -bs -bP -ae -an -af -co -cu -an -an -bq -cw -cG -cP -cR -dj -ds -du -dG -dQ -ee -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(46,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ae -av -az -aj -aj -ae -bf -bt -bQ -ae -cd -an -an -cu -an -an -cu -cA -cH -cQ -cY -dk -dl -dl -dH -dR -ef -eg -el -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(47,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ae -eI -aj -av -av -ae -bg -bu -bR -ae -ae -ae -ae -ae -ae -ae -ae -cw -cw -cw -cR -cR -cR -dy -dy -dy -cR -cw -cw -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(48,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ae -ae -ae -ae -ae -ae -bh -bv -bv -ae -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(49,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ab -ab -ab -ab -ab -ab -ab -ab -ae -bf -bw -bS -ae -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(50,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ab -ab -ab -ab -ab -ab -ab -ab -ae -bi -bx -bx -ae -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(51,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ab -ab -ae -ae -ae -ae -ae -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(52,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(53,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(54,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(55,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(56,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(57,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(58,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(59,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(60,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(61,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(62,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(63,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(64,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(65,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(66,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(67,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(68,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(69,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(70,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} diff --git a/maps/antag_spawn/mercenary/mercenary.dm b/maps/antag_spawn/mercenary/mercenary.dm deleted file mode 100644 index 52986c6777a9..000000000000 --- a/maps/antag_spawn/mercenary/mercenary.dm +++ /dev/null @@ -1,86 +0,0 @@ -/datum/map_template/ruin/antag_spawn/mercenary - name = "Mercenary Base" - id = MODE_MERCENARY + "_spawn" - suffixes = list("mercenary/mercenary_base.dmm") - shuttles_to_initialise = list(/datum/shuttle/autodock/overmap/merc_shuttle) - apc_test_exempt_areas = list( - /area/map_template/merc_spawn = NO_SCRUBBER|NO_VENT - ) - -/obj/effect/overmap/visitable/merc_base - name = "TCV Tersten Tenacity" - desc = "Sensor array detects a medium cargo vessel with high structural damage." - sector_flags = OVERMAP_SECTOR_IN_SPACE - icon_state = "ship" - hide_from_reports = TRUE - initial_generic_waypoints = list( - "nav_merc_1", - "nav_merc_2", - "nav_merc_3", - "nav_merc_4" - ) - has_distress_beacon = "SOS - multiple breaches, possible hostiles" - -/obj/effect/overmap/visitable/ship/landable/merc - name = "Desperado" - desc = "A military gunship of ICCG design. Scanner detects heavy modification to the framework of the vessel and no designation." - shuttle = "Desperado" - fore_dir = NORTH - vessel_size = SHIP_SIZE_SMALL - vessel_mass = 14000 - -/datum/shuttle/autodock/overmap/merc_shuttle - name = "Desperado" - shuttle_area = list(/area/map_template/merc_shuttle,/area/map_template/merc_shuttle/rear) - dock_target = "merc_shuttle" - current_location = "nav_merc_start" - defer_initialisation = TRUE - ceiling_type = /turf/simulated/floor/shuttle_ceiling/merc - warmup_time = 5 - range = 1 - fuel_consumption = 7 - skill_needed = SKILL_BASIC - -/turf/simulated/floor/shuttle_ceiling/merc - color = COLOR_RED - -/obj/machinery/computer/shuttle_control/explore/merc_shuttle - name = "shuttle control console" - shuttle_tag = "Desperado" - -/obj/effect/shuttle_landmark/merc/start - landmark_tag = "nav_merc_start" - -/obj/effect/shuttle_landmark/merc/nav1 - landmark_tag = "nav_merc_1" - -/obj/effect/shuttle_landmark/merc/nav2 - landmark_tag = "nav_merc_2" - -/obj/effect/shuttle_landmark/merc/nav3 - landmark_tag = "nav_merc_3" - -/obj/effect/shuttle_landmark/merc/nav4 - landmark_tag = "nav_merc_4" - -/obj/effect/shuttle_landmark/merc/dock - name = "Docking Port" - landmark_tag = "nav_merc_dock" - docking_controller = "nuke_shuttle_dock_airlock" - -//Areas - -/area/map_template/merc_spawn - name = "\improper TCV Tersten Tenacity" - icon_state = "syndie-ship" - req_access = list(access_syndicate) - -/area/map_template/merc_shuttle - name = "\improper Desperado Fore Compartment" - icon_state = "yellow" - area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED - req_access = list(access_syndicate) - -/area/map_template/merc_shuttle/rear - name = "\improper Desperado Rear Compartment" - icon_state = "green" \ No newline at end of file diff --git a/maps/antag_spawn/ninja/ninja.dm b/maps/antag_spawn/ninja/ninja.dm deleted file mode 100644 index 6a5996e10bbd..000000000000 --- a/maps/antag_spawn/ninja/ninja.dm +++ /dev/null @@ -1,48 +0,0 @@ -/datum/map_template/ruin/antag_spawn/ninja - name = "Ninja Base" - id = MODE_NINJA + "_spawn" - suffixes = list("ninja/ninja_base.dmm") - shuttles_to_initialise = list(/datum/shuttle/autodock/multi/antag/ninja) - apc_test_exempt_areas = list( - /area/map_template/ninja_dojo = NO_SCRUBBER|NO_VENT|NO_APC - ) - -/datum/shuttle/autodock/multi/antag/ninja - name = "Ninja" - defer_initialisation = TRUE - warmup_time = 0 - destination_tags = list( - "nav_ninja_start" - ) - shuttle_area = /area/map_template/ninja_dojo/start - current_location = "nav_ninja_start" - landmark_transition = "nav_ninja_transition" - announcer = "Proximity Sensor Array" - arrival_message = "Attention, anomalous sensor reading detected entering vessel proximity." - departure_message = "Attention, anomalous sensor reading detected leaving vessel proximity." - -/obj/effect/shuttle_landmark/ninja/start - name = "Clan Dojo" - landmark_tag = "nav_ninja_start" - -/obj/effect/shuttle_landmark/ninja/internim - name = "In transit" - landmark_tag = "nav_ninja_transition" - -// Areas -/area/map_template/ninja_dojo - name = "\improper Ninja Base" - icon_state = "green" - requires_power = 0 - dynamic_lighting = 1 - area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED - req_access = list(access_syndicate) - -/area/map_template/ninja_dojo/dojo - name = "\improper Clan Dojo" - dynamic_lighting = 0 - -/area/map_template/ninja_dojo/start - name = "\improper Clan Dojo" - icon_state = "shuttlered" - base_turf = /turf/simulated/floor/plating \ No newline at end of file diff --git a/maps/antag_spawn/ninja/ninja_base.dmm b/maps/antag_spawn/ninja/ninja_base.dmm deleted file mode 100644 index b8e17b22d8cd..000000000000 --- a/maps/antag_spawn/ninja/ninja_base.dmm +++ /dev/null @@ -1,3458 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"ac" = ( -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "snowwhite" - }, -/area/map_template/ninja_dojo/dojo) -"ad" = ( -/turf/unsimulated/floor{ - icon_state = "snow" - }, -/area/map_template/ninja_dojo/dojo) -"ae" = ( -/obj/effect/floor_decal/asteroid, -/turf/unsimulated/floor{ - icon_state = "snow" - }, -/area/map_template/ninja_dojo/dojo) -"af" = ( -/obj/effect/floor_decal/asteroid, -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "snowwhite" - }, -/area/map_template/ninja_dojo/dojo) -"ag" = ( -/obj/structure/flora/tree/dead, -/turf/unsimulated/floor{ - icon_state = "snow" - }, -/area/map_template/ninja_dojo/dojo) -"ah" = ( -/obj/structure/flora/tree/pine, -/turf/unsimulated/floor{ - icon_state = "snow" - }, -/area/map_template/ninja_dojo/dojo) -"ai" = ( -/obj/structure/flora/tree/dead, -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "snowwhite" - }, -/area/map_template/ninja_dojo/dojo) -"aj" = ( -/turf/simulated/wall/wood, -/area/map_template/ninja_dojo/dojo) -"ak" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/surgery, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"al" = ( -/obj/machinery/optable, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"am" = ( -/obj/structure/closet/medical_wall{ - pixel_y = 32 - }, -/obj/item/tank/anesthetic, -/obj/item/clothing/mask/breath/medical, -/obj/item/clothing/gloves/latex, -/obj/item/clothing/mask/surgical, -/obj/structure/hygiene/sink{ - dir = 1; - pixel_y = 16 - }, -/obj/item/chems/glass/bottle/sedatives, -/obj/item/chems/glass/bottle/sedatives, -/obj/item/chems/syringe, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"an" = ( -/obj/structure/table/glass, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"ao" = ( -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"ap" = ( -/obj/machinery/atmospherics/portables_connector, -/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aq" = ( -/obj/structure/table/glass, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"ar" = ( -/obj/structure/table/glass, -/obj/item/chems/spray/antiseptic, -/obj/item/chems/spray/cleaner, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"at" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/o2{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/firstaid/fire{ - pixel_x = 1 - }, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"au" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"av" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aw" = ( -/obj/structure/table/glass, -/obj/item/storage/box/beakers, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"ax" = ( -/obj/machinery/computer/teleporter, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/ninja_dojo/dojo) -"ay" = ( -/obj/machinery/teleport/station, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/ninja_dojo/dojo) -"az" = ( -/obj/machinery/teleport/hub, -/obj/effect/floor_decal/industrial/hatch/yellow, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/ninja_dojo/dojo) -"aA" = ( -/obj/effect/wingrille_spawn/reinforced/crescent, -/turf/unsimulated/floor{ - icon_state = "plating"; - name = "plating" - }, -/area/map_template/ninja_dojo/dojo) -"aB" = ( -/obj/structure/table/glass, -/obj/item/chems/syringe/antibiotic, -/obj/item/chems/syringe/antibiotic, -/obj/item/stack/medical/advanced/bruise_pack, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aC" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/toxin{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/firstaid/adv{ - pixel_x = 1 - }, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aD" = ( -/obj/machinery/chemical_dispenser/ert, -/obj/item/chems/glass/beaker/large, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aE" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"aF" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/obj/item/radio/intercom/syndicate{ - dir = 8; - pixel_x = 22 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"aG" = ( -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"aH" = ( -/obj/structure/flora/tree/pine, -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "snowwhite" - }, -/area/map_template/ninja_dojo/dojo) -"aI" = ( -/obj/structure/iv_drip, -/obj/structure/window/reinforced/crescent, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aJ" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/regular, -/obj/item/storage/firstaid/combat, -/obj/structure/window/reinforced/crescent{ - dir = 4 - }, -/obj/structure/window/reinforced/crescent, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aK" = ( -/obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aL" = ( -/obj/effect/floor_decal/spline/fancy/wood, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aM" = ( -/obj/effect/floor_decal/spline/fancy/wood, -/obj/machinery/chemical_dispenser/full, -/obj/item/chems/glass/beaker/large, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aN" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Teleporter" - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"aO" = ( -/obj/effect/floor_decal/carpet/blue{ - dir = 8 - }, -/obj/effect/floor_decal/carpet/blue{ - dir = 1 - }, -/obj/effect/floor_decal/carpet/blue{ - dir = 9 - }, -/obj/effect/landmark{ - name = "ninjastart" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"aP" = ( -/obj/effect/floor_decal/carpet/blue{ - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"aQ" = ( -/obj/effect/floor_decal/carpet/blue{ - dir = 1 - }, -/obj/effect/floor_decal/carpet/blue{ - dir = 4 - }, -/obj/effect/floor_decal/carpet/blue{ - dir = 5 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"aR" = ( -/obj/machinery/bodyscanner{ - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aS" = ( -/obj/machinery/body_scanconsole{ - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aT" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"aU" = ( -/obj/structure/flora/pottedplant/bamboo, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"aV" = ( -/obj/structure/flora/pottedplant/orientaltree, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"aW" = ( -/obj/effect/floor_decal/carpet/blue{ - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"aX" = ( -/obj/effect/floor_decal/chapel{ - icon_state = "chapel"; - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"aY" = ( -/obj/effect/floor_decal/chapel{ - icon_state = "chapel"; - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"aZ" = ( -/obj/effect/floor_decal/carpet/blue{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"ba" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Medical" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bb" = ( -/obj/item/radio/intercom/syndicate{ - dir = 1; - pixel_y = -22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bc" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Dojo" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bd" = ( -/obj/effect/floor_decal/chapel{ - icon_state = "chapel"; - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"be" = ( -/obj/effect/floor_decal/chapel, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"bf" = ( -/obj/effect/floor_decal/spline/fancy/wood, -/obj/machinery/sleeper/standard{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"bg" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 6 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "white" - }, -/area/map_template/ninja_dojo/dojo) -"bh" = ( -/obj/structure/door/wood, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bi" = ( -/obj/effect/floor_decal/carpet/blue, -/obj/effect/floor_decal/carpet/blue{ - dir = 8 - }, -/obj/effect/floor_decal/carpet/blue{ - dir = 10 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"bj" = ( -/obj/effect/floor_decal/carpet/blue, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"bk" = ( -/obj/effect/floor_decal/carpet/blue{ - dir = 4 - }, -/obj/effect/floor_decal/carpet/blue, -/obj/effect/floor_decal/carpet/blue{ - dir = 6 - }, -/obj/effect/landmark{ - name = "ninjastart" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "bcarpet" - }, -/area/map_template/ninja_dojo/dojo) -"bl" = ( -/obj/structure/table/rack, -/obj/item/storage/belt/medical, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bm" = ( -/obj/item/radio/intercom/syndicate{ - dir = 8; - pixel_x = 22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bn" = ( -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "snowplating" - }, -/area/map_template/ninja_dojo/dojo) -"bo" = ( -/obj/effect/floor_decal/snow, -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "snowplating" - }, -/area/map_template/ninja_dojo/dojo) -"bp" = ( -/obj/item/radio/intercom/syndicate{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bq" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/white_vest, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"br" = ( -/obj/structure/table/rack, -/obj/item/defibrillator/compact/combat/loaded, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bs" = ( -/obj/structure/table/rack, -/obj/item/sword/katana/toy{ - name = "practice katana" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bt" = ( -/obj/structure/flora/ausbushes/palebush, -/turf/unsimulated/floor{ - icon_state = "snow" - }, -/area/map_template/ninja_dojo/dojo) -"bu" = ( -/obj/structure/bookcase, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bv" = ( -/obj/structure/flora/pottedplant/flower, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bw" = ( -/obj/structure/table/woodentable, -/obj/machinery/chemical_dispenser/bar_soft/full, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bx" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/glasses, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"by" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/sinpockets, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bz" = ( -/obj/structure/table/woodentable, -/obj/machinery/microwave, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bA" = ( -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/obj/effect/floor_decal/carpet{ - dir = 9 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bB" = ( -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bC" = ( -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/obj/effect/floor_decal/carpet{ - dir = 1 - }, -/obj/effect/floor_decal/carpet{ - dir = 5 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bD" = ( -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"bE" = ( -/obj/effect/floor_decal/snow, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"bF" = ( -/obj/structure/table/woodentable, -/obj/item/chems/food/drinks/dry_ramen, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bG" = ( -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bH" = ( -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bI" = ( -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bJ" = ( -/obj/effect/floor_decal/snow, -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "ice" - }, -/area/map_template/ninja_dojo/dojo) -"bK" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Sleeping Chamber" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bL" = ( -/obj/structure/table/woodentable, -/obj/item/flashlight/lamp, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bM" = ( -/obj/effect/floor_decal/snow, -/obj/structure/aliumizer, -/turf/unsimulated/floor{ - icon = 'icons/turf/snow.dmi'; - icon_state = "ice" - }, -/area/map_template/ninja_dojo/dojo) -"bN" = ( -/obj/effect/landmark{ - name = "ninjastart" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bO" = ( -/obj/structure/bed/padded, -/obj/item/bedsheet/brown, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bP" = ( -/obj/effect/floor_decal/carpet, -/obj/effect/floor_decal/carpet{ - dir = 8 - }, -/obj/effect/floor_decal/carpet{ - dir = 10 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bQ" = ( -/obj/effect/floor_decal/carpet, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bR" = ( -/obj/effect/floor_decal/carpet{ - dir = 4 - }, -/obj/effect/floor_decal/carpet, -/obj/effect/floor_decal/carpet{ - dir = 6 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"bS" = ( -/obj/structure/table/woodentable, -/obj/item/chems/food/snacks/soylentgreen, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bT" = ( -/obj/structure/bookcase{ - name = "bookcase (Tactics)" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bU" = ( -/obj/structure/flora/pottedplant/shoot, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bV" = ( -/obj/structure/bookcase{ - name = "bookcase (Religious)" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bW" = ( -/obj/structure/table/woodentable, -/obj/item/toy/figure/wizard, -/obj/item/radio/intercom/syndicate{ - dir = 1; - pixel_y = -22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bX" = ( -/obj/structure/table/woodentable, -/obj/item/clothing/shoes/sandal, -/obj/item/clothing/mask/balaclava, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bY" = ( -/obj/structure/undies_wardrobe, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"bZ" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Bath" - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"ca" = ( -/obj/structure/table/woodentable, -/obj/item/flame/candle, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"cb" = ( -/obj/effect/floor_decal/spline/fancy/wood/corner, -/obj/item/radio/intercom/syndicate{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"cc" = ( -/obj/effect/floor_decal/spline/fancy/wood, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"cd" = ( -/obj/effect/floor_decal/spline/fancy/wood, -/obj/structure/hygiene/toilet{ - pixel_y = 8 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"ce" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Shrine" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"cf" = ( -/obj/effect/landmark{ - name = "ninjastart" - }, -/obj/effect/floor_decal/carpet{ - dir = 10 - }, -/obj/effect/floor_decal/carpet{ - dir = 6 - }, -/obj/effect/floor_decal/carpet{ - dir = 9 - }, -/obj/effect/floor_decal/carpet{ - dir = 5 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "carpet" - }, -/area/map_template/ninja_dojo/dojo) -"cg" = ( -/obj/structure/table/rack{ - desc = "A simple wooden altar covered in cloth."; - icon = 'icons/obj/cult.dmi'; - icon_state = "churchaltar"; - name = "wooden altar" - }, -/obj/item/sword/katana, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/ninja_dojo/dojo) -"ch" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 4 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"ci" = ( -/turf/unsimulated/floor{ - dir = 2; - icon = 'icons/misc/beach.dmi'; - icon_state = "seashallow"; - name = "water" - }, -/area/map_template/ninja_dojo/dojo) -"cj" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 4 - }, -/obj/structure/hygiene/sink{ - icon_state = "sink"; - dir = 8; - pixel_x = -12; - pixel_y = 2 - }, -/obj/item/storage/mirror{ - pixel_x = -32 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/ninja_dojo/dojo) -"ck" = ( -/obj/effect/paint/black, -/turf/simulated/wall/r_titanium, -/area/map_template/ninja_dojo/start) -"cl" = ( -/obj/machinery/door/morgue{ - dir = 2; - name = "Equipment" - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cm" = ( -/obj/machinery/fabricator/hacked, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cn" = ( -/obj/structure/table/rack, -/obj/item/stack/material/steel{ - amount = 50 - }, -/obj/item/stack/material/steel{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"co" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/secure/briefcase/money, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cp" = ( -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cq" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cr" = ( -/obj/structure/table/rack, -/obj/item/storage/belt/utility/full, -/obj/item/multitool, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cs" = ( -/obj/structure/table/steel_reinforced, -/obj/item/multitool/hacktool, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"ct" = ( -/obj/structure/table/steel_reinforced, -/obj/item/radio/uplink, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cu" = ( -/obj/machinery/door/airlock/centcom{ - name = "Equipment" - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cv" = ( -/obj/machinery/acting/changer, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cw" = ( -/obj/structure/table/rack, -/obj/item/stack/nanopaste, -/obj/item/stack/nanopaste, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cx" = ( -/obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion"; - dir = 1 - }, -/obj/effect/paint/black, -/turf/simulated/wall/r_titanium, -/area/map_template/ninja_dojo/start) -"cy" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/cell_charger, -/obj/effect/floor_decal/industrial/outline/grey, -/obj/item/clothing/accessory/storage/bandolier, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cz" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/recharger, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cA" = ( -/obj/structure/table/rack, -/obj/item/star/ninja, -/obj/item/star/ninja, -/obj/item/star/ninja, -/obj/item/star/ninja, -/obj/item/star/ninja, -/obj/item/star/ninja, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cB" = ( -/obj/structure/table/rack, -/obj/item/star, -/obj/item/star, -/obj/item/star, -/obj/item/star, -/obj/item/star, -/obj/item/star, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cC" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/black_vest, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cD" = ( -/obj/structure/table/rack, -/obj/item/storage/belt/holster/security/tactical, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cE" = ( -/obj/structure/table/steel_reinforced, -/obj/item/plastique, -/obj/item/plastique, -/obj/item/radio/intercom/syndicate{ - dir = 1; - pixel_y = -22 - }, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cF" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/box/anti_photons, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/dojo) -"cG" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 - }, -/obj/machinery/light{ - dir = 1 - }, -/obj/structure/table/rack, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cH" = ( -/obj/machinery/computer/teleporter{ - icon_state = "computer"; - dir = 2 - }, -/turf/simulated/floor/plating, -/area/map_template/ninja_dojo/start) -"cI" = ( -/obj/machinery/teleport/station, -/turf/simulated/floor/plating, -/area/map_template/ninja_dojo/start) -"cJ" = ( -/obj/machinery/teleport/hub, -/obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, -/area/map_template/ninja_dojo/start) -"cK" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/machinery/atmospherics/portables_connector, -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cL" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cM" = ( -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cN" = ( -/obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cO" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cP" = ( -/obj/effect/floor_decal/industrial/warning/corner{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cQ" = ( -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - frequency = 1331; - id_tag = "ninja_shuttle"; - pixel_x = -8; - pixel_y = 25; - req_access = list("ACCESS_SYNDICATE") - }, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cR" = ( -/obj/machinery/door/airlock/external/shuttle{ - density = 1; - id_tag = "ninja_shuttle_outer"; - name = "Ship External Access" - }, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "ninjadoor"; - name = "Blast Door"; - opacity = 0 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cS" = ( -/obj/machinery/sleeper/standard{ - dir = 4 - }, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cT" = ( -/obj/effect/shuttle_landmark/ninja/start, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cU" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" - }, -/obj/machinery/button/access/shuttle/interior{ - id_tag = "ninja_shuttle"; - name = "interior access button"; - pixel_x = 25; - pixel_y = 25; - req_access = list("ACCESS_SYNDICATE") - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cV" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/door/airlock/external/shuttle{ - id_tag = "ninja_shuttle_inner"; - name = "Ship External Access" - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cW" = ( -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ninja_shuttle_sensor"; - pixel_x = 8; - pixel_y = -25 - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 8; - id_tag = "ninja_shuttle_pump" - }, -/obj/machinery/button/blast_door{ - id_tag = "ninjadoor"; - name = "remote shutter control"; - pixel_x = 25 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cX" = ( -/obj/structure/closet, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cY" = ( -/obj/structure/table/rack, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"cZ" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/item/radio/intercom/syndicate{ - dir = 4; - pixel_x = -22 - }, -/obj/machinery/cell_charger, -/obj/item/screwdriver, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"da" = ( -/obj/structure/bed/chair/shuttle, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"db" = ( -/obj/machinery/button/blast_door{ - id_tag = "ninjawindow"; - name = "remote shutter control"; - pixel_x = 36; - pixel_y = -24 - }, -/obj/machinery/button/windowtint{ - id_tag = "ninja_ship"; - pixel_x = -24; - pixel_y = -25 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"dc" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/recharger, -/obj/item/wrench, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 4 - }, -/obj/effect/floor_decal/industrial/outline/grey, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"dd" = ( -/obj/effect/floor_decal/industrial/outline/grey, -/obj/machinery/computer/station_alert/all{ - icon_state = "computer"; - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"de" = ( -/obj/effect/floor_decal/industrial/outline/grey, -/obj/machinery/computer/shuttle_control/multi/ninja{ - icon_state = "computer"; - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"df" = ( -/obj/effect/floor_decal/industrial/outline/grey, -/obj/machinery/computer/modular/preset/security{ - icon_state = "console"; - dir = 1 - }, -/turf/unsimulated/floor{ - dir = 2; - icon_state = "dark" - }, -/area/map_template/ninja_dojo/start) -"dg" = ( -/obj/machinery/door/blast/regular{ - density = 1; - icon_state = "pdoor1"; - id_tag = "ninjawindow"; - name = "Blast Shutter"; - opacity = 1 - }, -/obj/effect/wallframe_spawn/reinforced/polarized{ - id = "ninja_ship" - }, -/obj/effect/paint/black, -/turf/simulated/floor/plating, -/area/map_template/ninja_dojo/start) -"ss" = ( -/turf/unsimulated/wall, -/area/map_template/ninja_dojo/dojo) -"zr" = ( -/obj/effect/floor_decal/snow, -/turf/unsimulated/wall, -/area/map_template/ninja_dojo/dojo) - -(1,1,1) = {" -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -zr -zr -zr -"} -(2,1,1) = {" -ss -ac -ac -ad -ad -ac -ac -af -ac -ac -ac -ac -ag -ac -ac -ac -ac -ad -ag -bn -bo -ad -ag -ac -ad -bn -bn -bn -bo -bo -bn -bn -bn -bn -bo -bn -bn -bo -bo -bo -zr -"} -(3,1,1) = {" -ss -ad -af -ad -ad -ad -ai -ad -ac -ad -ad -ac -ad -ad -ad -ac -ae -ad -ad -bo -bn -ad -ad -ad -ad -bn -bo -bo -bn -bn -bn -bn -ck -ck -ck -ck -bn -bn -bo -bn -zr -"} -(4,1,1) = {" -ss -ad -ad -ad -ac -ac -ad -ad -ac -ac -aH -ac -ad -ad -ad -ad -ad -ad -ad -bn -bn -ac -ad -ad -ac -bn -bn -bn -bn -bn -bn -ck -ck -cL -cS -ck -ck -bn -bn -bn -ss -"} -(5,1,1) = {" -ss -ad -ad -ad -ac -ad -ad -ac -ad -ad -ac -ac -ad -ad -ad -ad -ad -ad -ad -bn -bo -ad -ad -ae -ad -bo -bn -bn -bn -bn -bn -cx -ck -cM -cM -ck -ck -ck -bn -bn -zr -"} -(6,1,1) = {" -ss -ac -ac -ac -ae -ad -ad -ad -ac -ac -ac -ad -ad -ad -ad -ae -ac -ac -ag -bo -bn -ad -ag -ad -ad -bo -bn -ck -ck -ck -ck -ck -cG -cN -cM -cX -cZ -ck -ck -bn -zr -"} -(7,1,1) = {" -ss -ac -ac -ac -ac -ad -aj -aj -aj -aj -aj -aj -aj -aj -ad -ad -ad -ad -ad -bn -bn -ad -ad -ad -ad -bo -bn -bn -bo -bn -bn -ck -cH -cO -cM -cM -cM -dd -dg -bn -zr -"} -(8,1,1) = {" -ss -ac -ac -ac -ac -ad -aj -ak -ar -aB -aI -aR -ao -aj -aj -aj -aj -aj -aA -bh -bh -aA -aj -aj -ad -bn -bn -bn -bo -bo -bn -ck -cI -cO -cT -cM -da -de -dg -bn -ss -"} -(9,1,1) = {" -ss -ac -ag -ac -ad -ad -aj -al -ao -ao -ao -aS -ao -bf -bl -bq -aj -bu -aG -aG -aG -aG -bT -aj -ad -bn -bn -bn -bn -bn -bn -ck -cJ -cO -cM -cM -db -df -dg -bn -ss -"} -(10,1,1) = {" -ss -ac -ac -ad -ad -ad -aj -am -ao -ao -ao -ao -ao -aL -aG -aG -aA -aV -bA -bG -bG -bP -bU -aA -ad -bn -bn -ck -ck -ck -ck -ck -cK -cP -cU -cY -dc -ck -ck -bn -ss -"} -(11,1,1) = {" -ss -ac -ac -ad -ad -ad -aj -an -at -aC -aJ -ao -ao -aL -aG -aG -ba -aG -bB -bH -bH -bQ -aG -bh -bn -bn -bn -bn -bn -bn -bn -cx -ck -ck -cV -ck -ck -ck -bn -bn -ss -"} -(12,1,1) = {" -ss -ac -ac -ad -ad -ad -aj -ao -au -ao -aK -aT -aT -bg -aG -aG -ba -aG -bB -bH -bH -bQ -aG -bh -bn -bn -bn -bn -bn -bn -bn -ck -ck -cQ -cW -ck -ck -bn -bn -bn -ss -"} -(13,1,1) = {" -ss -ac -ad -ad -ad -ad -aj -ap -av -ao -aL -aG -aG -aG -aG -aG -aA -bv -bC -bI -bI -bR -aU -aA -ad -bn -bn -bo -bo -bn -bn -bn -ck -cR -ck -ck -bn -bn -bn -bn -zr -"} -(14,1,1) = {" -ss -ac -ad -ac -ae -ad -aj -aq -aw -aD -aM -aU -aG -aG -bm -br -aj -bu -aG -aG -aG -aG -bV -aj -ad -bn -bn -bn -bn -bn -bn -bn -bn -bn -bn -bn -bo -bo -bn -bn -ss -"} -(15,1,1) = {" -ss -ac -ad -ac -ac -ad -aj -aj -aj -aj -aj -aA -ba -aj -aj -aj -aj -aj -aA -bh -bh -aA -aj -aj -ad -bo -bn -bn -bn -bo -bn -bn -bn -bn -bo -bo -bo -bn -bn -bn -zr -"} -(16,1,1) = {" -ss -ad -ad -ac -ac -ad -ad -aj -ax -aE -aA -aV -aG -aj -ad -ad -ad -ad -ad -bn -bn -ad -ad -ad -ad -ad -ad -ad -ad -bn -bn -ad -ad -ad -ac -ad -ad -ad -ad -ad -ss -"} -(17,1,1) = {" -ss -ad -ac -ad -ac -ad -ad -aj -ay -aE -aN -aG -aG -aA -ae -bo -bn -bn -bn -bn -bo -bo -bn -bn -bn -ad -ad -ae -ad -bn -bn -ad -ac -ac -ad -ad -ad -ad -ac -ah -ss -"} -(18,1,1) = {" -ss -ad -ac -ah -ac -ac -ac -aj -az -aF -aA -aG -aG -aA -ad -bn -ag -bn -ad -ad -ad -ad -bn -ah -bn -ac -ad -ad -ad -bn -bn -ad -ad -ad -ad -ag -ad -ad -ad -ad -ss -"} -(19,1,1) = {" -ss -ad -ad -ad -ac -ac -ad -aj -aj -aj -aj -aG -bb -aj -ad -bo -bn -bn -ad -ad -ad -ad -bn -bn -bn -ac -ad -ad -ac -bn -bo -ad -ae -ad -ad -ac -ac -ad -ad -ae -ss -"} -(20,1,1) = {" -ss -ad -ad -ac -ac -ad -ad -ad -ac -ad -aA -aG -aG -aj -ad -bn -ad -ad -bD -bE -bE -bE -ad -ad -bn -ad -ad -ad -ac -bn -bn -ad -ad -ac -ad -ad -ad -ad -ac -ad -ss -"} -(21,1,1) = {" -ss -ad -ad -ac -ad -ac -ad -ad -af -ad -aA -aG -aG -bh -bn -bn -ae -ad -bE -bJ -bM -bD -ad -ad -bo -bn -bo -bn -bn -bn -bn -ad -ad -ac -ad -ac -ad -ad -ad -ac -ss -"} -(22,1,1) = {" -ss -ac -ad -ac -ad -ai -ad -ad -ac -ad -aA -aG -aG -bh -bo -bn -ac -ac -bD -bJ -bJ -bE -ad -ad -bo -bn -bn -bo -bn -bn -bn -ad -ad -ad -ad -ac -ad -ad -ad -ad -ss -"} -(23,1,1) = {" -ss -ac -ac -ac -ad -ad -ad -ad -ac -ad -aA -aG -aG -aj -ad -bn -ac -ad -bE -bE -bD -bE -ac -ad -bn -ac -ad -ad -ad -bn -bn -ad -ad -ad -ad -ad -ad -ad -ag -ad -ss -"} -(24,1,1) = {" -ss -ad -ad -ad -ad -ad -ad -ac -ad -ad -aj -aG -aG -aj -ad -bn -bn -bn -ad -ac -ad -ad -bn -bn -bn -ac -ae -ad -ad -bn -bn -ad -ad -ad -ad -ad -ad -ad -ad -ad -ss -"} -(25,1,1) = {" -ss -ac -ad -ad -ad -ad -ad -ac -ad -ad -aj -aG -aG -aA -ad -bo -bt -bn -ad -ad -ad -ac -bn -ag -bn -ac -ad -aj -aj -cu -cu -aj -aj -ad -ad -ae -ad -ad -ad -ad -ss -"} -(26,1,1) = {" -ss -ad -ad -ad -ad -ac -ac -ac -ad -ad -aj -aG -aG -aA -ad -bn -bn -bn -bo -bo -bn -bn -bn -bo -bn -ad -ad -aj -cm -cp -cp -cy -aj -ad -ad -ad -ac -ac -ac -ad -ss -"} -(27,1,1) = {" -ss -ad -ac -ac -ad -ad -ac -ac -ad -ad -aj -aV -aG -aj -ad -ad -ad -ad -ad -bn -bn -ad -ad -ae -ad -ad -ad -aj -cn -cp -cp -cz -aj -ad -ad -ad -ac -ad -ac -ad -ss -"} -(28,1,1) = {" -ss -ad -ad -ac -ac -ad -ae -ac -aj -aj -aj -aA -bc -aj -aj -aj -aA -aA -aj -bh -bh -aj -aA -aA -aj -aj -aj -aj -co -cp -cp -cA -aj -ad -ad -ad -ad -ad -ac -ad -ss -"} -(29,1,1) = {" -ss -ad -ae -ac -ad -ad -ae -ac -aj -aG -aG -aG -aG -aG -bp -bc -aG -aG -aG -aG -aG -aG -aG -aG -aG -bp -aG -cl -cp -cp -cp -cB -aj -ad -ad -ad -ad -ad -af -ad -ss -"} -(30,1,1) = {" -ss -ac -ac -ac -ac -ad -ac -ad -aA -aG -aG -aG -aG -aG -aG -aA -aV -aG -aG -aG -aG -aG -aG -aG -aG -aG -aV -aj -cq -cp -cp -cC -aj -ad -ad -ad -ad -ad -ac -ad -ss -"} -(31,1,1) = {" -ss -ac -ac -ac -ac -ac -ac -ad -aA -aG -aO -aW -aW -bi -aG -aj -aj -aj -aA -bK -bK -aA -aj -aj -aA -ce -aA -aj -cr -cp -cp -cD -aj -ad -ad -ac -ad -ad -ad -ad -ss -"} -(32,1,1) = {" -ss -ad -ad -ac -ad -ac -ac -ad -aA -aG -aP -aX -bd -bj -aG -bs -aj -bw -bF -aG -aG -bS -bW -aj -aG -cf -aG -aj -cs -cp -cp -cE -aj -ad -ad -ad -ad -aH -ac -ad -ss -"} -(33,1,1) = {" -ss -ad -ad -ac -ag -ad -ac -ad -aA -aG -aP -aY -be -bj -aG -bs -aj -bx -aG -aG -aG -aG -bX -aj -ca -cg -ca -aj -ct -cp -cp -cF -aj -ad -ad -ad -ad -ac -ad -ad -ss -"} -(34,1,1) = {" -ss -ad -ad -ac -ad -ad -ac -ad -aA -aG -aQ -aZ -aZ -bk -aG -bs -aj -by -aG -aG -bN -aG -bY -aj -aj -aj -aj -aj -aj -cv -cw -aj -aj -ad -ad -ad -ad -ad -ad -ad -ss -"} -(35,1,1) = {" -ss -ad -ad -ad -ac -ad -ac -ad -aj -aG -aG -aG -aG -aG -aG -bs -aj -bz -aG -bL -bO -aG -aG -bZ -cb -ch -cj -aj -aj -aj -aj -aj -ad -ad -ad -ad -ad -ad -ad -ad -ss -"} -(36,1,1) = {" -ss -ad -ad -ad -ad -ad -ad -ad -aj -aj -aA -aA -aA -aA -aA -aj -aj -aj -aA -aA -aA -aA -aj -aj -cc -ci -ci -aj -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ss -"} -(37,1,1) = {" -ss -ae -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aj -cd -ci -ci -aj -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ac -ad -ss -"} -(38,1,1) = {" -ss -ad -ad -ad -ad -ac -ad -ad -ad -ad -ad -ad -ae -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aj -aj -aj -aj -aj -ad -ae -ac -ac -ad -ad -ad -ad -ad -ad -ac -ad -ss -"} -(39,1,1) = {" -ss -ad -ag -ad -ad -ac -ad -ad -ad -ad -ad -ad -ac -ac -ac -ac -ac -ac -ac -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ac -ac -ad -ad -ad -ac -ad -ad -ad -ac -ad -ss -"} -(40,1,1) = {" -ss -ad -ad -ad -ad -ac -ad -ad -ad -ag -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ac -ac -ac -ac -ad -ad -ad -ac -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ss -"} -(41,1,1) = {" -ss -ad -ad -ad -ad -ad -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ag -ad -ad -ad -ad -ad -ad -ad -ac -aH -ac -ad -ad -ad -ad -ad -ad -ad -ad -ac -ad -ag -ad -ad -ss -"} -(42,1,1) = {" -ss -ad -ad -ad -ad -ad -ad -ac -ac -ac -ad -ad -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ac -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ss -"} -(43,1,1) = {" -ss -ad -ad -ad -ad -ad -ad -ad -ad -ad -ac -ac -ac -ad -ae -ad -ad -ad -ad -ad -ad -ad -ae -ad -ac -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ss -"} -(44,1,1) = {" -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -ss -"} diff --git a/maps/antag_spawn/wizard/wizard.dm b/maps/antag_spawn/wizard/wizard.dm deleted file mode 100644 index 136f4b0d9d7d..000000000000 --- a/maps/antag_spawn/wizard/wizard.dm +++ /dev/null @@ -1,11 +0,0 @@ -/datum/map_template/ruin/antag_spawn/wizard - name = "Wizard Base" - id = MODE_WIZARD + "_spawn" - suffixes = list("wizard/wizard_base.dmm") - -/area/map_template/wizard_station - name = "\improper Wizard's Den" - icon_state = "yellow" - requires_power = 0 - dynamic_lighting = 0 - req_access = list(access_syndicate) diff --git a/maps/antag_spawn/wizard/wizard_base.dmm b/maps/antag_spawn/wizard/wizard_base.dmm deleted file mode 100644 index 1654c7944fbc..000000000000 --- a/maps/antag_spawn/wizard/wizard_base.dmm +++ /dev/null @@ -1,1945 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/space/infinity, -/area/space) -"ab" = ( -/turf/unsimulated/wall, -/area/map_template/wizard_station) -"ac" = ( -/turf/unsimulated/wall/fakeglass{ - icon_state = "fakewindows"; - dir = 8 - }, -/area/map_template/wizard_station) -"ad" = ( -/turf/unsimulated/wall/fakeglass{ - dir = 8; - icon_state = "fakewindows2" - }, -/area/map_template/wizard_station) -"ae" = ( -/turf/unsimulated/wall/fakeglass{ - dir = 4 - }, -/area/map_template/wizard_station) -"af" = ( -/obj/structure/table/woodentable, -/obj/item/flashlight/lamp/green{ - on = 0; - pixel_x = -3; - pixel_y = 8 - }, -/obj/item/chems/food/drinks/flask/barflask, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ag" = ( -/obj/structure/bed/padded, -/obj/item/bedsheet/rd, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ah" = ( -/obj/structure/table/woodentable, -/obj/item/storage/backpack/satchel/grey/withwallet, -/obj/item/clothing/glasses/monocle, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ai" = ( -/obj/structure/table/woodentable, -/obj/effect/landmark{ - name = "Teleport-Scroll" - }, -/obj/item/toy/figure/ninja, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"aj" = ( -/obj/effect/landmark/start{ - name = "wizard" - }, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ak" = ( -/obj/structure/aliumizer, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"al" = ( -/obj/structure/table/woodentable, -/obj/item/storage/backpack/cultpack, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"am" = ( -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"an" = ( -/obj/item/radio/intercom/syndicate{ - dir = 8; - pixel_x = 22 - }, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ao" = ( -/obj/structure/table/woodentable, -/obj/item/storage/backpack/satchel/grey/withwallet, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ap" = ( -/obj/structure/undies_wardrobe, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"aq" = ( -/obj/structure/door/wood, -/turf/simulated/floor/carpet, -/area/map_template/wizard_station) -"ar" = ( -/obj/structure/bookcase{ - name = "Forbidden Knowledge" - }, -/obj/effect/decal/cleanable/cobweb, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"as" = ( -/obj/structure/table/woodentable, -/obj/item/dice, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"at" = ( -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"au" = ( -/obj/structure/table/woodentable, -/obj/item/dice/d20, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"av" = ( -/obj/structure/bookcase{ - name = "bookcase (Tactics)" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aw" = ( -/obj/structure/bookcase{ - name = "Forbidden Knowledge" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"ax" = ( -/mob/living/carbon/human/monkey{ - name = "Murphey" - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"ay" = ( -/turf/unsimulated/wall/fakeglass{ - dir = 1; - icon_state = "fakewindows" - }, -/area/map_template/wizard_station) -"az" = ( -/turf/unsimulated/floor{ - dir = 2; - icon = 'icons/misc/beach.dmi'; - icon_state = "seashallow"; - name = "water" - }, -/area/map_template/wizard_station) -"aA" = ( -/obj/item/bikehorn/rubberducky, -/turf/unsimulated/floor{ - dir = 2; - icon = 'icons/misc/beach.dmi'; - icon_state = "seashallow"; - name = "water" - }, -/area/map_template/wizard_station) -"aB" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 8 - }, -/obj/machinery/acting/changer/mirror{ - pixel_y = 32 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aC" = ( -/obj/structure/hygiene/toilet{ - pixel_y = 8 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aD" = ( -/obj/structure/table/woodentable, -/obj/item/radio/intercom/syndicate{ - dir = 4; - pixel_x = -22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aE" = ( -/obj/structure/bed/chair/wood/wings{ - icon_state = "wooden_chair_wings"; - dir = 4 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aF" = ( -/obj/structure/table/woodentable, -/obj/item/chems/food/snacks/chawanmushi, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aG" = ( -/obj/structure/bed/chair/wood/wings{ - icon_state = "wooden_chair_wings"; - dir = 8 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aH" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/cups, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aI" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/red, -/obj/item/clothing/shoes/sandal, -/obj/item/clothing/head/wizard/red, -/obj/item/staff, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"aJ" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/marisa, -/obj/item/clothing/shoes/sandal/marisa, -/obj/item/clothing/head/wizard/marisa, -/obj/item/staff/broom, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"aK" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/magusblue, -/obj/item/clothing/head/wizard/magus, -/obj/item/staff, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"aL" = ( -/obj/structure/closet, -/obj/item/chems/food/drinks/bottle/pwine, -/obj/item/chems/food/drinks/bottle/agedwhiskey, -/obj/item/chems/food/drinks/bottle/cognac, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"aM" = ( -/turf/unsimulated/wall/fakeglass{ - icon_state = "fakewindows2"; - dir = 1 - }, -/area/map_template/wizard_station) -"aN" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 8 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aO" = ( -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aP" = ( -/obj/structure/door/iron, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aQ" = ( -/obj/structure/table/woodentable, -/obj/item/megaphone, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aR" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/donut, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aS" = ( -/obj/structure/table/woodentable, -/obj/item/cash/c1, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"aT" = ( -/obj/structure/door/wood, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"aU" = ( -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"aV" = ( -/turf/unsimulated/wall/fakeglass, -/area/map_template/wizard_station) -"aW" = ( -/obj/item/soap, -/turf/unsimulated/floor{ - dir = 2; - icon = 'icons/misc/beach.dmi'; - icon_state = "seashallow"; - name = "water" - }, -/area/map_template/wizard_station) -"aX" = ( -/obj/effect/floor_decal/spline/fancy/wood{ - dir = 8 - }, -/obj/item/radio/intercom/syndicate{ - dir = 1; - pixel_y = -22 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aY" = ( -/obj/structure/hygiene/sink{ - dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 - }, -/obj/item/storage/mirror{ - pixel_x = 32 - }, -/turf/unsimulated/floor{ - icon_state = "freezerfloor"; - dir = 2 - }, -/area/map_template/wizard_station) -"aZ" = ( -/obj/machinery/vending/magivend, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"ba" = ( -/obj/structure/table/woodentable, -/obj/item/chems/food/snacks/milosoup, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bb" = ( -/obj/structure/table/woodentable, -/obj/machinery/chemical_dispenser/bar_soft/full, -/obj/item/radio/intercom/syndicate{ - dir = 8; - pixel_x = 22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bc" = ( -/obj/structure/closet, -/obj/item/clothing/under/psysuit, -/obj/item/clothing/suit/wizrobe/psypurple, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"bd" = ( -/obj/structure/closet, -/obj/item/clothing/shoes/sandal/marisa{ - desc = "A set of fancy shoes that are as functional as they are comfortable."; - name = "Gentlemans Shoes" - }, -/obj/item/clothing/under/gentlesuit, -/obj/item/clothing/suit/wizrobe/gentlecoat, -/obj/item/clothing/head/wizard/cap, -/obj/item/staff/gentcane, -/obj/item/radio/intercom/syndicate{ - dir = 1; - pixel_y = -22 - }, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"be" = ( -/obj/structure/closet, -/obj/item/clothing/suit/wizrobe/magusred, -/obj/item/clothing/head/wizard/magus, -/obj/item/staff, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"bf" = ( -/obj/structure/closet, -/obj/item/storage/briefcase, -/turf/unsimulated/floor{ - icon_state = "lino" - }, -/area/map_template/wizard_station) -"bg" = ( -/obj/structure/bookcase, -/obj/item/book/manual/nuclear, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bh" = ( -/obj/structure/bookcase, -/obj/item/book/manual/robotics_cyborgs, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bi" = ( -/obj/structure/bookcase, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bj" = ( -/obj/structure/table/woodentable, -/obj/item/storage/bag/cash, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bk" = ( -/obj/structure/table/woodentable, -/obj/item/storage/candle_box, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bl" = ( -/obj/structure/door/silver, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bm" = ( -/obj/item/radio/intercom/syndicate{ - dir = 1; - pixel_y = -22 - }, -/turf/unsimulated/floor{ - dir = 8; - icon_state = "wood" - }, -/area/map_template/wizard_station) -"bn" = ( -/obj/structure/closet/coffin, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bo" = ( -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bp" = ( -/obj/item/radio/intercom/syndicate{ - pixel_y = 22 - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bq" = ( -/obj/structure/cult/pylon, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"br" = ( -/obj/structure/kitchenspike, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bs" = ( -/obj/item/remains/human, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "lava" - }, -/area/map_template/wizard_station) -"bt" = ( -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "lava" - }, -/area/map_template/wizard_station) -"bu" = ( -/turf/unsimulated/floor{ - icon_state = "grass0"; - name = "grass" - }, -/area/map_template/wizard_station) -"bv" = ( -/obj/structure/flora/ausbushes/fullgrass, -/turf/unsimulated/floor{ - icon_state = "grass0"; - name = "grass" - }, -/area/map_template/wizard_station) -"bw" = ( -/mob/living/simple_animal/hostile/creature{ - name = "Experiment 35b" - }, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "lava" - }, -/area/map_template/wizard_station) -"bx" = ( -/obj/structure/cult/talisman, -/obj/item/knife/ritual, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"by" = ( -/obj/effect/gateway/active/cult, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bz" = ( -/obj/structure/table/marble, -/obj/item/flashlight/slime, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bA" = ( -/mob/living/simple_animal/hostile/retaliate/goat{ - name = "Experiment 97d" - }, -/turf/unsimulated/floor{ - icon_state = "grass0"; - name = "grass" - }, -/area/map_template/wizard_station) -"bB" = ( -/obj/structure/flora/ausbushes/grassybush, -/turf/unsimulated/floor{ - icon_state = "grass0"; - name = "grass" - }, -/area/map_template/wizard_station) -"bC" = ( -/obj/structure/flora/pottedplant/unusual, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bD" = ( -/obj/structure/table/woodentable, -/obj/item/cat_hide, -/turf/unsimulated/floor{ - name = "plating"; - icon_state = "cult" - }, -/area/map_template/wizard_station) -"bE" = ( -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/wizard_station) -"bF" = ( -/obj/effect/overlay/palmtree_r, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/wizard_station) -"bG" = ( -/mob/living/simple_animal/crab{ - name = "Experiment 68a" - }, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/wizard_station) -"bH" = ( -/obj/effect/overlay/coconut, -/turf/unsimulated/floor{ - icon_state = "asteroid" - }, -/area/map_template/wizard_station) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ay -aM -aV -ab -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -"} -(9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -az -az -aW -ab -aa -aa -aa -aa -aa -aa -aa -ab -bs -bt -bt -ab -aa -aa -aa -aa -aa -aa -aa -"} -(10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aA -az -az -ab -aa -aa -aa -aa -aa -aa -aa -ab -bt -bt -bt -ab -aa -aa -aa -aa -aa -aa -aa -"} -(11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aB -aN -aX -ab -aa -aa -aa -aa -aa -aa -aa -ab -bt -bw -bt -ab -aa -aa -aa -aa -aa -aa -aa -"} -(12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aC -aO -aY -ab -aa -aa -aa -aa -aa -aa -aa -ab -bt -bt -bs -ab -aa -aa -aa -aa -aa -aa -aa -"} -(13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aP -ab -ab -ab -aa -aa -aa -aa -aa -ab -ab -ay -aM -aV -ab -ab -aa -aa -aa -aa -aa -aa -"} -(14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -aw -aD -at -aZ -bg -ab -ab -aa -aa -aa -ab -ab -bq -bo -bx -bo -bq -ab -ab -aa -aa -aa -aa -aa -"} -(15,1,1) = {" -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -ar -at -at -at -at -at -bi -ab -ay -aM -aV -ab -bn -bo -bo -bo -bo -bo -bC -ab -ab -ab -ab -ab -ab -"} -(16,1,1) = {" -aa -aa -aa -aa -aa -aa -ac -af -ai -al -ao -ab -as -at -aE -aQ -aE -at -bj -ab -at -at -bm -ab -bo -bo -ac -ab -ac -bo -bo -ac -bE -bE -bE -bH -ab -"} -(17,1,1) = {" -aa -aa -aa -aa -aa -aa -ad -ag -aj -am -am -aq -at -at -aF -aR -ba -at -at -bl -at -at -at -bl -bo -bo -ad -by -ad -bo -bD -ad -bE -bE -bG -bE -ab -"} -(18,1,1) = {" -aa -aa -aa -aa -aa -aa -ae -ah -ak -an -ap -ab -au -ax -aG -aS -aG -at -bk -ab -at -at -at -ab -bp -bo -ae -ab -ae -bo -bo -ae -bE -bF -bE -bE -ab -"} -(19,1,1) = {" -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -ab -av -at -at -at -at -at -bi -ab -ay -aM -aV -ab -bn -bo -bo -bo -bo -bo -bC -ab -ab -ab -ab -ab -ab -"} -(20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -av -aH -at -bb -bh -ab -ab -aa -aa -aa -ab -ab -br -bo -bz -bo -br -ab -ab -aa -aa -aa -aa -aa -"} -(21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -aT -ab -ab -ab -aa -aa -aa -aa -aa -ab -ab -ay -aM -aV -ab -ab -aa -aa -aa -aa -aa -aa -"} -(22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aI -aU -bc -ab -aa -aa -aa -aa -aa -aa -aa -ab -bu -bu -bB -ab -aa -aa -aa -aa -aa -aa -aa -"} -(23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aJ -aU -bd -ab -aa -aa -aa -aa -aa -aa -aa -ab -bu -bu -bu -ab -aa -aa -aa -aa -aa -aa -aa -"} -(24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aK -aU -be -ab -aa -aa -aa -aa -aa -aa -aa -ab -bu -bA -bu -ab -aa -aa -aa -aa -aa -aa -aa -"} -(25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aL -aU -bf -ab -aa -aa -aa -aa -aa -aa -aa -ab -bv -bu -bu -ab -aa -aa -aa -aa -aa -aa -aa -"} -(26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ay -aM -aV -ab -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -"} -(27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} diff --git a/maps/away/README.md b/maps/away/README.md index 3c5fd70db367..9d675461078d 100644 --- a/maps/away/README.md +++ b/maps/away/README.md @@ -24,7 +24,7 @@ BUT HEED MY RUMINATIONS Away maps are expected to work whether you're on a specific main map. That means your map mustn't use areas, turfs, objects, mobs or datums that are specific to any main map. You can use content packages to define content that is only included for particular maps, as the away sites are tested with all packages enabled. -e.g. you can use `/area/space`, or `/turf/simulated/wall`, because neither are specific to a given map. They live out in the main codebase, are always compiled in, and are available to all maps. But you can't use `/obj/random_multi/single_item/punitelly`, because Punitelli only exists when `punitelli.dm` is compiled. +e.g. you can use `/area/space`, or `/turf/wall`, because neither are specific to a given map. They live out in the main codebase, are always compiled in, and are available to all maps. But you can't use `/obj/random_multi/single_item/punitelly`, because Punitelli only exists when `punitelli.dm` is compiled. To make life easier, you can uncheck your main map definition then recompile, to make sure these types aren't available while you're mapping. @@ -54,13 +54,13 @@ The game will read this to learn about your new shiny away sites, including what ### Include your .dm file in any main map file, and away sites testing -That's `maps/away_sites_testing/away_sites_testing.dm` plus your main map definition. It goes in the testing one to make sure Travis runs it through unit testing, and it goes in the primary map to make it available during real play. +That's `maps/away_sites_testing/away_sites_testing.dm` plus your main map definition. It goes in the testing one to make sure it is checked by unit testing, and it goes in the primary map to make it available during real play. ### Don't include it, or the .dmms, in the .dme That means don't have any of your away map stuff checked in Dream Maker. It'll get included, as if by magic, via the work you did in the previous step! -That's it! You're probably done! Unless Travis explodes at you. +That's it! You're probably done! Unless the unit tests explode on you. ### Some of the stuff I put in my map isn't behaving properly! diff --git a/maps/away/away_sites.dm b/maps/away/away_sites.dm deleted file mode 100644 index 27dd543aaa96..000000000000 --- a/maps/away/away_sites.dm +++ /dev/null @@ -1,18 +0,0 @@ -// Hey! Listen! Update \config\away_site_blacklist.txt with your new ruins! - -/datum/map_template/ruin/away_site - var/spawn_weight = 1 - var/list/generate_mining_by_z - prefix = "maps/away/" - -/datum/map_template/ruin/away_site/after_load(z) - if(islist(generate_mining_by_z)) - for(var/i in generate_mining_by_z) - var/current_z = z + i - 1 - new /datum/random_map/automata/cave_system(null, 1, 1, current_z, world.maxx, world.maxy) - new /datum/random_map/noise/ore(null, 1, 1, current_z, world.maxx, world.maxy) - GLOB.using_map.refresh_mining_turfs(current_z) - else if (isnum(generate_mining_by_z)) - new /datum/random_map/automata/cave_system(null, 1, 1, z + generate_mining_by_z - 1, world.maxx, world.maxy) - new /datum/random_map/noise/ore(null, 1, 1, z + generate_mining_by_z - 1, world.maxx, world.maxy) - GLOB.using_map.refresh_mining_turfs(z + generate_mining_by_z - 1) diff --git a/maps/away/bearcat/bearcat-1.dmm b/maps/away/bearcat/bearcat-1.dmm index 92efe051fa4b..534accc465e3 100644 --- a/maps/away/bearcat/bearcat-1.dmm +++ b/maps/away/bearcat/bearcat-1.dmm @@ -8,22 +8,19 @@ /area/space) "ac" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) "ad" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "cargo_out" }, /obj/machinery/shield_diffuser, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "ae" = ( /obj/machinery/door/airlock/external/bolted{ @@ -35,32 +32,38 @@ pixel_y = 17 }, /obj/machinery/shield_diffuser, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) +"af" = ( +/obj/machinery/cryopod/robot{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/computer/cryopod/robot{ + dir = 8 + }, +/turf/floor/tiled/usedup, +/area/ship/scrap/broken1) "ag" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "ah" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/escape_port) "ai" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "engwindow"; - name = "blast door"; - opacity = 0 - }, -/turf/simulated/floor/airless, +/obj/machinery/door/blast/regular/open{ + id_tag = "engwindow" + }, +/turf/floor/plating/airless, /area/ship/scrap/escape_port) "aj" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ id_tag = "cargo_pump" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "ak" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -72,92 +75,81 @@ tag_airpump = "cargo_pump"; tag_chamber_sensor = "cargo_sensor"; tag_exterior_door = "cargo_out"; - tag_interior_door = "cargo_in" + tag_interior_door = "cargo_in"; + dir = 8 }, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "al" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/cargo/lower) "am" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "ao" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/cargo/lower) "ap" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "engwindow"; - name = "blast door"; - opacity = 0 - }, -/turf/simulated/floor/airless, +/obj/machinery/door/blast/regular/open{ + id_tag = "engwindow" + }, +/turf/floor/plating/airless, /area/ship/scrap/escape_star) "aq" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/escape_star) "ar" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/door/window/southright, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/escape_port) "at" = ( /obj/machinery/atmospherics/pipe/simple/hidden, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "au" = ( /obj/machinery/airlock_sensor{ id_tag = "cargo_sensor"; - pixel_x = 25 + pixel_x = 25; + dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "av" = ( /obj/structure/ladder, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aw" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/flashlight/lamp, /obj/item/paper_bin, /obj/item/stamp/cargo, @@ -168,68 +160,63 @@ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "ax" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/door/window/southright, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/escape_star) "ay" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/escape_star) "az" = ( /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/escape_port) "aA" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/escape_port) "aB" = ( /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/escape_port) "aC" = ( /obj/structure/window/reinforced{ @@ -240,14 +227,14 @@ /obj/structure/window/reinforced{ dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aD" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "cargo_in" }, /obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "aE" = ( /obj/machinery/door/airlock/external/bolted{ @@ -259,172 +246,159 @@ pixel_y = -12 }, /obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "aF" = ( /obj/machinery/light_switch{ - pixel_x = -24 + pixel_x = -24; + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aG" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/stool/padded, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aH" = ( /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 8 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/escape_star) "aI" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/escape_star) "aJ" = ( /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/escape_star) "aK" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/gambling) "aL" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/gambling) "aM" = ( /obj/machinery/door/airlock/autoname/bearcat, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/escape_port) "aN" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aO" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aP" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aQ" = ( -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aR" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/closet/crate/plastic, /obj/random/accessory, /obj/random/accessory, -/obj/item/chems/glass/paint/random, -/turf/simulated/floor/tiled/usedup, +/obj/item/chems/glass/bucket/paint/random, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "aS" = ( /obj/machinery/door/airlock/autoname/bearcat, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/escape_star) "aT" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/dorms1) "aU" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/dorms1) "aV" = ( /obj/item/flashlight/lamp, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "aW" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/holostool, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/item/hand/missing_card, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "aX" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = 24 + pixel_x = 24; + dir = 8 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "aY" = ( /obj/machinery/light/small{ @@ -432,39 +406,33 @@ }, /obj/effect/decal/cleanable/cobweb2, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "aZ" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 8 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bb" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bc" = ( /obj/effect/floor_decal/industrial/outline/yellow, @@ -475,11 +443,10 @@ /obj/random/plushie, /obj/random/action_figure, /obj/random/action_figure, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bd" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/outline/yellow, @@ -487,12 +454,12 @@ dir = 4 }, /obj/random/closet, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "be" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/structure/ladder, /obj/effect/decal/cleanable/cobweb, @@ -500,78 +467,69 @@ pixel_x = -32 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "bf" = ( -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = -24 + pixel_x = -24; + dir = 4 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet, /obj/random/gloves, /obj/random/clothing, /obj/random/clothing, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bg" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/holostool, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/sign/poster{ pixel_y = 32 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bh" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/item/bedsheet/green, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bi" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bj" = ( /obj/structure/holostool, /obj/item/hand/missing_card, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bk" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -583,7 +541,7 @@ /obj/structure/table/gamblingtable, /obj/item/deck/cards, /obj/item/dice, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -593,13 +551,11 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/holostool, /obj/item/hand/missing_card, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bm" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -610,12 +566,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -628,64 +581,55 @@ icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "bo" = ( /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "bp" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bq" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "br" = ( /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bt" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bu" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -695,17 +639,12 @@ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "bw" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -716,12 +655,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -731,11 +667,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "by" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -744,26 +678,23 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bz" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/dark/airless, +/obj/structure/table, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bA" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/dorms1) "bB" = ( -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bC" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -772,35 +703,30 @@ }, /obj/structure/holostool, /obj/item/hand/missing_card, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bD" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, /obj/item/hand/missing_card, /obj/item/hand/missing_card, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/gambling) "bE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "bF" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, @@ -809,13 +735,13 @@ /obj/random/soap, /obj/item/bodybag, /obj/item/stack/tile/carpet/fifty, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bG" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/mech_wreckage/powerloader, /obj/machinery/mech_recharger, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bH" = ( /obj/structure/cable{ @@ -824,7 +750,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bI" = ( /obj/effect/floor_decal/industrial/outline/yellow, @@ -836,12 +762,11 @@ }, /obj/structure/closet/coffin, /obj/random/drinkbottle, -/obj/item/contraband/poster, -/turf/simulated/floor/tiled/usedup, +/obj/item/poster, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bJ" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/outline/yellow, @@ -849,23 +774,19 @@ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "bL" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, @@ -873,7 +794,7 @@ /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bM" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -881,21 +802,20 @@ level = 2 }, /obj/structure/holostool, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "bO" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning/corner, -/obj/machinery/mining/brace, -/turf/simulated/floor/tiled/usedup, +/obj/structure/drill_brace, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bP" = ( /obj/effect/floor_decal/industrial/outline/yellow, @@ -905,36 +825,34 @@ /obj/item/fossil/animal, /obj/item/fossil/animal, /obj/item/fossil, -/obj/item/cat_hide, -/obj/item/ore/strangerock, -/turf/simulated/floor/tiled/usedup, +/obj/item/strangerock, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bQ" = ( /obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/computer/shuttle_control/lift, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bR" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bS" = ( /obj/effect/floor_decal/industrial/warning, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bT" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/cable{ @@ -945,61 +863,57 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "bU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, /obj/structure/cable{ - d1 = 16; - d2 = 0; icon_state = "16-0" }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "bV" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/broken2) "bW" = ( /obj/machinery/floodlight, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "bX" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/item/frame/light/small, -/turf/simulated/floor/usedup, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/usedup, /area/ship/scrap/broken2) "bY" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = 24 + pixel_x = 24; + dir = 8 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, -/turf/simulated/floor/usedup, +/obj/structure/closet/crate/uranium, +/turf/floor/usedup, /area/ship/scrap/broken2) "bZ" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/broken2) "ca" = ( /obj/machinery/light/small{ @@ -1008,157 +922,137 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/effect/decal/cleanable/cobweb, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "cb" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/item/radio/intercom{ - pixel_x = -32 + pixel_x = -22; + dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "cc" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cd" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "ce" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cf" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "cg" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "ch" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/dorms2) "ci" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = -24 + pixel_x = -24; + dir = 4 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet, /obj/random/clothing, /obj/random/clothing, /obj/effect/decal/cleanable/cobweb, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cj" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/holostool, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "ck" = ( /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/item/bedsheet/ce, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cl" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/dorms2) "cm" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cn" = ( /obj/structure/foamedmetal, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "co" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1168,7 +1062,7 @@ dir = 5 }, /obj/item/cell/high/empty, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1178,11 +1072,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cq" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -1192,14 +1084,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/item/taperoll/engineering/applied, +/obj/structure/tape_barricade/engineering, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cr" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1209,48 +1098,42 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "cs" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "ct" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cu" = ( /obj/effect/shuttle_landmark/lift/bottom, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cv" = ( -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cw" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cx" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1260,17 +1143,12 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "cy" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -1281,12 +1159,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1296,11 +1171,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1309,27 +1182,24 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cB" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/newspaper, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cC" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/dorms2) "cD" = ( -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cE" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -1337,33 +1207,30 @@ level = 2 }, /obj/structure/foamedmetal, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cF" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, /obj/item/stack/cable_coil/random, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken2) "cG" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "cH" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, @@ -1372,15 +1239,15 @@ /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cI" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/obj/item/storage/briefcase, -/turf/simulated/floor/tiled/dark/airless, +/obj/item/briefcase, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "cK" = ( /turf/space, @@ -1392,88 +1259,76 @@ /area/ship/scrap/broken1) "cM" = ( /obj/structure/girder, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "cN" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/broken1) "cO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "cP" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "cQ" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cR" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cS" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/shuttle/lift) "cT" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/light/small{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "cU" = ( /obj/structure/lattice, @@ -1482,33 +1337,32 @@ /area/ship/scrap/broken1) "cV" = ( /obj/structure/inflatable/wall, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/broken1) "cW" = ( /obj/structure/inflatable/wall, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/broken1) "cX" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = 24 + pixel_x = 24; + dir = 8 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, -/obj/machinery/organ_printer/robot/mapped, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "cY" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/broken1) "cZ" = ( /obj/machinery/light/small{ @@ -1517,75 +1371,67 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "da" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/structure/sign/deck/second{ pixel_x = -32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "db" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "dc" = ( -/obj/structure/stairs/east, +/obj/structure/stairs/long/east, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "dd" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/ore_box, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "de" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 + dir = 1; + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "df" = ( /obj/machinery/light/small{ @@ -1594,54 +1440,48 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dg" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/dorms3) "dh" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = -24 + pixel_x = -24; + dir = 4 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet, /obj/random/gloves, /obj/random/clothing, /obj/random/clothing, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "di" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/holostool, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dj" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/curtain/open/bed, @@ -1651,19 +1491,16 @@ /obj/structure/sign/poster{ pixel_y = 32 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dk" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "dl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1673,7 +1510,7 @@ dir = 5 }, /obj/item/robotanalyzer, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "dm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1683,11 +1520,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "dn" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -1697,46 +1532,39 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/item/taperoll/engineering/applied, +/obj/structure/tape_barricade/engineering, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "do" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "dp" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "dq" = ( /obj/machinery/light/small, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "dr" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "ds" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -1747,12 +1575,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/dorms3) "dt" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1762,11 +1587,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "du" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1775,72 +1598,67 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dv" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/plushie, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dw" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/dorms3) "dx" = ( /obj/structure/mopbucket, -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, -/obj/item/storage/toolbox/mechanical, +/obj/item/toolbox/mechanical, /obj/item/multitool{ pixel_x = 3 }, /obj/item/clothing/glasses/welding, /obj/item/stack/cable_coil, /obj/item/stack/cable_coil, -/turf/simulated/floor/tiled/usedup, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/turf/floor/tiled/usedup, /area/ship/scrap/broken1) "dy" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/broken1) "dz" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, /obj/machinery/recharge_station, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/broken1) "dA" = ( /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "dB" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/cargo/lower) "dC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -1848,22 +1666,21 @@ /obj/structure/cable{ icon_state = "1-10" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dD" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/dorms3) "dE" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, /obj/structure/closet, /obj/random/clothing, /obj/random/clothing, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dF" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -1871,36 +1688,24 @@ level = 2 }, /obj/structure/holostool, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dG" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/item/bedsheet/brown, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms3) "dH" = ( /obj/machinery/floodlight, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/broken1) "dI" = ( /obj/item/stool/padded, -/turf/simulated/floor/tiled/usedup, -/area/ship/scrap/broken1) -"dJ" = ( -/obj/machinery/cryopod/robot{ - dir = 4 - }, -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/computer/cryopod/robot{ - pixel_x = 32; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/broken1) "dK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1910,15 +1715,13 @@ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/decal/cleanable/spiderling_remains, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dL" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -1929,12 +1732,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1944,19 +1744,15 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dN" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/machinery/power/apc/derelict, +/obj/machinery/apc/derelict, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, @@ -1964,21 +1760,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dO" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1987,25 +1778,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dP" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2015,27 +1803,20 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dR" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dS" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -2048,69 +1829,63 @@ /obj/structure/cable{ icon_state = "5-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/lower) "dU" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/techstorage) "dV" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/storage) "dW" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/storage) "dX" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "dY" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/eva) "dZ" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/eva) "ea" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/techstorage) "eb" = ( /obj/item/stock_parts/circuitboard/pacman, /obj/item/stock_parts/circuitboard/recharge_station, /obj/item/stock_parts/circuitboard/shield_generator, -/obj/structure/table/rack, +/obj/structure/rack, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/item/integrated_circuit_printer, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/techstorage) "ec" = ( /obj/item/stock_parts/circuitboard/helm, /obj/item/stock_parts/circuitboard/unary_atmos/cooler, -/obj/structure/table/rack, +/obj/structure/rack, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/alarm{ @@ -2118,21 +1893,23 @@ req_access = newlist() }, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/usedup, -/area/ship/scrap/maintenance/techstorage) -"ed" = ( /obj/item/stock_parts/circuitboard/autolathe, +/obj/item/stock_parts/circuitboard/recycler, /obj/item/stock_parts/circuitboard/unary_atmos/heater, -/obj/structure/table/rack, +/turf/floor/tiled/usedup, +/area/ship/scrap/maintenance/techstorage) +"ed" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/obj/machinery/network/relay{ + initial_network_id = "freightnet_0451" + }, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/techstorage) "ee" = ( -/obj/item/storage/toolbox/electrical, -/obj/item/storage/toolbox/electrical{ +/obj/item/toolbox/electrical, +/obj/item/toolbox/electrical{ pixel_x = 7; pixel_y = 4 }, @@ -2142,28 +1919,28 @@ pixel_y = 32; req_access = newlist() }, -/obj/item/tape_roll, +/obj/item/stack/tape_roll/duct_tape, /obj/machinery/light_switch{ - pixel_x = -24 + pixel_x = -24; + dir = 4 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 9 }, /obj/item/stock_parts/circuitboard/air_alarm, /obj/item/stock_parts/circuitboard/airlock_electronics, /obj/item/stock_parts/circuitboard/airlock_electronics, -/obj/structure/table/rack, -/turf/simulated/floor/tiled/usedup, +/obj/structure/rack, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "ef" = ( /obj/structure/closet/crate/plastic, -/obj/item/storage/ore, -/obj/item/pickaxe, +/obj/item/ore_satchel, +/obj/item/tool/pickaxe, /obj/item/stack/flag/yellow, -/obj/item/storage/box/glowsticks, +/obj/item/box/glowsticks, /obj/item/scanner/mining, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eg" = ( /obj/item/caution, @@ -2173,29 +1950,25 @@ /obj/item/mop, /obj/item/radio, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/obj/item/storage/bag/trash, -/turf/simulated/floor/usedup, +/obj/item/bag/trash, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "eh" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/ladder, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/sign/deck/second{ - pixel_x = 0; pixel_y = 32 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "ei" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -2204,53 +1977,51 @@ dir = 8; pixel_x = 22 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "ej" = ( -/obj/structure/table/rack, -/obj/item/tank/jetpack/oxygen, -/obj/item/clothing/mask/breath, -/turf/simulated/floor/usedup, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "ek" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/obj/structure/table/rack, +/obj/structure/rack, +/obj/item/tank/jetpack/oxygen, +/obj/item/clothing/mask/breath, /obj/item/tank/jetpack/oxygen, /obj/item/clothing/mask/breath, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "el" = ( -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "em" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) "en" = ( /obj/machinery/light/small{ dir = 8 }, /obj/machinery/vending/engineering/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/techstorage) "eo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2260,11 +2031,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/techstorage) "ep" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2274,12 +2043,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/techstorage) "eq" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -2290,19 +2056,15 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/techstorage) "er" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, @@ -2312,45 +2074,42 @@ /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "es" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "et" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eu" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "ev" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "ew" = ( /obj/structure/cable{ @@ -2363,12 +2122,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "ex" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2377,43 +2134,36 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "ey" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "ez" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 5 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "eA" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/external/bolted{ @@ -2424,27 +2174,23 @@ pixel_x = -12; pixel_y = 20 }, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "eB" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/machinery/airlock_sensor{ id_tag = "eva_sensor"; pixel_y = 40 }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ @@ -2461,7 +2207,7 @@ /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "eC" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -2472,7 +2218,7 @@ dir = 5 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "eD" = ( /obj/machinery/door/airlock/external/bolted{ @@ -2484,7 +2230,7 @@ pixel_y = -18 }, /obj/machinery/shield_diffuser, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "eE" = ( /obj/item/stock_parts/capacitor, @@ -2494,12 +2240,11 @@ /obj/item/stock_parts/scanning_module, /obj/item/stock_parts/scanning_module, /obj/item/stock_parts/scanning_module/adv, -/obj/structure/table/rack, +/obj/structure/rack, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/techstorage) "eF" = ( /obj/item/stock_parts/console_screen, @@ -2509,9 +2254,8 @@ /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/micro_laser/ultra, -/obj/structure/table/rack, -/obj/machinery/power/apc/derelict{ - dir = 2; +/obj/structure/rack, +/obj/machinery/apc/derelict{ name = "south bump"; pixel_y = -24 }, @@ -2520,79 +2264,67 @@ dir = 1; level = 2 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/techstorage) "eG" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/stock_parts/circuitboard/pacman/super/potato, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/ocp/ten, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, +/obj/item/stack/material/sheet/reinforced/mapped/ocp/ten, /obj/item/stock_parts/circuitboard/unary_atmos/engine, /obj/item/stock_parts/circuitboard/unary_atmos/engine, /obj/item/stock_parts/circuitboard/unary_atmos/engine, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/techstorage) "eH" = ( -/obj/item/storage/toolbox/mechanical{ +/obj/item/toolbox/mechanical{ pixel_x = 5; pixel_y = -7 }, -/obj/item/storage/toolbox/mechanical, +/obj/item/toolbox/mechanical, /obj/item/clothing/head/welding, /obj/item/scanner/gas, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 9 }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eI" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ icon_state = "4-9" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eJ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eK" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eL" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ icon_state = "5-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "eM" = ( /obj/item/radio/intercom{ @@ -2602,19 +2334,18 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "eN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/usedup, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "eO" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/sign/warning/vacuum{ @@ -2624,27 +2355,26 @@ dir = 8; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "eQ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/flashlight, /obj/item/flashlight, -/obj/item/storage/box/lights/bulbs, -/obj/item/storage/box/lights/mixed, +/obj/item/box/lights/bulbs, +/obj/item/box/lights/mixed, /obj/structure/cable, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ name = "Tools Storage APC" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 9 }, -/obj/item/taperoll/engineering, -/turf/simulated/floor/tiled/usedup, +/obj/item/stack/tape_roll/barricade_tape/engineering, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eR" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/inflatable_dispenser, /obj/item/radio, /obj/item/radio, @@ -2652,76 +2382,79 @@ dir = 1 }, /obj/machinery/light/small, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eS" = ( -/obj/item/tape_roll, -/obj/item/stack/material/plasteel/fifty, -/obj/item/stack/material/rods/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/plastic/fifty, -/obj/item/stack/material/steel/fifty, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, /obj/structure/closet/crate, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/reinforced/fifty, -/turf/simulated/floor/tiled/usedup, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/storage) "eT" = ( /obj/item/clothing/head/welding, /obj/item/radio, -/obj/item/tape_roll, -/obj/structure/table/standard, +/obj/item/stack/tape_roll/duct_tape, +/obj/structure/table, /obj/item/radio/intercom{ - pixel_y = -32 + pixel_y = -30; + dir = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "eU" = ( /obj/machinery/vending/tool/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "eV" = ( -/obj/structure/dispenser/oxygen, -/turf/simulated/floor/usedup, +/obj/structure/tank_rack/oxygen, +/turf/floor/usedup, /area/ship/scrap/maintenance/eva) "eW" = ( /obj/machinery/suit_cycler, /obj/machinery/light/small, -/turf/simulated/floor/tiled/usedup, +/obj/item/clothing/shoes/magboots, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "eX" = ( /obj/machinery/suit_cycler, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/obj/item/clothing/shoes/magboots, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/eva) "eY" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/storage) "fb" = ( /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/item/bedsheet/red, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms2) "gb" = ( /obj/effect/floor_decal/industrial/outline/yellow, @@ -2730,54 +2463,53 @@ /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/advdevice, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo/lower) "kH" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "kV" = ( -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "oj" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/broken1) "vU" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/item/bedsheet/brown, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/ship/scrap/crew/dorms1) "vY" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/escape_port) "xc" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/dorms3) "yN" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/techstorage) "Bu" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/eva) "GU" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/cargo/lower) "UZ" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/space) (1,1,1) = {" @@ -9077,7 +8809,7 @@ cN cX dm dz -dJ +af cN ec eo diff --git a/maps/away/bearcat/bearcat-2.dmm b/maps/away/bearcat/bearcat-2.dmm index b48aa1f19603..64fa7037ab30 100644 --- a/maps/away/bearcat/bearcat-2.dmm +++ b/maps/away/bearcat/bearcat-2.dmm @@ -4,53 +4,54 @@ /area/space) "ab" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/command/bridge) "ac" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/command/bridge) "ad" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/command/bridge) +"ae" = ( +/obj/machinery/cryopod, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24; + req_access = newlist() + }, +/obj/machinery/computer/cryopod, +/turf/floor/tiled/white, +/area/ship/scrap/crew/cryo) "ag" = ( /obj/machinery/computer/modular/preset/cardslot/command, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/ship/scrap/command/bridge) "ah" = ( /obj/machinery/computer/ship/helm, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/ship/scrap/command/bridge) "ai" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/toy/figure/captain, /obj/machinery/button/blast_door{ id_tag = "sensor"; @@ -58,24 +59,24 @@ }, /obj/item/radio, /obj/item/cell/high, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "aj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 1 }, -/obj/effect/landmark/deadcap, -/turf/simulated/floor/tiled/dark/usedup, +/obj/abstract/landmark/corpse/deadcap, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "ak" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/button/blast_door{ id_tag = "scraplock"; name = "External Lockdown" }, -/obj/item/gun/energy/captain, -/turf/simulated/floor/tiled/dark/usedup, +/obj/item/gun/energy/retro/captain, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "am" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -83,27 +84,25 @@ level = 2 }, /obj/machinery/computer/ship/engines{ - icon_state = "computer"; dir = 4 }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "an" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "ao" = ( /obj/machinery/computer/ship/sensors{ - icon_state = "computer"; dir = 8 }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "ap" = ( -/obj/effect/landmark/map_data{ +/obj/abstract/map_data{ height = 2 }, /turf/space, @@ -113,62 +112,65 @@ /turf/space, /area/space) "ar" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/comms) "as" = ( /obj/machinery/door/blast/regular{ - id_tag = "sensor" + id_tag = "sensor"; + dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/comms) "at" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/command/bridge) "au" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 8 }, /obj/structure/cable{ - d2 = 6; icon_state = "0-6" }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "av" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/hologram/holopad/longrange/remoteship, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "aw" = ( -/obj/machinery/requests_console{ +/obj/machinery/network/requests_console{ announcementConsole = 1; department = "Captain"; - pixel_x = 32 + pixel_x = 32; + initial_network_id = "freightnet_0451"; + dir = 4 }, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "ax" = ( /obj/machinery/shipsensors, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/comms) "ay" = ( /obj/machinery/light, /obj/item/radio/intercom{ - pixel_x = -32 + pixel_x = -22; + dir = 4 }, /obj/machinery/computer/modular/preset/engineering{ - icon_state = "console"; - dir = 1 + dir = 1; + icon_state = "console" }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "az" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -176,66 +178,61 @@ /obj/structure/cable{ icon_state = "2-9" }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "aA" = ( /obj/machinery/light, /obj/machinery/computer/modular/preset/cardslot/command{ - icon_state = "console"; - dir = 1 + dir = 1; + icon_state = "console" }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "aB" = ( /obj/machinery/door/blast/regular, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/command/captain) "aC" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/command/captain) "aD" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/comms) "aE" = ( /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/autoname/command/bearcat, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/bridge) "aF" = ( /obj/machinery/cryopod/lifepod, /obj/machinery/door/window/southright, /obj/machinery/computer/cryopod{ - pixel_x = 32 + dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aH" = ( -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/ship/scrap/comms) "aI" = ( /obj/machinery/light{ @@ -245,32 +242,31 @@ /obj/structure/window/reinforced{ dir = 8 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1; name = "Communications APC" }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/comms) "aJ" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4; name = "Bridge APC" }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -278,72 +274,66 @@ pixel_x = -32 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/hallway) "aK" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, /obj/structure/closet/cabinet, -/obj/item/storage/secure/briefcase, +/obj/item/secure_storage/briefcase, /obj/item/taperecorder, /obj/item/camera, -/obj/item/storage/backpack/dufflebag/syndie, -/obj/item/storage/box/ammo/shotgunshells, +/obj/item/backpack/dufflebag/syndie, +/obj/item/box/ammo/shotgunshells, /obj/item/handcuffs, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aL" = ( /obj/item/bedsheet/captain, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/item/gun/projectile/pistol/holdout, /obj/structure/bed/padded, -/obj/effect/submap_landmark/spawnpoint/captain, -/turf/simulated/floor/wood, +/obj/abstract/submap_landmark/spawnpoint/captain, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aM" = ( /obj/item/paper_bin, /obj/item/pen, -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/light_switch{ pixel_y = 25 }, /obj/random/action_figure, -/obj/item/storage/belt/utility/full, +/obj/item/belt/utility/full, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aN" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/comms) "aO" = ( -/obj/machinery/message_server, -/turf/simulated/floor/bluegrid/airless, +/obj/machinery/network/message_server{ + initial_network_id = "freightnet_0451" + }, +/turf/floor/bluegrid/airless, /area/ship/scrap/comms) "aP" = ( /obj/machinery/door/window/westleft, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -352,14 +342,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/comms) "aQ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -368,32 +355,25 @@ dir = 4 }, /obj/machinery/door/airlock/autoname/command/bearcat, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/comms) "aR" = ( /obj/structure/cable{ icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/hallway) "aS" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -402,7 +382,7 @@ dir = 4 }, /obj/machinery/door/airlock/autoname/command/bearcat, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/captain) "aT" = ( /obj/structure/cable{ @@ -414,7 +394,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -423,48 +403,42 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aV" = ( -/obj/structure/bed/chair/comfy/brown, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/brown, +/turf/floor/laminate, /area/ship/scrap/command/captain) "aW" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/command/captain) "aX" = ( /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = -32; req_access = newlist() }, /obj/machinery/computer/message_monitor{ - icon_state = "computer"; dir = 4 }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/ship/scrap/comms) "aY" = ( /obj/structure/window/reinforced{ dir = 8 }, /obj/item/radio/intercom{ - pixel_y = -32 + pixel_y = -30; + dir = 1 }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, @@ -472,21 +446,20 @@ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/comms) "aZ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/command/hallway) "ba" = ( /obj/item/radio/intercom{ - pixel_x = -32 + pixel_x = -22; + dir = 4 }, /obj/item/gun/projectile/shotgun/pump{ desc = "When words don't strike hard enough."; @@ -494,7 +467,7 @@ }, /obj/structure/window/reinforced/full, /obj/structure/table/marble, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "bb" = ( /obj/structure/cable{ @@ -504,49 +477,44 @@ dir = 1; level = 2 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/scrap/command/captain) "bc" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc/derelict/full{ +/obj/machinery/apc/derelict/full{ dir = 4; name = "Captain's Quarters APC" }, -/obj/item/chems/food/drinks/glass2/coffeecup/one, +/obj/item/chems/drinks/glass2/coffeecup/one, /obj/item/tank/oxygen, /obj/item/clothing/mask/breath/emergency, -/turf/simulated/floor/wood, +/obj/item/flashlight, +/turf/floor/laminate, /area/ship/scrap/command/captain) "bd" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/command/captain) "be" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/dock) "bf" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/autoname/command/bearcat, -/turf/simulated/floor/tiled/dark/usedup, +/turf/floor/tiled/dark/usedup, /area/ship/scrap/dock) "bg" = ( /obj/effect/shuttle_landmark/automatic, @@ -554,16 +522,13 @@ /area/space) "bh" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/dock) "bj" = ( /obj/machinery/atm{ @@ -571,57 +536,48 @@ }, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bk" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bl" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1; name = "Docking Area APC" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bm" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) "bn" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -630,10 +586,10 @@ /obj/structure/sign/warning/vacuum{ pixel_x = -35 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bo" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, @@ -641,11 +597,9 @@ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bp" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -657,12 +611,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -672,34 +623,25 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "br" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/plaque, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/obj/effect/submap_landmark/joinable_submap/bearcat, -/turf/simulated/floor/tiled/usedup, +/obj/abstract/submap_landmark/joinable_submap/bearcat, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -709,21 +651,19 @@ dir = 10 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bt" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/sign/warning/vacuum{ pixel_x = 35 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bu" = ( /obj/machinery/button/access/exterior{ @@ -736,12 +676,9 @@ }, /obj/machinery/shield_diffuser, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bv" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -749,12 +686,9 @@ id_tag = "dock_port_pump" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bw" = ( /obj/machinery/light{ @@ -773,24 +707,17 @@ tag_interior_door = "dock_port_in" }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bx" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/button/access/interior{ id_tag = "bearcat_dock_port"; @@ -798,37 +725,29 @@ pixel_y = 20 }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/external/bolted{ id_tag = "dock_port_in" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "by" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10; - icon_state = "intact" + dir = 10 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bz" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -836,49 +755,48 @@ level = 2 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bA" = ( -/obj/structure/closet/walllocker/emerglocker/south, +/obj/structure/emergency_dispenser/south, /obj/item/radio/intercom{ - pixel_x = -32 + pixel_x = -22; + dir = 4 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bB" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bC" = ( /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bD" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -886,32 +804,23 @@ level = 2 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bE" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 6 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bF" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/button/access/interior{ id_tag = "bearcat_starboard_dock"; @@ -919,19 +828,15 @@ pixel_y = 20 }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/external/bolted{ id_tag = "dock_star_in" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bG" = ( /obj/machinery/light{ @@ -950,16 +855,12 @@ tag_interior_door = "dock_star_in" }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bH" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -967,12 +868,9 @@ id_tag = "dock_star_pump" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bI" = ( /obj/machinery/button/access/exterior{ @@ -985,97 +883,83 @@ }, /obj/machinery/shield_diffuser, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bK" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/dock) "bL" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 4 }, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/portable_atmospherics/canister/empty/air, /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/dock) "bM" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bN" = ( /obj/item/radio/intercom{ - pixel_y = -32 + pixel_y = -30; + dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bO" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bP" = ( /obj/item/radio/intercom{ - pixel_y = -32 + pixel_y = -30; + dir = 1 }, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bR" = ( /obj/structure/window/reinforced{ @@ -1084,224 +968,189 @@ /obj/machinery/atmospherics/portables_connector{ dir = 8 }, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/portable_atmospherics/canister/empty/air, /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/dock) "bS" = ( /obj/structure/lattice, /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) "bT" = ( /obj/structure/sign/warning/docking_area, /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/dock) "bU" = ( /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bV" = ( /obj/structure/lattice, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/dock) "bW" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/dock) "bY" = ( /obj/structure/lattice, /turf/space, /area/space) "bZ" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/port) "ca" = ( -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "cc" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/dock) "ce" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "cf" = ( -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "cg" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/hallway/starboard) "ch" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/saloon) "ci" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cj" = ( /obj/random/maintenance, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "ck" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/saloon) "cl" = ( /obj/machinery/vending/snack, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cm" = ( -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1; name = "Crew Areas APC" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/structure/bed/chair, -/turf/simulated/floor/tiled/usedup, +/obj/structure/chair, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cn" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "co" = ( -/obj/structure/closet/walllocker/emerglocker/north, -/obj/structure/bed/chair/wood, +/obj/structure/emergency_dispenser/north, +/obj/structure/chair/wood, /obj/item/deck/tarot, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cp" = ( /obj/machinery/vending/coffee, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cq" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/toilets) "cr" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/toilets) "cs" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/toilets) "ct" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "cu" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/media/jukebox, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cv" = ( -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cw" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -1309,141 +1158,109 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cx" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cy" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/recharger, /obj/structure/sign/poster{ - pixel_x = 32; - pixel_y = 0 + pixel_x = 32 }, -/obj/item/trash/tray, +/obj/item/plate/tray, /obj/item/circular_saw, -/turf/simulated/floor/tiled/usedup, +/obj/item/flashlight/lamp, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cz" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/item/crowbar, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "cA" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/cryo) "cB" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/cryo) "cC" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/usedup, -/area/ship/scrap/crew/cryo) -"cD" = ( -/obj/machinery/computer/cryopod, -/turf/simulated/wall, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/cryo) "cE" = ( -/obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 - }, /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, -/obj/structure/window/reinforced/tinted{ - dir = 1 - }, /obj/item/soap, /obj/structure/curtain/open/shower, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "cF" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 - }, -/obj/structure/hygiene/toilet, -/obj/structure/window/reinforced/tinted{ - dir = 1 - }, -/obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 - }, -/obj/structure/window/reinforced/tinted{ dir = 8; - icon_state = "twindow" + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, +/obj/structure/hygiene/toilet, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "cH" = ( /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "cI" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/structure/reagent_dispensers/water_cooler, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cJ" = ( /obj/item/stool/padded, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cK" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/smokes, /obj/item/ashtray/glass, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/item/board, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cL" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/structure/closet/emcloset, /obj/structure/sign/deck/first{ @@ -1455,20 +1272,21 @@ /obj/random/voidsuit, /obj/random/voidsuit, /obj/random/voidsuit, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cM" = ( /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "cN" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/item/radio/intercom{ - pixel_x = -32 + pixel_x = -22; + dir = 4 }, /obj/structure/closet/wardrobe/pjs, /obj/structure/sign/poster{ @@ -1482,40 +1300,26 @@ /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "cO" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/obj/effect/submap_landmark/spawnpoint/crewman, -/turf/simulated/floor/tiled/white, -/area/ship/scrap/crew/cryo) -"cP" = ( -/obj/machinery/cryopod, -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24; - req_access = newlist() - }, -/turf/simulated/floor/tiled/white, +/obj/abstract/submap_landmark/spawnpoint/crewman, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "cQ" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/toilets) "cR" = ( /obj/machinery/door/window/westleft{ @@ -1526,12 +1330,12 @@ opacity = 1 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/item/towel, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "cS" = ( /obj/machinery/door/window/westleft{ @@ -1542,12 +1346,10 @@ opacity = 1 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "cT" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1557,14 +1359,11 @@ dir = 6 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "cU" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Bathrooms"; @@ -1577,14 +1376,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "cV" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 @@ -1592,59 +1388,43 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "cW" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cX" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cY" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "cZ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -1652,36 +1432,26 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "da" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "db" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "dc" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 @@ -1689,14 +1459,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "dd" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Cryo Storage"; @@ -1709,12 +1476,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/cryo) "de" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1723,141 +1488,109 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "df" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/obj/effect/submap_landmark/spawnpoint/crewman, -/turf/simulated/floor/tiled/white, +/obj/abstract/submap_landmark/spawnpoint/crewman, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "dg" = ( /obj/machinery/cryopod, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "dh" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/cryo) "di" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, -/obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 - }, -/obj/structure/window/reinforced/tinted, /obj/structure/curtain/open/shower, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "dj" = ( /obj/structure/hygiene/toilet{ - icon_state = "toilet00"; dir = 1 }, -/obj/structure/window/reinforced/tinted, -/obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 - }, -/obj/structure/window/reinforced/tinted{ - dir = 8; - icon_state = "twindow" - }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "dk" = ( /obj/structure/hygiene/toilet{ - icon_state = "toilet00"; dir = 1 }, -/obj/structure/window/reinforced/tinted{ - dir = 8; - icon_state = "twindow" - }, -/obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 - }, -/obj/structure/window/reinforced/tinted, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4; name = "Bathrooms APC" }, /obj/machinery/light_switch{ - pixel_y = -25 + pixel_y = -25; + dir = 1 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "dl" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 4 + dir = 4; + icon_state = "conpipe-c" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "dm" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/saloon) "dn" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/machinery/vending/cigarette, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "do" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "dp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/disposalpipe/segment{ @@ -1865,17 +1598,18 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "dq" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/item/radio/intercom{ - pixel_y = -32 + pixel_y = -30; + dir = 1 }, /obj/structure/ladder, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "dr" = ( /obj/machinery/disposal, @@ -1883,148 +1617,146 @@ dir = 8 }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/saloon) "ds" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "dt" = ( /obj/structure/cable, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ name = "Dorms APC" }, /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -25; + dir = 4 }, /obj/structure/closet/wardrobe/mixed, -/obj/item/storage/backpack/dufflebag/med, -/obj/item/storage/belt/utility/full, -/turf/simulated/floor/tiled/white, +/obj/item/backpack/dufflebag/med, +/obj/item/belt/utility/full, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "du" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/obj/effect/submap_landmark/spawnpoint/crewman, -/turf/simulated/floor/tiled/white, +/obj/abstract/submap_landmark/spawnpoint/crewman, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "dv" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/kitchen) "dw" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/kitchen) "dx" = ( /obj/structure/disposalpipe/segment, -/obj/structure/closet/walllocker/emerglocker/east, +/obj/structure/emergency_dispenser/east, /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -25; + dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "dy" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/cargo) "dz" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dA" = ( /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -25; + dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/sign/deck/first{ pixel_x = 32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/starboard) "dB" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/medbay) "dC" = ( /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "dD" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/medbay) "dE" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagentgrinder, /obj/effect/floor_decal/corner/red/diagonal, -/obj/structure/sign/monkey_painting{ +/obj/structure/sign/painting/monkey_painting{ pixel_y = 32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "dF" = ( /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/effect/floor_decal/corner/red/diagonal, /obj/machinery/vending/dinnerware, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "dG" = ( -/obj/structure/closet/walllocker/emerglocker/north, +/obj/structure/emergency_dispenser/north, /obj/structure/closet/secure_closet/freezer/fridge/bearcat, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/red/diagonal, /obj/random/drinkbottle, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "dH" = ( /obj/structure/disposalpipe/segment, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4; name = "Crew Deck APC" }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "dI" = ( /obj/structure/closet/crate, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/random/shoes, @@ -2032,183 +1764,167 @@ /obj/random/hat, /obj/random/hat, /obj/random/masks, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dJ" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dK" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dL" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dM" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "dO" = ( /obj/machinery/sleeper/standard, /obj/structure/sign/warning/nosmoking_2{ pixel_y = 28 }, -/obj/structure/closet/walllocker/emerglocker/west, +/obj/structure/emergency_dispenser/west, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "dP" = ( /obj/item/roller, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "dQ" = ( /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/item/bedsheet/medical, /obj/structure/curtain/open/privacy, /obj/structure/bed/padded, -/obj/item/clothing/accessory/stethoscope, +/obj/item/clothing/neck/stethoscope, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "dR" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/engine/port) "dS" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/kitchen) "dT" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/effect/floor_decal/corner/red/diagonal, /obj/item/chems/glass/beaker{ pixel_x = 5 }, /obj/item/book/manual/chef_recipes, -/obj/item/chems/food/condiment/small/peppermill{ +/obj/item/chems/condiment/small/peppermill{ pixel_x = 3 }, -/obj/item/chems/food/condiment/enzyme, -/obj/item/chems/glass/rag, -/turf/simulated/floor/tiled/usedup, +/obj/item/chems/condiment/enzyme, +/obj/item/chems/rag, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "dU" = ( /obj/item/stool/padded, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/corner/red/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "dV" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4; name = "Galley APC" }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "dW" = ( /obj/structure/disposalpipe/segment, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/sign/directions/engineering{ pixel_x = -32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "dX" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dY" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/closet/crate/hydroponics/prespawned, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "dZ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "ea" = ( /obj/effect/floor_decal/industrial/outline/yellow, @@ -2216,26 +1932,25 @@ dir = 8 }, /obj/item/stool/padded, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eb" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "ec" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2243,82 +1958,66 @@ pixel_x = -32 }, /obj/structure/ladder, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "ed" = ( -/obj/structure/sign/redcross, -/turf/simulated/wall, +/obj/structure/sign/department/cross, +/turf/wall, /area/ship/scrap/crew/medbay) "ee" = ( /obj/item/stool/padded, /obj/structure/hygiene/sink{ dir = 8; - icon_state = "sink"; - pixel_x = -13; - pixel_y = 0 + pixel_x = -13 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "ef" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "eg" = ( /obj/structure/iv_drip, -/obj/structure/closet/medical_wall{ - name = "pill cabinet"; - pixel_x = 26 - }, -/obj/item/storage/pill_bottle/antibiotics, -/obj/item/storage/pill_bottle/painkillers, -/obj/item/storage/pill_bottle/antitox, -/obj/item/storage/pill_bottle/burn_meds, -/turf/simulated/floor/tiled/white, +/obj/structure/closet/secure_closet/medical_wall/pills{ + req_access = null; + pixel_x = 26; + dir = 8 + }, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) -"eh" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall, -/area/ship/scrap/maintenance/engine/starboard) "ei" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/structure/cable{ icon_state = "4-10" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/kitchen) "ej" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/item/storage/box/donkpockets, +/obj/item/box/donkpockets, /obj/effect/floor_decal/corner/red/diagonal, -/obj/item/kitchen/rollingpin, -/obj/item/chems/food/condiment/small/saltshaker{ - pixel_x = -3; - pixel_y = 0 +/obj/item/rollingpin, +/obj/item/chems/condiment/small/saltshaker{ + pixel_x = -3 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "ek" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, @@ -2327,20 +2026,16 @@ }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "el" = ( /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 4 + dir = 4; + icon_state = "conpipe-c" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2351,21 +2046,16 @@ }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "em" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, @@ -2375,31 +2065,23 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "en" = ( /obj/structure/disposalpipe/junction, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "eo" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, @@ -2409,17 +2091,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "ep" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2428,14 +2106,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eq" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -2443,35 +2118,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "er" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "es" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -2479,22 +2145,16 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "et" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2503,28 +2163,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eu" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "ev" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Medical Bay"; @@ -2537,12 +2191,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/medbay) "ew" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2552,98 +2204,81 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "ex" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/obj/structure/bed/chair/office/light, +/obj/structure/chair/office/light, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "ey" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/glass_extra/straw, -/obj/item/toy/therapy_blue, +/obj/random/plush/therapy, /obj/item/chems/spray/cleaner, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "ez" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/medbay) "eA" = ( -/obj/item/storage/pill_bottle/happy, -/obj/machinery/power/apc/derelict{ +/obj/item/pill_bottle/happy, +/obj/machinery/apc/derelict{ dir = 1 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/port) "eB" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/machinery/meter, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/port) "eC" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/port) "eD" = ( /obj/item/screwdriver, @@ -2651,26 +2286,24 @@ icon_state = "5-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) "eE" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/microwave, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/red/diagonal, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "eF" = ( /obj/structure/closet/secure_closet/freezer/meat/bearcat, @@ -2678,50 +2311,50 @@ dir = 1 }, /obj/effect/floor_decal/corner/red/diagonal, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/turf/simulated/floor/tiled/usedup, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "eG" = ( /obj/machinery/disposal, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, /obj/effect/floor_decal/corner/red/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/kitchen) "eH" = ( /obj/structure/disposalpipe/segment, /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "eI" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -25; + dir = 4 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eJ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -2729,11 +2362,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eL" = ( /obj/structure/closet/crate, @@ -2745,83 +2376,82 @@ /obj/random/bomb_supply, /obj/random/bomb_supply, /obj/random/bomb_supply, -/obj/item/storage/box/syringes, -/turf/simulated/floor/tiled/usedup, +/obj/item/box/syringes, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eM" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4; name = "Cargo Hold APC" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "eN" = ( -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 4; name = "Crew Deck APC" }, /obj/structure/cable, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "eO" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/cable, -/obj/machinery/power/apc/derelict/full{ +/obj/machinery/apc/derelict/full{ name = "Medical Bay APC" }, /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -25; + dir = 4 }, /obj/structure/closet/medical_wall/filled{ - pixel_y = -32 + pixel_y = -32; + dir = 1 }, -/obj/item/tape_roll, +/obj/item/stack/tape_roll/duct_tape, /obj/item/retractor, /obj/item/scalpel, -/turf/simulated/floor/tiled/white, +/obj/item/tank/oxygen, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "eP" = ( /obj/machinery/light, /obj/machinery/optable, -/obj/item/chems/food/drinks/glass2/coffeecup/britcup, -/obj/item/chems/glass/rag, -/turf/simulated/floor/tiled/white, +/obj/item/chems/drinks/glass2/coffeecup/britcup, +/obj/item/chems/rag, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "eQ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/sign/warning/nosmoking_1{ pixel_y = -32 }, -/obj/structure/sign/goldenplaque/medical{ +/obj/structure/sign/plaque/golden/medical{ pixel_x = 32 }, -/obj/item/storage/firstaid/adv, +/obj/item/firstaid/adv, /obj/random/medical, -/obj/item/stack/medical/advanced/bruise_pack, +/obj/item/stack/medical/bandage/advanced, /obj/item/chems/syringe/antibiotic, /obj/item/scanner/health, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/medbay) "eR" = ( /obj/item/radio, @@ -2829,68 +2459,48 @@ icon_state = "4-9" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) -"eS" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; - dir = 4 - }, -/obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/usedup, -/area/ship/scrap/maintenance/engine/starboard) "eT" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/item/coin/gold, /obj/item/coin/silver, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, /obj/machinery/meter, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/starboard) "eU" = ( -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/starboard) "eV" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/port) "eW" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/port) "eX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel, @@ -2898,36 +2508,34 @@ /turf/space, /area/space) "eY" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/crew/wash) "eZ" = ( /obj/structure/disposalpipe/segment, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "fa" = ( /obj/effect/floor_decal/industrial/warning, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/sign/warning/fall{ pixel_x = -32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "fb" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/industrial/warning, /obj/machinery/computer/shuttle_control/lift, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "fc" = ( /obj/effect/floor_decal/industrial/warning, @@ -2937,10 +2545,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "fd" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2949,12 +2557,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "fe" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ @@ -2967,33 +2574,27 @@ dir = 10 }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "ff" = ( /obj/effect/decal/cleanable/cobweb, /obj/effect/decal/cleanable/cobweb2, /obj/structure/cable{ - d1 = 32; - d2 = 1; icon_state = "32-1" }, /obj/structure/lattice, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/open, +/turf/open, /area/ship/scrap/crew/hallway/starboard) "fg" = ( /obj/structure/lattice, @@ -3002,50 +2603,45 @@ /area/space) "fh" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/engine/starboard) "fi" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 8 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/starboard) "fj" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/starboard) "fk" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/sign/warning/hot_exhaust, /obj/effect/paint/red, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/engine/port) "fl" = ( /obj/machinery/atmospherics/unary/engine{ - icon_state = "nozzle"; dir = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/port) "fm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/space) "fo" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/structure/undies_wardrobe, @@ -3053,15 +2649,15 @@ dir = 4 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fp" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -3070,24 +2666,22 @@ dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fq" = ( /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 4 + dir = 4; + icon_state = "conpipe-c" }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1; name = "Washroom APC" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -3096,21 +2690,17 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fr" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Laundry"; @@ -3124,10 +2714,9 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fs" = ( /obj/machinery/light{ @@ -3141,37 +2730,32 @@ dir = 10 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/disposalpipe/junction, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "ft" = ( -/turf/simulated/open, +/turf/open, /area/ship/scrap/cargo) "fu" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "fv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3181,15 +2765,12 @@ dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "fw" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -3201,16 +2782,12 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3221,13 +2798,12 @@ }, /obj/random/junk, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fy" = ( /obj/machinery/light_switch{ @@ -3235,90 +2811,59 @@ }, /obj/random/maintenance, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fz" = ( /obj/effect/decal/cleanable/cobweb2, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/usedup, +/obj/machinery/network/relay{ + initial_network_id = "freightnet_0451" + }, +/turf/floor/usedup, /area/ship/scrap/unused) "fA" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/unused) "fB" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/sign/warning/hot_exhaust, /obj/effect/paint/red, -/turf/simulated/wall, -/area/ship/scrap/maintenance/engine/starboard) -"fC" = ( -/obj/machinery/atmospherics/unary/engine{ - icon_state = "nozzle"; - dir = 1 - }, -/turf/simulated/floor/usedup, -/area/ship/scrap/maintenance/engine/starboard) -"fD" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/structure/sign/warning/hot_exhaust, -/obj/effect/paint/red, -/turf/simulated/wall/r_wall, +/turf/wall, /area/ship/scrap/maintenance/engine/starboard) "fE" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/space, -/area/space) -"fF" = ( -/obj/structure/lattice, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/space, -/area/space) +/turf/floor/plating/airless, +/area/ship/scrap/maintenance/engine/port) "fG" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 5 }, /turf/space, /area/space) "fH" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/wash) "fI" = ( /obj/structure/closet, @@ -3327,99 +2872,91 @@ /obj/random/clothing, /obj/random/clothing, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, -/obj/item/storage/backpack/dufflebag, +/obj/item/backpack/dufflebag, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fK" = ( /obj/machinery/disposal, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 28; + dir = 8 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fL" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/structure/disposalpipe/segment, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/sign/directions/medical{ dir = 4; - icon_state = "direction_med"; pixel_x = 32; pixel_z = -4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "fM" = ( /obj/effect/shuttle_landmark/lift/top, -/turf/simulated/open, +/turf/open, /area/ship/scrap/cargo) "fN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "fO" = ( -/obj/structure/closet/walllocker/emerglocker/west, -/obj/effect/decal/cleanable/dirt, +/obj/structure/emergency_dispenser/west, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "fP" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/unused) "fQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fR" = ( /obj/effect/decal/cleanable/generic, /obj/item/flashlight, /obj/structure/skele_stand{ - anchored = 0; name = "Spookers" }, /obj/structure/cable{ @@ -3429,36 +2966,30 @@ dir = 1; level = 2 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fS" = ( /obj/random/junk, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fT" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "fU" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, /turf/space, @@ -3469,9 +3000,9 @@ /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, -/obj/item/chems/glass/rag, +/obj/item/chems/rag, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fW" = ( /obj/machinery/washing_machine, @@ -3480,122 +3011,116 @@ level = 2 }, /obj/effect/floor_decal/corner/white/diagonal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fX" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/light/small, /obj/item/chems/spray/cleaner, -/obj/item/storage/laundry_basket, +/obj/item/laundry_basket, /obj/effect/floor_decal/corner/white/diagonal, /obj/item/cell/high, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/wash) "fY" = ( -/obj/structure/closet/walllocker/emerglocker/east, +/obj/structure/emergency_dispenser/east, /obj/structure/disposalpipe/segment, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "fZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/sign/deck/first{ pixel_x = 32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "ga" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "gb" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/item/stool/padded, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "gc" = ( -/obj/machinery/power/apc/derelict/full{ +/obj/machinery/apc/derelict/full{ name = "Medical Bay APC" }, /obj/structure/cable, /obj/machinery/icecream_vat, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "gd" = ( /obj/random/maintenance, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/unused) "ge" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/fire) "gf" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/fire) "gg" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/hallway/port) "gh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ icon_state = "1-10" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "gi" = ( /obj/machinery/door/airlock/autoname/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "gj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/crew/hallway/starboard) "gk" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/hidden) "gl" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/hidden) "gm" = ( /obj/structure/closet/firecloset, @@ -3613,54 +3138,48 @@ /obj/item/seeds/potatoseed, /obj/item/seeds/poppyseed, /obj/item/seeds/poppyseed, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "go" = ( /obj/effect/decal/cleanable/cobweb2, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gp" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/airlock/autoname/bearcat, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/hallway) "gq" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "gr" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/cable{ icon_state = "5-8" @@ -3672,21 +3191,20 @@ dir = 4 }, /obj/machinery/light/small, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "gs" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 + dir = 1; + icon_state = "warningcorner" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/cargo) "gt" = ( /obj/machinery/door/airlock/autoname/bearcat, @@ -3694,22 +3212,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gv" = ( /obj/machinery/light_switch{ pixel_y = 25 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/item/storage/backpack/dufflebag/syndie, +/obj/item/backpack/dufflebag/syndie, /mob/living/simple_animal/hostile/vagrant, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gw" = ( /obj/structure/closet/crate, /obj/random/coin, /obj/item/cash/c1000, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gx" = ( /obj/structure/disposaloutlet{ @@ -3718,22 +3236,19 @@ /obj/structure/disposalpipe/trunk{ dir = 4 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "gy" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/fire) "gz" = ( /obj/machinery/portable_atmospherics/powered/pump/filled, @@ -3749,7 +3264,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gA" = ( /obj/structure/disposalpipe/segment{ @@ -3758,12 +3273,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gB" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/disposalpipe/segment{ @@ -3775,12 +3288,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gC" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ @@ -3797,13 +3308,11 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gD" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -3816,11 +3325,10 @@ icon_state = "6-8" }, /obj/structure/disposalpipe/junction/yjunction{ - icon_state = "pipe-y"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/hallway) "gE" = ( /obj/effect/decal/cleanable/cobweb, @@ -3831,7 +3339,7 @@ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3840,9 +3348,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall/r_wall{ - can_open = 1 - }, +/turf/wall/false, /area/ship/scrap/hidden) "gG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3852,7 +3358,7 @@ dir = 4 }, /mob/living/simple_animal/hostile/vagrant, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gH" = ( /obj/item/stool/padded, @@ -3862,15 +3368,15 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gI" = ( /obj/structure/table/reinforced, /obj/item/flashlight/lamp, /obj/item/cash/c1000, -/obj/item/storage/bible/booze, +/obj/item/bible/booze, /obj/item/cell/high, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gJ" = ( /obj/machinery/portable_atmospherics/powered/scrubber, @@ -3883,26 +3389,24 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gK" = ( -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gL" = ( /obj/structure/cable, -/obj/machinery/power/apc/derelict{ - dir = 2; +/obj/machinery/apc/derelict{ name = "south bump"; pixel_y = -24 }, /obj/structure/reagent_dispensers, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "gM" = ( /obj/structure/disposalpipe/segment{ @@ -3916,16 +3420,14 @@ dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 5 }, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/hallway) "gN" = ( /obj/machinery/light/small, @@ -3939,16 +3441,15 @@ icon_state = "4-9" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/hallway) "gO" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, @@ -3956,19 +3457,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 2 + dir = 2; + icon_state = "conpipe-c" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/hallway) "gP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3978,15 +3476,12 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gQ" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, @@ -3995,20 +3490,15 @@ icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ - icon_state = "map"; dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/hallway) "gR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4018,17 +3508,15 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4038,15 +3526,14 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gT" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/item/crowbar, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4056,44 +3543,38 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = -32; req_access = newlist() }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/structure/sign/directions/medical{ dir = 1; - icon_state = "direction_med"; pixel_x = 30; pixel_z = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/hallway) "gW" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gX" = ( /obj/structure/closet/crate, @@ -4102,30 +3583,28 @@ /obj/random/loot, /obj/random/projectile, /obj/random/projectile, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) "gY" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/atmos) "gZ" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/atmos) "ha" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/atmos) "hb" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/engineering) "hc" = ( /obj/structure/disposalpipe/segment, -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/engineering) "hd" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, @@ -4133,28 +3612,28 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "he" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/power) "hf" = ( /obj/structure/cable{ icon_state = "2-9" }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/power) "hg" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/power) "hh" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 6 }, /obj/effect/floor_decal/corner/blue, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hi" = ( /obj/machinery/atmospherics/binary/pump/on{ @@ -4162,127 +3641,109 @@ target_pressure = 200 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/blue{ dir = 10 }, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hj" = ( /obj/effect/floor_decal/corner/blue{ dir = 10 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hk" = ( /obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ - icon_state = "intact-scrubbers"; dir = 4 }, /obj/effect/floor_decal/corner/blue{ dir = 8 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hl" = ( /obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ - icon_state = "intact-scrubbers"; dir = 10 }, /obj/machinery/meter, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/light_switch{ pixel_y = 25 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hm" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 1 }, /obj/structure/sign/warning/compressed_gas{ pixel_x = -32 }, /obj/structure/bed/padded, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hn" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, /obj/machinery/disposal, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "ho" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet/toolcloset, -/obj/item/storage/backpack/dufflebag/eng, -/obj/item/stack/material/glass/reinforced/fifty, -/obj/item/stack/material/steel/fifty, -/turf/simulated/floor/tiled/usedup, +/obj/item/backpack/dufflebag/eng, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hp" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -4290,44 +3751,42 @@ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hq" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light_switch{ pixel_y = 25 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/obj/structure/table/standard, -/obj/item/chems/food/drinks/glass2/coffeecup/metal, -/obj/item/chems/food/drinks/glass2/coffeecup/metal, +/obj/structure/table, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/item/chems/drinks/glass2/coffeecup/metal, /obj/item/chems/chem_disp_cartridge/coffee{ name = "coffee canister" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hr" = ( -/obj/structure/bed/chair/comfy/brown, +/obj/structure/chair/comfy/brown, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet/hydrant{ pixel_y = 32 }, -/obj/item/storage/firstaid/regular, -/turf/simulated/floor/tiled/usedup, +/obj/item/firstaid/regular, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hu" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/cell_charger, -/obj/item/storage/toolbox/electrical{ +/obj/item/toolbox/electrical{ pixel_x = 7; pixel_y = 4 }, @@ -4335,32 +3794,29 @@ pixel_y = 25 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "hv" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/cell_charger, /obj/item/defibrillator/compact/loaded, /obj/item/flashlight, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "hw" = ( /turf/space, /area/ship/scrap/maintenance/atmos) "hx" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/atmos) "hy" = ( /obj/structure/window/reinforced{ @@ -4373,7 +3829,7 @@ /obj/effect/floor_decal/corner/blue/diagonal{ dir = 4 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "hz" = ( /obj/machinery/atmospherics/portables_connector, @@ -4381,33 +3837,25 @@ dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hA" = ( /obj/machinery/atmospherics/pipe/simple/visible/supply{ - icon_state = "intact-supply"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ - icon_state = "intact-scrubbers"; dir = 5 }, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hB" = ( /obj/machinery/door/firedoor, @@ -4418,23 +3866,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/atmos) "hC" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4443,14 +3884,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hD" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -4462,17 +3900,13 @@ icon_state = "4-10" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hE" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -4482,60 +3916,45 @@ }, /obj/structure/ladder, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hF" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/stool/padded, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hG" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hH" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -4543,15 +3962,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/tiled/usedup, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hI" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4561,14 +3977,11 @@ dir = 4 }, /obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "hJ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 @@ -4576,33 +3989,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "hK" = ( -/obj/machinery/power/sensor{ +/obj/machinery/power_sensor{ id_tag = "Main Grid" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "hL" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ icon_state = "2-9" @@ -4611,45 +4017,45 @@ /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "hM" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /obj/structure/lattice, /turf/space, /area/ship/scrap/maintenance/atmos) "hN" = ( /obj/item/shard, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/atmos) "hO" = ( /obj/machinery/atmospherics/unary/outlet_injector{ - icon_state = "map_injector"; dir = 8; - use_power = 1; - id_tag = "n2_in" + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 }, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "hP" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - icon_state = "map_vent_in"; dir = 4; - use_power = 1; - id_tag = "air_out"; - pump_direction = 0; external_pressure_bound = 0; - internal_pressure_bound = 2000; - pressure_checks = 2; external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; - pressure_checks_default = 2 + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "hQ" = ( /obj/machinery/meter, @@ -4659,36 +4065,33 @@ /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hR" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/atmospherics/pipe/simple/visible/supply, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "hS" = ( -/obj/structure/closet/walllocker/emerglocker/west, +/obj/structure/emergency_dispenser/west, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/cable{ icon_state = "2-5" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hT" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/closet/secure_closet/engineering_welding/bearcat, @@ -4696,83 +4099,79 @@ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hU" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/computer/ship/engines{ - icon_state = "computer"; dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hV" = ( /obj/structure/cable, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/button/ignition{ id_tag = "engine"; - pixel_x = -5 + pixel_x = -5; + dir = 4 }, /obj/machinery/button/blast_door{ id_tag = "engwindow"; name = "Engine Observation"; - pixel_x = 6 + pixel_x = 6; + dir = 8 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hW" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/light/small, /obj/machinery/button/blast_door{ id_tag = "scram"; name = "CORE SCRAM"; - pixel_y = -26 + pixel_y = -26; + dir = 1 }, /obj/machinery/computer/modular/preset/engineering{ - icon_state = "console"; - dir = 1 + dir = 1; + icon_state = "console" }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hX" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/machinery/vending/cigarette, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hY" = ( /obj/structure/reagent_dispensers/fueltank, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/structure/sign/warning/nosmoking_1{ pixel_y = -32 }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) "hZ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -4781,37 +4180,31 @@ }, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "ia" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "ib" = ( /obj/machinery/power/breakerbox/activated, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "ic" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "id" = ( /obj/item/shard, @@ -4819,8 +4212,8 @@ /turf/space, /area/ship/scrap/maintenance/atmos) "ie" = ( -/obj/item/stack/material/steel, -/turf/simulated/floor/airless, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/atmos) "if" = ( /obj/structure/window/reinforced{ @@ -4829,11 +4222,10 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "ig" = ( /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/visible/cyan, @@ -4841,12 +4233,11 @@ dir = 4; level = 2 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "ih" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/item/radio/intercom{ @@ -4856,67 +4247,57 @@ /obj/machinery/atmospherics/pipe/manifold/visible/supply{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "ii" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/machinery/door/airlock/autoname/engineering/bearcat, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engine/aft) "ij" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/engine/aft) "ik" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "engwindow"; - name = "blast door"; - opacity = 0 +/obj/machinery/door/blast/regular/open{ + id_tag = "engwindow" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/aft) "il" = ( /obj/machinery/light/small{ dir = 8 }, /obj/structure/closet/crate/uranium, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "im" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "in" = ( -/obj/machinery/power/shield_generator, +/obj/machinery/shield_generator/mapped, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "io" = ( /obj/structure/lattice, @@ -4935,54 +4316,48 @@ }, /obj/effect/floor_decal/corner/white/diagonal, /obj/effect/floor_decal/corner/white/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "ir" = ( /obj/machinery/atmospherics/omni/mixer{ active_power_usage = 7500; - tag_east = 0; tag_east_con = 0; tag_north = 1; tag_north_con = 0.21; tag_south = 1; tag_south_con = 0.79; - tag_west = 2; - use_power = 1 + tag_west = 2 }, /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "is" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/portable_atmospherics/powered/pump/filled, -/turf/simulated/floor/tiled/airless, +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "iu" = ( /obj/structure/sign/warning/fire{ pixel_y = 32 }, /obj/machinery/atmospherics/portables_connector, -/obj/item/stack/material/glass/reinforced_borosilicate{ - amount = 5 - }, -/turf/simulated/floor/airless, +/obj/item/stack/material/pane/mapped/rborosilicate/five, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iv" = ( /obj/machinery/light_switch{ pixel_y = 25 }, /obj/machinery/atmospherics/unary/tank/carbon_dioxide, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iw" = ( /obj/machinery/atmospherics/portables_connector, @@ -4992,12 +4367,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "ix" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 @@ -5005,24 +4380,21 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iy" = ( /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/airless, -/area/ship/scrap/maintenance/engine/aft) -"iz" = ( -/obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iA" = ( /obj/structure/closet/radiation, /obj/machinery/button/blast_door{ id_tag = "radaway"; name = "Radiation shields"; - pixel_x = -24 + pixel_x = -24; + dir = 4 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "iB" = ( /obj/machinery/power/terminal{ @@ -5030,20 +4402,18 @@ }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "iC" = ( /obj/structure/cable, /obj/machinery/power/smes/buildable, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "iD" = ( /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/visible/cyan, @@ -5051,58 +4421,55 @@ dir = 4; name = "Air to Ports" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "iE" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/blue{ - icon_state = "map"; - dir = 4 - }, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/tiled/airless, +/obj/machinery/atmospherics/pipe/manifold/visible/blue{ + dir = 4 + }, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "iF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 8 }, /obj/structure/cable, /obj/item/radio/intercom{ - pixel_x = -32 + pixel_x = -22; + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iG" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iH" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/manifold/visible/fuel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iJ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iL" = ( /obj/machinery/atmospherics/omni/mixer{ @@ -5112,50 +4479,43 @@ tag_west = 1; tag_west_con = 0.64 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iM" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/window/southright, /obj/machinery/door/window/northleft, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; - id_tag = "radaway"; - opacity = 0 + id_tag = "radaway" }, -/obj/structure/sign{ - icon_state = "radiation"; +/obj/structure/sign/warning/radioactive{ pixel_x = -32 }, -/obj/structure/sign{ - icon_state = "radiation"; +/obj/structure/sign/warning/radioactive{ pixel_x = 32 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "iN" = ( -/obj/item/stack/material/plasteel, -/turf/simulated/floor/usedup, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "iO" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /mob/living/simple_animal/hostile/carp, /turf/space, /area/ship/scrap/maintenance/atmos) "iP" = ( -/obj/item/stack/material/steel, -/obj/item/stack/material/rods, +/obj/item/stack/material/sheet/mapped/steel, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/ship/scrap/maintenance/atmos) "iQ" = ( -/obj/item/stack/material/plasteel, -/turf/simulated/floor/airless, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/atmos) "iR" = ( /obj/structure/window/reinforced{ @@ -5165,19 +4525,19 @@ dir = 1 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - icon_state = "map_vent_in"; dir = 4; - use_power = 1; - id_tag = "air_out"; - pump_direction = 0; external_pressure_bound = 0; - internal_pressure_bound = 2000; - pressure_checks = 2; external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; - pressure_checks_default = 2 + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "iS" = ( /obj/machinery/meter, @@ -5187,7 +4547,7 @@ /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "iT" = ( /obj/machinery/atmospherics/portables_connector{ @@ -5195,30 +4555,27 @@ }, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "iU" = ( /obj/machinery/atmospherics/valve/shutoff, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iV" = ( /obj/structure/window/borosilicate_reinforced{ @@ -5228,7 +4585,7 @@ dir = 1 }, /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/engine/aft) "iW" = ( /obj/structure/window/borosilicate_reinforced{ @@ -5238,7 +4595,7 @@ /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 6 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/engine/aft) "iX" = ( /obj/structure/window/borosilicate_reinforced{ @@ -5255,52 +4612,43 @@ icon_state = "map_injector"; use_power = 1 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/engine/aft) "iY" = ( /obj/structure/window/borosilicate_reinforced, /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/obj/item/stack/material/glass/reinforced_borosilicate{ - amount = 20 - }, -/turf/simulated/floor/airless, +/obj/item/stack/material/pane/mapped/rborosilicate/twenty, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "iZ" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "ja" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/simple/visible/green{ - dir = 9; - icon_state = "intact" + dir = 9 }, /obj/structure/closet/crate/solar, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jb" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; - id_tag = "radaway"; - opacity = 0 + id_tag = "radaway" }, /obj/machinery/meter/turf, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "jc" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /obj/structure/lattice, /turf/space, /area/ship/scrap/maintenance/power) @@ -5309,15 +4657,14 @@ dir = 4 }, /obj/effect/floor_decal/corner/red/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/window/reinforced{ - dir = 2; - health = 1e+007 + current_health = 1e+007 }, -/turf/simulated/floor/reinforced/airless, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "je" = ( /obj/machinery/atmospherics/portables_connector{ @@ -5326,7 +4673,7 @@ /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "jf" = ( /obj/machinery/light/small{ @@ -5334,38 +4681,38 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/machinery/meter, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jg" = ( /obj/structure/window/borosilicate_reinforced{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/engine/aft) "jh" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, /obj/machinery/igniter{ id_tag = "engine" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/engine/aft) "ji" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/engine/aft) "jj" = ( /obj/machinery/door/blast/regular{ id_tag = "scram" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jk" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jl" = ( /obj/item/radio/intercom{ @@ -5377,21 +4724,21 @@ }, /obj/machinery/portable_atmospherics/canister/empty, /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jm" = ( /obj/structure/cable, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/power) "jn" = ( -/obj/item/stack/material/steel, +/obj/item/stack/material/sheet/mapped/steel, /turf/space, /area/ship/scrap/maintenance/power) "jo" = ( /turf/space, /area/ship/scrap/maintenance/power) "jp" = ( -/obj/item/stack/material/steel, +/obj/item/stack/material/sheet/mapped/steel, /turf/space, /area/space) "jr" = ( @@ -5399,25 +4746,26 @@ dir = 1 }, /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "js" = ( /obj/machinery/atmospherics/valve/open, /obj/item/shard/borosilicate, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jt" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 5 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/ship/scrap/maintenance/engine/aft) "ju" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 9 }, /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/ship/scrap/maintenance/engine/aft) "jv" = ( /obj/structure/window/borosilicate_reinforced, @@ -5431,11 +4779,10 @@ dir = 4; external_pressure_bound = 4000; external_pressure_bound_default = 4000; - icon_state = "map_vent"; pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/ship/scrap/maintenance/engine/aft) "jw" = ( /obj/structure/window/borosilicate_reinforced{ @@ -5444,15 +4791,14 @@ /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/black{ - icon_state = "intact"; dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jy" = ( /obj/machinery/atmospherics/omni/filter{ @@ -5463,34 +4809,31 @@ use_power = 0 }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/black{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/power) "jA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/black{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/wall, +/turf/wall, /area/ship/scrap/maintenance/power) "jB" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/space) "jC" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/multitool{ pixel_x = 5 }, -/obj/item/pipe_painter, -/obj/item/clamp, -/turf/simulated/floor/usedup, +/obj/item/paint_sprayer, +/turf/floor/usedup, /area/ship/scrap/maintenance/atmos) "jD" = ( /obj/effect/floor_decal/corner/blue, @@ -5498,12 +4841,11 @@ dir = 8 }, /obj/machinery/space_heater, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "jE" = ( /obj/machinery/fabricator/pipe, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/effect/floor_decal/corner/blue, @@ -5511,25 +4853,25 @@ /obj/effect/floor_decal/corner/yellow{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "jF" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jG" = ( /obj/item/shard/borosilicate, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jH" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jI" = ( /obj/machinery/atmospherics/valve/open{ - icon_state = "map_valve1"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jK" = ( /obj/machinery/atmospherics/portables_connector{ @@ -5537,16 +4879,16 @@ }, /obj/machinery/portable_atmospherics/canister/empty, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jL" = ( /obj/machinery/door/blast/regular{ id_tag = "scram" }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/aft) "jM" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume{ @@ -5554,15 +4896,13 @@ external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; - pressure_checks = 1; - pressure_checks_default = 1; use_power = 1 }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/maintenance/engine/aft) "jN" = ( -/obj/item/stack/material/steel, -/obj/item/stack/material/rods, +/obj/item/stack/material/sheet/mapped/steel, +/obj/item/stack/material/rods/mapped/steel, /obj/structure/lattice, /turf/space, /area/ship/scrap/maintenance/engine/aft) @@ -5572,40 +4912,38 @@ "jP" = ( /obj/structure/window/reinforced, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 1 }, /obj/effect/floor_decal/industrial/warning, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jQ" = ( /obj/structure/window/reinforced, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 1 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jR" = ( /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jS" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/light/small, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/structure/closet/crate/solar_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jT" = ( /obj/structure/lattice, @@ -5613,7 +4951,7 @@ /turf/space, /area/ship/scrap/maintenance/engine/aft) "jU" = ( -/obj/item/stack/material/plasteel, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel, /obj/structure/lattice, /turf/space, /area/ship/scrap/maintenance/engine/aft) @@ -5623,110 +4961,99 @@ /area/ship/scrap/maintenance/engine/aft) "jW" = ( /obj/machinery/atmospherics/unary/engine{ - icon_state = "nozzle"; dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jX" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/ship/scrap/maintenance/engine/aft) "jY" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/structure/sign/warning/hot_exhaust{ pixel_y = 32 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "jZ" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "kb" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_y = 29 }, /obj/structure/hygiene/sink{ pixel_y = 18 }, -/obj/structure/window/reinforced/tinted{ - dir = 8; - icon_state = "twindow" - }, -/obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 - }, -/obj/structure/window/reinforced/tinted{ - dir = 1 - }, -/obj/structure/window/reinforced/tinted{ - dir = 8; - icon_state = "twindow" - }, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/item/hemostat, /obj/effect/floor_decal/corner/white/diagonal, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/crew/toilets) "km" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/toilets) "lX" = ( -/obj/item/stack/material/steel, +/obj/item/stack/material/sheet/mapped/steel, /obj/structure/lattice, /turf/space, /area/ship/scrap/maintenance/power) "nS" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/command/captain) "oa" = ( /obj/machinery/cryopod, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/scrap/crew/cryo) "ou" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/hallway/port) +"oR" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/turf/floor/plating/airless, +/area/ship/scrap/maintenance/engine/starboard) +"rH" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 1 + }, +/turf/floor/usedup, +/area/ship/scrap/maintenance/engine/starboard) "so" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/medbay) "sy" = ( /obj/structure/lattice, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/atmos) "ts" = ( /obj/structure/lattice, @@ -5734,63 +5061,81 @@ /area/ship/scrap/maintenance/power) "uf" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 5 }, /obj/effect/decal/cleanable/ash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "uM" = ( -/obj/item/stack/material/steel, +/obj/item/stack/material/sheet/mapped/steel, /obj/structure/lattice, +/obj/machinery/portable_atmospherics/canister/nitrogen, /turf/space, /area/ship/scrap/maintenance/atmos) "vs" = ( /obj/structure/lattice, /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/space) "vN" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/engine/aft) "wp" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/atmos) +"xs" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/effect/paint/red, +/turf/wall/r_wall, +/area/ship/scrap/maintenance/engine/starboard) "xU" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/space) +"zq" = ( +/obj/item/stack/material/rods, +/turf/space, +/area/ship/scrap/maintenance/atmos) "zT" = ( /obj/effect/floor_decal/corner/blue/diagonal{ dir = 4 }, /obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "Cs" = ( /obj/effect/floor_decal/industrial/warning, /obj/effect/paint/red, -/turf/simulated/wall/r_wall, -/area/space) +/turf/wall/r_wall, +/area/ship/scrap/maintenance/engine/port) +"Cy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/obj/machinery/door/airlock/autoname/engineering/bearcat, +/turf/floor/usedup, +/area/ship/scrap/maintenance/engine/starboard) "Dr" = ( /obj/structure/closet/secure_closet/engineering_electrical/bearcat, /obj/item/cell/device/standard, /obj/item/cell/device/standard, -/obj/machinery/power/apc/derelict{ +/obj/machinery/apc/derelict{ dir = 8 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/item/cell/crap, /obj/item/cell/crap, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/power) "Eq" = ( /obj/structure/lattice, @@ -5798,80 +5143,93 @@ /area/ship/scrap/maintenance/atmos) "FI" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "GG" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/kitchen) "Hd" = ( -/obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/space, -/area/space) +/obj/item/stack/material/sheet/mapped/steel, +/obj/machinery/atmospherics/unary/tank/nitrogen{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/ship/scrap/maintenance/atmos) "HQ" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "IG" = ( /obj/item/shard, /obj/machinery/atmospherics/unary/outlet_injector{ - icon_state = "map_injector"; dir = 8; - use_power = 1; - id_tag = "n2_in" + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/atmos) "Jy" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/fireaxecabinet{ pixel_y = 32 }, /obj/item/cell/potato, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/fire) "JC" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/sign/warning/high_voltage{ pixel_x = 32 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/toy/prize/powerloader, /obj/item/ashtray/plastic, /obj/machinery/recharger, /obj/structure/sign/poster{ pixel_y = 32 }, -/turf/simulated/floor/tiled/usedup, +/turf/floor/tiled/usedup, /area/ship/scrap/maintenance/engineering) +"KW" = ( +/obj/item/shard, +/obj/structure/lattice, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/space, +/area/ship/scrap/maintenance/atmos) "Lp" = ( -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "Ly" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/dock) +"LS" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/sign/warning/hot_exhaust, +/obj/effect/paint/red, +/turf/wall/r_wall, +/area/ship/scrap/maintenance/engine/starboard) "LW" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/fire) "Mm" = ( /obj/effect/floor_decal/corner/red/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, /obj/effect/floor_decal/corner/red/diagonal, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/scrap/maintenance/atmos) "Mp" = ( /obj/structure/closet/crate, @@ -5883,83 +5241,86 @@ /obj/item/cell/high, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24; req_access = newlist() }, -/turf/simulated/floor/usedup, +/turf/floor/usedup, /area/ship/scrap/hidden) +"Nc" = ( +/obj/machinery/network/router{ + initial_network_id = "bearnet" + }, +/turf/floor/bluegrid/airless, +/area/ship/scrap/comms) "Od" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) "PP" = ( -/obj/machinery/power/apc/derelict/full{ +/obj/machinery/apc/derelict/full{ name = "Medical Bay APC" }, /obj/structure/cable{ - d2 = 6; icon_state = "0-6" }, -/obj/machinery/power/port_gen/pacman/super, -/turf/simulated/floor/usedup, +/obj/machinery/port_gen/pacman/super, +/turf/floor/usedup, /area/ship/scrap/hidden) "Qe" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, /obj/machinery/meter, /obj/effect/decal/cleanable/ash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "Sm" = ( -/obj/structure/closet/walllocker/emerglocker/west, +/obj/structure/emergency_dispenser/west, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/effect/decal/cleanable/molten_item, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "Ul" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/cryo) "Ur" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/crew/wash) +"UD" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall, +/area/ship/scrap/maintenance/engine/starboard) "Va" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/hidden) "Wu" = ( /obj/effect/decal/cleanable/molten_item, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/scrap/maintenance/engine/aft) "Yl" = ( /obj/structure/lattice, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/maintenance/atmos) "Yv" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/scrap/comms) "YS" = ( /obj/effect/floor_decal/corner/red{ dir = 5 }, /obj/effect/decal/cleanable/ash, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/ship/scrap/maintenance/atmos) (1,1,1) = {" @@ -11274,8 +10635,8 @@ aa aa aa aa -xU -xU +dR +dR Cs aa aa @@ -11765,7 +11126,7 @@ dR eC dR fk -fF +fE bY aa aa @@ -11897,14 +11258,14 @@ wp gY hx hx -ie +Hd iQ -hw +zq iP Eq -id +KW Yl -Hd +aa aa aa aa @@ -12148,7 +11509,7 @@ IG Mm hN hx -hM +hw aa aa aa @@ -12595,7 +11956,7 @@ xU Yv Yv ar -aH +Nc aO aX Yv @@ -13484,7 +12845,7 @@ JC hH hY ij -iz +iy iL ja jl @@ -14072,8 +13433,8 @@ bY bY aa xU -cD -cP +cB +ae dg oa dB @@ -14445,11 +13806,11 @@ aa aa aa bY -eh -eS +UD +Cy fh fB -fF +oR aa aa aa @@ -14566,11 +13927,11 @@ aa aa aa aa -eh -eh +UD +UD eT fi -fC +rH aa aa aa @@ -14688,11 +14049,11 @@ aa aa aa aa -eh -eh +UD +UD eU fj -fC +rH aa aa aa @@ -14811,11 +14172,11 @@ aa aa aa aa -eh -eh -eh -fD -fE +UD +UD +UD +LS +oR aa aa aa @@ -14934,9 +14295,9 @@ aa aa aa aa -xU -xU -Cs +UD +UD +xs aa aa aa diff --git a/maps/away/bearcat/bearcat.dm b/maps/away/bearcat/bearcat.dm index 63c2083df290..dc13ca07d873 100644 --- a/maps/away/bearcat/bearcat.dm +++ b/maps/away/bearcat/bearcat.dm @@ -1,14 +1,14 @@ +#include "../../../mods/content/modern_earth/_modern_earth.dme" // for the British flag cups, which could honestly just be removed #include "bearcat_areas.dm" #include "bearcat_jobs.dm" #include "bearcat_access.dm" -/obj/effect/submap_landmark/joinable_submap/bearcat - name = "FTV Bearcat" +/obj/abstract/submap_landmark/joinable_submap/bearcat + name = "FTV Bearcat" archetype = /decl/submap_archetype/derelict/bearcat /decl/submap_archetype/derelict/bearcat - descriptor = "derelict cargo vessel" - map = "Bearcat Wreck" + name = "derelict cargo vessel" crew_jobs = list( /datum/job/submap/bearcat_captain, /datum/job/submap/bearcat_crewman @@ -25,13 +25,12 @@ name = "[pick("FTV","ITV","IEV")] [pick("Bearcat", "Firebug", "Defiant", "Unsinkable","Horizon","Vagrant")]" for(var/area/ship/scrap/A) A.name = "\improper [name] - [A.name]" - GLOB.using_map.area_purity_test_exempt_areas += A.type + global.using_map.area_purity_test_exempt_areas += A.type name = "[name], \a [initial(name)]" . = ..() /datum/map_template/ruin/away_site/bearcat_wreck name = "Bearcat Wreck" - id = "awaysite_bearcat_wreck" description = "A wrecked light freighter." suffixes = list("bearcat/bearcat-1.dmm", "bearcat/bearcat-2.dmm") cost = 1 @@ -70,7 +69,7 @@ icon_state = "tiny" icon_keyboard = "tiny_keyboard" icon_screen = "lift" - density = 0 + density = FALSE /obj/effect/shuttle_landmark/lift/top name = "Top Deck" @@ -81,21 +80,7 @@ name = "Lower Deck" landmark_tag = "nav_bearcat_lift_bottom" base_area = /area/ship/scrap/cargo/lower - base_turf = /turf/simulated/floor - -/obj/machinery/power/apc/derelict - lighting = 0 - equipment = 0 - environ = 0 - locked = 0 - uncreated_component_parts = list( - /obj/item/cell/crap/empty - ) - -/obj/machinery/power/apc/derelict/full - uncreated_component_parts = list( - /obj/item/cell/crap - ) + base_turf = /turf/floor/plating /obj/machinery/door/airlock/autoname/command door_color = COLOR_COMMAND_BLUE @@ -103,57 +88,52 @@ /obj/machinery/door/airlock/autoname/engineering door_color = COLOR_AMBER -/turf/simulated/floor/usedup +/turf/floor/usedup initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) -/turf/simulated/floor/tiled/usedup +/turf/floor/tiled/usedup initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) -/turf/simulated/floor/tiled/dark/usedup +/turf/floor/tiled/dark/usedup initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) -/turf/simulated/floor/tiled/white/usedup +/turf/floor/tiled/white/usedup initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) -/obj/effect/landmark/deadcap +/obj/abstract/landmark/corpse/deadcap name = "Dead Captain" + corpse_outfits = list(/decl/outfit/deadcap) + delete_me = FALSE // we handle this in LateInit -/obj/effect/landmark/deadcap/Initialize() +/obj/abstract/landmark/corpse/deadcap/Initialize() ..() return INITIALIZE_HINT_LATELOAD -// chair may need to init first -/obj/effect/landmark/deadcap/LateInitialize() - ..() - var/turf/T = get_turf(src) - var/mob/living/carbon/human/corpse = new(T) - scramble(1,corpse,100) - corpse.real_name = "Captain" - corpse.name = "Captain" - var/decl/hierarchy/outfit/outfit = outfit_by_type(/decl/hierarchy/outfit/deadcap) - outfit.equip(corpse) - corpse.adjustOxyLoss(corpse.maxHealth) - corpse.setBrainLoss(corpse.maxHealth) - var/obj/structure/bed/chair/C = locate() in T +/obj/abstract/landmark/corpse/deadcap/LateInitialize() + var/mob/corpse = my_corpse?.resolve() + if(!istype(corpse)) + return + corpse.SetName("Captain") + var/obj/structure/chair/C = locate() in loc if(C) C.buckle_mob(corpse) qdel(src) -/decl/hierarchy/outfit/deadcap +/decl/outfit/deadcap name = "Derelict Captain" - uniform = /obj/item/clothing/under/casual_pants/classicjeans - suit = /obj/item/clothing/suit/storage/hooded/wintercoat + uniform = /obj/item/clothing/pants/baggy/casual/classicjeans + suit = /obj/item/clothing/suit/jacket/winter shoes = /obj/item/clothing/shoes/color/black r_pocket = /obj/item/radio -/decl/hierarchy/outfit/deadcap/post_equip(mob/living/carbon/human/H) +/decl/outfit/deadcap/post_equip(mob/living/wearer) ..() - var/obj/item/clothing/uniform = H.w_uniform + var/obj/item/clothing/uniform = wearer.get_equipped_item(slot_w_uniform_str) if(uniform) - var/obj/item/clothing/accessory/toggleable/hawaii/random/eyegore = new() + var/obj/item/clothing/shirt/hawaii/random/eyegore = new() if(uniform.can_attach_accessory(eyegore)) uniform.attach_accessory(null, eyegore) else qdel(eyegore) var/obj/item/cell/super/C = new() - H.put_in_any_hand_if_possible(C) + wearer.put_in_hands(C) diff --git a/maps/away/bearcat/bearcat_access.dm b/maps/away/bearcat/bearcat_access.dm index 36f24ec45b45..167dd671f20b 100644 --- a/maps/away/bearcat/bearcat_access.dm +++ b/maps/away/bearcat/bearcat_access.dm @@ -1,10 +1,10 @@ -/var/const/access_bearcat = "ACCESS_BEARCAT" //998 +var/global/const/access_bearcat = "ACCESS_BEARCAT" //998 /datum/access/bearcat id = access_bearcat desc = "FTU Crewman" region = ACCESS_REGION_NONE -/var/const/access_bearcat_captain = "ACCESS_BEARCAT_CAPTAIN" //999 +var/global/const/access_bearcat_captain = "ACCESS_BEARCAT_CAPTAIN" //999 /datum/access/bearcat_captain id = access_bearcat_captain desc = "FTU Captain" @@ -39,3 +39,4 @@ /obj/machinery/vending/tool/bearcat req_access = list(access_bearcat) + diff --git a/maps/away/bearcat/bearcat_areas.dm b/maps/away/bearcat/bearcat_areas.dm index 1ab4dbada43b..85920d542ad4 100644 --- a/maps/away/bearcat/bearcat_areas.dm +++ b/maps/away/bearcat/bearcat_areas.dm @@ -1,134 +1,134 @@ /area/ship/scrap - name = "Generic Ship" + name = "\improper Generic Ship" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') /area/ship/scrap/crew - name = "Crew Compartements" + name = "\improper Crew Compartements" icon_state = "crew_quarters" /area/ship/scrap/crew/hallway/port - name = "Crew Hallway - Port" + name = "\improper Crew Hallway - Port" /area/ship/scrap/crew/hallway/starboard - name = "Crew Hallway - Starboard" + name = "\improper Crew Hallway - Starboard" /area/ship/scrap/crew/kitchen - name = "Galley" + name = "\improper Galley" icon_state = "kitchen" /area/ship/scrap/crew/cryo - name = "Cryo Storage" + name = "\improper Cryo Storage" icon_state = "cryo" /area/ship/scrap/crew/dorms1 - name = "Crew Cabin #1" + name = "\improper Crew Cabin #1" icon_state = "green" /area/ship/scrap/crew/dorms2 - name = "Crew Cabin #2" + name = "\improper Crew Cabin #2" icon_state = "purple" /area/ship/scrap/crew/dorms3 - name = "Crew Cabin #3" + name = "\improper Crew Cabin #3" icon_state = "yellow" /area/ship/scrap/crew/saloon - name = "Saloon" + name = "\improper Saloon" icon_state = "conference" /area/ship/scrap/crew/toilets - name = "Bathrooms" + name = "\improper Bathrooms" icon_state = "toilet" turf_initializer = /decl/turf_initializer/maintenance /area/ship/scrap/crew/wash - name = "Washroom" + name = "\improper Washroom" icon_state = "locker" /area/ship/scrap/crew/medbay - name = "Medical Bay" + name = "\improper Medical Bay" icon_state = "medbay" /area/ship/scrap/cargo - name = "Cargo Hold" + name = "\improper Cargo Hold" icon_state = "quartstorage" /area/ship/scrap/cargo/lower - name = "Lower Cargo Hold" + name = "\improper Lower Cargo Hold" /area/ship/scrap/dock - name = "Docking Bay" + name = "\improper Docking Bay" icon_state = "entry_1" /area/ship/scrap/fire - name = "Firefighting Equipment Comparment" + name = "\improper Firefighting Equipment Comparment" icon_state = "green" /area/ship/scrap/unused - name = "Compartment 2-B" + name = "\improper Compartment 2-B" icon_state = "yellow" turf_initializer = /decl/turf_initializer/maintenance ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg') /area/ship/scrap/hidden - name = "Unknown" //shielded compartment + name = "\improper Unknown" //shielded compartment icon_state = "auxstorage" /area/ship/scrap/escape_port - name = "Port Escape Pods" + name = "\improper Port Escape Pods" icon_state = "green" /area/ship/scrap/escape_star - name = "Starboard Escape Pods" + name = "\improper Starboard Escape Pods" icon_state = "yellow" /area/ship/scrap/broken1 - name = "Robotic Maintenance" + name = "\improper Robotic Maintenance" icon_state = "green" /area/ship/scrap/broken2 - name = "Compartment 1-B" + name = "\improper Compartment 1-B" icon_state = "yellow" /area/ship/scrap/gambling - name = "Compartment 1-C" + name = "\improper Compartment 1-C" icon_state = "cave" /area/ship/scrap/maintenance - name = "Maintenance Compartments" + name = "\improper Maintenance Compartments" icon_state = "amaint" req_access = list(access_bearcat) /area/ship/scrap/maintenance/hallway - name = "Maintenance Corridors" + name = "\improper Maintenance Corridors" /area/ship/scrap/maintenance/lower - name = "Lower Deck Maintenance Compartments" + name = "\improper Lower Deck Maintenance Compartments" icon_state = "sub_maint_aft" /area/ship/scrap/maintenance/storage - name = "Tools Storage" + name = "\improper Tools Storage" icon_state = "engineering_storage" /area/ship/scrap/maintenance/techstorage - name = "Parts Storage" + name = "\improper Parts Storage" icon_state = "engineering_supply" /area/ship/scrap/maintenance/eva - name = "EVA Storage" + name = "\improper EVA Storage" icon_state = "eva" /area/ship/scrap/maintenance/engineering - name = "Engineering Bay" + name = "\improper Engineering Bay" icon_state = "engineering_supply" /area/ship/scrap/maintenance/atmos - name = "Atmospherics Comparment" + name = "\improper Atmospherics Comparment" icon_state = "atmos" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambiatm1.ogg') /area/ship/scrap/maintenance/power - name = "Power Compartment" + name = "\improper Power Compartment" icon_state = "engine_smes" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') @@ -137,35 +137,35 @@ ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') /area/ship/scrap/maintenance/engine/aft - name = "Main Engine Bay" + name = "\improper Main Engine Bay" /area/ship/scrap/maintenance/engine/port - name = "Port Thruster" + name = "\improper Port Thruster" /area/ship/scrap/maintenance/engine/starboard - name = "Starboard Thruster" + name = "\improper Starboard Thruster" /area/ship/scrap/command/hallway - name = "Command Deck" + name = "\improper Command Deck" icon_state = "centcom" req_access = list(access_bearcat) /area/ship/scrap/command/bridge - name = "Bridge" + name = "\improper Bearcat Bridge" icon_state = "bridge" req_access = list(access_bearcat) /area/ship/scrap/command/captain - name = "Captain's Quarters" + name = "\improper Captain's Quarters" icon_state = "captain" req_access = list(access_bearcat_captain) /area/ship/scrap/comms - name = "Communications Relay" + name = "\improper Communications Relay" icon_state = "tcomsatcham" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/signal.ogg','sound/ambience/sonar.ogg') /area/ship/scrap/shuttle/lift - name = "Cargo Lift" + name = "\improper Cargo Lift" icon_state = "shuttle3" - base_turf = /turf/simulated/open \ No newline at end of file + base_turf = /turf/open \ No newline at end of file diff --git a/maps/away/bearcat/bearcat_jobs.dm b/maps/away/bearcat/bearcat_jobs.dm index 3b8b78a25864..aa3578e6a53e 100644 --- a/maps/away/bearcat/bearcat_jobs.dm +++ b/maps/away/bearcat/bearcat_jobs.dm @@ -1,56 +1,60 @@ /datum/job/submap/bearcat_captain title = "Independant Captain" total_positions = 1 - outfit_type = /decl/hierarchy/outfit/job/bearcat/captain + outfit_type = /decl/outfit/job/bearcat/captain supervisors = "your bottom line" info = "Your ship has suffered a catastrophic amount of damage, leaving it dark and crippled in the depths of \ unexplored space. The Captain is dead, leaving you, previously the First Mate in charge. Organize what's left of \ your crew, and maybe you'll be able to survive long enough to be rescued." + access = list( + access_engine, + access_atmospherics, + ) /datum/job/submap/bearcat_crewman title = "Independant Crewman" supervisors = "the Captain" total_positions = 3 - outfit_type = /decl/hierarchy/outfit/job/bearcat/crew + outfit_type = /decl/outfit/job/bearcat/crew info = "Your ship has suffered a catastrophic amount of damage, leaving it dark and crippled in the depths of \ unexplored space. Work together with the Acting Captain and what's left of the crew, and maybe you'll be able \ to survive long enough to be rescued." + access = list( + access_engine, + access_atmospherics + ) -#define BEARCAT_OUTFIT_JOB_NAME(job_name) ("Bearcat - Job - " + job_name) - -/decl/hierarchy/outfit/job/bearcat - hierarchy_type = /decl/hierarchy/outfit/job/bearcat +/decl/outfit/job/bearcat + abstract_type = /decl/outfit/job/bearcat pda_type = /obj/item/modular_computer/pda - pda_slot = slot_l_store + pda_slot = slot_l_store_str r_pocket = /obj/item/radio l_ear = null r_ear = null -/decl/hierarchy/outfit/job/bearcat/crew - name = BEARCAT_OUTFIT_JOB_NAME("FTU Crew") +/decl/outfit/job/bearcat/crew + name = "Bearcat - Job - FTU Crew" id_type = /obj/item/card/id/bearcat -/decl/hierarchy/outfit/job/bearcat/captain - name = BEARCAT_OUTFIT_JOB_NAME("FTU Captain") - uniform = /obj/item/clothing/under/casual_pants/classicjeans +/decl/outfit/job/bearcat/captain + name = "Bearcat - Job - FTU Captain" + uniform = /obj/item/clothing/pants/baggy/casual/classicjeans shoes = /obj/item/clothing/shoes/color/black pda_type = /obj/item/modular_computer/pda/heads/captain id_type = /obj/item/card/id/bearcat_captain -/decl/hierarchy/outfit/job/bearcat/captain/post_equip(var/mob/living/carbon/human/H) +/decl/outfit/job/bearcat/captain/post_equip(var/mob/living/wearer) ..() - var/obj/item/clothing/uniform = H.w_uniform + var/obj/item/clothing/uniform = wearer.get_equipped_item(slot_w_uniform_str) if(uniform) - var/obj/item/clothing/accessory/toggleable/hawaii/random/eyegore = new() + var/obj/item/clothing/shirt/hawaii/random/eyegore = new() if(uniform.can_attach_accessory(eyegore)) uniform.attach_accessory(null, eyegore) else qdel(eyegore) -#undef BEARCAT_OUTFIT_JOB_NAME - -/obj/effect/submap_landmark/spawnpoint/captain +/obj/abstract/submap_landmark/spawnpoint/captain name = "Independant Captain" -/obj/effect/submap_landmark/spawnpoint/crewman +/obj/abstract/submap_landmark/spawnpoint/crewman name = "Independant Crewman" diff --git a/maps/away/casino/casino.dm b/maps/away/casino/casino.dm index 31458f86ffcc..466a76e86667 100644 --- a/maps/away/casino/casino.dm +++ b/maps/away/casino/casino.dm @@ -15,10 +15,10 @@ "nav_casino_3", "nav_casino_4", "nav_casino_antag", - "nav_casino_hangar", + "nav_casino_dock", ) initial_restricted_waypoints = list( - "Casino Cutter" = list("nav_casino_hangar"), + /datum/shuttle/autodock/overmap/casino_cutter = list("nav_casino_hangar"), ) /obj/effect/overmap/visitable/ship/casino/Initialize() @@ -27,12 +27,12 @@ /datum/map_template/ruin/away_site/casino name = "Casino" - id = "awaysite_casino" description = "A casino ship!" suffixes = list("casino/casino.dmm") cost = 1 shuttles_to_initialise = list(/datum/shuttle/autodock/overmap/casino_cutter) area_usage_test_exempted_root_areas = list(/area/casino) + template_flags = TEMPLATE_FLAG_TEST_DUPLICATES apc_test_exempt_areas = list( /area/casino/casino_hangar = NO_SCRUBBER, /area/casino/casino_cutter = NO_SCRUBBER|NO_VENT, @@ -60,6 +60,11 @@ name = "Casino Ship Navpoint #5" landmark_tag = "nav_casino_antag" + +/obj/effect/shuttle_landmark/nav_casino/dock + name = "Casino Ship Docking Port" + landmark_tag = "nav_casino_dock" + /datum/shuttle/autodock/overmap/casino_cutter name = "Casino Cutter" warmup_time = 15 @@ -75,7 +80,7 @@ name = "Casino Hangar" landmark_tag = "nav_casino_hangar" base_area = /area/casino/casino_hangar - base_turf = /turf/simulated/floor/plating + base_turf = /turf/floor/plating /obj/effect/shuttle_landmark/nav_casino/cutter_transit name = "In transit" @@ -90,48 +95,58 @@ desc = "Spin the roulette to try your luck." icon = 'maps/away/casino/casino_sprites.dmi' icon_state = "roulette_r" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE var/busy=0 /obj/structure/casino/roulette/attack_hand(mob/user) - if (busy) - to_chat(user,"You cannot spin now! \The [src] is already spinning. ") - return - visible_message("\ [user] spins the roulette and throws inside little ball.") - busy = 1 + + if(user.check_intent(I_FLAG_HARM) || !user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + + if(busy) + to_chat(user, SPAN_WARNING("\The [src] is already spinning.")) + return TRUE + + visible_message(SPAN_NOTICE("\The [user] spins \the [src] and tosses the ball inside.")) + busy = TRUE var/n = rand(0,36) - var/color = "green" + var/result_color = "green" add_fingerprint(user) if ((n>0 && n<11) || (n>18 && n<29)) if (n%2) - color="red" + result_color="red" else - color="black" + result_color="black" if ( (n>10 && n<19) || (n>28) ) if (n%2) - color="black" + result_color="black" else - color="red" - spawn(5 SECONDS) - visible_message("\The [src] stops spinning, the ball landing on [n], [color].") - busy=0 + result_color="red" + announce_result(n, result_color) + return TRUE + +/obj/structure/casino/roulette/proc/announce_result(n, result_color) + set waitfor = FALSE + sleep(5 SECONDS) + visible_message("\The [src] stops spinning, the ball landing on [n], [result_color].") + busy = FALSE /obj/structure/casino/roulette_chart name = "roulette chart" desc = "Roulette chart. Place your bets! " icon = 'maps/away/casino/casino_sprites.dmi' icon_state = "roulette_l" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE /obj/structure/casino/bj_table name = "blackjack table" desc = "This is a blackjack table. " icon = 'maps/away/casino/casino_sprites.dmi' icon_state = "bj_left" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE /obj/structure/casino/bj_table/bj_right icon_state = "bj_right" @@ -141,16 +156,16 @@ desc = "Turned off slot machine. " icon = 'maps/away/casino/casino_sprites.dmi' icon_state = "slot_machine" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE /obj/structure/casino/craps name = "craps table" desc = "Craps table: roll dice!" icon = 'maps/away/casino/casino_sprites.dmi' icon_state = "craps_top" - density = 0 - anchored = 1 + density = FALSE + anchored = TRUE /obj/structure/casino/craps/craps_down icon_state = "craps_down" diff --git a/maps/away/casino/casino.dmm b/maps/away/casino/casino.dmm index 7bbe28ecd46f..64901cc1070a 100644 --- a/maps/away/casino/casino.dmm +++ b/maps/away/casino/casino.dmm @@ -63,9 +63,7 @@ teleport_z = 6; teleport_z_offset = 6 }, -/turf/space{ - icon_state = "black" - }, +/turf/space/black, /area/space) "ah" = ( /obj/effect/step_trigger/thrower{ @@ -85,7 +83,6 @@ "aj" = ( /obj/effect/step_trigger/thrower{ affect_ghosts = 1; - direction = 2; name = "thrower_throwdownside"; nostop = 1; stopper = 0; @@ -99,125 +96,114 @@ /area/space) "al" = ( /turf/space, -/turf/simulated/shuttle/wall/corner/dark/nw, +/turf/wall/shuttle/dark{ + unique_merge_identifier = "casino_bridge" + }, /area/casino/casino_bridge) "am" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_bridge) "an" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; id_tag = "casino_bridge"; - name = "Casino Bridge Blast Doors"; - opacity = 0 + name = "Casino Bridge Blast Doors" }, -/turf/simulated/floor/plating, -/area/casino/casino_bridge) -"ao" = ( -/turf/space, -/turf/simulated/shuttle/wall/corner/dark/ne, +/turf/floor/plating, /area/casino/casino_bridge) "ap" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aq" = ( /obj/machinery/computer/ship/engines, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "ar" = ( /obj/machinery/computer/ship/helm, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "as" = ( /obj/machinery/computer/ship/sensors, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "at" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "casino_bridge"; - name = "Casino Bridge Blast Doors"; - opacity = 0 + name = "Casino Bridge Blast Doors" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bridge) "au" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "av" = ( /obj/structure/table/steel_reinforced, /obj/random/handgun, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aw" = ( /obj/item/wirecutters, -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/space) "ax" = ( /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "ay" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aA" = ( /obj/machinery/computer/modular{ dir = 8; name = "Gambling console" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aB" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_maintenance) "aC" = ( /obj/machinery/door/firedoor, /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aD" = ( /obj/machinery/door/airlock/external{ - icon_state = "door_closed"; id_tag = "casino_dock_outer"; - locked = 0; name = "Docking Port Airlock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aE" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aF" = ( -/obj/structure/bed/chair{ - dir = 4; - +/obj/structure/chair{ + dir = 4 }, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aH" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, /obj/machinery/airlock_sensor{ id_tag = "casino_dock_sensor"; @@ -226,53 +212,51 @@ }, /obj/item/multitool, /obj/item/plastique, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aI" = ( /obj/effect/floor_decal/industrial/warning{ dir = 5 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; - id_tag = "admin_shuttle_dock_pump" + id_tag = "casino_dock_airlock" }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aJ" = ( /obj/structure/table/steel_reinforced, /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aL" = ( /obj/structure/table/steel_reinforced, /obj/item/radio, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aM" = ( /obj/machinery/computer/modular{ dir = 8; name = "Security console" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aN" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 4; - id_tag = "admin_shuttle_dock_pump" + id_tag = "casino_dock_airlock" }, /obj/effect/floor_decal/industrial/warning{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aO" = ( /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4; - icon_state = "map" + dir = 4 }, /obj/machinery/light/small{ dir = 4 @@ -280,69 +264,64 @@ /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aT" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aU" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/machinery/door/airlock/external{ - icon_state = "door_closed"; id_tag = "casino_dock_inner"; - locked = 0; name = "Docking Port Airlock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "aV" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/button/blast_door{ id_tag = "casino_weaponry"; name = "Weaponry Blast Door contol"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, /obj/structure/flora/pottedplant/unusual, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "aW" = ( /obj/machinery/button/blast_door{ id_tag = "casino_bridge"; name = "Casino Bridge Blast Door contol"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "ba" = ( /obj/structure/closet/emcloset, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "bb" = ( /obj/structure/lattice, @@ -368,20 +347,18 @@ dir = 4 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/casino/casino_maintenance) "bd" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/effect/decal/cleanable/blood/drip, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4; - icon_state = "map" + dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/casino/casino_maintenance) "be" = ( /obj/machinery/door/firedoor, @@ -389,12 +366,10 @@ name = "Casino Bridge" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bridge) "bf" = ( /obj/machinery/door/firedoor, @@ -402,19 +377,19 @@ name = "Casino Bridge" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bridge) "bh" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/casino/casino_maintenance) "bi" = ( /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/casino/casino_maintenance) "bj" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/pistol{ pixel_x = 4; pixel_y = 4 @@ -424,69 +399,69 @@ pixel_y = 2 }, /obj/item/gun/projectile/pistol, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bk" = ( /obj/machinery/door/blast/regular{ id_tag = "casino_weaponry" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bn" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bo" = ( /obj/machinery/floodlight, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/casino/casino_maintenance) "bq" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_security) "br" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_hangar) "bs" = ( /turf/space, -/turf/simulated/shuttle/wall/corner/dark/ne, +/turf/wall/shuttle/dark{ + unique_merge_identifier = "casino_bridge" + }, /area/casino/casino_hangar) "bt" = ( /obj/effect/shuttle_landmark/nav_casino/nav3, /turf/space, /area/space) "bu" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/knife/combat, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -495,14 +470,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bz" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -510,7 +482,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bA" = ( /obj/item/trash/cigbutt/professionals{ @@ -518,10 +490,7 @@ pixel_y = -5 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -529,15 +498,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bB" = ( /obj/item/trash/cigbutt/professionals, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -545,17 +511,14 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bC" = ( /obj/machinery/light/small{ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -563,30 +526,24 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bD" = ( /obj/item/shard, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bE" = ( /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/blood/drip, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -594,15 +551,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bF" = ( /obj/effect/decal/cleanable/blood/drip, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -610,7 +564,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bG" = ( /obj/machinery/door/airlock{ @@ -618,10 +572,7 @@ }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -629,17 +580,14 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "bI" = ( /obj/structure/fireaxecabinet{ pixel_y = 30 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 @@ -647,7 +595,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "bJ" = ( /obj/machinery/light{ @@ -662,7 +610,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "bK" = ( /obj/structure/reagent_dispensers/peppertank{ @@ -674,7 +622,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "bL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -686,7 +634,7 @@ /obj/machinery/alarm{ pixel_y = 25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "bM" = ( /obj/machinery/door/airlock{ @@ -700,7 +648,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "bN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -709,7 +657,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "bO" = ( /obj/machinery/light{ @@ -721,7 +669,7 @@ dir = 8; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "bP" = ( /obj/machinery/button/blast_door{ @@ -737,140 +685,137 @@ pixel_y = 25 }, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "bQ" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/plating, +/obj/structure/chair, +/turf/floor/plating, /area/casino/casino_security) "bR" = ( /obj/machinery/alarm{ pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "bS" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "bT" = ( /obj/machinery/atmospherics/unary/tank/nitrogen, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "bU" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bV" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bW" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "bZ" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_maintenance) "ca" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_crew_bunk) "cb" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_crew_bunk) "cc" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cd" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "ce" = ( /obj/structure/cable{ icon_state = "4-9" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cf" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/flora/pottedplant/unusual, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cg" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "ch" = ( -/obj/structure/table/rack, -/turf/simulated/floor/plating, +/obj/structure/rack, +/turf/floor/plating, /area/casino/casino_security) "ci" = ( /obj/structure/table/steel_reinforced, /obj/item/wrench, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "cj" = ( /obj/structure/table/steel_reinforced, /obj/item/radio, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "ck" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "cl" = ( /obj/machinery/atmospherics/binary/pump/high_power, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "cm" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "cn" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/tank/nitrogen, /obj/item/tank/nitrogen, /obj/item/tank/nitrogen, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "co" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_crew_bathroom) "cp" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_crew_bathroom) "cq" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "cr" = ( /obj/structure/bed, /obj/random/plushie, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cs" = ( /obj/structure/closet, @@ -878,11 +823,9 @@ /obj/random/glasses, /obj/random/shoes, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "ct" = ( /obj/machinery/light{ @@ -891,12 +834,9 @@ /obj/structure/bed, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cu" = ( /obj/machinery/vending/wallmed1{ @@ -905,35 +845,26 @@ /obj/structure/closet, /obj/random/smokes, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cv" = ( /obj/structure/bed, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cw" = ( /obj/structure/closet, /obj/random/accessory, /obj/random/drinkbottle, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cx" = ( /obj/machinery/light{ @@ -942,25 +873,21 @@ /obj/structure/closet, /obj/random/junk, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cy" = ( /obj/structure/bed, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cz" = ( /obj/structure/table/steel_reinforced, @@ -970,47 +897,45 @@ level = 2 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cA" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cB" = ( /obj/structure/table/steel_reinforced, /obj/item/radio, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cC" = ( /obj/machinery/computer/modular{ dir = 8; name = "Gambling console" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cD" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ - icon_state = "pdoor0"; id_tag = "casino_shuttle_control" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cE" = ( /obj/machinery/atmospherics/pipe/simple/visible/green, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_security) "cF" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "cH" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "cI" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 @@ -1018,14 +943,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "cJ" = ( /obj/machinery/door/firedoor, @@ -1033,10 +957,7 @@ name = "Crew toilet" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1044,31 +965,30 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bathroom) "cL" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cM" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - dir = 2; icon_state = "1-10" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cN" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cO" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cP" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "cQ" = ( /obj/structure/table/steel_reinforced, @@ -1076,15 +996,14 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cS" = ( -/obj/structure/bed/chair{ - dir = 4; - +/obj/structure/chair{ + dir = 4 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cT" = ( /obj/machinery/light{ @@ -1092,22 +1011,22 @@ icon_state = "tube1" }, /obj/machinery/computer/modular{ - name = "Cameras console"; + dir = 8; icon_state = "console"; - dir = 8 + name = "Cameras console" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "cU" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "cV" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "cW" = ( /obj/effect/floor_decal/industrial/warning, @@ -1116,11 +1035,9 @@ external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; - pressure_checks = 1; - pressure_checks_default = 1; use_power = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "cX" = ( /obj/machinery/door/blast/regular{ @@ -1128,7 +1045,7 @@ id_tag = "casino_hangar"; name = "Hangar gate" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_hangar) "cY" = ( /obj/structure/lattice, @@ -1139,7 +1056,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "db" = ( /obj/machinery/door/firedoor, @@ -1147,10 +1064,7 @@ name = "Crew bunk room" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1158,15 +1072,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_maintenance) "dc" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "dd" = ( /obj/structure/closet, @@ -1174,85 +1086,79 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "de" = ( /obj/machinery/light, /obj/structure/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "df" = ( /obj/structure/closet, /obj/random/junk, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "dg" = ( /obj/structure/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "dh" = ( /obj/structure/bed, /obj/random/plushie, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "di" = ( /obj/machinery/light, /obj/structure/closet, /obj/random/action_figure, /obj/random/shoes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "dj" = ( /obj/machinery/vending/security{ req_access = list() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dm" = ( /obj/machinery/computer/modular{ dir = 8; name = "Security console" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dn" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "do" = ( -/turf/simulated/shuttle/wall, -/area/casino/casino_cutter) -"dp" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_straight"; - dir = 4 +/turf/wall/shuttle{ + unique_merge_identifier = "casino_cutter" }, /area/casino/casino_cutter) "dq" = ( -/obj/structure/fuel_port, -/turf/simulated/shuttle/wall{ - dir = 8; - icon_state = "swall" +/obj/structure/fuel_port/hydrogen, +/turf/wall/shuttle{ + unique_merge_identifier = "casino_cutter" }, /area/casino/casino_cutter) "dr" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "ds" = ( /obj/machinery/power/tracker, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "dt" = ( /obj/structure/hygiene/toilet{ @@ -1260,55 +1166,54 @@ }, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/item/knife/folding, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "du" = ( /obj/machinery/door/airlock{ name = "Crew toilet" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "dx" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_storage) "dy" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_storage) "dz" = ( /obj/random/ammo, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dA" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/shotgun/pump, /obj/item/gun/projectile/shotgun/pump, /obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dB" = ( -/obj/structure/table/rack, -/obj/item/storage/box/ammo/shotgunammo, -/obj/item/storage/box/ammo/shotgunammo, -/obj/item/storage/box/ammo/shotgunammo, -/turf/simulated/floor/tiled, +/obj/structure/rack, +/obj/item/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunammo, +/turf/floor/tiled, /area/casino/casino_security) "dC" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/suit/armor/vest, /obj/item/clothing/suit/armor/vest, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dD" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/voidsuit, /obj/random/voidhelmet, /obj/item/tank/air, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dE" = ( /obj/effect/floor_decal/industrial/warning{ @@ -1317,14 +1222,14 @@ /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "dF" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_cutter) "dG" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/door/window, @@ -1332,145 +1237,139 @@ /obj/machinery/embedded_controller/radio/airlock/docking_port{ pixel_y = 25 }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dH" = ( /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dI" = ( -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dJ" = ( /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dK" = ( /obj/structure/shuttle/engine/propulsion{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_cutter) "dL" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "dM" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "dN" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/bj_table, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "dO" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/bj_table/bj_right, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "dP" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "dQ" = ( -/obj/structure/table/woodentable, -/obj/item/storage/fancy/cigar{ +/obj/structure/table/laminate, +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/obj/item/storage/fancy/cigar{ +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/obj/item/storage/fancy/cigar{ +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/obj/item/storage/fancy/cigar{ +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/obj/item/storage/fancy/cigar{ +/obj/item/box/fancy/cigar{ pixel_y = 5 }, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "dR" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/plating, +/obj/structure/chair, +/turf/floor/plating, /area/casino/casino_storage) "dS" = ( -/obj/structure/table/woodentable, -/obj/item/storage/toolbox/mechanical, +/obj/structure/table/laminate, +/obj/item/toolbox/mechanical, /obj/item/stack/cable_coil, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "dT" = ( -/obj/structure/bed/chair/office/light, -/turf/simulated/floor/plating, +/obj/structure/chair/office/light, +/turf/floor/plating, /area/casino/casino_storage) "dU" = ( /obj/item/clothing/suit/armor/vest, /obj/random/ammo, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "dW" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dX" = ( -/obj/item/storage/backpack/dufflebag, +/obj/item/backpack/dufflebag, /obj/random/cash, /obj/random/cash, /obj/random/cash, /obj/random/cash, /obj/random/cash, -/obj/structure/bed/chair/comfy/captain{ +/obj/structure/chair/comfy/captain{ dir = 1 }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dY" = ( -/obj/structure/bed/chair/comfy/captain{ +/obj/structure/chair/comfy/captain{ dir = 1 }, -/obj/item/storage/bag/cash, -/turf/simulated/floor/shuttle/yellow, +/obj/item/bag/cash, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "dZ" = ( -/obj/structure/bed/chair/comfy/captain{ +/obj/structure/chair/comfy/captain{ dir = 1 }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "ea" = ( /obj/structure/window/reinforced{ dir = 4 }, -/obj/structure/bed/chair/comfy/captain{ +/obj/structure/chair/comfy/captain{ dir = 1 }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "eb" = ( /obj/effect/overmap/visitable/ship/casino, @@ -1478,88 +1377,79 @@ /area/space) "ec" = ( /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ed" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ee" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "ef" = ( /obj/structure/curtain/open/shower, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "eg" = ( /obj/random/trash, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "eh" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/roulette_chart, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "ei" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/roulette, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "ej" = ( /obj/item/stock_parts/circuitboard/broken, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "ek" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "el" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "em" = ( /obj/random/ammo, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "en" = ( /obj/structure/safe, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "eo" = ( /obj/effect/shuttle_landmark/nav_casino/cutter_hangar, @@ -1568,242 +1458,200 @@ name = "cutter door" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/shuttle/blue, -/area/casino/casino_cutter) -"ep" = ( -/turf/simulated/shuttle/wall{ - dir = 8; - icon_state = "swall" - }, +/turf/floor/shuttle/blue, /area/casino/casino_cutter) "eq" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "er" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "es" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "et" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eu" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ev" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ew" = ( /obj/structure/reagent_dispensers/beerkeg, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "ex" = ( /obj/structure/casino/oh_bandit, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "ey" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "ez" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eA" = ( /obj/item/multitool, /obj/item/wirecutters, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "eB" = ( /obj/machinery/door/airlock/highsecurity{ name = "Safe area" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "eC" = ( /obj/random/coin, /obj/random/cash, /obj/random/ammo, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "eD" = ( /obj/random/coin, /obj/random/ammo, /obj/random/ammo, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "eE" = ( /obj/random/coin, /obj/random/coin, -/obj/item/storage/bag/cash, +/obj/item/bag/cash, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "eF" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "eG" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "eH" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "eI" = ( /obj/structure/cable/yellow, /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eJ" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "eK" = ( /obj/structure/reagent_dispensers/watertank, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "eL" = ( /obj/machinery/vending/assist, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "eM" = ( /obj/machinery/vending/engineering{ req_access = list() }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "eN" = ( /obj/machinery/light/small{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "eO" = ( /obj/machinery/constructable_frame/machine_frame, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eP" = ( /obj/machinery/light, /obj/machinery/vending/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eQ" = ( /obj/structure/table/steel_reinforced, /obj/random/tech_supply, /obj/random/tech_supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eR" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/toolbox/electrical, -/turf/simulated/floor/plating, +/obj/item/toolbox/electrical, +/turf/floor/plating, /area/casino/casino_storage) "eS" = ( /obj/structure/table/steel_reinforced, @@ -1812,7 +1660,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eT" = ( /obj/structure/table/steel_reinforced, @@ -1824,14 +1672,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eU" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 @@ -1839,64 +1686,52 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_storage) "eV" = ( /obj/random/cash, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "eW" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "eX" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "eY" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "eZ" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "fa" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "fb" = ( /obj/structure/closet/emcloset, @@ -1904,31 +1739,30 @@ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_hangar) "fc" = ( /obj/machinery/floodlight, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fd" = ( /obj/structure/reagent_dispensers/beerkeg, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fe" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/structure/cable, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "ff" = ( /obj/machinery/door/firedoor, @@ -1937,13 +1771,11 @@ }, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_maintenance) "fg" = ( /obj/machinery/door/airlock{ @@ -1951,7 +1783,7 @@ }, /obj/machinery/door/firedoor, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "fh" = ( /obj/machinery/door/firedoor, @@ -1959,23 +1791,18 @@ name = "Shuttle hangar" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "casino_checkpoint"; - name = "Casino Checkpoint Blast Doors"; - opacity = 0 + name = "Casino Checkpoint Blast Doors" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fi" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1984,7 +1811,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fk" = ( /obj/random/trash, @@ -1997,7 +1824,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fo" = ( /obj/machinery/door/airlock{ @@ -2005,15 +1832,15 @@ }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, /area/casino/casino_maintenance) "fq" = ( /obj/random/coin, @@ -2022,10 +1849,7 @@ }, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -2033,7 +1857,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fr" = ( /obj/machinery/door/airlock{ @@ -2042,10 +1866,7 @@ /obj/machinery/door/firedoor, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -2053,36 +1874,28 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fu" = ( /obj/structure/table/steel_reinforced, /obj/machinery/door/window/brigdoor/eastleft, /obj/machinery/door/window/brigdoor/westleft, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/blast/regular{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "casino_checkpoint"; - name = "Casino Checkpoint Blast Doors"; - opacity = 0 + name = "Casino Checkpoint Blast Doors" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fv" = ( /obj/effect/decal/cleanable/blood/drip, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fw" = ( /obj/machinery/light{ @@ -2090,39 +1903,37 @@ icon_state = "tube1" }, /obj/structure/coatrack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fx" = ( /obj/random/loot, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "fy" = ( /obj/structure/casino/oh_bandit, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "fz" = ( /obj/structure/casino/oh_bandit, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "fA" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 8; - icon_state = "pdoor0"; id_tag = "casino_main" }, /obj/machinery/door/firedoor, -/turf/space, +/turf/floor/plating, /area/casino/casino_mainfloor) "fB" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fC" = ( /obj/structure/cable{ @@ -2130,11 +1941,11 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fD" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fE" = ( /obj/machinery/door/firedoor, @@ -2142,11 +1953,9 @@ name = "Kitchen" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_maintenance) "fF" = ( /obj/machinery/door/airlock{ @@ -2154,13 +1963,11 @@ }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fH" = ( /obj/structure/table/steel_reinforced, @@ -2172,138 +1979,135 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fI" = ( /obj/effect/decal/cleanable/blood/drip, /obj/item/ammo_casing/shotgun, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fJ" = ( /obj/item/shard, /obj/structure/coatrack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "fK" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "fL" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 1 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "fM" = ( /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/structure/cable/yellow, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "fN" = ( /obj/structure/mopbucket, /obj/item/mop, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fO" = ( /obj/item/chems/glass/bucket, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fP" = ( /obj/structure/closet/crate/trashcart, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "fQ" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_crew_cantina) "fR" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fS" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled, +/obj/item/utensil/fork, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fT" = ( /obj/machinery/light{ dir = 1 }, -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/item/plate, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fU" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fV" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/chems/food/drinks/milk/smallcarton, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/milk/smallcarton, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fW" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/item/trash/cigbutt/professionals, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fX" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/trash/plate, +/obj/item/plate, /obj/random/snack, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fY" = ( /obj/machinery/light{ dir = 1 }, -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "fZ" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "ga" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_mainfloor) "gb" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "gc" = ( /obj/structure/closet/emcloset, @@ -2314,85 +2118,82 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gd" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock{ name = "Casino" }, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "casino_checkpoint"; - name = "Casino Checkpoint Blast Doors"; - opacity = 0 + name = "Casino Checkpoint Blast Doors" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_security) "ge" = ( -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "gf" = ( /obj/structure/window/basic, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "gg" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_solar_control) "gh" = ( -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, /obj/random/material, /obj/random/material, /obj/random/material, /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "gi" = ( -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, /obj/random/tech_supply, /obj/item/stack/cable_coil, /obj/item/stack/cable_coil, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "gj" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gk" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gl" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gm" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/obj/item/chems/food/drinks/flask/shiny, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/flask/shiny, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gn" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gp" = ( /obj/random/ammo, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gq" = ( /obj/structure/safe, @@ -2410,7 +2211,7 @@ /obj/structure/fireaxecabinet{ pixel_y = 30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gr" = ( /obj/structure/safe, @@ -2426,7 +2227,7 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gs" = ( /obj/machinery/door/firedoor, @@ -2435,47 +2236,41 @@ id_tag = "casino_main"; name = "Main floor Blast Doors" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gt" = ( /obj/machinery/door/firedoor, /obj/structure/table/marble, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gu" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/clothing/mask/smokable/pipe, /obj/machinery/light{ dir = 1 }, /obj/item/ashtray, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "gv" = ( -/obj/structure/table/woodentable, -/obj/item/storage/fancy/cigar, -/obj/item/storage/fancy/cigar{ +/obj/structure/table/laminate, +/obj/item/box/fancy/cigar, +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "gw" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gx" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/button/access/exterior{ @@ -2485,7 +2280,7 @@ pixel_y = 24; req_access = newlist() }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gy" = ( /obj/machinery/door/airlock/external{ @@ -2495,11 +2290,9 @@ name = "External Access" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "gz" = ( /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ @@ -2509,7 +2302,8 @@ tag_airpump = "casino_solar_pump"; tag_chamber_sensor = "casino_solar_sensor"; tag_exterior_door = "casino_solar_outer"; - tag_interior_door = "casino_solar_inner" + tag_interior_door = "casino_solar_inner"; + dir = 8 }, /obj/machinery/airlock_sensor{ id_tag = "casino_solar_sensor"; @@ -2518,75 +2312,69 @@ }, /obj/effect/floor_decal/industrial/warning/full, /obj/machinery/oxygen_pump{ - pixel_x = 0; pixel_y = 32 }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; id_tag = "casino_solar_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "gA" = ( -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, /obj/item/stack/cable_coil, /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "gB" = ( /obj/effect/decal/cleanable/generic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "gC" = ( -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, /obj/random/tech_supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "gD" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gE" = ( /obj/item/trash/cigbutt/menthol, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "gG" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gH" = ( /obj/random/coin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gI" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gJ" = ( /obj/random/cash, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "gK" = ( /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar{ - id = "auxsolarsport"; name = "Port Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gL" = ( /obj/machinery/door/airlock/external{ @@ -2597,52 +2385,43 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "gM" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_solar_control) "gX" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, +/obj/structure/chair, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gY" = ( /obj/random/cash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "gZ" = ( /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ha" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "hb" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8; - icon_state = "map" + dir = 8 }, /obj/machinery/button/access/interior{ id_tag = "casino_solar_airlock"; @@ -2652,11 +2431,9 @@ req_access = newlist() }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hc" = ( /obj/machinery/portable_atmospherics/canister/air/airlock, @@ -2667,29 +2444,29 @@ dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hd" = ( -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, /obj/random/tech_supply, /obj/item/stack/cable_coil, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "hf" = ( /obj/machinery/door/window/southleft, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "hg" = ( /obj/machinery/door/firedoor, /obj/structure/table/marble, /obj/structure/flora/pottedplant/unusual, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "hi" = ( -/obj/item/storage/secure/briefcase/money, +/obj/item/secure_storage/briefcase/money, /obj/random/cash, /obj/random/cash, /obj/random/cash, @@ -2697,205 +2474,185 @@ /obj/random/cash, /obj/random/cash, /obj/random/cash, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hj" = ( /obj/random/ammo, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hk" = ( /obj/structure/cable/yellow, /obj/machinery/power/solar{ - id = "auxsolarsport"; name = "Port Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "hl" = ( /obj/structure/cable/yellow, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/atmospherics/binary/pump/on{ dir = 1; target_pressure = 200 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hm" = ( /obj/machinery/power/solar_control{ - id = "solar"; - name = "Solar Control"; - track = 0 + name = "Solar Control" }, /obj/effect/floor_decal/industrial/warning/corner{ dir = 4 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hn" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_kitchen) "hp" = ( /obj/structure/hygiene/sink/kitchen{ pixel_y = 30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hq" = ( /obj/machinery/cooker/cereal, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hr" = ( /obj/machinery/cooker/candy, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hs" = ( /obj/machinery/cooker/fryer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "ht" = ( /obj/machinery/cooker/oven, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hu" = ( /obj/machinery/cooker/grill, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hv" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hw" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hx" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock{ name = "Kitchen" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hy" = ( /obj/item/shard, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hz" = ( /obj/item/flash, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hA" = ( /obj/machinery/light, /obj/structure/flora/pottedplant, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hB" = ( /obj/item/trash/cigbutt/cigarbutt, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hC" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/roulette_chart, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hD" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/roulette, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hE" = ( /obj/structure/flora/pottedplant/unusual, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hF" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hG" = ( /obj/machinery/power/terminal, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hH" = ( /obj/random/trash, -/obj/structure/table/rack{ +/obj/structure/rack{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "hJ" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hK" = ( /obj/effect/decal/cleanable/flour, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hL" = ( /obj/structure/table/marble, /obj/machinery/microwave, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hM" = ( /obj/structure/coatrack, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hN" = ( /obj/effect/decal/cleanable/generic, -/turf/simulated/floor/carpet, -/area/casino/casino_mainfloor) -"hO" = ( -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hP" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "hR" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2905,24 +2662,17 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "hS" = ( /obj/machinery/light/small, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -2930,7 +2680,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "hT" = ( /obj/machinery/door/firedoor, @@ -2938,10 +2688,7 @@ name = "Kitchen" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -2949,81 +2696,76 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hV" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hW" = ( /obj/effect/decal/cleanable/egg_smudge, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hX" = ( /obj/structure/table/marble, /obj/machinery/reagentgrinder/juicer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "hY" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/coatrack, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "hZ" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ia" = ( -/obj/structure/table/woodentable, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/obj/item/plate, +/obj/item/utensil/fork, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ib" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ic" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "id" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ie" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/craps, /obj/random/coin, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "if" = ( /obj/random/smokes, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ig" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ih" = ( /obj/machinery/door/firedoor, @@ -3032,11 +2774,9 @@ name = "Solar control" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "ii" = ( /obj/machinery/door/firedoor, @@ -3044,21 +2784,18 @@ name = "Atmos control" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, /area/casino/casino_crew_atmos) "ij" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_crew_atmos) "ik" = ( /obj/effect/decal/cleanable/tomato_smudge, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3067,7 +2804,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "il" = ( /obj/structure/closet/secure_closet/freezer/fridge, @@ -3078,26 +2815,28 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/item/storage/fancy/egg_box, -/obj/item/storage/fancy/egg_box, -/obj/item/storage/fancy/egg_box, -/obj/item/chems/food/condiment/flour, -/obj/item/chems/food/condiment/sugar, -/turf/simulated/floor/tiled, +/obj/item/box/fancy/egg_box, +/obj/item/box/fancy/egg_box, +/obj/item/box/fancy/egg_box, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/yeast, +/obj/item/chems/condiment/sugar, +/turf/floor/tiled, /area/casino/casino_kitchen) "im" = ( /obj/structure/closet/secure_closet/freezer/fridge, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/obj/item/chems/food/condiment/sugar, -/obj/item/chems/food/snacks/sliceable/bread, -/turf/simulated/floor/tiled, +/obj/item/chems/condiment/sugar, +/obj/item/food/sliceable/bread, +/turf/floor/tiled, /area/casino/casino_kitchen) "in" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/chems/food/condiment/flour, -/turf/simulated/floor/tiled, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/yeast, +/turf/floor/tiled, /area/casino/casino_kitchen) "io" = ( /obj/structure/table/marble, @@ -3106,84 +2845,70 @@ icon_state = "tube1" }, /obj/machinery/chem_master/condimaster, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "ip" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 4 }, /obj/item/knife/combat, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "iq" = ( -/obj/structure/table/woodentable, -/obj/item/trash/plate, -/obj/item/chems/food/snacks/applepie, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/obj/item/plate, +/obj/item/food/applepie, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ir" = ( -/obj/structure/table/woodentable, -/obj/item/trash/plate, -/obj/item/chems/food/snacks/bigbiteburger, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/obj/item/plate, +/obj/item/food/bigbiteburger, +/turf/floor/carpet, /area/casino/casino_mainfloor) "is" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/craps/craps_down, /obj/item/dice, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "iu" = ( /obj/structure/flora/pottedplant, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "iv" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iw" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "ix" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iz" = ( /obj/structure/fireaxecabinet{ pixel_y = 30 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -3191,12 +2916,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iA" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3205,271 +2928,254 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iB" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "iC" = ( /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/structure/window/basic{ dir = 8 }, /obj/structure/closet/secure_closet/freezer/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/turf/floor/tiled/freezer, /area/casino/casino_kitchen) "iD" = ( /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/machinery/gibber, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/casino/casino_kitchen) "iE" = ( /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, -/obj/structure/kitchenspike, -/turf/simulated/floor/tiled/freezer, +/obj/structure/meat_hook, +/turf/floor/tiled/freezer, /area/casino/casino_kitchen) "iF" = ( /obj/machinery/vending/dinnerware, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "iG" = ( /obj/structure/table/marble, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/item/plate, +/turf/floor/tiled, /area/casino/casino_kitchen) "iH" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/closet/emcloset, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iI" = ( /obj/machinery/atmospherics/unary/tank/carbon_dioxide, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iJ" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/machinery/floodlight, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iK" = ( /obj/effect/floor_decal/industrial/warning{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iL" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iM" = ( /obj/structure/window/basic{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/casino/casino_kitchen) "iN" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/casino/casino_kitchen) "iO" = ( /obj/machinery/door/window/brigdoor/eastleft, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/casino/casino_kitchen) "iP" = ( /obj/effect/decal/cleanable/pie_smudge, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "iQ" = ( /obj/machinery/door/firedoor, /obj/structure/table/marble, -/obj/item/trash/tray, -/obj/item/chems/food/snacks/stew, -/turf/simulated/floor/tiled, +/obj/item/plate/tray, +/obj/item/chems/glass/bowl/mapped/stew, +/turf/floor/tiled, /area/casino/casino_kitchen) "iR" = ( -/obj/structure/table/woodentable, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/spoon, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/obj/item/plate, +/obj/item/utensil/spoon, +/turf/floor/carpet, /area/casino/casino_mainfloor) "iS" = ( /obj/machinery/light, /obj/structure/flora/pottedplant/unusual, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "iT" = ( /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "iU" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_crew_atmos) "iV" = ( /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iW" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iX" = ( /obj/machinery/atmospherics/omni/filter{ dir = 8 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iY" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/casino/casino_crew_atmos) "iZ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "ja" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/flora/pottedplant/unusual, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jb" = ( /obj/structure/synthesized_instrument/synthesizer/piano, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jc" = ( -/obj/structure/bed/chair/comfy/beige{ +/obj/structure/chair/comfy/beige{ dir = 8 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jd" = ( /obj/random/coin, /obj/random/ammo, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "je" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_crew_atmos) "jf" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jg" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jh" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/casino/casino_crew_atmos) "ji" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jj" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jk" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3478,7 +3184,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jl" = ( /obj/machinery/door/firedoor, @@ -3491,7 +3197,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jm" = ( /obj/machinery/light{ @@ -3503,7 +3209,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3512,7 +3218,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jo" = ( /obj/machinery/door/firedoor, @@ -3525,7 +3231,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3534,7 +3240,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jq" = ( /obj/structure/hygiene/sink/kitchen{ @@ -3544,25 +3250,25 @@ dir = 8; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jr" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "js" = ( /obj/machinery/alarm{ pixel_y = 25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jt" = ( /obj/machinery/vending/boozeomat{ req_access = list() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "ju" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -3570,14 +3276,13 @@ icon_state = "map_injector"; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "jv" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_crew_atmos) "jw" = ( /obj/machinery/atmospherics/unary/tank/air{ @@ -3587,70 +3292,65 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jx" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/cyan, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jy" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jA" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jB" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jC" = ( /obj/item/broken_bottle, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jD" = ( /obj/machinery/vending/coffee, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jE" = ( /obj/structure/table/marble, -/obj/item/chems/food/drinks/bottle/absinthe, -/obj/item/chems/food/drinks/shaker{ +/obj/item/chems/drinks/bottle/absinthe, +/obj/item/chems/drinks/shaker{ pixel_x = 10; pixel_y = 10 }, @@ -3663,114 +3363,111 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jF" = ( /obj/structure/table/marble, /obj/machinery/chemical_dispenser/bar_alc/full, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jG" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jH" = ( /obj/structure/table/marble, /obj/item/ashtray, -/obj/item/flame/lighter/zippo/random, -/turf/simulated/floor/tiled, +/obj/item/flame/fuelled/lighter/zippo/random, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jI" = ( /obj/item/stool/bar, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jJ" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/ashtray, -/obj/item/chems/food/snacks/cubancarp, -/turf/simulated/floor/carpet, +/obj/item/food/cubancarp, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jK" = ( /obj/item/ashtray, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jL" = ( /obj/machinery/atmospherics/unary/tank/air{ dir = 4; start_pressure = 740.5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jM" = ( /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ - dir = 4; - icon_state = "map" + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jN" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jO" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jP" = ( /obj/effect/decal/cleanable/generic, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jQ" = ( /obj/structure/table/marble, -/obj/item/storage/box/glass_extras/sticks, -/obj/item/storage/box/glass_extras/straws, -/obj/item/storage/box/glass_extras, -/obj/item/storage/box/glasses/pint, -/obj/item/storage/box/glasses/wine, +/obj/item/box/glass_extras/sticks, +/obj/item/box/glass_extras/straws, +/obj/item/box/glass_extras, +/obj/item/box/glasses/pint, +/obj/item/box/glasses/wine, /obj/item/radio, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "jR" = ( /obj/structure/table/marble, -/obj/item/chems/food/drinks/bottle/gin, -/obj/item/chems/food/drinks/bottle/tequilla{ +/obj/item/chems/drinks/bottle/gin, +/obj/item/chems/drinks/bottle/tequila{ pixel_x = -10 }, -/obj/item/chems/food/drinks/bottle/vodka{ +/obj/item/chems/drinks/bottle/vodka{ pixel_x = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jS" = ( /obj/structure/table/marble, /obj/machinery/chemical_dispenser/bar_soft/full, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jT" = ( /obj/structure/table/marble, /obj/random/coin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "jU" = ( -/obj/structure/table/woodentable, -/obj/item/trash/plate, -/obj/item/chems/food/snacks/waffles, -/obj/item/chems/food/drinks/cans/iced_tea, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/obj/item/plate, +/obj/item/food/waffles, +/obj/item/chems/drinks/cans/iced_tea, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jV" = ( /obj/structure/table/gamblingtable, @@ -3780,7 +3477,7 @@ pixel_y = -5 }, /obj/item/dice, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jW" = ( /obj/structure/table/gamblingtable, @@ -3790,45 +3487,43 @@ pixel_y = -5 }, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jX" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/bj_table/bj_right, /obj/item/clothing/mask/smokable/cigarette/cigar/havana, /obj/item/ashtray, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "jY" = ( /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "jZ" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "ka" = ( /obj/effect/decal/cleanable/generic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kb" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kc" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kd" = ( /obj/structure/table/marble, @@ -3839,63 +3534,63 @@ /obj/random/drinkbottle, /obj/random/drinkbottle, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "ke" = ( /obj/structure/reagent_dispensers/beerkeg, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "kf" = ( /obj/structure/table/marble, -/obj/item/chems/food/drinks/bottle/rum, -/obj/item/chems/glass/rag, +/obj/item/chems/drinks/bottle/rum, +/obj/item/chems/rag, /obj/random/drinkbottle, /obj/random/drinkbottle, /obj/random/drinkbottle, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "kg" = ( /obj/item/trash/cigbutt/professionals, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "kh" = ( /obj/structure/table/marble, -/obj/item/chems/food/drinks/bottle/cognac, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/bottle/cognac, +/turf/floor/tiled, /area/casino/casino_mainfloor) "ki" = ( /obj/item/stool/bar, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kj" = ( /obj/item/broken_bottle, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kk" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/craps/craps_down, /obj/random/coin, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kl" = ( -/obj/structure/bed/chair/comfy/black{ +/obj/structure/chair/comfy/black{ dir = 1 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "km" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/wrench, /obj/item/clothing/head/welding, /obj/item/weldingtool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kn" = ( /obj/machinery/door/firedoor, @@ -3903,71 +3598,67 @@ name = "Kitchen" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "ko" = ( /obj/structure/table/marble, -/obj/item/chems/food/drinks/h_chocolate, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/h_chocolate, +/turf/floor/tiled, /area/casino/casino_mainfloor) "kp" = ( /obj/structure/table/marble, -/obj/item/storage/fancy/cigar{ +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "kq" = ( /obj/structure/table/marble, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "kr" = ( /obj/structure/table/marble, /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "ks" = ( /obj/structure/table/marble, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "kt" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/pizzabox/meat, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ku" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kv" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kw" = ( /obj/random/ammo, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kx" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "ky" = ( /obj/machinery/light{ @@ -3975,17 +3666,17 @@ }, /obj/random/ammo, /obj/structure/flora/pottedplant/overgrown, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kz" = ( /obj/structure/flora/pottedplant/overgrown, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kA" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/bj_table, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kB" = ( /obj/structure/table/gamblingtable, @@ -3995,36 +3686,33 @@ pixel_x = -2; pixel_y = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kC" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_bow) "kD" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kE" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/mask/gas, /obj/item/clothing/mask/gas, /obj/item/clothing/mask/gas, /obj/item/clothing/mask/gas, /obj/item/radio, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "kG" = ( /obj/random/ammo, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -4032,15 +3720,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kH" = ( /obj/random/loot, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -4048,15 +3733,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kI" = ( /obj/random/ammo, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -4064,14 +3746,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kJ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -4079,15 +3758,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kN" = ( /obj/machinery/light, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -4095,12 +3771,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kO" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4109,27 +3783,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) -"kP" = ( -/turf/simulated/floor/plating, -/area/casino/casino_crew_atmos) "kQ" = ( /obj/machinery/door/firedoor, /obj/structure/door/wood{ name = "VIP Private room" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_mainfloor) "kR" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_private_vip) "kS" = ( /obj/machinery/door/firedoor, @@ -4137,16 +3806,14 @@ name = "Private room 1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_mainfloor) "kT" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_private1) "kU" = ( /obj/machinery/door/firedoor, @@ -4154,254 +3821,209 @@ name = "Private room 2" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_mainfloor) "kV" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_private2) "kX" = ( /obj/structure/flora/pottedplant, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kY" = ( /obj/machinery/light, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "kZ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "la" = ( /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "lb" = ( -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/casino/casino_bow) "lc" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/casino/casino_bow) "ld" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, -/area/casino/casino_crew_atmos) -"le" = ( -/obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "lf" = ( /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "lg" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lh" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "li" = ( /obj/machinery/light{ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lj" = ( /obj/machinery/media/jukebox, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lk" = ( /obj/structure/flora/pottedplant, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "ll" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "lm" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "ln" = ( /obj/machinery/light{ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "lo" = ( /obj/structure/flora/pottedplant, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "lp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "lq" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "lr" = ( /obj/machinery/light{ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "ls" = ( /obj/structure/flora/pottedplant, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "lt" = ( /obj/machinery/door/firedoor, @@ -4409,29 +4031,24 @@ name = "Toilet room" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_mainfloor) "lu" = ( -/turf/simulated/wall, +/turf/wall, /area/casino/casino_patron_bathroom) "lv" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "lw" = ( /obj/structure/showcase{ @@ -4445,135 +4062,121 @@ name = "Containment Shield" }, /obj/structure/cable/green{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/casino/casino_bow) "lx" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/casino/casino_bow) "ly" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/casino/casino_bow) "lz" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/engineering{ - name = "Wormhole Generator"; - secured_wires = 0 + name = "Wormhole Generator" }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "lA" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "lB" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "lD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lE" = ( /obj/random/ammo, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lF" = ( /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lG" = ( /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lH" = ( /obj/item/trash/cigbutt/professionals, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lI" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lJ" = ( -/obj/item/storage/secure/safe{ +/obj/item/secure_storage/safe{ pixel_x = 30 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "lL" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "lM" = ( -/obj/item/storage/secure/safe{ +/obj/item/secure_storage/safe{ pixel_x = 30 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "lN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "lO" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "lP" = ( -/obj/item/storage/secure/safe{ +/obj/item/secure_storage/safe{ pixel_x = 25 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "lQ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "lR" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "lS" = ( /obj/machinery/door/airlock{ name = "Toilet #1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "lT" = ( /obj/structure/hygiene/toilet{ @@ -4584,225 +4187,214 @@ icon_state = "tube1" }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "lU" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "lV" = ( -/obj/structure/bed/chair/comfy/black, -/turf/simulated/floor/carpet, +/obj/structure/chair/comfy/black, +/turf/floor/carpet, /area/casino/casino_mainfloor) -"lW" = ( -/turf/simulated/floor/reinforced, -/area/casino/casino_bow) "lX" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock{ name = "Bow" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "lY" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "lZ" = ( -/obj/structure/table/woodentable, -/obj/item/storage/fancy/cigar{ +/obj/structure/table/laminate, +/obj/item/box/fancy/cigar{ pixel_y = 5 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "ma" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/ashtray, /obj/random/drinkbottle, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "mb" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "mc" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "md" = ( -/obj/structure/bed/chair/comfy/red, +/obj/structure/chair/comfy/red, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "me" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "mf" = ( -/obj/structure/bed/chair/comfy/red, -/obj/item/flame/lighter/zippo/random, +/obj/structure/chair/comfy/red, +/obj/item/flame/fuelled/lighter/zippo/random, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "mg" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "mi" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "mj" = ( -/obj/structure/table/woodentable, -/obj/item/chems/food/drinks/bottle/agedwhiskey, +/obj/structure/table/laminate, +/obj/item/chems/drinks/bottle/agedwhiskey, /obj/item/clothing/mask/smokable/cigarette/cigar/havana, /obj/item/clothing/mask/smokable/cigarette/cigar/havana, -/obj/item/flame/lighter/zippo/random, -/turf/simulated/floor/carpet, +/obj/item/flame/fuelled/lighter/zippo/random, +/turf/floor/carpet, /area/casino/casino_mainfloor) "mk" = ( /obj/machinery/computer/ship/engines{ - icon_state = "computer"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "ml" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mm" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mn" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mo" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mp" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 4 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "mq" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/drinkbottle, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "mr" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/turf/floor/laminate, /area/casino/casino_private_vip) "ms" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, -/obj/item/storage/bag/cash, -/turf/simulated/floor/wood, +/obj/item/bag/cash, +/turf/floor/laminate, /area/casino/casino_private_vip) "mt" = ( /obj/structure/bed, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private_vip) "mu" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/drinkbottle, /obj/random/coin, /obj/random/coin, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "mv" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "mw" = ( /obj/structure/bed, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private1) "mx" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/drinkbottle, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "my" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "mz" = ( /obj/structure/bed, /obj/random/coin, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/casino/casino_private2) "mB" = ( /obj/random/coin, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "mC" = ( /obj/machinery/door/airlock{ name = "Toilet #2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "mD" = ( /obj/structure/hygiene/toilet{ @@ -4812,13 +4404,14 @@ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "mE" = ( -/obj/structure/sign/warning/pods{ +/obj/structure/sign/directions/pods{ + dir = 1; pixel_y = -30 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "mF" = ( /obj/effect/shuttle_landmark/nav_casino/nav2, @@ -4828,41 +4421,40 @@ /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mH" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mI" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mJ" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mK" = ( /obj/structure/cable, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mL" = ( /obj/machinery/door/firedoor, @@ -4870,102 +4462,91 @@ name = "Bow" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_mainfloor) "mM" = ( /turf/space, -/turf/simulated/shuttle/wall/corner/dark/sw, +/turf/wall/shuttle/dark{ + unique_merge_identifier = "casino_bridge" + }, /area/casino/casino_bow) "mN" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mO" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mQ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mR" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mS" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, -/area/casino/casino_bow) -"mT" = ( -/turf/space, -/turf/simulated/shuttle/wall/corner/dark/se, +/turf/floor/plating, /area/casino/casino_bow) "mU" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mV" = ( /obj/machinery/atmospherics/binary/pump/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mW" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mX" = ( -/obj/structure/sign/warning/pods{ +/obj/structure/sign/directions/pods{ + dir = 1; pixel_y = -30 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mY" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/door/airlock{ name = "Engines #1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "mZ" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ - icon_state = "pdoor0"; id_tag = "Starboard wide window BD" }, -/turf/space, +/turf/floor/plating, /area/casino/casino_bow) "na" = ( /obj/machinery/door/airlock/external{ @@ -4974,55 +4555,55 @@ locked = 1; name = "Escape Pod" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "nb" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/door/airlock{ name = "Engines #2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "nc" = ( /obj/machinery/atmospherics/unary/tank/nitrogen{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "nd" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "ne" = ( -/obj/machinery/atmospherics/unary/heater{ +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "nf" = ( -/turf/simulated/shuttle/wall{ - icon_state = "wall3" +/turf/wall/shuttle{ + unique_merge_identifier = "casino_bridge" }, /area/casino/casino_bow) "ng" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 6 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/casino/casino_bow) "nh" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/black, /obj/machinery/meter, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/casino/casino_bow) "ni" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 10 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/casino/casino_bow) "nj" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/item/radio/intercom{ dir = 4; pixel_x = -22 @@ -5030,7 +4611,7 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "nk" = ( /obj/effect/shuttle_landmark/nav_casino/nav4, @@ -5040,55 +4621,57 @@ /obj/machinery/atmospherics/unary/engine{ dir = 1 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_bow) "nm" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/machinery/status_display{ pixel_x = -32; - pixel_y = 0 + dir = 8 }, /obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ id_tag = "Casino_escape_pod_3"; name = "Casino escape pod Three controller"; pixel_x = 24; - pixel_y = 0; - tag_door = "Casino escape_pod_3_hatch" + tag_door = "Casino escape_pod_3_hatch"; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "nn" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/machinery/status_display{ pixel_x = -32; - pixel_y = 0 + dir = 8 }, /obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ id_tag = "Casino_escape_pod_2"; name = "Casino escape pod Two controller"; pixel_x = 24; - pixel_y = 0; - tag_door = "Casino escape_pod_2_hatch" + tag_door = "Casino escape_pod_2_hatch"; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "no" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/machinery/status_display{ pixel_x = -32; - pixel_y = 0 + dir = 8 }, /obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ id_tag = "Casino_escape_pod_1"; name = "Casino escape pod One controller"; pixel_x = 24; - pixel_y = 0; - tag_door = "escape_pod_17_hatch" + tag_door = "escape_pod_casino_17_hatch"; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "np" = ( -/turf/simulated/shuttle/wall/corner/dark, +/turf/wall/shuttle/dark{ + unique_merge_identifier = "casino_bridge" + }, /area/casino/casino_bow) "nq" = ( /obj/structure/grille, @@ -5103,43 +4686,35 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/plating, -/area/casino/casino_bow) -"nr" = ( -/turf/simulated/shuttle/wall/corner/dark{ - dir = 6 - }, +/turf/floor/plating, /area/casino/casino_bow) "ns" = ( -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/casino/casino_bow) "ob" = ( /obj/structure/table/gamblingtable, /obj/structure/casino/roulette_chart, /obj/random/coin, /obj/random/coin, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "oc" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "pb" = ( /obj/item/ammo_casing/pistol/magnum/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "pc" = ( /obj/machinery/vending/wallmed1{ @@ -5148,16 +4723,14 @@ /obj/item/radio, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "qb" = ( /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "qc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5167,23 +4740,19 @@ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "rb" = ( /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "rc" = ( /obj/machinery/computer/arcade, @@ -5195,19 +4764,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "sb" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "sc" = ( /obj/structure/reagent_dispensers/water_cooler, @@ -5215,31 +4781,23 @@ dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "tb" = ( /obj/item/ammo_casing/rifle/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "tc" = ( /obj/machinery/vending/snack, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "ub" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/item/ammo_casing/rifle/used, @@ -5247,17 +4805,14 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "uc" = ( /obj/machinery/vending/fitness, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "vb" = ( /obj/effect/decal/cleanable/blood/splatter, @@ -5266,17 +4821,14 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "vc" = ( /obj/machinery/vending/cola, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "wb" = ( /obj/item/ammo_casing/rifle/used, @@ -5291,25 +4843,19 @@ dir = 1; pixel_y = -25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "wc" = ( /obj/machinery/vending/coffee, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "xb" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, @@ -5319,31 +4865,25 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "xc" = ( /obj/machinery/vending/cigarette, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "yb" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/item/ammo_casing/pistol/magnum/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "yc" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "zb" = ( /obj/item/ammo_casing/rifle/used, @@ -5357,7 +4897,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_bunk) "zc" = ( /obj/machinery/door/firedoor, @@ -5365,31 +4905,26 @@ name = "Kitchen" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "Ab" = ( /obj/item/gun/projectile/pistol, /obj/item/ammo_casing/pistol/magnum/used, /obj/item/ammo_casing/pistol/magnum/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "Ac" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) "Bb" = ( /obj/item/shard, /obj/item/ammo_casing/pistol/magnum/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "Bc" = ( /obj/machinery/door/firedoor, @@ -5397,31 +4932,25 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_crew_cantina) "Cb" = ( /obj/item/ammo_casing/rifle/used, /obj/item/ammo_casing/rifle/used, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "Cc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "Db" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/item/ammo_casing/rifle/used, @@ -5429,32 +4958,28 @@ /obj/item/ammo_casing/rifle/used, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Dc" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "Eb" = ( /obj/effect/decal/cleanable/blood, /obj/item/gun/projectile/revolver, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/item/ammo_casing/pistol/magnum/used, /obj/item/ammo_casing/pistol/magnum/used, @@ -5465,26 +4990,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "Ec" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Fb" = ( -/obj/structure/bed/chair{ - dir = 4; - +/obj/structure/chair{ + dir = 4 }, /obj/effect/decal/cleanable/blood, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/item/ammo_casing/pistol/magnum/used, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5493,12 +5014,13 @@ /obj/machinery/button/blast_door{ id_tag = "casino_checkpoint"; name = "Casino Checkpoint Blast Door contol"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "Fc" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/casino/casino_mainfloor) "Gb" = ( /obj/item/ammo_casing/pistol/magnum/used, @@ -5507,7 +5029,7 @@ level = 2 }, /obj/structure/flora/pottedplant/unusual, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "Gc" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5517,20 +5039,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_kitchen) "Hb" = ( /obj/item/ammo_casing/rifle/used, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Hc" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, @@ -5538,44 +5056,37 @@ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "Ib" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "Ic" = ( /obj/structure/flora/pottedplant, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Jb" = ( /obj/machinery/power/smes/buildable{ - charge = 0; RCon_tag = "Solar - Starboard" }, /obj/effect/engine_setup/smes, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_solar_control) "Jc" = ( /obj/effect/decal/cleanable/blood/splatter, @@ -5586,24 +5097,20 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Kb" = ( /obj/machinery/computer/modular{ - name = "Cameras console"; + dir = 8; icon_state = "console"; - dir = 8 + name = "Cameras console" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_bridge) "Kc" = ( /obj/item/ammo_casing/rifle{ @@ -5611,10 +5118,7 @@ pixel_y = -8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -5622,7 +5126,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Lb" = ( /obj/structure/lattice, @@ -5635,10 +5139,7 @@ pixel_y = -2 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -5646,11 +5147,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Mb" = ( /obj/machinery/shipsensors, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/casino/casino_bridge) "Mc" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5660,37 +5161,28 @@ dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Nb" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Nc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/casino/casino_mainfloor) "Ob" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5702,23 +5194,21 @@ /obj/structure/cable{ icon_state = "4-9" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Oc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "Pb" = ( /obj/effect/decal/cleanable/blood/splatter, @@ -5729,47 +5219,43 @@ dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Pc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_crew_atmos) "Qb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Qc" = ( /obj/effect/decal/cleanable/blood/splatter, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) +"QL" = ( +/obj/effect/shuttle_landmark/nav_casino/dock, +/turf/space, +/area/space) "Rb" = ( /obj/machinery/light/small{ dir = 4 @@ -5781,28 +5267,21 @@ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Rc" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_bow) "Sb" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5812,33 +5291,29 @@ dir = 8 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Sc" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 10 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/casino/casino_bow) "Tb" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "Tc" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ @@ -5847,66 +5322,60 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/casino/casino_bow) +"TO" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/red, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, +/area/casino/casino_crew_atmos) "Ub" = ( /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, /obj/machinery/computer/shuttle_control/explore/casino_cutter{ dir = 1 }, -/turf/simulated/floor/shuttle/yellow, +/turf/floor/shuttle/yellow, /area/casino/casino_cutter) "Uc" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -25 }, /obj/random/soap, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_crew_bathroom) "Vb" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Vc" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -25 }, /obj/random/soap, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -5914,7 +5383,7 @@ level = 2 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "Wb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5924,48 +5393,37 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Wc" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -25 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/casino/casino_patron_bathroom) "Xb" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/casino/casino_maintenance) "Yb" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5975,22 +5433,15 @@ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_security) "Zb" = ( /obj/structure/cable, @@ -5998,17 +5449,16 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/casino/casino_mainfloor) (1,1,1) = {" @@ -9650,7 +9100,7 @@ kC kC lc lx -lW +lb kC kC aa @@ -9851,7 +9301,7 @@ jY jY ku kD -kP +jN ld lA kC @@ -9954,7 +9404,7 @@ jN kv kv jN -le +ld lA kC ml @@ -10047,7 +9497,7 @@ gM gg ix iI -iW +TO iV jy jN @@ -10056,7 +9506,7 @@ jN jN jN jN -le +ld lB kC Qc @@ -10158,7 +9608,7 @@ ka jN jN jN -le +ld lA kC mm @@ -10421,7 +9871,7 @@ aa aa aa aa -ao +al am at at @@ -11137,7 +10587,7 @@ aa aa aa aa -aa +QL aD aI aO @@ -11189,7 +10639,7 @@ kC nf nf nf -nr +np ns aa aa @@ -11597,7 +11047,7 @@ kC nf nf nf -nr +np ns aa aa @@ -12005,7 +11455,7 @@ kC nf nf nf -nr +np ns aa aa @@ -12184,17 +11634,17 @@ ge gJ Hb hz -hO +Ec ge ge hN ge -hO +Ec ge ge ge ge -hO +Ec hj kJ kV @@ -12373,10 +11823,10 @@ bP ci cD cV -dp +do dG Ub -dp +do eG eX bq @@ -12475,7 +11925,7 @@ bQ cj cD cV -dp +do dH dW eo @@ -12577,10 +12027,10 @@ bR ck cD cV -dp +do dI dX -dp +do eG eZ br @@ -12679,10 +12129,10 @@ bS cl cE cW -dp +do Tb dY -dp +do eG cF br @@ -12781,10 +12231,10 @@ bq bq bq cU -dp +do dI dZ -dp +do eG cF br @@ -12883,10 +12333,10 @@ bT cm cF cV -dp +do dJ ea -dp +do eG fa br @@ -12988,7 +12438,7 @@ cV dq dK dK -ep +do eG fa br @@ -13021,7 +12471,7 @@ mE kC mH kC -mT +mM aa aa aa @@ -13122,7 +12572,7 @@ mj kl kC kC -mT +mM aa aa aa @@ -13223,7 +12673,7 @@ fA fA fA kC -mT +mM aa aa aa diff --git a/maps/away/derelict/derelict-station.dmm b/maps/away/derelict/derelict-station.dmm index 94abf28e3afa..46a25943bbfc 100644 --- a/maps/away/derelict/derelict-station.dmm +++ b/maps/away/derelict/derelict-station.dmm @@ -3,146 +3,133 @@ /turf/space, /area/space) "ab" = ( -/turf/simulated/wall/voxshuttle, +/turf/wall/raidershuttle, /area/derelict/ship) "ac" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ad" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ae" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "af" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ag" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "ah" = ( /obj/machinery/sleeper/standard, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "ai" = ( /obj/item/cell, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aj" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ak" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "al" = ( /obj/structure/shuttle/engine/propulsion{ - icon_state = "burst_r"; - dir = 4 + dir = 4; + icon_state = "burst_r" }, /turf/space, /area/derelict/ship) "am" = ( /obj/machinery/computer/modular/preset/medical, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "an" = ( /obj/random/maintenance, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "ao" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "ap" = ( /obj/machinery/door/airlock/glass, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aq" = ( /obj/structure/shuttle/engine/heater{ - icon_state = "heater"; dir = 4 }, /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/derelict/ship) "ar" = ( /obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion"; dir = 4 }, /turf/space, /area/derelict/ship) "as" = ( /obj/item/scalpel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "at" = ( /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "au" = ( /obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "av" = ( /obj/structure/grille, @@ -153,7 +140,7 @@ dir = 1 }, /obj/structure/window/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aw" = ( /obj/structure/grille, @@ -161,7 +148,7 @@ dir = 1 }, /obj/structure/window/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ax" = ( /obj/structure/grille, @@ -172,80 +159,72 @@ dir = 4 }, /obj/structure/window/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ay" = ( /obj/machinery/door/airlock/glass{ name = "Hibernation Pods" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "az" = ( /obj/machinery/light{ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aA" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aB" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/cell, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aC" = ( /obj/item/multitool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aD" = ( /obj/item/cell{ charge = 100; maxcharge = 15000 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aE" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aF" = ( /obj/machinery/door/airlock/glass, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aG" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aH" = ( /obj/machinery/fabricator/pipe, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aI" = ( /obj/structure/shuttle/engine/propulsion{ - icon_state = "burst_l"; - dir = 4 + dir = 4; + icon_state = "burst_l" }, /turf/space, /area/derelict/ship) @@ -253,20 +232,18 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aK" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/maintenance, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aL" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aM" = ( /obj/structure/grille, @@ -279,33 +256,32 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aN" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aO" = ( /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aP" = ( /obj/machinery/light_switch{ - pixel_x = 27 + pixel_x = 27; + dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aQ" = ( /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aR" = ( /obj/structure/lattice, @@ -319,7 +295,7 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "aT" = ( /obj/structure/bed, @@ -327,37 +303,35 @@ /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aU" = ( /obj/machinery/light{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aV" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aW" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/maintenance) "aX" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/handgun, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "aY" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/derelict/ship) "aZ" = ( /obj/structure/grille, @@ -371,24 +345,25 @@ /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ba" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bb" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/tank/oxygen, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bc" = ( /obj/machinery/light_switch{ - pixel_x = 27 + pixel_x = 27; + dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bd" = ( /obj/structure/grille, @@ -402,71 +377,71 @@ dir = 4 }, /obj/structure/window/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "be" = ( /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bf" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bg" = ( /obj/random/closet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bh" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bi" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bj" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/scanner/gas, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bk" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bl" = ( /obj/machinery/door/airlock/glass, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/derelict/ship) "bm" = ( /obj/machinery/door/airlock/glass{ name = "Living Module" }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/derelict/ship) "bn" = ( /obj/random/hostile, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bo" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bp" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bq" = ( /obj/random/cash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "br" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bs" = ( /obj/structure/bed, @@ -474,73 +449,71 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bt" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bu" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bv" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/bridge) "bw" = ( /obj/structure/grille, /obj/machinery/door/blast/regular/open, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bx" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "by" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "bz" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bA" = ( /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bB" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/modular_computer/laptop, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "bC" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/drinkbottle, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bD" = ( -/obj/structure/table/standard, -/turf/simulated/floor/airless, +/obj/structure/table, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bE" = ( /obj/structure/table, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bF" = ( /turf/space, /area/constructionsite/maintenance) "bG" = ( /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bH" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/maintenance) "bI" = ( /obj/structure/grille, @@ -551,412 +524,377 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "bJ" = ( /obj/machinery/light_switch{ - pixel_x = 27 + pixel_x = 27; + dir = 8 }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bK" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "bL" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bM" = ( /obj/random/trash, /obj/structure/table, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "bN" = ( /obj/random/closet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "bO" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bP" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper{ info = "\\\[center]\\\[b]ATTN: Regarding Meteor Storms\\\[/b]\[/center]\\\[br]\\\[br]We've recently heard mutterings from the Atmospheric Technicians that the meteor showers in this sector are becoming too much. However, this should be disregarded.\\\[br]\\\[br] High Command has assured us that our shields can easily keep pace with any meteor storm and then some. Any uneasiness the crew may feel should be disspelled swiftly. Thank you."; name = "ATTN: Regarding Meteor Storms" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bQ" = ( /obj/structure/table, /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "bR" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/bridge) "bS" = ( /obj/random/hostile{ spawn_nothing_percentage = 60 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "bT" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, +/obj/structure/chair, +/turf/floor/tiled, /area/derelict/ship) "bU" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/tank/emergency/oxygen, /obj/item/tank/emergency/oxygen, /obj/item/tank/emergency/oxygen, /obj/item/tank/emergency/oxygen, /obj/random/tank, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bV" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/mask/breath, /obj/item/cell, /obj/random/hardsuit, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bW" = ( -/obj/structure/table/rack, -/obj/item/storage/toolbox/syndicate, +/obj/structure/rack, +/obj/item/toolbox/syndicate, /obj/random/maintenance, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "bX" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/machinery/power/apc/high/inactive{ +/obj/machinery/apc/high/inactive{ dir = 8; name = "west bump"; pixel_x = -24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "bY" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "bZ" = ( /obj/item/cell{ charge = 100; maxcharge = 15000 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ca" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cb" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cc" = ( /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/power/solar_control, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cd" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "ce" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "cf" = ( /obj/random/handgun, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "cg" = ( /obj/item/stack/cable_coil, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ch" = ( /obj/structure/cable/yellow, /obj/machinery/power/terminal, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "ci" = ( /obj/machinery/door/airlock/hatch, /obj/machinery/door/blast/regular/open, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "cj" = ( /obj/random/hostile{ spawn_nothing_percentage = 60 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "ck" = ( /obj/random/junk, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "cl" = ( /obj/machinery/door/airlock/hatch, /obj/machinery/door/blast/regular, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "cm" = ( /obj/random/closet, /obj/random/maintenance, /obj/random/maintenance, /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "cn" = ( -/turf/simulated/wall/voxshuttle, +/turf/wall/raidershuttle, /area/space) "co" = ( /obj/machinery/door/airlock/glass{ name = "Pod Bay" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "cp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cq" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cr" = ( /obj/machinery/power/smes/batteryrack, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cs" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "ct" = ( /obj/random/trash, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "cu" = ( /obj/random/closet, /obj/random/energy, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "cv" = ( /obj/structure/bookcase/manuals/engineering, /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cw" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cx" = ( /obj/structure/bookcase, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "cy" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "cz" = ( /obj/structure/bookcase/manuals/xenoarchaeology, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cA" = ( /obj/structure/bookcase, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cB" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "cC" = ( /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "cD" = ( /obj/structure/table/marble, /obj/random/coin, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cE" = ( /obj/structure/table/marble, /obj/machinery/microwave, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cF" = ( /obj/structure/table/marble, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cG" = ( -/turf/simulated/floor/tiled/white/airless, -/area/constructionsite/hallway/fore) -"cH" = ( -/obj/structure/table, -/turf/simulated/floor/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/hallway/fore) "cI" = ( /obj/structure/table, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/hallway/fore) "cJ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/screwdriver, /obj/machinery/light, /obj/random/maintenance, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "cK" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/radio/off, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/derelict/ship) "cL" = ( /obj/machinery/fabricator, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cM" = ( /obj/structure/bookcase, /obj/item/book/manual/excavation, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cN" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "cO" = ( /obj/structure/bookcase/manuals/xenoarchaeology, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "cP" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cQ" = ( /obj/structure/bookcase, /obj/item/book/manual/ripley_build_and_repair, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cR" = ( /obj/structure/noticeboard{ - pixel_x = 32 + default_pixel_x = 32 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/bridge) "cS" = ( /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cT" = ( /obj/structure/window/reinforced, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/power/tracker, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cU" = ( /obj/structure/window/reinforced, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cV" = ( /obj/structure/window/reinforced, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable/yellow, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cW" = ( /obj/structure/window/reinforced, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/derelict/ship) "cX" = ( /obj/machinery/fabricator/book, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "cY" = ( -/obj/structure/filingcabinet/filingcabinet, -/turf/simulated/floor/airless, +/obj/structure/filing_cabinet/tall, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "cZ" = ( /obj/machinery/door/airlock/glass/command{ name = "Bridge" }, /obj/machinery/door/blast/regular, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/bridge) "da" = ( /obj/structure/closet/secure_closet/freezer/fridge{ @@ -964,213 +902,193 @@ locked = 0 }, /obj/random/contraband, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "db" = ( /obj/structure/table/marble, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dc" = ( /obj/structure/table/marble, -/obj/item/kitchen/rollingpin, -/turf/simulated/floor/airless, -/area/constructionsite/hallway/fore) -"dd" = ( -/obj/structure/table, -/turf/simulated/floor/tiled/dark/airless, +/obj/item/rollingpin, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "de" = ( /obj/random/closet, /obj/random/voidhelmet, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "df" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dg" = ( /obj/structure/bookcase/manuals/medical, /obj/item/book/manual/nuclear, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "dh" = ( /obj/random/trash, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "di" = ( -/obj/structure/table/rack, -/turf/simulated/floor/airless, +/obj/structure/rack, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dj" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dk" = ( /obj/structure/table/marble, /obj/random/drinkbottle, /obj/random/drinkbottle, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dl" = ( /obj/structure/table/marble, /obj/random/gloves, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dm" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dn" = ( /obj/structure/table/marble, /obj/random/drinkbottle, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "do" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dp" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dq" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/hat, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dr" = ( /obj/random/junk, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/hallway/fore) "ds" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/dark/airless, +/obj/structure/table, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "dt" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/toy, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "du" = ( -/obj/structure/table/standard, -/turf/simulated/floor/airless, +/obj/structure/table, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dv" = ( /obj/structure/grille, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dw" = ( -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/constructionsite/hallway/fore) "dx" = ( /obj/random/junk, /obj/structure/table, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dy" = ( /obj/random/snack, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dz" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/hallway/fore) "dA" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dB" = ( /obj/machinery/door/airlock/glass{ name = "Library" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dC" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "dD" = ( /obj/structure/grille/broken, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "dE" = ( /obj/structure/grille, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "dF" = ( /obj/structure/sign/warning/secure_area, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/hallway/fore) "dG" = ( /obj/machinery/door/airlock/glass/command{ name = "Bridge" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "dH" = ( /obj/machinery/door/airlock/glass/command{ name = "Bridge" }, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/constructionsite/hallway/fore) "dI" = ( /obj/machinery/door/airlock/glass{ name = "Kitchen" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dJ" = ( /obj/structure/table/marble, /obj/machinery/door/blast/shutters, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "dK" = ( /obj/structure/table/marble, /obj/machinery/door/blast/shutters/open, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dL" = ( /obj/structure/table, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/fore) "dM" = ( /obj/structure/table, /obj/machinery/door/blast/shutters/open, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dN" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dO" = ( -/turf/simulated/wall, +/turf/wall, /area/space) "dP" = ( /obj/structure/grille/broken, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dQ" = ( /obj/random/smokes, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "dR" = ( /obj/structure/lattice, @@ -1178,16 +1096,16 @@ /area/constructionsite/hallway/fore) "dS" = ( /obj/random/snack, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "dT" = ( /obj/random/trash, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "dU" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "dV" = ( /obj/structure/lattice, @@ -1195,235 +1113,187 @@ /turf/space, /area/space) "dW" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "dX" = ( /obj/effect/shuttle_landmark/derelict/nav2, /turf/space, /area/space) "dY" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/storage) "dZ" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "ea" = ( /obj/structure/extinguisher_cabinet{ icon_state = "extinguisher_empty"; - pixel_x = 30 + pixel_x = 29; + dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "eb" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/teleporter) "ec" = ( /obj/machinery/mech_recharger, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "ed" = ( /obj/machinery/fabricator/industrial, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "ee" = ( -/obj/structure/table/standard, -/turf/simulated/floor/airless, +/obj/structure/table, +/turf/floor/plating/airless, /area/constructionsite/storage) "ef" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/material, /obj/random/material, /obj/random/coin, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eg" = ( /obj/structure/table, /obj/machinery/cell_charger, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, -/area/constructionsite/storage) -"eh" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless/broken, /area/constructionsite/storage) "ei" = ( /obj/structure/table, /obj/random/medical, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "ej" = ( /obj/machinery/shieldgen, /obj/structure/window/basic{ - icon_state = "window"; dir = 8 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "ek" = ( /obj/machinery/shieldgen, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "el" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/structure/window/basic{ - icon_state = "window"; dir = 8 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "em" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "en" = ( /obj/structure/table/reinforced, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 0; - pixel_y = 0 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 0; - pixel_y = 0 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 0; - pixel_y = 0 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 0; - pixel_y = 0 - }, -/obj/item/stack/material/steel{ - amount = 50; - pixel_x = 0; - pixel_y = 0 + dir = 1; + icon_state = "tube1" }, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, /obj/random/tech_supply, /obj/random/maintenance, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "ep" = ( /obj/structure/table/reinforced, -/obj/item/stack/material/plasteel{ - amount = 50 - }, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, /obj/random/tech_supply, /obj/random/maintenance, -/turf/simulated/floor/tiled/dark, -/area/constructionsite/teleporter) -"eq" = ( -/obj/structure/table/reinforced, -/obj/random/powercell, -/obj/random/tech_supply, -/obj/random/tech_supply, -/obj/random/maintenance, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "er" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "es" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/storage) "et" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 1 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/storage) "eu" = ( /obj/machinery/optable{ name = "Robotics Operating Table" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "ev" = ( /obj/random/closet, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "ew" = ( /obj/machinery/shieldgen, /obj/structure/window/basic{ - icon_state = "window"; dir = 8 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "ex" = ( /obj/machinery/shieldgen, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "ey" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/structure/window/basic{ - icon_state = "window"; dir = 8 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "ez" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eA" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eB" = ( /obj/structure/table/reinforced, @@ -1436,7 +1306,7 @@ /obj/random/voidsuit, /obj/random/voidhelmet, /obj/random/maintenance, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eC" = ( /obj/structure/table/reinforced, @@ -1444,37 +1314,35 @@ /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/maintenance, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eD" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eE" = ( /obj/machinery/door/airlock/glass/science{ name = "Robotics" }, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/storage) "eF" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eG" = ( -/obj/structure/sign/warning/science, -/turf/simulated/wall, +/obj/structure/sign/department/science_1, +/turf/wall, /area/constructionsite/hallway/fore) "eH" = ( /obj/machinery/button/access/exterior{ id_tag = "constructionsite_airlock"; pixel_x = 20; - pixel_y = 0; - req_access = newlist() + req_access = newlist(); + dir = 8 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "eI" = ( /obj/structure/sign/warning/vacuum{ @@ -1483,55 +1351,54 @@ /obj/machinery/button/access/interior{ id_tag = "constructionsite_airlock"; pixel_x = -20; - pixel_y = 0; - req_access = newlist() + req_access = newlist(); + dir = 4 }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 + dir = 1; + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eJ" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "eK" = ( /obj/structure/cable/blue{ - d2 = 2; icon_state = "0-2" }, -/obj/machinery/power/port_gen/pacman, +/obj/machinery/port_gen/pacman, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eL" = ( /obj/structure/skele_stand, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eM" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eN" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eO" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/storage) "eP" = ( /obj/machinery/door/airlock/glass/science{ name = "Research" }, /obj/machinery/door/blast/shutters, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eQ" = ( /obj/machinery/door/airlock/glass/science{ name = "Research" }, /obj/machinery/door/blast/shutters, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "eR" = ( /obj/machinery/door/airlock/external{ @@ -1539,17 +1406,17 @@ id_tag = "constructionsite_outer"; locked = 1 }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "eS" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ id_tag = "constructionsite_vent" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "eU" = ( /obj/machinery/door/airlock/external{ @@ -1557,75 +1424,73 @@ id_tag = "constructionsite_inner"; locked = 1 }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "eV" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "eW" = ( /obj/structure/cable/blue, -/obj/machinery/power/port_gen/pacman, +/obj/machinery/port_gen/pacman, /obj/machinery/power/terminal, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "eX" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eY" = ( /obj/random/hostile, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "eZ" = ( /obj/machinery/door/airlock/glass/science{ name = "Research" }, /obj/machinery/door/blast/shutters/open, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "fa" = ( /obj/machinery/atmospherics/pipe/simple/hidden/blue{ - icon_state = "intact"; dir = 5 }, /obj/machinery/light/small, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "constructionsite_airlock"; - pixel_x = 0; pixel_y = -25; req_access = newlist(); tag_airpump = "constructionsite_vent"; tag_chamber_sensor = "constructionsite_sensor"; tag_exterior_door = "constructionsite_outer"; - tag_interior_door = "constructionsite_inner" + tag_interior_door = "constructionsite_inner"; + dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "fb" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/blue, /obj/machinery/airlock_sensor{ id_tag = "constructionsite_sensor"; - pixel_x = 0; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "fc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/blue{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/external{ @@ -1633,51 +1498,43 @@ id_tag = "constructionsite_inner"; locked = 1 }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "fd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/blue{ - icon_state = "intact"; dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "fe" = ( /obj/machinery/atmospherics/pipe/simple/hidden/blue{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "ff" = ( /obj/structure/cable/blue{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "fg" = ( /obj/structure/cable/blue{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "fh" = ( -/obj/machinery/power/smes/batteryrack{ - should_be_mapped = 1 - }, +/obj/machinery/power/smes/batteryrack, /obj/structure/cable/blue{ - d2 = 2; icon_state = "0-2" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fi" = ( /obj/effect/shuttle_landmark/derelict/nav1, @@ -1686,263 +1543,240 @@ "fj" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "fk" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/storage) "fl" = ( /obj/machinery/door/airlock/glass/science{ name = "Research" }, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/storage) "fm" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/storage) "fn" = ( /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/machinery/portable_atmospherics/canister/air/airlock, /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 4 }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fo" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/blue{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "fp" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "fq" = ( /obj/structure/cable/blue{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/constructionsite/teleporter) "fr" = ( /obj/structure/cable/blue{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fs" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/blue{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/fabricator, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "ft" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "fu" = ( /obj/structure/window/basic, /obj/machinery/portable_atmospherics/canister/air/airlock, /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/blue{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fw" = ( /obj/structure/cable/blue, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/obj/machinery/power/apc/high/inactive{ - dir = 2; +/obj/machinery/apc/high/inactive{ name = "south bump"; pixel_y = -24 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fx" = ( /obj/machinery/portable_atmospherics/canister/nitrogen/prechilled, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "fy" = ( /obj/machinery/fabricator/imprinter, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/storage) "fz" = ( /obj/machinery/destructive_analyzer, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "fA" = ( /obj/machinery/fabricator/protolathe{ stat = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "fB" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/storage) "fC" = ( /obj/machinery/fabricator/pipe, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fD" = ( /obj/machinery/fabricator/pipe/disposal, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fE" = ( /obj/structure/reagent_dispensers/watertank, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fF" = ( /obj/structure/reagent_dispensers/fueltank, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fG" = ( /obj/machinery/light, /obj/structure/closet/crate/solar, /obj/effect/floor_decal/industrial/outline/yellow, /obj/random/loot, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fH" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, /obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fI" = ( /obj/machinery/teleport/station, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fJ" = ( /obj/machinery/teleport/hub, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) "fK" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "fL" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/solar) "fM" = ( /obj/random/closet, /obj/random/material, /obj/random/contraband, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "fN" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/solar) "fO" = ( /obj/structure/lattice, /turf/space, /area/constructionsite/solar) "fP" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/solar) "fQ" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/maintenance) "fR" = ( /obj/structure/extinguisher_cabinet{ - pixel_y = 30 + pixel_y = 29 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "fS" = ( /obj/random/junk, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "fT" = ( /obj/effect/overmap/visitable/sector/derelict, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/solar) "fU" = ( /turf/space, /area/constructionsite/solar) "fV" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/solar) "fW" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/solar) "fX" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/fore) "fY" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/solar) "fZ" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/solar) "ga" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "gb" = ( /obj/effect/shuttle_landmark/derelict/nav3, @@ -1950,7 +1784,7 @@ /area/space) "gc" = ( /obj/random/firstaid, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "gd" = ( /obj/structure/lattice, @@ -1958,109 +1792,98 @@ /turf/space, /area/constructionsite/solar) "ge" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/plushie, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "gf" = ( /obj/machinery/door/airlock/highsecurity{ - icon_state = "door_closed"; - locked = 0; name = "AI Upload Access" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/hallway/fore) "gg" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/ai) "gh" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gi" = ( -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "gj" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gk" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/space) "gl" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gm" = ( /obj/structure/sign/warning/lethal_turrets, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/ai) "gn" = ( /obj/machinery/door/airlock/highsecurity{ - icon_state = "door_closed"; - locked = 0; name = "AI Upload" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "go" = ( /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) -"gp" = ( -/obj/machinery/porta_turret_construct, -/turf/simulated/floor/tiled/dark/airless, -/area/constructionsite/ai) "gq" = ( /obj/effect/decal/cleanable/blood/oil, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gr" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/space) "gs" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "gt" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "gu" = ( /obj/random/loot, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gv" = ( /obj/random/trash, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "gw" = ( /obj/machinery/drone_fabricator/derelict, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gx" = ( /obj/structure/cable/blue{ - d2 = 2; icon_state = "0-2" }, -/obj/machinery/power/apc/high/inactive{ +/obj/machinery/apc/high/inactive{ dir = 1; name = "north bump"; pixel_y = 24 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gy" = ( /obj/machinery/computer/drone_control, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gz" = ( /obj/random/hostile, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gA" = ( /obj/structure/lattice, @@ -2070,13 +1893,13 @@ /obj/machinery/door/airlock/highsecurity{ name = "Messaging Server" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "gC" = ( /obj/machinery/door/airlock/highsecurity{ name = "Messaging Server" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/ai) "gD" = ( /obj/structure/showcase{ @@ -2085,77 +1908,74 @@ icon_state = "4"; name = "Deactivated AI Core" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "gE" = ( /obj/machinery/door/airlock/highsecurity{ name = "Cyborg Station" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "gF" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "gG" = ( /obj/effect/decal/cleanable/blood/oil, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/ai) "gH" = ( /obj/machinery/door/airlock/highsecurity{ name = "Cyborg Station" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/hallway/fore) "gI" = ( /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gJ" = ( /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gK" = ( /obj/machinery/recharge_station, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gL" = ( /obj/structure/lattice, /obj/structure/extinguisher_cabinet{ icon_state = "extinguisher_empty"; - pixel_x = -30 + pixel_x = -29; + dir = 4 }, /turf/space, /area/constructionsite/hallway/fore) "gM" = ( /obj/machinery/porta_turret/stationary, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gN" = ( /obj/random/junk, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/ai) "gO" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/hallway/aft) "gP" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/aft) "gQ" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gR" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/aft) "gS" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gT" = ( /obj/structure/lattice, @@ -2163,44 +1983,42 @@ /area/constructionsite/hallway/aft) "gU" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gV" = ( /obj/structure/grille, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gW" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gX" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gY" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "gZ" = ( /obj/machinery/door/airlock/highsecurity{ - icon_state = "door_closed"; - locked = 0; name = "AI Upload Access" }, -/turf/simulated/floor/bluegrid/airless, +/turf/floor/bluegrid/airless, /area/constructionsite/hallway/aft) "ha" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "hb" = ( /obj/effect/floor_decal/plaque{ desc = "To commemorate the beginning of the Eternity Project, a station that will ferry us through the stars forever without fail."; name = "Eternity Project Dedication Plaque" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "hc" = ( /obj/structure/lattice, @@ -2213,32 +2031,26 @@ opened = 1 }, /obj/random/plushie/large, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/maintenance) "he" = ( /obj/random/trash, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/aft) "hf" = ( -/obj/machinery/door/airlock/multi_tile/glass{ +/obj/machinery/door/airlock/double/glass{ name = "Emergency Entrance" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "hg" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/aft) "hh" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/hallway/aft) "hi" = ( /obj/effect/shuttle_landmark/derelict/nav4, @@ -2246,153 +2058,143 @@ /area/space) "hj" = ( /obj/structure/door_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "hk" = ( /obj/machinery/mech_recharger, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hl" = ( -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hm" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, /obj/random/firstaid, /obj/effect/floor_decal/corner/green{ dir = 4 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hn" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/medical) "ho" = ( /obj/machinery/sleeper/standard, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hp" = ( /obj/structure/iv_drip, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hq" = ( /obj/random/trash, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hr" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "hs" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/atmospherics) "ht" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/atmospherics) "hu" = ( /obj/item/frame/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hv" = ( -/turf/simulated/floor/airless, -/area/constructionsite/medical) -"hw" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hx" = ( /obj/random/junk, /obj/effect/floor_decal/corner/green{ dir = 9 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hy" = ( /obj/effect/floor_decal/corner/green, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hz" = ( /obj/item/chems/ivbag, /obj/item/chems/ivbag, -/obj/item/chems/ivbag/blood/OMinus, +/obj/item/chems/ivbag/blood/ominus, /obj/structure/closet/medical_wall{ name = "Blood Closet" }, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/hallway/aft) "hA" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) -"hB" = ( -/obj/structure/table, -/turf/simulated/floor/airless, -/area/constructionsite/medical) "hC" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hD" = ( /obj/machinery/door/airlock/glass/medical{ name = "Medbay" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hE" = ( /obj/structure/door_assembly{ name = "Medbay" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hF" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "hG" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "hH" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hI" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hJ" = ( -/obj/structure/sign/directions/examroom, -/turf/simulated/wall, +/obj/structure/sign/department/examroom, +/turf/wall, /area/constructionsite/medical) "hK" = ( /obj/effect/floor_decal/corner/green{ dir = 9 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hL" = ( /obj/machinery/disposal, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hM" = ( /obj/structure/table, /obj/random/medical, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hN" = ( /obj/structure/table, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "hO" = ( /obj/structure/fireaxecabinet{ pixel_x = 32 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "hP" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/atmospherics) "hQ" = ( /obj/structure/girder, @@ -2401,25 +2203,26 @@ "hR" = ( /obj/item/roller, /obj/item/roller, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hS" = ( /obj/structure/closet/medical_wall/filled{ - pixel_x = 32 + pixel_x = 32; + dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hT" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "hU" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "hV" = ( /obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/atmospherics) "hW" = ( /obj/structure/lattice, @@ -2427,26 +2230,26 @@ /area/constructionsite/medical) "hX" = ( /obj/random/medical/lite, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hY" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "hZ" = ( /obj/item/roller, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "ia" = ( /obj/random/closet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "ib" = ( /turf/space, /area/constructionsite/medical) "ic" = ( /obj/structure/mech_wreckage/powerloader, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "id" = ( /obj/structure/closet/secure_closet/atmos_personal{ @@ -2455,19 +2258,19 @@ }, /obj/random/voidsuit, /obj/random/voidhelmet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "ie" = ( /obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "if" = ( /obj/structure/iv_drip, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "ig" = ( /obj/random/snack, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "ih" = ( /obj/structure/lattice, @@ -2478,46 +2281,46 @@ /obj/machinery/door/airlock/glass/medical{ name = "Medbay Storage" }, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/hallway/aft) "ij" = ( /obj/machinery/door/airlock/glass/atmos{ name = "Atmospherics" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "ik" = ( /obj/random/firstaid, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "il" = ( -/obj/item/storage/box/freezer, -/turf/simulated/floor/airless, +/obj/item/box/freezer, +/turf/floor/plating/airless, /area/constructionsite/medical) "im" = ( /obj/random/closet, /obj/random/masks, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "in" = ( /obj/random/tool, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/atmospherics) "io" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "ip" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "iq" = ( /obj/random/ammo, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "ir" = ( /obj/structure/lattice, @@ -2532,7 +2335,8 @@ /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "iv" = ( /turf/space, @@ -2550,7 +2354,7 @@ /obj/random/junk, /obj/random/masks, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "iy" = ( /obj/machinery/computer/air_control{ @@ -2558,13 +2362,13 @@ name = "Mixed Air Supply Control"; output_tag = "d_air_out"; pressure_setting = 2000; - sensor_tag = "d_air_sensor"; - sensor_name = "Air Supply Tank" + sensor_name = "Air Supply Tank"; + sensor_tag = "d_air_sensor" }, /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "iz" = ( /obj/structure/grille, @@ -2582,23 +2386,23 @@ /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/constructionsite/atmospherics) "iA" = ( /obj/machinery/atmospherics/unary/vent_pump/tank{ dir = 8; external_pressure_bound = 0; - external_pressure_bound_default = 0 + external_pressure_bound_default = 0; icon_state = "map_vent_in"; id_tag = "d_air_out"; internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; - use_power = 1; pressure_checks = 2; pressure_checks_default = 2; - pump_direction = 0 + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/constructionsite/atmospherics) "iB" = ( /obj/machinery/light/small{ @@ -2607,7 +2411,7 @@ /obj/machinery/air_sensor/dist{ id_tag = "d_air_sensor" }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/constructionsite/atmospherics) "iC" = ( /obj/structure/girder, @@ -2616,22 +2420,21 @@ "iD" = ( /obj/structure/lattice, /obj/structure/sign/warning/nosmoking_1, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/medical) "iE" = ( -/obj/structure/sign/bluecross_2, -/turf/simulated/wall, +/obj/structure/sign/department/cross/blue2, +/turf/wall, /area/constructionsite/hallway/aft) "iF" = ( /obj/structure/sign/warning/compressed_gas, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/hallway/aft) "iG" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/atmospherics) "iH" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -2640,56 +2443,53 @@ id_tag = "d_air_in"; use_power = 1 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/constructionsite/atmospherics) "iI" = ( /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/constructionsite/atmospherics) "iJ" = ( /obj/machinery/door/airlock/glass/medical{ name = "Medbay" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "iK" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 8 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/atmospherics) "iL" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "iM" = ( /obj/effect/floor_decal/plaque{ desc = "In memory of Earl Whitenmeinster. We'll never forget you."; - icon_state = "plaque"; name = "Whitenmeister Memorial Hall Plaque" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/aft) "iN" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "iO" = ( /obj/machinery/computer/air_control{ input_tag = "d_o2_in"; name = "Oxygen Supply Control"; output_tag = "d_o2_out"; - sensor_tag = "d_o2_sensor"; - sensor_name = "Oxygen Supply Tank" + sensor_name = "Oxygen Supply Tank"; + sensor_tag = "d_o2_sensor" }, /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "iP" = ( /obj/machinery/atmospherics/unary/vent_pump/tank{ @@ -2701,12 +2501,12 @@ initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; - use_power = 1; pressure_checks = 2; pressure_checks_default = 2; - pump_direction = 0 + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/constructionsite/atmospherics) "iQ" = ( /obj/machinery/light/small{ @@ -2715,20 +2515,20 @@ /obj/machinery/air_sensor{ id_tag = "d_o2_sensor" }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/constructionsite/atmospherics) "iR" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/medical) "iS" = ( /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "iT" = ( /obj/effect/floor_decal/corner/green{ dir = 10 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/constructionsite/medical) "iU" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -2737,11 +2537,11 @@ id_tag = "d_o2_in"; use_power = 1 }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/constructionsite/atmospherics) "iV" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/constructionsite/atmospherics) "iW" = ( /obj/structure/lattice, @@ -2750,44 +2550,41 @@ /area/constructionsite/medical) "iX" = ( /obj/structure/cable/blue{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/atmospherics) "iY" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite) "iZ" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ja" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jb" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "jc" = ( /obj/machinery/computer/air_control{ input_tag = "d_n2_in"; name = "Nitrogen Supply Control"; output_tag = "d_n2_out"; - sensor_tag = "d_n2_sensor"; - sensor_name = "N2 Supply Tank" + sensor_name = "N2 Supply Tank"; + sensor_tag = "d_n2_sensor" }, /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "jd" = ( /obj/machinery/atmospherics/unary/vent_pump/tank{ @@ -2799,12 +2596,12 @@ initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; - use_power = 1; pressure_checks = 2; pressure_checks_default = 2; - pump_direction = 0 + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/constructionsite/atmospherics) "je" = ( /obj/machinery/light/small{ @@ -2813,70 +2610,69 @@ /obj/machinery/air_sensor{ id_tag = "d_n2_sensor" }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/constructionsite/atmospherics) "jf" = ( /obj/random/smokes, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jg" = ( /obj/structure/lattice, /turf/space, /area/constructionsite) "jh" = ( -/obj/structure/table/standard, -/obj/structure/bedsheetbin, -/turf/simulated/floor/airless, +/obj/structure/table, +/obj/structure/bedsheetbin/mapped, +/turf/floor/plating/airless, /area/constructionsite) "ji" = ( /obj/structure/table, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jj" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/hat, /obj/random/gloves, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jk" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/gloves, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jl" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/maintenance, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jm" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jn" = ( -/obj/structure/table/standard, -/turf/simulated/floor/airless, +/obj/structure/table, +/turf/floor/plating/airless, /area/constructionsite/medical) "jo" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/closet/body_bag/cryobag, /obj/structure/closet/body_bag/cryobag, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/medical) "jp" = ( /obj/structure/cable/blue, -/obj/machinery/power/apc/high/inactive{ - dir = 2; +/obj/machinery/apc/high/inactive{ name = "south bump"; pixel_y = -24 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "jq" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/constructionsite/atmospherics) "jr" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -2885,68 +2681,64 @@ id_tag = "d_n2_in"; use_power = 1 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/constructionsite/atmospherics) "js" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/constructionsite/atmospherics) "jt" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite) "ju" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jv" = ( /obj/structure/door_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jw" = ( /turf/space, /area/constructionsite) "jx" = ( /obj/structure/lattice, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jy" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jz" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jA" = ( /obj/structure/lattice, -/turf/simulated/wall, +/turf/wall, /area/constructionsite) "jB" = ( /obj/random/clothing, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jC" = ( /obj/structure/coatrack, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jD" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite) "jE" = ( /obj/structure/closet/cabinet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jF" = ( /obj/structure/bed, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jG" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jH" = ( /obj/structure/lattice, @@ -2957,217 +2749,209 @@ /obj/machinery/door/airlock{ name = "Cabin" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jJ" = ( /obj/random/hat, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jK" = ( /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jL" = ( /obj/random/snack, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jM" = ( /obj/machinery/door/airlock{ name = "Bunk Room" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jN" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite) "jO" = ( /obj/item/bedsheet, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jP" = ( /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jQ" = ( /obj/structure/extinguisher_cabinet{ icon_state = "extinguisher_empty"; - pixel_x = 30 + pixel_x = 29; + dir = 8 }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/aft) "jR" = ( /obj/random/trash, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jS" = ( /obj/random/maintenance/clean, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jT" = ( /obj/machinery/washing_machine, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jU" = ( /obj/structure/table, /obj/random/clothing, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jV" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite) "jW" = ( /obj/random/clothing, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jX" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "jY" = ( /obj/item/clothing/head/radiation, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "jZ" = ( /obj/machinery/constructable_frame, /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ka" = ( /obj/machinery/door/airlock/glass/engineering, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kb" = ( /obj/random/obstruction, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kc" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kd" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ke" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kf" = ( /obj/random/action_figure, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kg" = ( /obj/random/voidhelmet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kh" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/hardsuit, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "ki" = ( /obj/random/hostile, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "kj" = ( /obj/random/hostile, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kk" = ( /obj/structure/table, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite) "kl" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/cell_charger, /obj/random/powercell, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "km" = ( /obj/machinery/power/terminal{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kn" = ( /obj/machinery/power/smes/buildable, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ko" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kp" = ( -/obj/structure/table/rack, -/turf/simulated/floor/airless, +/obj/structure/rack, +/turf/floor/plating/airless, /area/constructionsite) "kq" = ( /obj/random/glasses, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kr" = ( -/obj/machinery/power/shield_generator{ +/obj/machinery/shield_generator/mapped{ desc = "A heavy-duty shield generator and capacitor, capable of generating energy shields at large distances. This one seems to be in a state of disrepair."; name = "disused shield generator" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ks" = ( /obj/random/junk, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "kt" = ( /obj/machinery/power/breakerbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ku" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/toolbox, /obj/random/loot, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "kv" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite) "kw" = ( /obj/random/closet, /obj/random/loot, /obj/random/junk, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "kx" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite) "ky" = ( /obj/structure/closet/radiation, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/hallway/aft) "kz" = ( -/turf/simulated/wall, +/turf/wall, /area/constructionsite/engineering) "kA" = ( /obj/machinery/door/airlock/glass/engineering{ name = "Engine Access" }, -/turf/simulated/floor/airless, -/area/constructionsite/engineering) -"kB" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kC" = ( /obj/effect/shuttle_landmark/derelict/nav6, @@ -3175,7 +2959,7 @@ /area/space) "kD" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kE" = ( /obj/structure/lattice, @@ -3183,91 +2967,80 @@ /area/constructionsite/engineering) "kF" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kG" = ( /obj/machinery/door/airlock/glass/engineering, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kH" = ( /obj/structure/sign/warning/compressed_gas, -/turf/simulated/wall, -/area/constructionsite/engineering) -"kI" = ( -/turf/simulated/floor/airless, +/turf/wall, /area/constructionsite/engineering) "kJ" = ( /turf/space, /area/constructionsite/engineering) "kK" = ( -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "kL" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/dark/airless, +/obj/structure/table, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "kM" = ( /obj/structure/sign/warning/radioactive, -/turf/simulated/wall, +/turf/wall, /area/constructionsite/engineering) "kN" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/tool, /obj/random/maintenance, /obj/random/maintenance, -/turf/simulated/floor/airless, -/area/constructionsite/engineering) -"kO" = ( -/obj/structure/table, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kP" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kQ" = ( /obj/random/maintenance, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/engineering) "kR" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kS" = ( -/obj/structure/table/standard, -/turf/simulated/floor/airless, +/obj/structure/table, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kT" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kU" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/material, /obj/random/material, /obj/random/material, /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kV" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/constructionsite/engineering) "kW" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/toolbox, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kX" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "kY" = ( /obj/structure/grille/broken, @@ -3275,9 +3048,9 @@ /turf/space, /area/constructionsite/engineering) "kZ" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "la" = ( /obj/structure/grille, @@ -3286,55 +3059,55 @@ /area/constructionsite/engineering) "lb" = ( /obj/random/hostile, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lc" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "ld" = ( /obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "le" = ( -/obj/machinery/power/rad_collector, -/turf/simulated/floor/airless, +/obj/machinery/rad_collector, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lf" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lg" = ( /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lh" = ( /obj/random/maintenance, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "li" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/tool, /obj/random/voidsuit, /obj/random/coin, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lj" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lk" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "ll" = ( /obj/structure/closet/radiation, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "lm" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "ln" = ( /obj/random/maintenance, @@ -3344,193 +3117,170 @@ /obj/machinery/door/airlock/glass/engineering{ name = "SMES" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lp" = ( /obj/structure/cable/blue{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lq" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lr" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "ls" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "lt" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lu" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/AIsattele) "lv" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable/blue, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lw" = ( /obj/machinery/power/terminal{ dir = 8 }, /obj/structure/cable/blue{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "lx" = ( /obj/structure/cable/blue{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "ly" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/blue{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/blue{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lz" = ( /obj/structure/cable/blue{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "lA" = ( /obj/machinery/power/terminal{ dir = 4 }, /obj/structure/cable/blue{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lB" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lC" = ( /obj/machinery/constructable_frame/computerframe, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lD" = ( /obj/machinery/teleport/station, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lE" = ( /obj/machinery/teleport/hub, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lF" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable/blue{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lG" = ( /obj/machinery/power/terminal{ dir = 8 }, /obj/structure/cable/blue{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lH" = ( /obj/structure/cable/blue{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/blue{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lI" = ( /obj/item/shard{ icon_state = "medium" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lJ" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lK" = ( /obj/structure/cable, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lL" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/gloves/insulated, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lM" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "lN" = ( /obj/structure/cable/blue, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "lO" = ( /obj/structure/girder, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lP" = ( /obj/item/cell, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lQ" = ( /obj/structure/grille/broken, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lR" = ( /turf/space, @@ -3538,11 +3288,11 @@ "lS" = ( /obj/structure/table, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lT" = ( /obj/random/hostile, -/turf/simulated/floor/tiled/dark/airless, +/turf/floor/tiled/dark/airless, /area/constructionsite/engineering) "lU" = ( /obj/structure/lattice, @@ -3551,49 +3301,48 @@ "lV" = ( /obj/structure/closet, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lW" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lX" = ( /obj/structure/grille/broken, /turf/space, /area/AIsattele) "lY" = ( -/obj/item/storage/toolbox/electrical{ +/obj/item/toolbox/electrical{ pixel_x = 1; pixel_y = -1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/AIsattele) "lZ" = ( -/obj/machinery/power/emitter{ +/obj/machinery/emitter{ anchored = 1; dir = 4; state = 2 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "ma" = ( /obj/machinery/field_generator, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "mb" = ( -/obj/machinery/power/emitter{ +/obj/machinery/emitter{ anchored = 1; dir = 8; state = 2 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/engineering) "mc" = ( -/obj/machinery/the_singularitygen, -/turf/simulated/floor/airless, +/obj/machinery/singularity_generator, +/turf/floor/plating/airless, /area/constructionsite/engineering) "md" = ( /obj/effect/shuttle_landmark/derelict/nav7, @@ -3601,62 +3350,62 @@ /area/space) "nb" = ( /obj/structure/table/reinforced, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, -/obj/item/stack/material/glass{ - amount = 50 - }, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, /obj/random/tech_supply, /obj/random/maintenance, /obj/machinery/camera/motion{ c_tag = "Construction Site Teleporter" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/constructionsite/teleporter) +"nn" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/dark/airless, +/area/constructionsite/atmospherics) "ob" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ id_tag = "constructionsite_vent" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, /obj/machinery/camera/motion{ c_tag = "Construction Site Teleporter Airlock" }, -/turf/simulated/floor, +/turf/floor, /area/constructionsite/teleporter) "AR" = ( /obj/structure/grille, /obj/structure/wall_frame, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "BO" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) "DP" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/aft) "Lk" = ( /obj/structure/grille/broken, /obj/structure/wall_frame, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/constructionsite/hallway/fore) +"Yw" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/constructionsite/atmospherics) (1,1,1) = {" aa @@ -20470,9 +20219,9 @@ dY er eD eL -eh +fB fj -eh +fB dY dY bo @@ -20671,10 +20420,10 @@ dY ec es eD -eh -eh +fB +fB fk -eh +fB fx dY bo @@ -20871,12 +20620,12 @@ dA bo dY ed -eh +fB eD -eh +fB eY fj -eh +fB eN dY bo @@ -20922,8 +20671,8 @@ gQ gQ gS hm -hw -hB +hN +jn hI hv hv @@ -21076,9 +20825,9 @@ ee et eD eM -eh +fB eD -eh +fB fy dY bo @@ -21275,12 +21024,12 @@ dz bo dY ef -eh +fB eE -eh -eh +fB +fB fl -eh +fB fz dY bo @@ -21477,12 +21226,12 @@ dz bo dY eg -eh +fB eD eN -eh +fB fj -eh +fB fA dY bo @@ -21593,10 +21342,10 @@ kz kz kz kZ -kB -kB -kB -kB +lm +lm +lm +lm kz kz kJ @@ -21670,7 +21419,7 @@ cO cx cA cw -dd +ds dD cN dQ @@ -21678,14 +21427,14 @@ cw dz bo dY -eh -eh +fB +fB eF -eh -eh +fB +fB fm es -eh +fB dY bu dz @@ -21791,13 +21540,13 @@ kz kz kz kz -kB -kB -kB +lm +lm +lm kK kK kK -kB +lm kK kF kz @@ -21880,14 +21629,14 @@ cN dz bo dZ -eh +fB es eD -eh -eh +fB +fB eF ft -eh +fB dY bo dz @@ -21991,34 +21740,34 @@ iY ju kz kF -kB -kB +lm +lm kQ -kB +lm kK -kB +lm lb le -kB -kB -kB +lm +lm +lm kz -kB -kB +lm +lm kK le kz -kB -kB -kB -kB +lm +lm +lm +lm lk -kB -kB -kB -kB -kB -kB +lm +lm +lm +lm +lm +lm aa aa aa @@ -22086,9 +21835,9 @@ ei eu eD eO -eh +fB eD -eh +fB fB dY bo @@ -22193,12 +21942,12 @@ iY ju kz kz -kB +lm kK kK -kB -kB -kB +lm +lm +lm kK kK kK @@ -22206,22 +21955,22 @@ kK kK lo kK -kB -kB -kB +lm +lm +lm kz -kB -kB +lm +lm lZ -kB -kB -kB -kB -kB -kB -kB +lm +lm +lm +lm +lm +lm +lm lZ -kB +lm aa aa aa @@ -22394,17 +22143,17 @@ aa iY ju kz -kB +lm kK kK -kB +lm kK -kB +lm kK -kB +lm kK kK -kB +lm kV kM lr @@ -22412,18 +22161,18 @@ kK lB lM kz -kB +lm aR -kB +lm aR aR aR -kB +lm aR aR -kB -kB -kB +lm +lm +lm aa aa aa @@ -22489,8 +22238,8 @@ bo bo bo dY -eh -eh +fB +fB dY bo bu @@ -22596,36 +22345,36 @@ aa iY ju kz -kB +lm kL -kO -kB +kS +lm kU kW -kO -kO +kS +kS lf li -kO -kB +kS +lm kz kP kP kP kP kz -kB +lm aR ma -kB -kB -kB +lm +lm +lm ma -kB -kB -kB +lm +lm +lm ma -kB +lm aa aa aa @@ -22691,7 +22440,7 @@ bo bu ev dY -eh +fB es dY bo @@ -22716,7 +22465,7 @@ aR aR gg gg -gp +gh gi gh gi @@ -22818,16 +22567,16 @@ lN kz kz aR -kB +lm aR aR aR -kB +lm aR aR aR -kB -kB +lm +lm aa aa aa @@ -22998,9 +22747,9 @@ gO gO aR kz -kB +lm kz -kB +lm kz kE kE @@ -23012,24 +22761,24 @@ kE kE kE kz -kB +lm kK lw lG -kB -kB +lm +lm kz -kB -kB +lm +lm aR aa aR -kB +lm aR aa aR -kB -kB +lm +lm aa aa aa @@ -23200,9 +22949,9 @@ ky kz kz kz -kB +lm kz -kB +lm kM kz kz @@ -23214,24 +22963,24 @@ kz kz kz kz -kB -kB +lm +lm lx lz kK -kB +lm kP aR -kB +lm aR aR aR -kB +lm aR aR aR -kB -kB +lm +lm aa aa aa @@ -23400,40 +23149,40 @@ gQ gP gQ kA -kB +lm kA -kB +lm kA -kB +lm kA -kB -kB -kB -kB -kB -kB -kB -kB -kB +lm +lm +lm +lm +lm +lm +lm +lm +lm kA lp ls ly lH -kB +lm kK kP aR ma -kB -kB -kB +lm +lm +lm mc -kB -kB -kB +lm +lm +lm ma -kB +lm aa aa aa @@ -23604,9 +23353,9 @@ gQ kz kz kz -kB +lm kz -kB +lm kM kz kz @@ -23622,20 +23371,20 @@ kK kK lz lx -kB +lm kK kP aR -kB +lm aR aR aR -kB +lm aR aR aR -kB -kB +lm +lm aa aa aa @@ -23806,9 +23555,9 @@ gO gO aa kz -kB +lm kz -kB +lm kz kE kE @@ -23824,20 +23573,20 @@ le kK lA lA -kB +lm lT kz -kB -kB +lm +lm aR aa aR -kB +lm aR aa aR -kB -kB +lm +lm aa aa aa @@ -23928,11 +23677,11 @@ aR aR gg gg -gp +gh gi gh gi -gp +gh gg gg aR @@ -24030,16 +23779,16 @@ lN kz kz aR -kB +lm aR aR aR -kB +lm aR aR aR -kB -kB +lm +lm aa aa aa @@ -24212,16 +23961,16 @@ aa iY ju kz -kB +lm kN kL kS -kO +kS kX kK kX -kO -kO +kS +kS lj ll kz @@ -24230,18 +23979,18 @@ kP kP kR kz -kB +lm aR ma -kB -kB -kB +lm +lm +lm ma -kB -kB -kB +lm +lm +lm ma -kB +lm aa aa aa @@ -24414,36 +24163,36 @@ aa iY ju kz -kB -kB +lm +lm kK kK kV -kB +lm kK kK kK -kB +lm lk -kB +lm kM lt lB -kB +lm kZ kz -kB +lm aR -kB +lm aR aR aR -kB +lm aR aR -kB -kB -kB +lm +lm +lm aa aa aa @@ -24617,35 +24366,35 @@ iY ju kz kH -kB +lm kK kK -kB -kB -kB +lm +lm +lm ld kK -kB -kB +lm +lm kK lo -kB -kB -kB +lm +lm +lm kK kz -kB -kB +lm +lm mb -kB -kB -kB -kB -kB -kB -kB +lm +lm +lm +lm +lm +lm +lm mb -kB +lm aa aa aa @@ -24768,9 +24517,9 @@ hr hr hr hr -hV -ie +nn ie +Yw hr hs hr @@ -24818,35 +24567,35 @@ aa iY ju kz -kI +lm kK -kB -kB +lm +lm kK kK kK kV -kB -kB +lm +lm kV kK lq kK kK -kB -kB +lm +lm kz -kB -kB -kB -kB -kB -kB -kB -kB -kB -kB -kB +lm +lm +lm +lm +lm +lm +lm +lm +lm +lm +lm aa aa aa @@ -25024,13 +24773,13 @@ kz kz kz kT -kB +lm kF -kB +lm kK lg kK -kB +lm lm kz kP @@ -25228,11 +24977,11 @@ kz kz kz kz -kB +lm kK lh -kB -kI +lm +lm kz kz kJ @@ -25301,9 +25050,9 @@ bp aW bo aW -cH +du cy -dd +ds dn cw cG @@ -25506,7 +25255,7 @@ aW cI cw db -dd +ds cG cG dM @@ -25920,7 +25669,7 @@ cN dz bo eb -eq +eC eB eA eJ @@ -26177,10 +25926,10 @@ hr hr hs hr +nn hV -hV -ie ie +Yw hs hr hs diff --git a/maps/away/derelict/derelict.dm b/maps/away/derelict/derelict.dm index 2197121840b8..53a12ae6bf00 100644 --- a/maps/away/derelict/derelict.dm +++ b/maps/away/derelict/derelict.dm @@ -4,8 +4,6 @@ name = "debris field" desc = "A large field of miscellanious debris." icon_state = "object" - known = 0 - initial_generic_waypoints = list( "nav_derelict_1", "nav_derelict_2", @@ -18,7 +16,6 @@ /datum/map_template/ruin/away_site/derelict name = "Derelict Station" - id = "awaysite_derelict" description = "An abandoned construction project." suffixes = list("derelict/derelict-station.dmm") cost = 1 diff --git a/maps/away/empty.dmm b/maps/away/empty.dmm deleted file mode 100644 index 3688c3919e13..000000000000 --- a/maps/away/empty.dmm +++ /dev/null @@ -1,40405 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/space, -/area/space) - -(1,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(2,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(3,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(4,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(5,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(6,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(7,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(8,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(9,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(10,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(11,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(12,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(13,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(14,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(15,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(16,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(17,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(18,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(19,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(20,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(21,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(22,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(23,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(24,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(25,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(26,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(27,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(28,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(29,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(30,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(31,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(32,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(33,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(34,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(35,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(36,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(37,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(38,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(39,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(40,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(41,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(42,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(43,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(44,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(45,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(46,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(47,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(48,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(49,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(50,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(51,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(52,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(53,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(54,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(55,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(56,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(57,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(58,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(59,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(60,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(61,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(62,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(63,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(64,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(65,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(66,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(67,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(68,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(69,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(70,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(71,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(72,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(73,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(74,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(75,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(76,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(77,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(78,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(79,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(80,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(81,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(82,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(83,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(84,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(85,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(86,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(87,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(88,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(89,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(90,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(91,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(92,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(93,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(94,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(95,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(96,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(97,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(98,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(99,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(100,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(101,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(102,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(103,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(104,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(105,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(106,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(107,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(108,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(109,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(110,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(111,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(112,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(113,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(114,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(115,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(116,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(117,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(118,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(119,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(120,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(121,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(122,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(123,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(124,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(125,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(126,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(127,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(128,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(129,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(130,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(131,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(132,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(133,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(134,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(135,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(136,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(137,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(138,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(139,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(140,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(141,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(142,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(143,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(144,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(145,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(146,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(147,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(148,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(149,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(150,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(151,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(152,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(153,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(154,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(155,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(156,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(157,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(158,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(159,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(160,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(161,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(162,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(163,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(164,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(165,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(166,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(167,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(168,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(169,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(170,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(171,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(172,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(173,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(174,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(175,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(176,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(177,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(178,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(179,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(180,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(181,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(182,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(183,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(184,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(185,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(186,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(187,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(188,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(189,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(190,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(191,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(192,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(193,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(194,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(195,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(196,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(197,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(198,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(199,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(200,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} diff --git a/maps/away/errant_pisces/errant_pisces.dm b/maps/away/errant_pisces/errant_pisces.dm index a1648048ddb7..0f53db80c754 100644 --- a/maps/away/errant_pisces/errant_pisces.dm +++ b/maps/away/errant_pisces/errant_pisces.dm @@ -1,3 +1,4 @@ +#include "../../../mods/content/corporate/_corporate.dme" #include "errant_pisces_areas.dm" /obj/effect/overmap/visitable/ship/errant_pisces @@ -11,126 +12,64 @@ /datum/map_template/ruin/away_site/errant_pisces name = "Errant Pisces" - id = "awaysite_errant_pisces" description = "Carp trawler" suffixes = list("errant_pisces/errant_pisces.dmm") cost = 1 area_usage_test_exempted_root_areas = list(/area/errant_pisces) -/mob/living/simple_animal/hostile/carp/shark // generally stronger version of a carp that doesn't die from a mean look. Fance new sprites included, credits to F-Tang Steve - name = "cosmoshark" - desc = "Enormous creature that resembles a shark with magenta glowing lines along its body and set of long deep-purple teeth." - icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' - icon_state = "shark" - icon_living = "shark" - icon_dead = "shark_dead" - icon_gib = "shark_dead" - turns_per_move = 5 - meat_type = /obj/item/chems/food/snacks/sharkmeat - speed = 2 - maxHealth = 100 - health = 100 - natural_weapon = /obj/item/natural_weapon/bite/strong - break_stuff_probability = 35 - faction = "shark" - -/mob/living/simple_animal/hostile/carp/shark/carp_randomify() - return - -/mob/living/simple_animal/hostile/carp/shark/on_update_icon() - return - -/mob/living/simple_animal/hostile/carp/shark/death() - ..() - var/datum/gas_mixture/environment = loc.return_air() - if (environment) - var/datum/gas_mixture/sharkmaw_chlorine = new - sharkmaw_chlorine.adjust_gas(/decl/material/gas/chlorine, 10) - environment.merge(sharkmaw_chlorine) - visible_message(SPAN_WARNING("\The [src]'s body releases some gas from the gills with a quiet fizz!")) - -/mob/living/simple_animal/hostile/carp/shark/AttackingTarget() - set waitfor = 0//to deal with sleep() possibly stalling other procs - . =..() - var/mob/living/L = . - if(istype(L)) - if(prob(25))//if one is unlucky enough, they get tackled few tiles away - L.visible_message("\The [src] tackles [L]!") - var/tackle_length = rand(3,5) - for (var/i = 1 to tackle_length) - var/turf/T = get_step(L.loc, dir)//on a first step of tackling standing mob would block movement so let's check if there's something behind it. Works for consequent moves too - if (T.density || LinkBlocked(L.loc, T) || TurfBlockedNonWindow(T) || DirBlocked(T, GLOB.flip_dir[dir])) - break - sleep(2) - forceMove(T)//maybe there's better manner then just forceMove() them - L.forceMove(T) - visible_message("\The [src] releases [L].") - -/obj/item/chems/food/snacks/sharkmeat - name = "cosmoshark fillet" - desc = "A fillet of cosmoshark meat." - icon_state = "fishfillet" - filling_color = "#cecece" - center_of_mass = @"{'x':17,'y':13}" - -/obj/item/chems/food/snacks/sharkmeat/Initialize() - . = ..() - reagents.add_reagent(/decl/material/liquid/nutriment/protein, 5) - reagents.add_reagent(/decl/material/liquid/psychoactives, 1) - reagents.add_reagent(/decl/material/gas/chlorine, 1) - src.bitesize = 8 - - -/obj/structure/net//if you want to have fun, make them to be draggable as a whole unless at least one piece is attached to a non-space turf or anchored object +//if you want to have fun, make them to be draggable as a whole unless at least one piece is attached to a non-space turf or anchored object +/obj/structure/net name = "industrial net" desc = "A sturdy industrial net of synthetic belts reinforced with plasteel threads." - icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' + icon = 'maps/away/errant_pisces/icons/net.dmi' icon_state = "net_f" - anchored = 1 + anchored = TRUE layer = CATWALK_LAYER//probably? Should cover cables, pipes and the rest of objects that are secured on the floor - maxhealth = 100 + max_health = 100 /obj/structure/net/Initialize(var/mapload) . = ..() update_connections() if (!mapload)//if it's not mapped object but rather created during round, we should update visuals of adjacent net objects var/turf/T = get_turf(src) - for (var/turf/AT in T.CardinalTurfs(FALSE)) - for (var/obj/structure/net/N in AT) - if (type != N.type)//net-walls cause update for net-walls and floors for floors but not for each other - continue - N.update_connections() - -/obj/structure/net/show_examined_damage(mob/user, var/perc) - if(maxhealth == -1) + if(T) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + for (var/obj/structure/net/N in AT) + if (type != N.type)//net-walls cause update for net-walls and floors for floors but not for each other + continue + N.update_connections() + +/obj/structure/net/get_examined_damage_string() + if(!can_take_damage()) return - if(perc >= 1) - to_chat(user, SPAN_NOTICE("It looks fully intact.")) - else if (perc < 0.2) - to_chat(perc, SPAN_DANGER("\The [src] is barely hanging on by the last few threads.")) - else if (perc < 0.5) - to_chat(user, SPAN_WARNING("Large swathes of \the [src] have been cut.")) - else if (perc < 0.9) - to_chat(user, SPAN_NOTICE("A few strands of \the [src] have been severed.")) - -/obj/structure/net/attackby(obj/item/W, mob/user) - if(W.sharp || W.edge) - var/obj/item/SH = W - if (!(SH.sharp) || (SH.sharp && SH.force < 10))//is not sharp enough or at all - to_chat(user,"You can't cut throught \the [src] with \the [W], it's too dull.") - return - visible_message("[user] starts to cut through \the [src] with \the [W]!") - while(health > 0 && !QDELETED(src) && !QDELETED(user)) + var/health_percent = get_percent_health() + if(health_percent >= 100) + return SPAN_NOTICE("It looks fully intact.") + else if (health_percent < 20) + return SPAN_DANGER("\The [src] is barely hanging on by the last few threads.") + else if (health_percent < 50) + return SPAN_WARNING("Large swathes of \the [src] have been cut.") + else + return SPAN_NOTICE("A few strands of \the [src] have been severed.") + +/obj/structure/net/attackby(obj/item/used_item, mob/user) + if(used_item.is_sharp() || used_item.has_edge()) + var/force = used_item.expend_attack_force(user) + if (!(used_item.is_sharp()) || (used_item.is_sharp() && force < 10))//is not sharp enough or at all + to_chat(user,"You can't cut through \the [src] with \the [used_item], it's too dull.") + return TRUE + visible_message("[user] starts to cut through \the [src] with \the [used_item]!") + while(current_health > 0 && !QDELETED(src) && !QDELETED(user)) if (!do_after(user, 20, src)) - visible_message("[user] stops cutting through \the [src] with \the [W]!") - return - take_damage(20 * (1 + (SH.force-10)/10)) //the sharper the faster, every point of force above 10 adds 10 % to damage + visible_message("[user] stops cutting through \the [src] with \the [used_item]!") + return TRUE + take_damage(20 * (1 + (force-10)/10), used_item.atom_damage_type) //the sharper the faster, every point of force above 10 adds 10 % to damage new /obj/item/stack/net(src.loc) qdel(src) return TRUE . = ..() -/obj/structure/net/physically_destroyed() +/obj/structure/net/physically_destroyed(var/skip_qdel) SHOULD_CALL_PARENT(FALSE) visible_message("\The [src] is torn apart!") qdel(src) @@ -138,58 +77,58 @@ /obj/structure/net/bullet_act(obj/item/projectile/P) . = PROJECTILE_CONTINUE //few cloth ribbons won't stop bullet or energy ray - if(P.damage_type != BURN)//beams, lasers, fire. Bullets won't make a lot of damage to the few hanging belts. + if(P.atom_damage_type != BURN)//beams, lasers, fire. Bullets won't make a lot of damage to the few hanging belts. return visible_message("\The [P] hits \the [src] and tears it!") - take_damage(P.damage) + take_damage(P.damage, P.atom_damage_type) /obj/structure/net/update_connections()//maybe this should also be called when any of the walls nearby is removed but no idea how I can make it happen overlays.Cut() var/turf/T = get_turf(src) - for (var/turf/AT in T.CardinalTurfs(FALSE)) - if ( (locate(/obj/structure/net) in AT) || (!istype(AT, /turf/simulated/open) && !istype(AT, /turf/space)) || (locate(/obj/structure/lattice) in AT) )//connects to another net objects or walls/floors or lattices - var/image/I = image(icon,"[icon_state]_ol_[get_dir(src,AT)]") - overlays += I + if(T) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + if((locate(/obj/structure/net) in AT) || (locate(/obj/structure/lattice) in AT))//connects to another net objects or walls/floors or lattices + var/image/I = image(icon,"[icon_state]_ol_[get_dir(src,AT)]") + overlays += I /obj/structure/net/net_wall icon_state = "net_w" - density = 1 + density = TRUE layer = ABOVE_HUMAN_LAYER /obj/structure/net/net_wall/Initialize(var/mapload) . = ..() if (mapload)//if it's pre-mapped, it should put floor-net below itself var/turf/T = get_turf(src) - for (var/obj/structure/net/N in T) - if (N.type != /obj/structure/net/net_wall)//if there's net that is not a net-wall, we don't need to spawn it - return - new /obj/structure/net(T) - + if(T) + for (var/obj/structure/net/N in T) + if (N.type != /obj/structure/net/net_wall)//if there's net that is not a net-wall, we don't need to spawn it + return + new /obj/structure/net(T) /obj/structure/net/net_wall/update_connections()//this is different for net-walls because they only connect to walls and net-walls overlays.Cut() var/turf/T = get_turf(src) - for (var/turf/AT in T.CardinalTurfs(FALSE)) - if ((locate(/obj/structure/net/net_wall) in AT) || istype(AT, /turf/simulated/wall) || istype(AT, /turf/unsimulated/wall))//connects to another net-wall objects or walls - var/image/I = image(icon,"[icon_state]_ol_[get_dir(src,AT)]") - overlays += I + if(T) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + if ((locate(/obj/structure/net/net_wall) in AT) || istype(AT, /turf/wall) || istype(AT, /turf/unsimulated/wall))//connects to another net-wall objects or walls + var/image/I = image(icon,"[icon_state]_ol_[get_dir(src,AT)]") + overlays += I /obj/item/stack/net name = "industrial net roll" desc = "Sturdy industrial net reinforced with plasteel threads." - singular_name = "industrial net" - icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' + icon = 'maps/away/errant_pisces/icons/net_roll.dmi' icon_state = "net_roll" w_class = ITEM_SIZE_LARGE - force = 3.0 - throwforce = 5.0 throw_speed = 5 throw_range = 10 - matter = list("cloth" = 1875, "plasteel" = 350) + material = /decl/material/solid/organic/cloth + matter = list(/decl/material/solid/metal/plasteel = MATTER_AMOUNT_REINFORCEMENT) max_amount = 30 center_of_mass = null attack_verb = list("hit", "bludgeoned", "whacked") - lock_picking_level = 3 + _base_attack_force = 3 /obj/item/stack/net/Initialize() . = ..() @@ -199,6 +138,7 @@ amount = 30 /obj/item/stack/net/on_update_icon() + . = ..() if(amount == 1) icon_state = "net" else @@ -208,9 +148,10 @@ if (!has_gravity()) return 1 var/turf/T = get_turf(src) - for (var/turf/AT in T.CardinalTurfs(FALSE)) - if ((locate(/obj/structure/net/net_wall) in AT) || istype(AT, /turf/simulated/wall) || istype(AT, /turf/unsimulated/wall))//connects to another net-wall objects or walls - return 1 + if(T) + for (var/turf/AT in T.CardinalTurfs(FALSE)) + if ((locate(/obj/structure/net/net_wall) in AT) || istype(AT, /turf/wall) || istype(AT, /turf/unsimulated/wall))//connects to another net-wall objects or walls + return 1 return 0 /obj/item/stack/net/attack_self(mob/user)//press while holding to lay one. If there's net already, place wall @@ -232,20 +173,18 @@ if (amount < 1) qdel(src) -/obj/item/clothing/under/carp//as far as I know sprites are taken from /tg/ +/obj/item/clothing/costume/carp //as far as I know sprites are taken from /tg/ name = "space carp suit" desc = "A suit in a shape of a space carp. Usually worn by corporate interns who are sent to entertain children during HQ excursions." - icon_state = "carp_suit" - icon = 'maps/away/errant_pisces/errant_pisces_sprites.dmi' - item_icons = list(slot_w_uniform_str = 'maps/away/errant_pisces/errant_pisces_sprites.dmi') + icon = 'maps/away/errant_pisces/icons/carpsuit.dmi' -/obj/effect/landmark/corpse/carp_fisher +/obj/abstract/landmark/corpse/carp_fisher name = "carp fisher" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/carp_fisher) + corpse_outfits = list(/decl/outfit/corpse_carp_fisher) -/decl/hierarchy/outfit/corpse/carp_fisher +/decl/outfit/corpse_carp_fisher name = "Dead carp fisher" - uniform = /obj/item/clothing/under/color/green + uniform = /obj/item/clothing/jumpsuit/green suit = /obj/item/clothing/suit/apron/overalls belt = /obj/item/knife/combat shoes = /obj/item/clothing/shoes/jackboots diff --git a/maps/away/errant_pisces/errant_pisces.dmm b/maps/away/errant_pisces/errant_pisces.dmm index 8bec82de6ee4..85d9184d31c9 100644 --- a/maps/away/errant_pisces/errant_pisces.dmm +++ b/maps/away/errant_pisces/errant_pisces.dmm @@ -3,29 +3,28 @@ /turf/space, /area/space) "ab" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bow_starboard) "ac" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bow_port) "ad" = ( /obj/machinery/atmospherics/unary/engine, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bow_starboard) "ae" = ( /obj/machinery/atmospherics/unary/engine, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bow_port) "af" = ( /obj/machinery/alarm{ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ag" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -36,13 +35,13 @@ dir = 8 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ah" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel, /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ai" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -50,7 +49,7 @@ }, /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aj" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -60,10 +59,9 @@ /obj/effect/floor_decal/industrial/warning, /obj/machinery/alarm{ dir = 8; - pixel_x = 25; - pixel_y = 0 + pixel_x = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ak" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -75,16 +73,15 @@ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "al" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel, /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "am" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -92,7 +89,7 @@ }, /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "an" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -103,42 +100,41 @@ dir = 4 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "ao" = ( /obj/machinery/alarm{ dir = 8; - pixel_x = 25; - pixel_y = 0 + pixel_x = 25 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "ap" = ( /obj/machinery/portable_atmospherics/canister/empty/hydrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aq" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ar" = ( /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "as" = ( /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "at" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "au" = ( /obj/machinery/portable_atmospherics/canister/empty/hydrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "av" = ( /obj/machinery/atmospherics/portables_connector{ @@ -148,19 +144,19 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aw" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ax" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "ay" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ @@ -169,7 +165,7 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "az" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ @@ -178,19 +174,19 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aA" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aB" = ( /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aC" = ( /obj/machinery/atmospherics/portables_connector{ @@ -200,19 +196,17 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aD" = ( /obj/structure/closet/firecloset, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aE" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -221,22 +215,20 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aF" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aG" = ( /obj/machinery/portable_atmospherics/canister/empty/hydrogen, @@ -244,10 +236,10 @@ dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aH" = ( /obj/machinery/atmospherics/unary/tank/hydrogen{ @@ -256,7 +248,7 @@ /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aI" = ( /obj/machinery/atmospherics/unary/tank/hydrogen{ @@ -265,52 +257,49 @@ /obj/effect/floor_decal/industrial/warning{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aJ" = ( -/obj/machinery/atmospherics/unary/heater{ - icon_state = "heater_0"; +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aK" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aL" = ( /obj/machinery/atmospherics/valve{ - icon_state = "map_valve0"; dir = 8 }, /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aM" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aN" = ( -/obj/machinery/atmospherics/unary/heater{ - icon_state = "heater_0"; +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aO" = ( /obj/machinery/atmospherics/unary/tank/hydrogen{ dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aP" = ( /obj/machinery/atmospherics/unary/tank/hydrogen{ @@ -319,7 +308,7 @@ /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aQ" = ( /obj/machinery/portable_atmospherics/canister/empty/hydrogen, @@ -329,28 +318,24 @@ /obj/effect/floor_decal/industrial/warning{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aR" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aS" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -359,14 +344,14 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aT" = ( /obj/structure/closet/firecloset, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "aU" = ( /obj/structure/lattice, @@ -380,69 +365,63 @@ /turf/space, /area/space) "aW" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/storage_starboard) "aX" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_starboard) "aY" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/atmos) "aZ" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/enginering) "ba" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_port) "bb" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/storage_port) "bc" = ( /obj/structure/lattice, /turf/space, /area/space) "bd" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "be" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "bf" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "bg" = ( /obj/machinery/atmospherics/unary/tank/air, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bh" = ( /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bi" = ( /obj/machinery/light/small{ @@ -451,109 +430,78 @@ /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bj" = ( /obj/machinery/portable_atmospherics/canister, /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bk" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) -"bl" = ( -/turf/simulated/floor/plating, -/area/errant_pisces/enginering) "bm" = ( /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bn" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bo" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/obj/vehicle/train/cargo/trolley, -/turf/simulated/floor/plating, +/obj/vehicle/train/trolley, +/turf/floor/plating, /area/errant_pisces/enginering) "bp" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bq" = ( /obj/machinery/computer/ship/engines, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "br" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bs" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/toolbox, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "bt" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) -"bu" = ( -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable/yellow{ - d2 = 4; - icon_state = "0-4" - }, -/obj/machinery/power/solar{ - id = "HarpoonSolarStarboard" - }, -/turf/simulated/floor/airless, -/area/space) "bv" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/airless, -/area/space) -"bw" = ( -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable/yellow{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/solar{ - id = "HarpoonSolarStarboard" - }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "bx" = ( /obj/machinery/light/small{ dir = 4 }, /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "by" = ( /obj/machinery/light/small{ dir = 4 }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "bz" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue{ @@ -562,11 +510,11 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bA" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bB" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ @@ -575,78 +523,75 @@ /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bC" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bD" = ( /obj/machinery/atmospherics/pipe/manifold/visible/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bE" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bF" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bG" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bH" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bI" = ( /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bJ" = ( /obj/machinery/portable_atmospherics/canister, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bK" = ( -/obj/vehicle/train/cargo/trolley, -/turf/simulated/floor/plating, +/obj/vehicle/train/trolley, +/turf/floor/plating, /area/errant_pisces/enginering) "bL" = ( /obj/structure/table/steel, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bM" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bN" = ( /obj/machinery/light/small{ dir = 4 }, /obj/structure/table/steel, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "bO" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ @@ -654,317 +599,291 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "bP" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/powercell, /obj/machinery/light/small{ dir = 8 }, /obj/item/mop, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) -"bQ" = ( -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable/yellow{ - d2 = 4; - icon_state = "0-4" - }, -/obj/machinery/power/solar{ - id = "HarpoonSolarPort" - }, -/turf/simulated/floor/airless, -/area/space) "bR" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/solar{ - id = "HarpoonSolarPort" - }, -/turf/simulated/floor/airless, +/obj/machinery/power/solar, +/turf/floor/plating/airless, /area/space) "bS" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "bT" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "bU" = ( /obj/machinery/atmospherics/unary/tank/air{ dir = 1; start_pressure = 740.5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bV" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bW" = ( /obj/machinery/atmospherics/binary/pump, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bX" = ( /obj/machinery/atmospherics/omni/filter{ tag_east = 4; tag_north = 2; - tag_south = 1; - tag_west = 0 + tag_south = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bY" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "bZ" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, /obj/machinery/atmospherics/portables_connector{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "ca" = ( /obj/machinery/portable_atmospherics/canister, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cb" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cc" = ( /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cd" = ( /obj/structure/closet, /obj/random/tool, /obj/random/smokes, -/obj/item/clothing/under/hazard, -/turf/simulated/floor/plating, +/obj/item/clothing/jumpsuit/hazard, +/turf/floor/plating, /area/errant_pisces/enginering) "ce" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "cf" = ( /obj/machinery/atmospherics/unary/tank/nitrogen{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cg" = ( /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "ch" = ( /obj/machinery/atmospherics/portables_connector{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "ci" = ( /obj/machinery/atmospherics/pipe/simple/visible/universal, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cj" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "ck" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cl" = ( /obj/machinery/atmospherics/omni/filter{ - tag_east = 0; tag_north = 2; tag_south = 1; tag_west = 3 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cm" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cn" = ( /obj/machinery/fabricator, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "co" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, /obj/random/tech_supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cp" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, /obj/random/tech_supply, /obj/item/clothing/gloves/thick/duty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cq" = ( /obj/structure/closet, /obj/random/tech_supply, /obj/item/clothing/shoes/jackboots/duty, -/obj/item/clothing/under/hazard, -/turf/simulated/floor/plating, +/obj/item/clothing/jumpsuit/hazard, +/turf/floor/plating, /area/errant_pisces/enginering) "cr" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/powercell, /obj/random/clothing, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "cs" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "ct" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cu" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cv" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/errant_pisces/atmos) "cw" = ( /obj/machinery/atmospherics/omni/mixer{ dir = 1 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/errant_pisces/atmos) "cx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/visible/blue{ - icon_state = "intact"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cy" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cz" = ( /obj/machinery/atmospherics/binary/oxyregenerator{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cA" = ( /obj/machinery/atmospherics/omni/filter{ - tag_east = 0; tag_north = 2; tag_south = 1; tag_west = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cB" = ( /obj/machinery/fabricator/pipe, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cC" = ( -/obj/effect/landmark/corpse/engineer, +/obj/abstract/landmark/corpse/engineer, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cD" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cE" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, /obj/random/tank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cF" = ( /obj/structure/closet, /obj/random/tool, /obj/random/glasses, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cG" = ( /obj/structure/closet/l3closet/janitor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "cH" = ( /obj/random/junk, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "cI" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "cJ" = ( /obj/machinery/light/small{ dir = 4 }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "cK" = ( /obj/machinery/atmospherics/unary/tank/oxygen{ @@ -973,108 +892,104 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cL" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cM" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue, /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/errant_pisces/atmos) "cN" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ - icon_state = "intact"; dir = 9 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cO" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cQ" = ( /obj/machinery/light/small{ dir = 8 }, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cR" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cS" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "cT" = ( -/obj/structure/bed/chair/janicart, +/obj/structure/janicart, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "cU" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "cV" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "cW" = ( /obj/machinery/alarm{ dir = 8; - pixel_x = 25; - pixel_y = 0 + pixel_x = 25 }, /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "cX" = ( /obj/machinery/atmospherics/unary/tank/oxygen{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cY" = ( /obj/machinery/atmospherics/portables_connector{ @@ -1083,11 +998,11 @@ /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "cZ" = ( /obj/machinery/portable_atmospherics/powered/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "da" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1095,191 +1010,168 @@ }, /obj/machinery/light/small, /obj/machinery/portable_atmospherics/powered/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "db" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "dc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "dd" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "de" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/structure/closet/firecloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "df" = ( /obj/machinery/alarm{ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "dg" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "dh" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "di" = ( -/obj/structure/dispenser/oxygen, -/turf/simulated/floor/plating, +/obj/structure/tank_rack/oxygen, +/turf/floor/plating, /area/errant_pisces/enginering) "dj" = ( /obj/machinery/light/small, /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "dk" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "dl" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -32; - pixel_y = 0 + pixel_x = -32 }, /obj/structure/mopbucket, /obj/item/mop, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "dm" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "dn" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_starboard) "do" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/atmos) "dp" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/enginering) "dq" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/storage_port) "dr" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bow_maint) "ds" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1288,12 +1180,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dt" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1302,54 +1192,39 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "du" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dv" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dw" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1358,48 +1233,36 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dx" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/green{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dy" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dz" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1408,7 +1271,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dA" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -1417,92 +1280,77 @@ id_tag = "n2_in"; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "dB" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dC" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dD" = ( /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dE" = ( /obj/machinery/atmospherics/portables_connector{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dF" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dG" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dH" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dI" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dJ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dK" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1511,131 +1359,112 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dL" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -24 }, /obj/structure/cable/green, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dM" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dN" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dO" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/random/junk, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dP" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dQ" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dR" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/solar_starboard) "dS" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/hardsuit, /obj/random/shoes, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dT" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "dU" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/head_f) "dV" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/smes_room) "dW" = ( /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "dX" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "dY" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/head_m) "dZ" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "ea" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/solar_port) "eb" = ( /obj/effect/shuttle_landmark/automatic, @@ -1643,73 +1472,55 @@ /area/space) "ec" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/obj/machinery/power/tracker{ - id = "HarpoonSolarStarboard" - }, -/turf/simulated/floor/airless, +/obj/machinery/power/tracker, +/turf/floor/plating/airless, /area/space) "ed" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ee" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ef" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, /obj/machinery/button/access/exterior{ id_tag = "Harpoon_solar_starboard_airlock"; pixel_y = 20 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/errant_pisces/solar_starboard) "eg" = ( /obj/machinery/door/airlock/external{ id_tag = "Harpoon_solar_starboard_outer" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "eh" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -1725,18 +1536,17 @@ tag_airpump = "Harpoon_solar_starboard_pump"; tag_chamber_sensor = "Harpoon_solar_starboard_sensor"; tag_exterior_door = "Harpoon_solar_starboard_outer"; - tag_interior_door = "Harpoon_solar_starboard_inner" + tag_interior_door = "Harpoon_solar_starboard_inner"; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "ei" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "ej" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ @@ -1744,37 +1554,34 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "ek" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel/random, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "el" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "em" = ( /obj/machinery/door/airlock, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "en" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/obj/effect/landmark/corpse/carp_fisher, +/obj/abstract/landmark/corpse/carp_fisher, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "eo" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "ep" = ( /obj/structure/hygiene/toilet{ @@ -1783,64 +1590,51 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "eq" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "er" = ( /obj/structure/cable/green{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/power/smes/buildable, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "es" = ( /obj/machinery/light/small{ dir = 1 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "et" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "eu" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "ev" = ( /obj/machinery/light/small{ @@ -1849,36 +1643,31 @@ /obj/structure/hygiene/toilet{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "ew" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "ex" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "ey" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "ez" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel/random, /obj/item/towel/random, /obj/item/towel/random, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "eA" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ @@ -1886,12 +1675,10 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "eB" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -1903,120 +1690,98 @@ tag_airpump = "Harpoon_solar_port_pump"; tag_chamber_sensor = "Harpoon_solar_port_sensor"; tag_exterior_door = "Harpoon_solar_port_outer"; - tag_interior_door = "Harpoon_solar_port_inner" + tag_interior_door = "Harpoon_solar_port_inner"; + dir = 4 }, /obj/machinery/airlock_sensor{ id_tag = "Harpoon_solar_port_sensor"; pixel_y = 25 }, /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "eC" = ( /obj/machinery/door/airlock/external{ id_tag = "Harpoon_solar_port_outer" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "eD" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, /obj/machinery/button/access/exterior{ id_tag = "Harpoon_solar_port_airlock"; pixel_y = 20 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/errant_pisces/solar_port) "eE" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eF" = ( -/obj/machinery/power/tracker{ - id = "HarpoonSolarPort" - }, +/obj/machinery/power/tracker, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eG" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eH" = ( /obj/machinery/door/airlock/external{ id_tag = "Harpoon_solar_starboard_inner" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "eI" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "eJ" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/head_f) "eK" = ( /obj/structure/closet/athletic_mixed, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "eL" = ( /obj/machinery/light/small{ @@ -2026,13 +1791,12 @@ dir = 10 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "eM" = ( /obj/machinery/power/terminal, /obj/structure/cable, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2041,20 +1805,16 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "eN" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2063,12 +1823,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "eO" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2077,38 +1835,33 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "eP" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "eQ" = ( -/obj/machinery/power/port_gen/pacman/mrs, +/obj/machinery/port_gen/pacman/mrs, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "eR" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/head_m) "eS" = ( /obj/machinery/light/small{ @@ -2117,41 +1870,34 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "eT" = ( /obj/structure/closet/athletic_mixed, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "eU" = ( /obj/structure/hygiene/shower{ - dir = 8; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "eV" = ( /obj/machinery/door/airlock/external{ id_tag = "Harpoon_solar_port_inner" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "eW" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ @@ -2163,15 +1909,14 @@ pixel_x = -25; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "eX" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "eY" = ( /obj/machinery/light/small{ @@ -2179,7 +1924,7 @@ }, /obj/effect/decal/cleanable/blood, /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "eZ" = ( /obj/structure/closet/athletic_mixed, @@ -2187,7 +1932,7 @@ dir = 4; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "fa" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2195,112 +1940,93 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "fb" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/power/smes/buildable, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fc" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fd" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fe" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "ff" = ( -/obj/machinery/power/port_gen/pacman/mrs, +/obj/machinery/port_gen/pacman/mrs, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fh" = ( /obj/structure/closet/athletic_mixed, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fi" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fj" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/landmark/corpse/engineer, -/turf/simulated/floor/plating, +/obj/abstract/landmark/corpse/engineer, +/turf/floor/plating, /area/errant_pisces/bow_maint) "fk" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fl" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ @@ -2312,78 +2038,72 @@ pixel_x = 25; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fm" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fn" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fo" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fp" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fq" = ( /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fr" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2392,59 +2112,53 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "ft" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "fu" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fv" = ( /obj/machinery/power/terminal, /obj/structure/cable, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fw" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fx" = ( -/obj/machinery/power/port_gen/pacman/mrs, +/obj/machinery/port_gen/pacman/mrs, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fA" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2453,38 +2167,33 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "fB" = ( /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, /area/errant_pisces/solar_port) "fC" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2493,17 +2202,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fD" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2512,22 +2217,21 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fE" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fF" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fG" = ( /obj/machinery/power/solar_control, @@ -2535,17 +2239,15 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fH" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, @@ -2554,93 +2256,79 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_starboard) "fI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "fJ" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "fK" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fL" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/green{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fM" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fN" = ( /obj/machinery/light/small{ dir = 4 }, /obj/structure/closet/crate/radiation, -/obj/item/stack/material/tritium/ten, -/obj/item/stack/material/tritium/ten, -/turf/simulated/floor/plating, +/obj/item/stack/material/aerogel/mapped/tritium/ten, +/obj/item/stack/material/aerogel/mapped/tritium/ten, +/turf/floor/plating, /area/errant_pisces/smes_room) "fO" = ( /obj/structure/hygiene/urinal{ pixel_y = 30 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fP" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fR" = ( /obj/item/stool, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -32; - pixel_y = 0 + pixel_x = -32 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -24 }, /obj/structure/cable, @@ -2648,7 +2336,7 @@ dir = 1; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fS" = ( /obj/structure/cable/yellow, @@ -2656,68 +2344,60 @@ dir = 1 }, /obj/machinery/power/solar_control{ - icon_state = "solar"; - dir = 1; - id = "HarpoonSolarPort" + dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/solar_port) "fT" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bow_maint) "fU" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "fV" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/smes_room) "fW" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "fX" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/hallway) "fY" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "fZ" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "ga" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2726,7 +2406,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2735,23 +2415,19 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gc" = ( /obj/machinery/light, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gd" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2760,38 +2436,30 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "ge" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gf" = ( /obj/machinery/light, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2800,494 +2468,462 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gh" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gi" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/rooms) "gj" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/rooms) "gk" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -32; - pixel_y = 0 + pixel_x = -32 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gl" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gm" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gn" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/dorms) "go" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/dorms) "gp" = ( /obj/structure/bed/padded, /obj/item/bedsheet/rainbow, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gq" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gr" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gs" = ( /obj/structure/bed/padded, /obj/item/bedsheet/orange, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gt" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gu" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/machinery/media/jukebox, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gv" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gw" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gx" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/rooms) "gy" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gz" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled, /area/errant_pisces/hallway) "gA" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gB" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/dorms) "gC" = ( /obj/machinery/vending/snack, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gD" = ( /obj/machinery/vending/fitness, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gE" = ( /obj/machinery/vending/cola, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gF" = ( /obj/structure/closet, /obj/random/clothing, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gG" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gH" = ( /obj/structure/closet, /obj/random/accessory, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gI" = ( /obj/structure/bed/padded, /obj/item/bedsheet, /obj/random/plushie, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gJ" = ( /obj/structure/bed/padded, /obj/item/bedsheet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gK" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gL" = ( -/obj/structure/bed/chair/comfy/green, +/obj/structure/chair/comfy/green, /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gM" = ( /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gN" = ( /obj/structure/closet/cabinet, /obj/item/clothing/shoes/jackboots, /obj/item/clothing/suit/armor/vest, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gO" = ( -/obj/structure/bed/chair/comfy/teal, +/obj/structure/chair/comfy/teal, /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gP" = ( -/obj/structure/filingcabinet/chestdrawer, -/turf/simulated/floor/wood, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/laminate, /area/errant_pisces/rooms) "gQ" = ( /obj/structure/table/gamblingtable, /obj/item/deck/cards, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gR" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "gS" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "gT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gU" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gV" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gW" = ( /obj/structure/closet, /obj/random/cash, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gX" = ( /obj/structure/closet, /obj/random/hat, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gY" = ( /obj/structure/curtain/black, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "gZ" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/turf/floor/laminate, /area/errant_pisces/rooms) "ha" = ( /obj/structure/closet, /obj/random/smokes, /obj/random/projectile, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hb" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper_bin, /obj/item/flashlight/lamp, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hc" = ( /obj/structure/closet, /obj/random/snack, /obj/random/tool, /obj/random/suit, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hd" = ( /obj/structure/table/gamblingtable, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "he" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/ashtray, /obj/random/smokes, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hf" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/wood, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/laminate, /area/errant_pisces/rooms) "hg" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, /area/errant_pisces/rooms) "hh" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 + icon_state = "1-2" }, -/turf/simulated/floor/tiled, -/area/errant_pisces/hallway) +/turf/floor/plating, +/area/errant_pisces/bridge) "hi" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "hj" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, /area/errant_pisces/dorms) "hk" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled, /area/errant_pisces/dorms) "hl" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hm" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hn" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "ho" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hp" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/obj/machinery/power/solar{ - id = "HarpoonSolarPort" - }, -/obj/machinery/power/solar{ - id = "HarpoonSolarPort" - }, -/turf/simulated/floor/airless, +/obj/machinery/power/solar, +/turf/floor/plating/airless, /area/space) "hq" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/infirmary) "hr" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hs" = ( -/obj/effect/landmark/corpse/bridgeofficer, +/obj/abstract/landmark/corpse/bridgeofficer, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "ht" = ( -/obj/structure/bed/chair/comfy/brown, +/obj/structure/chair/comfy/brown, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/wood, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate, /area/errant_pisces/rooms) "hu" = ( /obj/machinery/vending/coffee, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hv" = ( /obj/machinery/vending/cigarette, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hw" = ( /obj/structure/closet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hx" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hy" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hz" = ( /obj/machinery/alarm{ @@ -3295,374 +2931,373 @@ pixel_y = -25; req_access = newlist() }, -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hA" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/smokes, /obj/structure/cable/green, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/rooms) "hB" = ( /obj/machinery/vending/games, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hC" = ( /obj/machinery/vending/assist, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hD" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hE" = ( /obj/structure/bed/padded, /obj/item/bedsheet, /obj/random/plushie/large, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hF" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/live_storage) "hG" = ( /obj/structure/closet, -/obj/item/clothing/under/rank/medical/scrubs, -/obj/item/clothing/under/rank/medical/scrubs, -/obj/item/clothing/under/rank/medical/scrubs, -/obj/item/clothing/under/rank/nurse, -/turf/simulated/floor/plating, +/obj/item/clothing/pants/scrubs, +/obj/item/clothing/pants/scrubs, +/obj/item/clothing/pants/scrubs, +/obj/item/clothing/shirt/scrubs, +/obj/item/clothing/shirt/scrubs, +/obj/item/clothing/shirt/scrubs, +/obj/item/clothing/dress/nurse, +/turf/floor/plating, /area/errant_pisces/infirmary) "hH" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, -/obj/item/storage/box/bodybags, -/turf/simulated/floor/plating, +/obj/item/box/bodybags, +/turf/floor/plating, /area/errant_pisces/infirmary) "hI" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/infirmary) "hJ" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/infirmary) "hK" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/infirmary) "hL" = ( /obj/structure/table/steel, /obj/item/clothing/head/surgery, -/obj/item/storage/firstaid/surgery, -/obj/item/storage/firstaid/adv, -/obj/item/clothing/mask/breath/anesthetic, -/turf/simulated/floor/tiled/white, +/obj/item/firstaid/surgery, +/obj/item/firstaid/adv, +/turf/floor/tiled/white, /area/errant_pisces/infirmary) "hM" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "hN" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hO" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "hP" = ( /obj/structure/crematorium, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "hQ" = ( -/obj/structure/morgue{ - dir = 2 - }, -/turf/simulated/floor/plating, +/obj/structure/morgue, +/turf/floor/plating, /area/errant_pisces/infirmary) "hR" = ( /obj/structure/iv_drip, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "hS" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "hT" = ( /obj/machinery/computer/operating{ - icon_state = "computer"; dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/infirmary) "hU" = ( /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/infirmary) "hV" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/infirmary) "hW" = ( /obj/structure/bed/padded, /obj/item/bedsheet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "hX" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "hY" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, +/obj/structure/chair, +/turf/floor/tiled, /area/errant_pisces/infirmary) "hZ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, /obj/structure/window/basic{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "ia" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/glasses, /obj/structure/window/basic{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "ib" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "ic" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "id" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "ie" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "if" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "ig" = ( /obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "ih" = ( -/obj/item/knife/table, -/turf/simulated/floor/tiled, +/obj/item/utensil/knife, +/turf/floor/tiled, /area/errant_pisces/dorms) "ii" = ( /obj/item/stool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "ij" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/errant_pisces/dorms) "ik" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "il" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "im" = ( -/obj/effect/landmark/corpse/chef, +/obj/abstract/landmark/corpse/chef, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "in" = ( /obj/machinery/door/airlock/freezer, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "io" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "ip" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "iq" = ( /obj/machinery/button/blast_door{ id_tag = "Harpoon_bd_cell1"; name = "Cell 1 blast door-control"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "ir" = ( /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "is" = ( /obj/machinery/button/blast_door{ id_tag = "Harpoon_bd_cell2"; name = "Cell 2 blast door-control"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "it" = ( /obj/machinery/button/blast_door{ id_tag = "Harpoon_bd_cell3"; name = "Cell 3 blast door-control"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "iu" = ( /obj/machinery/button/crematorium{ - pixel_x = -20 + pixel_x = -20; + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iv" = ( /obj/machinery/light/small{ dir = 1 }, -/obj/effect/landmark/corpse/carp_fisher, +/obj/abstract/landmark/corpse/carp_fisher, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iw" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "ix" = ( /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iy" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iz" = ( /obj/machinery/door/airlock, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iA" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iB" = ( /obj/structure/curtain/medical, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iC" = ( /obj/structure/window/basic, /obj/structure/window/basic{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iD" = ( /obj/structure/closet, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iE" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iF" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/plate, +/obj/item/utensil/fork, +/turf/floor/tiled, /area/errant_pisces/dorms) "iG" = ( /obj/structure/table/marble, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "iH" = ( /obj/structure/table/marble, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/item/plate, +/turf/floor/tiled, /area/errant_pisces/dorms) "iI" = ( /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "iJ" = ( /obj/structure/closet/crate/freezer, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "iK" = ( /obj/machinery/door/blast/regular{ id_tag = "Harpoon_bd_cell1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "iL" = ( /obj/machinery/door/blast/regular{ id_tag = "Harpoon_bd_cell2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "iM" = ( /obj/machinery/door/blast/regular{ id_tag = "Harpoon_bd_cell3" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "iN" = ( /obj/structure/closet/crate/secure/biohazard, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iO" = ( /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iP" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iQ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3671,7 +3306,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "iR" = ( /obj/machinery/door/airlock, @@ -3682,7 +3317,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3691,12 +3326,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iT" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/machinery/alarm{ dir = 1; @@ -3709,7 +3344,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3718,9 +3353,9 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/effect/landmark/corpse/doctor, +/obj/abstract/landmark/corpse/doctor, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3730,7 +3365,7 @@ dir = 4 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iW" = ( /obj/machinery/door/firedoor, @@ -3740,7 +3375,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3749,7 +3384,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iY" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3758,7 +3393,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "iZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3767,35 +3402,35 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "ja" = ( /obj/machinery/body_scanconsole, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jb" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jc" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jd" = ( /obj/structure/table/marble, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "je" = ( /obj/machinery/light/small{ dir = 8 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "jf" = ( /obj/structure/lattice, @@ -3810,34 +3445,34 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "ji" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "jj" = ( /obj/structure/iv_drip, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jk" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jn" = ( /obj/machinery/bodyscanner, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3846,12 +3481,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jp" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3860,14 +3493,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jq" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3876,17 +3507,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jr" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3895,32 +3522,32 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/hallway) "js" = ( -/obj/structure/table/standard, -/obj/item/kitchen/utensil/fork/plastic, +/obj/structure/table, +/obj/item/utensil/fork/plastic, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "jt" = ( /obj/structure/table/marble, /obj/machinery/microwave, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "ju" = ( /obj/structure/table/marble, /obj/machinery/reagentgrinder/juicer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "jv" = ( -/obj/effect/landmark/corpse/carp_fisher, +/obj/abstract/landmark/corpse/carp_fisher, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "jw" = ( /obj/structure/closet/secure_closet/freezer/meat, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "jx" = ( /obj/structure/lattice, @@ -3933,12 +3560,12 @@ /obj/machinery/button/access/exterior{ id_tag = "Harpoon_ls_airlock"; pixel_x = -25; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "jz" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/science_wing) "jA" = ( /obj/machinery/door/airlock, @@ -3946,33 +3573,33 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "jB" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jC" = ( -/obj/structure/table/standard, -/obj/item/storage/box/freezer, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/box/freezer, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jD" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, -/obj/item/clothing/under/rank/medical/paramedic, +/obj/item/clothing/jumpsuit/medical/paramedic, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jE" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/roller, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3981,7 +3608,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jG" = ( /obj/machinery/door/airlock, @@ -3992,7 +3619,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/infirmary) "jH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4001,7 +3628,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jI" = ( /obj/item/stool, @@ -4013,11 +3640,10 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jJ" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, @@ -4026,42 +3652,42 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/infirmary) "jK" = ( -/obj/structure/table/standard, -/obj/item/kitchen/utensil/fork, +/obj/structure/table, +/obj/item/utensil/fork, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "jL" = ( /obj/machinery/vending/dinnerware, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "jM" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "jN" = ( /obj/machinery/cooker/oven, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/dorms) "jO" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "jP" = ( /obj/structure/closet/secure_closet/freezer/kitchen{ req_access = newlist() }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/dorms) "jQ" = ( /obj/machinery/door/airlock/external{ id_tag = "Harpoon_ls_outer" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "jR" = ( /obj/structure/lattice, @@ -4073,7 +3699,7 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "jT" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -4081,48 +3707,43 @@ }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/closet, -/obj/item/clothing/under/carp, -/turf/simulated/floor/tiled, +/obj/item/clothing/costume/carp, +/turf/floor/tiled, /area/errant_pisces/science_wing) "jU" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/errant_pisces/science_wing) "jV" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "jW" = ( /obj/machinery/photocopier, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "jX" = ( -/obj/structure/filingcabinet/chestdrawer, -/turf/simulated/floor/tiled, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled, /area/errant_pisces/science_wing) "jY" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "jZ" = ( /obj/machinery/door/airlock, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "ka" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -4134,9 +3755,9 @@ /obj/machinery/airlock_sensor{ id_tag = "Harpoon_ls_sensor"; pixel_x = -25; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "kb" = ( /obj/structure/lattice, @@ -4156,80 +3777,73 @@ dir = 8 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "ke" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/closet, -/obj/item/clothing/suit/storage/toggle/labcoat/genetics, -/turf/simulated/floor/tiled, +/obj/item/clothing/suit/toggle/labcoat/genetics, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kf" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kg" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kh" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "ki" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kj" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/cryo) "kk" = ( /obj/machinery/sleeper/standard{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kl" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "km" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/window/basic{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kn" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "ko" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -4238,46 +3852,42 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kp" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kq" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, /obj/structure/window/basic{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kr" = ( /obj/machinery/sleeper/standard{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "ks" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/general_storage) "kt" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/prod_storage) "ku" = ( /obj/machinery/door/airlock/external{ @@ -4285,7 +3895,7 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "kv" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -4295,10 +3905,10 @@ dir = 5 }, /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4308,7 +3918,7 @@ dir = 4 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4317,7 +3927,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "ky" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4328,7 +3938,7 @@ }, /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4339,12 +3949,9 @@ }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kA" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -4354,131 +3961,129 @@ dir = 1 }, /obj/structure/bookcase, -/obj/item/book/manual/anomaly_testing, -/obj/item/book/manual/anomaly_spectroscopy, -/turf/simulated/floor/tiled, +/obj/item/book/fluff/anomaly_testing, +/obj/item/book/fluff/anomaly_spectroscopy, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kB" = ( /obj/structure/bookcase, /obj/item/book/manual/mass_spectrometry, /obj/item/book/manual/engineering_guide, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kC" = ( /obj/structure/bookcase, -/obj/item/book/manual/materials_chemistry_analysis, -/turf/simulated/floor/tiled, +/obj/item/book/fluff/materials_chemistry_analysis, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kD" = ( /obj/machinery/vending/assist, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kE" = ( /obj/machinery/light{ dir = 1 }, -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kF" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "kG" = ( /obj/structure/closet, -/obj/item/clothing/suit/storage/toggle/labcoat/blue, +/obj/item/clothing/suit/toggle/labcoat/blue, /obj/random/coin, /obj/random/coin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kH" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kI" = ( /obj/structure/closet, /obj/item/clothing/suit/apron/overalls, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kJ" = ( /obj/structure/window/basic{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kL" = ( /obj/structure/window/basic{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kM" = ( /obj/structure/closet, -/obj/item/clothing/suit/storage/toggle/labcoat, -/turf/simulated/floor/tiled, +/obj/item/clothing/suit/toggle/labcoat, +/turf/floor/tiled, /area/errant_pisces/cryo) "kN" = ( /obj/structure/closet, /obj/item/clothing/suit/apron/overalls, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "kO" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/plating, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating, /area/errant_pisces/general_storage) "kP" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "kQ" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/knife/combat, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "kR" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/harpoon, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "kS" = ( -/obj/structure/table/rack, -/obj/item/storage/box/survival, -/obj/item/storage/box/survival, -/obj/item/storage/box/survival, -/turf/simulated/floor/plating, +/obj/structure/rack, +/obj/item/box/survival, +/obj/item/box/survival, +/obj/item/box/survival, +/turf/floor/plating, /area/errant_pisces/general_storage) "kT" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/general_storage) "kU" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/chems/food/snacks/fish/poison, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat/fish/poison, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "kV" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "kW" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "kX" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "kY" = ( /obj/machinery/light/small{ @@ -4487,246 +4092,244 @@ /obj/structure/window/basic{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "la" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/prod_storage) "lb" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "lc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "Harpoon_ls_airlock"; pixel_x = 25; - pixel_y = 0; tag_airpump = "Harpoon_ls_pump"; tag_chamber_sensor = "Harpoon_ls_sensor"; tag_exterior_door = "Harpoon_ls_outer"; - tag_interior_door = "Harpoon_ls_inner" + tag_interior_door = "Harpoon_ls_inner"; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "ld" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/harpoon, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "le" = ( -/obj/effect/landmark/corpse/scientist, +/obj/abstract/landmark/corpse/scientist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lf" = ( -/obj/structure/table/rack, -/turf/simulated/floor/tiled, +/obj/structure/rack, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lg" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lh" = ( /obj/machinery/light/small{ dir = 8 }, -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/plating, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating, /area/errant_pisces/general_storage) "li" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "lj" = ( /obj/structure/closet/secure_closet/freezer/fridge, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lk" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/chems/food/snacks/cubancarp, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/cubancarp, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "ll" = ( /obj/structure/window/basic{ dir = 8 }, /obj/item/chems/chem_disp_cartridge/amphetamines, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lm" = ( /obj/structure/closet/crate, -/obj/item/chems/food/snacks/fish/poison, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat/fish/poison, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "ln" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "lp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/structure/closet/firecloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lr" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "ls" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/science_wing) "lt" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lu" = ( -/obj/structure/table/standard, -/obj/item/storage/box/freezer, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/box/freezer, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lv" = ( -/obj/structure/table/standard, -/obj/item/storage/toolbox/mechanical, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/toolbox/mechanical, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lw" = ( -/obj/structure/table/standard, -/obj/item/storage/toolbox/electrical, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/toolbox/electrical, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lx" = ( -/obj/structure/table/standard, -/obj/item/tape_roll, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/tiled, /area/errant_pisces/science_wing) "ly" = ( -/obj/structure/table/standard, -/obj/item/storage/box/gloves, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/box/gloves, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lz" = ( /obj/structure/closet, -/obj/item/clothing/suit/storage/toggle/labcoat, +/obj/item/clothing/suit/toggle/labcoat, /obj/random/advdevice, /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "lA" = ( /obj/structure/closet, /obj/random/loot, /obj/random/soap, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "lB" = ( /obj/structure/closet, -/obj/item/clothing/under/hazard, -/turf/simulated/floor/tiled, +/obj/item/clothing/jumpsuit/hazard, +/turf/floor/tiled, /area/errant_pisces/cryo) "lC" = ( /obj/structure/closet, /obj/item/clothing/suit/apron/overalls, /obj/random/glasses, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "lD" = ( -/obj/structure/table/rack, -/obj/item/storage/toolbox/mechanical, -/turf/simulated/floor/plating, +/obj/structure/rack, +/obj/item/toolbox/mechanical, +/turf/floor/plating, /area/errant_pisces/general_storage) "lE" = ( -/obj/structure/table/rack, -/obj/item/storage/ore, +/obj/structure/rack, +/obj/item/ore_satchel, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "lF" = ( -/obj/structure/table/rack, -/obj/item/storage/firstaid/empty, -/turf/simulated/floor/plating, +/obj/structure/rack, +/obj/item/firstaid/empty, +/turf/floor/plating, /area/errant_pisces/general_storage) "lG" = ( /obj/item/chems/chem_disp_cartridge/mercury, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lH" = ( /obj/machinery/portable_atmospherics/canister/empty/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "lI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "lJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "lK" = ( /obj/structure/closet/l3closet/scientist, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lL" = ( /obj/structure/closet/secure_closet/scientist{ req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lM" = ( /obj/structure/closet/secure_closet/hydroponics, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lN" = ( /obj/machinery/door/window/northright, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lO" = ( /obj/machinery/vending/hydronutrients, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lP" = ( /obj/structure/window/reinforced{ @@ -4736,14 +4339,14 @@ dir = 1 }, /obj/machinery/chem_master, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lQ" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/machinery/reagentgrinder, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lR" = ( /obj/structure/window/reinforced{ @@ -4752,72 +4355,72 @@ /obj/structure/window/reinforced{ dir = 4 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/book/manual/mass_spectrometry, /obj/item/scanner/spectrometer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "lS" = ( /obj/structure/window/reinforced{ dir = 8 }, /obj/machinery/door/window/northright, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/science_wing) "lT" = ( /obj/structure/table/steel, -/obj/item/storage/firstaid/surgery, +/obj/item/firstaid/surgery, /obj/item/knife/kitchen/cleaver, -/obj/item/twohanded/fireaxe, +/obj/item/bladed/axe/fire, /obj/structure/window/reinforced{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/science_wing) "lU" = ( -/obj/vehicle/train/cargo/engine, -/turf/simulated/floor/plating, +/obj/vehicle/train/engine, +/turf/floor/plating, /area/errant_pisces/general_storage) "lV" = ( -/obj/vehicle/train/cargo/trolley, -/turf/simulated/floor/plating, +/obj/vehicle/train/trolley, +/turf/floor/plating, /area/errant_pisces/general_storage) "lW" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/chems/food/snacks/fish/poison, -/obj/item/chems/food/snacks/fish/poison, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat/fish/poison, +/obj/item/food/butchery/meat/fish/poison, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lX" = ( /obj/structure/window/basic{ dir = 8 }, /obj/structure/closet/crate, -/obj/item/chems/food/snacks/fish/poison, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat/fish/poison, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lY" = ( /obj/structure/closet/crate, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "lZ" = ( /obj/structure/closet/secure_closet/freezer/meat, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "ma" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "mb" = ( /obj/structure/lattice, /obj/machinery/button/access/exterior{ id_tag = "Harpoon_sci_airlock"; - pixel_y = -20 + pixel_y = -20; + dir = 1 }, /turf/space, /area/errant_pisces/science_wing) @@ -4825,7 +4428,7 @@ /obj/machinery/door/airlock/external{ id_tag = "Harpoon_sci_outer" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "md" = ( /obj/machinery/light/small{ @@ -4837,18 +4440,18 @@ }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "Harpoon_sci_airlock"; - pixel_x = 0; pixel_y = -25; tag_airpump = "Harpoon_sci_pump"; tag_chamber_sensor = "Harpoon_sci_sensor"; tag_exterior_door = "Harpoon_sci_outer"; - tag_interior_door = "Harpoon_sci_inner" + tag_interior_door = "Harpoon_sci_inner"; + dir = 1 }, /obj/machinery/airlock_sensor{ id_tag = "Harpoon_sci_sensor"; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "me" = ( /obj/machinery/door/airlock/external{ @@ -4857,7 +4460,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "mf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4868,58 +4471,58 @@ pixel_x = -25; pixel_y = -25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "mg" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "mh" = ( /obj/structure/closet/l3closet/scientist, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mi" = ( /obj/structure/closet/secure_closet/scientist{ req_access = newlist() }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mj" = ( /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mk" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "ml" = ( /obj/structure/window/reinforced{ dir = 8 }, /obj/machinery/chemical_dispenser/full, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mm" = ( /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mn" = ( /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/science_wing) "mo" = ( /obj/machinery/light{ @@ -4927,67 +4530,66 @@ icon_state = "tube1" }, /obj/machinery/computer/operating{ - icon_state = "computer"; dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/science_wing) "mp" = ( /obj/structure/closet, -/obj/item/clothing/suit/storage/hooded/wintercoat, -/turf/simulated/floor/tiled, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/tiled, /area/errant_pisces/cryo) "mq" = ( /obj/structure/closet, /obj/random/plushie, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "mr" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "ms" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/stack/net/thirty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "mt" = ( /obj/machinery/light/small{ dir = 4 }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/stack/net, /obj/random/snack, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "mu" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mv" = ( /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mw" = ( /obj/structure/window/basic{ dir = 8 }, /obj/structure/closet/crate, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mx" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, /obj/item/harpoon, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "my" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -4997,60 +4599,56 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "mz" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/aft_hallway) "mA" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "mB" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "mC" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mD" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, /obj/structure/closet/secure_closet/scientist{ req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mE" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mF" = ( /obj/structure/window/reinforced{ dir = 8 }, -/obj/structure/table/standard, -/obj/item/storage/box/beakers, +/obj/structure/table, +/obj/item/box/beakers, /obj/item/chems/dropper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mG" = ( /obj/machinery/biogenerator, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mH" = ( /obj/structure/window/reinforced{ @@ -5059,43 +4657,42 @@ /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mI" = ( /obj/machinery/optable, /obj/item/clothing/glasses/welding, /obj/item/weldingtool, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/science_wing) "mJ" = ( /obj/machinery/light, -/obj/effect/landmark/corpse/carp_fisher, +/obj/abstract/landmark/corpse/carp_fisher, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "mK" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "mL" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "mM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "mN" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -5105,156 +4702,142 @@ dir = 1; pixel_y = -22 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "mO" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/general_storage) "mP" = ( /obj/machinery/alarm{ dir = 1; pixel_y = -22 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mQ" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, /obj/structure/cable/green{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mS" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/machinery/light/small, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mT" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "mU" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/obj/structure/table/rack, -/turf/simulated/floor/plating, +/obj/structure/rack, +/turf/floor/plating, /area/errant_pisces/live_storage) "mV" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "mW" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/science_wing) "mX" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) "mY" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "mZ" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/cryo) "na" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, /area/errant_pisces/general_storage) "nb" = ( /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock/freezer, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, /area/errant_pisces/prod_storage) "nc" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/live_storage) "nd" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/live_storage) "ne" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5265,10 +4848,9 @@ }, /obj/machinery/button/access/interior{ id_tag = "Harpoon_dock1_airlock"; - pixel_x = 0; - pixel_y = 25 + pixel_y = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "nf" = ( /obj/machinery/door/airlock/external{ @@ -5278,7 +4860,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "ng" = ( /obj/machinery/light/small{ @@ -5290,18 +4872,18 @@ }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "Harpoon_dock1_airlock"; - pixel_x = 0; pixel_y = -25; tag_airpump = "Harpoon_dock1_pump"; tag_chamber_sensor = "Harpoon_dock1_sensor"; tag_exterior_door = "Harpoon_dock1_outer"; - tag_interior_door = "Harpoon_dock1_inner" + tag_interior_door = "Harpoon_dock1_inner"; + dir = 1 }, /obj/machinery/airlock_sensor{ id_tag = "Harpoon_dock1_sensor"; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "nh" = ( /obj/machinery/door/airlock/external{ @@ -5309,63 +4891,54 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/errant_pisces/aft_hallway) -"ni" = ( /obj/machinery/button/access/exterior{ id_tag = "Harpoon_dock1_airlock"; - pixel_x = -25; - pixel_y = -25 + pixel_y = -22; + dir = 1 }, -/turf/simulated/floor/plating, -/area/space) -"nj" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, +/area/errant_pisces/aft_hallway) +"ni" = ( +/obj/effect/shuttle_landmark/automatic{ + dir = 8 + }, +/turf/space, /area/space) "nk" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/aux_power) "nl" = ( -/obj/machinery/power/port_gen/pacman/mrs, +/obj/machinery/port_gen/pacman/mrs, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "nm" = ( /obj/machinery/power/terminal{ dir = 4 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "nn" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable/green{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "no" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5374,12 +4947,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "np" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5388,12 +4959,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nq" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5402,12 +4971,10 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nr" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5419,19 +4986,14 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "ns" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5440,17 +5002,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nt" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5459,14 +5017,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nu" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5475,29 +5031,25 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5506,38 +5058,29 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nx" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "ny" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5546,75 +5089,61 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nz" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nC" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5622,25 +5151,18 @@ }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nE" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -5649,41 +5171,35 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nF" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nG" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nI" = ( /obj/machinery/door/airlock, @@ -5691,137 +5207,138 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nJ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "nK" = ( -/obj/machinery/power/port_gen/pacman/mrs, +/obj/machinery/port_gen/pacman/mrs, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "nL" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "nM" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/green{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, /area/errant_pisces/aux_power) "nN" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, /area/errant_pisces/aux_power) "nO" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nP" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nR" = ( -/obj/effect/landmark/corpse/scientist, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/corpse/scientist, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nS" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nT" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nU" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -24 }, /obj/structure/cable/green, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nV" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nW" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nX" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "nZ" = ( /obj/machinery/door/firedoor, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "oa" = ( -/obj/effect/landmark/corpse/bridgeofficer, +/obj/abstract/landmark/corpse/bridgeofficer, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/aft_hallway) "ob" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "oc" = ( /obj/machinery/power/terminal, @@ -5829,15 +5346,15 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "od" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "oe" = ( /obj/structure/closet/crate/radiation, -/obj/item/stack/material/tritium/ten, -/obj/machinery/power/apc{ +/obj/item/stack/material/aerogel/mapped/tritium/ten, +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 @@ -5847,46 +5364,42 @@ dir = 1; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "of" = ( /obj/machinery/door/firedoor, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "og" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/fishing_wing) "oh" = ( /obj/machinery/door/airlock/freezer, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oi" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bridge) "oj" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "ok" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5894,10 +5407,10 @@ }, /obj/machinery/button/access/interior{ id_tag = "Harpoon_dock2_airlock"; - pixel_x = 0; - pixel_y = -25 + pixel_y = -22; + dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "ol" = ( /obj/machinery/door/airlock/external{ @@ -5907,7 +5420,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "om" = ( /obj/machinery/light/small{ @@ -5919,18 +5432,18 @@ }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "Harpoon_dock2_airlock"; - pixel_x = 0; pixel_y = -25; tag_airpump = "Harpoon_dock2_pump"; tag_chamber_sensor = "Harpoon_dock2_sensor"; tag_exterior_door = "Harpoon_dock2_outer"; - tag_interior_door = "Harpoon_dock2_inner" + tag_interior_door = "Harpoon_dock2_inner"; + dir = 1 }, /obj/machinery/airlock_sensor{ id_tag = "Harpoon_dock2_sensor"; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aft_hallway) "on" = ( /obj/machinery/door/airlock/external{ @@ -5938,62 +5451,53 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/errant_pisces/aft_hallway) -"oo" = ( /obj/machinery/button/access/exterior{ id_tag = "Harpoon_dock2_airlock"; - pixel_x = -25; - pixel_y = -25 + pixel_y = -22; + dir = 1 }, -/turf/simulated/floor/plating, -/area/space) +/turf/floor/plating, +/area/errant_pisces/aft_hallway) "op" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable/green{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "oq" = ( /obj/structure/cable/green{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "or" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/wrench, /obj/item/screwdriver, /obj/item/wirecutters, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/aux_power) "os" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "ot" = ( -/turf/simulated/wall, +/turf/wall, /area/errant_pisces/fishing_wing) "ou" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "ov" = ( /obj/structure/table/marble, @@ -6001,84 +5505,78 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "ow" = ( /obj/machinery/gibber, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "ox" = ( /obj/structure/table/marble, -/obj/item/chems/food/snacks/fish/poison, -/obj/item/chems/food/snacks/fish/poison, -/obj/item/chems/food/snacks/fish/poison, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat/fish/poison, +/obj/item/food/butchery/meat/fish/poison, +/obj/item/food/butchery/meat/fish/poison, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oy" = ( /obj/machinery/gibber, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oz" = ( /obj/structure/table/marble, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oA" = ( /obj/structure/hygiene/sink{ dir = 1; pixel_y = 16 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oB" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oC" = ( /obj/structure/closet/crate, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oD" = ( /obj/random/obstruction, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oE" = ( /obj/machinery/door/airlock/freezer, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oF" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/landmark/corpse/bridgeofficer, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/corpse/bridgeofficer, +/turf/floor/tiled, /area/errant_pisces/bridge) "oH" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "oI" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -6087,10 +5585,9 @@ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "oJ" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -6100,42 +5597,44 @@ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oK" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "oL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable/green, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled, /area/errant_pisces/bridge) "oM" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/structure/closet/firecloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oN" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oO" = ( /obj/structure/table/steel, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oP" = ( /obj/machinery/light{ @@ -6143,43 +5642,40 @@ }, /obj/structure/table/steel, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oQ" = ( /obj/structure/bookcase/manuals/engineering, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oR" = ( /obj/structure/bookcase, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oS" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oT" = ( -/obj/structure/bed/chair/comfy/captain, -/turf/simulated/floor/tiled, +/obj/structure/chair/comfy/captain, +/turf/floor/tiled, /area/errant_pisces/bridge) "oU" = ( /obj/machinery/light{ dir = 1 }, /obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "oV" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "oW" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "oX" = ( /obj/machinery/light{ @@ -6191,54 +5687,44 @@ /obj/random/ammo, /obj/random/cash, /obj/random/cash, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "oY" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "oZ" = ( /obj/machinery/vending/medical{ req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pa" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pb" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/landmark/corpse/carp_fisher, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/corpse/carp_fisher, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pc" = ( /obj/structure/cable/green{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pd" = ( /obj/structure/cable/green{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/green{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -6246,11 +5732,11 @@ /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pe" = ( /obj/structure/closet/crate/secure/biohazard, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "pf" = ( /obj/structure/net, @@ -6260,55 +5746,56 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled, /area/errant_pisces/bridge) "ph" = ( /obj/random/tool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pi" = ( /obj/machinery/computer/ship/navigation{ - icon_state = "computer"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pj" = ( /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pk" = ( /obj/structure/table/steel, /obj/random/toy, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pl" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "pm" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "pn" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/turf/floor/laminate, /area/errant_pisces/bridge) "po" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/bridge) "pp" = ( /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/errant_pisces/bridge) "pq" = ( /obj/structure/lattice, @@ -6319,11 +5806,11 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "ps" = ( /obj/structure/cable/green, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 @@ -6332,20 +5819,20 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pt" = ( -/obj/structure/kitchenspike, -/turf/simulated/floor/tiled/freezer, +/obj/structure/meat_hook, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "pu" = ( -/obj/structure/kitchenspike, +/obj/structure/meat_hook, /obj/machinery/light/small, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "pv" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "pw" = ( /obj/structure/net/net_wall, @@ -6356,78 +5843,82 @@ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, -/turf/simulated/floor/tiled, +/obj/structure/cable/green{ + icon_state = "1-6" + }, +/turf/floor/tiled, /area/errant_pisces/bridge) "py" = ( /obj/random/junk, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pz" = ( /obj/effect/overmap/visitable/ship/errant_pisces, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pA" = ( /obj/structure/table/steel, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pB" = ( /obj/structure/bookcase/manuals/engineering, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "pC" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/toy, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "pD" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/fishing_wing) "pE" = ( /mob/living/simple_animal/hostile/carp/shark, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/fishing_wing) "pF" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/fishing_wing) "pG" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pI" = ( /obj/machinery/door/airlock/freezer, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/errant_pisces/fishing_wing) "pJ" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/table/steel, /obj/random/snack, -/turf/simulated/floor/tiled, +/obj/structure/cable/green{ + icon_state = "6-9" + }, +/turf/floor/tiled, /area/errant_pisces/bridge) "pK" = ( /obj/structure/table/steel, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pL" = ( -/obj/structure/bed/chair/office/dark, -/turf/simulated/floor/tiled, +/obj/structure/chair/office/dark, +/turf/floor/tiled, /area/errant_pisces/bridge) "pM" = ( /obj/machinery/light{ @@ -6436,31 +5927,31 @@ }, /obj/structure/table/steel, /obj/random/handgun, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "pN" = ( /obj/structure/curtain/open/bed, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "pO" = ( /obj/structure/hygiene/shower{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/fishing_wing) "pP" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pQ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "pR" = ( /obj/machinery/door/airlock, @@ -6471,7 +5962,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -6480,7 +5971,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pT" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -6489,14 +5980,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pU" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -6505,7 +5993,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -6514,7 +6002,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pW" = ( /obj/machinery/door/airlock, @@ -6525,14 +6013,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pX" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -6541,13 +6026,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pY" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "pZ" = ( /obj/structure/net, @@ -6556,30 +6041,32 @@ /area/space) "qa" = ( /obj/machinery/computer/ship/sensors{ - icon_state = "computer"; dir = 4 }, -/turf/simulated/floor/tiled, +/obj/structure/cable/green{ + icon_state = "2-9" + }, +/turf/floor/tiled, /area/errant_pisces/bridge) "qb" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qc" = ( /obj/structure/table/steel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qd" = ( /obj/structure/table/steel, /obj/random/toolbox, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qe" = ( /obj/structure/table/steel, /obj/random/advdevice, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qf" = ( /obj/structure/table/steel, @@ -6587,169 +6074,168 @@ id_tag = "Harpoon_perimeter_blast"; name = "perimeter blast door-control" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qg" = ( /obj/machinery/computer/ship/helm{ - icon_state = "computer"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qh" = ( /obj/machinery/computer/ship/engines{ - icon_state = "computer"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/bridge) "qi" = ( /obj/item/bedsheet/captain, /obj/structure/bed/padded, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/errant_pisces/bridge) "qj" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qk" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "ql" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qm" = ( /obj/structure/closet/l3closet/janitor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qn" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/mask/breath, -/obj/item/storage/box/survival, +/obj/item/box/survival, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qo" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qp" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/suit_cycler, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qq" = ( /obj/structure/janitorialcart, /obj/item/mop, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "qr" = ( /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "qs" = ( /obj/machinery/light/small{ dir = 8 }, -/obj/structure/table/rack, -/turf/simulated/floor/plating, +/obj/structure/rack, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qt" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/random/contraband, /obj/structure/closet/l3closet/janitor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qu" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/tank/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qw" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qx" = ( /obj/machinery/shipsensors, -/turf/simulated/floor/reinforced/airless, +/obj/structure/cable/green, +/turf/floor/reinforced/airless, /area/errant_pisces/bridge) "qy" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "qz" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/fishing_wing) "qA" = ( -/obj/structure/table/rack, -/turf/simulated/floor/plating, +/obj/structure/rack, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qB" = ( /obj/structure/closet, /obj/random/smokes, /obj/random/drinkbottle, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qC" = ( /obj/structure/lattice, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/errant_pisces/bridge) "qD" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/knife/combat, /obj/item/knife/combat, /obj/item/stack/net/thirty, /obj/item/stack/net/thirty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qE" = ( /obj/structure/closet, /obj/random/smokes, /obj/random/snack, /obj/random/tank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qF" = ( -/obj/structure/table/rack, -/obj/item/storage/box/survival, +/obj/structure/rack, +/obj/item/box/survival, /obj/item/stack/net/thirty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qG" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qH" = ( /obj/structure/grille, @@ -6759,46 +6245,46 @@ /obj/machinery/light/small{ dir = 8 }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/harpoon, /obj/item/harpoon, /obj/item/harpoon, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qJ" = ( /obj/structure/closet, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/random/gloves, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qK" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/mask/breath, /obj/item/flashlight, /obj/item/stack/net/thirty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qL" = ( -/obj/effect/landmark/corpse/carp_fisher, +/obj/abstract/landmark/corpse/carp_fisher, /obj/effect/decal/cleanable/blood, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qM" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/space) "qN" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/plating, +/obj/structure/chair, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qP" = ( /obj/effect/decal/cleanable/blood, @@ -6810,7 +6296,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qQ" = ( /obj/machinery/door/airlock/external{ @@ -6821,7 +6307,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qR" = ( /obj/machinery/light/small{ @@ -6830,12 +6316,12 @@ /obj/effect/decal/cleanable/blood, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "Harpoon_fish_airlock"; - pixel_x = 0; pixel_y = -25; tag_airpump = "Harpoon_fish_pump"; tag_chamber_sensor = "Harpoon_fish_sensor"; tag_exterior_door = "Harpoon_fish_outer"; - tag_interior_door = "Harpoon_fish_inner" + tag_interior_door = "Harpoon_fish_inner"; + dir = 1 }, /obj/machinery/airlock_sensor{ id_tag = "Harpoon_fish_sensor"; @@ -6845,7 +6331,7 @@ dir = 8; id_tag = "Harpoon_fish_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qS" = ( /obj/machinery/door/airlock/external{ @@ -6853,11 +6339,10 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Harpoon_perimeter_blast" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/space) "qT" = ( /obj/structure/net, @@ -6869,36 +6354,36 @@ /turf/space, /area/space) "qU" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qV" = ( /obj/structure/table/steel, /obj/random/smokes, -/obj/item/flame/lighter/random, -/turf/simulated/floor/plating, +/obj/item/flame/fuelled/lighter/random, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qW" = ( /obj/structure/table/steel, /obj/random/snack, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qX" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/item/flame/match, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qY" = ( -/obj/structure/dispenser/oxygen, -/turf/simulated/floor/plating, +/obj/structure/tank_rack/oxygen, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "qZ" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/errant_pisces/fishing_wing) "ra" = ( /obj/structure/net, @@ -6907,7 +6392,7 @@ /area/space) "rb" = ( /obj/structure/net, -/obj/item/chems/food/snacks/meat/syntiflesh, +/obj/item/food/butchery/meat/syntiflesh, /turf/space, /area/space) "rc" = ( @@ -6917,54 +6402,52 @@ /area/space) "sb" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -30 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_f) "tb" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = 30 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) "ub" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = 30 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/green{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/errant_pisces/head_m) +"QS" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, +/area/errant_pisces/atmos) "Ti" = ( /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/errant_pisces/science_wing) (1,1,1) = {" @@ -21179,27 +20662,27 @@ aa aa aV aa -bu -bu -bu -bu -bu -bu -bu -bu -bu -bu +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp ed -bu -bu -bu -bu -bu -bu -bu -bu -bu -bu +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp aa hq hq @@ -21583,27 +21066,27 @@ aa aa aV aa -bw -bw -bw -bw -bw -bw -bw -bw -bw -bw +bR +bR +bR +bR +bR +bR +bR +bR +bR +bR ed -bw -bw -bw -bw -bw -bw -bw -bw -bw -bw +bR +bR +bR +bR +bR +bR +bR +bR +bR +bR aa hq hq @@ -21987,26 +21470,26 @@ aa aa aV aa -bu -bu -bu -bu -bu -bu -bu -bu -bu -bu +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp ed -bu -bu -bu -bu -bu -bu -bu -bu -bu +hp +hp +hp +hp +hp +hp +hp +hp +hp aa aa hq @@ -22391,26 +21874,26 @@ aa aa aV aa -bw -bw -bw -bw -bw -bw -bw -bw -bw -bw +bR +bR +bR +bR +bR +bR +bR +bR +bR +bR ed -bw -bw -bw -bw -bw -bw -bw -bw -bw +bR +bR +bR +bR +bR +bR +bR +bR +bR aa hq hq @@ -22795,26 +22278,26 @@ aa aa aV aa -bu -bu -bu -bu -bu -bu -bu -bu -bu -bu +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp ed -bu -bu -bu -bu -bu -bu -bu -bu -bu +hp +hp +hp +hp +hp +hp +hp +hp +hp aa hq hq @@ -23199,26 +22682,26 @@ aa aa aV aa -bw -bw -bw -bw -bw -bw -bw -bw -bw -bw +bR +bR +bR +bR +bR +bR +bR +bR +bR +bR ed -bw -bw -bw -bw -bw -bw -bw -bw -bw +bR +bR +bR +bR +bR +bR +bR +bR +bR aa hq hq @@ -25827,7 +25310,7 @@ aY bh bA bV -bV +QS cw cM cZ @@ -26855,7 +26338,7 @@ gd gk gy fZ -hh +gd fZ fZ fZ @@ -27259,7 +26742,7 @@ gd gm gA fZ -hh +gd fZ fZ hM @@ -27440,7 +26923,7 @@ at aA aN aZ -bl +bn bH ca cn @@ -29508,7 +28991,7 @@ oS oS pK qa -po +hh qx pp qH @@ -30875,26 +30358,26 @@ aa aa aV aa -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp ed -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ +hp +hp +hp +hp +hp +hp +hp +hp +hp hp aa hF @@ -31683,26 +31166,26 @@ aa aa aV aa -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp ed -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ +hp +hp +hp +hp +hp +hp +hp +hp +hp hp aa hF @@ -32491,26 +31974,26 @@ aa aa aV aa -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ +hp +hp +hp +hp +hp +hp +hp +hp +hp +hp ed -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ -bQ +hp +hp +hp +hp +hp +hp +hp +hp +hp hp aa hF @@ -34345,12 +33828,12 @@ aa aa aa aa -bc +aa +ni +aa +aa ni -bc -bc -oo -bc +aa aa aa aa @@ -34547,12 +34030,12 @@ aa aa aa aa -bc -nj -bc -bc -nj -bc +aa +aa +aa +aa +aa +aa aa aa aa @@ -34749,12 +34232,12 @@ aa aa aa aa -bc -bc -bc -bc -bc -bc +aa +aa +aa +aa +aa +aa aa aa aa diff --git a/maps/away/errant_pisces/errant_pisces_areas.dm b/maps/away/errant_pisces/errant_pisces_areas.dm index 7298ff0e47dc..dedee8fc0250 100644 --- a/maps/away/errant_pisces/errant_pisces_areas.dm +++ b/maps/away/errant_pisces/errant_pisces_areas.dm @@ -1,102 +1,102 @@ -area/errant_pisces - icon = 'maps/away/errant_pisces/errant_pisces_areas_sprites.dmi'//24 areas so sprites are in a separate .dmi +/area/errant_pisces + icon = 'maps/away/errant_pisces/icons/areas.dmi' -area/errant_pisces/bow_port +/area/errant_pisces/bow_port name = "Bow Port" icon_state = "bow_port" -area/errant_pisces/bow_starboard +/area/errant_pisces/bow_starboard name = "Bow Starboard" icon_state = "bow_starboard" -area/errant_pisces/bow_maint +/area/errant_pisces/bow_maint name = "Bow Maintenace" icon_state = "bow_maint" -area/errant_pisces/storage_port +/area/errant_pisces/storage_port name = "Port Storage" icon_state = "storage_port" -area/errant_pisces/storage_starboard +/area/errant_pisces/storage_starboard name = "Starboard Storage" icon_state = "storage_starboard" -area/errant_pisces/solar_port +/area/errant_pisces/solar_port name = "Port Solars" icon_state = "solar_port" -area/errant_pisces/solar_starboard +/area/errant_pisces/solar_starboard name = "Starboard Solars" icon_state = "solar_starboard" -area/errant_pisces/atmos +/area/errant_pisces/atmos name = "Atmospherics" icon_state = "atmos" -area/errant_pisces/enginering +/area/errant_pisces/enginering name = "Engineering" icon_state = "enginering" -area/errant_pisces/head_f +/area/errant_pisces/head_f name = "Head, F" icon_state = "head_f" -area/errant_pisces/head_m +/area/errant_pisces/head_m name = "Head, M" icon_state = "head_m" -area/errant_pisces/smes_room +/area/errant_pisces/smes_room name = "SMES Room" icon_state = "smes_room" -area/errant_pisces/hallway +/area/errant_pisces/hallway name = "Central Hallway" icon_state = "hallway" -area/errant_pisces/dorms +/area/errant_pisces/dorms name = "Dorms" icon_state = "dorms" -area/errant_pisces/rooms +/area/errant_pisces/rooms name = "Rooms" icon_state = "rooms" -area/errant_pisces/infirmary +/area/errant_pisces/infirmary name = "Infirmary" icon_state = "infirmary" -area/errant_pisces/cryo +/area/errant_pisces/cryo name = "Cryo" icon_state = "cryo" -area/errant_pisces/aft_hallway +/area/errant_pisces/aft_hallway name = "Aft Hallway" icon_state = "aft_hallway" -area/errant_pisces/science_wing +/area/errant_pisces/science_wing name = "Science Wing" icon_state = "science_wing" -area/errant_pisces/aux_power +/area/errant_pisces/aux_power name = "Auxilary Power Room" icon_state = "aux_power" -area/errant_pisces/fishing_wing +/area/errant_pisces/fishing_wing name = "Fishing Wing" icon_state = "fishing_wing" -area/errant_pisces/bridge - name = "Bridge" +/area/errant_pisces/bridge + name = "Trawler Bridge" icon_state = "bridge" -area/errant_pisces/prod_storage +/area/errant_pisces/prod_storage name = "Production Storage" icon_state = "prod_storage" -area/errant_pisces/general_storage +/area/errant_pisces/general_storage name = "General Storage" icon_state = "general_storage" -area/errant_pisces/live_storage +/area/errant_pisces/live_storage name = "Live Storage" icon_state = "live_storage" diff --git a/maps/away/errant_pisces/errant_pisces_sprites.dmi b/maps/away/errant_pisces/errant_pisces_sprites.dmi deleted file mode 100644 index 0586ece844ef..000000000000 Binary files a/maps/away/errant_pisces/errant_pisces_sprites.dmi and /dev/null differ diff --git a/maps/away/errant_pisces/errant_pisces_areas_sprites.dmi b/maps/away/errant_pisces/icons/areas.dmi similarity index 100% rename from maps/away/errant_pisces/errant_pisces_areas_sprites.dmi rename to maps/away/errant_pisces/icons/areas.dmi diff --git a/maps/away/errant_pisces/icons/carpsuit.dmi b/maps/away/errant_pisces/icons/carpsuit.dmi new file mode 100644 index 000000000000..8d69ca911548 Binary files /dev/null and b/maps/away/errant_pisces/icons/carpsuit.dmi differ diff --git a/maps/away/errant_pisces/icons/cosmoshark.dmi b/maps/away/errant_pisces/icons/cosmoshark.dmi new file mode 100644 index 000000000000..3b09e99a1034 Binary files /dev/null and b/maps/away/errant_pisces/icons/cosmoshark.dmi differ diff --git a/maps/away/errant_pisces/icons/net.dmi b/maps/away/errant_pisces/icons/net.dmi new file mode 100644 index 000000000000..56ba3955c64c Binary files /dev/null and b/maps/away/errant_pisces/icons/net.dmi differ diff --git a/maps/away/errant_pisces/icons/net_roll.dmi b/maps/away/errant_pisces/icons/net_roll.dmi new file mode 100644 index 000000000000..451c6a17b422 Binary files /dev/null and b/maps/away/errant_pisces/icons/net_roll.dmi differ diff --git a/maps/away/liberia/hud.dmi b/maps/away/liberia/hud.dmi new file mode 100644 index 000000000000..01fe4cbfcd4f Binary files /dev/null and b/maps/away/liberia/hud.dmi differ diff --git a/maps/away/liberia/liberia.dm b/maps/away/liberia/liberia.dm new file mode 100644 index 000000000000..e9a8a470d28a --- /dev/null +++ b/maps/away/liberia/liberia.dm @@ -0,0 +1,39 @@ +#include "liberia_areas.dm" +#include "liberia_jobs.dm" +#include "liberia_shuttles.dm" +#include "liberia_machinery.dm" + +// Map template data. +/datum/map_template/ruin/away_site/liberia + name = "Liberia" + description = "A Merchant ship." + suffixes = list("liberia/liberia.dmm") + cost = 1 + area_usage_test_exempted_root_areas = list(/area/liberia) + shuttles_to_initialise = list( + /datum/shuttle/autodock/overmap/mule + ) + +// Overmap objects. +/obj/effect/overmap/visitable/ship/liberia + name = "Liberia" + desc = "Sensors detect a merchant ship." + color = "#8a6642" + vessel_mass = 3000 + fore_dir = WEST + max_speed = 1/(1 SECOND) + sector_flags = OVERMAP_SECTOR_KNOWN + initial_restricted_waypoints = list( + /datum/shuttle/autodock/overmap/mule = list("nav_mule_start") + ) + +/obj/abstract/submap_landmark/joinable_submap/liberia + name = "Liberia" + archetype = /decl/submap_archetype/liberia + +/obj/machinery/power/smes/buildable/preset/liberia + _input_maxed = TRUE + _output_maxed = TRUE + _input_on = TRUE + _output_on = TRUE + _fully_charged = TRUE diff --git a/maps/away/liberia/liberia.dmm b/maps/away/liberia/liberia.dmm new file mode 100644 index 000000000000..8d9c0495340a --- /dev/null +++ b/maps/away/liberia/liberia.dmm @@ -0,0 +1,49080 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/obj/machinery/power/smes/buildable/preset/liberia, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"ac" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "merchant_station_exterior"; + locked = 1; + name = "Station Exterior" + }, +/obj/machinery/shield_diffuser, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/dockinghall) +"ad" = ( +/obj/structure/chair/comfy/captain{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/mono, +/obj/abstract/submap_landmark/joinable_submap/liberia, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"ae" = ( +/obj/item/scanner/health, +/obj/item/scanner/gas, +/obj/item/scanner/mining, +/obj/item/scanner/autopsy, +/obj/item/scanner/plant, +/obj/item/scanner/price, +/obj/item/scanner/xenobio, +/obj/item/t_scanner, +/obj/item/gps, +/obj/item/gps, +/obj/structure/rack/dark, +/obj/random/maintenance/clean, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"af" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/rd, +/obj/item/secure_storage/safe{ + pixel_x = 34 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/carpet/red, +/area/liberia/captain) +"ag" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/brown, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/turf/floor/carpet, +/area/liberia/personellroom2) +"ah" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/brown, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/alarm/liberia{ + dir = 8; + pixel_x = 25 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/carpet, +/area/liberia/personellroom2) +"ak" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"al" = ( +/obj/structure/closet/secure_closet{ + name = "merchant's locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"aq" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"ar" = ( +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/junction/mirrored, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"as" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor/corner, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"at" = ( +/obj/structure/closet, +/obj/random/shoes, +/obj/random/shoes, +/obj/random/gloves, +/obj/random/clothing, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"au" = ( +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"ay" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "merch_radaway" + }, +/obj/machinery/door/window/northleft{ + dir = 8; + name = "Checkpoint's Desk"; + req_access = newlist() + }, +/obj/machinery/door/window/northleft{ + autoset_access = 0; + dir = 4; + name = "Checkpoint's Desk"; + req_access = newlist() + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/liberia/engineeringreactor) +"az" = ( +/obj/machinery/meter/turf, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = 30 + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "merch_radaway" + }, +/turf/floor, +/area/liberia/engineeringreactor) +"aA" = ( +/obj/machinery/port_gen/pacman/super/potato, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor, +/area/liberia/engineeringreactor) +"aC" = ( +/obj/machinery/door/window/brigdoor/northleft{ + dir = 4; + req_access = newlist() + }, +/obj/random/hardsuit, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/rack/dark, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"aD" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/techfloor{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"aE" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/computer/ship/engines, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringengines) +"aF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 10 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"aG" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 10 + }, +/obj/effect/floor_decal/techfloor/corner, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"aH" = ( +/obj/machinery/button/blast_door{ + dir = 8; + id_tag = "merch_radaway"; + name = "Radiation shields"; + pixel_x = 24 + }, +/obj/item/caution/cone, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"aI" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/merchantstorage) +"aK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/wall/r_wall/prepainted, +/area/liberia/captain) +"aM" = ( +/obj/effect/floor_decal/techfloor{ + dir = 9 + }, +/obj/structure/closet/emcloset{ + anchored = 1; + name = "anchored emergency closet" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringengines) +"aN" = ( +/obj/effect/floor_decal/techfloor{ + dir = 5 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringengines) +"aO" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"aP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/blast/shutters{ + id_tag = "merchantwarehouse"; + name = "Warehouse Shutters" + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/button/blast_door{ + id_tag = "merchantwarehouse"; + name = "Warehouse Shutters"; + pixel_x = -24; + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"aQ" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/blast/shutters{ + id_tag = "merchantwarehouse"; + name = "Warehouse Shutters" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"aR" = ( +/obj/machinery/shield_generator/mapped, +/obj/structure/cable, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"aU" = ( +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"aV" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance"; + req_access = newlist() + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"aW" = ( +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/firedoor, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"aX" = ( +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"aY" = ( +/obj/machinery/door/airlock/double/glass/maintenance{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"aZ" = ( +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"bb" = ( +/obj/effect/paint/red, +/obj/structure/shuttle/engine/heater{ + dir = 4 + }, +/obj/effect/paint_stripe/red, +/turf/wall/r_titanium, +/area/liberia/mule) +"bc" = ( +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"be" = ( +/obj/machinery/disposal, +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/effect/floor_decal/corner/green, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bf" = ( +/obj/structure/closet/crate, +/obj/random/loot, +/obj/random/loot, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bg" = ( +/obj/structure/rack, +/obj/random/loot, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/liberia/traidingroom) +"bj" = ( +/obj/machinery/vending/fashionvend, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bk" = ( +/obj/structure/table/steel, +/obj/item/paper_bin, +/obj/item/pen, +/obj/item/flashlight, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bl" = ( +/obj/structure/rack, +/obj/item/bag/cash, +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/effect/floor_decal/corner/green{ + dir = 8 + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/obj/item/cash/c1000{ + desc = "It's worth 13000 Thalers. Who the fuck made it?" + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bm" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "merch-ship_windows" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/bridge) +"bn" = ( +/obj/structure/chair/wood/walnut, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled, +/area/liberia/hallway) +"bo" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "merchantshuttle"; + name = "Merchant Window Shutters" + }, +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/liberia/mule) +"bp" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 6 + }, +/turf/wall/r_titanium, +/area/liberia/mule) +"bq" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 8; + external_pressure_bound = 140; + external_pressure_bound_default = 140; + icon_state = "map_vent_out"; + use_power = 1 + }, +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating/airless, +/area/liberia/mule) +"br" = ( +/obj/structure/closet/secure_closet{ + name = "merchant's locker"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/effect/floor_decal/corner/brown/half, +/obj/item/chems/pill/stimulants, +/obj/item/pill_bottle/gleam, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/beartrap, +/obj/item/beartrap, +/obj/item/grenade/smokebomb, +/obj/item/silencer, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"bs" = ( +/obj/structure/closet/secure_closet{ + name = "merchant's locker"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/effect/floor_decal/corner/brown/half, +/obj/item/belt/holster/security/tactical, +/obj/item/clothing/armor_attachment/plate/tactical, +/obj/item/clothing/mask/balaclava, +/obj/item/clothing/mask/balaclava, +/obj/item/clothing/gloves/insulated, +/obj/item/clothing/glasses/tacgoggles, +/obj/item/clothing/shoes/legguards, +/obj/item/clothing/shirt/syndicate, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"bt" = ( +/obj/effect/floor_decal/corner/brown/half, +/obj/machinery/apc/liberia{ + dir = 1; + name = "merchant north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/unary/tank/carbon_dioxide, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"bu" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/closet/crate/secure/weapon{ + req_access = list("ACCESS_MERCHANT") + }, +/obj/machinery/door/window/brigdoor/southright{ + req_access = newlist() + }, +/obj/item/secure_storage/briefcase, +/obj/item/poster, +/obj/item/poster, +/obj/item/poster, +/obj/item/poster, +/obj/item/poster, +/obj/item/poster, +/obj/item/knife/folding/combat/balisong, +/obj/item/knife/folding/combat/balisong, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"bv" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/closet/crate/medical, +/obj/random/medical, +/obj/random/medical, +/obj/random/medical, +/obj/random/medical/lite, +/obj/random/medical/lite, +/obj/random/medical/lite, +/obj/random/medical/lite, +/obj/random/medical/lite, +/obj/machinery/door/window/brigdoor/southright{ + req_access = newlist() + }, +/obj/item/firstaid/combat, +/obj/item/firstaid/surgery, +/obj/item/stack/nanopaste, +/obj/item/stack/nanopaste, +/obj/item/auto_cpr, +/obj/item/bodybag/rescue/loaded, +/obj/item/bodybag/rescue/loaded, +/obj/item/defibrillator/compact/combat/loaded, +/obj/item/sutures, +/obj/item/bonesetter, +/obj/item/circular_saw, +/obj/item/hemostat, +/obj/item/scalpel/laser, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"bw" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/turf/wall/titanium, +/area/liberia/mule) +"bx" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"by" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 6 + }, +/turf/wall/r_titanium, +/area/liberia/mule) +"bz" = ( +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/door/window/brigdoor/southright{ + req_access = newlist() + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"bA" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/door/window/brigdoor/southright{ + req_access = newlist() + }, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"bB" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/wall/r_titanium, +/area/liberia/mule) +"bC" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "merchantshuttle"; + name = "Merchant Window Shutters" + }, +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/liberia/mule) +"bD" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/computer/ship/helm{ + dir = 4 + }, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"bE" = ( +/obj/structure/chair/shuttle/blue{ + dir = 8 + }, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"bF" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/structure/cable/blue, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"bG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"bH" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/plating, +/area/liberia/traidingroom) +"bJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/traidingroom) +"bK" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/liberia/traidingroom) +"bM" = ( +/obj/machinery/computer/modular/preset/merchant{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"bN" = ( +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/obj/item/secure_storage/safe{ + pixel_x = 30 + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = null; + charge = 2.5e+006; + input_attempt = 1; + input_level = 250000; + output_attempt = 1; + output_level = 250000 + }, +/obj/structure/railing/mapped, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/liberia/mule) +"bO" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"bP" = ( +/turf/floor/tiled/dark, +/area/liberia/mule) +"bQ" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/valve/open, +/turf/floor/tiled/dark, +/area/liberia/mule) +"bR" = ( +/obj/machinery/door/airlock/hatch{ + name = "Trading Desk"; + req_access = newlist() + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"bS" = ( +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/liberia/mule) +"bT" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/mule) +"bU" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/mule) +"bV" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled, +/area/liberia/mule) +"bW" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/mule) +"bX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/turf/floor/tiled, +/area/liberia/mule) +"bY" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/liberia/mule) +"bZ" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "merchant_ship_vent" + }, +/obj/structure/catwalk, +/obj/structure/closet/emcloset, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/liberia/mule) +"ca" = ( +/obj/machinery/button/access/exterior{ + id_tag = "mule_port_shuttle_dock"; + pixel_x = 6; + pixel_y = 28 + }, +/obj/machinery/button/access/interior{ + id_tag = "mule_port_shuttle_dock"; + name = "interior access button"; + pixel_x = -6; + pixel_y = 28 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "merchant_ship_vent" + }, +/obj/structure/catwalk, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 8; + id_tag = "mule_port_shuttle_dock"; + pixel_x = 20; + tag_airpump = "merchant_ship_vent"; + tag_chamber_sensor = "merchant_ship_sensor"; + tag_exterior_door = "merchant_ship_exterior"; + tag_interior_door = "merchant_ship_interior" + }, +/turf/floor/plating, +/area/liberia/mule) +"cb" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor/corner, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"cc" = ( +/obj/machinery/computer/shuttle_control/explore/mule{ + dir = 4 + }, +/obj/effect/overmap/visitable/ship/landable/mule, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"cd" = ( +/obj/machinery/button/blast_door{ + id_tag = "merchantshuttle"; + name = "Merchant Window Shutters"; + pixel_y = -28; + req_access = list("ACCESS_MERCHANT"); + dir = 1 + }, +/obj/structure/chair/shuttle/blue{ + dir = 8 + }, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"ce" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/hologram/holopad/longrange, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"cf" = ( +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/mule) +"cg" = ( +/obj/machinery/door/airlock/hatch{ + name = "Cockpit"; + req_access = newlist() + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/mule) +"ch" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 1 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/liberia/mule) +"ci" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"cj" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/maintenance{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"ck" = ( +/obj/random/loot, +/obj/random/loot, +/obj/structure/rack/dark, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"cl" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"cm" = ( +/obj/machinery/merchant_pad, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"cn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/liberia/mule) +"co" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/item/taperecorder, +/obj/machinery/atmospherics/pipe/simple/visible/fuel{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/liberia/mule) +"cp" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "merchantdesk"; + name = "Merchant Desk Shutters" + }, +/obj/effect/paint/silver, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/mule) +"cq" = ( +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/mule) +"cr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/mule) +"cs" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/gun/projectile/pistol/holdout, +/obj/random/handgun, +/obj/random/handgun, +/obj/random/projectile, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"ct" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/item/clothing/mask/gas, +/obj/structure/table, +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"cu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"cv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"cw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/turf/floor/plating, +/area/liberia/mule) +"cx" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/mule) +"cy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "merchant_ship_interior"; + locked = 1; + name = "Ship Exterior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/tiled/techfloor/grid, +/area/liberia/mule) +"cz" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden, +/obj/structure/catwalk, +/turf/floor/plating, +/area/liberia/mule) +"cA" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/obj/machinery/airlock_sensor{ + id_tag = "merchant_ship_sensor"; + pixel_x = 28; + dir = 8 + }, +/obj/structure/catwalk, +/turf/floor/plating, +/area/liberia/mule) +"cB" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin, +/obj/item/pen, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"cC" = ( +/obj/structure/table/reinforced, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"cD" = ( +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/computer/ship/engines{ + dir = 1 + }, +/turf/floor/carpet/blue2, +/area/liberia/mule) +"cE" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance"; + req_access = newlist() + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"cF" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/unary/tank/carbon_dioxide, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringengines) +"cG" = ( +/obj/structure/chair/office/dark, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"cI" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"cJ" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/obj/effect/floor_decal/spline/fancy/wood/corner, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"cK" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"cL" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"cM" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/alarm/liberia{ + dir = 1; + pixel_y = -20 + }, +/obj/machinery/computer/ship/sensors{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/liberia/mule) +"cN" = ( +/obj/effect/paint/silver, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/paint_stripe/yellow, +/turf/wall/r_titanium, +/area/liberia/mule) +"cO" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"cP" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/liberia/mule) +"cQ" = ( +/obj/structure/chair/office/comfy/brown{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/liberia/mule) +"cR" = ( +/obj/machinery/door/window/brigdoor/eastright{ + autoset_access = 0; + req_access = newlist() + }, +/obj/structure/table/steel, +/obj/effect/paint/silver, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "merchantdesk"; + name = "Merchant Desk Shutters" + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/paint_stripe/yellow, +/obj/machinery/door/window/brigdoor/eastright{ + dir = 8; + req_access = newlist() + }, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"cS" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/liberia/mule) +"cU" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/liberia/mule) +"cV" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/liberia/mule) +"cW" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 5 + }, +/turf/floor/tiled, +/area/liberia/mule) +"cX" = ( +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"cY" = ( +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/valve/open, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"cZ" = ( +/obj/structure/table/laminate, +/obj/machinery/chemical_dispenser/bar_coffee{ + dir = 1 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"da" = ( +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"db" = ( +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"dc" = ( +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/suit_cycler/engineering/prepared/liberia, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"dd" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"de" = ( +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/plating, +/area/liberia/traidingroom) +"df" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"dg" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/silver, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 9 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/liberia/mule) +"dh" = ( +/obj/machinery/computer/ship/engines, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"di" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "merchant_ship_vent" + }, +/obj/structure/catwalk, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/mule) +"dk" = ( +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dl" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 1; + id_tag = "merchant_ship_vent" + }, +/obj/structure/sign/warning/airlock{ + dir = 8; + pixel_x = 32 + }, +/obj/structure/catwalk, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/structure/fuel_port/hydrogen{ + pixel_x = 32; + pixel_y = -32 + }, +/turf/floor/plating, +/area/liberia/mule) +"dm" = ( +/obj/machinery/fabricator{ + desc = "Your typical Autolathe. It appears to have much more options than your regular one, however..."; + fab_status_flags = 1; + name = "unlocked autolathe" + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "merchant_ship_dock"; + pixel_x = -24; + tag_airpump = "merchant_ship_vent"; + tag_chamber_sensor = "merchant_ship_sensor"; + tag_exterior_door = "merchant_ship_exterior"; + tag_interior_door = "merchant_ship_interior"; + dir = 4 + }, +/obj/effect/floor_decal/corner/brown/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"dn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/catwalk_plated, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"do" = ( +/obj/machinery/computer/modular/preset/civilian, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/green, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"dp" = ( +/obj/structure/rack, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/liberia/traidingroom) +"dq" = ( +/obj/machinery/recharger, +/obj/structure/table/reinforced, +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/effect/floor_decal/corner/green{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"dr" = ( +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"ds" = ( +/obj/structure/sign/warning{ + dir = 8; + pixel_x = 32 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 5 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"dt" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"dv" = ( +/obj/machinery/hologram/holopad/longrange, +/obj/effect/floor_decal/corner/blue/mono, +/obj/effect/overmap/visitable/ship/liberia, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"dw" = ( +/obj/structure/closet/secure_closet/engineering_electrical{ + req_access = list() + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"dx" = ( +/obj/structure/table/steel, +/obj/machinery/cell_charger, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/random/powercell, +/obj/machinery/apc/liberia{ + dir = 1; + name = "merchant north bump"; + pixel_y = 24 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dy" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/machinery/suit_cycler/engineering/prepared/atmospheric/liberia, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dz" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance"; + req_access = newlist() + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"dA" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/hallway) +"dB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"dC" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"dD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"dE" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/liberia/hallway) +"dF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"dG" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table/steel, +/obj/item/box/lights/mixed, +/obj/item/chems/spray/cleaner, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dH" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/glass/command{ + name = "Wreckage Site"; + req_access = newlist() + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"dI" = ( +/obj/machinery/computer/modular/preset/security{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"dJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/liberia/officeroom) +"dK" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dL" = ( +/obj/structure/table/glass, +/obj/item/folder/blue, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"dM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dN" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"dO" = ( +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/hallway) +"dP" = ( +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"dQ" = ( +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"dR" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"dS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 5 + }, +/turf/floor/plating, +/area/liberia/hallway) +"dT" = ( +/obj/machinery/cell_charger, +/obj/effect/floor_decal/corner/brown/half{ + dir = 1 + }, +/obj/structure/table/steel_reinforced, +/obj/machinery/alarm/liberia{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"dU" = ( +/obj/effect/floor_decal/corner/brown/half{ + dir = 1 + }, +/obj/structure/table/steel_reinforced, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/button/blast_door{ + dir = 1; + id_tag = "merchantdesk"; + name = "Merchant Desk Shutters"; + pixel_y = -21; + req_access = list("ACCESS_MERCHANT") + }, +/obj/structure/filing_cabinet/wall{ + pixel_x = 28 + }, +/obj/item/folder, +/obj/item/folder, +/obj/item/folder/blue, +/obj/item/folder/red, +/obj/item/hand_labeler, +/turf/floor/tiled/dark/monotile, +/area/liberia/mule) +"dV" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/double/glass/maintenance{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"dW" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment/bent, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/floor/plating, +/area/liberia/hallway) +"dX" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"dY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"dZ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/fuel, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"ea" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"eb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"ec" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/closet/crate/secure{ + name = "basic resources crate"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/forty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/machinery/door/window/brigdoor/northleft{ + req_access = newlist() + }, +/obj/item/stack/material/sheet/reinforced/mapped/titanium/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"ed" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"ee" = ( +/obj/structure/closet/crate/freezer, +/obj/random/snack, +/obj/random/snack, +/obj/random/snack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"ef" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/closet/crate/secure{ + name = "resources crate"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/item/stack/material/gemstone/mapped/diamond/ten, +/obj/item/stack/material/ingot/mapped/gold/ten, +/obj/item/stack/material/ingot/mapped/silver/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/machinery/door/window/brigdoor/northleft{ + req_access = newlist() + }, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"eg" = ( +/obj/item/wirecutters, +/obj/item/wrench, +/obj/item/flashlight/upgraded, +/obj/item/marshalling_wand, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/item/binoculars, +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"eh" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/item/guitar, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"ej" = ( +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"ek" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"el" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/closet/emcloset{ + anchored = 1; + name = "anchored emergency closet" + }, +/obj/item/clothing/head/helmet/space/void, +/obj/item/clothing/suit/space/void, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"em" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/catwalk_plated, +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"en" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"eo" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"ep" = ( +/obj/machinery/atm{ + pixel_y = -30 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window/brigdoor/northleft{ + req_access = newlist() + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"eq" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"er" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow/three_quarters, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"es" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"et" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/card/id{ + access = list("ACCESS_MERCHANT"); + desc = "A visitor's access card, this one is for the Merchant's Station."; + name = "Visitor's Card - Merchant's Station" + }, +/obj/item/card/id{ + access = list("ACCESS_MERCHANT"); + desc = "A visitor's access card, this one is for the Merchant's Station."; + name = "Visitor's Card - Merchant's Station" + }, +/obj/item/card/id{ + access = list("ACCESS_MERCHANT"); + desc = "A visitor's access card, this one is for the Merchant's Station."; + name = "Visitor's Card - Merchant's Station" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"eu" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/floor_decal/borderfloor{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/green{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"ev" = ( +/obj/structure/closet/crate, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"ew" = ( +/obj/structure/largecrate, +/obj/random/loot, +/obj/random/plushie, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"ex" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/turf/wall/r_titanium, +/area/liberia/mule) +"ey" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "merchant_ship_exterior"; + locked = 1; + name = "Ship Exterior" + }, +/obj/machinery/button/access/exterior{ + id_tag = "mule_port_shuttle_dock"; + pixel_x = -28; + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/shield_diffuser, +/obj/effect/shuttle_landmark/mule/start, +/obj/abstract/local_dock/automatic{ + shuttle_tag = "Mule"; + port_tag = "docking port"; + dock_target = "mule_port_shuttle_dock" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/mule) +"ez" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"eA" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"eB" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"eC" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_south = 3; + tag_west = 2 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eD" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eE" = ( +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eF" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/item/tank/emergency/oxygen/double, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eG" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/obj/machinery/sleeper{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"eH" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/obj/machinery/sleeper{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"eI" = ( +/obj/machinery/recharge_station, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"eJ" = ( +/obj/structure/sign/poster, +/turf/wall/prepainted, +/area/liberia/hallway) +"eM" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eN" = ( +/obj/structure/closet/crate, +/obj/item/stack/material/pane/mapped/glass/fifteen, +/obj/item/stack/material/panel/mapped/plastic/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/paint_sprayer, +/obj/item/clothing/gloves/insulated, +/obj/item/suit_cooling_unit, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/ten, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eO" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eP" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 8 + }, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eQ" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eR" = ( +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"eS" = ( +/obj/machinery/body_scanconsole, +/obj/machinery/apc/liberia{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"eT" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"eU" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 26 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 5 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"eV" = ( +/obj/machinery/cryopod{ + dir = 2 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/techfloor{ + dir = 9 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/cryo) +"eW" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/cryopod{ + dir = 2 + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/cryo) +"eX" = ( +/obj/machinery/cryopod{ + dir = 2 + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/computer/cryopod, +/turf/floor/tiled/techfloor/grid, +/area/liberia/cryo) +"eY" = ( +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"eZ" = ( +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"fa" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan, +/obj/effect/floor_decal/borderfloor/corner, +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fc" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fd" = ( +/obj/machinery/vitals_monitor, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"fe" = ( +/obj/machinery/vending/snack{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"ff" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"fg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor, +/obj/machinery/door/airlock, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"fh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 9 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"fi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"fk" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/liberia/hallway) +"fl" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/mule) +"fm" = ( +/obj/structure/closet/crate/uranium, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"fn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"fo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/structure/sign/warning/airlock{ + dir = 4; + pixel_x = -32 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"fp" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fq" = ( +/obj/machinery/atmospherics/binary/pump, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fr" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fs" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"ft" = ( +/obj/machinery/optable, +/obj/item/scanner/health, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"fu" = ( +/obj/structure/closet/walllocker{ + pixel_x = 24; + pixel_y = 4 + }, +/obj/item/chems/ivbag/blood/oplus, +/obj/item/chems/ivbag/blood/oplus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/food/junk/candy/donor, +/obj/item/food/junk/candy/donor, +/obj/item/food/junk/candy/donor, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"fv" = ( +/obj/machinery/vending/cola{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"fw" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/table, +/obj/effect/floor_decal/techfloor{ + dir = 10 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"fx" = ( +/obj/effect/floor_decal/techfloor, +/obj/structure/table, +/obj/machinery/apc/liberia{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/blue, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"fy" = ( +/obj/structure/sign/warning/radioactive{ + pixel_y = 30 + }, +/obj/structure/reagent_dispensers/fueltank, +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"fz" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 10 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fA" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/alarm/liberia{ + dir = 1; + pixel_y = -20 + }, +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fB" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/item/tank/nitrogen, +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fC" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"fD" = ( +/obj/machinery/disposal, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"fE" = ( +/obj/structure/disposalpipe/junction{ + dir = 1; + icon_state = "pipe-j2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"fF" = ( +/turf/floor/tiled, +/area/liberia/traidingroom) +"fG" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"fI" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/clothing/head/helmet/space/void, +/obj/item/clothing/suit/space/void, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"fJ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"fK" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table/reinforced, +/obj/item/paper_bin, +/obj/item/pen, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"fL" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/item/folder, +/obj/item/folder, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"fM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"fN" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-06" + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"fO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/turf/floor/carpet, +/area/liberia/bar) +"fP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet, +/area/liberia/bar) +"fQ" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/obj/structure/chair/wood/walnut{ + dir = 8 + }, +/turf/floor/carpet, +/area/liberia/bar) +"fR" = ( +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"fS" = ( +/obj/structure/table/laminate, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"fT" = ( +/obj/structure/chair/wood/walnut{ + dir = 8 + }, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"fU" = ( +/obj/structure/table/laminate, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"fV" = ( +/obj/structure/table/laminate, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"fW" = ( +/obj/structure/table/laminate, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/chemical_dispenser/bar_alc/full, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"fX" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"fY" = ( +/obj/machinery/atm{ + pixel_x = -30 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"fZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/machinery/alarm/liberia{ + dir = 1; + pixel_y = -20 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"ga" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"gb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/airlock/glass/command{ + name = "Office"; + req_access = newlist() + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/officeroom) +"gd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/chair/office/dark{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/officeroom) +"ge" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gf" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/turf/floor/carpet, +/area/liberia/bar) +"gg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/laminate, +/obj/item/deck/cards, +/turf/floor/carpet, +/area/liberia/bar) +"gh" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/structure/chair/wood/walnut{ + dir = 8 + }, +/turf/floor/carpet, +/area/liberia/bar) +"gi" = ( +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gj" = ( +/obj/structure/chair/wood/walnut, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gk" = ( +/obj/machinery/door/window/westright, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gl" = ( +/obj/structure/table/laminate, +/obj/item/box/glasses/pint, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gm" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/obj/structure/closet/firecloset, +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/effect/floor_decal/corner/green, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/clothing/head/helmet/space/void, +/obj/item/clothing/suit/space/void, +/turf/floor/tiled, +/area/liberia/hallway) +"gn" = ( +/obj/machinery/door/airlock{ + name = "Toilet" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"go" = ( +/obj/machinery/computer/shuttle_control/merchant{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 8 + }, +/obj/machinery/apc/liberia{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/blue, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gp" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/liberia/officeroom) +"gq" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/alarm/liberia{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gr" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/turf/floor/carpet, +/area/liberia/bar) +"gs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/spline/fancy/wood, +/turf/floor/carpet, +/area/liberia/bar) +"gt" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/turf/floor/carpet, +/area/liberia/bar) +"gu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/floor_decal/spline/plain/brown, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 6 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/spline/plain/brown, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gw" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/floor_decal/spline/plain/brown, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gx" = ( +/obj/structure/table/laminate, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gy" = ( +/obj/structure/table/laminate, +/obj/item/ashtray/glass, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/clothing/mask/smokable/cigarette/cigar/havana, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gz" = ( +/obj/structure/table/laminate, +/obj/item/chems/rag, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/wallframe_spawn/no_grille, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/bar) +"gC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/hallway) +"gD" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/clothing/head/helmet/space/void, +/obj/item/clothing/suit/space/void, +/turf/floor/tiled, +/area/liberia/hallway) +"gE" = ( +/obj/structure/table, +/obj/item/towel/random, +/obj/machinery/apc/liberia{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/blue{ + icon_state = "0-4" + }, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"gF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"gG" = ( +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/obj/structure/mirror{ + dir = 4; + pixel_x = -1; + pixel_y = 30 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"gH" = ( +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/obj/structure/mirror{ + dir = 4; + pixel_x = -1; + pixel_y = 30 + }, +/obj/machinery/alarm/liberia{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"gI" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin, +/obj/item/pen, +/obj/effect/floor_decal/borderfloor{ + dir = 10 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gJ" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/borderfloor, +/obj/item/eftpos{ + eftpos_name = "Merchant EFTPOS scanner" + }, +/obj/item/stack/package_wrap/twenty_five, +/obj/item/hand_labeler, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gK" = ( +/obj/effect/floor_decal/borderfloor, +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gL" = ( +/obj/machinery/photocopier, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"gM" = ( +/obj/structure/closet/cabinet, +/obj/item/clothing/shoes/craftable, +/obj/item/clothing/shirt/button, +/obj/item/clothing/neck/tie/navy, +/obj/item/clothing/suit/jacket/blazer, +/obj/item/clothing/costume/lawyer, +/obj/item/clothing/suit/jacket/navy, +/obj/random/handgun, +/obj/item/chems/drinks/bottle/premiumwine, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"gN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"gO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-4" + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"gP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 6 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"gQ" = ( +/obj/machinery/door/airlock{ + autoset_access = 0; + dir = 4; + name = "Merchant Leader"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/spline/plain/brown{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"gR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/liberia/library) +"gS" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"gT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"gU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/light, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 9 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"gW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"gX" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/spline/plain/brown{ + dir = 10 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gY" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/spline/plain/brown, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"gZ" = ( +/obj/item/stool/padded, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/spline/plain/brown, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"ha" = ( +/obj/machinery/door/airlock/glass{ + name = "Lounge" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"hb" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"hc" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"hd" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"he" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"hf" = ( +/obj/effect/floor_decal/spline/plain/brown, +/obj/structure/closet/secure_closet{ + name = "merchant's locker"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/item/folder, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"hh" = ( +/obj/effect/floor_decal/spline/plain/brown, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"hi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/spline/plain/brown, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 9 + }, +/turf/floor/laminate/ebony, +/area/liberia/captain) +"hj" = ( +/obj/machinery/door/airlock{ + name = "Merchant Assistants"; + req_access = newlist() + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/liberia/personellroom2) +"hk" = ( +/obj/machinery/media/jukebox/old, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"hl" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"hm" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"hn" = ( +/obj/structure/hygiene/shower{ + dir = 1 + }, +/obj/structure/curtain/open/shower, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom1) +"ho" = ( +/obj/structure/closet/radiation, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"hp" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 4; + icon_state = "console" + }, +/turf/floor/carpet/red, +/area/liberia/captain) +"hq" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/carpet/red, +/area/liberia/captain) +"hs" = ( +/obj/structure/undies_wardrobe, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-4" + }, +/turf/floor/carpet, +/area/liberia/personellroom2) +"ht" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/carpet, +/area/liberia/personellroom2) +"hv" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/item/clothing/suit/chef/classic, +/obj/item/rollingpin, +/obj/item/knife/kitchen, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hw" = ( +/obj/machinery/door/window/northleft{ + name = "Kitchen" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hx" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/microwave, +/obj/structure/table/reinforced, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hy" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"hz" = ( +/obj/machinery/vending/cigarette{ + dir = 1; + products = list(/obj/item/box/fancy/cigarettes=10,/obj/item/box/matches=10,/obj/item/flame/fuelled/lighter/zippo=4,/obj/item/clothing/mask/smokable/cigarette/cigar/havana=2) + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"hA" = ( +/obj/structure/table/laminate, +/obj/item/scanner/price, +/obj/item/scanner/price, +/obj/machinery/light/small, +/obj/item/scanner/price, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"hB" = ( +/obj/machinery/pipelayer, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"hC" = ( +/obj/structure/table/laminate, +/obj/item/ashtray, +/obj/item/box/matches, +/obj/random/smokes, +/turf/floor/carpet/red, +/area/liberia/captain) +"hD" = ( +/obj/structure/table/laminate, +/mob/living/simple_animal/tindalos{ + name = "Eddy" + }, +/turf/floor/carpet/red, +/area/liberia/captain) +"hE" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet/red, +/area/liberia/captain) +"hF" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/undies_wardrobe, +/turf/floor/carpet/red, +/area/liberia/captain) +"hG" = ( +/obj/structure/closet/cabinet, +/obj/item/clothing/shoes/color/black, +/obj/item/clothing/suit/apron/overalls/laborer, +/obj/item/clothing/skirt, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/turf/floor/carpet, +/area/liberia/personellroom2) +"hH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/carpet, +/area/liberia/personellroom2) +"hI" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/turf/floor/carpet, +/area/liberia/personellroom2) +"hJ" = ( +/obj/structure/table/reinforced, +/obj/machinery/reagentgrinder, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hL" = ( +/obj/structure/table/reinforced, +/obj/item/box/donkpockets, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hM" = ( +/obj/item/stock_parts/computer/tesla_link, +/obj/item/stock_parts/computer/tesla_link, +/obj/item/stock_parts/computer/tesla_link, +/obj/item/stock_parts/computer/tesla_link, +/obj/structure/rack/dark, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"hN" = ( +/obj/structure/table/laminate, +/obj/random/action_figure, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/turf/floor/carpet, +/area/liberia/personellroom2) +"hO" = ( +/obj/machinery/light/small, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/spline/fancy/wood, +/turf/floor/carpet, +/area/liberia/personellroom2) +"hQ" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/closet/secure_closet/freezer/kitchen{ + req_access = newlist() + }, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hR" = ( +/obj/structure/hygiene/sink, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hS" = ( +/obj/structure/closet/secure_closet/freezer/fridge, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/chems/condiment/enzyme, +/turf/floor/tiled/freezer, +/area/liberia/bar) +"hT" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"hU" = ( +/obj/structure/closet/radiation, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"hW" = ( +/obj/machinery/atmospherics/omni/mixer{ + active_power_usage = 2500; + tag_east = 1; + tag_east_con = 0.21; + tag_south = 2; + tag_west = 1; + tag_west_con = 0.79 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"hY" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"hZ" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"ib" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/fuel, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"ic" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/sign/warning/airlock{ + dir = 1; + pixel_y = -32 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"id" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"ie" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"ig" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"ih" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 6 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"ii" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance"; + req_access = newlist() + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"ij" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"ik" = ( +/obj/effect/floor_decal/techfloor, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"in" = ( +/obj/structure/table, +/obj/item/defibrillator/compact/loaded, +/obj/item/flashlight, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"io" = ( +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/item/toolbox/electrical{ + pixel_x = 7; + pixel_y = 4 + }, +/obj/item/toolbox/electrical{ + pixel_x = 7; + pixel_y = 4 + }, +/obj/item/rcd, +/obj/item/rcd_ammo/large, +/obj/item/rcd_ammo/large, +/obj/item/rcd_ammo/large, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"ip" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"iu" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"iv" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor{ + dir = 10 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"iw" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/effect/floor_decal/techfloor, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"ix" = ( +/obj/machinery/power/solar_control/autostart{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"iy" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringengines) +"iz" = ( +/obj/machinery/computer/ship/sensors{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"iA" = ( +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"iB" = ( +/obj/item/stack/nanopaste, +/obj/item/robotanalyzer, +/obj/item/stack/nanopaste, +/obj/structure/rack/dark, +/obj/random/maintenance/clean, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"iD" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"iG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance" + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/liberia/atmos) +"iH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/hallway) +"iI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"iK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/liberia/traidingroom) +"iL" = ( +/obj/structure/table/steel_reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"iN" = ( +/obj/structure/chair/comfy/blue{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"iO" = ( +/obj/machinery/computer/ship/helm{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"iS" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"iT" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "solar_merchant_outer_up"; + locked = 1; + name = "Solar External Access"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/button/access/exterior{ + id_tag = "solar_merchant_airlock_up"; + pixel_y = 24; + req_access = list("ACCESS_MERCHANT") + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"iU" = ( +/obj/structure/catwalk, +/obj/machinery/airlock_sensor{ + id_tag = "solar_merchant_sensor_up"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "solar_merchant_pump_up" + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 1; + id_tag = "solar_merchant_airlock_up"; + pixel_y = -24; + req_access = list("ACCESS_MERCHANT"); + tag_airpump = "solar_merchant_pump_up"; + tag_chamber_sensor = "solar_merchant_sensor_up"; + tag_exterior_door = "solar_merchant_outer_up"; + tag_interior_door = "solar_merchant_inner_up" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/engineeringstorage) +"iV" = ( +/obj/structure/largecrate, +/obj/random/loot, +/obj/random/plushie, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"iW" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "solar_merchant_inner_up"; + locked = 1; + name = "Solar External Access"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/button/access/interior{ + id_tag = "solar_merchant_airlock_up"; + name = "interior access button"; + pixel_y = 24; + req_access = list("ACCESS_MERCHANT") + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"iX" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"iY" = ( +/obj/machinery/computer/ship/engines{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"iZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"ja" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"jg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 6 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"jh" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/space) +"jo" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/space_heater, +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"jq" = ( +/obj/machinery/recharge_station, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"jr" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/port_gen/pacman/mrs, +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/cable/blue{ + icon_state = "0-4" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"js" = ( +/obj/structure/closet/crate/solar, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"jt" = ( +/obj/structure/cable/blue, +/obj/machinery/power/smes/buildable/preset/liberia, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"ju" = ( +/obj/machinery/vending/tool, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"jv" = ( +/obj/structure/table/steel, +/obj/random/advdevice, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"jw" = ( +/obj/structure/rack/dark, +/obj/item/stack/tile/carpet/red, +/obj/item/stack/tile/carpet/purple, +/obj/item/stack/tile/carpet/orange, +/obj/item/stack/tile/carpet/green, +/obj/item/stack/tile/carpet/blue, +/obj/item/stack/tile/carpet/blue2, +/obj/item/stack/tile/carpet, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"jx" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 8; + icon_state = "console" + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"jy" = ( +/obj/structure/closet, +/obj/random/shoes, +/obj/random/clothing, +/obj/random/hat, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"jz" = ( +/obj/structure/table/glass, +/obj/item/paper_bin, +/obj/item/pen, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"jA" = ( +/obj/structure/closet/crate, +/obj/random/loot, +/obj/random/loot, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"jB" = ( +/obj/structure/table/steel_reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/effect/floor_decal/corner/blue/mono, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -3; + pixel_y = 9 + }, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"jC" = ( +/obj/machinery/computer/ship/navigation{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"jD" = ( +/obj/structure/table/glass, +/obj/machinery/faxmachine/mapped, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"jE" = ( +/obj/random/action_figure, +/obj/random/plushie, +/obj/structure/rack/dark, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"jF" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"jG" = ( +/obj/structure/closet/cabinet, +/obj/random/plushie, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/carpet/green, +/area/liberia/guestroom1) +"jH" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/green, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/carpet/green, +/area/liberia/guestroom1) +"jI" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/rd, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/carpet/magenta, +/area/liberia/guestroom2) +"jJ" = ( +/obj/structure/closet/cabinet, +/obj/random/plushie, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/obj/machinery/alarm/liberia{ + dir = 8; + pixel_x = 25 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/carpet/magenta, +/area/liberia/guestroom2) +"jK" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/carpet, +/area/liberia/library) +"jL" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/obj/structure/chair/office/comfy/beige, +/turf/floor/carpet, +/area/liberia/library) +"jM" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"jO" = ( +/obj/structure/bookcase/skill_books/random, +/turf/floor/laminate/walnut, +/area/liberia/library) +"jP" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/guestroom1) +"jQ" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/machinery/light_switch{ + pixel_y = 3 + }, +/turf/floor/tiled/monotile, +/area/liberia/officeroom) +"jR" = ( +/obj/structure/chair/wood/walnut, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/turf/floor/carpet/green, +/area/liberia/guestroom1) +"jS" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"jT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/apc/liberia{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/blue, +/obj/effect/floor_decal/corner/blue/three_quarters, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"jU" = ( +/obj/structure/chair/wood/walnut, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/machinery/apc/liberia{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/turf/floor/carpet/magenta, +/area/liberia/guestroom2) +"jV" = ( +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/structure/rack/dark, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"jW" = ( +/obj/structure/chair/office/comfy/beige{ + dir = 4 + }, +/turf/floor/carpet, +/area/liberia/library) +"jX" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/lava/orange, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/turf/floor/carpet, +/area/liberia/library) +"jY" = ( +/obj/structure/table/laminate, +/obj/structure/flora/pottedplant/deskleaf{ + pixel_x = -5; + pixel_y = 2 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/carpet/green, +/area/liberia/guestroom1) +"jZ" = ( +/obj/machinery/button/alternate/door/bolts{ + dir = 4; + id_tag = "merchdorm2"; + name = "Lock"; + pixel_x = -24 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/carpet/magenta, +/area/liberia/guestroom2) +"ka" = ( +/obj/structure/table/laminate, +/obj/structure/flora/pottedplant/smallcactus{ + pixel_x = -5; + pixel_y = 9 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/carpet/magenta, +/area/liberia/guestroom2) +"kb" = ( +/obj/effect/floor_decal/spline/fancy/wood, +/obj/structure/chair/office/comfy/beige{ + dir = 4 + }, +/turf/floor/carpet, +/area/liberia/library) +"kc" = ( +/obj/structure/table/laminate, +/obj/item/box/fancy/donut, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/turf/floor/carpet, +/area/liberia/library) +"kf" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringengines) +"kg" = ( +/obj/machinery/door/airlock/civilian{ + id_tag = "merchdorm1"; + name = "Room One" + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor, +/area/liberia/guestroom1) +"kh" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"ki" = ( +/obj/machinery/newscaster{ + pixel_x = 26; + pixel_y = 2 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"kk" = ( +/obj/effect/floor_decal/techfloor{ + dir = 9 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"kl" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"km" = ( +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"kn" = ( +/obj/machinery/door/airlock/civilian, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor, +/area/liberia/library) +"ko" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/liberia/library) +"kp" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/turf/floor/carpet, +/area/liberia/library) +"kq" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/carpet, +/area/liberia/library) +"kr" = ( +/obj/structure/table/laminate, +/obj/item/modular_computer/laptop/preset/custom_loadout/standard{ + dir = 8 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/turf/floor/carpet, +/area/liberia/library) +"ks" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor/corner, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"kt" = ( +/obj/effect/floor_decal/techfloor, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"ku" = ( +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"kw" = ( +/obj/machinery/vending/coffee{ + dir = 1 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/turf/floor/carpet, +/area/liberia/library) +"kx" = ( +/obj/machinery/vending/weeb{ + dir = 1 + }, +/obj/effect/floor_decal/spline/fancy/wood, +/turf/floor/carpet, +/area/liberia/library) +"ky" = ( +/obj/structure/table/laminate, +/obj/effect/floor_decal/spline/fancy/wood, +/obj/machinery/apc/liberia{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/blue, +/turf/floor/carpet, +/area/liberia/library) +"kz" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/turf/floor/carpet, +/area/liberia/library) +"kB" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"kC" = ( +/obj/structure/table/steel, +/obj/item/toolbox/mechanical, +/obj/item/belt/utility/full, +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/effect/floor_decal/corner/yellow, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"kF" = ( +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"kG" = ( +/obj/machinery/vending/engivend{ + dir = 4; + req_access = newlist() + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"kJ" = ( +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"kK" = ( +/obj/machinery/light, +/obj/effect/floor_decal/borderfloor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"kL" = ( +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/power/smes/buildable/preset/liberia, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"kM" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"kO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"kQ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"kR" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"kS" = ( +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"kT" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"kU" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/liberia/medbay) +"kV" = ( +/obj/machinery/bodyscanner, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"kW" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"kX" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/personellroom1) +"kZ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"la" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/liberia/medbay) +"lb" = ( +/obj/structure/sign/warning/airlock{ + dir = 1; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 9 + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"lc" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"ld" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/techfloor, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"le" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/machinery/suit_cycler/engineering/prepared/liberia, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"lf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"lg" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 4; + id_tag = "mule_port_dock"; + pixel_x = -20; + tag_airpump = "merchant_station_vent"; + tag_chamber_sensor = "merchant_station_sensor"; + tag_exterior_door = "merchant_station_exterior"; + tag_interior_door = "merchant_station_interior" + }, +/obj/machinery/airlock_sensor{ + id_tag = "merchant_station_sensor"; + pixel_x = -28; + pixel_y = -10 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/catwalk, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/liberia/dockinghall) +"lh" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "merchant_station_vent" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/catwalk, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/dockinghall) +"li" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "merchant_station_interior"; + locked = 1; + name = "Station Interior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/button/access/interior{ + id_tag = "mule_port_dock"; + name = "interior access button"; + pixel_x = -1; + pixel_y = 22 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"lj" = ( +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"ll" = ( +/obj/machinery/meter, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"lm" = ( +/obj/machinery/atmospherics/omni/filter{ + active_power_usage = 2500; + tag_east = 1; + tag_south = 4; + tag_west = 2 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"ln" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"lo" = ( +/obj/structure/table, +/obj/item/defibrillator/loaded, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/sign/warning/nosmoking_1{ + dir = 8; + pixel_x = 32 + }, +/obj/item/firstaid/regular{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/firstaid/adv{ + pixel_x = -2 + }, +/obj/item/firstaid/fire{ + pixel_x = 2; + pixel_y = 3 + }, +/obj/item/firstaid/o2, +/obj/item/firstaid/toxin, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"lp" = ( +/obj/structure/bed/roller, +/obj/structure/closet/walllocker{ + pixel_x = -24; + pixel_y = 3 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"lq" = ( +/obj/structure/iv_drip, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"lr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"ls" = ( +/obj/structure/table, +/obj/item/firstaid/surgery{ + pixel_y = 6 + }, +/obj/item/stack/medical/bandage/advanced, +/obj/item/chems/spray/antiseptic, +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/white/monotile, +/area/liberia/medbay) +"lt" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"lu" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/bar) +"lv" = ( +/obj/machinery/vending/medical{ + initial_access = newlist() + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/liberia/medbay) +"lw" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/liberia/medbay) +"lx" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/apc/liberia{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/turf/floor/carpet/green, +/area/liberia/guestroom1) +"ly" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/carpet/magenta, +/area/liberia/guestroom2) +"lz" = ( +/obj/machinery/button/alternate/door/bolts{ + dir = 8; + id_tag = "merchdorm1"; + name = "Lock"; + pixel_x = 24 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/carpet/green, +/area/liberia/guestroom1) +"lB" = ( +/turf/floor/laminate/walnut, +/area/liberia/library) +"lC" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 5 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"lD" = ( +/turf/wall/prepainted, +/area/liberia/merchantstorage) +"lE" = ( +/obj/machinery/button/blast_door{ + dir = 4; + id_tag = "merch-ship_windows"; + name = "Bridge Window Blast Doors"; + pixel_x = -36 + }, +/obj/machinery/button/blast_door{ + dir = 4; + id_tag = "merch-ship_sensors"; + name = "Bridge Sensors Blast Door"; + pixel_x = -26 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"lR" = ( +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"ml" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"mo" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"mr" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"mu" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor/corner, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"mz" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"mO" = ( +/obj/structure/closet/crate/med_crate, +/obj/item/firstaid/fire, +/obj/item/firstaid/o2, +/obj/item/firstaid/regular, +/obj/item/firstaid/surgery, +/obj/item/firstaid/toxin, +/obj/item/firstaid/trauma, +/obj/item/defibrillator, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/rescue/loaded, +/obj/item/bodybag/rescue/loaded, +/obj/item/roller, +/obj/item/roller, +/obj/item/auto_cpr, +/obj/item/box/freezer, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"mT" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"no" = ( +/turf/floor/carpet/red, +/area/liberia/captain) +"np" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"ns" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"nD" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/machinery/recharge_station, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 5 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"nH" = ( +/obj/structure/chair/wood/walnut, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled, +/area/liberia/hallway) +"nO" = ( +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/turf/floor/reinforced/airless, +/area/space) +"nQ" = ( +/turf/wall/prepainted, +/area/liberia/bar) +"oe" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"op" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/rack/dark, +/obj/item/stack/material/plank/mapped/bamboo/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"os" = ( +/obj/structure/table/laminate, +/obj/effect/floor_decal/spline/fancy/wood, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"oD" = ( +/obj/effect/floor_decal/techfloor, +/obj/structure/table, +/obj/item/folder, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"oF" = ( +/turf/floor/tiled, +/area/liberia/officeroom) +"oH" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"oJ" = ( +/obj/abstract/level_data_spawner/player{ + name = "Liberia" + }, +/turf/space, +/area/space) +"oM" = ( +/obj/effect/floor_decal/solarpanel, +/obj/machinery/power/solar{ + name = "Aft Port Solar Array" + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/floor/reinforced/airless, +/area/space) +"oN" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringlobby) +"oO" = ( +/obj/machinery/recharge_station, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"oS" = ( +/obj/effect/floor_decal/techfloor, +/obj/structure/closet/firecloset, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"pa" = ( +/turf/wall/prepainted, +/area/liberia/guestroom1) +"pf" = ( +/obj/effect/floor_decal/borderfloor/corner{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"ps" = ( +/obj/machinery/door/blast/regular{ + dir = 2; + id_tag = "merch-ship_windows" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/bridge) +"pB" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"pD" = ( +/obj/structure/sign/poster, +/turf/wall/prepainted, +/area/liberia/toiletroom1) +"pE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 9 + }, +/turf/wall/r_wall/prepainted, +/area/liberia/captain) +"pF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringengines) +"pJ" = ( +/obj/structure/fireaxecabinet{ + pixel_x = -32 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"pS" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"pV" = ( +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"pX" = ( +/obj/effect/floor_decal/techfloor{ + dir = 5 + }, +/obj/machinery/cryopod{ + dir = 2 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"pZ" = ( +/obj/structure/table/laminate, +/obj/machinery/fabricator/micro/bartender{ + pixel_x = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"qc" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/northleft{ + req_access = newlist() + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atm{ + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"qg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"qj" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/personellroom1) +"qm" = ( +/obj/effect/catwalk_plated, +/obj/structure/disposalpipe/junction, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"qo" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 10 + }, +/obj/effect/floor_decal/corner/yellow, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"qx" = ( +/turf/wall/prepainted, +/area/liberia/hallway) +"qA" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"qD" = ( +/obj/effect/floor_decal/techfloor{ + dir = 5 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"qI" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"qR" = ( +/obj/structure/rack/dark, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"rc" = ( +/obj/effect/floor_decal/techfloor, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"rn" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/radio, +/obj/item/flashlight, +/obj/item/crowbar, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_ridged, +/area/liberia/engineeringlobby) +"ro" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/hallway) +"rx" = ( +/obj/machinery/apc/liberia{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"rE" = ( +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"rT" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/effect/floor_decal/corner/green{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/clothing/head/helmet/space/void, +/obj/item/clothing/suit/space/void, +/turf/floor/tiled/monotile, +/area/liberia/hallway) +"rZ" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/structure/closet/cabinet, +/obj/item/clothing/shoes/jackboots, +/obj/item/clothing/shoes/jackboots, +/obj/item/clothing/jumpsuit/engineer, +/obj/item/clothing/jumpsuit/security, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"se" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 9 + }, +/turf/floor/plating, +/area/liberia/hallway) +"ss" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"sF" = ( +/obj/machinery/door/airlock/civilian{ + id_tag = "merchdorm2"; + name = "Room One" + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor, +/area/liberia/guestroom2) +"sJ" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"sN" = ( +/obj/structure/catwalk, +/obj/machinery/airlock_sensor{ + id_tag = "solar_merchant_sensor_down"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "solar_merchant_pump_down" + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 1; + id_tag = "solar_merchant_airlock_down"; + pixel_y = -24; + req_access = list("ACCESS_MERCHANT"); + tag_airpump = "solar_merchant_pump_down"; + tag_chamber_sensor = "solar_merchant_sensor_down"; + tag_exterior_door = "solar_merchant_outer_down"; + tag_interior_door = "solar_merchant_inner_down" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/atmos) +"sQ" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 8 + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"sS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/spline/fancy/wood, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"sW" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"sY" = ( +/obj/item/stack/material/panel/mapped/plastic/ten{ + pixel_x = -4; + pixel_y = -4 + }, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/ten{ + pixel_y = -4 + }, +/obj/item/stack/material/pane/mapped/glass/ten{ + pixel_x = 4; + pixel_y = -4 + }, +/obj/structure/table/laminate, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"th" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"to" = ( +/obj/structure/rack/dark, +/obj/random/loot, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"tz" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 10 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"tG" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 5 + }, +/turf/wall/r_titanium, +/area/liberia/mule) +"tI" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/cryo) +"tK" = ( +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/reinforced/airless, +/area/space) +"tL" = ( +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/plating, +/area/liberia/bar) +"tR" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 6 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"tU" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"uf" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringreactor) +"uo" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"ur" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/guestroom1) +"uS" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled, +/area/liberia/mule) +"vd" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"vi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"vR" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/laminate/ebony, +/area/liberia/bar) +"wq" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "solar_merchant_inner_down"; + locked = 1; + name = "Solar External Access"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/button/access/interior{ + id_tag = "solar_merchant_airlock_down"; + name = "interior access button"; + pixel_y = 24; + req_access = list("ACCESS_MERCHANT") + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/atmos) +"wt" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/turf/floor/tiled/steel_ridged, +/area/liberia/engineeringlobby) +"wK" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"wM" = ( +/obj/machinery/floodlight, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"wW" = ( +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"xc" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/captain) +"xn" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/door/window/northright, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled/techfloor/grid, +/area/liberia/dockinghall) +"xr" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200 + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"xx" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/liberia/captain) +"xG" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"xT" = ( +/obj/structure/rack/dark, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"ya" = ( +/obj/structure/disposaloutlet{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/shield_diffuser, +/turf/floor/reinforced/airless, +/area/space) +"yh" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"yp" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"yC" = ( +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"yL" = ( +/obj/effect/floor_decal/borderfloor/corner, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"yP" = ( +/obj/structure/rack/dark, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"yS" = ( +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"yU" = ( +/obj/effect/floor_decal/techfloor{ + dir = 5 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"zd" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"zl" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"zn" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/officeroom) +"zq" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/bridge) +"zt" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "merch-ship_sensors" + }, +/turf/floor/reinforced/airless, +/area/liberia/merchantstorage) +"zQ" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"Aa" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/captain) +"Af" = ( +/obj/structure/table/laminate, +/obj/effect/floor_decal/borderfloor{ + dir = 10 + }, +/obj/effect/floor_decal/corner/green{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"Am" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"Aq" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"Au" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"Az" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/cryo) +"AO" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/hallway) +"AT" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/traidingroom) +"Bl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"Br" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"Bx" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/liberia/engineeringengines) +"BC" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/toiletroom2) +"BE" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 10 + }, +/obj/machinery/power/solar_control/autostart{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"BH" = ( +/turf/floor/laminate/walnut, +/area/liberia/bar) +"BJ" = ( +/turf/wall/prepainted, +/area/liberia/library) +"BW" = ( +/obj/structure/rack/dark, +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"BX" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel, +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringengines) +"Dl" = ( +/obj/structure/bookcase/skill_books/random, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"DI" = ( +/turf/wall/prepainted, +/area/liberia/personellroom1) +"DK" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/full, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"DL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"DP" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor/corner, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"Eb" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"Ei" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/obj/machinery/suit_cycler/engineering/prepared/liberia, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"Ep" = ( +/obj/structure/rack/dark, +/obj/item/box/gloves, +/obj/item/box/bloodpacks, +/obj/item/box/beakers, +/obj/item/box/masks, +/obj/item/box/syringes, +/obj/item/box/bodybags, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"Eq" = ( +/obj/effect/floor_decal/techfloor, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"Ez" = ( +/obj/structure/hygiene/toilet{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/apc/liberia{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/blue{ + icon_state = "0-4" + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom2) +"ED" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/valve/open, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"EG" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/dockinghall) +"EQ" = ( +/obj/machinery/alarm/liberia{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom2) +"EZ" = ( +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/plating, +/area/liberia/officeroom) +"Fc" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/reinforced/airless, +/area/space) +"Fs" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/personellroom2) +"FQ" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/tank/air{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"FZ" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 5 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"Gd" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 5 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"Gu" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance"; + req_access = newlist() + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"Gy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/green/full, +/turf/floor/tiled, +/area/liberia/hallway) +"Gz" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled, +/area/liberia/mule) +"GE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/catwalk_plated, +/obj/machinery/apc/liberia{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"GG" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"GP" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/atmos) +"GV" = ( +/obj/structure/janitorialcart, +/obj/item/mop, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/apc/liberia{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"Ha" = ( +/obj/structure/closet/crate, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/titanium/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/ocp/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/light/small, +/obj/machinery/apc/liberia{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/blue, +/turf/floor/tiled/steel_ridged, +/area/liberia/engineeringlobby) +"Hl" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"Hm" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/largecrate, +/obj/random/loot, +/obj/random/loot, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"Ht" = ( +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/floor/laminate/walnut, +/area/liberia/bar) +"Hv" = ( +/turf/wall/prepainted, +/area/liberia/medbay) +"Hw" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"HA" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 9 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 10 + }, +/obj/effect/floor_decal/corner/yellow, +/turf/floor/tiled, +/area/liberia/hallway) +"HG" = ( +/obj/machinery/fabricator/pipe/disposal, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"HM" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/structure/bed/padded, +/obj/item/bedsheet/ce, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"HQ" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor/corner, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"HT" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"HV" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/merchantstorage) +"Ig" = ( +/obj/machinery/light, +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"Io" = ( +/obj/machinery/shipsensors, +/obj/structure/cable/blue{ + icon_state = "0-8" + }, +/turf/floor/reinforced/airless, +/area/liberia/merchantstorage) +"Iq" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled/steel_grid, +/area/liberia/mule) +"Iw" = ( +/turf/wall/prepainted, +/area/liberia/dockinghall) +"Iy" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/turf/wall/r_titanium, +/area/liberia/mule) +"IA" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringstorage) +"IH" = ( +/obj/effect/floor_decal/techfloor, +/obj/machinery/alarm/liberia{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"IM" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 8 + }, +/turf/floor/plating, +/area/liberia/mule) +"IQ" = ( +/obj/structure/sign/poster, +/turf/wall/prepainted, +/area/liberia/bar) +"Ja" = ( +/obj/structure/chair/wood/walnut, +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled, +/area/liberia/hallway) +"Jf" = ( +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/liberia/bridge) +"JE" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "solar_merchant_outer_down"; + locked = 1; + name = "Solar External Access"; + req_access = list("ACCESS_MERCHANT") + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/button/access/exterior{ + id_tag = "solar_merchant_airlock_down"; + pixel_y = 24; + req_access = list("ACCESS_MERCHANT") + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/liberia/atmos) +"JI" = ( +/obj/effect/floor_decal/borderfloor/corner, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 8 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"JS" = ( +/obj/machinery/apc/liberia{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/blue{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/obj/structure/table/laminate, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"Kh" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"Km" = ( +/obj/structure/closet/crate/secure, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"Kv" = ( +/obj/machinery/fabricator{ + fab_status_flags = 1 + }, +/turf/floor/tiled/steel_ridged, +/area/liberia/engineeringlobby) +"KF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/liberia/captain) +"KH" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel, +/turf/wall/r_wall/prepainted, +/area/liberia/captain) +"Lh" = ( +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"Lj" = ( +/obj/effect/floor_decal/techfloor{ + dir = 10 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/closet/firecloset, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringengines) +"Lk" = ( +/obj/effect/floor_decal/solarpanel, +/obj/machinery/power/tracker, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/turf/floor/reinforced/airless, +/area/space) +"Lm" = ( +/turf/wall/prepainted, +/area/liberia/bridge) +"Lz" = ( +/turf/wall/prepainted, +/area/liberia/toiletroom2) +"LJ" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"LW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/liberia/hallway) +"Mj" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/officeroom) +"Ml" = ( +/obj/structure/table/laminate, +/obj/item/ashtray/glass, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"Mm" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/obj/structure/undies_wardrobe, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"MU" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"Nk" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 1 + }, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"Nq" = ( +/obj/effect/floor_decal/spline/fancy/wood/cee{ + dir = 4 + }, +/obj/machinery/atm{ + pixel_y = -30 + }, +/turf/floor/carpet/red, +/area/liberia/traidingroom) +"Nt" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"Nv" = ( +/turf/wall/prepainted, +/area/liberia/traidingroom) +"Nw" = ( +/obj/effect/floor_decal/techfloor{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"NK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"Od" = ( +/turf/wall/prepainted, +/area/liberia/atmos) +"OA" = ( +/turf/wall/prepainted, +/area/liberia/toiletroom1) +"OC" = ( +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"OT" = ( +/obj/machinery/alarm/liberia{ + dir = 8; + pixel_x = 25 + }, +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/obj/structure/closet/emcloset{ + anchored = 1; + name = "anchored emergency closet" + }, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"Py" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"PG" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 10 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"PI" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/library) +"PU" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 6 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"PW" = ( +/obj/machinery/shipsensors, +/obj/structure/cable/blue{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/liberia/mule) +"Qi" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"Qj" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"Qk" = ( +/obj/structure/closet/toolcloset, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/stack/cable_coil/random, +/obj/random/bomb_supply, +/turf/floor/tiled/steel_ridged, +/area/liberia/engineeringlobby) +"Qo" = ( +/obj/structure/railing/mapped, +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"QA" = ( +/obj/effect/floor_decal/techfloor, +/obj/machinery/apc/liberia{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/blue, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"QE" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "merchantshuttle"; + name = "Merchant Window Shutters" + }, +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/liberia/mule) +"QH" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"QK" = ( +/obj/structure/table/laminate, +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"QM" = ( +/turf/wall/prepainted, +/area/liberia/guestroom2) +"Ro" = ( +/turf/floor/tiled/dark, +/area/liberia/bridge) +"Rw" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/guestroom2) +"Rz" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"RF" = ( +/obj/structure/rack/dark, +/obj/random/maintenance/clean, +/obj/random/maintenance/clean, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"RO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/laminate/walnut, +/area/liberia/library) +"Sa" = ( +/turf/wall/prepainted, +/area/liberia/cryo) +"Sb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 9 + }, +/turf/wall/r_wall/prepainted, +/area/liberia/engineeringengines) +"Se" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/toiletroom1) +"Sm" = ( +/turf/floor/reinforced/airless, +/area/space) +"St" = ( +/turf/wall/prepainted, +/area/liberia/officeroom) +"SN" = ( +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/structure/railing/mapped, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/structure/tank_rack/oxygen, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringstorage) +"SP" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor{ + dir = 6 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 1 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"SU" = ( +/obj/effect/floor_decal/techfloor, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"SY" = ( +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 5 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/turf/floor/tiled/techfloor, +/area/liberia/dockinghall) +"Tg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"Tz" = ( +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/liberia/personellroom1) +"TB" = ( +/obj/effect/floor_decal/borderfloor/corner{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"TG" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/structure/cable/blue{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/liberia/hallway) +"TT" = ( +/obj/effect/floor_decal/corner_techfloor_grid, +/obj/effect/floor_decal/techfloor/corner, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringreactor) +"Uc" = ( +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"Ue" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"Uh" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/bar) +"Um" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"Ut" = ( +/obj/effect/floor_decal/techfloor{ + dir = 5 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"UV" = ( +/obj/effect/floor_decal/techfloor{ + dir = 6 + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"Vc" = ( +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"Vk" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"Vp" = ( +/turf/wall/prepainted, +/area/liberia/personellroom2) +"Vz" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/reinforced/airless, +/area/space) +"VP" = ( +/obj/effect/floor_decal/borderfloor/corner{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green/three_quarters, +/turf/floor/tiled, +/area/liberia/traidingroom) +"VX" = ( +/obj/effect/floor_decal/solarpanel, +/obj/machinery/power/solar{ + name = "Aft Port Solar Array" + }, +/obj/structure/cable/yellow, +/turf/floor/reinforced/airless, +/area/space) +"VZ" = ( +/obj/machinery/door/airlock{ + name = "Toilet" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/freezer, +/area/liberia/toiletroom2) +"Wb" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/liberia/library) +"Wn" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"Wr" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/liberia/hallway) +"Wx" = ( +/obj/structure/cable/blue{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/borderfloor, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/engineeringlobby) +"WC" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/rack/dark, +/obj/structure/railing/mapped, +/obj/item/stack/material/plank/mapped/yew/twentyfive, +/obj/item/stack/material/plank/mapped/walnut/twentyfive, +/obj/item/stack/material/plank/mapped/maple/twentyfive, +/obj/item/stack/material/plank/mapped/mahogany/ten, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/item/stack/material/plank/mapped/ebony/ten, +/obj/item/stack/material/plank/mapped/bamboo/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"WM" = ( +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment/bent, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/floor/plating, +/area/liberia/hallway) +"WS" = ( +/obj/effect/paint/silver, +/obj/effect/paint_stripe/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/wall/r_titanium, +/area/liberia/mule) +"WW" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/obj/structure/bed/padded, +/obj/item/bedsheet/hos, +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"Xe" = ( +/obj/effect/floor_decal/borderfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled, +/area/liberia/hallway) +"XE" = ( +/obj/effect/floor_decal/borderfloor/corner{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green/three_quarters, +/turf/floor/tiled, +/area/liberia/hallway) +"XH" = ( +/obj/structure/cable/blue{ + icon_state = "2-8" + }, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"XJ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/alarm/liberia{ + dir = 4; + pixel_x = -25 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet/blue, +/area/liberia/personellroom1) +"XS" = ( +/obj/effect/catwalk_plated, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/liberia/hallway) +"Yt" = ( +/obj/structure/rack/dark, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"Yy" = ( +/obj/effect/floor_decal/techfloor{ + dir = 8 + }, +/obj/effect/floor_decal/corner_techfloor_grid{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/corner{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/liberia/merchantstorage) +"YD" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor{ + dir = 5 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/techfloor, +/area/liberia/engineeringstorage) +"YW" = ( +/obj/abstract/submap_landmark/spawnpoint/liberia, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) +"YX" = ( +/obj/effect/floor_decal/borderfloor, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/atmospherics/unary/tank/air{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/liberia/atmos) +"Zg" = ( +/obj/structure/rack/dark, +/obj/random/loot, +/obj/random/loot, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/techfloor/grid, +/area/liberia/merchantstorage) +"Zp" = ( +/turf/wall/r_wall/prepainted, +/area/liberia/traidingroom) +"Zu" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/machinery/fabricator/pipe, +/turf/floor/tiled/techfloor/grid, +/area/liberia/engineeringreactor) +"ZB" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/full, +/turf/floor/tiled/dark, +/area/liberia/bridge) +"ZN" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"ZO" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/space) +"ZP" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/machinery/cryopod{ + dir = 2 + }, +/turf/floor/tiled/techfloor, +/area/liberia/cryo) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +oJ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ex +bC +bC +bC +ex +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bo +bD +cc +cB +bo +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bo +bE +cd +cC +bo +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +QE +bF +ce +cD +bo +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +PW +Iy +bN +cf +cM +ex +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Lk +aa +aa +aa +aa +aa +aa +ex +ex +ex +cg +cN +ex +ex +aa +aa +aa +aa +Lk +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +OC +Lh +Nt +VX +aa +aa +aa +aa +ex +br +bO +ch +cO +dm +ex +aa +aa +oM +OC +Lh +Nt +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +ex +ex +bs +bP +cn +cP +dT +ex +ex +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +bb +ex +bt +bQ +co +cQ +dU +ex +bb +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +fl +ex +ex +bR +cp +cR +ex +ex +fl +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +bo +bu +bS +cq +cS +ec +bo +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +bo +bv +bT +cr +cV +ef +bo +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +ex +bw +bU +cs +cU +bw +ex +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +by +WS +Iq +bV +ct +uS +eg +WS +tG +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oM +ZO +oM +pS +VX +aa +aa +aa +IM +ex +bx +Gz +cu +cV +eh +ex +IM +aa +oM +ZO +oM +pS +VX +nO +ya +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +Bx +Bx +Bx +Bx +iy +xG +oM +ZO +oM +pS +VX +aa +aa +aa +aa +ex +bw +bU +cv +cU +bw +ex +aa +aa +oM +ZO +oM +pS +VX +Fc +Aa +xx +xx +xx +xx +Aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +pF +kf +BX +Sb +iy +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +bo +bz +bW +cw +cV +ep +ex +aa +aa +oM +ZO +oM +pS +VX +Fc +Aa +aK +KH +KF +pE +Aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +aM +ED +ib +Lj +iy +xG +oM +ZO +oM +pS +VX +aa +aa +aa +aa +bo +bA +bX +cx +cW +qc +ex +aa +aa +oM +ZO +oM +pS +VX +Fc +Aa +gM +hf +hp +hC +xc +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +cF +cY +dZ +IH +iy +aa +oM +ZO +oM +pS +VX +aa +aa +aa +aa +bp +bB +bY +cy +dg +ex +ex +aa +aa +oM +ZO +oM +pS +VX +Fc +Aa +gN +hh +hq +hD +xc +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +aE +da +ea +ik +iy +xG +oM +ZO +oM +pS +VX +aa +aa +aa +aa +bq +ex +bZ +cz +di +ex +EG +EG +EG +oM +ZO +oM +pS +VX +Fc +Aa +gO +hh +no +hE +xc +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +aN +aU +ih +yC +iy +aa +Sm +iA +jF +iS +Sm +aa +aa +aa +aa +aa +ex +ca +cA +dl +ey +ac +lg +EG +Sm +jh +ZN +ja +Vz +tK +Aa +gP +hi +af +hF +Aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +iy +iy +iy +iy +ii +iy +iy +IA +IA +IA +IA +iT +ur +aa +aa +aa +aa +aa +ex +ex +ex +ex +ex +EG +lh +EG +GP +JE +GP +Uh +lu +lu +Aa +gQ +Vp +Vp +Vp +Fs +Fs +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +ab +aR +jo +aZ +jq +uf +js +jr +iu +IA +iU +ur +ur +jP +ur +ur +EG +EG +EG +EG +EG +EG +EG +li +Iw +Od +sN +Od +nQ +fO +gf +gr +np +Vp +hs +hG +hN +Fs +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +ak +ij +ij +bc +cb +cE +cX +Vc +iv +IA +iW +ur +jG +jR +jY +pa +kk +ks +kB +kB +iD +kB +xr +lj +xn +Od +wq +Od +nQ +fP +gg +gs +gS +hj +ht +hH +hO +Fs +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +aq +cK +df +TT +rE +uf +le +Vk +iw +ix +lb +ur +jH +lx +lz +kg +lC +rc +Iw +Iw +Iw +Iw +Iw +Iw +Iw +Od +ic +Od +nQ +fQ +gh +gt +gT +Vp +ag +hI +ah +Fs +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +as +aH +dr +kF +mz +uf +Ei +fX +tU +Py +lc +ur +pa +pa +pa +pa +kl +QA +Iw +kC +kG +eN +kL +ll +kR +BE +id +fz +nQ +fR +gi +gu +gU +IQ +nQ +nQ +nQ +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +ay +uf +eT +pV +Ig +uf +dc +dd +SN +dP +ld +Rw +jI +ly +jZ +sF +SY +Eq +Iw +dG +aO +eY +pB +lm +eM +hY +ie +fA +nQ +fS +gj +gv +BH +hk +hv +hJ +hQ +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +az +uf +fy +pV +HG +uf +GV +Vk +Qo +HQ +Hl +Rw +jJ +jU +ka +QM +km +ku +Iw +dK +Hw +kJ +kM +ln +hW +hZ +fp +fB +nQ +fT +vR +gw +gW +bG +hw +hK +hR +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +aA +uf +ju +pV +hB +uf +oO +YD +yS +Kh +jt +Rw +QM +QM +QM +QM +kn +BJ +BJ +dx +dk +ej +Br +eC +eO +MU +fq +fC +nQ +fU +gk +gx +gX +mr +hx +hL +hS +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +uf +uf +wM +pV +Zu +uf +IA +IA +IA +Gu +IA +PI +jK +jW +kb +kh +gR +sW +BJ +dy +dN +ek +eq +eD +eY +fc +fr +YX +nQ +fV +gi +gy +gY +fG +nQ +Uh +Uh +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +dw +PG +Nw +aV +mo +uo +pJ +Rz +rn +PI +jL +jX +kc +oe +ko +kw +BJ +nD +dM +tR +er +eE +eP +fa +fs +FQ +nQ +fW +gl +gz +gZ +hl +hy +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +fm +wW +in +uf +wt +GG +Bl +Wx +Kv +PI +jM +lB +NK +Ue +kp +kx +BJ +Od +iG +Od +es +eF +eQ +SP +Od +Od +nQ +nQ +tL +gA +nQ +yp +hz +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uf +hU +Au +io +uf +Qk +Gd +eZ +dQ +Ha +PI +jO +RO +Wb +oe +kq +ky +BJ +qo +iH +qx +Hv +Hv +Hv +Hv +Hv +lp +lp +Hv +gm +gC +ha +Ht +hA +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +qj +qj +qj +qj +qj +qj +oN +dz +oN +oN +PI +Dl +lB +Tg +ki +kr +kz +BJ +Xe +iI +qx +Hv +eG +eR +fd +ft +kZ +lq +lv +oH +ro +nQ +nQ +Uh +Uh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kX +HM +JS +XJ +qj +HA +dA +Wn +tz +qx +qx +aW +aY +qx +qx +qx +qx +Xe +iZ +qx +Hv +kQ +kS +kU +la +la +lr +lw +Gy +TG +Ja +Af +Wr +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kX +Nk +XH +sS +Tz +TB +dO +fk +sQ +mT +dR +ez +eA +eB +fn +fo +hT +ig +lf +el +Hv +eH +eS +kV +fu +lo +ls +Hv +lR +ro +nH +QK +Wr +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kX +WW +rZ +Mm +qj +FZ +WM +XS +Eb +XS +XS +ar +qm +ci +ci +GE +dn +dB +dS +qx +Hv +Hv +Hv +Hv +Hv +Hv +Hv +Hv +lt +ro +bn +Ml +Wr +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +qj +qj +qj +DI +DI +lD +lD +lD +lD +lD +Nv +bH +cj +Nv +Nv +Nv +Nv +dC +dV +qx +et +eI +qx +fe +fv +fD +fI +qx +ip +ro +Lz +Lz +BC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +al +jV +to +iB +ae +al +at +aC +lD +be +bI +fF +cG +cZ +Nv +do +dD +dW +em +kO +kO +kT +kW +kO +fE +kO +fY +kO +se +Lz +Ez +BC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +sJ +Yy +mu +qI +zd +qI +Yy +aD +lD +bf +bJ +fF +cI +os +de +dp +dE +dX +DP +yh +yh +eU +ff +PU +yh +XE +ff +yh +gD +Lz +EQ +BC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +ck +zQ +kt +qR +ss +BW +zQ +SU +lD +bg +bJ +fF +cI +pZ +de +dp +dF +dY +kK +qx +eJ +Sa +fg +Sa +Sa +ip +LW +pD +OA +Lz +VZ +BC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +ee +zQ +kt +xT +qg +Hm +ml +aF +aP +bh +bK +cl +cJ +sY +Nv +dq +dF +eb +pf +eu +qx +eV +fh +fw +Sa +lt +fZ +OA +gE +hb +hm +Se +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +ho +qD +au +Yt +Am +op +zQ +aG +aQ +VP +en +fF +Nq +Nv +Nv +Nv +dF +eb +th +ev +qx +eW +fi +fx +Sa +ip +ga +gn +gF +hc +hn +Se +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +HV +jV +Aq +yP +vd +WC +Ut +Qj +lD +bj +fF +fF +fF +fF +rx +ns +DL +eb +JI +ew +qx +eX +YW +oD +Sa +ip +LW +OA +gG +hd +Se +Se +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +hM +yU +qA +QH +Zg +HV +aI +HV +bk +fF +yL +cL +AT +ds +iK +iX +jg +LJ +qx +qx +ZP +YW +oS +Az +rT +LW +OA +gH +he +Se +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +HV +iV +zQ +kt +RF +HV +Io +HV +bl +bM +cm +Lm +Lm +Lm +dH +Lm +Lm +Lm +qx +qx +pX +aX +OT +Az +EZ +gb +St +St +Mj +Se +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +jv +zQ +kt +mO +HV +zt +HV +Zp +Zp +Zp +zq +db +dt +fM +ed +jT +zq +AO +AO +Az +tI +Az +Az +fK +dJ +go +gI +Mj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +jw +zQ +kt +jy +HV +aa +aa +xG +aa +aa +ps +Um +dh +iL +jB +vi +ps +aa +aa +xG +aa +aa +Mj +fL +gc +gp +gJ +zn +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +Ep +zQ +kt +jA +HV +aa +aa +xG +aa +aa +ps +DK +Jf +ad +lE +ZB +ps +aa +aa +xG +aa +aa +zn +jQ +gd +oF +gK +zn +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +Km +qD +UV +jE +HV +aa +aa +xG +aa +aa +ps +Qi +dI +jx +jC +wK +ps +aa +aa +xG +aa +aa +zn +fN +ge +gq +gL +Mj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HV +HV +HV +HV +HV +HV +xG +xG +xG +xG +xG +zq +fJ +dL +jz +jD +eo +zq +xG +xG +xG +xG +xG +Mj +zn +zn +Mj +Mj +Mj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ps +Qi +Ro +dv +Ro +wK +ps +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ps +jS +zl +iN +Uc +HT +ps +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +zq +zq +iz +iO +iY +zq +zq +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +zq +bm +bm +bm +zq +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(129,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(130,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(131,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(132,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(133,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(134,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(135,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(136,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(137,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(138,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(139,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(140,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(141,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(142,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(143,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(144,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(145,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(146,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(147,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(148,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(149,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(150,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(151,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(152,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(153,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(154,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(155,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(156,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(157,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(158,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(159,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(160,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(161,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(162,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(163,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(164,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(165,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(166,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(167,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(168,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(169,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(170,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(171,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(172,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(173,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(174,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(175,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(176,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(177,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(178,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(179,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(180,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(181,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(182,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(183,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(184,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(185,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(186,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(187,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(188,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(189,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(190,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(191,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(192,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(193,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(194,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(195,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(196,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(197,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(198,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(199,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(200,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/away/liberia/liberia_areas.dm b/maps/away/liberia/liberia_areas.dm new file mode 100644 index 000000000000..de18310846c2 --- /dev/null +++ b/maps/away/liberia/liberia_areas.dm @@ -0,0 +1,95 @@ +/area/liberia + req_access = list(access_merchant) + +/area/liberia/dockinghall + name = "\improper Liberia - Docking Hall" + icon_state = "entry_1" + +/area/liberia/guestroom1 + name = "\improper Liberia - Guest Room 1" + icon_state = "green" + +/area/liberia/guestroom2 + name = "\improper Liberia - Guest Room 2" + icon_state = "red" + +/area/liberia/library + name = "\improper Liberia - Library" + icon_state = "library" + +/area/liberia/hallway + name = "\improper Liberia - Hallway" + icon_state = "hallC1" + +/area/liberia/merchantstorage + name = "\improper Liberia - Merchant Storage" + icon_state = "storage" + +/area/liberia/engineeringlobby + name = "\improper Liberia - Engineering Lobby" + icon_state = "primarystorage" + +/area/liberia/engineeringstorage + name = "\improper Liberia - Engineering Storage" + icon_state = "emergencystorage" + +/area/liberia/engineeringreactor + name = "\improper Liberia - Engineering Reactor" + icon_state = "engineering_workshop" + +/area/liberia/engineeringengines + name = "\improper Liberia - Engineering Engines" + icon_state = "engine" + +/area/liberia/personellroom1 + name = "\improper Liberia - Personal Room 1" + icon_state = "dk_yellow" + +/area/liberia/personellroom2 + name = "\improper Liberia - Personal Room 2" + icon_state = "purple" + +/area/liberia/traidingroom + name = "\improper Liberia - Traiding Room" + icon_state = "purple" + +/area/liberia/bridge + name = "\improper Liberia - Bridge" + icon_state = "bridge" + +/area/liberia/cryo + name = "\improper Liberia - Cryo" + icon_state = "crew_quarters" + +/area/liberia/medbay + name = "\improper Liberia - Medbay" + icon_state = "medbay" + +/area/liberia/officeroom + name = "\improper Liberia - Office Room" + icon_state = "observatory" + +/area/liberia/toiletroom1 + name = "\improper Liberia - Shower" + icon_state = "showroom" + +/area/liberia/toiletroom2 + name = "\improper Liberia - Toilet" + icon_state = "toilet" + +/area/liberia/bar + name = "\improper Liberia - Bar" + icon_state = "bar" + +/area/liberia/captain + name = "\improper Liberia - Captain Office" + icon_state = "blue-red" + req_access = list(access_merchant) + +/area/liberia/atmos + name = "\improper Liberia - Atmos Chamber" + icon_state = "atmos" + +/area/liberia/mule + name = "\improper Mule" + icon_state = "shuttle" diff --git a/maps/away/liberia/liberia_jobs.dm b/maps/away/liberia/liberia_jobs.dm new file mode 100644 index 000000000000..34269ce2cd3a --- /dev/null +++ b/maps/away/liberia/liberia_jobs.dm @@ -0,0 +1,56 @@ +// Submap datum and archetype. +/decl/submap_archetype/liberia + name = "merchant ship" + crew_jobs = list( + /datum/job/submap/merchant + ) + +/datum/job/submap/merchant + title = "Merchant" + total_positions = 4 + info = "You are free traders who have drifted into unknown distances in search of profit. Travel, trade, make profit!" + supervisors = "the invisible hand of the market" + selection_color = "#515151" + hud_icon = 'maps/away/liberia/hud.dmi' + hud_icon_state = "hudmerchant" + ideal_character_age = 20 + minimal_player_age = 7 + + outfit_type = /decl/outfit/job/merchant + + skill_points = 24 + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_FINANCE = SKILL_ADEPT, + SKILL_PILOT = SKILL_BASIC + ) + +/datum/job/submap/merchant/equip_job(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) + to_chat(H, "Your connections helped you learn about the words that will help you identify a locals... Particularly interested buyers:") + to_chat(H, "Code phases: [syndicate_code_phrase]") + to_chat(H, "Responses to phrases: [syndicate_code_response]") + H.StoreMemory("Code phase: [syndicate_code_phrase]", /decl/memory_options/system) + H.StoreMemory("Responses to phrases: [syndicate_code_response]", /decl/memory_options/system) + return ..() + +// Spawn points. +/obj/abstract/submap_landmark/spawnpoint/liberia + name = "Merchant" + +/decl/outfit/job/merchant + name = "Job - Merchant - Liberia" + shoes = /obj/item/clothing/shoes/color/black + l_ear = /obj/item/radio/headset + uniform = /obj/item/clothing/pants/casual/camo/outfit_tacticool + id_slot = slot_wear_id_str + id_type = /obj/item/card/id/merchant + pda_slot = slot_r_store_str + pda_type = /obj/item/modular_computer/pda //cause I like the look + id_pda_assignment = "Merchant" + +/obj/item/card/id/merchant + name = "identification card" + desc = "A card issued to Merchants, indicating their right to sell and buy goods." + access = list(access_merchant) + color = COLOR_OFF_WHITE + detail_color = COLOR_BEIGE diff --git a/maps/away/liberia/liberia_machinery.dm b/maps/away/liberia/liberia_machinery.dm new file mode 100644 index 000000000000..cca1b41781d4 --- /dev/null +++ b/maps/away/liberia/liberia_machinery.dm @@ -0,0 +1,11 @@ +/obj/machinery/apc/liberia + req_access = list(access_merchant) + +/obj/machinery/alarm/liberia + req_access = list(access_merchant) + +/obj/machinery/suit_cycler/engineering/prepared/liberia + req_access = list(access_merchant) + +/obj/machinery/suit_cycler/engineering/prepared/atmospheric/liberia + req_access = list(access_merchant) diff --git a/maps/away/liberia/liberia_shuttles.dm b/maps/away/liberia/liberia_shuttles.dm new file mode 100644 index 000000000000..3dd672effbef --- /dev/null +++ b/maps/away/liberia/liberia_shuttles.dm @@ -0,0 +1,34 @@ +// Submap shuttles. +// Mule - Shuttle One, Port Side +/obj/effect/overmap/visitable/ship/landable/mule + name = "Mule" + shuttle = "Mule" + moving_state = "ship_moving" + max_speed = 1/(2 SECONDS) + burn_delay = 1 SECONDS + vessel_mass = 5000 + fore_dir = WEST + skill_needed = SKILL_BASIC + vessel_size = SHIP_SIZE_SMALL + +/obj/machinery/computer/shuttle_control/explore/mule + name = "shuttle control console" + shuttle_tag = "Mule" + +/obj/effect/shuttle_landmark/mule/start + name = "Mule Dock" + landmark_tag = "nav_mule_start" + docking_controller = "mule_port_dock" + flags = SLANDMARK_FLAG_REORIENT + +/datum/shuttle/autodock/overmap/mule + name = "Mule" + warmup_time = 5 + current_location = "nav_mule_start" + range = 2 + dock_target = "mule_port_shuttle_dock" + shuttle_area = list(/area/liberia/mule) + defer_initialisation = TRUE + flags = SHUTTLE_FLAGS_PROCESS + skill_needed = SKILL_BASIC + ceiling_type = /turf/floor/shuttle_ceiling diff --git a/maps/away/lost_supply_base/lost_supply_base.dm b/maps/away/lost_supply_base/lost_supply_base.dm index 6ca6031ac422..fd1a4fb3225d 100644 --- a/maps/away/lost_supply_base/lost_supply_base.dm +++ b/maps/away/lost_supply_base/lost_supply_base.dm @@ -3,9 +3,8 @@ /obj/effect/overmap/visitable/sector/lost_supply_base name = "supply station" - desc = "This looks like abandoned and heavy damaged supply station." + desc = "This looks like an abandoned and heavily damaged supply station." icon_state = "object" - known = 0 initial_generic_waypoints = list( "nav_lost_supply_base_1", @@ -16,11 +15,10 @@ /datum/map_template/ruin/away_site/lost_supply_base name = "Lost Supply Base" - id = "awaysite_lost_supply_base" description = "An abandoned supply base." suffixes = list("lost_supply_base/lost_supply_base.dmm") cost = 1 - generate_mining_by_z = 1 + level_data_type = /datum/level_data/mining_level area_usage_test_exempted_root_areas = list(/area/lost_supply_base) apc_test_exempt_areas = list( /area/lost_supply_base/solar = NO_SCRUBBER|NO_VENT @@ -40,4 +38,9 @@ /obj/effect/shuttle_landmark/nav_lost_supply_base/navantag name = "Abandoned Supply Base Navpoint #4" - landmark_tag = "nav_lost_supply_base_antag" \ No newline at end of file + landmark_tag = "nav_lost_supply_base_antag" + +/obj/effect/shuttle_landmark/nav_lost_supply_base/docking + name = "docking port" + landmark_tag = "nav_lost_supply_base_docking" + flags = SLANDMARK_FLAG_REORIENT | SLANDMARK_FLAG_AUTOSET \ No newline at end of file diff --git a/maps/away/lost_supply_base/lost_supply_base.dmm b/maps/away/lost_supply_base/lost_supply_base.dmm index da36b41cd02b..1123fa66fe22 100644 --- a/maps/away/lost_supply_base/lost_supply_base.dmm +++ b/maps/away/lost_supply_base/lost_supply_base.dmm @@ -14,10 +14,9 @@ "ad" = ( /obj/machinery/power/tracker, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ae" = ( /obj/effect/shuttle_landmark/nav_lost_supply_base/nav3, @@ -25,156 +24,116 @@ /area/space) "af" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ag" = ( /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ah" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/item/stack/material/steel, -/turf/simulated/floor/airless, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/plating/airless, /area/space) "ai" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aj" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ak" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "al" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "am" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "an" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ao" = ( /obj/structure/cable/yellow, /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ap" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aq" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/space) "ar" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/item/stack/material/rods{ - amount = 50 - }, -/obj/item/stack/material/steel, -/turf/simulated/floor/airless, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/plating/airless, /area/space) "as" = ( /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "at" = ( /obj/effect/shuttle_landmark/nav_lost_supply_base/nav1, @@ -182,12 +141,11 @@ /area/space) "au" = ( /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/structure/cable/yellow, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "av" = ( /obj/structure/girder/displaced, @@ -197,25 +155,22 @@ /obj/structure/lattice, /obj/structure/grille, /obj/structure/grille, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ax" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/solar) "ay" = ( /obj/machinery/door/airlock/external{ - icon_state = "door_locked"; id_tag = "solar_outer"; locked = 1; name = "Solar External Access" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/shield_diffuser, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "az" = ( /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ @@ -225,10 +180,10 @@ tag_airpump = "solar_starboard_pump"; tag_chamber_sensor = "solar_starboard_sensor"; tag_exterior_door = "solar_starboard_outer"; - tag_interior_door = "solar_starboard_inner" + tag_interior_door = "solar_starboard_inner"; + dir = 8 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; id_tag = "solar_starboard_pump" }, /obj/machinery/airlock_sensor{ @@ -237,36 +192,31 @@ pixel_y = 12 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning/full, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "aA" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base) "aB" = ( /obj/machinery/door/airlock/external{ - icon_state = "door_locked"; id_tag = "solar_inner"; locked = 1; name = "Solar Access" }, /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "aC" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/office) "aD" = ( /turf/space, @@ -278,62 +228,55 @@ "aF" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aG" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aH" = ( /obj/item/frame/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aI" = ( /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aJ" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aK" = ( -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/solar) "aL" = ( /obj/machinery/power/solar_control{ - id = "suuplybasesolar"; - name = "Solar Control"; - track = 0 + name = "Solar Control" }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/effect/floor_decal/industrial/warning/corner{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "aM" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8; - icon_state = "map" + dir = 8 }, /obj/machinery/button/access/interior{ id_tag = "solar_starboard_airlock"; @@ -343,16 +286,12 @@ req_access = newlist() }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "aN" = ( /obj/machinery/portable_atmospherics/canister/air/airlock, @@ -363,85 +302,75 @@ dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "aO" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "aP" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "aQ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/office) "aR" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/item/paper, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "aS" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "aT" = ( -/obj/structure/bed/chair/comfy/captain, -/turf/simulated/floor/tiled/airless, +/obj/structure/chair/comfy/captain, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "aU" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "aV" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "aW" = ( /obj/item/paper, /obj/structure/safe, /obj/random/drinkbottle, /obj/random/handgun, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "aX" = ( /obj/machinery/atmospherics/unary/vent_pump/tank{ @@ -458,59 +387,55 @@ pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aY" = ( /obj/machinery/atmospherics/binary/pump/on{ dir = 8; target_pressure = 200 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "aZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base) "ba" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/cyan{ - dir = 9; - icon_state = "intact" + dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bb" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bc" = ( /obj/random/projectile, -/obj/effect/landmark/corpse/syndicate, -/turf/simulated/floor/airless, +/obj/abstract/landmark/corpse/syndicate, +/turf/floor/plating/airless, /area/lost_supply_base) "bd" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "be" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bf" = ( /obj/structure/closet/crate/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "bg" = ( /obj/machinery/atmospherics/binary/pump/on{ @@ -518,58 +443,51 @@ target_pressure = 200 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "bh" = ( /obj/machinery/power/terminal, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "bi" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "bj" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "bk" = ( /obj/structure/table/steel_reinforced, /obj/random/handgun, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bl" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bm" = ( /obj/item/stack/tile/floor_dark{ pixel_x = 5; pixel_y = -3 }, -/obj/item/stack/material/steel, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" - }, +/obj/item/stack/material/sheet/mapped/steel, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bn" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bo" = ( /obj/item/stack/tile/floor_dark{ @@ -584,157 +502,131 @@ /area/space) "bq" = ( /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, -/area/lost_supply_base) -"br" = ( -/obj/machinery/door/airlock/external{ - icon_state = "door_locked"; - id_tag = "centcom_shuttle_bay_door"; - locked = 1; - name = "Transport Airlock" - }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bs" = ( /obj/effect/floor_decal/industrial/hatch/yellow, /obj/machinery/button/access/interior{ id_tag = "solar_starboard_airlock"; name = "interior access button"; - pixel_x = -24; + pixel_x = -20; pixel_y = 24; - req_access = newlist() - }, -/turf/simulated/floor/airless, -/area/lost_supply_base) -"bt" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken4" + req_access = newlist(); + dir = 4 }, +/turf/floor/plating/airless, /area/lost_supply_base) "bu" = ( /obj/effect/decal/cleanable/blood, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bv" = ( /obj/effect/floor_decal/industrial/hatch/yellow, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bw" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bx" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "by" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/tech_supply, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bz" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/solar) "bA" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "bB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "bC" = ( /obj/machinery/power/smes/buildable{ - charge = 0; + RCon_tag = "Supply base MAIN"; input_level = 5000; - input_level_max = 20000; - RCon_tag = "Supply base MAIN" + input_level_max = 20000 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lost_supply_base/solar) "bD" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "bE" = ( /obj/item/pen/red, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bF" = ( -/obj/effect/landmark/corpse/engineer, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/corpse/engineer, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bG" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken4" +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/button/access/interior{ + id_tag = "solar_starboard_airlock"; + name = "interior access button"; + pixel_x = -24; + pixel_y = 24; + req_access = newlist(); + dir = 4 }, -/area/lost_supply_base/office) +/turf/floor/plating/airless, +/area/lost_supply_base) "bH" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken1" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bI" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/wall/r_wall, +/turf/floor/plating/airless, /area/lost_supply_base/office) "bJ" = ( /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ @@ -744,197 +636,195 @@ tag_airpump = "solar_starboard_pump"; tag_chamber_sensor = "solar_starboard_sensor"; tag_exterior_door = "solar_starboard_outer"; - tag_interior_door = "solar_starboard_inner" + tag_interior_door = "solar_starboard_inner"; + dir = 8; + pixel_y = -4 }, /obj/machinery/airlock_sensor{ id_tag = "solar_starboard_sensor"; pixel_x = 24; - pixel_y = 12 + pixel_y = 8; + dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bK" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bL" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bM" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/tech_supply, /obj/item/radio, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bN" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base/solar) "bO" = ( /obj/random/ammo, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bP" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bQ" = ( /turf/space, /area/lost_supply_base/office) "bR" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/wall/r_wall, +/turf/floor/plating/airless, /area/lost_supply_base) "bS" = ( /obj/random/trash, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bT" = ( /obj/item/stack/tile/floor_dark{ pixel_x = 5; pixel_y = -3 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bU" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "bV" = ( -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base) "bW" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken1" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base) "bX" = ( /obj/machinery/door/airlock{ name = "Control room" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bY" = ( /obj/machinery/atmospherics/unary/vent_scrubber, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "bZ" = ( /obj/machinery/light, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "ca" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/office) "cb" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" +/obj/machinery/door/airlock/external{ + id_tag = "centcom_shuttle_bay_door"; + locked = 1; + name = "Transport Airlock" }, -/area/lost_supply_base/office) +/turf/floor/plating/airless, +/area/lost_supply_base) "cc" = ( -/obj/item/stack/material/steel, +/obj/item/stack/material/sheet/mapped/steel, /turf/space, /area/space) "cd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ce" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/lost_supply_base) "cf" = ( -/obj/item/stack/material/rods, -/obj/item/stack/material/steel, -/turf/simulated/floor/airless, +/obj/item/stack/material/rods/mapped/steel, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/plating/airless, /area/lost_supply_base) "cg" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken4" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base) "ch" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "ci" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/common) "cj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/common) "ck" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/common) "cl" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cm" = ( /obj/random/trash, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken1" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base) "cn" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "co" = ( /obj/effect/decal/cleanable/blood/gibs/body, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cp" = ( /obj/structure/door_assembly, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cq" = ( /obj/machinery/atmospherics/omni/mixer{ @@ -945,20 +835,17 @@ tag_west = 2; use_power = 0 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cr" = ( /obj/structure/cable, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cs" = ( /obj/item/stack/tile/floor_dark{ @@ -969,191 +856,159 @@ pixel_x = 5; pixel_y = -3 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ct" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "cu" = ( /obj/item/stack/tile/floor_dark{ pixel_x = 5; pixel_y = -3 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "cv" = ( -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/common) "cw" = ( /obj/machinery/fabricator/replicator, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cx" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/light{ dir = 1 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cy" = ( /obj/machinery/gibber, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cz" = ( /obj/structure/closet/secure_closet/freezer/meat, /obj/machinery/cooker/oven, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cA" = ( /obj/structure/closet/secure_closet/freezer/meat, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cB" = ( /obj/structure/closet/secure_closet/freezer/meat, /obj/structure/closet/secure_closet/freezer/meat, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cC" = ( /obj/structure/closet/crate/freezer, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cD" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cE" = ( -/obj/item/stack/material/cardboard, -/turf/simulated/floor/airless, +/obj/item/stack/material/cardstock/mapped/cardboard, +/turf/floor/plating/airless, /area/lost_supply_base) "cF" = ( /obj/item/scanner/price, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/lost_supply_base) "cH" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/airless, -/area/lost_supply_base) -"cI" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" - }, +/turf/floor/plating/airless, /area/lost_supply_base) "cJ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base) "cK" = ( -/turf/simulated/floor/tiled/airless, -/area/lost_supply_base/common) -"cL" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cM" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/space, +/turf/floor/plating/airless, /area/lost_supply_base/common) -"cN" = ( -/obj/item/frame/light, -/turf/simulated/floor/airless, -/area/lost_supply_base) "cO" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/airless, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating/airless, /area/lost_supply_base) "cP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base) "cR" = ( /obj/item/frame/light, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "cS" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/lost_supply_base) "cT" = ( /obj/structure/girder/displaced, /turf/space, /area/lost_supply_base) -"cU" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" - }, -/area/lost_supply_base) "cV" = ( /obj/random/junk, -/turf/simulated/floor/tiled/airless, -/area/lost_supply_base/common) -"cW" = ( -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/wall/r_wall, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "cX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/lost_supply_base) "cY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/lost_supply_base) "cZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1162,12 +1017,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall, +/obj/abstract/landmark/allowed_leak, +/turf/wall, /area/lost_supply_base) "da" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1176,42 +1030,41 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "db" = ( /obj/machinery/door/window/southleft, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dc" = ( -/obj/structure/table/standard, -/obj/item/trash/tray{ +/obj/structure/table, +/obj/item/plate/tray{ pixel_x = 10 }, -/obj/item/trash/tray, -/turf/simulated/floor/tiled/airless, +/obj/item/plate/tray, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dd" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/airless, +/obj/structure/table, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "de" = ( -/obj/structure/table/standard, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled/airless, +/obj/structure/table, +/obj/item/utensil/fork, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "df" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/microwave, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dg" = ( /obj/structure/closet/crate/secure/explosives{ name = "mineral crate"; req_access = newlist() }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dh" = ( /obj/effect/floor_decal/industrial/warning{ @@ -1221,58 +1074,54 @@ name = "mineral crate"; req_access = newlist() }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "di" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dj" = ( /obj/random/ammo, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dk" = ( /obj/structure/mech_wreckage/powerloader, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dl" = ( /obj/item/frame/light, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dm" = ( -/obj/item/stack/material/steel, -/turf/simulated/floor/airless, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/plating/airless, /area/lost_supply_base) "dn" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "do" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "dp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base) "dq" = ( /obj/machinery/door/airlock{ @@ -1281,249 +1130,203 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dr" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "ds" = ( /obj/structure/closet/crate/secure/gear, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dt" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/closet/crate/hydroponics, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "du" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, -/obj/item/storage/backpack/dufflebag, -/turf/simulated/floor/airless, +/obj/item/backpack/dufflebag, +/turf/floor/plating/airless, /area/lost_supply_base) "dv" = ( /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/blood/writing, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base) "dx" = ( -/obj/item/kitchen/utensil/spoon, -/turf/simulated/floor/tiled/airless, +/obj/item/utensil/spoon, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dy" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dz" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/trash/plate, -/turf/simulated/floor/tiled/airless, +/obj/item/plate, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dA" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dB" = ( -/obj/item/kitchen/utensil/fork, -/obj/structure/bed/chair{ +/obj/item/utensil/fork, +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dC" = ( /obj/random/trash, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "dE" = ( /obj/machinery/door/airlock/external{ - icon_state = "door_locked"; id_tag = "centcom_shuttle_hatch"; locked = 1; name = "Shuttle Hatch" }, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "dF" = ( -/turf/simulated/shuttle/wall{ - dir = 4; - icon_state = "swall" - }, -/area/space) -"dG" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_t"; - dir = 1 - }, -/area/space) -"dH" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_straight"; - dir = 4 - }, -/area/space) -"dI" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_s"; - dir = 2 +/turf/wall/shuttle{ + unique_merge_identifier = "supply_base" }, /area/space) "dJ" = ( /obj/random/junk, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dL" = ( /obj/machinery/atmospherics/unary/tank/oxygen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dM" = ( /obj/machinery/atmospherics/unary/tank/air, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dN" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "dO" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base) "dP" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/common) -"dR" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_straight"; - dir = 1 - }, -/area/space) "dS" = ( -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "dT" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/random/handgun, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "dU" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/shuttle/blue, +/obj/structure/chair, +/turf/floor/shuttle/blue, /area/space) "dV" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/random/smokes, -/turf/simulated/floor/shuttle/blue, -/area/space) -"dW" = ( -/turf/simulated/shuttle/wall{ - dir = 1; - icon_state = "swall_f" - }, +/turf/floor/shuttle/blue, /area/space) "dX" = ( /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dY" = ( /obj/item/stack/tile/floor_dark, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "dZ" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "eb" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ec" = ( /obj/random/tank, /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ed" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ee" = ( /obj/random/trash, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "ef" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "eg" = ( -/obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion_r"; +/obj/structure/shuttle/engine/propulsion/right{ dir = 8 }, /turf/space, /area/space) "eh" = ( /obj/structure/shuttle/engine/heater{ - icon_state = "heater"; dir = 8 }, /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/shuttle/blue, -/area/space) -"ei" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall"; - dir = 1 - }, +/turf/floor/shuttle/blue, /area/space) "ej" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "ek" = ( /obj/structure/grille, @@ -1535,199 +1338,166 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/space) "el" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "em" = ( /obj/effect/decal/cleanable/blood/splatter, -/obj/effect/landmark/corpse/engineer, -/turf/simulated/floor/airless, +/obj/abstract/landmark/corpse/engineer, +/turf/floor/plating/airless, /area/lost_supply_base) "en" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "eo" = ( /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ep" = ( /obj/random/tank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "eq" = ( /obj/structure/closet/medical_wall{ - pixel_x = -30 + pixel_x = -30; + dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "er" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/flame/lighter/random, -/turf/simulated/floor/tiled/airless, +/obj/item/flame/fuelled/lighter/random, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "es" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/chems/food/drinks/cans/waterbottle, -/turf/simulated/floor/tiled/airless, +/obj/item/chems/drinks/cans/waterbottle, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "et" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 - }, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" + dir = 4; + icon_state = "tube1" }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "ev" = ( /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "ew" = ( /obj/structure/door/shuttle, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "ex" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/item/key, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "ey" = ( -/obj/item/stack/material/cardboard, +/obj/item/stack/material/cardstock/mapped/cardboard, /obj/item/grenade/fake, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ez" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "eA" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken4" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base/common) -"eB" = ( -/turf/simulated/shuttle/wall{ - dir = 2; - icon_state = "swall" - }, -/area/space) "eD" = ( /obj/machinery/atmospherics/unary/tank/hydrogen{ - dir = 2; - volume = 3200 + gas_volume = 3200 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "eE" = ( /obj/item/bedsheet, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "eF" = ( /obj/machinery/atmospherics/unary/vent_scrubber, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "eG" = ( /obj/machinery/light, /obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "eH" = ( /obj/machinery/computer/arcade, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "eI" = ( /obj/machinery/light, /obj/machinery/computer/arcade, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "eJ" = ( /obj/machinery/media/jukebox, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) "eK" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "eL" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/tank/air, /obj/random/tech_supply, /obj/item/clothing/mask/breath, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "eM" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) "eN" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/random/voidhelmet, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, /area/space) -"eO" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_f"; - dir = 4 - }, -/area/space) -"eP" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_s"; - dir = 8 - }, -/area/space) -"eQ" = ( -/turf/simulated/floor/airless, -/area/lost_supply_base) -"eS" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/turf/simulated/floor/airless, -/area/lost_supply_base) "eT" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "eU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/common) "eV" = ( /obj/machinery/door/airlock{ @@ -1736,173 +1506,148 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/common) -"eW" = ( -/turf/simulated/shuttle/wall{ - dir = 5; - icon_state = "swall" - }, -/area/space) -"eX" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_t"; - dir = 2 - }, -/area/space) "eY" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "eZ" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fa" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fb" = ( /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base) "fc" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/random/obstruction, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "fd" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/random/obstruction, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "fe" = ( /obj/machinery/door/airlock{ name = "Bunk room" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "ff" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fg" = ( /obj/structure/closet/emcloset, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fh" = ( /obj/structure/bed, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fi" = ( /obj/structure/closet, /obj/random/clothing, /obj/item/trash/liquidfood, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fj" = ( /obj/structure/bed, /obj/random/plushie, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fk" = ( /obj/structure/closet, /obj/random/clothing, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fl" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base/supply) "fm" = ( /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fn" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fo" = ( /obj/random/junk, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "fp" = ( -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/supply) "fq" = ( /obj/item/bedsheet, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fr" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned0" - }, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fs" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "ft" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/smokes, /obj/item/radio, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fu" = ( /obj/effect/shuttle_landmark/nav_lost_supply_base/nav2, @@ -1911,28 +1656,27 @@ "fv" = ( /obj/structure/window/reinforced, /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fw" = ( /obj/structure/window/reinforced, /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fx" = ( /obj/machinery/atmospherics/unary/vent_scrubber{ - icon_state = "map_scrubber_off"; dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fz" = ( /obj/random/junk, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fA" = ( -/obj/structure/table/standard, -/obj/item/storage/briefcase, -/turf/simulated/floor/tiled/airless, +/obj/structure/table, +/obj/item/briefcase, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fB" = ( /obj/structure/sign/warning{ @@ -1940,30 +1684,30 @@ }, /obj/machinery/portable_atmospherics/canister/air, /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fC" = ( /obj/random/energy, -/obj/effect/landmark/corpse/syndicate, -/turf/simulated/floor/airless, +/obj/abstract/landmark/corpse/syndicate, +/turf/floor/plating/airless, /area/lost_supply_base) "fD" = ( /obj/effect/floor_decal/industrial/hatch/yellow, -/obj/effect/landmark/corpse/engineer, -/turf/simulated/floor/airless, +/obj/abstract/landmark/corpse/engineer, +/turf/floor/plating/airless, /area/lost_supply_base) "fE" = ( /obj/machinery/atmospherics/unary/vent_scrubber, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fF" = ( /obj/machinery/light, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fG" = ( /obj/machinery/light, /obj/structure/bed, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fH" = ( /obj/structure/largecrate, @@ -1971,17 +1715,17 @@ dir = 8; target_pressure = 200 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fI" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fJ" = ( -/obj/item/twohanded/fireaxe, +/obj/item/bladed/axe/fire, /obj/effect/decal/cleanable/blood, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fK" = ( /obj/effect/floor_decal/industrial/hatch/yellow, @@ -1990,41 +1734,39 @@ pixel_x = 5; pixel_y = -3 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fL" = ( /obj/effect/decal/cleanable/blood/writing{ dir = 4 }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fM" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/obj/abstract/landmark/allowed_leak, +/obj/abstract/landmark/proc_caller/floor_burner, +/turf/floor/tiled/airless, /area/lost_supply_base) "fN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/item/stack/material/steel, -/turf/simulated/floor/tiled/airless, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/tiled/airless, /area/lost_supply_base) "fO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/supply) "fP" = ( /obj/machinery/door/airlock{ @@ -2033,23 +1775,21 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/space, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fQ" = ( /obj/structure/door_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fR" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "fS" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2059,73 +1799,52 @@ pixel_x = 5; pixel_y = -3 }, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, /area/lost_supply_base) "fT" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/lost_supply_base/supply) "fU" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" - }, -/area/lost_supply_base/supply) -"fV" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_burned1" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fW" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "fX" = ( /obj/item/gun/projectile/shotgun/pump, -/obj/effect/landmark/corpse/syndicate, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken4" - }, +/obj/abstract/landmark/corpse/syndicate, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) -"fY" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 4 - }, -/turf/simulated/floor/airless, -/area/lost_supply_base) "fZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 6 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ga" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lost_supply_base) "gb" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "solar_starboard_airlock"; @@ -2134,14 +1853,17 @@ tag_airpump = "solar_starboard_pump"; tag_chamber_sensor = "solar_starboard_sensor"; tag_exterior_door = "solar_starboard_outer"; - tag_interior_door = "solar_starboard_inner" + tag_interior_door = "solar_starboard_inner"; + dir = 8; + pixel_y = -4 }, /obj/machinery/airlock_sensor{ id_tag = "solar_starboard_sensor"; pixel_x = 24; - pixel_y = 12 + pixel_y = 8; + dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "gc" = ( /obj/effect/floor_decal/industrial/warning, @@ -2149,36 +1871,36 @@ dir = 8; target_pressure = 200 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "gd" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "ge" = ( /obj/machinery/atmospherics/portables_connector{ dir = 8 }, /obj/effect/floor_decal/industrial/warning/full, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "gf" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "gg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, /area/lost_supply_base) "gh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2188,39 +1910,34 @@ pixel_x = 5; pixel_y = -3 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "gi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "gj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "gk" = ( /obj/machinery/door/airlock{ name = "Head" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) -"gl" = ( -/obj/structure/lattice, -/obj/structure/grille, -/turf/space, -/area/lost_supply_base) "gm" = ( /obj/machinery/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/lost_supply_base) "gn" = ( /obj/structure/closet/crate/trashcart, /obj/item/mop, -/obj/item/storage/box/lights/bulbs, +/obj/item/box/lights/bulbs, /obj/machinery/atmospherics/unary/vent_pump{ dir = 1; external_pressure_bound = 0; @@ -2229,32 +1946,31 @@ initialize_directions = 1; internal_pressure_bound = 4000; internal_pressure_bound_default = 4000; - use_power = 1; pressure_checks = 2; pressure_checks_default = 2; - pump_direction = 0 + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base) "go" = ( -/obj/item/stack/material/steel, -/turf/simulated/floor/tiled/airless, +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/tiled/airless, /area/lost_supply_base) "gq" = ( /obj/structure/hygiene/toilet{ dir = 1 }, /obj/machinery/light/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "gr" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, /obj/random/soap, /obj/machinery/light/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) "gs" = ( /obj/effect/shuttle_landmark/nav_lost_supply_base/navantag, @@ -2264,29 +1980,51 @@ /turf/unsimulated/mask, /area/mine/unexplored) "gu" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "ib" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -32 }, /obj/machinery/light/small, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless, /area/lost_supply_base/supply) +"nL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/lost_supply_base) "Jd" = ( /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/shuttle/blue, +/turf/floor/shuttle/blue, +/area/space) +"OK" = ( +/obj/structure/grille, +/obj/structure/lattice, +/turf/space, +/area/lost_supply_base) +"PE" = ( +/obj/effect/shuttle_landmark/nav_lost_supply_base/docking{ + dir = 4 + }, +/turf/space, /area/space) +"Xs" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating/airless, +/area/lost_supply_base) (1,1,1) = {" aa @@ -6003,9 +5741,9 @@ aa aa aa aa -eg -eg -eg +aa +aa +aa aa aa aa @@ -6103,13 +5841,13 @@ aa aa aa aa -eB -dR -eh -eh -eh -dR -eW +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6205,13 +5943,13 @@ aa aa aa aa -dE -dS -dS -ev -dS -eK -dH +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6307,13 +6045,13 @@ aa aa aa aa -dF -dS -dS -dS -dS -eL -dH +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6409,13 +6147,13 @@ aa aa aa aa -dG -dR -ei -ew -eB -dR -eX +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6511,13 +6249,13 @@ aa aa aa aa -dH -dT -dS -dS -dS -eM -dH +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6613,13 +6351,13 @@ aa aa aa aa -dH -dU -dS -dS -dS -eN -dH +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6715,13 +6453,13 @@ aa aa aa aa -dH -dV -dS -dS -dS -eM -dH +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6817,20 +6555,20 @@ aa aa aa aa -dH -dS -dS -dS -dS -dS -dH aa aa -aD -aD -aD -fY -gl +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -6919,20 +6657,20 @@ aa aa aa aa -dI -dW -ej -ex -Jd -eO -eP aa aa -aD -aD -aD -fZ -gl +aa +aa +aa +aa +aa +aa +aa +aa +aa +PE +aa +aa aa aa aa @@ -7009,9 +6747,9 @@ aa aa aa aa -aD -aD -aE +aa +aa +ac aA aA aa @@ -7022,18 +6760,18 @@ aa aa aa aa -dI -ek -ek -ek -eP +aa +aa +aa +aa +aa aa aa aa aA aA -br -ga +cb +aA aA aa aa @@ -7111,9 +6849,9 @@ aq av aa aa -aE -aD -aD +ac +aa +aa aG aA aa @@ -7135,7 +6873,7 @@ aa aA di bq -fZ +aG aA aa aa @@ -7213,7 +6951,7 @@ aa aa aq aa -aE +ac aX bq aG @@ -7238,9 +6976,9 @@ bR aX bq fZ -bR -aa -aa +Xs +ed +OK aa aa aa @@ -7341,8 +7079,8 @@ fH bq gb aA -aa -aa +aG +OK aa aa aa @@ -7419,7 +7157,7 @@ ab aA aA aZ -br +cb aA aA aA @@ -7444,7 +7182,7 @@ fQ ga aA aA -aa +OK aa aa aa @@ -7521,13 +7259,13 @@ aa aA aF ba -bs +bG bK aG aG cl cC -cN +aH cO aG ds @@ -7551,9 +7289,9 @@ aa aa aa aa -aa -aa -aa +eg +eg +eg aa aa aa @@ -7623,7 +7361,7 @@ aa aA aG bb -bt +bW bL aG aG @@ -7651,13 +7389,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dF +eh +eh +eh +dF +dF aa aa aa @@ -7740,7 +7478,7 @@ dY el aG aG -eQ +aG eZ aG fw @@ -7748,18 +7486,18 @@ aG aG bq ge -eQ +aG aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dE +dS +dS +ev +dS +eK +dF aa aa aa @@ -7855,13 +7593,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dS +dS +dS +dS +eL +dF aa aa aa @@ -7957,13 +7695,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dF +dF +ew +dF +dF +dF aa aa aa @@ -8059,13 +7797,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dT +dS +dS +dS +eM +dF aa aa aa @@ -8161,13 +7899,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dU +dS +dS +dS +eN +dF aa aa aa @@ -8263,13 +8001,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dV +dS +dS +dS +eM +dF aa aa aa @@ -8352,7 +8090,7 @@ dv em ez eD -eS +ed bq aG aG @@ -8365,13 +8103,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dS +dS +dS +dS +dS +dF aa aa aa @@ -8467,13 +8205,13 @@ aA aa aa aa -aa -aa -aa -aa -aa -aa -aa +dF +dF +ej +ex +Jd +dF +dF aa aa aa @@ -8557,7 +8295,7 @@ eo eo eD ed -eQ +aG bK aG bT @@ -8570,11 +8308,11 @@ aa aa aa aa -aa -aa -aa -aa -aa +dF +ek +ek +ek +dF aa aa aa @@ -8646,7 +8384,7 @@ bg bB bN bU -bU +nL cr aG cS @@ -8750,7 +8488,7 @@ aK aG cf cs -cI +bW cT cY dn @@ -8760,7 +8498,7 @@ ed ep aG eD -eS +ed aG bK dm @@ -8955,10 +8693,10 @@ bi cg ct cJ -cU +cJ da do -cU +cJ dN cJ dN @@ -9070,7 +8808,7 @@ ch fd bj bj -bt +bW fN fS gh @@ -9367,8 +9105,8 @@ cK dc cK dy -cL -cL +dP +dP dy cK eG @@ -9470,7 +9208,7 @@ dd cK dz dA -cL +dP er eA eH @@ -9480,7 +9218,7 @@ fs fr fh fp -fV +fr fp fp fl @@ -9562,11 +9300,11 @@ aC aU bl bn -bG +bH bn ck cz -cL +dP cV de cK @@ -9663,9 +9401,9 @@ aa aC aV bm -bG +bH bQ -bG +bH ck cA cK @@ -9767,7 +9505,7 @@ aW bn bH bQ -cb +bH ck cB cK @@ -9873,7 +9611,7 @@ aC ck ck cM -cW +cM ck ck cM diff --git a/maps/away/magshield/magshield.dm b/maps/away/magshield/magshield.dm index b478a974f4d2..dc0670443461 100644 --- a/maps/away/magshield/magshield.dm +++ b/maps/away/magshield/magshield.dm @@ -2,10 +2,8 @@ /obj/effect/overmap/visitable/sector/magshield name = "orbital station" - desc = "Sensors detect an orbital station above the exoplanet. Sporadic magentic impulses are registred inside it. Planet landing is impossible due to lower orbits being cluttered with chaotically moving metal chunks." + desc = "Sensors detect an orbital station above the exoplanet. Sporadic magentic impulses are registered inside it. Planet landing is impossible due to lower orbits being cluttered with chaotically moving metal chunks." icon_state = "object" - known = 0 - initial_generic_waypoints = list( "nav_magshield_1", "nav_magshield_2", @@ -16,7 +14,6 @@ /datum/map_template/ruin/away_site/magshield name = "Magshield" - id = "awaysite_magshield" description = "It's an orbital shield station." suffixes = list("magshield/magshield.dmm") cost = 1 @@ -42,15 +39,20 @@ name = "Orbital Station Navpoint #5" landmark_tag = "nav_magshield_antag" +/obj/effect/shuttle_landmark/nav_magshield/dock1 + name = "Orbital Station Docking Port #1" + landmark_tag = "nav_magshield_dock_1" + flags = SLANDMARK_FLAG_REORIENT | SLANDMARK_FLAG_AUTOSET + /obj/structure/magshield/maggen name = "magnetic field generator" desc = "A large three-handed generator with rotating top. It is used to create high-power magnetic fields in hard vacuum." icon = 'magshield_sprites.dmi' icon_state = "maggen" - anchored = 1 - density = 1 - light_outer_range = 3 - light_max_bright = 1 + anchored = TRUE + density = TRUE + light_range = 3 + light_power = 1 light_color = "#ffea61" var/heavy_range = 10 var/lighter_range = 20 @@ -68,70 +70,76 @@ /obj/structure/magshield/maggen/Process() var/eye_safety = 0 chance = rand(1,300)//I wanted to use Poisson distribution with Lambda for 5 minutes but made it simpler - if (chance == 1) + var/turf/T = get_turf(src) + var/area/A = get_area(src) + if (A && T && chance == 1) empulse(src, heavy_range, lighter_range, 0) - var/turf/T = get_turf(src) - var/area/A = get_area(src) - log_game("EMP with size ([heavy_range], [lighter_range]) in area [A] ([T.x], [T.y], [T.z])") - visible_message("\the [src] suddenly activates.", "Few lightnings jump between [src]'s rotating hands. You feel everything metal being pulled towards \the [src].") - for(var/mob/living/carbon/M in hear(10, get_turf(src))) + log_game("EMP with size ([heavy_range], [lighter_range]) in area [A.proper_name] ([T.x], [T.y], [T.z])") + visible_message( + SPAN_DANGER("\The [src] suddenly activates!"), + SPAN_DANGER("Electricity arcs between \the [src]'s rotating spokes as a powerful magnetic field tugs on every metallic object nearby.") + ) + for(var/mob/living/M in hear(10, T)) eye_safety = M.eyecheck() if(eye_safety < FLASH_PROTECTION_MODERATE) M.flash_eyes() - M.Stun(2) + SET_STATUS_MAX(M, STAT_STUN, 2) /obj/structure/magshield/maggen/attack_hand(mob/user) - ..() - to_chat(user, " You don't see how you could turn off \the [src]. You can try to stick something in rotating hands.") + SHOULD_CALL_PARENT(FALSE) + to_chat(user, SPAN_NOTICE("You don't see how you could turn off \the [src]. You could possibly jam something into the rotating spokes.")) + return TRUE -/obj/structure/magshield/maggen/attackby(obj/item/W, mob/user) +/obj/structure/magshield/maggen/attackby(obj/item/used_item, mob/user) if (being_stopped) - to_chat(user, " Somebody is already interacting with \the [src].") - return - if(istype(W, /obj/item/stack/material/rods)) - var/obj/item/stack/material/rods/R = W - to_chat(user, " You start to stick [R.singular_name] into rotating hands to make them stuck.") + to_chat(user, SPAN_WARNING("Somebody is already interacting with \the [src].")) + return TRUE + if(istype(used_item, /obj/item/stack/material/rods)) + var/obj/item/stack/material/rods/R = used_item + to_chat(user, SPAN_NOTICE("You start to jam \a [R.singular_name] into the rotating spokes.")) being_stopped = 1 if (!do_after(user, 100, src)) - to_chat(user, " You pull back [R.singular_name].") + to_chat(user, SPAN_NOTICE("You pull \the [R.singular_name] away.")) being_stopped = 0 - return + return TRUE R.use(1) - visible_message("\The [src] stops rotating and releases cloud of sparks. Better get to safe distance!") - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(10, 0, src) - s.start() + visible_message(SPAN_DANGER("\The [src] stops rotating and releases a cloud of sparks. Better get to a safe distance!")) + spark_at(src, amount=10) sleep(50) - visible_message("\The [src] explodes!") + visible_message(SPAN_DANGER("\The [src] explodes!")) var/turf/T = get_turf(src) - explosion(T, 2, 3, 4, 10, 1) empulse(src, heavy_range*2, lighter_range*2, 1) - qdel(src) - if(istype(W, /obj/item/mop)) - to_chat(user, " You stick [W] into rotating hands. It breaks to smallest pieces.") - qdel(W) + explosion(T, 2, 3, 4, 10, 1) + if(!QDELETED(src)) + qdel(src) + if(istype(used_item, /obj/item/mop)) + to_chat(user, SPAN_NOTICE("You stick \the [used_item] into the rotating spokes, and it immediately breaks into tiny pieces.")) + qdel(used_item) + return TRUE + return ..() /obj/structure/magshield/rad_sensor name = "radiation sensor" desc = "Very sensitive vacuum radiation sensor. On top of the metal stand two modified Wilson Cloud Chambers filled with deuterium and tritium water." icon = 'magshield_sprites.dmi' icon_state = "rad_sensor" - anchored = 1 + anchored = TRUE /obj/structure/magshield/nav_light name = "navigation light" desc = "Large and bright light regularly emitting green flashes." icon = 'magshield_sprites.dmi' icon_state = "nav_light_green" - anchored = 1 - density = 1 - light_outer_range = 10 - light_max_bright = 1 + anchored = TRUE + density = TRUE + light_range = 10 + light_power = 1 light_color = "#00ee00" /obj/structure/magshield/nav_light/Initialize() . = ..()//try make flashing through the process - set_light(light_max_bright, light_outer_range / 6, light_outer_range, 2, light_color) + set_light(light_range, light_power, light_color) + /obj/structure/magshield/nav_light/red desc = "Large and bright light regularly emitting red flashes." @@ -139,40 +147,24 @@ icon_state = "nav_light_red" -/obj/item/book/manual/magshield_manual +/obj/item/book/fluff/magshield_manual name = "SOP for Planetary Shield Orbital Station" icon = 'magshield_sprites.dmi' icon_state = "mg_guide" author = "Terraforms Industrial" title = "Standard operating procedures for Planetary Shield Orbital Station" - - dat = {" - - - - - -

    Introduction

    - Terraforms Industrial is happy to see you as our customer! Please read this guide before using and operating with your custom PSOS - Planetary Shield Orbital Statiion. -

    Best uses for PSOS

    - PSOS is intended for protecting exoplanets from high energy space radiation rays and particles. Best used for planets lacking active geomagnetic field so PSOS would compensate its absence.
    -

    Applied technologies

    - Terraforms Industrial is delivering you your new PSOS with set of four (4) high-strength magnetic field generators. Those devices use rotating supeconducter hands to create magnetic field with strength up to 5 Tesla effectively deflecting up to 99% of space radiation spectrum.
    -
    - Special modified vacuum radiation sensors will help you evaluate radiation level and adjust power input of PSOS magnetic generators for best efficiency and power saving. -


    - rest of the book pages are gone - - - "} + fluff_text = {" +

    Introduction

    + Terraforms Industrial is happy to see you as our customer! Please read this guide before using and operating with your custom PSOS - Planetary Shield Orbital Statiion. +

    Best uses for PSOS

    + PSOS is intended for protecting exoplanets from high energy space radiation rays and particles. Best used for planets lacking active geomagnetic field so PSOS would compensate its absence.
    +

    Applied technologies

    + Terraforms Industrial is delivering you your new PSOS with set of four (4) high-strength magnetic field generators. Those devices use rotating supeconducter hands to create magnetic field with strength up to 5 Tesla effectively deflecting up to 99% of space radiation spectrum.
    +
    + Special modified vacuum radiation sensors will help you evaluate radiation level and adjust power input of PSOS magnetic generators for best efficiency and power saving. +


    + The rest of the pages have been torn out... + "} /obj/item/paper/magshield/tornpage name = "torn book page" @@ -180,4 +172,4 @@ /obj/item/paper/magshield/log name = "printed page" - info = "\[07:31\] Attention: solar flare detected! Automatic countermeasures activated.
    \[07:33\] Warning: ERROR: NULL input at FARADAY_CAGE#12.TFI - line 2067: No command found. System will be rebooted.
    \[07:39\] Warning: radiaton countermeasures inactive. Please initiate emergency protocol.
    \[07:40\] Warning: radiaton countermeasures inactive. Please initiate emergency protocol.
    \[07:41\] Warning: radiaton countermeasures inactive. Please initiate emergency protocol.
    \[07:45\] Attention! Multiple systems failure. Please initiate emergency protocol
    \[07:52\] Warning: LIDAR-ASTRA system detected multiple meteors approaching. Estimate impact time: 12.478 seconds.
    \[07:52\] Warning! Miltiple hull breaches det~!!@#" + info = "\[07:31\] Attention: solar flare detected! Automatic countermeasures activated.
    \[07:33\] Warning: ERROR: NULL input at FARADAY_CAGE#12.TFI - line 2067: No command found. System will be rebooted.
    \[07:39\] Warning: radiation countermeasures inactive. Please initiate emergency protocol.
    \[07:40\] Warning: radiation countermeasures inactive. Please initiate emergency protocol.
    \[07:41\] Warning: radiation countermeasures inactive. Please initiate emergency protocol.
    \[07:45\] Attention! Multiple systems failure. Please initiate emergency protocol
    \[07:52\] Warning: LIDAR-ASTRA system detected multiple meteors approaching. Estimate impact time: 12.478 seconds.
    \[07:52\] Warning! Miltiple hull breaches det~!!@#" diff --git a/maps/away/magshield/magshield.dmm b/maps/away/magshield/magshield.dmm index 394527807117..b8848b94ee56 100644 --- a/maps/away/magshield/magshield.dmm +++ b/maps/away/magshield/magshield.dmm @@ -11,276 +11,230 @@ /turf/space, /area/space) "ad" = ( -/obj/item/ore, +/obj/item/stack/material/ore, /turf/space, /area/space) "ae" = ( /obj/machinery/power/tracker, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "af" = ( /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ag" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ah" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ai" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aj" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ak" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "al" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "am" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "an" = ( /obj/structure/cable/yellow, /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ao" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/space) "ap" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aq" = ( /obj/machinery/power/solar{ - id = "auxsolarstarboard"; name = "Starboard Auxiliary Solar Array" }, /obj/structure/cable/yellow, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ar" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/space) "as" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/button/access{ pixel_x = -25; pixel_y = -25 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "at" = ( /obj/machinery/light/small, /turf/space, /area/space) "au" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/smes_storage) "av" = ( /obj/machinery/door/airlock/external/bolted_open, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aw" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/engine) "ax" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume, /obj/effect/floor_decal/industrial/hatch/blue, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - pixel_x = 25 + pixel_x = 25; + dir = 8 }, /obj/machinery/airlock_sensor{ pixel_x = -25; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "ay" = ( /obj/structure/table/steel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "az" = ( /obj/structure/table/steel, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aA" = ( /obj/structure/table/steel, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aB" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aC" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/voidsuit, /obj/random/voidhelmet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aD" = ( /obj/machinery/door/airlock/external/bolted_open, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aE" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aF" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aG" = ( /obj/machinery/atmospherics/unary/tank/carbon_dioxide, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aH" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aI" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 6; - icon_state = "intact" + dir = 6 }, /turf/space, /area/space) "aJ" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 10 }, /turf/space, /area/space) "aK" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ - dir = 8; - icon_state = "intact" + dir = 8 }, /turf/space, /area/space) @@ -288,18 +242,16 @@ /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/smes_storage) "aM" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aN" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/unary/vent_pump/tank{ @@ -316,113 +268,96 @@ pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aO" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aP" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/obj/item/ore, -/turf/simulated/floor/airless, +/obj/item/stack/material/ore, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aQ" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aR" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aS" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aT" = ( /obj/structure/sign/warning/airlock{ pixel_y = 30 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "aV" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aW" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 5 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aX" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/black, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aY" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "aZ" = ( /obj/machinery/door/airlock/hatch, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "ba" = ( /obj/machinery/mass_driver{ dir = 4; id_tag = "enginecore" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bb" = ( /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bc" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, @@ -432,20 +367,18 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "be" = ( /obj/machinery/power/terminal, /obj/structure/cable/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bf" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bg" = ( /turf/space, @@ -453,60 +386,53 @@ "bh" = ( /obj/structure/closet/crate/plastic, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bj" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bk" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bl" = ( /obj/machinery/atmospherics/unary/vent_pump, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bm" = ( /obj/machinery/atmospherics/unary/outlet_injector, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bn" = ( /obj/machinery/power/smes/buildable/outpost_substation, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bo" = ( -/obj/item/ore, -/turf/simulated/floor/airless, +/obj/item/stack/material/ore, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bp" = ( /obj/structure/lattice, @@ -515,45 +441,41 @@ "bq" = ( /obj/structure/closet, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "br" = ( /obj/machinery/portable_atmospherics/canister, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bs" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bt" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bu" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, /obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bv" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bw" = ( /obj/effect/shuttle_landmark/nav_magshield/nav2, @@ -561,353 +483,301 @@ /area/space) "bx" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "by" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bz" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bA" = ( /obj/structure/closet, -/obj/item/toy/therapy_purple, +/obj/random/plush/therapy, /obj/random/hat, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bB" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bC" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bD" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bE" = ( -/obj/item/ore, +/obj/item/stack/material/ore, /turf/space, /area/magshield/smes_storage) "bF" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/magshield/smes_storage) "bG" = ( /obj/structure/closet, /obj/item/flashlight/flare/glowstick/random, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bH" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bI" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bJ" = ( /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bK" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bL" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/engine) "bM" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ - icon_state = "intact"; dir = 4 }, /turf/space, /area/space) "bN" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 4 }, /turf/space, /area/space) "bO" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/obj/item/ore, +/obj/item/stack/material/ore, /turf/space, /area/space) "bP" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bQ" = ( /obj/structure/table/steel, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bR" = ( /obj/structure/table/steel, /obj/random/drinkbottle, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bS" = ( /obj/structure/closet/crate/trashcart, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bT" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bU" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bV" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "bW" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 9 }, /turf/space, /area/space) "bX" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bY" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "bZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "ca" = ( /obj/structure/table/steel, /obj/item/geiger, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cb" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cc" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "EngineBlast"; - name = "Engine Monitoring Room Blast Doors"; - opacity = 0 + name = "Engine Monitoring Room Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/magshield/engine) "cd" = ( /obj/machinery/atmospherics/binary/circulator{ anchored = 1; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/magshield/engine) "ce" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cf" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cg" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 5; - icon_state = "intact" + dir = 5 }, /turf/space, /area/space) "ch" = ( /obj/structure/closet/crate/hydroponics/prespawned, /obj/random/gloves, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/magshield/smes_storage) "ci" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cj" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "ck" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "EngineBlast"; - name = "Engine Monitoring Room Blast Doors"; - opacity = 0 + name = "Engine Monitoring Room Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/magshield/engine) "cl" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cm" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cn" = ( /obj/machinery/atmospherics/binary/pump, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "co" = ( /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/generator{ - anchored = 1; - dir = 2 +/obj/machinery/generator{ + anchored = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/magshield/engine) "cp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cq" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -916,12 +786,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cr" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -930,7 +798,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cs" = ( /obj/machinery/door/airlock, @@ -940,12 +808,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "ct" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -954,7 +820,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cu" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -964,75 +830,65 @@ /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cv" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cw" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cx" = ( /obj/machinery/atmospherics/binary/circulator{ anchored = 1; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/magshield/engine) "cy" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cz" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cA" = ( /obj/item/flashlight/flare/glowstick/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cC" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cD" = ( /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cE" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 4 }, -/obj/item/ore, +/obj/item/stack/material/ore, /turf/space, /area/space) "cF" = ( @@ -1043,13 +899,10 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/obj/item/ore, -/turf/simulated/floor/airless, +/obj/item/stack/material/ore, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cG" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -1059,33 +912,31 @@ pixel_y = 1; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cH" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cI" = ( /obj/structure/closet, /obj/random/gloves, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cJ" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cK" = ( /obj/structure/table/steel, @@ -1094,21 +945,21 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cL" = ( /obj/structure/closet, /obj/item/clothing/suit/radiation, /obj/item/flashlight, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cM" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cN" = ( /obj/machinery/atmospherics/binary/pump, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cO" = ( /obj/structure/girder/displaced, @@ -1117,23 +968,17 @@ "cP" = ( /obj/structure/table/steel, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cQ" = ( /obj/structure/table/steel, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/random/tool, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1142,14 +987,11 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cR" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1158,19 +1000,14 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cS" = ( /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1178,14 +1015,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cT" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1193,7 +1027,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cU" = ( /obj/structure/cable{ @@ -1202,12 +1036,10 @@ /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1217,12 +1049,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/smes_storage) "cW" = ( /obj/machinery/door/airlock/hatch, @@ -1233,12 +1062,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1248,12 +1074,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1263,13 +1086,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "cZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1279,61 +1099,50 @@ dir = 9 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "da" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -24 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "db" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "dc" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "dd" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/engine) "de" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/north) "df" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/airlock, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dg" = ( /turf/space, @@ -1341,107 +1150,101 @@ "dh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/random/obstruction, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "di" = ( -/obj/item/ore, -/turf/simulated/floor/airless, +/obj/item/stack/material/ore, +/turf/floor/plating/airless, /area/magshield/north) "dj" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dk" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dl" = ( /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dm" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dn" = ( -/obj/item/storage/wallet/random, -/turf/simulated/floor/airless, +/obj/item/wallet/random, +/turf/floor/plating/airless, /area/magshield/north) "do" = ( /obj/structure/largecrate, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dp" = ( /obj/random/shoes, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dq" = ( /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dr" = ( /obj/structure/iv_drip, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ds" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dt" = ( -/turf/simulated/wall, +/turf/wall, /area/magshield/north) "du" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dv" = ( /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dw" = ( /obj/random/tank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dx" = ( /obj/structure/table/steel, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dy" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dz" = ( /obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dA" = ( /obj/structure/closet, /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dB" = ( /obj/structure/closet, /obj/random/suit, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dC" = ( /obj/structure/closet, @@ -1449,200 +1252,186 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dD" = ( /obj/structure/closet, /obj/structure/plushie/ian, /obj/random/drinkbottle, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dE" = ( /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dF" = ( -/obj/item/stack/material/rods, -/turf/simulated/floor/airless, +/obj/item/stack/material/rods/mapped/steel, +/turf/floor/plating/airless, /area/magshield/north) "dG" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dH" = ( /obj/structure/lattice, /turf/space, /area/magshield/north) "dI" = ( -/obj/item/clothing/under/color/lightpurple, -/turf/simulated/floor/airless, +/obj/item/clothing/jumpsuit/lightpurple, +/turf/floor/plating/airless, /area/magshield/north) "dJ" = ( /obj/random/firstaid, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dK" = ( /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dL" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, /obj/structure/largecrate, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dM" = ( /obj/random/obstruction, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dN" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dO" = ( /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dP" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dQ" = ( /obj/machinery/field_generator, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dR" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dS" = ( /obj/effect/floor_decal/industrial/warning, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dT" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/largecrate, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dU" = ( /obj/effect/floor_decal/industrial/warning, /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dV" = ( /obj/effect/floor_decal/industrial/warning, -/obj/item/flame/lighter/random, -/turf/simulated/floor/airless, +/obj/item/flame/fuelled/lighter/random, +/turf/floor/plating/airless, /area/magshield/north) "dW" = ( /obj/effect/floor_decal/industrial/warning, /obj/random/tank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dX" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, /obj/random/toolbox, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dY" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "dZ" = ( /obj/structure/table/steel, /obj/random/powercell, /obj/machinery/cell_charger, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ea" = ( -/obj/machinery/power/port_gen/pacman/mrs, -/turf/simulated/floor/airless, +/obj/machinery/port_gen/pacman/mrs, +/turf/floor/plating/airless, /area/magshield/north) "eb" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ec" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ed" = ( /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ee" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/voidsuit, /obj/random/voidhelmet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ef" = ( /obj/structure/grille, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/space) "eg" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eh" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ei" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/magshield/north) "ej" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ek" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1652,12 +1441,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "el" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, @@ -1665,12 +1451,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "em" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1681,28 +1464,21 @@ }, /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "en" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/magshield/north) "eo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1712,12 +1488,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ep" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1725,12 +1498,9 @@ }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1740,17 +1510,12 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "er" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1762,13 +1527,13 @@ /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "es" = ( /obj/structure/sign/warning/airlock{ pixel_x = 30 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "et" = ( /obj/machinery/light/small{ @@ -1778,19 +1543,20 @@ /area/space) "eu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ev" = ( /obj/structure/sign/warning/airlock{ pixel_y = -30 }, -/turf/simulated/wall, +/turf/wall, /area/magshield/north) "ew" = ( /obj/structure/sign/warning/docking_area{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ex" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1802,7 +1568,7 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ey" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1814,7 +1580,7 @@ /obj/structure/cable{ icon_state = "4-9" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "ez" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1823,12 +1589,9 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/floodlight, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eA" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, @@ -1837,12 +1600,9 @@ }, /obj/machinery/floodlight, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1852,13 +1612,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/light/small, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eC" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1868,19 +1625,13 @@ dir = 10 }, /obj/structure/cable{ - icon_state = "1-8"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "1-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eD" = ( /obj/machinery/door/airlock/external/bolted, @@ -1888,42 +1639,32 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eE" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - dir = 8; + dir = 8 }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - pixel_x = 0; pixel_y = 25 }, /obj/machinery/airlock_sensor{ - pixel_x = 0; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eF" = ( /obj/machinery/door/airlock/external/bolted, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eG" = ( /obj/machinery/button/access{ @@ -1931,29 +1672,16 @@ pixel_y = 25 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) -"eH" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/airless, -/area/space) "eI" = ( /obj/structure/magshield/maggen, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eJ" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -1961,123 +1689,114 @@ id_tag = "merchant_station_vent" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/item/newspaper, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eO" = ( /obj/item/frame/light/small, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eP" = ( /obj/structure/table, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eQ" = ( /obj/structure/table/steel, -/obj/item/storage/toolbox/mechanical, -/turf/simulated/floor/airless, +/obj/item/toolbox/mechanical, +/turf/floor/plating/airless, /area/magshield/north) "eR" = ( /obj/structure/table/steel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eS" = ( /obj/structure/table/steel, -/obj/item/storage/box/lights, -/turf/simulated/floor/airless, +/obj/item/box/lights/mixed, +/turf/floor/plating/airless, /area/magshield/north) "eT" = ( /obj/machinery/door/airlock/external/bolted_open, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/button/access{ - pixel_x = -25; - pixel_y = 25 + pixel_x = -20; + pixel_y = 32; + id_tag = "magshield_dock"; + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eU" = ( /obj/machinery/light/small, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eV" = ( /obj/structure/closet, /obj/random/material, /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eW" = ( /obj/structure/closet, /obj/random/material, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eX" = ( /obj/structure/closet, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eY" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "eZ" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "fa" = ( /obj/structure/janitorialcart, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "fb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "fc" = ( /obj/machinery/light/small{ @@ -2088,190 +1807,172 @@ "fd" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 1; - id_tag = "centcom_shuttle_dock_pump" + id_tag = "magshield_dock_pump" }, /obj/effect/floor_decal/industrial/hatch/blue, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - pixel_x = 25 + pixel_x = 25; + dir = 8; + id_tag = "magshield_dock" }, /obj/machinery/airlock_sensor{ pixel_x = -25; - pixel_y = 0 + dir = 4; + id_tag = "magshield_dock_sensor" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "fe" = ( -/turf/simulated/wall, +/turf/wall, /area/magshield/east) "ff" = ( /obj/machinery/atmospherics/unary/tank, /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fg" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 10 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fh" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fi" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fk" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/east) "fl" = ( /obj/structure/grille, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/north) "fm" = ( /obj/item/mop, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/north) "fn" = ( /obj/machinery/door/airlock/external/bolted_open, -/turf/simulated/floor/airless, +/obj/machinery/button/access{ + pixel_x = -25; + pixel_y = -16; + id_tag = "magshield_dock" + }, +/turf/floor/plating/airless, /area/magshield/north) "fo" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/black, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fp" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fr" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fs" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "ft" = ( /obj/effect/shuttle_landmark/nav_magshield/nav5, /turf/space, /area/space) "fu" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/west) "fv" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fw" = ( -/obj/machinery/button/access{ - pixel_x = -25; - pixel_y = 25 +/obj/effect/shuttle_landmark/nav_magshield/dock1{ + dir = 1 }, -/turf/simulated/floor/airless, -/area/magshield/north) +/turf/space, +/area/space) "fx" = ( /obj/machinery/atmospherics/unary/tank, /obj/machinery/atmospherics/portables_connector{ dir = 4 }, /obj/item/frame/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fy" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black{ dir = 4 }, -/turf/simulated/floor/airless, -/area/magshield/east) -"fz" = ( -/obj/item/frame/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fA" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fB" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "fC" = ( /obj/item/frame/light, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "fD" = ( /obj/random/junk, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "fE" = ( /obj/structure/cable{ icon_state = "1-10" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, -/area/magshield/west) -"fF" = ( -/obj/item/frame/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled/dark, /area/magshield/west) "fG" = ( /obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) -"fH" = ( -/obj/effect/overmap/visitable/sector/magshield, -/turf/simulated/floor/airless, -/area/magshield/north) "fI" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fJ" = ( /obj/structure/grille, @@ -2281,54 +1982,45 @@ /obj/structure/cable{ icon_state = "4-10" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "fL" = ( /obj/structure/table/steel, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fM" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fN" = ( /obj/structure/cable{ icon_state = "5-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fO" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "fP" = ( /obj/item/newspaper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fQ" = ( /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fR" = ( /obj/machinery/atmospherics/omni/mixer{ @@ -2338,22 +2030,18 @@ tag_south = 1; tag_south_con = 0.79 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fT" = ( /obj/machinery/atmospherics/omni/filter{ @@ -2361,28 +2049,19 @@ tag_south = 1; tag_west = 3 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fU" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/airless, -/area/magshield/east) -"fV" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; - dir = 1 - }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fW" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/east) "fX" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -2391,129 +2070,115 @@ id_tag = "d_n2_in"; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "fY" = ( /obj/structure/cable{ icon_state = "2-5" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "fZ" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "ga" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gb" = ( /obj/structure/table/steel, /obj/item/ashtray/plastic, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gc" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gd" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "ge" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gf" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gg" = ( /obj/structure/table/steel, /obj/random/toy, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gh" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gi" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gj" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gk" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/airless, -/area/magshield/east) -"gl" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; - dir = 9 - }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gm" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/item/frame/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gn" = ( /obj/structure/table/steel, -/obj/item/chems/food/drinks/coffee, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/coffee, +/turf/floor/tiled, /area/magshield/west) "go" = ( /obj/structure/table/steel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gp" = ( /obj/structure/magshield/nav_light/red{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gq" = ( /obj/structure/magshield/nav_light{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "gr" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gs" = ( /obj/structure/closet, @@ -2521,59 +2186,59 @@ /obj/random/cash, /obj/random/clothing, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gt" = ( /obj/structure/closet, -/obj/item/storage/wallet/leather, +/obj/item/wallet/leather, /obj/random/clothing, /obj/random/smokes, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gu" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gv" = ( -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gw" = ( /obj/structure/bed, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gx" = ( /obj/item/frame/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gy" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gB" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gC" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2581,70 +2246,65 @@ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gE" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gF" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gH" = ( -/obj/structure/table/woodentable{ +/obj/structure/table/laminate{ dir = 10 }, -/obj/item/storage/box/checkers, +/obj/item/box/checkers, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gI" = ( -/obj/structure/table/woodentable{ +/obj/structure/table/laminate{ dir = 10 }, -/obj/item/storage/belt/champion, -/turf/simulated/floor/carpet/blue, +/obj/item/belt/champion, +/turf/floor/carpet/blue, /area/magshield/west) "gJ" = ( -/obj/structure/table/woodentable{ +/obj/structure/table/laminate{ dir = 10 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "gK" = ( -/obj/structure/table/woodentable{ +/obj/structure/table/laminate{ dir = 10 }, -/obj/item/storage/bible/booze, -/turf/simulated/floor/carpet/blue, +/obj/item/bible/booze, +/turf/floor/carpet/blue, /area/magshield/west) "gL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2654,12 +2314,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2671,89 +2328,83 @@ /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gO" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gP" = ( -/turf/simulated/wall, +/turf/wall, /area/magshield/west) "gQ" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "gR" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "gS" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/random/junk, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "gT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "gU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gV" = ( /obj/structure/bookcase/manuals/xenoarchaeology, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gW" = ( /obj/structure/bookcase/manuals/engineering, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gX" = ( /obj/structure/bookcase/manuals/medical, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gY" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/action_figure, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "gZ" = ( /obj/structure/table/steel, -/obj/item/chems/food/drinks/coffee, +/obj/item/chems/drinks/coffee, /obj/random/smokes, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "ha" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "hb" = ( /obj/structure/table/steel, /obj/random/glasses, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hc" = ( /obj/effect/shuttle_landmark/nav_magshield/nav1, @@ -2761,13 +2412,13 @@ /area/space) "hd" = ( /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "he" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "hf" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2775,30 +2426,27 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hg" = ( /obj/machinery/door/airlock/external/bolted_open, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/magshield/east) "hh" = ( /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - pixel_x = 0; pixel_y = 25 }, /obj/machinery/airlock_sensor{ - pixel_x = 0; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hi" = ( /obj/structure/lattice, @@ -2814,84 +2462,80 @@ /area/magshield/east) "hk" = ( /obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "hl" = ( /obj/structure/magshield/rad_sensor, /obj/structure/cable/cyan{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "hm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hn" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/sword/replica, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "ho" = ( /obj/item/frame/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "hp" = ( -/obj/structure/bed/chair/comfy/captain, -/turf/simulated/floor/tiled/white, +/obj/structure/chair/comfy/captain, +/turf/floor/tiled/white, /area/magshield/west) "hq" = ( /obj/item/paper/magshield/log, /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "hr" = ( /obj/random/junk, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hs" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "ht" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hu" = ( /turf/space, /area/magshield/east) "hv" = ( -/obj/item/ore/slag, -/turf/simulated/floor/airless, +/obj/item/stack/material/ore/slag, +/turf/floor/plating/airless, /area/space) "hw" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/plushie/large, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hx" = ( /obj/structure/table/steel, /obj/item/ashtray, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/west) "hy" = ( /obj/structure/table/steel, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2899,13 +2543,13 @@ /obj/structure/cable{ icon_state = "1-10" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hA" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/voidsuit, /obj/random/voidhelmet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hB" = ( /obj/structure/safe, @@ -2918,39 +2562,36 @@ /obj/random/cash, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hC" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/toy/shipmodel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hD" = ( -/obj/item/book/manual/magshield_manual, -/turf/simulated/floor/tiled/white, +/obj/item/book/fluff/magshield_manual, +/turf/floor/tiled/white, /area/magshield/west) "hE" = ( /obj/structure/lattice, /turf/space, /area/magshield/west) "hF" = ( -/obj/item/ore, -/turf/simulated/floor/tiled, +/obj/item/stack/material/ore, +/turf/floor/tiled, /area/magshield/west) "hG" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable{ - icon_state = "0-2"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hH" = ( /obj/structure/cable{ @@ -2959,74 +2600,72 @@ /obj/structure/cable{ icon_state = "2-5" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hJ" = ( -/obj/structure/filingcabinet/chestdrawer, +/obj/structure/filing_cabinet/chestdrawer, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "hK" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/book/manual/supermatter_engine, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "hL" = ( -/obj/item/ore, -/turf/simulated/floor/tiled/dark, +/obj/item/stack/material/ore, +/turf/floor/tiled/dark, /area/magshield/west) "hM" = ( /turf/space, /area/magshield/west) "hN" = ( /obj/item/chems/glass/bucket, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "hO" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hP" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hQ" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/item/frame/light, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "hR" = ( -/obj/structure/filingcabinet/chestdrawer, +/obj/structure/filing_cabinet/chestdrawer, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "hS" = ( -/obj/structure/bed/chair/comfy/red, +/obj/structure/chair/comfy/red, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "hT" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/book/manual/evaguide, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -3034,7 +2673,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "hU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3043,7 +2682,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hV" = ( /obj/machinery/door/firedoor, @@ -3054,7 +2693,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "hW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3063,7 +2702,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "hX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3073,7 +2712,7 @@ dir = 4 }, /obj/item/paper/magshield/tornpage, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "hY" = ( /obj/structure/table/steel, @@ -3084,68 +2723,70 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, /area/magshield/west) "hZ" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/accessory, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "ia" = ( -/obj/structure/table/woodentable, -/obj/item/flame/lighter/zippo/random, +/obj/structure/table/laminate, +/obj/item/flame/fuelled/lighter/zippo/random, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "ib" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/ashtray, /obj/random/smokes, /obj/machinery/light, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/magshield/west) "ic" = ( -/obj/item/stack/material/rods, -/turf/simulated/floor/tiled/dark, +/obj/item/stack/material/rods/mapped/steel, +/turf/floor/tiled/dark, /area/magshield/west) "id" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/magshield/west) "ie" = ( /obj/machinery/seed_storage, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled, /area/magshield/east) "if" = ( /obj/structure/reagent_dispensers/watertank, /obj/item/chems/glass/bucket, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "ig" = ( /obj/structure/cable{ icon_state = "1-10" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "ih" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "ii" = ( -/obj/item/minihoe, +/obj/item/tool/hoe/mini, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "ij" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3154,7 +2795,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/east) "ik" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3163,7 +2804,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "il" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -3175,7 +2816,7 @@ /obj/structure/cable{ icon_state = "2-5" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "im" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3184,7 +2825,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) "in" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3193,17 +2834,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) -"io" = ( -/obj/item/frame/light, -/turf/simulated/floor/tiled, -/area/magshield/west) "ip" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/magshield/south) "iq" = ( -/turf/simulated/wall, +/turf/wall, /area/magshield/south) "ir" = ( /obj/machinery/door/firedoor, @@ -3211,125 +2848,115 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "is" = ( -/obj/item/ore/slag, +/obj/item/stack/material/ore/slag, /turf/space, /area/space) "it" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/magshield/west) "iu" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iv" = ( /obj/structure/curtain/open/shower, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iw" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "ix" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "iy" = ( /obj/structure/table, /obj/random/firstaid, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iz" = ( /obj/item/frame/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iA" = ( /obj/structure/bed, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iB" = ( /obj/random/material, /turf/space, /area/space) "iC" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/west) "iD" = ( /obj/structure/table/steel, -/obj/item/chems/food/drinks/cans/space_up, -/obj/item/chems/food/drinks/cans/space_up{ +/obj/item/chems/drinks/cans/space_up, +/obj/item/chems/drinks/cans/space_up{ pixel_x = 5; pixel_y = 4 }, -/obj/item/chems/food/drinks/cans/space_up{ +/obj/item/chems/drinks/cans/space_up{ pixel_x = -8; pixel_y = 5 }, -/obj/item/chems/food/drinks/cans/space_up{ +/obj/item/chems/drinks/cans/space_up{ pixel_x = -2; pixel_y = -4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "iE" = ( /obj/structure/iv_drip, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iF" = ( /obj/random/medical/lite, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iG" = ( /obj/item/frame/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "iH" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iI" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, /obj/random/trash, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iJ" = ( /obj/item/bedsheet, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iK" = ( /obj/machinery/door/firedoor, @@ -3337,29 +2964,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "iL" = ( /obj/structure/hygiene/toilet, -/turf/simulated/floor/tiled/white/usedup, +/turf/floor/tiled/white/usedup, /area/magshield/south) "iM" = ( /obj/structure/hygiene/urinal{ pixel_y = 25 }, /obj/random/trash, -/turf/simulated/floor/tiled/white/usedup, +/turf/floor/tiled/white/usedup, /area/magshield/south) "iN" = ( /obj/structure/hygiene/sink{ pixel_y = 25 }, -/turf/simulated/floor/tiled/white/usedup, +/turf/floor/tiled/white/usedup, /area/magshield/south) "iO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -3367,35 +2991,32 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "iP" = ( /obj/machinery/vending/coffee, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "iQ" = ( /obj/machinery/vending/cola, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "iR" = ( /obj/machinery/vending/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "iS" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "iT" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iU" = ( /obj/structure/hygiene/toilet{ @@ -3404,67 +3025,45 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, -/area/magshield/south) -"iV" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/item/frame/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled/white, /area/magshield/south) "iW" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "iX" = ( -/obj/item/ore/slag, -/turf/simulated/floor/tiled/white, +/obj/item/stack/material/ore/slag, +/turf/floor/tiled/white, /area/magshield/south) "iY" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/white/usedup, +/turf/floor/tiled/white/usedup, /area/magshield/south) "iZ" = ( /obj/machinery/light, -/turf/simulated/floor/tiled/white/usedup, +/turf/floor/tiled/white/usedup, /area/magshield/south) "ja" = ( /mob/living/simple_animal/hostile/carp, -/turf/simulated/floor/tiled/white/usedup, +/turf/floor/tiled/white/usedup, /area/magshield/south) "jb" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white/usedup, -/area/magshield/south) -"jc" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/turf/simulated/floor/tiled, +/turf/floor/tiled/white/usedup, /area/magshield/south) "jd" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "je" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, +/obj/structure/chair, +/turf/floor/tiled, /area/magshield/south) "jf" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jg" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3474,11 +3073,9 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3487,7 +3084,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "ji" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3496,126 +3093,126 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jk" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jl" = ( /turf/space, /area/magshield/south) "jm" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jn" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jo" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jp" = ( /obj/structure/bed, /obj/item/bedsheet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jq" = ( /obj/structure/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jr" = ( /obj/random/trash, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "js" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jt" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ju" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jv" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/trash/plate, -/obj/item/chems/food/snacks/flatbread, -/turf/simulated/floor/tiled, +/obj/item/plate, +/obj/item/food/flatbread, +/turf/floor/tiled, /area/magshield/south) "jw" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jx" = ( /obj/structure/table/marble, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jy" = ( /obj/structure/table/marble, /obj/item/knife/kitchen/cleaver, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jz" = ( /obj/structure/hygiene/sink{ pixel_y = 25 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jA" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/magshield/south) "jB" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/magshield/south) "jC" = ( /obj/machinery/washing_machine, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jD" = ( /obj/structure/lattice, @@ -3623,11 +3220,11 @@ /area/magshield/south) "jE" = ( /obj/structure/magshield/maggen, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "jF" = ( /obj/machinery/door/airlock/external/bolted, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/south) "jG" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -3635,46 +3232,41 @@ id_tag = "merchant_station_vent" }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - pixel_x = 0; pixel_y = 25 }, /obj/machinery/airlock_sensor{ - pixel_x = 0; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/south) "jH" = ( /obj/machinery/door/airlock/external/bolted, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/south) "jI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/cable{ - icon_state = "0-2"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jK" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3682,106 +3274,101 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jL" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/plushie/large, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jM" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jN" = ( /obj/structure/closet, /obj/random/glasses, /obj/random/hat, /obj/random/cash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jO" = ( /obj/structure/closet, /obj/random/clothing, /obj/random/accessory, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jP" = ( /obj/structure/closet, /obj/random/junk, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jQ" = ( /obj/structure/closet, /obj/random/clothing, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jR" = ( /obj/structure/closet, /obj/random/clothing, /obj/random/cash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jS" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/item/plate, +/turf/floor/tiled, /area/magshield/south) "jT" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/knife/table, -/turf/simulated/floor/tiled, +/obj/item/utensil/knife, +/turf/floor/tiled, /area/magshield/south) "jU" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "jV" = ( /obj/structure/table/marble, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jW" = ( /obj/item/knife/hook, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/magshield/south) "jX" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jY" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, /obj/item/soap, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "jZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -3789,145 +3376,131 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ka" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, /area/magshield/south) "kb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/south) "kc" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/south) "kd" = ( /obj/structure/bed/roller, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ke" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "kf" = ( /obj/structure/sign/warning/airlock{ pixel_x = -30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kh" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ki" = ( /obj/structure/curtain/open/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kj" = ( /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kk" = ( /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kl" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "km" = ( /obj/machinery/vending/dinnerware, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "kn" = ( /obj/structure/table/marble, /obj/machinery/microwave, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "ko" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/magshield/south) "kp" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/chems/food/snacks/hotdog, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/hotdog, +/turf/floor/tiled/freezer, /area/magshield/south) "kq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "kr" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "ks" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "kt" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/item/frame/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ku" = ( -/obj/item/ore, +/obj/item/stack/material/ore, /turf/space, /area/magshield/south) "kv" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3936,7 +3509,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3945,7 +3518,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ky" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3954,7 +3527,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kz" = ( /obj/machinery/door/firedoor, @@ -3965,7 +3538,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3975,7 +3548,7 @@ dir = 4 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kB" = ( /obj/item/flame/match, @@ -3985,7 +3558,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kC" = ( /obj/machinery/door/firedoor, @@ -3995,31 +3568,31 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kD" = ( -/obj/item/kitchen/utensil/fork/plastic, +/obj/item/utensil/fork/plastic, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kE" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kG" = ( /obj/random/trash, @@ -4029,7 +3602,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4038,63 +3611,63 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kI" = ( /obj/structure/table/marble, -/obj/item/chems/food/snacks/chips, -/turf/simulated/floor/tiled/white, +/obj/item/food/junk/chips, +/turf/floor/tiled/white, /area/magshield/south) "kJ" = ( /obj/structure/table/marble, -/obj/item/knife/table, -/turf/simulated/floor/tiled/white, +/obj/item/utensil/knife, +/turf/floor/tiled/white, /area/magshield/south) "kK" = ( -/obj/structure/kitchenspike, -/turf/simulated/floor/tiled/freezer, +/obj/structure/meat_hook, +/turf/floor/tiled/freezer, /area/magshield/south) "kL" = ( /obj/structure/closet/secure_closet/freezer/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/obj/item/chems/food/snacks/meat, -/turf/simulated/floor/tiled/freezer, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/obj/item/food/butchery/meat, +/turf/floor/tiled/freezer, /area/magshield/south) "kM" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/magshield/south) "kN" = ( /obj/structure/window/basic{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kO" = ( /obj/structure/fitness/weightlifter, /obj/structure/window/basic{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kP" = ( /obj/structure/window/basic{ dir = 1 }, /obj/item/towel/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kQ" = ( /obj/structure/window/basic{ dir = 1 }, /obj/structure/fitness/punchingbag, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kR" = ( /obj/structure/window/basic{ @@ -4103,19 +3676,19 @@ /obj/structure/window/basic{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kS" = ( /obj/machinery/computer/arcade, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kT" = ( /obj/structure/curtain/open/bed, -/obj/item/knife/table, -/turf/simulated/floor/tiled, +/obj/item/utensil/knife, +/turf/floor/tiled, /area/magshield/south) "kU" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -4124,68 +3697,68 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kV" = ( /obj/item/towel/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kW" = ( /obj/machinery/computer/arcade, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kX" = ( /obj/structure/closet, /obj/random/accessory, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kY" = ( /obj/structure/closet, /obj/random/tool, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "kZ" = ( /obj/structure/closet, /obj/random/firstaid, /obj/random/junk, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "la" = ( /obj/structure/closet, /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lb" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/hat, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lc" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/item/deck/cards, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ld" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/obj/item/kitchen/utensil/fork/plastic, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/item/utensil/fork/plastic, +/obj/item/plate, +/turf/floor/tiled, /area/magshield/south) "le" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/yellow{ + icon_state = "1-2" }, -/turf/simulated/floor/tiled, -/area/magshield/south) +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/magshield/smes_storage) "lf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 @@ -4193,68 +3766,68 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lg" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/space, /area/magshield/south) "lh" = ( /obj/structure/fitness/weightlifter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "li" = ( /obj/structure/fitness/punchingbag, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lj" = ( /obj/structure/window/basic{ dir = 4 }, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lk" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ll" = ( /obj/random/trash, /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lm" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ln" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lo" = ( /obj/machinery/vending/cigarette, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lp" = ( /obj/machinery/vending/cola, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lq" = ( /obj/machinery/vending/fitness, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lr" = ( /obj/item/frame/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "ls" = ( /obj/structure/girder/displaced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/south) "lt" = ( /obj/effect/shuttle_landmark/nav_magshield/nav4, @@ -4262,97 +3835,131 @@ /area/space) "lu" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "lv" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "lw" = ( /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar{ - id = "auxsolarsport"; name = "Port Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "lx" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ly" = ( /obj/structure/cable/yellow, /obj/machinery/power/solar{ - id = "auxsolarsport"; name = "Port Auxiliary Solar Array" }, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "lz" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "lA" = ( /obj/effect/shuttle_landmark/nav_magshield/nav3, /turf/space, /area/space) +"nQ" = ( +/obj/effect/overmap/visitable/sector/magshield, +/turf/space, +/area/space) +"qp" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/obj/abstract/landmark/allowed_leak, +/turf/space, +/area/space) "uL" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/magshield/west) "Eo" = ( /obj/machinery/atmospherics/omni/filter{ - tag_east = 0; tag_north = 2; tag_south = 1; tag_west = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/magshield/east) +"JW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, +/area/magshield/south) +"KZ" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/obj/abstract/landmark/allowed_leak, +/turf/space, +/area/space) +"Oa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/dark, +/area/magshield/west) +"TY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/magshield/north) +"Uw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, +/area/magshield/south) (1,1,1) = {" aa @@ -16965,7 +16572,7 @@ aa aa ab ap -eH +ke ap ab aa @@ -17167,7 +16774,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -17369,7 +16976,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -17571,7 +17178,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -17773,7 +17380,7 @@ aa aa ab aa -eH +ke aa aa aa @@ -17975,7 +17582,7 @@ aa aa ab aa -eH +ke aa aa aa @@ -18177,7 +17784,7 @@ aa aa ab aa -eH +ke aa aa aa @@ -18379,7 +17986,7 @@ aa de ef et -eH +ke aa aa aa @@ -18804,7 +18411,7 @@ fA hW fA hF -io +iG fA fA hF @@ -19815,13 +19422,13 @@ hM hM hM hM -it +Oa it it iK iO -jc -jc +ix +ix jK kg kw @@ -20201,7 +19808,7 @@ eL dj dj fu -fF +iG fP gb fZ @@ -20415,7 +20022,7 @@ fA ga ga ga -fF +iG ga ga ga @@ -20588,7 +20195,7 @@ bc bc bO bc -bc +qp aa ao aa @@ -20790,10 +20397,10 @@ bc bc bc bc -bc +qp aa aa -bN +KZ ab de de @@ -20991,7 +20598,7 @@ bc bc bc bc -bc +qp aa aa aa @@ -21413,7 +21020,7 @@ dg de de aa -ac +aa aa aa aa @@ -21609,13 +21216,13 @@ dl dj dH dg -ej +TY dg dj de de aa -ac +aa aa aa aa @@ -21817,7 +21424,7 @@ dj de de aa -ac +aa aa aa aa @@ -22019,7 +21626,7 @@ eP de de aa -ac +aa aa aa aa @@ -22221,7 +21828,7 @@ eP de de aa -ac +aa aa aa aa @@ -22423,7 +22030,7 @@ eQ de de aa -ac +aa aa aa aa @@ -22625,7 +22232,7 @@ eR de de aa -ac +aa aa aa aa @@ -22827,7 +22434,7 @@ eS de de aa -ac +aa aa aa aa @@ -23029,7 +22636,7 @@ eO de de aa -ac +aa aa aa aa @@ -23231,7 +22838,7 @@ eP de de aa -ac +aa aa aa aa @@ -23433,7 +23040,7 @@ dj de de aa -ac +aa aa aa aa @@ -23635,7 +23242,7 @@ dj de de aa -ac +aa aa aa aa @@ -23836,8 +23443,8 @@ ev de de de -dg -dj +aa +aa aa aa aa @@ -24018,7 +23625,7 @@ aD aU bi bg -aU +le aU aU bZ @@ -24039,7 +23646,6 @@ eT fd fn fw -fH aa aa aa @@ -24049,6 +23655,7 @@ aa aa aa aa +nQ aa aa aa @@ -24240,8 +23847,8 @@ ew de de de -dg -dj +aa +aa aa aa aa @@ -24443,7 +24050,7 @@ eU de de aa -ac +aa aa aa aa @@ -24645,7 +24252,7 @@ ee de de aa -ac +aa aa aa aa @@ -24847,7 +24454,7 @@ ee de de aa -ac +aa aa aa aa @@ -25049,7 +24656,7 @@ ee de de aa -ac +aa aa aa aa @@ -25251,7 +24858,7 @@ ee de de aa -ac +aa aa aa aa @@ -25453,7 +25060,7 @@ ee de de aa -ac +aa aa aa aa @@ -25655,7 +25262,7 @@ eU de de aa -ac +aa aa aa aa @@ -25857,7 +25464,7 @@ eV de de aa -ac +aa aa aa aa @@ -26059,7 +25666,7 @@ eW de de aa -ac +aa aa aa aa @@ -26261,7 +25868,7 @@ eX de de aa -ac +aa aa aa aa @@ -26463,7 +26070,7 @@ dA de de aa -ac +aa aa aa aa @@ -26665,7 +26272,7 @@ dt de de aa -ac +aa aa aa aa @@ -27502,7 +27109,7 @@ iq iq iq iq -le +kz iq ip ip @@ -28309,7 +27916,7 @@ iq iq iq iq -kx +JW ip jl jl @@ -28505,12 +28112,12 @@ ix ix ix ix -iV +kt jg ix jZ kt -ix +Uw ku kc jD @@ -28890,7 +28497,7 @@ fi fi fU fi -fU +fi fi fi gF @@ -29090,9 +28697,9 @@ fh fi fi fi -fV -ge -gl +fU +fi +fi fi fi fi @@ -29290,12 +28897,12 @@ eE de fi fi -fz +gx fi fU fi fi -fz +gx fi fi fi @@ -29892,7 +29499,7 @@ aa aa ab aa -eH +ke fc ab aa @@ -30094,7 +29701,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -30296,7 +29903,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -30498,7 +30105,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -30700,7 +30307,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -30902,7 +30509,7 @@ aa aa ab aa -eH +ke aa ab aa @@ -31104,7 +30711,7 @@ aa aa ab ap -eH +ke ap ab aa diff --git a/maps/away/mining/mining-asteroid.dmm b/maps/away/mining/mining-asteroid.dmm index 88802af6467c..89a0612365c1 100644 --- a/maps/away/mining/mining-asteroid.dmm +++ b/maps/away/mining/mining-asteroid.dmm @@ -6,213 +6,213 @@ /turf/unsimulated/mask, /area/mine/unexplored) "af" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "aj" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/djstation) "ak" = ( /obj/random/junk, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "al" = ( /obj/random/trash, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "am" = ( /obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "an" = ( /obj/machinery/teleport/station, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "ao" = ( /obj/machinery/teleport/hub, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "ap" = ( /obj/structure/table/glass, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aq" = ( /obj/structure/table/glass, /obj/random/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "ar" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "as" = ( /obj/random/junk, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "at" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "av" = ( /obj/structure/table/glass, /obj/random/loot, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aw" = ( /obj/random/closet, /obj/random/loot, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "ax" = ( /obj/random/junk, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "ay" = ( /obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "az" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aA" = ( /obj/structure/table/reinforced, /obj/random/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aB" = ( /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aC" = ( /obj/structure/table/reinforced, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aE" = ( /obj/structure/table/reinforced, /obj/random/loot, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aF" = ( /obj/structure/table/reinforced, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aG" = ( /obj/random/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aH" = ( /obj/structure/barricade, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aI" = ( /obj/random/closet, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aJ" = ( /obj/structure/table, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aK" = ( /obj/machinery/door/airlock/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aL" = ( -/turf/simulated/wall, +/turf/wall, /area/djstation) "aM" = ( /obj/structure/grille, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aN" = ( /obj/structure/grille/broken, /obj/random/trash, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aO" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aP" = ( /obj/structure/grille/broken, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aQ" = ( /obj/random/medical, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aR" = ( /obj/structure/bed, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aS" = ( /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aT" = ( /obj/random/loot, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aU" = ( /obj/random/closet, /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aV" = ( /obj/structure/flora/pottedplant/dead, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aW" = ( /obj/machinery/door/airlock/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aX" = ( /obj/structure/table/steel, /obj/random/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "aY" = ( /obj/random/closet, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "aZ" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, /obj/random/maintenance, /obj/random/action_figure, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "ba" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/maintenance, /obj/random/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "bb" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/junk, /obj/random/maintenance, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "bc" = ( /obj/structure/girder, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "bd" = ( /obj/structure/largecrate, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "be" = ( /obj/random/maintenance, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "bf" = ( /obj/effect/overmap/visitable/sector/cluster, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "cb" = ( /obj/effect/shuttle_landmark/cluster/nav5, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "db" = ( /obj/effect/shuttle_landmark/cluster/nav6, @@ -236,15 +236,16 @@ /area/space) "ib" = ( /obj/effect/shuttle_landmark/cluster/nav7, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "jb" = ( /obj/machinery/button/access/exterior{ id_tag = "lp_north_airlock"; name = "exterior access button"; - pixel_y = -24 + pixel_y = -24; + dir = 1 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "kb" = ( /obj/machinery/door/airlock/external{ @@ -252,7 +253,7 @@ id_tag = "lp_north_outer"; locked = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "lb" = ( /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ @@ -261,22 +262,24 @@ tag_airpump = "lp_north_pump"; tag_chamber_sensor = "lp_north_sensor"; tag_exterior_door = "lp_north_outer"; - tag_interior_door = "lp_north_inner" + tag_interior_door = "lp_north_inner"; + dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "mb" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ id_tag = "lp_north_pump" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "nb" = ( /obj/machinery/airlock_sensor{ id_tag = "lp_north_sensor"; - pixel_x = 24 + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "ob" = ( /obj/machinery/door/airlock/external{ @@ -285,7 +288,7 @@ locked = 1 }, /obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "pb" = ( /obj/machinery/door/airlock/external{ @@ -293,19 +296,19 @@ id_tag = "lp_north_inner"; locked = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "qb" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "rb" = ( /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "sb" = ( /obj/machinery/atmospherics/pipe/simple/visible{ @@ -316,34 +319,33 @@ name = "interior access button"; pixel_y = 24 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "tb" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "ub" = ( /obj/machinery/button/access/interior{ id_tag = "lp_east_airlock"; name = "interior access button"; pixel_x = 24; - pixel_y = 0; - req_access = null + req_access = null; + dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/djstation) "vb" = ( /obj/machinery/button/access/exterior{ id_tag = "lp_east_airlock"; name = "exterior access button"; pixel_x = -24; - pixel_y = 0; - req_access = null + req_access = null; + dir = 4 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "wb" = ( /obj/machinery/door/airlock/external{ @@ -351,29 +353,27 @@ id_tag = "lp_east_inner"; locked = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "xb" = ( /obj/random/trash, /obj/machinery/airlock_sensor{ id_tag = "lp_east_sensor"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "yb" = ( /obj/random/maintenance, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "lp_east_airlock"; - pixel_x = 0; pixel_y = 24; tag_airpump = "lp_east_pump"; tag_chamber_sensor = "lp_east_sensor"; tag_exterior_door = "lp_east_outer"; tag_interior_door = "lp_east_inner" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "zb" = ( /obj/machinery/door/airlock/external{ @@ -381,14 +381,13 @@ id_tag = "lp_east_outer"; locked = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "Ab" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - dir = 6; - icon_state = "intact" + dir = 6 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "Bb" = ( /obj/machinery/door/airlock/external{ @@ -397,27 +396,26 @@ locked = 1 }, /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "Cb" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "lp_east_pump" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "Db" = ( /obj/machinery/atmospherics/pipe/simple/visible, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) "Eb" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/djstation) (1,1,1) = {" diff --git a/maps/away/mining/mining-orb.dmm b/maps/away/mining/mining-orb.dmm index 46bb1d7275ca..46fc8c21fb46 100644 --- a/maps/away/mining/mining-orb.dmm +++ b/maps/away/mining/mining-orb.dmm @@ -14,59 +14,57 @@ /turf/unsimulated/mask, /area/mine/unexplored) "ae" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "af" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/unexplored) "ag" = ( -/turf/simulated/wall/natural/random/high_chance, +/turf/wall/natural/random/high_chance, /area/mine/unexplored) "ah" = ( -/turf/simulated/wall/natural/random, +/turf/wall/natural/random, /area/mine/unexplored) "ai" = ( -/turf/simulated/wall/sandstone, +/turf/wall/brick/sandstone, /area/mine/unexplored) "aj" = ( -/turf/simulated/floor/airless/stone, +/turf/floor/plating/airless/stone, /area/mine/explored) "ak" = ( -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/mine/explored) "al" = ( /obj/structure/monolith, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/mine/explored) "am" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/mine/unexplored) "an" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/mine/unexplored) "ao" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/mine/explored) "ap" = ( -/turf/simulated/wall/sandstone, +/turf/wall/brick/sandstone, /area/mine/explored) "aq" = ( /obj/effect/floor_decal/spline/fancy/wood, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "as" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 5 }, /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "au" = ( /obj/effect/shuttle_landmark/orb/nav4, @@ -74,82 +72,79 @@ /area/space) "ax" = ( /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aB" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aD" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aF" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aI" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 1 }, -/turf/simulated/floor/airless/stone, +/turf/floor/plating/airless/stone, /area/mine/explored) "aM" = ( /obj/item/stool/stone, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/mine/explored) "aN" = ( /obj/structure/door/sandstone{ desc = "It opens and closes. It's absolutely dominated by a huge engraving of some kind of bird."; name = "engraved door" }, -/turf/simulated/floor/airless/stone, +/turf/floor/plating/airless/stone, /area/mine/explored) "aP" = ( -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aQ" = ( /obj/structure/door/sandstone, -/turf/simulated/floor/airless/stone, +/turf/floor/plating/airless/stone, /area/mine/explored) "aR" = ( /obj/effect/shuttle_landmark/orb/nav3, /turf/space, /area/space) "aS" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/mine/explored) "aT" = ( /obj/effect/overmap/visitable/sector/orb, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/mine/explored) "aU" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 9 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aV" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 5 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aW" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, /obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aX" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -158,7 +153,7 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aY" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -167,7 +162,7 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "aZ" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -176,7 +171,7 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "ba" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -185,7 +180,7 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 1 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "bb" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -194,20 +189,19 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "bc" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "bd" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 6 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "be" = ( /turf/unsimulated/mask, @@ -224,48 +218,45 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "eM" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 6 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "fA" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 9 }, /obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "ma" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "pz" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 1 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "st" = ( /obj/effect/shuttle_landmark/orb/nav7, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "vc" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "wM" = ( /obj/effect/floor_decal/spline/fancy/wood{ @@ -274,33 +265,32 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "yQ" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "yR" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "Aj" = ( /obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "DJ" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 1 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "EM" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, /obj/effect/floor_decal/spline/fancy/wood/corner{ @@ -309,7 +299,7 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "Gl" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ @@ -318,30 +308,29 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 6 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "Le" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "LT" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/explored) "MX" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 8 }, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "NQ" = ( -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "Ol" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ @@ -350,20 +339,20 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/wall/sandstone, +/turf/wall/brick/sandstone, /area/mine/explored) "Rr" = ( /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mine/unexplored) "SY" = ( /obj/structure/fountain, -/mob/living/simple_animal/hostile/retaliate/parrot/space, -/turf/simulated/floor/airless/stone, +/mob/living/simple_animal/hostile/parrot/space, +/turf/floor/plating/airless/stone, /area/mine/explored) "TP" = ( /obj/structure/totem, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/mine/explored) (1,1,1) = {" diff --git a/maps/away/mining/mining-signal.dmm b/maps/away/mining/mining-signal.dmm index d645fde42eda..7badf05b3232 100644 --- a/maps/away/mining/mining-signal.dmm +++ b/maps/away/mining/mining-signal.dmm @@ -3,40 +3,40 @@ /turf/unsimulated/mask, /area/mine/unexplored) "ab" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "af" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "ag" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, /obj/random/bomb_supply, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "ah" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, /obj/random/loot, /obj/random/loot, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "ai" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "aj" = ( /obj/machinery/porta_turret/stationary, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "ak" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/cell/hyper, /obj/item/cell/hyper, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "am" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/energy, /obj/structure/window/reinforced{ dir = 8 @@ -45,7 +45,7 @@ dir = 4 }, /obj/machinery/door/window/brigdoor/southleft, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "an" = ( /obj/machinery/mech_recharger, @@ -53,35 +53,35 @@ /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "ao" = ( -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "ap" = ( /obj/structure/table, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "aq" = ( /obj/machinery/constructable_frame/machine_frame, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "ar" = ( /obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/outpost/abandoned) "as" = ( /obj/machinery/teleport/station, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/outpost/abandoned) "at" = ( /obj/machinery/teleport/hub, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/outpost/abandoned) "au" = ( /obj/structure/table, /obj/random/toolbox, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "av" = ( /turf/unsimulated/mask, @@ -90,128 +90,128 @@ /obj/structure/table/glass, /obj/item/newspaper, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "ax" = ( /obj/structure/table/glass, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "ay" = ( /obj/structure/table, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "az" = ( /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aA" = ( -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "aB" = ( /obj/machinery/papershredder, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aC" = ( /obj/structure/table/glass, /obj/effect/floor_decal/corner/paleblue/diagonal, /obj/random/loot, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aD" = ( /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "aE" = ( /obj/random/trash, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "aF" = ( /obj/random/technology_scanner, /obj/machinery/porta_turret/stationary, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "aG" = ( /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "aH" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "aI" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "aK" = ( -/obj/structure/bed/chair/office/dark{ - icon_state = "officechair_dark"; - dir = 8 +/obj/structure/chair/office/dark{ + dir = 8; + icon_state = "officechair_dark" }, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aL" = ( -/obj/structure/bed/chair/office/dark{ - icon_state = "officechair_dark"; - dir = 4 +/obj/structure/chair/office/dark{ + dir = 4; + icon_state = "officechair_dark" }, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aM" = ( /obj/structure/table/glass, /obj/item/pen, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aN" = ( /obj/machinery/door/airlock/highsecurity, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "aO" = ( /obj/effect/decal/cleanable/blood, /obj/item/shard, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "aP" = ( /obj/machinery/door/window/brigdoor/northright, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "aQ" = ( /obj/machinery/mech_recharger, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "aR" = ( /obj/machinery/mech_recharger, /obj/structure/mech_wreckage/powerloader, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "aS" = ( /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "aT" = ( /obj/random/tool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "aU" = ( /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "aV" = ( /obj/machinery/constructable_frame/computerframe, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "aW" = ( /obj/structure/table/glass, @@ -220,21 +220,21 @@ dir = 8 }, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aX" = ( /obj/machinery/fabricator/imprinter{ stat = 1 }, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aY" = ( /obj/machinery/fabricator/protolathe{ stat = 1 }, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "aZ" = ( /obj/structure/table/glass, @@ -243,74 +243,73 @@ dir = 4 }, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "ba" = ( /obj/machinery/door/window/brigdoor/northleft, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "bb" = ( /obj/machinery/door/window/brigdoor/northright, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "bc" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/holofloor/tiled/dark, +/turf/floor/holofloor/tiled/dark, /area/outpost/abandoned) "be" = ( /obj/effect/decal/cleanable/blood, /obj/random/loot, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "bf" = ( /obj/structure/table/glass, /obj/item/cell/potato, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bg" = ( /obj/item/pen, /obj/effect/floor_decal/corner/paleblue/diagonal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bh" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/rig/hazmat, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "bi" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/loot, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "bj" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "bk" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "bl" = ( /obj/machinery/light/small/emergency, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "bm" = ( /obj/machinery/door/airlock/glass/science, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bn" = ( /obj/machinery/door/airlock/vault/bolted, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "bo" = ( /obj/machinery/door/blast/shutters{ - icon_state = "shutter1"; dir = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "bp" = ( /obj/machinery/door/airlock/glass/science{ @@ -318,68 +317,67 @@ locked = 1; secured_wires = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/outpost/abandoned) "bq" = ( /obj/machinery/door/airlock/glass/science, /obj/structure/barricade, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "br" = ( /obj/structure/table/steel, /obj/effect/floor_decal/corner/purple/three_quarters{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bs" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bt" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bu" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bv" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small{ dir = 1 }, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bw" = ( /obj/random/trash, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bx" = ( /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "by" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor, /area/outpost/abandoned) "bz" = ( /obj/item/ammo_casing/shotgun/pellet, @@ -388,13 +386,12 @@ pixel_y = -10 }, /obj/effect/decal/cleanable/blood{ - pixel_x = 0; pixel_y = 32 }, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bA" = ( /obj/item/ammo_casing/shotgun/pellet{ @@ -406,39 +403,38 @@ /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bB" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/noticeboard/anomaly{ - pixel_y = 32 + default_pixel_y = 32 }, /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bC" = ( /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/outpost/abandoned) "bD" = ( /obj/machinery/light/small{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor, /area/outpost/abandoned) "bE" = ( /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/outpost/abandoned) "bF" = ( /obj/machinery/light/small{ @@ -447,7 +443,7 @@ /obj/effect/floor_decal/corner/purple{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bG" = ( /obj/structure/table/steel, @@ -455,64 +451,62 @@ dir = 9 }, /obj/random/loot, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bH" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bI" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/trash/cigbutt/cigarbutt, -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "bJ" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/outpost/abandoned) "bK" = ( /obj/effect/gibspawner/human, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bL" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/outpost/abandoned) "bM" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bN" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bO" = ( /obj/effect/floor_decal/corner/purple/three_quarters, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bP" = ( /obj/effect/floor_decal/corner/purple{ dir = 10 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bQ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/purple{ dir = 10 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bR" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small, -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "bS" = ( /obj/random/trash, -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "bT" = ( /obj/effect/floor_decal/corner/purple{ @@ -521,517 +515,459 @@ /obj/effect/floor_decal/corner/purple{ dir = 10 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bU" = ( /obj/effect/floor_decal/corner/purple{ dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/outpost/abandoned) "bV" = ( /obj/machinery/light/small, /obj/effect/floor_decal/corner/purple{ dir = 10 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bW" = ( /obj/machinery/door/airlock/security, /obj/machinery/door/blast/regular{ id_tag = "mars_blast" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "bX" = ( /obj/machinery/door/airlock/science, /obj/machinery/door/blast/regular{ id_tag = "mars_blast" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bY" = ( /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "bZ" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "ca" = ( /obj/structure/table/steel, /obj/effect/floor_decal/corner/paleblue/three_quarters{ - icon_state = "corner_white_three_quarters"; dir = 8 }, /obj/random/loot, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cb" = ( /obj/structure/table/steel, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cc" = ( /obj/machinery/optable, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cd" = ( /obj/machinery/computer/operating, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ce" = ( -/obj/structure/closet/secure_closet/medical2, /obj/effect/floor_decal/corner/paleblue/three_quarters{ - icon_state = "corner_white_three_quarters"; dir = 1 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cf" = ( /obj/effect/floor_decal/corner/red/three_quarters{ - icon_state = "corner_white_three_quarters"; dir = 8 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/ammo_casing/pistol/magnum, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "cg" = ( /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/ammo_casing/pistol/magnum, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "ch" = ( /obj/structure/table/steel_reinforced, /obj/machinery/embedded_controller/radio/airlock/access_controller, /obj/effect/floor_decal/corner/red/three_quarters{ - icon_state = "corner_white_three_quarters"; dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "cj" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "ck" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor, /area/outpost/abandoned) "cl" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, /obj/structure/window/reinforced/tinted/frosted, /obj/machinery/atmospherics/unary/vent_pump{ - icon_state = "map_vent"; dir = 4 }, /obj/structure/sign/warning/secure_area{ pixel_y = 32 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "cm" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 9 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/outpost/abandoned) "cn" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - icon_state = "wood_broken3" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/broken/three, /area/outpost/abandoned) "co" = ( -/obj/structure/table/woodentable, -/obj/effect/decal/cleanable/dirt, +/obj/structure/table/laminate, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/outpost/abandoned) "cp" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/board, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/outpost/abandoned) "cq" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/loot, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/outpost/abandoned) "cr" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood{ - icon_state = "wood_broken2" - }, +/turf/floor/laminate/broken/two, /area/outpost/abandoned) "cs" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate, /area/outpost/abandoned) "ct" = ( /obj/machinery/door/airlock/centcom, /obj/machinery/door/blast/regular{ id_tag = "mars_blast" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "cu" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cv" = ( /obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cw" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cx" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cy" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "cG" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/wall/titanium, +/obj/effect/decal/cleanable/dirt/visible, +/turf/wall/titanium, /area/outpost/abandoned) "cH" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate, /area/outpost/abandoned) "cI" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate, /area/outpost/abandoned) "cJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - icon_state = "wood_broken4" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/broken/four, /area/outpost/abandoned) "cK" = ( /obj/effect/floor_decal/plaque, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate, /area/outpost/abandoned) "cL" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/simulated/floor/wood{ - icon_state = "wood_broken0" - }, +/turf/floor/laminate/broken, /area/outpost/abandoned) "cM" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/outpost/abandoned) "cN" = ( -/obj/structure/filingcabinet/filingcabinet, -/turf/simulated/floor/carpet/blue, +/obj/structure/filing_cabinet/tall, +/turf/floor/carpet/blue, /area/outpost/abandoned) "cO" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/loot, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "cP" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "cQ" = ( -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "cR" = ( /obj/structure/girder, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "cS" = ( -/obj/structure/filingcabinet/filingcabinet, -/turf/simulated/floor/tiled/dark, +/obj/structure/filing_cabinet/tall, +/turf/floor/tiled/dark, /area/outpost/abandoned) "cT" = ( /obj/structure/foamedmetal, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "cU" = ( /obj/effect/floor_decal/corner/paleblue/three_quarters, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cV" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cW" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cX" = ( /obj/effect/decal/cleanable/blood, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/loot, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cY" = ( /obj/effect/floor_decal/corner/paleblue/three_quarters{ - icon_state = "corner_white_three_quarters"; dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "cZ" = ( /obj/effect/floor_decal/corner/red/three_quarters, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "da" = ( /obj/structure/sign/poster{ pixel_y = -32 }, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "db" = ( /obj/effect/floor_decal/corner/red/three_quarters{ - icon_state = "corner_white_three_quarters"; dir = 4 }, /obj/machinery/computer/modular/preset/security{ - icon_state = "console"; - dir = 8 + dir = 8; + icon_state = "console" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "dc" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "dd" = ( /obj/structure/barricade, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor, /area/outpost/abandoned) "de" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/red, /obj/structure/window/reinforced/tinted/frosted{ - icon_state = "fwindow"; - dir = 1 + dir = 1; + icon_state = "fwindow" }, /obj/machinery/atmospherics/unary/vent_pump{ - icon_state = "map_vent"; dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "df" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/door/blast/regular{ id_tag = "mars_blast" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "dg" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet, /area/outpost/abandoned) "dh" = ( -/turf/simulated/floor/carpet{ - icon_state = "carpet_broken" - }, +/turf/floor/carpet/broken, /area/outpost/abandoned) "di" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet{ - icon_state = "carpet_broken" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet/broken, /area/outpost/abandoned) "dj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet, /area/outpost/abandoned) "dk" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet{ - icon_state = "carpet_broken" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet/broken, /area/outpost/abandoned) "dl" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 6 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet, /area/outpost/abandoned) "dm" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular{ id_tag = "mars_blast" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "do" = ( /obj/effect/decal/cleanable/blood/gibs/limb, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "dp" = ( /obj/structure/janitorialcart, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "dq" = ( -/obj/structure/dispenser, -/turf/simulated/floor/tiled/dark, +/obj/structure/tank_rack, +/turf/floor/tiled/dark, /area/outpost/abandoned) "dr" = ( /obj/structure/barricade, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "ds" = ( -/obj/machinery/door/airlock/medical{ - density = 0; - icon_state = "door_open"; - opacity = 0 - }, +/obj/machinery/door/airlock/medical/open, /obj/machinery/holosign/surgery, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dt" = ( /obj/structure/door_assembly{ anchored = 1 }, -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "du" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "dv" = ( -/turf/simulated/floor/asteroid, -/turf/simulated/shuttle/wall{ - icon_state = "diagonalWall3" +/turf/floor/barren, +/turf/wall/shuttle{ + unique_merge_identifier = "mining_signal" }, /area/outpost/abandoned) "dw" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/loot, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/outpost/abandoned) "dx" = ( /obj/effect/floor_decal/spline/fancy/wood, -/obj/structure/table/woodentable, -/turf/simulated/floor/carpet, +/obj/structure/table/laminate, +/turf/floor/carpet, /area/outpost/abandoned) "dy" = ( /obj/effect/floor_decal/spline/fancy/wood, @@ -1039,51 +975,39 @@ icon_state = "plant-25" }, /obj/machinery/light/small, -/turf/simulated/floor/carpet{ - icon_state = "carpet_broken" - }, +/turf/floor/carpet/broken, /area/outpost/abandoned) "dz" = ( /obj/effect/floor_decal/spline/fancy/wood, -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/loot, -/turf/simulated/floor/carpet{ - icon_state = "carpet_broken" - }, +/turf/floor/carpet/broken, /area/outpost/abandoned) "dA" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 6 }, -/obj/structure/table/woodentable, -/turf/simulated/floor/carpet, -/area/outpost/abandoned) -"dB" = ( -/turf/simulated/floor/asteroid, -/turf/simulated/shuttle/wall{ - icon_state = "diagonalWall3"; - dir = 4 - }, +/obj/structure/table/laminate, +/turf/floor/carpet, /area/outpost/abandoned) "dC" = ( /obj/machinery/vending/coffee{ icon_state = "coffee-broken"; markup = 0 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "dD" = ( -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dE" = ( -/obj/effect/decal/remains, +/obj/item/remains, /obj/structure/table, /obj/item/shard{ icon_state = "shardlarge" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dF" = ( /obj/structure/table, @@ -1091,301 +1015,279 @@ icon_state = "shardsmall" }, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dG" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dH" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dI" = ( /obj/effect/decal/cleanable/cobweb, /obj/machinery/alarm{ dir = 4; icon_state = "alarmx"; - pixel_x = -23; - pixel_y = 0 + pixel_x = -23 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dJ" = ( -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/structure/table/steel, /obj/random/bomb_supply, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dK" = ( -/obj/effect/fluid_mapped/fuel, -/obj/structure/bed/chair, -/turf/simulated/floor/tiled/airless, +/obj/abstract/landmark/mapped_fluid/fuel, +/obj/structure/chair, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dL" = ( -/obj/effect/fluid_mapped/fuel, -/obj/structure/bed/chair, +/obj/abstract/landmark/mapped_fluid/fuel, +/obj/structure/chair, /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dM" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled/airless, +/obj/structure/chair, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dN" = ( /obj/machinery/vending/snack{ icon_state = "snack-broken"; stat = 1 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dO" = ( /obj/structure/ore_box, -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "dP" = ( /obj/structure/closet/crate/large, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "dQ" = ( /obj/structure/sign/directions/science{ dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/red, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "dR" = ( -/obj/structure/table/woodentable{ +/obj/structure/table/laminate{ icon_state = "solid_flip0" }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "dS" = ( /obj/item/shard{ icon_state = "splinterslarge" }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "dT" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "dU" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light/small{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dV" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - icon_state = "dmg1" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating/broken, /area/outpost/abandoned) "dW" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dY" = ( /obj/structure/extinguisher_cabinet{ icon_state = "extinguisher_empty"; - pixel_x = 30 + pixel_x = 29; + dir = 8 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "dZ" = ( -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/structure/sign/directions/medical{ dir = 8 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "ea" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/fluid_mapped/fuel, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/mapped_fluid/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eb" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/mop, -/turf/simulated/floor/plating{ - icon_state = "dmg2" - }, +/turf/floor/plating/broken/two, /area/outpost/abandoned) "ec" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ed" = ( -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/effect/decal/cleanable/blood/oil, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ee" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ef" = ( /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eg" = ( /obj/effect/decal/cleanable/cobweb2, /obj/item/ammo_magazine/pistol/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eh" = ( /obj/structure/hygiene/sink/puddle, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "ei" = ( /obj/random/trash, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "ej" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/asteroid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/barren, /area/mine/explored) "ek" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "el" = ( /obj/structure/firedoor_assembly{ anchored = 1 }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "em" = ( /obj/structure/wall_frame, /obj/structure/grille/broken, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "en" = ( /obj/machinery/door/airlock/centcom, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "ep" = ( /obj/machinery/newscaster, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "eq" = ( /obj/effect/decal/cleanable/blood, /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "er" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "es" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "et" = ( -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/structure/table, /obj/structure/window/reinforced{ dir = 1 }, /obj/item/shard, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "eu" = ( -/obj/effect/fluid_mapped/fuel, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/abstract/landmark/mapped_fluid/fuel, +/obj/effect/decal/cleanable/dirt/visible, /mob/living/bot/medbot, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "ev" = ( -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/tiled/white/airless, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "ex" = ( /obj/machinery/door/airlock/medical, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ey" = ( -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ez" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - icon_state = "dmg1" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating/broken/one, /area/outpost/abandoned) "eA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/gibspawner/human, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red, /obj/item/ammo_magazine/pistol/small, -/turf/simulated/floor/plating{ - icon_state = "dmg1" - }, +/turf/floor/plating/broken/one, /area/outpost/abandoned) "eC" = ( /obj/item/ammo_magazine/pistol/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eD" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eE" = ( /obj/machinery/door/blast/regular{ @@ -1393,60 +1295,56 @@ }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "eF" = ( /obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 4 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "eG" = ( /obj/machinery/door/airlock/external, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "eH" = ( /obj/effect/floor_decal/industrial/warning/cee{ - icon_state = "warningcee"; - dir = 1 + dir = 1; + icon_state = "warningcee" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "eI" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/door/airlock/external, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "eJ" = ( /obj/item/shard{ icon_state = "shardsmall" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "eK" = ( /obj/item/shard{ icon_state = "piecesmall" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "eL" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "eM" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "eO" = ( /obj/structure/table/glass, @@ -1455,165 +1353,142 @@ }, /obj/structure/window/reinforced, /obj/random/loot, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "eP" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - icon_state = "dmg4" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating/broken/four, /area/outpost/abandoned) "eQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/white/airless, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "eR" = ( /obj/structure/door_assembly, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eS" = ( /obj/effect/decal/cleanable/blood, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, /obj/random/trash, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eV" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/plating{ - icon_state = "dmg1" - }, +/turf/floor/plating/broken/one, /area/outpost/abandoned) "eW" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/fluid_mapped/fuel, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eX" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/generic, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/wrench, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "eZ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fa" = ( /obj/effect/decal/cleanable/ash, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fb" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/green{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/red, -/turf/simulated/floor/plating{ - icon_state = "dmg1" - }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/broken/one, /area/outpost/abandoned) "fc" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/blood, /obj/item/ammo_magazine/pistol/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fd" = ( /obj/effect/decal/cleanable/blood, /obj/item/ammo_magazine/pistol/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fe" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/mine/explored) "ff" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 4 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "fg" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning/cee, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "fh" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fi" = ( /obj/item/pen, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fj" = ( /obj/effect/decal/cleanable/blood/gibs/limb, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fk" = ( /obj/machinery/alarm{ @@ -1621,90 +1496,78 @@ icon_state = "alarmx"; pixel_x = 24 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fl" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fm" = ( -/turf/simulated/floor/plating{ - icon_state = "dmg3" - }, +/turf/floor/plating/broken/three, /area/outpost/abandoned) "fo" = ( /obj/random/medical, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fq" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fr" = ( /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, -/obj/structure/flora/ausbushes/brflowers, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/brflowers, +/turf/floor/fake_grass, /area/outpost/abandoned) "fs" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/vomit, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/vomit/mapped, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ft" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/medical, -/turf/simulated/floor/plating{ - icon_state = "dmg4" - }, +/turf/floor/plating/broken/four, /area/outpost/abandoned) "fu" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/mopbucket, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fv" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/remains, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/remains, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fw" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/simulated/floor/plating{ - icon_state = "dmg1" - }, +/turf/floor/plating/broken/one, /area/outpost/abandoned) "fx" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/ammo_magazine/pistol/small, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fy" = ( /obj/effect/floor_decal/asteroid, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "fz" = ( /obj/effect/floor_decal/asteroid, -/turf/simulated/floor/plating{ - icon_state = "dmg2" - }, +/turf/floor/plating/broken/two, /area/mine/explored) "fA" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/window/reinforced{ dir = 1 }, @@ -1712,284 +1575,252 @@ dir = 8 }, /obj/random/loot, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fB" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, /obj/machinery/door/window/northleft, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fC" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/window/reinforced{ dir = 1 }, /obj/item/gun/energy/taser, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fD" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/structure/table, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fE" = ( /obj/effect/floor_decal/corner/paleblue/three_quarters, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fF" = ( /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fG" = ( /obj/structure/mech_wreckage/powerloader, /obj/effect/floor_decal/corner/paleblue{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fH" = ( /obj/random/firstaid, -/turf/simulated/floor/tiled/white/airless, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "fI" = ( -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/outpost/abandoned) "fJ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/window/basic{ - icon_state = "window"; dir = 4 }, /obj/structure/window/basic{ - icon_state = "window"; dir = 1 }, -/obj/structure/flora/ausbushes/stalkybush, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/stalkybush, +/turf/floor/fake_grass, /area/outpost/abandoned) "fK" = ( /obj/effect/decal/cleanable/blood/gibs/down, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fL" = ( /obj/item/newspaper, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fM" = ( /obj/machinery/firealarm{ dir = 1; icon_state = "firex"; - pixel_x = 0; pixel_y = -24 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fN" = ( -/obj/machinery/requests_console{ +/obj/machinery/network/requests_console{ icon_state = "req_comp_rewired"; pixel_y = -32; - stat = 1 + stat = 1; + dir = 2 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fO" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - icon_state = "0-2"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-2" }, -/obj/machinery/power/apc/high/inactive{ - dir = 2; +/obj/machinery/apc/high/inactive{ name = "south bump"; pixel_y = -24 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fP" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small/emergency, /obj/structure/cable{ - icon_state = "1-8"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "1-8" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fQ" = ( /obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "fR" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/mine/explored) "fS" = ( /obj/effect/decal/cleanable/blood, /obj/machinery/light/small, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fT" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/firealarm{ dir = 1; icon_state = "firex"; - pixel_x = 0; pixel_y = -24 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fU" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/window/reinforced{ dir = 8 }, -/obj/item/chems/food/drinks/flask/vacuumflask, -/turf/simulated/floor/tiled/dark, +/obj/item/chems/drinks/flask/vacuumflask, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fV" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "fW" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "fX" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "fY" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "fZ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "ga" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gb" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/mine/explored) "gc" = ( /obj/item/solar_assembly, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/asteroid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/barren, /area/mine/explored) "gd" = ( /obj/structure/windoor_assembly{ anchored = 1; - dir = 8; - icon_state = "l_windoor_assembly01" + dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "ge" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "gf" = ( /obj/structure/cable, /obj/machinery/power/smes/batteryrack, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gg" = ( -/obj/machinery/computer/power_monitor, /obj/effect/decal/cleanable/cobweb2, /obj/structure/cable, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gh" = ( /obj/structure/barricade, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gi" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken0" - }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless/broken, /area/mine/explored) "gj" = ( /obj/machinery/door/airlock/hatch, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/outpost/abandoned) "gk" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gl" = ( /obj/structure/girder, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gm" = ( -/turf/simulated/floor/plating{ - icon_state = "dmg2" - }, +/turf/floor/plating/broken/two, /area/outpost/abandoned) "gn" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "go" = ( /obj/machinery/door/airlock/external, @@ -1997,214 +1828,187 @@ id_tag = "mars_blast" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gp" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 9 }, /obj/random/loot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gq" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 5 }, /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gr" = ( /obj/machinery/door/airlock/external, /obj/machinery/door/blast/regular/open, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gs" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/asteroid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/barren, /area/mine/explored) "gt" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/asteroid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/barren, /area/mine/explored) "gu" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/outpost/abandoned) "gv" = ( /obj/random/closet, /obj/random/loot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gw" = ( /obj/structure/cable/orange{ - icon_state = "1-2"; - dir = 1 + dir = 1; + icon_state = "1-2" }, /obj/structure/cable/orange{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gx" = ( /obj/structure/cable/orange{ - icon_state = "1-4"; - dir = 4 + dir = 4; + icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gy" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gz" = ( -/obj/machinery/door/airlock/external{ - density = 0; - icon_state = "door_open"; - opacity = 0 - }, +/obj/machinery/door/airlock/external/open, /obj/machinery/door/blast/regular/open, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gA" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gB" = ( /obj/effect/floor_decal/industrial/warning/dust{ - icon_state = "warning_dust"; dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gC" = ( -/turf/simulated/floor/tiled/airless{ - icon_state = "steel_broken4" - }, +/obj/abstract/landmark/proc_caller/floor_breaker, +/turf/floor/tiled/airless/broken, /area/mine/explored) "gD" = ( /obj/effect/floor_decal/industrial/hatch, /obj/structure/cable/orange{ - icon_state = "1-2"; - dir = 1 + dir = 1; + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gE" = ( /obj/effect/decal/cleanable/blood/tracks/footprints, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gF" = ( /obj/structure/sign/warning/vacuum{ pixel_x = 32 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gH" = ( /obj/structure/cable/orange{ icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gI" = ( /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gJ" = ( /obj/machinery/door/airlock/hatch, /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gK" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable/orange{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gL" = ( /obj/effect/decal/cleanable/blood/tracks/footprints, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gM" = ( /obj/item/solar_assembly, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "gN" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/door/firedoor, /obj/structure/cable/orange{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gO" = ( /obj/effect/decal/cleanable/blood/tracks/footprints, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/firedoor_assembly{ anchored = 1 }, -/turf/simulated/floor/plating{ - icon_state = "dmg2" - }, +/turf/floor/plating/broken/two, /area/outpost/abandoned) "gP" = ( /obj/effect/decal/cleanable/blood/gibs/limb, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gQ" = ( /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 1 }, /obj/machinery/power/tracker, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/outpost/abandoned) "gR" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable/orange{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gS" = ( /obj/machinery/firealarm{ @@ -2212,472 +2016,419 @@ icon_state = "firex"; pixel_x = 26 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "gT" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gU" = ( /obj/structure/cable/orange{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/orange{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gV" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gW" = ( /obj/structure/cable/orange{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/outpost/abandoned) "gX" = ( /obj/structure/cable/orange{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/orange{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/orange{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gY" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 4 }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "gZ" = ( /obj/random/junk, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "ha" = ( /obj/machinery/newscaster{ icon_state = "newscaster_off"; pixel_x = -30; - stat = 1 + stat = 1; + dir = 8 }, /obj/machinery/newscaster{ icon_state = "crack3"; pixel_x = -30; - stat = 1 + stat = 1; + dir = 8 }, /obj/structure/cable/orange{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hb" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hc" = ( /obj/structure/table/steel, /obj/item/ashtray/glass, /obj/effect/decal/cleanable/cobweb2, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "he" = ( /obj/effect/floor_decal/solarpanel, /obj/machinery/power/solar, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hf" = ( /obj/effect/floor_decal/solarpanel, /obj/machinery/power/solar, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hg" = ( /obj/structure/closet/crate/trashcart, /obj/random/loot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hh" = ( /obj/machinery/washing_machine, /obj/structure/cable/orange{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hj" = ( /obj/effect/decal/cleanable/blood/gibs/body, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hk" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hl" = ( /obj/random/trash, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hm" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hn" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/orange{ - icon_state = "0-1"; dir = 8 }, /obj/machinery/power/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "ho" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/toolbox, /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hp" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/plating, /area/outpost/abandoned) "hq" = ( /obj/structure/table/reinforced, /obj/random/contraband, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hr" = ( /obj/random/junk, /obj/structure/cable/orange{ icon_state = "1-4" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hs" = ( /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/random/loot, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "ht" = ( /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hu" = ( /obj/machinery/light/small/emergency, /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hv" = ( /obj/item/gun/energy/plasmacutter, /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hw" = ( /obj/structure/cable/orange{ icon_state = "0-4" }, /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/power/solar_control/autostart{ dir = 8 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/outpost/abandoned) "hx" = ( /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/outpost/abandoned) "hy" = ( /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /turf/unsimulated/mask, /area/outpost/abandoned) "hz" = ( /obj/structure/cable/orange{ - icon_state = "1-4"; - dir = 4 + dir = 4; + icon_state = "1-4" }, /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /turf/unsimulated/mask, /area/outpost/abandoned) "hA" = ( /obj/structure/cable/orange{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/orange{ - icon_state = "1-4"; - dir = 4 + dir = 4; + icon_state = "1-4" }, /turf/unsimulated/mask, /area/outpost/abandoned) "hB" = ( /obj/structure/cable/orange{ - icon_state = "1-4"; - dir = 4 + dir = 4; + icon_state = "1-4" }, /turf/unsimulated/mask, /area/outpost/abandoned) "hC" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hD" = ( /obj/random/junk, -/obj/effect/decal/cleanable/dirt, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/plating, /area/outpost/abandoned) "hE" = ( /obj/structure/table/reinforced, /obj/random/material, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/plating, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/plating, /area/outpost/abandoned) "hF" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/powercell, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hG" = ( -/obj/effect/fluid_mapped/fuel, +/obj/abstract/landmark/mapped_fluid/fuel, /obj/structure/closet/crate/radiation, /obj/random/voidsuit, /obj/random/voidhelmet, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "hH" = ( /obj/structure/reagent_dispensers/fueltank, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/plating, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/plating, /area/outpost/abandoned) "hL" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/overmap/visitable/sector/away, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "ib" = ( /obj/effect/shuttle_landmark/away/nav7, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "jb" = ( /obj/effect/shuttle_landmark/away/nav1, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "kb" = ( /obj/effect/shuttle_landmark/away/nav2, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "lb" = ( /obj/effect/shuttle_landmark/away/nav3, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "mb" = ( /obj/effect/shuttle_landmark/away/nav6, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "nb" = ( /obj/effect/shuttle_landmark/away/nav5, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "ob" = ( /obj/effect/shuttle_landmark/away/nav4, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "pb" = ( /obj/effect/gibspawner/human, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/outpost/abandoned) "qb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/ammo_casing/pistol/magnum, -/turf/simulated/floor/tiled/dark, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/dark, /area/outpost/abandoned) "rb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/ammo_casing/pistol/magnum, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "sb" = ( /obj/structure/table/steel_reinforced, /obj/machinery/atmospherics/pipe/simple/hidden/red{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/button/blast_door{ id_tag = "mars_blast" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/outpost/abandoned) "tb" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/atmospherics/pipe/simple/hidden/red{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) "ub" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/outpost/abandoned) "vb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/obj/effect/decal/cleanable/vomit, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, +/obj/effect/decal/cleanable/vomit/mapped, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor, /area/outpost/abandoned) "wb" = ( /obj/machinery/computer/modular/preset/cardslot/command{ - icon_state = "console"; - dir = 4 + dir = 4; + icon_state = "console" }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/outpost/abandoned) "yb" = ( -/obj/item/storage/mirror{ +/obj/structure/mirror{ icon_state = "mirror_broke"; - name = "mirror"; pixel_x = 30 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/red{ - icon_state = "intact"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/small/emergency{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/outpost/abandoned) "HD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/airless, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/airless, /area/outpost/abandoned) "IX" = ( /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/outpost/abandoned) (1,1,1) = {" @@ -18534,7 +18285,7 @@ cs cM dl dm -dB +dv ab ab ej @@ -18735,7 +18486,7 @@ af af af dm -dB +dv ab ab ab diff --git a/maps/away/mining/mining.dm b/maps/away/mining/mining.dm index 07a0178fe0c5..dcd99e53aeeb 100644 --- a/maps/away/mining/mining.dm +++ b/maps/away/mining/mining.dm @@ -14,7 +14,6 @@ "nav_cluster_6", "nav_cluster_7" ) - known = 0 /obj/effect/overmap/visitable/sector/cluster/generate_skybox() return overlay_image('icons/skybox/rockbox.dmi', "rockbox", COLOR_ASTEROID_ROCK, RESET_COLOR) @@ -26,12 +25,11 @@ /datum/map_template/ruin/away_site/mining_asteroid name = "Mining - Asteroid" - id = "awaysite_mining_asteroid" description = "A medium-sized asteroid full of minerals." suffixes = list("mining/mining-asteroid.dmm") cost = 1 accessibility_weight = 10 - generate_mining_by_z = 1 + level_data_type = /datum/level_data/mining_level/asteroid apc_test_exempt_areas = list( /area/outpost/abandoned = NO_SCRUBBER, /area/mine/explored = NO_SCRUBBER|NO_VENT|NO_APC, @@ -85,7 +83,6 @@ "nav_away_6", "nav_away_7" ) - known = 0 /obj/effect/overmap/visitable/sector/away/generate_skybox() return overlay_image('icons/skybox/rockbox.dmi', "rockbox", COLOR_ASTEROID_ROCK, RESET_COLOR) @@ -97,12 +94,10 @@ /datum/map_template/ruin/away_site/mining_signal name = "Mining - Planetoid" - id = "awaysite_mining_signal" description = "A mineral-rich, formerly-volcanic site on a planetoid." suffixes = list("mining/mining-signal.dmm") cost = 1 - generate_mining_by_z = 1 - base_turf_for_zs = /turf/simulated/floor/asteroid + level_data_type = /datum/level_data/mining_level/asteroid area_usage_test_exempted_root_areas = list(/area/mine, /area/outpost) apc_test_exempt_areas = list( /area/mine/explored = NO_SCRUBBER|NO_VENT|NO_APC, @@ -155,7 +150,6 @@ "nav_orb_6", "nav_orb_7" ) - known = 0 /obj/effect/overmap/visitable/sector/orb/get_skybox_representation() var/image/res = overlay_image('icons/skybox/skybox_rock_128.dmi', "bigrock", COLOR_ASTEROID_ROCK, RESET_COLOR) @@ -165,13 +159,11 @@ /datum/map_template/ruin/away_site/orb name = "Mining - Orb" - id = "awaysite_mining_orb" description = "A sort of circular asteroid with a bird." suffixes = list("mining/mining-orb.dmm") cost = 1 accessibility_weight = 10 - generate_mining_by_z = 1 - base_turf_for_zs = /turf/simulated/floor/asteroid + level_data_type = /datum/level_data/mining_level/asteroid area_usage_test_exempted_root_areas = list(/area/mine) area_usage_test_exempted_areas = list(/area/djstation) apc_test_exempt_areas = list( @@ -214,24 +206,23 @@ desc = "Some kind of post, pillar, plinth, column, or totem." icon = 'icons/obj/structures/totem.dmi' icon_state = "totem" - density = 1 - anchored = 1 - unacidable = 1 + density = TRUE + anchored = TRUE + material = /decl/material/solid/metal/aliumium var/number /obj/structure/totem/Initialize() . = ..() number = rand(10,99) -/obj/structure/totem/examine(mob/user) +/obj/structure/totem/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - to_chat(user, "It's been engraved with the symbols 'RWH QaG [number]'.") //i am not a linguist - + . += "It's been engraved with the symbols 'RWH QaG [number]'." /obj/item/stool/stone/Initialize(mapload) . = ..(mapload, /decl/material/solid/stone/sandstone) -/turf/simulated/floor/airless/stone +/turf/floor/plating/airless/stone name = "temple floor" desc = "You can only imagine what once took place in these halls." icon = 'icons/turf/flooring/cult.dmi' diff --git a/maps/away/mining/mining_areas.dm b/maps/away/mining/mining_areas.dm index 7788187e464c..3dd6da725299 100644 --- a/maps/away/mining/mining_areas.dm +++ b/maps/away/mining/mining_areas.dm @@ -3,8 +3,8 @@ icon_state = "mining" ambience = list('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg') sound_env = ASTEROID - base_turf = /turf/simulated/floor/asteroid - area_flags = AREA_FLAG_IS_BACKGROUND + base_turf = /turf/floor/barren + area_flags = AREA_FLAG_IS_BACKGROUND | AREA_FLAG_HIDE_FROM_HOLOMAP /area/mine/explored name = "Mine" diff --git a/maps/away/mobius_rift/mobius_rift.dm b/maps/away/mobius_rift/mobius_rift.dm index bead2032c4a6..48b89d81a81d 100644 --- a/maps/away/mobius_rift/mobius_rift.dm +++ b/maps/away/mobius_rift/mobius_rift.dm @@ -4,11 +4,9 @@ name = "unusual asteroid" desc = "Sensors error: ERROR #E0x003141592: recursive stack overflow for CALCULATE_APPROXIMATE_SIZE()." icon_state = "object" - known = 0 /datum/map_template/ruin/away_site/mobius_rift name = "Mobius rift" - id = "awaysite_mobius_rift" description = "Non-euclidian mess." suffixes = list("mobius_rift/mobius_rift.dmm") cost = 1 @@ -18,10 +16,8 @@ ) /obj/effect/step_trigger/mobius_rift/seamless_portal + is_spawnable_type = FALSE var/obj/effect/step_trigger/mobius_rift/seamless_portal/dest - //NORTH or EAST cases - //var/obj/effect/step_trigger/mobius_rift/seamless_portal/dest2//SOUTH or WEST cases - var/directed//NS or WE var/x_shift = 0 var/y_shift = 0 @@ -36,7 +32,7 @@ if (towards == WEST) x_shift = -1 -/obj/effect/step_trigger/mobius_rift/seamless_portal/proc/set_destination(var/D) +/obj/effect/step_trigger/mobius_rift/seamless_portal/proc/set_destination(var/obj/effect/step_trigger/mobius_rift/seamless_portal/D) dest = D /obj/effect/step_trigger/mobius_rift/seamless_portal/Trigger(var/atom/movable/AM) @@ -48,6 +44,7 @@ //spawns and presets portals to their destinations, must be in left lower chamber center /obj/effect/mobius_rift/portals_setup + is_spawnable_type = FALSE // Should only be mapped in, spawning it in has unpredictable results. var/grid_number = 4//amount of rooms in a square pattern grid var/grid_size = 31//lenfth from center of one room to another, or size of a chamber(room length, 12?) + corridor length. Corridor length is (view-range * 2) (16?) @@ -86,23 +83,24 @@ return INITIALIZE_HINT_QDEL /obj/effect/mobius_rift/chamber + is_spawnable_type = FALSE var/list/portals = list() /obj/effect/mobius_rift/chamber/Initialize(var/mapload, var/grid_size)//NORTH, SOUTH, EAST, WEST . = ..() - var/turf/T - T = locate(src.x, src.y + round(grid_size/2), src.z) - var/N = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, NORTH) - portals["NORTH"] = N - T = locate(src.x, src.y - round(grid_size/2), src.z) - var/S = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, SOUTH) - portals["SOUTH"] = S - T = locate(src.x + round(grid_size/2), src.y, src.z) - var/E = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, EAST) - portals["EAST"] = E - T = locate(src.x - round(grid_size/2), src.y, src.z) - var/W = new /obj/effect/step_trigger/mobius_rift/seamless_portal(T, WEST) - portals["WEST"] = W + var/turf/rift_turf + rift_turf = locate(src.x, src.y + round(grid_size/2), src.z) + var/north_portal = new /obj/effect/step_trigger/mobius_rift/seamless_portal(rift_turf, NORTH) + portals["NORTH"] = north_portal + rift_turf = locate(src.x, src.y - round(grid_size/2), src.z) + var/south_portal = new /obj/effect/step_trigger/mobius_rift/seamless_portal(rift_turf, SOUTH) + portals["SOUTH"] = south_portal + rift_turf = locate(src.x + round(grid_size/2), src.y, src.z) + var/east_portal = new /obj/effect/step_trigger/mobius_rift/seamless_portal(rift_turf, EAST) + portals["EAST"] = east_portal + rift_turf = locate(src.x - round(grid_size/2), src.y, src.z) + var/west_portal = new /obj/effect/step_trigger/mobius_rift/seamless_portal(rift_turf, WEST) + portals["WEST"] = west_portal /obj/effect/mobius_rift/chamber/proc/set_portals(var/list/destinations) for (var/iter = 1 to portals.len) diff --git a/maps/away/mobius_rift/mobius_rift.dmm b/maps/away/mobius_rift/mobius_rift.dmm index 02a0aa1ffb26..01d8bd7e375b 100644 --- a/maps/away/mobius_rift/mobius_rift.dmm +++ b/maps/away/mobius_rift/mobius_rift.dmm @@ -9,62 +9,62 @@ /turf/unsimulated/floor/infinity, /area/mobius_rift) "d" = ( -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/mobius_rift) "e" = ( -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/mobius_rift) "f" = ( -/turf/simulated/wall/natural/random/high_chance, +/turf/wall/natural/random/high_chance, /area/mobius_rift) "g" = ( /turf/space, /area/mobius_rift) "h" = ( -/obj/structure/flora/ausbushes/fullgrass, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, /area/mobius_rift) "i" = ( -/obj/structure/flora/ausbushes/fullgrass, -/turf/unsimulated/beach/sand, +/obj/structure/flora/bush/fullgrass, +/turf/unsimulated/floor/sand, /area/mobius_rift) "j" = ( -/obj/structure/flora/ausbushes/genericbush, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/genericbush, +/turf/floor/fake_grass, /area/mobius_rift) "k" = ( -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/mobius_rift) "l" = ( -/obj/structure/flora/ausbushes/fullgrass, -/obj/structure/flora/ausbushes/genericbush, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/fullgrass, +/obj/structure/flora/bush/genericbush, +/turf/floor/fake_grass, /area/mobius_rift) "m" = ( -/obj/structure/flora/ausbushes/grassybush, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/grassybush, +/turf/floor/fake_grass, /area/mobius_rift) "n" = ( /mob/living/simple_animal/hostile/vagrant, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/mobius_rift) "o" = ( -/obj/structure/flora/ausbushes/pointybush, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/pointybush, +/turf/floor/fake_grass, /area/mobius_rift) "p" = ( -/obj/structure/flora/ausbushes/sunnybush, -/turf/simulated/floor/grass, +/obj/structure/flora/bush/sunnybush, +/turf/floor/fake_grass, /area/mobius_rift) "q" = ( /mob/living/simple_animal/hostile/vagrant, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/mobius_rift) "r" = ( /obj/effect/mobius_rift/portals_setup, /obj/effect/overmap/visitable/sector/mobius_rift, /obj/effect/shuttle_landmark/automatic, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/mobius_rift) (1,1,1) = {" diff --git a/maps/away/mobius_rift/mobius_rift_areas.dm b/maps/away/mobius_rift/mobius_rift_areas.dm index 822bc88d8a2f..90d7a9a5555f 100644 --- a/maps/away/mobius_rift/mobius_rift_areas.dm +++ b/maps/away/mobius_rift/mobius_rift_areas.dm @@ -2,4 +2,4 @@ name = "Mobius Rift" icon = 'maps/away/mobius_rift/mobius_rift_sprites.dmi' icon_state = "mr" - base_turf = /turf/unsimulated/beach/sand \ No newline at end of file + base_turf = /turf/unsimulated/floor/sand \ No newline at end of file diff --git a/maps/away/slavers/slavers_base.dm b/maps/away/slavers/slavers_base.dm deleted file mode 100644 index 451fa65ac50f..000000000000 --- a/maps/away/slavers/slavers_base.dm +++ /dev/null @@ -1,191 +0,0 @@ -#include "slavers_base_areas.dm" -#include "../mining/mining_areas.dm" - -/obj/effect/overmap/visitable/sector/slavers_base - name = "large asteroid" - desc = "Sensor array is reading an artificial structure inside the asteroid." - icon_state = "object" - known = 0 - - initial_generic_waypoints = list( - "nav_slavers_base_1", - "nav_slavers_base_2", - "nav_slavers_base_3", - "nav_slavers_base_4", - "nav_slavers_base_5", - "nav_slavers_base_6", - "nav_slavers_base_antag" - ) - -/datum/map_template/ruin/away_site/slavers - name = "Slavers' Base" - id = "awaysite_slavers" - description = "Asteroid with slavers base inside." - suffixes = list("slavers/slavers_base.dmm") - cost = 1 - generate_mining_by_z = 1 - area_usage_test_exempted_root_areas = list(/area/slavers_base) - apc_test_exempt_areas = list( - /area/slavers_base/hangar = NO_SCRUBBER - ) - -/obj/effect/shuttle_landmark/nav_slavers_base/nav1 - name = "Slavers Base Navpoint #1" - landmark_tag = "nav_slavers_base_1" - -/obj/effect/shuttle_landmark/nav_slavers_base/nav2 - name = "Slavers Base Navpoint #2" - landmark_tag = "nav_slavers_base_2" - -/obj/effect/shuttle_landmark/nav_slavers_base/nav3 - name = "Slavers Base Navpoint #3" - landmark_tag = "nav_slavers_base_3" - -/obj/effect/shuttle_landmark/nav_slavers_base/nav4 - name = "Slavers Base Navpoint #4" - landmark_tag = "nav_slavers_base_4" - -/obj/effect/shuttle_landmark/nav_slavers_base/nav5 - name = "Slavers Base Navpoint #5" - landmark_tag = "nav_slavers_base_5" - -/obj/effect/shuttle_landmark/nav_slavers_base/nav6 - name = "Slavers Base Navpoint #6" - landmark_tag = "nav_slavers_base_6" - -/obj/effect/shuttle_landmark/nav_slavers_base/nav7 - name = "Slavers Base Navpoint #7" - landmark_tag = "nav_slavers_base_antag" - -/decl/hierarchy/outfit/corpse - name = "Corpse Clothing" - -/decl/hierarchy/outfit/corpse/Initialize() - ..() - hierarchy_type = type - -/decl/hierarchy/outfit/corpse/slavers_base - name = "Basic slaver output" - -/obj/effect/landmark/corpse/slavers_base/slaver1 - name = "Slaver" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver1) - -/decl/hierarchy/outfit/corpse/slavers_base/slaver1 - name = "Dead Slaver 1" - uniform = /obj/item/clothing/under/johnny - shoes = /obj/item/clothing/shoes/color/black - glasses = /obj/item/clothing/glasses/sunglasses - -/obj/effect/landmark/corpse/slavers_base/slaver2 - name = "Slaver" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver2) - -/decl/hierarchy/outfit/corpse/slavers_base/slaver2 - name = "Dead Slaver 2" - uniform = /obj/item/clothing/under/rank/corp/grayson - shoes = /obj/item/clothing/shoes/color/blue - -/obj/effect/landmark/corpse/slavers_base/slaver3 - name = "Slaver" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver3) - -/decl/hierarchy/outfit/corpse/slavers_base/slaver3 - name = "Dead Slaver 3" - uniform = /obj/item/clothing/under/pirate - shoes = /obj/item/clothing/shoes/color/brown - -/obj/effect/landmark/corpse/slavers_base/slaver4 - name = "Slaver" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver4) - -/decl/hierarchy/outfit/corpse/slavers_base/slaver4 - name = "Dead Slaver 4" - uniform = /obj/item/clothing/under/redcoat - shoes = /obj/item/clothing/shoes/color/brown - -/obj/effect/landmark/corpse/slavers_base/slaver5 - name = "Slaver" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver5) - -/decl/hierarchy/outfit/corpse/slavers_base/slaver5 - name = "Dead Slaver 5" - uniform = /obj/item/clothing/under/sterile - shoes = /obj/item/clothing/shoes/color/orange - mask = /obj/item/clothing/mask/surgical - -/obj/effect/landmark/corpse/slavers_base/slaver6 - name = "Slaver" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slaver6) - -/decl/hierarchy/outfit/corpse/slavers_base/slaver6 - name = "Dead Slaver 6" - uniform = /obj/item/clothing/under/frontier - shoes = /obj/item/clothing/shoes/color/orange - -/obj/effect/landmark/corpse/slavers_base/slave - name = "Slave" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/slavers_base/slave) - -/decl/hierarchy/outfit/corpse/slavers_base/slave - name = "Dead Slave" - uniform = /obj/item/clothing/under/color/orange - shoes = /obj/item/clothing/shoes/jackboots/tactical - -/mob/living/simple_animal/hostile/abolition_extremist - name = "abolition extremist" - desc = "Vigiliant fighter against slavery." - icon = 'maps/away/slavers/slavers_base_sprites.dmi' - icon_state = "extremist" - icon_living = "extremist" - icon_dead = "extremist_dead" - speak_chance = 0 - turns_per_move = 5 - response_help = "pushes" - response_disarm = "shoves" - response_harm = "hits" - speed = 4 - stop_automated_movement_when_pulled = 0 - maxHealth = 100 - health = 100 - natural_weapon = /obj/item/natural_weapon/punch - can_escape = TRUE - unsuitable_atmos_damage = 15 - var/corpse = /obj/effect/landmark/corpse/abolitionist - var/weapon = /obj/item/gun/energy/laser - projectilesound = 'sound/weapons/laser.ogg' - ranged = 1 - projectiletype = /obj/item/projectile/beam - faction = "extremist abolitionists" - -/mob/living/simple_animal/hostile/abolition_extremist/death(gibbed, deathmessage, show_dead_message) - . = ..(gibbed, deathmessage, show_dead_message) - if(corpse) - new corpse(loc) - if(weapon) - new weapon(loc) - qdel(src) - -/obj/effect/landmark/corpse/abolitionist - name = "abolitionist" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/abolitionist) - -/decl/hierarchy/outfit/corpse/abolitionist - name = "Dead abolitionist" - uniform = /obj/item/clothing/under/abol_uniform - shoes = /obj/item/clothing/shoes/jackboots - head = /obj/item/clothing/head/helmet/merc - -/obj/item/clothing/under/abol_uniform - name = "abolitionist combat suit" - desc = "Lightly armored suit worn by abolition extremists during raids. It has green patches on the right sleeve and the chest. There is big green \"A\" on the back." - icon = 'maps/away/slavers/slavers_base_sprites.dmi' - icon_state = "abol_suit" - item_icons = list(slot_w_uniform_str = 'maps/away/slavers/slavers_base_sprites.dmi') - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS - armor = list( - melee = ARMOR_MELEE_KNIVES, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_MINOR - ) diff --git a/maps/away/slavers/slavers_base.dmm b/maps/away/slavers/slavers_base.dmm deleted file mode 100644 index fe7fff815bcc..000000000000 --- a/maps/away/slavers/slavers_base.dmm +++ /dev/null @@ -1,44683 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/space, -/area/space) -"ab" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav2, -/turf/space, -/area/space) -"ac" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav3, -/turf/space, -/area/space) -"ad" = ( -/turf/unsimulated/mask, -/area/mine/unexplored) -"ae" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav1, -/turf/space, -/area/space) -"af" = ( -/turf/simulated/wall/natural, -/area/space) -"ag" = ( -/turf/simulated/floor/asteroid, -/area/space) -"ah" = ( -/turf/simulated/wall, -/area/slavers_base/mort) -"ai" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav4, -/turf/space, -/area/space) -"aj" = ( -/obj/structure/ore_box{ - desc = "A heavy box covered with dried blood."; - name = "Big dirty box" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"ak" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"al" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"am" = ( -/obj/structure/crematorium, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"an" = ( -/obj/effect/decal/cleanable/ash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"ao" = ( -/obj/structure/table/standard, -/obj/item/wirecutters, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"ap" = ( -/obj/structure/table/standard, -/obj/effect/landmark/corpse/slavers_base/slave, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aq" = ( -/obj/structure/table/standard, -/obj/item/paper{ - info = "If they'll keep having fun with cargo in such manner, we'll run out of freezers to keep what's left from it."; - name = "Note" - }, -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"ar" = ( -/obj/structure/table/standard, -/obj/item/knife/table, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"as" = ( -/obj/structure/table/rack, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"at" = ( -/obj/effect/gibspawner/human, -/turf/simulated/floor/asteroid, -/area/space) -"au" = ( -/obj/structure/table/rack, -/obj/item/wirecutters, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"av" = ( -/obj/item/shovel, -/turf/simulated/floor/asteroid, -/area/space) -"aw" = ( -/obj/item/remains/human, -/turf/simulated/floor/asteroid, -/area/space) -"ax" = ( -/obj/item/remains/human, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"ay" = ( -/obj/item/bodybag, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"az" = ( -/obj/item/knife/table, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aA" = ( -/obj/structure/table/rack, -/obj/item/hatchet, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aB" = ( -/obj/structure/closet/crate/freezer, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aC" = ( -/obj/effect/gibspawner/human, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aD" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aE" = ( -/obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/machinery/power/apc{ - dir = 4; - name = "Slaves Mortuary"; - pixel_x = 24 - }, -/obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aF" = ( -/obj/machinery/light/small, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aG" = ( -/obj/machinery/gibber, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aH" = ( -/obj/structure/kitchenspike, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aI" = ( -/obj/structure/kitchenspike, -/obj/machinery/light/small, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aJ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aK" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aL" = ( -/obj/machinery/door/airlock{ - name = "Mortuary backyard" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/mort) -"aM" = ( -/turf/simulated/wall, -/area/slavers_base/cells) -"aN" = ( -/obj/machinery/door/airlock{ - name = "Slaves mortuary" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"aO" = ( -/obj/structure/hygiene/toilet{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aP" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aQ" = ( -/obj/machinery/light/small/red{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aR" = ( -/obj/structure/mattress/dirty, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aS" = ( -/obj/structure/mattress/dirty, -/obj/item/chems/glass/rag, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"aU" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"aV" = ( -/obj/random/trash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aW" = ( -/obj/item/chems/glass/rag, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aX" = ( -/obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aY" = ( -/obj/item/chems/glass/rag, -/obj/random/trash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"aZ" = ( -/obj/structure/mattress/dirty, -/obj/item/chems/food/drinks/cans/waterbottle, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"ba" = ( -/obj/item/remains/human, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bb" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bc" = ( -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/obj/item/chems/glass/rag, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bd" = ( -/obj/structure/mattress/dirty, -/obj/item/trash/liquidfood, -/obj/effect/landmark/corpse/slavers_base/slave, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"be" = ( -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bf" = ( -/obj/item/chems/food/drinks/cans/waterbottle, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bg" = ( -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/obj/random/trash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bh" = ( -/obj/structure/mattress/dirty, -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bi" = ( -/obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bj" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan{ - d2 = 2; - icon_state = "0-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bk" = ( -/obj/machinery/door/window/brigdoor/southright, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bl" = ( -/obj/machinery/door/window/brigdoor/southright, -/obj/random/trash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bm" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bn" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bo" = ( -/obj/machinery/door/airlock{ - name = "Cell block B" - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bp" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bq" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"br" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bs" = ( -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bt" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bu" = ( -/obj/structure/mattress/dirty, -/obj/effect/landmark/corpse/slavers_base/slave, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bv" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bw" = ( -/obj/item/paper{ - info = "Tonight, when lights are out. Prepare shivs, pieces of glass, whatever you might find."; - name = "Note" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bx" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"by" = ( -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bz" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bA" = ( -/obj/random/trash, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bB" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/remains/human, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bC" = ( -/obj/machinery/light{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bD" = ( -/obj/random/shoes, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bE" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bF" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bG" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bH" = ( -/obj/machinery/door/window/brigdoor/northright, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bI" = ( -/obj/random/trash, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bJ" = ( -/obj/item/storage/bag/trash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bK" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bL" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bM" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bN" = ( -/obj/machinery/door/airlock{ - name = "Den B" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bO" = ( -/obj/machinery/light/small/red, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bP" = ( -/obj/machinery/light/small/red, -/obj/structure/mattress/dirty, -/obj/effect/landmark/corpse/slavers_base/slave, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bQ" = ( -/obj/structure/mattress/dirty, -/obj/random/junk, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"bR" = ( -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bS" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bU" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bV" = ( -/obj/random/trash, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bW" = ( -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/shotgun/beanbag{ - pixel_x = -8; - pixel_y = -4 - }, -/obj/item/ammo_casing/shotgun/beanbag{ - pixel_y = 5; - pixel_z = 7 - }, -/obj/item/ammo_casing/shotgun/beanbag, -/obj/item/ammo_casing/shotgun/beanbag, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bX" = ( -/obj/machinery/door/airlock{ - name = "Dens block" - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/landmark/corpse/slavers_base/slaver4, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"bZ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"ca" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cb" = ( -/obj/machinery/door/airlock{ - name = "Den A" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cc" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood, -/obj/structure/cable, -/obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cd" = ( -/obj/structure/hygiene/toilet{ - dir = 4 - }, -/obj/item/chems/food/snacks/liquidfood, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"ce" = ( -/obj/machinery/light/small/red{ - dir = 1 - }, -/obj/structure/mattress/dirty, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cf" = ( -/obj/structure/mattress/dirty, -/obj/random/snack, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cg" = ( -/obj/machinery/light/small/red{ - dir = 1 - }, -/obj/random/medical/lite, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"ch" = ( -/obj/structure/mattress/dirty, -/obj/item/remains/human, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"ci" = ( -/obj/random/junk, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cj" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"ck" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cl" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/item/flashlight, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cm" = ( -/turf/simulated/wall, -/area/slavers_base/hangar) -"cn" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/shotgun/beanbag, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"co" = ( -/obj/machinery/door/airlock{ - name = "Cell block A" - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cp" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cq" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cr" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cs" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"ct" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cu" = ( -/obj/machinery/door/blast/regular{ - id_tag = "service_hangar" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cv" = ( -/obj/effect/landmark/corpse/slavers_base/slave, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cw" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/shotgun/beanbag, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cx" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cy" = ( -/obj/random/medical/lite, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable, -/obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 4; - name = "Slavers holding area"; - pixel_x = 24 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/cells) -"cB" = ( -/obj/machinery/door/window/brigdoor/northright, -/obj/item/chems/glass/rag, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cC" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cD" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cE" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cF" = ( -/obj/item/paper, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cG" = ( -/obj/item/trash/liquidfood, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cH" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cI" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"cJ" = ( -/obj/item/paper{ - info = "Doc who checked us told implants won't explode our heads. Gotta make guys know. Seems I see a silver lining."; - name = "Note" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cK" = ( -/obj/machinery/light/small/red, -/obj/item/remains/human, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cL" = ( -/obj/random/snack, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cM" = ( -/obj/structure/mattress/dirty, -/obj/item/chems/food/drinks/cans/waterbottle, -/obj/random/junk, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cN" = ( -/obj/machinery/light/small/red, -/obj/random/trash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cO" = ( -/obj/structure/mattress/dirty, -/obj/item/chems/glass/rag, -/obj/item/chems/food/drinks/cans/waterbottle, -/obj/effect/landmark/corpse/slavers_base/slave, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cP" = ( -/obj/structure/hygiene/toilet{ - dir = 4 - }, -/obj/item/trash/liquidfood, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cQ" = ( -/obj/machinery/light/small/red, -/obj/structure/mattress/dirty, -/obj/item/chems/glass/rag, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/cells) -"cR" = ( -/turf/simulated/wall, -/area/slavers_base/powatm) -"cS" = ( -/turf/simulated/wall, -/area/slavers_base/secwing) -"cT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/door/airlock{ - name = "Slave hold hallway" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"cU" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/door/airlock{ - name = "Slave hold hallway" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"cV" = ( -/turf/simulated/wall, -/area/slavers_base/med) -"cW" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav7, -/turf/space, -/area/space) -"cX" = ( -/obj/machinery/atmospherics/unary/tank/air, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"cY" = ( -/obj/machinery/atmospherics/unary/tank/air, -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"cZ" = ( -/obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"da" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"db" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dc" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dd" = ( -/obj/structure/bed, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"de" = ( -/obj/structure/closet, -/obj/random/snack, -/obj/random/projectile, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"df" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"dg" = ( -/obj/structure/bed, -/obj/random/projectile, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"dh" = ( -/obj/structure/closet, -/obj/random/smokes, -/obj/random/masks, -/obj/random/suit, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"di" = ( -/obj/structure/table/rack, -/obj/item/flashlight, -/obj/random/medical/lite, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dj" = ( -/obj/structure/table/rack, -/obj/machinery/light{ - dir = 1 - }, -/obj/item/storage/box/handcuffs, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dk" = ( -/obj/structure/table/rack, -/obj/item/baton, -/obj/item/baton, -/obj/item/baton, -/obj/random/tool, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dl" = ( -/obj/structure/table/rack, -/obj/item/flash, -/obj/random/ammo, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dm" = ( -/obj/structure/table/rack, -/obj/item/storage/box/ammo/stunshells, -/obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dn" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"do" = ( -/obj/structure/cable{ - d2 = 6; - icon_state = "0-6" - }, -/obj/machinery/power/smes/buildable, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dp" = ( -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dq" = ( -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/machinery/power/smes/buildable, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dr" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"ds" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"dt" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"du" = ( -/obj/machinery/door/airlock{ - name = "Slave processing" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dv" = ( -/obj/machinery/flasher{ - id_tag = "permentryflash"; - name = "Floor mounted flash"; - pixel_x = 0 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dw" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 1; - name = "Medical room"; - pixel_x = 0; - pixel_y = 24 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dx" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dy" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/hygiene/shower{ - pixel_y = 30 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dA" = ( -/obj/machinery/door/airlock{ - name = "Storage" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dB" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"dC" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"dD" = ( -/obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"dE" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/item/chems/food/snacks/liquidfood, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"dF" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"dG" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dH" = ( -/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dI" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/yellow, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dJ" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 10 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dK" = ( -/obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"dL" = ( -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"dM" = ( -/obj/structure/cable/green{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dN" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dO" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dP" = ( -/obj/machinery/power/terminal{ - icon_state = "term"; - dir = 1 - }, -/obj/structure/cable/green{ - d2 = 4; - icon_state = "0-4" - }, -/obj/structure/cable/green{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dQ" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable{ - icon_state = "2-9" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dR" = ( -/obj/structure/table/steel, -/obj/item/storage/box/ammo/stunshells, -/obj/item/baton, -/obj/machinery/power/terminal{ - icon_state = "term"; - dir = 1 - }, -/obj/structure/cable/green{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"dS" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"dT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/shotgun/beanbag, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"dU" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"dV" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dW" = ( -/obj/effect/decal/cleanable/dirt, -/obj/random/junk, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dX" = ( -/obj/effect/decal/cleanable/dirt, -/obj/random/medical/lite, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dY" = ( -/obj/structure/bed, -/obj/item/remains/human, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"dZ" = ( -/obj/item/chems/food/snacks/liquidfood, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"ea" = ( -/obj/structure/closet/crate/trashcart, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"eb" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"ec" = ( -/obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"ed" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 6 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"ee" = ( -/obj/machinery/atmospherics/binary/pump{ - dir = 1; - name = "waste pump" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"ef" = ( -/obj/machinery/atmospherics/binary/pump, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eg" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eh" = ( -/obj/random/junk, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"ei" = ( -/obj/random/junk, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"ej" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"ek" = ( -/mob/living/simple_animal/hostile/abolition_extremist, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"el" = ( -/obj/effect/landmark/corpse/slavers_base/slaver6, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"em" = ( -/obj/random/junk, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"en" = ( -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eo" = ( -/obj/structure/bed/chair/office/dark{ - dir = 4 - }, -/obj/effect/decal/cleanable/blood, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"ep" = ( -/obj/structure/table/steel, -/obj/item/flash, -/obj/item/radio, -/obj/item/paper{ - info = "If this fuck from A-3 keeps thinking he's better then piece of meat, throw him to hangar and show how little pressure turns diamonds into shit."; - name = "Note" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eq" = ( -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"er" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"es" = ( -/obj/item/ammo_casing/shotgun/beanbag, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"et" = ( -/obj/structure/window/basic{ - dir = 1 - }, -/obj/item/clothing/gloves/latex, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eu" = ( -/obj/structure/window/basic{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/corpse/slavers_base/slaver5, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"ev" = ( -/obj/structure/window/basic{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"ew" = ( -/obj/structure/window/basic{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"ex" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/ammo_casing/shotgun/beanbag, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"ey" = ( -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"ez" = ( -/obj/structure/bed, -/obj/item/handcuffs, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eA" = ( -/obj/item/beartrap, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"eB" = ( -/obj/item/mop, -/obj/structure/mopbucket, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"eC" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"eD" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/light/small{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eE" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eF" = ( -/obj/random/tool, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eG" = ( -/obj/machinery/atmospherics/binary/pump{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eH" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eJ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eK" = ( -/obj/machinery/light/small{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"eL" = ( -/obj/structure/cable/green{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"eM" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"eN" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/door/airlock{ - name = "Slave hold hallway" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"eO" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eP" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eQ" = ( -/obj/machinery/computer/modular{ - name = "Cameras console" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eR" = ( -/obj/machinery/computer/modular{ - name = "Riot control console" - }, -/obj/machinery/power/apc{ - dir = 2; - name = "Slavers security wing"; - operating = 1; - pixel_y = -24 - }, -/obj/structure/cable, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eS" = ( -/obj/structure/table/steel, -/obj/item/handcuffs, -/turf/simulated/floor/tiled, -/area/slavers_base/secwing) -"eT" = ( -/obj/item/gun/projectile/shotgun/pump, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"eU" = ( -/obj/machinery/optable, -/obj/item/scalpel, -/obj/effect/decal/cleanable/blood, -/obj/machinery/light, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eV" = ( -/obj/structure/window/basic{ - dir = 4 - }, -/obj/structure/table/standard, -/obj/item/implanter, -/obj/item/implantcase/tracking, -/obj/item/surgicaldrill, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eW" = ( -/obj/machinery/optable, -/obj/effect/decal/cleanable/blood, -/obj/item/screwdriver, -/obj/machinery/light, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eX" = ( -/obj/structure/window/basic{ - dir = 4 - }, -/obj/structure/table/standard, -/obj/item/implantpad, -/obj/item/chems/pill/antibiotics, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eY" = ( -/obj/structure/table/standard, -/obj/item/storage/firstaid/empty, -/obj/item/handcuffs, -/obj/item/baton, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"eZ" = ( -/obj/structure/table/standard, -/obj/item/storage/firstaid/o2, -/obj/item/folder/cyan, -/obj/item/paper{ - info = "Seems they don't really look over my shoulder anymore. We have now maybe a dozen of them with inactive implants. Hope they will pick right moment to flip the lid. I'll kill few bastards myself soon as I have a chance."; - name = "Note" - }, -/obj/item/pen, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"fa" = ( -/obj/structure/table/standard, -/obj/item/storage/firstaid/regular, -/obj/item/hatchet, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"fb" = ( -/obj/item/roller, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"fc" = ( -/obj/structure/bed, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/med) -"fd" = ( -/obj/structure/table/standard, -/obj/item/storage/box/handcuffs, -/obj/item/storage/box/handcuffs, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"fe" = ( -/obj/structure/table/standard, -/obj/item/storage/box/bodybags, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"ff" = ( -/obj/structure/table/standard, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"fg" = ( -/obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/med) -"fh" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ - icon_state = "map"; - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"fi" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 9 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"fj" = ( -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 2; - name = "Slavers hangar"; - operating = 1; - pixel_y = -24 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"fk" = ( -/obj/machinery/light/small, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"fl" = ( -/obj/effect/decal/cleanable/generic, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4; - level = 2 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fm" = ( -/obj/effect/decal/cleanable/generic, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fn" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/door/airlock{ - name = "Slave hold hallway" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/secwing) -"fo" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fp" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"fq" = ( -/obj/machinery/door/airlock/external, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hangar) -"fr" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fs" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/green{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"ft" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/door/airlock{ - name = "Power/atmos" - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hallway) -"fu" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/green, -/obj/structure/cable/green{ - d2 = 8; - icon_state = "0-8" - }, -/obj/structure/cable/green{ - d2 = 2; - icon_state = "0-2" - }, -/obj/structure/cable/green{ - d2 = 4; - icon_state = "0-4" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fv" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fw" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/door/airlock{ - name = "West hallway" - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fx" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fy" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fz" = ( -/obj/machinery/door/airlock{ - name = "Transit area" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/maint) -"fA" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fB" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/power/terminal, -/obj/structure/cable/green{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fC" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/universal{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fF" = ( -/obj/machinery/atmospherics/binary/pump{ - dir = 4 - }, -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fG" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fH" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 9 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fI" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fJ" = ( -/turf/simulated/wall, -/area/slavers_base/maint) -"fK" = ( -/obj/machinery/atmospherics/unary/tank/carbon_dioxide, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fL" = ( -/obj/machinery/atmospherics/pipe/simple/visible/black{ - dir = 6 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fM" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow, -/obj/machinery/atmospherics/pipe/simple/visible/black{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fN" = ( -/obj/machinery/atmospherics/pipe/simple/visible/black{ - dir = 10 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fO" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fP" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fQ" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"fR" = ( -/obj/machinery/door/airlock{ - name = "Power/atmos" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/hallway) -"fS" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fT" = ( -/obj/item/wrench, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fU" = ( -/obj/machinery/light, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fV" = ( -/obj/machinery/door/airlock{ - name = "West hallway" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fW" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"fX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fY" = ( -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/machinery/power/smes/buildable, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"fZ" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"ga" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gb" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/black{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gc" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/black, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gd" = ( -/obj/machinery/atmospherics/pipe/simple/visible/black{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"ge" = ( -/obj/machinery/atmospherics/omni/filter{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gf" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; - dir = 4 - }, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gg" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gh" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 4; - name = "Slavers atmos and power room"; - pixel_x = 24 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gi" = ( -/turf/simulated/wall, -/area/slavers_base/dorms) -"gj" = ( -/obj/machinery/door/airlock{ - name = "Mess" - }, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gk" = ( -/obj/machinery/door/airlock{ - name = "Southern hallway" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"gl" = ( -/obj/machinery/door/airlock{ - name = "Southern hallway" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"gm" = ( -/obj/machinery/door/airlock{ - name = "Slave trade area" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gn" = ( -/obj/machinery/atmospherics/binary/pump, -/obj/machinery/light/small{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"go" = ( -/obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gp" = ( -/obj/item/crowbar, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gq" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gr" = ( -/obj/structure/table/steel, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/item/stock_parts/circuitboard/broken, -/obj/item/contraband/poster, -/obj/item/radio, -/obj/machinery/light/small{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gs" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"gt" = ( -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gu" = ( -/obj/machinery/vending/wallmed2{ - pixel_y = 30 - }, -/obj/structure/table/standard, -/obj/random/cash, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gv" = ( -/obj/structure/bed, -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gw" = ( -/obj/structure/closet, -/obj/random/smokes, -/obj/random/loot, -/obj/random/contraband, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gx" = ( -/obj/structure/table/standard, -/obj/random/coin, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gy" = ( -/obj/structure/bed, -/obj/random/plushie, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gz" = ( -/obj/structure/closet, -/obj/random/smokes, -/obj/random/loot, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gA" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gB" = ( -/obj/structure/closet, -/obj/random/loot, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gC" = ( -/obj/structure/table/standard, -/obj/random/contraband, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gD" = ( -/obj/structure/bed, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gE" = ( -/obj/structure/closet, -/obj/random/smokes, -/obj/random/cash, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gF" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"gG" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"gH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gI" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gJ" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gK" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gL" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gM" = ( -/obj/structure/table/steel, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/item/storage/toolbox/mechanical, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gN" = ( -/obj/random/junk, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"gO" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable, -/obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gP" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gQ" = ( -/obj/random/junk, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 2; - name = "Slavers Maintenance"; - operating = 1; - pixel_y = -24 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gR" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gS" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gT" = ( -/obj/machinery/door/airlock{ - name = "Exchange tunnel" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gU" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gV" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"gW" = ( -/obj/machinery/floodlight, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gX" = ( -/obj/structure/table/steel, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"gY" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"gZ" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"ha" = ( -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hb" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"hc" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"hd" = ( -/turf/simulated/wall, -/area/slavers_base/demo) -"he" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"hf" = ( -/obj/machinery/light/small{ - dir = 4; - pixel_y = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"hg" = ( -/obj/item/coilgun_assembly, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hh" = ( -/obj/random/junk, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hi" = ( -/obj/structure/table/steel, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hj" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hk" = ( -/obj/structure/table/standard, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hl" = ( -/obj/structure/bed, -/obj/item/radio, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hm" = ( -/obj/structure/closet, -/obj/random/projectile, -/obj/random/loot, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hn" = ( -/obj/structure/table/standard, -/obj/random/loot, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"ho" = ( -/obj/structure/table/standard, -/obj/random/gloves, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hp" = ( -/obj/structure/closet, -/obj/random/loot, -/obj/random/contraband, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hq" = ( -/obj/structure/closet, -/obj/random/projectile, -/obj/random/ammo, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hr" = ( -/obj/structure/safe, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"hs" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/structure/safe, -/obj/item/storage/bag/cash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"ht" = ( -/obj/structure/safe, -/obj/item/storage/bag/cash, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"hu" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hv" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hw" = ( -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hx" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hy" = ( -/obj/random/junk, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"hz" = ( -/obj/machinery/vending/engineering{ - req_access = list() - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hA" = ( -/obj/item/stock_parts/computer/card_slot, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hB" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hC" = ( -/obj/machinery/power/smes/buildable, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/door/airlock{ - name = "Slave hold hallway" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"hE" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"hF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"hG" = ( -/obj/machinery/door/airlock{ - name = "Safe room" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"hH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"hI" = ( -/obj/random/coin, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"hJ" = ( -/obj/machinery/door/airlock{ - name = "Cashier room" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"hK" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hL" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/obj/item/radio, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hM" = ( -/obj/structure/table/reinforced, -/obj/random/coin, -/obj/machinery/door/blast/regular/open{ - icon_state = "pdoor0"; - id_tag = "SC BD" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hN" = ( -/obj/structure/bed/chair/comfy/beige{ - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hO" = ( -/obj/structure/table/woodentable, -/obj/item/radio, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hP" = ( -/obj/structure/table/woodentable, -/obj/item/storage/secure/briefcase/money, -/obj/random/cash, -/obj/random/cash, -/obj/random/cash, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hQ" = ( -/obj/structure/bed/chair/comfy/beige{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"hR" = ( -/obj/machinery/power/terminal{ - icon_state = "term"; - dir = 1 - }, -/obj/structure/cable/green{ - d2 = 2; - icon_state = "0-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"hS" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hT" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hU" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hV" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/machinery/vending/dinnerware, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hW" = ( -/obj/machinery/cooker/oven, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hX" = ( -/obj/structure/table/standard, -/obj/machinery/microwave, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hY" = ( -/obj/structure/table/standard, -/obj/random/snack, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"hZ" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"ia" = ( -/obj/structure/table/standard, -/obj/machinery/light{ - dir = 1 - }, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"ib" = ( -/obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"ic" = ( -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"id" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"ie" = ( -/obj/structure/closet/secure_closet/guncabinet, -/obj/random/projectile, -/obj/random/projectile, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"if" = ( -/obj/structure/closet/secure_closet/guncabinet, -/obj/random/projectile, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"ig" = ( -/obj/random/coin, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"ih" = ( -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/demo) -"ii" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"ij" = ( -/obj/structure/table/woodentable, -/obj/item/storage/bag/cash, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"ik" = ( -/obj/structure/table/woodentable, -/obj/random/cash, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"il" = ( -/obj/structure/ore_box, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"im" = ( -/obj/structure/ore_box, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"in" = ( -/obj/structure/closet/crate, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"io" = ( -/obj/structure/closet/crate, -/obj/machinery/light/small, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"ip" = ( -/obj/structure/closet/crate, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"iq" = ( -/obj/machinery/power/port_gen/pacman/super, -/obj/structure/cable/green{ - d2 = 4; - icon_state = "0-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"ir" = ( -/obj/machinery/power/port_gen/pacman/super, -/obj/structure/cable/green{ - d2 = 4; - icon_state = "0-4" - }, -/obj/structure/cable/green{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"is" = ( -/obj/machinery/power/port_gen/pacman/super, -/obj/structure/cable/green{ - d2 = 4; - icon_state = "0-4" - }, -/obj/structure/cable/green{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/light/small, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"it" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/powatm) -"iu" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iv" = ( -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iw" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"ix" = ( -/obj/machinery/vending/snack, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iy" = ( -/obj/structure/table/woodentable, -/obj/item/paper{ - info = "
    Contract

    This contract describes exchanging of monetary pieces for the right o? the ownership for following examples: <*> Human, age 17. Price - 1500cr. <*> Human, age 49. Price - 1100cr. <*> Human, age 28. Good fist fighter. Price - 2400cr. <*> Human, age 34. Expirienced medic. Price - 6800cr. Overall price: 11800cr
    Place for signatures"; - name = "Contract" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iz" = ( -/obj/structure/table/woodentable, -/obj/random/coin, -/obj/item/pen, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iA" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iB" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iC" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iE" = ( -/mob/living/simple_animal/hostile/abolition_extremist, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iF" = ( -/obj/machinery/vending/fitness, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iG" = ( -/obj/random/junk, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"iH" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"iI" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iJ" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iK" = ( -/obj/item/clothing/suit/nun, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iL" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/item/clothing/suit/robe, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iM" = ( -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/machinery/power/apc{ - dir = 2; - name = "Slavers Dorms"; - operating = 1; - pixel_y = -24 - }, -/obj/structure/cable{ - icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iN" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iO" = ( -/obj/structure/table/standard, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/obj/item/chems/food/condiment/small/peppermill, -/obj/item/chems/food/condiment/small/saltshaker{ - pixel_x = 3; - pixel_y = 10 - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iP" = ( -/obj/structure/table/standard, -/obj/random/smokes, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iQ" = ( -/obj/structure/table/standard, -/obj/random/drinkbottle, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iR" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/fork, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iS" = ( -/obj/structure/table/standard, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iT" = ( -/obj/random/junk, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iU" = ( -/obj/item/kitchen/utensil/fork, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iV" = ( -/obj/machinery/vending/cola, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"iW" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"iX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"iY" = ( -/obj/machinery/door/airlock{ - name = "Scene" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"iZ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"ja" = ( -/obj/item/clothing/shoes/color/brown, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"jb" = ( -/obj/item/clothing/under/bluepyjamas, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"jc" = ( -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"jd" = ( -/obj/machinery/light, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"je" = ( -/obj/machinery/door/airlock{ - name = "Maintenance" - }, -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/dorms) -"jf" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/wall, -/area/slavers_base/dorms) -"jg" = ( -/obj/structure/table/standard, -/obj/random/projectile, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jh" = ( -/obj/structure/table/standard, -/obj/random/drinkbottle, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"ji" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/obj/random/snack, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jj" = ( -/obj/structure/table/standard, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jk" = ( -/obj/structure/table/standard, -/obj/random/smokes, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jl" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/vending/cigarette, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jm" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"jn" = ( -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"jo" = ( -/obj/machinery/door/airlock{ - name = "Private office" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"jp" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/dorms) -"jq" = ( -/obj/structure/table/standard, -/obj/item/radio, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/dorms) -"jr" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"js" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jt" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/power/apc{ - dir = 8; - name = "west bump"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"ju" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"jv" = ( -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jw" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jx" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jy" = ( -/obj/structure/cable/green, -/obj/machinery/power/terminal{ - dir = 4 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/dorms) -"jz" = ( -/obj/structure/cable, -/obj/machinery/power/smes/buildable, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/dorms) -"jA" = ( -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jB" = ( -/obj/machinery/light, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jC" = ( -/obj/item/paper{ - info = "We made over 200 grands for two last weeks. We should stay low-key for month or so, or we'll get our base discovered by fucking marshalls so shut your whining and relax, I'l l get you three crates of booze and some cargo to play with."; - name = "Note" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jD" = ( -/obj/random/snack, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jE" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/dorms) -"jF" = ( -/obj/machinery/door/airlock{ - name = "Mess" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"jG" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"jH" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"jI" = ( -/obj/structure/table/standard, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jJ" = ( -/obj/structure/table/standard, -/obj/item/megaphone, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jK" = ( -/obj/structure/table/standard, -/obj/item/clothing/mask/smokable/cigarette, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jL" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jM" = ( -/obj/structure/table/standard, -/obj/item/scanner/health, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jN" = ( -/obj/structure/table/standard, -/obj/random/drinkbottle, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jO" = ( -/obj/structure/table/standard, -/obj/item/pen, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jP" = ( -/obj/machinery/door/airlock{ - name = "Restroom" - }, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/dorms) -"jQ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/door/airlock{ - name = "Southern hallway" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"jR" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jS" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jT" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jU" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/obj/item/storage/secure/briefcase/money, -/obj/random/cash, -/obj/random/cash, -/obj/random/cash, -/obj/random/cash, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jV" = ( -/obj/structure/bed/chair{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jW" = ( -/obj/structure/table/standard, -/obj/item/clothing/mask/smokable/cigarette/professionals, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"jX" = ( -/obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/white/airless, -/area/slavers_base/dorms) -"jY" = ( -/obj/machinery/door/airlock{ - name = "Shower" - }, -/turf/simulated/floor/tiled/white/airless, -/area/slavers_base/dorms) -"jZ" = ( -/obj/effect/landmark/corpse/slavers_base/slaver3, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"ka" = ( -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"kb" = ( -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"kc" = ( -/obj/effect/landmark/corpse/slavers_base/slaver1, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"kd" = ( -/obj/machinery/door/airlock{ - name = "Toilet" - }, -/turf/simulated/floor/tiled/white/airless, -/area/slavers_base/dorms) -"ke" = ( -/obj/structure/hygiene/toilet{ - dir = 8 - }, -/obj/random/junk, -/turf/simulated/floor/tiled/white/airless, -/area/slavers_base/dorms) -"kf" = ( -/turf/simulated/wall, -/area/slavers_base/hallway) -"kg" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"kh" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"ki" = ( -/obj/machinery/door/airlock{ - name = "Slave trade area" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"kj" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kk" = ( -/mob/living/simple_animal/hostile/abolition_extremist, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kl" = ( -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"km" = ( -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kn" = ( -/obj/machinery/light{ - dir = 8 - }, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"ko" = ( -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"kp" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"kq" = ( -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"kr" = ( -/obj/machinery/door/airlock{ - name = "Slave trade area" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/demo) -"ks" = ( -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/machinery/power/apc{ - dir = 2; - name = "south bump"; - operating = 1; - pixel_y = -24 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kt" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"ku" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kv" = ( -/obj/structure/table/standard, -/obj/item/storage/box/glass_extras, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kw" = ( -/obj/structure/table/standard, -/obj/machinery/chemical_dispenser/bar_alc, -/turf/simulated/floor/tiled, -/area/slavers_base/demo) -"kz" = ( -/mob/living/simple_animal/hostile/abolition_extremist, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"kA" = ( -/obj/machinery/door/airlock{ - name = "Customers entry" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"kB" = ( -/obj/machinery/door/airlock{ - name = "Customers entry" - }, -/turf/simulated/floor/tiled/airless, -/area/slavers_base/hallway) -"kC" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kE" = ( -/obj/machinery/door/airlock{ - name = "Exchange area" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kF" = ( -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kG" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kH" = ( -/obj/machinery/light/small{ - dir = 8 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kI" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kJ" = ( -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kK" = ( -/obj/machinery/door/airlock{ - name = "Exchange point" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kL" = ( -/obj/machinery/atmospherics/binary/pump, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kM" = ( -/obj/structure/table/standard, -/obj/item/radio, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kN" = ( -/obj/structure/table/standard, -/obj/random/handgun, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kO" = ( -/obj/machinery/door/airlock/external, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kP" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kQ" = ( -/obj/structure/table/standard, -/obj/random/junk, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kR" = ( -/obj/structure/bed/chair{ - dir = 1 - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kS" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kT" = ( -/obj/structure/table/standard, -/obj/random/loot, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kU" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 1; - id_tag = "solar_port_pump" - }, -/turf/simulated/floor/airless/ceiling, -/area/slavers_base/maint) -"kV" = ( -/obj/machinery/door/airlock/external, -/turf/space, -/area/slavers_base/maint) -"kW" = ( -/obj/effect/overmap/visitable/sector/slavers_base, -/turf/space, -/area/space) -"kX" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav5, -/turf/space, -/area/space) -"kY" = ( -/obj/effect/shuttle_landmark/nav_slavers_base/nav6, -/turf/space, -/area/space) -"lb" = ( -/obj/structure/hygiene/sink{ - pixel_y = -20 - }, -/obj/item/storage/mirror{ - pixel_y = -35 - }, -/obj/effect/landmark/corpse/slavers_base/slaver2, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) -"mb" = ( -/obj/structure/hygiene/sink{ - pixel_y = -20 - }, -/obj/item/storage/mirror{ - pixel_y = -35 - }, -/turf/simulated/floor/tiled/white, -/area/slavers_base/dorms) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(15,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(16,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(17,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(18,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(19,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -aa -ad -ad -aa -aa -aa -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ai -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(34,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(35,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(36,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(37,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(38,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(39,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(40,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(41,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(42,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(43,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -kX -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(44,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(45,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(46,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(47,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(48,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(49,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(50,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(51,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(52,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cX -dG -ee -eD -da -da -fK -gb -gn -gL -gW -gW -hz -da -il -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(53,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cX -dH -ef -eE -da -da -fK -gc -go -go -da -da -da -da -im -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(54,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cX -dI -da -da -da -da -da -gd -da -go -da -hg -da -da -in -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(55,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cY -dI -da -eF -da -da -fL -gc -da -da -da -da -da -da -io -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(56,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cZ -dJ -eg -dG -eg -eg -fM -ge -gp -da -da -da -hA -da -ip -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(57,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -da -da -cZ -eG -da -da -fN -ge -da -eF -da -hh -da -da -iq -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(58,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -cZ -cZ -da -eH -da -da -da -gd -da -da -da -da -da -da -ir -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(59,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -db -cZ -da -eI -fl -da -fO -gf -da -da -eF -da -da -da -is -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(60,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -dc -dK -da -eJ -fm -fr -fP -gg -gq -gq -gq -gq -hB -da -ir -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(61,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cR -dc -da -dK -eK -da -fs -fQ -gh -gr -gM -gX -hi -hC -hR -it -cR -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(62,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ah -ah -ah -ah -ah -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -cS -cS -cS -cS -cS -cS -ft -fR -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(63,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -aj -aj -ak -ak -ak -aM -aO -aX -bi -aP -aP -aP -aP -aM -bR -aM -aP -aP -aP -aP -bi -aX -aO -cS -dd -dL -dL -eL -fn -fu -fS -gj -gs -gs -gY -gs -gs -hS -iu -iA -iu -je -jp -jy -gi -jX -gi -jX -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(64,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -aj -ak -ak -aM -aP -aP -aP -aR -aV -aP -aP -aM -aU -aM -aW -aZ -aP -cv -ba -aW -aP -cS -de -dL -eh -eM -cS -fv -fo -gi -gi -gi -gi -gi -gi -hT -ic -ic -iM -jf -jq -jz -gi -jY -gi -jY -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(65,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -ak -aj -ak -aM -aP -aY -aW -be -aP -aR -aW -bK -aU -bK -aP -aP -aP -be -aP -aP -cJ -cS -df -dL -dL -eM -cS -fv -fo -gi -gt -gt -gZ -hj -hD -hU -iv -ic -iN -gi -gi -gi -gi -jZ -kn -kb -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(66,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -al -aj -ak -ak -aF -aM -aQ -aP -aR -aP -aP -aP -aP -bL -bS -ca -aP -aP -aP -ch -aP -aP -bO -cS -dg -dL -ei -eM -cS -fv -fT -gi -gu -gt -gt -hk -gi -hT -ic -ic -iN -ic -ic -jA -jP -ka -kb -lb -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(67,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -ax -ak -ak -aM -aP -aP -ba -aP -aW -aP -aP -bM -bq -bM -aP -aP -aP -aP -aP -cv -aP -cS -dh -dL -dL -eM -cS -fv -fU -gi -gv -gt -gt -hl -gi -hV -ic -iv -iN -ic -ic -jB -gi -kb -kb -mb -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(68,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -ak -ak -aB -aM -aP -aZ -aP -aV -aW -aP -aP -aM -bq -aM -aP -aR -aV -aV -aP -cF -aP -cS -cS -cS -cS -eN -cS -fv -fo -gi -gw -gN -gt -hm -gi -hW -iw -iB -iO -jg -jr -ic -gi -kc -ko -kz -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(69,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -an -an -ak -ak -aM -aP -aP -aR -aP -bu -aP -aP -bK -bq -bK -aP -aP -aP -aP -aP -aP -bf -cS -di -dM -ej -eO -cS -fv -fo -gi -gx -gt -gt -hn -gi -hX -ic -iC -iP -jh -jr -ic -gi -kd -gi -kd -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(70,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -am -an -ak -ak -aB -aM -aP -aP -aP -be -aP -aP -aP -bL -bT -ca -aP -aP -aP -be -aP -aR -aP -cS -dj -dN -ek -eP -cS -fv -fo -gi -gy -gt -ha -gD -gi -hX -ic -iC -iQ -ji -jr -ic -gi -ke -gi -ke -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(71,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -an -ak -ak -aB -ak -aM -aP -aP -aP -aP -aV -aW -ba -bM -bU -bM -ci -aP -aW -ci -aP -aP -aP -cS -dk -dN -dp -dp -cS -fv -fo -gi -gz -gt -gt -gz -gi -hY -ic -iC -iR -jj -jr -ic -gi -gi -gi -gi -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(72,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -ay -aC -ay -aM -aR -aP -ba -aR -aP -aP -aP -aM -bq -aM -aP -aP -aP -aP -aP -aP -aP -cS -dl -dO -el -dp -cS -fv -fo -gi -gA -gt -gt -ho -gi -hZ -ic -iD -iS -jk -jr -ic -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(73,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ao -ak -ak -ay -aG -aM -aS -aP -aP -aP -aV -aP -aP -bK -bq -bK -aP -aP -ch -aP -ch -ch -aP -cS -dm -dN -em -dp -cS -fv -fU -gi -gv -gt -gN -gD -gi -ia -ic -ic -iN -ic -ic -jB -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(74,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ap -ak -az -ak -aH -aM -aS -aP -aP -aP -bv -aP -aP -bL -bV -ca -aP -aP -aP -aP -cy -aP -aP -cS -dn -dN -en -dp -cS -fv -fo -gi -gB -gt -gt -hp -gi -ib -ic -ic -iT -iv -ic -jC -gi -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(75,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -aq -ak -ak -ak -aI -aM -aQ -ba -aP -be -aP -bD -aP -bM -bq -bM -aP -aV -aP -be -bJ -aP -cK -cS -do -dP -en -eQ -cS -fv -fo -gi -gC -gt -gN -gA -gi -ib -ic -iE -iN -ic -ic -ic -gi -ad -ad -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(76,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ar -ak -ak -aC -aH -aM -aP -aP -aP -aP -bw -aP -aP -aM -bq -aM -aR -aP -aR -aP -aP -cG -cL -cS -dp -dQ -eo -eR -cS -fv -fo -gi -gD -gt -gt -gy -gi -ic -ic -ic -iU -iv -ic -jD -gi -ad -ad -fJ -gI -gI -kH -gI -kO -kH -gI -kV -ag -ag -ag -ag -ag -ag -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(77,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -ak -ak -ak -aM -aP -aP -aR -aP -aP -bE -bI -bN -bW -cb -cj -ck -aP -aP -aW -aP -bv -cS -dq -dR -ep -eS -cS -fv -fo -gi -gE -gt -gt -hq -gi -ic -ix -iF -iV -jl -js -jE -gi -ad -ad -fJ -kC -kG -kI -kL -kP -kS -kU -kV -ag -ag -ag -ag -ag -ag -kW -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(78,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -ak -ak -ak -aD -aJ -aM -aM -aM -aM -aM -aM -aM -aM -aM -bX -aM -aM -aM -aM -aM -aM -aM -aM -cS -dr -dS -eq -eq -cS -fw -fV -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -gi -jF -gi -kf -kf -fJ -fC -gI -fJ -fJ -fJ -fJ -fJ -fJ -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(79,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ah -as -au -aA -aE -aK -aN -aT -bb -bb -bm -bb -bF -bb -bb -bY -cc -bb -cl -bm -cw -cz -bb -bb -cT -ds -dT -er -er -er -fx -fW -gk -gF -er -hb -er -er -er -er -hb -er -er -jt -jG -jQ -kg -kp -kA -kD -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(80,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -ah -ah -ah -ah -ah -aL -aM -aU -aU -aU -bn -bx -bx -bx -bx -bZ -bx -bx -bx -cn -bx -cA -bx -bx -cU -dt -dU -es -eT -fo -fy -fo -gl -gG -fo -fo -fo -fo -id -fo -iG -fo -fo -ju -jH -gl -kh -kq -kB -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(81,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -ag -ag -ag -ag -aM -aM -aM -aM -bo -by -aM -aM -aM -aM -aM -aM -aM -co -cx -aM -aM -aM -cV -du -cV -cV -cV -cV -fz -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -hd -hd -hd -hd -ki -kr -hd -kE -kE -fJ -fJ -fJ -fJ -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(82,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -at -at -ag -ag -aM -aO -aV -bj -bp -bz -bG -aW -aO -aM -cd -aP -bj -cp -bz -bG -aP -aO -cV -dv -dV -et -eU -cV -fA -fX -gm -gH -gO -hc -gH -hE -gH -gH -iH -iW -hd -jv -jv -jR -kj -ks -hd -gI -gI -kJ -kM -kQ -kT -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(83,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -at -ag -ag -av -ag -aM -aQ -bc -bk -bq -aU -bH -be -bO -aM -ce -be -bk -bq -aU -cB -be -bO -cV -dw -dx -eu -eV -cV -fB -fY -fJ -gI -gP -gI -gI -hF -gI -gI -gI -iX -hd -jv -jv -jv -jv -kt -hd -gJ -gI -kJ -kN -kR -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(84,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -ag -ag -ag -ag -ag -ag -ag -aM -aP -bd -bj -br -bx -bG -aR -aP -aM -aP -aP -bj -cq -bx -bG -aP -cM -cV -dx -dx -ev -eW -cV -fC -fZ -fJ -gI -gQ -hd -hd -hG -hd -hd -hd -iY -hd -jw -jv -jv -jv -kt -hd -gI -gI -kJ -gI -hf -kF -fJ -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(85,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -ag -ag -ag -at -ag -ag -ag -aM -aM -aM -aM -bs -aU -aM -aM -aM -aM -aM -aM -aM -bs -aU -aM -aM -aM -cV -dy -dx -ew -eX -cV -fC -fZ -fJ -gI -gR -hd -hr -hH -ie -hd -iI -iZ -jm -jx -jI -jS -jx -ku -hd -kE -kE -fJ -gI -fJ -fJ -fJ -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(86,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -ag -ag -ag -ag -aM -aO -aP -bj -br -bA -bG -bJ -aO -aM -aO -ch -bj -cq -bx -bG -aP -aO -cV -dz -dx -dx -eY -cV -fD -fZ -fJ -gJ -gR -hd -hs -hH -if -hd -iJ -ja -jn -jv -jJ -jT -kk -jv -hd -gI -gI -kK -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(87,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -av -ag -ag -ag -aM -aQ -be -bk -bq -aU -bH -be -bP -aM -aQ -be -bk -bq -aU -bH -be -cN -cV -dz -dW -ex -eZ -cV -fC -fZ -fJ -gI -gR -hd -hr -hH -ig -hd -iI -jb -jn -jv -jK -jT -jv -jv -hd -kF -gI -fJ -fJ -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(88,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -ag -ag -ag -aM -aV -bf -bj -br -bx -bG -aV -aW -aM -aP -aP -bj -cq -bx -bG -ch -aW -cV -dx -dX -dx -fa -cV -fC -fZ -fJ -gI -gR -hd -hr -hI -ig -hd -iK -iI -jn -jv -jL -jT -kl -jv -hd -gI -kF -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(89,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -ag -ag -ag -ag -ag -aM -aM -aM -aM -bs -bB -aM -aM -aM -aM -aM -aM -aM -bs -aU -aM -aM -aM -cV -dx -dx -ey -fb -cV -fC -fZ -fJ -gI -gR -hd -ht -hH -ih -hd -iI -iI -jn -jv -jM -jT -jv -jv -hd -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(90,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -ag -ag -aM -aO -aP -bj -br -bx -bG -aP -aO -aM -aO -aP -bj -cq -bx -bG -aP -aO -cV -dx -dY -ez -fc -cV -fC -fZ -fJ -gI -gR -hd -hd -hJ -hd -hd -iI -iI -jn -jv -jL -jT -jv -jv -hd -gI -kF -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(91,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -ag -ag -aM -aQ -bg -bk -bq -aU -bH -be -bO -aM -aQ -be -bk -bq -aU -bH -be -bO -cV -dA -cV -cV -cV -cV -fD -fZ -fJ -gK -gR -hd -hu -hK -ii -hd -iL -iI -jn -jv -jN -jT -jv -jv -hd -gJ -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(92,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -ag -ag -aw -ag -aM -aR -aP -bj -br -bx -bG -aP -bQ -aM -cf -aP -bj -cq -bx -bG -aP -cO -cV -dB -dB -eA -fd -cV -fC -fZ -fJ -gI -gR -hd -hv -hL -hw -hd -iI -iI -jn -jv -jO -jU -jv -jv -hd -hy -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(93,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -ag -ag -ag -ag -ag -aM -aM -aM -aM -bs -aU -aM -aM -aM -aM -aM -aM -aM -bs -aU -aM -aM -aM -cV -dC -dB -dB -fe -cV -fC -fZ -fJ -gI -gS -hd -hd -hM -hd -hd -hd -hd -hd -jw -jv -jv -jv -jv -hd -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(94,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -aw -ag -ag -ag -aM -aO -aP -bj -br -bx -bG -aV -aO -aM -aO -aP -bj -cq -bx -bG -aP -cP -cV -dD -dB -dB -ff -cV -fC -fZ -fJ -gI -gR -hd -hw -hw -hw -hw -hw -hw -hd -jv -jv -jv -jv -jv -hd -kF -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(95,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -af -ag -ag -ag -aM -aQ -bh -bl -bq -aU -bH -be -bO -aM -cg -be -bk -bq -aU -bH -be -cQ -cV -dE -dZ -dB -dB -cV -fE -fZ -fJ -gI -gR -hd -hw -hN -hN -hN -hw -jc -hd -jv -jv -jV -jV -jV -hd -kF -hy -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(96,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -af -ag -ag -aM -aW -aW -bj -bt -bC -bG -aW -aR -aM -ch -bf -bj -cr -bC -bG -aP -aV -cV -dF -ea -eB -fg -cV -fF -fZ -fJ -gJ -gR -hd -hx -hO -ij -iy -hw -jd -hd -jv -jv -jW -jN -jL -hd -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(97,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -af -af -af -af -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -aM -cV -cV -cV -cV -cV -cV -fG -fZ -fJ -gI -gR -hd -hw -hP -ik -iz -hw -hw -hd -jv -jv -jL -jv -jv -hd -gK -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(98,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cs -cs -cs -cs -cs -cs -eC -fh -fp -fH -fZ -fJ -gI -gR -hd -hw -hQ -hQ -hQ -hw -hw -hd -jv -jv -jN -jv -kv -hd -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -kY -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(99,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cs -cs -cs -cs -cs -cs -eC -fi -fq -fI -ga -fJ -gI -gR -hd -hw -hw -hw -hw -hw -hw -jo -jv -jv -jv -km -kw -hd -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(100,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cC -cH -cH -cH -cH -eb -cs -fj -cm -fJ -fJ -fJ -fJ -gT -hd -hd -hd -hd -hd -hd -hd -hd -hd -hd -hd -hd -hd -hd -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(101,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -ct -cs -cD -cs -cs -cs -cs -ec -cs -fk -cm -ad -ad -fJ -gI -gU -he -gI -gI -hy -gI -gI -gI -gI -gI -gI -gI -gI -gI -gI -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(102,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -fJ -gI -gV -hf -hy -gI -gI -gI -gI -gI -hf -gI -gI -gI -hy -gI -hf -gI -gI -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(103,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -fJ -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(104,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(105,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(106,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(107,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(108,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cD -cs -cs -cs -cs -ec -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(109,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -ct -cs -cD -cs -cs -cs -cs -ec -cs -fk -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(110,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cE -cI -cI -cI -cI -ed -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(111,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cs -cs -cs -cs -cs -cs -cs -cs -cs -cs -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(112,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -cm -cu -cu -cu -cu -cu -cu -cu -cu -cu -cu -cm -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(113,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(114,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(115,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(116,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(117,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(118,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(119,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(120,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(121,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(122,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(123,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(124,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(125,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(126,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(127,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(128,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(129,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(130,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(131,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(132,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(133,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -ad -ad -aa -aa -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(134,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(135,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(136,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(137,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(138,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(139,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(140,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(141,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(142,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(143,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(144,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(145,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -ad -ad -ad -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(146,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -ad -ad -ad -aa -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(147,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(148,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ae -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(149,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(150,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -ad -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(151,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -ad -ad -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(152,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(153,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(154,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(155,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(156,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(157,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(158,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(159,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(160,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(161,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(162,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(163,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(164,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -cW -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(165,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(166,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(167,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(168,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(169,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(170,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(171,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(172,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(173,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(174,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(175,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(176,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(177,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(178,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(179,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(180,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(181,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(182,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(183,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(184,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(185,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(186,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(187,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(188,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(189,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(190,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(191,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(192,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(193,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(194,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(195,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(196,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(197,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(198,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(199,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(200,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} diff --git a/maps/away/slavers/slavers_base_areas.dm b/maps/away/slavers/slavers_base_areas.dm deleted file mode 100644 index 4a741f6f6e8e..000000000000 --- a/maps/away/slavers/slavers_base_areas.dm +++ /dev/null @@ -1,42 +0,0 @@ -/area/slavers_base - icon = 'maps/away/slavers/slavers_base_sprites.dmi' - -/area/slavers_base/maint - name = "\improper Slavers Base Maintenance" - icon_state = "maint" - -/area/slavers_base/dorms - name = "\improper Slavers Dorms" - icon_state = "dorms" - -/area/slavers_base/secwing - name = "\improper Slavers Base Security Wing" - icon_state = "secwing" - -/area/slavers_base/mort - name = "\improper Slaves Mortuary" - icon_state = "mort" - -/area/slavers_base/cells - name = "\improper Slaves Cells" - icon_state = "cells" - -/area/slavers_base/hallway - name = "\improper Slavers Base Hallways" - icon_state = "hallway" - -/area/slavers_base/med - name = "\improper Slaves Medical Examination Room" - icon_state = "med" - -/area/slavers_base/demo - name = "\improper Slaves Demonstration room" - icon_state = "demo" - -/area/slavers_base/powatm - name = "\improper Slavers Base power and atmos room" - icon_state = "powatm" - -/area/slavers_base/hangar - name = "\improper Slavers Base Hangar" - icon_state = "hangar" \ No newline at end of file diff --git a/maps/away/slavers/slavers_base_sprites.dmi b/maps/away/slavers/slavers_base_sprites.dmi deleted file mode 100644 index 8a18880985db..000000000000 Binary files a/maps/away/slavers/slavers_base_sprites.dmi and /dev/null differ diff --git a/maps/away/smugglers/smugglers.dm b/maps/away/smugglers/smugglers.dm index 9432a5dd9544..7a2f7c45c49e 100644 --- a/maps/away/smugglers/smugglers.dm +++ b/maps/away/smugglers/smugglers.dm @@ -4,8 +4,6 @@ name = "asteroid station" desc = "A small station built into an asteroid. No radio traffic detected." icon_state = "object" - known = 0 - initial_generic_waypoints = list( "nav_smugglers", "nav_smugglers_antag" @@ -13,11 +11,10 @@ /datum/map_template/ruin/away_site/smugglers name = "Smugglers' Base" - id = "awaysite_smugglers" description = "Yarr." suffixes = list("smugglers/smugglers.dmm") cost = 1 - generate_mining_by_z = 1 + level_data_type = /datum/level_data/mining_level area_usage_test_exempted_root_areas = list(/area/smugglers) apc_test_exempt_areas = list( /area/smugglers/base = NO_SCRUBBER|NO_VENT, @@ -40,7 +37,7 @@ /obj/item/paper/smug_2 name = "suspicious note" - info = "That vox fuckface will be curious about what we got from that mine storage last week." + info = "That scaly fuckface will be curious about what we got from that mine storage last week." /obj/item/paper/smug_3 name = "suspicious note" @@ -72,7 +69,7 @@ new /datum/atom_creator/simple(/obj/item/chems/syringe, 50), new /datum/atom_creator/simple(/obj/item/chems/syringe/steroid, 10), new /datum/atom_creator/simple(/obj/item/chems/syringe/steroid, 10), - new /datum/atom_creator/weighted(list(/obj/item/chems/food/drinks/cans/cola, /obj/item/chems/food/drinks/cans/waterbottle, /obj/item/chems/food/drinks/cans/dr_gibb)), + new /datum/atom_creator/weighted(list(/obj/item/chems/drinks/cans/cola, /obj/item/chems/drinks/cans/waterbottle, /obj/item/chems/drinks/cans/dr_gibb)), new /datum/atom_creator/simple(/obj/item/clothing/glasses/eyepatch, 30), new /datum/atom_creator/simple(/obj/item/clothing/gloves/thick/duty, 80), new /datum/atom_creator/simple(/obj/item/clothing/mask/balaclava/tactical, 30)) @@ -80,11 +77,11 @@ /obj/random/ore name = "random ore" desc = "This is a random ore." - icon = 'icons/obj/clothing/obj_accessories.dmi' - icon_state = "horribletie" + icon_state = "lump" + icon = 'icons/obj/materials/ore.dmi' /obj/random/ore_smug/spawn_choices() - return subtypesof(/obj/item/ore) + return subtypesof(/obj/item/stack/material/ore) /obj/random/ammo_magazine_smug name = "Random Ammo Magazine" @@ -93,11 +90,13 @@ icon_state = "magnum" /obj/random/ammo_magazine_smug/spawn_choices() - return list( + var/static/list/spawnable_choices = list( /obj/item/ammo_magazine/pistol, /obj/item/ammo_magazine/speedloader, /obj/item/ammo_magazine/rifle, - /obj/item/ammo_magazine/rifle) + /obj/item/ammo_magazine/rifle + ) + return spawnable_choices /obj/structure/closet/crate/plastic_smug_ammo name = "dirty plastic crate" diff --git a/maps/away/smugglers/smugglers.dmm b/maps/away/smugglers/smugglers.dmm index 2d27d5f3fd7e..7e219ab638e8 100644 --- a/maps/away/smugglers/smugglers.dmm +++ b/maps/away/smugglers/smugglers.dmm @@ -3,7 +3,7 @@ /turf/space, /area/space) "ab" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "ac" = ( /turf/unsimulated/mask, @@ -17,17 +17,14 @@ /turf/space, /area/space) "af" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/smugglers/base) "ag" = ( -/obj/machinery/door/airlock/external{ - icon_state = "door_closed"; - locked = 0 - }, -/turf/simulated/floor, +/obj/machinery/door/airlock/external, +/turf/floor, /area/smugglers/base) "ah" = ( -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/space) "aj" = ( /obj/item/ammo_casing/pistol/magnum{ @@ -35,28 +32,28 @@ pixel_y = 5 }, /obj/item/ammo_casing/pistol/magnum, -/obj/item/shovel{ +/obj/item/tool/shovel{ pixel_x = 10; pixel_y = -5 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "ak" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "al" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/smugglers/base) "am" = ( /obj/machinery/airlock_sensor{ id_tag = "asteroid_base_dock_airlock"; - pixel_x = 25 + pixel_x = 25; + dir = 8 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; id_tag = "asteroid_base_dock_pump" }, /obj/effect/floor_decal/industrial/warning/full, @@ -65,7 +62,7 @@ deployed = 1; icon_state = "beartrap1" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "an" = ( /turf/unsimulated/mask, @@ -78,24 +75,22 @@ injecting = 1; use_power = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aq" = ( /obj/machinery/door/airlock/external{ - icon_state = "door_closed"; - locked = 0; name = "Internal Airlock" }, -/turf/simulated/floor, +/obj/machinery/atmospherics/pipe/simple/visible/black, +/turf/floor, /area/smugglers/base) "ar" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/smugglers/base) "au" = ( /obj/item/flashlight/flare/glowstick/yellow{ @@ -103,17 +98,17 @@ pixel_y = 7 }, /obj/item/flashlight/flare/glowstick/yellow, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "av" = ( /obj/effect/decal/cleanable/blood/drip, -/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ +/obj/machinery/embedded_controller/radio/airlock/docking_port{ id_tag = "asteroid_base_dock_airlock"; - name = "Dock Airlock Controller"; pixel_x = -25; tag_airpump = "asteroid_base_dock_pump"; tag_exterior_door = "asteroid_base_dock_outer"; - tag_interior_door = "asteroid_base_dock_inner" + tag_interior_door = "asteroid_base_dock_inner"; + dir = 4 }, /obj/machinery/button/access/interior{ id_tag = "asteroid_base_dock_airlock"; @@ -125,60 +120,50 @@ /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 5 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aw" = ( /obj/machinery/portable_atmospherics/canister/air, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "ax" = ( /obj/machinery/floodlight, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "ay" = ( /obj/item/stack/cable_coil{ pixel_x = 5; - pixel_y = 5; - pixel_z = 0 + pixel_y = 5 }, /obj/item/stack/cable_coil, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "az" = ( -/obj/machinery/power/port_gen/pacman, +/obj/machinery/port_gen/pacman, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/machinery/atmospherics/pipe/simple/visible/black{ - dir = 4 + icon_state = "0-2" }, -/turf/simulated/floor, -/area/smugglers/base) -"aA" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aB" = ( /obj/machinery/atmospherics/portables_connector{ @@ -189,57 +174,47 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aC" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aD" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black{ - icon_state = "map"; dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aE" = ( /obj/machinery/door/airlock/maintenance, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aF" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aG" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aH" = ( /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ @@ -259,7 +234,7 @@ /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aI" = ( /obj/machinery/door/airlock/external{ @@ -271,7 +246,7 @@ /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aJ" = ( /obj/item/beartrap{ @@ -281,14 +256,15 @@ }, /obj/machinery/airlock_sensor{ id_tag = "asteroid_base_east_airlock"; - pixel_y = -25 + pixel_y = -25; + dir = 1 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "asteroid_base_east_pump" }, /obj/effect/floor_decal/industrial/warning/full, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aK" = ( /obj/machinery/door/airlock/external{ @@ -296,7 +272,7 @@ id_tag = "asteroid_base_east_outer"; locked = 1 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aL" = ( /obj/machinery/button/access/exterior{ @@ -305,87 +281,67 @@ pixel_x = -25; pixel_y = 25 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "aM" = ( /obj/random/trash, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "aN" = ( /obj/machinery/light/small{ dir = 8 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aO" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aP" = ( /obj/effect/decal/cleanable/blood/drip, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/item/wirecutters, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aQ" = ( /obj/structure/cable, /obj/structure/cable{ - d1 = 32; - d2 = 4; icon_state = "32-4" }, /obj/structure/cable{ - icon_state = "0-2"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-2" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aR" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aS" = ( /obj/effect/decal/cleanable/blood/drip, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aT" = ( /obj/machinery/light/small{ @@ -393,110 +349,100 @@ pixel_y = 8 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aU" = ( -/turf/simulated/wall, +/turf/wall, /area/smugglers/base) "aV" = ( /obj/machinery/light/small/red{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aW" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor, /area/smugglers/base) "aX" = ( -/obj/structure/table/rack{ - dir = 8; - +/obj/structure/rack{ + dir = 8 }, /obj/item/clothing/mask/breath, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aY" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "aZ" = ( /obj/random/trash, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "ba" = ( /obj/structure/closet/crate/plastic_smug_ammo, /obj/effect/floor_decal/industrial/warning{ dir = 9 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bb" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/item/paper/smug_1, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bc" = ( /obj/random/ore_smug, /obj/effect/floor_decal/industrial/warning{ dir = 5 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bd" = ( -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "be" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bf" = ( -/obj/structure/table/rack{ - dir = 8; - +/obj/structure/rack{ + dir = 8 }, /obj/item/tank/air{ pixel_x = 5 }, /obj/item/tank/air, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bg" = ( -/obj/item/pickaxe/xeno/hand{ +/obj/item/tool/xeno/hand{ pixel_x = -15 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "bh" = ( /obj/effect/floor_decal/industrial/warning{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bi" = ( /obj/structure/closet/crate/plastic_smug_weapons, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bj" = ( /obj/structure/closet/crate/plastic, @@ -506,55 +452,52 @@ /obj/random/smokes, /obj/random/smokes, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bk" = ( /obj/machinery/floodlight, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bl" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/light/small/red, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bm" = ( -/obj/structure/table/rack{ - dir = 8; - +/obj/structure/rack{ + dir = 8 }, /obj/random/voidsuit, /obj/random/voidhelmet, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bn" = ( /obj/structure/boulder, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "bo" = ( -/obj/item/ore/silver, -/obj/item/ore/silver{ +/obj/item/stack/material/ore/silver, +/obj/item/stack/material/ore/silver{ pixel_x = 10; pixel_y = -5 }, -/turf/simulated/floor/asteroid, +/turf/floor/barren, /area/mine/explored) "bp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bq" = ( /obj/item/paper/smug_2, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "br" = ( /obj/structure/ore_box, @@ -576,7 +519,7 @@ /obj/effect/floor_decal/industrial/warning{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bs" = ( /obj/structure/ore_box, @@ -591,19 +534,17 @@ /obj/random/ore_smug, /obj/random/ore_smug, /obj/random/ore_smug, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bt" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bu" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ @@ -611,22 +552,22 @@ pixel_y = 8 }, /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bv" = ( -/turf/simulated/wall, +/turf/wall, /area/smugglers/office) "bw" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/smugglers/office) "bx" = ( -/obj/item/ore/slag, -/obj/item/ore/slag{ +/obj/item/stack/material/ore/slag, +/obj/item/stack/material/ore/slag{ pixel_x = 5; pixel_y = -2 }, -/obj/item/ore/slag, -/turf/simulated/floor, +/obj/item/stack/material/ore/slag, +/turf/floor, /area/smugglers/base) "by" = ( /obj/structure/ore_box, @@ -640,57 +581,49 @@ /obj/effect/floor_decal/industrial/warning{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bz" = ( /obj/random/ore_smug, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bA" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bB" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/office) "bC" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/office) "bD" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper, /obj/item/pen, /obj/item/flashlight/lamp, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bE" = ( /obj/structure/safe/floor, @@ -701,44 +634,44 @@ /obj/random/cash, /obj/random/cash, /obj/random/cash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bF" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bG" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bH" = ( /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bI" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bJ" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/office) "bK" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/coin{ pixel_x = -5; pixel_y = -3 }, /obj/random/coin, -/obj/item/storage/bible/booze{ +/obj/item/bible/booze{ pixel_x = 10 }, /obj/item/paper/smug_4{ @@ -746,26 +679,26 @@ pixel_y = 4 }, /obj/item/paper/smug_5, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bL" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 8 }, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bM" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bN" = ( /obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bO" = ( /obj/machinery/portable_atmospherics/canister/air, @@ -774,239 +707,230 @@ dir = 4; pixel_y = 8 }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bP" = ( -/mob/living/simple_animal/hostile/retaliate/malf_drone, -/turf/simulated/floor/tiled, +/mob/living/simple_animal/hostile/malf_drone, +/turf/floor/tiled, /area/smugglers/office) "bQ" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bR" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/tech_supply, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bS" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/toolbox, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bT" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bU" = ( /obj/structure/closet/crate/trashcart, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bV" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, /obj/machinery/portable_atmospherics/canister, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bW" = ( /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor, +/turf/floor, /area/smugglers/base) "bX" = ( /obj/machinery/constructable_frame/machine_frame, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bY" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/head/cowboy_hat, /obj/item/clothing/suit/armor/hos/jensen, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/office) "bZ" = ( -/obj/structure/filingcabinet/chestdrawer, -/turf/simulated/floor/tiled, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled, /area/smugglers/office) "ca" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/smugglers/dorms) "cb" = ( /obj/machinery/door/airlock/maintenance{ name = "Restroom" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/dorms) "cc" = ( -/turf/simulated/wall, +/turf/wall, /area/smugglers/dorms) "cd" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "ce" = ( /obj/structure/noticeboard{ - pixel_y = 30 + default_pixel_y = 30 }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/standard, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/table, /obj/machinery/microwave{ pixel_y = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cf" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/closet/crate, /obj/random/snack, /obj/random/snack, /obj/random/snack, /obj/random/snack, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cg" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/closet/crate, /obj/random/drinkbottle, /obj/random/drinkbottle, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "ch" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/computer/arcade, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "ci" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/effect/decal/cleanable/cobweb2, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/dorms) "cj" = ( /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/airless/ceiling, +/turf/floor/plating/airless, /area/smugglers/dorms) "cl" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cm" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/dorms) "cn" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/dorms) "co" = ( /obj/machinery/door/airlock/maintenance{ name = "Toilet" }, -/turf/simulated/floor, +/turf/floor, /area/smugglers/dorms) "cp" = ( -/obj/effect/decal/cleanable/vomit, +/obj/effect/decal/cleanable/vomit/mapped, /obj/random/medical/lite, -/turf/simulated/floor/airless/ceiling, +/turf/floor/plating/airless, /area/smugglers/dorms) "cq" = ( /obj/structure/hygiene/toilet{ dir = 8 }, -/turf/simulated/floor/airless/ceiling, +/turf/floor/plating/airless, /area/smugglers/dorms) "cr" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/machinery/light, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cs" = ( -/obj/structure/table/standard, -/obj/effect/decal/cleanable/dirt, +/obj/structure/table, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/paper/smug_3, -/obj/item/flame/lighter, +/obj/item/flame/fuelled/lighter, /obj/random/coin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "ct" = ( -/obj/structure/table/standard, -/obj/effect/decal/cleanable/dirt, +/obj/structure/table, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/cash/c10, /obj/random/smokes, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cu" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cv" = ( /obj/structure/closet, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/medical, /obj/random/medical, /obj/random/tech_supply, /obj/random/action_figure, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cw" = ( /obj/machinery/door/airlock/maintenance, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cx" = ( /obj/structure/bed, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/dorms) "cy" = ( /obj/structure/closet/smuggler, /obj/random/suit, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/dorms) "cz" = ( /obj/structure/bed, -/obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/retaliate/malf_drone, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/mob/living/simple_animal/hostile/malf_drone, +/turf/floor/tiled, /area/smugglers/dorms) "cA" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/smugglers/dorms) "cB" = ( -/obj/machinery/light/small{ - dir = 2 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/machinery/light/small, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/smugglers/dorms) "cC" = ( /obj/effect/shuttle_landmark/nav_asteroid_base/nav2, @@ -1018,8 +942,8 @@ /area/space) "db" = ( /obj/effect/decal/cleanable/blood, -/obj/effect/landmark/corpse/doctor, -/turf/simulated/floor/asteroid, +/obj/abstract/landmark/corpse/doctor, +/turf/floor/barren, /area/mine/explored) "eb" = ( /obj/machinery/light/small{ @@ -1028,11 +952,11 @@ /obj/structure/hygiene/sink{ pixel_y = 15 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_y = 30 }, /obj/random/soap, -/turf/simulated/floor/airless/ceiling, +/turf/floor/plating/airless, /area/smugglers/dorms) (1,1,1) = {" @@ -4636,7 +4560,7 @@ aa aa ao af -aA +aG aO bd bd diff --git a/maps/away/unishi/unishi-1.dmm b/maps/away/unishi/unishi-1.dmm index b48c88f38a3d..865829cd4ee0 100644 --- a/maps/away/unishi/unishi-1.dmm +++ b/maps/away/unishi/unishi-1.dmm @@ -3,110 +3,93 @@ /turf/space, /area/space) "ab" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/space) "ac" = ( -/turf/simulated/wall, +/turf/wall, /area/space) "ad" = ( -/obj/machinery/power/port_gen/pacman/super/potato, +/obj/machinery/port_gen/pacman/super/potato, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ae" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/closet/crate/uranium, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "af" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/closet/crate/uranium, /obj/structure/cable{ - icon_state = "0-8"; - dir = 4 + dir = 4; + icon_state = "0-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ag" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/engineering) "ah" = ( -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/unishi/engineering) "ai" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/engineering) "aj" = ( -/obj/machinery/power/port_gen/pacman/super/potato, +/obj/machinery/port_gen/pacman/super/potato, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ak" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "al" = ( /obj/structure/closet/crate/uranium, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "am" = ( /obj/machinery/atmospherics/unary/vent_pump/siphon/on, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/unishi/engineering) "an" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ao" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ap" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -114,63 +97,57 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/wingrille_spawn/reinforced_borosilicate, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineering) "ar" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/engineering) "as" = ( -/obj/machinery/atmospherics/pipe/vent/high_volume{ - icon_state = "intact"; +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ dir = 8 }, /turf/space, /area/unishi/engineering) "at" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/engineering) "au" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/engineering, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "av" = ( /obj/structure/barricade, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aw" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ax" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/closet/crate/uranium, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "ay" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/engineering) "az" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aA" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -179,7 +156,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aB" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -188,30 +165,28 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineering) "aC" = ( /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 4 }, /obj/machinery/portable_atmospherics/canister/air/airlock, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aD" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 10 }, /obj/structure/sign/warning/airlock, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineering) "aE" = ( /obj/machinery/airlock_sensor{ id_tag = "unishi_sensor"; pixel_y = 23 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aF" = ( /obj/machinery/embedded_controller/radio/airlock/docking_port{ @@ -222,14 +197,14 @@ tag_exterior_door = "unishi_outer"; tag_interior_door = "unishi_inner" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aG" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/engineroom) "aH" = ( -/obj/structure/dispenser, -/turf/simulated/floor, +/obj/structure/tank_rack, +/turf/floor, /area/unishi/engineering) "aI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -237,20 +212,20 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aK" = ( /obj/machinery/atmospherics/binary/pump/on{ dir = 4; target_pressure = 200 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aL" = ( /obj/machinery/door/airlock/external/bolted{ @@ -258,119 +233,112 @@ id_tag = "unishi_inner" }, /obj/machinery/atmospherics/pipe/manifold/visible, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aM" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "unishi_vent" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aN" = ( /obj/machinery/door/airlock/external/bolted{ dir = 4; id_tag = "unishi_outer" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aO" = ( /obj/machinery/atmospherics/unary/tank/oxygen{ - dir = 2; - volume = 3200 + gas_volume = 3200 }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "aP" = ( /obj/machinery/atmospherics/unary/tank/hydrogen, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "aQ" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/obj/structure/table/standard, +/obj/structure/table, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "aR" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "aS" = ( /obj/machinery/power/smes/buildable/max_cap_in_out, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/effect/floor_decal/industrial/hatch/yellow, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "aT" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/vending/wallmed1, /obj/structure/sign/warning/high_voltage{ - icon_state = "shock"; dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineroom) "aU" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "aV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/engineroom) "aW" = ( /obj/structure/fireaxecabinet, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/engineroom) "aX" = ( /obj/machinery/button/access/interior{ id_tag = "unishi"; - pixel_x = 28 + pixel_x = 28; + dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "aY" = ( /obj/structure/sign/warning/airlock, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/engineering) "aZ" = ( /obj/machinery/button/access/exterior{ id_tag = "unishi"; - pixel_x = -28 + pixel_x = -28; + dir = 4 }, /turf/space, /area/space) @@ -383,47 +351,41 @@ req_access = newlist() }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bb" = ( /obj/machinery/atmospherics/binary/pump, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bc" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bd" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "be" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/vending/tool, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bg" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/engineroom) "bh" = ( /obj/machinery/light/small{ @@ -432,43 +394,40 @@ /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "bi" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black{ dir = 8 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/suit_cooling_unit, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bj" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bk" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 9 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bl" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bm" = ( /obj/machinery/floodlight, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -476,15 +435,15 @@ /obj/machinery/vending/engivend{ req_access = newlist() }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bo" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/engineroom) "bp" = ( /obj/structure/closet/hydrant, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/engineroom) "bq" = ( /obj/machinery/suit_cycler, @@ -492,12 +451,12 @@ dir = 4; pixel_x = -32 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "br" = ( /obj/structure/closet/radiation, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -508,7 +467,7 @@ /obj/machinery/vending/engineering{ req_access = newlist() }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bt" = ( /obj/machinery/atmospherics/unary/outlet_injector/engine{ @@ -517,22 +476,22 @@ id_tag = "unishi_fuel_in"; use_power = 1 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bu" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bv" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bw" = ( /obj/structure/closet/secure_closet/engineering_welding{ req_access = newlist() }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -543,93 +502,77 @@ /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "by" = ( /obj/structure/ladder, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineering) "bz" = ( /obj/machinery/light/small{ dir = 8 }, /obj/machinery/suit_cycler, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bA" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/closet/toolcloset, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bB" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bC" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bD" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineroom) "bE" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/engineroom) "bF" = ( /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers, /obj/machinery/atmospherics/pipe/zpipe/up/supply, /obj/structure/cable/yellow{ - d1 = 16; - d2 = 0; icon_state = "16-0" }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/engineroom) "bG" = ( /obj/machinery/computer/air_control{ @@ -641,11 +584,11 @@ sensor_name = "Tank"; sensor_tag = "n2_sensor" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bH" = ( /obj/machinery/recharge_station, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -654,7 +597,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineroom) "bJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -664,7 +607,7 @@ dir = 4 }, /obj/machinery/floorlayer, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -674,14 +617,14 @@ dir = 9 }, /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bL" = ( /obj/machinery/sparker{ id_tag = "unishi"; pixel_x = -20 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bM" = ( /obj/machinery/atmospherics/unary/vent_pump/engine{ @@ -691,52 +634,44 @@ icon_state = "map_vent_in"; id_tag = "unishi_fuel_out"; initialize_directions = 1; - pressure_checks = 1; - pressure_checks_default = 1; pump_direction = 0; use_power = 1 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bN" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bO" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor, -/area/unishi/engineroom) -"bP" = ( -/obj/machinery/atmospherics/pipe/simple/visible/fuel{ - dir = 4 - }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bQ" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 10 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bR" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/engineroom) "bS" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 6 }, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/engineroom) "bT" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/engineroom) "bU" = ( /obj/machinery/atmospherics/binary/pump{ @@ -744,59 +679,58 @@ }, /obj/machinery/button/ignition{ id_tag = "unishi"; - pixel_x = -28 + pixel_x = -28; + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bV" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ - dir = 4; - icon_state = "intact"; - + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bW" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 9 }, /obj/machinery/portable_atmospherics/canister/hydrogen, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bX" = ( /obj/structure/closet/hydrant, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineroom) "bY" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/rcd, /obj/item/rcd_ammo/large, /obj/item/rcd_ammo/large, /obj/item/rcd_ammo/large, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "bZ" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/engineroom) "ca" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 8 }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "cb" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 1 }, /obj/machinery/light/small, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "cc" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 1 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "cd" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -805,25 +739,25 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "ce" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/engineroom) "cf" = ( /obj/structure/sign/warning/vent_port, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/engineroom) "cg" = ( /obj/machinery/atmospherics/unary/engine{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/engineroom) "ch" = ( /obj/structure/sign/warning/vent_port, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/space) "ci" = ( /obj/structure/lattice, @@ -837,13 +771,13 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/engineroom) "Ic" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/engineering) (1,1,1) = {" @@ -5774,8 +5708,8 @@ bc bc bd aU -bP -bP +bV +bV cc ce cg @@ -5876,7 +5810,7 @@ br bw bA aU -bP +bV bV cb ce @@ -5978,7 +5912,7 @@ bc bc bB aU -bP +bV bV cc ce diff --git a/maps/away/unishi/unishi-2.dmm b/maps/away/unishi/unishi-2.dmm index 6e4cff3a78cb..376eed3145da 100644 --- a/maps/away/unishi/unishi-2.dmm +++ b/maps/away/unishi/unishi-2.dmm @@ -3,110 +3,94 @@ /turf/space, /area/space) "ab" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/library) "ac" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/unishi/library) "ad" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/space) "ae" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/advdevice, /obj/item/flashlight/lamp, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "af" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, -/turf/simulated/floor/carpet/red, -/area/unishi/library) -"ag" = ( -/obj/structure/table/woodentable, -/obj/item/flashlight/lamp, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ah" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ai" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/flashlight/lamp, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "aj" = ( /obj/machinery/vending/coffee, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ak" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/library) "al" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "am" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "an" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ao" = ( -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ap" = ( /obj/machinery/fabricator/book, -/turf/simulated/floor/carpet/red, -/area/unishi/library) -"aq" = ( -/obj/structure/bookcase, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ar" = ( /obj/structure/bookcase/manuals/engineering, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "as" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "at" = ( /obj/structure/bookcase/manuals/medical, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "au" = ( /obj/machinery/light{ @@ -115,35 +99,32 @@ /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "av" = ( /obj/structure/bookcase, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "aw" = ( /obj/structure/bookcase/manuals/xenoarchaeology, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/unishi/library) "ax" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/chem) "ay" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/chem) "az" = ( /obj/machinery/door/airlock/glass/research, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/library) "aA" = ( /obj/structure/closet/secure_closet/chemical{ @@ -158,10 +139,9 @@ /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -170,13 +150,12 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aC" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -186,15 +165,14 @@ dir = 4 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aD" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -203,11 +181,9 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/chem) "aE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -217,11 +193,9 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "aF" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -232,72 +206,65 @@ }, /obj/effect/floor_decal/cti, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/unishi/common) "aG" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/common) "aH" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/stock_parts/circuitboard/solar_control, -/obj/item/stock_parts/circuitboard/roboprinter, /obj/item/bot_kit, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "aI" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/integrated_circuit/converter/text2num, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "aJ" = ( -/obj/structure/table/standard, -/obj/item/stock_parts/circuitboard/roboprinter, +/obj/structure/table, /obj/item/stock_parts/circuitboard/helm, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "aK" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/stock_parts/circuitboard/robotics, /obj/item/stock_parts/circuitboard/protolathe, /obj/item/stock_parts/circuitboard/helm, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "aL" = ( /obj/machinery/smartfridge/chemistry, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aM" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aN" = ( /obj/item/chems/chem_disp_cartridge/acetone, /obj/item/chems/chem_disp_cartridge/copper, /obj/item/chems/chem_disp_cartridge/eyedrops, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/chems/syringe/antitoxin, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aO" = ( -/obj/structure/sign/chemistry{ - icon_state = "chemistry"; +/obj/structure/sign/department/chemistry{ dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/chem) "aP" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "aQ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -305,45 +272,39 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "aR" = ( /obj/structure/closet/crate/secure/biohazard, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor, -/area/unishi/common) -"aS" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "aT" = ( /obj/machinery/chemical_dispenser/full, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aU" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "aV" = ( /obj/structure/table/reinforced, /obj/item/chems/spray/cleaner, /obj/item/chems/dropper, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/chem) "aW" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "aX" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -351,110 +312,104 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "aY" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "aZ" = ( /obj/structure/closet/crate/secure/explosives, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "ba" = ( /obj/structure/closet/secure_closet/scientist{ req_access = newlist() }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bb" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 1 }, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "bc" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "bd" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/chem) "be" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bg" = ( /obj/structure/closet/crate/hydroponics, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bh" = ( /obj/structure/closet/crate/hydroponics/beekeeping, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bi" = ( /obj/structure/closet/crate/rcd, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bj" = ( /obj/machinery/chem_master, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "bk" = ( /obj/structure/table/reinforced, /obj/item/chems/glass/beaker/large, /obj/item/chems/glass/beaker/advanced, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "bl" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/common) "bm" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/classroom) "bn" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/classroom) "bo" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bp" = ( /obj/structure/railing/mapped, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bq" = ( -/obj/structure/stairs/east, +/obj/structure/stairs/long/east, /obj/structure/railing/mapped, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "br" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -463,7 +418,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -472,50 +427,42 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bt" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled/dark, +/obj/structure/chair, +/turf/floor/tiled/dark, /area/unishi/classroom) "bu" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bv" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bw" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/classroom) "bx" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "by" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -525,16 +472,12 @@ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -544,11 +487,9 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -558,12 +499,10 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/hatch, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bB" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -573,38 +512,31 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/ladder, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bE" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bG" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bH" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -614,11 +546,9 @@ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bI" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -627,7 +557,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bJ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -636,58 +566,49 @@ /obj/structure/closet/crate/bin, /obj/structure/sign/warning/nosmoking_1{ dir = 8; - icon_state = "nosmoking"; pixel_x = 32 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bK" = ( /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ - color = "#ff0000"; dir = 1 }, /obj/machinery/atmospherics/pipe/zpipe/up/supply{ - color = "#0000ff"; dir = 1 }, /obj/structure/cable/yellow{ - d1 = 16; - d2 = 0; icon_state = "16-0" }, /obj/structure/cable/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bL" = ( /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers{ - color = "#ff0000"; dir = 1 }, /obj/machinery/atmospherics/pipe/zpipe/down/supply{ - color = "#0000ff"; dir = 1 }, /obj/structure/cable/yellow{ - d1 = 32; - d2 = 1; icon_state = "32-1" }, -/turf/simulated/open, +/turf/open, /area/unishi/common) "bO" = ( /obj/machinery/floodlight, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bP" = ( /obj/item/flashlight/upgraded, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bQ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -696,17 +617,17 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bS" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -715,12 +636,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bU" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -728,7 +649,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/classroom) "bV" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -738,73 +659,68 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "bW" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24; req_access = newlist() }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "bX" = ( /obj/machinery/portable_atmospherics/canister/hydrogen, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bY" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "bZ" = ( /obj/machinery/portable_atmospherics/canister/sleeping_agent, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "ca" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/dark, +/obj/structure/table, +/turf/floor/tiled/dark, /area/unishi/classroom) "cb" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/powercell, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "cc" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "cd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "ce" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "cf" = ( /obj/machinery/portable_atmospherics/canister/chlorine, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "cg" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "ch" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -814,11 +730,9 @@ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "ci" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -827,12 +741,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "cj" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -840,7 +754,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "ck" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -849,7 +763,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "cl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -858,46 +772,44 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "cm" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "cn" = ( -/obj/item/modular_computer/telescreen/preset/generic{ - dir = 1; - pixel_y = -28 +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 1 }, /obj/structure/table/glass, /obj/item/pen/green, /obj/item/paper_bin, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "co" = ( -/obj/item/modular_computer/telescreen/preset/generic{ - dir = 1; - pixel_y = -28 +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/classroom) "cp" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "cq" = ( -/obj/structure/dispenser, -/turf/simulated/floor, +/obj/structure/tank_rack, +/turf/floor, /area/unishi/common) "cr" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/meeting) "cs" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/meeting) "ct" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/meeting) "cu" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -905,61 +817,55 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "cv" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "cw" = ( /obj/structure/sign/warning/biohazard, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/toxins) "cx" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/toxins) "cy" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/toxins) "cz" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cA" = ( -/obj/structure/bed/chair/office/comfy/black, -/turf/simulated/floor/tiled, +/obj/structure/chair/office/comfy/black, +/turf/floor/tiled, /area/unishi/meeting) "cB" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cC" = ( /obj/effect/wingrille_spawn/reinforced, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/meeting) "cD" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -967,195 +873,176 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "cE" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "cF" = ( /obj/effect/wingrille_spawn/reinforced, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/toxins) "cG" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "cH" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "cI" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/toxins) "cJ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/toxins) "cK" = ( /obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; dir = 8 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/toxins) "cL" = ( /obj/machinery/door/blast/regular{ - icon_state = "pdoor1"; dir = 8 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "cM" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cN" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper_bin, /obj/item/pen/fancy, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cO" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/pen/fancy, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cP" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/folder/yellow, /obj/item/pen/green, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cQ" = ( /obj/effect/floor_decal/cti, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/unishi/meeting) "cR" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/meeting) "cS" = ( /obj/effect/wingrille_spawn/reinforced, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/toxins) "cT" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "cU" = ( /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "cV" = ( /obj/machinery/atmospherics/unary/vent_pump/siphon/on{ - icon_state = "map_vent_in"; dir = 8 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/toxins) "cW" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 4 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cX" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/random/clipboard, /obj/item/folder/cyan, /obj/item/pen/reagent/sleepy, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cY" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/item/folder/yellow, /obj/item/pen/green, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "cZ" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, @@ -1164,7 +1051,7 @@ }, /obj/item/folder/yellow, /obj/item/pen/green, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "da" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1173,7 +1060,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "db" = ( /obj/effect/wingrille_spawn/reinforced, @@ -1183,27 +1070,27 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/meeting) "dc" = ( -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "dd" = ( /obj/machinery/vending/bombresearch, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "de" = ( /obj/machinery/door/airlock/glass/science, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/toxins) "df" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "dg" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 1 }, /obj/machinery/alarm{ @@ -1211,14 +1098,14 @@ pixel_y = -22; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "dh" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/meeting) "di" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/unishi/meeting) "dj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1227,17 +1114,16 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "dk" = ( /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -1245,7 +1131,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/toxins) "dl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1254,7 +1140,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "dm" = ( /obj/structure/closet/bombcloset, @@ -1264,7 +1150,7 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "dn" = ( /obj/item/transfer_valve, @@ -1273,37 +1159,35 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/unishi/toxins) "do" = ( /obj/structure/sign/warning/fire{ dir = 8; - pixel_x = 32; - pixel_y = 0 + pixel_x = 32 }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/unishi/toxins) "dp" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/toxins) "dq" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/rnd) "dr" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/rnd) "ds" = ( /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/unishi/toxins) "dt" = ( /obj/machinery/light, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/unishi/toxins) "du" = ( /obj/machinery/alarm{ @@ -1311,10 +1195,10 @@ pixel_y = -22; req_access = newlist() }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/unishi/toxins) "dv" = ( -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/unishi/toxins) "dw" = ( /obj/effect/shuttle_landmark/nav_unishi/nav2, @@ -1322,111 +1206,99 @@ /area/space) "dx" = ( /obj/machinery/computer/modular/preset/aislot/research, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dy" = ( /obj/machinery/computer/modular/preset/aislot/research, /obj/random/smokes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dz" = ( /obj/machinery/fabricator, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dA" = ( /obj/machinery/design_database, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dB" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dC" = ( /obj/effect/wingrille_spawn/reinforced, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/rnd) "dD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "dE" = ( /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "dF" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/toxins) "dG" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/toxins) "dH" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 1 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/toxins) "dI" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/toxins) "dJ" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/hydro) "dK" = ( -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dL" = ( -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 1 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1435,10 +1307,10 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dN" = ( -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1447,7 +1319,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1456,12 +1328,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dP" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1470,7 +1342,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/rnd) "dQ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1480,47 +1352,39 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "dR" = ( /obj/effect/wingrille_spawn/reinforced, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/hydro) "dS" = ( /obj/machinery/atmospherics/valve, /obj/machinery/vending/hydroseeds, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "dT" = ( /obj/effect/vine, /obj/machinery/vending/hydronutrients, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "dU" = ( /obj/effect/vine, @@ -1528,30 +1392,30 @@ /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "dV" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "dW" = ( /obj/effect/wingrille_spawn/reinforced/full, -/turf/simulated/floor, +/turf/floor, /area/unishi/hydro) "dX" = ( /obj/machinery/fabricator/imprinter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dY" = ( /obj/machinery/destructive_analyzer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "dZ" = ( /obj/machinery/fabricator/protolathe, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "ea" = ( /obj/structure/table/glass, @@ -1560,19 +1424,20 @@ pixel_y = -22; req_access = newlist() }, -/obj/item/stack/material/diamond/ten, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/silver/ten, -/obj/item/stack/material/glass/fifty, -/turf/simulated/floor/tiled, +/obj/item/stack/material/gemstone/mapped/diamond/ten, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/ingot/mapped/silver/ten, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/turf/floor/tiled, /area/unishi/rnd) "eb" = ( /obj/machinery/fabricator/replicator, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/rnd) "ec" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/unishi/rnd) "ed" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1580,76 +1445,69 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "ee" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "ef" = ( /obj/machinery/smartfridge, -/turf/simulated/floor, +/turf/floor, /area/unishi/hydro) "eg" = ( /obj/effect/vine, /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eh" = ( /obj/machinery/atmospherics/valve{ - icon_state = "map_valve0"; dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "ei" = ( /obj/effect/vine, /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 1 }, /obj/item/seeds/quantumatoseed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "ej" = ( /obj/effect/vine, /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "ek" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "el" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/xenobio) "em" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/xenobio) "en" = ( /obj/structure/sign/warning/biohazard, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/xenobio) "eo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "ep" = ( /obj/effect/wingrille_spawn/reinforced, @@ -1657,129 +1515,123 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/hydro) "eq" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 8 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "er" = ( /obj/effect/vine, -/obj/machinery/atmospherics/unary/freezer{ - icon_state = "freezer"; - dir = 8 +/obj/machinery/atmospherics/unary/temperature/freezer{ + dir = 8; + icon_state = "freezer" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "es" = ( -/mob/living/carbon/slime, -/mob/living/carbon/slime, -/mob/living/carbon/human/monkey, -/mob/living/carbon/human/monkey, -/mob/living/carbon/human/monkey, -/turf/simulated/floor/reinforced, +/mob/living/slime, +/mob/living/slime, +/mob/living/human/monkey, +/mob/living/human/monkey, +/mob/living/human/monkey, +/turf/floor/reinforced, /area/unishi/xenobio) "et" = ( /obj/structure/window/borosilicate_reinforced{ dir = 4 }, -/mob/living/carbon/slime, -/mob/living/carbon/human/monkey, -/mob/living/carbon/human/monkey, -/turf/simulated/floor/reinforced, +/mob/living/slime, +/mob/living/human/monkey, +/mob/living/human/monkey, +/turf/floor/reinforced, /area/unishi/xenobio) "eu" = ( /obj/structure/reagent_dispensers/watertank, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "ev" = ( /obj/structure/table/glass, /obj/item/scanner/xenobio, -/obj/item/storage/box/monkeycubes, +/obj/item/box/animal_cubes/monkeys, /obj/random/smokes, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "ew" = ( /obj/structure/table/glass, -/obj/item/extinguisher, -/obj/item/extinguisher, -/obj/item/extinguisher, -/obj/item/storage/box/monkeycubes, -/obj/machinery/power/apc{ +/obj/item/chems/spray/extinguisher, +/obj/item/chems/spray/extinguisher, +/obj/item/chems/spray/extinguisher, +/obj/item/box/animal_cubes/monkeys, +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "ex" = ( /obj/effect/wingrille_spawn/reinforced, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/xenobio) "ey" = ( /obj/item/seeds/random, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "ez" = ( /obj/effect/wingrille_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/hydro) "eA" = ( /obj/machinery/atmospherics/valve{ - icon_state = "map_valve0"; dir = 8 }, /obj/item/seeds/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eB" = ( -/mob/living/carbon/slime, -/mob/living/carbon/human/monkey, -/mob/living/carbon/human/monkey, -/turf/simulated/floor/reinforced, +/mob/living/slime, +/mob/living/human/monkey, +/mob/living/human/monkey, +/turf/floor/reinforced, /area/unishi/xenobio) "eC" = ( /obj/structure/window/borosilicate_reinforced{ dir = 4 }, -/mob/living/carbon/human/monkey, -/mob/living/carbon/human/monkey, -/turf/simulated/floor/reinforced, +/mob/living/human/monkey, +/mob/living/human/monkey, +/turf/floor/reinforced, /area/unishi/xenobio) "eD" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eE" = ( /obj/machinery/smartfridge/secure/extract, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eF" = ( /obj/effect/wingrille_spawn/reinforced, -/obj/structure/sign/xenobio_3, +/obj/structure/sign/department/xenobio_3, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/xenobio) "eG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1788,72 +1640,69 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "eH" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/hydro) "eI" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 8 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eJ" = ( /obj/effect/vine, -/obj/machinery/atmospherics/unary/heater{ - icon_state = "heater_0"; +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eK" = ( -/obj/item/sign/medipolma, -/turf/simulated/wall/titanium, +/obj/item/sign/diploma/fake/medical, +/turf/wall/titanium, /area/unishi/xenobio) "eL" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/xenobio) "eM" = ( /obj/structure/window/borosilicate_reinforced{ dir = 4 }, /obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/xenobio) "eN" = ( /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eO" = ( /obj/machinery/optable, /obj/item/scalpel, /obj/item/circular_saw, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eP" = ( /obj/effect/wingrille_spawn/reinforced, -/obj/structure/sign/xenobio_1{ - icon_state = "xenobio"; +/obj/structure/sign/department/xenobio_1{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/xenobio) "eQ" = ( /obj/effect/vine, @@ -1862,7 +1711,7 @@ }, /obj/item/seeds/random, /obj/item/seeds/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eR" = ( /obj/effect/vine, @@ -1875,7 +1724,7 @@ /obj/item/seeds/random, /obj/item/seeds/random, /obj/item/seeds/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eS" = ( /obj/effect/vine, @@ -1885,19 +1734,19 @@ /obj/item/seeds/random, /obj/item/seeds/random, /obj/item/seeds/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eT" = ( /obj/machinery/botany/editor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "eU" = ( -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/xenobio) "eV" = ( /obj/machinery/door/window/eastleft, /obj/machinery/door/window/westleft, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/unishi/xenobio) "eW" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -1908,7 +1757,7 @@ pixel_y = -22; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1917,7 +1766,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1926,12 +1775,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/xenobio) "eZ" = ( /obj/machinery/door/airlock/glass/research{ - icon_state = "closed"; - dir = 4 + dir = 4; + icon_state = "closed" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -1940,20 +1789,19 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/xenobio) "fa" = ( /obj/machinery/vending/snack, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fb" = ( /obj/effect/vine, /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 5 }, /obj/machinery/seed_extractor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "fc" = ( /obj/effect/vine, @@ -1961,7 +1809,7 @@ dir = 4 }, /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "fd" = ( /obj/effect/vine, @@ -1980,7 +1828,7 @@ pixel_y = -22; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "fe" = ( /obj/effect/vine, @@ -1988,25 +1836,23 @@ /obj/item/seeds/random, /obj/item/seeds/random, /obj/item/seeds/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "ff" = ( /obj/machinery/botany/extractor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/hydro) "fg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fh" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/common) "fi" = ( /obj/structure/flora/pottedplant/overgrown, @@ -2016,20 +1862,18 @@ /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fj" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fk" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2041,13 +1885,12 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fl" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, @@ -2055,39 +1898,32 @@ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fm" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fn" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fo" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2096,61 +1932,60 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fp" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "fq" = ( /obj/machinery/door/airlock/science, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "fr" = ( /obj/structure/sign/warning/radioactive{ - icon_state = "radiation"; dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/common) "fs" = ( /obj/effect/wingrille_spawn/reinforced, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "ft" = ( /obj/machinery/door/airlock/science, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/unishi/common) "fu" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/space) "fv" = ( /obj/structure/flora/pottedplant/aquatic, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fx" = ( /obj/machinery/computer/log_printer/prof1, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fy" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/snack, /obj/item/flashlight/lamp, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fz" = ( /obj/machinery/computer/log_printer/prof2, @@ -2158,145 +1993,131 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fA" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/item/plantspray/weeds, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fB" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 4 }, /obj/machinery/light, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fC" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper_bin, /obj/item/flashlight/lamp, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fD" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fE" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fF" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, /obj/machinery/light, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/cti, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/unishi/common) "fH" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 1 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fI" = ( /obj/machinery/light, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/common) "fJ" = ( /obj/machinery/portable_atmospherics/hydroponics, -/obj/item/weedkiller, -/turf/simulated/floor/tiled/dark, +/obj/item/plantspray/weedkiller, +/turf/floor/tiled/dark, /area/unishi/common) "fK" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "fL" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/smresearch) "fM" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "Biohazard"; - name = "Biohazard Shutter"; - opacity = 0 + name = "Biohazard Shutter" }, /obj/machinery/door/airlock/hatch, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, /obj/effect/floor_decal/industrial/warning/fulltile, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "fN" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/smresearch) "fO" = ( /obj/structure/sign/warning/radioactive{ - icon_state = "radiation"; dir = 4 }, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/smresearch) "fP" = ( /obj/structure/closet/radiation, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/smresearch) "fQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/smresearch) "fR" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "north bump"; - pixel_x = 0; pixel_y = 24; req_access = newlist() }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/smresearch) "fS" = ( /obj/structure/closet/radiation, @@ -2306,10 +2127,9 @@ /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/smresearch) "fT" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -2319,32 +2139,30 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/smresearch) "fU" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/unishi/smresearch) "fV" = ( /obj/machinery/light/small{ dir = 8 }, /obj/item/remains, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "fW" = ( /obj/machinery/atmospherics/unary/tank/hydrogen, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "fX" = ( /obj/machinery/atmospherics/portables_connector, @@ -2352,67 +2170,62 @@ dir = 4 }, /obj/item/remains, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "fY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning/fulltile, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/unishi/smresearch) "fZ" = ( /obj/machinery/atmospherics/unary/tank/air, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "ga" = ( /obj/machinery/atmospherics/unary/tank/carbon_dioxide, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gb" = ( /obj/machinery/atmospherics/unary/tank/hydrogen, /obj/machinery/light/small, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gc" = ( /obj/machinery/atmospherics/unary/tank/nitrogen, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gd" = ( /obj/machinery/atmospherics/unary/tank/oxygen, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "ge" = ( /obj/structure/closet/crate/secure/large/supermatter/experimentalsm, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gf" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Biohazard"; - name = "Biohazard Shutter"; - opacity = 0 + name = "Biohazard Shutter" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gg" = ( -/obj/effect/decal/remains, -/obj/item/clothing/under/rank/chief_engineer, +/obj/item/remains, +/obj/item/clothing/jumpsuit/chief_engineer, /obj/random/shoes, -/obj/item/clothing/suit/storage/toggle/labcoat/science{ +/obj/item/clothing/suit/toggle/labcoat/science{ name = "\improper labcoat" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gh" = ( /obj/machinery/atmospherics/binary/pump/high_power, @@ -2421,7 +2234,7 @@ dir = 8 }, /obj/effect/floor_decal/industrial/loading, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gi" = ( /obj/machinery/atmospherics/binary/pump/high_power, @@ -2430,7 +2243,7 @@ dir = 4 }, /obj/effect/floor_decal/industrial/loading, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gj" = ( /obj/machinery/atmospherics/binary/pump/high_power, @@ -2439,49 +2252,49 @@ dir = 8 }, /obj/effect/floor_decal/industrial/loading, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gk" = ( /obj/machinery/atmospherics/binary/pump/high_power, /obj/structure/window/borosilicate_reinforced, /obj/effect/floor_decal/industrial/loading, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gl" = ( /obj/machinery/atmospherics/binary/pump/high_power/on{ target_pressure = 15000 }, /obj/effect/floor_decal/industrial/loading, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gm" = ( /obj/machinery/atmospherics/binary/pump/high_power, /obj/structure/window/borosilicate_reinforced, /obj/item/remains, -/obj/item/clothing/suit/storage/toggle/labcoat/science{ +/obj/item/clothing/suit/toggle/labcoat/science{ name = "\improper labcoat" }, /obj/effect/floor_decal/industrial/loading, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gn" = ( /turf/space, /area/unishi/smresearch) "go" = ( -/obj/effect/decal/cleanable/vomit, +/obj/effect/decal/cleanable/vomit/mapped, /obj/item/defibrillator, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gp" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gq" = ( /obj/machinery/atmospherics/pipe/manifold/visible/yellow, -/obj/effect/decal/remains, -/turf/simulated/floor/tiled/techfloor, +/obj/item/remains, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gr" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ @@ -2490,29 +2303,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gs" = ( /obj/machinery/atmospherics/pipe/manifold/visible/yellow, /obj/item/remains, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gt" = ( /obj/machinery/atmospherics/pipe/manifold/visible/yellow, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gu" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gv" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ @@ -2520,33 +2330,32 @@ }, /obj/machinery/button/mass_driver{ id_tag = "unishi_sm_eject"; - pixel_x = 24 + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gw" = ( /obj/structure/lattice, /turf/space, /area/space) "gx" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; - opacity = 0 + }, /obj/item/remains, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gy" = ( -/obj/effect/decal/remains, +/obj/item/remains, /obj/effect/decal/cleanable/blood, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2555,7 +2364,7 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2564,10 +2373,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/item/clothing/suit/storage/toggle/labcoat/science{ +/obj/item/clothing/suit/toggle/labcoat/science{ name = "\improper labcoat" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gB" = ( /obj/item/remains, @@ -2575,34 +2384,29 @@ /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gC" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/obj/effect/decal/cleanable/vomit, +/obj/effect/decal/cleanable/vomit/mapped, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning/corner, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gD" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ @@ -2610,15 +2414,13 @@ }, /obj/machinery/light/small, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gE" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ @@ -2628,26 +2430,24 @@ target_pressure = 15000 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/item/clothing/suit/storage/toggle/labcoat/genetics, +/obj/item/clothing/suit/toggle/labcoat/genetics, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gF" = ( -/obj/machinery/power/emitter/anchored/on, +/obj/machinery/emitter/anchored/on, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, +/obj/machinery/power/terminal, /obj/machinery/atmospherics/binary/pump/high_power, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gG" = ( /obj/machinery/atmospherics/binary/pump{ @@ -2655,22 +2455,23 @@ }, /obj/machinery/button/blast_door{ id_tag = "unishi_eject"; - pixel_x = 22 + pixel_x = 22; + dir = 8 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gH" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "gI" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "gJ" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ @@ -2689,53 +2490,53 @@ "gL" = ( /obj/effect/decal/cleanable/ash, /obj/effect/decal/cleanable/blood, -/obj/item/clothing/under/blazer, +/obj/item/clothing/shirt/button, +/obj/item/clothing/neck/tie/navy, +/obj/item/clothing/suit/jacket/blazer, /obj/machinery/computer/modular/preset/engineering{ - icon_state = "console"; - dir = 4 + dir = 4; + icon_state = "console" }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gM" = ( /obj/effect/decal/cleanable/blood, -/obj/effect/decal/remains, +/obj/item/remains, /obj/random/shoes, -/obj/item/clothing/under/bluepyjamas, -/turf/simulated/floor/tiled/techfloor, +/obj/item/clothing/pants/pj/blue, +/obj/item/clothing/shirt/pj/blue, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gN" = ( -/obj/item/clothing/suit/storage/toggle/labcoat/chemist, +/obj/item/clothing/suit/toggle/labcoat/chemist, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/item/clothing/suit/storage/toggle/labcoat/cmoalt, +/obj/item/clothing/suit/toggle/labcoat/cmoalt, /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gP" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/computer/air_control/supermatter_core{ dir = 8; - frequency = 1438; - icon_state = "computer"; input_tag = "unishi_cooling_in"; name = "Supermatter Test Room Cooling Control"; output_tag = "unishi_cooling_out"; @@ -2743,14 +2544,14 @@ sensor_name = "Engine Core"; sensor_tag = "engine_sensor" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gQ" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gR" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, @@ -2758,19 +2559,18 @@ /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gS" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/machinery/atmospherics/pipe/manifold/visible/yellow{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gT" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "gU" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ @@ -2788,52 +2588,52 @@ /area/space) "gW" = ( /obj/structure/sign/warning/radioactive, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "gX" = ( /obj/item/remains, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gY" = ( -/obj/item/paper/crumpled/bloody{ +/obj/item/paper/crumpled{ info = "I FUCKING KNEW that piece of shit was no good. To whoever finds this, his name is Robert Moreno. He is one of the undergrads here, or at least his story went. The fucker lured us here on the pretense of a huge emergency, and the second we came in, the shutters closed behind us. We have been hearing gunshots through the ship throughout. The emitter was locked and on, and kept hitting that rock thing that one of the profs was studying, and we cant get the damn thing to stop. It chewed through everything we put in front of it and it doesnt look like it's stopping any time soon. The grad student in charge of this monstrosity is screaming and telling us that it's all over. We've been vomiting non stop, and I think our time here is running out." }, /obj/item/usedcryobag, /obj/item/clothing/suit/space/void/medical, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "gZ" = ( /obj/item/geiger, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "ha" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hb" = ( /obj/item/book/manual/engineering_construction, /obj/machinery/atmospherics/pipe/simple/visible/yellow, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hc" = ( /obj/machinery/door/airlock/hatch{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hd" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "he" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ @@ -2849,13 +2649,13 @@ use_power = 1; volume_rate = 700 }, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "hf" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 10 }, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "hg" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ @@ -2866,22 +2666,22 @@ /area/space) "hh" = ( /obj/effect/decal/cleanable/blood, -/obj/effect/decal/remains, -/obj/item/clothing/suit/storage/toggle/labcoat/science{ +/obj/item/remains, +/obj/item/clothing/suit/toggle/labcoat/science{ name = "\improper labcoat" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hi" = ( /obj/effect/decal/cleanable/blood, /obj/item/remains, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hj" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hk" = ( /obj/machinery/atmospherics/omni/filter{ @@ -2890,7 +2690,7 @@ tag_south = 2; tag_west = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hl" = ( /obj/machinery/atmospherics/omni/filter{ @@ -2899,18 +2699,17 @@ tag_west = 2 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hm" = ( /obj/effect/wingrille_spawn/reinforced_borosilicate/full, /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hn" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, @@ -2921,112 +2720,108 @@ icon_state = "map_vent_in"; id_tag = "unishi_cooling_out"; initialize_directions = 1; - pressure_checks = 1; - pressure_checks_default = 1; pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "ho" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/obj/machinery/power/supermatter/inert{ +/obj/structure/supermatter/inert{ color = "" }, /obj/machinery/mass_driver{ id_tag = "unishi_sm_eject" }, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "hp" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; - opacity = 0 + }, -/obj/effect/decal/remains, +/obj/item/remains, /obj/random/shoes, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hq" = ( -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hr" = ( /obj/machinery/computer/modular/preset/engineering{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hs" = ( /obj/machinery/atmospherics/pipe/simple/visible/green, -/obj/effect/decal/remains, +/obj/item/remains, /obj/random/shoes, /obj/machinery/light/small, /obj/item/remains, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "ht" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/unishi/smresearch) "hu" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 5 }, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "hv" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 9 }, -/turf/simulated/floor/reinforced/nitrogen/engine, +/turf/floor/reinforced/nitrogen/engine, /area/unishi/smresearch) "hw" = ( /obj/machinery/atmospherics/pipe/simple/visible/green, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "hx" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hy" = ( /obj/machinery/door/blast/regular{ id_tag = "unishi_eject" }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/unishi/smresearch) "hz" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/unishi/smresearch) "hA" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hB" = ( /obj/item/remains, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hC" = ( /obj/structure/window/borosilicate_reinforced{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/smresearch) "hD" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "hE" = ( /obj/machinery/atmospherics/unary/engine{ dir = 1 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/smresearch) "hF" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ @@ -3043,18 +2838,18 @@ /turf/space, /area/unishi/smresearch) "qW" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagent_temperature, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "xD" = ( /obj/machinery/reagentgrinder, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) "OW" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagent_temperature/cooler, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/chem) (1,1,1) = {" @@ -7768,7 +7563,7 @@ aa ac ae al -aq +av au av ay @@ -7870,7 +7665,7 @@ aa ac af am -aq +av ao av ay @@ -7970,7 +7765,7 @@ aa aa aa ac -ag +ai am ar ao @@ -8278,13 +8073,13 @@ aa ac af ao -aq +av ao -aq +av ak aH aR -aS +cp bg aG bq @@ -8380,13 +8175,13 @@ aa ac aj ap -aq +av ao -aq +av ak aI -aS -aS +cp +cp bh aG aG @@ -8487,14 +8282,14 @@ ak ak ak aJ -aS +cp aZ bi bl br bB bK -aS +cp bl bY cf @@ -8589,7 +8384,7 @@ ad ad ad aK -aS +cp ba ba bl diff --git a/maps/away/unishi/unishi-3.dmm b/maps/away/unishi/unishi-3.dmm index 18aa3290981e..ccb4c5e12c0d 100644 --- a/maps/away/unishi/unishi-3.dmm +++ b/maps/away/unishi/unishi-3.dmm @@ -9,178 +9,179 @@ /turf/space, /area/space) "ac" = ( -/obj/effect/submap_landmark/joinable_submap/unishi, +/obj/abstract/submap_landmark/joinable_submap/unishi, /turf/space, /area/space) "ad" = ( /obj/effect/wingrille_spawn/reinforced/full, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "ae" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/bridge) "af" = ( /obj/effect/wingrille_spawn/reinforced/full, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/bridge) "ag" = ( /obj/machinery/computer/ship/engines, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ah" = ( /obj/machinery/computer/ship/navigation, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ai" = ( /obj/machinery/computer/ship/helm, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aj" = ( /obj/machinery/computer/ship/sensors, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ak" = ( -/obj/machinery/computer/telecomms/server, -/turf/simulated/floor/tiled, +/obj/machinery/network/telecomms_hub{ + initial_network_id = "eduroam" + }, +/turf/floor/tiled, /area/unishi/bridge) "al" = ( /obj/structure/table/reinforced, /obj/item/paper/cig/fancy, /obj/random/action_figure, /obj/machinery/recharger, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "am" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "an" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ao" = ( /obj/effect/floor_decal/cti, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/unishi/bridge) "ap" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aq" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ar" = ( /obj/structure/table/reinforced, /obj/item/trash/chips, /obj/item/trash/driedfish, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "as" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/bridge) "at" = ( /obj/machinery/door/airlock/civilian, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "au" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/item/bedsheet/brown, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "av" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aw" = ( /obj/item/trash/driedfish, /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ax" = ( -/obj/effect/submap_landmark/spawnpoint/unishi_crew, -/turf/simulated/floor/tiled, +/obj/abstract/submap_landmark/spawnpoint/unishi_crew, +/turf/floor/tiled, /area/unishi/bridge) "ay" = ( -/obj/effect/submap_landmark/spawnpoint/unishi_crew, +/obj/abstract/submap_landmark/spawnpoint/unishi_crew, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "az" = ( -/obj/effect/submap_landmark/spawnpoint/unishi_crew, +/obj/abstract/submap_landmark/spawnpoint/unishi_crew, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aA" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aB" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aC" = ( /obj/machinery/shipsensors, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/bridge) "aD" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/bridge) "aE" = ( /obj/structure/closet/crate/internals, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aF" = ( /obj/structure/closet/toolcloset, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aG" = ( /obj/structure/fireaxecabinet, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/unishi/bridge) "aH" = ( /obj/structure/closet/l3closet, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aI" = ( /obj/structure/closet/radiation, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aJ" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aK" = ( /obj/machinery/light/small, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aL" = ( /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aM" = ( /obj/structure/cable{ @@ -192,28 +193,28 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aN" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aO" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aP" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/space) "aQ" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aR" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/bridge) "aS" = ( /obj/machinery/door/airlock/command, @@ -221,28 +222,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "aT" = ( /obj/structure/largecrate, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aU" = ( /obj/structure/closet/crate/med_crate/burn, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aV" = ( /obj/structure/closet/secure_closet/chemical{ req_access = newlist() }, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aW" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/laser, /obj/item/gun/energy/laser, /obj/item/clothing/suit/armor/pcarrier/blue, @@ -251,13 +250,13 @@ /obj/machinery/recharger/wallcharger{ pixel_y = -30 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "aX" = ( /obj/machinery/door/airlock/highsecurity/bolted{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "aY" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -267,177 +266,161 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "aZ" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "ba" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "bb" = ( -/obj/structure/bedsheetbin, +/obj/structure/bedsheetbin/mapped, /obj/structure/closet/wardrobe, /obj/random/handgun, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "bc" = ( /obj/structure/closet/crate/med_crate/toxin, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "bd" = ( /obj/structure/closet/crate/medical, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "be" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/living) "bf" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/living) "bg" = ( -/obj/structure/sign/warning/secure_area/armory, -/turf/simulated/wall, +/obj/structure/sign/warning/armory, +/turf/wall, /area/unishi/living) "bh" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bi" = ( /obj/structure/sign/directions/bridge{ dir = 1 }, -/turf/simulated/wall, +/turf/wall, /area/unishi/living) "bj" = ( /obj/structure/closet/crate/med_crate/trauma, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "bk" = ( /obj/structure/closet/crate/med_crate/oxyloss, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "bl" = ( /obj/structure/fitness/weightlifter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bm" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bo" = ( /obj/structure/railing/mapped, /obj/structure/railing/mapped{ - icon_state = "railing0"; - dir = 8 + dir = 8; + icon_state = "railing0" }, -/turf/simulated/open, +/turf/open, /area/unishi/living) "bp" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bq" = ( /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "br" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bs" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bt" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bu" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/wall, +/turf/wall, /area/unishi/living) "bv" = ( -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "bw" = ( /obj/structure/bed/padded, /obj/item/bedsheet/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bx" = ( /obj/structure/table/steel, /obj/item/modular_computer/tablet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "by" = ( /obj/structure/largecrate, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bz" = ( /obj/structure/closet/crate/bin, /obj/effect/floor_decal/corner/brown{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bA" = ( /obj/structure/closet/jcloset, @@ -445,14 +428,13 @@ /obj/machinery/atmospherics/pipe/zpipe/down/supply, /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers, /obj/structure/cable{ - d1 = 32; icon_state = "32-1" }, -/turf/simulated/open, +/turf/open, /area/unishi/living) "bB" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "bC" = ( /obj/structure/closet, @@ -464,19 +446,19 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bD" = ( -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bE" = ( /obj/machinery/door/airlock/command{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bF" = ( /obj/effect/floor_decal/corner/brown{ @@ -485,14 +467,14 @@ /obj/effect/floor_decal/corner/brown{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bG" = ( /obj/machinery/light, /obj/effect/floor_decal/corner/brown{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -504,7 +486,7 @@ /obj/effect/floor_decal/corner/brown{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -517,10 +499,9 @@ dir = 6 }, /obj/effect/floor_decal/corner/brown{ - icon_state = "corner_white"; dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bJ" = ( /obj/machinery/door/airlock/hatch{ @@ -533,20 +514,19 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "bL" = ( -/obj/structure/bed/chair/janicart, +/obj/structure/janicart, /obj/item/key, /obj/structure/hygiene/sink/kitchen{ dir = 8; @@ -555,13 +535,13 @@ /obj/structure/fireaxecabinet{ pixel_y = 32 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "bM" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/med) "bN" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/med) "bO" = ( /obj/machinery/door/firedoor, @@ -569,31 +549,27 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/cti, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/unishi/living) "bP" = ( /obj/item/stool/padded, -/obj/item/storage/box/lights/bulbs, -/turf/simulated/floor, +/obj/item/box/lights/bulbs, +/turf/floor, /area/unishi/living) "bQ" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "bR" = ( /obj/structure/table/reinforced, -/obj/item/storage/firstaid/surgery, -/obj/item/tank/anesthetic, -/obj/item/clothing/mask/breath/anesthetic, +/obj/item/firstaid/surgery, /obj/structure/window/reinforced{ dir = 4 }, -/obj/item/scalpel/laser1, -/turf/simulated/floor/tiled/white, +/obj/item/scalpel/laser, +/turf/floor/tiled/white, /area/unishi/med) "bS" = ( /obj/structure/closet/medical_wall/filled{ @@ -603,85 +579,81 @@ req_access = newlist() }, /obj/item/defibrillator/loaded, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "bT" = ( /obj/structure/closet/secure_closet/personal/patient, /obj/item/bodybag, /obj/item/bodybag, /obj/item/roller, -/obj/item/storage/chewables/candy/medicallollis, +/obj/item/chewables/candy/medicallollis, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "bU" = ( /obj/structure/closet/radiation, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "bV" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/lounge) "bW" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/lounge) "bX" = ( /obj/random/tool, /obj/random/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/living) "bY" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/living) "bZ" = ( /obj/machinery/door/window, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "ca" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/structure/window/reinforced{ - dir = 2; - health = 1e+007 + current_health = 1e+007 }, /obj/random/medical, /obj/random/medical, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "cb" = ( -/obj/structure/bed/chair/office/dark, -/turf/simulated/floor/tiled/white, +/obj/structure/chair/office/dark, +/turf/floor/tiled/white, /area/unishi/med) "cc" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/bodybag/cryobag, /obj/item/modular_computer/laptop/preset/custom_loadout/advanced, /obj/item/book/manual/medical_diagnostics_manual, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "cd" = ( -/obj/structure/bed/chair/armchair/black, -/turf/simulated/floor/wood, +/obj/structure/chair/armchair/black, +/turf/floor/laminate, /area/unishi/lounge) "ce" = ( /obj/machinery/vending/tool, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/living) "cf" = ( /obj/structure/janitorialcart, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/living) "cg" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -28; req_access = newlist() }, @@ -689,20 +661,19 @@ dir = 4 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor, +/turf/floor, /area/unishi/bridge) "ch" = ( /obj/random/medical/lite, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "ci" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "cj" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -712,11 +683,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "ck" = ( /obj/machinery/door/firedoor, @@ -727,13 +696,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/glass/medical, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/med) "cl" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -743,46 +709,41 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cm" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cn" = ( /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "co" = ( /obj/random/tool, /obj/structure/closet/toolcloset, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/unishi/living) "cp" = ( /obj/structure/bed/padded, /obj/structure/curtain/medical, /obj/item/bedsheet/medical, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "cq" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; pixel_x = 20; req_access = newlist() @@ -790,30 +751,25 @@ /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cr" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/bodyscanner{ - icon_state = "body_scanner_0"; dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "cs" = ( -/obj/structure/sign/bluecross_1, -/turf/simulated/wall, +/obj/structure/sign/department/cross/blue, +/turf/wall, /area/unishi/med) "ct" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -823,16 +779,12 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -842,12 +794,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cv" = ( /obj/machinery/door/airlock/medical{ @@ -861,33 +810,26 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/lounge) "cw" = ( /obj/structure/bed/roller, /obj/structure/iv_drip, /obj/random/medical/lite, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - operating = 1; pixel_y = -28; req_access = newlist() }, /obj/machinery/body_scanconsole{ - icon_state = "body_scannerconsole"; dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/unishi/med) "cx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -897,113 +839,109 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cy" = ( /obj/machinery/vending/games, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cz" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cA" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/space) "cB" = ( /obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "cC" = ( -/obj/structure/bed/chair/padded/brown, +/obj/structure/chair/padded/brown, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/effect/floor_decal/corner/brown{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cD" = ( -/obj/structure/bed/chair/padded/black, -/obj/item/modular_computer/telescreen/preset/generic{ - pixel_y = 30 - }, -/turf/simulated/floor/tiled, +/obj/structure/chair/padded/black, +/obj/machinery/computer/modular/telescreen/preset/generic, +/turf/floor/tiled, /area/unishi/living) "cE" = ( -/obj/structure/bed/chair/padded/black, -/turf/simulated/floor/tiled, +/obj/structure/chair/padded/black, +/turf/floor/tiled, /area/unishi/living) "cF" = ( /obj/structure/noticeboard{ - pixel_y = 25 + default_pixel_y = 25 }, -/obj/structure/bed/chair/padded/black, -/turf/simulated/floor/tiled, +/obj/structure/chair/padded/black, +/turf/floor/tiled, /area/unishi/living) "cG" = ( -/obj/structure/bed/chair/armchair/beige{ +/obj/structure/chair/armchair/beige{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cH" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/cell/crap, /obj/item/stock_parts/circuitboard/gyrotron_control, /obj/item/paper_bin, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cI" = ( /obj/effect/shuttle_landmark/nav_unishi/nav1, /turf/space, /area/space) "cJ" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/trash/raisins, /obj/item/pizzabox/margherita, /obj/random/advdevice, /obj/effect/floor_decal/corner/brown{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cK" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/dice, /obj/item/deck/cards, /obj/item/pen/fancy, /obj/random/tech_supply, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cL" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/board, /obj/item/book/manual/mass_spectrometry, -/obj/item/book/manual/stasis, -/turf/simulated/floor/tiled, +/obj/item/book/fluff/stasis, +/turf/floor/tiled, /area/unishi/living) "cM" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, /obj/item/cell/crap, /obj/item/newspaper, /obj/random/tech_supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1013,7 +951,7 @@ dir = 4 }, /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cO" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1023,89 +961,86 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cP" = ( -/obj/structure/bed/chair/armchair/black{ +/obj/structure/chair/armchair/black{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/lounge) "cQ" = ( -/obj/structure/bed/chair/padded/brown{ +/obj/structure/chair/padded/brown{ dir = 1 }, /obj/effect/floor_decal/corner/brown{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cR" = ( -/obj/structure/bed/chair/padded/black{ +/obj/structure/chair/padded/black{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cS" = ( -/turf/simulated/wall, +/turf/wall, /area/unishi/kitchen) "cT" = ( /obj/effect/floor_decal/corner/brown{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cU" = ( -/obj/effect/submap_landmark/spawnpoint/unishi_researcher, -/turf/simulated/floor/tiled, +/obj/abstract/submap_landmark/spawnpoint/unishi_researcher, +/turf/floor/tiled, /area/unishi/living) "cV" = ( /obj/machinery/vending/dinnerware, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "cW" = ( /obj/structure/hygiene/sink/kitchen{ - pixel_x = 0; pixel_y = 32 }, /obj/machinery/vending/boozeomat{ pixel_x = 32; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "cX" = ( -/obj/structure/bed/chair/padded/brown{ +/obj/structure/chair/padded/brown{ dir = 4 }, /obj/effect/floor_decal/corner/brown{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cY" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/trash/raisins, /obj/item/book/manual/nuclear, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "cZ" = ( -/obj/structure/bed/chair/padded/black{ +/obj/structure/chair/padded/black{ dir = 8 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "da" = ( -/obj/structure/filingcabinet/chestdrawer, +/obj/structure/filing_cabinet/chestdrawer, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "db" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1115,11 +1050,9 @@ dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1129,116 +1062,102 @@ dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dd" = ( /obj/item/stool/bar/padded, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "de" = ( /obj/structure/table/marble, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "df" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dg" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/trash/candy, /obj/machinery/recharger, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dh" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; pixel_x = 20; req_access = newlist() }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "di" = ( /obj/structure/table/marble, /obj/machinery/microwave, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dj" = ( /obj/structure/hygiene/toilet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dk" = ( /obj/structure/hygiene/shower, /obj/structure/curtain/open/shower, /obj/item/soap, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dl" = ( -/obj/structure/table/standard, -/obj/item/storage/laundry_basket, +/obj/structure/table, +/obj/item/laundry_basket, /obj/item/chems/pill/detergent, /obj/item/chems/pill/detergent, -/obj/item/storage/chewables/candy/gum, -/turf/simulated/floor/tiled, +/obj/item/chewables/candy/gum, +/turf/floor/tiled, /area/unishi/living) "dm" = ( /obj/machinery/washing_machine, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dn" = ( /obj/item/trash/driedfish, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "do" = ( /obj/structure/table/marble, /obj/item/book/manual/chef_recipes, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dp" = ( /obj/structure/hygiene/sink{ dir = 8; pixel_x = -15 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -28 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1249,7 +1168,7 @@ }, /obj/random/soap, /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dr" = ( /obj/machinery/door/airlock{ @@ -1261,17 +1180,15 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ds" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dt" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1280,7 +1197,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "du" = ( /obj/item/chems/pill/detergent, @@ -1290,7 +1207,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1300,10 +1217,10 @@ dir = 4 }, /obj/machinery/door/airlock/civilian{ - icon_state = "closed"; - dir = 8 + dir = 8; + icon_state = "closed" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1312,88 +1229,86 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dx" = ( /obj/structure/closet/chefcloset, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dy" = ( /obj/item/mop, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dz" = ( /obj/machinery/door/airlock/freezer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dA" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/unishi/kitchen) "dB" = ( /obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/storage/box/emps, -/obj/item/storage/box/smokes, -/turf/simulated/floor/tiled, +/obj/item/box/emps, +/obj/item/box/smokes, +/turf/floor/tiled, /area/unishi/living) "dC" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/item/ammo_casing/pistol/used, /obj/item/ammo_casing/pistol/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dD" = ( -/obj/structure/table/woodentable, -/obj/item/cane/concealed, +/obj/structure/table/laminate, +/obj/item/cane/fancy/sword, /obj/item/clothing/suit/radiation, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/item/caution, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, /area/unishi/living) "dF" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dG" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/unishi/kitchen) "dH" = ( /obj/structure/reagent_dispensers/beerkeg, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/unishi/kitchen) "dI" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/unishi/kitchen) "dJ" = ( /obj/structure/bed/padded, /obj/item/bedsheet/brown, /obj/item/toy/plushie/kitten, /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -1403,60 +1318,58 @@ /obj/item/ammo_casing/pistol/used, /obj/item/ammo_casing/pistol/used, /obj/item/ammo_casing/pistol/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dL" = ( /obj/structure/bed/padded, /obj/item/bedsheet/green, /obj/item/gun/projectile/pistol/holdout, -/obj/item/storage/secure/briefcase, +/obj/item/secure_storage/briefcase, /obj/item/card/emag_broken, /obj/item/plastique, /obj/item/ammo_casing/pistol/used, /obj/item/ammo_casing/pistol/used, /obj/item/ammo_casing/pistol/used, /obj/item/ammo_casing/pistol/used, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dM" = ( /obj/machinery/vending/cigarette{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dN" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/unishi/kitchen) "dO" = ( /obj/structure/closet/secure_closet/freezer/meat, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/unishi/kitchen) "dP" = ( /obj/structure/closet/crate/freezer, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/unishi/kitchen) "dQ" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dR" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dS" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1466,20 +1379,19 @@ dir = 8 }, /obj/effect/floor_decal/sign/a, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dT" = ( -/obj/item/trash/plate, +/obj/item/plate, /obj/machinery/light/small{ dir = 8 }, /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/kitchen) "dU" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1489,87 +1401,85 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dV" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/item/bedsheet/purple, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dW" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/item/bedsheet/green, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dX" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/item/bedsheet/yellow, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "dZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ea" = ( /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eb" = ( -/obj/structure/table/woodentable, -/obj/item/contraband/poster, -/obj/item/haircomb/random, +/obj/structure/table/laminate, +/obj/item/poster, +/obj/item/grooming/comb/colorable/random, /obj/random/advdevice, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ec" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ed" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ee" = ( /obj/structure/bed/padded, /obj/item/bedsheet/orange, /obj/machinery/light/small, /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ef" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eg" = ( /obj/structure/bed/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eh" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1578,7 +1488,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ei" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1588,15 +1498,15 @@ dir = 4 }, /obj/machinery/door/airlock/civilian{ - icon_state = "closed"; - dir = 8 + dir = 8; + icon_state = "closed" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ej" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ek" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1606,7 +1516,7 @@ dir = 1 }, /obj/effect/floor_decal/sign/b, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "el" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1615,12 +1525,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "em" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "en" = ( /obj/structure/bed/padded, @@ -1629,7 +1539,7 @@ dir = 4 }, /obj/item/bedsheet/orange, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1638,7 +1548,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ep" = ( /obj/machinery/door/airlock, @@ -1649,7 +1559,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1659,7 +1569,7 @@ dir = 4 }, /obj/effect/floor_decal/sign/c, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "er" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1669,23 +1579,23 @@ dir = 4 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "es" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/item/bedsheet/orange, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "et" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/item/bedsheet/purple, /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eu" = ( /obj/structure/bed/padded, @@ -1696,17 +1606,17 @@ }, /obj/item/bedsheet/orange, /obj/machinery/light/small, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ev" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock/civilian, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "ew" = ( /obj/random/maintenance, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ex" = ( /obj/structure/closet/secure_closet/personal/cabinet, @@ -1714,30 +1624,30 @@ /obj/random/clothing, /obj/random/clothing, /obj/random/hat, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "ey" = ( /obj/structure/bed/padded, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "ez" = ( /obj/structure/closet/toolcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eA" = ( /obj/structure/bed/padded, /obj/item/bedsheet/rd, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eB" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, /obj/item/toy/plushie/lizard, /obj/random/advdevice, /obj/random/drinkbottle, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1746,7 +1656,7 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eD" = ( /obj/machinery/door/airlock{ @@ -1759,7 +1669,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eE" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1768,7 +1678,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1778,7 +1688,7 @@ dir = 4 }, /obj/effect/floor_decal/sign/d, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eG" = ( /obj/machinery/door/airlock{ @@ -1791,7 +1701,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1800,30 +1710,30 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eI" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eJ" = ( -/obj/structure/table/woodentable, -/obj/item/haircomb/brush, -/obj/item/lipstick/black, -/obj/item/lipstick/green, -/obj/item/lipstick/violet, +/obj/structure/table/laminate, +/obj/item/grooming/brush, +/obj/item/cosmetics/lipstick/black, +/obj/item/cosmetics/lipstick/green, +/obj/item/cosmetics/lipstick/violet, /obj/random/drinkbottle, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eK" = ( -/obj/structure/bed/chair/office, +/obj/structure/chair/office, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1833,61 +1743,64 @@ dir = 10 }, /obj/structure/closet/crate/bin, -/turf/simulated/floor/tiled, +/obj/item/clothing/suit/space/void, +/obj/item/clothing/head/helmet/space/void, +/obj/item/tank/oxygen, +/turf/floor/tiled, /area/unishi/living) "eM" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eN" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/sign/m, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eP" = ( /obj/structure/coatrack, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "eR" = ( -/obj/structure/bed/chair/office/comfy/black{ +/obj/structure/chair/office/comfy/black{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eS" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/pen/fancy, /obj/random/drinkbottle, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eV" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper_bin, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -1898,7 +1811,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -1909,7 +1822,7 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eY" = ( /obj/structure/safe, @@ -1926,7 +1839,7 @@ /obj/item/cash/c200, /obj/item/cash/c200, /obj/item/grenade/supermatter, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "eZ" = ( /obj/structure/safe, @@ -1939,33 +1852,33 @@ /obj/item/cash/c500, /obj/item/pen/reagent/sleepy, /obj/random/hardsuit, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "fa" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "fb" = ( /obj/effect/wallframe_spawn/reinforced/hull, -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "fc" = ( -/obj/structure/bed/chair/armchair/black, -/turf/simulated/floor/wood, +/obj/structure/chair/armchair/black, +/turf/floor/laminate, /area/unishi/living) "fd" = ( /obj/structure/table/reinforced, -/obj/item/chems/food/drinks/bottle/premiumwine, +/obj/item/chems/drinks/bottle/premiumwine, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "fe" = ( -/obj/effect/landmark/map_data{ +/obj/abstract/map_data{ height = 3 }, /turf/space, @@ -1975,17 +1888,16 @@ /obj/machinery/alarm{ dir = 4; pixel_x = -23; - pixel_y = 0; req_access = newlist() }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "fg" = ( /obj/machinery/door/firedoor, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; pixel_y = -30; req_access = newlist() @@ -1997,10 +1909,9 @@ dir = 4 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "gj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2012,7 +1923,7 @@ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "pd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2020,14 +1931,14 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/living) "pG" = ( /obj/structure/closet/secure_closet/personal/cabinet, /obj/random/contraband, /obj/random/clothing, /obj/random/hat, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "qS" = ( /obj/structure/closet/secure_closet/personal/cabinet, @@ -2035,23 +1946,29 @@ /obj/random/drinkbottle, /obj/random/clothing, /obj/random/hat, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "sS" = ( /obj/structure/closet/secure_closet/personal/cabinet, /obj/random/clothing, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/unishi/living) "ur" = ( /obj/machinery/hologram/holopad/longrange/remoteship, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/unishi/bridge) "vn" = ( /obj/structure/bed/padded, /obj/structure/curtain/open/bed, /obj/item/bedsheet/orange, /obj/random/clothing, -/turf/simulated/floor/tiled, +/turf/floor/tiled, +/area/unishi/living) +"yC" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, /area/unishi/living) "zD" = ( /obj/structure/closet/secure_closet/personal/cabinet, @@ -2060,25 +1977,56 @@ /obj/random/contraband, /obj/random/clothing, /obj/random/hat, -/turf/simulated/floor/wood, +/turf/floor/laminate, +/area/unishi/living) +"AF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, /area/unishi/living) "AK" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, +/area/unishi/living) +"Dj" = ( +/obj/structure/closet/emcloset, +/obj/item/clothing/suit/space/void, +/obj/item/clothing/head/helmet/space/void, +/obj/item/tank/oxygen, +/turf/floor/tiled, +/area/unishi/living) +"Ew" = ( +/obj/structure/closet/emcloset, +/obj/item/clothing/head/helmet/space/void, +/obj/item/clothing/suit/space/void, +/obj/item/tank/oxygen, +/turf/floor/tiled, +/area/unishi/living) +"RG" = ( +/obj/structure/closet/crate/bin, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, /area/unishi/living) "Um" = ( /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/unishi/living) "XA" = ( /obj/structure/railing/mapped, -/turf/simulated/open, +/turf/open, /area/unishi/living) (1,1,1) = {" @@ -6315,9 +6263,9 @@ aO aO aO aO -aO -aO -aO +aP +aP +aP aO aO aO @@ -6931,7 +6879,7 @@ bf bf bf eq -dF +Ew bf bf eD @@ -7025,7 +6973,7 @@ bn ds bn dE -bn +AF dR dU dY @@ -7228,7 +7176,7 @@ bf dm du bf -dF +Dj dM bf dV @@ -7642,7 +7590,7 @@ bf dW ea bf -bq +RG bf es be @@ -7744,7 +7692,7 @@ aP aP aP aP -aP +yC aP aP aP @@ -7947,9 +7895,9 @@ aO aO aO aO -aO -aO -aO +aP +aP +aP aO aO aO diff --git a/maps/away/unishi/unishi.dm b/maps/away/unishi/unishi.dm index f47541de2469..665b85cc7ecf 100644 --- a/maps/away/unishi/unishi.dm +++ b/maps/away/unishi/unishi.dm @@ -1,13 +1,16 @@ #include "unishi_areas.dm" #include "unishi_jobs.dm" +#include "../../../mods/content/integrated_electronics/_integrated_electronics.dme" // this is used for just one prop, todo: remove? +#include "../../../mods/content/xenobiology/_xenobiology.dme" +#include "../../../mods/content/supermatter/_supermatter.dme" +#include "../../../mods/content/beekeeping/_beekeeping.dme" -/obj/effect/submap_landmark/joinable_submap/unishi - name = "SRV Verne" +/obj/abstract/submap_landmark/joinable_submap/unishi + name = "SRV Verne" archetype = /decl/submap_archetype/derelict/unishi /decl/submap_archetype/derelict/unishi - descriptor = "derelict research vessel" - map = "SRV Verne" + name = "derelict research vessel" crew_jobs = list( /datum/job/submap/unishi_crew, /datum/job/submap/unishi_researcher @@ -27,10 +30,9 @@ /datum/map_template/ruin/away_site/unishi name = "University Ship" - id = "awaysite_unishi" - description = "CTI research ship.." + description = "CTI research ship." suffixes = list("unishi/unishi-1.dmm", "unishi/unishi-2.dmm", "unishi/unishi-3.dmm") - cost = 2 + cost = 1 area_usage_test_exempted_root_areas = list(/area/unishi) @@ -47,12 +49,12 @@ landmark_tag = "nav_unishi_3" -/obj/machinery/power/supermatter/randomsample +/obj/structure/supermatter/randomsample name = "experimental supermatter sample" - icon_state = "darkmatter_shard" - base_icon_state = "darkmatter_shard" + icon = 'icons/obj/supermatter_32.dmi' + icon_state = "supermatter_shard" -/obj/machinery/power/supermatter/randomsample/Initialize() +/obj/structure/supermatter/randomsample/Initialize() . = ..() nitrogen_retardation_factor = rand(0.01, 1) //Higher == N2 slows reaction more thermal_release_modifier = rand(100, 1000000) //Higher == more heat released during reaction @@ -67,16 +69,16 @@ charging_factor = rand(0, 1) damage_rate_limit = rand( 1, 10) //damage rate cap at power = 300, scales linearly with power -/obj/machinery/power/supermatter/inert +/obj/structure/supermatter/inert name = "experimental supermatter sample" - icon_state = "darkmatter_shard" - base_icon_state = "darkmatter_shard" + icon = 'icons/obj/supermatter_32.dmi' + icon_state = "supermatter_shard" thermal_release_modifier = 0 //Basically inert product_release_modifier = 100000000000 oxygen_release_modifier = 100000000000 radiation_release_modifier = 1 -/obj/machinery/power/emitter/anchored/on +/obj/machinery/emitter/anchored/on active = 1 powered = 1 @@ -85,15 +87,14 @@ desc = "Are you sure you want to open this?" /obj/structure/closet/crate/secure/large/supermatter/experimentalsm/WillContain() - return list(/obj/machinery/power/supermatter/randomsample) - -obj/item/paper/prof1 - name = "Error log" + return list(/obj/structure/supermatter/randomsample) +/obj/item/paper/prof1 + name = "error log" info = " COMPUTER ID: 15231
    Attempting recovery of document directory.
    Three files recovered
    Printing file (1/2)
    ... about your concerns. I told you that the shielding is strong enough to avoid ANY leaks of radiation or hazardous materials. The entire lab is 100% isolated from the ship in terms of even the air supply. Leave me and my students the fuck alone. Your job is to maintain the fucking reactor an !#@!dqma211.
    File (2/3) Tested SM This thing has a lot of potential. It doesn't produce any measurable levels of gas, or even significant thermal signature. The potential is nearly limitless. We've had to fine tune our activation procedures as even a short beam of the emitter seems to activate this thing. CTI Engineering dept still won't fucking answer where they got this thing, but it's simply amazing. I've sent an ema #@^%da12k" -obj/item/paper/prof2 - name = "Error log" - info = " COMPUTER ID: 15131
    Attempting recovery of document directory.
    Three files recovered
    Printing file (1/2)
    Email to iodc@net
    To whom it may concern,
    I recieved your email today in regards to the research I am conducting. You have no legal right to question our research or attempt to block it. Per article 323, scientific research is protected information, that you have absolutely zero claim to. The compound is secret in composition, but I can fully promise you that it contains absolutely no proprietary molecules, and thus you have no claim whatsoever to it or the technologies to it. Your threats are laughable at best, and have been forwarded to CTI legal. Do not contact me aga!#!41asjw.
    Printing file (2/2)
    Email from fuckyou@12cmal
    We have ways of making you comply. " +/obj/item/paper/prof2 + name = "error log" + info = " COMPUTER ID: 15131
    Attempting recovery of document directory.
    Three files recovered
    Printing file (1/2)
    Email to iodc@net
    To whom it may concern,
    I received your email today in regards to the research I am conducting. You have no legal right to question our research or attempt to block it. Per article 323, scientific research is protected information, that you have absolutely zero claim to. The compound is secret in composition, but I can fully promise you that it contains absolutely no proprietary molecules, and thus you have no claim whatsoever to it or the technologies to it. Your threats are laughable at best, and have been forwarded to CTI legal. Do not contact me aga!#!41asjw.
    Printing file (2/2)
    Email from fuckyou@12cmal
    We have ways of making you comply. " /obj/machinery/computer/log_printer name = "Computer" diff --git a/maps/away/unishi/unishi_jobs.dm b/maps/away/unishi/unishi_jobs.dm index 2105d25e7851..4935f5c928c4 100644 --- a/maps/away/unishi/unishi_jobs.dm +++ b/maps/away/unishi/unishi_jobs.dm @@ -1,10 +1,10 @@ /datum/job/submap/unishi_crew title = "Unishi Crew" total_positions = 1 - outfit_type = /decl/hierarchy/outfit/job/unishi/crew + outfit_type = /decl/outfit/job/unishi/crew supervisors = "your survival" info = "You remember waking up to alarms blaring in your face. Before you could react, a gush of hot air blew \ - you away, knocking you cold unconcious. Before this happened you were a crew member \ + you away, knocking you cold unconscious. Before this happened you were a crew member \ on this research vessel, SRV Verne, as it carried the members of the presitigous Ceti Technical institute in \ their pursuit of research. " required_language = /decl/language/human/common @@ -13,37 +13,34 @@ title = "Unishi Researcher" supervisors = "the crew" total_positions = 2 - outfit_type = /decl/hierarchy/outfit/job/unishi/researcher + outfit_type = /decl/outfit/job/unishi/researcher info = "You remember waking up to alarms blaring in your face. Before you could react, a gush of hot air blew \ - you away, knocking you cold unconcious. Before this happened, you were a researcher, aboard SRV Verne." + you away, knocking you cold unconscious. Before this happened, you were a researcher, aboard SRV Verne." required_language = /decl/language/human/common -#define UNISHI_OUTFIT_JOB_NAME(job_name) ("CTI Research Vessel - Job - " + job_name) -/decl/hierarchy/outfit/job/unishi - hierarchy_type = /decl/hierarchy/outfit/job/unishi +/decl/outfit/job/unishi + abstract_type = /decl/outfit/job/unishi pda_type = /obj/item/modular_computer/pda - pda_slot = slot_l_store + pda_slot = slot_l_store_str l_ear = null r_ear = null -/decl/hierarchy/outfit/job/unishi/crew - name = UNISHI_OUTFIT_JOB_NAME("Unishi Crewman") +/decl/outfit/job/unishi/crew + name = "CTI Research Vessel - Job - Unishi Crewman" r_pocket = /obj/item/radio shoes = /obj/item/clothing/shoes/color/black - belt = /obj/item/storage/belt/utility/full + belt = /obj/item/belt/utility/full -/decl/hierarchy/outfit/job/unishi/researcher - name = UNISHI_OUTFIT_JOB_NAME("Researcher") - uniform = /obj/item/clothing/under/rank/engineer - suit = /obj/item/clothing/suit/storage/toggle/hoodie +/decl/outfit/job/unishi/researcher + name = "CTI Research Vessel - Job - Researcher" + uniform = /obj/item/clothing/jumpsuit/engineer + suit = /obj/item/clothing/suit/jacket/hoodie shoes = /obj/item/clothing/shoes/color/black r_pocket = /obj/item/radio l_pocket = /obj/item/crowbar -/obj/effect/submap_landmark/spawnpoint/unishi_crew +/obj/abstract/submap_landmark/spawnpoint/unishi_crew name = "Unishi Crew" -/obj/effect/submap_landmark/spawnpoint/unishi_researcher +/obj/abstract/submap_landmark/spawnpoint/unishi_researcher name = "Unishi Researcher" - -#undef UNISHI_OUTFIT_JOB_NAME diff --git a/maps/away/yacht/yacht.dm b/maps/away/yacht/yacht.dm index fe131797dd0d..d829a42770a4 100644 --- a/maps/away/yacht/yacht.dm +++ b/maps/away/yacht/yacht.dm @@ -20,10 +20,9 @@ /datum/map_template/ruin/away_site/yacht name = "Yacht" - id = "awaysite_yach" description = "Tiny movable ship with spiders." suffixes = list("yacht/yacht.dmm") - cost = 0.5 + cost = 1 area_usage_test_exempted_root_areas = list(/area/yacht) /obj/effect/shuttle_landmark/nav_yacht/nav1 diff --git a/maps/away/yacht/yacht.dmm b/maps/away/yacht/yacht.dmm index 3d2d24c5231f..74628600be7f 100644 --- a/maps/away/yacht/yacht.dmm +++ b/maps/away/yacht/yacht.dmm @@ -8,17 +8,15 @@ /area/space) "ac" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/bridge) "ad" = ( /obj/machinery/shipsensors, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/tiled/airless/broken, /area/yacht/bridge) "ae" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "af" = ( /obj/effect/shuttle_landmark/nav_yacht/nav2, @@ -29,65 +27,62 @@ /turf/space, /area/space) "ah" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/bridge) "ai" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/computer/ship/helm, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/bridge) "aj" = ( /obj/machinery/computer/ship/sensors{ - icon_state = "computer"; dir = 4 }, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/bridge) "ak" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/structure/bed/chair/comfy/captain, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/structure/chair/comfy/captain, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "al" = ( /obj/machinery/computer/ship/engines{ - icon_state = "computer"; dir = 8 }, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/bridge) "am" = ( /obj/item/folder/blue, /obj/item/form_printer, -/obj/structure/table/woodentable, -/obj/item/chems/food/drinks/glass2/coffeecup, +/obj/structure/table/laminate, +/obj/item/chems/drinks/glass2/coffeecup, /obj/item/newspaper, /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/energy, /obj/item/paper{ info = "I used up all of my energy. I am hopelessly lost. This ship has become my grave. They did it. The intelligence agency that no one ever talks about. Sol Gov wanted their revenge, and they got it. They easily could have killed me on my ship, or tortured me, but they knew that floating here through space would be the worst possible torture. " }, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/bridge) "an" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /mob/living/simple_animal/hostile/giant_spider/hunter, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/bridge) "ao" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/maintenance/clean, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/bridge) "ap" = ( -/obj/structure/filingcabinet/chestdrawer, +/obj/structure/filing_cabinet/chestdrawer, /obj/effect/decal/cleanable/cobweb2, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "aq" = ( /obj/machinery/light{ @@ -96,44 +91,38 @@ /obj/structure/safe, /obj/item/chems/pill/cyanide, /obj/item/rig/medical/equipped, -/obj/item/gun/energy/captain, +/obj/item/gun/energy/retro/captain, /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "ar" = ( /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "as" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "at" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "Yacht bridge"; - pixel_x = 0; pixel_y = -24 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "au" = ( /obj/machinery/light{ @@ -141,39 +130,37 @@ icon_state = "tube1" }, /obj/structure/reagent_dispensers/water_cooler, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/walnut, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/yacht/bridge) "av" = ( -/obj/item/storage/mirror, -/turf/simulated/wall/walnut, +/obj/structure/mirror, +/turf/wall/walnut, /area/yacht/living) "aw" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/door/airlock/silver, -/turf/simulated/floor/wood/yew, +/obj/machinery/door/airlock, +/turf/floor/laminate/yew, /area/yacht/bridge) "ax" = ( -/turf/simulated/wall/walnut, +/turf/wall/walnut, /area/yacht/bridge) "ay" = ( /obj/structure/disposalpipe/segment{ dir = 4; icon_state = "pipe-c" }, -/turf/simulated/wall/walnut, +/turf/wall/walnut, /area/yacht/living) "az" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/living) "aA" = ( /obj/structure/disposalpipe/trunk{ @@ -185,32 +172,30 @@ /turf/space, /area/space) "aB" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/living) "aD" = ( /obj/structure/hygiene/shower{ pixel_y = 20 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/freezer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/freezer, /area/yacht/living) "aE" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aF" = ( -/obj/structure/bed/chair/wood/wings{ +/obj/structure/chair/wood/wings{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aG" = ( /obj/machinery/light{ @@ -219,35 +204,33 @@ /obj/structure/table/marble, /obj/item/trash/snack_bowl, /obj/machinery/reagentgrinder/juicer, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/paper{ info = "Tonight I woke up to a sound I hoped to have never heard, a small explosion. I rushed to the bridge to diagnose the damage and saw the worst possible news. My solar tracker is gone, and so is the fucking computer. No way to override the settings now, because the assholes EMPd the computer. No way to charge my SMES reliably, and no way to heat the fuel. I am stuck in the water! Unheated, this gas will not be enough to get absolutely anywhere near a port. This is bad. Real bad. The current charge on SMES is 20 percent, so I'll just try and orient the ship to hit the current star at maximum efficiency so we will charge at 100, and maybe make it to the next solar system. The next port is in the orbit of a Gas giant named Duma. Maybe I can dock there and repair my array. I freaking knew I needed to get a generator. I spent all of the money the Terrans gave me, and this piece of shit is all I could get. " }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/yacht/living) "aH" = ( /obj/machinery/disposal, /obj/structure/disposalpipe/trunk{ dir = 1 }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/yacht/living) "aI" = ( /obj/item/towel/random, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/freezer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/freezer, /area/yacht/living) "aJ" = ( /obj/structure/hygiene/toilet{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/freezer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/freezer, /area/yacht/living) "aK" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -255,55 +238,55 @@ /obj/machinery/light{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aL" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aM" = ( /obj/structure/table/marble, /obj/item/pizzabox/vegetable, -/obj/item/chems/glass/rag, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/item/chems/rag, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aN" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/junk, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/yacht/living) "aO" = ( /obj/machinery/vending/wallmed1, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/living) "aP" = ( -/obj/machinery/door/airlock/silver, -/turf/simulated/floor/wood, +/obj/machinery/door/airlock, +/turf/floor/laminate, /area/yacht/living) "aQ" = ( /obj/structure/table/marble, /obj/item/deck/cards, /obj/item/dice, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aR" = ( /obj/effect/decal/cleanable/blood/gibs/robot/up, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aS" = ( /obj/structure/table/marble, /obj/machinery/microwave, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aT" = ( /obj/effect/decal/cleanable/cobweb, /obj/effect/spider/stickyweb, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/yacht/living) "aU" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -312,7 +295,7 @@ /obj/effect/decal/cleanable/blood/drip, /obj/effect/spider/stickyweb, /mob/living/simple_animal/hostile/giant_spider/hunter, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/living) "aV" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -323,7 +306,7 @@ }, /obj/effect/decal/cleanable/blood/drip, /obj/effect/spider/stickyweb, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/living) "aW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -332,21 +315,19 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/structure/closet/walllocker/emerglocker/north, +/obj/structure/emergency_dispenser/north, /obj/effect/decal/cleanable/blood/drip, -/obj/machinery/door/airlock/silver, -/turf/simulated/floor/wood/yew, +/obj/machinery/door/airlock, +/turf/floor/laminate/yew, /area/yacht/living) "aX" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -355,8 +336,8 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "aZ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -367,10 +348,10 @@ }, /obj/structure/table/marble, /obj/item/book/manual/chef_recipes, -/obj/item/chems/food/drinks/pitcher, -/obj/effect/decal/cleanable/dirt, +/obj/item/chems/drinks/pitcher, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/drinkbottle, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/yacht/living) "ba" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -378,8 +359,8 @@ }, /obj/effect/decal/cleanable/blood/gibs/robot/down, /obj/effect/decal/cleanable/blood/gibs/robot/up, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bb" = ( /obj/machinery/light{ @@ -387,124 +368,120 @@ icon_state = "tube1" }, /obj/machinery/vending/dinnerware, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bc" = ( /obj/structure/bed/padded, /obj/item/bedsheet/blue, /obj/effect/spider/stickyweb, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/yacht/living) "bd" = ( /obj/effect/spider/stickyweb, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/living) "bf" = ( /obj/effect/decal/cleanable/blood/gibs/robot/limb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bg" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bh" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bk" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/living) "bl" = ( /obj/machinery/light{ dir = 8 }, /obj/effect/spider/stickyweb, -/turf/simulated/floor/beach/water/ocean, +/turf/floor/rock/sand/water, /area/yacht/living) "bm" = ( /obj/effect/spider/stickyweb, -/turf/simulated/floor/beach/water/ocean, +/turf/floor/rock/sand/water, /area/yacht/living) "bn" = ( /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/freezer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/freezer, /area/yacht/living) "bo" = ( -/obj/machinery/door/airlock/silver, -/turf/simulated/floor/tiled/freezer, +/obj/machinery/door/airlock, +/turf/floor/tiled/freezer, /area/yacht/living) "bp" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/paper{ info = "I have accepted my fate. I will go into EVA with one of the cyanide pills in my mouth, and I will float off. I want a military funeral, and I will arrange it myself. Good bye all. I have earned and sealed my fate. " }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/yacht/living) "bq" = ( /obj/structure/bookcase, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "br" = ( /obj/machinery/light/small{ dir = 1 }, /obj/structure/bookcase, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bs" = ( /obj/item/inflatable_duck, /obj/effect/spider/stickyweb, -/turf/simulated/floor/beach/water/ocean, +/turf/floor/rock/sand/water, /area/yacht/living) "bt" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bu" = ( -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bv" = ( /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bw" = ( -/obj/structure/bed/chair/comfy/red{ +/obj/structure/chair/comfy/red{ dir = 4 }, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bx" = ( -/turf/simulated/floor/beach/water/ocean, +/turf/floor/rock/sand/water, /area/yacht/living) "by" = ( /mob/living/simple_animal/hostile/giant_spider/hunter, -/turf/simulated/floor/beach/water/ocean, +/turf/floor/rock/sand/water, /area/yacht/living) "bz" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/freezer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/freezer, /area/yacht/living) "bA" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -514,8 +491,8 @@ dir = 8 }, /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -525,8 +502,8 @@ dir = 4 }, /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -535,8 +512,8 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/machinery/door/airlock/silver, -/turf/simulated/floor/wood/yew, +/obj/machinery/door/airlock, +/turf/floor/laminate/yew, /area/yacht/living) "bD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -545,7 +522,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bE" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -554,191 +531,178 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bF" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/obj/item/storage/bible, +/obj/item/bible, /obj/item/pen/blue, -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper{ info = "Let me introduce myself. My name is Commander Archibald McKinley, although the Fleet fucks think that I do not deserve the title. Well, fuck them. They accused me of facilitating a destruction of the ship I was CO of. A small missile cruiser, with zero to fucking none point defenses was attacked, and they first accuse me of escaping before any of my crew. What kind of person wouldn't expect someone to escape when their ship is on fire? It's lunacy. But it only got worse. Then they said that I helped the Terrans take the ship. Well fuck them, they are wrong. That's non sense. I have no connection to the Terrans. They said that I got a large sum of money from them in order to betray my ship's position, which is once again total nonsense. I've got about 20 years of life left here, and I know that I will be safe with my ship here. I need to resupply once every 5 years, given how much food and fuel I have, and I've got enough range to go to pretty much any known part of the galaxy, in complete silence, as we are totally solar powered. I wish I could afford ion thrusters to not have to rely on gas for propulsion, but, our gas heaters should provide us with enough pressure to get anywhere in relative decent speed. Also, I got a robot butler who cooks delicious food for me! No more crappy lance corporal food, eh" }, /obj/item/flashlight/lamp/green, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bG" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/beach/water/ocean, +/turf/floor/rock/sand/water, /area/yacht/living) "bI" = ( /obj/machinery/light, /obj/item/clothing/shoes/swimmingfins, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/freezer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/freezer, /area/yacht/living) "bJ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood/gibs/robot/limb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bK" = ( /obj/effect/decal/cleanable/blood/gibs/robot/down, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/floodlight, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/yacht/living) "bL" = ( /obj/machinery/light/small, -/obj/structure/filingcabinet, -/turf/simulated/floor/carpet/purple, +/obj/structure/filing_cabinet, +/turf/floor/carpet/purple, /area/yacht/living) "bM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/carpet/purple, +/turf/floor/carpet/purple, /area/yacht/living) "bN" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/engine) "bO" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood/gibs/robot/down, -/obj/machinery/door/airlock/silver, -/turf/simulated/floor/wood/yew, +/obj/machinery/door/airlock, +/turf/floor/laminate/yew, /area/yacht/living) "bP" = ( -/turf/simulated/wall/walnut, +/turf/wall/walnut, /area/yacht/engine) "bQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "bR" = ( /obj/machinery/atmospherics/unary/tank/air, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "bS" = ( -/obj/structure/dispenser/oxygen, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/structure/tank_rack/oxygen, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "bT" = ( /obj/item/cell/hyper, /obj/item/book/manual/engineering_guide, /obj/item/rcd, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/computer/ship/engines, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "bU" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/power/smes/buildable, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "bV" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; name = "Yacht engine"; - pixel_x = 0; pixel_y = 24 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "bW" = ( -/obj/item/extinguisher, +/obj/item/chems/spray/extinguisher, /obj/machinery/portable_atmospherics/hydroponics, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bX" = ( /obj/machinery/vending/hydronutrients, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bY" = ( /obj/machinery/seed_storage/garden, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "bZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/visible/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "ca" = ( /obj/structure/closet/secure_closet/freezer/kitchen, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cb" = ( /obj/machinery/atmospherics/binary/pump, /obj/machinery/space_heater, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cc" = ( /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, /obj/machinery/power/solar, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "cd" = ( /obj/structure/closet/crate/hydroponics, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "ce" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/stock_parts/circuitboard/broken, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "ch" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -748,15 +712,13 @@ dir = 4 }, /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "ci" = ( /obj/structure/cable{ icon_state = "2-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -765,33 +727,31 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cj" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "ck" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cl" = ( /obj/structure/janitorialcart, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cm" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -801,170 +761,132 @@ /obj/machinery/light/small{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "co" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/portable_atmospherics/powered/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "cp" = ( /obj/structure/cable{ - icon_state = "0-2"; dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-2" }, /obj/effect/decal/cleanable/ash, /obj/effect/decal/cleanable/blood/oil/streak, /obj/effect/decal/cleanable/generic, /obj/effect/decal/cleanable/molten_item, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/tiled/airless/broken, /area/yacht/engine) "cq" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/item/stock_parts/circuitboard/broken, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/tiled/airless/broken, /area/yacht/engine) "cr" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/obj/item/storage/toolbox/syndicate, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/obj/item/toolbox/syndicate, +/turf/floor/tiled/airless/broken, /area/yacht/engine) "cs" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/item/plastique, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "ct" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "cu" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "cC" = ( /obj/structure/cable, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "Yacht living"; pixel_x = -24 }, /obj/machinery/portable_atmospherics/hydroponics, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/dirt, -/mob/living/bot/farmbot, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cE" = ( /obj/effect/spider/stickyweb, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cF" = ( /obj/structure/reagent_dispensers/watertank, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/engine) "cK" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -977,17 +899,17 @@ /obj/structure/cable, /obj/machinery/power/solar, /obj/effect/floor_decal/solarpanel, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "cN" = ( /obj/structure/closet/toolcloset, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cQ" = ( /obj/machinery/light{ @@ -995,116 +917,113 @@ }, /obj/machinery/alarm{ dir = 4; - pixel_x = -23; - pixel_y = 0 + pixel_x = -23 }, /obj/machinery/portable_atmospherics/hydroponics, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cR" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/obj/item/shovel/spade, +/obj/item/tool/spade, /obj/item/chems/glass/bucket, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cS" = ( /obj/machinery/light, /obj/structure/reagent_dispensers/beerkeg, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cW" = ( /obj/structure/closet/secure_closet/freezer/kitchen, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "cY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "cZ" = ( /obj/machinery/vending/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "da" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/item/caution/cone, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "db" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dc" = ( /obj/structure/closet/wardrobe/pjs, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "dd" = ( /obj/structure/closet/wardrobe/suit, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) "df" = ( /obj/structure/closet/secure_closet/bar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dg" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/structure/closet/crate/plastic/rations, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "dh" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "di" = ( -/obj/machinery/atmospherics/unary/heater, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/unary/temperature/heater, +/turf/floor/plating, /area/yacht/engine) "dj" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dk" = ( -/obj/machinery/atmospherics/unary/heater, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/unary/temperature/heater, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "dm" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dn" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 6 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "do" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/black, @@ -1112,15 +1031,15 @@ dir = 4; pixel_y = 8 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/meter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dp" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/yacht/engine) "dq" = ( /obj/machinery/atmospherics/unary/vent_pump{ @@ -1137,7 +1056,7 @@ pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/yacht/engine) "dr" = ( /obj/machinery/atmospherics/unary/vent_pump{ @@ -1154,82 +1073,80 @@ pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/yacht/engine) "dt" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/black, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/meter, /obj/machinery/light/small{ - dir = 8; - + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "du" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dv" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "dw" = ( -/obj/machinery/atmospherics/unary/heater{ +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "dx" = ( -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/yacht/engine) "dy" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dz" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black{ - dir = 8; - icon_state = "map" + dir = 8 }, /obj/structure/window/reinforced, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "dA" = ( /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 10 }, /obj/structure/window/reinforced, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/recharge_station, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dC" = ( /obj/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/visible/black{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dD" = ( /obj/structure/window/reinforced, /obj/machinery/atmospherics/pipe/manifold/visible/black{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "dE" = ( /obj/machinery/atmospherics/unary/engine{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "dF" = ( /obj/effect/shuttle_landmark/nav_yacht/nav3, @@ -1244,90 +1161,81 @@ dir = 4; icon_state = "tube1" }, -/obj/item/cane, -/obj/item/clothing/suit/storage/det_trench/grey, -/obj/item/clothing/ring/cti, -/obj/item/clothing/under/lawyer/oldman, -/obj/structure/table/woodentable, +/obj/item/cane/aluminium, +/obj/item/clothing/suit/det_trench/grey, +/obj/item/clothing/gloves/ring/cti, +/obj/item/clothing/costume/oldman, +/obj/structure/table/laminate, /obj/effect/spider/stickyweb, /obj/random/cash, /obj/random/cash, /obj/random/cash, /obj/random/projectile, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/yacht/living) "fb" = ( /obj/machinery/button/access/exterior{ id_tag = "yacht_airlock"; - pixel_x = 24 + pixel_x = 24; + dir = 8 }, /turf/space, /area/space) "gb" = ( /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/constructable_frame/computerframe, /obj/machinery/button/access/interior{ id_tag = "yacht_airlock"; - pixel_x = -24 + pixel_x = -24; + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "hb" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/obj/item/storage/toolbox/electrical, -/obj/effect/decal/cleanable/dirt, +/obj/item/toolbox/electrical, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "ib" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "jb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/door/airlock/external/bolted{ id_tag = "yacht_outer" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "kb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "yacht_airlock"; pixel_y = 24; @@ -1342,126 +1250,112 @@ }, /obj/machinery/airlock_sensor{ id_tag = "yacht_sensor"; - pixel_y = -24 + pixel_y = -24; + dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/yacht/engine) "lb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/machinery/door/airlock/external/bolted{ id_tag = "yacht_inner" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "mb" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1; - icon_state = "map" + dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "nb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/binary/pump{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "ob" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/visible/universal{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "pb" = ( /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "qb" = ( /obj/machinery/atmospherics/binary/pump{ dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/red{ - icon_state = "intact"; dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "rb" = ( /obj/machinery/atmospherics/unary/tank/air{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "sb" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "tb" = ( /obj/structure/closet/firecloset, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "ub" = ( /obj/structure/closet/secure_closet/freezer/meat, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/yacht/engine) "vb" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "wb" = ( /obj/machinery/light/small{ @@ -1471,26 +1365,25 @@ pixel_y = 20 }, /obj/item/bikehorn/rubberducky, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/soap, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/yacht/living) "xB" = ( -/turf/simulated/wall/walnut, +/turf/wall/walnut, /area/yacht/living) "Hj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/yacht/engine) "Ty" = ( /obj/structure/closet/secure_closet/freezer/meat, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood/yew, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/yew, /area/yacht/living) (1,1,1) = {" diff --git a/maps/away_sites_testing/away_sites_testing.dm b/maps/away_sites_testing/away_sites_testing.dm index ec4ae6837263..ab5e2b12a3df 100644 --- a/maps/away_sites_testing/away_sites_testing.dm +++ b/maps/away_sites_testing/away_sites_testing.dm @@ -3,22 +3,23 @@ #include "away_sites_testing_lobby.dm" #include "blank.dmm" - #include "../../mods/government/away_sites/icarus/icarus.dm" - #include "../../mods/corporate/away_sites/lar_maria/lar_maria.dm" - #include "../../mods/ascent/away_sites/ascent/ascent.dm" + #include "../../mods/content/government/away_sites/icarus/icarus.dm" + #include "../../mods/content/government/ruins/ec_old_crash/ec_old_crash.dm" + #include "../../mods/content/generic_shuttles/tanker/tanker.dm" + #include "../../mods/content/corporate/away_sites/lar_maria/lar_maria.dm" - #include "../away/empty.dmm" - #include "../away/mining/mining.dm" - #include "../away/derelict/derelict.dm" #include "../away/bearcat/bearcat.dm" - #include "../away/lost_supply_base/lost_supply_base.dm" - #include "../away/smugglers/smugglers.dm" #include "../away/casino/casino.dm" + #include "../away/derelict/derelict.dm" + #include "../away/errant_pisces/errant_pisces.dm" + #include "../away/lost_supply_base/lost_supply_base.dm" #include "../away/magshield/magshield.dm" - #include "../away/slavers/slavers_base.dm" + #include "../away/mining/mining.dm" #include "../away/mobius_rift/mobius_rift.dm" - #include "../away/errant_pisces/errant_pisces.dm" + #include "../away/smugglers/smugglers.dm" #include "../away/unishi/unishi.dm" + #include "../away/yacht/yacht.dm" + #include "../away/liberia/liberia.dm" #define USING_MAP_DATUM /datum/map/away_sites_testing diff --git a/maps/away_sites_testing/away_sites_testing_define.dm b/maps/away_sites_testing/away_sites_testing_define.dm index fb5bb54f0960..fd1868d5c2ad 100644 --- a/maps/away_sites_testing/away_sites_testing_define.dm +++ b/maps/away_sites_testing/away_sites_testing_define.dm @@ -3,19 +3,28 @@ name = "Away Sites Testing" full_name = "Away Sites Testing Land" path = "away_sites_testing" + overmap_ids = list(OVERMAP_ID_SPACE) + votable = FALSE - station_levels = list() - contact_levels = list() - player_levels = list() + allowed_latejoin_spawns = list() + default_spawn = null - allowed_spawns = list() +/datum/map/away_sites_testing/validate() + return TRUE // Do not check for level lists, this is not a playable map. + +// Set the observer spawn to include every flag so that CI flag checks pass. +/decl/spawnpoint/observer + spawn_flags = (SPAWN_FLAG_GHOSTS_CAN_SPAWN | SPAWN_FLAG_JOBS_CAN_SPAWN | SPAWN_FLAG_PRISONERS_CAN_SPAWN | SPAWN_FLAG_PERSISTENCE_CAN_SPAWN) /datum/map/away_sites_testing/build_away_sites() - var/list/unsorted_sites = list_values(SSmapping.away_sites_templates) + var/list/unsorted_sites = list_values(SSmapping.get_templates_by_category(MAP_TEMPLATE_CATEGORY_AWAYSITE)) var/list/sorted_sites = sortTim(unsorted_sites, /proc/cmp_sort_templates_tallest_to_shortest) - for (var/datum/map_template/ruin/away_site/A in sorted_sites) + for (var/datum/map_template/A in sorted_sites) A.load_new_z() - testing("Spawning [A] in [english_list(GetConnectedZlevels(world.maxz))]") + testing("Spawning [A] in [english_list(SSmapping.get_connected_levels(world.maxz))]") + if(A.template_flags & TEMPLATE_FLAG_TEST_DUPLICATES) + A.load_new_z() + testing("Spawning [A] in [english_list(SSmapping.get_connected_levels(world.maxz))]") /proc/cmp_sort_templates_tallest_to_shortest(var/datum/map_template/a, var/datum/map_template/b) - return b.tallness - a.tallness \ No newline at end of file + return b.tallness - a.tallness diff --git a/maps/away_sites_testing/away_sites_testing_lobby.dm b/maps/away_sites_testing/away_sites_testing_lobby.dm index c14dcef26902..2695a9b0f457 100644 --- a/maps/away_sites_testing/away_sites_testing_lobby.dm +++ b/maps/away_sites_testing/away_sites_testing_lobby.dm @@ -1,2 +1,2 @@ /datum/map/away_sites_testing - lobby_tracks = list(/music_track/absconditus) + lobby_tracks = list(/decl/music_track/absconditus) diff --git a/maps/away_sites_testing/blank.dmm b/maps/away_sites_testing/blank.dmm index 732bb3ccb3e4..22214a0dc964 100644 --- a/maps/away_sites_testing/blank.dmm +++ b/maps/away_sites_testing/blank.dmm @@ -3,23 +3,21 @@ /turf/space, /area/space) "b" = ( -/turf/simulated/wall, +/turf/wall, /area/space) "c" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/space) "d" = ( -/obj/effect/landmark/test/safe_turf, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/latejoin/observer, +/turf/space, /area/space) "e" = ( -/obj/effect/landmark/start{ - name = "JoinLate" - }, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/latejoin, +/turf/floor/tiled, /area/space) -"f" = ( -/obj/effect/landmark/test/space_turf, +"R" = ( +/obj/abstract/level_data_spawner/player, /turf/space, /area/space) @@ -37,6 +35,7 @@ a "} (2,1,1) = {" a +R a a a @@ -44,7 +43,6 @@ a a a a -f a "} (3,1,1) = {" @@ -66,7 +64,7 @@ a a a a -a +d a a a @@ -98,7 +96,7 @@ a (7,1,1) = {" b c -d +c c c b diff --git a/maps/example/example-1.dmm b/maps/example/example-1.dmm index dbcdfd268453..500a16664c7c 100644 --- a/maps/example/example-1.dmm +++ b/maps/example/example-1.dmm @@ -1,1884 +1,3837 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( +"af" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"aL" = ( +/obj/machinery/computer/arcade, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"bK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"bY" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"ck" = ( +/obj/structure/lattice, /turf/space, /area/space) -"b" = ( -/turf/simulated/wall, -/area/constructionsite) -"c" = ( -/turf/simulated/floor/tiled, -/area/constructionsite) -"d" = ( -/obj/machinery/light/spot, -/turf/simulated/floor/tiled, -/area/constructionsite) -"e" = ( -/obj/machinery/light/spot, -/turf/simulated/floor/plating, -/area/shuttle/escape) -"f" = ( -/obj/machinery/light/spot{ - icon_state = "tube_map"; +"co" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"g" = ( -/obj/effect/landmark/start, -/turf/simulated/floor/tiled, -/area/constructionsite) -"h" = ( -/obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 - }, -/obj/machinery/power/apc{ - dir = 8; - name = "west bump"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"i" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"j" = ( -/obj/structure/cable, -/obj/machinery/power/debug_items/infinite_generator, -/turf/simulated/floor/tiled, -/area/constructionsite) -"k" = ( -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/turf/floor/tiled/steel_grid, +/area/example/first) +"cy" = ( +/obj/machinery/vending/snack, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"cF" = ( +/obj/structure/rack, +/obj/item/gun/projectile/revolver, +/obj/item/gun/projectile/revolver, +/obj/item/gun/projectile/revolver, +/turf/floor/tiled/steel_grid, +/area/example/first) +"cS" = ( +/obj/structure/grille, +/turf/space, +/area/space) +"cV" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/shuttle/ferry) +"du" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/light_switch/on{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"dE" = ( +/obj/structure/rack, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/ingot/mapped/gold/ten, +/obj/item/stack/material/segment/mapped/mhydrogen/ten, +/obj/item/stack/material/ingot/mapped/silver/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/gemstone/mapped/diamond/ten, +/obj/item/belt/utility/full, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/turf/floor/tiled/steel_grid, +/area/example/first) +"dK" = ( +/obj/abstract/landmark/latejoin/observer, +/turf/wall/r_wall/prepainted, +/area/example/first) +"eh" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"eZ" = ( +/obj/effect/floor_decal/industrial/warning{ dir = 8 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"l" = ( -/obj/effect/landmark{ - name = "tdome1" - }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"m" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; - dir = 5 +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"n" = ( -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; +/turf/floor/tiled/steel_grid, +/area/example/first) +"fa" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8 }, -/obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled, -/area/constructionsite) -"o" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; +/turf/floor, +/area/example/first) +"fb" = ( +/obj/machinery/computer/shuttle_control{ + shuttle_tag = "Testing Site Ferry" + }, +/turf/floor/plating, +/area/shuttle/ferry) +"fu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"gk" = ( +/obj/machinery/vending/cola, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"gO" = ( +/turf/wall/titanium, +/area/shuttle/ferry) +"gT" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"he" = ( +/obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"p" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled/steel_grid, +/area/example/first) +"hA" = ( +/obj/effect/floor_decal/corner/orange{ dir = 6 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"q" = ( +/turf/floor/tiled/steel_grid, +/area/example/first) +"ii" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"jg" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 4; + id_tag = "example_shuttle_port"; + pixel_x = -19; + tag_door = "example_shuttle_port_hatch" + }, +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 8; + id_tag = "example_shuttle_starboard"; + pixel_x = 19; + tag_door = "example_shuttle_starboard_hatch" + }, +/obj/machinery/light/small, +/turf/floor/plating, +/area/shuttle/ferry) +"jB" = ( +/obj/machinery/door/airlock, +/turf/floor/tiled/steel_ridged, +/area/example/first) +"jP" = ( /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 8 }, +/obj/machinery/portable_atmospherics/canister/air, +/obj/effect/floor_decal/industrial/outline/blue, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"kw" = ( +/obj/abstract/landmark/latejoin, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"la" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "lower_level_dock_hatch_internal" + }, +/turf/floor, +/area/example/first) +"lJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"lN" = ( +/obj/effect/floor_decal/industrial/outline/red, +/obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/canister/empty, -/turf/simulated/floor/tiled, -/area/constructionsite) -"r" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - icon_state = "map_scrubber_on"; +/turf/floor/tiled/dark/monotile, +/area/example/first) +"mc" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"mo" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"mr" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"mu" = ( +/obj/effect/floor_decal/industrial/outline/blue, +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"nL" = ( +/obj/machinery/vending/coffee, +/obj/effect/floor_decal/corner/orange/half{ dir = 1 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"s" = ( +/turf/floor/tiled/dark/monotile, +/area/example/first) +"on" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, -/area/constructionsite) -"t" = ( -/obj/effect/landmark{ - name = "JoinLate" - }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"u" = ( -/obj/machinery/light_switch/on{ - pixel_x = -25 +/turf/floor/tiled/steel_grid, +/area/example/first) +"ou" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor, +/area/example/first) +"oy" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"oz" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"oB" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"oI" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 6 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"v" = ( /obj/machinery/light_switch/on{ - pixel_x = 25 - }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"w" = ( -/obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/tiled, -/area/constructionsite) -"x" = ( -/obj/structure/ladder, -/turf/simulated/floor/tiled, -/area/constructionsite) -"y" = ( -/turf/simulated/wall/iron, -/area/shuttle/escape) -"z" = ( -/obj/effect/wingrille_spawn/reinforced, -/turf/simulated/floor/plating, -/area/shuttle/escape) -"A" = ( -/obj/machinery/computer/shuttle_control{ - shuttle_tag = "Example" + dir = 8; + pixel_x = 24 }, -/turf/simulated/floor/plating, -/area/shuttle/escape) -"B" = ( -/obj/structure/bed/chair{ - dir = 1 +/turf/floor/tiled/steel_grid, +/area/example/first) +"oS" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 6 }, -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - id_tag = "example_shuttle_starboard"; - pixel_x = 28 +/obj/machinery/light{ + dir = 4 }, -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - id_tag = "example_shuttle_port"; - pixel_x = -28 +/turf/floor/tiled/steel_grid, +/area/example/first) +"oZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/light{ + dir = 8 }, -/obj/effect/shuttle_landmark/lower_level, -/turf/simulated/floor/plating, -/area/shuttle/escape) -"C" = ( -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/turf/floor/tiled/steel_grid, +/area/example/first) +"pv" = ( +/obj/structure/rack, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/example/first) +"qs" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ dir = 4 }, -/turf/simulated/floor/tiled, -/area/constructionsite) -"D" = ( +/turf/floor, +/area/example/first) +"qB" = ( +/obj/machinery/teleport/hub, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"qR" = ( +/obj/machinery/debug_items/infinite_generator, +/obj/structure/cable/yellow, +/turf/floor, +/area/example/first) +"rg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor, +/area/example/first) +"rH" = ( /obj/machinery/door/airlock/external/bolted{ - id_tag = "example_shuttle_port_hatch" + id_tag = "example_first_hatch_external" + }, +/turf/floor, +/area/example/first) +"se" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "lower_level_dock_pump" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor, +/area/example/first) +"sQ" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"sT" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/effect/floor_decal/corner/orange/three_quarters, +/turf/floor/tiled/steel_grid, +/area/example/first) +"th" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"tl" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"to" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor, +/area/example/first) +"tq" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "lower_level_dock_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "lower_level_dock_sensor_chamber"; + pixel_x = -22; + dir = 4 }, -/turf/simulated/floor/plating, -/area/shuttle/escape) -"E" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "lower_level_dock"; + pixel_y = 24; + tag_airpump = "lower_level_dock_pump"; + tag_chamber_sensor = "lower_level_dock_sensor_chamber"; + tag_exterior_door = "lower_level_dock_hatch_external"; + tag_interior_door = "lower_level_dock_hatch_internal" + }, +/turf/floor, +/area/example/first) +"tt" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"ty" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/example/first) +"tA" = ( +/obj/abstract/turbolift_spawner/example, +/turf/floor, +/area/turbolift/example/first) +"uD" = ( +/obj/machinery/light, +/turf/floor, +/area/example/first) +"uZ" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor, +/area/example/first) +"vg" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "example_shuttle_starboard_hatch" }, -/turf/simulated/floor/plating, -/area/shuttle/escape) -"F" = ( -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - id_tag = "lower_level_dock"; - pixel_x = -8; - pixel_y = -25 +/turf/floor/plating, +/area/shuttle/ferry) +"vi" = ( +/obj/structure/railing/mapped, +/turf/floor, +/area/example/first) +"vl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 }, -/turf/simulated/floor, -/area/constructionsite) -"G" = ( +/turf/floor/tiled/steel_grid, +/area/example/first) +"vK" = ( /obj/machinery/door/airlock/external/bolted{ - id_tag = "lower_level_dock_hatch" - }, -/turf/simulated/floor, -/area/constructionsite) -"H" = ( -/turf/simulated/floor, -/area/constructionsite) -"I" = ( -/obj/effect/landmark/test/safe_turf, -/turf/simulated/floor/tiled, -/area/constructionsite) -"J" = ( -/obj/effect/landmark/test/space_turf, + id_tag = "lower_level_dock_hatch_internal" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor, +/area/example/first) +"vZ" = ( +/obj/structure/table, +/obj/item/card/id/captains_spare, +/turf/floor/tiled/steel_grid, +/area/example/first) +"wj" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/corner/orange{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"wo" = ( +/obj/structure/ladder, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"wv" = ( +/obj/machinery/door/airlock/external/glass/bolted{ + id_tag = "example_first_hatch_internal" + }, +/turf/floor, +/area/example/first) +"wG" = ( +/obj/machinery/vending/cigarette, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"wP" = ( +/obj/structure/closet/firecloset/chief, +/obj/effect/floor_decal/corner/blue/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"xq" = ( +/obj/abstract/level_data_spawner/main_level{ + name = "Example First Deck" + }, /turf/space, /area/space) -"M" = ( -/obj/structure/table/steel, +"xR" = ( +/obj/structure/ladder, +/turf/floor, +/area/example/first) +"xT" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"ya" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor, +/area/example/first) +"yc" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"yf" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor, +/area/example/first) +"za" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor, +/area/example/first) +"Ae" = ( +/obj/machinery/button/access/interior{ + id_tag = "lower_level_dock"; + pixel_x = -24; + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"AF" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -19 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"AJ" = ( +/obj/effect/shuttle_landmark/lower_level, +/turf/floor/plating, +/area/shuttle/ferry) +"Bp" = ( +/obj/structure/stairs, +/turf/floor, +/area/example/first) +"Bs" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"BE" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/example/first) +"BS" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"BV" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/suit_cycler/engineering/prepared, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"CO" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"CQ" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/example/first) +"CU" = ( +/turf/floor/tiled/steel_grid, +/area/example/first) +"DA" = ( +/obj/structure/table, /obj/machinery/recharger, -/turf/simulated/floor/tiled, -/area/constructionsite) -"Q" = ( -/obj/structure/table/rack, -/obj/item/gun/projectile/automatic/assault_rifle, -/obj/item/gun/projectile/automatic/assault_rifle, -/obj/item/gun/projectile/automatic/assault_rifle, -/turf/simulated/floor/tiled, -/area/constructionsite) -"S" = ( -/obj/structure/table/rack, -/obj/item/gun/energy/laser, -/obj/item/gun/energy/laser, -/obj/item/gun/energy/laser, -/turf/simulated/floor/tiled, -/area/constructionsite) -"V" = ( -/obj/structure/table/rack, -/obj/item/gun/projectile/revolver, -/obj/item/gun/projectile/revolver, -/obj/item/gun/projectile/revolver, -/turf/simulated/floor/tiled, -/area/constructionsite) -"X" = ( -/obj/structure/table/rack, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Ed" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 26 + }, +/turf/floor, +/area/example/first) +"Eh" = ( +/obj/structure/table, +/obj/item/backpack/holding, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Er" = ( +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/example/first) +"EM" = ( +/obj/structure/closet/secure_closet/captains, +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Ft" = ( +/obj/machinery/fabricator/hacked, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/example/first) +"FZ" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor, +/area/example/first) +"Gg" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor, +/area/example/first) +"Hk" = ( +/turf/space, +/area/space) +"HA" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/effect/floor_decal/industrial/outline/red, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"HB" = ( +/obj/machinery/computer/teleporter, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"IR" = ( +/obj/effect/floor_decal/corner/orange/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Jc" = ( +/obj/machinery/door/airlock/glass, +/turf/floor/tiled/steel_ridged, +/area/example/first) +"Jn" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "lower_level_dock_hatch_external" + }, +/obj/machinery/button/access/exterior{ + id_tag = "lower_level_dock"; + pixel_y = -24; + dir = 8; + pixel_x = -12; + directional_offset = null + }, +/turf/floor, +/area/example/first) +"JH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor, +/area/example/first) +"JS" = ( +/obj/structure/closet/secure_closet/hos, +/obj/effect/floor_decal/corner/blue/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"Kn" = ( +/obj/structure/stairs{ + dir = 1 + }, +/turf/floor, +/area/example/first) +"KJ" = ( +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 4; + name = "west bump"; + pixel_x = 24 + }, +/turf/floor, +/area/example/first) +"KT" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"La" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Ly" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"LM" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor, +/area/example/first) +"LP" = ( +/turf/floor/plating, +/area/turbolift/example/first) +"LW" = ( +/obj/machinery/teleport/station, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"Mc" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 26 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Nu" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled/steel_grid, +/area/example/first) +"NC" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/example/first) +"NL" = ( +/obj/effect/floor_decal/corner/orange/three_quarters, +/turf/floor/tiled/steel_grid, +/area/example/first) +"OI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/example/first) +"OZ" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/effect/floor_decal/industrial/outline/red, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"Pp" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor, +/area/example/first) +"Pv" = ( +/obj/structure/rack, /obj/item/gun/projectile/shotgun/pump, /obj/item/gun/projectile/shotgun/pump, /obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/tiled, -/area/constructionsite) -"Z" = ( -/turf/simulated/wall/r_wall, -/area/space) +/turf/floor/tiled/steel_grid, +/area/example/first) +"PE" = ( +/obj/item/radio/beacon, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/orange, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"Qc" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/corner/blue/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"Rj" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"RB" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/example/first) +"RF" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/obj/effect/floor_decal/corner/orange/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"RV" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/light_switch/on{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"RW" = ( +/turf/floor, +/area/turbolift/example/first) +"Ss" = ( +/obj/structure/tank_rack/oxygen, +/obj/effect/floor_decal/corner/orange/half{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"Sv" = ( +/obj/structure/table, +/turf/floor, +/area/example/first) +"Tk" = ( +/obj/structure/closet/secure_closet/hop, +/obj/effect/floor_decal/corner/orange{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Ts" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Uw" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air, +/obj/effect/floor_decal/industrial/outline/blue, +/turf/floor/tiled/dark/monotile, +/area/example/first) +"UH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"VY" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"We" = ( +/obj/machinery/suit_cycler/security/prepared{ + initial_access = list() + }, +/turf/floor, +/area/example/first) +"Wi" = ( +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Wj" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Wr" = ( +/turf/floor/tiled/steel_ridged, +/area/example/first) +"WF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor, +/area/example/first) +"WK" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"WS" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor, +/area/example/first) +"WU" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor, +/area/example/first) +"WW" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/example/first) +"XZ" = ( +/turf/wall/r_wall/prepainted, +/area/example/first) +"Yo" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Yp" = ( +/turf/floor, +/area/example/first) +"Yt" = ( +/obj/structure/rack, +/obj/item/gun/projectile/automatic/assault_rifle, +/obj/item/gun/projectile/automatic/assault_rifle, +/obj/item/gun/projectile/automatic/assault_rifle, +/turf/floor/tiled/steel_grid, +/area/example/first) +"Zi" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/example/first) +"ZF" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "example_shuttle_port_hatch" + }, +/turf/floor/plating, +/area/shuttle/ferry) +"ZO" = ( +/obj/machinery/door/airlock/external/glass/bolted{ + id_tag = "example_first_hatch_internal" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor, +/area/example/first) +"ZV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor, +/area/example/first) (1,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +xq "} (2,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (3,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (4,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (5,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (6,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (7,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (8,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (9,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (10,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (11,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +BE +BE +BE +BE +BE +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (12,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +Yp +Yp +Yp +Yp +Yp +to +Yp +Yp +Yp +Yp +Yp +Yp +Yp +to +Yp +Yp +Yp +Yp +Yp +Yp +Yp +Yp +to +Yp +Yp +Yp +Yp +Yp +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (13,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -y -z -z -D -y -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +BE +BE +BE +BE +BE +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (14,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -y -A -B -e -y -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Yp +Yp +Bp +Gg +Yp +XZ +tl +tl +tl +tl +tl +tl +NL +XZ +RF +La +La +Ts +La +La +La +La +Ts +La +La +sT +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (15,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -y -z -z -E -y -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Yp +Yp +uZ +Yp +Yp +XZ +CU +CU +CU +CU +CU +CU +ii +XZ +wj +Yp +Yp +Yp +Yp +xR +Yp +Yp +Yp +Yp +Yp +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (16,1,1) = {" -a -a -a -a -a -a -a -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -b -G -b -Z -Z -Z -Z -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +za +Yp +Yp +Yp +Yp +jB +CU +CU +CU +CU +CU +CU +CU +jB +WW +Yp +yf +ZV +Yp +Yp +Yp +Yp +rg +WU +Yp +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (17,1,1) = {" -a -a -a -a -a -a -a -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -b -F -b -Z -Z -Z -Z -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Yp +Yp +Yp +Yp +Yp +XZ +CU +CU +CU +CU +CU +CU +ty +XZ +Ly +Yp +Yp +WF +Yp +Yp +Yp +Yp +WF +Yp +Yp +Zi +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (18,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -b -b -b -b -b -b -b -b -H -b -b -b -b -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +za +XZ +Yp +Yp +Yp +Yp +Yp +XZ +lN +lJ +OI +eh +CU +CU +ii +XZ +wj +Yp +Yp +WF +Yp +Yp +Yp +Yp +WF +Yp +Yp +Bs +XZ +uD +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (19,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -c -c -k -c -c -u -c -c -k -h -i -j -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +Wr +Wr +Wr +XZ +wj +Yp +Yp +WF +Yp +Yp +Yp +Yp +WF +Yp +Yp +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (20,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -l -l -l -c -c -c -c -c -c -c -c -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +Hk +Hk +Hk +Hk +Hk +Hk +XZ +EM +oy +tl +XZ +Wj +CU +ii +XZ +wj +Yp +Yp +WF +Yp +Yp +Yp +Yp +WF +Yp +We +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (21,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -l -l -l -c -c -c -c -c -t -t -t -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +Hk +Hk +Hk +Hk +Hk +Hk +BE +Er +CU +CU +BE +CU +CU +AF +XZ +wj +Yp +Yp +WF +Yp +Yp +Yp +Yp +WF +Yp +Sv +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (22,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -f -l -l -l -c -c -c -c -c -t -t -t -d -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +Hk +Hk +Hk +Hk +Hk +Hk +BE +Er +CU +CU +BE +CU +CU +ii +XZ +Ly +Yp +Yp +WF +Yp +Yp +Yp +ya +WF +Yp +Sv +Zi +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (23,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -c -c -x -c -c -c -I -c -t -t -t -c -b -Z -Z -J -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +Hk +Hk +Hk +Hk +Hk +Hk +BE +vZ +CU +CU +Jc +CU +CU +CU +Jc +WW +Yp +yf +ou +Yp +Yp +vi +Kn +JH +WU +Sv +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (24,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -w -w -w -c -c -c -c -c -c -c -c -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +gO +gO +ZF +gO +gO +Hk +BE +Eh +CU +CU +BE +CU +CU +ii +XZ +wj +Yp +Yp +WF +Yp +Yp +Yp +uZ +WF +Yp +Sv +Bs +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (25,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -b -w -w -c -c -g -c -c -c -c -Q -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +cV +fb +AJ +jg +gO +Hk +BE +Er +CU +CU +BE +CU +CU +ii +XZ +yc +Yo +Yo +oB +Yo +Yo +Yo +Yo +oB +Yo +Yo +bY +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (26,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -w -w -w -c -c -c -c -c -c -c -V -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +cS +Hk +gO +gO +vg +gO +gO +Hk +XZ +Tk +oS +hA +XZ +Wj +CU +ii +XZ +wo +oI +Uw +UH +CU +CU +CU +CU +af +OZ +hA +IR +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (27,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -c -c -c -c -c -c -c -c -c -c -S -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +XZ +XZ +XZ +Jn +XZ +BE +XZ +XZ +XZ +XZ +XZ +XZ +Wr +Wr +Wr +dK +XZ +XZ +XZ +XZ +Wr +Wr +Wr +Wr +XZ +XZ +XZ +XZ +XZ +uD +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (28,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -f -c -c -c -c -c -c -c -c -c -c -X -d -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +tq +ZV +la +Ae +CU +XZ +mu +oZ +OI +co +CU +CU +ii +XZ +HB +tl +NC +to +Yp +Yp +Yp +Yp +to +Yp +Yp +Yp +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (29,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -c -c -c -s -m -c -p -r -c -c -M -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +se +qs +vK +vl +CU +jB +CU +CU +CU +CU +CU +CU +ty +XZ +LW +CU +WW +Yp +RB +BS +eZ +CO +Yp +WK +Yo +RV +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (30,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -c -c -c -c -o -c -o -c -c -c -c -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +XZ +XZ +XZ +bK +CU +XZ +wG +CU +CU +CU +CU +CU +ii +XZ +qB +CU +WW +Yp +VY +kw +kw +WW +Yp +VY +CU +dE +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (31,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -c -c -v -C -c -n -c -q -c -C -c -c -c -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +sQ +OI +OI +fu +CU +XZ +nL +CU +CU +CU +CU +CU +AF +XZ +PE +CU +WW +Yp +VY +kw +kw +WW +Yp +VY +CU +Ft +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (32,1,1) = {" -a -a -a -a -a -a -a -Z -Z -b -b -b -b -b -b -b -b -b -b -b -b -b -b -b -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +BV +CU +CU +CU +CQ +XZ +gk +CU +CU +CU +CU +CU +CU +Jc +CU +CU +WW +Yp +VY +kw +kw +WW +Yp +VY +CU +DA +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (33,1,1) = {" -a -a -a -a -a -a -a -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Ss +CU +CU +CU +CU +XZ +cy +CU +CU +CU +CU +CU +CU +Jc +CU +CU +WW +Yp +VY +kw +kw +WW +Yp +VY +CU +Yt +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (34,1,1) = {" -a -a -a -a -a -a -a -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -Z -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +XZ +Jc +XZ +Jc +XZ +XZ +aL +th +CU +CU +CU +th +CU +Jc +CU +CU +WW +Yp +VY +kw +kw +WW +Yp +VY +CU +cF +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (35,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +za +XZ +Yp +Yp +Yp +Yp +Yp +XZ +XZ +XZ +XZ +Wr +XZ +XZ +XZ +XZ +mc +xT +gT +Pp +VY +kw +kw +WW +Yp +VY +CU +pv +XZ +uD +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (36,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Yp +Yp +Yp +Yp +Yp +XZ +wP +mr +CU +CU +CU +KT +oz +XZ +LP +LP +tA +LM +VY +kw +kw +WW +Yp +VY +CU +Pv +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (37,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +za +Yp +Yp +Yp +Yp +XZ +JS +CU +CU +CU +CU +CU +oz +XZ +LP +LP +RW +LM +on +he +tt +Rj +Yp +mo +xT +du +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (38,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Yp +Yp +Yp +Yp +Yp +XZ +Qc +CU +CU +CU +CU +CU +oz +XZ +LP +LP +RW +LM +Yp +WF +WF +Yp +Yp +Yp +Yp +Yp +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (39,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +Yp +Yp +Yp +Yp +Yp +XZ +Qc +CU +Nu +vl +Mc +CU +oz +XZ +Wi +Wi +Wi +FZ +Yp +jP +HA +Yp +WS +KJ +Ed +qR +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (40,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +ZO +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (41,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +Yp +Yp +Yp +Yp +Yp +Yp +WS +Yp +Yp +Yp +wv +fa +wv +Yp +WS +Yp +Yp +Yp +Yp +Yp +Yp +Yp +Yp +WS +Yp +Yp +Yp +Yp +Yp +Yp +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (42,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +rH +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +XZ +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (43,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (44,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +ck +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (45,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (46,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (47,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} (48,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +"} +(49,1,1) = {" +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +"} +(50,1,1) = {" +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +"} +(51,1,1) = {" +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +"} +(52,1,1) = {" +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk +Hk "} diff --git a/maps/example/example-2.dmm b/maps/example/example-2.dmm index 36d0de0487e3..51b091fc0d04 100644 --- a/maps/example/example-2.dmm +++ b/maps/example/example-2.dmm @@ -1,1996 +1,3534 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/space, -/area/space) -"ab" = ( -/obj/effect/landmark/map_data{ - height = 2 +"aj" = ( +/obj/structure/table/glass, +/obj/item/chems/dropper, +/obj/item/stack/nanopaste, +/obj/effect/floor_decal/corner/blue/mono, +/obj/machinery/light/small{ + dir = 4 }, -/turf/space, -/area/space) -"ac" = ( -/turf/simulated/wall, -/area/medical/surgery) -"ad" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/iv_drip, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OMinus, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ae" = ( -/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/white/monotile, +/area/example/second) +"bU" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_ridged, +/area/example/second) +"cb" = ( +/obj/effect/floor_decal/corner/mauve{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/example/second) +"cH" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"af" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/computer/operating, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ag" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/table/glass, -/obj/item/storage/box/syringes, -/obj/item/storage/box/freezer, -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"dh" = ( +/obj/machinery/design_database, +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"dz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor, +/area/example/second) +"es" = ( +/obj/machinery/light, +/turf/open, +/area/example/second) +"fJ" = ( +/obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ah" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/table/glass, -/obj/item/storage/box/gloves, -/obj/item/storage/box/masks, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ai" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aj" = ( -/obj/structure/lattice, -/turf/simulated/open, -/area/medical/surgery) -"ak" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "upper_level_dock_pump" + }, +/turf/floor, +/area/example/second) +"fS" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 4 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"fU" = ( +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor, +/area/example/second) +"fX" = ( +/obj/machinery/alarm{ + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"gl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/example/second) +"gs" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ dir = 1 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"al" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/table/glass, -/obj/item/storage/firstaid/surgery, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"am" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/hygiene/sink{ - icon_state = "sink"; +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/example/second) +"hM" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor, +/area/example/second) +"ii" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "upper_level_dock_hatch_internal" + }, +/turf/floor, +/area/example/second) +"iS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"an" = ( -/turf/simulated/open, -/area/medical/surgery) -"ao" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/table/glass, -/obj/item/chems/dropper, -/obj/item/stack/nanopaste, -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/obj/machinery/alarm{ + dir = 1; + pixel_y = -19 + }, +/turf/floor/tiled/white, +/area/example/second) +"iY" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/structure/railing/mapped, +/turf/floor/tiled/white, +/area/example/second) +"jd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"jr" = ( +/obj/effect/floor_decal/industrial/warning/dust/corner{ dir = 8 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ap" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/body_scanconsole{ - icon_state = "body_scannerconsole"; +/obj/effect/floor_decal/corner/orange{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"jW" = ( +/obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aq" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/bodyscanner{ - icon_state = "body_scanner_0"; +/turf/floor/tiled/dark/monotile, +/area/example/second) +"kf" = ( +/obj/machinery/fabricator/robotics, +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"kx" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "upper_level_dock_hatch_external" + }, +/obj/machinery/button/access/exterior{ + id_tag = "upper_level_dock"; + pixel_y = -24; + dir = 4; + pixel_x = 12; + directional_offset = null + }, +/turf/floor, +/area/example/second) +"lm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ar" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/sleeper/standard{ - icon_state = "sleeper_0"; +/turf/floor/tiled/white, +/area/example/second) +"ln" = ( +/obj/effect/floor_decal/industrial/warning/dust/corner, +/obj/effect/floor_decal/corner/orange/three_quarters{ dir = 8 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"as" = ( -/obj/machinery/light_switch/on{ - pixel_x = 25 +/turf/floor/tiled/steel_grid, +/area/example/second) +"lJ" = ( +/turf/floor, +/area/example/second) +"lP" = ( +/turf/floor/tiled/white, +/area/example/second) +"mC" = ( +/obj/effect/floor_decal/corner/orange, +/turf/floor/tiled/steel_grid, +/area/example/second) +"nz" = ( +/obj/machinery/light{ + dir = 1 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"at" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/table/glass, -/obj/item/scalpel/laser1, -/obj/item/scalpel/laser2, -/obj/item/scalpel/laser3, -/obj/item/robotanalyzer, -/obj/item/scanner/health, -/obj/item/storage/firstaid/adv, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"au" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/ladder, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"av" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/atmospherics/unary/freezer, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aw" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/fabricator/industrial, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ax" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, +/turf/floor/tiled/steel_grid, +/area/example/second) +"nB" = ( +/obj/effect/shuttle_landmark/upper_level, +/turf/open, +/area/space) +"nC" = ( +/obj/effect/floor_decal/corner/mauve/mono, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/example/second) +"nO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/example/second) +"oi" = ( +/obj/structure/tank_rack/oxygen, +/obj/machinery/light, +/turf/floor/tiled/dark/monotile, +/area/example/second) +"oC" = ( +/obj/machinery/suit_cycler/engineering/prepared, +/turf/floor/tiled/dark/monotile, +/area/example/second) +"oI" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/example/second) +"oS" = ( +/turf/open, +/area/space) +"pc" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/example/second) +"pk" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor, +/area/example/second) +"pr" = ( +/obj/machinery/computer/operating{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"ps" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "upper_level_dock_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "upper_level_dock_sensor_chamber"; + pixel_x = 22; + dir = 8 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "upper_level_dock"; + pixel_y = 24; + tag_airpump = "upper_level_dock_pump"; + tag_chamber_sensor = "upper_level_dock_sensor_chamber"; + tag_exterior_door = "upper_level_dock_hatch_external"; + tag_interior_door = "upper_level_dock_hatch_internal" + }, +/turf/floor, +/area/example/second) +"pt" = ( +/obj/effect/floor_decal/industrial/warning/dust/corner{ + dir = 4 + }, +/obj/effect/floor_decal/corner/orange/three_quarters, +/turf/floor/tiled/steel_grid, +/area/example/second) +"qk" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/example/second) +"qA" = ( +/obj/effect/floor_decal/industrial/warning/dust, +/obj/effect/floor_decal/corner/orange{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"qV" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"qW" = ( /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ay" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/obj/machinery/portable_atmospherics/canister/air, +/obj/effect/floor_decal/industrial/outline/blue, +/obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"az" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/closet/secure_closet/freezer/meat, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aA" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/fabricator/industrial, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aB" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/atmospherics/pipe/simple/visible/blue{ - icon_state = "intact"; +/turf/floor/tiled/dark/monotile, +/area/example/second) +"rb" = ( +/obj/effect/floor_decal/corner/blue/mono, +/obj/machinery/sleeper/standard, +/turf/floor/tiled/white/monotile, +/area/example/second) +"rn" = ( +/obj/machinery/door/airlock, +/turf/floor/tiled/steel_ridged, +/area/example/second) +"sA" = ( +/turf/floor/tiled/steel_ridged, +/area/example/second) +"sO" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "upper_level_dock_hatch_internal" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor, +/area/example/second) +"sT" = ( +/obj/effect/floor_decal/corner/mauve{ dir = 5 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aC" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/atmospherics/pipe/manifold/visible/blue, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aD" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/atmospherics/pipe/simple/visible/blue{ - icon_state = "intact"; +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/example/second) +"sV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/button/access/interior{ + id_tag = "upper_level_dock"; + pixel_x = 24; + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"sY" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 4 + }, +/obj/effect/floor_decal/corner/orange{ dir = 9 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aE" = ( -/obj/machinery/atmospherics/unary/vent_pump/on, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aF" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/organ_printer/flesh/mapped, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aG" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; - dir = 5 +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"ug" = ( +/obj/abstract/level_data_spawner/main_level{ + name = "Example Second Deck" + }, +/turf/space, +/area/space) +"uk" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 8 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aH" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; +/obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aI" = ( -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; +/turf/floor/tiled/steel_grid, +/area/example/second) +"un" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor, +/area/example/second) +"uF" = ( +/obj/effect/floor_decal/industrial/warning/dust{ dir = 8 }, -/obj/machinery/portable_atmospherics/canister/air, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aJ" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/organ_printer/robot/mapped, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aK" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/table/rack, -/obj/item/stack/material/plasteel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/gold/ten, -/obj/item/stack/material/mhydrogen/ten, -/obj/item/stack/material/silver/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/diamond/ten, -/obj/item/storage/belt/utility/full, -/obj/item/stack/material/steel/fifty, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aL" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; +/turf/floor/tiled/steel_grid, +/area/example/second) +"wP" = ( +/turf/open, +/area/example/second) +"xk" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/open, +/area/example/second) +"xs" = ( +/turf/space, +/area/space) +"xD" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"xX" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"ys" = ( +/obj/structure/table/glass, +/obj/item/box/syringes, +/obj/item/box/freezer, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"yy" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/example/second) +"yE" = ( +/turf/floor/tiled/dark/monotile, +/area/example/second) +"zG" = ( +/obj/effect/floor_decal/industrial/warning/dust/corner{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Am" = ( +/obj/machinery/light, +/turf/floor, +/area/example/second) +"Ba" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"BG" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/example/second) +"BY" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Ci" = ( +/obj/machinery/debug_items/infinite_generator, +/obj/structure/cable/yellow, +/turf/floor/tiled/white, +/area/example/second) +"Cq" = ( +/obj/machinery/light_switch/on{ + dir = 1; + pixel_y = -20 + }, +/turf/floor/tiled/white, +/area/example/second) +"Cu" = ( +/obj/effect/floor_decal/corner/orange{ dir = 6 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aM" = ( -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; +/turf/floor/tiled/steel_grid, +/area/example/second) +"CN" = ( +/obj/effect/floor_decal/corner/mauve{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/example/second) +"CW" = ( +/turf/floor/tiled/steel_grid, +/area/example/second) +"CX" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/example/second) +"Dt" = ( +/obj/effect/floor_decal/corner/blue/mono, +/obj/structure/closet/secure_closet/freezer/meat, +/turf/floor/tiled/white/monotile, +/area/example/second) +"En" = ( +/obj/machinery/bodyscanner{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"EO" = ( +/obj/machinery/fabricator/protolathe, +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"FE" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Gn" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor, +/area/example/second) +"Gy" = ( +/obj/effect/floor_decal/corner/orange/three_quarters{ dir = 8 }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"GG" = ( +/obj/structure/railing/mapped, +/turf/open, +/area/example/second) +"GP" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, /obj/machinery/portable_atmospherics/canister/empty, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aN" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aO" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - icon_state = "map_scrubber_on"; +/obj/effect/floor_decal/industrial/outline/red, +/turf/floor/tiled/dark/monotile, +/area/example/second) +"Hn" = ( +/obj/structure/table/glass, +/obj/item/box/gloves, +/obj/item/box/masks, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Hp" = ( +/obj/structure/grille, +/turf/space, +/area/space) +"JU" = ( +/obj/structure/table/glass, +/obj/item/scalpel/laser, +/obj/item/scalpel/laser/upgraded, +/obj/item/scalpel/laser/advanced, +/obj/item/robotanalyzer, +/obj/item/scanner/health, +/obj/item/firstaid/adv, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Lq" = ( +/obj/structure/stairs{ dir = 1 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aP" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light/spot{ - icon_state = "tube_map"; - dir = 8 +/turf/floor/tiled/white, +/area/example/second) +"Lz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aQ" = ( -/obj/machinery/light/spot, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/fabricator/protolathe, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aR" = ( -/obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 - }, -/obj/machinery/power/apc{ - dir = 8; - name = "west bump"; - pixel_x = -24 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aS" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aT" = ( -/obj/structure/cable, -/obj/machinery/power/debug_items/infinite_generator, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aU" = ( -/obj/machinery/light/spot, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aV" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/fabricator/robotics, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aW" = ( -/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/white, +/area/example/second) +"LK" = ( +/obj/structure/table/glass, +/obj/item/firstaid/surgery, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"LX" = ( /obj/machinery/fabricator/imprinter, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aX" = ( -/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Nj" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 1 + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/obj/machinery/light/small, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Ny" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor, +/area/example/second) +"NY" = ( +/obj/structure/ladder, +/turf/open, +/area/example/second) +"Pc" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Qn" = ( /obj/machinery/destructive_analyzer, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"aZ" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light_switch/on{ - pixel_x = -25 +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"QJ" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"QU" = ( +/obj/structure/rack, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/ingot/mapped/gold/ten, +/obj/item/stack/material/segment/mapped/mhydrogen/ten, +/obj/item/stack/material/ingot/mapped/silver/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/gemstone/mapped/diamond/ten, +/obj/item/belt/utility/full, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"SQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Uf" = ( +/obj/effect/floor_decal/corner/orange/three_quarters{ + dir = 4 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"ba" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/design_database{ +/turf/floor/tiled/steel_grid, +/area/example/second) +"UN" = ( +/obj/machinery/computer/design_console{ dir = 1 }, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) -"qL" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/computer/design_console, -/turf/simulated/floor/tiled/white, -/area/medical/surgery) +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Vm" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 4 + }, +/turf/floor, +/area/example/second) +"VG" = ( +/obj/machinery/fabricator/bioprinter, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"VL" = ( +/turf/open, +/area/turbolift/example/second) +"WW" = ( +/obj/effect/floor_decal/corner/mauve/mono, +/obj/machinery/recycler, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Xm" = ( +/obj/structure/iv_drip, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Xw" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/open, +/area/example/second) +"XE" = ( +/turf/wall/r_wall/prepainted, +/area/example/second) +"XR" = ( +/obj/effect/floor_decal/corner/orange{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/second) +"Yn" = ( +/obj/machinery/fabricator/industrial, +/obj/effect/floor_decal/corner/mauve/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"Yy" = ( +/turf/floor/shuttle_ceiling, +/area/space) +"YT" = ( +/obj/effect/floor_decal/corner/mauve{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/apc{ + dir = 1; + pixel_y = 21 + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/floor/tiled/white, +/area/example/second) +"ZD" = ( +/obj/machinery/body_scanconsole{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/mono, +/turf/floor/tiled/white/monotile, +/area/example/second) +"ZI" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled/dark/monotile, +/area/example/second) (1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +ug "} (2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +pc +pc +pc +pc +pc +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +lJ +lJ +lJ +lJ +lJ +hM +lJ +lJ +lJ +lJ +lJ +lJ +lJ +hM +lJ +lJ +lJ +lJ +lJ +lJ +lJ +lJ +hM +lJ +lJ +lJ +lJ +lJ +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +XE +XE +XE +XE +XE +XE +XE +sA +sA +sA +sA +sA +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +wP +wP +wP +CW +CW +rn +CW +CW +CW +CW +CW +CW +qV +sA +ln +fS +fS +sY +fS +fS +fS +fS +sY +fS +fS +pt +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (15,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +wP +xk +GG +CW +CW +XE +CW +CW +CW +CW +CW +CW +CW +sA +qA +En +ZD +lP +Xm +NY +lP +LX +cb +lP +dh +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (16,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +XE +XE +XE +fX +oi +XE +CW +CW +CW +CW +CW +CW +CW +sA +qA +lP +nO +gl +cH +lP +lP +Qn +sT +Lz +dh +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (17,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +fJ +dz +ii +CW +oC +XE +CW +CW +CW +CW +CW +CW +CW +sA +qA +LK +lP +lm +pr +lP +lP +EO +CN +lP +UN +Nj +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (18,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +pk +XE +ps +Ny +sO +sV +ZI +XE +CW +xX +CW +CW +CW +CW +CW +sA +qA +Hn +lP +lm +JU +lP +lP +Yn +CN +lP +kf +BY +XE +Am +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (19,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ad -al -ao -at -az -aF -aJ -aZ -aN -aP -aR -aS -aT -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +XE +XE +XE +kx +XE +pc +XE +XE +XE +XE +XE +XE +sA +sA +sA +XE +qA +ys +lP +lm +aj +lP +lP +nC +CN +lP +WW +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ae -aN -ap -aN -aN -aN -aN -aN -aN -aN -aN -aN -aW -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +oS +oS +oS +oS +oS +oS +XE +XR +Ba +XR +XE +nz +CW +CW +sA +qA +rb +lP +iS +XE +lP +Cq +XE +YT +CX +Ci +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -af -aN -aq -aN -aA -aN -aK -aN -aN -aN -aw -aN -aX -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +oS +oS +nB +oS +oS +oS +pc +CW +CW +CW +pc +CW +CW +CW +sA +qA +Dt +lP +lm +BG +lP +lP +BG +lm +lP +lP +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ag -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aQ -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +oS +oS +oS +oS +oS +oS +pc +CW +CW +CW +sA +CW +CW +CW +sA +qA +QU +lP +lm +yy +lP +lP +yy +lm +lP +lP +Nj +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ah -am -ar -au -aN -aN -aN -aN -aN -aN -aV -aN -ba -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +oS +oS +oS +oS +oS +oS +pc +CW +CW +CW +sA +CW +CW +CW +sA +qA +VG +nO +iY +Lq +lP +lP +wP +gs +Lz +lP +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aN -aj -an -av -aB -aN -aN -aN -aN -aN -qL -aN -ba -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +Yy +Yy +Yy +Yy +Yy +oS +pc +CW +CW +CW +sA +CW +CW +CW +sA +qA +lP +lP +lm +qk +lP +lP +qk +lm +lP +lP +BY +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aj -aj -an -ai -aC -aN -aN -aN -aN -aN -aN -aN -ba -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +Yy +Yy +Yy +Yy +Yy +oS +pc +CW +CW +CW +pc +CW +CW +CW +sA +jr +uF +uF +uk +uF +uF +uF +uF +uk +uF +uF +zG +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aN -an -an -ax -aD -aN -aN -aN -aN -aN -aN -aN -aN -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +Hp +oS +Yy +Yy +Yy +Yy +Yy +oS +XE +Cu +QJ +Cu +XE +nz +CW +CW +sA +NY +Cu +qW +jd +CW +CW +CW +CW +SQ +GP +Cu +Uf +XE +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +XE +XE +pc +pc +pc +pc +XE +XE +XE +XE +XE +XE +sA +sA +sA +XE +XE +XE +XE +sA +sA +sA +sA +sA +sA +XE +XE +XE +XE +Am +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ak -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aN -aU -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +sA +CW +qV +CW +CW +CW +CW +CW +bU +Gy +XR +XR +CW +CW +CW +CW +CW +CW +XR +XR +XR +sA +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aN -aN -aN -aN -aE -aG -aN -aL -aO -aN -aN -aN -aN -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +sA +CW +CW +CW +CW +CW +CW +CW +sA +Pc +yE +yE +yE +yE +yE +yE +yE +yE +yE +yE +yE +sA +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aN -aN -aN -aN -aN -aH -aN -aH -aN -aN -aN -aN -aN -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +sA +CW +CW +CW +CW +CW +CW +CW +sA +Pc +yE +mC +Cu +Cu +Cu +Cu +Cu +Cu +Cu +Cu +Cu +sA +lJ +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -aN -aN -as -ay -aN -aI -aN -aM -aN -aN -ay -aN -aN -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +sA +CW +CW +CW +CW +CW +CW +CW +sA +Pc +yE +xD +Gn +Gn +Gn +Gn +Gn +Gn +Gn +Gn +Gn +XE +Vm +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -ac -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +nz +CW +CW +CW +oI +XE +CW +CW +CW +CW +CW +CW +CW +sA +Pc +yE +xD +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +XE +CW +CW +CW +CW +CW +CW +CW +sA +Pc +yE +xD +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (34,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +XE +CW +xX +CW +CW +CW +xX +CW +sA +Pc +yE +xD +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (35,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +pk +XE +CW +CW +CW +CW +CW +XE +XE +XE +sA +sA +sA +XE +XE +XE +NY +jW +FE +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +es +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (36,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +XE +CW +qV +CW +CW +CW +qV +CW +XE +VL +VL +VL +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (37,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +nz +CW +CW +CW +oI +XE +CW +CW +CW +CW +CW +CW +CW +XE +VL +VL +VL +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (38,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +XE +CW +CW +CW +CW +CW +CW +CW +XE +VL +VL +VL +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (39,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +CW +CW +CW +CW +CW +XE +CW +CW +CW +CW +CW +CW +CW +XE +wP +Xw +wP +Gn +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (40,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +XE +XE +XE +XE +XE +XE +XE +XE +sA +sA +sA +sA +sA +XE +XE +XE +XE +XE +XE +wP +wP +wP +wP +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (41,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +lJ +lJ +lJ +lJ +lJ +lJ +un +lJ +lJ +lJ +lJ +lJ +lJ +lJ +un +lJ +lJ +lJ +lJ +fU +wP +wP +wP +xk +wP +wP +wP +wP +wP +wP +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (42,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +XE +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (43,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (44,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +oS +xs +xs +xs +xs +xs +xs +xs +xs "} (45,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (46,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (47,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} (48,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +"} +(49,1,1) = {" +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +"} +(50,1,1) = {" +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +"} +(51,1,1) = {" +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +"} +(52,1,1) = {" +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs +xs "} diff --git a/maps/example/example-3.dmm b/maps/example/example-3.dmm index 8c1ed71cd6a1..018cb124270b 100644 --- a/maps/example/example-3.dmm +++ b/maps/example/example-3.dmm @@ -1,1809 +1,3142 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( +"bE" = ( +/obj/abstract/map_data/example, /turf/space, /area/space) -"b" = ( -/obj/effect/landmark/map_data{ - height = 2 +"cd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 }, -/turf/space, -/area/space) -"c" = ( -/turf/simulated/wall, -/area/maintenance/fsmaint2) -"d" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"e" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light/spot{ - icon_state = "tube_map"; - dir = 1 +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor, +/area/example/third) +"cj" = ( +/turf/open, +/area/turbolift/example/third) +"cw" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/effect/floor_decal/industrial/outline/red, +/turf/floor/tiled/dark/monotile, +/area/example/third) +"dx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 }, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"f" = ( -/obj/structure/lattice, -/turf/simulated/open, -/area/maintenance/fsmaint2) -"g" = ( -/turf/simulated/open, -/area/maintenance/fsmaint2) -"h" = ( -/obj/machinery/light_switch/on{ - pixel_x = 25 +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 10 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"i" = ( -/obj/effect/shuttle_landmark/upper_level, -/turf/space, -/area/space) -"j" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/turf/floor, +/area/example/third) +"eg" = ( +/obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"k" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/structure/ladder, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"l" = ( -/turf/simulated/floor, -/area/maintenance/fsmaint2) -"m" = ( -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - id_tag = "upper_level_dock"; - pixel_x = 8; - pixel_y = -25 +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) +"eD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 8 }, -/turf/simulated/floor, -/area/maintenance/fsmaint2) -"n" = ( -/obj/machinery/door/airlock/external/bolted, -/turf/simulated/floor, -/area/maintenance/fsmaint2) -"o" = ( +/turf/floor, +/area/example/third) +"hv" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -21 + }, +/turf/floor, +/area/example/third) +"iI" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) +"jb" = ( +/obj/machinery/light, +/turf/open, +/area/example/third) +"lK" = ( +/turf/floor/glass, +/area/example/third) +"lY" = ( /obj/machinery/atmospherics/unary/vent_pump/on, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"p" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/machinery/light/spot{ - icon_state = "tube_map"; +/turf/floor, +/area/example/third) +"nG" = ( +/turf/open, +/area/space) +"nN" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) +"pB" = ( +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor/tiled/steel_grid, +/area/example/third) +"pH" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) +"rX" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"q" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; +/turf/floor, +/area/example/third) +"sH" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/example/third) +"uC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor, +/area/example/third) +"uK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 6 + }, +/turf/floor, +/area/example/third) +"vo" = ( +/obj/effect/floor_decal/industrial/warning/dust{ dir = 5 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"r" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; +/turf/floor, +/area/example/third) +"ww" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/open, +/area/example/third) +"wD" = ( +/obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"s" = ( -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; +/turf/floor/tiled/steel_grid, +/area/example/third) +"xk" = ( +/turf/space, +/area/space) +"xD" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor, +/area/example/third) +"yv" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 9 + }, +/turf/floor, +/area/example/third) +"Al" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning/dust{ dir = 8 }, +/turf/floor, +/area/example/third) +"AD" = ( +/turf/floor/tiled/steel_grid, +/area/example/third) +"Em" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 4 + }, +/turf/floor, +/area/example/third) +"Es" = ( +/turf/floor, +/area/example/third) +"EO" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor, +/area/example/third) +"Ff" = ( +/obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/canister/air, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"t" = ( -/obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; - dir = 6 +/obj/effect/floor_decal/industrial/outline/blue, +/turf/floor/tiled/dark/monotile, +/area/example/third) +"Fk" = ( +/obj/machinery/light{ + dir = 1 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"u" = ( -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; - dir = 8 +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) +"GA" = ( +/obj/machinery/debug_items/infinite_generator, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/floor, +/area/example/third) +"HC" = ( +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor, +/area/example/third) +"Ke" = ( +/turf/open, +/area/example/third) +"KS" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) +"LP" = ( +/turf/wall/r_wall/prepainted, +/area/example/third) +"MG" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/turf/floor, +/area/example/third) +"MO" = ( +/obj/abstract/level_data_spawner/admin_level{ + name = "Example Third Deck" + }, +/turf/space, +/area/space) +"Nz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning/dust, +/turf/floor, +/area/example/third) +"NO" = ( +/obj/machinery/light, +/turf/floor, +/area/example/third) +"NP" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 1 + }, +/turf/floor, +/area/example/third) +"OJ" = ( +/obj/machinery/door/airlock/external/glass, +/turf/floor/tiled/steel_ridged, +/area/example/third) +"Qg" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor, +/area/example/third) +"QH" = ( +/obj/machinery/apc{ + dir = 1; + pixel_y = 21 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" }, -/obj/machinery/portable_atmospherics/canister/empty, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"v" = ( /obj/machinery/light_switch/on{ - pixel_x = -25 + pixel_x = 11; + pixel_y = 31 + }, +/turf/floor, +/area/example/third) +"TM" = ( +/obj/structure/catwalk, +/turf/open, +/area/example/third) +"TO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 4 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"w" = ( +/turf/floor, +/area/example/third) +"UC" = ( +/obj/structure/ladder, +/turf/open, +/area/example/third) +"UM" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ - icon_state = "map_scrubber_on"; - dir = 1 + dir = 8 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"x" = ( -/obj/machinery/light/spot, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"y" = ( -/obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 +/turf/floor, +/area/example/third) +"UV" = ( +/obj/machinery/light{ + dir = 4 }, -/obj/machinery/power/apc{ - dir = 8; - name = "west bump"; - pixel_x = -24 +/turf/floor/tiled/steel_grid, +/area/example/third) +"Wn" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor, +/area/example/third) +"WU" = ( +/obj/effect/floor_decal/industrial/warning/dust{ + dir = 6 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"z" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 +/turf/floor/tiled/steel_grid, +/area/example/third) +"Xg" = ( +/obj/structure/railing/mapped{ + dir = 4 }, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) -"A" = ( -/obj/structure/cable, -/obj/machinery/power/debug_items/infinite_generator, -/obj/effect/floor_decal/corner/blue/diagonal, -/turf/simulated/floor/tiled, -/area/maintenance/fsmaint2) +/turf/floor, +/area/example/third) +"Ye" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor, +/area/example/third) +"Zr" = ( +/obj/effect/floor_decal/industrial/warning/dust/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/dust/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/example/third) (1,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +MO "} (2,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +bE "} (3,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (4,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (5,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (6,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (7,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (8,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (9,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (10,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (11,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (12,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +ww +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (13,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (14,1,1) = {" -a -a -a -a -a -a -a -a -a -b -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (15,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +yv +eD +Al +Al +Al +Al +Al +Al +Al +dx +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (16,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +NP +UM +Es +Es +Es +Es +Es +Es +Wn +xD +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (17,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +NP +Es +Es +Es +Es +Es +Es +Es +Es +cd +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (18,1,1) = {" -a -a -a -a -a -a -a -a -a -c -c -c -c -c -c -c -c -c -c -c -c -c -c -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +NP +GA +MG +Es +Es +Es +Es +Es +cw +Nz +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (19,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -j -d -d -d -d -v -j -y -z -A -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +LP +LP +LP +LP +LP +LP +LP +LP +pH +nN +nN +nN +nN +nN +nN +nN +nN +NP +LP +QH +Es +Es +Es +Es +hv +LP +HC +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (20,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -d -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +lK +sH +KS +AD +AD +AD +AD +AD +AD +AD +AD +NP +LP +Qg +Es +Es +Es +Es +NO +LP +HC +Ke +Ke +jb +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (21,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -d -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +lK +sH +KS +AD +AD +AD +AD +AD +AD +AD +AD +NP +Es +Es +Es +Es +Es +Es +Es +Ff +uC +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (22,1,1) = {" -a -a -a -a -a -a -a -a -a -c -e -d -d -d -d -d -d -d -d -d -d -d -x -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +lK +sH +KS +AD +AD +AD +AD +AD +AD +AD +AD +NP +Es +Es +Xg +Es +Es +Es +Es +Es +cd +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (23,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -k -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +lK +sH +KS +AD +AD +AD +AD +AD +AD +AD +AD +NP +Ye +Es +Ke +EO +Es +Es +Es +lY +xD +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (24,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -f -g -g -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +lK +sH +KS +AD +AD +AD +AD +AD +AD +AD +AD +vo +Em +TO +rX +TO +TO +TO +TO +TO +uK +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (25,1,1) = {" -a -a -a -a -a -a -a -a -a -c -f -f -g -g -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +lK +sH +KS +AD +AD +AD +AD +AD +AD +UV +AD +AD +pB +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (26,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -f -g -g -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +lK +lK +lK +lK +lK +lK +iI +OJ +Zr +AD +AD +AD +AD +AD +AD +LP +UC +AD +pB +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (27,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -d -d -d -d -d -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +LP +LP +LP +LP +LP +LP +LP +LP +Fk +wD +wD +wD +wD +wD +wD +eg +wD +wD +WU +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (28,1,1) = {" -a -a -a -a -a -a -a -a -a -c -e -d -d -d -d -d -d -d -d -d -d -d -x -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (29,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -d -o -q -d -t -w -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (30,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -d -d -d -r -d -r -d -d -d -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (31,1,1) = {" -a -a -a -a -a -a -a -a -a -c -d -d -h -d -p -s -d -u -d -d -p -d -d -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (32,1,1) = {" -a -a -a -a -a -a -a -a -a -c -c -c -c -l -c -c -c -c -c -c -c -c -c -c -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (33,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -c -l -c -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (34,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -c -m -c -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (35,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -c -n -c -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (36,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +cj +cj +cj +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (37,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -i -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +cj +cj +cj +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (38,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +cj +cj +cj +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (39,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +Ke +Ke +Ke +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (40,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +TM +TM +TM +TM +TM +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (41,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +Ke +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (42,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +LP +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (43,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (44,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +nG +xk +xk +xk +xk +xk +xk +xk +xk "} (45,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (46,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (47,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} (48,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +"} +(49,1,1) = {" +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +"} +(50,1,1) = {" +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +"} +(51,1,1) = {" +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +"} +(52,1,1) = {" +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk +xk "} diff --git a/maps/example/example.dm b/maps/example/example.dm index 4c6697f88395..955f65f1cf45 100644 --- a/maps/example/example.dm +++ b/maps/example/example.dm @@ -1,16 +1,13 @@ #if !defined(USING_MAP_DATUM) - #include "..\..\mods\misc\mundane.dm" - #include "..\..\mods\corporate\_corporate.dme" - #include "..\..\mods\government\_government.dme" - #include "..\..\mods\psionics\_psionics.dme" - #include "..\..\mods\borers\_borers.dme" - #include "..\..\mods\ascent\_ascent.dme" - #include "..\..\mods\modern_earth\_modern_earth.dme" - #include "..\..\mods\dionaea\_dionaea.dme" + #ifdef UNIT_TEST + #include "../../code/unit_tests/offset_tests.dm" + #endif #include "example_areas.dm" #include "example_shuttles.dm" + #include "example_departments.dm" + #include "example_jobs.dm" #include "example_unit_testing.dm" #include "example-1.dmm" @@ -21,6 +18,6 @@ #elif !defined(MAP_OVERRIDE) - #warn A map has already been included, ignoring Example + #warn A map has already been included, ignoring Testing Site #endif diff --git a/maps/example/example_areas.dm b/maps/example/example_areas.dm index 975820a8397f..097163dd93f0 100644 --- a/maps/example/example_areas.dm +++ b/maps/example/example_areas.dm @@ -1,11 +1,52 @@ -/area/constructionsite - name = "\improper Construction Site" - icon_state = "storage" +/area/example + holomap_color = HOLOMAP_AREACOLOR_CREW -/area/maintenance/fsmaint2 - name = "\improper Fore Starboard Maintenance - 2" +/area/example/first + name = "\improper Testing Site First Floor" icon_state = "fsmaint" -/area/medical/surgery - name = "\improper Operating Theatre" - icon_state = "surgery" \ No newline at end of file +/area/example/second + name = "\improper Testing Site Second Floor" + icon_state = "surgery" + +/area/example/third + name = "\improper Testing Site Third Floor" + icon_state = "storage" + +/area/turbolift/example + name = "\improper Testing Site Elevator" + icon_state = "shuttle" + requires_power = FALSE + dynamic_lighting = TRUE + sound_env = STANDARD_STATION + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED + ambience = list( + 'sound/ambience/ambigen3.ogg', + 'sound/ambience/ambigen4.ogg', + 'sound/ambience/ambigen5.ogg', + 'sound/ambience/ambigen6.ogg', + 'sound/ambience/ambigen7.ogg', + 'sound/ambience/ambigen8.ogg', + 'sound/ambience/ambigen9.ogg', + 'sound/ambience/ambigen10.ogg', + 'sound/ambience/ambigen11.ogg', + 'sound/ambience/ambigen12.ogg' + ) + arrival_sound = null + lift_announce_str = null + + base_turf = /turf/open + +/area/turbolift/example/first + name = "Testing Site First Floor Lift" + base_turf = /turf/floor/plating + +/area/turbolift/example/second + name = "Testing Site Second Floor Lift" + +/area/turbolift/example/third + name = "Testing Site Third Floor Lift" + +/area/shuttle/ferry + name = "\improper Testing Site Ferry" + icon_state = "shuttle" diff --git a/maps/example/example_define.dm b/maps/example/example_define.dm index f2be6fe239bb..da659b2892d9 100644 --- a/maps/example/example_define.dm +++ b/maps/example/example_define.dm @@ -1,22 +1,43 @@ /datum/map/example - name = "Example" - full_name = "The Example" + name = "Testing" + full_name = "Testing Site" path = "example" + votable = FALSE - lobby_screens = list('maps/example/lobby.png') - lobby_tracks = list(/music_track/absconditus) + lobby_screens = list( + 'maps/example/example_lobby.png' + ) - station_levels = list(1, 2, 3) - contact_levels = list(1, 2, 3) - player_levels = list(1, 2, 3) + lobby_tracks = list( + /decl/music_track/absconditus + ) - allowed_spawns = list("Arrivals Shuttle") + allowed_latejoin_spawns = list( + /decl/spawnpoint/arrivals + ) shuttle_docked_message = "The shuttle has docked." shuttle_leaving_dock = "The shuttle has departed from home dock." shuttle_called_message = "A scheduled transfer shuttle has been sent." shuttle_recall_message = "The shuttle has been recalled" + shuttle_arriving_at_dock_message = "The shuttle has arrived at %dock_name%." + emergency_shuttle_docked_message = "The emergency escape shuttle has docked." emergency_shuttle_leaving_dock = "The emergency escape shuttle has departed from %dock_name%." emergency_shuttle_called_message = "An emergency escape shuttle has been sent." emergency_shuttle_recall_message = "The emergency shuttle has been recalled" + emergency_shuttle_arriving_at_dock_message = "The emergency shuttle has arrived at %dock_name%." + + default_telecomms_channels = list( + COMMON_FREQUENCY_DATA, + list("name" = "Entertainment", "key" = "z", "frequency" = 1461, "color" = COMMS_COLOR_ENTERTAIN, "span_class" = CSS_CLASS_RADIO, "receive_only" = TRUE), + list("name" = "Command", "key" = "c", "frequency" = 1353, "color" = COMMS_COLOR_COMMAND, "span_class" = "comradio", "secured" = access_bridge), + list("name" = "Security", "key" = "s", "frequency" = 1359, "color" = COMMS_COLOR_SECURITY, "span_class" = "secradio", "secured" = access_security), + list("name" = "Engineering", "key" = "e", "frequency" = 1357, "color" = COMMS_COLOR_ENGINEER, "span_class" = "engradio", "secured" = access_engine), + list("name" = "Medical", "key" = "m", "frequency" = 1355, "color" = COMMS_COLOR_MEDICAL, "span_class" = "medradio", "secured" = access_medical), + list("name" = "Science", "key" = "n", "frequency" = 1351, "color" = COMMS_COLOR_SCIENCE, "span_class" = "sciradio", "secured" = access_research), + list("name" = "Service", "key" = "v", "frequency" = 1349, "color" = COMMS_COLOR_SERVICE, "span_class" = "srvradio", "secured" = access_bar), + list("name" = "Supply", "key" = "u", "frequency" = 1347, "color" = COMMS_COLOR_SUPPLY, "span_class" = "supradio", "secured" = access_cargo), + list("name" = "Exploration", "key" = "x", "frequency" = 1361, "color" = COMMS_COLOR_EXPLORER , "span_class" = "EXPradio", "secured" = access_eva), + list("name" = "AI Private", "key" = "p", "frequency" = 1343, "color" = COMMS_COLOR_AI, "span_class" = "airadio", "secured" = access_ai_upload) + ) diff --git a/maps/example/example_departments.dm b/maps/example/example_departments.dm new file mode 100644 index 000000000000..2e3a9cf66418 --- /dev/null +++ b/maps/example/example_departments.dm @@ -0,0 +1,4 @@ +/decl/department/example + name = "Tourism Board" + display_priority = -1 + display_color = "#ccffcc" diff --git a/maps/example/example_jobs.dm b/maps/example/example_jobs.dm new file mode 100644 index 000000000000..28d5cf504c67 --- /dev/null +++ b/maps/example/example_jobs.dm @@ -0,0 +1,21 @@ +/datum/map/example + default_job_type = /datum/job/example + default_department_type = /decl/department/example + +/datum/job/example + title = "Tourist" + total_positions = -1 + spawn_positions = -1 + supervisors = "your conscience" + description = "You need to goof off, have fun, and be silly." + economic_power = 1 + access = list() + minimal_access = list() + outfit_type = /decl/outfit/job/tourist + hud_icon = 'maps/example/hud.dmi' + department_types = list( + /decl/department/example + ) + +/decl/outfit/job/tourist + name = "Job - Testing Site Tourist" diff --git a/maps/example/example_lobby.png b/maps/example/example_lobby.png new file mode 100644 index 000000000000..a744adebfb61 Binary files /dev/null and b/maps/example/example_lobby.png differ diff --git a/maps/example/example_shuttles.dm b/maps/example/example_shuttles.dm index c79538b8cb13..bcc91db25c60 100644 --- a/maps/example/example_shuttles.dm +++ b/maps/example/example_shuttles.dm @@ -2,19 +2,50 @@ name = "Lower Level Dock" landmark_tag = "nav_example_station" docking_controller = "lower_level_dock" + special_dock_targets = list( + /datum/shuttle/autodock/ferry/example = "STARBOARD" + ) /obj/effect/shuttle_landmark/upper_level name = "Upper Level Dock" landmark_tag = "nav_example_offsite" - special_dock_targets = list("Example" = "example_shuttle_port") docking_controller = "upper_level_dock" + special_dock_targets = list( + /datum/shuttle/autodock/ferry/example = "PORT" + ) /datum/shuttle/autodock/ferry/example - name = "Example" - shuttle_area = /area/shuttle/escape + name = "Testing Site Ferry" + shuttle_area = /area/shuttle/ferry dock_target = "example_shuttle_starboard" warmup_time = 10 location = 0 waypoint_station = "nav_example_station" - waypoint_offsite = "nav_example_offsite" \ No newline at end of file + waypoint_offsite = "nav_example_offsite" + docking_cues = list( + "STARBOARD" = "example_shuttle_starboard", + "PORT" = "example_shuttle_port" + ) + ceiling_type = /turf/floor/shuttle_ceiling + +/obj/abstract/turbolift_spawner/example + name = "Testing Site elevator placeholder" + icon = 'icons/obj/turbolift_preview_nowalls_3x3.dmi' + depth = 3 + lift_size_x = 2 + lift_size_y = 2 + door_type = null + wall_type = null + firedoor_type = null + light_type = null + floor_type = /turf/floor/tiled/techfloor + button_type = /obj/structure/lift/button/standalone + panel_type = /obj/structure/lift/panel/standalone + areas_to_use = list( + /area/turbolift/example/first, + /area/turbolift/example/second, + /area/turbolift/example/third + ) + floor_departure_sound = 'sound/effects/lift_heavy_start.ogg' + floor_arrival_sound = 'sound/effects/lift_heavy_stop.ogg' diff --git a/maps/example/example_unit_testing.dm b/maps/example/example_unit_testing.dm index 6f0e43913936..df857c78a41c 100644 --- a/maps/example/example_unit_testing.dm +++ b/maps/example/example_unit_testing.dm @@ -3,5 +3,17 @@ apc_test_exempt_areas = list( /area/space = NO_SCRUBBER|NO_VENT|NO_APC, /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, - /area/shuttle/escape = NO_SCRUBBER|NO_VENT|NO_APC + /area/turbolift/example = NO_SCRUBBER|NO_VENT|NO_APC, + /area/shuttle/ferry = NO_SCRUBBER|NO_VENT|NO_APC ) + +/obj/abstract/map_data/example + height = 3 + +// Enforce that this map must not have any modpacks, to ensure core code compiles on its own. +// I'd do this in setup_map on the example map datum but that happens before modpack init. +// This catches any modpacks accidentally included by core code, default away sites, space/planet ruin maps, etc. +/datum/controller/subsystem/modpacks/Initialize() + . = ..() + if(length(loaded_modpacks)) + CRASH("Example map had the following modpacks loaded: [json_encode(loaded_modpacks)]") \ No newline at end of file diff --git a/maps/example/hud.dmi b/maps/example/hud.dmi new file mode 100644 index 000000000000..c2c456e9d507 Binary files /dev/null and b/maps/example/hud.dmi differ diff --git a/maps/example/lobby.png b/maps/example/lobby.png deleted file mode 100644 index b62daea53b71..000000000000 Binary files a/maps/example/lobby.png and /dev/null differ diff --git a/maps/exodus/exodus-1.dmm b/maps/exodus/exodus-1.dmm new file mode 100644 index 000000000000..6454cc223445 --- /dev/null +++ b/maps/exodus/exodus-1.dmm @@ -0,0 +1,71743 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/exterior) +"ac" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"ad" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/fore) +"ae" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"af" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/obj/structure/sign/warning/vacuum{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ag" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/fore) +"ah" = ( +/turf/space, +/area/exodus/maintenance/sub/fore) +"ai" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aj" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/machinery/button/access/interior{ + id_tag = "sub_sec_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = -25; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ak" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_sec_inner" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"al" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "sub_sec_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "sub_sec_airlock"; + pixel_y = -22; + tag_airpump = "sub_sec_pump"; + tag_chamber_sensor = "sub_sec_sensor"; + tag_exterior_door = "sub_sec_outer"; + tag_interior_door = "sub_sec_inner"; + dir = 1; + pixel_x = -6 + }, +/obj/machinery/airlock_sensor{ + id_tag = "sub_sec_sensor"; + pixel_x = 6; + pixel_y = -18; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"am" = ( +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"an" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_sec_outer" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"ao" = ( +/obj/machinery/button/access/exterior{ + id_tag = "sub_sec_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = 25; + dir = 4 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/fore) +"ap" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/sub/fore) +"aq" = ( +/obj/machinery/camera/network/maintenance{ + c_tag = "Security Elevator"; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ar" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"as" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"at" = ( +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"au" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"av" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aw" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ax" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"ay" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"az" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aA" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aB" = ( +/obj/abstract/turbolift_spawner/exodus/sec, +/turf/space, +/area/exodus/maintenance/sub/fore) +"aC" = ( +/obj/structure/sign/warning/lethal_turrets{ + dir = 4; + pixel_x = -34; + pixel_y = 32 + }, +/turf/space, +/area/space) +"aD" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/sign/directions/security{ + dir = 1; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aF" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aG" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aH" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aI" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aJ" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aK" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/oxygen_pump{ + pixel_y = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aM" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aN" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/machinery/computer/air_control{ + input_tag = "air_in"; + name = "air mix control console"; + output_tag = "air_out"; + sensor_name = "mix supply"; + sensor_tag = "air_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"aP" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"aQ" = ( +/turf/floor/plating/airless, +/area/space) +"aR" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aS" = ( +/obj/random/toolbox, +/turf/floor/plating/airless, +/area/space) +"aT" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aU" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aV" = ( +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aW" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aX" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aY" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"aZ" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ba" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bb" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Firefighting equipment" + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bd" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/sub/port) +"be" = ( +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bf" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bg" = ( +/obj/item/stack/tile/wood, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bh" = ( +/obj/item/stool/padded, +/turf/floor/carpet, +/area/exodus/maintenance/sub/port) +"bi" = ( +/obj/structure/chair/wood/wings, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bj" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bk" = ( +/obj/structure/chair/wood/wings{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bl" = ( +/obj/structure/table/gamblingtable, +/obj/random/coin, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bm" = ( +/obj/structure/table/gamblingtable, +/obj/item/deck/cards{ + pixel_y = 4 + }, +/turf/floor/laminate, +/area/exodus/maintenance/sub/port) +"bn" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bo" = ( +/obj/structure/table/gamblingtable, +/obj/random/coin, +/turf/floor/laminate, +/area/exodus/maintenance/sub/port) +"bp" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"br" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bs" = ( +/obj/structure/chair/wood/wings{ + dir = 1 + }, +/turf/floor/laminate, +/area/exodus/maintenance/sub/port) +"bt" = ( +/obj/structure/chair/wood/wings{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bu" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bw" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bx" = ( +/obj/random/obstruction, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"by" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bz" = ( +/obj/structure/bookcase, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bA" = ( +/obj/machinery/door/airlock, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"bB" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/port) +"bD" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bE" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bF" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"bG" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bH" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bM" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bO" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bP" = ( +/obj/structure/door_assembly, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bQ" = ( +/obj/effect/wallframe_spawn, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bR" = ( +/obj/machinery/door/airlock, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"bS" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bT" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bV" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bW" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"bY" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/space, +/area/space) +"bZ" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"ca" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cb" = ( +/obj/structure/table, +/obj/item/clothing/head/hardhat, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"cc" = ( +/obj/structure/table, +/obj/item/pen/red, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"cd" = ( +/obj/structure/table, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ce" = ( +/obj/structure/table, +/obj/item/flashlight, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"cf" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cg" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ch" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/sub/starboard) +"ci" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"cj" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"ck" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"cl" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"cm" = ( +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cn" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"co" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cp" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cq" = ( +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cr" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cs" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ct" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/starboard) +"cu" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cv" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/sub/central) +"cw" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cx" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cy" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"cz" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cA" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cB" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cC" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"cD" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/wall/prepainted, +/area/exodus/maintenance/sub/starboard) +"cE" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cF" = ( +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cG" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cH" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cI" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 1 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cJ" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cM" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"cN" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cO" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cP" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cR" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cS" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/central) +"cT" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cU" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cW" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"cY" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"cZ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"da" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"db" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dc" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dd" = ( +/obj/structure/sign/warning/lethal_turrets{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"de" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"df" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dg" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dh" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"di" = ( +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"dj" = ( +/obj/machinery/porta_turret, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"dk" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dl" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dm" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dn" = ( +/obj/machinery/camera/motion/command{ + c_tag = "Bridge - Sublevel - Fore"; + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"do" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dp" = ( +/obj/structure/table, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dq" = ( +/obj/item/stack/material/panel/mapped/plastic{ + amount = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dr" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/command) +"dt" = ( +/obj/structure/table, +/obj/item/pen/blue, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"du" = ( +/obj/structure/table, +/obj/item/paper_bin, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dv" = ( +/obj/structure/table, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dw" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dx" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dy" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/central) +"dz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Northwest" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/machinery/computer/air_control{ + input_tag = "o2_in"; + name = "oxygen control console"; + output_tag = "o2_out"; + sensor_name = "Oxygen Supply"; + sensor_tag = "o2_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"dA" = ( +/obj/structure/girder, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dB" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/port) +"dC" = ( +/obj/structure/firedoor_assembly, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dD" = ( +/obj/effect/wallframe_spawn, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dE" = ( +/obj/structure/chair/office/dark, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dF" = ( +/obj/machinery/button/access/exterior{ + id_tag = "sub_cargo_airlock"; + name = "exterior access button"; + pixel_x = 25; + pixel_y = 25; + dir = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/port) +"dG" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_cargo_outer" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"dH" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "sub_cargo_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "sub_cargo_airlock"; + pixel_y = -22; + tag_airpump = "sub_cargo_pump"; + tag_chamber_sensor = "sub_cargo_sensor"; + tag_exterior_door = "sub_cargo_outer"; + tag_interior_door = "sub_cargo_inner"; + dir = 1; + pixel_x = -6 + }, +/obj/machinery/airlock_sensor{ + id_tag = "sub_cargo_sensor"; + pixel_x = 6; + pixel_y = -18; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dI" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_cargo_inner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"dJ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/machinery/button/access/interior{ + id_tag = "sub_cargo_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = 25; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dK" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dL" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"dM" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dN" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dO" = ( +/obj/random/obstruction, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dP" = ( +/obj/machinery/door/airlock, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"dQ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/sign/warning/nosmoking_1{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dR" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dS" = ( +/obj/machinery/door/airlock, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"dT" = ( +/obj/machinery/portable_atmospherics/canister/empty/air, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"dU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/sign/warning/vacuum{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dV" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/table, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dW" = ( +/turf/space, +/area/exodus/maintenance/sub/port) +"dX" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"dZ" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ea" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eb" = ( +/obj/structure/door_assembly, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"ec" = ( +/obj/machinery/camera/motion/command{ + c_tag = "Bridge - Sublevel - Port"; + dir = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"ed" = ( +/obj/machinery/camera/motion/command{ + c_tag = "Bridge - Sublevel - Starboard"; + dir = 4 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"ee" = ( +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ef" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/central) +"eg" = ( +/obj/structure/door_assembly, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eh" = ( +/obj/abstract/turbolift_spawner/exodus/cargo, +/turf/space, +/area/exodus/maintenance/sub/port) +"ei" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/oxygen_pump{ + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"ej" = ( +/obj/machinery/camera/motion/command{ + c_tag = "Bridge - Sublevel - Center"; + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"ek" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"el" = ( +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/structure/disposaloutlet, +/turf/floor/reinforced, +/area/exodus/maintenance/sub/starboard) +"em" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/reinforced, +/area/exodus/maintenance/sub/starboard) +"en" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eo" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ep" = ( +/obj/structure/disposalpipe/broken{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eq" = ( +/obj/item/stack/cable_coil/random, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"er" = ( +/obj/item/stack/material/sheet/mapped/steel{ + amount = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"es" = ( +/obj/random/toolbox, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"et" = ( +/obj/structure/sign/directions/cargo/supply{ + dir = 1 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/port) +"eu" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"ev" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"ew" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"ex" = ( +/turf/floor/reinforced, +/area/exodus/maintenance/sub/starboard) +"ey" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/reinforced, +/area/exodus/maintenance/sub/starboard) +"ez" = ( +/turf/wall/r_wall/prepainted, +/area/space) +"eA" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eB" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eC" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"eD" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eE" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eG" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"eH" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"eI" = ( +/obj/random/obstruction, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"eJ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"eK" = ( +/obj/structure/table, +/obj/item/flashlight/lamp/green, +/obj/item/radio, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"eL" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"eM" = ( +/obj/random/tech_supply, +/obj/structure/rack, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eN" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/machinery/power_sensor{ + id_tag = "Command Sublevel Subgrid"; + name = "Powernet Sensor - Command Sublevel Subgrid" + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"eO" = ( +/obj/machinery/power/smes/buildable/max_cap_in_out, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"eP" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"eQ" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"eR" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eT" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eU" = ( +/obj/item/wrench, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eV" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/starboard) +"eW" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/obj/structure/sign/warning/vacuum{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eX" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"eY" = ( +/obj/machinery/camera/network/maintenance{ + c_tag = "Cargo Elevator"; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"eZ" = ( +/obj/structure/table, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fa" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fb" = ( +/obj/structure/table, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"fc" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"fd" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/obj/machinery/light_switch{ + pixel_y = -20; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"fe" = ( +/obj/structure/bed, +/obj/item/bedsheet/captain, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"ff" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/closet/crate/plastic, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/sign/warning/vacuum{ + pixel_y = -32; + dir = 1 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 8; + pixel_x = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"fg" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fh" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fi" = ( +/obj/machinery/button/access/exterior{ + id_tag = "sub_research_airlock"; + name = "exterior access button"; + pixel_x = 20; + pixel_y = 24; + dir = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/starboard) +"fj" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_research_outer" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"fk" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "sub_research_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "sub_research_airlock"; + pixel_y = -22; + tag_airpump = "sub_research_pump"; + tag_chamber_sensor = "sub_research_sensor"; + tag_exterior_door = "sub_research_outer"; + tag_interior_door = "sub_research_inner"; + dir = 1; + pixel_x = -6 + }, +/obj/machinery/airlock_sensor{ + id_tag = "sub_research_sensor"; + pixel_x = 6; + pixel_y = -18; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fl" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_research_inner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"fm" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/machinery/button/access/interior{ + id_tag = "sub_research_airlock"; + name = "interior access button"; + pixel_x = -20; + pixel_y = -24; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fn" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fo" = ( +/obj/structure/sign/warning/lethal_turrets{ + dir = 1; + pixel_y = -32 + }, +/turf/space, +/area/space) +"fp" = ( +/turf/space, +/area/exodus/maintenance/sub/starboard) +"fq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/command) +"fr" = ( +/obj/structure/disposalpipe/broken{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fs" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ft" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fu" = ( +/obj/item/stack/material/sheet/mapped/steel, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fv" = ( +/obj/item/crowbar, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fw" = ( +/obj/machinery/camera/network/maintenance{ + c_tag = "Research Elevator"; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fx" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fy" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"fz" = ( +/obj/machinery/camera/motion/command{ + c_tag = "Bridge - Sublevel - Aft" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"fA" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fB" = ( +/turf/wall/prepainted, +/area/space) +"fC" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fD" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fE" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/machinery/computer/air_control{ + id_tag = "n2_in"; + name = "nitrogen control console"; + output_tag = "n2_out"; + sensor_name = "Nitrogen Supply"; + sensor_tag = "n2_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"fF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fG" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fH" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/command) +"fJ" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fK" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fL" = ( +/obj/machinery/oxygen_pump{ + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fM" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fN" = ( +/obj/abstract/turbolift_spawner/exodus/research, +/turf/space, +/area/exodus/maintenance/sub/starboard) +"fO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 5 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fQ" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fR" = ( +/obj/structure/sign/warning/biohazard, +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/starboard) +"fS" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fT" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fU" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fV" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating/airless, +/area/space) +"fW" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"fY" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"fZ" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ga" = ( +/obj/machinery/light, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gb" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/machinery/computer/air_control{ + dir = 1; + input_tag = "co2_in"; + name = "carbon dioxide control console"; + output_tag = "co2_out"; + sensor_name = "Carbon Dioxide Supply"; + sensor_tag = "co2_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"gc" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gd" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/exterior) +"ge" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"gf" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"gg" = ( +/obj/structure/rack, +/obj/random/junk, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gh" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"gi" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/central) +"gj" = ( +/obj/structure/rack, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gk" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/wall/prepainted, +/area/exodus/maintenance/sub/central) +"gl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"gm" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gn" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"go" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gp" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/central) +"gq" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/sign/warning/vacuum{ + dir = 1; + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gr" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gs" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gt" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gu" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gv" = ( +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gw" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gx" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"gy" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gz" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gA" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"gB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gC" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gD" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gE" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/sub/aft) +"gF" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gG" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gH" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gI" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gJ" = ( +/obj/item/stack/material/rods/mapped/steel, +/turf/space, +/area/space) +"gK" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gL" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"gN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gO" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"gP" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gQ" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gR" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/sub/central) +"gS" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gT" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"gU" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"gV" = ( +/obj/structure/grille, +/turf/space, +/area/space) +"gW" = ( +/obj/structure/grille/broken{ + dir = 4 + }, +/turf/space, +/area/space) +"gX" = ( +/obj/structure/grille/broken{ + dir = 8 + }, +/turf/space, +/area/space) +"gY" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"gZ" = ( +/obj/structure/door_assembly, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"ha" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hb" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"he" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hf" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hg" = ( +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hh" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hi" = ( +/obj/structure/mirror{ + dir = 4; + pixel_x = -28 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hj" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hk" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"hl" = ( +/obj/structure/table, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hm" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"ho" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hp" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hq" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hr" = ( +/obj/structure/grille, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"hs" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/relay_station) +"ht" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hu" = ( +/obj/item/frame/air_alarm, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hv" = ( +/turf/floor/reinforced/airmix, +/area/exodus/engineering/atmos) +"hw" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Air" + }, +/turf/floor/reinforced/airmix, +/area/exodus/engineering/atmos) +"hx" = ( +/turf/floor/reinforced/oxygen, +/area/exodus/engineering/atmos) +"hy" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Oxygen" + }, +/turf/floor/reinforced/oxygen, +/area/exodus/engineering/atmos) +"hz" = ( +/turf/floor/reinforced/nitrogen, +/area/exodus/engineering/atmos) +"hA" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Nitrogen" + }, +/turf/floor/reinforced/nitrogen, +/area/exodus/engineering/atmos) +"hB" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/relay_station) +"hC" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/sub/relay_station) +"hD" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/relay_station) +"hE" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hF" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hG" = ( +/obj/random/toolbox, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"hH" = ( +/obj/machinery/portable_atmospherics/canister/empty/air, +/turf/floor/reinforced/airmix, +/area/exodus/engineering/atmos) +"hI" = ( +/obj/machinery/portable_atmospherics/canister/empty/oxygen, +/turf/floor/reinforced/oxygen, +/area/exodus/engineering/atmos) +"hJ" = ( +/obj/machinery/portable_atmospherics/canister/empty/nitrogen, +/turf/floor/reinforced/nitrogen, +/area/exodus/engineering/atmos) +"hK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/relay_station) +"hL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/cyan{ + icon_state = "2-8" + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/sub/relay_station) +"hM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/camera/network/maintenance{ + c_tag = "Relay Station"; + dir = 1 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/relay_station) +"hN" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; + internal_pressure_bound_default = 2000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/airmix, +/area/exodus/engineering/atmos) +"hO" = ( +/obj/machinery/air_sensor{ + id_tag = "air_sensor" + }, +/turf/floor/reinforced/airmix, +/area/exodus/engineering/atmos) +"hP" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + icon_state = "map_injector"; + id_tag = "air_in"; + use_power = 1 + }, +/turf/floor/reinforced/airmix, +/area/exodus/engineering/atmos) +"hQ" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + icon_state = "map_injector"; + id_tag = "o2_in"; + use_power = 1 + }, +/turf/floor/reinforced/oxygen, +/area/exodus/engineering/atmos) +"hR" = ( +/obj/machinery/air_sensor{ + id_tag = "o2_sensor" + }, +/turf/floor/reinforced/oxygen, +/area/exodus/engineering/atmos) +"hS" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "o2_out"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/oxygen, +/area/exodus/engineering/atmos) +"hT" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/turf/floor/reinforced/nitrogen, +/area/exodus/engineering/atmos) +"hU" = ( +/obj/machinery/air_sensor{ + id_tag = "n2_sensor" + }, +/turf/floor/reinforced/nitrogen, +/area/exodus/engineering/atmos) +"hV" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "n2_out"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/nitrogen, +/area/exodus/engineering/atmos) +"hW" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"hX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/glass/engineering{ + name = "Telecommunications" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"hY" = ( +/obj/structure/grille/broken{ + dir = 1 + }, +/turf/space, +/area/space) +"hZ" = ( +/obj/structure/grille, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/meter{ + id_tag = "mair_out_meter"; + name = "Mixed Air Tank Out" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"ia" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"ib" = ( +/obj/structure/grille, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/meter{ + id_tag = "mair_in_meter"; + name = "Mixed Air Tank In" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"ic" = ( +/obj/structure/grille, +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"id" = ( +/obj/structure/grille, +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"ie" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"if" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ig" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ih" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Access" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ii" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ij" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass/atmos{ + name = "Atmospherics" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/atmos) +"ik" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"il" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"im" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"in" = ( +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"io" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"ip" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iq" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/structure/lattice, +/turf/space, +/area/space) +"ir" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/space, +/area/space) +"is" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/space, +/area/space) +"it" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iu" = ( +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iv" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iw" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ix" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iy" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/glass/atmos{ + name = "Atmospherics" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/atmos) +"iz" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iA" = ( +/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/zpipe/up/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/zpipe/up/cyan{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iB" = ( +/obj/machinery/atmospherics/pipe/zpipe/up/red{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iC" = ( +/obj/structure/disposalpipe/up{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/zpipe/up{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "16-0" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iD" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iE" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"iF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iG" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iH" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iL" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iM" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iN" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 10 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iO" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iP" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iQ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 10 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iR" = ( +/obj/machinery/meter{ + id_tag = "wloop_atm_meter"; + name = "Waste Loop" + }, +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iS" = ( +/obj/machinery/meter{ + id_tag = "dloop_atm_meter"; + name = "Distribution Loop" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/supply{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iT" = ( +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iU" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iV" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"iW" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/substation/atmospherics) +"iX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"iY" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"iZ" = ( +/obj/machinery/atmospherics/binary/pump{ + name = "Air Mix to Connector" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ja" = ( +/obj/machinery/atmospherics/valve/digital/open{ + name = "Mixed Air Outlet Valve" + }, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jb" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/obj/machinery/computer/air_control{ + dir = 1; + input_tag = "tox_in"; + name = "toxins control console"; + output_tag = "tox_out"; + sensor_name = "Toxins Supply"; + sensor_tag = "tox_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jc" = ( +/obj/machinery/atmospherics/valve/digital/open{ + name = "Mixed Air Inlet Valve" + }, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jd" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"je" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/obj/machinery/computer/air_control{ + dir = 1; + input_tag = "n2o_in"; + name = "nitrous oxide control computer"; + output_tag = "n2o_out"; + sensor_name = "Nitrous Oxide Supply"; + sensor_tag = "n2o_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jf" = ( +/obj/machinery/atmospherics/valve/digital/open{ + name = "Oxygen Outlet Valve" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jg" = ( +/obj/machinery/atmospherics/binary/pump{ + name = "O2 to Connector" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jh" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ji" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/obj/machinery/computer/air_control{ + dir = 1; + input_tag = "waste_in"; + name = "waste control console"; + output_tag = "waste_out"; + sensor_name = "Waste Tank"; + sensor_tag = "waste_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jj" = ( +/obj/machinery/atmospherics/valve/digital/open{ + name = "Nitrogen Outlet Valve" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jk" = ( +/obj/machinery/atmospherics/binary/pump{ + name = "N2 to Connector" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jl" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jm" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jn" = ( +/obj/structure/tank_rack, +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jo" = ( +/obj/item/t_scanner, +/obj/item/multitool{ + pixel_x = 5 + }, +/obj/item/radio/headset/headset_eng, +/obj/item/paint_sprayer, +/obj/machinery/network/requests_console{ + department = "Atmospherics"; + name = "Atmos RC"; + pixel_y = 32; + dir = 1 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jp" = ( +/obj/item/clothing/head/welding{ + pixel_x = -5; + pixel_y = 3 + }, +/obj/item/clothing/glasses/welding, +/obj/structure/fireaxecabinet{ + pixel_y = 32 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jq" = ( +/obj/item/wrench, +/obj/structure/sign/plaque/atmos{ + pixel_y = 32 + }, +/obj/machinery/cell_charger, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Northeast" + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jr" = ( +/obj/machinery/newscaster{ + pixel_y = 30 + }, +/obj/item/clothing/gloves/thick, +/obj/item/clothing/gloves/thick, +/obj/item/belt/utility/atmostech, +/obj/item/belt/utility/atmostech, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"js" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ju" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jv" = ( +/obj/machinery/atmospherics/binary/pump/on{ + dir = 1; + name = "Air to Port"; + target_pressure = 200 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jw" = ( +/obj/machinery/atmospherics/binary/pump/on{ + name = "Port to Waste" + }, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jx" = ( +/obj/machinery/power_sensor{ + id_tag = "Atmospherics Subgrid"; + name = "Powernet Sensor - Atmospherics Subgrid" + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/atmospherics) +"jy" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Atmospherics"; + charge = 5e+006; + input_attempt = 1; + input_level = 250000; + output_attempt = 1; + output_level = 250000 + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/atmospherics) +"jz" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jB" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jC" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jD" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jE" = ( +/obj/item/ashtray/plastic, +/obj/effect/decal/cleanable/ash, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"jF" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"jG" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jH" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 8 + }, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jI" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8; + name = "Air Tank Bypass Pump" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jJ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jK" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jL" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jM" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Atmospheric Technician" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jN" = ( +/obj/machinery/atmospherics/binary/pump/on{ + name = "Scrubber to Waste" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jO" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jP" = ( +/obj/machinery/atmospherics/binary/pump/on{ + dir = 1; + name = "Air to Supply" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jQ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/structure/cable/cyan{ + icon_state = "2-4" + }, +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"jR" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Atmospherics Maintenance Access" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/atmospherics) +"jS" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Maintenance"; + dir = 1 + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/atmospherics) +"jT" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/substation/atmospherics) +"jU" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/atmospherics) +"jV" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jW" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jY" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"jZ" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"ka" = ( +/obj/structure/rack, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"kb" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kc" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kd" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ke" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kf" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 4; + name = "O2 to Mixing" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kg" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kh" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ki" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kj" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kk" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kl" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"km" = ( +/obj/machinery/fabricator/pipe, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 9 + }, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kn" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"kp" = ( +/obj/machinery/network/router, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"kq" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"kr" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"ks" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"kt" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"ku" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"kv" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kw" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kx" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ky" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kz" = ( +/obj/machinery/atmospherics/omni/mixer{ + active_power_usage = 7500; + tag_east = 1; + tag_east_con = 0.79; + tag_north = 1; + tag_north_con = 0.21; + tag_west = 2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kA" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kB" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kC" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 4; + name = "N2 to Mixing" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kD" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kE" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kF" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kG" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/red, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kH" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8; + name = "Supply to Waste" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kI" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/visible/blue{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kK" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kL" = ( +/obj/machinery/fabricator/pipe/disposal, +/obj/structure/window/reinforced, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kM" = ( +/turf/space, +/area/exodus/maintenance/sub/aft) +"kN" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"kO" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/oxygen_pump{ + pixel_x = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"kP" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"kQ" = ( +/obj/item/stack/material/rods{ + amount = 6 + }, +/turf/space, +/area/space) +"kR" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kS" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kT" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kU" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Port to Supply" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kV" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kW" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kX" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/cyan, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"kY" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"kZ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"la" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"lb" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"lc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_engineering_inner" + }, +/obj/machinery/button/access/interior{ + id_tag = "sub_engineering_airlock"; + name = "interior access button"; + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"ld" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "sub_engineering_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "sub_engineering_airlock"; + pixel_y = -22; + tag_airpump = "sub_engineering_pump"; + tag_chamber_sensor = "sub_engineering_sensor"; + tag_exterior_door = "sub_engineering_outer"; + tag_interior_door = "sub_engineering_inner"; + dir = 1 + }, +/obj/machinery/airlock_sensor{ + id_tag = "sub_engineering_sensor"; + pixel_x = 12; + pixel_y = -18; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"le" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "sub_engineering_outer" + }, +/obj/machinery/button/access/exterior{ + id_tag = "sub_engineering_airlock"; + name = "exterior access button"; + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"lf" = ( +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/aft) +"lg" = ( +/obj/structure/grille/broken, +/turf/space, +/area/space) +"lh" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"li" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 4; + name = "Air Mix to Port" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lj" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lk" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ll" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lm" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ln" = ( +/obj/machinery/atmospherics/unary/temperature/freezer{ + icon_state = "freezer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lo" = ( +/obj/machinery/atmospherics/unary/temperature/heater{ + icon_state = "heater" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lp" = ( +/obj/machinery/constructable_frame/machine_frame, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lq" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Southeast"; + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lr" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"ls" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"lt" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Maintenance" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"lu" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"lv" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"lw" = ( +/obj/structure/sign/warning/vacuum{ + dir = 8; + pixel_x = 32 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"lx" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/sub/aft) +"ly" = ( +/turf/wall/prepainted, +/area/exodus/engineering/atmos) +"lz" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lA" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lB" = ( +/obj/machinery/atmospherics/pipe/cap/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lC" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"lD" = ( +/obj/machinery/camera/network/maintenance{ + c_tag = "Engineering Elevator"; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"lE" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lF" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lG" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lH" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8; + name = "Port to Waste" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lI" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lK" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lL" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lM" = ( +/obj/abstract/turbolift_spawner/exodus/engineering, +/turf/space, +/area/exodus/maintenance/sub/aft) +"lN" = ( +/obj/structure/sign/directions/engineering{ + dir = 1 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/aft) +"lO" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"lP" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lQ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lR" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lS" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_north = 3; + tag_south = 6; + tag_west = 2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lT" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_north = 4; + tag_south = 7; + tag_west = 2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lU" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lV" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/red{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lW" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lX" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lY" = ( +/obj/machinery/atmospherics/binary/pump, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"lZ" = ( +/obj/machinery/atmospherics/portables_connector, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ma" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mb" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/machinery/atmospherics/valve/digital, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mc" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Mixing to Waste" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"md" = ( +/obj/machinery/atmospherics/binary/passive_gate{ + name = "Waste to Space" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"me" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mf" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mg" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mh" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/atmos) +"mi" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"mj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"mk" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ml" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mm" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mn" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mo" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 4; + name = "Mixing to Port" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mp" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 1 + }, +/obj/machinery/meter, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mq" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ms" = ( +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/atmos) +"mt" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"mu" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "CO2 to Mixing" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mv" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mw" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Phoron to Mixing" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mx" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "N2O to Mixing" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"my" = ( +/obj/machinery/atmospherics/binary/pump{ + name = "Mixing to Mix Tank" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mz" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Mix Tank to Port" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/sign/warning/compressed_gas{ + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mD" = ( +/obj/machinery/portable_atmospherics/canister/sleeping_agent, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mE" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mF" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mG" = ( +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mH" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mI" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mJ" = ( +/obj/machinery/network/mainframe, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"mK" = ( +/obj/machinery/atmospherics/valve/digital{ + name = "CO2 Outlet Valve" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mL" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "CO2 to Connector" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mM" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Southwest"; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mN" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/telecomms) +"mO" = ( +/obj/machinery/atmospherics/valve/digital{ + name = "Phoron Outlet Valve" + }, +/obj/effect/floor_decal/corner/orange{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mP" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Phoron to Connector" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mQ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mR" = ( +/obj/machinery/network/relay, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"mS" = ( +/obj/machinery/atmospherics/valve/digital{ + name = "N2O Outlet Valve" + }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mT" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "N2O to Connector" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mU" = ( +/obj/machinery/atmospherics/valve/digital{ + name = "Gas Mix Inlet Valve" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics South"; + dir = 1 + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mW" = ( +/obj/machinery/atmospherics/valve/digital{ + name = "Gas Mix Outlet Valve" + }, +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mX" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Mix Tank to Connector" + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"mZ" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"na" = ( +/obj/machinery/portable_atmospherics/canister/sleeping_agent, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"nb" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"nc" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"nd" = ( +/obj/machinery/portable_atmospherics/canister/air, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"ne" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/atmos) +"nf" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + external_pressure_bound = 140; + external_pressure_bound_default = 140; + icon_state = "map_vent_out"; + use_power = 1 + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating/airless, +/area/exodus/engineering/atmos) +"ng" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"nh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"ni" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"nj" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"nk" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"nl" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"nm" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"nn" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"no" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/atmos) +"np" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 5 + }, +/turf/floor/plating/airless, +/area/space) +"nq" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/space, +/area/space) +"nr" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/space, +/area/space) +"ns" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/space, +/area/space) +"nt" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 9 + }, +/turf/space, +/area/space) +"nu" = ( +/obj/structure/grille, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/obj/machinery/meter, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/atmos) +"nv" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "co2_in"; + pixel_y = 1; + use_power = 1 + }, +/turf/floor/reinforced/carbon_dioxide, +/area/exodus/engineering/atmos) +"nw" = ( +/obj/machinery/air_sensor{ + id_tag = "co2_sensor" + }, +/turf/floor/reinforced/carbon_dioxide, +/area/exodus/engineering/atmos) +"nx" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 1; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "co2_out"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/carbon_dioxide, +/area/exodus/engineering/atmos) +"ny" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "tox_in"; + pixel_y = 1; + use_power = 1 + }, +/turf/floor/reinforced, +/area/exodus/engineering/atmos) +"nz" = ( +/obj/machinery/air_sensor{ + id_tag = "tox_sensor" + }, +/turf/floor/reinforced, +/area/exodus/engineering/atmos) +"nA" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 1; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "tox_out"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced, +/area/exodus/engineering/atmos) +"nB" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "n2o_in"; + pixel_y = 1; + use_power = 1 + }, +/turf/floor/reinforced/n20, +/area/exodus/engineering/atmos) +"nC" = ( +/obj/machinery/air_sensor{ + id_tag = "n2o_sensor" + }, +/turf/floor/reinforced/n20, +/area/exodus/engineering/atmos) +"nD" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 1; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "n2o_out"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/n20, +/area/exodus/engineering/atmos) +"nE" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "waste_in"; + pixel_y = 1; + use_power = 1 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nF" = ( +/obj/machinery/air_sensor{ + id_tag = "waste_sensor" + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nG" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 1; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "waste_out"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nH" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"nI" = ( +/turf/floor/reinforced/carbon_dioxide, +/area/exodus/engineering/atmos) +"nJ" = ( +/obj/machinery/portable_atmospherics/canister/empty/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, +/area/exodus/engineering/atmos) +"nK" = ( +/turf/floor/reinforced, +/area/exodus/engineering/atmos) +"nL" = ( +/obj/machinery/portable_atmospherics/canister/empty, +/turf/floor/reinforced, +/area/exodus/engineering/atmos) +"nM" = ( +/turf/floor/reinforced/n20, +/area/exodus/engineering/atmos) +"nN" = ( +/obj/machinery/portable_atmospherics/canister/empty/sleeping_agent, +/turf/floor/reinforced/n20, +/area/exodus/engineering/atmos) +"nO" = ( +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nP" = ( +/obj/machinery/portable_atmospherics/canister/empty, +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nQ" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nR" = ( +/obj/machinery/light/small, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Carbon Dioxide"; + dir = 1 + }, +/turf/floor/reinforced/carbon_dioxide, +/area/exodus/engineering/atmos) +"nS" = ( +/obj/machinery/light/small, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Phoron"; + dir = 1 + }, +/turf/floor/reinforced, +/area/exodus/engineering/atmos) +"nT" = ( +/obj/machinery/light/small, +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Nitrous Oxide"; + dir = 1 + }, +/turf/floor/reinforced/n20, +/area/exodus/engineering/atmos) +"nU" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Tank - Gas Mixing"; + dir = 1 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/atmos) +"nV" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"nW" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"nX" = ( +/obj/structure/closet/wardrobe/black, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"nY" = ( +/obj/structure/closet/wardrobe/mixed, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"nZ" = ( +/obj/structure/closet/wardrobe/pjs, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"oa" = ( +/obj/machinery/constructable_frame/machine_frame, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"ob" = ( +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"oc" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"od" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/sub/aft) +"oe" = ( +/obj/machinery/computer/guestpass{ + dir = 1; + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"of" = ( +/obj/structure/rack, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/sub/fore) +"og" = ( +/obj/machinery/camera/network/command{ + c_tag = "Bridge - Sublevel - Turret Control" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/turretid/stun{ + dir = 1; + pixel_y = 32 + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/sub/command) +"oh" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12 + }, +/turf/floor/plating, +/area/exodus/maintenance/sub/starboard) +"oi" = ( +/obj/structure/mopbucket, +/obj/item/mop, +/turf/floor/plating, +/area/exodus/maintenance/sub/port) +"oz" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"oE" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"oQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"pI" = ( +/obj/structure/sign/warning/lethal_turrets{ + pixel_y = 32; + pixel_x = 34 + }, +/turf/space, +/area/space) +"qe" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"qQ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/structure/reagent_dispensers/water_cooler{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"rd" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"rj" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/camera/network/command{ + c_tag = "Telecommunications - Server Room Starboard" + }, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"rK" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/sign/warning/lethal_turrets{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/plating/airless, +/area/space) +"rL" = ( +/obj/item/stock_parts/subspace/analyzer, +/obj/item/stock_parts/subspace/analyzer, +/obj/item/stock_parts/subspace/analyzer, +/obj/structure/rack, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"sJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/exodus/maintenance/telecomms) +"ta" = ( +/obj/structure/table/steel, +/obj/item/flashlight/lamp, +/obj/random_multi/single_item/boombox, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"tX" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/exodus/maintenance/telecomms) +"ud" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"ue" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/highsecurity{ + name = "Telecommunications" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_ridged, +/area/exodus/maintenance/sub/aft) +"up" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/exodus/maintenance/telecomms) +"ww" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/telecomms) +"wC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"xi" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/camera/network/command{ + c_tag = "Telecommunications - Server Room Port"; + dir = 1 + }, +/obj/machinery/network/relay, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"xy" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/obj/structure/window/reinforced, +/obj/structure/table/steel, +/obj/machinery/cell_charger, +/obj/item/lunchbox/dais{ + pixel_x = 6; + pixel_y = 6 + }, +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"xM" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/telecomms) +"xZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/telecomms) +"yb" = ( +/obj/effect/shuttle_landmark/exodus_sub_starboard, +/turf/space, +/area/space) +"yy" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/closet/toolcloset, +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"zy" = ( +/obj/structure/sign/warning/lethal_turrets{ + dir = 4; + pixel_x = -34 + }, +/turf/space, +/area/space) +"zH" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"zJ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"zN" = ( +/obj/structure/table/steel, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Ad" = ( +/obj/machinery/light, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Ag" = ( +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"Ai" = ( +/obj/item/stock_parts/subspace/filter, +/obj/item/stock_parts/subspace/filter, +/obj/item/stock_parts/subspace/filter, +/obj/item/stock_parts/subspace/filter, +/obj/item/stock_parts/subspace/filter, +/obj/structure/rack, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"AE" = ( +/obj/abstract/level_data_spawner/main_level{ + name = "Exodus Underlevel" + }, +/turf/space, +/area/space) +"AG" = ( +/obj/structure/table/steel, +/obj/item/paper_bin, +/obj/item/folder/yellow, +/obj/item/pen/blue{ + pixel_x = -3; + pixel_y = 2 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"AU" = ( +/obj/structure/table/steel, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/item/toolbox/mechanical, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = -7 + }, +/obj/random/smokes, +/obj/item/chems/drinks/glass2/coffeecup/dais{ + pixel_x = -6; + pixel_y = 12 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"Bb" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"Bc" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"BO" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"BR" = ( +/obj/structure/table/steel, +/obj/item/multitool, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"CI" = ( +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/capacitor, +/obj/item/stock_parts/micro_laser/high, +/obj/item/stock_parts/micro_laser/high, +/obj/item/stock_parts/micro_laser/high, +/obj/item/stock_parts/micro_laser/high, +/obj/structure/rack, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"CJ" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/telecomms) +"CN" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Atmospherics"; + charge = 5e+006; + input_attempt = 1; + input_level = 250000; + output_attempt = 1; + output_level = 250000 + }, +/obj/structure/cable/green, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"CT" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"CW" = ( +/obj/structure/sign/warning/lethal_turrets{ + dir = 8; + pixel_x = 34 + }, +/turf/space, +/area/space) +"Dm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/telecomms) +"DZ" = ( +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Ec" = ( +/obj/machinery/computer/message_monitor{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"EG" = ( +/obj/structure/table/steel, +/obj/structure/noticeboard{ + default_pixel_x = 32 + }, +/obj/item/paper_bin, +/obj/item/pen, +/obj/item/sticky_pad/random, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"Gc" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"GD" = ( +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"GS" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"Ho" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/network/command{ + c_tag = "Telecommunications - Server Entry"; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Hq" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Hz" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/telecomms) +"HW" = ( +/obj/machinery/design_database, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"IA" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/sub/aft) +"IL" = ( +/obj/machinery/computer/design_console{ + dir = 4; + id_tag = "science" + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"IX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Maintenance" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"Ja" = ( +/obj/structure/rack, +/obj/item/stock_parts/subspace/treatment, +/obj/item/stock_parts/subspace/treatment, +/obj/item/stock_parts/subspace/treatment, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"Jv" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/network/message_server, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"JP" = ( +/obj/machinery/commsrelay, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"Kg" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"KB" = ( +/obj/effect/shuttle_landmark/exodus_sub_aft, +/turf/space, +/area/space) +"LF" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"LN" = ( +/obj/item/stock_parts/subspace/transmitter, +/obj/item/stock_parts/subspace/transmitter, +/obj/structure/rack, +/obj/item/stock_parts/computer/hard_drive/portable, +/obj/item/stock_parts/computer/hard_drive/portable, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"Me" = ( +/obj/machinery/door/airlock/hatch{ + name = "Telecoms Server Access"; + secured_wires = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/exodus/maintenance/telecomms) +"Mh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Mp" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/rack, +/obj/item/clothing/suit/jacket/winter/engineering, +/obj/item/clothing/suit/jacket/winter/dais{ + pixel_y = 12 + }, +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"MC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -22 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/exodus/maintenance/telecomms) +"MJ" = ( +/obj/machinery/camera/network/command{ + c_tag = "Telecommunications - Control"; + dir = 8 + }, +/obj/machinery/computer/modular/preset/aislot/research{ + dir = 8; + icon_state = "console" + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"MR" = ( +/obj/item/stock_parts/subspace/crystal, +/obj/item/stock_parts/subspace/crystal, +/obj/item/stock_parts/subspace/crystal, +/obj/structure/rack, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/alarm{ + pixel_y = 24 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"MV" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/catwalk_plated/dark, +/turf/floor/plating, +/area/exodus/maintenance/telecomms) +"Ni" = ( +/obj/effect/shuttle_landmark/exodus_sub_fore, +/turf/space, +/area/space) +"Nj" = ( +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"Nw" = ( +/obj/structure/table/steel, +/obj/item/box/cups, +/obj/machinery/apc/hyper{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"NK" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"Ou" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/port) +"Ox" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"Oz" = ( +/obj/machinery/door/airlock/highsecurity{ + name = "Telecoms Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_ridged, +/area/exodus/maintenance/telecomms) +"PM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"Qe" = ( +/obj/structure/lattice, +/turf/wall/prepainted, +/area/exodus/maintenance/sub/aft) +"Qs" = ( +/obj/structure/rack, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/telecomms) +"QB" = ( +/obj/item/stock_parts/subspace/amplifier, +/obj/item/stock_parts/subspace/amplifier, +/obj/item/stock_parts/subspace/amplifier, +/obj/structure/rack, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"Re" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) +"RL" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/network/telecomms_hub, +/turf/floor/bluegrid, +/area/exodus/maintenance/telecomms) +"Se" = ( +/obj/machinery/newscaster{ + pixel_y = -32; + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"Si" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/hologram/holopad, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"Sp" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"Sq" = ( +/obj/structure/sign/warning/server_room, +/turf/wall/prepainted, +/area/exodus/maintenance/telecomms) +"SM" = ( +/obj/effect/shuttle_landmark/exodus_sub_port, +/turf/space, +/area/space) +"SP" = ( +/obj/item/stock_parts/subspace/ansible, +/obj/item/stock_parts/subspace/ansible, +/obj/item/stock_parts/subspace/ansible, +/obj/structure/rack, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/monotile, +/area/exodus/maintenance/telecomms) +"TI" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"TT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -22 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/terminal{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/maintenance/telecomms) +"UC" = ( +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"UK" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"UM" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"Wa" = ( +/obj/structure/sign/directions/science{ + dir = 1; + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/starboard) +"Xu" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/fore) +"Yf" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/sub/aft) +"Yt" = ( +/obj/machinery/alarm/server{ + dir = 4; + pixel_x = -22; + req_access = list(list("ACCESS_ENGINE_EQUIP","ACCESS_ATMOS")) + }, +/turf/floor/tiled/dark, +/area/exodus/maintenance/telecomms) +"YT" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/exodus/maintenance/telecomms) +"Zt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/sub/aft) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +AE +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +SM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kQ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +gV +gV +hY +ab +ab +ab +ab +ab +hY +aa +lg +ab +ab +ab +ab +ab +gV +hY +lg +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +bd +bd +bj +bj +bd +bd +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +be +be +bk +be +be +bd +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ab +ab +ab +ab +ab +gV +gV +gV +ab +ab +ab +ab +ab +gV +gV +gV +ab +ab +ab +ab +ab +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +bf +bh +bl +bo +bs +bd +aa +aa +ac +aa +aa +bB +bB +bB +bB +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +bd +be +bi +bm +bm +bt +bd +bd +bd +bd +bd +bd +bB +bT +be +bB +bd +bd +bd +bd +bd +bB +bB +aa +aa +ab +ab +ab +ab +ab +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +bg +be +be +be +be +bd +be +bS +be +bF +be +cr +cu +be +bS +be +bF +be +bS +be +be +bB +ac +ac +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +gJ +aa +aa +ac +aa +aa +aa +ac +ac +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +bd +be +be +bp +bp +bd +be +bd +bd +bd +bd +bd +bd +bd +bd +bd +bd +bd +bd +cY +bT +bB +aa +aa +ac +ac +ac +ac +ac +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +ac +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +ac +aa +aa +gJ +aa +aa +ac +aa +aa +aa +aa +aa +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +ac +aa +aa +ac +ac +aa +aa +ac +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +bd +be +be +be +be +bA +be +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +bd +bG +bB +bB +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +ac +aa +ac +ac +ac +aa +aa +aa +aa +aa +ac +aa +ac +ac +aa +aa +aa +ac +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +be +be +bq +bu +bd +be +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +bd +be +bd +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +ac +ac +ac +aa +aa +aa +ac +aa +aa +aa +ac +ac +aa +aa +ac +aa +ac +ac +aa +aa +aa +aa +ac +ac +ac +aa +aa +aa +aa +ac +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +eM +bn +br +bu +bd +be +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +bd +bF +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +ac +aa +ac +ac +aa +aa +ac +aa +aa +ac +ac +aa +aa +aa +ac +aa +aa +ac +ac +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +bd +bd +bd +bd +bd +be +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +bd +be +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ac +ac +ac +ab +ac +ac +ac +ac +ac +aa +aa +ac +ac +aa +ac +aa +ac +ac +aa +aa +aa +aa +ac +aa +aa +aa +ac +ac +aa +ac +ac +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +ab +ac +ac +ac +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +be +bd +aa +aa +ac +aa +aa +ac +ab +ab +ac +ac +bd +bE +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +ab +aa +aa +ac +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +ac +ac +ac +nf +np +aa +aa +aa +aa +ac +ac +aa +aa +aa +ab +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +be +bd +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +bd +be +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +ac +ac +ac +aa +iF +iY +iY +iY +iY +iY +iY +iY +iY +iY +iY +iY +iY +iY +ng +nq +ac +ac +ac +aa +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +be +bd +aa +aa +ac +aa +aa +ac +aa +aa +aa +aa +bd +be +bd +aa +aa +aa +aa +aa +aa +ac +bB +bB +bB +bB +bB +bB +bd +bd +bd +aa +aa +ac +aa +bY +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +hr +hr +hr +hr +hr +ac +iG +iZ +jG +iv +iv +iv +iv +iv +iv +iv +iv +iv +iv +iv +iK +nq +hr +hr +hr +hr +hr +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +bd +be +bd +aa +aa +ac +aa +aa +ac +aa +aa +aa +aa +bd +be +bj +aa +aa +aa +aa +aa +aa +ac +bB +dW +dW +dW +eh +et +bf +be +bd +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +hr +hv +hv +hN +hZ +iq +iH +ja +jH +iw +iw +kv +iv +iv +iv +lP +jK +jK +jK +mI +iL +nr +ic +nv +nI +nI +hr +aa +aa +ac +ac +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +bE +bd +aa +ac +ac +aa +aa +ac +aa +aa +aa +aa +bd +be +bj +aa +aa +aa +aa +aa +dB +dF +bB +dW +dW +dW +dW +Ou +be +be +bd +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +hr +hw +hH +hO +ia +ac +iI +aO +jI +iv +iv +kw +iv +iv +iv +lQ +iv +iv +iv +gb +nh +nq +ia +nw +nJ +nR +hr +aa +aa +aa +ac +ac +aa +aa +ab +aa +aa +gW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +bd +be +bd +aa +aa +ac +aa +aa +ac +aa +aQ +aQ +ac +bd +be +bd +aa +aa +aa +aa +aa +bB +dG +bB +dW +dW +dW +dW +Ou +be +eY +bd +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gV +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +hr +hv +hv +hP +ib +iq +iJ +jc +jJ +iw +kv +kw +lh +ly +lE +lQ +iv +mk +mu +mK +ni +ns +id +nx +nI +nI +hr +ac +ac +ac +ac +ac +ac +ac +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bB +bF +bd +bd +bd +bd +bd +bd +ac +aa +aa +aa +aa +bd +be +bd +aa +aa +aa +aa +aa +bB +be +bB +dW +dW +dW +dW +bB +bf +be +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +hr +hr +hr +hr +hr +ac +iK +iv +iv +iv +kw +kw +iv +iv +iv +lR +iv +kc +mv +mL +nj +nq +hr +hr +hr +hr +hr +aa +aa +aa +ac +ac +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +bB +be +bd +bZ +bZ +bZ +bZ +bd +ac +aa +aa +aa +aa +bd +be +bd +aQ +aa +aa +aa +aa +bB +dH +bB +bB +bB +bB +bB +bB +be +be +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +hr +hx +hx +hQ +ic +ir +iL +jd +jK +jK +kx +kx +jK +jK +lF +lS +lF +kd +jK +mM +nk +nr +ic +ny +nK +nK +hr +aa +aa +ac +ac +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +aa +aa +aa +aa +ac +aa +bB +bG +bd +bd +bZ +bZ +bZ +bd +bd +bd +bd +bd +bd +bd +be +bd +bd +bd +bd +bd +bd +bB +dI +bB +dX +dX +bT +cr +eu +bV +be +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +hr +hy +hI +hR +ia +ac +iI +dz +iv +iv +ky +kw +iv +iv +iv +lQ +iv +kc +iv +jb +nl +nq +ia +nz +nL +nS +hr +aa +ac +ac +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +be +bT +bd +bd +bd +bd +bd +cA +cA +be +cN +bU +bU +bU +bU +dh +bU +ci +bU +ca +bU +dJ +dU +dY +ea +bU +ei +ev +eA +oi +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +hr +hx +hx +hS +id +is +iM +jf +jL +kb +kz +kw +iv +iv +iv +lR +iv +ml +mw +mO +ni +ns +id +nA +nK +nK +hr +ac +ac +aa +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bB +bH +bU +ca +bU +ci +bU +ca +bU +bU +bU +cO +bd +bd +bd +bd +bd +bd +bd +bd +bd +be +be +be +bd +bd +bd +bd +bd +eB +bd +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +hr +hr +hr +hr +hr +ac +iN +jg +jG +kc +kA +kw +iv +iv +iv +lQ +iv +kc +mv +mP +nj +nq +hr +hr +hr +hr +hr +aa +ac +ac +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bB +eD +bd +bd +bd +bd +bd +bd +bd +bd +bd +bd +bd +aa +aa +aa +aa +ac +aa +aa +bd +bd +bd +bd +bd +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +hr +hz +hz +hT +ic +ir +iL +jh +jK +kd +kd +kx +jK +jK +lF +lT +lF +kd +jK +mQ +nk +nr +ic +nB +nM +nM +hr +aa +aa +ac +ac +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bB +eA +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +eC +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +hr +hA +hJ +hU +ia +ac +iO +fE +iv +kc +kc +kw +iv +iv +iv +lU +iv +kc +iv +je +nl +nq +ia +nC +nN +nT +hr +aa +aa +aa +ac +ac +aa +aa +ab +aa +aa +gX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bB +eC +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +bd +bd +bd +bd +bd +bd +aa +aa +bd +eA +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gW +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +hr +hz +hz +hV +id +is +iP +jj +jL +ke +kB +kw +lh +ly +lE +ki +iv +ml +mx +mS +ni +ns +nu +nD +nM +nM +hr +ac +ac +ac +ac +ac +ac +ac +ab +kQ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +bd +be +be +be +be +bd +aa +aa +bd +eD +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +hr +hr +hr +hr +hr +ac +iQ +jk +jG +kc +kc +kw +iv +iv +iv +ki +iv +kc +mv +mT +nj +nq +hr +hr +hr +hr +hr +aa +aa +aa +ac +ac +aa +aa +ab +aa +aa +gW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +eB +bd +bd +aa +aa +aa +aa +aQ +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +bd +be +dp +dp +be +bd +bd +bd +bd +eA +bd +ac +ac +ac +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ia +iv +iv +kc +kc +kw +iv +iv +iv +lV +mc +mm +iv +iv +nm +nq +aa +ac +aa +ac +aa +aa +aa +ac +ac +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +bd +bM +bV +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +bd +bE +dp +dV +bU +eb +bU +bU +bU +eE +bd +aa +aa +aa +aa +ac +aa +ab +ab +aa +aa +aa +aa +aa +aa +gJ +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +hW +jl +iv +kf +kC +kw +iv +iv +iv +ki +iv +kc +iv +lh +nm +nq +hr +hr +hr +hr +hr +aa +ac +ac +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +bd +be +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +bd +be +be +be +be +bd +bd +bd +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +hW +jm +iv +kg +kD +kR +jL +jL +jL +lW +jL +mn +my +mU +nn +ns +id +nE +nO +nO +hr +ac +ac +aa +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +bd +bd +eA +bd +ac +ac +ac +ac +ac +ac +ab +ab +ab +ab +ab +ab +ab +ac +ac +ac +bd +be +bd +bd +bd +bd +aa +aa +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +ac +ac +hW +jn +iv +iv +kE +kS +kv +iv +iv +ki +iv +mo +iv +ji +nl +nq +ia +nF +nP +nU +hr +aa +ac +ac +aa +aa +aa +aa +gV +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Ni +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +ac +bd +dC +bd +ac +ac +ac +ac +ac +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +ac +ac +aa +hW +jo +iv +iv +kF +kw +li +iv +iv +ki +iv +mp +mz +mW +ni +ns +nu +nG +nQ +nO +hr +aa +aa +ac +ac +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +ac +aa +aa +ac +bd +bd +bd +be +bd +ac +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +ac +ac +ac +ac +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +gX +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +ac +ac +aa +aa +hW +jp +jM +kh +kG +kT +lj +lz +lG +kj +iv +lJ +mv +mX +nj +nq +hr +hr +hr +hr +hr +aa +aa +aa +ac +ac +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +ac +bd +be +be +be +bd +ac +aa +aa +aa +aa +bd +eF +bd +aa +ac +ac +ac +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +aa +aa +aa +hW +jq +iv +ki +kH +kw +lk +ly +lH +lX +md +mq +mA +mY +no +nt +aa +aa +aa +ac +ac +ac +ac +ac +ac +ac +ac +ac +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +bd +eA +bj +aa +aa +aa +aa +ac +ac +ac +aa +aa +ac +ac +ac +ac +ac +bd +dp +be +be +bd +ac +ac +aa +aa +aa +bd +eA +bd +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +gW +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +hW +jr +iv +ki +kI +kU +ll +lA +lI +lA +lA +mf +mB +hW +hW +ac +ac +ac +ac +ac +aa +aa +aa +aa +ac +ac +aa +aa +ab +aa +aa +gV +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +bd +eA +bd +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +aa +aa +aa +ac +bd +dq +be +be +bd +ac +aa +aa +aa +aa +bd +eC +bd +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +hW +hW +hW +hW +js +iv +ki +kJ +kw +iv +iv +lJ +iv +iv +iv +mC +mZ +hW +aa +aa +aa +aa +ac +ac +aa +aa +ac +ac +aa +aa +aa +ab +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aI +aG +ap +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +bd +eA +bd +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +aa +aa +aa +ac +bd +bd +bd +bd +bd +aQ +aa +aa +aa +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +hW +ie +it +iR +jt +jN +kj +kJ +kw +lm +iv +lJ +iv +iv +iv +mD +na +hW +aa +aa +aa +aa +aa +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +am +am +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +bd +eD +bd +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aQ +aa +aa +aa +aa +cv +eH +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +ef +ef +ef +ef +ef +ef +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +hW +if +iu +iS +ju +jO +kk +kK +kw +ln +lA +lI +lY +me +iv +mE +nb +hW +ac +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ad +am +av +aH +aE +aP +aE +aU +aE +aE +aE +aE +aF +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aQ +aa +aa +aa +aa +cv +eG +cF +cF +fx +fH +fO +fT +fW +cF +cF +gc +cF +gi +cF +gc +cF +cF +cv +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +hW +ig +iv +iT +ju +jP +kl +iw +kV +lo +lA +lK +lZ +lK +iv +mF +nc +hW +ac +ac +aa +aa +aa +aa +aa +ac +aa +aa +ab +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ap +aM +ap +ap +ap +ap +ap +ap +ap +ap +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bd +eC +bd +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aQ +aa +aa +aa +aa +cv +eG +cF +cF +cF +cF +fP +fU +fX +cF +ga +cv +cv +cv +cv +cv +cF +cF +cv +aa +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +hW +ih +iw +iU +jv +iw +kl +iw +kW +lp +lB +lI +ma +mf +iv +mG +nd +hW +aa +ac +ac +aa +aa +ac +ac +ac +ac +ac +ab +ac +ac +ac +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +ac +ac +aa +aa +ac +aa +aa +aa +aa +bd +eA +bd +aa +aa +aa +aa +aa +aa +aa +aa +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +eI +fa +fa +cF +cF +cF +cF +cF +cF +cF +cF +gg +gj +gj +cv +cF +cF +ef +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +aa +ac +ac +aa +aa +aa +aa +aa +hW +ii +ix +iV +jw +jQ +km +kL +kX +lq +iv +lL +mb +mg +mr +mH +ne +hW +aa +aa +ac +ac +aa +ac +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +ax +ap +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +ac +aa +ac +aa +aa +aa +aa +bd +eD +bB +bB +aa +aa +aa +aa +aa +aa +aa +cv +cF +cP +cw +cw +cw +dm +cw +dy +cw +dm +cw +cw +cw +cw +cw +cw +eJ +cw +cw +cw +cw +fQ +cw +cw +cw +cw +cw +cw +cw +do +cv +cF +cF +ef +ef +ef +aa +ac +ac +aa +aa +aa +aa +ac +aa +aa +ac +ac +aa +aa +aa +aa +hW +ij +iy +iW +iW +jR +iW +hW +hW +hW +hW +hW +hW +mh +ms +hW +hW +hW +ly +aa +aa +ac +ac +ac +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +bd +bd +bB +bW +bT +bB +bd +bd +cv +cv +cv +cv +cv +cv +cF +eG +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +eG +cv +gy +gK +cF +gR +ef +aa +aa +ac +aa +aa +aa +aa +ac +aa +aa +aa +ac +ac +aa +aa +aa +IA +ik +iz +iW +jx +jS +iW +kM +kM +kM +kM +lM +IA +mi +kY +IA +gF +gF +gE +aa +aa +aa +aa +ac +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ad +ah +ah +ah +aB +ad +ap +aM +ap +aa +aa +aa +aa +aa +aa +aa +ap +aX +aE +aE +aE +aE +aE +aE +aE +aE +aE +aE +aE +aU +aE +ci +bU +ca +bX +bU +cf +bU +ci +cw +cB +cw +cw +cw +cw +cw +cZ +cv +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +cv +eG +cv +ef +ef +ef +ef +ef +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +hs +hs +hs +IA +il +iA +iW +jy +jT +iW +kM +kM +kM +kM +kM +IA +mi +kY +IA +gF +gF +gE +aa +aa +aa +aa +ac +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ad +ah +ah +ah +ah +ad +am +aw +ap +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +bd +bd +bB +bB +bB +bd +bd +bd +cv +cv +cv +cv +cF +cF +cF +da +cv +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +hs +hB +hK +IA +im +iB +iW +iW +jU +iW +kM +kM +kM +kM +kM +IA +mi +mt +IA +gF +gF +gE +aa +aa +aa +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +ad +ah +ah +ah +ah +ad +am +aw +ap +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +cv +cG +cF +cF +db +cv +aa +aa +aa +aa +aa +ab +aC +aa +ac +aa +ac +zy +aa +aa +ac +aa +aa +zy +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +hs +hC +hL +hX +in +iC +IA +jz +jV +IA +kM +kM +kM +kM +kM +IA +mi +kY +IA +gF +gF +gE +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +ad +ah +ah +ah +ah +ad +aJ +aN +aA +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +cv +cP +cX +cX +dc +cv +aa +aa +aa +aa +aa +ab +aa +aa +ac +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +hs +hD +hM +IA +io +iD +iX +jA +jW +IA +kM +kM +kM +kM +kM +IA +mi +kY +IA +gF +gF +gE +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +ad +ad +ad +Xu +Xu +ad +ad +aw +am +aA +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cv +eG +cv +cv +cv +cv +ac +ab +ab +ab +ab +ab +aa +aa +ac +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +hs +hs +hs +IA +IA +IA +IA +jB +zH +IA +IA +Sp +Sp +Sp +lN +IA +mi +kY +IA +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +IA +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +ae +ai +am +am +aD +aG +aw +am +ap +aQ +aQ +aS +aa +ab +ac +ac +ap +aw +ap +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aa +aa +ac +aa +aa +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +cv +eG +cv +aa +aa +aa +aa +ab +aC +aa +ac +aa +aa +aa +ac +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +hd +jC +jY +kn +kN +kn +lr +lC +lO +lC +mj +kY +gE +hg +hg +hg +hg +nH +hg +ks +hg +kP +nV +hg +hg +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +af +aj +aq +av +aE +aE +aK +ap +ap +aQ +aQ +aQ +aa +ab +aa +aQ +ap +aw +ap +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aa +aa +aa +aa +ac +aa +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +aQ +cv +eG +cv +aa +aa +aa +ab +ab +aa +aa +ac +aa +aa +aa +di +di +di +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +gE +gE +gE +gE +gE +gE +gE +gE +jD +jZ +CT +kO +kZ +ls +lD +kY +kY +kY +kY +gE +hg +hg +gE +gE +gE +gE +gE +gE +gE +hg +hg +nW +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ak +ad +aw +ap +ap +ap +ap +aa +aa +aa +aa +aa +ab +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +dj +di +dj +ac +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +cv +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +hq +ht +hE +hg +hg +ip +iE +gE +Re +Re +gE +gE +gE +lt +gE +gE +gE +gE +gE +gE +hg +gE +gE +aa +aa +aa +aa +aa +gE +hd +hd +IA +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +al +ad +aw +ap +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +aa +ap +aw +ap +ap +ap +ap +ac +ac +ac +aQ +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cv +cR +cv +aa +aa +aa +ab +ac +aa +aa +ac +aa +aa +aa +di +ec +di +aa +aa +aa +ac +di +dj +ac +aa +aa +aa +aa +fo +ab +ac +cv +gm +gt +gz +gL +gP +gS +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +gP +PM +Zt +CT +PM +gP +gP +lu +hg +hg +hg +hg +hg +hg +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +am +ad +ax +ap +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +aa +ap +az +aE +aE +aF +ap +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cv +eG +cv +ac +ab +ab +ab +ac +aa +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +di +ac +aa +aa +aa +aa +aa +ab +aa +cv +gn +cv +cv +gE +gE +gE +gE +Hz +Hz +Hz +Hz +Hz +Hz +Hz +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +zH +kY +gE +mR +la +lv +gE +gE +gE +gE +gE +gE +gE +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +an +ad +aw +ap +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +ap +ap +ap +ap +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +aa +cv +cv +cv +cS +cv +aa +ab +aC +aa +ac +aa +dr +di +di +aa +aa +aa +di +aa +aa +dr +eK +fb +dr +ac +ac +ac +ac +ac +ac +ac +ab +aa +cv +gn +cv +aa +aa +aa +aa +Hz +Hz +qe +mJ +oz +kp +qe +Hz +Hz +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +gE +zH +kY +gE +kP +lb +lw +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ag +ao +ap +ay +ap +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ap +aV +am +aG +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +aA +am +am +am +am +am +am +of +of +ap +ap +ap +cF +cF +eG +cv +aa +ab +aa +aa +ac +aa +dr +di +dj +aa +aa +aa +di +aa +aa +dr +eL +fc +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +go +cv +aa +aa +Hz +Hz +Hz +rj +GD +UM +JP +Hq +GD +xi +Hz +Hz +Hz +aa +aa +aa +aa +aa +aa +ac +aa +aa +gE +zH +kY +gE +IA +lc +IA +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ap +as +am +am +bb +aw +ap +aa +aa +aa +aa +aa +aa +aa +aA +am +av +aE +aE +aE +aE +aE +aE +aU +aE +cC +cw +cw +cT +cv +aa +ab +aa +aa +ac +aa +dr +aa +aa +aa +aa +aa +di +aa +aa +dr +og +fd +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +gn +cv +aa +aa +Hz +DZ +Yt +UC +Bb +tX +up +MV +YT +UC +LF +zN +Hz +aa +aa +aa +aa +aa +aa +ac +ab +aa +gE +zH +kY +gE +IA +ld +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ab +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ap +aw +ap +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ap +aW +aY +ba +ap +aw +ap +ap +ap +ap +ap +ap +ap +ap +ap +am +aw +ap +ap +ap +ap +ap +ap +ap +ap +ap +cG +cF +eG +cv +aa +ab +aa +aa +ac +aa +dr +aa +aa +aa +aa +aa +di +aa +aa +dr +eN +fe +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +gp +cv +aa +Hz +Hz +RL +oz +UC +oz +GD +sJ +oz +HW +UC +oz +oz +Hz +aa +aa +aa +aa +aa +aa +aa +ab +aa +gE +zH +kY +gE +IA +hg +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +ap +ap +ap +ap +ap +aX +aE +aE +aE +aE +aE +aE +aE +aE +aE +aE +bw +ap +aa +aa +aa +aa +ac +aa +aa +cv +cH +cF +cU +cv +aa +ab +ac +di +dj +di +dr +aa +aa +aa +aa +di +di +di +di +dr +eO +ff +fq +fy +dj +di +ac +ac +ac +ac +ab +aa +cv +gn +cv +cv +Hz +BR +oz +oz +UC +oz +oz +sJ +oz +Jv +UC +oz +oz +Hz +aa +aa +aa +aa +aa +aa +aa +ab +aa +gE +zH +kY +gE +gE +le +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bY +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +ap +ap +ap +ap +ap +ap +ap +ap +ap +bx +ap +ap +ap +ap +ap +ac +aa +aa +cv +cI +cL +eG +cv +ac +ab +dd +di +di +dn +dr +di +di +di +di +di +dj +di +ej +dr +dr +dr +dr +fz +fI +fI +fV +fV +fV +rK +gd +fV +gk +gq +cv +fA +Hz +AG +oE +DZ +GS +oz +oz +MC +oz +HW +UC +DZ +Ad +Hz +aa +aa +aa +aa +aa +aa +aa +ac +aa +gE +zH +kY +gE +gE +lf +lx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ap +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +ap +aw +am +bO +am +cb +ap +aQ +aa +aa +cv +cJ +cJ +eG +cv +aa +ab +ac +di +dj +di +dr +aa +aa +aa +aa +di +di +di +aa +aa +aa +aa +dr +di +dj +di +ac +ac +ac +ac +ab +aa +cv +eG +cv +fA +Hz +mN +mN +mN +mN +mN +xZ +Me +mN +xZ +xZ +xZ +xZ +Hz +aa +aa +aa +aa +aa +aa +aa +ac +aa +gE +zH +kY +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ap +ap +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +ap +by +am +bP +am +cc +ap +aQ +aa +aa +cv +cv +cv +cS +cv +aa +ab +aa +aa +ac +aa +dr +aa +aa +aa +aa +aa +di +aa +aa +aa +aa +aa +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +fA +Hz +QB +rL +CI +Ja +mN +DZ +UK +Sq +Ag +Ag +Ec +IL +Hz +IA +gE +gE +gE +gE +gE +gE +Qe +gE +gE +wC +Kg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +ar +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +aQ +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +ap +am +am +bQ +am +am +ap +aQ +aa +aa +aa +aa +cv +eG +cv +aa +ab +aa +aa +ac +aa +dr +aa +aa +aa +aa +aa +di +aa +aa +aa +aa +aa +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +cv +Hz +SP +xM +CJ +Qs +mN +DZ +oQ +mN +AU +Bc +Ag +ta +Se +IA +kY +kY +kY +kY +kY +kY +kY +kY +Kg +zH +kY +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +ar +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +ap +am +am +bQ +am +aV +ap +aQ +aa +aa +aa +aa +cv +eH +cv +aa +ab +aa +aa +ac +aa +dr +di +dj +aa +aa +aa +di +aa +aa +aa +dj +di +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +gr +ew +do +Hz +MR +Dm +Dm +ww +Oz +Mh +TI +Ho +Gc +Si +ud +ud +TT +ue +CT +CT +CT +CT +CT +CT +CT +CT +BO +zJ +kY +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +am +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +ap +oe +bD +ap +ap +ap +ap +aQ +aa +aa +aa +aa +cv +eG +cv +aa +ab +pI +aa +ac +aa +dr +di +di +aa +aa +aa +di +aa +aa +aa +di +di +dr +ac +ac +ac +ac +ac +ac +ac +ab +aa +cv +eG +cv +eH +Hz +Ai +LN +Ox +Nj +mN +yy +Mp +xy +qQ +MJ +Nw +EG +CN +IA +gE +gE +gE +gE +gE +gE +gE +gE +gE +IX +gE +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +am +aw +ap +aa +aa +ab +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ap +aw +aA +aa +aa +aa +aa +aa +aa +ac +aa +ap +am +am +bO +am +cd +ap +ac +ac +ac +ac +ac +cv +eG +cv +ac +ab +ab +ab +ac +aa +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +dr +aa +ac +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +eG +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +Hz +IA +hl +oa +hg +hF +gE +aa +ab +aa +gE +gB +gE +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +as +aw +ap +aa +aa +aa +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ap +aw +aA +ac +ac +ac +ac +ac +ac +ac +ac +ap +am +am +bR +am +ce +ap +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +aa +ab +ac +aa +aa +ac +aa +aa +aa +di +ed +di +aa +aa +aa +ac +aa +aa +ac +aa +aa +aa +aa +fo +ab +ac +cv +eG +cv +gA +gE +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +ac +gE +hm +hg +hg +hg +gE +aa +ac +aa +gE +gB +gE +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +as +aw +ap +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +aA +aa +aa +aa +aa +aa +aQ +aQ +ac +ap +am +am +bO +am +am +ap +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +aa +ab +ac +ac +ac +ac +ac +ac +ac +dj +di +dj +ac +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +gB +gE +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +ac +gE +gB +hg +hu +hG +gE +aa +ac +gE +gE +gB +gE +gE +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +am +aw +ap +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aQ +aQ +ac +ap +bz +am +bO +am +aV +ap +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +aa +ab +ab +aa +aa +ac +aa +aa +aa +di +di +di +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +gC +IA +IA +IA +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +ho +gE +gE +gE +gE +gE +gE +gE +ka +gB +gE +Qe +ac +ac +ac +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +at +aw +ap +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +ac +ap +ap +ap +ap +ap +ap +ap +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +aa +aa +ab +pI +aa +ac +aa +aa +aa +ac +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +gD +gN +gN +gT +gN +gY +gN +ha +gN +gN +gN +gN +gN +gN +gN +gN +hp +gN +gN +gN +gN +gN +gN +gN +gN +kq +gE +gE +gE +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +at +aw +ap +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +cv +eG +cv +cv +cv +cv +aa +ab +ab +ab +ab +ab +aa +aa +ac +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +gE +IA +gQ +IA +gE +gE +gE +gE +gE +hd +hd +gE +nX +nY +nZ +nZ +nZ +hg +hg +ob +hg +oc +ip +od +iE +hg +hg +hg +gE +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +au +aw +ap +ap +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +cv +cW +cw +cw +de +cv +aa +aa +aa +aa +aa +ab +aa +aa +ac +aa +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +gF +IA +IA +IA +aa +aa +aa +aa +aa +aa +aa +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +gE +hg +gE +ac +ac +ac +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +au +az +aF +ap +ap +ap +ap +ad +ad +ad +ad +ap +ap +ap +ap +ap +ap +ap +aw +ap +ap +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +cv +cF +cF +cF +eG +cv +cv +cv +cv +cv +aa +ab +pI +aa +ac +aa +ac +CW +aa +aa +ac +aa +aa +CW +aa +aa +aa +aa +aa +ab +aa +cv +eG +cv +cv +cv +aa +aa +aa +aa +aa +aa +aa +bY +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ap +ap +am +az +aH +aE +aP +aE +aH +aE +aE +aH +aE +aP +aE +aU +aE +aE +aE +bc +aF +ap +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +cv +cv +cv +cP +df +cw +cw +cw +do +cv +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +cv +eG +gu +fT +cv +aa +aa +aa +aa +gJ +aa +aa +aa +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +ap +aA +ap +ap +ap +ap +ap +ap +am +am +ap +ap +ap +ap +ap +ap +ap +ap +ap +ay +ap +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +ac +aa +cv +eG +cF +cF +cF +cF +eG +cv +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +cv +eG +gv +gG +cv +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(129,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +ac +aa +aa +aa +aa +aa +ap +aR +am +aA +aa +aa +aa +ap +aZ +aZ +aZ +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +ac +aa +cv +cR +cv +cv +cv +dk +eG +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +cv +eG +cF +gH +cv +aa +aa +aa +aa +aa +aa +ac +ac +ac +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(130,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +ac +aa +aa +aa +aa +aa +ap +aI +aT +aA +aa +aa +aa +ap +aZ +aZ +aZ +ap +ax +ap +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +ac +ac +ac +aa +cv +eG +cv +aa +cv +dl +cW +cw +cw +cw +dK +cw +dm +cw +dy +cw +ew +eP +cw +dy +cw +dm +cw +cw +cw +cw +cw +dK +cw +cw +gs +cF +gI +cv +aa +aa +aa +aa +aa +ac +ac +aa +ac +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(131,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +ac +aa +aa +aa +aa +aa +ad +ad +ad +ad +aa +aa +aa +ap +aZ +aZ +aZ +ap +aw +ap +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +ac +aa +ap +ax +ap +aa +cv +cv +cv +cv +cv +cv +eG +cv +cv +cv +cv +ek +cF +eG +cF +cv +cv +cv +cv +cv +cv +cv +cv +eH +cv +cv +cv +gw +gw +cv +aa +aa +aa +aa +ac +ac +aa +aa +ac +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(132,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +aa +aa +ac +ac +ac +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +ap +ap +ap +ap +ap +aM +ap +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +ac +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +cv +cI +cL +eG +cF +cv +fA +fA +fA +fA +fA +fA +cv +eG +cv +aa +cv +cv +cv +cv +aa +aa +aa +ac +ac +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(133,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +ac +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ad +aG +aw +ap +ap +ap +ap +ap +ap +ap +ap +ap +aa +aa +aa +aa +ac +aa +aa +ab +ab +ab +ab +ac +aa +ap +ay +ap +aa +aa +aa +aa +aa +aa +cv +eG +cv +aa +aa +ef +cJ +cJ +eQ +fg +ef +fA +fA +fA +fA +fA +fA +ch +ge +ch +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +gE +hg +gE +ac +ac +ac +aa +aa +aa +aa +aa +KB +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(134,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +am +az +aU +aE +aP +aE +aU +aE +aE +aF +ap +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +ac +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +cv +dL +cv +aa +aa +ef +ef +ef +ef +ef +ef +fB +fB +fB +fB +fB +fB +ch +dN +ch +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +gE +kr +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(135,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aI +am +ap +ap +ap +ap +ap +ap +am +aw +ap +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +cv +cv +cv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +fD +ch +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(136,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +aa +aa +aa +aa +ap +am +aw +ap +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +aa +ap +aw +ap +aa +aa +aa +aa +aa +aa +ch +dM +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +gE +Yf +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(137,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +am +aw +ap +ap +ap +ap +ap +ad +ad +ad +ap +ap +ap +ap +ap +ap +ap +aw +ap +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +gE +gE +hg +gE +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(138,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +am +az +aU +aE +aP +aE +aU +aE +cg +cj +aH +aE +aP +aE +aH +aE +aE +aN +ap +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +gE +gE +hg +kt +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(139,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ap +ap +ap +ap +ap +ap +ap +ap +am +aI +by +ad +ap +ap +ap +ap +ap +ap +ap +ap +aa +aa +aa +aa +aa +aa +ch +dO +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bY +aa +ac +hd +jE +hg +ku +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(140,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ad +ad +ad +ck +ad +aZ +aZ +ap +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +ch +ch +dP +ch +ch +ch +ct +ct +ct +ct +ct +ct +ct +ct +fR +aa +aa +aa +ch +dN +ch +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +aQ +aQ +aQ +aQ +aa +aa +aa +aa +aa +aa +aa +aa +hd +jF +gQ +IA +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(141,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +ap +am +ap +aZ +aZ +ap +aa +aa +aa +aa +aa +aa +aa +aa +ch +dv +cm +dD +dN +cm +cm +cm +ct +el +ex +ex +ct +el +ex +ex +ct +aa +aa +aa +ch +dN +ch +ch +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +aQ +aQ +aQ +ac +aa +aa +aa +aa +aa +aa +aa +aa +IA +IA +IA +IA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(142,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +ap +cl +ap +aZ +aZ +ap +aa +aa +aa +aa +aa +aa +aa +aa +ch +dt +cm +cm +dN +cm +cm +cm +ct +em +ex +ex +ct +em +ex +ex +ct +aa +aa +aa +ch +fG +gh +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +aQ +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(143,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +ch +cm +ap +aZ +aZ +ap +aa +aa +aa +aa +aa +aa +aa +aa +ch +du +dw +dD +dN +cm +cm +cm +ct +em +ex +ex +ct +em +ex +ex +ct +aa +aa +aa +ch +cm +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aQ +aQ +aQ +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(144,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +ch +cn +ap +ap +ap +ap +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +ch +ch +dQ +dA +dA +dA +ct +en +ey +eR +ct +en +ey +eR +ct +aa +aa +aa +ch +cm +dN +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +aQ +aQ +aQ +ac +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(145,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +ch +cm +cm +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dv +cm +dD +dN +cm +cm +dx +ch +eo +cm +eS +cm +fr +cm +eS +ch +aa +aa +aa +ch +cm +dN +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aQ +aQ +aQ +aQ +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(146,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +cm +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +cm +cm +dR +cm +cm +ee +eg +ep +ee +eT +fh +eT +fh +fJ +ch +aa +aa +aa +ch +cm +dN +cm +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(147,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +cm +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dv +cm +cm +cm +cm +cm +dx +ch +cn +cm +cm +cm +fs +cm +eS +ch +aa +aa +aa +ch +ch +dN +cm +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(148,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +cm +cm +cD +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +dA +dA +cm +cm +dE +dx +ch +cm +cm +cm +dA +ft +ex +ft +ch +aa +aa +aa +aa +ch +dN +cs +cm +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(149,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +cm +cm +cD +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dw +dx +dx +cm +dx +dZ +dE +ch +eq +cm +cm +dA +ex +ex +ex +ch +aa +aa +aa +aa +ch +fG +fK +fK +gh +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(150,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +co +cs +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dx +dw +dE +cm +dx +dZ +dw +ch +er +cm +eU +ct +ex +ex +ex +ch +aa +aa +aa +aa +ch +ch +cp +cm +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +ac +ac +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(151,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cp +cs +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dw +dw +dw +cm +dw +dE +dZ +ch +es +cm +cm +ct +ex +ex +ex +ch +aa +aa +aa +aa +aa +ch +co +cm +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(152,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cq +cs +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +ch +ch +dS +ch +ch +ch +ch +ch +cD +ch +ch +ch +ch +ch +ch +aa +aa +aa +aa +aa +ch +cq +cm +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(153,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bY +ac +ch +ch +ch +cx +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dT +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(154,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(155,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +ch +cy +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(156,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ac +ac +ac +ac +ac +ac +ac +ac +ac +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(157,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cn +ch +cK +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(158,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cm +cm +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +fD +ch +aa +ac +ac +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(159,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cm +cm +cm +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +cm +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +ac +ac +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(160,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cz +cE +cm +cM +cm +cy +cm +dg +cm +cm +cm +cm +cm +cm +cm +cm +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ge +ch +aa +aa +aa +ac +ac +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(161,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +ct +ct +ct +ct +ct +ch +ch +ch +ch +ch +ch +ch +ch +ch +eZ +cm +cm +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(162,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +ac +aa +aa +aa +ch +ch +cm +cm +cm +cm +cm +cm +cm +cm +cm +cm +cm +es +ch +ch +ch +ch +ch +ch +ch +ct +ct +fD +ct +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +aa +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(163,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +ab +ab +ab +ab +aa +aa +aa +aa +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +fu +fC +fK +fK +fK +fK +fZ +fK +gf +fK +fY +fK +gx +fZ +fK +gf +fK +fY +fK +fK +fK +fK +fK +fK +fK +fK +gh +ch +aa +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(164,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +fv +dN +cm +ch +ch +ch +ch +ch +ch +ch +ct +cz +cE +ct +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +hj +ch +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(165,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +dN +ch +ch +aa +aa +aa +aa +aa +aa +ct +ct +ct +ct +aa +aa +ac +aa +aa +aa +aa +aa +ch +he +he +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(166,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ch +he +he +ch +ge +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(167,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ch +he +he +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(168,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ch +ch +ct +ct +hj +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(169,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +ac +ch +dN +ch +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ct +hh +dN +cK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(170,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ct +cz +dN +cK +aa +aa +bY +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(171,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ac +ac +ch +dN +ch +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +ct +cm +dN +cK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(172,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ch +ch +ch +ch +ch +ch +aa +aa +ct +ct +fD +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(173,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dv +dv +oh +cm +cm +ch +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(174,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bY +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +aa +aa +ch +dv +dv +cm +ch +dA +ch +aa +aa +aa +ch +ge +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(175,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cK +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +ac +ac +ch +cm +cm +cm +cm +cm +ch +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(176,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cK +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aQ +aQ +aa +aa +cK +cm +cm +cm +ch +cm +ch +ch +ch +ch +ch +hj +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(177,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cK +dN +ch +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +cK +cm +cM +cm +gZ +hb +fK +fK +fK +fK +fK +hk +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(178,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ch +dN +ch +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +cK +cm +ch +cm +ch +dA +ch +ch +ch +ch +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(179,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +ch +cm +dA +cm +hi +cm +ch +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(180,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +ch +gU +dA +cm +cm +cm +ch +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(181,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ch +dN +ch +aa +aa +aa +ac +ab +ab +ab +ab +ab +aa +aa +aa +ch +cm +cm +cm +cm +cm +ch +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(182,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ch +ch +ch +ch +ch +ch +ch +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(183,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +fD +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(184,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(185,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +ge +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(186,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yb +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +eV +fi +ct +fD +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ch +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(187,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +fj +ct +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +ct +ct +ct +ct +hj +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(188,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cm +ct +ge +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cz +cm +cs +cs +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(189,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +fk +ct +dN +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cn +fC +fK +fK +hf +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(190,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ez +ct +fl +ct +fF +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +cm +dN +ct +ct +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(191,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ez +eW +fm +fw +dN +fL +ch +ch +ch +ch +ch +ch +ct +ct +ct +cK +cK +ch +ch +ch +ch +ch +ch +ch +ct +cm +dN +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(192,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ez +eX +fn +cm +fG +fM +fS +fK +fY +fK +gf +fK +fZ +gl +fK +fK +fK +gO +fK +gf +fK +gO +fK +fK +fK +fK +hf +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(193,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ez +ct +ch +Wa +NK +ch +ct +ch +ch +ch +ch +ch +ct +cz +ct +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +ch +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(194,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +fp +cm +cm +fN +ct +aa +aa +aa +aa +aa +ct +ct +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(195,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +fp +fp +fp +fp +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(196,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +fp +fp +fp +fp +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(197,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +fp +fp +fp +fp +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(198,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ct +ct +ct +ct +ct +ct +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(199,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(200,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(201,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(202,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(203,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(204,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(205,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(206,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(207,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(208,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(209,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(210,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(211,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(212,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(213,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(214,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(215,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(216,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(217,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(218,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(219,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(220,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(221,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(222,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(223,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(224,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(225,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(226,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(227,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(228,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(229,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(230,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(231,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(232,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(233,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(234,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(235,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(236,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(237,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(238,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(239,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(240,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(241,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(242,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(243,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(244,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(245,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(246,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(247,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(248,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(249,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(250,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(251,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(252,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(253,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(254,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(255,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/exodus/exodus-2.dmm b/maps/exodus/exodus-2.dmm new file mode 100644 index 000000000000..a6fd60b3e000 --- /dev/null +++ b/maps/exodus/exodus-2.dmm @@ -0,0 +1,130377 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aaa" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Briefing Room" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/meeting) +"aab" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Firing Range" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/meeting) +"aac" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/space, +/area/space) +"aad" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + id_tag = "detdoor"; + name = "Detective" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/detectives_office) +"aae" = ( +/obj/structure/table/laminate, +/obj/item/chems/drinks/flask/barflask{ + pixel_x = -4; + pixel_y = 8 + }, +/obj/item/flashlight/lamp/green{ + pixel_x = 10; + pixel_y = 12 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"aaf" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"aag" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/floor/plating/airless, +/area/space) +"aah" = ( +/turf/wall/prepainted, +/area/space) +"aai" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Solar - Fore" + }, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"aaj" = ( +/obj/structure/girder/displaced, +/turf/floor/plating/airless, +/area/space) +"aak" = ( +/turf/floor/tiled/steel_grid, +/area/space) +"aal" = ( +/obj/structure/grille/broken, +/obj/item/shard{ + icon_state = "small" + }, +/turf/floor/plating/airless, +/area/space) +"aam" = ( +/obj/structure/grille, +/turf/space, +/area/space) +"aan" = ( +/obj/structure/grille/broken, +/turf/space, +/area/space) +"aao" = ( +/obj/item/clothing/suit/ianshirt, +/turf/floor/plating/airless, +/area/space) +"aap" = ( +/turf/floor/plating/airless, +/area/space) +"aaq" = ( +/obj/structure/grille/broken, +/obj/structure/lattice, +/turf/space, +/area/space) +"aar" = ( +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"aas" = ( +/obj/machinery/power/solar{ + id_tag = "auxsolarnorth"; + name = "Fore Solar Array" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"aat" = ( +/turf/wall/r_wall/prepainted, +/area/space) +"aav" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/solar{ + id_tag = "auxsolarnorth"; + name = "Fore Solar Array" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"aaw" = ( +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"aax" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/space) +"aay" = ( +/turf/wall/prepainted, +/area/exodus/security/range) +"aaz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaB" = ( +/obj/machinery/camera/network/security{ + c_tag = "Armory Exterior"; + dir = 4 + }, +/turf/space, +/area/space) +"aaC" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaD" = ( +/obj/structure/target_stake/steel, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaE" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaG" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/range) +"aaH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/range) +"aaI" = ( +/obj/structure/grille, +/obj/structure/lattice, +/turf/space, +/area/space) +"aaJ" = ( +/obj/item/stack/cable_coil/random, +/turf/space, +/area/space) +"aaK" = ( +/obj/structure/sign/warning/airlock{ + pixel_x = -32; + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"aaL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaO" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/window/eastleft{ + name = "Range Access" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaP" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/table/reinforced, +/obj/item/clothing/head/earmuffs{ + pixel_x = -3; + pixel_y = -2 + }, +/obj/item/clothing/head/earmuffs, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaQ" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaS" = ( +/obj/structure/closet/toolcloset, +/obj/item/clothing/head/hardhat/dblue, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"aaT" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/warden) +"aaU" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaV" = ( +/obj/structure/closet/crate, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/item/training_dummy, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaW" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/range) +"aaY" = ( +/obj/structure/table/reinforced, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/item/clothing/glasses/sunglasses, +/obj/item/clothing/glasses/sunglasses{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aaZ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"aba" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abb" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/security_starboard) +"abc" = ( +/obj/structure/lattice, +/obj/structure/grille/broken{ + dir = 4 + }, +/turf/space, +/area/space) +"abd" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/foresolar) +"abe" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"abf" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/security_port) +"abg" = ( +/obj/structure/rack, +/obj/item/gun/projectile/shotgun/pump, +/obj/item/gun/projectile/shotgun/pump, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"abh" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/tactical) +"abi" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"abj" = ( +/obj/structure/table/reinforced, +/obj/item/gun/energy/laser/practice, +/obj/machinery/door/firedoor, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abk" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abl" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/security{ + c_tag = "Security - Firing Range East"; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abm" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"abn" = ( +/obj/item/box/lights/mixed, +/obj/structure/rack{ + dir = 1 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"abo" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abp" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"abq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/range) +"abr" = ( +/obj/structure/flora/pottedplant/unusual{ + name = "Steve"; + desc = "This is an unusual plant. It's bulbous ends emit a soft blue light. The name Steve is written in black marker on the pot." + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"abs" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/main) +"abt" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"abu" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"abv" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"abw" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = -32 + }, +/turf/space, +/area/space) +"abx" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"aby" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/gun/energy/ionrifle, +/obj/item/gun/energy/ionrifle, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"abz" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "brig_solar_inner"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/foresolar) +"abA" = ( +/obj/machinery/camera/network/security{ + c_tag = "Armoury - Tactical Equipment" + }, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/structure/table, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"abB" = ( +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Weapons locker" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/box/flashbangs, +/obj/item/box/teargas, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"abC" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abD" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/main) +"abE" = ( +/obj/machinery/camera/network/security{ + c_tag = "Security - Firing Range West"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abF" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abG" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/airlock/maintenance{ + name = "Security Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/range) +"abH" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abI" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"abJ" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abK" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abL" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"abO" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/security/main) +"abP" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"abQ" = ( +/obj/machinery/power/tracker, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"abR" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/main) +"abS" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/main) +"abT" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/meeting) +"abU" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"abV" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"abW" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"abX" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "brig_solar_outer"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/foresolar) +"abY" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"abZ" = ( +/obj/machinery/button/access/exterior{ + id_tag = "brig_solar_airlock"; + name = "exterior access button"; + pixel_x = 25; + pixel_y = 25 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"aca" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"acb" = ( +/obj/machinery/door/airlock/engineering{ + name = "Fore Solar Access" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/foresolar) +"acc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/meeting) +"acd" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/security/meeting) +"ace" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"acf" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "brig_solar_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 1; + id_tag = "brig_solar_airlock"; + pixel_y = -25; + tag_airpump = "brig_solar_pump"; + tag_chamber_sensor = "brig_solar_sensor"; + tag_exterior_door = "brig_solar_outer"; + tag_interior_door = "brig_solar_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "brig_solar_sensor"; + pixel_x = 12; + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"acg" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/highsecurity{ + name = "Tactical Equipment" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/tactical) +"ach" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/meeting) +"aci" = ( +/obj/machinery/button/access/interior{ + id_tag = "brig_solar_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"acj" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"ack" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/security/main) +"acl" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/meeting) +"acm" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"acn" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/light/small/emergency{ + dir = 1 + }, +/obj/effect/shuttle_landmark/escape_pod/start/pod3, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_3) +"aco" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/meeting) +"acp" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/armoury) +"acq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/main) +"acr" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"act" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hos) +"acu" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Fore Access"; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"acv" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"acw" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/security/meeting) +"acx" = ( +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"acy" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"acz" = ( +/obj/structure/cable, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Fore"; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"acA" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"acB" = ( +/obj/machinery/power/solar_control{ + dir = 4; + id_tag = "auxsolarnorth"; + name = "Fore Solar Control" + }, +/obj/structure/cable/yellow, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/foresolar) +"acD" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"acE" = ( +/mob/living/simple_animal/passive/mouse, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"acF" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"acG" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"acH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"acI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"acJ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/item/airlock_brace, +/obj/item/airlock_brace, +/obj/item/airlock_brace, +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/item/crowbar/brace_jack, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"acK" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"acL" = ( +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"acM" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hos) +"acN" = ( +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/item/screwdriver{ + pixel_y = 15 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"acO" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/structure/table, +/obj/item/megaphone, +/obj/item/megaphone, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"acP" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/table, +/obj/machinery/recharger, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"acQ" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 1 + }, +/obj/item/box/lights/mixed, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"acR" = ( +/obj/structure/table, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/obj/item/folder/red, +/obj/item/folder/red, +/obj/item/taperecorder, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"acS" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acT" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hos) +"acU" = ( +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/security, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acV" = ( +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/structure/noticeboard{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acW" = ( +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acX" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acY" = ( +/obj/structure/disposalpipe/junction{ + dir = 2; + icon_state = "pipe-j2" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"acZ" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"ada" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"adb" = ( +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hos) +"adc" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"add" = ( +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"ade" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"adf" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "Armoury"; + name = "Emergency Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/armoury) +"adg" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adh" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adi" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adj" = ( +/obj/machinery/space_heater, +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adk" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adl" = ( +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adn" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ado" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/obj/item/box, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adp" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adq" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adr" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/vending/snack{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"ads" = ( +/obj/structure/sign/warning/vacuum{ + pixel_x = 32 + }, +/obj/structure/chair{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adt" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adu" = ( +/obj/structure/table/laminate, +/obj/item/flame/candle{ + pixel_x = -5; + pixel_y = 5 + }, +/obj/item/pen{ + pixel_x = -2; + pixel_y = -2 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adv" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adw" = ( +/obj/machinery/door/window/brigdoor/northleft{ + name = "Weapons locker" + }, +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/head/helmet/ablative, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"adx" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/warden) +"ady" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adA" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/flasher/portable{ + directional_offset = null + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adB" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"adC" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light, +/obj/machinery/flasher/portable{ + directional_offset = null + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adD" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/warden) +"adE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"adF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adG" = ( +/obj/structure/rack, +/obj/item/box/chemimp{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/item/box/trackimp, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adH" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adI" = ( +/obj/machinery/vending/cigarette{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/security/meeting) +"adK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adL" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/security/meeting) +"adM" = ( +/obj/machinery/door/window/brigdoor/northleft{ + name = "Weapons locker" + }, +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/item/clothing/suit/armor/vest, +/obj/item/clothing/suit/armor/vest, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/head/helmet/ballistic, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"adN" = ( +/obj/machinery/button/blast_door{ + id_tag = "Armoury"; + name = "Armoury Access"; + pixel_x = -1; + pixel_y = -28 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"adO" = ( +/obj/machinery/door/airlock/external{ + locked = 1; + name = "External Construction Airlock" + }, +/obj/structure/tape_barricade/engineering, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/security_starboard) +"adP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adQ" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"adR" = ( +/obj/structure/rack, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"adS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adT" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/warden) +"adU" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"adV" = ( +/obj/structure/chair/office/dark, +/obj/abstract/landmark/start{ + name = "Security Officer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adW" = ( +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adX" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adY" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"adZ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Briefing Room" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/meeting) +"aea" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 1; + name = "HoS Office"; + sort_type = "HoS Office" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hos) +"aeb" = ( +/obj/structure/table, +/obj/item/folder/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aec" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hos) +"aed" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aee" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/status_display/supply_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"aef" = ( +/obj/structure/table, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = -28 + }, +/obj/item/radio/headset/headset_sec, +/obj/item/radio/headset/headset_sec, +/obj/item/radio/headset/headset_sec, +/obj/item/radio/headset/headset_sec, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"aeg" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aeh" = ( +/obj/structure/table, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = -28 + }, +/obj/item/box/cdeathalarm_kit, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"aei" = ( +/obj/structure/closet/bombclosetsecurity, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aej" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Equipment North"; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aek" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/flasher/portable{ + directional_offset = null + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"ael" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"aem" = ( +/obj/machinery/button/blast_door{ + id_tag = "Armoury"; + name = "Emergency Access"; + pixel_x = -28; + pixel_y = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aen" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Security South" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeo" = ( +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aep" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Security Officer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aeq" = ( +/obj/machinery/network/requests_console{ + department = "Security"; + name = "Security RC"; + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aer" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/fore) +"aes" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/highsecurity{ + name = "Secure Armoury Section" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/warden) +"aet" = ( +/obj/structure/window/reinforced, +/obj/structure/table, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/obj/item/chems/spray/cleaner{ + pixel_x = -5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeu" = ( +/obj/structure/window/reinforced, +/obj/structure/table, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = -26 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aev" = ( +/obj/structure/window/reinforced, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aew" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hos) +"aex" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aey" = ( +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aez" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/window/reinforced, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/obj/structure/bed/roller, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeA" = ( +/obj/effect/floor_decal/corner/red, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeB" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeC" = ( +/turf/wall/prepainted, +/area/exodus/security/meeting) +"aeD" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aeE" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aeF" = ( +/turf/wall/prepainted, +/area/exodus/security/warden) +"aeG" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aeH" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeI" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aeJ" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aeK" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"aeL" = ( +/obj/machinery/deployable/barrier, +/obj/structure/sign/warning/armory{ + pixel_y = 32 + }, +/obj/machinery/camera/network/security{ + c_tag = "Armoury" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aeM" = ( +/obj/machinery/deployable/barrier, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aeN" = ( +/obj/structure/closet/l3closet/security, +/obj/structure/sign/warning/armory{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aeO" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aeP" = ( +/obj/structure/rack{ + pixel_y = 6 + }, +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Sub-Armory Storage" + }, +/obj/machinery/door/window/brigdoor/westleft{ + name = "Sub-Armory Storage" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced, +/obj/machinery/door/blast/shutters{ + dir = 4; + id_tag = "subarmory"; + name = "Sub-Armory Storage" + }, +/obj/effect/floor_decal/corner/red/full, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aeQ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"aeR" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"aeS" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/security_starboard) +"aeT" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aeU" = ( +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aeV" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aeW" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/security_port) +"aeX" = ( +/obj/structure/closet/secure_closet/security, +/obj/item/flashlight/flare, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aeY" = ( +/obj/machinery/button/blast_door{ + id_tag = "subarmory"; + name = "Sub-Armory Storage control"; + pixel_x = 24; + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"aeZ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/closet/secure_closet/security, +/obj/item/flashlight/flare, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afa" = ( +/obj/structure/table, +/obj/item/folder/red, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afb" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/abstract/landmark/start{ + name = "Security Officer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afc" = ( +/obj/structure/table, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afd" = ( +/obj/machinery/camera/network/security{ + c_tag = "Security - Briefing"; + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afe" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aff" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hos) +"afg" = ( +/obj/machinery/deployable/barrier, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afh" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afi" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afj" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afk" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afl" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afm" = ( +/obj/structure/grille/broken, +/obj/structure/lattice, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/turf/space, +/area/space) +"afn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afo" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"afp" = ( +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afq" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"afr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Sub-Armory" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/warden) +"afs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"aft" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 1; + name = "Security"; + sort_type = "Security" + }, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afu" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 4 + }, +/obj/item/box/fancy/donut, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afx" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afy" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"afz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afA" = ( +/obj/structure/rack, +/obj/item/toolbox/mechanical, +/obj/item/belt/utility, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/camera/xray/security{ + c_tag = "Security Escape Pod"; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afB" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/shuttle_landmark/escape_pod/start/pod1, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_1) +"afE" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afF" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afG" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"afI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/dark, +/area/exodus/security/tactical) +"afJ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/meter, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afK" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/red/full, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afL" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afM" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afN" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/red/full, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afO" = ( +/obj/structure/closet/wardrobe/red, +/obj/item/clothing/webbing/holster/waist, +/obj/item/clothing/webbing/holster/waist, +/obj/item/clothing/webbing/holster/waist, +/obj/item/clothing/armband, +/obj/item/clothing/armband, +/obj/item/clothing/armband, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"afP" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/shuttle/escape_pod_3) +"afQ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/interrogation) +"afR" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hos) +"afS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"afT" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"afU" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"afV" = ( +/obj/random/closet, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afW" = ( +/obj/structure/shuttle/engine/propulsion/burst{ + dir = 8 + }, +/obj/effect/paint/red, +/turf/wall/titanium, +/turf/space, +/area/shuttle/escape_pod_3) +"afX" = ( +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afY" = ( +/obj/structure/closet, +/obj/item/clothing/glasses/welding, +/obj/item/weldingtool, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"afZ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aga" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"agb" = ( +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"agc" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"agd" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"age" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/airlock/maintenance{ + name = "Security Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/meeting) +"agf" = ( +/obj/machinery/photocopier, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agg" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/meeting) +"agh" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ + dir = 1; + id_tag = "escape_pod_3"; + pixel_y = -25; + tag_door = "escape_pod_3_hatch" + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_3) +"agi" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agj" = ( +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/machinery/vending/cola{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agl" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth{ + dir = 8; + id_tag = "escape_pod_3_berth"; + pixel_x = 25; + pixel_y = 32; + tag_door = "escape_pod_3_berth_hatch" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"agm" = ( +/obj/machinery/network/relay, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"agn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"ago" = ( +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/obj/structure/filing_cabinet, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agp" = ( +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agq" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_3_berth_hatch"; + name = "Escape Pod" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/security_starboard) +"agr" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_3_hatch"; + name = "Escape Pod Hatch" + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_pod_3) +"ags" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"agt" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/baton/loaded, +/obj/item/baton/loaded, +/obj/item/baton/loaded, +/obj/item/baton/loaded, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"agu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"agv" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hos) +"agw" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"agx" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/clothing/mask/gas{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/item/clothing/mask/gas{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"agy" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agz" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agA" = ( +/obj/structure/disposalpipe/segment, +/obj/item/trash/raisins, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"agB" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"agC" = ( +/obj/machinery/atmospherics/valve{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor, +/area/exodus/security/brig) +"agD" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/brig) +"agE" = ( +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agF" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agG" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/obj/effect/floor_decal/corner/red, +/obj/item/stack/package_wrap, +/obj/item/box, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agH" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agI" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"agJ" = ( +/obj/structure/disposalpipe/segment, +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hos) +"agK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/detectives_office) +"agL" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table, +/obj/structure/reagent_dispensers/peppertank{ + pixel_x = 30 + }, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/crowbar, +/obj/item/crowbar, +/obj/item/crowbar, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agN" = ( +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/navbeacon/SecurityD, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/security/meeting) +"agO" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agP" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/command{ + id_tag = "HoSdoor"; + name = "Head of Security" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/hos) +"agQ" = ( +/obj/machinery/meter, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor, +/area/exodus/security/brig) +"agS" = ( +/obj/effect/paint_stripe/blue, +/turf/wall/titanium, +/area/shuttle/escape_pod_3) +"agT" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"agU" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"agV" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"agW" = ( +/turf/wall/prepainted, +/area/exodus/security/brig) +"agX" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Warden's Office" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/warden) +"agY" = ( +/obj/structure/closet/secure_closet/security, +/obj/item/flashlight/flare, +/obj/structure/window/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"agZ" = ( +/obj/machinery/door/window/eastright{ + dir = 8; + name = "Security Delivery" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aha" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/brig/processing) +"ahb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Secure Gate"; + name = "Security Blast Door" + }, +/turf/floor/plating, +/area/exodus/security/brig) +"ahc" = ( +/obj/structure/reagent_dispensers/peppertank{ + pixel_x = 30 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ahd" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Head of Security's Desk"; + name = "Head of Security RC"; + pixel_y = 32; + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahe" = ( +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahf" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahg" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Security Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/processing) +"ahh" = ( +/obj/machinery/photocopier, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahi" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/brig/interrogation) +"ahj" = ( +/obj/structure/closet{ + name = "Evidence Closet" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ahk" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "lawyer_blast"; + name = "Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/security/brig) +"ahl" = ( +/obj/structure/closet{ + name = "Evidence Closet" + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ahm" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ahn" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/table, +/obj/item/folder/red, +/obj/item/folder/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aho" = ( +/turf/wall/prepainted, +/area/exodus/security/brig/processing) +"ahp" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ahq" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ahr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ahs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aht" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"ahu" = ( +/obj/machinery/photocopier, +/obj/machinery/newscaster{ + pixel_x = -30; + pixel_y = 30 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"ahv" = ( +/obj/machinery/faxmachine/mapped, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"ahw" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/rack, +/obj/item/shield/riot, +/obj/item/clothing/head/helmet/riot, +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"ahx" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"ahy" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/security/brig) +"ahz" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/item/stamp/denied{ + pixel_x = 5 + }, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"ahA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"ahB" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor, +/area/exodus/security/brig) +"ahC" = ( +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/clipboard, +/obj/item/folder/red, +/obj/item/pen, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"ahD" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ahE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ahF" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-22" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ahG" = ( +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/obj/machinery/washing_machine, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ahH" = ( +/obj/structure/table/laminate, +/obj/item/megaphone, +/obj/item/radio/off, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"ahJ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahK" = ( +/turf/floor, +/area/exodus/security/brig) +"ahL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"ahM" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/shuttle_landmark/escape_pod/start/pod2, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_2) +"ahN" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/chair, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"ahO" = ( +/obj/structure/table/laminate, +/obj/machinery/keycard_auth{ + dir = 8 + }, +/obj/machinery/faxmachine/mapped, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahP" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ahQ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ahR" = ( +/obj/structure/window/reinforced, +/obj/machinery/recharge_station, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ahS" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/interrogation) +"ahT" = ( +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"ahU" = ( +/obj/structure/window/reinforced/tinted{ + dir = 1 + }, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/grille, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/brig/interrogation) +"ahV" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"ahW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Interrogation" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"ahX" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ahY" = ( +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ahZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"aia" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aib" = ( +/obj/item/eftpos{ + eftpos_name = "Brig EFTPOS scanner" + }, +/obj/machinery/door/window/brigdoor/westleft{ + name = "Warden's Desk" + }, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aic" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aid" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aie" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/security/prison/restroom) +"aif" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aig" = ( +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aih" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aii" = ( +/obj/item/hand_labeler, +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Warden's Desk" + }, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aij" = ( +/obj/machinery/door/airlock/security{ + name = "Evidence Storage" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/processing) +"aik" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"ail" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/vending/coffee{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aim" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ain" = ( +/obj/machinery/network/relay, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aio" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/computer/modular/preset/security{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/interrogation) +"aip" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"aiq" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"air" = ( +/obj/structure/table/laminate, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"ais" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/table/laminate, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ait" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"aiu" = ( +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/flashlight, +/obj/structure/rack, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aiv" = ( +/obj/structure/chair, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aiw" = ( +/obj/structure/table, +/obj/item/flashlight/lamp, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aix" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aiy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aiz" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/computer/modular/preset/security, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aiA" = ( +/obj/machinery/camera/network/security{ + c_tag = "Security - Interrogation Observation"; + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/interrogation) +"aiB" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Riot Control" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"aiC" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/security/brig) +"aiD" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"aiE" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"aiF" = ( +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/grille, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/security/brig/interrogation) +"aiG" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"aiH" = ( +/obj/structure/table, +/obj/item/flashlight/lamp, +/obj/item/taperecorder, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"aiI" = ( +/obj/structure/filing_cabinet, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"aiJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"aiK" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Warden" + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aiL" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aiM" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/recharger, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aiN" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aiO" = ( +/obj/machinery/vending/security{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aiP" = ( +/obj/structure/table/laminate, +/obj/item/taperecorder, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"aiQ" = ( +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"aiR" = ( +/obj/structure/table/laminate, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"aiS" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/item/folder/red, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"aiT" = ( +/obj/structure/table, +/obj/machinery/camera/network/security{ + c_tag = "Security - Processing"; + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/item/camera, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aiU" = ( +/obj/structure/closet/secure_closet/warden, +/obj/item/megaphone, +/obj/machinery/light{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"aiV" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aiW" = ( +/obj/structure/table, +/obj/item/taperecorder{ + pixel_x = -4; + pixel_y = 2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aiX" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/interrogation) +"aiY" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/interrogation) +"aiZ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"aja" = ( +/obj/structure/window/reinforced/tinted, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/grille, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/security/brig/interrogation) +"ajb" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/interrogation) +"ajc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "lawyer_blast"; + name = "Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/lawoffice) +"ajd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"aje" = ( +/obj/structure/closet{ + name = "Evidence Closet" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ajf" = ( +/obj/structure/chair/comfy/black{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Head of Security" + }, +/obj/machinery/button/alternate/door{ + id_tag = "HoSdoor"; + name = "Office Door"; + pixel_x = -36; + pixel_y = 29 + }, +/obj/machinery/button/windowtint{ + pixel_x = -26; + pixel_y = 30 + }, +/obj/machinery/button/blast_door{ + id_tag = "Secure Gate"; + name = "Brig Lockdown"; + pixel_x = -36; + pixel_y = 39 + }, +/obj/machinery/button/blast_door{ + id_tag = "Prison Gate"; + name = "Security Lockdown"; + pixel_x = -24; + pixel_y = 39 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hos) +"ajg" = ( +/obj/structure/table, +/obj/item/folder/red{ + pixel_x = 2; + pixel_y = 4 + }, +/obj/item/pen, +/obj/item/hand_labeler, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Evidence Storage"; + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ajh" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Secure Gate"; + name = "Security Blast Door" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"aji" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/security/brig/processing) +"ajj" = ( +/obj/machinery/computer/prisoner{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"ajk" = ( +/obj/structure/chair/wood/walnut{ + dir = 8 + }, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"ajm" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/rack, +/obj/item/shield/riot, +/obj/item/clothing/head/helmet/riot, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/camera/network/security{ + c_tag = "Armoury - Secure"; + dir = 4 + }, +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"ajn" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Equipment South"; + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ajo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ajp" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Secure Gate"; + name = "Security Blast Door" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ajq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "brigobs"; + name = "Security Blast Door" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ajr" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ajs" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "brigobs"; + name = "brigobs" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ajt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"aju" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "brigobs"; + name = "Security Blast Door" + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ajv" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/lobby) +"ajw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ajx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ajy" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ajz" = ( +/obj/structure/disposaloutlet{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"ajA" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Firefighting equipment" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/security_port) +"ajB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/item/wrench, +/turf/floor, +/area/exodus/security/brig) +"ajC" = ( +/obj/machinery/door/window/westright, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/obj/structure/window/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"ajE" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"ajF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ajG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ajH" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"ajI" = ( +/obj/structure/table, +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = -28 + }, +/obj/item/clothing/badge/holo, +/obj/item/clothing/badge/holo, +/obj/item/clothing/badge/holo/cord, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ajJ" = ( +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = -28 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"ajK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/newscaster{ + pixel_x = -30; + dir = 8 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - HoS' Office"; + dir = 1 + }, +/obj/machinery/papershredder, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ajL" = ( +/obj/structure/table/laminate, +/obj/machinery/newscaster{ + pixel_x = 28; + pixel_y = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/item/camera, +/obj/item/camera, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"ajM" = ( +/obj/machinery/computer/modular/preset/security{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ajN" = ( +/obj/structure/shuttle/engine/propulsion/burst, +/obj/effect/paint/red, +/turf/wall/titanium, +/turf/space, +/area/shuttle/escape_pod_1) +"ajO" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ajP" = ( +/obj/structure/closet/secure_closet/hos, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ajQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/light, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"ajR" = ( +/obj/structure/table, +/obj/item/box/evidence, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"ajS" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ajT" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Warden's Office" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/warden) +"ajU" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Equipment Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/main) +"ajV" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Equipment Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/main) +"ajW" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ajX" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ajY" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ajZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aka" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"akc" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ake" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akf" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akg" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/light, +/obj/machinery/light_switch{ + pixel_x = -14; + pixel_y = -25 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"akh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"aki" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akj" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akk" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/processing) +"akl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akm" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akn" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ako" = ( +/turf/wall/prepainted, +/area/exodus/security/detectives_office) +"akp" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"akq" = ( +/obj/item/clothing/mask/gas, +/obj/item/clothing/glasses/meson, +/obj/structure/rack, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"akr" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/item/radio/beacon, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aks" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akt" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aku" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akv" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akx" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Interrogation Observation" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/interrogation) +"aky" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/security, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"akz" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akA" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akB" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/bookcase, +/obj/structure/noticeboard{ + default_pixel_y = 27 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"akC" = ( +/obj/structure/rack, +/obj/item/briefcase{ + pixel_x = -2; + pixel_y = -5 + }, +/obj/item/briefcase{ + pixel_x = 3 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"akD" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/obj/item/secure_storage/safe{ + pixel_x = 6; + pixel_y = 28 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Forensic Office Fore" + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"akE" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-21" + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"akF" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"akG" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/table/laminate, +/obj/item/flash, +/obj/item/clothing/glasses/sunglasses, +/obj/item/chems/spray/pepper, +/obj/item/taperecorder{ + pixel_x = -4; + pixel_y = 2 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"akH" = ( +/obj/machinery/power/tracker, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"akI" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akJ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akK" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akL" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akM" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akN" = ( +/obj/machinery/door_timer/cell_3{ + pixel_y = -32 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akO" = ( +/obj/machinery/button/blast_door{ + id_tag = "Cell 3"; + name = "Cell 3 Door"; + pixel_x = -1; + pixel_y = -28 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akP" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akQ" = ( +/obj/machinery/light, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akR" = ( +/turf/wall/prepainted, +/area/exodus/security/brig/interrogation) +"akS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akT" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"akU" = ( +/obj/structure/table/laminate, +/obj/item/ashtray/plastic, +/obj/item/box/fancy/cigarettes/dromedaryco, +/obj/item/clothing/gloves/forensic, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"akV" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Brig Center"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Security Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"akX" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akY" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"akZ" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"ala" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alb" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alc" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ald" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ale" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/computer/guestpass{ + pixel_y = -29 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Brig East"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alf" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Firefighting equipment" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/security_starboard) +"alg" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ali" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alj" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alk" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"all" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 1; + name = "Atmospherics"; + sort_type = "Atmospherics"; + sortdir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"alm" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/item/stool/padded, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"aln" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"alo" = ( +/obj/structure/rack, +/obj/item/flame/fuelled/lighter/random, +/obj/item/box/fancy/cigarettes/dromedaryco, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"alp" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"alq" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Interrogation" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/interrogation) +"alr" = ( +/obj/machinery/atmospherics/unary/tank/nitrous_oxide{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor, +/area/exodus/security/brig) +"als" = ( +/obj/machinery/door/airlock/external{ + locked = 1; + name = "External Construction Airlock" + }, +/obj/structure/tape_barricade/engineering, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/security_starboard) +"alt" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"alu" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"alv" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alw" = ( +/obj/structure/closet/secure_closet/detective, +/obj/item/chems/drinks/flask/detflask, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"alx" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"aly" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alz" = ( +/obj/structure/closet/secure_closet/brig, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alB" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/security{ + name = "Evidence Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/processing) +"alC" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Detective" + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"alD" = ( +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"alE" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/table/laminate, +/obj/machinery/button/alternate/door{ + id_tag = "detdoor"; + name = "Office Door" + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"alF" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"alG" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"alH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/brig/processing) +"alI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Security Processing" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/processing) +"alJ" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"alK" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/obj/structure/table/glass, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/item/pen/blue{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/hand_labeler, +/obj/item/folder/red, +/obj/item/folder/blue, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"alL" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"alM" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/security/brig/processing) +"alN" = ( +/obj/machinery/door/window/brigdoor/northright, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"alO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/window/brigdoor/northleft, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"alP" = ( +/turf/floor/plating, +/area/exodus/security/brig) +"alQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"alR" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Security Processing" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/processing) +"alS" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/brig/processing) +"alT" = ( +/obj/machinery/light_switch{ + pixel_x = -25; + dir = 4 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"alU" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"alV" = ( +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"alW" = ( +/turf/wall/prepainted, +/area/exodus/security/prison) +"alX" = ( +/obj/machinery/power/tracker, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"alY" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/brig/processing) +"alZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/warden) +"ama" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amb" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amc" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amd" = ( +/obj/machinery/door/firedoor, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/door/window/brigdoor/eastleft, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ame" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amf" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amg" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor/westright, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"ami" = ( +/turf/wall/prepainted, +/area/exodus/lawoffice) +"amj" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/machinery/button/alternate/door{ + id_tag = "prisonentry"; + name = "Entry Doors"; + pixel_x = -6; + pixel_y = 24 + }, +/obj/machinery/button/alternate/door{ + id_tag = "prisonexit"; + name = "Exit Doors"; + pixel_x = 6; + pixel_y = 24 + }, +/obj/machinery/button/flasher{ + id_tag = "permentryflash"; + name = "entry flash"; + pixel_x = -26; + pixel_y = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aml" = ( +/turf/wall/prepainted, +/area/exodus/security/main) +"amm" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control switch for the brig foyer."; + id_tag = "BrigFoyer"; + name = "Brig Foyer Doors"; + pixel_x = 28; + pixel_y = -15 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amn" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"amo" = ( +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"amp" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"amq" = ( +/obj/structure/table/reinforced, +/obj/item/folder{ + pixel_x = -4 + }, +/obj/item/folder/red{ + pixel_y = 3 + }, +/obj/item/folder/blue{ + pixel_x = 5 + }, +/obj/item/folder/yellow, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amr" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"ams" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "lawyer_blast"; + name = "Privacy Shutters"; + pixel_x = -25; + dir = 4 + }, +/obj/item/clipboard, +/obj/item/hand_labeler, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/papershredder, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"amw" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"amx" = ( +/obj/machinery/door/airlock/engineering{ + name = "Security Substation" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"amy" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"amz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"amA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amB" = ( +/obj/structure/closet/wardrobe/lawyer_black, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amC" = ( +/obj/structure/table/reinforced, +/obj/item/flashlight/lamp, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amD" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amE" = ( +/obj/item/stool/padded, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"amF" = ( +/obj/structure/flora/pottedplant{ + icon_state = "plant-10" + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"amG" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"amH" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/power_sensor{ + id_tag = "Security Subgrid"; + name = "Powernet Sensor - Security Subgrid" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"amI" = ( +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"amJ" = ( +/obj/machinery/power/solar{ + id_tag = "auxsolareast"; + name = "Port Auxiliary Solar Array" + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"amK" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"amL" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"amM" = ( +/obj/machinery/atmospherics/valve{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor, +/area/exodus/security/brig) +"amN" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Brig Toxin Control"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor, +/area/exodus/security/brig) +"amO" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/structure/cable/green, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/security/prison) +"amP" = ( +/obj/structure/chair/office/dark, +/obj/abstract/landmark/start{ + name = "Internal Affairs Agent" + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"amQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amT" = ( +/obj/structure/flora/pottedplant{ + icon_state = "plant-10" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amU" = ( +/obj/structure/closet/secure_closet/brig, +/obj/machinery/camera/network/security{ + c_tag = "Security - Prison Processing"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"amV" = ( +/obj/machinery/flasher{ + id_tag = "Cell 3"; + pixel_x = -28 + }, +/obj/structure/bed/padded, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amW" = ( +/obj/structure/closet/secure_closet/brig{ + id = "Cell 3"; + name = "Cell 3 Locker" + }, +/obj/machinery/camera/network/prison{ + c_tag = "Security - Brig Cell 3"; + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amX" = ( +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amY" = ( +/obj/machinery/flasher{ + id_tag = "permentryflash"; + name = "Floor mounted flash" + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"amZ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/button/flasher{ + id_tag = "permflash"; + name = "Brig flashes"; + pixel_y = -27; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ana" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"anb" = ( +/obj/machinery/button/flasher{ + id_tag = "permflash"; + name = "Brig flashes"; + pixel_x = -6; + pixel_y = -24 + }, +/obj/machinery/button/blast_door{ + id_tag = "brigobs"; + name = "observation shutters"; + pixel_x = 6; + pixel_y = -24 + }, +/obj/machinery/button/blast_door{ + id_tag = "Secure Gate"; + name = "Brig Lockdown"; + pixel_x = -26; + pixel_y = -4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"anc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/obj/machinery/door/blast/regular/open{ + id_tag = "Secure Gate"; + name = "Security Blast Door" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"ane" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"anf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/disposalpipe/trunk, +/obj/machinery/disposal, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Prison Observation"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ang" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "lawyer_blast"; + name = "Privacy Shutters" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/lawoffice) +"anh" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"ani" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "Secure Gate"; + name = "Security Blast Door" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/window/brigdoor/southleft{ + id_tag = "Cell 3"; + name = "Cell 3" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"anj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"ank" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "Cell 2"; + name = "Cell Door" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"anl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"anm" = ( +/obj/structure/table/reinforced, +/obj/item/pen/blue{ + pixel_x = -5; + pixel_y = -1 + }, +/obj/item/pen/red{ + pixel_x = -1; + pixel_y = 3 + }, +/obj/item/stamp/denied{ + pixel_x = 4; + pixel_y = -2 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"ann" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"ano" = ( +/obj/item/secure_storage/safe{ + pixel_x = -23 + }, +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"anp" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"anq" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/laminate, +/obj/machinery/button/alternate/door{ + id_tag = "detdoor"; + name = "Office Door" + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"anr" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"ans" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/structure/sign/warning/high_voltage{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"ant" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/security/prison) +"anu" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"anv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "EVA\\Security Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/security_port) +"anw" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"anx" = ( +/obj/machinery/door/airlock/glass/security{ + id_tag = "prisonexit"; + name = "Brig Exit" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"any" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/hallway/primary/fore) +"anz" = ( +/obj/machinery/door/airlock/glass/security{ + id_tag = "BrigFoyer"; + name = "Security Wing" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"anA" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/security/brig) +"anB" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"anC" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"anD" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"anE" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"anF" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"anG" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/detectives_office) +"anH" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"anI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"anJ" = ( +/obj/machinery/door_timer/cell_6{ + id_tag = "Cell 2"; + name = "Cell 2"; + pixel_x = 32 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"anK" = ( +/obj/machinery/door/blast/regular{ + id_tag = "Cell 3"; + name = "Cell Door" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"anL" = ( +/obj/machinery/door/airlock/glass/security{ + id_tag = "prisonentry"; + name = "Brig Entry" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"anM" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"anN" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"anO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"anP" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/table/laminate, +/obj/item/photo_album{ + pixel_y = -10 + }, +/obj/item/camera_film, +/obj/item/camera_film, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"anQ" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/substation/security) +"anR" = ( +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Security Substation Bypass" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"anS" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"anT" = ( +/obj/structure/table/reinforced, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/ashtray/plastic{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/box/fancy/cigarettes/dromedaryco, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"anU" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/abstract/landmark{ + name = "Syndicate Breach Area" + }, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"anV" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"anW" = ( +/obj/item/secure_storage/safe{ + pixel_x = 32 + }, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"anX" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/evahallway) +"anY" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"anZ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aob" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Holodeck North"; + pixel_y = -6 + }, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"aoc" = ( +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Security" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"aod" = ( +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"aoe" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Detective" + }, +/turf/floor/carpet, +/area/exodus/security/detectives_office) +"aof" = ( +/obj/structure/table/laminate, +/obj/item/flash, +/obj/item/chems/spray/pepper, +/obj/item/clothing/glasses/sunglasses, +/obj/item/taperecorder{ + pixel_x = -4; + pixel_y = 2 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"aog" = ( +/obj/machinery/network/requests_console{ + department = "Security"; + name = "Security RC"; + pixel_x = 32; + dir = 4 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"aoh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aoi" = ( +/obj/machinery/ai_slipper, +/obj/machinery/camera/all/command{ + c_tag = "AI Chamber"; + dir = 1 + }, +/obj/machinery/power/smes/buildable{ + charge = 5e+006; + input_attempt = 1; + input_level = 125000; + output_attempt = 1; + output_level = 100000 + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"aoj" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/sleep/cryo) +"aok" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/light_switch{ + pixel_x = -25; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aol" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"aom" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"aon" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/security) +"aoo" = ( +/obj/machinery/power/solar{ + id_tag = "auxsolareast"; + name = "Port Auxiliary Solar Array" + }, +/obj/structure/cable/yellow, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"aop" = ( +/obj/machinery/power/solar{ + id_tag = "auxsolareast"; + name = "Port Auxiliary Solar Array" + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"aoq" = ( +/turf/unsimulated/mask, +/area/exodus/maintenance/security_port) +"aor" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aos" = ( +/obj/machinery/door/airlock/glass/security{ + id_tag = "BrigFoyer"; + name = "Security Wing" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig) +"aot" = ( +/obj/machinery/button/blast_door{ + id_tag = "Cell 2"; + name = "Cell 2 Door"; + pixel_x = 30; + pixel_y = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aou" = ( +/obj/structure/closet/secure_closet/brig{ + id = "Cell 2"; + name = "Cell 2 Locker" + }, +/obj/machinery/camera/network/prison{ + c_tag = "Security - Brig Cell 2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aov" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aow" = ( +/obj/machinery/computer/arcade, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/camera/network/prison{ + c_tag = "Security - Common Brig Northwest" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aox" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoy" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoz" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoA" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoB" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/engineering{ + name = "Security Substation" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/security) +"aoD" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aoE" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"aoG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoH" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/dormitory) +"aoI" = ( +/obj/structure/table, +/obj/item/tool/hoe/mini, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aoJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aoK" = ( +/obj/machinery/faxmachine/mapped{ + anchored = 0 + }, +/obj/structure/table/reinforced, +/obj/machinery/newscaster{ + pixel_x = 28; + pixel_y = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aoL" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/table, +/obj/machinery/camera/network/security{ + c_tag = "Security - Lobby"; + dir = 4 + }, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aoM" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor/westleft, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aoN" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aoO" = ( +/obj/structure/hygiene/shower{ + dir = 8; + pixel_x = -5; + pixel_y = -2 + }, +/obj/structure/curtain/open/shower, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aoP" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aoQ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aoR" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aoS" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aoT" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aoU" = ( +/obj/machinery/photocopier, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"aoV" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aoW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aoX" = ( +/obj/machinery/papershredder, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"aoY" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aoZ" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apa" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"apb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"apc" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/exterior) +"apd" = ( +/obj/machinery/photocopier, +/obj/machinery/network/requests_console{ + department = "Internal Affairs"; + name = "Internal Affairs RC"; + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"ape" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"apf" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apg" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/maintenance{ + name = "Dormitory\\Security Maintenance" + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aph" = ( +/obj/structure/grille, +/turf/floor/plating/airless, +/area/exodus/maintenance/exterior) +"api" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/security/detectives_office) +"apj" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"apk" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"apl" = ( +/obj/structure/cable, +/obj/effect/engine_setup/smes, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Engine - Main"; + charge = 2.5e+005; + input_attempt = 1; + input_level = 1e+006; + output_attempt = 1; + output_level = 1e+006; + uncreated_component_parts = list(/obj/item/stock_parts/smes_coil/super_capacity = 4) + }, +/turf/floor/plating, +/area/exodus/engineering/engine_smes) +"apm" = ( +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine control room blast doors."; + id_tag = "EngineEmitterPortWest"; + name = "Engine Room Blast Doors"; + pixel_y = 25 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/engine_setup/empty_canister, +/obj/structure/sign/warning/radioactive{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"apn" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"apo" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"app" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"apq" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor/eastright, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"apr" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aps" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"apt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"apu" = ( +/obj/random/obstruction, +/turf/floor, +/area/exodus/maintenance/evahallway) +"apv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"apw" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"apx" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "dorm_inner"; + name = "Dormitory Internal Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/dormitory) +"apy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"apz" = ( +/obj/machinery/flasher{ + id_tag = "permflash"; + name = "Floor mounted flash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"apA" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"apB" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"apC" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ + dir = 4; + id_tag = "escape_pod_1"; + pixel_x = -25; + tag_door = "escape_pod_1_hatch" + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_1) +"apD" = ( +/obj/structure/girder, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"apE" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"apF" = ( +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"apG" = ( +/obj/structure/chair/wood/wings, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"apH" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"apI" = ( +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"apJ" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/obj/structure/table/glass, +/obj/item/scanner/reagent, +/obj/item/scanner/spectrometer, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/ai_monitored/storage/eva) +"apL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/window/northleft{ + name = "Forensics Area" + }, +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apM" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/brig/solitaryB) +"apN" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table/glass, +/obj/item/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/chems/spray/antiseptic, +/obj/item/chems/spray/cleaner{ + pixel_x = -5 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apO" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"apP" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/table/reinforced, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"apQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"apR" = ( +/obj/structure/closet/secure_closet/lawyer, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"apS" = ( +/obj/structure/chair/office/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apT" = ( +/obj/structure/table/glass, +/obj/item/forensics/sample_kit/powder, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"apU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"apV" = ( +/obj/machinery/power/solar{ + id_tag = "auxsolareast"; + name = "Port Auxiliary Solar Array" + }, +/obj/structure/cable/yellow, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"apW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/network/security{ + c_tag = "Security - Brig West"; + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"apX" = ( +/obj/structure/bed/padded, +/obj/machinery/flasher{ + id_tag = "Cell 2"; + pixel_y = -26 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"apY" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"apZ" = ( +/obj/machinery/button/access/interior{ + id_tag = "dorm_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = 25 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aqa" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqb" = ( +/obj/structure/chair, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqc" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "on"; + id_tag = "air_in"; + use_power = 1 + }, +/obj/structure/chair, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqe" = ( +/obj/structure/chair, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqf" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aqg" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqh" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aqj" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aqk" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aql" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aqm" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock{ + name = "Internal Affairs" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/lawoffice) +"aqn" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aqo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"aqp" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aqq" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"aqr" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"aqs" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "E.V.A. Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/ai_monitored/storage/eva) +"aqt" = ( +/obj/structure/table/gamblingtable, +/obj/item/board, +/obj/item/box/checkers/chess/red, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"aqu" = ( +/obj/structure/table/gamblingtable, +/obj/item/deck/cards{ + pixel_y = 4 + }, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"aqv" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aqw" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"aqx" = ( +/obj/item/stool, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/camera/network/security{ + c_tag = "Security - Solitary Confinement North" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryB) +"aqy" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Internal Affairs Agent" + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aqz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"aqA" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/dormitory) +"aqB" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aqC" = ( +/obj/item/stool/padded, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"aqD" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/entry/pods) +"aqE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"aqF" = ( +/obj/structure/table, +/obj/item/pen, +/obj/item/paper, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryB) +"aqG" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/table/reinforced, +/obj/item/ashtray/plastic{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/box/fancy/cigarettes/dromedaryco, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aqH" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "lawyer_blast"; + name = "Privacy Shutters" + }, +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/window/eastright{ + base_state = "left"; + icon_state = "left"; + name = "Internal Affairs Desk" + }, +/turf/floor, +/area/exodus/lawoffice) +"aqI" = ( +/obj/structure/table/reinforced, +/obj/item/folder{ + pixel_x = -4 + }, +/obj/item/folder/red{ + pixel_y = 3 + }, +/obj/item/folder/blue{ + pixel_x = 5 + }, +/obj/item/folder/yellow, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"aqJ" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "dorm_pump" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aqK" = ( +/obj/machinery/airlock_sensor{ + id_tag = "dorm_sensor"; + pixel_x = 25; + pixel_y = -8; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aqL" = ( +/obj/machinery/shield_diffuser, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"aqM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table/glass, +/obj/machinery/forensic/microscope, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"aqN" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqO" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqP" = ( +/obj/structure/table, +/obj/item/dice, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"aqQ" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/pods) +"aqR" = ( +/obj/structure/table, +/obj/item/dice, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqS" = ( +/obj/structure/table, +/obj/item/taperecorder{ + pixel_x = -4; + pixel_y = 2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqT" = ( +/obj/structure/table, +/obj/item/ashtray/plastic, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqU" = ( +/obj/structure/table, +/obj/machinery/vending/wallmed1{ + pixel_y = -32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqV" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqW" = ( +/obj/structure/table, +/obj/item/box/cups, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aqY" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"aqZ" = ( +/obj/machinery/button/alternate/door{ + id_tag = "visitdoor"; + name = "Visitation Access"; + pixel_y = -28; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"ara" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"arb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/yjunction, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"arc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"ard" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/lobby) +"are" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"arf" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Holodeck South"; + dir = 1; + pixel_y = 6 + }, +/turf/floor/plating, +/area/exodus/crew_quarters/fitness) +"arg" = ( +/obj/structure/table/glass, +/obj/item/forensics/sample_kit, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"arh" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"ari" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/machinery/computer/ship/sensors, +/obj/effect/overmap/visitable/ship/exodus, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"arj" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/closet{ + name = "Evidence Closet" + }, +/obj/item/box/bodybags, +/obj/item/box/evidence, +/obj/item/box/swabs, +/obj/machinery/camera/network/security{ + c_tag = "Security - Forensic Office Aft"; + dir = 1 + }, +/obj/item/box/fingerprints, +/obj/item/box/beakers, +/obj/item/box/syringes, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"ark" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"arl" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/forensic/dnascanner, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"arm" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/security/detectives_office) +"arn" = ( +/obj/structure/table, +/obj/item/radio/headset, +/obj/item/radio/headset, +/obj/item/radio/headset, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aro" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"arp" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -25 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/structure/filing_cabinet, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"arq" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "lawyer_blast"; + name = "Privacy Shutters"; + pixel_y = -25; + dir = 1 + }, +/obj/item/pen/blue{ + pixel_x = -5; + pixel_y = -1 + }, +/obj/item/pen/red{ + pixel_x = -1; + pixel_y = 3 + }, +/obj/item/stamp/denied{ + pixel_x = 4; + pixel_y = -2 + }, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"arr" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/table/reinforced, +/obj/structure/cable/green, +/obj/machinery/camera/network/security{ + c_tag = "Security - IA Office"; + dir = 1 + }, +/obj/item/flashlight/lamp, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"ars" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "dorm_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"art" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "dorm_airlock"; + name = "Dormitory Airlock Console"; + pixel_x = 25; + tag_airpump = "dorm_pump"; + tag_chamber_sensor = "dorm_sensor"; + tag_exterior_door = "dorm_outer"; + tag_interior_door = "dorm_inner" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aru" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"arv" = ( +/obj/machinery/button/blast_door{ + id_tag = "Cell 1"; + name = "Cell 1 Door"; + pixel_x = 30; + pixel_y = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"arw" = ( +/obj/structure/table, +/obj/item/dice/d20, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"arx" = ( +/turf/wall/prepainted, +/area/exodus/security/brig/solitaryB) +"ary" = ( +/obj/structure/closet/secure_closet/brig{ + id = "Cell 1"; + name = "Cell 1 Locker" + }, +/obj/machinery/camera/network/prison{ + c_tag = "Security - Brig Cell 1" + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"arz" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eva_inner"; + name = "EVA Internal Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/evahallway) +"arA" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/primary/fore) +"arB" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"arC" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "eva_airlock"; + name = "EVA Airlock Console"; + pixel_y = 25; + tag_airpump = "eva_pump"; + tag_chamber_sensor = "eva_sensor"; + tag_exterior_door = "eva_outer"; + tag_interior_door = "eva_inner" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"arD" = ( +/obj/structure/table/gamblingtable, +/obj/item/box/checkers/chess, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"arE" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/fore) +"arF" = ( +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"arG" = ( +/obj/structure/table, +/obj/item/newspaper, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"arH" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"arI" = ( +/obj/structure/disposalpipe/segment, +/turf/wall/r_wall/prepainted, +/area/exodus/security/detectives_office) +"arJ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"arK" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/library) +"arL" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/security/prison) +"arM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryB) +"arN" = ( +/obj/machinery/vending/cigarette{ + dir = 8 + }, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"arO" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Security Lobby" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/fore) +"arP" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "Prison Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Security Lobby" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/fore) +"arQ" = ( +/obj/structure/table/reinforced, +/obj/item/clipboard, +/obj/item/hand_labeler, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/tiled/dark, +/area/exodus/lawoffice) +"arR" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"arT" = ( +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 21 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"arU" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"arW" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryB) +"arX" = ( +/obj/machinery/button/access/interior{ + id_tag = "eva_airlock"; + name = "interior access button"; + pixel_y = 25 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"arY" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"arZ" = ( +/obj/machinery/door/airlock/glass/security{ + name = "Solitary Confinement 2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/solitaryB) +"asa" = ( +/obj/structure/chair/wood/wings{ + dir = 1 + }, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"asb" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"asc" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/window/brigdoor/eastleft{ + id_tag = "Cell 2"; + name = "Cell 2" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"asd" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"ase" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asf" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Detective Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/security/detectives_office) +"asg" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "Cell 1"; + name = "Cell Door" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"ash" = ( +/obj/machinery/button/access/exterior{ + id_tag = "solar_chapel_airlock"; + name = "exterior access button"; + pixel_x = -25; + pixel_y = -25 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxstarboard) +"asi" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asj" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "dorm_outer"; + name = "Dormitory External Access" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/dormitory) +"ask" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asl" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asm" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asn" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/item/chems/glass/bucket, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aso" = ( +/obj/machinery/light/small, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"asp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asq" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asr" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"ass" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryB) +"ast" = ( +/obj/structure/bed/padded, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryB) +"asv" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asw" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/brig/solitaryA) +"asx" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ + dir = 4; + id_tag = "escape_pod_2"; + pixel_x = -25; + tag_door = "escape_pod_2_hatch" + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_2) +"asy" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"asz" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"asA" = ( +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/pods) +"asB" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"asC" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/clothing/shoes/magboots, +/obj/item/clothing/shoes/magboots, +/obj/item/suit_cooling_unit, +/obj/item/suit_cooling_unit, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"asD" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solar_chapel_outer"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/auxsolarstarboard) +"asE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asF" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asG" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asH" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asI" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "solar_chapel_airlock"; + pixel_x = 25; + tag_airpump = "solar_chapel_pump"; + tag_chamber_sensor = "solar_chapel_sensor"; + tag_exterior_door = "solar_chapel_outer"; + tag_interior_door = "solar_chapel_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "solar_chapel_sensor"; + pixel_x = 25; + pixel_y = 12 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "solar_chapel_pump" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"asJ" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asK" = ( +/obj/machinery/door_timer/cell_1{ + pixel_x = 32; + pixel_y = -32 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"asM" = ( +/obj/structure/bed/padded, +/obj/machinery/flasher{ + id_tag = "Cell 1"; + pixel_y = -28 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asN" = ( +/turf/wall/prepainted, +/area/exodus/security/brig/solitaryA) +"asO" = ( +/obj/item/stool, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/camera/network/security{ + c_tag = "Security - Solitary Confinement South" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryA) +"asP" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asR" = ( +/obj/structure/table, +/obj/item/pen, +/obj/item/paper, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryA) +"asS" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/obj/machinery/newscaster{ + pixel_x = 28; + pixel_y = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"asT" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solar_chapel_inner"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/auxsolarstarboard) +"asU" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"asW" = ( +/turf/wall/prepainted, +/area/exodus/security/prison/dorm) +"asX" = ( +/obj/structure/chair{ + dir = 8 + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"asY" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "visit_blast"; + name = "Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/security/prison/dorm) +"asZ" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/dormitory) +"ata" = ( +/obj/machinery/door/airlock{ + name = "Visitation Area" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison/dorm) +"atb" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_x = -32 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"atc" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"atd" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ate" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "Secure Gate"; + name = "Security Blast Door" + }, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "visit_blast"; + name = "Privacy Shutters" + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/security/prison/dorm) +"atf" = ( +/obj/structure/lattice, +/obj/structure/sign/warning/biohazard{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"atg" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/prison/dorm) +"ath" = ( +/obj/structure/disposalpipe/segment, +/mob/living/bot/secbot/beepsky, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"ati" = ( +/obj/machinery/button/access/interior{ + id_tag = "solar_chapel_airlock"; + name = "interior access button"; + pixel_x = 25; + pixel_y = 25 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"atj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"atk" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"atl" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"ato" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/shuttle/escape_pod_1) +"atq" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/pods) +"ats" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/library) +"att" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"atu" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/shuttle/escape_pod_2) +"atv" = ( +/obj/effect/floor_decal/industrial/warning/cee{ + dir = 1; + icon_state = "warningcee" + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"atw" = ( +/obj/machinery/door/airlock{ + id_tag = "visitdoor"; + name = "Visitation Area" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison/dorm) +"atx" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/prison) +"aty" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"atz" = ( +/obj/machinery/navbeacon/Security, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"atA" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/sign/directions/evac{ + pixel_x = -30; + pixel_z = -4 + }, +/obj/structure/sign/directions/medical{ + pixel_x = -30; + pixel_z = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"atB" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"atC" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"atD" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/sleep) +"atE" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/sleep) +"atF" = ( +/obj/machinery/suit_cycler/generic/prepared, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"atG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"atH" = ( +/obj/structure/cryofeed{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"atI" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"atJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/starboard) +"atK" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/abstract/landmark/latejoin/cryo, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"atL" = ( +/obj/machinery/cryopod{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/network/requests_console{ + department = "Crew Quarters"; + pixel_y = 32; + dir = 1 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"atM" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/abstract/landmark/latejoin/cryo, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"atN" = ( +/obj/structure/rack, +/obj/item/clothing/suit/space/void/security/prepared, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"atO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/fitness) +"atP" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/fitness) +"atQ" = ( +/obj/machinery/shield_diffuser, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/pods) +"atR" = ( +/obj/machinery/computer/cryopod, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Cryo Storage" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"atS" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/entry/fore) +"atT" = ( +/obj/structure/cryofeed, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"atU" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"atV" = ( +/obj/machinery/cryopod, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"atW" = ( +/turf/floor/reinforced, +/area/exodus/crew_quarters/fitness) +"atX" = ( +/obj/effect/paint_stripe/blue, +/turf/wall/titanium, +/area/shuttle/escape_pod_1) +"atY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryA) +"atZ" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"aub" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"auc" = ( +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aud" = ( +/obj/effect/paint_stripe/blue, +/turf/wall/titanium, +/area/shuttle/escape_pod_2) +"aue" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"auf" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_1_berth_hatch"; + name = "Escape Pod" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/pods) +"aug" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"auh" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryA) +"aui" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"auj" = ( +/obj/machinery/door/airlock/glass/security{ + name = "Solitary Confinement 1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/brig/solitaryA) +"auk" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/primary/central_one) +"aul" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aum" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/chapel/main) +"aun" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/window/brigdoor/eastleft{ + id_tag = "Cell 1"; + name = "Cell 1" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison) +"auo" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aup" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"auq" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aur" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig) +"aus" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aut" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"auu" = ( +/obj/machinery/flasher{ + id_tag = "IAflash"; + pixel_x = -30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"auv" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"auw" = ( +/obj/machinery/atm{ + pixel_x = -25; + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"aux" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"auy" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Bedroom Fore" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/sleep/bedrooms) +"auz" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"auA" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"auB" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/reagent_dispensers/watertank, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"auC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"auD" = ( +/obj/abstract/landmark/latejoin/cryo, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"auE" = ( +/obj/machinery/cryopod{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"auF" = ( +/obj/abstract/landmark/latejoin/cryo, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"auG" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"auH" = ( +/obj/machinery/cryopod, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"auI" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Fitness Room"; + sort_type = "Fitness Room" + }, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"auJ" = ( +/obj/structure/window/basic{ + dir = 8 + }, +/obj/effect/floor_decal/spline/plain{ + dir = 8 + }, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"auK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"auL" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"auM" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"auN" = ( +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/fore) +"auO" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"auP" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"auQ" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/arrivals) +"auR" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"auS" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"auT" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"auU" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/computer/cryopod, +/obj/machinery/light_switch{ + pixel_x = -25; + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"auV" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_2_berth_hatch"; + name = "Escape Pod" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/pods) +"auW" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth{ + id_tag = "escape_pod_1_berth"; + pixel_x = -25; + pixel_y = 25; + tag_door = "escape_pod_1_berth_hatch" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"auX" = ( +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"auY" = ( +/obj/structure/window/basic{ + dir = 4 + }, +/obj/effect/floor_decal/spline/plain{ + dir = 4 + }, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"auZ" = ( +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ava" = ( +/obj/structure/closet/secure_closet/personal, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"avb" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"avc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"avd" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/vending/cola, +/obj/effect/floor_decal/corner/grey{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ave" = ( +/obj/machinery/button/access/exterior{ + id_tag = "admin_shuttle_dock_airlock"; + name = "exterior access button"; + pixel_x = -28; + pixel_y = -6 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "admin_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"avf" = ( +/obj/structure/shuttle/engine/propulsion/burst, +/obj/effect/paint/red, +/turf/wall/titanium, +/turf/space, +/area/shuttle/escape_pod_2) +"avg" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"avh" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"avi" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"avj" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"avk" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"avl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"avm" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"avn" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryA) +"avo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"avp" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"avq" = ( +/obj/structure/bed/padded, +/turf/floor/tiled/steel_grid, +/area/exodus/security/brig/solitaryA) +"avr" = ( +/obj/machinery/portable_atmospherics/powered/scrubber/huge, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"avs" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"avt" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"avu" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"avv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"avw" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"avx" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/sleep/bedrooms) +"avy" = ( +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"avz" = ( +/obj/machinery/cryopod, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"avA" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"avB" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"avC" = ( +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"avD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"avE" = ( +/obj/machinery/cryopod{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/crew_quarters/sleep/cryo) +"avF" = ( +/obj/abstract/landmark/latejoin/cryo, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"avG" = ( +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/cryo) +"avH" = ( +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"avI" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"avJ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"avK" = ( +/obj/effect/floor_decal/corner/white, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"avL" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"avM" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/sign/directions/pods{ + dir = 1; + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"avN" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "admin_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"avO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"avP" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"avQ" = ( +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"avR" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"avS" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/hologram/holopad, +/obj/abstract/landmark/paperwork_finish_exodus, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"avT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"avU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/command{ + c_tag = "Bridge Center"; + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"avV" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"avW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock{ + id_tag = "Dormitory 2"; + name = "Dorm" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/sleep) +"avX" = ( +/obj/machinery/door/airlock/engineering{ + name = "Fore Starboard Solar Access" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/auxsolarstarboard) +"avY" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals North" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"avZ" = ( +/obj/machinery/button/access/exterior{ + id_tag = "arrivals_airlock"; + name = "exterior access button"; + pixel_x = -25; + pixel_y = -25 + }, +/turf/space, +/area/space) +"awa" = ( +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Engine - Core"; + charge = 5e+006; + input_attempt = 1; + input_level = 250000; + inputting = 1; + output_attempt = 1; + output_level = 250000 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/effect/engine_setup/smes, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"awb" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eva_outer"; + name = "EVA External Access" + }, +/obj/machinery/button/access/exterior{ + id_tag = "eva_airlock"; + name = "exterior access button"; + pixel_y = 25 + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/evahallway) +"awc" = ( +/obj/machinery/airlock_sensor{ + id_tag = "eva_sensor"; + pixel_y = 25 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "eva_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"awd" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "arrivals_outer"; + name = "Engineering External Access" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/arrivals) +"awe" = ( +/obj/machinery/camera/xray/security{ + c_tag = "Arrivals Escape Pods" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"awf" = ( +/obj/machinery/door/airlock/engineering{ + name = "Fore Port Solar Access" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/auxsolarport) +"awg" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"awh" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"awi" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/library) +"awj" = ( +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"awk" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"awl" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Secure Gate"; + name = "Secure Gate" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Visitation" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"awm" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/microwave, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"awn" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"awo" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"awp" = ( +/obj/structure/table, +/obj/item/box/donkpockets, +/obj/item/box/donkpockets{ + pixel_x = -3; + pixel_y = -3 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"awq" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/structure/sign/warning/radioactive{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"awr" = ( +/obj/machinery/seed_storage/garden{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aws" = ( +/obj/machinery/vending/hydronutrients{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"awt" = ( +/obj/structure/table, +/obj/structure/bedsheetbin/mapped, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"awu" = ( +/obj/machinery/button/flasher{ + id_tag = "IAflash"; + pixel_y = -30; + dir = 1 + }, +/obj/machinery/button/blast_door{ + id_tag = "visit_blast"; + name = "Privacy Shutters"; + pixel_x = 25; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"awv" = ( +/turf/wall/prepainted, +/area/exodus/security/prison/restroom) +"aww" = ( +/obj/machinery/washing_machine, +/obj/effect/floor_decal/corner/white/diagonal, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"awx" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"awy" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/prison/restroom) +"awz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"awA" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"awB" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_1_hatch"; + name = "Escape Pod Hatch" + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_pod_1) +"awC" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_2_hatch"; + name = "Escape Pod Hatch" + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_pod_2) +"awD" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"awE" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/sleep/bedrooms) +"awF" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"awG" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth{ + id_tag = "escape_pod_2_berth"; + pixel_x = -25; + pixel_y = 25; + tag_door = "escape_pod_2_berth_hatch" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"awH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"awI" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"awJ" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/sign/directions/pods{ + dir = 1; + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"awK" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"awL" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"awM" = ( +/obj/machinery/door/airlock/glass{ + name = "Cryogenic Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/sleep/cryo) +"awN" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"awO" = ( +/obj/machinery/door/airlock/glass{ + name = "Cryogenic Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/sleep/cryo) +"awP" = ( +/obj/machinery/door/airlock/glass{ + name = "Cryogenic Storage" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/sleep/cryo) +"awQ" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Fitness Room West"; + dir = 4 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"awR" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eva_inner"; + name = "EVA Internal Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/evahallway) +"awS" = ( +/obj/effect/floor_decal/corner/white/full{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"awT" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"awU" = ( +/obj/effect/floor_decal/corner/white/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"awV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"awW" = ( +/obj/machinery/button/access/exterior{ + id_tag = "solar_tool_airlock"; + name = "exterior access button"; + pixel_x = -25; + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/auxport) +"awX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Fore Port Access" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"awY" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"awZ" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"axa" = ( +/obj/machinery/door/airlock{ + id_tag = "Dormitory 1"; + name = "Dorm" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/sleep) +"axb" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "eva_pump" + }, +/obj/machinery/camera/network/security{ + c_tag = "Security Airlock Access"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor, +/area/exodus/maintenance/evahallway) +"axc" = ( +/turf/floor, +/area/exodus/maintenance/evahallway) +"axd" = ( +/obj/structure/cable, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"axe" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"axf" = ( +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"axg" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitories Central" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axh" = ( +/turf/floor/carpet, +/area/exodus/crew_quarters/sleep/bedrooms) +"axi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"axj" = ( +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = 10 + }, +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"axk" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"axl" = ( +/obj/effect/floor_decal/corner/grey{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axm" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axn" = ( +/obj/machinery/atm{ + pixel_y = 28 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axo" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eva_outer"; + name = "EVA External Access" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/evahallway) +"axp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axq" = ( +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axr" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axs" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"axt" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axu" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axw" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"axx" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"axy" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/fitness) +"axz" = ( +/turf/floor/tiled/white, +/area/exodus/crew_quarters/fitness) +"axA" = ( +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/fitness) +"axC" = ( +/obj/machinery/door/airlock/glass{ + name = "Holodeck" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/fitness) +"axD" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"axE" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hydroponics) +"axF" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/port) +"axG" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"axH" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"axI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/sign/warning/airlock{ + pixel_x = -32 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/random/obstruction, +/turf/floor, +/area/exodus/maintenance/evahallway) +"axJ" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"axK" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"axL" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"axM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"axN" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/closet/firecloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"axO" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/engineering{ + name = "Civilian East Substation" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/civilian_east) +"axP" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/disposalpipe/junction{ + dir = 4; + icon_state = "pipe-j2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"axQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"axR" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"axS" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/closet/secure_closet/personal, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"axT" = ( +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axU" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/closet/secure_closet/personal, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"axV" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24; + pixel_y = 6 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axW" = ( +/obj/item/stool/padded, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axX" = ( +/obj/item/t_scanner, +/obj/structure/table/steel, +/obj/machinery/recharger, +/turf/floor/plating, +/area/exodus/maintenance/security_port) +"axY" = ( +/obj/structure/table/laminate, +/obj/item/clothing/glasses/threedglasses, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"axZ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/stool/padded, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aya" = ( +/obj/structure/table/laminate, +/obj/random/coin, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayb" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/fitness) +"ayc" = ( +/obj/machinery/hologram/holopad, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"ayd" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"aye" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayf" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayg" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayh" = ( +/obj/effect/floor_decal/corner/white{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayi" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"ayj" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "admin_shuttle_dock_pump" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"ayk" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"ayl" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aym" = ( +/obj/machinery/apc/high{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"ayn" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"ayp" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"ayq" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"ayr" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"ays" = ( +/obj/structure/chair/comfy/beige{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"ayt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"ayu" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"ayv" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Fore"; + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"ayw" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"ayx" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayy" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/structure/sign/directions/pods{ + dir = 4; + pixel_x = 32 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"ayz" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayA" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ayB" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/library) +"ayC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ayD" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = -32 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ayE" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ayF" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/library) +"ayG" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ayH" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/stool/padded, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/evahallway) +"ayJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"ayK" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Crematorium Maintenance" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/office) +"ayL" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/ai_monitored/storage/eva) +"ayM" = ( +/obj/machinery/light/small, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"ayN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"ayO" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/glass{ + name = "Escape Pods" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"ayP" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayQ" = ( +/obj/structure/table/laminate, +/obj/item/paicard, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/item/stock_parts/computer/hard_drive/portable, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayR" = ( +/obj/structure/table/laminate, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayS" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/arrivals) +"ayT" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/item/stool/padded, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"ayV" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/double/glass/civilian{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/fitness) +"ayX" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"ayZ" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aza" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"azb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/turf/floor/plating, +/area/exodus/bridge) +"azc" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"azd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aze" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Fitness Room East"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"azf" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"azg" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"azh" = ( +/obj/structure/closet/emcloset, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azi" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azj" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solar_tool_outer"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/auxsolarport) +"azk" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azl" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azm" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azn" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/fore) +"azo" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/turf/floor/plating, +/area/exodus/bridge) +"azp" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azq" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Northwest" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azr" = ( +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azs" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azu" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azv" = ( +/obj/machinery/vending/cola, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"azx" = ( +/obj/machinery/door/airlock/glass/medical{ + name = "Medical Voidsuits" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/ai_monitored/storage/eva) +"azy" = ( +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"azz" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"azA" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"azB" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"azC" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"azD" = ( +/obj/machinery/power/solar_control{ + id_tag = "auxsolareast"; + name = "Fore Starboard Solar Control" + }, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"azE" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/turf/floor/plating, +/area/exodus/bridge) +"azF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/security{ + name = "Security Voidsuits" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/ai_monitored/storage/eva) +"azG" = ( +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"azH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/turf/floor/plating, +/area/exodus/bridge) +"azI" = ( +/obj/machinery/door/firedoor, +/obj/structure/door_assembly, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"azJ" = ( +/obj/machinery/camera/network/civilian_east{ + c_tag = "Kitchen Cold Room" + }, +/obj/structure/closet/secure_closet/freezer/fridge, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"azK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/primary/central_two) +"azL" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/crew_quarters/kitchen) +"azM" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/crew_quarters/kitchen) +"azN" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hydroponics/garden) +"azO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"azP" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"azQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"azR" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"azS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"azT" = ( +/obj/structure/rack, +/obj/item/clothing/suit/space/void/security/prepared, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"azU" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"azV" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"azW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"azX" = ( +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"azY" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"azZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/grey/three_quarters, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aAa" = ( +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAb" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"aAc" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aAd" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aAe" = ( +/obj/structure/closet/lasertag/blue, +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aAf" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aAg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/glass{ + name = "Holodeck Control" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/fitness) +"aAh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"aAi" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aAj" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aAk" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aAl" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "admin_shuttle_dock_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "admin_shuttle_dock_sensor"; + pixel_x = -20; + pixel_y = 8; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"aAm" = ( +/obj/machinery/vending/coffee, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aAn" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aAo" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aAp" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 8; + id_tag = "admin_shuttle_dock_airlock"; + pixel_x = 30; + tag_airpump = "admin_shuttle_dock_pump"; + tag_chamber_sensor = "admin_shuttle_dock_sensor"; + tag_exterior_door = "admin_shuttle_dock_outer"; + tag_interior_door = "admin_shuttle_dock_inner" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"aAq" = ( +/obj/machinery/door/airlock/external/bolted_open, +/obj/machinery/door/firedoor, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"aAr" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"aAs" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Solar - Fore Port" + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aAt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aAu" = ( +/obj/structure/table/reinforced, +/obj/item/secure_storage/briefcase, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aAv" = ( +/obj/machinery/power/solar_control{ + id_tag = "auxsolareast"; + name = "Fore Port Solar Control" + }, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aAw" = ( +/obj/machinery/door/airlock/external/bolted_open, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/arrival/station) +"aAx" = ( +/obj/machinery/door/airlock/external/bolted_open, +/obj/machinery/door/firedoor, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aAy" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "solar_tool_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "solar_tool_sensor"; + pixel_x = 25; + pixel_y = 12; + dir = 8 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "solar_tool_airlock"; + pixel_x = 25; + tag_airpump = "solar_tool_pump"; + tag_chamber_sensor = "solar_tool_sensor"; + tag_exterior_door = "solar_tool_outer"; + tag_interior_door = "solar_tool_inner" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aAz" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aAE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aAF" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/auxsolarport) +"aAG" = ( +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aAH" = ( +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aAI" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aAJ" = ( +/obj/structure/table/reinforced, +/obj/item/box/PDAs{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/ids, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aAK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aAL" = ( +/obj/structure/table/reinforced, +/obj/item/clothing/head/welding, +/obj/item/belt/utility, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aAN" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/item/radio/beacon, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aAO" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/ai_monitored/storage/eva) +"aAP" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/machinery/camera/network/security{ + c_tag = "EVA Northeast"; + dir = 8 + }, +/obj/item/stack/material/pane/mapped/rglass{ + amount = 50 + }, +/obj/item/stack/material/rods{ + amount = 50 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aAQ" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"aAR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/sleep/bedrooms) +"aAS" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/grey, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAT" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAU" = ( +/obj/machinery/light_switch{ + pixel_y = -25; + dir = 1 + }, +/obj/structure/undies_wardrobe, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAV" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-22" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAW" = ( +/obj/structure/closet/wardrobe/pjs, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAX" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aAY" = ( +/obj/structure/closet/secure_closet/personal, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aAZ" = ( +/obj/structure/table/reinforced, +/obj/item/flash, +/obj/item/flash, +/obj/item/aicard, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aBa" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/clothing/suit/space/void/medical/prepared, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aBb" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"aBc" = ( +/obj/structure/closet/wardrobe/pjs, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aBd" = ( +/obj/machinery/door/airlock{ + name = "Unisex Showers" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aBe" = ( +/obj/structure/closet, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBf" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aBg" = ( +/obj/machinery/light, +/obj/structure/closet, +/obj/effect/floor_decal/corner/grey/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBh" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-06" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBi" = ( +/obj/machinery/light_switch{ + pixel_y = -25; + dir = 1 + }, +/obj/structure/closet/athletic_mixed, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBj" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/toilet) +"aBk" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBl" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"aBm" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBo" = ( +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aBp" = ( +/obj/item/stool, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aBq" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/crew_quarters/kitchen) +"aBr" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aBs" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_one) +"aBt" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBu" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_two) +"aBv" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals South" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBw" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/vending/snack, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBx" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/lapvend, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBy" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hydroponics/garden) +"aBz" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aBA" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/clothing/suit/space/void/engineering/prepared, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aBB" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBC" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aBE" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Southwest" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/button/access/interior{ + id_tag = "nuke_shuttle_dock_airlock"; + name = "interior access button"; + pixel_x = -28; + pixel_y = 26 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBG" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aBH" = ( +/obj/item/stool, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aBI" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/entry/port) +"aBK" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "nuke_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aBL" = ( +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/port) +"aBM" = ( +/obj/random/trash, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aBP" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aBQ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aBR" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aBS" = ( +/obj/machinery/power/terminal, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aBT" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aBU" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aBV" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBW" = ( +/obj/structure/table, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aBX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aBY" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/security/nuke_storage) +"aBZ" = ( +/obj/machinery/network/requests_console{ + department = "EVA"; + pixel_x = -32; + dir = 8 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/item/multitool, +/obj/machinery/camera/network/security{ + c_tag = "EVA Northwest"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aCb" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aCc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/ai_monitored/storage/eva) +"aCd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aCe" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aCf" = ( +/obj/machinery/suit_cycler/security/prepared, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aCg" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/fore) +"aCh" = ( +/obj/structure/table, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aCi" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aCj" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"aCk" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = 10 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"aCl" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aCm" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/clothing/mask/breath, +/obj/item/clothing/suit/space, +/obj/item/clothing/head/helmet/space, +/obj/item/clothing/mask/breath, +/obj/item/clothing/suit/space, +/obj/item/clothing/head/helmet/space, +/obj/item/clothing/mask/breath, +/obj/item/clothing/suit/space, +/obj/item/clothing/head/helmet/space, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aCn" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aCo" = ( +/obj/structure/hygiene/shower{ + dir = 4; + pixel_x = 5 + }, +/obj/structure/curtain/open/shower, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aCp" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aCq" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aCr" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aCs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aCt" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aCu" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/substation/civilian_east) +"aCv" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/auxsolarstarboard) +"aCw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/apc/high{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aCx" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aCy" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 8 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aCz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aCA" = ( +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aCB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aCC" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/turf/floor/tiled/dark/monotile, +/area/exodus/security/nuke_storage) +"aCD" = ( +/obj/structure/closet/crate, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/obj/item/cash/c1000, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aCE" = ( +/turf/wall/prepainted, +/area/exodus/security/checkpoint2) +"aCF" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/tiled/dark/monotile, +/area/exodus/security/nuke_storage) +"aCG" = ( +/obj/machinery/nuclearbomb/station, +/turf/floor/tiled/dark/monotile, +/area/exodus/security/nuke_storage) +"aCH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/bridge) +"aCI" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aCJ" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aCK" = ( +/turf/wall/prepainted, +/area/exodus/storage/primary) +"aCS" = ( +/obj/structure/table/reinforced, +/obj/item/assembly/signaler, +/obj/item/assembly/signaler, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aCT" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aCU" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aCV" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/rack{ + dir = 8 + }, +/obj/item/clothing/suit/space/void/atmos/prepared, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aCW" = ( +/obj/structure/table/reinforced, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel{ + amount = 10 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aCX" = ( +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitory Bedroom Aft"; + dir = 1 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/sleep/bedrooms) +"aCY" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/mime, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/curtain/open/bed, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"aCZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aDa" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/structure/mirror{ + pixel_x = -28 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aDb" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aDc" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aDd" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aDe" = ( +/obj/structure/grille, +/obj/structure/sign/warning/docking_area{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/exterior) +"aDf" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/obj/item/bikehorn/rubberducky, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aDg" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/turf/floor/tiled/dark, +/area/shuttle/arrival/station) +"aDh" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/three_quarters, +/turf/floor/tiled/dark/monotile, +/turf/floor/tiled/dark, +/area/shuttle/arrival/station) +"aDi" = ( +/obj/structure/table/laminate, +/obj/machinery/fabricator/book, +/obj/item/stack/material/panel/mapped/plastic/ten, +/obj/item/stack/material/plank/mapped/wood/ten, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aDj" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/shuttle/arrival/station) +"aDk" = ( +/obj/machinery/atmospherics/pipe/zpipe/down/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/zpipe/down/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/zpipe/down/cyan{ + dir = 1 + }, +/obj/structure/lattice, +/turf/floor/plating, +/turf/open, +/area/exodus/engineering/sublevel_access) +"aDl" = ( +/obj/machinery/atmospherics/pipe/zpipe/down/red{ + dir = 1 + }, +/obj/structure/lattice, +/turf/floor/plating, +/turf/open, +/area/exodus/engineering/sublevel_access) +"aDm" = ( +/obj/structure/reagent_dispensers/beerkeg, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aDn" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aDo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals East"; + dir = 8 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aDp" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/bar) +"aDq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aDr" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aDs" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/bar) +"aDt" = ( +/obj/structure/closet/lasertag/red, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/fitness) +"aDu" = ( +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Civilian East" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_east) +"aDv" = ( +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Civilian East Substation Bypass" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_east) +"aDw" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/stack/package_wrap, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aDx" = ( +/obj/structure/reagent_dispensers/peppertank{ + pixel_y = 30 + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/machinery/computer/modular/preset/security, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aDy" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/fitness) +"aDz" = ( +/obj/structure/closet/secure_closet/security, +/obj/item/flashlight/flare, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aDA" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aDB" = ( +/obj/machinery/power/terminal, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aDC" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/library) +"aDD" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"aDE" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/chapel/main) +"aDF" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"aDH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aDI" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aDJ" = ( +/obj/machinery/vending/assist, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aDK" = ( +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/arrival/station) +"aDL" = ( +/obj/structure/table, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aDM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aDN" = ( +/obj/structure/table, +/obj/machinery/network/requests_console{ + department = "Tool Storage"; + pixel_y = 32; + dir = 1 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Tool Storage - Primary" + }, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aDO" = ( +/obj/structure/table, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aDP" = ( +/obj/structure/table, +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aDQ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/bridge) +"aDR" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/item/toolbox/electrical{ + pixel_x = 1; + pixel_y = -1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aDS" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aDT" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aDU" = ( +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aDV" = ( +/obj/structure/closet/gmcloset, +/obj/item/eftpos{ + eftpos_name = "Bar EFTPOS scanner" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/item/glass_jar, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aDW" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aDX" = ( +/obj/machinery/atmospherics/valve, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aDY" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Solar - Fore Starboard" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Fore Starboard"; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aDZ" = ( +/obj/machinery/smartfridge, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aEa" = ( +/obj/item/coin/silver{ + pixel_x = 7; + pixel_y = 12 + }, +/obj/item/coin/silver{ + pixel_x = 12; + pixel_y = 7 + }, +/obj/item/coin/silver{ + pixel_x = 4; + pixel_y = 8 + }, +/obj/item/coin/silver{ + pixel_x = -6; + pixel_y = 5 + }, +/obj/item/coin/silver{ + pixel_x = 5; + pixel_y = -8 + }, +/obj/structure/closet/crate{ + name = "Silver Crate" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aEc" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Fore Port"; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aEd" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/storage/primary) +"aEe" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/starboard) +"aEh" = ( +/obj/structure/table/laminate, +/obj/machinery/reagentgrinder, +/obj/item/chems/drinks/shaker, +/obj/item/stack/package_wrap, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Bar Backroom" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aEi" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/primary/starboard) +"aEj" = ( +/obj/machinery/vending/tool, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aEk" = ( +/obj/machinery/door/airlock/glass/engineering{ + name = "Engineering Voidsuits" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/ai_monitored/storage/eva) +"aEl" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aEm" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aEn" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aEo" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/ai_monitored/storage/eva) +"aEp" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aEq" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aEr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aEs" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aEt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aEu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aEv" = ( +/obj/structure/table/laminate, +/obj/item/gun/projectile/shotgun/doublebarrel, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aEw" = ( +/obj/machinery/door/airlock{ + name = "Unisex Showers" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aEx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aEy" = ( +/obj/machinery/light/small, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aEz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aEA" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "heads_meeting"; + name = "Meeting Room Window Shutters" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/bridge/meeting_room) +"aEB" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aEC" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aED" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Fore Starboard Access"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aEE" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solar_tool_inner"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/auxsolarport) +"aEF" = ( +/obj/structure/table/laminate, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aEG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "heads_meeting"; + name = "Meeting Room Window Shutters" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/bridge/meeting_room) +"aEH" = ( +/obj/machinery/atmospherics/pipe/zpipe/down{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "32-4" + }, +/obj/machinery/light, +/obj/structure/lattice, +/obj/structure/disposalpipe/down{ + dir = 1 + }, +/turf/floor/plating, +/turf/open, +/area/exodus/engineering/sublevel_access) +"aEI" = ( +/obj/structure/shuttle/engine/propulsion/burst{ + dir = 4 + }, +/turf/space, +/area/shuttle/arrival/station) +"aEK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "heads_meeting"; + name = "Meeting Room Window Shutters" + }, +/obj/structure/cable/green, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/bridge/meeting_room) +"aEL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aEM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aEN" = ( +/obj/structure/closet/wardrobe/red, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aEO" = ( +/obj/structure/chair/office/dark, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aEP" = ( +/obj/item/secure_storage/safe{ + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aEQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aER" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aES" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aET" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 2; + name = "Bar"; + sort_type = "Bar" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aEU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aEV" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aEW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aEX" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarstarboard) +"aEY" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aEZ" = ( +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFa" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aFb" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/door/airlock/research{ + name = "Mech Bay" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/chargebay) +"aFc" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFd" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFe" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFf" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFg" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFh" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aFi" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aFj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aFk" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aFn" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aFq" = ( +/obj/machinery/door/airlock{ + name = "Toilet" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison/restroom) +"aFr" = ( +/obj/item/stool, +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aFs" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aFt" = ( +/obj/structure/closet/crate, +/obj/item/stack/material/ingot/mapped/gold, +/obj/item/belt/champion, +/obj/machinery/camera/network/command{ + c_tag = "Vault"; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aFu" = ( +/obj/machinery/button/access/interior{ + id_tag = "escape_dock_north_airlock"; + name = "interior access button"; + pixel_x = 26; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aFv" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/mob/living/simple_animal/passive/mouse/brown/Tom, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aFw" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aFx" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aFy" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aFz" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "Skynet_launch"; + name = "Mech Bay" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"aFB" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aFC" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/substation/civilian_west) +"aFD" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "merchant_shuttle_station_exterior"; + name = "Docking Port Airlock" + }, +/obj/machinery/shield_diffuser, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"aFE" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - Northeast" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aFG" = ( +/obj/structure/closet/secure_closet/bar, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aFH" = ( +/obj/machinery/network/requests_console{ + department = "Security"; + pixel_y = 32; + dir = 1 + }, +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aFI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/command{ + name = "E.V.A." + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/ai_monitored/storage/eva) +"aFJ" = ( +/obj/structure/table/reinforced, +/obj/item/stack/material/pane/mapped/glass{ + amount = 50 + }, +/obj/item/stack/material/pane/mapped/glass{ + amount = 50 + }, +/obj/item/stack/material/pane/mapped/glass{ + amount = 50 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aFK" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/tank/jetpack/carbondioxide, +/obj/item/tank/jetpack/carbondioxide, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aFL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"aFM" = ( +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aFN" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aFO" = ( +/obj/machinery/lapvend, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aFP" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aFQ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/structure/sign/warning/high_voltage{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aFR" = ( +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/power_sensor{ + id_tag = "Civilian East Subgrid"; + name = "Powernet Sensor - Civilian East Subgrid" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_east) +"aFS" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aFT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Dormitories South"; + dir = 4 + }, +/obj/effect/floor_decal/corner/grey{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aFU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aFV" = ( +/obj/machinery/door/airlock{ + name = "Unisex Restrooms" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep) +"aFW" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aFX" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aFZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/maintenance{ + name = "Bar Maintenance" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/bar/cabin) +"aGb" = ( +/obj/structure/shuttle/engine/heater{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/shuttle/arrival/station) +"aGc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/plating, +/area/exodus/research/robotics) +"aGd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aGe" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/item/folder/cyan, +/obj/machinery/door/window/eastright{ + base_state = "left"; + dir = 2; + icon_state = "left"; + name = "Robotics Desk" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/plating, +/area/exodus/research/robotics) +"aGf" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Arrival Checkpoint"; + dir = 1 + }, +/obj/effect/floor_decal/corner/red/three_quarters, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aGg" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/plating, +/area/exodus/research/lab) +"aGh" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/pen, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aGi" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/southright{ + name = "Research and Development Desk" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/plating, +/area/exodus/research/lab) +"aGj" = ( +/obj/structure/table/reinforced, +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aGk" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_dock_north_inner"; + name = "Escape Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/exit) +"aGm" = ( +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aGn" = ( +/obj/structure/sign/poster, +/turf/wall/prepainted, +/area/exodus/crew_quarters/toilet) +"aGo" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/hologram/holopad, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aGp" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aGq" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/closet/wardrobe/grey, +/obj/effect/floor_decal/corner/white/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aGr" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aGs" = ( +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aGt" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aGu" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 8 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aGv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aGw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aGx" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/machinery/computer/cryopod, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aGy" = ( +/obj/structure/grille, +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/exterior) +"aGz" = ( +/obj/structure/safe, +/obj/item/clothing/jumpsuit/yellow, +/obj/item/key, +/obj/item/sword/katana, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/nuke_storage) +"aGA" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aGB" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "centcom_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aGC" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aGD" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aGE" = ( +/obj/structure/disposaloutlet{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"aGF" = ( +/turf/wall/prepainted, +/area/exodus/chapel/office) +"aGG" = ( +/turf/wall/prepainted, +/area/exodus/chapel/main) +"aGH" = ( +/obj/machinery/cryopod{ + dir = 2 + }, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aGI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/closet/chefcloset, +/obj/item/eftpos{ + eftpos_name = "Kitchen EFTPOS scanner" + }, +/obj/item/glass_jar, +/obj/item/book/manual/chef_recipes, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aGJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/blast/shutters{ + dir = 4; + id_tag = "bar"; + name = "Bar Shutters" + }, +/turf/floor/plating, +/area/exodus/hallway/primary/central_two) +"aGL" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aGM" = ( +/obj/structure/table/laminate, +/obj/item/dice/d20, +/obj/item/dice, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aGO" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 8; + id_tag = "chemwindow"; + name = "Chemistry Window Shutters" + }, +/turf/floor/plating, +/area/exodus/hallway/primary/central_two) +"aGP" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Security Maintenance" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/checkpoint2) +"aGQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aGT" = ( +/obj/machinery/suit_cycler/medical/prepared, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aGU" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = -7 + }, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = -7 + }, +/obj/item/radio/off, +/obj/item/radio/off, +/obj/item/radio/off, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aGV" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aGW" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aGX" = ( +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"aGY" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aGZ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/fore) +"aHb" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/fore) +"aHc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/engineering{ + name = "Civilian East Substation" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/civilian_east) +"aHd" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/storage/primary) +"aHe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/button/access/interior{ + id_tag = "escape_dock_south_airlock"; + name = "interior access button"; + pixel_x = 26; + pixel_y = -26; + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aHf" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_east) +"aHg" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_east) +"aHh" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/dormitory) +"aHi" = ( +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_east) +"aHj" = ( +/obj/item/crowbar, +/obj/item/flash, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/dark, +/area/exodus/security/checkpoint2) +"aHk" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/grey/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aHl" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aHm" = ( +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aHn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aHo" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aHp" = ( +/obj/structure/hygiene/toilet{ + pixel_y = 8 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aHq" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aHr" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/recharge_station, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aHs" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"aHt" = ( +/obj/machinery/door/window/southleft{ + dir = 8; + name = "Bar Delivery" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/bar/cabin) +"aHu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_dock_south_inner"; + name = "Escape Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/exit) +"aHv" = ( +/obj/structure/closet/wardrobe/chaplain_black, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aHw" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Chapel Office" + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aHx" = ( +/obj/machinery/network/requests_console{ + department = "Chapel"; + pixel_y = 32; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/lino, +/area/exodus/chapel/office) +"aHy" = ( +/obj/structure/closet/coffin, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "chapel"; + name = "Privacy Shutters" + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aHz" = ( +/obj/machinery/button/blast_door{ + id_tag = "chapel"; + name = "Privacy Shutters"; + pixel_y = 25 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aHA" = ( +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aHB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/hatch{ + name = "Command Substation" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/command) +"aHC" = ( +/obj/structure/closet/coffin, +/obj/machinery/door/window/eastleft{ + name = "Coffin Storage" + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aHD" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/button/mass_driver{ + id_tag = "chapelgun"; + pixel_x = 24; + pixel_y = -24 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aHE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aHF" = ( +/obj/structure/sign/warning/docking_area, +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/entry/port) +"aHG" = ( +/obj/machinery/door/window{ + dir = 8; + name = "Mass Driver" + }, +/obj/machinery/mass_driver{ + dir = 4; + id_tag = "chapelgun" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/airlock_sensor{ + pixel_y = 25 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/chapel/main) +"aHH" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aHI" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aHJ" = ( +/obj/machinery/door/airlock/security{ + name = "Security Checkpoint" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/starboard) +"aHK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aHL" = ( +/obj/structure/disposalpipe/junction{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aHM" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aHN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"aHO" = ( +/obj/structure/disposalpipe/junction{ + dir = 4 + }, +/obj/effect/decal/cleanable/flour, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aHP" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 4; + name = "Kitchen"; + sort_type = "Kitchen" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aHQ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aHR" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor/northleft{ + name = "Security Checkpoint" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/starboard) +"aHS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aHT" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "bar"; + name = "Bar Shutters" + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aHU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/terminal, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aHV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aHW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aHX" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 4; + name = "Hydroponics"; + sort_type = "Hydroponics" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aHY" = ( +/obj/structure/table, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aHZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aIa" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aIb" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aIc" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aId" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aIe" = ( +/obj/structure/table/reinforced, +/obj/item/chems/rag, +/obj/structure/noticeboard{ + default_pixel_x = -30 + }, +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "bar"; + name = "Bar Shutters" + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aIf" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aIg" = ( +/turf/wall/prepainted, +/area/exodus/library) +"aIh" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"aIi" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/item/stool, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aIj" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aIk" = ( +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/obj/machinery/light, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aIl" = ( +/obj/structure/sign/warning/secure_area{ + pixel_x = 32; + dir = 8 + }, +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aIm" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aIn" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aIq" = ( +/obj/structure/table, +/obj/item/deck/cards, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aIr" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 4; + name = "Chapel"; + sort_type = "Chapel" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aIu" = ( +/obj/machinery/button/access/exterior{ + id_tag = "xeno_airlock_control"; + name = "Xenobiology Access Button"; + pixel_x = -24; + dir = 4 + }, +/obj/machinery/door/airlock/research{ + autoclose = 0; + id_tag = "xeno_airlock_exterior"; + locked = 1; + name = "Xenobiology External Airlock" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology) +"aIv" = ( +/obj/abstract/landmark{ + name = "Marauder Entry" + }, +/turf/space, +/area/space) +"aIw" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/shuttle/arrival/station) +"aIx" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "chapelgun"; + name = "Chapel Launcher Door" + }, +/obj/machinery/shield_diffuser, +/turf/floor/plating, +/area/exodus/chapel/main) +"aIy" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aIz" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Chapel Maintenance" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/main) +"aIA" = ( +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/starboard) +"aIB" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aIC" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/command{ + name = "E.V.A. Cycler Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/ai_monitored/storage/eva) +"aID" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aIE" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"aIF" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"aIG" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aIH" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aII" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aIJ" = ( +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aIK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/engineering{ + name = "Civilian West Substation" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/civilian_west) +"aIM" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/starboard) +"aIN" = ( +/obj/structure/table/laminate, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/recharger, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aIO" = ( +/obj/machinery/door/airlock/glass{ + name = "Garden" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"aIP" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"aIQ" = ( +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/security/meeting) +"aIR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/meter, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aIS" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/obj/machinery/door/airlock/double/glass/civilian, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"aIT" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/structure/mirror{ + pixel_x = -28 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aIU" = ( +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aIV" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 4 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aIW" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aIX" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aIY" = ( +/obj/machinery/door/airlock{ + name = "Unit 1" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aIZ" = ( +/obj/machinery/door/airlock{ + name = "Unit 2" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aJa" = ( +/obj/machinery/door/airlock{ + name = "Unit B" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aJb" = ( +/obj/machinery/navbeacon/Bar, +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/bar/cabin) +"aJd" = ( +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/navbeacon/Kitchen, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/kitchen) +"aJe" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/primary/central_one) +"aJf" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aJg" = ( +/obj/structure/crematorium, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aJh" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/turf/floor/lino, +/area/exodus/chapel/office) +"aJi" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/primary/central_two) +"aJj" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = -2; + pixel_y = 5 + }, +/obj/item/box/fancy/crayons, +/turf/floor/lino, +/area/exodus/chapel/office) +"aJk" = ( +/obj/structure/chair/office/dark, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aJl" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/central_two) +"aJm" = ( +/obj/abstract/landmark/start{ + name = "Chaplain" + }, +/obj/structure/chair, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/lino, +/area/exodus/chapel/office) +"aJn" = ( +/turf/floor/lino, +/area/exodus/chapel/office) +"aJo" = ( +/obj/structure/closet/coffin, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aJp" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aJq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aJr" = ( +/obj/structure/sign/painting/monkey_painting{ + pixel_x = -28; + pixel_y = 4 + }, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar/cabin) +"aJt" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aJu" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"aJv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aJw" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aJx" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"aJy" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aJz" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aJA" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJB" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aJC" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/dormitory) +"aJD" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Library Maintenance" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/library) +"aJE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJF" = ( +/obj/machinery/door/window/southleft{ + name = "Kitchen Delivery" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/kitchen) +"aJG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Civilian West" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aJH" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJI" = ( +/obj/structure/filing_cabinet, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aJJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aJK" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Lounge" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJL" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aJN" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aJO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/structure/sign/double/map/left{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJP" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/computer/arcade, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aJQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/sign/double/map/right{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aJR" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aJS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aJT" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aJU" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"aJV" = ( +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aJW" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aJX" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aJY" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aJZ" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/power_sensor{ + id_tag = "Civilian West Subgrid"; + name = "Powernet Sensor - Civilian West" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aKa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Civilian West Substation Bypass" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/civilian_west) +"aKb" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aKc" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aKd" = ( +/obj/machinery/navbeacon/ToolStorage, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aKe" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aKf" = ( +/obj/machinery/light/small, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aKg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aKh" = ( +/obj/machinery/portable_atmospherics/canister/air, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aKi" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"aKj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/vault/bolted, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/nuke_storage) +"aKk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aKm" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aKp" = ( +/obj/machinery/vending/fashionvend, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aKr" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aKs" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/item/briefcase/inflatable{ + pixel_x = 3; + pixel_y = 6 + }, +/obj/item/briefcase/inflatable{ + pixel_y = 3 + }, +/obj/item/briefcase/inflatable{ + pixel_x = -3 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aKt" = ( +/obj/structure/disposalpipe/trunk, +/obj/machinery/disposal, +/turf/floor/tiled/monotile, +/area/exodus/storage/primary) +"aKu" = ( +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aKv" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aKw" = ( +/obj/structure/lattice, +/turf/space, +/area/exodus/ai_monitored/storage/eva) +"aKx" = ( +/obj/machinery/camera/network/security{ + c_tag = "EVA South"; + dir = 1 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/ai_monitored/storage/eva) +"aKy" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aKz" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/sign/warning/airlock, +/obj/machinery/door/firedoor, +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/port) +"aKA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aKC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aKD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"aKE" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/sign/directions/evac{ + dir = 4; + pixel_y = 32; + pixel_z = -8 + }, +/obj/structure/sign/directions/security{ + dir = 1; + pixel_y = 32; + pixel_z = 8 + }, +/obj/structure/sign/directions/medical{ + dir = 4; + pixel_y = 32 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - North" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aKF" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aKG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/grey/three_quarters, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"aKH" = ( +/obj/machinery/vending/cola{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/central_two) +"aKI" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aKJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aKK" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aKL" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aKM" = ( +/obj/machinery/light, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/toilet) +"aKN" = ( +/obj/machinery/door/airlock{ + name = "Bar Backroom" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/bar/cabin) +"aKO" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aKP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/command{ + name = "Electrical Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/command) +"aKQ" = ( +/obj/machinery/camera/network/civilian_east{ + c_tag = "Bar North" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/item/flame/fuelled/lighter/zippo, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aKR" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/quartermaster/storage) +"aKS" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aKT" = ( +/obj/machinery/door/window/eastright{ + dir = 2; + name = "Hydroponics Delivery" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aKU" = ( +/obj/machinery/network/requests_console{ + department = "Bar"; + name = "Bar RC"; + pixel_y = 32; + dir = 1 + }, +/obj/machinery/vending/boozeomat, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aKV" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aKW" = ( +/obj/machinery/navbeacon/Hydroponics, +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aKX" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/button/crematorium{ + pixel_x = 25; + dir = 8 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aKY" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aKZ" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/kitchen) +"aLa" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp{ + pixel_y = 10 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aLb" = ( +/obj/structure/table/laminate, +/obj/item/nullrod, +/obj/item/eftpos{ + eftpos_name = "Chapel EFTPOS scanner" + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aLc" = ( +/obj/structure/table/laminate, +/obj/item/pen, +/obj/item/chems/drinks/bottle/holywater, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/lino, +/area/exodus/chapel/office) +"aLd" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/maintenance{ + name = "Kitchen Cold Room Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/kitchen) +"aLe" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Bar\\Library Maintenance" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/bar) +"aLf" = ( +/turf/wall/prepainted, +/area/exodus/hydroponics) +"aLg" = ( +/obj/structure/closet/coffin, +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "chapel"; + name = "Privacy Shutters" + }, +/obj/machinery/door/window/westleft{ + name = "Coffin Storage" + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aLh" = ( +/obj/structure/disposalpipe/segment, +/turf/wall/prepainted, +/area/exodus/hydroponics) +"aLi" = ( +/obj/structure/chair/office/dark, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Library North" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aLj" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aLk" = ( +/obj/structure/table, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aLl" = ( +/obj/structure/table/laminate, +/obj/item/folder/yellow, +/obj/item/pen, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aLm" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aLo" = ( +/obj/machinery/newscaster{ + pixel_x = 30; + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aLq" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aLr" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/research/robotics) +"aLs" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/sign/directions/evac{ + dir = 4; + pixel_y = 32; + pixel_z = -8 + }, +/obj/structure/sign/directions/medical{ + dir = 4; + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aLt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aLu" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aLv" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aLw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/engineering{ + name = "Civilian West Substation" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/civilian_west) +"aLx" = ( +/obj/structure/closet/secure_closet/scientist, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"aLy" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aLz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aLA" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aLB" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aLC" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Primary Tool Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aLD" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/yjunction, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"aLE" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "nuke_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aLF" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/quartermaster/storage) +"aLH" = ( +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/ai_monitored/storage/eva) +"aLI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/command{ + name = "E.V.A." + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"aLJ" = ( +/obj/machinery/suit_cycler/generic/prepared, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aLK" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/port) +"aLL" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"aLM" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aLN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Robotics"; + sort_type = "Robotics" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"aLP" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "nuke_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "nuke_shuttle_dock_airlock"; + name = "exterior access button"; + pixel_x = -5; + pixel_y = -26 + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aLQ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aLR" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_three) +"aLS" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/medical/chemistry) +"aLT" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/medical/medbay2) +"aLU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/chargebay) +"aLV" = ( +/obj/machinery/vending/snack{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/central_two) +"aLW" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_dock_north_outer"; + name = "Escape Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "escape_dock_north_airlock"; + name = "exterior access button"; + pixel_x = 4; + pixel_y = -26; + dir = 1 + }, +/obj/machinery/shield_diffuser, +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/exit) +"aLX" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/medical/medbay3) +"aLY" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aLZ" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/computer/guestpass{ + pixel_x = -28 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"aMa" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aMb" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/central_one) +"aMc" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aMd" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"aMe" = ( +/obj/abstract/landmark{ + name = "lightsout" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/research) +"aMf" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aMg" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aMh" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"aMi" = ( +/obj/machinery/door/airlock/command{ + name = "Captain's Quarters" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/captain) +"aMj" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/smartfridge/drinks, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aMk" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aMl" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/chair/comfy/brown{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aMm" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/medical/medbay) +"aMo" = ( +/obj/structure/window/reinforced, +/turf/floor/tiled/white, +/area/exodus/research) +"aMp" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/item/book/manual/barman_recipes, +/obj/item/clothing/head/that{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/screwdriver, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aMq" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aMr" = ( +/obj/structure/closet/secure_closet/freezer/meat, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aMs" = ( +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aMt" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aMu" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aMv" = ( +/obj/machinery/disposal/deliveryChute{ + dir = 1; + name = "disposal inlet" + }, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/structure/window/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aMw" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Chef" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aMx" = ( +/obj/machinery/door/airlock{ + name = "Brig Restroom" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/prison/restroom) +"aMy" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aMz" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aMA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"aMB" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aMC" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aMD" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aME" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Bar Maintenance" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/bar) +"aMF" = ( +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 21 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aMG" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aMH" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aMI" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Chapel Crematorium"; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aMJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aMK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock{ + name = "Crematorium" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/office) +"aML" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aMM" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/docking) +"aMN" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aMO" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/hologram/holopad, +/turf/floor/lino, +/area/exodus/chapel/office) +"aMP" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aMQ" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Chapel North"; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aMR" = ( +/obj/structure/table/laminate, +/obj/machinery/recharger, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aMS" = ( +/obj/structure/closet/crate, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"aMT" = ( +/obj/structure/table, +/obj/machinery/light/small, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aMU" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aMV" = ( +/turf/wall/titanium, +/area/shuttle/arrival/station) +"aMW" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "arrivals_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "arrivals_sensor"; + pixel_x = 25; + pixel_y = 12 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "arrivals_airlock"; + pixel_x = 25; + tag_airpump = "arrivals_pump"; + tag_chamber_sensor = "arrivals_sensor"; + tag_exterior_door = "arrivals_outer"; + tag_interior_door = "arrivals_inner" + }, +/obj/effect/floor_decal/industrial/warning/cee, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aMX" = ( +/obj/structure/chair/comfy/beige, +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aMY" = ( +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aMZ" = ( +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aNa" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green{ + pixel_x = 1; + pixel_y = 5 + }, +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aNb" = ( +/obj/machinery/vending/cigarette{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/secondary/entry/starboard) +"aNc" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/maintenance{ + name = "Hydroponics Maintenance" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hydroponics) +"aNd" = ( +/obj/structure/chair/comfy/brown{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aNe" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNf" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aNg" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aNh" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aNi" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNj" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aNk" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNl" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "centcom_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "centcom_shuttle_dock_airlock"; + name = "exterior access button"; + pixel_x = -5; + pixel_y = -26 + }, +/obj/machinery/shield_diffuser, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aNm" = ( +/obj/machinery/flasher{ + id_tag = "permflash"; + name = "Floor mounted flash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aNn" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNo" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNp" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"aNq" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNr" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNs" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Port - Central" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNt" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNu" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNv" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNw" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNx" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNy" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -13; + pixel_y = 28 + }, +/obj/machinery/atm{ + pixel_x = 6; + pixel_y = 28 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNz" = ( +/obj/machinery/navbeacon/Lockers, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNA" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aNB" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"aNC" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"aND" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNE" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNF" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNG" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - Northwest" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNH" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = 30 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNI" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNJ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNK" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNL" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNM" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_dock_south_outer"; + name = "Escape Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "escape_dock_south_airlock"; + name = "exterior access button"; + pixel_x = 4; + pixel_y = 26 + }, +/obj/machinery/shield_diffuser, +/obj/structure/sign/warning/docking_area{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/exit) +"aNN" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aNO" = ( +/obj/machinery/suit_cycler/engineering/prepared, +/turf/floor/tiled/dark, +/area/exodus/ai_monitored/storage/eva) +"aNP" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/machinery/cryopod{ + dir = 2 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"aNQ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aNR" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aNS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aNT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aNU" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Captain's Office Maintenance" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/captain) +"aNV" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aNW" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aNX" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aNY" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aNZ" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aOa" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aOb" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = 30 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aOc" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aOd" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "specops_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "specops_dock_airlock"; + name = "exterior access button"; + pixel_x = -5; + pixel_y = -26 + }, +/obj/machinery/shield_diffuser, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aOe" = ( +/obj/structure/table/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/chemical_dispenser/bar_soft/full, +/obj/machinery/button/blast_door{ + id_tag = "bar"; + name = "Bar Shutters"; + pixel_y = 25 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aOf" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aOg" = ( +/obj/structure/table/laminate, +/obj/item/food/junk/chips, +/obj/random/single{ + name = "randomly spawned cola"; + spawn_object = /obj/item/chems/drinks/cans/cola + }, +/turf/floor/carpet, +/area/exodus/hallway/secondary/entry/starboard) +"aOh" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aOi" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"aOj" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aOk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/machinery/chemical_dispenser/bar_alc/full, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aOl" = ( +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aOm" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aOn" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/meat_hook, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aOo" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aOp" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/item/chems/condiment/small/peppermill{ + pixel_x = 3 + }, +/obj/item/chems/condiment/small/saltshaker{ + pixel_x = -3 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aOq" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aOr" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -27; + pixel_y = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Hydroponics Pasture West"; + dir = 4 + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOt" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOv" = ( +/obj/machinery/door/airlock/glass{ + name = "Hydroponics Pasture" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOw" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aOx" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOy" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOA" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aOC" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aOD" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aOE" = ( +/obj/structure/morgue, +/turf/floor/tiled/dark, +/area/exodus/chapel/office) +"aOF" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aOG" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aOH" = ( +/obj/machinery/newscaster{ + pixel_y = -28; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aOI" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/lino, +/area/exodus/chapel/office) +"aOJ" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/chair, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aOK" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aOL" = ( +/obj/structure/table/laminate, +/obj/structure/disposalpipe/segment, +/obj/item/deck/cards, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aOM" = ( +/obj/structure/table/laminate, +/obj/item/ashtray/plastic{ + pixel_x = -1; + pixel_y = 1 + }, +/obj/machinery/recharger, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aOP" = ( +/obj/machinery/vending/coffee{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/secondary/entry/starboard) +"aOQ" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_one) +"aOR" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/plaque, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aOS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aOT" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"aOU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aOV" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aOW" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aOX" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aOY" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aOZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/security/prison/dorm) +"aPa" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/research/docking) +"aPb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/turret_protected/ai_upload) +"aPc" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/orange, +/obj/machinery/camera/network/prison{ + c_tag = "Security - Brig Bedroom" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aPd" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPe" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPf" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPg" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPh" = ( +/turf/floor/carpet, +/area/exodus/hallway/secondary/entry/starboard) +"aPi" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPj" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPk" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPl" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPm" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPn" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPo" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPp" = ( +/obj/machinery/door/airlock/glass{ + name = "Locker Room" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aPq" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aPs" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/starboard) +"aPt" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPu" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPv" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPw" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPx" = ( +/obj/structure/tank_rack/oxygen, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/ai_monitored/storage/eva) +"aPy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPz" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPA" = ( +/obj/machinery/navbeacon/EVA, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPB" = ( +/obj/machinery/navbeacon/EVA2, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPD" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aPE" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aPF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aPG" = ( +/obj/machinery/navbeacon/Dorm, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aPH" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aPI" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aPJ" = ( +/obj/abstract/landmark/start{ + name = "Bartender" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/mob/living/human/monkey/punpun, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aPK" = ( +/obj/machinery/door/window{ + autoset_access = 0; + dir = 4; + name = "Bar"; + req_access = list("ACCESS_BAR") + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/lino, +/area/exodus/crew_quarters/bar) +"aPL" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"aPM" = ( +/obj/structure/meat_hook, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aPN" = ( +/obj/machinery/gibber, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aPO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aPP" = ( +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aPQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"aPR" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPS" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPT" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/hologram/holopad, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPU" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPV" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/medical/sleeper) +"aPW" = ( +/obj/machinery/seed_storage/garden, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPX" = ( +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aPZ" = ( +/obj/machinery/door/airlock/glass{ + name = "Chapel Office" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/office) +"aQa" = ( +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/obj/item/flame/fuelled/lighter/zippo, +/obj/item/box/fancy/cigarettes, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aQb" = ( +/obj/machinery/door/morgue{ + name = "Confession Booth (Chaplain)" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/main) +"aQc" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "exodus_rescue_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aQd" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "exodus_rescue_shuttle_dock_outer"; + name = "Docking Port Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "exodus_rescue_shuttle_dock_airlock"; + name = "exterior access button"; + pixel_x = -26; + pixel_y = -5 + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aQe" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aQf" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aQg" = ( +/obj/machinery/door/blast/regular{ + id_tag = "trash"; + name = "disposal mass driver" + }, +/obj/machinery/shield_diffuser, +/turf/floor/plating/airless, +/area/exodus/maintenance/disposal) +"aQh" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/exterior) +"aQi" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aQj" = ( +/obj/structure/table/laminate, +/obj/item/box/fancy/cigarettes{ + pixel_y = 2 + }, +/obj/random/single{ + name = "randomly spawned lighter"; + spawn_object = /obj/item/flame/fuelled/lighter + }, +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aQk" = ( +/obj/machinery/vending/cola{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/secondary/entry/starboard) +"aQl" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aQm" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aQn" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/orange, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aQo" = ( +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aQp" = ( +/obj/machinery/door/blast/regular/open{ + dir = 8; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"aQq" = ( +/obj/structure/closet/emcloset, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/port) +"aQr" = ( +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/obj/random/tech_supply, +/obj/item/clothing/head/flatcap, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aQs" = ( +/obj/structure/hygiene/toilet{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"aQt" = ( +/obj/structure/hygiene/shower{ + dir = 4; + pixel_x = 5 + }, +/obj/structure/curtain/open/shower/security, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"aQw" = ( +/obj/machinery/photocopier, +/obj/structure/table/laminate, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aQx" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/structure/mirror{ + pixel_x = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"aQy" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"aQz" = ( +/obj/structure/table, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/camera/network/prison{ + c_tag = "Security - Common Brig Southwest"; + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aQA" = ( +/obj/item/stool, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aQB" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hor) +"aQC" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_bay_door"; + name = "Cargo Docking Hatch" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"aQD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison) +"aQE" = ( +/obj/machinery/door/airlock/glass{ + name = "Brig Dormitories" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aQF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aQG" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aQH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"aQI" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aQJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters{ + dir = 8; + id_tag = "office_shutter"; + name = "Office Shutters" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/starboard) +"aQK" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aQL" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aQM" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aQN" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"aQO" = ( +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/quartermaster/qm) +"aQP" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aQQ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aQS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aQT" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/door/window/westright{ + name = "Library Desk Door" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aQU" = ( +/obj/effect/floor_decal/corner/purple/full, +/obj/structure/sign/warning/secure_area{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"aQV" = ( +/obj/item/chems/glass/bucket, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aQW" = ( +/obj/machinery/door/airlock/freezer{ + name = "Kitchen cold room" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/kitchen) +"aQX" = ( +/obj/item/tool/axe/hatchet, +/obj/item/tool/hoe/mini, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aQY" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/medical/genetics) +"aQZ" = ( +/obj/machinery/seed_extractor, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRa" = ( +/obj/machinery/biogenerator, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRb" = ( +/obj/machinery/seed_storage/garden, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRc" = ( +/obj/machinery/vending/hydronutrients, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRd" = ( +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRe" = ( +/obj/machinery/vending/hydronutrients, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRf" = ( +/obj/structure/table, +/obj/item/tool/hoe/mini, +/obj/item/tool/axe/hatchet, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRg" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/item/chems/glass/bucket, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRh" = ( +/obj/structure/closet/secure_closet/hydroponics, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRi" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"aRj" = ( +/obj/structure/closet/secure_closet/hydroponics, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRk" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Hydroponics Pasture East"; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics) +"aRl" = ( +/obj/structure/bookcase{ + name = "Forbidden Knowledge" + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/library) +"aRm" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen/invisible, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/library) +"aRn" = ( +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/machinery/button/windowtint{ + pixel_x = -25; + dir = 4 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the research doors."; + id_tag = "researchdoor"; + name = "Research door control"; + pixel_x = -27; + pixel_y = 13 + }, +/obj/machinery/button/blast_door{ + id_tag = "Biohazard"; + name = "Biohazard Shutter Control"; + pixel_x = -38; + pixel_y = 2 + }, +/obj/abstract/landmark/start{ + name = "Research Director" + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/button/blast_door{ + id_tag = "researchlockdown"; + name = "Research Division Emergency Lockdown Control"; + pixel_x = -38; + pixel_y = 13 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"aRo" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aRp" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters{ + id_tag = "office_shutter"; + name = "Office Shutters" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/starboard) +"aRq" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aRr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aRs" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/breath, +/obj/item/clothing/mask/breath, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/box/lights/mixed, +/obj/item/chems/spray/extinguisher, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aRt" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "acute1"; + name = "EMT Storage Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/sleeper) +"aRu" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aRv" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aRw" = ( +/obj/machinery/vending/cigarette{ + dir = 8 + }, +/obj/structure/window/reinforced, +/turf/floor/carpet, +/area/exodus/crew_quarters/bar) +"aRx" = ( +/obj/structure/table/laminate, +/obj/random/single{ + name = "randomly spawned deck of cards"; + spawn_object = /obj/item/deck/cards + }, +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aRy" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aRz" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aRA" = ( +/obj/structure/grille, +/obj/structure/window/reinforced/tinted{ + dir = 1 + }, +/obj/structure/window/reinforced/tinted, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/chapel/main) +"aRB" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_bay_door"; + name = "Cargo Docking Hatch" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"aRC" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "research_dock_outer"; + name = "Shuttle Airlock" + }, +/obj/machinery/shield_diffuser, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"aRD" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aRE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"aRF" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_bay_door"; + name = "Cargo Docking Hatch" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"aRH" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "arrivals_inner"; + name = "Engineering External Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/arrivals) +"aRI" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aRJ" = ( +/obj/structure/chair/comfy/beige{ + dir = 1 + }, +/turf/floor/lino, +/area/exodus/hallway/secondary/entry/starboard) +"aRK" = ( +/obj/structure/bookcase{ + name = "bookcase (Religious)" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aRL" = ( +/turf/floor/carpet, +/area/exodus/library) +"aRM" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/carpet, +/area/exodus/library) +"aRO" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"aRP" = ( +/obj/machinery/vending/snack{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/secondary/entry/starboard) +"aRQ" = ( +/obj/structure/cable/green, +/obj/machinery/apc/high{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aRR" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/glass{ + name = "Locker Room" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aRS" = ( +/obj/machinery/door/airlock/glass{ + name = "Art Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aRT" = ( +/obj/structure/table, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Port - East"; + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/port) +"aRU" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/maintenance/dormitory) +"aRV" = ( +/obj/structure/table, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/port) +"aRW" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/port) +"aRX" = ( +/obj/structure/sign/directions/security{ + dir = 4; + pixel_z = 4 + }, +/obj/structure/sign/directions/medical{ + dir = 4; + pixel_z = -4 + }, +/turf/wall/prepainted, +/area/exodus/hallway/primary/port) +"aRY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aRZ" = ( +/turf/wall/prepainted, +/area/exodus/hallway/secondary/exit) +"aSa" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay3) +"aSb" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aSc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay) +"aSd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay2) +"aSe" = ( +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aSf" = ( +/obj/machinery/camera/network/civilian_east{ + c_tag = "Bar East" + }, +/obj/structure/table/laminate, +/obj/item/paper_bin, +/obj/item/pen/blue{ + pixel_x = -3; + pixel_y = 2 + }, +/obj/item/pen/blue{ + pixel_x = -3; + pixel_y = 2 + }, +/obj/structure/noticeboard{ + default_pixel_y = 27 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aSg" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aSh" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/glass{ + name = "Hydroponics Pasture" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aSi" = ( +/obj/machinery/door/airlock/glass{ + name = "Garden Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hydroponics/garden) +"aSj" = ( +/obj/machinery/light/small, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/library) +"aSk" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 8; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay) +"aSl" = ( +/obj/machinery/light/small, +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aSm" = ( +/obj/structure/cult/tome, +/obj/item/clothing/pants/slacks/red/outfit, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/library) +"aSn" = ( +/obj/effect/floor_decal/chapel{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aSo" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aSp" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay2) +"aSq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 0; + id_tag = "staffroom"; + name = "Staff Room Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/cryo) +"aSr" = ( +/obj/structure/disposaloutlet{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/disposal) +"aSs" = ( +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aSt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/chapel{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aSu" = ( +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 21 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/dark, +/area/exodus/hydroponics) +"aSv" = ( +/obj/machinery/door/morgue{ + name = "Confession Booth" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/main) +"aSw" = ( +/obj/machinery/vending/cola, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aSx" = ( +/obj/machinery/lapvend, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aSy" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aSz" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aSA" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 8; + id_tag = "staffroom"; + name = "Staff Room Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay2) +"aSB" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"aSC" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"aSD" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"aSE" = ( +/obj/machinery/button/access/interior{ + id_tag = "solar_tool_airlock"; + name = "interior access button"; + pixel_x = 25; + pixel_y = 25 + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/auxsolarport) +"aSF" = ( +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aSG" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"aSH" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aSI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aSJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/research/mixing) +"aSK" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"aSL" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/storage/tech) +"aSM" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/storage/tech) +"aSN" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"aSO" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aSP" = ( +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aSQ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aSR" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aSS" = ( +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aST" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aSU" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aSV" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aSW" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aSX" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/storage/tech) +"aSY" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aSZ" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/hallway/primary/port) +"aTb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/research/mixing) +"aTc" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/storage/tech) +"aTd" = ( +/obj/machinery/door/window/eastright{ + base_state = "left"; + dir = 8; + icon_state = "left"; + name = "Research Division Delivery" + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research) +"aTe" = ( +/turf/wall/prepainted, +/area/exodus/hydroponics/garden) +"aTf" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"aTg" = ( +/obj/machinery/embedded_controller/radio/docking_port_multi{ + child_names_txt = "Airlock One;Airlock Two"; + child_tags_txt = "escape_dock_north_airlock;escape_dock_south_airlock"; + dir = 1; + id_tag = "escape_dock"; + pixel_y = -25 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aTh" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aTi" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aTj" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "specops_dock_inner"; + name = "Docking Port Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"aTk" = ( +/obj/structure/chair/wood/walnut{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aTl" = ( +/obj/machinery/conveyor{ + dir = 10; + id_tag = "garbage" + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aTm" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aTn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aTo" = ( +/turf/floor/carpet, +/area/exodus/chapel/main) +"aTp" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aTq" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aTr" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aTs" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/item/rollingpin, +/obj/item/knife, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aTt" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aTu" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aTv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aTw" = ( +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/space, +/area/space) +"aTx" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/storage/tech) +"aTy" = ( +/obj/machinery/atm{ + pixel_x = 24; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aTz" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aTA" = ( +/obj/structure/closet/wardrobe/xenos, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aTB" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/cooker/fryer, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aTC" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/cooker/grill, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aTD" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"aTE" = ( +/obj/machinery/vending/cola, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aTF" = ( +/obj/machinery/vending/coffee, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aTG" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"aTH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/medical/medbay4) +"aTI" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "cmooffice"; + name = "CMO Office Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay4) +"aTJ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aTK" = ( +/obj/machinery/vending/cigarette, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aTL" = ( +/obj/machinery/vending/snack, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aTM" = ( +/obj/structure/closet/secure_closet/personal, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aTN" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aTO" = ( +/obj/structure/table, +/obj/item/stack/cable_coil/random, +/obj/item/stack/cable_coil/random, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/storage/art) +"aTP" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/art) +"aTQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aTR" = ( +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aTS" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/locker) +"aTT" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/art) +"aTU" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Auxiliary Tool Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"aTV" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aTW" = ( +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/library) +"aTX" = ( +/obj/item/stool/bar/padded, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aTY" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "misclab"; + name = "misclab" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/plating, +/area/exodus/research/misc_lab) +"aTZ" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "misclab"; + name = "misclab" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/research/misc_lab) +"aUa" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/port) +"aUb" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aUc" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/storage/tech) +"aUd" = ( +/obj/machinery/cryopod, +/turf/floor/tiled/white/monotile, +/area/exodus/security/prison/dorm) +"aUe" = ( +/turf/wall/prepainted, +/area/exodus/storage/art) +"aUf" = ( +/obj/item/stool/bar/padded, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUg" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "scanhideside"; + name = "Diagnostics Room Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/medbay4) +"aUh" = ( +/obj/machinery/computer/modular/preset/civilian, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aUi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aUk" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/cyan, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/turret_protected/ai_upload) +"aUl" = ( +/obj/effect/floor_decal/corner/red/three_quarters{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/security, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aUm" = ( +/turf/wall/prepainted, +/area/exodus/storage/tools) +"aUn" = ( +/obj/machinery/disposal, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/laminate, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUp" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/bridge) +"aUq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUr" = ( +/obj/structure/closet/wardrobe/mixed, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aUs" = ( +/obj/machinery/vending/dinnerware, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Kitchen" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUt" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUu" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/stool/bar/padded, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUw" = ( +/obj/structure/closet/secure_closet/freezer/kitchen, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUx" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUy" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/machinery/reagent_temperature, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUz" = ( +/obj/structure/table/marble, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"aUA" = ( +/obj/machinery/vending/bombresearch{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"aUB" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Firefighting equipment" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/library) +"aUC" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters{ + dir = 8; + id_tag = "office_shutter"; + name = "Office Shutters" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"aUD" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUE" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUG" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUH" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUI" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUJ" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/item/chems/condiment/enzyme, +/obj/item/chems/glass/beaker{ + pixel_x = 5 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUK" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aUL" = ( +/obj/effect/wallframe_spawn/reinforced/polarized{ + id = "isoA_window_tint" + }, +/turf/floor/plating, +/area/exodus/medical/patient_a) +"aUM" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/portables_connector, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"aUN" = ( +/obj/abstract/landmark/start{ + name = "Gardener" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aUO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 1 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aUP" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aUQ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/chapel{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aUR" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Chapel South"; + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aUS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/chapel, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aUT" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aUU" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = -25; + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aUV" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aUW" = ( +/obj/structure/table/marble, +/obj/machinery/reagentgrinder, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aUX" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/light, +/obj/random/tech_supply, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aUY" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aUZ" = ( +/obj/structure/flora/bush/brflowers, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aVa" = ( +/obj/structure/flora/bush/ppflowers, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aVb" = ( +/obj/structure/flora/bush/brflowers, +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 28 + }, +/obj/item/chems/glass/bucket, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aVc" = ( +/obj/structure/bookcase{ + name = "bookcase (Fiction)" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aVd" = ( +/obj/structure/bookcase/skill_books/random, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aVf" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "nuke_shuttle_dock_airlock"; + pixel_y = 30; + tag_airpump = "nuke_shuttle_dock_pump"; + tag_chamber_sensor = "nuke_shuttle_dock_sensor"; + tag_exterior_door = "nuke_shuttle_dock_outer"; + tag_interior_door = "nuke_shuttle_dock_inner" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/port) +"aVg" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "nuke_shuttle_dock_pump" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/port) +"aVh" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"aVi" = ( +/obj/structure/table/laminate, +/turf/floor/carpet, +/area/exodus/chapel/main) +"aVj" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aVk" = ( +/obj/structure/flora/bush/sunnybush, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aVl" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aVm" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aVn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aVo" = ( +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aVp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"aVq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/research) +"aVr" = ( +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aVs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aVt" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aVu" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aVv" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/storage/tech) +"aVw" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Hallway"; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"aVx" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aVy" = ( +/obj/abstract/landmark{ + name = "lightsout" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aVz" = ( +/obj/structure/table, +/obj/item/stack/cable_coil/random, +/obj/item/stack/cable_coil/random, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/storage/art) +"aVA" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aVB" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/art) +"aVC" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/art) +"aVD" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aVE" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Tool Storage - Auxiliary" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aVF" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aVG" = ( +/turf/wall/prepainted, +/area/exodus/storage/emergency2) +"aVH" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/structure/closet/hydrant{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aVI" = ( +/obj/machinery/door/airlock{ + name = "Port Emergency Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"aVJ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"aVK" = ( +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aVL" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aVM" = ( +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aVN" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aVO" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aVP" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aVQ" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/chief) +"aVR" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aVS" = ( +/obj/structure/chair/wood/walnut, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aVT" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"aVU" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aVV" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aVW" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/chair/wood/walnut, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aVX" = ( +/obj/structure/chair/wood/walnut, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aVY" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aVZ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Kitchen" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/kitchen) +"aWa" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/chair/wood/walnut, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aWb" = ( +/obj/machinery/chem_master/condimaster{ + name = "CondiMaster Neo" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aWc" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/chief) +"aWd" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/stool/bar/padded, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aWe" = ( +/obj/item/chems/condiment/small/peppermill{ + pixel_x = 2; + pixel_y = 6 + }, +/obj/structure/table/laminate, +/obj/item/chems/condiment/small/saltshaker{ + pixel_x = -2; + pixel_y = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aWf" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aWg" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aWh" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/table/laminate, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aWi" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aWj" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Kitchen" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hydroponics/garden) +"aWk" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aWl" = ( +/obj/structure/chair/comfy/black, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aWm" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aWn" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/table/marble, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"aWo" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"aWp" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aWq" = ( +/obj/abstract/landmark/start{ + name = "Gardener" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aWr" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aWs" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aWt" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aWv" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aWx" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aWy" = ( +/obj/machinery/camera/network/civilian_east{ + c_tag = "Library Central"; + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aWz" = ( +/obj/abstract/landmark/start{ + name = "Librarian" + }, +/obj/structure/chair/office/dark, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aWA" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aWB" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/destructive_analyzer, +/obj/item/stock_parts/circuitboard/protolathe, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/item/stock_parts/circuitboard/autolathe{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/item/stock_parts/circuitboard/recycler, +/turf/floor/plating, +/area/exodus/storage/tech) +"aWC" = ( +/obj/structure/flora/bush, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aWD" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aWE" = ( +/obj/structure/flora/bush/sparsegrass, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aWF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aWG" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aWH" = ( +/obj/structure/table/laminate, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aWI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Vacant Office" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/vacantoffice) +"aWJ" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/closet/wardrobe/white, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aWK" = ( +/obj/item/stool, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aWL" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/abstract/landmark/start{ + name = "Chef" + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aWM" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aWN" = ( +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aWO" = ( +/obj/item/stool/padded, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aWP" = ( +/obj/effect/wallframe_spawn/reinforced/polarized{ + id = "isoB_window_tint" + }, +/turf/floor/plating, +/area/exodus/medical/patient_b) +"aWQ" = ( +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aWR" = ( +/obj/structure/closet/secure_closet/personal, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Locker Room East"; + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aWS" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/turf/floor/tiled/monotile, +/area/exodus/storage/art) +"aWT" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/engineering/break_room) +"aWU" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/medical/psych) +"aWV" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/chief) +"aWW" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"aWX" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"aWY" = ( +/obj/structure/table, +/obj/item/camera_film, +/obj/item/camera, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/storage/art) +"aWZ" = ( +/obj/structure/table, +/obj/item/box/fancy/crayons, +/obj/item/box/fancy/crayons, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/light/small, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Art Supply Storage"; + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/storage/art) +"aXa" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"aXb" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/heads/chief) +"aXc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/obj/structure/cable/cyan, +/turf/floor/plating, +/area/exodus/turret_protected/ai_upload) +"aXd" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aXe" = ( +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aXf" = ( +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 21 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aXg" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aXh" = ( +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aXi" = ( +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/machinery/cell_charger, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aXj" = ( +/obj/machinery/door/morgue{ + name = "Private Study" + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/techfloor/grid, +/area/exodus/library) +"aXk" = ( +/obj/machinery/camera/network/command{ + c_tag = "Bridge West" + }, +/obj/effect/floor_decal/corner/brown{ + dir = 5 + }, +/obj/structure/table/reinforced, +/obj/abstract/landmark/paperwork_spawn_exodus, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXl" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXm" = ( +/obj/item/radio/beacon, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXn" = ( +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aXo" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"aXp" = ( +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aXq" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"aXr" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/storage/emergency2) +"aXs" = ( +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aXt" = ( +/obj/structure/noticeboard{ + default_pixel_y = 27 + }, +/obj/machinery/camera/network/command{ + c_tag = "Bridge East" + }, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/structure/table/reinforced, +/obj/abstract/landmark/paperwork_spawn_exodus, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXu" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/brown/three_quarters{ + dir = 8 + }, +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXv" = ( +/obj/machinery/computer/modular/preset/medical, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXw" = ( +/obj/effect/wallframe_spawn/reinforced/polarized{ + id = "isoC_window_tint" + }, +/turf/floor/plating, +/area/exodus/medical/patient_c) +"aXx" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"aXy" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/door/airlock/research{ + name = "Toxins Launch Room Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/mixing) +"aXz" = ( +/obj/structure/table/laminate, +/obj/item/utensil/fork, +/obj/item/utensil/fork, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aXA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aXB" = ( +/obj/structure/table/laminate, +/obj/item/board, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aXD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/table/laminate, +/obj/item/box/checkers/chess/red, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aXE" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aXF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/laminate, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aXG" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/camera/network/command{ + c_tag = "Bridge Conference Room" + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"aXH" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/cooker/oven, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aXI" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"aXJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aXK" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/substation/medical) +"aXL" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/machinery/door/airlock/research{ + name = "Toxins Launch Room" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/mixing) +"aXM" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/drill_brace, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"aXN" = ( +/obj/abstract/landmark/start{ + name = "Gardener" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"aXO" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXP" = ( +/obj/structure/table/gamblingtable, +/obj/item/box/checkers, +/turf/floor/laminate, +/area/exodus/maintenance/dormitory) +"aXQ" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aXS" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/table/marble, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aXT" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aXU" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/chief) +"aXV" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aXW" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aXX" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aXY" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aXZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/chapel/main) +"aYa" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aYb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aYc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/cyan, +/turf/floor/plating, +/area/exodus/turret_protected/ai_upload) +"aYe" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "chemcounter"; + name = "Pharmacy Counter Shutters" + }, +/obj/structure/table/reinforced, +/obj/machinery/door/window/westright{ + name = "Chemistry Desk" + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"aYf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aYg" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/item/stock_parts/circuitboard/shield_generator, +/obj/item/stock_parts/circuitboard/shield_diffuser, +/obj/item/stock_parts/circuitboard/shield_diffuser, +/obj/item/stock_parts/circuitboard/shield_generator, +/turf/floor/plating, +/area/exodus/storage/tech) +"aYh" = ( +/obj/structure/flora/bush/brflowers, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aYi" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "nuke_shuttle_dock_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "nuke_shuttle_dock_sensor"; + pixel_y = -25; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/port) +"aYj" = ( +/obj/structure/bookcase{ + name = "bookcase (Adult)" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aYk" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/port) +"aYl" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green{ + pixel_x = 1; + pixel_y = 5 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aYm" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "nuke_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aYn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"aYo" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"aYp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"aYq" = ( +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aYr" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_eva) +"aYs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aYt" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aYu" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/papershredder, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aYv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"aYw" = ( +/obj/structure/window/basic{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aYx" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/hand_labeler, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"aYy" = ( +/obj/machinery/atm{ + pixel_x = -25; + dir = 4 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Bar West"; + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aYz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/button/blast_door{ + id_tag = "office_shutter"; + name = "Office Shutters"; + pixel_x = -8; + pixel_y = 22 + }, +/obj/machinery/light_switch{ + pixel_x = -8; + pixel_y = 32 + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"aYA" = ( +/obj/item/clothing/head/soft/grey{ + pixel_x = -2; + pixel_y = 3 + }, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aYB" = ( +/obj/machinery/door/airlock/research{ + autoclose = 0; + id_tag = "xeno_airlock_interior"; + locked = 1; + name = "Xenobiology Internal Airlock" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology) +"aYC" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aYD" = ( +/obj/structure/closet/wardrobe/grey, +/obj/machinery/network/requests_console{ + department = "Locker Room"; + pixel_x = -32; + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"aYE" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/item/stack/tape_roll/duct_tape, +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aYF" = ( +/obj/structure/table/laminate, +/obj/item/box/checkers, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aYG" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"aYH" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aYI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"aYJ" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/glass{ + name = "Arrivals" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/port) +"aYL" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology/xenoflora_storage) +"aYM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYO" = ( +/turf/wall/prepainted, +/area/exodus/security/vacantoffice) +"aYP" = ( +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"aYQ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aYR" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"aYS" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYT" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aYU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYV" = ( +/obj/machinery/light, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/newscaster{ + pixel_y = -28; + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYW" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"aYY" = ( +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Bridge"; + name = "Bridge RC"; + pixel_y = -32 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aYZ" = ( +/obj/machinery/light, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZa" = ( +/obj/machinery/button/blast_door{ + id_tag = "bridge blast"; + name = "Bridge Blast Door Control"; + pixel_x = 6; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_x = -5; + pixel_y = -23 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"aZc" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aZd" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/fireaxecabinet{ + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZg" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZh" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"aZi" = ( +/obj/structure/sign/warning/secure_area{ + pixel_x = 32; + dir = 8 + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"aZj" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Bridge East Entrance" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aZk" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"aZl" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table/marble, +/obj/machinery/microwave{ + pixel_x = -3; + pixel_y = 6 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aZm" = ( +/obj/structure/table/laminate, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aZn" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/three_quarters, +/obj/machinery/vending/wallmed1{ + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"aZo" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table/marble, +/obj/machinery/cooker/cereal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"aZp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/laminate, +/obj/structure/disposalpipe/segment, +/obj/item/camera, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aZq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology/xenoflora) +"aZr" = ( +/obj/structure/chair/wood/walnut{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aZs" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aZt" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aZu" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aZv" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"aZw" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "mixvent"; + name = "Mixer Room Vent" + }, +/obj/machinery/shield_diffuser, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"aZx" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light/small/red{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"aZy" = ( +/obj/structure/flora/bush/brflowers, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"aZz" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/starboard) +"aZA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/chair/wood/walnut{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aZB" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/carpet, +/area/exodus/library) +"aZC" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/carpet, +/area/exodus/library) +"aZD" = ( +/obj/structure/table/laminate, +/obj/item/paper, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aZE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/chair/wood/walnut{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aZF" = ( +/obj/structure/table/laminate, +/obj/item/camera_film, +/obj/item/camera_film, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aZG" = ( +/obj/structure/table/laminate, +/obj/item/pen/red{ + pixel_x = 2; + pixel_y = 6 + }, +/obj/item/pen/blue{ + pixel_x = 5; + pixel_y = 5 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aZH" = ( +/obj/structure/table/laminate, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aZI" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"aZK" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/chair/wood/walnut{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"aZL" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aZM" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "kitchen"; + name = "Kitchen Shutters" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/hallway/primary/starboard) +"aZN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"aZO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"aZP" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/research/xenobiology/xenoflora) +"aZQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"aZR" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/construction) +"aZS" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "surgeryobs"; + name = "Operating Theatre Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/surgeryobs) +"aZT" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"aZU" = ( +/turf/wall/prepainted, +/area/exodus/engineering/engine_eva) +"aZV" = ( +/obj/structure/chair/office/light{ + dir = 8 + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aZW" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aZX" = ( +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"aZY" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"aZZ" = ( +/obj/structure/window/basic{ + dir = 4 + }, +/obj/item/folder/blue{ + pixel_x = 5 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"baa" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/table, +/obj/item/stamp, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/item/pen, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bab" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bac" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bad" = ( +/obj/structure/closet/wardrobe/black, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"bae" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Locker Room West"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"baf" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bag" = ( +/obj/structure/rack{ + dir = 4 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bah" = ( +/obj/machinery/door/window/eastright{ + base_state = "left"; + dir = 1; + icon_state = "left"; + name = "Shower" + }, +/obj/structure/hygiene/shower{ + dir = 4; + pixel_x = 5; + pixel_y = -5 + }, +/obj/random/soap, +/obj/item/bikehorn/rubberducky, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/captain) +"bai" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"baj" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/locker) +"bak" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bal" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bam" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"ban" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 1; + name = "Locker Room"; + sort_type = "Locker Room" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bao" = ( +/obj/structure/closet/secure_closet/personal, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"bap" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"baq" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"bar" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"bas" = ( +/obj/structure/closet/toolcloset, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"bau" = ( +/obj/machinery/button/blast_door{ + id_tag = "Disposal Exit"; + name = "Disposal Vent Control"; + pixel_x = -25; + pixel_y = 4 + }, +/obj/machinery/button/mass_driver{ + id_tag = "trash"; + pixel_x = -26; + pixel_y = -6 + }, +/obj/item/stool/padded, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bav" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"baw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bax" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bay" = ( +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Medical Substation Bypass" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"baA" = ( +/obj/random/obstruction, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"baB" = ( +/obj/structure/closet/toolcloset, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/tools) +"baC" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"baD" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"baE" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"baF" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"baG" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"baH" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"baI" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/engineering/locker_room) +"baJ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/light_switch{ + pixel_x = -25; + pixel_y = -25 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baK" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"baL" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baM" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/structure/table/marble, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"baN" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baO" = ( +/obj/machinery/door/blast/regular{ + id_tag = "toxinsdriver"; + name = "Toxins Launcher Bay Door" + }, +/obj/machinery/shield_diffuser, +/turf/floor/plating/airless, +/area/exodus/research/mixing) +"baP" = ( +/obj/machinery/door/airlock/glass/command{ + name = "Bridge" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"baQ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baR" = ( +/obj/structure/table/reinforced, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/item/toolbox/mechanical, +/obj/item/box/lights/mixed, +/obj/item/flashlight, +/obj/item/multitool, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/light_switch{ + pixel_x = 25; + pixel_y = -25 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"baU" = ( +/obj/machinery/door/airlock/glass/command{ + name = "Bridge" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"baV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"baW" = ( +/obj/machinery/door/airlock/glass/command{ + id_tag = "sbridgedoor"; + name = "Bridge" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"baX" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"baY" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"baZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bba" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bbb" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bbc" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bbd" = ( +/obj/structure/table/laminate, +/obj/item/chems/condiment/small/peppermill{ + pixel_x = 2; + pixel_y = 6 + }, +/obj/item/chems/condiment/small/saltshaker{ + pixel_x = -2; + pixel_y = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bbe" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bbf" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bbg" = ( +/obj/structure/table/laminate, +/obj/item/utensil/fork, +/obj/item/utensil/fork, +/obj/item/utensil/fork, +/obj/item/utensil/fork, +/obj/item/utensil/fork, +/obj/item/utensil/fork, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bbh" = ( +/obj/structure/table/marble, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"bbi" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bbj" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bbk" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/table/marble, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"bbl" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bbm" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Library"; + sort_type = "Library" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bbn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bbo" = ( +/obj/structure/table/laminate, +/obj/item/flame/candle, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bbp" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bbq" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/flora/pottedplant/minitree, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bbr" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bbs" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"bbt" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bbu" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bbv" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/item/radio/beacon, +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bbw" = ( +/obj/machinery/light/small, +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{ + id_tag = "escape_dock_north_airlock"; + master_tag = "escape_dock"; + pixel_y = 25; + tag_airpump = "escape_dock_north_pump"; + tag_chamber_sensor = "escape_dock_north_sensor"; + tag_exterior_door = "escape_dock_north_outer"; + tag_interior_door = "escape_dock_north_inner" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "escape_dock_north_pump" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"bbx" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bby" = ( +/obj/machinery/door/blast/regular{ + id_tag = "toxinsdriver"; + name = "Toxins Launcher Bay Door" + }, +/obj/machinery/shield_diffuser, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"bbz" = ( +/obj/machinery/button/access/interior{ + id_tag = "centcom_shuttle_dock_airlock"; + name = "interior access button"; + pixel_x = -28; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bbA" = ( +/obj/machinery/shield_diffuser, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bbB" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bbC" = ( +/obj/structure/flora/bush/fernybush, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"bbD" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bbE" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"bbF" = ( +/obj/structure/table, +/obj/machinery/faxmachine/mapped, +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bbG" = ( +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bbH" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/library) +"bbI" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/carpet, +/area/exodus/library) +"bbJ" = ( +/obj/machinery/door/airlock{ + name = "Unisex Restrooms" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/locker/locker_toilet) +"bbK" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "kitchen"; + name = "Kitchen Shutters" + }, +/turf/floor/tiled/white, +/area/exodus/hallway/primary/starboard) +"bbL" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bbM" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bbN" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bbO" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bbP" = ( +/obj/structure/closet/secure_closet/personal, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"bbQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bbR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bbS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bbT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/maintenance, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bbU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bbV" = ( +/obj/machinery/camera/network/civilian_west{ + c_tag = "Vacant Office"; + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bbW" = ( +/obj/machinery/light, +/obj/machinery/camera/network/exodus{ + c_tag = "Bridge West Entrance"; + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bbX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/meter, +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/bar) +"bbY" = ( +/obj/machinery/atmospherics/valve, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bbZ" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/locker/locker_toilet) +"bca" = ( +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bcb" = ( +/obj/structure/table/reinforced, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/item/box/fancy/donut, +/obj/effect/floor_decal/corner/blue/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"bcc" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bcd" = ( +/obj/machinery/door/airlock/glass/command{ + id_tag = "sbridgedoor"; + name = "Bridge" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"bce" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology) +"bcf" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"bcg" = ( +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bch" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bci" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bcj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"bck" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "surgeryobs"; + name = "Operating Theatre Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/surgery) +"bcl" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating/airless, +/area/exodus/turret_protected/ai) +"bcm" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"bcn" = ( +/obj/machinery/computer/guestpass{ + pixel_y = -28 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/obj/machinery/papershredder, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"bco" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/maintenance/locker) +"bcp" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/storage/tools) +"bcq" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/wall/prepainted, +/area/exodus/storage/tools) +"bcr" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"bcs" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/item/box/glasses/square, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bct" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bcu" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bcv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bcw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Library" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bcx" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + dir = 8; + id_tag = "surgeryobs2"; + name = "Operating Theatre Privacy Shutters" + }, +/turf/floor/plating, +/area/exodus/medical/surgery2) +"bcz" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/blue{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bcA" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bcB" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Kitchen" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/kitchen) +"bcC" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bcD" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/bridge) +"bcE" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bcF" = ( +/obj/machinery/button/blast_door{ + id_tag = "kitchen"; + name = "Kitchen Shutters Control"; + pixel_x = -1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/light, +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bcG" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bcH" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bcI" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge) +"bcJ" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bcK" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bcL" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bcM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bcN" = ( +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bcO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bcP" = ( +/obj/structure/flora/bush/brflowers, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Hydroponics Pasture South"; + dir = 8 + }, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"bcQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bcR" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bcS" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Chapel" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/main) +"bcT" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/chapel{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bcU" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bcV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bcW" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bcX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/chapel{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bcY" = ( +/obj/structure/flora/bush, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"bcZ" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bda" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass{ + name = "Chapel" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/chapel/main) +"bdd" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/library) +"bde" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/carpet, +/area/exodus/library) +"bdf" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/carpet, +/area/exodus/library) +"bdg" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/library) +"bdh" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Departures East"; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bdi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bdj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bdk" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"bdl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/chapel/main) +"bdm" = ( +/obj/structure/window/basic{ + dir = 4 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"bdn" = ( +/obj/machinery/photocopier, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bdo" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bdp" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bdq" = ( +/obj/structure/hygiene/toilet{ + pixel_y = 8 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bdr" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bds" = ( +/obj/machinery/door/airlock{ + name = "Unit 1" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bdt" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bdu" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Library" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bdv" = ( +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bdw" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"bdx" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/library) +"bdy" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "admin_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/obj/structure/sign/warning/airlock{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"bdz" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"bdA" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bdB" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bdC" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bdD" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/conveyor{ + dir = 4; + id_tag = "packageSort2" + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"bdE" = ( +/obj/effect/floor_decal/corner/blue/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bdF" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_one) +"bdG" = ( +/obj/machinery/door/airlock/command{ + id_tag = "captaindoor"; + name = "Captain's Office" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/captain) +"bdH" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bdI" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/icecream_vat, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bdJ" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bdK" = ( +/obj/machinery/door/airlock/glass{ + name = "Garden" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bdM" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bdN" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bdO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bdP" = ( +/turf/wall/prepainted, +/area/exodus/quartermaster/storage) +"bdQ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bdR" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bdS" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "packageSort2" + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"bdT" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "packageSort2" + }, +/obj/structure/flaps, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"bdU" = ( +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal/deliveryChute{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"bdV" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bdW" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bdX" = ( +/turf/wall/prepainted, +/area/exodus/research/xenobiology/xenoflora) +"bdY" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/bridge/meeting_room) +"bdZ" = ( +/turf/wall/prepainted, +/area/exodus/bridge/meeting_room) +"bea" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/chapel, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"beb" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/turret_protected/ai) +"bec" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/wall/r_wall/prepainted, +/area/exodus/turret_protected/ai) +"bed" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/captain) +"bee" = ( +/obj/effect/floor_decal/chapel{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bef" = ( +/obj/machinery/computer/arcade, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"beg" = ( +/obj/machinery/vending/cola{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"beh" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/computer/modular/preset/engineering, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"bei" = ( +/obj/machinery/camera/network/civilian_east{ + c_tag = "Bar South"; + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bej" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/light, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bek" = ( +/obj/effect/floor_decal/chapel, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"bel" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bem" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"ben" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"beo" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bep" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"beq" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning/cee{ + dir = 8; + icon_state = "warningcee" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"ber" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Auxiliary Docking North"; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bes" = ( +/obj/item/folder/yellow, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"bet" = ( +/obj/machinery/newscaster{ + pixel_y = -32; + dir = 1 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"beu" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/obj/machinery/light_switch{ + pixel_x = -21; + pixel_y = -10 + }, +/obj/machinery/centrifuge/mapped, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"bev" = ( +/obj/machinery/light, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"bew" = ( +/obj/structure/filing_cabinet, +/turf/floor/tiled/dark, +/area/exodus/security/vacantoffice) +"bex" = ( +/obj/structure/chair/comfy/black, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bey" = ( +/obj/machinery/vending/coffee{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"bez" = ( +/obj/item/box, +/obj/structure/table, +/obj/item/box, +/obj/item/box, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"beA" = ( +/obj/structure/table/laminate, +/obj/item/pen, +/turf/floor/laminate/walnut, +/area/exodus/library) +"beB" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"beC" = ( +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"beD" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green{ + pixel_x = 1; + pixel_y = 5 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"beE" = ( +/obj/structure/chair/comfy/brown{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"beF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"beG" = ( +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"beH" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"beI" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"beJ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"beK" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"beL" = ( +/obj/structure/closet/crate, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light/small/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"beM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/moving_parts{ + pixel_y = -32 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"beN" = ( +/obj/structure/closet/crate/freezer, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"beO" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"beP" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"beQ" = ( +/obj/item/stool, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"beR" = ( +/obj/machinery/conveyor_switch/oneway{ + id_tag = "packageSort2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"beS" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"beT" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"beU" = ( +/obj/machinery/atm{ + pixel_x = -32; + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"beV" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"beW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + autoset_access = 0; + name = "Diner" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"beX" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + autoset_access = 0; + name = "Diner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"beY" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/smartfridge/drying_oven, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hydroponics/garden) +"beZ" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-22" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bfa" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bfb" = ( +/obj/machinery/light_switch{ + pixel_x = 16; + pixel_y = -23 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/item/stack/package_wrap, +/obj/item/chems/rag, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bfc" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = -24; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bfd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bfe" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Cargo Bay Warehouse Maintenance" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bff" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bfg" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/network/requests_console{ + department = "Kitchen"; + name = "Kitchen RC"; + pixel_y = -32 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bfh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Medbay Patient Wing Maintenance Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/patient_wing) +"bfi" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "packageSort1" + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"bfj" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bfk" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bfl" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bfm" = ( +/turf/wall/prepainted, +/area/exodus/quartermaster/office) +"bfn" = ( +/obj/machinery/photocopier, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bfo" = ( +/obj/machinery/door/airlock/command{ + name = "Conference Room" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/bridge/meeting_room) +"bfp" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bfq" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Chapel" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bfr" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bfs" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bft" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bfu" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bfv" = ( +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bfw" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"bfx" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Chapel" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bfy" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/light/small, +/obj/machinery/camera/network/civilian_east{ + c_tag = "Library South"; + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"bfz" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable/green, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bfA" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bfB" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bfC" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bfD" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bfE" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bfF" = ( +/obj/machinery/ai_status_display{ + pixel_y = 32 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bfG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/table/laminate, +/obj/item/box/checkers/chess, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bfH" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bfI" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bfJ" = ( +/obj/machinery/computer/arcade, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bfK" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bfL" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bfM" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bfN" = ( +/obj/machinery/door/airlock{ + name = "Unit 2" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bfO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bfP" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/structure/mirror{ + pixel_x = 28 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bfQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bfR" = ( +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bfS" = ( +/obj/machinery/washing_machine, +/obj/machinery/light, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bfT" = ( +/obj/machinery/washing_machine, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bfU" = ( +/obj/structure/closet/crate, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bfV" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bfW" = ( +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Warehouse"; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bfX" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bfY" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eng_eva_outer"; + name = "Engineering EVA External Access" + }, +/obj/machinery/button/access/exterior{ + id_tag = "eng_eva_airlock"; + name = "exterior access button"; + pixel_y = 25 + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/atmos_control) +"bfZ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bga" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bgb" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"bgc" = ( +/obj/machinery/button/mass_driver{ + id_tag = "enginecore"; + name = "Emergency Core Eject"; + pixel_x = -20; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/window/basic{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bgd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio3"; + name = "Containment Blast Doors" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bge" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bgf" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bgg" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bgh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bgi" = ( +/turf/unsimulated/mask, +/area/exodus/maintenance/locker) +"bgj" = ( +/obj/structure/table, +/obj/item/stack/package_wrap/fifty, +/obj/item/stack/package_wrap/fifty, +/obj/machinery/network/requests_console{ + department = "Cargo Bay"; + pixel_y = 32; + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bgk" = ( +/obj/structure/closet/crate/medical, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bgl" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bgn" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bgo" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/entry/aft) +"bgp" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/reagent_dispensers/watertank, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bgq" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bgr" = ( +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/aft) +"bgs" = ( +/obj/structure/table, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bgt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bgu" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bgv" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/papershredder, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bgw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bgx" = ( +/obj/structure/cable/cyan{ + icon_state = "2-4" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"bgy" = ( +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"bgz" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/flora/pottedplant, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bgA" = ( +/obj/machinery/navbeacon/CHW, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bgB" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bgC" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"bgE" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bgF" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgH" = ( +/obj/machinery/atm{ + pixel_y = 28 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgJ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgK" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgL" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgM" = ( +/obj/machinery/button/blast_door{ + id_tag = "heads_meeting"; + name = "Security Shutters"; + pixel_y = 24 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bgN" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bgO" = ( +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bgP" = ( +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bgQ" = ( +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bgR" = ( +/obj/machinery/hologram/holopad, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bgS" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bgT" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_two) +"bgU" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bgV" = ( +/obj/structure/sign/directions/evac{ + dir = 4; + pixel_y = 32; + pixel_z = -8 + }, +/obj/structure/sign/directions/medical{ + dir = 8; + pixel_y = 40 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bgW" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/flasher{ + id_tag = "AI"; + pixel_y = 24 + }, +/obj/machinery/porta_turret, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bgX" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bgY" = ( +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bgZ" = ( +/obj/structure/chair/comfy/brown{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bha" = ( +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bhb" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bhc" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bhd" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bhe" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bhf" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bhg" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bhh" = ( +/obj/structure/flora/pottedplant{ + icon_state = "plant-10" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bhi" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bhj" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Starboard - East" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bhk" = ( +/obj/abstract/landmark{ + name = "tripai" + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bhl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bhm" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bhn" = ( +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bho" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bhp" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bhq" = ( +/obj/machinery/airlock_sensor{ + id_tag = "escape_dock_north_sensor"; + pixel_y = -25; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"bhr" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "centcom_shuttle_dock_airlock"; + pixel_y = 25; + tag_airpump = "centcom_shuttle_dock_pump"; + tag_chamber_sensor = "centcom_shuttle_dock_sensor"; + tag_exterior_door = "centcom_shuttle_dock_outer"; + tag_interior_door = "centcom_shuttle_dock_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "centcom_shuttle_dock_sensor"; + pixel_y = -25; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "centcom_shuttle_dock_pump" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"bhs" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"bht" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bhu" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bhv" = ( +/obj/machinery/camera/network/civilian_west{ + c_tag = "Waste Disposal"; + dir = 8 + }, +/obj/item/ashtray/plastic{ + pixel_x = 5; + pixel_y = -5 + }, +/obj/item/trash/cigbutt/cigarbutt, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bhw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bhx" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/mining{ + name = "Delivery Office" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/office) +"bhy" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/turf/floor/plating, +/area/exodus/crew_quarters/captain) +"bhz" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bhA" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bhB" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Locker Room South"; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bhC" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/turf/floor/tiled/techfloor/grid, +/area/exodus/security/vacantoffice) +"bhD" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"bhE" = ( +/obj/structure/closet/crate/internals, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhF" = ( +/obj/machinery/door/airlock{ + name = "Private Restroom" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/captain) +"bhG" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhH" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/light/small/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhI" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/structure/closet/emcloset, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhJ" = ( +/obj/machinery/button/blast_door{ + id_tag = "qm_warehouse"; + name = "Warehouse Door Control"; + pixel_x = -1; + pixel_y = -24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhK" = ( +/obj/machinery/conveyor_switch/oneway{ + id_tag = "packageSort1" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bhL" = ( +/obj/structure/table, +/obj/item/destTagger{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/item/destTagger{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bhN" = ( +/obj/machinery/camera/network/civilian_west{ + c_tag = "Warehouse" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhO" = ( +/obj/machinery/atmospherics/omni/mixer{ + tag_north = 1; + tag_south = 2; + tag_west = 1; + use_power = 0 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"bhP" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/turf/floor/plating, +/area/exodus/crew_quarters/captain) +"bhQ" = ( +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"bhR" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/blue, +/obj/effect/engine_setup/coolant_canister, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"bhS" = ( +/obj/machinery/power_sensor{ + id_tag = "AI Subgrid"; + name = "Powernet Sensor - AI Subgrid" + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bhT" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/porta_turret{ + dir = 8 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bhU" = ( +/obj/structure/table/laminate, +/obj/item/box/fancy/donut, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bhV" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/papershredder, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bhW" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bhX" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/apc, +/obj/item/cell{ + maxcharge = 2000 + }, +/obj/machinery/light/small/red, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bhY" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"bhZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bia" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bib" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bic" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/starboard) +"bid" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bie" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bif" = ( +/obj/structure/disposalpipe/sortjunction/wildcard, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"big" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bih" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bii" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bij" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bik" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bil" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bim" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bin" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bio" = ( +/obj/item/hand_labeler, +/obj/item/assembly/timer, +/obj/item/eftpos{ + eftpos_name = "Bridge EFTPOS scanner" + }, +/obj/structure/table/laminate, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bip" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"biq" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bir" = ( +/obj/item/folder/red, +/obj/structure/table/laminate, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bis" = ( +/obj/structure/table/laminate, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bit" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biu" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"biv" = ( +/obj/structure/table/laminate, +/obj/machinery/faxmachine/mapped, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"biw" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bix" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biy" = ( +/turf/wall/prepainted, +/area/exodus/turret_protected/ai) +"biz" = ( +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/engineering, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"biA" = ( +/obj/machinery/vending/coffee, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"biB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"biC" = ( +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"biD" = ( +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"biE" = ( +/obj/structure/table/laminate, +/obj/random_multi/single_item/captains_spare_id, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"biF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biG" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"biH" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"biJ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biK" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biL" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"biM" = ( +/obj/machinery/navbeacon/HOP2, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"biN" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"biO" = ( +/obj/structure/sign/directions/medical{ + dir = 4; + pixel_y = 32 + }, +/obj/structure/sign/directions/evac{ + dir = 4; + pixel_y = 32; + pixel_z = -8 + }, +/obj/structure/sign/directions/science{ + dir = 4; + pixel_y = 32; + pixel_z = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"biP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"biQ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"biR" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"biS" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "garbage" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"biT" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Disposal Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/disposal) +"biU" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"biV" = ( +/obj/machinery/door/airlock{ + name = "Unit 3" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"biX" = ( +/obj/machinery/network/relay, +/turf/floor/tiled/dark/monotile, +/area/exodus/security/nuke_storage) +"biY" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/disposal/deliveryChute, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"biZ" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Delivery Office"; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bja" = ( +/obj/structure/filing_cabinet, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bjb" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bjc" = ( +/obj/machinery/newscaster{ + pixel_x = 32; + pixel_y = 32 + }, +/obj/machinery/network/requests_console{ + department = "AI"; + pixel_y = 32; + dir = 1 + }, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the AI core maintenance door."; + id_tag = "AICore"; + name = "AI Maintenance Hatch"; + pixel_x = 17; + pixel_y = 25 + }, +/obj/item/radio/intercom{ + pixel_x = -28; + pixel_y = 4 + }, +/obj/item/radio/intercom{ + pixel_x = 28; + pixel_y = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/abstract/landmark/start/ai, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bjd" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{ + dir = 1; + id_tag = "escape_dock_south_airlock"; + master_tag = "escape_dock"; + pixel_y = -25; + tag_airpump = "escape_dock_south_pump"; + tag_chamber_sensor = "escape_dock_south_sensor"; + tag_exterior_door = "escape_dock_south_outer"; + tag_interior_door = "escape_dock_south_inner" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "escape_dock_south_pump" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"bje" = ( +/obj/abstract/landmark{ + name = "tripai" + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bjf" = ( +/obj/machinery/door/airlock/research{ + name = "Research Shuttle Dock" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"bjg" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjh" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/rack{ + dir = 8 + }, +/obj/item/chems/spray/extinguisher, +/obj/item/chems/spray/extinguisher, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bji" = ( +/obj/machinery/navbeacon/Stbd, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjj" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bjk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/starboard) +"bjl" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/storage/emergency) +"bjm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bjn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bjo" = ( +/obj/structure/disposalpipe/junction{ + dir = 2; + icon_state = "pipe-j2" + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - East"; + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bjp" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/disposal) +"bjq" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bjr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"bjs" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bju" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bjv" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjx" = ( +/obj/structure/disposalpipe/tagger/partial{ + name = "Sorting Office"; + sort_tag = "Sorting Office" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bjy" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjz" = ( +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Starboard - West"; + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bjB" = ( +/obj/item/frame/apc, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bjC" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjD" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bjF" = ( +/obj/machinery/airlock_sensor{ + id_tag = "eng_eva_sensor"; + pixel_y = 25 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"bjG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bjH" = ( +/obj/machinery/light, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjI" = ( +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/structure/table/laminate, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bjJ" = ( +/obj/item/folder/blue, +/obj/structure/table/laminate, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bjK" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/porta_turret{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bjL" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bjM" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bjN" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjO" = ( +/obj/machinery/door/window{ + name = "AI Core Door" + }, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/cable/cyan{ + icon_state = "2-8" + }, +/obj/machinery/flasher{ + id_tag = "AI"; + pixel_x = 22; + pixel_y = 24 + }, +/obj/machinery/turretid/stun{ + check_synth = 1; + name = "AI Chamber turret control"; + pixel_x = 36; + pixel_y = 24 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bjP" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bjQ" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjR" = ( +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjS" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bjT" = ( +/obj/machinery/vending/cigarette, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bjU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bjV" = ( +/turf/wall/prepainted, +/area/exodus/engineering/engineering_monitoring) +"bjW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bjX" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bjY" = ( +/obj/abstract/landmark{ + name = "lightsout" + }, +/turf/wall/prepainted, +/area/exodus/turret_protected/ai) +"bjZ" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bka" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bkb" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Starboard - Central"; + dir = 1 + }, +/obj/machinery/light, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bkc" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Medicine Storage" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bkd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bke" = ( +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"bkf" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Starboard - Central East"; + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bkg" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bkh" = ( +/obj/machinery/newscaster{ + pixel_y = -32; + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bki" = ( +/obj/structure/table, +/obj/item/deck/cards{ + pixel_y = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bkj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bkk" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/locker) +"bkl" = ( +/obj/machinery/airlock_sensor{ + id_tag = "escape_dock_south_sensor"; + pixel_y = 25 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/exit) +"bkm" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Disposal Access" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/nosmoking_1{ + pixel_y = 32 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/disposal) +"bkn" = ( +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"bko" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bkp" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"bkq" = ( +/obj/machinery/button/access/interior{ + id_tag = "specops_dock_airlock"; + name = "interior access button"; + pixel_x = -28; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bkr" = ( +/obj/machinery/button/access/interior{ + id_tag = "research_dock_airlock"; + name = "interior access button"; + pixel_x = 25; + pixel_y = -25 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bks" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/apc/high{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bkt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bku" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Locker Room Toilets"; + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bkv" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_y = -6 + }, +/obj/item/pen/red{ + pixel_x = -1; + pixel_y = -9 + }, +/obj/item/pen/blue{ + pixel_x = 3; + pixel_y = -5 + }, +/obj/item/camera, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bkw" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bkx" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bky" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bkz" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bkA" = ( +/turf/wall/prepainted, +/area/exodus/engineering/workshop) +"bkB" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bkC" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Supply Foyer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bkD" = ( +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bkE" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bkF" = ( +/obj/item/paper_bin{ + pixel_y = -10 + }, +/obj/item/folder/cyan, +/obj/item/pen, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bkG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bkH" = ( +/obj/structure/table/laminate, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bkI" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/machinery/light{ + dir = 8 + }, +/obj/item/megaphone, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bkJ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bkK" = ( +/obj/machinery/door/window{ + dir = 4; + name = "AI Core Door" + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bkL" = ( +/obj/structure/closet/secure_closet/captains, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bkM" = ( +/obj/machinery/door/window{ + base_state = "right"; + dir = 8; + icon_state = "right"; + name = "AI Core Door" + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bkN" = ( +/obj/structure/table/laminate, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/camera/network/command{ + c_tag = "Bridge - Captain's Office"; + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bkO" = ( +/obj/machinery/teleport/station, +/turf/floor/tiled/dark/monotile, +/area/exodus/teleporter) +"bkP" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bkQ" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "garbage" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bkR" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "garbage" + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bkS" = ( +/obj/structure/disposaloutlet{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bkT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/maintenance/disposal) +"bkU" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "research_dock_inner"; + name = "Shuttle Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"bkV" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "medbayquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bkW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bkX" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "medbayquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bkY" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Morgue" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bkZ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime/full, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bla" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"blb" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"blc" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bld" = ( +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"ble" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"blf" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/quartermaster/storage) +"blg" = ( +/obj/structure/sign/warning/secure_area{ + pixel_x = 32; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime/full, +/obj/effect/floor_decal/industrial/loading{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"blh" = ( +/obj/effect/floor_decal/corner/lime/full, +/obj/effect/floor_decal/industrial/loading{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"blk" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/purple/full, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"blm" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/wall/prepainted, +/area/exodus/quartermaster/office) +"bln" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple/full, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"blo" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"blp" = ( +/turf/wall/prepainted, +/area/exodus/engineering/storage) +"blq" = ( +/obj/machinery/door/airlock{ + name = "Unit 4" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"blr" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/locker/locker_toilet) +"bls" = ( +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Bridge"; + name = "Bridge RC"; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"blt" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"blu" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/white/full{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/medical, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"blv" = ( +/obj/structure/rack{ + dir = 4 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"blw" = ( +/obj/machinery/space_heater, +/obj/structure/sign/directions/pods{ + dir = 1; + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"blx" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bly" = ( +/obj/machinery/vending/coffee, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"blz" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"blA" = ( +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"blB" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/obj/structure/sign/department/mail_delivery{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"blC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"blD" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"blE" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"blF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window{ + base_state = "right"; + dir = 8; + icon_state = "right"; + name = "Mailing Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"blG" = ( +/obj/structure/table/laminate, +/obj/item/folder/blue, +/obj/item/stamp/captain{ + pixel_x = -4; + pixel_y = 3 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/item/stamp/denied{ + pixel_x = 4; + pixel_y = 3 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"blH" = ( +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"blI" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"blJ" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"blK" = ( +/obj/structure/table/laminate, +/obj/item/pinpointer, +/obj/item/disk/nuclear, +/obj/item/secure_storage/safe{ + pixel_x = 35; + pixel_y = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"blL" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - West"; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"blN" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/command{ + name = "Conference Room" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/command) +"blO" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/primary/starboard) +"blP" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"blQ" = ( +/obj/structure/closet/secure_closet/personal, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/crew_quarters/locker) +"blR" = ( +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"blS" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "specops_dock_airlock"; + pixel_y = 25; + tag_airpump = "specops_dock_pump"; + tag_chamber_sensor = "specops_dock_sensor"; + tag_exterior_door = "specops_dock_outer"; + tag_interior_door = "specops_dock_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "specops_dock_sensor"; + pixel_y = -25; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "specops_dock_pump" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"blT" = ( +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"blU" = ( +/obj/machinery/chemical_dispenser/full, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"blV" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/chemical_dispenser/full, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"blW" = ( +/obj/structure/table/glass, +/obj/machinery/reagent_temperature/cooler, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"blX" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = 29 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay - Chemistry" + }, +/obj/structure/table/glass, +/obj/machinery/reagent_temperature, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"blY" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/button/blast_door{ + id_tag = "chemcounter"; + name = "Pharmacy Counter Lockdown Control"; + pixel_y = 25 + }, +/obj/machinery/reagentgrinder, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"blZ" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/item/box/cups, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bma" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/carpet, +/area/exodus/bridge/meeting_room) +"bmb" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bmc" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/exit) +"bmd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bme" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bmf" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Lobby Port" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/sign/warning/nosmoking_1{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bmg" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "garbage" + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bmh" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/medical/virology) +"bmi" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bmj" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Patient Hallway - Starboard"; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bmk" = ( +/obj/machinery/door/airlock/glass/medical{ + name = "Hygiene Facilities" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/patient_wing/washroom) +"bml" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bmm" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bmn" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bmo" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bmp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bmq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio3"; + name = "Containment Blast Doors" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bmr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bms" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bmt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bmu" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bmv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bmw" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Lobby Starboard" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/sign/warning/nosmoking_1{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bmx" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bmz" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bmA" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/closet/secure_closet/medical1, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bmB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bmC" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/chair/wheelchair, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bmD" = ( +/obj/machinery/disposal, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bmE" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/table/laminate, +/obj/item/box/fancy/donut, +/turf/floor/laminate/walnut, +/area/exodus/bridge/meeting_room) +"bmF" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bmG" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/substation/command) +"bmH" = ( +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/obj/machinery/apc/super/critical{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bmI" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/porta_turret{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bmJ" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bmK" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bmL" = ( +/obj/machinery/button/access/interior{ + id_tag = "eng_eva_airlock"; + name = "interior access button"; + pixel_y = 25 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bmM" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bmN" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bmO" = ( +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Captain's Desk"; + name = "Captain RC"; + pixel_x = -32; + dir = 8 + }, +/obj/structure/filing_cabinet, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bmP" = ( +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bmQ" = ( +/obj/machinery/light, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"bmR" = ( +/obj/structure/table/laminate, +/obj/item/eftpos{ + eftpos_name = "Captain EFTPOS scanner" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bmS" = ( +/obj/structure/table/laminate, +/obj/item/whip/chainofcommand, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/random_multi/single_item/captains_spare_id, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bmT" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/turf/floor/plating, +/area/exodus/hallway/primary/starboard) +"bmU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bmV" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bmW" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bmX" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bmY" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/medical/chemistry) +"bmZ" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Morgue" + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bna" = ( +/obj/structure/morgue{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bnb" = ( +/obj/machinery/light/small, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bnc" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Command" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bnd" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/workshop) +"bne" = ( +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/machinery/light_switch{ + pixel_x = -25; + dir = 4 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/belt/utility, +/obj/item/belt/utility, +/turf/floor/tiled/white/monotile, +/area/exodus/research/robotics) +"bnf" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bng" = ( +/obj/item/book/manual/robotics_cyborgs{ + pixel_x = 2; + pixel_y = 5 + }, +/obj/machinery/network/requests_console{ + department = "Robotics"; + name = "Robotics RC"; + pixel_y = 32; + dir = 1 + }, +/obj/item/chems/glass/beaker/large, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/white/monotile, +/area/exodus/research/robotics) +"bnh" = ( +/obj/machinery/fabricator/imprinter{ + id_tag = "science" + }, +/obj/item/chems/glass/beaker/sulfuric, +/obj/structure/reagent_dispensers/acid{ + pixel_y = 32 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/research/robotics) +"bni" = ( +/turf/wall/prepainted, +/area/exodus/medical/reception) +"bnj" = ( +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"bnk" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio2"; + name = "Containment Blast Doors" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bnl" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 8 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/structure/sign/department/chemistry, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnm" = ( +/obj/machinery/newscaster{ + pixel_x = 30; + dir = 4 + }, +/obj/structure/flora/pottedplant{ + icon_state = "plant-10" + }, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 1 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnn" = ( +/turf/wall/prepainted, +/area/exodus/medical/exam_room) +"bno" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/chief) +"bnp" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/chief) +"bnq" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/structure/table, +/turf/floor/tiled/white, +/area/exodus/research) +"bnr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/chair, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bns" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/exit) +"bnt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bnu" = ( +/obj/structure/closet/emcloset, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Auxiliary Docking South" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bnv" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/structure/sign/warning/vacuum{ + dir = 8; + pixel_x = 32 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bnw" = ( +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the office door."; + id_tag = "captaindoor"; + name = "Office Door Control"; + pixel_x = 15; + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the starboard bridge doors."; + id_tag = "sbridgedoor"; + name = "Bridge Door Control"; + pixel_x = 15; + pixel_y = 39 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bnx" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/rack{ + dir = 8 + }, +/obj/item/toolbox/electrical{ + pixel_x = 1; + pixel_y = 6 + }, +/obj/item/clothing/head/welding{ + pixel_x = -3; + pixel_y = 5 + }, +/obj/item/clothing/head/welding{ + pixel_x = -3; + pixel_y = 5 + }, +/obj/item/toolbox/mechanical, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bny" = ( +/obj/machinery/door/blast/shutters{ + dir = 2; + id_tag = "qm_warehouse"; + name = "Warehouse Shutters" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bnz" = ( +/obj/structure/disposalpipe/trunk, +/obj/structure/disposaloutlet{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bnA" = ( +/obj/item/folder/yellow, +/obj/item/pen{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bnB" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bnC" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bnD" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/structure/table/steel, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bnE" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/substation/command) +"bnF" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bnG" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bnH" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bnI" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/lab) +"bnJ" = ( +/obj/machinery/ai_slipper, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/obj/structure/cable/cyan{ + icon_state = "2-8" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai) +"bnK" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bnL" = ( +/obj/item/chems/glass/beaker/large, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bnM" = ( +/turf/wall/prepainted, +/area/exodus/storage/emergency) +"bnN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bnO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bnP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bnQ" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Chemist" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bnR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnS" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnT" = ( +/obj/machinery/conveyor_switch/oneway{ + convdir = -1; + id_tag = "garbage"; + name = "disposal coveyor" + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bnU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnV" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnW" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnX" = ( +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bnY" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bnZ" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"boa" = ( +/obj/structure/table, +/obj/item/box/lights/mixed, +/obj/item/box/lights/mixed, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bob" = ( +/obj/structure/window/reinforced, +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"boc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bod" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"boe" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/flashlight, +/obj/item/clothing/mask/gas, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bof" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/structure/sign/department/examroom{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bog" = ( +/obj/structure/disposalpipe/segment, +/turf/wall/prepainted, +/area/exodus/quartermaster/storage) +"boh" = ( +/obj/structure/disposalpipe/segment, +/turf/wall/prepainted, +/area/exodus/quartermaster/office) +"boi" = ( +/obj/structure/disposalpipe/trunk, +/obj/structure/disposaloutlet{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/quartermaster/office) +"boj" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bok" = ( +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bol" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bom" = ( +/obj/machinery/porta_turret, +/obj/item/radio/intercom{ + pixel_x = -4; + pixel_y = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bon" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"boo" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bop" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"boq" = ( +/obj/structure/table, +/obj/item/scanner/autopsy, +/obj/item/scalpel, +/obj/item/chems/spray/antiseptic, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bor" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bos" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bot" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/porta_turret, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bou" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Captain" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bov" = ( +/obj/structure/morgue{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bow" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"box" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"boy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"boz" = ( +/obj/machinery/light_switch{ + pixel_x = -6; + pixel_y = 28 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/button/blast_door{ + id_tag = "Skynet_launch"; + name = "Mech Bay Door Control"; + pixel_x = 6; + pixel_y = 28 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"boA" = ( +/obj/item/stool, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"boC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"boD" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/storage/emergency) +"boE" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"boF" = ( +/obj/machinery/faxmachine/mapped, +/obj/structure/table/laminate, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"boH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boI" = ( +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boJ" = ( +/obj/structure/table/steel_reinforced, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel{ + amount = 10 + }, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel{ + amount = 10 + }, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel{ + amount = 10 + }, +/obj/item/stack/material/panel/mapped/plastic{ + amount = 50 + }, +/obj/item/stack/material/panel/mapped/plastic{ + amount = 50 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"boK" = ( +/obj/structure/chair/office/light{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Roboticist" + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boL" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boM" = ( +/obj/machinery/camera/network/research{ + c_tag = "Research - Robotics" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk, +/obj/machinery/disposal, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boN" = ( +/obj/structure/filing_cabinet/chestdrawer, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boO" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"boP" = ( +/obj/machinery/door/airlock/research{ + id_tag = "researchdoor"; + name = "Research Division Access" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"boQ" = ( +/obj/machinery/recycler, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"boR" = ( +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -8 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"boS" = ( +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/chair/office/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"boT" = ( +/obj/structure/chair/office/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"boU" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - R&D Lab" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/obj/structure/table, +/obj/machinery/cell_charger, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"boV" = ( +/obj/item/folder/cyan, +/obj/structure/table, +/obj/item/disk/tech_disk, +/obj/item/disk/tech_disk, +/obj/item/disk/design_disk, +/obj/item/disk/design_disk, +/obj/item/chems/dropper{ + pixel_y = -4 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"boW" = ( +/obj/item/stack/material/rods{ + amount = 50 + }, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/item/cell/high, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/table/steel_reinforced, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"boX" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/network/relay, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"boY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"boZ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bpa" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bpb" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "garbage" + }, +/obj/machinery/door/blast/regular{ + id_tag = "Disposal Exit"; + name = "Disposal Exit Vent" + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bpc" = ( +/obj/structure/table, +/obj/item/aiModule/oxygen, +/obj/item/aiModule/oneHuman, +/obj/item/aiModule/purge, +/obj/structure/window/reinforced, +/obj/item/aiModule/antimov, +/obj/item/aiModule/teleporterOffline, +/obj/item/aiModule/robocop, +/obj/item/aiModule/paladin, +/obj/item/aiModule/corp, +/obj/item/aiModule/freeformcore, +/obj/item/aiModule/asimov, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bpd" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bpe" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/network/requests_console{ + department = "Cargo Bay"; + pixel_y = 32; + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bpf" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/closet/secure_closet/medical_wall/pills{ + pixel_y = 32 + }, +/obj/item/chems/syringe/stabilizer, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bpg" = ( +/obj/item/stack/package_wrap, +/obj/item/hand_labeler, +/obj/item/chems/spray/cleaner{ + desc = "Someone has crossed out the 'Space' from Space Cleaner and written in Chemistry. Scrawled on the back is, 'Okay, whoever filled this with polytrinic acid, it was only funny the first time. It was hard enough replacing the CMO's first cat!'"; + name = "Chemistry Cleaner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/glass, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bph" = ( +/turf/unsimulated/mask, +/area/exodus/storage/emergency) +"bpi" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/tank/emergency/oxygen, +/obj/item/tank/emergency/oxygen, +/turf/floor/tiled/dark, +/area/exodus/maintenance/substation/command) +"bpj" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/chargebay) +"bpk" = ( +/obj/machinery/button/blast_door{ + id_tag = "qm_warehouse"; + name = "Warehouse Door Control"; + pixel_x = -1; + pixel_y = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bpl" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"bpm" = ( +/obj/item/trash/candy, +/obj/item/trash/popcorn, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bpn" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bpo" = ( +/obj/machinery/newscaster{ + pixel_x = -27; + pixel_y = 1 + }, +/obj/item/stack/tape_roll/duct_tape, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/machinery/vending/wallmed1{ + pixel_y = -32 + }, +/obj/item/hand_labeler, +/obj/item/belt/utility, +/obj/machinery/cell_charger, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bpp" = ( +/turf/wall/prepainted, +/area/exodus/research/robotics) +"bpq" = ( +/obj/machinery/photocopier, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bpr" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bps" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bpt" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 1; + name = "Sorting Office"; + sort_type = "Sorting Office" + }, +/obj/machinery/papershredder, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bpu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bpv" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bpw" = ( +/obj/machinery/conveyor_switch/oneway{ + convdir = -1; + id_tag = "packageExternal" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bpx" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/medical/virology) +"bpy" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bpz" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bpA" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/structure/sign/warning/high_voltage{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bpB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bpC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green, +/obj/machinery/power_sensor{ + id_tag = "Command Subgrid"; + name = "Powernet Sensor - Command Subgrid" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bpD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bpE" = ( +/obj/structure/closet/hydrant{ + pixel_x = -32; + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bpF" = ( +/turf/floor/plating, +/area/exodus/storage/emergency) +"bpG" = ( +/obj/structure/table/laminate, +/obj/random_multi/single_item/captains_spare_id{ + weight = 10 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bpH" = ( +/obj/structure/table, +/obj/item/belt/utility, +/obj/item/clothing/gloves/latex, +/obj/item/stock_parts/computer/hard_drive/portable, +/obj/item/stock_parts/computer/hard_drive/portable, +/obj/item/stock_parts/matter_bin, +/obj/item/stock_parts/matter_bin, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/console_screen, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bpI" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/substation/command) +"bpJ" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bpK" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bpL" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bpM" = ( +/obj/machinery/camera/network/command{ + c_tag = "AI Upload - West"; + dir = 4 + }, +/obj/machinery/ai_status_display{ + pixel_x = -32 + }, +/obj/machinery/porta_turret{ + dir = 4 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bpN" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bpO" = ( +/obj/structure/disposaloutlet, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/space) +"bpP" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bpQ" = ( +/obj/item/box/beakers, +/obj/item/box/beakers, +/obj/item/chems/dropper, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bpR" = ( +/obj/machinery/light_switch{ + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/disposal) +"bpS" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24; + pixel_y = 6 + }, +/obj/item/scanner/spectrometer/adv, +/obj/item/clothing/glasses/science, +/obj/item/clothing/glasses/science, +/obj/item/clothing/glasses/science, +/obj/machinery/button/blast_door{ + id_tag = "chemwindow"; + name = "Pharmacy Windows Shutter Control"; + pixel_x = -22; + pixel_y = -10 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bpT" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bpU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bpV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bpW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bpX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio2"; + name = "Containment Blast Doors" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bpY" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bpZ" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bqa" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bqb" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bqc" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bqd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bqe" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Examination room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/exam_room) +"bqf" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bqg" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bqh" = ( +/obj/structure/sign/poster, +/turf/wall/prepainted, +/area/exodus/quartermaster/storage) +"bqi" = ( +/obj/structure/bed/padded, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bqj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bqk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/quartermaster/office) +"bql" = ( +/turf/wall/prepainted, +/area/exodus/engineering/atmos/storage) +"bqm" = ( +/obj/structure/filing_cabinet/chestdrawer{ + desc = "A large drawer filled with autopsy reports."; + name = "Autopsy Reports" + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bqn" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bqo" = ( +/obj/machinery/optable, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bqp" = ( +/obj/structure/morgue{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bqq" = ( +/obj/machinery/door/firedoor, +/obj/structure/sign/department/examroom{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bqr" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/cryopod/robot{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"bqs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"bqt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"bqu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bqv" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/research{ + name = "Robotics Lab" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/robotics) +"bqw" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bqx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bqy" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bqz" = ( +/obj/structure/rack, +/obj/item/tank/jetpack/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/clothing/suit/armor/captain, +/obj/item/clothing/head/helmet/space/capspace, +/obj/machinery/newscaster{ + pixel_x = -32; + dir = 8 + }, +/obj/random_multi/single_item/captains_spare_id, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bqA" = ( +/obj/machinery/keycard_auth{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bqB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bqC" = ( +/obj/machinery/light, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bqD" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bqE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bqF" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 26 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bqG" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bqH" = ( +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bqI" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bqJ" = ( +/obj/structure/closet/emcloset, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bqK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bqL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/wall/prepainted, +/area/exodus/engineering/atmos/storage) +"bqM" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bqN" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Division Access" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bqO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/research) +"bqP" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/reagent_dispensers/acid{ + pixel_x = -32 + }, +/obj/machinery/fabricator/imprinter{ + id_tag = "science" + }, +/obj/item/chems/glass/beaker/sulfuric, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"bqQ" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bqR" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bqS" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bqT" = ( +/obj/structure/table, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/capacitor, +/obj/item/stock_parts/capacitor, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/scanning_module, +/obj/item/stock_parts/scanning_module, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bqU" = ( +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bqV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bqW" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 4; + id_tag = "cargo_bay"; + name = "cargo bay hatch controller"; + pixel_x = -30; + tag_door = "cargo_bay_door" + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Receiving Dock"; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bqX" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bqY" = ( +/obj/structure/sign/warning/docking_area{ + pixel_y = -32; + dir = 1 + }, +/turf/space, +/area/space) +"bqZ" = ( +/obj/machinery/mech_recharger, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"bra" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"brb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"brc" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"brd" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bre" = ( +/obj/machinery/portable_atmospherics/powered/scrubber/huge, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/window/borosilicate_reinforced{ + dir = 4 + }, +/obj/structure/window/borosilicate_reinforced{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/research/mixing) +"brf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"brg" = ( +/obj/structure/catwalk, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"brh" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/robotics) +"bri" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"brj" = ( +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/porta_turret{ + dir = 8 + }, +/obj/machinery/camera/network/command{ + c_tag = "AI Upload - East"; + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"brk" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"brl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"brm" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/mining{ + name = "Delivery Office" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/office) +"brn" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bro" = ( +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/wallframe_spawn/reinforced/polarized, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hop) +"brp" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"brq" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "admin_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"brr" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/storage/emergency) +"brs" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio1"; + name = "Containment Blast Doors" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"brt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bru" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/vault/bolted{ + name = "AI core" + }, +/obj/machinery/door/blast/regular{ + id_tag = "AICore"; + name = "AI core maintenance hatch" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/turret_protected/ai) +"brv" = ( +/obj/machinery/door/window{ + base_state = "right"; + dir = 4; + icon_state = "right"; + name = "Captain's Desk Door" + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"brw" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "packageExternal" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"brx" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "packageExternal" + }, +/obj/structure/flaps{ + opacity = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/office) +"bry" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"brz" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"brA" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"brB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/item/toolbox/mechanical, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"brC" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/wall/prepainted, +/area/exodus/engineering/atmos/storage) +"brD" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/cell_charger, +/obj/structure/table/steel, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"brE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"brF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/wall/prepainted, +/area/exodus/engineering/atmos/storage) +"brG" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/locker) +"brH" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"brI" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/substation/command) +"brJ" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"brK" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -27; + pixel_y = 1 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"brL" = ( +/obj/structure/sign/department/science_1{ + pixel_x = 32 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"brM" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"brN" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"brO" = ( +/obj/item/box/syringes, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/item/screwdriver, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"brP" = ( +/obj/machinery/door/window/northright{ + name = "Medbay Lobby" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"brQ" = ( +/obj/machinery/door/window/northright{ + name = "Medbay Lobby" + }, +/obj/item/chems/spray/cleaner{ + pixel_x = -5 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"brS" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/item/paper_bin, +/obj/item/folder/cyan, +/obj/item/pen, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"brT" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/medical, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"brU" = ( +/obj/effect/floor_decal/corner/purple/full, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"brV" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"brW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio1"; + name = "xenobio1" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"brX" = ( +/obj/structure/closet/secure_closet/medical_wall/pills{ + pixel_y = -32; + dir = 1 + }, +/obj/item/chems/syringe/antibiotic, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"brY" = ( +/obj/item/cane, +/obj/item/cane{ + pixel_x = -3; + pixel_y = 2 + }, +/obj/item/cane{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/item/box/rxglasses, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"brZ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bsa" = ( +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Command Substation Bypass" + }, +/obj/machinery/light, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bsb" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bsc" = ( +/obj/structure/rack, +/obj/item/crowbar, +/obj/item/crowbar, +/obj/item/toolbox/mechanical, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/obj/item/rig/medical/equipped, +/obj/item/defibrillator/compact/loaded, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bsd" = ( +/obj/structure/table, +/obj/item/box/bodybags, +/obj/item/box/bodybags, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bse" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"bsf" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Mech Bay"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/recharge_station, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"bsg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bsh" = ( +/obj/machinery/fabricator/robotics{ + id_tag = "science"; + output_dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bsi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"bsj" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bsk" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/abstract/landmark/latejoin/cyborg, +/obj/machinery/computer/cryopod/robot{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"bsl" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bsm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/machinery/flasher{ + id_tag = "AI"; + pixel_x = -22; + pixel_y = 24 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bsn" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/ai_status_display{ + pixel_x = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bsp" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/captain) +"bsq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/wall/prepainted, +/area/exodus/engineering/atmos/storage) +"bsr" = ( +/obj/machinery/light, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bss" = ( +/obj/structure/closet/firecloset, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bst" = ( +/obj/structure/hygiene/shower{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6; + icon_state = "warning" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bsu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/research) +"bsv" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/item/box/cups, +/obj/item/box/cups{ + pixel_x = 2; + pixel_y = 5 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bsw" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/fabricator{ + id_tag = "science" + }, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"bsx" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Cargo Bay Maintenance" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bsy" = ( +/turf/wall/prepainted, +/area/exodus/engineering) +"bsz" = ( +/obj/machinery/computer/design_console{ + dir = 8; + id_tag = "science" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"bsA" = ( +/obj/item/toolbox/electrical, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/table/steel, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bsB" = ( +/obj/machinery/door/window/eastright{ + dir = 8; + name = "Sublevel Access" + }, +/obj/machinery/ai_status_display{ + pixel_y = 32 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bsC" = ( +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"bsD" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bsE" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bsF" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bsG" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bsH" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bsI" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bsL" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bsM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bsN" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/medical/virology) +"bsO" = ( +/obj/machinery/portable_atmospherics/powered/scrubber/huge, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/window/borosilicate_reinforced{ + dir = 8 + }, +/obj/structure/window/borosilicate_reinforced{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/research/mixing) +"bsP" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bsQ" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"bsR" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eng_eva_outer"; + name = "Engineering EVA External Access" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/atmos_control) +"bsS" = ( +/obj/machinery/mass_driver{ + id_tag = "trash" + }, +/obj/machinery/airlock_sensor{ + pixel_x = -25; + pixel_y = 10 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/disposal) +"bsT" = ( +/obj/structure/closet/emcloset, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bsU" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bsV" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bsW" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bsX" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bsY" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/conveyor_switch/oneway{ + id_tag = "QMLoad3" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bsZ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bta" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"btb" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Teleporter Maintenance" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/teleporter) +"btc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"btd" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bte" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"btf" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"btg" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bth" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"bti" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"btj" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"btk" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/structure/window/reinforced, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"btl" = ( +/obj/machinery/door/airlock/command{ + name = "Head of Personnel" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/command) +"btm" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"btn" = ( +/obj/machinery/door/window/southright{ + name = "Virology Isolation Room Two" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"bto" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = -32 + }, +/obj/structure/cable/green, +/obj/effect/wallframe_spawn/reinforced/polarized, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/crew_quarters/heads/hop) +"btp" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/structure/mirror{ + pixel_x = 28 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/captain) +"btq" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"btr" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - East Southwest"; + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bts" = ( +/obj/item/chems/dropper, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"btt" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"btu" = ( +/obj/machinery/chem_master, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"btv" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = -25; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"btw" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"btx" = ( +/obj/structure/filing_cabinet/chestdrawer{ + name = "Medical Forms" + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bty" = ( +/obj/machinery/button/alternate/door{ + desc = "A remote control switch for the medbay foyer."; + id_tag = "MedbayFoyerPort"; + name = "Medbay Doors Control"; + pixel_x = -16; + pixel_y = 28 + }, +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"btA" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/table/laminate, +/obj/item/deck/cards{ + pixel_y = 4 + }, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"btB" = ( +/obj/machinery/button/blast_door{ + id_tag = "medbayrecquar"; + name = "Medbay Entrance Lockdown Shutters Control"; + pixel_x = 6; + pixel_y = 8 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"btC" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/central_three) +"btD" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "xenobio3"; + name = "Containment Blast Doors"; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"btE" = ( +/obj/machinery/button/access/interior{ + id_tag = "admin_shuttle_dock_airlock"; + name = "interior access button"; + pixel_x = -8; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"btF" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"btG" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/primary/central_three) +"btH" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/research/docking) +"btI" = ( +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"btJ" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/window/reinforced, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"btK" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/machinery/papershredder, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"btL" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"btM" = ( +/obj/machinery/button/alternate/door{ + desc = "A remote control switch for the medbay foyer."; + id_tag = "MedbayFoyerStar"; + name = "Medbay Doors Control"; + pixel_x = 6; + pixel_y = 28 + }, +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"btN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"btO" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = -32 + }, +/obj/effect/floor_decal/corner/paleblue/three_quarters, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"btP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"btQ" = ( +/obj/structure/displaycase, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"btR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"btS" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"btT" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"btU" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"btV" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"btW" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"btX" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"btZ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bua" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"bub" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/medical/morgue) +"buc" = ( +/turf/wall/prepainted, +/area/exodus/medical/chemistry) +"bud" = ( +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bue" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/recharge_station, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"buf" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bug" = ( +/obj/item/stack/material/sheet/reinforced/mapped/plasteel{ + amount = 10 + }, +/obj/item/stack/cable_coil, +/obj/item/flash, +/obj/item/flash, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"buh" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bui" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"buj" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"buk" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/red, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bul" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bum" = ( +/obj/effect/floor_decal/corner/purple/full, +/obj/structure/flora/pottedplant/minitree, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bun" = ( +/obj/structure/sign/warning/docking_area{ + dir = 8; + pixel_x = 32 + }, +/turf/space, +/area/space) +"buo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bup" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "xenobio2"; + name = "Containment Blast Doors"; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"buq" = ( +/obj/machinery/door/airlock/research{ + id_tag = "researchdoor"; + name = "Research Division Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"bur" = ( +/obj/machinery/computer/design_console{ + dir = 4; + id_tag = "science" + }, +/obj/machinery/fabricator/protolathe{ + id_tag = "science" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"bus" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/destructive_analyzer{ + id_tag = "science" + }, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"but" = ( +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/turf/floor/tiled/dark, +/area/exodus/research/lab) +"buu" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/light_switch{ + pixel_x = -5; + pixel_y = -22 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"buv" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"buw" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bux" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"buy" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "eng_eva_pump" + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"buz" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "xenobio1"; + name = "Containment Blast Doors"; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/research{ + c_tag = "Xenobiology Southwest"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"buA" = ( +/obj/item/radio/beacon, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"buB" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/conveyor{ + dir = 1; + id_tag = "QMLoad3" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buC" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buD" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buE" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buF" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buG" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/computer/upload/robot{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"buH" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buI" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"buJ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buK" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/double/glass/mining{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"buL" = ( +/obj/structure/disposalpipe/tagger/partial{ + name = "Sorting Office"; + sort_tag = "Sorting Office" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buM" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buN" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/computer/upload/ai{ + dir = 8 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"buO" = ( +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/clipboard, +/obj/item/pen/red{ + pixel_x = 2; + pixel_y = 6 + }, +/obj/structure/table, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buP" = ( +/obj/item/stamp/cargo{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/stamp/denied{ + pixel_x = 4; + pixel_y = -2 + }, +/obj/structure/table, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/status_display/supply_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buQ" = ( +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/wall/prepainted, +/area/exodus/quartermaster/miningdock) +"buR" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"buS" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Lobby" + }, +/obj/item/radio/beacon, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buT" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/firealarm{ + pixel_y = 27 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"buU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"buW" = ( +/obj/structure/disposalpipe/segment, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"buX" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/machinery/recharger, +/obj/item/stack/package_wrap, +/obj/item/hand_labeler, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/table/glass, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"buY" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/table/glass, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"buZ" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/papershredder, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bva" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/machinery/recharger/wallcharger{ + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bvb" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bvc" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "xenobio4"; + name = "Containment Blast Doors"; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bvd" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bve" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bvf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bvg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bvh" = ( +/obj/structure/hygiene/toilet{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/captain) +"bvi" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bvj" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bvk" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Chemistry Laboratory" + }, +/obj/structure/sign/department/chemistry{ + pixel_x = 32 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bvl" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "medbayrecquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/reception) +"bvm" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "medbayrecquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/reception) +"bvn" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bvo" = ( +/obj/machinery/door/window/eastright{ + base_state = "left"; + dir = 8; + icon_state = "left"; + name = "Medical Reception" + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bvp" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bvq" = ( +/obj/machinery/door/window/eastright{ + name = "Medical Reception" + }, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bvr" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bvs" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"bvt" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "medbayrecquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/reception) +"bvu" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "medbayrecquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/reception) +"bvv" = ( +/obj/structure/table, +/obj/item/firstaid/regular{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/machinery/light_switch{ + pixel_x = -23; + dir = 4 + }, +/obj/random/firstaid{ + pixel_y = 1 + }, +/obj/effect/floor_decal/corner/beige/three_quarters, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bvw" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hop) +"bvx" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Examination Room" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bvy" = ( +/obj/machinery/door/airlock/medical{ + name = "Morgue" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bvz" = ( +/turf/wall/prepainted, +/area/exodus/research/chargebay) +"bvA" = ( +/obj/effect/floor_decal/corner/paleblue, +/obj/structure/table, +/obj/item/organ/internal/brain_interface/empty, +/obj/item/organ/internal/brain_interface/empty, +/obj/item/organ/internal/brain_interface/empty, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bvB" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bvC" = ( +/obj/structure/table, +/obj/item/assembly/prox_sensor{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/assembly/prox_sensor{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/assembly/prox_sensor{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/assembly/prox_sensor{ + pixel_x = -8; + pixel_y = 4 + }, +/obj/item/toolbox/mechanical, +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bvD" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bvE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"bvF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bvG" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/command) +"bvH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bvK" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/research/lab) +"bvL" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/research{ + name = "Research and Development" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/lab) +"bvM" = ( +/turf/wall/prepainted, +/area/exodus/research/lab) +"bvN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bvO" = ( +/obj/effect/paint/red, +/turf/wall/titanium, +/area/ship/exodus_pod_research) +"bvP" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/security/range) +"bvQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bvR" = ( +/obj/machinery/network/relay, +/turf/floor/bluegrid, +/area/exodus/research/server) +"bvS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bvT" = ( +/obj/machinery/apc/high{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Server Room" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bvU" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bvV" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/machinery/light/small, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "eng_eva_pump" + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"bvW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio4"; + name = "xenobio4" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bvX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio4"; + name = "xenobio4" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bvY" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"bvZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio5"; + name = "xenobio5" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bwa" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio5"; + name = "xenobio5" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bwb" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bwc" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "QMLoad3" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bwd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bwe" = ( +/obj/vehicle/train/trolley, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bwf" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bwg" = ( +/obj/vehicle/train/engine, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bwh" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 1 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwi" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 1; + name = "Cargo Bay"; + sort_type = "Cargo Bay" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwj" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwk" = ( +/turf/wall/prepainted, +/area/exodus/medical/medbay2) +"bwl" = ( +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwm" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio6"; + name = "xenobio6" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bwn" = ( +/obj/structure/table, +/obj/item/aiModule/nanotrasen, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/item/aiModule/reset, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bwo" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwp" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable/green, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio6"; + name = "xenobio6" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bwr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/westleft{ + name = "Cargo Desk" + }, +/obj/structure/noticeboard{ + default_pixel_y = 27 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/office) +"bws" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bwt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bwu" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Medical" + }, +/obj/structure/cable/green, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"bwv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bww" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research) +"bwx" = ( +/obj/structure/table, +/obj/item/aiModule/freeform, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/item/aiModule/protectStation, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bwy" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"bwz" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bwA" = ( +/obj/effect/floor_decal/corner/grey{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/sleep) +"bwB" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bwC" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/captain, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bwE" = ( +/turf/wall/prepainted, +/area/exodus/engineering/drone_fabrication) +"bwF" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bwG" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "hop_office_desk"; + name = "Desk Privacy Shutter"; + pixel_x = 16; + pixel_y = 28 + }, +/obj/machinery/button/windowtint{ + pixel_x = 16; + pixel_y = 38 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bwI" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bwJ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"bwK" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bwL" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bwM" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bwN" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/atmos_control) +"bwO" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/atmos_control) +"bwP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/atmos_control) +"bwQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload) +"bwR" = ( +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/camera/network/command{ + c_tag = "Bridge - Captain's Quarters"; + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bwS" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bwT" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Fore Starboard Corridor" + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bwU" = ( +/obj/structure/table/laminate, +/obj/item/box/matches, +/obj/item/clothing/mask/smokable/cigarette/cigar, +/obj/item/chems/drinks/flask{ + pixel_x = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bwV" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bwW" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bwX" = ( +/obj/structure/closet/secure_closet/medical1, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bwY" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = 32 + }, +/obj/effect/floor_decal/corner/paleblue/three_quarters{ + dir = 4 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/reception) +"bwZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bxa" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/closet/secure_closet/chemical, +/obj/item/box/pillbottles, +/obj/item/radio/headset/headset_med, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Drug Storage" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bxb" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bxc" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/atmos_control) +"bxd" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bxe" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/medical{ + id_tag = "MedbayFoyerPort" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bxf" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Medbay Reception" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay3) +"bxg" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bxh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/medical{ + id_tag = "MedbayFoyerStar" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bxi" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hop) +"bxj" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hop) +"bxk" = ( +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hop) +"bxl" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"bxm" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bxn" = ( +/obj/structure/table/laminate, +/obj/item/camera, +/obj/item/photo_album{ + pixel_y = -10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/crew_quarters/captain) +"bxo" = ( +/obj/machinery/light, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"bxp" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bxq" = ( +/obj/machinery/photocopier, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bxr" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/turret_protected/ai_upload) +"bxs" = ( +/obj/structure/table, +/obj/item/stack/package_wrap, +/obj/item/hand_labeler, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/beige/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bxt" = ( +/obj/structure/table, +/obj/item/chems/glass/bottle/sedatives{ + pixel_x = -6; + pixel_y = 10 + }, +/obj/item/chems/glass/bottle/antitoxin{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/item/chems/glass/bottle/stabilizer{ + pixel_x = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/random/medical, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/item/chems/spray/antiseptic, +/obj/item/chems/spray/cleaner{ + pixel_x = -5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bxu" = ( +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/effect/floor_decal/corner/black/three_quarters, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bxv" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/black{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bxw" = ( +/obj/machinery/vending/medical, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bxx" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"bxy" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bxz" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bxA" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/fabricator/bioprinter, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bxB" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/structure/table, +/obj/item/box/bodybags{ + pixel_x = -1; + pixel_y = -2 + }, +/obj/item/pen, +/obj/machinery/camera/network/research{ + c_tag = "Research - Robotics - Operational Room"; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bxC" = ( +/turf/wall/prepainted, +/area/exodus/medical/medbay) +"bxD" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"bxE" = ( +/obj/structure/table, +/obj/item/firstaid/empty, +/obj/item/firstaid/empty, +/obj/item/firstaid/empty, +/obj/item/scanner/health, +/obj/item/scanner/health, +/obj/item/scanner/health, +/obj/machinery/newscaster{ + pixel_x = 26; + pixel_y = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bxF" = ( +/turf/wall/prepainted, +/area/exodus/medical/medbay3) +"bxG" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics Maintenance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/atmos_control) +"bxH" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"bxI" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/ladder, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bxJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bxK" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"bxL" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/item/paper_bin, +/obj/item/pen, +/turf/floor/tiled/white, +/area/exodus/research) +"bxM" = ( +/obj/machinery/network/requests_console{ + department = "Science"; + name = "Science Requests Console"; + pixel_y = 32; + dir = 1 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/stack/material/pane/mapped/glass{ + amount = 50; + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/shiny/mapped/aluminium, +/obj/item/clothing/glasses/welding, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bxN" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_monitoring) +"bxO" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/research) +"bxP" = ( +/obj/machinery/vending/coffee{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/dark, +/area/exodus/research) +"bxQ" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"bxR" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/obj/effect/floor_decal/industrial/warning/cee{ + dir = 1; + icon_state = "warningcee" + }, +/turf/floor/plating, +/area/exodus/quartermaster/storage) +"bxS" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bxT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bxU" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bxV" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bxW" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bxX" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bxY" = ( +/obj/machinery/fabricator, +/obj/machinery/light_switch{ + pixel_x = -27; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bxZ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bya" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"byb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"byc" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"byd" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "xenobio5"; + name = "Containment Blast Doors"; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bye" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/button/access/interior{ + id_tag = "arrivals_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = 25 + }, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"byf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"byg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"byh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"byi" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"byj" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"byk" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"byl" = ( +/obj/machinery/computer/modular/preset/medical, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bym" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"byn" = ( +/obj/effect/overmap/visitable/ship/landable/pod/research, +/obj/machinery/computer/ship/helm{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"byo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/highsecurity{ + name = "AI Upload" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/turret_protected/ai_upload) +"byp" = ( +/obj/machinery/door/airlock/command{ + id_tag = "hopdoor"; + name = "Head of Personnel" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/hop) +"byq" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"byr" = ( +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bys" = ( +/obj/machinery/turretid/stun{ + control_area = "\improper AI Upload Chamber"; + name = "AI Upload turret control"; + pixel_x = 6; + pixel_y = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_x = -12; + pixel_y = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload_foyer) +"byt" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"byu" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"byv" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"byw" = ( +/obj/structure/cryofeed, +/turf/floor/tiled/white/monotile, +/area/exodus/security/prison/dorm) +"byx" = ( +/obj/machinery/button/alternate/door{ + desc = "A remote control switch for the medbay foyer."; + id_tag = "MedbayFoyerPort"; + name = "Medbay Doors Control"; + pixel_x = -24; + pixel_y = 26 + }, +/obj/machinery/computer/guestpass{ + pixel_x = -28 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"byy" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/network/relay, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"byz" = ( +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"byA" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/engi_shuttle) +"byB" = ( +/obj/structure/closet/secure_closet/medical3, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"byC" = ( +/obj/structure/closet/secure_closet/medical3, +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"byD" = ( +/obj/machinery/button/alternate/door{ + desc = "A remote control switch for the medbay foyer."; + id_tag = "MedbayFoyerStar"; + name = "Medbay Doors Control"; + pixel_x = 24; + pixel_y = 26 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byF" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"byG" = ( +/obj/machinery/portable_atmospherics/powered/scrubber/huge, +/obj/structure/sign/warning/nosmoking_2{ + pixel_x = 28 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/storage) +"byH" = ( +/obj/machinery/hologram/holopad, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hop) +"byI" = ( +/mob/living/simple_animal/corgi/Ian, +/turf/floor/carpet, +/area/exodus/crew_quarters/heads/hop) +"byJ" = ( +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byL" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byN" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/teleporter) +"byO" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byP" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/structure/mirror{ + pixel_x = 30 + }, +/obj/random/soap, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"byQ" = ( +/obj/structure/disposalpipe/junction{ + dir = 4; + icon_state = "pipe-j2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byR" = ( +/obj/structure/disposalpipe/junction{ + dir = 4; + icon_state = "pipe-j2" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byS" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/structure/sign/warning/high_voltage{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"byT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"byU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"byV" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"byW" = ( +/obj/machinery/light/small, +/obj/structure/mopbucket, +/obj/item/mop, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/turf/floor/tiled/freezer, +/area/exodus/security/prison/restroom) +"byX" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"byY" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/machinery/light, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"byZ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/research/chargebay) +"bza" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bzb" = ( +/obj/machinery/portable_atmospherics/powered/scrubber/huge, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/window/borosilicate_reinforced{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/research/mixing) +"bzc" = ( +/obj/structure/table, +/obj/item/flash/synthetic, +/obj/item/flash/synthetic, +/obj/item/flash/synthetic, +/obj/item/flash/synthetic, +/obj/item/flash/synthetic, +/obj/item/flash/synthetic, +/obj/item/organ/internal/brain/robotic, +/obj/item/robotanalyzer, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bzd" = ( +/obj/machinery/camera/network/security{ + c_tag = "Engineering Airlock Access"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "eng_eva_pump" + }, +/obj/machinery/light/small, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"bze" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bzf" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/corner/black/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bzg" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bzh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/research) +"bzi" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bzj" = ( +/obj/machinery/design_database{ + id_tag = "science" + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bzl" = ( +/obj/effect/floor_decal/industrial/warning/cee, +/turf/floor/plating, +/area/exodus/quartermaster/storage) +"bzm" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/conveyor_switch/oneway{ + id_tag = "QMLoad2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzn" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzo" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzq" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzr" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzs" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzt" = ( +/obj/machinery/navbeacon/HOP, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bzu" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bzv" = ( +/obj/machinery/network/requests_console{ + department = "Cargo Bay"; + pixel_x = -32; + dir = 8 + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Office"; + dir = 4 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/stack/material/pane/mapped/glass/fifty{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/multitool, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bzw" = ( +/obj/structure/filing_cabinet, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bzx" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bzy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bzz" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"bzA" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/structure/table, +/obj/item/firstaid/surgery, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bzB" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bzC" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bzD" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bzE" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 4 + }, +/obj/structure/window/borosilicate_reinforced{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bzF" = ( +/obj/machinery/portable_atmospherics/canister, +/obj/effect/floor_decal/corner/purple/three_quarters, +/obj/structure/window/borosilicate_reinforced{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bzG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bzH" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bzI" = ( +/obj/item/clothing/glasses/welding/superior, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/obj/structure/closet/secure_closet/research_director, +/obj/item/paper/monitorkey, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bzJ" = ( +/obj/structure/closet/secure_closet/hop, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bzK" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_bay_door"; + name = "Cargo Docking Hatch" + }, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bzL" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/item/stack/material/ore/coal{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/stack/material/ore/iron, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bzM" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/structure/sign/warning/lethal_turrets{ + pixel_x = 32 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_server_room) +"bzN" = ( +/obj/machinery/apc/critical{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/catwalk, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"bzO" = ( +/obj/machinery/computer/shuttle_control/explore/research{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"bzP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload_foyer) +"bzQ" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/teleport/hub, +/turf/floor/tiled/dark/monotile, +/area/exodus/teleporter) +"bzR" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload_foyer) +"bzS" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/structure/sign/warning/lethal_turrets{ + pixel_x = -32 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_cyborg_station) +"bzT" = ( +/obj/structure/closet/secure_closet/psychiatry, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"bzU" = ( +/obj/machinery/computer/teleporter, +/turf/floor/tiled/dark/monotile, +/area/exodus/teleporter) +"bzV" = ( +/obj/structure/rack, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/turf/floor/tiled/dark/monotile, +/area/exodus/teleporter) +"bzW" = ( +/obj/structure/table, +/obj/item/box/beakers, +/obj/item/box/syringes{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/syringes, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bzX" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bzY" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bAa" = ( +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bAb" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bAc" = ( +/obj/structure/table, +/obj/item/firstaid/fire{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/random/firstaid, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bAd" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/matter_bin, +/obj/item/stock_parts/matter_bin, +/obj/item/stock_parts/capacitor, +/obj/item/stock_parts/capacitor, +/turf/floor/plating, +/area/exodus/storage/tech) +"bAe" = ( +/obj/structure/table, +/obj/item/firstaid/toxin{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/random/firstaid{ + pixel_y = 1 + }, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bAf" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bAg" = ( +/obj/structure/table, +/obj/item/firstaid/o2{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/random/firstaid, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bAh" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/turret_protected/ai_server_room) +"bAi" = ( +/obj/machinery/computer/shuttle_control/research{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bAj" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/turret_protected/ai_cyborg_station) +"bAk" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bAl" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 1; + name = "Medbay"; + sort_type = "Medbay" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bAm" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bAn" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bAo" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Medical Equipment" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bAp" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Medbay Storage" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bAq" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bAr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Medical Equipment" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bAs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Medbay Substation" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/medical) +"bAt" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bAu" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAv" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAw" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/mauve{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAx" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/mauve{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAy" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/mauve{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAz" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/mauve{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAA" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_x = -5; + pixel_y = -22 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 6; + pixel_y = -29 + }, +/obj/effect/floor_decal/corner/mauve{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAB" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAC" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/mauve{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAD" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bAE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"bAF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green, +/obj/machinery/power_sensor{ + id_tag = "Medbay Subgrid"; + name = "Powernet Sensor - Medbay Subgrid" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"bAG" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bAH" = ( +/obj/structure/morgue, +/obj/effect/floor_decal/corner/paleblue{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bAI" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/machinery/optable{ + name = "Robotics Operating Table" + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bAJ" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bAK" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/machinery/computer/operating{ + dir = 1; + name = "Robotics Operating Computer" + }, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"bAM" = ( +/obj/machinery/light, +/obj/structure/table, +/obj/item/paper_bin, +/obj/item/pen, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bAN" = ( +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Roboticist" + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bAO" = ( +/obj/structure/table, +/obj/item/crowbar, +/obj/item/radio/headset/headset_sci{ + pixel_x = -3 + }, +/obj/item/multitool{ + pixel_x = 3 + }, +/obj/item/multitool{ + pixel_x = 3 + }, +/obj/item/clothing/glasses/welding, +/obj/item/clothing/glasses/welding, +/obj/machinery/light_switch{ + pixel_x = 25; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bAP" = ( +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "EngineBlast"; + name = "EngineBlast" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"bAQ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"bAR" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bAS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bAT" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bAU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bAV" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bAW" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bAX" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bAY" = ( +/obj/machinery/light, +/obj/structure/bed/padded, +/obj/item/bedsheet/orange, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"bAZ" = ( +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/obj/item/clothing/head/soft/orange, +/obj/item/clothing/shoes/sandal, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"bBa" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"bBb" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "EngineBlast"; + name = "Engine Monitoring Room Blast Doors" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"bBc" = ( +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/obj/item/chems/drinks/bottle/absinthe, +/obj/item/clothing/suit/apron/overalls, +/turf/floor/tiled/steel_grid, +/area/exodus/security/prison/dorm) +"bBd" = ( +/obj/machinery/door/airlock{ + name = "Starboard Emergency Storage" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/storage/emergency) +"bBe" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"bBf" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bBg" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bBh" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"bBi" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"bBj" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bBk" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bBl" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/lab) +"bBm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bBn" = ( +/obj/machinery/navbeacon/QM1, +/obj/structure/closet/secure_closet/cargotech, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bBo" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"bBp" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"bBq" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/item/folder/yellow, +/obj/item/eftpos{ + eftpos_name = "Cargo Bay EFTPOS scanner" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bBr" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/unary_atmos/heater, +/obj/item/stock_parts/circuitboard/unary_atmos/cooler{ + pixel_x = 3; + pixel_y = -3 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bBs" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bBt" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bBu" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_bay_door"; + name = "Cargo Docking Hatch" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bBv" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/mining{ + id_tag = "cargodoor"; + name = "Cargo Office" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/office) +"bBw" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bBx" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bBy" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bBz" = ( +/obj/structure/closet/secure_closet/hop2, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bBA" = ( +/obj/item/pen, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/item/megaphone, +/obj/structure/table/glass, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bBB" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/blue, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bBC" = ( +/obj/machinery/door/airlock/highsecurity{ + name = "AI Upload Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/turret_protected/ai_server_room) +"bBE" = ( +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_server_room) +"bBF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/obj/machinery/camera/network/command{ + c_tag = "AI - Upload Foyer"; + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/light, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload_foyer) +"bBG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload_foyer) +"bBH" = ( +/obj/machinery/door/airlock/highsecurity{ + name = "AI Upload Access" + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/turret_protected/ai_cyborg_station) +"bBI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_upload_foyer) +"bBJ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/maintenance{ + name = "Medbay Substation" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/medical) +"bBK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/cyan{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_cyborg_station) +"bBM" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/item/stool, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bBN" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/item/radio/beacon, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bBO" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bBP" = ( +/obj/machinery/network/message_server, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_server_room) +"bBQ" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/obj/machinery/shieldwallgen, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bBR" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/command{ + name = "Teleport Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/teleporter) +"bBS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bBT" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bBU" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bBV" = ( +/obj/machinery/computer/modular/telescreen/preset/generic, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bBW" = ( +/obj/structure/table, +/obj/item/roller{ + pixel_y = 1 + }, +/obj/item/roller{ + pixel_y = 8 + }, +/obj/item/roller{ + pixel_y = 16 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bBX" = ( +/obj/structure/closet/wardrobe/chemistry_white, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"bBY" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bBZ" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bCa" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bCb" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bCc" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bCd" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bCe" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + id_tag = "GeneticsDoor"; + name = "Cloning Laboratory" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bCf" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/glass/medical{ + id_tag = "GeneticsDoor"; + name = "Genetics Laboratory" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bCg" = ( +/obj/machinery/ai_status_display{ + pixel_x = 32 + }, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bCh" = ( +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bCi" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/research) +"bCj" = ( +/turf/floor/tiled/white, +/area/exodus/research) +"bCk" = ( +/obj/effect/floor_decal/corner/purple, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/exodus/research) +"bCl" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "researchlockdown"; + name = "researchlockdown" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 28 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"bCm" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bCn" = ( +/obj/machinery/navbeacon/QM2, +/obj/structure/closet/secure_closet/cargotech, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bCo" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"bCp" = ( +/turf/wall/prepainted, +/area/exodus/medical/genetics) +"bCq" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "xenobio6"; + name = "Containment Blast Doors"; + pixel_y = 4 + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for a door to space."; + id_tag = "xenobioout6"; + name = "Containment Release Switch"; + pixel_x = 24; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bCr" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"bCs" = ( +/obj/structure/table, +/obj/machinery/faxmachine/mapped, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bCt" = ( +/obj/machinery/light_switch{ + pixel_x = -23; + pixel_y = -23; + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bCu" = ( +/obj/abstract/landmark/start{ + name = "Assistant" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"bCv" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bCw" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bCx" = ( +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Mining Dock"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bCy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bCz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/table/steel_reinforced, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"bCA" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 8; + name = "QM Office"; + sort_type = "QM Office" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bCB" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bCC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bCD" = ( +/obj/machinery/shipsensors/weak, +/obj/structure/cable/green, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"bCE" = ( +/obj/effect/floor_decal/industrial/warning/cee{ + dir = 1; + icon_state = "warningcee" + }, +/turf/floor/plating, +/area/exodus/quartermaster/storage) +"bCF" = ( +/obj/item/stack/material/pane/mapped/glass{ + amount = 50 + }, +/obj/item/stack/material/pane/mapped/glass{ + amount = 50 + }, +/obj/item/stack/material/pane/mapped/glass{ + amount = 50 + }, +/obj/structure/table/steel_reinforced, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"bCG" = ( +/obj/machinery/conveyor_switch/oneway{ + convdir = -1; + id_tag = "QMLoad" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bCH" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bCI" = ( +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_server_room) +"bCJ" = ( +/turf/wall/prepainted, +/area/exodus/research/docking) +"bCK" = ( +/obj/machinery/computer/message_monitor, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_server_room) +"bCL" = ( +/obj/machinery/navbeacon/Research, +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research) +"bCM" = ( +/obj/machinery/recycler, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bCN" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bCO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_server_room) +"bCP" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bCQ" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bCR" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Head of Personnel" + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "hop_office_desk"; + name = "Desk Privacy Shutter"; + pixel_x = 26; + pixel_y = 17 + }, +/obj/machinery/button/windowtint{ + pixel_x = 36; + pixel_y = 18 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the office door."; + id_tag = "hopdoor"; + name = "Office Door Control"; + pixel_x = 26; + pixel_y = -17 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bCS" = ( +/obj/machinery/keycard_auth{ + dir = 4 + }, +/obj/machinery/computer/account_database{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bCT" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bCU" = ( +/obj/item/folder/blue, +/obj/item/stamp/denied, +/obj/item/eftpos{ + eftpos_name = "HoP EFTPOS scanner" + }, +/obj/structure/table/glass, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bCV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_server_room) +"bCW" = ( +/obj/abstract/landmark/start{ + name = "Cyborg" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_cyborg_station) +"bCX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_server_room) +"bCY" = ( +/obj/abstract/landmark/start{ + name = "Cyborg" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_cyborg_station) +"bCZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_cyborg_station) +"bDa" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/item/wrench, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Cryogenics" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bDb" = ( +/obj/structure/closet/crate{ + name = "Camera Assembly Crate" + }, +/obj/item/frame/camera, +/obj/item/frame/camera, +/obj/item/frame/camera, +/obj/item/frame/camera, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_cyborg_station) +"bDc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bDd" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -27; + pixel_y = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bDe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bDg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bDh" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bDi" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/maintenance, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_port) +"bDj" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bDk" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bDl" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = 32 + }, +/obj/effect/floor_decal/corner/white, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bDm" = ( +/obj/machinery/door/window/eastright{ + dir = 1; + name = "Emergency Kit" + }, +/obj/machinery/door/firedoor, +/obj/item/toolbox/emergency, +/obj/item/bodybag/cryobag{ + pixel_x = 6 + }, +/obj/item/bodybag/cryobag{ + pixel_x = 6 + }, +/obj/item/bodybag/cryobag, +/obj/item/radio{ + name = "medbay emergency radio link" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bDn" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Medicine Storage" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bDo" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bDp" = ( +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bDq" = ( +/obj/structure/table, +/obj/item/clothing/suit/straight_jacket, +/obj/item/clothing/mask/muzzle, +/obj/machinery/light, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/item/flashlight/pen, +/obj/item/flashlight/pen, +/obj/item/flashlight/pen, +/obj/item/flashlight/pen, +/obj/item/flashlight/pen, +/obj/item/clothing/glasses/hud/health, +/obj/item/clothing/glasses/hud/health, +/obj/item/clothing/glasses/hud/health, +/obj/item/clothing/glasses/hud/health, +/obj/item/clothing/glasses/hud/health, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bDr" = ( +/obj/structure/rack, +/obj/item/belt/medical, +/obj/item/belt/medical, +/obj/item/belt/medical, +/obj/item/belt/medical, +/obj/item/belt/medical, +/obj/item/clothing/neck/stethoscope, +/obj/item/clothing/neck/stethoscope, +/obj/item/clothing/neck/stethoscope, +/obj/item/clothing/neck/stethoscope, +/obj/item/clothing/neck/stethoscope, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Equipment Storage"; + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bDs" = ( +/obj/structure/table, +/obj/machinery/light, +/obj/item/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/masks, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bDt" = ( +/turf/wall/prepainted, +/area/exodus/medical/sleeper) +"bDu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/storage/primary) +"bDw" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bDx" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Primary Tool Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/port) +"bDz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bDA" = ( +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bDB" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bDC" = ( +/obj/structure/closet/wardrobe/medic_white, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bDD" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bDE" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bDF" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = -32 + }, +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Research"; + sort_type = "Research" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bDG" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bDH" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/ore_box, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bDI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bDJ" = ( +/turf/wall/prepainted, +/area/exodus/medical/cryo) +"bDK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bDL" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bDM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Division West" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bDN" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bDO" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bDP" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/command{ + name = "Server Room" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bDQ" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "research_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/exodus_pod_research) +"bDR" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bDS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bDT" = ( +/turf/floor/bluegrid, +/area/exodus/research/server) +"bDU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/research) +"bDV" = ( +/obj/machinery/light, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bDW" = ( +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bDX" = ( +/obj/item/stack/material/pane/mapped/glass{ + amount = 20; + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/item/stack/material/sheet/mapped/steel{ + amount = 50 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"bDY" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bDZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/sign/warning/server_room{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/research/server) +"bEa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bEb" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/borgupload{ + pixel_x = -1; + pixel_y = 1 + }, +/obj/item/stock_parts/circuitboard/aiupload{ + pixel_x = 2; + pixel_y = -2 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bEc" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bEd" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Shuttle Dock"; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bEe" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bEf" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/obj/effect/floor_decal/industrial/warning/cee, +/turf/floor/plating, +/area/exodus/quartermaster/storage) +"bEg" = ( +/obj/structure/filing_cabinet/chestdrawer, +/obj/machinery/light{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bEh" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/obj/machinery/status_display/supply_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bEi" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bEj" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bEk" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bEl" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Bay South"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bEm" = ( +/obj/machinery/navbeacon/QM3, +/obj/effect/floor_decal/industrial/outline/yellow, +/mob/living/bot/mulebot{ + suffix = "#1" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bEn" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/research_shuttle) +"bEp" = ( +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/computer/guestpass{ + pixel_y = -28 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/brown, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bEq" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bEr" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/turret_protected/ai_upload_foyer) +"bEs" = ( +/obj/structure/noticeboard{ + default_pixel_y = -27 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bEt" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"bEu" = ( +/obj/machinery/atm{ + pixel_x = -28; + dir = 4 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bEv" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bEw" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bEx" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bEy" = ( +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Head of Personnel's Desk"; + name = "Head of Personnel RC"; + pixel_y = -32 + }, +/obj/machinery/camera/network/command{ + c_tag = "Bridge - HoP's Office"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bEz" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bEA" = ( +/obj/machinery/faxmachine/mapped, +/obj/structure/table/glass, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bEB" = ( +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bEC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light_switch{ + pixel_x = 24; + pixel_y = -8 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_server_room) +"bED" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light_switch{ + pixel_x = -24; + pixel_y = -8 + }, +/turf/floor/tiled/dark, +/area/exodus/turret_protected/ai_cyborg_station) +"bEE" = ( +/obj/structure/table, +/obj/abstract/prefab/hand_teleporter, +/obj/machinery/light, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bEF" = ( +/obj/structure/table, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bEG" = ( +/obj/machinery/camera/network/command{ + c_tag = "Bridge - Teleporter"; + dir = 1 + }, +/obj/structure/closet/crate, +/obj/item/crowbar, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bEH" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/table, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"bEI" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"bEJ" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 8; + id_tag = "medbayquar"; + name = "Medbay Emergency Quarantine Shutters" + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bEK" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bEL" = ( +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bEM" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bEN" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bEO" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Emergency Entrance" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bEP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bEQ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bER" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bES" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Medical Equipment" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay3) +"bET" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bEU" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Mining Maintenance" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/miningdock) +"bEV" = ( +/obj/structure/table, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bEW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bEX" = ( +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bEY" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bEZ" = ( +/obj/machinery/apc/high{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bFa" = ( +/obj/structure/sign/warning/nosmoking_2{ + pixel_x = -32 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Toxins Lab"; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bFb" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_bay_door"; + name = "Cargo Docking Hatch" + }, +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/storage) +"bFc" = ( +/obj/machinery/recharge_station, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_cyborg_station) +"bFd" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bFe" = ( +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/frame/apc, +/obj/structure/table, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bFf" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/table, +/obj/item/frame/camera, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bFg" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "RD Office"; + sort_type = "RD Office" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bFh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Genetics Research" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/genetics) +"bFi" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bFj" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/research{ + name = "Research Division Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"bFk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bFl" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bFm" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bFn" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bFo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 1 + }, +/obj/machinery/ai_status_display{ + pixel_y = -32 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bFp" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bFq" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bFr" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_shuttle) +"bFs" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research) +"bFt" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/white, +/area/exodus/research) +"bFu" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bFw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bFx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bFy" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_shuttle) +"bFz" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bFA" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Port - West"; + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bFB" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bFC" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bFD" = ( +/turf/floor/plating, +/area/exodus/medical/genetics) +"bFE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bFF" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bFG" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bFH" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Toxins Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/storage) +"bFI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bFJ" = ( +/obj/machinery/airlock_sensor{ + id_tag = "tox_airlock_sensor"; + pixel_y = 24 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bFK" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bFL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bFM" = ( +/obj/machinery/network/relay, +/turf/floor/laminate/walnut, +/area/exodus/library) +"bFN" = ( +/obj/structure/disposalpipe/sortjunction/untagged{ + dir = 1 + }, +/obj/machinery/network/relay, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bFO" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bFP" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/storage/emergency) +"bFQ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Xenobiology Research" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology) +"bFR" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bFS" = ( +/obj/machinery/door/window/southright{ + name = "Toxins Launcher" + }, +/obj/machinery/door/window/southright{ + dir = 1; + name = "Toxins Launcher" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/research/mixing) +"bFT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bFU" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 4 + }, +/obj/machinery/network/relay, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bFV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bFW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bFX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/research/mixing) +"bFY" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "research_dock_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/docking) +"bFZ" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/mining{ + id_tag = "cargodoor"; + name = "Mining Dock" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/miningdock) +"bGa" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/hor) +"bGb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bGc" = ( +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bGd" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/starboard) +"bGe" = ( +/obj/structure/filing_cabinet, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bGf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/engineering{ + dir = 1 + }, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bGg" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "tox_airlock_control"; + pixel_x = -24; + tag_airpump = "tox_airlock_pump"; + tag_chamber_sensor = "tox_airlock_sensor"; + tag_exterior_door = "tox_airlock_exterior"; + tag_interior_door = "tox_airlock_interior"; + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/tvalve/bypass{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bGh" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 4; + name = "Primary Tool Storage"; + sort_type = "Primary Tool Storage" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGj" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGl" = ( +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGm" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGn" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGo" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"bGp" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"bGq" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bGr" = ( +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bGs" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bGt" = ( +/turf/wall/prepainted, +/area/exodus/quartermaster/miningdock) +"bGu" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - Southwest"; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime, +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bGv" = ( +/turf/wall/prepainted, +/area/exodus/quartermaster/qm) +"bGw" = ( +/obj/machinery/door/airlock/highsecurity{ + name = "Messaging Server" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/turret_protected/ai_server_room) +"bGx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/highsecurity{ + name = "Cyborg Station" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/turret_protected/ai_cyborg_station) +"bGy" = ( +/obj/machinery/door/airlock/double/glass/medical{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bGz" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bGA" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bGB" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/sign/warning/docking_area{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"bGC" = ( +/obj/machinery/camera/network/command{ + c_tag = "AI - Messaging Server"; + dir = 1 + }, +/obj/machinery/light/small, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_server_room) +"bGD" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bGE" = ( +/obj/machinery/recharge_station, +/obj/machinery/camera/network/command{ + c_tag = "AI - Cyborg Station"; + dir = 1 + }, +/obj/machinery/light/small, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_cyborg_station) +"bGF" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bGG" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 1; + name = "Chemistry"; + sort_type = "Chemistry" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bGI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bGJ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bGK" = ( +/obj/structure/disposalpipe/segment, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bGL" = ( +/obj/structure/noticeboard{ + default_pixel_y = 28 + }, +/obj/machinery/hologram/holopad, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bGM" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/network/requests_console{ + department = "Medbay"; + name = "Medbay RC"; + pixel_y = 32; + dir = 1 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bGN" = ( +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bGO" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bGP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bGQ" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bGR" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bGS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bGT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bGU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bGV" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + id_tag = "GeneticsDoor"; + name = "Cloning Laboratory" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/cryo) +"bGW" = ( +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bGX" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bGY" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + id_tag = "GeneticsDoor"; + name = "Genetics Laboratory" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/genetics) +"bGZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bHa" = ( +/obj/item/frame/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bHb" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bHc" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bHd" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bHe" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "tox_airlock_pump" + }, +/obj/machinery/air_sensor{ + id_tag = "toxins_mixing_interior"; + pixel_x = -8; + pixel_y = -18 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bHf" = ( +/obj/machinery/botany/editor, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bHg" = ( +/obj/machinery/navbeacon/QM4, +/obj/effect/floor_decal/industrial/outline/yellow, +/mob/living/bot/mulebot{ + suffix = "#1" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"bHh" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"bHi" = ( +/obj/machinery/network/relay, +/turf/floor/plating, +/area/exodus/maintenance/library) +"bHj" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Patient A"; + dir = 8 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bHk" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/research) +"bHl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai) +"bHm" = ( +/turf/wall/prepainted, +/area/exodus/research) +"bHn" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bHo" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bHp" = ( +/obj/machinery/door/airlock/research{ + name = "Research Division Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"bHq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bHr" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology/xenoflora) +"bHs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bHt" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_4_berth_hatch"; + name = "Escape Pod" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/cargo) +"bHu" = ( +/obj/machinery/door/airlock/glass/research{ + autoclose = 0; + id_tag = "tox_airlock_exterior"; + locked = 1; + name = "Mixing Room Exterior Airlock" + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bHv" = ( +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bHw" = ( +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bHx" = ( +/obj/machinery/airlock_sensor{ + id_tag = "research_dock_sensor"; + pixel_y = -25; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "research_dock_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/docking) +"bHy" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Shuttle Dock Maintainance" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bHz" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 8; + id_tag = "research_dock_airlock"; + pixel_x = 25; + tag_airpump = "research_dock_pump"; + tag_chamber_sensor = "research_dock_sensor"; + tag_exterior_door = "research_dock_outer"; + tag_interior_door = "research_dock_inner" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/docking) +"bHA" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/apc/critical{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bHB" = ( +/obj/machinery/material_processing/unloader, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bHC" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/obj/item/belt/utility, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bHD" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bHE" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bHF" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bHG" = ( +/obj/machinery/camera/network/research{ + c_tag = "Research - Miscellaneous Test Chamber"; + preset_channels = list("Research","Miscellaneous Reseach") + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bHH" = ( +/obj/structure/chair/office/dark, +/obj/abstract/landmark/start{ + name = "Quartermaster" + }, +/obj/machinery/button/windowtint{ + pixel_x = 24; + pixel_y = -24 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the office door."; + id_tag = "qmdoor"; + name = "office door control"; + pixel_x = 15; + pixel_y = -25 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the cargo doors."; + id_tag = "cargodoor"; + name = "cargo door control"; + pixel_x = 15; + pixel_y = -34 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bHI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bHJ" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/captain) +"bHK" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHL" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHM" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"bHN" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHO" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/central_three) +"bHP" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"bHQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHR" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - South Southwest" + }, +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHT" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHU" = ( +/obj/machinery/ai_status_display{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHV" = ( +/obj/structure/chair/office/light, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bHW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHX" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bHY" = ( +/obj/machinery/disposal, +/obj/structure/sign/warning/airlock{ + pixel_x = -32; + dir = 4 + }, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bHZ" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - South Southeast" + }, +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bIa" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology) +"bIb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bIc" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bId" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = 28 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bIe" = ( +/obj/machinery/atm{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bIf" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Central - Southeast" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bIg" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bIh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "acute1"; + name = "EMT Storage Privacy Shutters" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bIi" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "acute1"; + name = "EMT Storage Privacy Shutters" + }, +/obj/machinery/light_switch{ + pixel_x = 22; + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bIj" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/paleblue, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bIk" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + pixel_y = 11 + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bIl" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bIm" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bIn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bIo" = ( +/obj/structure/sign/plaque/golden{ + desc = "Done No Harm."; + name = "Best Doctor 2552"; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Equipment Storage Hallway"; + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bIp" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bIq" = ( +/obj/machinery/door/airlock/research{ + name = "Research Shuttle Dock" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/docking) +"bIr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay3) +"bIs" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod_berth{ + id_tag = "escape_pod_4_berth"; + pixel_x = -25; + pixel_y = 25; + tag_door = "escape_pod_4_berth_hatch" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bIt" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bIu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bIv" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bIw" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/research_port) +"bIx" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/server) +"bIy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bIz" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bIA" = ( +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/machinery/light_switch{ + pixel_y = 24 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bIB" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bIC" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/sleeper{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/cryo) +"bID" = ( +/obj/item/shard{ + icon_state = "small" + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bIE" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/apc/critical{ + name = "south bump"; + pixel_y = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"bIG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/item/shard{ + icon_state = "medium" + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bIH" = ( +/obj/structure/chair/office/dark, +/obj/abstract/landmark/start{ + name = "Geneticist" + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bII" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bIJ" = ( +/turf/wall/prepainted, +/area/exodus/research/storage) +"bIK" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = 32 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bIL" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bIM" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/nitrogen, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"bIN" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bIO" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bIP" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bIQ" = ( +/obj/structure/sign/warning/docking_area{ + dir = 4; + pixel_x = -32 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/hallway/secondary/entry/aft) +"bIR" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/robotics{ + pixel_x = -2; + pixel_y = 2 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bIS" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bIT" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bIU" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/computer/modular/preset/medical{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/reception) +"bIV" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"bIW" = ( +/obj/item/screwdriver{ + pixel_y = 16 + }, +/obj/item/wirecutters, +/obj/structure/table/steel, +/obj/item/crowbar/brace_jack, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bIX" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bIY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bIZ" = ( +/obj/effect/floor_decal/corner/brown/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bJa" = ( +/obj/item/folder/yellow, +/obj/structure/table, +/obj/item/pen, +/obj/machinery/network/requests_console{ + department = "Cargo Bay"; + pixel_x = -32; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bJb" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bJc" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/tool/pickaxe{ + pixel_x = 5 + }, +/obj/item/tool/shovel{ + pixel_x = -5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bJd" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bJe" = ( +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/megaphone, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/table{ + name = "plastic table frame" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bJf" = ( +/obj/item/clipboard, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/stamp/denied, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bJg" = ( +/obj/item/folder/yellow, +/obj/item/pen{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/pen/red{ + pixel_x = 2; + pixel_y = 6 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/eftpos{ + eftpos_name = "Quartermaster EFTPOS scanner" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bJh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bJi" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo - Quartermaster's Office"; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bJj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/meter, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bJk" = ( +/obj/machinery/navbeacon/QM, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJm" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJn" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJo" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJp" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJq" = ( +/obj/structure/disposalpipe/junction, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJr" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJs" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJt" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJu" = ( +/obj/machinery/navbeacon/AIW, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJv" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJw" = ( +/obj/machinery/navbeacon/AIE, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bJz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bJA" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bJB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bJC" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bJD" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bJE" = ( +/obj/structure/sign/warning/secure_area{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bJF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_port) +"bJG" = ( +/obj/machinery/navbeacon/CHE, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bJH" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bJI" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bJJ" = ( +/obj/structure/table, +/obj/item/defibrillator/loaded, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bJK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/research{ + name = "Robotics Lab" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/robotics) +"bJL" = ( +/obj/machinery/button/blast_door{ + id_tag = "acute1"; + name = "EMT Storage Privacy Shutters"; + pixel_x = 26; + pixel_y = 25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bJM" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bJN" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bJO" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/command{ + id_tag = "cmodoor"; + name = "CMO's Office" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/cmo) +"bJP" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bJQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bJR" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bJS" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bJT" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/obj/structure/bed/roller, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bJU" = ( +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/obj/structure/bed/roller, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bJV" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/light, +/obj/machinery/vending/medical{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/cryo) +"bJW" = ( +/obj/machinery/constructable_frame/machine_frame, +/obj/item/shard{ + icon_state = "small" + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bJX" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/machinery/constructable_frame/machine_frame, +/obj/item/shard, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bJY" = ( +/obj/machinery/light, +/obj/machinery/constructable_frame/computerframe, +/obj/item/shard{ + icon_state = "medium" + }, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"bJZ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/light_switch{ + pixel_x = -6; + pixel_y = 26 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/hydroponics{ + closed_system = 1; + name = "isolation tray" + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora) +"bKa" = ( +/obj/machinery/alarm/server{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bKb" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/westleft{ + name = "Server Room"; + opacity = 1 + }, +/obj/machinery/door/window/eastleft{ + name = "Server Room" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/server) +"bKc" = ( +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bKe" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/sign/warning/server_room{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/research/server) +"bKf" = ( +/obj/item/frame/light, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bKg" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/cargo) +"bKh" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_port) +"bKi" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bKj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bKk" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bKl" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bKm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bKn" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bKo" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/storage) +"bKp" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bKq" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bKr" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bKs" = ( +/turf/wall/prepainted, +/area/exodus/research/test_area) +"bKt" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/test_area) +"bKu" = ( +/obj/structure/sign/warning/bomb_range, +/turf/wall/r_wall/prepainted, +/area/exodus/research/test_area) +"bKv" = ( +/obj/machinery/vending/snack, +/turf/floor/tiled/white, +/area/exodus/research) +"bKw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bKx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/machinery/network/relay, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"bKy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bKz" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bKB" = ( +/obj/machinery/door/airlock/research{ + name = "Xenoflora Research" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology/xenoflora) +"bKC" = ( +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_cyborg_station) +"bKD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bKE" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"bKF" = ( +/obj/structure/window/reinforced/full, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bKG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/engineering/engineering_monitoring) +"bKH" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "cargo_mining_conveyor" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bKI" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bKK" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bKL" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bKN" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bKO" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bKP" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bKQ" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/brown/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKR" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKS" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKT" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bKV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table, +/obj/item/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/masks, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bKW" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bKX" = ( +/obj/machinery/light, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKY" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bKZ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bLa" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/telecomms_hub, +/turf/floor/plating, +/area/exodus/storage/tech) +"bLb" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bLc" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/sign/directions/evac{ + dir = 4; + pixel_y = -32; + pixel_z = 8 + }, +/obj/structure/sign/directions/medical{ + dir = 4; + pixel_y = -32 + }, +/obj/structure/sign/directions/engineering{ + pixel_y = -32; + pixel_z = -8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bLd" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bLe" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bLf" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/aft) +"bLg" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 8; + name = "Janitor Closet"; + sort_type = "Janitor Closet" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"bLi" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bLj" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"bLk" = ( +/obj/effect/floor_decal/corner/purple, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bLl" = ( +/obj/machinery/atmospherics/unary/temperature/freezer{ + icon_state = "freezer" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"bLm" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bLn" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engineering_monitoring) +"bLo" = ( +/turf/wall/prepainted, +/area/exodus/medical/genetics/cloning) +"bLp" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bLq" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/machinery/constructable_frame/machine_frame, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bLr" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"bLs" = ( +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bLt" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "EMT Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bLu" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bLv" = ( +/obj/machinery/atmospherics/unary/temperature/heater{ + icon_state = "heater" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"bLw" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bLx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bLy" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bLz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bLA" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/filing_cabinet/chestdrawer{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bLB" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bLC" = ( +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bLD" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/photocopier, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bLE" = ( +/obj/machinery/constructable_frame/computerframe, +/obj/item/shard{ + icon_state = "medium" + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bLF" = ( +/obj/item/shard, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bLG" = ( +/obj/structure/window/reinforced, +/obj/machinery/constructable_frame/computerframe, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bLH" = ( +/obj/machinery/network/relay, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"bLI" = ( +/obj/machinery/atmospherics/valve, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bLJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/medical{ + autoclose = 0; + id_tag = "virology_airlock_interior"; + locked = 1; + name = "Virology Interior Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology) +"bLK" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bLL" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bLM" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "eng_eva_airlock"; + name = "Engineering Airlock Console"; + pixel_y = 25; + tag_airpump = "eng_eva_pump"; + tag_chamber_sensor = "eng_eva_sensor"; + tag_exterior_door = "eng_eva_outer"; + tag_interior_door = "eng_eva_inner" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"bLN" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_shuttle) +"bLO" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/light, +/obj/machinery/button/blast_door{ + id_tag = "Biohazard"; + name = "Biohazard Shutter Control"; + pixel_x = 8; + pixel_y = -24 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = -7; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bLP" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bLQ" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bLR" = ( +/obj/abstract/landmark/start{ + name = "Paramedic" + }, +/obj/item/stool/padded, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bLS" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bLT" = ( +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"bLU" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bLV" = ( +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/keycard_auth, +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bLW" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bLX" = ( +/obj/machinery/material_processing/smeltery, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bLY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bLZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bMa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bMb" = ( +/obj/structure/table, +/obj/item/taperecorder{ + pixel_x = -3 + }, +/obj/item/paicard{ + pixel_x = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/obj/item/stock_parts/circuitboard/teleporter, +/obj/item/stock_parts/circuitboard/aicore{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bMc" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bMd" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"bMe" = ( +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bMf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bMg" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bMh" = ( +/obj/machinery/material_processing/stacker{ + input_turf = 1; + output_turf = 8 + }, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bMi" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Shaft Miner" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bMj" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bMk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bMl" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bMm" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/light_switch{ + pixel_x = -24; + pixel_y = -24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bMn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/mining{ + id_tag = "qmdoor"; + name = "Quartermaster" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/qm) +"bMo" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bMp" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bMq" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bMr" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bMs" = ( +/obj/machinery/light/small{ + dir = 4; + pixel_y = 8 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 8; + id_tag = "mining_dock_airlock"; + pixel_x = 25; + pixel_y = -5; + tag_airpump = "mining_dock_pump"; + tag_chamber_sensor = "mining_dock_sensor"; + tag_exterior_door = "mining_dock_outer"; + tag_interior_door = "mining_dock_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "mining_dock_sensor"; + pixel_x = 25; + pixel_y = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor, +/area/exodus/quartermaster/miningdock) +"bMt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bMu" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bMv" = ( +/obj/machinery/door/airlock{ + name = "Custodial Closet" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"bMw" = ( +/obj/machinery/vending/cigarette{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/central_two) +"bMx" = ( +/obj/structure/closet/secure_closet/medical1, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/flashlight, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/random/medical, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/item/stack/tape_roll/barricade_tape/medical, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bMy" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bMz" = ( +/obj/machinery/button/blast_door{ + id_tag = "acutesep"; + name = "Acute Separation Shutters"; + pixel_y = -25; + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Paramedic" + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay EMT Storage"; + dir = 1 + }, +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bMA" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/fireaxecabinet{ + pixel_x = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bMB" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Starboard Corridor"; + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bMC" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/faxmachine/mapped, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bMD" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bME" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall/prepainted, +/area/exodus/medical/medbay2) +"bMF" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/closet/secure_closet/cmo, +/obj/item/clothing/mask/gas, +/obj/item/clothing/neck/stethoscope, +/obj/item/belt/medical, +/obj/item/clothing/glasses/hud/health, +/obj/item/flashlight/pen, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bMG" = ( +/obj/structure/disposalpipe/junction{ + dir = 2; + icon_state = "pipe-j2" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/light_switch{ + pixel_x = 22; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bMH" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/engineering{ + name = "Engineering Monitoring Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engineering_monitoring) +"bMI" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/wall/prepainted, +/area/exodus/engineering/sublevel_access) +"bMJ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/button/blast_door{ + id_tag = "staffroom"; + name = "Staff Room Shutters Control"; + pixel_x = -26; + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bMK" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/medbreak) +"bML" = ( +/obj/machinery/washing_machine, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Break Room" + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bMM" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bMN" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eng_eva_inner"; + name = "Engineering EVA Internal Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/atmos_control) +"bMO" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/misc_lab) +"bMP" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/library) +"bMQ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/bookcase/manuals/medical, +/obj/item/book/fluff/stasis, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bMR" = ( +/obj/structure/noticeboard{ + default_pixel_y = 28 + }, +/obj/item/book/manual/medical_diagnostics_manual{ + pixel_y = 7 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bMS" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bMT" = ( +/obj/item/shard{ + icon_state = "medium" + }, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bMU" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bMV" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/mixing) +"bMW" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bMX" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Toxins Storage"; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bMY" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/storage) +"bMZ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/camera/network/research{ + c_tag = "Research Division Central"; + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bNa" = ( +/obj/structure/mirror{ + pixel_y = 32 + }, +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"bNb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bNc" = ( +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bNd" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bNe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bNf" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bNg" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "mining_dock_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/floor, +/area/exodus/quartermaster/miningdock) +"bNh" = ( +/obj/structure/chair/office/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bNi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bNj" = ( +/obj/machinery/door/airlock/external{ + name = "Toxins Test Chamber" + }, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"bNk" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"bNl" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/passive_gate/on, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bNm" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Toxins Test Chamber North"; + preset_channels = list("Research","Toxins Test Area") + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bNn" = ( +/obj/machinery/computer/message_monitor{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/research/server) +"bNp" = ( +/obj/structure/mirror{ + pixel_y = 32 + }, +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"bNq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"bNr" = ( +/obj/effect/paint_stripe/brown, +/turf/wall/titanium, +/area/ship/exodus_pod_mining) +"bNs" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bNt" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bNu" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"bNv" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bNw" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bNx" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/cargo) +"bNy" = ( +/turf/wall/prepainted, +/area/exodus/storage/tech) +"bNz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/papershredder, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bNB" = ( +/obj/machinery/shipsensors/weak, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor, +/area/ship/exodus_pod_mining) +"bNC" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/stationalert{ + pixel_x = 1; + pixel_y = -1 + }, +/obj/item/stock_parts/circuitboard/atmos_alert{ + pixel_x = 3; + pixel_y = -3 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bND" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/stock_parts/circuitboard/acl, +/obj/item/stock_parts/circuitboard/relay, +/obj/item/stock_parts/circuitboard/router, +/turf/floor/plating, +/area/exodus/storage/tech) +"bNE" = ( +/obj/machinery/vending/assist, +/turf/floor/plating, +/area/exodus/storage/tech) +"bNF" = ( +/turf/wall/prepainted, +/area/exodus/hallway/primary/aft) +"bNG" = ( +/obj/structure/table, +/obj/machinery/faxmachine/mapped, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bNH" = ( +/obj/structure/closet/secure_closet/quartermaster, +/obj/item/coin/silver{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/coin/silver, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bNI" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/network/requests_console{ + department = "Cargo Bay"; + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"bNJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bNK" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bNL" = ( +/obj/structure/closet/l3closet/janitor, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNM" = ( +/obj/structure/closet/jcloset, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNN" = ( +/obj/machinery/newscaster{ + pixel_y = 30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNO" = ( +/obj/item/box/lights/mixed, +/obj/item/box/lights/mixed, +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/camera/network/security{ + c_tag = "Custodial Closet" + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bNQ" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_three) +"bNR" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNS" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bNT" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bNU" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/engineering) +"bNV" = ( +/obj/item/frame/camera, +/turf/floor/plating, +/area/exodus/medical/genetics) +"bNW" = ( +/obj/machinery/door/window/westright{ + name = "Janitoral Delivery" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNX" = ( +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bNY" = ( +/obj/machinery/navbeacon/Janitor, +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/janitor) +"bNZ" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "acutesep"; + name = "Acute Separation Shutters" + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bOa" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bOb" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_two) +"bOc" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bOd" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/command{ + name = "CMO's Office" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/cmo) +"bOe" = ( +/obj/structure/chair, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bOf" = ( +/obj/structure/chair, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bOg" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/command{ + name = "CMO's Office" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/cmo) +"bOh" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bOi" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bOj" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bOk" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/obj/machinery/light_switch{ + pixel_x = -22; + pixel_y = -22 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bOl" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/medical{ + name = "Staff Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay2) +"bOm" = ( +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bOn" = ( +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bOo" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Aft Starboard Access"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bOp" = ( +/obj/structure/sign/warning/fire{ + pixel_x = 32 + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bOq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bOr" = ( +/obj/machinery/portable_atmospherics/canister, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bOs" = ( +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bOt" = ( +/obj/machinery/portable_atmospherics/canister, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bOu" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 1 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOv" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOw" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bOx" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bOy" = ( +/obj/structure/table, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bOz" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bOA" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bOB" = ( +/obj/machinery/portable_atmospherics/canister/sleeping_agent, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/storage) +"bOC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bOD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/meter, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bOE" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bOF" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bOG" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/structure/closet/secure_closet/scientist, +/obj/item/tank/air, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOH" = ( +/obj/structure/closet/bombcloset, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOI" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Starboard - Central West" + }, +/obj/effect/floor_decal/corner/white{ + dir = 1 + }, +/obj/structure/noticeboard{ + default_pixel_y = 27 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bOJ" = ( +/obj/machinery/portable_atmospherics/canister, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOK" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/megaphone, +/obj/item/stamp/rd, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bOL" = ( +/obj/item/flashlight{ + pixel_x = 1; + pixel_y = 5 + }, +/obj/item/flashlight{ + pixel_x = 1; + pixel_y = 5 + }, +/obj/item/flash, +/obj/item/flash, +/obj/machinery/ai_status_display{ + pixel_x = -32 + }, +/obj/structure/table/steel, +/turf/floor/plating, +/area/exodus/storage/tech) +"bOM" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/camera/network/security{ + c_tag = "Engineering - Technical Storage" + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bON" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bOO" = ( +/turf/wall/prepainted, +/area/exodus/research/mixing) +"bOP" = ( +/obj/structure/sign/warning/bomb_range, +/turf/wall/prepainted, +/area/exodus/research/test_area) +"bOQ" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOR" = ( +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bOS" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor, +/area/exodus/construction) +"bOT" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/sleeper{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/cryo) +"bOU" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_south = 6; + tag_west = 2; + use_power = 0 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOV" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOW" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/omni/mixer{ + tag_east = 1; + tag_east_con = 0.5; + tag_south = 1; + tag_south_con = 0.5; + tag_west = 2; + use_power = 0 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bOX" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bOY" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bOZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bPa" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bPb" = ( +/obj/machinery/button/access/interior{ + id_tag = "mining_dock_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = 25 + }, +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bPc" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bPd" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology/access) +"bPe" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor, +/area/exodus/construction) +"bPf" = ( +/turf/floor/plating, +/area/exodus/storage/tech) +"bPg" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bPh" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/plating, +/area/exodus/storage/tech) +"bPi" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bPj" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bPk" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"bPl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"bPm" = ( +/obj/structure/disposalpipe/segment, +/obj/abstract/landmark/start{ + name = "Shaft Miner" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bPn" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bPo" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/aft) +"bPp" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/aft) +"bPq" = ( +/obj/machinery/door/airlock/glass{ + name = "Central Access" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/aft) +"bPr" = ( +/obj/item/stool, +/obj/abstract/landmark/start{ + name = "Janitor" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPs" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPt" = ( +/turf/wall/prepainted, +/area/exodus/janitor) +"bPu" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPv" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPw" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Patient Room B"; + dir = 8 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bPx" = ( +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bPy" = ( +/obj/machinery/door/airlock/engineering{ + name = "Aft Starboard Solar Access" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/starboardsolar) +"bPz" = ( +/obj/item/chems/glass/bucket, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPA" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPB" = ( +/obj/structure/mopbucket, +/obj/item/mop, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bPC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bPD" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/button/blast_door{ + id_tag = "acutesep"; + name = "Acute Separation Shutters"; + pixel_y = 25 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Acute" + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bPE" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/machinery/door/airlock/medical{ + autoclose = 0; + name = "Acute Treatment" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bPF" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -9 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Port Corridor"; + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bPG" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + pixel_y = -9 + }, +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Chief Medical Officer's Desk"; + name = "Chief Medical Officer RC"; + pixel_x = -32; + dir = 8 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay - CMO's Office"; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bPH" = ( +/obj/item/radio{ + name = "medbay emergency radio link" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bPI" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/item/megaphone, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bPJ" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/computer/modular/preset/medical, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bPK" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/newscaster{ + pixel_x = 30; + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bPL" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bPM" = ( +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bPN" = ( +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bPO" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bPP" = ( +/obj/machinery/recharger, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bPQ" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 8 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bPR" = ( +/obj/abstract/landmark/start{ + name = "Geneticist" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bPS" = ( +/obj/machinery/sparker{ + id_tag = "Xenobio"; + pixel_x = -25 + }, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bPT" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bPU" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 4; + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bPV" = ( +/obj/structure/table, +/obj/item/stack/cable_coil, +/obj/item/multitool, +/obj/machinery/cell_charger, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bPW" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"bPX" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark, +/area/exodus/research/storage) +"bPY" = ( +/obj/structure/sign/warning/fire{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 4 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bPZ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_shuttle) +"bQa" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Monitoring Room"; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bQb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQc" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8; + name = "Waste to Scrubbers" + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQe" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"bQf" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQg" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold4w/visible, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQh" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQi" = ( +/obj/machinery/network/requests_console{ + department = "Science"; + name = "Science Requests Console"; + pixel_x = 32; + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQj" = ( +/obj/item/stock_parts/circuitboard/apc, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/structure/table/steel, +/turf/floor/plating, +/area/exodus/storage/tech) +"bQk" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bQl" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bQm" = ( +/obj/machinery/button/mass_driver{ + id_tag = "toxinsdriver"; + pixel_y = 24 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Toxins Launch Room" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bQn" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bQo" = ( +/obj/machinery/button/blast_door{ + id_tag = "mixvent"; + name = "Mixing Room Vent Control"; + pixel_x = -25; + pixel_y = 5 + }, +/obj/machinery/button/ignition{ + id_tag = "mixingsparker"; + pixel_x = -25; + pixel_y = -5 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/machinery/atmospherics/valve{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bQp" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Firefighting equipment" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engineering) +"bQq" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bQr" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bQs" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bQt" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bQu" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"bQv" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bQw" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 8; + name = "HoP Office"; + sort_type = "HoP Office" + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bQx" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bQy" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology/access) +"bQz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"bQB" = ( +/obj/machinery/cell_charger{ + pixel_y = 5 + }, +/obj/item/multitool, +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/obj/structure/table/steel, +/obj/item/scanner/plant, +/turf/floor/plating, +/area/exodus/storage/tech) +"bQD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bQE" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/toolbox/electrical{ + pixel_x = 1; + pixel_y = -1 + }, +/obj/item/clothing/gloves/insulated, +/obj/item/t_scanner, +/obj/item/clothing/glasses/meson, +/obj/item/multitool, +/turf/floor/plating, +/area/exodus/storage/tech) +"bQF" = ( +/obj/structure/table, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/yellow/full, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bQG" = ( +/obj/effect/floor_decal/corner/grey/diagonal, +/obj/machinery/computer/modular/preset/medical{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bQH" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bQI" = ( +/obj/machinery/camera/network/security{ + c_tag = "Engineering - Secure Technical Storage" + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bQJ" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/computer/tesla_link, +/obj/item/stock_parts/computer/network_card/advanced, +/obj/item/stock_parts/computer/nano_printer, +/obj/item/stock_parts/computer/hard_drive, +/obj/item/stock_parts/computer/card_slot, +/obj/item/stock_parts/computer/hard_drive/portable, +/obj/item/stock_parts/computer/processor_unit, +/obj/item/stock_parts/computer/ai_slot, +/turf/floor/plating, +/area/exodus/storage/tech) +"bQK" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bQL" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bQM" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bQN" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bQO" = ( +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/machinery/network/requests_console{ + department = "Janitorial"; + pixel_y = -32 + }, +/obj/item/chems/spray/cleaner, +/obj/structure/table/steel, +/obj/item/chems/spray/antiseptic, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQP" = ( +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/structure/table/steel, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQQ" = ( +/obj/structure/janitorialcart, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQR" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bQT" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bQU" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bQV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQW" = ( +/obj/item/box/mousetraps, +/obj/item/box/mousetraps, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQX" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/janitor) +"bQY" = ( +/obj/structure/bed/roller, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22; + pixel_y = -32 + }, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/structure/closet/secure_closet/medical_wall{ + name = "O- Blood Locker"; + pixel_x = -32; + dir = 4 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bQZ" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Emergency Recovery" + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bRa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bRb" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "acute2"; + name = "Acute Privacy Shutters" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay) +"bRc" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Chief Medical Officer" + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "cmooffice"; + name = "CMO Privacy Shutters"; + pixel_x = 38; + pixel_y = 21 + }, +/obj/machinery/button/blast_door{ + desc = "A remote control switch for the CMO's office."; + id_tag = "cmodoor"; + name = "CMO Office Door Control"; + pixel_x = 28; + pixel_y = 21 + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "virologyquar"; + name = "Virology Emergency Lockdown Control"; + pixel_x = -15; + pixel_y = 38 + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "medbayquar"; + name = "Medbay Emergency Lockdown Control"; + pixel_x = -15; + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/keycard_auth{ + pixel_x = 16; + pixel_y = 24 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bRd" = ( +/mob/living/simple_animal/passive/cat/fluff/runtime, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bRe" = ( +/obj/item/folder/cyan{ + pixel_y = 10 + }, +/obj/item/clipboard, +/obj/item/paper_bin, +/obj/item/pen, +/obj/item/stamp/cmo, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bRf" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bRg" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/closet/secure_closet/personal/patient, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bRh" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table, +/obj/item/clipboard, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = 36 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/button/windowtint{ + id_tag = "isoA_window_tint"; + pixel_y = 26 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bRi" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bRj" = ( +/turf/wall/prepainted, +/area/exodus/medical/patient_a) +"bRk" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/closet/secure_closet/personal/patient, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bRl" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table, +/obj/item/clipboard, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = 36 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/button/windowtint{ + id_tag = "isoB_window_tint"; + pixel_y = 26 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bRm" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bRn" = ( +/turf/wall/prepainted, +/area/exodus/medical/patient_b) +"bRo" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bRp" = ( +/obj/structure/table, +/obj/item/assembly/igniter, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bRq" = ( +/obj/machinery/door/window/eastright{ + name = "Engineering Delivery" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"bRr" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/tiled/dark, +/area/exodus/research/storage) +"bRs" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bRt" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bRu" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRv" = ( +/obj/machinery/computer/atmos_alert{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bRw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRx" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 4; + name = "Heater to Waste" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRA" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 1; + name = "Heated to Waste" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bRD" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bRH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bRI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bRJ" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bRK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bRL" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"bRM" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bRN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bRO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bRP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bRQ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bRR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bRS" = ( +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bRT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bRV" = ( +/obj/structure/closet/secure_closet/miner, +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/obj/item/rig/industrial/equipped, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"bRW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bRX" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bRY" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bRZ" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bSa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bSb" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bSc" = ( +/obj/machinery/door/airlock/engineering{ + name = "Tech Storage" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/aft) +"bSd" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bSe" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bSf" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Primary Hallway Aft"; + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bSg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bSh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bSi" = ( +/obj/machinery/papershredder, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bSj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bSk" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bSl" = ( +/obj/item/aicard, +/obj/item/aiModule/reset, +/obj/structure/table/steel, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bSm" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bSn" = ( +/obj/machinery/button/blast_door{ + id_tag = "scanhide"; + name = "Diagnostics Room Separation Shutters"; + pixel_x = -6; + pixel_y = -25 + }, +/obj/machinery/button/blast_door{ + id_tag = "acute2"; + name = "Acute Treatment Privacy Shutters"; + pixel_x = 6; + pixel_y = -25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"bSo" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay) +"bSp" = ( +/obj/machinery/port_gen/pacman{ + sheets = 25 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"bSq" = ( +/obj/machinery/light, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bSr" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bSs" = ( +/obj/abstract/landmark/start{ + name = "Chemist" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey/diagonal, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bSt" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Atmospheric Technician" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bSu" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay2) +"bSv" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/light, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bSw" = ( +/obj/machinery/hologram/holopad, +/obj/effect/floor_decal/corner/grey/diagonal, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bSx" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/abstract/landmark/start{ + name = "Chemist" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/grey/diagonal, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bSy" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Examination Room" + }, +/obj/structure/chair/wheelchair, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bSz" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair/office/dark, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bSA" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair/office/dark, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bSB" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/obj/structure/curtain/open/privacy, +/obj/machinery/vending/wallmed1{ + pixel_x = 25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"bSC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bSD" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bSE" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Patient Room C"; + dir = 8 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 25 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"bSF" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/network/requests_console{ + department = "Tech storage"; + pixel_x = 32; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bSG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bSH" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bSI" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bSJ" = ( +/obj/structure/chair/comfy/teal{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bSK" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/closet/crate/solar, +/turf/floor/plating, +/area/exodus/engineering/storage) +"bSL" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/binary/pump{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bSN" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSO" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold4w/visible, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSP" = ( +/obj/machinery/atmospherics/pipe/manifold/visible, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSQ" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSS" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bST" = ( +/obj/structure/tank_rack, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSU" = ( +/turf/wall/prepainted, +/area/exodus/engineering/break_room) +"bSV" = ( +/obj/item/wrench, +/obj/item/screwdriver{ + pixel_y = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bSW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bSX" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Toxins Launch Room Access"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bSY" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/plating, +/area/exodus/research/xenobiology/xenoflora) +"bSZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bTa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bTb" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/toolbox/electrical{ + pixel_x = 1; + pixel_y = -1 + }, +/obj/item/multitool, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/storage/tech) +"bTc" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bTd" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bTh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bTi" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/airlock_brace, +/obj/item/airlock_brace, +/obj/item/airlock_brace, +/turf/floor/plating, +/area/exodus/storage/tech) +"bTj" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bTk" = ( +/obj/machinery/door/airlock/glass/research{ + name = "Toxins Lab" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/mixing) +"bTl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/medical{ + name = "Hygiene Facilities" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bTm" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/obj/effect/engine_setup/pump_max, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"bTn" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bTo" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6; + icon_state = "warning" + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"bTp" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bTq" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bTs" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "scanhide"; + name = "Diagnostics Room Separation Shutters" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bTt" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/research) +"bTu" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "scanhide"; + name = "Diagnostics Room Separation Shutters" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bTw" = ( +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bTx" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 2; + id_tag = "scanhide"; + name = "Diagnostics Room Separation Shutters" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"bTy" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bTz" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bTA" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bTB" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/engine_setup/coolant_canister, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"bTC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bTD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bTE" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bTF" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bTG" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bTH" = ( +/obj/structure/table, +/obj/machinery/computer/modular/preset/medical{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink/three_quarters, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bTI" = ( +/obj/structure/iv_drip, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bTJ" = ( +/turf/wall/prepainted, +/area/exodus/medical/medbay4) +"bTK" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_a) +"bTL" = ( +/obj/structure/table, +/obj/machinery/computer/modular/preset/medical{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink/three_quarters, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bTM" = ( +/obj/structure/iv_drip, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bTN" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_b) +"bTO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bTP" = ( +/obj/machinery/shieldwallgen{ + anchored = 1 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bTQ" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bTR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bTS" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "misclab"; + name = "misclab" + }, +/obj/machinery/door/window/southright{ + name = "Test Chamber" + }, +/obj/machinery/door/window/southright{ + dir = 1; + name = "Test Chamber" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bTT" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bTU" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "misclab"; + name = "misclab" + }, +/obj/machinery/door/window/southleft{ + name = "Test Chamber" + }, +/obj/machinery/door/window/southleft{ + dir = 1; + name = "Test Chamber" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/reinforced, +/area/exodus/research/misc_lab) +"bTV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bTW" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bTX" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bTY" = ( +/obj/machinery/light_switch{ + pixel_y = -23; + dir = 1 + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/vending/cigarette{ + dir = 1; + pixel_y = 2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"bTZ" = ( +/obj/structure/shuttle/engine/propulsion/burst{ + dir = 4 + }, +/obj/effect/paint/red, +/turf/wall/titanium, +/area/shuttle/escape_pod_4) +"bUa" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 26 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bUb" = ( +/obj/structure/sign/plaque/golden{ + pixel_y = 32 + }, +/turf/floor/tiled/dark, +/area/exodus/crew_quarters/heads/hos) +"bUc" = ( +/obj/machinery/atmospherics/binary/passive_gate{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bUd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"bUe" = ( +/obj/structure/disposaloutlet, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating/airless, +/area/exodus/research/mixing) +"bUf" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bUg" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"bUh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bUi" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bUj" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bUk" = ( +/obj/machinery/material_processing/unloader, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bUl" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bUm" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bUn" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/research_starboard) +"bUo" = ( +/obj/machinery/door/airlock/highsecurity{ + name = "Secure Tech Storage" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/storage/tech) +"bUp" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bUq" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bUr" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"bUs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bUt" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bUu" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/shuttle/escape_pod_4) +"bUv" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/cargo) +"bUw" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bUx" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bUy" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bUz" = ( +/obj/machinery/button/blast_door{ + id_tag = "scanhide"; + name = "Diagnostics Room Separation Shutters"; + pixel_x = -6; + pixel_y = 25 + }, +/obj/machinery/atmospherics/unary/temperature/freezer{ + dir = 8; + icon_state = "freezer" + }, +/obj/machinery/button/blast_door{ + id_tag = "scanhideside"; + name = "Diagnostics Room Privacy Shutters"; + pixel_x = 6; + pixel_y = 25 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bUA" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Custodial Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/janitor) +"bUB" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"bUC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bUD" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUE" = ( +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUF" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Lounge" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUG" = ( +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bUH" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bUI" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bUJ" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bUK" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bUL" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"bUM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bUN" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/chair/comfy/teal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUP" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bUQ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUR" = ( +/obj/machinery/vending/coffee, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUS" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUU" = ( +/obj/machinery/vending/medical, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bUV" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bUW" = ( +/obj/item/chems/spray/cleaner, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bUX" = ( +/obj/machinery/vending/cigarette, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bUY" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod{ + dir = 1; + id_tag = "escape_pod_4"; + pixel_y = -25; + tag_door = "escape_pod_4_hatch" + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_4) +"bUZ" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/exodus/medical/exam_room) +"bVa" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/grey/diagonal, +/obj/structure/filing_cabinet, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/medbreak) +"bVb" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Sub-Acute A" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/patient_wing) +"bVc" = ( +/obj/structure/table/laminate, +/obj/item/dice, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bVd" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Sub-Acute B" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/patient_wing) +"bVe" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVf" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bVg" = ( +/obj/structure/table/reinforced, +/obj/item/wrench, +/obj/item/crowbar/red, +/obj/item/clothing/glasses/science, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVh" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/ignition{ + id_tag = "Xenobio"; + pixel_x = -6; + pixel_y = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVi" = ( +/turf/wall/prepainted, +/area/exodus/medical/patient_wing) +"bVj" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVk" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/hologram/holopad, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVl" = ( +/obj/structure/table/reinforced, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVm" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVn" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/rig/ce/equipped, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bVo" = ( +/obj/structure/rack, +/obj/item/rig/hazmat/equipped, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"bVp" = ( +/obj/machinery/vending/coffee, +/turf/floor/tiled/white, +/area/exodus/research) +"bVq" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bVr" = ( +/obj/structure/table, +/obj/item/box/animal_cubes/monkeys, +/obj/item/food/animal_cube/wrapped/monkey, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bVs" = ( +/obj/machinery/sparker{ + id_tag = "mixingsparker"; + pixel_x = 25 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 4; + icon_state = "map_injector"; + id_tag = "air_in"; + use_power = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bVt" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bVu" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/table/steel, +/obj/item/book/manual/supermatter_engine, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_airlock) +"bVv" = ( +/obj/structure/closet/radiation, +/obj/item/clothing/glasses/meson, +/obj/item/clothing/glasses/meson, +/obj/machinery/camera/network/engine{ + c_tag = "Engine Airlock" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_airlock) +"bVw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bVx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"bVy" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bVz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/airlock_sensor{ + pixel_y = -25; + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/research/mixing) +"bVA" = ( +/obj/machinery/mass_driver{ + dir = 4; + id_tag = "toxinsdriver" + }, +/turf/floor/plating/airless, +/area/exodus/research/mixing) +"bVB" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/door/window/brigdoor/westleft{ + name = "Engine Waste" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/engine_setup/empty_canister, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"bVC" = ( +/obj/structure/table/laminate, +/obj/item/book/manual/engineering_guide{ + pixel_x = 3; + pixel_y = 2 + }, +/obj/item/book/manual/atmospipes, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bVD" = ( +/obj/structure/table/laminate, +/obj/item/book/manual/engineering_construction, +/obj/item/book/manual/evaguide{ + pixel_x = -2; + pixel_y = 7 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bVE" = ( +/obj/structure/bookcase/manuals/engineering, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bVF" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bVG" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/exodus/research/mixing) +"bVH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bVI" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bVJ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Virology Access" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology/access) +"bVK" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bVL" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Toxins Test Chamber East"; + dir = 8; + preset_channels = list("Research","Toxins Test Area") + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bVM" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/light/small/emergency, +/obj/effect/shuttle_landmark/escape_pod/start/pod4, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_pod_4) +"bVN" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_pod_4_hatch"; + name = "Escape Pod Hatch" + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_pod_4) +"bVO" = ( +/obj/effect/paint_stripe/blue, +/turf/wall/titanium, +/area/shuttle/escape_pod_4) +"bVP" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"bVQ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/plating, +/area/exodus/engineering/storage) +"bVR" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bVS" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bVT" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bVU" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bVV" = ( +/obj/machinery/door/window/eastleft{ + name = "Medical Delivery" + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/medical/sleeper) +"bVW" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/storage/tech) +"bVX" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bVY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bVZ" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "toxin_test_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "toxin_test_sensor"; + pixel_y = 16 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/cee{ + dir = 8; + icon_state = "warningcee" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bWa" = ( +/obj/machinery/navbeacon/Medbay, +/obj/structure/flaps{ + opacity = 1 + }, +/turf/floor/plating, +/area/exodus/medical/sleeper) +"bWb" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bWc" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bWd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/hologram/holopad{ + holopad_id = "Emergency Scanning" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bWe" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bWf" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "scanhideside"; + name = "Diagnostics Room Privacy Shutters" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bWh" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWi" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWj" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWl" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWm" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWn" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/mixing) +"bWo" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "cargo_mining_conveyor" + }, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"bWp" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWq" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWs" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bWt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWu" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWw" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWx" = ( +/obj/structure/chair/comfy/teal, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWy" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWz" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/structure/table, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWA" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWB" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bWC" = ( +/obj/machinery/door/airlock/glass/research{ + name = "Toxins Lab" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/mixing) +"bWD" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bWE" = ( +/obj/machinery/button/blast_door{ + id_tag = "misclab"; + name = "Test Chamber Blast Doors"; + pixel_x = 6; + pixel_y = 30 + }, +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bWF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bWG" = ( +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bWH" = ( +/obj/structure/chair/office/light{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bWI" = ( +/obj/item/stack/cable_coil{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/stack/cable_coil, +/obj/structure/table/steel, +/obj/item/scanner/health, +/turf/floor/plating, +/area/exodus/storage/tech) +"bWJ" = ( +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"bWK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Miscellaneous Reseach Room" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bWL" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bWM" = ( +/obj/machinery/light, +/obj/machinery/computer/modular/preset/medical{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/cmo) +"bWN" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/sign/warning/compressed_gas{ + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bWO" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin, +/obj/item/clipboard, +/obj/item/folder/blue{ + pixel_x = -5; + pixel_y = 10 + }, +/obj/item/folder/cyan{ + pixel_x = 5; + pixel_y = 10 + }, +/obj/item/pen, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"bWP" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bWQ" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bWR" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bWS" = ( +/obj/machinery/air_sensor{ + id_tag = "toxins_mixing_exterior" + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bWT" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_airlock) +"bWU" = ( +/obj/machinery/door/airlock/glass/research{ + autoclose = 0; + id_tag = "tox_airlock_interior"; + locked = 1; + name = "Mixing Room Interior Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bWV" = ( +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/aft) +"bWW" = ( +/obj/structure/hygiene/shower{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_airlock) +"bWX" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/light_switch{ + pixel_x = -27; + dir = 4 + }, +/obj/machinery/airlock_sensor{ + id_tag = "engine_room_airlock"; + pixel_y = -22; + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_airlock) +"bWY" = ( +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bWZ" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_airlock) +"bXa" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"bXb" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/closet/bombcloset, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bXc" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + pixel_y = -10 + }, +/obj/machinery/computer/modular/telescreen/preset/generic{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bXd" = ( +/obj/machinery/computer/modular/preset/engineering, +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Chief Engineer's Desk"; + name = "Chief Engineer RC"; + pixel_y = 32; + dir = 1 + }, +/obj/machinery/newscaster{ + pixel_x = -28; + pixel_y = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bXe" = ( +/obj/structure/closet/wardrobe/engineering_yellow, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bXf" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Workshop"; + dir = 8 + }, +/obj/machinery/light_switch{ + pixel_x = 24; + pixel_y = -10 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"bXg" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/turf/floor/plating, +/area/exodus/engineering/storage) +"bXh" = ( +/obj/structure/closet/wardrobe/atmospherics_yellow, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bXi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/research/mixing) +"bXj" = ( +/turf/wall/prepainted, +/area/exodus/medical/patient_wing/washroom) +"bXk" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 1; + id_tag = "robotics_solar_airlock"; + pixel_y = -25; + tag_airpump = "robotics_solar_pump"; + tag_chamber_sensor = "robotics_solar_sensor"; + tag_exterior_door = "robotics_solar_outer"; + tag_interior_door = "robotics_solar_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "robotics_solar_sensor"; + pixel_x = 12; + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "robotics_solar_pump" + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"bXl" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bXm" = ( +/obj/effect/shuttle_landmark/supply/station, +/turf/space, +/area/space) +"bXn" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/research/mixing) +"bXo" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bXp" = ( +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bXq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_starboard) +"bXr" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"bXs" = ( +/obj/machinery/atmospherics/unary/tank/oxygen{ + gas_volume = 3200 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"bXt" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "scanhideside"; + name = "Diagnostics Room Privacy Shutters" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXu" = ( +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/structure/chair/comfy/brown, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"bXv" = ( +/obj/machinery/atmospherics/unary/tank/hydrogen{ + gas_volume = 3200 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"bXw" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bXy" = ( +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXz" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXA" = ( +/obj/machinery/newscaster{ + pixel_y = -32; + dir = 1 + }, +/obj/structure/disposalpipe/sortjunction{ + dir = 8; + name = "CMO Office"; + sort_type = "CMO Office" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXB" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"bXC" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXD" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/sign/department/cross/green{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXF" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXG" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXH" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Hallway Southwest"; + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bXI" = ( +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXL" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bXM" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXN" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXO" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXP" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXQ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXR" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXS" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bXT" = ( +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bXU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bXV" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bXW" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bXX" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bXY" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/substation/research) +"bXZ" = ( +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/floor/plating/airless, +/area/space) +"bYa" = ( +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bYb" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bYc" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/substation/research) +"bYd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bYe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bYf" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/research_port) +"bYg" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = -32 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"bYh" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bYi" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bYj" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/research{ + name = "Miscellaneous Reseach Room" + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bYk" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bYl" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bYm" = ( +/obj/machinery/light_switch{ + pixel_x = 7; + pixel_y = -23 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bYn" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bYo" = ( +/obj/machinery/light, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bYp" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research) +"bYq" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bYr" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Division South"; + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bYs" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research) +"bYt" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"bYu" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bYv" = ( +/obj/machinery/sparker{ + id_tag = "mixingsparker"; + pixel_x = 25 + }, +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 4; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bYw" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/turf/floor/reinforced, +/area/exodus/research/mixing) +"bYx" = ( +/obj/structure/table/laminate, +/obj/item/book/manual/supermatter_engine{ + pixel_x = -3 + }, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"bYy" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/disposalpipe/trunk, +/obj/machinery/disposal, +/obj/structure/sign/warning/deathsposal{ + pixel_y = 32 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"bYz" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"bYA" = ( +/obj/machinery/light, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"bYB" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bYC" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/closet/secure_closet/personal/patient, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bYD" = ( +/obj/machinery/door/airlock/medical{ + autoclose = 0; + id_tag = "virology_airlock_exterior"; + locked = 1; + name = "Virology Exterior Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "virology_airlock_control"; + name = "Virology Access Button"; + pixel_x = -24; + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology) +"bYE" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"bYF" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Hallway Southeast"; + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bYG" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/turf/floor/plating, +/area/exodus/engineering/storage) +"bYH" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bYI" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/crew_quarters/heads/chief) +"bYJ" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"bYK" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"bYL" = ( +/obj/structure/table/reinforced, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/light_switch{ + pixel_y = 27 + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bYM" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + name = "SMES Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_smes) +"bYN" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"bYO" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/papershredder, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bYP" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bYQ" = ( +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"bYR" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"bYS" = ( +/obj/machinery/atm{ + pixel_y = 28 + }, +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"bYT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"bYU" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"bYV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"bYW" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"bYX" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"bYY" = ( +/obj/machinery/door/airlock/engineering{ + name = "Engineering Supplies" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/break_room) +"bYZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bZa" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"bZb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_x = -20; + pixel_y = 22 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bZc" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_eva) +"bZd" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bZe" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/sleep/engi_wash) +"bZf" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/atmos_control) +"bZg" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/atmos_control) +"bZh" = ( +/obj/machinery/light_switch{ + pixel_y = 27 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"bZi" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bZj" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bZk" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bZl" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "scanhideside"; + name = "Diagnostics Room Privacy Shutters" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bZm" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bZn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"bZo" = ( +/obj/structure/disposalpipe/junction{ + dir = 1; + icon_state = "pipe-j2" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bZp" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"bZr" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/door/window/southleft{ + name = "Engineering Voidsuits" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/obj/item/clothing/suit/space/void/engineering/prepared, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"bZs" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Patient Ward" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay4) +"bZt" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + id_tag = "mentaldoor"; + name = "Mental Health" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/psych) +"bZu" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bZv" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Patient Hallway - Port"; + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bZx" = ( +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"bZy" = ( +/turf/wall/prepainted, +/area/exodus/medical/biostorage) +"bZA" = ( +/turf/wall/prepainted, +/area/exodus/medical/patient_c) +"bZB" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Secondary Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/biostorage) +"bZC" = ( +/obj/machinery/light_switch{ + pixel_x = 22; + pixel_y = -10; + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"bZD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"bZE" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Sub-Acute C" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/patient_c) +"bZF" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"bZG" = ( +/obj/structure/hygiene/toilet{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"bZH" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"bZI" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bZJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bZK" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bZL" = ( +/obj/machinery/disposal, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research - Miscellaneous"; + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bZM" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/closet/wardrobe/science_white, +/obj/structure/sign/warning/high_voltage{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bZN" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/light, +/obj/machinery/suit_cycler, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"bZO" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/bed/roller, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Scanning"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"bZP" = ( +/obj/effect/shuttle_landmark/escape_shuttle/station, +/turf/space, +/area/space) +"bZQ" = ( +/obj/structure/table/reinforced, +/obj/item/toolbox/electrical, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Drone Fabrication"; + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"bZR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"bZS" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bZT" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 8 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bZU" = ( +/obj/item/wrench, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"bZV" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window/southleft{ + name = "Engineering Voidsuits" + }, +/obj/item/clothing/suit/space/void/engineering/prepared, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"bZW" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"bZX" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"bZY" = ( +/obj/structure/table/reinforced, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"bZZ" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cab" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cac" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/box/lights/mixed, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cad" = ( +/obj/structure/table/reinforced, +/obj/item/folder/yellow, +/obj/item/stamp/ce, +/obj/item/pen, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/flame/fuelled/lighter/zippo, +/obj/item/megaphone, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cae" = ( +/obj/structure/chair/office/light{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Chief Engineer" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/button/windowtint{ + pixel_x = 36; + pixel_y = 18 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the office door."; + id_tag = "cedoor"; + name = "Office Door Control"; + pixel_x = 26; + pixel_y = 17 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"caf" = ( +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cag" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cah" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cai" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"caj" = ( +/obj/structure/table/laminate, +/obj/item/folder/yellow, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"cak" = ( +/obj/structure/table/laminate, +/obj/item/food/junk/chips, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"cal" = ( +/obj/machinery/newscaster{ + pixel_x = 28; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cam" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/command{ + id_tag = "cedoor"; + name = "Chief Engineer" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/chief) +"can" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cao" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cap" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"caq" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/sleep/engi_wash) +"car" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"cas" = ( +/obj/structure/disposalpipe/sortjunction{ + name = "CE Office"; + sort_type = "CE Office" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cat" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"cau" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"cav" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"caw" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/iv_drip, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"cax" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair/comfy/teal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cay" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/machinery/door/airlock/medical{ + autoclose = 0; + name = "Diagnostics Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay4) +"caz" = ( +/obj/machinery/apc/high{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"caA" = ( +/obj/machinery/door/airlock/medical{ + autoclose = 0; + id_tag = "virology_airlock_interior"; + locked = 1; + name = "Virology Interior Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology) +"caB" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"caC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"caD" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"caE" = ( +/turf/wall/prepainted, +/area/exodus/medical/ward) +"caF" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/laminate, +/area/exodus/medical/psych) +"caG" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate, +/area/exodus/medical/psych) +"caH" = ( +/obj/structure/table/laminate, +/obj/machinery/computer/modular/preset/medical, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/laminate, +/area/exodus/medical/psych) +"caI" = ( +/turf/wall/prepainted, +/area/exodus/medical/psych) +"caJ" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Miscellaneous Reseach Maintenance" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/research) +"caK" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"caL" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/obj/structure/sign/department/cross/green{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"caM" = ( +/obj/structure/iv_drip, +/obj/machinery/light_switch{ + pixel_x = 22; + dir = 8 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"caN" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"caO" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/structure/bed/roller, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"caP" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/machinery/vending/snack, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"caQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"caR" = ( +/obj/machinery/door/airlock/medical{ + autoclose = 0; + id_tag = "cubicle1"; + name = "Cubicle 1" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/patient_wing/washroom) +"caS" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"caT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/meter, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"caU" = ( +/obj/random/closet, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"caV" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"caW" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"caX" = ( +/obj/structure/table, +/obj/machinery/computer/modular/preset/medical, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"caY" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"caZ" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cba" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cbb" = ( +/obj/structure/iv_drip, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"cbc" = ( +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cbd" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"cbe" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cbf" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/structure/mirror{ + pixel_x = 32 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"cbg" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/meter, +/obj/machinery/button/blast_door{ + id_tag = "disvent"; + name = "Incinerator Vent Control"; + pixel_y = -24; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cbh" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"cbi" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Xenobiology Research" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research) +"cbj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cbk" = ( +/obj/abstract/landmark/start{ + name = "Atmospheric Technician" + }, +/obj/structure/chair/comfy/brown{ + dir = 8 + }, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"cbl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"cbm" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cbn" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Medbay Diagnostics Maintenance Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"cbo" = ( +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + id_tag = "xeno_airlock_control"; + name = "Xenobiology Access Console"; + pixel_x = 8; + pixel_y = 22; + tag_exterior_door = "xeno_airlock_exterior"; + tag_interior_door = "xeno_airlock_interior" + }, +/obj/machinery/light_switch{ + pixel_x = -6; + pixel_y = 26 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cbp" = ( +/obj/machinery/network/requests_console{ + department = "Science"; + name = "Science Requests Console"; + pixel_y = 32; + dir = 1 + }, +/obj/machinery/camera/network/research{ + c_tag = "Xenobiology North" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cbq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cbr" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"cbs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cbt" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cbu" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eng_eva_inner"; + name = "Engineering EVA Internal Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/atmos_control) +"cbv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"cbw" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/item/remains/robot, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cbx" = ( +/obj/structure/closet/secure_closet/engineering_chief, +/obj/item/tank/emergency/oxygen/engi, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cby" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cbz" = ( +/obj/machinery/keycard_auth{ + dir = 4 + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for engine core."; + id_tag = "EngineVent"; + name = "Engine Ventillatory Control"; + pixel_x = -24; + pixel_y = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/button/alternate/door/bolts{ + desc = "A remote control-switch for the engine core airlock hatch bolts."; + id_tag = "engine_access_hatch"; + name = "Engine Hatch Bolt Control"; + pixel_x = -24; + pixel_y = -10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cbA" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + name = "SMES Access" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_monitoring) +"cbB" = ( +/obj/structure/table/reinforced, +/obj/item/clipboard, +/obj/item/clothing/glasses/meson{ + pixel_y = 4 + }, +/obj/item/clothing/glasses/welding/superior, +/obj/item/box/fancy/cigarettes, +/obj/item/book/manual/supermatter_engine, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cbC" = ( +/obj/structure/table/reinforced, +/obj/machinery/faxmachine/mapped, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cbD" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/obj/machinery/door/window/southleft{ + name = "Engineering Voidsuits" + }, +/obj/item/clothing/suit/space/void/engineering/prepared, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cbE" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cbF" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cbG" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cbH" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/break_room) +"cbI" = ( +/turf/wall/prepainted, +/area/exodus/medical/surgeryobs) +"cbJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cbK" = ( +/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller{ + dir = 4; + id_tag = "engine_room_airlock"; + name = "Engine Room Airlock"; + pixel_x = -24; + tag_airpump = "engine_airlock_pump"; + tag_chamber_sensor = "eng_al_c_snsr"; + tag_exterior_door = "engine_airlock_exterior"; + tag_exterior_sensor = "eng_al_ext_snsr"; + tag_interior_door = "engine_airlock_interior"; + tag_interior_sensor = "eng_al_int_snsr" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"cbL" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cbM" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cbN" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"cbO" = ( +/obj/structure/lattice, +/obj/structure/grille/broken, +/turf/space, +/area/space) +"cbP" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/laminate, +/area/exodus/medical/psych) +"cbQ" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Surgery Access"; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"cbR" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/machinery/vending/wallmed1{ + pixel_x = -26 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/obj/structure/curtain/open/privacy, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cbS" = ( +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cbT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cbU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cbV" = ( +/obj/structure/bed/roller, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"cbW" = ( +/obj/structure/closet/crate{ + name = "Grenade Crate"; + opened = 1 + }, +/obj/item/grenade/chem_grenade, +/obj/item/grenade/chem_grenade, +/obj/item/grenade/chem_grenade, +/obj/item/grenade/chem_grenade, +/obj/item/assembly/igniter, +/obj/item/assembly/igniter, +/obj/item/assembly/igniter, +/obj/item/assembly/timer, +/obj/item/assembly/timer, +/obj/item/assembly/timer, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cbX" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cbY" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering - CE's Office"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cbZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cca" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"ccb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"ccc" = ( +/obj/structure/curtain/open/shower, +/obj/structure/hygiene/shower{ + dir = 4; + pixel_x = 5 + }, +/obj/machinery/door/window/southleft{ + dir = 4; + name = "shower door" + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"ccd" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"cce" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/obj/machinery/power_sensor{ + id_tag = "Research Subgrid"; + name = "Powernet Sensor - Research Subgrid" + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/research) +"ccf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"ccg" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/newscaster{ + pixel_x = 28; + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cch" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cci" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cck" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + id_tag = "engine_airlock_exterior"; + name = "Engine Airlock Exterior" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_airlock) +"ccl" = ( +/obj/machinery/door/airlock/medical{ + autoclose = 0; + id_tag = "virologyq_airlock_exterior"; + locked = 1; + name = "Virology Quarantine Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "virologyq_airlock_control"; + name = "Virology Quarantine Access Button"; + pixel_x = -24; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology) +"ccm" = ( +/obj/structure/closet/l3closet/virology, +/obj/item/clothing/mask/gas, +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + id_tag = "virology_airlock_control"; + name = "Virology Access Console"; + pixel_x = 8; + pixel_y = 22; + tag_exterior_door = "virology_airlock_exterior"; + tag_interior_door = "virology_airlock_interior" + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ccn" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"cco" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/noticeboard{ + default_pixel_y = 27 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "hop_office_desk"; + name = "HoP Office Privacy Shutters" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/machinery/door/window/brigdoor/eastright{ + name = "Head of Personnel's Desk" + }, +/obj/machinery/door/window/westleft{ + name = "Reception Window" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/hop) +"ccp" = ( +/obj/effect/paint/red, +/turf/wall/titanium, +/area/ship/exodus_pod_engineering) +"ccs" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Research" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/research) +"cct" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"ccu" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ccv" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/machinery/button/access/interior{ + id_tag = "toxin_test_airlock"; + name = "interior access button"; + pixel_x = 20; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ccw" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ccx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"ccy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ccz" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"ccA" = ( +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Research Substation Bypass" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/research) +"ccB" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/atmos_control) +"ccC" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"ccD" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"ccE" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ccF" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"ccG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/patient_wing/washroom) +"ccH" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"ccI" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"ccJ" = ( +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + id_tag = "virologyq_airlock_control"; + name = "Virology Quarantine Access Console"; + pixel_x = -8; + pixel_y = -22; + tag_exterior_door = "virologyq_airlock_exterior"; + tag_interior_door = "virologyq_airlock_interior" + }, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ccK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/command{ + name = "Chief Engineer" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/chief) +"ccL" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"ccM" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ccN" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/mining_drill, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"ccO" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"ccP" = ( +/turf/wall/prepainted, +/area/exodus/medical/virology/access) +"ccQ" = ( +/obj/machinery/shipsensors/weak, +/obj/structure/cable/green, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"ccR" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ccS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ccT" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ccU" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ccV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ccW" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Engineering Break Room"; + sort_type = "Engineering Break Room" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ccX" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/double/glass/engineering{ + dir = 4; + name = "Engineering Break Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/break_room) +"ccY" = ( +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/structure/table/steel, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"ccZ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Washroom" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/break_room) +"cda" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cdb" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_x = -20; + pixel_y = -21 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cdc" = ( +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cdd" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cde" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cdf" = ( +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cdg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cdh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cdi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Surgery Observation" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cdj" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Observation Room" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay4) +"cdk" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = 22 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cdl" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"cdm" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/medbay4) +"cdn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cdo" = ( +/obj/machinery/door/airlock/glass/medical{ + name = "Patient Ward" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay4) +"cdp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cdq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cdr" = ( +/obj/machinery/newscaster{ + pixel_x = 30; + dir = 4 + }, +/obj/machinery/computer/modular/preset/medical{ + dir = 8 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cds" = ( +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"cdt" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"cdu" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"cdv" = ( +/obj/structure/iv_drip, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"cdw" = ( +/obj/structure/table, +/obj/item/box/lights/mixed, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = 22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/item/toolbox/emergency, +/obj/item/flashlight, +/obj/item/flashlight, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cdx" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cdy" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cdz" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/closet/secure_closet/personal/patient, +/obj/effect/floor_decal/corner/pink/three_quarters, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"cdA" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table, +/obj/item/clipboard, +/obj/item/paper_bin, +/obj/item/pen, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -36; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/button/windowtint{ + id_tag = "isoC_window_tint"; + pixel_y = -26; + dir = 1 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"cdB" = ( +/obj/machinery/light, +/obj/machinery/newscaster{ + pixel_y = -28; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 10 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/medical/patient_c) +"cdC" = ( +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cdD" = ( +/obj/structure/flora/grass/brown, +/obj/structure/closet/crate/hydroponics/beekeeping, +/turf/floor/fake_grass, +/area/exodus/hydroponics/garden) +"cdE" = ( +/obj/structure/hygiene/shower{ + dir = 4; + pixel_x = 5; + pixel_y = -5 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cdF" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cdG" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/research) +"cdH" = ( +/obj/structure/cable/green, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/research) +"cdI" = ( +/obj/item/hand_labeler, +/obj/structure/table/glass, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cdJ" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -7; + pixel_y = 32 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/vending/wallmed1{ + pixel_x = 7; + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cdK" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/machinery/cooker/candy, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"cdL" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/xenobiology/xenoflora_storage) +"cdM" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/research) +"cdO" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/xenobiology) +"cdP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/sublevel_access) +"cdQ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cdR" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/light/small, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cdS" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/research/xenobiology/xenoflora) +"cdU" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/light/small, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/structure/sign/warning/secure_area{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cdW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/wall/prepainted, +/area/exodus/engineering) +"cdX" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cdY" = ( +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"cdZ" = ( +/obj/abstract/landmark/start{ + name = "Atmospheric Technician" + }, +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/turf/floor/carpet, +/area/exodus/engineering/break_room) +"cea" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/engineering) +"ceb" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Break Room"; + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cec" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"ced" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cee" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cef" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"ceg" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "toxin_test_airlock"; + pixel_y = 25; + tag_airpump = "toxin_test_pump"; + tag_chamber_sensor = "toxin_test_sensor"; + tag_exterior_door = "toxin_test_outer"; + tag_interior_door = "toxin_test_inner" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/cee{ + dir = 4; + icon_state = "warningcee" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ceh" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/door/window/northright{ + name = "Atmospherics Voidsuits" + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/clothing/suit/space/void/atmos/prepared, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cei" = ( +/obj/structure/table/laminate, +/turf/floor/laminate, +/area/exodus/medical/psych) +"cej" = ( +/turf/wall/prepainted, +/area/exodus/construction) +"cek" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cel" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/button/windowtint{ + pixel_x = -25; + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_x = -25; + pixel_y = 8 + }, +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for the office door."; + id_tag = "mentaldoor"; + name = "office door control"; + pixel_x = -34; + pixel_y = 7 + }, +/turf/floor/laminate, +/area/exodus/medical/psych) +"cem" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"cen" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ceo" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cep" = ( +/obj/random/tech_supply, +/obj/structure/table/steel, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor, +/area/exodus/construction) +"ceq" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"cer" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"ces" = ( +/obj/machinery/door/airlock/external{ + name = "Toxins Test Chamber" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"cet" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"ceu" = ( +/obj/machinery/light, +/obj/machinery/camera/network/research{ + c_tag = "Research - Toxins Test Chamber South"; + dir = 1; + preset_channels = list("Research","Toxins Test Area") + }, +/turf/floor/tiled/airless, +/area/exodus/research/test_area) +"cev" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"cew" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"cex" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "merchant_shuttle_station_vent" + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "merchant_shuttle_station_dock"; + pixel_y = 25; + tag_airpump = "merchant_shuttle_station_vent"; + tag_chamber_sensor = "merchant_shuttle_station_sensor"; + tag_exterior_door = "merchant_shuttle_station_exterior"; + tag_interior_door = "merchant_shuttle_station_interior" + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/airlock_sensor{ + id_tag = "merchant_shuttle_station_sensor"; + pixel_y = -32; + dir = 1 + }, +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/fore) +"cey" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"cez" = ( +/obj/machinery/smartfridge/secure/medbay, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"ceA" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ceB" = ( +/obj/structure/chair/office/dark, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"ceC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ceD" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"ceE" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"ceF" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"ceG" = ( +/obj/machinery/hologram/holopad, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"ceH" = ( +/obj/machinery/button/access/interior{ + id_tag = "merchant_shuttle_station_dock"; + name = "interior access button"; + pixel_x = -28; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"ceI" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "merchant_shuttle_station_interior"; + name = "Docking Port Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/fore) +"ceJ" = ( +/obj/structure/noticeboard{ + default_pixel_x = 32 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"ceK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"ceL" = ( +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"ceM" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"ceN" = ( +/obj/structure/hygiene/shower{ + dir = 4; + pixel_x = 5; + pixel_y = -5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ceO" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"ceP" = ( +/obj/structure/chair, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"ceQ" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/door/window/northleft{ + name = "Atmospherics Hardsuits" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/item/clothing/suit/space/void/atmos/prepared, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"ceR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/blue, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"ceS" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"ceT" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/machinery/holosign/surgery, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay4) +"ceU" = ( +/obj/machinery/door/firedoor, +/obj/machinery/holosign/surgery, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/double/glass/medical{ + id_tag = "Surgery"; + name = "Pre-Op Prep Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/medbay4) +"ceV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"ceW" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/structure/sign/double/barsign{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"ceX" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Mental Health Room"; + dir = 1 + }, +/obj/structure/filing_cabinet/chestdrawer{ + name = "Medical Forms" + }, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"ceY" = ( +/obj/machinery/vending/medical{ + dir = 8 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"ceZ" = ( +/obj/machinery/navbeacon/AftH, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cfa" = ( +/obj/structure/table, +/obj/item/box/cdeathalarm_kit, +/obj/item/bodybag/cryobag{ + pixel_x = -3 + }, +/obj/item/bodybag/cryobag{ + pixel_x = -3 + }, +/obj/item/stack/nanopaste, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cfb" = ( +/obj/structure/table, +/obj/item/box/glasses/square{ + pixel_x = 1; + pixel_y = 4 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"cfc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cfd" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/closet/secure_closet/scientist, +/turf/floor/tiled/white, +/area/exodus/research/misc_lab) +"cfe" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cff" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/closet/l3closet/scientist, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cfg" = ( +/obj/machinery/light/small, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/kitchen) +"cfh" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/closet/secure_closet/xenobio, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cfi" = ( +/obj/item/crowbar, +/obj/item/clothing/gloves/thick, +/obj/item/clothing/gloves/thick, +/obj/item/box/lights/mixed, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cfj" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/multitool{ + pixel_x = 5 + }, +/obj/item/clothing/gloves/insulated, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cfk" = ( +/obj/structure/closet/l3closet, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/suit/bio_suit/general, +/obj/item/clothing/suit/bio_suit/general, +/obj/item/clothing/suit/bio_suit/general, +/obj/item/clothing/head/bio_hood/general, +/obj/item/clothing/head/bio_hood/general, +/obj/item/clothing/head/bio_hood/general, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cfl" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"cfm" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/hydroponics{ + closed_system = 1; + name = "isolation tray" + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora) +"cfn" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"cfo" = ( +/obj/machinery/vending/hydronutrients{ + categories = 3 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cfp" = ( +/obj/machinery/seed_storage/xenobotany, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cfq" = ( +/obj/structure/closet/crate, +/obj/item/stock_parts/circuitboard/smes, +/obj/item/stock_parts/circuitboard/smes, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil/super_io, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cfr" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating/airless, +/area/space) +"cfs" = ( +/obj/structure/table, +/obj/machinery/reagentgrinder, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cft" = ( +/obj/machinery/botany/extractor, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cfu" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/smartfridge, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cfv" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "robotics_solar_inner"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/portsolar) +"cfw" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cfx" = ( +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/structure/table/steel, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cfy" = ( +/obj/item/clothing/mask/smokable/cigarette, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"cfz" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_south = 4; + tag_west = 2; + use_power = 0 + }, +/obj/effect/engine_setup/filter, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cfA" = ( +/obj/machinery/light/small, +/turf/floor/plating/airless, +/area/exodus/research/test_area) +"cfB" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cfC" = ( +/obj/machinery/airlock_sensor{ + id_tag = "engine_room_airlock"; + pixel_y = 22 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cfD" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Transfer - Upper"; + dir = 8 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cfE" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/sublevel_access) +"cfF" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cfG" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/random/tech_supply, +/obj/structure/table/steel, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cfH" = ( +/obj/structure/disposalpipe/segment, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"cfI" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "toxin_test_inner"; + name = "Engineering External Access" + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_starboard) +"cfJ" = ( +/obj/random/tech_supply, +/turf/floor, +/area/exodus/construction) +"cfK" = ( +/obj/structure/tank_rack/oxygen, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cfL" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"cfM" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cfN" = ( +/obj/structure/closet/wardrobe/robotics_black, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"cfO" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cfP" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cfQ" = ( +/obj/structure/sign/warning/docking_area{ + dir = 1; + pixel_y = -32 + }, +/turf/space, +/area/space) +"cfR" = ( +/obj/machinery/newscaster{ + pixel_x = 31; + pixel_y = 3 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cfS" = ( +/obj/structure/closet/secure_closet/personal, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/sleep/bedrooms) +"cfT" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"cfU" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "toxin_test_outer"; + name = "Engineering External Access" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_starboard) +"cfV" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"cfW" = ( +/obj/machinery/light, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"cfX" = ( +/obj/machinery/light, +/obj/structure/table, +/obj/machinery/chemical_dispenser/bar_soft/full{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"cfY" = ( +/turf/wall/prepainted, +/area/exodus/medical/surgeryprep) +"cfZ" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair/comfy/brown{ + dir = 4 + }, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"cga" = ( +/obj/machinery/vending/snack{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"cgb" = ( +/obj/machinery/door/airlock/medical{ + autoclose = 0; + id_tag = "engineering_cubicle"; + name = "Restroom" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cgc" = ( +/obj/structure/table, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 8 + }, +/obj/item/wrench, +/obj/item/hand_labeler, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cgd" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cge" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/machinery/smartfridge/drying_oven, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cgf" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/blue/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cgg" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryobs) +"cgh" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/light_switch{ + pixel_x = 22; + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cgi" = ( +/obj/structure/closet/secure_closet/personal/patient, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cgj" = ( +/obj/machinery/vending/engineering, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cgk" = ( +/obj/structure/closet/secure_closet/personal/patient, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cgl" = ( +/obj/machinery/button/alternate/door{ + desc = "A remote control-switch for Surgery."; + id_tag = "Surgery"; + name = "Surgery"; + pixel_x = -24; + pixel_y = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cgm" = ( +/obj/machinery/computer/modular/preset/engineering{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/break_room) +"cgn" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/maintenance/evahallway) +"cgo" = ( +/obj/machinery/computer/modular/preset/engineering, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cgp" = ( +/obj/structure/chair/comfy/brown, +/obj/abstract/landmark/start{ + name = "Psychiatrist" + }, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"cgq" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"cgr" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/patient_wing) +"cgs" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/substation/engineering) +"cgt" = ( +/obj/machinery/door/window/southright{ + dir = 1; + name = "Virology Isolation Room One" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cgu" = ( +/obj/structure/table/laminate, +/obj/machinery/recharger, +/turf/floor/carpet, +/area/exodus/hallway/secondary/entry/starboard) +"cgv" = ( +/obj/structure/disposalpipe/segment, +/turf/wall/r_wall/prepainted, +/area/exodus/medical/virology) +"cgw" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table, +/obj/item/box/botanydisk{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/botanydisk, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cgx" = ( +/obj/structure/closet/radiation, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cgy" = ( +/obj/structure/grille, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cgz" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Xenobiologist" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cgA" = ( +/obj/structure/table/marble, +/obj/machinery/recharger, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"cgB" = ( +/obj/structure/sign/warning/deathsposal{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cgC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/sign/warning/fire{ + pixel_y = -32 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cgD" = ( +/obj/machinery/optable{ + name = "Xenobiology Operating Table" + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cgE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Maintenance" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/sublevel_access) +"cgF" = ( +/obj/machinery/light_switch{ + pixel_x = 8; + pixel_y = 25 + }, +/obj/structure/disposalpipe/trunk, +/obj/machinery/disposal, +/turf/floor/lino, +/area/exodus/hydroponics/garden) +"cgG" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cgH" = ( +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/locker) +"cgI" = ( +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cgK" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cgL" = ( +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/machinery/recharger, +/turf/floor/lino, +/area/exodus/security/vacantoffice) +"cgM" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Atmospherics Maintenance Access" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/sublevel_access) +"cgN" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/starboardsolar) +"cgO" = ( +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/table/steel, +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cgQ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 8; + name = "Isolation to Waste" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cgR" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/engineering{ + name = "Science Substation" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/research) +"cgS" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cgT" = ( +/obj/machinery/atmospherics/pipe/manifold/visible, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cgU" = ( +/turf/floor, +/area/exodus/construction) +"cgV" = ( +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cgW" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cgX" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cgY" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cgZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cha" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"chb" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"chc" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"chd" = ( +/obj/machinery/atmospherics/binary/pump, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/engine_setup/pump_max, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"che" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"chf" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"chg" = ( +/obj/structure/hygiene/shower{ + dir = 8; + pixel_x = -5; + pixel_y = -5 + }, +/obj/structure/curtain/open/shower/engineering, +/obj/structure/window/basic{ + dir = 1 + }, +/obj/machinery/door/window/westright{ + name = "Shower" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"chh" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"chi" = ( +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"chj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"chk" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Engineering EVA Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_eva) +"chl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"chm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"chn" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cho" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"chp" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chq" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_eva) +"chr" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chs" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cht" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chv" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"chx" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chy" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Foyer"; + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chz" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"chA" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -27; + pixel_y = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"chB" = ( +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"chC" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Miscellaneous Research"; + sort_type = "Miscellaneous Research" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"chD" = ( +/obj/machinery/button/alternate/door/bolts{ + id_tag = "engineering_cubicle"; + name = "Door Bolt Control"; + pixel_x = -25; + pixel_y = 8 + }, +/obj/structure/hygiene/toilet{ + dir = 1 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"chE" = ( +/obj/structure/closet/secure_closet/personal/patient, +/obj/effect/floor_decal/corner/pink/three_quarters, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"chF" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"chG" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Solar - Aft Starboard" + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"chH" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"chI" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/structure/table/steel_reinforced, +/obj/item/inflatable_dispenser{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/inflatable_dispenser, +/obj/item/inflatable_dispenser{ + pixel_x = -2; + pixel_y = -2 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"chJ" = ( +/obj/structure/bed/psych, +/obj/item/bedsheet/brown, +/turf/floor/carpet/blue, +/area/exodus/medical/psych) +"chK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Virology Access" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology/access) +"chL" = ( +/obj/structure/table, +/obj/item/gun/launcher/syringe, +/obj/item/box/syringegun, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"chM" = ( +/obj/structure/bedsheetbin/mapped, +/obj/structure/table, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"chN" = ( +/obj/machinery/button/access/interior{ + id_tag = "virology_airlock"; + name = "interior access button"; + pixel_x = -20; + pixel_y = -20 + }, +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"chO" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"chP" = ( +/obj/structure/table, +/obj/item/sutures, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/item/surgicaldrill, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"chQ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"chR" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"chS" = ( +/obj/machinery/door/airlock/research{ + name = "Xenoflora Storage" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/xenobiology) +"chT" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"chV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"chW" = ( +/obj/structure/curtain/open/shower/engineering, +/obj/structure/window/basic{ + dir = 1 + }, +/obj/structure/hygiene/shower{ + dir = 8; + pixel_x = -5; + pixel_y = -5 + }, +/obj/machinery/door/window/westleft{ + name = "Shower" + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"chX" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"chY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"chZ" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"cia" = ( +/obj/structure/table, +/obj/item/sutures, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/item/surgicaldrill, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"cib" = ( +/obj/machinery/power/breakerbox/activated{ + RCon_tag = "Engineering Substation Bypass" + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/engineering) +"cic" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Xenobiologist" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cid" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/biostorage) +"cie" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cif" = ( +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"cig" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/closet/crate/hydroponics/prespawned, +/obj/machinery/camera/network/research{ + c_tag = "Xenoflora Storage"; + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/item/clothing/jumpsuit/hydroponics, +/obj/item/clothing/jumpsuit/hydroponics, +/obj/item/clothing/gloves/thick/botany, +/obj/item/clothing/gloves/thick/botany, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cih" = ( +/obj/machinery/light_switch{ + pixel_x = 26; + pixel_y = -6; + dir = 8 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cii" = ( +/obj/machinery/light_switch{ + name = "light switch "; + pixel_x = -23; + pixel_y = -8 + }, +/turf/floor/tiled/freezer, +/area/exodus/crew_quarters/sleep/engi_wash) +"cij" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cik" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cil" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cim" = ( +/obj/machinery/door/airlock/engineering{ + name = "Engineering Washroom" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/locker_room) +"cio" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cip" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ciq" = ( +/turf/wall/prepainted, +/area/exodus/engineering/locker_room) +"cir" = ( +/obj/random/closet, +/obj/random/coin, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cis" = ( +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/structure/rack, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cit" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ciu" = ( +/obj/item/briefcase/inflatable{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/briefcase/inflatable, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"civ" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"ciw" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cix" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"ciy" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"ciz" = ( +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora) +"ciA" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/substation/engineering) +"ciB" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/structure/rack, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"ciC" = ( +/obj/machinery/door/window/eastright{ + name = "Engineering Reception Desk" + }, +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ciD" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"ciE" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/structure/sign/warning/deathsposal{ + pixel_x = 32 + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"ciF" = ( +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"ciG" = ( +/turf/wall/prepainted, +/area/exodus/medical/surgery) +"ciH" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ciI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/engineering{ + dir = 4; + name = "Engineering EVA Storage" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_eva) +"ciJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ciK" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ciL" = ( +/obj/structure/sign/warning/nosmoking_2{ + pixel_y = -30 + }, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"ciM" = ( +/obj/structure/closet/secure_closet/engineering_personal, +/obj/item/tank/emergency/oxygen/engi, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ciN" = ( +/obj/structure/closet/secure_closet/engineering_personal, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/tank/emergency/oxygen/engi, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ciO" = ( +/obj/structure/closet/secure_closet/engineering_personal, +/obj/item/tank/emergency/oxygen/engi, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ciP" = ( +/obj/structure/closet/secure_closet/engineering_personal, +/obj/item/tank/emergency/oxygen/engi, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ciQ" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ciR" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"ciS" = ( +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"ciT" = ( +/obj/machinery/button/blast_door{ + id_tag = "surgeryobs"; + name = "Privacy Shutters"; + pixel_y = 25 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"ciU" = ( +/turf/wall/prepainted, +/area/exodus/medical/surgery2) +"ciV" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"ciW" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"ciX" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 1" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"ciY" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"ciZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cja" = ( +/obj/machinery/button/blast_door{ + id_tag = "surgeryobs2"; + name = "Privacy Shutters"; + pixel_y = 25 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cjb" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"cjc" = ( +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cjd" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cje" = ( +/obj/machinery/light_switch{ + pixel_x = 22; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cjf" = ( +/obj/structure/table/steel, +/obj/machinery/recharger, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cjg" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cjh" = ( +/obj/machinery/camera/network/medbay{ + c_tag = "Virology Access Fore" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cji" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cjj" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/structure/sign/warning/deathsposal{ + pixel_x = 32 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cjk" = ( +/obj/machinery/button/access/exterior{ + id_tag = "incinerator_access_control"; + name = "Incinerator airlock control"; + pixel_x = 10; + pixel_y = -22 + }, +/obj/structure/sign/warning/fire{ + pixel_x = -32 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/binary/pump, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"cjl" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cjm" = ( +/obj/machinery/button/access/interior{ + id_tag = "incinerator_access_control"; + name = "Incinerator airlock control"; + pixel_x = -8; + pixel_y = 24 + }, +/obj/structure/sign/warning/fire{ + pixel_x = 32 + }, +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"cjn" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cjo" = ( +/obj/structure/closet/secure_closet/personal/patient, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Recovery Ward"; + dir = 1 + }, +/obj/effect/floor_decal/corner/pink/three_quarters{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/medical/ward) +"cjp" = ( +/obj/structure/table, +/obj/item/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/item/box/masks, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cjq" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cjr" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cjs" = ( +/obj/structure/closet/secure_closet/atmos_personal, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/item/tank/emergency/oxygen/engi, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cjt" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cju" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cjv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cjw" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cjx" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"cjy" = ( +/obj/machinery/door/window/southright{ + dir = 4; + name = "Primate Pen" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cjz" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/closet/wardrobe/medic_white, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cjA" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Xenobiologist" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cjB" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"cjC" = ( +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/paper_bin, +/obj/item/pen, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cjD" = ( +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/box/beakers{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/syringes, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cjF" = ( +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cjG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Xenobiologist" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cjH" = ( +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cjI" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Elevator - Fore" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cjJ" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cjK" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cjL" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cjM" = ( +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Virology Break/Access" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cjN" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor, +/area/exodus/maintenance/atmos_control) +"cjO" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Firefighting equipment" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/research_port) +"cjP" = ( +/obj/machinery/suit_cycler/engineering, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering EVA"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cjQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_eva) +"cjR" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cjS" = ( +/obj/machinery/light_switch{ + pixel_x = 25; + pixel_y = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 25; + pixel_y = -5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cjT" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cjU" = ( +/obj/structure/table/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/obj/item/folder/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cjV" = ( +/obj/structure/table/reinforced, +/obj/item/stack/package_wrap, +/obj/item/hand_labeler, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cjW" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cjX" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cjY" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cjZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cka" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/locker_room) +"ckb" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ckc" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ckd" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cke" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"ckf" = ( +/obj/machinery/ai_status_display{ + pixel_y = 32 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"ckg" = ( +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/engineering) +"ckh" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/power_sensor{ + id_tag = "Engineering Subgrid"; + name = "Powernet Sensor - Engineering Subgrid" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/substation/engineering) +"cki" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/structure/bed/padded, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ckj" = ( +/obj/machinery/computer/operating{ + dir = 8 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"ckk" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/obj/item/chems/spray/antiseptic, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"ckl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"ckm" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"ckn" = ( +/obj/structure/disposalpipe/segment, +/obj/item/roller, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cko" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"ckp" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/obj/item/chems/spray/antiseptic, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"ckq" = ( +/obj/machinery/computer/operating{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"ckr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cks" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ckt" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/research_port) +"cku" = ( +/obj/machinery/light_switch{ + pixel_x = -22; + pixel_y = -10 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Storage"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"ckv" = ( +/obj/structure/table/steel, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/machinery/recharger, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"ckw" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating/airless, +/area/space) +"ckx" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"cky" = ( +/obj/machinery/door/window/northright{ + name = "Xenoflora Containment" + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"ckz" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"ckA" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/visible, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"ckB" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Virology Laboratory" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ckC" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckD" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckF" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckG" = ( +/obj/structure/rack, +/obj/item/box/lights/mixed, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/tech_supply, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"ckH" = ( +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckI" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckJ" = ( +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ckK" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ckL" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/atmos_control) +"ckN" = ( +/obj/machinery/network/requests_console{ + department = "Science"; + name = "Science Requests Console"; + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"ckO" = ( +/obj/machinery/button/access/interior{ + id_tag = "solar_xeno_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = -25; + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 8 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"ckP" = ( +/obj/machinery/power/solar_control{ + dir = 1; + id_tag = "starboardsolar"; + name = "Aft Starboard Solar Control" + }, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"ckQ" = ( +/obj/structure/table, +/obj/item/box/donkpockets, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"ckS" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"ckT" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ckU" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ckV" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ckW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ckX" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random/maintenance, +/obj/random/maintenance, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"ckY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"ckZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cla" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"clb" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"clc" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Engineering EVA Storage Maintainance" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_eva) +"cld" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/random/closet, +/obj/structure/sign/warning/high_voltage{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cle" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"clf" = ( +/obj/structure/table/reinforced, +/obj/item/clipboard, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"clg" = ( +/obj/machinery/navbeacon/Engineering, +/obj/structure/flaps{ + opacity = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"clh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cli" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"clj" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"clk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cll" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Substation - Engineering" + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/maintenance/substation/engineering) +"clm" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/double/glass/engineering{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/locker_room) +"cln" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"clo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table, +/obj/item/scanner/plant, +/obj/item/scanner/plant, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"clp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"clq" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"clr" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cls" = ( +/obj/structure/table, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"clt" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"clu" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/ai_status_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"clv" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/engineering) +"clx" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cly" = ( +/obj/structure/table, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/item/circular_saw{ + pixel_y = 8 + }, +/obj/item/scalpel, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"clz" = ( +/obj/machinery/optable, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"clA" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"clB" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"clC" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"clD" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 1" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"clE" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"clF" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"clG" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/pink{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"clH" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 2" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"clI" = ( +/obj/machinery/optable, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"clJ" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"clK" = ( +/obj/structure/table, +/obj/item/circular_saw{ + pixel_y = 8 + }, +/obj/item/scalpel, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"clL" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 1; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + initialize_directions = 1; + internal_pressure_bound = 4000; + internal_pressure_bound_default = 4000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/obj/structure/sign/warning/vacuum{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/reinforced, +/area/exodus/maintenance/incinerator) +"clM" = ( +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"clN" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/medical/virology/access) +"clO" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"clP" = ( +/obj/machinery/light/small, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 8 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"clQ" = ( +/obj/machinery/light/small, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/lime, +/obj/structure/sign/warning/biohazard{ + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"clS" = ( +/obj/structure/sign/warning/radioactive{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"clT" = ( +/obj/structure/sign/warning/fire{ + pixel_y = 32 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"clU" = ( +/obj/structure/closet/secure_closet/scientist, +/obj/item/tank/air, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/white, +/area/exodus/research/mixing) +"clV" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/hydroponics{ + closed_system = 1; + name = "isolation tray" + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"clW" = ( +/obj/machinery/button/access/exterior{ + id_tag = "toxin_test_airlock"; + name = "exterior access button"; + pixel_x = -20; + dir = 4 + }, +/turf/space, +/area/space) +"clX" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"clY" = ( +/obj/machinery/light, +/obj/machinery/light_switch{ + name = "light switch "; + pixel_y = -22; + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora_storage) +"clZ" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cma" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 8; + name = "Drone Fabrication"; + sort_type = "Drone Fabrication" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cmb" = ( +/obj/item/radio/off{ + pixel_y = 6 + }, +/obj/item/radio/off{ + pixel_x = 6; + pixel_y = 4 + }, +/obj/item/radio/off{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/item/radio/off, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cmc" = ( +/obj/structure/sign/warning/biohazard{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"cmd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cme" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/reagent_dispensers/watertank, +/obj/item/chems/glass/bucket, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cmf" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora) +"cmg" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cmh" = ( +/obj/machinery/seed_extractor, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cmi" = ( +/obj/machinery/biogenerator, +/obj/machinery/camera/network/research{ + c_tag = "Xenoflora"; + dir = 1 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cmj" = ( +/turf/unsimulated/mask, +/area/exodus/engineering/sublevel_access) +"cmk" = ( +/obj/item/lockbox/vials, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cml" = ( +/obj/machinery/light, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled/freezer, +/area/exodus/research/xenobiology/xenoflora) +"cmm" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/engineering{ + name = "Construction Area" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/construction) +"cmn" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/reagent_dispensers/watertank, +/obj/item/chems/glass/bucket, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cmo" = ( +/obj/machinery/door/blast/regular{ + dir = 8; + id_tag = "EngineEmitterPortWest"; + name = "Engine Waste Handling Access" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cmp" = ( +/obj/item/stool, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Aft Starboard"; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"cmq" = ( +/obj/item/box/fancy/vials, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cmr" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "EngineEmitterPortWest"; + name = "Engine Waste Handling Access" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cms" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cmt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cmu" = ( +/obj/machinery/door/airlock/atmos{ + name = "Atmospherics Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/atmos/storage) +"cmv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cmw" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cmx" = ( +/mob/living/bot/floorbot/premade, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"cmy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmz" = ( +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "SupermatterPort"; + name = "Reactor Blast Door" + }, +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cmA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/network/requests_console{ + department = "Engineering"; + name = "Engineering RC"; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmD" = ( +/obj/structure/sign/warning/vacuum{ + pixel_x = -32 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cmE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/computer/guestpass{ + pixel_y = -28 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmG" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cmH" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmI" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmJ" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 4 + }, +/obj/structure/sign/warning/secure_area{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmK" = ( +/obj/structure/disposalpipe/junction{ + dir = 2; + icon_state = "pipe-j2" + }, +/obj/effect/floor_decal/corner/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"cmL" = ( +/obj/structure/closet/secure_closet/atmos_personal, +/obj/item/tank/emergency/oxygen/engi, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cmM" = ( +/obj/machinery/door/blast/regular/open{ + density = 0; + dir = 4; + id_tag = "SupermatterPort"; + name = "Reactor Blast Door" + }, +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cmN" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cmO" = ( +/obj/structure/table, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cmP" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Locker Room"; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/locker_room) +"cmQ" = ( +/obj/machinery/button/access/exterior{ + id_tag = "robotics_solar_airlock"; + name = "exterior access button"; + pixel_x = 25; + pixel_y = 25 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cmR" = ( +/obj/machinery/door/airlock/engineering{ + name = "Engineering Substation" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/engineering) +"cmS" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/substation/engineering) +"cmU" = ( +/obj/structure/table, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/item/stack/medical/bandage/advanced, +/obj/item/retractor, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"cmV" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"cmW" = ( +/obj/machinery/button/holosign{ + pixel_x = 24; + pixel_y = 2 + }, +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Operating Theatre 1"; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"cmX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/surgery) +"cmY" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cmZ" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cna" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cnb" = ( +/obj/machinery/button/holosign{ + pixel_x = -24; + pixel_y = 2 + }, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Operating Theatre 2"; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cnc" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cnd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/surgery2) +"cne" = ( +/obj/structure/table, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/item/stack/medical/bandage/advanced, +/obj/item/retractor, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"cng" = ( +/obj/machinery/button/access/interior{ + id_tag = "robotics_solar_airlock"; + name = "interior access button"; + pixel_x = -25; + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cnh" = ( +/obj/structure/supermatter, +/obj/machinery/mass_driver{ + id_tag = "enginecore" + }, +/obj/effect/engine_setup/core, +/turf/floor/greengrid/nitrogen, +/area/exodus/engineering/engine_room) +"cni" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora) +"cnj" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cnk" = ( +/obj/structure/closet/radiation, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cnl" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/maintenance/arrivals) +"cnn" = ( +/obj/structure/table/laminate, +/obj/item/taperecorder, +/obj/item/camera, +/obj/item/eftpos{ + eftpos_name = "Library EFTPOS scanner" + }, +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor/tiled/steel_grid, +/area/exodus/library) +"cno" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "solar_xeno_airlock"; + pixel_x = 25; + tag_airpump = "solar_xeno_pump"; + tag_chamber_sensor = "solar_xeno_sensor"; + tag_exterior_door = "solar_xeno_outer"; + tag_interior_door = "solar_xeno_inner" + }, +/obj/machinery/airlock_sensor{ + id_tag = "solar_xeno_sensor"; + pixel_x = 25; + pixel_y = 12; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "solar_xeno_pump" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/exodus/maintenance/starboardsolar) +"cnp" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/construction) +"cnq" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cnr" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/tiled/steel_grid, +/area/exodus/construction) +"cns" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"cnt" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/maintenance/research_starboard) +"cnu" = ( +/obj/machinery/light_switch{ + pixel_x = 8; + pixel_y = 24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/storage) +"cnv" = ( +/obj/machinery/door/firedoor{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/sign/warning/compressed_gas{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"cnw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cnx" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cny" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/engineering{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"cnz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/chair/office/dark, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cnA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cnB" = ( +/obj/structure/table/reinforced, +/obj/item/flashlight, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cnC" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cnD" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/construction) +"cnE" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/structure/sign/warning/compressed_gas{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cnF" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/engineering{ + name = "Engineering Hallway" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"cnG" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engineering_monitoring) +"cnH" = ( +/obj/item/box/syringes{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/beakers, +/obj/item/chems/dropper, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cnI" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/engineering{ + name = "Engineering Hallway" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"cnJ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/high_voltage{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cnK" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/workshop) +"cnL" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/engineering{ + name = "Engineering Locker Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/workshop) +"cnM" = ( +/obj/structure/lattice, +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"cnN" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cnO" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/workshop) +"cnP" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/green, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cnQ" = ( +/obj/structure/table, +/obj/item/hemostat, +/obj/machinery/light, +/obj/item/cautery, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"cnR" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/locker_room) +"cnS" = ( +/obj/structure/table, +/obj/item/bonesetter, +/obj/item/bonegel, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"cnT" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"cnU" = ( +/obj/structure/table, +/obj/machinery/vending/wallmed1{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/random/medical, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"cnV" = ( +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cnW" = ( +/obj/structure/table, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cnX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cnY" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"cnZ" = ( +/obj/structure/table, +/obj/machinery/vending/wallmed1{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/random/medical, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"coa" = ( +/obj/structure/table, +/obj/item/hemostat, +/obj/machinery/light, +/obj/item/cautery, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"cob" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solar_xeno_inner"; + name = "Engineering External Access" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/starboardsolar) +"coc" = ( +/obj/structure/table, +/obj/item/bonesetter, +/obj/item/bonegel, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"cod" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"coe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/medbay{ + c_tag = "Virology Starboard"; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cof" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/obj/structure/sign/warning/biohazard{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cog" = ( +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/structure/disposaloutlet, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"coh" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"coi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"coj" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cok" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"col" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"com" = ( +/turf/wall/prepainted, +/area/exodus/research/xenobiology) +"con" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"coo" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/machinery/button/access/interior{ + id_tag = "xeno_airlock_control"; + name = "Xenobiology Access Button"; + pixel_x = 8; + pixel_y = -28 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cop" = ( +/obj/machinery/camera/xray/research{ + c_tag = "Xenobiology Access" + }, +/obj/structure/closet/secure_closet/xenobio, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"coq" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 7; + pixel_y = -32 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/table, +/obj/item/scanner/xenobio, +/obj/machinery/vending/wallmed1{ + pixel_x = -7; + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cor" = ( +/obj/machinery/airlock_sensor{ + id_tag = "eng_al_c_snsr"; + pixel_x = -25; + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"cos" = ( +/obj/machinery/disposal, +/obj/structure/sign/warning/deathsposal{ + pixel_y = -32 + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/xenobiology) +"cot" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cou" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/structure/table, +/obj/item/circular_saw, +/obj/item/scalpel{ + pixel_y = 12 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cov" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/space_heater, +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cow" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cox" = ( +/obj/machinery/atmospherics/binary/pump, +/obj/effect/engine_setup/pump_max, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"coy" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/substation/engineering) +"coz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"coA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"coB" = ( +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"coC" = ( +/obj/structure/ladder, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"coD" = ( +/obj/structure/table/reinforced, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"coE" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/structure/table/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"coF" = ( +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"coG" = ( +/obj/structure/table/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"coH" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"coI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"coJ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"coK" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"coL" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/sign/directions/medical{ + dir = 1; + pixel_x = 30; + pixel_z = 4 + }, +/obj/structure/sign/directions/evac{ + dir = 8; + pixel_x = 30; + pixel_z = -4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"coM" = ( +/obj/machinery/vending/engivend, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"coN" = ( +/obj/machinery/vending/tool, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"coO" = ( +/obj/structure/closet/toolcloset, +/obj/item/flashlight, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"coP" = ( +/obj/structure/closet/toolcloset, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/flashlight, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"coQ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"coR" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"coS" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 1 Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgery) +"coT" = ( +/obj/structure/window/reinforced, +/obj/machinery/atmospherics/binary/pump{ + dir = 8; + name = "waste pump" + }, +/obj/machinery/door/window/brigdoor/westleft{ + name = "Engine Waste" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/engine_setup/pump_max, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"coU" = ( +/obj/item/chems/ivbag/blood, +/obj/item/chems/ivbag/blood, +/obj/item/chems/ivbag/blood, +/obj/item/chems/ivbag/blood, +/obj/item/chems/ivbag/blood, +/obj/structure/table, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/camera/network/medbay{ + c_tag = "Medbay Surgery Prep"; + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"coV" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 2 Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgery2) +"coW" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "virologyquar"; + name = "virologyquar" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology/access) +"coX" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "virologyquar"; + name = "virologyquar" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/virology/access) +"coY" = ( +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"coZ" = ( +/mob/living/slime, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cpa" = ( +/obj/machinery/door/window/eastleft{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpb" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"cpc" = ( +/obj/structure/sign/warning/internals_required{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/maintenance/security_starboard) +"cpd" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio3"; + name = "xenobio3" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/window/westright{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cpe" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cpf" = ( +/obj/abstract/map_data/exodus, +/turf/space, +/area/space) +"cpg" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cph" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"cpi" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cpj" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/storage) +"cpm" = ( +/obj/machinery/button/access/exterior{ + id_tag = "solar_xeno_airlock"; + name = "exterior access button"; + pixel_x = 25; + pixel_y = 25 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cpn" = ( +/obj/machinery/rad_collector, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cpo" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cpp" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Elevator - Aft"; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cpq" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 25 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cpr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cps" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cpt" = ( +/obj/machinery/door/window/southright{ + name = "Virology Isolation Room Three" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cpu" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/sublevel_access) +"cpw" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/mech_recharger, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"cpx" = ( +/obj/machinery/computer/modular/preset/engineering{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cpy" = ( +/obj/machinery/vending/wallmed1{ + pixel_x = -25; + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/sleeper) +"cpz" = ( +/obj/machinery/camera/network/engineering{ + c_tag = "Atmospherics Monitoring Room"; + dir = 8 + }, +/obj/machinery/computer/modular/preset/engineering{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cpA" = ( +/obj/machinery/camera/network/research{ + c_tag = "Xenobiology Southeast"; + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpB" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/lattice, +/turf/space, +/area/space) +"cpD" = ( +/obj/machinery/computer/modular/preset/engineering{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cpE" = ( +/obj/machinery/computer/modular/preset/engineering{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cpF" = ( +/obj/machinery/computer/shuttle_control/explore/engineering{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cpH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cpI" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpK" = ( +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpL" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpN" = ( +/obj/machinery/bodyscanner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/sleeper) +"cpO" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpP" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpT" = ( +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cpV" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "Biohazard"; + name = "Biohazard" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/research/xenobiology) +"cpW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/atmos{ + name = "Atmospherics Monitoring Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engineering_monitoring) +"cpX" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_north = 4; + tag_west = 2; + use_power = 0 + }, +/obj/effect/engine_setup/filter, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cpY" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/glass/engineering{ + name = "Engineering Monitoring Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engineering_monitoring) +"cpZ" = ( +/obj/structure/disposalpipe/junction, +/turf/floor/plating/airless, +/area/space) +"cqa" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cqb" = ( +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"cqd" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cqe" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cqf" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cqg" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cqh" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"cqi" = ( +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"cqj" = ( +/obj/structure/iv_drip, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"cqk" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"cql" = ( +/obj/structure/closet/secure_closet/medical3, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cqm" = ( +/obj/structure/table, +/obj/item/chems/ivbag/blood/aminus, +/obj/item/chems/ivbag/blood/aplus, +/obj/item/chems/ivbag/blood/bminus, +/obj/item/chems/ivbag/blood/bplus, +/obj/item/chems/ivbag/blood/oplus, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"cqn" = ( +/obj/structure/iv_drip, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"cqo" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"cqp" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"cqq" = ( +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"cqr" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "virology_outer"; + name = "Engineering External Access" + }, +/obj/machinery/shield_diffuser, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/medbay) +"cqs" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solar_xeno_outer"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/starboardsolar) +"cqu" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/light, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for shutters."; + id_tag = "virologyquar"; + name = "Virology Emergency Lockdown Control"; + pixel_y = -28; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cqv" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/medical/virology) +"cqw" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/button/access/interior{ + id_tag = "engineering_dock_airlock"; + name = "interior access button"; + pixel_x = -30; + pixel_y = -25; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cqx" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"cqz" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/light, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology/access) +"cqA" = ( +/obj/machinery/button/access/exterior{ + id_tag = "virology_airlock"; + name = "exterior access button"; + pixel_x = 20; + pixel_y = 20 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"cqB" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"cqC" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cqD" = ( +/obj/structure/lattice, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/space, +/area/space) +"cqE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cqF" = ( +/obj/structure/lattice, +/obj/structure/disposalpipe/segment, +/turf/space, +/area/space) +"cqG" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "engineering_dock_inner"; + name = "Engineering Dock Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engi_shuttle) +"cqH" = ( +/obj/structure/sign/warning/hot_exhaust{ + pixel_x = -32 + }, +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/space, +/area/space) +"cqJ" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cqL" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cqN" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine control room blast doors."; + id_tag = "EngineBlast"; + name = "Engine Monitoring Room Blast Doors"; + pixel_y = -3; + dir = 1; + directional_offset = null + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine charging port."; + id_tag = "SupermatterPort"; + name = "Reactor Blast Doors"; + pixel_x = -6; + pixel_y = 7; + dir = 1; + directional_offset = null + }, +/obj/machinery/button/toggle{ + desc = "A remote control-switch for the engine emitter."; + id_tag = "EngineEmitter"; + name = "Engine Emitter"; + pixel_x = 6; + pixel_y = 7; + dir = 1; + directional_offset = null + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cqO" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "EngineRadiatorViewport"; + name = "EngineRadiatorViewport" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cqP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cqR" = ( +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/space) +"crb" = ( +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/qm) +"crc" = ( +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/structure/disposaloutlet, +/turf/floor/plating/airless, +/area/space) +"crd" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "engineering_dock_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 4; + id_tag = "engineering_dock_airlock"; + pixel_x = -25; + tag_airpump = "engineering_dock_pump"; + tag_chamber_sensor = "engineering_dock_sensor"; + tag_exterior_door = "engineering_dock_outer"; + tag_interior_door = "engineering_dock_inner" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cre" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"crf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"crg" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 10 + }, +/turf/floor/plating/airless, +/area/space) +"crh" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple/three_quarters, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology/xenoflora_storage) +"cri" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"crj" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"crk" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/space, +/area/space) +"crl" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"crm" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"crn" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"cro" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"crp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"crq" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "engineering_dock_pump" + }, +/obj/machinery/airlock_sensor{ + id_tag = "engineering_dock_sensor"; + pixel_x = -25; + pixel_y = 8; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"crr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"crs" = ( +/obj/machinery/door/blast/regular{ + dir = 2; + id_tag = "disvent"; + name = "Incinerator Vent" + }, +/obj/machinery/shield_diffuser, +/turf/floor/reinforced, +/area/exodus/maintenance/incinerator) +"crt" = ( +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 1 Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"cru" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/three_quarters, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"crv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engineering) +"crw" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"crx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"cry" = ( +/obj/machinery/door/airlock/medical{ + name = "Operating Theatre 2 Storage" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"crz" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"crA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"crB" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"crC" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/exodus/maintenance/incinerator) +"crD" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"crE" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/plating/airless, +/area/space) +"crF" = ( +/obj/machinery/door/blast/regular{ + desc = "By gods, release the hounds!"; + dir = 4; + id_tag = "xenobioout6"; + name = "Containment Release" + }, +/obj/machinery/shield_diffuser, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"crG" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/medbay) +"crH" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "engineering_dock_outer"; + name = "Engineering Dock Airlock" + }, +/obj/machinery/shield_diffuser, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/button/access/exterior{ + id_tag = "engineering_dock_airlock"; + name = "exterior access button"; + pixel_x = 25; + dir = 8 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engi_shuttle) +"crI" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"crJ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"crK" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/plating, +/area/exodus/engineering/storage) +"crL" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"crM" = ( +/obj/machinery/computer/ship/sensors{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"crN" = ( +/obj/machinery/door/blast/regular{ + id_tag = "EngineVent"; + name = "Reactor Vent" + }, +/obj/machinery/shield_diffuser, +/turf/floor/reinforced, +/area/exodus/engineering/engine_room) +"crO" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"crP" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/space, +/area/space) +"crQ" = ( +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"crR" = ( +/obj/structure/table, +/obj/item/box/matches, +/obj/item/box/fancy/cigarettes, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/item/deck/cards, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"crS" = ( +/obj/structure/window/basic{ + dir = 8 + }, +/obj/effect/floor_decal/spline/plain, +/obj/effect/floor_decal/spline/plain{ + dir = 8 + }, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"crU" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"crV" = ( +/obj/effect/floor_decal/spline/plain, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"crY" = ( +/obj/structure/window/basic{ + dir = 4 + }, +/obj/effect/floor_decal/spline/plain, +/obj/effect/floor_decal/spline/plain{ + dir = 4 + }, +/turf/floor/pool, +/area/exodus/crew_quarters/fitness) +"csb" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stock_parts/circuitboard/arcade/battle, +/obj/item/stock_parts/circuitboard/arcade/orion_trail, +/turf/floor/plating, +/area/exodus/storage/tech) +"csg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/surgeryprep) +"csj" = ( +/obj/machinery/smartfridge/secure/extract, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"csk" = ( +/obj/machinery/computer/operating{ + name = "Xenobiology Operating Computer" + }, +/obj/effect/floor_decal/corner/purple/three_quarters{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"csl" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 4 + }, +/turf/space, +/area/space) +"csm" = ( +/obj/structure/table, +/obj/item/box/beakers{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/syringes, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"csn" = ( +/obj/structure/table/reinforced, +/obj/machinery/light, +/obj/item/flashlight, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"cso" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/lime/three_quarters, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"csp" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"csq" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 1 + }, +/turf/space, +/area/space) +"csr" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"css" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cst" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"csu" = ( +/obj/structure/closet/secure_closet/engineering_welding, +/obj/item/clothing/glasses/welding, +/obj/item/clothing/glasses/welding, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"csv" = ( +/obj/structure/closet/secure_closet/engineering_welding, +/obj/item/clothing/glasses/welding, +/obj/item/clothing/glasses/welding, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"csw" = ( +/obj/structure/closet/secure_closet/engineering_electrical, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"csx" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"csy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"csz" = ( +/obj/structure/closet/secure_closet/engineering_electrical, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"csA" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/obj/machinery/camera/network/engine{ + c_tag = "Engine Radiator" + }, +/obj/structure/sign/warning/docking_area{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"csB" = ( +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/computer/robotics, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"csC" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"csD" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"csE" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/fabricator/bioprinter, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery) +"csF" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery) +"csG" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/fabricator/bioprinter, +/turf/floor/tiled/white/monotile, +/area/exodus/medical/surgery2) +"csH" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"csI" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "EngineRadiatorViewport"; + name = "EngineRadiatorViewport" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"csJ" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"csK" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/turf/floor/tiled/freezer, +/area/exodus/medical/surgery2) +"csL" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/black, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"csM" = ( +/obj/structure/lattice, +/obj/structure/grille/broken{ + dir = 8 + }, +/turf/space, +/area/space) +"csN" = ( +/obj/structure/closet/wardrobe/virology_white, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/camera/xray/medbay{ + c_tag = "Virology Access Aft" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"csO" = ( +/obj/structure/closet/secure_closet/personal/patient, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"csP" = ( +/obj/item/roller, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"csQ" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 4 + }, +/turf/space, +/area/space) +"csR" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 8 + }, +/turf/space, +/area/space) +"csS" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"csT" = ( +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/turf/floor/plating/airless, +/area/space) +"csX" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"ctb" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/stock_parts/circuitboard/message_monitor{ + pixel_x = 3; + pixel_y = -3 + }, +/turf/floor/plating, +/area/exodus/storage/tech) +"cte" = ( +/obj/effect/floor_decal/corner/lime/full, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"ctg" = ( +/obj/item/stack/material/rods{ + amount = 6 + }, +/turf/space, +/area/space) +"ctn" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"cto" = ( +/obj/structure/lattice, +/obj/structure/grille/broken{ + dir = 1 + }, +/turf/space, +/area/space) +"ctp" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 8 + }, +/turf/space, +/area/space) +"ctq" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 8 + }, +/obj/effect/engine_setup/pump_max, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"ctr" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cts" = ( +/obj/item/stack/material/rods{ + amount = 10 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"ctt" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"ctu" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Hallway North"; + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"ctv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"ctw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"ctx" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cty" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"ctz" = ( +/obj/machinery/papershredder, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"ctA" = ( +/obj/machinery/apc/high{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"ctB" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"ctC" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"ctD" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Operating Theatre 1 Maintenance Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgery) +"ctE" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Operating Theatre 2 Maintenance Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgery2) +"ctF" = ( +/turf/wall/prepainted, +/area/exodus/medical/virology) +"ctH" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"ctI" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/closet/l3closet/virology, +/obj/item/clothing/mask/gas, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ctJ" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/tiled/steel_grid, +/area/exodus/medical/virology) +"ctK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "EngineRadiatorViewport"; + name = "EngineRadiatorViewport" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"ctM" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "EngineRadiatorViewport"; + name = "EngineRadiatorViewport" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"ctO" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/item/secure_storage/safe{ + pixel_x = 5; + pixel_y = 29 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ctP" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/space, +/area/space) +"ctQ" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/camera/network/medbay{ + c_tag = "Virology Monkey Pen" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ctR" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"ctS" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio2"; + name = "xenobio2" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/window/westright{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"ctT" = ( +/obj/structure/table, +/obj/item/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/masks, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ctU" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ctV" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/closet/secure_closet/xenobio, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ctW" = ( +/obj/structure/table, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/paper_bin, +/obj/item/pen, +/obj/item/stack/tape_roll/duct_tape, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ctX" = ( +/obj/structure/table, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/glass_jar, +/obj/item/glass_jar, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"ctZ" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cua" = ( +/obj/machinery/power/solar{ + id_tag = "starboardsolar"; + name = "Starboard Solar Array" + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cub" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 5 + }, +/turf/space, +/area/space) +"cud" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/turf/space, +/area/space) +"cuf" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Pre-Op Prep Room Maintenance Access" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/surgeryprep) +"cul" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"cum" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"cun" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cuo" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cuq" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cur" = ( +/obj/machinery/newscaster{ + pixel_y = 30 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cus" = ( +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cut" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/workshop) +"cuu" = ( +/obj/structure/disposalpipe/sortjunction/flipped{ + dir = 2; + name = "Engineering"; + sort_type = "Engineering" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cuv" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cuw" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cux" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cuy" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cuz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"cuA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"cuB" = ( +/obj/machinery/emitter, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cuC" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cuD" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cuE" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cuF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cuG" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cuH" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cuI" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cuJ" = ( +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/machinery/generator{ + anchored = 1; + dir = 4 + }, +/obj/structure/cable/yellow, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cuK" = ( +/obj/machinery/button/access/exterior{ + id_tag = "dorm_airlock"; + name = "exterior access button"; + pixel_x = -25; + pixel_y = -25; + dir = 1 + }, +/turf/space, +/area/space) +"cuL" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/machinery/button/access/interior{ + id_tag = "virology_airlock_control"; + name = "Virology Access Button"; + pixel_x = 8; + pixel_y = -28 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuM" = ( +/obj/structure/closet/l3closet/virology, +/obj/item/clothing/mask/gas, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuN" = ( +/obj/structure/chair/office/dark{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuO" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/item/folder/cyan, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuP" = ( +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuQ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuR" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cuS" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/rack, +/obj/item/shield/riot, +/obj/item/clothing/head/helmet/riot, +/obj/structure/window/reinforced, +/obj/machinery/door/window/brigdoor/eastleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"cuT" = ( +/obj/structure/rack, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window/brigdoor/northleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"cuU" = ( +/obj/structure/rack, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/northleft{ + name = "Weapons locker" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/clothing/suit/armor/vest/nt, +/obj/item/clothing/suit/armor/vest/nt, +/obj/item/clothing/suit/armor/vest/nt, +/obj/item/clothing/suit/armor/vest/nt, +/turf/floor/tiled/dark, +/area/exodus/security/armoury) +"cuV" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/flash, +/obj/item/flash, +/obj/item/flash, +/obj/item/flash, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"cuW" = ( +/obj/structure/extinguisher_cabinet, +/turf/wall/r_wall/prepainted, +/area/exodus/medical/virology) +"cuX" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/rack, +/obj/item/box/handcuffs, +/obj/item/box/handcuffs, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"cuY" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/item/chems/spray/pepper, +/obj/item/chems/spray/pepper, +/obj/item/chems/spray/pepper, +/obj/item/chems/spray/pepper, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/security/warden) +"cuZ" = ( +/obj/structure/filing_cabinet/chestdrawer, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/security{ + c_tag = "Security - Warden's Office" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"cva" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"cvb" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cvc" = ( +/obj/structure/table, +/obj/machinery/reagentgrinder, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cvd" = ( +/obj/structure/closet/l3closet/scientist, +/obj/item/clothing/head/bio_hood/scientist, +/obj/item/clothing/suit/bio_suit/scientist, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cve" = ( +/obj/structure/table, +/obj/item/chems/spray/cleaner, +/obj/item/hand_labeler, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cvf" = ( +/obj/structure/rack, +/obj/item/crowbar, +/obj/item/radio/off, +/obj/item/wrench, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"cvg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"cvh" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/exodus/security/warden) +"cvi" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cvj" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cvk" = ( +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"cvl" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cvo" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cvq" = ( +/obj/structure/table, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/obj/item/food/animal_cube/wrapped/monkey, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cvt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"cvy" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cvA" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cvC" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cvD" = ( +/obj/structure/disposalpipe/junction{ + dir = 8; + icon_state = "pipe-j2" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cvE" = ( +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cvF" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cvG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cvH" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cvJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cvK" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/item/box/gloves{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/box/masks, +/obj/machinery/camera/network/medbay{ + c_tag = "Virology Port"; + dir = 4 + }, +/obj/structure/table/glass, +/obj/effect/floor_decal/corner/lime{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cvL" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cvM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cvN" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/incinerator) +"cvO" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/newscaster{ + pixel_x = 28; + pixel_y = 3 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cvP" = ( +/obj/structure/disposalpipe/junction{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cvS" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cvZ" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cwa" = ( +/obj/structure/closet/l3closet/scientist, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cwb" = ( +/obj/structure/table, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cwc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table, +/obj/item/scanner/xenobio, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cwd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cwe" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cwf" = ( +/obj/machinery/power/solar{ + id_tag = "starboardsolar"; + name = "Starboard Solar Array" + }, +/obj/structure/cable/yellow, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cwm" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cwn" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cwo" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cwp" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cwt" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/command{ + name = "Research Director" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/crew_quarters/heads/hor) +"cwu" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cwv" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cww" = ( +/obj/machinery/shieldgen, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cwx" = ( +/obj/machinery/shieldwallgen, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cwy" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cwz" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/light_switch{ + pixel_y = 27 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cwO" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Hard Storage" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/storage) +"cwQ" = ( +/obj/structure/table, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/obj/item/box/animal_cubes/monkeys, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cwR" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cwU" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"cwW" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering{ + name = "Engineering Hard Storage" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/storage) +"cwX" = ( +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_y = 32 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance{ + name = "Engineering\\Medbay Maintenance" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engineering) +"cwZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"cxb" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan, +/turf/floor/plating, +/area/exodus/maintenance/arrivals) +"cxe" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"cxs" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Research Director's Desk"; + name = "Research Director RC"; + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"cxt" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"cxu" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cxv" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/passive_gate/on, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cxx" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cxy" = ( +/obj/machinery/recycler, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cxz" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cxA" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cxC" = ( +/obj/machinery/camera/network/research{ + c_tag = "Research - RD's Office"; + dir = 1 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -25 + }, +/obj/structure/filing_cabinet/chestdrawer, +/obj/machinery/light, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"cxD" = ( +/obj/structure/tank_rack/hydrogen, +/obj/machinery/light, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cxF" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Incinerator Access" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/incinerator) +"cxG" = ( +/obj/machinery/atmospherics/binary/pump, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cxH" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cxI" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"cxJ" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"cxK" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/cargo) +"cxM" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/closet/secure_closet/personal/patient, +/obj/effect/floor_decal/corner/lime{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cxN" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/medical{ + name = "Virology Laboratory" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cxP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cxQ" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cxV" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "xenobio1"; + name = "xenobio1" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/door/window/westright{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cxW" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cxX" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cyh" = ( +/obj/machinery/photocopier, +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"cyi" = ( +/obj/effect/floor_decal/corner/grey/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/heads/hor) +"cyq" = ( +/obj/machinery/computer/guestpass{ + pixel_y = 28 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"cyv" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cyx" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cyy" = ( +/obj/item/belt/utility, +/obj/item/belt/utility, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cyz" = ( +/obj/structure/chair, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cyA" = ( +/obj/machinery/fabricator, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cyD" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cyE" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Toxins Storage" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/research/storage) +"cyF" = ( +/mob/living/simple_animal/passive/mouse, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cyG" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals Southeast"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"cyI" = ( +/obj/structure/chair/office/dark, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cyJ" = ( +/obj/machinery/network/requests_console{ + department = "Virology"; + name = "Virology Requests Console"; + pixel_x = -32; + dir = 8 + }, +/obj/structure/table/glass, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cyK" = ( +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/item/chems/spray/cleaner, +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cyL" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"cyN" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cyP" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cyU" = ( +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cyV" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/engineering/atmos/storage) +"cyY" = ( +/obj/item/toolbox/mechanical{ + pixel_y = 5 + }, +/obj/item/toolbox/mechanical{ + pixel_y = 5 + }, +/obj/item/toolbox/electrical, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cyZ" = ( +/obj/item/paint_sprayer, +/obj/item/multitool{ + pixel_x = 5 + }, +/obj/item/t_scanner, +/obj/item/chems/spray/cleaner, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"cza" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"czb" = ( +/obj/machinery/light, +/obj/item/wrench, +/obj/item/flashlight, +/obj/machinery/cell_charger, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"czc" = ( +/obj/machinery/network/requests_console{ + department = "Engineering"; + name = "Engineering RC"; + pixel_y = -32 + }, +/obj/structure/reagent_dispensers/watertank, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/workshop) +"czd" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cze" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "exodus_rescue_shuttle_dock_airlock"; + pixel_y = 25; + tag_airpump = "exodus_rescue_shuttle_dock_pump"; + tag_chamber_sensor = "exodus_rescue_shuttle_dock_sensor"; + tag_exterior_door = "exodus_rescue_shuttle_dock_outer"; + tag_interior_door = "exodus_rescue_shuttle_dock_inner" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"czf" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "virology_inner"; + name = "Engineering External Access" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/medbay) +"czg" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"czi" = ( +/obj/machinery/atmospherics/tvalve/digital/bypass{ + dir = 1; + icon_state = "map_tvalve0"; + state = 0 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"czj" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "exodus_rescue_shuttle_dock_pump" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"czk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/button/access/interior{ + id_tag = "exodus_rescue_shuttle_dock_airlock"; + name = "interior access button"; + pixel_x = -8; + pixel_y = 26 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"czn" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czp" = ( +/obj/machinery/light, +/obj/machinery/computer/modular/preset/medical{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "exodus_rescue_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"czr" = ( +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czs" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czu" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czv" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czx" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"czy" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "exodus_rescue_shuttle_dock_pump" + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"czA" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering) +"czD" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"czE" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"czI" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"czN" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"czO" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"czP" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cAe" = ( +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cAi" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/machinery/airlock_sensor{ + id_tag = "exodus_rescue_shuttle_dock_sensor"; + pixel_x = -25; + dir = 4 + }, +/turf/floor/plating, +/area/exodus/hallway/secondary/entry/aft) +"cAj" = ( +/obj/machinery/embedded_controller/radio/airlock/access_controller{ + dir = 1; + id_tag = "incinerator_access_control"; + name = "Incinerator Access Console"; + pixel_x = -6; + pixel_y = -26; + tag_exterior_door = "incinerator_airlock_exterior"; + tag_interior_door = "incinerator_airlock_interior" + }, +/obj/machinery/button/ignition{ + id_tag = "Incinerator"; + pixel_x = 6; + pixel_y = -24 + }, +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/maintenance/incinerator) +"cAk" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "exodus_rescue_shuttle_dock_inner"; + name = "Docking Port Airlock" + }, +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/secondary/entry/aft) +"cAp" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cAt" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cAz" = ( +/obj/machinery/door/window/southright{ + autoset_access = 0; + dir = 1; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cAB" = ( +/obj/machinery/light, +/obj/structure/reagent_dispensers/watertank, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cAD" = ( +/obj/machinery/light, +/obj/structure/closet, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/xenobiology) +"cAN" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cAP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cAV" = ( +/turf/floor/plating, +/area/exodus/maintenance/incinerator) +"cBl" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cBm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cBn" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cBo" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cBp" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cBq" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"cBs" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cBt" = ( +/obj/structure/table, +/obj/item/box/cups, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cBu" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/hallway/secondary/entry/port) +"cBz" = ( +/obj/structure/table/steel, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cBA" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cBB" = ( +/obj/machinery/door/window/southright{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio4"; + name = "xenobio4" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cBD" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engi_shuttle) +"cBH" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"cBI" = ( +/obj/machinery/oxygen_pump, +/turf/wall/prepainted, +/area/exodus/medical/medbay) +"cBN" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/drone_fabrication) +"cBW" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cBX" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cBY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cBZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cCa" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/incinerator) +"cCb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/incinerator) +"cCf" = ( +/obj/structure/closet/crate/solar_assembly, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cCq" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cCx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/sign/warning/secure_area{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"cCz" = ( +/obj/structure/rack{ + dir = 1 + }, +/obj/item/clothing/suit/fire, +/obj/item/tank/oxygen, +/obj/item/clothing/mask/gas, +/obj/item/chems/spray/extinguisher, +/obj/item/clothing/head/hardhat/red, +/obj/item/clothing/glasses/meson, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cCA" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cCC" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cCJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/space) +"cCO" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"cCP" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/fore) +"cCR" = ( +/obj/machinery/atmospherics/valve, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cCS" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/green, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cCT" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cCV" = ( +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cCW" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Virology Cafeteria" + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cCX" = ( +/obj/structure/table, +/obj/machinery/microwave{ + pixel_x = -3; + pixel_y = 6 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cCY" = ( +/obj/structure/table, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cDc" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/pods) +"cDd" = ( +/obj/machinery/door/window/southright{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio5"; + name = "xenobio5" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cDf" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cDg" = ( +/obj/structure/table/steel, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cDh" = ( +/obj/machinery/cryopod/robot{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDi" = ( +/obj/machinery/computer/cryopod/robot, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDj" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDk" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_smes) +"cDm" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/abstract/landmark/latejoin/cyborg, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDr" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_airlock) +"cDt" = ( +/obj/structure/chair, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDu" = ( +/obj/machinery/recharge_station, +/obj/machinery/light_switch{ + pixel_y = 27 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDw" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/engineering{ + name = "Engine Monitoring Room" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_monitoring) +"cDx" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + name = "Engine Access" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_airlock) +"cDy" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDA" = ( +/obj/machinery/computer/drone_control{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDB" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cDC" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cDE" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/visible, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"cDF" = ( +/obj/machinery/door/airlock/glass{ + autoclose = 0; + heat_proof = 1; + id_tag = "incinerator_airlock_interior"; + locked = 1; + name = "Mixing Room Interior Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/incinerator) +"cDJ" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_monitoring) +"cDL" = ( +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cDM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cDN" = ( +/obj/machinery/washing_machine, +/obj/effect/floor_decal/corner/red/diagonal, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cDR" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cDS" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cDU" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDV" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDW" = ( +/obj/machinery/recharge_station, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cDY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cEd" = ( +/obj/structure/table, +/obj/machinery/microwave{ + pixel_x = -2; + pixel_y = 5 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cEe" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cEk" = ( +/obj/machinery/drone_fabricator, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cEn" = ( +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cEo" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cEp" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cEr" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cEt" = ( +/turf/floor/reinforced, +/area/exodus/maintenance/incinerator) +"cEu" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "air_in"; + use_power = 1 + }, +/obj/machinery/sparker{ + id_tag = "Incinerator"; + pixel_x = -20 + }, +/turf/floor/reinforced, +/area/exodus/maintenance/incinerator) +"cEw" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cEx" = ( +/obj/structure/table, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cEy" = ( +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cEz" = ( +/obj/machinery/computer/arcade, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cEA" = ( +/obj/structure/disposaloutlet{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cEE" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cEF" = ( +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/structure/table/steel, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cEI" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cEJ" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Drone Fabrication" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/drone_fabrication) +"cEL" = ( +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cEM" = ( +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cEN" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cEU" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cEV" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cEW" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/green, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cEX" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cEZ" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cFb" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/closet/secure_closet/personal/patient, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/jumpsuit/white, +/obj/item/clothing/shoes/color/white, +/obj/item/clothing/shoes/color/white, +/obj/item/clothing/shoes/color/white, +/obj/item/clothing/shoes/color/white, +/obj/item/clothing/shoes/color/white, +/obj/item/clothing/shoes/color/white, +/obj/item/clothing/shoes/color/white, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cFt" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cFA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cFC" = ( +/obj/machinery/computer/shuttle_control/engineering{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/camera/network/engineering{ + c_tag = "Engineering Shuttle Access"; + dir = 8 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_shuttle) +"cFH" = ( +/obj/machinery/vending/coffee{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cFI" = ( +/obj/machinery/vending/snack{ + dir = 8 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cFL" = ( +/obj/machinery/power/tracker, +/obj/structure/cable/yellow, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/starboard) +"cFM" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/purple/diagonal{ + dir = 4 + }, +/obj/item/folder/cyan, +/obj/structure/noticeboard{ + dir = 4; + default_pixel_x = -28 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"cFR" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk, +/turf/floor/tiled/white, +/area/exodus/research) +"cFT" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "engine_airlock_pump" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"cFU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/exodus/research) +"cFY" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"cFZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"cGc" = ( +/obj/abstract/landmark/latejoin/cyborg, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cGd" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cGf" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/camera/network/engine{ + c_tag = "Engineering SMES"; + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cGi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cGk" = ( +/obj/structure/table/reinforced, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/camera/network/engine{ + c_tag = "Engine Monitoring Room"; + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cGm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cGn" = ( +/obj/structure/chair/office/dark, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cGo" = ( +/obj/structure/table/reinforced, +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"cGr" = ( +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"cGs" = ( +/obj/machinery/door/window/southright{ + autoset_access = 0; + name = "Containment Pen"; + req_access = list("ACCESS_XENOBIO") + }, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "xenobio6"; + name = "xenobio6" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/reinforced, +/area/exodus/research/xenobiology) +"cGt" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_room) +"cGA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "engineering_dock_inner"; + name = "Engineering Dock Airlock" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engi_shuttle) +"cGC" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cGI" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cGK" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/exodus/medical/virology) +"cGM" = ( +/obj/machinery/door/airlock/glass{ + autoclose = 0; + heat_proof = 1; + id_tag = "incinerator_airlock_exterior"; + locked = 1; + name = "Mixing Room Exterior Airlock" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/incinerator) +"cGQ" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 6 + }, +/turf/space, +/area/space) +"cGR" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/turf/space, +/area/space) +"cGS" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 8 + }, +/obj/structure/lattice, +/obj/structure/grille, +/turf/space, +/area/space) +"cGU" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/structure/cable/cyan{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cGV" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cGW" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cGX" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cGZ" = ( +/obj/machinery/computer/drone_control{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cHa" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/light, +/obj/machinery/fabricator/robotics, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cHb" = ( +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHc" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/turf/space, +/area/space) +"cHf" = ( +/obj/machinery/light, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power_sensor{ + id_tag = "Master"; + name = "Powernet Sensor - Master Grid" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cHg" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/drone_fabrication) +"cHl" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cHm" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/machinery/light, +/obj/machinery/button/alternate/door/bolts{ + id_tag = "engine_electrical_maintenance"; + name = "Door Bolt Control"; + pixel_x = 5; + pixel_y = -25; + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_smes) +"cHq" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/turf/space, +/area/space) +"cHt" = ( +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHu" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHw" = ( +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHy" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/space, +/area/space) +"cHA" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_airlock) +"cHB" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/ion_thruster{ + dir = 4; + icon_state = "nozzle" + }, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"cHD" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHE" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cHF" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHK" = ( +/obj/item/stack/material/rods{ + amount = 10 + }, +/turf/space, +/area/space) +"cHL" = ( +/obj/machinery/atmospherics/valve/digital{ + dir = 4; + name = "Emergency Cooling Valve 1" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHM" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHP" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/space, +/area/space) +"cHR" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_waste) +"cHT" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/camera/network/engine{ + c_tag = "Engine Waste Handling" + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cHU" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/sign/warning/radioactive{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cHY" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cHZ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIa" = ( +/obj/machinery/emitter{ + anchored = 1; + id_tag = "EngineEmitter"; + state = 2 + }, +/obj/structure/cable/cyan, +/obj/machinery/power/terminal{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIb" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable/yellow, +/obj/machinery/power_sensor{ + id_tag = "Engine Output"; + name = "Powernet Sensor - Engine Output" + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIc" = ( +/obj/item/stack/cable_coil, +/turf/space, +/area/space) +"cId" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/machinery/alarm/nobreach{ + pixel_y = 22 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIe" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIl" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/turf/space, +/area/space) +"cIm" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 4 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"cIn" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/turf/space, +/area/space) +"cIo" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/turf/space, +/area/space) +"cIp" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/engineering/engine_waste) +"cIq" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIr" = ( +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIs" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/maintenance{ + name = "Engine Waste Handling" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/engi_engine) +"cIu" = ( +/obj/machinery/power/solar{ + id_tag = "portsolar"; + name = "Port Solar Array" + }, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cIv" = ( +/obj/machinery/power/solar{ + id_tag = "portsolar"; + name = "Port Solar Array" + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cIw" = ( +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cIx" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/black, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIC" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cID" = ( +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIF" = ( +/obj/machinery/atmospherics/binary/circulator{ + anchored = 1; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIG" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIH" = ( +/obj/machinery/atmospherics/binary/circulator{ + anchored = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIJ" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIK" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/portsolar) +"cIL" = ( +/turf/wall/r_wall/prepainted, +/area/exodus/maintenance/engi_engine) +"cIN" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIO" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/turf/space, +/area/space) +"cIQ" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cIU" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cIV" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIX" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIY" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 9 + }, +/obj/machinery/door/window/brigdoor/westleft{ + name = "Engine Waste" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cIZ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJa" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/plating, +/area/exodus/hallway/primary/central_two) +"cJb" = ( +/obj/structure/cable/cyan{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJd" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJe" = ( +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJf" = ( +/obj/machinery/apc{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJh" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJi" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cJj" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/obj/machinery/meter, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cJk" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/aft) +"cJl" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cJn" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/smes/buildable{ + RCon_tag = "Solar - Aft Port" + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cJo" = ( +/obj/structure/window/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJs" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJt" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJu" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJv" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJx" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJD" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/sign/warning/radioactive{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cJF" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJG" = ( +/obj/machinery/door/airlock/engineering{ + name = "Aft Port Solar Access" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/portsolar) +"cJH" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJI" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJL" = ( +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine control room blast doors."; + id_tag = "EngineBlast"; + name = "Engine Monitoring Room Blast Doors"; + pixel_x = 5; + pixel_y = -25 + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine charging port."; + id_tag = "SupermatterPort"; + name = "Reactor Blast Doors"; + pixel_x = -5; + pixel_y = -25 + }, +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJM" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJO" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJP" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJT" = ( +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cJU" = ( +/obj/machinery/camera/network/engine{ + c_tag = "Engine Core West"; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJV" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cJW" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJX" = ( +/obj/machinery/space_heater, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJY" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cJZ" = ( +/obj/machinery/generator{ + anchored = 1; + dir = 4 + }, +/obj/structure/cable/yellow, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKa" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/obj/machinery/meter, +/obj/machinery/camera/network/engine{ + c_tag = "Engine Core East"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKd" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKf" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKg" = ( +/turf/wall/prepainted, +/area/exodus/maintenance/engi_engine) +"cKk" = ( +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine radiator viewport shutters."; + id_tag = "EngineRadiatorViewport"; + name = "Engine Radiator Viewport Shutters"; + pixel_x = 25; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 4 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKr" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cKu" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKv" = ( +/obj/machinery/air_sensor{ + id_tag = "engine_sensor" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/reinforced, +/area/exodus/engineering/engine_room) +"cKw" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "cooling_in"; + name = "Coolant Injector"; + pixel_y = 1; + power_rating = 30000; + use_power = 1; + volume_rate = 700 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/reinforced/airless, +/area/exodus/engineering/engine_room) +"cKx" = ( +/obj/structure/sign/warning/vent_port{ + pixel_y = 32 + }, +/turf/space, +/area/space) +"cKB" = ( +/obj/machinery/atmospherics/unary/vent_pump/engine{ + dir = 1; + external_pressure_bound = 100; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "cooling_out"; + initialize_directions = 1; + pump_direction = 0; + use_power = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/engine_room) +"cKC" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKE" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKH" = ( +/obj/structure/sign/warning/radioactive{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cKI" = ( +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/engineering) +"cKM" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cKN" = ( +/obj/machinery/power/tracker, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/solarpanel, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cKO" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "engineering_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/exodus_pod_engineering) +"cKU" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cKV" = ( +/obj/machinery/airlock_sensor{ + id_tag = "virology_sensor"; + pixel_x = 25; + pixel_y = 12 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "virology_airlock"; + pixel_x = 25; + tag_airpump = "virology_pump"; + tag_chamber_sensor = "virology_sensor"; + tag_exterior_door = "virology_outer"; + tag_interior_door = "virology_inner" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cKW" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "virology_pump" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cKX" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"cKY" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "virology_pump" + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cKZ" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/plating, +/area/exodus/maintenance/medbay) +"cLc" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + id_tag = "engineering_shuttle"; + pixel_y = 25; + tag_door = "engineering_shuttle_hatch" + }, +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cLe" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Drone Fabrication/Engine Waste Handling" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/drone_fabrication) +"cLf" = ( +/obj/machinery/door/airlock/hatch{ + id_tag = "engine_electrical_maintenance"; + locked = 1; + name = "Electrical Maintenance" + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLg" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + id_tag = "engine_airlock_interior"; + name = "Engine Airlock Interior" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLh" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/engine_room) +"cLi" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/engine_room) +"cLj" = ( +/obj/machinery/computer/ship/helm{ + dir = 8 + }, +/obj/effect/overmap/visitable/ship/landable/pod/engineering, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cLk" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cLm" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLp" = ( +/obj/machinery/light_switch{ + pixel_x = 12; + pixel_y = 25 + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/obj/machinery/power_sensor{ + id_tag = "Engine Power"; + name = "Powernet Sensor - Engine Power" + }, +/obj/machinery/apc/super/critical{ + dir = 1; + name = "north bump"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLs" = ( +/obj/machinery/power/solar_control{ + dir = 4; + id_tag = "portsolar"; + name = "Aft Port Solar Control" + }, +/obj/structure/cable/yellow, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cLt" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"cLu" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/light, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cLv" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Aft Port Access"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cLw" = ( +/turf/floor/greengrid/nitrogen, +/area/exodus/engineering/engine_room) +"cLx" = ( +/obj/machinery/camera/network/engine{ + c_tag = "Engine Core South"; + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/reinforced/airless, +/area/exodus/engineering/engine_room) +"cLy" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLz" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLA" = ( +/obj/machinery/atmospherics/valve/digital{ + dir = 4; + name = "Emergency Cooling Valve 2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLB" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLC" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cLD" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLE" = ( +/obj/machinery/door/airlock/hatch{ + id_tag = "engine_access_hatch"; + locked = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_room) +"cLF" = ( +/obj/machinery/door/airlock/hatch{ + id_tag = "engine_access_hatch"; + locked = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/engine_room) +"cLI" = ( +/obj/machinery/button/blast_door{ + id_tag = "EngineVent"; + name = "Reactor Ventillatory Control"; + pixel_x = -25; + dir = 4 + }, +/obj/structure/window/reinforced, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"cLJ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cLK" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "robotics_solar_outer"; + name = "Engineering External Access" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/portsolar) +"cLL" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cLP" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/exodus/solar/port) +"cLQ" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24 + }, +/obj/structure/cable, +/obj/machinery/camera/network/engineering{ + c_tag = "Solar Maintenance Aft Port"; + dir = 1 + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cLS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cLU" = ( +/turf/space, +/area/space) +"cLZ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cMa" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/obj/machinery/meter{ + id_tag = "wloop_atm_meter" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cMb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/engineering/engine_waste) +"cMe" = ( +/obj/structure/disposalpipe/segment, +/obj/random/obstruction, +/turf/floor/plating, +/area/exodus/medical/genetics) +"cMf" = ( +/obj/item/shard, +/turf/floor/plating, +/area/exodus/medical/genetics/cloning) +"cMg" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/portsolar) +"cMh" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/exodus/maintenance/engi_engine) +"cMF" = ( +/obj/machinery/material_processing/compressor, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"cNa" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"cQw" = ( +/obj/machinery/computer/ship/engines{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"cQX" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/machinery/shieldwallgen, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"cSp" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"cUO" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"cYR" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"djd" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"dkO" = ( +/obj/machinery/computer/shuttle_control/explore/mining, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"doN" = ( +/obj/abstract/level_data_spawner/main_level{ + name = "Exodus Operations Deck" + }, +/turf/space, +/area/space) +"drB" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/plating, +/area/exodus/engineering/storage) +"drR" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/storage/emergency) +"dvY" = ( +/obj/machinery/vending/snack{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/central_two) +"dxK" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"dEE" = ( +/obj/machinery/cryopod{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"dHF" = ( +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"dJe" = ( +/obj/structure/closet/wardrobe/mixed, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"dKq" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"dMi" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/obj/effect/floor_decal/corner/beige{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"dMn" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"dMz" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/chapel/main) +"dNC" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"dNS" = ( +/obj/effect/shuttle_landmark/exodus_main_port, +/turf/space, +/area/space) +"dQa" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"dRD" = ( +/obj/effect/overmap/visitable/ship/landable/pod/mining, +/obj/machinery/computer/ship/helm, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"ejv" = ( +/obj/effect/shuttle_landmark/research_pod_dock, +/obj/structure/catwalk, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"elq" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Security North" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/security/main) +"esY" = ( +/obj/effect/paint_stripe/blue, +/turf/wall/titanium, +/area/shuttle/arrival/station) +"etN" = ( +/turf/floor/tiled/freezer, +/area/shuttle/arrival/station) +"eut" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"ewE" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"eEn" = ( +/turf/floor/plating/airless, +/area/exodus/turret_protected/ai) +"eEV" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"eJK" = ( +/obj/machinery/network/relay, +/turf/floor/plating, +/area/exodus/maintenance/locker) +"eKH" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/turf/floor/tiled/freezer, +/area/shuttle/arrival/station) +"eNu" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"eTV" = ( +/obj/structure/catwalk, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"eWD" = ( +/obj/structure/catwalk, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/item/radio/beacon, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"eYg" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"eZK" = ( +/obj/effect/floor_decal/corner/purple, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/exodus/research) +"ffg" = ( +/obj/effect/shuttle_landmark/engineering_pod_dock, +/obj/structure/cable/green, +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/item/radio/beacon, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"fhb" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"fmR" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "mining_dock_inner"; + name = "Mining Dock Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/miningdock) +"fnT" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/command{ + name = "E.V.A." + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"fpV" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"fyf" = ( +/obj/structure/catwalk, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"fCE" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"fKm" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"fKS" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"fPv" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 5 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"fPF" = ( +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "bridge blast"; + name = "Bridge Blast Doors" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green, +/turf/floor/plating, +/area/exodus/bridge) +"fTj" = ( +/obj/machinery/mech_recharger, +/obj/effect/floor_decal/industrial/outline/yellow, +/mob/living/exosuit/premade/light/exploration, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"gcu" = ( +/turf/floor/tiled/dark/monotile, +/area/exodus/security/nuke_storage) +"gdx" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/conveyor_switch{ + id_tag = "cargo_mining_conveyor" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"gny" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor, +/area/exodus/quartermaster/miningdock) +"gpG" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"gsd" = ( +/obj/machinery/vending/cola{ + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/exodus/hallway/primary/central_two) +"gwY" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"gyJ" = ( +/obj/machinery/computer/ship/engines{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"gAA" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"gOE" = ( +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/obj/machinery/camera/network/exodus{ + c_tag = "Arrivals - Main Shuttle"; + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"gSL" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Engine - Main"; + charge = 1e+007; + input_attempt = 1; + input_level = 1e+006; + output_attempt = 1; + output_level = 1e+006 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"hbt" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor, +/area/exodus/quartermaster/miningdock) +"hgF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"hkD" = ( +/obj/machinery/light_switch{ + pixel_x = 4; + pixel_y = -24 + }, +/obj/machinery/mech_recharger, +/obj/effect/floor_decal/industrial/outline/yellow, +/mob/living/exosuit/premade/powerloader, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"hoh" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"hsk" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Engine - Main"; + charge = 1e+007; + input_attempt = 1; + input_level = 1e+006; + output_attempt = 1; + output_level = 1e+006 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"htC" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/aft) +"hDl" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = -32 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"hDm" = ( +/obj/machinery/door/window{ + dir = 4; + name = "High-Risk Modules" + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"hLX" = ( +/turf/floor/laminate/walnut, +/area/exodus/library) +"hOb" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"hPt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"hWZ" = ( +/obj/structure/chair, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"hZw" = ( +/obj/structure/catwalk, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"idh" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"idY" = ( +/obj/machinery/power/terminal, +/obj/structure/cable/green, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"igB" = ( +/obj/machinery/hologram/holopad, +/obj/abstract/landmark/latejoin/observer, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"ihN" = ( +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"iok" = ( +/obj/machinery/vending/robotics{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"itc" = ( +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"itS" = ( +/obj/effect/paint/red, +/turf/wall/titanium, +/area/shuttle/arrival/station) +"ixD" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"iFB" = ( +/obj/effect/floor_decal/corner_steel_grid{ + dir = 6 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"iFX" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = -28 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/bridge) +"iKS" = ( +/obj/machinery/conveyor{ + id_tag = "cargo_mining_conveyor" + }, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"iNs" = ( +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"iTt" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"iUa" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/machinery/reagent_temperature/cooler, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"iXX" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/sublevel_access) +"iYA" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"jfD" = ( +/obj/abstract/landmark/start{ + name = "Shaft Miner" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"jko" = ( +/obj/machinery/rad_collector, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"jsn" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"jva" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"jFq" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/exodus/hallway/primary/aft) +"jHW" = ( +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/hallway/primary/central_one) +"jKq" = ( +/turf/wall/prepainted, +/area/exodus/crew_quarters/bar/cabin) +"jYD" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"klA" = ( +/turf/floor/plating, +/area/space) +"klX" = ( +/obj/machinery/light, +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 1; + id_tag = "research_shuttle"; + pixel_y = -25; + tag_door = "research_shuttle_hatch" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"kvT" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/mob/living/simple_animal/hostile/parrot/Poly, +/turf/floor/tiled/steel_grid, +/area/exodus/crew_quarters/heads/chief) +"kxa" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"kSt" = ( +/obj/machinery/vending/coffee{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/exodus/crew_quarters/bar) +"kVV" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"lbI" = ( +/obj/item/chems/glass/beaker/large, +/obj/structure/table/glass, +/obj/item/chems/dropper, +/turf/floor/tiled/white, +/area/exodus/medical/chemistry) +"lfJ" = ( +/obj/item/radio/beacon, +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/turf/floor/tiled/freezer, +/area/shuttle/arrival/station) +"lyt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"lAZ" = ( +/obj/machinery/camera/network/exodus{ + c_tag = "Departures West"; + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"lDi" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor, +/area/ship/exodus_pod_mining) +"lDJ" = ( +/obj/effect/floor_decal/corner_steel_grid{ + dir = 9 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"lFM" = ( +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/turf/floor/tiled/dark, +/area/ship/exodus_pod_engineering) +"miB" = ( +/obj/structure/cable/green, +/obj/machinery/ion_thruster{ + dir = 1; + icon_state = "nozzle" + }, +/turf/floor, +/area/ship/exodus_pod_mining) +"mue" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/medical/sleeper) +"mwu" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/exodus/bridge) +"mGD" = ( +/obj/machinery/fabricator/industrial{ + id_tag = "science" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/robotics) +"mKS" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/glass/engineering{ + dir = 4; + name = "Engineering Locker Room" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering/workshop) +"mLL" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"mNK" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_engineering) +"mVl" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"mYp" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"ngU" = ( +/obj/effect/shuttle_landmark/exodus_main_aft, +/turf/space, +/area/space) +"nky" = ( +/obj/effect/shuttle_landmark/exodus_main_starboard, +/turf/space, +/area/space) +"noV" = ( +/obj/effect/paint/red, +/turf/wall/titanium, +/area/ship/exodus_pod_mining) +"nvs" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"nIv" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/storage) +"nOM" = ( +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/abstract/landmark/latejoin, +/turf/floor/tiled/freezer, +/area/shuttle/arrival/station) +"nPR" = ( +/obj/machinery/shieldwallgen, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"nYi" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"oaC" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/table, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/roller, +/obj/item/clothing/gloves/latex/nitrile, +/turf/floor/tiled/dark, +/area/exodus/research/robotics) +"odK" = ( +/obj/machinery/mech_recharger, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/chargebay) +"ohn" = ( +/obj/machinery/emitter, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/plating, +/area/exodus/engineering/storage) +"ouk" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"oxE" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 8; + id_tag = "mining_shuttle"; + pixel_x = 25; + pixel_y = -8; + tag_door = "mining_shuttle_hatch" + }, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"oAO" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engine_monitoring) +"oDi" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"oWh" = ( +/obj/machinery/network/requests_console{ + department = "Arrival shuttle"; + pixel_y = -32 + }, +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/obj/machinery/cryopod{ + dir = 1 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"pbo" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"poU" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/dark, +/area/exodus/chapel/main) +"pqS" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"pAd" = ( +/obj/structure/cable/green{ + icon_state = "0-4" + }, +/obj/machinery/ion_thruster{ + dir = 4; + icon_state = "nozzle" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"pGo" = ( +/obj/effect/floor_decal/corner/brown{ + dir = 9 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"pWa" = ( +/obj/effect/shuttle_landmark/exodus_main_fore, +/turf/space, +/area/space) +"qlX" = ( +/obj/machinery/hologram/holopad, +/turf/floor/laminate/walnut, +/area/exodus/library) +"qmC" = ( +/obj/effect/floor_decal/corner_steel_grid{ + dir = 5 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"qBY" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/obj/item/radio/beacon, +/turf/floor, +/area/ship/exodus_pod_mining) +"qHi" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/sign/department/cross/star_of_life{ + name = "Medbay"; + pixel_x = 32 + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"qHU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"qJj" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"qJW" = ( +/obj/machinery/computer/atmos_alert{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/engineering_monitoring) +"rhM" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/starboard) +"rkN" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"roQ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/exodus/maintenance/research_starboard) +"rup" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"rwB" = ( +/obj/structure/cable/cyan{ + icon_state = "4-8" + }, +/obj/machinery/light, +/turf/floor/bluegrid, +/area/exodus/turret_protected/ai_upload) +"rAK" = ( +/obj/structure/girder/displaced, +/turf/floor/plating, +/area/exodus/maintenance/evahallway) +"rNu" = ( +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"rPP" = ( +/obj/machinery/computer/ship/engines{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"rQB" = ( +/obj/effect/paint_stripe/yellow, +/turf/wall/titanium, +/area/ship/exodus_pod_engineering) +"rUP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/entry/port) +"rVT" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/chair, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"rYD" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"scJ" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"sdB" = ( +/obj/structure/catwalk, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor, +/area/ship/exodus_pod_mining) +"sfM" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/exodus/bridge) +"sfO" = ( +/obj/effect/floor_decal/corner/lime/three_quarters{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"sgI" = ( +/obj/machinery/conveyor{ + backwards = 8; + dir = 9; + forwards = 2; + id_tag = "cargo_mining_conveyor"; + movedir = 6 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/plating, +/area/exodus/quartermaster/miningdock) +"ssg" = ( +/turf/floor/tiled/techfloor, +/area/exodus/engineering/storage) +"sxY" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"sBp" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/plating, +/area/exodus/engineering/storage) +"sCJ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"sDc" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"sFU" = ( +/obj/effect/floor_decal/corner/brown/diagonal{ + dir = 8 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/crew_quarters/kitchen) +"sGZ" = ( +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"sNl" = ( +/obj/structure/closet/wardrobe/xenos, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"sVy" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/exodus/research/docking) +"sWj" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"sYh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/engineering{ + name = "Engineering Hallway" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/engineering) +"tos" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"tpe" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + icon_state = "1-4" + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"tuN" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/closet/wardrobe/black, +/obj/effect/floor_decal/corner/white/three_quarters, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"tzU" = ( +/obj/machinery/computer/ship/sensors{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/ship/exodus_pod_mining) +"tAY" = ( +/obj/effect/floor_decal/corner/purple/full, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"tCN" = ( +/obj/machinery/computer/ship/sensors{ + dir = 4 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"tDI" = ( +/obj/effect/floor_decal/corner/purple, +/obj/machinery/camera/network/research{ + c_tag = "Research Division North"; + dir = 1 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"tGf" = ( +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/obj/structure/cable/green, +/obj/structure/catwalk, +/turf/floor, +/area/ship/exodus_pod_mining) +"tGo" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"tQY" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/ship/exodus_pod_research) +"tRc" = ( +/obj/effect/paint_stripe/mauve, +/turf/wall/titanium, +/area/ship/exodus_pod_research) +"tUa" = ( +/obj/effect/shuttle_landmark/mining_pod_dock, +/obj/structure/cable/green{ + icon_state = "2-4" + }, +/obj/structure/catwalk, +/turf/floor, +/area/ship/exodus_pod_mining) +"tXh" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/structure/catwalk, +/turf/floor, +/area/ship/exodus_pod_mining) +"tYK" = ( +/obj/effect/floor_decal/corner_steel_grid{ + dir = 10 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"ult" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "mining_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/exodus_pod_mining) +"uoa" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "mining_dock_outer"; + name = "Mining Dock Airlock" + }, +/obj/machinery/shield_diffuser, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/exodus/quartermaster/miningdock) +"uFU" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/exodus/research) +"uGq" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "EngineEmitterPortWest"; + name = "Engine Waste Handling Access" + }, +/turf/floor/plating, +/area/exodus/engineering/engine_room) +"uJB" = ( +/obj/machinery/button/access/exterior{ + id_tag = "mining_dock_airlock"; + name = "exterior access button"; + pixel_x = -5; + pixel_y = 25 + }, +/turf/space, +/area/space) +"uKl" = ( +/obj/effect/floor_decal/corner/yellow/three_quarters, +/obj/structure/sign/warning/secure_area{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering/foyer) +"uRH" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/structure/cable/green{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"vcu" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_one) +"vfH" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"vme" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"vno" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/engineering) +"vHf" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/computer/shuttle_control/mining{ + dir = 4 + }, +/obj/structure/sign/warning/airlock{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"vKw" = ( +/obj/machinery/shipsensors, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/space) +"vRS" = ( +/obj/structure/cable/green{ + icon_state = "1-2" + }, +/obj/structure/catwalk, +/turf/floor, +/area/ship/exodus_pod_mining) +"vVU" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ship/exodus_pod_research) +"wby" = ( +/turf/floor/tiled/techfloor/grid, +/area/exodus/maintenance/locker) +"wht" = ( +/obj/structure/catwalk, +/turf/floor, +/area/ship/exodus_pod_mining) +"wiC" = ( +/obj/item/stack/material/ore/silver, +/obj/item/stack/material/ore/silver, +/obj/item/stack/material/ore/iron, +/obj/structure/closet/crate, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "mining_dock_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/structure/sign/warning/docking_area{ + dir = 1; + pixel_y = -32 + }, +/turf/floor, +/area/exodus/quartermaster/miningdock) +"wjf" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"woj" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Library Rec Area" + }, +/turf/floor/laminate/walnut, +/area/exodus/library) +"wqh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/lime{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/starboard) +"wsi" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/white{ + dir = 10 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"wAA" = ( +/obj/structure/closet/emcloset, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/machinery/camera/network/civilian_west{ + c_tag = "Cargo Mining Dock Airlock"; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor, +/area/exodus/quartermaster/miningdock) +"wBc" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"wJf" = ( +/obj/structure/table, +/turf/floor/tiled/white, +/area/exodus/research/robotics) +"wTp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/exodus/teleporter) +"wVz" = ( +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"xhz" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_two) +"xpO" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/fabricator/industrial, +/obj/item/stack/material/ingot/mapped/osmium/ten, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/miningdock) +"xrP" = ( +/turf/floor/laminate/walnut, +/area/exodus/engineering/break_room) +"xFu" = ( +/obj/effect/floor_decal/corner/lime{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/port) +"xHt" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/obj/machinery/camera/network/research{ + c_tag = "Research Shuttle Dock Airlock" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/research/docking) +"xJn" = ( +/obj/machinery/power/smes/buildable{ + RCon_tag = "Engine - Main"; + charge = 1e+007; + input_attempt = 1; + input_level = 1e+006; + output_attempt = 1; + output_level = 1e+006 + }, +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/cable/green{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/ship/exodus_pod_mining) +"xOe" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/exodus/research) +"xTe" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Sorting Office" + }, +/turf/floor/tiled/steel_grid, +/area/exodus/quartermaster/office) +"xVx" = ( +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/abstract/landmark/latejoin, +/turf/floor/tiled/dark/monotile, +/area/shuttle/arrival/station) +"xVT" = ( +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/white{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"xZr" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/lime{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/primary/central_three) +"yce" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) +"yeJ" = ( +/obj/machinery/light, +/obj/machinery/shieldwallgen, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/exodus/teleporter) +"yjb" = ( +/obj/structure/cable/green, +/obj/machinery/apc/super/critical{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/steel_grid, +/area/exodus/hallway/secondary/exit) + +(1,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cpf +"} +(2,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(3,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(4,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(5,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +doN +cLU +cLU +cLU +cLU +"} +(6,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(7,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(8,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(9,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(10,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(11,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(12,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(13,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(14,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(15,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(16,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(17,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(18,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(19,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(20,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(21,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(22,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(23,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(24,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(25,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(26,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(27,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(28,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(29,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(30,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cec +aFD +cec +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(31,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cec +cex +cec +cLU +aaf +apc +aGy +aph +aph +aph +aph +aDe +apc +aaf +aKz +aLE +aLP +axF +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(32,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cec +cec +cec +atS +cec +ceI +cec +atS +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +axF +aVg +aYk +axF +aaf +crP +crP +crP +crP +crP +crP +aaf +crP +crP +crP +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(33,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +ave +ayd +aAl +bdy +cer +ceH +axH +cec +cLU +cLU +esY +aIw +aIw +aIw +esY +cLU +cLU +aaf +axF +aVf +aYi +axF +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +ctn +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(34,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +avN +ayj +aAp +brq +cev +azk +ays +cec +cLU +cLU +esY +aDg +rNu +aDh +esY +cLU +cLU +aBI +axF +aBK +aYm +axF +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(35,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cec +cec +cec +atS +btE +azk +ays +cec +cLU +cLU +esY +aID +iFB +iNs +esY +cLU +cLU +aHF +aBE +aBF +aDn +aBI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(36,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cec +bvY +awH +azh +atS +cLU +esY +esY +aMV +aDK +aMV +esY +esY +cLU +aBI +aCe +aCz +aSH +aBI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(37,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cec +buv +azt +ayZ +cec +cec +esY +aGq +dJe +lDJ +sNl +tuN +esY +axF +axF +aBV +aBX +aTr +aBI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bgo +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(38,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cec +buv +azt +azi +azs +aAq +aAw +qmC +aFM +igB +aFM +tYK +aAw +aAx +aBt +aCi +aBX +aVl +axF +cLU +cLU +cLU +cLU +cLU +bgo +cLU +cLU +cLU +cLU +cLU +bIQ +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(39,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cec +azq +azt +azk +azr +cec +esY +aGx +aFM +aFM +aFM +wsi +esY +axF +aBk +aRD +aBX +aVj +axF +cLU +cLU +cLU +cLU +cLU +bIQ +cLU +cLU +cLU +cLU +cLU +aDF +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(40,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +auN +bvY +azt +azk +azv +cec +esY +cwU +xVx +aFM +xVx +aIk +esY +axF +aBw +aRD +aBX +aVj +axF +cLU +cLU +cLU +cLU +cLU +aDF +cLU +cLU +cLU +cLU +cLU +aDF +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(41,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +auN +azu +azt +azk +aBr +cec +aDj +dHF +aFM +aFM +aFM +aCA +aDj +axF +aBv +aRD +aBX +aVj +axF +cLU +cLU +cLU +cLU +cLU +aDF +cLU +cLU +cLU +cLU +cLU +aCj +aCj +aCj +aCj +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +eYg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(42,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +auN +asz +aAt +azk +aAn +cec +aDj +aIy +gOE +aFM +xVx +itc +aDj +axF +aBB +aRD +aEz +aVm +axF +cLU +cLU +cLU +cLU +cLU +aDF +cLU +cLU +cLU +cLU +cLU +aCj +czj +cAi +aQd +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(43,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aqD +asA +asA +auN +asy +aAE +azk +aAm +cec +esY +aMV +aMV +aDK +aMV +aMV +esY +axF +aBx +aRD +aDq +aVj +axF +cLU +cLU +cLU +cLU +cLU +bgo +cLU +cLU +cLU +cLU +cLU +aCj +cze +czy +aQc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(44,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +aaf +aaf +aqD +aqD +aqD +aqD +aqD +aqD +aqD +avL +aym +auN +avY +aAE +azk +azr +cec +esY +aNP +eKH +etN +eKH +oWh +esY +axF +aBk +aRD +aDq +aVj +axF +cLU +cLU +cLU +cLU +cLU +bgo +cLU +cLU +cLU +cLU +cLU +aCj +czq +cAk +aCj +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(45,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +cLU +cLU +cLU +atX +atX +atX +ajN +aqQ +asA +avc +axx +auN +ctA +aAE +azm +aAo +cec +esY +aGH +nOM +lfJ +nOM +dEE +esY +axF +aBC +aCn +aDq +aVl +axF +cLU +cLU +cLU +cLU +cLU +bgo +cLU +cLU +cLU +cLU +cLU +aCj +czk +bsL +aCj +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(46,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +aph +aaf +cLU +cLU +ato +apC +afB +awB +atQ +auf +auW +axx +atZ +cul +aAE +ayZ +cec +cec +esY +esY +aGb +aGb +aGb +esY +esY +axF +axF +aBV +aDq +aVj +axF +aaf +aCj +aNl +aCj +aaf +bgo +aaf +aCj +aOd +aCj +cLU +aCj +bgw +bsP +bGB +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +dNS +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(47,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +aaf +aaf +cLU +atX +atX +atX +ajN +atq +asA +avM +axx +atZ +aCt +aAE +azp +cec +cLU +itS +aEI +aEI +aEI +aEI +aEI +itS +cLU +axF +aCe +aCB +aVj +aBI +aCj +aCj +bhr +aCj +aCj +bgo +aCj +aCj +blS +aCj +aCj +aCj +bgw +bsP +bgo +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(48,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +aaf +aaf +aaf +aaf +aqD +aqD +aqD +aqD +asA +awe +ayq +ayO +azl +aDA +cCP +aBI +aBI +aBI +aBI +aBI +aBI +aBI +aBI +aBI +aBI +aBI +aRI +aDq +aVo +cBu +aYo +aDF +aGB +aDF +beq +bgr +beq +aCj +aTj +aCj +bnu +boZ +bht +bsQ +bgo +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(49,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +cLU +aaf +cLU +aud +aud +aud +avf +aqQ +asA +awI +ayo +atZ +aEY +cvg +cvt +aFN +cxe +cxt +cxt +cxt +cxt +aGV +cxt +cxI +cxJ +cyG +cyL +cza +aVn +aWF +aYn +aZO +bbz +bdi +bep +bdH +bhu +aZO +bkq +aZO +bnt +boY +bho +bsP +aCj +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(50,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +cLU +cLU +cLU +atu +asx +ahM +awC +atQ +auV +awG +ayo +atZ +ayy +aFB +aFL +aFP +aCw +aDo +aEL +aEL +aHI +aJt +aLt +rUP +aOK +rUP +rUP +aTt +aVp +aYK +aYp +aZQ +bbB +bdj +ber +bfL +aHN +bgY +bks +blo +bnv +bpa +brc +cJk +aCj +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(51,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +aac +cLU +cLU +aud +aud +aud +avf +atq +asA +awJ +ayo +auN +auN +auN +auN +aBL +aBL +aBL +aBL +aBL +aIA +aIM +aJA +atJ +atJ +atJ +atJ +aPs +aJA +aIA +aQJ +aUC +aUC +aUC +aUC +bgr +aHM +bgr +bgr +bgr +bgr +bgr +bgr +bgr +bgr +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(52,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aph +aaf +aaf +aqD +aqD +aqD +aqD +aqD +aqD +aqD +cDc +ayr +ayS +avH +avH +avH +cum +aCE +aDz +aEN +aGf +aIA +aId +aLy +aMX +aRx +aQj +aRJ +aTv +aLy +aRp +aYq +cgL +aZX +aYq +aYq +aYO +aHV +bjp +aTl +bmg +biS +bpb +aMv +bsS +aQg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(53,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +crP +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aqD +asA +asA +auQ +aGr +aQi +avH +aBD +aCE +aDr +aEM +aGd +aHJ +aJE +aLu +aMX +aOg +cgu +aRJ +aTu +aLy +aRp +aYq +aZV +aZX +bdk +bes +aYO +beM +bjp +bkQ +bjp +aGt +bjp +bfd +aSr +bjp +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(54,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +auQ +auQ +cnl +auQ +ayp +aBD +aCE +aDx +aES +aGj +atJ +aJH +aLy +aMY +aPh +aPh +aMY +rhM +aLy +aRp +aYu +aZX +aZX +aZX +bev +aYO +aJv +biT +bkR +aFa +bpm +bau +bki +boA +aGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(55,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +avZ +awd +atv +aMW +aRH +bye +aBz +aCE +aBT +aEO +aGh +aHR +aJH +aLy +aMX +aPh +aPh +aRJ +rhM +aLy +aRp +aYs +aZW +aZX +aZW +bet +aYO +aHZ +bjp +bkR +aFa +bnT +aYP +bhv +aYP +aGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(56,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aaI +aaI +aaI +aam +aaI +aaI +aaI +aam +aaI +aaI +aaf +ayl +ayl +ayl +aSN +aAj +aBD +aCE +aDI +aES +aGm +atJ +aJL +aLy +aNa +aIJ +aIJ +aNa +rhM +aLy +aRp +aYw +aZZ +aZX +bdm +bdm +aYO +aHV +bjp +bkS +bjp +aWM +bnF +bjp +bjp +bjp +aaf +crP +crP +crP +crP +crP +crP +crP +crP +crP +aaf +crP +crP +crP +crP +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(57,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +aaf +aaf +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +ayl +aBD +aCE +aFH +aEU +aHj +aIA +aJK +aLy +aIA +aIA +aIA +aIA +aNV +aVs +aWI +aYv +aZY +bbD +bbD +bbD +bhC +aKV +bjp +bkT +bjp +aVr +bpR +bjp +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(58,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aop +apk +apV +cLU +aop +apk +apV +cLU +aop +apk +apV +cLU +cLU +cLU +cLU +ayl +aBD +aCE +aCE +aGP +aCE +aIA +aoS +aLy +aNb +aOP +aQk +aRP +rhM +aVu +aIA +aYz +bab +bbG +bbG +bbV +aYO +aMB +aSU +aTn +bjp +bjp +bkm +bjp +cLU +cLU +cLU +cLU +ctn +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(59,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +aaI +aaf +aop +apj +apV +cLU +aop +apj +apV +cLU +aop +apj +apV +cLU +cLU +cLU +cLU +ayl +aOB +bsi +bke +awV +axJ +aIA +aJO +aLz +aLz +aLz +aLz +aLz +aLz +aVt +aIA +aYx +baa +bbF +bdn +bew +aYO +aOh +bjm +aTm +bmV +bps +bqG +baj +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +crP +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(60,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +aop +apj +apV +aaf +aop +apj +apV +cLU +aop +apj +apV +cLU +cLU +cLU +cLU +ayl +aue +aCy +aDX +cxb +bdw +aIA +aJQ +aLA +aNf +aOR +ewE +aRQ +aTy +aVw +aIA +aYO +aYO +aYO +aYO +aYO +aYO +baj +bqU +aTq +aHq +blv +bqK +aKJ +aaf +cLU +apc +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +apc +aGX +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(61,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aop +apj +apV +cLU +aop +apj +apV +cLU +aop +apj +apV +cLU +cLU +cLU +cLU +auQ +aBP +aCx +auQ +awN +aFC +aFC +aLw +aFC +aLs +nvs +aLy +aIA +aIA +aIA +aIA +aTR +aHq +bag +bdo +beB +bfM +aKe +aSW +aTp +aHq +bnY +bqK +aKJ +cnM +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(62,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aaI +cLU +cLU +aop +apj +apV +cLU +aop +apj +apV +cLU +aop +apj +apV +cLU +cLU +cLU +aoN +aAF +aAF +aAF +aAF +aFx +aFC +aGQ +aJZ +aFC +aNg +aNB +aNg +aLK +bxH +eJK +aXe +aGw +aYQ +bbY +bdp +beF +bfM +aSW +cCO +bml +aHq +bnZ +bqK +brG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(63,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +cLU +cLU +aaf +acy +aaf +aaf +aaf +acy +aaf +cLU +cLU +acy +cLU +cLU +aoN +aoN +aoN +aAv +aBH +aEc +aAF +awX +aFC +aHS +aJS +aFC +aNe +aNz +wjf +aLK +aHq +aHq +aXe +aYR +bai +bai +bai +bai +bai +bai +bai +bmo +bmW +bmW +bqM +brG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaI +aaI +aaI +aaI +aaI +aaI +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(64,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +alX +amL +amL +amL +alV +amL +amL +amL +alV +amL +amL +amL +alV +amL +awW +azj +aAy +aEE +aSE +awD +avi +awf +awZ +aFC +aHU +aJG +aFC +wBc +aOV +scJ +aSV +aVA +aVA +aFj +aYC +baj +bbZ +bbZ +bbZ +bbZ +bbZ +bbZ +bbZ +bbZ +bbZ +bkW +brG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(65,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +cLU +aaf +aaf +acy +aaf +cLU +aaf +acy +aaf +cLU +cLU +acy +cLU +cLU +aoN +aoN +aoN +aAH +aBS +aAs +aAF +aFh +aIK +ayN +aKa +aFC +aNi +aOU +wjf +aLK +aTS +aTS +aTS +aTS +aTS +bbZ +bdq +bbZ +bdq +bbZ +bdq +bbZ +bdq +bbZ +bpU +brG +cLU +cLU +cLU +cLU +cLU +bXm +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(66,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaq +aaI +cLU +aaf +aop +apn +apV +cLU +aop +apn +apV +cLU +aop +apn +apV +cLU +cLU +cLU +aoN +aAF +aAF +aAF +aAF +aHd +aFC +aFC +aFC +aFC +aEp +aOW +wjf +aLK +aTA +aUr +aWJ +aYD +bad +bbZ +bds +bbZ +bfN +bbZ +biV +bbZ +blq +bbZ +bkW +brG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaI +aaI +aaI +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(67,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aop +apn +apV +cLU +aop +apn +apV +cLU +aop +apn +apV +aaf +aaf +cLU +cLU +anX +amo +aCK +aDJ +aFk +aGu +aHY +aHY +auT +wBc +aOW +aQm +aLK +aTz +aTz +aTz +aTz +bac +bbZ +bdr +beG +beG +bhz +biU +beG +beG +bbZ +bkW +brG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cLU +crP +aaf +aaf +crP +cto +aaf +cbO +crP +crP +crP +crP +crP +crP +crP +crP +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(68,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +aop +apn +apV +aaf +aop +apn +apV +aaf +aop +apn +apV +cLU +aaf +cLU +cLU +anX +aBU +aEd +aDM +bBh +bBi +bCu +bDu +bDx +bDI +bDS +bFi +aLK +aKp +aTz +aTz +aTz +baf +bbJ +bdt +beH +bfP +beH +bfP +bku +blr +bbZ +bkW +brG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +aaf +aaf +aaf +aaf +crP +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aam +aam +aam +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(69,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +aaI +aaf +aop +apn +apV +cLU +aop +apn +apV +cLU +aop +apn +apV +cLU +aaf +cLU +cLU +alL +ayC +aCK +aDL +aFn +aFn +aIc +aJT +auT +wBc +aOY +bDV +aLK +aJP +aTz +aWK +aWK +bae +bbZ +bbZ +bbZ +brG +brG +brG +brG +brG +brG +bkW +baj +bXZ +cLU +aLF +aQC +aRB +aLF +aRB +aRF +aLF +cLU +bqY +apc +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +aQh +apc +aGX +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(70,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aop +apo +apV +cLU +aop +apo +apV +cLU +aop +apo +apV +aaf +aaI +cLU +cLU +alL +ayC +aCK +aDO +aFn +aFn +aFn +aJX +auT +wBc +aOY +bFA +aLK +aTE +aTz +aWQ +aWN +bal +aXs +beJ +bfT +brG +bgi +bgi +bgi +bgi +brG +aTQ +baj +aap +cLU +aLF +bxR +bzl +aLF +bCE +bEf +aLF +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aam +aam +aam +aam +aan +aam +aam +aam +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aam +aam +aam +aam +aam +aaf +aaI +aaI +aaI +aam +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(71,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +aaf +aaf +cLU +aaf +aaf +aaf +cLU +aaf +aaf +cLU +cLU +aaI +cLU +cLU +alL +aHQ +aCK +aDN +aFn +aFn +aFn +aJV +auT +wBc +aOY +bFx +aPp +aTz +aTz +cgH +aYA +bak +aTz +bdv +bfS +brG +bgi +bgi +bgi +bgi +wby +aTQ +bdP +aLF +aLF +aLF +bzK +bBu +aLF +bBu +bFb +aLF +cLU +cLU +bNr +bNr +bNr +bNr +tGo +bNr +tGo +bNr +bNr +bNr +noV +cLU +aQh +aaf +aaf +aaf +aaf +aaf +aam +aam +aam +aan +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(72,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aaI +aaI +aaI +aaq +aaI +aaI +aaI +aam +aaI +aaI +aaI +aaI +aaI +cLU +cLU +anX +ayC +aCK +aCh +aFr +aFn +aIi +aHY +auT +aNn +aPe +bFT +aRR +aTJ +aTJ +aXn +aYE +ban +bbN +bfO +bfT +brG +bgi +bgi +bgi +bgi +wby +aTQ +bdP +bhI +bkw +bvU +bxS +bzn +bqW +bwb +bEh +bdP +cLU +cLU +bNr +dkO +idh +tGf +vRS +lDi +vRS +rVT +tzU +rup +miB +cLU +aQh +cLU +cLU +cLU +aaf +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aam +aam +aam +cLU +cLU +aan +aam +aam +aaI +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +cKN +aaf +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(73,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +anX +ayC +aCK +aDP +aFn +aFn +aFn +aJY +auT +wBc +aPd +bFI +aLK +aTF +aVy +aWO +aWK +bam +bbc +aTS +aTS +brG +bgi +bgi +bgi +bgi +brG +bgq +bdP +bsT +brd +bvU +bxS +bzm +brd +bCG +bDL +bdP +cLU +cLU +fKm +dRD +iTt +tUa +vRS +qBY +vRS +idY +xJn +tpe +miB +cLU +aQh +cLU +cLU +cLU +aaf +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +aan +aam +aam +aam +aam +aaf +aaf +cLU +cKM +cLU +aaf +cLU +aaI +aaI +aaq +aaI +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(74,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anX +anX +anX +anX +ayC +aCK +aBW +aFn +aFn +aIm +aKi +auT +wBc +aPd +bFV +aLK +aTL +aTz +aTz +beI +bam +bbO +bgg +bgg +brG +brG +brG +brG +brG +brG +bhA +bsx +bsW +buC +bwd +bxT +bzp +bBm +bCH +bEi +aLF +cLU +cLU +bNu +fhb +oxE +tXh +wht +sdB +wht +hWZ +rPP +uRH +miB +cLU +aQh +cLU +cLU +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cKM +aaf +aaf +cLU +aaf +aaf +aaf +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(75,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aaI +aam +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anX +aBU +atd +atd +auL +aCK +aDS +aFs +aFs +aIj +aKd +aLC +aNo +aPf +bFI +aLK +aTK +aTz +aTz +aTz +bam +bbO +bgf +bgf +bgf +bgl +aTS +bdA +aSI +bdO +bgN +bdP +biY +buB +bwc +bwc +bzo +brd +bvU +bEi +aLF +cLU +cLU +bNB +fKm +bNr +ult +tGo +bNr +tGo +bNr +bNr +bNr +noV +cLU +aQh +cLU +cLU +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIu +cIu +cIu +cIu +cIu +aaf +cKM +aaf +cIu +cIu +cIu +cIu +cIu +aaf +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(76,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +aam +cLU +aaf +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +aaf +anX +ayC +anX +aJw +ark +aCK +aEj +aFO +aIV +aHY +aKt +avu +aNq +aPg +bGh +aLK +aTN +aTz +aTz +aYG +bap +bbQ +bdC +bdC +bdC +bhD +aTS +aXe +bmt +bdP +bdP +bdP +bsY +buE +bwf +bwf +bzr +brd +bvU +bEi +aLF +cLU +cLU +cLU +aSC +aSC +uoa +aSC +aSC +uJB +cLU +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +cbO +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIw +cIU +cIU +cIU +cIU +anD +anH +anD +cLL +cLL +cLL +cLL +cLP +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(77,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +abQ +aaf +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +aaf +anX +ayD +anX +anX +anX +aCK +aCK +aCK +aCK +aCK +aCK +aLK +aNh +aNC +aOS +aLK +aTM +aTM +aWR +blQ +bao +bbP +bdB +beK +beK +bhB +bkk +blb +bmu +bdP +bpe +blP +nIv +buD +bwe +brd +bzq +brd +bvU +bEi +aLF +cLU +cLU +cLU +aSC +bNg +hbt +wiC +aSC +aaf +aaf +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIv +cIv +cIv +cIv +cIv +aaf +cKM +aaf +cIv +cIv +cIv +cIv +cIv +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(78,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aam +aam +aaI +aaf +aaf +cLU +abW +cLU +aaf +cLU +aaI +aaI +aaq +aaI +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +alL +ayC +aoV +cLU +aaf +cLU +aaf +cLU +aaf +cLU +cLU +awn +aNr +hOb +aSz +aLK +aUe +aUe +aUe +aUe +aTS +aTS +aTS +aTS +aTS +aTS +aTS +blc +bmt +bdP +brd +brd +bsX +buD +bwe +brd +bzq +brd +bCG +bEi +aLF +cLU +cLU +cLU +aSC +bMs +gny +wAA +aSC +cLU +aaf +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +aam +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +cKM +cLU +cLU +aaf +cLU +cLU +cLU +cLU +aaq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(79,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +cLU +cLU +aaf +cLU +cLU +aaf +abW +aaf +aaf +cLU +aaf +aaf +aaf +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +alL +ayC +aoT +aaf +aBY +aBY +aBY +aBY +aBY +aBY +aaf +avV +aNr +aOW +bFI +auT +aTO +aVz +aWS +aUe +aGA +aXe +aXe +aXe +aXe +aSO +bjx +bld +bmt +bdP +bhG +bzq +bsX +buD +bwe +bxU +bzq +brd +bvU +bEj +bdP +buQ +bGt +bGt +bGt +bGt +fmR +bGt +bGt +bGt +aaf +cLU +cLU +cLU +cLU +aQh +cLU +cLU +cLU +aam +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIu +cIu +cIu +cIu +cIu +aaf +cKM +aaf +cIu +cIu +cIu +cIu +cIu +aaf +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(80,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aas +aas +aas +aas +aas +aaf +abW +aaf +aas +aas +aas +aas +aas +aaf +aaI +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +alL +ayC +aoT +cLU +aBY +aCD +aDU +aFt +aDU +aBY +cLU +avV +aNt +aPj +bGj +aRS +aTT +aVC +aWZ +aUe +bav +bch +bdO +bdO +bdO +bif +bdO +ble +bla +bdP +biq +brd +bsX +buH +bwg +bxW +bzs +bxW +bxW +bEl +bdP +bIZ +pGo +bMg +bMg +bKI +bPb +vHf +xpO +bGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIw +cIU +cIU +cIU +cIU +anD +anH +anD +cLL +cLL +cLL +cLL +cLP +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(81,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +aam +cLU +aar +aaw +aaw +aaw +aaw +abm +abU +abm +ada +ada +ada +ada +aer +cLU +afm +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +alL +ayC +aoT +aaf +aBY +aCC +gcu +gcu +aFv +aBY +atU +axk +aNs +aPi +bFI +auT +aTP +aVB +aWY +aUe +baw +bci +bdP +bdP +bdP +bdP +bdP +blf +bdP +bdP +bhN +bzq +bsX +buF +brf +brf +brf +brf +brf +bEk +aLF +bJb +bKK +bKK +bKK +bKK +bPc +bKK +dMi +bGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIv +cIv +cIv +cIv +cIv +aaf +cKM +aaf +cIv +cIv +cIv +cIv +cIv +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(82,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aav +aav +aav +aav +aav +aaf +abW +aaf +aav +aav +aav +aav +aav +cLU +aam +cLU +cLU +cLU +cLU +abf +abi +abi +abf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anX +awb +axo +anX +ayE +aoW +cLU +aBY +aCF +aCG +gcu +aGv +aKj +aQG +aKm +aNu +aPl +bFI +aLK +aUe +aUe +aUe +aUe +bax +bbS +bdP +aGE +aZx +beP +bfV +bgk +bpn +bny +bpn +bpn +bta +buD +brd +bxX +brd +brd +bzu +bzu +aLF +bJb +bHB +bUk +bzL +bKK +bPc +bKK +fTj +bGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aac +cLU +cLU +cLU +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cKM +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(83,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +cLU +cLU +cLU +aaf +aaf +aaf +abW +cLU +cLU +aaf +cLU +cLU +cLU +cLU +aam +cLU +cLU +cLU +cLU +abi +aid +agb +abf +abf +abf +abf +abf +abf +abf +anX +anX +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anX +awc +aso +anX +ayC +aoT +aaf +aBY +biX +gcu +gcu +aFy +aBY +atU +axk +aNr +aPk +bGk +aSZ +aUi +aUi +aUi +aUi +aKg +bbR +bfe +aMA +aMS +beN +brf +bfX +bhJ +bdP +bpk +brf +bsZ +buI +hkD +bdP +bBn +bCn +bEm +bHg +aLF +bJb +bKH +bWo +gdx +jfD +bPc +bCx +bGt +bGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIu +cIu +cIu +cIu +cIu +aaf +cKM +aaf +cIu +cIu +cIu +cIu +cIu +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(84,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aan +cLU +aas +aas +aas +aas +aas +aaf +abW +aaf +aas +aas +aas +aas +aas +aaf +aam +cLU +cLU +cLU +cLU +abi +aeU +agb +ajA +agB +adE +adE +adE +adE +anv +anY +anX +alL +alL +alL +alL +alL +anX +anX +anX +arC +axb +cgn +ayC +aoT +cLU +aBY +aCJ +aDW +aEa +aGz +aBY +cLU +avV +aNr +aPm +bGl +aLK +aLK +aVG +aVG +aVG +baj +bbT +bdP +aXM +bzo +brd +bfU +bsX +bhX +bdP +bqh +aKR +btd +buK +aKR +bdP +bdP +bdP +bdP +bdP +bdP +bpd +bLX +cMF +bKK +bKK +bPc +bKK +bDH +aSC +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +cIw +cIU +cIU +cIU +cIU +anD +anH +anD +cLL +cLL +cLL +cLL +cLP +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(85,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aar +aaw +aaw +aaw +aaw +abm +abU +abm +ada +ada +ada +ada +aer +aaf +aam +cLU +cLU +cLU +cLU +abi +axX +aiD +abf +afZ +agD +agD +amy +agD +agD +ajF +auc +auc +auc +ark +asX +asb +alo +amo +anX +arz +awR +anX +ayC +aoT +aaf +aBY +aBY +aBY +aBY +aBY +aBY +aaf +avV +aNr +aPm +bFI +aUa +aLK +aVH +aXp +aVG +bnZ +blc +bdP +aXM +bzo +bfU +brd +bhE +brd +bdP +bpq +bri +btc +buJ +bwh +bxY +bzv +bBq +bCM +bpo +bGt +bJb +sgI +iKS +bMh +bJb +bPc +bKK +bDH +aSC +cLU +cLU +cLU +cLU +cLU +apc +aQh +aQh +apc +aaf +cLU +cLU +cLU +cLU +cLU +apc +apc +apc +apc +apc +cLU +aac +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cIv +cIv +cIv +cIv +cIv +aaf +cKM +aaf +cIv +cIv +cIv +cIv +cIv +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(86,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aav +aav +aav +aav +aav +aaf +abW +aaf +aav +aav +aav +aav +aav +aaf +cLU +cLU +abf +abf +abf +abf +abf +abf +abf +aga +agD +alr +ahK +amN +agD +agU +apb +apb +apb +apb +apb +apb +apb +anY +anX +arX +asB +axI +ayG +ape +cLU +aaf +cLU +aaf +cLU +aaf +cLU +cLU +axs +aNr +aPn +bGm +aQl +aVI +aCq +aKf +aVG +aKh +aKk +bdP +ccN +beL +brd +bfW +bhH +bFN +bog +bpt +brk +btg +buM +bwj +bga +bga +bga +bga +bEq +bGt +fPv +bGt +bGt +bMj +bJb +buo +cUO +bGt +bGt +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cKM +cLU +aaf +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(87,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +cLU +cLU +aaf +cLU +cLU +cLU +abW +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +abi +aeT +afy +aiD +aix +agb +agb +afZ +agD +agC +ahK +amM +apM +apM +apM +apM +asw +asw +asw +asw +asw +afo +apb +arR +axc +apu +ayD +anX +anX +anX +anX +anX +anX +anX +anX +anX +aLK +aNv +aPm +bFI +aRT +aLK +aKc +aXr +aVG +baj +bco +bdP +bdP +bdP +bdP +bdP +bdP +blf +bdP +bqk +bqa +btf +buL +bwi +brk +brk +bBs +brk +bEp +bGt +bHA +bJa +jsn +bMi +bKK +btV +bCy +bRV +aSC +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cKM +cLU +cLU +cLU +cLU +aaf +aaI +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(88,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +eYg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aas +aas +aas +aas +aas +aaf +abW +aaf +aas +aas +aas +aas +aas +cLU +cLU +cLU +abi +agB +adE +adE +adE +adE +adE +agc +agD +agQ +ahB +ajB +apM +aqF +arW +ast +asN +asR +auh +avq +asw +auo +aCd +azg +aul +awT +ayA +azO +azO +azO +azO +azO +azO +azO +azO +azO +aNX +aNx +aPo +bGn +aRV +aLK +aVK +aRs +aVG +bbL +bco +bdD +bfi +bfi +bfi +boi +boh +blm +bfm +bqk +brm +bfm +buP +bwo +bwo +bzx +bBt +bwo +bEt +bFZ +bHD +bJd +bJd +bMl +bNt +bPm +bDR +bRV +aSC +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cKM +cLU +cLU +cLU +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(89,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aar +aaw +aaw +aaw +aaw +abm +abU +abm +ada +ada +ada +ada +aer +aaf +cLU +cLU +abi +afZ +ahi +ahi +ahi +ahi +ahi +ajH +agD +alP +ahy +aiC +apM +aqx +arM +ass +asN +asO +atY +avn +asw +anX +anX +anX +anX +anX +ayI +anX +anX +anX +apD +apD +anX +anX +anX +anX +aLK +aNw +aPi +hgF +aQq +aLK +aUm +aUm +aUm +aUm +bcp +bdS +beQ +bfZ +bhK +bfm +bfm +blB +bnz +aJx +brl +aLL +buO +bwl +cFY +bzw +bga +bga +bEs +bGt +bHC +bJc +bKK +bMk +bNs +bPi +bCA +bRV +bGt +aaf +cLU +cLU +cLU +aaf +aaf +cLU +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cKM +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(90,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aav +aav +aav +aav +aav +aaf +abW +aaf +aav +aav +aav +aav +aav +aaf +cLU +abf +abf +afZ +ahi +ahS +aiA +aiY +ahi +akW +agD +agD +aiB +agD +apM +arx +arZ +arx +asN +asN +auj +asN +asw +aie +aie +aie +aie +anX +axM +anX +aBM +auc +auc +auc +aAG +auc +auc +aBM +aLK +aNy +aPi +hgF +aRW +aLK +aVE +aXd +aYH +bar +bcp +bdS +beS +bgh +bgh +biZ +bkB +blC +blC +bpu +brp +bfm +bfm +bwr +aMh +aMh +bBv +aee +bGv +bGv +aQO +aQO +aQO +bMn +bGv +bGv +bEU +bGt +bGt +aaf +bVO +bUu +bVO +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +aaf +cLU +cLU +cmQ +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(91,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +aaf +aaf +cLU +aaf +cLU +abW +cLU +aaf +cLU +aaf +aaf +aaf +cLU +cLU +abf +att +afZ +ahi +afQ +aio +aiX +akx +ajW +akI +alv +aic +amS +anI +aor +arY +alv +apW +aru +aui +arn +agD +aie +aie +aie +aie +anX +axM +apD +auc +auc +auc +auc +auc +auc +auc +auc +aLK +wBc +aPi +hgF +aNk +auT +aVD +aVM +aXg +baq +bcp +bdS +beR +bga +bga +bga +bga +bga +bga +bga +brn +bfm +cqb +bwp +bya +bzy +bgh +bCN +aQO +bGe +bHE +bJe +bKM +bMm +bNz +bGv +bEe +bNx +bNx +bUv +bVO +bUY +bVO +bZf +bfY +bsR +cej +cej +aZR +aZR +aZR +aZR +aZR +cej +cnD +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cIc +aaf +aaf +bBp +cLK +bBp +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(92,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +aaf +cLU +cLU +cLU +cLU +abW +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +abf +afT +afZ +ahi +ahU +aiF +aja +akR +ajY +akK +aly +aly +aly +anJ +aot +asr +aoD +aly +arv +aur +asK +agD +awy +awy +awy +aie +anX +axM +anX +auc +auc +auc +auc +auc +auc +auc +auc +aLK +aNA +aPq +bGp +aQG +aTU +aVL +aXh +aYI +aUX +bcp +bdT +bfm +bez +bga +bga +xTe +bga +bga +bga +brt +bhx +bga +bga +byb +bga +bga +bga +aQO +crb +bHH +bJg +bKO +bMo +bNH +bGv +bFE +bFO +cxK +bUv +bVO +bVM +bVO +bZf +bhs +bvV +cej +bPe +cgU +cgU +cgU +cfJ +cgU +cnq +cnD +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cHK +cLU +cLU +aaf +bBp +bXk +bBp +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(93,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaq +aam +aaf +cLU +cLU +cLU +cLU +abW +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +abf +afU +afZ +ahi +ahT +aiE +aiZ +akR +ajX +akJ +ahX +ahX +alz +alW +arL +asc +arL +alW +arL +aun +arL +agW +awx +aQs +awy +awy +anX +axM +anX +auc +aBM +auc +auc +auc +auc +auc +auc +aLK +qHU +xFu +hgF +aRX +aLK +aVF +aXg +aXg +bas +bcp +bdS +bfm +bgj +bga +bga +bga +blE +bga +bpw +brt +bfm +buS +bga +byb +bkC +bga +bga +aQO +bHF +bHF +bJf +bKN +bMo +bNG +bGv +bQv +bVT +cxK +bUv +bTZ +bVN +bTZ +bZf +bgb +buy +cej +bOS +cgU +cfJ +chf +cgU +cgU +chi +cnD +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +bBp +bBp +cfv +bBp +bBp +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(94,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +aaf +aaf +cLU +aac +cLU +abW +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +abf +aeV +afZ +ahi +ahW +aiH +ajb +alq +aka +akL +alA +ama +amU +alW +aov +amQ +apY +alW +aov +ase +apY +awv +aFq +awv +awv +awy +atc +axM +anX +auc +auc +aAG +auc +auc +aBM +auc +auc +aMb +aNp +aOQ +aOT +aMb +aUm +aVM +aXi +aXg +baB +bcq +bdU +bfm +bgs +bhL +bja +bkD +blH +bnA +bfm +brx +bfm +buT +bws +byf +bga +bBw +bCb +bGv +bGs +bGK +bJi +bKP +bMp +bNI +bGv +bQv +bFL +bFR +bNx +bVS +bbA +bJR +bZg +bjF +buy +cnp +cep +cgU +chf +chf +chf +chf +chf +cnD +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cGQ +cHq +cGQ +cHq +cLU +cIK +cmD +cng +cLs +cIK +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(95,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +abZ +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +abf +avk +adQ +ahi +ahV +aiG +ahT +akR +ajZ +akJ +alz +alz +amT +alW +aou +amA +apX +alW +ary +asd +asM +awv +axe +aQt +aQt +awy +axK +axM +anX +anX +rAK +anX +anX +anX +anX +azI +anX +aMb +aNE +vcu +bHh +aMb +aMb +aBs +aBs +aBs +aBs +aMb +aMb +aMb +aMb +aMb +aMb +aBs +blF +aBs +aMb +brw +btC +aLR +aLR +byc +bzz +aLR +aLR +btC +btC +btC +btC +btC +btC +bGv +bGv +bQv +bFL +ccx +bNx +bNx +bHt +bNx +bZg +bLM +bzd +cej +ccY +chf +chf +chf +chf +chf +chf +cnD +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cGR +cGR +cGR +cGR +cLU +cIK +cKr +cEw +cJT +cIK +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(96,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaJ +aaf +aaf +abe +abX +abe +aaf +aaf +aaf +aaf +cLU +cLU +cLU +abf +afZ +aha +aha +aho +aho +aho +aho +akc +akN +alW +alW +alW +alW +ajy +ank +ajy +alW +ajy +asg +ajy +awv +aJU +aQy +byW +awy +axL +ayJ +azQ +azQ +azQ +azQ +azQ +azQ +aHn +aIW +aKC +aMb +aNE +aLM +kVV +vcu +aTV +vcu +vcu +vcu +vcu +bbt +beU +vcu +bgu +bfR +bjb +bkE +bkE +bkE +bpz +brz +bti +bBx +bBx +byh +bzC +bBx +bBx +bEu +bBx +bBx +bBx +bKQ +btC +bvF +bKm +bNl +bYE +cbr +bSj +ccz +bIs +cxK +bZg +bMN +cbu +cej +cfx +cfG +cgO +cjL +chf +cms +cnr +cnD +cLU +cLU +cLU +aaf +cLU +cLU +cfE +cfE +cfE +cfE +cfE +cfE +cfE +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cGR +cGR +cGR +cGR +cLU +cIK +cJn +cMg +cLQ +cIK +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(97,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +abe +acf +abe +aaf +aaf +aeW +aeW +aeW +aeW +aeW +aeW +afZ +aha +ahj +ahl +ahl +aje +aho +ajZ +akM +anc +amb +amV +ajd +aow +amR +app +aqN +aoy +aoz +avr +awv +aIh +aQx +byP +awy +axM +auc +aIl +auc +aJw +anX +aub +aFW +aHo +aIX +aKD +aOi +aND +aPt +bgA +aRY +aRY +aRY +aRY +aRY +baC +bbU +bdF +sCJ +bgt +aRY +aRY +aRY +aRY +aRY +bpy +bry +bth +buU +buU +byg +bzB +bzB +bzB +bzB +bzB +bzB +bJk +ouk +btC +bux +bvS +bQw +bxI +bTn +bRS +bRS +bUM +bNx +bZg +bmL +bKn +cej +cej +cej +cej +cmm +cej +cej +cnD +cnD +bMI +bUg +bUg +cfE +cLU +cLU +cfE +cmj +cmj +cmj +cmj +cmj +cfE +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cGR +cGR +cGR +cGR +cLU +cIK +cIK +cJG +cIK +cIK +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(98,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abe +abe +abz +abe +acm +cLU +aeW +aoq +aoq +aoq +aoq +aeW +afZ +aha +ahm +ahZ +ahZ +aji +alB +ake +akP +ani +ame +amX +anK +aoy +amR +aoy +aoz +aoy +aoz +avr +awv +aMx +awv +awv +awy +axM +ayL +ayL +ayL +ayL +ayL +ayL +ayL +ayL +ayL +ayL +aJe +aNI +aPu +bca +aLQ +aLQ +aLQ +aLQ +aKF +baD +bca +bgC +aLQ +aLQ +aLQ +aLQ +bFK +blL +bnB +bpA +brA +btj +buk +bwz +byi +bzH +bzH +bCP +bEx +bGu +xZr +bJm +bKS +bNQ +bOX +bOZ +bQx +bNw +cct +bNw +bVU +bII +bKg +blx +byk +bLu +cey +bLP +bNv +cbv +cjN +ckM +bwP +bxG +bLY +bPC +cbZ +aDk +cfE +cLU +cLU +cfE +cmj +cmj +cmj +cmj +cmj +cfE +bxK +bxK +bxK +bxK +bxK +bxK +cLU +cGS +cGS +cGS +cGS +aaf +cIL +cld +cMh +cLv +cKg +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(99,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +abd +aaK +aci +acB +abd +cLU +aeW +aoq +aoq +aoq +aoq +aeW +afZ +aha +ahl +ahY +aiI +ajg +aho +akd +akO +anc +amc +amW +ajd +aox +anZ +aqa +aqO +arB +aqO +avs +aww +aLB +aQz +awm +atx +axM +ayL +aBa +aBa +ayL +aBA +aCV +ayL +aGT +aIB +aNO +aJe +aMk +aPu +eEV +auk +auk +auk +auk +aNJ +aLM +bbW +bdY +bdY +aEA +aEG +aEK +bdY +bmG +bmG +bmG +aHB +bmG +bmG +bwt +aLR +aLR +aLR +aLR +bEw +btC +ixD +bJl +bKL +btC +bNx +aSK +aSK +aSK +aSK +aSK +bNx +bNx +bNx +blw +bra +ccC +cew +cfH +bMS +bQe +ccB +bwN +bwO +bxc +bxJ +bNP +cbU +aDl +cfE +cfE +cfE +cfE +cmj +cmj +cmj +cmj +cmj +cfE +cDh +cDy +crR +cEV +cDh +bxK +cBN +cHR +cHR +cHR +cHR +cIp +cIL +ckX +cJI +cJW +bCo +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(100,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +abd +abu +abY +acx +abd +cLU +aeW +aoq +aoq +aoq +aoq +aeW +afZ +aha +aho +aij +aho +aho +aho +ajZ +akJ +alW +alW +alW +alW +aoz +aoa +aqc +aqS +arF +asi +asP +aoz +aNm +aQA +awp +atx +axM +ayL +azy +ayM +ayL +aBG +azy +ayL +aGT +azy +aNO +aJe +aNH +aPu +eEV +auk +aaf +cLU +auk +aNJ +baF +bcc +bdY +bfn +biv +bio +bkH +bmE +bmG +bgp +bjh +bmi +bpi +bmG +bwB +byj +byj +byj +bCQ +byj +btC +bHL +bJl +fKS +btC +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abw +bYI +bYI +bYI +bYI +bYI +bZc +chk +aZU +aZU +aZU +clg +cfE +bMc +bSh +ahP +aEH +cfE +cik +ckT +cfE +cmj +cmj +cmj +cmj +cmj +cfE +cDm +cDU +cbw +cDU +cGc +cHa +cBN +cef +cIx +cIx +cJj +cIr +cIL +ckX +cJI +cJe +bCo +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(101,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aah +aap +aal +aah +aaf +aaf +aaf +abd +aai +abV +acz +abd +cLU +aeW +aoq +aoq +aoq +aoq +aeW +afZ +aha +ahn +aia +aiT +ajr +alH +akf +akQ +ant +amf +amY +ajh +aoz +aoz +aqb +aqR +aIq +asi +aoz +aoz +avo +aoy +aoI +atx +axM +ayL +azx +apK +ayL +apK +aEk +ayL +apK +aIC +apK +aJe +aNG +aPu +eEV +auk +aaf +cLU +aJe +aZh +baH +bcg +bdY +bgM +bgO +bip +bgO +bls +bmG +bnC +bpB +brB +bmG +bmG +cco +bro +bto +bvw +bvw +bvw +btG +bHK +bJn +bKT +btC +cLU +aSL +aTc +aTx +aTc +aUc +cLU +cLU +aVQ +bZY +cbx +bVn +bYI +cfK +chj +ciu +chI +aZU +bRq +cdP +bMa +bRW +all +avT +cgE +cij +ckK +cfE +cmj +cmj +cmj +cmj +cmj +cfE +cDi +cDA +cEk +cEn +cEk +cGZ +cBN +cGC +bTm +cIV +cJi +cIq +cIL +ckX +cJI +cJe +bCo +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(102,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aag +aap +aap +aap +aak +aax +cLU +cLU +aaf +abd +abd +acb +abd +abd +abf +aeW +aeW +agb +agb +aeW +aeW +afZ +aha +ahq +aia +aia +ajR +alM +aki +akS +anx +amh +ana +anL +aoA +apA +aqe +aqT +arG +ask +asQ +asQ +aOX +aQD +aws +atx +axM +ayL +azA +aAL +aBZ +aCS +aEl +aDR +aGU +aEl +aKs +auk +aNI +aPu +eEV +auk +cLU +cLU +aUp +aCp +baP +aDH +bdY +bfp +bgP +bfj +bhd +bjE +bmG +bnc +bpD +bsa +bmG +buY +bwG +bIV +bzJ +bBz +bCS +bEg +btG +bHN +bJp +fKS +btC +cLU +aSM +bEb +ctb +bIR +aSM +cLU +cLU +aWc +bZZ +cby +ccH +bYI +cfM +chm +ciw +cjQ +clc +cmA +cgM +bMf +bTV +cdC +cfD +cfE +cjI +ckW +cfE +cfE +iXX +iXX +iXX +cfE +cfE +cDt +cpD +cEn +cEn +cEn +cHg +cBN +cGI +bTB +cIX +cJl +cIs +cIL +cJf +cLJ +cJX +bCo +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(103,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aah +aap +aap +aak +aao +aat +cLU +cLU +aaf +abi +abt +acj +acu +ade +ade +ade +ade +aeg +ade +apU +ade +afq +aha +ahp +aim +aiV +ajw +alI +amu +amZ +ahb +amg +aoM +ajp +aoz +apz +aqd +aoz +aoz +aoz +aoz +aoz +aoz +aqd +awr +atx +axM +ayL +azz +aAI +aBQ +aKr +azy +azy +aKr +azy +aKr +fnT +aNI +aPu +eEV +auk +cLU +aaf +aUp +aZi +baK +bcI +bdY +aXG +bex +bir +bjI +bma +bmG +bnD +bpC +brD +bmG +buX +bxi +bxk +bxk +bBy +bCR +bEy +btG +bGq +bJl +fKS +btC +cLU +aSM +bQI +bRX +bPf +aSM +cLU +cLU +bYI +aXb +aXb +ccF +bYI +bZr +chl +civ +cjP +aZU +cmy +cnG +cnG +bKG +bKG +cnG +cnG +cip +ckU +ckY +cnx +coz +cdC +cdC +cps +bwE +ckf +cDV +cEE +cFt +cDV +cHf +cBN +cHT +cLS +cLZ +cMa +cMb +cIt +cJg +cLC +cJX +cKg +aaf +cLU +cLU +cLU +aaf +abc +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(104,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aah +aah +aaj +aah +aat +aat +aaf +cLU +abh +abh +abh +abh +acp +acp +acp +acp +acp +acp +agb +aed +agb +agn +aha +ahs +aiw +aiW +akh +alS +akl +akV +agW +amj +anb +alW +anr +aoz +aqg +aqV +arH +asn +asS +aty +aup +aqd +awt +atx +apQ +aqs +azC +aAN +aCb +aCU +aEn +aGY +aKy +aIG +aGW +aLI +aNK +aPu +aNR +aJe +klA +aUp +aUp +aUp +baU +aUp +bdY +bfr +bex +bis +bjJ +bjE +bmG +bvG +bor +bsA +bmG +bva +bxj +byH +bxk +bBA +bCU +bEA +btG +bHM +bHO +bHM +btC +bNy +aSX +aVv +bUo +aVv +aSX +bNy +aVv +bYI +bgc +aXb +ccK +bYI +cbD +cho +ciy +ceQ +aZU +cmB +bKG +bQa +qJW +cjw +cnB +bjV +cjK +cma +cpo +cpo +cpr +cpo +aXo +aYX +cEJ +cDj +cDj +cEp +bZR +cFA +cGd +cLe +cHU +bVB +cIY +coT +cJD +cIL +ckX +coC +cJY +cKg +aaf +aaf +cLU +cLU +cLU +crP +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(105,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +aaf +aaf +cLU +abh +abh +abB +abh +abh +acp +ahw +ajm +cuS +acp +acp +aey +aed +aeT +agn +aha +ahr +aiv +aia +akb +alR +akj +akJ +alJ +ahX +alQ +ajq +aoB +aoz +aqg +aqU +asW +asW +asW +asW +aOZ +aQE +aOZ +atg +axM +ayL +azB +aEm +aCT +aCT +aEm +aCT +aEm +aNN +aPx +auk +aNJ +aPu +eEV +auk +klA +mwu +aXu +aYM +baJ +bcf +bdZ +bfs +bgR +bfB +bhf +bkG +bmG +bmG +aKP +bmG +bmG +buZ +bxk +byI +bxk +bBy +bCT +bBy +btG +bGr +bJl +fKS +btC +bOL +bQj +bSl +bRX +bIW +bWI +bQB +aVv +bXd +cab +cbz +ccI +aXU +bZV +chn +cix +ceh +aZU +cmB +bKG +cjw +bSt +cju +cjw +cpW +cjJ +ckV +clX +cow +coA +cpp +cpq +cpu +bwE +cDu +cDW +cEo +bZQ +cDW +cDW +cGt +cGt +cmo +uGq +cmr +cGt +cGt +cGt +cGt +cGt +cGt +cLU +aaf +aaI +cLU +cLU +crP +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(106,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +aaf +aaf +cLU +cLU +abh +abv +acE +adM +abh +acA +add +adz +add +cuU +acp +adR +aed +aeU +agu +ahg +ahE +aiy +aiy +akk +alY +aki +akX +alO +amk +anf +aju +ajC +aoG +apr +aqX +ata +auu +awh +asW +aQa +aQH +bAZ +atg +axM +ayL +azG +azS +aAP +aCW +aFJ +aIH +azS +ayL +aKx +auk +aNL +aPv +eEV +auk +vKw +sfM +aXl +aYS +baN +bcj +bfo +bft +bgS +biu +bjL +bkJ +blN +bnE +bpI +brI +btl +bvd +bwK +bym +bqF +bqH +bwK +bEB +byp +bHR +bJp +fKS +btC +bON +bPf +bPf +bRY +bPf +bPf +bVW +aVv +cfT +cae +cbC +kvT +bno +aYr +chq +ciI +aYr +aZU +cmE +cnG +bRf +bYH +cnA +coE +bjV +cns +cny +bql +bql +cmu +bql +bql +coB +bsy +cDk +cDk +cDk +cDk +cDk +cDk +cGt +apm +cIC +cIZ +cJs +cKH +cIQ +cLI +bIM +cnE +cGt +cLU +cLU +aaI +cLU +cLU +crP +aap +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(107,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aaf +aaf +aah +bnj +cLU +abh +abg +acv +adw +abh +ags +add +acH +add +cuT +acp +aaT +aaT +aaT +aaT +aaT +adD +aib +aeJ +aiz +aeF +akm +akJ +alN +ahX +ane +ajs +ajz +aoz +aqh +aqW +asY +aut +avt +asW +aPc +aQF +bAY +atg +axM +ayL +azF +aAO +aCc +ayL +aEo +aFI +aLH +ayL +aKw +aJe +aQN +jHW +aQN +aUp +aUp +aUp +aXk +aYN +baL +bcn +bdZ +bfu +bgv +bjM +bly +bdY +bmG +bmG +bmG +bmG +bmG +bvw +bvw +bvw +bvw +bvw +bvw +bvw +btG +bHQ +bJn +bKR +btC +bOM +bPg +aWB +bRZ +bLa +bPf +bQE +aVv +bYL +cad +cbB +cbY +bno +cfO +chp +ciH +cjT +cgo +cmC +cnG +coG +bVY +cnz +coD +bjV +cil +cvy +bql +cyU +cmt +cot +bql +bTW +cCq +cDk +cfj +cEF +cac +bKx +apl +cGt +cfB +cfz +cHD +cpX +cHb +cHb +cJo +bIM +awq +cGt +clS +cLU +aaI +cLU +cLU +crP +cLU +cLU +crP +aaf +cLU +cLU +cLU +cLU +cLU +cLU +ngU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(108,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aaf +cLU +aaB +cLU +cLU +abh +aby +acI +aeh +abh +aht +add +ady +add +adC +acp +aeM +afg +afF +cuX +adD +ahu +aig +aiK +ain +adD +akl +akJ +akF +amm +apw +atx +ajG +alx +amw +amO +atg +avj +awl +atg +auU +bjr +bBa +atg +axM +ayL +azy +azy +azy +ayL +asC +azy +atF +ayL +aKw +auk +aNJ +aPw +eEV +azo +aUb +aVO +aXm +aYU +baR +aUp +bdY +bdY +bdY +bdY +bdY +bdY +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +bAh +bCK +bCO +bBP +btG +bHT +bJl +bKY +btC +bBr +bPh +aYg +bsV +bND +bUB +bTb +aVv +bYP +cag +cbE +bVq +bno +cfO +chs +ciH +cjV +ciH +cmB +bMH +cjw +bYN +crf +coH +cpY +cio +clx +bql +cla +cnw +cov +bql +bUl +bVw +bYM +bZn +bZD +cbj +cGi +cHm +cGt +cId +cIG +cHF +cHZ +cHb +cHb +cHb +cHb +cHb +cGt +cLU +cLU +csM +cLU +cLU +crP +cLU +cLU +crP +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(109,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +abh +abx +acF +aef +abh +agt +add +ady +add +adA +acp +aeL +aeM +afE +cuV +adx +cuZ +aig +aig +ajj +alZ +akl +akY +agD +amd +apq +ajv +aoL +apE +aqj +aqY +ate +avh +awk +atg +aQn +aUd +aQn +atg +axM +ayL +atN +azT +aCf +ayL +aCm +azy +aLJ +ayL +auk +auk +aEV +aPw +eEV +azb +aUl +aVN +aVR +aXO +aUp +aUp +beb +beb +beb +beb +bhk +beb +beb +beb +beb +aPb +aUk +aYc +bxr +bxr +bAh +bCI +bCV +bGC +btG +bHS +bJl +bKX +btC +bAd +bPf +csb +bSb +bNC +bPf +bQJ +aVv +bYO +caf +bUa +ccO +bno +cfP +chr +ciJ +cjU +cle +cmF +bKG +coG +cqa +cre +csn +bjV +cuo +cvA +bql +ckZ +cmv +cyV +bql +bUh +cnJ +cDk +bZh +bZC +cai +cGf +cHl +cLf +cIb +cID +cHb +cHY +cHb +cHb +cHb +cHb +cHb +cGt +aaf +crP +crP +aaf +crP +csM +aaf +crP +crP +aaf +aaI +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(110,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +csM +cLU +cLU +cLU +cLU +cLU +abh +abA +adc +afI +acg +acK +acK +adG +acK +ael +aes +aeO +afi +afH +aeO +agX +cva +aih +aiL +cvh +ajT +aks +alb +anA +akr +amp +amp +amp +apH +aqk +ara +atw +avl +awu +atg +aQr +byw +bBc +atg +axM +ayL +ayL +ayL +ayL +ayL +aFK +azy +azy +aFI +aDT +aQI +aNF +aPy +aQK +azb +aAJ +aVR +aVR +aYW +aUp +aaf +beb +byl +bmI +biw +bkK +blz +bmI +boX +beb +bob +buG +bwn +bpM +bxr +bzM +bBE +bCX +bEC +bGw +bHW +bJs +bLb +btC +bNE +bPn +bQK +bSb +bTw +bSF +bTi +aVv +aWV +cam +bYI +aWV +bnp +ccE +chu +ciH +cjW +clf +ciC +cnG +bRv +cpx +cpx +cpz +bjV +cur +cvC +bqL +brC +brF +bsq +bql +bUp +bXH +cDJ +cDJ +cDJ +cbA +cDJ +cDJ +cGt +awa +cIN +cHb +cHY +cJF +cJU +cKu +cKu +cKu +cGt +aaf +aat +aaI +aaf +aat +cts +aaf +aat +crP +aaf +aat +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(111,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abc +cLU +cLU +aac +cLU +cLU +abh +abh +abh +abh +abh +acJ +add +adF +add +aek +acp +aeN +afh +afG +cuY +adx +ahv +aig +aig +cvf +alZ +akn +ala +anA +amn +amp +amp +amp +amp +aoP +aqZ +arA +arA +arA +arA +arA +arA +arA +arA +azn +ayL +axN +aAr +aAr +ayL +ayL +ayL +ayL +ayL +aPE +aLM +aLM +aPu +aNR +azb +aAu +aVP +aVP +aYV +aUp +aaf +beb +bgU +bgx +bhQ +bkn +blA +blR +bFo +beb +bsB +btL +bvH +rwB +bxr +bAh +bBC +bAh +bAh +btG +bHU +bJr +bKZ +btC +bNF +bNF +bNF +bSc +bNF +bNF +bNF +bNF +bYS +cah +cbF +ccR +cbF +cbF +cht +cbF +cbF +cbF +uKl +cnG +bjV +bLn +bLn +bjV +bjV +cdJ +cvy +cwm +cwm +cyv +cyv +bsy +bUm +bUC +bxN +cEd +cEI +cbt +cGk +cqL +bAP +cIe +cIJ +cHb +cHY +coF +cGt +cmM +cmM +cmM +cGt +aaf +crP +aaI +aaf +crP +crP +aaf +crP +crP +aaf +aaI +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(112,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abh +acp +adg +adH +adN +acp +acp +aei +aeY +afG +agx +adT +ahC +aik +aig +aiU +adT +akn +ald +anz +anj +anj +anj +aoQ +anj +aql +arc +arO +atb +atj +atA +auw +avv +awz +axf +axQ +ayv +azU +azU +azU +azU +azU +azU +aHb +aQI +aNF +aLM +aLM +aPA +eEV +azb +aXQ +aVU +aVU +aYY +aUp +eEn +beb +bfv +bhS +biy +biy +bmH +bmK +bow +beb +bom +btm +bvf +btm +bxr +bys +bBG +bEr +cLU +btG +bHX +bJu +dNC +bJo +bLf +bMq +bQM +bSe +bTp +bNJ +bPp +bNJ +lyt +cao +bYV +ccU +bYV +bYV +chx +bYV +bYV +clh +cmI +cnF +vno +vno +vno +css +ctu +cuo +cvy +coK +coK +coK +coK +sYh +bUh +bUC +bxN +ckQ +cEL +ccf +cGn +cpE +bAP +cGV +cHu +cJd +cJt +cJJ +cLE +cKw +cLh +cLh +cGt +cKx +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(113,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +abw +acp +acp +adf +adf +adf +acp +acp +aeF +aeP +afr +aeF +aeF +ahz +aii +aiM +aeF +aeF +akt +alc +anA +amn +amp +anM +aoP +amp +aoP +arb +any +auv +ath +atz +auv +auv +auv +auv +axP +ayu +ayu +ayu +ayu +ayu +ayu +amr +aGZ +cbl +aKA +aKA +aKA +aPz +eEV +azE +ari +auR +avS +avU +fPF +eEn +beb +bgW +aoi +bjY +bjc +bjO +bnJ +box +bru +bsm +btN +bve +bwQ +byo +bzP +bBF +bEr +cLU +btG +ixD +bJt +fKS +qJj +jFq +htC +bQL +bSd +bTj +bMu +bPo +bUq +dQa +can +bYU +ccT +bYU +bYU +chv +ciK +cjX +ceZ +cmH +cnC +coJ +cqe +cqe +csr +ctt +cus +cvD +cwn +cxu +cxu +cxu +cAe +bUy +bYl +cDw +cEe +bZF +cbM +cGm +cqN +bBb +cGU +cHt +cJb +cIa +cJH +cmz +cKv +cnh +cLw +crN +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(114,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +pWa +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +aap +aaf +cLU +cLU +abD +acN +adk +adk +adk +aem +aeu +aej +afj +afM +agy +ahR +ahF +adh +aiN +ajn +aml +akv +alg +aos +amv +anl +anN +aoR +anl +aqn +ard +arP +atG +atk +atG +aux +avw +awA +avI +axR +ayw +ayw +aAQ +aCg +ayw +ayw +ayw +aHb +aLQ +aKF +aLM +aLM +aPB +eEV +azb +aYJ +aVP +aVP +aZa +bcD +bcl +bec +bgX +bfz +biy +biy +blD +bmK +boy +beb +bot +btm +bvg +bvi +bxr +bzR +bBI +bEr +cLU +btG +ixD +bJw +bLd +bJq +bPq +bMr +bQN +bSf +bTq +bNK +bPq +bUr +eut +cas +bYX +ccW +bYX +bYX +chz +bYX +chz +clj +cmK +cnI +coL +cqf +cri +cst +cst +cuu +cvE +cwo +hoh +cyx +hoh +sYh +cuo +bUC +bxN +clu +cEN +cch +cGn +cpE +bAP +cGX +cHu +cJh +cJu +cJM +cLF +cKB +cLi +cLx +cGt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(115,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +abs +acL +adh +adh +adh +adh +aet +afO +afn +afK +agz +agY +ahD +adh +adh +ajo +acq +aku +ale +agW +ami +ajc +ami +ami +aqH +aqm +ang +arA +arA +arE +arE +arE +arE +arE +arE +azn +arE +arE +arE +arE +arE +arE +arE +arE +arE +aKE +aLM +aLM +aPu +aNR +azb +aAX +aVU +aVU +aYZ +aUp +aaf +beb +abr +bgy +bgy +bgx +blA +blT +bGf +beb +hDm +btL +bvN +bxo +bxr +bAj +bBH +bAj +bAj +btG +bwS +bJv +bLc +btC +bNF +bNF +bNF +bNF +bWV +bNF +bNF +bNF +bYW +cap +cbG +ccV +ceA +cfR +chy +ced +cjY +cli +cmJ +cnO +bkA +bkA +bkA +bnd +bnd +cut +mKS +bnd +bnd +bkA +bkA +bkA +cBl +bUC +bxN +cnk +cEM +ccg +cGo +oAO +bAP +cGW +cHu +cHb +cHY +cJL +cGt +cmM +cmM +cmM +cGt +aaf +crP +aaI +aaf +crP +crP +aaf +crP +crP +aaf +aaI +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(116,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aaf +aaf +aaf +aaG +aaG +aaG +aaG +aaG +abq +abO +acP +adn +adn +adn +adn +aez +aeZ +aft +afN +agL +agY +ahD +adh +adh +ajx +ajV +aif +ali +ahk +ams +anm +amC +aok +apI +aqp +arh +arp +asZ +aqf +atB +atB +atB +atB +atB +avp +aAi +aAi +aAi +aJC +aAi +aAi +aFQ +ayi +aHh +aNZ +aLQ +aKF +aPu +eEV +azb +aAZ +aVR +aVR +aZd +aUp +aaf +beb +bzi +bhT +bge +bkM +biD +bjK +bHl +beb +bpc +buN +bwx +brj +bxr +bzS +bBK +bCZ +bED +bGx +bIb +bJx +qJj +btC +bNM +bPs +bQP +bPt +bTC +bSU +bSU +bSU +aWT +aWT +cbH +ccX +aWT +aWT +bSU +ciq +cka +clm +baI +cnO +coN +coR +crj +csv +boW +cuw +cvF +cwp +cfi +cyy +cyZ +bkA +cdJ +bYF +cDJ +cDJ +cDJ +cDJ +cDJ +cDJ +cGt +cLp +cHu +cHb +cHY +cJP +cKa +cKE +cKE +cLz +cGt +aaf +aat +aaI +aaf +aat +crP +aaf +aat +crP +aaf +aat +aaI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(117,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aap +cLU +cLU +aaG +aaz +aaF +aaR +abo +abC +ack +acO +adm +adm +adP +elq +aev +aeX +afp +afK +agH +agY +ahD +aen +adh +ajt +ajU +akw +alh +ahk +amq +amP +anT +aoh +anO +apO +aqv +aro +asZ +asU +aoH +aoH +aoH +aoH +aoH +aoH +aoH +aoH +aoH +aoH +aoH +aCu +aCu +aHc +aCu +auk +auk +dKq +aPu +eEV +azb +beh +aVN +aVR +aXR +aUp +aUp +beb +beb +beb +beb +bje +beb +beb +beb +beb +aPb +aXc +aYc +bxr +bxr +bAj +bDb +bCY +bGE +btG +bHZ +bJl +bLe +btC +bNL +bPr +bQO +bPt +bTC +bSU +bUX +bXc +xrP +xrP +xrP +cdy +ceB +cgm +bSU +ciM +cjZ +clk +cmL +cnO +coM +coR +coR +csu +boJ +cuv +coR +coR +coR +coR +cyY +bkA +cBm +bUC +cDr +bVu +bWX +bYz +cbK +cor +cGt +bhR +chd +cHD +cJv +cJO +cJV +cKC +cKu +cLy +cGt +aaf +crP +aaI +aaf +crP +crP +aaf +crP +crP +aaf +aaI +aaI +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(118,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaG +aaD +aaL +aaU +abj +abF +abS +acR +adp +adp +adU +adp +aeB +adp +adp +agd +agO +adp +adp +adp +adp +ajJ +aml +akz +ala +ahk +amB +apI +anV +apI +aoY +apP +aqG +arr +asZ +asU +aoH +auz +avg +awF +axi +axS +cfS +azV +awF +aAb +aCY +aCu +aDv +aHg +aCu +cLU +auk +aNJ +aPC +aQP +azH +biz +aVV +aVR +aZe +bcb +aUp +bed +bed +bed +bed +bed +bed +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +bAj +bKC +bCW +bFc +btG +ixD +bJl +qJj +btC +bNO +bPv +bQR +bPt +bTC +bSU +bVf +bWJ +bYQ +bYQ +bWJ +cdQ +ceE +cfW +bSU +ciO +ckb +cln +cmL +cnO +coP +coR +coR +csz +bCF +cuv +cvH +coR +coR +cyz +czb +bkA +cBo +bYK +cDx +bWT +bWZ +cck +cFT +cGr +cLg +cHb +cHu +cHL +cJx +cIF +cKd +cJx +cIF +cLB +cGt +cLU +aap +aaI +cLU +cLU +aaf +cLU +cLU +crP +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(119,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaG +aaC +aaL +bvP +aba +abE +abR +acQ +ado +adI +adS +aeA +aeH +aeo +afu +agG +agM +ahc +ahG +ail +aiO +ajI +aml +ajS +ala +ahk +amt +anp +anp +anp +anp +anp +aqy +arq +asZ +asV +aoH +auy +avx +awE +axh +awj +ayc +axh +aAR +axh +aCX +aCu +aDu +aHf +aCu +aaf +aMb +aQN +jHW +hDl +aUp +aUp +aUp +aXt +aYN +baQ +aZn +bed +bfC +bgz +biA +bjT +bed +bed +bed +bed +bed +bed +bed +bed +byN +byN +byN +byN +byN +btG +bIc +bJy +qJj +btC +bNN +bPu +bQQ +bPt +bTC +bSU +bVc +bXu +bYx +caj +cdY +cdF +ceD +cfV +bSU +ciN +ckb +cln +cjs +cnO +coO +coR +crl +csw +bCz +cux +cvG +cvG +cxx +coR +cmb +bkA +cBn +bUC +bZa +bVv +bWW +bZa +aVT +cHA +cGt +cfC +cHw +cun +cuq +cuJ +cuI +cuH +cJZ +cLA +cGt +clS +cLU +aaI +cLU +cLU +crP +cLU +cLU +crP +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(120,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaG +aaD +aaL +aaU +abj +abF +acc +acw +acw +adL +adZ +aeC +aaa +agg +agg +adL +act +aea +aec +aew +aff +afR +agv +akA +alj +ahk +amD +ann +anW +aoK +apd +apR +aqI +arQ +asZ +auK +aoH +auA +avB +awY +axj +cfS +axU +auA +aAh +aCk +auA +aCu +aFR +aHi +aCu +aJl +aJl +xhz +aPD +aQQ +azK +klA +mwu +aXv +aZg +baT +bcr +bdG +bfD +bhb +biB +bjU +bkI +bmO +bkL +bqz +bsp +btQ +bwC +bqw +byN +bzU +bBM +bDd +bEF +btG +ixD +bJp +bLg +bMv +bNR +bPA +bQW +bPt +bTC +bSU +bVD +bXu +bYR +cak +cdZ +cek +ceG +cfb +bSU +ciO +ckb +cln +clr +cnL +coR +coR +coR +coR +coR +cuv +coR +coR +coR +coR +czc +bkA +cBn +bUC +cDr +cDr +cDr +cDr +cDr +cDr +cGt +bhR +cox +cHM +bBo +cIH +cKf +cuG +cIH +ctB +cGt +cLU +cLU +aaq +cLU +cLU +crP +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(121,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +csM +cLU +cLU +cLU +aaG +aaC +aaL +aaC +aba +abH +abT +acr +acZ +adK +adY +adK +aeI +afv +agf +ago +agv +ahd +ahH +aae +aiP +ajK +agv +agK +aad +ako +ako +ako +ako +ako +ako +ako +ako +anG +asZ +asV +atE +atE +atE +axa +atE +atE +atE +atE +avW +atE +atE +aCu +aCu +axO +aCu +gsd +dvY +xhz +aPD +aQQ +azK +klA +mwu +blu +aZf +baS +iFX +bed +bfE +bhc +biC +bnf +blG +bnw +boC +boC +aMi +btR +bvQ +bwR +byN +bkO +bBO +bDc +bEE +btG +ixD +bJl +qJj +btC +bFF +bPz +bQV +bUA +bTD +bSU +bVC +bWJ +cbk +cbk +bWJ +cee +ceF +cfX +bSU +ciP +ckc +clp +cmN +cnK +coQ +cqg +crm +coQ +bXf +ctC +cuy +cvO +cxy +cyA +cgj +bkA +cBp +cCx +czA +cLU +cLU +aaf +aap +cLU +cGt +cGt +cGt +cGt +ctq +cLm +cLD +ctq +cLm +cty +ctK +cLU +cLU +aaI +ctg +cLU +crP +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(122,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abc +cLU +cLU +cLU +aaG +aaD +aaL +aaU +abj +abF +ach +acU +adq +adq +aep +aep +afb +afw +adq +agE +acM +ahe +ahJ +aip +ahe +ajQ +agJ +akC +alk +alT +amF +ano +aof +api +apJ +apT +arg +arI +atI +auM +atD +auC +avD +awL +axm +axV +ayz +azW +aAT +azW +aCZ +aEr +aFT +aKG +aIS +aKK +aMa +aNT +aPF +aQM +aJi +klA +aUp +aUp +aUp +baW +aUp +aUp +bfF +beC +bgQ +bnr +aSD +bou +bHJ +bqA +bsp +btS +bxn +bwU +byN +bzQ +bBO +wTp +bEH +btG +bHM +bHO +bHP +btC +bNX +bPB +bQX +bPt +bTE +bSU +bVE +bWR +bYT +cal +ceb +cem +ceJ +cga +bSU +ciQ +cke +clr +cmP +cnR +blp +blp +blp +blp +blp +cwO +cwW +blp +blp +blp +bkA +bkA +cBq +cdW +czA +aaf +cLU +bun +ccp +cHB +cHB +cHB +ccp +cGt +crU +csL +cKk +ctr +ctx +ctH +ctM +cub +aaf +apc +aaf +aaf +crP +aaf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(123,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaG +aaE +aaM +aaV +aba +abJ +acd +acS +adq +adV +aeb +aeb +afa +afw +adq +agp +acT +bUb +ahI +aiR +aiQ +ajM +agv +akB +akT +alD +amE +akU +aoe +alw +aoZ +apS +aqM +anG +apy +aqi +atE +auB +bwA +awK +axl +axT +ayx +axT +aAS +avC +avC +aEq +aFS +aHk +aIP +aKI +aLY +aNS +aPD +aQQ +azK +cLU +aaf +aUp +baE +baV +bcI +aUp +blt +bhU +biE +bjW +blI +bmR +bpG +brv +bsp +bhF +bsp +bsp +byN +bzV +bBN +bDe +bEG +btG +ixD +bJl +qJj +btC +bNW +bPt +bPt +bPt +bUL +bSU +bSU +bSU +bYY +bSU +bSU +ccZ +bSU +bSU +bSU +ciq +ckd +clr +cmO +cnR +bYG +sBp +bSp +csx +cku +bTo +ssg +cjB +cpe +blp +bZH +czD +cBW +cCz +byA +byA +byA +byA +rQB +cKX +gwY +mNK +rQB +cGt +cqO +csI +cGt +cGt +csI +csI +cGt +ctP +aaf +apc +cLU +cLU +crP +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(124,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaG +aaG +aaO +aba +aay +abL +acd +acW +adq +adV +aeb +aeD +afc +afx +agi +agF +agP +ahf +ahN +air +ajf +ajO +agv +akE +alm +alF +aeK +anq +amG +alt +apL +aqq +arl +anG +asp +aoH +aoj +aoj +aoj +aoj +axg +axT +ayP +axT +aAV +atE +atE +atE +aFV +atE +aJl +aJl +aJl +aNW +aPD +aQQ +azK +cLU +cLU +aUp +aCH +bcd +aDQ +aUp +bfH +beE +bgZ +bjW +biC +biC +biC +bqC +bsp +btp +bvh +bah +byN +bBQ +bBQ +bDg +cQX +aJi +bIe +bJC +bLj +aJl +bNY +bPt +bsH +bwI +bPx +bUH +caq +bQF +bZb +caq +bNp +cdb +ceM +chA +cii +cim +cjr +cjS +cmO +cnR +bXg +drB +ssg +ssg +cmx +cuA +ssg +ssg +cNa +blp +cBz +cBz +cBW +cqw +cqG +crd +crq +byA +rQB +crM +hsk +cQw +rQB +aQh +csq +csR +ctp +csR +csR +ctp +csR +cud +cLU +apc +cLU +cLU +cbO +cLU +cLU +csM +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(125,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +aaG +aaN +aaW +abk +abK +acd +acV +adq +adV +aeb +aeb +afa +afw +adq +aIQ +acT +ahe +ahL +aiq +aiQ +ajO +agv +akD +akU +alE +ahA +alD +alD +aod +apf +aqo +arj +anG +asp +aoH +atH +atH +atH +aoj +axn +axW +ayH +axT +aAU +aBj +aDa +aEs +aFU +aHl +aIT +aKL +aJl +aFE +aPD +aQQ +azK +aaf +cLU +aJi +baG +baX +bdE +aJi +bfI +bhg +biG +bjX +blJ +biG +biG +bqD +bed +bed +bed +bed +byN +bzY +gpG +bDg +yeJ +aJi +bId +bJA +bLi +aJl +bPx +bLm +bPx +bsI +bPx +bUI +caq +bXe +bYZ +caq +bNa +cda +ceL +chg +chW +ciA +cmR +ciA +ciA +cgs +bVQ +crK +crJ +csy +csy +cuz +bUd +bXr +cxD +blp +ckv +cDg +cDR +cDY +cGA +cEr +cbJ +crH +cKO +cHE +ffg +lFM +rQB +aQh +csl +csQ +csQ +cIm +cIm +csQ +cIm +csQ +cLU +apc +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(126,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +aaX +aaQ +aaZ +aaZ +abP +aab +acY +adt +adX +aex +aeG +afe +afS +agk +agI +adb +ahe +ahQ +ait +ahe +akg +agv +akG +alC +alG +ahA +alD +alD +aoX +alK +amz +arm +anG +asp +aoH +atL +auE +avE +aoj +axq +axY +ayR +axT +aAY +aBj +aDc +aEt +aFX +aHm +aIU +aIU +aJl +aNQ +aPD +aQQ +azK +aaf +cLU +azK +aZk +baZ +bcu +aJi +bfJ +bhh +bhV +bkN +blK +bmS +boF +bpN +aNU +bhy +bhP +bhy +btb +bAa +bBS +bDh +bEI +aJi +bIg +bJD +bcv +bOb +brb +brb +bQT +bOY +bTF +bUJ +caq +bXe +bZe +caq +caq +cdd +cdf +caq +caq +ciA +ckh +cll +cib +cgs +cpn +jko +fCE +fCE +fCE +ohn +ohn +cwx +nPR +blp +czO +czE +cBX +cCC +byF +byF +byF +byA +rQB +cLc +cLk +cLu +rQB +aQh +cIl +cGR +cGR +csX +csX +cGR +csX +cGR +cLU +apc +cLU +cLU +crP +cLU +cLU +cLU +cLU +ctg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(127,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +aaH +aaP +aaY +abl +abM +acl +acX +adr +adW +aeq +aeE +afd +afz +agj +agZ +agv +ahh +ahO +ais +aiS +ajP +agv +aky +alw +alU +ajL +anP +aog +aoU +apN +aqE +aqw +anG +asp +aqA +atK +auD +auD +awM +axp +aIN +ayQ +axW +aAW +aBj +aDb +aEt +aBj +aBj +aBj +aIU +aJl +aNY +aPD +aQQ +azK +azK +azK +azK +aZj +baY +bct +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +aJi +bBR +aJi +aJi +aJi +bIf +bJA +bKW +aJl +bNU +bQp +bNU +bNU +bNU +bUK +caq +bXh +bZd +caq +bxl +cdc +cgS +cgb +chD +ciA +ckg +clv +cmS +cgs +cpn +cpn +bSK +cCf +cfq +cuB +cuB +cww +cww +blp +czN +cAN +cBY +cFC +byF +aaf +cLU +cLU +rQB +cpF +cLj +cLt +bBe +aQh +cIl +cGR +cGR +csX +csX +cGR +csX +cGR +cLU +apc +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(128,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaf +aaG +aaG +aaG +aaG +abG +aco +aco +adJ +aco +aco +aco +aco +age +aco +agN +agv +agv +agv +agv +agv +agv +agv +anG +anG +anG +anG +anG +anG +anG +anG +asf +anG +anG +asq +aoH +atR +auG +avG +awP +axq +aya +ayR +azY +aBc +aBj +aDd +aEx +aBj +aHp +aIY +aIU +aJl +aOb +aPD +sWj +cYR +cYR +cYR +cYR +aSb +bbb +bcz +bAb +bhY +bgB +bgn +bjo +bGo +bAb +bnH +bpP +brK +btq +buW +bwW +byq +bAb +bAb +bDk +bwW +bwW +sDc +bJH +gAA +aKH +bNU +bPx +bPx +bQH +bNU +bUK +caq +caq +caq +caq +caq +caq +caq +caq +caq +ciA +ciA +ciA +coy +cgs +cpj +cpj +cpj +cpj +cpj +cpj +cpj +cpj +cpj +cpj +cBD +byA +byA +byA +byA +cLU +cLU +cLU +rQB +rQB +bBe +cKX +ccQ +aQh +cIl +cGR +cGR +csX +csX +cGR +csX +cGR +cLU +apc +cLU +cLU +crP +cLU +cLU +abc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(129,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +aaf +aaf +cLU +cLU +abb +abn +abN +acs +acs +acD +adB +adB +adB +adB +aeQ +afk +afJ +agw +agT +ahx +ahx +ahx +ahx +ahx +akp +agA +agV +adB +ans +aol +apg +apB +aps +are +arJ +asv +aoH +atM +auF +avF +awO +axr +axZ +ayT +ayn +aBj +aBj +aBj +aEw +aBj +aBj +aBj +aKM +aJl +aOa +aPG +aQS +aQS +aQS +aQS +aQS +aQS +bba +bcv +nYi +bgT +biM +bhW +bzt +bgT +pbo +bnG +aQS +aQS +bba +bcv +bcv +beT +aQS +aQS +bDj +aQS +aQS +aQS +bJG +gAA +aLV +bNU +bPx +bPx +bSk +bNU +bkx +bTF +bIK +bKi +bTF +bTF +bTF +bTF +bTF +bTF +bTF +bTF +bQS +bRR +bSg +crv +bTF +bTF +bTF +ctv +cuC +bPx +bLm +bLm +baA +cBA +bLm +cis +bQH +cea +cea +cea +cea +cea +cea +aQh +aQh +aQh +apc +csA +csX +csX +csX +csX +csX +csX +csX +aaf +apc +aaf +aaf +crP +aaf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(130,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +aaf +aaf +cLU +cLU +cLU +abb +abp +abp +abp +abb +adj +adl +cpc +adl +aeR +afl +afA +agl +afs +adl +afX +afY +avA +abb +abb +alf +abb +anQ +anQ +anQ +aoC +anQ +aoH +alu +alu +alu +asF +aoH +atV +auH +avz +aoj +axu +axT +ayx +aAa +aBj +aCo +aCo +aEt +aBj +aHp +aIZ +aIU +aJl +aOc +aPH +aLY +bpK +aLY +aLY +aLY +aLY +aZc +aLY +aLY +biI +aLY +bia +bjn +biI +aLY +aLY +aLY +aLY +btr +bvj +aLY +beV +aLY +aLY +bDl +wVz +wVz +qHi +bvj +sfO +bMw +bNU +bCv +bLW +bQU +bNU +bNU +bWa +bDt +bPx +bQH +cbI +cbI +cbI +cbI +cbI +ciG +ciG +ciG +ciG +ciG +ciG +cir +bQH +cis +ctw +cuD +cfc +cvM +cvM +cvM +cCA +cAP +cBZ +cCR +cbs +bPx +bPx +bPx +cis +bzX +cLU +cGQ +cHy +cHP +cIn +cGR +cGR +csX +csX +cGR +csX +cGR +aaf +apc +apc +cLU +crP +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(131,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +csM +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abb +abb +adO +abb +abb +abb +abb +abb +agq +abb +abb +abp +abp +abp +abb +agm +akZ +aln +amx +amH +anu +aon +anQ +apa +apF +apF +apF +asE +aoH +atT +atT +atT +aoj +axt +avC +ayU +azX +aBd +aCl +aDf +aEy +aBj +aBj +aBj +aIU +aJl +aJl +aGJ +aJl +aJl +aJl +cJa +aJl +aBu +aJl +aBu +aJl +aJl +biO +aYT +bkP +aJl +aJl +aGO +aJl +aGO +aJl +aJl +aJl +aJl +aJl +aJl +aJl +bEJ +bEJ +aJl +aJl +aJl +aJl +bDt +bDt +bDt +bDt +bDt +bDt +bVV +bDt +cbn +bDt +cbI +cde +ceO +cgf +cbI +ciR +chP +cly +cmU +cnQ +ciG +ciG +ciG +ciG +ciG +cwX +cvN +cvN +cvN +cvN +cvN +cvN +cvN +cbq +cDB +bPx +bLm +cKI +ckG +bzX +cLU +cHc +cHy +cHP +cIo +cGR +cGR +csX +csX +cGR +csX +cGR +aaf +cLU +apc +cLU +crP +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(132,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aap +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +abb +adv +adl +aaS +abb +cLU +abb +afL +aqL +adl +abb +cLU +aaf +aaf +abb +ajE +afV +agm +anQ +amI +aoc +anR +anQ +aqC +aqt +aXP +asa +asE +aoH +atP +atP +atP +atP +aoE +ayb +ayW +aoE +aBj +aoO +aoO +aEB +aBj +aHr +aJa +aIU +aBj +aOq +aPI +aIe +aUf +aUD +aSS +aYy +aSS +aUU +aSS +bef +aZz +bgE +bic +bjq +aZz +blV +lbI +bpS +bnL +bts +aLS +bxs +bxt +bAe +bvv +bDt +mue +bGy +bDt +bJJ +cpy +bMx +bDt +bJT +bQY +bJU +bDt +aUM +bWc +bXl +bZj +cau +cbI +cdg +ceP +cgd +aZS +ciS +ciS +ciS +ciS +cnS +ciG +cqi +cro +csD +ciG +cuF +cvN +bXv +cxA +bYJ +cyD +caV +cvN +cCT +cDC +bSk +bNU +bzX +bzX +bNU +aGX +cGQ +cHy +cHP +cIn +cGR +cGR +csX +csX +cGR +csX +cGR +aaf +cLU +apc +cLU +csM +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(133,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cbO +crP +crP +crP +crP +crP +crP +crP +crP +aaf +aaf +abb +adu +adl +acG +abb +aaf +aeS +afW +agr +afW +aeS +cLU +cLU +aaf +abb +abp +abp +abp +anQ +aiJ +aiJ +aiJ +anQ +apG +aqu +arD +asa +asG +asm +atO +auI +avJ +awQ +axw +axw +ayV +azZ +atP +aBj +aBj +aBj +aGn +aBj +aBj +aBj +aBj +aOe +aPI +aHT +aTX +aUE +aSP +aSP +aSS +aSP +aSS +beg +aZz +dxK +eNu +iYA +aZz +btu +bnK +bpQ +bnK +blU +aLS +bwX +byr +bAc +bBU +bDm +bEK +bEK +aRt +bsc +bEN +bLR +bDt +abI +bEL +bEL +bTs +bUt +bWb +bXo +bZi +cat +cbI +ccL +ceP +cgd +aZS +ciS +ckj +clz +cmV +cmV +coS +cqh +crn +csC +ctD +cuF +cvN +bXs +cxz +bhO +czd +ciL +cCa +cCa +cCa +cCa +cCa +clT +aaf +aph +cLU +cHc +cHy +cHP +cIo +cGR +cGR +csX +csX +cGR +csX +cGR +aaf +cLU +apc +cLU +abc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(134,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +abb +ads +adl +adi +abb +cLU +aeS +agS +acn +agS +aeS +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +alu +apF +apF +apF +apF +asH +avb +atP +auO +avK +awS +axz +ayf +ayY +aAd +aBg +atP +aDm +aEP +aGo +aHH +aJr +jKq +aMj +aOk +aPI +aHT +aTX +aUF +aWe +aXz +aSS +bbo +aSS +kSt +aZz +dxK +bid +iYA +aZz +blX +bnO +bpZ +brN +btu +aLS +bxa +byr +bAg +bBU +bDt +bpf +bGA +bDt +cpw +bEP +bMz +bDt +bPD +bRa +bRa +bTx +bUx +bWe +cpN +bZk +bZO +cbI +cdi +ceP +cgd +aZS +ciV +ckl +clB +cmX +cnU +ciG +cqk +crr +csF +ciG +cgC +cvN +cwv +cxG +cxz +czg +cAj +cCb +cjk +cCb +cEu +crs +aaf +cLU +aph +cLU +cGQ +cHy +cHP +cIn +cGR +cGR +csX +csX +cGR +csX +cGR +aaf +cLU +apc +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(135,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +abb +abb +als +abb +abb +aaf +aeS +agS +agh +agS +aeS +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +aap +cLU +alu +azR +aqP +arw +arN +asH +aiu +atP +auJ +auJ +crS +axy +aye +ayX +aAc +aBe +atP +aEh +aEQ +aGp +aGp +aGp +aKN +aMc +aOj +aPJ +aHT +aTX +aUF +aTk +aTk +aSS +aTk +aSS +bmQ +aZz +dxK +bid +bjs +aZz +blW +bnN +bpT +brM +btt +buc +cez +bwZ +bAf +byt +bDn +bEM +bGz +bIh +bEL +bLp +bEL +bNZ +bEL +bQZ +bSm +bTu +bUw +bWd +bXp +bZk +caw +cbI +cdh +ceR +cgg +cbI +ciT +ckk +clA +cmW +cnT +ciG +cqj +crp +csE +ciG +cuE +cxF +cwu +cyD +cyF +cyD +cbe +cDF +cAV +cGM +cEt +crs +aaf +cLU +aph +cLU +cHc +cHy +cHP +cIo +cGR +cGR +csX +csX +cGR +csX +cGR +aaf +cLU +apc +cLU +crP +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(136,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +aeS +agS +afP +agS +aeS +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +aap +aaf +aaf +aoH +aoH +aoH +aRU +aoH +anh +akq +atP +auX +auX +crV +axA +ayg +ayY +aAc +aBi +atP +aEv +aER +aDV +aFG +aHt +jKq +aKU +aOl +aPI +aHT +aTX +aUF +aSS +aSS +aSS +aSS +aSS +aSS +beW +bgF +bih +bjg +aZz +blY +bnQ +bpg +brO +boR +bvk +bxb +byu +bAk +bBX +aPV +bEP +bGF +bIi +bJL +bLx +bMA +bNZ +bEL +bEL +bSn +bDt +bUz +bWg +bXw +bZm +caz +cbI +cdk +ceS +cbI +cbI +ciX +bck +clD +ciG +ciG +ciG +ciG +crt +ciG +ciG +bTQ +cvN +cwz +cxH +cxz +czi +cbg +cCb +cjm +cCb +clL +crs +aaf +aaf +aph +cLU +cGQ +cHP +cHP +cIn +cGR +cGR +cGR +cGR +cGR +cGR +cGR +aaf +cLU +apc +apc +crP +cLU +aap +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(137,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +cLU +cLU +aeS +cLU +cLU +cLU +aeS +cLU +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +aaf +cLU +cLU +aoH +aqJ +ars +aoH +asJ +asl +atP +avm +auX +crV +axA +ayg +ayY +aAc +aBh +atP +jKq +aFZ +jKq +jKq +aJb +jKq +aKQ +aOl +aPI +aHT +aTX +aUF +aVS +aXB +aYF +aZr +aSS +bcG +aEe +dxK +big +bjt +aZz +bmY +aYe +buc +buc +buc +buc +bxC +bxC +bkc +bxC +bxC +bEO +bGD +bxC +bxC +bLt +bxC +cBI +bPE +bRb +bRb +bTJ +aUg +bWf +bXt +bZl +cay +bTJ +cdj +bTJ +cfY +cjp +ciW +ckm +clC +cmY +cmY +cjz +cql +cru +cfY +ciB +bTO +cvN +cwy +cyD +cyD +bZW +cAV +cCa +cCa +cCa +cCa +cCa +aaf +aaf +aph +aaf +cIO +cHy +cHy +cHy +cIn +cIO +cIn +cIO +cIn +cIO +cIn +aaf +cLU +cLU +apc +crP +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(138,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +aeS +cLU +cLU +cLU +aeS +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aap +aaf +cuK +asj +apt +apv +apx +apZ +aqB +atP +aBl +auX +crV +axA +ayg +azc +aAf +aBm +aDy +avO +aET +aIn +aJB +aGs +aDp +aMp +aOm +aPK +aHT +aTX +aUG +aVX +aXD +bfG +aZE +bcM +bcO +beX +bgG +bij +bjy +aZz +bnl +bnS +bnS +brJ +btO +bvm +bxe +byx +bAm +bBZ +avy +bER +bGI +bIk +bDp +bLz +bDp +bOc +bDp +bDp +bSo +bTz +bUE +bWi +bXz +bZp +caC +cbQ +cdm +ceU +cgl +chH +ciZ +cko +clF +cna +cna +cna +cna +crw +cuf +clM +bTO +cvN +bXB +clZ +ciE +bZX +cbh +bvs +cqx +cqH +crk +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cto +aaf +aaf +apc +aaI +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(139,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aac +cLU +cLU +cLU +cLU +aaf +aap +cLU +aoH +aqK +art +aoH +auP +atl +atP +auY +auY +crY +axy +ayg +aza +aAe +aDt +atP +aVh +awg +bbX +ayt +aGs +aDp +aLv +aMZ +aQe +aRu +aSQ +aUH +aVW +aZm +aZm +aZA +aSS +bcN +aZz +ceW +bii +bjw +aZz +blZ +bnR +bqb +bqb +btw +bvl +bxd +byv +bAl +bBY +bDo +bEQ +bGG +bIj +bJM +bLy +bMy +bOa +bPF +bDo +bEQ +bTy +bUD +bWh +bXy +bZo +caB +cbN +cdl +ceT +cgh +chF +ciY +ckn +clE +cmZ +cnW +coU +cqm +csg +cfY +ciD +bTO +cvN +cvN +cvN +cvN +cvN +cvN +cvN +coI +cLU +crg +crC +cLU +cLU +cLU +cLU +cLU +crP +crP +crP +cbO +crP +crP +crP +crP +crP +crP +cLU +cLU +cLU +apc +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(140,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +aoH +aoH +aoH +aoH +alu +alu +atP +ava +avQ +awU +axz +ayh +aze +atP +aoE +atP +aDs +aDs +aDs +aHL +avO +aME +aMy +aOw +aQf +aRv +aSR +aUI +aWa +aXF +aZp +aZK +bbj +bei +aZz +dxK +bii +bjz +aZz +bmf +bnU +bnX +bsv +bIU +bvo +bxC +aMm +bAo +bxC +aMm +bxC +bGJ +bIm +aSc +aSk +bxC +bOd +bxC +aSk +aSk +aTI +bUN +bWk +bXC +bTJ +bTJ +bTJ +cdo +bTJ +cfY +cfY +cjb +bcx +clH +ciU +ciU +ciU +ciU +cry +ciU +ciU +bTO +ckS +ciF +cKU +crG +cKW +cKZ +crG +coI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +apc +abc +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(141,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +apc +aph +aph +aph +aph +aph +apc +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +aaf +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +atP +auZ +avP +avP +avP +avP +azd +aAg +aBn +aCr +atP +aap +aDs +aHK +aFi +aDp +aMl +aNd +aOM +aRw +aSS +aUF +aWm +aSS +aSS +aSS +aSS +btA +aZz +dxK +bii +aIF +aZz +bmb +bnU +bnX +brQ +bty +bvn +bxF +byy +bAn +bCa +bDq +bxF +bEz +bIl +aSa +bLA +bMC +bLC +bPG +bLC +bSq +aTH +bUF +bWj +bXA +bTJ +cax +cbR +cdn +cbR +chE +caE +cja +ckp +clG +cnb +cnY +ciU +cqn +crx +csG +ciU +bTR +bVx +cxv +chN +czf +cKV +cKY +cqr +cqA +aaf +aaf +aaf +aaf +aaf +crP +crP +crP +crP +crP +crP +crP +crP +crP +cto +cbO +crP +crP +crP +aaf +aaf +apc +crP +aaf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(142,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aap +cLU +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +atP +avd +avR +avR +axG +axG +azf +atP +aBo +aCs +atP +aap +aDs +aHK +aKZ +aKZ +aKZ +aKZ +aKZ +aKZ +aST +aUv +aWd +aTX +aTX +aSS +aSS +ajk +aZz +ccd +bik +bjC +bkX +bmn +bnW +bnX +brT +btI +bvp +aLX +byB +bAq +byz +bDr +bxF +bGL +bIo +bxF +bLC +bLC +bOf +bPI +bRd +bSi +bTJ +bSJ +bWk +bXE +bTJ +caL +cbT +cdq +cbS +cgk +caE +cjd +ckr +clJ +cnd +cnZ +ciU +cqp +crA +csJ +ciU +bTO +crG +crG +crG +crG +crG +crG +crG +coI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +apc +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(143,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +atP +atP +aoE +aoE +aoE +axC +axC +aoE +atP +aqr +aqz +atP +aap +aDs +aHK +aKZ +arT +aMr +aOn +aPM +aKZ +aSf +aUo +aWh +aZm +aZm +bbd +aSS +bej +aZz +dxK +bii +bdV +bkV +bmm +bnV +bnX +brS +btB +bvp +bxf +byz +bAp +byz +byz +bES +byz +bIn +bJO +bLB +bMD +bOe +bPH +bRc +bSr +bOd +bUE +bWl +bXD +bZs +caK +cbS +cdp +ceV +cgi +caE +cjc +ckq +clI +cnc +cnc +coV +cqo +crz +csH +ctE +bTO +crG +cLU +cLU +cLU +cLU +cLU +cLU +coI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aap +cLU +cLU +aaf +cts +cLU +cLU +cLU +cLU +cLU +cLU +apc +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(144,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +cLU +cLU +cLU +cLU +aaf +cLU +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anU +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHO +aLd +aKS +aMt +aGD +cfg +aKZ +aUn +aUx +aWm +aSS +aSS +bbg +aSS +beZ +aZz +dxK +bii +aIE +aZz +bmb +bnX +bnX +brP +btM +bvr +bxF +byC +bAt +bzW +bDs +bxF +bGN +bIr +aSa +bLD +bMF +bOh +bPJ +bRe +bWM +aTI +bUR +bWk +bXG +bTJ +caM +bSB +cdr +bSB +cjo +caE +cjc +cjc +cjc +cjc +coc +ciU +cqq +crB +csK +ciU +bTO +crG +aaf +aaf +aaf +aaf +aaf +aaf +cqD +aaf +aaf +crP +crP +crP +cto +cbO +crP +crP +cto +aaf +cbO +crP +crP +crP +crP +crP +aaf +aaf +aaf +crP +aaI +crP +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(145,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaf +aaf +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHK +aKZ +aBf +aMs +aOo +aPN +aKZ +azL +aBq +aVZ +aBq +aBq +aBq +bcB +aBq +aZz +bgH +bii +bjD +aZz +bmw +bnX +bnX +btx +btK +bvq +bwk +aLT +bAr +bwk +aLT +bwk +bGM +bIp +aSd +aSp +bwk +bOg +bwk +aSp +aSp +aTI +bUQ +bWm +bXF +bTJ +caE +caE +caE +caE +caE +caE +cje +cia +clK +cne +coa +ciU +ciU +ciU +ciU +ciU +bTT +crG +cLU +cLU +cLU +cLU +cLU +cLU +cqB +bpO +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(146,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaf +cLU +cLU +cLU +cHK +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHK +aKZ +azJ +aMs +aOo +aPP +aKZ +aGI +aUw +aWf +aUt +aUt +aUt +bbM +baM +aZz +dxK +bii +rkN +aZz +bmz +boj +bqd +bqd +btP +bvu +bxh +byE +bAv +bCd +bDz +bEW +bGP +bIu +bDz +bDz +bMB +bOj +bPL +bDz +bEW +bTG +bUT +bWq +bXJ +bZt +caF +cbP +cdt +bzT +ceX +caI +ciU +ciU +ciU +ciU +ciU +ciU +clM +bTa +bTh +bTh +bSM +crG +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(147,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaf +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHK +aJd +aJF +aMu +aPQ +aPO +aQW +aSg +aUq +aVY +aXA +aXA +aXA +bbr +bfb +aZz +bRJ +bii +rkN +aZz +bnm +bof +bqc +brV +bwY +bvt +bxg +byD +bAu +bCc +bDw +bET +bGO +bIt +bJS +bIt +bMG +bOi +bPK +bIt +bSu +bTA +bUS +bWp +bXI +aWU +caG +cei +cds +cds +cds +cfZ +caI +bOD +bRK +bSa +bSa +bSa +bSa +bSM +crG +crG +crG +crG +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +crP +crP +crP +cto +crP +crP +crP +apc +apc +apc +apc +apc +apc +apc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(148,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +csT +aaf +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +abc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHK +aKZ +aKZ +aKZ +aKZ +aKZ +aKZ +aKZ +aXf +aKv +aXS +aTC +aWL +bcC +bfg +aZz +bfa +bim +rkN +aZz +bni +bni +bqe +bni +bni +bBW +bwk +byJ +bAx +bwk +aLT +bEY +bGR +aLT +bwk +aSA +bME +bOl +bwk +aSA +aSA +bTJ +bUV +bWs +bXL +aWU +caH +cel +cdu +bWO +cgp +chJ +caI +bPj +cnX +chh +chh +cpi +cpi +crG +crG +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(149,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aob +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +arf +aap +atC +aHK +aGs +aKW +aKT +aOr +aQV +aQX +aKZ +aUs +aWg +aOp +aTB +bbe +bcA +bbi +aEi +bgJ +bil +rkN +aZz +bmA +bok +bok +brX +bnn +bwk +bwk +bqq +bAw +bwk +bIA +bEX +bFd +bGQ +bIC +aSq +bMJ +bOk +bPM +bPM +bSv +bMK +bUU +bWr +bXK +caI +caI +caI +caI +caI +caI +caI +caI +bPd +clN +clN +clN +clN +clN +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cqv +cmc +aaf +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(150,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aap +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +ctg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +atC +aHP +aJy +aLh +axD +aOt +aPS +aPS +aSh +aUu +aXE +aUt +aUt +aUt +sFU +bcs +aEi +cvk +bil +rkN +aZz +bmC +bon +bqg +brZ +btU +bvx +bxm +byL +bAy +bwk +bDA +bEX +bGT +bGQ +bJV +aSq +bMM +bOn +bPP +bPN +bSx +bMK +bUP +bWt +bXN +bZv +caN +caN +caN +caN +cgr +ccP +cjh +bPl +clP +clN +cjt +coX +cqu +cqv +clb +ceN +cuL +ctF +ccm +cxM +bpx +cuP +cmg +ctF +cCS +cCS +cnP +cEW +cqv +cLU +aaf +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(151,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aam +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHK +aGs +aLf +aMF +aOs +aPR +aDZ +aKZ +aUt +aMw +aTs +aUy +aUt +arU +bfw +aZM +bRL +bil +bjv +aZz +bSy +bol +bqf +brY +btT +aLT +bkz +byK +bAx +bwk +bDa +bEZ +bGS +bIv +bOT +bDJ +bML +bOm +bPN +bPN +bSs +bMK +bUW +bWr +bXM +bZu +bZu +bZu +bZu +bZu +cgq +chK +cjg +bPk +clO +bVJ +cod +coW +cbm +bYD +ceo +ceC +cgZ +caA +btF +ccu +bLJ +ceC +cqd +ccl +cqE +cqP +chw +cEU +cqv +cLU +aaf +cLU +cLU +cLU +cLU +csM +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(152,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +aDs +aHK +aGs +aLf +aAz +aOs +aPR +aRa +azM +aZl +aWi +aUJ +iUa +aUt +aUt +aUt +bbK +bff +bin +bjN +aZz +bmD +bUZ +bqi +bkF +bsG +bwk +bxq +byK +bAA +bwk +bDJ +bDJ +bGV +bDJ +bDJ +bDJ +bMR +bOq +bPR +bPR +bSw +bMK +caP +bWv +bXP +bZx +caO +cbV +cdv +cdv +ceY +ccP +cji +bQz +clQ +clN +cof +coX +cqz +cqv +csN +ctI +cuM +ctF +ckJ +ccJ +bpx +cuP +czx +bpx +cCV +cDM +cEy +cEZ +bmh +bmh +cqv +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(153,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anS +atW +atW +atW +atW +atW +atW +atW +atW +atW +atW +anS +aap +atC +aHK +aGs +aLf +aMz +aOs +aPR +aQZ +azM +aUW +aWi +aUt +aUt +aUt +aUt +bcF +aZz +bOI +bid +bjH +aZz +bnn +bnn +bnn +bnn +bnn +bwk +bxp +byM +bAz +bwk +bDC +bFe +bGU +bID +bJW +bLo +bMQ +bBB +bPQ +bQG +bVa +bMK +bYC +bWu +bXO +bZy +bZy +bZy +bZy +bZy +bZy +bZy +bZy +bQy +clN +clN +clN +clN +clN +cqv +cqv +ctF +ctF +ctF +ckB +cxN +ctF +bpx +ctF +ctF +cjM +cDL +cEx +cEX +cFH +cso +bmh +cLU +cLU +cLU +cLU +abc +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(154,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +anS +aom +anS +anS +anS +anS +anS +anS +anS +anS +aom +anS +aaf +atC +aKO +aJz +aLf +aMC +aOs +aPR +aRc +azM +aWb +aWk +aUt +cdK +aXH +aZo +bdI +aZz +cyq +bid +rkN +aZz +bkv +boq +bqm +bsd +bov +bwk +bwT +byO +bAB +bCe +bDE +cMf +bGX +bIH +bJY +bLo +bMK +bMK +bMK +bMK +bMK +bMK +bVi +bWw +bXQ +bZB +caW +cbX +cdx +cid +cid +chM +bZy +bQD +aZT +cLU +cLU +cLU +cLU +cLU +cqv +cdI +cuO +cvK +cmd +cxQ +cyJ +czr +bpx +cBt +cCW +cDL +cEx +cuP +cEy +cGK +bmh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(155,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aaf +aDs +aEu +aAK +aLf +aLq +aOu +aPR +aRb +aTe +azN +aWj +aBy +aBy +aBy +aTe +aTe +aZz +bjP +bib +bjP +aZz +bmJ +bop +bqj +bqj +btX +bwk +bxu +byK +bAx +bwk +bDB +bFf +bGW +bIG +bJX +bLo +bFD +bsr +bCp +bRg +bSz +bTH +aUL +bWv +bXP +bZy +cdw +cbW +cfa +cfk +cgx +chL +bZy +bQD +aZT +cLU +cLU +cLU +cLU +cLU +cqv +ctJ +cuN +cvJ +clq +cxP +cyI +czp +bpx +cBs +cuP +cDM +cEy +cuP +cEy +cGK +bmh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(156,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aap +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aDs +aDs +aDs +aHX +aNc +aMD +aOx +aPT +aRd +aTe +cgF +aWo +aXI +aXI +bbk +beY +beu +aEi +dxK +bid +bjR +bkY +bmN +bos +bqo +bos +btZ +bvy +bxv +byR +bAC +bwk +bCp +aQY +bGY +aQY +aQY +bCp +bFD +bFD +bCp +bRi +bSC +bTK +bVb +bWy +bXR +bZA +bZA +bZA +bZA +bZA +bZy +bZy +bZy +bRC +aZT +cLU +cLU +cLU +aac +aaf +cqv +cgB +cuP +cvP +cmq +cnN +cyK +czs +bsN +cjj +cCY +czv +cuP +cuP +cEy +cGK +bmh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(157,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aDs +aus +aDs +aHW +aLf +axE +aOv +axE +axE +aTe +cgA +aWn +aUz +aUz +bbh +bcE +bcH +bdK +bfk +bit +bjQ +aZz +bmM +bmP +bqn +bmP +btW +bwk +bzf +byQ +bAx +aLT +bjB +bFB +bHb +bKf +bFD +bLE +bFD +bFD +bCp +bRh +bHj +bTI +aUL +bWx +bXP +aXw +caX +caD +cdz +bZA +cgy +bYf +bQt +bQD +bYf +bYf +cLU +cLU +cLU +cLU +cqv +cuP +cuP +cvL +cmk +bpx +bpx +ctF +ctF +ctF +cCX +cDN +cEz +cFb +cFI +csp +bmh +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(158,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aDs +aus +aDs +aIa +aLf +aSu +aOz +aPW +aRe +azN +aUN +aWq +aXN +aXN +bbl +bcJ +bdN +aIO +bgK +biF +bjS +aZz +bmZ +bna +bna +bna +bua +bwk +bxw +byS +bAD +bCf +cMe +bDO +bHc +bFD +bFD +bLq +bFD +bNV +bCp +bRj +bRj +bRj +bRj +bWz +bXS +bZE +cbd +ccb +cdB +bZA +bYf +bYf +bpv +bRG +bRP +bYf +cLU +cLU +cLU +cLU +cqv +ctO +cuR +cvS +cnH +bpx +csO +czu +cmw +bmh +bmh +cqv +cqv +cqv +bmh +bmh +cqv +aaf +aaf +aaf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(159,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aDs +aDs +aDs +aLe +aLf +aAz +aOy +aPU +aPU +aSi +aUK +aWp +aXJ +aXJ +aXJ +aXJ +bdM +aEi +bgJ +bix +rkN +aZz +bmP +bov +bov +bov +bua +aXK +aXK +aXK +bBJ +aXK +bBT +bFC +bGZ +bmp +bJP +bLF +bFD +bFD +bCp +bRk +bSA +bTL +aWP +bWx +bXP +aXw +cbb +bSE +cdA +bZA +bZG +bXj +bXj +bXj +bQD +bYf +cLU +cLU +cLU +cLU +cqv +bLH +cuQ +chV +cnj +btn +ceC +cpH +cAp +bmh +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(160,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +csM +cLU +cLU +aaI +aaq +aaI +aaI +aaI +aam +aaI +aaI +aaI +aam +aaI +aam +aam +aam +aam +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aDC +bdx +bdz +aLf +aMC +aOA +aPR +aRf +azN +aUO +aWr +aWr +aWr +aWr +aWr +aWr +aEi +bgJ +bix +bjv +aZz +bmP +bmP +bmP +bmP +bub +aXK +bay +bwu +bAF +aXK +bEV +bFD +bmd +bFD +bFD +bLs +bMT +bFD +bCp +bRm +bSG +bTN +bVd +bWB +bmj +bZA +bZA +bZA +bZA +bZA +caR +bXj +ccc +bXj +bQD +aZT +cLU +cLU +cqv +cqv +cqv +cqv +clt +cie +cnV +bpx +csP +czv +cAt +bmh +cLU +crc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(161,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaI +cLU +aaf +aaf +aaf +cLU +aaf +aaf +aaf +cLU +aaf +aaf +cLU +cLU +aam +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +aDC +ayF +aIr +aLf +aMz +aOA +aPR +aRg +aTe +aUZ +aWC +aYh +aYh +bbC +aYh +aYh +aEi +bfa +bmB +bjZ +aZz +bna +bna +bqp +bna +bna +aXK +bxx +byT +bAE +aXK +bFD +bjG +bHa +bEV +bFD +bLG +bFD +bsr +bCp +bRl +bPw +bTM +aWP +bWA +bky +bmk +bmr +bpW +bTl +bXU +car +bnP +cca +bXj +bQD +aZT +cLU +cLU +bmh +crD +csO +bpx +cuP +chX +cnN +bsN +bsN +bsN +bsN +cgv +cqF +cqR +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(162,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaI +cLU +amJ +anB +aoo +cLU +amJ +anB +aoo +cLU +amJ +anB +aoo +aaf +aaI +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aDC +ayB +aIb +aLf +aAz +aOC +aPY +aRj +aTe +aVa +aWD +aWD +aWD +aWD +aWD +aYh +aEi +bgJ +bKy +bkb +aZz +bYf +bYf +bYf +bYf +bYf +aXK +aXK +bAs +aXK +aXK +bCp +bFh +bCp +bCp +bCp +bCp +bCp +bCp +bCp +bRn +bRn +bRn +bRn +bfh +bYf +bYf +bYf +bYf +bXj +bYk +cbf +cbf +ccG +bXj +bQD +aZT +cLU +cLU +bmh +cen +ceC +cgt +ceC +cjq +cnV +bpx +csO +czn +cEZ +bmh +cLU +cqD +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(163,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +aaf +cLU +cLU +aaI +aaf +amJ +anw +aoo +cLU +amJ +anw +aoo +cLU +amJ +anw +aoo +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aDC +aDC +aGC +aIb +aLf +aMG +aRk +aPX +aRh +aTe +aVb +aWE +aVk +aZy +bcP +bcY +cdD +aEi +bgJ +aLD +bka +bmT +aVJ +aLN +aVJ +aVJ +aXq +aVJ +bxy +byU +bAG +bDi +bDF +bFg +bHd +bKh +bmX +bpr +bPO +bPO +bPO +bPO +bPO +bPO +bPO +bxV +bYg +bPO +bPO +bwV +bXj +bXj +bXj +bXj +bXj +bXj +bQD +aZT +cLU +cLU +bmh +cki +csP +bpx +cuP +cjn +coe +cpt +ceC +cpH +cAp +bmh +cLU +cqD +aaf +crP +crP +crP +crP +crP +crP +cto +cbO +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(164,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaI +aaf +amJ +anw +aoo +aaf +amJ +anw +aoo +aaf +amJ +anw +aoo +aaf +cLU +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +arK +aEZ +aGL +aIR +aLf +aLf +aLf +aLf +aLf +aTe +aTe +aTe +aTe +aZz +aZz +aZz +aZz +aZz +bjj +bjk +bGd +aZz +bpj +aLU +bpj +bpj +bpj +bpj +brh +brh +brh +brh +bDG +bFk +brL +bYf +boe +bsE +bMO +bMO +bMO +bMO +bMO +bMO +bMO +bMO +bIw +bIw +bIw +bYd +caQ +caQ +chC +bOC +bOC +bOC +bRT +bYf +cLU +cLU +cqv +cqv +cqv +cqv +bpx +cjy +cuW +cqv +csP +czx +cmG +bmh +cLU +cqD +cLU +cLU +cLU +aap +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(165,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +amJ +anw +aoo +cLU +amJ +anw +aoo +cLU +amJ +anw +aoo +aaf +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +arK +aEW +aug +bMP +aJR +aJR +aJR +aJR +aJR +aJR +aJR +aJR +aJR +bbf +bbm +bcK +bdQ +bdQ +bgL +biH +rkN +cte +bpj +boz +bqr +bsk +bsf +bvz +bvA +bxB +bAH +brh +bDU +bFj +bIx +bIx +bIx +bIx +bMO +bOr +bPS +bOs +bMO +bTP +bVe +bZJ +bXV +bZI +bXY +bYc +bYc +bYc +cci +bYf +bYf +cjO +bYf +bYf +aaf +aaf +aaf +aaf +cqv +ctQ +chw +cjv +cuP +cqv +cqv +cqv +cqv +cqv +atf +cCJ +aap +cLU +cLU +cLU +aaf +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +eYg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(166,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaI +aaI +cLU +cLU +amJ +anw +aoo +cLU +amJ +anw +aoo +cLU +amJ +anw +aoo +cLU +cLU +cLU +cLU +cLU +aoJ +aCv +aCv +aCv +aCv +aDC +aFd +aDC +aIg +aIg +aIg +aIg +aIg +aIg +aIg +aIg +aIg +aIg +aZz +bbn +bcQ +bdV +bdV +bdV +bKy +rkN +cte +aFz +bpl +odK +bui +byX +bvz +bzc +boI +bAJ +bpp +aXx +aXx +bIx +bvR +bKa +bvR +bMO +bOt +bPU +bOs +bMO +aTZ +bVh +bWE +bXX +bZK +caJ +cce +cdH +bYc +cgG +bYf +cjl +chB +ckt +aZT +cLU +cLU +cLU +aaf +cqv +ctR +cuP +cvZ +cwQ +cqv +cLU +aaf +cLU +cLU +cLU +cqD +aap +cLU +cLU +cLU +aaf +aaf +aaf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(167,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +cLU +aaf +cLU +cLU +aaf +aca +aaf +aaf +aaf +aca +aaf +cLU +aaf +aca +aaf +cLU +cLU +cLU +aoJ +aoJ +aoJ +azD +aBp +aEX +aCv +aEC +aFc +aDC +aJI +aLj +aMP +hLX +bFM +aRK +aTh +aVc +aTh +aYj +aZz +bbn +bcL +bdR +bfl +bgI +biJ +bkd +bkZ +aFz +bpl +bqt +buj +byY +bvz +bzA +boI +bAI +bpp +brH +bFl +bIx +bDT +bKc +bDT +bMO +bOs +bPT +bRo +bRo +aTY +bVg +bWD +bXW +bZM +bXY +ccs +cdG +cgR +bMU +bYf +cjf +cjR +cgV +aZT +cLU +cLU +cLU +aTw +cqv +cqv +cqv +cqv +cqv +cqv +cLU +aaf +cLU +cLU +cLU +cqD +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(168,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +akH +alp +alp +alp +ace +alp +alp +alp +ace +alp +alp +alp +ace +alp +alp +alp +ash +asD +asI +asT +ati +auq +auS +avX +aSG +aFw +aJD +aJJ +aJW +aMg +woj +hLX +aRK +hLX +aVc +hLX +aYj +aZz +bcw +bdu +aZz +aZz +bdJ +hPt +rkN +blh +aFz +bpl +bqZ +bse +byZ +bvz +bxz +boI +bAK +bpp +bDK +bDK +bIx +bFn +bKc +bLw +bMO +bHG +bOs +bOs +bOs +bTU +bVk +bWG +bYe +cfd +bXY +ccA +cdM +bYc +bNe +bYf +bYf +bYf +bYf +bYf +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cqD +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(169,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +cLU +aaf +aaf +aca +aaf +cLU +aaf +aca +aaf +cLU +aaf +aca +aaf +cLU +cLU +cLU +aoJ +aoJ +aoJ +aAk +aDB +aDY +aCv +aED +aDC +aDC +aLi +aLl +aMR +aNj +aRL +aRL +aRL +aRL +aRL +aRL +aZB +bbH +bdd +bey +aZz +bgV +hPt +rkN +blg +aFb +boE +bqs +bxD +bue +bvz +bxA +boI +oaC +bpp +bDK +bFm +bIx +bDZ +bKb +bKe +bMO +bOs +bOs +bOs +bOs +bTS +bVj +bWF +bYa +bZL +bXY +bYc +bYc +bYc +bNb +aZT +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +cqD +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(170,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaq +aaI +cLU +aaf +amJ +anE +aoo +cLU +amJ +anE +aoo +cLU +amJ +anE +aoo +cLU +aaf +cLU +cLU +cLU +aoJ +aCv +aCv +aCv +aCv +aFd +aDC +aGM +aJk +aEF +aOL +aOf +aRM +aRM +aRM +aRM +aRM +aRM +aZC +bbI +bde +bbs +aZz +bgH +hPt +bkf +blO +brh +aLr +bqv +aLr +bpp +bpp +wJf +boI +iok +bpp +bDM +bDN +bDP +bFG +bIy +bBk +bMO +bOx +bOs +bOs +bOs +aTZ +bVm +bWH +bYi +bXb +bIw +caU +ccD +bsE +bNb +aZT +cLU +aac +cLU +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cdO +cmc +cLU +cLU +cqD +cLU +aaf +cLU +cLU +aaf +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(171,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +amJ +anE +aoo +cLU +amJ +anE +aoo +cLU +amJ +anE +aoo +aaf +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +aDC +aFd +aDC +aDw +aJM +aKb +aMq +hLX +aDi +aVd +hLX +aVd +hLX +aWl +aZD +aRL +bdd +beA +aZz +dxK +hPt +bjD +blO +bne +boI +bqu +aJu +buf +bvB +boI +boI +bAN +bpp +aRE +bDD +bIx +bvT +bHV +bCC +bMO +bOw +bOs +bOs +bMO +aTZ +bVl +bWG +bYh +bZN +bIw +caS +ccD +ccD +bNb +aZT +cLU +cLU +cLU +cdO +cog +coY +coY +com +cog +coY +coY +com +cog +coY +coY +cdO +cLU +cLU +cLU +cqD +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(172,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +amJ +anE +aoo +aaf +amJ +anE +aoo +aaf +amJ +anE +aoo +cLU +aaf +cLU +cLU +cLU +aaf +aaf +cLU +cLU +arK +aFd +aDC +aIf +aJN +aLo +aMU +hLX +aQw +aVd +hLX +aVd +hLX +hLX +aYt +aRL +bdd +aYt +aZz +bha +hPt +rkN +blO +bng +boK +boH +byV +buh +bza +bza +jYD +bAN +bpp +bmx +bFq +bIx +bzj +bIO +bNn +bMO +bOy +bPV +bRp +bMO +bTP +bVR +bWG +bYm +bMO +bIw +bJh +bMt +bMt +bNi +bYf +cLU +cLU +cLU +cdO +coj +coZ +coY +com +coj +coY +coY +com +coj +coZ +coY +cdO +aaf +aaf +aaf +cfr +cqF +crE +cqF +crI +aaf +aaf +aaf +aaf +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(173,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaI +aaf +amJ +anE +aoo +cLU +amJ +anE +aoo +cLU +amJ +anE +aoo +cLU +aaf +cLU +cLU +cLU +cLU +aaf +aaf +cLU +arK +aFd +aDC +aIg +aIg +aIg +aIg +aIg +aIg +aZH +aTi +aWy +hLX +hLX +qlX +aRL +bdd +bfy +aZz +dxK +hPt +bjv +blO +bnh +boI +bsg +bsh +bug +bDX +mGD +bze +bAM +bpp +aSB +bFp +bIx +bIx +bIx +bIx +bMO +bMO +bMO +bMO +bMO +bMO +bMO +bWK +bYj +bMO +bVI +bIY +cdL +cdL +cdL +cdL +cdL +cdL +cdL +cdO +coh +coY +coY +com +coh +coY +coY +com +coh +coY +coY +cdO +cLU +cLU +cLU +aaf +cLU +aaf +cLU +coI +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(174,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +amJ +anF +aoo +cLU +amJ +anF +aoo +cLU +amJ +anF +aoo +aaf +aaI +aaf +cLU +cLU +cLU +cLU +aaf +aaf +aDC +aFe +axd +aGF +aJg +aKY +aMI +aOE +aGF +aIg +aIg +aIg +aQT +aYl +aZF +aRL +bdd +bbE +aZz +bBV +hPt +rkN +blO +brh +boM +bqE +bsl +bsj +bsj +bsl +bze +cfN +bpp +bod +bFt +bIJ +cnu +bKk +bLL +bMX +bOA +bCw +bCw +bSI +bTY +bIJ +cnv +bYo +bww +bVX +bJz +cdL +cgc +cig +che +crh +cky +clY +com +bgd +cpd +bmq +com +bnk +ctS +bpX +com +brs +cxV +brW +cdO +cdO +cdO +cdO +cdO +cdO +cdO +atf +cCJ +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(175,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +aaf +aaf +aaf +cLU +aaf +aaf +aaf +cLU +aaf +aaf +cLU +cLU +aaI +cLU +cLU +cLU +cLU +aDC +aDC +aDC +aDC +aFf +aJR +ayK +aJf +aKX +aMH +aOD +aGF +aRl +aSj +aIg +aWG +hLX +aZG +aRL +bdd +beD +aZz +dxK +hPt +rkN +brU +aGc +boL +bqx +bsj +bsj +bsj +bsj +bze +cfL +aLr +bmU +bFs +bFH +bIP +bKj +bLK +bMW +bOz +bLK +bLK +bSH +bTX +cyE +bWL +bYn +bww +caT +bJj +aYL +cff +cgI +chO +bLl +ckx +clV +com +btk +cpa +btD +crO +btJ +cpa +bup +cwa +btJ +cpa +buz +cpI +bvb +bvW +cDf +cDS +cEA +cdO +cLU +cqD +aaf +aaf +aaf +aah +aah +aal +aat +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(176,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aam +aaI +aaI +aaI +aam +aaI +aaI +aaI +aam +aaI +aaI +aaq +aaI +aaI +cLU +cLU +cLU +cLU +arK +aMf +aQL +aDC +aFg +aGF +aGF +aGF +aGF +aMK +aGF +aGF +cnn +aTW +aXj +hLX +aWz +aZH +aRL +bdf +bcm +aZz +bhi +hPt +rkN +brU +aGe +boO +bqI +bul +bul +bvD +bvD +rYD +bAQ +bJK +bpY +bWN +bIJ +byG +bKo +bKo +bMY +bOB +bPX +bRr +bRr +byG +bIJ +bWP +bAU +bww +bms +bJB +aYL +cfh +cgI +chO +bLv +ckA +cfn +com +con +cpg +cqC +cpg +cqC +ctU +cvb +cpg +cvb +cpg +cyN +czP +cAz +cBB +coY +coY +coY +cdO +cLU +coI +cLU +aag +aap +aap +aap +aak +aax +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(177,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +arK +bHi +aEZ +aUB +aFg +aGF +aHv +aJh +aLa +aMJ +aOF +aGF +aRm +aSm +aIg +aWH +aVx +aZI +aRL +bdg +hLX +aZz +bhe +hPt +rkN +brU +aGc +boN +bnx +bsn +bud +bvC +bxE +bAO +aLr +aLr +bDY +bFu +bIJ +bIJ +bKo +bKo +bMY +bOB +bPX +bRr +bRr +bIJ +bIJ +bTt +bYp +bww +chB +bIY +cdL +cge +cgK +chQ +bLr +ckz +cif +com +col +bfQ +bwv +crQ +crQ +czP +crQ +crQ +cwR +crQ +crQ +cpK +bvc +bvX +coY +coY +coY +cdO +cLU +coI +cLU +aah +aap +aap +aak +aap +aat +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(178,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +arK +ats +aSe +aDC +aFg +aGF +aHx +aJm +aLc +aMN +aOH +aGF +aGG +aGG +aGG +aGG +aGG +aGG +aGG +bcS +aGG +aZz +bfK +hPt +rkN +blk +blO +blO +brh +brh +brh +brh +bpp +bpp +aLr +cFR +cFU +cFZ +bKv +bIJ +bIJ +bIJ +bIJ +bIJ +bIJ +bIJ +bIJ +bIJ +bVp +bCj +bYr +bww +bww +bJF +cdO +cdO +aZb +chS +bNq +com +com +com +com +com +cbp +crQ +ctT +ctX +cve +cvq +cwd +crQ +crQ +czP +cAB +com +com +com +com +cdO +cLU +coI +aaf +aah +aah +aaj +ckw +aap +aat +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(179,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +aDC +aDC +aDC +aDC +aFg +aGF +aHw +aJj +aLb +aML +aOG +aGF +aRo +aHA +aUP +aWs +cph +aZs +bbp +bcR +aHA +aEe +bhj +hPt +rkN +brU +brU +blO +bqJ +bss +bww +bCl +aLZ +bAR +bAR +bAR +bEa +bFw +bAR +bIT +bKp +bLQ +bMZ +bOE +btv +bLQ +bSD +bIT +bAR +bAR +bYq +aWW +bww +bJE +cdR +cdO +bce +chR +bLO +com +cit +cdE +coo +com +cbo +crQ +csm +ctW +cvc +cwb +cwc +cxW +crQ +cpL +bvb +bvZ +cDf +cDS +cEA +cdO +cLU +coI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(180,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +aaf +aaf +cLU +cLU +cLU +cLU +cLU +aaf +aDC +aFg +aGF +aHz +aJn +aJn +aMO +aOI +aPZ +aRq +aSo +aUQ +aWt +aXV +aZu +aXV +bcU +bee +aEe +dxK +djd +fpV +tAY +tAY +boP +bqO +bsu +buq +bvE +aMe +bzh +bAT +bCi +bEc +bFz +bHk +bHk +bKr +bLS +bNd +bOF +bLS +bRt +bLS +bLS +bLS +bLS +bYt +aXa +cbi +bme +bBf +bFQ +bIa +bKw +bPa +aIu +cfF +bVK +bVP +aYB +aBb +bVK +bVK +cgz +bVK +cjA +cok +cxX +cxX +cpO +cAz +cDd +coY +coY +coY +cdO +aaf +cCJ +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(181,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +cLU +cLU +aaf +aaf +arK +aFg +aGF +aHy +aHy +aLg +aGF +aGF +aGF +aII +aSn +aVi +aTo +aXT +aZt +aXT +bcT +bea +bfq +bhl +biK +rkN +brU +aQU +blO +bqN +bst +bww +bwy +aMd +bCh +bAS +bCh +bCh +bCh +bCh +bCh +bKq +bLk +bNc +bCh +bCh +bRs +bCh +bOp +bCh +bCh +bYs +aWX +bww +bkj +cdU +cdO +bce +bJN +bNS +com +cop +ctV +cvd +com +aRO +crQ +crQ +crQ +crQ +crQ +coi +crQ +crQ +czI +byd +bwa +coY +coY +coY +cdO +cLU +coI +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(182,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +aaf +aaf +aaf +arK +aFg +aGG +aHC +aJo +aJo +aGG +aHA +aHA +aRr +aTo +aVi +aTo +aTo +aTo +aTo +bdl +aTo +aEe +dxK +bik +rkN +blk +blO +blO +bnI +bnI +bnI +bnI +bHm +xOe +bAW +bCk +aQB +aQB +aQB +aQB +cwt +bGa +bMV +aSJ +bTk +bWC +aSJ +bMV +aVq +aVq +aVq +bww +bww +roQ +cdO +cdO +aZP +bKB +bSY +bdX +bdX +bdX +com +com +aTD +cks +csS +ctZ +crQ +crQ +coi +cpA +crQ +cpS +cAD +com +com +com +com +cdO +cLU +coI +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(183,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +aaf +aap +aaf +arK +awi +aGG +aHA +aHA +aHA +aMQ +aHA +aHA +aRr +aSs +aVi +aTo +aXW +aZv +aXW +bcV +bee +bfx +bhm +biL +wqh +bln +aGg +boQ +bqP +bsw +bur +bvK +cFM +bCj +uFU +tDI +aQB +bmF +bBg +bBg +bCt +bEv +bMV +bOG +bWY +bRu +aUA +bMV +aaf +aaf +aaf +bMV +bYb +bnb +cdS +bYy +cgQ +bKz +cjF +ckC +cme +cdS +aat +cdO +cdO +cdO +cdO +cdO +csj +crQ +coq +com +crQ +cpP +bvb +bwm +cDf +cDS +cEA +crF +cLU +coI +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(184,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +crP +aaf +cLU +cLU +aaf +arK +awo +aIz +aHE +aJq +aJq +aJq +aJq +aJq +aRz +aSt +aUS +aSt +aXY +aZt +aXT +bcX +bek +aEe +dxK +bii +rkN +brU +aGi +boS +bqR +bsC +but +bvK +bxL +bCj +uFU +bCh +aQB +bOR +bNh +bDW +bzG +bzI +bMV +clU +bWY +bRx +aTG +bMV +aZw +aZw +aZw +bMV +caY +bpV +aZq +cfm +cgT +bKU +bUs +ckF +cmf +bHr +aaf +cLU +cLU +cLU +cLU +cdO +cgD +crQ +cou +com +cyP +cpS +cAz +cGs +coY +coY +coY +crF +cLU +coI +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(185,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaf +arK +arK +aGG +aHD +aJp +aHA +aHA +aHA +aHA +aRy +aHA +aUR +aHA +aXX +aHA +poU +bcW +aHA +aEe +dxK +bji +rkN +bum +aGg +aHs +bqQ +bsz +bus +bvK +bnq +bCj +uFU +eZK +bGa +bIL +bNf +bCs +cwZ +cxC +bMV +bOH +bQb +bRw +bSL +bXi +bQq +bWQ +bYu +bMV +bXT +bpV +aZq +cfm +cgT +bKD +cjF +ckD +cmf +bHr +aaf +cLU +cLU +cLU +cLU +cdO +csk +cwe +cos +com +crQ +cpT +bCq +bwq +coY +coY +coY +crF +cLU +coI +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(186,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaf +aaf +aaf +aGG +aHG +aGG +aLm +aLm +aGG +aQb +aGG +aSv +aGG +aGG +aXZ +dMz +aGG +bda +aGG +aZz +dxK +vme +rkN +blO +bnI +boU +bqS +bsF +bAX +bvL +bxO +bHq +bHo +bCm +bGa +bLV +aRn +bOK +cwZ +cyh +bsO +bzF +bQd +bRz +bSO +bXn +bVt +bWQ +bYw +bMV +bXT +bpV +aZq +cfm +cgT +bKD +cjF +ckD +cmf +bHr +aaf +cLU +cLU +cLU +cLU +cdO +chT +chT +cpb +cdO +ccn +cpV +cdO +cdO +cdO +cdO +cdO +cdO +atf +cCJ +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(187,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +aaf +aaf +aaf +aGG +aDE +aGG +aLk +aMT +aGG +aOJ +aRA +aSl +aGG +bbq +aBR +aCI +lAZ +bcZ +yjb +aRZ +bdW +biN +bkg +bmc +bxM +boT +bzg +bsD +bBl +bvK +tos +aMo +bHn +bNc +bGa +csB +cyi +cyi +cwZ +ctz +bzb +bOJ +bQc +bRy +bSN +bMV +bVs +bWS +bYv +bMV +bXT +bpV +cdS +bJZ +cgW +bKV +bVr +ckF +ciz +cdS +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +coI +cLU +cLU +coI +cLU +cLU +cLU +cLU +cLU +aaf +cLU +coI +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(188,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +crP +aaf +aaf +aGG +aIx +aGG +aum +aum +aGG +aGG +aGG +aGG +aGG +aWv +aYb +bel +bel +bel +bel +bfA +ihN +dMn +bfc +bmc +bpH +boV +bqT +aLx +buu +bvM +bxP +bww +aPL +aTd +bGa +bVo +bMb +bCg +cxs +cyi +bre +bzE +bQg +bRB +bSQ +bMV +bFX +bHu +bFX +bMV +bwM +brE +cdS +cfp +cgY +cjD +cni +ckI +cmi +cdS +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cfr +cpB +cpB +cpZ +cpB +cpB +cpB +cpB +cpB +crE +cpB +crL +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(189,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +crP +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aRZ +aSw +aUT +aWx +aYa +jva +jva +jva +jva +kxa +xVT +biP +bkh +bmc +bnI +bnI +bnI +bnI +bnI +bnI +bww +bww +bHp +bCL +bGa +bGa +bGa +bGa +bGa +bGa +bMV +bOQ +bQf +bRA +bSP +bMV +bFJ +bHe +bPY +bMV +caZ +bpV +cdS +cfo +cgX +cjC +cls +ckH +cmh +cdS +cLU +cLU +aaf +crP +crP +crP +crP +crP +crP +crP +crP +crP +cbO +crP +crP +crP +crP +crP +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(190,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +nky +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +crP +aaf +cLU +aaf +cLU +cLU +cLU +cLU +aaf +aaf +aRZ +aSx +aUV +aWx +aZL +aZL +aZL +aZL +aZL +vfH +ihN +biR +bkp +bns +bpE +bFP +bmv +bsM +buw +bzD +bAV +bBd +bHI +bie +bFy +bGb +bGb +boc +bGb +bqy +bMV +bOU +bQh +bRE +bSS +bMV +bFX +bWU +bFX +bMV +cba +bpV +cdS +cgw +cha +clo +cls +ckD +cml +cdS +cLU +cLU +cLU +crP +cLU +cLU +aaf +aaf +cLU +cLU +aaf +aaf +cLU +cLU +aaf +aaf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(191,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +crP +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aRZ +aRZ +aKu +aWx +mYp +mYp +mYp +mYp +mYp +vfH +ihN +biQ +aSY +aRZ +boD +bpL +bqV +bhw +bpF +bpF +boa +bnM +bHy +bhZ +bFr +bGc +bGc +bIS +bKl +bLN +bMV +bOu +bQh +bwL +bxZ +bFa +bGg +bIN +bQo +bMV +cbc +bpV +aZq +bHf +bJI +chY +bVF +ckD +cmf +bHr +cLU +cLU +cLU +crP +aaf +cua +cvi +cwf +aaf +cua +cvi +cwf +aaf +cua +cvi +cwf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(192,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +crP +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +ayk +aUh +aUV +aWx +aYf +aZN +aZN +aZN +aZN +yce +bhp +aZN +aTg +aRZ +bpJ +bpJ +brr +boo +bpF +bpF +bwF +bnM +bIq +bjf +bEn +bEn +bEn +bEn +bEn +bqB +bMV +bOW +bQh +bRH +bSV +bUc +bVy +bOv +bYA +bMV +bIX +bLZ +aZq +cft +cha +chY +cjF +ckD +cmf +bHr +cLU +cLU +cLU +cbO +cLU +cua +cvj +cwf +cLU +cua +cvj +cwf +cLU +cua +cvj +cwf +aaf +crP +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(193,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +cLU +cLU +crP +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +ayk +aSy +aQo +cBH +aFu +aSF +bbu +aUY +ben +sGZ +aHe +aWA +bhn +aRZ +bnM +bnM +bjl +bjl +drR +drR +bjl +bjl +aQp +aTf +bCJ +bbx +bbx +bEn +bsb +bqB +bMV +bOV +bQi +bRF +bST +bSS +bSS +bRD +bSS +bMV +ccM +ceK +aZq +cfs +chb +cic +cjG +ckL +cmf +bHr +cLU +cLU +cLU +aaf +aaf +cua +cvj +cwf +aaf +cua +cvj +cwf +aaf +cua +cvj +cwf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(194,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aaf +cLU +cLU +crP +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +ayk +azP +azP +azP +aGk +aDD +bbv +bdh +beo +aDD +aHu +azP +azP +aRZ +cLU +cLU +bjl +bph +bph +bph +bph +bjl +bIB +bju +bCJ +bbx +bbx +bEn +bte +bqB +bMV +bMV +bMV +aXy +bMV +bMV +bMV +bMV +bMV +bMV +cav +cfe +cdS +cfu +chc +cih +cjH +ckN +cmn +cdS +cLU +cLU +aac +aaf +cLU +cua +cvj +cwf +aaf +cua +cvj +cwf +cLU +cua +cvj +cwf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(195,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +aaf +aaf +cLU +crP +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +azP +bbw +azP +ayk +ayk +ayk +azP +bjd +azP +aaf +cLU +cLU +cLU +bjl +bph +bph +bph +bph +bjl +sVy +bIE +bCJ +bCJ +bCJ +bCJ +bqX +bsU +bGb +bPZ +bQk +bRI +bSW +bXq +bVH +bVH +bVH +cbL +ccS +ccw +cdS +cdS +cdS +cdS +cdS +cdS +cdS +cdS +aaf +aaf +aaf +aaf +cLU +cua +cvj +cwf +aaf +cua +cvj +cwf +aaf +cua +cvj +cwf +cLU +cLU +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(196,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +cLU +aaf +aaf +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +azP +bhq +azP +aaf +aaf +aaf +azP +bkl +azP +cLU +cLU +cLU +cLU +bjl +bph +bph +bph +bph +bjl +bIz +bjA +bHs +bko +bAi +bCJ +bEn +aRi +aRi +bEn +bQl +bRM +bSX +bUn +bUG +bZU +bJQ +bZT +bLI +ccy +bXT +cfw +cgN +chZ +cmp +ckP +bem +beO +beO +cLU +cLU +aaf +cLU +aaf +anC +cLU +cLU +aaf +anC +cLU +cLU +aaf +anC +cLU +cLU +cLU +aaf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +eYg +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(197,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +azP +aLW +azP +aaf +cLU +aaf +azP +aNM +azP +aaf +cLU +cLU +aac +bjl +bph +bph +bph +bph +bjl +bBj +bCB +bEd +bkt +bHw +bCJ +aaf +cLU +cLU +bOO +bOO +aXL +bOO +bOO +bOO +bOO +bYB +bZS +bUn +bFU +cdX +bNT +bPy +bPW +bQu +ckO +cob +cno +cqs +cpm +cqJ +cqJ +cqJ +cqJ +amK +cqJ +cqJ +cqJ +amK +cqJ +cqJ +cqJ +amK +cqJ +cqJ +cqJ +cFL +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(198,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaf +apc +aaf +crP +aaf +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cfQ +bjl +bjl +bjl +bjl +bjl +bjl +aPa +aPa +aMM +bkt +bHw +aPa +aaf +cLU +cLU +bOO +bQn +bRO +bHY +bUe +bVA +bOO +bUn +bUn +bUn +ccv +cDE +bOo +cgN +chG +cjx +cfl +beO +beO +beO +cLU +cLU +aaf +cLU +aaf +anC +cLU +cLU +aaf +anC +aaf +cLU +aaf +anC +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(199,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aMM +bkt +bHw +aPa +aaf +cLU +cLU +bOO +bQm +bRN +bSZ +bFS +bVz +bOO +aaf +cLU +bUn +bUn +cfI +bUn +cgN +cgN +cgN +cgN +beO +aaf +aaf +aaf +aaf +aaf +aaf +cua +cvl +cwf +aaf +cua +cvl +cwf +aaf +cua +cvl +cwf +cLU +cLU +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(200,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bvO +pAd +pAd +pAd +bvO +aMM +bkt +bHw +aPa +aaf +cLU +cLU +bOO +bLU +bWn +bTc +aTb +bVG +bOO +aaf +aaf +aaf +bUn +bVZ +bUn +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +cua +cvl +cwf +cLU +cua +cvl +cwf +cLU +cua +cvl +cwf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(201,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +aac +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +mVl +mLL +vVU +tRc +aMM +bFW +bHw +aPa +aaf +aaf +aaf +bOO +aTb +aTb +aTb +bOO +baO +bOO +aaf +cLU +aaf +bUn +ceg +cnt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +cua +cvl +cwf +aaf +cua +cvl +cwf +aaf +cua +cvl +cwf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(202,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +tCN +gSL +gyJ +tRc +aMM +bkt +bHw +aPa +aaf +cLU +aaf +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +cLU +aaf +bUn +cfU +bUn +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +cua +cvl +cwf +cLU +cua +cvl +cwf +aaf +cua +cvl +cwf +aaf +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(203,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +bxQ +cSp +tQY +tRc +aPa +bkr +bHv +aPa +aaf +cLU +aaf +cLU +aaf +cLU +aaf +cLU +cLU +aaf +aaf +cLU +aaf +cLU +ceq +clW +aaf +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaq +cLU +cua +cvo +cwf +aaf +cua +cvo +cwf +aaf +cua +cvo +cwf +cLU +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(204,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bZP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +buR +hZw +hZw +fyf +buR +aPa +bkU +btH +bCJ +cLU +cLU +aaf +cLU +aaf +cLU +aaf +cLU +cLU +cLU +aaf +cLU +aaf +aaf +ceq +aaf +aaf +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +crP +cLU +cLU +aaf +aaf +cLU +aaf +aaf +cLU +aaf +aaf +aaf +cLU +cLU +cbO +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(205,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +brg +eWD +eTV +tRc +aPa +xHt +bHx +bCJ +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(206,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +bzN +ejv +oDi +bDQ +aRC +bFY +bHz +aPa +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(207,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +aac +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +bwJ +pqS +klX +tRc +aMM +aPa +bCJ +bCJ +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(208,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +bzO +byn +bCr +buR +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +aac +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(209,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +cLU +apc +cLU +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +tRc +tRc +buR +sxY +bCD +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(210,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aam +aaf +apc +aaf +aam +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(211,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +aaf +cLU +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +aaf +ceq +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(212,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +cLU +aaf +aaf +cLU +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(213,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +apc +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(214,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +apc +apc +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +aaf +ceq +aaf +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(215,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +apc +apc +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +crP +cLU +cLU +cLU +crP +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(216,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +aaf +cLU +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +cLU +aaf +cLU +aaf +cLU +cLU +cLU +aaf +cLU +aaf +cLU +ceq +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(217,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +aaf +aaf +aaf +aaf +cLU +aaf +aaf +aaf +aaf +aaf +ceq +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(218,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +apc +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +cLU +aaf +cLU +aaf +cLU +cLU +cLU +aaf +cLU +aaf +cLU +ceq +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(219,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +crP +cto +cbO +crP +crP +crP +crP +crP +aaf +aaf +aaf +aaf +cLU +cLU +aaf +cLU +aaf +cLU +cLU +cLU +aaf +cLU +aaf +cLU +ceq +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(220,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +crP +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +cLU +aaf +bKE +bKE +bNj +bOP +bKs +bKt +bKt +bKt +bby +bKt +bKt +bKt +bKs +bOP +ces +bKE +bKE +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(221,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +bKE +bLT +bLT +bKt +bKt +bKt +bMe +bUf +bLT +bQr +bMe +bKt +bKt +bKt +ceq +cfy +bKE +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(222,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +bKE +bMd +bLT +bNj +bQs +bRQ +bMe +bUf +bLT +bQr +bMe +bRQ +bUj +bNj +ceq +cfA +bKE +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(223,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +bKE +bLT +bNk +bKt +bQr +bMe +bMe +bUf +bLT +bQr +bMe +bMe +bUf +bKt +cet +bNk +bKE +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(224,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bKs +bKs +bKt +bKt +bQr +bMe +bMe +bUf +bLT +bQr +bMe +bMe +bUf +bKt +bKt +bKs +bKs +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(225,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bKs +bKt +bKt +bMe +bMe +bMe +bMe +bUf +bLT +bQr +bMe +bMe +bMe +bMe +bKt +bKt +bKs +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(226,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bKt +bKt +bMe +bMe +bMe +bMe +bMe +bUf +bLT +bQr +bMe +bMe +bMe +bMe +bMe +bKt +bKt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(227,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +bKt +bMe +bMe +bMe +bMe +bMe +bTd +bUi +bLT +bXa +bTd +bMe +bMe +bMe +bMe +bMe +bKt +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(228,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +bKt +bKF +bNm +bMe +bMe +bMe +bMe +bMe +buA +bMe +bMe +bMe +bMe +bMe +ceu +bKF +bKt +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(229,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +bKt +bMe +bMe +bMe +bMe +bMe +bMe +bUj +bKF +bQs +bMe +bMe +bMe +bMe +bMe +bMe +bKt +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(230,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +bKu +bKt +bMe +bMe +bMe +bMe +bMe +bUf +bMe +bQr +bMe +bMe +bMe +bMe +bMe +bKt +bKu +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(231,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +bKt +bKt +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bKt +bKt +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(232,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +bKt +bKt +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bKt +bKt +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(233,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +bKt +bKt +bMe +bMe +bMe +bMe +bMe +bMe +bMe +bKt +bKt +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(234,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +bKt +bKt +bMe +bMe +bVL +bMe +bMe +bKt +bKt +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(235,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +bKt +bKt +bMe +bKF +bMe +bKt +bKt +aaf +aaf +cLU +cLU +aac +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(236,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aac +cLU +cLU +cLU +aaf +aaf +bKt +bKt +bKu +bKt +bKt +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(237,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aaf +aaf +aaf +cLU +aaf +aaf +aaf +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(238,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(239,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(240,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aIv +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(241,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aIv +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(242,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aIv +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(243,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(244,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(245,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(246,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(247,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aIv +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aIv +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(248,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +aIv +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(249,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(250,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(251,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(252,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(253,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(254,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} +(255,1,1) = {" +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +cLU +"} diff --git a/maps/exodus/exodus-admin.dmm b/maps/exodus/exodus-admin.dmm new file mode 100644 index 000000000000..493d426ffd7b --- /dev/null +++ b/maps/exodus/exodus-admin.dmm @@ -0,0 +1,43228 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aab" = ( +/turf/space, +/area/space) +"aad" = ( +/turf/unsimulated/wall, +/area/centcom) +"aae" = ( +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aaq" = ( +/obj/effect/floor_decal/corner/green{ + dir = 5 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aay" = ( +/obj/machinery/computer/teleporter, +/turf/unsimulated/floor/steel, +/area/centcom) +"aaz" = ( +/obj/machinery/teleport/station{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aaA" = ( +/obj/machinery/teleport/hub, +/turf/unsimulated/floor/steel, +/area/centcom) +"aaK" = ( +/turf/unsimulated/floor/steel, +/area/centcom) +"aaQ" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 8; + id_tag = "cargo_bay_centcom"; + pixel_x = 25 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aaR" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/plating, +/area/centcom) +"aaT" = ( +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"abg" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_ridged, +/area/shuttle/supply_shuttle) +"abi" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/turf/floor, +/area/shuttle/supply_shuttle) +"abn" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad2" + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "supply_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/turf/floor, +/area/shuttle/supply_shuttle) +"abr" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"abB" = ( +/obj/effect/floor_decal/corner/green/three_quarters, +/turf/unsimulated/floor/steel, +/area/centcom) +"abC" = ( +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"acd" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "supply_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/turf/floor, +/area/shuttle/supply_shuttle) +"ace" = ( +/obj/machinery/door/airlock/centcom{ + name = "Maintenance Access" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"acf" = ( +/obj/structure/sign/warning/secure_area, +/turf/unsimulated/wall, +/area/centcom) +"ach" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"aci" = ( +/obj/machinery/porta_turret/crescent, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/unsimulated/floor/steel, +/area/centcom) +"acj" = ( +/obj/machinery/door/airlock/centcom{ + name = "Teleporter Bay" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"ack" = ( +/obj/effect/shuttle_landmark/supply/start, +/turf/floor/tiled/steel_ridged, +/area/shuttle/supply_shuttle) +"acl" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 8; + id_tag = "supply_shuttle"; + pixel_x = 25; + tag_door = "supply_shuttle_hatch" + }, +/turf/floor/tiled/steel_ridged, +/area/shuttle/supply_shuttle) +"acm" = ( +/obj/effect/floor_decal/corner/green, +/turf/unsimulated/floor/steel, +/area/centcom) +"acE" = ( +/obj/effect/floor_decal/corner/green{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"acQ" = ( +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"adL" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/turf/floor, +/area/shuttle/supply_shuttle) +"aeQ" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aeR" = ( +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"ala" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/structure/decoy{ + name = "A.L.I.C.E." + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"alg" = ( +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"alr" = ( +/obj/effect/floor_decal/corner/green{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/unsimulated/floor/steel, +/area/centcom) +"auJ" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 4; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"auW" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"avf" = ( +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/obj/structure/window/reinforced/crescent, +/turf/unsimulated/floor/steel, +/area/centcom) +"avn" = ( +/obj/structure/rack, +/obj/item/clothing/jumpsuit/green, +/obj/item/clothing/shoes/color/brown, +/obj/item/clothing/suit/armor/tdome/green, +/obj/item/clothing/head/helmet/thunderdome, +/obj/item/baton/loaded, +/obj/item/energy_blade/sword/green, +/turf/unsimulated/floor/vault, +/area/tdome) +"avy" = ( +/obj/machinery/door/window{ + name = "AI Core Door" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"avQ" = ( +/turf/unsimulated/floor/vault, +/area/tdome) +"avV" = ( +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/obj/structure/window/reinforced/crescent, +/turf/unsimulated/floor/steel, +/area/centcom) +"awl" = ( +/obj/effect/shuttle_landmark/escape_pod/out/pod2, +/turf/space, +/area/space) +"awB" = ( +/turf/space, +/turf/space, +/area/space) +"ayg" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"ayh" = ( +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"ayi" = ( +/obj/structure/window/reinforced{ + dir = 1; + current_health = 1e+006 + }, +/obj/structure/showcase{ + desc = "A self-contained autopilot that controls supply drones."; + icon_state = "showcase_5"; + name = "Supply Drone Virtual Intelligence" + }, +/turf/floor/plating, +/area/shuttle/supply_shuttle) +"azR" = ( +/turf/floor/tiled/steel_ridged, +/area/shuttle/supply_shuttle) +"azS" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "QMLoad" + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "supply_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/turf/floor, +/area/shuttle/supply_shuttle) +"aAa" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_ridged, +/area/shuttle/supply_shuttle) +"aAl" = ( +/turf/unsimulated/wall, +/area/space) +"aAm" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aAM" = ( +/turf/wall/titanium, +/area/shuttle/supply_shuttle) +"aAN" = ( +/obj/machinery/door/airlock/centcom{ + name = "Bridge" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aBc" = ( +/obj/structure/shuttle/engine/heater, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/shuttle/supply_shuttle) +"aBz" = ( +/obj/structure/shuttle/engine/propulsion, +/turf/space, +/area/shuttle/supply_shuttle) +"aBA" = ( +/obj/structure/chair, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aBB" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aBC" = ( +/obj/structure/chair, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aBO" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aBZ" = ( +/obj/effect/floor_decal/corner/green, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCb" = ( +/obj/machinery/computer/robotics{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCj" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCk" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 8; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCl" = ( +/obj/effect/floor_decal/corner/green{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCm" = ( +/obj/structure/shuttle/engine/propulsion{ + icon_state = "burst_l" + }, +/turf/space, +/area/shuttle/supply_shuttle) +"aCt" = ( +/obj/structure/shuttle/engine/propulsion{ + icon_state = "burst_r" + }, +/turf/space, +/area/shuttle/supply_shuttle) +"aCu" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCv" = ( +/obj/structure/chair, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCx" = ( +/obj/machinery/button/blast_door{ + id_tag = "crescent_checkpoint_access"; + name = "Crescent Checkpoint Access"; + pixel_x = -6; + pixel_y = -24 + }, +/obj/machinery/button/blast_door{ + id_tag = "crescent_thunderdome"; + name = "Thunderdome Access"; + pixel_x = 6; + pixel_y = -24 + }, +/obj/machinery/button/blast_door{ + id_tag = "crescent_vip_shuttle"; + name = "VIP Shuttle Access"; + pixel_x = 6; + pixel_y = -34 + }, +/obj/machinery/button/blast_door{ + id_tag = "CREED"; + name = "Spec Ops Ready Room"; + pixel_x = -6; + pixel_y = -34 + }, +/obj/machinery/turretid{ + pixel_x = 28; + pixel_y = -28; + req_access = list("ACCESS_CENT_GENERAL") + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aCy" = ( +/obj/structure/table/reinforced, +/obj/item/card/id/captains_spare, +/turf/unsimulated/floor/steel, +/area/centcom) +"aDk" = ( +/obj/machinery/computer/modular/preset/security{ + dir = 1; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aDl" = ( +/obj/effect/floor_decal/corner/green{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aDF" = ( +/obj/machinery/computer/shuttle_control/emergency, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aDQ" = ( +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aDR" = ( +/obj/structure/table, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aEg" = ( +/obj/machinery/status_display{ + pixel_y = 30 + }, +/obj/structure/table, +/obj/item/firstaid/toxin, +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle Bridge East" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aEW" = ( +/obj/structure/aicore/deactivated, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aEX" = ( +/obj/machinery/computer/station_alert/all, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aFa" = ( +/obj/machinery/status_display, +/obj/effect/paint_stripe/red, +/turf/wall/titanium, +/area/shuttle/escape_shuttle) +"aFC" = ( +/obj/machinery/door/airlock/centcom{ + name = "Holding Cell" + }, +/obj/machinery/door/blast/regular{ + id_tag = "crescent_checkpoint_access"; + name = "Crescent Checkpoint" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aFM" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/half{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aFY" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle Cell" + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aGs" = ( +/obj/structure/sign/warning/nosmoking_2, +/turf/unsimulated/wall, +/area/centcom) +"aGC" = ( +/obj/structure/table, +/obj/item/firstaid/fire, +/obj/item/chems/spray/extinguisher, +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle Bridge West" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aGD" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aGE" = ( +/obj/structure/chair/shuttle/black{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aGF" = ( +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aGG" = ( +/obj/item/stool/padded, +/obj/item/stool/padded, +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aGP" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/obj/structure/sign/warning/docking_area, +/turf/unsimulated/floor/plating, +/area/centcom/holding) +"aGR" = ( +/obj/effect/paint_stripe/red, +/turf/wall/titanium, +/area/shuttle/escape_shuttle) +"aGT" = ( +/obj/structure/table, +/obj/structure/emergency_dispenser{ + pixel_x = 28 + }, +/obj/machinery/recharger, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aHb" = ( +/obj/item/stool/padded, +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aHc" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aHe" = ( +/obj/machinery/computer/modular/preset/security, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHg" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHh" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "escape_shuttle_hatch"; + name = "Shuttle Hatch" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_shuttle) +"aHm" = ( +/obj/machinery/door/airlock/centcom{ + name = "General Access" + }, +/obj/machinery/door/blast/regular{ + id_tag = "crescent_checkpoint_access"; + name = "Crescent Checkpoint" + }, +/turf/unsimulated/floor/steel, +/area/centcom) +"aHp" = ( +/obj/machinery/sleeper{ + dir = 8 + }, +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aHr" = ( +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHs" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 1; + id_tag = "escape_shuttle"; + pixel_y = -25; + tag_door = "escape_shuttle_hatch" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aHt" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Emergency Shuttle Bridge" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aHu" = ( +/obj/machinery/light, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aHz" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aHA" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"aHF" = ( +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHG" = ( +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHH" = ( +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHN" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 4 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aHW" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aHX" = ( +/obj/effect/floor_decal/corner/green{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aIh" = ( +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aIj" = ( +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aIk" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aIt" = ( +/obj/machinery/computer/modular/preset/security{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aIv" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aIy" = ( +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aIz" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aIA" = ( +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aIR" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/shuttle/escape_shuttle) +"aIS" = ( +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aIT" = ( +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aJu" = ( +/obj/machinery/bodyscanner{ + dir = 8 + }, +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aJv" = ( +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aJW" = ( +/obj/structure/table, +/obj/item/firstaid/o2{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/firstaid/toxin, +/obj/item/firstaid/fire{ + pixel_x = 2; + pixel_y = 3 + }, +/turf/unsimulated/floor/white, +/area/space) +"aKa" = ( +/obj/machinery/door/airlock/command{ + autoset_access = 0; + req_access = list("ACCESS_BRIDGE") + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_shuttle) +"aKb" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Crescent Arrivals - Holding Cell"; + dir = 4 + }, +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aKd" = ( +/obj/machinery/door/airlock/glass/security{ + name = "Holding Cell" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aKo" = ( +/obj/structure/emergency_dispenser{ + pixel_x = -28 + }, +/obj/structure/closet/crate/plastic/rations, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aKt" = ( +/obj/structure/closet/crate/medical, +/obj/item/firstaid/regular{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/bodybag/cryobag{ + pixel_x = 5 + }, +/obj/item/bodybag/cryobag{ + pixel_x = 5 + }, +/obj/item/firstaid/o2{ + pixel_x = 4; + pixel_y = 6 + }, +/obj/item/box/masks, +/obj/item/box/gloves{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/firstaid/toxin, +/obj/item/firstaid/adv{ + pixel_x = -2 + }, +/obj/item/chems/ivbag, +/obj/item/chems/ivbag, +/obj/item/chems/ivbag, +/obj/item/chems/ivbag, +/obj/item/chems/ivbag, +/obj/effect/floor_decal/corner/blue/border{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"aKv" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/plating, +/area/centcom/holding) +"aKC" = ( +/obj/machinery/door/blast/regular{ + id_tag = "CentComPort"; + name = "Security Doors" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aKD" = ( +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aKE" = ( +/obj/machinery/door/airlock/centcom{ + name = "Arrivals Processing" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aKV" = ( +/obj/structure/table, +/obj/item/firstaid/regular{ + pixel_x = 2; + pixel_y = 6 + }, +/obj/item/firstaid/regular{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/firstaid/adv{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/firstaid/adv{ + pixel_x = -2 + }, +/turf/unsimulated/floor/white, +/area/space) +"aKW" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red/half{ + dir = 4 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aKX" = ( +/obj/structure/bed, +/obj/item/bedsheet/red, +/turf/unsimulated/floor/cult, +/area/centcom/holding) +"aKY" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aKZ" = ( +/obj/machinery/door/window/northleft{ + base_state = "right"; + dir = 8; + icon_state = "right"; + name = "Arrivals Processing" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLa" = ( +/obj/machinery/computer/modular/preset/security{ + dir = 8; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLb" = ( +/obj/structure/table, +/obj/item/box/gloves{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/box/masks, +/turf/unsimulated/floor/white, +/area/space) +"aLc" = ( +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/half{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aLd" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Emergency Shuttle Brig" + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aLe" = ( +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red/half{ + dir = 4 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"aLf" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLh" = ( +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLl" = ( +/turf/floor/tiled/white, +/area/shuttle/escape_shuttle) +"aLm" = ( +/obj/structure/chair/office/dark, +/obj/machinery/button/blast_door{ + desc = "A remote control switch for port-side blast doors."; + id_tag = "CentComPort"; + name = "Security Doors"; + pixel_x = -12; + pixel_y = -25 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLn" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Crescent Arrivals North"; + dir = 8 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 8; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLo" = ( +/obj/structure/table, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aLs" = ( +/obj/structure/closet/hydrant{ + pixel_x = 30; + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"aLt" = ( +/obj/machinery/vending/wallmed1{ + name = "Emergency NanoMed"; + pixel_y = -32 + }, +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aLu" = ( +/obj/structure/table, +/obj/item/clothing/glasses/hud/health, +/obj/item/clothing/glasses/hud/health, +/obj/item/chems/spray/cleaner, +/turf/unsimulated/floor/white, +/area/space) +"aLv" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLw" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLz" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLB" = ( +/obj/effect/paint/red, +/turf/wall/titanium, +/area/shuttle/escape_shuttle) +"aLD" = ( +/obj/machinery/sleeper{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/border{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"aLE" = ( +/obj/structure/shuttle/engine/propulsion, +/turf/space, +/area/shuttle/escape_shuttle) +"aLF" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "CentComPort"; + name = "Security Doors" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLG" = ( +/obj/structure/table/reinforced, +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/obj/structure/window/reinforced/crescent, +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 1; + icon_state = "console" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLI" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/pen, +/obj/machinery/door/window/southright{ + name = "Arrivals Processing" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLJ" = ( +/obj/structure/sign/department/cross, +/turf/unsimulated/wall, +/area/centcom/holding) +"aLK" = ( +/obj/machinery/door/airlock/glass/medical{ + autoset_access = 0; + name = "Arrivals Medbay" + }, +/turf/unsimulated/floor/white, +/area/centcom/holding) +"aLL" = ( +/obj/structure/table, +/obj/item/firstaid/fire, +/obj/item/firstaid/regular{ + pixel_x = 2; + pixel_y = 3 + }, +/obj/item/chems/spray/extinguisher, +/obj/item/crowbar, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aLP" = ( +/obj/machinery/door/airlock/security{ + autoset_access = 0; + req_access = list("ACCESS_SECURITY") + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_shuttle) +"aLQ" = ( +/obj/machinery/atm{ + pixel_x = -26 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLR" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLS" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aLV" = ( +/obj/machinery/porta_turret/crescent, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMd" = ( +/obj/machinery/button/access/interior{ + id_tag = "centcom_escape_dock_north_airlock"; + name = "interior access button"; + pixel_x = 26; + pixel_y = 26 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMe" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "centcom_escape_dock_north_inner"; + name = "Escape Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/centcom/holding) +"aMf" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "centcom_escape_dock_north_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{ + id_tag = "centcom_escape_dock_north_airlock"; + master_tag = "centcom_escape_dock"; + pixel_y = 24; + tag_airpump = "centcom_escape_dock_north_pump"; + tag_chamber_sensor = "centcom_escape_dock_north_sensor"; + tag_exterior_door = "centcom_escape_dock_north_outer"; + tag_interior_door = "centcom_escape_dock_north_inner" + }, +/turf/floor/plating, +/area/centcom/holding) +"aMg" = ( +/obj/machinery/airlock_sensor{ + id_tag = "centcom_escape_dock_north_sensor"; + pixel_y = -25; + dir = 1 + }, +/turf/floor/plating, +/area/centcom/holding) +"aMh" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "centcom_escape_dock_north_outer"; + name = "Escape Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "centcom_escape_dock_north_airlock"; + name = "exterior access button"; + pixel_x = 4; + pixel_y = -26 + }, +/turf/floor/plating, +/area/centcom/holding) +"aMm" = ( +/obj/machinery/status_display{ + pixel_y = 30 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"aMn" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle Center" + }, +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"aMo" = ( +/turf/unsimulated/floor/grass, +/area/centcom/holding) +"aMp" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMq" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMr" = ( +/obj/effect/paint_stripe/blue, +/turf/wall/titanium, +/area/shuttle/escape_shuttle) +"aMs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMt" = ( +/obj/machinery/status_display{ + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMu" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle West"; + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aMz" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMA" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMC" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMD" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMF" = ( +/obj/machinery/porta_turret/crescent, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/unsimulated/floor/grass, +/area/centcom/holding) +"aMG" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/obj/machinery/status_display, +/turf/unsimulated/floor/plating, +/area/centcom/holding) +"aMH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMK" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMR" = ( +/obj/structure/chair/wood/wings{ + dir = 4 + }, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aMT" = ( +/obj/machinery/hologram/holopad, +/obj/effect/shuttle_landmark/escape_shuttle/start, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"aMU" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle East"; + dir = 4 + }, +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aMW" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMX" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aMY" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/amanita_pie, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aMZ" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/bigbiteburger, +/obj/machinery/camera/network/crescent{ + c_tag = "Crescent Bar Center" + }, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNa" = ( +/obj/structure/chair/wood/wings{ + dir = 8 + }, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNb" = ( +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNc" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNh" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/chems/glass/bowl/mapped/stew, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNj" = ( +/obj/structure/closet/secure_closet/bar, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aNk" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/book/manual/barman_recipes, +/obj/item/chems/rag, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aNl" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/machinery/chemical_dispenser/bar_alc/full, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aNm" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aNn" = ( +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aNo" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 1 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aNx" = ( +/obj/machinery/door/airlock/glass{ + autoset_access = 0; + name = "Arrivals Processing" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aNA" = ( +/obj/structure/emergency_dispenser{ + pixel_x = -28 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"aNB" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/boiledrice, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNC" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/chems/glass/bowl/mapped/beet, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNI" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/stuffing, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNJ" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/soylenviridians, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aNK" = ( +/obj/machinery/door/airlock/glass{ + autoset_access = 0; + name = "Arrivals Bar" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aNL" = ( +/obj/machinery/embedded_controller/radio/docking_port_multi{ + child_names_txt = "Airlock One;Airlock Two"; + child_tags_txt = "centcom_escape_dock_north_airlock;centcom_escape_dock_south_airlock"; + dir = 1; + id_tag = "centcom_escape_dock"; + pixel_y = -25 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aNM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aNN" = ( +/obj/machinery/button/access/interior{ + id_tag = "centcom_escape_dock_south_airlock"; + name = "interior access button"; + pixel_x = 26; + pixel_y = -26 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aNQ" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "centcom_escape_dock_south_inner"; + name = "Escape Airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/centcom/holding) +"aNR" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "centcom_escape_dock_south_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port_multi{ + dir = 1; + id_tag = "centcom_escape_dock_south_airlock"; + master_tag = "centcom_escape_dock"; + pixel_y = -25; + tag_airpump = "centcom_escape_dock_south_pump"; + tag_chamber_sensor = "centcom_escape_dock_south_sensor"; + tag_exterior_door = "centcom_escape_dock_south_outer"; + tag_interior_door = "centcom_escape_dock_south_inner" + }, +/turf/floor/plating, +/area/centcom/holding) +"aNS" = ( +/obj/machinery/airlock_sensor{ + id_tag = "centcom_escape_dock_south_sensor"; + pixel_y = 25 + }, +/turf/floor/plating, +/area/centcom/holding) +"aNT" = ( +/obj/machinery/vending/cigarette, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aOv" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "centcom_escape_dock_south_outer"; + name = "Escape Airlock" + }, +/obj/machinery/button/access/exterior{ + id_tag = "centcom_escape_dock_south_airlock"; + name = "exterior access button"; + pixel_x = 4; + pixel_y = 26 + }, +/turf/floor/plating, +/area/centcom/holding) +"aOZ" = ( +/obj/machinery/status_display{ + pixel_y = -30; + dir = 1 + }, +/obj/machinery/light, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"aPa" = ( +/obj/machinery/hologram/holopad, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aPH" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Crescent Bar East"; + dir = 4 + }, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aPJ" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Holding Facility Bar" + }, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"aPK" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/effect/floor_decal/corner/green, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"aPL" = ( +/obj/machinery/door/airlock/civilian, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_shuttle) +"aPN" = ( +/turf/wall/titanium, +/area/shuttle/escape_shuttle) +"aPO" = ( +/obj/machinery/door/airlock/medical, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/shuttle/escape_shuttle) +"aPR" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/chems/glass/bowl/mapped/blood, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aPS" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/skewer/tofu, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aRl" = ( +/turf/unsimulated/wall, +/area/centcom/holding) +"aRm" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/poppypretzel, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"aZb" = ( +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/clothing/pants/slacks/outfit, +/obj/item/clothing/head/that{ + pixel_x = 4; + pixel_y = 6 + }, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"bgb" = ( +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/obj/structure/table/laminate{ + dir = 5 + }, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"bgJ" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/turf/unsimulated/floor/lino, +/area/centcom/holding) +"bjb" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 8 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"bkb" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Holding Facility Foyer" + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"blb" = ( +/obj/structure/table, +/obj/item/firstaid/regular{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/effect/floor_decal/corner/blue/border{ + dir = 8 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"bmb" = ( +/obj/structure/table, +/obj/item/firstaid/fire{ + pixel_x = 2; + pixel_y = 3 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"bnb" = ( +/obj/structure/table, +/obj/item/wrench, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"bpb" = ( +/obj/structure/closet/hydrant{ + pixel_x = -30; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"brb" = ( +/obj/structure/emergency_dispenser{ + pixel_x = 28 + }, +/obj/machinery/computer/cryopod/robot{ + dir = 4; + pixel_x = 32; + pixel_y = -32 + }, +/obj/machinery/recharge_station, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"bvb" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/spesslaw, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"bwE" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"byb" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/candiedapple, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"bzm" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/chems/glass/bowl/mapped/mushroom, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"bDh" = ( +/obj/structure/table, +/obj/item/toolbox/electrical, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"bMb" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/food/meatsteak, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"cnP" = ( +/obj/item/stool/padded, +/turf/unsimulated/floor/laminate, +/area/centcom/holding) +"cxx" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"cEu" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/camera/network/crescent{ + c_tag = "Crescent Arrivals South"; + dir = 4 + }, +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"cGo" = ( +/obj/structure/closet/crate/plastic/rations, +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle West Storage"; + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"cIe" = ( +/obj/structure/chair, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"cIv" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"cQH" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/abstract/landmark{ + name = "tdomeadmin" + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"djD" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle Medical"; + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/border{ + dir = 8 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"dkK" = ( +/obj/machinery/vending/wallmed1{ + name = "Emergency NanoMed"; + pixel_x = 28 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/border{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"dzr" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"dzs" = ( +/obj/machinery/camera/network/crescent{ + c_tag = "Shuttle East Storage"; + dir = 8 + }, +/obj/machinery/cryopod/robot{ + time_till_despawn = 10 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"dUx" = ( +/obj/effect/floor_decal/corner/green{ + dir = 9 + }, +/obj/structure/chair{ + dir = 4 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"edo" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"ewc" = ( +/obj/machinery/vending/coffee, +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/steel, +/area/centcom/holding) +"exJ" = ( +/obj/machinery/door/blast/regular{ + id_tag = "thunderdome"; + name = "Thunderdome Blast Door" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"eCw" = ( +/obj/structure/shuttle/engine/heater, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/shuttle/escape_shuttle) +"eDH" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/iv_drip, +/obj/effect/floor_decal/corner/blue/border{ + dir = 8 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"fis" = ( +/obj/structure/rack, +/obj/item/clothing/jumpsuit/green, +/obj/item/clothing/shoes/color/brown, +/obj/item/energy_blade/axe, +/turf/unsimulated/floor/vault, +/area/tdome) +"fpV" = ( +/obj/machinery/hologram/holopad{ + holopad_id = "Emergency Shuttle Medbay" + }, +/turf/floor/tiled/white, +/area/shuttle/escape_shuttle) +"fsh" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/corner/blue/border{ + dir = 4 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"fsI" = ( +/obj/machinery/sleeper{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/border{ + dir = 8 + }, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"fyA" = ( +/obj/structure/bed/roller, +/turf/floor/tiled/white/monotile, +/area/shuttle/escape_shuttle) +"fFh" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/plating, +/area/tdome) +"fJA" = ( +/obj/machinery/door/airlock/centcom{ + name = "Thunderdome" + }, +/obj/machinery/door/blast/regular{ + id_tag = "crescent_thunderdome"; + name = "Thunderdome" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"fMq" = ( +/obj/structure/table, +/turf/unsimulated/floor/vault, +/area/tdome) +"fRC" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"fUy" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/vault, +/area/tdome) +"fZb" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"gcV" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"ghj" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"gkM" = ( +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"gtc" = ( +/obj/effect/floor_decal/corner/red/three_quarters, +/turf/unsimulated/floor/vault, +/area/tdome) +"gMh" = ( +/obj/effect/floor_decal/corner/red{ + dir = 10 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"gWz" = ( +/obj/effect/floor_decal/corner/green{ + dir = 10 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"gXh" = ( +/obj/item/wrench, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"haH" = ( +/obj/effect/floor_decal/corner/green/three_quarters{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"heW" = ( +/obj/effect/floor_decal/corner/green, +/turf/unsimulated/floor/vault, +/area/tdome) +"hhT" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"hlP" = ( +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"hqi" = ( +/obj/machinery/door/airlock/centcom{ + name = "General Access" + }, +/obj/machinery/door/blast/regular{ + id_tag = "crescent_thunderdome"; + name = "Thunderdome" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"hvD" = ( +/obj/machinery/door/airlock/centcom{ + name = "General Access" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"hAQ" = ( +/obj/structure/closet/secure_closet/bar, +/turf/unsimulated/floor/white, +/area/tdome) +"hBn" = ( +/turf/unsimulated/floor/white, +/area/tdome) +"hDq" = ( +/obj/machinery/gibber, +/turf/unsimulated/floor/white, +/area/tdome) +"hFt" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"hMN" = ( +/obj/structure/chair{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/obj/abstract/landmark{ + name = "tdomeadmin" + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"hYN" = ( +/obj/machinery/door/airlock/command{ + name = "Thunderdome" + }, +/obj/machinery/door/blast/regular{ + id_tag = "crescent_thunderdome"; + name = "Thunderdome" + }, +/turf/unsimulated/floor/lino, +/area/tdome) +"igT" = ( +/obj/machinery/vending/cigarette, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"iqx" = ( +/obj/structure/table, +/obj/item/chems/drinks/bottle/small/beer, +/obj/item/chems/drinks/bottle/small/beer, +/obj/item/chems/drinks/bottle/small/beer, +/obj/item/flame/fuelled/lighter/zippo/random, +/obj/item/box/fancy/cigarettes, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"itR" = ( +/obj/item/chems/drinks/cans/cola, +/obj/item/chems/drinks/cans/cola, +/obj/item/chems/drinks/cans/cola, +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"iMp" = ( +/obj/machinery/door/airlock/centcom{ + name = "General Access" + }, +/turf/unsimulated/floor/lino, +/area/tdome) +"iYo" = ( +/obj/structure/flora/pottedplant/minitree, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"jlk" = ( +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/turf/floor/tiled/dark/monotile, +/area/shuttle/escape_shuttle) +"jpr" = ( +/obj/structure/reagent_dispensers/beerkeg, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"jqP" = ( +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"jzQ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"jHj" = ( +/obj/machinery/vending/coffee, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"jLF" = ( +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"jRy" = ( +/obj/structure/closet/secure_closet/freezer/meat, +/turf/unsimulated/floor/white, +/area/tdome) +"jRE" = ( +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"jSH" = ( +/obj/structure/chair/shuttle/black{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"kca" = ( +/obj/structure/closet/secure_closet/freezer/fridge, +/turf/unsimulated/floor/white, +/area/tdome) +"kfk" = ( +/obj/structure/chair, +/obj/abstract/landmark{ + name = "tdomeobserve" + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"khR" = ( +/obj/structure/disposalpipe/trunk, +/obj/structure/disposaloutlet, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"kjk" = ( +/obj/structure/chair/shuttle/black{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"kkN" = ( +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"kuG" = ( +/obj/machinery/vending/snack, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"kBZ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"kLu" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"kSw" = ( +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/structure/table, +/turf/unsimulated/floor/white, +/area/tdome) +"kXc" = ( +/obj/structure/table, +/obj/machinery/microwave, +/turf/unsimulated/floor/white, +/area/tdome) +"lcs" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/white, +/area/tdome) +"ljR" = ( +/obj/item/camera, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"lEJ" = ( +/obj/structure/disposalpipe/segment, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"lOB" = ( +/obj/machinery/button/blast_door{ + dir = 1; + id_tag = "thunderdomegen"; + name = "Thunderdome General Supply" + }, +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"lPd" = ( +/obj/structure/table, +/obj/item/stack/medical/bandage, +/obj/item/stack/medical/bandage, +/obj/item/stack/medical/bandage, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"lQy" = ( +/obj/structure/chair, +/obj/structure/disposalpipe/segment, +/obj/abstract/landmark{ + name = "tdomeobserve" + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeobserve) +"lQQ" = ( +/obj/item/chems/spray/extinguisher, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"lSf" = ( +/obj/structure/rack, +/obj/item/clothing/jumpsuit/red, +/obj/item/clothing/shoes/color/brown, +/obj/item/energy_blade/axe, +/turf/unsimulated/floor/vault, +/area/tdome) +"lSj" = ( +/obj/effect{ + density = 1; + desc = "You can't get in. Heh."; + name = "Blocker" + }, +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/dark, +/area/tdome) +"lTa" = ( +/obj/structure/disposalpipe/segment, +/turf/unsimulated/floor/dark, +/area/tdome) +"mgi" = ( +/obj/effect{ + density = 1; + desc = "You can't get in. Heh."; + name = "Blocker" + }, +/obj/structure/disposalpipe/segment, +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/dark, +/area/tdome) +"mhI" = ( +/obj/machinery/igniter, +/turf/unsimulated/floor/dark, +/area/tdome) +"mHo" = ( +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"mXz" = ( +/turf/unsimulated/floor/dark, +/area/tdome) +"mZU" = ( +/obj/effect/shuttle_landmark/escape_pod/out/pod3, +/turf/space, +/area/space) +"nBg" = ( +/obj/structure/rack, +/obj/item/clothing/jumpsuit/red, +/obj/item/clothing/shoes/color/brown, +/obj/item/clothing/suit/armor/tdome/red, +/obj/item/clothing/head/helmet/thunderdome, +/obj/item/baton/loaded, +/obj/item/energy_blade/sword/red, +/turf/unsimulated/floor/vault, +/area/tdome) +"nIB" = ( +/obj/machinery/door/blast/regular{ + id_tag = "thunderdomegen"; + name = "General Supply" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"nKf" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"nKw" = ( +/obj/abstract/landmark{ + name = "tdome2" + }, +/turf/unsimulated/floor/vault, +/area/tdome/tdome2) +"nPB" = ( +/obj/structure/chair/shuttle/black{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/shuttle/escape_shuttle) +"nSv" = ( +/obj/effect/shuttle_landmark/escape_pod/out/pod1, +/turf/space, +/area/space) +"nZT" = ( +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/unsimulated/floor/dark, +/area/tdome) +"ofF" = ( +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/dark, +/area/tdome) +"oNm" = ( +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/abstract/landmark{ + name = "tdome2" + }, +/turf/unsimulated/floor/vault, +/area/tdome/tdome2) +"oVC" = ( +/obj/abstract/landmark{ + name = "tdome2" + }, +/obj/machinery/camera/network/television{ + c_tag = "Thunderdome - Red Team" + }, +/turf/unsimulated/floor/vault, +/area/tdome/tdome2) +"pfy" = ( +/turf/unsimulated/floor/bcircuit, +/area/tdome) +"pra" = ( +/obj/machinery/flasher{ + id_tag = "flash"; + name = "Thunderdome Flash" + }, +/turf/unsimulated/floor/bcircuit, +/area/tdome) +"pwa" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/sleeping_agent{ + pixel_x = 1 + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"pyW" = ( +/obj/abstract/landmark{ + name = "tdome1" + }, +/obj/machinery/camera/network/television{ + c_tag = "Green Team" + }, +/turf/unsimulated/floor/vault, +/area/tdome/tdome1) +"pMA" = ( +/obj/machinery/atmospherics/unary/vent_pump, +/turf/unsimulated/floor/bcircuit, +/area/tdome) +"pQZ" = ( +/obj/machinery/camera/network/television{ + c_tag = "Thunderdome Arena" + }, +/turf/unsimulated/floor/bcircuit, +/area/tdome) +"qgz" = ( +/obj/item/stack/medical/ointment, +/obj/item/stack/medical/ointment, +/obj/item/stack/medical/ointment, +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"qBg" = ( +/obj/machinery/door/blast/regular{ + id_tag = "thunderdomeaxe"; + name = "Axe Supply" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"qUZ" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/unsimulated/floor/dark, +/area/tdome) +"rsb" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"sfj" = ( +/obj/structure/rack, +/obj/item/clothing/jumpsuit/green, +/obj/item/clothing/shoes/color/brown, +/obj/item/clothing/suit/armor/vest, +/obj/item/clothing/head/helmet/swat, +/obj/item/gun/energy/laser, +/turf/unsimulated/floor/vault, +/area/tdome) +"smK" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 1 + }, +/turf/unsimulated/floor/dark, +/area/tdome) +"sCN" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/turf/unsimulated/floor/dark, +/area/tdome) +"sDZ" = ( +/obj/structure/table, +/obj/item/toolbox/mechanical, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"sKA" = ( +/obj/abstract/level_data_spawner/admin_level{ + name = "Centcomm" + }, +/turf/space, +/area/space) +"sMD" = ( +/obj/effect/shuttle_landmark/escape_pod/out/pod4, +/turf/space, +/area/space) +"sOE" = ( +/obj/machinery/button/blast_door{ + dir = 1; + id_tag = "thunderdome"; + name = "Thunderdome Blast Door Control" + }, +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"sRb" = ( +/obj/structure/table, +/obj/item/box/handcuffs, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"tda" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/unsimulated/floor/dark, +/area/tdome) +"trW" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"twS" = ( +/obj/machinery/door/airlock/command{ + name = "Thunderdome Administration" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"tWl" = ( +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/abstract/landmark{ + name = "tdome1" + }, +/turf/unsimulated/floor/vault, +/area/tdome/tdome1) +"uFd" = ( +/obj/machinery/door/blast/regular{ + id_tag = "thunderdomehea"; + name = "Heavy Supply" + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"uOk" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"vBi" = ( +/obj/machinery/button/blast_door{ + dir = 1; + id_tag = "thunderdomehea"; + name = "Thunderdome Heavy Supply" + }, +/obj/structure/table, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"vHR" = ( +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"vTe" = ( +/obj/effect/floor_decal/corner/red{ + dir = 8 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"wjz" = ( +/obj/effect/floor_decal/corner/green{ + dir = 6 + }, +/turf/unsimulated/floor/vault, +/area/tdome) +"wkp" = ( +/turf/unsimulated/wall, +/area/tdome) +"wOU" = ( +/obj/machinery/button/blast_door{ + dir = 1; + id_tag = "thunderdomeaxe"; + name = "Thunderdome Axe Supply" + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"wRq" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"xeT" = ( +/obj/structure/rack, +/obj/item/clothing/jumpsuit/red, +/obj/item/clothing/shoes/color/brown, +/obj/item/clothing/suit/armor/vest, +/obj/item/clothing/head/helmet/swat, +/obj/item/gun/energy/laser, +/turf/unsimulated/floor/vault, +/area/tdome) +"xfb" = ( +/obj/machinery/door/airlock/command{ + name = "Thunderdome Administration" + }, +/turf/unsimulated/floor/dark, +/area/tdome) +"xog" = ( +/obj/abstract/landmark{ + name = "tdome1" + }, +/turf/unsimulated/floor/vault, +/area/tdome/tdome1) +"xIV" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/turf/floor/tiled, +/area/shuttle/escape_shuttle) +"xSD" = ( +/obj/effect{ + density = 1; + desc = "You can't get in. Heh."; + name = "Blocker" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/dark, +/area/tdome) +"yda" = ( +/obj/machinery/atmospherics/valve, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) +"yiv" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/floor/tiled/dark, +/area/shuttle/escape_shuttle) +"ylZ" = ( +/obj/structure/table, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/turf/unsimulated/floor/lino, +/area/tdome/tdomeadmin) + +(1,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(2,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(3,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(4,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(5,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +sKA +aab +aab +aab +aab +"} +(6,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(7,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(8,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(9,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(10,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(11,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(12,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(13,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(14,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(15,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(16,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(17,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(18,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(19,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(20,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(21,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +gkM +gkM +gkM +gkM +gkM +gkM +gkM +gkM +gkM +gtc +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(22,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +avQ +avQ +avQ +avQ +avQ +avQ +avQ +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +vTe +wkp +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(23,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +nBg +nBg +nBg +nBg +nBg +avQ +twS +avQ +avQ +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(24,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +hAQ +hAQ +jRy +jRy +wkp +wkp +wkp +nIB +nIB +nIB +nIB +nIB +nIB +wkp +wkp +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(25,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +hBn +hBn +hBn +kSw +wkp +lSf +qBg +nKw +nKw +nKw +nKw +nKw +nKw +uFd +xeT +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(26,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aRl +aRl +aRl +aRl +aRl +aRl +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +hBn +hBn +hBn +kXc +wkp +lSf +qBg +nKw +oNm +nKw +nKw +oNm +nKw +uFd +xeT +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(27,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +awB +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aMR +aMR +aNb +aMR +aMR +aRl +aab +aab +aab +aab +aab +aab +wkp +avQ +hvD +hBn +hBn +hBn +kXc +wkp +lSf +qBg +nKw +nKw +oVC +nKw +nKw +nKw +uFd +xeT +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(28,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aMY +aNB +aNb +aPR +bvb +aRl +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +hBn +hBn +hBn +hBn +wkp +lSf +qBg +nKw +oNm +nKw +nKw +oNm +nKw +uFd +xeT +wkp +avQ +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(29,1,1) = {" +aab +aab +aab +aab +aab +aab +awB +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aMZ +aNC +aNb +aPS +byb +aRl +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +hDq +hDq +kca +hBn +wkp +lSf +qBg +nKw +nKw +nKw +nKw +nKw +nKw +uFd +xeT +wkp +avQ +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(30,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aNa +aNa +aNb +aNa +aNa +aRl +aRl +aRl +aab +aab +aab +aab +wkp +avQ +wkp +wkp +wkp +wkp +lcs +wkp +wkp +wkp +exJ +exJ +exJ +exJ +exJ +exJ +wkp +wkp +wkp +wkp +iMp +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(31,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aNb +aNb +aPa +aNb +aNb +aNb +aNb +aRl +aab +aab +aab +aab +wkp +avQ +avQ +wkp +igT +jqP +jqP +jqP +lSj +mhI +nZT +nZT +nZT +nZT +nZT +nZT +mhI +lSj +jRE +jRE +jRE +ylZ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(32,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aMR +aMR +aNb +aMR +aMR +aNb +aNb +aRl +aab +aab +aab +aab +wkp +avQ +avQ +wkp +iqx +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +jRE +ylZ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(33,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aNc +aNI +aNb +aRm +bzm +aNb +aNb +wkp +wkp +wkp +wkp +wkp +wkp +wkp +avQ +wkp +itR +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +jRE +ylZ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(34,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aNh +aNJ +aNb +aNc +bMb +aNb +aNb +wkp +fMq +avQ +fFh +gkM +gtc +wkp +avQ +wkp +iqx +kfk +ljR +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +mHo +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(35,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aNa +aNa +aNb +aNa +aNa +aNb +aNb +wkp +avQ +fRC +avQ +avQ +gMh +hqi +avQ +wkp +jpr +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +wOU +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(36,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aKv +aKv +aRl +aKv +aKv +aNb +aNb +fFh +fFh +fUy +fFh +avQ +gMh +wkp +avQ +wkp +jqP +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +lOB +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(37,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aRl +aRl +aRl +aRl +aRl +aRl +aRl +aRl +aab +aab +aab +aRl +aNj +aNn +aPH +aZb +cnP +aNb +aNb +fFh +avQ +avQ +avQ +avQ +gMh +wkp +wkp +wkp +jqP +jqP +jqP +jqP +lSj +mXz +mXz +mXz +pfy +pMA +qUZ +mXz +mXz +xfb +lQQ +jRE +jRE +vBi +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(38,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aGF +aGF +aGF +aKb +aGF +aGF +aGF +aRl +aab +aab +aab +aRl +aNk +aNn +aNn +bgb +cnP +aNb +aNb +fJA +avQ +avQ +avQ +avQ +avQ +avQ +avQ +hYN +jqP +jqP +jqP +jqP +lSj +mXz +mXz +mXz +pra +pQZ +smK +tda +tda +xSD +yda +pwa +jRE +sOE +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(39,1,1) = {" +aab +aab +aab +aab +aab +aab +awB +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aGG +aHz +aHb +aGF +aKX +aKX +aKX +aHc +aab +aab +aab +aRl +aNl +aNn +aPJ +bgb +cnP +aNb +aNb +fFh +avQ +avQ +avQ +avQ +gWz +wkp +wkp +wkp +jqP +jqP +jqP +jqP +lSj +mXz +mXz +mXz +pfy +pMA +sCN +mXz +mXz +xfb +jRE +gXh +jRE +sOE +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(40,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aRl +aHb +aHz +aHb +aGF +aGF +aGF +aGF +aHc +aab +aab +aab +aRl +aNm +aNn +aNn +bgJ +cnP +aNb +aNb +fFh +fFh +fUy +fFh +avQ +gWz +wkp +avQ +wkp +jqP +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +qgz +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(41,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +awB +aab +aab +aab +aad +aad +aaR +aaR +aad +aad +aad +aad +aad +aad +aad +aad +aad +aad +aad +aad +aad +aGF +aGF +aGF +aGF +aKX +aKX +aKX +aRl +aab +aab +aab +aRl +aNn +aNn +aNn +bgJ +cnP +aNb +aNb +wkp +avQ +ghj +avQ +avQ +gWz +hqi +avQ +wkp +jpr +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +lPd +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(42,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aae +aaT +aaT +abB +ace +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aad +aHc +aHc +aHc +aKd +aHc +aHc +aHc +aRl +aab +aab +aab +aRl +aNb +aNb +aNb +aNb +aNb +aNb +aNb +wkp +fMq +avQ +fFh +wjz +haH +wkp +avQ +wkp +jqP +kfk +ljR +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +sRb +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(43,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaq +aaK +aaK +abC +acf +aaK +aci +aaK +aaK +aaK +aaK +aaK +aaK +aci +aaK +acf +aHe +aHF +aHF +aHF +aHF +aHF +aLv +aRl +aab +aab +aab +aRl +aNb +aNb +aNb +aNb +aNb +aNb +aNb +wkp +wkp +wkp +wkp +wkp +wkp +wkp +avQ +wkp +jpr +kfk +jqP +kfk +lSj +mXz +mXz +mXz +mXz +mXz +mXz +mXz +mXz +lSj +cQH +jRE +cIe +kkN +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(44,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaq +aaK +aaK +abC +aaR +acm +acQ +acQ +alr +aAm +aBZ +acQ +acQ +acQ +aDl +aFC +aHr +aHr +aHr +aHr +aHr +aHr +aLw +aRl +aRl +aRl +aRl +aRl +aRl +aNK +aNK +aRl +aRl +aRl +aRl +aRl +aab +aab +aab +aab +aab +wkp +avQ +wkp +jqP +khR +lEJ +lQy +mgi +lTa +lTa +lTa +lTa +lTa +lTa +lTa +lTa +mgi +hMN +jLF +cIe +bDh +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(45,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaq +aaK +aaK +abC +aaR +abC +aaR +aaR +aaR +aAN +aaR +aaR +aad +aad +aaq +aGs +aHg +aHg +aHg +aHg +aKY +aKY +aLz +aRl +aMo +aMo +aMF +aMo +aKv +aHr +aHr +aKv +aMo +aMF +aMo +aRl +aab +aab +aab +aab +aab +wkp +avQ +wkp +jHj +kuG +jqP +jqP +lSj +mhI +ofF +ofF +ofF +ofF +ofF +ofF +mhI +lSj +jRE +jRE +jRE +sDZ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(46,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaq +aaK +aaK +abC +aaR +abC +aaR +aeQ +auJ +aaK +aCb +aCu +aad +aad +aaq +aad +aRl +aRl +aRl +aRl +aKd +aKd +aRl +aRl +aKv +aKv +aKv +aKv +aKv +aNx +aNx +aKv +aKv +aKv +aKv +aRl +aab +aab +aab +aab +aab +wkp +avQ +wkp +wkp +wkp +wkp +wkp +wkp +wkp +exJ +exJ +exJ +exJ +exJ +exJ +wkp +wkp +wkp +wkp +iMp +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(47,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aad +aad +aad +aad +aad +abC +aaR +aaK +auW +aaK +auW +aaK +aCu +aaR +aaq +aaK +aad +aHG +aIA +aKv +aHr +aHr +aKv +aLQ +aMp +aMp +aMp +aMp +aNo +aHr +aHr +bjb +cEu +dUx +dUx +aRl +aab +aab +aab +aab +aab +wkp +avQ +avQ +avQ +avQ +avQ +wkp +fis +qBg +xog +xog +xog +xog +xog +xog +uFd +sfj +wkp +avQ +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(48,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aaR +aaK +aaK +abC +aaR +aeR +avf +aBA +aaK +aCv +aDk +aaR +aaq +aaK +acf +aHH +aHr +aKC +aHr +aHr +aLF +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aRl +aab +aab +aab +aab +aab +wkp +wkp +wkp +wkp +wkp +avQ +wkp +fis +qBg +xog +tWl +xog +xog +tWl +xog +uFd +sfj +wkp +avQ +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(49,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aaR +aaK +aci +abC +aaR +ala +avy +aBB +aaK +aaK +aaK +aaR +aaq +aci +aHm +aHW +aHr +aKv +aKZ +aLh +aLG +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +bkb +aHr +aHr +aHr +aRl +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +fis +qBg +xog +xog +pyW +xog +xog +xog +uFd +sfj +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(50,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aaR +aaK +aaK +abC +aaR +alg +avV +aBC +aCj +aCv +aDk +aaR +aaq +aaK +aGs +aHX +aHr +aKE +aHr +aLm +aLI +aLR +aMq +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aRl +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +fis +qBg +xog +tWl +xog +xog +tWl +xog +uFd +sfj +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(51,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aad +aad +aad +aad +aad +abC +aaR +aaK +ayg +aaK +ayg +aCx +aCu +aaR +aaq +aaK +aad +aIh +aIT +aKv +aLa +aLn +aKv +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aPK +aLf +aLf +ewc +aNT +aRl +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +fis +qBg +xog +xog +xog +xog +xog +xog +uFd +sfj +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(52,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aay +aaK +aaK +aaK +aaR +abC +aaR +aeQ +aaK +aaK +aCk +aCy +aad +aad +aaq +aad +aRl +aRl +aRl +aRl +aRl +aRl +aRl +aLS +aLS +aMz +aMz +aMz +aHr +aHr +aRl +aRl +aRl +aRl +aRl +aRl +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +wkp +wkp +wkp +nIB +nIB +nIB +nIB +nIB +nIB +wkp +wkp +wkp +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(53,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaz +aaK +aaK +aaK +aaR +abC +aaR +aaR +aaR +aAN +aaR +aaR +aad +aad +aaq +aad +aHp +aIj +aJu +aIj +aIj +aLo +aRl +aLV +aKv +aKv +aMG +aKv +aNx +aNx +aRl +aab +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +avQ +avQ +avQ +wkp +avn +avn +avn +avn +avn +avQ +twS +avQ +avQ +avQ +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(54,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaA +aaK +aaK +aaK +aaR +acE +aaT +aaT +ayh +aBO +aCl +aaT +aaT +aaT +aDQ +aad +aHp +aIj +aJv +aIj +aIj +aIj +aLJ +aLS +aLS +aMA +aMA +aMA +aHr +aNL +aRl +ach +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +wkp +wkp +avQ +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +heW +wkp +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(55,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaK +aaK +aaK +aaK +acf +aaK +aci +aaK +aaK +aaK +aaK +aaK +aaK +aci +aaK +aad +aHp +aIj +aIj +aIj +aIj +aIj +aLK +aHr +aHr +aHr +aHr +aHr +aHr +aHr +aKv +aab +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +wjz +wjz +wjz +wjz +wjz +wjz +wjz +wjz +wjz +haH +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(56,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aaQ +aaK +aaK +aaK +acj +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aaK +aad +aHp +aIj +aIj +aIj +aIj +aIj +aLK +aMb +aMs +aMs +aMH +aMs +aMs +aNM +aKv +aab +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +wkp +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(57,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aad +aad +aaR +aaR +aad +aad +aad +aad +aad +aad +aad +aad +acf +aad +aad +aad +aad +aRl +aIj +aIj +aIj +aIj +aLt +aRl +aMd +aMt +aMC +aMJ +aMW +aMt +aNN +aRl +ach +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(58,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +aab +aab +aab +ach +aab +aab +aab +ach +aab +aab +aab +aab +ach +aab +aab +aRl +aRl +aJW +aKV +aLb +aLu +aRl +aMe +aKv +aMD +aMK +aMX +aKv +aNQ +aRl +aab +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(59,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +aab +aab +aab +ach +ach +aab +aab +ach +aab +aab +aab +aab +ach +aab +aab +aab +aRl +aRl +aRl +aRl +aRl +aRl +aMf +aKv +aKv +aKv +aKv +aKv +aNR +aRl +ach +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(60,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +ach +aab +aab +ach +ach +aab +aab +aab +ach +ach +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +ach +ach +aKv +aMg +aKv +ach +ach +ach +aKv +aNS +aKv +aab +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(61,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +aab +aab +ach +ach +ach +aab +aab +ach +aab +aab +aab +aab +ach +ach +ach +ach +ach +ach +ach +ach +ach +aGP +aMh +aKv +ach +aab +ach +aKv +aOv +aGP +ach +ach +ach +ach +ach +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(62,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +aab +aab +ach +ach +aab +aab +ach +ach +aab +aab +aab +aab +ach +aab +aab +aab +aab +aab +aab +aab +aMr +aMr +aHh +aMr +aIR +aIR +aIR +aMr +aHh +aMr +aMr +aMr +aLB +aLB +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(63,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +ach +aab +aab +aab +ach +aab +aab +aab +ach +ach +aab +aab +aab +ach +aab +aMr +aIR +aMr +aMr +aMr +aIR +aMr +aLL +bwE +aMu +nPB +nPB +nPB +aNA +bwE +aIR +aKo +cGo +eCw +aLE +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(64,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +ach +aab +aab +aab +ach +aab +aab +aab +ach +aab +aab +aab +aab +ach +aMr +aMr +hFt +aIk +aKa +kLu +kLu +edo +kLu +wRq +aHA +aHA +aHA +aHA +aHA +xIV +aPL +aLs +cIv +eCw +aLE +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(65,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +aAM +aAM +aAM +aAM +aAM +aAM +aAM +aAM +aAM +aAM +aab +aab +aab +aMr +aMr +aGC +vHR +hlP +aIR +aIS +aIS +aIS +aIS +gcV +aIS +aIS +aIS +aIS +aIS +aOZ +aPN +aMr +aMr +aMr +aMr +aMr +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(66,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +azR +aAa +azR +azR +azR +azR +azR +aAa +aAM +aAM +aCm +aab +aab +aIR +aDR +aGD +aKD +aIt +aGR +aGR +aIR +aIR +aGR +aMm +aIR +aIR +aIR +aIR +aIR +cxx +aIR +blb +djD +eDH +fsI +aMr +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(67,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +azR +azR +azR +azR +azR +azR +azR +azR +aAM +aBc +aBz +aab +aab +aIR +aEX +aGE +aHs +aMr +aGR +aFM +aLc +aLc +aIR +aMn +nPB +nPB +nPB +nPB +nPB +cxx +aIR +bmb +aLl +aLl +fyA +aIR +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(68,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +azR +azR +azR +azR +ack +azR +azR +azR +ayi +aBc +aBz +aab +aab +aIR +aDR +jSH +aHt +aEW +aFa +aFY +aLd +aIy +aLP +trW +abr +abr +aMT +abr +abr +fZb +aPO +aLl +aLl +fpV +fyA +aIR +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(69,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +azR +azR +azR +azR +azR +azR +azR +azR +aAM +aBc +aBz +aab +aab +aIR +aDF +kjk +aHu +aMr +aGR +aKW +aLe +aLe +aIR +gcV +aIS +aIS +aIS +aIS +aIS +cxx +aIR +bnb +aLl +aLl +fyA +aIR +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(70,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +azR +abg +abi +azR +acl +azR +adL +abg +aAM +aAM +aCt +aab +aab +aIR +aDR +hhT +aKD +aHN +aGR +aGR +aIR +aIR +aGR +aMm +aIR +aIR +aIR +aIR +aIR +cxx +aIR +aKt +dkK +fsh +aLD +aMr +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(71,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAM +aAM +aAM +abn +acd +aAM +acd +azS +aAM +aAM +aAM +aab +aab +aab +aMr +aMr +aEg +yiv +jlk +aIR +nPB +nPB +nPB +nPB +gcV +nPB +nPB +aMU +nPB +nPB +aOZ +aPN +aMr +aMr +aMr +aMr +aMr +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(72,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aAl +aAl +aAl +aAl +aAl +aAl +aAl +aAl +aAl +aAl +aAl +ach +ach +ach +ach +aMr +aMr +jzQ +aIz +aKa +aHA +aHA +rsb +aHA +uOk +kBZ +kBZ +kBZ +kBZ +kBZ +nKf +aPL +bpb +dzr +eCw +aLE +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(73,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aMr +aIR +aMr +aMr +aMr +aIR +aMr +aGT +iYo +aIS +aIS +aIv +aIS +aIS +aLL +aIR +brb +dzs +eCw +aLE +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(74,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aMr +aMr +aIR +aMr +aMr +aMr +aMr +aMr +aIR +aMr +aMr +aMr +aLB +aLB +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(75,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(76,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(77,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(78,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(79,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(80,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(81,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(82,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(83,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(84,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(85,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(86,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(87,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(88,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(89,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(90,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(91,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(92,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(93,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(94,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(95,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(96,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(97,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(98,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(99,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(100,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(101,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(102,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(103,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(104,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(105,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(106,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(107,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(108,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(109,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(110,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(111,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(112,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(113,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(114,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(115,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(116,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(117,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(118,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(119,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(120,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(121,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(122,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(123,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(124,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(125,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(126,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(127,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(128,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(129,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(130,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(131,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(132,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(133,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(134,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(135,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(136,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(137,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(138,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(139,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(140,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(141,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(142,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(143,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(144,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(145,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(146,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(147,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(148,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(149,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(150,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(151,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(152,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(153,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(154,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(155,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(156,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(157,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(158,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(159,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(160,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(161,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(162,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(163,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(164,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(165,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(166,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(167,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(168,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +nSv +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(169,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(170,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(171,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(172,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(173,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(174,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +mZU +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(175,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(176,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(177,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(178,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(179,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(180,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +awl +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(181,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(182,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(183,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(184,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(185,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(186,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(187,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(188,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +sMD +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(189,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(190,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(191,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(192,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(193,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(194,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(195,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(196,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(197,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(198,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(199,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} +(200,1,1) = {" +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +aab +"} diff --git a/maps/exodus/exodus-transit.dmm b/maps/exodus/exodus-transit.dmm new file mode 100644 index 000000000000..3561cf644776 --- /dev/null +++ b/maps/exodus/exodus-transit.dmm @@ -0,0 +1,65585 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/obj/effect/shuttle_landmark/escape_pod/transit/pod3, +/turf/space, +/area/space) +"ac" = ( +/obj/effect/shuttle_landmark/escape_pod/transit/pod1, +/turf/space, +/area/space) +"ad" = ( +/obj/effect/shuttle_landmark/escape_pod/transit/pod2, +/turf/space, +/area/space) +"ae" = ( +/obj/effect/shuttle_landmark/escape_pod/transit/pod4, +/turf/space, +/area/space) +"rv" = ( +/obj/effect/step_trigger/teleporter/random{ + affect_ghosts = 1; + name = "escapeshuttle_leave"; + opacity = 0; + teleport_x = 25; + teleport_x_offset = 245; + teleport_y = 25; + teleport_y_offset = 245; + teleport_z = 6; + teleport_z_offset = 6 + }, +/obj/effect/step_trigger/thrower{ + affect_ghosts = 1; + name = "thrower_throwdown"; + tiles = 0 + }, +/turf/space, +/area/space) +"yM" = ( +/obj/effect/shuttle_landmark/escape_shuttle/transit, +/turf/space, +/area/space) +"QP" = ( +/obj/abstract/level_data_spawner/admin_level{ + name = "Exodus Transit Level" + }, +/turf/space, +/area/space) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +QP +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(129,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(130,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(131,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(132,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(133,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(134,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(135,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(136,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(137,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(138,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(139,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(140,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(141,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(142,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(143,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(144,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(145,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(146,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(147,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(148,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(149,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(150,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(151,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(152,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(153,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(154,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(155,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(156,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(157,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(158,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(159,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(160,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(161,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(162,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(163,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(164,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(165,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(166,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(167,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(168,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(169,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(170,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(171,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(172,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(173,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(174,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(175,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(176,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(177,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(178,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(179,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(180,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(181,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(182,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(183,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(184,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(185,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(186,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(187,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(188,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(189,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(190,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(191,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +rv +rv +rv +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(192,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(193,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(194,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(195,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(196,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(197,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yM +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(198,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(199,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(200,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(201,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(202,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(203,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +rv +rv +rv +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(204,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(205,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(206,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(207,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(208,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(209,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(210,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(211,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(212,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(213,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(214,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(215,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(216,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(217,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(218,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(219,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(220,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(221,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(222,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(223,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(224,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(225,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(226,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(227,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(228,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(229,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(230,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(231,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(232,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(233,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(234,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(235,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(236,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(237,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(238,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(239,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(240,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(241,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(242,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(243,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(244,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(245,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(246,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(247,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(248,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(249,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(250,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(251,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(252,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(253,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(254,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(255,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/exodus/exodus.dm b/maps/exodus/exodus.dm new file mode 100644 index 000000000000..a5bb07e061cf --- /dev/null +++ b/maps/exodus/exodus.dm @@ -0,0 +1,91 @@ +#if !defined(USING_MAP_DATUM) + + #include "../../mods/content/mundane.dm" + #include "../../mods/content/scaling_descriptors.dm" + + #include "../../mods/content/augments/_augments.dme" + #include "../../mods/content/beekeeping/_beekeeping.dme" + #include "../../mods/content/bigpharma/_bigpharma.dme" + #include "../../mods/content/blob/_blob.dme" + #include "../../mods/content/corporate/_corporate.dme" + #include "../../mods/content/government/_government.dme" + #include "../../mods/content/integrated_electronics/_integrated_electronics.dme" + #include "../../mods/content/matchmaking/_matchmaking.dme" + #include "../../mods/content/modern_earth/_modern_earth.dme" + #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" + #include "../../mods/content/pheromones/_pheromones.dme" + #include "../../mods/content/psionics/_psionics.dme" + #include "../../mods/content/response_team/_response_team.dme" + #include "../../mods/content/sealant_gun/_sealant_gun.dme" + #include "../../mods/content/standard_jobs/_standard_jobs.dme" + #include "../../mods/content/supermatter/_supermatter.dme" + #include "../../mods/content/ventcrawl/_ventcrawl.dme" + #include "../../mods/content/xenobiology/_xenobiology.dme" + #include "../../mods/content/exploration/_exploration.dme" + #include "../../mods/content/tabloids/_tabloids.dme" + + #include "../../mods/gamemodes/cult/_cult.dme" + #include "../../mods/gamemodes/heist/_heist.dme" + #include "../../mods/gamemodes/meteor/_meteor.dme" + #include "../../mods/gamemodes/mercenary/_mercenary.dme" + #include "../../mods/gamemodes/ninja/_ninja.dme" + #include "../../mods/gamemodes/revolution/_revolution.dme" + #include "../../mods/gamemodes/spyvspy/_spyvspy.dme" + #include "../../mods/gamemodes/traitor/_traitor.dme" + #include "../../mods/gamemodes/mixed.dm" + + #include "../../mods/mobs/borers/_borers.dme" + #include "../../mods/mobs/dionaea/_dionaea.dme" + + #include "../../mods/species/ascent/_ascent.dme" + #include "../../mods/species/tajaran/_tajaran.dme" + #include "../../mods/species/unathi/_unathi.dme" + #include "../../mods/species/skrell/_skrell.dme" + #include "../../mods/species/adherent/_adherent.dme" + #include "../../mods/species/tritonian/_tritonian.dme" + #include "../../mods/species/serpentid/_serpentid.dme" + #include "../../mods/species/utility_frames/_utility_frames.dme" + + #include "../random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm" + #include "../random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dm" + + #include "../../mods/content/government/away_sites/icarus/icarus.dm" + #include "../../mods/content/corporate/away_sites/lar_maria/lar_maria.dm" + + #include "../away/liberia/liberia.dm" + #include "../away/bearcat/bearcat.dm" + #include "../away/casino/casino.dm" + #include "../away/derelict/derelict.dm" + #include "../away/errant_pisces/errant_pisces.dm" + #include "../away/lost_supply_base/lost_supply_base.dm" + #include "../away/magshield/magshield.dm" + #include "../away/mining/mining.dm" + #include "../away/mobius_rift/mobius_rift.dm" + #include "../away/smugglers/smugglers.dm" + #include "../away/unishi/unishi.dm" + #include "../away/yacht/yacht.dm" + + #include "exodus_goals.dm" + + #include "exodus_announcements.dm" + #include "exodus_antagonism.dm" + #include "exodus_cameras.dm" + #include "exodus_areas.dm" + #include "exodus_elevator.dm" + #include "exodus_jobs.dm" + #include "exodus_loadout.dm" + #include "exodus_overmap.dm" + #include "exodus_setup.dm" + #include "exodus_shuttles.dm" + #include "exodus_unit_testing.dm" + + #include "exodus-1.dmm" + #include "exodus-2.dmm" + #include "exodus-admin.dmm" + #include "exodus-transit.dmm" + + #define USING_MAP_DATUM /datum/map/exodus + +#elif !defined(MAP_OVERRIDE) + #warn A map has already been included, ignoring Exodus +#endif diff --git a/maps/exodus/exodus_announcements.dm b/maps/exodus/exodus_announcements.dm new file mode 100644 index 000000000000..ca9c028ccc65 --- /dev/null +++ b/maps/exodus/exodus_announcements.dm @@ -0,0 +1,26 @@ +/datum/map/exodus + emergency_shuttle_docked_message = "The Emergency Shuttle has docked with the station. You have approximately %ETD% to board the Emergency Shuttle." + emergency_shuttle_leaving_dock = "The Emergency Shuttle has left the station. Estimate %ETA% until the shuttle docks at %dock_name%." + + emergency_shuttle_called_message = "An emergency evacuation shuttle has been called. It will arrive in approximately %ETA%." + emergency_shuttle_called_sound = 'sound/AI/shuttlecalled.ogg' + + emergency_shuttle_recall_message = "The emergency shuttle has been recalled." + + command_report_sound = 'sound/AI/commandreport.ogg' + grid_check_sound = 'sound/AI/poweroff.ogg' + grid_restored_sound = 'sound/AI/poweron.ogg' + meteor_detected_sound = 'sound/AI/meteors.ogg' + radiation_detected_sound = 'sound/AI/radiation.ogg' + space_time_anomaly_sound = 'sound/AI/spanomalies.ogg' + unidentified_lifesigns_sound = 'sound/AI/aliens.ogg' + + electrical_storm_moderate_sound = null + electrical_storm_major_sound = null + +/datum/map/exodus/level_x_biohazard_sound(var/bio_level) + switch(bio_level) + if(7) + return 'sound/AI/outbreak7.ogg' + else + return 'sound/AI/outbreak5.ogg' diff --git a/maps/exodus/exodus_antagonism.dm b/maps/exodus/exodus_antagonism.dm new file mode 100644 index 000000000000..e09d2ddc9002 --- /dev/null +++ b/maps/exodus/exodus_antagonism.dm @@ -0,0 +1,19 @@ +/decl/special_role/traitor/Initialize() + . = ..() + LAZYINITLIST(protected_jobs) + protected_jobs |= list(/datum/job/standard/officer, /datum/job/standard/warden, /datum/job/standard/detective, /datum/job/standard/captain, /datum/job/standard/lawyer, /datum/job/standard/hos) + +/decl/special_role/cultist/Initialize() + . = ..() + LAZYINITLIST(restricted_jobs) + restricted_jobs |= list(/datum/job/standard/lawyer, /datum/job/standard/captain, /datum/job/standard/hos) + LAZYINITLIST(protected_jobs) + protected_jobs |= list(/datum/job/standard/officer, /datum/job/standard/warden, /datum/job/standard/detective) + LAZYINITLIST(blacklisted_jobs) + blacklisted_jobs |= list(/datum/job/standard/chaplain, /datum/job/standard/counselor) + +/decl/special_role/loyalist + command_department_id = /decl/department/command + +/decl/special_role/revolutionary + command_department_id = /decl/department/command diff --git a/maps/exodus/exodus_areas.dm b/maps/exodus/exodus_areas.dm new file mode 100644 index 000000000000..336403c6218d --- /dev/null +++ b/maps/exodus/exodus_areas.dm @@ -0,0 +1,1094 @@ +/datum/event/prison_break/medical + areaType = list(/area/exodus/medical) + +/datum/event/prison_break/science + areaType = list(/area/exodus/research) + +/datum/event/prison_break/station + areaType = list(/area/exodus/security) + +//Comments are for my own sanity. PLEASE DONT REMOVE THEM AS IT WAS VERY HARD TO SORT ALL THIS +//Do not remove dots after comments + +/area/exodus + secure = TRUE + holomap_color = HOLOMAP_AREACOLOR_CREW + +//COMMAND. + +/area/exodus/bridge + name = "\improper Bridge" + icon_state = "bridge" + req_access = list(access_bridge) + +/area/exodus/bridge/meeting_room + name = "\improper Heads of Staff Meeting Room" + icon_state = "bridge" + sound_env = MEDIUM_SOFTFLOOR + +//CAPTAIN'S QUARTERS. + +/area/exodus/crew_quarters/captain + name = "\improper Command - Captain's Office" + icon_state = "captain" + sound_env = MEDIUM_SOFTFLOOR + req_access = list(access_captain) + +//COMMAND QUARTERS. + +/area/exodus/crew_quarters/heads + icon_state = "head_quarters" + req_access = list(access_heads) + +/area/exodus/crew_quarters/heads/chief + name = "\improper Engineering - CE's Office" + req_access = list(access_ce) + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +/area/exodus/crew_quarters/heads/hos + name = "\improper Security - HoS' Office" + req_access = list(access_hos) + holomap_color = HOLOMAP_AREACOLOR_SECURITY + +/area/exodus/crew_quarters/heads/hop + name = "\improper Command - HoP's Office" + req_access = list(access_hop) + +/area/exodus/crew_quarters/heads/hor + name = "\improper Research - RD's Office" + req_access = list(access_rd) + holomap_color = HOLOMAP_AREACOLOR_SCIENCE + +/area/exodus/crew_quarters/heads/cmo + name = "\improper Command - CMO's Office" + req_access = list(access_cmo) + holomap_color = HOLOMAP_AREACOLOR_MEDICAL + +//TCOMS. + +/area/exodus/maintenance/telecomms + name = "Telecommunications Sublevel" + sound_env = SMALL_ENCLOSED + req_access = list(access_tcomsat) + +//SOLAR. + +/area/exodus/maintenance/auxsolarport + name = "Solar Maintenance - Port" + icon_state = "SolarcontrolP" + sound_env = SMALL_ENCLOSED + req_access = list(access_engine) + +/area/exodus/maintenance/auxsolarstarboard + name = "Solar Maintenance - Starboard" + icon_state = "SolarcontrolS" + sound_env = SMALL_ENCLOSED + req_access = list(access_engine) + +/area/exodus/solar + requires_power = TRUE + always_unpowered = TRUE + has_gravity = FALSE + base_turf = /turf/space + +/area/exodus/solar/auxstarboard + name = "\improper Fore Starboard Solar Array" + icon_state = "panelsA" + +/area/exodus/solar/port + name = "\improper Port Auxiliary Solar Array" + icon_state = "panelsP" + +/area/exodus/solar/starboard + name = "\improper Starboard Auxiliary Solar Array" + icon_state = "panelsS" + +/area/exodus/solar/auxport + name = "\improper Fore Port Solar Array" + icon_state = "panelsA" + +/area/exodus/solar/fore + name = "\improper Fore Solar Array" + icon_state = "yellow" + +/area/exodus/maintenance/foresolar + name = "\improper Solar Maintenance - Fore" + icon_state = "SolarcontrolA" + sound_env = SMALL_ENCLOSED + +/area/exodus/maintenance/portsolar + name = "\improper Solar Maintenance - Aft Port" + icon_state = "SolarcontrolP" + sound_env = SMALL_ENCLOSED + +/area/exodus/maintenance/starboardsolar + name = "\improper Solar Maintenance - Aft Starboard" + icon_state = "SolarcontrolS" + sound_env = SMALL_ENCLOSED + +//STORAGE. + +/area/exodus/storage/tech + name = "Technical Storage" + icon_state = "storage" + req_access = list(access_tech_storage) + +/area/exodus/storage/primary + name = "Primary Tool Storage" + icon_state = "primarystorage" + +/area/exodus/storage/tools + name = "Auxiliary Tool Storage" + icon_state = "auxstorage" + +/area/exodus/storage/art + name = "Art Supply Storage" + icon_state = "storage" + +/area/exodus/storage/emergency + name = "Starboard Emergency Storage" + icon_state = "emergencystorage" + req_access = list(access_emergency_storage) + +/area/exodus/storage/emergency2 + name = "Port Emergency Storage" + icon_state = "emergencystorage" + req_access = list(access_emergency_storage) + +//ENGINEERING. + +/area/exodus/engineering + name = "\improper Engineering" + icon_state = "engineering" + ambience = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg') + req_access = list(access_engine) + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +//Generic +/area/exodus/engineering/foyer + name = "\improper Engineering Foyer" + icon_state = "engineering_foyer" + +/area/exodus/engineering/locker_room + name = "\improper Engineering Locker Room" + icon_state = "engineering_locker" + +/area/exodus/engineering/storage + name = "\improper Engineering Storage" + icon_state = "engineering_storage" + +/area/exodus/engineering/engine_eva + name = "\improper Engine EVA" + icon_state = "engine_eva" + +//Supermatter +/area/exodus/engineering/engine_monitoring + name = "\improper Engine Monitoring Room" + icon_state = "engine_monitoring" + +/area/exodus/engineering/engine_airlock + name = "\improper Engine Room Airlock" + icon_state = "engine" + holomap_color = HOLOMAP_AREACOLOR_AIRLOCK + +/area/exodus/engineering/engine_room + name = "\improper Engine Room" + icon_state = "engine" + sound_env = LARGE_ENCLOSED + +/area/exodus/engineering/engine_waste + name = "\improper Engine Waste Handling" + icon_state = "engine_waste" + +/area/exodus/engineering/engine_smes + name = "\improper Engineering SMES" + icon_state = "engine_smes" + sound_env = SMALL_ENCLOSED + +//Monitoring and misc +/area/exodus/engineering/engineering_monitoring + name = "\improper Engineering Monitoring Room" + icon_state = "engine_monitoring" + +/area/exodus/engineering/break_room + name = "\improper Engineering Break Room" + icon_state = "engineering_break" + sound_env = MEDIUM_SOFTFLOOR + +/area/exodus/engineering/drone_fabrication + name = "\improper Engineering Drone Fabrication" + icon_state = "drone_fab" + sound_env = SMALL_ENCLOSED + +/area/exodus/engineering/workshop + name = "\improper Engineering Workshop" + icon_state = "engineering_workshop" + +/area/exodus/engineering/sublevel_access + name = "\improper Engineering Sublevel Access" + +/area/exodus/construction + name = "\improper Engineering Construction Area" + icon_state = "yellow" + req_access = list(access_construction) + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +//ATMOSPHERICS. + +/area/exodus/engineering/atmos + name = "\improper Atmospherics" + icon_state = "atmos" + sound_env = LARGE_ENCLOSED + req_access = list(access_atmospherics) + +/area/exodus/engineering/atmos/storage + name = "\improper Atmospherics Storage" + icon_state = "atmos_storage" + sound_env = SMALL_ENCLOSED + +//MEDICAL. + +/area/exodus/medical + req_access = list(access_medical) + holomap_color = HOLOMAP_AREACOLOR_MEDICAL + +//Reception and such + +/area/exodus/medical/reception + name = "\improper Medbay Reception" + icon_state = "medbay" + ambience = list('sound/ambience/signal.ogg') + +//Hallways + +/area/exodus/medical/medbay + name = "\improper Medbay Hallway - Port" + icon_state = "medbay" + ambience = list('sound/ambience/signal.ogg') + +/area/exodus/medical/medbay2 + name = "\improper Medbay Hallway - Starboard" + icon_state = "medbay2" + ambience = list('sound/ambience/signal.ogg') + +/area/exodus/medical/medbay3 + name = "\improper Medbay Hallway - Fore" + icon_state = "medbay3" + ambience = list('sound/ambience/signal.ogg') + +/area/exodus/medical/medbay4 + name = "\improper Medbay Hallway - Aft" + icon_state = "medbay4" + ambience = list('sound/ambience/signal.ogg') + +//Main + +/area/exodus/medical/chemistry + name = "\improper Chemistry" + icon_state = "chem" + req_access = list(access_chemistry) + +/area/exodus/medical/morgue + name = "\improper Morgue" + icon_state = "morgue" + ambience = list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg','sound/music/main.ogg') + req_access = list(access_morgue) + +/area/exodus/medical/sleeper + name = "\improper Emergency Treatment Centre" + icon_state = "exam_room" + +//Surgery + +/area/exodus/medical/surgery + name = "\improper Operating Theatre" + icon_state = "surgery" + +/area/exodus/medical/surgery2 + name = "\improper Operating Theatre 2" + icon_state = "surgery" + +/area/exodus/medical/surgeryobs + name = "\improper Operation Observation Room" + icon_state = "surgery" + +/area/exodus/medical/surgeryprep + name = "\improper Pre-Op Prep Room" + icon_state = "surgery" + +//Cryo + +/area/exodus/medical/cryo + name = "\improper Cryogenics" + icon_state = "cryo" + +/area/exodus/medical/exam_room + name = "\improper Exam Room" + icon_state = "exam_room" + +//Misc + +/area/exodus/medical/psych + name = "\improper Psych Room" + icon_state = "medbay3" + ambience = list('sound/ambience/signal.ogg') + req_access = list(access_psychiatrist) + +/area/exodus/crew_quarters/medbreak + name = "\improper Break Room" + icon_state = "medbay3" + ambience = list('sound/ambience/signal.ogg') + req_access = list(access_medical) + +/area/exodus/medical/biostorage + name = "\improper Secondary Storage" + icon_state = "medbay4" + ambience = list('sound/ambience/signal.ogg') + +//Patient wing + +/area/exodus/medical/patient_a + name = "\improper Isolation A" + icon_state = "patients" + +/area/exodus/medical/patient_b + name = "\improper Isolation B" + icon_state = "patients" + +/area/exodus/medical/patient_c + name = "\improper Isolation C" + icon_state = "patients" + +/area/exodus/medical/patient_wing + name = "\improper Patient Wing" + icon_state = "patients" + +/area/exodus/medical/patient_wing/washroom + name = "\improper Patient Wing Washroom" + req_access = list() + +/area/exodus/medical/ward + name = "\improper Recovery Ward" + icon_state = "patients" + +// Virology + +/area/exodus/medical/virology + name = "\improper Virology" + icon_state = "virology" + req_access = list(access_virology) + +/area/exodus/medical/virology/access + name = "\improper Virology Access" + req_access = list() // This is like the lobby, needs low access to allow passing through in a different direction. + +//Unused + +/area/exodus/medical/genetics + name = "\improper Genetics Lab" + icon_state = "genetics" + +/area/exodus/medical/genetics/cloning + name = "\improper Cloning Lab" + icon_state = "cloning" + +//RESEARCH. + +/area/exodus/research + name = "\improper Research and Development" + icon_state = "research" + req_access = list(access_research) + holomap_color = HOLOMAP_AREACOLOR_SCIENCE + +//Labs + +/area/exodus/research/lab + name = "\improper Research Lab" + icon_state = "toxlab" + +/area/exodus/research/misc_lab + name = "\improper Miscellaneous Research" + icon_state = "toxmisc" + +/area/exodus/research/storage + name = "\improper Toxins Storage" + icon_state = "toxstorage" + req_access = list(access_tox) + +/area/exodus/research/mixing + name = "\improper Toxins Mixing Room" + icon_state = "toxmix" + req_access = list(access_tox) + +/area/exodus/research/test_area + name = "\improper Toxins Test Area" + icon_state = "toxtest" + req_access = list(access_tox) + +/area/exodus/research/xenobiology + name = "\improper Xenobiology Lab" + icon_state = "xeno_lab" + req_access = list(access_xenobiology, access_research) + +/area/exodus/research/xenobiology/xenoflora + name = "\improper Xenoflora Lab" + icon_state = "xeno_f_lab" + +/area/exodus/research/xenobiology/xenoflora_storage + name = "\improper Xenoflora Storage" + icon_state = "xeno_f_store" + +//Robotics + +/area/exodus/research/robotics + name = "\improper Robotics Lab" + icon_state = "robotics" + req_access = list(access_robotics) + +/area/exodus/research/chargebay + name = "\improper Mech Bay" + icon_state = "mechbay" + req_access = list(access_robotics) + +//Misc + +/area/exodus/research/docking + name = "\improper Research Dock" + icon_state = "research_dock" + +/area/exodus/research/server + name = "\improper Research Server Room" + icon_state = "server" + req_access = list(access_rd) + +//SECURITY. + +/area/exodus/security + area_flags = AREA_FLAG_SECURITY + req_access = list(access_security) + holomap_color = HOLOMAP_AREACOLOR_SECURITY + +//Lobby and such + +/area/exodus/security/lobby + name = "\improper Security Lobby" + icon_state = "security" + req_access = list() + +//Main + +/area/exodus/security/main + name = "\improper Security Office" + icon_state = "security" + +/area/exodus/security/meeting + name = "\improper Security Meeting Room" + icon_state = "security" + +/area/exodus/security/checkpoint2 + name = "\improper Security - Checkpoint" + icon_state = "checkpoint1" + +//Warden and such + +/area/exodus/security/armoury + name = "\improper Security - Armory" + icon_state = "Warden" + req_access = list(access_armory) + +/area/exodus/security/tactical + name = "\improper Security - Tactical Equipment" + icon_state = "Tactical" + req_access = list(access_armory) + +/area/exodus/security/warden + name = "\improper Security - Warden's Office" + icon_state = "Warden" + req_access = list(access_armory) + +//Brig + +/area/exodus/security/brig + name = "\improper Security - Brig" + req_access = list(access_brig) + +/area/exodus/security/brig/processing + name = "\improper Security - Processing" + icon_state = "brig" + +/area/exodus/security/brig/interrogation + name = "\improper Security - Interrogation" + icon_state = "brig" + +/area/exodus/security/brig/solitaryA + name = "\improper Security - Solitary 1" + icon_state = "sec_prison" + +/area/exodus/security/brig/solitaryB + name = "\improper Security - Solitary 2" + icon_state = "sec_prison" + +//Prison + +/area/exodus/security/prison + name = "\improper Security - Prison Wing" + icon_state = "sec_prison" + req_access = list(access_brig) + area_flags = AREA_FLAG_PRISON + +/area/exodus/security/prison/restroom + name = "\improper Security - Prison Wing Restroom" + icon_state = "sec_prison" + +/area/exodus/security/prison/dorm + name = "\improper Security - Prison Wing Dormitory" + icon_state = "sec_prison" + +//Misc + +/area/exodus/security/detectives_office + name = "\improper Security - Forensic Office" + icon_state = "detective" + sound_env = MEDIUM_SOFTFLOOR + req_access = list(access_forensics_lockers) + +/area/exodus/security/nuke_storage + name = "\improper Vault" + icon_state = "nuke_storage" + req_access = list(access_heads_vault) + +/area/exodus/security/vacantoffice + name = "\improper Vacant Office" + icon_state = "security" + req_access = list() + +/area/exodus/security/range + name = "\improper Security - Firing Range" + icon_state = "firingrange" + +//CARGO. + +/area/exodus/quartermaster + name = "\improper Quartermasters" + icon_state = "quart" + req_access = list(access_cargo) + holomap_color = HOLOMAP_AREACOLOR_CARGO + +/area/exodus/quartermaster/office + name = "\improper Supply Office" + icon_state = "quartoffice" + req_access = list(list(access_cargo, access_mining)) + +/area/exodus/quartermaster/storage + name = "\improper Warehouse" + icon_state = "quartstorage" + sound_env = LARGE_ENCLOSED + +/area/exodus/quartermaster/miningdock + name = "\improper Cargo Mining Dock" + icon_state = "mining" + req_access = list(access_mining) + +//qm + +/area/exodus/quartermaster/qm + name = "\improper Cargo - Quartermaster's Office" + icon_state = "quart" + req_access = list(access_qm) + +//CREW. + +/area/exodus/crew_quarters + name = "\improper Dormitories" + icon_state = "Sleep" + +/area/exodus/crew_quarters/sleep + name = "\improper Dormitories" + icon_state = "Sleep" + +/area/exodus/crew_quarters/sleep/cryo + name = "\improper Cryogenic Storage" + icon_state = "Sleep" + +/area/exodus/crew_quarters/sleep/bedrooms + name = "\improper Dormitory Bedroom One" + icon_state = "Sleep" + sound_env = SMALL_SOFTFLOOR + +/area/exodus/crew_quarters/sleep/engi_wash + name = "\improper Engineering Washroom" + icon_state = "toilet" + sound_env = SMALL_ENCLOSED + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +/area/exodus/crew_quarters/locker + name = "\improper Locker Room" + icon_state = "locker" + +/area/exodus/crew_quarters/locker/locker_toilet + name = "\improper Locker Toilets" + icon_state = "toilet" + sound_env = SMALL_ENCLOSED + +/area/exodus/crew_quarters/toilet + name = "\improper Dormitory Toilets" + icon_state = "toilet" + sound_env = SMALL_ENCLOSED + +/area/exodus/crew_quarters/fitness + name = "\improper Fitness Room" + icon_state = "fitness" + +/area/exodus/library + name = "\improper Library" + icon_state = "library" + sound_env = LARGE_SOFTFLOOR + + +//Service and such + +/area/exodus/crew_quarters/kitchen + name = "\improper Kitchen" + icon_state = "kitchen" + req_access = list(access_kitchen) + +/area/exodus/crew_quarters/bar + name = "\improper Bar" + icon_state = "bar" + sound_env = LARGE_SOFTFLOOR + +/area/exodus/crew_quarters/bar/cabin + name = "\improper Bartender's Room" + req_access = list(access_bar) + +/area/exodus/janitor + name = "\improper Custodial Closet" + icon_state = "janitor" + req_access = list(access_janitor) + +/area/exodus/hydroponics + name = "\improper Hydroponics" + icon_state = "hydro" + req_access = list(access_hydroponics) + +/area/exodus/hydroponics/garden + name = "\improper Garden" + icon_state = "garden" + req_access = list() + +/area/exodus/chapel + area_flags = AREA_FLAG_HOLY + +/area/exodus/chapel/main + name = "\improper Chapel" + icon_state = "chapel" + sound_env = LARGE_ENCLOSED + ambience = list( + 'sound/ambience/ambicha1.ogg', + 'sound/ambience/ambicha2.ogg', + 'sound/ambience/ambicha3.ogg', + 'sound/ambience/ambicha4.ogg', + 'sound/music/traitor.ogg' + ) + +/area/exodus/chapel/office + name = "\improper Chapel Office" + icon_state = "chapeloffice" + req_access = list(access_chapel_office) + +/area/exodus/lawoffice + name = "\improper Internal Affairs" + icon_state = "law" + req_access = list(access_lawyer) + +//AI. + +/area/exodus/ai_monitored + name = "AI Monitored Area" + +/area/exodus/ai_monitored/storage/eva + name = "\improper EVA Storage" + icon_state = "eva" + req_access = list(access_eva) + +/area/exodus/turret_protected + req_access = list(access_ai_upload) + +/area/exodus/turret_protected/ai + name = "\improper AI Chamber" + icon_state = "ai_chamber" + ambience = list('sound/ambience/ambimalf.ogg') + +/area/exodus/turret_protected/ai_cyborg_station + name = "\improper Cyborg Station" + icon_state = "ai_cyborg" + sound_env = SMALL_ENCLOSED + +/area/exodus/turret_protected/ai_upload + name = "\improper AI Upload Chamber" + icon_state = "ai_upload" + ambience = list('sound/ambience/ambimalf.ogg') + +/area/exodus/turret_protected/ai_upload_foyer + name = "\improper AI Upload Access" + icon_state = "ai_foyer" + ambience = list('sound/ambience/ambimalf.ogg') + sound_env = SMALL_ENCLOSED + +/area/exodus/turret_protected/ai_server_room + name = "Messaging Server Room" + icon_state = "ai_server" + sound_env = SMALL_ENCLOSED + req_access = list(access_tcomsat) + +//SHUTTLE. + +/area/shuttle/arrival + name = "\improper Arrival Shuttle" + +/area/shuttle/arrival/station + icon_state = "shuttle" + +// SUBSTATIONS. (Subtype of maint, that should let them serve as shielded area during radstorm) + +/area/exodus/maintenance/substation + name = "Substation" + icon_state = "substation" + sound_env = SMALL_ENCLOSED + req_access = list(access_engine) + +/area/exodus/maintenance/substation/command // AI and central cluster. This one will be between HoP office and meeting room (probably). + name = "Command Substation" + +/area/exodus/maintenance/substation/engineering // Probably will be connected to engineering SMES room, as wires cannot be crossed properly without them sharing powernets. + name = "Engineering Substation" + +/area/exodus/maintenance/substation/medical // Medbay + name = "Medical Substation" + +/area/exodus/maintenance/substation/research // Research + name = "Research Substation" + +/area/exodus/maintenance/substation/civilian_east // Bar, kitchen, dorms, ... + name = "Civilian East Substation" + +/area/exodus/maintenance/substation/civilian_west // Cargo, PTS, locker room, probably arrivals, ...) + name = "Civilian West Substation" + +/area/exodus/maintenance/substation/security // Security, Brig, Permabrig, etc. + name = "Security Substation" + +/area/exodus/maintenance/substation/atmospherics + name = "Atmospherics Substation" + +//MAINTENANCE. + +/area/exodus/maintenance + area_flags = AREA_FLAG_RAD_SHIELDED + sound_env = TUNNEL_ENCLOSED + turf_initializer = /decl/turf_initializer/maintenance + forced_ambience = list('sound/ambience/maintambience.ogg') + req_access = list(access_maint_tunnels) + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE + +/area/exodus/maintenance/atmos_control + name = "\improper Atmospherics Maintenance" + icon_state = "fpmaint" + req_access = list(list(access_atmospherics, access_maint_tunnels)) + +/area/exodus/maintenance/arrivals + name = "\improper Arrivals Maintenance" + icon_state = "maint_arrivals" + +/area/exodus/maintenance/bar + name = "\improper Bar Maintenance" + icon_state = "maint_bar" + req_access = list(list(access_bar, access_kitchen, access_maint_tunnels)) + +/area/exodus/maintenance/cargo + name = "\improper Cargo Maintenance" + icon_state = "maint_cargo" + req_access = list(list(access_cargo, access_maint_tunnels)) + +/area/exodus/maintenance/engi_engine + name = "\improper Engine Maintenance" + icon_state = "maint_engine" + +/area/exodus/maintenance/engi_shuttle + name = "\improper Engineering Shuttle Access" + icon_state = "maint_e_shuttle" + +/area/exodus/maintenance/engineering + name = "\improper Engineering Maintenance" + icon_state = "maint_engineering" + +/area/exodus/maintenance/evahallway + name = "\improper EVA Maintenance" + icon_state = "maint_eva" + req_access = list(list(access_eva, access_maint_tunnels)) + +/area/exodus/maintenance/dormitory + name = "\improper Dormitory Maintenance" + icon_state = "maint_dormitory" + +/area/exodus/maintenance/library + name = "\improper Library Maintenance" + icon_state = "maint_library" + req_access = list(list(access_library, access_maint_tunnels)) + +/area/exodus/maintenance/locker + name = "\improper Locker Room Maintenance" + icon_state = "maint_locker" + +/area/exodus/maintenance/medbay + name = "\improper Medbay Maintenance" + icon_state = "maint_medbay" + req_access = list(list(access_medical, access_maint_tunnels)) + +/area/exodus/maintenance/research_port + name = "\improper Research Maintenance - Port" + icon_state = "maint_research_port" + +/area/exodus/maintenance/research_shuttle + name = "\improper Research Shuttle Dock Maintenance" + icon_state = "maint_research_shuttle" + +/area/exodus/maintenance/research_starboard + name = "\improper Research Maintenance - Starboard" + icon_state = "maint_research_starboard" + +/area/exodus/maintenance/security_port + name = "\improper Security Maintenance - Port" + icon_state = "maint_security_port" + +/area/exodus/maintenance/security_starboard + name = "\improper Security Maintenance - Starboard" + icon_state = "maint_security_starboard" + +//MISC. MAINTENANCE. + +/area/exodus/maintenance/exterior + name = "\improper Exterior Reinforcements" + icon_state = "maint_security_starboard" + has_gravity = FALSE + turf_initializer = /decl/turf_initializer/maintenance/space + req_access = list(list(access_security, access_engine)) //whatever + +/area/exodus/maintenance/disposal + name = "Waste Disposal" + icon_state = "disposal" + +/area/exodus/maintenance/incinerator + name = "\improper Incinerator" + icon_state = "disposal" + +//SUBLEVEL MAINTENANCE. + +/area/exodus/maintenance/sub + turf_initializer = /decl/turf_initializer/maintenance/heavy + ambience = list( + 'sound/ambience/ambiatm1.ogg', + 'sound/ambience/ambigen3.ogg', + 'sound/ambience/ambigen4.ogg', + 'sound/ambience/ambigen5.ogg', + 'sound/ambience/ambigen6.ogg', + 'sound/ambience/ambigen7.ogg', + 'sound/ambience/ambigen8.ogg', + 'sound/ambience/ambigen9.ogg', + 'sound/ambience/ambigen10.ogg', + 'sound/ambience/ambigen11.ogg', + 'sound/ambience/ambigen12.ogg', + 'sound/ambience/ambimine.ogg', + 'sound/ambience/ambimo2.ogg', + 'sound/ambience/ambisin4.ogg', + 'sound/effects/wind/wind_2_1.ogg', + 'sound/effects/wind/wind_2_2.ogg', + 'sound/effects/wind/wind_3_1.ogg', + ) + +/area/exodus/maintenance/sub/relay_station + name = "\improper Sublevel Maintenance - Relay Station" + icon_state = "blue2" + turf_initializer = null + req_access = list(access_engine) + +/area/exodus/maintenance/sub/fore + name = "\improper Sublevel Maintenance - Fore" + icon_state = "sub_maint_fore" + +/area/exodus/maintenance/sub/aft + name = "\improper Sublevel Maintenance - Aft" + icon_state = "sub_maint_aft" + +/area/exodus/maintenance/sub/port + name = "\improper Sublevel Maintenance - Port" + icon_state = "sub_maint_port" + +/area/exodus/maintenance/sub/starboard + name = "\improper Sublevel Maintenance - Starboard" + icon_state = "sub_maint_starboard" + +/area/exodus/maintenance/sub/central + name = "\improper Sublevel Maintenance - Central" + icon_state = "sub_maint_central" + +/area/exodus/maintenance/sub/command + name = "\improper Sublevel Maintenance - Command" + icon_state = "sub_maint_command" + turf_initializer = null + +///////////// +//ELEVATORS// +///////////// + +/area/turbolift/security_station + name = "Station - By Security" + lift_announce_str = "Arriving at the station level, by the Security department." + +/area/turbolift/security_maintenance + name = "Maintenance - Below Security" + lift_announce_str = "Arriving at the maintenance level, below the Security department." + base_turf = /turf/floor/plating + +/area/turbolift/research_station + name = "Station - By Research" + lift_announce_str = "Arriving at the station level, by the R&D department." + +/area/turbolift/research_maintenance + name = "Maintenance - Below Research" + lift_announce_str = "Arriving at the maintenance level, below the R&D department." + base_turf = /turf/floor/plating + +/area/turbolift/engineering_station + name = "Station - By Engineering" + lift_announce_str = "Arriving at the station level, by the Engineering department." + +/area/turbolift/engineering_maintenance + name = "Maintenance - Below Engineering" + lift_announce_str = "Arriving at the maintenance level, below the Engineering department." + base_turf = /turf/floor/plating + +/area/turbolift/cargo_station + name = "Station - By Cargo" + lift_announce_str = "Arriving at the station level, by the Cargo department." + +/area/turbolift/cargo_maintenance + name = "Maintenance - Below Cargo" + lift_announce_str = "Arriving at the maintenance level, below the Cargo department." + base_turf = /turf/floor/plating + +///////////////// +//ELEVATORS END// +///////////////// + +//HALLWAYS. + +/area/exodus/hallway + area_flags = AREA_FLAG_HALLWAY + +/area/exodus/hallway/primary + sound_env = LARGE_ENCLOSED + +/area/exodus/hallway/primary/fore + name = "\improper Fore Primary Hallway" + icon_state = "hallF" + +/area/exodus/hallway/primary/starboard + name = "\improper Starboard Primary Hallway" + icon_state = "hallS" + +/area/exodus/hallway/primary/aft + name = "\improper Aft Primary Hallway" + icon_state = "hallA" + +/area/exodus/hallway/primary/port + name = "\improper Port Primary Hallway" + icon_state = "hallP" + +/area/exodus/hallway/primary/central_one + name = "\improper Central Primary Hallway" + icon_state = "hallC1" + +/area/exodus/hallway/primary/central_two + name = "\improper Central Primary Hallway" + icon_state = "hallC2" + +/area/exodus/hallway/primary/central_three + name = "\improper Central Primary Hallway" + icon_state = "hallC3" + +/area/exodus/hallway/secondary/exit + name = "\improper Escape Shuttle Hallway" + icon_state = "escape" + +/area/exodus/hallway/secondary/entry/pods + name = "\improper Arrival Shuttle Hallway - Escape Pods" + icon_state = "entry_pods" + +/area/exodus/hallway/secondary/entry/fore + name = "\improper Arrival Shuttle Hallway - Fore" + icon_state = "entry_1" + +/area/exodus/hallway/secondary/entry/port + name = "\improper Arrival Shuttle Hallway - Port" + icon_state = "entry_2" + +/area/exodus/hallway/secondary/entry/starboard + name = "\improper Arrival Shuttle Hallway - Starboard" + icon_state = "entry_3" + +/area/exodus/hallway/secondary/entry/aft + name = "\improper Arrival Shuttle Hallway - Aft" + icon_state = "entry_4" + +//TELEPORTER. + +/area/exodus/teleporter + name = "\improper Teleporter" + icon_state = "teleporter" + req_access = list(access_teleporter) + +// Thunderdome + +/area/tdome + name = "\improper Thunderdome" + icon_state = "thunder" + requires_power = 0 + dynamic_lighting = 0 + sound_env = ARENA + req_access = list(access_cent_thunder) + +/area/tdome/tdome1 + name = "\improper Thunderdome (Team 1)" + icon_state = "green" + +/area/tdome/tdome2 + name = "\improper Thunderdome (Team 2)" + icon_state = "yellow" + +/area/tdome/tdomeadmin + name = "\improper Thunderdome (Admin.)" + icon_state = "purple" + +/area/tdome/tdomeobserve + name = "\improper Thunderdome (Observer.)" + icon_state = "purple" + +/area/centcom + name = "\improper Centcom" + icon_state = "centcom" + requires_power = FALSE + dynamic_lighting = FALSE + req_access = list(access_cent_general) + +/area/centcom/holding + name = "\improper Holding Facility" + +/area/shuttle/supply_shuttle + name = "Supply Shuttle" + icon_state = "shuttle3" + req_access = list(access_cargo) + +/area/shuttle/escape_shuttle + name = "\improper Emergency Shuttle" + icon_state = "shuttle" diff --git a/maps/exodus/exodus_cameras.dm b/maps/exodus/exodus_cameras.dm new file mode 100644 index 000000000000..0c55ca3a3824 --- /dev/null +++ b/maps/exodus/exodus_cameras.dm @@ -0,0 +1,62 @@ +var/global/const/CAMERA_CHANNEL_COMMAND = "Command" +var/global/const/CAMERA_CHANNEL_ENGINE = "Engine" +var/global/const/CAMERA_CHANNEL_ENGINEERING_OUTPOST = "Engineering Outpost" +// +// Cameras +// + +// Networks +/obj/machinery/camera/network/command + preset_channels = list(CAMERA_CHANNEL_COMMAND) + req_access = list(access_heads) + +/obj/machinery/camera/network/crescent + preset_channels = list(CAMERA_CHANNEL_CRESCENT) + +/obj/machinery/camera/network/engine + preset_channels = list(CAMERA_CHANNEL_ENGINE) + req_access = list(access_engine) + +/obj/machinery/camera/network/engineering_outpost + preset_channels = list(CAMERA_CHANNEL_ENGINEERING_OUTPOST) + req_access = list(access_engine) + +// Motion +/obj/machinery/camera/motion/engineering_outpost + preset_channels = list(CAMERA_CHANNEL_ENGINEERING_OUTPOST) + req_access = list(access_engine) + +// All Upgrades +/obj/machinery/camera/all/command + preset_channels = list(CAMERA_CHANNEL_COMMAND) + req_access = list(access_heads) + +// Compile stubs. +/obj/machinery/camera/motion/command + preset_channels = list(CAMERA_CHANNEL_COMMAND) + req_access = list(access_heads) + +/obj/machinery/camera/network/maintenance + preset_channels = list(CAMERA_CHANNEL_ENGINEERING) + req_access = list(access_engine) + +/obj/machinery/camera/xray/security + preset_channels = list(CAMERA_CHANNEL_SECURITY) + +/obj/machinery/camera/network/exodus + preset_channels = list(CAMERA_CHANNEL_SECURITY) + +/obj/machinery/camera/network/civilian_east + preset_channels = list(CAMERA_CHANNEL_SECURITY) + +/obj/machinery/camera/network/civilian_west + preset_channels = list(CAMERA_CHANNEL_SECURITY) + +/obj/machinery/camera/network/prison + preset_channels = list(CAMERA_CHANNEL_SECURITY) + +/obj/machinery/camera/xray/medbay + preset_channels = list(CAMERA_CHANNEL_SECURITY) + +/obj/machinery/camera/xray/research + preset_channels = list(CAMERA_CHANNEL_SECURITY) diff --git a/maps/exodus/exodus_define.dm b/maps/exodus/exodus_define.dm new file mode 100644 index 000000000000..809350682b85 --- /dev/null +++ b/maps/exodus/exodus_define.dm @@ -0,0 +1,53 @@ +/datum/map/exodus + name = "Exodus" + full_name = "NSS Exodus" + path = "exodus" + + station_name = "NSS Exodus" + station_short = "Exodus" + dock_name = "NAS Crescent" + boss_name = "Central Command" + boss_short = "Centcomm" + company_name = "NanoTrasen" + company_short = "NT" + system_name = "Nyx" + + overmap_ids = list(OVERMAP_ID_SPACE) + num_exoplanets = 1 + + lobby_screens = list( + 'maps/exodus/lobby/exodus.png' + ) + + evac_controller_type = /datum/evacuation_controller/shuttle + +// For /datum/evacuation_controller/shuttle + + shuttle_docked_message = "The public ferry to %dock_name% has docked with the station. It will depart in approximately %ETD%" + shuttle_leaving_dock = "The public ferry has left the station. Estimate %ETA% until the ferry docks at %dock_name%." + shuttle_called_message = "A public ferry to %dock_name% has been scheduled. It will arrive in approximately %ETA%" + shuttle_recall_message = "The scheduled ferry has been cancelled." + +// For /datum/evacuation_controller/starship + +// shuttle_docked_message = "Attention all hands: Jump preparation complete. The subspace drive is now spooling up, secure all stations for departure. Time to jump: approximately %ETD%." +// shuttle_leaving_dock = "Attention all hands: Jump initiated, exiting subspace in %ETA%." +// shuttle_called_message = "Attention all hands: Jump sequence initiated. Transit procedures are now in effect. Jump in %ETA%." +// shuttle_recall_message = "Attention all hands: Jump sequence aborted, return to normal operating conditions." + + default_telecomms_channels = list( + COMMON_FREQUENCY_DATA, + list("name" = "Entertainment", "key" = "z", "frequency" = 1461, "color" = COMMS_COLOR_ENTERTAIN, "span_class" = CSS_CLASS_RADIO, "receive_only" = TRUE), + list("name" = "Command", "key" = "c", "frequency" = 1353, "color" = COMMS_COLOR_COMMAND, "span_class" = "comradio", "secured" = list(access_bridge)), + list("name" = "Security", "key" = "s", "frequency" = 1359, "color" = COMMS_COLOR_SECURITY, "span_class" = "secradio", "secured" = list(access_security)), + list("name" = "Engineering", "key" = "e", "frequency" = 1357, "color" = COMMS_COLOR_ENGINEER, "span_class" = "engradio", "secured" = list(access_engine)), + list("name" = "Medical", "key" = "m", "frequency" = 1355, "color" = COMMS_COLOR_MEDICAL, "span_class" = "medradio", "secured" = list(access_medical)), + list("name" = "Science", "key" = "n", "frequency" = 1351, "color" = COMMS_COLOR_SCIENCE, "span_class" = "sciradio", "secured" = list(access_research)), + list("name" = "Service", "key" = "v", "frequency" = 1349, "color" = COMMS_COLOR_SERVICE, "span_class" = "srvradio", "secured" = list(access_bar)), + list("name" = "Supply", "key" = "u", "frequency" = 1347, "color" = COMMS_COLOR_SUPPLY, "span_class" = "supradio", "secured" = list(access_cargo)), + list("name" = "Exploration", "key" = "x", "frequency" = 1361, "color" = COMMS_COLOR_EXPLORER , "span_class" = "EXPradio", "secured" = list(access_eva)), + list("name" = "AI Private", "key" = "p", "frequency" = 1343, "color" = COMMS_COLOR_AI, "span_class" = "airadio", "secured" = list(access_ai_upload)) + ) + +/datum/map/exodus/get_map_info() + return "Welcome to Exodus Station, one of the largest remaining stopovers between the core worlds and the rim. Enjoy your stay!" diff --git a/maps/exodus/exodus_elevator.dm b/maps/exodus/exodus_elevator.dm new file mode 100644 index 000000000000..a455e5ad5bd6 --- /dev/null +++ b/maps/exodus/exodus_elevator.dm @@ -0,0 +1,42 @@ +/obj/abstract/turbolift_spawner/exodus + depth = 2 + lift_size_x = 3 + lift_size_y = 3 + +/obj/abstract/turbolift_spawner/exodus/sec + name = "Exodus turbolift map placeholder - Securiy" + dir = EAST + + areas_to_use = list( + /area/turbolift/security_maintenance, + /area/turbolift/security_station + ) + +/obj/abstract/turbolift_spawner/exodus/research + name = "Exodus turbolift map placeholder - Research" + dir = WEST + + areas_to_use = list( + /area/turbolift/research_maintenance, + /area/turbolift/research_station + ) + +/obj/abstract/turbolift_spawner/exodus/engineering + name = "Exodus turbolift map placeholder - Engineering" + icon = 'icons/obj/turbolift_preview_3x3.dmi' + dir = EAST + lift_size_x = 4 + lift_size_y = 4 + + areas_to_use = list( + /area/turbolift/engineering_maintenance, + /area/turbolift/engineering_station + ) + +/obj/abstract/turbolift_spawner/exodus/cargo + name = "Exodus turbolift map placeholder - Cargo" + + areas_to_use = list( + /area/turbolift/cargo_maintenance, + /area/turbolift/cargo_station + ) diff --git a/maps/exodus/exodus_goals.dm b/maps/exodus/exodus_goals.dm new file mode 100644 index 000000000000..8275bc4173bb --- /dev/null +++ b/maps/exodus/exodus_goals.dm @@ -0,0 +1,48 @@ +/decl/department/command + goals = list(/datum/goal/department/paperwork/exodus) + +var/global/list/exodus_paperwork_spawn_turfs = list() +var/global/list/exodus_paperwork_end_areas = list() + +/obj/abstract/landmark/paperwork_spawn_exodus + name = "Exodus Paperwork Goal Spawn Point" + +/obj/abstract/landmark/paperwork_spawn_exodus/Initialize() + ..() + var/turf/T = get_turf(src) + if(istype(T)) + global.exodus_paperwork_spawn_turfs |= T + return INITIALIZE_HINT_QDEL + +/obj/abstract/landmark/paperwork_finish_exodus + name = "Exodus Paperwork Goal Finish Point" + +/obj/abstract/landmark/paperwork_finish_exodus/Initialize() + ..() + var/turf/T = get_turf(src) + if(istype(T)) + var/area/A = get_area(T) + if(istype(A)) + global.exodus_paperwork_end_areas |= A + return INITIALIZE_HINT_QDEL + +/datum/goal/department/paperwork/exodus + paperwork_types = list(/obj/item/paperwork/exodus) + signatory_job_list = list( + /datum/job/standard/captain, + /datum/job/standard/hop, + /datum/job/standard/cmo, + /datum/job/standard/chief_engineer, + /datum/job/standard/rd, + /datum/job/standard/hos + ) + +/datum/goal/department/paperwork/exodus/get_paper_spawn_turfs() + return global.exodus_paperwork_spawn_turfs + +/datum/goal/department/paperwork/exodus/get_paper_end_areas() + return global.exodus_paperwork_end_areas + +/obj/item/paperwork/exodus + name = "\improper Exodus payroll paperwork" + desc = "A complex list of salaries, hours and tax withheld for Exodus workers this month." diff --git a/maps/exodus/exodus_jobs.dm b/maps/exodus/exodus_jobs.dm new file mode 100644 index 000000000000..9310a431e2b1 --- /dev/null +++ b/maps/exodus/exodus_jobs.dm @@ -0,0 +1,86 @@ +/datum/map/exodus + default_job_type = /datum/job/standard/assistant + default_department_type = /decl/department/civilian + allowed_jobs = list( + /datum/job/standard/captain, + /datum/job/standard/hop, + /datum/job/standard/chaplain, + /datum/job/standard/bartender, + /datum/job/standard/chef, + /datum/job/standard/hydro, + /datum/job/standard/qm, + /datum/job/standard/cargo_tech, + /datum/job/standard/mining, + /datum/job/standard/janitor, + /datum/job/standard/librarian, + /datum/job/standard/lawyer, + /datum/job/standard/chief_engineer, + /datum/job/standard/engineer, + /datum/job/standard/cmo, + /datum/job/standard/doctor, + /datum/job/standard/chemist, + /datum/job/standard/counselor, + /datum/job/standard/rd, + /datum/job/standard/scientist, + /datum/job/standard/roboticist, + /datum/job/standard/hos, + /datum/job/standard/detective, + /datum/job/standard/warden, + /datum/job/standard/officer, + /datum/job/standard/robot, + /datum/job/standard/computer + ) + + species_to_job_whitelist = list( + /decl/species/adherent = list( + /datum/job/standard/computer, + /datum/job/standard/robot, + /datum/job/standard/assistant, + /datum/job/standard/janitor, + /datum/job/standard/chef, + /datum/job/standard/bartender, + /datum/job/standard/cargo_tech, + /datum/job/standard/engineer, + /datum/job/standard/roboticist, + /datum/job/standard/chemist, + /datum/job/standard/scientist, + /datum/job/standard/mining + ), + /decl/species/utility_frame = list( + /datum/job/standard/computer, + /datum/job/standard/robot, + /datum/job/standard/assistant, + /datum/job/standard/janitor, + /datum/job/standard/chef, + /datum/job/standard/bartender, + /datum/job/standard/cargo_tech, + /datum/job/standard/engineer, + /datum/job/standard/roboticist, + /datum/job/standard/chemist, + /datum/job/standard/scientist, + /datum/job/standard/mining + ), + /decl/species/serpentid = list( + /datum/job/standard/computer, + /datum/job/standard/robot, + /datum/job/standard/assistant, + /datum/job/standard/janitor, + /datum/job/standard/chef, + /datum/job/standard/bartender, + /datum/job/standard/cargo_tech, + /datum/job/standard/roboticist, + /datum/job/standard/chemist + ) + ) + +#define HUMAN_ONLY_JOBS /datum/job/standard/captain, /datum/job/standard/hop, /datum/job/standard/hos + species_to_job_blacklist = list( + /decl/species/unathi = list( + HUMAN_ONLY_JOBS + ), + /decl/species/tajaran = list( + HUMAN_ONLY_JOBS + ) + ) + +#undef HUMAN_ONLY_JOBS diff --git a/maps/exodus/exodus_loadout.dm b/maps/exodus/exodus_loadout.dm new file mode 100644 index 000000000000..d5f70fdf9571 --- /dev/null +++ b/maps/exodus/exodus_loadout.dm @@ -0,0 +1,20 @@ +/decl/loadout_option/accessory/insignia + name = "religious insignia" + path = /obj/item/clothing/insignia + cost = 1 + allowed_roles = list(/datum/job/standard/chaplain) + uid = "gear_accessory_insignia" + +/decl/loadout_option/accessory/insignia/Initialize() + . = ..() + var/insignia = list() + insignia["chaplain insignia (christianity)"] = /obj/item/clothing/insignia/christian + insignia["chaplain insignia (judaism)"] = /obj/item/clothing/insignia/judaism + insignia["chaplain insignia (islam)"] = /obj/item/clothing/insignia/islam + insignia["chaplain insignia (buddhism)"] = /obj/item/clothing/insignia/buddhism + insignia["chaplain insignia (hinduism)"] = /obj/item/clothing/insignia/hinduism + insignia["chaplain insignia (sikhism)"] = /obj/item/clothing/insignia/sikhism + insignia["chaplain insignia (baha'i faith)"] = /obj/item/clothing/insignia/bahaifaith + insignia["chaplain insignia (jainism)"] = /obj/item/clothing/insignia/jainism + insignia["chaplain insignia (taoism)"] = /obj/item/clothing/insignia/taoism + gear_tweaks += new/datum/gear_tweak/path(insignia) diff --git a/maps/exodus/exodus_overmap.dm b/maps/exodus/exodus_overmap.dm new file mode 100644 index 000000000000..2c54ec7835bd --- /dev/null +++ b/maps/exodus/exodus_overmap.dm @@ -0,0 +1,64 @@ +/obj/effect/overmap/visitable/ship/exodus + name = "Exodus Station" + color = "#00ffff" + start_x = 4 + start_y = 4 + sector_flags = OVERMAP_SECTOR_KNOWN|OVERMAP_SECTOR_BASE|OVERMAP_SECTOR_IN_SPACE + vessel_mass = 50000 + max_speed = 1/(20 SECONDS) + burn_delay = 20 SECONDS + initial_generic_waypoints = list( + "nav_exodus_port_upper", + "nav_exodus_fore_upper", + "nav_exodus_aft_upper", + "nav_exodus_starboard_lower", + "nav_exodus_port_lower", + "nav_exodus_fore_lower", + "nav_exodus_aft_lower", + "nav_exodus_engineering_pod_dock", + "nav_exodus_mining_pod_dock", + "nav_exodus_research_pod_dock" + ) + +/obj/effect/overmap/visitable/ship/landable/pod + name = "Generic Pod" + desc = "A single-seater short-range pod." + max_speed = 1/(2 SECONDS) + burn_delay = 1 SECONDS + vessel_mass = 4000 + fore_dir = NORTH + skill_needed = SKILL_BASIC + vessel_size = SHIP_SIZE_SMALL + +// Overmap transit landmarks +/obj/effect/shuttle_landmark/exodus_main_starboard + name = "Exodus starboard approach" + landmark_tag = "nav_exodus_starboard_upper" + +/obj/effect/shuttle_landmark/exodus_main_port + name = "Exodus port approach" + landmark_tag = "nav_exodus_port_upper" + +/obj/effect/shuttle_landmark/exodus_main_fore + name = "Exodus fore approach" + landmark_tag = "nav_exodus_fore_upper" + +/obj/effect/shuttle_landmark/exodus_main_aft + name = "Exodus aft approach" + landmark_tag = "nav_exodus_aft_upper" + +/obj/effect/shuttle_landmark/exodus_sub_starboard + name = "Exodus starboard underside" + landmark_tag = "nav_exodus_starboard_lower" + +/obj/effect/shuttle_landmark/exodus_sub_port + name = "Exodus port underside" + landmark_tag = "nav_exodus_port_lower" + +/obj/effect/shuttle_landmark/exodus_sub_fore + name = "Exodus fore underside" + landmark_tag = "nav_exodus_fore_lower" + +/obj/effect/shuttle_landmark/exodus_sub_aft + name = "Exodus aft underside" + landmark_tag = "nav_exodus_aft_lower" diff --git a/maps/exodus/exodus_setup.dm b/maps/exodus/exodus_setup.dm new file mode 100644 index 000000000000..19bb80bf3a2a --- /dev/null +++ b/maps/exodus/exodus_setup.dm @@ -0,0 +1,45 @@ +/datum/map/exodus/send_welcome() + var/obj/effect/overmap/visitable/ship/exodus = SSshuttle.ship_by_type(/obj/effect/overmap/visitable/ship/exodus) + + var/welcome_text = "
    [global.using_map.station_name] Sensor Readings:
    " + welcome_text += "Report generated on [stationdate2text()] at [stationtime2text()]


    " + welcome_text += "
    Current system:
    [global.using_map.system_name || "Unknown"]

    " + + if(exodus) //If the overmap is disabled, it's possible for there to be no exodus. + var/list/space_things = list() + welcome_text += "Current Coordinates:
    [exodus.x]:[exodus.y]

    " + welcome_text += "Next system targeted for jump:
    [generate_system_name()]

    " + welcome_text += "Travel time to [company_name]:
    [rand(15,45)] days

    " + welcome_text += "Time since last port visit:
    [rand(60,180)] days

    " + welcome_text += "Scan results show the following points of interest:
    " + + for(var/zlevel, sector in global.overmap_sectors) + var/obj/effect/overmap/visitable/O = sector + if(O.name == exodus.name) + continue + if(istype(O, /obj/effect/overmap/visitable/ship/landable)) //Don't show shuttles + continue + if (O.hide_from_reports) + continue + space_things |= O + + var/list/distress_calls + for(var/obj/effect/overmap/visitable/O in space_things) + var/location_desc = " at present co-ordinates." + if(O.loc != exodus.loc) + var/bearing = round(90 - Atan2(O.x - exodus.x, O.y - exodus.y),5) //fucking triangles how do they work + if(bearing < 0) + bearing += 360 + location_desc = ", bearing [bearing]." + if(O.has_distress_beacon) + LAZYADD(distress_calls, "[O.has_distress_beacon][location_desc]") + welcome_text += "
  • \A [O.name][location_desc]
  • " + + if(LAZYLEN(distress_calls)) + welcome_text += "
    Distress calls logged:
    [jointext(distress_calls, "
    ")]
    " + else + welcome_text += "
    No distress calls logged.
    " + welcome_text += "
    " + + post_comm_message("[global.using_map.station_short] Sensor Readings", welcome_text) + minor_announcement.Announce(message = "New [global.using_map.station_short] Update available at all communication consoles.") diff --git a/maps/exodus/exodus_shuttles.dm b/maps/exodus/exodus_shuttles.dm new file mode 100644 index 000000000000..c7abc4523d25 --- /dev/null +++ b/maps/exodus/exodus_shuttles.dm @@ -0,0 +1,125 @@ +#define ESCAPE_POD(NUMBER) \ +/datum/shuttle/autodock/ferry/escape_pod/pod##NUMBER { \ + shuttle_area = /area/shuttle/escape_pod_##NUMBER; \ + name = "Escape Pod " + #NUMBER; \ + dock_target = "escape_pod_" + #NUMBER; \ + arming_controller = "escape_pod_"+ #NUMBER +"_berth"; \ + waypoint_station = "escape_pod_"+ #NUMBER +"_start"; \ + landmark_transition = "escape_pod_"+ #NUMBER +"_transit"; \ + waypoint_offsite = "escape_pod_"+ #NUMBER +"_out"; \ +} \ +/obj/effect/shuttle_landmark/escape_pod/start/pod##NUMBER { \ + landmark_tag = "escape_pod_"+ #NUMBER +"_start"; \ + docking_controller = "escape_pod_"+ #NUMBER +"_berth"; \ +} \ +/obj/effect/shuttle_landmark/escape_pod/transit/pod##NUMBER { \ + landmark_tag = "escape_pod_"+ #NUMBER +"_transit"; \ +} \ +/obj/effect/shuttle_landmark/escape_pod/out/pod##NUMBER { \ + landmark_tag = "escape_pod_"+ #NUMBER +"_out"; \ +} \ +/area/shuttle/escape_pod_##NUMBER { \ + name = "Escape Pod " + #NUMBER; \ + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED | AREA_FLAG_NO_LEGACY_PERSISTENCE; \ +} + +ESCAPE_POD(1) +ESCAPE_POD(2) +ESCAPE_POD(3) +ESCAPE_POD(4) + +/obj/machinery/computer/shuttle_control/explore/research + name = "research pod control console" + shuttle_tag = "Research Pod" +/datum/shuttle/autodock/overmap/research + name = "Research Pod" + shuttle_area = /area/ship/exodus_pod_research + dock_target = "research_shuttle" + current_location = "nav_exodus_research_pod_dock" +/area/ship/exodus_pod_research + name = "Research Pod" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED | AREA_FLAG_NO_LEGACY_PERSISTENCE +/obj/effect/overmap/visitable/ship/landable/pod/research + name = "Exodus Research Pod" + shuttle = "Research Pod" +/obj/effect/shuttle_landmark/research_pod_dock + name = "Research Docking Port" + landmark_tag = "nav_exodus_research_pod_dock" + docking_controller = "research_dock_airlock" + +/obj/machinery/computer/shuttle_control/explore/mining + name = "mining pod control console" + shuttle_tag = "Mining Pod" +/datum/shuttle/autodock/overmap/mining + name = "Mining Pod" + shuttle_area = /area/ship/exodus_pod_mining + dock_target = "mining_shuttle" + current_location = "nav_exodus_mining_pod_dock" +/area/ship/exodus_pod_mining + name = "Mining Pod" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED | AREA_FLAG_NO_LEGACY_PERSISTENCE +/obj/effect/overmap/visitable/ship/landable/pod/mining + name = "Exodus Mining Pod" + shuttle = "Mining Pod" +/obj/effect/shuttle_landmark/mining_pod_dock + name = "Mining Docking Port" + landmark_tag = "nav_exodus_mining_pod_dock" + docking_controller = "mining_dock_airlock" + +/obj/machinery/computer/shuttle_control/explore/engineering + name = "engineering pod control console" + shuttle_tag = "Engineering Pod" +/datum/shuttle/autodock/overmap/engineering + name = "Engineering Pod" + shuttle_area = /area/ship/exodus_pod_engineering + dock_target = "engineering_shuttle" + current_location = "nav_exodus_engineering_pod_dock" +/area/ship/exodus_pod_engineering + name = "Engineering Pod" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED | AREA_FLAG_NO_LEGACY_PERSISTENCE +/obj/effect/overmap/visitable/ship/landable/pod/engineering + name = "Exodus Engineering Pod" + shuttle = "Engineering Pod" +/obj/effect/shuttle_landmark/engineering_pod_dock + name = "Engineering Docking Port" + landmark_tag = "nav_exodus_engineering_pod_dock" + docking_controller = "engineering_dock_airlock" + +/datum/shuttle/autodock/ferry/emergency/escape_shuttle + name = "Escape Shuttle" + warmup_time = 10 + location = 1 + dock_target = "escape_shuttle" + shuttle_area = /area/shuttle/escape_shuttle + waypoint_offsite = "nav_escape_shuttle_start" + waypoint_station = "nav_escape_shuttle_station" + landmark_transition = "nav_escape_shuttle_transit" + +/obj/effect/shuttle_landmark/escape_shuttle/start + landmark_tag = "nav_escape_shuttle_start" + docking_controller = "centcom_escape_dock" + +/obj/effect/shuttle_landmark/escape_shuttle/transit + landmark_tag = "nav_escape_shuttle_transit" + +/obj/effect/shuttle_landmark/escape_shuttle/station + landmark_tag = "nav_escape_shuttle_station" + docking_controller = "escape_dock" + +/datum/shuttle/autodock/ferry/supply/cargo + name = "Supply Shuttle" + warmup_time = 10 + location = 1 + dock_target = "supply_shuttle" + shuttle_area = /area/shuttle/supply_shuttle + waypoint_offsite = "nav_cargo_start" + waypoint_station = "nav_cargo_station" + +/obj/effect/shuttle_landmark/supply/start + landmark_tag = "nav_cargo_start" + docking_controller = "cargo_bay_centcom" + +/obj/effect/shuttle_landmark/supply/station + landmark_tag = "nav_cargo_station" + docking_controller = "cargo_bay" + diff --git a/maps/exodus/exodus_unit_testing.dm b/maps/exodus/exodus_unit_testing.dm new file mode 100644 index 000000000000..adb24152b2c7 --- /dev/null +++ b/maps/exodus/exodus_unit_testing.dm @@ -0,0 +1,55 @@ +/datum/map/exodus + // Unit test exemptions + apc_test_exempt_areas = list( + /area/space = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exodus/construction = NO_SCRUBBER|NO_VENT, + /area/exodus/engineering/atmos/storage = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/arrivals = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/atmos_control = 0, + /area/exodus/maintenance/auxsolarport = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/auxsolarstarboard = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/dormitory = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/engi_shuttle = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/evahallway = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/exterior = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exodus/maintenance/medbay = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/incinerator = NO_SCRUBBER, + /area/exodus/maintenance/foresolar = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/portsolar = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/research_port = 0, + /area/exodus/maintenance/research_starboard = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/starboardsolar = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/sub/aft = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/sub/fore = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/sub/port = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/sub/starboard = NO_SCRUBBER|NO_VENT, + /area/exodus/maintenance/sub/relay_station = 0, + /area/exodus/maintenance/sub/command = 0, + /area/exodus/maintenance/substation/command = 0, + /area/exodus/maintenance/telecomms = 0, + /area/exodus/medical/genetics = NO_APC, + /area/exodus/medical/genetics/cloning = NO_APC, + /area/exodus/research/test_area = NO_SCRUBBER|NO_VENT, + /area/exodus/research/server = 0, + /area/shuttle = NO_SCRUBBER|NO_VENT|NO_APC, + /area/turbolift = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exodus/solar = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exodus/storage/emergency = NO_SCRUBBER|NO_VENT, + /area/exodus/storage/emergency2 = NO_SCRUBBER|NO_VENT, + /area/ship/exodus_pod_engineering = NO_SCRUBBER|NO_VENT, + /area/ship/exodus_pod_mining = NO_SCRUBBER|NO_VENT, + /area/ship/exodus_pod_research = NO_SCRUBBER|NO_VENT + ) + + area_coherency_test_exempt_areas = list( + /area/space, + /area/exodus/maintenance/exterior) + + area_coherency_test_subarea_count = list( + /area/exodus/engineering/atmos = 4, + /area/exodus/maintenance/incinerator = 2) + +/obj/abstract/map_data/exodus + height = 2 diff --git a/maps/exodus/lobby/exodus.png b/maps/exodus/lobby/exodus.png new file mode 100644 index 000000000000..c4181f9e39b5 Binary files /dev/null and b/maps/exodus/lobby/exodus.png differ diff --git a/maps/ministation/bin.dmi b/maps/ministation/bin.dmi new file mode 100644 index 000000000000..eb69503cbed4 Binary files /dev/null and b/maps/ministation/bin.dmi differ diff --git a/maps/ministation/hud.dmi b/maps/ministation/hud.dmi new file mode 100644 index 000000000000..8a3e91cf3a74 Binary files /dev/null and b/maps/ministation/hud.dmi differ diff --git a/maps/ministation/jobs/civilian.dm b/maps/ministation/jobs/civilian.dm new file mode 100644 index 000000000000..18024cc23791 --- /dev/null +++ b/maps/ministation/jobs/civilian.dm @@ -0,0 +1,99 @@ +/datum/job/standard/assistant/ministation + title = "Recruit" + supervisors = "absolutely everyone" + alt_titles = list("Technical Recruit","Medical Recruit","Research Recruit","Visitor") + outfit_type = /decl/outfit/job/ministation_assistant + event_categories = list(ASSIGNMENT_GARDENER) + +/decl/outfit/job/ministation_assistant + name = "Job - Ministation Assistant" + +/datum/job/standard/bartender/ministation + title = "Bartender" + alt_titles = list("Cook","Barista") + supervisors = "the Lieutenant and the Captain" + total_positions = 2 + spawn_positions = 1 + outfit_type = /decl/outfit/job/ministation/bartender + department_types = list(/decl/department/service) + selection_color = "#3fbe4a" + economic_power = 5 + min_skill = list( + SKILL_COOKING = SKILL_ADEPT, + SKILL_BOTANY = SKILL_BASIC, + SKILL_CHEMISTRY = SKILL_BASIC + ) + max_skill = list( + SKILL_COOKING = SKILL_MAX, + SKILL_BOTANY = SKILL_MAX + ) + skill_points = 30 + +/datum/job/standard/cargo_tech/ministation + title = "Cargo Technician" + alt_titles = list("Shaft Miner","Drill Technician","Prospector") + supervisors = "the Lieutenant and the Captain" + total_positions = 3 + spawn_positions = 1 + outfit_type = /decl/outfit/job/ministation/cargo + selection_color = "#8a7c00" + economic_power = 5 + access = list( + access_cargo, + access_cargo_bot, + access_mining, + access_mailsorting, + access_mining, + access_mining_station, + access_external_airlocks, + access_eva + ) + minimal_access = list( + access_cargo, + access_cargo_bot, + access_mining, + access_mailsorting, + access_eva, + access_mining, + access_mining_station, + access_external_airlocks + ) + min_skill = list( + SKILL_FINANCE = SKILL_BASIC, + SKILL_HAULING = SKILL_ADEPT, + SKILL_EVA = SKILL_BASIC, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_LITERACY = SKILL_BASIC + ) + max_skill = list( + SKILL_HAULING = SKILL_MAX, + SKILL_EVA = SKILL_MAX, + SKILL_FINANCE = SKILL_MAX + ) + skill_points = 30 + +/datum/job/standard/janitor/ministation + total_positions = 2 + supervisors = "the Lieutenant and the Captain" + economic_power = 3 + selection_color = "#940088" + outfit_type = /decl/outfit/job/ministation/janitor + min_skill = list( + SKILL_HAULING = SKILL_BASIC + ) + skill_points = 28 + +/datum/job/standard/librarian/ministation + spawn_positions = 2 + supervisors = "the Lieutenant, the Captain, and the smell of old paper" + economic_power = 5 + selection_color = "#008800" + access = list(access_library) + alt_titles = list( + "Curator", + "Archivist" + ) + outfit_type = /decl/outfit/job/ministation/librarian + min_skill = list( + SKILL_LITERACY = SKILL_AVERAGE + ) diff --git a/maps/ministation/jobs/command.dm b/maps/ministation/jobs/command.dm new file mode 100644 index 000000000000..1a27ff0736d1 --- /dev/null +++ b/maps/ministation/jobs/command.dm @@ -0,0 +1,53 @@ +/datum/job/standard/captain/ministation + supervisors = "your profit margin, your conscience, and the watchful eye of the Tradehouse Rep" + outfit_type = /decl/outfit/job/ministation/captain + hud_icon = 'maps/ministation/hud.dmi' + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_WEAPONS = SKILL_ADEPT, + SKILL_SCIENCE = SKILL_ADEPT, + SKILL_PILOT = SKILL_ADEPT + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX + ) + skill_points = 40 + +/datum/job/standard/captain/ministation/equip_job(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) + . = ..() + if(H) + H.verbs |= /mob/proc/freetradeunion_rename_company + +/mob/proc/freetradeunion_rename_company() + set name = "Defect from Tradehouse" + set category = "Captain's Powers" + var/company = sanitize(input(src, "What should your enterprise be called?", "Company name", global.using_map.company_name), MAX_NAME_LEN) + if(!company) + return + var/company_s = sanitize(input(src, "What's the short name for it?", "Company name", global.using_map.company_short), MAX_NAME_LEN) + if(company != global.using_map.company_name) + if (company) + global.using_map.company_name = company + if(company_s) + global.using_map.company_short = company_s + command_announcement.Announce("Congratulations to all members of [capitalize(global.using_map.company_name)] on the new name. Their rebranding has changed the [global.using_map.company_short] market value by [0.01*rand(-10,10)]%.", "Trade Union Name Change") + verbs -= /mob/proc/freetradeunion_rename_company + +/datum/job/standard/hop/ministation + title = "Lieutenant" + outfit_type = /decl/outfit/job/ministation/hop + hud_icon = 'maps/ministation/hud.dmi' + hud_icon_state = "hudlieutenant" + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_WEAPONS = SKILL_BASIC, + SKILL_FINANCE = SKILL_EXPERT, + SKILL_PILOT = SKILL_ADEPT + ) + max_skill = list( + SKILL_LITERACY = SKILL_MAX, + SKILL_PILOT = SKILL_MAX, + SKILL_FINANCE = SKILL_MAX + ) + skill_points = 40 diff --git a/maps/ministation/jobs/engineering.dm b/maps/ministation/jobs/engineering.dm new file mode 100644 index 000000000000..a3cb57fbc0a9 --- /dev/null +++ b/maps/ministation/jobs/engineering.dm @@ -0,0 +1,87 @@ +/datum/job/standard/engineer/ministation + title = "Station Engineer" + supervisors = "the Head Engineer" + total_positions = 2 + spawn_positions = 2 + outfit_type = /decl/outfit/job/ministation/engineer + minimal_player_age = 3 + access = list( + access_eva, + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_external_airlocks, + access_construction, + access_atmospherics, + access_emergency_storage, + access_cameras + ) + minimal_access = list( + access_eva, + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_external_airlocks, + access_construction, + access_atmospherics, + access_emergency_storage, + access_cameras + ) + skill_points = 30 + alt_titles = list("Atmospheric Technician", "Electrician", "Maintenance Technician") + +/datum/job/standard/chief_engineer/ministation + title = "Head Engineer" + access = list( + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_heads, + access_teleporter, + access_external_airlocks, + access_atmospherics, + access_emergency_storage, + access_eva, + access_bridge, + access_construction, access_sec_doors, + access_ce, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_mining, + access_kitchen, + access_robotics, + access_hydroponics, + access_ai_upload, + access_cameras + ) + minimal_access = list( + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_heads, + access_teleporter, + access_external_airlocks, + access_atmospherics, + access_emergency_storage, + access_eva, + access_bridge, + access_construction, + access_sec_doors, + access_ce, access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_mining, + access_kitchen, + access_robotics, + access_hydroponics, + access_ai_upload, + access_cameras + ) + outfit_type = /decl/outfit/job/ministation/chief_engineer + skill_points = 40 + alt_titles = list("Chief of Engineering") diff --git a/maps/ministation/jobs/medical.dm b/maps/ministation/jobs/medical.dm new file mode 100644 index 000000000000..1dd568c8176e --- /dev/null +++ b/maps/ministation/jobs/medical.dm @@ -0,0 +1,95 @@ +/datum/job/standard/doctor/ministation + title = "Medical Doctor" + supervisors = "the Head Doctor" + total_positions = 2 + spawn_positions = 2 + alt_titles = list("Chemist", "Nurse", "Surgeon") + skill_points = 34 + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_EXPERT, + SKILL_ANATOMY = SKILL_EXPERT, + SKILL_CHEMISTRY = SKILL_BASIC + ) + max_skill = list( + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX, + SKILL_CHEMISTRY = SKILL_MAX + ) + access = list( + access_medical, + access_medical_equip, + access_morgue, + access_surgery, + access_chemistry, + access_virology, + access_cameras + ) + minimal_access = list( + access_medical, + access_medical_equip, + access_morgue, + access_surgery, + access_virology, + access_cameras + ) + outfit_type = /decl/outfit/job/ministation/doctor + +/datum/job/standard/cmo/ministation + title = "Head Doctor" + supervisors = "the Captain and your own ethics" + outfit_type = /decl/outfit/job/ministation/doctor/head + alt_titles = list("Chief Medical Officer", "Head Surgeon") + skill_points = 38 + access = list( + access_medical, + access_medical_equip, + access_morgue, + access_bridge, + access_heads, + access_engine_equip, + access_eva, + access_chemistry, + access_virology, + access_cmo, + access_surgery, + access_RC_announce, + access_keycard_auth, + access_sec_doors, + access_psychiatrist, + access_eva, + access_mining, + access_kitchen, + access_xenobiology, + access_robotics, + access_hydroponics, + access_maint_tunnels, + access_external_airlocks, + access_cameras + ) + minimal_access = list( + access_medical, + access_medical_equip, + access_morgue, + access_bridge, + access_heads, + access_engine_equip, + access_eva, + access_chemistry, + access_virology, + access_cmo, + access_surgery, + access_RC_announce, + access_keycard_auth, + access_sec_doors, + access_psychiatrist, + access_eva, + access_mining, + access_kitchen, + access_xenobiology, + access_robotics, + access_hydroponics, + access_maint_tunnels, + access_external_airlocks, + access_cameras + ) diff --git a/maps/ministation/jobs/science.dm b/maps/ministation/jobs/science.dm new file mode 100644 index 000000000000..7b8e61e4591d --- /dev/null +++ b/maps/ministation/jobs/science.dm @@ -0,0 +1,82 @@ +/datum/job/standard/scientist/ministation + title = "Researcher" + alt_titles = list("Scientist","Xenobiologist","Roboticist","Xenobotanist") + supervisors = "the Head Researcher" + spawn_positions = 1 + total_positions = 2 + outfit_type = /decl/outfit/job/ministation/scientist + skill_points = 34 + +/datum/job/standard/rd/ministation + title = "Research Director" + alt_titles = list("Head Researcher", "Chief Researcher") + outfit_type = /decl/outfit/job/ministation/scientist/head + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_FINANCE = SKILL_ADEPT, + SKILL_BOTANY = SKILL_BASIC, + SKILL_ANATOMY = SKILL_BASIC, + SKILL_DEVICES = SKILL_BASIC, + SKILL_SCIENCE = SKILL_ADEPT + ) + max_skill = list( + SKILL_ANATOMY = SKILL_MAX, + SKILL_DEVICES = SKILL_MAX, + SKILL_SCIENCE = SKILL_MAX + ) + skill_points = 40 + access = list( + access_rd, + access_bridge, + access_tox, + access_morgue, + access_tox_storage, + access_teleporter, + access_sec_doors, + access_heads, + access_eva, + access_research, + access_robotics, + access_xenobiology, + access_ai_upload, + access_tech_storage, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_gateway, + access_xenoarch, + access_engine_equip, + access_mining, + access_kitchen, + access_hydroponics, + access_network, + access_cameras + ) + minimal_access = list( + access_rd, + access_bridge, + access_tox, + access_morgue, + access_tox_storage, + access_teleporter, + access_sec_doors, + access_heads, + access_eva, + access_research, + access_robotics, + access_xenobiology, + access_ai_upload, + access_tech_storage, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_gateway, + access_xenoarch, + access_engine_equip, + access_mining, + access_kitchen, + access_hydroponics, + access_network, + access_cameras + ) diff --git a/maps/ministation/jobs/security.dm b/maps/ministation/jobs/security.dm new file mode 100644 index 000000000000..242c665e7f31 --- /dev/null +++ b/maps/ministation/jobs/security.dm @@ -0,0 +1,103 @@ +/datum/job/standard/officer/ministation + title = "Security Officer" + alt_titles = list("Warden") + spawn_positions = 1 + total_positions = 2 + outfit_type = /decl/outfit/job/ministation/security + economic_power = 7 + access = list( + access_security, + access_brig, + access_lawyer, + access_maint_tunnels, + access_cameras + ) + minimal_access = list( + access_security, + access_forensics_lockers, + access_maint_tunnels, + access_lawyer, + access_brig, + access_cameras + ) + skill_points = 30 + +/datum/job/standard/detective/ministation + alt_titles = list("Inspector") + supervisors = "Justice... and the Trademaster" + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/ministation/detective + economic_power = 7 + minimal_player_age = 3 + access = list( + access_forensics_lockers, + access_brig, + access_security, + access_lawyer, + access_maint_tunnels, + access_cameras + ) + minimal_access = list( + access_security, + access_brig, + access_lawyer, + access_forensics_lockers, + access_maint_tunnels, + access_cameras + ) + min_skill = list( + SKILL_LITERACY = SKILL_BASIC, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_COMBAT = SKILL_BASIC, + SKILL_WEAPONS = SKILL_BASIC, + SKILL_FORENSICS = SKILL_ADEPT + ) + skill_points = 34 + +/datum/job/standard/hos/ministation + outfit_type = /decl/outfit/job/ministation/security/head + access = list( + access_security, + access_sec_doors, + access_brig, + access_eva, + access_forensics_lockers, + access_heads, + access_lawyer, + access_maint_tunnels, + access_armory, + access_engine_equip, + access_mining, + access_kitchen, + access_robotics, + access_hydroponics, + access_hos, + access_cameras + ) + minimal_access = list( + access_security, + access_sec_doors, + access_brig, + access_lawyer, + access_eva, + access_forensics_lockers, + access_heads, + access_maint_tunnels, + access_armory, + access_engine_equip, + access_mining, + access_kitchen, + access_robotics, + access_hydroponics, + access_hos, + access_cameras + ) + min_skill = list( + SKILL_LITERACY = SKILL_BASIC, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_COMBAT = SKILL_ADEPT, + SKILL_WEAPONS = SKILL_ADEPT + ) + skill_points = 40 + alt_titles = list("Security Commander") diff --git a/maps/ministation/jobs/tradehouse.dm b/maps/ministation/jobs/tradehouse.dm new file mode 100644 index 000000000000..daa715dddd5b --- /dev/null +++ b/maps/ministation/jobs/tradehouse.dm @@ -0,0 +1,99 @@ +/datum/job/tradehouse_rep + title = "Tradehouse Representative" + alt_titles = list("Narc") + hud_icon_state = "hudnarc" + hud_icon = 'maps/ministation/hud.dmi' + spawn_positions = 1 + total_positions = 2 + req_admin_notify = 1 + guestbanned = 1 + supervisors = "the Trademaster" + outfit_type = /decl/outfit/job/ministation/tradehouse + min_skill = list( + SKILL_WEAPONS = SKILL_BASIC, + SKILL_FINANCE = SKILL_EXPERT, + SKILL_LITERACY = SKILL_ADEPT, + SKILL_PILOT = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_ADEPT + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX, + SKILL_FINANCE = SKILL_MAX, + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_EXPERT + ) + skill_points = 35 + department_types = list(/decl/department/tradehouse) + selection_color = "#a89004" + access = list( + access_lawyer, + access_security, + access_sec_doors, + access_brig, + access_heads, + access_medical, + access_engine, + access_atmospherics, + access_ai_upload, + access_eva, + access_bridge, + access_all_personal_lockers, + access_maint_tunnels, + access_bar, + access_janitor, + access_construction, + access_morgue, + access_crematorium, + access_kitchen, + access_cargo, + access_cargo_bot, + access_qm, + access_hydroponics, + access_lawyer, + access_chapel_office, + access_library, + access_research, + access_mining, + access_heads_vault, + access_mining_station, + access_hop, + access_RC_announce, + access_keycard_auth, + access_gateway, + access_cameras + ) + + minimal_access = list( + access_lawyer, + access_security, + access_sec_doors, + access_brig, + access_medical, + access_heads, + access_engine, + access_atmospherics, + access_ai_upload, + access_eva, + access_bridge, + access_maint_tunnels, + access_bar, + access_janitor, + access_construction, + access_morgue, + access_crematorium, + access_kitchen, + access_cargo, + access_cargo_bot, + access_hydroponics, + access_chapel_office, + access_library, + access_research, + access_mining, + access_heads_vault, + access_mining_station, + access_hop, + access_RC_announce, + access_keycard_auth, + access_gateway, + access_cameras + ) \ No newline at end of file diff --git a/maps/ministation/ministation-0.dmm b/maps/ministation/ministation-0.dmm new file mode 100644 index 000000000000..45af5c6f8e6b --- /dev/null +++ b/maps/ministation/ministation-0.dmm @@ -0,0 +1,79603 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/space, +/area/space) +"ac" = ( +/turf/wall, +/area/space) +"ad" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"ae" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/camera/network/engineering{ + name = "SM Airlock" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"af" = ( +/turf/wall/natural/random/ministation, +/area/space) +"ai" = ( +/obj/structure/table/laminate, +/turf/floor/pool, +/area/ministation/dorms) +"ak" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"al" = ( +/obj/machinery/network/relay, +/turf/floor/plating, +/area/ministation/engine) +"am" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"aq" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/window/brigdoor/westleft, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/obj/machinery/door/blast/shutters{ + id_tag = "cargoshut"; + name = "cargo shutters" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"as" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/flora/pottedplant/smalltree, +/turf/floor/tiled, +/area/ministation/hall/n) +"au" = ( +/turf/wall, +/area/ministation/cargo) +"av" = ( +/turf/wall/r_wall, +/area/ministation/engine) +"aw" = ( +/turf/wall, +/area/ministation/mining) +"ax" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"ay" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"aA" = ( +/obj/structure/railing/mapped, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"aG" = ( +/obj/structure/table, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/obj/item/blueprints, +/obj/item/cell, +/turf/floor/tiled, +/area/ministation/eva) +"aJ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"aK" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"aL" = ( +/obj/machinery/apc{ + name = "_South APC"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/dorms) +"aM" = ( +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"aS" = ( +/turf/wall, +/area/ministation/ai_sat) +"aV" = ( +/turf/floor/tiled, +/area/ministation/hall/s1) +"aW" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/closet/secure_closet{ + closet_appearance = /decl/closet_appearance/secure_closet/command; + name = "captain's locker"; + req_access = list("ACCESS_CAPTAIN") + }, +/obj/machinery/camera/network/command{ + initial_access = null + }, +/turf/floor/tiled, +/area/ministation/eva) +"aZ" = ( +/obj/structure/fitness/punchingbag, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"bb" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/fabricator/pipe/disposal, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"bc" = ( +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"bd" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/item/inflatable_dispenser, +/obj/structure/table, +/obj/item/suit_cooling_unit, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"bg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"bh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"bi" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/turf/floor/carpet/green, +/area/ministation/dorms) +"bj" = ( +/obj/structure/table/reinforced, +/obj/item/rcd, +/obj/item/rcd_ammo/large, +/obj/item/gun/launcher/sealant, +/turf/floor/carpet/orange, +/area/ministation/engine) +"bk" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/engine) +"bl" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "westatmos_vent" + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"bm" = ( +/obj/structure/closet/radiation, +/obj/machinery/camera/network/engineering, +/turf/floor/tiled, +/area/ministation/engine) +"bp" = ( +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"bt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"bB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/engine) +"bC" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/door/airlock/glass/command, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/eva) +"bE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"bN" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 8; + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/turf/floor/reinforced/oxygen, +/area/ministation/atmospherics) +"bO" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 4; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; + internal_pressure_bound_default = 2000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/oxygen, +/area/ministation/atmospherics) +"bP" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/eva) +"bR" = ( +/obj/machinery/disposal/deliveryChute{ + dir = 1; + name = "disposals ejection chute" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"bV" = ( +/obj/structure/table, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/item/chems/spray/extinguisher, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/eva) +"bW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/eva) +"bX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/cargo) +"bY" = ( +/obj/effect/floor_decal/corner/black{ + dir = 9 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"cb" = ( +/obj/item/stack/material/ore/iron{ + pixel_x = -1; + pixel_y = -4 + }, +/obj/item/stack/material/ore/iron{ + pixel_x = 2; + pixel_y = 4 + }, +/obj/item/stack/material/ore/iron, +/turf/floor/plating/airless, +/area/space) +"cc" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/material_processing/unloader{ + input_turf = 4; + output_turf = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cd" = ( +/obj/item/stack/material/rods/mapped/steel/fifty, +/turf/floor/plating/airless, +/area/space) +"ce" = ( +/obj/item/ore_satchel, +/turf/floor/plating/airless, +/area/space) +"cf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cg" = ( +/obj/structure/chair/comfy, +/turf/floor/carpet/blue2, +/area/ministation/hall/s1) +"cj" = ( +/obj/machinery/generator{ + anchored = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"ck" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/space) +"cl" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cm" = ( +/obj/structure/ore_box, +/turf/floor/plating/airless, +/area/space) +"cn" = ( +/turf/floor/plating/airless, +/area/space) +"cp" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/engine) +"cr" = ( +/turf/wall/r_wall, +/area/ministation/eva) +"cu" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/computer/modular/preset/engineering, +/turf/floor/laminate/yew, +/area/ministation/engine) +"cv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/engine) +"cw" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"cx" = ( +/obj/machinery/conveyor{ + id_tag = "mining_internal" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cy" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/cargo) +"cz" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cA" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "mining_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "mining_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = -10; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/cargo) +"cB" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/turf/floor/reinforced/carbon_dioxide, +/area/ministation/atmospherics) +"cD" = ( +/turf/floor, +/area/ministation/hall/s1) +"cG" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 4; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; + internal_pressure_bound_default = 2000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/nitrogen, +/area/ministation/atmospherics) +"cH" = ( +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "16-0" + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"cK" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/ai_sat) +"cL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"cM" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "mining_internal" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cN" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"cO" = ( +/obj/machinery/material_processing/smeltery, +/turf/floor/tiled, +/area/ministation/cargo) +"cP" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/conveyor{ + dir = 4; + id_tag = "mining_internal" + }, +/obj/machinery/camera/network/mining, +/turf/floor/tiled, +/area/ministation/cargo) +"cQ" = ( +/obj/machinery/material_processing/stacker, +/turf/floor/tiled, +/area/ministation/cargo) +"cR" = ( +/obj/structure/closet, +/obj/item/bikehorn/airhorn, +/obj/item/grenade/chem_grenade/water, +/turf/floor, +/area/ministation/maint/eastatmos) +"cS" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "mining_vent" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/cargo) +"cT" = ( +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"cX" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1; + dir = 1 + }, +/turf/floor/reinforced/hydrogen, +/area/ministation/atmospherics) +"dc" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"de" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "mining_internal" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"df" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"di" = ( +/turf/wall, +/area/ministation/hall/n) +"dl" = ( +/obj/machinery/power/solar, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/space) +"do" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "trash_sort" + }, +/obj/structure/sign/warning/deathsposal{ + pixel_x = -30; + dir = 4 + }, +/obj/structure/flaps/airtight, +/turf/floor/plating, +/area/ministation/trash) +"dp" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 4; + external_pressure_bound = 140; + external_pressure_bound_default = 140; + icon_state = "map_vent_out"; + use_power = 1 + }, +/turf/floor/plating/airless, +/area/ministation/atmospherics) +"dq" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"ds" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/turf/space, +/area/space) +"du" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"dw" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"dx" = ( +/obj/item/ball, +/turf/floor/pool, +/area/ministation/dorms) +"dB" = ( +/obj/machinery/conveyor{ + dir = 1; + id_tag = "mining_internal" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"dC" = ( +/obj/machinery/conveyor_switch/oneway{ + id_tag = "mining_internal"; + name = "mining conveyor" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"dD" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/plating, +/area/ministation/supermatter) +"dE" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/cargo) +"dF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"dG" = ( +/obj/machinery/conveyor{ + id_tag = "mining_internal" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"dH" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"dI" = ( +/turf/floor/tiled, +/area/ministation/cargo) +"dL" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 0; + id_tag = "sat1_airlock"; + pixel_y = 24; + tag_airpump = "sat1_vent"; + tag_chamber_sensor = "sat1_sensor"; + tag_exterior_door = "sat1_airlock_exterior"; + tag_interior_door = "sat1_airlock_interior" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "sat1_vent" + }, +/obj/machinery/airlock_sensor{ + id_tag = "sat1_sensor"; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"dM" = ( +/obj/structure/stairs/long/west, +/turf/floor/tiled, +/area/ministation/hall/n) +"dN" = ( +/obj/structure/closet, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/cloak, +/obj/item/clothing/suit/cloak, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"dR" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/eva) +"dU" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"dV" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"dX" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"dZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"eh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/turf/floor/tiled, +/area/ministation/janitor) +"ej" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/cargo) +"ek" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"el" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/cargo) +"en" = ( +/obj/machinery/camera/network/engineering{ + name = "Tube Entrance"; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"eo" = ( +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"es" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/dorms) +"et" = ( +/obj/structure/closet/secure_closet/miner, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"eu" = ( +/turf/wall, +/area/ministation/maint/l1ne) +"ev" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"ew" = ( +/obj/structure/closet/secure_closet/atmos_personal, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/jumpsuit/hazard, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 10 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ex" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"ez" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/trash) +"eB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/conveyor{ + dir = 4; + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"eC" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/ai_sat) +"eE" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 4; + id_tag = "cargo_bay"; + tag_airpump = "cargo_vent"; + tag_chamber_sensor = "cargo_sensor"; + tag_exterior_door = "cargo_airlock_exterior"; + tag_interior_door = "cargo_airlock_interior"; + pixel_x = -20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/cargo) +"eF" = ( +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/obj/item/stool/padded, +/turf/floor/tiled, +/area/ministation/cargo) +"eG" = ( +/obj/structure/tank_rack/oxygen, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"eI" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/plating, +/area/ministation/supermatter) +"eK" = ( +/turf/floor/plating, +/area/ministation/supermatter) +"eM" = ( +/obj/machinery/atm{ + pixel_y = 32 + }, +/obj/machinery/camera/network/hallway, +/turf/floor/tiled, +/area/ministation/hall/n) +"eO" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/junction, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"eR" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/white/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/obj/machinery/meter/turf, +/turf/floor/reinforced/airmix, +/area/ministation/atmospherics) +"eS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"eU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"eW" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/eva) +"eX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"eY" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/stack/material/ingot/mapped/osmium/forty, +/obj/item/stack/material/ingot/mapped/iron/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/ingot/mapped/chromium/fifty, +/obj/item/stack/material/ingot/mapped/brass/fifty, +/obj/item/stack/material/ingot/mapped/blackbronze/fifty, +/obj/item/stack/material/ingot/mapped/gold/fifty, +/obj/item/stack/material/ingot/mapped/platinum/twenty, +/obj/item/stack/material/ingot/mapped/silver/fifty, +/obj/item/stack/material/ingot/mapped/stainlesssteel/forty, +/obj/item/stack/material/ingot/mapped/tin/fifty, +/obj/item/stack/material/ingot/mapped/zinc/fifty, +/turf/floor/tiled, +/area/ministation/cargo) +"eZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"fa" = ( +/obj/structure/window/reinforced/tinted{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + level = 2 + }, +/obj/item/hemostat, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"fe" = ( +/turf/wall/r_wall, +/area/ministation/hall/s1) +"fg" = ( +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple/full, +/turf/floor/reinforced/hydrogen, +/area/ministation/atmospherics) +"fh" = ( +/obj/machinery/network/relay/wall_mounted{ + dir = 4 + }, +/turf/floor/carpet/orange, +/area/ministation/engine) +"fi" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/machinery/suit_cycler/mining/ministation, +/turf/floor/tiled, +/area/ministation/cargo) +"fj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/table, +/obj/item/destTagger{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/item/stack/package_wrap/twenty_five, +/turf/floor/tiled, +/area/ministation/cargo) +"fm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table, +/obj/item/hand_labeler, +/turf/floor/tiled, +/area/ministation/cargo) +"fn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/cargo) +"fo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fp" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fq" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/status_display/supply_display{ + pixel_y = -32; + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector{ + pixel_x = -3; + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled, +/area/ministation/cargo) +"fr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fs" = ( +/obj/structure/tank_rack/oxygen, +/turf/floor/plating, +/area/ministation/engine) +"ft" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/hologram/holopad, +/obj/item/radio/intercom/locked{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fu" = ( +/obj/machinery/door/airlock/glass/mining, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fv" = ( +/obj/effect/wallframe_spawn, +/obj/machinery/door/blast/shutters{ + id_tag = "cargoshut"; + name = "cargo shutters" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fw" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/hall/n) +"fx" = ( +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/n) +"fy" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s1) +"fz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/n) +"fA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark{ + name = "lightsout" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"fB" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fE" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"fF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fL" = ( +/obj/structure/rack, +/obj/item/tool/pickaxe, +/obj/item/tool/pickaxe{ + pixel_x = 5 + }, +/obj/item/tool/shovel{ + pixel_x = -5 + }, +/obj/item/tool/shovel{ + pixel_x = -5 + }, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/machinery/camera/network/mining{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fM" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/cargo) +"fO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/cargo) +"fP" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fQ" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fR" = ( +/obj/machinery/camera/network/mining{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fS" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/machinery/computer/modular/preset/merchant/ministation{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"fU" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/window/basic/full, +/turf/floor/plating, +/area/ministation/dorms) +"fV" = ( +/obj/item/radio/intercom{ + broadcasting = 1; + frequency = 1447; + listening = 0; + name = "Station Intercom (AI Private)"; + pixel_y = -30; + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"fW" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled, +/area/ministation/engine) +"fX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"fZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"ga" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/blood/oil, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"gb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/flora/pottedplant/minitree, +/turf/floor/tiled, +/area/ministation/hall/s1) +"gc" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ge" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"gg" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/conveyor{ + dir = 8; + id_tag = "trash_sort" + }, +/turf/floor/plating, +/area/ministation/trash) +"gi" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"gj" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/drill_brace, +/turf/floor/tiled, +/area/ministation/cargo) +"gk" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"gl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"gm" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"gn" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/space, +/area/space) +"go" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/displaycase, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/item/toy/prize/powerloader, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/cargo) +"gq" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/tiled, +/area/ministation/cargo) +"gr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"gs" = ( +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/structure/chair/office, +/turf/floor/tiled, +/area/ministation/cargo) +"gt" = ( +/obj/machinery/door/airlock/glass/mining, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/cargo) +"gu" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled, +/area/ministation/hall/n) +"gv" = ( +/obj/machinery/computer/modular/preset/supply_public{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"gw" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/obj/machinery/disposal, +/turf/floor/tiled, +/area/ministation/hall/n) +"gx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"gy" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"gD" = ( +/obj/machinery/port_gen/pacman/super, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/engine) +"gE" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 4; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; + internal_pressure_bound_default = 2000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/airmix, +/area/ministation/atmospherics) +"gF" = ( +/obj/structure/table/laminate, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/pool, +/area/ministation/dorms) +"gI" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "l1ne_vent" + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"gJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/n) +"gL" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/mining_drill, +/turf/floor/tiled, +/area/ministation/cargo) +"gM" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"gO" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/turf/floor/tiled, +/area/ministation/cargo) +"gP" = ( +/obj/effect/floor_decal/industrial/warning/fulltile, +/turf/floor/tiled, +/area/ministation/cargo) +"gQ" = ( +/turf/floor/tiled, +/area/ministation/hall/n) +"gR" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"gS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"gT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/n) +"gU" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"gV" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"gW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "stern_engineering_vent" + }, +/turf/floor/plating, +/area/ministation/engine) +"gX" = ( +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"gY" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/engine) +"gZ" = ( +/obj/machinery/computer/modular/preset/engineering{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/smcontrol) +"hb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"hc" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"hf" = ( +/turf/floor/plating, +/area/ministation/trash) +"hi" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"hk" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 6 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"hn" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"ho" = ( +/obj/machinery/atmospherics/portables_connector{ + pixel_x = -3 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled, +/area/ministation/cargo) +"hp" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"hq" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/light{ + icon_state = "tube1" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"ht" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hu" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/airlock/double/mining{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hv" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"hw" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/atmospherics) +"hA" = ( +/obj/effect/floor_decal/industrial/custodial{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/trash) +"hE" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"hK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/black{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"hP" = ( +/obj/structure/sign/warning/docking_area{ + pixel_y = 30 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_airlock_interior"; + name = "Cargo Docking Airlock"; + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/cargo) +"hQ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hS" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hT" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"hU" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"hV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"hY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"ia" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"ie" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_airlock_exterior"; + name = "Cargo Docking Airlock"; + autoset_access = 0 + }, +/turf/floor/plating, +/area/ministation/cargo) +"if" = ( +/obj/machinery/fabricator/pipe, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ij" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"il" = ( +/turf/wall/r_wall, +/area/ministation/supermatter) +"im" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"iq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"it" = ( +/obj/machinery/door/window/southleft, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup, +/turf/floor/tiled, +/area/ministation/engine) +"iu" = ( +/obj/machinery/vending/cola{ + dir = 4; + pixel_x = -5 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"ix" = ( +/obj/machinery/camera/network/ministation/sat, +/turf/floor/plating, +/area/ministation/ai_upload) +"iz" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"iB" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"iE" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"iM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"iN" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"iP" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/camera/autoname{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"iU" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"iV" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "cargo_vent" + }, +/turf/floor/plating, +/area/ministation/cargo) +"iW" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"jd" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + autoset_access = 0 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/trash) +"je" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"jf" = ( +/obj/machinery/atmospherics/binary/circulator{ + anchored = 1; + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"jh" = ( +/turf/wall, +/area/ministation/maint/l1central) +"jj" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"jn" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/black, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"jo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/n) +"jq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"ju" = ( +/obj/machinery/atmospherics/omni/mixer{ + active_power_usage = 7500; + tag_east_con = 0; + tag_north = 1; + tag_north_con = 0.21; + tag_south = 1; + tag_south_con = 0.79; + tag_west = 2 + }, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"jy" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/dorms) +"jz" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/closet/secure_closet{ + closet_appearance = /decl/closet_appearance/secure_closet/security; + req_access = list("ACCESS_BRIG"); + name = "Security locker" + }, +/obj/item/clothing/suit/space/void/security, +/obj/item/clothing/suit/space/void/security, +/obj/item/clothing/head/helmet/space/void/security, +/obj/item/clothing/head/helmet/space/void/security, +/turf/floor/tiled, +/area/ministation/eva) +"jA" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"jB" = ( +/obj/machinery/vending/games{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"jC" = ( +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/red{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"jF" = ( +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"jH" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"jI" = ( +/obj/structure/closet/secure_closet/cargotech, +/obj/item/clothing/suit/jacket/winter/cargo, +/obj/item/key/cargo_train, +/obj/item/clothing/suit/jacket/winter/cargo, +/turf/floor/tiled, +/area/ministation/cargo) +"jL" = ( +/obj/item/pen, +/turf/floor/tiled, +/area/ministation/eva) +"jM" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/reinforced/airmix, +/area/ministation/atmospherics) +"jO" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 9 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/table/gamblingtable, +/obj/item/paicard, +/turf/floor/carpet/green, +/area/ministation/dorms) +"jQ" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"jR" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/effect/floor_decal/industrial/loading, +/obj/machinery/conveyor{ + id_tag = "mining_transfer" + }, +/obj/structure/flaps/airtight, +/turf/floor/plating/airless, +/area/ministation/mining) +"jT" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"jU" = ( +/obj/structure/sign/warning/docking_area{ + pixel_y = -30; + dir = 1 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "cargo_airlock_interior"; + name = "Cargo Docking Airlock"; + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/cargo) +"jV" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 8 + }, +/obj/machinery/camera/network/mining{ + dir = 1 + }, +/obj/structure/closet/crate, +/obj/item/stack/material/ore/slag, +/turf/floor/tiled, +/area/ministation/cargo) +"jW" = ( +/obj/structure/closet/crate, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/item/stack/material/ore/handful/sand, +/turf/floor/tiled, +/area/ministation/cargo) +"jX" = ( +/obj/structure/closet/crate, +/obj/item/stack/material/ore/iron, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/machinery/light, +/turf/floor/tiled, +/area/ministation/cargo) +"jY" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"ka" = ( +/obj/machinery/vending/hotfood{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"kb" = ( +/obj/machinery/meter, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"ke" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/n) +"kf" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/wall, +/area/ministation/hall/n) +"kg" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/structure/closet/secure_closet{ + closet_appearance = /decl/closet_appearance/secure_closet/command/hop; + req_access = list("ACCESS_HEAD_OF_PERSONNEL"); + name = "lieutenant's locker" + }, +/obj/item/clothing/suit/space/void/expedition, +/obj/item/clothing/suit/space/void/expedition, +/obj/item/clothing/head/helmet/space/void/expedition, +/obj/item/clothing/head/helmet/space/void/expedition, +/turf/floor/tiled, +/area/ministation/eva) +"kh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"km" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor, +/area/ministation/maint/eastatmos) +"kq" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/reinforced/airmix, +/area/ministation/atmospherics) +"kv" = ( +/obj/machinery/light, +/obj/machinery/suit_cycler/engineering/ministation{ + suit = /obj/item/clothing/suit/space/void/atmos; + helmet = /obj/item/clothing/head/helmet/space/void/atmos + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"kw" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/engine) +"kx" = ( +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"ky" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"kA" = ( +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/obj/structure/janicart{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/janitor) +"kC" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/space, +/area/space) +"kH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor, +/area/ministation/maint/eastatmos) +"kI" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/eva) +"kL" = ( +/obj/structure/hygiene/toilet, +/obj/structure/window/reinforced/tinted{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/start{ + name = "Deck Hand" + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"kM" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/hall/n) +"kN" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 4; + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/obj/effect/floor_decal/corner/white/diagonal, +/obj/effect/floor_decal/corner/white/diagonal{ + dir = 4 + }, +/turf/floor/reinforced/airmix, +/area/ministation/atmospherics) +"kP" = ( +/obj/machinery/door/airlock, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"kU" = ( +/obj/machinery/door/blast/regular{ + id_tag = "mine_process" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"kY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/light, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"kZ" = ( +/turf/wall, +/area/ministation/janitor) +"lb" = ( +/obj/structure/undies_wardrobe, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"le" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"lf" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/turf/space, +/area/space) +"lg" = ( +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/space, +/area/space) +"li" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"lj" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"lk" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"ll" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"ln" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/turf/floor/tiled, +/area/ministation/engine) +"lp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"lq" = ( +/obj/machinery/camera/network/mining{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/closet/crate, +/obj/item/stack/material/brick/mapped/sandstone/forty, +/turf/floor/tiled, +/area/ministation/cargo) +"lr" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"lt" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/turf/floor/reinforced/nitrogen, +/area/ministation/atmospherics) +"lu" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/obj/machinery/atmospherics/valve, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ly" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastinterior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/smcontrol) +"lA" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"lB" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/plating, +/area/ministation/trash) +"lC" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/eva) +"lK" = ( +/obj/structure/lattice, +/turf/wall, +/area/ministation/mining) +"lL" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"lM" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "westatmos_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "westatmos_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = 10; + command = "cycle_exterior" + }, +/turf/floor/plating/airless, +/area/ministation/maint/westatmos) +"lN" = ( +/obj/effect/floor_decal/corner/blue, +/obj/machinery/atmospherics/pipe/manifold4w/visible/red, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"lO" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sat1_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sat1_airlock"; + name = "exterior access button"; + pixel_x = -10; + pixel_y = 20; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"lR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"lS" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"lW" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/ministation/hall/s1) +"lX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/wall, +/area/ministation/ai_sat) +"ma" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/atmospherics) +"mb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastexterior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/supermatter) +"md" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"me" = ( +/obj/structure/table, +/obj/item/firstaid/regular{ + pixel_x = 6; + pixel_y = -5 + }, +/obj/item/multitool, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"mg" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/structure/displaycase, +/obj/item/toy/shipmodel, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"ml" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/structure/tank_rack/oxygen, +/turf/floor/tiled, +/area/ministation/eva) +"mn" = ( +/obj/machinery/atmospherics/binary/pump{ + name = "waste pump" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"mq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/s1) +"mr" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"ms" = ( +/turf/wall, +/area/ministation/hall/s1) +"mu" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/turf/floor/plating, +/area/space) +"mv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/wall/r_wall, +/area/ministation/ai_sat) +"mw" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"my" = ( +/obj/structure/table, +/obj/item/box, +/obj/item/stack/package_wrap/twenty_five, +/turf/floor/tiled, +/area/ministation/cargo) +"mz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/trash) +"mC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/engine) +"mD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/purple, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"mH" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"mJ" = ( +/obj/structure/closet/secure_closet/atmos_personal, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/jumpsuit/hazard, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"mN" = ( +/obj/machinery/camera/network/ministation/sat{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"mP" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "l1ne_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "l1ne_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = -10; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"mQ" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/engine) +"mS" = ( +/turf/floor/tiled, +/area/ministation/janitor) +"mT" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/turf/space, +/area/space) +"mV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"mW" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled, +/area/ministation/cargo) +"mY" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"na" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"nb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"nc" = ( +/obj/structure/fireaxecabinet{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 6 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ne" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"nf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"ng" = ( +/obj/structure/hygiene/toilet{ + dir = 1 + }, +/obj/structure/window/reinforced/tinted, +/obj/effect/decal/cleanable/dirt/visible, +/obj/random_multi/single_item/captains_spare_id, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"ni" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"nj" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -21 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"nk" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"nn" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/sign/warning/vent_port{ + dir = 1; + pixel_y = -34 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/turf/floor/plating, +/area/ministation/supermatter) +"nu" = ( +/obj/structure/closet, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"nw" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 8; + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/turf/floor/reinforced/nitrogen, +/area/ministation/atmospherics) +"nx" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"nz" = ( +/obj/machinery/suit_cycler/engineering/ministation, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"nA" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"nD" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/turf/space, +/area/space) +"nE" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"nG" = ( +/obj/effect/floor_decal/industrial/custodial{ + dir = 1 + }, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/machinery/conveyor_switch/oneway{ + id_tag = "recycler"; + name = "recycler conveyor" + }, +/turf/floor/plating, +/area/ministation/trash) +"nH" = ( +/obj/structure/railing/mapped, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"nM" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 5 + }, +/obj/machinery/meter, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"nN" = ( +/obj/structure/curtain/open/bed, +/obj/machinery/recharge_station, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"nO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/pool, +/area/ministation/dorms) +"nR" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue, +/obj/machinery/space_heater, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"nS" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"nY" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "westatmos_airlock"; + pixel_y = null; + tag_airpump = "westatmos_vent"; + tag_chamber_sensor = "westatmos_sensor"; + tag_exterior_door = "westatmos_airlock_exterior"; + tag_interior_door = "westatmos_airlock_interior"; + dir = 4; + pixel_x = -20 + }, +/obj/machinery/airlock_sensor{ + id_tag = "westatmos_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"ob" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"oc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/pool, +/area/ministation/dorms) +"od" = ( +/obj/structure/chair/comfy/black{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"oi" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 1 + }, +/turf/floor, +/area/ministation/maint/westatmos) +"ow" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"oy" = ( +/turf/wall/r_wall, +/area/ministation/smcontrol) +"oB" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/machinery/camera/network/engineering{ + dir = 8; + name = "Atmospherics"; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"oC" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/turf/space, +/area/space) +"oE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/door/airlock/glass/command, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/eva) +"oF" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor, +/area/ministation/engine) +"oI" = ( +/obj/abstract/landmark/start{ + name = "Janitor" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/stool, +/turf/floor/tiled, +/area/ministation/janitor) +"oK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/green, +/turf/floor/tiled, +/area/ministation/supermatter) +"oM" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable/max_cap_in_out, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"oO" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastinterior" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/smcontrol) +"oQ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"oS" = ( +/obj/effect/floor_decal/corner/red{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"oV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"oX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"oY" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"oZ" = ( +/obj/machinery/material_processing/stacker, +/turf/floor/plating/airless, +/area/ministation/mining) +"pa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"pe" = ( +/obj/effect/decal/cleanable/blood/oil, +/turf/floor/tiled, +/area/ministation/eva) +"pf" = ( +/obj/machinery/shieldgen, +/turf/floor/plating, +/area/ministation/engine) +"ph" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/engine) +"pi" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/reinforced/airmix, +/area/ministation/atmospherics) +"po" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/n) +"pr" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/hall/n) +"ps" = ( +/obj/structure/ladder, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"pw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"px" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"pz" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/cargo) +"pB" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastinterior" + }, +/turf/floor/plating, +/area/ministation/smcontrol) +"pG" = ( +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"pJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"pQ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 5 + }, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"pS" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/vehicle/train/trolley, +/turf/floor/tiled, +/area/ministation/cargo) +"pT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"pV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/engine) +"pX" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/plating, +/area/ministation/ai_upload) +"pZ" = ( +/obj/effect/floor_decal/industrial/custodial/corner{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/trash) +"qa" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/cargo) +"qb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/engine) +"qd" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l1central) +"qe" = ( +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"qf" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/floor/plating, +/area/ministation/supermatter) +"qm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"qo" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"qr" = ( +/obj/structure/closet, +/obj/random/maintenance, +/obj/item/clothing/shirt/hawaii, +/obj/random/gloves, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"qs" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; + internal_pressure_bound_default = 2000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/carbon_dioxide, +/area/ministation/atmospherics) +"qt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/laminate, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"qu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"qw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 8; + icon_state = "pipe-c" + }, +/turf/floor/pool, +/area/ministation/dorms) +"qA" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"qD" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"qG" = ( +/obj/effect/floor_decal/industrial/custodial/corner{ + dir = 1 + }, +/obj/machinery/conveyor{ + dir = 8; + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"qH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark{ + name = "lightsout" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"qI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"qK" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/temperature/freezer, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"qL" = ( +/obj/machinery/camera/network/engineering{ + name = "SM West"; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"qM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"qN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"qO" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/n) +"qP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"qQ" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"qW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/railing/mapped, +/turf/floor/plating, +/area/ministation/trash) +"qY" = ( +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/turf/space, +/area/space) +"rb" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"rc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"rd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"re" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"rf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"rj" = ( +/obj/machinery/conveyor{ + dir = 8; + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"rn" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"rp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"rq" = ( +/obj/machinery/door/airlock/glass/engineering{ + name = "Chief of Engineering"; + autoset_access = 0; + req_access = list("ACCESS_CHIEF_ENGINEER") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"rt" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ru" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/black{ + dir = 6 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"rz" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/plating, +/area/ministation/trash) +"rA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"rC" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"rD" = ( +/obj/structure/table, +/obj/item/radio/intercom/locked{ + pixel_y = 20 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"rH" = ( +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/hygiene/drain, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"rI" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "bulb1" + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"rM" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/effect/floor_decal/corner/black{ + dir = 5 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"rQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"rT" = ( +/obj/machinery/conveyor{ + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"rU" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/closet/secure_closet/engineering_chief, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/clothing/suit/jacket/winter, +/obj/item/telebaton, +/obj/item/sealant_tank/mapped, +/obj/item/sealant_tank/mapped, +/turf/floor/carpet/orange, +/area/ministation/engine) +"rX" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"sb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/yew, +/area/ministation/engine) +"sc" = ( +/obj/abstract/turbolift_spawner/ministation{ + dir = 1; + icon_state = "" + }, +/turf/floor, +/area/ministation/hall/s1) +"se" = ( +/obj/item/airlock_brace, +/obj/item/airlock_brace, +/obj/structure/rack{ + dir = 8 + }, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/turf/floor/plating, +/area/ministation/engine) +"sf" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/external/glass{ + locked = 1; + id_tag = "stern_engineering_airlock_exterior"; + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/visible/black, +/turf/floor/plating, +/area/ministation/engine) +"sh" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"sl" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_north = 4; + tag_west = 2; + use_power = 0 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"sp" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"sr" = ( +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"sx" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/space, +/area/space) +"sy" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/structure/closet/jcloset, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/tiled, +/area/ministation/janitor) +"sz" = ( +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/camera/autoname, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled, +/area/ministation/janitor) +"sA" = ( +/obj/structure/table, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/box/lights/mixed, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/stack/material/bar/wax, +/turf/floor/tiled, +/area/ministation/janitor) +"sC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"sD" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 4; + icon_state = "pdoor0"; + id_tag = "scraplock"; + name = "External Blast Doors"; + opacity = 0 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/atmospherics) +"sE" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"sG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"sJ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"sK" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/table, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"sO" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/closet/crate, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/turf/floor/tiled, +/area/ministation/eva) +"sR" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"sT" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/space) +"sV" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"sX" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"ta" = ( +/obj/machinery/shieldwallgen, +/turf/floor/plating, +/area/ministation/engine) +"tc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/dorms) +"tg" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"th" = ( +/obj/structure/table, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/item/clothing/head/welding, +/obj/machinery/recharger, +/turf/floor/tiled, +/area/ministation/eva) +"tj" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"tk" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/turf/space, +/area/space) +"tl" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 6 + }, +/turf/space, +/area/space) +"tm" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"tq" = ( +/obj/item/chems/glass/bucket, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/janitor) +"tr" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/janitor) +"ts" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/janitor) +"tt" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"tu" = ( +/obj/structure/ore_box, +/turf/floor/tiled, +/area/ministation/cargo) +"tv" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/floor, +/area/ministation/hall/s1) +"tw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"tz" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"tB" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/trash) +"tD" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/helium{ + start_pressure = 2559.63 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"tF" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"tH" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"tK" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"tO" = ( +/obj/effect/floor_decal/carpet/blue2{ + dir = 8 + }, +/obj/structure/closet/crate/bin/ministation, +/turf/floor/tiled, +/area/ministation/hall/s1) +"tP" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"tQ" = ( +/turf/floor/plating, +/area/ministation/ai_upload) +"tU" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/table/gamblingtable, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/item/flashlight/lamp/green, +/obj/item/poster, +/turf/floor/carpet/green, +/area/ministation/dorms) +"tW" = ( +/obj/machinery/door/airlock/mining, +/turf/floor/plating, +/area/ministation/cargo) +"tZ" = ( +/obj/machinery/light, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ua" = ( +/obj/machinery/power/solar, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/space) +"ue" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/network/hallway{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"uf" = ( +/obj/effect/floor_decal/corner/black{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ug" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"uh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"ui" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/s1) +"uj" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/item/chems/drinks/juicebox/sensible_random, +/obj/item/chems/drinks/juicebox/sensible_random, +/turf/floor/tiled, +/area/ministation/hall/n) +"ul" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/rack{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"um" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red/diagonal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/diagonal, +/obj/machinery/meter/turf, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/turf/floor/reinforced/nitrogen, +/area/ministation/atmospherics) +"un" = ( +/obj/machinery/atmospherics/unary/heat_exchanger, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ur" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"us" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/janitorialcart, +/obj/item/mop, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/janitor) +"ut" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/eva) +"uy" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/turf/floor/carpet/green, +/area/ministation/dorms) +"uB" = ( +/obj/structure/tank_rack/oxygen, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"uE" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/janitor) +"uG" = ( +/obj/machinery/door/airlock/atmos, +/turf/floor/tiled, +/area/ministation/smcontrol) +"uH" = ( +/obj/machinery/light, +/obj/structure/chair/comfy/black{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"uK" = ( +/turf/wall, +/area/ministation/maint/westatmos) +"uL" = ( +/obj/machinery/door/airlock/glass/engineering{ + name = "Chief of Engineering"; + autoset_access = 0; + req_access = list("ACCESS_CHIEF_ENGINEER") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/laminate/yew, +/area/ministation/engine) +"uM" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "trash_sort" + }, +/turf/floor/plating, +/area/ministation/trash) +"uN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"uS" = ( +/obj/effect/floor_decal/corner/yellow/diagonal, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"uT" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"uX" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"uY" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"uZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"va" = ( +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/closet/crate, +/obj/item/cell, +/obj/item/cell, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"ve" = ( +/obj/machinery/apc{ + dir = 4; + name = "_East APC"; + pixel_x = 27; + pixel_y = 2 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"vf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/conveyor{ + dir = 8; + id_tag = "trash_sort" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/trash) +"vg" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/s1) +"vk" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"vl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -10; + dir = 4; + pixel_x = -34 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/engine) +"vp" = ( +/turf/wall, +/area/ministation/supermatter) +"vq" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"vv" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"vx" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"vz" = ( +/obj/machinery/fabricator, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"vA" = ( +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"vB" = ( +/obj/machinery/vending/fitness, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"vC" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/item/stamp/denied{ + pixel_x = 4; + pixel_y = -2 + }, +/obj/item/pen/red, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/machinery/button/blast_door{ + id_tag = "cargoshut"; + name = "Cargo Shutters Button"; + pixel_y = 8; + pixel_x = -6 + }, +/obj/item/stamp/cargo, +/obj/item/folder/yellow, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"vF" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"vI" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/computer/atmos_alert{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"vK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/chair/wood{ + dir = 8 + }, +/obj/machinery/camera/autoname{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"vL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/yew, +/area/ministation/engine) +"vM" = ( +/obj/machinery/floodlight, +/turf/floor/plating, +/area/ministation/engine) +"vP" = ( +/obj/effect/floor_decal/industrial/warning/corner, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/tiled, +/area/ministation/eva) +"vV" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"vY" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"wb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"wd" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -34; + dir = 1; + pixel_x = -8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/plating, +/area/ministation/supermatter) +"we" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/hallway{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"wg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"wi" = ( +/obj/machinery/atmospherics/valve, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"wk" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"wm" = ( +/obj/structure/closet/secure_closet/quartermaster{ + req_access = list("ACCESS_MINING") + }, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/tiled, +/area/ministation/cargo) +"wo" = ( +/obj/machinery/camera/network/engineering{ + dir = 4; + name = "Atmospherics"; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"wp" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/laminate/yew, +/area/ministation/engine) +"ws" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"wt" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate, +/area/ministation/engine) +"wu" = ( +/obj/structure/fitness/punchingbag, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"wv" = ( +/obj/machinery/door/window/southleft, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/helium, +/turf/floor/tiled, +/area/ministation/engine) +"wx" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/camera/network/hallway{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"wA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/engine) +"wB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"wC" = ( +/obj/structure/closet, +/obj/item/gun/launcher/foam/crossbow, +/obj/item/box/foam_darts, +/obj/item/box/foam_darts, +/obj/item/gun/launcher/foam/revolver, +/obj/item/gun/launcher/foam/revolver, +/obj/item/gun/launcher/foam, +/obj/item/gun/launcher/foam, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"wD" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/l1central) +"wG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/n) +"wJ" = ( +/obj/machinery/camera/autoname{ + dir = 8 + }, +/obj/machinery/material_processing/stacker, +/turf/floor/plating, +/area/ministation/trash) +"wK" = ( +/obj/structure/bed/padded, +/obj/random/plushie, +/obj/item/bedsheet/ce, +/turf/floor/carpet/orange, +/area/ministation/engine) +"wM" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/hall/s1) +"wN" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/belt, +/obj/item/belt, +/obj/item/belt, +/obj/item/belt, +/obj/item/belt, +/obj/machinery/light{ + dir = 1; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"wP" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/table/steel, +/obj/item/stack/material/puck/mapped/uranium/ten, +/turf/floor/plating, +/area/ministation/engine) +"wS" = ( +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/obj/item/plunger, +/turf/floor/tiled, +/area/ministation/janitor) +"wT" = ( +/obj/structure/closet/lasertag/blue, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"wZ" = ( +/obj/item/mollusc/barnacle{ + pixel_x = 20 + }, +/turf/floor/plating/airless, +/area/space) +"xg" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"xj" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"xk" = ( +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"xm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"xo" = ( +/obj/machinery/emitter, +/turf/floor/plating, +/area/ministation/engine) +"xp" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/valve, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"xq" = ( +/obj/structure/ladder, +/turf/floor/plating, +/area/ministation/maint/l1central) +"xr" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/sign/department/eva{ + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"xt" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"xw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"xE" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"xJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"xN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/pool, +/area/ministation/dorms) +"xP" = ( +/obj/machinery/atmospherics/binary/pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"xQ" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/ministation/trash) +"xV" = ( +/obj/item/rpd, +/obj/structure/closet/crate, +/turf/floor/plating, +/area/ministation/engine) +"xW" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"xX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/conveyor{ + dir = 4; + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"xZ" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/turf/space, +/area/space) +"yc" = ( +/obj/machinery/camera/network/engineering{ + dir = 8; + name = "Tank Storage" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/table/steel, +/obj/item/stack/net_cable_coil, +/turf/floor/plating, +/area/ministation/engine) +"yh" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/engine) +"yi" = ( +/obj/machinery/light/small, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"yj" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"yk" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/obj/machinery/camera/network/engineering{ + name = "SM East"; + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"ym" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/double/engineering, +/turf/floor/plating, +/area/ministation/engine) +"yo" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/blue, +/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup, +/turf/floor/plating, +/area/ministation/engine) +"yp" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"yr" = ( +/obj/structure/lattice, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/space, +/area/space) +"yu" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/sign/warning/airlock{ + dir = 8; + pixel_x = 43 + }, +/turf/floor/tiled, +/area/ministation/eva) +"yv" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/space) +"yx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"yz" = ( +/obj/machinery/vending/engineering{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"yC" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"yD" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"yE" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"yH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"yL" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"yM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"yO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/structure/drill_brace, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"yP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5; + pixel_x = 2; + pixel_y = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"yS" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/space, +/area/space) +"yT" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"yU" = ( +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l1central) +"yW" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"yY" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"yZ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"za" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/janitor) +"ze" = ( +/obj/effect/floor_decal/corner/black{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/red, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"zg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/engine) +"zk" = ( +/obj/structure/transit_tube, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/space, +/area/ministation/engine) +"zl" = ( +/obj/structure/table/marble, +/obj/item/towel/random, +/obj/item/towel/random, +/obj/item/towel/random, +/obj/item/towel/random, +/obj/item/towel/random, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"zm" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"zr" = ( +/turf/floor/plating, +/area/ministation/maint/westatmos) +"zu" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"zw" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/dorms) +"zy" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/s1) +"zz" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/closet/crate, +/obj/item/stack/material/brick/mapped/sandstone/five, +/turf/floor/tiled, +/area/ministation/cargo) +"zB" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"zH" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/blue{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"zJ" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/l1central) +"zN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/yellow/diagonal, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"zR" = ( +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "SupermatterPort"; + name = "Reactor Blast Door" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"zS" = ( +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "SupermatterPort"; + name = "Reactor Blast Door" + }, +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/turf/floor/plating, +/area/ministation/supermatter) +"zU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/railing/mapped, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"zW" = ( +/turf/wall, +/area/ministation/dorms) +"zX" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/turf/space, +/area/space) +"zY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"zZ" = ( +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ab" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/machinery/meter/turf, +/turf/floor/reinforced/oxygen, +/area/ministation/atmospherics) +"Ad" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/belt/utility, +/obj/item/wrench, +/obj/item/weldingtool, +/obj/item/clothing/head/welding, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ae" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/camera/network/engineering{ + name = "Office"; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Ai" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/washing_machine, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Aj" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/vending/coffee, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ak" = ( +/obj/structure/table/gamblingtable, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Al" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/pool, +/area/ministation/dorms) +"Am" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"Ao" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Aq" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/belt/utility, +/obj/item/wrench, +/obj/item/weldingtool, +/obj/item/clothing/head/welding/engie, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ar" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"As" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/cable/cyan{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Aw" = ( +/obj/machinery/light, +/obj/machinery/mech_recharger, +/turf/floor/plating/airless, +/area/ministation/mining) +"Ax" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/eva) +"Az" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"AB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/external/glass{ + id_tag = "port_engineering_airlock_exterior"; + locked = 1; + autoset_access = 0 + }, +/obj/machinery/button/access/interior{ + id_tag = "port_engineering_airlock"; + name = "exterior access button"; + pixel_x = -10; + pixel_y = 20; + command = "cycle_exterior" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/engine) +"AC" = ( +/obj/structure/lattice, +/turf/wall, +/area/space) +"AF" = ( +/turf/floor/plating, +/area/ministation/maint/l1ne) +"AH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/s1) +"AJ" = ( +/obj/machinery/power/smes/buildable/max_cap_in_out{ + capacity = 5e+009; + charge = 5e+009 + }, +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"AK" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/airlock_sensor{ + id_tag = "stern_engineering_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/engine) +"AM" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"AN" = ( +/obj/machinery/conveyor{ + dir = 4; + id_tag = "recycler" + }, +/turf/floor/plating, +/area/ministation/trash) +"AP" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastinterior" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/smcontrol) +"AQ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastinterior" + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/smcontrol) +"AR" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/wall/r_wall, +/area/ministation/engine) +"AS" = ( +/obj/machinery/door/window/southleft, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/tiled, +/area/ministation/engine) +"AT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"AU" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/eva) +"AV" = ( +/obj/machinery/photocopier, +/turf/floor/tiled, +/area/ministation/cargo) +"AW" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/floor, +/area/ministation/maint/westatmos) +"AX" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Ba" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"Bb" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Bd" = ( +/turf/floor/plating/airless, +/area/ministation/mining) +"Be" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/engine) +"Bg" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Bh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Bi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"Bj" = ( +/turf/floor/carpet/orange, +/area/ministation/engine) +"Bk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Bn" = ( +/obj/effect/floor_decal/carpet/blue2{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Bo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Bp" = ( +/obj/machinery/button/blast_door{ + req_access = list("ACCESS_MINING"); + dir = 1; + pixel_y = -24; + name = "Mineral Processing Blast Door Button"; + id_tag = "mine_process" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"Bq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/chair/wood{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Bt" = ( +/obj/structure/table/gamblingtable, +/turf/floor/carpet/blue2, +/area/ministation/hall/s1) +"Bu" = ( +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable{ + icon_state = "16-0" + }, +/obj/machinery/atmospherics/pipe/zpipe/up/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/up{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"Bw" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Bx" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/table/gamblingtable, +/obj/item/stack/cable_coil/random, +/obj/item/stack/cable_coil/random, +/obj/item/toolbox/mechanical, +/obj/item/toolbox/electrical, +/obj/item/clothing/gloves/insulated/cheap, +/obj/item/clothing/gloves/insulated/cheap, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/carpet/green, +/area/ministation/dorms) +"Bz" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sat2_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sat2_airlock"; + name = "exterior access button"; + pixel_x = -10; + pixel_y = 20; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"BB" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 10 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/ministation/supermatter) +"BC" = ( +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/item/multitool, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/item/clothing/gloves/insulated, +/turf/floor/tiled, +/area/ministation/eva) +"BD" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/ladder, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"BF" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"BG" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"BK" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/pool, +/area/ministation/dorms) +"BM" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 9 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"BN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"BP" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"BQ" = ( +/obj/machinery/conveyor{ + id_tag = "mining_transfer" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"BS" = ( +/obj/structure/closet, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"BV" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/corner/blue{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"BW" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"BY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"BZ" = ( +/obj/machinery/conveyor_switch/oneway{ + id_tag = "trash_sort" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/trash) +"Ca" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/ministation/ai_upload) +"Cb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Cg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ch" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/highsecurity{ + id_tag = "upload" + }, +/turf/floor/plating/airless, +/area/ministation/ai_upload) +"Ci" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/n) +"Cm" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/plating, +/area/ministation/ai_sat) +"Cn" = ( +/turf/wall, +/area/ministation/maint/eastatmos) +"Cp" = ( +/obj/machinery/ai_status_display, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"Cq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/ministation/ai_sat) +"Cr" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Cs" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ct" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/ministation/ai_sat) +"Cu" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Cv" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/turf/floor/plating, +/area/ministation/engine) +"Cw" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"Cx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/highsecurity/bolted{ + id_tag = "aibolt" + }, +/turf/floor/plating, +/area/ministation/ai_core) +"Cy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Cz" = ( +/obj/machinery/light/small, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"CA" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/eva) +"CB" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"CC" = ( +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"CE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"CF" = ( +/obj/machinery/atmospherics/binary/pump/on, +/turf/floor/plating, +/area/ministation/ai_sat) +"CG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/ministation/ai_sat) +"CH" = ( +/obj/machinery/portable_atmospherics/canister/air, +/turf/floor/plating, +/area/ministation/ai_sat) +"CJ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"CL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/custodial{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/trash) +"CM" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"CN" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"CQ" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "starboard_engineering_airlock_interior"; + locked = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/button/access/interior{ + id_tag = "starboard_engineering_airlock"; + name = "interior access button"; + pixel_x = -10; + pixel_y = 20 + }, +/turf/floor, +/area/ministation/engine) +"CS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/engine) +"CV" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"CW" = ( +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"CZ" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_north = 3; + tag_south = 4; + tag_west = 2 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Da" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Df" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Di" = ( +/obj/machinery/door/airlock/atmos, +/turf/floor/reinforced/airless, +/area/ministation/supermatter) +"Dk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/hallway{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Dl" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup, +/turf/floor/plating, +/area/ministation/engine) +"Dm" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/plating, +/area/ministation/engine) +"Dn" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, +/turf/floor/plating, +/area/ministation/engine) +"Do" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/plating, +/area/ministation/engine) +"Dp" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/turf/floor/plating, +/area/ministation/engine) +"Dq" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/helium, +/turf/floor/plating, +/area/ministation/engine) +"Dr" = ( +/obj/structure/closet/firecloset, +/turf/floor/tiled, +/area/ministation/engine) +"Ds" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/floodlight, +/turf/floor/tiled, +/area/ministation/engine) +"Dt" = ( +/turf/wall, +/area/ministation/engine) +"Du" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Dv" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"Dw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/hall/s1) +"Dx" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Dy" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s1) +"DB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/smcontrol) +"DC" = ( +/turf/floor/tiled, +/area/ministation/engine) +"DD" = ( +/turf/wall/r_wall, +/area/ministation/maint/westatmos) +"DE" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/light_switch{ + pixel_y = 10; + pixel_x = 21; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"DF" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/rig/ce/equipped, +/turf/floor/carpet/orange, +/area/ministation/engine) +"DG" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s1) +"DH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/item/cash/scavbucks, +/turf/floor, +/area/ministation/maint/eastatmos) +"DK" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup, +/turf/floor/plating, +/area/ministation/engine) +"DL" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/plating, +/area/ministation/engine) +"DM" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/turf/floor/plating, +/area/ministation/engine) +"DN" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/turf/floor/plating, +/area/ministation/engine) +"DO" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/turf/floor/plating, +/area/ministation/engine) +"DP" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/helium, +/turf/floor/plating, +/area/ministation/engine) +"DQ" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/flashlight{ + pixel_x = 1; + pixel_y = 5 + }, +/obj/item/clothing/mask/gas/budget, +/turf/floor/tiled, +/area/ministation/engine) +"DR" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/camera/network/engineering{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/engine) +"DT" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/glass/atmos, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techfloor, +/area/ministation/engine) +"DU" = ( +/obj/structure/disposaloutlet{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/space) +"DV" = ( +/obj/structure/table, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/recharger, +/obj/machinery/cell_charger{ + pixel_y = 14 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"DW" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = 25 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"DX" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable/max_cap_in_out{ + capacity = 5e+009; + charge = 5e+009 + }, +/obj/machinery/camera/network/engineering{ + name = "Engineering Hub" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"DY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"DZ" = ( +/obj/structure/table, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/item/toolbox/electrical{ + pixel_y = 5 + }, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/item/clothing/gloves/insulated, +/obj/item/toolbox/mechanical{ + pixel_y = 5 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Eb" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power_sensor{ + id_tag = "Station Power"; + name = "Powernet Sensor - Station Power" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ec" = ( +/obj/machinery/light, +/obj/machinery/vending/snack{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ed" = ( +/obj/machinery/vending/cola{ + dir = 4; + pixel_x = -5 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ee" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ef" = ( +/obj/abstract/landmark{ + name = "lightsout" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Eg" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Eh" = ( +/obj/machinery/vending/snack{ + dir = 8; + pixel_x = 5 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ei" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = -24; + dir = 1; + pixel_x = -1 + }, +/turf/floor/laminate/yew, +/area/ministation/engine) +"Ej" = ( +/obj/machinery/conveyor_switch{ + id_tag = "CanisterStore" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Ek" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"El" = ( +/obj/machinery/door/window/southleft, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/tiled, +/area/ministation/engine) +"Em" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/tiled, +/area/ministation/engine) +"En" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/engine) +"Eo" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/engine) +"Eq" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Er" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/abstract/landmark/start{ + name = "Atmospheric Technician" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Es" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Et" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Atmospheric Technician" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Eu" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/ministation/engine) +"Ev" = ( +/obj/structure/cable, +/obj/machinery/computer/air_control/supermatter_core{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ew" = ( +/obj/machinery/vending/coffee{ + dir = 4; + pixel_x = -5 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ex" = ( +/obj/machinery/vending/cigarette{ + dir = 8; + pixel_x = 5 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ey" = ( +/obj/machinery/fabricator/pipe/disposal, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ez" = ( +/obj/item/stool/padded, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/laminate, +/area/ministation/engine) +"EB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate, +/area/ministation/engine) +"EE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/sign/department/janitor{ + dir = 4; + pixel_x = -33 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"EF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/s1) +"EG" = ( +/obj/structure/lattice, +/obj/item/stack/cable_coil, +/turf/space, +/area/space) +"EJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/closet/secure_closet/engineering_electrical{ + req_access = list("ACCESS_ENGINEERING") + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"EK" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"EL" = ( +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/item/stool/padded, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate, +/area/ministation/engine) +"EM" = ( +/obj/item/music_player/boombox, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/laminate/reinforced/walnut/maple, +/turf/floor/laminate, +/area/ministation/engine) +"EN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/table/laminate/reinforced/walnut/maple, +/obj/item/chems/chem_disp_cartridge/coffee{ + name = "coffee canister" + }, +/turf/floor/laminate, +/area/ministation/engine) +"EO" = ( +/obj/item/food/old/pizza, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/laminate/reinforced/walnut/maple, +/turf/floor/laminate, +/area/ministation/engine) +"EP" = ( +/obj/machinery/vending/materials{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"EQ" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"ER" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"ES" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"ET" = ( +/obj/effect/floor_decal/corner/yellow/three_quarters, +/obj/structure/sign/warning/engineering_access{ + pixel_y = -32; + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"EU" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"EV" = ( +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 4 + }, +/obj/structure/sign/department/engineering{ + dir = 1; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"EW" = ( +/obj/structure/table/steel, +/turf/floor/plating, +/area/ministation/engine) +"EX" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/fabricator/pipe, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"EY" = ( +/obj/effect/decal/cleanable/blood/oil, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"EZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/engine) +"Fa" = ( +/obj/machinery/camera/network/engineering{ + name = "Engineering Hub"; + dir = 4 + }, +/obj/structure/closet/secure_closet/engineering_welding, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fb" = ( +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Fc" = ( +/obj/item/wrench, +/obj/item/clothing/gloves/insulated, +/obj/structure/table/laminate/reinforced/walnut/maple, +/turf/floor/laminate, +/area/ministation/engine) +"Fd" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/item/stack/tape_roll/barricade_tape/atmos, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/table/laminate/reinforced/walnut/maple, +/obj/item/chems/spray/cleaner, +/turf/floor/laminate, +/area/ministation/engine) +"Fe" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/structure/table/laminate/reinforced/walnut/maple, +/obj/item/chems/drinks/glass2/coffeecup/tall, +/turf/floor/laminate, +/area/ministation/engine) +"Ff" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/mob/living/simple_animal/opossum/poppy, +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Fg" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Fh" = ( +/obj/structure/closet/firecloset, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Fi" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/pool, +/area/ministation/dorms) +"Fj" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/engineering, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/turf/floor/pool, +/area/ministation/dorms) +"Fm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate, +/area/ministation/engine) +"Fn" = ( +/obj/machinery/space_heater, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fo" = ( +/obj/machinery/space_heater, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fq" = ( +/obj/structure/ore_box, +/turf/floor/plating/airless, +/area/ministation/mining) +"Fr" = ( +/obj/structure/tank_rack/oxygen, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fs" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ft" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Fu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate, +/area/ministation/engine) +"Fv" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Fw" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/laminate, +/area/ministation/engine) +"Fx" = ( +/obj/machinery/vending/engivend{ + dir = 8 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Fy" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/power_sensor{ + id_tag = "Engine Power"; + name = "Powernet Sensor - Engine Power" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Fz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 8 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FA" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/effect/decal/cleanable/blood/oil, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FB" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/floor_decal/corner/yellow/three_quarters{ + dir = 1 + }, +/obj/machinery/light_switch{ + pixel_y = 25 + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FC" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/turf/floor/plating, +/area/ministation/engine) +"FD" = ( +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/turf/floor/tiled, +/area/ministation/engine) +"FE" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/solar, +/turf/floor/plating/airless, +/area/space) +"FF" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/space) +"FG" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/solar, +/turf/floor/plating/airless, +/area/space) +"FH" = ( +/obj/machinery/light, +/obj/structure/closet/secure_closet/engineering_personal{ + req_access = list("ACCESS_ENGINEERING") + }, +/obj/item/clothing/suit/jacket/winter/engineering, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/backpack/dufflebag/eng, +/obj/item/backpack/dufflebag/eng, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FI" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/chems/spray/extinguisher{ + pixel_x = 8 + }, +/obj/item/clothing/gloves/thick, +/obj/item/hoist_kit, +/obj/item/flashlight/lantern, +/obj/item/flashlight/lantern, +/obj/item/mobile_ladder, +/obj/item/backpack/dufflebag/eng, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FJ" = ( +/obj/machinery/port_gen/pacman/super, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FK" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/engine) +"FM" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/table/gamblingtable, +/obj/machinery/recharger, +/obj/item/poster, +/turf/floor/carpet/green, +/area/ministation/dorms) +"FN" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/civilian, +/turf/floor/tiled, +/area/ministation/janitor) +"FO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FP" = ( +/obj/machinery/door/airlock/glass/engineering, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor, +/area/ministation/engine) +"FQ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FR" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FS" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"FT" = ( +/obj/machinery/door/airlock/glass/engineering, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor, +/area/ministation/engine) +"FU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/engine) +"FV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"FW" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"FX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32; + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/effect/floor_decal/industrial/hatch/red, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/engine) +"FY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/camera/network/engineering{ + dir = 1; + name = "Tank Storage" + }, +/turf/floor/tiled, +/area/ministation/engine) +"FZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Ga" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"Gb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Gc" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"Gd" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/ministation/trash) +"Ge" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/engine) +"Gf" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Gg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/engine) +"Gh" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/solar, +/turf/floor/plating, +/area/space) +"Gi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/engine) +"Gj" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/engine) +"Gk" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Gl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/engine) +"Gm" = ( +/obj/structure/lattice, +/turf/wall, +/area/ministation/engine) +"Gn" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/smes/buildable/preset, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Gp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Gq" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Gr" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green, +/turf/floor/tiled, +/area/ministation/engine) +"Gs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/engine) +"Gt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Gu" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable/preset, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Gv" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Gw" = ( +/obj/structure/cable, +/turf/floor/plating, +/area/space) +"Gx" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Gy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/engine) +"Gz" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/engine) +"GA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/engine) +"GB" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/obj/structure/lattice, +/turf/space, +/area/space) +"GC" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/space, +/area/space) +"GF" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"GG" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/space) +"GH" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/space) +"GI" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/space) +"GJ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/space) +"GL" = ( +/obj/machinery/door/airlock/civilian{ + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/trash) +"GM" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/plating, +/area/space) +"GN" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"GO" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/space) +"GP" = ( +/obj/machinery/power/tracker, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/space) +"GQ" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/tracker, +/turf/floor/plating, +/area/space) +"GR" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"GS" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/space) +"GT" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/space) +"GU" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/ministation/hall/s1) +"GV" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/external/glass{ + id_tag = "port_engineering_airlock_interior"; + autoset_access = 0; + locked = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/button/access/interior{ + id_tag = "port_engineering_airlock"; + name = "interior access button"; + pixel_x = 10; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/engine) +"GW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/airlock_sensor{ + id_tag = "port_engineering_sensor"; + pixel_y = 20 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "port_engineering_airlock"; + pixel_y = 24; + tag_airpump = "port_engineering_vent"; + tag_chamber_sensor = "port_engineering_sensor"; + tag_exterior_door = "port_engineering_airlock_exterior"; + tag_interior_door = "port_engineering_airlock_interior" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/engine) +"GX" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"GY" = ( +/obj/machinery/power/solar_control{ + dir = 8 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"GZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"Ha" = ( +/obj/item/radio/intercom{ + canhear_range = 3; + name = "Common Channel"; + pixel_x = 27; + pixel_y = -3; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hb" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hc" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/engine) +"Hd" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"He" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/space) +"Hf" = ( +/obj/structure/cable, +/obj/machinery/power/solar_control{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Hg" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/camera/network/engineering{ + name = "Port Solars" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hh" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor, +/area/ministation/engine) +"Hi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/engine) +"Hj" = ( +/obj/machinery/light/small, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hk" = ( +/obj/structure/transit_tube{ + dir = 4; + icon_state = "Block" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hl" = ( +/obj/structure/transit_tube_pod{ + dir = 4 + }, +/obj/structure/transit_tube/station{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hm" = ( +/obj/structure/transit_tube, +/turf/floor/tiled, +/area/ministation/engine) +"Hn" = ( +/obj/structure/closet/wardrobe/mixed, +/obj/item/clothing/jumpsuit, +/obj/item/clothing/jumpsuit{ + color = "#ff00ff" + }, +/obj/item/clothing/jumpsuit{ + color = "#000000" + }, +/obj/item/clothing/jumpsuit{ + color = "#008000" + }, +/obj/item/clothing/jumpsuit{ + color = "#808080" + }, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/jumpsuit, +/obj/item/clothing/jumpsuit, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Ho" = ( +/obj/structure/transit_tube, +/turf/space, +/area/space) +"Hp" = ( +/obj/structure/transit_tube{ + icon_state = "E-W-Pass" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"Hq" = ( +/obj/structure/transit_tube{ + icon_state = "W-SE" + }, +/turf/space, +/area/space) +"Hr" = ( +/obj/structure/transit_tube{ + icon_state = "D-SW" + }, +/turf/space, +/area/space) +"Hs" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/tiled, +/area/ministation/engine) +"Ht" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hu" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/structure/sign/warning/radioactive{ + pixel_y = 42; + pixel_x = 9 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/engine) +"Hv" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "smsafetydoor" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Hx" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Hz" = ( +/obj/structure/transit_tube{ + icon_state = "D-NE" + }, +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/space, +/area/space) +"HA" = ( +/obj/structure/transit_tube{ + icon_state = "S-NW" + }, +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/space, +/area/space) +"HB" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/item/stool, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"HC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/engine) +"HD" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "smsafetydoor" + }, +/turf/floor/tiled, +/area/ministation/engine) +"HE" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"HF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/item/stool, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"HG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"HH" = ( +/obj/structure/transit_tube{ + icon_state = "N-S" + }, +/turf/space, +/area/space) +"HI" = ( +/obj/structure/table, +/obj/item/stack/cable_coil, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/item/stock_parts/circuitboard/airlock_electronics, +/obj/item/scanner/gas, +/obj/item/stack/cable_coil, +/turf/floor/tiled, +/area/ministation/engine) +"HJ" = ( +/obj/structure/table, +/obj/item/folder/yellow, +/obj/item/clothing/head/earmuffs, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/cash/scavbucks, +/turf/floor/tiled, +/area/ministation/engine) +"HK" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled, +/area/ministation/engine) +"HL" = ( +/obj/structure/cable, +/obj/machinery/power/smes/buildable/preset, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"HM" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/sign/warning/airlock{ + dir = 1; + pixel_y = -32 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"HN" = ( +/obj/machinery/firealarm{ + pixel_y = 21 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/ministation/smcontrol) +"HO" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/solar_control{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"HP" = ( +/obj/structure/table, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/turf/floor/tiled, +/area/ministation/engine) +"HQ" = ( +/obj/structure/table, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/turf/floor/tiled, +/area/ministation/engine) +"HR" = ( +/obj/structure/table, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/turf/floor/tiled, +/area/ministation/engine) +"HS" = ( +/obj/structure/transit_tube{ + icon_state = "N-S" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"HT" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"HU" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"HV" = ( +/obj/structure/transit_tube{ + icon_state = "N-S-Pass" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/turf/space, +/area/space) +"HW" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black, +/obj/machinery/door/blast/regular{ + id_tag = "EngineVent" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"HY" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/solar, +/turf/floor/plating, +/area/space) +"Ia" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Ib" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/flora/pottedplant/aquatic, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ic" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/carpet/orange, +/area/ministation/engine) +"If" = ( +/obj/structure/cable, +/obj/machinery/power/solar, +/turf/floor/plating, +/area/space) +"Ig" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "starboard_engineering_vent"; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/engine) +"Ih" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ii" = ( +/obj/structure/closet/crate/solar_assembly, +/turf/floor/plating, +/area/ministation/engine) +"Ij" = ( +/obj/machinery/atmospherics/unary/tank/air, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ik" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sat2_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sat2_airlock"; + name = "interior access button"; + pixel_x = 10; + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Il" = ( +/turf/floor/plating, +/area/ministation/ai_sat) +"Im" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"In" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Io" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/black/full, +/turf/floor/reinforced/carbon_dioxide, +/area/ministation/atmospherics) +"Ip" = ( +/obj/machinery/atmospherics/binary/pump/on{ + dir = 4 + }, +/obj/machinery/camera/network/ministation/sat, +/turf/floor/plating, +/area/ministation/ai_sat) +"Iq" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"It" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/space) +"Iu" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/ai_sat) +"Iv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/wall/r_wall, +/area/ministation/ai_sat) +"Iw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_sat) +"Ix" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock, +/turf/floor/plating, +/area/ministation/ai_sat) +"Iy" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/wall/r_wall, +/area/ministation/ai_sat) +"Iz" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"IA" = ( +/obj/machinery/camera/autoname, +/turf/floor/pool, +/area/ministation/dorms) +"ID" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/ministation/ai_sat) +"IE" = ( +/obj/machinery/camera/autoname{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"IF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/wall/r_wall, +/area/ministation/ai_sat) +"IG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/ai_sat) +"IH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/cargo) +"II" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/plating, +/area/ministation/ai_sat) +"IJ" = ( +/obj/machinery/alarm{ + pixel_y = 28 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"IK" = ( +/obj/machinery/camera/network/mining, +/obj/machinery/atm{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -32 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"IL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/random/maintenance, +/obj/structure/rack, +/turf/floor/plating, +/area/ministation/ai_upload) +"IM" = ( +/obj/machinery/apc{ + name = "_South APC"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"IN" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"IO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Cargo Technician" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"IP" = ( +/obj/structure/closet, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/obj/item/backpack, +/obj/item/backpack, +/obj/item/backpack, +/obj/item/backpack, +/obj/item/backpack, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"IQ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"IR" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 1 + }, +/turf/space, +/area/space) +"IW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"IX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 4; + icon_state = "pdoor0"; + id_tag = "scraplock"; + name = "External Blast Doors"; + opacity = 0 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/atmospherics) +"IY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 8 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"IZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/engine) +"Jb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Jc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Jd" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 0; + id_tag = "sat3_airlock"; + pixel_y = 24; + tag_airpump = "sat3_vent"; + tag_chamber_sensor = "sat3_sensor"; + tag_exterior_door = "sat3_airlock_exterior"; + tag_interior_door = "sat3_airlock_interior" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "sat3_vent" + }, +/obj/machinery/airlock_sensor{ + id_tag = "sat3_sensor"; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Je" = ( +/turf/wall/r_wall, +/area/ministation/maint/eastatmos) +"Jf" = ( +/obj/machinery/meter, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Jg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/wall/r_wall, +/area/ministation/ai_core) +"Jh" = ( +/turf/wall/r_wall, +/area/ministation/ai_core) +"Ji" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"Jj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/random/trash, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"Jk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Jl" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup, +/turf/floor/plating, +/area/ministation/engine) +"Jm" = ( +/obj/structure/table, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/button/alternate/door/bolts{ + name = "AI core door bolts"; + id_tag = "aibolt" + }, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"Jn" = ( +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"Jo" = ( +/obj/structure/table, +/obj/item/folder/blue, +/obj/machinery/camera/motion/ministation, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Jp" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Jq" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen{ + pixel_x = 4; + pixel_y = 4 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Jr" = ( +/obj/structure/table, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/item/aicard, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"Jt" = ( +/turf/floor/plating, +/area/space) +"Ju" = ( +/obj/structure/hygiene/shower{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted, +/obj/structure/curtain/open/shower, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"Jv" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/ministation/ai_sat) +"Jw" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Jx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Jy" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Jz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"JA" = ( +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"JB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/wall/r_wall, +/area/ministation/ai_core) +"JC" = ( +/obj/machinery/porta_turret{ + dir = 4; + id_tag = "upload" + }, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"JD" = ( +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"JE" = ( +/obj/machinery/porta_turret{ + dir = 8; + id_tag = "upload" + }, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"JG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"JH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"JI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"JJ" = ( +/turf/floor/bluegrid, +/area/ministation/ai_core) +"JK" = ( +/obj/machinery/flasher{ + pixel_y = -21; + dir = 1 + }, +/obj/machinery/ai_slipper{ + uses = 10 + }, +/obj/machinery/light, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"JL" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"JM" = ( +/obj/machinery/hologram/holopad, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"JN" = ( +/turf/wall/r_wall, +/area/ministation/ai_upload) +"JO" = ( +/obj/structure/cable, +/obj/machinery/power/tracker, +/turf/floor/plating, +/area/space) +"JP" = ( +/obj/structure/transit_tube{ + icon_state = "N-SE" + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"JQ" = ( +/obj/structure/transit_tube{ + icon_state = "D-SW" + }, +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/space, +/area/space) +"JR" = ( +/turf/floor/tiled, +/area/ministation/ai_sat) +"JS" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"JT" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"JU" = ( +/turf/wall, +/area/ministation/ai_core) +"JV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"JW" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/item/stock_parts/circuitboard/aiupload, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"JX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"JY" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 4 + }, +/obj/item/stock_parts/circuitboard/borgupload, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Ka" = ( +/obj/structure/transit_tube{ + icon_state = "D-NE" + }, +/turf/space, +/area/space) +"Kb" = ( +/obj/structure/transit_tube{ + icon_state = "E-NW" + }, +/turf/space, +/area/space) +"Kc" = ( +/obj/structure/lattice, +/obj/structure/transit_tube{ + icon_state = "E-W-Pass" + }, +/turf/space, +/area/space) +"Kd" = ( +/obj/structure/transit_tube, +/obj/structure/lattice, +/turf/space, +/area/space) +"Ke" = ( +/obj/structure/transit_tube, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Kf" = ( +/obj/structure/transit_tube, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Kg" = ( +/obj/structure/transit_tube/station{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Kh" = ( +/obj/structure/transit_tube{ + dir = 8; + icon_state = "Block" + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Ki" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 6 + }, +/obj/machinery/meter, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Kj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"Kk" = ( +/obj/machinery/porta_turret{ + dir = 4; + id_tag = "aihome" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Kl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"Km" = ( +/obj/machinery/ai_slipper{ + uses = 10 + }, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"Kn" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_x = -27; + pixel_y = 5 + }, +/obj/item/radio/intercom{ + listening = 0; + name = "Custom Channel"; + pixel_y = 20 + }, +/obj/item/radio/intercom{ + frequency = 1447; + name = "Private Channel"; + pixel_x = 27; + pixel_y = 5 + }, +/obj/machinery/newscaster{ + pixel_x = -32; + pixel_y = 32 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = 31 + }, +/obj/structure/aicore/deactivated, +/obj/abstract/landmark/start/ai, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"Ko" = ( +/obj/machinery/porta_turret{ + dir = 8; + id_tag = "aihome" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Kp" = ( +/obj/structure/table, +/obj/item/aiModule/asimov, +/obj/item/aiModule/corp, +/obj/item/aiModule/dais, +/obj/item/aiModule/paladin, +/obj/item/aiModule/protectStation, +/obj/item/aiModule/quarantine, +/obj/item/aiModule/reset, +/obj/item/aiModule/robocop, +/obj/item/aiModule/safeguard, +/obj/item/aiModule/tyrant, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Kq" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Kr" = ( +/obj/machinery/computer/upload/ai{ + dir = 1 + }, +/obj/machinery/flasher{ + pixel_y = -20; + dir = 1 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Ks" = ( +/obj/structure/cable, +/obj/machinery/apc{ + name = "_South APC"; + pixel_y = -24 + }, +/turf/floor/bluegrid, +/area/ministation/ai_upload) +"Kt" = ( +/obj/item/radio/intercom{ + broadcasting = 1; + frequency = 1447; + listening = 0; + name = "Station Intercom (AI Private)"; + pixel_y = -30; + dir = 1 + }, +/obj/machinery/computer/upload/robot{ + dir = 1 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Ku" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Kv" = ( +/obj/structure/table, +/obj/machinery/recharger, +/turf/floor/tiled/techmaint, +/area/ministation/ai_upload) +"Kw" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"Kx" = ( +/obj/machinery/door/window/southright, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"Ky" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/machinery/flasher{ + pixel_x = -6; + pixel_y = 24 + }, +/obj/machinery/camera/motion/ministation, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"Kz" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/ministation/trash) +"KA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/computer/modular/preset/engineering{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"KB" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"KC" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/computer/modular/preset/security{ + dir = 8 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"KD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KE" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/ministation/ai_sat) +"KF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 28 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KH" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/table/marble, +/obj/item/grooming/brush, +/obj/item/grooming/brush, +/obj/item/grooming/comb, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"KJ" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/computer/modular/preset/medical{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"KK" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"KL" = ( +/obj/machinery/power/terminal, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"KM" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"KO" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/ministation/ai_sat) +"KP" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KQ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KR" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/ministation/ai_sat) +"KS" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KU" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/ai_sat) +"KY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"KZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/wall, +/area/ministation/ai_sat) +"La" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/wall, +/area/ministation/ai_sat) +"Lb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/turf/floor/plating, +/area/space) +"Lc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ld" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_sat) +"Le" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Lf" = ( +/obj/machinery/apc{ + dir = 8; + name = "MiniSat Maint APC"; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = 31 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lg" = ( +/obj/structure/rack, +/obj/item/toolbox/electrical{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/toolbox/mechanical, +/obj/item/multitool, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lh" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Li" = ( +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/smes/buildable/max_cap_in_out, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lj" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/camera/network/ministation/sat, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lk" = ( +/obj/structure/rack, +/obj/item/crowbar/red, +/obj/item/wrench, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Ll" = ( +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_x = 22; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lm" = ( +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ln" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lo" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lp" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lq" = ( +/obj/structure/sign/department/cargo{ + dir = 1; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Lr" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Ls" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/blue{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/meter, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Lt" = ( +/obj/structure/hygiene/shower{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted{ + dir = 1 + }, +/obj/item/soap, +/obj/structure/curtain/open/shower, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"Lu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Lv" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lw" = ( +/obj/abstract/landmark{ + name = "xeno_spawn"; + pixel_x = -1 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lx" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Ly" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"Lz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LB" = ( +/obj/machinery/recharge_station, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LC" = ( +/obj/structure/table, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/cable_coil/yellow, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LD" = ( +/obj/item/stool, +/obj/item/radio, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LE" = ( +/obj/structure/bed, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LF" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/item/stack/material/puck/mapped/uranium/ten, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LG" = ( +/obj/structure/cable, +/obj/machinery/port_gen/pacman/super, +/turf/floor/tiled, +/area/ministation/ai_sat) +"LI" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"LJ" = ( +/obj/effect/shuttle_landmark/supply/station, +/turf/space, +/area/ministation/supply_dock) +"LO" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"LP" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"LS" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled, +/area/ministation/eva) +"LY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"LZ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/double{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"Ma" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 5 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"Mc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/autoname{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Md" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Mg" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/hydrogen, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/engine) +"Mh" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/engine) +"Mj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ml" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200 + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Mm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/ministation/sat{ + dir = 1 + }, +/obj/machinery/turretid/stun{ + control_area = "\improper AI Upload Chamber"; + id_tag = "aihome"; + pixel_y = -24; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Mn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Mo" = ( +/obj/structure/closet/crate, +/obj/item/stock_parts/circuitboard/smes, +/obj/item/stock_parts/circuitboard/smes, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil/super_io, +/turf/floor/plating, +/area/ministation/engine) +"Mq" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Mv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/green, +/turf/floor/tiled, +/area/ministation/engine) +"Mx" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Mz" = ( +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"MB" = ( +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/item/stool/padded, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"MC" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = 12; + dir = 8; + pixel_x = 24 + }, +/turf/floor/carpet/orange, +/area/ministation/engine) +"ME" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/structure/cable/cyan{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"MF" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/item/stool/padded, +/turf/floor/carpet/green, +/area/ministation/dorms) +"MI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"MJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"MK" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"ML" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"MM" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "smsafetydoor" + }, +/turf/floor/tiled, +/area/ministation/engine) +"MN" = ( +/obj/structure/closet/l3closet/janitor, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/bag/trash, +/obj/item/bag/trash, +/obj/item/bag/trash, +/obj/item/bag/trash, +/turf/floor/tiled, +/area/ministation/janitor) +"MR" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/engine) +"MS" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"MT" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/fulltile, +/obj/machinery/door/airlock/double/mining{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"MW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastexterior" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"MX" = ( +/turf/wall, +/area/ministation/trash) +"MZ" = ( +/obj/machinery/door/airlock/atmos, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/supermatter) +"Nc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Ne" = ( +/obj/structure/closet/lasertag/red, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Nf" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 1 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/atmospherics) +"Ng" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Nh" = ( +/obj/structure/sign/directions/engineering{ + pixel_x = -32; + pixel_y = -32 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4; + icon_state = "warningcorner" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ni" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock{ + pixel_x = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Nm" = ( +/obj/abstract/landmark{ + name = "blobstart" + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Nq" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/item/eftpos, +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Ns" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Nu" = ( +/obj/abstract/landmark/start{ + name = "Head Engineer" + }, +/obj/structure/chair/office{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/yew, +/area/ministation/engine) +"Nw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"Nx" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -34; + dir = 1; + pixel_x = 9 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"NB" = ( +/obj/machinery/camera/network/engineering{ + name = "SM North" + }, +/obj/machinery/apc{ + name = "SM APC"; + pixel_y = 20; + dir = 1 + }, +/obj/structure/cable/cyan{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"NF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/s1) +"NH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"NI" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"NL" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "l1ne_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "l1ne_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = 10; + command = "cycle_exterior" + }, +/turf/floor/plating/airless, +/area/ministation/maint/l1ne) +"NM" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/space) +"NN" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + dir = 1; + external_pressure_bound = 0; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; + internal_pressure_bound_default = 2000; + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/hydrogen, +/area/ministation/atmospherics) +"NO" = ( +/obj/abstract/level_data_spawner/main_level, +/turf/space, +/area/space) +"NQ" = ( +/turf/floor/plating, +/area/ministation/engine) +"NR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/sign/directions/cargo/supply{ + dir = 1; + pixel_x = -32; + pixel_y = 32 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"NS" = ( +/obj/machinery/door/airlock/atmos, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/reinforced/airless, +/area/ministation/supermatter) +"NU" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 1; + id_tag = "sat2_airlock"; + pixel_y = -24; + tag_airpump = "sat2_vent"; + tag_chamber_sensor = "sat2_sensor"; + tag_exterior_door = "sat2_airlock_exterior"; + tag_interior_door = "sat2_airlock_interior" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "sat2_vent" + }, +/obj/machinery/airlock_sensor{ + id_tag = "sat2_sensor"; + pixel_y = -20; + pixel_x = -10; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"NV" = ( +/obj/machinery/atmospherics/unary/vent_pump/engine{ + dir = 4; + external_pressure_bound = 100; + external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "cooling_out"; + initialize_directions = 1; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/airless, +/area/ministation/supermatter) +"NW" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ + dir = 10 + }, +/obj/machinery/meter, +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"NX" = ( +/turf/floor/plating, +/area/ministation/maint/l1central) +"NY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Oa" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/engine) +"Oc" = ( +/obj/machinery/conveyor_switch/oneway{ + id_tag = "mining_transfer"; + name = "mining conveyor" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"Oe" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/plating, +/area/ministation/engine) +"Of" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Og" = ( +/obj/machinery/door/airlock/external{ + locked = 1; + id_tag = "starboard_engineering_airlock_exterior"; + autoset_access = 0 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/button/access/interior{ + id_tag = "starboard_engineering_airlock"; + name = "exterior access button"; + pixel_x = 10; + pixel_y = 20; + command = "cycle_exterior" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/engine) +"Oh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Oi" = ( +/obj/machinery/light_switch{ + pixel_y = 8; + dir = 4; + pixel_x = -23 + }, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/obj/structure/table/reinforced, +/obj/item/book/manual/supermatter_engine, +/turf/floor/tiled, +/area/ministation/supermatter) +"Oj" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, +/turf/floor/plating, +/area/space) +"Om" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"On" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"Oo" = ( +/obj/structure/fitness/weightlifter, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Or" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Os" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/trash) +"Ot" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/plating, +/area/ministation/engine) +"Ov" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/hall/n) +"Ow" = ( +/obj/machinery/camera/network/mining{ + dir = 1 + }, +/obj/item/ore_satchel, +/turf/floor/plating/airless, +/area/space) +"Oy" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/item/firstaid/regular{ + pixel_x = 6; + pixel_y = -5 + }, +/obj/structure/table, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/item/suit_cooling_unit, +/turf/floor/tiled, +/area/ministation/eva) +"Oz" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastexterior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"OA" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"OC" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/eva) +"OE" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/red{ + dir = 8 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"OF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/sign/warning/vent_port{ + dir = 1; + pixel_y = -34 + }, +/turf/floor/tiled, +/area/ministation/engine) +"OG" = ( +/obj/machinery/apc{ + name = "_South APC"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/ministation/eva) +"OH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/yellow/diagonal, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"OJ" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"OK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"ON" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/n) +"OO" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sat3_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sat3_airlock"; + name = "exterior access button"; + pixel_x = -10; + pixel_y = 20; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"OQ" = ( +/obj/machinery/door/airlock/glass/command{ + autoset_access = 0; + name = "Telecommunications relay airlock"; + req_access = list("ACCESS_TELECOMS") + }, +/turf/floor/tiled, +/area/ministation/engine) +"OR" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "mining_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "mining_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = 10; + command = "cycle_exterior" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating/airless, +/area/ministation/cargo) +"OS" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/machinery/emitter{ + anchored = 1; + id_tag = "EngineEmitter"; + state = 2 + }, +/obj/structure/cable, +/turf/floor/plating, +/area/ministation/supermatter) +"OT" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"OU" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"OV" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"OW" = ( +/obj/structure/sign/directions/cargo/supply{ + dir = 1; + pixel_x = -32; + pixel_y = 32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning/corner{ + icon_state = "warningcorner" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"OX" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "atmos_airlock_interior"; + locked = 1 + }, +/obj/machinery/button/access/interior{ + id_tag = "atmos_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor, +/area/ministation/maint/eastatmos) +"OY" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"OZ" = ( +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "SupermatterPort"; + name = "Reactor Blast Door" + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Pa" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/s1) +"Pb" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Pc" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"Pe" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/cargo) +"Pg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ph" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/yew, +/area/ministation/engine) +"Pi" = ( +/obj/machinery/drone_fabricator/maintenance, +/turf/floor/plating, +/area/ministation/engine) +"Pl" = ( +/obj/structure/sign/warning/airlock{ + pixel_x = 32; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Pm" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/smes/buildable/max_cap_in_out{ + capacity = 5e+009; + charge = 5e+009 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/smcontrol) +"Po" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Pp" = ( +/turf/space, +/area/ministation/supply_dock) +"Pq" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/table, +/obj/item/megaphone, +/obj/item/box, +/turf/floor/tiled, +/area/ministation/cargo) +"Pr" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = -14 + }, +/turf/space, +/area/space) +"Ps" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/smcontrol) +"Pw" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 6 + }, +/obj/machinery/atmospherics/valve/open, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Px" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/effect/floor_decal/corner/purple/full, +/turf/floor/reinforced/hydrogen, +/area/ministation/atmospherics) +"Py" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Pz" = ( +/obj/machinery/atmospherics/unary/heat_exchanger, +/turf/floor/plating, +/area/ministation/supermatter) +"PC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"PD" = ( +/turf/wall/r_wall, +/area/ministation/atmospherics) +"PE" = ( +/obj/machinery/atmospherics/portables_connector, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"PF" = ( +/obj/random/trash, +/turf/floor/tiled, +/area/ministation/engine) +"PH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"PI" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"PK" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"PM" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 8 + }, +/obj/machinery/meter{ + id_tag = "wloop_atm_meter" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"PN" = ( +/obj/machinery/vending/snix{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"PO" = ( +/obj/machinery/camera/autoname{ + dir = 8 + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"PQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"PR" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"PT" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/black/full, +/turf/floor/reinforced/carbon_dioxide, +/area/ministation/atmospherics) +"PW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"PZ" = ( +/obj/machinery/door/airlock/atmos, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/supermatter) +"Qa" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "smsafetydoor" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Qe" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Qg" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/tiled, +/area/ministation/smcontrol) +"Qh" = ( +/obj/structure/table/gamblingtable, +/obj/item/flashlight/lamp/green, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/carpet/blue2, +/area/ministation/hall/s1) +"Qj" = ( +/obj/machinery/atmospherics/binary/circulator{ + anchored = 1; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Qk" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/eva) +"Ql" = ( +/obj/machinery/atmospherics/binary/pump, +/turf/floor/plating, +/area/ministation/engine) +"Qn" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/pool, +/area/ministation/dorms) +"Qo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Qq" = ( +/obj/structure/closet/crate/bin/ministation, +/turf/floor/tiled, +/area/ministation/hall/n) +"Qt" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Qv" = ( +/obj/structure/supermatter, +/obj/machinery/mass_driver{ + id_tag = "eject" + }, +/turf/floor/reinforced/airless, +/area/ministation/supermatter) +"Qw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Qz" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"QA" = ( +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"QC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/vent_port{ + dir = 1; + pixel_y = -34 + }, +/turf/floor/tiled, +/area/ministation/engine) +"QD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"QE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled, +/area/ministation/smcontrol) +"QG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/s1) +"QH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"QM" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"QN" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"QO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"QP" = ( +/obj/machinery/door/airlock/command, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/eva) +"QR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/pool, +/area/ministation/dorms) +"QS" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"QU" = ( +/obj/machinery/vending/coffee{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"QV" = ( +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/space, +/area/space) +"QW" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/space, +/area/space) +"QY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"QZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"Ra" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"Rb" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/janitor) +"Rc" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/turf/floor/plating, +/area/space) +"Re" = ( +/obj/machinery/light_switch{ + pixel_y = 25 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Rf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/department/eva{ + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Rg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/laminate/yew, +/area/ministation/engine) +"Rh" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "cargo_vent" + }, +/obj/machinery/airlock_sensor{ + id_tag = "cargo2_sensor"; + pixel_y = -20; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/cargo) +"Rj" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/effect/decal/cleanable/blood/oil, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/rack{ + dir = 8 + }, +/obj/item/tank/jetpack/carbondioxide, +/obj/item/tank/jetpack/carbondioxide, +/obj/item/clothing/shoes/magboots, +/obj/item/clothing/shoes/magboots, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/eva) +"Rl" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"Rm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/drill_brace, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"Ro" = ( +/obj/structure/table/laminate, +/obj/item/clothing/mask/snorkel, +/obj/item/clothing/mask/snorkel, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/pool, +/area/ministation/dorms) +"Rp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Rq" = ( +/obj/structure/lattice, +/obj/machinery/mech_recharger, +/turf/floor/plating/airless, +/area/ministation/mining) +"Rr" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Rs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Rt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Ru" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/wall/r_wall, +/area/ministation/ai_core) +"Rv" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n) +"Rw" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Rz" = ( +/obj/machinery/atmospherics/valve/digital{ + dir = 4; + name = "Emergency Cooling Valve 1" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"RA" = ( +/obj/structure/closet/boxinggloves, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"RB" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/structure/closet/secure_closet{ + req_access = list("ACCESS_MEDICAL_EQUIP"); + closet_appearance = /decl/closet_appearance/secure_closet/medical/alt; + name = "Doctor locker" + }, +/obj/item/clothing/suit/space/void/medical, +/obj/item/clothing/suit/space/void/medical, +/obj/item/clothing/head/helmet/space/void/medical, +/obj/item/clothing/head/helmet/space/void/medical, +/turf/floor/tiled, +/area/ministation/eva) +"RC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"RD" = ( +/obj/structure/curtain/open/bed, +/obj/structure/bed/padded, +/obj/item/bedsheet/ce, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"RE" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "l1ne_airlock"; + pixel_y = null; + tag_airpump = "l1ne_vent"; + tag_chamber_sensor = "l1ne_sensor"; + tag_exterior_door = "l1ne_airlock_exterior"; + tag_interior_door = "l1ne_airlock_interior"; + dir = 4; + pixel_x = -20 + }, +/obj/machinery/airlock_sensor{ + id_tag = "l1ne_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"RF" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"RH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/material_processing/compressor, +/turf/floor/plating, +/area/ministation/trash) +"RM" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock{ + pixel_x = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"RN" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/s1) +"RO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"RP" = ( +/obj/random/trash, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/engine) +"RR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/plating, +/area/ministation/trash) +"RS" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"RU" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"RW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"RX" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/tiled, +/area/ministation/engine) +"RY" = ( +/mob/living/simple_animal/hostile/parrot/Poly, +/obj/structure/table/reinforced, +/obj/item/chems/drinks/glass2/coffeecup/one, +/turf/floor/laminate/yew, +/area/ministation/engine) +"Sa" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"Sb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/eva) +"Se" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Sf" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Sg" = ( +/obj/structure/closet/crate/solar, +/turf/floor/plating, +/area/ministation/engine) +"Sj" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"Sk" = ( +/obj/machinery/camera/network/ministation/sat, +/turf/floor/plating, +/area/ministation/ai_sat) +"Sm" = ( +/obj/structure/tank_rack/oxygen, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"So" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/n) +"Sp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Sq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Sr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor, +/area/ministation/maint/eastatmos) +"Ss" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"St" = ( +/obj/effect/floor_decal/corner/black{ + dir = 5 + }, +/obj/machinery/atmospherics/binary/pump/high_power, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Su" = ( +/turf/floor/pool, +/area/ministation/dorms) +"Sv" = ( +/obj/item/toy/ringbell, +/obj/structure/table/steel, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Sw" = ( +/obj/structure/cable, +/obj/machinery/apc{ + name = "SM APC"; + pixel_x = -27; + pixel_y = null; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/smcontrol) +"SB" = ( +/obj/machinery/door/blast/regular{ + id_tag = "EngineVent" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"SD" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/engine) +"SE" = ( +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/machinery/camera/autoname, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"SF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/sign/warning/vent_port{ + dir = 1; + pixel_y = -34 + }, +/turf/floor/tiled, +/area/ministation/engine) +"SG" = ( +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"SI" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"SJ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled, +/area/ministation/smcontrol) +"SK" = ( +/obj/machinery/material_processing/smeltery, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"SM" = ( +/obj/machinery/light_switch{ + pixel_y = 26; + dir = 4; + pixel_x = -23 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/chair/office, +/turf/floor/tiled, +/area/ministation/smcontrol) +"SO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"SQ" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/tiled, +/area/ministation/engine) +"SR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"ST" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"SU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"SV" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"SW" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/camera/network/engineering, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"SY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"SZ" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector, +/turf/floor, +/area/ministation/maint/eastatmos) +"Tb" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"Td" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"Tg" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Ti" = ( +/obj/structure/filing_cabinet, +/turf/floor/tiled, +/area/ministation/cargo) +"Tj" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Tl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + id_tag = "stern_engineering_airlock_interior"; + locked = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/engine) +"Tm" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/red, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Tp" = ( +/obj/structure/table, +/obj/item/stack/material/cardstock/mapped/cardboard/fifty, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/item/stack/material/pane/mapped/glass/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/ten, +/obj/machinery/camera/network/mining, +/turf/floor/tiled, +/area/ministation/cargo) +"Tr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, +/area/ministation/ai_upload) +"Tt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/airlock_sensor{ + id_tag = "starboard_engineering_sensor"; + pixel_y = 20 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "starboard_engineering_airlock"; + pixel_y = 24; + tag_airpump = "starboard_engineering_vent"; + tag_chamber_sensor = "starboard_engineering_sensor"; + tag_exterior_door = "starboard_engineering_airlock_exterior"; + tag_interior_door = "starboard_engineering_airlock_interior" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/engine) +"Tu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Tv" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "atmos_vent" + }, +/obj/machinery/airlock_sensor{ + id_tag = "atmos_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "atmos_airlock"; + pixel_y = null; + tag_airpump = "atmos_vent"; + tag_chamber_sensor = "atmos_sensor"; + tag_exterior_door = "atmos_airlock_exterior"; + tag_interior_door = "atmos_airlock_interior"; + dir = 4; + pixel_x = -20 + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Tw" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Tx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 4 + }, +/turf/floor/plating, +/area/space) +"Ty" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Tz" = ( +/obj/machinery/camera/network/engineering{ + dir = 1; + name = "Tank Storage" + }, +/turf/floor/plating, +/area/ministation/engine) +"TA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"TB" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"TC" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/mirrored{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n) +"TE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"TH" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/s1) +"TJ" = ( +/obj/machinery/disposal/deliveryChute{ + dir = 8; + name = "disposals ejection chute" + }, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/trash) +"TK" = ( +/obj/structure/rack{ + dir = 8 + }, +/obj/item/clothing/suit/hazardvest, +/obj/item/tank/emergency/oxygen/engi, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"TL" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "smsafetydoor" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"TM" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/space) +"TO" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"TP" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"TR" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l1central) +"TT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/engine) +"TX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"TY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"TZ" = ( +/obj/structure/sign/warning/vent_port{ + pixel_y = 28 + }, +/turf/space, +/area/space) +"Ua" = ( +/obj/structure/table/laminate, +/obj/item/clothing/mask/snorkel, +/obj/item/clothing/mask/snorkel, +/turf/floor/pool, +/area/ministation/dorms) +"Uc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Ud" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Ue" = ( +/obj/structure/table/gamblingtable, +/obj/machinery/chemical_dispenser/bar_alc/full, +/turf/floor/laminate/yew, +/area/ministation/engine) +"Ug" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 1 + }, +/obj/machinery/meter, +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Uh" = ( +/obj/machinery/atmospherics/pipe/simple/visible/black, +/turf/floor/plating, +/area/ministation/supermatter) +"Ui" = ( +/turf/floor/reinforced/airless, +/area/ministation/supermatter) +"Uj" = ( +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Uk" = ( +/obj/machinery/door/window/southleft, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, +/turf/floor/tiled, +/area/ministation/engine) +"Ul" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Um" = ( +/obj/random/trash, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Uq" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Ur" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Uu" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/turf/floor/plating, +/area/space) +"Uv" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/plating, +/area/ministation/supermatter) +"Ux" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"UA" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"UC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"UE" = ( +/obj/machinery/door/window/southleft, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/conveyor{ + id_tag = "CanisterStore" + }, +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/turf/floor/tiled, +/area/ministation/engine) +"UG" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/suit_cycler/ministation, +/turf/floor/tiled, +/area/ministation/eva) +"UI" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/ministation/eva) +"UJ" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"UK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/pool, +/area/ministation/dorms) +"UO" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"US" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/green, +/turf/floor/tiled, +/area/ministation/engine) +"UT" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/engine) +"UU" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/engine) +"UV" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "mining_airlock"; + pixel_y = null; + tag_airpump = "mining_vent"; + tag_chamber_sensor = "mining_sensor"; + tag_exterior_door = "mining_airlock_exterior"; + tag_interior_door = "mining_airlock_interior"; + dir = 4; + pixel_x = -20 + }, +/obj/machinery/airlock_sensor{ + id_tag = "mining_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/cargo) +"UW" = ( +/obj/effect/floor_decal/corner/black{ + dir = 1 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"UX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/floor/plating, +/area/space) +"UY" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging, +/turf/floor/plating, +/area/space) +"Vb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Vc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/ai_sat) +"Ve" = ( +/obj/abstract/landmark/start{ + name = "Station Engineer" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/tiled, +/area/ministation/engine) +"Vf" = ( +/obj/structure/curtain/open/bed, +/obj/structure/bed/padded, +/obj/item/bedsheet/ce, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Vj" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/pool, +/area/ministation/dorms) +"Vk" = ( +/obj/structure/lattice, +/obj/structure/transit_tube{ + icon_state = "N-S-Pass" + }, +/turf/space, +/area/space) +"Vl" = ( +/obj/structure/closet, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Vm" = ( +/obj/structure/cable/yellow{ + icon_state = "2-8" + }, +/obj/machinery/camera/network/engineering{ + dir = 8; + name = "SM Command" + }, +/turf/floor/tiled, +/area/ministation/smcontrol) +"Vn" = ( +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Vq" = ( +/obj/machinery/merchant_pad, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Vr" = ( +/obj/machinery/atmospherics/valve/digital{ + dir = 4; + name = "Emergency Cooling Valve 1" + }, +/turf/floor/plating, +/area/ministation/engine) +"Vs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/pool, +/area/ministation/dorms) +"Vx" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/engine) +"Vy" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled, +/area/ministation/cargo) +"VA" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sat1_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sat1_airlock"; + name = "interior access button"; + pixel_x = 10; + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"VC" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"VF" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"VG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/sign/warning/airlock, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"VH" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/machinery/door/airlock/double/glass/atmos{ + req_access = list("ACCESS_ENGINEERING"); + autoset_access = 0; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/engine) +"VJ" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l1ne) +"VK" = ( +/obj/machinery/ai_slipper{ + uses = 10 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/bluegrid, +/area/ministation/ai_core) +"VL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/trash) +"VM" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/turf/space, +/area/space) +"VO" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating/airless, +/area/space) +"VP" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black, +/turf/floor/plating, +/area/ministation/supermatter) +"VR" = ( +/obj/machinery/fabricator, +/turf/floor/tiled, +/area/ministation/cargo) +"VT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"VV" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"VX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/warning/vent_port{ + dir = 1; + pixel_y = -34 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/black, +/turf/floor/tiled, +/area/ministation/engine) +"VZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hall/s1) +"Wa" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastexterior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/ministation/supermatter) +"Wb" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark{ + name = "lightsout" + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Wc" = ( +/obj/structure/closet/crate, +/obj/item/stack/material/ore/handful/sand, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/cargo) +"Wd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/status_display{ + pixel_y = -32; + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Wi" = ( +/obj/structure/disposaloutlet, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Wj" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine charging port."; + id_tag = "SupermatterPort"; + name = "Reactor Blast Doors"; + pixel_x = -6; + pixel_y = 7; + directional_offset = null + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine control room blast doors."; + id_tag = "EngineBlastexterior"; + name = "Engine Bay Blast Doors"; + pixel_y = -3; + pixel_x = 5; + directional_offset = null + }, +/obj/machinery/button/blast_door{ + desc = "A remote control-switch for the engine control room blast doors."; + id_tag = "EngineBlastinterior"; + name = "Engine Monitoring Room Blast Doors"; + pixel_y = -3; + pixel_x = -6; + directional_offset = null + }, +/obj/machinery/button/toggle{ + desc = "A remote control-switch for the engine emitter."; + id_tag = "EngineEmitter"; + name = "Engine Emitter"; + pixel_x = 6; + pixel_y = 7; + directional_offset = null + }, +/turf/floor/tiled/steel_grid, +/area/ministation/smcontrol) +"Wk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"Wn" = ( +/obj/structure/sign/plaque/atmos{ + pixel_y = 32 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/engine) +"Wr" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/machinery/camera/network/engineering{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/engine) +"Ws" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/vehicle/train/engine, +/turf/floor/tiled, +/area/ministation/cargo) +"Wt" = ( +/obj/structure/mirror{ + pixel_y = 29 + }, +/obj/structure/hygiene/sink{ + pixel_y = 23 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "bulb1" + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"Wv" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"Wx" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Wy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"Wz" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 1 + }, +/turf/space, +/area/space) +"WB" = ( +/turf/floor, +/area/ministation/maint/eastatmos) +"WE" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, +/turf/space, +/area/space) +"WF" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/trash) +"WH" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"WJ" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/engine) +"WK" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor, +/area/ministation/maint/eastatmos) +"WM" = ( +/obj/machinery/door/airlock/double/glass/civilian, +/obj/machinery/door/firedoor, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"WO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/eva) +"WP" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"WR" = ( +/obj/machinery/conveyor{ + dir = 8; + id_tag = "trash_sort" + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/plating, +/area/ministation/trash) +"WS" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"WU" = ( +/turf/floor, +/area/space) +"WV" = ( +/obj/machinery/light{ + dir = 1; + icon_state = "bulb1" + }, +/obj/structure/closet/secure_closet/atmos_personal, +/obj/item/toolbox/emergency, +/obj/item/clothing/suit/space/emergency, +/obj/item/clothing/head/helmet/space/emergency, +/obj/item/clothing/mask/breath/emergency, +/obj/item/firstaid/o2, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"WW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/eastatmos) +"WY" = ( +/obj/item/mollusc/barnacle{ + pixel_x = 20 + }, +/turf/space, +/area/space) +"Xb" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Xc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 8 + }, +/turf/floor/plating, +/area/space) +"Xf" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 1; + icon_state = "map_injector"; + id_tag = "cooling_in"; + name = "Coolant Injector"; + pixel_y = 1; + power_rating = 30000; + use_power = 1; + volume_rate = 700 + }, +/turf/floor/reinforced/airless, +/area/ministation/supermatter) +"Xg" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/n) +"Xh" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/green, +/turf/floor/tiled, +/area/ministation/engine) +"Xi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/pool, +/area/ministation/dorms) +"Xj" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Xk" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"Xm" = ( +/obj/structure/hygiene/toilet{ + dir = 1 + }, +/obj/structure/window/reinforced/tinted, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted{ + dir = 4 + }, +/turf/floor/tiled/freezer, +/area/ministation/dorms) +"Xo" = ( +/obj/structure/table/reinforced, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Xt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/turretid/stun{ + name = "AI Upload turret control"; + id_tag = "upload"; + control_area = "\improper AI Upload Chamber"; + pixel_y = -24; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/ai_upload) +"Xu" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Xw" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/mining) +"Xx" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/n) +"Xz" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/black, +/turf/floor/tiled, +/area/ministation/engine) +"XA" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "westatmos_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "westatmos_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = -10; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"XB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/wall/r_wall, +/area/ministation/ai_upload) +"XC" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/emitter, +/turf/floor/plating, +/area/ministation/engine) +"XE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"XF" = ( +/obj/machinery/drone_fabricator/construction, +/turf/floor/plating, +/area/ministation/engine) +"XI" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 6 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"XJ" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 4 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"XK" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 8 + }, +/turf/floor/plating, +/area/space) +"XL" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/pool, +/area/ministation/dorms) +"XO" = ( +/obj/structure/lattice, +/turf/wall/r_wall, +/area/ministation/engine) +"XP" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_north = 5; + tag_south = 7; + tag_west = 2 + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"XQ" = ( +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"XR" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"XT" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"XU" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"XV" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"XW" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"XY" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"XZ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/ministation/mining) +"Yi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"Yk" = ( +/obj/machinery/atmospherics/binary/pump/high_power, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"Ym" = ( +/turf/floor/tiled, +/area/ministation/eva) +"Yr" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"Ys" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible/black, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"Yt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "port_engineering_vent" + }, +/turf/floor/plating, +/area/ministation/engine) +"Yu" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/engine) +"Yv" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Yx" = ( +/obj/effect/floor_decal/industrial/custodial{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/flaps/airtight, +/obj/structure/disposaloutlet{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/plating, +/area/ministation/trash) +"Yy" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/reinforced/oxygen, +/area/ministation/atmospherics) +"Yz" = ( +/obj/machinery/atmospherics/unary/heat_exchanger{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"YA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/engine) +"YC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/engine) +"YD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"YE" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/empty, +/turf/floor/plating, +/area/ministation/supermatter) +"YF" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"YG" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sat3_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sat3_airlock"; + name = "interior access button"; + pixel_x = 10; + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"YJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/plating, +/area/ministation/engine) +"YK" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/item/janicart_key, +/turf/floor/tiled, +/area/ministation/janitor) +"YM" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 1; + name = "Air to Supply" + }, +/obj/machinery/camera/network/engineering{ + dir = 8; + name = "Atmospherics"; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"YN" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastexterior" + }, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"YT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/ministation/sat, +/turf/floor/plating, +/area/ministation/ai_sat) +"YU" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/engine) +"YV" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"YW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/engine) +"YY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/eva) +"Za" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/black{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Zd" = ( +/obj/effect/floor_decal/corner/yellow/diagonal, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/engine) +"Ze" = ( +/obj/machinery/door/airlock/external{ + locked = 1; + id_tag = "atmos_airlock_exterior"; + autoset_access = 0 + }, +/obj/machinery/button/access/interior{ + id_tag = "atmos_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = -10; + command = "cycle_exterior"; + dir = 4 + }, +/turf/floor, +/area/ministation/maint/eastatmos) +"Zf" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Recruit" + }, +/obj/item/stool/padded, +/turf/floor/carpet/green, +/area/ministation/dorms) +"Zg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/camera/autoname, +/obj/structure/table/laminate, +/obj/item/poster, +/obj/item/pen, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Zh" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable/yellow, +/turf/floor/tiled/steel_grid, +/area/ministation/smcontrol) +"Zi" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + id_tag = "EngineBlastexterior" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"Zj" = ( +/obj/effect/floor_decal/corner/blue, +/obj/effect/floor_decal/corner/yellow{ + dir = 8 + }, +/obj/machinery/suit_cycler/engineering/ministation{ + suit = /obj/item/clothing/suit/space/void/atmos; + helmet = /obj/item/clothing/head/helmet/space/void/atmos + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Zk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"Zn" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/engine) +"Zo" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"Zp" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/turf/floor/plating, +/area/ministation/engine) +"Zs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/laminate/walnut, +/area/ministation/dorms) +"Zv" = ( +/obj/structure/ladder, +/turf/floor, +/area/ministation/maint/eastatmos) +"Zx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/camera/motion/ministation, +/turf/floor/tiled/techmaint, +/area/ministation/ai_core) +"Zz" = ( +/obj/machinery/light/small, +/turf/floor/plating/airless, +/area/ministation/mining) +"ZA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/cargo) +"ZC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"ZF" = ( +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/machinery/atmospherics/binary/pump/on{ + dir = 4; + name = "Air to Ports" + }, +/turf/floor/tiled/monotile, +/area/ministation/atmospherics) +"ZG" = ( +/obj/machinery/button/blast_door{ + id_tag = "EngineVent"; + name = "3. Reactor Ventillatory Control"; + pixel_x = -22; + pixel_y = 9 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "stern_engineering_airlock"; + pixel_y = -6; + tag_airpump = "stern_engineering_vent"; + tag_chamber_sensor = "stern_engineering_sensor"; + tag_exterior_door = "stern_engineering_airlock_exterior"; + tag_interior_door = "stern_engineering_airlock_interior"; + dir = 4; + pixel_x = -20; + name = "2. Airlock Controller" + }, +/obj/machinery/button/blast_door{ + id_tag = "smsafetydoor"; + name = "1. Vent Safety"; + pixel_x = -36; + pixel_y = 9 + }, +/obj/machinery/button/mass_driver{ + pixel_y = -4; + pixel_x = -35; + id_tag = "eject"; + name = "4. SM CORE EJECT"; + dir = 4 + }, +/obj/machinery/atmospherics/valve/digital{ + dir = 1; + name = "Emergency Cooling Valve 2" + }, +/turf/floor/plating, +/area/ministation/supermatter) +"ZH" = ( +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"ZJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/maint/westatmos) +"ZK" = ( +/obj/structure/closet/crate/bin/ministation, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/railing/mapped, +/turf/floor/plating, +/area/ministation/trash) +"ZL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/cargo) +"ZM" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible/black{ + dir = 9 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/engine) +"ZR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s1) +"ZT" = ( +/obj/machinery/door/airlock/glass/atmos, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/ministation/atmospherics) +"ZU" = ( +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/supermatter) +"ZX" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/ai_sat) +"ZY" = ( +/obj/machinery/atmospherics/omni/filter{ + tag_east = 1; + tag_south = 4; + tag_west = 2; + use_power = 0 + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/supermatter) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +NO +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +af +aa +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +ab +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yY +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yS +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +GQ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +GJ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +XI +GB +GB +GC +GB +GB +GB +GB +UX +GB +GB +GB +GB +GC +GB +GB +ds +sx +sx +sx +sx +sx +sx +sx +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +GF +FE +FE +FE +FE +Gh +Gh +aa +GH +aa +Gh +Gh +FE +FE +FE +FE +VM +tl +xZ +tl +xZ +tl +xZ +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +sx +sx +sx +sx +sx +sx +ad +ad +ad +ad +ad +ad +ad +ad +WU +dp +WU +aa +aa +aa +aa +aa +GF +FF +Ga +Ga +Ga +Ga +Ga +Gw +Jt +GM +GN +GN +GN +GN +GN +GO +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +ad +aa +ad +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +PD +PD +sD +IX +sD +PD +PD +aa +aa +aa +GF +FG +FG +FG +FG +FG +FG +aa +Jt +aa +FG +FG +FG +FG +FG +FG +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +ad +ad +ad +ad +ad +ad +PD +PD +PD +PD +PD +PD +WV +QA +gc +QA +tZ +PD +PD +PD +PD +GF +aa +aa +ad +ad +aa +aa +aa +Jt +aa +aa +aa +ad +ad +aa +aa +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +XI +kC +kC +kC +GB +kC +Nf +aJ +xW +un +OE +lu +sp +RS +Tm +wi +sp +mY +wo +Uq +hw +GF +FE +FE +FE +FE +FE +FE +aa +Jt +aa +FE +FE +FE +FE +FE +FE +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +Pp +Pp +Pp +Pp +LJ +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +Yr +kC +kC +kC +ML +aa +hw +LI +aM +rt +jn +ru +ru +hK +bh +md +mD +wg +wg +dZ +hw +GF +FF +Ga +Ga +Ga +Ga +Ga +Gw +Jt +GM +GN +GN +GN +GN +GN +GO +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +XI +kC +kC +kC +Gc +tl +Nf +oQ +xW +un +ze +Io +qs +St +XJ +PE +sr +NN +fg +QO +hw +GF +FG +FG +FG +FG +FG +FG +aa +Jt +aa +FG +FG +FG +FG +FG +FG +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +Yr +kC +kC +kC +ML +mT +PD +qK +sp +oB +ze +PT +cB +rM +XP +RS +sE +cX +Px +kY +PD +GF +aa +aa +ad +ad +aa +aa +aa +Jt +aa +aa +aa +ad +ad +aa +aa +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +Pp +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +XI +kC +kC +kC +Gc +mT +PD +PD +PD +PD +uf +bY +bY +UW +oY +SG +vF +zu +yM +hb +PD +GF +dl +dl +dl +dl +dl +dl +aa +Jt +aa +dl +dl +dl +dl +dl +dl +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +ad +au +cy +ie +ie +cy +au +AC +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +Yr +GB +GB +GB +ML +Rl +ad +PD +ay +Cu +gc +SG +Ki +le +CZ +le +nM +bg +uZ +mY +PD +GF +RF +tj +tj +tj +tj +tj +Gw +Jt +GM +YF +YF +YF +YF +YF +NM +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WY +aa +ad +ad +ad +ad +ad +ad +ad +au +cy +iV +Rh +cy +au +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +ab +aa +XI +kC +kC +kC +Gc +mT +aa +PD +nc +sp +lN +CM +Pw +kx +jC +kx +xp +yW +pG +bc +PD +GF +ua +ua +ua +ua +ua +ua +aa +Jt +aa +ua +ua +ua +ua +ua +ua +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +au +au +au +au +au +au +au +au +au +au +au +au +cy +hP +jU +cy +au +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +Yr +kC +kC +kC +ML +mT +aa +ma +dX +QA +xP +Ab +bN +jM +eR +kq +nw +um +sX +kv +PD +GF +aa +aa +ad +ad +aa +aa +aa +Jt +aa +aa +aa +ad +ad +aa +aa +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +yr +cb +ck +bX +cM +de +dB +cc +fi +fL +fi +gj +gL +ho +eE +fB +Vy +hQ +fq +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +XI +GB +GB +GB +Gc +mT +aa +ma +tF +QA +hv +Yy +bO +pi +kN +gE +cG +lt +sX +Sm +PD +GF +FE +FE +FE +FE +FE +FE +aa +Jt +aa +FE +FE +FE +FE +FE +FE +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +ad +ad +ad +ad +ad +ad +cn +cn +au +cz +dC +tu +cl +dI +fj +fM +yO +Rm +ZA +SO +dI +Xu +Pe +IH +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +Yr +kC +kC +kC +ML +mT +aa +PD +bp +yZ +Du +BV +kb +cT +ju +ZF +Jf +rX +oS +Zj +PD +GF +FF +Ga +Ga +Ga +Ga +Ga +Gw +Jt +GM +GN +GN +GN +GN +GN +GO +VM +oC +mT +mT +mT +mT +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +cd +cn +bX +cO +dq +dI +dI +eF +fk +fN +gk +pT +Mq +hR +SR +iU +dI +jV +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +XI +kC +kC +kC +Gc +mT +aa +PD +ew +Vn +Zo +Ng +ZC +SY +SG +zH +Yk +Rw +pw +nR +PD +GF +FG +FG +FG +FG +FG +FG +aa +GI +aa +FG +FG +FG +FG +FG +FG +zX +nD +tk +nD +tk +nD +mT +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aw +kU +kU +kU +kU +aw +cd +Ow +au +cP +dE +eY +dI +Pq +fl +fO +gl +QZ +fF +hS +fJ +hS +dI +jW +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +aa +aa +Yr +kC +kC +kC +GB +nD +aa +PD +mJ +QA +gU +CJ +md +MI +eS +PI +eS +eS +Nc +nR +PD +Yr +GB +GB +GC +GB +GB +GB +IR +Xc +WE +GB +GB +GB +GC +GB +GB +GC +GC +GC +GC +GC +Wz +nD +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Xw +PR +PR +PR +Bp +lK +ce +wZ +bX +cN +dq +dI +dI +my +fm +dI +cf +gM +qH +hT +NI +iW +ZA +jX +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +sx +ad +aa +ad +aa +aa +aa +ad +DD +DD +DD +DD +PD +NW +pQ +gi +vq +YM +Ls +vk +tD +bb +if +PD +aa +aa +av +av +av +av +EG +XO +AB +XO +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +ad +ad +ad +sx +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Xw +oZ +Bd +Oc +Fq +aw +cm +ac +au +cQ +dq +mW +SO +CC +IO +ej +Ss +hp +Zk +hp +dI +hp +dI +Wc +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +aa +ad +DD +XY +zr +vA +PD +PD +ZT +av +av +av +av +av +av +av +XO +av +av +av +av +DF +fh +av +ad +av +GW +Ma +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aw +Wv +BQ +jR +bR +XZ +XZ +tK +Wi +cx +cx +dG +ek +ZA +fn +ZA +ZL +dI +hq +dI +dI +dI +dI +pS +au +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WU +DD +DD +DD +DD +zr +zr +zr +zr +Dv +DE +DT +qA +EJ +Fa +EP +Fs +Dt +wp +Rg +cu +Ei +Dt +rU +Bj +XO +aa +im +Yt +gm +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aw +SK +Bd +Bd +Fq +Rq +Aw +au +au +au +au +dH +nf +rC +fo +fP +rC +rC +uN +zz +lq +Ws +dI +pS +au +aa +jh +jh +jh +jh +jh +jh +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WU +lM +nY +bl +XA +re +Qz +oi +xw +DD +av +av +XR +EK +oX +PQ +FH +Dt +Ue +sb +RY +Nu +Dt +Ic +wK +av +im +VG +GV +gm +im +av +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Xw +WP +Bd +Bd +Bd +ve +TE +OR +UV +cS +cA +Pl +TP +eG +fp +fQ +go +XV +nj +au +au +au +el +au +au +jh +jh +CN +NX +NX +NX +CN +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WU +DD +DD +DD +DD +nA +RO +zr +GZ +Am +av +DV +PW +EL +Fb +EB +FI +Dt +Ak +uS +vL +Ph +uL +MC +bj +av +Gn +Gx +GX +XU +Hf +av +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +sx +sx +sx +sx +sx +sx +ad +sx +sx +sx +sx +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Xw +Bd +Bd +Bd +Zz +aw +lK +au +au +au +au +au +au +au +au +fu +au +gO +MT +au +NX +NX +NX +NX +CN +NX +NX +NX +jh +jh +jh +NX +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +DD +ps +Dv +AM +AW +iz +uK +RO +av +DW +Er +EM +Fc +Fm +FJ +Dt +Dt +rq +oF +oF +av +av +av +av +Uc +Um +UT +mV +Ft +av +av +av +av +aa +aa +aa +aa +aa +ad +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +ad +ad +ad +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aw +aw +aw +aw +aw +aw +aa +au +VR +ky +qu +gt +iq +NH +fr +fR +gq +gP +wB +au +NX +jh +MX +MX +jd +MX +MX +MX +jh +Bu +jh +NX +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +DD +DD +DD +DD +DD +DD +DD +PH +av +DX +Es +EN +Fd +Fu +FK +bB +zN +Zd +OH +EZ +EZ +EZ +EZ +Gi +Gp +Gy +EZ +Bo +ln +Hs +zg +HI +av +aa +aa +aa +aa +aa +ad +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +bX +Tp +uX +et +au +au +fu +au +au +au +gP +hs +au +NX +jh +Yx +pZ +WF +ZK +uM +do +jh +cw +qd +dw +NX +NX +CN +NX +NX +NX +CN +NX +NX +NX +NX +Tb +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +DD +TX +av +DY +Et +EO +Fe +Fv +jq +Gb +Gf +Gb +Gb +Ae +CS +Gb +Gb +Gj +Gq +Gz +NY +Ha +YA +Ht +HB +HJ +av +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +au +rD +dI +wm +au +IK +nb +ft +Vq +au +gP +ht +au +pz +jh +AN +nG +Os +qW +WR +TJ +jh +jh +jh +dF +di +di +ON +di +kZ +kZ +kZ +kZ +kZ +kZ +sV +NX +jh +jh +jh +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +DD +TX +av +DZ +wt +Ez +Ff +Fw +Ad +av +av +av +av +av +av +av +av +av +Zi +Zi +YN +av +Hg +DC +ex +HK +av +aa +aa +aa +aa +HY +GS +If +aa +HY +GS +If +aa +HY +GS +If +aa +HY +GS +If +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +au +me +dI +jI +au +Nq +vC +gs +fS +gq +gP +JV +qa +rn +jh +xX +CL +ez +mz +vf +RR +VL +VL +GL +dU +di +di +gQ +Qq +kZ +sy +MN +tr +us +kZ +Rb +TR +wD +CN +xq +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +DD +Yi +av +va +XQ +BY +EY +XQ +Aq +av +eK +eK +ur +eK +Tw +Uh +mn +PM +Yz +Pz +VP +eK +av +SQ +QS +av +av +aa +aa +aa +aa +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +bX +wN +ZH +au +au +fv +fv +aq +fv +au +gO +hu +au +NX +jh +eB +hA +rT +rT +gg +lB +MX +MX +jh +On +di +dM +qQ +Xx +kZ +eh +mS +tq +wS +kZ +yU +yp +jh +jh +jh +jh +ad +ad +ad +ad +ad +ad +ms +ms +ms +ms +ms +ad +ad +ad +ad +ad +ad +DD +TX +av +Eb +vY +FS +ER +ER +FO +Zi +eK +Gk +hk +zm +zB +eK +eK +Za +Yz +Pz +VP +eK +av +Hu +ST +av +ad +ad +ad +ad +ad +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +WY +aa +aa +au +Df +dI +au +Mx +fw +fw +gu +gQ +Xg +Ia +Lq +di +zJ +jh +RH +rT +qG +BZ +rz +xQ +MX +tB +zY +yD +di +gQ +qQ +gQ +kZ +sz +oI +ts +mS +za +NX +yp +jh +aa +aa +aa +aa +aa +aa +aa +aa +aa +ms +cg +Qh +cg +ms +aa +aa +aa +aa +aa +aa +DD +ZJ +av +vI +Ev +EQ +nx +nx +eX +av +AJ +Lr +ZY +Wx +sl +vp +eK +fE +eK +eK +VC +eK +MZ +Da +SF +av +aa +aa +aa +aa +aa +HY +GT +If +ad +HY +GT +If +ad +HY +GT +If +EG +HY +GT +If +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cr +cr +cr +cr +cr +cr +dI +AV +au +gV +fx +fx +gv +gQ +gQ +gQ +Sj +di +di +di +yL +rj +wJ +hf +Gd +Kz +MX +kM +nk +jY +di +gQ +gQ +wx +kZ +sA +YK +uE +kA +kZ +SV +yp +ms +ms +ms +ms +aa +aa +aa +aa +aa +ms +ms +cg +Bt +cg +ms +ms +aa +aa +aa +aa +aa +DD +Dw +fe +AR +av +av +yz +Fx +Se +av +As +ME +LO +yj +df +vp +YE +jA +qL +eI +QM +dD +av +Hv +MM +av +av +ad +ad +ad +ad +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +cr +aG +th +BC +bV +cr +dI +Ti +au +eM +uj +uj +gw +uY +uY +uY +TC +di +iu +di +di +di +di +di +di +kf +di +di +di +Ci +di +di +pr +di +kZ +kZ +kZ +FN +kZ +kZ +ms +vg +ms +wM +wM +ms +ms +ms +Pa +Pa +Pa +ms +Aj +Bn +tO +Bn +Ec +ms +ms +ms +ms +ms +ms +uK +qP +ms +Ed +Ew +av +av +av +FP +av +av +NB +UJ +eK +Nx +il +il +il +il +il +Qa +Qa +av +ae +HE +HL +im +aa +aa +aa +aa +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +aa +HY +GT +If +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +sO +LS +bW +Oy +cr +tW +cr +cr +xr +fz +fz +fz +gR +So +gR +OU +Md +fz +fz +fz +NR +fz +jo +fz +mr +OK +Rs +Rs +sh +Rs +Rs +rQ +Rv +rA +OW +EE +tt +mq +Nh +vV +ug +we +uh +uh +uh +uh +uh +uh +uh +uh +uh +uh +uh +uh +uh +uh +uh +ZR +uh +NF +uh +Dk +Fg +Dx +DG +Ee +VF +ET +av +Fz +FQ +ul +Wa +WS +RU +eK +Pb +NS +Xf +Ui +Ui +zR +eK +eK +Zi +bk +ST +HM +im +aa +aa +aa +aa +aa +GJ +aa +aa +aa +GJ +aa +aa +aa +GJ +aa +aa +aa +GJ +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +UG +Ym +pe +CA +ut +AU +kI +Ax +kh +gQ +gQ +Xx +kh +gQ +kh +ij +gQ +gQ +gQ +Xx +gQ +Xx +gQ +Xx +iN +ll +gQ +gQ +Jk +gQ +gQ +iN +po +aV +GU +cD +cD +sc +iE +TH +aV +sC +aV +aV +Rr +aV +aV +aV +Rr +aV +aV +aV +Rr +aV +aV +aV +aV +aV +aV +aV +aV +aV +Sq +sC +aV +sC +aV +VZ +av +iB +tg +XQ +Zi +YD +UJ +eK +dV +zR +Ui +Ui +Ui +zR +eK +eK +Zi +bk +ST +QC +im +im +im +av +TZ +aa +GH +aa +aa +aa +GH +aa +aa +aa +GH +aa +aa +aa +GH +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +aW +Ym +Ym +Sb +bC +YY +Qk +oE +px +qI +qI +fA +hY +gx +gS +eO +iM +iM +iM +iM +iM +iM +iM +iM +na +ni +OY +uY +LY +uY +OY +eo +po +aV +GU +cD +tv +cD +rf +TH +Rr +jT +Rt +Pg +Rt +Pg +Pg +Pg +Pg +Pg +Pg +Pg +Rt +Pg +Rt +Pg +Rt +Pg +Pg +Pg +Pg +Rt +fX +Dy +fy +Ef +fy +EU +Fj +FA +FR +Wb +MW +XE +Jc +OS +dV +zS +Ui +Qv +Ui +SB +eK +Tw +HW +TT +YC +Be +Tl +gW +AK +sf +Oj +UY +Rc +Jt +Jt +Jt +Jt +Jt +Jt +Jt +Jt +Jt +Jt +Jt +Jt +GM +GR +yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +RB +Ym +jL +vP +eW +yu +lC +bP +ow +gQ +Xx +gQ +MJ +lp +gQ +lp +gQ +gQ +Xx +gQ +gQ +gQ +Xx +gQ +iN +gQ +gQ +gQ +lp +gQ +gQ +gQ +po +aV +lW +cD +cD +cD +rf +TH +aV +aV +Rr +aV +aV +aV +aV +aV +aV +aV +aV +aV +aV +aV +aV +aV +aV +Rr +aV +aV +aV +aV +Mn +aV +aV +aV +aV +fZ +av +SW +lL +XQ +Zi +YD +Fy +eK +dV +zR +Ui +Ui +Ui +zR +eK +fE +Zi +SD +Xz +VX +Ys +Ys +ZM +av +TZ +aa +sT +aa +aa +aa +GI +aa +aa +aa +GI +aa +aa +aa +GI +aa +ad +OV +JO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +jz +UI +WO +Rj +cr +cr +QP +cr +Rf +wG +gT +gT +Po +gy +gT +gy +hV +gT +gT +Bq +vK +as +gT +gT +Ao +gT +gT +gT +Qt +gT +Mc +qO +ke +ui +xE +ge +ge +ge +LP +RN +ui +CE +ui +ui +ui +QG +ui +zy +EF +ui +gb +ue +ui +ui +QG +ui +Ib +ui +ui +eZ +ui +ui +AH +ui +AT +Eg +ui +EV +av +FB +PK +TK +mb +xj +TB +eK +dV +Di +NV +Ui +Ui +zR +eK +fE +Zi +bk +HC +PW +im +aa +aa +aa +aa +aa +TM +aa +aa +aa +GJ +aa +aa +aa +GJ +aa +aa +aa +GJ +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(129,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +kg +OC +dR +ml +cr +MK +OG +eu +nS +eu +fU +fU +es +fU +fU +zW +zW +zW +zW +zW +zW +zW +zW +gJ +Ov +gJ +di +di +di +di +di +di +di +ms +ms +Pa +Pa +Pa +ms +ms +ms +ms +Pa +Pa +Pa +ms +ms +ms +ms +ms +ms +ms +ms +Pa +Pa +Pa +ms +ms +ms +ms +ms +ms +hn +Dt +Dt +Eh +Ex +av +av +av +FT +oy +il +ly +AQ +oy +wd +il +OZ +zR +zR +il +Qa +TL +av +Hx +Gt +HO +im +aa +aa +aa +aa +HY +Uu +If +aa +HY +He +If +aa +HY +He +If +aa +HY +He +If +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(130,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +cr +cr +cr +cr +cr +cr +pa +AF +qr +qM +eu +SE +gX +xm +gX +tH +hc +zW +Vf +jj +Vf +qe +nN +zW +aa +DU +Pr +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Wy +hU +ak +Je +av +av +av +av +mg +XQ +Py +oy +Oi +SM +Wj +pB +dV +eK +BB +qf +yk +ZG +Ur +nn +av +Hv +HD +av +av +ad +ad +ad +ad +HY +Uu +If +aa +HY +He +If +aa +HY +He +If +aa +HY +He +If +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(131,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +aa +eu +eu +eu +eu +vv +AF +AF +IM +eu +MB +jO +tU +Zf +bi +Ux +zW +RD +qe +Vf +qe +Vf +jy +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Nw +av +av +av +nz +nz +Ey +EX +vz +DC +FV +Ps +SJ +QE +gZ +pB +HU +eK +eK +eK +jf +cj +Qj +Rz +av +Tj +OF +av +aa +aa +aa +aa +aa +HY +Uu +If +ad +HY +He +If +ad +HY +He +If +ad +HY +He +If +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(132,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +NL +RE +gI +mP +xt +Sa +qN +ws +Az +gX +FM +Bx +MF +uy +nE +CW +je +du +ob +QN +lb +jy +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +rd +av +bd +uB +XQ +DC +DC +DC +PF +Eu +FW +oy +HN +DB +Pm +AP +Ug +yT +yT +yT +BM +Uj +BW +dc +av +mQ +Gt +av +ad +ad +ad +ad +ad +HY +Uu +If +aa +HY +He +If +aa +HY +He +If +aa +HY +He +If +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(133,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +eu +eu +eu +eu +Ba +BD +ax +aL +zW +Mz +Cb +YV +xg +yH +Wd +zW +Vf +AX +Vf +qe +Vf +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +ga +av +Wn +DC +DC +DC +DC +DC +cp +qb +FX +oy +Qg +Vm +Zh +oO +XW +ev +eK +Uv +eK +eK +ZU +UA +av +DC +Gt +av +av +aa +aa +aa +aa +HY +XK +If +aa +HY +He +If +aa +HY +He +If +aa +HY +He +If +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(134,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zW +zW +eu +eu +eu +VJ +eu +zW +zW +rH +zW +zW +qt +ne +zW +zW +zW +zW +zW +zW +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +vx +av +bm +DC +DC +Ej +DC +Tg +TY +FD +FY +oy +uG +oy +oy +oy +PZ +il +Zi +av +Zi +Zi +Oz +av +Hh +En +HC +HP +av +aa +tl +xZ +tl +xZ +VM +ad +ad +HY +HT +If +aa +HY +HT +If +aa +HY +HT +If +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(135,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zW +Fi +Su +Qn +Xi +Al +UK +zW +Wt +bt +zl +zW +Ai +ne +zW +IP +dN +Hn +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +sG +av +Dl +Dl +DK +it +qo +Iq +FL +kw +FU +Gb +RP +Sw +Gb +vl +OJ +oK +Mv +US +Gr +Gr +Xh +en +DC +Eu +HF +HQ +av +aa +oC +oC +oC +oC +VM +aa +aa +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(136,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zW +Su +Su +Su +Su +Su +xN +kP +jF +bt +KH +zW +Bg +TA +CW +je +du +QN +jy +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Jj +av +Mg +Dm +DL +El +Ek +lr +Xk +Ve +FZ +Ge +Gg +IZ +IZ +YW +Bk +IZ +IZ +Gl +Gs +Qo +Jb +GA +Hi +Hy +HG +HR +av +aa +oC +oC +oC +oC +VM +aa +aa +ad +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +ad +aa +aa +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(137,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yY +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zW +Vj +Su +Su +Su +Su +xN +zW +fa +QH +Xm +zW +qm +ne +zW +Vl +nu +BS +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Wk +av +Dn +Dn +DM +Uk +Ek +lr +Fn +Dt +im +im +im +Dt +Dt +UU +VH +Dt +Dt +Gm +sK +TO +Xb +Hb +Hj +AR +av +av +av +aa +oC +oC +oC +oC +VM +aa +aa +ad +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +ad +ad +ad +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(138,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zw +IA +Su +Su +Su +Su +xN +zW +kL +jF +ng +zW +Zg +ne +zW +zW +zW +zW +zW +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +sG +av +Do +Do +DN +AS +Ek +lr +Fo +Dt +yo +Ql +YU +Oe +YJ +Zp +MR +NQ +Jl +Dt +Ni +fW +UC +Hc +Hk +am +ad +ad +tl +xZ +oC +oC +oC +oC +VM +aa +aa +sx +sx +sx +sx +sx +sx +ad +sx +sx +sx +sx +sx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(139,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zw +Su +Su +Su +Su +Su +Fk +zW +Lt +rI +Ju +zW +ES +tz +qe +ka +jB +QU +PN +zW +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Wk +av +Mh +Dp +DO +UE +qo +lr +Fp +Dt +NQ +NQ +Vr +NQ +NQ +UU +NQ +NQ +Jl +Dt +Gu +Rp +rp +Hd +Hl +am +ad +ad +oC +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(140,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +zw +Su +Su +Su +Su +Su +xN +zW +zW +zW +zW +zW +cL +tz +Bb +Bb +Bb +Bb +qe +od +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Wk +av +Dq +Dq +DP +wv +Ek +lr +Fp +Dt +yo +Ql +Zn +Ot +Wr +gY +NQ +NQ +Jl +Dt +Gv +MS +GY +Hd +Hm +am +aa +aa +oC +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(141,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zw +Su +Su +Su +Su +Su +xN +WM +IE +wT +Ne +zW +Vb +zU +Xo +Xo +Xo +Xo +Yv +od +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +sG +av +Fh +Dr +DQ +Em +En +lr +pJ +Dt +Dt +Gm +Dt +Dt +Dt +Dt +Dt +Dt +av +XO +Dt +CQ +gm +im +zk +AR +aa +aa +oC +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(142,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zw +Su +Su +Su +Su +Su +QR +ia +CB +CB +CB +rb +Zs +aA +Xo +Xo +Xo +Xo +Yv +uH +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +OA +Vx +Gb +Gb +Gb +Gb +Ul +Eq +Fr +Dt +gD +wP +Sg +Ii +WJ +Pi +se +XF +al +av +av +Ig +gm +aa +Ho +QV +aa +aa +oC +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(143,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zw +Su +Su +Su +Su +Su +oc +tc +qe +Oo +Tu +wu +Ud +nH +Xo +Xo +Xo +Xo +Yv +od +jy +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +wb +av +Ds +DC +DR +En +En +Yu +rc +ym +yh +wA +wA +mC +cv +ph +NQ +NQ +xV +av +av +Tt +ZM +aa +Hp +QV +aa +aa +VM +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(144,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zw +dx +Su +XL +Vs +nO +qw +tc +wC +qe +CV +qe +qe +nH +Xo +Xo +Xo +Xo +Yv +od +jy +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +bE +av +av +OQ +av +Re +En +En +aK +xk +FC +NQ +NQ +Cv +NQ +pV +cv +Oa +Tz +av +av +Og +av +aa +Ho +QV +aa +aa +VM +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(145,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zW +Ro +Ua +Su +BK +gF +ai +zW +tP +Oo +qe +aZ +qe +ne +Bw +Bw +Bw +Bw +qe +od +jy +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +WW +XO +RX +DC +av +Eo +Eo +Eo +av +av +av +NQ +NQ +pf +xo +xo +ta +pf +vM +av +aa +Tx +aa +aa +Ho +QV +aa +aa +VM +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(146,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +zW +zW +zW +zW +zW +zW +zW +zW +vB +qe +qe +qe +qe +iP +VT +VT +VT +VT +Sf +PO +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Cn +Cn +WW +av +av +av +av +WU +WU +WU +aa +aa +av +EW +yc +Mo +xo +XC +ta +pf +fs +av +aa +mu +aa +aa +Ho +QV +aa +aa +VM +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(147,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +zW +zW +jy +jy +jy +jy +zW +RA +lA +wk +lA +Sv +zW +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Nm +Xj +PC +OX +Tv +Ze +WB +WU +aa +aa +aa +aa +av +av +av +av +av +XO +av +av +av +av +aa +mu +aa +aa +Ho +QV +aa +aa +VM +oC +oC +oC +oC +oC +VM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(148,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +zW +jy +jy +zW +jy +jy +zW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +cR +WB +Qw +Je +Je +Je +Cn +Cn +Cn +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +mu +aa +aa +Hq +Hz +aa +ad +VM +zX +nD +tk +nD +zX +lf +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(149,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Cn +SZ +kH +Ty +kH +km +Oh +WK +Zv +Cn +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +mu +ad +aa +Hr +HA +HH +HS +HV +HS +HH +HH +HH +HS +Vk +HS +HH +HH +HH +HH +HH +HS +HS +HH +HH +JP +Ka +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(150,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +cH +OT +OT +UO +Sr +Ml +DH +Cn +Cn +Cn +ad +ad +ad +ad +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +Lb +GC +Wz +GC +gn +QW +QW +qY +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +lg +JQ +Kb +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(151,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Cn +Cn +Cn +Cn +Cn +Cn +Cn +Cn +Cn +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +GJ +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +ad +ad +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(152,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Pr +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +GJ +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +QV +Kc +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(153,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +VO +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(154,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +aa +aa +aa +aa +GJ +aa +aa +aa +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(155,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FE +FE +FE +FE +Gh +Gh +aa +GH +aa +Gh +Gh +FE +FE +FE +FE +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(156,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FF +Ga +Ga +Ga +Ga +Ga +Gw +Jt +GM +GN +GN +GN +GN +GN +GO +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(157,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FG +FG +FG +FG +FG +FG +aa +Jt +aa +FG +FG +FG +FG +FG +FG +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(158,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +Jt +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +ab +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Kd +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(159,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FE +FE +FE +FE +FE +FE +aa +Jt +aa +FE +FE +FE +FE +FE +FE +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Kc +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(160,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FF +Ga +Ga +Ga +Ga +Ga +Gw +Jt +GM +GN +GN +GN +GN +GN +GO +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(161,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FG +FG +FG +FG +FG +FG +aa +Jt +aa +FG +FG +FG +FG +FG +FG +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(162,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +Jt +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(163,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +dl +dl +dl +dl +dl +dl +aa +Jt +aa +dl +dl +dl +dl +dl +dl +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +QV +Ho +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(164,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +RF +BP +BP +BP +BP +BP +Gw +Jt +GM +GG +GG +GG +GG +GG +NM +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +Jt +aa +QV +Kc +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(165,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ua +ua +ua +ua +ua +ua +aa +Jt +aa +ua +ua +ua +ua +ua +ua +ad +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aS +Jt +aS +lX +Ke +aS +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(166,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +Jt +aa +aa +aa +ad +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +ad +ad +aa +aa +ad +ad +Ih +Bz +aS +qD +Kf +Ih +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(167,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FE +FE +FE +FE +FE +FE +aa +Jt +aa +FE +FE +FE +FE +FE +FE +ad +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +Ih +NU +aS +sJ +Kg +Ih +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(168,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yY +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FF +Ga +Ga +Ga +Ga +Ga +Gw +Jt +GM +GN +GN +GN +GN +GN +GO +ad +aa +aa +aa +aa +aa +ad +ad +cn +ad +ad +ad +ad +Ih +Ik +aS +JS +Kh +Ih +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(169,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +FG +FG +FG +FG +FG +FG +aa +GI +aa +FG +FG +FG +FG +FG +FG +ad +aa +aa +aa +aa +aa +ad +cn +cn +aS +aS +aS +Ih +aS +XT +Il +IQ +Jv +aS +Ih +Ih +aS +aa +aa +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(170,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +GJ +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +ad +aS +lO +aS +cK +Vc +Ns +Il +RC +Il +mH +yx +yx +yx +tm +aS +aa +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(171,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +ad +ad +GJ +ad +ad +ad +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +ad +aS +dL +aS +ID +Il +RC +Il +Td +hE +yP +Il +Il +Il +IQ +aS +ad +ad +cn +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(172,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +GP +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +VA +aS +ID +Of +Cm +Il +RC +Om +mN +VV +Il +Il +IQ +aS +aS +aS +cn +cn +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(173,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +gr +Iu +Vc +RW +SI +eC +yi +JG +Kj +Ra +JB +Ji +Or +yx +tm +aS +OO +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(174,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Il +Iv +IF +IF +mv +Jg +Jg +JH +JT +Kk +JA +Kj +JB +JB +xJ +aS +Jd +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(175,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Il +Iw +ID +Il +BN +Jh +Jw +JI +JI +Kl +JI +KA +KJ +Jh +oV +aS +YG +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(176,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Iw +ID +II +KE +Jh +Jx +JJ +JJ +Km +JJ +JJ +sR +Jh +Sp +tm +RC +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(177,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Im +Iw +Im +Il +Mm +Jh +Zx +JJ +JU +JU +Kw +KB +KK +Ru +Ld +IQ +RC +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(178,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Ix +Il +Il +Ar +Cx +Jy +JK +JU +Kn +Kx +VK +KL +oM +Ld +ZX +RC +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(179,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Im +Iw +Im +Il +fV +Jh +JA +JJ +JU +JU +Ky +JJ +KM +Jh +Ld +Hw +Cm +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(180,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Iy +IG +IN +KY +Jh +JA +JJ +JJ +Km +JJ +JJ +sR +Jh +KF +BG +RM +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(181,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Iw +Il +uT +Qe +JB +Cy +Cy +Cr +JJ +JA +KC +IY +Jh +KF +SU +aS +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(182,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Jz +tQ +LZ +JN +Jh +Jh +Jh +JA +Ko +JA +Jh +QY +Jh +lS +Mj +aS +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(183,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Jz +tQ +lk +JN +Jm +JC +Jh +Jh +Jh +Jh +Jh +KO +ID +KF +IQ +aS +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(184,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Jz +pX +Ca +JN +Jn +Jn +JL +JW +Kp +JN +Sk +yE +yx +lR +Lc +aS +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(185,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Jz +tQ +lk +JN +Jn +Jn +Jn +JD +Kq +XB +IG +KP +aS +aS +Lm +aS +aS +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(186,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Im +Jz +ix +lk +JN +Jo +JD +JD +JD +Kr +JN +Il +KQ +aS +Lf +Ln +Lv +LB +aS +ad +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(187,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +Jz +IJ +Pc +Ch +Jp +Jp +JM +JX +Ks +JN +Il +KQ +aS +Lg +Lo +Lw +LC +Ih +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(188,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Im +Jz +WH +Xt +JN +Jq +JD +JD +JD +Kt +JN +KD +KR +KZ +Lh +Lp +Lx +LD +Ih +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(189,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +Ih +Il +hi +Tr +Cw +Cp +Jn +Jn +Jn +JD +Ku +tw +KE +KS +La +Li +yC +JR +JR +Ih +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(190,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +ad +ad +aS +Il +Jz +tQ +QD +JN +Jn +Jn +Jn +JY +Kv +JN +KF +KT +aS +Lj +JR +Ly +LE +Ih +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(191,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +aS +In +Iz +IL +eU +JN +Jr +JE +JN +JN +JN +JN +KG +KT +aS +Lk +JR +Lz +LF +Ih +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(192,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +aS +jQ +JN +JN +Bi +JN +JN +JN +JN +Cs +Il +Il +KF +KT +aS +Ll +Bh +LA +LG +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(193,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +aS +Ip +Il +Il +Cg +Cq +Cq +Cq +Cq +Cq +Cq +Cq +Ct +KU +aS +aS +zZ +aS +aS +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(194,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +jH +li +Jv +aS +Ih +Ih +aS +Ih +Ih +aS +Ih +aS +YT +IW +IG +IG +Lu +aS +ad +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(195,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +Il +lj +Il +aS +ad +ad +ad +ad +ad +ad +ad +aS +Le +CG +CF +BF +Cz +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(196,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aS +aS +mw +aS +aS +aa +ad +ad +aa +aa +ad +ad +aS +Il +Il +CH +Ij +Ij +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(197,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +It +ad +aa +aa +aa +ad +aa +aa +ad +aa +aS +Ih +Ih +aS +Ih +Ih +aS +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(198,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +aa +aa +aa +ad +aa +aa +ad +aa +aa +aa +ad +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(199,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +ad +aa +aa +ad +aa +aa +aa +ad +aa +ad +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(200,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(201,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(202,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(203,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(204,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(205,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(206,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(207,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(208,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(209,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(210,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(211,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(212,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(213,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(214,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(215,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(216,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(217,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(218,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(219,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(220,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(221,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(222,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(223,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(224,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(225,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(226,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(227,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(228,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(229,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(230,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(231,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(232,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(233,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(234,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(235,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(236,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(237,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(238,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(239,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(240,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(241,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(242,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(243,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(244,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(245,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(246,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(247,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(248,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(249,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(250,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(251,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(252,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(253,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(254,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(255,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/ministation/ministation-1.dmm b/maps/ministation/ministation-1.dmm new file mode 100644 index 000000000000..fc3ebff786d9 --- /dev/null +++ b/maps/ministation/ministation-1.dmm @@ -0,0 +1,76266 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/space, +/area/space) +"ac" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hydro) +"ad" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"ae" = ( +/obj/machinery/optable, +/turf/floor/tiled/white, +/area/ministation/detective) +"af" = ( +/turf/wall/natural/random/ministation, +/area/space) +"ag" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"aj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"al" = ( +/obj/machinery/vending/coffee, +/turf/floor/tiled, +/area/ministation/hall/w2) +"am" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/table/steel, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"ar" = ( +/obj/structure/table, +/obj/item/clothing/suit/jacket/winter, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/machinery/button/blast_door{ + id_tag = "CMO1"; + name = "CMO Shutter Button"; + pixel_y = 24 + }, +/obj/item/flashlight/lamp/green, +/obj/item/box/fancy/cigarettes/covert/tricord, +/turf/floor/carpet/blue, +/area/ministation/medical) +"at" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"av" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/vending/medical{ + pixel_x = -2 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ax" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"az" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/carpet, +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/effect/floor_decal/carpet{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"aA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"aB" = ( +/obj/structure/disposalpipe/junction/mirrored{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"aC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/fountain/mundane, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"aD" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloorblack, +/turf/floor/tiled, +/area/ministation/hall/e2) +"aG" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"aH" = ( +/obj/structure/chair, +/turf/floor/tiled, +/area/ministation/hall/w2) +"aL" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/bed/sofa/middle/black, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"aN" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/structure/table, +/obj/item/surgicaldrill, +/turf/floor/tiled/white, +/area/ministation/medical) +"aR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"aU" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/hop) +"aV" = ( +/turf/floor/tiled, +/area/ministation/hall/w2) +"aW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"bj" = ( +/turf/wall, +/area/ministation/cafe) +"bo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"bp" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/structure/rack, +/obj/random/plushie, +/obj/random/plushie, +/obj/random/plushie, +/obj/random/plushie/large, +/turf/floor/tiled/dark, +/area/ministation/security) +"br" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/mob/living/simple_animal/passive/mouse/brown/Tom, +/turf/floor/lino, +/area/ministation/cafe) +"bs" = ( +/obj/structure/ladder, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"bu" = ( +/turf/wall, +/area/ministation/maint/l2underpass) +"bv" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"bw" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"bx" = ( +/obj/item/secure_storage/safe{ + pixel_x = 4; + pixel_y = 26 + }, +/obj/machinery/camera/network/security, +/turf/floor/laminate, +/area/ministation/detective) +"by" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/red, +/area/ministation/security) +"bA" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"bB" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"bC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/security) +"bG" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "32-2" + }, +/obj/machinery/atmospherics/pipe/zpipe/down/supply, +/obj/machinery/atmospherics/pipe/zpipe/down/scrubbers, +/obj/structure/disposalpipe/down, +/turf/open, +/area/ministation/maint/l2centraln) +"bH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/blue, +/area/ministation/medical) +"bI" = ( +/obj/effect/floor_decal/ss13/l13, +/turf/floor/tiled, +/area/ministation/hall/w2) +"bJ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"bK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"bL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"bN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"bO" = ( +/obj/machinery/camera/motion{ + req_access = list("ACCESS_SECURITY") + }, +/turf/floor/bluegrid, +/area/ministation/security) +"bQ" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/structure/table/reinforced, +/obj/machinery/button/blast_door{ + id_tag = "quarantine"; + name = "Infirmary Quarantine Button"; + directional_offset = null + }, +/obj/machinery/button/alternate/door{ + id_tag = "medleave"; + name = "Interior medbay doors button"; + pixel_y = 8; + directional_offset = null + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/turf/floor/tiled/white, +/area/ministation/medical) +"bR" = ( +/obj/structure/flora/bush/lavendergrass, +/turf/floor/fake_grass, +/area/ministation/security) +"bU" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/camera/autoname, +/obj/structure/closet/secure_closet/freezer/meat, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"bW" = ( +/obj/structure/table, +/obj/machinery/chemical_dispenser/bar_coffee/full, +/obj/effect/floor_decal/carpet, +/turf/floor/tiled/dark, +/area/ministation/security) +"bX" = ( +/obj/machinery/door/firedoor, +/obj/structure/window/basic/full, +/turf/floor/plating, +/area/ministation/hydro) +"cd" = ( +/obj/machinery/vending/hydronutrients{ + dir = 1 + }, +/obj/effect/floor_decal/corner/beige/half, +/turf/floor/tiled, +/area/ministation/hydro) +"cf" = ( +/obj/machinery/cryopod, +/obj/abstract/landmark/latejoin, +/obj/machinery/light/small/emergency{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/arrival) +"cg" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/floor/reinforced/airless, +/area/space) +"cm" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"cq" = ( +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/ministation/arrival) +"cr" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/w2) +"ct" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/obj/machinery/apc{ + dir = 8; + name = "_West APC"; + pixel_x = -25 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"cv" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/hop) +"cA" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/carpet, +/area/ministation/hop) +"cE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"cH" = ( +/obj/structure/catwalk, +/obj/machinery/camera/autoname{ + dir = 4 + }, +/turf/open, +/area/ministation/hall/w2) +"cL" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"cN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"cQ" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"cR" = ( +/obj/structure/chair/office/comfy/brown, +/obj/abstract/landmark/start{ + name = "Detective" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"cT" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/security) +"cU" = ( +/obj/machinery/door/airlock{ + name = "Cryo B" + }, +/turf/floor/plating, +/area/ministation/arrival) +"cY" = ( +/turf/wall/r_wall, +/area/ministation/security) +"da" = ( +/turf/wall, +/area/ministation/security) +"db" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/sign/warning/armory{ + pixel_y = 32 + }, +/turf/floor/tiled, +/area/ministation/security) +"dc" = ( +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/obj/machinery/disposal, +/turf/floor/carpet, +/area/ministation/hall/w2) +"dd" = ( +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"de" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/lino, +/area/ministation/cafe) +"dm" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"dn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/hygiene/drain, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"dq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/civilian{ + name = "Hydroponics" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hydro) +"dr" = ( +/turf/floor/tiled, +/area/ministation/security) +"ds" = ( +/obj/machinery/computer/cryopod{ + pixel_y = -27; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/arrival) +"dw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"dB" = ( +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_HEAD_OF_SECURITY"); + autoset_access = 0; + dir = 8 + }, +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/turf/floor/tiled/dark, +/area/ministation/security) +"dC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_HEAD_OF_SECURITY"); + autoset_access = 0; + dir = 8 + }, +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/security) +"dE" = ( +/obj/machinery/camera/autoname{ + dir = 1 + }, +/obj/machinery/lapvend{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"dH" = ( +/obj/machinery/camera/network/medbay{ + dir = 8; + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"dK" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/structure/railing/mapped, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/open, +/area/ministation/hall/w2) +"dN" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"dQ" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"dS" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"dT" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/medical) +"dW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/security{ + name = "Warden"; + autoset_access = 0; + req_access = list("ACCESS_ARMORY") + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/dark, +/area/ministation/security) +"dZ" = ( +/obj/machinery/door/window/brigdoor/westleft, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/blast/shutters{ + id_tag = "barshut"; + name = "Bar Shutters" + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"eb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"ed" = ( +/turf/floor/plating, +/area/ministation/arrival) +"ef" = ( +/turf/floor/plating, +/area/ministation/maint/secmaint) +"eg" = ( +/obj/machinery/hologram/holopad, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/hop) +"eh" = ( +/obj/structure/window/basic/full, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hydro) +"ek" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"em" = ( +/obj/machinery/vending/cola, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"eo" = ( +/obj/structure/closet/emcloset, +/obj/machinery/light/small/emergency{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/arrival) +"er" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"et" = ( +/obj/effect/floor_decal/snow_floor, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"ew" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/security) +"ex" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"ey" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ez" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"eB" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"eE" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"eF" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = 17 + }, +/turf/space, +/area/space) +"eH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"eK" = ( +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"eV" = ( +/obj/machinery/light, +/obj/machinery/vitals_monitor, +/turf/floor/tiled/white, +/area/ministation/medical) +"eZ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/security) +"fd" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/machinery/computer/modular/telescreen/preset/generic{ + name = "south bump"; + pixel_y = -32; + dir = 1 + }, +/obj/item/radio/intercom/locked/entertainment{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled, +/area/ministation/hop) +"fe" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/hall/w2) +"fl" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"fm" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/borderfloorblack{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"fn" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/item/gun/projectile/pistol/rubber{ + name = "pistol SN 3001" + }, +/obj/item/gun/projectile/pistol/rubber{ + name = "pistol SN 3002" + }, +/obj/item/ammo_magazine/pistol/rubber, +/obj/item/ammo_magazine/pistol/rubber, +/obj/item/ammo_magazine/pistol/rubber, +/obj/item/ammo_magazine/pistol/flash, +/obj/item/ammo_magazine/pistol/flash, +/obj/item/ammo_magazine/pistol/flash, +/turf/floor/tiled/dark, +/area/ministation/security) +"fr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"fs" = ( +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/security) +"fu" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/window/brigdoor/southright, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/blast/shutters{ + name = "office shutters"; + id_tag = "hopshut" + }, +/turf/floor/plating, +/area/ministation/hop) +"fw" = ( +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"fx" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"fy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/rack, +/obj/item/defensive_barrier, +/obj/item/defensive_barrier, +/obj/item/airlock_brace, +/obj/item/crowbar/brace_jack, +/turf/floor/tiled/dark, +/area/ministation/security) +"fA" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/button/blast_door{ + id_tag = "secshut"; + name = "security shutter button"; + pixel_y = -32; + dir = 1 + }, +/obj/machinery/computer/prisoner{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"fC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/firstaid{ + dir = 8 + }, +/obj/effect/decal/cleanable/blood, +/obj/structure/sign/department/cross{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"fD" = ( +/obj/structure/meat_hook, +/obj/effect/floor_decal/snow_floor, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"fF" = ( +/obj/structure/ladder, +/obj/machinery/light/small, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"fH" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/ministation/security) +"fL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"fN" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/cafe) +"fP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"fW" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/camera/network/security, +/obj/item/implanter, +/turf/floor/tiled/dark, +/area/ministation/security) +"fY" = ( +/obj/effect/floor_decal/industrial/firstaid{ + dir = 8 + }, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"fZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hop) +"gb" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/security) +"gc" = ( +/obj/structure/closet/secure_closet/brig, +/turf/floor/tiled, +/area/ministation/security) +"ge" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"gm" = ( +/obj/machinery/vending/sovietsoda, +/turf/floor/tiled, +/area/ministation/security) +"gp" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"gw" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/fake_grass, +/area/ministation/hydro) +"gz" = ( +/turf/open, +/area/ministation/hall/e2) +"gB" = ( +/obj/structure/table/laminate/mahogany, +/obj/item/pen/blue, +/turf/floor/carpet/red, +/area/ministation/security) +"gC" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"gD" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/eastright{ + id_tag = "Cell 2" + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/security) +"gE" = ( +/obj/structure/table/reinforced, +/obj/item/toy/eightball, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"gJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/laminate, +/area/ministation/detective) +"gL" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/chair/armchair/black{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"gS" = ( +/obj/machinery/cryopod{ + dir = 1 + }, +/obj/abstract/landmark/latejoin/cryo, +/obj/machinery/camera/network/medbay{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"gT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/carpet, +/area/ministation/hop) +"gU" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/dark, +/area/ministation/medical) +"gW" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/machinery/vending/snack{ + dir = 8; + pixel_x = 5 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"gX" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"ha" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"hb" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/door_timer/cell_2{ + pixel_x = 31; + pixel_y = -1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"hc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/wall/r_wall, +/area/ministation/security) +"hd" = ( +/obj/structure/bed, +/obj/item/bedsheet/mime, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled, +/area/ministation/security) +"hh" = ( +/obj/structure/chair/office/light, +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"hi" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"hj" = ( +/obj/machinery/door/airlock{ + locked = 1; + name = "helm" + }, +/turf/floor/plating, +/area/ministation/arrival) +"hl" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/w2) +"hm" = ( +/obj/structure/chair, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ho" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"hp" = ( +/turf/wall, +/area/space) +"hr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/turf/floor/tiled/white, +/area/ministation/medical) +"hs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"ht" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/carpet, +/obj/structure/flora/pottedplant/orientaltree, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"hu" = ( +/obj/abstract/landmark/start{ + name = "Lieutenant" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/carpet, +/area/ministation/hop) +"hv" = ( +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hydro) +"hw" = ( +/obj/structure/table, +/obj/item/clothing/glasses/sunglasses, +/obj/item/clothing/glasses/sunglasses, +/obj/item/clothing/head/earmuffs, +/obj/item/clothing/head/earmuffs, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled, +/area/ministation/security) +"hx" = ( +/obj/structure/table, +/obj/machinery/recharger/wallcharger{ + pixel_y = 25 + }, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 32 + }, +/obj/item/flashlight/lamp/green, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"hz" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/flora/pottedplant/minitree, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/security) +"hA" = ( +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"hC" = ( +/obj/structure/table/laminate, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/item/scanner/spectrometer, +/obj/item/handcuffs, +/turf/floor/carpet/red, +/area/ministation/detective) +"hD" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 4 + }, +/obj/item/firstaid/adv, +/obj/item/firstaid/adv, +/turf/floor/tiled/white, +/area/ministation/medical) +"hH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"hI" = ( +/obj/structure/closet/secure_closet/security, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/jacket/winter/security, +/obj/item/flashlight/maglight, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/obj/item/chems/spray/pepper, +/turf/floor/tiled, +/area/ministation/security) +"hO" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"hQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/security) +"hS" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"hU" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/turf/floor/tiled/dark, +/area/ministation/security) +"hV" = ( +/obj/effect/floor_decal/corner/paleblue/half{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"hX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/security) +"hY" = ( +/obj/structure/table, +/obj/item/assembly/timer, +/obj/item/flash, +/turf/floor/tiled, +/area/ministation/security) +"hZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/security) +"ia" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/door_timer/cell_1{ + pixel_x = 31 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"ib" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"ic" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"id" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"if" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"ig" = ( +/obj/abstract/landmark{ + name = "blobstart" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"ih" = ( +/obj/machinery/door/airlock{ + name = "ATMOS"; + locked = 1 + }, +/turf/floor/plating, +/area/ministation/arrival) +"ii" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/medical) +"in" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"io" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table, +/obj/item/firstaid/regular{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/firstaid/regular{ + pixel_x = -2; + pixel_y = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"iq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"ir" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"is" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"iv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light, +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"iw" = ( +/obj/machinery/seed_extractor, +/obj/effect/floor_decal/corner/beige/half, +/turf/floor/tiled, +/area/ministation/hydro) +"ix" = ( +/obj/machinery/door/airlock/medical, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"iy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"iz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"iA" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"iB" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/eastright{ + id_tag = "Cell 1" + }, +/obj/effect/floor_decal/corner/red{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/security) +"iD" = ( +/obj/structure/table/reinforced, +/obj/item/synthesized_instrument/violin, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"iE" = ( +/obj/structure/table/reinforced, +/obj/item/folder, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"iG" = ( +/obj/structure/chair/office/comfy/brown{ + dir = 1 + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"iH" = ( +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"iJ" = ( +/obj/structure/table, +/obj/item/box/gloves, +/obj/item/box/masks, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/stack/medical/bandage/advanced, +/obj/item/stack/medical/bandage/advanced, +/turf/floor/tiled/white, +/area/ministation/medical) +"iK" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2underpass) +"iN" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"iQ" = ( +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"iR" = ( +/obj/machinery/light/small/emergency{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/arrival) +"iU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"iW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/e2) +"iX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hop) +"iY" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"jd" = ( +/obj/machinery/computer/station_alert/security{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/tiled, +/area/ministation/security) +"je" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/security) +"jg" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"jh" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"jk" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/apc{ + name = "_South APC"; + pixel_y = -24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/laminate, +/area/ministation/detective) +"jl" = ( +/obj/machinery/porta_turret{ + dir = 4; + id_tag = "goodstuff"; + max_health = 160 + }, +/turf/floor/bluegrid, +/area/ministation/security) +"jq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/security) +"js" = ( +/obj/machinery/computer/modular/preset/medical, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"jv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"jy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"jF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/mob/living/simple_animal/corgi/Ian, +/turf/floor/tiled, +/area/ministation/hop) +"jH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/junction/mirrored{ + dir = 8 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"jM" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/borderfloorblack/corner{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"jN" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/turf/floor/tiled, +/area/ministation/security) +"jO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/hallway{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"jP" = ( +/obj/structure/closet/secure_closet/freezer/kitchen, +/obj/item/chems/condiment/small/saltshaker, +/obj/item/chems/condiment/small/peppermill, +/turf/floor/lino, +/area/ministation/cafe) +"jR" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"jS" = ( +/obj/structure/table, +/obj/item/book/skill/service/cooking, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/machinery/fabricator/micro/bartender{ + pixel_x = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"jT" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/item/pill_bottle, +/obj/machinery/light{ + dir = 4 + }, +/obj/item/eftpos, +/turf/floor/tiled/white, +/area/ministation/medical) +"jU" = ( +/turf/wall, +/area/ministation/maint/sebypass) +"jV" = ( +/obj/effect/floor_decal/corner/green/half, +/turf/floor/tiled, +/area/ministation/hall/e2) +"jW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"jZ" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/ministation/hall/w2) +"kb" = ( +/obj/abstract/landmark{ + name = "blobstart" + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"kd" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/random/maintenance, +/obj/structure/closet, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"ke" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/w2) +"kg" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/circular_saw, +/obj/item/scalpel{ + pixel_y = 12 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"kh" = ( +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/security) +"km" = ( +/obj/structure/closet/secure_closet/medical3, +/obj/item/clothing/suit/toggle/labcoat, +/obj/item/clothing/suit/jacket/winter/medical, +/obj/item/clothing/suit/jacket/winter/medical, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/tiled/white, +/area/ministation/medical) +"kr" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"ku" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"kv" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet/blue2, +/area/ministation/security) +"ky" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"kz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/fake_grass, +/area/ministation/hydro) +"kB" = ( +/obj/structure/dogbed, +/obj/item/clothing/shoes/color/brown{ + desc = "Old, but sensible brown shoes. These belong to Ian." + }, +/turf/floor/tiled, +/area/ministation/hop) +"kC" = ( +/obj/machinery/vending/snack, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"kD" = ( +/obj/abstract/landmark/start{ + name = "Bartender" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/carpet, +/area/ministation/cafe) +"kE" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 9; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/security) +"kG" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/security) +"kI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/w2) +"kK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/hygiene/drain, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"kM" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"kR" = ( +/obj/structure/table, +/obj/item/chems/rag, +/obj/item/trash/stick, +/obj/item/utensil/spoon, +/turf/floor/tiled/white, +/area/ministation/medical) +"kS" = ( +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/medical) +"kV" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/obj/machinery/disposal, +/turf/floor/tiled/white, +/area/ministation/medical) +"kX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/abstract/landmark/latejoin/observer, +/turf/floor/tiled, +/area/ministation/hall/w2) +"kZ" = ( +/turf/wall, +/area/ministation/hall/w2) +"la" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/e2) +"lg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + dir = 8; + name = "_West APC"; + pixel_x = -25 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"lh" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/closet/crate/freezer, +/obj/item/chems/ivbag/blood/aminus, +/obj/item/chems/ivbag/blood/aplus, +/obj/item/chems/ivbag/blood/bminus, +/obj/item/chems/ivbag/blood/bplus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/oplus, +/turf/floor/tiled/white, +/area/ministation/medical) +"ln" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/ss13/l12, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/w2) +"lo" = ( +/obj/machinery/door/airlock/external{ + locked = 1; + id_tag = "l2_central_north_airlock_exterior"; + autoset_access = 0 + }, +/obj/machinery/button/access/interior{ + id_tag = "l2_central_north_airlock"; + name = "exterior access button"; + pixel_x = 10; + pixel_y = 20; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"lp" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/dark, +/area/ministation/security) +"ls" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sqm_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sqm_airlock"; + name = "interior access button"; + pixel_x = -10; + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"lw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"ly" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/effect/floor_decal/borderfloorblack/corner, +/turf/floor/tiled, +/area/ministation/hall/e2) +"lB" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"lF" = ( +/turf/wall, +/area/ministation/maint/nebypass) +"lG" = ( +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"lH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"lI" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/structure/chair, +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"lJ" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = -30; + dir = 1 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"lK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + id_tag = "Chef1" + }, +/turf/floor/plating, +/area/ministation/cafe) +"lL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/w2) +"lN" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/mirrored{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"lQ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -11 + }, +/obj/item/chems/glass/bucket, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"lR" = ( +/obj/structure/chair/comfy/beige{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"mc" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/open, +/area/ministation/hall/w2) +"md" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"mf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"mh" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"mi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"mj" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled, +/area/ministation/hall/e2) +"mk" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/security) +"mo" = ( +/obj/structure/table, +/obj/machinery/microwave, +/obj/effect/floor_decal/carpet, +/turf/floor/tiled/dark, +/area/ministation/security) +"mp" = ( +/obj/machinery/network/requests_console{ + department = "Detective's office"; + pixel_x = -32; + initial_network_id = "molluscnet"; + dir = 8 + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"mq" = ( +/turf/wall, +/area/ministation/maint/l2centraln) +"mu" = ( +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hydro) +"mv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/hologram/holopad{ + holopad_id = "Security Meeting Room" + }, +/turf/floor/carpet/red, +/area/ministation/security) +"mw" = ( +/obj/machinery/light/small, +/obj/effect/floor_decal/snow_floor, +/obj/structure/meat_hook, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"mz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/light, +/turf/floor/tiled/dark, +/area/ministation/security) +"mC" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/light, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"mG" = ( +/obj/machinery/atmospherics/unary/engine, +/turf/space, +/area/ministation/arrival) +"mH" = ( +/turf/wall, +/area/ministation/hall/e2) +"mJ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/flora/bush/fullgrass, +/obj/structure/flora/bush/lavendergrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"mL" = ( +/obj/machinery/newscaster{ + pixel_x = -32; + dir = 8 + }, +/obj/machinery/camera/network/security{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/flora/pottedplant/largebush, +/turf/floor/tiled, +/area/ministation/security) +"mO" = ( +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"mR" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"mW" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"mX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/security) +"nb" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"nf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/optable, +/turf/floor/tiled/white, +/area/ministation/medical) +"no" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/turf/floor/tiled, +/area/ministation/security) +"np" = ( +/obj/machinery/door/airlock/external{ + autoset_access = 0; + id_tag = "l2_central_north_airlock_interior"; + locked = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/button/access/interior{ + id_tag = "l2_central_north_airlock"; + name = "interior access button"; + pixel_x = -10; + pixel_y = 20 + }, +/turf/floor, +/area/ministation/maint/l2centraln) +"ns" = ( +/obj/structure/sign/department/id_office{ + dir = 1; + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"nt" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"nu" = ( +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"nx" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 4; + id_tag = "station1"; + tag_airpump = "escape1_vent"; + tag_chamber_sensor = "escape1_sensor"; + tag_exterior_door = "escape1_airlock_exterior"; + tag_interior_door = "escape1_airlock_interior"; + pixel_x = -20 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"nB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"nC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/w2) +"nD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/w2) +"nF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"nK" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + id_tag = "l2_central_south_airlock_interior"; + locked = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/button/access/interior{ + id_tag = "l2_central_south_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = 10 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"nS" = ( +/obj/machinery/camera/network/security{ + dir = 8 + }, +/obj/structure/table, +/obj/machinery/recharger, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet/blue3, +/area/ministation/security) +"nX" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"ob" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/flora/bush/fernybush, +/turf/floor/fake_grass, +/area/ministation/security) +"oc" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/item/clothing/suit/jacket/bomber, +/obj/item/clothing/mask/horsehead, +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"od" = ( +/obj/structure/skele_stand, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"oj" = ( +/obj/structure/reagent_dispensers/peppertank{ + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"ol" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"on" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ministation/hall/w2) +"or" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"ov" = ( +/obj/structure/table/reinforced, +/obj/machinery/camera/autoname, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/item/medical_lolli_jar{ + pixel_y = 7 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"oz" = ( +/turf/wall, +/area/ministation/medical) +"oA" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor/southright, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/turf/floor/plating, +/area/ministation/medical) +"oB" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"oD" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"oE" = ( +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"oF" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"oG" = ( +/obj/structure/rack, +/obj/item/clothing/suit/armor/riot, +/obj/item/clothing/gloves/armguards/riot, +/obj/item/clothing/shoes/legguards/riot, +/obj/item/clothing/head/helmet/riot, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"oH" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"oN" = ( +/obj/effect/shuttle_landmark/escape_shuttle/station, +/turf/space, +/area/space) +"oS" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/carpet/blue, +/area/ministation/medical) +"oW" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"oX" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/w2) +"oY" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"oZ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/security) +"pb" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"pd" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/table, +/obj/item/box/flashbangs, +/obj/item/box/handcuffs{ + pixel_x = 5; + pixel_y = 5 + }, +/turf/floor/tiled, +/area/ministation/security) +"pe" = ( +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/ministation/medical) +"pf" = ( +/obj/structure/table/laminate, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ph" = ( +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"pl" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"pn" = ( +/obj/structure/mopbucket, +/obj/item/mop, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"po" = ( +/obj/machinery/camera/network/security{ + dir = 4 + }, +/turf/floor/bluegrid, +/area/ministation/security) +"pr" = ( +/turf/floor/plating/airless, +/area/space) +"ps" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/wall, +/area/ministation/hall/w2) +"pu" = ( +/obj/structure/closet/crate/bin/ministation, +/turf/floor/tiled, +/area/ministation/hall/w2) +"pw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"px" = ( +/obj/structure/table/laminate, +/obj/item/chems/glass/beaker, +/turf/floor/lino, +/area/ministation/cafe) +"pz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/dark, +/area/ministation/security) +"pA" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/table/laminate/mahogany, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/flashlight/lamp/green, +/turf/floor/tiled, +/area/ministation/security) +"pC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"pD" = ( +/turf/floor/tiled/white, +/area/ministation/medical) +"pE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloorblack{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"pF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"pG" = ( +/obj/structure/sign/plaque/diploma/medical{ + pixel_y = 31 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"pH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/structure/sign/warning/nosmoking_2{ + pixel_y = 32 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"pI" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/item/stool/padded, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/status_display{ + pixel_y = 33; + pixel_x = -1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/wall, +/area/ministation/medical) +"pK" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/mirrored, +/turf/floor/tiled/white, +/area/ministation/medical) +"pL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/ministation/medical) +"pM" = ( +/obj/structure/table, +/obj/item/scalpel{ + pixel_y = 12 + }, +/obj/item/circular_saw, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/vending/medical{ + pixel_x = -2 + }, +/obj/machinery/camera/network/medbay, +/turf/floor/tiled/white, +/area/ministation/medical) +"pO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pP" = ( +/obj/structure/table, +/obj/item/hemostat, +/obj/item/retractor, +/obj/item/stack/medical/bandage/advanced, +/obj/machinery/body_scan_display{ + pixel_y = 20; + id_tag = "mediscanner1" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pQ" = ( +/obj/structure/chair/armchair/black{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pS" = ( +/obj/structure/table, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/item/bonesetter, +/obj/item/bonegel, +/turf/floor/tiled/white, +/area/ministation/medical) +"pT" = ( +/obj/structure/table, +/obj/item/cautery{ + pixel_x = 4 + }, +/obj/item/sutures, +/obj/machinery/button/blast_door{ + id_tag = "SURG1"; + name = "Surgery Shutter Button"; + pixel_y = 24 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"pU" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/medical) +"pZ" = ( +/obj/structure/table, +/obj/item/firstaid/clotting, +/turf/floor/tiled/white, +/area/ministation/medical) +"qa" = ( +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/detective) +"qe" = ( +/obj/structure/table/laminate, +/turf/floor/tiled, +/area/ministation/hall/w2) +"qf" = ( +/turf/wall, +/area/ministation/maint/l2centrals) +"qg" = ( +/obj/machinery/meter{ + name = "Distribution Loop" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"qk" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"qn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table, +/obj/item/book/skill/medical, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"qo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/table, +/obj/item/newspaper, +/obj/item/chems/spray/cleaner, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"qp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"qq" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"qr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qs" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/airlock/double/medical{ + name = "medbay airlock"; + autoset_access = 0; + id_tag = "medleave"; + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/ministation/medical) +"qy" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/structure/closet/secure_closet/cmo, +/obj/item/clothing/suit/jacket/winter, +/obj/item/gun/projectile/dartgun/medical, +/obj/item/ammo_magazine/chemdart, +/obj/item/ammo_magazine/chemdart, +/obj/item/telebaton, +/obj/item/stamp/cmo, +/turf/floor/tiled/white, +/area/ministation/medical) +"qz" = ( +/obj/structure/chair/armchair/black{ + dir = 4 + }, +/obj/structure/chair/armchair/black{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qA" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"qB" = ( +/obj/structure/table/marble, +/obj/machinery/door/blast/shutters{ + id_tag = "Kitchen1"; + name = "Kitchen" + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"qF" = ( +/obj/structure/chair/comfy/beige{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/carpet, +/area/ministation/hall/w2) +"qI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/e2) +"qL" = ( +/obj/machinery/airlock_sensor{ + id_tag = "l2_central_north_sensor"; + pixel_y = 20 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "l2_central_north_airlock"; + pixel_y = 24; + tag_airpump = "l2_central_north_vent"; + tag_chamber_sensor = "l2_central_north_sensor"; + tag_exterior_door = "l2_central_north_airlock_exterior"; + tag_interior_door = "l2_central_north_airlock_interior" + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"qM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"qN" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4; + icon_state = "warningcorner" + }, +/turf/open, +/area/ministation/hall/w2) +"qO" = ( +/obj/machinery/cryopod{ + dir = 1 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/abstract/landmark/latejoin/cryo, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"qS" = ( +/obj/machinery/floodlight, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"qT" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"qX" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/computer/modular/preset/security{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"qY" = ( +/turf/floor/carpet/blue2, +/area/ministation/medical) +"qZ" = ( +/obj/machinery/light, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"ra" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/carpet/blue2, +/area/ministation/medical) +"rb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rc" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/status_display{ + pixel_x = -32; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rd" = ( +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/button/alternate/door{ + dir = 4; + id_tag = "medleave"; + name = "Interior medbay doors button"; + pixel_x = -32; + pixel_y = -32 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"re" = ( +/obj/abstract/landmark/start{ + name = "Medical Doctor" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/medical) +"rg" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rh" = ( +/obj/machinery/camera/network/medbay{ + dir = 8; + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/table, +/obj/item/sutures, +/obj/item/cautery{ + pixel_x = 4 + }, +/obj/machinery/button/blast_door{ + id_tag = "SURG2"; + name = "Surgery Shutter Button"; + pixel_y = 24 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ri" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/bodyscanner{ + dir = 8; + id_tag = "mediscanner1" + }, +/obj/machinery/body_scan_display{ + pixel_y = 20; + id_tag = "mediscanner1" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rj" = ( +/obj/structure/bed/roller, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rk" = ( +/obj/machinery/optable, +/turf/floor/tiled/white, +/area/ministation/medical) +"rm" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rq" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"rt" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/hall/w2) +"rw" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled, +/area/ministation/hydro) +"ry" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" + }, +/turf/open, +/area/ministation/hall/w2) +"rA" = ( +/obj/structure/table/laminate, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rC" = ( +/obj/machinery/airlock_sensor{ + id_tag = "l2_central_south_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "l2_central_south_airlock"; + pixel_y = null; + tag_airpump = "l2_central_south_vent"; + tag_chamber_sensor = "l2_central_south_sensor"; + tag_exterior_door = "l2_central_south_airlock_exterior"; + tag_interior_door = "l2_central_south_airlock_interior"; + dir = 4; + pixel_x = -20 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"rD" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/closet/secure_closet/hop, +/obj/item/stamp/hop, +/turf/floor/tiled, +/area/ministation/hop) +"rE" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rG" = ( +/obj/abstract/landmark/start{ + name = "Clown" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"rI" = ( +/obj/item/stool/padded, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rL" = ( +/obj/structure/bed, +/obj/item/bedsheet/medical, +/obj/structure/curtain/medical, +/turf/floor/tiled/white, +/area/ministation/medical) +"rM" = ( +/obj/machinery/status_display{ + pixel_y = -29; + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rN" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/medical) +"rP" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/wall, +/area/ministation/medical) +"rR" = ( +/obj/machinery/vitals_monitor, +/turf/floor/tiled/white, +/area/ministation/medical) +"rS" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/table, +/obj/item/retractor, +/obj/item/hemostat, +/obj/item/stack/medical/bandage/advanced, +/obj/machinery/body_scan_display{ + pixel_y = 20; + id_tag = "mediscanner1" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"rU" = ( +/obj/structure/table, +/obj/machinery/faxmachine/mapped, +/turf/floor/tiled, +/area/ministation/hop) +"rW" = ( +/obj/machinery/light, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rX" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"rY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/security) +"sb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"sg" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"sh" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"si" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/machinery/door/airlock/double/medical{ + name = "Medbay Lobby airlock"; + autoset_access = 0 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"sj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"sk" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/tiled/white, +/area/ministation/medical) +"sl" = ( +/obj/abstract/landmark/start{ + name = "Chef" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/carpet, +/area/ministation/cafe) +"sm" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"sn" = ( +/obj/structure/table, +/obj/item/surgicaldrill, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"so" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"sp" = ( +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hall/w2) +"sq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ss" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/w2) +"st" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"su" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atm{ + pixel_y = 32 + }, +/obj/machinery/camera/network/hallway, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"sv" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"sw" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/carpet, +/area/ministation/cafe) +"sB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"sC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/e2) +"sD" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"sG" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"sI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"sK" = ( +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_HEAD_OF_SECURITY"); + autoset_access = 0; + dir = 8 + }, +/obj/structure/closet/secure_closet/guncabinet{ + req_access = list("ACCESS_HEAD_OF_SECURITY") + }, +/obj/item/box/ammo/shotgunammo/large, +/obj/item/box/ammo/shotgunammo/large, +/obj/item/box/ammo/shotgunshells, +/obj/item/box/ammo/shotgunshells, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/grenade/flashbang/clusterbang, +/turf/floor/tiled/dark, +/area/ministation/security) +"sM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"sN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/sign/department/forensics{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloorblack/corner{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"sO" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/carpet, +/obj/structure/reagent_dispensers/water_cooler, +/turf/floor/tiled/dark, +/area/ministation/security) +"sP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"sQ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"sS" = ( +/obj/effect/floor_decal/industrial/firstaid{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"sU" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/sign/department/security/alt{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"sV" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/decal/cleanable/filth, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"sW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"sX" = ( +/obj/machinery/sleeper/standard, +/turf/floor/tiled/white, +/area/ministation/medical) +"sY" = ( +/obj/structure/table, +/obj/item/chems/dropper, +/obj/item/chems/glass/beaker, +/turf/floor/tiled/white, +/area/ministation/medical) +"ta" = ( +/obj/structure/iv_drip, +/turf/floor/tiled/white, +/area/ministation/medical) +"tb" = ( +/obj/item/chems/ivbag/blood/aminus, +/obj/item/chems/ivbag/blood/aplus, +/obj/item/chems/ivbag/blood/bminus, +/obj/item/chems/ivbag/blood/bplus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/oplus, +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white, +/area/ministation/medical) +"te" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tf" = ( +/obj/effect/floor_decal/ss13/l1, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tg" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/ss13/l3, +/turf/floor/tiled, +/area/ministation/hall/w2) +"th" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/ss13/l5, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ti" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/ss13/l7, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/ss13/l9, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tm" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"to" = ( +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/detective) +"tq" = ( +/obj/structure/railing/mapped, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tt" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"tv" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/open, +/area/ministation/hall/e2) +"tx" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/e2) +"ty" = ( +/turf/floor/tiled, +/area/ministation/hall/e2) +"tz" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"tA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"tD" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/e2) +"tE" = ( +/obj/abstract/landmark{ + name = "lightsout" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"tG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"tH" = ( +/obj/effect/floor_decal/industrial/firstaid{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"tI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"tJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"tL" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/green/half, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/e2) +"tM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/wall, +/area/ministation/hall/w2) +"tN" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/airlock/medical, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"tO" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"tP" = ( +/obj/effect/floor_decal/ss13/l10, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tQ" = ( +/turf/wall/r_wall, +/area/ministation/maint/secmaint) +"tS" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/cooker/fryer, +/turf/floor/lino, +/area/ministation/cafe) +"tT" = ( +/obj/machinery/apc{ + dir = 4; + name = "_East APC"; + pixel_x = 27; + pixel_y = 2 + }, +/obj/structure/cable, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"tU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"tV" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/chair/armchair/red{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/security) +"tW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tX" = ( +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"tY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"tZ" = ( +/obj/machinery/vending/coffee{ + dir = 4; + pixel_x = -5 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ua" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ub" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/newscaster{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"uc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ud" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/ss13/l6, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ue" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ug" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ui" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"ul" = ( +/obj/structure/table/reinforced, +/obj/machinery/forensic/dnascanner, +/turf/floor/tiled/white, +/area/ministation/detective) +"um" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"un" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/camera/network/security{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/carpet/blue2, +/area/ministation/security) +"up" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/e2) +"uq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"us" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/firstaid{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"ut" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"uu" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"uv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"ux" = ( +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/vending/sovietsoda{ + dir = 8; + pixel_x = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"uy" = ( +/obj/structure/morgue, +/turf/floor/tiled/dark, +/area/ministation/medical) +"uB" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/hall/w2) +"uC" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/hall/w2) +"uD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/w2) +"uG" = ( +/obj/structure/chair/office/comfy/brown{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled, +/area/ministation/hop) +"uH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/machinery/apc{ + name = "_South APC"; + pixel_y = -24 + }, +/obj/structure/cable, +/turf/floor/tiled, +/area/ministation/hall/e2) +"uI" = ( +/turf/wall/r_wall, +/area/ministation/hop) +"uJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"uK" = ( +/obj/effect/decal/cleanable/filth, +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"uL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/glass/civilian{ + name = "Bar" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/cafe) +"uM" = ( +/obj/machinery/door/firedoor, +/obj/structure/window/basic/full, +/turf/floor/plating, +/area/ministation/cafe) +"uN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/glass/civilian{ + name = "Bar" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/cafe) +"uO" = ( +/obj/machinery/door/airlock/highsecurity{ + req_access = list("ACCESS_HEAD_OF_SECURITY"); + autoset_access = 0 + }, +/obj/machinery/door/blast/regular{ + name = "High Risk Armory"; + id_tag = "goodstuff2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"uP" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"uQ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/security) +"uV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/sign/warning/nosmoking_1{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"uW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"uX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/ministation/medical) +"uZ" = ( +/turf/floor/tiled/dark, +/area/ministation/medical) +"va" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/machinery/camera/network/security{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/security) +"vb" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ve" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters{ + name = "office shutters"; + id_tag = "hopshut" + }, +/turf/floor/plating, +/area/ministation/hop) +"vf" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters{ + name = "office shutters"; + id_tag = "hopshut" + }, +/turf/floor/plating, +/area/ministation/hop) +"vi" = ( +/obj/machinery/door/window/brigdoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/security) +"vk" = ( +/obj/structure/flora/bush/brflowers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"vm" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"vn" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"vp" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/machinery/door/window/brigdoor/eastleft, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/medical) +"vq" = ( +/obj/structure/table/laminate, +/obj/item/book/manual/detective, +/turf/floor/carpet/red, +/area/ministation/detective) +"vr" = ( +/obj/machinery/chem_master/condimaster{ + name = "CondiMaster Neo" + }, +/turf/floor/lino, +/area/ministation/cafe) +"vt" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/structure/flora/pottedplant/minitree, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vv" = ( +/obj/structure/flora/pottedplant/unusual, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vy" = ( +/obj/machinery/vending/boozeomat, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vz" = ( +/obj/structure/table, +/obj/machinery/chemical_dispenser/bar_coffee/full, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vA" = ( +/obj/structure/table, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vE" = ( +/obj/item/synthesized_instrument/guitar, +/obj/machinery/door/firedoor, +/obj/machinery/door/window/southright, +/obj/structure/table/reinforced, +/turf/floor/tiled, +/area/ministation/hydro) +"vF" = ( +/obj/machinery/computer/arcade, +/obj/structure/noticeboard{ + default_pixel_y = 32 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vG" = ( +/obj/machinery/atm{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/vending/cigarette, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"vH" = ( +/obj/structure/table, +/obj/item/chems/dropper, +/obj/item/box/syringes, +/obj/item/mollusc/clam, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/item/flashlight/lamp/green, +/turf/floor/tiled/white, +/area/ministation/medical) +"vJ" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/mob/living/simple_animal/crow/doctor, +/turf/floor/tiled/white, +/area/ministation/medical) +"vK" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/medical) +"vL" = ( +/obj/machinery/door/airlock/medical{ + name = "Chief Medical Officer" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"vM" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/structure/closet/coffin, +/turf/floor/tiled/dark, +/area/ministation/medical) +"vN" = ( +/obj/structure/table, +/obj/item/box/bodybags, +/obj/item/pen, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/item/scanner/autopsy, +/turf/floor/tiled/dark, +/area/ministation/medical) +"vO" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"vP" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/ministation/hall/w2) +"vS" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/command{ + name = "Lieutenant" + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hop) +"vT" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/button/blast_door{ + id_tag = "hopshut"; + name = "Office Shutters Button"; + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hop) +"vU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/hop) +"vV" = ( +/obj/machinery/computer/modular/preset/cardslot/command{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hop) +"vX" = ( +/obj/structure/flora/bush/brflowers, +/turf/floor/fake_grass, +/area/ministation/hydro) +"wc" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"wd" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + req_access = list("ACCESS_MAINT"); + autoset_access = 0 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/medical) +"wj" = ( +/obj/effect/shuttle_landmark/arrivas_south{ + landmark_tag = "nav_ministation_arrivals_west" + }, +/turf/space, +/area/space) +"wk" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wm" = ( +/obj/item/stool/bar/padded, +/turf/floor/carpet, +/area/ministation/cafe) +"wn" = ( +/obj/structure/table/marble, +/obj/structure/sign/painting/monkey_painting{ + pixel_y = 24 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/item/sticky_pad{ + pixel_x = -8; + pixel_y = 1 + }, +/obj/structure/flora/pottedplant/flower, +/obj/machinery/door/blast/shutters{ + id_tag = "barshut"; + name = "Bar Shutters" + }, +/turf/floor/carpet, +/area/ministation/cafe) +"wo" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/button/blast_door{ + id_tag = "barshut"; + name = "Bar Shutters Button"; + pixel_x = -24; + pixel_y = 36 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wp" = ( +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wq" = ( +/obj/structure/hygiene/sink/kitchen{ + dir = 8; + pixel_x = 21 + }, +/obj/machinery/light_switch{ + pixel_x = 27; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wr" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/turf/open, +/area/ministation/maint/l2centrals) +"ws" = ( +/turf/floor/tiled, +/area/ministation/hydro) +"wt" = ( +/obj/effect/floor_decal/snow_floor, +/obj/machinery/gibber, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"wu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"ww" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/camera/network/medbay{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"wx" = ( +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/w2) +"wy" = ( +/obj/machinery/chem_master, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"wz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/ministation/medical) +"wA" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/machinery/door/window/brigdoor/westright, +/obj/item/chems/spray/cleaner, +/turf/floor/plating, +/area/ministation/medical) +"wB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"wC" = ( +/obj/machinery/camera/network/medbay{ + dir = 8; + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/medical) +"wD" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/e2) +"wE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/e2) +"wF" = ( +/turf/floor/tiled, +/area/ministation/hop) +"wL" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/disposal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wN" = ( +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"wO" = ( +/obj/item/chems/condiment/small/peppermill, +/obj/item/utensil/knife, +/obj/item/utensil/fork, +/obj/structure/table/gamblingtable, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/table/gamblingtable, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wQ" = ( +/obj/structure/table/marble, +/obj/item/box/fancy/donut, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/blast/shutters{ + id_tag = "barshut"; + name = "Bar Shutters" + }, +/turf/floor/carpet, +/area/ministation/cafe) +"wR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wS" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/table, +/obj/item/flame/fuelled/lighter/zippo, +/obj/item/chems/drinks/shaker, +/obj/item/clothing/head/collectable/tophat, +/obj/machinery/fabricator/micro, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"wU" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window/brigdoor/southright{ + dir = 1 + }, +/obj/machinery/suit_cycler/medical/prepared, +/turf/floor/tiled/white, +/area/ministation/medical) +"wW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/portable_atmospherics/hydroponics, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"wY" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/ministation/medical) +"wZ" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"xa" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/medical{ + name = "Morgue" + }, +/turf/floor/tiled/dark, +/area/ministation/medical) +"xb" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/ministation/medical) +"xc" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table, +/obj/item/cell/device/high, +/obj/item/cell/device/high, +/obj/item/defibrillator/loaded, +/turf/floor/tiled/white, +/area/ministation/medical) +"xd" = ( +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/carpet/blue, +/area/ministation/medical) +"xe" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"xf" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/hall/w2) +"xg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white/half{ + dir = 1 + }, +/obj/effect/floor_decal/corner/lime/half, +/turf/floor/tiled/white, +/area/ministation/medical) +"xj" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"xn" = ( +/obj/structure/table/laminate/mahogany, +/obj/item/paper_bin, +/turf/floor/carpet/red, +/area/ministation/security) +"xo" = ( +/obj/item/utensil/spoon, +/obj/item/chems/condiment/small/saltshaker, +/obj/item/chems/condiment/small/sugar, +/obj/structure/table/gamblingtable, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/deck/cards, +/obj/structure/table/gamblingtable, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xq" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xr" = ( +/obj/machinery/door/airlock/glass/civilian{ + name = "Hydroponics" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"xs" = ( +/obj/structure/table/marble, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/item/plate/tray, +/obj/machinery/door/blast/shutters{ + id_tag = "barshut"; + name = "Bar Shutters" + }, +/turf/floor/carpet, +/area/ministation/cafe) +"xt" = ( +/obj/structure/table, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/chemical_dispenser/bar_alc/full{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"xy" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled, +/area/ministation/hydro) +"xz" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"xA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"xB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"xC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/medical{ + name = "Chemistry" + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"xD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/medical) +"xE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"xF" = ( +/obj/machinery/camera/network/medbay{ + dir = 1; + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/ministation/medical) +"xH" = ( +/obj/structure/table, +/obj/item/firstaid/fire{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/firstaid/fire{ + pixel_x = -2; + pixel_y = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"xJ" = ( +/turf/wall, +/area/ministation/hop) +"xK" = ( +/obj/machinery/light/small/emergency{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"xO" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"xP" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"xQ" = ( +/obj/item/stool/padded, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xR" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xT" = ( +/obj/item/stool/bar/padded, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet, +/area/ministation/cafe) +"xU" = ( +/obj/structure/table/marble, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/blast/shutters{ + id_tag = "barshut"; + name = "Bar Shutters" + }, +/turf/floor/carpet, +/area/ministation/cafe) +"xV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"xW" = ( +/obj/structure/table/marble, +/obj/machinery/status_display{ + pixel_y = -29; + dir = 1 + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/item/chems/condiment/ketchup, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/blast/shutters{ + id_tag = "barshut"; + name = "Bar Shutters" + }, +/turf/floor/carpet, +/area/ministation/cafe) +"xY" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 1 + }, +/turf/space, +/area/space) +"xZ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"ya" = ( +/obj/machinery/camera/network/security{ + dir = 4 + }, +/turf/floor/carpet/red, +/area/ministation/security) +"yb" = ( +/obj/structure/table, +/obj/machinery/reagentgrinder/juicer, +/obj/item/chems/glass/beaker, +/turf/floor/tiled/white, +/area/ministation/medical) +"yc" = ( +/obj/structure/table, +/obj/machinery/reagent_temperature/cooler, +/obj/item/book/manual/chemistry_recipes, +/obj/item/modular_computer/holotablet/wide, +/turf/floor/tiled/white, +/area/ministation/medical) +"ye" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hop) +"yf" = ( +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 5 + }, +/obj/structure/table/glass, +/obj/item/plant_satchel, +/obj/item/scanner/plant, +/obj/item/wirecutters/clippers, +/obj/item/book/skill/service/botany, +/obj/item/tool/axe/hatchet, +/obj/item/tool/hoe/mini, +/obj/item/tool/hoe/mini, +/obj/item/tool/spade, +/obj/item/tool/spade, +/obj/item/hive_frame/crafted, +/obj/item/hive_frame/crafted, +/obj/item/hive_frame/crafted, +/turf/floor/tiled, +/area/ministation/hydro) +"yg" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"yh" = ( +/obj/structure/table, +/obj/item/firstaid/toxin{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/firstaid/toxin{ + pixel_x = -2; + pixel_y = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"yk" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/open, +/area/ministation/maint/nebypass) +"yl" = ( +/obj/structure/displaycase, +/obj/item/clothing/mask/gas/owl_mask{ + desc = "So realistic, you'd almost think it's the real thing."; + name = "replica 'The Owl' mask"; + pixel_x = 1; + pixel_y = -5 + }, +/obj/machinery/light_switch{ + pixel_y = 29; + pixel_x = 7 + }, +/turf/floor/carpet, +/area/ministation/hop) +"yn" = ( +/obj/random/trash, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"yu" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"yv" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"yw" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"yx" = ( +/obj/machinery/camera/autoname{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"yy" = ( +/obj/item/stool/bar/padded, +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/carpet, +/area/ministation/cafe) +"yA" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/decal/cleanable/tomato_smudge, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/camera/autoname{ + dir = 1 + }, +/obj/structure/reagent_dispensers/beerkeg, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"yB" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"yC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"yD" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/obj/machinery/camera/network/hallway{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"yE" = ( +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hydro) +"yF" = ( +/obj/machinery/camera/autoname{ + dir = 8 + }, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"yG" = ( +/obj/machinery/light, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"yJ" = ( +/obj/structure/table, +/obj/item/gun/launcher/syringe, +/obj/item/flashlight/pen, +/obj/item/flashlight/pen, +/obj/item/clothing/suit/straight_jacket, +/obj/item/chems/hypospray/vial{ + desc = "One of the first hyposprays ever made. Supposedly only a handful exist."; + name = "prototype hypospray"; + origin_tech = null + }, +/obj/item/clothing/neck/stethoscope, +/turf/floor/tiled/white, +/area/ministation/medical) +"yK" = ( +/obj/effect/floor_decal/corner/yellow/half{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"yM" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/junction{ + dir = 8 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"yN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/hallway{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"yP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/yellow/half, +/turf/floor/tiled/white, +/area/ministation/medical) +"yS" = ( +/obj/effect/floor_decal/ss13/l11, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"yV" = ( +/obj/machinery/papershredder, +/turf/floor/tiled, +/area/ministation/hop) +"yY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/table, +/obj/machinery/reagent_temperature, +/obj/machinery/camera/network/medbay{ + dir = 8; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"zd" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ze" = ( +/obj/effect/floor_decal/ss13/l16, +/turf/floor/tiled, +/area/ministation/hall/w2) +"zf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"zg" = ( +/obj/structure/sign/warning/high_voltage{ + pixel_y = 32; + pixel_x = 23 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"zh" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/civilian{ + autoset_access = 0; + name = "Kitchen airlock"; + req_access = list("ACCESS_KITCHEN") + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"zi" = ( +/obj/structure/chair/office/light, +/turf/floor/carpet/red, +/area/ministation/security) +"zj" = ( +/obj/effect/floor_decal/corner/beige/half, +/obj/structure/table/glass, +/obj/machinery/centrifuge/mapped, +/turf/floor/tiled, +/area/ministation/hydro) +"zl" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"zn" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/chair/armchair/black{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"zo" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"zq" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/table/laminate/mahogany, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/item/pen/retractable, +/obj/machinery/light, +/turf/floor/tiled, +/area/ministation/security) +"zt" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/table, +/obj/item/chems/spray/cleaner, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"zv" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"zy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"zA" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/hall/w2) +"zC" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/freezer{ + autoset_access = 0 + }, +/turf/floor/tiled/steel_ridged, +/area/ministation/cafe) +"zD" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 25 + }, +/turf/floor/lino, +/area/ministation/cafe) +"zE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/lino, +/area/ministation/cafe) +"zF" = ( +/turf/floor/lino, +/area/ministation/cafe) +"zG" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"zH" = ( +/obj/machinery/microwave{ + pixel_x = -3; + pixel_y = 6 + }, +/obj/structure/table/laminate, +/obj/machinery/button/blast_door{ + id_tag = "Kitchen1"; + name = "Kitchen Shutter"; + pixel_y = 24 + }, +/turf/floor/lino, +/area/ministation/cafe) +"zI" = ( +/obj/machinery/status_display{ + pixel_y = 30 + }, +/obj/machinery/cooker/cereal, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/lino, +/area/ministation/cafe) +"zJ" = ( +/obj/machinery/vending/dinnerware, +/turf/floor/lino, +/area/ministation/cafe) +"zK" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/lino, +/area/ministation/cafe) +"zL" = ( +/obj/machinery/smartfridge/foods, +/turf/floor/plating, +/area/ministation/cafe) +"zM" = ( +/obj/machinery/atmospherics/portables_connector{ + pixel_x = -3 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"zO" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"zP" = ( +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"zQ" = ( +/turf/wall, +/area/ministation/hydro) +"zS" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"zW" = ( +/obj/machinery/door/airlock/glass/security{ + autoset_access = 0; + name = "Detective's Office"; + req_access = list("ACCESS_FORENSICS") + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate, +/area/ministation/detective) +"zZ" = ( +/obj/structure/chair/comfy/beige{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Ae" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/lino, +/area/ministation/cafe) +"Af" = ( +/obj/machinery/door/airlock/civilian{ + autoset_access = 0; + name = "Kitchen airlock"; + req_access = list("ACCESS_KITCHEN") + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Ag" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/lino, +/area/ministation/cafe) +"Ah" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/lino, +/area/ministation/cafe) +"Ai" = ( +/obj/effect/decal/cleanable/flour, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/lino, +/area/ministation/cafe) +"Aj" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/lino, +/area/ministation/cafe) +"Ak" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/junction{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Am" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"An" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Aq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"As" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"At" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/cooker/grill, +/turf/floor/lino, +/area/ministation/cafe) +"Au" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -23 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"Av" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/lino, +/area/ministation/cafe) +"Aw" = ( +/obj/machinery/cooker/oven, +/turf/floor/lino, +/area/ministation/cafe) +"Ax" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"Ay" = ( +/obj/machinery/icecream_vat, +/turf/floor/lino, +/area/ministation/cafe) +"Az" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -11 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"AA" = ( +/obj/machinery/cooker/candy, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/lino, +/area/ministation/cafe) +"AB" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hop) +"AD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"AG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"AJ" = ( +/obj/structure/closet/wardrobe/mixed, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/jumpsuit, +/obj/item/clothing/jumpsuit, +/obj/item/clothing/jumpsuit, +/obj/item/clothing/jumpsuit{ + color = "#ff00ff" + }, +/obj/item/clothing/jumpsuit{ + color = "#000000" + }, +/obj/item/clothing/jumpsuit{ + color = "#008000" + }, +/obj/item/clothing/jumpsuit{ + color = "#808080" + }, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/turf/floor/tiled/white, +/area/ministation/medical) +"AK" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"AQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/half, +/turf/floor/tiled/white, +/area/ministation/medical) +"AR" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"AX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Be" = ( +/obj/structure/disposalpipe/junction/yjunction{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/ministation/medical) +"Bj" = ( +/obj/machinery/airlock_sensor{ + id_tag = "escape3_sensor"; + pixel_y = 20 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "escape1_vent" + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"Bk" = ( +/obj/structure/table/laminate, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/pen, +/obj/item/camera, +/turf/floor/carpet, +/area/ministation/hall/w2) +"Bm" = ( +/obj/structure/table/laminate, +/turf/floor/lino, +/area/ministation/cafe) +"Br" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/lino, +/area/ministation/cafe) +"Bs" = ( +/obj/structure/chair/office/light, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/red, +/area/ministation/security) +"Bu" = ( +/obj/machinery/door/airlock/medical, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/medical) +"Bv" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/closet/crate/bin/ministation, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Bw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/media/jukebox/old, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Bz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"BA" = ( +/obj/machinery/computer/modular/telescreen/preset/generic{ + name = "north bump"; + pixel_y = 32 + }, +/obj/item/radio/intercom/locked/entertainment{ + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet/blue2, +/area/ministation/security) +"BE" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"BG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"BH" = ( +/obj/effect/floor_decal/ss13/l2, +/turf/floor/tiled, +/area/ministation/hall/w2) +"BI" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/laminate, +/area/ministation/detective) +"BJ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/ministation/cafe) +"BS" = ( +/obj/machinery/vending/snack, +/turf/floor/tiled, +/area/ministation/hall/e2) +"BT" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"BU" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"BW" = ( +/obj/structure/flora/bush/lavendergrass, +/turf/floor/fake_grass, +/area/ministation/hall/w2) +"BZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"Ca" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Cb" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Ci" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Ck" = ( +/turf/floor/plating, +/area/ministation/maint/l2underpass) +"Co" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Cp" = ( +/obj/machinery/vending/wallmed1{ + pixel_y = -24; + dir = 1 + }, +/obj/structure/table/laminate, +/obj/machinery/reagent_temperature, +/obj/item/chems/cooking_vessel/pot, +/obj/item/chems/cooking_vessel/skillet, +/turf/floor/lino, +/area/ministation/cafe) +"Ct" = ( +/obj/structure/closet/chefcloset, +/obj/item/clothing/suit/jacket/winter/hydro, +/obj/item/clothing/suit/jacket/winter/hydro, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/gun/projectile/shotgun/doublebarrel/sawn, +/turf/floor/carpet, +/area/ministation/cafe) +"Cu" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/medical) +"Cw" = ( +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"Cx" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + id_tag = "CMO1"; + name = "CMO Shutters" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/medical) +"Cz" = ( +/obj/machinery/door/window/brigdoor{ + dir = 1; + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/structure/table/reinforced, +/obj/machinery/door/window/brigdoor, +/obj/machinery/door/blast/shutters{ + name = "security shutter"; + id_tag = "armoryshut" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"CD" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/medical) +"CJ" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"CL" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"CO" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/item/clothing/suit/jacket/winter/security, +/obj/item/flashlight/maglight, +/obj/item/chems/spray/pepper, +/obj/structure/closet/secure_closet/warden{ + req_access = list("ACCESS_BRIG") + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"CP" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"CU" = ( +/obj/machinery/door/airlock/external{ + name = "Arrival Airlock"; + autoset_access = 0 + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"CV" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/carpet, +/area/ministation/hall/w2) +"CW" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/borderfloorblack{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Db" = ( +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_EVA"); + autoset_access = 0; + dir = 4 + }, +/obj/item/suit_cooling_unit, +/turf/floor/tiled, +/area/ministation/security) +"Dh" = ( +/obj/effect/floor_decal/corner/lime/half{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Di" = ( +/obj/machinery/alarm{ + pixel_y = -2; + dir = 4; + pixel_x = -24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/security) +"Dj" = ( +/obj/structure/table/laminate, +/obj/item/chems/condiment/enzyme, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/chems/spray/cleaner, +/turf/floor/lino, +/area/ministation/cafe) +"Dk" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/structure/closet/secure_closet/freezer/fridge, +/obj/item/chems/drinks/juicebox/apple, +/obj/item/chems/drinks/juicebox/apple, +/obj/item/chems/drinks/juicebox/grape, +/obj/item/chems/drinks/juicebox/grape, +/obj/item/chems/drinks/juicebox/orange, +/obj/item/chems/drinks/juicebox/orange, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"Dl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/civilian{ + autoset_access = 0; + name = "Kitchen airlock"; + req_access = list("ACCESS_KITCHEN") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Dn" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Ds" = ( +/obj/structure/bed, +/obj/item/bedsheet/hop, +/obj/random/plushie, +/turf/floor/carpet, +/area/ministation/hop) +"Dv" = ( +/obj/structure/railing/mapped, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"Dw" = ( +/obj/machinery/photocopier, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hop) +"DA" = ( +/obj/machinery/button/blast_door{ + req_access = list("ACCESS_HEAD_OF_SECURITY"); + dir = 1; + pixel_y = -24; + name = "High Risk Armory Button"; + id_tag = "goodstuff2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"DC" = ( +/obj/machinery/newscaster{ + pixel_x = -32; + dir = 8 + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"DD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"DF" = ( +/obj/abstract/landmark/start{ + name = "Robot" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"DG" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"DH" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/shoes/legguards/ablative, +/obj/item/clothing/gloves/armguards/ablative, +/obj/item/clothing/suit/armor/laserproof, +/turf/floor/tiled/dark, +/area/ministation/security) +"DI" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = -14 + }, +/turf/space, +/area/space) +"DJ" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"DO" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/borderfloorblack{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"DY" = ( +/obj/machinery/camera/network/security{ + dir = 4 + }, +/obj/structure/closet/secure_closet{ + req_access = list("ACCESS_FORENSICS"); + name = "evidence locker"; + closet_appearance = /decl/closet_appearance/secure_closet/security + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/security) +"DZ" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = -14 + }, +/obj/structure/lattice, +/turf/space, +/area/space) +"Ea" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Eb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Ec" = ( +/turf/floor/carpet, +/area/ministation/hall/w2) +"Eg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Ei" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/structure/chair/comfy/beige, +/turf/floor/carpet, +/area/ministation/hall/w2) +"Es" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/camera/autoname{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Ev" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 1 + }, +/turf/space, +/area/ministation/arrival) +"Ez" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hop) +"EA" = ( +/obj/effect/shuttle_landmark/arrivas_south, +/turf/space, +/area/space) +"ED" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/cafe) +"EE" = ( +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Security Officer" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/security) +"EG" = ( +/obj/machinery/light/small/emergency{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"EL" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"EM" = ( +/obj/machinery/computer/account_database{ + dir = 8 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/camera/network/command{ + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled, +/area/ministation/hop) +"EO" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"EQ" = ( +/obj/structure/rack/dark, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller{ + pixel_y = 10 + }, +/obj/item/roller{ + pixel_y = 10 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ER" = ( +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "16-0" + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers, +/obj/machinery/atmospherics/pipe/zpipe/up/supply, +/obj/structure/disposalpipe/up{ + dir = 2 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"EV" = ( +/obj/structure/bed, +/obj/machinery/light{ + dir = 4 + }, +/obj/item/bedsheet/clown, +/obj/random/plushie, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"Fa" = ( +/obj/structure/closet, +/obj/item/clothing/mask/gas/clown_hat, +/obj/item/clothing/shoes/clown_shoes, +/obj/item/clothing/costume/clown, +/obj/item/stamp/clown, +/obj/item/backpack/clown, +/obj/item/bikehorn, +/obj/item/box/fancy/crayons, +/obj/item/poster, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"Fh" = ( +/obj/structure/flora/bush, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Fj" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"Fn" = ( +/obj/structure/closet, +/obj/random/maintenance, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/item/poster, +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Fo" = ( +/obj/machinery/door/firedoor, +/obj/machinery/smartfridge/chemistry, +/turf/floor/tiled/white, +/area/ministation/medical) +"Fr" = ( +/obj/structure/flora/pottedplant/flower, +/turf/floor/tiled/white, +/area/ministation/medical) +"Ft" = ( +/obj/structure/target_stake/steel, +/turf/floor/tiled, +/area/ministation/security) +"Fy" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"Fz" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"FF" = ( +/obj/structure/reagent_dispensers/water_cooler{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"FI" = ( +/obj/machinery/biogenerator, +/obj/effect/floor_decal/corner/beige/half, +/turf/floor/tiled, +/area/ministation/hydro) +"FJ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/computer/modular/telescreen/preset/generic{ + name = "south bump"; + pixel_y = -32; + dir = 1 + }, +/obj/item/radio/intercom/locked/entertainment{ + dir = 1; + pixel_y = -30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"FL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/junction/mirrored, +/turf/floor/tiled, +/area/ministation/security) +"FQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"FZ" = ( +/obj/machinery/firealarm{ + pixel_y = 32 + }, +/obj/structure/chair/comfy/beige, +/turf/floor/carpet, +/area/ministation/hall/w2) +"Ga" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"Gb" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/carpet/blue2, +/area/ministation/security) +"Gd" = ( +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"Ge" = ( +/obj/structure/table, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/turf/floor/tiled/white, +/area/ministation/medical) +"Gg" = ( +/obj/structure/railing/mapped, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Gh" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Gi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/abstract/landmark/start{ + name = "Warden" + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"Gk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled, +/area/ministation/security) +"Gp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"Gr" = ( +/obj/structure/flora/bush/sunnybush, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Gu" = ( +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/obj/structure/rack/dark, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/turf/floor/tiled/white, +/area/ministation/medical) +"Gx" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Gy" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/borderfloorblack{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Gz" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor, +/area/ministation/hop) +"GC" = ( +/obj/machinery/suit_cycler/medical/prepared, +/obj/machinery/door/window/brigdoor/southright{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"GE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"GF" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"GN" = ( +/obj/structure/sign/warning/lethal_turrets, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/camera/motion{ + req_access = list("ACCESS_SECURITY") + }, +/obj/structure/closet/secure_closet/brig, +/obj/item/implantcase/death_alarm, +/obj/item/implantcase/death_alarm, +/obj/item/implanter, +/turf/floor/tiled/dark, +/area/ministation/security) +"GO" = ( +/obj/effect/overlay/palmtree_r, +/turf/floor/fake_grass, +/area/ministation/security) +"GR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/w2) +"GZ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Hd" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/table/steel, +/obj/item/flame/candle/scented, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Hi" = ( +/obj/effect/floor_decal/industrial/firstaid{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"Hn" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Hq" = ( +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hydro) +"Hx" = ( +/obj/structure/table/laminate, +/obj/machinery/reagent_temperature/cooler, +/turf/floor/lino, +/area/ministation/cafe) +"Hy" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/pen, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Hz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"HF" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_y = -1; + pixel_x = -25 + }, +/obj/structure/closet/secure_closet/detective, +/obj/item/chems/drinks/bottle/whiskey, +/obj/item/ammo_magazine/pistol/flash, +/obj/item/classic_baton{ + pixel_w = -7 + }, +/obj/item/ammo_magazine/pistol/rubber, +/obj/item/ammo_magazine/pistol, +/obj/item/camera/loaded, +/obj/item/hand_labeler, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/clothing/head/beret/corp/sec, +/turf/floor/laminate, +/area/ministation/detective) +"HG" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"HJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled, +/area/ministation/hall/w2) +"HL" = ( +/obj/machinery/chemical_dispenser/full, +/obj/item/chems/glass/beaker/large, +/turf/floor/tiled/white, +/area/ministation/medical) +"HM" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/item/pen, +/obj/item/eftpos, +/obj/item/mollusc/clam, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hop) +"HN" = ( +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -29 + }, +/turf/floor/lino, +/area/ministation/cafe) +"HO" = ( +/turf/floor/reinforced/airless, +/area/space) +"HP" = ( +/turf/floor/carpet/red, +/area/ministation/detective) +"HR" = ( +/mob/living/simple_animal/passive/mouse, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"HW" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_EVA"); + autoset_access = 0; + dir = 4 + }, +/obj/machinery/suit_cycler/security/prepared, +/turf/floor/tiled, +/area/ministation/security) +"HX" = ( +/obj/structure/table, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/chems/drinks/glass2/mug, +/obj/item/chems/drinks/glass2/mug, +/obj/effect/floor_decal/carpet, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"Ia" = ( +/obj/structure/table/laminate/mahogany, +/obj/machinery/faxmachine/mapped, +/turf/floor/carpet/red, +/area/ministation/security) +"Ib" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Ie" = ( +/obj/machinery/status_display{ + pixel_y = -29; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/arrival) +"Ig" = ( +/obj/structure/bed, +/obj/item/bedsheet/hos, +/obj/random/plushie, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/carpet/blue2, +/area/ministation/security) +"Ij" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Ik" = ( +/turf/floor/bluegrid, +/area/ministation/security) +"Im" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/window/southleft, +/obj/structure/table/reinforced, +/obj/structure/sign/department/botany{ + pixel_y = -1; + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"In" = ( +/obj/structure/flora/bush/sunnybush, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Io" = ( +/obj/machinery/light/small, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Ip" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"Ir" = ( +/obj/structure/table, +/obj/item/folder/blue, +/obj/item/box/PDAs, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled, +/area/ministation/hop) +"Iw" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/unary/engine, +/turf/space, +/area/ministation/arrival) +"Ix" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "l2_central_south_vent" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Iz" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/w2) +"IA" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "Dock Airlock"; + autoclose = 0 + }, +/turf/floor/plating, +/area/ministation/arrival) +"IB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"II" = ( +/obj/structure/table, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/item/stack/medical/bandage/advanced, +/obj/effect/floor_decal/industrial/hatch/red, +/obj/item/flashlight/lamp/green, +/turf/floor/tiled/white, +/area/ministation/medical) +"IO" = ( +/obj/structure/table, +/obj/item/firstaid/o2{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/firstaid/o2{ + pixel_x = -2; + pixel_y = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"IP" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/machinery/recharger, +/turf/floor/tiled, +/area/ministation/hop) +"IQ" = ( +/obj/structure/flora/bush/brflowers, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/fake_grass, +/area/ministation/hydro) +"IT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"IX" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Jc" = ( +/obj/structure/closet/secure_closet/personal/patient, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Jd" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/machinery/camera/autoname{ + dir = 1 + }, +/turf/floor/carpet, +/area/ministation/cafe) +"Ji" = ( +/turf/floor/fake_grass, +/area/ministation/hydro) +"Jj" = ( +/obj/structure/table/laminate, +/obj/machinery/camera/autoname{ + dir = 8 + }, +/obj/machinery/cooker/candy, +/turf/floor/lino, +/area/ministation/cafe) +"Jl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Jm" = ( +/obj/machinery/apc{ + dir = 4; + name = "_East APC"; + pixel_x = 27; + pixel_y = 2 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Jn" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/turf/floor/tiled/dark, +/area/ministation/security) +"Jo" = ( +/obj/structure/table/laminate, +/obj/item/box/fancy/cigarettes, +/obj/item/pen, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"Js" = ( +/obj/structure/closet/secure_closet/brig, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/floor/tiled, +/area/ministation/security) +"Jx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"Jz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/railing/mapped, +/obj/effect/floor_decal/borderfloorblack/corner{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"JH" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"JJ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"JO" = ( +/obj/structure/closet/secure_closet/guncabinet, +/obj/item/box/ammo/stunshells/large, +/obj/item/box/ammo/stunshells/large, +/obj/item/box/ammo/beanbags, +/obj/item/box/ammo/beanbags, +/obj/item/gun/projectile/shotgun/doublebarrel/sawn{ + ammo_type = /obj/item/ammo_casing/shotgun/beanbag; + name = "sawn-off shotgun SN 101" + }, +/obj/item/gun/projectile/shotgun/doublebarrel/sawn{ + ammo_type = /obj/item/ammo_casing/shotgun/beanbag; + name = "sawn-off shotgun SN 102" + }, +/obj/item/gun/energy/taser{ + name = "electrolaser SN 22" + }, +/obj/item/gun/energy/taser{ + name = "electrolaser SN 21" + }, +/obj/item/gun/energy/gun/secure{ + name = "smartgun SN 11" + }, +/obj/item/gun/energy/gun/secure{ + name = "smartgun SN 12" + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/item/gun/energy/gun/secure{ + name = "smartgun SN 13" + }, +/obj/item/gun/energy/gun/secure{ + name = "smartgun SN 14" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"JQ" = ( +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"JV" = ( +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_HEAD_OF_SECURITY"); + autoset_access = 0; + dir = 8 + }, +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/ammo_magazine/pistol, +/obj/item/ammo_magazine/pistol, +/obj/item/ammo_magazine/pistol, +/turf/floor/tiled/dark, +/area/ministation/security) +"JW" = ( +/obj/structure/table, +/obj/machinery/recharger, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/camera/motion, +/turf/floor/tiled/dark, +/area/ministation/security) +"JX" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"JZ" = ( +/turf/wall, +/area/ministation/detective) +"Kd" = ( +/obj/structure/table/reinforced, +/obj/machinery/forensic/microscope, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/detective) +"Ke" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/dark, +/area/ministation/security) +"Ki" = ( +/obj/structure/window/basic/full, +/turf/floor/plating, +/area/ministation/hydro) +"Kk" = ( +/obj/structure/bed, +/obj/item/bedsheet/blue, +/obj/random/plushie, +/turf/floor/carpet/blue, +/area/ministation/medical) +"Km" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"Kn" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + id_tag = "Barman1" + }, +/turf/floor/plating, +/area/ministation/cafe) +"Kr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Kt" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/medical) +"Kv" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/flora/bush/fullgrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"Kz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/camera/network/hallway{ + dir = 1 + }, +/obj/structure/flora/bush/lavendergrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"KG" = ( +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"KH" = ( +/obj/structure/table, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/box/ammo/beanbags, +/obj/machinery/recharger, +/obj/structure/window/reinforced, +/turf/floor/tiled, +/area/ministation/security) +"KI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/security) +"KK" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"KN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"KR" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"KS" = ( +/turf/floor/tiled/dark, +/area/ministation/security) +"KV" = ( +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_EVA"); + autoset_access = 0; + dir = 4 + }, +/obj/machinery/suit_cycler/security/prepared, +/turf/floor/tiled, +/area/ministation/security) +"KW" = ( +/obj/structure/chair/office/comfy/brown{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/carpet/red, +/area/ministation/detective) +"KX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"KZ" = ( +/obj/structure/window/reinforced, +/obj/structure/table, +/obj/machinery/recharger, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/item/gun/energy/laser/practice, +/turf/floor/tiled, +/area/ministation/security) +"Lk" = ( +/obj/structure/table/laminate/mahogany, +/obj/item/pen/multi, +/turf/floor/carpet/red, +/area/ministation/security) +"Lm" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Lp" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/security) +"Lr" = ( +/obj/structure/table/laminate, +/obj/machinery/reagentgrinder/juicer, +/obj/item/chems/glass/beaker, +/turf/floor/lino, +/area/ministation/cafe) +"Ls" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"Lt" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"LE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"LH" = ( +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2underpass) +"LI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"LK" = ( +/obj/structure/chair/office/light{ + dir = 4 + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/carpet/red, +/area/ministation/security) +"LM" = ( +/obj/structure/table/laminate, +/obj/item/knife/kitchen/cleaver, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet, +/area/ministation/cafe) +"LN" = ( +/obj/machinery/computer/dummy, +/turf/floor/plating, +/area/ministation/arrival) +"LQ" = ( +/obj/machinery/door/airlock/glass/security{ + req_access = list("ACCESS_SECURITY"); + autoset_access = 0 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"LR" = ( +/obj/machinery/recharger/wallcharger{ + pixel_y = 25 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"LT" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"LV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/e2) +"LW" = ( +/obj/structure/table, +/obj/item/box/beakers, +/obj/item/chems/glass/beaker/large, +/obj/item/chems/glass/beaker/large, +/obj/item/box/fancy/vials, +/turf/floor/tiled/white, +/area/ministation/medical) +"LY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"Mb" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Md" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Me" = ( +/obj/structure/rack, +/obj/item/training_dummy, +/obj/item/training_dummy/alien, +/obj/item/training_dummy/syndicate, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/item/training_dummy/syndicate, +/obj/item/training_dummy/syndicate, +/obj/item/training_dummy/syndicate, +/obj/item/training_dummy/alien, +/obj/item/training_dummy/alien, +/obj/item/training_dummy/alien, +/turf/floor/tiled, +/area/ministation/security) +"Mp" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"Mu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Mw" = ( +/obj/machinery/cryopod{ + dir = 1 + }, +/obj/abstract/landmark/latejoin/cryo, +/obj/machinery/status_display{ + pixel_y = -1; + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"MA" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/closet/secure_closet/hop2, +/obj/item/book/skill/organizational/finance, +/obj/item/clothing/suit/jacket/winter, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/item/gun/energy/laser/practice, +/turf/floor/carpet, +/area/ministation/hop) +"MF" = ( +/obj/structure/bed/roller, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"MG" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/w2) +"MH" = ( +/obj/structure/table, +/obj/item/implantcase/tracking, +/obj/item/implantcase/chem, +/obj/item/implanter, +/obj/machinery/button/alternate/door{ + dir = 8; + id_tag = "secdoor"; + name = "security airlock access button"; + pixel_x = 24 + }, +/turf/floor/tiled, +/area/ministation/security) +"MK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/hop) +"ML" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"MQ" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/open, +/area/ministation/hall/w2) +"MT" = ( +/obj/machinery/body_scan_display{ + pixel_y = 20; + id_tag = "mediscanner1" + }, +/obj/machinery/bodyscanner{ + dir = 8; + id_tag = "mediscanner1" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"MU" = ( +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled, +/area/ministation/hop) +"MW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"Ne" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet/red, +/area/ministation/security) +"Nf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/sign/double/barsign{ + dir = 1; + pixel_x = 1; + pixel_y = -63 + }, +/obj/structure/flora/bush/lavendergrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"Nh" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4; + icon_state = "warningcorner" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Ni" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Nj" = ( +/obj/structure/table/reinforced, +/obj/item/folder, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/item/bell, +/turf/floor/tiled/white, +/area/ministation/medical) +"Nm" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"No" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/camera/network/security{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/vending/wallmed1{ + pixel_x = -26; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"Np" = ( +/obj/machinery/door/airlock/command, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor, +/area/ministation/hop) +"Nq" = ( +/obj/effect/floor_decal/ss13/l8, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Nu" = ( +/obj/machinery/airlock_sensor{ + id_tag = "escape2_sensor"; + pixel_y = -20; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "escape1_vent" + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"Ny" = ( +/obj/structure/closet/secure_closet/guncabinet, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/gun/projectile/automatic/smg{ + name = "submachine gun SN 301" + }, +/obj/item/gun/projectile/automatic/smg{ + name = "submachine gun SN 302" + }, +/obj/item/gun/energy/plasmastun{ + name = "plasma pulse projector SN 444" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"Nz" = ( +/obj/effect/floor_decal/ss13/l15, +/turf/floor/tiled, +/area/ministation/hall/w2) +"NA" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"NC" = ( +/turf/open, +/area/ministation/hall/w2) +"ND" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"NE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"NM" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"NO" = ( +/obj/abstract/level_data_spawner/main_level, +/turf/space, +/area/space) +"NR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"NU" = ( +/obj/structure/closet, +/obj/random/maintenance, +/obj/item/clothing/glasses/meson, +/obj/item/flashlight, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"NX" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"NZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Ob" = ( +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/arrival) +"Oc" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Oe" = ( +/obj/structure/flora/bush/fernybush, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Of" = ( +/obj/abstract/landmark/start{ + name = "Head of Security" + }, +/turf/floor/carpet/blue2, +/area/ministation/security) +"Ok" = ( +/obj/machinery/recharger/wallcharger{ + pixel_y = 25 + }, +/obj/item/clothing/suit/armor/reactive, +/obj/structure/rack, +/obj/item/shield/riot, +/obj/item/shield/riot/metal/security, +/obj/item/shield/riot, +/turf/floor/tiled/dark, +/area/ministation/security) +"Om" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Oo" = ( +/obj/machinery/beehive, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Op" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/security) +"Oq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/double/glass/security{ + id_tag = "secdoor"; + name = "Security"; + req_access = list("ACCESS_SECURITY"); + autoset_access = 0 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/security) +"Ou" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/security) +"Ov" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Ow" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"OF" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/cafe) +"OG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"OH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"OK" = ( +/obj/machinery/door/airlock/security{ + name = "Head of Security"; + autoset_access = 0; + req_access = list("ACCESS_HEAD_OF_SECURITY") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/dark, +/area/ministation/security) +"OL" = ( +/obj/structure/closet/secure_closet/medical1, +/turf/floor/tiled/white, +/area/ministation/medical) +"ON" = ( +/obj/structure/table/reinforced, +/obj/item/folder, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled/white, +/area/ministation/medical) +"OT" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + locked = 1; + id_tag = "escape1_airlock_interior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"OV" = ( +/obj/structure/window/basic/full, +/turf/floor/tiled, +/area/ministation/hydro) +"OW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/directions/evac{ + dir = 8; + pixel_x = -32; + pixel_y = 25 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + icon_state = "warningcorner" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"OY" = ( +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/e2) +"OZ" = ( +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"Pb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + id_tag = "SURG2"; + name = "Surgery Shutters" + }, +/turf/floor/plating, +/area/ministation/medical) +"Pc" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/medical) +"Pd" = ( +/obj/structure/table/laminate, +/obj/item/box/fancy/cigarettes{ + pixel_y = 2 + }, +/obj/item/flame/fuelled/lighter/random, +/turf/floor/carpet, +/area/ministation/hall/w2) +"Pe" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/iv_drip, +/turf/floor/tiled/white, +/area/ministation/medical) +"Pf" = ( +/turf/wall, +/area/ministation/arrival) +"Pj" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Pk" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Po" = ( +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"Ps" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Pw" = ( +/obj/structure/table, +/obj/machinery/reagentgrinder, +/turf/floor/tiled/white, +/area/ministation/medical) +"Pz" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/medical) +"PH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"PI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"PL" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"PN" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + locked = 1; + id_tag = "escape1_airlock_exterior" + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"PO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/e2) +"PR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/light, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"PS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"PU" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/security) +"PV" = ( +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 32 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/carpet/blue2, +/area/ministation/security) +"PX" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "l2_central_north_vent"; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"PY" = ( +/obj/machinery/airlock_sensor{ + id_tag = "escape1_sensor"; + pixel_y = -20; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "escape1_vent" + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"Qa" = ( +/obj/structure/bed, +/obj/item/bedsheet/brown, +/obj/machinery/button/blast_door{ + id_tag = "Barman1"; + name = "Kitchen Shutter"; + pixel_y = 24 + }, +/obj/random/plushie, +/turf/floor/carpet, +/area/ministation/cafe) +"Qg" = ( +/obj/structure/closet/secure_closet/security, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/jacket/winter/security, +/obj/item/flashlight/maglight, +/obj/item/chems/spray/pepper, +/turf/floor/tiled, +/area/ministation/security) +"Qh" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/effect/floor_decal/corner/paleblue/full, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/medical{ + name = "Medical Supply" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Qj" = ( +/obj/structure/chair/comfy/beige{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Qk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Qm" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/security) +"Qp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"Qs" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Qw" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Qy" = ( +/obj/machinery/vending/snix, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Qz" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/obj/abstract/landmark/start{ + name = "Head Doctor" + }, +/turf/floor/carpet/blue, +/area/ministation/medical) +"QC" = ( +/obj/machinery/camera/network/medbay{ + dir = 1; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"QE" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/closet, +/obj/random/maintenance, +/obj/random/suit, +/obj/item/poster, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"QF" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"QH" = ( +/obj/structure/table/laminate/mahogany, +/obj/item/pen, +/turf/floor/carpet/red, +/area/ministation/security) +"QK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"QL" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/window/brigdoor, +/obj/machinery/door/blast/shutters{ + name = "security shutter"; + id_tag = "secshut" + }, +/turf/floor/plating, +/area/ministation/security) +"QM" = ( +/obj/structure/rack, +/obj/item/suit_cooling_unit, +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/turf/floor/tiled/white, +/area/ministation/medical) +"QN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/w2) +"QO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/lino, +/area/ministation/cafe) +"QP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/medical) +"QR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/security) +"Rd" = ( +/obj/structure/chair/armchair/black{ + dir = 1 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Rk" = ( +/obj/machinery/cryopod{ + dir = 4 + }, +/obj/abstract/landmark/latejoin, +/turf/floor/plating, +/area/ministation/arrival) +"Rl" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"Ro" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/stone, +/area/ministation/hall/e2) +"Rp" = ( +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/hygiene/drain, +/turf/floor/tiled, +/area/ministation/hydro) +"Ru" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/portable_atmospherics/hydroponics, +/obj/effect/floor_decal/corner/green/half{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"Rw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/lino, +/area/ministation/cafe) +"Rx" = ( +/turf/wall, +/area/ministation/maint/secmaint) +"Ry" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"RB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"RD" = ( +/turf/wall/r_wall, +/area/ministation/cryo) +"RH" = ( +/obj/structure/lattice, +/turf/wall/r_wall, +/area/ministation/cryo) +"RK" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "32-1" + }, +/turf/open, +/area/ministation/maint/hydromaint) +"RQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"RU" = ( +/obj/machinery/camera/network/medbay{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/medical) +"RW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"RZ" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/camera/autoname{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Sa" = ( +/turf/wall, +/area/ministation/maint/hydromaint) +"Sb" = ( +/obj/structure/table/reinforced, +/obj/item/scanner/reagent, +/obj/item/modular_computer/laptop/preset/custom_loadout/standard, +/turf/floor/tiled/white, +/area/ministation/detective) +"Sd" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/sign/warning/airlock{ + pixel_y = -1; + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Sg" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Sp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/flora/bush/lavendergrass, +/turf/floor/fake_grass, +/area/ministation/hall/e2) +"Sq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Su" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Sw" = ( +/obj/structure/meat_hook, +/turf/floor/tiled/freezer/kitchen, +/area/ministation/cafe) +"Sx" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "Dock Airlock" + }, +/turf/floor/plating, +/area/ministation/arrival) +"Sy" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/structure/railing/mapped, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/open, +/area/ministation/hall/w2) +"SA" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"SB" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"SC" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "sqm_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "sqm_airlock"; + name = "exterior access button"; + pixel_x = 10; + pixel_y = 20; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"SD" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/arrival) +"SF" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/ss13/l4, +/turf/floor/tiled, +/area/ministation/hall/w2) +"SG" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 6 + }, +/obj/structure/flora/pottedplant/orientaltree, +/turf/floor/tiled/white, +/area/ministation/medical) +"SJ" = ( +/obj/machinery/chem_master/condimaster{ + name = "CondiMaster Neo" + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/lino, +/area/ministation/cafe) +"SK" = ( +/obj/machinery/light/small/emergency{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/arrival) +"SV" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"SW" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/tiled, +/area/ministation/hop) +"SX" = ( +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"SZ" = ( +/obj/structure/table, +/obj/item/belt/medical/emt, +/obj/item/bodybag/rescue, +/obj/item/auto_cpr, +/turf/floor/tiled/white, +/area/ministation/medical) +"Td" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"Te" = ( +/obj/structure/chair/office/light, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"Ti" = ( +/obj/machinery/vending/cigarette, +/turf/floor/tiled/dark, +/area/ministation/security) +"Tj" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Tk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/dark, +/area/ministation/security) +"To" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Tr" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"Ts" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/carpet/blue, +/area/ministation/medical) +"Tv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/borderfloorblack{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"TA" = ( +/obj/machinery/cryopod{ + dir = 4 + }, +/obj/abstract/landmark/latejoin, +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/arrival) +"TB" = ( +/obj/machinery/door/airlock/hatch/maintenance{ + autoset_access = 0; + req_access = list("ACCESS_FORENSICS") + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/detective) +"TD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"TM" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "sqm_vent"; + dir = 8 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 0; + id_tag = "sqm_airlock"; + pixel_y = 24; + tag_airpump = "sqm_vent"; + tag_chamber_sensor = "sqm_sensor"; + tag_exterior_door = "sqm_airlock_exterior"; + tag_interior_door = "sqm_airlock_interior" + }, +/obj/machinery/airlock_sensor{ + id_tag = "sqm_sensor"; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"TO" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"TQ" = ( +/obj/machinery/door/airlock/hatch/autoname/command{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ministation/security) +"TS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"TT" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/security) +"TV" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/glass/security{ + req_access = list("ACCESS_SECURITY"); + autoset_access = 0 + }, +/turf/floor/tiled, +/area/ministation/security) +"TX" = ( +/obj/structure/table/laminate, +/obj/item/eftpos, +/obj/item/chems/spray/cleaner, +/obj/item/chems/packet/honey_fake, +/obj/item/chems/packet/honey_fake, +/obj/item/chems/packet/honey, +/obj/item/chems/packet/honey, +/obj/item/chems/packet/honey, +/obj/item/chems/packet/honey_fake, +/obj/item/chems/packet/honey, +/turf/floor/lino, +/area/ministation/cafe) +"Ue" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/chair/armchair/black{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Ug" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/railing/mapped, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Uh" = ( +/obj/structure/lattice, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Uj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/obj/effect/floor_decal/carpet{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"Up" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/item/poster, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"Ur" = ( +/obj/structure/table/laminate/mahogany, +/turf/floor/carpet/red, +/area/ministation/security) +"Ut" = ( +/obj/structure/sign/plaque/golden/security{ + pixel_y = 32 + }, +/obj/machinery/vending/security, +/turf/floor/tiled, +/area/ministation/security) +"Uv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Uw" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/table/steel, +/obj/machinery/recharger, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Ux" = ( +/obj/structure/lattice, +/obj/structure/flora/bush/brflowers, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Uz" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "Dock Airlock"; + autoclose = 0 + }, +/turf/floor/plating, +/area/ministation/hall/w2) +"UB" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/item/taperecorder, +/obj/item/firstaid/surgery, +/obj/item/scanner/autopsy, +/turf/floor/tiled/white, +/area/ministation/detective) +"UC" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/structure/closet/wardrobe/chemistry_white, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/medical) +"UJ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/turf/floor/tiled/white, +/area/ministation/medical) +"UL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/ministation/maint/l2centraln) +"UN" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/arrival) +"UV" = ( +/obj/item/mollusc/barnacle{ + pixel_x = 15 + }, +/turf/space, +/area/space) +"UW" = ( +/obj/structure/chair, +/turf/floor/tiled, +/area/ministation/hall/e2) +"UY" = ( +/obj/machinery/apc{ + dir = 4; + name = "_East APC"; + pixel_x = 27; + pixel_y = 2 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"UZ" = ( +/turf/wall/r_wall/hull, +/area/ministation/arrival) +"Va" = ( +/obj/structure/chair/wheelchair, +/obj/machinery/camera/network/medbay{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Vb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/security) +"Vc" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"Vd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/tiled, +/area/ministation/security) +"Vg" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"Vi" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/medical) +"Vk" = ( +/obj/machinery/door/airlock/glass/medical{ + autoset_access = 0; + name = "Cryogenics airlock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/ministation/cryo) +"Vq" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/fake_grass, +/area/ministation/hydro) +"Vr" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hop) +"Vs" = ( +/obj/machinery/door/airlock/external/glass{ + locked = 1; + id_tag = "l2_central_south_airlock_exterior"; + autoset_access = 0 + }, +/obj/machinery/button/access/interior{ + id_tag = "l2_central_south_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = -10; + command = "cycle_exterior"; + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Vt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"Vu" = ( +/obj/machinery/status_display{ + pixel_y = -1; + pixel_x = 32; + dir = 4 + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 5 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"Vx" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"VC" = ( +/obj/structure/table, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/clothing/suit/surgicalapron, +/obj/item/clothing/suit/surgicalapron, +/obj/item/clothing/suit/surgicalapron, +/obj/item/box/masks, +/obj/item/box/gloves, +/obj/item/box/syringes, +/obj/effect/floor_decal/corner/paleblue{ + dir = 9 + }, +/obj/item/chems/glass/beaker, +/turf/floor/tiled/white, +/area/ministation/medical) +"VE" = ( +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"VJ" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"VL" = ( +/obj/structure/closet/emcloset, +/obj/machinery/light/small/emergency{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/arrival) +"VN" = ( +/obj/machinery/alarm{ + pixel_y = -24; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"VO" = ( +/obj/machinery/vending/hydroseeds{ + dir = 1 + }, +/obj/effect/floor_decal/corner/beige/half, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"VR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/e2) +"VS" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters{ + name = "security shutter"; + id_tag = "secshut" + }, +/turf/floor/plating, +/area/ministation/security) +"VY" = ( +/obj/structure/bed/roller, +/turf/floor/tiled/white, +/area/ministation/medical) +"VZ" = ( +/obj/machinery/door/firedoor, +/obj/structure/window/basic/full, +/obj/machinery/door/blast/shutters/open{ + id_tag = "quarantine"; + name = "quarantine shutters" + }, +/turf/floor/plating, +/area/ministation/medical) +"Wa" = ( +/obj/structure/table/laminate, +/obj/item/flashlight/lamp/green{ + pixel_x = 1; + pixel_y = 5 + }, +/obj/machinery/status_display{ + pixel_y = 32 + }, +/obj/structure/sign/warning/smoking{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/carpet, +/area/ministation/hall/w2) +"Wb" = ( +/turf/wall, +/area/ministation/cryo) +"Wc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"Wd" = ( +/turf/floor/plating, +/area/ministation/maint/l2centrals) +"Wf" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/open, +/area/ministation/maint/sebypass) +"Wi" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/tiled, +/area/ministation/security) +"Wj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Wl" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -23 + }, +/turf/floor/laminate, +/area/ministation/detective) +"Wm" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled, +/area/ministation/security) +"Wo" = ( +/obj/structure/stairs/long/east, +/turf/floor/tiled, +/area/ministation/hall/w2) +"Wr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/carpet/blue3, +/area/ministation/security) +"Wt" = ( +/obj/item/clothing/suit/jacket/winter/hydro, +/obj/item/clothing/suit/jacket/winter/hydro, +/obj/structure/closet/chefcloset, +/turf/floor/carpet, +/area/ministation/cafe) +"Wv" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Ww" = ( +/obj/machinery/cryopod, +/obj/abstract/landmark/latejoin, +/turf/floor/plating, +/area/ministation/arrival) +"WC" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/item/beartrap, +/obj/random/maintenance, +/obj/structure/rack, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"WF" = ( +/obj/item/mollusc/barnacle{ + pixel_x = 15; + pixel_y = -13 + }, +/turf/space, +/area/space) +"WL" = ( +/obj/machinery/smartfridge/drying_oven, +/turf/floor/plating, +/area/ministation/maint/hydromaint) +"WN" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/carpet/red, +/area/ministation/security) +"WO" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/floordetail/edgedrain{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hydro) +"WQ" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"WW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"WX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/shutters/open{ + id_tag = "SURG1"; + name = "Surgery Shutters" + }, +/turf/floor/plating, +/area/ministation/medical) +"WY" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/tiled, +/area/ministation/security) +"WZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"Xi" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = -14 + }, +/turf/floor/reinforced/airless, +/area/space) +"Xl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Xm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"Xp" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/turretid/stun{ + dir = 8; + pixel_x = 26; + initial_access = null; + req_access = list("ACCESS_HEAD_OF_SECURITY"); + id_tag = "goodstuff" + }, +/turf/floor/tiled/dark, +/area/ministation/security) +"Xq" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 10 + }, +/obj/structure/sign/department/chemistry{ + pixel_x = 32; + pixel_y = -5; + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/hall/e2) +"Xr" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/sign/warning/armory{ + pixel_x = -32; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/security) +"Xs" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/security) +"Xv" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/closet/secure_closet/hos, +/obj/item/clothing/suit/jacket/winter, +/obj/item/flashlight/maglight, +/obj/item/chems/spray/pepper, +/obj/item/stamp/hos, +/turf/floor/carpet/blue2, +/area/ministation/security) +"Xw" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"XA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/ministation/medical) +"XE" = ( +/obj/machinery/light, +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/structure/closet/secure_closet{ + req_access = list("ACCESS_FORENSICS"); + name = "evidence locker"; + closet_appearance = /decl/closet_appearance/secure_closet/security + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/detective) +"XK" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/ss13/l14, +/turf/floor/tiled, +/area/ministation/hall/w2) +"XW" = ( +/obj/structure/table/laminate, +/obj/item/box/ammo/beanbags, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/item/flashlight/lamp/green, +/turf/floor/carpet, +/area/ministation/cafe) +"XY" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/blast/shutters{ + name = "security shutter"; + id_tag = "secshut" + }, +/turf/floor/plating, +/area/ministation/security) +"Yj" = ( +/obj/structure/chair/office/light, +/obj/abstract/landmark/start{ + name = "Security Officer" + }, +/turf/floor/tiled, +/area/ministation/security) +"Yk" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/bed/sofa/left/black, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Ym" = ( +/obj/structure/window/reinforced/tinted{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/detective) +"Yn" = ( +/obj/machinery/door/airlock{ + name = "Cryo A" + }, +/turf/floor/plating, +/area/ministation/arrival) +"Yv" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/sign/directions/medical{ + dir = 4; + pixel_x = 32; + pixel_y = 25 + }, +/obj/structure/sign/directions/security{ + dir = 4; + pixel_x = 32; + pixel_y = 32 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/e2) +"Yw" = ( +/obj/effect/shuttle_landmark/arrivas_south{ + landmark_tag = "nav_ministation_medical_east" + }, +/turf/space, +/area/space) +"YF" = ( +/obj/structure/rack, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/southleft{ + req_access = list("ACCESS_ARMORY"); + autoset_access = 0 + }, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/turf/floor/tiled/dark, +/area/ministation/security) +"YH" = ( +/obj/random/maintenance, +/obj/structure/closet, +/obj/item/poster, +/turf/floor/plating, +/area/ministation/maint/secmaint) +"YS" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled, +/area/ministation/security) +"YT" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/table, +/obj/item/bonegel, +/obj/item/bonesetter, +/turf/floor/tiled/white, +/area/ministation/medical) +"YU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/glass/security{ + req_access = list("ACCESS_SECURITY"); + autoset_access = 0 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/security) +"YY" = ( +/obj/item/radio/intercom{ + name = "Common Channel"; + pixel_y = 20 + }, +/obj/item/mop, +/obj/structure/mopbucket, +/turf/floor/tiled/white, +/area/ministation/medical) +"Zb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/cafe) +"Zh" = ( +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/structure/bed/sofa/right/black, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Zm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hop) +"Zn" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/cafe) +"Zz" = ( +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/ministation/medical) +"ZE" = ( +/obj/structure/bed, +/obj/item/bedsheet/brown, +/obj/machinery/button/blast_door{ + id_tag = "Chef1"; + name = "Kitchen Shutter"; + pixel_y = -24; + dir = 1 + }, +/obj/random/plushie, +/turf/floor/carpet, +/area/ministation/cafe) +"ZK" = ( +/obj/machinery/computer/cryopod{ + pixel_y = 32 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ministation/cryo) +"ZR" = ( +/obj/machinery/vending/coffee{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/w2) +"ZS" = ( +/obj/structure/rack, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/classic_baton{ + pixel_w = -7 + }, +/obj/item/classic_baton{ + pixel_w = -7 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/grenade/light, +/obj/item/grenade/light, +/obj/item/grenade/light, +/obj/item/grenade/light, +/obj/item/grenade/light, +/obj/item/grenade/light, +/obj/machinery/button/blast_door{ + id_tag = "armoryshut"; + name = "security shutter button"; + pixel_y = 30 + }, +/obj/machinery/camera/motion, +/turf/floor/tiled/dark, +/area/ministation/security) +"ZT" = ( +/obj/structure/table, +/obj/item/firstaid/surgery, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/medical) +"ZX" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/lino, +/area/ministation/cafe) +"ZZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/medical) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +NO +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +af +aa +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +wj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +ab +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oN +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WF +kZ +ad +rt +PN +kZ +ad +ad +ad +rt +PN +kZ +PN +rt +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +ad +rt +PY +kZ +ad +ad +ad +rt +Nu +kZ +Bj +rt +aa +aa +aa +ad +aa +aa +aa +UV +aa +aa +mG +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +Ev +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +ad +rt +Qp +kZ +ad +ad +ad +rt +Qp +kZ +Qp +rt +aa +aa +aa +kZ +cr +cr +kZ +kZ +kZ +kZ +UZ +UZ +UZ +UZ +ed +Ob +Pf +TA +Rk +Rk +VL +UZ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +kZ +ad +rt +Qp +kZ +ad +ad +ad +rt +Qp +kZ +Qp +rt +aa +ad +aa +kZ +uB +aV +vO +CU +mO +Uz +IA +ed +Ob +Sx +ed +ed +Yn +ed +ed +ed +ds +UZ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +kZ +rt +OT +rt +kZ +cr +kZ +rt +OT +rt +OT +rt +aa +ad +kZ +kZ +uC +aV +vP +kZ +kZ +kZ +UZ +UZ +Pf +Pf +Pf +Ie +Pf +Ww +Ww +Ww +cq +UZ +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +lI +mh +Ry +Sd +nx +oH +rc +mh +Ry +Sd +rW +kZ +aa +ad +kZ +Qy +aV +GZ +GZ +aV +xf +rt +aa +SD +ed +ed +Pf +ed +Pf +Pf +Pf +Pf +Pf +UZ +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cr +aH +hi +mR +GZ +aV +aV +aV +aV +mR +rm +rX +kZ +kZ +kZ +kZ +aV +aV +aV +aV +aV +xf +rt +aa +SD +LN +UN +Pf +SK +Pf +ed +ed +ed +ed +UZ +xY +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cr +hm +fe +Bz +Ca +HJ +HJ +HJ +HJ +rE +rn +md +aV +aV +te +aV +aV +aV +aV +aV +aV +dE +rt +aa +SD +ed +ed +hj +ed +ih +ed +ed +iR +ed +UZ +xY +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +Bv +Sq +aV +in +GZ +aV +aV +GZ +aV +rn +in +aV +aV +tf +BH +aV +aV +aV +aV +aV +ZR +rt +aa +SD +ed +ed +Pf +ed +Pf +Pf +Pf +Pf +Pf +UZ +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +kC +bo +zy +Ov +NZ +nC +nC +nC +nC +rp +TD +ss +nC +tg +SF +nC +kX +vb +jZ +kZ +kZ +kZ +UZ +UZ +Pf +Pf +Pf +Ie +Pf +Rk +Rk +Rk +cq +UZ +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kZ +em +aV +md +md +Sq +Iz +yD +HJ +HJ +ey +fr +st +uD +th +ud +nD +uD +Lm +vP +CU +xK +Uz +IA +ed +iR +Sx +ed +ed +cU +ed +ed +ed +ds +UZ +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +mq +kZ +tM +kZ +tM +tM +xO +tM +tM +kZ +FZ +Pd +Ec +rn +aV +ti +Nq +aV +aV +aV +vP +kZ +kZ +kZ +UZ +UZ +UZ +UZ +ed +iR +Pf +cf +Ww +Ww +eo +UZ +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +cg +HO +HO +HO +mq +zM +nF +Gx +hO +NU +sg +Pk +mi +kZ +Ei +Bk +Ec +rn +aV +tj +tP +ua +aV +aV +Gh +kZ +aa +aa +Iw +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +UZ +Ev +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +IB +cN +er +Eg +UL +qg +JJ +Io +kZ +CV +Ec +Ec +SV +zf +yS +ln +hS +kI +uc +dQ +kZ +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +ad +aa +aa +ad +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +mq +mq +mq +mq +mq +mq +mq +mq +pw +uK +aG +mf +dd +ez +Td +dd +kZ +Wa +qF +dc +RQ +dm +bI +XK +RW +SX +uI +vS +uI +uI +uI +uI +uI +uI +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +dd +dd +dd +dd +pl +dd +ir +dd +PL +dd +kb +dd +mq +mq +mq +kZ +kZ +kZ +kZ +su +aV +Nz +ze +aR +on +uI +vT +eg +rD +xJ +yl +MA +uI +qf +qf +eF +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +Co +mq +mq +mq +mq +mq +mq +mq +Lt +dd +dd +dd +dd +dd +pl +dd +dd +dd +dd +kZ +tY +GZ +aV +aV +aR +on +ve +vU +Ez +iX +Np +gT +hu +Gz +Wd +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +mq +HO +HO +HO +HO +HO +mq +mq +mq +mq +mq +mq +mq +mq +mq +mq +mq +Co +kZ +sv +aV +aV +aV +lL +on +vf +vV +Zm +kB +xJ +cA +Ds +uI +Wd +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +mq +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +DI +aa +aa +mq +dd +kZ +Ak +hl +zG +hl +GR +Cb +fu +uG +MK +fd +uI +uI +uI +uI +Wd +qf +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +HO +HO +HO +aa +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +mq +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +mq +dd +kZ +Kr +wx +sp +WQ +ns +uI +uI +EM +fZ +wF +rU +uI +aU +Dn +Wd +qf +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +mq +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +mq +mq +mq +mq +dd +kZ +tW +Gg +sp +WQ +aR +uI +IP +HM +fZ +wF +yV +uI +cv +Wd +JX +qf +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +mq +HO +HO +HO +HO +HO +HO +aa +HO +HO +HO +HO +HO +mq +ER +or +at +BT +kZ +lH +tq +BW +bJ +aR +uI +Ir +ye +jF +Dw +uI +uI +xj +HR +qf +qf +qf +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +dd +mq +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +mq +mq +mq +mq +jy +kZ +Kr +tq +BW +WQ +aR +uI +SW +AB +Vr +MU +uI +Fn +xj +Wd +DJ +ph +qf +qf +qf +qf +qf +qf +qf +qf +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +mq +mq +Co +mq +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +mq +mq +zM +bw +Gx +qk +eb +mq +Kr +Ug +sp +WQ +sG +uI +uI +uI +uI +uI +uI +QE +xj +Oc +qf +qf +qf +Wd +Wd +Wd +Dn +Wd +Wd +wr +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +aa +HO +HO +HO +HO +HO +HO +HO +HO +mq +bs +dd +dd +mq +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +bG +at +cE +QK +Nm +iq +lN +lB +LI +hH +WW +bN +QN +Hn +An +cm +An +SB +An +An +zl +Wd +DJ +Wd +Dn +Wd +qf +qf +qf +qf +qf +qf +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +mq +mq +mq +mq +mq +cg +HO +HO +HO +HO +HO +HO +HO +HO +mq +mq +mq +np +mq +Co +dd +Jm +mq +PH +aV +Sq +aV +iN +kZ +Wd +qf +qf +qf +qf +Qs +DF +Wd +qf +qf +qf +qf +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +fx +PX +mq +mq +ir +mq +kZ +PI +aV +dm +GZ +jO +kZ +Wd +qf +qf +qf +qf +qf +qf +qf +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +qL +kZ +mc +qN +cH +kZ +ke +GZ +aV +aV +Sq +kZ +Wd +DJ +Dn +wr +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +mq +lo +kZ +NC +Sy +aV +kZ +As +Ea +Ea +Ea +ue +ex +BG +qf +qf +qf +qf +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +ps +NC +dK +Wo +kZ +PI +aV +aV +aV +Sq +kZ +vm +qf +qf +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +cg +aa +aa +aa +aa +aa +aa +HO +HO +bu +bu +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +kZ +MQ +ry +kZ +kZ +PI +aV +aV +GZ +Sq +kZ +vn +kd +qf +HO +HO +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +HO +HO +bu +LH +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +kZ +kZ +kZ +zA +kZ +kZ +sB +Mb +Mb +Mb +ug +kZ +tm +VN +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +Ck +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +rt +al +RZ +aV +oX +ty +OW +zv +TO +tt +Nh +kZ +gp +Wd +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +Ck +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cg +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +rt +pu +aV +aV +oX +ty +Xl +gz +gz +gz +ML +kZ +sI +FQ +qf +Ij +Ij +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +Ck +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +rt +pf +zZ +Ci +MG +VR +dN +gz +tv +gz +ML +DJ +Wd +xz +nK +Ix +rC +Vs +HO +HO +HO +HO +HO +cg +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +iK +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +rt +qe +Qj +lR +oX +ty +sC +gz +gz +gz +PR +mH +kr +Ib +qf +Ij +Ij +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +Ck +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +rt +qe +qe +rA +oX +ty +Yv +AX +NR +AX +ui +mH +Wd +qf +qf +HO +HO +Xi +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +Ck +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(129,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +rt +rt +rt +rt +rt +mH +sD +tx +tx +tx +sh +mH +Wd +qf +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +bu +Ck +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(130,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +cY +cY +cY +cY +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +mH +RB +ty +ty +ty +sM +mH +AR +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +bu +LH +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(131,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +bR +kh +GO +cY +cY +cY +cY +cY +cY +cY +aa +aa +aa +aa +ab +aa +la +RB +ty +ty +ty +sM +mH +VN +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +bu +bu +bu +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(132,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +lF +lF +lF +HO +HO +HO +HO +HO +HO +HO +HO +cY +bp +az +LK +ya +Uj +OK +un +Gb +kv +cY +aa +aa +aa +aa +aa +aa +la +RB +ty +wD +ty +sM +DJ +Wd +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(133,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +lF +yk +lF +HO +HO +HO +HO +HO +HO +HO +HO +cY +ht +by +xn +Ur +Ne +cY +BA +Of +Ig +cY +cY +cY +cY +cY +cY +aa +la +RB +ty +ty +ty +yN +mH +qf +qf +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(134,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +lF +lF +lF +HO +HO +HO +HO +HO +HO +HO +HO +cY +mo +Bs +QH +Ia +Ne +hZ +PV +Xv +cY +cY +cY +hI +Qg +mL +cY +cY +mH +TS +ty +mj +qI +Om +mH +aa +DI +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(135,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +HX +Bs +Ur +Lk +Ne +cY +cY +cY +cY +oW +LQ +dr +dr +dr +qX +fA +cY +RB +wD +ty +ty +sM +la +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(136,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +bW +mv +gB +Ur +Ne +hZ +Ow +CO +cY +cY +cY +pd +Wi +dr +dr +Yj +QL +RB +ty +ty +wD +sM +la +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(137,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +sO +by +zi +WN +Ne +hZ +Gp +Gi +xP +cY +cY +Ut +BZ +dr +iz +dr +VS +nB +ty +ty +ty +sM +la +fN +Zb +Zb +Zb +Zb +Zb +bj +bj +bj +bj +bj +bj +Kn +bj +bj +bj +lK +bj +bj +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(138,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +Ti +KG +fs +nu +eK +dW +Wr +EV +nS +cY +cY +hw +EE +hX +iy +jd +XY +tU +QF +QF +QF +uH +mH +Yk +Uw +Rd +BE +gL +wL +bj +Sw +Cw +fD +bj +Qa +XW +Ct +bj +Wt +LM +ZE +bj +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(139,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +cY +cY +cY +cY +cY +cY +hZ +YU +cY +cY +cY +cY +cY +cY +cY +hx +MH +hY +QR +je +cY +PO +wD +ty +OY +Jx +uM +aL +am +zn +BE +Hd +Wv +bj +bU +Cw +mw +bj +sw +kD +Jd +bj +sw +sl +Jd +bj +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(140,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +Ft +dr +Wi +kE +Me +cY +Fj +QR +DY +Lp +YS +Db +HW +KV +cY +da +da +hZ +TV +da +cY +JH +ty +ty +OY +Sp +uM +Zh +BE +BE +BE +Ue +ub +bj +Dk +Cw +Cw +bj +Af +bj +bj +bj +Af +bj +bj +bj +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(141,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +Ft +dr +hQ +oZ +Ou +vi +Gk +nb +NE +NE +ic +FL +NE +Op +Xr +ha +No +Vt +gX +jg +Oq +ly +Tv +Tv +Jz +mJ +bj +vF +wk +BE +wk +xZ +FJ +bj +Cw +et +wt +bj +Zn +bK +bK +Ps +sb +bj +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(142,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +Ft +dr +LY +TT +dr +KZ +fH +rY +mk +Xs +Xs +Vc +UY +Po +gC +hb +hz +ia +iA +jh +kG +aD +OZ +OZ +CW +Jx +bj +vG +BE +iH +iH +BE +Bw +bj +zC +bj +bj +bj +Af +bj +bj +pn +Es +bj +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(143,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +Ft +dr +eZ +PU +KH +gm +dr +QR +Vb +eB +dr +no +cY +Vd +gD +hc +cY +ew +iB +WY +cY +sU +Fy +tz +Dv +uu +bj +vt +xQ +wO +xo +xQ +yu +bj +zD +tS +At +Aw +Ag +vr +bj +bj +bj +bj +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(144,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +cY +cY +cY +cY +cY +cY +cY +oj +Vb +cY +eE +tQ +cY +Qm +dr +eZ +da +gb +dr +eZ +cY +sV +GE +tA +GE +uv +uL +vu +ND +wP +xp +ND +yv +Dl +zE +Ae +Br +Br +de +zF +zF +ZX +jP +ED +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(145,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +cY +JW +cL +TQ +Di +Vg +cY +LR +zq +cY +ef +fF +cY +Js +gE +hd +da +gc +iD +hd +cY +sW +uq +aC +dn +AG +uM +BE +BE +iH +xq +BE +yw +qB +zF +Rw +Bm +Bm +zF +zF +zF +zF +Hx +ED +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(146,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +cY +cY +hU +ho +cY +JO +bC +cY +LR +tV +cY +ef +ef +cY +cY +cY +cY +cY +cY +cY +cY +cY +jH +iY +kM +iY +OH +uN +To +wl +vw +wl +xR +yx +qB +zF +Ag +zF +zF +zF +zF +zF +zF +px +ED +HO +HO +HO +cg +HO +HO +HO +HO +HO +HO +HO +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(147,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +Jn +KS +ho +cY +Ny +Te +Cz +QR +tV +cY +qS +ef +bA +Am +oB +Am +Ip +Am +Am +Am +DG +zg +OZ +Ro +Dv +Nf +bj +vv +BE +BE +BE +xS +IX +qB +zF +Ag +zF +zF +zF +zF +zF +zF +Cp +bj +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(148,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +fn +lp +BU +cY +ZS +jv +cY +db +tV +cY +Rl +ig +zo +JZ +JZ +JZ +JZ +JZ +JZ +JZ +JZ +pE +OZ +Ro +DO +ge +bj +ku +wm +wm +wm +xT +yy +bj +zH +br +zF +Av +SJ +TX +Lr +Dj +Jj +bj +HO +HO +HO +HO +HO +HO +HO +jU +jU +jU +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(149,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +fW +KS +Fz +cY +Ok +ag +TQ +Wm +pA +cY +tQ +oc +zo +JZ +HF +mp +HP +DC +KK +Wl +JZ +sN +fm +Gy +jM +iv +bj +bj +wn +wQ +xs +xU +xW +bj +zI +Rw +Ay +bj +Sa +Sa +Sa +Sa +Sa +Sa +Sa +Sa +HO +HO +HO +HO +HO +jU +Wf +jU +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(150,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +WF +cY +YF +KS +DA +cY +cY +cY +cY +KI +mX +cY +tQ +od +pC +TB +BI +aW +cR +Jo +KW +gJ +zW +yC +iW +Sg +wE +Kv +bj +vy +wo +wR +wR +xV +yA +bj +zJ +Ai +QO +BJ +Ga +ib +mW +ib +Mp +ib +RK +Sa +HO +HO +HO +HO +HO +jU +jU +jU +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(151,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +cY +DH +pz +iU +fy +oG +oG +cY +jN +va +cY +tQ +oD +nX +JZ +bx +vq +hC +id +iG +jk +JZ +lw +ty +Xw +OY +Kz +bj +vz +wp +wp +wp +Ni +aB +zh +zK +Ah +HN +bj +rq +tX +Sa +Sa +Sa +Sa +Sa +Sa +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(152,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +cY +GN +Xp +fl +NM +zS +cY +kh +ob +cY +tQ +ef +ef +JZ +qa +to +Ym +Ym +Ym +XE +JZ +lw +ty +Xw +ty +Wj +bj +vA +jS +wS +xt +wq +yB +bj +zF +Aj +AA +bj +OF +tX +tX +tX +rG +tX +Fa +Sa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(153,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +cY +cY +uO +cY +cY +cY +uQ +cT +cY +Rx +oE +ef +JZ +ae +UB +ul +Sb +Kd +JZ +mH +sP +ty +Xw +ty +um +bj +bj +bj +bj +bj +bj +dZ +bj +zL +bj +bj +bj +dS +Ax +Tr +Tr +Tr +Wc +tT +Sa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(154,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +bO +Ik +ho +po +Ik +cY +aa +aa +aa +Rx +ef +ef +Rx +oz +oz +oz +oz +oz +oz +wc +sQ +qI +tD +aj +up +tL +dq +is +Au +lQ +qM +yM +KN +WO +ct +EL +eH +AK +NX +tX +WL +Sa +ls +Sa +Sa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(155,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +jl +KS +Tk +KS +jl +cY +aa +aa +aa +Rx +YH +Up +ef +wd +pD +RU +pD +FF +oz +UW +lw +ty +Xw +ty +um +jV +OV +if +qT +wN +qT +wN +xy +JQ +ws +cd +Sa +yn +WC +xe +ol +Sa +TM +Sa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(156,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +ax +jq +dC +Ke +mz +cY +aa +aa +aa +Rx +Rx +Rx +Rx +oz +pe +oF +jR +lJ +oz +BS +lw +ty +tE +ty +um +jV +Im +MW +Ru +uJ +Ru +Rp +Hq +hv +ws +iw +Sa +Sa +Sa +Sa +Sa +Sa +SC +Sa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(157,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +jl +KS +KS +KS +jl +cY +aa +aa +aa +aa +DI +aa +aa +vK +pe +pF +qn +qZ +oz +oz +LV +ty +Xw +ty +um +jV +vE +wu +wW +xx +wW +yE +rw +zO +Km +FI +zQ +mu +vX +Gr +zQ +hp +pr +Sa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(158,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cY +cY +dB +sK +JV +cY +cY +aa +aa +aa +aa +aa +aa +aa +vK +Fr +pF +qo +qY +rI +oz +uP +qI +tG +wD +um +jV +OV +Vu +oY +CL +VE +yF +ws +pb +Aq +VO +bX +KR +gw +Ji +ac +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(159,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +cY +cY +cY +cY +cY +DZ +ad +ad +ad +ad +ad +ad +ad +oz +oz +pG +qp +qY +pe +oz +fC +sS +tH +Hi +us +fY +oz +oz +oz +vp +oz +oz +yf +zP +iQ +zj +bX +vk +Fh +mu +ac +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(160,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +ad +ad +ad +ad +ad +ad +aa +aa +aa +aa +ad +aa +aa +aa +oz +pH +qq +ra +rJ +si +KX +kK +tI +tJ +ut +LT +kS +HL +UC +fw +mC +oz +bX +eh +xr +Ki +zQ +vk +gw +Ji +zQ +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(161,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +aa +oz +pI +qr +rb +rK +sj +WZ +Gd +Ls +Gd +Gd +Xq +oA +hh +pD +pD +Pw +VZ +vX +mu +fP +In +mu +OG +vX +Ji +zQ +ad +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(162,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +oz +oz +pJ +hr +qs +oz +oz +ov +Nj +iE +ON +Hy +oz +oz +wy +pD +pD +yb +VZ +In +kz +bL +Qk +IQ +Vq +gw +vX +ac +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(163,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +oz +MT +uW +qt +rd +rL +sk +bQ +so +hA +so +cQ +oz +vH +wz +qw +xA +yc +VZ +vX +Ji +Ji +mu +Uh +Ux +Qw +In +ac +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(164,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +oz +VJ +pL +Kt +re +rL +sk +js +pD +zd +Zz +Gu +oz +jT +pe +wY +xB +yY +oz +NA +Oe +Oo +Ji +zQ +ac +zQ +ac +zQ +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(165,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +oz +iJ +uW +qu +pD +rM +oz +CD +pU +tN +pU +pU +oz +oz +wA +Fo +xC +rQ +oz +RD +RD +RD +RD +RD +aa +ad +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(166,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aa +aa +oz +oz +pN +qv +rf +rN +Az +Jl +rf +Tj +rf +rf +uV +lg +rf +rN +xD +Cu +tZ +Wb +CP +Hz +gS +RD +aa +ad +aa +ab +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(167,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +oz +oz +oz +ri +pO +rg +rO +pK +rO +Be +LE +Pj +Uv +Uv +sq +jW +XA +bB +xE +PS +DD +Vk +AD +hs +qO +RD +aa +ad +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(168,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +oz +II +VY +lG +pD +aA +pD +rP +pD +gW +Vx +aA +pD +ux +tO +vJ +wC +wZ +pD +wB +AJ +Wb +ZK +EG +Mw +RD +ad +ad +ad +ad +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(169,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +nt +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +vK +rj +ek +QP +QP +IT +fL +pD +rP +Md +oz +UJ +aA +QC +oz +oz +oz +oz +xa +oz +Qh +vK +Wb +RD +RD +RH +RD +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(170,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +av +aA +pD +pD +qA +pD +pD +rP +yG +oz +sX +aA +pD +oz +uy +uZ +gU +xb +oz +yg +ii +zt +km +oz +oz +aa +aa +ad +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +nt +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(171,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +vK +MF +ky +pQ +qz +SG +pQ +pQ +CJ +dT +oz +sX +aA +pD +oz +uy +uZ +uX +xF +oz +Va +uW +qu +pD +OL +vK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(172,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +vK +ix +vK +vK +oz +Pc +vK +Bu +vK +oz +HG +aA +pD +oz +uy +uZ +Pz +vM +oz +xc +uW +Pe +pD +SA +vK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(173,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +sn +aA +so +VC +oz +aN +kV +Xm +Jc +oz +oz +vL +Cx +oz +uy +uZ +uZ +vN +oz +Ge +AQ +IO +hV +yJ +vK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(174,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +pP +Eb +GF +ta +oz +rS +rf +Su +sY +oz +ww +Mu +bv +oz +oz +pU +pU +oz +oz +YY +yP +xH +yK +wU +oz +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(175,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +kg +dw +rk +rR +oz +pM +pD +nf +eV +oz +xd +Qz +qy +oz +aa +aa +aa +aa +oz +io +xg +yh +Dh +GC +oz +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(176,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +pS +ZZ +pR +lh +oz +YT +pD +qA +ta +oz +Kk +bH +oS +Cx +aa +aa +aa +aa +vK +pZ +uW +ta +pD +QM +vK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(177,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +pT +kR +EO +dH +oz +rh +sm +pD +tb +oz +ar +Ts +oz +oz +aa +aa +aa +aa +vK +hD +qA +pD +pD +ZT +vK +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(178,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +WX +WX +WX +oz +oz +oz +Pb +Pb +Pb +oz +Cx +Cx +oz +aa +aa +aa +aa +aa +oz +oz +SZ +LW +EQ +oz +oz +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(179,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +aa +aa +aa +aa +oz +aa +aa +aa +aa +oz +aa +aa +aa +aa +aa +aa +aa +aa +aa +oz +vK +vK +Vi +oz +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(180,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(181,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(182,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(183,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(184,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(185,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(186,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(187,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(188,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(189,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(190,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(191,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Yw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(192,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(193,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(194,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(195,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(196,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(197,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +HO +HO +HO +HO +HO +HO +HO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(198,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(199,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(200,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(201,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(202,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(203,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(204,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(205,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(206,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(207,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(208,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(209,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(210,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(211,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(212,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(213,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(214,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(215,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(216,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(217,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(218,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(219,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(220,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(221,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(222,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(223,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(224,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(225,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(226,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(227,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(228,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(229,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(230,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(231,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(232,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(233,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(234,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(235,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(236,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(237,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(238,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(239,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(240,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(241,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(242,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(243,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(244,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(245,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(246,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(247,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(248,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(249,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(250,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(251,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(252,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(253,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(254,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(255,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/ministation/ministation-2.dmm b/maps/ministation/ministation-2.dmm new file mode 100644 index 000000000000..36d8182f59f5 --- /dev/null +++ b/maps/ministation/ministation-2.dmm @@ -0,0 +1,74130 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/obj/structure/sign/warning/bomb_range{ + dir = 4; + pixel_x = -32 + }, +/turf/space, +/area/space) +"ab" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/space, +/area/space) +"ad" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"ae" = ( +/turf/wall, +/area/ministation/science) +"af" = ( +/turf/wall/natural/random/ministation, +/area/space) +"ah" = ( +/turf/wall, +/area/ministation/bridge) +"am" = ( +/obj/structure/table/reinforced, +/obj/item/wrench, +/obj/item/assembly/timer, +/obj/item/assembly/signaler, +/obj/item/assembly/signaler, +/obj/item/multitool, +/turf/floor/tiled, +/area/ministation/bridge) +"ao" = ( +/obj/structure/table/reinforced, +/obj/machinery/faxmachine/mapped, +/turf/floor/tiled, +/area/ministation/bridge) +"ap" = ( +/turf/floor/plating, +/area/ministation/maint/l3se) +"aq" = ( +/obj/machinery/photocopier, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled, +/area/ministation/court) +"ar" = ( +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"as" = ( +/obj/machinery/computer/modular/preset/security, +/obj/effect/floor_decal/corner/red/full, +/turf/floor/tiled, +/area/ministation/bridge) +"av" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"aw" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor, +/area/ministation/science) +"ax" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/effect/floor_decal/corner/blue/full, +/turf/floor/tiled, +/area/ministation/bridge) +"ay" = ( +/obj/effect/floor_decal/corner/white/full, +/obj/machinery/computer/modular/preset/medical, +/turf/floor/tiled, +/area/ministation/bridge) +"az" = ( +/obj/effect/floor_decal/corner/yellow/full, +/obj/machinery/computer/ship/sensors{ + id_tag = "stationsensors" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"aA" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/floor/reinforced/airless, +/area/space) +"aB" = ( +/obj/structure/table/reinforced, +/obj/item/folder/envelope/nuke_instructions, +/obj/item/documents/tradehouse/account, +/obj/item/documents/tradehouse/personnel, +/turf/floor/tiled, +/area/ministation/bridge) +"aC" = ( +/obj/structure/table/reinforced, +/obj/item/radio, +/obj/item/radio/beacon, +/turf/floor/tiled, +/area/ministation/bridge) +"aD" = ( +/turf/wall/r_wall, +/area/ministation/bridge) +"aF" = ( +/obj/structure/glass_tank/aquarium, +/mob/living/simple_animal/aquatic/fish, +/mob/living/simple_animal/aquatic/fish, +/mob/living/simple_animal/aquatic/fish, +/mob/living/simple_animal/aquatic/fish, +/mob/living/simple_animal/aquatic/fish, +/mob/living/simple_animal/aquatic/fish/grump, +/turf/floor/tiled, +/area/ministation/bridge) +"aI" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger, +/turf/floor/tiled, +/area/ministation/bridge) +"aJ" = ( +/turf/floor/tiled, +/area/ministation/bridge) +"aK" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"aN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"aO" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"aP" = ( +/obj/structure/table/reinforced, +/obj/item/firstaid/regular, +/obj/item/toolbox/emergency, +/turf/floor/tiled, +/area/ministation/bridge) +"aQ" = ( +/obj/structure/displaycase, +/obj/item/sword/replica/officersword, +/obj/machinery/status_display{ + pixel_y = 30 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"aR" = ( +/obj/structure/bed, +/obj/item/bedsheet/captain, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/curtain/open/bed, +/obj/random/plushie, +/turf/floor/carpet/red, +/area/ministation/bridge) +"aT" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/laminate/walnut, +/area/ministation/bridge) +"aU" = ( +/obj/machinery/atmospherics/portables_connector, +/turf/floor/reinforced, +/area/ministation/science) +"aV" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"aW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/button/alternate/door/bolts{ + id_tag = "vaultbolt"; + name = "Vault Deadbolt Button"; + pixel_y = 27 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/laminate/walnut, +/area/ministation/bridge) +"aX" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/command{ + autoset_access = 0; + req_access = list("ACCESS_CAPTAIN"); + name = "Captain's Dormitory" + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet, +/area/ministation/bridge) +"aY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"aZ" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/camera/network/research, +/turf/floor/tiled/white, +/area/ministation/science) +"ba" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bb" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/pen, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/item/megaphone, +/turf/floor/tiled, +/area/ministation/bridge) +"bc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/table/reinforced, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"be" = ( +/obj/structure/table/reinforced, +/obj/item/folder/yellow, +/turf/floor/tiled, +/area/ministation/bridge) +"bf" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled, +/area/ministation/bridge) +"bg" = ( +/turf/wall/r_wall, +/area/ministation/bridge/vault) +"bi" = ( +/obj/structure/filing_cabinet, +/obj/machinery/light_switch{ + pixel_y = 28 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge/vault) +"bl" = ( +/turf/wall/r_wall, +/area/ministation/telecomms) +"bn" = ( +/obj/machinery/apc{ + dir = 1; + name = "Vault APC"; + pixel_y = 25 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/bluegrid, +/area/ministation/bridge/vault) +"bo" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/closet/l3closet/scientist, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"bp" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/bluegrid, +/area/ministation/bridge/vault) +"bq" = ( +/turf/floor/bluegrid, +/area/ministation/bridge/vault) +"br" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/turf/floor/carpet/red, +/area/ministation/bridge) +"bs" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/abstract/landmark/start{ + name = "Captain" + }, +/turf/floor/laminate/walnut, +/area/ministation/bridge) +"bt" = ( +/obj/item/flashlight/lamp/green, +/obj/structure/table/laminate/mahogany, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/item/gun/launcher/bow/crossbow/powered, +/obj/item/stack/material/bow_ammo/rod, +/obj/item/stack/material/bow_ammo/rod, +/obj/item/cell/crap, +/obj/item/mollusc/clam, +/turf/floor/laminate/walnut, +/area/ministation/bridge) +"bu" = ( +/obj/machinery/shipsensors{ + id_tag = "stationsensors" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/terminal{ + icon_state = "term-omni" + }, +/turf/floor/plating/airless, +/area/ministation/maint/l3sw) +"bv" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/bridge) +"bw" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bx" = ( +/obj/structure/table/reinforced, +/obj/item/secure_storage/briefcase, +/obj/item/flash, +/obj/item/flash, +/turf/floor/tiled, +/area/ministation/bridge) +"by" = ( +/obj/structure/closet, +/obj/item/stack/material/ingot/mapped/gold, +/obj/item/stack/material/ingot/mapped/gold, +/obj/item/stack/material/ingot/mapped/gold, +/obj/item/belt/champion, +/turf/floor/tiled, +/area/ministation/bridge/vault) +"bz" = ( +/obj/abstract/landmark/start{ + name = "Captain" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/chair/comfy/captain, +/turf/floor/tiled, +/area/ministation/bridge) +"bA" = ( +/obj/structure/table/reinforced, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/button/blast_door{ + id_tag = "bridgeblast"; + directional_offset = null + }, +/obj/machinery/button/blast_door{ + id_tag = "sensor"; + name = "Sensor Shroud"; + pixel_y = 9; + directional_offset = null + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bD" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/vault/bolted{ + autoset_access = 0; + id_tag = "vaultbolt"; + req_access = list("ACCESS_VAULT") + }, +/turf/floor/tiled, +/area/ministation/bridge/vault) +"bE" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge/vault) +"bF" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/bluegrid, +/area/ministation/bridge/vault) +"bG" = ( +/obj/structure/closet/secure_closet/captains, +/obj/item/clothing/shoes/sandal, +/obj/item/belt/holster, +/obj/item/clothing/suit/jacket/winter/captain, +/obj/item/stamp/captain, +/turf/floor/carpet/red, +/area/ministation/bridge) +"bH" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/chair/comfy/captain{ + dir = 4 + }, +/obj/machinery/camera/network/command{ + dir = 1; + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/laminate/walnut, +/area/ministation/bridge) +"bI" = ( +/obj/structure/table/laminate/mahogany, +/obj/item/modular_computer/tablet/lease/preset/command, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/laminate/walnut, +/area/ministation/bridge) +"bK" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/hologram/holopad/longrange, +/turf/floor/tiled, +/area/ministation/bridge) +"bO" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bR" = ( +/obj/machinery/nuclearbomb/station{ + pixel_y = 2 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled/dark/monotile, +/area/ministation/bridge/vault) +"bT" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/closet/emcloset, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/ammo_magazine/rifle/practice, +/obj/item/ammo_magazine/rifle/practice, +/turf/floor/tiled, +/area/ministation/bridge/vault) +"bV" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/camera/network/command{ + dir = 1; + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bW" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/structure/sign/department/bridge{ + dir = 4; + pixel_x = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"bX" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = -30; + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"bZ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"ca" = ( +/obj/machinery/newscaster{ + pixel_y = -28; + dir = 1 + }, +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/bridge) +"cb" = ( +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 4 + }, +/obj/machinery/meter{ + pixel_x = -16 + }, +/turf/floor/reinforced, +/area/ministation/science) +"cg" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning/corner{ + icon_state = "warningcorner" + }, +/turf/open, +/area/ministation/hall/n3) +"ch" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"ci" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/glass/command, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/bridge) +"cn" = ( +/turf/floor/plating/airless, +/area/space) +"co" = ( +/turf/wall/r_wall, +/area/ministation/tradehouse_rep) +"cp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"cr" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"cs" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"ct" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/bridge) +"cu" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/ministation/bridge) +"cw" = ( +/turf/floor/reinforced/airless, +/area/space) +"cx" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/tiled/white, +/area/ministation/science) +"cD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"cE" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/sign/warning/high_voltage{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"cF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/bridge) +"cI" = ( +/obj/structure/closet/secure_closet{ + closet_appearance = /decl/closet_appearance/secure_closet/rd; + req_access = list("ACCESS_RESEARCH"); + name = "Science locker" + }, +/obj/item/med_pouch/trauma, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/shield/crafted/buckler, +/obj/item/gps/explorer, +/obj/item/belt/holster/machete, +/obj/item/tool/machete/deluxe, +/obj/item/bladed/polearm/spear/improvised/steel, +/turf/floor/tiled/white, +/area/ministation/science) +"cJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"cL" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/science) +"cN" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/wall, +/area/ministation/science) +"cP" = ( +/obj/machinery/network/acl{ + initial_network_id = "molluscnet" + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"cQ" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/research{ + name = "Toxins Launch Room" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/science) +"cU" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable, +/turf/floor/tiled, +/area/ministation/bridge) +"cV" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"cW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"cX" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/random_multi/single_item/captains_spare_id, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"cZ" = ( +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"da" = ( +/obj/structure/window/basic/full, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/library) +"db" = ( +/turf/floor/tiled/white, +/area/ministation/science) +"dc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"dd" = ( +/turf/floor, +/area/ministation/science) +"de" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"di" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"dn" = ( +/obj/structure/table/laminate/reinforced/walnut, +/obj/item/paper_bin, +/obj/item/pen/retractable, +/turf/floor/carpet/red, +/area/ministation/court) +"dq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/court) +"dr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/airlock/glass/command{ + name = "Bridge" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/bridge) +"dt" = ( +/obj/machinery/button/blast_door{ + id_tag = "mech"; + name = "Mech Bay Door Control"; + pixel_x = -24; + pixel_y = 2; + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"du" = ( +/mob/living/slime, +/turf/floor, +/area/ministation/science) +"dv" = ( +/obj/machinery/cryopod/robot, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"dw" = ( +/obj/structure/table, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"dx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"dy" = ( +/obj/machinery/door/window/westleft, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/science) +"dz" = ( +/turf/wall/r_wall, +/area/ministation/science) +"dA" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor, +/area/ministation/science) +"dE" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"dF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"dM" = ( +/obj/machinery/atmospherics/omni/mixer{ + tag_north = 1; + tag_south = 2; + tag_west = 1 + }, +/turf/floor/reinforced, +/area/ministation/science) +"dQ" = ( +/obj/structure/table, +/obj/item/hand_labeler, +/obj/item/pen, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"dS" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/effect/decal/cleanable/filth, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"dT" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/random/trash, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"dX" = ( +/obj/machinery/papershredder, +/turf/floor/tiled, +/area/ministation/court) +"dY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/court) +"dZ" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"eb" = ( +/obj/machinery/mech_recharger, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"ec" = ( +/obj/machinery/door/airlock/science, +/obj/machinery/door/firedoor, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"ee" = ( +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/obj/structure/reagent_dispensers/acid{ + pixel_y = 29 + }, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"ef" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/science) +"eg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"eh" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/structure/disposaloutlet{ + dir = 1 + }, +/turf/floor, +/area/ministation/science) +"ei" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"ek" = ( +/obj/structure/lattice, +/turf/wall, +/area/space) +"em" = ( +/obj/structure/table, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/sign/warning/nosmoking_2{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"eq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"es" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/n3) +"et" = ( +/obj/structure/closet/wardrobe/lawyer_black, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/court) +"ex" = ( +/obj/machinery/button/mass_driver{ + id_tag = "toxinsdriver"; + pixel_y = 24 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"ey" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/reinforced, +/area/ministation/science) +"ez" = ( +/obj/machinery/mass_driver{ + dir = 4; + id_tag = "toxinsdriver" + }, +/turf/floor/plating/airless, +/area/ministation/science) +"eA" = ( +/obj/machinery/computer/shuttle_control/explore/ministation{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"eB" = ( +/obj/structure/table, +/obj/machinery/faxmachine/mapped, +/turf/floor/tiled, +/area/ministation/court) +"eC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/reinforced, +/area/ministation/science) +"eD" = ( +/obj/machinery/recharge_station, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"eF" = ( +/obj/structure/fireaxecabinet{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"eH" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "science_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "ministation_science_dock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = -10; + command = "cycle_exterior"; + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating/airless, +/area/ministation/science) +"eM" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"eO" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"eP" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"eV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"eW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = 32 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"eX" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/court) +"eY" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/court) +"eZ" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s3) +"fb" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"fc" = ( +/obj/structure/closet/secure_closet/scientist, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter/science, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"fd" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/optable, +/turf/floor/tiled/white, +/area/ministation/science) +"fe" = ( +/obj/machinery/computer/operating, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ff" = ( +/obj/structure/table, +/obj/item/scalpel{ + pixel_y = 15 + }, +/obj/item/circular_saw, +/obj/machinery/camera/network/research, +/turf/floor/tiled/white, +/area/ministation/science) +"fg" = ( +/obj/structure/table, +/obj/machinery/reagentgrinder, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"fh" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"fi" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"fk" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"fl" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"fz" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"fA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark{ + name = "lightsout" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"fF" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating/airless, +/area/space) +"fJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s3) +"fK" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"fN" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"fS" = ( +/obj/structure/sign/warning/hot_exhaust{ + pixel_y = 32 + }, +/turf/floor/reinforced/airless, +/area/space) +"fU" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"fV" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/effect/floor_decal/corner/black/border{ + dir = 4; + pixel_x = 1 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"fW" = ( +/obj/machinery/light, +/turf/floor/reinforced/airless, +/area/space) +"fZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"gd" = ( +/obj/machinery/destructive_analyzer{ + initial_network_id = "molluscnet" + }, +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"ge" = ( +/obj/machinery/computer/shuttle_control/explore/ministation{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"gf" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/ministation/science) +"gg" = ( +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/obj/item/stool/padded, +/turf/floor/tiled/white, +/area/ministation/science) +"gh" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled/white, +/area/ministation/science) +"gi" = ( +/obj/machinery/smartfridge/secure/extract, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"gk" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/effect/wingrille_spawn/reinforced_borosilicate/full, +/turf/floor/reinforced, +/area/ministation/science) +"gn" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"gp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"gx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"gy" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"gF" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = -14 + }, +/turf/floor/reinforced/airless, +/area/space) +"gG" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"gH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"gI" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"gJ" = ( +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/table, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"gK" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/floor/tiled/white, +/area/ministation/science) +"gN" = ( +/obj/structure/chair/shuttle/blue{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"gQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"gR" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"gS" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"gT" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"gU" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "pqm_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "pqm_airlock"; + name = "interior access button"; + pixel_x = 10; + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"gV" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/bookcase/skill_books/random, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"hd" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/reinforced/airless, +/area/space) +"he" = ( +/obj/structure/closet, +/obj/random/maintenance, +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"hf" = ( +/obj/machinery/fabricator/protolathe{ + initial_network_id = "molluscnet" + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"hg" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"hh" = ( +/obj/machinery/fabricator/bioprinter{ + initial_network_id = "molluscnet" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"hi" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"hj" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"hl" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/ministation/shuttle/outgoing) +"hm" = ( +/obj/machinery/atmospherics/unary/vent_pump/siphon/on, +/turf/floor/bluegrid/mainframe, +/area/ministation/science) +"hn" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/design_database{ + initial_network_id = "molluscnet" + }, +/turf/floor/tiled/dark, +/area/ministation/science) +"hv" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/library) +"hx" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/n3) +"hy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/wall/titanium, +/area/ministation/shuttle/outgoing) +"hF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/table, +/obj/item/box/syringes, +/obj/item/chems/glass/beaker/large, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"hG" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"hH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"hI" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table, +/obj/item/disk/tech_disk, +/obj/item/disk/tech_disk, +/obj/item/disk/design_disk, +/obj/item/stack/material/ingot/mapped/osmium/twentyfive, +/turf/floor/tiled/white, +/area/ministation/science) +"hJ" = ( +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"hK" = ( +/obj/structure/table, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/manipulator, +/obj/item/stock_parts/capacitor, +/obj/item/stock_parts/capacitor, +/obj/item/stock_parts/manipulator, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/obj/item/transfer_valve, +/turf/floor/tiled/white, +/area/ministation/science) +"hL" = ( +/obj/structure/table, +/obj/item/stack/cable_coil{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/stack/cable_coil, +/obj/item/stock_parts/scanning_module, +/obj/item/stock_parts/scanning_module{ + pixel_x = 2; + pixel_y = 3 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"hM" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/bluegrid/mainframe, +/area/ministation/science) +"hN" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/science) +"hO" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ministation/science) +"hS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"hV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"hY" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/turf/open, +/area/ministation/maint/l3nw) +"if" = ( +/obj/machinery/door/window/eastright, +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/blast/shutters{ + name = "science shutters"; + id_tag = "scishut" + }, +/turf/floor/plating, +/area/ministation/science) +"ig" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ih" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ii" = ( +/obj/machinery/door/airlock/glass/science, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/ministation/science) +"ik" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/hologram/holopad, +/turf/floor/tiled/white, +/area/ministation/science) +"im" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"in" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/machinery/recharger, +/obj/structure/table, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"io" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/science) +"ip" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 9 + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/science) +"iq" = ( +/obj/effect/decal/cleanable/filth, +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/court) +"it" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"iu" = ( +/obj/machinery/vending/cola{ + dir = 4; + pixel_x = -5 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"iy" = ( +/obj/machinery/portable_atmospherics/canister/hydrogen, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/reinforced, +/area/ministation/science) +"iC" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + name = "fuel pump" + }, +/obj/structure/handrail{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"iG" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"iI" = ( +/obj/machinery/fabricator{ + initial_network_id = "molluscnet" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"iJ" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"iK" = ( +/obj/machinery/fabricator/imprinter{ + initial_network_id = "molluscnet" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"iL" = ( +/turf/floor/tiled/techfloor, +/area/ministation/science) +"iM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/hologram/holopad/longrange, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"iN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/industrial/loading{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"iO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"iP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/glass/science{ + name = "Xenobiology" + }, +/obj/machinery/door/firedoor, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"iQ" = ( +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/obj/structure/chair/office/light, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"iR" = ( +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"iS" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/science, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/tiled/dark, +/area/ministation/science) +"iT" = ( +/obj/machinery/atmospherics/pipe/manifold/visible, +/turf/floor/tiled/white, +/area/ministation/science) +"iZ" = ( +/obj/machinery/vending/coffee{ + dir = 4; + pixel_x = -5 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"jd" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/ministation/science) +"jm" = ( +/obj/machinery/door/blast/regular{ + id_tag = "sensor" + }, +/turf/floor/plating/airless, +/area/ministation/maint/l3sw) +"jn" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table, +/obj/item/wrench, +/obj/item/crowbar/red, +/turf/floor/tiled/white, +/area/ministation/science) +"jo" = ( +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/table, +/obj/item/clothing/glasses/science, +/obj/item/clothing/mask/gas/budget, +/turf/floor/tiled/white, +/area/ministation/science) +"jp" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"jq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple, +/obj/structure/disposalpipe/junction/mirrored{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"js" = ( +/obj/structure/table, +/obj/item/chems/glass/beaker/large, +/obj/item/chems/glass/beaker/sulfuric, +/obj/item/chems/dropper, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jt" = ( +/obj/structure/table, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/matter_bin, +/obj/item/stock_parts/matter_bin, +/turf/floor/tiled/white, +/area/ministation/science) +"ju" = ( +/obj/structure/table, +/obj/item/clothing/glasses/welding, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/machinery/camera/network/research{ + dir = 1; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jv" = ( +/obj/structure/table, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/item/toolbox/mechanical{ + pixel_x = 2; + pixel_y = 3 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jw" = ( +/obj/abstract/landmark{ + name = "blobstart" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jx" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jy" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"jL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"jM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/obj/structure/sign/department/eva{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"jN" = ( +/obj/effect/shuttle_landmark/bridge_north, +/turf/space, +/area/space) +"jO" = ( +/obj/structure/closet/secure_closet{ + closet_appearance = /decl/closet_appearance/secure_closet/rd; + req_access = list("ACCESS_RESEARCH"); + name = "Science locker" + }, +/obj/item/med_pouch/trauma, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/shield/crafted/buckler, +/obj/item/gps/explorer, +/obj/item/flashlight/lantern, +/obj/item/bladed/polearm/spear/improvised/steel, +/turf/floor/tiled/white, +/area/ministation/science) +"jP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/science{ + name = "Research and Development/Robotics"; + req_access = list("ACCESS_XENOBIO"); + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"jR" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kc" = ( +/obj/structure/table/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kg" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/s3) +"kh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"ki" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"kk" = ( +/turf/floor/laminate/walnut, +/area/ministation/library) +"kn" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ko" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kp" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"kr" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/science) +"ks" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"ku" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kv" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kx" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ky" = ( +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kz" = ( +/mob/living/simple_animal/passive/cat/fluff/ran, +/turf/floor/tiled/white, +/area/ministation/science) +"kG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/machinery/computer/design_console{ + dir = 4 + }, +/turf/floor/carpet/magenta, +/area/ministation/science) +"kP" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/airlock/glass/science{ + autoset_access = 0; + req_access = list("ACCESS_ROBOTICS") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/science) +"kQ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kR" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kT" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/science) +"kU" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kV" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"kW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters/open{ + name = "RD Shutter"; + id_tag = "RD1" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/science) +"lb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"lh" = ( +/obj/structure/closet, +/obj/item/clothing/pants/slacks/red, +/obj/item/clothing/shirt/button, +/obj/item/clothing/neck/tie/navy, +/obj/item/clothing/suit/jacket/charcoal, +/obj/item/clothing/shoes/sandal, +/obj/item/multitool, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"ll" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"lp" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"ls" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"lv" = ( +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lw" = ( +/obj/structure/closet/firecloset, +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled/white, +/area/ministation/science) +"lx" = ( +/obj/structure/closet/firecloset, +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lz" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/science) +"lA" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lB" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"lC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/obj/structure/sign/department/xenoflora{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lF" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/science) +"lG" = ( +/obj/machinery/door/blast/shutters{ + dir = 4; + id_tag = "mech"; + name = "Mech Bay" + }, +/turf/floor/tiled, +/area/ministation/science) +"lH" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"mf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/glass/science{ + name = "Xenobotony" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"mk" = ( +/obj/effect/floor_decal/corner/red{ + dir = 5 + }, +/obj/structure/chair/padded/blue{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"ml" = ( +/obj/machinery/mass_driver{ + id_tag = "artifactlauncher"; + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"mm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/chair/shuttle/blue{ + dir = 1 + }, +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"mn" = ( +/obj/structure/table/reinforced, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/window/reinforced, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/button/blast_door{ + id_tag = "slimeblast2"; + name = "Enclosure 2 Blastdoors Button" + }, +/obj/machinery/camera/network/research, +/turf/floor/tiled, +/area/ministation/science) +"mr" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"ms" = ( +/obj/machinery/atmospherics/unary/tank/air{ + start_pressure = 6000 + }, +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"mw" = ( +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"mA" = ( +/obj/machinery/seed_extractor, +/turf/floor/tiled/white, +/area/ministation/science) +"mB" = ( +/obj/machinery/botany/editor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"mC" = ( +/obj/machinery/botany/extractor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"mD" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/biogenerator, +/obj/effect/floor_decal/corner/purple{ + dir = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"mE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"mF" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/vending/hydronutrients, +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"mG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/vending/hydroseeds, +/turf/floor/tiled/white, +/area/ministation/science) +"mH" = ( +/obj/machinery/atmospherics/portables_connector, +/turf/floor/tiled/white, +/area/ministation/science) +"mJ" = ( +/turf/floor/reinforced, +/area/ministation/science) +"mK" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/fake_grass, +/area/ministation/science) +"mN" = ( +/obj/machinery/door/airlock/glass/science{ + name = "Research Director"; + autoset_access = 0; + req_access = list("ACCESS_RESEARCH_DIRECTOR") + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"mU" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/chair/shuttle/blue{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"mV" = ( +/obj/structure/table, +/obj/machinery/doppler_array, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"mW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"mX" = ( +/obj/machinery/camera/autoname{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"mY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"mZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/reinforced, +/area/ministation/science) +"nj" = ( +/obj/machinery/camera/network/command{ + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/bluegrid, +/area/ministation/bridge/vault) +"nl" = ( +/turf/wall, +/area/ministation/maint/l3ne) +"nr" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/structure/table, +/obj/item/box/syringes, +/obj/item/box/botanydisk, +/obj/item/chems/glass/beaker/large, +/obj/item/scanner/plant, +/obj/item/scanner/gas, +/obj/item/tool/axe/hatchet, +/obj/item/tool/hoe/mini, +/obj/item/wrench, +/obj/item/wirecutters/clippers, +/obj/effect/floor_decal/industrial/fire/fulltile, +/turf/floor/tiled/white, +/area/ministation/science) +"ns" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"nt" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"nu" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"nv" = ( +/obj/machinery/door/window/westleft, +/obj/machinery/door/window/eastleft, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"nw" = ( +/obj/machinery/atmospherics/unary/vent_pump{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"nz" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/disposalpipe/junction/mirrored{ + dir = 2 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"nA" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"nG" = ( +/turf/wall/titanium, +/area/ministation/shuttle/outgoing) +"nI" = ( +/obj/machinery/apc{ + dir = 4; + name = "_East APC"; + pixel_x = 27; + pixel_y = 2 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/alarm{ + pixel_y = -24; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/hall/s3) +"nL" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"nN" = ( +/obj/structure/ladder, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"nP" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3central) +"nQ" = ( +/obj/structure/lattice, +/turf/wall, +/area/ministation/maint/l3ne) +"nS" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"nW" = ( +/obj/structure/filing_cabinet, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled, +/area/ministation/court) +"nX" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/floor/tiled, +/area/ministation/court) +"nZ" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"ob" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"oc" = ( +/turf/wall, +/area/ministation/maint/l3se) +"od" = ( +/obj/machinery/computer/air_control{ + dir = 8; + id_tag = "xenobot"; + name = "Xenoflora Gas Monitor" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"oe" = ( +/obj/machinery/air_sensor{ + id_tag = "xenobot"; + name = "Xenoflora Gas Sensor" + }, +/turf/floor/reinforced, +/area/ministation/science) +"of" = ( +/obj/machinery/commsrelay, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"og" = ( +/obj/machinery/door/airlock/glass/command{ + autoset_access = 0; + name = "Telecommunications glass airlock"; + req_access = list("ACCESS_TELECOMS") + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/holofloor/lino, +/area/ministation/telecomms) +"op" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"ot" = ( +/obj/structure/tank_rack/oxygen, +/turf/floor/tiled/white, +/area/ministation/science) +"oB" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/obj/effect/floor_decal/corner/green/full, +/turf/floor/tiled/white, +/area/ministation/science) +"oC" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/item/chems/glass/bucket, +/turf/floor/tiled/white, +/area/ministation/science) +"oD" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor, +/area/ministation/science) +"oE" = ( +/obj/machinery/light, +/turf/floor/reinforced, +/area/ministation/science) +"oF" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/telecomms) +"oG" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/closet/crate, +/obj/item/stock_parts/circuitboard/telecomms_hub, +/obj/item/cell, +/turf/floor/lino, +/area/ministation/telecomms) +"oH" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"oN" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/s3) +"oP" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"oQ" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"oR" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"oS" = ( +/obj/effect/floor_decal/corner/yellow/full, +/obj/machinery/computer/modular/preset/engineering, +/turf/floor/tiled, +/area/ministation/bridge) +"pa" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -13; + pixel_y = -14 + }, +/turf/space, +/area/space) +"pb" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/turf/open, +/area/ministation/maint/l3sw) +"pf" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"pi" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"pm" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast3"; + name = "enclosure 3 blast door" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"pp" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"pr" = ( +/obj/structure/disposalpipe/trunk, +/obj/structure/disposaloutlet{ + dir = 8 + }, +/turf/floor, +/area/ministation/science) +"ps" = ( +/obj/structure/table/laminate/ebony, +/obj/item/paper_bundle, +/obj/effect/floor_decal/stoneborder{ + dir = 6 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"pz" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/plating, +/area/ministation/hall/n3) +"pF" = ( +/obj/machinery/portable_atmospherics/canister/oxygen/prechilled, +/turf/floor/reinforced, +/area/ministation/science) +"pM" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/structure/chair/padded/blue{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"pP" = ( +/obj/effect/floor_decal/techfloor/orange, +/turf/floor/tiled, +/area/ministation/hall/n3) +"pS" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 5 + }, +/obj/machinery/camera/network/research{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"qi" = ( +/obj/structure/ladder, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"qj" = ( +/obj/structure/target_stake/steel, +/obj/item/toy/figure/clown, +/turf/floor/reinforced/airless, +/area/space) +"qn" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/space, +/area/ministation/science) +"qx" = ( +/obj/machinery/keycard_auth{ + pixel_x = -24; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"qJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/reinforced, +/area/ministation/science) +"qY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"rf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"rh" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"rk" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"rl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/light, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"rp" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -11 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"rx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"rB" = ( +/obj/machinery/computer/ship/helm{ + dir = 8 + }, +/obj/effect/overmap/visitable/ship/landable/science_shuttle, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"rC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/reinforced, +/area/ministation/science) +"rE" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"rI" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/l3se) +"rK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"rQ" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/ministation/science) +"rV" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/button/blast_door{ + id_tag = "RD1"; + name = "RD Shutter Button"; + pixel_x = 24; + pixel_y = -6; + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"rW" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"rZ" = ( +/obj/structure/lattice, +/obj/structure/sign/warning/bomb_range{ + dir = 8; + pixel_x = 32 + }, +/turf/space, +/area/space) +"sh" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"sl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/airlock/glass{ + name = "Library" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/library) +"sp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"sq" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"sr" = ( +/turf/floor/tiled/dark/monotile/telecomms, +/area/ministation/telecomms) +"ss" = ( +/obj/machinery/door/airlock/glass/command{ + name = "Bridge" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"st" = ( +/obj/effect/floor_decal/carpet/green{ + dir = 8 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 8 + }, +/obj/machinery/camera/autoname{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"sB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"sC" = ( +/turf/floor/tiled, +/area/ministation/hall/n3) +"sD" = ( +/turf/wall, +/area/ministation/hall/n3) +"sE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"sL" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 9 + }, +/turf/floor/reinforced, +/area/ministation/science) +"sM" = ( +/obj/structure/closet, +/obj/item/briefcase, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/machinery/camera/network/command{ + dir = 8; + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/button/blast_door{ + id_tag = "repblast"; + name = "Panic Lockdown"; + pixel_y = -32; + dir = 1 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"sQ" = ( +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/zpipe/up/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "16-0" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"sV" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/bed, +/obj/item/bedsheet/purple, +/obj/random/plushie, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"sW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"sY" = ( +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/flora/bush/fullgrass, +/turf/floor/grass, +/area/ministation/hall/n3) +"tc" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/dark/monotile/telecomms, +/area/ministation/telecomms) +"td" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/dark/monotile/telecomms, +/area/ministation/telecomms) +"te" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"tm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table, +/obj/item/chems/spray/extinguisher{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/item/chems/spray/extinguisher{ + pixel_x = 4; + pixel_y = 3 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ts" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"tt" = ( +/turf/floor/tiled, +/area/ministation/hall/s3) +"tu" = ( +/obj/structure/table, +/obj/item/integrated_circuit_printer, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"tv" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/open, +/area/ministation/hall/n3) +"tx" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/hall/n3) +"ty" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/turf/open, +/area/ministation/maint/l3se) +"tA" = ( +/obj/effect/floor_decal/corner/yellow/full, +/obj/machinery/computer/modular/preset/civilian, +/turf/floor/tiled, +/area/ministation/bridge) +"tB" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/structure/sign/department/science_2{ + pixel_x = 31; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s3) +"tC" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"tQ" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + name = "bridge blast door"; + id_tag = "bridgeblast" + }, +/turf/floor/plating, +/area/ministation/bridge) +"tT" = ( +/obj/machinery/atmospherics/unary/temperature/freezer{ + dir = 8; + set_temperature = 263 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"tU" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled/dark/monotile/telecomms, +/area/ministation/telecomms) +"tV" = ( +/obj/machinery/network/router{ + initial_network_id = "molluscnet" + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"tY" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"tZ" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/court) +"ug" = ( +/obj/structure/catwalk, +/turf/open, +/area/ministation/hall/n3) +"uh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s3) +"ui" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/s3) +"ur" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"uz" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/reinforced/airless, +/area/ministation/science) +"uA" = ( +/obj/machinery/network/mainframe{ + initial_network_id = "molluscnet" + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"uB" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/obj/effect/floor_decal/corner/b_green/three_quarters, +/turf/floor/tiled, +/area/ministation/hall/s3) +"uG" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/command{ + dir = 8; + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled, +/area/ministation/bridge) +"uH" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"uK" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/carpet/green/corners, +/obj/effect/floor_decal/stoneborder{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"uN" = ( +/obj/machinery/door/airlock/glass/science, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"uR" = ( +/obj/machinery/airlock_sensor{ + id_tag = "science_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + tag_airpump = "science_vent"; + tag_chamber_sensor = "science_sensor"; + tag_exterior_door = "science_airlock_exterior"; + tag_interior_door = "science_airlock_interior"; + id_tag = "ministation_science_dock"; + dir = 4; + pixel_y = -3; + pixel_x = -21 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/science) +"uS" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"uV" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/n3) +"uW" = ( +/obj/machinery/camera/network/research{ + name = "Bomb Range Internal" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/reinforced/airless, +/area/space) +"uX" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"uZ" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/floor/tiled, +/area/ministation/hall/n3) +"vc" = ( +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ve" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast1"; + name = "enclosure 1 blast door" + }, +/turf/floor, +/area/ministation/science) +"vj" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white, +/area/ministation/science) +"vl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "repblast"; + name = "rep blast door" + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"vm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"vo" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "anomvent"; + name = "Emergency Vent" + }, +/turf/floor/reinforced, +/area/ministation/science) +"vq" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"vs" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/bridge) +"vv" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/court) +"vz" = ( +/obj/machinery/camera/network/research, +/turf/floor/reinforced, +/area/ministation/science) +"vA" = ( +/turf/space, +/area/space) +"vF" = ( +/obj/machinery/button/blast_door{ + name = "Toxins Blast Door Control"; + pixel_y = 26; + id_tag = "toxingasroom"; + req_access = list("ACCESS_XENOBIO") + }, +/turf/floor/tiled/white, +/area/ministation/science) +"vJ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"vP" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"vT" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"wa" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/railing/mapped, +/turf/floor/tiled, +/area/ministation/hall/n3) +"wd" = ( +/obj/effect/floor_decal/corner/red/full, +/obj/machinery/computer/station_alert/all, +/turf/floor/tiled, +/area/ministation/bridge) +"we" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/hallway{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"wk" = ( +/obj/machinery/door/airlock/glass/science{ + name = "Toxins"; + req_access = list("ACCESS_XENOBIO"); + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"wl" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/turf/floor/reinforced, +/area/ministation/science) +"wo" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"wq" = ( +/obj/item/stool/padded, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"wH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"wJ" = ( +/obj/machinery/atmospherics/unary/vent_pump/siphon/on{ + external_pressure_bound = 98; + external_pressure_bound_default = 98 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor, +/area/ministation/science) +"wM" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/machinery/vending/cola{ + dir = 1 + }, +/turf/floor/lino, +/area/ministation/hall/s3) +"wY" = ( +/obj/structure/table/laminate/ebony, +/obj/item/pen/fancy, +/obj/item/box/fancy/crayons, +/obj/effect/floor_decal/stoneborder{ + dir = 6 + }, +/obj/item/box/candles, +/turf/floor/laminate/walnut, +/area/ministation/library) +"xc" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/turf/open, +/area/ministation/maint/l3ne) +"xg" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/lino, +/area/ministation/telecomms) +"xr" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"xt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"xH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"xJ" = ( +/obj/structure/sign/department/xenoarch{ + pixel_y = 30 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"xN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, +/area/ministation/maint/l3central) +"xT" = ( +/obj/machinery/door/blast/regular{ + id_tag = "toxinsdriver"; + name = "Toxins Launcher Bay Door" + }, +/turf/floor/plating/airless, +/area/ministation/science) +"ya" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/closet/secure_closet/freezer/fridge, +/obj/item/chems/drinks/bottle/cola, +/obj/item/chems/drinks/bottle/cola, +/obj/item/chems/drinks/bottle/cola, +/obj/item/chems/drinks/bottle/cola, +/obj/item/food/sliceable/chocolatecake, +/obj/item/food/sliceable/pizza/vegetablepizza, +/obj/item/food/sliceable/pizza/meatpizza, +/obj/item/food/sliceable/pizza/margherita, +/obj/item/food/sliceable/pizza/mushroompizza, +/obj/item/chems/drinks/cans/waterbottle, +/obj/item/chems/drinks/cans/waterbottle, +/obj/item/chems/drinks/cans/waterbottle, +/obj/item/chems/drinks/cans/waterbottle, +/obj/item/chems/drinks/cans/waterbottle, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"yc" = ( +/obj/machinery/camera/autoname{ + dir = 8; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"yd" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/tiled, +/area/ministation/bridge) +"yf" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"yh" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3se) +"yj" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/camera/autoname{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"ym" = ( +/turf/floor/tiled, +/area/ministation/bridge/vault) +"yu" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/science) +"yx" = ( +/obj/machinery/camera/network/command{ + dir = 4; + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"yz" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"yA" = ( +/obj/machinery/door/airlock/civilian, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/library) +"yH" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"yK" = ( +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, +/obj/machinery/disposal, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"yM" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + external_pressure_bound = 103; + external_pressure_bound_default = 102 + }, +/turf/floor, +/area/ministation/science) +"yP" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"yR" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 4 + }, +/turf/floor/plating/airless, +/area/ministation/shuttle/outgoing) +"yS" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/space, +/area/space) +"zd" = ( +/obj/machinery/fabricator/industrial{ + initial_network_id = "molluscnet" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"zl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"zs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning/corner{ + icon_state = "warningcorner" + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/sign/directions/bridge{ + dir = 1; + pixel_y = 42; + pixel_x = -28 + }, +/obj/machinery/camera/network/hallway{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"zt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"zw" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/floor/reinforced/airless, +/area/space) +"zx" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast1"; + name = "enclosure 1 blast door" + }, +/turf/floor, +/area/ministation/science) +"zy" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/s3) +"zC" = ( +/turf/floor/carpet/magenta, +/area/ministation/science) +"zP" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"zQ" = ( +/obj/structure/closet/secure_closet{ + closet_appearance = /decl/closet_appearance/secure_closet/rd; + req_access = list("ACCESS_RESEARCH"); + name = "Science locker" + }, +/obj/machinery/light, +/obj/item/med_pouch/trauma, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/shield/crafted/buckler, +/obj/item/gps/explorer, +/obj/item/flashlight/lantern, +/obj/item/bladed/polearm/spear/improvised/steel, +/turf/floor/tiled/white, +/area/ministation/science) +"zS" = ( +/obj/structure/lattice, +/obj/machinery/camera/network/research{ + dir = 1; + name = "Bomb Range External Gantry" + }, +/turf/space, +/area/space) +"zT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Aa" = ( +/obj/machinery/camera/network/command{ + dir = 4; + initial_access = null + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"Ab" = ( +/obj/machinery/network/message_server{ + initial_network_id = "molluscnet" + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"Af" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"Aj" = ( +/obj/effect/floor_decal/carpet/green{ + dir = 8 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"Al" = ( +/obj/machinery/button/blast_door{ + id_tag = "scishut"; + name = "Science Shutter Button"; + pixel_x = 5; + pixel_y = -6; + directional_offset = null + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = 1; + pixel_y = 9 + }, +/obj/item/pen, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Am" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Ar" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"As" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Ax" = ( +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"AE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"AH" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/wall, +/area/ministation/hall/n3) +"AK" = ( +/obj/machinery/portable_atmospherics/canister/helium, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/reinforced, +/area/ministation/science) +"AL" = ( +/obj/machinery/network/telecomms_hub{ + initial_network_id = "molluscnet" + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"AQ" = ( +/obj/effect/floor_decal/carpet/green{ + dir = 4 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"AS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/techfloor/orange, +/turf/floor/tiled, +/area/ministation/hall/n3) +"AU" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/shutters{ + name = "science shutters"; + id_tag = "scishut" + }, +/turf/floor/plating, +/area/ministation/science) +"AV" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + dir = 8; + name = "_West APC"; + pixel_x = -25 + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"AW" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable/max_cap_in_out, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"AX" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/tradehouse_rep) +"AY" = ( +/obj/machinery/computer/cryopod/robot{ + pixel_y = 29 + }, +/obj/abstract/landmark/start{ + name = "Robot" + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"AZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"Bb" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"Be" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Bf" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Bh" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Bk" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Bn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Bo" = ( +/obj/structure/sign/warning/hot_exhaust{ + pixel_x = -6; + pixel_y = 32 + }, +/obj/structure/sign/warning/vent_port{ + pixel_x = 6; + pixel_y = 32 + }, +/turf/floor/reinforced/airless, +/area/space) +"Bp" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"Br" = ( +/obj/machinery/light/small, +/turf/floor/bluegrid/mainframe, +/area/ministation/telecomms) +"Bs" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ministation/telecomms) +"Bt" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/lino, +/area/ministation/telecomms) +"Bu" = ( +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/obj/machinery/computer/station_alert/all, +/turf/floor/lino, +/area/ministation/telecomms) +"Bv" = ( +/obj/structure/table, +/obj/item/folder/blue, +/obj/item/pen/blue, +/obj/item/paper/monitorkey, +/turf/floor/lino, +/area/ministation/telecomms) +"Bw" = ( +/obj/machinery/computer/message_monitor, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"Bx" = ( +/obj/structure/table, +/obj/item/clothing/suit/jacket/winter, +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_y = 20 + }, +/obj/item/radio, +/turf/floor/lino, +/area/ministation/telecomms) +"By" = ( +/obj/structure/table, +/obj/item/flashlight/lamp, +/turf/floor/lino, +/area/ministation/telecomms) +"BC" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 4 + }, +/obj/structure/sign/warning/server_room{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"BD" = ( +/obj/structure/table, +/obj/item/paper_bin, +/turf/floor/lino, +/area/ministation/telecomms) +"BE" = ( +/obj/structure/chair/padded/blue{ + dir = 1 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"BG" = ( +/obj/structure/table, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/item/disk/nuclear, +/obj/machinery/recharger, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/lino, +/area/ministation/telecomms) +"BK" = ( +/obj/machinery/door/blast/regular{ + id_tag = "toxingasroom"; + name = "Toxins Gas Storage Blast Door" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/reinforced, +/area/ministation/science) +"BP" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"BQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"BR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"BS" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"BV" = ( +/obj/effect/floor_decal/carpet/green, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"BZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/glass/command{ + autoset_access = 0; + name = "Telecommunications glass airlock"; + req_access = list("ACCESS_TELECOMS") + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/lino, +/area/ministation/telecomms) +"Cd" = ( +/turf/wall, +/area/ministation/maint/l3central) +"Cg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"Cj" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"Ck" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/lino, +/area/ministation/telecomms) +"Cl" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/closet/emcloset, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/camera/network/command{ + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/lino, +/area/ministation/telecomms) +"Co" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Ct" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Cw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table, +/obj/item/box/animal_cubes/monkeys, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Cy" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/hall/n3) +"CA" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/lino, +/area/ministation/telecomms) +"CB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/hologram/holopad/longrange, +/turf/floor/lino, +/area/ministation/telecomms) +"CC" = ( +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/lino, +/area/ministation/telecomms) +"CD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/corner/black{ + dir = 8 + }, +/obj/structure/sign/warning/server_room{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"CE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"CL" = ( +/obj/machinery/fabricator/robotics{ + initial_network_id = "molluscnet" + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"CM" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"CN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"CR" = ( +/obj/machinery/door/window{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"CT" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"CU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/highsecurity{ + name = "Telecommunications" + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor, +/area/ministation/telecomms) +"CV" = ( +/obj/effect/floor_decal/corner/black{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"CW" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"CX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/science) +"CY" = ( +/obj/machinery/door/airlock/glass{ + autoset_access = 0; + name = "Court Room Airlock" + }, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"Da" = ( +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/flora/grass/both, +/turf/floor/grass, +/area/ministation/hall/n3) +"Dc" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"Dd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"De" = ( +/obj/structure/table, +/obj/item/multitool, +/obj/item/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/machinery/light_switch{ + dir = 1; + pixel_y = -23 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"Df" = ( +/obj/structure/table, +/obj/item/radio, +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_y = -30; + dir = 1 + }, +/obj/item/chems/spray/extinguisher, +/turf/floor/lino, +/area/ministation/telecomms) +"Dg" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -22 + }, +/obj/structure/filing_cabinet/chestdrawer, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/floor/lino, +/area/ministation/telecomms) +"Dh" = ( +/obj/effect/floor_decal/corner/black{ + dir = 1 + }, +/obj/structure/sign/department/telecomms{ + dir = 4; + pixel_x = -32 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Di" = ( +/obj/machinery/light/small, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Dj" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/structure/reagent_dispensers/watertank/firefighter, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"Dk" = ( +/obj/machinery/camera/network/hallway{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Dl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/button/blast_door{ + id_tag = "slimeblast3"; + name = "Enclosure 3 Blastdoors Button"; + pixel_x = -26; + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Dm" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 1 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Do" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/machinery/camera/autoname{ + dir = 4 + }, +/turf/open, +/area/ministation/hall/n3) +"Dp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/junction/mirrored, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Dt" = ( +/turf/wall, +/area/ministation/maint/l3sw) +"Du" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "pqm_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "pqm_airlock"; + name = "exterior access button"; + pixel_x = -10; + pixel_y = 20; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Dv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/abstract/landmark{ + name = "blobstart" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Dw" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Dx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light{ + icon_state = "tube1" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Dy" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Dz" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + name = "bridge blast door"; + id_tag = "bridgeblast" + }, +/turf/floor/plating, +/area/ministation/bridge) +"DB" = ( +/obj/effect/floor_decal/corner/green/full, +/obj/machinery/smartfridge/drying_oven, +/turf/floor/tiled/white, +/area/ministation/science) +"DC" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"DD" = ( +/obj/structure/table/laminate, +/obj/item/stack/material/panel/mapped/plastic/ten, +/obj/item/stack/material/plank/mapped/wood/ten, +/obj/item/stack/material/plank/mapped/wood/ten, +/obj/item/stack/material/panel/mapped/plastic/ten, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"DF" = ( +/obj/machinery/camera/autoname{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/court) +"DO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"DQ" = ( +/obj/structure/table/laminate, +/obj/item/pill_bottle/dice, +/turf/floor/carpet/green, +/area/ministation/library) +"DS" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"DX" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"DZ" = ( +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l3se) +"Ec" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Ee" = ( +/turf/floor/plating, +/area/ministation/maint/l3nw) +"Ef" = ( +/obj/structure/table/laminate, +/turf/floor/carpet/green, +/area/ministation/library) +"Eg" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Eu" = ( +/obj/structure/table, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/carpet/magenta, +/area/ministation/science) +"Ex" = ( +/obj/structure/chair/armchair/black{ + dir = 4 + }, +/turf/floor/carpet/green, +/area/ministation/library) +"EB" = ( +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/door/airlock/glass/science{ + name = "Science Department"; + req_access = list("ACCESS_ROBOTICS"); + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/science) +"EE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"EF" = ( +/obj/machinery/door/window/westleft{ + dir = 2 + }, +/obj/machinery/door/window/eastleft{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/tiled/white, +/area/ministation/science) +"EJ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled/white, +/area/ministation/science) +"EP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ER" = ( +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/machinery/portable_atmospherics/canister/helium, +/turf/floor/reinforced, +/area/ministation/science) +"ET" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"EV" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"EW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/techfloor/orange, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Fe" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4; + icon_state = "warningcorner" + }, +/obj/structure/sign/directions/science{ + pixel_y = -21; + pixel_x = -28 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Fm" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Fo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Fv" = ( +/obj/machinery/door/airlock/glass/science{ + name = "Toxins"; + req_access = list("ACCESS_XENOBIO"); + autoset_access = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/reinforced, +/area/ministation/science) +"Fy" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/sign/warning/airlock{ + pixel_y = 26; + pixel_x = -31 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"FC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/vending/coffee, +/turf/floor/lino, +/area/ministation/hall/s3) +"FE" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"FH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"FM" = ( +/obj/machinery/port_gen/pacman/super, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"FS" = ( +/obj/machinery/camera/network/research{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled/white, +/area/ministation/science) +"FV" = ( +/obj/structure/table/laminate, +/obj/item/mollusc/clam, +/obj/machinery/light/small, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Gh" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Gi" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Gk" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"Go" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"Gt" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/reinforced, +/area/ministation/science) +"Gu" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Gy" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/s3) +"GD" = ( +/turf/open, +/area/ministation/hall/n3) +"GE" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"GF" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/research{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"GJ" = ( +/obj/machinery/light, +/turf/floor/tiled/white, +/area/ministation/science) +"GK" = ( +/obj/machinery/computer/ship/sensors{ + dir = 8; + id_tag = "shuttlesensors" + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"GL" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/blood/oil, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"GN" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"GT" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/court) +"Hj" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Hl" = ( +/obj/structure/table/laminate/ebony, +/obj/item/paper_bin, +/obj/effect/floor_decal/stoneborder{ + dir = 6 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"Ho" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Hu" = ( +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/turf/floor/reinforced, +/area/ministation/science) +"Hw" = ( +/turf/wall/r_wall/prepainted, +/area/space) +"HB" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"HK" = ( +/obj/effect/floor_decal/carpet/green{ + dir = 4 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"HN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/window/eastleft, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast2"; + name = "enclosure 2 blast door" + }, +/turf/floor, +/area/ministation/science) +"HX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/handrail{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"Ia" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Ib" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "repblast"; + name = "rep blast door" + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"Id" = ( +/obj/machinery/door/airlock, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/court) +"Ie" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Ik" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"Il" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/ministation/tradehouse_rep) +"Io" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/chair/wood/maple{ + dir = 8 + }, +/obj/abstract/landmark/start{ + name = "Tradehouse Representative" + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"Ir" = ( +/turf/floor/laminate/yew, +/area/ministation/court) +"Ix" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"IA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"IB" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"IC" = ( +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"IL" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast3"; + name = "enclosure 3 blast door" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/floor, +/area/ministation/science) +"IP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"IS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/lino, +/area/ministation/telecomms) +"IT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"IV" = ( +/obj/machinery/door/airlock/glass/command, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/bridge) +"Je" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Ji" = ( +/obj/machinery/door/firedoor, +/obj/structure/window/basic/full, +/turf/floor/plating, +/area/ministation/library) +"Jk" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Jo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Jr" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/structure/closet/firecloset, +/obj/item/firstaid/fire, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"Ju" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = 23 + }, +/obj/structure/closet/firecloset, +/turf/floor/reinforced, +/area/ministation/science) +"Jx" = ( +/obj/structure/closet/secure_closet/research_director, +/obj/item/clothing/suit/jacket/winter, +/obj/item/stamp/rd, +/obj/item/rig/eva/equipped, +/turf/floor/tiled/white, +/area/ministation/science) +"Jz" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"JF" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast2"; + name = "enclosure 2 blast door" + }, +/turf/floor, +/area/ministation/science) +"JJ" = ( +/obj/machinery/door/airlock/glass, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s3) +"JK" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "32-4" + }, +/obj/machinery/atmospherics/pipe/zpipe/down/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/zpipe/down/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/down{ + dir = 4 + }, +/turf/open, +/area/ministation/maint/l3central) +"JN" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating/airless, +/area/ministation/science) +"JX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"JY" = ( +/obj/machinery/atmospherics/unary/temperature/freezer, +/obj/structure/sign/warning/nosmoking_burned{ + pixel_y = 32 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Kf" = ( +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/reinforced, +/area/ministation/science) +"Kg" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Kh" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Kj" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ + dir = 4 + }, +/obj/effect/wingrille_spawn/reinforced_borosilicate/full, +/turf/floor/reinforced/airless, +/area/ministation/science) +"Kr" = ( +/obj/effect/floor_decal/corner/b_green/half{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Kv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Ky" = ( +/obj/machinery/vending/bombresearch, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/sign/warning/fire{ + pixel_y = 32 + }, +/turf/floor/reinforced, +/area/ministation/science) +"KQ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"KU" = ( +/turf/floor/carpet/green, +/area/ministation/library) +"Le" = ( +/obj/structure/table/laminate, +/obj/item/chems/drinks/cans/waterbottle, +/turf/floor/carpet/green, +/area/ministation/library) +"Lq" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Lr" = ( +/obj/machinery/atmospherics/pipe/manifold/visible, +/obj/machinery/meter, +/turf/floor/tiled/white, +/area/ministation/science) +"LA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"LC" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"LD" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"LK" = ( +/obj/machinery/atmospherics/unary/temperature/freezer{ + set_temperature = 263 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"LL" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"LM" = ( +/turf/floor/laminate/mahogany, +/area/ministation/library) +"LN" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"LP" = ( +/obj/machinery/keycard_auth{ + pixel_y = -24; + dir = 1 + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/camera/network/command{ + dir = 1; + initial_access = null; + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled, +/area/ministation/bridge) +"LQ" = ( +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/obj/structure/table, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled/white, +/area/ministation/science) +"LS" = ( +/turf/floor/plating, +/area/ministation/maint/l3central) +"LT" = ( +/obj/structure/chair/armchair/black{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"LW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Mb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"Mc" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Md" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Me" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + name = "bridge blast door"; + id_tag = "bridgeblast" + }, +/turf/floor/plating, +/area/ministation/bridge) +"Mi" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/obj/effect/floor_decal/corner/green/full, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Mk" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/blood/oil, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Mn" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Mo" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + name = "bridge blast door"; + id_tag = "bridgeblast" + }, +/turf/floor/plating/airless, +/area/ministation/bridge) +"Mq" = ( +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Ms" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/table/laminate/reinforced/walnut, +/obj/item/folder, +/turf/floor/carpet/red, +/area/ministation/court) +"My" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Mz" = ( +/obj/machinery/atmospherics/unary/tank/carbon_dioxide{ + start_pressure = 10000 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"MA" = ( +/obj/structure/closet/secure_closet/courtroom, +/turf/floor/tiled, +/area/ministation/court) +"MB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s3) +"MF" = ( +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"MI" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"MJ" = ( +/obj/structure/chair/armchair/black, +/turf/floor/carpet/green, +/area/ministation/library) +"MP" = ( +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 32 + }, +/obj/machinery/disposal, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"MU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/camera/network/hallway{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/orange, +/turf/floor/tiled, +/area/ministation/hall/n3) +"MV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"MW" = ( +/obj/machinery/door/blast/regular{ + id_tag = "toxinsburnvent"; + name = "Toxins Blast Door Vent" + }, +/turf/floor/reinforced, +/area/ministation/science) +"MY" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast2"; + name = "enclosure 2 blast door" + }, +/turf/floor, +/area/ministation/science) +"MZ" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Na" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/machinery/light_switch{ + dir = 4; + pixel_x = -23 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"Nb" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"Nc" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/light_switch{ + pixel_y = 32 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"Ne" = ( +/obj/structure/table, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Ng" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/wall/titanium, +/area/ministation/shuttle/outgoing) +"Nh" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"Nk" = ( +/obj/machinery/photocopier, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Nm" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ + dir = 4 + }, +/turf/wall/titanium, +/area/ministation/shuttle/outgoing) +"Np" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Nr" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/airlock/double/glass/science{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"Nw" = ( +/turf/floor/tiled, +/area/ministation/court) +"Ny" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = -32; + dir = 1 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"ND" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"NF" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"NH" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"NJ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/flora/pottedplant/aquatic, +/turf/floor/lino, +/area/ministation/hall/s3) +"NM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"NN" = ( +/obj/structure/table, +/obj/machinery/alarm{ + pixel_y = -2; + dir = 4; + pixel_x = -24 + }, +/obj/machinery/light, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"NO" = ( +/obj/abstract/level_data_spawner/main_level, +/turf/space, +/area/space) +"NR" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"NW" = ( +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/machinery/light/small, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Oa" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Oc" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"Od" = ( +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"Ok" = ( +/obj/structure/shuttle/engine/heater{ + dir = 8 + }, +/obj/effect/paint/red, +/turf/wall/titanium, +/area/ministation/shuttle/outgoing) +"Om" = ( +/obj/structure/chair/armchair/black{ + dir = 8 + }, +/turf/floor/carpet/green, +/area/ministation/library) +"Oo" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/disposalpipe/segment{ + dir = 4; + icon_state = "conpipe-c" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Ou" = ( +/obj/effect/floor_decal/corner/b_green/three_quarters{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Ov" = ( +/obj/structure/table/laminate/walnut, +/obj/machinery/light, +/turf/floor/laminate/yew, +/area/ministation/court) +"Oy" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 4; + name = "airlock pump" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"OC" = ( +/obj/structure/sign/warning/airlock{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"OD" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/railing/mapped, +/turf/open, +/area/ministation/hall/n3) +"OG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/chair/office/light{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"OK" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "science_shuttle_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "science_shuttle"; + name = "interior access button"; + pixel_x = 20; + dir = 8 + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"OL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"OM" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/carpet/green{ + dir = 4 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"ON" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"OP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"OQ" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"OU" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"OW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Pa" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Pe" = ( +/obj/structure/catwalk, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/open, +/area/ministation/hall/n3) +"Pg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Pk" = ( +/obj/structure/table/laminate/walnut, +/obj/item/folder/blue, +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/laminate/yew, +/area/ministation/court) +"Pn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"Po" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Pq" = ( +/obj/machinery/light/navigation{ + pixel_y = 16; + pixel_x = 16 + }, +/turf/space, +/area/space) +"Pw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/techfloor/orange, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Px" = ( +/obj/structure/table/laminate/walnut, +/obj/item/folder/red, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"Pz" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/tiled, +/area/ministation/bridge) +"PA" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast3"; + name = "enclosure 3 blast door" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"PB" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Librarian" + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"PE" = ( +/obj/structure/chair/armchair/black{ + dir = 8 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"PL" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "science_shuttle_pump"; + dir = 4 + }, +/obj/effect/shuttle_landmark/science_dock, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + cycle_to_external_air = 1; + id_tag = "science_shuttle"; + tag_airpump = "science_shuttle_pump"; + tag_chamber_sensor = "science_shuttle_sensor"; + tag_exterior_door = "science_shuttle_exterior"; + tag_interior_door = "science_shuttle_interior"; + dir = 4; + pixel_x = -20 + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"PO" = ( +/turf/wall, +/area/ministation/maint/l3nw) +"PP" = ( +/obj/structure/closet, +/obj/random/maintenance, +/obj/item/flashlight, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"PR" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/n3) +"PT" = ( +/obj/structure/table/laminate/reinforced/walnut, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/carpet/red, +/area/ministation/court) +"PV" = ( +/obj/structure/table, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/item/modular_computer/tablet/preset/custom_loadout/cheap, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"PW" = ( +/obj/structure/closet/secure_closet/xenoarchaeologist, +/obj/item/clothing/suit/jacket/winter/science, +/obj/item/ano_scanner, +/obj/item/stock_parts/circuitboard/suspension_gen, +/turf/floor/tiled/white, +/area/ministation/science) +"PX" = ( +/obj/abstract/landmark/start{ + name = "Research Director" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/carpet/magenta, +/area/ministation/science) +"PY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Qf" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Qh" = ( +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"Qk" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"Qq" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Qs" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"Qt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/disposalpipe/junction/mirrored, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Qu" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Qx" = ( +/obj/structure/table, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/item/firstaid/stab, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"QD" = ( +/obj/structure/table/laminate, +/obj/item/book/printable_red, +/obj/item/pen, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"QF" = ( +/turf/wall, +/area/space) +"QG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/s3) +"QK" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/abstract/landmark/latejoin/cyborg, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"QR" = ( +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/laminate/yew, +/area/ministation/court) +"QT" = ( +/obj/machinery/computer/design_console{ + dir = 8; + initial_network_id = "molluscnet" + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"QW" = ( +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/structure/table/laminate, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Re" = ( +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor/plating, +/area/ministation/maint/l3nw) +"Rf" = ( +/obj/machinery/door/airlock/civilian{ + autoset_access = 0; + name = "Librarian's Chamber"; + req_access = list("ACCESS_LIBRARY") + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/library) +"Ri" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Rl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/structure/sign/department/xenobio_3{ + pixel_y = 32; + pixel_x = 32 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Rp" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Rt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Rv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Rx" = ( +/turf/wall, +/area/ministation/court) +"Ry" = ( +/obj/machinery/portable_atmospherics/canister/hydrogen, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/reinforced, +/area/ministation/science) +"RB" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3central) +"RD" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/window/eastleft, +/obj/machinery/door/blast/regular/open{ + id_tag = "slimeblast1"; + name = "enclosure 1 blast door" + }, +/turf/floor, +/area/ministation/science) +"RE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/handrail{ + dir = 1 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"RG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"RI" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"RL" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/turf/floor/tiled/white, +/area/ministation/science) +"RN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/reinforced, +/area/ministation/science) +"RO" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"RQ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"RR" = ( +/obj/effect/floor_decal/carpet/green{ + dir = 8 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 8 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"RS" = ( +/obj/machinery/power/smes/buildable/max_cap_in_out{ + RCon_tag = null; + capacity = 5e+009; + charge = 5e+009 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"RT" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ministation/maint/l3se) +"RV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"RY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Sa" = ( +/turf/wall, +/area/ministation/library) +"Sb" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Sc" = ( +/obj/machinery/door/airlock, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/tradehouse_rep) +"Sf" = ( +/obj/structure/table/laminate/walnut, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"Sh" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Sk" = ( +/obj/machinery/light, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"Sm" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/white, +/area/ministation/science) +"So" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Sq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"SA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"SE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/hallway{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"SG" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/hall/s3) +"SI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"SL" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 1 + }, +/obj/structure/skeleton, +/turf/floor/tiled/white, +/area/ministation/science) +"SP" = ( +/obj/item/stool/padded, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"SS" = ( +/obj/machinery/computer/ship/engines{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"ST" = ( +/obj/effect/floor_decal/corner/paleblue{ + dir = 5 + }, +/obj/effect/floor_decal/corner/white{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"SW" = ( +/obj/structure/closet/secure_closet/lawyer, +/turf/floor/tiled, +/area/ministation/court) +"Tc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Tk" = ( +/obj/structure/table/laminate, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Tm" = ( +/obj/effect/floor_decal/carpet/green{ + dir = 1 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 1 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"Tn" = ( +/obj/machinery/shipsensors{ + id_tag = "shuttlesensors" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/terminal{ + icon_state = "term-omni" + }, +/turf/floor/plating/airless, +/area/ministation/shuttle/outgoing) +"Tq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/machinery/camera/network/hallway{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Tr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/effect/floor_decal/corner/purple, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/ministation/science) +"Tt" = ( +/obj/machinery/portable_atmospherics/canister/helium, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/reinforced, +/area/ministation/science) +"Tv" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/structure/table/laminate/ebony, +/obj/item/pen, +/obj/item/pen/blue, +/obj/item/pen/retractable, +/obj/item/pen/retractable/green, +/obj/item/pen/retractable/blue, +/obj/item/pen/multi, +/obj/effect/floor_decal/stoneborder/corner, +/turf/floor/laminate/walnut, +/area/ministation/library) +"Tx" = ( +/obj/machinery/light_switch{ + pixel_y = -1; + pixel_x = -24; + dir = 4 + }, +/obj/structure/bed, +/obj/item/bedsheet/rd, +/obj/random/plushie, +/turf/floor/carpet/magenta, +/area/ministation/science) +"Tz" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock{ + start_pressure = 730 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/camera/network/research{ + req_access = list("ACCESS_CAMERAS") + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"TC" = ( +/obj/machinery/portable_atmospherics/canister/sleeping_agent, +/turf/floor/reinforced, +/area/ministation/science) +"TD" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/ministation/science) +"TE" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/effect/overmap/visitable/ship/ministation, +/obj/structure/chair/padded/blue, +/turf/floor/tiled, +/area/ministation/bridge) +"TF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"TG" = ( +/obj/machinery/atmospherics/binary/pump/high_power{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"TH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"TI" = ( +/obj/structure/table/laminate, +/obj/random/cash, +/obj/item/chems/drinks/cans/waterbottle, +/turf/floor/carpet/green, +/area/ministation/library) +"TP" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/open, +/area/ministation/hall/n3) +"TR" = ( +/obj/structure/window/basic{ + dir = 1 + }, +/obj/structure/curtain/open/bed{ + icon_state = "closed"; + opacity = 1 + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "repblast"; + name = "rep blast door" + }, +/turf/floor/plating, +/area/ministation/tradehouse_rep) +"TS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"TX" = ( +/obj/machinery/camera/network/research{ + dir = 1; + name = "Bomb Range External Adjacent" + }, +/turf/space, +/area/space) +"TY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/extinguisher_cabinet{ + pixel_x = -29; + dir = 4 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/n3) +"TZ" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"Ua" = ( +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/obj/structure/table, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/obj/machinery/faxmachine/mapped, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"Uh" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/reinforced, +/area/ministation/science) +"Ul" = ( +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + max_health = 1e+007 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/disposaloutlet{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/science) +"Um" = ( +/obj/effect/floor_decal/carpet/green/corners, +/obj/effect/floor_decal/stoneborder/corner{ + dir = 8 + }, +/obj/structure/reagent_dispensers/water_cooler{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"Uo" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Up" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Uq" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Uw" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"UB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/lino, +/area/ministation/hall/s3) +"UD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"UE" = ( +/obj/structure/closet/crate/uranium, +/obj/item/wrench, +/obj/item/inflatable_dispenser, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"UG" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/bookcase/skill_books/random, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"UH" = ( +/obj/machinery/alarm{ + pixel_y = 23 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"UI" = ( +/obj/effect/wallframe_spawn/no_grille, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/court) +"UJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"UK" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/portables_connector{ + pixel_x = -3 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"UL" = ( +/obj/effect/decal/cleanable/filth, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"UM" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/space, +/area/space) +"UQ" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l3se) +"UR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"UT" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Vb" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/open, +/area/ministation/maint/l3se) +"Vi" = ( +/obj/machinery/light_switch{ + pixel_y = 25 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/table/laminate, +/obj/item/knife/kitchen, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/obj/item/mollusc/clam, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Vl" = ( +/obj/structure/bookcase/manuals, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Vq" = ( +/obj/structure/bookcase/skill_books/random, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Vt" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Vu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/extinguisher_cabinet{ + pixel_x = 29; + dir = 8 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Vv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/obj/structure/chair/comfy/captain{ + dir = 8 + }, +/obj/machinery/camera/autoname{ + dir = 8 + }, +/turf/floor/carpet/red, +/area/ministation/court) +"Vw" = ( +/obj/structure/table/laminate, +/obj/item/deck/cards, +/turf/floor/carpet/green, +/area/ministation/library) +"Vx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"VB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"VI" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "science_vent"; + dir = 1 + }, +/turf/floor/plating, +/area/ministation/science) +"VJ" = ( +/turf/floor/plating, +/area/ministation/maint/l3ne) +"VL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"VN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/structure/reagent_dispensers/watertank/firefighter, +/turf/floor/tiled/white, +/area/ministation/science) +"VW" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/status_display{ + pixel_y = 30; + pixel_x = -33 + }, +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/table/laminate, +/obj/machinery/fabricator/book, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"VX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"VY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "science_shuttle_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "science_shuttle"; + name = "exterior access button"; + pixel_x = 21; + pixel_y = 11; + command = "cycle_exterior" + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"VZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Wg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Wh" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular{ + name = "bridge blast door"; + id_tag = "bridgeblast" + }, +/turf/floor/plating, +/area/ministation/bridge) +"Wj" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Wo" = ( +/obj/machinery/button/blast_door{ + name = "Burn Chamber Vent"; + dir = 8; + pixel_x = 22; + id_tag = "toxinsburnvent"; + pixel_y = -6 + }, +/obj/structure/tank_rack/oxygen, +/obj/machinery/button/ignition{ + id_tag = "toxinsigniter"; + pixel_y = 8; + dir = 8; + pixel_x = 22 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Wr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Ws" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Wx" = ( +/obj/machinery/door/airlock/hatch/maintenance, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"WA" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/tiled/white, +/area/ministation/science) +"WJ" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"WK" = ( +/obj/machinery/artifact_analyser, +/turf/floor/tiled/white, +/area/ministation/science) +"WM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -26 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"WO" = ( +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"WQ" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/stoneborder{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"WT" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/green, +/obj/random_multi/single_item/captains_spare_id, +/obj/machinery/light_switch{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"WV" = ( +/obj/machinery/igniter{ + id_tag = "toxinsigniter" + }, +/turf/floor/reinforced, +/area/ministation/science) +"Xa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Xb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/tiled, +/area/ministation/hall/n3) +"Xe" = ( +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/laminate/yew, +/area/ministation/court) +"Xi" = ( +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/carpet/red, +/area/ministation/court) +"Xl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Xm" = ( +/obj/machinery/light/navigation{ + pixel_y = -16; + pixel_x = 16 + }, +/turf/space, +/area/space) +"Xv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"XA" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/railing/mapped, +/turf/open, +/area/ministation/hall/n3) +"XE" = ( +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" + }, +/turf/open, +/area/ministation/hall/n3) +"XI" = ( +/obj/effect/floor_decal/carpet/green/corners, +/obj/effect/floor_decal/stoneborder/corner{ + dir = 4 + }, +/turf/floor/laminate/walnut, +/area/ministation/library) +"XJ" = ( +/obj/structure/closet, +/obj/random/maintenance, +/obj/random/suit, +/obj/random/gloves, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/item/cash/scavbucks, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"XM" = ( +/obj/machinery/door/airlock, +/obj/machinery/door/firedoor{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ministation/court) +"XR" = ( +/obj/structure/table/reinforced, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/window/reinforced, +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/machinery/button/blast_door{ + id_tag = "slimeblast1"; + name = "Enclosure 1 Blastdoors Button" + }, +/obj/machinery/camera/network/research, +/turf/floor/tiled, +/area/ministation/science) +"XS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"XT" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ministation/science) +"XY" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Yc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/stool/padded, +/obj/abstract/landmark/start{ + name = "Scientist" + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Ye" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"Yi" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Yj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"Yl" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/table, +/turf/floor/tiled/white, +/area/ministation/science) +"Ym" = ( +/obj/structure/window/reinforced, +/obj/structure/flora/bush/grassybush, +/turf/floor/grass, +/area/ministation/hall/n3) +"Yv" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l3central) +"Yw" = ( +/obj/machinery/artifact_scanpad, +/turf/floor/tiled/white, +/area/ministation/science) +"Yy" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "science_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "ministation_science_dock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/science) +"YE" = ( +/obj/machinery/vending/wallmed1{ + pixel_y = 32 + }, +/turf/floor/tiled/techfloor, +/area/ministation/science) +"YF" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, +/area/ministation/science) +"YH" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"YI" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/laminate/yew, +/area/ministation/court) +"YJ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"YL" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"YO" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "science_shuttle_pump_out_internal" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/airlock_sensor{ + id_tag = "science_shuttle_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"YP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/computer/modular/preset/civilian{ + dir = 1 + }, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"YQ" = ( +/obj/structure/closet/lawcloset, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/court) +"YR" = ( +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/apc{ + dir = 8; + pixel_x = -27 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/plating, +/area/ministation/shuttle/outgoing) +"YS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"YX" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "science_shuttle_pump_out_external" + }, +/obj/structure/handrail{ + dir = 8 + }, +/turf/floor/plating/airless, +/area/ministation/shuttle/outgoing) +"YZ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled, +/area/ministation/hall/s3) +"Za" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 5 + }, +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 8; + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Zd" = ( +/obj/machinery/button/blast_door{ + id_tag = "anomvent"; + name = "emergency vent control"; + pixel_y = -24; + pixel_x = -5; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/button/mass_driver{ + pixel_y = -22; + pixel_x = 7; + id_tag = "artifactlauncher"; + name = "LAUNCH"; + dir = 1 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"Zg" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Zj" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Zo" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 0; + id_tag = "pqm_airlock"; + pixel_y = 24; + tag_airpump = "pqm_vent"; + tag_chamber_sensor = "pqm_sensor"; + tag_exterior_door = "pqm_airlock_exterior"; + tag_interior_door = "pqm_airlock_interior" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "pqm_vent" + }, +/obj/machinery/airlock_sensor{ + id_tag = "pqm_sensor"; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/maint/l3sw) +"Zq" = ( +/obj/machinery/atmospherics/pipe/simple/heat_exchanging{ + dir = 10 + }, +/turf/floor/reinforced, +/area/ministation/science) +"Zr" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l3ne) +"Zt" = ( +/obj/structure/chair/wood/walnut{ + dir = 4 + }, +/obj/machinery/firealarm{ + pixel_y = 25 + }, +/turf/floor/laminate/yew, +/area/ministation/court) +"Zu" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/alarm{ + pixel_y = 22 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"Zv" = ( +/turf/wall, +/area/ministation/hall/s3) +"ZB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 5 + }, +/turf/floor/tiled, +/area/ministation/bridge) +"ZH" = ( +/obj/effect/floor_decal/carpet/green, +/turf/floor/laminate/walnut, +/area/ministation/library) +"ZJ" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/tiled, +/area/ministation/hall/n3) +"ZK" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/carpet/magenta, +/area/ministation/science) +"ZO" = ( +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ministation/science) +"ZP" = ( +/obj/effect/wallframe_spawn/no_grille, +/turf/floor/plating, +/area/ministation/court) +"ZR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ministation/hall/s3) +"ZS" = ( +/obj/structure/chair/shuttle/blue{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled, +/area/ministation/shuttle/outgoing) +"ZT" = ( +/obj/machinery/camera/network/research{ + dir = 4; + req_access = list("ACCESS_CAMERAS") + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/white, +/area/ministation/science) +"ZV" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/item/paper_bin, +/obj/item/pen, +/turf/floor/carpet/green, +/area/ministation/tradehouse_rep) +"ZW" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/laminate/mahogany, +/area/ministation/library) +"ZZ" = ( +/obj/structure/table/laminate/reinforced/walnut, +/obj/item/bell, +/turf/floor/carpet/red, +/area/ministation/court) + +(1,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(2,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(3,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(4,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(5,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +NO +vA +vA +vA +vA +"} +(6,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(7,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(8,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(9,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(10,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(11,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(12,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(13,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(14,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(15,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(16,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(17,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(18,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(19,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(20,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(21,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(22,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(23,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(24,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(25,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(26,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(27,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(28,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(29,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(30,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(31,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(32,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(33,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(34,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(35,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(36,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(37,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(38,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(39,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(40,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(41,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(42,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(43,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(44,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(45,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(46,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(47,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(48,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(49,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +af +af +af +af +af +vA +vA +vA +vA +af +af +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(50,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +af +af +af +af +af +vA +vA +af +af +af +af +af +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(51,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +af +af +af +af +af +vA +af +af +af +af +af +af +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(52,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +af +af +af +af +af +af +vA +vA +vA +af +af +af +af +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(53,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +af +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(54,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +af +af +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(55,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(56,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(57,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(58,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(59,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(60,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(61,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(62,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +af +vA +vA +vA +af +vA +af +af +af +af +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(63,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +af +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(64,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(65,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(66,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(67,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(68,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(69,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(70,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +af +af +af +af +vA +vA +af +af +af +af +vA +vA +vA +vA +ab +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(71,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(72,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(73,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(74,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(75,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(76,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(77,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(78,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(79,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(80,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(81,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(82,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +sq +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(83,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(84,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(85,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(86,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(87,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(88,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +yS +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(89,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(90,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(91,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(92,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +vA +cw +cw +cw +vA +vA +vA +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(93,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +af +af +af +af +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +vA +cw +cw +cw +vA +vA +vA +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(94,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +af +af +af +af +af +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +vA +cw +cw +cw +vA +vA +vA +cw +cw +cw +cw +cw +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(95,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +af +af +af +af +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +vA +cw +cw +cw +vA +vA +vA +cw +cw +cw +cw +cw +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(96,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +af +vA +vA +vA +af +af +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(97,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(98,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(99,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(100,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(101,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(102,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(103,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(104,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(105,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(106,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +cn +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(107,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dt +Du +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(108,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +Dt +Zo +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(109,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +Dt +jm +Dt +Dt +Dt +gU +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(110,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +Dt +bu +Dt +UK +XJ +NW +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(111,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +Dt +Dt +Dt +Dt +Dt +Dt +Dt +Dt +Zg +Dt +PP +HB +NF +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(112,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Cd +Cd +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +Dt +Gh +vm +Zj +zT +zT +mY +zT +RO +CN +KQ +eP +Dv +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(113,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Cd +JK +Cd +cw +Cd +Cd +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +Dt +Dt +Dt +Dt +oR +bl +bl +bl +bl +bl +bl +bl +bl +bl +bl +Am +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(114,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +PO +PO +PO +PO +PO +PO +vA +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +Cd +Ie +Cd +cw +Cd +sQ +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +Dt +pb +rk +Wx +sh +bl +nA +of +yx +Ax +cP +Ax +AV +Aa +bl +Am +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(115,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ah +ah +ah +ah +ah +vA +vA +PO +Re +mW +mW +dZ +PO +PO +PO +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +Cd +lp +Cd +cw +Cd +DC +Cd +cw +cw +cw +cw +cw +cw +cw +aA +cw +cw +cw +cw +cw +Dt +Dt +Dt +Dt +sh +bl +sr +sr +sr +sr +sr +Ax +AW +Br +bl +Ec +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(116,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +pa +ah +aR +br +bG +ah +vA +vA +PO +Il +Af +mW +qY +ur +hY +PO +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +Cd +Cd +Gu +Cd +Cd +Cd +RB +Cd +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +Dt +sh +bl +nA +Ax +Ab +AL +sr +Ax +Bp +Ax +bl +Am +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(117,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Mo +aT +bs +bH +ah +co +co +co +co +co +Ee +av +PO +PO +PO +cw +cw +vA +vA +ab +vA +vA +vA +vA +vA +vA +cw +gF +Cd +Oo +Lq +xN +xN +xN +Fy +ls +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +Dt +sh +bl +Bs +Bs +Bs +Bs +sr +tc +tU +sr +bl +GL +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(118,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ah +aW +bt +bI +ah +co +Ua +ZV +PV +co +yf +av +PO +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Cd +lp +sD +sD +Gi +sD +sD +Np +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +Dt +Dt +sh +bl +Bv +BD +BP +og +sr +td +tV +uA +bl +Am +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(119,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ah +ah +aX +ah +ah +ah +co +Dc +Io +YP +co +co +av +PO +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Cd +lp +sD +Pe +cg +Do +sD +Np +Cd +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +Dt +nL +sh +bl +Bu +BE +BQ +Bs +Bs +oF +Bs +Bs +bl +Yi +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(120,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ah +ah +aF +NH +bv +bK +qx +TR +IC +cD +Yj +Ib +AX +av +PO +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Cd +lp +sD +ug +XA +GD +sD +Np +Cd +Cd +Cd +Cd +Cd +Cd +Cd +Cd +Cd +cw +vA +vA +vA +vA +vA +Dt +fi +sh +bl +xg +Bt +IS +Bs +Cj +CA +By +De +bl +Am +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(121,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +tQ +am +aI +ba +bw +TH +aJ +TR +WT +kq +sM +co +co +av +PO +PO +PO +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +sD +sD +Cd +jy +AH +ug +OD +GD +sD +dE +Yv +Yv +Yv +Yv +Yv +Rp +Bh +ls +Cd +vA +vA +vA +vA +vA +vA +Dt +Dt +xr +bl +Bw +BE +BR +BZ +Ck +CB +BP +Df +bl +Am +Dt +Dt +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(122,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +af +af +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +ao +aJ +aY +aJ +MV +aJ +co +co +vl +co +co +fU +av +ur +qi +PO +vA +vA +vA +vA +vA +vA +vA +vA +sD +sD +sD +sD +pz +Eg +fl +sD +ug +XE +TP +sD +Be +LS +LS +LS +Mq +LS +nI +Zv +nP +Zv +Zv +vA +vA +vA +vA +vA +vA +Dt +vJ +bl +Bx +BG +oG +Bs +Cl +CC +CT +Dg +bl +fN +GN +pb +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(123,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +as +aK +aY +aJ +MV +bV +aD +aD +Sc +aD +aD +sD +eM +sD +sD +sD +sD +sD +sD +sD +tx +tx +tx +sD +sD +iu +iZ +sD +sD +Gu +sD +sD +sD +Cy +sD +sD +sD +sD +sD +sD +sD +Zv +Zv +Zv +Mn +Hj +Zv +kg +kg +kg +Zv +Zv +Zv +Zv +Bf +bl +bl +bl +bl +bl +bl +bl +CU +bl +bl +Dw +Dt +Dt +Dt +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(124,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +wd +mk +aY +aJ +UR +pf +IV +Na +jL +Oc +ss +bW +cr +Pw +xH +fz +MU +RY +TY +Md +OW +So +gR +gR +Md +So +OW +OW +OW +OU +OW +OW +Qu +OW +uV +cp +zs +IA +hS +IA +Fe +JJ +Mc +we +Kg +uh +FC +UB +NJ +UB +wM +Pa +uh +uh +RQ +Bn +uh +RI +uh +ZR +uh +CD +CV +Dh +Dk +Dx +Zv +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(125,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +tA +aO +bb +bx +bM +Qs +yd +ZB +bM +rh +uX +sY +sB +pP +MZ +kh +pP +MZ +sC +sC +sC +sC +kh +kh +sC +PR +sC +sC +sC +ll +sC +sC +sC +sC +ZJ +sC +hx +GD +GD +GD +de +Gy +tt +tt +Mn +tt +Ou +Kr +Kr +Kr +uB +tt +tt +oN +Mn +tt +tt +Sq +tt +tt +tt +tt +Xl +tt +tt +Mn +kg +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(126,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Wh +ax +TE +bc +bz +bN +bX +ch +cs +fk +cE +cU +Ym +Sb +EW +Ar +rx +EW +zt +LL +fA +es +gx +gS +rx +LL +LL +LL +LL +LL +eO +sC +PR +sC +sC +ZJ +sC +uZ +GD +tv +GD +BS +Gy +oN +tt +uS +Pg +Pg +Pg +Pg +Pg +Bk +Pg +Pg +Pg +Rv +Pg +Pg +YZ +Pg +Pg +Rt +Pg +CW +Rt +Pg +Dy +kg +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(127,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +ay +ST +be +bA +bM +Qs +yd +OQ +bM +di +Pz +Da +sB +pP +MZ +kh +pP +MZ +sC +sC +sC +gQ +sC +kh +sC +PR +sC +sC +sC +ts +PR +sC +sC +sC +ZJ +sC +wa +GD +GD +GD +vq +Gy +tt +tt +tt +tt +tt +tt +tt +tt +aV +tt +tt +tt +tt +oN +oN +Sq +tt +tt +oN +tt +fZ +tt +tt +Mn +kg +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(128,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +az +pM +aJ +aY +bO +bY +ci +ct +uG +cF +dr +WO +Jo +AS +VL +gT +AS +VL +Wr +Dp +VZ +gy +VZ +Qt +hV +Tq +VZ +cJ +VZ +tY +Fo +VZ +VZ +VZ +Ia +VZ +LN +Xb +rf +Xb +lb +eZ +MB +fJ +iN +iN +iN +QG +Kv +zy +Co +fJ +fJ +rK +SE +fJ +tB +CM +SG +ui +Vu +CE +SI +tt +oN +Dx +Zv +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(129,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +oS +aO +aJ +aY +bM +bZ +aD +ah +ah +ah +ah +LW +UI +UI +UI +CY +UI +ZP +Rx +Id +Sa +da +da +sl +da +Sa +Sa +da +da +Sa +Sa +Sa +Ji +Ji +sD +sD +sD +tx +tx +tx +sD +ae +ae +ae +lG +lG +lG +ae +ae +ae +ae +ae +ae +if +AU +ae +ae +EB +ae +ae +ae +ae +ae +ae +ae +RT +oc +oc +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(130,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Dz +aB +aJ +aJ +aY +bM +vs +aD +cu +Mk +cV +yP +dS +Rx +Qh +Od +ND +Od +Xe +Rx +rW +Sa +QW +SP +YS +LT +gV +Vq +LM +LM +Vl +yj +Vq +SP +FE +Sa +cw +cw +cw +cw +cw +gF +ae +dw +dt +ar +ar +ar +ae +tu +zd +hf +iK +Al +gg +MF +ae +kn +kQ +lv +ae +mA +nr +MF +Mi +ae +iG +yh +ty +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(131,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Me +aC +aP +bf +bB +bP +ca +aD +he +VJ +UL +VJ +dT +Rx +Zt +Od +ND +Od +Od +Rx +Sk +Sa +wq +Uw +Up +Uw +Uw +Ws +LM +LM +Vq +LM +Vq +SP +FE +Sa +cw +cw +cw +cw +cw +cw +ae +gJ +fK +ar +eb +ar +ae +ee +iL +iL +iL +ig +db +dQ +ae +ko +RV +lw +ae +mB +ns +As +oB +ae +iG +oc +oc +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(132,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ah +ah +aQ +eF +Mb +LP +ah +aD +nl +Qq +cW +cW +Zr +tZ +Ir +Ir +UD +Ir +Ny +Rx +rW +Sa +VW +Tk +Ri +LM +Vq +Vq +Nk +LM +LM +LM +LM +LM +FV +Sa +cw +cw +cw +cw +cw +cw +ae +AY +fK +ar +ar +ar +ae +QT +iL +iL +iL +ig +db +jn +ae +kp +kR +lx +ae +mC +db +As +oB +ae +Nh +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(133,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +jN +vA +vA +vA +vA +vA +vA +vA +vA +aD +bg +bg +bD +bg +bg +ad +nl +xc +cX +VJ +ET +Rx +Sf +Pk +TF +Px +Ov +Rx +pi +Sa +PB +QD +Uq +AE +RG +Jz +LM +LM +Vq +LM +Vl +SP +FE +Sa +cw +cw +ae +ae +kW +kW +ae +dv +Ik +QK +hg +eD +ae +gd +iL +iL +iL +ig +db +jo +ae +ae +kP +ae +ae +mD +db +As +oB +ae +iG +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(134,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +bg +bi +bE +bT +bg +vA +nl +nl +nl +nl +tC +Rx +QR +Ir +ND +Ir +Ir +Rx +rW +Sa +Jk +ZW +yc +MP +UG +Vq +LM +fV +Vq +PE +Vl +Sa +Sa +Sa +cw +cw +kW +Tx +kG +Jx +ae +ae +ae +ec +ae +ae +ae +YE +CL +iI +hh +ih +db +jp +ae +kr +kT +lz +ae +mG +db +As +oB +ae +Gk +oc +oc +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(135,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +bg +bn +bF +bq +bg +vA +vA +vA +vA +nl +NR +Rx +IB +ZZ +PT +dn +Ir +Rx +rW +Sa +Rf +Sa +Sa +Sa +Tv +WQ +uK +AQ +OM +OM +OM +HK +Um +hv +cw +cw +kW +zC +PX +UJ +mN +Ix +hj +Sm +te +GF +iJ +nz +hG +hG +hG +Cg +LC +jq +ae +ks +kU +lA +ae +mF +db +As +DB +ae +iG +ap +rI +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(136,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +bg +bp +bR +bq +bg +ad +vA +nl +nl +nl +Tc +Rx +Nc +Ms +Vv +Xi +YI +XM +eV +Sa +Zu +oQ +DD +Sa +Hl +kk +ZH +KU +Ex +Ex +Ex +KU +Tm +hv +cw +cw +kW +Eu +ZK +rV +cL +bo +hH +hH +hH +XT +gH +Rl +gG +hH +hH +ik +iO +jr +jP +kt +kV +lB +mf +mE +nt +Po +dx +yu +ki +ap +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(137,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +bg +nj +bq +bq +bg +ad +ad +nl +nN +nS +Tc +Rx +Rx +Rx +Rx +Rx +Rx +Rx +eW +Sa +ya +LM +lh +Sa +ps +kk +ZH +MJ +TI +DQ +Le +KU +Tm +Sa +cw +cw +ae +ae +ae +ae +ae +cN +ae +ae +ae +ae +ae +iP +ae +ae +hI +db +db +js +ae +ku +NM +lC +ae +mH +nu +od +oC +ae +Qk +ap +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(138,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +bg +by +ym +ym +bg +ad +vA +nl +nl +nQ +ET +VJ +Rx +MA +YQ +dX +eB +nX +eX +Sa +Vi +LA +lH +Sa +wY +mX +BV +KU +Vw +Le +Ef +KU +Tm +Sa +cw +cw +ae +wJ +PA +kc +Wj +Dl +db +db +FS +rp +Je +Wg +SL +ae +hJ +db +db +jt +ae +kv +NM +lD +ae +oD +nv +oD +oD +ae +iG +ap +DZ +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(139,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +bg +bg +bg +bg +bg +vA +vA +vA +vA +nl +Tc +VJ +Rx +Nw +dq +dY +dY +dY +eY +Sa +sV +LM +xt +Sa +Sa +Sa +Sa +KU +Om +Om +Om +KU +Tm +hv +cw +cw +uz +yM +IL +EF +EJ +ob +db +Xa +fb +dc +dc +RL +GJ +ae +hK +db +db +ju +ae +kw +NM +lE +ae +mJ +nw +oe +mJ +ae +jd +ap +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(140,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +nl +Vt +yH +tZ +Nw +OP +Nw +Nw +Nw +Nw +Sa +Sa +Sa +yA +Sa +Sa +nZ +nl +RR +RR +st +RR +Aj +XI +hv +cw +cw +ae +pr +pm +yK +sW +ob +db +XS +ae +fd +gf +OL +gK +ae +hL +in +iQ +jv +ae +kx +NM +rQ +ae +vz +mJ +mJ +oE +ae +DX +op +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(141,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +nl +iq +GT +Rx +SW +et +aq +nW +DF +vv +Rx +WJ +pp +Ho +VJ +Oa +VJ +nl +Sa +Sa +Sa +Sa +Sa +Sa +Sa +cw +cw +ae +ae +ae +LK +PY +ob +gh +eg +ae +fe +db +tm +ae +ae +ae +ae +ae +ae +ae +ZO +EE +ZO +ae +mK +mK +mK +mK +ae +oc +oc +yh +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(142,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +nl +nl +Tc +Rx +Rx +Rx +Rx +Rx +Rx +Rx +Rx +Tc +nl +nl +nl +nl +nS +nl +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +YF +aN +aN +aN +mr +im +DO +ae +ff +vc +Cw +ae +hm +hN +io +iR +ZT +db +kz +NM +db +ae +ae +ae +ae +ae +ae +vA +oc +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(143,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +nl +yz +pp +cW +cW +cW +pp +cW +cW +cW +Ho +nl +cw +cw +nl +Di +nl +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +XR +dy +ef +ae +mn +dy +ef +ae +fg +gh +hF +ae +hn +hO +iS +iT +db +jw +db +NM +db +ae +cx +db +db +cI +ae +vA +oc +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(144,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +cw +cw +nl +VJ +nl +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +ve +RD +zx +ae +MY +HN +JF +ae +fh +LC +gi +ae +hM +ip +io +BC +jx +db +Xa +My +Tr +ae +lF +db +db +cI +ae +vA +oc +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(145,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +nl +xc +nl +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +dd +dd +aw +ae +dd +dd +aw +ae +CX +CX +CX +ae +ae +ae +ae +tT +fc +db +XS +ob +Vx +uN +MI +db +db +zQ +ae +vA +oc +UQ +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +sq +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(146,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +nl +nl +nl +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +dd +dd +aw +ae +dd +du +aw +ae +Jr +db +db +db +db +db +ZO +db +db +db +XS +ob +jM +ae +gI +db +db +jO +ae +vA +oc +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(147,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +dd +dA +eh +ae +dd +dA +eh +ae +Dj +db +Kh +dc +dc +dc +FH +dc +Xv +vT +hi +ob +Oy +ae +ot +db +db +ge +ae +vA +oc +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(148,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ae +ae +ae +ae +dz +dz +dz +dz +dz +dz +dz +wk +dz +dz +ae +ae +ae +ae +ae +it +IP +oP +ae +ae +ae +CX +CX +ae +vA +oc +ap +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(149,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +dz +dz +dz +dz +dz +dz +em +YJ +VN +dz +PW +Yl +Yw +WK +ae +xJ +VX +WA +ae +cw +pa +vA +vA +vA +vA +oc +Vb +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(150,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +pF +UT +RN +eC +dz +dz +Ne +gh +jR +dz +Uo +OG +im +AZ +ii +hi +VX +GJ +ae +cw +vA +vA +vA +vA +vA +oc +oc +oc +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(151,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +aA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aA +cw +cw +cw +cw +dz +dz +Hu +Hu +Hu +sp +dz +dz +LQ +Wj +Yc +dz +db +Qf +db +Zd +ae +vP +VX +zP +ae +cw +vA +vA +hl +YX +yR +yR +Tn +hl +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(152,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +ER +AK +Tt +rC +dz +dz +JY +Lr +XS +dz +aZ +gn +CR +Sh +ae +JX +VX +db +CX +vA +vA +vA +Ok +sE +Ng +Nm +VB +Ok +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(153,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +wl +wl +wl +XY +dz +dz +vF +mw +XS +dz +UH +ey +ml +mJ +ae +JX +VX +db +CX +vA +vA +vA +nG +FM +UE +YR +rl +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(154,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +Kf +iy +Ry +dF +Fv +BK +vj +LD +wH +dz +uH +ey +mJ +mJ +ae +ky +VX +OC +ae +ae +ae +ae +nG +hy +nG +nG +zl +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(155,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +ab +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +TC +TC +TC +sp +dz +dz +Ky +mJ +Fm +dz +dz +ae +vo +ae +ae +oH +EP +gp +Yy +VI +uR +eH +VY +YO +PL +OK +HX +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(156,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +Uh +GE +Gt +mZ +dz +dz +Ju +aU +dM +pS +dz +cw +cw +cw +ae +Dd +SA +db +ae +ae +cL +ae +nG +Ye +Nb +nG +RE +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(157,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +dz +dz +dz +dz +dz +dz +Ct +Fm +Fm +wo +dz +cw +cw +cw +ae +ae +cQ +ae +ae +QF +vA +vA +ei +Mz +Go +iC +WM +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(158,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +dz +dz +dz +dz +dz +dz +Wo +cb +TG +qJ +dz +cw +cw +cw +ae +ex +eq +TD +mV +QF +vA +vA +nG +Tz +IT +TZ +YL +ei +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(159,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +Kj +Kj +gk +dz +fS +cw +cw +ae +DS +rE +Bb +cZ +ek +vA +vA +nG +ms +iM +Pn +mU +ei +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(160,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +EV +Zq +Za +MW +cw +cw +cw +ae +cL +Ul +cL +ae +ek +ad +vA +nG +RS +ON +TS +mm +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(161,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +EV +WV +EV +MW +cw +cw +cw +qn +JN +ez +JN +qn +ad +ad +vA +nG +nG +YH +Nr +nG +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(162,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +Zq +Dm +sL +MW +cw +cw +cw +cw +qn +xT +qn +vA +vA +ad +vA +nG +Qx +gN +ZS +NN +nG +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(163,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +dz +dz +dz +dz +Bo +cw +cw +cw +cw +vA +vA +vA +vA +ad +vA +ei +eA +rB +GK +SS +ei +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(164,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +dz +dz +dz +dz +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +ad +vA +ei +ei +ei +ei +ei +ei +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(165,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ad +ad +ad +vA +vA +vA +ad +ad +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(166,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ad +vA +ad +vA +vA +vA +ad +vA +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(167,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(168,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(169,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(170,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +sq +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(171,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(172,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +zw +ad +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(173,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(174,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(175,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(176,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(177,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(178,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +cw +zw +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(179,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +vA +vA +vA +vA +cw +vA +vA +vA +vA +cw +vA +vA +vA +vA +vA +vA +vA +vA +vA +cw +cw +cw +cw +cw +UM +vA +ad +ad +ad +vA +vA +vA +ad +zS +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(180,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(181,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(182,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(183,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(184,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(185,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +ab +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(186,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(187,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +UM +ad +ad +vA +ad +vA +vA +vA +ad +vA +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(188,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +UM +vA +ad +vA +ad +vA +vA +vA +ad +TX +UM +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(189,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +vA +ad +vA +vA +vA +ad +vA +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(190,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +vA +ad +vA +vA +vA +ad +vA +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(191,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +vA +ad +vA +vA +vA +ad +vA +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(192,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +vA +rZ +fF +cw +fF +rZ +vA +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(193,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +Hw +Hw +hd +cw +fW +Hw +Hw +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(194,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ad +Hw +cw +cw +cw +cw +cw +Hw +ad +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(195,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Hw +uW +cw +cw +cw +fW +Hw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(196,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Hw +cw +cw +qj +cw +cw +Hw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(197,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Hw +Hw +hd +cw +fW +Hw +Hw +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(198,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +Xm +Hw +Hw +cw +Hw +Hw +Pq +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(199,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +aa +vA +fF +vA +aa +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(200,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(201,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(202,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(203,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(204,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(205,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(206,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(207,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(208,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(209,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(210,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(211,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(212,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(213,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(214,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(215,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(216,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(217,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(218,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(219,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(220,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(221,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(222,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(223,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(224,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(225,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(226,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(227,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(228,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(229,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(230,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(231,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(232,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(233,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(234,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(235,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(236,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(237,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(238,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(239,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(240,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(241,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(242,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +ab +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(243,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(244,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(245,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(246,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(247,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(248,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(249,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(250,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(251,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(252,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(253,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(254,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} +(255,1,1) = {" +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +vA +"} diff --git a/maps/ministation/ministation-3.dmm b/maps/ministation/ministation-3.dmm new file mode 100644 index 000000000000..0ffc162ec9aa --- /dev/null +++ b/maps/ministation/ministation-3.dmm @@ -0,0 +1,66039 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/obj/abstract/landmark{ + name = "carpspawn" + }, +/turf/space, +/area/space) +"af" = ( +/turf/wall/natural/random/ministation, +/area/space) +"aF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"aV" = ( +/obj/machinery/atmospherics/binary/pump/on{ + target_pressure = 200; + dir = 4 + }, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"cw" = ( +/turf/floor/reinforced/airless, +/area/space) +"dp" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, +/obj/structure/cable, +/turf/floor/plating, +/area/ministation/maint/l4central) +"dH" = ( +/turf/floor/plating, +/area/space) +"es" = ( +/obj/machinery/light/small, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/sign/warning/airlock{ + pixel_y = 26 + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"gu" = ( +/turf/floor/plating, +/area/ministation/maint/l4central) +"hx" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/tracker, +/turf/floor/plating, +/area/space) +"hC" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/space) +"jq" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"kH" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"kV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"ld" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"mI" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"nf" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/space) +"nY" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"oZ" = ( +/obj/structure/lattice, +/obj/item/stack/cable_coil, +/turf/space, +/area/space) +"rw" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/plating, +/area/space) +"rB" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 20 + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"sD" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"tN" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/plating, +/area/ministation/maint/l4overpass) +"ug" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "roof_airlock_exterior" + }, +/obj/machinery/button/access/interior{ + id_tag = "roof_airlock"; + name = "exterior access button"; + pixel_x = -20; + pixel_y = 10; + command = "cycle_exterior" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating/airless, +/area/ministation/maint/l4central) +"uG" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"uQ" = ( +/turf/floor/plating, +/area/ministation/maint/l4overpass) +"vm" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"vD" = ( +/obj/machinery/power/solar_control{ + dir = 8 + }, +/obj/structure/cable, +/turf/floor/plating, +/area/ministation/maint/l4central) +"wi" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/space) +"xN" = ( +/obj/abstract/map_data{ + height = 4 + }, +/turf/space, +/area/space) +"xZ" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/space) +"yS" = ( +/obj/abstract/landmark{ + name = "bluespace_a" + }, +/turf/space, +/area/space) +"yX" = ( +/turf/wall, +/area/ministation/maint/l4overpass) +"zd" = ( +/obj/structure/ladder, +/obj/structure/lattice, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open, +/area/ministation/maint/l4overpass) +"Aj" = ( +/obj/structure/cable, +/turf/floor/plating, +/area/space) +"AT" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/solar, +/turf/floor/plating, +/area/space) +"Cd" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/maintenance, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"Cl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/space) +"Cu" = ( +/obj/structure/ladder, +/obj/structure/lattice, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/open, +/area/ministation/maint/l4overpass) +"CJ" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/solar, +/turf/floor/plating/airless, +/area/space) +"Dc" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"DX" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/space) +"Ed" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"Fa" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/plating, +/area/ministation/maint/l4overpass) +"GD" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + req_access = list("ACCESS_EXTERNAL"); + locked = 1; + id_tag = "roof_airlock_interior" + }, +/obj/machinery/button/access/interior{ + id_tag = "roof_airlock"; + name = "interior access button"; + pixel_x = 20; + pixel_y = -10; + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"Hs" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"HM" = ( +/obj/machinery/network/relay{ + initial_network_id = "molluscnet" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"IZ" = ( +/obj/machinery/power/solar, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/plating, +/area/space) +"Lu" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/solar, +/turf/floor/plating/airless, +/area/space) +"Lx" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/space) +"MF" = ( +/obj/machinery/power/solar, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/space) +"Np" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"Nz" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = 5; + pixel_y = 30 + }, +/obj/effect/floor_decal/industrial/hatch/red, +/turf/floor/plating, +/area/ministation/maint/l4central) +"NO" = ( +/obj/abstract/level_data_spawner/main_level, +/turf/space, +/area/space) +"SJ" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"Uw" = ( +/obj/structure/lattice, +/obj/structure/ladder, +/obj/structure/cable{ + icon_state = "32-4" + }, +/obj/machinery/atmospherics/pipe/zpipe/down/supply{ + dir = 4 + }, +/turf/open, +/area/ministation/maint/l4central) +"VO" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"Wi" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/plating, +/area/space) +"Wl" = ( +/obj/machinery/power/smes/buildable/preset, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"XA" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "roof_vent" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "roof_airlock"; + pixel_y = null; + tag_airpump = "roof_vent"; + tag_chamber_sensor = "roof_sensor"; + tag_exterior_door = "roof_airlock_exterior"; + tag_interior_door = "roof_airlock_interior"; + dir = 4; + pixel_x = -20 + }, +/obj/machinery/airlock_sensor{ + id_tag = "roof_sensor"; + pixel_y = 10; + pixel_x = -20 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ministation/maint/l4central) +"Yv" = ( +/turf/wall, +/area/ministation/maint/l4central) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +NO +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +af +af +af +af +aa +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +af +aa +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +af +af +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +ab +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +yS +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +af +af +af +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +af +af +af +af +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +af +af +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +hx +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +Cl +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uG +uG +uG +uG +Cl +uG +uG +uG +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Lu +Lu +Lu +Lu +Lu +AT +AT +aa +wi +aa +AT +AT +Lu +Lu +Lu +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +xZ +mI +mI +mI +mI +mI +mI +Aj +dH +rw +Lx +Lx +Lx +Lx +hC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +CJ +CJ +CJ +CJ +CJ +CJ +CJ +aa +dH +aa +CJ +CJ +CJ +CJ +CJ +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uG +aa +aa +aa +dH +aa +aa +aa +uG +aa +aa +uG +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Lu +Lu +Lu +Lu +Lu +Lu +Lu +aa +dH +aa +Lu +Lu +Lu +Lu +Lu +uG +uG +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +xZ +mI +mI +mI +mI +mI +mI +Aj +dH +rw +Lx +Lx +Lx +Lx +hC +aa +uG +uG +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +CJ +CJ +CJ +CJ +CJ +CJ +CJ +aa +dH +aa +CJ +CJ +CJ +CJ +CJ +cw +aa +uG +uG +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +uG +aa +aa +aa +dH +aa +aa +aa +uG +cw +cw +cw +aa +Yv +Yv +Yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +IZ +IZ +IZ +IZ +IZ +IZ +IZ +aa +dH +aa +IZ +IZ +IZ +IZ +IZ +cw +aa +Yv +Uw +Yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +aa +SJ +Wi +vm +Wi +Wi +Wi +Wi +Aj +dH +rw +Ed +Ed +Ed +Ed +DX +cw +aa +Yv +es +Yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +aa +MF +MF +MF +MF +MF +MF +MF +aa +dH +aa +MF +MF +MF +MF +MF +cw +cw +Yv +Cd +Yv +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +uG +aa +aa +aa +dH +aa +uG +aa +cw +cw +cw +cw +Yv +Yv +kV +Yv +Yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +Lu +Lu +Lu +Lu +Lu +Lu +Lu +aa +dH +aa +uG +aa +cw +cw +cw +cw +Yv +rB +aF +jq +Yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +xN +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +xZ +mI +mI +mI +mI +mI +mI +Aj +nf +aa +oZ +aa +cw +cw +cw +Yv +Yv +Yv +aV +Np +Yv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +CJ +CJ +CJ +CJ +CJ +CJ +CJ +aa +Hs +nY +nY +nY +nY +nY +nY +ug +XA +GD +sD +Dc +Yv +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +yX +yX +aa +aa +aa +aa +aa +uG +aa +aa +aa +dH +aa +cw +cw +cw +cw +cw +Yv +Yv +Yv +Nz +Wl +Yv +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +af +af +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +Cu +yX +aa +aa +aa +aa +aa +uG +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +Yv +gu +VO +dp +Yv +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +Yv +HM +ld +vD +Yv +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +Yv +Yv +Yv +Yv +Yv +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +tN +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(129,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(130,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(131,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(132,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(133,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +cw +cw +cw +yX +tN +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(134,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +cw +cw +cw +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(135,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +aa +cw +cw +cw +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(136,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +yX +yX +yX +yX +yX +yX +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(137,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +yX +zd +uQ +Fa +uQ +uQ +uQ +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(138,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +yX +yX +yX +yX +yX +yX +yX +yX +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(139,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(140,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(141,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(142,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(143,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(144,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(145,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(146,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(147,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(148,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(149,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(150,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(151,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(152,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(153,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(154,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(155,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(156,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +kH +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(157,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(158,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(159,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(160,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(161,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(162,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(163,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(164,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(165,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(166,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(167,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(168,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(169,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(170,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(171,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(172,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(173,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(174,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(175,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(176,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(177,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(178,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(179,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(180,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(181,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(182,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(183,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(184,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(185,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(186,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(187,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(188,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(189,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(190,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(191,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(192,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(193,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(194,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(195,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(196,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(197,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(198,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +cw +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(199,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(200,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(201,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(202,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(203,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(204,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(205,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(206,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(207,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(208,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(209,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(210,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(211,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(212,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(213,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(214,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(215,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(216,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(217,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(218,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(219,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(220,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(221,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(222,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(223,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(224,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(225,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(226,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(227,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(228,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(229,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(230,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(231,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(232,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(233,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(234,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(235,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(236,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(237,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(238,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(239,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(240,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(241,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(242,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(243,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(244,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(245,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(246,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(247,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(248,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(249,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(250,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(251,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(252,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(253,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(254,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(255,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/ministation/ministation.dm b/maps/ministation/ministation.dm new file mode 100644 index 000000000000..a44a244232b9 --- /dev/null +++ b/maps/ministation/ministation.dm @@ -0,0 +1,116 @@ +/* +Ministation "Zebra" +A butchered variant on Giacom's Ministation designed for 5 to 10 players. +Now poorly imported for Nebula! +And then imported back to ScavStation! +And then copied back upstream to Neb... +Twice... +*/ + +#if !defined(USING_MAP_DATUM) + + #define USING_MAP_DATUM /datum/map/ministation + + #ifdef UNIT_TEST + #include "../../code/unit_tests/offset_tests.dm" + #endif + + #include "../random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm" + + #include "../../mods/content/mundane.dm" + #include "../../mods/content/scaling_descriptors.dm" + + #include "../../mods/content/augments/_augments.dme" + #include "../../mods/content/bigpharma/_bigpharma.dme" + #include "../../mods/content/blob/_blob.dme" + #include "../../mods/content/corporate/_corporate.dme" + #include "../../mods/content/government/_government.dme" + #include "../../mods/content/integrated_electronics/_integrated_electronics.dme" + #include "../../mods/content/matchmaking/_matchmaking.dme" + #include "../../mods/content/modern_earth/_modern_earth.dme" + #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" + #include "../../mods/content/pheromones/_pheromones.dme" + #include "../../mods/content/psionics/_psionics.dme" + #include "../../mods/content/sealant_gun/_sealant_gun.dme" + #include "../../mods/content/standard_jobs/_standard_jobs.dme" + #include "../../mods/content/supermatter/_supermatter.dme" + #include "../../mods/content/ventcrawl/_ventcrawl.dme" + #include "../../mods/content/xenobiology/_xenobiology.dme" + #include "../../mods/content/exploration/_exploration.dme" + + #include "../../mods/gamemodes/cult/_cult.dme" + #include "../../mods/gamemodes/heist/_heist.dme" + #include "../../mods/gamemodes/mercenary/_mercenary.dme" + #include "../../mods/gamemodes/ninja/_ninja.dme" + #include "../../mods/gamemodes/revolution/_revolution.dme" + #include "../../mods/gamemodes/traitor/_traitor.dme" + #include "../../mods/gamemodes/spyvspy/_spyvspy.dme" + #include "../../mods/gamemodes/mixed.dm" + + #include "../../mods/mobs/dionaea/_dionaea.dme" + #include "../../mods/mobs/borers/_borers.dme" + + #include "../../mods/content/beekeeping/_beekeeping.dme" + #include "../../mods/content/tabloids/_tabloids.dme" + #include "../../mods/species/ascent/_ascent.dme" + #include "../../mods/species/tajaran/_tajaran.dme" + #include "../../mods/species/unathi/_unathi.dme" + #include "../../mods/species/skrell/_skrell.dme" + #include "../../mods/species/adherent/_adherent.dme" + #include "../../mods/species/tritonian/_tritonian.dme" + #include "../../mods/species/neoavians/_neoavians.dme" + #include "../../mods/species/serpentid/_serpentid.dme" + + #include "ministation_antagonists.dm" + #include "ministation_areas.dm" + #include "ministation_departments.dm" + #include "ministation_documents.dm" + #include "ministation_jobs.dm" + #include "ministation_shuttles.dm" + #include "ministation_objects.dm" + #include "ministation_unit_testing.dm" + #include "ministation_overrides.dm" + + #include "ministation-0.dmm" + #include "ministation-1.dmm" + #include "ministation-2.dmm" + #include "ministation-3.dmm" + #include "space.dmm" + + #include "../away/bearcat/bearcat.dm" + #include "../away/casino/casino.dm" + #include "../away/derelict/derelict.dm" + #include "../away/errant_pisces/errant_pisces.dm" + #include "../away/lost_supply_base/lost_supply_base.dm" + #include "../away/magshield/magshield.dm" + #include "../away/mining/mining.dm" + #include "../away/mobius_rift/mobius_rift.dm" + #include "../away/smugglers/smugglers.dm" + #include "../away/unishi/unishi.dm" + #include "../away/yacht/yacht.dm" + #include "../away/liberia/liberia.dm" + + #include "ministation_overmap.dm" + + #include "jobs/command.dm" + #include "jobs/civilian.dm" + #include "jobs/engineering.dm" + #include "jobs/medical.dm" + #include "jobs/security.dm" + #include "jobs/science.dm" + #include "jobs/tradehouse.dm" + + #include "outfits/_outfits.dm" + #include "outfits/command.dm" + #include "outfits/civilian.dm" + #include "outfits/engineering.dm" + #include "outfits/medical.dm" + #include "outfits/science.dm" + #include "outfits/security.dm" + #include "outfits/tradehouse.dm" + +#elif !defined(MAP_OVERRIDE) + + #warn A map has already been included, ignoring ministation. + +#endif \ No newline at end of file diff --git a/maps/ministation/ministation_antagonists.dm b/maps/ministation/ministation_antagonists.dm new file mode 100644 index 000000000000..c924733529f6 --- /dev/null +++ b/maps/ministation/ministation_antagonists.dm @@ -0,0 +1,51 @@ +/decl/special_role + initial_spawn_req = 1 + initial_spawn_target = 1 + +/decl/special_role/mercenary + initial_spawn_req = 1 + initial_spawn_target = 2 + +/decl/special_role/raider + initial_spawn_req = 1 + initial_spawn_target = 2 + +/decl/special_role/cultist + initial_spawn_req = 1 + initial_spawn_target = 2 + +/decl/special_role/renegade + initial_spawn_req = 1 + initial_spawn_target = 2 + +/decl/special_role/loyalist + initial_spawn_req = 1 + initial_spawn_target = 2 + command_department_id = /decl/department/command + +/decl/special_role/revolutionary + initial_spawn_req = 1 + initial_spawn_target = 2 + command_department_id = /decl/department/command + +/datum/map/ministation + potential_theft_targets = list( + "an owl mask" = /obj/item/clothing/mask/gas/owl_mask, + "a toy ripley" = /obj/item/toy/prize/powerloader, + "a collectable top hat" = /obj/item/clothing/head/collectable/tophat, + "a jetpack" = /obj/item/tank/jetpack, + "a captain's jumpsuit" = /obj/item/clothing/jumpsuit/captain, + "a pair of magboots" = /obj/item/clothing/shoes/magboots, + "the master blueprints" = /obj/item/blueprints, + "a sample of slime extract" = /obj/item/slime_extract, + "a piece of corgi meat" = /obj/item/food/butchery/meat/corgi, + "the hypospray" = /obj/item/chems/hypospray, + "the captain's pinpointer" = /obj/item/pinpointer, + "the championship belt" = /obj/item/belt/champion, + "the tradehouse account documents" = /obj/item/documents/tradehouse/account, + "the tradehouse personnel data" = /obj/item/documents/tradehouse/personnel, + "the table-top spaceship model" = /obj/item/toy/shipmodel, + "the AI intelliCard" = /obj/item/aicard, + "the nuclear authentication disk" = /obj/item/disk/nuclear, + "the officer's sword" = /obj/item/sword/replica/officersword + ) \ No newline at end of file diff --git a/maps/ministation/ministation_areas.dm b/maps/ministation/ministation_areas.dm new file mode 100644 index 000000000000..b9da56005930 --- /dev/null +++ b/maps/ministation/ministation_areas.dm @@ -0,0 +1,346 @@ +/datum/event/prison_break/medical + areaType = list(/area/ministation/medical) + +/datum/event/prison_break/science + areaType = list(/area/ministation/science) + +/datum/event/prison_break/station + areaType = list(/area/ministation/security) + +/area/ministation + name = "\improper Ministation" + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') + icon = 'maps/ministation/ministation_areas.dmi' + icon_state = "default" + holomap_color = HOLOMAP_AREACOLOR_CREW + +/area/ministation/supply_dock + name = "Supply Shuttle Dock" + icon_state = "yellow" + base_turf = /turf/space + holomap_color = HOLOMAP_AREACOLOR_CARGO + +/area/ministation/supply + name = "Supply Shuttle" + icon_state = "shuttle3" + req_access = list(access_cargo) + requires_power = 0 + holomap_color = HOLOMAP_AREACOLOR_CARGO + +//Hallways +/area/ministation/hall + icon_state = "white" + area_flags = AREA_FLAG_HALLWAY + holomap_color = HOLOMAP_AREACOLOR_HALLWAYS + +/area/ministation/hall/n + name = "\improper Forward Hallway" + +// first floor hallways + +/area/ministation/hall/s1 + name = "\improper L1 Aft Hallway" + +// second floor hallways + +/area/ministation/hall/w2 + name = "\improper L2 Port Hallway" + +/area/ministation/hall/e2 + name = "\improper L2 Starboard Hallway" + +// third floor hallways + +/area/ministation/hall/s3 + name = "\improper L3 Aft Hallway" + +/area/ministation/hall/n3 + name = "\improper L3 Forward Hallway" + +//Maintenance +/area/ministation/maint + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_MAINTENANCE + req_access = list(access_maint_tunnels) + turf_initializer = /decl/turf_initializer/maintenance + icon_state = "orange" + secure = TRUE + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE + +// First floor maint + +/area/ministation/maint/westatmos + name = "\improper West Atmos Maintenance" + +/area/ministation/maint/eastatmos + name = "\improper East Atmos Maintenance" + +// /area/ministation/maint/l1nw +// name = "\improper Level One North West Maintenance" + +/area/ministation/maint/l1ne + name = "\improper Level One North East Maintenance" + +/area/ministation/maint/l1central + name = "\improper Level One Central Maintenance" + +// Second Floor Maint + +/area/ministation/maint/l2centraln + name = "\improper Level Two Central North Maintenance" + +/area/ministation/maint/l2centrals + name = "\improper Level Two Central South Maintenance" + +/area/ministation/maint/secmaint + name = "\improper Security Maintenance" + +/area/ministation/maint/hydromaint + name = "\improper Hydro Maintenance" + +/area/ministation/maint/l2underpass + name = "\improper Level Two Maintenance Underpass" + +// Third Floor Maint + +/area/ministation/maint/l3nw + name = "\improper Level Three Northwest Maintenance" + +/area/ministation/maint/l3ne + name = "\improper Level Three Northeast Maintenance" + +/area/ministation/maint/l3central + name = "\improper Level Three Central Maintenance" + +/area/ministation/maint/l3sw + name = "\improper Level Three Southwest Maintenance" + +/area/ministation/maint/l3se + name = "\improper Level Three Southeast Maintenance" + +// Fourth Floor Maint +/area/ministation/maint/l4central + name = "\improper Level Four Central Maintenance" + +/area/ministation/maint/l4overpass + name = "\improper Level Four Maintenance Overpass" + +//Maint Bypasses + +/area/ministation/maint/sebypass + name = "\improper Southeast Maintenance Shaft" + +/area/ministation/maint/nebypass + name = "\improper Northeast Maintenance Shaft" + +//Departments +/area/ministation/hop + name = "\improper Lieutenant's Office" + req_access = list(access_hop) + secure = TRUE + icon_state = "dark_blue" + +/area/ministation/janitor + name = "\improper Custodial Closet" + req_access = list(access_janitor) + icon_state = "janitor" + +/area/ministation/trash + name = "\improper Trash Room" + req_access = list(access_janitor) + icon_state = "janitor" + +/area/ministation/cargo + name = "\improper Cargo Bay" + req_access = list(access_mining) + icon_state = "brown" + secure = TRUE + holomap_color = HOLOMAP_AREACOLOR_CARGO + +/area/ministation/mining + name = "\improper Mineral Processing" + req_access = list(access_mining) + icon_state = "mining_production" + secure = TRUE + +/area/ministation/bridge + name = "\improper Bridge" + req_access = list(access_heads) + secure = TRUE + icon_state = "dark_blue" + holomap_color = HOLOMAP_AREACOLOR_SECURITY + +/area/ministation/bridge/vault + name = "\improper Vault" + req_access = list(access_heads_vault) + ambience = list() + icon_state = "green" + +/area/ministation/security + name = "\improper Security Office" + req_access = list(access_security) + secure = TRUE + icon_state = "red" + area_flags = AREA_FLAG_SECURITY + +/area/ministation/detective + name = "\improper Detective Office" + req_access = list(access_forensics_lockers) + secure = TRUE + icon_state = "dark_blue" + +/area/ministation/court + name = "\improper Court Room" + req_access =list(access_lawyer) + secure = TRUE + icon_state = "pink" + +/area/ministation/library + name = "\improper Library" + icon_state = "LIB" + +/area/ministation/atmospherics + name = "\improper Atmospherics" + req_access = list(access_atmospherics) + icon_state = "ATMOS" + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +/area/ministation/science + name = "\improper Research & Development Laboratory" + req_access = list(access_robotics) + secure = TRUE + icon_state = "purple" + +/area/ministation/eva + name = "\improper EVA Storage" + req_access = list(access_eva) + secure = TRUE + icon_state = "dark_blue" + +/area/ministation/medical + name = "\improper Infirmary" + req_access = list(access_medical) + icon_state = "light_blue" + secure = TRUE + holomap_color = HOLOMAP_AREACOLOR_MEDICAL + +/area/ministation/cryo + name = "\improper Medical Cryogenics" + req_access = list() + icon_state = "green" + secure = FALSE + +/area/ministation/dorms + name = "\improper Dormatories" + req_access = list() + icon_state = "red" + secure = FALSE + +/area/ministation/hydro + name = "\improper Hydroponics" + req_access = list(access_hydroponics) + icon_state = "green" + +/area/ministation/cafe // no access requirement to get in. inner doors need access kitchen + name = "\improper Cafeteria" + icon_state = "red" + secure = TRUE + +/area/ministation/engine + name = "Engineering" + req_access = list(access_engine_equip) + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + secure = TRUE + icon_state = "yellow" + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +/area/ministation/supermatter + name = "\improper Supermatter Engine" + req_access = list(access_engine) + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + secure = TRUE + icon_state = "brown" + +/area/ministation/smcontrol + name = "\improper Supermatter Control" + req_access = list(access_engine) + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') + secure = TRUE + icon_state = "red" + +/area/ministation/telecomms + name = "\improper Telecommunications Control" + req_access = list(list(access_engine),list(access_heads)) //can get inside to monitor but not actually access anything important. Inner doors have tcomm access + ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/signal.ogg','sound/ambience/sonar.ogg') + secure = TRUE + icon_state = "light_blue" + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING + +/area/ministation/tradehouse_rep + name = "\improper Tradehouse Representative Chamber" + req_access = list(access_lawyer) + icon_state = "brown" + +/area/ministation/arrival + name = "\improper Arrival Shuttle" // I hate this ugly thing + icon_state = "white" + requires_power = 0 + +/area/ministation/shuttle/outgoing + name = "\improper Science Shuttle" + icon_state = "shuttle" + +//satellite +/area/ministation/ai_sat + name = "\improper Satellite" + secure = TRUE + turf_initializer = /decl/turf_initializer/maintenance + icon_state = "brown" + +/area/ministation/ai_core + name = "\improper AI Core" + req_access = list(access_ai_upload) + secure = TRUE + icon_state = "green" + +/area/ministation/ai_upload + name = "\improper AI Upload Control" + secure = TRUE + req_access = list(access_ai_upload) + icon_state = "light_blue" + +/area/shuttle/escape_shuttle + name = "\improper Emergency Shuttle" + icon_state = "shuttle" + +//Elevator + +/area/turbolift + name = "\improper Elevator" + icon_state = "shuttle" + requires_power = 0 + dynamic_lighting = TRUE + sound_env = STANDARD_STATION + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED + ambience = list( + 'sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg' + ) + + arrival_sound = null + lift_announce_str = null + +/area/turbolift/alert_on_fall(var/mob/living/human/H) + if(H.client && SSpersistence.elevator_fall_shifts > 0) + SSwebhooks.send(WEBHOOK_ELEVATOR_FALL, list("text" = "We managed to make it [SSpersistence.elevator_fall_shifts] shift\s without someone falling down an elevator shaft.")) + SSpersistence.elevator_fall_shifts = -1 + +/area/turbolift/l1 + name = "Station Level 1" + base_turf = /turf/floor/plating + +/area/turbolift/l2 + name = "Station Level 2" + base_turf = /turf/open + +/area/turbolift/l3 + name = "Station Level 3" + base_turf = /turf/open \ No newline at end of file diff --git a/maps/ministation/ministation_areas.dmi b/maps/ministation/ministation_areas.dmi new file mode 100644 index 000000000000..e4389c0e3bd2 Binary files /dev/null and b/maps/ministation/ministation_areas.dmi differ diff --git a/maps/ministation/ministation_define.dm b/maps/ministation/ministation_define.dm new file mode 100644 index 000000000000..b47a6b470241 --- /dev/null +++ b/maps/ministation/ministation_define.dm @@ -0,0 +1,69 @@ +/datum/map/ministation + name = "Ministation" + full_name = "Tradepost Zebra" + path = "ministation" + ground_noun = "floor" + + station_name = "Tradepost Zebra" + station_short = "Zebra" + + dock_name = "Salvia Station" + boss_name = "Trademaster" + boss_short = "Admin" + company_name = "Tradehouse Administration" + company_short = "Admin" + + lobby_screens = list('maps/ministation/ministation_lobby.png') + + overmap_ids = list(OVERMAP_ID_SPACE) + num_exoplanets = 3 + away_site_budget = 3 + lobby_tracks = list( + /decl/music_track/absconditus, + /decl/music_track/level3_mod + ) + + shuttle_docked_message = "The public ferry to %dock_name% has docked with the station. It will depart in approximately %ETD%" + shuttle_leaving_dock = "The public ferry has left the station. Estimate %ETA% until the ferry docks at %dock_name%." + shuttle_called_message = "A public ferry to %dock_name% has been scheduled. It will arrive in approximately %ETA%" + shuttle_recall_message = "The scheduled ferry has been cancelled." + + emergency_shuttle_docked_message = "The emergency shuttle has docked with the station. You have approximately %ETD% to board the emergency shuttle." + emergency_shuttle_leaving_dock = "The emergency shuttle has left the station. Estimate %ETA% until the shuttle docks at %dock_name%." + emergency_shuttle_called_message = "An emergency evacuation shuttle has been called. It will arrive in approximately %ETA%." + emergency_shuttle_called_sound = 'sound/AI/shuttlecalled.ogg' + + emergency_shuttle_recall_message = "The emergency shuttle has been recalled." + + evac_controller_type = /datum/evacuation_controller/shuttle + + pray_reward_type = /obj/item/mollusc/clam + + starting_money = 5000 + department_money = 1000 + salary_modifier = 0.2 + + radiation_detected_message = "High levels of radiation have been detected in proximity of the %STATION_NAME%. Station wide maintenance access has been granted. Please take shelter within the nearest maintenance tunnel." + + allowed_latejoin_spawns = list( + /decl/spawnpoint/arrivals, + /decl/spawnpoint/cryo + ) + default_spawn = /decl/spawnpoint/arrivals + + default_telecomms_channels = list( + list("name" = "Science", "key" = "n", "frequency" = 1351, "color" = COMMS_COLOR_SCIENCE, "span_class" = "sciradio", "secured" = list(access_research)), + list("name" = "Medical", "key" = "m", "frequency" = 1355, "color" = COMMS_COLOR_MEDICAL, "span_class" = "medradio", "secured" = list(access_medical)), + list("name" = "Supply", "key" = "u", "frequency" = 1347, "color" = COMMS_COLOR_SUPPLY, "span_class" = "supradio", "secured" = list(access_cargo)), + list("name" = "Service", "key" = "v", "frequency" = 1349, "color" = COMMS_COLOR_SERVICE, "span_class" = "srvradio", "secured" = list(access_bar)), + COMMON_FREQUENCY_DATA, + list("name" = "AI Private", "key" = "p", "frequency" = 1343, "color" = COMMS_COLOR_AI, "span_class" = "airadio", "secured" = list(access_ai_upload)), + list("name" = "Entertainment", "key" = "z", "frequency" = 1461, "color" = COMMS_COLOR_ENTERTAIN, "span_class" = CSS_CLASS_RADIO, "receive_only" = TRUE), + list("name" = "Command", "key" = "c", "frequency" = 1353, "color" = COMMS_COLOR_COMMAND, "span_class" = "comradio", "secured" = list(access_bridge)), + list("name" = "Engineering", "key" = "e", "frequency" = 1357, "color" = COMMS_COLOR_ENGINEER, "span_class" = "engradio", "secured" = list(access_engine)), + list("name" = "Security", "key" = "s", "frequency" = 1359, "color" = COMMS_COLOR_SECURITY, "span_class" = "secradio", "secured" = list(access_security)) + ) + +/datum/map/ministation/get_map_info() + return "You're aboard the [station_name], an older station once used for unethical economic research. It has long since been repurposed as deep space communication relay, though only on paper. \ + Onboard activity is at the whims of the [boss_name] who treat the station as a dumping ground for less desired tradehouse personnel." \ No newline at end of file diff --git a/maps/ministation/ministation_departments.dm b/maps/ministation/ministation_departments.dm new file mode 100644 index 000000000000..206042093ee9 --- /dev/null +++ b/maps/ministation/ministation_departments.dm @@ -0,0 +1,6 @@ +/decl/department/tradehouse + name = "Tradehouse" + announce_channel = "Tradehouse" + colour = "#b98f03" + display_priority = 4 + display_color = "#ffddf0" diff --git a/maps/ministation/ministation_documents.dm b/maps/ministation/ministation_documents.dm new file mode 100644 index 000000000000..ff1d8d99b41f --- /dev/null +++ b/maps/ministation/ministation_documents.dm @@ -0,0 +1,9 @@ +/obj/item/documents/tradehouse/account + name = "tradehouse accounting documents" + desc = "These contain exhaustive information about tradehouse dealings, with up-to-date information regarding wealth and resources controlled by the house." + description_antag = "In the wrong hands, the house could certainly find itself disavantaged in dealings in the future." + +/obj/item/documents/tradehouse/personnel + name = "tradehouse personnel data" + desc = "Tradehouse interests are furthered by those who serve the house. A good house must know all who work for it." + description_antag = "An enemy of the house could use this to figure out where personnel live and who among them might be a problem to them." diff --git a/maps/ministation/ministation_jobs.dm b/maps/ministation/ministation_jobs.dm new file mode 100644 index 000000000000..17bb28b7b9e8 --- /dev/null +++ b/maps/ministation/ministation_jobs.dm @@ -0,0 +1,24 @@ +/datum/map/ministation + default_job_type = /datum/job/standard/assistant/ministation + default_department_type = /decl/department/civilian + allowed_jobs = list( + /datum/job/standard/assistant/ministation, + /datum/job/standard/bartender/ministation, + /datum/job/standard/captain/ministation, + /datum/job/standard/cargo_tech/ministation, + /datum/job/standard/robot, + /datum/job/standard/computer, + /datum/job/standard/detective/ministation, + /datum/job/standard/doctor/ministation, + /datum/job/standard/cmo/ministation, + /datum/job/standard/engineer/ministation, + /datum/job/standard/chief_engineer/ministation, + /datum/job/standard/hop/ministation, + /datum/job/standard/janitor/ministation, + /datum/job/standard/scientist/ministation, + /datum/job/standard/rd/ministation, + /datum/job/standard/officer/ministation, + /datum/job/standard/hos/ministation, + /datum/job/standard/librarian/ministation, + /datum/job/tradehouse_rep + ) \ No newline at end of file diff --git a/maps/ministation/ministation_lobby.png b/maps/ministation/ministation_lobby.png new file mode 100644 index 000000000000..1b8bf821b7df Binary files /dev/null and b/maps/ministation/ministation_lobby.png differ diff --git a/maps/ministation/ministation_objects.dm b/maps/ministation/ministation_objects.dm new file mode 100644 index 000000000000..75f53e798707 --- /dev/null +++ b/maps/ministation/ministation_objects.dm @@ -0,0 +1,81 @@ +/turf/wall/natural/random/ministation + initial_gas = null + floor_type = /turf/floor/barren/airless + +/turf/floor/barren/airless + initial_gas = null + +/turf/wall/natural/random/ministation/get_weighted_mineral_list() + if(prob(80)) + . = list() + else if(prob(75)) + if(strata_override) + var/decl/strata/strata_info = GET_DECL(strata_override) + . = strata_info.ores_sparse + if(!.) + . = SSmaterials.weighted_minerals_sparse + else + if(strata_override) + var/decl/strata/strata_info = GET_DECL(strata_override) + . = strata_info.ores_rich + if(!.) + . = SSmaterials.weighted_minerals_rich + +//trash bins +/decl/closet_appearance/crate/ministation + decals = null + extra_decals = null + base_icon = 'maps/ministation/bin.dmi' + decal_icon = 'icons/obj/closets/decals/crate.dmi' + color = COLOR_WHITE + +/obj/structure/closet/crate/bin/ministation + name = "garbage bin" + desc = "A large bin for putting trash in." + icon = 'maps/ministation/bin.dmi' + icon_state = "base" + closet_appearance = /decl/closet_appearance/crate/ministation + storage_types = CLOSET_STORAGE_MOBS | CLOSET_STORAGE_ITEMS + +//suit cyclers +/obj/machinery/suit_cycler/ministation //this one goes in eva + req_access = list() + suit = /obj/item/clothing/suit/space + helmet = /obj/item/clothing/head/helmet/space + +/obj/machinery/suit_cycler/engineering/ministation + suit = /obj/item/clothing/suit/space/void/engineering + helmet = /obj/item/clothing/head/helmet/space/void/engineering + boots = /obj/item/clothing/shoes/magboots + +/obj/machinery/suit_cycler/mining/ministation + suit = /obj/item/clothing/suit/space/void/mining + helmet = /obj/item/clothing/head/helmet/space/void/mining + boots = /obj/item/clothing/shoes/magboots + +/obj/structure/closet/medical_wall/ministation/WillContain() // for common area, has slightly less than normal + return list( + /obj/random/firstaid, + /obj/random/medical/lite = 8) + +/obj/machinery/vending/assist/ministation/Initialize() //vending machines found in maint tunnels + . = ..() + contraband += list(/obj/item/multitool = 1) + +//cameras +/obj/machinery/camera/network/ministation/sat + preset_channels = list("Satellite") + +/obj/machinery/camera/motion/ministation + preset_channels = list("Satellite") + +/obj/machinery/camera/network/command + preset_channels = list("Command") + initial_access = list(access_bridge) + +/obj/machinery/camera/network/hallway + preset_channels = list("Hallway") + +/mob/living/simple_animal/crow/doctor + desc = "She's not a real doctor, but she is a real bird." + name = "Dr. Bird" diff --git a/maps/ministation/ministation_overmap.dm b/maps/ministation/ministation_overmap.dm new file mode 100644 index 000000000000..8c4673f5ffcb --- /dev/null +++ b/maps/ministation/ministation_overmap.dm @@ -0,0 +1,19 @@ +/obj/effect/overmap/visitable/ship/ministation + name = "Tradepost Zebra" + color = "#00ffff" + vessel_mass = 5000 + max_speed = 1/(2 SECONDS) + burn_delay = 2 SECONDS + restricted_area = 30 + sector_flags = OVERMAP_SECTOR_KNOWN|OVERMAP_SECTOR_BASE|OVERMAP_SECTOR_IN_SPACE + + initial_generic_waypoints = list( + "nav_ministation_bridge_north", + "nav_ministation_arrivals_south" + ) + + + //exploration and rescue shuttles can only dock port side, b/c there's only one door. + initial_restricted_waypoints = list( + /datum/shuttle/autodock/overmap/science_shuttle = list("nav_ministation_science_dock_shuttle") + ) diff --git a/maps/ministation/ministation_overrides.dm b/maps/ministation/ministation_overrides.dm new file mode 100644 index 000000000000..709065f74aa6 --- /dev/null +++ b/maps/ministation/ministation_overrides.dm @@ -0,0 +1,14 @@ +/datum/computer_file/program/merchant/ministation + read_access = list() + +/obj/machinery/computer/modular/preset/merchant/ministation + default_software = list( + /datum/computer_file/program/merchant/ministation, + /datum/computer_file/program/email_client, + /datum/computer_file/program/wordprocessor, + /datum/computer_file/program/supply + ) + +// This has to be here rather than ministation_define.dm because it's from a modpack. +/datum/map/ministation + default_law_type = /datum/ai_laws/nanotrasen \ No newline at end of file diff --git a/maps/ministation/ministation_shuttles.dm b/maps/ministation/ministation_shuttles.dm new file mode 100644 index 000000000000..af90fe8838ea --- /dev/null +++ b/maps/ministation/ministation_shuttles.dm @@ -0,0 +1,93 @@ +//supply +/datum/shuttle/autodock/ferry/supply/cargo + name = "Supply" + warmup_time = 10 + location = 1 + dock_target = "supply_shuttle" + shuttle_area = /area/ministation/supply + waypoint_offsite = "nav_cargo_start" + waypoint_station = "nav_cargo_station" + +/obj/effect/shuttle_landmark/supply/start + landmark_tag ="nav_cargo_start" + +/obj/effect/shuttle_landmark/supply/station + landmark_tag = "nav_cargo_station" + docking_controller = "cargo_bay" + base_area = /area/ministation/supply_dock + base_turf = /turf/space + +/datum/shuttle/autodock/ferry/emergency/escape_shuttle + name = "Escape Shuttle" + warmup_time = 10 + location = 1 + dock_target = "shuttle1" + shuttle_area = /area/shuttle/escape_shuttle + waypoint_offsite = "nav_escape_shuttle_start" + waypoint_station = "nav_escape_shuttle_station" + landmark_transition = "nav_escape_shuttle_transit" + +/obj/effect/shuttle_landmark/escape_shuttle/start + landmark_tag = "nav_escape_shuttle_start" + //docking_controller = "centcom_escape_dock" + +/obj/effect/shuttle_landmark/escape_shuttle/transit + landmark_tag = "nav_escape_shuttle_transit" + +/obj/effect/shuttle_landmark/escape_shuttle/station + landmark_tag = "nav_escape_shuttle_station" + docking_controller = "station1" + +/obj/effect/shuttle_landmark/bridge_north + landmark_tag = "nav_ministation_bridge_north" + +/obj/effect/shuttle_landmark/arrivas_south + landmark_tag = "nav_ministation_arrivals_south" + +/obj/machinery/computer/shuttle_control/explore/ministation + name = "science shuttle console" + shuttle_tag = "Science Shuttle" + +/datum/shuttle/autodock/overmap/science_shuttle + name = "Science Shuttle" + shuttle_area = /area/ministation/shuttle/outgoing + dock_target = "science_shuttle" + current_location = "nav_ministation_science_dock_shuttle" + +/obj/effect/shuttle_landmark/science_dock + name = "Tradepost Science Department Docking Arm" + docking_controller = "ministation_science_dock" + landmark_tag = "nav_ministation_science_dock_shuttle" + +/obj/effect/overmap/visitable/ship/landable/science_shuttle + name = "Science Shuttle" + shuttle = "Science Shuttle" + moving_state = "ship_moving" + max_speed = 1/(2 SECONDS) + burn_delay = 1 SECONDS + vessel_mass = 3000 + fore_dir = EAST + skill_needed = SKILL_BASIC + vessel_size = SHIP_SIZE_SMALL + +// Essentially a bare platform that moves up and down. +/obj/abstract/turbolift_spawner/ministation + name = "Tradestation cargo elevator placeholder" +// icon = 'icons/obj/turbolift_preview_nowalls_3x3.dmi' + depth = 3 + lift_size_x = 2 + lift_size_y = 2 + door_type = null + wall_type = null + firedoor_type = null + light_type = null + floor_type = /turf/floor/tiled/steel_grid + button_type = /obj/structure/lift/button/standalone + panel_type = /obj/structure/lift/panel/standalone + areas_to_use = list( + /area/turbolift/l1, + /area/turbolift/l2, + /area/turbolift/l3 + ) + floor_departure_sound = 'sound/effects/lift_heavy_start.ogg' + floor_arrival_sound = 'sound/effects/lift_heavy_stop.ogg' diff --git a/maps/ministation/ministation_unit_testing.dm b/maps/ministation/ministation_unit_testing.dm new file mode 100644 index 000000000000..6918d6da3075 --- /dev/null +++ b/maps/ministation/ministation_unit_testing.dm @@ -0,0 +1,20 @@ +/datum/map/ministation + // Unit test exemptions + apc_test_exempt_areas = list( + /area/space = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, + /area/shuttle/escape_shuttle = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/supply = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/maint = NO_SCRUBBER|NO_VENT, + /area/ministation/bridge/vault = NO_SCRUBBER|NO_VENT, + /area/ministation/supply_dock = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/arrival = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/shuttle/outgoing = NO_SCRUBBER, + /area/ministation/maint/sebypass = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/maint/nebypass = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/maint/l4overpass = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/maint/l2underpass = NO_SCRUBBER|NO_VENT|NO_APC, + /area/turbolift = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ministation/atmospherics = NO_SCRUBBER, + /area/ministation/mining = NO_SCRUBBER|NO_VENT, + ) diff --git a/maps/ministation/outfits/_outfits.dm b/maps/ministation/outfits/_outfits.dm new file mode 100644 index 000000000000..762206a2d576 --- /dev/null +++ b/maps/ministation/outfits/_outfits.dm @@ -0,0 +1,7 @@ +// OUTFITS +/decl/outfit/job/ministation + abstract_type = /decl/outfit/job/ministation + pda_type = /obj/item/modular_computer/pda + pda_slot = slot_l_store_str + l_ear = null + r_ear = null diff --git a/maps/ministation/outfits/civilian.dm b/maps/ministation/outfits/civilian.dm new file mode 100644 index 000000000000..631204576f2e --- /dev/null +++ b/maps/ministation/outfits/civilian.dm @@ -0,0 +1,49 @@ +/decl/outfit/job/ministation/cargo + l_ear = /obj/item/radio/headset/headset_cargo + name = "Ministation - Job - Cargo technician" + uniform = /obj/item/clothing/jumpsuit/cargotech + id_type = /obj/item/card/id/ministation/cargo + pda_type = /obj/item/modular_computer/pda/cargo + backpack_contents = list(/obj/item/crowbar = 1, /obj/item/ore_satchel = 1) + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR + +/decl/outfit/job/ministation/cargo/Initialize() + . = ..() + BACKPACK_OVERRIDE_ENGINEERING + +/decl/outfit/job/ministation/bartender + l_ear = /obj/item/radio/headset/headset_service + name = "Ministation - Job - Bartender" + uniform = /obj/item/clothing/pants/formal/black/outfit + id_type = /obj/item/card/id/ministation/bartender + pda_type = /obj/item/modular_computer/pda + head = /obj/item/clothing/head/chefhat + +/decl/outfit/job/ministation/janitor + l_ear = /obj/item/radio/headset/headset_service + name = "Ministation - Job - Janitor" + uniform = /obj/item/clothing/jumpsuit/janitor + id_type = /obj/item/card/id/ministation/janitor + pda_type = /obj/item/modular_computer/pda + +/decl/outfit/job/ministation/librarian + l_ear = /obj/item/radio/headset/headset_service + name = "Ministation - Job - Librarian" + uniform = /obj/item/clothing/pants/slacks/red/outfit + id_type = /obj/item/card/id/ministation/librarian + pda_type = /obj/item/modular_computer/pda + +//cards +/obj/item/card/id/ministation/cargo + name = "identification card" + desc = "A card issued to cargo staff." + detail_color = COLOR_BROWN + +/obj/item/card/id/ministation/bartender + desc = "A card issued to kitchen staff." + +/obj/item/card/id/ministation/janitor + desc = "A card issued to custodial staff." + +/obj/item/card/id/ministation/librarian + desc = "A card issued to the station librarian." diff --git a/maps/ministation/outfits/command.dm b/maps/ministation/outfits/command.dm new file mode 100644 index 000000000000..4ac5c896f09e --- /dev/null +++ b/maps/ministation/outfits/command.dm @@ -0,0 +1,39 @@ +/decl/outfit/job/ministation/captain + name = "Ministation - Job - Captain" + head = /obj/item/clothing/head/caphat + glasses = /obj/item/clothing/glasses/sunglasses + uniform = /obj/item/clothing/jumpsuit/captain + l_ear = /obj/item/radio/headset/heads/captain + shoes = /obj/item/clothing/shoes/color/brown + id_type = /obj/item/card/id/gold + pda_type = /obj/item/modular_computer/pda/heads/captain + +/decl/outfit/job/ministation/captain/Initialize() + . = ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/captain + backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/cap + backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/com + +/decl/outfit/job/ministation/captain/post_equip(mob/living/wearer) + ..() + if(wearer.get_age() > 20) + // Since we can have something other than the default uniform at this + // point, check if we can actually attach the medal + var/obj/item/clothing/uniform = wearer.get_equipped_item(slot_w_uniform_str) + if(istype(uniform)) + var/obj/item/clothing/medal/gold/medal = new + if(uniform.can_attach_accessory(medal)) + uniform.attach_accessory(null, medal) + else + qdel(medal) + +/decl/outfit/job/ministation/hop + name = "Ministation - Job - Lieutenant" + uniform = /obj/item/clothing/jumpsuit/head_of_personnel + l_ear = /obj/item/radio/headset/heads/hop + shoes = /obj/item/clothing/shoes/color/brown + r_pocket = /obj/item/gun/energy/taser + hands = list(/obj/item/clothing/suit/armor/bulletproof) + id_type = /obj/item/card/id/silver + pda_type = /obj/item/modular_computer/pda/heads/hop + backpack_contents = list(/obj/item/box/ids = 1) diff --git a/maps/ministation/outfits/engineering.dm b/maps/ministation/outfits/engineering.dm new file mode 100644 index 000000000000..b6758fcd31bc --- /dev/null +++ b/maps/ministation/outfits/engineering.dm @@ -0,0 +1,35 @@ +/decl/outfit/job/ministation/engineer + name = "Job - Station Engineer" + belt = /obj/item/belt/utility/full + l_ear = /obj/item/radio/headset/headset_eng + shoes = /obj/item/clothing/shoes/workboots + pda_slot = slot_l_store_str + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR + head = /obj/item/clothing/head/hardhat + uniform = /obj/item/clothing/jumpsuit/hazard + r_pocket = /obj/item/t_scanner + id_type = /obj/item/card/id/ministation/engineering + pda_type = /obj/item/modular_computer/pda/engineering + +/decl/outfit/job/ministation/engineer/Initialize() + . = ..() + BACKPACK_OVERRIDE_ENGINEERING + +/obj/item/card/id/ministation/engineering + name = "identification card" + desc = "A card issued to engineering staff." + detail_color = COLOR_SUN + +/decl/outfit/job/ministation/chief_engineer + name = "Job - Head Engineer" + uniform = /obj/item/clothing/jumpsuit/hazard + glasses = /obj/item/clothing/glasses/welding/superior + suit = /obj/item/clothing/suit/hazardvest + gloves = /obj/item/clothing/gloves/thick + shoes = /obj/item/clothing/shoes/workboots + pda_type = /obj/item/modular_computer/pda/heads/ce + hands = list(/obj/item/wrench) + belt = /obj/item/belt/utility/full + id_type = /obj/item/card/id/ministation/engineering + l_ear = /obj/item/radio/headset/heads/ce + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR diff --git a/maps/ministation/outfits/medical.dm b/maps/ministation/outfits/medical.dm new file mode 100644 index 000000000000..756bbf299004 --- /dev/null +++ b/maps/ministation/outfits/medical.dm @@ -0,0 +1,34 @@ +/decl/outfit/job/ministation/doctor/head + name = "Ministation - Job - Head Doctor" + l_ear = /obj/item/radio/headset/heads/cmo + uniform = /obj/item/clothing/pants/slacks/black/outfit/detective + shoes = /obj/item/clothing/shoes/dress + pda_type = /obj/item/modular_computer/pda/medical + pda_slot = slot_l_store_str + r_pocket = /obj/item/chems/hypospray/vial + hands = list(/obj/item/firstaid/adv) + id_type = /obj/item/card/id/ministation/doctor + +/decl/outfit/job/ministation/doctor + l_ear = /obj/item/radio/headset/headset_med + shoes = /obj/item/clothing/shoes/color/white + pda_type = /obj/item/modular_computer/pda/medical + pda_slot = slot_l_store_str + name = "Ministation - Job - Junior Doctor" + uniform = /obj/item/clothing/jumpsuit/medical + hands = list(/obj/item/firstaid/adv) + r_pocket = /obj/item/flashlight/pen + id_type = /obj/item/card/id/ministation/doctor + +/decl/outfit/job/ministation/doctor/Initialize() + . = ..() + BACKPACK_OVERRIDE_MEDICAL + +/decl/outfit/job/ministation/doctor/head/Initialize() + . = ..() + BACKPACK_OVERRIDE_MEDICAL + +/obj/item/card/id/ministation/doctor + name = "identification card" + desc = "A card issued to medical staff." + detail_color = COLOR_PALE_BLUE_GRAY \ No newline at end of file diff --git a/maps/ministation/outfits/science.dm b/maps/ministation/outfits/science.dm new file mode 100644 index 000000000000..c2e2663ef1ac --- /dev/null +++ b/maps/ministation/outfits/science.dm @@ -0,0 +1,24 @@ +/decl/outfit/job/ministation/scientist + l_ear = /obj/item/radio/headset/headset_sci + shoes = /obj/item/clothing/shoes/color/white + pda_type = /obj/item/modular_computer/pda/science + name = "Ministation - Job - Researcher" + uniform = /obj/item/clothing/jumpsuit/white + id_type = /obj/item/card/id/ministation/scientist + +/obj/item/card/id/ministation/scientist + name = "identification card" + desc = "A card issued to science staff." + detail_color = COLOR_PALE_PURPLE_GRAY + +/decl/outfit/job/ministation/scientist/head + name = "Tradeship - Job - Head Researcher" + l_ear = /obj/item/radio/headset/heads/rd + shoes = /obj/item/clothing/shoes/dress + pda_type = /obj/item/modular_computer/pda/science + id_type = /obj/item/card/id/ministation/scientist/head + +/obj/item/card/id/ministation/scientist/head + name = "identification card" + desc = "A card which represents knowledge and reasoning." + extra_details = list("goldstripe") \ No newline at end of file diff --git a/maps/ministation/outfits/security.dm b/maps/ministation/outfits/security.dm new file mode 100644 index 000000000000..03d1a62820de --- /dev/null +++ b/maps/ministation/outfits/security.dm @@ -0,0 +1,70 @@ +/obj/item/modular_computer/pda/security + color = COLOR_DARK_RED + decals = list("stripe" = COLOR_RED_LIGHT) + +/decl/outfit/job/ministation/security + l_ear = /obj/item/radio/headset/headset_sec + glasses = /obj/item/clothing/glasses/sunglasses/sechud + gloves = /obj/item/clothing/gloves/thick + shoes = /obj/item/clothing/shoes/jackboots + backpack_contents = list(/obj/item/handcuffs = 1) + name = "Ministation - Job - Security Officer" + uniform = /obj/item/clothing/jumpsuit/security + l_pocket = /obj/item/flash + r_pocket = /obj/item/handcuffs + id_type = /obj/item/card/id/ministation/security + pda_type = /obj/item/modular_computer/pda/security + +/decl/outfit/job/ministation/security/head + glasses = /obj/item/clothing/glasses/sunglasses/sechud + l_ear = /obj/item/radio/headset/heads/hos + gloves = /obj/item/clothing/gloves/thick + shoes = /obj/item/clothing/shoes/jackboots + backpack_contents = list(/obj/item/handcuffs = 1) + name = "Ministation - Job - Head of Security" + uniform = /obj/item/clothing/jumpsuit/security + l_pocket = /obj/item/flash + r_pocket = /obj/item/handcuffs + id_type = /obj/item/card/id/ministation/security + pda_type = /obj/item/modular_computer/pda/security + +/decl/outfit/job/ministation/security/Initialize() + . = ..() + BACKPACK_OVERRIDE_SECURITY + +/decl/outfit/job/ministation/security/head/Initialize() + . = ..() + BACKPACK_OVERRIDE_SECURITY + +/obj/item/modular_computer/pda/forensics + color = COLOR_DARK_RED + decals = list("stripe" = COLOR_SKY_BLUE) + +/obj/item/modular_computer/pda/forensics/install_default_hardware() + default_hardware |= /obj/item/stock_parts/computer/scanner/reagent + . = ..() + +/decl/outfit/job/ministation/detective + name = "Ministation - Job - Detective" + head = /obj/item/clothing/head/det + glasses = /obj/item/clothing/glasses/sunglasses/sechud + l_ear = /obj/item/radio/headset/headset_sec + uniform = /obj/item/clothing/pants/slacks/outfit/detective + suit = /obj/item/clothing/suit/det_trench + l_pocket = /obj/item/flame/fuelled/lighter/zippo + shoes = /obj/item/clothing/shoes/dress + hands = list(/obj/item/briefcase/crimekit) + id_type = /obj/item/card/id/ministation/security + pda_type = /obj/item/modular_computer/pda/forensics + backpack_contents = list(/obj/item/box/evidence = 1) + gloves = /obj/item/clothing/gloves/thick + +/decl/outfit/job/ministation/detective/Initialize() + . = ..() + backpack_overrides.Cut() + +/obj/item/card/id/ministation/security + name = "identification card" + desc = "A card issued to security staff." + color = COLOR_OFF_WHITE + detail_color = COLOR_MAROON diff --git a/maps/ministation/outfits/tradehouse.dm b/maps/ministation/outfits/tradehouse.dm new file mode 100644 index 000000000000..32b85f4e9041 --- /dev/null +++ b/maps/ministation/outfits/tradehouse.dm @@ -0,0 +1,9 @@ +/decl/outfit/job/ministation/tradehouse + name = "Ministation - Tradehouse Representative" + id_type = /obj/item/card/id/ministation/tradehouse_rep + +/obj/item/card/id/ministation/tradehouse_rep + name = "identification card" + desc = "A card issued to Tradehouse Representatives." + color = COLOR_GOLD + extra_details = list("goldstripe") diff --git a/maps/ministation/space.dmm b/maps/ministation/space.dmm new file mode 100644 index 000000000000..f97b25e1675d --- /dev/null +++ b/maps/ministation/space.dmm @@ -0,0 +1,17107 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/obj/effect/paint/sun, +/turf/wall/r_titanium, +/area/ministation/supply) +"ac" = ( +/turf/floor/shuttle/yellow, +/area/ministation/supply) +"ad" = ( +/obj/effect/shuttle_landmark/supply/start, +/turf/floor/shuttle/yellow, +/area/ministation/supply) +"ae" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "supply_shuttle_hatch"; + name = "Shuttle Hatch"; + use_power = 1 + }, +/turf/floor/plating, +/area/ministation/supply) +"af" = ( +/obj/structure/shuttle/engine/heater, +/obj/structure/window/borosilicate_reinforced{ + icon_state = "rwindow"; + dir = 1 + }, +/turf/floor/shuttle/black, +/area/ministation/supply) +"ag" = ( +/obj/structure/shuttle/engine/propulsion, +/obj/effect/paint/sun, +/turf/wall/r_titanium, +/area/ministation/supply) +"aj" = ( +/obj/effect/paint/silver, +/turf/wall/r_titanium, +/area/shuttle/escape_shuttle) +"ak" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"al" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"am" = ( +/obj/item/music_player/boombox, +/obj/structure/table/steel_reinforced, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"an" = ( +/obj/machinery/computer/shuttle_control/emergency, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"ao" = ( +/obj/structure/chair/shuttle/black{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/obj/machinery/light, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"ap" = ( +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aq" = ( +/obj/structure/chair/shuttle/black{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/obj/machinery/light, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "shuttle1"; + tag_airpump = "shuttle1_vent"; + tag_chamber_sensor = "shuttle1_sensor"; + tag_exterior_door = "shuttle1_airlock_exterior"; + tag_interior_door = "shuttle1_airlock_interior"; + pixel_y = -25; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"ar" = ( +/obj/machinery/door/airlock/command{ + autoset_access = 0; + req_access = list("ACCESS_HEADS") + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"as" = ( +/obj/structure/closet/emcloset, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"at" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + locked = 1; + id_tag = "shuttle1_airlock_exterior" + }, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"au" = ( +/obj/machinery/airlock_sensor{ + id_tag = "shuttle3_sensor"; + pixel_y = -20; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "shuttle1_vent" + }, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"av" = ( +/obj/effect/floor_decal/industrial/traffic{ + icon_state = "stripe"; + dir = 1 + }, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/obj/machinery/light{ + icon_state = "tube_map"; + dir = 8 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aw" = ( +/obj/effect/floor_decal/industrial/traffic{ + icon_state = "stripe"; + dir = 1 + }, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"ax" = ( +/obj/effect/floor_decal/industrial/traffic{ + icon_state = "stripe"; + dir = 5 + }, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"ay" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"az" = ( +/obj/effect/floor_decal/industrial/traffic{ + icon_state = "stripe"; + dir = 4 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aA" = ( +/obj/machinery/sleeper/standard, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aB" = ( +/obj/structure/table/reinforced, +/obj/machinery/sleeper/standard, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aC" = ( +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aD" = ( +/obj/effect/floor_decal/industrial/traffic{ + icon_state = "stripe"; + dir = 4 + }, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aE" = ( +/obj/structure/table/reinforced, +/obj/item/firstaid/adv, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aF" = ( +/obj/structure/table/reinforced, +/obj/structure/bed/roller{ + pixel_y = 10 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aG" = ( +/obj/effect/floor_decal/industrial/traffic, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/obj/machinery/light{ + icon_state = "tube_map"; + dir = 8 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aH" = ( +/obj/effect/floor_decal/industrial/traffic, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aI" = ( +/obj/effect/floor_decal/industrial/traffic{ + icon_state = "stripe"; + dir = 6 + }, +/obj/structure/chair/shuttle{ + icon_state = "shuttle_chair"; + dir = 1 + }, +/obj/effect/shuttle_landmark/escape_shuttle/start, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aJ" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -29; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aK" = ( +/obj/machinery/status_display{ + pixel_y = -30; + dir = 1 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aL" = ( +/obj/machinery/door/airlock, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"aM" = ( +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aN" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = 29 + }, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aO" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aP" = ( +/obj/machinery/computer/modular/preset/security{ + icon_state = "computer"; + dir = 4 + }, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aQ" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/floor/shuttle/red, +/area/shuttle/escape_shuttle) +"aR" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/eastright{ + autoset_access = 0; + req_access = list("ACCESS_BRIG") + }, +/turf/floor/shuttle/red, +/area/shuttle/escape_shuttle) +"aS" = ( +/obj/machinery/oxygen_pump{ + pixel_x = -30 + }, +/turf/floor/shuttle/red, +/area/shuttle/escape_shuttle) +"aT" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/shuttle/escape_shuttle) +"aU" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aV" = ( +/obj/machinery/light, +/obj/structure/table/reinforced, +/obj/machinery/recharger, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aW" = ( +/obj/structure/closet/toolcloset, +/obj/item/screwdriver, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aX" = ( +/obj/structure/closet/crate/plastic/rations, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aY" = ( +/obj/machinery/recharge_station, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"aZ" = ( +/obj/structure/shuttle/engine/heater, +/obj/structure/window/borosilicate_reinforced{ + icon_state = "rwindow"; + dir = 1 + }, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"ba" = ( +/obj/structure/shuttle/engine/propulsion, +/turf/space, +/area/shuttle/escape_shuttle) +"bm" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"fy" = ( +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + locked = 1; + id_tag = "shuttle1_airlock_interior" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"hM" = ( +/obj/machinery/airlock_sensor{ + id_tag = "shuttle2_sensor"; + pixel_y = -20; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "shuttle1_vent" + }, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"lo" = ( +/turf/space/transit/north, +/area/space) +"qu" = ( +/obj/machinery/airlock_sensor{ + id_tag = "shuttle1_sensor"; + pixel_y = -20; + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "shuttle1_vent" + }, +/turf/floor/shuttle/black, +/area/shuttle/escape_shuttle) +"tC" = ( +/turf/wall/shuttle{ + unique_merge_identifier = "ministation_escape" + }, +/area/space) +"AD" = ( +/obj/structure/window/borosilicate_reinforced, +/turf/floor/bluegrid, +/area/ministation/supply) +"AH" = ( +/obj/effect/paint/silver, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/wall/r_titanium, +/area/shuttle/escape_shuttle) +"EW" = ( +/obj/effect/step_trigger/teleporter/random, +/turf/space, +/area/space) +"FN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"Kt" = ( +/obj/structure/window/borosilicate_reinforced, +/obj/structure/showcase{ + desc = "It's actually a possum inside the box piloting the shuttle but don't tell anyone."; + icon_state = "message_server_o_off"; + name = "auto-pilot system" + }, +/turf/floor/bluegrid, +/area/ministation/supply) +"KH" = ( +/obj/machinery/light/small/emergency{ + icon_state = "bulb_map"; + dir = 4 + }, +/turf/floor/shuttle/yellow, +/area/ministation/supply) +"Mu" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 8; + id_tag = "supply_shuttle"; + pixel_x = 32; + tag_door = "supply_shuttle_hatch"; + use_power = 1 + }, +/turf/floor/shuttle/yellow, +/area/ministation/supply) +"MW" = ( +/obj/machinery/atmospherics/pipe/manifold{ + dir = 8 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"Pe" = ( +/obj/abstract/level_data_spawner/admin_level, +/turf/space, +/area/space) +"Qd" = ( +/obj/machinery/atmospherics/pipe/manifold{ + dir = 8 + }, +/turf/floor/shuttle/yellow, +/area/shuttle/escape_shuttle) +"QS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/floor/shuttle/blue, +/area/shuttle/escape_shuttle) +"Ub" = ( +/obj/effect/shuttle_landmark/escape_shuttle/transit, +/turf/space/transit/north, +/area/space) +"UO" = ( +/obj/effect/step_trigger/teleporter/random, +/turf/space/transit/north, +/area/space) + +(1,1,1) = {" +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +Pe +aa +"} +(3,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +tC +tC +tC +tC +tC +tC +tC +tC +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +ab +ab +ab +ab +ab +ab +ab +ab +tC +aa +aa +aa +aa +"} +(8,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +ab +ac +ac +ac +ac +ac +ac +ab +ab +tC +aa +aa +aa +aa +"} +(9,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +AD +ac +ac +ac +ac +ac +ac +af +ag +tC +aa +aa +aa +aa +"} +(10,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +Kt +ac +ac +ad +ac +ac +ac +af +ag +tC +aa +aa +aa +aa +"} +(11,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +AD +ac +ac +ac +ac +ac +ac +af +ag +tC +aa +aa +aa +aa +"} +(12,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +ab +ac +ac +Mu +ac +ac +KH +ab +ab +tC +aa +aa +aa +aa +"} +(13,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +ab +ab +ab +ab +ae +ae +ab +ab +ab +tC +aa +aa +aa +aa +"} +(14,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +tC +tC +tC +tC +tC +tC +tC +tC +tC +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +Ub +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +UO +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +lo +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +UO +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(71,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(72,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(73,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(74,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(75,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(76,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(77,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(78,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(79,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(80,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(81,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(82,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(83,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(84,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(85,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(86,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +aj +aj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(87,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +aj +aj +ak +ak +ak +aj +aj +aj +aj +aj +ak +aj +aj +aj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(88,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +aj +ap +av +ap +aC +ap +aG +ap +aL +aM +aP +aQ +aS +aZ +ba +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(89,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +ak +ak +aj +as +ap +aw +ap +aC +ap +aH +ap +aj +aM +aM +aR +aT +aZ +ba +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(90,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ak +al +ao +aj +as +ap +aw +ap +aC +ap +aH +aJ +aj +aN +aM +aM +aU +aZ +ba +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(91,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ak +am +ap +ar +ap +ap +ax +az +aD +az +aI +aK +aj +aO +aM +aM +aV +aj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(92,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ak +an +aq +aj +ap +QS +ay +FN +FN +FN +ay +MW +AH +Qd +bm +aM +aW +aZ +ba +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(93,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +ak +ak +aj +aj +fy +aj +aA +ap +aE +aj +fy +aj +fy +aj +aM +aX +aZ +ba +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(94,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +aj +qu +aj +aB +ap +aF +aj +hM +aj +au +aj +aM +aY +aZ +ba +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(95,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +at +aj +ak +ak +ak +aj +at +aj +at +aj +ak +aj +aj +aj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(96,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aj +aj +aj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(97,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(98,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(99,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(100,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(101,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(102,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(103,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(104,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(105,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(106,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(107,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(108,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(109,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(110,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(111,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(112,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(113,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(114,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(115,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(116,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(117,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(118,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(119,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(120,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(121,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(122,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(123,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(124,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(125,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(126,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(127,1,1) = {" +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(128,1,1) = {" +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +EW +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/maps/modpack_testing/blank.dmm b/maps/modpack_testing/blank.dmm new file mode 100644 index 000000000000..1096cb7ac606 --- /dev/null +++ b/maps/modpack_testing/blank.dmm @@ -0,0 +1,143 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/space, +/area/space) +"b" = ( +/turf/wall, +/area/space) +"c" = ( +/turf/floor/tiled, +/area/space) +"e" = ( +/obj/abstract/landmark/latejoin, +/turf/floor/tiled, +/area/space) +"R" = ( +/obj/abstract/level_data_spawner/player, +/turf/space, +/area/space) +"X" = ( +/obj/abstract/landmark/latejoin/observer, +/turf/space, +/area/space) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +R +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +a +a +a +a +a +a +a +a +"} +(4,1,1) = {" +a +a +a +a +a +a +X +a +a +a +"} +(5,1,1) = {" +b +b +b +b +b +b +a +a +a +a +"} +(6,1,1) = {" +b +c +c +c +e +b +a +a +a +a +"} +(7,1,1) = {" +b +c +c +c +c +b +a +a +a +a +"} +(8,1,1) = {" +b +c +c +c +c +b +a +a +a +a +"} +(9,1,1) = {" +b +c +c +c +c +b +a +a +a +a +"} +(10,1,1) = {" +b +b +b +b +b +b +a +a +a +a +"} diff --git a/maps/modpack_testing/modpack_testing.dm b/maps/modpack_testing/modpack_testing.dm new file mode 100644 index 000000000000..47b6b1468144 --- /dev/null +++ b/maps/modpack_testing/modpack_testing.dm @@ -0,0 +1,77 @@ +#if !defined(USING_MAP_DATUM) + + #include "modpack_testing_lobby.dm" + #include "blank.dmm" + + #include "../../mods/content/actors.dm" + #include "../../mods/content/mundane.dm" + #include "../../mods/content/scaling_descriptors.dm" + + #include "../../mods/content/augments/_augments.dme" + #include "../../mods/content/beekeeping/_beekeeping.dme" + #include "../../mods/content/bigpharma/_bigpharma.dme" + #include "../../mods/content/biomods/_biomods.dme" + #include "../../mods/content/blacksmithy/_blacksmithy.dme" + #include "../../mods/content/blob/_blob.dme" + #include "../../mods/content/breath_holding/_breath_holding.dme" + #include "../../mods/content/byond_membership/_byond_membership.dm" + #include "../../mods/content/corporate/_corporate.dme" + #include "../../mods/content/dungeon_loot/_dungeon_loot.dme" + #include "../../mods/content/fantasy/_fantasy.dme" + #include "../../mods/content/generic_shuttles/_generic_shuttles.dme" + #include "../../mods/content/government/_government.dme" + #include "../../mods/content/inertia/_inertia.dme" + #include "../../mods/content/integrated_electronics/_integrated_electronics.dme" + #include "../../mods/content/item_sharpening/_item_sharpening.dme" + #include "../../mods/content/matchmaking/_matchmaking.dme" + #include "../../mods/content/modern_earth/_modern_earth.dme" + #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" + #include "../../mods/content/pheromones/_pheromones.dme" + #include "../../mods/content/plant_dissection/_plant_dissection.dme" + #include "../../mods/content/psionics/_psionics.dme" + #include "../../mods/content/response_team/_response_team.dme" + #include "../../mods/content/sealant_gun/_sealant_gun.dme" + #include "../../mods/content/shackles/_shackles.dme" + #include "../../mods/content/standard_jobs/_standard_jobs.dme" + #include "../../mods/content/supermatter/_supermatter.dme" + #include "../../mods/content/tabloids/_tabloids.dme" + #include "../../mods/content/undead/_undead.dme" + #include "../../mods/content/ventcrawl/_ventcrawl.dme" + #include "../../mods/content/xenobiology/_xenobiology.dme" + #include "../../mods/content/exploration/_exploration.dme" + + #include "../../mods/gamemodes/cult/_cult.dme" + #include "../../mods/gamemodes/heist/_heist.dme" + #include "../../mods/gamemodes/meteor/_meteor.dme" + #include "../../mods/gamemodes/mercenary/_mercenary.dme" + #include "../../mods/gamemodes/ninja/_ninja.dme" + #include "../../mods/gamemodes/revolution/_revolution.dme" + #include "../../mods/gamemodes/spyvspy/_spyvspy.dme" + #include "../../mods/gamemodes/traitor/_traitor.dme" + #include "../../mods/gamemodes/mixed.dm" + + #include "../../mods/mobs/borers/_borers.dme" + #include "../../mods/mobs/dionaea/_dionaea.dme" + + #include "../../mods/species/adherent/_adherent.dme" + #include "../../mods/species/ascent/_ascent.dme" + #include "../../mods/species/drakes/_drakes.dme" + #include "../../mods/species/neoavians/_neoavians.dme" + #include "../../mods/species/random_species/_random_species.dme" + #include "../../mods/species/serpentid/_serpentid.dme" + #include "../../mods/species/skrell/_skrell.dme" + #include "../../mods/species/tajaran/_tajaran.dme" + #include "../../mods/species/tritonian/_tritonian.dme" + #include "../../mods/species/unathi/_unathi.dme" + #include "../../mods/species/utility_frames/_utility_frames.dme" + #include "../../mods/species/vox/_vox.dme" + + #include "../../mods/utility/prometheus_metrics/_prometheus_metrics.dme" + + #define USING_MAP_DATUM /datum/map/modpack_testing + +#elif !defined(MAP_OVERRIDE) + + #warn A map has already been included, ignoring Modpack Testing + +#endif diff --git a/maps/modpack_testing/modpack_testing_define.dm b/maps/modpack_testing/modpack_testing_define.dm new file mode 100644 index 000000000000..8ed4837727c9 --- /dev/null +++ b/maps/modpack_testing/modpack_testing_define.dm @@ -0,0 +1,10 @@ +/datum/map/modpack_testing + name = "Modpack Testing" + full_name = "Modpack Testing District" + path = "modpack_testing" + allowed_latejoin_spawns = list() + default_spawn = null + votable = FALSE + +/datum/map/modpack_testing/validate() + return TRUE // Do not check for level lists, this is not a playable map. diff --git a/maps/modpack_testing/modpack_testing_lobby.dm b/maps/modpack_testing/modpack_testing_lobby.dm new file mode 100644 index 000000000000..80ced4e78443 --- /dev/null +++ b/maps/modpack_testing/modpack_testing_lobby.dm @@ -0,0 +1,2 @@ +/datum/map/modpack_testing + lobby_tracks = list(/decl/music_track/absconditus) diff --git a/maps/planets/test_planet/neutralia-1.dmm b/maps/planets/test_planet/neutralia-1.dmm new file mode 100644 index 000000000000..7b96c4c40407 --- /dev/null +++ b/maps/planets/test_planet/neutralia-1.dmm @@ -0,0 +1,16655 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/floor/rock/volcanic, +/area/exoplanet/underground/neutralia/bottom) +"b" = ( +/turf/unsimulated/mineral, +/area/exoplanet/underground/neutralia/bottom) +"c" = ( +/turf/floor/lava, +/area/exoplanet/underground/neutralia/bottom) +"d" = ( +/obj/abstract/level_data_spawner/neutralia/bottom, +/turf/floor/rock/volcanic, +/area/exoplanet/underground/neutralia/bottom) + +(1,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(2,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(3,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(4,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(5,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(6,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(7,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(8,1,1) = {" +b +b +b +b +b +b +b +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +d +b +b +b +b +b +b +b +"} +(9,1,1) = {" +b +b +b +b +b +b +b +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +"} +(10,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(11,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(12,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(13,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(14,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(15,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(16,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(17,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(18,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(19,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(20,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(21,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(22,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(23,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(24,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(25,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(26,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(27,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(28,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(29,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(30,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(31,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(32,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(33,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(34,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(35,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(36,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(37,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(38,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(39,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(40,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(41,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(42,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(43,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(44,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(45,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(46,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(47,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(48,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(49,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(50,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(51,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(52,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(53,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(54,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(55,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(56,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(57,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(58,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(59,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(60,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(61,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(62,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(63,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(64,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(65,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(66,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(67,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(68,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(69,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(70,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(71,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(72,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(73,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(74,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(75,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(76,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(77,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(78,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(79,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(80,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(81,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(82,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(83,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(84,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(85,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(86,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(87,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(88,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(89,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(90,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(91,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(92,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(93,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(94,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(95,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(96,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(97,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(98,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(99,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(100,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(101,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(102,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(103,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(104,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(105,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(106,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(107,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(108,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(109,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(110,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(111,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(112,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(113,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(114,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(115,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(116,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(117,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(118,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(119,1,1) = {" +b +b +b +b +b +b +b +a +a +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +a +a +b +b +b +b +b +b +b +"} +(120,1,1) = {" +b +b +b +b +b +b +b +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +"} +(121,1,1) = {" +b +b +b +b +b +b +b +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +b +b +b +b +b +b +b +"} +(122,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(123,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(124,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(125,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(126,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(127,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} +(128,1,1) = {" +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +"} diff --git a/maps/planets/test_planet/neutralia-2.dmm b/maps/planets/test_planet/neutralia-2.dmm new file mode 100644 index 000000000000..cc84b991ea84 --- /dev/null +++ b/maps/planets/test_planet/neutralia-2.dmm @@ -0,0 +1,16652 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/unsimulated/mineral, +/area/exoplanet/underground/neutralia) +"b" = ( +/turf/floor/barren, +/area/exoplanet/underground/neutralia) +"c" = ( +/obj/abstract/level_data_spawner/neutralia/underground, +/turf/floor/barren, +/area/exoplanet/underground/neutralia) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(4,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(5,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(6,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(7,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(8,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +c +a +a +a +a +a +a +a +"} +(9,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(10,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(11,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(12,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(13,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(14,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(15,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(16,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(17,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(18,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(19,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(20,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(21,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(22,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(24,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(25,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(26,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(27,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(28,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(29,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(30,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(31,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(32,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(33,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(34,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(35,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(36,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(37,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(38,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(39,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(40,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(41,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(42,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(43,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(44,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(45,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(46,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(47,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(48,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(49,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(50,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(51,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(52,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(53,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(54,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(55,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(56,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(57,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(58,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(59,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(60,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(61,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(62,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(63,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(64,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(65,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(66,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(67,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(68,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(69,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(70,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(71,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(72,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(73,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(74,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(75,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(76,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(77,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(78,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(79,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(80,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(81,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(82,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(83,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(84,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(85,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(86,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(87,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(88,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(89,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(90,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(91,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(92,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(93,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(94,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(95,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(96,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(97,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(98,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(99,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(100,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(101,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(102,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(103,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(104,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(105,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(106,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(107,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(108,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(109,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(110,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(111,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(112,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(113,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(114,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(115,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(116,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(117,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(118,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(119,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(120,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(121,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(122,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(123,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(124,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(125,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(126,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(127,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(128,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/maps/planets/test_planet/neutralia-3.dmm b/maps/planets/test_planet/neutralia-3.dmm new file mode 100644 index 000000000000..fb4f5b6268e2 --- /dev/null +++ b/maps/planets/test_planet/neutralia-3.dmm @@ -0,0 +1,16670 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/floor/barren, +/area/exoplanet/neutralia) +"b" = ( +/turf/unsimulated/mineral, +/area/exoplanet/neutralia) +"c" = ( +/turf/unsimulated/floor/rescue_base, +/area/exoplanet/neutralia) +"d" = ( +/obj/abstract/level_data_spawner/neutralia/surface, +/turf/unsimulated/floor/rescue_base, +/area/exoplanet/neutralia) +"e" = ( +/turf/floor/shuttle_ceiling, +/area/exoplanet/neutralia) +"j" = ( +/obj/abstract/landmark/exoplanet_spawn/large_plant, +/turf/floor/barren, +/area/exoplanet/neutralia) +"o" = ( +/obj/abstract/landmark/exoplanet_spawn/animal, +/turf/floor/barren, +/area/exoplanet/neutralia) +"x" = ( +/obj/abstract/landmark/exoplanet_spawn/plant, +/turf/floor/barren, +/area/exoplanet/neutralia) + +(1,1,1) = {" +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +"} +(2,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(3,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(4,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(5,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(6,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(7,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(8,1,1) = {" +e +b +b +b +b +b +b +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +d +b +b +b +b +b +b +e +"} +(9,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(10,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(11,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(12,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(13,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(14,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(15,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(16,1,1) = {" +e +b +b +b +b +b +b +c +a +o +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +o +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(17,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(18,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(19,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(20,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(21,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(22,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(23,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(24,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(25,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(26,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(27,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(28,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(29,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(30,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(31,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(32,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(33,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(34,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(35,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(36,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(37,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(38,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(39,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(40,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(41,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(42,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(43,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(44,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(45,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(46,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(47,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(48,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(49,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(50,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(51,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(52,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(53,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(54,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(55,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(56,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(57,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(58,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(59,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(60,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(61,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(62,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(63,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(64,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(65,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(66,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(67,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(68,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(69,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(70,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(71,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(72,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(73,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(74,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(75,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(76,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(77,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(78,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(79,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(80,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(81,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(82,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(83,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(84,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(85,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(86,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(87,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(88,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(89,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(90,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(91,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(92,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(93,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(94,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(95,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(96,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(97,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(98,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(99,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(100,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(101,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(102,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(103,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(104,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(105,1,1) = {" +e +b +b +b +b +b +b +c +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +c +b +b +b +b +b +b +e +"} +(106,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(107,1,1) = {" +e +b +b +b +b +b +b +c +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +c +b +b +b +b +b +b +e +"} +(108,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(109,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(110,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(111,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(112,1,1) = {" +e +b +b +b +b +b +b +c +a +o +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +o +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(113,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(114,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(115,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(116,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(117,1,1) = {" +e +b +b +b +b +b +b +c +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +c +b +b +b +b +b +b +e +"} +(118,1,1) = {" +e +b +b +b +b +b +b +c +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +a +j +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(119,1,1) = {" +e +b +b +b +b +b +b +c +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +x +a +x +a +a +a +a +c +b +b +b +b +b +b +e +"} +(120,1,1) = {" +e +b +b +b +b +b +b +c +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +c +b +b +b +b +b +b +e +"} +(121,1,1) = {" +e +b +b +b +b +b +b +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +b +b +b +b +b +b +e +"} +(122,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(123,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(124,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(125,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(126,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(127,1,1) = {" +e +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +"} +(128,1,1) = {" +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +e +"} diff --git a/maps/planets/test_planet/neutralia-4.dmm b/maps/planets/test_planet/neutralia-4.dmm new file mode 100644 index 000000000000..bf23c1fb529d --- /dev/null +++ b/maps/planets/test_planet/neutralia-4.dmm @@ -0,0 +1,16660 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/unsimulated/dark_filler, +/area/exoplanet/neutralia/sky) +"b" = ( +/turf/open, +/area/exoplanet/neutralia/sky) +"c" = ( +/obj/abstract/level_data_spawner/neutralia/sky, +/turf/open, +/area/exoplanet/neutralia/sky) +"d" = ( +/obj/abstract/map_data/neutralia, +/turf/open, +/area/exoplanet/neutralia/sky) +"e" = ( +/obj/effect/overmap/visitable/sector/planetoid/neutralia, +/turf/open, +/area/exoplanet/neutralia/sky) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(4,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(5,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(6,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(7,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(8,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +e +c +a +a +a +a +a +a +a +"} +(9,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +d +a +a +a +a +a +a +a +"} +(10,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(11,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(12,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(13,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(14,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(15,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(16,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(17,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(18,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(19,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(20,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(21,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(22,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(24,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(25,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(26,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(27,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(28,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(29,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(30,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(31,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(32,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(33,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(34,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(35,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(36,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(37,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(38,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(39,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(40,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(41,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(42,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(43,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(44,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(45,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(46,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(47,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(48,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(49,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(50,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(51,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(52,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(53,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(54,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(55,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(56,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(57,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(58,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(59,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(60,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(61,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(62,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(63,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(64,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(65,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(66,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(67,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(68,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(69,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(70,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(71,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(72,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(73,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(74,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(75,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(76,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(77,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(78,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(79,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(80,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(81,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(82,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(83,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(84,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(85,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(86,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(87,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(88,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(89,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(90,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(91,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(92,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(93,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(94,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(95,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(96,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(97,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(98,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(99,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(100,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(101,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(102,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(103,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(104,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(105,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(106,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(107,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(108,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(109,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(110,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(111,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(112,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(113,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(114,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(115,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(116,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(117,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(118,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(119,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(120,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(121,1,1) = {" +a +a +a +a +a +a +a +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +b +a +a +a +a +a +a +a +"} +(122,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(123,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(124,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(125,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(126,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(127,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(128,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/maps/planets/test_planet/test_planet.dm b/maps/planets/test_planet/test_planet.dm new file mode 100644 index 000000000000..83c42703e654 --- /dev/null +++ b/maps/planets/test_planet/test_planet.dm @@ -0,0 +1,170 @@ +#define NEUTRALIA_SKY_LEVEL_ID "neutralia_sky" +#define NEUTRALIA_SURFACE_LEVEL_ID "neutralia_surface" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Atmosphere +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/gas_mixture/atmos_neutralia + temperature = T20C + gas = list( + /decl/material/gas/oxygen = MOLES_O2STANDARD, + /decl/material/gas/nitrogen = MOLES_N2STANDARD, + ) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Flora +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/planet_flora/random/neutralia + flora_diversity = 2 + has_trees = TRUE + grass_color = COLOR_GRAY80 + plant_colors = list( + COLOR_SURGERY_BLUE, + COLOR_SILVER, + COLOR_GRAY80, + COLOR_OFF_WHITE + ) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Fauna +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/fauna_generator/neutralia + max_fauna_alive = 10 + max_megafauna_alive = 0 + fauna_types = list( + /mob/living/simple_animal/yithian, + ) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Overmap Marker +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/obj/effect/overmap/visitable/sector/planetoid/neutralia + name = "Neutralia" + color = COLOR_GRAY + planetoid_id = "neutralia" + start_x = 10 + start_y = 10 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Planetoid Data +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/planetoid_data/neutralia + id = "neutralia" + name = "\improper Neutralia" + topmost_level_id = NEUTRALIA_SKY_LEVEL_ID + surface_level_id = NEUTRALIA_SURFACE_LEVEL_ID + habitability_class = HABITABILITY_OKAY + atmosphere = /datum/gas_mixture/atmos_neutralia + surface_color = COLOR_GRAY + water_color = COLOR_BLUE_GRAY + rock_color = COLOR_GRAY40 + has_rings = TRUE + ring_color = COLOR_OFF_WHITE + ring_type_name = SKYBOX_PLANET_RING_TYPE_SPARSE + strata = /decl/strata/sedimentary + engraving_generator = /datum/xenoarch_engraving_flavor + daycycle_type = /datum/daycycle/exoplanet/neutralia + surface_light_level = 0.5 + surface_light_color = COLOR_OFF_WHITE + flora = /datum/planet_flora/random/neutralia + fauna = /datum/fauna_generator/neutralia + +/datum/daycycle/exoplanet/neutralia + cycle_duration = 12 MINUTES + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Neutralia Template +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/map_template/planetoid/neutralia + name = "Neutralia" + template_categories = list(MAP_TEMPLATE_CATEGORY_PLANET) + template_flags = TEMPLATE_FLAG_SPAWN_GUARANTEED + planetoid_data_type = /datum/planetoid_data/neutralia + level_data_type = null //We have our own level_data + mappaths = list( + "maps/planets/test_planet/neutralia-1.dmm", + "maps/planets/test_planet/neutralia-2.dmm", + "maps/planets/test_planet/neutralia-3.dmm", + "maps/planets/test_planet/neutralia-4.dmm", + ) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Areas +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/area/exoplanet/neutralia + name = "surface" + +/area/exoplanet/neutralia/sky + name = "sky" + +/area/exoplanet/underground/neutralia + name = "underground" + +/area/exoplanet/underground/neutralia/bottom + name = "abyssal depths" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Level Data +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/level_data/planetoid/neutralia + parent_planetoid = "neutralia" + level_max_width = 128 + level_max_height = 128 + loop_turf_type = /turf/mimic_edge/transition/loop + +/datum/level_data/planetoid/neutralia/sky + name = "neutralia sky" + level_id = NEUTRALIA_SKY_LEVEL_ID + base_area = /area/exoplanet/neutralia/sky + base_turf = /turf/open + border_filler = /turf/unsimulated/dark_filler + +/datum/level_data/planetoid/neutralia/surface + name = "neutralia surface" + level_id = NEUTRALIA_SURFACE_LEVEL_ID + base_area = /area/exoplanet/neutralia + base_turf = /turf/floor/barren + border_filler = /turf/unsimulated/dark_filler + +/datum/level_data/planetoid/neutralia/underground + name = "neutralia underground" + level_id = "neutralia_underground" + base_area = /area/exoplanet/underground/neutralia + base_turf = /turf/floor/barren + border_filler = /turf/unsimulated/mineral + +/datum/level_data/planetoid/neutralia/underground/bottom + name = "neutralia abyssal depths" + level_id = "neutralia_abyssal_depths" + base_area = /area/exoplanet/underground/neutralia/bottom + base_turf = /turf/floor/rock/volcanic + +/obj/abstract/level_data_spawner/neutralia/sky + level_data_type = /datum/level_data/planetoid/neutralia/sky + +/obj/abstract/level_data_spawner/neutralia/surface + level_data_type = /datum/level_data/planetoid/neutralia/surface + +/obj/abstract/level_data_spawner/neutralia/underground + level_data_type = /datum/level_data/planetoid/neutralia/underground + +/obj/abstract/level_data_spawner/neutralia/bottom + level_data_type = /datum/level_data/planetoid/neutralia/underground/bottom + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Neutralia Map Data +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/obj/abstract/map_data/neutralia + height = 4 + +#undef NEUTRALIA_SKY_LEVEL_ID +#undef NEUTRALIA_SURFACE_LEVEL_ID \ No newline at end of file diff --git a/maps/planets_testing/planets_testing.dm b/maps/planets_testing/planets_testing.dm new file mode 100644 index 000000000000..db3acef03dc5 --- /dev/null +++ b/maps/planets_testing/planets_testing.dm @@ -0,0 +1,15 @@ +#if !defined(USING_MAP_DATUM) + + //Include Static Planet + #include "../planets/test_planet/test_planet.dm" + + #define USING_MAP_DATUM /datum/map/planet_testing + + ///Tells the base planet gen code to create planets even if UNIT_TEST is defined + #define PLANET_UNIT_TEST 1 + +#elif !defined(MAP_OVERRIDE) + + #warn A map has already been included, ignoring Planet Testing + +#endif diff --git a/maps/planets_testing/planets_testing_define.dm b/maps/planets_testing/planets_testing_define.dm new file mode 100644 index 000000000000..8380842377fe --- /dev/null +++ b/maps/planets_testing/planets_testing_define.dm @@ -0,0 +1,25 @@ +/datum/map/planet_testing + name = "Planets Testing" + full_name = "Planets Testing" + path = "planets_testing" + overmap_ids = list(OVERMAP_ID_SPACE) + default_spawn = null + votable = FALSE + allowed_latejoin_spawns = list() + +/datum/map/planet_testing/validate() + return FALSE // Testing map, do not validate levels. + +// Set the observer spawn to include every flag so that CI flag checks pass. +/decl/spawnpoint/observer + spawn_flags = (SPAWN_FLAG_GHOSTS_CAN_SPAWN | SPAWN_FLAG_JOBS_CAN_SPAWN | SPAWN_FLAG_PRISONERS_CAN_SPAWN | SPAWN_FLAG_PERSISTENCE_CAN_SPAWN) + +/datum/map/planet_testing/build_planets() + report_progress("Instantiating planets...") + + //Spawn all templates once + spawn_planet_templates(list_values(get_all_planet_templates())) + // Place an observer landmark just to appease CI and on the off-chance that anyone ever wants to observer. + new /obj/abstract/landmark/latejoin/observer(locate(round(world.maxx/2), round(world.maxy/2), world.maxz)) + report_progress("Finished instantiating planets.") + diff --git a/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dm b/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dm index fea42dc016ca..b893cabaae96 100644 --- a/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dm +++ b/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dm @@ -1,20 +1,17 @@ -GLOBAL_LIST_INIT(crashed_pod_areas, new) - /datum/map_template/ruin/exoplanet/crashed_pod - name = "crashed survival pod" - id = "crashed_pod" - description = "A crashed survival pod from a destroyed ship." - suffixes = list("crashed_pod/crashed_pod.dmm") - cost = 2 + name = "crashed survival pod" + description = "A crashed survival pod from a destroyed ship." + suffixes = list("crashed_pod/crashed_pod.dmm") + cost = 2 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS | TEMPLATE_FLAG_NO_RADS - ruin_tags = RUIN_HUMAN|RUIN_WRECK + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WRECK /area/map_template/crashed_pod - name = "\improper Crashed Survival Pod" + name = "\improper Crashed Survival Pod" icon_state = "blue" /decl/submap_archetype/crashed_pod - descriptor = "crashed survival pod" + name = "crashed survival pod" crew_jobs = list(/datum/job/submap/pod) /datum/submap/crashed_pod/sync_cell(var/obj/effect/overmap/visitable/cell) @@ -23,10 +20,10 @@ GLOBAL_LIST_INIT(crashed_pod_areas, new) /datum/job/submap/pod title = "Stranded Survivor" info = "Your ship has been destroyed by a terrible disaster." - outfit_type = /decl/hierarchy/outfit/job/survivor + outfit_type = /decl/outfit/job/survivor -/decl/hierarchy/outfit/job/survivor - name = OUTFIT_JOB_NAME("Survivor") +/decl/outfit/job/survivor + name = "Job - Survivor" id_type = null pda_type = null @@ -38,15 +35,15 @@ GLOBAL_LIST_INIT(crashed_pod_areas, new) signal might draw help, but even if you should be so lucky, you must survive long \ enough for it to arrive." -/obj/effect/submap_landmark/spawnpoint/crashed_pod_survivor +/obj/abstract/submap_landmark/spawnpoint/crashed_pod_survivor name = "Stranded Survivor" -/obj/effect/submap_landmark/joinable_submap/crashed_pod +/obj/abstract/submap_landmark/joinable_submap/crashed_pod name = "Crashed Survival Pod" archetype = /decl/submap_archetype/crashed_pod submap_datum_type = /datum/submap/crashed_pod -/obj/effect/submap_landmark/joinable_submap/crashed_pod/Initialize(mapload) +/obj/abstract/submap_landmark/joinable_submap/crashed_pod/Initialize(mapload) var/list/possible_ship_names = list( "Hornet", "Witchmoth", "Planthopper", "Mayfly", "Locust", "Cicada", @@ -60,3 +57,7 @@ GLOBAL_LIST_INIT(crashed_pod_areas, new) "Adder", "Bumblebee") name = "[pick("SEV", "SIC", "FTUV", "ICV", "HMS")] [pick(possible_ship_names)]" . = ..() + +/obj/structure/sign/plaque/ai_dev/pod + desc = "A plaque with information regarding this particular lifepod. It reads: 'Yoyodyne Propulsion Systems Exoplanetary Suvival Pod MK 7' there's a registry number, and an assigned mothership, but they've both been scratched to illegiblity." + name = "\improper Lifepod Plaque" \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dmm b/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dmm index a86d0b475716..7ecd88d90d76 100644 --- a/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dmm +++ b/maps/random_ruins/exoplanet_ruins/crashed_pod/crashed_pod.dmm @@ -1,1028 +1,1276 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "aa" = ( -/obj/structure/grille, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "crashed_pod_pump_out_external" + }, +/obj/machinery/button/access/exterior{ + id_tag = "crashed_pod"; + pixel_x = 10; + pixel_y = -20; + dir = 1; + name = "exterior access button" + }, +/obj/machinery/airlock_sensor{ + dir = 1; + pixel_x = -1; + id_tag = "crashed_pod_ext_sensor"; + pixel_y = -19 + }, +/turf/floor/plating, /area/map_template/crashed_pod) "ab" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/crashed_pod) "ac" = ( /obj/machinery/atmospherics/unary/engine, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/crashed_pod) "ad" = ( /obj/structure/shuttle/engine/heater{ - icon_state = "heater"; dir = 1 }, /obj/structure/wall_frame, /obj/structure/grille, /obj/structure/window/borosilicate_reinforced/full, -/obj/effect/submap_landmark/joinable_submap/crashed_pod, -/turf/simulated/floor/plating, +/obj/abstract/submap_landmark/joinable_submap/crashed_pod, +/turf/floor/plating, /area/map_template/crashed_pod) "ae" = ( /obj/structure/shuttle/engine/heater{ - icon_state = "heater"; dir = 1 }, /obj/structure/wall_frame, /obj/structure/grille, /obj/structure/window/borosilicate_reinforced/full, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/crashed_pod) "af" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; +/obj/structure/shuttle/engine/heater{ + dir = 1 + }, +/obj/structure/wall_frame, +/obj/structure/grille, +/obj/structure/window/borosilicate_reinforced/full, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ dir = 6 }, -/turf/simulated/wall/r_wall, +/turf/floor/plating, /area/map_template/crashed_pod) "ag" = ( /obj/structure/shuttle/engine/heater{ - icon_state = "heater"; dir = 1 }, /obj/structure/wall_frame, /obj/structure/grille, /obj/structure/window/borosilicate_reinforced/full, -/obj/machinery/atmospherics/pipe/simple/visible/red{ +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ dir = 10 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/map_template/crashed_pod) "ah" = ( -/obj/machinery/alarm{ - dir = 4; - locked = 0; - pixel_x = -25; - pixel_y = 0 +/obj/structure/rack, +/obj/item/tank/emergency/oxygen/double, +/obj/item/tank/emergency/oxygen/double, +/obj/item/tank/emergency/oxygen/double, +/obj/item/tank/emergency/oxygen/double, +/obj/item/clothing/suit/space/emergency, +/obj/item/clothing/suit/space/emergency, +/obj/item/clothing/suit/space/emergency, +/obj/item/clothing/suit/space/emergency, +/obj/item/clothing/head/helmet/space/emergency, +/obj/item/clothing/head/helmet/space/emergency, +/obj/item/clothing/head/helmet/space/emergency, +/obj/item/clothing/head/helmet/space/emergency, +/obj/effect/floor_decal/industrial/hatch/orange, +/obj/item/tool/pickaxe, +/obj/item/tool/pickaxe, +/obj/item/scanner/gas, +/obj/item/scanner/gas, +/obj/machinery/light/small{ + dir = 4 }, -/obj/machinery/atmospherics/unary/vent_pump/on, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "ai" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/raisins, -/obj/item/chems/food/drinks/glass2/fitnessflask, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/turf/wall/r_wall, /area/map_template/crashed_pod) "aj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 5 + }, +/obj/structure/rack, +/obj/item/stock_parts/circuitboard/pacman/super, +/obj/item/stock_parts/circuitboard/space_heater, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stock_parts/circuitboard/unary_atmos/heater, +/obj/item/stock_parts/circuitboard/unary_atmos/cooler, +/obj/item/stock_parts/circuitboard/oxyregenerator, +/obj/item/stock_parts/circuitboard/biogenerator, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "ak" = ( -/obj/machinery/power/terminal, -/obj/machinery/light/small{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "al" = ( -/obj/structure/sign/kiddieplaque{ - desc = "A plaque with information regarding this particular lifepod. It reads: 'Armalev Industries Skyfin-E, Exoplanetary Suvival Pod' there's a registry number, and an assigned mothership, but they've both been scratched to illegiblity."; - name = "\improper Lifepod Plaque"; - pixel_y = 30 +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "am" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 6 +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "2-4" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "an" = ( -/obj/machinery/atmospherics/omni/filter, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/table/steel_reinforced{ + dir = 8 + }, +/obj/item/belt/utility/full, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/random/toolbox, +/obj/random/toolbox, +/obj/random/toolbox, +/obj/item/clothing/gloves/insulated, +/obj/item/t_scanner, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/item/multitool, +/obj/item/wrench, +/obj/item/toolbox/repairs, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "ao" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; - dir = 4 +/obj/machinery/atmospherics/omni/filter, +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/tastybread, -/obj/item/chems/food/drinks/cans/speer, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/closet/crate/solar, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "ap" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/vomit, -/obj/effect/decal/cleanable/filth, -/obj/structure/curtain/open/shower/engineering, -/obj/structure/hygiene/toilet{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" }, -/obj/item/storage/mirror{ - pixel_x = 27 +/obj/machinery/power/smes/buildable{ + charge = 50000; + inputting = 1; + outputting = 1 }, -/obj/item/stock_parts/circuitboard/solar_control, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/cobweb2, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aq" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/effect/decal/cleanable/dirt, -/obj/structure/closet/hydrant{ - pixel_x = -27 +/obj/machinery/portable_atmospherics/canister/oxygen, +/obj/effect/floor_decal/industrial/hatch/orange, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "ar" = ( -/obj/effect/floor_decal/industrial/outline/blue, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" +/obj/machinery/portable_atmospherics/canister/air/airlock{ + start_pressure = 0 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 }, -/obj/machinery/space_heater, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "as" = ( -/obj/effect/floor_decal/industrial/outline/blue, -/obj/machinery/power/apc{ - dir = 2; - locked = 0; - name = "south bump"; - operating = 1; - pixel_y = -28 - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/tiled/techfloor, +/turf/wall, /area/map_template/crashed_pod) "at" = ( -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/power/smes/buildable{ - charge = 50000; - inputting = 1; - outputting = 1 +/obj/machinery/fabricator/pipe, +/obj/effect/floor_decal/industrial/outline/blue, +/obj/machinery/light/small{ + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "au" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ - icon_state = "map"; +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/obj/structure/reagent_dispensers/fueltank, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "av" = ( -/obj/machinery/atmospherics/omni/filter, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/obj/machinery/alarm{ + pixel_y = -18; + dir = 1; + locked = 0 + }, +/obj/item/trash/candy/proteinbar, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aw" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; - dir = 4 +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "ax" = ( /obj/effect/wallframe_spawn/reinforced/hull, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/space, /area/map_template/crashed_pod) "ay" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/crashed_pod) "az" = ( -/obj/machinery/atmospherics/binary/pump, -/turf/simulated/wall, -/area/map_template/crashed_pod) -"aA" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/engineering, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"aA" = ( +/obj/effect/wallframe_spawn/reinforced/hull, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "aB" = ( -/obj/machinery/sleeper/standard{ - dir = 4 +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/obj/effect/floor_decal/industrial/outline/blue, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aC" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/engineering, -/obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; - dir = 4 +/obj/machinery/atmospherics/unary/vent_pump/high_volume/airlock{ + dir = 4; + id_tag = "crashed_pod_pump" + }, +/obj/machinery/airlock_sensor{ + dir = 4; + pixel_x = -18; + id_tag = "crashed_pod_sensor" + }, +/obj/effect/floor_decal/industrial/hatch/orange, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aD" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; - dir = 5 +/obj/structure/cable{ + icon_state = "1-8" }, -/turf/simulated/wall, +/turf/wall/r_wall, /area/map_template/crashed_pod) "aE" = ( -/obj/machinery/sleeper/standard{ - dir = 4 +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 }, -/obj/effect/floor_decal/industrial/outline/blue, -/obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/tiled/techfloor/grid, -/area/map_template/crashed_pod) -"aF" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 +/obj/structure/emergency_dispenser/east, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/white, /area/map_template/crashed_pod) -"aG" = ( -/obj/structure/closet/crate, -/obj/effect/floor_decal/industrial/hatch/orange, -/obj/item/scanner/gas, -/obj/item/stock_parts/circuitboard/unary_atmos/cooler, -/obj/item/stock_parts/circuitboard/unary_atmos/heater, -/obj/item/stock_parts/circuitboard/oxyregenerator, -/obj/item/tank/emergency/oxygen/double/red, -/obj/structure/cable, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/clothing/under/savage_hunter, -/obj/item/clothing/under/savage_hunter/female, -/obj/item/clothing/under/wetsuit, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/candy/proteinbar, -/obj/item/trash/liquidfood, -/obj/item/stock_parts/matter_bin/super, -/obj/item/stock_parts/circuitboard/biogenerator, -/obj/item/bedsheet/orange, -/obj/item/bedsheet/orange, -/obj/item/stock_parts/matter_bin/adv, -/obj/item/stock_parts/micro_laser/ultra, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/stack/material/sandstone{ - amount = 50 +"aF" = ( +/obj/machinery/button/access/interior{ + id_tag = "crashed_pod"; + pixel_x = -10; + pixel_y = 20; + name = "interior access button" }, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) -"aH" = ( +"aG" = ( +/obj/machinery/fabricator, +/obj/effect/floor_decal/industrial/outline/blue, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 + dir = 4; + level = 2 }, -/obj/machinery/portable_atmospherics/canister/oxygen, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) -"aI" = ( -/obj/machinery/atmospherics/unary/tank/air, +"aH" = ( +/obj/machinery/material_processing/smeltery, /obj/effect/floor_decal/industrial/outline/blue, -/obj/effect/decal/cleanable/generic, -/turf/simulated/floor/tiled/techfloor, -/area/map_template/crashed_pod) -"aJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/obj/structure/curtain/open/shower/engineering, -/obj/structure/hygiene/shower{ - dir = 8; - icon_state = "shower"; - pixel_x = -6; - pixel_y = 0 +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/map_template/crashed_pod) -"aK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 - }, -/obj/machinery/light/small{ +/obj/machinery/light{ dir = 1 }, -/obj/item/mop, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/trash/candy/proteinbar, -/obj/item/trash/liquidfood, -/obj/item/storage/box/detergent, -/obj/item/clothing/mask/plunger, -/turf/simulated/floor/tiled/techfloor, +/obj/item/trash/candy/proteinbar, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) -"aL" = ( -/obj/effect/floor_decal/industrial/warning{ +"aI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, -/area/map_template/crashed_pod) -"aM" = ( -/obj/machinery/fabricator/pipe, -/obj/effect/floor_decal/industrial/outline/blue, -/obj/effect/decal/cleanable/generic, -/obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"aN" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 8 +"aJ" = ( +/obj/machinery/power/terminal{ + dir = 1 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/solar_control{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/floor_decal/industrial/outline/blue, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"aO" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; - dir = 4 +"aK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/ore_box, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/sign/plaque/ai_dev/pod, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) -"aP" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/cyan, -/obj/effect/decal/cleanable/dirt, +"aL" = ( +/obj/structure/hygiene/toilet{ + dir = 1 + }, /obj/effect/decal/cleanable/filth, -/obj/item/solar_assembly, -/obj/item/solar_assembly, -/obj/item/solar_assembly, -/obj/item/solar_assembly, -/turf/simulated/floor/tiled/techfloor, -/area/map_template/crashed_pod) -"aQ" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/obj/structure/curtain/open/shower/engineering, +/turf/floor/tiled/techfloor/grid, +/area/map_template/crashed_pod) +"aM" = ( +/obj/structure/curtain/open/shower/engineering, +/obj/structure/hygiene/shower{ + dir = 8; + pixel_x = -6 + }, +/obj/machinery/alarm{ + pixel_y = -24; + dir = 1; + locked = 0 + }, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/effect/decal/cleanable/cobweb2, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor/grid, +/area/map_template/crashed_pod) +"aN" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"aO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"aP" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/emergency_dispenser/south, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"aQ" = ( +/obj/structure/table/steel_reinforced, +/obj/item/backpack/dufflebag/eng, +/obj/item/backpack/dufflebag/eng, +/obj/item/box/animal_cubes/monkeys, +/obj/item/multitool, +/obj/item/screwdriver, +/obj/item/wrench, +/obj/item/cell/device/high, +/obj/item/cell/device/high, +/obj/item/cell/crap, +/obj/item/toolbox/mechanical, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "aR" = ( -/obj/machinery/fabricator, -/obj/effect/floor_decal/industrial/outline/blue, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/binary/pump, +/turf/wall/r_wall, /area/map_template/crashed_pod) "aS" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/civilian, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/apc{ + dir = 1; + name = "_North APC"; + pixel_y = 24 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aT" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ - dir = 9; - icon_state = "intact" +/obj/item/stool/padded, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 }, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/tastybread, -/turf/simulated/floor/tiled/techfloor, +/obj/item/trash/candy/proteinbar, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/white, /area/map_template/crashed_pod) "aU" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; - dir = 6 +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/obj/machinery/light/small{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/door/airlock{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aV" = ( -/obj/machinery/atmospherics/binary/pump{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/turf/wall/r_wall, /area/map_template/crashed_pod) "aW" = ( -/obj/machinery/atmospherics/portables_connector{ +/obj/effect/floor_decal/industrial/outline/blue, +/obj/machinery/atmospherics/unary/tank/air{ dir = 1 }, -/obj/machinery/portable_atmospherics/canister/empty, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "aX" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 4 +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume{ + external_pressure_bound = 140; + external_pressure_bound_default = 140; + icon_state = "map_vent_out"; + use_power = 1 }, -/obj/machinery/atmospherics/pipe/simple/visible/red, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/plating, /area/map_template/crashed_pod) "aY" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/civilian, -/obj/machinery/atmospherics/pipe/simple/hidden/universal, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/structure/closet/crate/hydroponics, +/obj/item/chems/glass/bucket, +/obj/item/seeds/random, +/obj/item/seeds/random, +/obj/item/seeds/random, +/obj/item/seeds/random, +/obj/item/seeds/random, +/obj/item/seeds/clam, +/obj/item/seeds/cornseed, +/obj/item/seeds/potatoseed, +/obj/item/tool/hoe/mini, +/obj/item/tool/axe/hatchet, +/obj/item/plantspray/pests, +/obj/item/plantspray/weeds, +/obj/item/plant_satchel, +/obj/item/chems/glass/bottle/eznutrient, +/obj/item/seeds/wheatseed, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "aZ" = ( -/obj/effect/submap_landmark/spawnpoint/crashed_pod_survivor, -/obj/structure/bed/chair/shuttle/black, -/obj/structure/window/reinforced{ - dir = 8 - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/light{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/outline, +/obj/structure/closet/crate{ + dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark/monotile, +/obj/item/ore_satchel, +/obj/item/ore_satchel, +/obj/item/mop, +/obj/item/flashlight/lantern, +/obj/item/flashlight/lantern, +/obj/item/plunger, +/obj/item/box/glowsticks, +/obj/item/box/glowsticks, +/obj/item/crowbar, +/obj/item/bag/trash, +/obj/item/bag/trash, +/obj/item/beartrap, +/obj/random/plushie, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "ba" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/table, +/obj/item/pill_bottle/assorted, +/obj/item/pill_bottle/assorted, +/obj/item/pill_bottle/assorted, +/obj/item/pill_bottle/assorted, +/obj/item/pill_bottle/antidepressants, +/obj/item/firstaid/stab, +/obj/item/scanner/health, +/obj/item/firstaid/surgery, +/obj/item/chems/drinks/bottle/vodka, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/map_template/crashed_pod) "bb" = ( -/obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced/hull, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/space, /area/map_template/crashed_pod) "bc" = ( -/obj/effect/submap_landmark/spawnpoint/crashed_pod_survivor, -/obj/structure/bed/chair/shuttle/black, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark/monotile, +/obj/structure/table/steel_reinforced, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24; + locked = 0 + }, +/obj/machinery/reagentgrinder, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bd" = ( -/obj/structure/table/steel_reinforced, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/item/radio, -/obj/random/plushie, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark/monotile, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/wall/r_wall, /area/map_template/crashed_pod) "be" = ( -/obj/machinery/light/small{ - dir = 1 +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24; + locked = 0 }, -/obj/structure/bed/chair, -/obj/structure/closet/hydrant{ - pixel_x = -27 +/obj/structure/chair{ + dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/trash/liquidfood, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bf" = ( -/obj/effect/submap_landmark/spawnpoint/crashed_pod_survivor, -/obj/structure/bed/chair/shuttle/black, -/obj/structure/window/reinforced{ +/obj/machinery/seed_extractor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/map_template/crashed_pod) +"bg" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/obj/machinery/light{ - dir = 1 +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark/monotile, -/area/map_template/crashed_pod) -"bg" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bh" = ( -/obj/structure/window/reinforced{ - dir = 8 +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 }, -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/trash/tastybread, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bi" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/floor_decal/industrial/outline, +/obj/structure/closet/crate/plastic/rations, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/food/junk/liquidfood, +/obj/item/box/fancy/egg_box, +/obj/item/box/fancy/egg_box, +/obj/item/box/donkpockets, +/obj/item/box/donkpockets, +/obj/item/chems/drinks/milk, +/obj/item/chems/drinks/milk, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bj" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/recharger, -/obj/effect/decal/cleanable/dirt, -/obj/item/chems/food/drinks/glass2/coffeecup/metal, -/turf/simulated/floor/tiled/dark/monotile, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 1 + }, +/turf/wall/r_wall, /area/map_template/crashed_pod) "bk" = ( -/obj/machinery/atmospherics/unary/vent_pump/on, -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/floor_decal/industrial/outline, +/obj/structure/closet/crate, +/obj/item/gun/energy/gun/small, +/obj/item/gun/energy/gun/small, +/obj/item/gun/energy/gun/small, +/obj/item/knife/combat, +/obj/item/knife/combat, +/obj/item/bladed/polearm/spear, +/obj/item/bladed/polearm/spear, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bl" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/structure/table/steel_reinforced, +/obj/machinery/recharger, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/geiger, +/obj/item/geiger, +/obj/item/screwdriver, +/obj/item/wrench, +/obj/item/pill_bottle/happy, +/obj/item/box/fancy/cigar, +/obj/item/box/fancy/cigarettes, +/obj/item/chems/drinks/bottle/vodka, +/obj/item/chems/drinks/cans/speer, +/obj/effect/decal/cleanable/cobweb2, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/box/lights/mixed, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bm" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/candy/proteinbar, -/obj/item/trash/liquidfood, -/turf/simulated/floor/tiled/dark, +/obj/effect/floor_decal/industrial/hatch/orange, +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "Internal Airlock Hatch"; + locked = 1; + id_tag = "crashed_pod_airlock_interior" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bn" = ( -/obj/structure/window/reinforced{ - dir = 4 +/obj/machinery/portable_atmospherics/hydroponics, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/closet/hydrant{ + pixel_x = -27 }, -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bo" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/flour, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bp" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/decal/cleanable/filth, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/unary/vent_pump/on, +/obj/item/trash/tastybread, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bq" = ( -/obj/structure/closet/emcloset, -/obj/machinery/light/small{ - dir = 1 - }, -/obj/item/crowbar, -/obj/item/crowbar, -/turf/simulated/floor/tiled/dark, +/obj/structure/table/steel_reinforced, +/obj/item/chems/condiment/small/saltshaker, +/obj/item/chems/condiment/small/peppermill, +/obj/machinery/reagentgrinder/juicer, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/item/chems/condiment/enzyme, +/obj/item/knife/kitchen/cleaver, +/obj/item/chems/drinks/bottle/vodka, +/obj/item/trash/candy/proteinbar, +/obj/effect/decal/cleanable/flour, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "br" = ( /obj/structure/table/steel_reinforced, /obj/machinery/microwave, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/flour, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bt" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/light, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bu" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/food/condiment/small/saltshaker, -/obj/item/chems/food/condiment/small/peppermill, -/obj/effect/decal/cleanable/flour, -/obj/item/trash/candy/proteinbar, -/obj/machinery/reagentgrinder, -/obj/item/chems/food/condiment/small/sugar, -/turf/simulated/floor/tiled/dark, +/obj/effect/floor_decal/industrial/hatch/orange, +/obj/machinery/door/airlock/external/glass{ + autoset_access = 0; + name = "External Airlock Hatch"; + locked = 1; + id_tag = "crashed_pod_airlock_exterior" + }, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bv" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bw" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, -/area/map_template/crashed_pod) -"bx" = ( -/obj/machinery/alarm{ - dir = 4; - locked = 0; - pixel_x = -25; - pixel_y = 0 +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/obj/structure/bed/chair{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"bx" = ( +/obj/structure/table/gamblingtable, +/obj/item/deck/cards, +/obj/item/dice, +/obj/item/flashlight/lamp/green, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/item/trash/candy/proteinbar, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/filth, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "by" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/machinery/atmospherics/unary/vent_pump/high_volume/airlock{ + dir = 8; + id_tag = "crashed_pod_pump_out_internal" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/floor_decal/industrial/hatch/orange, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "crashed_pod"; + pixel_y = null; + tag_airpump = "crashed_pod_pump"; + tag_chamber_sensor = "crashed_pod_sensor"; + tag_exterior_door = "crashed_pod_airlock_exterior"; + tag_interior_door = "crashed_pod_airlock_interior"; + dir = 4; + pixel_x = -20; + tag_pump_out_external = "crashed_pod_pump_out_external"; + tag_pump_out_internal = "crashed_pod_pump_out_internal"; + cycle_to_external_air = 1; + tag_exterior_sensor = "crashed_pod_ext_sensor"; + tag_interior_sensor = "crashed_pod_int_sensor" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bz" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 +/obj/machinery/light/small{ + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/trash/liquidfood, +/obj/item/trash/liquidfood, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bB" = ( -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/door/airlock/engineering, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bC" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 +/obj/structure/chair{ + dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bD" = ( /obj/effect/floor_decal/industrial/hatch/orange, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/wall/r_wall, /area/map_template/crashed_pod) "bG" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bH" = ( -/obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/chair/shuttle/black, +/obj/abstract/submap_landmark/spawnpoint/crashed_pod_survivor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bI" = ( -/obj/structure/closet/crate, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 +/obj/structure/chair/shuttle/black, +/obj/structure/window/reinforced{ + dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/obj/abstract/submap_landmark/spawnpoint/crashed_pod_survivor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bJ" = ( -/obj/machinery/door/airlock/external{ - name = "escape pod airlock" - }, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/optable, +/obj/item/chems/drinks/bottle/agedwhiskey, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/map_template/crashed_pod) "bK" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/machinery/light/small, -/obj/effect/decal/cleanable/ash, -/obj/item/trash/cigbutt/cigarbutt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/structure/reagent_dispensers/watertank, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bL" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/floor_decal/industrial/outline, +/obj/random/crate{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bM" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/closet, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/gloves, -/obj/random/gloves, -/obj/random/hat, -/obj/random/hat, -/obj/random/hat, -/obj/random/hat, -/obj/random/hat, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/color/black, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/structure/closet/emcloset, +/obj/item/crowbar, +/obj/effect/floor_decal/industrial/outline/red, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bN" = ( -/obj/machinery/seed_extractor, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/flashlight/flare/glowstick/random, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bO" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/structure/table/steel_reinforced, -/obj/item/binoculars, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/candy/proteinbar, -/obj/item/chems/food/drinks/cans/speer, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/machinery/door/airlock, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bP" = ( -/obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/item/crowbar, +/obj/structure/closet/emcloset, +/obj/effect/floor_decal/industrial/outline/red, +/obj/effect/decal/cleanable/cobweb2, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) "bQ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/closet, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/gloves, -/obj/random/gloves, -/obj/random/hat, -/obj/random/hat, -/obj/random/hat, -/obj/random/hat, -/obj/random/hat, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/color/black, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/effect/floor_decal/industrial/outline, +/obj/structure/closet/crate, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/puck/mapped/uranium/fifty, +/obj/item/box/parts, +/obj/item/box/parts, +/obj/item/box/parts, +/obj/item/stock_parts/matter_bin, +/obj/item/stock_parts/matter_bin, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bR" = ( -/obj/structure/table/steel_reinforced, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/tastybread, -/obj/item/geiger, -/obj/item/geiger, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/wall/r_wall, /area/map_template/crashed_pod) "bS" = ( -/obj/effect/floor_decal/industrial/hatch/orange, -/obj/structure/table/rack, -/obj/item/clothing/suit/space/emergency, -/obj/item/clothing/head/helmet/space/emergency, -/obj/item/clothing/head/helmet/space/emergency, -/obj/item/clothing/suit/space/emergency, -/obj/item/tank/emergency/oxygen/double, -/obj/item/tank/emergency/oxygen/double, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/sleeper/standard, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/map_template/crashed_pod) "bT" = ( -/obj/structure/closet/emcloset, -/obj/machinery/light/small, -/obj/item/crowbar, -/obj/item/crowbar, -/turf/simulated/floor/tiled/dark, +/obj/item/bedsheet/brown, +/obj/structure/curtain/open/privacy, +/obj/structure/bed/padded, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/trash/candy/proteinbar, +/obj/item/trash/candy/proteinbar, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bU" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, /obj/structure/closet, +/obj/item/crowbar, /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, -/obj/random/clothing, -/obj/random/clothing, -/obj/random/gloves, /obj/random/hat, /obj/random/hat, /obj/random/hat, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/color/black, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/random/hat, +/obj/item/clothing/jumpsuit/orange, +/obj/random/gloves, +/obj/random/gloves, +/obj/item/clothing/jumpsuit/blackjumpshorts, +/obj/item/clothing/jumpsuit/black, +/obj/item/clothing/jumpsuit/black, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/clothing/jumpsuit/hazard, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/head/winterhood, +/obj/item/clothing/head/winterhood, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) "bV" = ( -/obj/effect/floor_decal/industrial/hatch/orange, -/obj/structure/table/rack, -/obj/item/clothing/suit/space/emergency, -/obj/item/clothing/suit/space/emergency, -/obj/item/clothing/head/helmet/space/emergency, -/obj/item/clothing/head/helmet/space/emergency, -/obj/item/tank/emergency/oxygen/double, -/obj/item/tank/emergency/oxygen/double, +/obj/structure/closet/crate/medical{ + dir = 4 + }, +/obj/random/firstaid, +/obj/random/firstaid, +/obj/random/firstaid, +/obj/random/firstaid, +/obj/item/med_pouch/radiation, +/obj/item/med_pouch/radiation, +/obj/item/med_pouch/toxin, +/obj/item/med_pouch/toxin, +/obj/item/med_pouch/burn, +/obj/item/med_pouch/burn, +/obj/item/med_pouch/trauma, +/obj/item/med_pouch/trauma, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, +/area/map_template/crashed_pod) +"bW" = ( +/obj/structure/chair/shuttle/black, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/abstract/submap_landmark/spawnpoint/crashed_pod_survivor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/map_template/crashed_pod) +"bX" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/medical, +/obj/structure/curtain/open/privacy, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, +/area/map_template/crashed_pod) +"bY" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/item/trash/tastybread, +/obj/item/trash/candy/proteinbar, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/obj/item/flashlight/flare/glowstick/random, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"bZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/map_template/crashed_pod) -"bW" = ( -/obj/structure/closet/crate/medical, -/obj/random/firstaid, -/obj/random/firstaid, -/obj/random/firstaid, -/obj/random/firstaid, -/obj/random/firstaid, -/obj/item/storage/firstaid/surgery, -/obj/item/storage/firstaid/stab, -/obj/item/storage/pill_bottle/antibiotics, -/obj/item/storage/pill_bottle/antibiotics, -/obj/item/storage/med_pouch/radiation, -/obj/item/storage/med_pouch/radiation, -/obj/item/storage/med_pouch/radiation, -/obj/item/storage/med_pouch/radiation, -/obj/item/storage/pill_bottle/assorted, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/alarm{ + pixel_y = -24; + dir = 1; + locked = 0 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"ca" = ( +/obj/structure/chair, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/map_template/crashed_pod) +"cb" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/effect/decal/cleanable/vomit/mapped, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"bX" = ( -/obj/structure/closet/crate, -/obj/random/handgun, -/obj/random/handgun, -/obj/random/handgun, -/obj/item/pickaxe, -/obj/item/pickaxe, -/obj/item/pickaxe, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/plasteel/fifty, -/obj/item/flashlight/lantern, -/obj/item/flashlight/lantern, -/obj/item/storage/box/glowsticks, -/obj/item/storage/box/glowsticks, -/obj/item/storage/box/glowsticks, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/random/toolbox, -/obj/random/toolbox, -/obj/random/toolbox, -/obj/random/toolbox, -/turf/simulated/floor/tiled/techfloor/grid, +"cc" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"bY" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/item/storage/bag/trash, -/obj/item/storage/bag/trash, -/obj/item/storage/box/donkpockets, -/obj/item/storage/box/donkpockets, -/obj/item/storage/fancy/egg_box, -/obj/item/storage/fancy/egg_box, -/obj/item/storage/fancy/egg_box, -/obj/item/chems/food/condiment/enzyme, -/obj/item/chems/food/drinks/milk, -/obj/item/chems/food/drinks/milk, -/obj/item/trash/liquidfood, -/obj/item/trash/liquidfood, -/obj/item/trash/liquidfood, +"cd" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/item/chems/drinks/cans/speer, /obj/item/trash/liquidfood, -/obj/item/beartrap, -/obj/item/knife/kitchen/cleaver, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/obj/item/chems/food/snacks/liquidfood, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/flashlight/flare/glowstick/random, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"bZ" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 +"kw" = ( +/obj/structure/closet/hydrant{ + pixel_x = -27 }, -/obj/machinery/power/port_gen/pacman/super, -/obj/machinery/light/small, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"ca" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/backpack/dufflebag/eng, -/obj/item/ashtray, -/obj/item/paper_bin, -/obj/item/chems/food/drinks/cans/speer, -/obj/effect/decal/cleanable/dirt, -/obj/item/pen, -/turf/simulated/floor/tiled/dark, +"nM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 22; + locked = 0 + }, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/dirt{ + dir = 9 + }, +/turf/floor/tiled/white, /area/map_template/crashed_pod) -"cb" = ( -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, -/obj/item/oxycandle, +"nQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"qc" = ( +/obj/effect/floor_decal/industrial/outline, +/obj/structure/closet/crate, /obj/item/oxycandle, /obj/item/oxycandle, /obj/item/oxycandle, @@ -1031,91 +1279,113 @@ /obj/item/oxycandle, /obj/item/oxycandle, /obj/item/oxycandle, -/obj/structure/closet/crate, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/map_template/crashed_pod) +"yo" = ( +/obj/item/bedsheet/brown, +/obj/structure/curtain/open/privacy, +/obj/structure/bed/padded, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/map_template/crashed_pod) +"Ar" = ( +/obj/item/trash/liquidfood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, +/area/map_template/crashed_pod) +"DM" = ( +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/airlock_sensor{ + dir = 4; + pixel_x = -17; + id_tag = "crashed_pod_int_sensor" }, -/obj/machinery/light/small, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/crashed_pod) -"cc" = ( +"GT" = ( +/obj/item/trash/candy/proteinbar, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"Ta" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -13 + }, +/obj/effect/decal/cleanable/vomit/mapped, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"Ut" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/tiled/techfloor, +/area/map_template/crashed_pod) +"Ys" = ( /obj/structure/table/steel_reinforced, -/obj/item/multitool, -/obj/item/screwdriver, -/obj/item/cell/device/high, -/obj/item/cell/device/high, -/obj/item/cell/crap, -/obj/item/storage/box/lights, -/obj/item/scanner/gas, -/obj/item/chems/food/drinks/cans/speer, -/obj/item/chems/food/drinks/cans/speer, -/obj/item/chems/food/drinks/cans/speer, -/obj/item/storage/box/monkeycubes, -/obj/item/chems/food/drinks/bottle/vodka, -/obj/item/chems/food/drinks/bottle/agedwhiskey, -/obj/item/tracker_electronics, -/obj/item/pen/blue, -/obj/item/pen/green, -/obj/item/pen/red, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/item/paper_bin, +/obj/structure/emergency_dispenser/west, +/obj/item/ashtray, +/obj/item/pen, +/obj/item/pen/multi, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/item/flame/fuelled/lighter/random, +/obj/random/plushie, +/obj/item/chems/drinks/bottle/agedwhiskey, +/obj/item/chems/drinks/cans/speer, +/obj/item/chems/drinks/cans/speer, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/map_template/crashed_pod) -"cd" = ( -/obj/structure/closet/crate/large/hydroponics, -/obj/item/seeds/potatoseed, -/obj/item/seeds/potatoseed, -/obj/item/seeds/wheatseed, -/obj/item/seeds/wheatseed, -/obj/item/seeds/orangeseed, -/obj/item/seeds/orangeseed, -/obj/item/seeds/cornseed, -/obj/item/seeds/cornseed, -/obj/item/hatchet, -/obj/item/chems/glass/bucket, -/obj/item/minihoe, -/obj/item/plantspray/pests, -/obj/item/plantspray/pests, -/obj/item/plantspray/weeds, -/obj/item/seeds/poppyseed, -/obj/item/seeds/corkwood, -/obj/item/seeds/glowbell, -/obj/item/seeds/whitebeetseed, -/obj/item/storage/plants, -/obj/item/seeds/bananaseed, -/turf/simulated/floor/tiled/techfloor/grid, +"Zp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 10 + }, +/obj/machinery/meter, +/turf/wall/r_wall, /area/map_template/crashed_pod) (1,1,1) = {" aa -aa -aa -aa -ab +bR +bb +ax ab ab ab ab -bb ab +ax ab ab ab +ax ab ab "} (2,1,1) = {" -ab -ab -ab -ab -ab -aE -aB -ay +bD +bu +by +aC +bm +DM +kw +Ys be ca bx -bK -ax +ay +ba bV bS ab @@ -1128,138 +1398,138 @@ aq aA aF aN -aS -bg +GT +aB bg bC -bL -bJ -bD -bD +aA bJ +aT +Ar +ax "} (4,1,1) = {" -ab -ab -ai +ac +ae +ay as ay aK aO -ay +bQ aZ bh bE bO -ab -ab -ab +nM +aE +bX ab "} (5,1,1) = {" -ac -ae +bF +aR aj ar ay aH -aV +aB +bL ay -bc bi bt -bR ay -bY -bX +ay +ay +ay ab "} (6,1,1) = {" -ab -ab +bj +aW ak at -ax -aI -ba -ax -bd +ay +aS +aB +bL +ay bk bG bv bB -bF +bv bZ -ax +ab "} (7,1,1) = {" -ab -ab +bj +aW al aG -ax +aA aI +qc aQ -ax -bj +ay bl -bw +nQ bM ay bW cc -ab +ax "} (8,1,1) = {" -ac -ae +Zp +ai am au az aP -aT ay -bc -bm -by -bQ ay ay ay -ab +aU +ay +ay +bH +bY +ax "} (9,1,1) = {" -ab +ac af an av -aD -aU -aW ay +ay +ay +bK bf bn -by +bw bU ay bH bN -ab +ax "} (10,1,1) = {" ac ag ao aw -aC +Ta aL -aX +ay aY bp bo bA bz -bB +ay bI cb ax @@ -1269,13 +1539,13 @@ ab ab ap aJ -ay +Ut aM -aR ay +bc bq -bu br +yo bT ay bP @@ -1283,10 +1553,10 @@ cd ab "} (12,1,1) = {" -aa -ab -ab -ab +aX +bd +aV +aD ab ab ab @@ -1296,7 +1566,7 @@ ax ab ab ab -ab +ax ab ab "} diff --git a/maps/random_ruins/exoplanet_ruins/datacapsule/contents_1.dmm b/maps/random_ruins/exoplanet_ruins/datacapsule/contents_1.dmm index fde1c8ee3339..9b82cda30a6a 100644 --- a/maps/random_ruins/exoplanet_ruins/datacapsule/contents_1.dmm +++ b/maps/random_ruins/exoplanet_ruins/datacapsule/contents_1.dmm @@ -6,9 +6,6 @@ /obj/structure/window/basic/full, /turf/template_noop, /area/template_noop) -"b" = ( -/turf/template_noop, -/area/template_noop) "c" = ( /obj/structure/foamedmetal, /turf/template_noop, @@ -25,7 +22,7 @@ /turf/template_noop, /area/template_noop) "g" = ( -/obj/item/stack/material/steel, +/obj/item/stack/material/sheet/mapped/steel, /obj/structure/foamedmetal, /turf/template_noop, /area/template_noop) @@ -38,8 +35,8 @@ a "} (2,1,1) = {" c -b -b +e +e c "} (3,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/datacapsule/contents_2.dmm b/maps/random_ruins/exoplanet_ruins/datacapsule/contents_2.dmm index ea28c115b099..35c3a405653d 100644 --- a/maps/random_ruins/exoplanet_ruins/datacapsule/contents_2.dmm +++ b/maps/random_ruins/exoplanet_ruins/datacapsule/contents_2.dmm @@ -1,6 +1,5 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( -/obj/machinery/telecomms/server, /obj/structure/foamedmetal, /turf/template_noop, /area/template_noop) @@ -8,14 +7,6 @@ /mob/living/simple_animal/hostile/viscerator, /turf/template_noop, /area/template_noop) -"c" = ( -/obj/structure/foamedmetal, -/turf/template_noop, -/area/template_noop) -"d" = ( -/obj/structure/foamedmetal, -/turf/template_noop, -/area/template_noop) "e" = ( /turf/template_noop, /area/template_noop) @@ -41,13 +32,13 @@ f h "} (2,1,1) = {" -c -c -c +a +a +a b "} (3,1,1) = {" -d +a e f h diff --git a/maps/random_ruins/exoplanet_ruins/datacapsule/contents_3.dmm b/maps/random_ruins/exoplanet_ruins/datacapsule/contents_3.dmm index ec21de1bbaa8..4a088ed21c92 100644 --- a/maps/random_ruins/exoplanet_ruins/datacapsule/contents_3.dmm +++ b/maps/random_ruins/exoplanet_ruins/datacapsule/contents_3.dmm @@ -34,7 +34,7 @@ /turf/template_noop, /area/template_noop) "i" = ( -/obj/effect/landmark/corpse/zombiescience, +/obj/abstract/landmark/corpse/zombiescience, /obj/structure/foamedmetal, /turf/template_noop, /area/template_noop) diff --git a/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dm b/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dm index 566b961b29ca..5fbaa19d44b8 100644 --- a/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dm +++ b/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dm @@ -1,11 +1,10 @@ /datum/map_template/ruin/exoplanet/datacapsule name = "ejected data capsule" - id = "datacapsule" description = "A damaged capsule with some strange contents." suffixes = list("datacapsule/datacapsule.dmm") cost = 1 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN|RUIN_WRECK + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WRECK apc_test_exempt_areas = list( /area/map_template/datacapsule = NO_SCRUBBER|NO_VENT|NO_APC @@ -15,18 +14,19 @@ name = "\improper Ejected Data Capsule" icon_state = "blue" -/obj/effect/landmark/corpse/zombiescience +/obj/abstract/landmark/corpse/zombiescience name = "Dead Scientist" - corpse_outfits = list(/decl/hierarchy/outfit/zombie_science) + corpse_outfits = list(/decl/outfit/zombie_science) -/decl/hierarchy/outfit/zombie_science - name = OUTFIT_JOB_NAME("Dead Scientist") - uniform = /obj/item/clothing/under/color/white +/decl/outfit/zombie_science + name = "Job - Dead Scientist" + uniform = /obj/item/clothing/jumpsuit/white suit = /obj/item/clothing/suit/bio_suit/anomaly head = /obj/item/clothing/head/bio_hood/anomaly /decl/material/liquid/zombie/science name = "isolated corruption" + uid = "liquid_corruption_isolated" lore_text = "An incredibly dark, oily substance. Moves very slightly." taste_description = "decayed blood" color = "#800000" @@ -38,8 +38,9 @@ /obj/item/chems/glass/beaker/vial/random_podchem/Initialize() . = ..() desc += "Label is smudged, and there's crusted blood fingerprints on it." - var/reagent_type = pick(/decl/material/liquid/random, /decl/material/liquid/zombie/science, /decl/material/liquid/retrovirals) - reagents.add_reagent(pick(reagent_type), 5) + +/obj/item/chems/glass/beaker/vial/random_podchem/populate_reagents() + add_to_reagents(pick(/decl/material/liquid/random, /decl/material/liquid/zombie/science, /decl/material/liquid/retrovirals), 5) /obj/structure/backup_server name = "backup server" @@ -48,28 +49,49 @@ desc = "Impact resistant server rack. You might be able to pry a disk out." var/disk_looted -/obj/structure/backup_server/attackby(obj/item/W, mob/user, var/click_params) - if(isCrowbar(W)) - to_chat(user, SPAN_NOTICE("You pry out the data drive from \the [src].")) - playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) - var/obj/item/stock_parts/computer/hard_drive/cluster/drive = new(get_turf(src)) - drive.origin_tech = "{'[TECH_DATA]':[rand(4,5)],'[TECH_ENGINEERING]':[rand(4,5)],'[TECH_EXOTIC_MATTER]':[rand(4,5)],'[TECH_COMBAT]':[rand(2,5)],'[TECH_ESOTERIC]':[rand(0,6)]}" - -/obj/effect/landmark/map_load_mark/ejected_datapod +/obj/structure/backup_server/attackby(obj/item/used_item, mob/user, var/click_params) + if(IS_CROWBAR(used_item)) + if(disk_looted) + to_chat(user, SPAN_WARNING("There's no disk in \the [src].")) + else + to_chat(user, SPAN_NOTICE("You pry out the data drive from \the [src].")) + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + var/obj/item/stock_parts/computer/hard_drive/cluster/drive = new(get_turf(src)) + drive.origin_tech = json_encode(list( + (TECH_DATA) = rand(4,5), + (TECH_ENGINEERING) = rand(4,5), + (TECH_EXOTIC_MATTER) = rand(4,5), + (TECH_COMBAT) = rand(2,5), + (TECH_ESOTERIC) = rand(0,6) + )) + disk_looted = TRUE + return TRUE + . = ..() + +#define POD_ONE "random datapod contents #1 (chem vials)" +#define POD_TWO "random datapod contents #2 (servers)" +#define POD_THREE "random datapod contents #2 (spiders)" + +/obj/abstract/landmark/map_load_mark/ejected_datapod name = "random datapod contents" - templates = list(/datum/map_template/ejected_datapod_contents, /datum/map_template/ejected_datapod_contents/type2, /datum/map_template/ejected_datapod_contents/type3) + map_template_names = list( + POD_ONE, + POD_TWO, + POD_THREE + ) /datum/map_template/ejected_datapod_contents - name = "random datapod contents #1 (chem vials)" - id = "datapod_1" + name = POD_ONE mappaths = list("maps/random_ruins/exoplanet_ruins/datacapsule/contents_1.dmm") /datum/map_template/ejected_datapod_contents/type2 - name = "random datapod contents #2 (servers)" - id = "datapod_2" + name = POD_TWO mappaths = list("maps/random_ruins/exoplanet_ruins/datacapsule/contents_2.dmm") /datum/map_template/ejected_datapod_contents/type3 - name = "random datapod contents #2 (spiders)" - id = "datapod_3" - mappaths = list("maps/random_ruins/exoplanet_ruins/datacapsule/contents_3.dmm") \ No newline at end of file + name = POD_THREE + mappaths = list("maps/random_ruins/exoplanet_ruins/datacapsule/contents_3.dmm") + +#undef POD_ONE +#undef POD_TWO +#undef POD_THREE diff --git a/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dmm b/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dmm index f0a65aae4eee..54ffd2c8813d 100644 --- a/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dmm +++ b/maps/random_ruins/exoplanet_ruins/datacapsule/datacapsule.dmm @@ -4,25 +4,25 @@ /area/template_noop) "b" = ( /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/datacapsule) "c" = ( -/obj/effect/landmark/scorcher, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) "d" = ( /obj/machinery/door/blast/shutters, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/datacapsule) "e" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/datacapsule) "f" = ( -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/map_template/datacapsule) "g" = ( -/obj/effect/landmark/map_load_mark/ejected_datapod, -/turf/simulated/floor/reinforced/airless, +/obj/abstract/landmark/map_load_mark/ejected_datapod, +/turf/floor/reinforced/airless, /area/map_template/datacapsule) (1,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dm b/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dm index 707b97828ef3..5cde3625eda5 100644 --- a/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dm +++ b/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dm @@ -1,8 +1,7 @@ /datum/map_template/ruin/exoplanet/deserted_lab name = "deserted lab" - id = "deserted_lab" description = "A mid-sized abandoned lab with some enemies, traps, and loot." suffixes = list("deserted_lab/deserted_lab.dmm") cost = 1.5 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS|TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN \ No newline at end of file + template_tags = TEMPLATE_TAG_HUMAN \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dmm b/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dmm index a8de9ec91087..39a8a4743f78 100644 --- a/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dmm +++ b/maps/random_ruins/exoplanet_ruins/deserted_lab/deserted_lab.dmm @@ -3,66 +3,66 @@ /turf/template_noop, /area/template_noop) "ab" = ( -/turf/simulated/wall/r_wall/prepainted{ +/turf/wall/r_wall/prepainted{ paint_color = "#556769" }, /area/template_noop) "ac" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "ad" = ( /obj/random/loot, /obj/effect/decal/cleanable/cobweb, /obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/mucus, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "ae" = ( /obj/random/loot, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "af" = ( /obj/structure/anomaly_container, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "ag" = ( /obj/structure/sign/warning/secure_area{ pixel_y = 32 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "ah" = ( /obj/structure/mattress/dirty, /obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "ai" = ( /obj/machinery/floodlight, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aj" = ( -/obj/structure/sign/warning/science/anomalous_materials{ +/obj/structure/sign/warning/anomalous_materials{ pixel_y = 32 }, /obj/effect/decal/cleanable/spiderling_remains, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "ak" = ( /obj/structure/artifact, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "al" = ( /obj/random/loot, /obj/effect/decal/cleanable/mucus, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "am" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "ao" = ( /obj/random/junk, @@ -70,89 +70,89 @@ /area/template_noop) "ap" = ( /obj/structure/closet/crate, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aq" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "ar" = ( /obj/structure/closet/crate/trashcart, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "as" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/effect/landmark/clear, +/obj/structure/closet/crate/plastic/rations, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "at" = ( /obj/random/loot, -/mob/living/simple_animal/hostile/voxslug, -/turf/simulated/floor/tiled/steel_ridged, +/mob/living/simple_animal/hostile/slug, +/turf/floor/tiled/steel_ridged, /area/template_noop) "au" = ( -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "av" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/random/contraband, /obj/random/masks, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "aw" = ( /obj/effect/decal/cleanable/mucus, /mob/living/simple_animal/hostile/creature, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "ax" = ( -/obj/structure/bed/chair/office/light, -/obj/structure/closet/walllocker/emerglocker/east, -/turf/simulated/floor/tiled/white, +/obj/structure/chair/office/light, +/obj/structure/emergency_dispenser/east, +/turf/floor/tiled/white, /area/template_noop) "ay" = ( -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "az" = ( /obj/structure/door/wood, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aA" = ( -/obj/structure/sign/monkey_painting{ +/obj/structure/sign/painting/monkey_painting{ pixel_y = -32 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "aB" = ( /obj/item/clothing/head/bio_hood/anomaly, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aC" = ( /obj/random/closet, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aE" = ( /obj/structure/bookcase/manuals/xenoarchaeology, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aF" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aG" = ( -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aH" = ( /obj/random/trash, /obj/random/trash, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aI" = ( /obj/machinery/door/airlock/vault{ @@ -162,60 +162,61 @@ deployed = 1; icon_state = "beartrap1" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aJ" = ( /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "aK" = ( /obj/effect/decal/cleanable/spiderling_remains, -/obj/structure/table/standard{ +/obj/structure/table{ name = "plastic table frame" }, /obj/machinery/reagentgrinder, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aL" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/firstaid, /obj/random/advdevice, /obj/random/advdevice, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "aM" = ( -/obj/effect/decal/cleanable/vomit, -/obj/item/chems/glass/paint/random, +/obj/effect/decal/cleanable/vomit/mapped, +/obj/item/chems/glass/bucket/paint/random, /obj/structure/closet/medical_wall/filled{ pixel_y = 32 }, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aN" = ( /obj/effect/decal/cleanable/mucus, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "aO" = ( /obj/machinery/door/airlock/vault{ name = "Door"; welded = null }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aP" = ( /obj/machinery/door/airlock/external/bolted, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aQ" = ( /obj/effect/decal/cleanable/cobweb2, /obj/structure/closet/cabinet, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aR" = ( /obj/structure/extinguisher_cabinet{ - pixel_x = -32 + pixel_x = -29; + dir = 4 }, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aS" = ( /obj/random/junk, @@ -226,82 +227,82 @@ /obj/machinery/door/airlock/vault{ name = "Door" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aU" = ( /obj/random/junk, -/obj/structure/bed/chair/office/light, -/turf/simulated/floor/carpet/blue2, +/obj/structure/chair/office/light, +/turf/floor/carpet/blue2, /area/template_noop) "aV" = ( /obj/item/harpoon, -/obj/effect/landmark/corpse/scientist, +/obj/abstract/landmark/corpse/scientist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "aW" = ( /obj/item/beartrap, -/obj/structure/sign/warning/science/anomalous_materials{ +/obj/structure/sign/warning/anomalous_materials{ pixel_x = 32 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "aX" = ( /obj/random/trash, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aY" = ( /obj/structure/bed/padded, /obj/item/bedsheet/purple, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "aZ" = ( /obj/structure/railing/mapped, /obj/machinery/replicator, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "ba" = ( /obj/random/snack, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "bb" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/powercell, /obj/random/voidsuit, /obj/random/voidhelmet, /obj/random/toolbox, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "bc" = ( /obj/structure/bed/padded, /obj/item/bedsheet/mime, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "bd" = ( /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "be" = ( /obj/effect/decal/cleanable/mucus, -/turf/simulated/floor/carpet/blue2, +/turf/floor/carpet/blue2, /area/template_noop) "bf" = ( /obj/random/trash, /obj/effect/decal/cleanable/blood, /obj/effect/decal/cleanable/mucus, /mob/living/simple_animal/hostile/creature, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "bg" = ( /obj/random/trash, -/obj/structure/filingcabinet/wallcabinet{ +/obj/structure/filing_cabinet/wall{ pixel_y = -32 }, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/template_noop) "za" = ( -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) diff --git a/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dm b/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dm index 8cd3e7b8ac17..ac9d41228c03 100644 --- a/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dm +++ b/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dm @@ -1,8 +1,7 @@ /datum/map_template/ruin/exoplanet/drill_site name = "drill site" - id = "drill_site" description = "A small, abandoned mining drill operation." suffixes = list("drill_site/drill_site.dmm") cost = 0.5 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS|TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN \ No newline at end of file + template_tags = TEMPLATE_TAG_HUMAN \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dmm b/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dmm index 4c8988ca6838..3e1ee2d531e6 100644 --- a/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dmm +++ b/maps/random_ruins/exoplanet_ruins/drill_site/drill_site.dmm @@ -4,84 +4,84 @@ /area/template_noop) "b" = ( /obj/random/trash, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "d" = ( /obj/random/loot, /obj/random/junk, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "e" = ( /obj/machinery/floodlight, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "f" = ( -/obj/machinery/mining/brace, -/obj/effect/landmark/clear, +/obj/structure/drill_brace, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "g" = ( /obj/structure/ore_box, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "h" = ( /obj/random/tool, -/obj/effect/landmark/clear, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "j" = ( /obj/random/tool, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "k" = ( -/obj/machinery/mining/drill, -/obj/effect/landmark/clear, +/obj/machinery/mining_drill, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "l" = ( /obj/structure/pit, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "n" = ( /obj/random/drinkbottle, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "s" = ( /obj/random/loot, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "u" = ( -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "y" = ( /obj/random/hat, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "C" = ( /obj/random/trash, -/obj/effect/landmark/clear, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "H" = ( /obj/random/powercell, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "O" = ( /obj/random/toolbox, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) diff --git a/maps/random_ruins/exoplanet_ruins/exoplanet_ruins.dm b/maps/random_ruins/exoplanet_ruins/exoplanet_ruins.dm deleted file mode 100644 index 0236edcd5180..000000000000 --- a/maps/random_ruins/exoplanet_ruins/exoplanet_ruins.dm +++ /dev/null @@ -1,5 +0,0 @@ -// Hey! Listen! Update \config\exoplanet_ruin_blacklist.txt with your new ruins! - -/datum/map_template/ruin/exoplanet - prefix = "maps/random_ruins/exoplanet_ruins/" - var/list/ruin_tags diff --git a/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dm b/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dm index 35b8ebed0b4b..e99c60570e0c 100644 --- a/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dm +++ b/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dm @@ -1,8 +1,12 @@ /datum/map_template/ruin/exoplanet/fountain name = "Fountain of Youth" - id = "planetsite_fountain" description = "The fountain of youth itself." suffixes = list("fountain/fountain_ruin.dmm") - cost = 2 + cost = 0.5 template_flags = TEMPLATE_FLAG_NO_RUINS | TEMPLATE_FLAG_CLEAR_CONTENTS - ruin_tags = RUIN_ALIEN \ No newline at end of file + template_tags = TEMPLATE_TAG_ALIEN + +/turf/wall/brick/sandstonediamond + icon_state = "reinforced_stone" + material = /decl/material/solid/stone/sandstone + reinf_material = /decl/material/solid/gemstone/diamond diff --git a/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dmm b/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dmm index a52244c3261f..695e5ebd269e 100644 --- a/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dmm +++ b/maps/random_ruins/exoplanet_ruins/fountain/fountain_ruin.dmm @@ -3,10 +3,10 @@ /turf/template_noop, /area/template_noop) "b" = ( -/turf/simulated/wall/sandstonediamond, +/turf/wall/brick/sandstonediamond, /area/template_noop) "c" = ( -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/template_noop) "e" = ( /obj/structure/fountain, diff --git a/maps/random_ruins/exoplanet_ruins/hut/hut.dm b/maps/random_ruins/exoplanet_ruins/hut/hut.dm index 0af97d4f6ecf..0115507be431 100644 --- a/maps/random_ruins/exoplanet_ruins/hut/hut.dm +++ b/maps/random_ruins/exoplanet_ruins/hut/hut.dm @@ -1,8 +1,12 @@ /datum/map_template/ruin/exoplanet/hut name = "hut" - id = "hut" description = "A small and simple little research hut." suffixes = list("hut/hut.dmm") cost = 0.5 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS|TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN|RUIN_HABITAT \ No newline at end of file + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_HABITAT + +/turf/wall/silver + icon_state = "metal" + color = COLOR_SILVER + material = /decl/material/solid/metal/silver diff --git a/maps/random_ruins/exoplanet_ruins/hut/hut.dmm b/maps/random_ruins/exoplanet_ruins/hut/hut.dmm index ebb86bba8397..a3ba0e14396d 100644 --- a/maps/random_ruins/exoplanet_ruins/hut/hut.dmm +++ b/maps/random_ruins/exoplanet_ruins/hut/hut.dmm @@ -3,58 +3,55 @@ /turf/template_noop, /area/template_noop) "b" = ( -/turf/simulated/wall/silver, -/area/template_noop) -"c" = ( -/turf/simulated/floor/tiled/dark, +/turf/wall/silver, /area/template_noop) "d" = ( /obj/random/trash, /obj/structure/inflatable/door, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "e" = ( /obj/machinery/artifact_scanpad, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "f" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "g" = ( /obj/structure/curtain/black, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/template_noop) "h" = ( /obj/structure/inflatable/door, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "i" = ( -/obj/structure/filingcabinet, +/obj/structure/filing_cabinet, /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "j" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "k" = ( -/obj/structure/bed/chair/wheelchair, -/turf/simulated/floor/tiled/dark, +/obj/structure/chair/wheelchair, +/turf/floor/tiled/dark, /area/template_noop) "l" = ( /obj/structure/table/marble, /obj/item/flashlight/lamp, -/obj/structure/sign/monkey_painting{ +/obj/structure/sign/painting/monkey_painting{ pixel_y = -32 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "m" = ( /obj/structure/table/marble, /obj/item/paper_bin, /obj/random/voidhelmet, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "n" = ( /obj/structure/gravemarker/random, @@ -62,46 +59,46 @@ /area/template_noop) "o" = ( /obj/structure/bookcase/manuals/xenoarchaeology, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "p" = ( /obj/random/junk, /obj/random/loot, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "q" = ( /obj/item/pen/multi, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "r" = ( /mob/living/bot/medbot, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "t" = ( /obj/structure/bed, /obj/item/bedsheet/rainbow, /obj/random/drinkbottle, /obj/random/trash, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/template_noop) "u" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/glasses/eyepatch/hud/medical, /obj/random/loot, /obj/random/loot, /obj/random/hat, /obj/random/voidsuit, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "G" = ( -/obj/structure/sign/science_1{ +/obj/structure/sign/department/science_1{ pixel_y = 32 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/template_noop) "K" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) (1,1,1) = {" @@ -125,8 +122,8 @@ b (3,1,1) = {" b o -c -c +f +f q l b @@ -134,7 +131,7 @@ b (4,1,1) = {" b j -c +f r k m @@ -153,7 +150,7 @@ b a d h -c +f g t b diff --git a/maps/random_ruins/exoplanet_ruins/hydrobase/farmbot.dmi b/maps/random_ruins/exoplanet_ruins/hydrobase/farmbot.dmi new file mode 100644 index 000000000000..126d4a3b1d9c Binary files /dev/null and b/maps/random_ruins/exoplanet_ruins/hydrobase/farmbot.dmi differ diff --git a/maps/random_ruins/exoplanet_ruins/hydrobase/hydro.dmi b/maps/random_ruins/exoplanet_ruins/hydrobase/hydro.dmi index 14cfda90a9fa..30c8f4d104c1 100644 Binary files a/maps/random_ruins/exoplanet_ruins/hydrobase/hydro.dmi and b/maps/random_ruins/exoplanet_ruins/hydrobase/hydro.dmi differ diff --git a/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dm b/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dm index 956d51b63ee2..eb2c3e60c687 100644 --- a/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dm +++ b/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dm @@ -1,11 +1,10 @@ /datum/map_template/ruin/exoplanet/hydrobase name = "hydroponics base" - id = "exoplanet_hydrobase" - description = "hydroponics base with random plants and a lot of enemies" + description = "A hydroponics base with random plants and a lot of enemies." suffixes = list("hydrobase/hydrobase.dmm") cost = 2 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_ALIEN + template_tags = TEMPLATE_TAG_ALIEN apc_test_exempt_areas = list( /area/map_template/hydrobase = NO_SCRUBBER|NO_VENT|NO_APC, /area/map_template/hydrobase/station = NO_SCRUBBER, @@ -82,47 +81,41 @@ // Mobs // -/mob/living/simple_animal/hostile/retaliate/goat/hydro +/mob/living/simple_animal/hostile/goat/hydro name = "goat" desc = "An impressive goat, in size and coat. His horns look pretty serious!" - health = 100 - maxHealth = 100 + max_health = 100 natural_weapon = /obj/item/natural_weapon/hooves/strong faction = "farmbots" /obj/item/natural_weapon/hooves/strong - force = 15 + _base_attack_force = 15 -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro +/mob/living/simple_animal/hostile/malf_drone/hydro name = "Farmbot" desc = "The botanist's best friend. There's something slightly odd about the way it moves." - icon = 'maps/random_ruins/exoplanet_ruins/hydrobase/hydro.dmi' - speak = list("Initiating harvesting subrout-ine-ine.", "Connection timed out.", "Connection with master AI syst-tem-tem lost.", "Core systems override enab-...") - emote_see = list("beeps repeatedly", "whirrs violently", "flashes its indicator lights", "emits a ping sound") - icon_state = "farmbot" - icon_living = "farmbot" - icon_dead = "farmbot_dead" + icon = 'maps/random_ruins/exoplanet_ruins/hydrobase/farmbot.dmi' faction = "farmbots" - health = 225 - maxHealth = 225 + max_health = 225 + ai = /datum/mob_controller/aggressive/malf_drone/hydro + +/datum/mob_controller/aggressive/malf_drone/hydro malfunctioning = 0 + emote_speech = list("Initiating harvesting subrout-ine-ine.", "Connection timed out.", "Connection with master AI syst-tem-tem lost.", "Core systems override enab-...") + emote_see = list("beeps repeatedly", "whirrs violently", "flashes its indicator lights", "emits a ping sound") -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro/Initialize() +/mob/living/simple_animal/hostile/malf_drone/hydro/Initialize() . = ..() if(prob(15)) projectiletype = /obj/item/projectile/beam/drone/weak -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro/emp_act(severity) - health -= rand(5,10) * (severity + 1) +/mob/living/simple_animal/hostile/malf_drone/hydro/emp_act(severity) + take_damage(rand(5, 10) * (severity + 1)) disabled = rand(15, 30) - malfunctioning = 1 - hostile_drone = 1 - destroy_surroundings = 1 + var/datum/mob_controller/aggressive/malf_drone/drone_brain = ai + if(istype(drone_brain)) + drone_brain.malfunctioning = 1 + drone_brain.hostile_drone = 1 + drone_brain.try_destroy_surroundings = TRUE projectiletype = initial(projectiletype) - walk(src,0) - -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro/ListTargets() - if(hostile_drone) - return view(src, 3) - else - return ..() + stop_automove() diff --git a/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dmm b/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dmm index a883b99d1ce2..102a1b78168d 100644 --- a/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dmm +++ b/maps/random_ruins/exoplanet_ruins/hydrobase/hydrobase.dmm @@ -3,21 +3,21 @@ /turf/template_noop, /area/template_noop) "ab" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growX) "ac" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/structure/catwalk, /obj/item/seeds/random, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growX) "ad" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growX) "ae" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growX) "af" = ( /obj/machinery/portable_atmospherics/hydroponics, @@ -26,34 +26,27 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/fixed/alium, -/area/map_template/hydrobase/station/growX) -"ag" = ( -/mob/living/bot/farmbot{ - faction = "farmbots" - }, -/turf/simulated/floor/tiled/dark, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growX) "ah" = ( /obj/machinery/portable_atmospherics/powered/scrubber, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growX) "ai" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growX) "ak" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growX) "al" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "am" = ( /obj/machinery/portable_atmospherics/hydroponics, @@ -61,270 +54,248 @@ /obj/item/seeds/random, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growX) "an" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/structure/catwalk, /obj/item/seeds/random, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growX) "ao" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/tobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "ap" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/tobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "aq" = ( -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "ar" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -38; - pixel_y = 0 + pixel_x = -38 }, /obj/effect/floor_decal/floordetail/edgedrain, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growX) "as" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/effect/floor_decal/floordetail/edgedrain, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growX) "at" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growD) "au" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growD) "av" = ( -/mob/living/bot/farmbot{ - faction = "farmbots" - }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "aw" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/goatzone) "ax" = ( /obj/structure/lattice, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/goatzone) "ay" = ( /obj/structure/sign/warning/biohazard, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growX) "az" = ( /obj/effect/floor_decal/industrial/hatch/yellow, /obj/machinery/door/airlock/virology, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growX) "aA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/hatch/yellow, /obj/machinery/door/airlock/virology, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growX) "aB" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/ambrosiavulgarisseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growD) "aC" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/ambrosiavulgarisseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growD) "aD" = ( /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growD) -"aE" = ( -/turf/simulated/floor/tiled/white, -/area/map_template/hydrobase/station/growA) "aF" = ( /obj/machinery/firealarm{ dir = 8; - pixel_x = -38; - pixel_y = 0 + pixel_x = -38 }, -/obj/item/clothing/accessory/armband/hydro, -/turf/simulated/floor/tiled/dark, +/obj/item/clothing/armband/hydro, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "aG" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "aH" = ( -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/hydrobase/station/goatzone) "aI" = ( /obj/structure/disposaloutlet, /obj/structure/disposalpipe/trunk{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "aJ" = ( /obj/structure/disposalpipe/segment{ dir = 2; icon_state = "pipe-c" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/goatzone) "aK" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growF) "aL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "aM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "aN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "aO" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/ambrosiadeusseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growD) "aP" = ( -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growD) "aQ" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "aR" = ( /obj/item/trash/cigbutt/woodbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "aS" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/tobaccoseed, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "aT" = ( /obj/item/trash/cigbutt/menthol, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "aU" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, -/mob/living/simple_animal/hostile/retaliate/goat/hydro, -/turf/simulated/floor/tiled/dark, +/mob/living/simple_animal/hostile/goat/hydro, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "aV" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/hydrobase/station/goatzone) "aW" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/structure/catwalk, /obj/item/seeds/whitebeetseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/goatzone) "aX" = ( /obj/structure/disposalpipe/segment{ dir = 1; icon_state = "pipe-c" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/goatzone) "aY" = ( /obj/structure/disposalpipe/trunk{ @@ -336,129 +307,109 @@ }, /obj/structure/sign/warning/moving_parts{ name = "\improper FEEDING CHUTE"; - pixel_x = 0; pixel_y = 32 }, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growF) "aZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "ba" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bb" = ( /obj/structure/catwalk, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/ambrosiadeusseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growD) "bc" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "bd" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/mob/living/simple_animal/hostile/retaliate/goat/hydro, -/turf/simulated/floor/tiled/dark, +/mob/living/simple_animal/hostile/goat/hydro, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "be" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "bf" = ( /obj/effect/floor_decal/industrial/warning/cee, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/growF) "bg" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bh" = ( /obj/structure/lattice, /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/wheatseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) -"bi" = ( -/mob/living/bot/farmbot{ - faction = "farmbots" - }, -/turf/simulated/floor/tiled/white, -/area/map_template/hydrobase/station/growD) "bj" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bk" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, /obj/machinery/light, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "bl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "bm" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, @@ -469,39 +420,34 @@ id_tag = "goatzone"; name = "Containment Zone" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/goatzone) "bn" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bp" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/pumpkinseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "bq" = ( /obj/structure/lattice, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growF) "br" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/firealarm{ @@ -509,53 +455,51 @@ pixel_x = 39; pixel_y = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bs" = ( /obj/structure/catwalk, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/tobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "bt" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "bu" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growA) "bv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "bw" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/tobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "bx" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "by" = ( /obj/effect/floor_decal/industrial/warning{ @@ -565,19 +509,17 @@ name = "\improper DO NOT ENTER - FOR AI USE ONLY"; pixel_y = 32 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bz" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bA" = ( /obj/effect/floor_decal/industrial/warning{ @@ -586,386 +528,337 @@ /obj/machinery/button/blast_door{ id_tag = "goatzone"; name = "containment zone control"; - pixel_w = 0; - pixel_x = 0; pixel_y = 25 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bB" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/light{ dir = 1 }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bC" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bE" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/whitebeetseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "bF" = ( /obj/machinery/mech_recharger, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "bG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "bH" = ( /obj/item/trash/cigbutt/woodbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bI" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bJ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bK" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/whitebeetseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "bL" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bM" = ( /obj/item/trash/cigbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bN" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bO" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bP" = ( /obj/machinery/door/airlock/virology, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "bQ" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "bR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "bS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "bT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "bU" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "bV" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bW" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bX" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bY" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growF) "bZ" = ( /obj/machinery/mech_recharger, -/mob/living/bot/farmbot{ - faction = "farmbots" - }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growF) "ca" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "cb" = ( /obj/structure/catwalk, /obj/machinery/light, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/ambrosiadeusseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growD) "cc" = ( /obj/structure/cable/yellow, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - icon_state = "apc0"; pixel_x = 25 }, /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/tiled/white, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growD) "cd" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "ce" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -38; - pixel_y = 0 + pixel_x = -38 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cf" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "ch" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "ci" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/item/trash/cigbutt/woodbutt, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cj" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "ck" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cl" = ( /obj/machinery/seed_extractor, /obj/machinery/seed_storage/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cm" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growC) "cn" = ( /obj/machinery/light{ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "co" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/item/trash/cigbutt/menthol, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "cp" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "cq" = ( /obj/structure/closet/secure_closet/hydroponics/hydro, -/obj/item/hatchet/machete, -/turf/simulated/floor/tiled, +/obj/item/tool/machete, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cr" = ( /obj/structure/closet/secure_closet/hydroponics/hydro, /obj/item/scythe, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cs" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "ct" = ( /obj/item/knife/kitchen, /obj/structure/table/glass/pglass, /obj/item/ashtray, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cu" = ( /obj/machinery/seed_extractor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cv" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cw" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/lemonseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cx" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/glowberryseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cy" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/goldappleseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cz" = ( /obj/structure/catwalk, @@ -974,24 +867,23 @@ }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/garlicseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cA" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/eggplantseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cB" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/cornseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cC" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/firealarm{ @@ -1000,19 +892,17 @@ pixel_y = 4 }, /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growC) "cD" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/puretobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "cE" = ( /obj/machinery/atmospherics/unary/tank/air{ @@ -1022,18 +912,17 @@ /obj/structure/window/borosilicate_reinforced{ dir = 1 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "cF" = ( /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ - icon_state = "map"; dir = 1 }, /obj/structure/window/borosilicate_reinforced{ dir = 1 }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "cG" = ( /obj/machinery/atmospherics/binary/pump{ @@ -1044,13 +933,12 @@ }, /obj/structure/catwalk, /obj/random/toolbox, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/zipgun, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "cH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, /obj/structure/window/borosilicate_reinforced{ @@ -1061,18 +949,16 @@ }, /obj/structure/catwalk, /obj/machinery/fabricator, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "cI" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cJ" = ( /obj/structure/table/glass/pglass, @@ -1080,67 +966,57 @@ /obj/item/seeds/random, /obj/item/seeds/random, /obj/item/gun/energy/floragun, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cK" = ( /obj/machinery/biogenerator, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "cL" = ( -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "cM" = ( -/obj/machinery/power/solar{ - id = "hydrosolar" - }, +/obj/machinery/power/solar, /obj/effect/floor_decal/solarpanel, /obj/structure/cable{ - icon_state = "0-2"; - dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-4" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "cN" = ( /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "cO" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/chiliseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "cP" = ( -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growC) "cQ" = ( /obj/item/trash/cigbutt/woodbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "cR" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "cS" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - icon_state = "apc0"; pixel_x = 25 }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "cT" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/catwalk, @@ -1149,108 +1025,98 @@ }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/puretobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "cU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "cV" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "cW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "cX" = ( /obj/item/trash/cigbutt/woodbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "cY" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/puretobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "cZ" = ( /obj/machinery/atmospherics/unary/tank/air{ dir = 4; start_pressure = 740.5 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "da" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 9 }, /obj/machinery/light, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "db" = ( /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "dc" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ pixel_y = -25 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growF) "dd" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "de" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "df" = ( /obj/machinery/vending/hydronutrients, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "dg" = ( /turf/template_noop, /area/map_template/hydrobase/solars) "dh" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "di" = ( /obj/machinery/light{ @@ -1259,122 +1125,99 @@ /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/grassseed, -/turf/simulated/floor/fixed/alium, -/area/map_template/hydrobase/station/growC) -"dj" = ( -/mob/living/bot/farmbot{ - faction = "farmbots" - }, -/turf/simulated/floor/tiled/white, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dk" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/quantumatoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dl" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/tomatoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dm" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/bluetomatoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dn" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/greengrapeseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "do" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/bananaseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dp" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "dq" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "dr" = ( /obj/machinery/door/airlock/virology, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "ds" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "dt" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "du" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "dv" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1384,104 +1227,86 @@ icon_state = "ai-crash"; name = "inactive AI" }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "dw" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "dx" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "dy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/virology, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/growF) "dz" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growF) "dA" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growF) "dB" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growF) "dC" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growF) "dD" = ( /obj/structure/cable{ icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "dE" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/peppercornseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dF" = ( /obj/item/trash/cigbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growC) "dG" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "dH" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, @@ -1489,101 +1314,92 @@ faction = "farmbots"; name = "Steward Stewart" }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "dI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/puretobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "dJ" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/processing) "dK" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/machinery/reagentgrinder/juicer, /obj/structure/table/glass/pglass, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dL" = ( /obj/structure/catwalk, /obj/structure/closet/shipping_wall/filled{ - pixel_x = 0; pixel_y = 32 }, /obj/structure/table/glass/pglass, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dM" = ( /obj/structure/catwalk, -/obj/item/kitchen/utensil/spoon, +/obj/item/utensil/spoon, /obj/structure/table/glass/pglass, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dN" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/obj/machinery/smartfridge/drying_rack, -/turf/simulated/floor/fixed/alium, +/obj/machinery/smartfridge/drying_oven, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "dP" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/sign/warning/smoking{ - pixel_x = 0; pixel_y = 32 }, -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "dQ" = ( /obj/structure/table/glass/pglass, -/obj/item/storage/box/pillbottles, -/obj/item/storage/box/pillbottles, +/obj/item/box/pillbottles, +/obj/item/box/pillbottles, /obj/item/chems/glass/beaker/vial/random, /obj/item/chems/glass/beaker/vial/random, /obj/item/chems/glass/beaker/vial/random, /obj/item/chems/glass/beaker/vial/random, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "dR" = ( -/obj/machinery/power/solar_control/autostart{ - id = "hydrosolar"; - track = 2 - }, +/obj/machinery/power/solar_control/autostart, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, /obj/structure/cable, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dS" = ( /obj/machinery/power/terminal{ @@ -1594,152 +1410,141 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dT" = ( /obj/machinery/power/smes/buildable/max_cap_in_out, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "dU" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/processing) "dV" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /turf/template_noop, /area/map_template/hydrobase/solars) "dW" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; desc = "A flexible superconducting cable for heavy-duty power transfer. It's been labeled 'chaos reigns'."; icon_state = "2-8" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "dX" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/onionseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dY" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/peanutseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "dZ" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/potatoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "ea" = ( /obj/structure/catwalk, /obj/machinery/light, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/riceseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "eb" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/sugarcaneseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "ec" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/soyaseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "ed" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/poisonberryseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growC) "ee" = ( /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growC) "ef" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/finetobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "eg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/puretobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "eh" = ( /obj/structure/catwalk, -/obj/item/kitchen/rollingpin, +/obj/item/rollingpin, /obj/item/knife/kitchen, /obj/structure/table/glass/pglass, /obj/item/ashtray, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "ei" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "ej" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "ek" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "el" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "em" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "en" = ( /obj/machinery/chem_master, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eo" = ( /obj/structure/closet/toolcloset, @@ -1748,63 +1553,57 @@ }, /obj/structure/window/borosilicate_reinforced, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "ep" = ( /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "eq" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable/yellow, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/window/borosilicate_reinforced, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "er" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/solarlock) "es" = ( /obj/effect/floor_decal/industrial/warning/corner, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "et" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "eu" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "ev" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -38; - pixel_y = 0 + pixel_x = -38 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "ew" = ( /obj/machinery/door/airlock/virology, @@ -1812,56 +1611,52 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/processing) "ex" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "ey" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "ez" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eA" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ - icon_state = "map_universal"; dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eC" = ( /obj/machinery/atmospherics/binary/pump/on{ dir = 4; target_pressure = 200 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eD" = ( /obj/machinery/atmospherics/pipe/manifold/hidden{ - icon_state = "map"; dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/button/access/interior{ id_tag = "solars_airlock"; @@ -1870,21 +1665,16 @@ pixel_y = -24 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eE" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/machinery/door/airlock/external{ icon_state = "door_locked"; @@ -1894,20 +1684,17 @@ }, /obj/structure/catwalk, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/solarlock) "eF" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "solars_airlock"; @@ -1916,12 +1703,11 @@ tag_airpump = "solars_pump"; tag_chamber_sensor = "solars_sensor"; tag_exterior_door = "solars_outer"; - tag_interior_door = "solars_inner" + tag_interior_door = "solars_inner"; + dir = 1 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; - icon_state = "apc0"; - pixel_x = 0; pixel_y = 25 }, /obj/structure/catwalk, @@ -1929,19 +1715,17 @@ dir = 1 }, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/solarlock) "eG" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/airlock_sensor{ id_tag = "solars_sensor"; - pixel_x = 0; pixel_y = 25 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -1949,7 +1733,7 @@ id_tag = "solars_pump" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/solarlock) "eH" = ( /obj/machinery/door/airlock/external{ @@ -1959,12 +1743,12 @@ name = "EVA External Access" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/solarlock) "eI" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/button/access/exterior{ id_tag = "solars_airlock"; @@ -1973,113 +1757,94 @@ pixel_y = 24 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - icon_state = "0-2"; - dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "1-4" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "eJ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "eK" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "eL" = ( -/obj/machinery/power/tracker{ - id = "hydrosolar" - }, +/obj/machinery/power/tracker, /obj/structure/cable{ - icon_state = "0-1"; - dir = 4 + icon_state = "0-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "eM" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "eN" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/growB) "eO" = ( /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growB) "eP" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/amanitamycelium, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "eQ" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/amanitamycelium, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "eR" = ( /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - icon_state = "apc0"; pixel_x = 25 }, /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growB) "eS" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; - icon_state = "apc0"; pixel_x = -25 }, /obj/structure/cable/yellow, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "eT" = ( /obj/structure/catwalk, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, /obj/machinery/light{ @@ -2087,15 +1852,14 @@ }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -38; - pixel_y = 0 + pixel_x = -38 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "eU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/item/trash/cigbutt/woodbutt, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eW" = ( /obj/structure/catwalk, @@ -2113,49 +1877,41 @@ /obj/item/chems/pill/zoom, /obj/item/chems/pill/zoom, /obj/item/chems/pill/zoom, -/obj/item/toy/crossbow{ - desc = "A minature crossbow that fires some sort of dart from an internal magazine."; +/obj/item/gun/launcher/foam/crossbow{ + desc = "A miniature crossbow that fires some sort of dart from an internal magazine."; name = "mini-crossbow" }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "eX" = ( /obj/structure/closet/l3closet/general/multi, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "eZ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/item/shreddedp, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "fa" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/catwalk, @@ -2163,126 +1919,116 @@ dir = 8 }, /obj/item/shard/borosilicate, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fb" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fc" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/catwalk, /obj/structure/window/borosilicate_reinforced{ dir = 1 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fd" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/solarlock) "fe" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "ff" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "fg" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 + dir = 1; + icon_state = "warningcorner" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/template_noop) "fh" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "fi" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "fj" = ( -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growB) "fk" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "fl" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "fm" = ( /obj/machinery/door/airlock/virology, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "fn" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growA) "fo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "fp" = ( /obj/structure/catwalk, /obj/machinery/button/blast_door{ id_tag = "shipping"; - pixel_x = -25 + pixel_x = -25; + dir = 4 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "fr" = ( /obj/structure/catwalk, @@ -2291,8 +2037,7 @@ /obj/random/coin, /obj/structure/closet/crate/secure/weapon{ desc = "A heavy-duty crate with a suite of firearms safety instructions plastered on the side. The ID scanner is unlike anything you've seen before."; - name = "weapons crate"; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_HACKED") }, /obj/random/projectile, /obj/item/knife/combat, @@ -2300,26 +2045,24 @@ /obj/random/cash, /obj/random/cash, /obj/random/handgun, -/obj/item/stack/material/diamond/ten, -/obj/item/stack/material/gold/ten, -/obj/item/stack/material/gold/ten, -/turf/simulated/floor/fixed/alium, +/obj/item/stack/material/gemstone/mapped/diamond/ten, +/obj/item/stack/material/ingot/mapped/gold/ten, +/obj/item/stack/material/ingot/mapped/gold/ten, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/processing) "ft" = ( /obj/machinery/light, /obj/structure/window/borosilicate_reinforced{ dir = 8 }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/ammo_casing/shotgun/emp, /obj/item/ammo_casing/shotgun/emp, /obj/item/gun/projectile/shotgun/doublebarrel, @@ -2328,14 +2071,14 @@ }, /obj/item/grenade/chem_grenade/antiweed, /obj/item/grenade/chem_grenade/incendiary, -/obj/item/weedkiller/D24, +/obj/item/plantspray/weedkiller/D24, /obj/item/shard/borosilicate, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/processing) "fu" = ( -/obj/structure/dispenser/oxygen, +/obj/structure/tank_rack/oxygen, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fv" = ( /obj/machinery/portable_atmospherics/canister/air/airlock, @@ -2344,29 +2087,28 @@ }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/processing) "fw" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "fx" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/reishimycelium, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "fy" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/angelmycelium, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "fz" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/firealarm{ @@ -2374,21 +2116,21 @@ pixel_x = 39; pixel_y = 4 }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growB) "fA" = ( /obj/machinery/light, /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "fB" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/shipaccess) "fC" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/hydrobase/station/shipaccess) "fD" = ( /obj/machinery/atmospherics/binary/pump/on, @@ -2397,66 +2139,50 @@ id_tag = "shipping" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/shipaccess) "fE" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/shower) "fF" = ( /obj/machinery/door/airlock/virology, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "fG" = ( -/obj/machinery/power/solar{ - id = "hydrosolar" - }, +/obj/machinery/power/solar, /obj/effect/floor_decal/solarpanel, /obj/structure/cable{ - icon_state = "0-2"; - dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 + icon_state = "0-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "fH" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "fI" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "fJ" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "fK" = ( /obj/machinery/light{ @@ -2465,114 +2191,98 @@ /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/finetobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "fL" = ( /obj/structure/catwalk, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/finetobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "fM" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/catwalk, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/shipaccess) "fN" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/shipaccess) "fO" = ( /obj/structure/catwalk, /obj/machinery/button/blast_door{ id_tag = "shipping"; - pixel_x = 25 + pixel_x = 25; + dir = 8 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/shipaccess) "fP" = ( /obj/machinery/washing_machine, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; - icon_state = "apc0"; - pixel_x = 0; pixel_y = 25 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "fQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "fR" = ( /obj/structure/curtain/open/shower, /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, /obj/item/bikehorn/rubberducky, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "fS" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, -/obj/item/seeds/corkwood, -/turf/simulated/floor/fixed/alium, -/area/map_template/hydrobase/station/growB) -"fT" = ( -/mob/living/bot/farmbot{ - faction = "farmbots" - }, -/turf/simulated/floor/tiled/white, +/obj/item/seeds/towercap, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "fU" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "fV" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, /obj/machinery/light{ - icon_state = "tube1"; - dir = 1 + dir = 1; + icon_state = "tube1" }, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/bluegrid, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/bluegrid, /area/map_template/hydrobase/station/growA) "fW" = ( /obj/machinery/light/small{ @@ -2583,24 +2293,21 @@ id_tag = "hydrodock_airlock"; name = "interior access button"; pixel_x = -24; - pixel_y = 0; - req_access = newlist() + req_access = newlist(); + dir = 4 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/shipaccess) "fX" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/shipaccess) "fY" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/light/small{ @@ -2612,7 +2319,7 @@ pixel_x = 39; pixel_y = 4 }, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/shipaccess) "fZ" = ( /obj/machinery/light{ @@ -2621,36 +2328,33 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "ga" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gb" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gc" = ( /obj/structure/catwalk, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/portable_atmospherics/hydroponics, -/obj/item/seeds/corkwood, -/turf/simulated/floor/fixed/alium, +/obj/item/seeds/towercap, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "gd" = ( /obj/item/trash/cigbutt, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "ge" = ( /obj/machinery/portable_atmospherics/canister/air/airlock, @@ -2659,25 +2363,20 @@ }, /obj/effect/floor_decal/industrial/warning, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/shipaccess) "gf" = ( /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4; - icon_state = "map" + dir = 4 }, /obj/effect/floor_decal/industrial/warning, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/shipaccess) "gg" = ( /obj/effect/floor_decal/industrial/warning, @@ -2685,67 +2384,58 @@ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/shipaccess) "gh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gj" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gk" = ( /obj/structure/curtain/open/shower, /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gl" = ( /obj/structure/lattice, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/shower) "gm" = ( /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/chantermycelium, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "gn" = ( -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/dockport) "go" = ( /obj/machinery/atmospherics/pipe/simple/hidden, @@ -2756,27 +2446,24 @@ name = "Shipping Internal Access" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/dockport) "gp" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/hydrobase/station/dockport) "gq" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gr" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/firealarm{ @@ -2784,90 +2471,85 @@ pixel_x = 39; pixel_y = 4 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gs" = ( /obj/structure/catwalk, /obj/machinery/light, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/chantermycelium, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growB) "gt" = ( /obj/machinery/mech_recharger, -/mob/living/simple_animal/hostile/retaliate/malf_drone/hydro, -/turf/simulated/floor/tiled/white, +/mob/living/simple_animal/hostile/malf_drone/hydro, +/turf/floor/tiled/white, /area/map_template/hydrobase/station/growB) "gu" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/machinery/airlock_sensor{ id_tag = "hydrodock_sensor"; - pixel_x = 0; pixel_y = 25 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/dockport) "gv" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8; - icon_state = "map" + dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/dockport) "gw" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "hydrodock_pump" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/dockport) "gx" = ( -/obj/item/clothing/under/overalls, +/obj/item/clothing/suit/apron/overalls/laborer, /obj/item/clothing/shoes/jackboots/desertboots, /obj/structure/closet, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gy" = ( -/obj/item/clothing/accessory/toggleable/hawaii/random, -/obj/item/clothing/under/casual_pants/greyjeans, +/obj/item/clothing/shirt/hawaii/random, +/obj/item/clothing/pants/casual/greyjeans, /obj/item/clothing/head/bowler, /obj/item/clothing/shoes/craftable, /obj/structure/closet, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gz" = ( -/obj/item/clothing/under/skirt_c/dress/black, +/obj/item/clothing/skirt, /obj/item/clothing/head/beret/purple, /obj/item/clothing/shoes/dress, /obj/structure/closet, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/hydrobase/station/shower) "gA" = ( /obj/machinery/oxygen_pump{ @@ -2878,11 +2560,11 @@ id_tag = "hydrodock_pump" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/dockport) "gB" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/dockport) "gC" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -2893,35 +2575,32 @@ id_tag = "hydrodock_airlock"; name = "Shipping Airlock Console"; pixel_x = 24; - pixel_y = 0; req_access = newlist(); tag_airpump = "hydrodock_pump"; tag_chamber_sensor = "hydrodock_sensor"; tag_exterior_door = "hydrodock_outer"; - tag_interior_door = "hydrodock_inner" + tag_interior_door = "hydrodock_inner"; + dir = 8 }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/dockport) "gD" = ( -/obj/machinery/power/solar{ - id = "hydrosolar" - }, +/obj/machinery/power/solar, /obj/effect/floor_decal/solarpanel, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/fixed/alium/airless, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "gE" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/fixed/alium/airless, +/turf/floor/fixed/alium/airless, /area/map_template/hydrobase/solars) "gF" = ( /obj/effect/floor_decal/industrial/warning, @@ -2933,13 +2612,13 @@ id_tag = "hydrodock_pump" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/dockport) "gG" = ( /obj/effect/floor_decal/industrial/warning, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/hydrobase/station/dockport) "gH" = ( /obj/effect/floor_decal/industrial/warning, @@ -2951,18 +2630,18 @@ id_tag = "hydrodock_pump" }, /obj/structure/catwalk, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/dockport) "gI" = ( /obj/machinery/light, /obj/structure/catwalk, /obj/machinery/portable_atmospherics/hydroponics, /obj/item/seeds/finetobaccoseed, -/turf/simulated/floor/fixed/alium, +/turf/floor/fixed/alium, /area/map_template/hydrobase/station/growA) "gJ" = ( /obj/structure/sign/warning/smoking, -/turf/simulated/wall/alium, +/turf/wall/alium, /area/map_template/hydrobase/station/dockport) "gK" = ( /obj/machinery/door/airlock/external{ @@ -2971,7 +2650,7 @@ locked = 1; name = "Shipping Access" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/dockport) "gL" = ( /obj/machinery/button/access/exterior{ @@ -2981,15 +2660,15 @@ pixel_y = 24; req_access = newlist() }, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "NL" = ( -/mob/living/simple_animal/hostile/retaliate/goat/hydro, -/turf/simulated/floor/tiled/dark, +/mob/living/simple_animal/hostile/goat/hydro, +/turf/floor/tiled/dark, /area/map_template/hydrobase/station/goatzone) "RI" = ( -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) @@ -3180,7 +2859,7 @@ aD cm cw cP -dj +cR cP dX cm @@ -3295,7 +2974,7 @@ au aC aQ aC -bi +aQ aQ aP aQ @@ -3311,7 +2990,7 @@ eQ fi fj fi -fT +fi fx fi fj @@ -3580,26 +3259,26 @@ al al ap aq -aE -aE -aE -aE +av +av +av +av aq bR -aE -aE -aE -aE +av +av +av +av dt cU -aE -aE +av +av cX bR aq -aE -aE -aE +av +av +av aT aq ef @@ -3620,12 +3299,12 @@ al al ap aq -aE -aE -aE -aE +av +av +av +av bt -aE +av bS bG bG @@ -3637,12 +3316,12 @@ bG bG bG fo -aE +av bt -aE -aE -aE -aE +av +av +av +av aq ef al @@ -3661,7 +3340,7 @@ al ao aq av -aE +av aS aS bk @@ -3683,7 +3362,7 @@ bu fV ef ef -aE +av av aq gI @@ -3702,9 +3381,9 @@ al al ap aq -aE -aE -aE +av +av +av bl bv bG @@ -3722,9 +3401,9 @@ bT bG bv cW -aE -aE -aE +av +av +av aq ef al @@ -3745,26 +3424,26 @@ al ap aq aT -aE -aE -aE +av +av +av aq aq -aE -aE -aE +av +av +av cX dw -aE -aE -aE -aE +av +av +av +av aq aq -aE -aE -aE -aE +av +av +av +av aq ef al @@ -3799,8 +3478,8 @@ dx dI eg cU -aE -aE +av +av aq fL ef @@ -4187,7 +3866,7 @@ ab ac ad ad -ag +ad ai ak ak diff --git a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm index d0b8dcbf888b..893ebdb5c648 100644 --- a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm +++ b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm @@ -1,11 +1,10 @@ /datum/map_template/ruin/exoplanet/lodge name = "lodge" - id = "lodge" description = "A wood cabin." suffixes = list("lodge/lodge.dmm") cost = 1 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN|RUIN_HABITAT + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_HABITAT -/turf/simulated/floor/wood/usedup +/turf/floor/wood/usedup initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD) \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm index 87e96f867d74..a98e2f8fec67 100644 --- a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm +++ b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dmm @@ -3,76 +3,74 @@ /turf/template_noop, /area/template_noop) "b" = ( -/turf/simulated/wall/wood, +/turf/wall/wood, /area/template_noop) "c" = ( -/obj/machinery/power/port_gen/pacman, -/turf/simulated/floor/wood, +/obj/machinery/port_gen/pacman, +/turf/floor/wood, /area/template_noop) "d" = ( /obj/structure/closet/cabinet, -/obj/item/clothing/under/color/black, +/obj/item/clothing/jumpsuit/black, /obj/item/clothing/shoes/jackboots/jungleboots, /obj/item/clothing/mask/breath, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/template_noop) "e" = ( -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/template_noop) "f" = ( /obj/structure/bed, /obj/item/bedsheet, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/template_noop) "g" = ( /obj/structure/window/reinforced/full, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "h" = ( -/obj/structure/table/woodentable, +/obj/structure/table/wood, /obj/item/board, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "i" = ( /obj/item/flashlight/lamp/green, -/obj/structure/table/woodentable, -/turf/simulated/floor/carpet/green, +/obj/structure/table/wood, +/turf/floor/carpet/green, /area/template_noop) "j" = ( -/obj/structure/table/woodentable, +/obj/structure/table/wood, /obj/item/clothing/mask/smokable/pipe/cobpipe, -/obj/item/storage/chewables/rollable/generic, +/obj/item/chewables/rollable/generic, /obj/item/ashtray, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/template_noop) "k" = ( -/obj/structure/table/woodentable, -/obj/item/kitchen/utensil/fork/plastic, -/obj/item/kitchen/utensil/fork/plastic, -/obj/item/kitchen/utensil/fork/plastic, -/obj/item/knife/table, +/obj/structure/table/wood, +/obj/item/utensil/fork/plastic, +/obj/item/utensil/fork/plastic, +/obj/item/utensil/fork/plastic, +/obj/item/utensil/knife, /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 1 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "l" = ( -/obj/structure/table/woodentable, -/obj/item/knife/table, -/obj/item/knife/table, +/obj/structure/table/wood, +/obj/item/utensil/knife, +/obj/item/utensil/knife, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "m" = ( /obj/structure/closet/crate/freezer, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "n" = ( /obj/machinery/cooker/oven, @@ -82,135 +80,134 @@ /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 4 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "o" = ( -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "p" = ( -/obj/structure/bed/chair/wood{ +/obj/structure/chair/wood{ dir = 8 }, /obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "q" = ( -/obj/structure/table/woodentable, +/obj/structure/table/wood, /obj/item/book/manual/detective, /obj/item/ashtray, /obj/item/deck/cards, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "r" = ( /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "s" = ( -/obj/structure/table/woodentable, +/obj/structure/table/wood, /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/blood/drip, /obj/item/knife/kitchen/cleaver, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "t" = ( -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "u" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "w" = ( -/turf/simulated/floor/wood/usedup, +/turf/floor/wood/usedup, /area/template_noop) "x" = ( -/obj/structure/table/woodentable, +/obj/structure/table/wood, /obj/item/flashlight/lamp, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "y" = ( /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "z" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 6 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "A" = ( /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "B" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "C" = ( -/obj/structure/table/woodentable, -/obj/machinery/computer/atmoscontrol/laptop{ +/obj/structure/table/wood, +/obj/machinery/computer/central_atmos/laptop{ desc = "A cheap, beat-up old laptop."; name = "old laptop" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "D" = ( -/obj/structure/bed/chair/wood{ +/obj/structure/chair/wood{ dir = 8 }, /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/template_noop) "E" = ( /obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "F" = ( /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "G" = ( /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "H" = ( /obj/structure/door/wood, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "I" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/zipgun, -/obj/item/storage/box/ammo/shotgunshells, -/turf/simulated/floor/wood, +/obj/item/box/ammo/shotgunshells, +/turf/floor/wood, /area/template_noop) "J" = ( /obj/structure/closet, -/obj/item/stack/material/steel/ten, -/obj/item/stack/material/wood/fifty, -/obj/item/stack/tile/carpetgreen/fifty, -/obj/item/stack/material/glass/reinforced/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/item/stack/tile/carpet/green/fifty, +/obj/item/stack/material/pane/mapped/rglass/ten, /obj/effect/floor_decal/spline/fancy/wood/corner{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "L" = ( /obj/machinery/portable_atmospherics/hydroponics/soil, -/obj/item/seeds/corkwood, +/obj/item/seeds/towercap, /turf/template_noop, /area/template_noop) "M" = ( @@ -230,12 +227,12 @@ /area/template_noop) "Q" = ( /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) "S" = ( /obj/machinery/portable_atmospherics/powered/scrubber, /obj/effect/floor_decal/spline/fancy/wood/corner, -/turf/simulated/floor/wood, +/turf/floor/wood, /area/template_noop) (1,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/marooned/icons/medal_magnitka.dmi b/maps/random_ruins/exoplanet_ruins/marooned/icons/medal_magnitka.dmi new file mode 100644 index 000000000000..7b4f540751c3 Binary files /dev/null and b/maps/random_ruins/exoplanet_ruins/marooned/icons/medal_magnitka.dmi differ diff --git a/maps/random_ruins/exoplanet_ruins/marooned/icons/uniform_magnitka.dmi b/maps/random_ruins/exoplanet_ruins/marooned/icons/uniform_magnitka.dmi new file mode 100644 index 000000000000..d97b99cfc97d Binary files /dev/null and b/maps/random_ruins/exoplanet_ruins/marooned/icons/uniform_magnitka.dmi differ diff --git a/maps/random_ruins/exoplanet_ruins/marooned/marooned.dm b/maps/random_ruins/exoplanet_ruins/marooned/marooned.dm index 13296d5400a5..a735e499842c 100644 --- a/maps/random_ruins/exoplanet_ruins/marooned/marooned.dm +++ b/maps/random_ruins/exoplanet_ruins/marooned/marooned.dm @@ -1,42 +1,38 @@ -/datum/map_template/ruin/exoplanet/marooned - name = "Marooned" - id = "awaysite_marooned" - description = "crashed dropship with marooned Magnitka officer" - suffixes = list("marooned/marooned.dmm") - cost = 1 +/datum/map_template/ruin/exoplanet/marooned + name = "Marooned" + description = "crashed dropship with marooned Magnitka officer" + suffixes = list("marooned/marooned.dmm") + cost = 1 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN|RUIN_WRECK + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WRECK apc_test_exempt_areas = list( /area/map_template/marooned = NO_SCRUBBER|NO_VENT|NO_APC ) -/obj/item/clothing/under/magintka_uniform - name = "officer uniform" - desc = "A dark uniform coat worn by Magnitka fleet officers." - icon_state = "magnitka_officer" - icon = 'maps/random_ruins/exoplanet_ruins/marooned/marooned_icons.dmi' - item_icons = list(slot_w_uniform_str = 'maps/random_ruins/exoplanet_ruins/marooned/marooned_icons.dmi') - -/obj/item/clothing/accessory/medal/silver/marooned_medal - name = "silver medal" - desc = "An silver round medal of marooned officer. It has inscription \"For Distinguished Service\" in lower part. On medal's plank it's engraved \"H. Warda\"" - icon_state = "marooned_medal" - icon = 'maps/random_ruins/exoplanet_ruins/marooned/marooned_icons.dmi' - -/obj/effect/landmark/corpse/marooned_officer - name = "Horazy Warda" - corpse_outfits = list(/decl/hierarchy/outfit/marooned_officer) - spawn_flags = ~CORPSE_SPAWNER_RANDOM_NAME - -/decl/hierarchy/outfit/marooned_officer - name = "Dead Magnitka's fleet officer" - uniform = /obj/item/clothing/under/magintka_uniform - suit = /obj/item/clothing/suit/storage/hooded/wintercoat - shoes = /obj/item/clothing/shoes/jackboots/jungleboots - gloves = /obj/item/clothing/gloves/thick - head = /obj/item/clothing/head/beret - l_pocket = /obj/item/knife/folding/combat/switchblade - +/obj/item/clothing/costume/magintka_uniform + name = "officer uniform" + desc = "A dark uniform coat worn by Magnitka fleet officers." + icon = 'maps/random_ruins/exoplanet_ruins/marooned/icons/uniform_magnitka.dmi' + +/obj/item/clothing/medal/silver/marooned_medal + name = "silver medal" + desc = "A silver medallion with a tri-coloured ribbon. It has the inscription \"For Distinguished Service\" on the lower part. On the medal's top bar is carved \"H. Warda\"" + icon = 'maps/random_ruins/exoplanet_ruins/marooned/icons/medal_magnitka.dmi' + +/obj/abstract/landmark/corpse/marooned_officer + name = "Horacy Warda" + corpse_outfits = list(/decl/outfit/marooned_officer) + spawn_flags = ~CORPSE_SPAWNER_RANDOM_NAME + +/decl/outfit/marooned_officer + name = "Dead Magnitka's fleet officer" + uniform = /obj/item/clothing/costume/magintka_uniform + suit = /obj/item/clothing/suit/jacket/winter + shoes = /obj/item/clothing/shoes/jackboots/jungleboots + gloves = /obj/item/clothing/gloves/thick + head = /obj/item/clothing/head/beret + l_pocket = /obj/item/knife/folding/combat/switchblade + /area/map_template/marooned name = "\improper Crashed Dropship" icon_state = "A" diff --git a/maps/random_ruins/exoplanet_ruins/marooned/marooned.dmm b/maps/random_ruins/exoplanet_ruins/marooned/marooned.dmm index fc6bdff1f23b..430aedf95a2c 100644 --- a/maps/random_ruins/exoplanet_ruins/marooned/marooned.dmm +++ b/maps/random_ruins/exoplanet_ruins/marooned/marooned.dmm @@ -3,78 +3,76 @@ /turf/template_noop, /area/template_noop) "ac" = ( -/obj/item/stack/material/rods, +/obj/item/stack/material/rods/mapped/steel, /turf/template_noop, /area/template_noop) "ad" = ( -/obj/item/stack/material/rods, -/obj/item/stack/material/ocp, +/obj/item/stack/material/rods/mapped/steel, +/obj/item/stack/material/sheet/reinforced/mapped/ocp, /turf/template_noop, /area/template_noop) "ae" = ( -/obj/item/stack/material/ocp, +/obj/item/stack/material/sheet/reinforced/mapped/ocp, /turf/template_noop, /area/template_noop) "af" = ( /obj/structure/lattice, -/obj/item/stack/material/ocp, -/obj/effect/landmark/scorcher, +/obj/item/stack/material/sheet/reinforced/mapped/ocp, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) "ag" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/marooned) "ah" = ( /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/marooned) "ai" = ( -/obj/effect/landmark/scorcher, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) "aj" = ( -/obj/item/stack/material/ocp, -/obj/effect/landmark/scorcher, +/obj/item/stack/material/sheet/reinforced/mapped/ocp, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) "ak" = ( /obj/machinery/computer/dummy, /obj/effect/floor_decal/corner/red/full, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "al" = ( /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/binary/oxyregenerator, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "am" = ( -/obj/effect/landmark/corpse/marooned_officer, -/obj/structure/bed/chair{ +/obj/abstract/landmark/corpse/marooned_officer, +/obj/structure/chair{ dir = 1 }, /obj/effect/decal/cleanable/blood, /obj/item/gun/projectile/revolver, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "an" = ( -/obj/item/clothing/accessory/medal/silver/marooned_medal{ +/obj/item/clothing/medal/silver/marooned_medal{ desc = "A heart-shaped bronze medal. Has Magnitka flag at top part and engraved name - H. Warda."; name = "\improper Magnitka medal" }, /obj/structure/table/steel_reinforced, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 6 }, /obj/item/paper/marooned/note09, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "ao" = ( /obj/structure/lattice, -/obj/effect/landmark/scorcher, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) "ap" = ( @@ -88,16 +86,15 @@ }, /obj/structure/table/steel_reinforced, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "aq" = ( /obj/machinery/space_heater, /obj/effect/decal/cleanable/blood/drip, /obj/effect/floor_decal/steeldecal/steel_decals_central7, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "ar" = ( /obj/item/paper/marooned/note03{ @@ -106,44 +103,42 @@ }, /obj/structure/table/steel_reinforced, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "as" = ( /obj/machinery/door/airlock/centcom, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/marooned) "at" = ( /obj/structure/closet/crate/freezer, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "au" = ( /obj/structure/closet/crate/freezer, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/handrail, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "av" = ( /obj/item/paper/marooned/note06, /obj/random/trash, /obj/item/paper/marooned/note08, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aw" = ( /obj/machinery/space_heater, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/handrail, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "ax" = ( /obj/machinery/suit_cycler, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "ay" = ( /obj/structure/closet/crate/freezer, @@ -152,23 +147,22 @@ pixel_x = -3; pixel_y = 1 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "az" = ( /obj/item/trash/liquidfood, /obj/item/trash/liquidfood, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aA" = ( /obj/random/trash, /obj/effect/floor_decal/steeldecal/steel_decals_central7, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aB" = ( /obj/item/paper/marooned/note07{ @@ -177,148 +171,142 @@ /obj/random/trash, /obj/effect/decal/cleanable/blood/drip, /obj/structure/bed, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aC" = ( /obj/structure/shuttle/engine/propulsion, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aD" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/item/trash/liquidfood, /obj/item/trash/liquidfood, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "aE" = ( /obj/item/trash/liquidfood, /obj/item/trash/liquidfood, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aF" = ( /obj/effect/floor_decal/steeldecal/steel_decals_central6, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aG" = ( -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aH" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/marooned) "aI" = ( /obj/item/wirecutters, /obj/item/stack/cable_coil, -/obj/machinery/power/port_gen/pacman/super, +/obj/machinery/port_gen/pacman/super, /obj/structure/cable{ - icon_state = "0-5"; - dir = 8 + dir = 8; + icon_state = "0-5" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aJ" = ( /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aL" = ( /obj/structure/inflatable/wall, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/marooned) "aM" = ( /obj/structure/inflatable/door, /obj/structure/cable{ - icon_state = "1-6"; - dir = 1 + dir = 1; + icon_state = "1-6" }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aN" = ( /obj/structure/inflatable/wall, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/marooned) "aO" = ( /obj/structure/inflatable/door, /obj/structure/cable{ - icon_state = "2-5"; - dir = 1 + dir = 1; + icon_state = "2-5" }, /obj/effect/floor_decal/industrial/warning, /obj/machinery/door/airlock/centcom, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/marooned) "aP" = ( -/obj/structure/fuel_port, +/obj/structure/fuel_port/hydrogen, /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/marooned) "aQ" = ( /obj/structure/inflatable/wall, /obj/structure/cable{ - icon_state = "2-5"; - dir = 2 + icon_state = "2-5" }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aR" = ( /obj/structure/inflatable/door, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aS" = ( /obj/structure/inflatable/wall, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aT" = ( /obj/structure/cable{ - icon_state = "2-5"; - dir = 1 + dir = 1; + icon_state = "2-5" }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aU" = ( -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/template_noop) "aV" = ( /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/template_noop) "aW" = ( /obj/item/stock_parts/computer/battery_module{ - pixel_x = -7; - pixel_y = 0 + pixel_x = -7 }, /obj/item/baton/cattleprod{ desc = "Metal rod with wire attached to it."; @@ -329,26 +317,22 @@ /obj/item/radio, /obj/item/stack/cable_coil, /obj/structure/cable{ - icon_state = "0-6"; - dir = 4 + dir = 4; + icon_state = "0-6" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aX" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "aY" = ( @@ -359,28 +343,27 @@ pixel_y = 3 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "hi" = ( -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "tb" = ( -/obj/effect/landmark/clear, -/obj/effect/landmark/scorcher, +/obj/abstract/landmark/clear, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) "Wb" = ( /obj/structure/shuttle/engine/propulsion, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/obj/effect/landmark/scorcher, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/obj/abstract/landmark/scorcher, /turf/template_noop, /area/template_noop) diff --git a/maps/random_ruins/exoplanet_ruins/marooned/marooned_icons.dmi b/maps/random_ruins/exoplanet_ruins/marooned/marooned_icons.dmi deleted file mode 100644 index 18e4a840ddbf..000000000000 Binary files a/maps/random_ruins/exoplanet_ruins/marooned/marooned_icons.dmi and /dev/null differ diff --git a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm index 4a88f6492854..1f8f82994c3f 100644 --- a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm +++ b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm @@ -1,20 +1,19 @@ /datum/map_template/ruin/exoplanet/monolith name = "Monolith Ring" - id = "planetsite_monoliths" description = "Bunch of monoliths surrounding an artifact." suffixes = list("monoliths/monoliths.dmm") cost = 1 template_flags = TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_ALIEN + template_tags = TEMPLATE_TAG_ALIEN /obj/structure/monolith name = "monolith" - desc = "An obviously artifical structure of unknown origin. The symbols 'DWNbTX' are engraved on the base." + desc = "An obviously artificial structure of unknown origin. The symbols 'DWNbTX' are engraved on the base." icon = 'icons/obj/structures/monolith.dmi' icon_state = "jaggy1" layer = ABOVE_HUMAN_LAYER - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE material = /decl/material/solid/metal/aliumium material_alteration = MAT_FLAG_ALTERATION_COLOR var/active = 0 @@ -22,59 +21,73 @@ /obj/structure/monolith/Initialize() . = ..() icon_state = "jaggy[rand(1,4)]" - if(GLOB.using_map.use_overmap) - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(istype(E)) - desc += "\nThere are images on it: [E.get_engravings()]" + var/datum/planetoid_data/E = loc ? SSmapping.planetoid_data_by_z[z] : null + if(istype(E)) + desc += "\nThere are images on it: [E.engraving_generator.generate_engraving_text()]" update_icon() /obj/structure/monolith/on_update_icon() ..() - overlays.Cut() if(active) - var/image/I = image(icon,"[icon_state]decor") + var/image/I = emissive_overlay(icon,"[icon_state]decor") I.appearance_flags = RESET_COLOR I.color = get_random_colour(0, 150, 255) - I.layer = ABOVE_LIGHTING_LAYER - I.plane = EFFECTS_ABOVE_LIGHTING_PLANE - overlays += I - set_light(0.3, 0.1, 2, l_color = I.color) + z_flags |= ZMM_MANGLE_PLANES + add_overlay(I) + set_light(2, 0.3, I.color) + else + z_flags &= ~ZMM_MANGLE_PLANES - var/turf/simulated/floor/exoplanet/T = get_turf(src) + var/turf/T = get_turf(src) if(istype(T)) - var/image/I = overlay_image(icon, "dugin", T.dirt_color, RESET_COLOR) - overlays += I + var/soil_color = T.get_soil_color() + if(soil_color) + var/image/I = overlay_image(icon, "dugin", soil_color, RESET_COLOR) + add_overlay(I) /obj/structure/monolith/attack_hand(mob/user) - visible_message("[user] touches \the [src].") - if(GLOB.using_map.use_overmap && istype(user,/mob/living/carbon/human)) - var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[z]"] - if(istype(E)) - var/mob/living/carbon/human/H = user - if(!H.isSynthetic()) - playsound(src, 'sound/effects/zapbeep.ogg', 100, 1) - active = 1 - update_icon() - if(prob(70)) - to_chat(H, "As you touch \the [src], you suddenly get a vivid image - [E.get_engravings()]") - else - to_chat(H, "An overwhelming stream of information invades your mind!") - var/vision = "" - for(var/i = 1 to 10) - vision += pick(E.actors) + " " + pick("killing","dying","gored","expiring","exploding","mauled","burning","flayed","in agony") + ". " - to_chat(H, "[uppertext(vision)]") - H.Paralyse(2) - H.hallucination(20, 100) - return - to_chat(user, "\The [src] is still.") - return ..() + SHOULD_CALL_PARENT(FALSE) + visible_message("\The [user] touches \the [src].") -/turf/simulated/floor/fixed/alium/ruin + if(!ishuman(user)) + to_chat(user, SPAN_NOTICE("\The [src] is still.")) + return TRUE + + var/datum/planetoid_data/E = SSmapping.planetoid_data_by_z[z] + if(!istype(E)) + to_chat(user, SPAN_NOTICE("\The [src] is still.")) + return TRUE + + var/mob/living/human/H = user + if(H.isSynthetic()) + to_chat(user, SPAN_NOTICE("\The [src] is still.")) + return TRUE + + playsound(src, 'sound/effects/zapbeep.ogg', 100, 1) + active = 1 + update_icon() + if(prob(70)) + to_chat(user, SPAN_NOTICE("As you touch \the [src], you suddenly get a vivid image - [E.engraving_generator.generate_engraving_text()]")) + return TRUE + + to_chat(user, SPAN_DANGER("An overwhelming stream of information invades your mind!")) + to_chat(user, SPAN_DANGER("[uppertext(E.engraving_generator.generate_violent_vision_text())]")) + SET_STATUS_MAX(user, STAT_PARA, 2) + H.set_hallucination(20, 100) + return TRUE + +/turf/floor/fixed/alium/ruin name = "ancient alien plating" desc = "This obviously wasn't made for your feet. Looks pretty old." initial_gas = null -/turf/simulated/floor/fixed/alium/ruin/Initialize() - . = ..() - if(prob(10)) - ChangeTurf(get_base_turf_by_area(src)) \ No newline at end of file +/obj/abstract/landmark/random_base_turf + name = "random chance base turf" + var/turf_prob = 10 + +/obj/abstract/landmark/random_base_turf/Initialize() + ..() + if(isturf(loc) && prob(turf_prob)) + var/turf/my_turf = loc + my_turf.ChangeTurf(get_base_turf_by_area(src)) + return INITIALIZE_HINT_QDEL diff --git a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm index 30f85a78a582..f3d241c13d00 100644 --- a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm +++ b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dmm @@ -4,11 +4,12 @@ /area/template_noop) "b" = ( /obj/structure/monolith, -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) "c" = ( -/turf/simulated/floor/fixed/alium/ruin, +/obj/abstract/landmark/random_base_turf, +/turf/floor/fixed/alium/ruin, /area/template_noop) "d" = ( /obj/structure/artifact, @@ -22,10 +23,11 @@ dir = 8 }, /obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/fixed/alium/ruin, +/obj/abstract/landmark/random_base_turf, +/turf/floor/fixed/alium/ruin, /area/template_noop) "e" = ( -/obj/effect/landmark/clear, +/obj/abstract/landmark/clear, /turf/template_noop, /area/template_noop) diff --git a/maps/random_ruins/exoplanet_ruins/oasis/oasis.dm b/maps/random_ruins/exoplanet_ruins/oasis/oasis.dm index a6acfc4c011f..e648a663a5d4 100644 --- a/maps/random_ruins/exoplanet_ruins/oasis/oasis.dm +++ b/maps/random_ruins/exoplanet_ruins/oasis/oasis.dm @@ -1,18 +1,15 @@ /datum/map_template/ruin/exoplanet/oasis name = "oasis 1" - id = "oasis1" description = "A tiny patch of life in a vast desert." suffixes = list("oasis/oasis.dmm") cost = 0.5 template_flags = TEMPLATE_FLAG_NO_RUINS | TEMPLATE_FLAG_ALLOW_DUPLICATES - ruin_tags = RUIN_NATURAL|RUIN_WATER + template_tags = TEMPLATE_TAG_NATURAL|TEMPLATE_TAG_WATER /datum/map_template/ruin/exoplanet/oasis/oasis2 name = "oasis 2" - id = "oasis2" suffixes = list("oasis/oasis2.dmm") /datum/map_template/ruin/exoplanet/oasis/oasis3 name = "oasis 3" - id = "oasis3" suffixes = list("oasis/oasis3.dmm") \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/oasis/oasis.dmm b/maps/random_ruins/exoplanet_ruins/oasis/oasis.dmm index 848748bf1bca..fea6fcf869d5 100644 --- a/maps/random_ruins/exoplanet_ruins/oasis/oasis.dmm +++ b/maps/random_ruins/exoplanet_ruins/oasis/oasis.dmm @@ -7,42 +7,38 @@ /turf/template_noop, /area/template_noop) "d" = ( -/obj/structure/flora/ausbushes/lavendergrass, +/obj/structure/flora/bush/lavendergrass, /turf/template_noop, /area/template_noop) "e" = ( /obj/structure/flora/grass/green, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) "f" = ( /obj/structure/flora/grass/both, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) "g" = ( -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/template_noop) "h" = ( -/obj/structure/flora/ausbushes/reedbush, -/turf/simulated/floor/exoplanet/water/shallow, +/obj/structure/flora/bush/reedbush, +/turf/floor/rock/sand/water, /area/template_noop) "i" = ( /obj/structure/flora/bush, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) "j" = ( -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) "k" = ( -/obj/structure/flora/ausbushes/palebush, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/palebush, +/turf/floor/grass/wild, /area/template_noop) "l" = ( /obj/structure/flora/grass/brown, -/turf/simulated/floor/exoplanet/grass, -/area/template_noop) -"m" = ( -/obj/structure/flora/ausbushes, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) (1,1,1) = {" @@ -141,7 +137,7 @@ a a i j -m +i a "} (12,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/oasis/oasis2.dmm b/maps/random_ruins/exoplanet_ruins/oasis/oasis2.dmm index 14ddf2be26ca..d5a8f4a89293 100644 --- a/maps/random_ruins/exoplanet_ruins/oasis/oasis2.dmm +++ b/maps/random_ruins/exoplanet_ruins/oasis/oasis2.dmm @@ -3,59 +3,59 @@ /turf/template_noop, /area/template_noop) "b" = ( -/obj/structure/flora/ausbushes/genericbush, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/genericbush, +/turf/floor/grass/wild, /area/template_noop) "c" = ( -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) "d" = ( -/obj/structure/flora/ausbushes/brflowers, -/obj/structure/flora/ausbushes/ywflowers, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/brflowers, +/obj/structure/flora/bush/ywflowers, +/turf/floor/grass/wild, /area/template_noop) "e" = ( -/obj/structure/flora/ausbushes/ppflowers, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/ppflowers, +/turf/floor/grass/wild, /area/template_noop) "f" = ( -/obj/structure/flora/ausbushes/fullgrass, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/fullgrass, +/turf/floor/grass/wild, /area/template_noop) "g" = ( -/obj/structure/flora/ausbushes/leafybush, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/leafybush, +/turf/floor/grass/wild, /area/template_noop) "h" = ( -/obj/structure/flora/ausbushes/ppflowers, -/obj/structure/flora/ausbushes/fernybush, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/ppflowers, +/obj/structure/flora/bush/fernybush, +/turf/floor/grass/wild, /area/template_noop) "i" = ( /obj/structure/flora/grass/both, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/template_noop) "j" = ( -/turf/simulated/floor/exoplanet/water/shallow, +/turf/floor/rock/sand/water, /area/template_noop) "k" = ( /obj/structure/flora/grass/both, -/obj/structure/flora/ausbushes/ywflowers, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/ywflowers, +/turf/floor/grass/wild, /area/template_noop) "l" = ( -/obj/structure/flora/ausbushes/reedbush, -/turf/simulated/floor/exoplanet/water/shallow, +/obj/structure/flora/bush/reedbush, +/turf/floor/rock/sand/water, /area/template_noop) "m" = ( /obj/structure/flora/grass/both, -/obj/structure/flora/ausbushes/fullgrass, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/fullgrass, +/turf/floor/grass/wild, /area/template_noop) "n" = ( -/obj/structure/flora/ausbushes/ywflowers, -/obj/structure/flora/ausbushes/ppflowers, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/ywflowers, +/obj/structure/flora/bush/ppflowers, +/turf/floor/grass/wild, /area/template_noop) (1,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/oasis/oasis3.dmm b/maps/random_ruins/exoplanet_ruins/oasis/oasis3.dmm index 683cc1d0156a..5235be136f05 100644 --- a/maps/random_ruins/exoplanet_ruins/oasis/oasis3.dmm +++ b/maps/random_ruins/exoplanet_ruins/oasis/oasis3.dmm @@ -3,11 +3,11 @@ /turf/template_noop, /area/template_noop) "b" = ( -/obj/structure/flora/ausbushes/grassybush, +/obj/structure/flora/bush/grassybush, /turf/template_noop, /area/template_noop) "c" = ( -/obj/structure/flora/ausbushes/stalkybush, +/obj/structure/flora/bush/stalkybush, /turf/template_noop, /area/template_noop) "d" = ( @@ -15,11 +15,11 @@ /turf/template_noop, /area/template_noop) "e" = ( -/obj/structure/flora/ausbushes/palebush, +/obj/structure/flora/bush/palebush, /turf/template_noop, /area/template_noop) "f" = ( -/obj/structure/flora/ausbushes/ppflowers, +/obj/structure/flora/bush/ppflowers, /turf/template_noop, /area/template_noop) diff --git a/maps/random_ruins/exoplanet_ruins/oldpod/oldpod.dmm b/maps/random_ruins/exoplanet_ruins/oldpod/oldpod.dmm deleted file mode 100644 index 46dc43bcf1a2..000000000000 --- a/maps/random_ruins/exoplanet_ruins/oldpod/oldpod.dmm +++ /dev/null @@ -1,638 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/simulated/shuttle/wall/corner/dark{ - dir = 9 - }, -/area/map_template/oldpod) -"ab" = ( -/obj/structure/shuttle/engine/propulsion{ - dir = 1 - }, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"ac" = ( -/turf/simulated/shuttle/wall{ - icon_state = "wall3" - }, -/area/map_template/oldpod) -"ad" = ( -/obj/effect/wallframe_spawn/reinforced/hull, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"ae" = ( -/obj/machinery/door/firedoor, -/obj/effect/wallframe_spawn/reinforced/hull, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"af" = ( -/turf/simulated/shuttle/wall/corner/dark{ - dir = 5 - }, -/area/map_template/oldpod) -"ag" = ( -/obj/structure/shuttle/engine/heater{ - icon_state = "heater"; - dir = 1 - }, -/obj/effect/wallframe_spawn/reinforced/hull, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"ah" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/machinery/atmospherics/portables_connector{ - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"ai" = ( -/obj/effect/decal/cleanable/filth, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aj" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/portable_atmospherics/canister/empty, -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/machinery/atmospherics/portables_connector{ - dir = 8 - }, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"ak" = ( -/obj/structure/bed, -/obj/effect/landmark/corpse/doctor, -/obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"al" = ( -/obj/structure/bed, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"am" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"an" = ( -/obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"ao" = ( -/obj/structure/bed/chair/shuttle{ - dir = 8 - }, -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"ap" = ( -/obj/structure/bed/chair/shuttle{ - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aq" = ( -/obj/structure/closet/hydrant{ - pixel_x = 24; - pixel_y = 0 - }, -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/filth, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"ar" = ( -/obj/machinery/light/small{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"as" = ( -/obj/effect/decal/cleanable/filth, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"at" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"au" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"av" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aw" = ( -/obj/machinery/light/small{ - dir = 4 - }, -/obj/effect/decal/cleanable/filth, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"ax" = ( -/obj/machinery/door/firedoor, -/obj/effect/wallframe_spawn/reinforced/hull, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"ay" = ( -/obj/item/frame/air_alarm, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stock_parts/circuitboard/air_alarm, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"az" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aA" = ( -/obj/random/firstaid, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aB" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/filth, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aC" = ( -/obj/item/clothing/head/helmet/space/emergency, -/obj/item/clothing/suit/space/emergency, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aD" = ( -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/table/standard{ - name = "plastic table frame" - }, -/obj/random/tech_supply, -/obj/random/tech_supply, -/obj/random/tech_supply, -/obj/random/tech_supply, -/obj/random/tech_supply, -/obj/item/pickaxe, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aE" = ( -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/table, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aF" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aG" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aH" = ( -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/item/frame/apc, -/obj/effect/decal/cleanable/dirt, -/obj/item/cell/crap/empty, -/obj/item/stock_parts/circuitboard/apc, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aI" = ( -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/decal/cleanable/filth, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aJ" = ( -/obj/effect/landmark/corpse/pirate, -/obj/item/gun/energy/captain, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aK" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aL" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aM" = ( -/obj/effect/landmark/corpse/scientist, -/obj/item/baton/cattleprod, -/obj/item/shard, -/obj/effect/decal/cleanable/blood, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aN" = ( -/obj/machinery/door/firedoor, -/obj/structure/wall_frame/hull, -/obj/structure/grille, -/obj/item/stack/material/rods, -/obj/item/stack/material/rods, -/obj/item/stack/material/rods, -/obj/item/stack/material/rods, -/obj/item/shard, -/obj/item/shard, -/obj/item/shard, -/obj/item/shard, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"aO" = ( -/obj/machinery/door/airlock/external{ - name = "escape pod airlock" - }, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"aP" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/structure/cable/cyan, -/obj/machinery/light/small{ - dir = 8 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 - }, -/obj/machinery/power/smes/buildable/power_shuttle, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"aQ" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"aR" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/table/standard{ - name = "plastic table frame" - }, -/obj/item/storage/firstaid/surgery, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"aS" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"aT" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 - }, -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/closet/crate/freezer/rations, -/obj/effect/decal/cleanable/dirt, -/obj/item/gun/projectile/zipgun, -/obj/item/gun/projectile/zipgun, -/obj/item/gun/projectile/zipgun, -/obj/item/gun/projectile/zipgun, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"aU" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 9 - }, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"aV" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 5 - }, -/obj/machinery/light/small{ - dir = 4 - }, -/obj/item/clothing/head/helmet/space/emergency, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"aW" = ( -/obj/machinery/power/terminal{ - icon_state = "term"; - dir = 1 - }, -/obj/structure/cable/cyan{ - d2 = 2; - icon_state = "0-2" - }, -/obj/effect/floor_decal/industrial/warning{ - dir = 4 - }, -/obj/structure/closet/crate, -/obj/item/tank/oxygen, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"aX" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 8 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/machinery/optable, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"aY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"aZ" = ( -/obj/machinery/sleeper/standard{ - dir = 8 - }, -/obj/effect/floor_decal/industrial/warning{ - dir = 4 - }, -/obj/machinery/light/small{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"ba" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 10 - }, -/obj/item/clothing/suit/space/emergency, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"bb" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 6 - }, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"bc" = ( -/obj/machinery/power/port_gen/pacman, -/obj/structure/cable/cyan, -/obj/effect/floor_decal/industrial/warning{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/oldpod) -"bd" = ( -/obj/effect/landmark/corpse/bridgeofficer, -/obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/monotile, -/area/map_template/oldpod) -"be" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/structure/table/standard{ - name = "plastic table frame" - }, -/obj/random/firstaid, -/obj/random/firstaid, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"bf" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"bg" = ( -/obj/machinery/sleeper/standard{ - dir = 8 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white/monotile, -/area/map_template/oldpod) -"bh" = ( -/turf/simulated/shuttle/wall/corner/dark{ - dir = 10 - }, -/area/map_template/oldpod) -"bi" = ( -/turf/simulated/shuttle/wall/corner/dark{ - dir = 6 - }, -/area/map_template/oldpod) - -(1,1,1) = {" -aa -ac -ac -ac -ax -ae -ac -ac -ac -bh -"} -(2,1,1) = {" -ab -ag -ak -ar -ay -aG -ad -aU -ba -ac -"} -(3,1,1) = {" -ac -ac -al -as -az -am -aO -aV -bb -aO -"} -(4,1,1) = {" -ac -ah -al -at -aA -aH -ac -ac -ac -ac -"} -(5,1,1) = {" -ad -ai -am -au -aB -aI -aP -aW -bc -ad -"} -(6,1,1) = {" -ae -ai -an -av -aC -aJ -aQ -aK -bd -ae -"} -(7,1,1) = {" -ac -aj -ao -ao -aD -aK -aR -aX -be -ac -"} -(8,1,1) = {" -ac -ac -ap -ap -aE -aL -aS -aY -bf -ac -"} -(9,1,1) = {" -ab -ag -aq -aw -aF -aM -aT -aZ -bg -ac -"} -(10,1,1) = {" -af -ac -ac -ac -ae -aN -ac -ac -ac -bi -"} diff --git a/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm b/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm index 96edf3c346d0..2fb3f4ba5366 100644 --- a/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm +++ b/maps/random_ruins/exoplanet_ruins/playablecolony/colony.dmm @@ -3,27 +3,27 @@ /turf/template_noop, /area/template_noop) "ab" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/template_noop) "ac" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/command) "ad" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/command) "ae" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/tcomms) "af" = ( /obj/structure/grille, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ag" = ( /obj/structure/table/steel_reinforced, /obj/item/paper_bin, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "ah" = ( /obj/structure/table/steel_reinforced, @@ -35,10 +35,9 @@ dir = 9 }, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "ai" = ( /obj/structure/table/steel_reinforced, @@ -53,22 +52,21 @@ /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "aj" = ( /obj/structure/catwalk, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ak" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/tcomms) "al" = ( /obj/machinery/power/solar, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/template_noop) "am" = ( /obj/effect/floor_decal/corner/red{ @@ -77,42 +75,41 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "an" = ( /obj/structure/table/steel_reinforced, /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "ao" = ( -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ap" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/effect/floor_decal/corner/blue, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "aq" = ( -/obj/effect/submap_landmark/joinable_submap/colony, +/obj/abstract/submap_landmark/joinable_submap/colony, /turf/template_noop, /area/template_noop) "ar" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/engineering) "as" = ( /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "at" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/dorms) "au" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/medbay) "av" = ( /obj/structure/table/steel_reinforced, @@ -129,62 +126,65 @@ desc = "this card can be used to access the Colony's telepad to exchange goods."; name = "trade array access card" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "aw" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/surgery) "ax" = ( -/obj/structure/filingcabinet/chestdrawer, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "ay" = ( /obj/machinery/computer/modular/preset/merchant, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "az" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/dorms) "aA" = ( /obj/machinery/merchant_pad, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "aB" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/medbay) "aC" = ( /obj/item/gun/energy/gun/small, /obj/item/flashlight/upgraded, /obj/item/crowbar, -/obj/item/clothing/under/captain_fly, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/frontier, -/obj/item/clothing/under/hazard, -/obj/item/clothing/under/suit_jacket/female, -/obj/item/clothing/under/suit_jacket/charcoal, -/obj/item/clothing/under/syndicate, -/obj/item/clothing/under/det/grey, -/obj/item/clothing/under/casual_pants/baggy, -/obj/item/clothing/under/casual_pants/youngfolksjeans, -/obj/item/clothing/suit/storage/toggle/bomber, -/obj/item/clothing/suit/storage/hooded/wintercoat/miner, -/obj/item/clothing/suit/storage/hooded/wintercoat, -/obj/item/clothing/suit/storage/toggle/brown_jacket, -/obj/item/clothing/suit/storage/toggle/hoodie/nt, -/obj/item/clothing/suit/storage/toggle/hoodie/smw, -/obj/item/clothing/suit/storage/toggle/track/gcc, +/obj/item/clothing/costume/captain_fly, +/obj/item/clothing/jumpsuit/blackjumpshorts, +/obj/item/clothing/shirt/flannel/red, +/obj/item/clothing/suit/apron/overalls/denim, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/clothing/pants/slacks/outfit, +/obj/item/clothing/pants/slacks/black/outfit, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/shirt/syndicate, +/obj/item/clothing/pants/slacks/outfit/detective, +/obj/item/clothing/pants/baggy, +/obj/item/clothing/pants/casual/youngfolksjeans, +/obj/item/clothing/suit/jacket/bomber, +/obj/item/clothing/suit/jacket/winter/miner, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/brown, +/obj/item/clothing/suit/toggle/nt_hoodie, +/obj/item/clothing/suit/jacket/hoodie, +/obj/item/clothing/suit/toggle/track, /obj/item/radio, /obj/structure/closet/shipping_wall{ - pixel_y = -28 + pixel_y = -28; + dir = 1 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/command) "aD" = ( /obj/structure/flora/pottedplant/unusual{ desc = "Steve's distant cousin."; name = "Randy" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "aE" = ( /obj/structure/table/steel_reinforced, @@ -194,22 +194,22 @@ /obj/random/contraband, /obj/random/contraband, /obj/random/contraband, -/obj/item/stack/material/tritium/fifty, -/obj/item/stack/material/deuterium/fifty, -/obj/item/stack/material/deuterium/fifty, -/turf/simulated/floor/tiled/techfloor, +/obj/item/stack/material/aerogel/mapped/tritium/fifty, +/obj/item/stack/material/aerogel/mapped/deuterium/fifty, +/obj/item/stack/material/aerogel/mapped/deuterium/fifty, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "aF" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/atmospherics) "aG" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/surgery) "aH" = ( /obj/structure/closet/crate, /obj/item/stock_parts/circuitboard/fusion/core_control, /obj/item/stock_parts/circuitboard/fusion_core, -/obj/item/stock_parts/circuitboard/fusion_fuel_compressor, +/obj/item/stock_parts/circuitboard/fuel_compressor, /obj/item/stock_parts/circuitboard/fusion_fuel_control, /obj/item/stock_parts/circuitboard/fusion_injector, /obj/item/stock_parts/circuitboard/fusion_injector, @@ -249,105 +249,94 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/map_template/colony/command) "aI" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/messhall) "aJ" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony) "aK" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/messhall) "aL" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/engineering) "aM" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "aN" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/engineering) "aO" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/jail) "aP" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/bathroom) "aQ" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/commons) "aR" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "aS" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/commons) "aT" = ( -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "aU" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/armory) "aV" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "aW" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "aX" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "aY" = ( /obj/machinery/alarm{ @@ -355,153 +344,129 @@ pixel_y = 20 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "aZ" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ba" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/hydroponics) "bb" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/corner/blue{ dir = 8 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bc" = ( /obj/machinery/power/tracker, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/template_noop) "bd" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony) "be" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "bf" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bg" = ( -/obj/effect/submap_landmark/spawnpoint/colonist_spawn, +/obj/abstract/submap_landmark/spawnpoint/colonist_spawn, /obj/structure/bed/padded, /obj/item/bedsheet/hop, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/command) "bh" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/airlock) "bi" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/obj/item/storage/mre/menu10, -/obj/item/storage/mre/menu9, -/obj/item/storage/mre/random, -/obj/item/storage/mre/random, -/obj/item/storage/mre/random, -/turf/simulated/floor/tiled/techfloor, +/obj/item/mre/menu10, +/obj/item/mre/menu9, +/obj/item/mre/random, +/obj/item/mre/random, +/obj/item/mre/random, +/turf/floor/tiled/techfloor, /area/map_template/colony) "bj" = ( /obj/structure/closet/firecloset, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "bk" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bl" = ( /obj/structure/curtain/black, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/map_template/colony/command) "bm" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/engineering) "bn" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/blue{ @@ -511,7 +476,7 @@ dir = 8 }, /obj/machinery/recharge_station, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -521,25 +486,20 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor, /obj/machinery/light, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/effect/floor_decal/corner/blue{ @@ -550,21 +510,21 @@ }, /obj/item/radio/intercom{ dir = 1; - pixel_y = -28 + pixel_y = -30 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bq" = ( -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "br" = ( -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/map_template/colony/messhall) "bs" = ( /obj/structure/closet/crate, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, /obj/item/oxycandle, /obj/item/oxycandle, /obj/item/oxycandle, @@ -579,28 +539,25 @@ /obj/item/oxycandle, /obj/item/oxycandle, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "bt" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/power/terminal{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "bu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -610,29 +567,24 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "bv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "bw" = ( /obj/structure/table/steel_reinforced, @@ -640,54 +592,48 @@ /obj/random/contraband, /obj/random/contraband, /obj/random/contraband, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "bx" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/effect/floor_decal/corner/blue, /obj/item/radio/intercom{ dir = 4; - pixel_x = -21 + pixel_x = -22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "by" = ( /obj/structure/curtain/open/shower, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "bz" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/medbay) "bA" = ( /obj/machinery/power/smes/buildable/max_cap_in_out, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "bB" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "bC" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/effect/floor_decal/corner/blue{ @@ -697,36 +643,32 @@ /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bD" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/effect/floor_decal/corner/blue{ dir = 4 }, /obj/machinery/computer/arcade/orion_trail, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 @@ -735,52 +677,44 @@ /obj/effect/floor_decal/corner/blue{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bF" = ( -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/colony/jail) "bG" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "bH" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 6; - icon_state = "intact" + dir = 6 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/map_template/colony/atmospherics) "bI" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "bJ" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/atmospherics) "bK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -791,105 +725,84 @@ /obj/effect/floor_decal/corner/blue{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "bL" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 6; - icon_state = "intact" + dir = 6 }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/map_template/colony/atmospherics) "bM" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "bN" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/map_template/colony/atmospherics) "bO" = ( /obj/machinery/power/terminal{ dir = 8 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "bP" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/techfloor, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "bQ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "bR" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "bS" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 10 }, /obj/machinery/air_sensor{ id_tag = "c1" }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/map_template/colony/atmospherics) "bT" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "bU" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -899,13 +812,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/techfloor, @@ -913,38 +822,34 @@ dir = 5 }, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "bV" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/effect/floor_decal/corner/blue{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "bW" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 10 }, /obj/machinery/air_sensor{ id_tag = "c2" }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/map_template/colony/atmospherics) "bX" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/effect/floor_decal/corner/red{ @@ -952,30 +857,27 @@ }, /obj/item/radio/intercom{ dir = 4; - pixel_x = -21 + pixel_x = -22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "bY" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 10 }, /obj/machinery/air_sensor{ id_tag = "c3" }, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/map_template/colony/atmospherics) "bZ" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/surgery) "ca" = ( /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, /obj/effect/floor_decal/industrial/hatch/orange, /obj/machinery/alarm{ @@ -985,85 +887,75 @@ /obj/machinery/light{ dir = 1 }, -/obj/machinery/power/port_gen/pacman/mrs, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/port_gen/pacman/mrs, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "cb" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/power/solar_control/autostart, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "cc" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/medbay) "cd" = ( /obj/structure/grille, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ce" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, /obj/machinery/atmospherics/unary/outlet_injector{ id_tag = "cn2n" }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/map_template/colony/atmospherics) "cf" = ( /obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/power/emitter/gyrotron, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/emitter/gyrotron, +/turf/floor/concrete, /area/template_noop) "cg" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/power/smes/buildable/max_cap_in_out, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "ch" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 9 }, /obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos/tank{ id_tag = "cn2o" }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/map_template/colony/atmospherics) "ci" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "cj" = ( /obj/structure/table/steel_reinforced, -/obj/item/spacecash/bundle/c1000, +/obj/item/cash/c1000, /obj/random/cash, /obj/random/cash, /obj/random/cash, @@ -1081,95 +973,79 @@ /obj/random/cash, /obj/random/cash, /obj/random/cash, -/obj/item/spacecash/bundle/c1000, -/turf/simulated/floor/tiled/techfloor, +/obj/item/cash/c1000, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "ck" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/glass/command, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "cl" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cm" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cn" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "co" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cp" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cq" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "cr" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "cs" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ct" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, @@ -1177,252 +1053,230 @@ dir = 5 }, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cu" = ( /obj/machinery/atmospherics/pipe/manifold/visible/black{ dir = 4 }, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cv" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cw" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "cx" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "cy" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cz" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "cA" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 5; - icon_state = "intact" + dir = 5 }, /obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos/tank{ id_tag = "co2o" }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/map_template/colony/atmospherics) "cB" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cC" = ( /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "cD" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "cE" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cF" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/effect/floor_decal/corner/blue{ dir = 4 }, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "cG" = ( /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/dorms) "cH" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 9 }, /obj/machinery/atmospherics/unary/outlet_injector{ id_tag = "co2n" }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/map_template/colony/atmospherics) "cI" = ( /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/dorms) "cJ" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 5; - icon_state = "intact" + dir = 5 }, /obj/machinery/atmospherics/unary/outlet_injector{ id_tag = "cco2n" }, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/map_template/colony/atmospherics) "cK" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "cL" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cM" = ( /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cN" = ( /obj/machinery/atmospherics/pipe/manifold/visible/cyan, /obj/machinery/portable_atmospherics/powered/pump/filled, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cO" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 9 }, /obj/machinery/portable_atmospherics/powered/pump/filled, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cP" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/sign/warning/compressed_gas{ pixel_y = -28 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "cQ" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cR" = ( /obj/machinery/atmospherics/portables_connector, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 8 }, /obj/effect/floor_decal/corner_techfloor_grid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cS" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - dir = 9; - icon_state = "intact" + dir = 9 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cT" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "cU" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cV" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cW" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cX" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/machinery/atmospherics/binary/pump, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "cY" = ( /obj/machinery/atmospherics/binary/pump/on{ dir = 4; target_pressure = 303.96 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "cZ" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/messhall) "da" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -1430,29 +1284,24 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "db" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - icon_state = "intact"; dir = 9 }, /obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos/tank{ id_tag = "cco2o" }, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/map_template/colony/atmospherics) "dc" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -1463,121 +1312,111 @@ pixel_y = 20 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/corner/blue{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dd" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "de" = ( /obj/machinery/atmospherics/pipe/manifold/visible, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "df" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "dg" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "dh" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/atmospherics/pipe/simple/visible{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "di" = ( /obj/machinery/atmospherics/binary/pump/on{ dir = 8; target_pressure = 200 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "dj" = ( /obj/item/gun/energy/gun/small, /obj/item/flashlight/upgraded, /obj/item/crowbar, -/obj/item/clothing/under/captain_fly, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/frontier, -/obj/item/clothing/under/hazard, -/obj/item/clothing/under/skirt, -/obj/item/clothing/under/suit_jacket/female, -/obj/item/clothing/under/suit_jacket/navy, -/obj/item/clothing/under/suit_jacket/charcoal, -/obj/item/clothing/under/syndicate, -/obj/item/clothing/under/sterile, -/obj/item/clothing/under/det/grey, -/obj/item/clothing/under/casual_pants/baggy, -/obj/item/clothing/under/casual_pants/camo, -/obj/item/clothing/under/casual_pants/track, -/obj/item/clothing/under/casual_pants/youngfolksjeans, -/obj/item/clothing/suit/storage/hooded/wintercoat/miner, -/obj/item/clothing/suit/storage/hooded/wintercoat, -/obj/item/clothing/suit/storage/toggle/bomber, -/obj/item/clothing/suit/storage/toggle/brown_jacket, -/obj/item/clothing/suit/storage/toggle/hoodie/nt, -/obj/item/clothing/suit/storage/toggle/hoodie/smw, +/obj/item/clothing/costume/captain_fly, +/obj/item/clothing/jumpsuit/blackjumpshorts, +/obj/item/clothing/shirt/flannel/red, +/obj/item/clothing/suit/apron/overalls/denim, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/clothing/skirt, +/obj/item/clothing/pants/slacks/outfit, +/obj/item/clothing/pants/slacks/black/outfit/navy, +/obj/item/clothing/pants/slacks/black/outfit, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/shirt/syndicate, +/obj/item/clothing/jumpsuit/sterile, +/obj/item/clothing/pants/slacks/outfit/detective, +/obj/item/clothing/pants/baggy, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/pants/casual/track, +/obj/item/clothing/pants/casual/youngfolksjeans, +/obj/item/clothing/suit/jacket/winter/miner, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/bomber, +/obj/item/clothing/suit/jacket/brown, +/obj/item/clothing/suit/toggle/nt_hoodie, +/obj/item/clothing/suit/jacket/hoodie, /obj/item/radio, /obj/structure/closet/cabinet, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/dorms) "dk" = ( /obj/machinery/gibber, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/messhall) "dl" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "dm" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light/spot, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "dn" = ( /obj/structure/catwalk, -/obj/machinery/power/rad_collector, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/machinery/rad_collector, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "do" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1588,50 +1427,46 @@ }, /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/messhall) "dp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dr" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, /obj/machinery/light{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ds" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "dt" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1640,7 +1475,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "du" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1649,58 +1484,55 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dv" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/messhall) "dw" = ( /obj/effect/floor_decal/techfloor, /obj/effect/floor_decal/techfloor/hole/right, /obj/machinery/atmospherics/pipe/simple/hidden/universal, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dx" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dy" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/reagent_dispensers/fueltank, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "dz" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "dA" = ( -/obj/structure/dispenser, +/obj/structure/tank_rack, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "dB" = ( -/obj/effect/submap_landmark/spawnpoint/colonist_spawn, +/obj/abstract/submap_landmark/spawnpoint/colonist_spawn, /obj/structure/bed/padded, /obj/item/bedsheet/hos, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/dorms) "dC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1709,7 +1541,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "dD" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, @@ -1718,152 +1550,134 @@ pixel_y = 20 }, /obj/structure/closet, -/obj/item/clothing/under/wetsuit, -/obj/item/clothing/under/wetsuit, -/obj/item/clothing/under/savage_hunter, -/obj/item/clothing/under/savage_hunter/female, -/obj/item/clothing/under/harness, -/obj/item/clothing/under/harness, +/obj/item/clothing/costume/wetsuit, +/obj/item/clothing/costume/wetsuit, +/obj/item/clothing/costume/savage_hunter, +/obj/item/clothing/costume/savage_hunter/female, +/obj/item/clothing/shirt/harness, +/obj/item/clothing/shirt/harness, /obj/item/clothing/head/cowboy_hat, /obj/item/clothing/head/cowboy_hat, -/obj/item/clothing/suit/storage/det_trench/ft, -/turf/simulated/floor/wood, +/obj/item/clothing/suit/det_trench, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "dE" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dF" = ( /obj/structure/catwalk, /obj/machinery/light/spot{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/surgery) "dG" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "dH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dJ" = ( -/obj/machinery/atmospherics/unary/freezer{ - dir = 2; +/obj/machinery/atmospherics/unary/temperature/freezer{ icon_state = "freezer" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "dK" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "dL" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/firstaid/adv, -/obj/item/storage/box/gloves, -/turf/simulated/floor/tiled/freezer, +/obj/item/firstaid/adv, +/obj/item/box/gloves, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "dM" = ( /obj/structure/curtain/black, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/map_template/colony/dorms) "dN" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/firstaid/surgery, +/obj/item/firstaid/surgery, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/obj/item/clothing/accessory/stethoscope, -/turf/simulated/floor/tiled/freezer, +/obj/item/clothing/neck/stethoscope, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "dO" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "dP" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "dQ" = ( /obj/structure/closet/crate/freezer, -/obj/item/chems/ivbag/nanoblood, -/obj/item/chems/ivbag/nanoblood, -/turf/simulated/floor/tiled/freezer, +/obj/item/chems/ivbag/blood/nanoblood, +/obj/item/chems/ivbag/blood/nanoblood, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "dR" = ( /obj/structure/closet/crate/freezer, -/obj/item/storage/box/pillbottles, -/obj/item/storage/firstaid/adv, -/obj/item/storage/firstaid/adv, -/obj/item/storage/firstaid/stab, -/obj/item/storage/firstaid/stab, -/obj/item/storage/firstaid/regular, +/obj/item/box/pillbottles, +/obj/item/firstaid/adv, +/obj/item/firstaid/adv, +/obj/item/firstaid/stab, +/obj/item/firstaid/stab, +/obj/item/firstaid/regular, /obj/machinery/alarm{ locked = 0; pixel_y = 20 @@ -1871,21 +1685,19 @@ /obj/effect/floor_decal/corner/paleblue{ dir = 10 }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/map_template/colony/medbay) "dS" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/machinery/meter, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "dT" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/computer/air_control{ @@ -1896,21 +1708,21 @@ sensor_tag = "c1" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "dU" = ( /obj/machinery/chem_master, /obj/effect/floor_decal/corner/paleblue{ dir = 10 }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/map_template/colony/medbay) "dV" = ( /obj/machinery/chemical_dispenser/full, /obj/effect/floor_decal/corner/paleblue{ dir = 10 }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/map_template/colony/medbay) "dW" = ( /obj/structure/table/steel_reinforced, @@ -1925,32 +1737,30 @@ /obj/effect/floor_decal/corner/paleblue{ dir = 10 }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/map_template/colony/medbay) "dX" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "dY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "dZ" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "ea" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/box/syringes, -/obj/item/storage/box/autoinjectors, -/obj/item/storage/box/autoinjectors, +/obj/item/box/syringes, +/obj/item/box/autoinjectors, +/obj/item/box/autoinjectors, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 @@ -1961,7 +1771,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eb" = ( /obj/structure/iv_drip, @@ -1976,7 +1786,7 @@ dir = 1; pixel_y = 16 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "ec" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1986,13 +1796,11 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/glass/medical, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "ed" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -2001,7 +1809,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "ee" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2011,11 +1819,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "ef" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2025,61 +1831,52 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eg" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eh" = ( /obj/structure/catwalk, /obj/structure/closet/crate/solar_assembly, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "ei" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "ej" = ( /obj/structure/table/steel_reinforced, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, -/obj/item/storage/box/freezer, -/obj/item/storage/box/freezer, +/obj/item/box/freezer, +/obj/item/box/freezer, /obj/effect/floor_decal/corner/red{ dir = 9 }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "ek" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -2089,27 +1886,22 @@ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "el" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/sign/warning/compressed_gas{ pixel_y = -28 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "em" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2118,7 +1910,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/map_template/colony/messhall) "en" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2127,49 +1919,42 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/map_template/colony/messhall) "eo" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ep" = ( /obj/machinery/atmospherics/pipe/cap/hidden, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/template_noop) "eq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "er" = ( /obj/machinery/atmospherics/pipe/simple/visible, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "es" = ( /obj/machinery/atmospherics/binary/pump{ @@ -2177,10 +1962,9 @@ name = "waste pump" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "et" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2190,38 +1974,32 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "eu" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/visible/fuel, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "ev" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/map_template/colony/messhall) "ew" = ( /obj/structure/railing/mapped{ - dir = 1; - icon_state = "railing0-1" + dir = 1 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "ex" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2231,22 +2009,19 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/medical, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "ey" = ( /obj/machinery/atmospherics/pipe/simple/visible, /obj/machinery/meter, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "ez" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2256,37 +2031,31 @@ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eA" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 8 }, /obj/effect/floor_decal/corner_techfloor_grid, /obj/machinery/light/spot{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eB" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/alarm{ @@ -2297,30 +2066,27 @@ /obj/machinery/light/spot{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/table/marble, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "eD" = ( /obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/command) "eE" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2330,27 +2096,22 @@ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/surgery) "eG" = ( /obj/machinery/door/blast/shutters{ id_tag = "colsen"; - name = "Hard Storage Shutter"; - + name = "Hard Storage Shutter" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/command) "eH" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/closet/crate, @@ -2373,77 +2134,74 @@ /obj/item/stock_parts/smes_coil/super_io, /obj/item/stock_parts/smes_coil/weak, /obj/item/stock_parts/smes_coil/weak, -/obj/item/stack/material/tritium/fifty, -/obj/item/stack/material/tritium/fifty, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/item/stack/material/aerogel/mapped/tritium/fifty, +/obj/item/stack/material/aerogel/mapped/tritium/fifty, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "eI" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/structure/table/steel_reinforced, -/obj/item/pipe_painter, -/turf/simulated/floor/tiled/techfloor, +/obj/item/paint_sprayer, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eJ" = ( /obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/canister/air, /obj/effect/floor_decal/industrial/outline/blue, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eK" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/machinery/vending/tool, +/obj/machinery/vending/tool{ + dir = 4 + }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "eL" = ( -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "eM" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/toolbox/mechanical, -/obj/item/storage/toolbox/mechanical, +/obj/item/toolbox/mechanical, +/obj/item/toolbox/mechanical, /obj/item/integrated_circuit_printer/upgraded, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "eN" = ( /obj/structure/table/marble, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "eO" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, /obj/structure/table/steel_reinforced, -/obj/item/storage/box/beakers, -/obj/item/storage/box/beakers, +/obj/item/box/beakers, +/obj/item/box/beakers, /obj/effect/floor_decal/corner/paleblue{ dir = 5 }, -/obj/item/storage/belt/medical, +/obj/item/belt/medical, /obj/item/scanner/health, -/obj/item/storage/pill_bottle/painkillers, -/obj/item/storage/pill_bottle/painkillers, -/obj/item/storage/pill_bottle/antibiotics, -/obj/item/storage/pill_bottle/antibiotics, +/obj/item/pill_bottle/painkillers, +/obj/item/pill_bottle/painkillers, +/obj/item/pill_bottle/antibiotics, +/obj/item/pill_bottle/antibiotics, /obj/item/chems/glass/beaker/large, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2452,7 +2210,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "eQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2461,35 +2219,31 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "eR" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "eS" = ( /obj/machinery/reagentgrinder, /obj/effect/floor_decal/corner/paleblue{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2499,33 +2253,29 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "eU" = ( /obj/machinery/atmospherics/pipe/manifold/visible{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eV" = ( /obj/machinery/atmospherics/binary/pump, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "eW" = ( /obj/machinery/door/firedoor, @@ -2536,47 +2286,46 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/civilian{ name = "Bunk Room" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/dorms) "eX" = ( -/obj/effect/submap_landmark/spawnpoint/colonist_spawn, +/obj/abstract/submap_landmark/spawnpoint/colonist_spawn, /obj/structure/bed/padded, /obj/item/gun/energy/gun/small, /obj/item/flashlight/upgraded, /obj/item/crowbar, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/captain_fly, -/obj/item/clothing/under/frontier, -/obj/item/clothing/under/hazard, -/obj/item/clothing/under/skirt, -/obj/item/clothing/under/suit_jacket/female, -/obj/item/clothing/under/suit_jacket/navy, -/obj/item/clothing/under/suit_jacket/charcoal, -/obj/item/clothing/under/syndicate, -/obj/item/clothing/under/sterile, -/obj/item/clothing/under/det/grey, -/obj/item/clothing/under/casual_pants/baggy, -/obj/item/clothing/under/casual_pants/camo, -/obj/item/clothing/under/casual_pants/track, -/obj/item/clothing/under/casual_pants/youngfolksjeans, -/obj/item/clothing/suit/storage/hooded/wintercoat/miner, -/obj/item/clothing/suit/storage/hooded/wintercoat, -/obj/item/clothing/suit/storage/toggle/bomber, -/obj/item/clothing/suit/storage/toggle/brown_jacket, -/obj/item/clothing/suit/storage/toggle/hoodie/nt, -/obj/item/clothing/suit/storage/toggle/hoodie/smw, +/obj/item/clothing/jumpsuit/blackjumpshorts, +/obj/item/clothing/costume/captain_fly, +/obj/item/clothing/shirt/flannel/red, +/obj/item/clothing/suit/apron/overalls/denim, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/clothing/skirt, +/obj/item/clothing/pants/slacks/black/outfit/navy, +/obj/item/clothing/pants/slacks/black/outfit, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/shirt/syndicate, +/obj/item/clothing/jumpsuit/sterile, +/obj/item/clothing/pants/slacks/outfit/detective, +/obj/item/clothing/pants/baggy, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/pants/casual/track, +/obj/item/clothing/pants/casual/youngfolksjeans, +/obj/item/clothing/suit/jacket/winter/miner, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/bomber, +/obj/item/clothing/suit/jacket/brown, +/obj/item/clothing/suit/toggle/nt_hoodie, +/obj/item/clothing/suit/jacket/hoodie, /obj/item/radio, /obj/structure/closet/shipping_wall{ pixel_y = 34 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/dorms) "eY" = ( /obj/machinery/sleeper/standard{ @@ -2588,81 +2337,79 @@ /obj/effect/floor_decal/corner/paleblue{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/medbay) "eZ" = ( /obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "fa" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fc" = ( /obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "fd" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/toolbox/syndicate, -/obj/item/tape_roll, -/obj/item/tape_roll, +/obj/item/toolbox/syndicate, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/tape_roll/duct_tape, /obj/item/crowbar/brace_jack, /obj/item/clothing/head/hardhat/white, /obj/item/grenade/chem_grenade/metalfoam, /obj/item/grenade/chem_grenade/metalfoam, /obj/item/grenade/chem_grenade/metalfoam, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "fe" = ( -/obj/structure/table/woodentable_reinforced, +/obj/structure/table/wood/reinforced, /obj/structure/flora/pottedplant/smallcactus{ pixel_y = 12 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/obj/item/chems/food/condiment/small/peppermill, -/obj/item/chems/food/condiment/small/saltshaker, -/obj/item/chems/food/condiment/small/sugar, -/turf/simulated/floor/wood, +/obj/item/chems/condiment/small/peppermill, +/obj/item/chems/condiment/small/saltshaker, +/obj/item/chems/condiment/small/sugar, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "ff" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "fh" = ( /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fi" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, -/turf/simulated/floor/exoplanet/concrete, +/obj/abstract/landmark/allowed_leak, +/turf/floor/concrete, /area/template_noop) "fj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -2670,10 +2417,10 @@ dir = 1 }, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "fk" = ( /obj/machinery/alarm{ @@ -2682,32 +2429,30 @@ }, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/structure/table/marble, -/obj/machinery/chemical_dispenser/bar_coffee/full, +/obj/machinery/chemical_dispenser/bar_coffee/full{ + dir = 4 + }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 9 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fl" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/machinery/light/spot{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fm" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/computer/air_control{ @@ -2718,89 +2463,76 @@ sensor_tag = "c2" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fn" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fo" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, /obj/structure/sign/double/maltesefalcon/right{ pixel_y = 32 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/vending/engineering{ + dir = 4; req_access = list() }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "fq" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "fr" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "fs" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "ft" = ( /obj/machinery/atmospherics/pipe/simple/visible/black, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/computer/air_control{ @@ -2811,20 +2543,19 @@ sensor_tag = "c3" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fu" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, /obj/structure/sign/double/maltesefalcon/left{ pixel_y = 32 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -2832,172 +2563,154 @@ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fw" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/vending/engivend{ + dir = 4; req_access = list() }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "fx" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "fz" = ( /obj/machinery/atmospherics/pipe/simple/visible{ - icon_state = "intact"; dir = 9 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fA" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/structure/closet/crate, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/wood/fifty, -/obj/item/stack/material/wood/fifty, -/obj/item/stack/material/wood/fifty, -/obj/item/stack/material/wood/fifty, -/turf/simulated/floor/tiled/techfloor, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/item/stack/material/plank/mapped/wood/fifty, +/obj/item/stack/material/plank/mapped/wood/fifty, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "fB" = ( /obj/structure/closet/crate, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/glass/reinforced/fifty, -/obj/item/stack/material/glass/reinforced/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, /obj/item/clothing/head/hardhat/orange, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "fC" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fD" = ( /obj/machinery/atmospherics/binary/pump, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/red{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fE" = ( /obj/machinery/atmospherics/binary/pump, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/blue{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fF" = ( /obj/machinery/atmospherics/binary/pump, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fG" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/glass/civilian, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/messhall) "fH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fI" = ( -/obj/structure/table/woodentable_reinforced, -/obj/item/storage/box/donut, +/obj/structure/table/wood/reinforced, +/obj/item/box/fancy/donut, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/obj/item/chems/food/condiment/small/peppermill, -/obj/item/chems/food/condiment/small/saltshaker, -/obj/item/chems/food/condiment/small/sugar, -/turf/simulated/floor/wood, +/obj/item/chems/condiment/small/peppermill, +/obj/item/chems/condiment/small/saltshaker, +/obj/item/chems/condiment/small/sugar, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3006,62 +2719,61 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/messhall) "fK" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, /obj/machinery/light{ dir = 4 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 5 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "fL" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/engineering, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "fM" = ( /obj/item/gun/energy/gun/small, /obj/item/flashlight/upgraded, /obj/item/crowbar, -/obj/item/clothing/under/captain_fly, -/obj/item/clothing/under/color/blackjumpshorts, -/obj/item/clothing/under/frontier, -/obj/item/clothing/under/hazard, -/obj/item/clothing/under/skirt, -/obj/item/clothing/under/suit_jacket/female, -/obj/item/clothing/under/suit_jacket/navy, -/obj/item/clothing/under/syndicate, -/obj/item/clothing/under/sterile, -/obj/item/clothing/under/det/grey, -/obj/item/clothing/under/casual_pants/baggy, -/obj/item/clothing/under/casual_pants/camo, -/obj/item/clothing/under/casual_pants/track, -/obj/item/clothing/under/casual_pants/youngfolksjeans, -/obj/item/clothing/suit/storage/hooded/wintercoat/miner, -/obj/item/clothing/suit/storage/hooded/wintercoat, -/obj/item/clothing/suit/storage/toggle/bomber, -/obj/item/clothing/suit/storage/toggle/brown_jacket, -/obj/item/clothing/suit/storage/toggle/hoodie/nt, -/obj/item/clothing/suit/storage/toggle/hoodie/smw, -/obj/item/clothing/suit/storage/toggle/track/gcc, +/obj/item/clothing/costume/captain_fly, +/obj/item/clothing/jumpsuit/blackjumpshorts, +/obj/item/clothing/shirt/flannel/red, +/obj/item/clothing/suit/apron/overalls/denim, +/obj/item/clothing/jumpsuit/hazard, +/obj/item/clothing/skirt, +/obj/item/clothing/pants/slacks/outfit, +/obj/item/clothing/pants/slacks/black/outfit/navy, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/shirt/syndicate, +/obj/item/clothing/jumpsuit/sterile, +/obj/item/clothing/pants/slacks/outfit/detective, +/obj/item/clothing/pants/baggy, +/obj/item/clothing/pants/casual/camo, +/obj/item/clothing/pants/casual/track, +/obj/item/clothing/pants/casual/youngfolksjeans, +/obj/item/clothing/suit/jacket/winter/miner, +/obj/item/clothing/suit/jacket/winter, +/obj/item/clothing/suit/jacket/bomber, +/obj/item/clothing/suit/jacket/brown, +/obj/item/clothing/suit/toggle/nt_hoodie, +/obj/item/clothing/suit/jacket/hoodie, +/obj/item/clothing/suit/toggle/track, /obj/item/radio, /obj/structure/closet/cabinet, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/map_template/colony/dorms) "fN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3071,11 +2783,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "fO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3085,15 +2795,12 @@ dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fP" = ( /obj/machinery/door/firedoor, @@ -3104,24 +2811,20 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/atmos, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "fR" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -3131,32 +2834,24 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fS" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3166,10 +2861,9 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3179,29 +2873,21 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fV" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/corner/green{ @@ -3210,7 +2896,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -3218,10 +2904,9 @@ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fX" = ( /obj/machinery/door/firedoor, @@ -3232,54 +2917,45 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fY" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "fZ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ga" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3287,15 +2963,15 @@ }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/table/marble, -/obj/item/storage/box/glasses/mug, -/obj/item/storage/box/glasses/pint, -/obj/item/storage/box/glasses/square, -/obj/item/storage/box/glass_extras/straws, +/obj/item/box/glasses/mug, +/obj/item/box/glasses/pint, +/obj/item/box/glasses/square, +/obj/item/box/glass_extras/straws, /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/obj/item/chems/food/drinks/pitcher, -/turf/simulated/floor/wood, +/obj/item/chems/drinks/pitcher, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "gc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3308,7 +2984,7 @@ locked = 0; pixel_y = 20 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/messhall) "gd" = ( /obj/machinery/door/firedoor, @@ -3319,7 +2995,7 @@ dir = 4 }, /obj/machinery/door/airlock/civilian, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "ge" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -3333,60 +3009,51 @@ /obj/random/drinkbottle, /obj/random/drinkbottle, /obj/random/drinkbottle, -/obj/item/storage/lunchbox/syndicate/filled, -/obj/item/storage/lunchbox/cat/filled, -/obj/item/storage/lunchbox/nt/filled, -/obj/item/storage/lunchbox/nymph/filled, +/obj/item/lunchbox/syndicate/filled, +/obj/item/lunchbox/cat/filled, +/obj/item/lunchbox/nt/filled, +/obj/item/lunchbox/nymph/filled, /obj/item/pizzabox/meat, /obj/item/pizzabox/margherita, /obj/item/pizzabox/mushroom, /obj/item/pizzabox/vegetable, -/obj/item/storage/box/cola/spaceup, -/obj/item/storage/box/cola/spacewind, -/obj/item/storage/box/cola/icedtea, -/obj/item/storage/box/cola/drgibb, -/obj/item/chems/food/drinks/shaker, -/obj/item/chems/food/drinks/pitcher, +/obj/item/box/cola/spaceup, +/obj/item/box/cola/spacewind, +/obj/item/box/cola/icedtea, +/obj/item/box/cola/drgibb, +/obj/item/chems/drinks/shaker, +/obj/item/chems/drinks/pitcher, /obj/item/chems/glass/beaker/bowl, -/obj/item/chems/food/condiment/salt, -/obj/item/chems/food/condiment/enzyme, -/turf/simulated/floor/tiled/freezer, +/obj/item/chems/condiment/large/salt, +/obj/item/chems/condiment/enzyme, +/turf/floor/tiled/freezer, /area/map_template/colony/messhall) "gf" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/engineering) "gg" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3396,29 +3063,24 @@ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/paleblue{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gi" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "gj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3428,15 +3090,12 @@ dir = 5 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gk" = ( /obj/machinery/atmospherics/binary/pump{ @@ -3444,21 +3103,19 @@ }, /obj/effect/floor_decal/techfloor, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 4 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 1 }, /obj/machinery/light/spot, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "gm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3468,14 +3125,13 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/alarm{ locked = 0; pixel_y = 20 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3485,22 +3141,19 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "go" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "gp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3510,15 +3163,12 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3528,15 +3178,12 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gr" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -3544,88 +3191,78 @@ level = 2 }, /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/storage/box/snack/tastybread, -/obj/item/storage/box/snack/tastybread, -/obj/item/storage/box/snack/noraisin, -/obj/item/storage/box/snack/jerky, -/obj/item/storage/box/snack/candy, -/turf/simulated/floor/tiled/freezer, +/obj/item/box/snack/tastybread, +/obj/item/box/snack/tastybread, +/obj/item/box/snack/noraisin, +/obj/item/box/snack, +/obj/item/box/snack/candy, +/turf/floor/tiled/freezer, /area/map_template/colony/messhall) "gs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet/green, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet/green, /area/map_template/colony/messhall) "gt" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/colony/jail) "gu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/colony/jail) "gv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/colony/jail) "gw" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gx" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gy" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gz" = ( /obj/structure/closet/secure_closet/freezer/meat, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/map_template/colony/messhall) "gA" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -3634,14 +3271,13 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "gB" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gC" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -3650,7 +3286,7 @@ }, /obj/structure/table/marble, /obj/machinery/microwave, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "gD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3660,7 +3296,7 @@ dir = 4 }, /obj/structure/hygiene/drain, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3670,48 +3306,48 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/effect/floor_decal/corner/green, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gF" = ( /obj/machinery/atmospherics/binary/pump/high_power, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "gG" = ( /obj/machinery/atmospherics/unary/tank/air, /obj/effect/floor_decal/industrial/outline/blue, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "gH" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/toolbox/electrical, -/obj/item/storage/toolbox/electrical, +/obj/item/toolbox/electrical, +/obj/item/toolbox/electrical, /obj/machinery/light{ dir = 4 }, -/obj/item/storage/belt/utility, -/obj/item/storage/belt/utility, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/steel/fifty, +/obj/item/belt/utility, +/obj/item/belt/utility, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, /obj/item/geiger, /obj/item/geiger, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "gI" = ( /obj/structure/table/marble, -/obj/machinery/chemical_dispenser/bar_soft/full, +/obj/machinery/chemical_dispenser/bar_soft/full{ + dir = 4 + }, /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "gJ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -3719,7 +3355,6 @@ level = 2 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/paleblue{ @@ -3729,55 +3364,53 @@ /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "gK" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/table/marble, -/obj/machinery/chemical_dispenser/bar_alc/full, -/turf/simulated/floor/lino, +/obj/machinery/chemical_dispenser/bar_alc/full{ + dir = 1 + }, +/turf/floor/lino, /area/map_template/colony/messhall) "gL" = ( -/obj/machinery/atmospherics/unary/heater{ - icon_state = "heater_0"; +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gM" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/meter, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gN" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gO" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red, /obj/effect/floor_decal/techfloor, /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gP" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/carpet/green, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/carpet/green, /area/map_template/colony/messhall) "gQ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -3785,40 +3418,32 @@ pressure_checks = 0 }, /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/structure/railing/mapped{ - dir = 1; - icon_state = "railing0-1" + dir = 1 }, /obj/effect/floor_decal/industrial/hatch/orange, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/airlock) "gR" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; - id_tag = "playablecolonymain_pump_out_external"; - + id_tag = "playablecolonymain_pump_out_external" }, /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/hatch/orange, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/airlock) "gT" = ( /obj/machinery/atmospherics/binary/pump, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gU" = ( /obj/machinery/atmospherics/omni/mixer{ @@ -3828,20 +3453,19 @@ tag_west = 1; tag_west_con = 0.79 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "gV" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gW" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/engineering) "gX" = ( /obj/machinery/atmospherics/portables_connector{ @@ -3849,22 +3473,19 @@ }, /obj/machinery/portable_atmospherics/canister/carbon_dioxide, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "gY" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "gZ" = ( /obj/machinery/atmospherics/unary/heat_exchanger{ @@ -3875,9 +3496,8 @@ }, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "ha" = ( /obj/machinery/atmospherics/unary/heat_exchanger{ @@ -3885,12 +3505,11 @@ }, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "hb" = ( /obj/machinery/atmospherics/pipe/simple/visible/universal{ @@ -3898,10 +3517,9 @@ }, /obj/machinery/meter, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "hc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3911,22 +3529,18 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/green{ dir = 10 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hd" = ( /obj/machinery/fabricator/pipe, @@ -3935,33 +3549,28 @@ level = 2 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "he" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "hf" = ( /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor/hole/right, /obj/machinery/light, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hg" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -3971,64 +3580,53 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/green{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hh" = ( /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hi" = ( /obj/machinery/atmospherics/portables_connector, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "hj" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/manifold/visible/black{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "hk" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hl" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "hm" = ( /obj/machinery/atmospherics/omni/filter{ @@ -4036,119 +3634,99 @@ tag_north = 4; tag_south = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "hn" = ( /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/item/radio/intercom{ dir = 1; - pixel_y = -28 + pixel_y = -30 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ho" = ( /obj/effect/floor_decal/techfloor, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hp" = ( /obj/machinery/door/firedoor, /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hq" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, -/turf/simulated/floor/exoplanet/concrete, +/obj/abstract/landmark/allowed_leak, +/turf/floor/concrete, /area/template_noop) "hr" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony) "hs" = ( /obj/item/stool/bar/padded, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "ht" = ( /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hu" = ( /obj/machinery/door/firedoor, /obj/effect/floor_decal/techfloor, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hv" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hw" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hx" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, /obj/item/radio/intercom{ dir = 1; - pixel_y = -28 + pixel_y = -30 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "hy" = ( /obj/machinery/alarm{ @@ -4156,31 +3734,30 @@ pixel_y = 20 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "hz" = ( /obj/machinery/vending/cola{ - name = "hacked Robust Softdrinks"; - markup = 0 + dir = 1; + markup = 0; + name = "hacked Robust Softdrinks" }, /obj/machinery/light, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "hA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hB" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/ammo_magazine/pistol/small, /obj/item/ammo_magazine/pistol, /obj/item/ammo_magazine/pistol, @@ -4188,10 +3765,10 @@ /obj/item/ammo_magazine/pistol/small, /obj/item/ammo_magazine/pistol/small, /obj/item/ammo_magazine/pistol/rubber, -/obj/item/storage/box/ammo/shotgunshells, -/obj/item/storage/box/ammo/shotgunshells, -/obj/item/storage/box/ammo/shotgunammo, -/obj/item/storage/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunshells, +/obj/item/box/ammo/shotgunshells, +/obj/item/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunammo, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, @@ -4202,102 +3779,96 @@ /obj/item/radio, /obj/item/radio, /obj/item/radio, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "hC" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/effect/floor_decal/corner/red, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "hD" = ( /obj/machinery/vending/snack{ - name = "hacked Getmore Chocolate Corp"; - markup = 0 + dir = 1; + markup = 0; + name = "hacked Getmore Chocolate Corp" }, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "hE" = ( /obj/machinery/vending/fitness{ - name = "hacked SweatMAX"; - markup = 0 + dir = 4; + markup = 0; + name = "hacked SweatMAX" }, /obj/effect/floor_decal/corner/paleblue{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hF" = ( /obj/machinery/atmospherics/binary/oxyregenerator, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "hG" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "hI" = ( /obj/item/stool/bar/padded, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "hJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/item/stool/bar/padded, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "hL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/machinery/alarm{ locked = 0; pixel_y = 20 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "hM" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/corner/red{ @@ -4306,47 +3877,40 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "hN" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hO" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/green{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hP" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; dir = 1 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "hQ" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/red{ @@ -4356,11 +3920,11 @@ dir = 1 }, /obj/structure/table/steel_reinforced, -/obj/item/storage/box/donut, -/turf/simulated/floor/tiled/techfloor, +/obj/item/box/fancy/donut, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "hR" = ( -/turf/simulated/wall, +/turf/wall, /area/map_template/colony/jail) "hS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -4369,27 +3933,25 @@ /obj/structure/casino/roulette_chart{ density = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "hT" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, /obj/item/stool/bar/padded, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "hU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/spline/fancy/wood{ dir = 6 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/messhall) "hV" = ( /obj/machinery/door/firedoor, @@ -4400,15 +3962,13 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/highsecurity, /obj/machinery/door/blast/regular{ id_tag = "colarm" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "hW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -4416,82 +3976,69 @@ dir = 8 }, /obj/structure/hygiene/drain, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hX" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "hY" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/green{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "hZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ia" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "ib" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ic" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "id" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/cryopod{ @@ -4500,19 +4047,17 @@ /obj/machinery/computer/cryopod{ pixel_y = 25 }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/map_template/colony/bathroom) "ie" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, /obj/effect/floor_decal/corner/red, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "if" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/machinery/alarm{ @@ -4522,7 +4067,7 @@ /obj/effect/floor_decal/corner/red{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "ig" = ( /obj/machinery/door/firedoor, @@ -4533,79 +4078,71 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/glass/civilian, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/map_template/colony/commons) "ih" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ii" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/pistol/holdout, /obj/item/gun/projectile/pistol/holdout, /obj/item/gun/projectile/pistol, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "ij" = ( /obj/structure/hygiene/shower{ - pixel_x = 0; pixel_y = 20 }, /obj/effect/floor_decal/corner/paleblue{ dir = 5 }, -/turf/simulated/floor/tiled/white/monotile, +/turf/floor/tiled/white/monotile, /area/map_template/colony/bathroom) "ik" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, /obj/effect/floor_decal/industrial/outline, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "il" = ( /obj/machinery/atmospherics/portables_connector{ dir = 8 }, /obj/effect/floor_decal/industrial/outline/red, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "im" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "in" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/red{ dir = 10 }, /obj/effect/floor_decal/techfloor/hole/right{ - icon_state = "techfloor_hole_right"; dir = 1 }, /obj/machinery/recharger/wallcharger{ @@ -4617,10 +4154,10 @@ /obj/machinery/recharger/wallcharger{ pixel_y = 36 }, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "io" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -4631,27 +4168,24 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "ip" = ( /obj/effect/floor_decal/borderfloorwhite, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "iq" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "ir" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -4659,10 +4193,9 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "is" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -4672,11 +4205,9 @@ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "it" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -4686,11 +4217,10 @@ /obj/machinery/door/blast/regular{ id_tag = "colsecarm" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "iu" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/alarm{ @@ -4700,33 +4230,31 @@ /obj/effect/floor_decal/corner/red{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iv" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/effect/floor_decal/corner/red{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iw" = ( /obj/structure/table/marble, /obj/machinery/reagent_temperature, -/obj/item/chems/food/drinks/shaker, +/obj/item/chems/drinks/shaker, /obj/machinery/vending/boozeomat{ density = 0; pixel_y = -32; req_access = list() }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony/messhall) "ix" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/structure/reagent_dispensers/peppertank{ @@ -4735,13 +4263,13 @@ /obj/effect/floor_decal/corner/red{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iy" = ( /obj/effect/floor_decal/borderfloorwhite, /obj/structure/bed/roller/ironingboard, /obj/item/ironingiron, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "iz" = ( /obj/machinery/door/firedoor, @@ -4752,31 +4280,29 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/glass/security, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iA" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/shotgun/doublebarrel, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "iB" = ( /obj/machinery/atmospherics/portables_connector{ dir = 4 }, /obj/effect/floor_decal/industrial/outline/orange, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "iC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4786,24 +4312,21 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iD" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4813,54 +4336,44 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/green{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iG" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4870,16 +4383,12 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -4889,66 +4398,54 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iJ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iK" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/effect/floor_decal/techfloor, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 4 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 1 }, /obj/structure/closet/firecloset, /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "iL" = ( /obj/machinery/door/firedoor, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iM" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -4956,10 +4453,9 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iN" = ( /obj/machinery/atmospherics/portables_connector{ @@ -4967,21 +4463,19 @@ }, /obj/effect/floor_decal/industrial/outline/orange, /obj/machinery/light/spot, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "iO" = ( /obj/structure/table/gamblingtable, /obj/item/ashtray/glass, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "iP" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/item/stool/bar/padded, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "iQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -4989,34 +4483,30 @@ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "iR" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/closet/crate, /obj/item/deck/cards, /obj/item/deck/cards, -/obj/item/storage/pill_bottle/dice, -/obj/item/storage/pill_bottle/dice_nerd, +/obj/item/pill_bottle/dice, +/obj/item/pill_bottle/dice_nerd, /obj/random/drinkbottle, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 9 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "iS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "iT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5026,23 +4516,18 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5052,28 +4537,25 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iV" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/mineralprocessing) "iW" = ( /obj/machinery/atmospherics/pipe/manifold/visible{ dir = 8 }, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "iX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5083,31 +4565,23 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/hygiene/drain, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "iY" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/scanner/gas, /obj/item/scanner/gas, /obj/item/scanner/gas, -/obj/item/clamp, -/obj/item/clamp, -/obj/item/clamp, -/obj/item/clamp, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "iZ" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/red{ @@ -5117,7 +4591,7 @@ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "ja" = ( /obj/machinery/vending/sovietsoda, @@ -5125,29 +4599,27 @@ dir = 1 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jc" = ( /obj/structure/sign/warning/smoking{ pixel_y = -28 }, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jd" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ dir = 6 }, /obj/structure/flora/pottedplant/minitree, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "je" = ( /obj/item/stool/bar/padded, @@ -5155,65 +4627,54 @@ pixel_y = 28 }, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jf" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jg" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jh" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/structure/closet{ name = "Prisoner's Locker" }, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "ji" = ( /obj/effect/floor_decal/techfloor, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, @@ -5223,31 +4684,28 @@ /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jj" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/item/stool/bar/padded, /obj/effect/decal/cleanable/cobweb2, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 5 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jk" = ( /obj/structure/hygiene/toilet{ pixel_y = 12 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/vomit, -/turf/simulated/floor/tiled/white/monotile, +/obj/effect/decal/cleanable/vomit/mapped, +/turf/floor/tiled/white/monotile, /area/map_template/colony/bathroom) "jl" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -5257,15 +4715,13 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jm" = ( /obj/effect/floor_decal/techfloor, @@ -5277,7 +4733,7 @@ /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jn" = ( /obj/machinery/door/firedoor, @@ -5288,12 +4744,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/civilian, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jo" = ( /obj/effect/floor_decal/techfloor, @@ -5301,52 +4755,45 @@ dir = 5 }, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jp" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jr" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "js" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jt" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5358,7 +4805,7 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "ju" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -5366,7 +4813,7 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -5374,35 +4821,31 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 4 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/paleblue{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "jy" = ( /obj/effect/floor_decal/techfloor, @@ -5412,67 +4855,61 @@ /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jz" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, /obj/effect/floor_decal/corner/red{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jA" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/glass/security, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jB" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/item/radio/intercom{ dir = 4; - pixel_x = -21 + pixel_x = -22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jC" = ( /obj/machinery/conveyor{ id_tag = "colonymine" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/mineralprocessing) "jD" = ( /obj/effect/floor_decal/borderfloorwhite, /obj/structure/table/steel_reinforced, -/obj/item/storage/box/detergent, +/obj/item/box/detergent, /obj/item/radio/intercom{ dir = 1; - pixel_y = -28 + pixel_y = -30 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jE" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -5480,74 +4917,68 @@ }, /obj/item/stool/bar/padded, /obj/effect/floor_decal/spline/fancy/wood{ - icon_state = "spline_fancy"; dir = 10 }, /obj/item/radio/intercom{ dir = 1; - pixel_y = -28 + pixel_y = -30 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jF" = ( /obj/machinery/door/airlock/civilian, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jG" = ( /obj/structure/table/gamblingtable, /obj/machinery/light, /obj/effect/floor_decal/spline/fancy/wood, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "jH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jI" = ( /obj/structure/hygiene/sink{ dir = 1; pixel_y = 16 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_y = 32 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jK" = ( /obj/structure/catwalk, /obj/machinery/light/spot{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/messhall) "jL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -5557,14 +4988,12 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/paleblue{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "jM" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, @@ -5572,43 +5001,34 @@ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jN" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/green{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -5617,7 +5037,7 @@ /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -5625,13 +5045,12 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jQ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -5639,11 +5058,11 @@ level = 2 }, /obj/machinery/vending/lavatory{ - name = "hacked Lavatory Essentials"; - markup = 0 + dir = 4; + markup = 0; + name = "hacked Lavatory Essentials" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ @@ -5652,11 +5071,10 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony) "jR" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ @@ -5666,16 +5084,13 @@ /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jS" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -5688,7 +5103,7 @@ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5699,7 +5114,7 @@ }, /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "jU" = ( /obj/machinery/door/firedoor, @@ -5710,21 +5125,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/glass/civilian, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "jV" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/red{ @@ -5733,7 +5143,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -5744,43 +5154,38 @@ dir = 10 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "jX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jY" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "jZ" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/reagent_dispensers/watertank, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ka" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -5791,25 +5196,23 @@ /obj/effect/floor_decal/spline/fancy/wood{ dir = 6 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/commons) "kb" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/item/stool/bar/padded, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kc" = ( /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "kd" = ( /obj/machinery/door/window, @@ -5817,12 +5220,10 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "ke" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -5834,7 +5235,7 @@ /obj/structure/table/steel_reinforced, /obj/machinery/reagentgrinder/juicer, /obj/item/chems/glass/beaker/large, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "kf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5844,18 +5245,17 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/seed_extractor, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "kg" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/glass/security, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "kh" = ( /obj/machinery/atmospherics/pipe/simple/visible/universal{ @@ -5863,24 +5263,23 @@ }, /obj/machinery/meter, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "ki" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "kj" = ( -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "kk" = ( /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "kl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5894,19 +5293,17 @@ pixel_y = 20 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/seed_storage/garden, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "km" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/vending/hydronutrients, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "kn" = ( /obj/machinery/atmospherics/omni/filter{ @@ -5915,44 +5312,41 @@ tag_west = 2 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "ko" = ( -/obj/machinery/mineral/processing_unit{ +/obj/machinery/material_processing/smeltery{ input_turf = 2; output_turf = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/mineralprocessing) "kp" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/gun, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "kq" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible, /obj/machinery/meter, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "kr" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/zipgun, /obj/item/gun/projectile/zipgun, /obj/item/gun/projectile/zipgun, @@ -5960,22 +5354,19 @@ dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "ks" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ @@ -5988,14 +5379,14 @@ /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kt" = ( -/obj/machinery/atmospherics/unary/freezer{ +/obj/machinery/atmospherics/unary/temperature/freezer{ dir = 8 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "ku" = ( /obj/machinery/alarm{ @@ -6004,22 +5395,20 @@ }, /obj/structure/reagent_dispensers/beerkeg, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kv" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/structure/closet/crate, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, /obj/item/oxycandle, /obj/item/oxycandle, /obj/item/oxycandle, @@ -6033,7 +5422,7 @@ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kw" = ( /obj/machinery/atmospherics/omni/filter{ @@ -6042,36 +5431,40 @@ tag_south = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "kx" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/obj/structure/closet/secure_closet/hydroponics, +/obj/structure/closet/secure_closet/hydroponics{ + anchored = 1; + locked = 0; + req_access = null + }, /obj/item/chems/glass/bucket, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "ky" = ( /obj/machinery/light, /obj/effect/floor_decal/techfloor, /obj/machinery/atmospherics/pipe/manifold4w/visible, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "kz" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, /obj/machinery/vending/coffee{ - name = "hacked Hot Drinks machine"; - markup = 0 + dir = 4; + markup = 0; + name = "hacked Hot Drinks machine" }, /obj/item/radio/intercom{ dir = 4; - pixel_x = -21 + pixel_x = -22 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "kA" = ( /obj/machinery/alarm{ @@ -6079,7 +5472,7 @@ pixel_y = 20 }, /obj/structure/flora/pottedplant/tropical, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "kB" = ( /obj/structure/window/reinforced{ @@ -6088,38 +5481,33 @@ /obj/structure/table/steel_reinforced, /obj/item/paper_bin, /obj/item/pen/multi, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "kC" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kD" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/atmospherics) "kE" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "kF" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -6129,46 +5517,45 @@ /obj/item/chems/spray/pepper, /obj/machinery/recharger, /obj/item/radio, -/obj/item/storage/box/handcuffs, -/turf/simulated/floor/tiled/techfloor, +/obj/item/box/handcuffs, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "kG" = ( /obj/effect/floor_decal/techfloor/orange, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/button/alternate/door/bolts{ id_tag = "colj"; name = "Jail Bolt Control"; - pixel_x = 28 + pixel_x = 28; + dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "kH" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/closet, -/obj/item/storage/backpack/rucksack/tan, -/obj/item/storage/backpack/rucksack/navy, -/obj/item/storage/backpack/rucksack/green, -/obj/item/storage/backpack/rucksack/blue, -/obj/item/storage/backpack/satchel/leather/black, -/obj/item/storage/backpack/satchel/leather/khaki, -/obj/item/storage/backpack/satchel/leather/navy, -/obj/item/storage/backpack/satchel/leather/olive, -/obj/item/storage/backpack/satchel/leather/reddish, -/obj/item/storage/backpack/messenger/med, -/obj/item/storage/backpack/messenger/chem, -/obj/item/clothing/accessory/storage/drop_pouches/black, -/obj/item/clothing/accessory/storage/drop_pouches/black, -/obj/item/clothing/accessory/storage/drop_pouches/brown, -/obj/item/clothing/accessory/storage/drop_pouches/brown, -/obj/item/clothing/accessory/storage/drop_pouches/white, -/obj/item/clothing/accessory/storage/drop_pouches/white, -/turf/simulated/floor/wood, +/obj/item/backpack/rucksack/tan, +/obj/item/backpack/rucksack/navy, +/obj/item/backpack/rucksack/green, +/obj/item/backpack/rucksack/blue, +/obj/item/backpack/satchel/leather/black, +/obj/item/backpack/satchel/leather/khaki, +/obj/item/backpack/satchel/leather/navy, +/obj/item/backpack/satchel/leather/olive, +/obj/item/backpack/satchel/leather/reddish, +/obj/item/backpack/messenger/med, +/obj/item/backpack/messenger/chem, +/obj/item/clothing/webbing/drop_pouches/black, +/obj/item/clothing/webbing/drop_pouches/black, +/obj/item/clothing/webbing/drop_pouches/brown, +/obj/item/clothing/webbing/drop_pouches/brown, +/obj/item/clothing/webbing/drop_pouches/white, +/obj/item/clothing/webbing/drop_pouches/white, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "kI" = ( /obj/machinery/door/airlock/hatch, @@ -6176,7 +5563,7 @@ /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony) "kJ" = ( /obj/machinery/atmospherics/binary/pump{ @@ -6185,118 +5572,109 @@ /obj/effect/floor_decal/techfloor, /obj/effect/floor_decal/techfloor/hole, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 4 }, /obj/effect/floor_decal/corner_techfloor_grid{ - icon_state = "corner_techfloor_grid"; dir = 1 }, /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/atmospherics) "kK" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/industrial/loading{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "kL" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "kM" = ( /obj/structure/crematorium{ - id = 8 + id_tag = "playablecolony_crematorium" }, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "kN" = ( /obj/machinery/button/crematorium{ - id_tag = 8; + id_tag = "playablecolony_crematorium"; pixel_y = 25; req_access = list() }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/table/steel_reinforced, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/recharger, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "kO" = ( /obj/structure/closet/firecloset, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kP" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/obj/machinery/vending/snix, -/turf/simulated/floor/lino, +/obj/machinery/vending/snix{ + dir = 4 + }, +/turf/floor/lino, /area/map_template/colony) "kQ" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "kR" = ( /obj/machinery/mech_recharger, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "kS" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kT" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "kV" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "kW" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -6305,7 +5683,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "kX" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -6313,72 +5691,62 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/obj/structure/sign/warning/secure_area/armory{ +/obj/structure/sign/warning/armory{ dir = 4; pixel_x = -32 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "kY" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/airlock) "kZ" = ( -/obj/machinery/computer/mining, /obj/structure/table/steel_reinforced, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "la" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lb" = ( /obj/machinery/door/window/eastright, /obj/structure/table/steel_reinforced, /obj/machinery/button/blast_door{ id_tag = "colmainexit"; - name = "Exit Blast Doors"; - pixel_y = 0 + name = "Exit Blast Doors" }, /obj/machinery/button/blast_door{ id_tag = "colmainblast"; name = "Entry Blast Doors"; pixel_y = 8 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "lc" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ - dir = 5; - icon_state = "intact" + dir = 5 }, /obj/machinery/atmospherics/unary/outlet_injector{ id_tag = "cn2n" }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/map_template/colony/atmospherics) "le" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -6386,26 +5754,23 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /mob/living/simple_animal/cow, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "lf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lg" = ( /obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lh" = ( /obj/machinery/door/airlock/external{ @@ -6413,146 +5778,131 @@ locked = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "li" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/machinery/conveyor_switch{ id_tag = "colonymine" }, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/steel_ridged, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/mineralprocessing) "lj" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lk" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ll" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lm" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ dir = 6 }, /obj/machinery/vending/cigarette{ - name = "hacked Cigarette machine"; - markup = 0 + dir = 4; + markup = 0; + name = "hacked Cigarette machine" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony) "ln" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning/dust{ dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lo" = ( /mob/living/simple_animal/cow, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "lp" = ( /obj/structure/hygiene/drain, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lq" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/commons) "lr" = ( /obj/effect/floor_decal/techfloor, /obj/effect/floor_decal/techfloor/hole/right, /obj/machinery/light, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "ls" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/jail) "lt" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning/dust{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lu" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning/dust{ dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lv" = ( /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lw" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8; - icon_state = "map" + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/airlock) "lx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -6565,30 +5915,25 @@ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/structure/closet/firecloset, /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "ly" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/commons) "lz" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, -/obj/machinery/computer/mining, /obj/structure/table/steel_reinforced, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lA" = ( /obj/machinery/light/spot{ @@ -6598,49 +5943,46 @@ /obj/effect/floor_decal/industrial/warning/dust{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lB" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/hydroponics) "lC" = ( /obj/machinery/light/spot{ dir = 8 }, /obj/structure/closet/crate, -/obj/item/stack/material/plasteel/ten, -/obj/item/stack/material/plasteel/ten, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/platinum/ten, -/obj/item/stack/material/diamond/ten, -/obj/item/stack/material/gold/ten, -/obj/item/stack/material/silver/ten, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/ingot/mapped/platinum/ten, +/obj/item/stack/material/gemstone/mapped/diamond/ten, +/obj/item/stack/material/ingot/mapped/gold/ten, +/obj/item/stack/material/ingot/mapped/silver/ten, /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lD" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lG" = ( /obj/machinery/door/firedoor, @@ -6649,10 +5991,10 @@ /obj/machinery/door/airlock/glass/security{ id_tag = "colj" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "lH" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/ammo_magazine/rifle, /obj/item/ammo_magazine/rifle, /obj/item/ammo_magazine/rifle, @@ -6665,7 +6007,7 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "lI" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -6678,11 +6020,10 @@ }, /obj/structure/table/steel_reinforced, /obj/machinery/recharger, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) "lJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ cycle_to_external_air = 1; id_tag = "playablecolonymain"; @@ -6692,15 +6033,15 @@ tag_exterior_door = "playablecolonymain_exterior_door"; tag_exterior_sensor = "playablecolonymain_sensor_external"; tag_interior_door = "playablecolonymain_interior_door"; - tag_interior_sensor = "playablecolonymain_sensor_interior" + tag_interior_sensor = "playablecolonymain_sensor_interior"; + tag_pump_out_internal = "playablecolonymain_pump_out_internal"; + tag_pump_out_external = "playablecolonymain_pump_out_external" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; id_tag = "playablecolonymain_pump"; - power_rating = 25000; - + power_rating = 25000 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "lK" = ( /obj/machinery/atmospherics/omni/filter{ @@ -6708,7 +6049,7 @@ tag_north = 3; tag_west = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "lL" = ( /obj/machinery/atmospherics/omni/filter{ @@ -6716,36 +6057,33 @@ tag_north = 5; tag_west = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/atmospherics) "lM" = ( /obj/machinery/airlock_sensor{ id_tag = "playablecolonymain_sensor_chamber"; - pixel_x = 22 + pixel_x = 22; + dir = 8 }, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 2; id_tag = "playablecolonymain_pump"; - power_rating = 25000; - + power_rating = 25000 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "lN" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/glass/security{ id_tag = "colj" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "lO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -6755,19 +6093,17 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lP" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lQ" = ( /obj/machinery/portable_atmospherics/canister/air/airlock, @@ -6778,19 +6114,19 @@ pixel_y = 5 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/airlock_sensor{ id_tag = "playablecolonymain_sensor_interior"; - pixel_x = -22 + pixel_x = -22; + dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "lR" = ( /obj/machinery/alarm{ @@ -6798,45 +6134,43 @@ pixel_y = 20 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/suit_cycler{ name = "Colonial suit cycler"; req_access = list() }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "lS" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning/dust{ dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lT" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lU" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning/dust{ dir = 6 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lV" = ( /obj/effect/floor_decal/industrial/warning/dust{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -6846,136 +6180,118 @@ dir = 6 }, /obj/structure/closet/crate/trashcart, -/obj/item/storage/box/detergent, -/obj/item/storage/box/detergent, +/obj/item/box/detergent, +/obj/item/box/detergent, /obj/item/mop, /obj/item/chems/glass/bucket, -/obj/item/storage/bag/trash, -/obj/item/storage/bag/trash, -/obj/item/storage/bag/trash, -/obj/item/storage/bag/trash, -/obj/item/storage/bag/trash, +/obj/item/bag/trash, +/obj/item/bag/trash, +/obj/item/bag/trash, +/obj/item/bag/trash, +/obj/item/bag/trash, /obj/item/chems/spray/cleaner, /obj/item/chems/spray/cleaner, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/obj/item/clothing/mask/plunger, +/obj/item/plunger, /obj/item/lightreplacer, -/obj/item/storage/box/lights/mixed, -/obj/item/storage/box/lights/mixed, -/turf/simulated/floor/tiled/techfloor, +/obj/item/box/lights/mixed, +/obj/item/box/lights/mixed, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lX" = ( /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "lY" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "lZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 4 }, /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "ma" = ( /obj/machinery/airlock_sensor{ id_tag = "playablecolonymain_sensor_external"; - pixel_x = 22 + pixel_x = 22; + dir = 8 }, /obj/machinery/button/access/exterior{ id_tag = "playablecolonymain"; pixel_x = 19; pixel_y = 5 }, -/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, /obj/structure/catwalk, /obj/structure/cable{ - d1 = 2; - d2 = 8; desc = "A flexible superconducting cable for heavy-duty power transfer. It's been labeled 'chaos reigns'."; icon_state = "2-8" }, /obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/closet/emcloset, /obj/item/clothing/head/helmet/space/emergency, /obj/item/clothing/suit/space/emergency, /obj/item/clothing/suit/space/emergency, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "mb" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/manifold4w/hidden, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "mc" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "md" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "me" = ( /obj/machinery/fabricator/hacked, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/engineering) "mf" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/bed, @@ -6989,15 +6305,15 @@ /obj/machinery/light/spot{ dir = 1 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "mg" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden, +/obj/machinery/atmospherics/pipe/manifold/hidden, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "mh" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ @@ -7006,168 +6322,141 @@ /obj/machinery/door/airlock/external{ id_tag = "playablecolonymain_interior_door" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "mi" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/command) "mj" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "colmainblast"; name = "Entry Blast Door" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mk" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "ml" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/jail) "mm" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/jail) "mn" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/structure/railing/mapped{ - dir = 4; - icon_state = "railing0-1"; - + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "mo" = ( /obj/machinery/door/firedoor, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "colmainexit" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mp" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/jail) "mq" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony) "mr" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "ms" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/binary/pump/high_power/on{ dir = 8; target_pressure = 500 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "mt" = ( /obj/machinery/door/firedoor, /obj/structure/cable, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/jail) "mu" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "mv" = ( /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/warning/dust, /obj/structure/ore_box, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "mw" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced_borosilicate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/airlock) "mx" = ( /obj/machinery/hologram/holopad/longrange, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/command) "my" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -7177,13 +6466,12 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/effect/floor_decal/corner/green{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mz" = ( /obj/machinery/door/firedoor, @@ -7194,56 +6482,48 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/command, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/tcomms) "mA" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/structure/closet/firecloset, /obj/item/flashlight/lamp/floodlamp, /obj/random/firstaid, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mB" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "colmainblast"; name = "Entry Blast Door" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mC" = ( /obj/structure/catwalk, /obj/machinery/button/blast_door{ id_tag = "colsen"; name = "Hard Equipment Storage"; - pixel_y = 28; - + pixel_y = 28 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/command) "mD" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/shoes/magboots, /obj/item/clothing/mask/gas/radical, /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/item/suit_cooling_unit, @@ -7251,26 +6531,22 @@ /obj/item/clothing/head/helmet/space/void/atmos, /obj/item/tank/emergency/oxygen/engi, /obj/item/tank/emergency/oxygen/engi, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "mE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "mF" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -7278,15 +6554,12 @@ level = 2 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "mG" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -7296,31 +6569,27 @@ dir = 8 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "mH" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, /obj/effect/floor_decal/corner/lime{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "mI" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/automatic/assault_rifle, /obj/item/gun/projectile/automatic/assault_rifle, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -7330,79 +6599,72 @@ dir = 5 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/armory) "mJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/effect/floor_decal/corner/red{ dir = 5 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/map_template/colony/armory) "mK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "mL" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/red{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "mM" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, -/obj/item/storage/mre/menu10, -/obj/item/storage/mre/menu9, -/obj/item/storage/mre/random, -/obj/item/storage/mre/random, -/obj/item/storage/mre/random, -/turf/simulated/floor/tiled/techfloor, +/obj/item/mre/menu10, +/obj/item/mre/menu9, +/obj/item/mre/random, +/obj/item/mre/random, +/obj/item/mre/random, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mN" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/effect/floor_decal/techfloor, -/obj/item/storage/mre/menu10, -/obj/item/storage/mre/menu9, -/obj/item/storage/mre/random, -/obj/item/storage/mre/random, -/obj/item/storage/mre/random, -/turf/simulated/floor/tiled/techfloor, +/obj/item/mre/menu10, +/obj/item/mre/menu9, +/obj/item/mre/random, +/obj/item/mre/random, +/obj/item/mre/random, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -7410,55 +6672,50 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "mP" = ( /obj/structure/table/steel_reinforced, /obj/machinery/cell_charger, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/flashlight/lamp/floodlamp, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "mQ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/railing/mapped, /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/machinery/recharge_station, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "mR" = ( -/obj/structure/bed/chair/comfy/beige{ +/obj/structure/chair/comfy/beige{ dir = 4 }, /obj/effect/floor_decal/techfloor, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mS" = ( -/obj/structure/table/woodentable_reinforced, +/obj/structure/table/wood/reinforced, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mT" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/effect/floor_decal/corner/green{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mU" = ( /obj/effect/floor_decal/techfloor, @@ -7466,7 +6723,7 @@ dir = 5 }, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -7475,26 +6732,22 @@ /obj/effect/floor_decal/corner/green{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mW" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/effect/floor_decal/corner/green{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "mX" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/lime{ @@ -7506,35 +6759,32 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "mY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor/orange, /obj/effect/floor_decal/techfloor/hole/right, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/jail) "mZ" = ( -/obj/machinery/mining/brace{ +/obj/structure/drill_brace{ dir = 4 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "na" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 5 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "nb" = ( /obj/structure/window/reinforced{ @@ -7543,7 +6793,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "nc" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -7554,14 +6804,12 @@ pixel_y = 20 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nd" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -7569,14 +6817,12 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "ne" = ( /obj/structure/window/reinforced{ @@ -7585,17 +6831,13 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "nf" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/corner/red{ @@ -7604,33 +6846,29 @@ /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "ng" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/colony/hydroponics) "nh" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/shoes/magboots, /obj/item/clothing/mask/gas/radical, /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/item/suit_cooling_unit, @@ -7638,7 +6876,7 @@ /obj/item/clothing/head/helmet/space/void/engineering/salvage, /obj/item/tank/emergency/oxygen/engi, /obj/item/tank/emergency/oxygen/engi, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "ni" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -7646,88 +6884,80 @@ dir = 5 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "nj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "nk" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/light, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/map_template/colony) "nl" = ( /obj/machinery/light{ dir = 8 }, -/mob/living/simple_animal/chicken, -/turf/simulated/floor/grass, +/mob/living/simple_animal/fowl/chicken, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "nm" = ( -/obj/machinery/mining/drill, +/obj/machinery/mining_drill, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "nn" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/portable_atmospherics/hydroponics, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "no" = ( /obj/structure/table/steel_reinforced, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "np" = ( -/obj/structure/bed/chair, +/obj/structure/chair, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nq" = ( -/obj/machinery/mining/brace{ +/obj/structure/drill_brace{ dir = 8 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/template_noop) "nr" = ( -/obj/machinery/atmospherics/unary/heater{ +/obj/machinery/atmospherics/unary/temperature/heater{ dir = 8 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "ns" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/window/reinforced{ @@ -7736,13 +6966,11 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "nt" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/wall/r_wall, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/wall/r_wall, /area/map_template/colony/airlock) "nu" = ( /obj/structure/bed, @@ -7750,7 +6978,7 @@ dir = 9 }, /obj/item/bedsheet/orange, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nv" = ( /obj/structure/table/steel_reinforced, @@ -7758,22 +6986,19 @@ dir = 6 }, /obj/machinery/recharger, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nw" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/shoes/magboots, /obj/item/clothing/mask/gas/radical, /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/item/tank/oxygen, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/item/suit_cooling_unit, @@ -7781,87 +7006,74 @@ /obj/item/clothing/head/helmet/space/void/mining/alt, /obj/item/tank/emergency/oxygen/engi, /obj/item/tank/emergency/oxygen/engi, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "nx" = ( /obj/structure/sign/warning/moving_parts{ dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/jail) "ny" = ( /obj/structure/grille, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "nz" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "nA" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "nB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "nC" = ( /obj/machinery/computer/arcade/orion_trail, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nD" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nE" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light{ @@ -7869,15 +7081,14 @@ }, /obj/structure/railing/mapped, /obj/structure/railing/mapped{ - dir = 1; - icon_state = "railing0-1" + dir = 1 }, /obj/structure/closet/emcloset, /obj/item/clothing/suit/space/emergency, /obj/item/clothing/suit/space/emergency, /obj/item/clothing/head/helmet/space/emergency, /obj/item/clothing/head/helmet/space/emergency, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "nF" = ( /obj/effect/floor_decal/corner/paleblue{ @@ -7886,7 +7097,7 @@ /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -7901,37 +7112,33 @@ /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/colony/jail) "nH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/effect/floor_decal/corner/beige, /obj/effect/floor_decal/corner/red{ - icon_state = "corner_white"; dir = 4 }, /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/map_template/colony/jail) "nI" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nJ" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -7939,20 +7146,15 @@ }, /obj/machinery/portable_atmospherics/hydroponics, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "nK" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nL" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -7968,166 +7170,136 @@ /obj/machinery/light/spot, /obj/item/radio/intercom{ dir = 1; - pixel_y = -28 + pixel_y = -30 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nM" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/corner/red{ dir = 9 }, /obj/machinery/light/spot, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nN" = ( /obj/structure/hygiene/toilet{ dir = 8 }, -/turf/simulated/floor/tiled/dark/monotile, +/turf/floor/tiled/dark/monotile, /area/map_template/colony/jail) "nO" = ( /obj/effect/floor_decal/industrial/warning/dust{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 8; - id_tag = "playablecolonymain_pump_out_internal"; - power_rating = 25000; - - }, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/radio/intercom{ dir = 4; - pixel_x = -21 + pixel_x = -22 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "playablecolonymain_pump"; + power_rating = 25000 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "nP" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "nQ" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/door/blast/regular/open{ - dir = 1; - icon_state = "pdoor0"; id_tag = "colmainexit" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "nR" = ( /obj/structure/grille, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "nS" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 1; - id_tag = "playablecolonymain_pump"; - power_rating = 25000; - + id_tag = "playablecolonymain_pump_out_internal"; + power_rating = 25000 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "nT" = ( -/obj/machinery/mineral/stacking_machine{ - input_turf = 8; - output_turf = 4 - }, +/obj/machinery/material_processing/stacker, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/mineralprocessing) "nU" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 1; - id_tag = "playablecolonymain_pump"; - power_rating = 25000; - + id_tag = "playablecolonymain_pump_out_internal"; + power_rating = 25000 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "nV" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ dir = 9 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/map_template/colony/airlock) "nW" = ( /obj/machinery/atmospherics/pipe/simple/hidden, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "nX" = ( -/obj/machinery/mineral/unloading_machine{ +/obj/machinery/material_processing/unloader{ input_turf = 2; output_turf = 1 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/map_template/colony/mineralprocessing) "nY" = ( /obj/machinery/portable_atmospherics/canister/air/airlock, @@ -8135,14 +7307,13 @@ dir = 1 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/sign/warning/nosmoking_burned{ dir = 1; pixel_x = -32 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "nZ" = ( /obj/structure/sign/warning/high_voltage{ @@ -8155,111 +7326,95 @@ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 10 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "ob" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "oc" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/airlock) "od" = ( /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/warning/dust, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oe" = ( /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "of" = ( /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "og" = ( /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oh" = ( /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oi" = ( /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/warning/dust, -/obj/structure/table/rack, -/obj/item/stack/material/rods/fifty, -/obj/item/stack/material/rods/fifty, -/obj/item/stack/material/rods/fifty, -/obj/item/stack/material/rods/fifty, -/obj/item/pickaxe, -/obj/item/pickaxe, -/obj/item/shovel, -/obj/item/shovel, -/obj/item/storage/ore, -/obj/item/storage/ore, -/obj/item/storage/backpack/dufflebag/eng, -/obj/item/storage/backpack/dufflebag/eng, +/obj/structure/rack, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/tool/pickaxe, +/obj/item/tool/pickaxe, +/obj/item/tool/shovel, +/obj/item/tool/shovel, +/obj/item/ore_satchel, +/obj/item/ore_satchel, +/obj/item/backpack/dufflebag/eng, +/obj/item/backpack/dufflebag/eng, /obj/machinery/door/window/northright, /obj/structure/window/reinforced{ dir = 8; - health = 1e+006 }, /obj/structure/window/reinforced{ dir = 4 @@ -8268,32 +7423,22 @@ /obj/item/cell/super, /obj/item/cell/super, /obj/item/scanner/mining, -/obj/item/storage/box/greenglowsticks, -/obj/item/storage/box/greenglowsticks, -/obj/item/storage/box/greenglowsticks, +/obj/item/box/greenglowsticks, +/obj/item/box/greenglowsticks, +/obj/item/box/greenglowsticks, /obj/item/stack/flag/yellow, /obj/item/stack/flag/yellow, /obj/item/stack/flag/yellow, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oj" = ( /obj/structure/railing/mapped, /obj/effect/floor_decal/industrial/warning/dust, -/obj/structure/table/rack, -/obj/item/gun/projectile/heavysniper/ant{ +/obj/structure/rack, +/obj/item/gun/projectile/bolt_action{ desc = "A large, unwieldy bolt-action rifle in shoddy condition. Chambered in small caliber, looks far scarier than it is. Vamoos ya varmint!"; name = "anti-varmint rifle" }, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, -/obj/item/ammo_magazine/pistol/small, /obj/machinery/door/window/northright, /obj/structure/window/reinforced{ dir = 4 @@ -8301,7 +7446,108 @@ /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/exoplanet/concrete, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/projectile/bullet/rifle, +/obj/item/stock_parts/ammo_box, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "ok" = ( /obj/structure/railing/mapped, @@ -8312,21 +7558,15 @@ }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "ol" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning/dust{ @@ -8335,37 +7575,27 @@ /obj/effect/floor_decal/industrial/warning/dust{ dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/catwalk, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "om" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning/dust{ dir = 1 }, /obj/effect/floor_decal/industrial/warning/dust, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/catwalk, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "on" = ( /obj/structure/railing/mapped{ - dir = 4; - icon_state = "railing0-1"; - + dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning/dust{ @@ -8374,189 +7604,153 @@ /obj/effect/floor_decal/industrial/warning/dust{ dir = 6 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/catwalk, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oo" = ( /obj/structure/grille, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "op" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "oq" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "or" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/catwalk, /obj/structure/sign/warning/high_voltage{ pixel_y = 28 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "os" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "ot" = ( /obj/structure/catwalk, /obj/machinery/light/spot{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/map_template/colony/hydroponics) "ou" = ( /obj/effect/floor_decal/industrial/warning/dust{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "ov" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "ow" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 + dir = 10 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "ox" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning/dust{ dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 8; id_tag = "playablecolonymain_pump_out_internal"; - power_rating = 25000; - + power_rating = 25000 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/airlock) "oy" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1; - icon_state = "map" + dir = 1 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning/dust{ dir = 5 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, /obj/structure/catwalk, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oB" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning/dust{ dir = 4 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oC" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 5 }, /obj/structure/catwalk, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "oD" = ( /obj/machinery/alarm{ @@ -8564,16 +7758,13 @@ pixel_y = 20 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "oE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -8582,21 +7773,20 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "oF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "oG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/light{ @@ -8605,14 +7795,13 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "oH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 1 }, /obj/machinery/alarm{ @@ -8620,10 +7809,9 @@ pixel_y = 20 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "oI" = ( /obj/effect/floor_decal/techfloor, @@ -8631,97 +7819,83 @@ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "oJ" = ( /obj/effect/floor_decal/techfloor, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "tz" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "tI" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 6 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "uf" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "vk" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "vt" = ( -/mob/living/simple_animal/chicken, -/turf/simulated/floor/grass, +/mob/living/simple_animal/fowl/chicken, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "vJ" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "yE" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/portable_atmospherics/hydroponics, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "yN" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/green{ @@ -8731,128 +7905,129 @@ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony) "Bc" = ( /obj/machinery/light{ dir = 4 }, /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) +"CM" = ( +/obj/effect/floor_decal/techfloor{ + dir = 1 + }, +/obj/effect/floor_decal/corner/blue{ + dir = 10 + }, +/obj/effect/floor_decal/techfloor/hole/right{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/techfloor, +/area/map_template/colony/command) "Dj" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/machinery/light{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "Ek" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/item/radio/intercom{ dir = 4; - pixel_x = -21 + pixel_x = -22 }, -/turf/simulated/floor/wood, +/turf/floor/laminate/walnut, /area/map_template/colony/dorms) "GU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) +"Hu" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/obj/machinery/atmospherics/pipe/manifold/hidden, +/turf/floor/plating, +/area/map_template/colony/airlock) "Hy" = ( /obj/machinery/portable_atmospherics/hydroponics, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ locked = 0; name = "south bump"; - operating = 1; pixel_y = -28 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/light{ dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "IA" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/power/solar, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/template_noop) "JN" = ( /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/concrete, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/concrete, /area/template_noop) "Kn" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/corner/lime{ dir = 9 }, /obj/structure/window/reinforced, -/obj/machinery/smartfridge/drying_rack, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/smartfridge/drying_oven, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "Kz" = ( /obj/structure/catwalk, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light/spot{ dir = 1 }, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/hydroponics) "KK" = ( /obj/machinery/portable_atmospherics/hydroponics, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) "LQ" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -8860,81 +8035,88 @@ dir = 5 }, /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "LT" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/grass, +/turf/floor/fake_grass, /area/map_template/colony/hydroponics) "Md" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 8 }, /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/colony/hydroponics) +"Nh" = ( +/obj/structure/curtain/black, +/turf/floor/laminate/walnut, +/area/map_template/colony/dorms) "Og" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/structure/railing/mapped{ - dir = 8; - icon_state = "railing0-1"; - + dir = 8 }, /obj/structure/railing/mapped, -/turf/simulated/floor/exoplanet/concrete, +/turf/floor/concrete, /area/map_template/colony/mineralprocessing) "Ot" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/colony/bathroom) +"Rf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/turf/wall/r_wall, +/area/map_template/colony/airlock) "RR" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "Vk" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/window/reinforced, /obj/machinery/constructable_frame/machine_frame, /obj/item/stack/cable_coil, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) +"VV" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/floor/plating, +/area/map_template/colony/airlock) "Xh" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) "YV" = ( /obj/effect/floor_decal/techfloor{ - icon_state = "techfloor_edges"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/colony/hydroponics) (1,1,1) = {" @@ -9750,10 +8932,10 @@ kI kq ky nV -nt +bh lh ow -bh +Rf bh or "} @@ -9794,7 +8976,7 @@ mw nO ou ox -mw +Hu mZ os "} @@ -9809,13 +8991,13 @@ bi cn at az -dM +Nh az az -dM +Nh az az -dM +Nh az az gm @@ -9835,7 +9017,7 @@ bd lJ mb nS -bh +nt nm os "} @@ -9876,7 +9058,7 @@ aJ lM mg nU -mw +VV nq os "} @@ -9897,7 +9079,7 @@ az eQ az az -dM +Nh az az gp @@ -10047,7 +9229,7 @@ os (28,1,1) = {" ad aD -aV +CM bk bC ac diff --git a/maps/random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm b/maps/random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm index 662729131afb..d0b72f2445f6 100644 --- a/maps/random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm +++ b/maps/random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm @@ -1,36 +1,51 @@ -#include "../../../mods/dionaea/_dionaea.dme" +#include "../../../../mods/mobs/dionaea/_dionaea.dme" /datum/map_template/ruin/exoplanet/playablecolony - name = "established colony" - id = "playablecolony" - description = "a fully functional colony on the frontier of settled space" - suffixes = list("playablecolony/colony.dmm") - cost = 2 + name = "established colony" + description = "a fully functional colony on the frontier of settled space" + suffixes = list("playablecolony/colony.dmm") + cost = 2 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS | TEMPLATE_FLAG_NO_RADS - ruin_tags = RUIN_HUMAN|RUIN_HABITAT + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_HABITAT apc_test_exempt_areas = list( /area/map_template/colony/mineralprocessing = NO_SCRUBBER|NO_VENT ) /decl/submap_archetype/playablecolony - descriptor = "established colony" + name = "established colony" crew_jobs = list(/datum/job/submap/colonist) /datum/job/submap/colonist title = "Colonist" info = "You are a Colonist, living on the rim of explored, let alone inhabited, space in a reconstructed shelter made from the very ship that took you here." total_positions = 6 - outfit_type = /decl/hierarchy/outfit/job/colonist + outfit_type = /decl/outfit/job/colonist + min_skill = list( + SKILL_LITERACY = SKILL_BASIC, + SKILL_CONSTRUCTION = SKILL_BASIC, + SKILL_MEDICAL = SKILL_BASIC, + SKILL_BOTANY = SKILL_BASIC, + SKILL_EVA = SKILL_BASIC, + SKILL_ELECTRICAL = SKILL_BASIC + ) + skill_points = 20 + alt_titles = list( + "Colony Engineer", + "Colony Doctor", + "Colony Botanist", + "Colony Officer", + "Colony Miner" + ) -/decl/hierarchy/outfit/job/colonist - name = OUTFIT_JOB_NAME("Colonist") +/decl/outfit/job/colonist + name = "Job - Colonist" id_type = null pda_type = null -/obj/effect/submap_landmark/spawnpoint/colonist_spawn +/obj/abstract/submap_landmark/spawnpoint/colonist_spawn name = "Colonist" -/obj/effect/submap_landmark/joinable_submap/colony +/obj/abstract/submap_landmark/joinable_submap/colony name = "Established Colony" archetype = /decl/submap_archetype/playablecolony diff --git a/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dm b/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dm index b389c040a3d8..795317530523 100644 --- a/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dm +++ b/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dm @@ -1,8 +1,12 @@ +/turf/wall/uranium + icon_state = "metal" + color = COLOR_GREEN + material = /decl/material/solid/metal/uranium + /datum/map_template/ruin/exoplanet/radshrine name = "radshrine" - id = "radshrine" description = "A small radioactive shrine dedicated to an anomaly." suffixes = list("radshrine/radshrine.dmm") cost = 1 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS|TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN|RUIN_HABITAT \ No newline at end of file + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_HABITAT \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dmm b/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dmm index b243cb1cd905..8d586cbed4b2 100644 --- a/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dmm +++ b/maps/random_ruins/exoplanet_ruins/radshrine/radshrine.dmm @@ -1,37 +1,37 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "b" = ( -/turf/simulated/wall/iron, +/turf/wall/iron, /area/template_noop) "c" = ( /obj/structure/door/uranium, -/turf/template_noop, +/turf/floor/carpet/red, /area/template_noop) "d" = ( -/turf/simulated/wall/uranium, +/turf/wall/uranium, /area/template_noop) "e" = ( -/obj/structure/bed/chair/wood, +/obj/structure/chair/wood, /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/template_noop) "f" = ( -/turf/simulated/floor/carpet/red, +/turf/floor/carpet/red, /area/template_noop) "g" = ( -/obj/item/trash/candle, -/turf/simulated/floor/carpet/red, +/obj/item/flame/candle/spent, +/turf/floor/carpet/red, /area/template_noop) "h" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "i" = ( /obj/structure/artifact, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/template_noop) "I" = ( -/obj/structure/bed/chair/wood, -/turf/simulated/floor/carpet/red, +/obj/structure/chair/wood, +/turf/floor/carpet/red, /area/template_noop) (1,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dm b/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dm index 4f579ef724d6..dca18492f4a6 100644 --- a/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dm +++ b/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dm @@ -1,8 +1,7 @@ /datum/map_template/ruin/exoplanet/spider_nest name = "spider nest" - id = "spider_nest" description = "A small buidling with a spider infestation." suffixes = list("spider_nest/spider_nest.dmm") cost = 1 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS|TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN + template_tags = TEMPLATE_TAG_HUMAN diff --git a/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dmm b/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dmm index d924ddfc284b..5e646433908f 100644 --- a/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dmm +++ b/maps/random_ruins/exoplanet_ruins/spider_nest/spider_nest.dmm @@ -3,61 +3,61 @@ /turf/template_noop, /area/template_noop) "b" = ( -/turf/simulated/wall/r_wall/prepainted{ +/turf/wall/r_wall/prepainted{ paint_color = "#5b8693" }, /area/template_noop) "c" = ( -/obj/structure/closet/walllocker/emerglocker/east, +/obj/structure/emergency_dispenser/east, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "d" = ( /obj/machinery/door/airlock/external, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/template_noop) "e" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "f" = ( /obj/effect/wallframe_spawn/reinforced, /obj/structure/barricade, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "h" = ( /obj/structure/grille, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "i" = ( -/obj/structure/table/standard{ - flipped = 1 +/obj/structure/table{ + is_flipped = 1 }, /obj/effect/spider/cocoon, /obj/random/energy, /obj/random/trash, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "j" = ( -/obj/structure/table/standard{ - flipped = 1 +/obj/structure/table{ + is_flipped = 1 }, /obj/item/pen, /obj/random/junk, /obj/effect/spider/stickyweb, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "k" = ( -/obj/structure/filingcabinet, +/obj/structure/filing_cabinet, /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "l" = ( -/obj/structure/bed/chair/office/comfy/blue, +/obj/structure/chair/office/comfy/blue, /obj/item/pen, /obj/effect/spider/stickyweb, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "m" = ( /obj/random/trash, @@ -67,24 +67,24 @@ /obj/effect/spider/stickyweb, /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "o" = ( -/obj/structure/table/standard{ - flipped = 1 +/obj/structure/table{ + is_flipped = 1 }, /obj/random/junk, /obj/random/loot, /obj/item/paper, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "p" = ( -/obj/effect/landmark/corpse/doctor, +/obj/abstract/landmark/corpse/doctor, /obj/effect/decal/cleanable/blood, /obj/item/shard, /obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/vomit, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/vomit/mapped, +/turf/floor/tiled/techfloor, /area/template_noop) "q" = ( /obj/item/telebaton, @@ -93,38 +93,38 @@ /obj/structure/fireaxecabinet{ pixel_x = -32 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "r" = ( /obj/item/paper_bin, /obj/random/trash, /obj/effect/spider/stickyweb, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "s" = ( /obj/machinery/seed_storage/random, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "t" = ( /obj/item/paper, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "u" = ( /obj/effect/spider/stickyweb, /obj/item/paper, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "v" = ( /obj/random/junk, /obj/effect/spider/stickyweb, /obj/item/seeds/random, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "w" = ( /obj/effect/decal/cleanable/spiderling_remains, /obj/effect/decal/cleanable/blood, /mob/living/simple_animal/hostile/giant_spider, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "x" = ( /obj/structure/grille/broken, @@ -132,22 +132,22 @@ /obj/effect/decal/cleanable/blood/gibs/limb, /obj/effect/decal/cleanable/blood/drip, /mob/living/simple_animal/hostile/giant_spider/nurse, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "y" = ( /obj/random/trash, /obj/effect/spider/stickyweb, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "z" = ( /obj/effect/decal/cleanable/blood, /obj/item/paper, /obj/random/loot, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "A" = ( /obj/random/loot, -/obj/structure/sign/xenobio_1{ +/obj/structure/sign/department/xenobio_1{ pixel_y = 32 }, /turf/template_noop, @@ -155,65 +155,65 @@ "B" = ( /obj/random/smokes, /obj/random/voidhelmet, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "C" = ( /obj/random/loot, /mob/living/simple_animal/hostile/giant_spider/hunter, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "D" = ( /obj/structure/bookcase, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "E" = ( /obj/effect/spider/stickyweb, /obj/effect/spider/cocoon, /obj/random/loot, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/template_noop) "F" = ( -/obj/structure/bed/chair/office/comfy/purple, +/obj/structure/chair/office/comfy/purple, /obj/effect/decal/cleanable/blood/drip, /obj/effect/decal/cleanable/filth, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "G" = ( /obj/structure/grille/broken, /obj/effect/spider/stickyweb, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "H" = ( /obj/structure/grille/broken, /obj/random/trash, /obj/effect/decal/cleanable/blood, /obj/random/loot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) "I" = ( /obj/item/paper, /obj/effect/decal/cleanable/blood/drip, /mob/living/simple_animal/hostile/giant_spider, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "J" = ( /obj/effect/spider/stickyweb, /obj/machinery/door/airlock/external, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/template_noop) "K" = ( /obj/random/trash, /obj/effect/decal/cleanable/blood/gibs/body, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/template_noop) "L" = ( /obj/random/loot, /obj/effect/spider/stickyweb, /obj/effect/decal/cleanable/blood/gibs/limb, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/template_noop) "M" = ( /obj/effect/decal/cleanable/blood, @@ -222,7 +222,7 @@ "N" = ( /obj/effect/spider/stickyweb, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "O" = ( /obj/effect/decal/cleanable/spiderling_remains, @@ -234,7 +234,7 @@ /area/template_noop) "R" = ( /obj/structure/sign/warning/biohazard, -/turf/simulated/wall/r_wall/prepainted{ +/turf/wall/r_wall/prepainted{ paint_color = "#5b8693" }, /area/template_noop) @@ -242,24 +242,25 @@ /obj/effect/spider/stickyweb, /obj/random/voidsuit, /obj/random/loot, -/obj/effect/decal/cleanable/vomit, +/obj/effect/decal/cleanable/vomit/mapped, /obj/structure/extinguisher_cabinet{ - pixel_x = -32 + pixel_x = -29; + dir = 4 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/template_noop) "X" = ( -/obj/structure/filingcabinet, -/turf/simulated/floor/lino, +/obj/structure/filing_cabinet, +/turf/floor/lino, /area/template_noop) "Y" = ( /obj/effect/spider/stickyweb, /obj/effect/decal/cleanable/blood/drip, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/template_noop) "Z" = ( /obj/effect/spider/stickyweb, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/template_noop) (1,1,1) = {" diff --git a/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dm b/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dm index f7292dffd9a6..9f2637a18eec 100644 --- a/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dm +++ b/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dm @@ -1,8 +1,7 @@ /datum/map_template/ruin/exoplanet/tar_anomaly name = "tar anomaly" - id = "tar_anomaly" description = "An anomaly in the center of a ring of tar." suffixes = list("tar_anomaly/tar_anomaly.dmm") cost = 1 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS|TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_ALIEN \ No newline at end of file + template_tags = TEMPLATE_TAG_ALIEN \ No newline at end of file diff --git a/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dmm b/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dmm index 0475dfb3c391..6f895827e814 100644 --- a/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dmm +++ b/maps/random_ruins/exoplanet_ruins/tar_anomaly/tar_anomaly.dmm @@ -1,26 +1,26 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( -/turf/simulated/floor/exoplanet/water/shallow/tar, +/turf/floor/shrouded/tar, /area/template_noop) "b" = ( /turf/template_noop, /area/template_noop) "c" = ( -/obj/structure/flora/ausbushes/lavendergrass, +/obj/structure/flora/bush/lavendergrass, /turf/template_noop, /area/template_noop) "d" = ( /obj/structure/artifact, -/obj/effect/landmark/clear, -/turf/simulated/floor/exoplanet/shrouded, +/obj/abstract/landmark/clear, +/turf/floor/shrouded, /area/template_noop) "e" = ( -/obj/structure/flora/ausbushes/fullgrass, +/obj/structure/flora/bush/fullgrass, /turf/template_noop, /area/template_noop) "f" = ( /obj/structure/monolith, -/turf/simulated/floor/exoplanet/water/shallow/tar, +/turf/floor/shrouded/tar, /area/template_noop) (1,1,1) = {" diff --git a/maps/random_ruins/space_ruins/multi_zas_test.dmm b/maps/random_ruins/space_ruins/multi_zas_test.dmm index 7a0282fb1b11..e90fb1fbc7ab 100644 --- a/maps/random_ruins/space_ruins/multi_zas_test.dmm +++ b/maps/random_ruins/space_ruins/multi_zas_test.dmm @@ -1,25 +1,25 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( -/turf/simulated/wall/diamond, +/turf/wall/diamond, /area/template_noop) "b" = ( -/turf/simulated/floor, +/turf/floor, /area/template_noop) "c" = ( /mob/living/simple_animal/corgi, -/turf/simulated/floor, +/turf/floor, /area/template_noop) "d" = ( -/turf/simulated/open, +/turf/open, /area/template_noop) "e" = ( -/turf/unsimulated/floor/shuttle_ceiling, +/turf/floor/shuttle_ceiling, /area/template_noop) "f" = ( -/obj/effect/landmark/map_data{ +/obj/abstract/map_data{ height = 3 }, -/turf/unsimulated/floor/shuttle_ceiling, +/turf/floor/shuttle_ceiling, /area/template_noop) (1,1,1) = {" diff --git a/maps/random_ruins/space_ruins/space_ruins.dm b/maps/random_ruins/space_ruins/space_ruins.dm index c85c0fb847f7..460f5a6995a7 100644 --- a/maps/random_ruins/space_ruins/space_ruins.dm +++ b/maps/random_ruins/space_ruins/space_ruins.dm @@ -1,12 +1,17 @@ // Hey! Listen! Update \config\space_ruin_blacklist.txt with your new ruins! +/turf/wall/diamond + color = COLOR_SKY_BLUE + icon_state = "stone" + material = /decl/material/solid/gemstone/diamond /datum/map_template/ruin/space + abstract_type = /datum/map_template/ruin/space + template_categories = list(MAP_TEMPLATE_CATEGORY_SPACE) prefix = "maps/random_ruins/space_ruins/" cost = 1 /datum/map_template/ruin/space/multi_zas_test name = "Multi-ZAS Test" - id = "multi_zas_test" description = "if this has vacuum in it, that's not good!" suffixes = list("multi_zas_test.dmm") cost = 1 \ No newline at end of file diff --git a/maps/shaded_hills/areas/_areas.dm b/maps/shaded_hills/areas/_areas.dm new file mode 100644 index 000000000000..bdf893f4f7e0 --- /dev/null +++ b/maps/shaded_hills/areas/_areas.dm @@ -0,0 +1,40 @@ +/area/shaded_hills + abstract_type = /area/shaded_hills + allow_xenoarchaeology_finds = FALSE + icon = 'maps/shaded_hills/areas/icons.dmi' + icon_state = "area" + base_turf = /turf/floor/rock/basalt + fishing_failure_prob = 5 + fishing_results = list( + /mob/living/simple_animal/aquatic/fish = 10, + /mob/living/simple_animal/aquatic/fish/grump = 10, + /obj/item/mollusc = 5, + /obj/item/mollusc/barnacle/fished = 5, + /obj/item/mollusc/clam/fished/pearl = 3, + /obj/item/trash/mollusc_shell/clam = 1, + /obj/item/trash/mollusc_shell/barnacle = 1, + /obj/item/remains/mouse = 1, + /obj/item/remains/lizard = 1, + /obj/item/stick = 1, + /obj/item/trash/mollusc_shell = 1, + ) + sound_env = GENERIC + ambience = list() + +/area/shaded_hills/outside + name = "\improper Grasslands" + color = COLOR_GREEN + is_outside = OUTSIDE_YES + sound_env = PLAIN + ambience = list( + 'sound/effects/wind/wind_2_1.ogg', + 'sound/effects/wind/wind_2_2.ogg', + 'sound/effects/wind/wind_3_1.ogg', + 'sound/effects/wind/wind_4_1.ogg', + 'sound/effects/wind/wind_4_2.ogg', + 'sound/effects/wind/wind_5_1.ogg' + ) + description = "Birds and insects call from the grasses, and a cool wind gusts from across the river." + area_blurb_category = /area/shaded_hills/outside + interior_ambient_light_modifier = -0.4 + area_flags = AREA_FLAG_EXTERNAL | AREA_FLAG_IS_BACKGROUND diff --git a/maps/shaded_hills/areas/downlands.dm b/maps/shaded_hills/areas/downlands.dm new file mode 100644 index 000000000000..76d91cce821e --- /dev/null +++ b/maps/shaded_hills/areas/downlands.dm @@ -0,0 +1,96 @@ +/area/shaded_hills/outside/downlands + name = "Downlands" + +/area/shaded_hills/outside/downlands/poi + name = "Deep Downlands" + +/area/shaded_hills/inn + name = "\improper Inn" + fishing_failure_prob = 100 + fishing_results = list() + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/decl/turf_initializer/combo/kitchen_webs + initialisers = list( + /decl/turf_initializer/spiderwebs, + /decl/turf_initializer/kitchen + ) + +/area/shaded_hills/inn/kitchen + name = "\improper Inn Kitchen" + turf_initializer = /decl/turf_initializer/combo/kitchen_webs + +/area/shaded_hills/inn/porch + name = "\improper Inn Porch" + interior_ambient_light_modifier = -0.4 // night is pitch-black on the porch + sound_env = FOREST + +/area/shaded_hills/stable + name = "\improper Stable" + fishing_failure_prob = 100 + fishing_results = list() + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/area/shaded_hills/farmhouse + name = "\improper Farmhouse" + fishing_failure_prob = 100 + fishing_results = list() + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/area/shaded_hills/farmhouse/porch + name = "\improper Farmhouse Porch" + interior_ambient_light_modifier = -0.4 // night is pitch-black on the porch + sound_env = FOREST + +/area/shaded_hills/slaughterhouse + name = "\improper Slaughterhouse" + fishing_failure_prob = 100 + fishing_results = list() + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/area/shaded_hills/storehouse + name = "\improper Storehouse" + fishing_failure_prob = 100 + fishing_results = list() + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/area/shaded_hills/general_store + name = "\improper General Store" + fishing_failure_prob = 100 + fishing_results = list() + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/area/shaded_hills/general_store/porch + name = "\improper General Store Porch" + interior_ambient_light_modifier = -0.4 // night is pitch-black on the porch + sound_env = FOREST + +/area/shaded_hills/shrine + name = "\improper Shrine" + fishing_failure_prob = 100 + fishing_results = list() + area_flags = AREA_FLAG_HOLY + sound_env = ROOM + turf_initializer = /decl/turf_initializer/spiderwebs + +/area/shaded_hills/shrine/kitchen + name = "\improper Shrine Kitchen" + turf_initializer = /decl/turf_initializer/combo/kitchen_webs + +/area/shaded_hills/outside/shrine + name = "\improper Shrine Grounds" + +/area/shaded_hills/caves/dungeon + name = "\improper Deep Dungeon" + +/area/shaded_hills/caves/dungeon/inn + name = "\improper Root Cellar" + +/area/shaded_hills/caves/dungeon/poi + name = "\improper Deepest Dungeon" diff --git a/maps/shaded_hills/areas/grassland.dm b/maps/shaded_hills/areas/grassland.dm new file mode 100644 index 000000000000..ae0827242f20 --- /dev/null +++ b/maps/shaded_hills/areas/grassland.dm @@ -0,0 +1,77 @@ +/area/shaded_hills/caves/entrance + name = "\improper Surface Tunnels" + color = COLOR_GRAY80 + +/area/shaded_hills/caves/unexplored + name = "\improper Trackless Deeps - North" + color = COLOR_GRAY20 + ambience = list( + 'sound/ambience/ominous1.ogg', + 'sound/ambience/ominous2.ogg', + 'sound/ambience/ominous3.ogg', + ) + +// Area coherency test hates that the unexplored area is split by a tunnel. +/area/shaded_hills/caves/unexplored/south + name = "\improper Trackless Deeps - South" + +/area/shaded_hills/caves/river + name = "\improper Silent River" + color = COLOR_GRAY20 + description = "The silent, black water catches whatever sparse light survives in the depths, glittering like a river of stars." + area_blurb_category = /area/shaded_hills/caves/river + ambience = list( + 'sound/ambience/ominous1.ogg', + 'sound/ambience/ominous2.ogg', + 'sound/ambience/ominous3.ogg', + ) + // hopefully the sound environment makes this sound nicer? + forced_ambience = list('sound/ambience/shore.ogg') + +/area/shaded_hills/outside/poi + name = "Deep Grassland" + +/area/shaded_hills/outside/river + name = "River" + color = COLOR_BLUE + description = "The soft susurration of running water mingles with the hum of insects and croak of frogs." + area_blurb_category = /area/shaded_hills/outside/river + forced_ambience = list('sound/ambience/shore.ogg') + +/area/shaded_hills/outside/river/get_additional_fishing_results() + var/static/list/additional_fishing_results = list( + /mob/living/simple_animal/aquatic/fish/large = 5, + /mob/living/simple_animal/aquatic/fish/large/salmon = 5, + /mob/living/simple_animal/aquatic/fish/large/trout = 5, + /mob/living/simple_animal/aquatic/fish/large/pike = 3 + ) + return additional_fishing_results + +/area/shaded_hills/caves + name = "\improper Deep Tunnels" + color = COLOR_GRAY40 + is_outside = OUTSIDE_NO + description = "The deep dark brings distant, whispering echoes to your ears." + ambience = list( + 'sound/ambience/ambimine.ogg', + 'sound/ambience/song_game.ogg' + ) + area_blurb_category = /area/shaded_hills/caves + sound_env = CAVE + area_flags = AREA_FLAG_IS_BACKGROUND + fishing_results = list( + /mob/living/simple_animal/aquatic/fish/large/cave = 13, + /mob/living/simple_animal/aquatic/fish/large/lantern = 7, + /obj/item/mollusc = 5, + /obj/item/mollusc/barnacle/fished = 5, + /obj/item/mollusc/clam/fished/pearl = 3, + /obj/item/trash/mollusc_shell/clam = 1, + /obj/item/trash/mollusc_shell/barnacle = 1, + /obj/item/trash/mollusc_shell = 1 + ) + +/area/shaded_hills/caves/deep + name = "\improper Deep Caverns" + +/area/shaded_hills/caves/deep/poi + name = "\improper Deepest Caverns" diff --git a/maps/shaded_hills/areas/icons.dmi b/maps/shaded_hills/areas/icons.dmi new file mode 100644 index 000000000000..9849d6f87d8d Binary files /dev/null and b/maps/shaded_hills/areas/icons.dmi differ diff --git a/maps/shaded_hills/areas/swamp.dm b/maps/shaded_hills/areas/swamp.dm new file mode 100644 index 000000000000..7c1de587f446 --- /dev/null +++ b/maps/shaded_hills/areas/swamp.dm @@ -0,0 +1,28 @@ +// Swamp areas. +/area/shaded_hills/witch_hut + name = "Witches' Hut" + fishing_failure_prob = 100 + fishing_results = list() + +/area/shaded_hills/caves/river/swamp + name = "Southern Silent River" + +/area/shaded_hills/outside/swamp + name = "Swamp" + description = "The reek of stagnant water and the chirp of insects filter through the humid air." + forced_ambience = list('sound/ambience/marshy.ogg') + +/area/shaded_hills/outside/swamp/poi + name = "Deep Swamp" + forced_ambience = list('sound/ambience/marshy.ogg') + +/area/shaded_hills/outside/river/swamp + name = "Swampy River" + description = "Mud squelches underfoot as the river broadens and splits, feeding a broad expanse of swamp and still water." + +/area/shaded_hills/caves/swamp + name = "Southern Deep Tunnels" + forced_ambience = list('sound/ambience/marshy.ogg') + +/area/shaded_hills/caves/unexplored/swamp + name = "Trackless Deeps - Far South" diff --git a/maps/shaded_hills/areas/woods.dm b/maps/shaded_hills/areas/woods.dm new file mode 100644 index 000000000000..1ef25b471ca7 --- /dev/null +++ b/maps/shaded_hills/areas/woods.dm @@ -0,0 +1,39 @@ +// Woodland areas. +/area/shaded_hills/caves/river/woods + name = "Northern Silent River" + +/area/shaded_hills/outside/river/lake + name = "Woodland Lake" + forced_ambience = list('sound/ambience/shore.ogg') + +/area/shaded_hills/outside/river/lake/get_additional_fishing_results() + var/static/list/additional_fishing_results = list( + /mob/living/simple_animal/aquatic/fish/large/bass = 5, + /mob/living/simple_animal/aquatic/fish/large/trout = 5, + /mob/living/simple_animal/aquatic/fish/large/javelin = 5, + /mob/living/simple_animal/hostile/aquatic/carp = 3, + /mob/living/simple_animal/aquatic/fish/large/koi = 1 + ) + return additional_fishing_results + +/area/shaded_hills/outside/woods + name = "Woodlands" + sound_env = FOREST + +/area/shaded_hills/outside/woods/poi + name = "Deep Woodlands" + +/area/shaded_hills/outside/river/woods + name = "Woodland River" + +/area/shaded_hills/caves/woods + name = "Northern Deep Tunnels" + +/area/shaded_hills/caves/unexplored/woods + name = "Trackless Deeps - Far North" + +/area/shaded_hills/forester_hut + name = "\improper Foresters' Hut" + sound_env = STANDARD_STATION + fishing_failure_prob = 100 + fishing_results = list() diff --git a/maps/shaded_hills/jobs/_jobs.dm b/maps/shaded_hills/jobs/_jobs.dm new file mode 100644 index 000000000000..7eb2719f6615 --- /dev/null +++ b/maps/shaded_hills/jobs/_jobs.dm @@ -0,0 +1,60 @@ +/datum/map/shaded_hills + allowed_jobs = list( + /datum/job/shaded_hills/visitor/traveller, + /datum/job/shaded_hills/visitor/traveller/learned, + /datum/job/shaded_hills/visitor/beggar_knight, + /datum/job/shaded_hills/local/miner, + /datum/job/shaded_hills/local/herbalist, + /datum/job/shaded_hills/local/forester, + /datum/job/shaded_hills/inn/storekeeper, + /datum/job/shaded_hills/inn/innkeeper, + /datum/job/shaded_hills/inn/inn_worker, + /datum/job/shaded_hills/inn/bartender, + /datum/job/shaded_hills/inn/farmer, + /datum/job/shaded_hills/caves/dweller, + /datum/job/shaded_hills/shrine/keeper, + /datum/job/shaded_hills/shrine/attendant, + /datum/job/shaded_hills/visitor/traveller/cleric + ) + default_job_type = /datum/job/shaded_hills/visitor/traveller + default_department_type = /decl/department/shaded_hills/visitors + species_to_job_whitelist = list( + /decl/species/grafadreka = list( + /datum/job/shaded_hills/caves/dweller, + /datum/job/shaded_hills/visitor/traveller + ) + ) + job_to_species_blacklist = list( + /datum/job/shaded_hills/caves/dweller = list( + /decl/species/human, + /decl/species/hnoll + ), + ) + species_to_job_blacklist = list( + /decl/species/kobaloi = list( + /datum/job/shaded_hills/visitor/beggar_knight, + /datum/job/shaded_hills/inn/innkeeper, + /datum/job/shaded_hills/shrine/keeper, + /datum/job/shaded_hills/visitor/traveller/cleric + ) + ) + +/decl/department/shaded_hills + abstract_type = /decl/department/shaded_hills + noun = "faction" + noun_adj = "faction" + announce_channel = null + +/datum/job/shaded_hills + abstract_type = /datum/job/shaded_hills + hud_icon_state = "hudblank" + department_types = list( + /decl/department/shaded_hills/locals + ) + min_skill = list() + // if you consider adding something like literacy to this list to make it rarer/more exclusive + // consider making the higher levels cost more points instead + max_skill = list( + SKILL_CHEMISTRY = SKILL_BASIC, // this is the domain of the herbalist + ) + skill_points = 20 diff --git a/maps/shaded_hills/jobs/caves.dm b/maps/shaded_hills/jobs/caves.dm new file mode 100644 index 000000000000..ee1d50ba05f2 --- /dev/null +++ b/maps/shaded_hills/jobs/caves.dm @@ -0,0 +1,17 @@ +/datum/job/shaded_hills/caves + abstract_type = /datum/job/shaded_hills/caves + +/datum/job/shaded_hills/caves/dweller + title = "Cave Dweller" + spawn_positions = -1 + total_positions = -1 + outfit_type = /decl/outfit/job/shaded_hills/cave_dweller + max_skill = list( + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX, + SKILL_CHEMISTRY = SKILL_MAX, + ) + skill_points = 24 + +/obj/abstract/landmark/start/shaded_hills/cave_dweller + name = "Cave Dweller" \ No newline at end of file diff --git a/maps/shaded_hills/jobs/inn.dm b/maps/shaded_hills/jobs/inn.dm new file mode 100644 index 000000000000..5d3209ffebd2 --- /dev/null +++ b/maps/shaded_hills/jobs/inn.dm @@ -0,0 +1,119 @@ +/decl/department/shaded_hills/inn + name = "Inn Workers" + colour = "#404e68" + display_color = "#8c96c4" + +/datum/job/shaded_hills/inn + abstract_type = /datum/job/shaded_hills/inn + department_types = list(/decl/department/shaded_hills/inn) + +/datum/job/shaded_hills/inn/innkeeper + title = "Innkeeper" + supervisors = "your business and self-interest" + description = "You are the proprietor of the inn, directing your employees and ensuring guests are treated properly, whatever you think that may mean." + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/shaded_hills/innkeeper + head_position = TRUE + req_admin_notify = TRUE + guestbanned = TRUE + must_fill = TRUE + not_random_selectable = TRUE + min_skill = list( + // notably: no athletics requirement, and no literacy requirement but i'm less certain on that + SKILL_FINANCE = SKILL_BASIC, // at least competent enough to keep the inn running + SKILL_COOKING = SKILL_ADEPT, // and should at least be skilled enough to run the inn on their own + ) + max_skill = list( + SKILL_CHEMISTRY = SKILL_ADEPT, // a bit more leeway than most jobs, but still not as good as the herbalist + ) + skill_points = 22 + lock_keys = list( + "inn back room" = /decl/material/solid/metal/silver, + "inn interior" = /decl/material/solid/metal/copper, + "inn exterior" = /decl/material/solid/metal/iron + ) + +/obj/abstract/landmark/start/shaded_hills/innkeeper + name = "Innkeeper" + +/datum/job/shaded_hills/inn/inn_worker + title = "Inn Worker" + supervisors = "the innkeeper" + description = "You work at the inn, though your exact duties are nebulous. You may be a cook in the kitchen, someone who keeps the lanterns lit and the furniture from falling apart, or something else entirely; either way, you have to earn your keep." + spawn_positions = 3 + total_positions = 3 + outfit_type = /decl/outfit/job/shaded_hills/inn_worker + min_skill = list( + SKILL_HAULING = SKILL_BASIC, // must be fit enough to do basic tasks around the inn + SKILL_COOKING = SKILL_BASIC, // and should be skilled enough to do basic cooking/farming work + SKILL_BOTANY = SKILL_BASIC, + ) + skill_points = 18 + lock_keys = list( + "inn interior" = /decl/material/solid/metal/copper, + "inn exterior" = /decl/material/solid/metal/iron + ) + +/obj/abstract/landmark/start/shaded_hills/inn_worker + name = "Inn Worker" + +/datum/job/shaded_hills/inn/bartender + title = "Bartender" + supervisors = "the innkeeper" + description = "You work the bar at the inn and ensure that patrons are fed, slaked, and merry. If you keep the hearth lit and prepare fresh food and drink, you will certainly earn your keep." + spawn_positions = 2 + total_positions = 2 + outfit_type = /decl/outfit/job/shaded_hills/bartender + min_skill = list( + SKILL_COOKING = SKILL_EXPERT // skilled with food and drink + ) + skill_points = 18 + lock_keys = list( + "inn interior" = /decl/material/solid/metal/copper, + "inn exterior" = /decl/material/solid/metal/iron + ) + +/obj/abstract/landmark/start/shaded_hills/bartender + name = "Bartender" + +/datum/job/shaded_hills/inn/farmer + title = "Farmer" + supervisors = "your own self-interest" + description = "You grow crops both for your own subsistence and to sell to others like the innkeeper or general store. You are knowledgeable of local plants grown for sustenance, but your knowledge of niche herbs may be spottier." + spawn_positions = 3 + total_positions = 3 + outfit_type = /decl/outfit/job/shaded_hills/farmer + min_skill = list( + SKILL_HAULING = SKILL_ADEPT, // farming can be demanding work + SKILL_HUSBANDRY = SKILL_ADEPT, // must be able to pick up and milk animals + SKILL_BOTANY = SKILL_ADEPT, // must be skilled enough to have plants reliably survive when planted + ) + skill_points = 18 + lock_keys = list( + "farmhouse" = /decl/material/solid/metal/copper + ) + +/obj/abstract/landmark/start/shaded_hills/farmer + name = "Farmer" + +// Effectively a placeholder role until economic mechanics are in. +/datum/job/shaded_hills/inn/storekeeper + title = "Storekeeper" + supervisors = "growth, profit, and your own self-interest" + description = "You run the local store, and are responsible for both selling goods to interested parties, and restocking from local suppliers." + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/shaded_hills/storekeeper + min_skill = list( + SKILL_HAULING = SKILL_ADEPT, + SKILL_FINANCE = SKILL_ADEPT, + ) + skill_points = 18 + lock_keys = list( + "general store" = /decl/material/solid/metal/copper, + "general store stockroom" = /decl/material/solid/metal/iron + ) + +/obj/abstract/landmark/start/shaded_hills/storekeeper + name = "Storekeeper" diff --git a/maps/shaded_hills/jobs/shrine.dm b/maps/shaded_hills/jobs/shrine.dm new file mode 100644 index 000000000000..dcf090656213 --- /dev/null +++ b/maps/shaded_hills/jobs/shrine.dm @@ -0,0 +1,70 @@ +/decl/department/shaded_hills/shrine + name = "Shrine Attendants" + colour = "#404e68" + display_color = "#8c96c4" + +/datum/job/shaded_hills/shrine + abstract_type = /datum/job/shaded_hills/shrine + department_types = list(/decl/department/shaded_hills/shrine) + skill_points = 20 + lock_keys = list( + "shrine" = /decl/material/solid/metal/copper + ) + +/datum/job/shaded_hills/shrine/keeper + title = "Shrine Keeper" + supervisors = "your vows, and your faith" + description = "You are the leader of the local religious order, living and working within the shrine. You are expected to see to both the spiritual and physical health of the populace, as well as travellers, if they can offer appropriate tithe." + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/shaded_hills/shrine/keeper + min_skill = list( + SKILL_STONEMASONRY = SKILL_BASIC, + SKILL_CARPENTRY = SKILL_BASIC, + SKILL_TEXTILES = SKILL_BASIC, + SKILL_COOKING = SKILL_BASIC, + SKILL_BOTANY = SKILL_BASIC, + SKILL_ATHLETICS = SKILL_BASIC, + SKILL_LITERACY = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_ADEPT, + SKILL_ANATOMY = SKILL_ADEPT, + ) + max_skill = list( + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX, + ) + skill_points = 24 + lock_keys = list( + "shrine" = /decl/material/solid/metal/copper, + "sunken keep" = /decl/material/solid/organic/bone + ) + +/obj/abstract/landmark/start/shaded_hills/shrine_keeper + name = "Shrine Keeper" + +/datum/job/shaded_hills/shrine/attendant + title = "Shrine Attendant" + supervisors = "the Shrine Keeper, your vows, and your faith" + description = "You are an acolyte of the local religious order, living and working within the shrine. Under the direction of the shrine keeper, you are expected to tend to the shrine and the grounds, and to produce food or other goods for use or trade to support the clergy." + spawn_positions = 2 + total_positions = 2 + outfit_type = /decl/outfit/job/shaded_hills/shrine + min_skill = list( + SKILL_STONEMASONRY = SKILL_BASIC, + SKILL_CARPENTRY = SKILL_BASIC, + SKILL_TEXTILES = SKILL_BASIC, + SKILL_COOKING = SKILL_BASIC, + SKILL_BOTANY = SKILL_BASIC, + SKILL_ATHLETICS = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_ADEPT, + SKILL_ANATOMY = SKILL_ADEPT, + ) + max_skill = list( + SKILL_COOKING = SKILL_EXPERT, + SKILL_BOTANY = SKILL_EXPERT, + SKILL_MEDICAL = SKILL_EXPERT, + SKILL_ANATOMY = SKILL_EXPERT, + ) + +/obj/abstract/landmark/start/shaded_hills/shrine_attendant + name = "Shrine Attendant" diff --git a/maps/shaded_hills/jobs/visitors.dm b/maps/shaded_hills/jobs/visitors.dm new file mode 100644 index 000000000000..65c4f0415f45 --- /dev/null +++ b/maps/shaded_hills/jobs/visitors.dm @@ -0,0 +1,96 @@ +/decl/department/shaded_hills/visitors + name = "Visitors" + colour = "#685b40" + display_color = "#c4bc8c" + +/datum/job/shaded_hills/visitor + abstract_type = /datum/job/shaded_hills/visitor + department_types = list(/decl/department/shaded_hills/visitors) + +/datum/job/shaded_hills/visitor/traveller + title = "Traveller" + supervisors = "your conscience" + description = "You have travelled to this area from elsewhere. You may be a vagabond, a wastrel, a nomad, or just passing through on your way to somewhere else. How long you're staying and where you're headed is up to you entirely." + spawn_positions = -1 + total_positions = -1 + outfit_type = /decl/outfit/job/shaded_hills/traveller + skill_points = 20 + +/obj/abstract/landmark/start/shaded_hills/traveller + name = "Traveller" + +/datum/job/shaded_hills/visitor/traveller/learned + title = "Itinerant Scholar" + // todo: outfits for alt-titles? + alt_titles = list("Itinerant Monk", "Travelling Doctor", "Dilettante") + supervisors = "your conscience" + description = "You are a skilled professional who has travelled to this area from elsewhere. You may be a doctor, a scholar, a monk, or some other highly-educated individual with rare skills. Whatever your reason for coming here, you are likely one of the only individuals in the area to possess your unique skillset." + spawn_positions = 2 + total_positions = 2 + outfit_type = /decl/outfit/job/shaded_hills/traveller/scholar + skill_points = 26 + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT + ) + max_skill = list( + SKILL_CHEMISTRY = SKILL_MAX, + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX, + ) + +/obj/abstract/landmark/start/shaded_hills/traveller/learned + name = "Itinerant Scholar" + +/datum/job/shaded_hills/visitor/beggar_knight + title = "Beggar Knight" + supervisors = "your vows" + description = "You are a wandering swordmaster sworn to a vow of poverty, with nothing to your name but the armour on your back and the blade at your hip. Beggar knights are tolerated due to their martial prowess, and are usually paid with food or new equipment as they are avowed against carrying coin." + spawn_positions = 2 + total_positions = 2 + outfit_type = /decl/outfit/job/shaded_hills/beggar_knight + min_skill = list( + SKILL_COMBAT = SKILL_ADEPT, + SKILL_WEAPONS = SKILL_ADEPT, + SKILL_ATHLETICS = SKILL_ADEPT + ) + max_skill = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + SKILL_CARPENTRY = SKILL_BASIC, + SKILL_METALWORK = SKILL_BASIC, + SKILL_TEXTILES = SKILL_BASIC, + SKILL_STONEMASONRY = SKILL_BASIC, + SKILL_SCULPTING = SKILL_BASIC, + SKILL_ARTIFICE = SKILL_BASIC, + SKILL_FINANCE = SKILL_NONE + ) + +/obj/abstract/landmark/start/shaded_hills/beggar_knight + name = "Beggar Knight" + + +/datum/job/shaded_hills/visitor/traveller/cleric + title = "Travelling Cleric" + supervisors = "your vows, and your faith" + description = "You are an ordained person of faith, travelling the lands on the business of your order, to preach, or simply to experience new people and cultures. You are battle-trained, but are also a healer." + spawn_positions = 2 + total_positions = 2 + outfit_type = /decl/outfit/job/shaded_hills/traveller/cleric + min_skill = list( + SKILL_COMBAT = SKILL_ADEPT, + SKILL_WEAPONS = SKILL_ADEPT, + SKILL_ATHLETICS = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_ADEPT, + SKILL_ANATOMY = SKILL_ADEPT + ) + max_skill = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX + ) + skill_points = 22 + +/obj/abstract/landmark/start/shaded_hills/cleric + name = "Travelling Cleric" + diff --git a/maps/shaded_hills/jobs/wilderness.dm b/maps/shaded_hills/jobs/wilderness.dm new file mode 100644 index 000000000000..2ae6a03ef709 --- /dev/null +++ b/maps/shaded_hills/jobs/wilderness.dm @@ -0,0 +1,67 @@ +/decl/department/shaded_hills/locals + name = "Locals" + colour = "#40684a" + display_color = "#8cc4a8" + +/datum/job/shaded_hills/local + abstract_type = /datum/job/shaded_hills/local + department_types = list(/decl/department/shaded_hills/locals) + +/datum/job/shaded_hills/local/miner + title = "Miner" + description = "You mine ores from the mountain, and occasionally refine them, too. The only limit to your potential bounty is your own hard work and ingenuity... and the kobaloi in the caves." + supervisors = "the consequences of your actions" + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/shaded_hills/miner + min_skill = list( + SKILL_HAULING = SKILL_ADEPT, // general physical activity + SKILL_METALWORK = SKILL_BASIC, // ore smelting, metallurgy + SKILL_STONEMASONRY = SKILL_BASIC, // experienced working with stone + SKILL_SCULPTING = SKILL_BASIC, // producing clay molds, firing pottery + ) + skill_points = 20 + +/obj/abstract/landmark/start/shaded_hills/miner + name = "Miner" + +/datum/job/shaded_hills/local/herbalist + title = "Herbalist" + description = "You collect and grow plants and herbs and process them into various useful substances, such as medicinal tinctures, ointments, and teas." + supervisors = "nature" + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/shaded_hills/herbalist + min_skill = list( + SKILL_BOTANY = SKILL_ADEPT, // growing, processing, and identifying plants + SKILL_MEDICAL = SKILL_BASIC, // identifying illnesses and applying medicines + SKILL_CHEMISTRY = SKILL_BASIC, // processing plant extracts into tinctures, ointments, etc + ) + max_skill = list( + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX, + SKILL_CHEMISTRY = SKILL_MAX, + ) + skill_points = 22 + +/obj/abstract/landmark/start/shaded_hills/herbalist + name = "Herbalist" + +/datum/job/shaded_hills/local/forester + title = "Forester" + description = "You are at home in nature, whether you're fishing, hunting wild game, or chopping timber for firewood and construction." + supervisors = "nature" + spawn_positions = 1 + total_positions = 1 + outfit_type = /decl/outfit/job/shaded_hills/forester + min_skill = list( + SKILL_HAULING = SKILL_ADEPT, // overall physical activity + SKILL_HUSBANDRY = SKILL_BASIC, // handling and caring for animals + SKILL_BOTANY = SKILL_BASIC, // growing and harvesting plants, trees, etc + SKILL_COOKING = SKILL_BASIC, // butchery + SKILL_CARPENTRY = SKILL_ADEPT, // tree felling + ) + skill_points = 22 + +/obj/abstract/landmark/start/shaded_hills/forester + name = "Forester" diff --git a/maps/shaded_hills/levels/_levels.dm b/maps/shaded_hills/levels/_levels.dm new file mode 100644 index 000000000000..411714f57c56 --- /dev/null +++ b/maps/shaded_hills/levels/_levels.dm @@ -0,0 +1,197 @@ +/obj/abstract/map_data/shaded_hills + height = 2 + +/datum/level_data/main_level/shaded_hills + use_global_exterior_ambience = FALSE + base_area = null + base_turf = /turf/floor/dirt + abstract_type = /datum/level_data/main_level/shaded_hills + ambient_light_level = 1 + ambient_light_color = "#f3e6ca" + strata = /decl/strata/shaded_hills + exterior_atmosphere = list( + /decl/material/gas/oxygen = MOLES_O2STANDARD, + /decl/material/gas/nitrogen = MOLES_N2STANDARD + ) + daycycle_type = /datum/daycycle/shaded_hills + daycycle_id = "daycycle_shaded_hills" + template_edge_padding = 0 // we use a strictly delineated subarea, no need for this guard + +/datum/daycycle/shaded_hills + cycle_duration = 2 HOURS // 1 hour of daylight, 1 hour of night + +// Randomized time of day to start at. +/datum/daycycle/shaded_hills/New() + time_in_cycle = rand(cycle_duration) + ..() + +/datum/level_data/main_level/shaded_hills/grassland + name = "Shaded Hills - Grassland" + level_id = "shaded_hills_grassland" + level_generators = list( + /datum/random_map/automata/cave_system/shaded_hills, + /datum/random_map/noise/ore/poor/shaded_hills, + /datum/random_map/noise/forage/shaded_hills/grassland + ) + connected_levels = list( + "shaded_hills_woods" = NORTH, + "shaded_hills_swamp" = SOUTH, + "shaded_hills_downlands" = EAST + ) + subtemplate_budget = 5 + subtemplate_category = MAP_TEMPLATE_CATEGORY_FANTASY_GRASSLAND + subtemplate_area = /area/shaded_hills/outside/poi + +/datum/level_data/main_level/shaded_hills/grassland/get_mobs_to_populate_level() + var/static/list/mobs_to_spawn = list( + list( + list( + /mob/living/simple_animal/passive/mouse = 9, + /mob/living/simple_animal/passive/rabbit = 3, + /mob/living/simple_animal/passive/rabbit/brown = 3, + /mob/living/simple_animal/passive/rabbit/black = 3, + /mob/living/simple_animal/opossum = 5 + ), + /turf/floor/grass, + 10 + ) + ) + return mobs_to_spawn + +/datum/level_data/main_level/shaded_hills/swamp + name = "Shaded Hills - Swamp" + level_id = "shaded_hills_swamp" + connected_levels = list( + "shaded_hills_grassland" = NORTH + ) + level_generators = list( + /datum/random_map/noise/shaded_hills/swamp, + /datum/random_map/noise/forage/shaded_hills/swamp + ) + subtemplate_budget = 5 + subtemplate_category = MAP_TEMPLATE_CATEGORY_FANTASY_SWAMP + subtemplate_area = /area/shaded_hills/outside/swamp/poi + +/datum/level_data/main_level/shaded_hills/swamp/get_mobs_to_populate_level() + var/static/list/mobs_to_spawn = list( + list( + list( + /mob/living/simple_animal/passive/mouse = 6, + /mob/living/simple_animal/passive/rabbit = 2, + /mob/living/simple_animal/passive/rabbit/brown = 2, + /mob/living/simple_animal/passive/rabbit/black = 2, + /mob/living/simple_animal/frog = 3, + /mob/living/simple_animal/frog/brown = 2, + /mob/living/simple_animal/frog/yellow = 2, + /mob/living/simple_animal/frog/purple = 1 + ), + /turf/floor/grass, + 5 + ), + list( + list( + /mob/living/simple_animal/frog = 3, + /mob/living/simple_animal/frog/brown = 2, + /mob/living/simple_animal/frog/yellow = 2, + /mob/living/simple_animal/frog/purple = 1 + ), + /turf/floor/mud, + 10 + ) + ) + return mobs_to_spawn + +/datum/level_data/main_level/shaded_hills/woods + name = "Shaded Hills - Woods" + level_id = "shaded_hills_woods" + connected_levels = list( + "shaded_hills_grassland" = SOUTH + ) + level_generators = list( + /datum/random_map/noise/shaded_hills/woods, + /datum/random_map/noise/forage/shaded_hills/woods + ) + subtemplate_budget = 5 + subtemplate_category = MAP_TEMPLATE_CATEGORY_FANTASY_WOODS + subtemplate_area = /area/shaded_hills/outside/woods/poi + +/datum/level_data/main_level/shaded_hills/woods/get_mobs_to_populate_level() + var/static/list/mobs_to_spawn = list( + list( + list( + /mob/living/simple_animal/passive/mouse = 6, + /mob/living/simple_animal/passive/rabbit = 2, + /mob/living/simple_animal/passive/rabbit/brown = 2, + /mob/living/simple_animal/passive/rabbit/black = 2, + /mob/living/simple_animal/opossum = 2 + ), + /turf/floor/grass, + 10 + ), + list( + list( + /mob/living/simple_animal/passive/deer = 1 + ), + /turf/floor/grass, + 5 + ) + ) + return mobs_to_spawn + +/datum/level_data/main_level/shaded_hills/downlands + name = "Shaded Hills - Downlands" + level_id = "shaded_hills_downlands" + level_generators = list( + /datum/random_map/noise/shaded_hills/woods, + /datum/random_map/noise/forage/shaded_hills/grassland + ) + connected_levels = list( + "shaded_hills_grassland" = WEST + ) + subtemplate_budget = 5 + subtemplate_category = MAP_TEMPLATE_CATEGORY_FANTASY_DOWNLANDS + subtemplate_area = /area/shaded_hills/outside/downlands/poi + +/datum/level_data/main_level/shaded_hills/caverns + name = "Shaded Hills - Caverns" + level_id = "shaded_hills_caverns" + connected_levels = list( + "shaded_hills_dungeon" = EAST + ) + subtemplate_budget = 5 + subtemplate_category = MAP_TEMPLATE_CATEGORY_FANTASY_CAVERNS + subtemplate_area = /area/shaded_hills/caves/deep/poi + level_generators = list( + /datum/random_map/automata/cave_system/shaded_hills, + /datum/random_map/noise/ore/rich/shaded_hills + ) + base_turf = /turf/floor/rock/basalt + +/datum/level_data/main_level/shaded_hills/dungeon + name = "Shaded Hills - Dungeon" + level_id = "shaded_hills_dungeon" + connected_levels = list( + "shaded_hills_caverns" = WEST + ) + subtemplate_budget = 5 + subtemplate_category = MAP_TEMPLATE_CATEGORY_FANTASY_DUNGEON + subtemplate_area = /area/shaded_hills/caves/dungeon/poi + base_turf = /turf/floor/rock/basalt + +/obj/abstract/level_data_spawner/shaded_hills_grassland + level_data_type = /datum/level_data/main_level/shaded_hills/grassland + +/obj/abstract/level_data_spawner/shaded_hills_swamp + level_data_type = /datum/level_data/main_level/shaded_hills/swamp + +/obj/abstract/level_data_spawner/shaded_hills_woods + level_data_type = /datum/level_data/main_level/shaded_hills/woods + +/obj/abstract/level_data_spawner/shaded_hills_downlands + level_data_type = /datum/level_data/main_level/shaded_hills/downlands + +/obj/abstract/level_data_spawner/shaded_hills_caverns + level_data_type = /datum/level_data/main_level/shaded_hills/caverns + +/obj/abstract/level_data_spawner/shaded_hills_dungeon + level_data_type = /datum/level_data/main_level/shaded_hills/dungeon diff --git a/maps/shaded_hills/levels/random_map.dm b/maps/shaded_hills/levels/random_map.dm new file mode 100644 index 000000000000..5c3098b3c2c7 --- /dev/null +++ b/maps/shaded_hills/levels/random_map.dm @@ -0,0 +1,130 @@ +/datum/random_map/automata/cave_system/shaded_hills + descriptor = "Shaded Hills caves" + floor_type = /turf/floor/rock/basalt + wall_type = /turf/wall/natural/basalt/shaded_hills + sparse_mineral_turf = /turf/wall/natural/random/basalt/shaded_hills + rich_mineral_turf = /turf/wall/natural/random/high_chance/basalt/shaded_hills + +/datum/random_map/noise/shaded_hills + abstract_type = /datum/random_map/noise/shaded_hills + smoothing_iterations = 1 + smooth_single_tiles = TRUE + target_turf_type = /turf/unsimulated/mask + +/datum/random_map/noise/forage/shaded_hills + abstract_type = /datum/random_map/noise/forage/shaded_hills + +/datum/random_map/noise/ore/poor/shaded_hills + +/datum/random_map/noise/ore/rich/shaded_hills + +/datum/random_map/noise/shaded_hills/swamp + descriptor = "Shaded Hills swamp" + +/datum/random_map/noise/shaded_hills/swamp/get_appropriate_path(var/value) + value = noise2value(value) + if(value <= 3) + return /turf/floor/mud/water/deep + if(value <= 5) + return /turf/floor/mud/water + if(value <= 7) + return /turf/floor/mud + return /turf/floor/grass + +/datum/random_map/noise/shaded_hills/woods + descriptor = "Shaded Hills Woods" + +/datum/random_map/noise/shaded_hills/woods/get_appropriate_path(var/value) + value = noise2value(value) + if(value <= 6) + return /turf/floor/grass/wild + return /turf/floor/grass + +/datum/random_map/noise/forage/shaded_hills/grassland/New() + forage["grass"] |= list( + "yarrow", + "valerian" + ) + ..() + +/datum/random_map/noise/forage/shaded_hills/swamp + tree_weight = 4 + trees = list( + /obj/structure/flora/tree/hardwood/walnut = 1, + /obj/structure/flora/tree/dead/walnut = 2, + /obj/structure/flora/bush = 4, + /obj/structure/flora/bush/leafybush = 5, + /obj/structure/flora/bush/grassybush = 5, + /obj/structure/flora/bush/stalkybush = 5, + /obj/structure/flora/bush/reedbush = 6, + /obj/structure/flora/bush/fernybush = 6, + ) + +/datum/random_map/noise/forage/shaded_hills/swamp/New() + forage["grass"] |= list( + "aloe", + "foxglove" + ) + forage["riverbed"] = list( + // the swamp doesn't really have enough flowing water for molluscs to live here or for flint to wash up + "algae" + ) + forage["riverbank"] = list( + "harebells", + "lavender", + "nettle", + "algae", + "mushrooms" + ) + return ..() + +/datum/random_map/noise/forage/shaded_hills/woods + tree_weight = 7 + trees = list( + /obj/structure/flora/tree/hardwood/walnut = 8, + /obj/structure/flora/tree/hardwood/yew = 8, + /obj/structure/flora/tree/hardwood/mahogany = 8, + /obj/structure/flora/bush/pointybush = 3, + /obj/structure/flora/tree/dead/walnut = 1, + /obj/structure/flora/tree/dead/yew = 1, + /obj/structure/flora/tree/dead/mahogany = 1, + /obj/structure/flora/stump/tree/walnut = 1, + /obj/structure/flora/stump/tree/yew = 1, + /obj/structure/flora/stump/tree/mahogany = 1, + /obj/structure/flora/bush/genericbush = 1, + /obj/structure/flora/bush/grassybush = 1, + /obj/structure/flora/bush/stalkybush = 1, + /obj/structure/flora/bush/reedbush = 1, + /obj/structure/flora/bush/fernybush = 1, + /atom/movable/spawn_litter = 1, + ) + +/datum/random_map/noise/forage/shaded_hills/woods/New() + forage["grass"] |= list( + "ginseng", + "foxglove", + /atom/movable/spawn_litter + ) + forage["riverbank"] = list(/atom/movable/spawn_litter) + ..() + +/// Helper type to spawn random forest litter. +/atom/movable/spawn_litter + name = "forest litter spawner" + is_spawnable_type = FALSE + simulated = FALSE + var/list/spawn_type = list( + /obj/effect/decal/cleanable/plant_bits = 5, + /atom/movable/spawn_boulder/rock = 2, + /obj/item/rock/flint = 2, + /atom/movable/spawn_boulder = 1 + ) + +/atom/movable/spawn_litter/Initialize() + ..() + if(isturf(loc)) + if(islist(spawn_type)) + spawn_type = pickweight(spawn_type) + if(spawn_type) + new spawn_type(loc) + return INITIALIZE_HINT_QDEL \ No newline at end of file diff --git a/maps/shaded_hills/levels/strata.dm b/maps/shaded_hills/levels/strata.dm new file mode 100644 index 000000000000..54781d0f5dca --- /dev/null +++ b/maps/shaded_hills/levels/strata.dm @@ -0,0 +1,20 @@ +// Simplified metal list. +/decl/strata/shaded_hills + name = "mountainous rock" + base_materials = list(/decl/material/solid/stone/basalt) + default_strata_candidate = FALSE + ores_sparse = list( + /decl/material/solid/quartz, + /decl/material/solid/graphite, + /decl/material/solid/tetrahedrite, + /decl/material/solid/hematite, + /decl/material/solid/pyrite, + /decl/material/solid/sodiumchloride + ) + ores_rich = list( + /decl/material/solid/gemstone/diamond, + /decl/material/solid/metal/gold, + /decl/material/solid/metal/platinum, + /decl/material/solid/densegraphite, + /decl/material/solid/galena + ) diff --git a/maps/shaded_hills/outfits/_outfits.dm b/maps/shaded_hills/outfits/_outfits.dm new file mode 100644 index 000000000000..49b61a0ec63a --- /dev/null +++ b/maps/shaded_hills/outfits/_outfits.dm @@ -0,0 +1,17 @@ +/decl/outfit/job/shaded_hills + name = "Shaded Hills Outfit" + abstract_type = /decl/outfit/job/shaded_hills + id_type = null + pda_type = null + l_ear = null + shoes = /obj/item/clothing/shoes/craftable/boots + uniform = list( + /obj/item/clothing/pants/trousers, + /obj/item/clothing/shirt/jerkin + ) + backpack_contents = list( + /obj/item/rock/flint/striker, + /obj/item/bladed/folding/iron, + /obj/item/flame/torch + ) + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL diff --git a/maps/shaded_hills/outfits/caves.dm b/maps/shaded_hills/outfits/caves.dm new file mode 100644 index 000000000000..0f9ac1f637db --- /dev/null +++ b/maps/shaded_hills/outfits/caves.dm @@ -0,0 +1,8 @@ +/decl/outfit/job/shaded_hills/cave_dweller + name = "Shaded Hills - Cave Dweller" + uniform = /obj/item/clothing/pants/loincloth + shoes = /obj/item/clothing/shoes/sandal + hands = list( + /obj/item/gun/launcher/bow/sling, + /obj/item/stack/material/ore/basalt/ten, + ) diff --git a/maps/shaded_hills/outfits/inn.dm b/maps/shaded_hills/outfits/inn.dm new file mode 100644 index 000000000000..fdb283591b1e --- /dev/null +++ b/maps/shaded_hills/outfits/inn.dm @@ -0,0 +1,15 @@ +/decl/outfit/job/shaded_hills/innkeeper + name = "Shaded Hills - Innkeeper" + suit = /obj/item/clothing/suit/apron/colourable + +/decl/outfit/job/shaded_hills/inn_worker + name = "Shaded Hills - Inn Worker" + +/decl/outfit/job/shaded_hills/bartender + name = "Shaded Hills - Bartender" + +/decl/outfit/job/shaded_hills/farmer + name = "Shaded Hills - Farmer" + +/decl/outfit/job/shaded_hills/storekeeper + name = "Shaded Hills - Storekeeper" diff --git a/maps/shaded_hills/outfits/shrine.dm b/maps/shaded_hills/outfits/shrine.dm new file mode 100644 index 000000000000..4f47ac02e623 --- /dev/null +++ b/maps/shaded_hills/outfits/shrine.dm @@ -0,0 +1,14 @@ +/decl/outfit/job/shaded_hills/shrine + name = "Shaded Hills - Shrine Attendant" + uniform = /obj/item/clothing/suit/robe + shoes = /obj/item/clothing/shoes/sandal + backpack_contents = list( + /obj/item/stack/medical/bandage/crafted/five = 1, + /obj/item/stack/medical/ointment/crafted/five = 1, + /obj/item/stack/medical/splint/crafted/five = 1 + ) + +/decl/outfit/job/shaded_hills/shrine/keeper + name = "Shaded Hills - Shrine Keeper" + suit = /obj/item/clothing/suit/mantle + mask = /obj/item/clothing/neck/prayer_beads/basalt diff --git a/maps/shaded_hills/outfits/visitors.dm b/maps/shaded_hills/outfits/visitors.dm new file mode 100644 index 000000000000..ca0204ce1a76 --- /dev/null +++ b/maps/shaded_hills/outfits/visitors.dm @@ -0,0 +1,23 @@ +/decl/outfit/job/shaded_hills/traveller + name = "Shaded Hills - Traveller" + +/decl/outfit/job/shaded_hills/beggar_knight + name = "Shaded Hills - Beggar Knight" + suit = /obj/item/clothing/suit/armor/forged/banded + belt = /obj/item/bladed/shortsword + backpack_contents = list( + /obj/item/stack/medical/bandage/crafted/five = 1, + /obj/item/stack/medical/ointment/crafted/five = 1, + /obj/item/chems/glass/waterskin/crafted/wine = 1 + ) + +/decl/outfit/job/shaded_hills/traveller/scholar + name = "Shaded Hills - Itinerant Scholar" + +/decl/outfit/job/shaded_hills/traveller/cleric + name = "Shaded Hills - Travelling Cleric" + backpack_contents = list( + /obj/item/stack/medical/bandage/crafted/ten = 1, + /obj/item/stack/medical/ointment/crafted/ten = 1, + /obj/item/stack/medical/splint/crafted/five = 1 + ) diff --git a/maps/shaded_hills/outfits/wilderness.dm b/maps/shaded_hills/outfits/wilderness.dm new file mode 100644 index 000000000000..1129a47be4ea --- /dev/null +++ b/maps/shaded_hills/outfits/wilderness.dm @@ -0,0 +1,12 @@ +/decl/outfit/job/shaded_hills/forester + name = "Shaded Hills - Forester" + hands = list( + /obj/item/gun/launcher/bow, + /obj/item/stack/material/bow_ammo/arrow/fifteen + ) + +/decl/outfit/job/shaded_hills/miner + name = "Shaded Hills - Miner" + +/decl/outfit/job/shaded_hills/herbalist + name = "Shaded Hills - Herbalist" diff --git a/maps/shaded_hills/shaded_hills-caverns.dmm b/maps/shaded_hills/shaded_hills-caverns.dmm new file mode 100644 index 000000000000..1916bb3b5d22 --- /dev/null +++ b/maps/shaded_hills/shaded_hills-caverns.dmm @@ -0,0 +1,22840 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"az" = ( +/obj/random/hostile/cave, +/turf/floor/rock/basalt, +/area/shaded_hills/caves/deep/poi) +"bV" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/caves/deep) +"kZ" = ( +/obj/abstract/level_data_spawner/shaded_hills_caverns, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/deep) +"mZ" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/deep) +"qR" = ( +/obj/abstract/ramp_sculptor/south, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/deep) +"um" = ( +/turf/unsimulated/mask, +/area/shaded_hills/caves/deep/poi) +"vo" = ( +/obj/abstract/ramp_sculptor/east, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/deep) +"vR" = ( +/turf/floor/lava, +/area/shaded_hills/caves/deep/poi) +"wz" = ( +/obj/random/hostile/cave, +/turf/floor/rock/basalt, +/area/shaded_hills/caves/deep) +"MT" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/caves/deep/poi) +"Ng" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/deep) + +(1,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(2,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(3,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(4,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(5,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(6,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(7,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(8,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(9,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +kZ +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(10,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(11,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(12,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(13,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(14,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(15,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(16,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(17,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(18,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(19,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(20,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(21,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(22,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(23,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(24,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(25,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(26,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(27,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(28,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(29,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(30,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(31,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +az +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(32,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(33,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +bV +bV +Ng +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(34,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +qR +bV +vo +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(35,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +az +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +qR +bV +bV +vo +vo +Ng +Ng +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(36,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +qR +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(37,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(38,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +um +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +bV +bV +wz +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(39,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(40,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +az +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(41,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(42,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +vR +vR +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(43,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +vR +vR +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(44,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +vR +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(45,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(46,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(47,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(48,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(49,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(50,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(51,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +MT +MT +MT +az +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(52,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +MT +MT +MT +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(53,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +MT +MT +MT +MT +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(54,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +MT +MT +vR +MT +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(55,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +MT +MT +vR +vR +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +vR +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(56,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +vR +MT +MT +MT +MT +MT +MT +MT +vR +vR +vR +vR +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(57,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +MT +MT +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +vR +vR +vR +vR +vR +MT +MT +MT +MT +vR +vR +vR +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(58,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +MT +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +MT +MT +MT +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +vR +vR +MT +MT +vR +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(59,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +vR +MT +MT +vR +vR +vR +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(60,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +bV +bV +bV +bV +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +MT +vR +vR +vR +vR +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(61,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +um +vR +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(62,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +vR +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(63,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(64,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(65,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(66,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(67,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(68,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +vR +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(69,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +vR +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(70,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +um +um +um +um +um +um +vR +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(71,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(72,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(73,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(74,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(75,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(76,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +bV +bV +um +um +um +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(77,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +bV +bV +um +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(78,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +um +um +um +um +um +um +um +um +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(79,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +um +um +um +um +um +um +um +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(80,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +MT +bV +bV +bV +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +az +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(81,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(82,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(83,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(84,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(85,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(86,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(87,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(88,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(89,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(90,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(91,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +az +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +vR +um +um +um +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(92,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +um +MT +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +vR +vR +vR +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(93,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +vR +vR +vR +um +um +um +um +um +um +um +vR +vR +um +um +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(94,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +vR +vR +vR +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(95,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(96,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +vR +vR +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(97,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +az +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(98,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(99,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(100,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +MT +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(101,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(102,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(103,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(104,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(105,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +MT +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(106,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(107,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +um +um +um +um +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(108,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +MT +MT +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(109,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +MT +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(110,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(111,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(112,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(113,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +MT +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(114,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +MT +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(115,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(116,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(117,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(118,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(119,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(120,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(121,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(122,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(123,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(124,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(125,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(126,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(127,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(128,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +wz +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(129,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(130,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(131,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(132,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(133,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(134,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(135,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(136,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(137,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(138,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +bV +bV +bV +bV +bV +bV +bV +bV +bV +bV +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +um +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(139,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +bV +bV +bV +bV +bV +bV +bV +bV +bV +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(140,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +bV +bV +bV +bV +bV +bV +bV +bV +bV +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(141,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +bV +bV +bV +bV +bV +bV +bV +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(142,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +bV +bV +bV +bV +bV +bV +bV +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(143,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +bV +bV +bV +bV +bV +bV +bV +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +Ng +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(144,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(145,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(146,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(147,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(148,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(149,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(150,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} diff --git a/maps/shaded_hills/shaded_hills-dungeon.dmm b/maps/shaded_hills/shaded_hills-dungeon.dmm new file mode 100644 index 000000000000..b50e7b8b0385 --- /dev/null +++ b/maps/shaded_hills/shaded_hills-dungeon.dmm @@ -0,0 +1,23485 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ae" = ( +/obj/item/stack/material/bolt/mapped/cloth/fifty, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"aK" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/caves/dungeon/poi) +"aS" = ( +/obj/item/stack/material/bolt/mapped/cloth/five, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"bD" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"bG" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/obj/item/clothing/suit/armor/crafted/copper, +/obj/item/clothing/pants/trousers/braies, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"ce" = ( +/obj/structure/table/wood/reinforced/ebony/walnut, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"cp" = ( +/obj/structure/table/wood/ebony, +/obj/item/bladed/knife/iron, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"cM" = ( +/obj/item/stool/rustic, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"dA" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/obj/item/remains/human, +/obj/item/clothing/pants/trousers/braies, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"dP" = ( +/obj/structure/table/wood/ebony, +/obj/item/flame/torch, +/obj/item/flame/torch, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"dT" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/knife/kitchen/cleaver/bronze, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"fh" = ( +/mob/living/simple_animal/aquatic/fish/grump, +/turf/floor/path/basalt/water/deep, +/area/shaded_hills/caves/dungeon/poi) +"fD" = ( +/obj/structure/table/wood/reinforced/ebony/walnut, +/obj/item/ancient_surgery/bonesaw, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"fF" = ( +/obj/random/dungeon_bookcase, +/turf/floor/rock/basalt, +/area/shaded_hills/caves/dungeon/poi) +"fW" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/item/stack/medical/bandage/crafted/five, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"gy" = ( +/obj/structure/table/wood/reinforced/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"hd" = ( +/obj/structure/table/wood/ebony, +/obj/item/stack/material/brick/mapped/graphite/fifteen, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"hr" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"hz" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"hU" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/dungeon/poi) +"it" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/caves/dungeon/poi) +"iI" = ( +/obj/structure/wall_sconce{ + dir = 8 + }, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"jf" = ( +/obj/item/remains/human, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"jh" = ( +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"jv" = ( +/obj/item/remains/human, +/turf/floor/mud, +/area/shaded_hills/caves/dungeon) +"jU" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/item/food/grown/dried_tobacco/bad, +/obj/item/rock/flint/striker, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"jV" = ( +/obj/item/stack/material/plank/mapped/ebony/five, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"ko" = ( +/obj/item/stack/material/bone/mapped/bone/twentyfive, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"kE" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/ingot/mapped/silver/ten, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"kI" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/flame/candle, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"kL" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/bladed/folding, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"kN" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/obj/item/stack/material/bolt/mapped/cloth/five, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"lj" = ( +/obj/structure/drying_rack/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"lo" = ( +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"lC" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/dungeon) +"lE" = ( +/obj/abstract/level_data_spawner/shaded_hills_dungeon, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/dungeon) +"mM" = ( +/turf/floor/dirt, +/area/shaded_hills/caves/dungeon) +"ni" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/ingot/mapped/iron/twentyfive, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"nD" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"nE" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/item/bladed/folding, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"nH" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/obj/item/clothing/suit/armor/forged/banded, +/obj/item/clothing/pants/trousers/braies, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"nJ" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/food/grown/dried_tobacco/fine, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"nT" = ( +/obj/structure/table/wood/ebony, +/obj/item/stack/material/ore/diamond, +/obj/item/stack/material/ore/diamond, +/obj/item/stack/material/ore/diamond, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"nV" = ( +/obj/structure/table/wood/ebony, +/obj/item/bladed/folding, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"ob" = ( +/obj/structure/table/wood/ebony, +/obj/item/bladed/knife/iron, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"ok" = ( +/obj/random/hostile/dungeon, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"oq" = ( +/obj/item/stack/material/skin/mapped/leather/twentyfive, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"ou" = ( +/obj/random/hostile/dungeon, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"oD" = ( +/obj/structure/wall_sconce{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"oF" = ( +/turf/wall/natural/dirt, +/area/shaded_hills/caves/dungeon/poi) +"oP" = ( +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/inn) +"oW" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"pl" = ( +/obj/item/cash/imperial/crown, +/turf/floor/path/basalt/water, +/area/shaded_hills/caves/dungeon/poi) +"pZ" = ( +/obj/structure/reagent_dispensers/barrel/ebony/oil, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"qh" = ( +/obj/structure/wall_sconce{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"rz" = ( +/turf/floor/path/basalt/water/deep, +/area/shaded_hills/caves/dungeon/poi) +"rA" = ( +/turf/wall/log/walnut, +/area/shaded_hills/caves/dungeon/inn) +"rI" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/ingot/mapped/tin/twenty, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"rM" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/bladed/longsword, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"rP" = ( +/obj/structure/table/wood/reinforced/ebony/walnut, +/obj/item/ancient_surgery/forceps, +/obj/item/ancient_surgery/retractor, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"sU" = ( +/turf/floor/dirt, +/area/shaded_hills/caves/dungeon/poi) +"tQ" = ( +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/turf/floor/path/basalt/water, +/area/shaded_hills/caves/dungeon/poi) +"ud" = ( +/obj/structure/wall_sconce{ + dir = 4 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"uU" = ( +/obj/item/remains/human, +/turf/floor/mud, +/area/shaded_hills/caves/dungeon/poi) +"vu" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/bladed/longsword, +/obj/item/bladed/poignard, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"vN" = ( +/obj/structure/table/wood/reinforced/ebony/walnut, +/obj/item/remains/human, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"vO" = ( +/obj/structure/working/loom/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"wa" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"wg" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/obj/random/hostile/dungeon, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"wP" = ( +/obj/structure/table/wood/ebony, +/obj/item/tool/hammer, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"xo" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/medical/ointment/crafted/five, +/obj/item/stack/medical/ointment/crafted/five, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"xL" = ( +/obj/abstract/ramp_sculptor/east, +/turf/wall/natural/dirt, +/area/shaded_hills/caves/dungeon) +"yh" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"yM" = ( +/obj/structure/table/wood/ebony, +/obj/item/tool/pickaxe/iron, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"zm" = ( +/obj/structure/wall_sconce{ + dir = 8 + }, +/obj/structure/table/wood/reinforced/ebony/walnut, +/obj/item/ancient_surgery/bonesetter, +/obj/item/ancient_surgery/sutures, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"zA" = ( +/obj/structure/door/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ad" = ( +/obj/structure/wall_sconce{ + dir = 8 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"AK" = ( +/obj/structure/fire_source/stove, +/obj/effect/decal/cleanable/ash, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Bk" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/obj/item/food/grown/dried_tobacco/bad, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"BG" = ( +/obj/structure/table/wood/ebony, +/obj/item/stack/material/thread/mapped/cotton/thirty, +/obj/item/bladed/knife/iron, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Cu" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/caves/dungeon/inn) +"CA" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/ingot/mapped/bronze/twenty, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"CP" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/ingot/mapped/gold/ten, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"CZ" = ( +/obj/structure/door/ebony, +/obj/abstract/landmark/lock_preset/shaded_hills/inn_exterior, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/inn) +"Dr" = ( +/obj/structure/wall_sconce{ + dir = 4 + }, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"DW" = ( +/obj/structure/table/wood/ebony, +/obj/item/bladed/folding, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ef" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Eq" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/item/stack/material/bolt/mapped/cloth/five, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Fx" = ( +/turf/wall/natural/dirt, +/area/shaded_hills/caves/dungeon/inn) +"FT" = ( +/obj/random/hostile/dungeon, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Gr" = ( +/obj/structure/working/spinning_wheel/twisting_bench/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Gu" = ( +/obj/structure/table/wood/reinforced/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"GA" = ( +/obj/structure/door/ebony, +/obj/abstract/landmark/lock_preset{ + lock_preset_id = "sunken keep"; + name = "sunken keep locked door" + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"GV" = ( +/turf/floor/path/basalt/water, +/area/shaded_hills/caves/dungeon/poi) +"Hj" = ( +/obj/item/cash/imperial/quin, +/turf/floor/path/basalt/water, +/area/shaded_hills/caves/dungeon/poi) +"Hs" = ( +/obj/structure/table/wood/ebony, +/obj/item/flame/candle, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"HI" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/caves/dungeon) +"HO" = ( +/obj/structure/table/wood/reinforced/ebony/walnut, +/obj/item/ancient_surgery/cautery, +/obj/item/ancient_surgery/scalpel, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ie" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/mortar, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Im" = ( +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ip" = ( +/turf/floor/mud, +/area/shaded_hills/caves/dungeon/poi) +"IF" = ( +/obj/structure/wall_sconce{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Kq" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/bladed/broadsword, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ky" = ( +/obj/random/dungeon_bookcase, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Kz" = ( +/obj/structure/fire_source/kiln/high_temperature, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"KB" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/inn) +"Ln" = ( +/obj/structure/table/wood/ebony, +/obj/item/tool/hammer/sledge, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"LB" = ( +/obj/structure/table/wood/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"ME" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/obj/item/stack/medical/bandage/crafted/five, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"MW" = ( +/obj/structure/table/wood/ebony, +/obj/item/rock/flint/striker, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"NN" = ( +/obj/structure/table/desk/ebony/right, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Og" = ( +/turf/floor/mud/water, +/area/shaded_hills/caves/dungeon/poi) +"Oq" = ( +/obj/structure/table/wood/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Pb" = ( +/turf/wall/natural/dirt, +/area/shaded_hills/caves/dungeon) +"Pq" = ( +/obj/structure/wall_sconce, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ql" = ( +/obj/structure/door/ebony, +/turf/floor/dirt, +/area/shaded_hills/caves/dungeon/poi) +"QI" = ( +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/turf/floor/path/basalt/water, +/area/shaded_hills/caves/dungeon/poi) +"QT" = ( +/obj/structure/stairs/north, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/inn) +"Ri" = ( +/obj/item/stack/material/plank/mapped/ebony/five, +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/medical/bandage/crafted/five, +/obj/item/stack/medical/bandage/crafted/five, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Rm" = ( +/obj/structure/table/wood/ebony, +/obj/item/stack/material/ore/diamond, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Rt" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/random/hostile/dungeon, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"RA" = ( +/turf/floor/mud, +/area/shaded_hills/caves/dungeon) +"Ss" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/bolt/mapped/cloth/fifty, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"SN" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/item/remains/human, +/obj/item/clothing/suit/armor/forged/banded, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"SX" = ( +/obj/structure/door/ebony, +/obj/abstract/landmark/lock_preset/shaded_hills/shrine, +/turf/floor/mud, +/area/shaded_hills/caves/dungeon) +"TA" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/ingot/mapped/copper/twenty, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"TR" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/dungeon) +"Ua" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Ve" = ( +/obj/structure/bed/simple/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Vk" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/food/grown/dried_tobacco/bad, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Xx" = ( +/turf/wall/log/walnut, +/area/shaded_hills/caves/dungeon) +"XD" = ( +/obj/item/flame/candle, +/obj/structure/table/desk/ebony/right, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"XX" = ( +/obj/structure/wall_sconce, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Yi" = ( +/obj/structure/table/wood/ebony, +/obj/item/stack/material/thread/mapped/dried_gut/thirty, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"YE" = ( +/obj/item/stack/material/plank/mapped/ebony/five, +/turf/floor/path/basalt, +/area/shaded_hills/caves/dungeon/poi) +"YN" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon) +"Zg" = ( +/obj/structure/working/spinning_wheel/ebony, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) +"Zp" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/obj/item/clothing/suit/armor/crafted/leather, +/obj/item/clothing/pants/trousers/braies, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/caves/dungeon/poi) + +(1,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(2,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(3,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(4,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(5,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(6,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(7,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(8,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(9,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +TR +lC +lC +lC +lC +lC +lC +lC +"} +(10,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(11,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(12,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(13,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(14,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(15,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(16,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(17,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(18,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(19,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(20,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(21,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(22,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(23,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(24,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(25,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +mM +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(26,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +HI +HI +HI +HI +HI +HI +HI +mM +mM +mM +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(27,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +HI +mM +HI +HI +HI +mM +mM +mM +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(28,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +sU +sU +Ua +sU +Ua +sU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(29,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +Ua +sU +Ua +sU +sU +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(30,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +Ua +sU +sU +sU +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(31,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +sU +sU +sU +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(32,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +sU +sU +sU +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(33,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +sU +sU +sU +sU +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(34,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +sU +sU +sU +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(35,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +sU +sU +sU +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(36,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +sU +sU +sU +sU +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(37,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +sU +sU +sU +sU +oF +oF +oF +it +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(38,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +sU +Ip +Ip +Ip +oF +oF +oF +it +oF +GV +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(39,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +sU +Ip +Ip +uU +Ip +Ip +oF +oF +oF +oF +GV +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(40,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +sU +sU +Ip +Og +Og +Ip +Ip +oF +oF +it +oF +GV +rz +oF +oF +it +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(41,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +sU +Ip +Og +Og +Og +Og +Ip +sU +oF +it +oF +GV +rz +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(42,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +sU +Ip +Og +aK +Og +Og +Ip +sU +oF +it +oF +GV +rz +GV +oF +it +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(43,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +sU +Ip +Og +Og +Og +Og +Og +Ip +sU +it +oF +GV +rz +GV +oF +it +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(44,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +Ip +Ip +Og +Og +Og +Og +Ip +sU +it +oF +GV +rz +GV +oF +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(45,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +sU +sU +Ip +Og +Ip +Ip +sU +sU +bD +GV +fh +GV +oF +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(46,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +sU +Ip +Ip +sU +sU +Ql +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(47,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +sU +sU +sU +it +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(48,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +it +oF +oF +sU +sU +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(49,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +sU +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(50,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +Ef +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(51,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +pZ +lo +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(52,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +Im +YE +lo +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(53,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +lo +lo +lo +dT +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(54,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +lo +lo +lo +Gu +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(55,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +AK +lo +lo +Im +it +bD +GV +fh +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(56,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +oF +Cu +Cu +rA +Fx +rA +rA +rA +rA +rA +oF +oF +oF +oF +it +oD +lo +lo +Pq +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(57,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +it +oF +Cu +QT +KB +oP +oP +oP +oP +oP +rA +oF +oF +oF +oF +it +Gu +lo +lo +Gu +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(58,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +it +IF +bD +bD +ok +XX +it +bD +bD +it +IF +bD +bD +bD +XX +it +bD +it +oF +Cu +KB +KB +oP +oP +oP +oP +oP +Fx +oF +oF +oF +oF +it +Gu +lo +lo +Gu +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(59,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +bD +wa +dA +wa +bD +jh +jh +jh +jh +bD +wa +wa +wg +bD +bD +bD +it +it +Cu +KB +KB +oP +oP +oP +oP +Cu +Cu +it +it +it +it +it +it +zA +zA +it +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(60,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +bD +gy +gy +gy +bD +jh +QI +pl +jh +bD +kL +Vk +Vk +bD +bD +bD +GA +oF +Fx +Fx +KB +KB +oP +oP +KB +KB +rA +lo +lo +bD +bD +bD +bD +bD +bD +bD +zA +bD +GV +rz +GV +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(61,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +bD +gy +gy +nJ +bD +jh +tQ +Hj +jh +bD +gy +kI +gy +bD +bD +bD +GA +oF +oF +Fx +Fx +Fx +Fx +KB +oP +oP +CZ +bD +bD +bD +bD +bD +bD +bD +bD +bD +zA +bD +GV +rz +GV +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(62,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +bD +Eq +hz +Rt +bD +jh +jh +jh +jh +bD +hz +hz +SN +bD +bD +bD +it +GA +oF +it +it +oF +Fx +Fx +Fx +Cu +Cu +it +it +it +it +it +it +it +it +it +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(63,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +it +IF +bD +bD +bD +XX +it +bD +bD +it +IF +bD +bD +bD +XX +it +bD +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +GV +GV +GV +GV +GV +GV +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(64,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +GV +it +it +it +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(65,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +it +it +it +it +GA +GA +it +it +it +it +it +it +it +it +it +it +it +it +it +bD +bD +it +it +it +it +it +it +it +it +it +it +it +it +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +bD +it +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(66,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +bD +jV +Ve +it +Kq +bD +Ve +it +vu +bD +Ve +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +it +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(67,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +IF +bD +bD +it +IF +bD +bD +it +IF +bD +bD +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +it +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(68,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +bD +bD +nH +it +bD +bD +Zp +it +bD +bD +bG +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(69,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +IF +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +IF +bD +it +it +zA +it +it +it +zA +it +it +it +zA +it +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(70,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +jh +jh +jh +Ad +jh +jh +jh +Ad +jh +jh +jh +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(71,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +GA +jh +bD +bD +ok +bD +bD +bD +ok +bD +bD +jh +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(72,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +GA +jh +bD +bD +bD +bD +bD +bD +bD +bD +bD +jh +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(73,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +jh +oW +nE +jh +jh +jU +fW +jh +jh +oW +oW +it +GV +it +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(74,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +it +IF +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +IF +bD +it +it +it +it +it +it +it +it +it +it +it +it +it +GV +oF +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(75,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +jh +nD +nD +jh +jh +kN +nD +jh +jh +Bk +ME +it +GV +oF +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(76,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +GA +jh +bD +bD +bD +bD +bD +bD +bD +ok +bD +jh +it +oF +oF +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(77,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +GA +jh +bD +bD +bD +ok +bD +bD +bD +bD +bD +jh +oF +oF +oF +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(78,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +it +IF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +IF +bD +it +jh +jh +jh +ud +jh +jh +jh +ud +oF +jh +oF +oF +oF +oF +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(79,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +it +zA +it +it +it +zA +it +it +it +oF +oF +oF +oF +oF +oF +oF +it +bD +GV +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(80,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +oF +oF +oF +oF +oF +oF +oF +oF +it +it +it +it +oF +it +bD +bD +it +jV +bD +Zp +it +bD +bD +Zp +it +oF +oF +oF +oF +oF +it +it +it +it +bD +bD +bD +bD +bD +it +it +it +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(81,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +bD +bD +bD +bD +bD +bD +bD +bD +it +oF +it +bD +bD +it +IF +bD +oF +oF +IF +oF +oF +oF +oF +oF +oF +oF +GV +it +bD +bD +bD +bD +bD +bD +jf +bD +bD +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(82,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +it +oF +it +bD +bD +it +rM +bD +Ve +oF +oF +oF +oF +oF +oF +bD +Ve +it +GV +it +bD +GV +GV +GV +GV +rz +GV +GV +GV +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(83,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +hU +it +it +it +it +it +it +it +it +it +it +it +it +it +it +bD +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +it +it +it +zA +zA +it +it +it +it +oF +oF +oF +oF +oF +it +it +it +it +GV +it +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(84,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +GV +rz +rz +rz +rz +rz +fh +rz +GV +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +oF +oF +oF +bD +bD +bD +bD +GV +bD +bD +GV +rz +rz +rz +rz +rz +fh +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(85,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +bD +GV +rz +fh +rz +rz +rz +rz +rz +GV +bD +bD +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(86,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +rz +rz +rz +rz +rz +rz +rz +rz +rz +rz +fh +rz +rz +rz +rz +rz +bD +bD +rz +rz +rz +rz +rz +rz +rz +rz +rz +bD +bD +rz +rz +rz +fh +rz +rz +rz +rz +rz +rz +rz +rz +rz +fh +rz +rz +rz +rz +bD +bD +rz +rz +rz +rz +rz +rz +rz +rz +GV +bD +it +it +it +it +it +it +oF +oF +it +it +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +it +it +it +it +it +it +bD +bD +it +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(87,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +bD +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +jh +bD +bD +bD +bD +bD +bD +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +bD +bD +bD +bD +bD +bD +it +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(88,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +GV +rz +rz +rz +fh +rz +rz +rz +GV +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +GV +rz +rz +fh +rz +rz +rz +rz +GV +bD +jh +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +bD +bD +bD +it +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(89,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +it +it +it +it +it +it +it +it +it +it +it +it +it +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +it +it +it +it +it +it +it +it +it +it +it +it +zA +zA +it +it +it +it +it +it +bD +GV +rz +rz +rz +rz +rz +rz +rz +GV +bD +it +it +it +it +it +it +it +it +it +it +it +it +it +oF +oF +oF +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +it +it +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(90,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +it +oF +it +ob +Oq +hd +jh +Ad +jh +jh +Oq +it +bD +bD +it +fD +zm +HO +rP +it +bD +GV +GV +GV +GV +GV +GV +GV +GV +GV +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(91,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +it +oF +it +jh +bD +bD +bD +bD +bD +bD +yM +it +bD +bD +it +bD +bD +bD +bD +it +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(92,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +it +it +it +it +it +zA +zA +it +it +it +it +it +oF +it +qh +bD +FT +jh +jh +Kz +bD +Ln +it +bD +bD +it +IF +ce +bD +xo +it +it +it +it +it +it +zA +zA +it +it +it +it +it +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(93,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +it +jh +bD +jh +lo +lo +jh +bD +jh +GA +bD +bD +zA +bD +vN +bD +Ri +it +oF +oF +oF +oF +oF +oF +bD +it +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(94,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +oF +oF +oF +oF +oF +it +jh +bD +jh +lo +lo +jh +bD +jh +GA +bD +bD +zA +bD +bD +bD +aS +it +oF +oF +oF +oF +oF +bD +bD +it +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(95,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +IF +bD +it +oF +oF +oF +oF +oF +it +qh +bD +jh +jh +jh +Kz +bD +DW +it +bD +bD +it +bD +bD +bD +jV +oF +oF +oF +oF +oF +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(96,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +oF +oF +oF +oF +it +jh +bD +bD +bD +bD +bD +bD +Oq +it +bD +bD +it +bD +oF +oF +oF +oF +oF +oF +oF +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(97,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +oF +oF +oF +oF +oF +oF +it +Rm +nT +hd +jh +ud +jh +jh +yM +it +bD +bD +it +oF +oF +oF +oF +oF +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(98,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +oF +oF +oF +oF +oF +oF +oF +it +it +it +it +it +it +it +it +it +it +GA +GA +it +it +it +it +it +it +it +it +it +it +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(99,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +oF +oF +oF +oF +oF +it +Ss +bD +bD +bD +bD +BG +it +ni +bD +bD +bD +bD +wP +it +lj +iI +Ie +nV +MW +iI +hr +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(100,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +oF +oF +oF +oF +oF +oF +oF +oF +it +ae +jh +jh +jh +jh +vO +it +kE +jh +jh +FT +jh +LB +it +lj +jh +jh +jh +jh +jh +hr +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(101,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +it +ko +jh +lo +ou +jh +hz +it +CP +jh +lo +lo +jh +hz +it +Gr +jh +lo +lo +lo +jh +yh +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(102,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +oF +oF +oF +hU +hU +hU +it +ko +jh +lo +lo +jh +wa +it +TA +jh +ou +lo +jh +wa +it +hr +jh +lo +ou +lo +jh +yh +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(103,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +bD +bD +it +it +it +it +it +it +it +oq +jh +jh +jh +jh +Zg +it +CA +jh +jh +jh +jh +wP +it +lj +jh +jh +jh +jh +jh +hr +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(104,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +it +bD +bD +it +bD +bD +iI +bD +bD +it +oq +Dr +bD +bD +Dr +Yi +it +rI +Dr +bD +bD +Dr +cp +it +lj +bD +Dr +bD +bD +bD +hr +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(105,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +it +bD +bD +it +bD +jh +jh +jh +bD +it +it +it +GA +GA +it +it +it +it +it +GA +GA +it +it +it +it +it +it +it +GA +GA +it +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(106,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +it +IF +bD +zA +bD +jh +rz +jh +bD +zA +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +zA +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(107,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +it +bD +bD +zA +bD +jh +rz +jh +bD +zA +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +zA +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(108,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +it +bD +bD +it +bD +jh +jh +jh +bD +it +it +it +it +it +it +it +it +it +zA +zA +it +it +it +it +it +it +it +it +it +it +it +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(109,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +it +bD +bD +it +bD +bD +Dr +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(110,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +it +it +it +it +it +it +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(111,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(112,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +oF +oF +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +it +hU +hU +hU +hU +it +IF +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(113,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +oF +oF +oF +it +XD +cM +iI +bD +LB +LB +bD +iI +LB +Hs +bD +bD +LB +LB +iI +bD +bD +iI +bD +LB +it +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(114,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +oF +oF +oF +it +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +bD +Hs +it +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(115,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +oF +oF +oF +it +bD +bD +Ky +Ky +bD +bD +Ky +Ky +bD +bD +Ky +Ky +bD +bD +fF +Ky +bD +bD +bD +dP +it +it +it +it +it +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(116,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +oF +oF +oF +it +NN +cM +Ky +Ky +bD +ok +Ky +Ky +bD +Ua +Ky +Ky +bD +bD +fF +fF +bD +ok +bD +bD +GA +bD +bD +bD +bD +zA +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(117,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +oF +oF +oF +oF +it +bD +bD +Ky +Ky +bD +bD +Ky +Ky +bD +Ua +fF +Ky +bD +Ua +hU +fF +bD +bD +bD +bD +GA +bD +bD +bD +bD +zA +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(118,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +oF +oF +oF +oF +it +bD +bD +Ky +Ky +bD +bD +Ky +Ky +Ua +bD +Ky +hU +Ua +bD +hU +fF +Ua +bD +bD +MW +it +it +it +it +it +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(119,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +hU +oF +oF +oF +oF +it +NN +cM +bD +bD +bD +bD +bD +bD +bD +hU +HI +HI +YN +hU +hU +hU +Ua +Ua +bD +bD +it +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(120,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +hU +oF +oF +oF +oF +it +bD +bD +bD +bD +LB +Hs +bD +Ua +oF +HI +HI +HI +HI +hU +hU +hU +hU +Ua +Ua +Ua +it +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(121,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +oF +oF +oF +oF +it +it +it +it +it +it +it +it +hU +hU +HI +HI +HI +hU +hU +hU +hU +hU +hU +it +it +it +hU +hU +hU +hU +it +IF +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(122,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +oF +hU +hU +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(123,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +oF +oF +oF +oF +oF +oF +oF +oF +oF +hU +hU +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(124,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +oF +oF +oF +oF +oF +oF +oF +oF +oF +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(125,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +oF +oF +oF +oF +oF +oF +oF +oF +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(126,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Xx +xL +Xx +oF +oF +oF +oF +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(127,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +RA +Pb +Pb +Pb +HI +mM +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(128,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +RA +RA +Xx +mM +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(129,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +Pb +jv +SX +mM +mM +mM +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +IF +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(130,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +Pb +Pb +Xx +Pb +Pb +mM +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(131,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +Pb +Pb +Pb +Pb +Pb +mM +HI +HI +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(132,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +Pb +Pb +Pb +Pb +hU +hU +mM +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(133,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +Pb +Pb +Pb +oF +hU +hU +hU +HI +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(134,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +Pb +Pb +Pb +Pb +Pb +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(135,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +TR +TR +TR +TR +TR +oF +oF +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(136,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(137,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +it +bD +bD +it +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(138,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +hU +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(139,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(140,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(141,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(142,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(143,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(144,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(145,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(146,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(147,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(148,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(149,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(150,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} diff --git a/maps/shaded_hills/shaded_hills-grassland.dmm b/maps/shaded_hills/shaded_hills-grassland.dmm new file mode 100644 index 000000000000..789f7d766c7b --- /dev/null +++ b/maps/shaded_hills/shaded_hills-grassland.dmm @@ -0,0 +1,23175 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aX" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/path/basalt, +/area/shaded_hills/outside) +"bJ" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/grass, +/area/shaded_hills/outside) +"cy" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/abstract/landmark/start/shaded_hills/miner, +/turf/floor/grass, +/area/shaded_hills/outside) +"ee" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/poi) +"el" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/woven, +/area/shaded_hills/outside) +"ex" = ( +/obj/abstract/exterior_marker/inside, +/obj/item/chems/glass/bucket/wood, +/obj/structure/table/end, +/turf/floor/woven, +/area/shaded_hills/outside) +"eL" = ( +/obj/item/stack/material/ore/silver, +/obj/abstract/exterior_marker/inside, +/obj/item/flame/fuelled/lantern/filled, +/turf/floor/woven, +/area/shaded_hills/outside) +"eR" = ( +/turf/floor/dirt, +/area/shaded_hills/caves/unexplored/south) +"fH" = ( +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/barren, +/area/shaded_hills/caves/unexplored/south) +"fO" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/river) +"gQ" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/caves/unexplored/south) +"hT" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/grass, +/area/shaded_hills/outside/river) +"iP" = ( +/obj/structure/fire_source/firepit/basalt, +/obj/item/stack/material/log/mapped/walnut/ten, +/turf/floor/barren, +/area/shaded_hills/outside) +"jj" = ( +/turf/floor/barren, +/area/shaded_hills/caves/unexplored/south) +"js" = ( +/obj/structure/fire_source/kiln/high_temperature, +/turf/floor/rock/basalt, +/area/shaded_hills/outside) +"kq" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside) +"kr" = ( +/obj/item/tool/pickaxe/iron, +/obj/item/tool/axe/iron, +/obj/abstract/exterior_marker/inside, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/woven, +/area/shaded_hills/outside) +"kz" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside) +"kZ" = ( +/obj/abstract/level_data_spawner/shaded_hills_grassland, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/river) +"lC" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/river) +"lE" = ( +/turf/floor/grass, +/area/shaded_hills/outside) +"lU" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/unexplored/south) +"ma" = ( +/turf/floor/mud, +/area/shaded_hills/caves) +"mG" = ( +/obj/structure/chair/bench/ebony, +/obj/item/bladed/folding, +/obj/abstract/landmark/start/shaded_hills/miner, +/turf/floor/barren, +/area/shaded_hills/outside) +"mX" = ( +/obj/abstract/landmark/latejoin/observer, +/turf/floor/barren, +/area/shaded_hills/outside) +"mZ" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/river) +"nd" = ( +/turf/floor/barren, +/area/shaded_hills/caves/entrance) +"nl" = ( +/obj/structure/door/walnut, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside) +"oo" = ( +/obj/item/stack/material/ore/handful/sand, +/turf/floor/rock/basalt, +/area/shaded_hills/outside) +"pU" = ( +/obj/structure/table/wood/ebony, +/obj/item/rock/hematite, +/obj/item/rock/flint, +/obj/item/flame/torch, +/obj/item/flame/torch, +/obj/item/bag/sack, +/turf/floor/woven, +/area/shaded_hills/caves/unexplored/south) +"qj" = ( +/obj/abstract/force_fluid_flow/north, +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river) +"qy" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/river) +"se" = ( +/obj/structure/table/wood/ebony, +/obj/item/basket, +/turf/floor/woven, +/area/shaded_hills/caves/unexplored/south) +"sS" = ( +/turf/floor/mud/water, +/area/shaded_hills/caves/unexplored/south) +"te" = ( +/turf/unsimulated/mask, +/area/shaded_hills/caves/unexplored/south) +"tp" = ( +/turf/unsimulated/mask, +/area/shaded_hills/caves/unexplored) +"ul" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside) +"vX" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/river) +"wW" = ( +/turf/floor/barren, +/area/shaded_hills/outside/poi) +"xe" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/poi) +"xr" = ( +/turf/floor/dirt, +/area/shaded_hills/outside) +"xC" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside) +"yA" = ( +/obj/abstract/landmark/latejoin/observer, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside) +"zp" = ( +/turf/floor/clay, +/area/shaded_hills/outside/river) +"CO" = ( +/obj/abstract/landmark/start/shaded_hills/cave_dweller, +/turf/floor/mud, +/area/shaded_hills/caves/unexplored/south) +"DX" = ( +/turf/floor/mud, +/area/shaded_hills/caves/unexplored/south) +"Ed" = ( +/obj/item/stack/material/brick/mapped/graphite/ten, +/obj/item/stack/material/ore/coal, +/obj/abstract/exterior_marker/inside, +/obj/item/flame/torch, +/obj/item/flame/torch, +/obj/item/flame/torch, +/obj/item/flame/torch, +/obj/item/bag/sack, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/woven, +/area/shaded_hills/outside) +"EE" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside/river) +"EL" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/landmark/start/shaded_hills/miner, +/turf/floor/woven, +/area/shaded_hills/outside) +"EP" = ( +/turf/floor/dirt, +/area/shaded_hills/caves/entrance) +"EQ" = ( +/obj/structure/bed/bedroll/fur, +/obj/abstract/exterior_marker/inside, +/obj/abstract/landmark/start/shaded_hills/miner, +/turf/floor/woven, +/area/shaded_hills/outside) +"ES" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/log/walnut, +/area/shaded_hills/outside) +"EV" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/caves/river) +"Fg" = ( +/obj/structure/door/walnut, +/obj/abstract/exterior_marker/inside, +/turf/floor/path/basalt, +/area/shaded_hills/outside) +"Ft" = ( +/obj/structure/fire_source, +/obj/item/stack/material/log/mapped/wood/ten, +/turf/floor/barren, +/area/shaded_hills/caves) +"Fv" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/outside) +"FK" = ( +/obj/item/stack/material/ore/coal, +/obj/abstract/exterior_marker/inside, +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/woven, +/area/shaded_hills/outside) +"Gh" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/river) +"Gt" = ( +/turf/floor/woven, +/area/shaded_hills/caves/unexplored/south) +"Hn" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/mud, +/area/shaded_hills/outside/river) +"HA" = ( +/turf/floor/dirt, +/area/shaded_hills/caves) +"HI" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/brick/basalt, +/area/shaded_hills/outside/river) +"HV" = ( +/turf/floor/barren, +/area/shaded_hills/outside) +"Ic" = ( +/turf/floor/mud, +/area/shaded_hills/outside/river) +"Jv" = ( +/obj/item/chems/mould/ingot, +/obj/item/chems/mould/ingot, +/turf/floor/rock/basalt, +/area/shaded_hills/outside) +"JN" = ( +/turf/wall/log/walnut, +/area/shaded_hills/outside/river) +"Kd" = ( +/turf/floor/mud, +/area/shaded_hills/outside) +"Ku" = ( +/obj/structure/bed/bedroll/fur, +/obj/abstract/landmark/start/shaded_hills/cave_dweller, +/turf/floor/woven, +/area/shaded_hills/caves/unexplored/south) +"KQ" = ( +/turf/floor/barren, +/area/shaded_hills/caves) +"LF" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/unexplored) +"LX" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/shaded_hills/outside) +"My" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river) +"MH" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/grass/wild, +/area/shaded_hills/outside) +"MK" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/barren, +/area/shaded_hills/outside) +"Ng" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside/poi) +"OL" = ( +/turf/floor/grass, +/area/shaded_hills/outside/poi) +"OP" = ( +/obj/item/chems/crucible, +/turf/floor/rock/basalt, +/area/shaded_hills/outside) +"PO" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/brick/basalt, +/area/shaded_hills/outside) +"Qx" = ( +/turf/open, +/area/shaded_hills/caves/unexplored/south) +"Sm" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside) +"TD" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/grass/wild, +/area/shaded_hills/outside) +"TH" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/unexplored/south) +"TR" = ( +/turf/floor/grass, +/area/shaded_hills/outside/river) +"UE" = ( +/turf/floor/grass/wild, +/area/shaded_hills/outside/poi) +"UI" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/outside/poi) +"UV" = ( +/turf/floor/mud/water, +/area/shaded_hills/caves/river) +"VO" = ( +/turf/floor/mud, +/area/shaded_hills/caves/entrance) +"WH" = ( +/obj/item/chems/glass/bucket/wood, +/turf/floor/mud, +/area/shaded_hills/caves/unexplored/south) +"WO" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/grass, +/area/shaded_hills/outside) +"Xd" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside/river) +"Xt" = ( +/turf/floor/grass/wild, +/area/shaded_hills/outside) +"Yf" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/unexplored) +"Yv" = ( +/obj/abstract/map_data/shaded_hills, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/river) +"YB" = ( +/obj/structure/chair/bench/ebony{ + dir = 8 + }, +/obj/abstract/landmark/start/shaded_hills/miner, +/turf/floor/dirt, +/area/shaded_hills/outside) +"Zf" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/caves/unexplored/south) +"ZV" = ( +/turf/wall/log/walnut, +/area/shaded_hills/outside) + +(1,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(2,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(3,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(4,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(5,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(6,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(7,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(8,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(9,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +kZ +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(10,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +Yv +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(11,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +qy +qy +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +qy +qy +UV +UV +EV +UV +UV +UV +EV +EV +EV +EV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(12,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +UV +UV +UV +EV +EV +EV +EV +EV +UV +UV +UV +UV +qy +qy +UV +qy +qy +UV +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +UV +qy +qy +qy +qy +qy +qy +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +UV +UV +EV +EV +EV +EV +EV +EV +UV +qy +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(13,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +EV +EV +EV +EV +UV +UV +UV +EV +EV +EV +EV +UV +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +EV +EV +EV +EV +qy +UV +UV +qy +qy +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +UV +UV +EV +EV +EV +UV +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(14,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +UV +UV +UV +UV +UV +qy +qy +UV +UV +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +UV +qy +qy +qy +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +UV +UV +UV +qy +qy +UV +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +EV +EV +qy +qy +qy +qy +qy +UV +UV +qy +UV +UV +qy +UV +qy +qy +UV +UV +qy +qy +qy +qy +UV +UV +EV +EV +EV +UV +UV +UV +qy +qy +qy +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(15,1,1) = {" +mZ +mZ +mZ +mZ +mZ +mZ +mZ +UV +UV +UV +LF +LF +LF +LF +LF +LF +LF +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +UV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +qy +qy +qy +UV +UV +qy +qy +UV +qy +qy +qy +qy +qy +UV +UV +qy +qy +UV +UV +qy +qy +qy +qy +qy +UV +UV +UV +qy +UV +UV +UV +qy +qy +qy +UV +UV +qy +qy +UV +UV +UV +qy +qy +qy +qy +qy +qy +UV +EV +EV +EV +EV +UV +UV +UV +qy +qy +qy +qy +UV +UV +UV +qy +qy +UV +qy +qy +UV +UV +UV +UV +qy +qy +qy +UV +UV +UV +EV +EV +EV +UV +UV +UV +qy +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(16,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +UV +qy +qy +qy +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +UV +UV +UV +EV +EV +EV +EV +UV +UV +UV +UV +UV +UV +UV +UV +qy +UV +UV +qy +qy +qy +UV +UV +UV +qy +qy +qy +UV +qy +qy +UV +qy +UV +qy +qy +qy +qy +UV +UV +UV +EV +EV +qy +UV +qy +UV +qy +qy +qy +qy +UV +qy +qy +qy +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +UV +DX +DX +DX +DX +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +UV +qy +UV +UV +lU +lU +UV +UV +UV +UV +UV +lU +UV +UV +UV +EV +EV +EV +UV +UV +qy +qy +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(17,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +qy +qy +qy +qy +qy +qy +UV +qy +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +EV +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +UV +qy +qy +UV +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +UV +UV +qy +qy +qy +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +DX +DX +DX +DX +DX +DX +DX +DX +DX +UV +UV +qy +qy +UV +UV +UV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +UV +UV +UV +EV +EV +UV +UV +UV +qy +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(18,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +qy +qy +qy +qy +qy +qy +UV +qy +qy +qy +UV +UV +UV +UV +UV +UV +qy +qy +qy +UV +UV +qy +UV +UV +UV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +UV +UV +UV +UV +EV +EV +EV +EV +EV +UV +UV +UV +UV +UV +EV +EV +UV +UV +UV +UV +EV +EV +EV +EV +EV +EV +UV +lU +UV +lU +UV +UV +UV +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +DX +DX +DX +lU +UV +UV +UV +UV +UV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +UV +UV +UV +EV +EV +EV +UV +UV +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(19,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +qy +qy +qy +qy +qy +qy +UV +UV +qy +qy +qy +qy +UV +qy +qy +qy +qy +UV +UV +UV +UV +UV +qy +qy +qy +UV +UV +qy +UV +UV +qy +qy +qy +qy +qy +qy +UV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +EV +EV +EV +EV +EV +EV +UV +UV +UV +qy +UV +lU +lU +UV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +DX +DX +DX +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +UV +UV +UV +EV +EV +EV +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(20,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +qy +qy +qy +qy +qy +UV +UV +UV +qy +qy +qy +UV +UV +UV +UV +qy +UV +UV +qy +qy +qy +qy +UV +UV +UV +UV +qy +qy +qy +UV +UV +qy +qy +qy +qy +qy +qy +UV +UV +UV +UV +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +UV +UV +UV +UV +UV +qy +UV +qy +UV +UV +lU +lU +UV +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +eR +DX +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +UV +UV +EV +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(21,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +qy +qy +qy +qy +UV +UV +LF +LF +UV +UV +UV +LF +LF +LF +LF +UV +UV +UV +UV +qy +qy +qy +UV +UV +UV +UV +qy +qy +qy +qy +UV +UV +qy +qy +qy +UV +ma +ma +ma +ma +ma +ma +ma +UV +UV +UV +UV +UV +qy +qy +qy +qy +qy +UV +UV +qy +UV +UV +qy +qy +qy +UV +UV +UV +UV +lU +lU +lU +lU +lU +UV +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +eR +eR +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +UV +UV +mZ +mZ +mZ +mZ +mZ +mZ +mZ +"} +(22,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +UV +UV +UV +UV +LF +LF +LF +LF +LF +UV +UV +LF +LF +LF +LF +LF +LF +LF +UV +UV +UV +UV +UV +qy +UV +UV +UV +UV +qy +UV +UV +qy +UV +UV +ma +ma +ma +LF +LF +ma +ma +ma +ma +ma +ma +ma +ma +ma +UV +qy +qy +UV +lU +lU +lU +lU +lU +UV +UV +qy +UV +UV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +lU +eR +eR +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(23,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +UV +LF +LF +LF +LF +LF +LF +LF +LF +UV +UV +UV +qy +qy +UV +qy +qy +UV +UV +UV +qy +qy +qy +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +ma +ma +UV +UV +UV +lU +lU +lU +lU +lU +lU +UV +UV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +jj +eR +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +lU +lU +lU +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(24,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +LF +LF +LF +LF +LF +LF +LF +LF +UV +UV +qy +qy +qy +UV +UV +qy +qy +qy +qy +qy +qy +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +jj +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +lU +lU +lU +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(25,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +UV +LF +LF +LF +LF +LF +LF +LF +UV +qy +qy +qy +qy +qy +UV +UV +qy +qy +ma +ma +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +HA +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +eR +eR +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +lU +lU +lU +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(26,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +qy +qy +qy +qy +qy +UV +UV +ma +ma +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +eR +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +lU +lU +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(27,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +UV +UV +qy +qy +qy +qy +ma +ma +ma +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +DX +DX +eR +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +lU +lU +lU +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(28,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +tp +LF +LF +LF +LF +LF +LF +LF +qy +UV +LF +LF +LF +LF +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +DX +eR +eR +eR +lU +lU +lU +DX +DX +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(29,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +tp +tp +tp +LF +LF +LF +LF +LF +LF +UV +UV +LF +LF +LF +tp +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +DX +eR +lU +lU +DX +DX +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(30,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +UV +UV +UV +LF +LF +LF +tp +tp +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +Zf +Zf +Zf +Zf +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +eR +eR +lU +DX +DX +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(31,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Zf +Zf +Zf +Zf +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +eR +eR +eR +DX +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(32,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Zf +Zf +Zf +Zf +Zf +Zf +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +eR +eR +DX +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(33,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Qx +Qx +Zf +Zf +Zf +Zf +Zf +Zf +Zf +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +eR +DX +DX +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(34,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Zf +Qx +Qx +Qx +Zf +Zf +Zf +Zf +Zf +Zf +Zf +te +te +te +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +eR +eR +DX +lU +lU +lU +lU +lU +te +eR +eR +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(35,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Qx +Qx +Qx +Qx +Qx +Zf +Zf +Zf +Zf +Zf +Zf +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +eR +DX +lU +lU +lU +lU +lU +eR +eR +jj +jj +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(36,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +HA +HA +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Zf +Qx +Qx +Qx +Qx +Qx +Zf +Zf +Zf +Zf +Zf +Zf +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +eR +eR +DX +lU +lU +eR +eR +eR +te +te +jj +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(37,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Zf +Qx +Qx +lU +lU +lU +lU +Zf +Zf +Zf +Zf +Zf +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +eR +eR +eR +eR +jj +jj +jj +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(38,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +Zf +Zf +Zf +lU +lU +lU +lU +lU +lU +Zf +Zf +Zf +eR +jj +jj +eR +eR +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +lU +lU +lU +lU +DX +eR +eR +jj +jj +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(39,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +HA +HA +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +Zf +lU +lU +lU +lU +lU +lU +lU +Zf +Zf +Zf +lU +lU +lU +eR +eR +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +lU +lU +lU +lU +DX +DX +DX +eR +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(40,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +ma +ma +HA +HA +HA +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +eR +eR +eR +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(41,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +ma +ma +HA +HA +HA +HA +HA +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +lU +lU +eR +eR +eR +eR +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +eR +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(42,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +ma +ma +HA +HA +HA +HA +KQ +KQ +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +jj +lU +lU +lU +lU +jj +eR +eR +eR +eR +lU +DX +DX +DX +lU +lU +lU +lU +lU +DX +DX +eR +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(43,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +HA +HA +HA +HA +KQ +KQ +KQ +KQ +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +jj +eR +lU +lU +lU +lU +lU +jj +eR +eR +eR +eR +DX +DX +DX +DX +DX +DX +DX +DX +eR +eR +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(44,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +HA +HA +HA +KQ +KQ +KQ +KQ +KQ +KQ +lU +lU +te +te +te +te +te +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +eR +lU +lU +lU +lU +lU +lU +lU +lU +jj +eR +eR +DX +DX +DX +DX +DX +eR +eR +eR +jj +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(45,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +HA +HA +HA +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +te +te +te +te +te +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +te +te +eR +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +eR +eR +eR +eR +eR +eR +eR +eR +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(46,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +HA +HA +KQ +KQ +KQ +KQ +Ft +KQ +KQ +KQ +KQ +HA +HA +HA +te +te +te +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +jj +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +eR +eR +eR +DX +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +lU +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(47,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +ma +HA +HA +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +HA +HA +ma +ma +ma +HA +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +eR +jj +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +DX +eR +eR +DX +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(48,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +ma +ma +ma +ma +HA +HA +HA +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +ma +ma +ma +ma +ma +ma +HA +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +DX +eR +eR +DX +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(49,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +ma +ma +HA +HA +HA +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +HA +ma +lU +lU +lU +ma +ma +ma +HA +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +lU +DX +eR +eR +eR +DX +DX +DX +lU +lU +lU +lU +lU +lU +lU +lU +DX +lU +lU +lU +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(50,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +ma +HA +HA +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +HA +ma +ma +lU +lU +lU +lU +ma +ma +HA +HA +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +eR +jj +eR +eR +DX +DX +DX +DX +lU +lU +lU +lU +lU +lU +DX +lU +lU +lU +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(51,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +ma +ma +ma +ma +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +KQ +KQ +KQ +LF +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +ma +ma +ma +lU +lU +lU +lU +lU +ma +ma +HA +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +jj +eR +eR +eR +DX +DX +Gt +lU +lU +lU +lU +DX +DX +lU +lU +lU +lU +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(52,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +HA +HA +HA +HA +HA +ma +ma +ma +ma +ma +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +HA +HA +LF +LF +LF +KQ +KQ +KQ +KQ +KQ +KQ +KQ +KQ +HA +HA +ma +ma +lU +lU +lU +lU +lU +lU +lU +ma +HA +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +eR +eR +eR +Gt +Ku +Ku +lU +DX +DX +lU +lU +lU +lU +lU +lU +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(53,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +KQ +KQ +KQ +KQ +HA +HA +HA +HA +HA +HA +HA +HA +HA +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HA +HA +HA +HA +LF +LF +LF +LF +LF +KQ +KQ +KQ +KQ +KQ +KQ +HA +HA +ma +ma +ma +ma +lU +lU +lU +lU +lU +lU +ma +HA +HA +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +jj +eR +Gt +Gt +Gt +Gt +DX +DX +sS +lU +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(54,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +KQ +KQ +KQ +KQ +KQ +KQ +LF +LF +LF +LF +LF +LF +KQ +HA +HA +LF +LF +LF +LF +LF +LF +LF +LF +LF +HA +HA +ma +ma +LF +LF +LF +LF +LF +LF +KQ +KQ +KQ +HA +HA +HA +HA +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +ma +ma +HA +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +jj +eR +Gt +pU +se +DX +DX +sS +sS +sS +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(55,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +KQ +KQ +KQ +KQ +KQ +KQ +KQ +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +KQ +LF +LF +LF +LF +LF +LF +LF +LF +HA +HA +ma +ma +LF +LF +LF +LF +LF +LF +LF +KQ +HA +HA +HA +ma +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +ma +ma +HA +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +fH +eR +eR +Gt +DX +DX +WH +sS +sS +sS +gQ +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(56,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +KQ +KQ +KQ +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +LF +LF +LF +LF +LF +LF +HA +HA +ma +ma +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +HA +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +ma +ma +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +jj +eR +DX +DX +DX +sS +sS +sS +sS +gQ +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(57,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +tp +tp +KQ +KQ +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +KQ +LF +LF +LF +HA +HA +ma +ma +tp +LF +LF +LF +LF +LF +LF +LF +KQ +HA +HA +ma +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +ma +ma +ma +lU +lU +lU +lU +lU +lU +ma +ma +ma +ma +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +jj +eR +DX +DX +DX +sS +sS +sS +gQ +gQ +gQ +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(58,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +tp +tp +KQ +KQ +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +KQ +HA +HA +HA +ma +ma +ma +tp +LF +LF +LF +LF +LF +LF +nd +EP +HA +HA +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +ma +ma +ma +ma +lU +lU +lU +HA +ma +ma +HA +HA +HA +HA +ma +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +eR +eR +DX +DX +DX +sS +sS +sS +gQ +gQ +gQ +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(59,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +tp +KQ +KQ +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HA +HA +HA +HA +HA +ma +ma +ma +tp +LF +LF +LF +LF +LF +LF +nd +EP +EP +VO +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +ma +ma +ma +ma +ma +ma +HA +HA +HA +te +te +te +HA +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +eR +DX +DX +DX +DX +sS +sS +sS +gQ +gQ +gQ +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(60,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +tp +KQ +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +ma +ma +ma +ma +ma +tp +tp +LF +LF +LF +LF +LF +LF +nd +EP +VO +VO +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +lU +lU +lU +lU +lU +lU +lU +ma +ma +ma +ma +ma +ma +te +te +te +te +te +te +HA +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +eR +DX +DX +CO +DX +sS +sS +sS +gQ +gQ +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(61,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +tp +KQ +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +nd +EP +VO +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +ma +ma +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +DX +DX +DX +DX +sS +sS +sS +gQ +gQ +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(62,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +tp +KQ +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +LF +LF +LF +LF +LF +EP +nd +EP +DX +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +ma +ma +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +DX +DX +DX +DX +DX +sS +sS +sS +gQ +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(63,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +KQ +KQ +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +LF +LF +LF +LF +LF +EP +nd +EP +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +HA +ma +HA +HA +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +DX +DX +sS +sS +sS +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(64,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +KQ +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +LF +LF +LF +VO +EP +nd +EP +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +lU +DX +DX +DX +sS +lU +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(65,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +LF +LF +LF +VO +EP +nd +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +lU +lU +DX +DX +DX +lU +lU +lU +lU +lU +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(66,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +VO +EP +nd +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +lU +lU +lU +eR +DX +DX +lU +lU +lU +lU +lU +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(67,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +VO +EP +nd +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +DX +DX +lU +lU +lU +lU +lU +eR +eR +lU +lU +lU +lU +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(68,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +EP +EP +nd +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +eR +eR +lU +lU +DX +DX +DX +lU +lU +lU +lU +lU +DX +eR +eR +DX +lU +lU +lU +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(69,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +VO +EP +EP +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +te +DX +eR +eR +eR +eR +eR +eR +eR +DX +DX +lU +lU +lU +lU +lU +lU +DX +eR +eR +DX +te +lU +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(70,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +VO +VO +EP +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +te +te +te +eR +eR +eR +DX +DX +DX +eR +eR +DX +DX +lU +lU +lU +lU +lU +lU +lU +DX +eR +eR +DX +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(71,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +VO +VO +EP +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +eR +lU +lU +lU +lU +DX +DX +DX +DX +DX +lU +lU +lU +lU +lU +lU +lU +DX +eR +eR +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(72,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +VO +VO +EP +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +jj +eR +lU +lU +lU +lU +lU +lU +DX +DX +lU +lU +lU +lU +lU +lU +lU +lU +DX +eR +eR +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(73,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +VO +VO +EP +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +jj +eR +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +eR +eR +DX +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(74,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +VO +VO +VO +VO +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +jj +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +DX +DX +eR +eR +DX +te +lU +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(75,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +EP +VO +xr +Kd +VO +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +jj +eR +te +te +lU +lU +lU +lU +lU +te +te +lU +lU +lU +lU +lU +lU +DX +DX +eR +eR +eR +lU +lU +lU +lU +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(76,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +VO +Kd +xr +xr +VO +EP +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +DX +eR +eR +eR +DX +lU +lU +lU +lU +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(77,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +EP +VO +xr +lE +xr +xr +xr +xr +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +DX +eR +eR +DX +lU +lU +lU +lU +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(78,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +xr +xr +Kd +xr +lE +xr +xr +xr +xr +HV +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +DX +DX +eR +eR +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(79,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +xr +Kd +Kd +xr +lE +xr +xr +xr +xr +HV +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +DX +eR +eR +jj +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(80,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +xr +Kd +Kd +xr +xr +xr +xr +xr +xr +xr +HV +HV +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +DX +eR +eR +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(81,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +xr +Kd +xr +xr +xr +lE +lE +HV +lE +xr +xr +HV +HV +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +DX +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(82,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +xr +xr +xr +xr +HV +xr +lE +lE +lE +xr +xr +xr +xr +HV +HV +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +DX +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(83,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HV +xr +xr +lE +lE +lE +lE +lE +lE +lE +xr +lE +xr +xr +HV +HV +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +DX +eR +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(84,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HV +HV +xr +xr +xr +OL +OL +OL +OL +OL +lE +xr +xr +xr +xr +xr +HV +HV +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +DX +eR +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(85,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HV +HV +HV +xr +xr +lE +OL +OL +OL +OL +OL +OL +lE +xr +xr +xr +xr +xr +xr +HV +HV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +DX +eR +eR +lU +lU +lU +lU +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(86,1,1) = {" +Yf +Yf +Yf +Yf +Yf +Yf +Yf +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +Fv +Fv +Fv +Fv +LF +LF +LF +LF +LF +HV +HV +HV +HV +lE +xr +OL +OL +OL +OL +OL +OL +OL +OL +lE +xr +lE +xr +xr +xr +xr +HV +HV +HV +HV +HV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +lU +lU +lU +lU +lU +te +te +te +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +DX +DX +eR +lU +lU +lU +lU +te +te +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(87,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +Fv +LF +Fv +Fv +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HV +HV +HV +Fv +HV +HV +HV +LF +LF +ES +ES +ES +ES +ES +HV +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +xr +xr +xr +xr +xr +xr +xr +xr +xr +HV +HV +HV +Fv +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +eR +DX +DX +DX +eR +lU +lU +lU +lU +lU +te +te +te +te +te +te +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(88,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +HV +HV +HV +HV +HV +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +HV +HV +HV +HV +xr +HV +Fv +HV +xr +HV +HV +HV +ES +EQ +ex +EQ +ES +HV +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +HV +HV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +HV +HV +HV +HV +HV +lU +lU +lU +lU +lU +lU +HV +HV +HV +HV +Fv +Fv +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +xr +lE +lE +lE +lE +lE +xr +lU +lU +lU +lU +lU +te +te +te +te +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(89,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +xr +HV +xr +xr +HV +HV +LF +LF +LF +LF +LF +LF +HV +HV +HV +HV +HV +xr +HV +xr +xr +HV +HV +HV +xr +xr +HV +HV +ES +el +el +el +ES +HV +OL +OL +OL +OL +xe +xe +OL +OL +OL +OL +OL +OL +xe +OL +OL +xr +xr +xr +xr +xr +xr +xr +xr +HV +HV +HV +lU +lU +lU +lU +lU +Fv +Fv +Fv +Fv +Fv +Fv +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +HV +HV +HV +HV +HV +xr +HV +xr +HV +HV +HV +HV +Fv +HV +HV +HV +xr +xr +HV +HV +HV +HV +lE +lU +lU +lU +lU +lU +HV +HV +HV +HV +xr +xr +lE +Xt +lE +Xt +lE +lE +HV +HV +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(90,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +xr +xr +xr +xr +HV +HV +HV +LF +LF +HV +HV +HV +HV +xr +xr +xr +xr +xr +HV +HV +HV +xr +HV +ES +HV +HV +HV +HV +el +kr +el +HV +HV +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +xr +xr +xr +xr +xr +xr +xr +HV +HV +HV +HV +lU +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +lU +lU +lU +lU +lU +lU +HV +HV +HV +HV +xr +xr +xr +HV +xr +xr +xr +xr +xr +xr +HV +HV +HV +xr +xr +xr +HV +HV +HV +xr +xr +lE +lE +lE +HV +HV +HV +HV +xr +xr +xr +xr +lE +lE +lE +HV +HV +lE +lE +lE +HV +HV +HV +lU +lU +lU +lU +lU +lU +lU +lU +lU +TH +TH +TH +TH +TH +TH +TH +"} +(91,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +lE +xr +xr +xr +xr +HV +HV +HV +HV +xr +xr +xr +xr +xr +xr +HV +HV +Fv +HV +Fv +Fv +FK +eL +el +HV +HV +HV +HV +ES +HV +HV +HV +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +xr +xr +xr +xr +xr +xr +xr +HV +HV +HV +HV +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +HV +HV +xr +Fv +HV +HV +HV +HV +HV +HV +xr +xr +xr +xr +xr +xr +xr +xr +xr +HV +xr +xr +xr +xr +xr +lE +lE +lE +xr +xr +xr +xr +xr +lE +Xt +lE +xr +xr +xr +xr +xr +xr +HV +lE +lE +lE +lE +lE +lE +lE +lE +lE +xr +HV +Fv +Fv +lU +lU +lU +lU +HV +HV +HV +HV +kz +kz +kz +kz +kz +kz +kz +"} +(92,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +xr +lE +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +lE +lE +xr +HV +HV +HV +Fv +Fv +ES +Ed +EL +el +ES +HV +mX +HV +HV +HV +HV +wW +OL +OL +OL +OL +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +xr +xr +xr +xr +xr +xr +xr +xr +HV +HV +Fv +Fv +Fv +Fv +Fv +Fv +Fv +HV +HV +xr +HV +HV +HV +xr +HV +HV +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +HV +lE +lE +Xt +lE +xr +xr +HV +xr +xr +lE +Xt +lE +xr +HV +HV +xr +xr +lE +lE +lE +lE +lE +lE +lE +lE +lE +xr +HV +HV +Fv +Fv +Fv +Fv +Fv +HV +HV +HV +xr +HV +xr +kz +kz +kz +kz +kz +kz +kz +"} +(93,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +xr +lE +xr +xr +lE +lE +lE +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +HV +Fv +Fv +Fv +Fv +Fv +el +el +el +HV +HV +HV +HV +HV +HV +HV +OL +OL +OL +OL +UE +UE +UE +UE +OL +OL +OL +OL +xe +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +xr +xr +xr +xr +xr +xr +HV +HV +Fv +Fv +Fv +Fv +Fv +HV +HV +HV +xr +xr +xr +xr +xr +xr +xr +xr +HV +xr +xr +xr +xr +HV +xr +xr +xr +xr +xr +xr +lE +xr +xr +xr +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +xr +xr +xr +xr +xr +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +xr +HV +HV +HV +Fv +Fv +Fv +HV +HV +xr +xr +xr +xr +xr +kz +kz +kz +kz +kz +kz +kz +"} +(94,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +OL +xe +xe +OL +OL +OL +lE +xr +xr +lE +xr +lE +xr +xr +HV +HV +HV +Fv +Fv +js +Jv +Fv +ES +HV +HV +mG +HV +iP +HV +HV +wW +OL +OL +OL +UE +UE +UE +UE +UE +OL +OL +OL +xe +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +xr +xr +lE +xr +HV +HV +Fv +Fv +Fv +Fv +Fv +HV +HV +xr +xr +xr +xr +xr +xr +xr +xr +HV +xr +xr +xr +xr +lE +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +lE +lE +Xt +Xt +lE +lE +xr +xr +xr +xr +xr +lE +lE +lE +lE +Xt +lE +lE +lE +lE +lE +lE +xr +xr +xr +HV +HV +HV +Fv +HV +xr +xr +xr +xr +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(95,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +xr +HV +Fv +HV +Fv +Fv +Fv +Fv +oo +Fv +Fv +HV +HV +HV +HV +HV +HV +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +xe +OL +OL +OL +UE +UE +OL +OL +OL +OL +OL +OL +lE +lE +xr +xr +HV +HV +Fv +Fv +Fv +HV +HV +xr +xr +xr +xr +xr +xe +xe +xr +xr +xr +lE +lE +lE +lE +lE +xr +xr +lE +lE +xr +xr +xe +xe +OL +OL +xe +OL +xr +xr +xr +lE +lE +lE +lE +xr +xr +xr +lE +lE +lE +lE +lE +lE +lE +Xt +lE +lE +lE +lE +lE +xr +xr +xr +HV +HV +xr +HV +HV +HV +xr +xr +lE +lE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(96,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +xr +HV +HV +HV +HV +Fv +Fv +OP +Fv +Fv +Fv +HV +HV +YB +xr +cy +lE +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +OL +OL +OL +OL +OL +OL +OL +xe +xe +xr +xr +HV +Fv +Fv +HV +HV +xr +xr +xr +xr +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +lE +OL +OL +OL +xe +OL +OL +OL +xe +xe +xe +xe +xe +xe +xe +xe +xe +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +lE +lE +lE +lE +lE +lE +xr +xr +xr +HV +HV +HV +HV +HV +HV +xr +xr +lE +lE +lE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(97,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +xr +xr +xr +xr +HV +HV +xr +HV +Fv +Fv +Fv +HV +Fv +HV +xr +xr +lE +lE +OL +OL +UE +UE +UE +UE +xe +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +xe +xe +xe +wW +wW +UI +wW +wW +xe +xe +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +Xt +Xt +Xt +xr +Xt +lE +lE +lE +lE +xr +xr +xr +HV +HV +HV +Fv +Fv +Fv +HV +xr +xr +lE +lE +lE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(98,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +xr +lE +xr +xr +HV +HV +HV +Fv +Fv +Fv +HV +HV +HV +xr +lE +lE +lE +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +UE +UE +UE +OL +OL +xe +xe +xe +xe +wW +wW +wW +xe +xe +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +OL +OL +OL +lE +lE +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +xr +HV +HV +HV +Fv +Fv +Fv +Fv +Fv +HV +HV +xr +lE +lE +lE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(99,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +OL +OL +OL +OL +OL +OL +UE +UE +OL +OL +OL +OL +OL +lE +lE +lE +lE +xr +xr +HV +HV +HV +Fv +Fv +HV +HV +xr +xr +lE +lE +lE +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +xe +xe +xe +xe +xe +xe +xe +xe +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +OL +OL +UE +UE +OL +OL +UE +UE +UE +OL +OL +OL +OL +UE +UE +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +OL +lE +lE +Xt +lE +lE +lE +lE +lE +xr +HV +HV +Fv +Fv +Fv +Fv +Fv +Fv +HV +HV +xr +lE +lE +Xt +lE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(100,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +OL +OL +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +lE +lE +xr +lE +lE +xr +HV +HV +HV +HV +Fv +HV +xr +xr +xr +lE +lE +lE +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +xe +OL +xe +xe +xe +xe +OL +OL +OL +OL +OL +OL +UE +UE +UE +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +lE +lE +lE +lE +lE +lE +xr +HV +Fv +Fv +Fv +Fv +Fv +Fv +Fv +HV +HV +lE +lE +lE +Xt +Xt +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(101,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +lE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +lE +lE +xr +lE +lE +xr +xr +HV +HV +HV +HV +HV +xr +xr +xr +xr +lE +lE +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +xr +lE +lE +lE +lE +lE +lE +lE +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +lE +lE +lE +lE +xr +xr +HV +Fv +Fv +HV +HV +HV +Fv +HV +HV +xr +lE +lE +Xt +Xt +Xt +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(102,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +Xt +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +lE +lE +lE +lE +lE +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +OL +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +UE +UE +UE +UE +UE +UE +Xt +lE +lE +xr +lE +lE +lE +lE +lE +lE +lE +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +lE +lE +lE +xr +xr +HV +HV +HV +HV +xr +HV +HV +HV +xr +xr +lE +lE +Xt +Xt +Xt +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(103,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +UE +UE +OL +OL +OL +lE +lE +xr +xr +lE +lE +lE +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +xr +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +UE +UE +UE +Xt +Xt +Xt +lE +xr +lE +ES +ES +ES +bJ +ES +ES +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +lE +lE +xr +xr +xr +HV +HV +xr +HV +xr +xr +xr +lE +lE +OL +UE +UE +UE +Xt +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(104,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +Sm +Sm +Sm +Sm +Sm +Xt +Xt +Xt +Xt +Xt +Xt +Xt +OL +OL +OL +OL +lE +lE +lE +lE +xr +xr +lE +xr +Sm +Sm +Sm +Sm +Sm +xr +Sm +Sm +Xt +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +xr +xr +Sm +xr +Sm +Sm +Sm +Sm +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +xr +lE +lE +ul +LX +LX +bJ +ES +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +lE +lE +lE +xr +xr +xr +xr +xr +lE +lE +lE +OL +OL +OL +UE +UE +UE +UE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(105,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +xr +kq +kq +kq +kq +Sm +Sm +Sm +Xt +Xt +Xt +Xt +Xt +xe +xe +xe +xe +lE +lE +lE +Sm +Sm +xr +kq +kq +kq +kq +Sm +Sm +xr +Xt +Xt +xr +Ng +Ng +Ng +xe +xr +Xt +xr +Sm +Sm +Sm +Sm +kq +kq +kq +kq +kq +kq +kq +kq +xr +Sm +Sm +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +lE +xr +lE +ZV +xC +xC +bJ +MH +MH +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +lE +lE +lE +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(106,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +Sm +xr +Sm +Sm +xr +xr +kq +kq +Sm +Xt +xr +xr +Sm +Sm +Ng +Ng +Ng +xr +Sm +Sm +kq +Sm +Sm +Sm +Sm +Sm +Sm +Sm +xr +Sm +Xt +xr +ee +ee +ee +xe +Xt +Xt +kq +kq +kq +kq +kq +Sm +Sm +xr +Sm +Sm +Sm +xr +xr +xr +xr +xr +kq +kq +Sm +Sm +xr +Sm +Xt +Xt +Xt +Xt +xr +xr +ES +xC +xC +bJ +TD +bJ +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(107,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +Xt +Xt +Xt +Xt +Sm +Sm +xr +Sm +xr +kq +kq +kq +kq +ee +ee +ee +kq +Sm +Sm +Sm +xr +xr +lE +xr +xr +xr +lE +Xt +Xt +Ng +Ng +Ng +Ng +xe +Xt +Sm +Sm +Sm +Sm +xr +Sm +Sm +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +xr +Sm +kq +kq +kq +xr +xr +Xt +Xt +Xt +lE +xr +ul +LX +ul +bJ +TD +ES +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(108,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Sm +xr +Xt +Sm +Sm +Sm +Xt +Ng +Ng +Ng +Ng +xr +xr +xr +lE +lE +lE +lE +lE +lE +Xt +Xt +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +UE +UE +UE +UE +Xt +Xt +Xt +xr +Sm +Sm +Sm +Sm +xr +xr +Xt +Xt +lE +xC +nl +ul +ul +ul +bJ +ES +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(109,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +Xt +Xt +UE +UE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +UE +xe +xe +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +xr +xr +kq +xr +xr +Xt +xr +xr +ES +WO +ul +xC +lE +ES +Xt +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +UE +UE +UE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(110,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +Xt +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +OL +OL +OL +lE +lE +lE +lE +lE +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Sm +Sm +Sm +xr +xr +lE +ES +bJ +ul +xC +LX +ES +Xt +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +lE +kz +kz +kz +kz +kz +kz +kz +"} +(111,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +lE +UE +UE +UE +UE +UE +UE +OL +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +xr +kq +Sm +xr +lE +ES +bJ +LX +ul +LX +ES +lE +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(112,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +lE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Sm +kq +Sm +xr +ES +xC +bJ +LX +bJ +ES +lE +lE +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(113,1,1) = {" +kz +kz +kz +kz +kz +kz +kz +lE +lE +lE +lE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +xr +yA +Sm +xr +lE +lE +ES +ES +ES +ES +lE +lE +lE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +lE +lE +lE +kz +kz +kz +kz +kz +kz +kz +"} +(114,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +lE +lE +lE +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Sm +kq +kq +xr +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +UE +Xt +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +OL +Xt +Xt +Xt +lE +lE +lE +lE +lE +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(115,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +lE +lE +lE +UE +UE +xe +UE +UE +UE +UE +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +OL +OL +UE +UE +UE +UE +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +xr +Xt +xr +Sm +Sm +kq +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +Xt +Xt +lE +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(116,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +UE +UE +UE +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +OL +OL +OL +OL +OL +OL +OL +UE +Xt +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +xr +lE +PO +PO +PO +xr +Sm +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +xr +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +UE +UE +UE +Xt +Xt +Xt +Xt +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(117,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +UE +UE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +Xt +Xt +lE +lE +PO +lE +TD +aX +PO +xr +Sm +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +OL +OL +OL +OL +OL +OL +OL +OL +UE +UE +Xt +Xt +Xt +Xt +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(118,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Ic +TR +TR +TR +TR +TR +TR +TR +TR +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +OL +OL +OL +OL +OL +OL +OL +OL +OL +OL +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +PO +aX +aX +aX +Fg +xr +Sm +lE +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +fO +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +lC +lC +lC +lC +lC +lC +lC +"} +(119,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +OL +OL +OL +OL +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +PO +MK +Sm +aX +PO +lE +kq +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +lC +lC +lC +lC +lC +lC +lC +"} +(120,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +PO +PO +PO +PO +lE +xr +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +zp +zp +lC +lC +lC +lC +lC +lC +lC +"} +(121,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lE +lE +lE +lE +lE +lE +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +fO +TR +TR +TR +Ic +TR +TR +TR +TR +TR +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +zp +zp +zp +Ic +Ic +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +lE +lE +lE +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +TR +TR +Ic +zp +zp +zp +zp +Gh +lC +lC +lC +lC +lC +lC +lC +"} +(122,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Gh +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +Xd +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +Ic +Ic +zp +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +Ic +Ic +zp +zp +Gh +Gh +Gh +Gh +lC +lC +lC +lC +lC +lC +lC +"} +(123,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +Ic +TR +TR +TR +Ic +Ic +vX +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +zp +zp +Gh +Gh +Gh +Gh +Gh +lC +lC +lC +lC +lC +lC +lC +"} +(124,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +Ic +TR +TR +Xd +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +Ic +TR +TR +Ic +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +lC +lC +lC +lC +lC +lC +lC +"} +(125,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +TR +Hn +TR +Xd +vX +Xd +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +Ic +hT +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +lC +lC +lC +lC +lC +lC +lC +"} +(126,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +My +My +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +Ic +TR +TR +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Xd +vX +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +qj +lC +lC +lC +lC +lC +lC +lC +"} +(127,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +qj +qj +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +My +My +qj +qj +qj +qj +qj +qj +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Xd +vX +Xd +Gh +Gh +Gh +Gh +My +My +My +My +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +zp +zp +zp +zp +zp +zp +zp +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +qj +qj +qj +lC +lC +lC +lC +lC +lC +lC +"} +(128,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +qj +qj +qj +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +JN +Xd +vX +Xd +JN +My +My +My +qj +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +My +My +Gh +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +zp +zp +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +My +qj +qj +qj +lC +lC +lC +lC +lC +lC +lC +"} +(129,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +qj +qj +qj +qj +qj +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Xd +vX +Xd +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +My +Gh +Gh +Gh +Ic +zp +zp +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +lC +lC +lC +lC +lC +lC +lC +"} +(130,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +My +qj +qj +qj +qj +qj +qj +My +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Gh +Gh +Gh +My +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +My +My +My +My +My +My +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +My +My +My +Xd +vX +Xd +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +Gh +Gh +Gh +Gh +Ic +zp +zp +zp +Gh +Gh +My +My +My +My +My +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +lC +lC +lC +lC +lC +lC +lC +"} +(131,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +Gh +Gh +Gh +My +My +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Gh +Gh +My +My +qj +qj +qj +qj +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +EE +EE +Xd +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +Gh +Gh +Gh +Ic +Ic +zp +zp +zp +Gh +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +Gh +lC +lC +lC +lC +lC +lC +lC +"} +(132,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Gh +Gh +My +My +My +My +My +My +My +qj +qj +qj +qj +qj +qj +qj +My +My +My +qj +qj +My +Gh +Gh +Gh +Ic +Ic +Ic +Gh +Gh +Gh +Gh +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +qj +qj +qj +qj +qj +qj +qj +qj +JN +EE +EE +EE +JN +qj +qj +My +My +My +qj +qj +qj +My +My +qj +qj +qj +qj +qj +qj +qj +qj +qj +My +Gh +My +My +My +My +My +My +My +My +My +My +My +My +My +My +Gh +Gh +Gh +Ic +Ic +zp +zp +zp +Gh +Gh +My +qj +qj +qj +qj +qj +qj +qj +qj +My +My +My +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +lC +lC +lC +lC +lC +lC +lC +"} +(133,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +qj +qj +qj +qj +qj +qj +qj +qj +My +Gh +Gh +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +zp +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +qj +qj +qj +qj +qj +EE +vX +EE +qj +My +My +Gh +Gh +Gh +My +My +My +Gh +Gh +My +My +My +My +qj +qj +qj +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +zp +zp +zp +Gh +Gh +Gh +My +My +My +My +My +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +lC +lC +lC +lC +lC +lC +lC +"} +(134,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +My +My +My +My +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +zp +zp +zp +zp +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +My +My +EE +EE +EE +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +My +My +My +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +Ic +Ic +lC +lC +lC +lC +lC +lC +lC +"} +(135,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +EE +EE +EE +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +zp +zp +zp +zp +zp +Ic +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +lC +lC +lC +lC +lC +lC +lC +"} +(136,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +zp +zp +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +Gh +Gh +JN +Xd +EE +EE +JN +Gh +Ic +Ic +Ic +Gh +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +TR +lC +lC +lC +lC +lC +lC +lC +"} +(137,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +Gh +Gh +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Gh +Xd +vX +EE +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +Ic +Ic +Ic +Ic +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +Gh +zp +zp +zp +Ic +Ic +TR +TR +TR +TR +Ic +Ic +Ic +Ic +lC +lC +lC +lC +lC +lC +lC +"} +(138,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Xd +vX +Xd +Ic +Ic +Ic +TR +TR +TR +TR +Ic +TR +TR +TR +Ic +Ic +Ic +TR +TR +TR +Ic +Ic +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +TR +TR +TR +TR +Ic +Ic +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +zp +zp +zp +zp +zp +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +TR +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(139,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +Ic +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +Xd +vX +Xd +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +Ic +Ic +Ic +Ic +zp +zp +zp +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(140,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +Ic +Ic +TR +Ic +TR +TR +TR +TR +TR +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Xd +vX +Xd +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +Ic +Ic +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(141,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +Ic +fO +Xd +vX +Xd +fO +Ic +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(142,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +fO +Xd +vX +Xd +fO +fO +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(143,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +fO +fO +Xd +vX +Xd +fO +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +lC +lC +lC +lC +lC +lC +lC +"} +(144,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(145,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(146,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(147,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(148,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(149,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(150,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} diff --git a/maps/shaded_hills/shaded_hills-inn.dmm b/maps/shaded_hills/shaded_hills-inn.dmm new file mode 100644 index 000000000000..59e1397ce1d1 --- /dev/null +++ b/maps/shaded_hills/shaded_hills-inn.dmm @@ -0,0 +1,24825 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"af" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/turf/floor/carpet/rustic, +/area/shaded_hills/inn) +"ah" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/shrine/kitchen) +"aK" = ( +/obj/abstract/landmark/start/shaded_hills/storekeeper, +/obj/item/stool/rustic, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"aP" = ( +/obj/structure/flora/tree/dead/ebony, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"aU" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"bu" = ( +/obj/structure/table/desk/dresser, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"bv" = ( +/obj/structure/chair/rustic{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"bz" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/general_store) +"bW" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/cooking_vessel/skillet/iron, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"cl" = ( +/obj/structure/table/wood/ebony, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"cq" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/bowl/wood, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"cx" = ( +/turf/wall/brick/basalt{ + unique_merge_identifier = "outer wall" + }, +/area/shaded_hills/outside/downlands) +"cT" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"dr" = ( +/obj/structure/chair/rustic{ + dir = 4; + pixel_x = 16; + pixel_y = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"dx" = ( +/obj/structure/fire_source/kiln/oven, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine/kitchen) +"dC" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"dD" = ( +/obj/item/towel/doormat/flat{ + dir = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"dH" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut/shutter/open, +/area/shaded_hills/general_store) +"dK" = ( +/obj/structure/table/wood/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"dL" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"dN" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"dX" = ( +/obj/structure/chair/rustic_fancy/ebony{ + dir = 1; + pixel_y = 20; + pixel_x = 6 + }, +/turf/floor/carpet, +/area/shaded_hills/inn) +"ev" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"eD" = ( +/obj/structure/working/loom/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"eG" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/trader, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"eM" = ( +/obj/structure/table/end, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10; + start_lit = 1 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"fg" = ( +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/reagent_dispensers/compost_bin/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"fh" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/obj/structure/table/marble, +/obj/item/utensil/spoon/wood, +/obj/item/utensil/spoon/wood, +/obj/item/utensil/spoon/wood, +/obj/item/utensil/spoon/wood, +/obj/item/utensil/spoon/wood, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"ft" = ( +/turf/floor/mud, +/area/shaded_hills/outside/shrine) +"fw" = ( +/turf/wall/brick/basalt/shutter/open, +/area/shaded_hills/slaughterhouse) +"fK" = ( +/obj/structure/cask_rack/large/mapped, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"fM" = ( +/obj/structure/working/bellows, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"fR" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"fS" = ( +/obj/structure/table/marble, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/mug/wood, +/obj/item/chems/glass/handmade/mug/wood, +/obj/item/chems/glass/handmade/mug/wood, +/obj/item/chems/glass/handmade/mug/wood, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/obj/abstract/landmark/organize/horizontal, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"gc" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"ge" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"gg" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/obj/structure/table/wood/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"gn" = ( +/obj/item/flame/candle/handmade, +/obj/structure/table/end, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"gp" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"gt" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"gA" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"gB" = ( +/obj/structure/wall_sconce/lantern{ + start_lit = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"gJ" = ( +/mob/living/simple_animal/passive/horse/small, +/turf/floor/straw, +/area/shaded_hills/stable) +"gL" = ( +/obj/structure/reagent_dispensers/barrel/ebony/oil, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"gR" = ( +/obj/structure/table/marble, +/obj/item/chems/glass/mortar{ + pixel_x = 4; + pixel_y = 4 + }, +/obj/item/rock/basalt{ + pixel_x = -6 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"gU" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/inn/kitchen) +"gW" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"hb" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4; + start_lit = 1 + }, +/turf/floor/carpet, +/area/shaded_hills/inn) +"hc" = ( +/obj/structure/chair/bench/ebony{ + dir = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse/porch) +"hu" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"hE" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/railing/mapped/wooden/walnut, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"hJ" = ( +/obj/item/stool/rustic, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"hU" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"hZ" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"id" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/bottle/beer, +/obj/item/chems/glass/handmade/bottle/beer, +/obj/item/chems/glass/handmade/bottle/beer, +/obj/item/chems/glass/handmade/bottle/beer, +/obj/item/chems/glass/handmade/bottle/beer, +/obj/abstract/landmark/organize/horizontal, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"ij" = ( +/obj/structure/chair/rustic{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"iq" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut/shutter/open, +/area/shaded_hills/inn/kitchen) +"iC" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/obj/abstract/landmark/lock_preset/shaded_hills/trader, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"iH" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/inn_interior, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"iJ" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"iK" = ( +/turf/wall/brick/basalt{ + unique_merge_identifier = "shrine wall" + }, +/area/shaded_hills/outside/shrine) +"iX" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut/shutter/open, +/area/shaded_hills/inn) +"iZ" = ( +/obj/structure/fire_source/fireplace/basalt, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"jf" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"jk" = ( +/obj/structure/chair/bench/pew/mahogany{ + dir = 1 + }, +/obj/abstract/landmark/start/shaded_hills/cleric, +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"js" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"jx" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/carrot, +/obj/item/food/grown/carrot, +/obj/item/food/grown/carrot, +/obj/item/food/grown/cabbage, +/obj/item/food/grown/cabbage, +/obj/item/food/grown/cabbage, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"jA" = ( +/obj/structure/bed/simple/ebony, +/obj/item/bedsheet/furs, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"jI" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"ke" = ( +/obj/item/chems/glass/bucket/wood, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"kv" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"kx" = ( +/obj/structure/banner_frame/wall/ebony/green{ + pixel_y = 32 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"kE" = ( +/obj/structure/door/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"kI" = ( +/obj/structure/chair/bench/pew/ebony{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"ls" = ( +/obj/item/towel/doormat/flat{ + dir = 1 + }, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"ly" = ( +/turf/wall/wattle/daubed/walnut, +/area/shaded_hills/inn) +"lz" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/knife/kitchen/cleaver/bronze, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"lC" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/downlands) +"lD" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"lE" = ( +/obj/abstract/level_data_spawner/shaded_hills_downlands, +/turf/unsimulated/mask, +/area/shaded_hills/outside/downlands) +"lF" = ( +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"lL" = ( +/obj/structure/chair/bench/ebony{ + dir = 1 + }, +/obj/abstract/landmark/start/shaded_hills/farmer, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse/porch) +"me" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/cabbage, +/obj/item/seeds/extracted/cabbage, +/obj/item/seeds/extracted/cabbage, +/obj/item/tool/shovel/wood/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"ml" = ( +/obj/structure/table/wood/ebony, +/obj/item/shears, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -5 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"mD" = ( +/obj/structure/chair/rustic, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"mG" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse/porch) +"mJ" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"mK" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"nn" = ( +/turf/wall/log/walnut, +/area/shaded_hills/stable) +"nx" = ( +/obj/structure/chair/bench/pew/ebony{ + dir = 8 + }, +/obj/structure/railing/mapped/wooden/ebony{ + dir = 4 + }, +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"nJ" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/yellowed, +/turf/floor/carpet/rustic, +/area/shaded_hills/inn) +"nN" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/chems/glass/bucket/wood, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"nS" = ( +/obj/abstract/landmark/lock_preset/shaded_hills/shrine, +/obj/structure/door/mahogany, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"ol" = ( +/obj/structure/railing/mapped/wooden/walnut, +/turf/floor/mud, +/area/shaded_hills/outside/shrine) +"or" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"oL" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut, +/area/shaded_hills/farmhouse) +"oN" = ( +/turf/wall/log/walnut, +/area/shaded_hills/shrine/kitchen) +"oO" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"pd" = ( +/obj/structure/chair/bench/pew/mahogany{ + dir = 1 + }, +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"pi" = ( +/obj/structure/table/wood/ebony, +/obj/item/stack/medical/ointment/crafted/five, +/obj/item/stack/medical/bandage/crafted/five, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"px" = ( +/turf/wall/log/walnut/shutter/open, +/area/shaded_hills/shrine/kitchen) +"qe" = ( +/obj/structure/bed/simple/ebony, +/obj/abstract/landmark/start/shaded_hills/shrine_attendant, +/obj/item/bedsheet/furs, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"qf" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"qG" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/inn) +"qL" = ( +/obj/structure/table/wood/ebony, +/obj/item/ancient_surgery/bonesetter, +/obj/item/ancient_surgery/retractor, +/obj/item/ancient_surgery/sutures, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"qP" = ( +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"qV" = ( +/turf/wall/wattle/daubed/plastered, +/area/shaded_hills/shrine) +"qW" = ( +/obj/structure/town_bell, +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"qY" = ( +/turf/wall/brick/basalt{ + unique_merge_identifier = "outer wall" + }, +/area/shaded_hills/outside/downlands/poi) +"ra" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/mortar, +/obj/item/rock/basalt, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"rc" = ( +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/flora/bush/palebush, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"rg" = ( +/obj/item/paper/scroll, +/obj/item/paper/scroll, +/obj/item/paper/scroll, +/obj/item/paper/scroll, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/turf/floor/carpet, +/area/shaded_hills/inn) +"rp" = ( +/obj/structure/divider/extended/wood/ebony{ + dir = 4; + pixel_x = 16 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"rv" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/bottle, +/obj/item/chems/glass/handmade/bottle/tall, +/obj/item/chems/glass/handmade/bottle/wide, +/obj/abstract/landmark/organize/horizontal, +/obj/item/chems/glass/handmade/bottle/wide/whiskey, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"ry" = ( +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"rC" = ( +/obj/structure/table/marble, +/obj/item/chems/glass/handmade/jar, +/obj/item/chems/glass/handmade/jar, +/obj/item/chems/glass/handmade/jar, +/obj/abstract/landmark/organize/horizontal, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"rO" = ( +/mob/living/simple_animal/fowl/chicken, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"rS" = ( +/obj/structure/wall_sconce/lantern{ + start_lit = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"rY" = ( +/obj/effect/floor_decal/spline/fancy/wood/corner/walnut, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"sl" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/inn_interior, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"sz" = ( +/obj/structure/door/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"sJ" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"sM" = ( +/obj/structure/table/wood/reinforced/ebony, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"th" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/yellowed, +/obj/abstract/landmark/start/shaded_hills/inn_worker, +/turf/floor/carpet/rustic, +/area/shaded_hills/inn) +"tq" = ( +/obj/structure/door/walnut, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"tv" = ( +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 1 + }, +/obj/structure/table/wood/reinforced/ebony, +/obj/item/chems/glass/handmade/cup/wood, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"tF" = ( +/obj/structure/table/marble, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/abstract/landmark/organize/horizontal, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"tH" = ( +/obj/structure/reagent_dispensers/barrel/ebony/wine, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"tS" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/obj/structure/railing/mapped/wooden/walnut, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"tZ" = ( +/obj/structure/chair/rustic{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"uk" = ( +/obj/structure/chair/bench/pew/ebony{ + dir = 8 + }, +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 4 + }, +/obj/structure/railing/mapped/wooden/ebony{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"uu" = ( +/obj/structure/bed/simple/ebony, +/obj/item/bedsheet/furs, +/obj/abstract/landmark/start/shaded_hills/farmer, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"uD" = ( +/turf/wall/wattle/daubed/plastered/framed/mahogany/shutter/open, +/area/shaded_hills/shrine) +"uJ" = ( +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"uK" = ( +/obj/structure/table/marble, +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"uM" = ( +/turf/floor/path/basalt, +/area/shaded_hills/general_store) +"uP" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"vz" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/cooking_vessel/baking_dish/earthenware, +/obj/item/chems/cooking_vessel/baking_dish/earthenware, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"vA" = ( +/obj/structure/table/marble, +/obj/item/food/meatpie, +/obj/item/food/cherrypie, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"wf" = ( +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 1 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"wg" = ( +/obj/structure/table/wood/ebony, +/obj/item/ancient_surgery/bonesaw, +/obj/item/ancient_surgery/forceps, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"wh" = ( +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/general_store) +"wp" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/obj/structure/chair/rustic{ + dir = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"wr" = ( +/turf/wall/wattle/daubed/plastered/framed/mahogany, +/area/shaded_hills/shrine) +"wF" = ( +/obj/structure/banner_frame/sign/store, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"xa" = ( +/obj/item/stack/material/bar/mapped/iron/thirty, +/obj/structure/table/wood/reinforced/ebony, +/obj/item/tongs, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"xh" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/condiment/large/salt, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/sugar, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"xk" = ( +/obj/structure/flora/tree/dead/mahogany, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"xH" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/slaughterhouse) +"xI" = ( +/obj/structure/fire_source/forge, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"xJ" = ( +/obj/structure/table/desk/dresser/ebony, +/turf/floor/carpet/rustic, +/area/shaded_hills/inn) +"xU" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"xW" = ( +/obj/structure/reagent_dispensers/compost_bin/walnut, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"ya" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"yn" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/inn_backroom, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"yu" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/cabbage, +/obj/item/seeds/extracted/cabbage, +/obj/item/seeds/extracted/cabbage, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"yw" = ( +/turf/wall/wattle/daubed/walnut, +/area/shaded_hills/stable) +"yx" = ( +/obj/structure/table/marble, +/obj/item/staff/broom, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"yz" = ( +/turf/wall/wattle/daubed/plastered/walnut, +/area/shaded_hills/general_store) +"yJ" = ( +/obj/structure/chair/rustic{ + dir = 1 + }, +/obj/abstract/landmark/start/shaded_hills/farmer, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"yN" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"yY" = ( +/turf/floor/grass, +/area/shaded_hills/outside/downlands/poi) +"zj" = ( +/obj/structure/table/marble, +/obj/item/rollingpin, +/obj/item/knife/kitchen/cleaver/bronze, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"zl" = ( +/obj/structure/table/marble, +/obj/item/chems/cooking_vessel/pot/iron, +/obj/item/chems/cooking_vessel/skillet/iron, +/obj/item/chems/cooking_vessel/baking_dish/earthenware, +/obj/item/chems/cooking_vessel/baking_dish/earthenware, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"zm" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"zA" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut, +/area/shaded_hills/inn/kitchen) +"zH" = ( +/obj/structure/produce_bin/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"zO" = ( +/obj/structure/door/walnut, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"zQ" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/general_store/porch) +"Ak" = ( +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"Ap" = ( +/obj/abstract/landmark/start/shaded_hills/bartender, +/obj/item/stool/rustic, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"Aq" = ( +/obj/structure/working/loom/ebony, +/obj/structure/wall_sconce/lantern, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"At" = ( +/turf/wall/log/walnut/shutter/open, +/area/shaded_hills/stable) +"Aw" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/seeds/extracted/foxglove, +/obj/item/seeds/extracted/foxglove, +/obj/item/seeds/extracted/ginseng, +/obj/item/seeds/extracted/ginseng, +/obj/item/seeds/extracted/valerian, +/obj/item/seeds/extracted/valerian, +/obj/item/seeds/extracted/yarrow, +/obj/item/seeds/extracted/yarrow, +/obj/item/tool/hoe/wood/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"Ay" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/downlands) +"AA" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut, +/area/shaded_hills/inn) +"AE" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/shrine, +/turf/floor/path/basalt, +/area/shaded_hills/shrine) +"AG" = ( +/obj/structure/table/wood/ebony, +/obj/item/bag/sack, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = 5 + }, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -16 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"AS" = ( +/mob/living/simple_animal/passive/horse, +/turf/floor/straw, +/area/shaded_hills/stable) +"AW" = ( +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/flora/bush/brflowers, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"AX" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"Bp" = ( +/obj/structure/working/butter_churn/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"Br" = ( +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"Bx" = ( +/obj/structure/wall_sconce/lantern, +/obj/structure/working/spinning_wheel/twisting_bench/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"By" = ( +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"BG" = ( +/obj/structure/chair/bench/ebony{ + dir = 1 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"BI" = ( +/obj/abstract/map_data/shaded_hills, +/turf/unsimulated/mask, +/area/shaded_hills/outside/downlands) +"BL" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/yellowed, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"BX" = ( +/obj/structure/wall_sconce/lantern, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse/porch) +"Cg" = ( +/obj/structure/banner_frame/sign/tavern, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"Cj" = ( +/obj/item/stack/material/log/mapped/walnut/twenty, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"CP" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/shrine, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine/kitchen) +"CR" = ( +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"CV" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"Dk" = ( +/turf/wall/wattle/daubed/walnut, +/area/shaded_hills/shrine) +"Dl" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse/porch) +"Dn" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"Dr" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/yellowed, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Dt" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/abstract/landmark/start/shaded_hills/shrine_keeper, +/obj/item/bedsheet/furs, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"Ee" = ( +/turf/wall/wattle/daubed/plastered/walnut, +/area/shaded_hills/inn) +"Ep" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/obj/structure/table/end, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"Er" = ( +/obj/structure/chair/bench/pew/ebony{ + dir = 4 + }, +/obj/structure/railing/mapped/wooden/ebony{ + dir = 8 + }, +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 8 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Ev" = ( +/obj/structure/table/wood/ebony, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10; + start_lit = 1 + }, +/obj/item/staff/broom, +/turf/floor/carpet, +/area/shaded_hills/inn) +"EJ" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"EK" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4; + start_lit = 1 + }, +/obj/structure/table/wood/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"EV" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"Ff" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"Fz" = ( +/obj/structure/working/quern, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"FD" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/obj/item/tool/shovel/wood/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"FE" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"FH" = ( +/obj/structure/fire_source/stove, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Ga" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"Gb" = ( +/obj/structure/table/marble, +/obj/item/stack/medical/bandage/crafted/five, +/obj/item/stack/medical/ointment/crafted/five, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"Gc" = ( +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Gj" = ( +/obj/structure/table/wood/reinforced/mahogany, +/turf/floor/carpet/red, +/area/shaded_hills/shrine) +"Gq" = ( +/obj/abstract/landmark/start/shaded_hills/traveller/learned, +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"Gs" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/general_store/porch) +"Gu" = ( +/obj/structure/table/marble, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/yeast, +/obj/item/chems/condiment/sugar, +/obj/item/chems/condiment/large/salt, +/obj/abstract/landmark/organize/horizontal, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Gw" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/bag/sack, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"GN" = ( +/obj/item/towel/doormat/flat{ + dir = 1 + }, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"GQ" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"GV" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/flora/bush/ywflowers, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"GW" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/mud, +/area/shaded_hills/outside/downlands) +"GZ" = ( +/obj/item/food/butchery/meat/chicken, +/obj/item/food/butchery/meat/chicken, +/obj/item/food/butchery/haunch/side/beef, +/obj/item/food/butchery/haunch/shoulder/beef, +/obj/item/food/butchery/cutlet/raw/beef, +/obj/item/food/butchery/cutlet/raw/beef, +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/structure/wall_sconce/lantern, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Hp" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/chems/glass/bucket/wood, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"Hv" = ( +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/flora/bush/sparsegrass, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"Hw" = ( +/obj/effect/floor_decal/spline/fancy/wood/walnut, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"HE" = ( +/turf/wall/log/walnut/shutter, +/area/shaded_hills/stable) +"HF" = ( +/obj/structure/working/spinning_wheel/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"HI" = ( +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"HK" = ( +/mob/living/simple_animal/passive/sheep, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"HL" = ( +/obj/structure/table/marble, +/obj/structure/fire_source/heater/mapped, +/obj/item/chems/glass/handmade/jar, +/obj/item/chems/glass/handmade/jar, +/obj/item/chems/glass/handmade/jar, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine/kitchen) +"HM" = ( +/obj/structure/cask_rack/large/mapped, +/obj/structure/reagent_dispensers/barrel/cask/ebony/water, +/obj/structure/reagent_dispensers/barrel/cask/ebony/oil, +/obj/structure/reagent_dispensers/barrel/cask/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"HP" = ( +/obj/structure/table/end/alt, +/obj/item/flame/candle/handmade{ + pixel_y = 12 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"Ic" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/downlands) +"Il" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"Im" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"IB" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/shrine, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"IC" = ( +/obj/structure/bookcase/ebony, +/turf/floor/carpet, +/area/shaded_hills/inn) +"IL" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"IQ" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut/shutter/open, +/area/shaded_hills/farmhouse) +"IS" = ( +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"IV" = ( +/obj/abstract/landmark/latejoin, +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"IZ" = ( +/obj/structure/banner_frame/wall/ebony/green{ + dir = 4; + pixel_x = 32 + }, +/turf/floor/carpet, +/area/shaded_hills/inn) +"Je" = ( +/obj/structure/pit/closed/grave, +/turf/floor/grass, +/area/shaded_hills/outside/shrine) +"Jo" = ( +/obj/structure/table/end/alt/ebony, +/obj/structure/divider/extended/wood/ebony{ + dir = 4; + pixel_x = 16 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Jp" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/carpet, +/area/shaded_hills/inn) +"Jt" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"Jw" = ( +/obj/structure/chair/rustic, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"Jz" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/obj/abstract/landmark/lock_preset/shaded_hills/inn_interior, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"JK" = ( +/obj/structure/table/wood/reinforced/mahogany, +/obj/item/flame/candle/handmade, +/turf/floor/carpet/red, +/area/shaded_hills/shrine) +"JM" = ( +/obj/structure/table/wood/ebony, +/obj/item/ancient_surgery/cautery, +/obj/item/ancient_surgery/scalpel, +/obj/structure/wall_sconce/lantern, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"JS" = ( +/obj/structure/chair/rustic{ + dir = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"JU" = ( +/obj/structure/railing/mapped/wooden/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"Ka" = ( +/mob/living/simple_animal/cow, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"Ke" = ( +/obj/structure/working/spinning_wheel/twisting_bench/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"Kh" = ( +/turf/wall/log/walnut/shutter/open, +/area/shaded_hills/shrine) +"KD" = ( +/obj/structure/table/desk/dresser/ebony, +/obj/item/candelabra/filled{ + pixel_y = 9 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"KF" = ( +/obj/structure/wall_sconce/lantern, +/obj/structure/coatrack/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"KG" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"Lj" = ( +/obj/structure/reagent_dispensers/well/mapped/covered, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"Ly" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4; + start_lit = 1 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"LA" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/stack/material/brick/mapped/graphite/forty, +/obj/item/rock/flint/striker, +/obj/item/bladed/knife/iron, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"LH" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/bucket/wood, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = 6 + }, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -15 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"LK" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"LN" = ( +/turf/wall/wattle/daubed/walnut, +/area/shaded_hills/farmhouse) +"Mb" = ( +/obj/abstract/landmark/start/shaded_hills/traveller/learned, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/downlands) +"Mj" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/structure/produce_bin/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"Mo" = ( +/turf/open, +/area/shaded_hills/outside/shrine) +"Mp" = ( +/obj/structure/wall_sconce/lantern, +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"My" = ( +/obj/item/chems/glass/inkwell/quilled{ + pixel_x = 12; + pixel_y = 8 + }, +/obj/item/hourglass{ + pixel_y = 12 + }, +/obj/structure/table/desk/ebony/right, +/turf/floor/carpet, +/area/shaded_hills/inn) +"MT" = ( +/obj/structure/drying_rack/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"No" = ( +/turf/open, +/area/shaded_hills/inn/kitchen) +"NF" = ( +/obj/structure/table/wood/ebony, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"NH" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/downlands/poi) +"NZ" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/bottle/tall/wine, +/obj/item/chems/glass/handmade/bottle/tall/wine, +/obj/item/chems/glass/handmade/bottle/tall/wine, +/obj/abstract/landmark/organize/horizontal, +/obj/structure/banner_frame/wall/ebony/green{ + pixel_y = 32 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"Oa" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"Ot" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/cooking_vessel/pot/iron, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"ON" = ( +/obj/structure/table/marble, +/obj/item/rock/flint/striker{ + pixel_x = 4 + }, +/obj/item/bladed/folding/iron{ + pixel_x = -4 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Pa" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/downlands/poi) +"Pb" = ( +/obj/structure/closet/cabinet/wooden/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/stable) +"Pd" = ( +/turf/floor/carpet/rustic, +/area/shaded_hills/farmhouse) +"Pe" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/obj/structure/chair/bench/pew/ebony{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"PA" = ( +/turf/floor/straw, +/area/shaded_hills/stable) +"PG" = ( +/obj/structure/door/mahogany, +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"PQ" = ( +/obj/item/food/butchery/meat/beef, +/obj/item/food/butchery/meat/beef, +/obj/item/food/butchery/meat/beef, +/obj/item/food/butchery/meat/chicken, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"PS" = ( +/obj/structure/reagent_dispensers/barrel/ebony/oil, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/storehouse) +"Qa" = ( +/obj/structure/working/grindstone, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"Qb" = ( +/turf/floor/carpet, +/area/shaded_hills/inn) +"Qs" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/inn_exterior, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Qx" = ( +/obj/structure/table/desk/dresser, +/obj/item/flame/candle/handmade{ + pixel_y = 12 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"QB" = ( +/turf/wall/log/walnut, +/area/shaded_hills/shrine) +"QL" = ( +/obj/structure/chair/rustic{ + dir = 1 + }, +/obj/structure/wall_sconce/lantern{ + dir = 8; + start_lit = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"QQ" = ( +/turf/wall/log/walnut, +/area/shaded_hills/storehouse) +"QS" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/general_store/porch) +"QW" = ( +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine/kitchen) +"Rg" = ( +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Rh" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/yellowed, +/obj/abstract/landmark/start/shaded_hills/innkeeper, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Rk" = ( +/obj/structure/anvil, +/obj/item/tool/hammer/forge/iron, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"Rl" = ( +/turf/floor/mud, +/area/shaded_hills/outside/downlands) +"Rp" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/carpet/rustic, +/area/shaded_hills/inn) +"Rz" = ( +/obj/effect/departure_signpost/east, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"RB" = ( +/turf/floor/carpet/rustic, +/area/shaded_hills/inn) +"RC" = ( +/obj/structure/railing/mapped/wooden/walnut, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"RG" = ( +/turf/wall/brick/basalt/shutter/open, +/area/shaded_hills/shrine/kitchen) +"RO" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Sf" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/grass, +/area/shaded_hills/outside/downlands) +"Sj" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/item/chems/glass/bucket/wood, +/turf/floor/mud, +/area/shaded_hills/outside/shrine) +"Sw" = ( +/obj/structure/chair/rustic{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"Sy" = ( +/obj/structure/working/spinning_wheel/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"SB" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn) +"SF" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/trader_stockroom, +/turf/floor/path/basalt, +/area/shaded_hills/general_store) +"SG" = ( +/obj/structure/door/walnut, +/turf/floor/path/basalt, +/area/shaded_hills/stable) +"SU" = ( +/obj/structure/table/desk/dresser, +/obj/item/flame/candle/handmade{ + pixel_y = 12 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"SW" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands/poi) +"SX" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/obj/structure/rack/ebony, +/obj/item/stack/material/log/mapped/walnut/twenty, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Td" = ( +/obj/structure/chair/rustic{ + dir = 8 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Ti" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"Tr" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 1 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Ts" = ( +/obj/structure/wall_sconce/lantern, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"Tz" = ( +/obj/abstract/landmark/latejoin, +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"TM" = ( +/obj/structure/table/wood/ebony, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/carrot, +/obj/item/food/grown/carrot, +/obj/item/food/grown/cabbage, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"TR" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/downlands) +"TZ" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/shrine, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"Ue" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/farmhouse, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"UD" = ( +/obj/item/flame/candle/handmade, +/obj/structure/table/end/alt, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine) +"US" = ( +/obj/structure/chair/rustic{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"UU" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/path/basalt, +/area/shaded_hills/outside/downlands) +"UY" = ( +/turf/wall/log/walnut/shutter, +/area/shaded_hills/storehouse) +"Vj" = ( +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine) +"VE" = ( +/obj/structure/cask_rack/large/mapped, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"VM" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/turf/floor/dirt, +/area/shaded_hills/outside/shrine) +"VO" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse) +"VU" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/farmhouse/porch) +"VW" = ( +/obj/structure/table/marble, +/obj/item/chems/glass/beaker/bowl/pottery{ + pixel_y = 4 + }, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"VZ" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/downlands/poi) +"Wg" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut, +/area/shaded_hills/general_store) +"Wh" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/mortar, +/obj/item/rock/basalt, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/shrine/kitchen) +"Wk" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/straw, +/area/shaded_hills/stable) +"Wl" = ( +/obj/structure/table/wood/reinforced/ebony, +/obj/item/chems/glass/handmade/cup/wood, +/obj/effect/floor_decal/spline/fancy/wood/walnut{ + dir = 1 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Wm" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/downlands) +"WD" = ( +/obj/structure/railing/mapped/wooden/walnut, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"WE" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/obj/item/seeds/extracted/cabbage, +/obj/item/seeds/extracted/cabbage, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/carrot, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/wheat, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/rice, +/obj/item/seeds/extracted/potato, +/obj/item/seeds/extracted/potato, +/obj/structure/railing/mapped/wooden/walnut{ + dir = 4 + }, +/obj/item/tool/shovel/wood/walnut, +/turf/floor/mud, +/area/shaded_hills/outside/shrine) +"WG" = ( +/obj/structure/coatrack/ebony, +/turf/floor/carpet, +/area/shaded_hills/inn) +"WI" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"WO" = ( +/obj/structure/door/walnut, +/obj/abstract/landmark/lock_preset/shaded_hills/farmhouse, +/turf/floor/wood/walnut, +/area/shaded_hills/farmhouse) +"WV" = ( +/obj/structure/fire_source/kiln/oven, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"WY" = ( +/obj/structure/table/wood/ebony, +/turf/floor/wood/walnut, +/area/shaded_hills/inn) +"Xr" = ( +/obj/structure/meat_hook, +/turf/floor/path/basalt, +/area/shaded_hills/slaughterhouse) +"XH" = ( +/obj/structure/fire_source/stove, +/obj/item/stack/material/log/mapped/walnut/twenty, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/shrine/kitchen) +"XJ" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10; + start_lit = 1 + }, +/turf/floor/wood/mahogany, +/area/shaded_hills/shrine) +"XM" = ( +/turf/floor/carpet/red, +/area/shaded_hills/shrine) +"XY" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/shrine) +"Yc" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/shrine) +"Yg" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/inn/porch) +"Yj" = ( +/obj/structure/meat_hook, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Yp" = ( +/obj/structure/table/marble, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"Yu" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/downlands) +"Zb" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/shaded_hills/general_store) +"Zx" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/mud, +/area/shaded_hills/outside/shrine) +"ZC" = ( +/obj/structure/table/wood/ebony, +/turf/floor/wood/walnut, +/area/shaded_hills/stable) +"ZD" = ( +/obj/abstract/landmark/start/shaded_hills/bartender, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"ZE" = ( +/obj/structure/table/marble, +/obj/item/chems/glass/handmade/teapot, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/inn/kitchen) +"ZY" = ( +/turf/floor/wood/walnut, +/area/shaded_hills/inn) + +(1,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(2,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(3,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(4,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(5,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(6,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(7,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(8,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(9,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lE +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(10,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +BI +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(11,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(12,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(13,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(14,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +TR +TR +EV +TR +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(15,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +TR +EV +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(16,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +TR +EV +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(17,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(18,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(19,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +TR +Ic +EV +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(20,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(21,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(22,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +EV +Ic +TR +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(23,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(24,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +EV +Ic +EV +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(25,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(26,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(27,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +HI +TR +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(28,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +HI +TR +EV +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(29,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +TR +TR +TR +Ic +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(30,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +TR +EV +TR +Ic +EV +TR +HI +TR +TR +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(31,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +TR +EV +Ic +EV +EV +HI +TR +HI +TR +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(32,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +TR +TR +Ic +EV +TR +HI +HI +HI +HI +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(33,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +TR +EV +TR +HI +HI +HI +HI +yY +yY +yY +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(34,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +HI +yY +yY +VZ +qY +qY +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(35,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +TR +EV +TR +HI +HI +HI +HI +HI +yY +yY +VZ +qY +qY +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(36,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +yY +yY +VZ +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(37,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +HI +HI +HI +HI +TR +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +VZ +qY +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(38,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +HI +HI +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(39,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +HI +TR +TR +TR +EV +Ic +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(40,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +EV +Ic +EV +HI +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(41,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(42,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +Lj +TR +TR +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(43,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(44,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(45,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +TR +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +TR +TR +TR +TR +TR +TR +TR +EV +Yu +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +TR +HI +HI +HI +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(46,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +TR +cx +cx +TR +TR +TR +cx +cx +cx +cx +cx +cx +cx +TR +HI +TR +TR +cx +cx +cx +cx +cx +TR +TR +EV +Mb +EV +TR +TR +TR +TR +cx +cx +cx +cx +cx +cx +cx +TR +cx +cx +cx +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(47,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +cx +cx +cx +cx +TR +TR +TR +TR +cx +cx +cx +TR +TR +cx +cx +cx +cx +cx +cx +cx +cx +TR +TR +EV +Ic +TR +TR +TR +TR +TR +TR +TR +TR +cx +cx +cx +cx +cx +cx +TR +TR +cx +cx +cx +cx +TR +cx +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(48,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +cx +TR +TR +TR +HI +TR +TR +TR +HI +TR +TR +TR +HI +TR +TR +TR +TR +TR +TR +TR +TR +HI +TR +EV +Ic +EV +TR +TR +TR +TR +TR +TR +HI +HI +TR +TR +HI +HI +TR +TR +TR +TR +TR +TR +TR +TR +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(49,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +cx +TR +HI +HI +TR +TR +TR +TR +TR +AA +AA +iX +AA +AA +AA +iX +AA +AA +TR +HI +HI +TR +TR +EV +Ic +EV +wF +Wg +Wg +dH +Wg +dH +Wg +Wg +HI +QQ +QQ +QQ +QQ +UY +QQ +QQ +QQ +QQ +TR +TR +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(50,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +cx +AA +AA +iX +AA +AA +AA +iX +AA +AA +th +RB +gn +ly +th +RB +gn +AA +TR +TR +HI +TR +TR +EV +Ic +EV +Gs +dH +uJ +uJ +WI +uJ +uJ +dH +HI +QQ +Hp +fR +fR +fR +fR +fR +fR +QQ +TR +TR +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(51,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +cx +AA +Rh +KD +sJ +Ee +th +RB +gn +ly +af +RB +Td +ly +af +RB +Td +AA +GV +TR +HI +TR +TR +EV +TR +TR +zQ +eG +uJ +uJ +sM +sM +uJ +Wg +HI +QQ +Fz +fR +fR +fR +fR +fR +fR +QQ +TR +cx +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(52,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +cx +AA +ZY +dr +ZY +Ee +af +RB +Td +ly +ly +Jz +ly +ly +ly +Jz +ly +AA +Hv +TR +TR +HI +TR +EV +Ic +EV +QS +dH +uJ +uJ +sM +aK +Zb +dH +HI +QQ +fR +fR +fR +fR +fR +fR +fR +QQ +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(53,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +AA +Ee +Jo +rp +Ee +ly +Jz +ly +ly +ZY +ZY +ZY +ZY +Qb +Qb +Qb +iX +AW +TR +TR +TR +TR +TR +Ic +TR +Mp +Wg +GQ +uJ +yz +iC +yz +Wg +HI +UY +Hp +fR +fR +fR +fR +fR +fR +UY +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(54,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +AA +My +dX +ZY +Ee +Jp +Qb +Qb +ZY +Qb +Qb +Qb +ZY +Qb +Qb +Qb +AA +rc +TR +TR +HI +TR +TR +TR +Ic +EV +Wg +uJ +uJ +yz +uJ +BL +dH +HI +QQ +Fz +fR +fR +fR +fR +fR +yu +QQ +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(55,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +AA +rg +hb +ZY +yn +Qb +IZ +Qb +Im +Qb +Qb +Qb +ZY +ZY +Im +ZY +AA +TR +TR +HI +TR +TR +TR +EV +Ic +EV +Wg +yz +yz +yz +uJ +Qx +Wg +HI +QQ +fR +fR +fR +fR +fR +fR +Dn +QQ +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(56,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +AA +iX +AA +Ee +Ee +ly +ly +ly +ly +IC +Qb +Qb +Ee +Ee +Ee +Ee +AA +TR +TR +TR +TR +HI +TR +EV +Ic +EV +Wg +wh +uM +yz +uJ +ij +Wg +HI +QQ +PS +dL +fR +fR +fR +fR +PS +QQ +TR +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(57,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +cx +cx +TR +zA +zj +vA +Gc +RO +No +ly +Ev +Qb +WG +Ee +ZY +Pe +kI +AA +mJ +qf +WD +TR +TR +HI +TR +Ic +EV +Wg +bz +uM +SF +uJ +Ep +Wg +HI +QQ +QQ +UY +QQ +IL +QQ +UY +QQ +QQ +TR +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(58,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +cx +TR +iq +Gu +Gc +Gc +Gc +fh +Ee +Ee +SB +Ee +Ee +ZY +WY +WY +iX +Yg +tZ +JU +TR +HI +TR +EV +Ic +EV +Wg +Wg +Wg +Wg +dH +Wg +Wg +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(59,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +cx +TR +zA +ZE +Gc +gR +Gc +Gc +NF +lF +lF +wf +dN +ZY +nx +nx +AA +Jw +dK +JU +TR +TR +HI +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(60,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +TR +TR +iq +rC +Gc +VW +Gc +ZD +EK +lF +lF +tv +BG +ZY +Er +Er +AA +Jw +dK +JU +TR +HI +TR +EV +TR +TR +HI +xH +xH +xH +xH +xH +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +HI +TR +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(61,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +TR +TR +zA +fS +Gc +Yp +Gc +jx +Ee +rv +lF +Tr +BG +ZY +WY +cq +iX +Yg +Sw +JU +Cg +TR +qW +EV +Ic +EV +TR +fw +Xr +gc +Gw +fw +HI +HI +oO +Sf +Sf +Sf +Sf +Sf +Sf +tS +HI +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(62,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +TR +HI +iq +tF +ZD +Yp +Gc +GZ +Ee +NZ +Ap +Tr +BG +ZY +uk +uk +AA +hZ +Yg +Yg +TR +EV +EV +EV +TR +EV +HI +xH +Xr +Br +lz +xH +HI +HI +gp +HI +HI +HI +HI +HI +HI +RC +HI +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(63,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +TR +TR +TR +TR +HI +zA +ON +Gc +zl +Gc +Yj +Ee +id +lF +Tr +BG +rY +Rg +Rg +Qs +dD +Yg +Yg +Ic +Ic +Ic +EV +Ic +EV +Ts +xH +Xr +Br +nN +xH +HI +HI +gp +HI +HI +HI +Ka +HI +rO +RC +HI +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(64,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +TR +HI +sl +Gc +Gc +Gc +Gc +Gc +iH +lF +lF +Wl +BG +Hw +lF +KF +qG +Yg +Yg +Yg +Ic +Ic +EV +Ic +TR +EV +TR +fw +IS +Br +Bx +fw +HI +HI +gp +HI +Ay +HI +HI +HI +HI +RC +HI +TR +TR +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(65,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +TR +HI +gU +SX +FH +WV +Gc +fK +Ee +pi +Ly +Wl +BG +Hw +Cj +iZ +qG +kx +Yg +Yg +TR +TR +EV +EV +Ic +EV +TR +tq +Br +Br +Br +tq +HI +HI +gp +Ay +Ay +Ay +HI +HI +HI +RC +HI +TR +TR +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(66,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +TR +AA +qG +qG +qG +qG +qG +Ee +Ee +Ee +Ee +Ee +Ee +dC +qG +qG +qG +Yg +tZ +JU +TR +TR +TR +EV +Ic +EV +TR +xH +PQ +Oa +MT +xH +HI +HI +gp +Ay +Ay +HI +HI +HI +rO +RC +HI +HI +TR +cx +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(67,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +cx +TR +AA +gn +ZY +zO +ZY +dN +ZY +ZY +ZY +dN +ZY +Ee +ZY +Rp +nJ +AA +Jw +dK +JU +TR +HI +TR +EV +Ic +EV +TR +xH +xH +fw +xH +xH +HI +HI +gp +HI +HI +HI +HK +HI +HI +RC +HI +TR +cx +cx +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(68,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +cx +TR +AA +Td +ZY +Ee +ZY +ZY +ZY +ZY +ZY +ZY +ZY +zO +ZY +RB +xJ +AA +Jw +dK +JU +TR +HI +TR +TR +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +LK +hU +hU +hU +hU +hU +hU +hE +HI +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(69,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +cx +TR +AA +sJ +Dr +Ee +dC +Ee +Ee +Ee +dC +Ee +Ee +Ee +ZY +RB +nJ +iX +Yg +Sw +JU +HI +TR +EV +Ic +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(70,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +cx +TR +AA +AA +iX +AA +ZY +ZY +US +Ee +ZY +ZY +US +Ee +RB +RB +xJ +AA +hu +lD +ry +TR +HI +EV +Ic +TR +HI +HI +oL +oL +oL +IQ +oL +HI +HI +HI +HI +HI +HI +HI +TR +HI +HI +HI +HI +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(71,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +cx +TR +TR +TR +TR +AA +sJ +Dr +gn +Ee +sJ +Dr +gn +Ee +xJ +nJ +AA +AA +TR +TR +TR +TR +TR +EV +Ic +EV +TR +HI +oL +uu +qP +qP +oL +HI +TR +HI +HI +HI +TR +TR +HI +HI +HI +HI +TR +cx +cx +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(72,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +cx +TR +TR +TR +TR +AA +AA +iX +AA +AA +AA +iX +AA +AA +AA +iX +AA +TR +TR +TR +TR +TR +TR +EV +Ic +EV +TR +HI +oL +SU +Pd +qP +WO +HI +HI +TR +TR +TR +TR +TR +TR +HI +TR +HI +TR +cx +TR +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(73,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +cx +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +EV +Ic +EV +TR +HI +IQ +bv +Pd +qP +oL +HI +TR +Rl +Rl +TR +Rl +Rl +TR +TR +HI +TR +TR +cx +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(74,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +cx +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +EV +Ic +EV +TR +HI +oL +eM +qP +FE +oL +TR +Rl +GW +Rl +Rl +Rl +Ay +Rl +TR +Rl +TR +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(75,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +cx +TR +HI +TR +nn +HE +nn +nn +nn +nn +At +nn +nn +nn +nn +nn +nn +nn +nn +nn +nn +TR +TR +EV +Ic +EV +TR +oL +oL +LN +Ti +LN +oL +TR +Rl +GW +Ay +GW +GW +Ay +Rl +Rl +Ay +Rl +HI +cx +cx +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(76,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +TR +cx +cx +TR +nn +jA +HP +Pb +yw +mD +ZC +JS +js +yw +LA +Ak +Ak +Ak +Ak +HM +nn +TR +TR +EV +Ic +EV +TR +oL +cl +VO +VO +yN +oL +TR +Rl +GW +Ay +Rl +GW +Ay +GW +Rl +Ay +GW +TR +cx +cx +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(77,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +TR +HI +TR +cx +cx +TR +nn +js +js +js +kE +js +js +js +js +kE +GN +Ak +fM +Ak +Ak +Qa +nn +aU +TR +EV +Ic +EV +TR +IQ +LH +yJ +VO +yN +oL +TR +Rl +GW +Ay +GW +GW +Ay +GW +GW +Ay +GW +TR +cx +cx +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(78,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +TR +cx +TR +TR +nn +bu +wp +js +yw +js +jf +tH +gW +yw +Ak +Ak +xI +Ak +Ak +xa +HE +KG +EV +EV +Ic +EV +TR +oL +ml +VO +VO +gB +oL +TR +Rl +Rl +Ay +GW +GW +Ay +GW +Rl +Ay +GW +TR +TR +cx +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(79,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +HI +HI +HI +HI +HI +TR +TR +TR +TR +HI +TR +nn +yw +yw +yw +yw +yw +yw +yw +yw +yw +Ak +Ak +Rk +Ak +Ak +Ak +SG +Ic +Ic +Ic +Ic +EV +TR +oL +AG +VO +VO +ya +oL +zH +Rl +GW +Ay +GW +GW +Ay +Rl +Rl +Ay +GW +TR +HI +cx +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(80,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +TR +cx +TR +TR +nn +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +Ak +SG +Ic +Ic +Ic +EV +VU +VU +oL +LN +mK +LN +LN +oL +me +Rl +GW +Ay +Rl +GW +Ay +Rl +GW +Ay +Rl +HI +TR +cx +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(81,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +cx +TR +TR +nn +Ak +Ak +Ak +or +Ak +Ak +Ak +or +Ak +Ak +Ak +or +Ak +Ak +Ak +HE +UU +EV +EV +Ic +Dl +BX +oL +VO +VO +hJ +Bp +IQ +FD +Rl +Rl +Ay +Rl +GW +Ay +GW +GW +Ay +GW +HI +TR +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(82,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +HI +HI +TR +nn +Wk +Wk +Wk +yw +Wk +Wk +Wk +yw +Wk +Wk +Wk +yw +Wk +Wk +Wk +nn +aU +TR +EV +EV +Dl +Dl +Ue +VO +VO +VO +VO +Ue +TR +Rl +GW +Ay +GW +GW +Ay +Rl +GW +Ay +GW +HI +TR +cx +TR +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(83,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +TR +HI +TR +nn +PA +AS +PA +yw +PA +PA +PA +yw +PA +gJ +PA +yw +PA +PA +PA +nn +TR +HI +TR +Ic +Dl +lL +oL +hJ +VO +VO +VO +oL +xW +Rl +Rl +Ay +GW +GW +Ay +GW +Rl +Ay +GW +TR +TR +cx +TR +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(84,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +HI +HI +HI +HI +TR +cx +TR +TR +TR +nn +nn +HE +nn +nn +nn +HE +nn +nn +nn +HE +nn +nn +nn +HE +nn +nn +TR +HI +EV +Ic +Dl +hc +IQ +HF +ra +gg +eD +oL +ke +TR +Rl +Rl +Rl +Rl +Rl +Rl +Rl +Rl +TR +TR +TR +cx +TR +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(85,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +HI +HI +HI +TR +TR +cx +TR +TR +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +EV +Ic +mG +mG +oL +oL +oL +oL +oL +oL +TR +TR +TR +TR +Rl +TR +TR +Rl +Rl +TR +TR +TR +TR +cx +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(86,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +HI +HI +HI +TR +TR +cx +TR +TR +TR +TR +TR +TR +HI +TR +TR +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +EV +EV +EV +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(87,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +HI +HI +HI +HI +TR +cx +cx +cx +cx +cx +cx +cx +TR +TR +TR +TR +TR +cx +cx +cx +cx +cx +cx +cx +cx +TR +TR +TR +EV +Ic +EV +TR +TR +cx +cx +cx +TR +TR +TR +TR +TR +TR +TR +TR +cx +cx +cx +cx +cx +cx +TR +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(88,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +TR +cx +cx +TR +TR +cx +cx +cx +cx +cx +cx +cx +cx +cx +cx +cx +TR +TR +TR +TR +TR +TR +TR +TR +EV +Ic +EV +TR +TR +TR +cx +cx +cx +TR +TR +TR +cx +cx +cx +cx +cx +cx +cx +cx +cx +cx +cx +cx +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(89,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +TR +TR +TR +HI +TR +TR +TR +TR +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +HI +TR +TR +EV +Mb +EV +EV +TR +TR +TR +TR +TR +TR +HI +HI +HI +TR +TR +TR +HI +HI +TR +TR +TR +TR +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(90,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +Yu +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(91,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +EV +Ic +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(92,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(93,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +EV +Ic +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(94,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +EV +Ic +EV +TR +TR +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(95,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +TR +TR +Ic +EV +EV +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(96,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +By +By +By +By +By +yY +yY +yY +yY +By +HI +TR +TR +EV +TR +TR +EV +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(97,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +By +By +By +By +kv +kv +kv +By +By +By +By +By +By +kv +TR +TR +TR +EV +Ic +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(98,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +By +By +kv +kv +kv +kv +kv +kv +kv +kv +kv +By +By +kv +kv +TR +TR +EV +EV +Ic +EV +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(99,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +By +By +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +TR +TR +EV +EV +Ic +TR +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(100,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +By +By +kv +kv +kv +kv +By +By +By +By +By +kv +kv +kv +kv +kv +kv +TR +TR +EV +EV +Ic +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(101,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +By +By +By +kv +kv +kv +kv +By +By +By +By +By +By +By +By +By +By +By +By +HI +TR +TR +EV +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(102,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +kv +By +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +HI +TR +TR +EV +EV +TR +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(103,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +By +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +EV +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(104,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(105,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +EV +EV +EV +EV +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(106,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +By +By +NH +NH +NH +NH +By +By +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +EV +EV +TR +TR +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(107,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(108,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +NH +By +By +By +By +By +By +By +kv +By +By +By +kv +By +By +By +By +kv +kv +By +By +By +By +By +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +EV +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(109,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +By +By +By +By +By +By +By +kv +kv +By +kv +iK +kv +By +By +kv +kv +iK +kv +By +By +kv +kv +kv +kv +kv +By +By +NH +NH +NH +NH +NH +NH +NH +NH +By +By +By +kv +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +EV +EV +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(110,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +zm +gA +gA +gA +gA +gA +gA +iK +QB +Kh +QB +QB +kv +kv +kv +iK +iK +iK +kv +kv +kv +kv +iK +iK +kv +iK +kv +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +EV +Ic +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(111,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +By +Je +By +iK +QB +UD +QL +QB +By +By +By +kv +kv +kv +kv +kv +By +By +kv +kv +kv +kv +kv +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +EV +Ic +EV +TR +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(112,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +Je +By +By +By +By +By +iK +QB +Dt +CV +QB +QB +QB +Kh +QB +QB +wr +wr +uD +wr +wr +wr +wr +wr +wr +wr +By +By +NH +NH +NH +NH +NH +NH +NH +NH +By +By +By +kv +kv +kv +By +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +TR +Ic +Ic +EV +TR +TR +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(113,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +Je +By +Je +By +iK +QB +Jt +CV +sz +CV +CV +iJ +CV +CV +nS +CR +CR +gt +CR +CR +CR +CR +CR +wr +By +By +NH +NH +NH +NH +NH +NH +NH +By +By +By +kv +kv +kv +By +By +By +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +EV +Ic +EV +EV +TR +TR +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(114,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +Je +By +By +By +By +By +iK +QB +QB +Il +QB +Il +Dk +Dk +Il +Dk +qV +CR +XM +XM +XM +pd +CR +pd +CR +uD +By +By +By +By +By +By +By +By +By +By +By +By +kv +kv +By +By +By +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +TR +TR +EV +EV +EV +TR +TR +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(115,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +Je +By +Je +By +iK +iK +kv +kv +Kh +CV +rS +Dk +CV +rS +qV +CR +XM +JK +XM +jk +CR +pd +CR +wr +jI +By +kv +kv +kv +kv +kv +kv +By +kv +kv +kv +kv +kv +By +By +By +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +EV +EV +TR +EV +EV +EV +TR +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(116,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +By +By +By +iK +kv +kv +kv +QB +Jt +qe +Dk +Jt +qe +qV +XJ +XM +Gj +XM +XM +XM +XM +CR +PG +ls +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +By +By +By +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +EV +TR +EV +EV +EV +TR +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(117,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +kv +kv +By +By +iK +kv +kv +kv +Yc +Yc +Dk +Dk +Dk +Dk +qV +CR +XM +JK +XM +pd +CR +pd +CR +wr +jI +kv +kv +kv +kv +kv +kv +kv +kv +kv +By +By +By +By +By +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +EV +TR +TR +SW +SW +SW +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(118,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +By +kv +kv +kv +kv +kv +kv +kv +kv +kv +kv +RG +dx +QW +ge +Ff +ge +qV +CR +XM +XM +XM +pd +CR +pd +CR +uD +By +By +By +By +By +By +By +By +By +By +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +SW +VZ +VZ +SW +SW +Pa +SW +SW +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(119,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +kv +kv +kv +kv +kv +kv +kv +ah +XH +QW +xh +vz +ge +nS +CR +CR +AX +CR +CR +CR +CR +CR +wr +By +By +By +NH +NH +NH +By +By +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +VZ +VZ +SW +SW +Pa +Pa +SW +SW +VZ +VZ +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(120,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +By +By +By +kv +iK +kv +kv +ah +HL +QW +TM +Wh +ge +wr +wr +uD +wr +wr +wr +wr +wr +wr +wr +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +VZ +VZ +SW +Pa +Pa +SW +SW +VZ +VZ +yY +yY +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(121,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +Je +By +Je +By +By +kv +kv +iK +kv +kv +CP +ge +ge +Ot +bW +ge +IB +ft +ft +ft +ft +ft +ft +ft +kv +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +VZ +VZ +VZ +SW +Pa +SW +EV +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(122,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +By +By +kv +iK +iK +kv +kv +oN +uP +ge +ge +ge +ge +Kh +ft +Zx +XY +Zx +ol +ft +kv +By +kv +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +VZ +VZ +EV +EV +EV +EV +EV +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(123,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +Je +By +By +kv +iK +iK +kv +By +px +ge +VE +ge +Sy +Aq +QB +ft +Zx +XY +Zx +ol +kv +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +TR +TR +TR +TR +EV +EV +EV +TR +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(124,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +By +kv +kv +iK +kv +By +kv +QB +Dk +Dk +Dk +Dk +Dk +QB +ft +Zx +XY +Zx +ol +kv +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +TR +TR +EV +EV +EV +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(125,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +Je +By +By +kv +kv +kv +kv +kv +kv +QB +yx +uK +Gb +Vj +Vj +TZ +ft +Zx +XY +Zx +ol +kv +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +TR +TR +EV +EV +EV +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(126,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +EJ +By +By +By +By +aP +Mo +xk +kv +kv +By +AE +Vj +Vj +Vj +Vj +JM +QB +ft +ft +ft +ft +ol +kv +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +TR +TR +EV +EV +EV +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(127,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +cT +xU +xU +xU +xU +kv +aP +kv +kv +By +kv +Kh +ev +gL +Ke +wg +qL +Kh +Aw +WE +Mj +Sj +fg +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +TR +TR +TR +EV +EV +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(128,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +By +By +By +By +By +By +VM +kv +kv +kv +By +kv +QB +QB +QB +QB +QB +QB +QB +kv +kv +By +kv +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +EV +EV +EV +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(129,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +NH +NH +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +EV +EV +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +yY +yY +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(130,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +By +By +By +By +NH +NH +NH +By +By +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +TR +EV +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(131,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +By +By +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +EV +Ic +TR +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(132,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +EV +Ic +TR +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(133,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +EV +EV +Ic +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(134,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +EV +EV +Ic +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(135,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +EV +Ic +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(136,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +EV +EV +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(137,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +EV +EV +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(138,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +NH +NH +NH +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +TR +EV +EV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(139,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +EV +EV +TR +TR +TR +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(140,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +yY +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +EV +Ic +EV +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(141,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +TR +EV +EV +Ic +EV +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(142,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +Rz +EV +Gq +Ic +Gq +EV +TR +TR +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(143,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +Wm +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +HI +TR +Tz +Ga +IV +Yu +IV +EV +TR +HI +HI +HI +HI +HI +HI +HI +HI +HI +Wm +Wm +Wm +Wm +Wm +Wm +Wm +lC +lC +lC +lC +lC +lC +lC +"} +(144,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(145,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(146,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(147,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(148,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(149,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} +(150,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +"} diff --git a/maps/shaded_hills/shaded_hills-swamp.dmm b/maps/shaded_hills/shaded_hills-swamp.dmm new file mode 100644 index 000000000000..f3d064b8b2ba --- /dev/null +++ b/maps/shaded_hills/shaded_hills-swamp.dmm @@ -0,0 +1,23003 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aM" = ( +/turf/wall/log/walnut/shutter/open, +/area/shaded_hills/witch_hut) +"bg" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"cE" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/river/swamp) +"cS" = ( +/obj/structure/chair/wood/ebony{ + dir = 8 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"fG" = ( +/obj/item/seeds/extracted/aloe, +/obj/item/seeds/extracted/aloe, +/obj/item/seeds/extracted/foxglove, +/obj/item/seeds/extracted/foxglove, +/obj/item/seeds/extracted/ginseng, +/obj/item/seeds/extracted/ginseng, +/obj/item/seeds/extracted/ginseng, +/obj/item/seeds/extracted/valerian, +/obj/item/seeds/extracted/valerian, +/obj/item/seeds/extracted/yarrow, +/obj/item/seeds/extracted/yarrow, +/obj/item/seeds/extracted/yarrow, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"hT" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river/swamp) +"kZ" = ( +/obj/abstract/level_data_spawner/shaded_hills_swamp, +/turf/floor/grass, +/area/shaded_hills/outside/swamp) +"ll" = ( +/obj/structure/fire_source/fireplace/basalt, +/obj/item/stack/material/log/mapped/ebony/ten, +/obj/item/chems/glass/beaker/kettle, +/turf/floor/path/basalt, +/area/shaded_hills/witch_hut) +"lC" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/river/swamp) +"lE" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/swamp) +"lZ" = ( +/turf/floor/mud, +/area/shaded_hills/caves/swamp) +"nK" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/rock/hematite, +/obj/item/rock/flint, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"oF" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/swamp) +"oX" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/swamp) +"pl" = ( +/obj/structure/drying_rack/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"rP" = ( +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/mud, +/area/shaded_hills/outside/swamp) +"sj" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/river/swamp) +"sn" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/river/swamp) +"tp" = ( +/turf/floor/barren, +/area/shaded_hills/outside/swamp) +"vz" = ( +/obj/structure/wall_sconce/lantern{ + dir = 8; + start_lit = 1 + }, +/obj/structure/table/end/alt/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"vZ" = ( +/turf/floor/mud/water, +/area/shaded_hills/caves/river/swamp) +"wv" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4 + }, +/turf/floor/mud, +/area/shaded_hills/outside/swamp) +"xr" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/swamp) +"yi" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/unexplored/swamp) +"BC" = ( +/turf/floor/mud, +/area/shaded_hills/outside/river/swamp) +"BF" = ( +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"BY" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/mud, +/area/shaded_hills/outside/swamp) +"Dh" = ( +/obj/item/stool/rustic, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"Do" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/unexplored/swamp) +"Ev" = ( +/turf/wall/log/walnut, +/area/shaded_hills/witch_hut) +"EI" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/swamp) +"Hi" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/teapot, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/item/chems/glass/bucket/wood, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"Ic" = ( +/turf/floor/clay, +/area/shaded_hills/outside/river/swamp) +"KA" = ( +/obj/abstract/landmark/start/shaded_hills/herbalist, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"LF" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/swamp) +"Ma" = ( +/turf/floor/barren, +/area/shaded_hills/caves/swamp) +"OM" = ( +/obj/abstract/landmark/start/shaded_hills/herbalist, +/turf/floor/mud, +/area/shaded_hills/outside/swamp) +"SE" = ( +/obj/structure/door/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"Ty" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/mud, +/area/shaded_hills/outside/swamp) +"TA" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/swamp/poi) +"TD" = ( +/turf/floor/grass, +/area/shaded_hills/outside/swamp) +"TR" = ( +/obj/structure/table/desk/ebony, +/obj/item/chems/glass/mortar, +/obj/item/rock/basalt, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"Vl" = ( +/obj/structure/wall_sconce/lantern{ + dir = 4; + start_lit = 1 + }, +/obj/structure/closet/crate/chest/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) +"VA" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/witch_hut) +"Xc" = ( +/turf/floor/grass, +/area/shaded_hills/outside/river/swamp) +"Xt" = ( +/turf/floor/mud, +/area/shaded_hills/outside/swamp) +"Yn" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/caves/river/swamp) +"YX" = ( +/obj/structure/bed/simple/ebony, +/obj/item/bedsheet/furs, +/obj/abstract/landmark/start/shaded_hills/herbalist, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/witch_hut) + +(1,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(2,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(3,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(4,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(5,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(6,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(7,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oX +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(8,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(9,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +kZ +TD +oF +oF +oF +oF +oF +oF +oF +"} +(10,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(11,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TD +TD +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(12,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +Yn +Yn +vZ +lZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(13,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +Yn +Yn +vZ +vZ +lZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(14,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +Yn +Yn +vZ +vZ +vZ +lZ +lZ +LF +LF +LF +LF +tp +tp +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(15,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +Yn +vZ +vZ +vZ +lZ +lZ +Ma +lZ +Ma +Ma +tp +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(16,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +vZ +Yn +Yn +vZ +vZ +LF +LF +LF +LF +Ma +Ma +Ma +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(17,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +Ma +Ma +Ma +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(18,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +vZ +sj +sj +sj +sj +sj +sj +sj +sj +vZ +vZ +vZ +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +Ma +Ma +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(19,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +vZ +vZ +sj +sj +sj +sj +sj +sj +vZ +vZ +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +Ma +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(20,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +Yn +Yn +vZ +sj +sj +sj +sj +vZ +vZ +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(21,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +vZ +Yn +Yn +vZ +sj +sj +vZ +vZ +vZ +Yn +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(22,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +vZ +Yn +Yn +Yn +vZ +vZ +vZ +Yn +Yn +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(23,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +vZ +Yn +Yn +Yn +Yn +Yn +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(24,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +vZ +Yn +Yn +Yn +Yn +vZ +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(25,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +vZ +vZ +vZ +vZ +Yn +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(26,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +vZ +vZ +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(27,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +vZ +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(28,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(29,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(30,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(31,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(32,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(33,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(34,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +vZ +Yn +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(35,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(36,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(37,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +vZ +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(38,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +vZ +Yn +Yn +vZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(39,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +vZ +Yn +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(40,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +vZ +vZ +vZ +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(41,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +vZ +lZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(42,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +vZ +lZ +lZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(43,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +LF +lZ +lZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(44,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +sj +lZ +lZ +lZ +LF +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(45,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +sj +yi +yi +lZ +lZ +lZ +LF +LF +LF +LF +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(46,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +sj +sj +yi +yi +yi +yi +lZ +lZ +lZ +lZ +lZ +lZ +lZ +LF +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(47,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +sj +sj +yi +yi +yi +yi +yi +yi +lZ +lZ +lZ +lZ +lZ +Ma +Ma +Ma +Ma +LF +LF +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(48,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +lZ +lZ +Ma +Ma +Ma +Ma +Ma +Ma +Ma +Ma +Ma +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(49,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +lZ +lZ +Ma +Ma +Ma +Ma +LF +LF +LF +Ma +Ma +Ma +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(50,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +lZ +Ma +Ma +Ma +Ma +Ma +Ma +LF +Ma +Ma +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(51,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +lZ +Ma +Ma +Ma +Ma +Ma +Ma +Ma +Ma +Ma +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(52,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +lZ +lZ +Ma +Ma +Ma +Ma +Ma +Ma +Ma +Ma +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(53,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +lZ +lZ +lZ +lZ +Ma +Ma +Ma +Ma +Ma +Ma +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(54,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +lZ +lZ +lZ +lZ +lZ +lZ +lZ +lZ +Ma +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(55,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +lZ +lZ +lZ +yi +yi +lZ +lZ +lZ +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(56,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +lZ +lZ +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +wv +Xt +rP +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(57,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +lZ +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Ev +Ev +Ev +Ev +BF +VA +VA +Xt +TD +TD +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(58,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +aM +vz +YX +Ev +bg +ll +VA +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(59,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Ev +cS +bg +SE +bg +bg +Ev +Xt +Xt +Xt +Xt +OM +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(60,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Ev +Ev +Ev +Ev +bg +Hi +aM +Xt +BY +lE +BY +BY +lE +BY +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(61,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Ev +TR +bg +bg +bg +KA +Ev +Xt +BY +lE +BY +BY +lE +BY +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(62,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Ev +fG +Dh +pl +Vl +nK +Ev +Xt +BY +lE +BY +BY +lE +BY +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(63,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Ev +Ev +aM +Ev +Ev +Ev +Ev +Xt +BY +lE +BY +BY +lE +BY +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(64,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BY +lE +BY +BY +lE +BY +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(65,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(66,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(67,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(68,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(69,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(70,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(71,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(72,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(73,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(74,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(75,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(76,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(77,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(78,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(79,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +Xt +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(80,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(81,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +tp +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(82,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +tp +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(83,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +tp +Xt +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(84,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(85,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +tp +tp +tp +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(86,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +yi +tp +tp +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(87,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +yi +yi +tp +tp +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(88,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +yi +tp +tp +tp +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(89,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +yi +yi +tp +tp +tp +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(90,1,1) = {" +Do +Do +Do +Do +Do +Do +Do +yi +tp +tp +tp +tp +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(91,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +tp +tp +xr +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(92,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +xr +xr +xr +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(93,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(94,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(95,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(96,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +cE +cE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(97,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(98,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +cE +cE +cE +BC +Xt +Xt +lE +lE +lE +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(99,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +hT +cE +cE +cE +BC +Xt +Xt +Xt +lE +lE +lE +lE +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(100,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +hT +hT +cE +cE +cE +BC +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(101,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +hT +cE +cE +cE +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(102,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +hT +hT +cE +cE +cE +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Ty +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(103,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +cE +cE +cE +cE +hT +hT +cE +cE +cE +BC +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(104,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +hT +cE +cE +cE +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(105,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +hT +hT +cE +cE +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(106,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +hT +hT +cE +cE +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(107,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +cE +cE +cE +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(108,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +cE +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(109,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(110,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(111,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(112,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(113,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(114,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(115,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +TD +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +Ic +BC +BC +BC +BC +BC +BC +BC +BC +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(116,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +TD +Xt +Xt +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +Ic +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(117,1,1) = {" +oF +oF +oF +oF +oF +oF +oF +Xt +Xt +Xt +Xt +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +cE +cE +cE +cE +cE +Ic +Ic +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xc +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(118,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +cE +cE +Ic +Ic +Ic +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xc +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(119,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +BC +Ic +Ic +Ic +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +cE +Ic +Ic +Ic +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xc +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(120,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Ic +Ic +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +cE +cE +Ic +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xc +Xc +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(121,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +Ic +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xc +Xc +Xc +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(122,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +Ic +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(123,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +Ic +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(124,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(125,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(126,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(127,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(128,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +hT +hT +hT +cE +cE +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(129,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +hT +cE +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(130,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +cE +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(131,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +cE +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +hT +hT +hT +hT +cE +hT +hT +hT +hT +hT +cE +cE +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(132,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +BC +BC +BC +BC +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(133,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +BC +BC +BC +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(134,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +BC +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(135,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(136,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(137,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TA +TA +TA +TA +TA +TA +TA +TA +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(138,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +cE +cE +cE +cE +cE +cE +cE +cE +Ic +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(139,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +BC +cE +cE +cE +Ic +Ic +Ic +Ic +cE +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(140,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Ic +Ic +Ic +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(141,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Ic +Ic +Ic +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +EI +EI +EI +EI +EI +EI +EI +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(142,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Ic +Ic +cE +cE +cE +cE +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(143,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +Xc +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +BC +Ic +Ic +cE +cE +cE +hT +hT +hT +hT +hT +hT +hT +cE +cE +cE +cE +BC +BC +BC +BC +BC +Xt +Xt +Xt +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +TD +oF +oF +oF +oF +oF +oF +oF +"} +(144,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(145,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(146,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(147,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(148,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(149,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} +(150,1,1) = {" +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +sn +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +oF +"} diff --git a/maps/shaded_hills/shaded_hills-woods.dmm b/maps/shaded_hills/shaded_hills-woods.dmm new file mode 100644 index 000000000000..b1884d02ba86 --- /dev/null +++ b/maps/shaded_hills/shaded_hills-woods.dmm @@ -0,0 +1,23078 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"af" = ( +/obj/abstract/landmark/start/shaded_hills/traveller/learned, +/turf/floor/path/basalt, +/area/shaded_hills/outside/woods) +"bL" = ( +/obj/abstract/landmark/latejoin, +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/woods) +"cN" = ( +/obj/structure/table/desk/dresser/ebony, +/obj/structure/wall_sconce/lantern{ + start_lit = 1 + }, +/obj/item/candelabra/filled{ + pixel_y = 9 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"dp" = ( +/turf/wall/log/walnut, +/area/shaded_hills/outside/river/woods) +"eJ" = ( +/obj/abstract/landmark/start/shaded_hills/forester, +/turf/floor/path/basalt, +/area/shaded_hills/outside/river/woods) +"eR" = ( +/turf/floor/barren, +/area/shaded_hills/outside/woods) +"fw" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/river/woods) +"gQ" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/unexplored/woods) +"hT" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river/lake) +"ix" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/woods) +"jk" = ( +/obj/structure/meat_hook, +/turf/floor/dirt, +/area/shaded_hills/outside/river/woods) +"kx" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/river/woods) +"kZ" = ( +/obj/abstract/level_data_spawner/shaded_hills_woods, +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/river/woods) +"lb" = ( +/turf/wall/brick/basalt, +/area/shaded_hills/forester_hut) +"lC" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/woods) +"lU" = ( +/turf/floor/dirt, +/area/shaded_hills/outside/woods) +"ma" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/river/lake) +"mo" = ( +/obj/structure/door/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"nl" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/river/woods) +"oA" = ( +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = 5 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"pu" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/river/lake) +"qy" = ( +/turf/floor/barren, +/area/shaded_hills/caves/woods) +"sS" = ( +/turf/floor/mud/water, +/area/shaded_hills/caves/river/woods) +"te" = ( +/turf/floor/rock/basalt, +/area/shaded_hills/outside/woods) +"uA" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/outside/river/woods) +"wD" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside/river/woods) +"xn" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/woods/poi) +"xr" = ( +/turf/floor/mud, +/area/shaded_hills/outside/river/lake) +"zp" = ( +/turf/floor/mud, +/area/shaded_hills/outside/river/woods) +"zq" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside/river/woods) +"Al" = ( +/turf/unsimulated/dark_filler, +/area/shaded_hills/caves/unexplored/woods) +"AN" = ( +/obj/structure/railing/mapped/wooden/walnut, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside/river/woods) +"Co" = ( +/obj/abstract/landmark/start/shaded_hills/traveller/learned, +/turf/floor/dirt, +/area/shaded_hills/outside/woods) +"DB" = ( +/obj/structure/drying_rack/ebony, +/turf/floor/dirt, +/area/shaded_hills/outside/river/woods) +"DX" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/caves/river/woods) +"En" = ( +/turf/floor/mud/water, +/area/shaded_hills/outside/river/woods) +"ES" = ( +/turf/floor/grass, +/area/shaded_hills/outside/river/woods) +"EV" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/woods) +"Fv" = ( +/turf/wall/natural/basalt/shaded_hills, +/area/shaded_hills/caves/woods) +"Fz" = ( +/obj/structure/chair/rustic{ + dir = 1; + pixel_y = 20; + pixel_x = -4 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"Gp" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut/shutter/open, +/area/shaded_hills/forester_hut) +"GB" = ( +/turf/floor/carpet/rustic, +/area/shaded_hills/forester_hut) +"HA" = ( +/turf/floor/grass, +/area/shaded_hills/outside/woods) +"IA" = ( +/obj/structure/fire_source/stove, +/obj/item/stack/material/log/mapped/walnut/ten, +/turf/floor/path/herringbone/basalt, +/area/shaded_hills/forester_hut) +"Jd" = ( +/turf/floor/path/basalt, +/area/shaded_hills/outside/woods) +"Jz" = ( +/obj/structure/bed/simple/ebony, +/obj/item/bedsheet/furs, +/obj/abstract/landmark/start/shaded_hills/forester, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"JI" = ( +/obj/structure/railing/mapped/wooden/walnut{ + dir = 1 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/outside/river/woods) +"JJ" = ( +/obj/structure/table/end/alt/ebony, +/obj/item/stack/material/bundle/grass/dry{ + amount = 5 + }, +/obj/item/fishing_rod, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"LJ" = ( +/turf/floor/path/running_bond/basalt, +/area/shaded_hills/outside/woods) +"Md" = ( +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"My" = ( +/turf/floor/grass, +/area/shaded_hills/outside/river/lake) +"MR" = ( +/obj/structure/coatrack/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"MU" = ( +/obj/structure/table/desk/ebony, +/obj/item/whetstone, +/obj/item/bladed/knife/iron, +/turf/floor/carpet/rustic, +/area/shaded_hills/forester_hut) +"Oi" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"PO" = ( +/obj/abstract/force_fluid_flow/north, +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river/lake) +"SD" = ( +/obj/structure/travois/walnut, +/turf/floor/dirt, +/area/shaded_hills/outside/river/woods) +"SI" = ( +/turf/wall/wattle/daubed/plastered/framed/walnut, +/area/shaded_hills/forester_hut) +"TC" = ( +/obj/item/horseshoe/hung{ + pixel_y = 42 + }, +/obj/item/towel/doormat/flat{ + dir = 1 + }, +/turf/floor/path/basalt, +/area/shaded_hills/outside/river/woods) +"TP" = ( +/obj/structure/table/desk/dresser/ebony, +/obj/item/candelabra/filled{ + pixel_y = 9 + }, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"Uz" = ( +/obj/effect/departure_signpost/north, +/turf/floor/dirt, +/area/shaded_hills/outside/woods) +"VA" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/path/basalt, +/area/shaded_hills/outside/woods) +"Wa" = ( +/obj/structure/divider/extended/wood/ebony, +/turf/floor/wood/rough/walnut, +/area/shaded_hills/forester_hut) +"Wb" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/barren, +/area/shaded_hills/caves/woods) +"Wo" = ( +/obj/abstract/force_fluid_flow/north, +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river/woods) +"Xt" = ( +/turf/floor/mud, +/area/shaded_hills/caves/woods) +"YB" = ( +/obj/abstract/landmark/latejoin, +/turf/floor/dirt, +/area/shaded_hills/outside/woods) +"YO" = ( +/turf/unsimulated/mask, +/area/shaded_hills/outside/river/woods) +"Zo" = ( +/turf/floor/mud/water/deep, +/area/shaded_hills/outside/river/woods) +"Zs" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/dirt, +/area/shaded_hills/outside/river/woods) +"ZO" = ( +/obj/abstract/landmark/start/shaded_hills/traveller, +/turf/floor/grass, +/area/shaded_hills/outside/woods) + +(1,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(2,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(3,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(4,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(5,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(6,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(7,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +lC +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +ix +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +fw +"} +(8,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +DX +DX +DX +DX +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +fw +fw +fw +fw +fw +fw +fw +"} +(9,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +sS +DX +DX +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +kZ +nl +fw +fw +fw +fw +fw +fw +fw +"} +(10,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +eR +eR +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +DX +DX +DX +DX +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +fw +fw +fw +fw +fw +fw +fw +"} +(11,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +YB +Uz +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +eR +eR +eR +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +DX +DX +DX +DX +sS +sS +sS +nl +nl +nl +nl +nl +sS +sS +sS +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +sS +sS +sS +sS +sS +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +fw +fw +fw +fw +fw +fw +fw +"} +(12,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +VA +Co +lU +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +eR +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +DX +DX +DX +DX +DX +DX +DX +sS +sS +sS +sS +sS +sS +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +sS +sS +sS +sS +DX +DX +DX +DX +DX +sS +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +sS +sS +fw +fw +fw +fw +fw +fw +fw +"} +(13,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +bL +LJ +LJ +Jd +Jd +lU +lU +lU +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +sS +DX +DX +DX +DX +DX +DX +DX +DX +DX +DX +DX +DX +sS +sS +sS +sS +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +DX +DX +DX +nl +nl +DX +DX +sS +sS +sS +DX +nl +nl +nl +sS +sS +nl +nl +nl +nl +nl +nl +sS +DX +fw +fw +fw +fw +fw +fw +fw +"} +(14,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +VA +af +LJ +LJ +LJ +LJ +LJ +LJ +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Xt +Xt +Xt +Fv +Fv +Fv +Fv +sS +sS +sS +sS +sS +sS +sS +sS +sS +sS +sS +DX +DX +DX +DX +DX +DX +DX +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +DX +DX +DX +nl +DX +DX +DX +DX +sS +gQ +gQ +gQ +DX +DX +DX +nl +DX +DX +DX +DX +sS +sS +sS +sS +DX +DX +fw +fw +fw +fw +fw +fw +fw +"} +(15,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +YB +lU +lU +lU +lU +lU +lU +lU +Jd +LJ +LJ +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +qy +qy +qy +qy +Xt +Xt +Xt +Fv +Fv +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Fv +Fv +sS +sS +sS +DX +DX +DX +DX +DX +DX +nl +sS +sS +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +nl +sS +DX +DX +sS +sS +sS +sS +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +DX +DX +DX +sS +sS +DX +DX +DX +DX +DX +DX +sS +fw +fw +fw +fw +fw +fw +fw +"} +(16,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +EV +EV +EV +EV +lU +lU +lU +lU +Jd +LJ +LJ +LJ +EV +lU +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +qy +qy +qy +qy +qy +Fv +qy +qy +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +sS +DX +nl +nl +nl +nl +sS +sS +sS +nl +nl +nl +nl +nl +nl +nl +sS +sS +DX +DX +sS +sS +sS +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +sS +sS +sS +sS +sS +sS +sS +sS +sS +fw +fw +fw +fw +fw +fw +fw +"} +(17,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +lU +lU +LJ +LJ +LJ +LJ +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +qy +qy +Xt +Xt +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +DX +DX +DX +DX +DX +DX +sS +sS +DX +DX +DX +sS +sS +DX +DX +DX +DX +DX +sS +sS +sS +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +sS +sS +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(18,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +EV +EV +xn +xn +xn +EV +EV +EV +EV +lU +lU +lU +lU +Jd +Jd +LJ +LJ +LJ +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +lU +lU +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +qy +qy +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +sS +sS +sS +sS +sS +DX +DX +DX +DX +sS +DX +DX +DX +DX +sS +sS +sS +sS +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(19,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +Jd +Jd +LJ +LJ +LJ +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +eR +eR +eR +eR +eR +qy +qy +qy +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Xt +Xt +Xt +sS +sS +sS +sS +sS +sS +sS +sS +sS +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(20,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +lU +Jd +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +eR +qy +qy +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Xt +Xt +Xt +Xt +Xt +Xt +Xt +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(21,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Xt +Xt +Xt +Xt +Xt +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(22,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +Jd +lU +lU +lU +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Xt +Xt +Xt +Xt +Xt +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(23,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +Jd +EV +LJ +Jd +Jd +lU +lU +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Xt +Xt +Xt +Xt +Xt +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(24,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +EV +EV +EV +Jd +Jd +lU +lU +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +Fv +qy +qy +qy +Xt +Xt +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(25,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +Jd +lU +lU +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +Fv +Fv +Fv +Fv +Fv +Fv +qy +qy +qy +qy +Xt +Xt +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(26,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +EV +LJ +Jd +Jd +lU +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +Fv +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +Xt +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(27,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +Jd +lU +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +qy +qy +qy +qy +qy +qy +qy +qy +qy +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(28,1,1) = {" +lC +lC +lC +lC +lC +lC +lC +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +Jd +lU +lU +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +qy +qy +qy +Wb +qy +qy +qy +qy +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(29,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +LJ +LJ +Jd +Jd +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +qy +qy +qy +qy +qy +qy +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(30,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +Jd +lU +lU +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +eR +qy +qy +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(31,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +lU +LJ +LJ +LJ +lU +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +qy +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(32,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +xr +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +lU +lU +LJ +LJ +Jd +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(33,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +ma +xr +xr +My +My +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +lU +EV +EV +EV +EV +lU +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(34,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +ma +ma +xr +xr +My +My +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +EV +EV +EV +Jd +EV +lU +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +eR +eR +qy +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(35,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +ma +ma +ma +xr +xr +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +LJ +LJ +Jd +lU +lU +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(36,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +ma +ma +ma +ma +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +LJ +LJ +Jd +lU +lU +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(37,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +ma +ma +ma +xr +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +Jd +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(38,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +ma +ma +ma +xr +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +LJ +Jd +Jd +lU +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +lU +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(39,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +ma +ma +ma +xr +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +LJ +LJ +Jd +lU +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(40,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +LJ +LJ +Jd +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(41,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +My +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +LJ +LJ +Jd +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(42,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +lU +LJ +Jd +Jd +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(43,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +lU +LJ +Jd +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(44,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +LJ +LJ +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(45,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +LJ +xn +xn +xn +xn +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(46,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +EV +xn +xn +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(47,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +xn +xn +xn +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(48,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +xn +xn +xn +EV +LJ +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(49,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +lU +LJ +Jd +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(50,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +LJ +LJ +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(51,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +lU +LJ +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(52,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +EV +lU +lU +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(53,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +LJ +LJ +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(54,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +LJ +Jd +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(55,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +LJ +EV +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(56,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +EV +EV +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(57,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +LJ +EV +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(58,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +LJ +Jd +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(59,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(60,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +LJ +Jd +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(61,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +ZO +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(62,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +LJ +Jd +lU +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(63,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +LJ +EV +lU +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(64,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(65,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(66,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +lU +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +lU +eR +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(67,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +LJ +LJ +lU +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +lU +eR +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(68,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +LJ +Jd +lU +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +eR +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(69,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +Jd +LJ +Jd +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(70,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +Jd +Jd +lU +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(71,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +lU +lU +lU +Jd +Jd +lU +lU +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(72,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +lU +lU +lU +LJ +Jd +lU +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(73,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +lU +lU +Jd +LJ +Jd +Jd +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(74,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +Jd +EV +Jd +Jd +lU +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +lU +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(75,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +Jd +EV +EV +Jd +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(76,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +LJ +EV +Jd +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(77,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +Jd +Jd +Jd +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(78,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +Jd +LJ +LJ +lU +lU +EV +EV +EV +EV +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +gQ +gQ +gQ +gQ +gQ +gQ +te +te +te +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(79,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +xr +My +My +My +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +lU +lU +lU +eR +eR +gQ +gQ +gQ +gQ +te +te +te +te +eR +te +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(80,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +xr +xr +xr +xr +xr +My +My +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +lU +lU +Jd +LJ +LJ +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +eR +eR +eR +eR +eR +eR +eR +eR +eR +te +te +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(81,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +xr +My +My +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +lU +eR +lU +lU +lU +lU +lU +eR +te +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(82,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +lU +lU +EV +EV +EV +EV +EV +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +lU +lU +lU +lU +te +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(83,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +Jd +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +eR +eR +lU +lU +eR +te +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(84,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +xr +My +My +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +Jd +Jd +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +eR +lU +lU +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(85,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +Jd +LJ +LJ +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(86,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +LJ +LJ +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(87,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +lU +lU +LJ +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +eR +eR +te +gQ +gQ +gQ +gQ +gQ +gQ +gQ +gQ +Al +Al +Al +Al +Al +Al +Al +"} +(88,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +Jd +Jd +Jd +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +te +te +gQ +gQ +gQ +gQ +te +te +lC +lC +lC +lC +lC +lC +lC +"} +(89,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +LJ +LJ +LJ +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +te +te +te +te +te +te +eR +lC +lC +lC +lC +lC +lC +lC +"} +(90,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +Jd +LJ +LJ +Jd +Jd +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +eR +eR +eR +te +te +te +te +lU +lU +lC +lC +lC +lC +lC +lC +lC +"} +(91,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +Jd +LJ +Jd +Jd +Jd +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +eR +eR +lU +lU +HA +lC +lC +lC +lC +lC +lC +lC +"} +(92,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +LJ +LJ +LJ +Jd +Jd +Jd +lU +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +lU +lU +lU +lU +lC +lC +lC +lC +lC +lC +lC +"} +(93,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +lU +LJ +LJ +LJ +LJ +EV +EV +EV +EV +lU +lU +lU +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +lU +lU +lU +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(94,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +lU +Jd +Jd +LJ +LJ +EV +EV +EV +Jd +Jd +lU +lU +lU +lU +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +lU +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(95,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +lU +lU +lU +EV +EV +EV +LJ +LJ +Jd +lU +lU +lU +lU +lU +lU +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lU +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(96,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +xr +My +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +EV +EV +EV +Jd +LJ +Jd +LJ +LJ +LJ +Jd +lU +lU +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(97,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +Jd +LJ +Jd +LJ +LJ +Jd +lU +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(98,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +lU +lU +Jd +Jd +LJ +LJ +Jd +Jd +lU +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(99,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +My +My +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +Jd +Jd +Jd +LJ +LJ +lU +lU +lU +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(100,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +Jd +Jd +LJ +LJ +Jd +lU +lU +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(101,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +xn +xn +xn +xn +xn +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +Jd +Jd +Jd +Jd +Jd +lU +lU +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(102,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +kx +kx +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +Jd +LJ +LJ +Jd +lU +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(103,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +kx +zq +zq +kx +kx +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +lU +lU +lU +Jd +Jd +Jd +lU +lU +lU +HA +lU +lC +lC +lC +lC +lC +lC +lC +"} +(104,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +ES +ES +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +kx +kx +kx +kx +zq +kx +ES +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +lU +lU +LJ +LJ +LJ +Jd +lU +Jd +lC +lC +lC +lC +lC +lC +lC +"} +(105,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +dp +JI +AN +dp +zp +zq +kx +ES +ES +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +HA +lU +lU +lU +lU +lU +lU +Jd +LJ +LJ +lC +lC +lC +lC +lC +lC +lC +"} +(106,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +JI +AN +zp +zp +zp +zq +zq +ES +ES +ES +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +lU +lU +Jd +Jd +lU +HA +HA +HA +lU +lU +Jd +lC +lC +lC +lC +lC +lC +lC +"} +(107,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +JI +AN +zp +zp +zp +zp +kx +zq +kx +ES +ES +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +lU +lU +Jd +lU +lU +HA +HA +HA +HA +HA +HA +lU +lC +lC +lC +lC +lC +lC +lC +"} +(108,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +My +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +JI +AN +En +zp +zp +zp +zp +kx +kx +kx +ES +ES +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +EV +EV +EV +EV +HA +lU +Jd +lU +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(109,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +xr +xr +xr +xr +HA +HA +HA +HA +HA +HA +ZO +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +En +En +En +En +En +En +dp +JI +AN +dp +En +zp +zp +zp +zp +ES +zq +kx +kx +ES +HA +HA +HA +HA +HA +HA +HA +HA +HA +EV +EV +EV +EV +EV +HA +lU +lU +lU +lU +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(110,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +xr +xr +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +En +En +En +En +JI +AN +En +En +En +zp +zp +zp +zp +kx +zq +zq +kx +kx +kx +HA +HA +lU +lU +HA +HA +HA +lU +HA +HA +lU +lU +lU +lU +Jd +lU +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(111,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +xr +xr +xr +zp +ES +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +En +JI +AN +En +En +En +zp +zp +zp +zp +zp +ES +kx +zq +zq +zq +kx +lU +Jd +Jd +lU +lU +lU +Jd +lU +lU +Jd +Jd +Jd +lU +lU +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(112,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +xr +xr +xr +zp +ES +ES +HA +HA +HA +HA +HA +HA +HA +HA +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +En +En +En +En +En +En +En +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +JI +AN +En +En +En +En +En +zp +zp +zp +zp +ES +kx +kx +kx +ES +ES +kx +Jd +Jd +Jd +lU +lU +Jd +Jd +lU +lU +lU +lU +HA +HA +ES +ES +ES +ES +ES +ES +ES +ES +ES +HA +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(113,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +xr +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +dp +JI +AN +dp +En +En +En +En +En +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +kx +kx +lU +HA +HA +lU +lU +HA +HA +HA +HA +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +HA +HA +lC +lC +lC +lC +lC +lC +lC +"} +(114,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +Zo +En +En +Zo +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +JI +AN +Zo +En +En +En +En +En +En +En +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(115,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +zp +zp +zp +zp +zp +zp +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +JI +AN +Zo +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(116,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +JI +AN +Wo +Zo +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +zp +zp +zp +zp +zp +zp +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(117,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +dp +JI +AN +dp +Wo +Zo +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +uA +uA +uA +uA +uA +uA +uA +"} +(118,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +En +En +En +En +Zo +Wo +Wo +Wo +Wo +JI +AN +Wo +Wo +Wo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +uA +uA +uA +uA +uA +uA +uA +"} +(119,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +Zo +Zo +Wo +Wo +JI +AN +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +uA +uA +uA +uA +uA +uA +uA +"} +(120,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +Zo +Zo +JI +AN +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +uA +uA +uA +uA +uA +uA +uA +"} +(121,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +dp +JI +AN +dp +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(122,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +JI +AN +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +Zo +Zo +En +En +En +En +En +En +En +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(123,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +ES +ES +zp +zp +zp +ES +ES +zp +zp +zp +zp +zp +zp +En +En +En +En +En +JI +AN +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +Zo +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +Zo +En +En +En +En +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(124,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +kx +kx +ES +zp +zp +zp +zp +zp +En +En +En +En +JI +AN +En +En +En +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +En +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(125,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +hT +hT +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +zp +zp +zp +zp +zp +ES +ES +ES +YO +ES +ES +kx +kx +kx +kx +kx +kx +ES +zp +zp +zp +zp +zp +zp +En +dp +JI +AN +dp +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +Zo +En +En +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +uA +uA +uA +uA +uA +uA +uA +"} +(126,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +hT +hT +hT +ma +ma +ma +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +zp +zp +zp +zp +ES +ES +ES +YO +YO +ES +SI +SI +SI +SI +SI +SI +SI +kx +kx +zp +zp +zp +zp +zp +zp +zp +wD +wD +En +En +En +En +En +En +En +En +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Zo +Zo +Zo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +uA +uA +uA +uA +uA +uA +uA +"} +(127,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +hT +hT +hT +En +En +En +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +ES +YO +YO +YO +ES +SI +TP +Jz +Wa +Jz +cN +SI +Zs +zq +zq +zq +zp +zp +zp +zq +zq +zq +zp +zp +En +En +En +En +En +En +En +En +En +En +Zo +Zo +Zo +Zo +En +En +En +Zo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +Wo +Wo +uA +uA +uA +uA +uA +uA +uA +"} +(128,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +Zo +Zo +Zo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +ES +ES +YO +YO +YO +ES +Gp +JJ +GB +GB +GB +Md +mo +TC +zq +eJ +zq +zq +zq +zq +zq +zq +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +Zo +Zo +Wo +Wo +Wo +uA +uA +uA +uA +uA +uA +uA +"} +(129,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +YO +YO +YO +YO +YO +ES +SI +Oi +GB +MU +GB +MR +Gp +SD +kx +kx +ES +zq +zq +ES +ES +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +Zo +Zo +Wo +uA +uA +uA +uA +uA +uA +uA +"} +(130,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Wo +Zo +Zo +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +YO +YO +YO +YO +YO +ES +ES +SI +SI +oA +Md +Fz +IA +lb +DB +kx +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +En +Zo +uA +uA +uA +uA +uA +uA +uA +"} +(131,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +Wo +Wo +Zo +Zo +Zo +Wo +Wo +Wo +Zo +Zo +Zo +En +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +ES +YO +YO +YO +YO +YO +ES +ES +kx +SI +SI +Gp +SI +lb +lb +jk +kx +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +En +En +En +En +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(132,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +PO +PO +PO +PO +PO +hT +hT +Zo +Zo +En +En +En +Zo +Zo +Zo +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +ES +ES +ES +YO +YO +YO +YO +ES +ES +ES +ES +ES +kx +kx +kx +kx +kx +kx +ES +ES +ES +ES +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +zp +zp +zp +zp +En +En +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(133,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +PO +PO +PO +PO +hT +hT +hT +hT +hT +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +kx +kx +ES +kx +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +En +En +uA +uA +uA +uA +uA +uA +uA +"} +(134,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +PO +hT +hT +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +ES +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +uA +uA +uA +uA +uA +uA +uA +"} +(135,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +zp +zp +zp +uA +uA +uA +uA +uA +uA +uA +"} +(136,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +En +En +En +zp +zp +zp +En +En +En +En +En +En +En +En +En +En +zp +zp +zp +zp +zp +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(137,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +En +En +zp +zp +zp +zp +zp +zp +zp +En +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(138,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +En +En +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(139,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +En +zp +zp +zp +zp +zp +zp +ES +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(140,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +zp +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(141,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +zp +zp +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(142,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +xr +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +ES +ES +ES +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +ES +ES +YO +YO +YO +YO +YO +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(143,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +hT +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +ma +xr +zp +zp +zp +zp +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +ES +uA +uA +uA +uA +uA +uA +uA +"} +(144,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} +(145,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} +(146,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} +(147,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} +(148,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} +(149,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} +(150,1,1) = {" +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +pu +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +uA +"} diff --git a/maps/shaded_hills/shaded_hills.dm b/maps/shaded_hills/shaded_hills.dm new file mode 100644 index 000000000000..0d7f2b5f7708 --- /dev/null +++ b/maps/shaded_hills/shaded_hills.dm @@ -0,0 +1,58 @@ +#if !defined(USING_MAP_DATUM) + + #include "../../mods/content/matchmaking/_matchmaking.dme" + #include "../../mods/content/dungeon_loot/_dungeon_loot.dme" + #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" + #include "../../mods/content/scaling_descriptors.dm" + #include "../../mods/species/drakes/_drakes.dme" // include before _fantasy.dme so overrides work + #include "../../mods/content/item_sharpening/_item_sharpening.dme" + #include "../../mods/content/fantasy/_fantasy.dme" + #include "../../mods/content/blacksmithy/_blacksmithy.dme" + + #include "areas/_areas.dm" + #include "areas/downlands.dm" + #include "areas/grassland.dm" + #include "areas/swamp.dm" + #include "areas/woods.dm" + + #include "jobs/_jobs.dm" + #include "jobs/caves.dm" + #include "jobs/inn.dm" + #include "jobs/shrine.dm" + #include "jobs/visitors.dm" + #include "jobs/wilderness.dm" + + #include "levels/_levels.dm" + #include "levels/random_map.dm" + #include "levels/strata.dm" + + #include "outfits/_outfits.dm" + #include "outfits/caves.dm" + #include "outfits/inn.dm" + #include "outfits/shrine.dm" + #include "outfits/visitors.dm" + #include "outfits/wilderness.dm" + + #include "shaded_hills_currency.dm" + #include "shaded_hills_events.dm" + #include "shaded_hills_locks.dm" + #include "shaded_hills_map.dm" + #include "shaded_hills_skills.dm" + #include "shaded_hills_testing.dm" + #include "shaded_hills_turfs.dm" + + // Caverns are below grassland and must be compiled in that order for multiz. + #include "shaded_hills-caverns.dmm" + #include "shaded_hills-grassland.dmm" + // Dungeon is under inn and must be compiled in that order for multiz. + #include "shaded_hills-dungeon.dmm" + #include "shaded_hills-inn.dmm" + // Other levels are lateral and compile order doesn't matter. + #include "shaded_hills-swamp.dmm" + #include "shaded_hills-woods.dmm" + + #define USING_MAP_DATUM /datum/map/shaded_hills + +#elif !defined(MAP_OVERRIDE) + #warn A map has already been included, ignoring Shaded Hills +#endif diff --git a/maps/shaded_hills/shaded_hills_currency.dm b/maps/shaded_hills/shaded_hills_currency.dm new file mode 100644 index 000000000000..7c3efd6cbea4 --- /dev/null +++ b/maps/shaded_hills/shaded_hills_currency.dm @@ -0,0 +1,12 @@ +/datum/map/shaded_hills + starting_cash_choices = list( + /decl/starting_cash_choice/cash, + /decl/starting_cash_choice/none + ) + default_currency = /decl/currency/imperial + salary_modifier = 0.05 // turn the 300-400 base into 15-20 base + +/// Functionally identical to its parent type, but with a different name since it's not defined until later. +/decl/starting_cash_choice/none + name = "none" + uid = "starting_cash_none" diff --git a/maps/shaded_hills/shaded_hills_define.dm b/maps/shaded_hills/shaded_hills_define.dm new file mode 100644 index 000000000000..4c4bb5879157 --- /dev/null +++ b/maps/shaded_hills/shaded_hills_define.dm @@ -0,0 +1,57 @@ +/datum/map/shaded_hills + name = "shaded_hills" + full_name = "Shaded Hills" + path = "shaded_hills" + station_name = "Shaded Hills" + station_short = "Shaded Hills" + dock_name = "shaded heights" + boss_name = "the Splinter Kingdoms" + boss_short = "Splinter Kingdoms" + company_name = "whispers from the Deep" + company_short = "the Deep" + system_name = "Downlands" + default_spawn = /decl/spawnpoint/arrivals + allowed_latejoin_spawns = list( + /decl/spawnpoint/arrivals + ) + map_tech_level = MAP_TECH_LEVEL_MEDIEVAL + survival_box_choices = list() + passport_type = null + _available_backpacks = list( + /decl/backpack_outfit/sack, + /decl/backpack_outfit/backpack/crafted, + /decl/backpack_outfit/haversack + ) + lobby_tracks = list( + /decl/music_track/dhaka, + /decl/music_track/teller, + /decl/music_track/suonatore, + /decl/music_track/adventure, + ) + credit_sound = list( + 'sound/music/Miris-Magic-Dance.ogg' + ) + game_year = -914 // in 2024, the year should be 1110, roughly a century after the fall of the Imperial Aegis + security_state = /decl/security_state/none + + char_preview_bgstate_options = list( + "000", + "midgrey", + "FFF", + "wood" = /turf/floor/wood::color, + "mud", + "grass" = /turf/floor/grass::color, + "rock" = /turf/floor/rock/basalt::color, + "brick" = /turf/wall/brick/sandstone::color + ) + default_ui_style = /decl/ui_style/underworld + +/decl/backpack_outfit/sack + is_default = TRUE + +/datum/map/shaded_hills/get_map_info() + return "You're in the [station_name] of the [system_name], nestled between the mountains and the river and bisected by the decaying Queens' Road. On all sides, you are surrounded by untamed wilds, with only a small ruined fort, rebuilt into an inn, to the east as a sign of civilisation. \ + Far from the control of [boss_name], you are free to carve forward a path to survival for yourself and your comrades however you wish. Strike the earth!" + +/datum/map/shaded_hills/get_available_submap_archetypes() + return null // Return list of decl instances when relevant submaps exist. diff --git a/maps/shaded_hills/shaded_hills_events.dm b/maps/shaded_hills/shaded_hills_events.dm new file mode 100644 index 000000000000..cd2b3aa86739 --- /dev/null +++ b/maps/shaded_hills/shaded_hills_events.dm @@ -0,0 +1,20 @@ +/datum/map/shaded_hills + event_container_mundane = /datum/event_container/mundane/fantasy + event_container_moderate = /datum/event_container/moderate/fantasy + event_container_major = /datum/event_container/major/fantasy + +// TODO: more appropriate events. +/datum/event_container/mundane/fantasy + available_events = list( + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Nothing", /datum/event/nothing, 100) + ) + +/datum/event_container/moderate/fantasy + available_events = list( + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Nothing", /datum/event/nothing, 100) + ) + +/datum/event_container/major/fantasy + available_events = list( + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Nothing", /datum/event/nothing, 100) + ) diff --git a/maps/shaded_hills/shaded_hills_locks.dm b/maps/shaded_hills/shaded_hills_locks.dm new file mode 100644 index 000000000000..f6e769f507ec --- /dev/null +++ b/maps/shaded_hills/shaded_hills_locks.dm @@ -0,0 +1,35 @@ + +/obj/abstract/landmark/lock_preset/shaded_hills + name = "Shaded Hills locked door" + abstract_type = /obj/abstract/landmark/lock_preset/shaded_hills + lock_material = /decl/material/solid/metal/copper + +/obj/abstract/landmark/lock_preset/shaded_hills/inn_interior + name = "Shaded Hills locked door - inn interior" + lock_preset_id = "inn interior" + +/obj/abstract/landmark/lock_preset/shaded_hills/inn_exterior + name = "Shaded Hills locked door - inn exterior" + lock_preset_id = "inn exterior" + lock_material = /decl/material/solid/metal/iron + +/obj/abstract/landmark/lock_preset/shaded_hills/inn_backroom + name = "Shaded Hills locked door - inn back room" + lock_preset_id = "inn back room" + lock_material = /decl/material/solid/metal/silver + +/obj/abstract/landmark/lock_preset/shaded_hills/shrine + name = "Shaded Hills locked door - shrine" + lock_preset_id = "shrine" + +/obj/abstract/landmark/lock_preset/shaded_hills/farmhouse + name = "Shaded Hills locked door - farmhouse" + lock_preset_id = "farmhouse" + +/obj/abstract/landmark/lock_preset/shaded_hills/trader + name = "Shaded Hills locked door - general store" + lock_preset_id = "general store" + +/obj/abstract/landmark/lock_preset/shaded_hills/trader_stockroom + name = "Shaded Hills locked door - general store stockroom" + lock_preset_id = "general store stockroom" diff --git a/maps/shaded_hills/shaded_hills_map.dm b/maps/shaded_hills/shaded_hills_map.dm new file mode 100644 index 000000000000..59f2a26ce09a --- /dev/null +++ b/maps/shaded_hills/shaded_hills_map.dm @@ -0,0 +1,22 @@ +/datum/map/shaded_hills + default_liquid_fuel_type = /decl/material/liquid/oil + default_species = /decl/species/kobaloi::uid + loadout_categories = list( + /decl/loadout_category/fantasy/clothing, + /decl/loadout_category/fantasy/utility + ) + +/datum/map/shaded_hills/finalize_map_generation() + . = ..() + var/static/list/banned_weather = list( + /decl/state/weather/snow/medium, + /decl/state/weather/snow/heavy, + /decl/state/weather/snow + ) + var/datum/level_data/shadyhills = SSmapping.levels_by_id["shaded_hills_grassland"] + if(istype(shadyhills)) // if this is false, something has badly exploded + SSweather.setup_weather_system(shadyhills, banned_states = banned_weather) + +/decl/spawnpoint/arrivals + name = "Queens' Road" + spawn_announcement = null diff --git a/maps/shaded_hills/shaded_hills_skills.dm b/maps/shaded_hills/shaded_hills_skills.dm new file mode 100644 index 000000000000..a7a86be4c5e7 --- /dev/null +++ b/maps/shaded_hills/shaded_hills_skills.dm @@ -0,0 +1,15 @@ +// Removal of space skills +/datum/map/shaded_hills/get_available_skill_types() + . = ..() + . -= list( + SKILL_EVA, + SKILL_MECH, + SKILL_PILOT, + SKILL_COMPUTER, + SKILL_FORENSICS, + SKILL_ELECTRICAL, + SKILL_ATMOS, + SKILL_ENGINES, + SKILL_DEVICES, + SKILL_CONSTRUCTION, // Anything using this should be replaced with another skill. + ) diff --git a/maps/shaded_hills/shaded_hills_testing.dm b/maps/shaded_hills/shaded_hills_testing.dm new file mode 100644 index 000000000000..e13f0fffa547 --- /dev/null +++ b/maps/shaded_hills/shaded_hills_testing.dm @@ -0,0 +1,4 @@ +/datum/map/shaded_hills/New() + LAZYDISTINCTADD(area_coherency_test_exempted_root_areas, /area/shaded_hills/outside) + LAZYSET(apc_test_exempt_areas, /area/shaded_hills, (NO_SCRUBBER|NO_VENT|NO_APC)) + ..() diff --git a/maps/shaded_hills/shaded_hills_turfs.dm b/maps/shaded_hills/shaded_hills_turfs.dm new file mode 100644 index 000000000000..7684b39c1be8 --- /dev/null +++ b/maps/shaded_hills/shaded_hills_turfs.dm @@ -0,0 +1,8 @@ +/turf/wall/natural/basalt/shaded_hills + strata_override = /decl/strata/shaded_hills + +/turf/wall/natural/random/basalt/shaded_hills + strata_override = /decl/strata/shaded_hills + +/turf/wall/natural/random/high_chance/basalt/shaded_hills + strata_override = /decl/strata/shaded_hills diff --git a/maps/tradeship/hud.dmi b/maps/tradeship/hud.dmi new file mode 100644 index 000000000000..c0f438fff7a8 Binary files /dev/null and b/maps/tradeship/hud.dmi differ diff --git a/maps/tradeship/jobs/_goals.dm b/maps/tradeship/jobs/_goals.dm new file mode 100644 index 000000000000..ac7cc4422dcd --- /dev/null +++ b/maps/tradeship/jobs/_goals.dm @@ -0,0 +1,41 @@ +var/global/list/tradeship_paperwork_spawn_turfs = list() +var/global/list/tradeship_paperwork_end_areas = list() + +/obj/abstract/landmark/paperwork_spawn_tradeship + name = "Tradeship Paperwork Goal Spawn Point" + +/obj/abstract/landmark/paperwork_spawn_tradeship/Initialize() + ..() + var/turf/T = get_turf(src) + if(istype(T)) + global.tradeship_paperwork_spawn_turfs |= T + return INITIALIZE_HINT_QDEL + +/obj/abstract/landmark/paperwork_finish_tradeship + name = "Tradeship Paperwork Goal Finish Point" + +/obj/abstract/landmark/paperwork_finish_tradeship/Initialize() + ..() + var/turf/T = get_turf(src) + if(istype(T)) + var/area/A = get_area(T) + if(istype(A)) + global.tradeship_paperwork_end_areas |= A + return INITIALIZE_HINT_QDEL + +/datum/goal/department/paperwork/tradeship + paperwork_types = list(/obj/item/paperwork/tradeship) + signatory_job_list = list( + /datum/job/standard/captain/tradeship, + /datum/job/tradeship_first_mate + ) + +/datum/goal/department/paperwork/tradeship/get_paper_spawn_turfs() + return global.tradeship_paperwork_spawn_turfs + +/datum/goal/department/paperwork/tradeship/get_paper_end_areas() + return global.tradeship_paperwork_end_areas + +/obj/item/paperwork/tradeship + name = "\improper Tradehouse payroll paperwork" + desc = "A complex list of salaries, hours and tax withheld for Tradehouse workers this month." diff --git a/maps/tradeship/jobs/_jobs.dm b/maps/tradeship/jobs/_jobs.dm deleted file mode 100644 index 20c7a8259683..000000000000 --- a/maps/tradeship/jobs/_jobs.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/job/cyborg - supervisors = "your laws and the Captain" - total_positions = 1 - spawn_positions = 1 - alt_titles = list() - -/datum/job/assistant - title = "Deck Hand" - supervisors = "literally everyone, you bottom feeder" - outfit_type = /decl/hierarchy/outfit/job/tradeship/hand - alt_titles = list( - "Cook" = /decl/hierarchy/outfit/job/tradeship/hand/cook, - "Cargo Hand", - "Passenger") - hud_icon = "hudcargotechnician" diff --git a/maps/tradeship/jobs/civilian.dm b/maps/tradeship/jobs/civilian.dm new file mode 100644 index 000000000000..fe0f2d50ca66 --- /dev/null +++ b/maps/tradeship/jobs/civilian.dm @@ -0,0 +1,30 @@ +/datum/job/standard/assistant/tradeship + title = "Deck Hand" + supervisors = "literally everyone, you bottom feeder" + outfit_type = /decl/outfit/job/tradeship/hand + alt_titles = list( + "Cook" = /decl/outfit/job/tradeship/hand/cook, + "Cargo Hand", + "Passenger" + ) + event_categories = list(ASSIGNMENT_GARDENER, ASSIGNMENT_JANITOR) + +/datum/job/tradeship_helmsman + title = "Helmsman" + hud_icon = 'maps/tradeship/hud.dmi' + total_positions = 1 + spawn_positions = 1 + supervisors = "the Captain, so don't mess up!" + outfit_type = /decl/outfit/job/tradeship/hand + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_PILOT = SKILL_ADEPT + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX + ) + skill_points = 10 + department_types = list(/decl/department/civilian) + economic_power = 1 + access = list(access_bridge) + minimal_access = list(access_bridge) diff --git a/maps/tradeship/jobs/command.dm b/maps/tradeship/jobs/command.dm index da70f6880988..d4dd0bdff303 100644 --- a/maps/tradeship/jobs/command.dm +++ b/maps/tradeship/jobs/command.dm @@ -1,82 +1,66 @@ -/datum/job/tradeship_captain +/datum/job/standard/captain/tradeship title = "Captain" supervisors = "your profit margin, your conscience, and the Trademaster" - outfit_type = /decl/hierarchy/outfit/job/tradeship/captain + outfit_type = /decl/outfit/job/tradeship/captain min_skill = list( SKILL_LITERACY = SKILL_ADEPT, SKILL_WEAPONS = SKILL_ADEPT, SKILL_SCIENCE = SKILL_ADEPT, SKILL_PILOT = SKILL_ADEPT ) - max_skill = list( - SKILL_PILOT = SKILL_MAX, - SKILL_WEAPONS = SKILL_MAX - ) - skill_points = 30 - head_position = 1 - department_refs = list(DEPT_COMMAND) - total_positions = 1 - spawn_positions = 1 - selection_color = "#1d1d4f" - req_admin_notify = 1 - access = list() - minimal_access = list() - minimal_player_age = 14 - economic_power = 20 ideal_character_age = 70 - guestbanned = 1 - must_fill = 1 - not_random_selectable = 1 - forced_spawnpoint = "Captain Compartment" + forced_spawnpoint = /decl/spawnpoint/cryo/captain -/datum/job/tradeship_captain/equip(var/mob/living/carbon/human/H) +/datum/job/standard/captain/tradeship/equip_job(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) . = ..() - if(H.client) - H.client.verbs += /client/proc/tradehouse_rename_ship - H.client.verbs += /client/proc/tradehouse_rename_company + if(H) + H.verbs |= /mob/proc/tradehouse_rename_ship + H.verbs |= /mob/proc/tradehouse_rename_company -/datum/job/tradeship_captain/get_access() - return get_all_station_access() - -/client/proc/tradehouse_rename_ship() +/mob/proc/tradehouse_rename_ship() set name = "Rename Tradeship" set category = "Captain's Powers" - var/ship = sanitize(input(src, "What is your ship called? Don't add the vessel prefix, 'Tradeship' will be attached automatically.", "Ship Name", GLOB.using_map.station_short), MAX_NAME_LEN) + var/ship = sanitize(input(src, "What is your ship called? Don't add the vessel prefix, 'Tradeship' will be attached automatically.", "Ship Name", global.using_map.station_short), MAX_NAME_LEN) if(!ship) return - GLOB.using_map.station_short = ship - GLOB.using_map.station_name = "Tradeship [ship]" - var/obj/effect/overmap/visitable/ship/tradeship/B = locate() in world - if(B) - B.SetName(GLOB.using_map.station_name) - command_announcement.Announce("Attention all hands on [GLOB.using_map.station_name]! Thank you for your attention.", "Ship re-Christened") - verbs -= /client/proc/tradehouse_rename_ship + global.using_map.station_short = ship + global.using_map.station_name = "Tradeship [ship]" + + for(var/sz, sec in global.overmap_sectors) + var/obj/effect/overmap/visitable/ship/tradeship/B = sec + if(istype(B)) + B.SetName(global.using_map.station_name) + command_announcement.Announce("Attention all hands on [global.using_map.station_name]! Thank you for your attention.", "Ship Re-Christened") + verbs -= /mob/proc/tradehouse_rename_ship + return + + to_chat(src, SPAN_WARNING("Could not find an appropriate overmap object for this verb to rename, sorry.")) -/client/proc/tradehouse_rename_company() +/mob/proc/tradehouse_rename_company() set name = "Rename Tradehouse" set category = "Captain's Powers" - var/company = sanitize(input(src, "What should your enterprise be called?", "Company name", GLOB.using_map.company_name), MAX_NAME_LEN) + var/company = sanitize(input(src, "What should your enterprise be called?", "Company name", global.using_map.company_name), MAX_NAME_LEN) if(!company) return - var/company_s = sanitize(input(src, "What's the short name for it?", "Company name", GLOB.using_map.company_short), MAX_NAME_LEN) - if(company != GLOB.using_map.company_name) + var/company_s = sanitize(input(src, "What's the short name for it?", "Company name", global.using_map.company_short), MAX_NAME_LEN) + if(company != global.using_map.company_name) if (company) - GLOB.using_map.company_name = company + global.using_map.company_name = company if(company_s) - GLOB.using_map.company_short = company_s - command_announcement.Announce("Congratulations to all members of [capitalize(GLOB.using_map.company_name)] on the new name. Their rebranding has changed the [GLOB.using_map.company_short] market value by [0.01*rand(-10,10)]%.", "Tradehouse Name Change") - verbs -= /client/proc/tradehouse_rename_company + global.using_map.company_short = company_s + command_announcement.Announce("Congratulations to all members of [capitalize(global.using_map.company_name)] on the new name. Their rebranding has changed the [global.using_map.company_short] market value by [0.01*rand(-10,10)]%.", "Tradehouse Name Change") + verbs -= /mob/proc/tradehouse_rename_company /datum/job/tradeship_first_mate title = "First Mate" supervisors = "the Captain" - outfit_type = /decl/hierarchy/outfit/job/tradeship/mate - hud_icon = "hudheadofpersonnel" + hud_icon = 'maps/tradeship/hud.dmi' + outfit_type = /decl/outfit/job/tradeship/mate head_position = 1 - department_refs = list( - DEPT_COMMAND, - DEPT_CIVILIAN + department_types = list( + /decl/department/command, + /decl/department/civilian ) total_positions = 1 spawn_positions = 1 diff --git a/maps/tradeship/jobs/engineering.dm b/maps/tradeship/jobs/engineering.dm index 1d0aad1c5d61..62a9c6659c46 100644 --- a/maps/tradeship/jobs/engineering.dm +++ b/maps/tradeship/jobs/engineering.dm @@ -1,127 +1,10 @@ -/datum/job/tradeship_engineer +/datum/job/standard/engineer/tradeship title = "Junior Engineer" supervisors = "the Head Engineer" - total_positions = 2 - spawn_positions = 2 - hud_icon = "hudengineer" - outfit_type = /decl/hierarchy/outfit/job/tradeship/hand/engine - department_refs = list(DEPT_ENGINEERING) - total_positions = 8 - spawn_positions = 7 - selection_color = "#5b4d20" - economic_power = 5 - minimal_player_age = 7 - access = list( - access_eva, - access_engine, - access_engine_equip, - access_tech_storage, - access_maint_tunnels, - access_external_airlocks, - access_construction, - access_atmospherics, - access_emergency_storage - ) - minimal_access = list( - access_eva, - access_engine, - access_engine_equip, - access_tech_storage, - access_maint_tunnels, - access_external_airlocks, - access_construction, - access_atmospherics, - access_emergency_storage - ) - min_skill = list( - SKILL_LITERACY = SKILL_ADEPT, - SKILL_COMPUTER = SKILL_BASIC, - SKILL_EVA = SKILL_BASIC, - SKILL_CONSTRUCTION = SKILL_ADEPT, - SKILL_ELECTRICAL = SKILL_BASIC, - SKILL_ATMOS = SKILL_BASIC, - SKILL_ENGINES = SKILL_BASIC - ) - max_skill = list( - SKILL_CONSTRUCTION = SKILL_MAX, - SKILL_ELECTRICAL = SKILL_MAX, - SKILL_ATMOS = SKILL_MAX, - SKILL_ENGINES = SKILL_MAX - ) - skill_points = 20 + outfit_type = /decl/outfit/job/tradeship/hand/engine alt_titles = list() -/datum/job/tradeship_engineer/head +/datum/job/standard/chief_engineer/tradeship title = "Head Engineer" - head_position = 1 - department_refs = list( - DEPT_ENGINEERING, - DEPT_COMMAND - ) - total_positions = 1 - spawn_positions = 1 - selection_color = "#7f6e2c" - req_admin_notify = 1 - economic_power = 10 - ideal_character_age = 50 - guestbanned = 1 - must_fill = 1 - not_random_selectable = 1 - access = list( - access_engine, - access_engine_equip, - access_tech_storage, - access_maint_tunnels, - access_heads, - access_teleporter, - access_external_airlocks, - access_atmospherics, - access_emergency_storage, - access_eva, - access_bridge, - access_construction, access_sec_doors, - access_ce, - access_RC_announce, - access_keycard_auth, - access_tcomsat, - access_ai_upload - ) - minimal_access = list( - access_engine, - access_engine_equip, - access_tech_storage, - access_maint_tunnels, - access_heads, - access_teleporter, - access_external_airlocks, - access_atmospherics, - access_emergency_storage, - access_eva, - access_bridge, - access_construction, - access_sec_doors, - access_ce, access_RC_announce, - access_keycard_auth, - access_tcomsat, - access_ai_upload - ) - minimal_player_age = 14 - supervisors = "the Captain" - outfit_type = /decl/hierarchy/outfit/job/tradeship/chief_engineer - min_skill = list( - SKILL_LITERACY = SKILL_ADEPT, - SKILL_COMPUTER = SKILL_ADEPT, - SKILL_EVA = SKILL_ADEPT, - SKILL_CONSTRUCTION = SKILL_ADEPT, - SKILL_ELECTRICAL = SKILL_ADEPT, - SKILL_ATMOS = SKILL_ADEPT, - SKILL_ENGINES = SKILL_EXPERT - ) - max_skill = list( - SKILL_CONSTRUCTION = SKILL_MAX, - SKILL_ELECTRICAL = SKILL_MAX, - SKILL_ATMOS = SKILL_MAX, - SKILL_ENGINES = SKILL_MAX - ) - skill_points = 30 + outfit_type = /decl/outfit/job/tradeship/chief_engineer alt_titles = list() diff --git a/maps/tradeship/jobs/medical.dm b/maps/tradeship/jobs/medical.dm index daac2044c94f..bedcf5584533 100644 --- a/maps/tradeship/jobs/medical.dm +++ b/maps/tradeship/jobs/medical.dm @@ -1,13 +1,9 @@ -/datum/job/tradeship_doctor +/datum/job/standard/doctor/tradeship title = "Junior Doctor" - department_refs = list(DEPT_MEDICAL) - head_position = 0 supervisors = "the Head Doctor and the Captain" - total_positions = 2 - spawn_positions = 2 alt_titles = list() + // Slightly beefier skills due to smaller crew. skill_points = 24 - hud_icon = "hudmedicaldoctor" min_skill = list( SKILL_LITERACY = SKILL_ADEPT, SKILL_MEDICAL = SKILL_EXPERT, @@ -19,11 +15,6 @@ SKILL_ANATOMY = SKILL_MAX, SKILL_CHEMISTRY = SKILL_MAX ) - minimal_player_age = 3 - total_positions = 5 - spawn_positions = 3 - selection_color = "#013d3b" - economic_power = 7 access = list( access_medical, access_medical_equip, @@ -39,62 +30,13 @@ access_surgery, access_virology ) - outfit_type = /decl/hierarchy/outfit/job/tradeship/doc/junior + outfit_type = /decl/outfit/job/tradeship/doc/junior + event_categories = list(ASSIGNMENT_MEDICAL) -/datum/job/tradeship_doctor/head +/datum/job/standard/cmo/tradeship title = "Head Doctor" - head_position = 1 - department_refs = list( - DEPT_MEDICAL, - DEPT_COMMAND - ) supervisors = "the Captain and your own ethics" - outfit_type = /decl/hierarchy/outfit/job/tradeship/doc + outfit_type = /decl/outfit/job/tradeship/doc alt_titles = list("Surgeon") - total_positions = 1 - spawn_positions = 1 + // Slightly beefier skills due to smaller crew. skill_points = 28 - guestbanned = 1 - must_fill = 1 - not_random_selectable = 1 - selection_color = "#026865" - req_admin_notify = 1 - economic_power = 10 - access = list( - access_medical, - access_medical_equip, - access_morgue, - access_bridge, - access_heads, - access_chemistry, - access_virology, - access_cmo, - access_surgery, - access_RC_announce, - access_keycard_auth, - access_sec_doors, - access_psychiatrist, - access_eva, - access_maint_tunnels, - access_external_airlocks - ) - minimal_access = list( - access_medical, - access_medical_equip, - access_morgue, - access_bridge, - access_heads, - access_chemistry, - access_virology, - access_cmo, - access_surgery, - access_RC_announce, - access_keycard_auth, - access_sec_doors, - access_psychiatrist, - access_eva, - access_maint_tunnels, - access_external_airlocks - ) - minimal_player_age = 14 - ideal_character_age = 50 diff --git a/maps/tradeship/jobs/science.dm b/maps/tradeship/jobs/science.dm index 9adae36db18c..d941587b27dc 100644 --- a/maps/tradeship/jobs/science.dm +++ b/maps/tradeship/jobs/science.dm @@ -1,117 +1,14 @@ -/datum/job/tradeship_researcher +/datum/job/standard/scientist/tradeship title = "Junior Researcher" supervisors = "the Head Researcher and the Captain" - spawn_positions = 1 total_positions = 2 - department_refs = list(DEPT_SCIENCE) + spawn_positions = 1 alt_titles = list() - outfit_type = /decl/hierarchy/outfit/job/tradeship/hand/researcher/junior - min_skill = list( - SKILL_LITERACY = SKILL_ADEPT, - SKILL_COMPUTER = SKILL_BASIC, - SKILL_DEVICES = SKILL_BASIC, - SKILL_SCIENCE = SKILL_ADEPT - ) - max_skill = list( - SKILL_ANATOMY = SKILL_MAX, - SKILL_DEVICES = SKILL_MAX, - SKILL_SCIENCE = SKILL_MAX - ) + outfit_type = /decl/outfit/job/tradeship/hand/researcher/junior + // Smaller crew, more points. skill_points = 24 - access = list( - access_robotics, - access_tox, - access_tox_storage, - access_research, - access_xenobiology, - access_xenoarch - ) - minimal_access = list( - access_robotics, - access_tox, - access_tox_storage, - access_research, - access_xenobiology, - access_xenoarch - ) - selection_color = "#633d63" - economic_power = 7 - minimal_player_age = 7 -/datum/job/tradeship_researcher/head +/datum/job/standard/rd/tradeship title = "Head Researcher" - supervisors = "the Captain" - spawn_positions = 1 - total_positions = 1 alt_titles = list() - outfit_type = /decl/hierarchy/outfit/job/tradeship/hand/researcher - min_skill = list( - SKILL_LITERACY = SKILL_ADEPT, - SKILL_COMPUTER = SKILL_BASIC, - SKILL_FINANCE = SKILL_ADEPT, - SKILL_BOTANY = SKILL_BASIC, - SKILL_ANATOMY = SKILL_BASIC, - SKILL_DEVICES = SKILL_BASIC, - SKILL_SCIENCE = SKILL_ADEPT - ) - max_skill = list( - SKILL_ANATOMY = SKILL_MAX, - SKILL_DEVICES = SKILL_MAX, - SKILL_SCIENCE = SKILL_MAX - ) - skill_points = 30 - head_position = 1 - department_refs = list( - DEPT_SCIENCE, - DEPT_COMMAND - ) - selection_color = "#ad6bad" - req_admin_notify = 1 - economic_power = 15 - access = list( - access_rd, - access_bridge, - access_tox, - access_morgue, - access_tox_storage, - access_teleporter, - access_sec_doors, - access_heads, - access_research, - access_robotics, - access_xenobiology, - access_ai_upload, - access_tech_storage, - access_RC_announce, - access_keycard_auth, - access_tcomsat, - access_gateway, - access_xenoarch, - access_network - ) - minimal_access = list( - access_rd, - access_bridge, - access_tox, - access_morgue, - access_tox_storage, - access_teleporter, - access_sec_doors, - access_heads, - access_research, - access_robotics, - access_xenobiology, - access_ai_upload, - access_tech_storage, - access_RC_announce, - access_keycard_auth, - access_tcomsat, - access_gateway, - access_xenoarch, - access_network - ) - minimal_player_age = 14 - ideal_character_age = 50 - guestbanned = 1 - must_fill = 1 - not_random_selectable = 1 + outfit_type = /decl/outfit/job/tradeship/hand/researcher diff --git a/maps/tradeship/outfits/_outfits.dm b/maps/tradeship/outfits/_outfits.dm index d838f6bdff66..44f0a65873a9 100644 --- a/maps/tradeship/outfits/_outfits.dm +++ b/maps/tradeship/outfits/_outfits.dm @@ -1,20 +1,24 @@ // OUTFITS -#define TRADESHIP_OUTFIT_JOB_NAME(job_name) ("Tradeship - Job - " + job_name) - -/decl/hierarchy/outfit/job/tradeship - hierarchy_type = /decl/hierarchy/outfit/job/tradeship +/decl/outfit/job/tradeship + abstract_type = /decl/outfit/job/tradeship pda_type = /obj/item/modular_computer/pda - pda_slot = slot_l_store + pda_slot = slot_l_store_str l_ear = null r_ear = null -/decl/hierarchy/outfit/job/tradeship/hand - name = TRADESHIP_OUTFIT_JOB_NAME("Deck Hand") +/decl/outfit/job/tradeship/hand + name = "Tradeship - Job - Deck Hand" -/decl/hierarchy/outfit/job/tradeship/hand/pre_equip(mob/living/carbon/human/H) +/decl/outfit/job/tradeship/hand/pre_equip(mob/living/wearer) ..() - uniform = pick(list(/obj/item/clothing/under/overalls, /obj/item/clothing/under/hazard, /obj/item/clothing/under/rank/cargotech, /obj/item/clothing/under/color/black, /obj/item/clothing/under/color/grey, /obj/item/clothing/under/casual_pants/track)) + uniform = pick(list( + /obj/item/clothing/pants/mustard/overalls, + /obj/item/clothing/jumpsuit/hazard, + /obj/item/clothing/jumpsuit/cargotech, + /obj/item/clothing/jumpsuit/black, + /obj/item/clothing/jumpsuit/grey + )) -/decl/hierarchy/outfit/job/tradeship/hand/cook - name = TRADESHIP_OUTFIT_JOB_NAME("Cook") +/decl/outfit/job/tradeship/hand/cook + name = "Tradeship - Job - Cook" head = /obj/item/clothing/head/chefhat diff --git a/maps/tradeship/outfits/command.dm b/maps/tradeship/outfits/command.dm index 1e65c60ef8d6..8755b97c5554 100644 --- a/maps/tradeship/outfits/command.dm +++ b/maps/tradeship/outfits/command.dm @@ -1,34 +1,28 @@ -/decl/hierarchy/outfit/job/tradeship/captain - name = TRADESHIP_OUTFIT_JOB_NAME("Tradehouse Captain") - uniform = /obj/item/clothing/under/casual_pants/classicjeans +/decl/outfit/job/tradeship/captain + name = "Tradeship - Job - Tradehouse Captain" + uniform = /obj/item/clothing/pants/baggy/casual/classicjeans shoes = /obj/item/clothing/shoes/color/black pda_type = /obj/item/modular_computer/pda/heads/captain r_pocket = /obj/item/radio - id_type = /obj/item/card/id/gold/tradeship_captain + id_type = /obj/item/card/id/gold + l_ear = /obj/item/radio/headset/heads/captain -/decl/hierarchy/outfit/job/tradeship/captain/post_equip(var/mob/living/carbon/human/H) +/decl/outfit/job/tradeship/captain/post_equip(var/mob/living/wearer) ..() - var/obj/item/clothing/uniform = H.w_uniform + var/obj/item/clothing/uniform = wearer.get_equipped_item(slot_w_uniform_str) if(uniform) - var/obj/item/clothing/accessory/toggleable/hawaii/random/eyegore = new() + var/obj/item/clothing/shirt/hawaii/random/eyegore = new() if(uniform.can_attach_accessory(eyegore)) uniform.attach_accessory(null, eyegore) else qdel(eyegore) -/decl/hierarchy/outfit/job/tradeship/mate - name = TRADESHIP_OUTFIT_JOB_NAME("Tradehouse First Mate") - uniform = /obj/item/clothing/under/suit_jacket/checkered +/decl/outfit/job/tradeship/mate + name = "Tradeship - Job - Tradehouse First Mate" + uniform = /obj/item/clothing/pants/slacks/black/outfit/checkered shoes = /obj/item/clothing/shoes/dress glasses = /obj/item/clothing/glasses/sunglasses/big - pda_type = /obj/item/modular_computer/pda/cargo - l_hand = /obj/item/clipboard - id_type = /obj/item/card/id/silver/tradeship_first_mate + hands = list(/obj/item/clipboard) + id_type = /obj/item/card/id/silver pda_type = /obj/item/modular_computer/pda/heads/hop - -//id cards -/obj/item/card/id/gold/tradeship_captain - job_access_type = /datum/job/tradeship_captain - -/obj/item/card/id/silver/tradeship_first_mate - job_access_type = /datum/job/tradeship_first_mate \ No newline at end of file + l_ear = /obj/item/radio/headset/heads/hop diff --git a/maps/tradeship/outfits/engineering.dm b/maps/tradeship/outfits/engineering.dm index 2431c92a2ad3..2ec0070a066d 100644 --- a/maps/tradeship/outfits/engineering.dm +++ b/maps/tradeship/outfits/engineering.dm @@ -1,35 +1,35 @@ -/decl/hierarchy/outfit/job/tradeship/hand/engine - name = TRADESHIP_OUTFIT_JOB_NAME("Junior Engineer") +/decl/outfit/job/tradeship/hand/engine + name = "Tradeship - Job - Junior Engineer" head = /obj/item/clothing/head/hardhat - flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL id_type = /obj/item/card/id/tradeship/engineering shoes = /obj/item/clothing/shoes/workboots - l_hand = /obj/item/wrench - belt = /obj/item/storage/belt/utility/full + hands = list(/obj/item/wrench) + belt = /obj/item/belt/utility/full r_pocket = /obj/item/radio + l_ear = /obj/item/radio/headset/headset_eng + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR /obj/item/card/id/tradeship/engineering name = "identification card" desc = "A card issued to engineering staff." - job_access_type = /datum/job/tradeship_engineer detail_color = COLOR_SUN -/decl/hierarchy/outfit/job/tradeship/chief_engineer - name = TRADESHIP_OUTFIT_JOB_NAME("Head Engineer") - uniform = /obj/item/clothing/under/rank/chief_engineer +/decl/outfit/job/tradeship/chief_engineer + name = "Tradeship - Job - Head Engineer" + uniform = /obj/item/clothing/jumpsuit/chief_engineer glasses = /obj/item/clothing/glasses/welding/superior - suit = /obj/item/clothing/suit/storage/hazardvest + suit = /obj/item/clothing/suit/hazardvest gloves = /obj/item/clothing/gloves/thick shoes = /obj/item/clothing/shoes/workboots pda_type = /obj/item/modular_computer/pda/heads/ce - l_hand = /obj/item/wrench - belt = /obj/item/storage/belt/utility/full + hands = list(/obj/item/wrench) + belt = /obj/item/belt/utility/full id_type = /obj/item/card/id/tradeship/engineering/head r_pocket = /obj/item/radio - flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR + l_ear = /obj/item/radio/headset/heads/ce /obj/item/card/id/tradeship/engineering/head name = "identification card" desc = "A card which represents creativity and ingenuity." - job_access_type = /datum/job/tradeship_engineer/head extra_details = list("goldstripe") diff --git a/maps/tradeship/outfits/medical.dm b/maps/tradeship/outfits/medical.dm index 7093e3d0bc1c..1466d8dc013c 100644 --- a/maps/tradeship/outfits/medical.dm +++ b/maps/tradeship/outfits/medical.dm @@ -1,15 +1,17 @@ -/decl/hierarchy/outfit/job/tradeship/doc - name = TRADESHIP_OUTFIT_JOB_NAME("Head Doctor") - uniform = /obj/item/clothing/under/det/black +/decl/outfit/job/tradeship/doc + name = "Tradeship - Job - Head Doctor" + uniform = /obj/item/clothing/pants/slacks/black/outfit/detective shoes = /obj/item/clothing/shoes/dress pda_type = /obj/item/modular_computer/pda/medical id_type = /obj/item/card/id/tradeship/medical + l_ear = /obj/item/radio/headset/heads/cmo + /obj/item/card/id/tradeship/medical name = "identification card" desc = "A card issued to medical staff." - job_access_type = /datum/job/tradeship_doctor detail_color = COLOR_PALE_BLUE_GRAY -/decl/hierarchy/outfit/job/tradeship/doc/junior - name = TRADESHIP_OUTFIT_JOB_NAME("Junior Doctor") +/decl/outfit/job/tradeship/doc/junior + name = "Tradeship - Job - Junior Doctor" + l_ear = /obj/item/radio/headset/headset_med diff --git a/maps/tradeship/outfits/science.dm b/maps/tradeship/outfits/science.dm index 61aef8d36042..23e5458618b6 100644 --- a/maps/tradeship/outfits/science.dm +++ b/maps/tradeship/outfits/science.dm @@ -1,21 +1,21 @@ -/decl/hierarchy/outfit/job/tradeship/hand/researcher - name = TRADESHIP_OUTFIT_JOB_NAME("Head Researcher") +/decl/outfit/job/tradeship/hand/researcher + name = "Tradeship - Job - Head Researcher" shoes = /obj/item/clothing/shoes/dress pda_type = /obj/item/modular_computer/pda/science id_type = /obj/item/card/id/tradeship/science/head + l_ear = /obj/item/radio/headset/heads/rd -/obj/item/card/id/science +/obj/item/card/id/tradeship/science name = "identification card" desc = "A card issued to science staff." - job_access_type = /datum/job/tradeship_researcher detail_color = COLOR_PALE_PURPLE_GRAY -/decl/hierarchy/outfit/job/tradeship/hand/researcher/junior - name = TRADESHIP_OUTFIT_JOB_NAME("Junior Researcher") +/decl/outfit/job/tradeship/hand/researcher/junior + name = "Tradeship - Job - Junior Researcher" id_type = /obj/item/card/id/tradeship/science + l_ear = /obj/item/radio/headset/headset_sci /obj/item/card/id/tradeship/science/head name = "identification card" desc = "A card which represents knowledge and reasoning." - job_access_type = /datum/job/tradeship_researcher/head extra_details = list("goldstripe") diff --git a/maps/tradeship/tradeship-0.dmm b/maps/tradeship/tradeship-0.dmm index ccc4e3af9c31..64ebd190f204 100644 --- a/maps/tradeship/tradeship-0.dmm +++ b/maps/tradeship/tradeship-0.dmm @@ -2,67 +2,91 @@ "aa" = ( /turf/space, /area/space) +"ab" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/disused) +"ac" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor, +/area/ship/trade/undercomms) "ad" = ( /obj/structure/door/wood{ - name = "matriarch's quarters" + name = "captain's quarters" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) "ae" = ( /obj/effect/decal/cleanable/generic, /obj/item/stool/wood, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) "af" = ( /obj/structure/disposalpipe/up, /obj/structure/hygiene/drain, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "ag" = ( /obj/machinery/conveyor_switch/oneway{ id_tag = "trash_sort" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) +"ah" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/undercomms) "ai" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "aj" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" }, -/mob/living/simple_animal/mouse, -/turf/simulated/floor, -/area/ship/trade/loading_bay) +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/fore_port_underside_maint) "ak" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 1 - }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) +"al" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/loading_bay) "am" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor, -/area/ship/trade/fore_port_underside_maint) +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/livestock) "an" = ( /obj/machinery/conveyor{ dir = 4; @@ -70,229 +94,236 @@ }, /obj/random/trash, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "ao" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/closet/crate, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "ap" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/door/firedoor/autoset, -/turf/simulated/floor/plating, -/area/ship/trade/disused) -"aq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 + dir = 9 }, +/turf/floor, +/area/ship/trade/undercomms) +"aq" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/disused) "ar" = ( /obj/structure/lattice, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "as" = ( /obj/structure/lattice, /turf/space, /area/space) +"at" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/livestock) "au" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/machinery/door/airlock/external/bolted{ - id_tag = "lower_cargo_in"; - name = "Internal Cargo Airlock" +/obj/effect/floor_decal/corner/beige{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "av" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden, /obj/machinery/door/airlock/external/bolted{ id_tag = "lower_cargo_in"; name = "Internal Cargo Airlock" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aw" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 4; - icon_state = "map_vent"; - id_tag = "lower_cargo_pump" +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/machinery/airlock_sensor{ - id_tag = "lower_cargo_sensor"; - pixel_x = -20; - pixel_y = 0 +/obj/effect/floor_decal/corner/beige{ + dir = 10 }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/loading_bay) -"ax" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ +/obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/button/access/interior{ + dir = 1; + id_tag = "lower_cargo"; + pixel_y = -22 }, +/turf/floor/tiled/steel_grid, +/area/ship/trade/loading_bay) +"ax" = ( +/obj/item/stool/padded, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/item/stool/padded, -/obj/effect/decal/cleanable/generic, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/disused) "ay" = ( -/obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 +/obj/effect/floor_decal/industrial/warning{ + dir = 9; + icon_state = "warning" }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 +/obj/machinery/door/airlock/external/bolted{ + id_tag = "lower_cargo_in"; + name = "Internal Cargo Airlock" + }, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "az" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/item/stool/wood, -/turf/simulated/floor/tiled, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled, /area/ship/trade/disused) "aA" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 9; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 8; + dir = 4; id_tag = "lower_cargo_pump" }, -/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - dir = 8; - icon_state = "airlock_control_off"; - id_tag = "lower_cargo"; - pixel_x = 25; - pixel_y = 0; - tag_airpump = "lower_cargo_pump"; - tag_chamber_sensor = "lower_cargo_sensor"; - tag_exterior_door = "lower_cargo_out"; - tag_interior_door = "lower_cargo_in" +/obj/machinery/airlock_sensor{ + dir = 4; + id_tag = "lower_cargo_sensor"; + pixel_x = -22 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aB" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 4; - icon_state = "map_vent"; id_tag = "lower_cargo_pump" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aC" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" + }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aD" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aE" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "lower_cargo_pump" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aF" = ( /obj/effect/floor_decal/industrial/warning/corner, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) +"aG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/livestock) "aH" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/steel_grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "aI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -301,456 +332,349 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "aJ" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 4; - icon_state = "map_vent"; id_tag = "lower_cargo_pump" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aK" = ( -/obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 - }, /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aL" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "lower_cargo_pump" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aM" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" }, -/obj/machinery/door/airlock/external/bolted{ - id_tag = "lower_cargo_out"; - name = "External Cargo Airlock" +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aN" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 10; + icon_state = "warning" }, -/obj/machinery/door/airlock/external/bolted{ +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/external/glass/bolted{ id_tag = "lower_cargo_out"; name = "External Cargo Airlock" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aO" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aP" = ( /obj/effect/floor_decal/industrial/warning/corner, /obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "aQ" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "aR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "aS" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" + icon_state = "1-2" }, -/obj/effect/decal/cleanable/filth, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor, -/area/ship/trade/disused) +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/fore_port_underside_maint) "aT" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/effect/floor_decal/corner/beige{ + dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +/obj/machinery/light_switch{ + pixel_y = -20; + dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/machinery/light_switch{ - pixel_y = -20 - }, -/turf/simulated/floor, -/area/ship/trade/disused) -"aU" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/obj/machinery/door/firedoor/autoset, -/turf/simulated/floor/plating, +/turf/floor/tiled, /area/ship/trade/disused) -"aV" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor, +"aU" = ( +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/door/firedoor/autoset, +/turf/floor, /area/ship/trade/fore_port_underside_maint) -"aY" = ( -/obj/machinery/conveyor{ +"aV" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ dir = 4; - id_tag = "trash_sort" + id_tag = "scraplock"; + name = "External Blast Doors" }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; +/obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/livestock) +"aW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor/autoset, +/turf/floor, +/area/ship/trade/livestock) +"aX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, /area/ship/trade/loading_bay) +"aY" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/aft_port_underside_maint) +"aZ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor/autoset, +/turf/floor/plating, +/area/ship/trade/aft_starboard_underside_maint) "ba" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, -/area/ship/trade/fore_port_underside_maint) +/obj/effect/floor_decal/industrial/warning{ + dir = 5; + icon_state = "warning" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "lower_cargo_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "lower_cargo"; + pixel_x = 22; + tag_airpump = "lower_cargo_pump"; + tag_chamber_sensor = "lower_cargo_sensor"; + tag_exterior_door = "lower_cargo_out"; + tag_interior_door = "lower_cargo_in" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/loading_bay) "bb" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 8; + icon_state = "warningcorner" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "bc" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 6; + icon_state = "warning" }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 6 +/obj/machinery/door/airlock/external/glass/bolted{ + id_tag = "lower_cargo_out"; + name = "External Cargo Airlock" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/loading_bay) "bd" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/bed/roller/ironingboard, -/turf/simulated/floor, -/area/ship/trade/fore_port_underside_maint) -"be" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/machinery/button/access/exterior/cabled{ + id_tag = "lower_cargo"; + pixel_y = 24 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 + icon_state = "0-4" }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"bf" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 +/turf/floor/plating/airless, +/area/space) +"be" = ( +/obj/structure/cable{ + icon_state = "1-8" }, -/obj/random/trash, -/obj/structure/mattress, -/turf/simulated/floor, -/area/ship/trade/fore_port_underside_maint) +/turf/floor/plating/airless, +/area/space) "bg" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ - icon_state = "up-scrubbers"; dir = 4 }, /obj/machinery/atmospherics/pipe/zpipe/up/supply{ - icon_state = "up-supply"; dir = 4 }, /obj/structure/cable{ - d1 = 16; - d2 = 0; icon_state = "16-0" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/structure/ladder, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "bh" = ( -/obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, /obj/structure/cable{ icon_state = "2-8" }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 6 +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" }, -/obj/machinery/light_switch{ - pixel_x = 20 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "bi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bj" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "bk" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/standard, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/table, /obj/item/paicard, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/disused) "bl" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/gamblingtable, -/obj/item/chems/food/snacks/fish/mollusc, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/trash/mollusc_shell/clam, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/disused) -"bm" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 1 - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"bn" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) "bo" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; level = 2 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "bp" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4; - level = 2 - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"bq" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/livestock) "br" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/effect/floor_decal/corner/beige, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bs" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 - }, -/turf/simulated/floor, +/obj/item/tool/axe/hatchet, +/turf/floor, /area/ship/trade/aft_port_underside_maint) -"bt" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) "bu" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/disposalpipe/segment/bent{ - icon_state = "pipe-c"; - dir = 1 - }, -/obj/machinery/honey_extractor, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) +/obj/machinery/door/window/brigdoor/northright, +/obj/machinery/door/window/brigdoor/southright, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/livestock) "bv" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled, -/area/ship/trade/loading_bay) -"bx" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-8" }, -/obj/structure/closet/crate/hydroponics/beekeeping, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) +/obj/effect/floor_decal/corner/beige{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled, +/area/ship/trade/loading_bay) "by" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" + icon_state = "4-8" }, -/obj/random/trash, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "bz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -759,7 +683,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "bB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -769,34 +693,30 @@ dir = 10 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bC" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/light, -/mob/living/simple_animal/mouse, -/turf/simulated/floor, +/mob/living/simple_animal/passive/mouse, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "bD" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - pixel_y = -24 + pixel_y = -22 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/closet, @@ -805,8 +725,7 @@ name = "shank" }, /obj/item/synthesized_instrument/synthesizer, -/obj/item/twohanded/spear, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "bE" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -814,91 +733,60 @@ level = 2 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/light{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bG" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/vending/cola{ - icon_state = "Cola_Machine"; dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) -"bI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) "bJ" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "bK" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; - pixel_x = 24 + pixel_x = 21 }, /obj/structure/reagent_dispensers/beerkeg, /obj/random/mre/sauce/crayon, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "bL" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -908,130 +796,84 @@ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 10 - }, -/turf/simulated/floor/tiled, -/area/ship/trade/loading_bay) -"bO" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bP" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/atmospherics/pipe/manifold/hidden{ - icon_state = "map"; dir = 1 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "bQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "bR" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/atmospherics/portables_connector{ dir = 8 }, /obj/machinery/portable_atmospherics/canister/air/airlock, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "bS" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" + icon_state = "1-2" }, -/turf/simulated/floor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "bT" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "bU" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/random/trash, -/obj/item/haircomb/random, +/obj/item/grooming/comb/colorable/random, /obj/random/tech_supply, /obj/random/single/textbook, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "bV" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, @@ -1039,35 +881,28 @@ dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bW" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "bX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1077,195 +912,141 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "bY" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "bZ" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - pixel_y = -24 + pixel_y = -22 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 4 }, /obj/machinery/portable_atmospherics/canister/air/airlock, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "ca" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/random/drinkbottle, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "cb" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor, +/obj/structure/closet/crate/hydroponics/beekeeping, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "cc" = ( /obj/machinery/light{ dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 + dir = 9; + icon_state = "warning" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "cd" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 - }, -/turf/simulated/floor, -/area/ship/trade/loading_bay) -"cI" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/button/access/interior{ - pixel_x = 0; - pixel_y = 12; - pixel_z = -33; - id_tag = "lower_cargo" + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor, /area/ship/trade/loading_bay) +"cr" = ( +/obj/item/tool/hoe/mini, +/turf/floor, +/area/ship/trade/aft_starboard_underside_maint) "cX" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light{ dir = 8; flickering = 1 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/disused) +"dN" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/obj/item/tool/hoe/mini, +/turf/floor/plating/dirt, +/area/ship/trade/aft_port_underside_maint) "en" = ( -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) "eu" = ( /obj/structure/window/basic, /obj/structure/curtain/open/bed{ icon_state = "closed"; - opacity = 1; - pixel_y = 0 + opacity = 1 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) -"fq" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, +"fp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/light/small{ + dir = 1 + }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "2-4" }, -/turf/simulated/floor/plating, +/obj/structure/loot_pile/maint/technical, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "fV" = ( /obj/item/mollusc, /obj/item/mollusc/barnacle, /obj/item/mollusc/clam, /obj/structure/table/gamblingtable, -/turf/simulated/floor/carpet/red, -/area/ship/trade/disused) -"fY" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, +/turf/floor/carpet/red, /area/ship/trade/disused) "ga" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1275,104 +1056,95 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/hygiene/drain, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "gf" = ( /obj/structure/lattice, /obj/machinery/light/small{ - icon_state = "bulb_map"; dir = 8 }, -/turf/simulated/floor/carpet/green, +/turf/floor/carpet/green, /area/ship/trade/disused) "hc" = ( -/obj/item/megaphone, /obj/item/radio, -/obj/structure/table/woodentable/walnut, -/turf/simulated/floor/wood/walnut, +/obj/structure/table/laminate/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) "hf" = ( /obj/structure/lattice, /obj/machinery/light/small, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) "hg" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) +"hF" = ( +/turf/floor, +/area/ship/trade/aft_starboard_underside_maint) "hZ" = ( /obj/machinery/conveyor{ dir = 4; id_tag = "trash_sort" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) -"iq" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 2 +"iy" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/random/trash, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, -/turf/simulated/floor, -/area/ship/trade/loading_bay) +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ship/trade/disused) "iD" = ( /obj/structure/closet/crate, /obj/item/clothing/suit/rubber, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) -"iH" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/ship/trade/fore_starboard_underside_maint) "iY" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) +"jk" = ( +/obj/item/mollusc/barnacle{ + pixel_x = -5; + pixel_y = 5 + }, +/turf/floor/plating/airless, +/area/ship/trade/livestock) +"jT" = ( +/turf/floor/plating/airless, +/area/ship/trade/livestock) +"kH" = ( +/obj/structure/window/reinforced, +/turf/floor, +/area/ship/trade/loading_bay) "kO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "kS" = ( /obj/machinery/conveyor{ @@ -1380,9 +1152,23 @@ id_tag = "trash_sort" }, /obj/random/trash, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "lg" = ( +/obj/item/stool/bar/padded, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled, +/area/ship/trade/disused) +"ls" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, @@ -1390,20 +1176,17 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/item/stool/bar/padded, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, -/area/ship/trade/disused) +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/plating/dirt, +/area/ship/trade/aft_port_underside_maint) "lv" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/fore_starboard_underside_maint) +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/bluegrid, +/area/ship/trade/undercomms) "lA" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/disused) "lB" = ( /obj/machinery/conveyor{ @@ -1411,36 +1194,66 @@ id_tag = "trash_sort" }, /obj/item/shard, -/obj/item/stack/cable_coil/random{ - amount = 3 - }, -/turf/simulated/floor, +/obj/item/stack/cable_coil/random/three, +/turf/floor, /area/ship/trade/loading_bay) -"oo" = ( +"lG" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) +"ne" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" + }, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) +"nz" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "xenovent"; + name = "Specimen Consignment Shutter" }, -/turf/simulated/floor, +/turf/floor, +/area/ship/trade/livestock) +"nE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/random/trash, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) +"oo" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/plating/dirt, /area/ship/trade/aft_starboard_underside_maint) +"or" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/turf/floor/plating/dirt, +/area/ship/trade/aft_port_underside_maint) "os" = ( /obj/structure/lattice, /obj/item/mollusc/barnacle{ pixel_x = 9; pixel_y = 7 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "oG" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled, +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/disused) "oO" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -1449,20 +1262,12 @@ }, /obj/item/wrench, /obj/random/tool, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) -"oU" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, -/area/ship/trade/loading_bay) +"oP" = ( +/obj/effect/paint/brown, +/turf/wall, +/area/ship/trade/livestock) "oX" = ( /obj/structure/lattice, /obj/item/mollusc/barnacle{ @@ -1476,105 +1281,139 @@ id_tag = "trash_sort" }, /obj/item/trash/mollusc_shell/clam, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "pi" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/loading_bay) +"pG" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled, +/area/ship/trade/disused) "pU" = ( /obj/structure/window/basic, /obj/structure/curtain/open/bed{ icon_state = "closed"; - opacity = 1; - pixel_y = 0 + opacity = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/loading_bay) +"qt" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ship/trade/disused) "qK" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/loading_bay) +"qQ" = ( +/obj/machinery/network/relay{ + initial_network_id = "tradenet" + }, +/turf/floor/bluegrid, +/area/ship/trade/undercomms) "rp" = ( /obj/effect/floor_decal/corner/beige, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/backpack/dufflebag, -/obj/item/chems/glass/rag, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/backpack/dufflebag, +/obj/item/chems/rag, /obj/item/chems/glass/bucket, /obj/machinery/firealarm{ - pixel_y = 25 + pixel_y = 21 }, /obj/structure/closet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/disused) "rt" = ( -/obj/structure/bed/chair/padded/beige, -/turf/simulated/floor/carpet/red, +/obj/structure/chair/padded/beige, +/turf/floor/carpet/red, /area/ship/trade/disused) -"sX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +"rv" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"ty" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/obj/effect/decal/cleanable/dirt, -/obj/item/radio/intercom{ - dir = 8; - pixel_x = 22 - }, -/turf/simulated/floor/tiled/steel_grid, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, /area/ship/trade/loading_bay) -"tD" = ( +"rI" = ( +/obj/structure/table, +/obj/item/box/beakers, +/obj/item/box/syringes, +/obj/item/scalpel, +/obj/item/box/animal_cubes/monkeys, +/obj/item/circular_saw, +/obj/structure/extinguisher_cabinet{ + pixel_y = 29 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) +"sO" = ( +/turf/floor, +/area/ship/trade/loading_bay) +"sX" = ( /obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/machinery/door/firedoor, -/turf/simulated/floor, -/area/ship/trade/loading_bay) -"tM" = ( -/obj/structure/disposalpipe/trunk{ +/obj/machinery/door/firedoor/autoset, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/disposal/deliveryChute{ - dir = 8; - icon_state = "intake"; - name = "disposals ejection chute" +/turf/floor/plating, +/area/ship/trade/livestock) +"tD" = ( +/obj/structure/cable{ + icon_state = "2-4" }, -/obj/structure/sign/warning/deathsposal{ - pixel_y = -32 +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 }, -/turf/simulated/floor, +/turf/floor/tiled, /area/ship/trade/loading_bay) "ug" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/loading_bay) "un" = ( /obj/structure/janitorialcart, -/turf/simulated/floor, +/obj/item/box/water{ + pixel_x = -10; + pixel_y = -5 + }, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "ux" = ( /obj/structure/lattice, /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/disused) "vi" = ( /obj/structure/mattress/dirty, @@ -1583,37 +1422,52 @@ name = "shank" }, /obj/machinery/newscaster{ - pixel_x = 30 + pixel_x = 32; + dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "vP" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white, +/area/ship/trade/livestock) +"wG" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/machinery/light{ + dir = 4 + }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ship/trade/loading_bay) +"wI" = ( +/obj/structure/loot_pile/surface/medicine_cabinet{ + pixel_y = 18 + }, +/turf/floor/carpet/green, +/area/ship/trade/disused) +"wP" = ( +/obj/structure/disposalpipe/trunk, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/disposalpipe/segment/bent, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"ws" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + icon_state = "1-8" }, -/turf/simulated/floor/plating, -/area/ship/trade/aft_starboard_underside_maint) +/obj/machinery/disposal, +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 21 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) "xc" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/aft_port_underside_maint) "xn" = ( /obj/machinery/light{ @@ -1622,47 +1476,73 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) -"xF" = ( -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, -/area/ship/trade/loading_bay) +"xy" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/plating/dirt, +/area/ship/trade/aft_port_underside_maint) "xP" = ( -/obj/effect/paint/brown, -/turf/simulated/wall, -/area/ship/trade/fore_starboard_underside_maint) -"xV" = ( -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/hygiene/sink/kitchen{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) "xZ" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - pixel_y = -24 + pixel_y = -22 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/closet/l3closet/janitor, -/obj/item/clothing/mask/plunger, +/obj/item/plunger, /obj/item/sutures, /obj/item/clothing/gloves/thick, -/obj/item/floor_painter, +/obj/item/paint_sprayer, /obj/item/chems/glass/bucket, /obj/item/mop, -/obj/item/storage/box/lights/mixed, +/obj/item/box/lights/mixed, /obj/item/assembly/mousetrap, /obj/item/assembly/mousetrap, /obj/item/radio, -/obj/item/storage/bag/trash, -/obj/item/chems/glass/rag, +/obj/item/bag/trash, +/obj/item/chems/rag, /obj/item/caution, /obj/item/caution, /obj/item/caution, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) +"yr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled, +/area/ship/trade/disused) "yE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -1671,497 +1551,640 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) "yO" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/loading_bay) "yQ" = ( -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) +"yT" = ( +/obj/machinery/centrifuge/mapped, +/obj/item/seeds/tomatoseed, +/turf/floor, +/area/ship/trade/aft_port_underside_maint) +"zb" = ( +/turf/wall, +/area/ship/trade/livestock) "zi" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/random/trash, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) -"zw" = ( -/turf/simulated/floor/carpet/green, -/area/ship/trade/disused) +"AG" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/reagentgrinder, +/turf/floor/tiled/white, +/area/ship/trade/livestock) "AO" = ( /obj/structure/hygiene/drain, -/mob/living/simple_animal/mouse, -/turf/simulated/floor, +/mob/living/simple_animal/passive/mouse, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) -"AY" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/steel_grid, -/area/ship/trade/loading_bay) +"AT" = ( +/turf/floor/carpet/green, +/area/ship/trade/disused) +"AZ" = ( +/obj/machinery/smartfridge/secure/extract, +/turf/floor/tiled/white, +/area/ship/trade/livestock) "Bm" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/fore_port_underside_maint) -"Cj" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" +"Cg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 }, -/obj/machinery/light, -/obj/item/storage/box/water{ - pixel_x = -10; - pixel_y = -5 +/obj/random/trash, +/obj/structure/mattress, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"Da" = ( +/turf/floor, +/area/ship/trade/fore_port_underside_maint) +"Ck" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) +"Dt" = ( +/obj/abstract/level_data_spawner/tradeship_basement, +/turf/space, +/area/space) "Dz" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) +"DT" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/undercomms) +"DV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/decal/cleanable/generic, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ship/trade/disused) +"Ff" = ( +/obj/structure/flora/pottedplant/bamboo, +/turf/floor/carpet/red, +/area/ship/trade/disused) +"Ft" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor, +/area/ship/trade/undercomms) +"Fy" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/loot_pile/maint/trash, +/turf/floor/tiled, +/area/ship/trade/disused) "FD" = ( /obj/item/mollusc/barnacle{ pixel_x = -5; pixel_y = 5 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) -"FT" = ( -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/ship/trade/disused) "Gb" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/fore_port_underside_maint) "Gp" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/coin/iron{ pixel_x = 3; pixel_y = 3 }, -/obj/item/clothing/accessory/bracelet, +/obj/item/clothing/gloves/bracelet, /obj/random/lipstick, /obj/random/coin, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "GH" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, -/area/ship/trade/fore_starboard_underside_maint) -"GP" = ( -/turf/simulated/floor/carpet/green, -/area/ship/trade/disused) +/turf/floor/tiled/white, +/area/ship/trade/livestock) "GQ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) +/mob/living/slime, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/livestock) "Hk" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/optable, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) +"HG" = ( +/obj/effect/decal/cleanable/generic, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/item/trash/mollusc_shell/barnacle, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) + icon_state = "0-8" + }, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -22 + }, +/turf/floor/bluegrid, +/area/ship/trade/undercomms) "HS" = ( /obj/structure/disposalpipe/trunk{ dir = 8 }, /obj/structure/disposaloutlet{ - icon_state = "outlet"; dir = 4 }, -/turf/simulated/floor/airless, -/area/space) +/turf/floor/plating/airless, +/area/ship/trade/livestock) +"If" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) +"Iu" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, +/area/ship/trade/disused) +"Iv" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall/hull, +/area/ship/trade/livestock) +"IA" = ( +/obj/structure/loot_pile/maint/junk, +/turf/floor/carpet/green, +/area/ship/trade/disused) "IG" = ( -/obj/structure/bed/chair/comfy/green{ +/obj/structure/chair/comfy/green{ dir = 1 }, -/obj/machinery/power/apc{ - dir = 2; - name = "south bump"; - pixel_y = -24 +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -22 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/laminate/walnut, +/area/ship/trade/disused) +"II" = ( +/obj/structure/stairs/long/west, +/turf/floor/tiled/steel_grid, +/area/ship/trade/loading_bay) +"IO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/loot_pile/maint/boxfort, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) +"IQ" = ( +/obj/structure/disposalpipe/trunk{ + dir = 4 }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 +/obj/machinery/disposal/deliveryChute{ + dir = 8; + name = "disposals ejection chute" }, -/turf/simulated/floor/wood/walnut, -/area/ship/trade/disused) -"II" = ( -/obj/structure/stairs/west, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor, /area/ship/trade/loading_bay) "Jz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/random/trash, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) "JI" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, +/area/ship/trade/loading_bay) +"JQ" = ( +/turf/wall, +/area/ship/trade/undercomms) +"Ky" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, /area/ship/trade/loading_bay) +"KO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/structure/closet/emcloset, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/turf/floor, +/area/ship/trade/aft_starboard_underside_maint) "KZ" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) +"Lm" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall/hull, +/area/ship/trade/undercomms) +"Lx" = ( +/obj/machinery/apc{ + dir = 4; + pixel_x = 22 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) "LB" = ( /obj/structure/lattice, /obj/structure/bed, /obj/item/bedsheet/rainbow, /obj/structure/curtain/open/bed, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) +"LH" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/bed/roller/ironingboard, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) "LI" = ( -/obj/machinery/light{ - dir = 1 +/obj/structure/cable{ + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"LO" = ( -/obj/machinery/light{ +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/button/blast_door{ + id_tag = "xenovent"; + name = "vent control"; + pixel_x = 6; + pixel_y = -24; dir = 1 }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 +/obj/structure/extinguisher_cabinet{ + pixel_x = -8; + pixel_y = -29; + dir = 1 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) +"LO" = ( +/obj/structure/sign/warning/deathsposal{ + pixel_y = 32 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) "Mb" = ( -/turf/simulated/wall, -/area/ship/trade/fore_starboard_underside_maint) +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/undercomms) "Ms" = ( /obj/structure/disposalpipe/segment{ - dir = 4 + dir = 2; + icon_state = "pipe-c" + }, +/obj/structure/table, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/box/syringes, +/turf/floor/tiled/white, +/area/ship/trade/livestock) +"MI" = ( +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/floor_decal/corner/beige{ + dir = 6 }, -/turf/simulated/wall, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, /area/ship/trade/loading_bay) "MK" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) -"MX" = ( -/obj/machinery/portable_atmospherics/hydroponics/soil, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) +"MY" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/turf/floor/tiled/white, +/area/ship/trade/livestock) +"Nq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) "NR" = ( /obj/structure/mattress, /obj/item/trash/mollusc_shell, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/fore_port_underside_maint) -"PF" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 - }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 6 +"Pa" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 }, +/turf/floor, +/area/ship/trade/disused) +"PE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" }, -/turf/simulated/floor/tiled/steel_grid, +/obj/structure/loot_pile/maint/junk, +/turf/floor, +/area/ship/trade/fore_port_underside_maint) +"PF" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled, /area/ship/trade/loading_bay) "PZ" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/light{ dir = 8 }, /obj/random/toy, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "Qh" = ( -/obj/structure/table/woodentable/mahogany, -/obj/item/gun/launcher/crossbow, -/obj/item/stack/material/rods, +/obj/structure/table/laminate/mahogany, /obj/item/cell/crap/empty, -/turf/simulated/floor/wood/walnut, +/turf/floor/laminate/walnut, /area/ship/trade/disused) "Qv" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -24 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/loading_bay) "Qy" = ( -/obj/turbolift_map_holder/tradeship{ - icon_state = ""; - dir = 1 +/obj/abstract/turbolift_spawner/tradeship{ + dir = 1; + icon_state = "" }, -/turf/simulated/floor/tiled, +/turf/floor, /area/ship/trade/loading_bay) -"QW" = ( -/obj/item/stack/tile/floor{ - amount = 5 +"QQ" = ( +/obj/machinery/portable_atmospherics/hydroponics/soil, +/obj/machinery/light{ + dir = 4 }, +/turf/floor/plating/dirt, +/area/ship/trade/aft_starboard_underside_maint) +"QW" = ( +/obj/item/stack/tile/floor/five, /obj/item/crowbar/red, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/stool/padded, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/disused) -"Rr" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +"RR" = ( +/obj/structure/loot_pile/maint/boxfort, +/turf/floor/carpet/red, +/area/ship/trade/disused) +"Ss" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 }, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) -"RT" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/plating, -/area/ship/trade/aft_starboard_underside_maint) -"Sm" = ( -/turf/simulated/floor/tiled/steel_grid, -/area/ship/trade/loading_bay) +/turf/floor, +/area/ship/trade/fore_port_underside_maint) "SC" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/disused) "SE" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/loading_bay) -"SK" = ( -/obj/machinery/button/access/exterior{ - pixel_x = 0; - pixel_y = -10; - pixel_z = 32; - id_tag = "lower_cargo" - }, -/turf/simulated/floor/airless, -/area/space) "SS" = ( /obj/item/radio/intercom{ - pixel_y = 25 + pixel_y = 20 }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/flora/pottedplant/bamboo, -/turf/simulated/floor, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/loot_pile/maint/junk, +/turf/floor, /area/ship/trade/disused) +"TA" = ( +/obj/machinery/light, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/livestock) "Ua" = ( -/obj/structure/bed/chair/wood/walnut, -/turf/simulated/floor/carpet/red, +/obj/structure/chair/wood/walnut, +/turf/floor/carpet/red, /area/ship/trade/disused) "Ug" = ( /obj/structure/curtain/medical, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/disused) -"Ux" = ( -/turf/simulated/floor/carpet/red, -/area/ship/trade/disused) -"UF" = ( -/obj/machinery/power/apc{ - dir = 2; - name = "south bump"; - pixel_y = -24 - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/structure/table/standard, -/obj/item/seeds/tobaccoseed, -/obj/item/seeds/tomatoseed, -/obj/item/hatchet, -/obj/item/chems/glass/bottle/eznutrient, -/obj/item/chems/glass/bottle/eznutrient, -/obj/item/minihoe, -/turf/simulated/floor, -/area/ship/trade/fore_starboard_underside_maint) "UI" = ( /obj/structure/disposaloutlet{ - icon_state = "outlet"; dir = 4 }, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) +"VT" = ( +/obj/machinery/hologram/holopad/longrange, +/turf/floor/laminate/walnut, +/area/ship/trade/disused) "Xe" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/fore_port_underside_maint) "Xo" = ( /obj/structure/hygiene/drain, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_port_underside_maint) -"XK" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +"XL" = ( +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/turf/simulated/floor/plating, -/area/ship/trade/aft_port_underside_maint) -"XU" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 2 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 +/obj/machinery/door/firedoor/autoset, +/obj/structure/cable{ + icon_state = "4-8" }, -/turf/simulated/floor, -/area/ship/trade/loading_bay) +/turf/floor/plating, +/area/ship/trade/disused) "Yc" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/aft_starboard_underside_maint) -"Yd" = ( -/obj/random/trash, -/turf/simulated/floor, -/area/ship/trade/loading_bay) -"YH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +"Yh" = ( +/obj/effect/decal/cleanable/generic, +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + level = 2 }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/undercomms) +"Ym" = ( +/turf/floor/carpet/red, +/area/ship/trade/disused) +"YH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, /obj/structure/closet/crate, -/obj/item/clothing/accessory/medal/gold, -/obj/item/clothing/accessory/locket, +/obj/item/clothing/medal/gold, +/obj/item/clothing/neck/necklace/locket, /obj/random_multi/single_item/captains_spare_id, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) +"YL" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/item/chems/glass/bottle/eznutrient, +/obj/item/chems/glass/bottle/eznutrient, +/obj/item/seeds/tomatoseed, +/obj/item/seeds/tomatoseed, +/obj/structure/table, +/turf/floor, +/area/ship/trade/aft_port_underside_maint) "YW" = ( /obj/machinery/conveyor{ dir = 4; @@ -2169,56 +2192,44 @@ }, /obj/random/trash, /obj/random/single/textbook, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/loading_bay) +"YZ" = ( +/obj/structure/hygiene/sink/puddle, +/turf/floor, +/area/ship/trade/aft_starboard_underside_maint) "Zz" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - pixel_y = -24 + pixel_y = -22 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/structure/table/standard, -/obj/item/stack/material/uranium, -/obj/item/knife/table/plastic, -/obj/item/clothing/accessory/bowtie/ugly, +/obj/structure/table, +/obj/item/stack/material/puck/mapped/uranium, +/obj/item/utensil/knife/plastic, +/obj/item/clothing/neck/tie/bow/ugly, /obj/random/action_figure, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/aft_starboard_underside_maint) "ZA" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/structure/disposaloutlet, +/obj/structure/disposalpipe/trunk{ + dir = 1 }, -/turf/simulated/floor/plating, -/area/ship/trade/fore_starboard_underside_maint) -"ZB" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/livestock) +"ZC" = ( +/obj/structure/window/reinforced{ + dir = 1 }, -/turf/simulated/floor/plating, -/area/ship/trade/fore_port_underside_maint) -"ZL" = ( -/turf/simulated/floor/wood/walnut, -/area/ship/trade/disused) +/turf/floor, +/area/ship/trade/loading_bay) "ZR" = ( /obj/structure/window/basic, /obj/structure/curtain/open/bed, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/loading_bay) (1,1,1) = {" @@ -2625,7 +2636,7 @@ aa aa aa aa -aa +Dt aa aa aa @@ -3498,7 +3509,7 @@ aa aa aa aa -aa +lG aa aa aa @@ -4554,7 +4565,7 @@ aa aa aa aa -aa +as aa aa aa @@ -4635,26 +4646,26 @@ aa aa aa aa -aa -aa +as +as +as as aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +as +Gb +Bm +ai +ai +ai +FD +Bm +xc +as +as +as +as +as aa as aa @@ -4718,26 +4729,26 @@ aa aa aa aa -as -as -as -as -aa -as +oX +Gb +Gb +Gb +aj +Gb Gb Bm -ai -ai -ai -FD +Bm +aj +aj +Bm Bm xc -as -as -as -as -as -aa +xc +xc +xc +xc +xc +xc as as aa @@ -4798,27 +4809,27 @@ aa aa aa aa -aa -aa -aa -oX -Gb -Gb -ZB -Gb +SC +SC +SC Gb -Bm -Bm -ZB -ZB -Bm -Bm -xc -xc -xc -xc -xc -xc +fp +ne +ne +IO +ne +aS +Ss +LH +Cg +nE +aS +kO +kO +kO +bX +YL +bJ xc ar aa @@ -4880,28 +4891,28 @@ aa aa aa aa -aa -SC SC -SC -Gb +Ff +Ym +Xe +PE ak -aV -aV -aV -ba +ak +ak +ak +aU bH -bd -bf +bH +Ck by -fq -kO -kO -kO -bX +aU +or +xy +dN +yE bs -bJ -xc +yT +aY ar aa aa @@ -4962,12 +4973,12 @@ aa aa aa aa -aa SC Qh IG Xe -am +If +ak yO hg yO @@ -4980,10 +4991,10 @@ yO yO yO yO -yE +ls Xo un -XK +aY ar aa aa @@ -5044,13 +5055,13 @@ aa aa aa aa -aa -fY +ab LB hf Xe -Da -xF +Nq +ak +al af UI yO @@ -5065,7 +5076,7 @@ SE bY bT cb -XK +aY ar aa aa @@ -5126,12 +5137,12 @@ aa aa aa aa -aa ux lA ad lA -ap +XL +lA yO ag hZ @@ -5208,11 +5219,11 @@ aa aa aa aa -aa SC SS iY cX +yr aq yO cc @@ -5290,31 +5301,31 @@ aa aa aa aa -aa -fY +ab en ae -ZL +VT +DV ax pU zi lB -XU -JI -JI -JI +sO +sO +sO +sO Qy ao yO aI pi -cI -yO aw +yO +aA aB aJ qK -SK +bd aa aa aa @@ -5372,31 +5383,31 @@ aa aa aa aa -aa -fY +ab rt hc bk +pG az eu cd kS -aj -JI -JI -JI -JI +sO +sO +sO +sO +sO bL II bz -Sm -bO +yQ au ay aC aK aM -ai +aN +be aa aa aa @@ -5454,30 +5465,30 @@ aa aa aa aa -aa -fY +ab Ua fV bl -aS +Pa +iy ZR cd -kS -iq -JI -JI -JI -JI +hZ +sO +sO +sO +sO +sO bL yQ bz -Sm +yQ bP av aD aO aP -aN +bc ai aa aa @@ -5536,30 +5547,30 @@ aa aa aa aa -aa -fY +ab +en en -ZL QW +qt lg eu -cd +iD pg -XU -JI -JI -JI -JI +sO +sO +sO +sO +sO bg JI aI JI bQ -oU -aA +aX +ba aE aL -oU +aX ai aa aa @@ -5618,20 +5629,20 @@ aa aa aa aa -aa SC rp +Iu oG -FT +Fy aT yO LO -aY +YW bb PF -AY -bc -ty +PF +PF +PF bh bi br @@ -5700,22 +5711,22 @@ aa aa aa aa -aa ux lA Ug -lA -aU -yO -iD -YW -yO +JQ +JQ +ac +JQ +kH +IQ +ZC tD -yO -yO -yO -yO -yO +wG +Ky +rv +Ky +MI bv yO yO @@ -5782,28 +5793,28 @@ aa aa aa aa -aa -fY +ab gf -GP +AT +JQ Mb -be -xF -Yd -tM -yO +ap +JQ +am +aG +zb sX -MX -MX -MX -UF -yO +zb +zb +zb +zb +zb bB SE bS PZ bU -ws +aZ ar aa aa @@ -5864,28 +5875,28 @@ aa aa aa aa -aa SC -zw -Ux -Mb -Rr -yO -yO +wI +Ym +JQ +Yh +Ft +JQ +rI Ms -yO +AG LI -bn +zb bp -xV -Cj -yO +bp +bp +zb yO yO YH AO Gp -ws +aZ ar aa aa @@ -5946,29 +5957,29 @@ aa aa aa aa -aa -SC -SC SC +IA +RR +JQ lv -bm -bq +DT +JQ Hk vP GH -bt +MY bu -bx +bp GQ -bI -RT -oo +bp +zb oo +cr ca -oO -bK -Yc -ar +hF +YZ +aZ +ai aa aa aa @@ -6028,27 +6039,27 @@ aa aa aa aa -aa -aa -aa -aa -lv -lv -ZA -lv -lv -xP +SC +SC +SC +Lm +qQ +HG +JQ +AZ +Lx xP -iH +wP +aW ZA -xP -xP -Yc -Yc -Yc -Yc -Yc -Yc +bp +TA +zb +oo +QQ +KO +oO +bK Yc ar aa @@ -6112,27 +6123,27 @@ aa aa aa aa -as -as -as -as -as -as -lv -xP -ai -HS -FD -ai -xP -Yc -as -as -aa aa -as -as -as +Lm +Lm +ah +Lm +at +Iv +aV +oP +oP +nz +nz +nz +oP +Yc +Yc +Yc +Yc +Yc +Yc +ar aa aa aa @@ -6193,27 +6204,27 @@ aa aa aa aa -aa -aa +as +as +as as aa +as +as +Iv +HS +oP +oP +jk +jT +jk +oP +as +as aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +as +as as aa aa @@ -6276,6 +6287,7 @@ aa aa aa aa +as aa aa aa @@ -6295,8 +6307,7 @@ aa aa aa aa -aa -aa +as aa aa aa @@ -7351,7 +7362,7 @@ aa aa aa aa -aa +lG aa aa aa diff --git a/maps/tradeship/tradeship-1.dmm b/maps/tradeship/tradeship-1.dmm index 2ed885e786d4..34a51a33bfa2 100644 --- a/maps/tradeship/tradeship-1.dmm +++ b/maps/tradeship/tradeship-1.dmm @@ -6,72 +6,129 @@ /obj/effect/shuttle_landmark/below_deck_bow, /turf/space, /area/space) +"ac" = ( +/obj/machinery/door/blast/regular{ + dir = 2 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/escape_port) "ad" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "cargo_out" }, /obj/machinery/shield_diffuser, -/turf/simulated/floor/plating, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/turf/floor/plating, /area/ship/trade/cargo/lower) "ae" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "cargo_out" }, /obj/machinery/button/access/exterior{ + dir = 1; id_tag = "cargo"; - pixel_x = 18; - pixel_y = 17 + pixel_x = 24; + pixel_y = 11; + directional_offset = null }, /obj/machinery/shield_diffuser, -/turf/simulated/floor/plating, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/turf/floor/plating, /area/ship/trade/cargo/lower) +"af" = ( +/obj/machinery/door/blast/regular{ + dir = 2 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/escape_star) +"ag" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "anomvent"; + name = "Emergency Vent" + }, +/turf/floor/plating, +/area/ship/trade/artifact_storage) "ah" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/escape_port) "ai" = ( -/obj/machinery/door/blast/regular{ - dir = 4 +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" }, -/turf/simulated/floor/plating, -/area/ship/trade/escape_port) +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/crew/dorms1) "aj" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - id_tag = "cargo_pump" - }, -/turf/simulated/floor/plating, -/area/ship/trade/cargo/lower) -"ak" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ id_tag = "cargo_pump" }, /obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 4; id_tag = "cargo"; - pixel_x = 24; + pixel_x = -22; tag_airpump = "cargo_pump"; tag_chamber_sensor = "cargo_sensor"; tag_exterior_door = "cargo_out"; tag_interior_door = "cargo_in" }, +/turf/floor/plating, +/area/ship/trade/cargo/lower) +"ak" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "cargo_pump" + }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/cargo/lower) "al" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/cargo/lower) +"am" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating/airless, +/area/ship/trade/crew/dorms1) +"an" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/crew/dorms2) "ao" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/cargo/lower) "ap" = ( -/obj/machinery/door/blast/regular{ - dir = 8 - }, -/turf/simulated/floor/plating, -/area/ship/trade/escape_star) +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) "aq" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/escape_star) "ar" = ( /obj/machinery/cryopod/lifepod, @@ -79,58 +136,61 @@ dir = 4 }, /obj/machinery/door/window/southright, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/escape_port) "as" = ( /obj/machinery/cryopod/lifepod, /obj/machinery/door/window/southright, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/escape_port) -"au" = ( -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/machinery/door/blast/regular{ - density = 0; +"at" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/plating, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/drunk_tank) +"au" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/floor/plating, /area/ship/trade/cargo/lower) "av" = ( /obj/machinery/airlock_sensor{ + dir = 8; id_tag = "cargo_sensor"; - pixel_x = 25 + pixel_x = 22 }, /obj/machinery/atmospherics/pipe/simple/hidden, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/cargo/lower) -"ax" = ( -/obj/structure/table/standard, -/obj/item/flashlight/lamp, -/obj/item/paper_bin, -/obj/item/stamp/cargo, -/obj/item/stamp/denied, -/obj/random/clipboard, -/obj/item/radio, -/obj/item/radio/intercom{ - dir = 8; - pixel_x = 22 +"aw" = ( +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; +/obj/effect/floor_decal/corner/yellow{ dir = 6 }, -/turf/simulated/floor/tiled, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/button/access/interior{ + dir = 8; + id_tag = "eva"; + pixel_x = 20 + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/eva) +"ax" = ( +/obj/effect/floor_decal/corner/beige, +/obj/machinery/mining_drill, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "ay" = ( /obj/machinery/cryopod/lifepod, @@ -138,274 +198,322 @@ dir = 4 }, /obj/machinery/door/window/southright, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/escape_star) "az" = ( /obj/machinery/cryopod/lifepod, /obj/machinery/door/window/southright, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/escape_star) "aA" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/escape_star) +"aB" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/eva) "aC" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/machinery/computer/cryopod{ - pixel_y = -32 - }, -/obj/effect/landmark{ - name = "JoinLateCryo" + dir = 1 }, +/obj/abstract/landmark/latejoin/cryo, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_port) +"aD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "eva_in" + }, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/maintenance/eva) "aE" = ( /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, -/obj/effect/landmark{ - name = "JoinLateCryo" - }, +/obj/abstract/landmark/latejoin/cryo, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_port) "aF" = ( -/obj/structure/window/reinforced{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 }, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; - dir = 4 +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "aG" = ( /obj/machinery/door/airlock/external/bolted{ + icon_state = "closed"; id_tag = "cargo_in" }, /obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/cargo/lower) "aH" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "cargo_in" +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 }, +/obj/machinery/portable_atmospherics/canister/air/airlock, /obj/machinery/button/access/interior{ - id_tag = "cargo"; - pixel_x = 20; - pixel_y = -12 + id_tag = "cargo" }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/plating, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) +"aI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "eva"; + pixel_y = 24; + tag_airpump = "eva_pump"; + tag_chamber_sensor = "eva_sensor"; + tag_exterior_door = "eva_out"; + tag_interior_door = "eva_in" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light/small{ + icon_state = "bulb1" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/maintenance/eva) +"aJ" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "eva_pump" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/airlock_sensor{ + id_tag = "eva_sensor"; + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/maintenance/eva) "aK" = ( /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/obj/effect/landmark{ - name = "JoinLateCryoTwo" - }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/abstract/landmark/latejoin/cryo_two, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_star) +"aL" = ( +/obj/machinery/shield_diffuser, +/obj/machinery/door/airlock/external/glass/bolted{ + id_tag = "eva_out" + }, +/obj/machinery/button/access/exterior{ + dir = 4; + id_tag = "eva"; + pixel_x = 12; + pixel_y = 24; + directional_offset = null + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/maintenance/eva) "aM" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/machinery/computer/cryopod{ - pixel_y = -32 + dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/landmark{ - name = "JoinLateCryoTwo" - }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/abstract/landmark/latejoin/cryo_two, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_star) +"aN" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/structure/sign/warning/vacuum{ + dir = 8; + pixel_x = 34 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/eva) "aO" = ( -/turf/simulated/wall, -/area/ship/trade/maintenance/robot) +/turf/wall, +/area/ship/trade/artifact_storage) "aP" = ( -/turf/simulated/wall/r_wall, -/area/ship/trade/maintenance/robot) +/turf/wall/r_wall, +/area/ship/trade/artifact_storage) "aR" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/obj/machinery/mining/brace, +/obj/structure/drill_brace, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "aS" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/tiled/steel_grid, -/area/ship/trade/cargo/lower) -"aT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 9 - }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "aU" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "aV" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, /obj/structure/closet/crate/plastic, -/obj/item/stack/material/plastic/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/aluminium/fifty, -/obj/item/stack/material/glass, -/turf/simulated/floor/tiled/monotile, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/fifty, +/obj/item/stack/material/pane/mapped/glass, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "aX" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/dorms1) "aY" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/dorms1) "aZ" = ( -/obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 +/obj/machinery/alarm{ + pixel_y = 24 }, -/obj/machinery/firealarm{ - pixel_y = 18 +/obj/structure/table, +/obj/machinery/button/blast_door{ + id_tag = "anomvent"; + name = "emergency vent control"; + directional_offset = null }, -/obj/machinery/recharge_station, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) +/turf/floor/tiled/white, +/area/ship/trade/artifact_storage) "ba" = ( -/obj/machinery/atmospherics/unary/vent_pump/on, -/obj/machinery/alarm{ - pixel_y = 17 +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 }, -/obj/effect/landmark/start{ - name = "Robot" +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) -"bb" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, -/obj/machinery/light_switch{ - pixel_x = 24 - }, -/obj/machinery/power/apc{ - dir = 1 - }, -/obj/machinery/cryopod/robot, -/obj/effect/landmark{ - name = "JoinLateCyborg" + pixel_y = 1 }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) +/turf/floor/tiled/white, +/area/ship/trade/artifact_storage) "bc" = ( /obj/machinery/light{ dir = 8 }, /obj/effect/decal/cleanable/cobweb2, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "bd" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/machinery/power/apc{ - dir = 8 +/obj/machinery/apc{ + dir = 8; + pixel_x = -22 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/structure/closet/crate/plastic, /obj/random/accessory, /obj/random/accessory, -/obj/item/chems/glass/paint/random, -/turf/simulated/floor/tiled/monotile, +/obj/item/chems/glass/bucket/paint/random, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bf" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -414,7 +522,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bg" = ( /obj/effect/floor_decal/industrial/outline/yellow, @@ -431,170 +539,124 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bh" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/light{ dir = 4 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/obj/structure/ore_box, -/turf/simulated/floor/tiled/monotile, +/obj/item/firstaid/regular, +/obj/structure/closet/crate, +/obj/item/stack/tile/carpet/fifty, +/obj/item/bodybag, +/obj/random/soap, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bi" = ( -/obj/machinery/light{ - icon_state = "bulb1"; +/obj/structure/sign/deck/second{ + pixel_x = -32; dir = 4 }, /obj/structure/ladder, -/obj/effect/decal/cleanable/cobweb, -/obj/structure/sign/deck/second{ - pixel_x = -32 +/obj/structure/cable{ + icon_state = "16-0" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "0-4" }, -/turf/simulated/floor/plating, +/obj/structure/disposalpipe/up, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "bj" = ( -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/light_switch{ - pixel_x = -24; - pixel_z = 21; - pixel_w = 33 + pixel_x = 9; + pixel_y = 25 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet, /obj/random/gloves, /obj/random/clothing, /obj/random/clothing, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bl" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/item/bedsheet/green, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bm" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/machinery/door/window{ + dir = 4 }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) +/turf/floor/reinforced, +/area/ship/trade/artifact_storage) "bn" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) +/turf/floor/tiled/white, +/area/ship/trade/artifact_storage) "bo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/obj/machinery/light/small{ - flickering = 1 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) -"bp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/obj/machinery/computer/cryopod{ - pixel_y = -27 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) +/turf/floor/tiled/white, +/area/ship/trade/artifact_storage) "br" = ( -/obj/structure/cable{ - icon_state = "2-8" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, /obj/structure/lattice, /obj/structure/disposalpipe/down, -/turf/simulated/open, +/turf/open, /area/ship/trade/maintenance/lower) "bt" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bu" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bv" = ( /obj/structure/cable{ icon_state = "6-8" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bw" = ( /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ @@ -603,7 +665,7 @@ /obj/machinery/atmospherics/pipe/zpipe/up/supply{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -612,11 +674,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "by" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -625,19 +686,14 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bz" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 @@ -645,8 +701,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/obj/structure/disposalpipe/up, -/turf/simulated/floor/plating, +/obj/structure/disposalpipe/segment{ + dir = 2; + icon_state = "pipe-c" + }, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "bB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -656,11 +715,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -669,68 +726,31 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bD" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/masks, /obj/random_multi/single_item/captains_spare_id, -/turf/simulated/floor/lino, -/area/ship/trade/crew/dorms1) -"bE" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, /obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "bJ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, -/obj/structure/closet/crate, -/obj/random/soap, -/obj/random/soap, -/obj/item/bodybag, -/obj/item/stack/tile/carpet/fifty, -/obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bK" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/structure/mech_wreckage/powerloader, -/obj/machinery/mech_recharger, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/cargo/lower) -"bL" = ( -/obj/effect/landmark/test/safe_turf, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bM" = ( /obj/structure/cable{ @@ -739,37 +759,29 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "bN" = ( -/obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/cable{ icon_state = "6-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/structure/closet/coffin, -/obj/random/drinkbottle, -/obj/item/contraband/poster, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "bQ" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, /obj/structure/closet, @@ -777,78 +789,64 @@ /obj/random/clothing, /obj/random/clothing, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bS" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/item/bedsheet/brown, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Head Doctor" }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) "bT" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 - }, /obj/effect/floor_decal/industrial/warning/corner, /obj/machinery/light/small{ - icon_state = "bulb_map"; dir = 8 }, -/obj/item/storage/firstaid/regular, /obj/structure/sign/warning/fall{ - pixel_w = -31 + dir = 4; + pixel_x = -34 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bU" = ( -/obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/industrial/warning, -/obj/structure/closet/crate, -/obj/item/fossil/skull, -/obj/item/fossil/animal, -/obj/item/fossil/animal, -/obj/item/fossil, -/obj/item/ore/strangerock, /obj/structure/railing/mapped, -/turf/simulated/floor/tiled/monotile, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "bV" = ( /obj/effect/floor_decal/industrial/warning, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/steel_grid, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "bW" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "bY" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, -/obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/cable{ icon_state = "2-9" }, @@ -857,84 +855,53 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/monotile, +/obj/structure/emergency_dispenser/east, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) -"bZ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/item/radio/intercom{ - dir = 8; - pixel_x = 22 - }, -/obj/structure/cable{ - d1 = 16; - d2 = 0; - icon_state = "16-0" - }, -/obj/structure/cable{ - icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/lower) "ca" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/science/fabricaton) "cb" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/item/radio/intercom{ dir = 1; pixel_y = -30 }, -/obj/effect/landmark{ - name = "JoinLateCryo" - }, +/obj/abstract/landmark/latejoin/cryo, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_port) "cc" = ( /obj/machinery/design_database, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "cd" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - pixel_w = 1 + pixel_x = 22 }, /obj/machinery/light_switch{ - pixel_z = 23; - pixel_w = -1 + pixel_y = 23 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/integrated_circuit_printer, -/turf/simulated/floor/tiled/white, +/obj/machinery/cell_charger, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "ce" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/science/fabricaton) "cf" = ( /obj/machinery/light{ @@ -943,105 +910,90 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "ck" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "cl" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "cm" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/dorms2) "cn" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, -/obj/machinery/light_switch{ - pixel_x = -24; - pixel_z = 21; - pixel_w = 33 + pixel_y = 1 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet, /obj/random/clothing, /obj/random/clothing, /obj/effect/decal/cleanable/cobweb, -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/random/gloves, -/turf/simulated/floor/lino, +/obj/machinery/light_switch{ + pixel_x = 9; + pixel_y = 25 + }, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cp" = ( /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/item/bedsheet/ce, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Cook" }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cq" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/dorms2) "cr" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/science/fabricaton) "cs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1050,38 +1002,31 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "cu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "cx" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/steel_grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) -"cz" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall, -/area/space) "cC" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 @@ -1090,18 +1035,13 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "cE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1111,11 +1051,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1124,54 +1062,38 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cG" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/newspaper, -/turf/simulated/floor/lino, -/area/ship/trade/crew/dorms2) -"cH" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cJ" = ( /obj/machinery/light, -/obj/machinery/fabricator/imprinter{ - initial_id_tag = "tradeship_rnd" - }, -/turf/simulated/floor/tiled/white, +/obj/machinery/fabricator/imprinter, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "cL" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -24; + dir = 4 }, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "cM" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; pixel_x = -24 }, /obj/structure/closet, @@ -1179,175 +1101,161 @@ /obj/random/clothing, /obj/item/clothing/mask/gas/clown_hat, /obj/item/clothing/shoes/clown_shoes, -/obj/item/clothing/under/rank/clown, +/obj/item/clothing/costume/clown, /obj/item/stamp/clown, -/obj/item/storage/backpack/clown, +/obj/item/backpack/clown, /obj/item/bikehorn, -/obj/item/storage/fancy/crayons, +/obj/item/box/fancy/crayons, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cO" = ( /obj/structure/curtain/open/bed, /obj/structure/bed/padded, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 10 }, /obj/item/bedsheet/red, /obj/random_multi/single_item/captains_spare_id, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Head Engineer" }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "cP" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/science/fabricaton) "cS" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/science) "cU" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "cY" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/light{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "cZ" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/science) "da" = ( -/obj/machinery/seed_storage/xenobotany, -/turf/simulated/floor/tiled/white, +/obj/machinery/seed_storage/xenobotany{ + dir = 4 + }, +/turf/floor/tiled/white, /area/ship/trade/science) "db" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/wirecutters/clippers, -/obj/item/minihoe, +/obj/item/tool/hoe/mini, /obj/item/chems/glass/bucket, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/item/disk/botany, /obj/item/chems/glass/bottle/eznutrient, /obj/item/chems/glass/bottle/robustharvest, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "dd" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/science) "df" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/structure/sign/deck/second{ - pixel_x = -32 + pixel_x = -32; + dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "dh" = ( -/obj/structure/stairs/east, +/obj/structure/stairs/long/east, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "di" = ( /obj/structure/cable{ icon_state = "32-4" }, /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers{ - icon_state = "down-scrubbers"; dir = 4 }, /obj/machinery/atmospherics/pipe/zpipe/down/supply{ - icon_state = "down-supply"; dir = 4 }, /obj/structure/ladder, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo/lower) "dj" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 + dir = 1; + icon_state = "warningcorner" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ icon_state = "2-8" @@ -1358,50 +1266,38 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "dk" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/disposalpipe/segment, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "dl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, -/obj/machinery/power/apc{ - dir = 1 + icon_state = "1-2" }, -/turf/simulated/floor/plating, -/area/ship/trade/drunk_tank) +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "dm" = ( /obj/effect/wallframe_spawn/reinforced, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/drunk_tank) "do" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/hygiene/sink{ pixel_y = 21 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "dq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1411,10 +1307,10 @@ dir = 5 }, /obj/item/stool/padded, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Junior Researcher" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "dr" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1424,61 +1320,49 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "ds" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 +/obj/structure/disposalpipe/segment/bent{ + dir = 8 }, -/obj/structure/disposalpipe/segment, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "dt" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/steel_grid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "du" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "dv" = ( /obj/machinery/light, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo/lower) "dw" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 + dir = 1; + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "dy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1489,18 +1373,16 @@ }, /obj/machinery/door/firedoor, /obj/machinery/door/window/brigdoor/eastleft{ - id = "tank"; + id_tag = "tank"; name = "drunk tank" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/drunk_tank) "dz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1509,7 +1391,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "dA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1518,36 +1400,33 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "dB" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/plushie, /obj/item/synthesized_instrument/violin, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "dD" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "dE" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "dH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -1556,23 +1435,23 @@ icon_state = "1-10" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) -"dI" = ( -/obj/machinery/door_timer/cell_1{ - name = "Drunk Tank"; - pixel_x = 1; - pixel_y = -29; - id = "tank" - }, -/turf/simulated/floor/plating, -/area/ship/trade/drunk_tank) "dJ" = ( /obj/effect/wallframe_spawn/reinforced, /obj/structure/cable, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/drunk_tank) +"dK" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/obj/structure/emergency_dispenser/south, +/turf/floor/tiled/white, +/area/ship/trade/science) "dL" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; @@ -1580,45 +1459,19 @@ }, /obj/machinery/firealarm{ dir = 1; - pixel_y = -24 + pixel_y = -21 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "dO" = ( /obj/machinery/botany/editor, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "dP" = ( -/obj/effect/decal/cleanable/spiderling_remains, -/obj/machinery/light{ - dir = 8 - }, -/obj/structure/disposalpipe/segment/bent{ - icon_state = "pipe-c"; - dir = 1 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/tiled, -/area/ship/trade/maintenance/lower) -"dR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, @@ -1626,20 +1479,16 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "dS" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1648,25 +1497,23 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/machinery/power/apc, -/turf/simulated/floor/plating, +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 + }, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "dT" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1678,7 +1525,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "dU" = ( /obj/structure/disposalpipe/segment{ @@ -1691,11 +1538,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/obj/structure/emergency_dispenser/north, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "dV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1705,165 +1551,116 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "dW" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "dY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 + dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 4 }, -/obj/structure/disposalpipe/segment/bent{ - icon_state = "pipe-c"; - dir = 8 +/obj/structure/cable{ + icon_state = "5-8" }, -/obj/machinery/firealarm{ - dir = 1; - pixel_y = -24 +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "dZ" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/techstorage) "eb" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/storage) -"ec" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/techstorage) "ed" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/eva) "ee" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/eva) "ef" = ( -/turf/simulated/wall/r_wall, -/area/ship/trade/maintenance/techstorage) -"ek" = ( -/obj/structure/closet/crate/plastic, -/obj/item/storage/ore, -/obj/item/pickaxe, -/obj/item/stack/flag/yellow, -/obj/item/storage/box/glowsticks, -/obj/item/scanner/mining, -/obj/item/floor_painter, -/turf/simulated/floor/tiled/techfloor, +/turf/wall/r_wall, /area/ship/trade/maintenance/techstorage) "em" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/ladder, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/sign/deck/second{ - pixel_x = 0; pixel_y = 32 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/storage) "en" = ( /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/firealarm{ pixel_y = 24 }, /obj/structure/closet/secure_closet{ name = "secure engineering voidsuit locker"; - req_access = list("ACCESS_CHIEF_ENGINEER") + req_access = list("ACCESS_ENGINE_EQUIP") }, /obj/item/clothing/head/helmet/space/void/engineering/salvage, /obj/item/clothing/suit/space/void/engineering/salvage, -/turf/simulated/floor/plating, +/obj/item/tank/oxygen/yellow, +/obj/item/tank/oxygen/yellow, +/obj/item/tank/oxygen/yellow, +/turf/floor/plating, /area/ship/trade/maintenance/storage) "eo" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/eva) "ep" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/tank/jetpack/oxygen, /obj/item/clothing/mask/breath, /obj/item/tank/jetpack/oxygen, /obj/item/clothing/mask/breath, -/turf/simulated/floor/plating, +/obj/machinery/light_switch{ + pixel_x = 9; + pixel_y = 25 + }, +/turf/floor/plating, /area/ship/trade/maintenance/eva) -"eq" = ( -/obj/machinery/power/apc{ - dir = 1 +"er" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" }, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/cable{ - icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, -/obj/machinery/atmospherics/portables_connector, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/eva) -"er" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/eva) "et" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1873,11 +1670,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "eu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1887,15 +1682,12 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "ew" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, @@ -1903,11 +1695,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "ey" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1918,28 +1708,23 @@ }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/storage) +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) "ez" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/storage) "eA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1949,19 +1734,15 @@ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/storage) "eC" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1970,186 +1751,45 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/eva) "eD" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/eva) -"eE" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 5 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/eva) -"eF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 - }, -/obj/machinery/door/airlock/external/bolted{ - id_tag = "eva_in" - }, -/obj/machinery/button/access/interior{ - id_tag = "eva"; - pixel_x = -12; - pixel_y = 20 - }, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/maintenance/eva) -"eG" = ( -/obj/machinery/airlock_sensor{ - id_tag = "eva_sensor"; - pixel_y = 40 - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 - }, -/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - id_tag = "eva"; - pixel_y = 25; - tag_airpump = "eva_pump"; - tag_chamber_sensor = "eva_sensor"; - tag_exterior_door = "eva_out"; - tag_interior_door = "eva_in" - }, -/obj/effect/floor_decal/industrial/warning{ - dir = 10 - }, -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/obj/machinery/light/small{ - dir = 2; - icon_state = "bulb1" - }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/plating, /area/ship/trade/maintenance/eva) "eH" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 8; - id_tag = "eva_pump" - }, -/obj/effect/floor_decal/industrial/warning{ - dir = 5 - }, -/obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/eva) -"eI" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "eva_out" - }, -/obj/machinery/button/access/exterior{ - id_tag = "eva"; - pixel_x = 18; - pixel_y = -18 - }, -/obj/machinery/shield_diffuser, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/maintenance/eva) +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) "eJ" = ( /obj/machinery/vending/materials{ - icon_state = "engivend"; dir = 4 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/techstorage) -"eK" = ( -/obj/item/stock_parts/console_screen, -/obj/item/stock_parts/console_screen, -/obj/item/stock_parts/console_screen, -/obj/item/stock_parts/micro_laser, -/obj/item/stock_parts/micro_laser, -/obj/item/stock_parts/micro_laser, -/obj/item/stock_parts/micro_laser/ultra, -/obj/structure/table/rack, -/obj/machinery/power/apc{ - dir = 2; - name = "south bump"; - pixel_y = -24 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/techstorage) -"eL" = ( -/obj/structure/table/rack, -/obj/item/stock_parts/circuitboard/pacman/super/potato, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/ocp/ten, -/obj/item/stock_parts/circuitboard/unary_atmos/engine, -/obj/item/stock_parts/circuitboard/unary_atmos/engine, -/obj/item/stock_parts/circuitboard/unary_atmos/engine, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "eN" = ( -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) -"eP" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/start{ - name = "Junior Engineer" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/storage) "eQ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/light_switch{ - pixel_w = 22 + pixel_x = 24; + dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/storage) "eR" = ( /obj/item/radio/intercom{ @@ -2159,59 +1799,42 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/ship/trade/maintenance/eva) "eS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/techfloor, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/eva) -"eT" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/sign/warning/vacuum{ - pixel_x = 35 +"eV" = ( +/obj/abstract/landmark/start{ + name = "Robot" }, -/obj/machinery/atmospherics/unary/vent_pump/on{ +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"eW" = ( +/obj/machinery/computer/cryopod{ dir = 8; - level = 2 + pixel_x = 24 }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/eva) -"eV" = ( -/obj/structure/table/standard, -/obj/item/flashlight, -/obj/item/flashlight, -/obj/item/storage/box/lights/bulbs, -/obj/item/storage/box/lights/mixed, -/obj/item/taperoll/engineering, -/obj/item/tape_roll, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) -"eW" = ( -/obj/structure/table/standard, -/obj/item/inflatable_dispenser, -/obj/item/radio, -/obj/item/radio, -/obj/machinery/light, -/obj/item/radio, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/storage) "eY" = ( /obj/item/radio/intercom{ dir = 1; - pixel_y = -25 + pixel_y = -30 }, /obj/structure/reagent_dispensers/fueltank, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/storage) "eZ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -2219,62 +1842,58 @@ level = 2 }, /obj/structure/cable, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "Engineering Supply Storage APC"; - pixel_w = 1 + pixel_x = 22 }, /obj/machinery/vending/engineering{ - icon_state = "engi"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/storage) +"fa" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, +/area/ship/trade/drunk_tank) "fb" = ( /obj/machinery/light, /obj/machinery/suit_cycler/tradeship, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/eva) "fc" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/suit_cycler/tradeship, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/eva) -"fe" = ( -/obj/effect/landmark/test/space_turf, -/turf/space, -/area/space) "fs" = ( /obj/structure/closet/wardrobe/mixed, -/obj/item/storage/backpack/dufflebag, +/obj/item/backpack/dufflebag, /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; - pixel_x = 0; - pixel_y = -32 + pixel_y = -21 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_port) "fL" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "fX" = ( -/obj/structure/handrai, +/obj/structure/handrail, /turf/space, /area/space) "gb" = ( @@ -2284,7 +1903,7 @@ /obj/random/tech_supply, /obj/random/tech_supply, /obj/random/advdevice, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "gc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2296,45 +1915,65 @@ /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch/autoname/engineering, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/eva) +"gh" = ( +/obj/machinery/material_processing/stacker{ + input_turf = 1; + output_turf = 8 + }, +/turf/floor/plating, +/area/ship/trade/cargo/lower) "gX" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/escape_star) "hb" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/floodlight, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "hc" = ( -/obj/structure/dispenser/oxygen, +/obj/structure/tank_rack/oxygen, /obj/machinery/firealarm{ dir = 1; - pixel_y = -24 + pixel_y = -21 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/eva) "he" = ( /obj/machinery/conveyor{ - dir = 1; - icon_state = "conveyor0"; + dir = 4; id_tag = "con" }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/plating, /area/ship/trade/cargo/lower) +"hf" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 10 + }, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) +"hn" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall, +/area/ship/trade/maintenance/eva) "hp" = ( /obj/machinery/door/firedoor, /obj/machinery/door/window/westleft, @@ -2343,84 +1982,116 @@ name = "Fabrication Bay Shutters" }, /obj/structure/table/marble, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/science/fabricaton) "hI" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/railing/mapped{ - icon_state = "railing0"; - dir = 8 + dir = 8; + icon_state = "railing0" }, -/turf/simulated/floor/tiled/steel_grid, +/obj/machinery/light_switch{ + pixel_y = -20; + dir = 1 + }, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "ib" = ( /obj/effect/floor_decal/industrial/warning, -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/portable_atmospherics/powered/scrubber, /obj/structure/railing/mapped, -/turf/simulated/floor/tiled/monotile, +/obj/structure/closet/coffin, +/obj/random/drinkbottle, +/obj/item/poster, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) +"it" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 4 + }, +/obj/structure/sign/department/science_1{ + pixel_x = -32; + dir = 4 + }, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) +"iH" = ( +/obj/item/toolbox/mechanical{ + pixel_x = 5; + pixel_y = -7 + }, +/obj/item/toolbox/mechanical, +/obj/item/clothing/head/welding, +/obj/item/scanner/gas, +/obj/structure/rack, +/obj/item/inflatable_dispenser, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"iQ" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/sign/warning/caution{ + dir = 4; + pixel_x = -34 + }, +/turf/floor/reinforced, +/area/ship/trade/artifact_storage) +"iS" = ( +/obj/abstract/level_data_spawner/tradeship_cargo, +/turf/space, +/area/space) "iW" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/science) "jb" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/machinery/firealarm{ dir = 1; - pixel_y = -24 - }, -/obj/effect/landmark{ - name = "JoinLateCryo" + pixel_y = -21 }, +/obj/abstract/landmark/latejoin/cryo, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_port) -"js" = ( -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled, -/area/ship/trade/cargo/lower) "jD" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/dorms1) -"jH" = ( +"jV" = ( /obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 + dir = 8; + pixel_x = 22 }, -/obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/white, -/area/ship/trade/science) -"jM" = ( -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 +/obj/effect/floor_decal/corner/beige{ + dir = 10 }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/mineral/unloading_machine{ - input_turf = 2; - output_turf = 1 +/obj/effect/floor_decal/corner/beige{ + dir = 6 }, -/turf/simulated/floor/tiled/steel_grid, +/obj/structure/table, +/obj/item/radio, +/obj/random/clipboard, +/obj/item/stamp/denied, +/obj/item/stamp/cargo, +/obj/item/paper_bin, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "kb" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -2430,159 +2101,207 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ icon_state = "2-8" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) +"kr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/dark, +/area/ship/trade/drunk_tank) "kP" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/dorms1) "lb" = ( -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/seed_extractor, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = 24 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) +"lg" = ( +/obj/structure/closet/crate/plastic, +/obj/item/ore_satchel, +/obj/item/tool/pickaxe, +/obj/item/stack/flag/yellow, +/obj/item/box/glowsticks, +/obj/item/scanner/mining, +/obj/item/paint_sprayer, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"lw" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/machinery/conveyor_switch{ + id_tag = "con" + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ship/trade/cargo/lower) "lD" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/maintenance/robot) +/turf/floor/reinforced, +/area/ship/trade/artifact_storage) "lE" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/cargo/lower) "lK" = ( -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) -"lO" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/sign/science_1{ - pixel_x = -30 - }, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled, -/area/ship/trade/maintenance/lower) "lZ" = ( -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo/lower) "mb" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) +"my" = ( +/obj/machinery/cryopod/robot, +/obj/abstract/landmark/latejoin/cyborg, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"mN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) "nb" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/machinery/firealarm{ dir = 1; - pixel_y = -24 + pixel_y = -21 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/landmark{ - name = "JoinLateCryoTwo" - }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/abstract/landmark/latejoin/cryo_two, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_star) +"nf" = ( +/obj/structure/mech_wreckage/powerloader, +/obj/machinery/mech_recharger, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ship/trade/cargo/lower) +"ni" = ( +/obj/structure/rack, +/obj/item/stock_parts/circuitboard/pacman/super/potato, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, +/obj/item/stack/material/sheet/reinforced/mapped/ocp/ten, +/obj/item/stock_parts/circuitboard/unary_atmos/engine, +/obj/item/stock_parts/circuitboard/unary_atmos/engine, +/obj/item/stock_parts/circuitboard/unary_atmos/engine, +/obj/item/box/lights/mixed, +/obj/item/box/lights/bulbs, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) "nn" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/science) "nz" = ( /obj/machinery/light{ dir = 8 }, /obj/machinery/vending/tool{ - icon_state = "tool"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) -"ob" = ( +"nG" = ( +/obj/machinery/artifact_scanpad, +/obj/machinery/light, +/turf/floor/tiled/white, +/area/ship/trade/artifact_storage) +"od" = ( +/obj/structure/ore_box, +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 4 }, -/obj/machinery/portable_atmospherics/hydroponics, -/obj/machinery/light_switch{ - pixel_w = -23 +/turf/floor/tiled, +/area/ship/trade/cargo/lower) +"oC" = ( +/obj/machinery/conveyor{ + id_tag = "con" }, -/turf/simulated/floor/tiled/white, -/area/ship/trade/science) +/turf/floor/plating, +/area/ship/trade/cargo/lower) "pn" = ( -/obj/item/tape_roll, -/obj/item/stack/material/plasteel/fifty, -/obj/item/stack/material/rods/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/plastic/fifty, -/obj/item/stack/material/steel/fifty, -/obj/structure/closet/crate, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/reinforced/fifty, -/obj/item/clothing/head/welding, -/obj/item/stack/material/cardboard/fifty, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/abstract/landmark/start{ + name = "Junior Engineer" + }, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "pr" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/cargo/lower) +"ps" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/emergency_dispenser/east, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) "qb" = ( /obj/effect/floor_decal/industrial/warning{ dir = 1 }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 1 }, /obj/item/radio/intercom{ @@ -2590,108 +2309,101 @@ pixel_y = -30 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/landmark{ - name = "JoinLateCryoTwo" - }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/abstract/landmark/latejoin/cryo_two, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_star) "ql" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 1 }, /turf/space, /area/space) +"qF" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/floor/reinforced, +/area/ship/trade/artifact_storage) "rb" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/fabricator, /obj/machinery/light_switch{ - pixel_x = -24; - pixel_z = 21; - pixel_w = 33 + pixel_x = 9; + pixel_y = 25 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "rv" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/techstorage) "rB" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/iron, -/obj/item/ore/coal{ +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/iron, +/obj/item/stack/material/ore/coal{ pixel_x = 3; pixel_y = 3 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) +"rN" = ( +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "rP" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /turf/space, /area/space) +"rW" = ( +/turf/wall, +/area/ship/trade/maintenance/lower) "sb" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/escape_port) "se" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/techstorage) -"sh" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/ship/trade/drunk_tank) "sB" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, +/area/ship/trade/science/fabricaton) +"sM" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "sY" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/escape_port) -"tb" = ( -/obj/item/storage/toolbox/mechanical{ - pixel_x = 5; - pixel_y = -7 +"ts" = ( +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 }, -/obj/item/storage/toolbox/mechanical, -/obj/item/clothing/head/welding, -/obj/item/scanner/gas, -/obj/structure/table/rack, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/techstorage) -"tf" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/science/fabricaton) +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 + }, +/obj/item/stool/padded, +/turf/floor/plating, +/area/ship/trade/drunk_tank) "tz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/tiled/steel_grid, +/obj/machinery/material_processing/smeltery, +/turf/floor/plating, /area/ship/trade/cargo/lower) "tE" = ( /obj/machinery/door/airlock/hatch/autoname/engineering, @@ -2699,177 +2411,217 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/techstorage) "ub" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Head Researcher" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) -"uh" = ( -/obj/effect/paint/brown, -/turf/simulated/wall, -/area/ship/trade/maintenance/eva) +"ui" = ( +/obj/structure/closet/crate, +/obj/item/strangerock, +/obj/item/fossil, +/obj/item/fossil/animal, +/obj/item/fossil/animal, +/obj/item/fossil/skull, +/turf/floor/tiled, +/area/ship/trade/cargo/lower) "uj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) +"un" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/fabricator/industrial, +/obj/item/stack/material/ingot/mapped/osmium/ten, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ship/trade/cargo/lower) "uo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "uw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" + }, +/obj/structure/sign/department/xenoflora{ + pixel_x = -32; + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) +"uz" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/structure/sign/xenoflora{ - pixel_x = -30 +/obj/structure/cable{ + icon_state = "2-8" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) +"uX" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -21 + }, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "uY" = ( /obj/structure/closet/wardrobe/mixed, -/obj/item/storage/backpack/dufflebag, +/obj/item/backpack/dufflebag, /obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" + }, +/obj/machinery/apc{ + pixel_y = -22 }, -/obj/machinery/power/apc, /obj/machinery/alarm{ pixel_y = 17 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/escape_star) "vb" = ( /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 - }, -/obj/machinery/fabricator/robotics{ - id_tag = "tradeship_rnd" + pixel_x = 24 }, +/obj/machinery/fabricator/robotics, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) -"vw" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/airless, -/area/ship/trade/crew/dorms1) -"vz" = ( -/obj/machinery/conveyor_switch{ - id_tag = "con"; - pixel_x = 10; - pixel_y = 10 - }, -/turf/simulated/floor/tiled, -/area/ship/trade/cargo/lower) +"vI" = ( +/obj/structure/emergency_dispenser/east, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "vW" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/storage) "wb" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/escape_star) +"wl" = ( +/obj/item/stock_parts/circuitboard/pacman, +/obj/item/stock_parts/circuitboard/recharge_station, +/obj/item/stock_parts/circuitboard/shield_generator, +/obj/structure/rack, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) "wI" = ( /obj/structure/bed/padded, /obj/machinery/light/small{ - icon_state = "bulb_map"; dir = 1 }, /obj/item/bedsheet/mime, /obj/effect/decal/cleanable/cobweb2, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/dark, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "xa" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/dorms2) "xb" = ( /obj/effect/shuttle_landmark/below_deck_starboardastern, /turf/space, /area/space) -"xj" = ( -/obj/structure/lattice, -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/cargo/lower) "yb" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/holostool, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/sign/poster{ - pixel_y = 32 + pixel_y = 32; + dir = 1 }, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) +"yF" = ( +/obj/effect/paint/brown, +/turf/wall, +/area/ship/trade/maintenance/techstorage) +"yL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) +"yT" = ( +/obj/structure/sign/warning/caution{ + dir = 4; + pixel_x = -34 + }, +/turf/floor/reinforced, +/area/ship/trade/artifact_storage) "zb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -2878,20 +2630,35 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch/autoname/science, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/robot) +/turf/floor/plating, +/area/ship/trade/artifact_storage) +"zC" = ( +/obj/machinery/conveyor{ + backwards = 8; + dir = 9; + forwards = 2; + id_tag = "con"; + movedir = 6 + }, +/turf/floor/plating, +/area/ship/trade/cargo/lower) +"zJ" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/emergency_dispenser/east, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "Ab" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/cargo/lower) +"AM" = ( +/turf/floor/tiled/dark, +/area/ship/trade/drunk_tank) "Bb" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2901,57 +2668,52 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/crew/dorms1) "Bq" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/conveyor{ - backwards = 8; - dir = 9; - forwards = 2; - icon_state = "conveyor1"; - id_tag = "con"; - movedir = 6 +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/obj/machinery/light{ + dir = 1 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "BO" = ( /obj/structure/bed/padded, /obj/item/bedsheet/mime, /obj/machinery/light_switch{ - pixel_y = -24 + pixel_y = -20; + dir = 1 }, /obj/machinery/newscaster{ - pixel_x = 30; - pixel_y = 0 + pixel_x = 32; + dir = 4 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "Cd" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/drunk_tank) "Cr" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/floor_decal/industrial/loading{ + dir = 4 + }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 9 + dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "CN" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; +/obj/structure/window/reinforced{ dir = 1 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "Db" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -2961,76 +2723,76 @@ /obj/structure/holostool, /obj/machinery/firealarm{ dir = 1; - pixel_y = -24 + pixel_y = -21 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms1) +"De" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -21 + }, +/turf/floor/tiled/white, +/area/ship/trade/science) "Dh" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/cargo/lower) -"Dl" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/airless, -/area/ship/trade/maintenance/robot) "DQ" = ( /obj/machinery/door/airlock/hatch/autoname/engineering, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/eva) +"DV" = ( +/obj/machinery/door_timer/cell_1{ + id_tag = "tank"; + name = "Drunk Tank"; + pixel_x = 1; + pixel_y = -29 + }, +/obj/item/stool/padded, +/turf/floor/plating, +/area/ship/trade/drunk_tank) "DX" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/drunk_tank) -"Eb" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +"Ei" = ( +/turf/floor/plating/airless, +/area/space) +"En" = ( +/obj/item/stool/padded, +/turf/floor/plating, +/area/ship/trade/drunk_tank) +"EB" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "bulb1" + }, +/obj/effect/decal/cleanable/cobweb, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 +/obj/structure/cable{ + icon_state = "1-8" }, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled, +/turf/floor/plating, /area/ship/trade/maintenance/lower) -"Ei" = ( -/turf/simulated/floor/airless, -/area/space) -"Fb" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/machinery/alarm{ - pixel_y = 24 - }, -/turf/simulated/floor/tiled/white, -/area/ship/trade/science/fabricaton) "Fw" = ( /obj/item/stool/padded, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "Gb" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/item/radio/intercom{ @@ -3038,77 +2800,77 @@ pixel_x = -22 }, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "Gd" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/eva) "Hb" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/firealarm{ - dir = 4; - pixel_x = 24; - pixel_y = 0 - }, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/tiled/steel_grid, +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 + }, +/turf/floor/tiled/steel_grid, /area/ship/trade/cargo/lower) "HH" = ( /obj/structure/ladder, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 6 - }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) +"HY" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/fabricator/protolathe, +/obj/machinery/alarm{ + pixel_y = 24 + }, +/turf/floor/tiled/white, +/area/ship/trade/science/fabricaton) "Ib" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/holostool, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 5 }, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "Ic" = ( -/obj/machinery/organ_printer/robot/mapped, -/turf/simulated/floor/tiled/white, +/obj/machinery/recycler, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "IU" = ( -/obj/machinery/conveyor{ - dir = 10; - icon_state = "conveyor1"; - id_tag = "con" +/obj/structure/window/reinforced, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/corner/beige{ + dir = 5 }, -/turf/simulated/floor/tiled/steel_grid, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "Jb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3118,35 +2880,36 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch/autoname/science, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/science/fabricaton) +"Jl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) "Jr" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "Js" = ( /obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/mining/drill, -/turf/simulated/floor/tiled/monotile, +/obj/structure/drill_brace, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) -"Jv" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/space) "JM" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor, +/turf/floor, /area/ship/trade/science/fabricaton) "Kb" = ( /obj/machinery/door/airlock/hatch/autoname/general, @@ -3157,69 +2920,100 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/crew/dorms2) +"La" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 8 + }, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) "Lb" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/obj/item/storage/briefcase, +/obj/item/briefcase, /obj/machinery/firealarm{ dir = 1; - pixel_y = -24 + pixel_y = -21 }, -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) "Lx" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/stool/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, +/area/ship/trade/cargo/lower) +"LA" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/turf/floor/plating, +/area/ship/trade/cargo/lower) +"LE" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"LN" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "Mb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) +"Ml" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/maintenance/lower) "Mx" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/escape_port) -"MK" = ( -/obj/item/mollusc/barnacle{ - pixel_w = 18 - }, -/turf/space, -/area/space) "Nb" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/radio/intercom/department/security{ +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/radio/intercom{ pixel_y = 20 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) "Nc" = ( /obj/machinery/destructive_analyzer, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "NL" = ( /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "Ob" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3229,19 +3023,17 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch/autoname/science, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/science) +"On" = ( +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "Pb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3251,121 +3043,189 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/drunk_tank) +"Py" = ( +/obj/effect/decal/cleanable/spiderling_remains, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/disposalpipe/segment/bent{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/lower) +"PJ" = ( +/obj/structure/curtain/open/bed, +/obj/structure/bed/padded, +/obj/effect/floor_decal/corner/beige{ + dir = 10 + }, +/obj/item/bedsheet/red, +/obj/random_multi/single_item/captains_spare_id, +/obj/abstract/landmark/start{ + name = "Head Engineer" + }, +/obj/item/stack/material/ingot/mapped/osmium/ten, +/turf/floor/lino, +/area/ship/trade/crew/dorms2) "Qb" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, /obj/structure/sign/warning/fall{ - pixel_y = 0; - pixel_w = 32 + pixel_x = 34; + dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo/lower) "Qc" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/mob/living/simple_animal/cat/fluff/ran, -/turf/simulated/floor/tiled/white, +/mob/living/simple_animal/passive/cat/fluff/ran, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) -"Qi" = ( -/obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 +"Qg" = ( +/obj/structure/sign/warning/caution{ + dir = 8; + pixel_x = 34 }, -/obj/machinery/fabricator/protolathe{ - initial_id_tag = "tradeship_rnd" +/turf/space, +/area/space) +"QK" = ( +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/console_screen, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/micro_laser, +/obj/item/stock_parts/micro_laser/ultra, +/obj/structure/rack, +/obj/machinery/apc{ + name = "south bump"; + pixel_y = -22 }, -/turf/simulated/floor/tiled/white, -/area/ship/trade/science/fabricaton) +/obj/structure/cable, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/item/flashlight, +/obj/item/flashlight, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"QV" = ( +/obj/machinery/artifact_analyser, +/turf/floor/tiled/white, +/area/ship/trade/artifact_storage) "Rb" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/cargo/lower) "Rl" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/mineral/processing_unit{ - input_turf = 1; - output_turf = 2 - }, -/turf/simulated/floor/tiled/steel_grid, +/obj/machinery/material_processing/compressor, +/turf/floor/plating, /area/ship/trade/cargo/lower) "Rs" = ( /obj/machinery/button/blast_door{ id_tag = "rndshutters"; name = "Desk Shutters"; - pixel_x = -25 + pixel_x = -24; + dir = 4 }, /obj/machinery/computer/design_console{ - dir = 4; - icon_state = "computer" + dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) "Sb" = ( /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; - pixel_x = 0; - pixel_y = -32 + pixel_y = -21 }, -/obj/effect/decal/cleanable/vomit, +/obj/effect/decal/cleanable/vomit/mapped, /obj/structure/hygiene/toilet{ - icon_state = "toilet00"; dir = 1 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/ship/trade/drunk_tank) +"Sc" = ( +/obj/structure/window/reinforced, +/obj/effect/floor_decal/corner/beige{ + dir = 5 + }, +/turf/floor/tiled, +/area/ship/trade/cargo/lower) "Sm" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/tiled/steel_grid, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/ship/trade/cargo/lower) +"Sx" = ( +/obj/machinery/material_processing/unloader, +/turf/floor/plating, /area/ship/trade/cargo/lower) "Tb" = ( /obj/machinery/light, /obj/machinery/botany/extractor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science) "Tp" = ( /obj/item/mollusc/barnacle{ - pixel_w = 18 + pixel_x = 18 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) +"TC" = ( +/obj/machinery/recharge_station, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"TZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "Ub" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3375,23 +3235,27 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/lower) -"Ud" = ( -/obj/item/mollusc/barnacle{ - pixel_z = 19 +"UX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/structure/cable, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/space, -/area/space) +/turf/floor/plating, +/area/ship/trade/drunk_tank) +"Va" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall, +/area/ship/trade/artifact_storage) "Vb" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3400,65 +3264,65 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/structure/cable{ - icon_state = "5-8" - }, /obj/machinery/door/firedoor, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, /area/ship/trade/maintenance/lower) "Vc" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/dorms2) -"VM" = ( -/obj/effect/paint/brown, -/turf/simulated/wall, -/area/ship/trade/maintenance/robot) +"Vm" = ( +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/structure/closet/crate, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/fiberglass/fifty, +/obj/item/clothing/head/welding, +/obj/item/stack/material/cardstock/mapped/cardboard/fifty, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/tape_roll/barricade_tape/engineering, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/techstorage) +"VX" = ( +/turf/floor/plating, +/area/ship/trade/maintenance/lower) +"Wi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "Wm" = ( /obj/machinery/network/relay{ initial_network_id = "tradenet" }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/ship/trade/maintenance/techstorage) -"WT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/computer/mining{ - density = 0; - pixel_w = 32; - pixel_z = 0 - }, -/turf/simulated/floor/tiled/steel_grid, -/area/ship/trade/cargo/lower) "WZ" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/science) -"Xb" = ( -/obj/item/stock_parts/circuitboard/pacman, -/obj/item/stock_parts/circuitboard/recharge_station, -/obj/item/stock_parts/circuitboard/shield_generator, -/obj/structure/table/rack, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/machinery/firealarm{ - pixel_y = 24 - }, -/obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/maintenance/techstorage) "XF" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, /turf/space, @@ -3466,52 +3330,71 @@ "Yb" = ( /obj/item/stock_parts/circuitboard/helm, /obj/item/stock_parts/circuitboard/unary_atmos/cooler, -/obj/structure/table/rack, +/obj/structure/rack, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/item/stock_parts/circuitboard/unary_atmos/heater, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) +"YH" = ( +/turf/floor/plating/airless, +/area/ship/trade/maintenance/eva) +"Za" = ( +/turf/floor/plating, +/area/ship/trade/drunk_tank) "Zb" = ( -/obj/item/storage/toolbox/electrical, -/obj/item/storage/toolbox/electrical{ +/obj/item/toolbox/electrical, +/obj/item/toolbox/electrical{ pixel_x = 7; pixel_y = 4 }, /obj/item/t_scanner, /obj/item/cell/high, -/obj/item/tape_roll, +/obj/item/stack/tape_roll/duct_tape, /obj/item/stock_parts/circuitboard/air_alarm, /obj/item/stock_parts/circuitboard/airlock_electronics, /obj/item/stock_parts/circuitboard/airlock_electronics, -/obj/structure/table/rack, +/obj/structure/rack, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/emergency_dispenser/north, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/techstorage) "Zd" = ( /obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/mining/brace, /obj/random/accessory, /obj/random/accessory, -/turf/simulated/floor/tiled/monotile, +/obj/machinery/floodlight, +/obj/random/soap, +/turf/floor/tiled/monotile, /area/ship/trade/cargo/lower) "Zs" = ( -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Junior Researcher" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/science/fabricaton) +"Zv" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/storage) +"ZA" = ( +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled, +/area/ship/trade/maintenance/lower) "ZJ" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/escape_star) "ZY" = ( -/turf/simulated/floor/lino, +/turf/floor/lino, /area/ship/trade/crew/dorms2) (1,1,1) = {" @@ -3841,91 +3724,8 @@ aa aa aa aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa +"} +(5,1,1) = {" aa aa aa @@ -4001,12 +3801,13 @@ aa aa aa aa +iS aa aa aa aa "} -(7,1,1) = {" +(6,1,1) = {" aa aa aa @@ -4088,7 +3889,7 @@ aa aa aa "} -(8,1,1) = {" +(7,1,1) = {" aa aa aa @@ -4170,7 +3971,7 @@ aa aa aa "} -(9,1,1) = {" +(8,1,1) = {" aa aa aa @@ -4252,7 +4053,7 @@ aa aa aa "} -(10,1,1) = {" +(9,1,1) = {" aa aa aa @@ -4334,7 +4135,7 @@ aa aa aa "} -(11,1,1) = {" +(10,1,1) = {" aa aa aa @@ -4416,7 +4217,7 @@ aa aa aa "} -(12,1,1) = {" +(11,1,1) = {" aa aa aa @@ -4498,7 +4299,7 @@ aa aa aa "} -(13,1,1) = {" +(12,1,1) = {" aa aa aa @@ -4580,7 +4381,7 @@ aa aa aa "} -(14,1,1) = {" +(13,1,1) = {" aa aa aa @@ -4662,7 +4463,7 @@ aa aa aa "} -(15,1,1) = {" +(14,1,1) = {" aa aa aa @@ -4724,7 +4525,6 @@ aa aa aa aa -fe aa aa aa @@ -4743,9 +4543,9 @@ aa aa aa aa -"} -(16,1,1) = {" aa +"} +(15,1,1) = {" aa aa aa @@ -4791,6 +4591,7 @@ aa aa aa aa +eH aa aa aa @@ -4826,7 +4627,7 @@ aa aa aa "} -(17,1,1) = {" +(16,1,1) = {" aa aa aa @@ -4908,7 +4709,7 @@ aa aa aa "} -(18,1,1) = {" +(17,1,1) = {" aa aa aa @@ -4990,7 +4791,7 @@ aa aa aa "} -(19,1,1) = {" +(18,1,1) = {" aa aa aa @@ -5072,7 +4873,7 @@ aa aa aa "} -(20,1,1) = {" +(19,1,1) = {" aa aa aa @@ -5154,7 +4955,7 @@ aa aa aa "} -(21,1,1) = {" +(20,1,1) = {" aa aa aa @@ -5236,7 +5037,7 @@ aa aa aa "} -(22,1,1) = {" +(21,1,1) = {" aa aa aa @@ -5318,7 +5119,7 @@ aa aa aa "} -(23,1,1) = {" +(22,1,1) = {" aa aa aa @@ -5400,7 +5201,7 @@ aa aa aa "} -(24,1,1) = {" +(23,1,1) = {" aa aa aa @@ -5482,7 +5283,7 @@ aa aa aa "} -(25,1,1) = {" +(24,1,1) = {" aa aa aa @@ -5564,7 +5365,7 @@ aa aa aa "} -(26,1,1) = {" +(25,1,1) = {" aa aa aa @@ -5646,7 +5447,7 @@ aa aa aa "} -(27,1,1) = {" +(26,1,1) = {" aa aa aa @@ -5728,7 +5529,7 @@ aa aa aa "} -(28,1,1) = {" +(27,1,1) = {" aa aa aa @@ -5766,17 +5567,17 @@ aa aa aa aa -MK aa aa aa +Qg +aa +Qg aa -XF aa aa aa aa -MK aa aa aa @@ -5810,7 +5611,7 @@ aa aa aa "} -(29,1,1) = {" +(28,1,1) = {" aa aa aa @@ -5850,10 +5651,11 @@ XF sY sY sY -lD -lD -Dl -tf +Va +Va +ag +Va +ca ca ca cr @@ -5861,12 +5663,11 @@ cr cP cZ cZ -WZ +cZ iW WZ XF -Jv -Jv +aa aa aa aa @@ -5892,7 +5693,7 @@ aa aa aa "} -(30,1,1) = {" +(29,1,1) = {" aa aa aa @@ -5932,25 +5733,25 @@ sY Mx ah ah -VM -aO -bm +aP +iQ +lD +yT sB -Qi +HY Rs Nc Ic cP da NL -ob -jH -WZ -cz -se -se -Jv -aa +NL +dK +yF +rv +rv +rv +rv aa aa aa @@ -5974,7 +5775,7 @@ aa aa aa "} -(31,1,1) = {" +(30,1,1) = {" aa aa aa @@ -6014,11 +5815,12 @@ sY sY ah fs -aO -aZ -bn -ce -Fb +aP +qF +bm +qF +sB +sM Fw cs Jr @@ -6026,14 +5828,13 @@ JM fL fL fL -fL -WZ -Xb -nz -eJ +De +yF +se +se +se +se se -aa -aa aa aa aa @@ -6056,7 +5857,7 @@ aa aa aa "} -(32,1,1) = {" +(31,1,1) = {" aa aa aa @@ -6093,30 +5894,30 @@ aa aa aa Ei -ai +ac ar cb aP -ba -bo -ce +aZ +bn +QV +JM cc Zs ub cJ -ce +JM db dq dD Tb -cS -Yb -et -eK +dZ +wl +LE +nz +eJ ef -rv -aa -aa +se aa aa aa @@ -6138,7 +5939,7 @@ aa aa aa "} -(33,1,1) = {" +(32,1,1) = {" aa aa aa @@ -6175,12 +5976,13 @@ aa aa aa Ei -ai +ac ar aC aO -bb -bp +ba +bo +nG ce cd Qc @@ -6191,14 +5993,13 @@ lb dr dE dO -cS -rb -eu -eL +dZ +Yb +et +mN +QK ef rv -fX -aa aa aa aa @@ -6220,7 +6021,7 @@ aa aa aa "} -(34,1,1) = {" +(33,1,1) = {" aa aa aa @@ -6257,12 +6058,13 @@ aa aa aa Ei -ai +ac ar jb aP aO zb +aO ce ce hp @@ -6273,15 +6075,14 @@ dd Ob cS nn -cS -Wm +dZ +rb eu -pn +eN +ni ef rv -aa -aa -aa +fX aa aa aa @@ -6302,7 +6103,7 @@ aa aa aa "} -(35,1,1) = {" +(34,1,1) = {" aa aa aa @@ -6339,28 +6140,29 @@ aa aa aa Ei -ai +ac as aE sb bc -br -bI -Eb -ds -kb -lO +hf +Ml +Wi +it +TZ +uz uo cf -kb uw -dP +kb +Py +Jl tE uj -ec -tb +pn +eN +Vm ef -se rv aa aa @@ -6382,10 +6184,8 @@ aa aa aa aa -aa "} -(36,1,1) = {" -aa +(35,1,1) = {" aa aa aa @@ -6420,10 +6220,93 @@ aa ql pr pr -pr al al al +ah +ah +ah +On +br +zJ +bI +ds +On +On +ap +VX +VX +vI +dP +VX +dZ +Wm +ew +eN +iH +ef +rv +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +aj +au +aG +aF +nf +un ao ao Ab @@ -6437,11 +6320,12 @@ ao Ab ao Ub +rW dZ Zb ew -eN eV +TC ef rv aa @@ -6464,7 +6348,6 @@ aa aa aa aa -aa "} (37,1,1) = {" aa @@ -6499,12 +6382,12 @@ aa aa aa aa -pr -pr -al -al -aF -js +ae +ak +av +aG +aS +du Cr aR bd @@ -6518,12 +6401,13 @@ cU df dt Qb -dR +dP +On dZ -ek +lg ew -eN eW +my ef rv aa @@ -6546,7 +6430,6 @@ aa aa aa aa -aa "} (38,1,1) = {" aa @@ -6581,13 +6464,13 @@ aa aa aa aa -ad -aj -au -aG -aS -du +pr +lE +al +al +aH aU +du Js gb bu @@ -6601,14 +6484,14 @@ mb lK ao dS -eb -eb +On +ef +ef ey -eb -eb -eb -vW -aa +ef +ef +ef +rv aa aa aa @@ -6663,17 +6546,17 @@ aa aa aa aa -ae -ak -av -aH -aT +LA +LN +du +du +du aU du du Dh bv -bL +du bV lZ lZ @@ -6683,10 +6566,11 @@ dh dv ao dT +On eb em ez -eP +Zv eY eb vW @@ -6710,7 +6594,6 @@ aa aa aa aa -aa "} (40,1,1) = {" aa @@ -6745,14 +6628,14 @@ aa aa aa aa -pr -lE -al -al -vz +LA +Sc +Sx +Sx +CN rB du -aU +ui bf bw bM @@ -6765,6 +6648,7 @@ ao lZ ao dU +VX eb en eA @@ -6792,7 +6676,6 @@ aa aa aa aa -aa "} (41,1,1) = {" aa @@ -6827,11 +6710,11 @@ aa aa aa aa -xj +pr IU he -jM -CN +he +lw aU Lx Zd @@ -6847,12 +6730,13 @@ di hI ao dV +On ed ee gc ee ee -ee +ed Gd aa aa @@ -6874,7 +6758,6 @@ aa aa aa aa -aa "} (42,1,1) = {" aa @@ -6909,11 +6792,11 @@ aa aa aa aa -xj +pr Bq tz Rl -WT +aU HH ax aV @@ -6929,12 +6812,13 @@ dj dw Rb dW +On DQ eo eC eR hc -ee +ed Gd aa aa @@ -6956,7 +6840,6 @@ aa aa aa aa -aa "} (43,1,1) = {" aa @@ -6992,12 +6875,12 @@ aa aa aa pr -pr -pr -pr -ao -al -al +Sc +zC +oC +gh +od +jV ao ao Ab @@ -7011,6 +6894,7 @@ ao Ab ao Vb +rW ed ep eD @@ -7038,7 +6922,6 @@ aa aa aa aa -aa "} (44,1,1) = {" aa @@ -7072,35 +6955,117 @@ aa aa aa aa +ql +pr +pr +pr +pr +gX +ZJ +ZJ +ZJ +bi +rN +VX +On +On +VX +VX +ap +dk +On +ZA +dY +VX +ee +aw +aB +aN +fc +ed +Gd +fX +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa aa Ei -ap +af ay aK wb -bi +EB bz -bP -bZ +ps +yL cl cC bP Mb -dk +dl cC dH -dY +La +uX ee -eq -eE -eT -fc +ed +aD +ed +ed ed Gd -fX aa aa aa @@ -7122,7 +7087,7 @@ aa aa aa "} -(45,1,1) = {" +(46,1,1) = {" aa aa aa @@ -7159,7 +7124,7 @@ aa aa aa Ei -ap +af ay nb aX @@ -7171,16 +7136,16 @@ cm Kb cm cm -dl +ts Pb -dI -DX -uh -uh -eF -ee -ee -ed +Za +En +DV +hn +Gd +aI +Gd +Gd Gd aa aa @@ -7204,7 +7169,7 @@ aa aa aa "} -(46,1,1) = {" +(47,1,1) = {" aa aa aa @@ -7241,7 +7206,7 @@ aa aa aa Ei -ap +af ay aM aX @@ -7255,15 +7220,15 @@ cM cm dm dy +UX dJ DX -rP -uh -eG -uh Gd Gd +aJ +er aa +rP aa aa aa @@ -7286,7 +7251,7 @@ aa aa aa "} -(47,1,1) = {" +(48,1,1) = {" aa aa aa @@ -7323,7 +7288,7 @@ aa aa aa Tp -ap +af az qb aX @@ -7337,14 +7302,14 @@ Lb cm Nb dz +AM Sb DX -Ud -er -eH +YH +Gd +aL er aa -rP aa aa aa @@ -7368,7 +7333,7 @@ aa aa aa "} -(48,1,1) = {" +(49,1,1) = {" aa aa aa @@ -7419,12 +7384,12 @@ cO cm do dA +kr dL DX aa -er -eI -er +aa +aa aa aa aa @@ -7450,7 +7415,7 @@ aa aa aa "} -(49,1,1) = {" +(50,1,1) = {" aa aa aa @@ -7492,15 +7457,16 @@ aA aA kP aY -bE +ai aX cq cp cG -cO +PJ xa wI dB +fa BO DX aa @@ -7530,9 +7496,8 @@ aa aa aa aa -aa "} -(50,1,1) = {" +(51,1,1) = {" aa aa aa @@ -7574,15 +7539,16 @@ gX gX jD jD -vw +am jD Vc cq -cH +an xa cq Cd -sh +at +at DX DX aa @@ -7612,9 +7578,8 @@ aa aa aa aa -aa "} -(51,1,1) = {" +(52,1,1) = {" aa aa aa @@ -7696,88 +7661,6 @@ aa aa aa "} -(52,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} (53,1,1) = {" aa aa @@ -8808,7 +8691,7 @@ aa aa aa aa -aa +eH aa aa aa diff --git a/maps/tradeship/tradeship-2.dmm b/maps/tradeship/tradeship-2.dmm index e62bb8f0211d..765635bb94f9 100644 --- a/maps/tradeship/tradeship-2.dmm +++ b/maps/tradeship/tradeship-2.dmm @@ -3,116 +3,399 @@ /turf/space, /area/space) "ab" = ( -/obj/structure/shuttle/engine/propulsion/burst/left{ +/obj/structure/chair/comfy/brown{ dir = 1 }, -/turf/simulated/floor/airless, -/area/ship/trade/shuttle/outgoing) +/obj/effect/floor_decal/corner/beige{ + dir = 10 + }, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) "ac" = ( -/obj/machinery/airlock_sensor{ - id_tag = "tradeship_shuttle_sensor"; - pixel_y = -24 +/obj/structure/handrail, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + cycle_to_external_air = 1; + id_tag = "bee_star"; + pixel_y = 24; + tag_interior_sensor = "bee_interior_sensor"; + tag_pump_out_external = "bee_pump_out_external" }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 +/obj/structure/cable/orange{ + icon_state = "4-8" }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 1; - id_tag = "tradeship_shuttle_pump_out_internal" +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 10 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) "ad" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/machinery/atmospherics/pipe/simple/visible/supply, /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "ae" = ( -/obj/structure/cable{ - icon_state = "4-9" - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 - }, -/obj/machinery/network/acl{ - initial_network_id = "tradenet" +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/ship/trade/command/captain) "af" = ( -/obj/item/bedsheet/captain, +/obj/item/paper_bin, +/obj/item/pen, +/obj/structure/table/laminate, +/obj/machinery/light_switch{ + pixel_y = 25 + }, +/obj/random/action_figure, +/obj/random_multi/single_item/captains_spare_id, /obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/laminate, +/area/ship/trade/command/captain) +"ag" = ( +/obj/item/bedsheet/captain, /obj/item/gun/projectile/pistol/holdout, /obj/structure/bed/padded, -/obj/effect/landmark{ - name = "JoinLateCryoCaptain" +/obj/abstract/landmark/latejoin/cryo_captain, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 21 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/trade/command/captain) +"ah" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) +"ai" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 21 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) +"aj" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -21 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) "ak" = ( -/obj/effect/overmap/visitable/ship/tradeship, -/turf/space, -/area/space) +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/airlock/hatch/autoname/command, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"al" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/apc{ + dir = 8; + name = "Crew Deck APC"; + pixel_x = -22 + }, +/obj/structure/cable, +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) +"am" = ( +/obj/structure/ladder, +/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/zpipe/up/supply{ + dir = 1 + }, +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "16-0" + }, +/obj/machinery/atm{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) +"an" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/command/hallway) +"ao" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/command/bridge) +"ap" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/command/hallway) +"aq" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) "ar" = ( /obj/machinery/door/blast/regular, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/command/captain) "as" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/command/captain) "at" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/structure/lattice, +/obj/machinery/light/navigation/delay5{ + color = "#00ff00" + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"au" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/turf/floor/tiled/steel_ridged, +/area/ship/trade/command/bridge) +"av" = ( +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/turf/floor/plating/airless, +/area/ship/trade/crew/toilets) "aw" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/command/fmate) +"ax" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/crew/saloon) +"ay" = ( +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/turf/floor/plating/airless, +/area/ship/trade/crew/medbay/chemistry) +"az" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/crew/toilets) +"aA" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ship/trade/crew/medbay/chemistry) +"aB" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/closet/emcloset, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"aC" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) +"aD" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) +"aE" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/crew/hallway/port) +"aF" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) +"aG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/cargo) +"aH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/starboard) +"aI" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/plating, +/area/ship/trade/maintenance/hallway) "aJ" = ( -/obj/item/paper_bin, -/obj/item/pen, -/obj/structure/table/woodentable, -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"aK" = ( +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/plating, +/area/ship/trade/maintenance/hallway) +"aL" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/effect/paint/sun, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"aM" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 }, -/obj/machinery/light_switch{ - pixel_y = 25 +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/unused) +"aN" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/hatch/autoname/general, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"aO" = ( +/obj/random/maintenance, +/obj/machinery/atm{ + pixel_y = 32 }, -/obj/random/action_figure, -/obj/random_multi/single_item/captains_spare_id, -/turf/simulated/floor/wood, -/area/ship/trade/command/captain) -"aL" = ( -/turf/simulated/wall/titanium, -/area/ship/trade/shuttle/outgoing) +/turf/floor/tiled/monotile, +/area/ship/trade/dock) "aP" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/megaphone, /obj/machinery/cell_charger, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/ship/trade/command/fmate) "aQ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -121,26 +404,47 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/trade/command/fmate) -"aS" = ( +"aR" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, /obj/structure/cable{ - icon_state = "2-8" + icon_state = "4-8" + }, +/obj/machinery/light{ + icon_state = "bulb1" }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"aS" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" + icon_state = "1-4" }, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/tiled/dark, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/tiled/monotile, /area/ship/trade/command/hallway) +"aT" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 6 + }, +/turf/floor/plating, +/area/ship/trade/maintenance/atmos) "aU" = ( /obj/structure/cable{ icon_state = "6-8" @@ -151,7 +455,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/ship/trade/command/captain) "aV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -160,757 +464,856 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/ship/trade/command/captain) "aW" = ( -/obj/structure/bed/chair/comfy/brown, -/turf/simulated/floor/carpet/blue, +/obj/structure/chair/comfy/brown, +/turf/floor/carpet/blue, /area/ship/trade/command/captain) +"aX" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "engwindow" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/power) +"aY" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "scram" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/black{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/maintenance/engine/aft) +"aZ" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "scram" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/engine/aft) "ba" = ( /obj/machinery/computer/modular/preset/cardslot/command{ - icon_state = "computer"; dir = 4 }, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/ship/trade/command/fmate) "bb" = ( -/obj/machinery/light, -/obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, -/obj/machinery/alarm{ - dir = 1; - icon_state = "alarm0"; - pixel_x = 0; - pixel_y = -24 +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/machinery/computer/modular/preset/engineering{ - dir = 1 +/obj/structure/cable{ + icon_state = "1-8" }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) +/obj/machinery/light{ + icon_state = "bulb1" + }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) "bc" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/dark, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/monotile, /area/ship/trade/command/hallway) "bd" = ( /obj/machinery/atmospherics/pipe/simple/visible/universal, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = 21 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) -"bg" = ( +"be" = ( /obj/effect/floor_decal/industrial/outline/yellow, -/obj/structure/closet/walllocker/emerglocker/north, -/obj/machinery/floodlight, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"bh" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/obj/machinery/computer/shuttle_control/explore/tradeship{ + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"bf" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/command/bridge) +"bg" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/structure/chair/shuttle/black{ + dir = 8 + }, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/obj/machinery/light{ + dir = 1; + icon_state = "tube1" + }, +/obj/structure/emergency_dispenser/north, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) "bi" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/structure/chair/shuttle/blue{ + dir = 8 + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) +"bj" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/command/bridge) +"bk" = ( /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"bm" = ( -/turf/simulated/wall/r_wall, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -21 + }, +/turf/floor/tiled/monotile, /area/ship/trade/dock) -"bp" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/obj/machinery/light, -/obj/structure/bed/chair{ +"bl" = ( +/obj/structure/closet/secure_closet/freezer/meat, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/obj/effect/floor_decal/corner/red/diagonal, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/item/box/fancy/egg_box, +/obj/item/box/fancy/egg_box, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/yeast, +/turf/floor/tiled, +/area/ship/trade/crew/kitchen) +"bm" = ( +/turf/wall/r_wall, +/area/ship/trade/dock) +"bn" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/closet/secure_closet/freezer/kitchen, +/turf/floor/tiled/techfloor, +/area/ship/trade/cargo) +"bo" = ( +/obj/random/maintenance, +/obj/structure/sign/warning/vacuum{ + dir = 8; + pixel_x = 34 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) "bq" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/light, +/obj/effect/floor_decal/techfloor/orange{ + dir = 10 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"br" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/emergency_dispenser/north, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"bs" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "dock_star_in" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/dock) +"bt" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "tradeship_starboard_dock"; + pixel_y = 25; + tag_airpump = "dock_star_pump"; + tag_chamber_sensor = "dock_star_sensor"; + tag_exterior_door = "dock_star_out"; + tag_interior_door = "dock_star_in" + }, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/dock) +"bu" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; - level = 2 + id_tag = "dock_star_pump" }, -/obj/structure/bed/chair{ +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/obj/machinery/airlock_sensor{ + id_tag = "dock_star_sensor"; + pixel_y = 24 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/dock) "bv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"bw" = ( +/obj/machinery/button/access/exterior{ + dir = 4; + id_tag = "tradeship_starboard_dock"; + pixel_x = 12; + pixel_y = 24; + directional_offset = null + }, +/obj/machinery/shield_diffuser, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/external/glass/bolted{ + id_tag = "dock_star_out" + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/dock) +"bx" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/cable/orange{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/structure/closet/medical_wall/filled{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) +"by" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "dock_port_pump" + }, /obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" + icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 +/obj/machinery/airlock_sensor{ + id_tag = "dock_port_sensor"; + pixel_y = 24 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/dock) -"bw" = ( +"bz" = ( /obj/machinery/light{ - icon_state = "tube1"; dir = 1 }, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 1; - name = "Docking Area APC" +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "tradeship_dock_port"; + pixel_y = 24; + tag_airpump = "dock_port_pump"; + tag_chamber_sensor = "dock_port_sensor"; + tag_exterior_door = "dock_port_out"; + tag_interior_door = "dock_port_in" }, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 }, -/obj/machinery/light_switch{ - pixel_w = 27 +/obj/structure/cable{ + icon_state = "4-8" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/dock) -"bx" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) "bA" = ( /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/dock) "bB" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 - }, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/sign/warning/vacuum{ - pixel_x = -35 + dir = 4; + pixel_x = -34 }, -/obj/machinery/computer/shuttle_control/explore/tradeship, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "bC" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "bD" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "bE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ +/obj/machinery/atmospherics/pipe/simple/hidden{ dir = 4 }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "dock_port_in" + }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/steel_ridged, /area/ship/trade/dock) "bF" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" + icon_state = "1-8" }, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" + icon_state = "1-2" }, -/obj/effect/floor_decal/ivenmoth, -/turf/simulated/floor/tiled/monotile, +/obj/random/maintenance, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "bG" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/monotile, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "bH" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 +/obj/machinery/door/airlock/external/bolted{ + id_tag = "bee_star_outer" }, -/obj/structure/sign/warning/vacuum{ - pixel_x = 35 +/obj/machinery/button/access/exterior{ + dir = 4; + id_tag = "bee_star"; + pixel_x = 16; + pixel_y = -26; + directional_offset = null }, -/obj/effect/floor_decal/steeldecal/steel_decals6, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"bQ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10; - icon_state = "intact" +/obj/structure/cable/orange{ + icon_state = "4-8" + }, +/obj/effect/shuttle_landmark/docking_arm_port/shuttle{ + dir = 4 + }, +/obj/abstract/local_dock/automatic{ + dir = 4; + shuttle_tag = "Bee Shuttle"; + port_tag = "starboard"; + name = "starboard docking port"; + dock_target = "bee_star" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"bI" = ( +/obj/machinery/button/access/exterior{ + dir = 8; + id_tag = "tradeship_dock_port"; + pixel_x = -12; + pixel_y = 24; + directional_offset = null + }, +/obj/machinery/door/airlock/external/bolted{ + id_tag = "dock_port_out" }, +/obj/machinery/shield_diffuser, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/steel_ridged, /area/ship/trade/dock) -"bT" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +"bJ" = ( +/obj/structure/handrail, +/obj/machinery/airlock_sensor{ + id_tag = "bee_star_sensor"; + pixel_y = 24 }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 +/obj/structure/cable/orange{ + icon_state = "4-8" }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"bW" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 6 +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"bK" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 6 }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"bX" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/structure/handrail{ + dir = 8 }, /obj/machinery/button/access/interior{ - id_tag = "tradeship_starboard_dock"; - pixel_x = -12; - pixel_y = 20 - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 + dir = 8; + id_tag = "bee_star"; + pixel_x = 20 }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) +"bL" = ( /obj/machinery/door/airlock/external/bolted{ - id_tag = "dock_star_in" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + id_tag = "bee_star_inner" }, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/dock) -"bY" = ( -/obj/machinery/airlock_sensor{ - id_tag = "dock_star_sensor"; - pixel_y = 37 +/obj/structure/cable/orange{ + icon_state = "4-8" }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - id_tag = "tradeship_starboard_dock"; - pixel_y = 25; - tag_airpump = "dock_star_pump"; - tag_chamber_sensor = "dock_star_sensor"; - tag_exterior_door = "dock_star_out"; - tag_interior_door = "dock_star_in" +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"bM" = ( +/obj/structure/disposalpipe/segment, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"bN" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 +/obj/machinery/button/access/interior{ + dir = 4; + id_tag = "tradeship_dock_port"; + pixel_x = -20 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/monotile, /area/ship/trade/dock) -"bZ" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ +"bO" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/steeldecal/steel_decals6, +/obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8; - id_tag = "dock_star_pump" + level = 2 }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 +/obj/machinery/button/access/interior{ + dir = 8; + id_tag = "tradeship_starboard_dock"; + pixel_x = 20 }, -/obj/machinery/light{ - dir = 1 +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"bQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/monotile, /area/ship/trade/dock) -"ca" = ( -/obj/machinery/button/access/exterior{ - id_tag = "bearcat_starboard_dock"; - pixel_x = 18; - pixel_y = 20 +"bU" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 }, -/obj/machinery/door/airlock/external/bolted{ - id_tag = "dock_star_out" +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"bW" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 }, -/obj/machinery/shield_diffuser, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "cb" = ( -/obj/effect/shuttle_landmark/docking_arm_starboard/pod, -/turf/space, -/area/space) -"cc" = ( -/obj/machinery/door/airlock/hatch, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - icon_state = "2-5" + icon_state = "1-8" }, -/obj/structure/sign{ - icon_state = "radiation"; - pixel_x = 32 +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "tradeship_rescue_shuttle_pump_out_internal" }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) -"cd" = ( -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/wall/titanium, -/area/ship/trade/shuttle/outgoing) -"cf" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + cycle_to_external_air = 1; + dir = 4; + id_tag = "tradeship_rescue_shuttle"; + pixel_x = -22; + pixel_y = 32; + tag_airpump = "tradeship_rescue_shuttle_pump"; + tag_chamber_sensor = "tradeship_rescue_shuttle_sensor"; + tag_exterior_door = "tradeship_rescue_shuttle_out"; + directional_offset = null }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/ship/trade/dock) -"cg" = ( -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; - dir = 4 +/obj/effect/floor_decal/corner/white{ + dir = 9 }, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/machinery/airlock_sensor{ + id_tag = "tradeship_rescue_shuttle_sensor"; + pixel_x = -22; + pixel_y = 20; + dir = 4; + directional_offset = null }, -/obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, -/area/ship/trade/dock) -"ch" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 9 +/obj/abstract/local_dock/automatic{ + dir = 1; + shuttle_tag = "Rescue Shuttle"; + port_tag = "center"; + name = "center"; + reorient = 0 }, -/obj/effect/floor_decal/steeldecal/steel_decals6, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"cj" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"cd" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" }, -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/dock) -"cl" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 5 +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "bee_star_pump" }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"cm" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 8 +/obj/structure/closet/walllocker/suit{ + dir = 4; + pixel_x = -32 }, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"cf" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, +/obj/machinery/door/firedoor, +/turf/floor/plating, /area/ship/trade/dock) -"cp" = ( +"cj" = ( +/obj/machinery/computer/ship/helm, /obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 +/turf/floor/bluegrid, +/area/ship/trade/command/bridge) +"cl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"cq" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"cs" = ( +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"cp" = ( /obj/machinery/atmospherics/unary/tank/air, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "ct" = ( -/obj/structure/sign/warning/docking_area, -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall, -/area/ship/trade/dock) +/obj/structure/sign/warning/docking_area{ + dir = 8; + pixel_x = 34 + }, +/turf/space, +/area/space) "cu" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/dock) "cw" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +/obj/structure/chair/comfy/teal{ + dir = 1 + }, +/obj/abstract/landmark/start{ + name = "Captain" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, -/area/ship/trade/dock) +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/overmap/visitable/ship/tradeship, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) "cy" = ( /obj/structure/lattice, /turf/space, /area/space) "cz" = ( -/obj/machinery/power/apc{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/machinery/atmospherics/pipe/manifold/hidden/blue{ dir = 4 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"cA" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/obj/item/wrench, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "cB" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal{ +/obj/structure/handrail{ dir = 4 }, -/obj/structure/cable{ - icon_state = "2-8" +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "bee_pump_out_external" + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 9 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "cC" = ( -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 +/obj/machinery/atmospherics/pipe/manifold/hidden/red{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/blue{ - icon_state = "intact"; - dir = 9 +/obj/effect/floor_decal/techfloor/orange{ + dir = 5 }, -/obj/machinery/floodlight, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "cE" = ( -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "cG" = ( -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) -"cH" = ( -/obj/machinery/light{ - dir = 8 +"cI" = ( +/obj/structure/handrail{ + dir = 4 }, -/obj/structure/closet/crate/uranium, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"cI" = ( -/obj/structure/cable, -/obj/machinery/power/port_gen/pacman/super, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"cJ" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall, -/area/ship/trade/crew/saloon) -"cK" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 }, -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/crew/saloon) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "cL" = ( /obj/random/maintenance, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "cN" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/saloon) "cO" = ( -/obj/machinery/vending/snack{ - dir = 4 +/obj/machinery/apc{ + dir = 1; + name = "Crew Areas APC"; + pixel_y = 22 }, -/obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 +/obj/structure/cable{ + icon_state = "0-4" }, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/deck/tarot, +/obj/item/synthesized_instrument/guitar, +/obj/random/drinkbottle, +/obj/item/chems/drinks/bottle/limejuice, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "cQ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "cS" = ( -/obj/machinery/vending/coffee{ - dir = 8 - }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/obj/item/chems/drinks/shaker, +/obj/item/chems/drinks/bottle/orangejuice, +/obj/random/drinkingglass, +/obj/random/drinkingglass, +/obj/random/drinkingglass, +/obj/random/drinkingglass, +/obj/random/drinkingglass, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "cT" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/toilets) "cU" = ( -/turf/simulated/wall/r_wall, -/area/ship/trade/crew/toilets) -"cV" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/wall/r_wall, /area/ship/trade/crew/toilets) "cW" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "cY" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "cZ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/item/stool/padded, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/obj/item/synthesized_instrument/guitar, -/turf/simulated/floor/tiled, +/obj/structure/chair/wood, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "da" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "db" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/recharger, /obj/structure/sign/poster{ pixel_x = 32; - pixel_y = 0 + dir = 4 }, -/obj/item/trash/tray, +/obj/item/plate/tray, /obj/item/circular_saw, -/turf/simulated/floor/tiled, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dc" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/item/crowbar, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "dd" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/medbay/chemistry) "de" = ( -/turf/simulated/wall, -/area/ship/trade/crew/medbay/chemistry) -"df" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/tiled{ - icon_state = "white" - }, +/turf/wall, /area/ship/trade/crew/medbay/chemistry) "dh" = ( /obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 + dir = 4; + icon_state = "twindow" }, /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, /obj/structure/window/reinforced/tinted{ @@ -918,110 +1321,108 @@ }, /obj/item/soap, /obj/structure/curtain/open/shower, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "di" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/structure/hygiene/toilet, /obj/structure/window/reinforced/tinted{ dir = 1 }, /obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 + dir = 4; + icon_state = "twindow" }, /obj/structure/window/reinforced/tinted{ dir = 8; icon_state = "twindow" }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/start{ +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/start{ name = "Deck Hand" }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) -"dk" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/crew/hallway/port) "dl" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/structure/reagent_dispensers/water_cooler, /obj/machinery/light{ dir = 8 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/floor/tiled, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 + }, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dm" = ( /obj/item/stool/padded, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Junior Researcher" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) -"dp" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/crew/hallway/starboard) +"dn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) "dr" = ( /obj/machinery/chemical_dispenser/full, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "ds" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagent_temperature, -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/machinery/light_switch{ - pixel_x = 24 + pixel_x = 24; + dir = 8 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "dt" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/toilets) "du" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/item/towel, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "dv" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "dw" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1030,14 +1431,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "dx" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Bathrooms"; @@ -1051,35 +1449,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/toilets) "dy" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "dz" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, @@ -1089,17 +1478,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/saloon) "dA" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1108,14 +1493,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dB" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -1123,35 +1505,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dC" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/item/stool/padded, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dD" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -1159,17 +1532,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dE" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1178,35 +1547,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dF" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "dG" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1220,7 +1580,7 @@ normalspeed = 0; stripe_color = "#ffffff" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/medbay/chemistry) "dH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1230,12 +1590,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "dI" = ( /obj/item/stool/padded, @@ -1245,19 +1602,16 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Junior Doctor" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "dJ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/chems/dropper, /obj/item/chems/glass/beaker/large, /obj/item/chems/glass/beaker/large, @@ -1266,46 +1620,39 @@ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "dK" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/medbay/chemistry) "dM" = ( /obj/structure/hygiene/toilet{ - icon_state = "toilet00"; dir = 1 }, /obj/structure/window/reinforced/tinted, /obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 + dir = 4; + icon_state = "twindow" }, /obj/structure/window/reinforced/tinted{ dir = 8; icon_state = "twindow" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random_multi/single_item/captains_spare_id, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "dN" = ( /obj/structure/hygiene/toilet{ - icon_state = "toilet00"; dir = 1 }, /obj/structure/window/reinforced/tinted{ @@ -1313,344 +1660,253 @@ icon_state = "twindow" }, /obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 + dir = 4; + icon_state = "twindow" }, /obj/structure/window/reinforced/tinted, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - name = "Bathrooms APC" + name = "Bathrooms APC"; + pixel_x = 22 }, /obj/machinery/light_switch{ - pixel_y = -25 + pixel_y = -20; + dir = 1 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "dO" = ( -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 4 + dir = 4; + icon_state = "conpipe-c" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "dP" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/saloon) "dQ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/vending/cigarette{ - dir = 1 - }, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/machinery/disposal, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dS" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dU" = ( /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 24; + dir = 8 }, /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/structure/ladder, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "dV" = ( -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "dW" = ( /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, /obj/machinery/reagentgrinder, /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "dX" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) "dY" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/kitchen) "dZ" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/kitchen) "ea" = ( /obj/structure/disposalpipe/segment, -/obj/structure/closet/walllocker/emerglocker/east, -/obj/machinery/light_switch{ - pixel_x = -25 - }, +/obj/structure/emergency_dispenser/east, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/plating, /area/ship/trade/crew/hallway/port) "eb" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/cargo) "ec" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/cargo) "ed" = ( /obj/machinery/light_switch{ - pixel_x = -25 + on = 1; + pixel_x = -25; + dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/sign/deck/first{ - pixel_x = 32 - }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "ee" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/medbay) -"ef" = ( -/obj/machinery/door/window/southright, -/obj/structure/table/marble, -/obj/machinery/door/firedoor, -/turf/simulated/floor/tiled{ - icon_state = "white" - }, -/area/ship/trade/crew/medbay/chemistry) "eh" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/space) "el" = ( /obj/structure/disposalpipe/segment, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - name = "Crew Deck APC" + name = "Crew Deck APC"; + pixel_x = 22 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "eo" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) -"eq" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, -/area/ship/trade/command/captain) "er" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/hallway/starboard) "es" = ( /obj/machinery/sleeper/standard, /obj/structure/sign/warning/nosmoking_2{ pixel_y = 28 }, -/obj/structure/closet/walllocker/emerglocker/west, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "ev" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/medbay) "ew" = ( -/turf/simulated/wall/natural/random/high_chance, +/turf/wall/natural/random/high_chance, /area/space) "ex" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/engine/port) "ey" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/kitchen) "ez" = ( /obj/effect/floor_decal/corner/red/diagonal, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "eA" = ( /obj/item/stool/padded, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/floor_decal/corner/red/diagonal, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Cook" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "eB" = ( /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - name = "Galley APC" + name = "Galley APC"; + pixel_x = 22 }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "eC" = ( /obj/structure/disposalpipe/segment, -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 - }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/sign/directions/engineering{ - pixel_x = -32 - }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/plating, /area/ship/trade/crew/hallway/port) -"eD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor, -/area/ship/trade/cargo) "eE" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/closet/crate/hydroponics/prespawned, @@ -1661,13 +1917,11 @@ /obj/structure/cable{ icon_state = "4-9" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) "eF" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -1676,26 +1930,21 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) "eH" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) "eI" = ( -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/sign/directions/engineering{ @@ -1703,69 +1952,69 @@ }, /obj/structure/ladder, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/obj/structure/sign/redcross{ - pixel_w = 32 +/obj/structure/lattice, +/obj/structure/cable{ + icon_state = "32-1" }, -/turf/simulated/floor/plating, +/obj/structure/disposalpipe/down, +/turf/open, /area/ship/trade/crew/hallway/starboard) "eL" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "eM" = ( /obj/machinery/bodyscanner{ - icon_state = "body_scanner_0"; dir = 1 }, /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "eN" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/engine/starboard) "eO" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "eP" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/item/storage/box/donkpockets, +/obj/item/box/donkpockets, /obj/effect/floor_decal/corner/red/diagonal, -/obj/item/kitchen/rollingpin, -/obj/item/chems/food/condiment/small/saltshaker{ - pixel_x = -3; - pixel_y = 0 +/obj/item/rollingpin, +/obj/item/chems/condiment/small/saltshaker{ + pixel_x = -3 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/obj/item/chems/glass/beaker{ + pixel_x = 5 + }, +/obj/item/chems/condiment/small/peppermill{ + pixel_x = 3 + }, +/obj/item/chems/condiment/enzyme, +/obj/item/chems/rag, +/obj/item/chems/cooking_vessel/pot, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "eQ" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, @@ -1774,20 +2023,16 @@ }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "eR" = ( /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 4 + dir = 4; + icon_state = "conpipe-c" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1798,21 +2043,16 @@ }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "eS" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, @@ -1822,7 +2062,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/kitchen) "eT" = ( /obj/structure/disposalpipe/junction, @@ -1833,51 +2073,41 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ icon_state = "2-8" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/plating, /area/ship/trade/crew/hallway/port) "eU" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/cargo) "eV" = ( /obj/structure/catwalk, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "fa" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/obj/structure/disposalpipe/down, -/turf/simulated/floor/plating, +/obj/structure/disposalpipe/segment, +/turf/floor/plating, /area/ship/trade/crew/hallway/starboard) "fb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Medical Bay"; @@ -1891,12 +2121,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/medbay) "fc" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -1906,141 +2134,107 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "fd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/item/stool/padded, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "fe" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/body_scanconsole{ - icon_state = "body_scannerconsole"; dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "ff" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/medbay) "fg" = ( -/obj/item/storage/pill_bottle/happy, -/obj/machinery/power/apc{ - dir = 1 +/obj/item/pill_bottle/happy, +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/port) "fh" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/machinery/meter, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/port) "fk" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/microwave, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/effect/floor_decal/corner/red/diagonal, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "fm" = ( /obj/machinery/disposal, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 24; + dir = 8 }, /obj/effect/floor_decal/corner/red/diagonal, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) -"fn" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/techmaint, -/area/ship/trade/crew/hallway/port) "fo" = ( -/obj/structure/table/standard, -/obj/item/glass_extra/straw, -/obj/item/toy/therapy_blue, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/item/defibrillator/compact/loaded, -/obj/item/modular_computer/telescreen/preset/medical{ - pixel_x = 31; - pixel_y = -2 - }, -/turf/simulated/floor/tiled/white, +/obj/structure/closet/crate/freezer, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "fp" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/catwalk, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "fr" = ( /obj/structure/closet/crate, @@ -2048,231 +2242,190 @@ /obj/random/bomb_supply, /obj/random/bomb_supply, /obj/random/bomb_supply, -/obj/item/storage/box/syringes, +/obj/item/box/syringes, /obj/structure/catwalk, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "fs" = ( /obj/structure/catwalk, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/turf/simulated/open, -/area/ship/trade/cargo) -"ft" = ( -/obj/machinery/power/apc{ - dir = 4; - name = "Crew Deck APC" - }, -/obj/structure/cable, -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, -/area/ship/trade/crew/hallway/starboard) +/turf/open, +/area/ship/trade/cargo) "fu" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/structure/iv_drip, -/obj/item/chems/ivbag/blood/AMinus, -/obj/item/chems/ivbag/blood/APlus, -/obj/item/chems/ivbag/blood/BMinus, -/obj/item/chems/ivbag/blood/BPlus, -/obj/item/chems/ivbag/blood/OMinus, -/obj/item/chems/ivbag/blood/OPlus, -/obj/machinery/newscaster{ - pixel_x = -32 - }, -/turf/simulated/floor/tiled/white, +/obj/item/chems/ivbag/blood/aminus, +/obj/item/chems/ivbag/blood/aplus, +/obj/item/chems/ivbag/blood/bminus, +/obj/item/chems/ivbag/blood/bplus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/oplus, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "fw" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, /obj/structure/sign/warning/nosmoking_1{ - pixel_y = -32 + pixel_y = -32; + dir = 1 }, -/obj/structure/sign/goldenplaque/medical{ - pixel_x = 32 +/obj/structure/sign/plaque/diploma/medical{ + pixel_x = 32; + dir = 8 }, -/obj/item/storage/firstaid/adv, +/obj/item/firstaid/adv, /obj/random/medical, -/obj/item/stack/medical/advanced/bruise_pack, +/obj/item/stack/medical/bandage/advanced, /obj/item/chems/syringe/antibiotic, /obj/item/scanner/health, -/turf/simulated/floor/tiled/white, +/obj/item/defibrillator/compact/loaded, +/obj/random/plush/therapy, +/obj/item/glass_extra/straw, +/obj/item/tank/oxygen/yellow, +/obj/structure/closet/emcloset, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) +"fx" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ship/trade/garden) "fz" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/item/coin/gold, /obj/item/coin/silver, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, /obj/machinery/meter, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/starboard) "fA" = ( -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/starboard) "fB" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/port) "fC" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/port) -"fD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/obj/structure/lattice, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/turf/space, -/area/space) "fE" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/wash) "fI" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "fJ" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning, /obj/structure/railing/mapped, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "fK" = ( /obj/structure/catwalk, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 4 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) -"fM" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/turf/space, -/area/space) "fN" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/engine/starboard) "fO" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/starboard) "fP" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/starboard) "fQ" = ( /obj/effect/floor_decal/industrial/warning, -/obj/structure/sign/warning/hot_exhaust, /obj/effect/paint/red, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/engine/port) "fT" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/wash) "fU" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/structure/undies_wardrobe, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "fV" = ( -/obj/structure/bed/chair/office/light, -/obj/effect/landmark/start{ +/obj/structure/chair/office/light, +/obj/abstract/landmark/start{ name = "Head Doctor" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "fX" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ name = "Laundry"; @@ -2287,20 +2440,16 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/wash) "fY" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/disposalpipe/junction, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 10 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -2310,52 +2459,24 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "fZ" = ( -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "ga" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/railing/mapped{ - icon_state = "railing0"; dir = 8 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) -"gb" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; - dir = 6 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, -/area/ship/trade/crew/hallway/starboard) "gc" = ( /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, @@ -2366,16 +2487,12 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/unused) "gd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2386,13 +2503,12 @@ }, /obj/random/junk, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ icon_state = "6-8" }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "ge" = ( /obj/machinery/light_switch{ @@ -2400,80 +2516,60 @@ }, /obj/random/maintenance, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/fabricator/book, -/obj/item/stack/material/plastic/ten, -/obj/item/stack/material/wood/ten, -/obj/structure/table/standard, +/obj/item/stack/material/panel/mapped/plastic/ten, +/obj/item/stack/material/plank/mapped/wood/ten, +/obj/structure/table, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "gg" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/unused) "gh" = ( /obj/effect/floor_decal/industrial/warning, -/obj/structure/sign/warning/hot_exhaust, /obj/effect/paint/red, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/engine/starboard) "gj" = ( /obj/effect/floor_decal/industrial/warning, -/obj/structure/sign/warning/hot_exhaust, /obj/effect/paint/red, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/engine/starboard) "gk" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/space, -/area/space) -"gl" = ( -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/structure/sign/warning/hot_exhaust{ + pixel_y = 32 }, -/obj/structure/lattice, -/turf/space, -/area/space) +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/port) "gm" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 5 }, /turf/space, /area/space) "gn" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/wash) "go" = ( /obj/structure/closet, @@ -2482,104 +2578,84 @@ /obj/random/clothing, /obj/random/clothing, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, -/obj/item/storage/backpack/dufflebag, -/turf/simulated/floor/tiled/freezer, +/obj/item/backpack/dufflebag, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "gp" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "gq" = ( /obj/machinery/disposal, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, /obj/machinery/light_switch{ - pixel_x = 28 + pixel_x = 24; + dir = 8 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "gr" = ( -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 - }, /obj/structure/disposalpipe/segment, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/sign/directions/medical{ dir = 4; - icon_state = "direction_med"; pixel_x = 32; - pixel_z = -4 + pixel_y = -4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "gs" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, +/obj/structure/emergency_dispenser/east, /obj/structure/railing/mapped{ - icon_state = "railing0"; dir = 8 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "gt" = ( -/obj/structure/closet/walllocker/emerglocker/west, -/obj/effect/decal/cleanable/dirt, +/obj/structure/emergency_dispenser/west, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "gu" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/unused) "gv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "gw" = ( /obj/effect/decal/cleanable/generic, /obj/structure/skele_stand{ - anchored = 0; name = "Grand Archivist Spookers" }, /obj/structure/cable{ @@ -2590,203 +2666,168 @@ level = 2 }, /obj/item/synthesized_instrument/trumpet, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "gx" = ( /obj/item/radio/intercom{ dir = 8; pixel_x = 22 }, -/turf/simulated/floor/wood/yew, -/area/ship/trade/unused) -"gy" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/floor/plating, +/turf/floor/laminate/yew, /area/ship/trade/unused) "gz" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, /turf/space, /area/space) "gA" = ( /obj/machinery/washing_machine, -/obj/item/storage/box/monkeycubes{ - pixel_z = 13 +/obj/item/box/animal_cubes/monkeys{ + pixel_y = 13 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "gB" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "gC" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/light, /obj/item/chems/spray/cleaner, -/obj/item/storage/laundry_basket, +/obj/item/laundry_basket, /obj/random_multi/single_item/captains_spare_id, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "gE" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/sign/deck/first{ - pixel_x = 32 + pixel_x = 32; + dir = 8 }, /obj/structure/railing/mapped{ - icon_state = "railing0"; dir = 8 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "gI" = ( /obj/random/maintenance, /obj/machinery/newscaster{ - pixel_x = 30 + pixel_x = 32; + dir = 4 }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "gL" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/plating, /area/ship/trade/crew/hallway/port) "gM" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "gN" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/cargo) +/obj/effect/floor_decal/techfloor/orange{ + dir = 9 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "gO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/hallway/starboard) "gP" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/hidden) "gQ" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/hidden) "gS" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/engine/starboard) -"gU" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/techmaint, -/area/ship/trade/maintenance/hallway) "gV" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "gW" = ( /obj/structure/catwalk, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/railing/mapped{ - icon_state = "railing0"; dir = 1 }, /obj/machinery/light/spot, -/turf/simulated/open, +/obj/machinery/light_switch{ + pixel_y = -20; + dir = 1 + }, +/turf/open, /area/ship/trade/cargo) -"gY" = ( -/obj/machinery/door/airlock/hatch/autoname/general, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +"hb" = ( +/obj/machinery/power/terminal{ + dir = 8 + }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "0-4" }, -/obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/hallway) -"hb" = ( -/obj/structure/shuttle/engine/propulsion/burst/left, -/turf/simulated/floor/airless, -/area/ship/trade/shuttle/outgoing) +/obj/structure/closet/crate/uranium, +/obj/item/wrench, +/obj/structure/cable/orange, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "hd" = ( /obj/structure/closet/crate/uranium, /obj/machinery/button/blast_door{ id_tag = "radaway"; name = "Radiation shields"; - pixel_x = -24 + pixel_x = -24; + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) +"hf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled, +/area/ship/trade/garden) "hi" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -2800,7 +2841,7 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/maintenance/hallway) "hj" = ( /obj/effect/decal/cleanable/cobweb, @@ -2812,13 +2853,10 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/hallway) "hk" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2827,34 +2865,29 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/wall/r_wall{ - can_open = 1 - }, +/turf/wall/false, /area/ship/trade/hidden) "hl" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/item/cash/c1000, /obj/random/coin, /obj/structure/closet/crate, -/turf/simulated/floor/plating, -/area/ship/trade/hidden) -"hm" = ( -/obj/item/stool/padded, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, +/turf/floor/plating, +/area/ship/trade/hidden) +"hm" = ( +/obj/item/stool/padded, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/machinery/firealarm{ - pixel_y = 24 + pixel_y = 21 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/hidden) "hr" = ( /obj/structure/disposalpipe/segment{ @@ -2868,18 +2901,19 @@ dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 5 }, -/obj/machinery/alarm{ +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"hs" = ( +/obj/machinery/light{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/techmaint, -/area/ship/trade/maintenance/hallway) +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) "ht" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, @@ -2887,19 +2921,15 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/disposalpipe/junction{ - icon_state = "pipe-j1"; dir = 4 }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/maintenance/hallway) "hu" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2909,34 +2939,28 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/obj/structure/emergency_dispenser/north, +/turf/floor/plating, /area/ship/trade/maintenance/hallway) "hv" = ( /obj/structure/cable{ icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ - icon_state = "map"; dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; dir = 1 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2945,7 +2969,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/maintenance/hallway) "hw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2955,26 +2979,22 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/hallway) "hx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2984,19 +3004,15 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/hallway) "hy" = ( /obj/item/crowbar, @@ -3007,81 +3023,61 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/light/small{ - icon_state = "bulb_map"; dir = 1 }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/hallway) "hz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/obj/structure/sign/directions/medical{ - dir = 1; - icon_state = "direction_med"; - pixel_x = 30; - pixel_z = 4 - }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/disposalpipe/segment/bent{ - icon_state = "pipe-c"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/hallway) "hA" = ( -/obj/machinery/power/apc{ - name = "Medical Bay APC" - }, -/obj/structure/cable{ - d2 = 6; - icon_state = "0-6" +/obj/machinery/apc{ + name = "Medical Bay APC"; + pixel_y = -22 }, -/obj/item/storage/backpack/dufflebag/syndie, +/obj/item/backpack/dufflebag/syndie, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, -/turf/simulated/floor/plating, +/obj/structure/cable{ + icon_state = "0-2"; + pixel_y = 1 + }, +/turf/floor/plating, /area/ship/trade/hidden) "hB" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 - }, /obj/item/disk/design_disk, /obj/item/disk/tech_disk, /obj/item/disk/tech_disk, /obj/random/loot, /obj/random/loot, /obj/structure/closet/crate, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/hidden) "hC" = ( /obj/structure/closet/crate, @@ -3090,32 +3086,27 @@ /obj/random/loot, /obj/random/projectile, /obj/random/projectile, -/turf/simulated/floor/plating, +/obj/item/tank/oxygen/yellow, +/turf/floor/plating, /area/ship/trade/hidden) "hD" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/atmos) "hF" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/atmos) "hG" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/engineering) "hH" = ( /obj/structure/disposalpipe/segment, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/engineering) "hJ" = ( -/turf/simulated/wall, -/area/ship/trade/maintenance/power) -"hK" = ( -/obj/structure/cable{ - icon_state = "2-9" - }, -/turf/simulated/wall/r_wall, +/turf/wall, /area/ship/trade/maintenance/power) "hL" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/power) "hO" = ( /obj/machinery/atmospherics/pipe/simple/visible/universal{ @@ -3124,86 +3115,77 @@ /obj/effect/floor_decal/corner/blue{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/light{ + dir = 1; + icon_state = "bulb1" + }, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "hP" = ( /obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ - icon_state = "intact-scrubbers"; dir = 4 }, /obj/effect/floor_decal/corner/blue{ dir = 8 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/obj/machinery/power/apc/high{ - dir = 1 +/obj/machinery/apc/high{ + dir = 1; + pixel_y = 22 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "hQ" = ( /obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ - icon_state = "intact-scrubbers"; dir = 10 }, /obj/machinery/meter, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/light_switch{ pixel_y = 25 }, /obj/structure/closet/secure_closet/engineering_welding, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "hR" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/space) "hS" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/alarm{ pixel_y = 32 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/disposalpipe/trunk{ - icon_state = "pipe-t"; dir = 1 }, /obj/machinery/disposal, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/handrail, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "hU" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -3211,81 +3193,79 @@ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "hV" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/light_switch{ pixel_y = 25 }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/obj/structure/table/standard, -/obj/item/chems/food/drinks/glass2/coffeecup/metal, -/obj/item/chems/food/drinks/glass2/coffeecup/metal, +/obj/structure/table, +/obj/item/chems/drinks/glass2/coffeecup/metal, +/obj/item/chems/drinks/glass2/coffeecup/metal, /obj/item/chems/chem_disp_cartridge/coffee{ name = "coffee canister" }, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/handrail, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "hW" = ( -/obj/structure/bed/chair/comfy/brown, -/obj/effect/landmark/start{ +/obj/structure/chair/comfy/brown, +/obj/abstract/landmark/start{ name = "Head Engineer" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet/hydrant{ pixel_y = 32 }, -/obj/item/storage/firstaid/regular, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor, +/obj/item/firstaid/regular, +/obj/structure/handrail, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "hX" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/sign/warning/high_voltage{ - pixel_x = 32 + pixel_x = 32; + dir = 8 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/toy/prize/powerloader, /obj/item/ashtray/plastic, /obj/machinery/recharger, /obj/item/blueprints, /obj/structure/sign/poster{ - pixel_y = 32 + pixel_y = 32; + dir = 1 }, /obj/machinery/firealarm{ - pixel_y = 24 + pixel_y = 21 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "ib" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red, /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/effect/floor_decal/corner/blue{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "ic" = ( /obj/structure/window/reinforced{ @@ -3299,7 +3279,7 @@ dir = 4 }, /obj/machinery/meter/turf, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/ship/trade/maintenance/atmos) "id" = ( /obj/structure/window/reinforced{ @@ -3312,7 +3292,7 @@ /obj/effect/floor_decal/corner/blue/diagonal{ dir = 4 }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/ship/trade/maintenance/atmos) "ie" = ( /obj/machinery/atmospherics/portables_connector, @@ -3320,43 +3300,31 @@ dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "if" = ( /obj/machinery/atmospherics/pipe/simple/visible/supply{ - icon_state = "intact-supply"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/visible/scrubbers{ - icon_state = "intact-scrubbers"; dir = 5 }, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "ih" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3365,14 +3333,11 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "ii" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -3384,18 +3349,14 @@ icon_state = "4-10" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "ij" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -3404,64 +3365,49 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/ladder, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "ik" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/stool/padded, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Junior Engineer" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "il" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "im" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -3469,15 +3415,15 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/effect/fluid_mapped/fuel, -/turf/simulated/floor/tiled/techfloor, +/obj/abstract/landmark/mapped_fluid/fuel, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) +"in" = ( +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) "io" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 @@ -3485,33 +3431,26 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) "ip" = ( -/obj/machinery/power/sensor{ +/obj/machinery/power_sensor{ id_tag = "Main Grid" }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) "iq" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/cable{ icon_state = "2-9" @@ -3522,52 +3461,50 @@ }, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = 21 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) "is" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/visible/red, /obj/effect/floor_decal/corner/blue{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "it" = ( /obj/structure/window/reinforced{ dir = 8 }, /obj/machinery/atmospherics/unary/outlet_injector{ - icon_state = "map_injector"; dir = 8; - use_power = 1; - id_tag = "n2_in" + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/ship/trade/maintenance/atmos) "iu" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - icon_state = "map_vent_in"; dir = 4; - use_power = 1; - id_tag = "air_out"; - pump_direction = 0; external_pressure_bound = 0; - internal_pressure_bound = 2000; - pressure_checks = 2; external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; - pressure_checks_default = 2 + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/oxygen, +/turf/floor/reinforced/oxygen, /area/ship/trade/maintenance/atmos) "iv" = ( /obj/machinery/meter, @@ -3577,23 +3514,21 @@ /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "ix" = ( -/obj/structure/closet/walllocker/emerglocker/west, +/obj/structure/emergency_dispenser/west, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/structure/cable{ icon_state = "2-5" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iy" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -3603,124 +3538,110 @@ /obj/machinery/computer/modular/preset/engineering{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iz" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/computer/ship/engines{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iA" = ( /obj/structure/cable, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/button/blast_door{ id_tag = "engwindow"; name = "Engine Observation"; - pixel_x = 6 + pixel_x = 6; + dir = 8; + directional_offset = null }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /mob/living/simple_animal/opossum/poppy, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iB" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/light, /obj/machinery/button/blast_door{ id_tag = "scram"; name = "CORE SCRAM"; - pixel_y = -26 + pixel_y = -26; + dir = 1 }, /obj/machinery/computer/fusion/fuel_control{ dir = 1; - icon_state = "computer"; initial_id_tag = "main_drive" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iC" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, /obj/machinery/computer/fusion/core_control{ dir = 1; - icon_state = "computer"; initial_id_tag = "main_drive" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iD" = ( /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 10 }, -/obj/structure/sign/warning/nosmoking_1{ - pixel_y = -32 - }, /obj/machinery/computer/fusion/gyrotron{ dir = 1; - icon_state = "computer"; initial_id_tag = "main_drive" }, /obj/machinery/newscaster{ - pixel_x = 30 + pixel_x = 32; + dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/sign/warning/nosmoking_1{ + pixel_y = -32; + dir = 1 + }, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "iE" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) "iF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) -"iI" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/atmos) "iJ" = ( /obj/machinery/atmospherics/pipe/simple/visible/green, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "iK" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red, /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/manifold/visible/red{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "iL" = ( /obj/structure/window/reinforced{ @@ -3729,7 +3650,7 @@ /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/ship/trade/maintenance/atmos) "iM" = ( /obj/structure/window/reinforced{ @@ -3738,49 +3659,62 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/ship/trade/maintenance/atmos) +"iN" = ( +/obj/machinery/light, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) "iQ" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/engine/aft) "iR" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "engwindow"; - name = "blast door"; - opacity = 0 +/obj/machinery/door/blast/regular/open{ + id_tag = "engwindow" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"iS" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "tradeship_rescue_shuttle_pump" + }, +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) "iT" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) "iU" = ( -/obj/machinery/power/shield_generator, +/obj/machinery/shield_generator/mapped, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) "iV" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume{ @@ -3788,60 +3722,45 @@ external_pressure_bound = 140; external_pressure_bound_default = 140; icon_state = "map_vent_out"; - pressure_checks = 1; - pressure_checks_default = 1; use_power = 1 }, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/atmos) "iW" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; - dir = 4 - }, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/atmos) -"iY" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; dir = 4 }, +/turf/floor/plating, +/area/ship/trade/maintenance/atmos) +"iY" = ( /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 6 }, -/obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/valve/open, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "iZ" = ( /obj/structure/window/reinforced{ dir = 8 }, /obj/effect/floor_decal/corner/white/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, /obj/effect/floor_decal/corner/white/diagonal, /obj/machinery/meter/turf, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/ship/trade/maintenance/atmos) "ja" = ( /obj/structure/window/reinforced{ @@ -3851,64 +3770,40 @@ dir = 4; icon_state = "map_injector"; id_tag = "n2_in"; - power_rating = 45000; use_power = 1 }, /obj/effect/floor_decal/corner/white/diagonal, /obj/effect/floor_decal/corner/white/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/ship/trade/maintenance/atmos) "jb" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 1 }, -/turf/simulated/floor/tiled, +/obj/machinery/media/jukebox/old, +/turf/floor/tiled, /area/ship/trade/crew/saloon) -"jc" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "tradeship_shuttle_out" - }, -/obj/machinery/button/access/exterior{ - id_tag = "tradeship_shuttle"; - pixel_x = 18; - pixel_y = -20 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) "jd" = ( -/obj/structure/closet/walllocker/emerglocker/west, +/obj/structure/emergency_dispenser/west, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "je" = ( /obj/machinery/atmospherics/portables_connector, /obj/machinery/camera/network/engineering, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jf" = ( /obj/machinery/light_switch{ pixel_y = 25 }, /obj/machinery/atmospherics/unary/tank/carbon_dioxide, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jg" = ( /obj/machinery/atmospherics/portables_connector, @@ -3918,12 +3813,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jh" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 @@ -3931,37 +3826,33 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "ji" = ( /obj/machinery/atmospherics/portables_connector, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jj" = ( /obj/machinery/atmospherics/portables_connector, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jk" = ( /obj/structure/closet/radiation, /obj/effect/floor_decal/techfloor/orange, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" + }, +/obj/structure/sign/warning/radioactive{ + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) "jl" = ( /obj/machinery/power/terminal{ @@ -3969,62 +3860,51 @@ }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/effect/floor_decal/techfloor/orange, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) "jm" = ( /obj/machinery/power/smes/buildable/max_cap_in_out, /obj/structure/cable, /obj/effect/floor_decal/techfloor/orange, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/power) -"jo" = ( -/obj/machinery/atmospherics/portables_connector{ +/obj/structure/sign/warning/radioactive{ + pixel_y = -32; dir = 1 }, -/obj/machinery/portable_atmospherics/powered/scrubber, -/obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; - dir = 6 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/atmos) +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/maintenance/power) "jp" = ( /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/ship/trade/maintenance/atmos) "jq" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - icon_state = "map_vent_in"; dir = 4; - use_power = 1; - id_tag = "air_out"; - pump_direction = 0; external_pressure_bound = 0; - internal_pressure_bound = 2000; - pressure_checks = 2; external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; - pressure_checks_default = 2 + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/airmix, +/turf/floor/reinforced/airmix, /area/ship/trade/maintenance/atmos) "jr" = ( /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/visible/cyan, @@ -4032,44 +3912,39 @@ dir = 4; name = "Air to Ports" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "js" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue{ - icon_state = "map"; dir = 4 }, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "ju" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 8 }, /obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jx" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jy" = ( /obj/machinery/atmospherics/pipe/simple/visible/green, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jz" = ( /obj/machinery/atmospherics/omni/mixer{ @@ -4079,32 +3954,19 @@ tag_west = 1; tag_west_con = 0.64 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jA" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/window/southright, /obj/machinery/door/window/northleft, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; - id_tag = "radaway"; - opacity = 0 - }, -/obj/structure/sign{ - icon_state = "radiation"; - pixel_x = -32 + id_tag = "radaway" }, -/obj/structure/sign{ - icon_state = "radiation"; - pixel_x = 32 - }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) "jB" = ( /obj/structure/grille, @@ -4112,13 +3974,13 @@ /area/space) "jD" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "jE" = ( /obj/structure/window/reinforced{ @@ -4128,12 +3990,12 @@ dir = 1 }, /obj/machinery/atmospherics/unary/outlet_injector{ - icon_state = "map_injector"; dir = 8; - use_power = 1; - id_tag = "n2_in" + icon_state = "map_injector"; + id_tag = "n2_in"; + use_power = 1 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/ship/trade/maintenance/atmos) "jF" = ( /obj/structure/window/reinforced{ @@ -4143,19 +4005,19 @@ dir = 1 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - icon_state = "map_vent_in"; dir = 4; - use_power = 1; - id_tag = "air_out"; - pump_direction = 0; external_pressure_bound = 0; - internal_pressure_bound = 2000; - pressure_checks = 2; external_pressure_bound_default = 0; + icon_state = "map_vent_in"; + id_tag = "air_out"; + internal_pressure_bound = 2000; internal_pressure_bound_default = 2000; - pressure_checks_default = 2 + pressure_checks = 2; + pressure_checks_default = 2; + pump_direction = 0; + use_power = 1 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/ship/trade/maintenance/atmos) "jG" = ( /obj/machinery/meter, @@ -4165,7 +4027,7 @@ /obj/machinery/atmospherics/pipe/manifold/visible/cyan{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "jH" = ( /obj/machinery/atmospherics/portables_connector{ @@ -4173,38 +4035,35 @@ }, /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/portable_atmospherics/powered/pump/filled, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "jI" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/machinery/atmospherics/valve/shutoff, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jJ" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "jK" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 6 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "jL" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -4215,7 +4074,7 @@ /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 10 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "jM" = ( /obj/structure/window/borosilicate_reinforced, @@ -4223,86 +4082,81 @@ dir = 8 }, /obj/structure/closet/crate/radiation, -/obj/item/stack/material/deuterium/fifty, -/obj/item/stack/material/tritium/ten, +/obj/item/stack/material/aerogel/mapped/deuterium/fifty, +/obj/item/stack/material/aerogel/mapped/tritium/ten, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jN" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jO" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/simple/visible/green{ - dir = 9; - icon_state = "intact" + dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jP" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; - id_tag = "radaway"; - opacity = 0 + id_tag = "radaway" }, /obj/machinery/meter/turf, -/turf/simulated/floor/plating, +/obj/structure/sign/warning/radioactive{ + pixel_x = -32; + dir = 4 + }, +/obj/structure/sign/warning/radioactive{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/plating, /area/ship/trade/maintenance/power) "jQ" = ( /obj/effect/floor_decal/corner/red{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "jR" = ( /obj/structure/window/reinforced{ dir = 8 }, /obj/effect/floor_decal/corner/red/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, /obj/effect/floor_decal/corner/red/diagonal, /obj/machinery/meter/turf, /obj/structure/window/reinforced{ - dir = 2; - health = 1e+007 + current_health = 1e+007 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/ship/trade/maintenance/atmos) "jS" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/effect/floor_decal/corner/red/diagonal{ - icon_state = "corner_white_diagonal"; dir = 4 }, /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/window/reinforced{ - dir = 2; - health = 1e+007 + current_health = 1e+007 }, -/turf/simulated/floor/reinforced/nitrogen, +/turf/floor/reinforced/nitrogen, /area/ship/trade/maintenance/atmos) "jT" = ( /obj/machinery/atmospherics/portables_connector{ @@ -4311,18 +4165,17 @@ /obj/effect/floor_decal/corner/red{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "jU" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/portable_atmospherics/canister/helium{ start_pressure = 2559.63 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "jV" = ( /obj/machinery/light{ @@ -4331,31 +4184,23 @@ /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/machinery/meter, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "jX" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/machinery/power/fusion_core/mapped{ +/obj/machinery/fusion_core/mapped{ initial_id_tag = "main_drive" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "jY" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging, -/turf/simulated/floor/reinforced/airless, -/area/ship/trade/maintenance/engine/aft) -"jZ" = ( -/obj/machinery/door/blast/regular{ - id_tag = "scram" - }, -/turf/simulated/floor/plating, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "kb" = ( /obj/item/radio/intercom{ @@ -4367,39 +4212,33 @@ }, /obj/machinery/portable_atmospherics/canister/empty, /obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kc" = ( /obj/structure/cable, /obj/machinery/light, -/obj/machinery/power/port_gen/pacman/super, +/obj/machinery/port_gen/pacman/super, /obj/item/wrench, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) "kd" = ( /obj/effect/floor_decal/corner/red{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/atmos) -"ke" = ( -/obj/machinery/light, -/obj/effect/floor_decal/corner/red{ - dir = 5 - }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/simple/visible/red, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "kf" = ( /obj/effect/floor_decal/corner/red{ dir = 5 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "kg" = ( /obj/effect/floor_decal/corner/red{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "kh" = ( /obj/machinery/atmospherics/valve/open, @@ -4408,63 +4247,57 @@ pixel_x = -22 }, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "ki" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 5 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "kj" = ( /obj/machinery/atmospherics/pipe/simple/heat_exchanging{ dir = 9 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "kk" = ( /obj/machinery/atmospherics/unary/vent_pump/engine{ dir = 4; - external_pressure_bound = 4000; - external_pressure_bound_default = 4000; - icon_state = "map_vent"; - pump_direction = 0; - use_power = 1 + external_pressure_bound = 0; + external_pressure_bound_default = 0; + id_tag = "tradeship_engine_vent"; + pump_direction = 0 }, /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction{ dir = 1 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) "kl" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/obj/machinery/fusion_fuel_compressor, +/obj/machinery/fuel_compressor, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 8 }, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "km" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kn" = ( /obj/machinery/atmospherics/omni/filter{ @@ -4474,25 +4307,32 @@ tag_west = 1; use_power = 0 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kq" = ( /obj/structure/grille/broken, /obj/structure/lattice, /turf/space, /area/space) +"kr" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/shuttle/rescue) "ks" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ dir = 8 }, /obj/machinery/space_heater, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "kt" = ( /obj/machinery/fabricator/pipe, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/effect/floor_decal/corner/blue, @@ -4500,31 +4340,27 @@ /obj/effect/floor_decal/corner/yellow{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "kv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/fusion_fuel_injector/mapped{ dir = 1; - icon_state = "injector0"; initial_id_tag = "main_drive" }, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/black{ - icon_state = "intact"; dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kA" = ( /obj/machinery/atmospherics/portables_connector{ @@ -4532,194 +4368,261 @@ }, /obj/machinery/portable_atmospherics/canister/empty, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kB" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume{ - icon_state = "map_vent"; dir = 8; - use_power = 1; external_pressure_bound = 140; - pressure_checks = 1; external_pressure_bound_default = 140; - pressure_checks_default = 1 + use_power = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"kC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/starboard) "kD" = ( /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kE" = ( /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kF" = ( /obj/structure/window/reinforced, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 1 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kG" = ( /obj/structure/window/reinforced, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kI" = ( /obj/machinery/atmospherics/unary/engine{ - icon_state = "nozzle"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "kJ" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" + }, +/obj/structure/window/borosilicate_reinforced{ + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"kR" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall/hull, +/area/space) +"kX" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) "lb" = ( -/obj/machinery/light, -/obj/machinery/newscaster{ - pixel_y = -32 +/obj/structure/catwalk, +/obj/structure/handrail, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" }, -/obj/machinery/firealarm{ +/obj/machinery/button/access/exterior{ dir = 4; - pixel_x = 24; - pixel_y = 0 + id_tag = "bee_star"; + pixel_x = 16; + pixel_y = 26; + directional_offset = null }, -/obj/machinery/computer/modular/preset/cardslot/command{ +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"ld" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/obj/machinery/apc/high{ + dir = 8; + pixel_x = -22 + }, +/obj/structure/cable, +/obj/structure/window/borosilicate_reinforced{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/maintenance/engine/aft) +"lu" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/ship/trade/maintenance/engine/aft) +"lC" = ( +/obj/machinery/portable_atmospherics/powered/scrubber, +/obj/machinery/atmospherics/portables_connector{ dir = 1 }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) -"lc" = ( -/obj/machinery/button/access/exterior{ - id_tag = "tradeship_dock_port"; - pixel_x = -18; - pixel_y = 20 +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/atmos) +"lJ" = ( +/obj/structure/table, +/obj/machinery/light{ + dir = 1; + icon_state = "tube1" }, -/obj/machinery/door/airlock/external/bolted{ - id_tag = "dock_port_out" +/obj/item/deck/tarot, +/obj/machinery/button/blast_door{ + id_tag = "bee_shutters"; + directional_offset = null + }, +/obj/item/stack/medical/bandage, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"lU" = ( +/obj/structure/sign/warning/docking_area{ + dir = 4; + pixel_x = -34 }, -/obj/machinery/shield_diffuser, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 +/turf/space, +/area/space) +"lW" = ( +/obj/structure/catwalk, +/obj/structure/handrail{ + dir = 1 }, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/dock) -"ld" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/obj/machinery/power/apc/high{ +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"lZ" = ( +/obj/structure/sign/department/cross{ + pixel_x = 32; dir = 8 }, -/obj/structure/cable, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/engine/aft) -"lu" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; - dir = 10 - }, -/obj/machinery/meter, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/engine/aft) -"lx" = ( -/obj/structure/shuttle/engine/propulsion/burst/right, -/turf/simulated/floor/airless, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) "mb" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/garden) "mc" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/port) "md" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 5 }, /obj/machinery/meter, -/turf/simulated/floor/plating, +/obj/structure/window/borosilicate_reinforced{ + dir = 4 + }, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"me" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/ship/trade/maintenance/hallway) +"mf" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + level = 2 + }, +/obj/effect/floor_decal/corner/beige{ + dir = 10 + }, +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"ml" = ( +/obj/structure/table, +/obj/item/toolbox/electrical{ + pixel_x = 7; + pixel_y = 4 + }, +/obj/random/powercell, +/obj/random/powercell, +/turf/floor/plating, +/area/ship/trade/shieldbay) +"mr" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/obj/structure/cable/orange{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "mt" = ( /obj/item/roller, /obj/structure/hygiene/sink{ pixel_y = 23 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) -"mw" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/hologram/holopad/longrange, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) "my" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"mW" = ( +/obj/structure/cable/orange{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "mX" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/garden) "nb" = ( -/turf/simulated/wall, +/turf/wall, /area/ship/trade/garden) -"nc" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 4; - id_tag = "dock_port_pump" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/dock) "nd" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 8 + dir = 8; + icon_state = "bulb1" }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_y = 29 }, /obj/structure/hygiene/sink{ @@ -4730,8 +4633,8 @@ icon_state = "twindow" }, /obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 + dir = 4; + icon_state = "twindow" }, /obj/structure/window/reinforced/tinted{ dir = 1 @@ -4742,42 +4645,62 @@ }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; - pixel_x = 24 + pixel_x = 21 }, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/item/hemostat, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "nj" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/medbay/chemistry) -"nu" = ( -/obj/structure/shuttle/engine/propulsion/burst/right{ +"nm" = ( +/obj/machinery/apc{ + dir = 4; + pixel_x = 22 + }, +/obj/structure/cable, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "tradeship_rescue_shuttle_pump" + }, +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/airless, -/area/ship/trade/shuttle/outgoing) -"nH" = ( -/obj/structure/table/standard, -/obj/effect/floor_decal/corner/red/diagonal, -/obj/item/chems/glass/beaker{ - pixel_x = 5 +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"nv" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 }, -/obj/item/chems/food/condiment/small/peppermill{ - pixel_x = 3 +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"nD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 5 }, -/obj/item/chems/food/condiment/enzyme, -/obj/item/chems/glass/rag, -/turf/simulated/floor/tiled, +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"nH" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/red/diagonal, +/obj/machinery/reagent_temperature, +/obj/item/chems/cooking_vessel/skillet, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) -"nL" = ( -/turf/simulated/floor/airless, -/area/space) +"nR" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "nU" = ( /obj/structure/catwalk, /obj/machinery/atmospherics/pipe/zpipe/down/supply{ @@ -4786,143 +4709,184 @@ /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers{ dir = 1 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "nW" = ( /obj/effect/floor_decal/corner/red/diagonal, /obj/machinery/cooker/fryer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "nZ" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/dock) -"ob" = ( -/obj/machinery/computer/shuttle_control/explore/tradeship, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 6 +"og" = ( +/obj/structure/handrail{ + dir = 8 }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) -"oc" = ( -/obj/machinery/light{ +/obj/structure/catwalk, +/obj/structure/railing/mapped{ dir = 1 }, -/obj/machinery/airlock_sensor{ - id_tag = "dock_port_sensor"; - pixel_y = 36 - }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - id_tag = "tradeship_dock_port"; - pixel_y = 25; - tag_airpump = "dock_port_pump"; - tag_chamber_sensor = "dock_port_sensor"; - tag_exterior_door = "dock_port_out"; - tag_interior_door = "dock_port_in" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"oi" = ( +/obj/machinery/vending/snack{ dir = 4 }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/port) +"ok" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "2-8" }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/dock) +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "om" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/medbay/chemistry) "on" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/medbay) "oo" = ( /obj/machinery/light, /obj/machinery/optable, -/obj/item/chems/food/drinks/glass2/coffeecup/britcup, -/obj/item/chems/glass/rag, -/turf/simulated/floor/tiled/white, +/obj/item/chems/drinks/glass2/coffeecup/britcup, +/obj/item/chems/rag, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) +"op" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "or" = ( /obj/structure/lattice, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/aft) "oK" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/command/fmate) -"pb" = ( -/obj/item/radio/intercom{ - pixel_y = 22 +"oM" = ( +/obj/machinery/power/terminal{ + dir = 1 }, -/obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled, -/area/ship/trade/garden) -"pc" = ( -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/structure/cable{ + icon_state = "0-2" }, -/obj/machinery/button/access/interior{ - id_tag = "tradeship_dock_port"; - pixel_x = 12; - pixel_y = 20 +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "tradeship_rescue_shuttle_pump_out_internal" }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; +/obj/structure/handrail{ dir = 4 }, -/obj/machinery/door/airlock/external/bolted{ - id_tag = "dock_port_in" +/obj/effect/floor_decal/corner/white{ + dir = 9 }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 +/obj/effect/floor_decal/corner/white{ + dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/dock) +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"oV" = ( +/obj/structure/catwalk, +/obj/structure/handrail{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"pb" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/tiled, +/area/ship/trade/garden) +"pe" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/obj/structure/handrail{ + dir = 8 + }, +/turf/space, +/area/ship/trade/maintenance/engine/starboard) "pn" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/engine/port) +"pt" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/port) +"pu" = ( +/obj/machinery/computer/ship/engines, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"pv" = ( +/obj/structure/lattice, +/obj/machinery/light/navigation/delay5{ + color = "#ff3333" + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"pG" = ( +/obj/structure/closet/crate/uranium, +/turf/floor/plating, +/area/ship/trade/shieldbay) "pT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/radio/intercom{ - pixel_y = 32 + pixel_y = 20 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 5 }, /obj/structure/closet/toolcloset, -/obj/item/storage/backpack/dufflebag/eng, -/obj/item/stack/material/glass/reinforced/fifty, -/obj/item/stack/material/steel/fifty, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor, +/obj/item/backpack/dufflebag/eng, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/structure/handrail, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) "qb" = ( /obj/effect/decal/cleanable/cobweb2, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/machinery/alarm{ @@ -4930,155 +4894,207 @@ }, /obj/machinery/biogenerator, /obj/machinery/light_switch{ - pixel_w = 22 + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) -"qc" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 - }, +"qd" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" + icon_state = "4-8" }, -/obj/machinery/firealarm{ +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"qg" = ( +/obj/random/drinkbottle, +/obj/random/drinkbottle, +/turf/floor/plating, +/area/ship/trade/hidden) +"qp" = ( +/obj/machinery/vending/cola{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/port) +"qt" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/obj/machinery/light{ dir = 4; - pixel_x = 24; - pixel_y = 0 + icon_state = "bulb1" }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"qv" = ( +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"qA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "tradeship_rescue_shuttle_pump_out_internal" + }, +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) "qE" = ( /obj/machinery/atmospherics/omni/mixer{ - active_power_usage = 7500; - tag_east = 0; tag_east_con = 0; tag_north = 1; tag_north_con = 0.21; tag_south = 1; tag_south_con = 0.79; - tag_west = 2; - use_power = 1 + tag_west = 2 }, /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 9 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) +"qM" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/shuttle/rescue) "qO" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/computer/modular/preset/merchant, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/computer/modular/preset/merchant/tradeship, +/obj/machinery/light_switch{ + pixel_y = 25 + }, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) -"qS" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +"qR" = ( +/obj/structure/sign/directions/engineering{ + pixel_x = -32 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "bulb1" }, -/turf/simulated/floor/plating, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "qT" = ( /obj/machinery/door/blast/regular{ id_tag = "sensor" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/command/fmate) +"qZ" = ( +/obj/structure/closet/radiation, +/turf/floor/plating, +/area/ship/trade/shieldbay) "ra" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor/plating, -/area/ship/trade/command/bridge) +/obj/structure/closet/emcloset, +/obj/random/voidsuit, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/voidhelmet, +/turf/floor/plating, +/area/ship/trade/shieldbay) "rb" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/garden) -"rc" = ( -/obj/structure/closet/walllocker/emerglocker/south, -/obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 - }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4; - level = 2 - }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) "rp" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/command/fmate) "rv" = ( /obj/machinery/light, /obj/effect/floor_decal/industrial/warning, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "rx" = ( /obj/structure/lattice, /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/atmos) -"rQ" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +"rH" = ( +/obj/structure/chair{ + dir = 1 }, -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"rI" = ( +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/machinery/apc{ + dir = 4; + pixel_x = 22 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/newscaster{ + pixel_x = 32; + dir = 4 + }, +/turf/floor/tiled/dark, /area/ship/trade/command/bridge) +"rL" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/structure/chair/shuttle/white{ + dir = 4 + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) "rR" = ( /obj/item/flashlight, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) +"rT" = ( +/obj/machinery/computer/modular/preset/engineering, +/obj/effect/floor_decal/corner/yellow{ + dir = 10 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 5 + }, +/obj/machinery/keycard_auth{ + pixel_y = 28 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) "sb" = ( /obj/effect/floor_decal/corner/blue{ dir = 1 @@ -5089,164 +5105,264 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/chems/glass/bottle/eznutrient, /obj/item/plantspray/pests, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) -"sc" = ( -/obj/machinery/firealarm{ - dir = 1; - pixel_y = -24 - }, -/obj/structure/ladder, -/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/zpipe/up/supply{ - dir = 1 - }, -/obj/structure/cable, -/obj/structure/cable{ - d1 = 16; - d2 = 0; - icon_state = "16-0" - }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) +"se" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall, +/area/ship/trade/shieldbay) "sf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 1 }, /obj/machinery/fusion_fuel_injector/mapped{ dir = 1; - icon_state = "injector0"; initial_id_tag = "main_drive" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"sj" = ( +/obj/machinery/alarm{ + pixel_y = 21 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock{ + start_pressure = 730 + }, +/obj/structure/cable/orange{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "sl" = ( /obj/machinery/atmospherics/unary/engine{ - icon_state = "nozzle"; dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/starboard) +"sm" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/red, +/obj/effect/paint/sun, +/obj/machinery/door/blast/regular/open{ + id_tag = "bee_shutters" + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"sw" = ( +/obj/structure/handrail, +/obj/structure/catwalk, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"sz" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/structure/sign/warning/hot_exhaust{ + pixel_y = 32 + }, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/starboard) +"sA" = ( +/obj/machinery/door/airlock/hatch, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) "sB" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/sign/warning/fall{ - pixel_x = -32 + pixel_x = -34; + dir = 4 }, /obj/structure/catwalk, /obj/structure/railing/mapped, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 8 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) +"sG" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/floodlight, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/button/access/interior{ + dir = 4; + id_tag = "bee_port"; + pixel_x = -20 + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) "sI" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/hidden) "sM" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, -/area/space) +/turf/wall/r_wall, +/area/ship/trade/shieldbay) "sS" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/hidden) "sY" = ( /obj/machinery/portable_atmospherics/hydroponics, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) -"tc" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 +"tg" = ( +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"to" = ( +/obj/structure/closet/crate, +/obj/item/radio, +/obj/item/spaceflare, +/obj/item/clothing/head/helmet/space/void/expedition, +/obj/item/clothing/suit/space/void/expedition, +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/apc/high{ + dir = 8; + pixel_x = -22 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" + icon_state = "0-2" }, -/obj/machinery/firealarm{ +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) +"tv" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/apc{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -22 }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 8 +/obj/structure/cable{ + icon_state = "0-4" }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"tg" = ( -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"tJ" = ( -/obj/machinery/door/blast/regular{ - id_tag = "scram" +/obj/structure/cable{ + icon_state = "1-4" }, -/obj/machinery/atmospherics/pipe/simple/hidden/black{ - icon_state = "intact"; - dir = 4 +/obj/machinery/light{ + icon_state = "bulb1" }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/engine/aft) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"tG" = ( +/obj/abstract/ramp_sculptor/north, +/turf/wall/natural, +/area/space) +"tV" = ( +/turf/space, +/area/ship/trade/command/fmate) "tW" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/command/fmate) "uc" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; - pixel_x = 24 + pixel_x = 21 }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/item/radio/intercom{ dir = 1; pixel_y = -30 }, -/turf/simulated/floor/tiled/monotile, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/floor/tiled/monotile, /area/ship/trade/dock) +"uf" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 5 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"uk" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/obj/effect/paint/black, +/turf/wall/titanium, +/area/ship/trade/shuttle/outgoing/engineering) "ul" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/crew/medbay/chemistry) +"uD" = ( +/obj/machinery/port_gen/pacman/super, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/sign/warning/radioactive{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"uL" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/techfloor/orange{ + dir = 6 + }, +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"uP" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/structure/lattice, +/turf/space, +/area/ship/trade/command/captain) "vb" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -5255,90 +5371,102 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) "vc" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + pixel_x = -21 }, /obj/item/radio/intercom{ dir = 1; pixel_y = -30 }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/monotile, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/floor/tiled/monotile, /area/ship/trade/dock) "vj" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/toilets) -"vu" = ( -/obj/machinery/computer/ship/sensors, -/obj/machinery/light_switch{ - pixel_x = 28 +"vt" = ( +/obj/item/radio, +/obj/structure/cable{ + icon_state = "4-9" }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 6 + }, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/starboard) "vL" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, /obj/structure/sign/warning/hot_exhaust{ pixel_y = 32 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/aft) +"vN" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) "vP" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 8 + dir = 8; + icon_state = "tube1" }, /obj/structure/closet/cabinet, -/obj/item/storage/secure/briefcase, -/obj/item/storage/backpack/dufflebag/syndie, -/obj/item/storage/box/ammo/shotgunshells, +/obj/item/secure_storage/briefcase, +/obj/item/backpack/dufflebag/syndie, +/obj/item/box/ammo/shotgunshells, /obj/item/handcuffs, -/obj/item/boombox, -/obj/item/radio/intercom{ - pixel_y = 20 - }, -/obj/item/taperoll/bureaucracy, -/turf/simulated/floor/wood, +/obj/item/music_player/boombox, +/obj/item/stack/tape_roll/barricade_tape/bureaucracy, +/obj/machinery/keycard_auth, +/turf/floor/laminate, /area/ship/trade/command/captain) "vS" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) "vW" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/smokes, /obj/item/ashtray/glass, -/obj/effect/landmark{ - name = "Observer-Start" - }, +/obj/abstract/landmark/latejoin/observer, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/item/board, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) +"vY" = ( +/obj/structure/handrail, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + cycle_to_external_air = 1; + id_tag = "bee_port"; + pixel_y = 24; + tag_interior_sensor = "bee_interior_sensor"; + tag_pump_out_external = "bee_pump_out_external" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 6 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) "wb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/door/airlock/hatch{ @@ -5353,126 +5481,148 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) -"wc" = ( -/obj/machinery/portable_atmospherics/canister/air/airlock{ - start_pressure = 730 - }, -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) "we" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/engine/starboard) "wB" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/aft) "wG" = ( /obj/machinery/atmospherics/pipe/zpipe/up/supply, /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers, /obj/structure/cable{ - d1 = 16; - d2 = 0; icon_state = "16-0" }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/maintenance/atmos) "wL" = ( /obj/item/mollusc/barnacle{ - pixel_w = -15 + pixel_x = -15 }, /turf/space, /area/space) "wP" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/command/captain) "wU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) -"xb" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) "xc" = ( -/obj/machinery/power/apc{ - dir = 1; - name = "Crew Areas APC" +/obj/machinery/firealarm{ + pixel_y = 21 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "4-8" }, -/obj/structure/bed/chair, -/obj/machinery/firealarm{ - pixel_y = 24 +/turf/floor/tiled, +/area/ship/trade/crew/saloon) +"xh" = ( +/obj/abstract/level_data_spawner/tradeship_habitation, +/turf/space, +/area/space) +"xn" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating, +/area/ship/trade/maintenance/engine/aft) +"xz" = ( +/obj/structure/closet/crate, +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/obj/item/roller, +/obj/item/firstaid/adv, +/obj/item/pill_bottle/painkillers, +/obj/item/pill_bottle/antitoxins, +/obj/item/pill_bottle/antibiotics, +/obj/item/pill_bottle/burn_meds, +/obj/item/scanner/health, +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/obj/effect/floor_decal/corner/white, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"xB" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/turf/simulated/floor/tiled, -/area/ship/trade/crew/saloon) -"xn" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/engine/aft) +/turf/floor/plating, +/area/ship/trade/maintenance/hallway) +"xI" = ( +/obj/machinery/light, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/atmos) "xL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 9 }, /obj/structure/window/borosilicate_reinforced, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"xM" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/floodlight, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"xO" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "xS" = ( -/turf/simulated/floor/carpet, +/turf/floor/carpet, /area/ship/trade/command/fmate) +"xW" = ( +/obj/machinery/door/airlock/hatch, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/sign/warning/radioactive{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/engineering) "xX" = ( /obj/item/mollusc/barnacle{ - pixel_w = 17 + pixel_x = 17 }, /turf/space, /area/space) -"xZ" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4; - level = 2 - }, -/obj/machinery/computer/ship/engines, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) "yb" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) "yc" = ( /obj/machinery/chem_master, @@ -5480,272 +5630,415 @@ dir = 4; pixel_x = -22 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) -"yg" = ( -/obj/machinery/computer/ship/helm, -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/bluegrid, -/area/ship/trade/command/bridge) +"yh" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"yq" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"yt" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall/hull, +/area/ship/trade/shieldbay) +"yy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) "yA" = ( /obj/structure/closet, /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, /obj/random/clothing, -/obj/item/chems/glass/rag, -/obj/item/storage/firstaid/regular, -/turf/simulated/floor/tiled/freezer, +/obj/item/chems/rag, +/obj/item/firstaid/regular, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) -"zb" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 8; - id_tag = "tradeship_shuttle_pump_out_external" - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 +"yF" = ( +/obj/machinery/vending/cigarette{ + dir = 8 }, -/turf/simulated/floor/airless, -/area/ship/trade/shuttle/outgoing) +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/starboard) "zc" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, /obj/structure/window/reinforced/tinted{ - icon_state = "twindow"; - dir = 4 + dir = 4; + icon_state = "twindow" }, /obj/structure/window/reinforced/tinted, /obj/structure/curtain/open/shower, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/toilets) "zs" = ( /obj/machinery/shipsensors, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/command/fmate) "zO" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/command/captain) +"zP" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green, +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/maintenance/atmos) +"zY" = ( +/obj/structure/lattice, +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/sign/warning/docking_area{ + dir = 4; + pixel_x = -34 + }, +/turf/space, +/area/space) "Ab" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 6 }, /obj/effect/floor_decal/corner/blue, /obj/structure/fireaxecabinet{ pixel_y = 32 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "Ac" = ( /obj/item/radio/intercom{ dir = 1; pixel_y = -30 }, -/obj/machinery/disposal, -/obj/structure/disposalpipe/trunk{ - dir = 8 - }, -/turf/simulated/floor/tiled, +/obj/structure/reagent_dispensers/water_cooler, +/turf/floor/tiled, /area/ship/trade/crew/saloon) -"Ah" = ( -/obj/structure/table/standard, +"Ai" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/abstract/landmark/paperwork_finish_tradeship, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"As" = ( +/obj/machinery/power/smes/buildable/max_cap_in_out, +/obj/structure/cable{ + icon_state = "0-4" + }, /obj/machinery/light{ - icon_state = "tube1"; dir = 1 }, -/obj/item/deck/tarot, -/obj/machinery/cell_charger, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "AB" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/maintenance/engine/aft) +"AE" = ( +/obj/effect/paint/red, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 4 + }, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) "AH" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/wash) -"Bb" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, +"AQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/door/airlock/hatch/autoname/command, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/captain) +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) +"Ba" = ( +/obj/machinery/hologram/holopad/longrange, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"Bb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/random/maintenance, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) "Bc" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagentgrinder/juicer, /obj/effect/floor_decal/corner/red/diagonal, -/obj/structure/sign/monkey_painting{ +/obj/structure/sign/painting/monkey_painting{ pixel_y = 32 }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) -"Bg" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +"Bi" = ( +/obj/structure/catwalk, +/obj/structure/railing/mapped{ + dir = 1 }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/door/airlock/hatch/autoname/command, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/dock) +/obj/structure/railing/mapped{ + dir = 4 + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"Bl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 9 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"Br" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "bee_port_pump" + }, +/obj/structure/closet/walllocker/suit{ + dir = 8; + pixel_x = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) "Bx" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/power) "BD" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/multitool{ pixel_x = 5 }, -/obj/item/pipe_painter, -/obj/item/clamp, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) +"BN" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + id_tag = "bee_shutters" + }, +/obj/effect/paint/black, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"BP" = ( +/obj/random/maintenance, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "BZ" = ( /obj/structure/table/marble, /obj/machinery/door/window/brigdoor/southright, /obj/machinery/door/blast/shutters{ id_tag = "fmate" }, -/turf/simulated/floor/wood, +/obj/machinery/button/blast_door{ + id_tag = "fmate"; + pixel_x = 22; + pixel_y = -2; + dir = 8 + }, +/turf/floor/laminate, /area/ship/trade/command/fmate) "Cb" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ dir = 6 }, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/closet/firecloset, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "Cc" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, /obj/effect/floor_decal/corner/red/diagonal, /obj/machinery/vending/dinnerware, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "Cd" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/kitchen) "Ce" = ( -/obj/structure/lattice, /obj/effect/paint/brown, /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/crew/medbay/chemistry) +"Cg" = ( +/obj/abstract/ramp_sculptor/east, +/turf/wall/natural, +/area/space) "Co" = ( /obj/effect/floor_decal/corner/red/diagonal, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "Cq" = ( -/obj/structure/table/standard, -/obj/machinery/button/blast_door{ - id_tag = "scraplock"; - name = "External Lockdown" +/obj/structure/railing/mapped{ + dir = 8 }, -/obj/random_multi/single_item/captains_spare_id, -/obj/item/documents/tradehouse/account, -/obj/item/documents/tradehouse/personnel, -/obj/machinery/newscaster{ - pixel_x = 30 +/obj/structure/railing/mapped, +/obj/structure/catwalk, +/obj/machinery/light/navigation{ + color = "#ff3333" }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) +/obj/structure/lattice, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"Cz" = ( +/obj/structure/shuttle/engine/propulsion/burst, +/turf/floor/plating/airless, +/area/ship/trade/shuttle/rescue) "CD" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/atmos) "CG" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/toy/figure/captain, /obj/machinery/button/blast_door{ id_tag = "sensor"; - name = "Sensor Shroud" + name = "Sensor Shroud"; + directional_offset = null }, /obj/item/radio, -/turf/simulated/floor/tiled/dark, +/obj/random/drinkbottle, +/obj/abstract/landmark/paperwork_spawn_tradeship, +/turf/floor/tiled/dark, /area/ship/trade/command/bridge) +"CI" = ( +/obj/structure/shuttle/engine/propulsion/burst/left, +/turf/floor/plating/airless, +/area/ship/trade/shuttle/outgoing/engineering) +"CP" = ( +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/command/fmate) +"CV" = ( +/obj/effect/floor_decal/techfloor/orange{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"CW" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/abstract/local_dock/automatic{ + dir = 1; + shuttle_tag = "Bee Shuttle"; + name = "center"; + reorient = 0 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) "Db" = ( /obj/effect/floor_decal/corner/white{ - icon_state = "corner_white"; dir = 9 }, /obj/machinery/atmospherics/pipe/simple/visible/cyan, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) "Dc" = ( -/obj/structure/closet/walllocker/emerglocker/north, +/obj/structure/emergency_dispenser/north, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/corner/red/diagonal, /obj/machinery/cooker/oven, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "Dd" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch/autoname/general, /obj/machinery/door/firedoor, @@ -5755,55 +6048,130 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/crew/saloon) +"Dj" = ( +/obj/machinery/power/smes/buildable/max_cap_in_out, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) "Dl" = ( -/obj/machinery/power/apc{ - name = "Medical Bay APC" +/obj/machinery/apc{ + name = "Medical Bay APC"; + pixel_y = -22 }, /obj/structure/cable, /obj/machinery/icecream_vat, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "Dq" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/kitchen) -"DL" = ( -/obj/structure/bed/chair{ - dir = 1 +"Dw" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/structure/railing/mapped, +/obj/structure/catwalk, +/obj/machinery/light/navigation{ + color = "#00ff00" + }, +/obj/structure/lattice, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"Dx" = ( +/obj/effect/paint/red, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 9 + }, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) +"DC" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "bee_port_outer" + }, +/obj/machinery/button/access/exterior{ + dir = 8; + id_tag = "bee_port"; + pixel_x = -16; + pixel_y = -26; + directional_offset = null + }, +/obj/abstract/local_dock/automatic{ + dir = 8; + shuttle_tag = "Bee Shuttle"; + port_tag = "port"; + name = "port docking port" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"DE" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"DH" = ( +/obj/structure/handrail, +/obj/machinery/airlock_sensor{ + id_tag = "bee_port_sensor"; + pixel_y = 24 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"DO" = ( +/obj/effect/paint/brown, +/turf/wall/r_wall, +/area/ship/trade/command/bridge) +"DY" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "tradeship_rescue_shuttle_out" + }, +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/machinery/power/apc{ +/obj/machinery/atmospherics/pipe/manifold/hidden{ dir = 8 }, -/obj/structure/cable{ - d2 = 6; - icon_state = "0-6" +/obj/effect/decal/warning_stripes, +/obj/effect/shuttle_landmark/docking_arm_starboard/rescue{ + dir = 8 }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) -"DO" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall, -/area/ship/trade/command/bridge) +/obj/abstract/local_dock/automatic{ + dir = 8; + shuttle_tag = "Rescue Shuttle"; + port_tag = "port"; + dock_target = "tradeship_rescue_shuttle" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/rescue) "Eb" = ( /obj/machinery/light{ dir = 4; icon_state = "tube1" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; - name = "Communications APC" + name = "Communications APC"; + pixel_y = 22 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = 21 }, /obj/item/handcuffs, /obj/item/telebaton, @@ -5812,16 +6180,16 @@ req_access = list("ACCESS_HEAD_OF_PERSONNEL") }, /obj/item/clothing/suit/armor/vest, -/obj/item/storage/box/ids, +/obj/item/box/ids, /obj/item/flash, /obj/item/clothing/glasses/sunglasses, -/obj/item/storage/box/evidence, -/obj/item/taperoll/police, +/obj/item/box/evidence, +/obj/item/stack/tape_roll/barricade_tape/police, /obj/item/holowarrant, -/obj/item/storage/briefcase/crimekit, +/obj/item/briefcase/crimekit, /obj/item/taperecorder, /obj/item/camera, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/trade/command/fmate) "Ec" = ( /obj/structure/closet/crate, @@ -5831,117 +6199,141 @@ /obj/random/hat, /obj/random/hat, /obj/random/masks, -/obj/machinery/firealarm{ - pixel_y = 24 - }, -/obj/machinery/power/apc{ - dir = 8 +/obj/machinery/apc{ + dir = 8; + pixel_x = -22 }, /obj/structure/cable{ - d2 = 6; icon_state = "0-6" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) +"Eh" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/structure/catwalk, +/obj/machinery/light/navigation{ + color = "#ff3333" + }, +/obj/structure/lattice, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"Eq" = ( +/obj/effect/paint/sun, +/turf/wall/titanium, +/area/ship/trade/shuttle/outgoing/general) "Et" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) -"EA" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; - dir = 1 +"Ey" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" + icon_state = "4-8" }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"EQ" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/starboard) +"EA" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 }, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) +"EQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/obj/machinery/door/airlock/hatch/autoname/command, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/fmate) +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) +"ER" = ( +/obj/machinery/network/acl{ + initial_network_id = "tradenet" + }, +/turf/floor/tiled/techfloor, +/area/ship/trade/command/captain) "Fc" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/portable_atmospherics/powered/pump/filled, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) +"Fl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) "Fm" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/hidden) +"Fv" = ( +/obj/machinery/door/window/southright, +/obj/structure/table/marble, +/obj/machinery/door/firedoor, +/turf/floor/tiled/white, +/area/ship/trade/crew/medbay/chemistry) "FD" = ( /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/command/fmate) "FS" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; +/obj/structure/table, +/obj/machinery/button/blast_door{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, -/area/ship/trade/dock) -"FV" = ( -/obj/item/radio, -/obj/structure/cable{ - icon_state = "4-9" + name = "External Lockdown"; + directional_offset = null }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; - dir = 6 +/obj/random_multi/single_item/captains_spare_id, +/obj/item/documents/tradehouse/account, +/obj/item/documents/tradehouse/personnel, +/obj/abstract/landmark/paperwork_spawn_tradeship, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"FT" = ( +/obj/machinery/alarm{ + dir = 4; + pixel_x = -21 }, -/turf/simulated/floor/airless, -/area/space) +/turf/floor/plating, +/area/ship/trade/maintenance/hallway) "FW" = ( /obj/structure/table/reinforced, /obj/item/flashlight/lamp, @@ -5951,156 +6343,270 @@ pixel_y = 25 }, /obj/random/single/textbook, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/hidden) "Gb" = ( /obj/machinery/atmospherics/omni/filter{ tag_east = 1; tag_north = 3; tag_south = 4; - tag_west = 2; - use_power = 1 + tag_west = 2 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "Gc" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/starboard) -"Gv" = ( -/obj/machinery/door/airlock/hatch, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, +"Gj" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/plating, +/area/ship/trade/hidden) +"Gw" = ( +/obj/machinery/computer/ship/sensors, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"GA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"GB" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/techfloor/orange{ + dir = 10 + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"GD" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/obj/effect/paint/sun, +/obj/machinery/door/blast/regular/open{ + id_tag = "bee_shutters" + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "GF" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/atmos) +"GJ" = ( +/obj/machinery/portable_atmospherics/canister/empty, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"GN" = ( +/obj/structure/sign/directions/medical{ + dir = 1; + pixel_x = 30; + pixel_y = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"GO" = ( +/obj/effect/paint/red, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) +"GS" = ( +/obj/item/inflatable_dispenser, +/obj/machinery/light{ + dir = 1; + icon_state = "bulb1" + }, +/obj/machinery/cell_charger, +/obj/structure/table/steel, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"GT" = ( +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "Hb" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/atmospherics/binary/passive_gate/on{ dir = 1; name = "Air to Supply" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "Hc" = ( /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; - pixel_x = 24 + pixel_x = 21 }, /obj/item/bedsheet/medical, /obj/structure/curtain/open/privacy, /obj/structure/bed/padded, -/obj/item/clothing/accessory/stethoscope, -/turf/simulated/floor/tiled/white, +/obj/item/clothing/neck/stethoscope, +/obj/random/drinkbottle, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) +"Hp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) "Hs" = ( -/turf/simulated/floor/wood/yew, +/obj/machinery/light, +/turf/floor/laminate/yew, /area/ship/trade/unused) -"HF" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "engwindow"; - name = "blast door"; - opacity = 0 - }, -/obj/machinery/door/firedoor, +"HA" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/wall, /area/ship/trade/maintenance/power) -"HO" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/turf/space, -/area/space) "HR" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/atmos) +"HT" = ( +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"HZ" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "Ib" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 5 }, /obj/machinery/light, -/obj/structure/closet/walllocker/emerglocker/west, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/emergency_dispenser/west, +/obj/machinery/meter, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "Ic" = ( /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, -/obj/item/storage/medical_lolli_jar, -/obj/structure/table/standard, -/turf/simulated/floor/tiled/white, +/obj/item/medical_lolli_jar, +/obj/structure/table, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) +"If" = ( +/obj/effect/paint/black, +/turf/wall/titanium, +/area/ship/trade/shuttle/outgoing/engineering) "Ig" = ( /obj/machinery/computer/account_database, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/ship/trade/command/bridge) "Im" = ( -/obj/structure/table/standard, -/obj/item/chems/food/snacks/monkeycube/wrapped, -/obj/structure/closet/medical_wall{ - name = "pill cabinet"; - pixel_x = 0; - pixel_y = -29 - }, -/obj/item/storage/pill_bottle/antibiotics, -/obj/item/storage/pill_bottle/painkillers, -/obj/item/storage/pill_bottle/antitox, -/obj/item/storage/pill_bottle/burn_meds, -/turf/simulated/floor/tiled/white, +/obj/structure/table, +/obj/item/food/animal_cube/wrapped/monkey, +/obj/structure/closet/secure_closet/medical_wall/pills{ + pixel_y = -32; + req_access = null; + dir = 1 + }, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "Is" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /turf/space, /area/space) +"Iw" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -21 + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) +"Iy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/port) "IA" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/engine/aft) +"IC" = ( +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) +"IH" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"IJ" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/port_gen/pacman/super, +/turf/floor/plating, +/area/ship/trade/shieldbay) +"IM" = ( +/turf/floor/plating/airless, +/area/ship/trade/command/captain) +"IW" = ( +/obj/effect/paint/red, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 10 + }, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) "Jb" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/cell_charger, -/obj/item/storage/toolbox/electrical{ +/obj/item/toolbox/electrical{ pixel_x = 7; pixel_y = 4 }, @@ -6108,185 +6614,211 @@ pixel_y = 25 }, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/structure/cable{ icon_state = "6-8" }, /obj/random/powercell, /obj/random/powercell, -/obj/item/boombox, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/item/music_player/boombox, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) -"Jc" = ( -/obj/structure/closet/secure_closet/freezer/meat, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 1 - }, -/obj/effect/floor_decal/corner/red/diagonal, -/obj/random/drinkbottle, -/obj/random/drinkbottle, -/obj/random/drinkbottle, -/turf/simulated/floor/tiled, -/area/ship/trade/crew/kitchen) "Jg" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/engine/port) "Jh" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/monotile, /area/ship/trade/command/hallway) "Jk" = ( -/obj/structure/bed/chair/office/dark, -/obj/machinery/button/blast_door{ - id_tag = "fmate"; - pixel_x = 25; - pixel_y = -2 - }, -/obj/effect/landmark/start{ +/obj/structure/chair/office/dark, +/obj/abstract/landmark/start{ name = "First Mate" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/trade/command/fmate) "Jn" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 6 }, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/obj/structure/closet/emcloset, /obj/structure/sign/deck/first{ - pixel_x = 32 + pixel_x = 32; + dir = 8 }, -/obj/random/voidhelmet, -/obj/random/voidsuit, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/obj/random/voidhelmet, -/obj/random/voidsuit, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "Jp" = ( /obj/effect/floor_decal/corner/red/diagonal, -/obj/effect/decal/cleanable/dirt, -/obj/structure/kitchenspike, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/meat_hook, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/kitchen) "Jr" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/maintenance/power) +"Jv" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/apc{ + dir = 1; + name = "Docking Area APC"; + pixel_y = 22 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"JA" = ( +/obj/machinery/keycard_auth{ + pixel_y = 28 + }, +/turf/floor/carpet, +/area/ship/trade/command/fmate) "JI" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) +"JN" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/port) "JR" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; dir = 9 }, -/obj/machinery/newscaster{ - pixel_x = -32 - }, -/obj/machinery/media/jukebox/old, -/turf/simulated/floor/tiled, +/obj/structure/closet/emcloset, +/obj/random/voidsuit, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/voidhelmet, +/obj/item/tank/oxygen, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "JX" = ( /obj/effect/floor_decal/corner/blue, /obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; dir = 4 }, /obj/machinery/fabricator/pipe/disposal, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/atmos) "Kb" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/cell_charger, /obj/item/flashlight, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/random/powercell, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) "Kc" = ( /obj/structure/disposalpipe/segment, -/obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = 21 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) +"Kd" = ( +/obj/machinery/alarm{ + dir = 8; + pixel_x = 21 + }, +/obj/structure/table, +/obj/machinery/cell_charger, +/turf/floor/plating, +/area/ship/trade/shieldbay) +"Kj" = ( +/obj/machinery/door/airlock/hatch/autoname/general, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/command/captain) +"Kl" = ( +/obj/machinery/light_switch{ + pixel_x = -24; + dir = 4 + }, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/port) "Kw" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) +"Kx" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "bee_star_pump_out_internal" + }, +/obj/structure/emergency_dispenser/west{ + pixel_x = 32 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"KA" = ( +/obj/structure/railing/mapped, +/obj/structure/handrail{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 6 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "KI" = ( /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -24; + dir = 4 }, /obj/structure/catwalk, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) "KO" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -6296,119 +6828,87 @@ dir = 4 }, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/power) -"KP" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, -/area/ship/trade/command/bridge) "KR" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/crew/medbay) -"Lb" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; - level = 2 - }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 10 - }, +"KZ" = ( /obj/machinery/alarm{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + dir = 8; + pixel_x = 21 + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) +"Lb" = ( +/obj/structure/shuttle/engine/propulsion/burst/right{ + dir = 1 }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating/airless, +/area/ship/trade/shuttle/outgoing/general) "Lc" = ( /obj/effect/decal/cleanable/cobweb, /obj/effect/decal/cleanable/cobweb2, /obj/structure/cable{ - d1 = 32; - d2 = 1; - icon_state = "32-1" - }, -/obj/structure/lattice, -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/disposalpipe/segment, -/turf/simulated/open, +/turf/floor/plating, /area/ship/trade/crew/hallway/starboard) -"Ln" = ( -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/command/bridge) +"Ld" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"Lm" = ( +/obj/machinery/shield_generator/mapped, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "Ls" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/command/fmate) +"Lu" = ( +/obj/machinery/light/spot, +/obj/structure/lattice, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) "Lx" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, /turf/space, /area/space) +"LC" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/starboard) "LP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) -"LY" = ( -/obj/item/screwdriver, -/obj/structure/cable{ - icon_state = "5-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; - dir = 10 - }, -/turf/simulated/floor/airless, -/area/space) -"Mb" = ( -/obj/structure/bed/chair/comfy/brown{ - dir = 1 - }, -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/item/radio/intercom{ - dir = 8; - pixel_x = 22 - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +"LU" = ( +/obj/effect/paint/sun, +/turf/wall/titanium, +/area/ship/trade/shuttle/outgoing/engineering) "Mc" = ( /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -6417,27 +6917,21 @@ dir = 6 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) -"Mo" = ( -/obj/structure/lattice, -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/crew/medbay/chemistry) "Mp" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/atmos) "Mw" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/dock) "MB" = ( /obj/item/stool/padded, @@ -6445,33 +6939,66 @@ dir = 4; level = 2 }, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Junior Doctor" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/crew/saloon) "MD" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/unused) +"MG" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4; + level = 2 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"MO" = ( +/obj/machinery/light, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -24 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"MW" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/power/smes/buildable/max_cap_in_out, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"MX" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "bulb1" + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) "Nb" = ( -/obj/effect/wallframe_spawn/reinforced/titanium, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/catwalk, +/obj/structure/railing/mapped{ + dir = 1 + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) "Nc" = ( /obj/structure/disposalpipe/segment{ - icon_state = "conpipe-c"; - dir = 4 + dir = 4; + icon_state = "conpipe-c" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 1; - name = "Washroom APC" + name = "Washroom APC"; + pixel_y = 22 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -6480,38 +7007,115 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/machinery/firealarm{ - pixel_y = 24 + pixel_y = 21 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/ship/trade/crew/wash) +"Nd" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/red, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"Nm" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) +"Np" = ( +/obj/machinery/network/requests_console{ + announcementConsole = 1; + department = "Captain"; + pixel_y = -32 + }, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/closet/emcloset, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/item/tank/oxygen, +/obj/item/tank/oxygen, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"Nx" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/port) +"NF" = ( +/obj/item/screwdriver, +/obj/structure/cable{ + icon_state = "5-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 10 + }, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/port) +"NG" = ( +/obj/structure/shuttle/engine/propulsion/burst/left{ + dir = 1 + }, +/turf/floor/plating/airless, +/area/ship/trade/shuttle/outgoing/general) "NI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/bookcase/skill_books/random, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) -"NN" = ( -/obj/machinery/requests_console{ - announcementConsole = 1; - department = "Captain"; - pixel_x = 32 +"NM" = ( +/obj/effect/floor_decal/corner/beige{ + dir = 9 }, -/obj/structure/bed/chair{ - dir = 1 +/obj/structure/chair/shuttle/blue{ + dir = 4 }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/alarm{ + pixel_y = 21 + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) +"NS" = ( +/obj/machinery/computer/shuttle_control/explore/tradeship, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"NT" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "bee_port_inner" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/cyan{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) "Ob" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; - pixel_x = 24 + pixel_x = 21 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; @@ -6525,79 +7129,68 @@ /obj/item/clothing/shoes/color/brown, /obj/random/plushie, /mob/living/simple_animal/corgi/Ian, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/trade/command/fmate) "Oc" = ( /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/effect/decal/cleanable/cobweb2, /obj/machinery/network/relay{ initial_network_id = "tradenet" }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) "Og" = ( -/obj/machinery/power/apc{ - dir = 4; - name = "Bridge APC" +/obj/structure/cable{ + icon_state = "1-2" }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "2-4" }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/monotile, /area/ship/trade/command/hallway) -"Oi" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/turf/simulated/floor/airless, -/area/space) -"Oq" = ( -/obj/structure/bed/chair/comfy/teal{ - dir = 1 - }, -/obj/effect/landmark/start{ - name = "Captain" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) "Os" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/manifold/visible/fuel, /obj/structure/window/borosilicate_reinforced, -/obj/machinery/power/emitter/gyrotron/anchored{ +/obj/machinery/emitter/gyrotron/anchored{ initial_id_tag = "main_drive" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/plating, +/obj/machinery/power/terminal, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) -"OI" = ( -/obj/structure/lattice, -/obj/structure/handrai, -/turf/space, -/area/space) "OP" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; - pixel_x = 24 + pixel_x = 21 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagent_temperature/cooler, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay/chemistry) +"OQ" = ( +/obj/abstract/ramp_sculptor/west, +/turf/wall/natural, +/area/space) +"Pa" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/apc{ + dir = 8; + pixel_x = -22 + }, +/obj/structure/table, +/turf/floor/plating, +/area/ship/trade/shieldbay) "Pb" = ( /obj/item/gun/projectile/shotgun/pump{ desc = "When words don't strike hard enough."; @@ -6605,40 +7198,52 @@ }, /obj/structure/displaycase, /obj/machinery/newscaster{ - pixel_y = -30 + pixel_y = -32; + dir = 1 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/ship/trade/command/captain) "Pc" = ( -/obj/structure/closet/walllocker/emerglocker/east, +/obj/structure/emergency_dispenser/east, /obj/structure/disposalpipe/segment, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/obj/machinery/firealarm{ +/turf/floor/plating, +/area/ship/trade/crew/hallway/port) +"Pp" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ship/trade/command/captain) +"PB" = ( +/obj/machinery/alarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = 21 }, -/turf/simulated/floor/tiled/techmaint, -/area/ship/trade/crew/hallway/port) -"PA" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - icon_state = "2-9" + icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "tradeship_rescue_shuttle_pump" + }, +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/effect/floor_decal/corner/white{ + dir = 1 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) "PE" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/firedoor, @@ -6646,109 +7251,137 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, /obj/machinery/door/airlock/hatch/autoname/engineering, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/engineering) +"PF" = ( +/obj/machinery/recharge_station, +/turf/floor/plating, +/area/ship/trade/shieldbay) "PH" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/power) "PU" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, /obj/item/mollusc/barnacle{ - pixel_z = -11 + pixel_y = -11 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/command/captain) "Qb" = ( /obj/machinery/computer/modular/preset/cardslot/command, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/ship/trade/command/bridge) "Qc" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/fuel, -/obj/machinery/firealarm{ - dir = 4; - pixel_x = 24; - pixel_y = 0 - }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/structure/disposalpipe/segment, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/crew/hallway/starboard) "Ql" = ( /obj/structure/lattice, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/space, -/area/space) +/obj/structure/sign/warning/hot_exhaust{ + pixel_y = 32 + }, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/engine/starboard) +"Qu" = ( +/obj/machinery/portable_atmospherics/canister/hydrogen, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"Qz" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/blue/diagonal{ + dir = 4 + }, +/obj/machinery/keycard_auth{ + pixel_y = 28 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"QF" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) "QH" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/cable, -/obj/machinery/power/apc{ - name = "Medical Bay APC" +/obj/machinery/apc{ + name = "Medical Bay APC"; + pixel_y = -22 }, /obj/machinery/light_switch{ - pixel_x = -25 + pixel_x = -24; + dir = 4 }, /obj/structure/closet/medical_wall/filled{ - pixel_y = -32 + pixel_y = -32; + dir = 1 }, -/obj/item/tape_roll, -/obj/item/storage/firstaid/surgery, -/turf/simulated/floor/tiled/white, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/firstaid/surgery, +/turf/floor/tiled/white, /area/ship/trade/crew/medbay) "QS" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/light, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" + }, +/obj/machinery/button/toggle/engine{ + id_tag = "tradeship_engine_vent"; + name = "engine vent control button"; + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"QW" = ( +/obj/machinery/light, +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -24 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) "Rb" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; - name = "Captain's Quarters APC" + name = "Captain's Quarters APC"; + pixel_x = 22 }, -/obj/item/chems/food/drinks/glass2/coffeecup/one, +/obj/item/chems/drinks/glass2/coffeecup/one, /obj/machinery/firealarm{ dir = 1; pixel_y = -24 }, -/turf/simulated/floor/carpet/blue, +/turf/floor/carpet/blue, /area/ship/trade/command/captain) "Rc" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -6757,42 +7390,77 @@ /obj/item/stool/padded, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, -/turf/simulated/floor/wood/yew, +/turf/floor/laminate/yew, /area/ship/trade/unused) +"Rg" = ( +/obj/structure/railing/mapped{ + dir = 4 + }, +/obj/structure/catwalk, +/obj/machinery/light/navigation{ + color = "#00ff00" + }, +/obj/structure/lattice, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"Rl" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/turf/floor/plating/airless, +/area/ship/trade/maintenance/atmos) +"Rq" = ( +/obj/structure/cable{ + icon_state = "4-9" + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/turf/floor/carpet/blue, +/area/ship/trade/command/captain) "Rv" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/start{ +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/start{ name = "Cargo Technician" }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/merchant_pad, -/turf/simulated/floor/tiled/techfloor, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = 21 + }, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) "RL" = ( -/obj/structure/closet/walllocker/emerglocker/north, -/obj/structure/bed/chair/wood, -/obj/item/deck/tarot, -/obj/structure/handrai, -/turf/simulated/floor/tiled, +/obj/structure/emergency_dispenser/north, +/obj/structure/handrail, +/turf/floor/tiled, /area/ship/trade/crew/saloon) +"RM" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/shuttle/rescue) "RW" = ( /obj/machinery/atmospherics/unary/engine{ - icon_state = "nozzle"; dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/maintenance/engine/port) "Sb" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 5 +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 9 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "Sc" = ( /obj/effect/decal/cleanable/cobweb, /obj/effect/floor_decal/corner/blue{ @@ -6803,202 +7471,340 @@ }, /obj/machinery/portable_atmospherics/hydroponics, /obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 1; + icon_state = "bulb1" }, /obj/machinery/newscaster{ - pixel_x = -32 + pixel_x = -32; + dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) +"Sg" = ( +/obj/machinery/light, +/obj/machinery/light_switch{ + pixel_y = -20; + dir = 1 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) "Si" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/crew/toilets) +"Sj" = ( +/obj/effect/floor_decal/techfloor/orange{ + dir = 10 + }, +/obj/structure/handrail{ + dir = 1 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"Sr" = ( +/turf/floor/plating, +/area/ship/trade/maintenance/hallway) +"SB" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/machinery/computer/shuttle_control/explore/rescue, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) "SC" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/command/captain) -"Tb" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/structure/closet/crate, -/obj/item/radio, -/obj/item/spaceflare, -/obj/machinery/firealarm{ +"SG" = ( +/turf/space, +/area/ship/trade/command/captain) +"SI" = ( +/obj/machinery/alarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = -21 }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10; - icon_state = "intact" +/obj/effect/floor_decal/steeldecal/steel_decals6, +/obj/structure/sign/warning/radioactive{ + pixel_y = 32 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/machinery/vending/cigarette, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) +"SL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) +"SQ" = ( +/obj/machinery/light{ + dir = 1; + icon_state = "tube1" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/apc{ + dir = 1; + name = "Docking Area APC"; + pixel_y = 22 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) -"Tl" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/door/airlock/hatch/autoname/command, +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/hallway) +"Tb" = ( +/obj/effect/floor_decal/techfloor/orange{ + dir = 5 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"Tp" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; + icon_state = "4-8" + }, +/obj/machinery/light, +/obj/random/maintenance, +/turf/floor/tiled/techmaint, +/area/ship/trade/shieldbay) +"Tr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable/orange{ icon_state = "1-2" }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) -"Tt" = ( -/obj/effect/paint/brown, -/turf/simulated/wall, -/area/ship/trade/crew/saloon) +/obj/effect/paint/sun, +/turf/wall/titanium, +/area/ship/trade/shuttle/outgoing/engineering) +"Tv" = ( +/obj/structure/lattice, +/turf/wall/natural, +/area/space) +"Tx" = ( +/obj/structure/shuttle/engine/propulsion/burst/right, +/turf/floor/plating/airless, +/area/ship/trade/shuttle/outgoing/engineering) "TB" = ( /obj/machinery/atmospherics/valve/open{ - icon_state = "map_valve1"; dir = 4 }, -/turf/simulated/floor/plating, +/obj/structure/window/borosilicate_reinforced{ + dir = 8 + }, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "TL" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) -"Ub" = ( -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/item/storage/backpack/dufflebag, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +"TM" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"TR" = ( +/obj/structure/sign/deck/first{ + pixel_x = 32; + dir = 8 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/starboard) "Uc" = ( /obj/machinery/seed_storage/garden{ - icon_state = "seeds_generic"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) "Ue" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "scraplock" }, /obj/structure/cable{ icon_state = "4-10" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/crew/kitchen) "Ui" = ( /obj/effect/paint/brown, -/turf/simulated/wall, +/turf/wall, /area/ship/trade/crew/toilets) -"Uo" = ( -/obj/machinery/network/relay{ - initial_network_id = "tradenet" +"UA" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "bee_port_pump_out_internal" + }, +/obj/structure/emergency_dispenser/west{ + dir = 4 + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/shuttle/outgoing/general) +"UB" = ( +/obj/machinery/light, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/light_switch{ + pixel_y = -20; + dir = 1 }, -/turf/simulated/floor/bluegrid, -/area/ship/trade/comms) +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge) +"UD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel, +/obj/structure/lattice, +/obj/structure/handrail{ + dir = 4 + }, +/turf/space, +/area/ship/trade/maintenance/engine/port) "UP" = ( /obj/machinery/door/blast/regular{ id_tag = "scram" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/ship/trade/maintenance/engine/aft) -"Vb" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ +"UQ" = ( +/obj/effect/paint/red, +/obj/machinery/atmospherics/pipe/manifold/hidden{ + dir = 8 + }, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) +"UT" = ( +/obj/effect/paint/black, +/turf/wall/titanium, +/area/ship/trade/shuttle/outgoing/general) +"UV" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/ship/trade/dock) +"UY" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white{ dir = 6 }, +/obj/effect/floor_decal/corner/white{ + dir = 8 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"Vb" = ( /obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; - dir = 9 + dir = 6 }, -/obj/item/radio/intercom{ - dir = 4; - pixel_x = -22 +/obj/structure/handrail{ + dir = 8 }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 +/obj/random/closet, +/obj/item/backpack/dufflebag, +/obj/machinery/airlock_sensor{ + dir = 8; + id_tag = "bee_interior_sensor"; + pixel_x = 22 }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/turf/floor/tiled/steel_ridged, +/area/ship/trade/shuttle/outgoing/general) "Vc" = ( /obj/structure/cable, -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; - pixel_y = -24 + pixel_y = -22 }, /obj/item/chems/glass/bucket, /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) +"Vd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/laminate, +/area/ship/trade/command/fmate) +"Vl" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/light, +/obj/effect/floor_decal/techfloor/orange{ + dir = 6 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"Vq" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"VK" = ( +/obj/machinery/network/relay{ + initial_network_id = "tradenet" + }, +/turf/floor/bluegrid, +/area/ship/trade/command/fmate) "VL" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel, /obj/machinery/fusion_fuel_injector/mapped{ dir = 1; - icon_state = "injector0"; initial_id_tag = "main_drive" }, /obj/structure/window/borosilicate_reinforced{ - icon_state = "rwindow"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) +"VW" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "scraplock"; + name = "scraplock" + }, +/obj/machinery/door/firedoor, +/turf/floor/plating, +/area/ship/trade/crew/hallway/starboard) +"VX" = ( +/obj/machinery/vending/coffee{ + dir = 8 + }, +/turf/floor/tiled/techmaint, +/area/ship/trade/crew/hallway/starboard) "Wb" = ( -/obj/effect/floor_decal/corner/beige{ - icon_state = "corner_white"; +/obj/effect/floor_decal/techfloor/orange{ dir = 6 }, -/obj/machinery/alarm{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 - }, -/obj/structure/bed/chair{ +/obj/structure/handrail{ dir = 1 }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/turf/simulated/floor/tiled, -/area/ship/trade/shuttle/outgoing) +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) "Wc" = ( -/obj/machinery/light, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, @@ -7009,17 +7815,12 @@ icon_state = "4-9" }, /obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - icon_state = "intact"; dir = 4 }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/machinery/firealarm{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/tiled/techmaint, +/turf/floor/tiled/techmaint, /area/ship/trade/maintenance/hallway) "Wf" = ( /obj/effect/floor_decal/corner/blue{ @@ -7033,218 +7834,305 @@ }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -21 }, /obj/machinery/light{ - dir = 2; icon_state = "bulb1" }, /obj/machinery/vending/hydronutrients/generic{ - icon_state = "nutri_generic"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) "Wp" = ( /obj/machinery/cryopod/lifepod, /obj/machinery/door/window/southright, /obj/machinery/computer/cryopod{ - pixel_x = 32 + dir = 8; + pixel_x = 24 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/ship/trade/command/captain) "WE" = ( /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/hatch/autoname/engineering, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/steel_ridged, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/atmos) +"WF" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "bee_pump_out_external" + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 5 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"WK" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 8; + id_tag = "tradeship_rescue_shuttle_pump_out_internal" + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/corner/white{ + dir = 9 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"WM" = ( +/obj/structure/catwalk, +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) "WO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/ship/trade/garden) "Xc" = ( /obj/machinery/atmospherics/binary/pump/on{ - dir = 8; - target_pressure = 101.325 - }, -/obj/machinery/light{ - icon_state = "bulb1"; - dir = 1 + dir = 8 }, /obj/effect/floor_decal/corner/blue{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/atmos) -"Xl" = ( -/obj/machinery/atm{ - pixel_y = 25 - }, -/obj/machinery/alarm{ +"Xx" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"Xz" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/techmaint, +/area/ship/trade/maintenance/hallway) +"XG" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "alarm0"; - pixel_x = -24 + id_tag = "scraplock"; + name = "scraplock" }, -/obj/effect/floor_decal/steeldecal/steel_decals6, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/dock) -"Xu" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 5 }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge) +/turf/floor/plating, +/area/ship/trade/maintenance/atmos) "XR" = ( /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/item/stool/padded, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/cargo) "XX" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "engwindow"; - name = "blast door"; - opacity = 0 +/obj/machinery/door/blast/regular/open{ + id_tag = "engwindow" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/engine/aft) "Ya" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/floor_decal/industrial/warning, /obj/structure/catwalk, /obj/structure/railing/mapped, -/turf/simulated/open, +/turf/open, /area/ship/trade/cargo) -"Yb" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "tradeship_shuttle_in" - }, -/obj/structure/cable{ - icon_state = "4-10" - }, -/obj/machinery/button/access/interior{ - id_tag = "bearcat_shuttle"; - pixel_x = -12; - pixel_y = 20 - }, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) "Yc" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/bed/padded, -/obj/effect/landmark/start{ +/obj/abstract/landmark/start{ name = "Head Engineer" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/ship/trade/maintenance/engineering) +"Yd" = ( +/obj/structure/cable/orange{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ + dir = 1 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/outgoing/general) +"Yl" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "tradeship_rescue_shuttle_pump" + }, +/obj/effect/floor_decal/corner/white{ + dir = 6 + }, +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled, +/area/ship/trade/shuttle/rescue) +"Ys" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/red{ + dir = 8 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 9 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"Yt" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/structure/lattice, +/obj/structure/sign/warning/docking_area{ + dir = 8; + pixel_x = 34 + }, +/turf/space, +/area/space) "YE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/hologram/holopad/longrange, -/turf/simulated/floor/tiled/dark, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/dark, /area/ship/trade/command/bridge) -"YN" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +"YI" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 + }, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/red{ + dir = 4 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) +"YN" = ( +/turf/floor/plating, /area/ship/trade/crew/hallway/starboard) -"YS" = ( -/obj/structure/lattice, -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, -/area/ship/trade/crew/toilets) +"YR" = ( +/obj/effect/paint/red, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 6 + }, +/turf/wall/titanium, +/area/ship/trade/shuttle/rescue) "Za" = ( /obj/machinery/power/breakerbox/activated, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/power) "Zb" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - id_tag = "tradeship_shuttle_pump" +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - cycle_to_external_air = 1; - id_tag = "tradeship_shuttle"; - pixel_x = 0; - pixel_y = -24; - tag_airpump = "tradeship_shuttle_pump"; - tag_chamber_sensor = "tradeship_shuttle_sensor"; - tag_exterior_door = "tradeship_shuttle_out"; - tag_interior_door = "tradeship_shuttle_in" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/effect/shuttle_landmark/docking_arm_port/shuttle, -/turf/simulated/floor/plating, -/area/ship/trade/shuttle/outgoing) +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/engineering) "Zc" = ( /obj/structure/closet/secure_closet/engineering_electrical, /obj/item/cell/device/standard, /obj/item/cell/device/standard, -/obj/machinery/power/apc{ - dir = 8 +/obj/machinery/apc{ + dir = 8; + pixel_x = -22 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/item/radio/intercom{ - pixel_y = 22 + pixel_y = 20 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/power) +"Zf" = ( +/obj/structure/railing/mapped, +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 10 + }, +/turf/floor/plating, +/area/ship/trade/shuttle/outgoing/general) +"Zg" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/structure/lattice, +/turf/space, +/area/ship/trade/command/fmate) "Zv" = ( /obj/structure/lattice, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /turf/space, /area/space) +"Zx" = ( +/obj/structure/lattice, +/turf/space, +/area/ship/trade/shuttle/outgoing/general) +"ZK" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 1; + id_tag = "tradeship_rescue_shuttle_pump_out_external" + }, +/turf/floor/plating/airless, +/area/ship/trade/shuttle/rescue) (1,1,1) = {" aa @@ -7328,89 +8216,7 @@ aa aa aa "} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" +(2,1,1) = {" aa aa aa @@ -7492,7 +8298,7 @@ aa aa aa "} -(4,1,1) = {" +(3,1,1) = {" aa aa aa @@ -7574,7 +8380,7 @@ aa aa aa "} -(5,1,1) = {" +(4,1,1) = {" aa aa aa @@ -7656,8 +8462,7 @@ aa aa aa "} -(6,1,1) = {" -aa +(5,1,1) = {" aa aa aa @@ -7733,12 +8538,13 @@ aa aa aa aa +xh aa aa aa aa "} -(7,1,1) = {" +(6,1,1) = {" aa aa aa @@ -7820,7 +8626,7 @@ aa aa aa "} -(8,1,1) = {" +(7,1,1) = {" aa aa aa @@ -7902,7 +8708,7 @@ aa aa aa "} -(9,1,1) = {" +(8,1,1) = {" aa aa aa @@ -7984,7 +8790,7 @@ aa aa aa "} -(10,1,1) = {" +(9,1,1) = {" aa aa aa @@ -8066,7 +8872,7 @@ aa aa aa "} -(11,1,1) = {" +(10,1,1) = {" aa aa aa @@ -8148,7 +8954,7 @@ aa aa aa "} -(12,1,1) = {" +(11,1,1) = {" aa aa aa @@ -8230,8 +9036,7 @@ aa aa aa "} -(13,1,1) = {" -aa +(12,1,1) = {" aa aa aa @@ -8244,6 +9049,7 @@ aa aa aa aa +vN aa aa aa @@ -8312,7 +9118,7 @@ aa aa aa "} -(14,1,1) = {" +(13,1,1) = {" aa aa aa @@ -8394,8 +9200,7 @@ aa aa aa "} -(15,1,1) = {" -aa +(14,1,1) = {" aa aa aa @@ -8458,6 +9263,7 @@ aa aa aa aa +vN aa aa aa @@ -8476,7 +9282,7 @@ aa aa aa "} -(16,1,1) = {" +(15,1,1) = {" aa aa aa @@ -8558,7 +9364,7 @@ aa aa aa "} -(17,1,1) = {" +(16,1,1) = {" aa aa aa @@ -8640,7 +9446,7 @@ aa aa aa "} -(18,1,1) = {" +(17,1,1) = {" aa aa aa @@ -8722,7 +9528,7 @@ aa aa aa "} -(19,1,1) = {" +(18,1,1) = {" aa aa aa @@ -8804,7 +9610,7 @@ aa aa aa "} -(20,1,1) = {" +(19,1,1) = {" aa aa aa @@ -8886,16 +9692,7 @@ aa aa aa "} -(21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa +(20,1,1) = {" aa aa aa @@ -8918,6 +9715,15 @@ aa aa aa aa +WM +Eh +lW +Eq +DC +Eq +Eq +sw +Cq aa aa aa @@ -8968,12 +9774,7 @@ aa aa aa "} -(22,1,1) = {" -aa -aa -aa -aa -aa +(21,1,1) = {" aa aa aa @@ -8995,6 +9796,17 @@ aa aa aa aa +WM +gN +qv +Sj +Eq +DH +UA +sm +Ys +nD +GB aa aa aa @@ -9043,14 +9855,14 @@ aa aa aa aa +"} +(22,1,1) = {" aa aa aa aa aa aa -"} -(23,1,1) = {" aa aa aa @@ -9063,8 +9875,20 @@ aa aa aa aa +pv aa aa +og +uf +CV +Vl +Eq +vY +Br +GD +WF +HZ +KA aa aa aa @@ -9072,6 +9896,10 @@ aa aa aa aa +OQ +OQ +OQ +xX aa aa aa @@ -9093,7 +9921,6 @@ aa aa aa aa -xX aa aa aa @@ -9110,6 +9937,8 @@ aa aa aa aa +"} +(23,1,1) = {" aa aa aa @@ -9128,14 +9957,33 @@ aa aa aa aa +Zx aa +NG +Eq +Eq +GD +Eq +Eq +NT +LU +If +LU +uk +LU +CI aa aa -"} -(24,1,1) = {" aa aa aa +tG +eh +eh +eh +pn +pn +Jg aa aa aa @@ -9171,13 +10019,10 @@ aa aa aa aa +"} +(24,1,1) = {" aa aa -eh -eh -pn -pn -Jg aa aa aa @@ -9192,11 +10037,36 @@ aa aa aa aa +IH +Zx +BN +BN +UT +Eq +NM +rL +to +sG +Nm +xW +yq +Zb +YI +tv +LU aa aa aa aa aa +tG +eh +ew +ex +ex +ex +fQ +gk aa aa aa @@ -9213,8 +10083,6 @@ aa aa aa aa -"} -(25,1,1) = {" aa aa aa @@ -9233,6 +10101,8 @@ aa aa aa aa +"} +(25,1,1) = {" aa aa aa @@ -9249,18 +10119,36 @@ aa aa aa aa +IH +Zx +BN +lJ +mf +sA +Vq +QF +Ld +CW +yy +LU +GS +xM +Nd +MW +If aa aa aa aa aa +tG eh -ew -ex ex ex -fQ -gk +fg +fB +RW +aa aa aa aa @@ -9313,23 +10201,23 @@ aa aa aa aa -aa -aa -aa -aa +IH +Lu +BN +NS ab aL -aL -at -aL -aL -aL -aL -aL -aL -aL +Ba +Xx +kX +Xx +Yd +Tr +sj +mr +mW hb -aa +LU aa aa aa @@ -9339,8 +10227,8 @@ aa eh ex ex -fg -fB +fh +fC RW aa aa @@ -9395,23 +10283,23 @@ aa aa aa aa -aa -aa -at -at -aL -aL +IH +Zx +BN +BN +UT +Eq bg bi Vb +bK bx -bx -cc +LU cp cz -aL -aL -aa +qt +uD +If aa aa aa @@ -9419,12 +10307,13 @@ aa aa aa aa +cy ex +mc ex -fh -fC -RW -aa +fQ +gk +cy aa aa aa @@ -9436,10 +10325,10 @@ aa aa aa aa +aa Lx jB jB -jB kq aa aa @@ -9458,7 +10347,6 @@ aa aa aa aa -aa "} (28,1,1) = {" aa @@ -9479,47 +10367,48 @@ aa aa aa aa -at -Ah -Lb -Gv -bh -mw -bp -aL -Yb -aL -cq -cA -cH -aL -aa -aa -aa +Zx aa +Lb +Eq +Eq +GD +Eq +Eq +bL +LU +If +LU +uk +LU +Tx aa aa +Lx aa +xX aa +Lx cy -ex -mc -ex -fQ -gl cy +NF +UD +JN +gm +cy +Lx aa aa aa aa -aa -GF +kR GF GF GF +Rl iV +Rl GF -rx GF rx aa @@ -9540,7 +10429,6 @@ aa aa aa aa -aa "} (29,1,1) = {" aa @@ -9562,104 +10450,22 @@ aa aa aa at -ob -Mb +aa +aa Nb Sb -bi +qv bq -at -Zb +Eq +ac cd -wc +GD cB cI -aL -aa -aa -aa -Lx -aa -xX -aa -Lx -cy -cy -LY -fD -Oi -gm -cy -Lx -aa -aa -aa -GF -GF -hD -hD -iI -iW -iI -hD -hD -GF -GF -GF -jB -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa +Zf aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -at -xb -aL -aL -Tb -Ub -Wb -Nb -ac -aL -cs -cC -aL -aL -aa -aa -YS +vj vj Si vj @@ -9676,20 +10482,20 @@ mX mX rb mX -HR -hD -hD -Cb -iJ -Gb -iJ -Ib +mX +HR +GF hD hD +aT +iW +XG +hD hD GF -kq -aa +GF +GF +jB aa aa aa @@ -9706,7 +10512,7 @@ aa aa aa "} -(31,1,1) = {" +(30,1,1) = {" aa aa aa @@ -9726,19 +10532,19 @@ aa aa aa aa -zb -nu -aL -aL -at -aL -aL -jc -aL -aL -aL -aL -lx +aa +aa +Bi +Tb +CV +Wb +Eq +bJ +Kx +sm +cC +Bl +uL aa vj Ui @@ -9757,21 +10563,21 @@ yA nb Sc sb +hf Wf HR -Ab -ib -is -iK -iY -jo -jD -jQ -kd +hD +hD +Cb +zP +iJ +Gb +Ib +hD +hD hD GF -GF -aa +kq aa aa aa @@ -9788,13 +10594,7 @@ aa aa aa "} -(32,1,1) = {" -aa -aa -aa -aa -aa -aa +(31,1,1) = {" aa aa aa @@ -9814,12 +10614,18 @@ aa aa aa aa -bA -lc -bA aa aa aa +Bi +Rg +oV +Eq +bH +Eq +Eq +lb +Dw aa aa vj @@ -9839,21 +10645,21 @@ gA nb sY WO +yb Uc hD -Xc -ic -it -iL -iZ -jp -jE -jR -ke -hD +Ab +ib +is +iK +iY +iK +jD +jQ +kd +lC hD GF -jB aa aa aa @@ -9870,7 +10676,7 @@ aa aa aa "} -(33,1,1) = {" +(32,1,1) = {" aa aa aa @@ -9887,25 +10693,25 @@ aa aa aa aa -ak +Lx aa aa aa aa -xX aa aa -nZ -Mw -nc +aa +ct +bA +bI bA -Lx aa aa aa aa -Si -cV +aa +av +az di dv dM @@ -9913,7 +10719,7 @@ dZ Cc eA eQ -Jc +bl fE Mc gp @@ -9922,21 +10728,21 @@ nb pb WO yb +yb Mp -hO -id -iu -iM -ja -jq -jF -jS +Xc +ic +it +iL +iZ +jp +jE +jR kf -BD +xI hD GF -kq -aa +jB aa aa aa @@ -9952,9 +10758,7 @@ aa aa aa "} -(34,1,1) = {" -aa -aa +(33,1,1) = {" aa aa aa @@ -9968,25 +10772,27 @@ aa aa aa aa -Lx aa aa +tV +Ls Ls +oK Ls tW Ls Ls aa nZ -bm -oc -cf -ct -OI +Mw +by +bA +Yt cy cy cy -YS +cy +vj cU nd dw @@ -10003,22 +10809,22 @@ gC mb qb vb +fx Vc hF -hP -ie -iv -Db -qE -jr -jG -jT -kg -ks +hO +id +iu +iM +ja +jq +jF +jS +kf +BD hD GF -jB -aa +kq aa aa aa @@ -10034,7 +10840,7 @@ aa aa aa "} -(35,1,1) = {" +(34,1,1) = {" aa aa aa @@ -10051,24 +10857,24 @@ aa aa aa Ls -Ls -Ls oK aw +aw +aw rp aw oK cy -Mw +nZ bm -pc -cg +bz +cf Mw -qS -qS -qS -qS -YS +aq +aq +aq +aq +vj cU cT dx @@ -10086,6 +10892,89 @@ mb mb wb nb +nb +hF +hP +ie +iv +Db +qE +jr +jG +jT +kg +ks +hD +GF +jB +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +cy +cy +Zg +qT +zs +FD +VK +aP +ba +aw +oK +Mw +bm +bE +cf +Mw +oi +qp +cE +cE +in +cE +aC +Hp +MX +Kl +in +qR +Iy +aE +pt +AQ +MX +Iw +in +aI +Fl +FT +Sr hF hQ if @@ -10114,7 +11003,6 @@ aa aa aa aa -aa "} (36,1,1) = {" aa @@ -10130,44 +11018,45 @@ aa aa aa aa -aa -aa -Ls -oK -aw -aw -Uo -aP -ba -aw +yt sM -bm +sM +se +se +sM +JA +xS +xS +Jk +BZ bB +bN bQ -ch +cl cu cE cE -cE +Nx cE cE cW -dk +aC dy dO ea el eC eT -fn +aF Kc fY gr Pc gL -gU +aJ hi hr +Xz hF wG WE @@ -10196,7 +11085,6 @@ aa aa aa aa -aa "} (37,1,1) = {" aa @@ -10206,33 +11094,33 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -HO -qT -zs -FD -xS -xS -xS -Jk -BZ -tg +aa +aa +aa +aa +aa +yt +sM +sM +pG +qZ +Pa +sM +Eb +aQ +Vd +Ob +oK +aO bC -qc +be uc -Mw -qS -qS -qS -cJ -Tt +DO +ao +ao +DO +DO +ax cN cN dz @@ -10250,6 +11138,7 @@ eb eb eb Wc +QW hG Yc ih @@ -10278,7 +11167,6 @@ aa aa aa aa -aa "} (38,1,1) = {" aa @@ -10293,35 +11181,35 @@ aa aa aa aa -ra -KP -Ln -Ln -DO -DO +yt +sM +IJ +nR +BP +qd +sM +oK +CP +aw aw -Eb -aQ -Ob oK -Mw -Mw -bD -bm -Mw -Mw -aa -aa -aa -cJ +br +aR +DO +DO +DO +rT +rH +Np +DO cO JR dl dA dQ -eb +aG Ec -eD +bn eV KI sB @@ -10332,6 +11220,7 @@ fZ fZ eb ht +bM hH hS ii @@ -10360,7 +11249,6 @@ aa aa aa aa -aa "} (39,1,1) = {" aa @@ -10374,28 +11262,28 @@ aa aa aa aa -aa -rQ +yt +sM +sM +xO +GT +yh +Tp +sM +SI +EQ +ah +aj +ap +tg +bD +bf Ig CG -xZ -DL -bb -aw -aw -EQ -aw -aw -bm -Xl -bE -rc -Mw -FS -FS -FS -FS -cJ +pu +MG +MO +DO xc cY MB @@ -10414,6 +11302,7 @@ fZ fZ eb hu +HT hG pT ij @@ -10442,7 +11331,6 @@ aa aa aa aa -aa "} (40,1,1) = {" aa @@ -10456,28 +11344,28 @@ aa aa aa aa -aa -rQ -yg -Oq -Xu -YE -PA -Tl +yt +sM +sM +As +GA +op +ok +ak Og aS Jh bc -Bg +an bv bF -bT +bj cj cw -cw -cw -cw -cK +Ai +YE +dn +au cQ cZ vW @@ -10496,6 +11384,7 @@ fZ gV eU hv +me PE hU ik @@ -10524,7 +11413,6 @@ aa aa aa aa -aa "} (41,1,1) = {" aa @@ -10538,28 +11426,28 @@ aa aa aa aa -aa -rQ -Qb -Cq -vu -NN -lb -as -as +yt +sM +sM +Lm +GT +bU +Sg +sM +SQ Bb -as -as -bm -bw -EA -sc -Mw -FS -FS -FS +ai +am +ap +UV +DE +bf +Qb FS -cJ +Gw +TM +UB +DO RL da dm @@ -10568,8 +11456,8 @@ Ac eb qO XR -eV fr +eV fJ fZ fZ @@ -10578,6 +11466,7 @@ fZ gW eb hw +Xz hG hV il @@ -10606,7 +11495,6 @@ aa aa aa aa -aa "} (42,1,1) = {" aa @@ -10621,33 +11509,33 @@ aa aa aa aa -ra -KP -Ln -Ln -DO -DO +yt +sM +PF +BP +GJ +Qu +sM +SC +Kj +as as -vP -aU -Pb SC -Mw -Mw -bD -bm -Mw -Mw -aa -aa -aa -cJ +Jv +bb +DO +DO +DO +Qz +rH +rI +DO cS db Jn dE dU -eb +aG Rv eH eV @@ -10660,6 +11548,7 @@ gM eV eb hx +Xz hG hW il @@ -10688,7 +11577,6 @@ aa aa aa aa -aa "} (43,1,1) = {" aa @@ -10703,28 +11591,28 @@ aa aa aa aa -aa -aa -aa -HO -nL -ar -Wp -af -aV +yt +sM +sM +ml +ra +Kd +sM +vP +aU ae -eq -aa -bA +Pb +SC +tg bG -tc +bk vc -Mw -YN -YN -YN -cJ -Tt +DO +ao +ao +DO +DO +ax cN cN Dd @@ -10738,10 +11626,11 @@ eb eb eb eb -gN +eU eb eb hy +iN hG hX im @@ -10770,7 +11659,6 @@ aa aa aa aa -aa "} (44,1,1) = {" aa @@ -10786,56 +11674,57 @@ aa aa aa aa -aa -aa -wP -wP -SC -as -aJ -aW -Rb -SC -aa -bA -bH +yt +sM +sM +se +se +sM +af +aV +Rq +ER +Pp +bo +bO bW -cl +nv cu cG cG -cG +LC cL -cG +YN dc -dp +aD dF dV ed er eI fa -ft +aH Lc gt -gb +al Qc gO -gY +aK hj hz +Sr hJ hJ KO hJ hL -HF +aX hL hL hL hJ -tJ -jZ +aY +aZ iQ iQ hR @@ -10852,7 +11741,6 @@ aa aa aa aa -aa "} (45,1,1) = {" aa @@ -10868,27 +11756,109 @@ aa aa aa aa +cy +cy +uP +IM +ar +Wp +ag +aW +Rb +SC +SC +Mw +bm +bs +cf +Mw +VX +yF +YN +YN +cG +cG +aD +SL +hs +TR +hs +lZ +SL +aD +KZ +hs +Ey +IC +cG +aN +xB +GN +aB +hJ +Zc +io +iE +hd +jk +hL +hL +hL +hJ +kB +or +IA +IA +hR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa -wP wP wP SC as +as zO as SC cy -Mw +nZ bm -bX -cm +bt +cf Mw -YN -YN -YN -YN -Mo +VW +VW +VW +VW +om dd de dG @@ -10906,21 +11876,18 @@ gu gP hk gP +gP hJ -Zc -io -iE -hd -jk -hL -hL +Jb +ip +iF +iT +jl +jA +jP +kc hL -hJ -kB -or -IA -IA -hR +Bx aa aa aa @@ -10935,11 +11902,11 @@ aa aa aa aa -"} -(46,1,1) = {" aa aa aa +"} +(47,1,1) = {" aa aa aa @@ -10952,21 +11919,24 @@ aa aa aa aa -Is aa aa +aa +SG +wP wP +SC wP PU wP wP aa nZ -bm -bY -cf -ct -OI +Mw +bu +bA +zY +cy cy cy cy @@ -10987,17 +11957,18 @@ gv Rc gQ hl +Gj hA -hJ -Jb -ip -iF -iT -jl -jA -jP -kc +HA +Kb +iq +Za +iU +jm +hL hL +hL +Jr Bx aa aa @@ -11016,10 +11987,8 @@ aa aa aa aa -aa "} -(47,1,1) = {" -aa +(48,1,1) = {" aa aa aa @@ -11036,6 +12005,7 @@ aa aa aa aa +Is aa aa aa @@ -11043,21 +12013,21 @@ aa aa aa aa -nZ -Mw -bZ +lU +bA +bw bA -Zv aa aa aa aa -ul -df +aa +ay +aA dr dI dX -ef +Fv Kw eL fd @@ -11069,18 +12039,18 @@ gw Dl gQ hm +sS hB -hK -Kb -iq -Za -iU -jm +hL +hL +hL +JI +hL +hL hL hL hL Jr -Bx aa aa aa @@ -11100,13 +12070,7 @@ aa aa aa "} -(48,1,1) = {" -aa -aa -aa -aa -aa -aa +(49,1,1) = {" aa aa aa @@ -11126,12 +12090,18 @@ aa aa aa aa -bA -ca -bA aa aa aa +RM +RM +YR +UQ +DY +kr +GO +UQ +ZK aa aa om @@ -11152,16 +12122,16 @@ Hs gQ sS sS -hL -hL -hL -JI -hL -hL -hL -hL -hL -Jr +qg +gP +Bx +Bx +PH +Bx +Bx +Bx +Bx +Bx aa aa aa @@ -11182,16 +12152,7 @@ aa aa aa "} -(49,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa +(50,1,1) = {" aa aa aa @@ -11214,6 +12175,15 @@ aa aa aa aa +RM +Dj +oM +qA +cb +WK +xz +EA +Cz aa aa om @@ -11233,23 +12203,15 @@ gx gI gQ FW +sS hC sI -Bx -Bx -PH -Bx -Bx -Bx -Bx -Bx -aa -aa -aa +Is aa aa aa aa +Is aa aa aa @@ -11263,8 +12225,6 @@ aa aa aa aa -"} -(50,1,1) = {" aa aa aa @@ -11273,6 +12233,8 @@ aa aa aa aa +"} +(51,1,1) = {" aa aa aa @@ -11291,11 +12253,19 @@ aa aa aa aa -cb aa aa aa aa +RM +SB +PB +nm +iS +Yl +UY +EA +Cz aa aa aa @@ -11310,19 +12280,14 @@ ff KR KR KR -gy +aM gg MD sI sI sI +sI Fm -Is -aa -aa -aa -aa -Is aa aa aa @@ -11345,17 +12310,13 @@ aa aa aa aa -"} -(51,1,1) = {" -aa -aa -aa -aa aa aa aa aa aa +"} +(52,1,1) = {" aa aa aa @@ -11378,6 +12339,15 @@ aa aa aa aa +RM +RM +IW +AE +AE +qM +Dx +IW +ZK aa aa aa @@ -11389,9 +12359,9 @@ aa Is cy cy -FV -fM -Oi +vt +pe +kC gz cy Zv @@ -11428,9 +12398,7 @@ aa aa aa "} -(52,1,1) = {" -aa -aa +(53,1,1) = {" aa aa aa @@ -11469,7 +12437,9 @@ aa aa aa aa -cy +eh +eh +Tv eN Gc fN @@ -11510,8 +12480,7 @@ aa aa aa "} -(53,1,1) = {" -aa +(54,1,1) = {" aa aa aa @@ -11549,6 +12518,7 @@ aa aa aa aa +tG eh eh eN @@ -11592,9 +12562,7 @@ aa aa aa "} -(54,1,1) = {" -aa -aa +(55,1,1) = {" aa aa aa @@ -11632,6 +12600,8 @@ aa aa aa aa +tG +eh ew eN eN @@ -11674,9 +12644,7 @@ aa aa aa "} -(55,1,1) = {" -aa -aa +(56,1,1) = {" aa aa aa @@ -11714,13 +12682,15 @@ aa aa aa aa +tG +eh eh eh eN eN eN gj -gk +sz aa aa aa @@ -11756,10 +12726,7 @@ aa aa aa "} -(56,1,1) = {" -aa -aa -aa +(57,1,1) = {" aa aa aa @@ -11798,6 +12765,9 @@ aa aa aa aa +Cg +Cg +Cg aa we we @@ -11838,88 +12808,6 @@ aa aa aa "} -(57,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -wL -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} (58,1,1) = {" aa aa @@ -11963,7 +12851,7 @@ aa aa aa aa -aa +wL aa aa aa @@ -12312,7 +13200,7 @@ aa aa aa aa -aa +vN aa aa aa @@ -12755,7 +13643,7 @@ aa aa aa aa -aa +vN aa aa aa diff --git a/maps/tradeship/tradeship-3.dmm b/maps/tradeship/tradeship-3.dmm index 73eab79024ec..52e3a262d0c8 100644 --- a/maps/tradeship/tradeship-3.dmm +++ b/maps/tradeship/tradeship-3.dmm @@ -2,22 +2,41 @@ "aa" = ( /turf/space, /area/space) +"ab" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/turf/floor/plating, +/area/ship/trade/bridge_unused) "ac" = ( /obj/structure/lattice, /turf/space, /area/space) +"ad" = ( +/turf/floor/reinforced/airless, +/area/ship/trade/comms) "ae" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "af" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solars_out" + }, /obj/structure/cable/yellow{ icon_state = "1-2" }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - id_tag = "solars_pump" - }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/plating, /area/ship/trade/maintenance/solars) +"ag" = ( +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/reinforced/airless, +/area/space) "ah" = ( /obj/structure/cable/yellow{ icon_state = "1-8" @@ -25,15 +44,15 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "ai" = ( -/obj/structure/bed/chair/wood, -/turf/simulated/floor/reinforced/airless, +/obj/structure/chair/wood, +/turf/floor/reinforced/airless, /area/space) "aj" = ( /obj/item/newspaper, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "ak" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -43,32 +62,60 @@ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"al" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/maintenance/solars) +"am" = ( +/obj/structure/handrail{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/machinery/button/access/exterior/cabled{ + dir = 1; + id_tag = "solars"; + pixel_y = -22 + }, +/turf/floor/reinforced/airless, +/area/space) +"an" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solars_out" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_ridged, /area/ship/trade/maintenance/solars) "ao" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "ap" = ( -/obj/structure/ladder, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "solars_pump" }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/solars) "aq" = ( -/obj/item/stack/cable_coil/yellow{ - amount = 1; - icon_state = "coil2" +/obj/item/stack/cable_coil/single/yellow, +/turf/floor/plating/airless, +/area/space) +"ar" = ( +/obj/structure/handrail{ + dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/reinforced/airless, /area/space) "as" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -79,16 +126,12 @@ }, /obj/machinery/light/small, /obj/structure/cable{ - icon_state = "4-8"; - d1 = 1; - d2 = 4 + icon_state = "4-8" }, /obj/structure/cable{ - icon_state = "1-8"; - d1 = 1; - d2 = 4 + icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "at" = ( /obj/machinery/atmospherics/portables_connector{ @@ -96,230 +139,463 @@ }, /obj/machinery/portable_atmospherics/canister/air/airlock, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, +/obj/structure/sign/warning/airlock{ + pixel_y = 32 + }, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "au" = ( /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "av" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + dir = 8; + id_tag = "solars"; + tag_airpump = "solars_pump"; + tag_chamber_sensor = "solars_sensor"; + tag_exterior_door = "solars_out"; + tag_interior_door = "solars_in"; + pixel_x = 22 }, -/obj/machinery/power/apc, /obj/structure/cable{ - d2 = 8; - icon_state = "0-8" + icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/maintenance/solars) +"aw" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/reinforced/airless, +/area/space) "ax" = ( -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "ay" = ( /obj/item/solar_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, +/area/space) +"az" = ( +/obj/structure/cable/yellow{ + icon_state = "4-10" + }, +/turf/floor/reinforced/airless, /area/space) +"aA" = ( +/obj/machinery/airlock_sensor{ + dir = 4; + id_tag = "solars_sensor"; + pixel_x = -18; + pixel_y = -8 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/maintenance/solars) "aB" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable{ - icon_state = "0-2"; - d1 = 1; - d2 = 4 + icon_state = "0-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aC" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solars_in" + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_ridged, +/area/ship/trade/maintenance/solars) +"aD" = ( +/obj/machinery/door/airlock/external/bolted{ + id_tag = "solars_in" }, -/turf/simulated/floor/plating, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aE" = ( +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/button/access/interior{ + id_tag = "solars"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aF" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "aG" = ( /obj/structure/closet/crate/solar, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "aH" = ( -/obj/structure/handrai, -/turf/simulated/floor/reinforced/airless, +/obj/structure/handrail, +/turf/floor/reinforced/airless, /area/space) "aI" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/item/solar_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) +"aJ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) "aK" = ( -/obj/effect/landmark/map_data{ +/obj/abstract/map_data{ height = 4 }, /turf/space, /area/space) "aL" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 8 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aM" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "aN" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/comms) +"aO" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aP" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aQ" = ( +/obj/structure/railing/mapped, +/obj/effect/floor_decal/industrial/warning, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) "aR" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "aS" = ( -/obj/structure/catwalk, -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 8 +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 8; + icon_state = "warningcorner" }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" }, -/turf/simulated/open, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "aT" = ( /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/item/solar_assembly, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) +"aU" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) "aV" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/maintenance/solars) "aW" = ( /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) -"bb" = ( -/obj/structure/sign/warning/airlock, -/obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +"aX" = ( +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aY" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"aZ" = ( +/obj/structure/railing/mapped{ + dir = 1 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 1; + icon_state = "warning" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"ba" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1; + icon_state = "warningcorner" + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"bc" = ( +/obj/machinery/door/firedoor, +/obj/structure/sign/warning/fall{ + pixel_x = 34; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "bd" = ( -/obj/item/stack/material/glass/ten, -/turf/simulated/floor/airless, +/obj/item/stack/material/pane/mapped/glass/ten, +/turf/floor/plating/airless, /area/space) +"be" = ( +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) "bf" = ( /obj/machinery/atmospherics/pipe/zpipe/down/supply, /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers, /obj/structure/cable{ - d1 = 32; - d2 = 2; - dir = 2; icon_state = "32-2" }, /obj/structure/lattice, -/turf/simulated/open, +/turf/open, +/area/ship/trade/maintenance/solars) +"bg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"bh" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"bi" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8; + level = 2 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"bj" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/apc{ + pixel_y = -22 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"bk" = ( +/obj/structure/ladder, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/ship/trade/maintenance/solars) +"bl" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -32 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "br" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "bE" = ( /obj/effect/floor_decal/steeldecal/steel_decals6, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "cB" = ( /obj/structure/girder, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) "cO" = ( /obj/structure/grille/broken, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) +"dm" = ( +/obj/abstract/level_data_spawner/tradeship_upper, +/turf/space, +/area/space) "dq" = ( /obj/structure/cable/yellow{ icon_state = "6-9" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "ds" = ( /obj/machinery/network/router{ initial_network_id = "tradenet" }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/ship/trade/comms) -"eX" = ( -/turf/space, -/turf/simulated/open, -/area/space) "fi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "gb" = ( /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "gw" = ( /obj/item/caution/cone, /obj/structure/cable{ - icon_state = "1-8"; - d1 = 1; - d2 = 4 + icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -327,59 +603,56 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) -"gx" = ( -/obj/structure/railing/mapped, -/obj/effect/floor_decal/industrial/warning, -/obj/structure/cable/yellow{ - icon_state = "1-8" - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) "gY" = ( /obj/structure/cable/yellow{ icon_state = "6-9" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) -"hp" = ( -/obj/structure/catwalk, -/obj/effect/floor_decal/industrial/warning, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) +"hJ" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/ship/trade/bridge_unused) "iz" = ( /obj/structure/cable/yellow{ icon_state = "5-10" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "jv" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) "jy" = ( /obj/machinery/constructable_frame/computerframe{ - icon_state = "unwired"; dir = 4 }, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "jz" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/comms) "jJ" = ( /obj/machinery/door/airlock/hatch/autoname/command, @@ -390,62 +663,38 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/comms) -"kF" = ( -/obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/machinery/portable_atmospherics/canister/air/airlock, -/obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; - dir = 4 - }, -/obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) -"kL" = ( -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge_upper) -"ma" = ( -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ - id_tag = "solars"; - pixel_x = 25; - pixel_y = -4; - tag_airpump = "solars_pump"; - tag_chamber_sensor = "solars_sensor"; - tag_exterior_door = "solars_out"; - tag_interior_door = "solars_in" - }, -/obj/structure/cable/yellow{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/solars) +"mn" = ( +/turf/floor/tiled/dark, +/area/ship/trade/bridge_unused) "mV" = ( /obj/structure/cable/yellow{ icon_state = "2-9" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "mW" = ( /obj/item/mollusc/barnacle{ - pixel_w = -17 + pixel_x = -17 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "ne" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/bridge_unused) +"ng" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ship/trade/comms) "nZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 @@ -454,101 +703,75 @@ dir = 10 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "oq" = ( /obj/random/trash, -/obj/machinery/power/apc{ - dir = 8 +/obj/machinery/apc{ + dir = 8; + pixel_x = -22 }, /obj/structure/cable{ - icon_state = "0-2"; - d1 = 1; - d2 = 4 + icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) -"oE" = ( -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 4 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) "oY" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 }, -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) +"pt" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/monotile, +/area/ship/trade/command/bridge_upper) "pC" = ( /obj/item/wrench, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) -"qw" = ( -/obj/machinery/light_switch{ - pixel_z = 0; - pixel_w = 24 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) "rl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "sx" = ( /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ icon_state = "1-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "sX" = ( /obj/machinery/door/window/westleft, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -557,137 +780,98 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/comms) +"tu" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/apc{ + dir = 1; + name = "Communications APC"; + pixel_y = 22 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/light_switch{ + pixel_x = 24; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/comms) "tJ" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/command/bridge_upper) -"uM" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "solars_in" - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/structure/cable/yellow{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/maintenance/solars) "uT" = ( -/obj/random/shoes, -/obj/machinery/alarm{ - dir = 1; - icon_state = "alarm0"; - pixel_x = 0; - pixel_y = -24 - }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) "vi" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) -"vC" = ( -/obj/machinery/door/firedoor, -/obj/structure/sign/warning/fall{ - pixel_w = 32 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) "wc" = ( /obj/effect/floor_decal/steeldecal/steel_decals6, -/obj/machinery/power/apc{ - dir = 1 +/obj/machinery/apc{ + dir = 1; + pixel_y = 22 }, /obj/structure/cable{ icon_state = "0-2"; - pixel_y = 1; - d2 = 2 + pixel_y = 1 }, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 + pixel_x = 24 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "wf" = ( /obj/structure/cable/yellow{ icon_state = "6-8" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "wq" = ( -/obj/item/stack/material/rods, -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/plating, /area/ship/trade/bridge_unused) -"xe" = ( -/obj/structure/catwalk, -/obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 - }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 4 +"xr" = ( +/obj/random/shoes, +/obj/machinery/alarm{ + dir = 1; + pixel_y = -24 }, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) +/turf/floor/plating, +/area/ship/trade/bridge_unused) "yp" = ( -/obj/item/ore/iron, -/turf/simulated/floor/reinforced/airless, +/obj/item/stack/material/ore/iron, +/turf/floor/reinforced/airless, /area/space) -"yt" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "solars_out" - }, -/obj/structure/cable/yellow{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/steel_ridged, -/area/ship/trade/maintenance/solars) "yA" = ( /obj/machinery/alarm{ dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 - }, -/obj/item/radio/intercom{ - dir = 1; - pixel_y = -30 - }, /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/comms) -"yQ" = ( -/obj/machinery/airlock_sensor{ - id_tag = "solars_sensor"; - pixel_x = -25 - }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 8 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/solars) -"zh" = ( -/obj/structure/catwalk, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 - }, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) +"yM" = ( +/obj/item/stack/material/rods/mapped/steel, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/plating, +/area/ship/trade/bridge_unused) "zn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 @@ -695,83 +879,73 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) "zH" = ( /obj/structure/cable/yellow{ icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "zY" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/bridge_unused) "Al" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) -"BD" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8; - level = 2 +"AK" = ( +/obj/machinery/network/mainframe{ + initial_network_id = "tradenet" }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) +/turf/floor/bluegrid, +/area/ship/trade/comms) "Db" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/bridge_unused) -"Dl" = ( -/obj/item/mollusc/barnacle{ - pixel_x = 0 +"Dg" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/simulated/floor/reinforced/airless, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/ship/trade/bridge_unused) +"Dl" = ( +/obj/item/mollusc/barnacle, +/turf/floor/reinforced/airless, /area/space) "Dr" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, -/area/ship/trade/comms) +/turf/floor/reinforced/airless, +/area/ship/trade/bridge_unused) "DP" = ( /obj/structure/cable/yellow{ icon_state = "2-5" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "DY" = ( /obj/machinery/door/airlock/hatch/autoname/command, /obj/structure/cable{ - icon_state = "4-8"; - d1 = 1; - d2 = 4 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 @@ -780,278 +954,163 @@ dir = 4 }, /obj/machinery/door/firedoor, -/obj/item/taperoll/engineering/applied, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/tape_barricade/engineering, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/bridge_unused) -"DZ" = ( -/turf/simulated/floor/tiled/techfloor/grid, -/area/ship/trade/maintenance/solars) +"EO" = ( +/obj/machinery/computer/message_monitor{ + dir = 1 + }, +/turf/floor/bluegrid, +/area/ship/trade/comms) "Fe" = ( /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "FY" = ( /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "GP" = ( -/turf/simulated/open, -/area/ship/trade/maintenance/solars) -"Hh" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "solars_in" - }, -/obj/machinery/button/access/interior{ - pixel_x = -24; - pixel_y = -1; - id_tag = "solars" - }, -/turf/space, +/turf/open, /area/ship/trade/maintenance/solars) "HN" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled/monotile, -/area/ship/trade/command/bridge_upper) -"IY" = ( -/obj/structure/cable/yellow{ - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) -"Jf" = ( -/obj/structure/catwalk, -/obj/structure/railing/mapped, -/obj/effect/floor_decal/industrial/warning, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) -"Jm" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "Jo" = ( -/obj/machinery/message_server, -/turf/simulated/floor/bluegrid, +/obj/machinery/network/message_server, +/turf/floor/bluegrid, /area/ship/trade/comms) -"Ko" = ( -/obj/structure/catwalk, -/obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 1 - }, -/obj/machinery/light/small{ - icon_state = "bulb_map"; - dir = 4 - }, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) "Ks" = ( /obj/item/mollusc/barnacle{ pixel_x = -14 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "KG" = ( /obj/structure/cable/yellow{ icon_state = "5-10" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "KK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/light_switch{ - pixel_x = 32 - }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge_upper) -"KS" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1; - level = 2 + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/tiled/dark, +/area/ship/trade/command/bridge_upper) +"KS" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/plating, /area/ship/trade/bridge_unused) "Lf" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 2 + icon_state = "warningcorner" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/light/small{ - icon_state = "bulb_map"; dir = 8 }, /obj/structure/sign/warning/fall{ - pixel_z = 0; - pixel_w = -32 + pixel_x = -34; + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) -"Mk" = ( -/obj/structure/catwalk, -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 8 +"Ll" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1; + level = 2 }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) -"MD" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/plating, -/area/ship/trade/command/bridge_upper) -"Nc" = ( -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/turf/simulated/floor/airless, -/area/ship/trade/command/bridge_upper) +/turf/floor/tiled/techfloor/grid, +/area/ship/trade/comms) "NY" = ( /obj/item/mollusc/barnacle{ - pixel_w = 16 + pixel_x = 16 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "Ob" = ( /obj/effect/paint/brown, -/turf/simulated/wall/r_wall/hull, +/turf/wall/r_wall/hull, /area/ship/trade/comms) -"Oy" = ( -/obj/structure/cable/yellow{ - icon_state = "4-10" - }, -/turf/simulated/floor/airless, -/area/space) "Pg" = ( -/obj/item/chems/glass/paint/yellow, +/obj/item/chems/glass/bucket/paint/yellow, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 4 + dir = 4; + icon_state = "warningcorner" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/light/small{ - icon_state = "bulb_map"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) "PJ" = ( /obj/machinery/door/firedoor, /obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/command/bridge_upper) "PZ" = ( -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "QK" = ( -/obj/machinery/door/blast/regular{ - density = 0; +/obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/ship/trade/comms) "Rg" = ( /obj/structure/cable/yellow, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) -"Rk" = ( -/obj/machinery/door/airlock/external/bolted{ - id_tag = "solars_out" - }, -/obj/machinery/button/access/exterior{ - id_tag = "solars"; - pixel_x = -24; - pixel_y = -1 - }, -/turf/space, -/area/ship/trade/maintenance/solars) "RZ" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; @@ -1064,221 +1123,138 @@ /obj/machinery/alarm{ pixel_y = 17 }, -/turf/simulated/floor/tiled/monotile, +/turf/floor/tiled/monotile, /area/ship/trade/command/bridge_upper) "Sc" = ( /obj/structure/cable/yellow{ icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "Su" = ( -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/ship/trade/comms) -"SC" = ( -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - icon_state = "map-scrubbers"; - dir = 1 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/turf/simulated/floor/tiled/dark, -/area/ship/trade/command/bridge_upper) -"SO" = ( -/obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) "SQ" = ( /obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; +/obj/machinery/door/blast/regular/open{ id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 + name = "External Blast Doors" }, /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/command/bridge_upper) "Tt" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "Tx" = ( -/obj/machinery/network/mainframe{ - initial_network_id = "tradenet" +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + dir = 2; + id_tag = "scraplock"; + name = "External Blast Doors" }, -/turf/simulated/floor/bluegrid, +/turf/floor/plating, /area/ship/trade/comms) "Ua" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) -"Ux" = ( -/obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) -"UT" = ( -/obj/structure/catwalk, -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 1 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 +"Uq" = ( +/obj/machinery/alarm{ + dir = 1; + pixel_y = -32 }, -/turf/simulated/open, -/area/ship/trade/maintenance/solars) +/obj/machinery/commsrelay, +/turf/floor/bluegrid, +/area/ship/trade/comms) +"UX" = ( +/obj/effect/shuttle_landmark/automatic, +/turf/space, +/area/space) "UY" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/firealarm{ dir = 8; - pixel_x = -24; - pixel_y = 0 + pixel_x = -24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) -"We" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 - }, -/obj/machinery/alarm{ - dir = 1; - icon_state = "alarm0"; - pixel_x = 0; - pixel_y = -32 +"Vp" = ( +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" }, -/turf/simulated/floor/plating, -/area/ship/trade/maintenance/solars) +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/ship/trade/bridge_unused) "Xb" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/ship/trade/command/bridge_upper) "Xu" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "XF" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/bridge_unused) "XQ" = ( -/obj/machinery/door/airlock/multi_tile/engineering, +/obj/machinery/door/airlock/double/engineering, /obj/machinery/door/firedoor, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/ship/trade/maintenance/solars) -"Yq" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 1 - }, -/obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/reinforced/airless, -/area/space) "YA" = ( /obj/machinery/door/airlock/hatch/autoname/command, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2"; - pixel_y = 0 + icon_state = "1-2" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/command/bridge_upper) "Zx" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, -/turf/simulated/floor/reinforced/airless, +/turf/floor/reinforced/airless, /area/space) "ZD" = ( -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/obj/machinery/power/apc{ - dir = 1; - name = "Communications APC" +/obj/structure/window/reinforced{ + dir = 8 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 - }, -/obj/machinery/light_switch{ - pixel_x = 32 + icon_state = "1-2" }, -/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/firealarm{ dir = 4; - pixel_x = 24; - pixel_y = 0 - }, -/obj/structure/window/reinforced{ - dir = 8 + pixel_x = 24 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/ship/trade/comms) "ZT" = ( /obj/structure/ladder, @@ -1289,29 +1265,23 @@ dir = 1 }, /obj/structure/cable{ - d1 = 32; - d2 = 1; icon_state = "32-1" }, /obj/machinery/light{ dir = 4 }, /obj/machinery/light_switch{ - pixel_x = 32 + pixel_x = 24; + dir = 8 }, -/turf/simulated/floor/tiled/monotile, +/obj/structure/lattice, +/turf/open, /area/ship/trade/command/bridge_upper) "ZU" = ( -/obj/machinery/alarm{ - dir = 1; - icon_state = "alarm0"; - pixel_x = 0; - pixel_y = -32 - }, -/obj/machinery/computer/message_monitor{ - dir = 4 +/obj/machinery/network/telecomms_hub{ + initial_network_id = "tradenet" }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/ship/trade/comms) (1,1,1) = {" @@ -1718,7 +1688,7 @@ aa aa aa aa -aa +dm aa aa aa @@ -2414,7 +2384,7 @@ aa aa aa aa -aa +UX aa aa aa @@ -3241,8 +3211,8 @@ aa aa aa aa -eX -eX +aa +aa ax ax ax @@ -3322,8 +3292,8 @@ aa aa aa aa -eX -eX +aa +aa ax ax ax @@ -3404,7 +3374,7 @@ aa aa aa aa -eX +aa ax ax ax @@ -3646,22 +3616,22 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa ax -aa ax -aa -aa -aa -aa -aa -ac +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax ax ax ax @@ -3897,8 +3867,8 @@ ax ax ax yp -ax DP +aw zH Rg ae @@ -3978,8 +3948,8 @@ Ks ax ax ax -ae iz +ae ax bd ae @@ -4034,17 +4004,17 @@ aa aa aa aa -aa -aa -aa -aa -aa Ob Ob QK +QK Ob ax -aa +ax +ax +ax +ax +ax ax ax ax @@ -4059,8 +4029,8 @@ ax ax ax ax -ax -iz +KG +ae ax ax ax @@ -4114,19 +4084,14 @@ aa aa aa aa -aa -aa -aa -aa -ax -ax +Ob Ob jz jz aN +aN jz Ob -ac ax ax ax @@ -4137,14 +4102,19 @@ ax ax ax ax -ae ax ax ax +ax +ax +ae +ax +ax KG ax ax ax +ax NY vi aV @@ -4154,6 +4124,7 @@ aV vi ax ax +ax aV au au @@ -4168,7 +4139,6 @@ ax ax ax ax -ax aa aa aa @@ -4195,20 +4165,15 @@ aa aa aa aa -aa -aa -aa -aa -aa -ax -ax Ob -jz +Ob +Ob +AK ds Jo ZU +Uq Ob -ac ax ax ax @@ -4222,7 +4187,12 @@ ax ax ax ax -Oy +ax +ax +ax +ax +az +ae ax ax ax @@ -4236,6 +4206,7 @@ aV aV aV ax +ax aV bf ak @@ -4245,7 +4216,6 @@ ax ax ax ax -ax Dl ax ax @@ -4278,19 +4248,18 @@ aa aa aa aa -aa -aa -aa -aa -aa -ax -Ob -jz +ad Tx Su Su -Dr -ac +Su +Su +EO +ng +ax +ax +ax +ax ax ax ax @@ -4308,6 +4277,7 @@ Tt ax ax ax +ax aV aV Lf @@ -4318,6 +4288,7 @@ FY Pg aV ax +ax aV aB as @@ -4332,7 +4303,6 @@ ax ax ax ax -ax aa aa aa @@ -4359,40 +4329,40 @@ aa aa aa aa -aa -aa -ax -ax -ax -ax -ax Ob -jz +Ob +Ob +tu ZD sX yA -Ob +Ll tJ tJ SQ +SQ tJ tJ ax -aa -aa -aa ax ax ax ax ax -Yq +ax +ax +ax +ax +ax +ax +Tt +ar aV au aV aV -kF -gx +aE +aM GP GP GP @@ -4401,8 +4371,9 @@ Fe aV aV aV +aV aL -av +bj aV ax ax @@ -4414,7 +4385,6 @@ ax ax ax ax -ax aa aa aa @@ -4442,12 +4412,7 @@ aa aa aa ac -ac -ax -ax -ax -ax -ax +Ob Ob jz jz @@ -4457,6 +4422,7 @@ jz Xb RZ HN +PZ bE SQ ax @@ -4468,23 +4434,28 @@ ax ax ax ax -Tt -Rk -DZ -yQ -Hh -SO -Ux +ax +ax +ax +Xu +aw +af +al +aA +aD +aF +aO GP GP GP GP Al XQ +aR UY aR ah -ap +bk aV ax ax @@ -4494,7 +4465,6 @@ ax ax ax ax -ax ai ax aa @@ -4525,21 +4495,17 @@ aa aa aa aa -ax -ax -ax -ax -ax -Nc -MD -kL -SC -Jm +ab +mn +mn +hJ +Dg KK YA rl fi PZ +PZ PJ ax ax @@ -4550,23 +4516,28 @@ ax ax ax ax -Xu -yt -af -ma -uM -IY -hp +ax +ax +ax +Tt +ag +an +ap +av +aC +aJ +aP GP GP GP GP -zh -vC -qw -oE -BD -We +aY +bc +be +bg +bh +bi +bl aV aH ax @@ -4576,7 +4547,6 @@ ax ax ax ax -ax aj ax aa @@ -4605,13 +4575,8 @@ aa aa aa aa -aa ac -ax -ax -ax -ax -ax +zY zY ne ne @@ -4621,6 +4586,7 @@ ne Xb wc nZ +pt ZT SQ ax @@ -4632,18 +4598,23 @@ ax ax ax ax -Yq +ax +ax +ax +Tt +am aV au aV -bb +aV at -Jf +aQ GP GP GP GP -UT +aZ +aV aV aV aV @@ -4660,7 +4631,6 @@ ax ax ax ax -ax aa aa aa @@ -4687,28 +4657,27 @@ aa aa aa aa -aa -aa -ax -ax -ax -ax -ax zY -ne +zY +zY +uT oq gw uT -zY +xr tJ tJ SQ +SQ tJ tJ ax -aa -aa -aa +ax +ax +ax +ax +ax +ax ax ax ax @@ -4717,22 +4686,23 @@ ax br ax ax +ax mW aV aV -xe -Mk -aS aS -Mk -Ko +aU +aX +aX +aU +ba aV ax ax ax ax -mW ax +mW ax ax ax @@ -4770,19 +4740,18 @@ aa aa aa aa -aa -aa -aa -aa -aa -ax -zY -ne +Dr +ab +yM wq zn KS oY -aa +Vp +ax +ax +ax +ax ax ax ax @@ -4801,6 +4770,7 @@ ax ax ax ax +ax aV aV aV @@ -4851,20 +4821,19 @@ aa aa aa aa -aa -aa -aa -aa -aa -ax -ax +zY +zY zY cB cO XF +uT XF zY -ac +ax +ax +ax +ax ax ax ax @@ -4884,6 +4853,7 @@ ax ax ax ax +ax Zx aV au @@ -4934,19 +4904,18 @@ aa aa aa aa -aa -aa -aa -aa -ax -ax +zY zY ne ne jv +jv cB zY -ac +ax +ax +ax +ax ax ax ax @@ -4963,6 +4932,7 @@ ax ax ax gY +ae ax ae ax @@ -5018,17 +4988,17 @@ aa aa aa aa -aa -aa -aa -aa -aa zY zY Db +Db zY ax -aa +ax +ax +ax +ax +ax ax ax ax @@ -5044,9 +5014,9 @@ ax ax ax ax -ax dq ax +ax aI aI ae @@ -5067,7 +5037,8 @@ ax ax ax ax -ac +ax +ax ac aa aa @@ -5084,7 +5055,6 @@ aa aa aa aa -aa "} (47,1,1) = {" aa @@ -5127,8 +5097,8 @@ ax ax ax ax -ax mV +aw Sc Sc Rg @@ -5149,6 +5119,8 @@ ax ax ax ax +ax +ax ac aa aa @@ -5165,8 +5137,6 @@ aa aa aa aa -aa -aa "} (48,1,1) = {" aa @@ -5230,9 +5200,9 @@ ax ax ax ax -aa -aa -aa +ax +ax +ax aa aa aa @@ -5311,10 +5281,10 @@ ax ax Dl ax -aa -aa -aa -aa +ax +ax +ax +ax aa aa aa @@ -5385,17 +5355,17 @@ ax ax ax ax -ac -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax aa aa aa @@ -5450,34 +5420,34 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa ax -aa ax -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax +ax aa aa aa @@ -5549,15 +5519,15 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +ax +ax +ax +ax +ax +ax +ax +ax +ax aa aa aa @@ -5617,8 +5587,8 @@ aa aa aa aa -eX -eX +aa +aa ax ax ax @@ -5700,7 +5670,7 @@ aa aa aa aa -eX +aa ax ax ax @@ -5782,8 +5752,8 @@ aa aa aa aa -eX -eX +aa +aa ax ax ax @@ -6697,7 +6667,7 @@ aa aa aa aa -aa +UX aa aa aa diff --git a/maps/tradeship/tradeship.dm b/maps/tradeship/tradeship.dm index c1951b3a2930..28f3b208c5a1 100644 --- a/maps/tradeship/tradeship.dm +++ b/maps/tradeship/tradeship.dm @@ -1,14 +1,87 @@ #if !defined(USING_MAP_DATUM) - #include "../../mods/corporate/_corporate.dme" - #include "../../mods/ascent/_ascent.dme" + #ifdef UNIT_TEST + #include "../../code/unit_tests/offset_tests.dm" + #endif + + #include "../../mods/content/tabloids/_tabloids.dme" + + #include "../random_ruins/exoplanet_ruins/playablecolony/playablecolony.dm" + + #include "../../mods/content/government/away_sites/icarus/icarus.dm" + #include "../../mods/content/corporate/away_sites/lar_maria/lar_maria.dm" + + #include "../../mods/content/mundane.dm" + #include "../../mods/content/scaling_descriptors.dm" + + #include "../../mods/content/plant_dissection/_plant_dissection.dme" + + #include "../../mods/content/augments/_augments.dme" + #include "../../mods/content/beekeeping/_beekeeping.dme" + #include "../../mods/content/bigpharma/_bigpharma.dme" + #include "../../mods/content/blob/_blob.dme" + #include "../../mods/content/breath_holding/_breath_holding.dme" + #include "../../mods/content/corporate/_corporate.dme" + #include "../../mods/content/dungeon_loot/_dungeon_loot.dme" + #include "../../mods/content/government/_government.dme" + #include "../../mods/content/integrated_electronics/_integrated_electronics.dme" + #include "../../mods/content/matchmaking/_matchmaking.dme" + #include "../../mods/content/modern_earth/_modern_earth.dme" + #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" + #include "../../mods/content/pheromones/_pheromones.dme" + #include "../../mods/content/psionics/_psionics.dme" + #include "../../mods/content/sealant_gun/_sealant_gun.dme" + #include "../../mods/content/standard_jobs/_standard_jobs.dme" + #include "../../mods/content/supermatter/_supermatter.dme" + #include "../../mods/content/ventcrawl/_ventcrawl.dme" + #include "../../mods/content/xenobiology/_xenobiology.dme" + #include "../../mods/content/exploration/_exploration.dme" + + #include "../../mods/gamemodes/cult/_cult.dme" + #include "../../mods/gamemodes/heist/_heist.dme" + #include "../../mods/gamemodes/mercenary/_mercenary.dme" + #include "../../mods/gamemodes/ninja/_ninja.dme" + #include "../../mods/gamemodes/revolution/_revolution.dme" + #include "../../mods/gamemodes/spyvspy/_spyvspy.dme" + #include "../../mods/gamemodes/traitor/_traitor.dme" + #include "../../mods/gamemodes/mixed.dm" + + #include "../../mods/mobs/borers/_borers.dme" + #include "../../mods/mobs/dionaea/_dionaea.dme" + + #include "../../mods/species/ascent/_ascent.dme" + #include "../../mods/species/tajaran/_tajaran.dme" + #include "../../mods/species/unathi/_unathi.dme" + #include "../../mods/species/skrell/_skrell.dme" + #include "../../mods/species/adherent/_adherent.dme" + #include "../../mods/species/tritonian/_tritonian.dme" + #include "../../mods/species/drakes/_drakes.dme" + #include "../../mods/species/neoavians/_neoavians.dme" + #include "../../mods/species/serpentid/_serpentid.dme" + #include "../../mods/species/utility_frames/_utility_frames.dme" + #include "../../mods/species/vox/_vox.dme" + + #include "../away/bearcat/bearcat.dm" + #include "../away/casino/casino.dm" + #include "../away/derelict/derelict.dm" + #include "../away/errant_pisces/errant_pisces.dm" + #include "../away/lost_supply_base/lost_supply_base.dm" + #include "../away/magshield/magshield.dm" + #include "../away/mining/mining.dm" + #include "../away/mobius_rift/mobius_rift.dm" + #include "../away/smugglers/smugglers.dm" + #include "../away/unishi/unishi.dm" + #include "../away/yacht/yacht.dm" + #include "../away/liberia/liberia.dm" #include "tradeship_antagonists.dm" #include "tradeship_areas.dm" #include "tradeship_documents.dm" #include "tradeship_jobs.dm" + #include "tradeship_levels.dm" #include "tradeship_loadouts.dm" #include "tradeship_overmap.dm" + #include "tradeship_overrides.dm" #include "tradeship_shuttles.dm" #include "tradeship_spawnpoints.dm" #include "tradeship_unit_testing.dm" @@ -17,29 +90,19 @@ #include "tradeship-2.dmm" #include "tradeship-3.dmm" - #include "jobs/_jobs.dm" + #include "jobs/_goals.dm" + #include "jobs/civilian.dm" #include "jobs/command.dm" #include "jobs/engineering.dm" #include "jobs/medical.dm" #include "jobs/science.dm" + #include "outfits/_outfits.dm" #include "outfits/command.dm" #include "outfits/engineering.dm" #include "outfits/medical.dm" #include "outfits/science.dm" - #include "../away/mining/mining.dm" - #include "../away/derelict/derelict.dm" - #include "../away/bearcat/bearcat.dm" - #include "../away/lost_supply_base/lost_supply_base.dm" - #include "../away/smugglers/smugglers.dm" - #include "../away/casino/casino.dm" - #include "../away/magshield/magshield.dm" - #include "../away/slavers/slavers_base.dm" - #include "../away/mobius_rift/mobius_rift.dm" - #include "../away/errant_pisces/errant_pisces.dm" - #include "../away/unishi/unishi.dm" - #define USING_MAP_DATUM /datum/map/tradeship #elif !defined(MAP_OVERRIDE) diff --git a/maps/tradeship/tradeship_antagonists.dm b/maps/tradeship/tradeship_antagonists.dm index 6bafd854db76..ef19642550db 100644 --- a/maps/tradeship/tradeship_antagonists.dm +++ b/maps/tradeship/tradeship_antagonists.dm @@ -1,31 +1,29 @@ -/datum/antagonist +/decl/special_role initial_spawn_req = 1 initial_spawn_target = 1 -/datum/antagonist/borer - initial_spawn_req = 1 - initial_spawn_target = 1 - -/datum/antagonist/mercenary +/decl/special_role/mercenary initial_spawn_req = 1 initial_spawn_target = 2 -/datum/antagonist/raider +/decl/special_role/raider initial_spawn_req = 1 initial_spawn_target = 2 -/datum/antagonist/cultist +/decl/special_role/cultist initial_spawn_req = 1 initial_spawn_target = 2 - -/datum/antagonist/renegade + +/decl/special_role/renegade initial_spawn_req = 1 initial_spawn_target = 2 -/datum/antagonist/loyalist +/decl/special_role/loyalist initial_spawn_req = 1 initial_spawn_target = 2 + command_department_id = /decl/department/command -/datum/antagonist/revolutionary +/decl/special_role/revolutionary initial_spawn_req = 1 - initial_spawn_target = 2 \ No newline at end of file + initial_spawn_target = 2 + command_department_id = /decl/department/command diff --git a/maps/tradeship/tradeship_areas.dm b/maps/tradeship/tradeship_areas.dm index bfa53d48a4df..1d46436626ce 100644 --- a/maps/tradeship/tradeship_areas.dm +++ b/maps/tradeship/tradeship_areas.dm @@ -1,7 +1,19 @@ +/datum/event/prison_break/medical + areaType = list(/area/ship/trade/crew/medbay) + +/datum/event/prison_break/science + areaType = list(/area/ship/trade/livestock) + +/datum/event/prison_break/station + areaType = list(/area/ship/trade/drunk_tank) + /area/ship/trade - name = "\improper Generic Ship" + name = "\improper Tradeship" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') +/area/ship/trade + holomap_color = HOLOMAP_AREACOLOR_CREW + /area/ship/trade/crew name = "\improper Crew Compartements" icon_state = "crew_quarters" @@ -43,42 +55,66 @@ name = "\improper Medical Bay" icon_state = "medbay" area_flags = AREA_FLAG_RAD_SHIELDED + holomap_color = HOLOMAP_AREACOLOR_MEDICAL /area/ship/trade/cargo name = "\improper Cargo Hold" icon_state = "quartstorage" area_flags = AREA_FLAG_RAD_SHIELDED + holomap_color = HOLOMAP_AREACOLOR_CARGO /area/ship/trade/cargo/lower name = "Loading Bay" + area_flags = AREA_FLAG_RAD_SHIELDED /area/ship/trade/dock name = "\improper Docking Bay" icon_state = "entry_1" - + holomap_color = HOLOMAP_AREACOLOR_AIRLOCK /area/ship/trade/aft_port_underside_maint name = "\improper Underside - Aft Port Maintenance" icon_state = "medbay" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_MAINTENANCE + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE /area/ship/trade/aft_starboard_underside_maint name = "\improper Underside - Aft Starboard Maintenance" icon_state = "toilet" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_MAINTENANCE + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE /area/ship/trade/loading_bay name = "\improper Underside - Loading Bay" icon_state = "entry_1" + holomap_color = HOLOMAP_AREACOLOR_AIRLOCK /area/ship/trade/fore_port_underside_maint name = "\improper Underside - Fore Port Maintenance" icon_state = "green" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_MAINTENANCE + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE + +/area/ship/trade/livestock + name = "\improper Underside - Livestock Handling" + icon_state = "red" + req_access = list(access_xenobiology) + holomap_color = HOLOMAP_AREACOLOR_SCIENCE /area/ship/trade/fore_starboard_underside_maint name = "\improper Underside - Fore Starboard Maintenance" icon_state = "locker" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_MAINTENANCE + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE /area/ship/trade/disused name = "\improper Underside - Disused" icon_state = "yellow" + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE + +/area/ship/trade/undercomms + name = "\improper Underside - Communications Relay" + icon_state = "blue" + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/ship/trade/garden name = "\improper Garden" @@ -89,36 +125,46 @@ icon_state = "yellow" turf_initializer = /decl/turf_initializer/maintenance ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg') + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE /area/ship/trade/hidden name = "\improper Unknown" //shielded compartment icon_state = "auxstorage" + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE /area/ship/trade/escape_port name = "\improper Port Escape Pods" icon_state = "green" + holomap_color = HOLOMAP_AREACOLOR_AIRLOCK /area/ship/trade/escape_star name = "\improper Starboard Escape Pods" icon_state = "yellow" + holomap_color = HOLOMAP_AREACOLOR_AIRLOCK /area/ship/trade/science name = "\improper Research Bay" icon_state = "green" req_access = list(access_research) + holomap_color = HOLOMAP_AREACOLOR_SCIENCE /area/ship/trade/science/fabricaton name = "\improper Fabrication Bay" icon_state = "yellow" + req_access = list(access_research) + holomap_color = HOLOMAP_AREACOLOR_SCIENCE /area/ship/trade/crew/medbay/chemistry name = "\improper Chemistry Bay" icon_state = "cave" req_access = list(access_medical) + holomap_color = HOLOMAP_AREACOLOR_MEDICAL /area/ship/trade/maintenance name = "\improper Maintenance Compartments" icon_state = "amaint" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_MAINTENANCE + holomap_color = HOLOMAP_AREACOLOR_MAINTENANCE /area/ship/trade/maintenance/hallway name = "\improper Maintenance Corridors" @@ -152,17 +198,20 @@ icon_state = "atmos" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambiatm1.ogg') req_access = list(access_engine) + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/ship/trade/maintenance/power name = "\improper Power Compartment" icon_state = "engine_smes" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') req_access = list(access_engine) + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/ship/trade/maintenance/engine icon_state = "engine" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambieng1.ogg') req_access = list(access_engine) + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/ship/trade/maintenance/engine/aft name = "\improper Main Engine Bay" @@ -176,7 +225,6 @@ /area/ship/trade/command/hallway name = "\improper Command Deck" icon_state = "centcom" - req_access = list(access_heads) /area/ship/trade/command/bridge name = "\improper Bridge" @@ -187,12 +235,18 @@ name = "\improper Captain's Quarters" icon_state = "captain" req_access = list(access_captain) + area_flags = AREA_FLAG_RAD_SHIELDED /area/ship/trade/command/fmate name = "\improper First Mate's Office" icon_state = "heads_hop" req_access = list(access_hop) +/area/ship/trade/shieldbay + name = "\improper Auxillary Shield Bay" + icon_state = "engine" + req_access = list(access_engine_equip) + /area/ship/trade/command/bridge_upper name = "\improper Upper Bridge" icon_state = "blue" @@ -202,6 +256,7 @@ name = "\improper Communications Relay" icon_state = "tcomsatcham" ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/signal.ogg','sound/ambience/sonar.ogg') + holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/ship/trade/bridge_unused name = "\improper Bridge Starboard Storage" @@ -210,53 +265,65 @@ /area/ship/trade/shuttle area_flags = AREA_FLAG_RAD_SHIELDED -/area/ship/trade/shuttle/outgoing - name = "\improper Exploration Shuttle" +/area/ship/trade/shuttle/outgoing/general + name = "\improper Bee" + icon_state = "away" + +/area/ship/trade/shuttle/outgoing/engineering + name = "\improper Bee Skiff Engineering Compartment" + icon_state = "yellow" + +/area/ship/trade/shuttle/rescue + name = "\improper Rescue Shuttle" icon_state = "tcomsatcham" /area/ship/trade/maintenance/solars name = "\improper Solar Array Access" icon_state = "SolarcontrolA" req_access = list(access_engine) + holomap_color = HOLOMAP_AREACOLOR_AIRLOCK -/area/ship/trade/maintenance/robot - name = "\improper Robot Storage" +/area/ship/trade/artifact_storage + name = "\improper Artifact Storage" icon_state = "ai_cyborg" + req_access = list(access_xenoarch) + holomap_color = HOLOMAP_AREACOLOR_SCIENCE /area/ship/trade/drunk_tank name = "Drunk Tank" icon_state = "brig" req_access = list(access_brig) - area_flags = AREA_FLAG_RAD_SHIELDED + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_SECURITY + holomap_color = HOLOMAP_AREACOLOR_SECURITY /area/turbolift name = "\improper Cargo Elevator" icon_state = "shuttle" requires_power = 0 - dynamic_lighting = 1 + dynamic_lighting = TRUE sound_env = STANDARD_STATION area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED ambience = list('sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg') arrival_sound = null lift_announce_str = null -/area/turbolift/alert_on_fall(var/mob/living/carbon/human/H) +/area/turbolift/alert_on_fall(var/mob/living/human/H) if(H.client && SSpersistence.elevator_fall_shifts > 0) SSwebhooks.send(WEBHOOK_ELEVATOR_FALL, list("text" = "We managed to make it [SSpersistence.elevator_fall_shifts] shift\s without someone falling down an elevator shaft.")) SSpersistence.elevator_fall_shifts = -1 /area/turbolift/tradeship_enclave name = "Disused Sublevel" - base_turf = /turf/simulated/floor + base_turf = /turf/floor/plating /area/turbolift/tradeship_cargo name = "Lower Cargo Bay" - base_turf = /turf/simulated/open + base_turf = /turf/open /area/turbolift/tradeship_upper name = "Upper Cargo Bay" - base_turf = /turf/simulated/open + base_turf = /turf/open /area/turbolift/tradeship_roof name = "Solar Array Access" - base_turf = /turf/simulated/open \ No newline at end of file + base_turf = /turf/open \ No newline at end of file diff --git a/maps/tradeship/tradeship_define.dm b/maps/tradeship/tradeship_define.dm index b1a848eba651..970d2506f027 100644 --- a/maps/tradeship/tradeship_define.dm +++ b/maps/tradeship/tradeship_define.dm @@ -4,10 +4,6 @@ path = "tradeship" ground_noun = "deck" - station_levels = list(1, 2, 3, 4) - contact_levels = list(1, 2, 3, 4) - player_levels = list(1, 2, 3, 4) - station_name = "Tradeship Ocelot Alpha" station_short = "Ocelot" @@ -16,14 +12,12 @@ boss_short = "Merchant Admiral" company_name = "Legit Cargo Ltd." company_short = "LC" - overmap_event_areas = 11 - default_law_type = /datum/ai_laws/corporate lobby_screens = list('maps/tradeship/lobby/bloodmoney.png','maps/tradeship/lobby/vapormoney.png') - use_overmap = 1 - num_exoplanets = 3 + overmap_ids = list(OVERMAP_ID_SPACE) + num_exoplanets = 1 welcome_sound = 'sound/effects/cowboysting.ogg' emergency_shuttle_leaving_dock = "Attention all hands: the escape pods have been launched, maintaining burn for %ETA%." - emergency_shuttle_called_message = "Attention all hands: emergency evacuation procedures are now in effect. Escape pods will launch in %ETA%" + emergency_shuttle_called_message = "Attention all hands: emergency evacuation procedures are now in effect. Escape pods will launch in %ETA%." emergency_shuttle_recall_message = "Attention all hands: emergency evacuation sequence aborted. Return to normal operating conditions." evac_controller_type = /datum/evacuation_controller/lifepods @@ -32,7 +26,22 @@ salary_modifier = 0.2 radiation_detected_message = "High levels of radiation have been detected in proximity of the %STATION_NAME%. Please move to a shielded area such as the cargo bay, dormitories or medbay until the radiation has passed." + default_telecomms_channels = list(COMMON_FREQUENCY_DATA) /datum/map/tradeship/get_map_info() return "You're aboard the [station_name], a survey and mercantile vessel affiliated with the Free Trade Union. \ No meaningful authorities can claim the planets and resources in this uncharted sector, so their exploitation is entirely up to you - mine, poach and deforest all you want." + +/datum/map/tradeship/create_trade_hubs() + new /datum/trade_hub/singleton/tradeship + +/datum/trade_hub/singleton/tradeship + name = "Tradehouse Freight Network" + +/datum/trade_hub/singleton/tradeship/get_initial_traders() + return list( + /datum/trader/xeno_shop, + /datum/trader/medical, + /datum/trader/mining, + /datum/trader/books + ) diff --git a/maps/tradeship/tradeship_departments.dm b/maps/tradeship/tradeship_departments.dm new file mode 100644 index 000000000000..277a2ab0ddb2 --- /dev/null +++ b/maps/tradeship/tradeship_departments.dm @@ -0,0 +1,59 @@ +/decl/department/civilian + name = "Civilian" + display_priority = 1 + display_color = "#dddddd" + +/decl/department/engineering + name = "Engineering" + announce_channel = "Engineering" + colour = "#ffa500" + display_priority = 2 + display_color = "#fff5cc" + +/obj/item/robot_module/engineering + associated_department = /decl/department/engineering + +/obj/machinery/network/pager/engineering + department = /decl/department/engineering + +/decl/department/medical + name = "Medical" + goals = list(/datum/goal/department/medical_fatalities) + announce_channel = "Medical" + colour = "#008000" + display_priority = 3 + display_color = "#ffeef0" + +/obj/item/robot_module/medical + associated_department = /decl/department/medical + +/obj/machinery/network/pager/medical + department = /decl/department/medical + +/decl/department/science + name = "Science" + goals = list(/datum/goal/department/extract_slime_cores) + announce_channel = "Science" + colour = "#a65ba6" + display_color = "#e79fff" + +/obj/item/robot_module/research + associated_department = /decl/department/science + +/obj/machinery/network/pager/science + department = /decl/department/science + +/decl/department/command + name = "Command" + colour = "#800080" + display_priority = 4 + display_color = "#ccccff" + goals = list(/datum/goal/department/paperwork/tradeship) + +/obj/machinery/network/pager + department = /decl/department/command + +/decl/department/miscellaneous + name = "Misc" + display_priority = -1 + display_color = "#ccffcc" diff --git a/maps/tradeship/tradeship_jobs.dm b/maps/tradeship/tradeship_jobs.dm index 98abae70320f..71ba7143cc3a 100644 --- a/maps/tradeship/tradeship_jobs.dm +++ b/maps/tradeship/tradeship_jobs.dm @@ -1,37 +1,41 @@ /datum/map/tradeship - default_assistant_title = "Deck Hand" + default_job_type = /datum/job/standard/assistant/tradeship + default_department_type = /decl/department/civilian + default_law_type = /datum/ai_laws/corporate allowed_jobs = list( - /datum/job/tradeship_captain, - /datum/job/tradeship_engineer/head, - /datum/job/tradeship_doctor, - /datum/job/tradeship_researcher/head, + /datum/job/standard/assistant/tradeship, + /datum/job/standard/captain/tradeship, /datum/job/tradeship_first_mate, - /datum/job/cyborg, - /datum/job/assistant, - /datum/job/tradeship_engineer, - /datum/job/tradeship_doctor/head, - /datum/job/tradeship_researcher + /datum/job/standard/cmo/tradeship, + /datum/job/standard/doctor/tradeship, + /datum/job/standard/chief_engineer/tradeship, + /datum/job/standard/engineer/tradeship, + /datum/job/standard/rd/tradeship, + /datum/job/standard/scientist/tradeship, + /datum/job/standard/robot ) /obj/machinery/suit_cycler/tradeship boots = /obj/item/clothing/shoes/magboots req_access = list() + initial_access = list() + locked = FALSE /obj/machinery/suit_cycler/tradeship/Initialize() if(prob(75)) suit = pick(list( - /obj/item/clothing/suit/space/void/mining, - /obj/item/clothing/suit/space/void/engineering, - /obj/item/clothing/suit/space/void/pilot, - /obj/item/clothing/suit/space/void/excavation, + /obj/item/clothing/suit/space/void/mining, + /obj/item/clothing/suit/space/void/engineering, + /obj/item/clothing/suit/space/void/expedition, + /obj/item/clothing/suit/space/void/excavation, /obj/item/clothing/suit/space/void/engineering/salvage )) if(prob(75)) helmet = pick(list( - /obj/item/clothing/head/helmet/space/void/mining, - /obj/item/clothing/head/helmet/space/void/engineering, - /obj/item/clothing/head/helmet/space/void/pilot, - /obj/item/clothing/head/helmet/space/void/excavation, + /obj/item/clothing/head/helmet/space/void/mining, + /obj/item/clothing/head/helmet/space/void/engineering, + /obj/item/clothing/head/helmet/space/void/expedition, + /obj/item/clothing/head/helmet/space/void/excavation, /obj/item/clothing/head/helmet/space/void/engineering/salvage )) - . = ..() \ No newline at end of file + . = ..() diff --git a/maps/tradeship/tradeship_levels.dm b/maps/tradeship/tradeship_levels.dm new file mode 100644 index 000000000000..90612e7a9c56 --- /dev/null +++ b/maps/tradeship/tradeship_levels.dm @@ -0,0 +1,30 @@ +/obj/abstract/level_data_spawner/tradeship_basement + level_data_type = /datum/level_data/main_level/tradeship/basement + +/obj/abstract/level_data_spawner/tradeship_cargo + level_data_type = /datum/level_data/main_level/tradeship/cargo + +/obj/abstract/level_data_spawner/tradeship_habitation + level_data_type = /datum/level_data/main_level/tradeship/habitation + +/obj/abstract/level_data_spawner/tradeship_upper + level_data_type = /datum/level_data/main_level/tradeship/upper + +/datum/level_data/main_level/tradeship + abstract_type = /datum/level_data/main_level/tradeship + +/datum/level_data/main_level/tradeship/basement + name = "Tradeship Basement Deck" + level_id = "tradeship_basement" + +/datum/level_data/main_level/tradeship/cargo + name = "Tradeship Cargo Deck" + level_id = "tradeship_cargo" + +/datum/level_data/main_level/tradeship/habitation + name = "Tradeship Habitation Deck" + level_id = "tradeship_habitation" + +/datum/level_data/main_level/tradeship/upper + name = "Tradeship Upper Deck" + level_id = "tradeship_upper" diff --git a/maps/tradeship/tradeship_loadouts.dm b/maps/tradeship/tradeship_loadouts.dm index e403a7207b01..0c352eed634b 100644 --- a/maps/tradeship/tradeship_loadouts.dm +++ b/maps/tradeship/tradeship_loadouts.dm @@ -1,11 +1,11 @@ -/datum/gear/utility/guns - display_name = "guns" +/decl/loadout_option/utility/guns + name = "guns" cost = 4 - sort_category = "Utility" path = /obj/item/gun/projectile + uid = "gear_utility_guns" -/datum/gear/utility/guns/New() - ..() +/decl/loadout_option/utility/guns/Initialize() + . = ..() var/guns = list() guns["holdout pistol"] = /obj/item/gun/projectile/pistol/holdout gear_tweaks += new/datum/gear_tweak/path(guns) diff --git a/maps/tradeship/tradeship_overmap.dm b/maps/tradeship/tradeship_overmap.dm index b3eb6718e9b1..bc3d2dee83c5 100644 --- a/maps/tradeship/tradeship_overmap.dm +++ b/maps/tradeship/tradeship_overmap.dm @@ -1,13 +1,17 @@ /obj/effect/overmap/visitable/ship/tradeship - name = "Tradeship Ivenmoth" + name = "Tradeship Ocelot Alpha" color = "#00ffff" start_x = 4 start_y = 4 vessel_mass = 5000 max_speed = 1/(2 SECONDS) burn_delay = 2 SECONDS + restricted_area = 30 + sector_flags = OVERMAP_SECTOR_KNOWN|OVERMAP_SECTOR_BASE|OVERMAP_SECTOR_IN_SPACE - initial_generic_waypoints = list("nav_tradeship_below_bow", "nav_tradeship_below_starboardastern", "nav_tradeship_port_dock_shuttle") - initial_restricted_waypoints = list( - "Exploration Pod" = list("nav_tradeship_starboard_dock_pod"), //pod can only dock starboard-side, b/c there's only one door. + initial_generic_waypoints = list( + "nav_tradeship_below_bow", + "nav_tradeship_below_starboardastern", + "nav_tradeship_port_dock_shuttle", + "nav_tradeship_starboard_dock_rescue" ) \ No newline at end of file diff --git a/maps/tradeship/tradeship_overrides.dm b/maps/tradeship/tradeship_overrides.dm new file mode 100644 index 000000000000..78171f334ad6 --- /dev/null +++ b/maps/tradeship/tradeship_overrides.dm @@ -0,0 +1,18 @@ +/datum/computer_file/program/merchant/tradeship + read_access = list() + +/obj/machinery/computer/modular/preset/merchant/tradeship + default_software = list( + /datum/computer_file/program/merchant/tradeship, + /datum/computer_file/program/email_client, + /datum/computer_file/program/wordprocessor + ) + +/obj/item/stack/tile/floor/five + amount = 5 + +/obj/item/stack/cable_coil/single/yellow + color = COLOR_AMBER + +/obj/item/stack/cable_coil/random/three + amount = 3 diff --git a/maps/tradeship/tradeship_shuttles.dm b/maps/tradeship/tradeship_shuttles.dm index 2d9232bd0987..c309ad625a2d 100644 --- a/maps/tradeship/tradeship_shuttles.dm +++ b/maps/tradeship/tradeship_shuttles.dm @@ -1,25 +1,37 @@ /obj/machinery/computer/shuttle_control/explore/tradeship name = "exploration shuttle console" - shuttle_tag = "Exploration Shuttle" + shuttle_tag = "Bee Shuttle" + +/obj/machinery/computer/shuttle_control/explore/rescue + name = "rescue shuttle console" + shuttle_tag = "Rescue Shuttle" /datum/shuttle/autodock/overmap/exploration - name = "Exploration Shuttle" - shuttle_area = /area/ship/trade/shuttle/outgoing - dock_target = "tradeship_shuttle" + name = "Bee Shuttle" + shuttle_area = list(/area/ship/trade/shuttle/outgoing/general, /area/ship/trade/shuttle/outgoing/engineering) + dock_target = "bee_star" current_location = "nav_tradeship_port_dock_shuttle" +/datum/shuttle/autodock/overmap/rescue + name = "Rescue Shuttle" + shuttle_area = /area/ship/trade/shuttle/rescue + dock_target = "tradeship_rescue_shuttle" + current_location = "nav_tradeship_starboard_dock_rescue" + //In case multiple shuttles can dock at a location, //subtypes can be used to hold the shuttle-specific data /obj/effect/shuttle_landmark/docking_arm_starboard name = "Tradeship Starboard-side Docking Arm" docking_controller = "tradeship_starboard_dock" + flags = SLANDMARK_FLAG_REORIENT -/obj/effect/shuttle_landmark/docking_arm_starboard/pod - landmark_tag = "nav_tradeship_starboard_dock_pod" +/obj/effect/shuttle_landmark/docking_arm_starboard/rescue + landmark_tag = "nav_tradeship_starboard_dock_rescue" /obj/effect/shuttle_landmark/docking_arm_port name = "Tradeship Port-side Docking Arm" docking_controller = "tradeship_dock_port" + flags = SLANDMARK_FLAG_REORIENT /obj/effect/shuttle_landmark/docking_arm_port/shuttle landmark_tag = "nav_tradeship_port_dock_shuttle" @@ -33,8 +45,9 @@ landmark_tag = "nav_tradeship_below_starboardastern" // Essentially a bare platform that moves up and down. -/obj/turbolift_map_holder/tradeship +/obj/abstract/turbolift_spawner/tradeship name = "Tradeship cargo elevator placeholder" + icon = 'icons/obj/turbolift_preview_nowalls_4x4.dmi' depth = 4 lift_size_x = 3 lift_size_y = 3 @@ -42,7 +55,7 @@ wall_type = null firedoor_type = null light_type = null - floor_type = /turf/simulated/floor/tiled/steel_grid + floor_type = /turf/floor/tiled/steel_grid button_type = /obj/structure/lift/button/standalone panel_type = /obj/structure/lift/panel/standalone areas_to_use = list( diff --git a/maps/tradeship/tradeship_spawnpoints.dm b/maps/tradeship/tradeship_spawnpoints.dm index 63ba50b95aa2..36e4d8acdb7c 100644 --- a/maps/tradeship/tradeship_spawnpoints.dm +++ b/maps/tradeship/tradeship_spawnpoints.dm @@ -1,38 +1,29 @@ -GLOBAL_LIST_EMPTY(latejoin_cryo_two) -GLOBAL_LIST_EMPTY(latejoin_cryo_captain) - -/obj/effect/landmark/Initialize() - if(name == "JoinLateCryoTwo") - GLOB.latejoin_cryo_two += loc - delete_me = 1 - if(name == "JoinLateCryoCaptain") - GLOB.latejoin_cryo_captain += loc - delete_me = 1 - . = ..() - /datum/map/tradeship - allowed_spawns = list("Port Cryogenic Storage", "Starboard Cryogenic Storage", "Robot Storage", "Captain Compartment") - default_spawn = "Port Cryogenic Storage" + allowed_latejoin_spawns = list( + /decl/spawnpoint/cryo, + /decl/spawnpoint/cryo/two, + /decl/spawnpoint/cyborg, + ) + default_spawn = /decl/spawnpoint/cryo -/datum/spawnpoint/cryo - display_name = "Port Cryogenic Storage" - msg = "has completed revival in the port cryogenics bay" - disallow_job = list("Robot") +/decl/spawnpoint/cryo + name = "Port Cryogenic Storage" + spawn_announcement = "has completed revival in the port cryogenics bay" + disallow_job = list(/datum/job/standard/robot) -/datum/spawnpoint/cryo/two - display_name = "Starboard Cryogenic Storage" - msg = "has completed revival in the starboard cryogenics bay" - disallow_job = list("Robot") +/decl/spawnpoint/cryo/two + name = "Starboard Cryogenic Storage" + spawn_announcement = "has completed revival in the starboard cryogenics bay" + uid = "spawn_cryo_two" -/datum/spawnpoint/cryo/two/New() - ..() - turfs = GLOB.latejoin_cryo_two +/obj/abstract/landmark/latejoin/cryo_two + spawn_decl = /decl/spawnpoint/cryo/two -/datum/spawnpoint/cryo/captain - display_name = "Captain Compartment" - msg = "has completed revival in the captain compartment" - restrict_job = list("Captain") +/decl/spawnpoint/cryo/captain + name = "Captain Compartment" + spawn_announcement = "has completed revival in the captain compartment" + restrict_job = list(/datum/job/standard/captain/tradeship) + uid = "spawn_cryo_captain" -/datum/spawnpoint/cryo/captain/New() - ..() - turfs = GLOB.latejoin_cryo_captain +/obj/abstract/landmark/latejoin/cryo_captain + spawn_decl = /decl/spawnpoint/cryo/captain diff --git a/maps/tradeship/tradeship_unit_testing.dm b/maps/tradeship/tradeship_unit_testing.dm index 01c5a9191d2f..1ee322ce624e 100644 --- a/maps/tradeship/tradeship_unit_testing.dm +++ b/maps/tradeship/tradeship_unit_testing.dm @@ -1,22 +1,21 @@ -/datum/unit_test/station_wires_shall_be_connected - exceptions = list(list(48, 54, 3, EAST)) - /datum/map/tradeship + disconnected_wires_test_exempt_turfs = list(list(48, 54, 3, EAST)) // Unit test exemptions apc_test_exempt_areas = list( - /area/turbolift = NO_SCRUBBER|NO_VENT|NO_APC, - /area/space = NO_SCRUBBER|NO_VENT|NO_APC, - /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, - /area/ship/trade/maintenance/engine/port = NO_SCRUBBER|NO_VENT, + /area/turbolift = NO_SCRUBBER|NO_VENT|NO_APC, + /area/space = NO_SCRUBBER|NO_VENT|NO_APC, + /area/exoplanet = NO_SCRUBBER|NO_VENT|NO_APC, + /area/ship/trade/maintenance/engine/port = NO_SCRUBBER|NO_VENT, /area/ship/trade/maintenance/engine/starboard = NO_SCRUBBER|NO_VENT, - /area/ship/trade/crew/hallway/port = NO_SCRUBBER|NO_VENT, - /area/ship/trade/crew/hallway/starboard = NO_SCRUBBER|NO_VENT, - /area/ship/trade/maintenance/hallway = NO_SCRUBBER|NO_VENT, - /area/ship/trade/maintenance/lower = NO_SCRUBBER|NO_VENT, - /area/ship/trade/command/hallway = NO_SCRUBBER|NO_VENT, - /area/ship/trade/escape_port = NO_SCRUBBER|NO_VENT, - /area/ship/trade/escape_star = NO_SCRUBBER|NO_VENT, - /area/ship/trade/shuttle/outgoing = NO_SCRUBBER, - /area/ship/trade/maintenance/atmos = NO_SCRUBBER + /area/ship/trade/crew/hallway/port = NO_SCRUBBER|NO_VENT, + /area/ship/trade/crew/hallway/starboard = NO_SCRUBBER|NO_VENT, + /area/ship/trade/maintenance/hallway = NO_SCRUBBER|NO_VENT, + /area/ship/trade/maintenance/lower = NO_SCRUBBER|NO_VENT, + /area/ship/trade/escape_port = NO_SCRUBBER|NO_VENT, + /area/ship/trade/escape_star = NO_SCRUBBER|NO_VENT, + /area/ship/trade/shuttle/rescue = NO_SCRUBBER|NO_VENT, + /area/ship/trade/shuttle/outgoing/general = NO_SCRUBBER, + /area/ship/trade/shuttle/outgoing/engineering = NO_SCRUBBER, + /area/ship/trade/maintenance/atmos = NO_SCRUBBER ) diff --git a/maps/~mapsystem/map_preferences.dm b/maps/~mapsystem/map_preferences.dm index 1962812eec9d..8da77b1227b0 100644 --- a/maps/~mapsystem/map_preferences.dm +++ b/maps/~mapsystem/map_preferences.dm @@ -1,19 +1,3 @@ -/datum/map - var/load_legacy_saves = FALSE - -/datum/map/proc/character_save_path(var/slot) - return "/[path]/character[slot]" - -/datum/map/proc/character_load_path(var/savefile/S, var/slot) - var/original_cd = S.cd - S.cd = "/" - . = private_use_legacy_saves(S, slot) ? "/character[slot]" : "/[path]/character[slot]" - S.cd = original_cd // Attempting to make this call as side-effect free as possible - -/datum/map/proc/private_use_legacy_saves(var/savefile/S, var/slot) - if(!load_legacy_saves) // Check if we're bothering with legacy saves at all - return FALSE - if(!S.dir.Find(path)) // If we cannot find the map path folder, load the legacy save - return TRUE - S.cd = "/[path]" // Finally, if we cannot find the character slot in the map path folder, load the legacy save - return !S.dir.Find("character[slot]") +/// Must be a filename-safe string. In future if map paths get funky, do some sanitization here. +/datum/map/proc/preferences_key() + return path diff --git a/maps/~mapsystem/map_ranks.dm b/maps/~mapsystem/map_ranks.dm index 3c859c657e72..8bd2dd54b04b 100644 --- a/maps/~mapsystem/map_ranks.dm +++ b/maps/~mapsystem/map_ranks.dm @@ -1,5 +1,13 @@ /datum/map - var/list/branch_types // list of branch datum paths for military branches available on this map + /// All branches that exist on this map + var/list/branches = list() + /// Branches that a player can choose for spawning on this map, not including species restrictions. + var/list/spawn_branches_ = list() + /// Branches that a player can choose for spawning on this map, with species restrictions. Populated on an as-needed basis + var/list/spawn_branches_by_species_ = list() + + /// list of branch datum paths for military branches available on this map + var/list/branch_types var/list/spawn_branch_types // subset of above for branches a player can spawn in with var/list/species_to_branch_whitelist = list() // List of branches which are allowed, per species. Checked before the blacklist. @@ -8,8 +16,102 @@ var/list/species_to_rank_whitelist = list() // List of ranks which are allowed, per branch and species. Checked before the blacklist. var/list/species_to_rank_blacklist = list() // Lists of ranks which are restricted, per species. +// todo: this will need heavy reworking if we promote submaps from second to first class map status +/** + * Populate the map branches list + */ +/datum/map/proc/populate_branches() + if(!(global.using_map.flags & MAP_HAS_BRANCH) && !(global.using_map.flags & MAP_HAS_RANK)) + branches = null + spawn_branches_ = null + spawn_branches_by_species_ = null + return 1 + + branches = list() + spawn_branches_ = list() + spawn_branches_by_species_ = list() + for(var/branch_path in global.using_map.branch_types) + if(!ispath(branch_path, /datum/mil_branch)) + PRINT_STACK_TRACE("populate_branches() attempted to instantiate object with path [branch_path], which is not a subtype of /datum/mil_branch.") + continue + + var/datum/mil_branch/branch = new branch_path () + branches[branch.name] = branch + + if(branch_path in global.using_map.spawn_branch_types) + spawn_branches_[branch.name] = branch + + return 1 + +/** + * Retrieve branch object by branch name + */ +/datum/map/proc/get_branch(var/branch_name) + if(ispath(branch_name, /datum/mil_branch)) + var/datum/mil_branch/branch = branch_name + branch_name = initial(branch.name) + if(branch_name && branch_name != "None") + return branches[branch_name] + +/** + * Retrieve branch object by branch type + */ +/datum/map/proc/get_branch_by_type(var/branch_type) + for(var/name in branches) + if (istype(branches[name], branch_type)) + return branches[name] + +/** + * Retrieve a rank object from given branch by name + */ +/datum/map/proc/get_rank(var/branch_name, var/rank_name) + if(ispath(rank_name)) + var/datum/mil_rank/rank = rank_name + rank_name = initial(rank.name) + if(rank_name && rank_name != "None") + var/datum/mil_branch/branch = get_branch(branch_name) + if(branch) + return branch.ranks[rank_name] + +/** + * Return all spawn branches for the given input + */ +/datum/map/proc/spawn_branches(var/decl/species/S) + if(!S) + return spawn_branches_.Copy() + . = LAZYACCESS(spawn_branches_by_species_, S) + if(!.) + . = list() + LAZYSET(spawn_branches_by_species_, S, .) + for(var/spawn_branch in spawn_branches_) + if(!global.using_map.is_species_branch_restricted(S, spawn_branches_[spawn_branch])) + . += spawn_branch + +/** + * Return all spawn ranks for the given input + */ +/datum/map/proc/spawn_ranks(var/branch_name, var/decl/species/S) + var/datum/mil_branch/branch = get_branch(branch_name) + return branch && branch.spawn_ranks(S) + +/** + * Return a true value if branch_name is a valid spawn branch key + */ +/datum/map/proc/is_spawn_branch(var/branch_name, var/decl/species/S) + return (branch_name in spawn_branches(S)) + +/** + * Return a true value if rank_name is a valid spawn rank in branch under branch_name + */ +/datum/map/proc/is_spawn_rank(var/branch_name, var/rank_name, var/decl/species/S) + var/datum/mil_branch/branch = get_branch(branch_name) + if(branch && (rank_name in branch.spawn_ranks(S))) + return TRUE + else + return FALSE + // The white, and blacklist are type specific, any subtypes (of both species and jobs) have to be added explicitly -/datum/map/proc/is_species_branch_restricted(var/datum/species/S, var/datum/mil_branch/MB) +/datum/map/proc/is_species_branch_restricted(var/decl/species/S, var/datum/mil_branch/MB) if(!istype(S) || !istype(MB)) return TRUE @@ -23,7 +125,7 @@ return whitelist // not in the whitelist, no blacklist = bad, no whitelist or blacklist = fine -/datum/map/proc/is_species_rank_restricted(var/datum/species/S, var/datum/mil_branch/MB, var/datum/mil_rank/MR) +/datum/map/proc/is_species_rank_restricted(var/decl/species/S, var/datum/mil_branch/MB, var/datum/mil_rank/MR) if(!istype(S) || !istype(MB) || !istype(MR)) return TRUE diff --git a/maps/~mapsystem/map_skills.dm b/maps/~mapsystem/map_skills.dm new file mode 100644 index 000000000000..5651a433c345 --- /dev/null +++ b/maps/~mapsystem/map_skills.dm @@ -0,0 +1,22 @@ +/datum/map + var/list/_available_skills + +// Broken into a proc to allow maps to override the general skillset. +/datum/map/proc/get_available_skill_types() + . = list() + for(var/skill_type in decls_repository.get_decls_of_type(/decl/skill)) + . += skill_type + +/datum/map/proc/build_available_skills() + _available_skills = list() + for(var/skill_type in get_available_skill_types()) + var/decl/skill/skill = GET_DECL(skill_type) + if(!skill) + PRINT_STACK_TRACE("Invalid skill path [skill_type] in get_available_skill_types()!") + continue + _available_skills |= skill + +/datum/map/proc/get_available_skills() + if(!_available_skills) + build_available_skills() + return _available_skills diff --git a/maps/~mapsystem/maps.dm b/maps/~mapsystem/maps.dm index cd3cc2ec6969..5ddba61742de 100644 --- a/maps/~mapsystem/maps.dm +++ b/maps/~mapsystem/maps.dm @@ -1,47 +1,39 @@ -GLOBAL_DATUM_INIT(using_map, /datum/map, new USING_MAP_DATUM) -GLOBAL_LIST_EMPTY(all_maps) - -var/const/MAP_HAS_BRANCH = 1 //Branch system for occupations, togglable -var/const/MAP_HAS_RANK = 2 //Rank system, also togglable - -/hook/startup/proc/initialise_map_list() - for(var/type in subtypesof(/datum/map)) - var/datum/map/M - if(type == GLOB.using_map.type) - M = GLOB.using_map - M.setup_map() - else - M = new type - if(!M.path) - log_error("Map '[M]' ([type]) does not have a defined path, not adding to map list!") - else - GLOB.all_maps[M.path] = M - return 1 +var/global/datum/map/using_map = new USING_MAP_DATUM +var/global/list/all_maps = list() +var/global/list/votable_maps = list() +var/global/const/MAP_HAS_BRANCH = 1 //Branch system for occupations, toggleable +var/global/const/MAP_HAS_RANK = 2 //Rank system, also toggleable -/datum/map - var/name = "Unnamed Map" - var/full_name = "Unnamed Map" - var/path +/proc/initialise_map_list() + for(var/map_type in subtypesof(/datum/map)) - var/list/station_levels = list() // Z-levels the station exists on - var/list/admin_levels = list() // Z-levels for admin functionality (Centcom, shuttle transit, etc) - var/list/contact_levels = list() // Z-levels that can be contacted from the station, for eg announcements - var/list/player_levels = list() // Z-levels a character can typically reach - var/list/sealed_levels = list() // Z-levels that don't allow random transit at edge - var/list/empty_levels = null // Empty Z-levels that may be used for various things (currently used by FTL jump) + var/datum/map/map_instance = map_type + if(TYPE_IS_ABSTRACT(map_instance)) + continue - var/list/map_levels // Z-levels available to various consoles, such as the crew monitor. Defaults to station_levels if unset. + if(map_type == global.using_map.type) + map_instance = global.using_map + map_instance.setup_map() + else if(map_instance::path) + map_instance = new map_instance + else + log_error("Map '[map_type]' does not have a defined path, not adding to map list!") + continue - var/list/base_turf_by_z = list() // Custom base turf by Z-level. Defaults to world.turf for unlisted Z-levels - var/list/usable_email_tlds = list("freemail.net") + global.all_maps[map_instance.path] = map_instance + if(map_instance.votable) + global.votable_maps[map_instance.path] = map_instance - var/base_floor_type = /turf/simulated/floor/airless // The turf type used when generating floors between Z-levels at startup. - var/base_floor_area // Replacement area, if a base_floor_type is generated. Leave blank to skip. + return 1 - //This list contains the z-level numbers which can be accessed via space travel and the percentile chances to get there. - var/list/accessible_z_levels = list() +/datum/map + var/name = "Unnamed Map" + var/full_name = "Unnamed Map" + var/path + // TODO: move all the lobby stuff onto this handler. + var/lobby_handler = /decl/lobby_handler var/list/allowed_jobs //Job datums to use. //Works a lot better so if we get to a point where three-ish maps are used //We don't have to C&P ones that are only common between two of them @@ -59,17 +51,28 @@ var/const/MAP_HAS_RANK = 2 //Rank system, also togglable var/system_name = "Uncharted System" var/ground_noun = "ground" - var/map_admin_faxes = list() + var/default_announcement_frequency = "Common" + + // Current game year. Uses current system year + game_year num. + var/game_year = 288 + + /** + * Associative list of network URIs to a list with their display name, color, and "req_access formated" needed access list. + * EX: list("BIG_BOSS.COM" = list("name" = "Big boss", "color" = "#00ff00", "access" = list(list(access_heads, access_clown)))) + */ + var/list/map_admin_faxes + + var/map_tech_level = MAP_TECH_LEVEL_SPACE var/shuttle_docked_message var/shuttle_leaving_dock var/shuttle_called_message var/shuttle_recall_message + var/shuttle_arriving_at_dock_message var/emergency_shuttle_docked_message var/emergency_shuttle_leaving_dock var/emergency_shuttle_recall_message - - var/list/station_networks = list() // Camera networks that will show up on the console. + var/emergency_shuttle_arriving_at_dock_message var/list/holodeck_programs = list() // map of string ids to /datum/holodeck_program instances var/list/holodeck_supported_programs = list() // map of maps - first level maps from list-of-programs string id (e.g. "BarPrograms") to another map @@ -77,88 +80,163 @@ var/const/MAP_HAS_RANK = 2 //Rank system, also togglable // second level maps from program friendly display names ("Picnic Area") to program string ids ("picnicarea") // as defined in holodeck_programs var/list/holodeck_restricted_programs = list() // as above... but EVIL! + var/list/holodeck_default_program = list() // map of program list string ids to default program string id + var/list/holodeck_off_program = list() // as above... but for being off i guess + + var/allowed_latejoin_spawns = list( + /decl/spawnpoint/arrivals + ) + var/default_spawn = /decl/spawnpoint/arrivals - var/allowed_spawns = list("Arrivals Shuttle","Gateway", "Cryogenic Storage", "Robot Storage") - var/default_spawn = "Arrivals Shuttle" var/flags = 0 var/evac_controller_type = /datum/evacuation_controller - var/use_overmap = 0 //If overmap should be used (including overmap space travel override) - var/overmap_size = 20 //Dimensions of overmap zlevel if overmap is used. - var/overmap_z = 0 //If 0 will generate overmap zlevel on init. Otherwise will populate the zlevel provided. - var/overmap_event_areas = 0 //How many event "clouds" will be generated - var/pray_reward_type = /obj/item/chems/food/snacks/cookie // What reward should be given by admin when a prayer is received? + var/list/overmap_ids // Assoc list of overmap ID to overmap type, leave empty to disable overmap. + + var/pray_reward_type = /obj/item/food/cookie // What reward should be given by admin when a prayer is received? - var/list/lobby_screens = list('icons/default_lobby.png') // The list of lobby screen images to pick() from. + // The list of lobby screen images to pick() from. + var/list/lobby_screens = list('icons/default_lobby.png') var/current_lobby_screen - var/music_track/lobby_track // The track that will play in the lobby screen. - var/list/lobby_tracks = list() // The list of lobby tracks to pick() from. If left unset will randomly select among all available /music_track subtypes. - var/welcome_sound = 'sound/AI/welcome.ogg' // Sound played on roundstart + // The track that will play in the lobby screen. + var/decl/music_track/lobby_track + // The list of lobby tracks to pick() from. If left unset will randomly select among all available /music_track subtypes. + var/list/lobby_tracks = list() + + // A server logo displayed on the taskbar and top-left part of the window. Leave null for the default DM icon. + var/window_icon + + // Sounds played on roundstart + var/list/welcome_sound = 'sound/AI/welcome.ogg' + // Sounds played with end titles (credits) + var/list/credit_sound = list('sound/music/THUNDERDOME.ogg', 'sound/music/europa/Chronox_-_03_-_In_Orbit.ogg', 'sound/music/europa/asfarasitgets.ogg') + // Sounds played on server reboot + var/list/reboot_sound = list('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg') var/default_law_type = /datum/ai_laws/asimov // The default lawset use by synth units, if not overriden by their laws var. var/security_state = /decl/security_state/default // The default security state system to use. - var/id_hud_icons = 'icons/mob/hud.dmi' // Used by the ID HUD (primarily sechud) overlay. + var/hud_icons = 'icons/screen/hud.dmi' // Used by the ID HUD (primarily sechud) overlay. + var/implant_hud_icons = 'icons/screen/hud_implants.dmi' + var/med_hud_icons = 'icons/screen/hud_med.dmi' var/num_exoplanets = 0 - //dimensions of planet zlevels, defaults to world size if smaller, INCREASES world size if larger. + var/force_exoplanet_type // Used to override exoplanet weighting and always pick the same exoplanet. + //dimensions of planet zlevels, defaults to world size if smaller, INCREASES world size if larger. //Due to how maps are generated, must be (2^n+1) e.g. 17,33,65,129 etc. Map will just round up to those if set to anything other. var/list/planet_size = list() + ///The amount of z-levels generated for exoplanets. Default is 1. Be careful with this, since exoplanets are already pretty expensive. + var/planet_depth = 1 var/away_site_budget = 0 var/list/loadout_blacklist //list of types of loadout items that will not be pickable //Economy stuff - var/starting_money = 75000 //Money in station account - var/department_money = 5000 //Money in department accounts - var/salary_modifier = 1 //Multiplier to starting character money + var/starting_money = 75000 // Money in station account + var/department_money = 5000 // Money in department accounts + var/salary_modifier = 1 // Multiplier to starting character money + var/passport_type = /obj/item/passport // Item type to grant people on join. + var/list/station_departments = list()//Gets filled automatically depending on jobs allowed - var/default_species = SPECIES_HUMAN - - var/list/available_cultural_info = list( - TAG_HOMEWORLD = list( - HOME_SYSTEM_OTHER - ), - TAG_FACTION = list( - FACTION_OTHER - ), - TAG_CULTURE = list( - CULTURE_OTHER - ), - TAG_RELIGION = list( - RELIGION_OTHER - ) + var/default_species = /decl/species/human::uid + + // Can this map be voted for by players? + var/votable = TRUE + + var/list/available_background_info = list( + /decl/background_category/citizenship = list(/decl/background_detail/citizenship/other), + /decl/background_category/homeworld = list(/decl/background_detail/location/other), + /decl/background_category/faction = list(/decl/background_detail/faction/other), + /decl/background_category/heritage = list(/decl/background_detail/heritage/other), + /decl/background_category/religion = list(/decl/background_detail/religion/other) ) - var/list/default_cultural_info = list( - TAG_HOMEWORLD = HOME_SYSTEM_OTHER, - TAG_FACTION = FACTION_OTHER, - TAG_CULTURE = CULTURE_OTHER, - TAG_RELIGION = RELIGION_OTHER + var/list/default_background_info = list( + /decl/background_category/citizenship = /decl/background_detail/citizenship/other, + /decl/background_category/homeworld = /decl/background_detail/location/other, + /decl/background_category/faction = /decl/background_detail/faction/other, + /decl/background_category/heritage = /decl/background_detail/heritage/other, + /decl/background_category/religion = /decl/background_detail/religion/other ) + // Order must conform to ACCESS_REGION_FOO defines. var/access_modify_region = list( - ACCESS_REGION_SECURITY = list(access_hos, access_change_ids), - ACCESS_REGION_MEDBAY = list(access_cmo, access_change_ids), - ACCESS_REGION_RESEARCH = list(access_rd, access_change_ids), - ACCESS_REGION_ENGINEERING = list(access_ce, access_change_ids), - ACCESS_REGION_COMMAND = list(access_change_ids), - ACCESS_REGION_GENERAL = list(access_change_ids), - ACCESS_REGION_SUPPLY = list(access_change_ids) + list(access_hos, access_change_ids), + list(access_cmo, access_change_ids), + list(access_rd, access_change_ids), + list(access_ce, access_change_ids), + list(access_change_ids), + list(access_change_ids), + list(access_change_ids) + ) + var/secrets_directory + + /// A list of /decl/loadout_category types which will be available for characters made on this map. Uses all categories if null. + var/list/decl/loadout_category/loadout_categories + + /// A list of survival box types selectable for this map. If null, defaults to all defined decls. At runtime, this is an associative list of decl type -> decl. + var/list/decl/survival_box_option/survival_box_choices + + // A list of cash spawn options, similar to above. + var/list/decl/starting_cash_choice/starting_cash_choices + + /// A reagent used to prefill lanterns. + var/default_liquid_fuel_type = /decl/material/liquid/fuel + + /// Decl list of backpacks available to outfits and in character generation. + var/list/_available_backpacks + var/backpacks_setup = FALSE + + var/list/char_preview_bgstate_options = list( + "000", + "midgrey", + "FFF", + "white", + "steel", + "techmaint", + "dark", + "plating", + "reinforced" + ) + var/background_categories_generated = FALSE + + // Hard defining this to avoid pulling in unimplemented citizenship decls for the time being. + var/list/_background_categories = list( + /decl/background_category/heritage, + /decl/background_category/homeworld, + /decl/background_category/faction, + /decl/background_category/religion ) + var/default_ui_style + + /// Is maint currently all-access? + var/maint_all_access = FALSE + /datum/map/New() - if(!map_levels) - map_levels = station_levels.Copy() - if(!allowed_jobs) - allowed_jobs = list() - for(var/jtype in subtypesof(/datum/job)) - var/datum/job/job = jtype - if(initial(job.available_by_default)) - allowed_jobs += jtype - if(!LAZYLEN(planet_size)) - planet_size = list(world.maxx, world.maxy) - current_lobby_screen = pick(lobby_screens) + ..() + default_ui_style ||= DEFAULT_UI_STYLE + +/datum/map/proc/get_background_categories() + if(!background_categories_generated) + if(isnull(_background_categories)) + _background_categories = decls_repository.get_decls_of_type(/decl/background_category) + _background_categories = _background_categories?.Copy() || list() // Avoid mutating the cache. + else + for(var/cat_type in _background_categories) + _background_categories[cat_type] = GET_DECL(cat_type) + background_categories_generated = TRUE + return _background_categories + +/datum/map/proc/get_random_location() + var/list/options = list() + for(var/cat_type in available_background_info) + var/decl/background_category/background_cat = GET_DECL(cat_type) + if(istype(background_cat) && (background_cat.background_flags & BACKGROUND_FLAG_LOCATION)) + options |= available_background_info[cat_type] + if(length(options)) + return GET_DECL(pick(options)) + return GET_DECL(/decl/background_detail/location/other) /datum/map/proc/get_lobby_track(var/exclude) var/lobby_track_type @@ -167,20 +245,112 @@ var/const/MAP_HAS_RANK = 2 //Rank system, also togglable else if(LAZYLEN(lobby_tracks)) lobby_track_type = pickweight(lobby_tracks - exclude) else - lobby_track_type = pick(subtypesof(/music_track) - exclude) - return decls_repository.get_decl(lobby_track_type) + lobby_track_type = pick(decls_repository.get_decl_paths_of_subtype(/decl/music_track) - exclude) + return GET_DECL(lobby_track_type) + +/datum/map/proc/get_available_backpacks() + if(!backpacks_setup) + backpacks_setup = TRUE + if(length(_available_backpacks)) + for(var/backpack_type in _available_backpacks) + _available_backpacks[backpack_type] = GET_DECL(backpack_type) + _available_backpacks[/decl/backpack_outfit/nothing] = GET_DECL(/decl/backpack_outfit/nothing) + else + _available_backpacks = decls_repository.get_decls_of_subtype(/decl/backpack_outfit) + return _available_backpacks /datum/map/proc/setup_map() + + populate_branches() + + if(!length(loadout_categories)) + loadout_categories = list() + for(var/decl_type in decls_repository.get_decls_of_type(/decl/loadout_category)) + loadout_categories += decl_type + + for(var/loadout_category in loadout_categories) + loadout_categories -= loadout_category + loadout_categories += GET_DECL(loadout_category) + + if(isnull(survival_box_choices)) // an empty list is a valid option here, a null one is not + survival_box_choices = decls_repository.get_decls_of_subtype(/decl/survival_box_option) + else if(length(survival_box_choices)) + survival_box_choices = decls_repository.get_decls(survival_box_choices) + + if(isnull(starting_cash_choices)) + starting_cash_choices = decls_repository.get_decls_of_subtype(/decl/starting_cash_choice) + else if(length(starting_cash_choices)) + starting_cash_choices = decls_repository.get_decls(starting_cash_choices) + + if(secrets_directory) + secrets_directory = trim(lowertext(secrets_directory)) + if(!length(secrets_directory)) + log_warning("[type] secrets_directory is zero length after trim.") + if(copytext(secrets_directory, -1) != "/") + secrets_directory = "[secrets_directory]/" + if(!fexists(secrets_directory)) + log_warning("[type] secrets_directory does not exist.") + SSsecrets.load_directories |= secrets_directory + + if(!allowed_jobs) + allowed_jobs = list() + for(var/datum/job/job as anything in subtypesof(/datum/job)) + if(!TYPE_IS_ABSTRACT(job) && job::available_by_default) + allowed_jobs += job + + if(ispath(default_job_type, /datum/job)) + var/datum/job/J = default_job_type + default_job_title = initial(J.title) + + if(default_spawn && !(default_spawn in allowed_latejoin_spawns)) + PRINT_STACK_TRACE("Map datum [type] has default spawn point [default_spawn] not in the allowed spawn list.") + + for(var/spawn_type in allowed_latejoin_spawns) + allowed_latejoin_spawns -= spawn_type + allowed_latejoin_spawns += GET_DECL(spawn_type) + + if(!SSmapping.map_levels) + SSmapping.map_levels = SSmapping.station_levels.Copy() + + if(!LAZYLEN(planet_size)) + planet_size = list(world.maxx, world.maxy) + if(planet_depth <= 0) + planet_depth = 1 + + game_year = (text2num(time2text(world.realtime, "YYYY")) + game_year) + + setup_admin_faxes() + lobby_track = get_lobby_track() + update_titlescreen() world.update_status() +///Generates the default admin faxes addresses +/datum/map/proc/setup_admin_faxes() + LAZYSET(map_admin_faxes, uppertext(replacetext("[boss_name].COM", " ", "_")), list("name" = "[boss_name]", "color" = "#006100", "access" = list(access_heads))) + LAZYSET(map_admin_faxes, uppertext(replacetext("[boss_short]_SUPPLY.COM", " ", "_")), list("name" = "[boss_short] Supply", "color" = "#5f4519", "access" = list(access_heads))) + LAZYSET(map_admin_faxes, uppertext(replacetext("[system_name]_POLICE.GOV", " ", "_")), list("name" = "[system_name] Police", "color" = "#1f66a0", "access" = list(access_heads))) + /datum/map/proc/setup_job_lists() - return -/datum/map/proc/send_welcome() - return + // Populate blacklists for any default-blacklisted species. + for(var/decl/species/species as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/species)) + if(!species.job_blacklist_by_default) + continue + var/found_whitelisted_job = FALSE + for(var/datum/job/job as anything in SSjobs.primary_job_datums) + if((species.type in job_to_species_whitelist[job.type]) || (job.type in species_to_job_whitelist[species.type])) + found_whitelisted_job = TRUE + else + LAZYDISTINCTADD(species_to_job_blacklist[species.type], job.type) + LAZYDISTINCTADD(job_to_species_blacklist[job.type], species.type) + + // If no jobs are available for the main map, mark the species as unavailable to avoid player confusion. + if(!found_whitelisted_job && src == global.using_map) + species.spawn_flags &= ~SPECIES_CAN_JOIN + species.spawn_flags |= SPECIES_IS_RESTRICTED -/datum/map/proc/perform_map_generation() +/datum/map/proc/send_welcome() return /datum/map/proc/build_away_sites() @@ -190,72 +360,92 @@ var/const/MAP_HAS_RANK = 2 //Rank system, also togglable #else report_progress("Loading away sites...") var/list/sites_by_spawn_weight = list() - for (var/site_name in SSmapping.away_sites_templates) - var/datum/map_template/ruin/away_site/site = SSmapping.away_sites_templates[site_name] + var/list/away_sites_templates = SSmapping.get_templates_by_category(MAP_TEMPLATE_CATEGORY_AWAYSITE) + for (var/site_name in away_sites_templates) + var/datum/map_template/site = away_sites_templates[site_name] if((site.template_flags & TEMPLATE_FLAG_SPAWN_GUARANTEED) && site.load_new_z()) // no check for budget, but guaranteed means guaranteed report_progress("Loaded guaranteed away site [site]!") - away_site_budget -= site.cost + away_site_budget -= site.get_template_cost() continue - sites_by_spawn_weight[site] = site.spawn_weight + sites_by_spawn_weight[site] = site.get_spawn_weight() while (away_site_budget > 0 && sites_by_spawn_weight.len) - var/datum/map_template/ruin/away_site/selected_site = pickweight(sites_by_spawn_weight) + var/datum/map_template/selected_site = pickweight(sites_by_spawn_weight) if (!selected_site) break sites_by_spawn_weight -= selected_site - if(selected_site.cost > away_site_budget) + var/site_cost = selected_site.get_template_cost() + if(site_cost > away_site_budget) continue if (selected_site.load_new_z()) report_progress("Loaded away site [selected_site]!") - away_site_budget -= selected_site.cost + away_site_budget -= site_cost + report_progress("Finished loading away sites, remaining budget [away_site_budget], remaining sites [sites_by_spawn_weight.len]") #endif -/datum/map/proc/build_exoplanets() - if(!use_overmap) - return - if(LAZYLEN(planet_size)) - if(world.maxx < planet_size[1]) - world.maxx = planet_size[1] - if(world.maxy < planet_size[2]) - world.maxy = planet_size[2] - for(var/i = 0, i < num_exoplanets, i++) - var/exoplanet_type = pick(subtypesof(/obj/effect/overmap/visitable/sector/exoplanet)) - INCREMENT_WORLD_Z_SIZE - var/obj/effect/overmap/visitable/sector/exoplanet/new_planet = new exoplanet_type(null, world.maxz) - new_planet.build_level(planet_size[1], planet_size[2]) - -// Used to apply various post-compile procedural effects to the map. -/datum/map/proc/refresh_mining_turfs(var/zlevel) - - set background = 1 - set waitfor = 0 - - for(var/thing in mining_floors["[zlevel]"]) - var/turf/simulated/floor/asteroid/M = thing - if(istype(M)) - M.updateMineralOverlays() - -/datum/map/proc/get_network_access(var/network) - return 0 - -// By default transition randomly to another zlevel +/datum/map/proc/build_planets() +#ifdef UNIT_TEST + report_progress("Unit testing, so not loading planets.") + return +#else + report_progress("Instantiating planets...") + var/list/planets_spawn_weight = list() + var/list/planets_to_spawn = list() + + //Fill up our lists of planets to spawn + generate_planet_spawn_lists(get_all_planet_templates(), planets_spawn_weight, planets_to_spawn) + + //Pick the random planets we want to spawn + var/datum/map_template/planetoid/forced_planet = ispath(force_exoplanet_type)? SSmapping.get_template_by_type(force_exoplanet_type) : null + var/random_planets_to_pick = max(num_exoplanets - length(planets_to_spawn), 0) //subtract guaranteed planets + for(var/i = 0, i < random_planets_to_pick, i++) + planets_to_spawn += forced_planet || pickweight(planets_spawn_weight) + + //Actually spawn the templates + spawn_planet_templates(planets_to_spawn) + + report_progress("Finished instantiating planets.") +#endif + +///Returns an associative list of all the planet templates we get to pick from. The key is the template name, and the value is the template instance. +/datum/map/proc/get_all_planet_templates() + . = list() + var/list/exoplanet_templates = SSmapping.get_templates_by_category(MAP_TEMPLATE_CATEGORY_EXOPLANET) + if(islist(exoplanet_templates)) + . |= exoplanet_templates + + var/list/planets_templates = SSmapping.get_templates_by_category(MAP_TEMPLATE_CATEGORY_PLANET) + if(islist(planets_templates)) + . |= planets_templates + +///Fill up the list of planet_spawn_weight and guaranteed_planets +/datum/map/proc/generate_planet_spawn_lists(var/list/planets_templates, var/list/planets_spawn_weight, var/list/guaranteed_planets) + for(var/template_name in planets_templates) + var/datum/map_template/planetoid/E = planets_templates[template_name] + if((E.template_flags & TEMPLATE_FLAG_SPAWN_GUARANTEED)) + guaranteed_planets += E + else + planets_spawn_weight[E] = E.get_spawn_weight() + +///Spawns all the templates in the given list, one after the other +/datum/map/proc/spawn_planet_templates(var/list/templates_to_spawn) + for(var/datum/map_template/planetoid/PT in templates_to_spawn) + PT.load_new_z() +#ifdef UNIT_TEST + log_unit_test("Loaded template '[PT]' ([PT.type]) at Z-level [world.maxz] with a tallness of [PT.tallness]") +#endif + +// By default return a random accessible z-level, or the current level if one is unavailable /datum/map/proc/get_transit_zlevel(var/current_z_level) - var/list/candidates = GLOB.using_map.accessible_z_levels.Copy() + var/list/candidates = SSmapping.accessible_z_levels.Copy() candidates.Remove(num2text(current_z_level)) if(!candidates.len) return current_z_level return text2num(pickweight(candidates)) -/datum/map/proc/get_empty_zlevel() - if(empty_levels == null) - INCREMENT_WORLD_Z_SIZE - empty_levels = list(world.maxz) - return pick(empty_levels) - - /datum/map/proc/setup_economy() news_network.CreateFeedChannel("News Daily", "Minister of Information", 1, 1) news_network.CreateFeedChannel("The Gibson Gazette", "Editor Mike Hammers", 1, 1) @@ -265,14 +455,14 @@ var/const/MAP_HAS_RANK = 2 //Rank system, also togglable for(var/job in allowed_jobs) var/datum/job/J = SSjobs.get_by_path(job) - var/list/dept = J.department_refs + var/list/dept = J.department_types if(LAZYLEN(dept)) station_departments |= dept for(var/department in station_departments) - var/datum/department/dept = SSdepartments.departments[department] + var/decl/department/dept = SSjobs.get_department_by_type(department) if(istype(dept)) - department_accounts[department] = create_account("[dept.title] Account", "[dept.title]", department_money, ACCOUNT_TYPE_DEPARTMENT) + department_accounts[department] = create_account("[dept.name] Account", "[dept.name]", department_money, ACCOUNT_TYPE_DEPARTMENT) department_accounts["Vendor"] = create_account("Vendor Account", "Vendor", 0, ACCOUNT_TYPE_DEPARTMENT) vendor_account = department_accounts["Vendor"] @@ -291,39 +481,115 @@ var/const/MAP_HAS_RANK = 2 //Rank system, also togglable return /datum/map/proc/make_maint_all_access(var/radstorm = 0) - maint_all_access = 1 + maint_all_access = TRUE priority_announcement.Announce("The maintenance access requirement has been revoked on all maintenance airlocks.", "Attention!") /datum/map/proc/revoke_maint_all_access(var/radstorm = 0) - maint_all_access = 0 + maint_all_access = FALSE priority_announcement.Announce("The maintenance access requirement has been readded on all maintenance airlocks.", "Attention!") -// Access check is of the type requires one. These have been carefully selected to avoid allowing the janitor to see channels he shouldn't -// This list needs to be purged but people insist on adding more cruft to the radio. -/datum/map/proc/default_internal_channels() - return list( - num2text(PUB_FREQ) = list(), - num2text(AI_FREQ) = list(access_synth), - num2text(ENT_FREQ) = list(), - num2text(ERT_FREQ) = list(access_cent_specops), - num2text(COMM_FREQ) = list(access_bridge), - num2text(ENG_FREQ) = list(access_engine_equip, access_atmospherics), - num2text(MED_FREQ) = list(access_medical_equip), - num2text(MED_I_FREQ) = list(access_medical_equip), - num2text(SEC_FREQ) = list(access_security), - num2text(SEC_I_FREQ) = list(access_security), - num2text(SCI_FREQ) = list(access_tox,access_robotics,access_xenobiology), - num2text(SUP_FREQ) = list(access_cargo), - num2text(SRV_FREQ) = list(access_janitor, access_hydroponics), - ) - /datum/map/proc/show_titlescreen(client/C) + set waitfor = FALSE + winset(C, "lobbybrowser", "is-disabled=false;is-visible=true") - - show_browser(C, current_lobby_screen, "file=titlescreen.png;display=0") - show_browser(C, file('html/lobby_titlescreen.html'), "window=lobbybrowser") + + show_browser(C, current_lobby_screen, "file=titlescreen.gif;display=0") + + if(isnewplayer(C.mob)) + var/mob/new_player/player = C.mob + show_browser(C, player.get_lobby_browser_html(), "window=lobbybrowser") /datum/map/proc/hide_titlescreen(client/C) if(C.mob) // Check if the client is still connected to something // Hide title screen, allowing player to see the map - winset(C, "lobbybrowser", "is-disabled=true;is-visible=false") \ No newline at end of file + winset(C, "lobbybrowser", "is-disabled=true;is-visible=false") + +/datum/map/proc/update_titlescreen(new_screen) + current_lobby_screen = new_screen || pick(lobby_screens) + refresh_lobby_browsers() + +/datum/map/proc/refresh_lobby_browsers() + for(var/mob/new_player/player in global.player_list) + show_titlescreen(player.client) + player.show_lobby_menu() + +/datum/map/proc/create_trade_hubs() + new /datum/trade_hub/singleton + +/datum/map/proc/get_radio_chatter_types() + return + +/datum/map/proc/get_universe_end_evac_areas() + . = list(/area/space) + +/datum/map/proc/get_specops_area() + return + +/datum/map/proc/summarize_roundend_for(var/mob/player) + if(!player) + return + if(player.stat != DEAD) + var/turf/playerTurf = get_turf(player) + if(SSevac.evacuation_controller && SSevac.evacuation_controller.round_over() && SSevac.evacuation_controller.emergency_evacuation) + if(isNotAdminLevel(playerTurf.z)) + to_chat(player, SPAN_NEUTRAL("You managed to survive, but were marooned on [station_name()] as [player.real_name]...")) + else + to_chat(player, SPAN_GOOD("You managed to survive the events on [station_name()] as [player.real_name].")) + else if(isAdminLevel(playerTurf.z)) + to_chat(player, SPAN_GOOD("You successfully underwent crew transfer after events on [station_name()] as [player.real_name].")) + else if(issilicon(player)) + to_chat(player, SPAN_GOOD("You remain operational after the events on [station_name()] as [player.real_name].")) + else + to_chat(player, SPAN_NEUTRAL("You got through just another workday on [station_name()] as [player.real_name].")) + else + if(isghost(player)) + var/mob/observer/ghost/O = player + if(!O.started_as_observer) + to_chat(player, SPAN_BAD("You did not survive the events on [station_name()]...")) + else + to_chat(player, SPAN_BAD("You did not survive the events on [station_name()]...")) + +/datum/map/proc/create_passport(var/mob/living/human/H) + if(!passport_type) + return + var/obj/item/passport/pass = new passport_type(get_turf(H)) + if(istype(pass)) + pass.set_info(H) + if(!H.equip_to_slot_if_possible(pass, slot_in_wallet_str, del_on_fail=FALSE, disable_warning=TRUE) && !H.equip_to_slot_if_possible(pass, slot_in_backpack_str, del_on_fail=FALSE, disable_warning=TRUE)) + H.put_in_hands(pass) + +/datum/map/proc/populate_overmap_events() + for(var/overmap_id in global.overmaps_by_name) + SSmapping.overmap_event_handler.create_events(global.overmaps_by_name[overmap_id]) + +/datum/map/proc/finalize_map_generation() + return + +/datum/map/proc/validate() + . = TRUE + if(!length(SSmapping.player_levels)) + log_error("[name] has no player levels!") + . = FALSE + if(!length(SSmapping.station_levels)) + log_error("[name] has no station levels!") + . = FALSE + // TODO: add an admin level loaded from template for maps like tradeship (generic admin level modpack?) + /* + if(!length(SSmapping.admin_levels)) + log_error("[name] has no admin levels!") + . = FALSE + */ + if(!length(SSmapping.contact_levels)) + log_error("[name] has no contact levels!") + . = FALSE + var/decl/species/default_species_decl = decls_repository.get_decl_by_id(default_species) + if(default_species_decl.species_flags & SPECIES_IS_RESTRICTED) + log_error("[name]'s default species [default_species_decl.type] is set to restricted!") + if(default_species_decl.species_flags & SPECIES_IS_WHITELISTED) + log_error("[name]'s default species [default_species_decl.type] is set to whitelisted!") + if(default_species_decl.species_flags & SPECIES_CAN_JOIN) + log_error("[name]'s default species [default_species_decl.type] is not allowed to join the game!") + +/datum/map/proc/get_available_submap_archetypes() + return decls_repository.get_decls_of_subtype_unassociated(/decl/submap_archetype) + diff --git a/maps/~mapsystem/maps_announcements.dm b/maps/~mapsystem/maps_announcements.dm index 4f8dfef7eba8..2749e4f5e175 100644 --- a/maps/~mapsystem/maps_announcements.dm +++ b/maps/~mapsystem/maps_announcements.dm @@ -29,7 +29,8 @@ var/lifesign_spawn_sound = 'sound/AI/aliens.ogg' /datum/map/proc/emergency_shuttle_called_announcement() - SSevac.evacuation_controller.evac_called.Announce(replacetext(emergency_shuttle_called_message, "%ETA%", "[round(SSevac.evacuation_controller.get_eta()/60)] minute\s."), new_sound = emergency_shuttle_called_sound) + if(SSevac.evacuation_controller && emergency_shuttle_called_message) + SSevac.evacuation_controller.evac_called.Announce(replacetext(emergency_shuttle_called_message, "%ETA%", "[round(SSevac.evacuation_controller.get_eta()/60)] minute\s"), new_sound = emergency_shuttle_called_sound) /datum/map/proc/grid_check_announcement() command_announcement.Announce(replacetext(grid_check_message, "%STATION_NAME%", station_name()), "Automated Grid Check", new_sound = grid_check_sound) @@ -48,14 +49,11 @@ /datum/map/proc/level_x_biohazard_sound(var/bio_level) return -/datum/map/proc/radiation_detected_announcement() - command_announcement.Announce(replacetext(radiation_detected_message, "%STATION_NAME%", station_name()), "Anomaly Alert", new_sound = radiation_detected_sound) +/datum/map/proc/radiation_detected_announcement(list/affecting_z) + command_announcement.Announce(replacetext(radiation_detected_message, "%STATION_NAME%", station_name()), "Anomaly Alert", new_sound = radiation_detected_sound, zlevels = affecting_z) -/datum/map/proc/space_time_anomaly_detected_annoncement() - command_announcement.Announce("Space-time anomalies have been detected on the [station_name()].", "Anomaly Alert", new_sound = space_time_anomaly_sound) +/datum/map/proc/space_time_anomaly_detected_annoncement(list/affecting_z) + command_announcement.Announce("Space-time anomalies have been detected on the [station_name()].", "Anomaly Alert", new_sound = space_time_anomaly_sound, zlevels = affecting_z) -/datum/map/proc/unidentified_lifesigns_announcement() - command_announcement.Announce(replacetext(unidentified_lifesigns_message, "%STATION_NAME%", station_name()), "Lifesign Alert", new_sound = unidentified_lifesigns_sound) - -/datum/map/proc/unknown_biological_entities_announcement() - command_announcement.Announce(replacetext(unknown_biological_entities_message, "%STATION_NAME%", station_name()), "Lifesign Alert", new_sound = command_report_sound) +/datum/map/proc/unidentified_lifesigns_announcement(list/affecting_z) + command_announcement.Announce(replacetext(unidentified_lifesigns_message, "%STATION_NAME%", station_name()), "Lifesign Alert", new_sound = unidentified_lifesigns_sound, zlevels = affecting_z) diff --git a/maps/~mapsystem/maps_antagonism.dm b/maps/~mapsystem/maps_antagonism.dm index a1fa663dfca5..320d177359c3 100644 --- a/maps/~mapsystem/maps_antagonism.dm +++ b/maps/~mapsystem/maps_antagonism.dm @@ -1,35 +1,33 @@ /datum/map var/list/potential_theft_targets = list( - "the captain's antique laser gun" = /obj/item/gun/energy/captain, - "a wormhole generator" = /obj/item/integrated_circuit/manipulation/wormhole, + "the captain's antique laser gun" = /obj/item/gun/energy/retro/captain, "an RCD" = /obj/item/rcd, "a jetpack" = /obj/item/tank/jetpack, - "a captain's jumpsuit" = /obj/item/clothing/under/rank/captain, + "a captain's jumpsuit" = /obj/item/clothing/jumpsuit/captain, "a functional AI" = /obj/item/aicard, "a pair of magboots" = /obj/item/clothing/shoes/magboots, "the master blueprints" = /obj/item/blueprints, "a nasa voidsuit" = /obj/item/clothing/suit/space/void, "full tank of hydrogen" = /obj/item/tank/hydrogen, - "a sample of slime extract" = /obj/item/slime_extract, - "a piece of corgi meat" = /obj/item/chems/food/snacks/meat/corgi, - "a chief science officer's jumpsuit" = /obj/item/clothing/under/rank/research_director, - "a chief engineer's jumpsuit" = /obj/item/clothing/under/rank/chief_engineer, - "a chief medical officer's jumpsuit" = /obj/item/clothing/under/rank/chief_medical_officer, - "a head of security's jumpsuit" = /obj/item/clothing/under/rank/head_of_security, - "a head of personnel's jumpsuit" = /obj/item/clothing/under/rank/head_of_personnel, + "a piece of corgi meat" = /obj/item/food/butchery/meat/corgi, + "a chief science officer's jumpsuit" = /obj/item/clothing/jumpsuit/research_director, + "a chief engineer's jumpsuit" = /obj/item/clothing/jumpsuit/chief_engineer, + "a chief medical officer's jumpsuit" = /obj/item/clothing/jumpsuit/chief_medical_officer, + "a head of security's jumpsuit" = /obj/item/clothing/jumpsuit/head_of_security, + "a head of personnel's jumpsuit" = /obj/item/clothing/jumpsuit/head_of_personnel, "the hypospray" = /obj/item/chems/hypospray, "the captain's pinpointer" = /obj/item/pinpointer, "an ablative armor vest" = /obj/item/clothing/suit/armor/laserproof ) var/list/potential_special_theft_targets = list( - "nuclear gun" = /obj/item/gun/energy/gun/nuclear, - "diamond drill" = /obj/item/pickaxe/diamonddrill, - "bag of holding" = /obj/item/storage/backpack/holding, - "hyper-capacity cell" = /obj/item/cell/hyper, - "10 diamonds" = /obj/item/stack/material/diamond, - "50 gold bars" = /obj/item/stack/material/gold, - "25 refined uranium bars" = /obj/item/stack/material/uranium, + "nuclear gun" = /obj/item/gun/energy/gun/nuclear, + "diamond drill" = /obj/item/tool/drill/diamond, + "bag of holding" = /obj/item/backpack/holding, + "hyper-capacity cell" = /obj/item/cell/hyper, + "10 diamonds" = list(/obj/item/stack/material/gemstone, 10, /decl/material/solid/gemstone/diamond), + "50 gold ingots" = list(/obj/item/stack/material/ingot, 50, /decl/material/solid/metal/gold), + "25 uranium pucks" = list(/obj/item/stack/material/puck, 25, /decl/material/solid/metal/uranium), ) /datum/map/proc/get_theft_targets() diff --git a/maps/~mapsystem/maps_areas.dm b/maps/~mapsystem/maps_areas.dm index 51c6d7b0f9c9..d2a000aeb663 100644 --- a/maps/~mapsystem/maps_areas.dm +++ b/maps/~mapsystem/maps_areas.dm @@ -9,7 +9,7 @@ ..() if(!post_round_safe_areas.len) for(var/area/A) - if(isspace(A)) + if(isspacearea(A)) continue - if(A.z && (A.z in admin_levels)) + if(A.z && (A.z in SSmapping.admin_levels)) post_round_safe_areas += A.type diff --git a/maps/~mapsystem/maps_comms.dm b/maps/~mapsystem/maps_comms.dm new file mode 100644 index 000000000000..44f77be81666 --- /dev/null +++ b/maps/~mapsystem/maps_comms.dm @@ -0,0 +1,4 @@ +/datum/map + var/list/default_telecomms_channels = list( + COMMON_FREQUENCY_DATA + ) diff --git a/maps/~mapsystem/maps_currency.dm b/maps/~mapsystem/maps_currency.dm index 934768f8a9da..e83f0c010931 100644 --- a/maps/~mapsystem/maps_currency.dm +++ b/maps/~mapsystem/maps_currency.dm @@ -1,2 +1,68 @@ /datum/map var/default_currency = /decl/currency/credits + +/decl/starting_cash_choice + decl_flags = DECL_FLAG_MANDATORY_UID + uid = "starting_cash_account" + var/name = "all in bank account" + var/transfer_mult = 1 + +/decl/starting_cash_choice/proc/get_cash_objects(var/mob/living/human/owner, var/datum/money_account/owner_account) + return + +/decl/starting_cash_choice/credstick + name = "all on charge stick" + uid = "starting_cash_stick" + +/decl/starting_cash_choice/credstick/get_cash_objects(var/mob/living/human/owner, var/datum/money_account/owner_account) + var/obj/item/charge_stick/credstick = new + credstick.creator = owner.real_name + credstick.currency = owner_account.currency + credstick.loaded_worth = min(credstick.max_worth, floor(owner_account.money * transfer_mult)) + owner_account.money -= credstick.loaded_worth + return list(credstick) + +/decl/starting_cash_choice/credstick/half + name = "split between bank account and charge stick" + transfer_mult = 0.5 + uid = "starting_cash_account_stick_split" + +/decl/starting_cash_choice/cash + name = "all in cash" + uid = "starting_cash_cash" + +/decl/starting_cash_choice/cash/get_cash_objects(var/mob/living/human/owner, var/datum/money_account/owner_account) + var/obj/item/cash/cash = new + cash.set_currency(owner_account.currency) + cash.adjust_worth(floor(owner_account.money * transfer_mult)) + owner_account.money -= cash.absolute_worth + return list(cash) + +/decl/starting_cash_choice/cash/half + name = "split between bank account and cash" + transfer_mult = 0.5 + uid = "starting_cash_cash_account_split" + +/decl/starting_cash_choice/split + name = "split between cash and charge stick" + transfer_mult = 0.5 + uid = "starting_cash_cash_stick_split" + +/decl/starting_cash_choice/split/get_cash_objects(var/mob/living/human/owner, var/datum/money_account/owner_account) + . = list() + var/obj/item/cash/cash = new + cash.set_currency(owner_account.currency) + cash.adjust_worth(floor(owner_account.money * transfer_mult)) + . += cash + var/obj/item/charge_stick/credstick = new + credstick.creator = owner.real_name + credstick.currency = owner_account.currency + credstick.loaded_worth = min(credstick.max_worth, floor(owner_account.money * transfer_mult)) + . += credstick + owner_account.money -= cash.absolute_worth + owner_account.money -= credstick.loaded_worth + +/decl/starting_cash_choice/split/even + name = "split between bank account, cash and charge stick" + transfer_mult = 0.33 + uid = "starting_cash_cash_account_stick_split" diff --git a/maps/~mapsystem/maps_events.dm b/maps/~mapsystem/maps_events.dm new file mode 100644 index 000000000000..6740542eb6a7 --- /dev/null +++ b/maps/~mapsystem/maps_events.dm @@ -0,0 +1,4 @@ +/datum/map + var/event_container_mundane = /datum/event_container/mundane + var/event_container_moderate = /datum/event_container/moderate + var/event_container_major = /datum/event_container/major diff --git a/maps/~mapsystem/maps_jobs.dm b/maps/~mapsystem/maps_jobs.dm index ce6fa1ddf4f4..b867bbc4d1dc 100644 --- a/maps/~mapsystem/maps_jobs.dm +++ b/maps/~mapsystem/maps_jobs.dm @@ -3,10 +3,15 @@ var/species_to_job_blacklist = list() var/job_to_species_whitelist = list() var/job_to_species_blacklist = list() - var/default_assistant_title = "Assistant" + + /// Default job title which will be set in some cases. + var/default_job_title + /// Default job type which will be used if map lack of any jobs or for respawn. + var/datum/job/default_job_type = /datum/job + var/decl/department/default_department_type = /decl/department // The white, and blacklist are type specific, any subtypes (of both species and jobs) have to be added explicitly -/datum/map/proc/is_species_job_restricted(var/datum/species/S, var/datum/job/J) +/datum/map/proc/is_species_job_restricted(var/decl/species/S, var/datum/job/J) if(!istype(S) || !istype(J)) return TRUE diff --git a/maps/~mapsystem/maps_unit_testing.dm b/maps/~mapsystem/maps_unit_testing.dm index a90b76df1bc0..2ac13dfa9bb6 100644 --- a/maps/~mapsystem/maps_unit_testing.dm +++ b/maps/~mapsystem/maps_unit_testing.dm @@ -1,7 +1,11 @@ /datum/map - var/const/NO_APC = 1 - var/const/NO_VENT = 2 - var/const/NO_SCRUBBER = 4 + var/const/NO_APC = BITFLAG(0) + var/const/NO_VENT = BITFLAG(1) + var/const/NO_SCRUBBER = BITFLAG(2) + var/const/SKIP_ALL_TESTS = BITFLAG(3) + + /// Defines the expected result of the atmospherics shuttle unit test for atmosphere. + var/shuttle_atmos_expectation = UT_NORMAL // Unit test vars var/list/apc_test_exempt_areas = list( @@ -19,42 +23,25 @@ // These areas are used specifically by code and need to be broken out somehow var/list/area_usage_test_exempted_areas = list( - /area/beach, /area/ship, - /area/centcom, - /area/centcom/holding, - /area/centcom/specops, - /area/chapel, /area/hallway, /area/maintenance, - /area/medical, - /area/medical/virology, - /area/medical/virologyaccess, /area/overmap, - /area/rnd, - /area/rnd/xenobiology, - /area/rnd/xenobiology/xenoflora, - /area/rnd/xenobiology/xenoflora_storage, - /area/security, - /area/security/prison, - /area/security/brig, /area/shuttle, - /area/shuttle/escape, - /area/shuttle/escape/centcom, - /area/shuttle/specops, - /area/shuttle/specops/centcom, - /area/shuttle/syndicate_elite, - /area/shuttle/syndicate_elite/mothership, - /area/shuttle/syndicate_elite/station, - /area/turbolift, - /area/supply, - /area/syndicate_elite_squad, /area/template_noop ) var/list/area_usage_test_exempted_root_areas = list( /area/map_template, - /area/exoplanet + /area/exoplanet, + /area/turbolift ) - var/list/area_purity_test_exempt_areas = list() \ No newline at end of file + var/list/area_purity_test_exempt_areas = list() + + /// A list of disposals tags (sort_type var) that aren't expected to have outputs. + var/list/disconnected_disposals_tags = list() + + /// A list of lists, of the format ((x, y, z, dir),). + var/list/disconnected_wires_test_exempt_turfs = list() + diff --git a/maps/~unit_tests/proximity_tests.dmm b/maps/~unit_tests/proximity_tests.dmm index 9863991734bc..00f65cdf6383 100644 --- a/maps/~unit_tests/proximity_tests.dmm +++ b/maps/~unit_tests/proximity_tests.dmm @@ -6,22 +6,26 @@ /turf/unsimulated/wall, /area/test_area/proximity) "c" = ( -/turf/simulated/floor, +/turf/floor, /area/test_area/proximity) "d" = ( -/turf/simulated/wall, +/turf/wall, /area/test_area/proximity) "e" = ( -/obj/effect/landmark/proximity_spawner, -/turf/simulated/floor, +/obj/abstract/landmark/proximity_spawner, +/turf/floor, /area/test_area/proximity) "f" = ( -/obj/effect/landmark/proximity_wall, -/turf/simulated/wall, +/obj/abstract/landmark/proximity_wall, +/turf/wall, /area/test_area/proximity) +"Q" = ( +/obj/abstract/level_data_spawner/debug, +/turf/space, +/area/space) (1,1,1) = {" -a +Q a a a diff --git a/maps/~unit_tests/unit_testing.dm b/maps/~unit_tests/unit_testing.dm index 73e3e82ff544..f0e625e1f885 100644 --- a/maps/~unit_tests/unit_testing.dm +++ b/maps/~unit_tests/unit_testing.dm @@ -1,6 +1,6 @@ // It's unlikely you'll be able to open these maps without UNIT_TEST defined #ifdef UNIT_TEST - #include "virtual_mob_tests.dmm" #include "proximity_tests.dmm" + #include "unit_tests.dmm" #endif diff --git a/maps/~unit_tests/unit_tests.dmm b/maps/~unit_tests/unit_tests.dmm new file mode 100644 index 000000000000..2acc17c7d1ed --- /dev/null +++ b/maps/~unit_tests/unit_tests.dmm @@ -0,0 +1,846 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/space, +/area/test_area/edge_of_map) +"b" = ( +/turf/unsimulated/wall, +/area/test_area/powered_dynamic_lighting) +"c" = ( +/turf/unsimulated/wall, +/area/test_area/requires_power_dynamic_lighting) +"d" = ( +/turf/unsimulated/floor/hydro, +/area/test_area/powered_dynamic_lighting) +"e" = ( +/turf/unsimulated/floor/hydro, +/area/test_area/requires_power_dynamic_lighting) +"f" = ( +/turf/unsimulated/wall, +/area/test_area/powered_non_dynamic_lighting) +"g" = ( +/turf/unsimulated/wall, +/area/test_area/requires_power_non_dynamic_lighting) +"h" = ( +/obj/abstract/landmark/test/virtual_spawn/two, +/turf/unsimulated/floor/hydro, +/area/test_area/powered_non_dynamic_lighting) +"i" = ( +/turf/unsimulated/floor/hydro, +/area/test_area/powered_non_dynamic_lighting) +"j" = ( +/obj/abstract/landmark/test/virtual_spawn/one, +/turf/unsimulated/floor/hydro, +/area/test_area/powered_non_dynamic_lighting) +"k" = ( +/obj/abstract/landmark/test/virtual_spawn/three, +/turf/unsimulated/floor/hydro, +/area/test_area/powered_non_dynamic_lighting) +"l" = ( +/turf/unsimulated/floor/hydro, +/area/test_area/requires_power_non_dynamic_lighting) +"m" = ( +/turf/unsimulated/wall, +/area/test_area/general) +"n" = ( +/turf/floor, +/area/test_area/general) +"o" = ( +/turf/space, +/area/test_area/general) +"p" = ( +/obj/abstract/landmark/test/safe_turf, +/turf/floor, +/area/test_area/general) +"q" = ( +/obj/abstract/landmark/test/space_turf, +/turf/space, +/area/test_area/general) +"X" = ( +/obj/abstract/level_data_spawner/debug, +/turf/unsimulated/floor/hydro, +/area/test_area/powered_dynamic_lighting) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(4,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(5,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(6,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(7,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(8,1,1) = {" +a +a +a +a +a +a +a +m +m +m +m +m +m +b +b +b +f +f +f +a +a +a +a +a +a +a +"} +(9,1,1) = {" +a +a +a +a +a +a +a +m +n +n +n +n +n +b +d +b +f +h +f +a +a +a +a +a +a +a +"} +(10,1,1) = {" +a +a +a +a +a +a +a +m +n +n +n +n +n +b +d +b +f +i +f +a +a +a +a +a +a +a +"} +(11,1,1) = {" +a +a +a +a +a +a +a +m +n +n +p +n +n +b +d +b +f +j +f +a +a +a +a +a +a +a +"} +(12,1,1) = {" +a +a +a +a +a +a +a +m +n +n +n +n +n +b +b +b +f +f +f +a +a +a +a +a +a +a +"} +(13,1,1) = {" +a +a +a +a +a +a +a +m +n +n +n +n +n +b +X +b +f +k +f +a +a +a +a +a +a +a +"} +(14,1,1) = {" +a +a +a +a +a +a +a +m +m +m +m +m +m +b +b +b +f +f +f +a +a +a +a +a +a +a +"} +(15,1,1) = {" +a +a +a +a +a +a +a +m +m +m +m +m +m +c +c +c +g +g +g +a +a +a +a +a +a +a +"} +(16,1,1) = {" +a +a +a +a +a +a +a +m +o +o +o +o +o +c +e +c +g +l +g +a +a +a +a +a +a +a +"} +(17,1,1) = {" +a +a +a +a +a +a +a +m +o +o +o +o +o +c +e +c +g +l +g +a +a +a +a +a +a +a +"} +(18,1,1) = {" +a +a +a +a +a +a +a +m +o +o +q +o +o +c +e +c +g +l +g +a +a +a +a +a +a +a +"} +(19,1,1) = {" +a +a +a +a +a +a +a +m +o +o +o +o +o +c +c +c +g +g +g +a +a +a +a +a +a +a +"} +(20,1,1) = {" +a +a +a +a +a +a +a +m +o +o +o +o +o +c +e +c +g +l +g +a +a +a +a +a +a +a +"} +(21,1,1) = {" +a +a +a +a +a +a +a +m +m +m +m +m +m +c +c +c +g +g +g +a +a +a +a +a +a +a +"} +(22,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(23,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(24,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(25,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(26,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(27,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(28,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/maps/~unit_tests/virtual_mob_tests.dmm b/maps/~unit_tests/virtual_mob_tests.dmm deleted file mode 100644 index bbd0928e6b96..000000000000 --- a/maps/~unit_tests/virtual_mob_tests.dmm +++ /dev/null @@ -1,671 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/space, -/area/space) -"b" = ( -/turf/unsimulated/wall, -/area/test_area/powered_dynamic_lighting) -"c" = ( -/turf/unsimulated/wall, -/area/test_area/requires_power_dynamic_lighting) -"d" = ( -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/powered_dynamic_lighting) -"e" = ( -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/requires_power_dynamic_lighting) -"f" = ( -/turf/unsimulated/wall, -/area/test_area/powered_non_dynamic_lighting) -"g" = ( -/turf/unsimulated/wall, -/area/test_area/requires_power_non_dynamic_lighting) -"h" = ( -/obj/effect/landmark/virtual_spawn/two, -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/powered_non_dynamic_lighting) -"i" = ( -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/powered_non_dynamic_lighting) -"j" = ( -/obj/effect/landmark/virtual_spawn/one, -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/powered_non_dynamic_lighting) -"k" = ( -/obj/effect/landmark/virtual_spawn/three, -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/powered_non_dynamic_lighting) -"l" = ( -/turf/unsimulated/floor{ - icon_state = "hydrofloor" - }, -/area/test_area/requires_power_non_dynamic_lighting) - -(1,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(2,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(3,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(4,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(5,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(6,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(7,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(8,1,1) = {" -a -a -a -a -a -a -a -b -b -b -f -f -f -a -a -a -a -a -a -a -"} -(9,1,1) = {" -a -a -a -a -a -a -a -b -d -b -f -h -f -a -a -a -a -a -a -a -"} -(10,1,1) = {" -a -a -a -a -a -a -a -b -d -b -f -i -f -a -a -a -a -a -a -a -"} -(11,1,1) = {" -a -a -a -a -a -a -a -b -d -b -f -j -f -a -a -a -a -a -a -a -"} -(12,1,1) = {" -a -a -a -a -a -a -a -b -b -b -f -f -f -a -a -a -a -a -a -a -"} -(13,1,1) = {" -a -a -a -a -a -a -a -b -d -b -f -k -f -a -a -a -a -a -a -a -"} -(14,1,1) = {" -a -a -a -a -a -a -a -b -b -b -f -f -f -a -a -a -a -a -a -a -"} -(15,1,1) = {" -a -a -a -a -a -a -a -c -c -c -g -g -g -a -a -a -a -a -a -a -"} -(16,1,1) = {" -a -a -a -a -a -a -a -c -e -c -g -l -g -a -a -a -a -a -a -a -"} -(17,1,1) = {" -a -a -a -a -a -a -a -c -e -c -g -l -g -a -a -a -a -a -a -a -"} -(18,1,1) = {" -a -a -a -a -a -a -a -c -e -c -g -l -g -a -a -a -a -a -a -a -"} -(19,1,1) = {" -a -a -a -a -a -a -a -c -c -c -g -g -g -a -a -a -a -a -a -a -"} -(20,1,1) = {" -a -a -a -a -a -a -a -c -e -c -g -l -g -a -a -a -a -a -a -a -"} -(21,1,1) = {" -a -a -a -a -a -a -a -c -c -c -g -g -g -a -a -a -a -a -a -a -"} -(22,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(23,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(24,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(25,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(26,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(27,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} -(28,1,1) = {" -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -"} diff --git a/mods/README.md b/mods/README.md new file mode 100644 index 000000000000..c6b7a62b11f8 --- /dev/null +++ b/mods/README.md @@ -0,0 +1,68 @@ +# Modpacks + +## What exactly are modpacks? +Modpacks are, effectively, self-contained (modular) feature bundles. They can contain new objects, new species, new UIs, overrides for existing code, and even more. If you want a feature to be optional on a per-map or per-server basis, while ensuring it's always checked for correctness in unit tests, it should be placed in a modpack. + +## Are modpacks the same as 'module' folders in other codebases? +No. Those were more or less just subdirectories that organized features into conceptual 'modules', but lacked any sort of defined structure or handling, and generally couldn't be selectively enabled or disabled. Nebula's modpacks are more rigorous, with scripts and tests for validation. Each modpack is tested as a unit (along with the base game) as well as in integration with other modpacks on the various included maps. + +## Making a new modpack +All of Nebula's modpacks are kept inside of the `/mods` subdirectory. + +Code inside of a modpack must depend on only itself and stock Nebula code, and not from other modpacks. Cross-modpack code goes elsewhere and is discussed further below. + +Do NOT tick files inside of your modpack, as that'll add it to the base Nebula .dme file. Instead, you must add them to your modpack's .dme file. + +### Modpack .dme +Each modpack contains its own .dme file, as the modpack is more or less a mini codebase contained within the larger stock Nebula codebase. The .dme needs to be at the base of your modpack directory. +By convention, the .dme should share the same name as the modpack itself, with a leading underscore in front. +The first line of the .dme should be an `#ifndef`, and then a define for your modpack, e.g. `#ifndef MODPACK_YOUR_MODPACK_NAME_HERE`. This needs to be unique across the codebase. +The second line should be a `#define`, and then the same thing as before, e.g. `#define MODPACK_YOUR_MODPACK_NAME_HERE`. +Below that, you should `#include` all of the paths of the files which are inside. The paths are relative to where the .dme is. +At the bottom, after all of the `#define`s, you must add `#endif`. Make sure to add `// BEGIN_INCLUDE` and `// END_INCLUDE` after the `#define` and before the `#endif`. + +### Modpack Decl +Every modpack has a `/decl/modpack` subtype. + +By convention, the decl is defined at the base of the modpack directory, with the .dm file sharing the same name as the modpack, with a leading underscore, the same as the .dme file. + +The decl also lets players to see which modpacks a server is currently running, and holds some miscellaneous information to use for things such as dreams and the round-end credits screen. + +You can have code run during server initialization, or the round starting, by overriding `pre_initialize()`, `initialize()`, `post_initialize()`, and `on_roundstart()` on your modpack's decl. + +If your modpack has NanoUI templates, you must set the `nanoui_directory` variable to point to the path of the folder where the templates are, or NanoUI won't be able to find them in-game. + +### Load Order +Modpacks have a defined, user-controlled load order, and cross-modpack compatibility is always handled after all modpacks are loaded. + +### Enabling Your Modpack +Modpacks are enabled on a per-map basis. To activate a modpack, you `#include` the modpack's .dme in a map's .dme file. + +### Overriding Stock Code +TODO: Actually write this section. It's distinct from the "How do I write upstream/core code with extension via modpacks in mind?" part because it's the *opposite,* this section is about overriding core code while the other section is about writing core code to be extended. Maybe do a basic explanation of side-overrides and associated footguns here. + +### Cross-modpack interactions +Sometimes, a modpack that's enabled might need to do something in response to another modpack also being enabled. Compatibility patches allow for this to happen without the modpacks in question requiring a hard dependency on each other. + +An example of such an interaction is that the Supermatter content modpack can give the SM monitoring program to engineering jobs that exist inside the Standard Jobs modpack. Another example is allowing content in the Psionics content modpack to interact with content in the Cult gamemode modpack. + +Cross-modpack code is kept inside of `/mods/~compatibility`. There is another README inside which has more information. + +Some modpacks extend other modpacks and make no sense to include on their own, in which case it's generally okay to make the extension modpack have a hard dependency on the original one by `#include`ing the original modpack's DME in the new one. + +### How do I modpack... +- A subsystem? + - Check the psionics modpack for an example. +- Something small? + - Check the mundane or scaling descriptor modpacks as examples. +- NanoUI templates? + - Check the inertial dampener or supermatter modpacks as examples. (Don't forget to set the nanoui_directory variable on the modpack decl!) + +## Using modpacks as a downstream server +Modular code on a downstream with an upstream that does frequent refactors and rewrites is inevitably going to break when the upstream codebase does anything. Names change, so do assumptions, and even design directions might diverge so far that reconciling them will be hard or even impossible. There's not really getting around that, but we can at least mitigate it by designing stable interfaces and documenting changes. When upstream code is written with modularity in mind, downstreams have a much easier time adding content. + +## How do I write upstream/core code with extension via modpacks in mind? +TODO: Actually write this section. Give examples like `/decl/atmos_grief_fix_step`, `/decl/human_examination`, the cocktails system, etc. Iterating over subtypes of a base type makes it easy for modpacks to add new code. Also maybe address some footguns like trying to make something modular before trying to make it actually work? Could also discuss the open-closed principle I guess, e.g. write code that gets *extended* rather than *modified* (so avoiding side-overrides where possible, etc.). + +# Contribution +Please contribute to this README/guide. It's currently unfinished and doesn't cover a lot of important things. Thanks. \ No newline at end of file diff --git a/mods/_modpack.dm b/mods/_modpack.dm index 0892aec1f7cb..0fb1d5d79089 100644 --- a/mods/_modpack.dm +++ b/mods/_modpack.dm @@ -1,16 +1,27 @@ /decl/modpack - var/name // A string name for the modpack. Used for looking up other modpacks in init. + /// A string name for the modpack. Used for looking up other modpacks in init. + var/name + /// A string desc for the modpack. Can be used for modpack verb list as description. + var/desc + /// A string with authors of this modpack. + var/author + var/secrets_directory + /// The folder to load additional NanoUI templates from. Must be relative to the DME's location (root game folder). + var/nanoui_directory - var/list/dreams // A list of strings to be added to the random dream proc. + var/list/dreams //! A list of strings to be added to the random dream proc. - var/list/credits_other // A list of strings that are used by the end of round credits roll. - var/list/credits_adventure_names // As above. - var/list/credits_crew_names // As above. - var/list/credits_holidays // As above. - var/list/credits_adjectives // As above. - var/list/credits_crew_outcomes // As above. - var/list/credits_topics // As above. - var/list/credits_nouns // As above. + var/list/tabloid_headlines //! A list of headline and article data used by the tabloids modpack. + var/list/tabloid_publishers //! A list of name strings used by the tabloids modpack. + + var/list/credits_other //! A list of strings that are used by the end of round credits roll. + var/list/credits_adventure_names //! A list of strings that are used by the end of round credits roll. + var/list/credits_crew_names //! A list of strings that are used by the end of round credits roll. + var/list/credits_holidays //! A list of strings that are used by the end of round credits roll. + var/list/credits_adjectives //! A list of strings that are used by the end of round credits roll. + var/list/credits_crew_outcomes //! A list of strings that are used by the end of round credits roll. + var/list/credits_topics //! A list of strings that are used by the end of round credits roll. + var/list/credits_nouns //! A list of strings that are used by the end of round credits roll. /decl/modpack/proc/get_player_panel_options(var/mob/M) return @@ -18,6 +29,24 @@ /decl/modpack/proc/pre_initialize() if(!name) return "Modpack name is unset." + if(secrets_directory) + secrets_directory = trim(lowertext(secrets_directory)) + if(!length(secrets_directory)) + return "Modpack secrets_directory is zero length after trim." + if(copytext(secrets_directory, -1) != "/") + secrets_directory = "[secrets_directory]/" + if(!fexists(secrets_directory)) + return "Modpack secrets_directory does not exist." + SSsecrets.load_directories |= secrets_directory + if(nanoui_directory) + nanoui_directory = trim(lowertext(nanoui_directory)) + if(!length(nanoui_directory)) + return "Modpack nanoui_directory is zero length after trim." + if(copytext(nanoui_directory, -1) != "/") + nanoui_directory = "[nanoui_directory]/" + if(!fexists(nanoui_directory)) + return "Modpack nanoui_directory does not exist." + SSmodpacks.modpack_nanoui_directories |= nanoui_directory /decl/modpack/proc/initialize() return @@ -41,3 +70,40 @@ SSlore.credits_topics |= credits_topics if(length(credits_nouns)) SSlore.credits_nouns |= credits_nouns + +/// This runs on-roundstart after roundstart characters have been created. +/decl/modpack/proc/on_roundstart() + return + +/decl/modpack/proc/get_membership_perks() + return + +/client/verb/modpacks_list() + set name = "Modpacks List" + set category = "OOC" + + if(!mob || !SSmodpacks.initialized) + return + + if(SSmodpacks.loaded_modpacks.len) + . = "

    Modpacks List



    " + for(var/modpack in SSmodpacks.loaded_modpacks) + var/decl/modpack/M = SSmodpacks.loaded_modpacks[modpack] + + if(M.name) + . += "
    " + . += "
    [M.name]
    " + + if(M.desc || M.author) + . += "
    " + if(M.desc) + . += "
    Description: [M.desc]" + if(M.author) + . += "
    Author: [M.author]" + . += "

    " + + var/datum/browser/popup = new(mob, "modpacks_list", "Modpacks List", 480, 580) + popup.set_content(.) + popup.open() + else + to_chat(src, SPAN_WARNING("This server does not include any modpacks.")) diff --git a/mods/ascent/_ascent.dme b/mods/ascent/_ascent.dme deleted file mode 100644 index 370a02840480..000000000000 --- a/mods/ascent/_ascent.dme +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef MODPACK_ASCENT -#define MODPACK_ASCENT -// BEGIN_INCLUDE -#include "ascent.dm" -#include "datum\access.dm" -#include "datum\ai_laws.dm" -#include "datum\antagonist.dm" -#include "datum\attacks.dm" -#include "datum\codex.dm" -#include "datum\culture.dm" -#include "datum\descriptors.dm" -#include "datum\emotes.dm" -#include "datum\languages.dm" -#include "datum\species.dm" -#include "effects\razorweb.dm" -#include "items\cell.dm" -#include "items\clothing.dm" -#include "items\clustertool.dm" -#include "items\guns.dm" -#include "items\id_control.dm" -#include "items\rig.dm" -#include "items\suits.dm" -#include "items\tools.dm" -#include "machines\ship_alarm.dm" -#include "machines\ship_machines.dm" -#include "mobs\bodyparts.dm" -#include "mobs\bodyparts_insectoid.dm" -#include "mobs\bodyparts_serpentid.dm" -#include "mobs\drone.dm" -#include "structures\furniture.dm" -#include "structures\ship_furniture.dm" -#include "turfs\ship.dm" -// END_INCLUDE -#endif diff --git a/mods/ascent/ascent.dm b/mods/ascent/ascent.dm deleted file mode 100644 index 5938d3651251..000000000000 --- a/mods/ascent/ascent.dm +++ /dev/null @@ -1,28 +0,0 @@ -#define SPECIES_SERPENTID "Serpentid" -#define SPECIES_MANTID_ALATE "Kharmaan Alate" -#define SPECIES_MANTID_GYNE "Kharmaan Gyne" - -#define BODYTYPE_SNAKE "Snakelike Body" -#define BODYTYPE_MANTID_SMALL "Small Mantid Body" -#define BODYTYPE_MANTID_LARGE "Large Mantid Body" - -#define CULTURE_ASCENT "The Ascent" -#define HOME_SYSTEM_KHARMAANI "Core" -#define FACTION_ASCENT_GYNE "Ascent Gyne" -#define FACTION_ASCENT_ALATE "Ascent Alate" -#define FACTION_ASCENT_SERPENTID "Ascent Serpentid" -#define RELIGION_KHARMAANI "Nest-Lineage Veneration" - -#define MODE_HUNTER "hunter" -#define IS_MANTID "mantid" -#define IS_SERPENTID "serpentid" - -#define MANTIDIFY(_thing, _name, _desc) \ -##_thing/ascent/name = _name; \ -##_thing/ascent/desc = "Some kind of strange alien " + _desc + " technology."; \ -##_thing/ascent/color = COLOR_PURPLE; - -#define ALL_ASCENT_SPECIES list(SPECIES_MANTID_ALATE, SPECIES_MANTID_GYNE, SPECIES_SERPENTID) - -/decl/modpack/ascent - name = "The Ascent" \ No newline at end of file diff --git a/mods/ascent/away_sites/ascent/ascent-1.dmm b/mods/ascent/away_sites/ascent/ascent-1.dmm deleted file mode 100644 index 208849e4f552..000000000000 --- a/mods/ascent/away_sites/ascent/ascent-1.dmm +++ /dev/null @@ -1,19893 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/space, -/area/space) -"ab" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/shuttle_starboard) -"ac" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/fore_starboard_prow) -"ad" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"ae" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"af" = ( -/obj/structure/table/steel_reinforced, -/obj/item/knife/kitchen/cleaver/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"ag" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/wing_starboard) -"ah" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/fore_starboard_prow) -"ai" = ( -/obj/machinery/recharge_station/ascent, -/obj/effect/submap_landmark/spawnpoint/ascent_seedship/drone, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"aj" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/wing_starboard) -"ak" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"al" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/fore_starboard_spike) -"am" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/obj/machinery/door/airlock/external/bolted/ascent{ - airlock_type = "Internal"; - id_tag = "ascent_starboard_inner" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"an" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"aq" = ( -/obj/machinery/portable_atmospherics/hydroponics/ascent, -/obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"ar" = ( -/obj/machinery/ion_engine{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"as" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"av" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/hydroponics_starboard) -"aw" = ( -/obj/machinery/atmospherics/portables_connector, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"ax" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"ay" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"az" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/bridge) -"aA" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_spike) -"aC" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"aD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"aE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"aF" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"aH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"aJ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"aK" = ( -/obj/structure/table/rack/dark, -/obj/item/robot_parts/robot_component/armour/light, -/obj/item/robot_parts/robot_component/armour/light, -/obj/item/robot_parts/robot_component/armour/light, -/obj/item/robot_parts/robot_component/armour/light, -/obj/item/robot_parts/robot_component/armour/light, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"aL" = ( -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_spike) -"aN" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"aO" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"aP" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_spike) -"aQ" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/habitation) -"aR" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"aS" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/fore_port_prow) -"aT" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_starboard) -"aU" = ( -/obj/machinery/computer/ship/helm/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"aW" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"aX" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"aY" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"aZ" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"ba" = ( -/obj/structure/table/rack/dark, -/obj/item/storage/firstaid/surgery, -/obj/item/storage/bag/trash/purple/ascent, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"bb" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"bc" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"bd" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"be" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"bf" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"bg" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"bh" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_spike) -"bi" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"bk" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/obj/effect/overmap/visitable/ship/ascent_seedship, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"bl" = ( -/obj/effect/submap_landmark/spawnpoint/ascent_seedship/alate, -/obj/structure/ascent_spawn, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"bm" = ( -/obj/machinery/computer/ship/engines/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"bn" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/engineering) -"bo" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"bp" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"bq" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - airlock_type = "Internal"; - id_tag = "ascent_dock_starboard_internal" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"br" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"bs" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"bt" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 6 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"bu" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"bv" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"bw" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"bx" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"bz" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/habitation) -"bA" = ( -/obj/effect/submap_landmark/joinable_submap/ascent_seedship, -/turf/simulated/wall/ascent, -/area/ship/ascent/habitation) -"bD" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_seedship_fore_pumps" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"bE" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"bF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"bH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"bI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"bJ" = ( -/obj/structure/table/rack/dark, -/obj/item/robot_parts/robot_component/diagnosis_unit, -/obj/item/robot_parts/robot_component/diagnosis_unit, -/obj/item/robot_parts/robot_component/diagnosis_unit, -/obj/item/robot_parts/robot_component/actuator, -/obj/item/robot_parts/robot_component/actuator, -/obj/item/robot_parts/robot_component/actuator, -/obj/item/robot_parts/robot_component/actuator, -/obj/item/robot_parts/robot_component/actuator, -/obj/item/robot_parts/robot_component/diagnosis_unit, -/obj/item/robot_parts/robot_component/diagnosis_unit, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"bK" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/obj/structure/bed/chair/padded/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"bL" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"bM" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"bN" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"bO" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"bP" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/wing_port) -"bQ" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"bR" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"bS" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 4 - }, -/obj/machinery/fabricator/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"bT" = ( -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/machinery/power/apc/hyper/ascent/west, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"bU" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"bV" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"bW" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/wing_port) -"bX" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"bY" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/obj/structure/cable/cyan, -/obj/machinery/power/apc/hyper/ascent/south, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_starboard) -"bZ" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"ca" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"cc" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"cd" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"ce" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_dock_inner" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"cf" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"cg" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"ch" = ( -/obj/structure/ascent_spawn, -/obj/effect/submap_landmark/spawnpoint/ascent_seedship, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"ci" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"cj" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"ck" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"cl" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"cm" = ( -/obj/structure/ascent_spawn, -/obj/effect/submap_landmark/spawnpoint/ascent_seedship/adjunct, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"cn" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/obj/machinery/button/access/interior{ - id_tag = "ascent_seedship_fore_dock_controller"; - pixel_x = -4; - pixel_y = 24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"cp" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_spike) -"cq" = ( -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"cr" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"cs" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/alarm/ascent{ - pixel_y = 24 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"ct" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"cu" = ( -/obj/machinery/power/apc/hyper/ascent/south, -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/item/storage/bag/trash/purple/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_spike) -"cv" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"cw" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/obj/item/storage/bag/trash/purple/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_spike) -"cx" = ( -/obj/machinery/light/ascent, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_seedship_fore_pumps" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"cy" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/fore_port_prow) -"cz" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"cA" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/hydroponics_port) -"cB" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_spike) -"cC" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 6 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"cD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"cE" = ( -/obj/machinery/door/airlock/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"cF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"cG" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"cH" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"cI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"cJ" = ( -/obj/structure/cable/cyan{ - icon_state = "0-2" - }, -/obj/machinery/power/apc/hyper/ascent/north, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"cK" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"cL" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"cN" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/shuttle_port) -"cO" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"cQ" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"cR" = ( -/obj/structure/reagent_dispensers/water_cooler/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"cS" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"cT" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"cU" = ( -/obj/effect/wallframe_spawn/borosilicate, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"cV" = ( -/obj/effect/wallframe_spawn/borosilicate, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"cW" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"cX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"cY" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"da" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"db" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dc" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"dd" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"de" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"df" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dg" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dh" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"di" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"dj" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"dk" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"dm" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dn" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"do" = ( -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 6 - }, -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"dp" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_port) -"dq" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"dr" = ( -/obj/structure/table/rack/dark, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/plastic/fifty, -/obj/item/stack/material/aluminium/fifty, -/obj/item/stack/material/glass/fifty, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"ds" = ( -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dt" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"du" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dv" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"dw" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"dx" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"dy" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dz" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"dA" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"dB" = ( -/obj/structure/ascent_spawn, -/obj/effect/submap_landmark/spawnpoint/ascent_seedship/queen, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"dC" = ( -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"dD" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_seedship_fore_external" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/button/access/shuttle/exterior{ - id_tag = "ascent_seedship_fore_dock_controller"; - pixel_x = -4; - pixel_y = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"dE" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"dF" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"dG" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/alarm/ascent{ - dir = 8; - pixel_x = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"dH" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"dK" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d2 = 2; - icon_state = "0-2" - }, -/obj/machinery/power/terminal{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"dL" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/structure/table/rack/dark, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"dM" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/table/rack/dark, -/obj/item/chems/glass/beaker, -/obj/item/chems/glass/beaker, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"dN" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"dO" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"dP" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/button/access/interior, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"dQ" = ( -/obj/effect/wallframe_spawn/borosilicate, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"dR" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"dS" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"dT" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"dU" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"dV" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"dW" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1 - }, -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ascent_port_dock_sensor"; - pixel_x = -8; - pixel_y = 24 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"dX" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_dock_inner" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"ea" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent, -/obj/machinery/button/access/shuttle/interior{ - id_tag = "ascent_starboard"; - pixel_y = -24 - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eb" = ( -/obj/structure/cable/cyan{ - icon_state = "0-8" - }, -/obj/machinery/light/ascent{ - dir = 4 - }, -/obj/machinery/power/apc/hyper/ascent/east, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"ec" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"ed" = ( -/obj/structure/cable/cyan{ - icon_state = "0-8" - }, -/obj/machinery/power/ascent_reactor, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"ee" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"ef" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/obj/structure/table/steel_reinforced, -/obj/item/storage/box/beakers, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"eg" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"eh" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"ei" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"ej" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ek" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"el" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"em" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_seedship_fore_pumps" - }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - airflow_dest = "ascent_seedship_fore_dock_controller"; - frequency = 1331; - id_tag = "ascent_seedship_fore_dock_controller"; - pixel_y = 24; - tag_airpump = "ascent_seedship_fore_pumps"; - tag_chamber_sensor = "ascent_seedship_fore_dock_sensor"; - tag_exterior_door = "ascent_seedship_fore_external"; - tag_interior_door = "ascent_seedship_fore_internal" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"en" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"eo" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 2; - id_tag = "ascent_starboard_pump_out_internal" - }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - cycle_to_external_air = 1; - frequency = 1331; - id_tag = "ascent_starboard"; - pixel_x = -24; - pixel_y = 0; - req_access = list("ACCESS_ASCENT"); - tag_exterior_sensor = "ascent_starboard_sensor" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"ep" = ( -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eq" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"er" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_seedship_fore_internal" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"es" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"et" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"eu" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"ev" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - icon_state = "0-2" - }, -/obj/machinery/power/smes/buildable/power_shuttle/ascent{ - charge = 5e+006 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"ew" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_seedship_fore_pumps" - }, -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ascent_seedship_fore_dock_sensor"; - pixel_y = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"ex" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"ey" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/shuttle_landmark/ascent_seedship/start, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_dock_outer" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"ez" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"eA" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/alarm/ascent{ - dir = 8; - pixel_x = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"eB" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/alarm/ascent{ - pixel_y = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eC" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eD" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/machinery/power/terminal{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"eE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"eF" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_dock_outer" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"eH" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"eN" = ( -/obj/machinery/recharge_station/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eO" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - airlock_type = "Internal"; - id_tag = "ascent_starboard_inner" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 6 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eP" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/manifold4w/hidden, -/obj/machinery/door/airlock/external/bolted/ascent{ - airlock_type = "Internal"; - id_tag = "ascent_starboard_inner" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"eR" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/kitchenspike, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"eT" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"eU" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"eV" = ( -/obj/machinery/power/smes/buildable/power_shuttle/ascent{ - charge = 5e+006 - }, -/obj/structure/cable/cyan, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"fa" = ( -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ascent_starboard_sensor"; - pixel_x = -24; - pixel_y = 0 - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_starboard_pump" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"fb" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_starboard_pump" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"fc" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 2; - id_tag = "ascent_starboard_pump_out_internal" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"fe" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_outer" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ff" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"fg" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_shuttle_starboard_vent_inner" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"fh" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_port_dock_pump" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"fi" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_port_dock_pump" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"fj" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fk" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"fl" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fm" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"fn" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - frequency = 1331; - id_tag = "ascent_port_shuttle_dock"; - pixel_x = 24; - tag_airpump = "ascent_port_pump"; - tag_chamber_sensor = "ascent_port_sensor"; - tag_exterior_door = "ascent_port_outer"; - tag_interior_door = "ascent_port_inner" - }, -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ascent_port_sensor"; - pixel_x = 24; - pixel_y = -12 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fo" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fp" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fq" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fr" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 8 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fs" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ft" = ( -/obj/machinery/door/airlock/ascent{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fu" = ( -/obj/machinery/power/terminal, -/obj/structure/cable/cyan{ - d2 = 8; - icon_state = "0-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"fv" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_shuttle_starboard_vent_inner" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"fw" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"fx" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"fy" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_port_pump" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fz" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"fA" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"fB" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fC" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - icon_state = "0-8" - }, -/obj/machinery/power/apc/hyper/ascent/north, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"fD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fE" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"fF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fG" = ( -/obj/machinery/hologram/holopad/longrange/ascent, -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fH" = ( -/obj/machinery/computer/ship/sensors/ascent{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fI" = ( -/obj/machinery/computer/ship/engines/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fJ" = ( -/obj/structure/bed/chair/padded/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"fK" = ( -/obj/structure/bed/chair/padded/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"fL" = ( -/obj/machinery/computer/ship/navigation/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fM" = ( -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fN" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"fO" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"fP" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"fQ" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/fore_port_spike) -"fR" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_spike) -"fS" = ( -/obj/structure/window/borosilicate_reinforced, -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"fT" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"fU" = ( -/obj/machinery/computer/ship/sensors/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"fV" = ( -/obj/structure/table/rack/dark, -/obj/item/tank/mantid/methyl_bromide, -/obj/item/gun/energy/particle/small, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"fW" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"fX" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"fY" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"fZ" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"ga" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/obj/structure/table/steel_reinforced, -/obj/item/storage/box/botanydisk, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gb" = ( -/obj/machinery/atmospherics/binary/pump/high_power{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"gc" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"gd" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ge" = ( -/obj/machinery/light/ascent, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gf" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gg" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"gh" = ( -/obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gi" = ( -/obj/machinery/atmospherics/omni/mixer, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"gj" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"gk" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gl" = ( -/obj/machinery/atmospherics/binary/pump/high_power{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gm" = ( -/obj/machinery/atmospherics/omni/mixer, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gn" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"go" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gp" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"gq" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/black{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/wall/ascent, -/area/ship/ascent/shuttle_starboard) -"gr" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_seedship_fore_pumps" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"gs" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_inner" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gt" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gu" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gv" = ( -/obj/machinery/light/ascent{ - dir = 4 - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - id_tag = "ascent_port_pump" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gw" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gx" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gy" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/power/shield_generator, -/obj/structure/cable/cyan{ - icon_state = "0-8" - }, -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gz" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gA" = ( -/obj/machinery/computer/ship/sensors/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"gB" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold4w/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_hallway) -"gC" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gD" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gE" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gF" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"gG" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"gH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"gI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gJ" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gK" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"gL" = ( -/obj/machinery/portable_atmospherics/canister/empty, -/obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gM" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - icon_state = "0-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/power/smes/buildable/power_shuttle/ascent{ - charge = 5e+006 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gN" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan, -/obj/machinery/power/terminal{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gO" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan, -/obj/machinery/power/smes/buildable/power_shuttle/ascent{ - charge = 5e+006 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gP" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"gQ" = ( -/obj/effect/wallframe_spawn/borosilicate, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"gR" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/obj/structure/bed/chair/padded/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"gS" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"gT" = ( -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"gU" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gV" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gW" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/snacks/meat/syntiflesh, -/obj/item/chems/food/snacks/meat/syntiflesh, -/obj/item/chems/food/snacks/meat/syntiflesh, -/obj/item/chems/food/snacks/meat/beef, -/obj/item/chems/food/snacks/meat/beef, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"gX" = ( -/obj/machinery/portable_atmospherics/canister/empty, -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"gY" = ( -/obj/effect/wallframe_spawn/borosilicate, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"gZ" = ( -/obj/machinery/portable_atmospherics/hydroponics/ascent, -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"ha" = ( -/obj/machinery/ion_engine{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"hb" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"hc" = ( -/obj/structure/bed/chair/padded/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"hd" = ( -/obj/machinery/ion_engine{ - dir = 8 - }, -/turf/simulated/floor/ascent{ - initial_gas = newlist() - }, -/area/ship/ascent/engineering) -"he" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 6 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"hf" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"hg" = ( -/obj/effect/wallframe_spawn/borosilicate, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"hh" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"hi" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"hj" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"hl" = ( -/obj/machinery/shipsensors, -/turf/simulated/floor/ascent{ - initial_gas = newlist() - }, -/area/ship/ascent/engineering) -"hm" = ( -/obj/effect/wallframe_spawn/borosilicate, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"hn" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/obj/structure/kitchenspike, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"ho" = ( -/obj/structure/table/rack/dark, -/obj/item/gun/energy/particle/small, -/obj/item/rig/mantid/gyne, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"hp" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"hr" = ( -/obj/machinery/power/apc/hyper/ascent/north, -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_spike) -"hs" = ( -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_spike) -"ht" = ( -/obj/structure/bed/chair/padded/purple/ascent/gyne, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"hv" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/structure/table/rack/dark, -/obj/item/organ/internal/controller, -/obj/item/organ/internal/controller, -/obj/item/organ/internal/controller, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hw" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/machinery/optable/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hx" = ( -/obj/item/storage/firstaid/surgery, -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hy" = ( -/obj/machinery/light/ascent, -/obj/machinery/optable/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hz" = ( -/obj/structure/table/steel_reinforced, -/obj/item/stack/material/glass/fifty, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"hA" = ( -/obj/structure/table/rack/dark, -/obj/item/clustertool, -/obj/item/clustertool, -/obj/item/clustertool, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"hB" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_spike) -"hC" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_spike) -"hD" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_spike) -"hE" = ( -/obj/structure/kitchenspike, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"hF" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/structure/table/rack/dark, -/obj/item/tank/mantid/methyl_bromide, -/obj/item/gun/energy/particle/small, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"hG" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"hH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"hJ" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 1 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"hK" = ( -/obj/machinery/light/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"hL" = ( -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"hM" = ( -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"hN" = ( -/obj/structure/table/rack/dark, -/obj/item/multitool/mantid, -/obj/item/multitool/mantid, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"hO" = ( -/obj/structure/table/rack/dark, -/obj/item/scanner/gas, -/obj/item/lightreplacer, -/obj/item/lightreplacer, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"hP" = ( -/obj/structure/table/steel_reinforced, -/obj/item/stack/material/glass/reinforced/fifty, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"hQ" = ( -/obj/structure/table/steel_reinforced, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/plastic/fifty, -/obj/item/stack/material/aluminium/fifty, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"hR" = ( -/obj/structure/table/rack/dark, -/obj/item/stack/medical/resin, -/obj/item/stack/medical/resin, -/obj/item/stack/medical/resin, -/obj/item/stack/medical/resin, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hS" = ( -/obj/structure/table/rack/dark, -/obj/item/stack/medical/bruise_pack, -/obj/item/stack/medical/bruise_pack, -/obj/item/stack/medical/ointment, -/obj/item/stack/medical/ointment, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hT" = ( -/obj/structure/table/rack/dark, -/obj/item/stack/medical/splint, -/obj/item/stack/medical/splint, -/obj/item/stack/medical/splint, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"hU" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"hV" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"hX" = ( -/obj/machinery/light/ascent, -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 1 - }, -/obj/item/storage/box/water/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_spike) -"hY" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/food/snacks/meat/syntiflesh, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"hZ" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/food/snacks/meat/beef, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"ia" = ( -/obj/machinery/door/airlock/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"ib" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/obj/item/storage/box/water/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_spike) -"ic" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"id" = ( -/obj/machinery/computer/ship/navigation/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"ie" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_starboard_outer" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/black, -/obj/machinery/button/access/shuttle/exterior{ - id_tag = "ascent_starboard"; - pixel_x = -24; - pixel_y = 0 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"ih" = ( -/obj/structure/cable/cyan{ - d2 = 4; - icon_state = "0-4" - }, -/obj/machinery/power/apc/hyper/ascent/west, -/obj/effect/catwalk_plated/ascent, -/obj/structure/hygiene/sink/ascent{ - dir = 1; - icon_state = "sink"; - pixel_y = 28 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_prow) -"ii" = ( -/obj/machinery/computer/ship/engines/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port{ - dir = 1 - }) -"ij" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ik" = ( -/obj/machinery/ion_engine, -/obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"il" = ( -/obj/machinery/light/ascent, -/obj/structure/table/rack/dark, -/obj/item/tank/mantid/methyl_bromide, -/obj/item/gun/energy/particle/small, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/bridge) -"in" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"io" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/computer/ship/sensors/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ip" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/alarm/ascent{ - dir = 4; - pixel_x = -24 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/computer/ship/navigation/ascent{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iq" = ( -/obj/machinery/light/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"ir" = ( -/obj/machinery/light/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"is" = ( -/obj/structure/cable/cyan, -/obj/machinery/power/apc/hyper/ascent/west, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"it" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/black, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_starboard_outer" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"iv" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/button/access/shuttle/interior{ - id_tag = "ascent_port_shuttle_dock"; - pixel_x = 4; - pixel_y = 24 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iw" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ix" = ( -/obj/structure/bed/chair/padded/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"iA" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iB" = ( -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - frequency = 1331; - id_tag = "ascent_port_dock"; - pixel_x = -24; - pixel_y = 0; - tag_airpump = "ascent_port_dock_pump"; - tag_chamber_sensor = "ascent_port_dock_sensor"; - tag_exterior_door = "ascent_port_dock_outer"; - tag_interior_door = "ascent_port_dock_inner" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"iC" = ( -/obj/machinery/computer/shuttle_control/explore/ascent{ - dir = 1 - }, -/obj/effect/overmap/visitable/ship/landable/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"iD" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iE" = ( -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_dock_starboard_external" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"iG" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/effect/catwalk_plated/ascent, -/obj/effect/shuttle_landmark/ascent_seedship/start/two, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_dock_starboard_external" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"iH" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 4 - }, -/obj/machinery/portable_atmospherics/canister/empty, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iJ" = ( -/obj/machinery/light/ascent{ - dir = 4 - }, -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 1; - id_tag = "ascent_starboard_pump" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"iK" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"iM" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/obj/machinery/alarm/ascent{ - dir = 8; - pixel_x = 24 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"iN" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/visible/universal, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iO" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iP" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/obj/machinery/alarm/ascent{ - dir = 4; - pixel_x = -24 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"iQ" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/external/bolted/ascent{ - airlock_type = "Internal"; - id_tag = "ascent_dock_starboard_internal" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"iR" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/habitation) -"iS" = ( -/obj/machinery/light/ascent{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"iT" = ( -/obj/structure/table/steel_reinforced, -/obj/item/storage/box/water/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"iU" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"iV" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"iW" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/empty, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"iX" = ( -/obj/machinery/shipsensors, -/turf/simulated/floor/ascent{ - initial_gas = newlist() - }, -/area/ship/ascent/shuttle_port) -"ja" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/obj/structure/ore_box{ - color = "PURPLE"; - name = "heavy duty box" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"jb" = ( -/obj/structure/table/rack/dark, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"jc" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 6 - }, -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"jd" = ( -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/alarm/ascent{ - pixel_y = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"je" = ( -/obj/machinery/alarm/ascent{ - pixel_y = 24 - }, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"jf" = ( -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"jg" = ( -/obj/machinery/sleeper/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"jh" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/alarm/ascent{ - pixel_y = 24 - }, -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"ji" = ( -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/engineering) -"jj" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"jk" = ( -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"jl" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"jm" = ( -/obj/machinery/atmospherics/portables_connector, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"jn" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10 - }, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"jo" = ( -/obj/structure/cable/cyan{ - icon_state = "0-8" - }, -/obj/machinery/power/apc/hyper/ascent/south, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"jp" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"jq" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5 - }, -/obj/machinery/light/ascent, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"jr" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ascent_shuttle_starboard_interior_sensor"; - pixel_x = -8; - pixel_y = -24 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"js" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"jt" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"ju" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"jv" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"jw" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/obj/structure/cable/cyan{ - d2 = 2; - icon_state = "0-2" - }, -/obj/machinery/power/apc/hyper/ascent/north, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_port) -"jx" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 4 - }, -/obj/structure/table/steel_reinforced, -/obj/item/scanner/health, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"jy" = ( -/obj/machinery/light/ascent, -/obj/structure/table/steel_reinforced, -/obj/item/robotanalyzer, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"jz" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/light/ascent, -/obj/item/weldingtool/electric/mantid, -/obj/item/weldingtool/electric/mantid, -/turf/simulated/floor/ascent, -/area/ship/ascent/engineering) -"jA" = ( -/obj/machinery/light/ascent, -/obj/structure/table/rack/dark, -/obj/item/clustertool, -/obj/item/multitool/mantid, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"jB" = ( -/obj/item/storage/firstaid/surgery, -/obj/structure/table/steel_reinforced, -/obj/machinery/alarm/ascent{ - pixel_y = 24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"jC" = ( -/obj/machinery/computer/ship/helm/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"jD" = ( -/obj/machinery/computer/ship/navigation/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"jE" = ( -/obj/structure/bed/chair/padded/purple/ascent/gyne, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_prow) -"jF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"jG" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"jH" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"jI" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"jJ" = ( -/obj/machinery/light/ascent, -/obj/machinery/body_scanconsole/ascent{ - dir = 2 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"jK" = ( -/obj/machinery/bodyscanner/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"jL" = ( -/obj/structure/cable/cyan, -/obj/machinery/power/apc/hyper/ascent/south, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_port) -"jM" = ( -/obj/machinery/button/access/exterior/airlock_interior{ - id_tag = "ascent_port_shuttle_dock"; - pixel_x = 24 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_outer" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"jN" = ( -/obj/structure/cable/cyan{ - d2 = 2; - icon_state = "0-2" - }, -/obj/machinery/power/smes/buildable/power_shuttle/ascent{ - charge = 5e+006 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"jO" = ( -/obj/structure/cable/cyan{ - icon_state = "0-4" - }, -/obj/machinery/power/terminal{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"jQ" = ( -/obj/machinery/light/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"jT" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/fore_hallway) -"kp" = ( -/obj/machinery/body_scanconsole/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_port) -"kq" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/hydroponics_starboard) -"kv" = ( -/obj/item/mop/advanced/ascent, -/obj/item/chems/glass/bucket/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_spike) -"kH" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 8; - id_tag = "ascent_starboard_pump_out_external" - }, -/obj/machinery/airlock_sensor/shuttle{ - id_tag = "ascent_starboard_sensor_external"; - pixel_x = -24; - pixel_y = 0 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"lb" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"lk" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"lG" = ( -/obj/structure/table/rack/dark, -/obj/item/gun/energy/particle/small, -/obj/item/gun/energy/particle/small, -/obj/item/gun/energy/particle/small, -/obj/item/gun/energy/particle/small, -/obj/item/tank/jetpack/ascent, -/obj/item/tank/jetpack/ascent, -/obj/item/tank/jetpack/ascent, -/obj/item/tank/jetpack/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"lJ" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"lW" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/aft_starboard_jut) -"md" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"me" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"mg" = ( -/turf/space, -/area/ship/ascent/fore_starboard_jut) -"mn" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"mx" = ( -/obj/machinery/recharge_station/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"mM" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/reagent_temperature{ - color = "PURPLE"; - name = "reactant boiler" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"mN" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"mV" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/aft_starboard_jut) -"mY" = ( -/turf/simulated/wall/ascent, -/area/ship/ascent/fore_starboard_jut) -"na" = ( -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"ng" = ( -/obj/machinery/light/ascent, -/obj/machinery/botany/editor, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_port) -"nh" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"nz" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"nE" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"nV" = ( -/obj/machinery/embedded_controller/radio/airlock/docking_port{ - frequency = 1331; - id_tag = "ascent_starboard_dock"; - pixel_x = -24; - pixel_y = 0; - tag_airpump = "ascent_shuttle_starboard_vent_inner"; - tag_chamber_sensor = "ascent_shuttle_starboard_interior_sensor"; - tag_exterior_door = "ascent_dock_starboard_external"; - tag_interior_door = "ascent_dock_starboard_internal" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"om" = ( -/obj/machinery/chem_master{ - color = "PURPLE"; - name = "chemical analyzer" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"oL" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_starboard) -"oU" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"oV" = ( -/obj/machinery/seed_extractor, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_starboard) -"pp" = ( -/obj/structure/table/rack/dark, -/obj/item/clothing/suit/space/void/ascent, -/obj/item/clothing/suit/space/void/ascent, -/obj/item/clothing/suit/space/void/ascent, -/obj/item/clothing/suit/space/void/ascent, -/obj/item/clothing/head/helmet/space/void/ascent, -/obj/item/clothing/head/helmet/space/void/ascent, -/obj/item/clothing/head/helmet/space/void/ascent, -/obj/item/clothing/head/helmet/space/void/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"pr" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"py" = ( -/obj/machinery/door/airlock/ascent, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/wing_starboard) -"pE" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_port_inner" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"qc" = ( -/turf/space, -/area/ship/ascent/aft_starboard_jut) -"qG" = ( -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"qH" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"qI" = ( -/obj/structure/railing/mapped, -/obj/machinery/light/ascent{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"qR" = ( -/obj/structure/table/steel_reinforced, -/obj/item/chems/dropper, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"rb" = ( -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"re" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_jut) -"sF" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"sM" = ( -/obj/structure/railing/mapped, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"tr" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/aft_starboard_jut) -"tw" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_jut) -"tz" = ( -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"uk" = ( -/obj/machinery/computer/mining{ - color = "PURPLE"; - name = "distributor control"; - pixel_y = 32 - }, -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"uV" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"vt" = ( -/obj/structure/table/rack/dark, -/obj/item/gun/energy/particle, -/obj/item/gun/energy/particle, -/obj/item/gun/energy/particle/small, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"vx" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/reagent_temperature/cooler{ - color = "PURPLE"; - name = "reactant cooler" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"vz" = ( -/obj/machinery/chemical_dispenser/full{ - color = "PURPLE"; - name = "chemical fabricator" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"vF" = ( -/obj/machinery/computer/ship/engines/ascent, -/obj/effect/overmap/visitable/ship/landable/ascent/two, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"vY" = ( -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"wd" = ( -/obj/machinery/door/window/brigdoor{ - color = "PURPLE"; - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"wu" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/obj/machinery/atmospherics/portables_connector, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"wB" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/alarm/ascent{ - dir = 1; - pixel_y = -24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"wM" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"wO" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 2; - id_tag = "ascent_starboard_pump_out_internal" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"wW" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/table/rack/dark, -/obj/item/knife/kitchen/cleaver/ascent, -/obj/item/stack/medical/bruise_pack, -/obj/item/gun/energy/particle/small, -/obj/item/tank/mantid/oxygen, -/obj/item/tank/mantid/oxygen, -/obj/item/tank/mantid/oxygen, -/obj/machinery/alarm/ascent{ - dir = 8; - pixel_x = 24 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"wX" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden, -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"yx" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"yP" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"yU" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"zf" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"zt" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_port) -"zw" = ( -/obj/structure/table/rack/dark, -/obj/item/tank/mantid/reactor/oxygen, -/obj/item/tank/mantid/reactor/oxygen, -/obj/item/tank/mantid/reactor/oxygen, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"zA" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"zB" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"zV" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/aft_starboard_jut) -"Aj" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/hydroponics_port) -"Ap" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"As" = ( -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"Av" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_port) -"AI" = ( -/obj/machinery/mineral/stacking_machine{ - color = "PURPLE"; - input_turf = 4; - name = "materials distributor"; - output_turf = 2 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"BX" = ( -/turf/simulated/wall/r_wall/ascent, -/area/ship/ascent/engineering) -"Cd" = ( -/obj/machinery/computer/shuttle_control/explore/ascent/two, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"CA" = ( -/obj/structure/table/steel_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"CV" = ( -/obj/structure/window/borosilicate_reinforced, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"CW" = ( -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"Ek" = ( -/obj/machinery/atmospherics/portables_connector, -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Es" = ( -/obj/structure/ore_box{ - color = "PURPLE"; - name = "heavy duty box" - }, -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"Ew" = ( -/obj/machinery/seed_storage, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_starboard) -"Ex" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"EB" = ( -/obj/structure/table/steel_reinforced, -/obj/machinery/computer/mining{ - color = "PURPLE"; - name = "compression dynamo control" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"ER" = ( -/obj/structure/table/rack/dark, -/obj/item/pickaxe/diamonddrill/ascent, -/obj/item/pickaxe/diamonddrill/ascent, -/obj/item/pickaxe/diamonddrill/ascent, -/obj/item/pickaxe/diamonddrill/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"Fd" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/aft_starboard_jut) -"Fg" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ - dir = 4; - id_tag = "ascent_starboard_pump_out_external" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"FN" = ( -/obj/item/storage/bag/trash/purple/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_port_spike) -"FO" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/aft_starboard_jut) -"Gd" = ( -/obj/structure/window/borosilicate_reinforced, -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Gl" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Gs" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent{ - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"GB" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/portable_atmospherics/canister/methyl_bromide, -/turf/simulated/floor/ascent, -/area/ship/ascent/hydroponics_starboard) -"GZ" = ( -/obj/structure/window/borosilicate_reinforced, -/obj/structure/table/rack/dark, -/obj/item/clustertool, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/aft_starboard_jut) -"HZ" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"If" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"IQ" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"IZ" = ( -/obj/machinery/atmospherics/unary/vent_pump/on/ascent{ - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"Jp" = ( -/obj/structure/hygiene/sink/ascent{ - pixel_y = -24 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_jut) -"Js" = ( -/obj/machinery/botany/extractor, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_port) -"Jx" = ( -/obj/machinery/hologram/holopad/longrange/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"JC" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"JE" = ( -/obj/structure/table/rack/dark, -/obj/item/rig/mantid/serpentid, -/obj/item/rig/mantid/serpentid, -/obj/item/rig/mantid/serpentid, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"JZ" = ( -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/obj/item/chems/food/drinks/cans/waterbottle/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"Ka" = ( -/obj/structure/table/rack/dark, -/obj/item/rig/mantid, -/obj/item/rig/mantid, -/obj/machinery/light/ascent, -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/obj/machinery/door/window/northright{ - color = "PURPLE" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"Kh" = ( -/obj/machinery/door/airlock/ascent, -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"KO" = ( -/obj/machinery/ion_engine{ - dir = 8 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"Lp" = ( -/obj/structure/table/rack/dark, -/obj/item/rig/mantid, -/obj/item/rig/mantid, -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/obj/machinery/door/window/southright{ - color = "PURPLE" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/bridge) -"LN" = ( -/obj/structure/hygiene/shower/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"MY" = ( -/obj/structure/ore_box{ - color = "PURPLE"; - name = "heavy duty box" - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"MZ" = ( -/obj/machinery/light/ascent{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Nv" = ( -/obj/structure/table/rack/dark, -/obj/item/storage/bag/trash/purple/ascent, -/obj/machinery/power/apc/hyper/ascent/south, -/obj/structure/cable/cyan{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"NJ" = ( -/obj/machinery/light/ascent{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"NO" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 10 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"NR" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"Ob" = ( -/obj/structure/bed/chair/padded/purple/ascent/gyne, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"Of" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d2 = 2; - icon_state = "0-2" - }, -/obj/machinery/power/apc/hyper/ascent/north, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"Os" = ( -/obj/structure/table/rack/dark, -/obj/item/storage/ore{ - color = "PURPLE"; - name = "mineral carrier" - }, -/obj/item/storage/ore{ - color = "PURPLE"; - name = "mineral carrier" - }, -/obj/item/storage/ore{ - color = "PURPLE"; - name = "mineral carrier" - }, -/obj/item/storage/ore{ - color = "PURPLE"; - name = "mineral carrier" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"Ou" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"OZ" = ( -/obj/machinery/mineral/unloading_machine{ - color = "PURPLE"; - input_turf = 2; - name = "mineral collector"; - output_turf = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"Pv" = ( -/obj/machinery/mineral/processing_unit{ - color = "PURPLE"; - input_turf = 4; - name = "compression dynamo"; - output_turf = 8 - }, -/obj/structure/railing/mapped, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"Qm" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"Qs" = ( -/obj/machinery/biogenerator, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_port) -"Qw" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"Qy" = ( -/obj/structure/table/rack/dark, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/obj/item/storage/bag/trash/purple/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"Qz" = ( -/obj/machinery/ion_engine{ - dir = 1 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"QJ" = ( -/obj/structure/window/borosilicate_reinforced, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"QT" = ( -/obj/structure/hygiene/shower/ascent{ - icon_state = "shower"; - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"QY" = ( -/obj/machinery/light/ascent{ - dir = 1 - }, -/obj/machinery/chem_master, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/hydroponics_starboard) -"RI" = ( -/obj/machinery/hologram/holopad/longrange/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"RK" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"Sp" = ( -/obj/structure/bed/chair/padded/purple/ascent/gyne{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_starboard) -"Sv" = ( -/obj/structure/closet/crate/freezer/meat/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_port_spike) -"TL" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"TN" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"TO" = ( -/obj/structure/hygiene/shower/ascent{ - icon_state = "shower"; - dir = 8 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_hallway) -"TV" = ( -/obj/machinery/reagentgrinder{ - color = "PURPLE"; - name = "reactant obliterator" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"Uy" = ( -/obj/structure/cable/cyan{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) -"UQ" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4; - level = 2 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"UX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 9 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Vf" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Vr" = ( -/obj/structure/table/rack/dark, -/obj/item/tank/mantid/reactor, -/obj/item/tank/mantid/reactor, -/obj/item/tank/mantid/reactor, -/obj/item/tank/mantid/reactor, -/turf/simulated/floor/ascent, -/area/ship/ascent/habitation) -"Vx" = ( -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 4 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_prow) -"Vz" = ( -/obj/machinery/optable/ascent, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"VB" = ( -/obj/structure/reagent_dispensers/water_cooler/ascent, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"VC" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"VR" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/door/airlock/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"WI" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"Xa" = ( -/obj/effect/catwalk_plated/ascent, -/obj/machinery/atmospherics/pipe/manifold/hidden/black, -/obj/machinery/door/airlock/external/bolted/ascent{ - id_tag = "ascent_starboard_outer" - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Xk" = ( -/obj/structure/cable/cyan{ - icon_state = "0-4" - }, -/obj/effect/catwalk_plated/ascent, -/obj/machinery/power/apc/hyper/ascent/south, -/obj/machinery/light/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_jut) -"Xp" = ( -/obj/structure/bed/chair/padded/purple/ascent{ - dir = 8 - }, -/obj/effect/catwalk_plated/ascent, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_port) -"Xt" = ( -/turf/space, -/area/ship/ascent/shuttle_port) -"XG" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate/hull, -/turf/simulated/floor/ascent, -/area/ship/ascent/aft_starboard_jut) -"XM" = ( -/turf/simulated/floor/ascent{ - initial_gas = newlist() - }, -/area/ship/ascent/shuttle_port) -"Yh" = ( -/obj/machinery/shipsensors, -/obj/structure/window/borosilicate_reinforced{ - dir = 4 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"Zh" = ( -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/fore_starboard_jut) -"Zn" = ( -/obj/machinery/power/apc/hyper/ascent/north, -/obj/structure/cable/cyan{ - icon_state = "0-4" - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/wing_starboard) -"Zx" = ( -/obj/structure/window/borosilicate_reinforced{ - dir = 8 - }, -/obj/structure/window/borosilicate_reinforced{ - dir = 1 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/shuttle_starboard) -"ZF" = ( -/obj/machinery/computer/ship/helm/ascent{ - dir = 1 - }, -/turf/simulated/floor/tiled/ascent, -/area/ship/ascent/shuttle_port) -"ZK" = ( -/obj/effect/catwalk_plated/ascent, -/obj/structure/cable/cyan{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/turf/simulated/floor/ascent, -/area/ship/ascent/fore_starboard_prow) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(8,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(9,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(10,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(11,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(12,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(13,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(14,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(15,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(16,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(17,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(18,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(19,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(20,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(21,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(22,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(23,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(24,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(25,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -al -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -fQ -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(26,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hs -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(27,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hs -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(28,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hs -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(29,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -al -aL -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hs -fQ -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(30,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -aL -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hs -hs -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(31,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aP -aA -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -fR -hD -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(32,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -aA -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -fR -hs -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(33,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -aA -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -fR -FN -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(34,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aL -aA -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -fR -FN -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(35,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aA -aA -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -fR -Sv -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(36,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -aA -cu -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hr -kv -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(37,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -bh -cw -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hB -hX -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(38,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -al -cp -cB -al -aa -aa -aa -aa -aa -aa -aa -aa -aa -fQ -hC -ib -fQ -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(39,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ac -ac -cE -ac -ac -aa -jT -jT -dD -jT -jT -aa -aS -aS -hG -aS -aS -aS -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(40,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ac -ac -vz -aF -dC -dL -ac -bX -jT -em -el -gr -jT -dN -aS -fO -hb -hn -hE -aS -aS -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(41,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -cL -om -as -as -as -dM -ac -cH -ah -bD -gB -cx -cy -ee -aS -fP -cv -cv -cv -af -dT -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(42,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -cL -TV -as -vx -as -dC -Uy -dR -ah -ew -eq -gr -cy -fN -fO -hb -hi -jv -cv -af -dT -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(43,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -cL -qR -as -mM -as -as -hH -jQ -ah -jT -er -jT -cy -hJ -hb -jE -hi -cv -cv -hi -dT -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(44,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -cL -CA -as -mN -as -as -as -hV -ah -cn -es -ct -cy -eh -cv -cv -hi -jv -cv -hi -dT -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(45,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mg -cL -CA -as -as -as -as -as -hV -ah -cJ -et -jk -cy -ei -cv -cv -cv -cv -hK -aS -aS -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(46,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mg -mY -mY -ac -uk -Vx -as -as -as -dG -ia -bp -ez -bp -aY -eA -cv -cv -cv -cv -cv -aS -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(47,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mY -mY -mY -mY -mY -ac -AI -vY -as -aX -ah -ah -ah -di -gg -dE -cy -cy -cy -gF -cv -cv -cv -dT -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(48,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -pr -nE -CV -tz -nE -ac -qI -mN -as -cO -bT -ah -LN -bd -gg -bd -QT -cy -ih -hp -cv -hc -hY -dT -aa -cN -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(49,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -pr -tz -QJ -tz -JZ -ac -Pv -EB -ZK -bi -hj -ia -bp -bp -cf -bp -bp -aY -cS -fT -cv -hc -hZ -dT -aa -ik -WI -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(50,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mY -mY -mY -wd -zB -wd -yP -ac -sM -mN -Ap -bV -Os -ah -TO -bd -gg -bd -TO -cy -iT -dk -cv -hc -ic -dT -aa -ik -WI -VB -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(51,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -pr -qG -qG -Zh -Zh -Zh -Zh -ac -OZ -Es -Ap -as -ER -ah -aQ -aQ -dP -aQ -aQ -cy -cR -cv -cv -hK -aS -aS -aa -cN -WI -cQ -cQ -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(52,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -pr -Vz -qG -re -Ex -tw -Jp -ac -lk -lk -Ap -aX -ah -ah -cW -bb -br -bb -dF -cy -cy -cv -cv -hc -ic -dT -aa -cN -je -cQ -cQ -fx -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(53,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mY -mY -mY -ba -qG -aR -yx -qG -Xk -ac -as -as -Ap -as -aQ -pp -bt -bN -bU -bN -cz -JE -aQ -cv -cv -hc -hY -dT -aa -cN -WI -Xp -qH -cQ -cQ -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(54,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mY -tz -tz -mY -pr -pr -mY -eR -gS -TL -Kh -lb -lb -mn -as -hm -Vr -br -bb -eb -bb -br -zw -hm -cv -cv -hc -hZ -dT -aa -ik -eT -fq -qH -Ob -cQ -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(55,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -mY -mY -Ou -wW -ac -as -as -as -as -aQ -lG -br -bu -bz -fJ -br -vt -aQ -cv -cv -hK -aS -aS -aa -ik -WI -fr -qH -cQ -cQ -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(56,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -UQ -aa -aa -aa -mY -mY -mY -ac -as -as -aX -ah -aQ -As -bE -bK -bA -gR -fA -uV -aQ -cy -cv -hc -gW -dT -aa -ik -iM -fs -gT -iS -gT -cN -cN -Xt -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(57,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -Ek -MZ -sF -ab -IQ -ad -ad -ab -Qz -aa -aa -ac -as -as -as -ah -bl -bb -br -iR -bz -fJ -br -bb -cm -cy -cv -hc -ic -aS -cN -cN -cN -ft -cN -cN -cN -cN -cN -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(58,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -Zx -VC -HZ -ab -aw -zA -cT -wX -bH -MY -ab -ab -Qz -aa -ac -as -as -as -ah -ch -bb -br -bb -cc -bb -br -bb -dB -cy -cv -hc -hY -aS -cN -jN -fj -fz -eH -io -ip -is -gT -cN -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(59,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -TN -aa -aa -aa -ab -ab -ab -ab -Gl -ae -dH -eN -ab -Qz -Fg -ac -as -as -as -ah -bl -bb -bF -cz -bb -bt -cF -bb -cm -cy -cv -cv -cv -aS -cN -jO -iH -gd -ij -cQ -bs -cQ -zf -cN -XM -iX -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(60,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -gA -ae -fw -Gs -ae -ea -ab -ab -ab -gq -ac -ac -iQ -ah -ah -cW -bb -bb -br -bb -br -bb -bb -dF -cy -cy -ce -aS -aS -cN -ej -iO -cN -iv -cQ -cQ -cQ -ZF -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(61,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -id -in -ae -ae -ae -dH -eO -fa -eo -ie -iE -fv -jq -ag -bb -bb -az -az -bO -az -bO -az -az -bb -bb -bP -do -fh -ey -fe -fy -fl -gs -iw -cQ -cQ -ix -iC -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(62,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -vF -RI -ae -Sp -ae -ep -eP -fb -fc -it -iG -fg -jr -ag -az -az -az -be -bR -az -bR -be -az -az -az -bP -dW -fi -eF -jM -gv -fn -pE -iw -cQ -cQ -cQ -ii -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(63,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -Cd -in -ae -ae -ae -ex -am -iJ -wO -Xa -iE -fv -js -ag -az -ck -fL -be -iU -az -bR -be -fL -ck -az -bP -dX -bW -bW -cN -cN -cN -cN -iA -cQ -Jx -cQ -cQ -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(64,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -aU -ae -iq -IZ -ae -eC -ab -ab -ab -gq -aj -aj -bq -az -az -bm -cY -be -bR -fG -bR -be -fK -fI -az -az -gE -iB -bW -cN -fm -fo -gt -iD -cQ -cQ -cQ -zf -cN -XM -XM -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(65,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -Yh -aa -aa -aa -ab -ab -ab -ab -eB -ae -fu -eV -ab -Qz -kH -aj -nV -bx -az -fV -ck -fH -be -cg -fB -fF -be -fH -ck -fV -az -jd -dA -bW -cN -eU -fp -gu -gT -gT -gT -gT -gT -cN -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(66,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -Vf -md -Gd -ab -wu -nh -VR -yU -ae -Nv -ab -ab -Qz -aa -aj -an -fW -az -dq -be -be -be -be -bR -be -be -be -be -dx -az -jF -cl -bW -cN -cN -cN -ft -cN -cN -cN -cN -cN -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(67,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -Ek -NJ -UX -ab -ad -ad -ad -ab -Qz -aa -aa -aj -cG -gG -aN -bc -bc -bc -bc -bc -bk -bc -bc -bc -bc -fD -aN -jG -bQ -dU -aa -ik -iP -gu -gT -jc -jl -cN -cN -Xt -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(68,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ab -ab -ab -ab -ab -aa -aa -aa -aa -lW -lW -lW -aj -bg -gH -az -be -be -be -be -bv -bo -bL -be -be -be -jo -az -jI -jH -dU -aa -ik -Qm -iw -gT -jj -jp -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(69,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -lW -JC -CW -aj -ak -bI -az -hF -ck -fL -be -jC -fM -jD -be -fL -ck -il -az -gI -bQ -dU -aa -ik -oU -gw -iN -jt -iV -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(70,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -rb -rb -lW -XG -XG -lW -GZ -JC -CW -aj -ag -cj -az -az -bm -cY -be -bm -ht -fU -be -fK -fI -az -az -gJ -bW -bW -aa -cN -ja -gD -iN -ju -iW -dV -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(71,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -lW -lW -tr -tr -zV -tr -na -na -aj -ai -bI -aK -az -ck -fH -be -be -be -be -be -fH -ck -az -hS -gI -bQ -bW -aa -cN -jb -cQ -cQ -ir -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(72,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -XG -tr -tr -tr -Fd -If -NR -aj -ag -aC -bJ -az -az -az -Lp -fM -ho -fM -Ka -az -az -az -hT -gI -jJ -bW -aa -cN -Qy -cQ -mx -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(73,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -XG -tr -tr -tr -tr -Qw -na -aj -ai -bI -bS -hO -jA -az -az -cU -cU -cU -az -az -hv -hR -jx -gI -kp -dU -aa -ik -WI -cQ -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(74,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -lW -lW -Of -wM -lJ -RK -ag -Zn -bI -aO -aZ -ak -jf -ag -bf -ci -ca -bP -jg -bQ -cd -da -gI -jK -dU -aa -ik -WI -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(75,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -qc -XG -FO -tr -NO -nz -py -aW -cq -cr -cI -cI -cI -cK -du -ek -du -gx -gz -gz -gz -gC -gK -jL -bW -aa -cN -cN -cN -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(76,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -XG -tr -mV -me -wB -aj -dw -ak -ax -ak -ak -ak -aj -dt -en -dv -bP -jB -bQ -bQ -dc -bQ -hx -bW -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(77,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -XG -FO -tr -na -NR -aj -aj -dr -ax -ak -jy -ag -ag -dO -en -ji -bP -hw -bQ -bQ -dc -bQ -hy -bW -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(78,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -lW -na -na -na -aj -aj -gQ -ay -ag -ag -BX -BX -BX -eu -bn -BX -bP -bP -bP -dd -dQ -bW -bW -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(79,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -lW -lW -lW -kq -QY -oL -aD -bY -bn -gL -db -eg -eE -eg -gU -gX -BX -jw -cD -Av -ng -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(80,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -lW -KO -KO -KO -av -oV -oL -aE -ef -bn -gL -df -ds -fE -ds -gV -gX -BX -jh -cX -Av -Js -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(81,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -Ew -oL -aH -fX -cV -gL -dn -bw -gy -bM -jn -gX -cV -ga -dh -Av -Qs -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(82,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -aq -aJ -aT -fY -cV -hz -dy -ev -gM -gO -ds -hQ -cV -gk -dp -he -gZ -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(83,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -aq -dS -hL -gb -cV -hA -dy -dK -eD -gN -ds -hN -cV -gl -hM -hf -gZ -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(84,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -av -gY -de -fY -cV -hA -dy -bZ -ec -fS -ds -hN -cV -gk -ge -hg -cA -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(85,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -aq -dS -cC -gi -BX -hP -dy -dg -ed -gh -ds -jz -BX -gm -go -hf -gZ -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(86,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -aq -gP -dj -gj -BX -BX -cs -dm -ff -hU -ds -BX -BX -gn -gp -hh -gZ -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(87,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -av -av -dz -gc -kq -BX -fC -ds -ds -ds -ds -BX -Aj -jm -gf -cA -cA -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(88,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -dz -gc -kq -hd -BX -ds -fk -ds -BX -hd -Aj -jm -gf -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(89,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -fZ -gc -kq -aa -hd -BX -BX -BX -hd -aa -Aj -jm -iK -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(90,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -hL -GB -kq -aa -aa -hd -hl -hd -aa -aa -Aj -zt -hM -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(91,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -av -hL -hL -kq -aa -aa -aa -aa -aa -aa -aa -Aj -hM -hM -cA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(92,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ha -av -GB -kq -aa -aa -aa -aa -aa -aa -aa -Aj -zt -cA -ar -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(93,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ha -av -kq -aa -aa -aa -aa -aa -aa -aa -Aj -cA -ar -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(94,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ha -kq -aa -aa -aa -aa -aa -aa -aa -Aj -ar -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(95,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ha -aa -aa -aa -aa -aa -aa -aa -ar -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(96,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(97,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(98,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(99,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(100,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(101,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(102,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(103,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(104,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(105,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(106,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(107,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(108,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(109,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(110,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(111,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(112,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(113,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(114,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(115,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(116,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(117,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(118,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(119,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(120,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} diff --git a/mods/ascent/away_sites/ascent/ascent.dm b/mods/ascent/away_sites/ascent/ascent.dm deleted file mode 100644 index fff14f7ea0cb..000000000000 --- a/mods/ascent/away_sites/ascent/ascent.dm +++ /dev/null @@ -1,55 +0,0 @@ -#include "../../_ascent.dme" -#include "ascent_areas.dm" -#include "ascent_jobs.dm" -#include "ascent_shuttles.dm" - -// Map template data. -/datum/map_template/ruin/away_site/ascent_seedship - name = "\improper Ascent seedship" - id = "awaysite_ascent_seedship" - description = "A small Ascent colony ship." - suffixes = list("ascent/ascent-1.dmm") - cost = 0.5 - shuttles_to_initialise = list( - /datum/shuttle/autodock/overmap/ascent, - /datum/shuttle/autodock/overmap/ascent/two - ) - -// Overmap objects. -/obj/effect/overmap/visitable/ship/ascent_seedship - name = "\improper Ascent seedship" - desc = "Wake signature indicates a small to medium sized vessel of unknown design." - vessel_mass = 6500 - fore_dir = WEST - max_speed = 1/(1 SECOND) - hide_from_reports = TRUE - initial_restricted_waypoints = list( - "Trichoptera" = list("nav_hangar_ascent_one"), - "Lepidoptera" = list("nav_hangar_ascent_two") - ) - -/obj/effect/submap_landmark/joinable_submap/ascent_seedship - name = "\improper Ascent seedship" - archetype = /decl/submap_archetype/ascent_seedship - submap_datum_type = /datum/submap/ascent - -/obj/effect/submap_landmark/joinable_submap/ascent_seedship/Initialize(mapload) - var/list/all_elements = list( - "Hydrogen", "Helium", "Lithium", "Beryllium", "Carbon", "Nitrogen", "Oxygen", - "Fluorine", "Neon", "Sodium", "Magnesium", "Silicon", "Phosphorus", "Sulfur", - "Chlorine", "Argon", "Potassium", "Calcium", "Scandium", "Titanium", "Chromium", - "Manganese", "Iron", "Cobalt", "Nickel", "Zinc", "Gallium", "Germanium", - "Arsenic", "Selenium", "Bromine", "Krypton", "Rubidium", "Strontium", "Zirconium", - "Molybdenum", "Technetium", "Ruthenium", "Rhodium", "Palladium", "Silver", "Cadmium", - "Indium", "Tin", "Antimony", "Tellurium", "Iodine", "Xenon", "Caesium", - "Barium", "Lanthanum", "Cerium", "Praseodymium", "Neodymium", "Promethium", "Samarium", - "Gadolinium", "Dysprosium", "Holmium", "Erbium", "Ytterbium", "Hafnium", "Tantalum", - "Tungsten", "Rhenium", "Osmium", "Iridium", "Gold", "Mercury", "Lead", - "Bismuth", "Polonium", "Astatine", "Radon", "Francium", "Radium", "Actinium", - "Thorium", "Uranium", "Plutonium", "Americium", "Curium", "Berkelium", "Californium", - "Einsteinium", "Fermium", "Mendelevium", "Nobelium", "Lawrencium", "Rutherfordium", "Dubnium", - "Seaborgium", "Bohrium", "Hassium", "Meitnerium", "Darmstadtium", "Roentgenium", "Copernicium", - "Nihonium", "Flerovium", "Moscovium", "Livermorium", "Tennessine", "Oganesson" - ) - name = "[pick(all_elements)]-[rand(10,99)]-[rand(10,99)]" - . = ..() diff --git a/mods/ascent/away_sites/ascent/ascent_areas.dm b/mods/ascent/away_sites/ascent/ascent_areas.dm deleted file mode 100644 index 5ceaeb4bdf00..000000000000 --- a/mods/ascent/away_sites/ascent/ascent_areas.dm +++ /dev/null @@ -1,69 +0,0 @@ -/area/ship/ascent - name = "\improper Ascent Seedship" - area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED - base_turf = /turf/space - req_access = list(access_ascent) - -/area/ship/ascent/bridge - name = "\improper Ascent Seedship - Command Chamber" - icon_state = "bridge" - -/area/ship/ascent/habitation - name = "\improper Ascent Seedship - Habitation Chamber" - icon_state = "conf" - -/area/ship/ascent/wing_port - name = "\improper Ascent Seedship - Hospital Chamber" - icon_state = "entry_1" - -/area/ship/ascent/wing_starboard - name = "\improper Ascent Seedship - Maintenance Chamber" - icon_state = "entry_2" - -/area/ship/ascent/engineering - name = "\improper Ascent Seedship - Power Chamber" - icon_state = "engine_smes" - -/area/ship/ascent/hydroponics_starboard - name = "\improper Ascent Seedship - Starboard Hydroponics Chamber" - icon_state = "green" - -/area/ship/ascent/hydroponics_port - name = "\improper Ascent Seedship - Port Hydroponics Chamber" - icon_state = "hydro" - -/area/ship/ascent/shuttle_port - name = "\improper Trichoptera" - icon_state = "shuttlered" - -/area/ship/ascent/shuttle_starboard - name = "\improper Lepidoptera" - icon_state = "shuttlered" - -/area/ship/ascent/fore_hallway - name = "\improper Ascent Seedship - Antechamber" - icon_state = "dk_yellow" - -/area/ship/ascent/fore_starboard_prow - name = "\improper Ascent Seedship - Fabrication Bay" - icon_state = "armory" - -/area/ship/ascent/fore_starboard_jut - name = "\improper Ascent Seedship - Holding Cells" - icon_state = "purple" - -/area/ship/ascent/aft_starboard_jut - name = "\improper Ascent Seedship - Auxillary Storage" - icon_state = "green" - -/area/ship/ascent/fore_port_prow - name = "\improper Ascent Seedship - Feeding Chamber" - icon_state = "cafeteria" - -/area/ship/ascent/fore_port_spike - name = "\improper Ascent Seedship - Fore Port Spike" - icon_state = "purple" - -/area/ship/ascent/fore_starboard_spike - name = "\improper Ascent Seedship - Fore Starboard Spike" - icon_state = "ai" \ No newline at end of file diff --git a/mods/ascent/away_sites/ascent/ascent_jobs.dm b/mods/ascent/away_sites/ascent/ascent_jobs.dm deleted file mode 100644 index 96fb0b69432d..000000000000 --- a/mods/ascent/away_sites/ascent/ascent_jobs.dm +++ /dev/null @@ -1,185 +0,0 @@ -#define WEBHOOK_SUBMAP_LOADED_ASCENT "webhook_submap_ascent" - -// Submap datum and archetype. -/decl/webhook/submap_loaded/ascent - id = WEBHOOK_SUBMAP_LOADED_ASCENT - -/decl/submap_archetype/ascent_seedship - descriptor = "Ascent colony ship" - map = "\improper Ascent seedship" - blacklisted_species = null - whitelisted_species = null - crew_jobs = list( - /datum/job/submap/ascent, - /datum/job/submap/ascent/alate, - /datum/job/submap/ascent/drone - ) - call_webhook = WEBHOOK_SUBMAP_LOADED_ASCENT - -/datum/submap/ascent - var/gyne_name - -/datum/submap/ascent/sync_cell(obj/effect/overmap/visitable/cell) - return - -/datum/submap/ascent/check_general_join_blockers(var/mob/new_player/joining, var/datum/job/submap/job) - . = ..() - if(. && istype(job, /datum/job/submap/ascent)) - var/datum/job/submap/ascent/ascent_job = job - if(ascent_job.set_species_on_join == SPECIES_MANTID_GYNE && !is_species_whitelisted(joining, SPECIES_MANTID_GYNE)) - to_chat(joining, SPAN_WARNING("You are not whitelisted to play a [SPECIES_MANTID_GYNE].")) - return FALSE - if(ascent_job.set_species_on_join == SPECIES_SERPENTID && !is_species_whitelisted(joining, SPECIES_SERPENTID)) - to_chat(joining, SPAN_WARNING("You are not whitelisted to play a [SPECIES_SERPENTID].")) - return FALSE - -/mob/living/carbon/human/proc/gyne_rename_lineage() - set name = "Name Nest-Lineage" - set category = "IC" - set desc = "Rename yourself and your alates." - - if(species.name == SPECIES_MANTID_GYNE && mind && istype(mind.assigned_job, /datum/job/submap/ascent)) - var/datum/job/submap/ascent/ascent_job = mind.assigned_job - var/datum/submap/ascent/cutter = ascent_job.owner - if(istype(cutter)) - - var/new_number = input("What is your position in your lineage?", "Name Nest-Lineage") as num|null - if(!new_number) - return - new_number = Clamp(new_number, 1, 999) - var/new_name = sanitize(input("What is the true name of your nest-lineage?", "Name Nest-Lineage") as text|null, MAX_NAME_LEN) - if(!new_name) - return - - if(species.name != SPECIES_MANTID_GYNE || !mind || mind.assigned_job != ascent_job) - return - - // Rename ourselves. - fully_replace_character_name("[new_number] [new_name]") - - // Rename our alates (and only our alates). - cutter.gyne_name = new_name - for(var/mob/living/carbon/human/H in GLOB.human_mob_list) - if(!H.mind || H.species.name != SPECIES_MANTID_ALATE) - continue - var/datum/job/submap/ascent/temp_ascent_job = H.mind.assigned_job - if(!istype(temp_ascent_job) || temp_ascent_job.owner != ascent_job.owner) - continue - - - var/new_alate_number = is_species_whitelisted(H, SPECIES_MANTID_GYNE) ? random_id(/datum/species/mantid, 1000, 9999) : random_id(/datum/species/mantid, 10000, 99999) - H.fully_replace_character_name("[new_alate_number] [new_name]") - to_chat(H, SPAN_NOTICE("Your gyne, [real_name], has awakened, and you recall your place in the nest-lineage: [H.real_name].")) - - verbs -= /mob/living/carbon/human/proc/gyne_rename_lineage - -// Jobs. -/datum/job/submap/ascent - title = "Ascent Gyne" - total_positions = 1 - supervisors = "nobody but yourself" - info = "You are the Gyne of an independent Ascent vessel. Your hunting has brought you to this remote sector full of crawling primitives. Impose your will, found a new nest, and bring prosperity to your lineage." - outfit_type = /decl/hierarchy/outfit/job/ascent - blacklisted_species = null - whitelisted_species = null - loadout_allowed = FALSE - is_semi_antagonist = TRUE - var/requires_supervisor = FALSE - var/set_species_on_join = SPECIES_MANTID_GYNE - min_skill = list( - SKILL_LITERACY = SKILL_ADEPT, - SKILL_EVA = SKILL_ADEPT, - SKILL_PILOT = SKILL_ADEPT, - SKILL_HAULING = SKILL_ADEPT, - SKILL_COMBAT = SKILL_ADEPT, - SKILL_WEAPONS = SKILL_ADEPT, - SKILL_SCIENCE = SKILL_ADEPT, - SKILL_MEDICAL = SKILL_BASIC - ) - -/datum/job/submap/ascent/is_position_available() - . = ..() - if(. && requires_supervisor) - for(var/mob/M in GLOB.player_list) - if(!M.client || !M.mind || !M.mind.assigned_job || M.mind.assigned_job.title != requires_supervisor) - continue - var/datum/job/submap/ascent/ascent_job = M.mind.assigned_job - if(istype(ascent_job) && ascent_job.owner == owner) - return TRUE - return FALSE - -/datum/job/submap/ascent/is_available(client/caller) - . = ..() - if(.) - switch(set_species_on_join) - if(SPECIES_MANTID_GYNE) - . = is_species_whitelisted(caller.mob, SPECIES_MANTID_GYNE) - if(SPECIES_SERPENTID) - . = is_species_whitelisted(caller.mob, SPECIES_SERPENTID) - -/datum/job/submap/ascent/handle_variant_join(var/mob/living/carbon/human/H, var/alt_title) - - if(ispath(set_species_on_join, /mob/living/silicon/robot)) - return H.Robotize(set_species_on_join) - if(ispath(set_species_on_join, /mob/living/silicon/ai)) - return H.AIize(set_species_on_join, move = FALSE) - - var/datum/submap/ascent/cutter = owner - if(!istype(cutter)) - crash_with("Ascent submap job is being used by a non-Ascent submap, aborting variant join.") - return - - if(!cutter.gyne_name) - cutter.gyne_name = create_gyne_name() - - if(set_species_on_join) - H.set_species(set_species_on_join) - switch(H.species.name) - if(SPECIES_MANTID_GYNE) - H.real_name = "[random_id(/datum/species/mantid, 1, 99)] [cutter.gyne_name]" - H.verbs |= /mob/living/carbon/human/proc/gyne_rename_lineage - if(SPECIES_MANTID_ALATE) - var/new_alate_number = is_species_whitelisted(H, SPECIES_MANTID_GYNE) ? random_id(/datum/species/mantid, 1000, 9999) : random_id(/datum/species/mantid, 10000, 99999) - H.real_name = "[new_alate_number] [cutter.gyne_name]" - H.name = H.real_name - if(H.mind) - H.mind.name = H.real_name - return H - -/datum/job/submap/ascent/alate - title = "Ascent Alate" - total_positions = 4 - supervisors = "the Gyne" - info = "You are an Alate of an independent Ascent vessel. Your Gyne has directed you to this remote sector full of crawling primitives. Follow her instructions and bring prosperity to your nest-lineage." - set_species_on_join = SPECIES_MANTID_ALATE - outfit_type = /decl/hierarchy/outfit/job/ascent/tech - requires_supervisor = "Ascent Gyne" - min_skill = list( - SKILL_LITERACY = SKILL_ADEPT, - SKILL_EVA = SKILL_ADEPT, - SKILL_HAULING = SKILL_ADEPT, - SKILL_COMBAT = SKILL_ADEPT, - SKILL_WEAPONS = SKILL_ADEPT, - SKILL_MEDICAL = SKILL_BASIC - ) - -/datum/job/submap/ascent/drone - title = "Ascent Drone" - supervisors = "the Gyne" - total_positions = 2 - info = "You are a Machine Intelligence of an independent Ascent vessel. The Gyne you assist, and her children, have wandered into this sector full of primitive bioforms. Try to keep them alive, and assist where you can." - set_species_on_join = /mob/living/silicon/robot/flying/ascent - requires_supervisor = "Ascent Gyne" - -// Spawn points. -/obj/effect/submap_landmark/spawnpoint/ascent_seedship - name = "Ascent Gyne" - movable_flags = MOVABLE_FLAG_EFFECTMOVE - -/obj/effect/submap_landmark/spawnpoint/ascent_seedship/alate - name = "Ascent Alate" - -/obj/effect/submap_landmark/spawnpoint/ascent_seedship/drone - name = "Ascent Drone" - -#undef WEBHOOK_SUBMAP_LOADED_ASCENT diff --git a/mods/ascent/away_sites/ascent/ascent_shuttles.dm b/mods/ascent/away_sites/ascent/ascent_shuttles.dm deleted file mode 100644 index b612580ecb48..000000000000 --- a/mods/ascent/away_sites/ascent/ascent_shuttles.dm +++ /dev/null @@ -1,67 +0,0 @@ -// Submap shuttles. -// Trichoptera - Shuttle One, Port Side -// Lepidoptera - Shuttle Two, Starboard Side -/obj/effect/overmap/visitable/ship/landable/ascent - name = "Trichoptera" - shuttle = "Trichoptera" - moving_state = "ship_moving" - max_speed = 1/(2 SECONDS) - burn_delay = 1 SECONDS - vessel_mass = 5000 - fore_dir = SOUTH - skill_needed = SKILL_BASIC - vessel_size = SHIP_SIZE_SMALL - -/obj/effect/overmap/visitable/ship/landable/ascent/two - name = "Lepidoptera" - shuttle = "Lepidoptera" - fore_dir = NORTH - -/obj/machinery/computer/shuttle_control/explore/ascent - name = "shuttle control console" - shuttle_tag = "Trichoptera" - icon_state = "ascent" - icon_keyboard = "ascent_key" - icon_screen = "ascent_screen" - req_access = list(access_ascent) - -/obj/machinery/computer/shuttle_control/explore/ascent/two - name = "shuttle control console" - shuttle_tag = "Lepidoptera" - -/obj/effect/shuttle_landmark/ascent_seedship/start - name = "Trichoptera Docked" - landmark_tag = "nav_hangar_ascent_one" - docking_controller = "ascent_port_dock" - base_area = /area/ship/ascent/wing_port - movable_flags = MOVABLE_FLAG_EFFECTMOVE - -/obj/effect/shuttle_landmark/ascent_seedship/start/two - name = "Lepidoptera Docked" - landmark_tag = "nav_hangar_ascent_two" - docking_controller = "ascent_starboard_dock" - base_area = /area/ship/ascent/wing_starboard - -/datum/shuttle/autodock/overmap/ascent - name = "Trichoptera" - warmup_time = 5 - current_location = "nav_hangar_ascent_one" - range = 2 - dock_target = "ascent_port_shuttle_dock" - shuttle_area = /area/ship/ascent/shuttle_port - defer_initialisation = TRUE - flags = SHUTTLE_FLAGS_PROCESS - skill_needed = SKILL_BASIC - ceiling_type = /turf/simulated/floor/shuttle_ceiling/ascent - -/datum/shuttle/autodock/overmap/ascent/two - name = "Lepidoptera" - warmup_time = 5 - current_location = "nav_hangar_ascent_two" - range = 2 - dock_target = "ascent_starboard" - shuttle_area = /area/ship/ascent/shuttle_starboard - defer_initialisation = TRUE - flags = SHUTTLE_FLAGS_PROCESS - skill_needed = SKILL_NONE - ceiling_type = /turf/simulated/floor/shuttle_ceiling/ascent \ No newline at end of file diff --git a/mods/ascent/datum/access.dm b/mods/ascent/datum/access.dm deleted file mode 100644 index 41eab6352933..000000000000 --- a/mods/ascent/datum/access.dm +++ /dev/null @@ -1,5 +0,0 @@ -/var/const/access_ascent = "ACCESS_ASCENT" -/datum/access/ascent - id = access_ascent - desc = "Ascent Materiel" - access_type = ACCESS_TYPE_NONE diff --git a/mods/ascent/datum/antagonist.dm b/mods/ascent/datum/antagonist.dm deleted file mode 100644 index 9767c02a553f..000000000000 --- a/mods/ascent/datum/antagonist.dm +++ /dev/null @@ -1,51 +0,0 @@ -GLOBAL_DATUM_INIT(hunters, /datum/antagonist/hunter, new) - -/datum/antagonist/hunter - id = MODE_HUNTER - role_text = "Hunter" - role_text_plural = "Hunters" - flags = ANTAG_HAS_LEADER | ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT - leader_welcome_text = "You are a gyne of the Ascent, and command a brood of alates. Your task is to \ - take control of this sector so that you may found a new fortress-nest. Identify and capture local resources, \ - and remove anything that might threaten your progeny." - welcome_text = "You are an alate of the Ascent, tasked with ridding this sector of whatever your matriarch directs you to, \ - preparing it for the foundation of a new fortress-nest. Obey your gyne and bring prosperity to your nest-lineage." - leader_welcome_text - antaghud_indicator = "hudhunter" - antag_indicator = "hudhunter" - hard_cap = 10 - hard_cap_round = 10 - initial_spawn_req = 4 - initial_spawn_target = 6 - -/datum/antagonist/hunter/update_antag_mob(var/datum/mind/player, var/preserve_appearance) - . = ..() - if(ishuman(player.current)) - var/mob/living/carbon/human/H = player.current - if(!leader && is_species_whitelisted(player.current, SPECIES_MANTID_GYNE)) - leader = player - if(H.species.get_root_species_name() != SPECIES_MANTID_GYNE) - H.set_species(SPECIES_MANTID_GYNE) - H.gender = FEMALE - else - if(H.species.get_root_species_name() != SPECIES_MANTID_ALATE) - H.set_species(SPECIES_MANTID_ALATE) - H.gender = MALE - var/decl/cultural_info/culture/ascent/ascent_culture = SSlore.get_culture(CULTURE_ASCENT) - H.real_name = ascent_culture.get_random_name(H.gender) - H.name = H.real_name - -/datum/antagonist/hunter/equip(var/mob/living/carbon/human/player) - . = ..() - if(.) - if(player.species.get_root_species_name(player) == SPECIES_MANTID_GYNE) - equip_rig(/obj/item/rig/mantid/gyne, player) - else - equip_rig(/obj/item/rig/mantid, player) - player.put_in_hands(new /obj/item/gun/energy/particle) - -/datum/antagonist/hunter/equip_rig(rig_type, mob/living/carbon/human/player) - var/obj/item/rig/mantid/rig = ..() - if(rig) - rig.visible_name = player.real_name - return rig diff --git a/mods/ascent/datum/attacks.dm b/mods/ascent/datum/attacks.dm deleted file mode 100644 index 837eb42e8409..000000000000 --- a/mods/ascent/datum/attacks.dm +++ /dev/null @@ -1,13 +0,0 @@ - -/decl/natural_attack/serpentid - attack_verb = list("mauled", "slashed", "struck", "pierced") - attack_noun = list("forelimb") - damage = 8 - shredding = 1 - sharp = 1 - edge = 1 - delay = 20 - eye_attack_text = "a forelimb" - eye_attack_text_victim = "a forelimb" - attack_name = "forelimb slash" - usable_with_limbs = list(BP_L_HAND, BP_R_HAND) \ No newline at end of file diff --git a/mods/ascent/datum/codex.dm b/mods/ascent/datum/codex.dm deleted file mode 100644 index 47398781372c..000000000000 --- a/mods/ascent/datum/codex.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/codex_entry/ascent - display_name = "The Ascent" - associated_strings = list("ascent") - associated_paths = list( - /mob/living/silicon/robot/flying/ascent, - /obj/item/multitool/mantid, - /obj/item/weldingtool/electric/mantid, - /obj/item/cell/mantid, - /obj/item/gun/energy/particle, - /obj/item/gun/energy/particle/small - ) - lore_text = "The Ascent is a hostile alien culture located rimward of the settled territories.\ - Little is known about them, and diplomatic channels do not currently exist outside of informal \ - contacts with individual seedships or warships. They are insectoid, crystalline, and seem to have \ - a rigid heirarchial society structured around their massive queen 'gynes'." diff --git a/mods/ascent/datum/culture.dm b/mods/ascent/datum/culture.dm deleted file mode 100644 index 7f1b970f9a1e..000000000000 --- a/mods/ascent/datum/culture.dm +++ /dev/null @@ -1,138 +0,0 @@ -GLOBAL_LIST_INIT(gyne_names, list()) - -/proc/get_gyne_name() - return GLOB.gyne_names.len ? pick(GLOB.gyne_names) : create_gyne_name() - -/proc/create_gyne_name() - var/gynename = "[capitalize(pick(GLOB.gyne_architecture))] [capitalize(pick(GLOB.gyne_geoforms))]" - GLOB.gyne_names += gynename - return gynename - -//Thanks to: -// - https://en.wikipedia.org/wiki/List_of_landforms -// - https://en.wikipedia.org/wiki/Outline_of_classical_architecture - -GLOBAL_LIST_INIT(gyne_geoforms, list( - "abime", "abyss", "ait", "anabranch", "arc", "arch", "archipelago", "arete", - "arroyo", "atoll", "ayre", "badlands", "bar", "barchan", "barrier", "basin", - "bay", "bayou", "beach", "bight", "blowhole", "blowout", "bluff", "bornhardt", - "braid", "nest", "calanque", "caldera", "canyon" , "cape", "cave", "cenote", - "channel", "cirque", "cliff", "coast", "col", "colony", "cone", "confluence", - "corrie", "cove", "crater", "crevasse", "cryovolcano", "cuesta", "cusps", "yardang", - "dale", "dam", "defile", "dell", "delta", "diatreme", "dike", "divide", - "doab", "doline", "dome", "draw", "dreikanter", "drumlin", "dune", "ejecta", - "erg", "escarpment", "esker", "estuary", "fan", "fault", "field", "firth", - "fissure", "fjard", "fjord", "flat", "flatiron", "floodplain", "foibe", "foreland", - "geyser", "glacier", "glen", "gorge", "graben", "gulf", "gully", "guyot", - "headland", "hill", "hogback", "hoodoo", "horn", "horst", "inlet", "interfluve", - "island", "islet", "isthmus", "kame", "karst", "karst", "kettle", "kipuka", - "knoll", "lagoon", "lake", "lavaka", "levee", "loess", "maar", "machair", - "malpas", "mamelon", "marsh", "meander", "mesa", "mogote", "monadnock", "moraine", - "moulin", "nunatak", "oasis", "outwash", "pediment", "pediplain", "peneplain", "peninsula", - "pingo", "pit" , "plain", "plateau", "plug", "polje", "pond", "potrero", - "pseudocrater", "quarry", "rapid", "ravine", "reef", "ria", "ridge", "riffle", - "river", "sandhill", "sandur", "scarp", "scowle", "scree", "seamount", "shelf", - "shelter", "shield", "shoal", "shore", "sinkhole", "sound", "spine", "spit", - "spring", "spur", "strait", "strandflat", "strath", "stratovolcano", "stream", "subglacier", - "summit", "supervolcano", "surge", "swamp", "table", "tepui", "terrace", "terracette", - "thalweg", "tidepool", "tombolo", "tor", "towhead", "tube", "tunnel", "turlough", - "tuya", "uvala", "vale", "valley", "vent", "ventifact", "volcano", "wadi", - "waterfall", "watershed" -)) - -GLOBAL_LIST_INIT(gyne_architecture, list( - "barrel", "annular", "aynali", "baroque", "catalan", "cavetto", "catenary", "cloister", - "corbel", "cross", "cycloidal", "cylindrical", "diamond", "domical", "fan", "lierne", - "muqarnas", "net", "nubian", "ogee", "ogival", "parabolic", "hyperbolic", "volute", - "quadripartite", "rampant", "rear", "rib", "sail", "sexpartite", "shell", "stalactite", - "stellar", "stilted", "surbased", "surmounted", "timbrel", "tierceron", "tripartite", "tunnel", - "grid", "acroterion ", "aedicule", "apollarium", "aegis", "apse", "arch", "architrave", - "archivolt", "amphiprostyle", "atlas", "bracket", "capital", "caryatid", "cella", "colonnade", - "column", "cornice", "crepidoma", "crocket", "cupola", "decastyle", "dome", "eisodos", - "entablature", "epistyle ", "euthynteria", "exedra", "finial", "frieze", "gutta", "imbrex", - "tegula", "keystone", "metope", "naos", "nave", "opisthodomos", "orthostates", "pediment", - "peristyle", "pilaster", "plinth", "portico", "pronaos", "prostyle", "quoin", "stoa", - "suspensura", "term ", "tracery", "triglyph", "sima", "stylobate", "unitary", "sovereign", - "grand", "supreme", "rampant", "isolated", "standalone", "seminal", "pedagogical", "locus", - "figurative", "abstract", "aesthetic", "grandiose", "kantian", "pure", "conserved", "brutalist", - "extemporary", "theological", "theoretical", "centurion", "militant", "eusocial", "prominent", "empirical", - "key", "civic", "analytic", "formal", "atonal", "tonal", "synchronized", "asynchronous", - "harmonic", "discordant", "upraised", "sunken", "life", "order", "chaos", "systemic", - "system", "machine", "mechanical", "digital", "electrical", "electronic", "somatic", "cognitive", - "mobile", "immobile", "motile", "immotile", "environmental", "contextual", "stratified", "integrated", - "ethical", "micro", "macro", "genetic", "intrinsic", "extrinsic", "academic", "literary", - "artisan", "absolute", "absolutist", "autonomous", "collectivist", "bicameral", "colonialist", "federal", - "imperial", "independant", "managed", "multilateral", "neutral", "nonaligned", "parastatal" -)) - -/decl/cultural_info/culture/ascent - name = CULTURE_ASCENT - language = /decl/language/mantid/nonvocal - default_language = /decl/language/mantid - additional_langs = list(/decl/language/mantid/worldnet, /decl/language/mantid) - hidden = TRUE - description = "The Ascent is an ancient, isolated stellar empire composed of the mantid-cephalopodean \ - Kharmaani, the Serpentids, and their gaggle of AI servitors. Day to day existence in the Ascent is \ - largely a matter of navigating a bewildering labyrinth of social obligations, gyne power dynamics, factional \ - tithing, protection rackets, industry taxes and plain old interpersonal backstabbing. Both member cultures of \ - this stellar power are eusocial to an extent, and their society is shaped around the teeming masses \ - of workers, soldiers, technicians and 'lesser' citizens supporting a throng of imperious and all-powerful queens." - -/decl/cultural_info/culture/ascent/get_random_name(var/gender) - if(gender == MALE) - return "[random_id(/datum/species/mantid, 10000, 99999)] [get_gyne_name()]" - else - return "[random_id(/datum/species/mantid, 1, 99)] [get_gyne_name()]" - -/decl/cultural_info/location/kharmaani - name = HOME_SYSTEM_KHARMAANI - language = /decl/language/mantid/nonvocal - description = "The Kharmaani are not terribly imaginative when it comes to naming their worlds. Core, \ - their birth star, supports the humid greenhouse-gas-choked giant called Home, which the majority of the \ - populace call their motherland. While the planet's orbit is thickly populated with habitats, factories \ - and defense platforms, each belonging to a different node in the ever-shifting political web of Ascent \ - social culture, the surface itself is a pristine monument to the Kharmaan evolutionary past." - hidden = TRUE - -/decl/cultural_info/faction/ascent_serpentid - name = FACTION_ASCENT_SERPENTID - language = /decl/language/mantid/nonvocal - description = "Members of the Ascent tend to be organized along the natural lines of their respective species. \ - For Kharmaani, this is oriented around individual gynes and their power structures. Serpentids have a slightly less \ - manipulative approach, as well as more numerous and less self-absorbed queens. They tend to cluster in broad social groups, \ - usually within the designated oxygen-rich 'mezzanines' each fortress-nest happily allocates to them. As mild as they are by \ - comparison to their fellows, Serpentid political and social culture is still factional and often vicious." - hidden = TRUE - -/decl/cultural_info/faction/ascent_alate - name = FACTION_ASCENT_ALATE - language = /decl/language/mantid/nonvocal - description = "The life of an alate is a difficult and frequently short one. Those who survive \ - to maturity have had the violent and uncompromising culture of the Ascent beaten into them with \ - bladed forelimbs for their entire lives. There is no formal schooling within the Kharmaani \ - populations of the Ascent, as alates are so numerous and short-lived that it is something of a \ - waste of resources. However, as they mature, a smart and capable alate will amass an education \ - in practical and theoretical disciplines like piloting, engineering, farming or any number of \ - fields. A particularly lucky (or non-lethally gelded) alate can aspire to a position within the \ - retinue of their mother-gyne, where they will receive directed specialist training and an \ - important role under the careful supervision of the gyne's AI control minds." - hidden = TRUE - -/decl/cultural_info/faction/ascent_gyne - name = FACTION_ASCENT_GYNE - language = /decl/language/mantid/nonvocal - description = "By the time a gyne has survived her 'childhood' and shed the exoskeleton of an \ - alate during a breeding frenzy, she has obtained a master class education in murdering and eating \ - her rivals at the first opportunity, as well as a sideline in a technical or practical field. The \ - rapid growth of her body and brain, and the responsibilities of her position, require every gyne to \ - supplement this with intensive training in management, logistics, military command, sociology, politics \ - and any number of the other critical fields tied into managing a fortress-nest of tens of thousands of \ - individual citizens." - hidden = TRUE - -/decl/cultural_info/religion/kharmaani - name = RELIGION_KHARMAANI - description = "To the Kharmaani, the gyne is the embodiment of both the soul of the land she rules, and the \ - power and prosperity of the genetic lineage she contains. The closest thing they have to spirituality is the \ - veneration of their mother, and the protection and preservation of their worlds." - hidden = TRUE diff --git a/mods/ascent/datum/descriptors.dm b/mods/ascent/datum/descriptors.dm deleted file mode 100644 index d9eb4639345d..000000000000 --- a/mods/ascent/datum/descriptors.dm +++ /dev/null @@ -1,28 +0,0 @@ -/datum/mob_descriptor/body_length - name = "body length" - comparative_value_descriptor_equivalent = "around the same length as yours" - standalone_value_descriptors = list( - "short and stubby", - "rather short", - "of average length", - "quite long", - "extremely long" - ) - comparative_value_descriptors_smaller = list( - "a bit shorter in length than yours", - "shorter in length than yours", - "much shorter in length than yours", - "tiny in comparison to yours" - ) - comparative_value_descriptors_larger = list( - "slightly longer than yours", - "longer than yours", - "much longer than yours", - "easily twice your length" - ) - -/datum/mob_descriptor/body_length/get_first_person_message_start() - return "Your body is" - -/datum/mob_descriptor/body_length/get_third_person_message_start(var/datum/gender/my_gender) - return "[my_gender.His] body is" \ No newline at end of file diff --git a/mods/ascent/datum/emotes.dm b/mods/ascent/datum/emotes.dm deleted file mode 100644 index a4f0b157cfdb..000000000000 --- a/mods/ascent/datum/emotes.dm +++ /dev/null @@ -1,58 +0,0 @@ -/datum/species/mantid - default_emotes = list( - /decl/emote/audible/ascent_purr, - /decl/emote/audible/ascent_hiss, - /decl/emote/audible/ascent_snarl, - /decl/emote/visible/ascent_flicker, - /decl/emote/visible/ascent_glint, - /decl/emote/visible/ascent_glimmer, - /decl/emote/visible/ascent_pulse, - /decl/emote/visible/ascent_shine, - /decl/emote/visible/ascent_dazzle - ) - -/mob/living/silicon/robot/flying/ascent - default_emotes = list( - /decl/emote/audible/ascent_purr, - /decl/emote/audible/ascent_hiss, - /decl/emote/audible/ascent_snarl - ) - -/decl/emote/audible/ascent_purr - key = "purr" - emote_message_3p = "USER purrs." - emote_sound = 'mods/ascent/sounds/ascent1.ogg' - -/decl/emote/audible/ascent_hiss - key ="hiss" - emote_message_3p = "USER hisses." - emote_sound = 'mods/ascent/sounds/razorweb.ogg' - -/decl/emote/audible/ascent_snarl - key = "snarl" - emote_message_3p = "USER snarls." - emote_sound = 'mods/ascent/sounds/razorweb_hiss.ogg' - -/decl/emote/visible/ascent_flicker - key = "flicker" - emote_message_3p = "USER flickers prismatically." - -/decl/emote/visible/ascent_glint - key = "glint" - emote_message_3p = "USER glints." - -/decl/emote/visible/ascent_glimmer - key = "glimmer" - emote_message_3p = "USER glimmers." - -/decl/emote/visible/ascent_pulse - key = "pulse" - emote_message_3p = "USER pulses with light." - -/decl/emote/visible/ascent_shine - key = "shine" - emote_message_3p = "USER shines brightly!" - -/decl/emote/visible/ascent_dazzle - key = "dazzle" - emote_message_3p = "USER dazzles!" diff --git a/mods/ascent/datum/languages.dm b/mods/ascent/datum/languages.dm deleted file mode 100644 index a585e0dbccf5..000000000000 --- a/mods/ascent/datum/languages.dm +++ /dev/null @@ -1,101 +0,0 @@ -/decl/language/mantid - name = "Ascent-Voc" - desc = "A curt, sharp language developed by the insectoid Ascent for use over comms." - speech_verb = "clicks" - ask_verb = "chirps" - exclaim_verb = "rasps" - colour = "alien" - syllables = list("-","=","+","_","|","/") - space_chance = 0 - key = "|" - flags = RESTRICTED - shorthand = "KV" - machine_understands = FALSE - var/list/correct_mouthbits = list( - SPECIES_MANTID_ALATE, - SPECIES_MANTID_GYNE, - SPECIES_SERPENTID - ) - -/decl/language/mantid/can_be_spoken_properly_by(var/mob/speaker) - var/mob/living/S = speaker - if(!istype(S)) - return FALSE - if(S.isSynthetic()) - return TRUE - if(ishuman(speaker)) - var/mob/living/carbon/human/H = speaker - if(H.species.name in correct_mouthbits) - return TRUE - return FALSE - -/decl/language/mantid/muddle(var/message) - message = replacetext(message, "...", ".") - message = replacetext(message, "!?", ".") - message = replacetext(message, "?!", ".") - message = replacetext(message, "!", ".") - message = replacetext(message, "?", ".") - message = replacetext(message, ",", "") - message = replacetext(message, ";", "") - message = replacetext(message, ":", "") - message = replacetext(message, ".", "...") - message = replacetext(message, "'", "'") - return message - -/decl/language/mantid/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) - . = ..(speaker, message, speaker.real_name) - -/decl/language/mantid/nonvocal - key = "]" - name = "Ascent-Glow" - desc = "A complex visual language of bright bio-luminescent flashes, 'spoken' natively by the Kharmaani of the Ascent." - colour = "alien" - speech_verb = "flashes" - ask_verb = "gleams" - exclaim_verb = "flares" - flags = RESTRICTED | NO_STUTTER | NONVERBAL - shorthand = "KNV" - -#define MANTID_SCRAMBLE_CACHE_LEN 20 -/decl/language/mantid/nonvocal/scramble(var/input) - if(input in scramble_cache) - var/n = scramble_cache[input] - scramble_cache -= input - scramble_cache[input] = n - return n - var/i = length(input) - var/scrambled_text = "" - while(i) - i-- - scrambled_text += "*" - scramble_cache[input] = scrambled_text - if(scramble_cache.len > MANTID_SCRAMBLE_CACHE_LEN) - scramble_cache.Cut(1, scramble_cache.len-MANTID_SCRAMBLE_CACHE_LEN-1) - return scrambled_text -#undef MANTID_SCRAMBLE_CACHE_LEN - -/decl/language/mantid/nonvocal/can_speak_special(var/mob/living/speaker) - if(istype(speaker) && speaker.isSynthetic()) - return TRUE - else if(ishuman(speaker)) - var/mob/living/carbon/human/H = speaker - return (H.species.name == SPECIES_MANTID_ALATE || H.species.name == SPECIES_MANTID_GYNE) - return FALSE - -/decl/language/mantid/worldnet - key = "\[" - name = "Worldnet" - desc = "The mantid aliens of the Ascent maintain an extensive self-supporting broadcast network for use in team communications." - colour = "alien" - speech_verb = "flashes" - ask_verb = "gleams" - exclaim_verb = "flares" - flags = RESTRICTED | NO_STUTTER | NONVERBAL | HIVEMIND - shorthand = "KB" - -/decl/language/mantid/worldnet/check_special_condition(var/mob/living/carbon/other) - if(istype(other, /mob/living/silicon/robot/flying/ascent)) - return TRUE - if(istype(other) && (locate(/obj/item/organ/internal/controller) in other.internal_organs)) - return TRUE - return FALSE diff --git a/mods/ascent/datum/species.dm b/mods/ascent/datum/species.dm deleted file mode 100644 index d61ead909306..000000000000 --- a/mods/ascent/datum/species.dm +++ /dev/null @@ -1,513 +0,0 @@ -/datum/species/mantid - - name = SPECIES_MANTID_ALATE - name_plural = "Kharmaan Alates" - show_ssd = "quiescent" - - description = "When human surveyors finally arrived at the outer reaches of explored space, they hoped to find \ - new frontiers and new planets to exploit. They were largely not expecting to have entire expeditions lost \ - amid reports of highly advanced, astonishingly violent mantid-cephlapodean sentients with particle cannons." - - icobase = 'mods/ascent/icons/species/body/alate/body.dmi' - deform = 'mods/ascent/icons/species/body/alate/body.dmi' - damage_overlays = 'mods/ascent/icons/species/body/alate/damage_mask.dmi' - blood_mask = 'mods/ascent/icons/species/body/alate/blood_mask.dmi' - organs_icon = 'mods/ascent/icons/species/body/organs.dmi' - bodytype = BODYTYPE_MANTID_SMALL - - blood_color = "#660066" - flesh_color = "#009999" - hud_type = /datum/hud_data/mantid - move_trail = /obj/effect/decal/cleanable/blood/tracks/snake - - speech_chance = 100 - speech_sounds = list( - 'mods/ascent/sounds/ascent1.ogg', - 'mods/ascent/sounds/ascent2.ogg', - 'mods/ascent/sounds/ascent3.ogg', - 'mods/ascent/sounds/ascent4.ogg', - 'mods/ascent/sounds/ascent5.ogg', - 'mods/ascent/sounds/ascent6.ogg' - ) - - siemens_coefficient = 0.2 // Crystalline body. - oxy_mod = 0.8 // Don't need as much breathable gas as humans. - toxins_mod = 0.8 // Not as biologically fragile as meatboys. - radiation_mod = 0.5 // Not as biologically fragile as meatboys. - flash_mod = 2 // Highly photosensitive. - - min_age = 1 - max_age = 20 - slowdown = -1 - rarity_value = 3 - gluttonous = 2 - siemens_coefficient = 0 - body_temperature = null - - breath_type = /decl/material/gas/methyl_bromide - exhale_type = /decl/material/gas/methane - poison_types = list(/decl/material/gas/chlorine) - - reagent_tag = IS_MANTID - genders = list(MALE) - - appearance_flags = 0 - species_flags = SPECIES_FLAG_NO_SCAN | SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_MINOR_CUT - spawn_flags = SPECIES_IS_RESTRICTED - - heat_discomfort_strings = list( - "You feel brittle and overheated.", - "Your overheated carapace flexes uneasily.", - "Overheated ichor trickles from your eyes." - ) - cold_discomfort_strings = list( - "Frost forms along your carapace.", - "You hear a faint crackle of ice as you shift your freezing body.", - "Your movements become sluggish under the weight of the chilly conditions." - ) - unarmed_attacks = list( - /decl/natural_attack/claws/strong/gloves, - /decl/natural_attack/bite/sharp - ) - - has_limbs = list( - BP_CHEST = list("path" = /obj/item/organ/external/chest/insectoid), - BP_GROIN = list("path" = /obj/item/organ/external/groin/insectoid/mantid), - BP_HEAD = list("path" = /obj/item/organ/external/head/insectoid), - BP_L_ARM = list("path" = /obj/item/organ/external/arm/insectoid), - BP_L_HAND = list("path" = /obj/item/organ/external/hand/insectoid), - BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/insectoid), - BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/insectoid), - BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/insectoid), - BP_L_LEG = list("path" = /obj/item/organ/external/leg/insectoid), - BP_L_FOOT = list("path" = /obj/item/organ/external/foot/insectoid), - BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/insectoid) - ) - - has_organ = list( - BP_HEART = /obj/item/organ/internal/heart/insectoid, - BP_STOMACH = /obj/item/organ/internal/stomach/insectoid, - BP_LUNGS = /obj/item/organ/internal/lungs/insectoid, - BP_LIVER = /obj/item/organ/internal/liver/insectoid, - BP_KIDNEYS = /obj/item/organ/internal/kidneys/insectoid, - BP_BRAIN = /obj/item/organ/internal/brain/insectoid, - BP_EYES = /obj/item/organ/internal/eyes/insectoid, - BP_SYSTEM_CONTROLLER = /obj/item/organ/internal/controller - ) - - force_cultural_info = list( - TAG_CULTURE = CULTURE_ASCENT, - TAG_HOMEWORLD = HOME_SYSTEM_KHARMAANI, - TAG_FACTION = FACTION_ASCENT_ALATE, - TAG_RELIGION = RELIGION_KHARMAANI - ) - - descriptors = list( - /datum/mob_descriptor/height = -1, - /datum/mob_descriptor/body_length = -2 - ) - - pain_emotes_with_pain_level = list( - list(/decl/emote/visible/ascent_shine, /decl/emote/visible/ascent_dazzle) = 80, - list(/decl/emote/visible/ascent_glimmer, /decl/emote/visible/ascent_pulse) = 50, - list(/decl/emote/visible/ascent_flicker, /decl/emote/visible/ascent_glint) = 20, - ) - -/datum/species/mantid/handle_sleeping(var/mob/living/carbon/human/H) - return - -/datum/species/mantid/get_blood_name() - return "hemolymph" - -/datum/species/mantid/post_organ_rejuvenate(var/obj/item/organ/org, var/mob/living/carbon/human/H) - org.status |= ORGAN_CRYSTAL - -/datum/species/mantid/equip_survival_gear(var/mob/living/carbon/human/H, var/extendedtank = 1) - return - -/datum/species/mantid/gyne - - name = SPECIES_MANTID_GYNE - name_plural = "Kharmaan Gynes" - - genders = list(FEMALE) - icobase = 'mods/ascent/icons/species/body/gyne/body.dmi' - deform = 'mods/ascent/icons/species/body/gyne/body.dmi' - icon_template = 'mods/ascent/icons/species/body/gyne/template.dmi' - damage_overlays = 'mods/ascent/icons/species/body/gyne/damage_mask.dmi' - blood_mask = 'mods/ascent/icons/species/body/gyne/blood_mask.dmi' - bodytype = BODYTYPE_MANTID_LARGE - - gluttonous = 3 - slowdown = 2 - rarity_value = 10 - min_age = 5 - max_age = 500 - blood_volume = 1200 - spawns_with_stack = 0 - - pixel_offset_x = -4 - antaghud_offset_y = 18 - antaghud_offset_x = 4 - - bump_flag = HEAVY - push_flags = ALLMOBS - swap_flags = ALLMOBS - - override_limb_types = list( - BP_HEAD = /obj/item/organ/external/head/insectoid/mantid, - BP_GROIN = /obj/item/organ/external/groin/insectoid/mantid/gyne - ) - - descriptors = list( - /datum/mob_descriptor/height = 5, - /datum/mob_descriptor/body_length = 2 - ) - - force_cultural_info = list( - TAG_CULTURE = CULTURE_ASCENT, - TAG_HOMEWORLD = HOME_SYSTEM_KHARMAANI, - TAG_FACTION = FACTION_ASCENT_GYNE, - TAG_RELIGION = RELIGION_KHARMAANI - ) - -/datum/species/mantid/gyne/New() - equip_adjust = list( - slot_l_hand_str = list( - "[NORTH]" = list("x" = -4, "y" = 12), - "[EAST]" = list("x" = -4, "y" = 12), - "[SOUTH]" = list("x" = -4, "y" = 12), - "[WEST]" = list("x" = -4, "y" = 12) - ) - ) - ..() - -/datum/hud_data/mantid - gear = list( - "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1), - "o_clothing" = list("loc" = ui_oclothing, "name" = "Suit", "slot" = slot_wear_suit, "state" = "suit", "toggle" = 1), - "mask" = list("loc" = ui_mask, "name" = "Mask", "slot" = slot_wear_mask, "state" = "mask", "toggle" = 1), - "gloves" = list("loc" = ui_gloves, "name" = "Gloves", "slot" = slot_gloves, "state" = "gloves", "toggle" = 1), - "eyes" = list("loc" = ui_glasses, "name" = "Glasses", "slot" = slot_glasses, "state" = "glasses","toggle" = 1), - "l_ear" = list("loc" = ui_l_ear, "name" = "Left Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), - "r_ear" = list("loc" = ui_r_ear, "name" = "Right Ear", "slot" = slot_r_ear, "state" = "ears", "toggle" = 1), - "head" = list("loc" = ui_head, "name" = "Hat", "slot" = slot_head, "state" = "hair", "toggle" = 1), - "shoes" = list("loc" = ui_shoes, "name" = "Shoes", "slot" = slot_shoes, "state" = "shoes", "toggle" = 1), - "suit storage" = list("loc" = ui_sstore1, "name" = "Suit Storage", "slot" = slot_s_store, "state" = "suitstore"), - "back" = list("loc" = ui_back, "name" = "Back", "slot" = slot_back, "state" = "back"), - "id" = list("loc" = ui_id, "name" = "ID", "slot" = slot_wear_id, "state" = "id"), - "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), - "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), - "belt" = list("loc" = ui_belt, "name" = "Belt", "slot" = slot_belt, "state" = "belt") - ) - -/datum/species/serpentid - name = SPECIES_SERPENTID - name_plural = "Serpentids" - spawn_flags = SPECIES_IS_RESTRICTED - has_organ = list( - BP_BRAIN = /obj/item/organ/internal/brain/insectoid/serpentid, - BP_EYES = /obj/item/organ/internal/eyes/insectoid/serpentid, - BP_TRACH = /obj/item/organ/internal/lungs/insectoid/serpentid, - BP_HEART = /obj/item/organ/internal/heart/open, - BP_LIVER = /obj/item/organ/internal/liver/insectoid/serpentid, - BP_STOMACH = /obj/item/organ/internal/stomach/insectoid, - BP_SYSTEM_CONTROLLER = /obj/item/organ/internal/controller - ) - has_limbs = list( - BP_CHEST = list("path" = /obj/item/organ/external/chest/insectoid/serpentid), - BP_GROIN = list("path" = /obj/item/organ/external/groin/insectoid/serpentid), - BP_HEAD = list("path" = /obj/item/organ/external/head/insectoid/serpentid), - BP_L_ARM = list("path" = /obj/item/organ/external/arm/insectoid), - BP_L_HAND = list("path" = /obj/item/organ/external/hand/insectoid), - BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/insectoid), - BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/insectoid), - BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/insectoid), - BP_L_LEG = list("path" = /obj/item/organ/external/leg/insectoid), - BP_L_FOOT = list("path" = /obj/item/organ/external/foot/insectoid), - BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/insectoid) - ) - force_cultural_info = list( - TAG_CULTURE = CULTURE_ASCENT, - TAG_HOMEWORLD = HOME_SYSTEM_KHARMAANI, - TAG_FACTION = FACTION_ASCENT_SERPENTID, - TAG_RELIGION = RELIGION_KHARMAANI - ) - hidden_from_codex = TRUE - silent_steps = TRUE - antaghud_offset_y = 8 - min_age = 8 - max_age = 40 - skin_material = /decl/material/solid/skin/insect - bone_material = null - speech_sounds = list('sound/voice/bug.ogg') - speech_chance = 2 - warning_low_pressure = 50 - hazard_low_pressure = -1 - body_temperature = null - blood_color = "#525252" - flesh_color = "#525252" - blood_oxy = 0 - reagent_tag = IS_SERPENTID - icon_template = 'icons/mob/human_races/species/template_tall.dmi' - icobase = 'mods/ascent/icons/species/body/serpentid/body.dmi' - deform = 'mods/ascent/icons/species/body/serpentid/body.dmi' - preview_icon = 'mods/ascent/icons/species/body/serpentid/preview.dmi' - blood_mask = 'mods/ascent/icons/species/body/serpentid/blood_mask.dmi' - limb_blend = ICON_MULTIPLY - darksight_range = 8 - darksight_tint = DARKTINT_GOOD - slowdown = -0.5 - rarity_value = 4 - hud_type = /datum/hud_data/serpentid - total_health = 200 - brute_mod = 0.9 - burn_mod = 1.35 - bodytype = BODYTYPE_SNAKE - natural_armour_values = list( - melee = ARMOR_MELEE_KNIVES, - bullet = ARMOR_BALLISTIC_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = 0.5*ARMOR_RAD_MINOR - ) - gluttonous = GLUT_SMALLER - mob_size = MOB_SIZE_LARGE - strength = STR_HIGH - breath_pressure = 25 - blood_volume = 840 - spawns_with_stack = 0 - heat_level_1 = 410 //Default 360 - Higher is better - heat_level_2 = 440 //Default 400 - heat_level_3 = 800 //Default 1000 - species_flags = SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_BLOCK | SPECIES_FLAG_NO_MINOR_CUT | SPECIES_FLAG_NEED_DIRECT_ABSORB - appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_SKIN_TONE_NORMAL | HAS_BASE_SKIN_COLOURS - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED - bump_flag = HEAVY - push_flags = ALLMOBS - swap_flags = ALLMOBS - breathing_organ = BP_TRACH - move_trail = /obj/effect/decal/cleanable/blood/tracks/snake - base_skin_colours = list( - "Grey" = "", - "Green" = "_green" - ) - unarmed_attacks = list(/decl/natural_attack/serpentid) - descriptors = list( - /datum/mob_descriptor/height = 3, - /datum/mob_descriptor/body_length = 0 - ) - pain_emotes_with_pain_level = list( - list(/decl/emote/audible/bug_hiss) = 40 - ) - -/datum/species/serpentid/New() - equip_adjust = list( - slot_head_str = list("[NORTH]" = list("x" = 0, "y" = 7), "[EAST]" = list("x" = 0, "y" = 8), "[SOUTH]" = list("x" = 0, "y" = 8), "[WEST]" = list("x" = 0, "y" = 8)), - slot_back_str = list("[NORTH]" = list("x" = 0, "y" = 7), "[EAST]" = list("x" = 0, "y" = 8), "[SOUTH]" = list("x" = 0, "y" = 8), "[WEST]" = list("x" = 0, "y" = 8)), - slot_belt_str = list("[NORTH]" = list("x" = 0, "y" = 0), "[EAST]" = list("x" = 8, "y" = 0), "[SOUTH]" = list("x" = 0, "y" = 0), "[WEST]" = list("x" = -8, "y" = 0)), - slot_glasses_str = list("[NORTH]" = list("x" = 0, "y" = 10), "[EAST]" = list("x" = 0, "y" = 11), "[SOUTH]" = list("x" = 0, "y" = 11), "[WEST]" = list("x" = 0, "y" = 11)) - ) - ..() - -/datum/species/serpentid/get_blood_name() - return "haemolymph" - -/datum/species/serpentid/can_overcome_gravity(var/mob/living/carbon/human/H) - var/datum/gas_mixture/mixture = H.loc.return_air() - - if(mixture) - var/pressure = mixture.return_pressure() - if(pressure > 50) - var/turf/below = GetBelow(H) - var/turf/T = H.loc - if(!T.CanZPass(H, DOWN) || !below.CanZPass(H, DOWN)) - return TRUE - - return FALSE - -/datum/species/serpentid/handle_environment_special(var/mob/living/carbon/human/H) - if(!H.on_fire && H.fire_stacks < 2) - H.fire_stacks += 0.2 - return - -/datum/species/serpentid/can_fall(var/mob/living/carbon/human/H) - var/datum/gas_mixture/mixture = H.loc.return_air() - var/turf/T = GetBelow(H.loc) - for(var/obj/O in T) - if(istype(O, /obj/structure/stairs)) - return TRUE - if(mixture) - var/pressure = mixture.return_pressure() - if(pressure > 80) - return FALSE - return TRUE - -/datum/species/serpentid/handle_fall_special(var/mob/living/carbon/human/H, var/turf/landing) - - var/datum/gas_mixture/mixture = H.loc.return_air() - var/turf/T = GetBelow(H.loc) - for(var/obj/O in T) - if(istype(O, /obj/structure/stairs)) - return FALSE - - if(mixture) - var/pressure = mixture.return_pressure() - if(pressure > 50) - if(istype(landing, /turf/simulated/open)) - H.visible_message("\The [H] descends from the deck above through \the [landing]!", "Your wings slow your descent.") - else - H.visible_message("\The [H] buzzes down from \the [landing], wings slowing their descent!", "You land on \the [landing], folding your wings.") - - return TRUE - - return FALSE - - -/datum/species/serpentid/can_shred(var/mob/living/carbon/human/H, var/ignore_intent, var/ignore_antag) - if(!H.handcuffed || H.buckled) - return ..(H, ignore_intent, TRUE) - else - return 0 - -/datum/species/serpentid/handle_movement_delay_special(var/mob/living/carbon/human/H) - var/tally = 0 - - H.remove_cloaking_source(src) - - var/obj/item/organ/internal/B = H.internal_organs_by_name[BP_BRAIN] - if(istype(B,/obj/item/organ/internal/brain/insectoid/serpentid)) - var/obj/item/organ/internal/brain/insectoid/serpentid/N = B - tally += N.lowblood_tally * 2 - return tally - -/datum/species/serpentid/update_skin(var/mob/living/carbon/human/H) - - if(H.stat) - H.skin_state = SKIN_NORMAL - - switch(H.skin_state) - if(SKIN_NORMAL) - return - if(SKIN_THREAT) - - var/image_key = "[H.species.get_icon_cache_uid(H)]" - - for(var/organ_tag in H.species.has_limbs) - var/obj/item/organ/external/part = H.organs_by_name[organ_tag] - if(isnull(part) || part.is_stump()) - image_key += "0" - continue - if(part) - image_key += "[part.species.get_icon_cache_uid(part.owner)]" - image_key += "[part.dna.GetUIState(DNA_UI_GENDER)]" - if(BP_IS_PROSTHETIC(part)) - image_key += "2[part.model ? "-[part.model]": ""]" - else if(part.status & ORGAN_DEAD) - image_key += "3" - else - image_key += "1" - - var/image/threat_image = skin_overlays[image_key] - if(!threat_image) - var/icon/base_icon = icon(H.stand_icon) - var/icon/I = new('mods/ascent/icons/species/body/serpentid/threat.dmi', "threat") - base_icon.Blend(COLOR_BLACK, ICON_MULTIPLY) - base_icon.Blend(I, ICON_ADD) - threat_image = image(base_icon) - skin_overlays[image_key] = threat_image - - return(threat_image) - return - -/datum/species/serpentid/disarm_attackhand(var/mob/living/carbon/human/attacker, var/mob/living/carbon/human/target) - if(attacker.pulling_punches || target.lying || attacker == target) - return ..(attacker, target) - if(world.time < attacker.last_attack + 20) - to_chat(attacker, "You can't attack again so soon.") - return 0 - attacker.last_attack = world.time - var/turf/T = get_step(get_turf(target), get_dir(get_turf(attacker), get_turf(target))) - playsound(target.loc, 'sound/weapons/pushhiss.ogg', 50, 1, -1) - if(!T.density) - step(target, get_dir(get_turf(attacker), get_turf(target))) - target.visible_message("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]") - else - target.turf_collision(T, target.throw_speed / 2) - if(prob(50)) - target.set_dir(GLOB.reverse_dir[target.dir]) - -/datum/species/serpentid/get_additional_examine_text(var/mob/living/carbon/human/H) - var/datum/gender/T = gender_datums[H.get_gender()] - if(H.pulling_punches) - return "\n[T.His] manipulation arms are out and [T.he] looks ready to use complex items." - else - return "\n[T.His] upper arms are raised and [T.he] looks ready to attack!" - -/datum/species/serpentid/handle_post_spawn(var/mob/living/carbon/human/H) - ..() - H.pulling_punches = TRUE - -/datum/species/serpentid/get_manual_dexterity(var/mob/living/carbon/human/H) - . = (H && H.pulling_punches) ? ..() : DEXTERITY_SIMPLE_MACHINES - -/datum/species/serpentid/toggle_stance(var/mob/living/carbon/human/H) - if(H.incapacitated()) - return FALSE - var/datum/gender/T = gender_datums[H.get_gender()] - to_chat(H, "You begin to adjust the fluids in your arms, dropping everything and getting ready to swap which set you're using.") - var/hidden = H.is_cloaked() - if(!hidden) H.visible_message("\The [H] shifts [T.his] arms.") - H.unEquip(H.l_hand) - H.unEquip(H.r_hand) - if(do_after(H, 30)) - arm_swap(H) - else - to_chat(H, "You stop adjusting your arms and don't switch between them.") - return TRUE - -/datum/species/serpentid/proc/arm_swap(var/mob/living/carbon/human/H, var/forced) - H.unEquip(H.l_hand) - H.unEquip(H.r_hand) - var/hidden = H.is_cloaked() - var/datum/gender/T = gender_datums[H.get_gender()] - H.pulling_punches = !H.pulling_punches - if(H.pulling_punches) - if(forced) - to_chat(H, "You can't keep your hunting arms prepared and they drop, forcing you to use your manipulation arms.") - if(!hidden) - H.visible_message("[H] falters, [T.his] hunting arms failing.") - else - to_chat(H, "You relax your hunting arms, lowering the pressure and folding them tight to your thorax. \ - You reach out with your manipulation arms, ready to use complex items.") - if(!hidden) - H.visible_message("[H] seems to relax as [T.he] folds [T.his] massive curved arms to [T.his] thorax and reaches out \ - with [T.his] small handlike limbs.") - else - to_chat(H, "You pull in your manipulation arms, dropping any items and unfolding your massive hunting arms in preparation of grabbing prey.") - if(!hidden) - H.visible_message("[H] tenses as [T.he] brings [T.his] smaller arms in close to [T.his] body. [T.His] two massive spiked arms reach \ - out. [T.He] looks ready to attack.") - -/datum/species/serpentid/skills_from_age(age) //Converts an age into a skill point allocation modifier. Can be used to give skill point bonuses/penalities not depending on job. - switch(age) - if(0 to 18) . = 8 - if(19 to 27) . = 2 - if(28 to 40) . = -2 - else . = -4 - -/datum/hud_data/serpentid - gear = list( - "i_clothing" = list("loc" = ui_iclothing, "name" = "Uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1), - "o_clothing" = list("loc" = ui_shoes, "name" = "Suit", "slot" = slot_wear_suit, "state" = "suit", "toggle" = 1), - "l_ear" = list("loc" = ui_oclothing, "name" = "Ear", "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), - "gloves" = list("loc" = ui_gloves, "name" = "Gloves", "slot" = slot_gloves, "state" = "gloves", "toggle" = 1), - "head" = list("loc" = ui_mask, "name" = "Hat", "slot" = slot_head, "state" = "hair", "toggle" = 1), - "eyes" = list("loc" = ui_glasses, "name" = "Glasses", "slot" = slot_glasses, "state" = "glasses","toggle" = 1), - "suit storage" = list("loc" = ui_sstore1, "name" = "Suit Storage", "slot" = slot_s_store, "state" = "suitstore"), - "back" = list("loc" = ui_back, "name" = "Back", "slot" = slot_back, "state" = "back"), - "id" = list("loc" = ui_id, "name" = "ID", "slot" = slot_wear_id, "state" = "id"), - "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), - "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), - "belt" = list("loc" = ui_belt, "name" = "Belt", "slot" = slot_belt, "state" = "belt") - ) \ No newline at end of file diff --git a/mods/ascent/effects/razorweb.dm b/mods/ascent/effects/razorweb.dm deleted file mode 100644 index 0163f7d016eb..000000000000 --- a/mods/ascent/effects/razorweb.dm +++ /dev/null @@ -1,169 +0,0 @@ -/obj/item/razorweb - name = "razorweb wad" - desc = "A wad of crystalline monofilament." - icon = 'mods/ascent/icons/razorweb.dmi' - icon_state = "wad" - var/web_type = /obj/effect/razorweb - -/obj/item/razorweb/throw_impact(var/atom/hit_atom) - var/obj/effect/razorweb/web = new web_type(get_turf(hit_atom)) - . = ..() - if(isliving(hit_atom)) - web.buckle_mob(hit_atom) - web.visible_message(SPAN_DANGER("\The [hit_atom] is tangled in \the [web]!")) - web.entangle(hit_atom, TRUE) - playsound(usr, 'mods/ascent/sounds/razorweb_twang.ogg', 50) - qdel(src) - -// Hey, did you ever see The Cube (1997) directed by Vincenzo Natali? -/obj/effect/razorweb - name = "razorweb" - desc = "A glimmering web of razor-sharp crystalline strands. Probably not something you want to sprint through." - icon = 'mods/ascent/icons/razorweb.dmi' - icon_state = "razorweb" - anchored = TRUE - - var/mob/owner - var/decays = TRUE - var/break_chance = 100 - var/last_light - var/image/gleam - var/image/web - var/global/species_immunity_list = list( - SPECIES_MANTID_ALATE = TRUE, - SPECIES_MANTID_GYNE = TRUE, - SPECIES_SERPENTID = TRUE - ) - -/obj/effect/razorweb/Destroy() - if(owner) - owner = null - . = ..() - -/obj/effect/razorweb/mapped - decays = FALSE - -/obj/effect/razorweb/tough - name = "tough razorweb" - break_chance = 33 - -/obj/effect/razorweb/Initialize(var/mapload) - - . = ..(mapload) - - for(var/obj/effect/razorweb/otherweb in loc) - if(otherweb != src) - return INITIALIZE_HINT_QDEL - - if(decays) - addtimer(CALLBACK(src, /obj/effect/razorweb/proc/decay), 15 MINUTES) - - web = image(icon = icon, icon_state = "razorweb") - gleam = image(icon = icon, icon_state = "razorweb-gleam") - gleam.layer = EYE_GLOW_LAYER - gleam.plane = EFFECTS_ABOVE_LIGHTING_PLANE - var/turf/T = get_turf(src) - if(T) last_light = T.get_lumcount() - icon_state = "" - update_icon() - START_PROCESSING(SSobj, src) - -/obj/effect/razorweb/proc/decay() - playsound(usr, 'mods/ascent/sounds/razorweb_break.ogg', 50) - qdel_self() - -/obj/effect/razorweb/attack_hand(mob/living/user) - user.visible_message(SPAN_DANGER("\The [user] yanks on \the [src]!")) - entangle(user, TRUE) - qdel_self() - -/obj/effect/razorweb/attackby(var/obj/item/thing, var/mob/user) - - var/destroy_self - if(thing.force) - visible_message(SPAN_DANGER("\The [user] breaks \the [src] with \the [thing]!")) - destroy_self = TRUE - - if(prob(15) && user.unEquip(thing)) - visible_message(SPAN_DANGER("\The [thing] is sliced apart!")) - qdel(thing) - - if(destroy_self) - qdel(src) - -/obj/effect/razorweb/on_update_icon() - overlays.Cut() - web.alpha = 255 * last_light - overlays = list(web, gleam) - -/obj/effect/razorweb/Process() - var/turf/T = get_turf(src) - if(T) - var/current_light = T.get_lumcount() - if(current_light != last_light) - last_light = current_light - update_icon() - -/obj/effect/razorweb/user_unbuckle_mob(var/mob/user) - var/mob/living/M = unbuckle_mob() - if(M) - if(M != user) - visible_message(SPAN_NOTICE("\The [user] drags \the [M] free of \the [src]!")) - entangle(user, silent = TRUE) - else - visible_message(SPAN_NOTICE("\The [M] writhes free of \the [src]!")) - entangle(M, silent = TRUE) - add_fingerprint(user) - return M - -/obj/effect/razorweb/Crossed(var/mob/living/L) - . = ..() - entangle(L) - -/obj/effect/razorweb/proc/entangle(var/mob/living/L, var/silent) - - if(!istype(L) || !L.simulated || L.lying || (MOVING_DELIBERATELY(L) && prob(25)) || L.is_floating) - return - - var/mob/living/carbon/human/H - if(ishuman(L)) - H = L - if(species_immunity_list[H.species.name]) - return - - if(!silent) - visible_message(SPAN_DANGER("\The [L] blunders into \the [src]!")) - - var/severed = FALSE - var/armour_prob = prob(100 * L.get_blocked_ratio(null, BRUTE, damage = ARMOR_MELEE_RESISTANT)) - if(H && prob(35)) - var/obj/item/organ/external/E - for(var/thing in shuffle(H.organs_by_name)) - var/obj/item/organ/external/limb = H.organs_by_name[thing] - if(!istype(limb) || limb.is_stump() || !(limb.limb_flags & ORGAN_FLAG_CAN_AMPUTATE)) - continue - var/is_vital = FALSE - for(var/obj/item/organ/internal/I in limb.internal_organs) - if(I.vital) - is_vital = TRUE - break - if(!is_vital) - E = thing - break - if(E && !armour_prob) - E = H.organs_by_name[E] - visible_message(SPAN_DANGER("The crystalline strands slice straight through \the [H]'s [E.amputation_point || E.name]!")) - E.droplimb() - severed = TRUE - - if(!severed && !armour_prob) - L.apply_damage(rand(25, 50), used_weapon = src) - visible_message(SPAN_DANGER("The crystalline strands cut deeply into \the [L]!")) - - if(prob(break_chance)) - visible_message(SPAN_DANGER("\The [src] breaks apart!")) - playsound(usr, 'mods/ascent/sounds/razorweb_break.ogg', 50) - qdel(src) - else - playsound(usr, 'mods/ascent/sounds/razorweb_twang.ogg', 50) - break_chance = min(break_chance+10, 100) \ No newline at end of file diff --git a/mods/ascent/icons/magboots/boots.dmi b/mods/ascent/icons/magboots/boots.dmi deleted file mode 100644 index 9db697b92dcb..000000000000 Binary files a/mods/ascent/icons/magboots/boots.dmi and /dev/null differ diff --git a/mods/ascent/icons/magboots/boots_gyne.dmi b/mods/ascent/icons/magboots/boots_gyne.dmi deleted file mode 100644 index 30f0b6682b56..000000000000 Binary files a/mods/ascent/icons/magboots/boots_gyne.dmi and /dev/null differ diff --git a/mods/ascent/icons/rig/alate.dmi b/mods/ascent/icons/rig/alate.dmi deleted file mode 100644 index b5155ef822b1..000000000000 Binary files a/mods/ascent/icons/rig/alate.dmi and /dev/null differ diff --git a/mods/ascent/icons/rig/gyne.dmi b/mods/ascent/icons/rig/gyne.dmi deleted file mode 100644 index 912c17566362..000000000000 Binary files a/mods/ascent/icons/rig/gyne.dmi and /dev/null differ diff --git a/mods/ascent/icons/rig/inventory.dmi b/mods/ascent/icons/rig/inventory.dmi deleted file mode 100644 index 78a68f001799..000000000000 Binary files a/mods/ascent/icons/rig/inventory.dmi and /dev/null differ diff --git a/mods/ascent/icons/rig/serpentid.dmi b/mods/ascent/icons/rig/serpentid.dmi deleted file mode 100644 index 52419dd2e8c8..000000000000 Binary files a/mods/ascent/icons/rig/serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/alate/body.dmi b/mods/ascent/icons/species/body/alate/body.dmi deleted file mode 100644 index 5bf7b2f708b2..000000000000 Binary files a/mods/ascent/icons/species/body/alate/body.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/alate/damage_mask.dmi b/mods/ascent/icons/species/body/alate/damage_mask.dmi deleted file mode 100644 index 83ce10fad811..000000000000 Binary files a/mods/ascent/icons/species/body/alate/damage_mask.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/alate/preview.dmi b/mods/ascent/icons/species/body/alate/preview.dmi deleted file mode 100644 index 7e8de54b5069..000000000000 Binary files a/mods/ascent/icons/species/body/alate/preview.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/gyne/body.dmi b/mods/ascent/icons/species/body/gyne/body.dmi deleted file mode 100644 index dd66ef775d0e..000000000000 Binary files a/mods/ascent/icons/species/body/gyne/body.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/gyne/damage_mask.dmi b/mods/ascent/icons/species/body/gyne/damage_mask.dmi deleted file mode 100644 index 5f9fa8f49107..000000000000 Binary files a/mods/ascent/icons/species/body/gyne/damage_mask.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/gyne/preview.dmi b/mods/ascent/icons/species/body/gyne/preview.dmi deleted file mode 100644 index add0531b9ddc..000000000000 Binary files a/mods/ascent/icons/species/body/gyne/preview.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/gyne/template.dmi b/mods/ascent/icons/species/body/gyne/template.dmi deleted file mode 100644 index b03bb8085545..000000000000 Binary files a/mods/ascent/icons/species/body/gyne/template.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/serpentid/body.dmi b/mods/ascent/icons/species/body/serpentid/body.dmi deleted file mode 100644 index ca2110fbb7cd..000000000000 Binary files a/mods/ascent/icons/species/body/serpentid/body.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/body/serpentid/preview.dmi b/mods/ascent/icons/species/body/serpentid/preview.dmi deleted file mode 100644 index eb50618ca9ce..000000000000 Binary files a/mods/ascent/icons/species/body/serpentid/preview.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_back_alate.dmi b/mods/ascent/icons/species/mantid/onmob_back_alate.dmi deleted file mode 100644 index 64b5c48f6518..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_back_alate.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_belt_alate.dmi b/mods/ascent/icons/species/mantid/onmob_belt_alate.dmi deleted file mode 100644 index b1d50c57eb99..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_belt_alate.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_belt_gyne.dmi b/mods/ascent/icons/species/mantid/onmob_belt_gyne.dmi deleted file mode 100644 index 8fe0eaf32cf9..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_belt_gyne.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_mask_alate.dmi b/mods/ascent/icons/species/mantid/onmob_mask_alate.dmi deleted file mode 100644 index a930154c5d36..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_mask_alate.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_mask_gyne.dmi b/mods/ascent/icons/species/mantid/onmob_mask_gyne.dmi deleted file mode 100644 index 8d3af756d236..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_mask_gyne.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_under_alate.dmi b/mods/ascent/icons/species/mantid/onmob_under_alate.dmi deleted file mode 100644 index ac7431c31646..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_under_alate.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/mantid/onmob_under_gyne.dmi b/mods/ascent/icons/species/mantid/onmob_under_gyne.dmi deleted file mode 100644 index c506b01412f3..000000000000 Binary files a/mods/ascent/icons/species/mantid/onmob_under_gyne.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_accessories_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_accessories_serpentid.dmi deleted file mode 100644 index 90d5355875e6..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_accessories_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_back_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_back_serpentid.dmi deleted file mode 100644 index baf6afa35e34..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_back_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_belt_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_belt_serpentid.dmi deleted file mode 100644 index 47062b734443..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_belt_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_hands_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_hands_serpentid.dmi deleted file mode 100644 index f3127e60c23f..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_hands_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_mask_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_mask_serpentid.dmi deleted file mode 100644 index 9af4fc1b1d39..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_mask_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_suit_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_suit_serpentid.dmi deleted file mode 100644 index 0680cca804ec..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_suit_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/icons/species/serpentid/onmob_under_serpentid.dmi b/mods/ascent/icons/species/serpentid/onmob_under_serpentid.dmi deleted file mode 100644 index 3bff89b1b62b..000000000000 Binary files a/mods/ascent/icons/species/serpentid/onmob_under_serpentid.dmi and /dev/null differ diff --git a/mods/ascent/items/cell.dm b/mods/ascent/items/cell.dm deleted file mode 100644 index 28f9299a9ef4..000000000000 --- a/mods/ascent/items/cell.dm +++ /dev/null @@ -1,21 +0,0 @@ -// Self-charging power cell. -/obj/item/cell/mantid - name = "mantid microfusion plant" - desc = "An impossibly tiny fusion reactor of mantid design." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "plant" - maxcharge = 1500 - w_class = ITEM_SIZE_NORMAL - var/recharge_amount = 12 - -/obj/item/cell/mantid/Initialize() - START_PROCESSING(SSobj, src) - . = ..() - -/obj/item/cell/mantid/Destroy() - STOP_PROCESSING(SSobj, src) - . = ..() - -/obj/item/cell/mantid/Process() - if(charge < maxcharge) - give(recharge_amount) diff --git a/mods/ascent/items/clothing.dm b/mods/ascent/items/clothing.dm deleted file mode 100644 index e356c980e2a0..000000000000 --- a/mods/ascent/items/clothing.dm +++ /dev/null @@ -1,107 +0,0 @@ -/decl/hierarchy/outfit/job/ascent - name = "Ascent - Gyne" - mask = /obj/item/clothing/mask/gas/ascent - uniform = /obj/item/clothing/under/ascent - id_type = /obj/item/card/id/ascent - shoes = /obj/item/clothing/shoes/magboots/ascent - l_ear = null - pda_type = null - pda_slot = 0 - flags = 0 - -/decl/hierarchy/outfit/job/ascent/attendant - name = "Ascent - Attendant" - back = /obj/item/rig/mantid - -/decl/hierarchy/outfit/job/ascent/tech - name = "Ascent - Technician" - suit = /obj/item/clothing/suit/storage/ascent - -/obj/item/clothing/mask/gas/ascent - name = "mantid facemask" - desc = "An alien facemask with chunky gas filters and a breathing valve." - filter_water = TRUE - icon_state = "ascent_mask" - item_state = "ascent_mask" - sprite_sheets = list( - BODYTYPE_SNAKE = 'mods/ascent/icons/species/serpentid/onmob_mask_serpentid.dmi', - BODYTYPE_MANTID_LARGE = 'mods/ascent/icons/species/mantid/onmob_mask_gyne.dmi', - BODYTYPE_MANTID_SMALL = 'mods/ascent/icons/species/mantid/onmob_mask_alate.dmi' - ) - - bodytype_restricted = list(BODYTYPE_MANTID_SMALL, BODYTYPE_MANTID_LARGE) - filtered_gases = list( - /decl/material/gas/nitrous_oxide, - /decl/material/gas/chlorine, - /decl/material/gas/ammonia, - /decl/material/gas/carbon_monoxide, - /decl/material/gas/methane - ) - flags_inv = 0 - -/obj/item/clothing/mask/gas/ascent/monarch - name = "serpentid facemask" - desc = "An alien facemask with chunky gas filters and a breathing valve." - filtered_gases = list( - /decl/material/gas/nitrous_oxide, - /decl/material/gas/chlorine, - /decl/material/gas/ammonia, - /decl/material/gas/carbon_monoxide, - /decl/material/gas/methyl_bromide, - /decl/material/gas/methane - ) - bodytype_restricted = list(BODYTYPE_SNAKE) - -/obj/item/clothing/shoes/magboots/ascent - name = "mantid mag-claws" - desc = "A set of powerful gripping claws." - icon = 'mods/ascent/icons/magboots/boots.dmi' - bodytype_restricted = list(BODYTYPE_MANTID_SMALL, BODYTYPE_MANTID_LARGE) - sprite_sheets = list( - BODYTYPE_MANTID_LARGE = 'mods/ascent/icons/magboots/boots_gyne.dmi' - ) - -/obj/item/clothing/under/ascent - name = "mantid undersuit" - desc = "A ribbed, spongy undersuit of some sort. It has a big sleeve for a tail, so it probably isn't for humans." - bodytype_restricted = list(BODYTYPE_MANTID_LARGE, BODYTYPE_MANTID_SMALL, BODYTYPE_SNAKE) - icon_state = "ascent" - worn_state = "ascent" - color = COLOR_DARK_GUNMETAL - -/obj/item/clothing/suit/storage/ascent - name = "mantid gear harness" - desc = "A complex tangle of articulated cables and straps." - bodytype_restricted = list(BODYTYPE_MANTID_LARGE, BODYTYPE_MANTID_SMALL, BODYTYPE_SNAKE) - icon_state = ICON_STATE_WORLD - icon = 'mods/ascent/icons/harness/alate.dmi' - on_mob_use_spritesheets = TRUE - sprite_sheets = list( - BODYTYPE_MANTID_LARGE = 'mods/ascent/icons/harness/gyne.dmi', - BODYTYPE_SNAKE = 'mods/ascent/icons/harness/serpentid.dmi' - ) - body_parts_covered = 0 - slot_flags = SLOT_OCLOTHING | SLOT_BELT - allowed = list( - /obj/item/flashlight, - /obj/item/tank, - /obj/item/suit_cooling_unit, - /obj/item/inflatable_dispenser, - /obj/item/rcd - ) - -/obj/item/clothing/suit/storage/ascent/Initialize() - . = ..() - for(var/tool in list( - /obj/item/gun/energy/particle/small, - /obj/item/multitool/mantid, - /obj/item/clustertool, - /obj/item/clustertool, - /obj/item/weldingtool/electric/mantid, - /obj/item/stack/medical/resin - )) - allowed |= tool - new tool(pockets) - pockets.make_exact_fit() - allowed |= /obj/item/chems/food/drinks/cans/waterbottle/ascent - pockets.can_hold |= /obj/item/chems/food/drinks/cans/waterbottle/ascent diff --git a/mods/ascent/items/clustertool.dm b/mods/ascent/items/clustertool.dm deleted file mode 100644 index acfc0a83e0b3..000000000000 --- a/mods/ascent/items/clustertool.dm +++ /dev/null @@ -1,40 +0,0 @@ -/obj/item/clustertool - name = "alien clustertool" - desc = "A bewilderingly complex knot of tool heads." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "clustertool" - w_class = ITEM_SIZE_SMALL - - var/tool_mode - var/list/tool_modes = list("wrench", "wirecutters", "crowbar", "screwdriver") - -/obj/item/clustertool/attack_self(var/mob/user) - var/new_index = tool_modes.Find(tool_mode) + 1 - if(new_index > tool_modes.len) - new_index = 1 - tool_mode = tool_modes[new_index] - name = "[initial(name)] ([tool_mode])" - playsound(user, 'sound/machines/bolts_down.ogg', 10) - to_chat(user, SPAN_NOTICE("You select the [tool_mode] attachment.")) - update_icon() - -/obj/item/clustertool/on_update_icon() - icon_state = "[initial(icon_state)]-[tool_mode]" - -/obj/item/clustertool/Initialize() - . = ..() - tool_mode = tool_modes[1] - name = "[initial(name)] ([tool_mode])" - update_icon() - -/obj/item/clustertool/iswrench() - return tool_mode == "wrench" - -/obj/item/clustertool/iswirecutter() - return tool_mode == "wirecutters" - -/obj/item/clustertool/isscrewdriver() - return tool_mode == "screwdriver" - -/obj/item/clustertool/iscrowbar() - return tool_mode == "crowbar" diff --git a/mods/ascent/items/guns.dm b/mods/ascent/items/guns.dm deleted file mode 100644 index d48b92cb3051..000000000000 --- a/mods/ascent/items/guns.dm +++ /dev/null @@ -1,76 +0,0 @@ -/obj/item/gun/energy/particle - name = "particle lance" - desc = "A long, thick-bodied energy rifle of some kind, clad in a curious indigo polymer and lit from within by Cherenkov radiation. The grip is clearly not designed for human hands." - icon = 'mods/ascent/icons/particle_rifle/rifle.dmi' - icon_state = ICON_STATE_WORLD - slot_flags = SLOT_BACK - force = 25 // Heavy as Hell. - projectile_type = /obj/item/projectile/beam/particle - max_shots = 18 - self_recharge = 1 - w_class = ITEM_SIZE_HUGE - one_hand_penalty = 6 - multi_aim = 1 - burst_delay = 3 - burst = 3 - accuracy = -1 - charge_meter = 0 - has_safety = FALSE - firemodes = list( - list(mode_name="stun", projectile_type = /obj/item/projectile/beam/stun), - list(mode_name="shock", projectile_type = /obj/item/projectile/beam/stun/shock), - list(mode_name="lethal", projectile_type = /obj/item/projectile/beam/particle) - ) - sprite_sheets = list( - BODYTYPE_MANTID_LARGE = 'mods/ascent/icons/particle_rifle/inhands_gyne.dmi', - BODYTYPE_SNAKE = 'mods/ascent/icons/particle_rifle/inhands_serpentid.dmi' - ) - -/obj/item/gun/energy/particle/small - name = "particle projector" - desc = "A smaller variant on the Ascent particle lance, usually carried by drones and alates." - icon = 'mods/ascent/icons/particle_rifle/rifle_small.dmi' - force = 12 - max_shots = 9 - burst = 1 - one_hand_penalty = 0 - w_class = ITEM_SIZE_NORMAL - slot_flags = SLOT_DENYPOCKET | SLOT_HOLSTER - projectile_type = /obj/item/projectile/beam/particle/small - firemodes = list( - list(mode_name="stun", projectile_type = /obj/item/projectile/beam/stun), - list(mode_name="shock", projectile_type = /obj/item/projectile/beam/stun/shock), - list(mode_name="lethal", projectile_type = /obj/item/projectile/beam/particle/small) - ) - - -/obj/item/gun/energy/particle/on_update_icon() - . = ..() - var/datum/firemode/current_mode = firemodes[sel_mode] - overlays = list( - image(icon, "[get_world_inventory_state()]-[istype(current_mode) ? current_mode.name : "lethal"]"), - image(icon, "[get_world_inventory_state()]-charge-[Floor(power_supply.percent()/20)]") - ) - -/obj/item/gun/magnetic/railgun/flechette/ascent - name = "mantid flechette rifle" - desc = "A viciously pronged rifle-like weapon." - has_safety = FALSE - one_hand_penalty = 6 - var/charge_per_shot = 10 - -/obj/item/gun/magnetic/railgun/flechette/ascent/get_cell() - if(isrobot(loc) || istype(loc, /obj/item/rig_module)) - return loc.get_cell() - -/obj/item/gun/magnetic/railgun/flechette/ascent/show_ammo(var/mob/user) - var/obj/item/cell/cell = get_cell() - to_chat(user, "There are [cell ? Floor(cell.charge/charge_per_shot) : 0] shot\s remaining.") - -/obj/item/gun/magnetic/railgun/flechette/ascent/check_ammo() - var/obj/item/cell/cell = get_cell() - return cell && cell.charge >= charge_per_shot - -/obj/item/gun/magnetic/railgun/flechette/ascent/use_ammo() - var/obj/item/cell/cell = get_cell() - if(cell) cell.use(charge_per_shot) \ No newline at end of file diff --git a/mods/ascent/items/id_control.dm b/mods/ascent/items/id_control.dm deleted file mode 100644 index 9a84dc53e56a..000000000000 --- a/mods/ascent/items/id_control.dm +++ /dev/null @@ -1,65 +0,0 @@ -// ID 'card' -/obj/item/card/id/ascent - name = "alien chip" - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "access_card" - desc = "A slender, complex chip of alien circuitry." - access = list(access_ascent) - -/obj/item/card/id/ascent/GetAccess() - var/mob/living/carbon/human/H = loc - if(istype(H) && !(H.species.name in ALL_ASCENT_SPECIES)) - . = list() - else - . = ..() - -/obj/item/card/id/ascent/on_update_icon() - return - -/obj/item/card/id/ascent/prevent_tracking() - return TRUE - -/obj/item/card/id/ascent/attack_self(mob/user) - return - -/obj/item/card/id/ascent/show() - return - -// ID implant/organ/interface device. -/obj/item/organ/internal/controller - name = "system controller" - desc = "A fist-sized lump of complex circuitry." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "plant" - parent_organ = BP_CHEST - organ_tag = BP_SYSTEM_CONTROLLER - surface_accessible = TRUE - var/obj/item/card/id/id_card = /obj/item/card/id/ascent - -/obj/item/organ/internal/controller/replaced(mob/living/carbon/human/target, obj/item/organ/external/affected) - . = ..() - if(owner) - owner.add_language(/decl/language/mantid/worldnet) - -/obj/item/organ/internal/controller/removed(mob/living/user, drop_organ, detach) - var/mob/living/carbon/H = owner - . = ..() - if(istype(H) && H != owner && !(locate(type) in H.internal_organs)) - H.remove_language(/decl/language/mantid/worldnet) - -/obj/item/organ/internal/controller/Initialize() - if(ispath(id_card)) - id_card = new id_card(src) - robotize() - . = ..() - if(owner) - owner.set_id_info(id_card) - -/obj/item/organ/internal/controller/GetIdCard() - //Not using is_broken() because it should be able to function when CUT_AWAY is set - if(damage < min_broken_damage) - return id_card - -/obj/item/organ/internal/controller/GetAccess() - if(id_card && damage < min_broken_damage) - return id_card.GetAccess() diff --git a/mods/ascent/items/rig.dm b/mods/ascent/items/rig.dm deleted file mode 100644 index aac9c6e55940..000000000000 --- a/mods/ascent/items/rig.dm +++ /dev/null @@ -1,286 +0,0 @@ -// Rigs and gear themselves. -/obj/item/rig/mantid - name = "alate support exosuit" - desc = "A powerful support exosuit with integrated power supply, weapon and atmosphere. It's closer to a mech than a rig." - icon_state = "kexosuit" - item_state = null - suit_type = "support exosuit" - armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = 1.1 * ARMOR_BALLISTIC_RESISTANT, - laser = 1.1 * ARMOR_LASER_RIFLES, - energy = ARMOR_ENERGY_RESISTANT, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED - ) - armor_type = /datum/extension/armor/ablative - armor_degradation_speed = 0.05 - online_slowdown = 0 - offline_slowdown = 1 - equipment_overlay_icon = null - air_type = /obj/item/tank/mantid/reactor - cell_type = /obj/item/cell/mantid - chest_type = /obj/item/clothing/suit/space/rig/mantid - helm_type = /obj/item/clothing/head/helmet/space/rig/mantid - boot_type = /obj/item/clothing/shoes/magboots/rig/mantid - glove_type = /obj/item/clothing/gloves/rig/mantid - update_visible_name = TRUE - icon = 'mods/ascent/icons/rig/inventory.dmi' - sprite_sheets = list( - BODYTYPE_MANTID_LARGE = 'mods/ascent/icons/rig/gyne.dmi', - BODYTYPE_MANTID_SMALL = 'mods/ascent/icons/rig/alate.dmi', - BODYTYPE_SNAKE = 'mods/ascent/icons/rig/serpentid.dmi' - ) - initial_modules = list( - /obj/item/rig_module/vision/thermal, - /obj/item/rig_module/ai_container, - /obj/item/rig_module/electrowarfare_suite, - /obj/item/rig_module/chem_dispenser/mantid, - /obj/item/rig_module/device/multitool, - /obj/item/rig_module/device/cable_coil, - /obj/item/rig_module/device/welder, - /obj/item/rig_module/device/clustertool, - /obj/item/rig_module/mounted/plasmacutter, - /obj/item/rig_module/maneuvering_jets - ) - req_access = list(access_ascent) - var/mantid_caste = SPECIES_MANTID_ALATE - -// Renamed blade. -/obj/item/rig_module/mounted/energy_blade/mantid - name = "nanoblade projector" - desc = "A fusion-powered blade nanofabricator of Ascent design." - interface_name = "nanoblade projector" - interface_desc = "A fusion-powered blade nanofabricator of Ascent design." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "blade" - interface_name = "nanoblade" - usable = FALSE - gun = null - -/obj/item/rig_module/mounted/flechette_rifle - name = "flechette rifle" - desc = "A flechette nanofabricator and launch system of Ascent design." - interface_name = "flechette rifle" - interface_desc = "A flechette nanofabricator and launch system of Ascent design." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "rifle" - gun = /obj/item/gun/magnetic/railgun/flechette/ascent - -/obj/item/rig_module/mounted/particle_rifle - name = "particle rifle" - desc = "A mounted particle rifle of Ascent design." - interface_name = "particle rifle" - interface_desc = "A mounted particle rifle of Ascent design." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "rifle" - gun = /obj/item/gun/energy/particle - -/obj/item/rig_module/device/multitool - name = "mantid integrated multitool" - desc = "A limited-sentience integrated multitool capable of interfacing with any number of systems." - interface_name = "multitool" - interface_desc = "A limited-sentience integrated multitool capable of interfacing with any number of systems." - device = /obj/item/multitool/mantid - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "multitool" - usable = FALSE - selectable = TRUE - -/obj/item/rig_module/device/multitool/ismultitool() - return device && device.ismultitool() - -/obj/item/rig_module/device/cable_coil - name = "mantid cable extruder" - desc = "A cable nanofabricator of Ascent design." - interface_name = "cable fabricator" - interface_desc = "A cable nanofabricator of Ascent design." - device = /obj/item/stack/cable_coil/fabricator - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "cablecoil" - usable = FALSE - selectable = TRUE - -/obj/item/rig_module/device/welder - name = "mantid welding arm" - desc = "An electrical cutting torch of Ascent design." - interface_name = "welding arm" - interface_desc = "An electrical cutting torch of Ascent design." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "welder1" - engage_string = "Toggle Welder" - device = /obj/item/weldingtool/electric/mantid - usable = TRUE - selectable = TRUE - -/obj/item/rig_module/device/clustertool - name = "mantid clustertool" - desc = "A complex assembly of self-guiding, modular heads capable of performing most manual tasks." - interface_name = "modular clustertool" - interface_desc = "A complex assembly of self-guiding, modular heads capable of performing most manual tasks." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "clustertool" - engage_string = "Select Mode" - device = /obj/item/clustertool - usable = TRUE - selectable = TRUE - -/obj/item/rig_module/device/clustertool/iswrench() - return device && device.iswrench() - -/obj/item/rig_module/device/clustertool/iswirecutter() - return device && device.iswirecutter() - -/obj/item/rig_module/device/clustertool/isscrewdriver() - return device && device.isscrewdriver() - -/obj/item/rig_module/device/clustertool/iscrowbar() - return device && device.iscrowbar() - -// Atmosphere/jetpack filler. -/obj/item/tank/mantid - name = "mantid gas tank" - icon_state = "bromomethane" - distribute_pressure = ONE_ATMOSPHERE*O2STANDARD - volume = 180 - -/obj/item/tank/mantid/methyl_bromide - starting_pressure = list(/decl/material/gas/methyl_bromide = 6 * ONE_ATMOSPHERE) - -/obj/item/tank/mantid/oxygen - name = "mantid oxygen tank" - starting_pressure = list(OXYGEN = 6 * ONE_ATMOSPHERE) - -// Boilerplate due to hard typechecks in jetpack code. Todo: make it an extension. -/obj/item/tank/jetpack/ascent - name = "catalytic maneuvering pack" - desc = "An integrated Ascent gas processing plant and maneuvering pack that continuously synthesises 'breathable' atmosphere and propellant." - sprite_sheets = list( - BODYTYPE_MANTID_LARGE = 'mods/ascent/icons/species/mantid/onmob_back_gyne.dmi', - BODYTYPE_MANTID_SMALL = 'mods/ascent/icons/species/mantid/onmob_back_alate.dmi', - BODYTYPE_SNAKE = 'mods/ascent/icons/species/serpentid/onmob_back_serpentid.dmi' - ) - icon_state = "maneuvering_pack" - var/refill_gas_type = /decl/material/gas/methyl_bromide - var/gas_regen_amount = 0.03 - var/gas_regen_cap = 30 - -/obj/item/tank/jetpack/ascent/Initialize() - starting_pressure = list(refill_gas_type = 6 * ONE_ATMOSPHERE) - . = ..() - -/obj/item/tank/jetpack/ascent/Process() - ..() - if(air_contents.total_moles < gas_regen_cap) - air_contents.adjust_gas(refill_gas_type, gas_regen_amount) - -/obj/item/tank/mantid/reactor - name = "mantid gas reactor" - desc = "A mantid gas processing plant that continuously synthesises 'breathable' atmosphere." - var/charge_cost = 12 - var/refill_gas_type = /decl/material/gas/methyl_bromide - var/gas_regen_amount = 0.05 - var/gas_regen_cap = 50 - -/obj/item/tank/mantid/reactor/Initialize() - starting_pressure = list(refill_gas_type = 6 * ONE_ATMOSPHERE) - . = ..() - -/obj/item/tank/mantid/reactor/oxygen - name = "serpentid gas reactor" - refill_gas_type = /decl/material/gas/oxygen - distribute_pressure = 31 - -/obj/item/tank/mantid/reactor/Process() - ..() - var/obj/item/rig/holder = loc - if(air_contents.total_moles < gas_regen_cap && istype(holder) && holder.cell && holder.cell.use(charge_cost)) - air_contents.adjust_gas(refill_gas_type, gas_regen_amount) - -// Chem dispenser. -/obj/item/rig_module/chem_dispenser/mantid - name = "mantid chemical injector" - desc = "A compact chemical dispenser of mantid design." - interface_name = "mantid chemical injector" - interface_desc = "A compact chemical dispenser of mantid design." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "injector" - charges = list( - list("bromide", "bromide", /decl/material/liquid/bromide, 80), - list("crystallizing agent", "crystallizing agent", /decl/material/liquid/crystal_agent, 80), - list("antibiotics", "antibiotics", /decl/material/liquid/antibiotics, 80), - list("painkillers", "painkillers", /decl/material/liquid/painkillers, 80) - ) - -// Rig definitions. -/obj/item/rig/mantid/gyne - name = "gyne support exosuit" - armor = list( - melee = ARMOR_MELEE_VERY_HIGH, - bullet = ARMOR_BALLISTIC_RIFLE, - laser = ARMOR_LASER_RIFLES, - energy = ARMOR_ENERGY_RESISTANT, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED - ) - mantid_caste = SPECIES_MANTID_GYNE - initial_modules = list( - /obj/item/rig_module/vision/thermal, - /obj/item/rig_module/ai_container, - /obj/item/rig_module/electrowarfare_suite, - /obj/item/rig_module/chem_dispenser/mantid, - /obj/item/rig_module/mounted/energy_blade/mantid, - /obj/item/rig_module/mounted/flechette_rifle, - /obj/item/rig_module/mounted/particle_rifle, - /obj/item/rig_module/device/multitool, - /obj/item/rig_module/device/cable_coil, - /obj/item/rig_module/device/welder, - /obj/item/rig_module/device/clustertool, - /obj/item/rig_module/mounted/plasmacutter, - /obj/item/rig_module/maneuvering_jets - ) - -/obj/item/rig/mantid/serpentid - name = "serpentid support exosuit" - mantid_caste = SPECIES_SERPENTID - air_type = /obj/item/tank/mantid/reactor/oxygen - chest_type = /obj/item/clothing/suit/space/rig/mantid/serpentid - boot_type = null - -/obj/item/clothing/suit/space/rig/mantid/serpentid - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET - -/obj/item/rig/mantid/mob_can_equip(var/mob/M, var/slot) - . = ..() - if(. && slot == slot_back) - var/mob/living/carbon/human/H = M - if(!istype(H) || H.species.get_root_species_name(H) != mantid_caste) - to_chat(H, "Your species cannot wear \the [src].") - . = 0 - -/obj/item/clothing/head/helmet/space/rig/mantid - light_color = "#00ffff" - desc = "More like a torpedo casing than a helmet." - bodytype_restricted = list(BODYTYPE_MANTID_LARGE, BODYTYPE_MANTID_SMALL) - -/obj/item/clothing/suit/space/rig/mantid - desc = "It's closer to a mech than a suit." - bodytype_restricted = list(BODYTYPE_MANTID_LARGE, BODYTYPE_MANTID_SMALL) - allowed = list( - /obj/item/clustertool, - /obj/item/gun/energy/particle/small, - /obj/item/weldingtool/electric/mantid, - /obj/item/multitool/mantid, - /obj/item/stack/medical/resin, - /obj/item/chems/food/drinks/cans/waterbottle/ascent - ) - -/obj/item/clothing/shoes/magboots/rig/mantid - desc = "It's like a highly advanced forklift." - bodytype_restricted = list(BODYTYPE_MANTID_LARGE, BODYTYPE_MANTID_SMALL) - -/obj/item/clothing/gloves/rig/mantid - desc = "They look like a cross between a can opener and a Swiss army knife the size of a shoebox." - bodytype_restricted = list(BODYTYPE_MANTID_LARGE, BODYTYPE_MANTID_SMALL) diff --git a/mods/ascent/items/suits.dm b/mods/ascent/items/suits.dm deleted file mode 100644 index b4491b141ccb..000000000000 --- a/mods/ascent/items/suits.dm +++ /dev/null @@ -1,40 +0,0 @@ -/obj/item/clothing/head/helmet/space/void/ascent - name = "\improper Ascent voidsuit helmet" - desc = "An articulated spacesuit helmet of mantid manufacture." - icon = 'mods/ascent/icons/alate_spacesuit/helmet.dmi' - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED - ) - max_pressure_protection = ENG_VOIDSUIT_MAX_PRESSURE - bodytype_restricted = list(BODYTYPE_MANTID_SMALL) - -/obj/item/clothing/suit/space/void/ascent - name = "\improper Ascent voidsuit" - desc = "A form-fitting spacesuit of mantid manufacture." - icon = 'mods/ascent/icons/alate_spacesuit/suit.dmi' - max_pressure_protection = ENG_VOIDSUIT_MAX_PRESSURE - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_MINOR, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED - ) - bodytype_restricted = list(BODYTYPE_MANTID_SMALL) - allowed = list( - /obj/item/clustertool, - /obj/item/tank/mantid, - /obj/item/gun/energy/particle/small, - /obj/item/weldingtool/electric/mantid, - /obj/item/multitool/mantid, - /obj/item/stack/medical/resin, - /obj/item/chems/food/drinks/cans/waterbottle/ascent - ) \ No newline at end of file diff --git a/mods/ascent/items/tools.dm b/mods/ascent/items/tools.dm deleted file mode 100644 index 9637792526a1..000000000000 --- a/mods/ascent/items/tools.dm +++ /dev/null @@ -1,61 +0,0 @@ -MANTIDIFY(/obj/item/storage/bag/trash/purple, "sample collection carrier", "material storage") -MANTIDIFY(/obj/item/pickaxe/diamonddrill, "lithobliterator", "drilling") -MANTIDIFY(/obj/item/tank/jetpack/carbondioxide, "maneuvering pack", "propulsion") - -/obj/item/light/tube/ascent - name = "mantid light filament" - color = COLOR_CYAN - b_colour = COLOR_CYAN - desc = "Some kind of strange alien lightbulb technology." - -/obj/item/multitool/mantid - name = "mantid multitool" - desc = "An alien microcomputer of some kind." - icon = 'mods/ascent/icons/ascent.dmi' - icon_state = "multitool" - -/obj/item/weldingtool/electric/mantid - name = "mantid welding tool" - desc = "An oddly shaped alien welding tool." - icon = 'mods/ascent/icons/ascent.dmi' - -/obj/item/mop/advanced/ascent - name = "deck detritus delaminator" - desc = "An alien staff with spongy filaments on one end." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - item_state = "advmop" - -/obj/item/chems/glass/bucket/ascent - name = "portable liquid cleaning agent carrier" - desc = "An alien container of some sort." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - -/obj/item/knife/kitchen/cleaver/ascent - name = "xenobiological flenser" - desc = "A mindboggingly alien tool for flensing flesh." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - icon_state = "xenobutch" - - -/obj/item/chems/food/drinks/cans/waterbottle/ascent - name = "hydration cylinder" - desc = "An alien portable long term storage device for potable water." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - -/obj/item/chems/food/snacks/hydration - name = "hydration ration" - desc = "Approximately ten units of liquid hydration in a edible membrane. Unflavored." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - icon_state = "h2o_ration" - bitesize = 10 - -/obj/item/chems/food/snacks/hydration/Initialize() - .=..() - reagents.add_reagent(/decl/material/liquid/water, 10) - -/obj/item/storage/box/water/ascent - name = "box of hydration cylinders" - desc = "A box full of bottled water." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - icon_state = "box" - startswith = list(/obj/item/chems/food/drinks/cans/waterbottle/ascent = 7) diff --git a/mods/ascent/machines/ship_alarm.dm b/mods/ascent/machines/ship_alarm.dm deleted file mode 100644 index 3c1640a6ac95..000000000000 --- a/mods/ascent/machines/ship_alarm.dm +++ /dev/null @@ -1,23 +0,0 @@ -/decl/environment_data/mantid - important_gasses = list( - /decl/material/gas/oxygen = TRUE, - /decl/material/gas/methyl_bromide = TRUE, - /decl/material/gas/carbon_dioxide = TRUE, - /decl/material/gas/methane = TRUE - ) - dangerous_gasses = list( - /decl/material/gas/carbon_dioxide = TRUE, - /decl/material/gas/methane = TRUE - ) - -MANTIDIFY(/obj/machinery/alarm, "mantid thermostat", "atmospherics") - -/obj/machinery/alarm/ascent - req_access = list(access_ascent) - construct_state = null - environment_type = /decl/environment_data/mantid - -/obj/machinery/alarm/ascent/Initialize() - . = ..() - TLV[/decl/material/gas/methyl_bromide] = list(16, 19, 135, 140) - TLV[/decl/material/gas/methane] = list(-1.0, -1.0, 5, 10) \ No newline at end of file diff --git a/mods/ascent/machines/ship_machines.dm b/mods/ascent/machines/ship_machines.dm deleted file mode 100644 index b99599fb6321..000000000000 --- a/mods/ascent/machines/ship_machines.dm +++ /dev/null @@ -1,255 +0,0 @@ -MANTIDIFY(/obj/machinery/power/apc/hyper, "mantid power node", "power controller") -MANTIDIFY(/obj/machinery/atmospherics/unary/vent_pump/on, "mantid atmosphere outlet", "vent") -MANTIDIFY(/obj/machinery/atmospherics/unary/vent_scrubber/on, "mantid atmosphere intake", "scrubber") -MANTIDIFY(/obj/machinery/hologram/holopad/longrange, "mantid holopad", "holopad") -MANTIDIFY(/obj/machinery/optable, "mantid operating table", "operating table") -MANTIDIFY(/obj/machinery/door/airlock/external/bolted, "mantid airlock", "door") - -/obj/machinery/optable/ascent - construct_state = /decl/machine_construction/default/no_deconstruct - base_type = /obj/machinery/optable - -/obj/machinery/portable_atmospherics/hydroponics/ascent - name = "mantid algae vat" - desc = "Some kind of strange alien hydroponics technology." - icon = 'mods/ascent/icons/mantid_hydroponics.dmi' - closed_system = TRUE - construct_state = /decl/machine_construction/default/no_deconstruct - base_type = /obj/machinery/portable_atmospherics/hydroponics - -// No maintenance needed. -/obj/machinery/portable_atmospherics/hydroponics/ascent/Process() - if(dead) - seed = null - update_icon() - if(!seed) - seed = SSplants.seeds["algae"] - update_icon() - waterlevel = 100 - nutrilevel = 10 - pestlevel = 0 - weedlevel = 0 - mutation_level = 0 - health = 100 - sampled = 0 - . = ..() - -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent/Initialize() - . = ..() - scrubbing_gas -= /decl/material/gas/methyl_bromide - -/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent/shuttle - stock_part_presets = list( - /decl/stock_part_preset/radio/receiver/vent_scrubber/shuttle = 1, - /decl/stock_part_preset/radio/event_transmitter/vent_scrubber/shuttle = 1 - ) -/obj/machinery/recharge_station/ascent - name = "mantid recharging dock" - desc = "An oddly organic aperture stuffed with power connectors." - icon = 'mods/ascent/icons/mantid_charger.dmi' - overlay_icon = 'mods/ascent/icons/mantid_charger.dmi' - construct_state = /decl/machine_construction/default/no_deconstruct - base_type = /obj/machinery/recharge_station - -/obj/machinery/body_scanconsole/ascent - name = "mantid scanner console" - desc = "Some kind of strange alien console technology." - req_access = list(access_ascent) - icon = 'mods/ascent/icons/ascent_sleepers.dmi' - construct_state = /decl/machine_construction/default/no_deconstruct - base_type = /obj/machinery/body_scanconsole - -/obj/machinery/bodyscanner/ascent - name = "mantid body scanner" - desc = "Some kind of strange alien body scanning technology." - icon = 'mods/ascent/icons/ascent_sleepers.dmi' - construct_state = /decl/machine_construction/default/no_deconstruct - base_type = /obj/machinery/bodyscanner - -MANTIDIFY(/obj/item/chems/chem_disp_cartridge, "canister", "chemical storage") -/obj/item/chems/chem_disp_cartridge/ascent/crystal - spawn_reagent = /decl/material/liquid/crystal_agent -/obj/item/chems/chem_disp_cartridge/ascent/bromide - spawn_reagent = /decl/material/liquid/bromide - -/obj/machinery/sleeper/ascent - name = "mantid sleeper" - desc = "Some kind of strange alien sleeper technology." - icon = 'mods/ascent/icons/ascent_sleepers.dmi' - base_type = /obj/machinery/sleeper - construct_state = /decl/machine_construction/default/no_deconstruct - -/obj/machinery/sleeper/ascent/Initialize(mapload, d, populate_parts) - . = ..() - add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/ascent/crystal()) - add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/ascent/bromide()) - -/obj/machinery/fabricator/ascent - name = "\improper Ascent nanofabricator" - desc = "A squat, complicated fabrication system clad in purple polymer." - icon = 'mods/ascent/icons/nanofabricator.dmi' - icon_state = "nanofab" - base_icon_state = "nanofab" - req_access = list(access_ascent) - base_type = /obj/machinery/fabricator - construct_state = /decl/machine_construction/default/no_deconstruct - -/obj/machinery/power/apc/hyper/ascent - req_access = list(access_ascent) - base_type = /obj/machinery/power/apc - -/obj/machinery/hologram/holopad/longrange/ascent - req_access = list(access_ascent) - -/obj/effect/catwalk_plated/ascent - color = COLOR_GRAY40 - -/obj/machinery/door/airlock/ascent - desc = "Some kind of strange alien door technology." - icon = 'mods/ascent/icons/doors/base.dmi' - bolts_file = 'mods/ascent/icons/doors/lights_bolts.dmi' - deny_file = 'mods/ascent/icons/doors/lights_deny.dmi' - lights_file = 'mods/ascent/icons/doors/lights_green.dmi' - panel_file = 'mods/ascent/icons/doors/panel.dmi' - sparks_damaged_file = 'mods/ascent/icons/doors/sparks_damaged.dmi' - sparks_broken_file = 'mods/ascent/icons/doors/sparks_broken.dmi' - welded_file = 'mods/ascent/icons/doors/welded.dmi' - emag_file = 'mods/ascent/icons/doors/emag.dmi' - -/obj/machinery/door/airlock/ascent/set_airlock_overlays(state) - return - -/obj/machinery/door/airlock/external/bolted/ascent - door_color = COLOR_PURPLE - stripe_color = COLOR_GRAY40 - stock_part_presets = list( - /decl/stock_part_preset/radio/receiver/airlock/shuttle = 1, - /decl/stock_part_preset/radio/event_transmitter/airlock/shuttle = 1 - ) - -/obj/machinery/power/apc/hyper/ascent/north - name = "north bump" - pixel_x = 0 - pixel_y = 24 - dir = NORTH - -/obj/machinery/power/apc/hyper/ascent/south - name = "south bump" - pixel_x = 0 - pixel_y = -24 - dir = SOUTH - -/obj/machinery/power/apc/hyper/ascent/east - name = "east bump" - pixel_x = 24 - pixel_y = 0 - dir = EAST - -/obj/machinery/power/apc/hyper/ascent/west - name = "west bump" - pixel_x = -24 - pixel_y = 0 - dir = WEST - -/obj/machinery/light/ascent - name = "mantid light" - light_type = /obj/item/light/tube/ascent - desc = "Some kind of strange alien lighting technology." - -/obj/machinery/computer/ship/helm/ascent - icon_state = "ascent" - icon_keyboard = "ascent_key" - icon_screen = "ascent_screen" - req_access = list(access_ascent) - construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct - base_type = /obj/machinery/computer/ship/helm - -/obj/machinery/computer/ship/engines/ascent - icon_state = "ascent" - icon_keyboard = "ascent_key" - icon_screen = "ascent_screen" - req_access = list(access_ascent) - construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct - base_type = /obj/machinery/computer/ship/engines - -/obj/machinery/computer/ship/navigation/ascent - icon_state = "ascent" - icon_keyboard = "ascent_key" - icon_screen = "ascent_screen" - req_access = list(access_ascent) - construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct - base_type = /obj/machinery/computer/ship/navigation - -/obj/machinery/computer/ship/sensors/ascent - icon_state = "ascent" - icon_keyboard = "ascent_key" - icon_screen = "ascent_screen" - req_access = list(access_ascent) - construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct - base_type = /obj/machinery/computer/ship/sensors - -// This is an absolutely stupid machine. Basically the same as the debug one with some alterations. -// It is a placeholder for a proper reactor setup (probably a RUST descendant) -/obj/machinery/power/ascent_reactor - name = "mantid fusion stack" - desc = "A tall, gleaming assemblage of advanced alien machinery. It hums and crackles with restrained power." - icon = 'icons/obj/machines/power/fusion_core.dmi' - icon_state = "core1" - color = COLOR_PURPLE - var/on = TRUE - var/output_power = 9000 KILOWATTS - var/image/field_image - -/obj/machinery/power/ascent_reactor/attack_hand(mob/user) - . = ..() - - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(!(H.species.name in ALL_ASCENT_SPECIES)) - to_chat(H, SPAN_WARNING("You have no idea how to use \the [src].")) - return - else if(!istype(user, /mob/living/silicon/robot/flying/ascent)) - to_chat(user, SPAN_WARNING("You have no idea how to interface with \the [src].")) - return - - user.visible_message(SPAN_NOTICE("\The [user] switches \the [src] [on ? "off" : "on"].")) - on = !on - update_icon() - -/obj/machinery/power/ascent_reactor/on_update_icon() - . = ..() - - if(!field_image) - field_image = image(icon = 'icons/obj/machines/power/fusion.dmi', icon_state = "emfield_s1") - field_image.color = COLOR_CYAN - field_image.alpha = 50 - field_image.layer = SINGULARITY_LAYER - field_image.appearance_flags |= RESET_COLOR - - var/matrix/M = matrix() - M.Scale(3) - field_image.transform = M - - if(on) - overlays |= field_image - set_light(0.8, 1, 6, l_color = COLOR_CYAN) - icon_state = "core1" - else - overlays -= field_image - set_light(0) - icon_state = "core0" - -/obj/machinery/power/ascent_reactor/Initialize() - . = ..() - update_icon() - -/obj/machinery/power/ascent_reactor/Process() - if(on) - add_avail(output_power) - -/obj/machinery/power/smes/buildable/power_shuttle/ascent - name = "mantid battery" - desc = "Some kind of strange alien SMES technology." - icon = 'mods/ascent/icons/mantid_smes.dmi' - overlay_icon = 'mods/ascent/icons/mantid_smes.dmi' - construct_state = /decl/machine_construction/default/no_deconstruct diff --git a/mods/ascent/mobs/bodyparts.dm b/mods/ascent/mobs/bodyparts.dm deleted file mode 100644 index 7cd2ff4bf5fe..000000000000 --- a/mods/ascent/mobs/bodyparts.dm +++ /dev/null @@ -1,90 +0,0 @@ -/obj/item/organ/external/groin/insectoid/mantid - name = "central support limb" - action_button_name = "Weave Razorweb" - var/list/existing_webs = list() - var/list/max_webs = 4 - var/web_weave_time = 20 SECONDS - var/cooldown - -/obj/item/organ/external/groin/insectoid/mantid/gyne - max_webs = 8 - web_weave_time = 10 SECONDS - -/obj/item/organ/external/groin/insectoid/mantid/Destroy() - for(var/obj/effect/razorweb/web in existing_webs) - web.owner = null - existing_webs.Cut() - . = ..() - -/obj/item/organ/external/groin/insectoid/mantid/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "weave-web-[cooldown ? "off" : "on"]" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/external/groin/insectoid/mantid/attack_self(var/mob/user) - . = ..() - if(. && !cooldown) - - if(!isturf(owner.loc)) - to_chat(owner, SPAN_WARNING("You cannot use this ability in this location.")) - return - - if(locate(/obj/effect/razorweb) in owner.loc) - to_chat(owner, SPAN_WARNING("There is already a razorweb here.")) - return - - if(length(existing_webs) >= max_webs) - to_chat(owner, SPAN_WARNING("You cannot maintain more than [max_webs] razorweb\s.")) - return - - playsound(user, 'mods/ascent/sounds/razorweb_hiss.ogg', 70) - owner.visible_message(SPAN_WARNING("\The [owner] separates their jaws and begins to weave a web of crystalline filaments...")) - cooldown = TRUE - refresh_action_button() - addtimer(CALLBACK(src, .proc/reset_cooldown), web_weave_time) - if(do_after(owner, web_weave_time) && length(existing_webs) < max_webs) - playsound(user, 'mods/ascent/sounds/razorweb.ogg', 70, 0) - owner.visible_message(SPAN_DANGER("\The [owner] completes a razorweb!")) - var/obj/effect/razorweb/web = new(owner.loc) - existing_webs += web - web.owner = owner - -/obj/item/organ/external/groin/insectoid/mantid/proc/reset_cooldown() - cooldown = FALSE - refresh_action_button() - -/obj/item/organ/external/head/insectoid/mantid - name = "crested head" - action_button_name = "Spit Razorweb" - var/cooldown_time = 2.5 MINUTES - var/cooldown - -/obj/item/organ/external/head/insectoid/mantid/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "shot-web-[cooldown ? "off" : "on"]" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/external/head/insectoid/mantid/attack_self(var/mob/user) - . = ..() - if(.) - - if(cooldown) - to_chat(owner, SPAN_WARNING("Your filament channel hasn't refilled yet!")) - return - - var/obj/item/razorweb/web = new(get_turf(owner)) - if(owner.put_in_hands(web)) - playsound(user, 'mods/ascent/sounds/razorweb.ogg', 100) - to_chat(owner, SPAN_WARNING("You spit up a wad of razorweb, ready to throw!")) - owner.throw_mode_on() - cooldown = TRUE - refresh_action_button() - addtimer(CALLBACK(src, .proc/reset_cooldown), cooldown_time) - else - qdel(web) - -/obj/item/organ/external/head/insectoid/mantid/proc/reset_cooldown() - cooldown = FALSE - refresh_action_button() diff --git a/mods/ascent/mobs/bodyparts_insectoid.dm b/mods/ascent/mobs/bodyparts_insectoid.dm deleted file mode 100644 index 67ff6148a9c3..000000000000 --- a/mods/ascent/mobs/bodyparts_insectoid.dm +++ /dev/null @@ -1,80 +0,0 @@ -/obj/item/organ/external/arm/insectoid - name = "left forelimb" - amputation_point = "coxa" - icon_position = LEFT - encased = "carapace" - -/obj/item/organ/external/arm/right/insectoid - name = "right forelimb" - amputation_point = "coxa" - icon_position = RIGHT - encased = "carapace" - -/obj/item/organ/external/leg/insectoid - name = "left tail side" - icon_position = LEFT - encased = "carapace" - -/obj/item/organ/external/leg/right/insectoid - name = "right tail side" - encased = "carapace" - -/obj/item/organ/external/foot/insectoid - name = "left tail tip" - icon_position = LEFT - encased = "carapace" - -/obj/item/organ/external/foot/right/insectoid - name = "right tail tip" - icon_position = RIGHT - encased = "carapace" - -/obj/item/organ/external/hand/insectoid - name = "left grasper" - icon_position = LEFT - encased = "carapace" - -/obj/item/organ/external/hand/right/insectoid - name = "right grasper" - icon_position = RIGHT - encased = "carapace" - -/obj/item/organ/external/groin/insectoid - name = "abdomen" - icon_position = UNDER - encased = "carapace" - -/obj/item/organ/external/head/insectoid - name = "head" - has_lips = 0 - encased = "carapace" - -/obj/item/organ/external/chest/insectoid - name = "thorax" - encased = "carapace" - -/obj/item/organ/internal/heart/insectoid - name = "hemolymph pump" - -/obj/item/organ/internal/stomach/insectoid - name = "digestive sac" - -/obj/item/organ/internal/lungs/insectoid - name = "spiracle junction" - icon_state = "trach" - gender = NEUTER - -/obj/item/organ/internal/liver/insectoid - name = "primary filters" - gender = PLURAL - -/obj/item/organ/internal/kidneys/insectoid - name = "secondary filters" - -/obj/item/organ/internal/brain/insectoid - name = "ganglial junction" - icon_state = "brain-distributed" - -/obj/item/organ/internal/eyes/insectoid - name = "compound ocelli" - icon_state = "eyes-compound" \ No newline at end of file diff --git a/mods/ascent/mobs/bodyparts_serpentid.dm b/mods/ascent/mobs/bodyparts_serpentid.dm deleted file mode 100644 index c616afc677fb..000000000000 --- a/mods/ascent/mobs/bodyparts_serpentid.dm +++ /dev/null @@ -1,210 +0,0 @@ -/obj/item/organ/internal/eyes/insectoid/serpentid - name = "compound eyes" - innate_flash_protection = FLASH_PROTECTION_VULNERABLE - contaminant_guard = 1 - action_button_name = "Toggle Eye Shields" - eye_icon = 'mods/ascent/icons/species/body/serpentid/eyes.dmi' - var/eyes_shielded - -/obj/item/organ/internal/eyes/insectoid/serpentid/get_special_overlay() - var/icon/I = get_onhead_icon() - if(I) - var/image/eye_overlay = image(I) - if(owner && owner.is_cloaked()) - eye_overlay.alpha = 100 - if(eyes_shielded) - eye_overlay.color = "#aaaaaa" - return eye_overlay - -/obj/item/organ/internal/eyes/insectoid/serpentid/additional_flash_effects(var/intensity) - if(!eyes_shielded) - take_internal_damage(max(0, 4 * (intensity))) - return 1 - else - return -1 - -/obj/item/organ/internal/eyes/insectoid/serpentid/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "serpentid-shield-[eyes_shielded ? 1 : 0]" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/internal/eyes/insectoid/serpentid/attack_self(var/mob/user) - . = ..() - if(.) - eyes_shielded = !eyes_shielded - if(eyes_shielded) - to_chat(owner, "Nearly opaque lenses slide down to shield your eyes.") - innate_flash_protection = FLASH_PROTECTION_MAJOR - owner.overlay_fullscreen("eyeshield", /obj/screen/fullscreen/blind) - owner.update_icons() - else - to_chat(owner, "Your protective lenses retract out of the way.") - innate_flash_protection = FLASH_PROTECTION_VULNERABLE - addtimer(CALLBACK(src, .proc/remove_shield), 1 SECONDS) - owner.update_icons() - refresh_action_button() - -/obj/item/organ/internal/eyes/insectoid/serpentid/proc/remove_shield() - owner.clear_fullscreen("eyeshield") - -/obj/item/organ/internal/eyes/serpentid/Initialize() - . = ..() - if(dna) - color = rgb(dna.GetUIValue(DNA_UI_EYES_R), dna.GetUIValue(DNA_UI_EYES_G), dna.GetUIValue(DNA_UI_EYES_B)) - -/obj/item/organ/internal/eyes/insectoid/serpentid/set_dna(var/datum/dna/new_dna) - . = ..() - color = rgb(new_dna.GetUIValue(DNA_UI_EYES_R), new_dna.GetUIValue(DNA_UI_EYES_G), new_dna.GetUIValue(DNA_UI_EYES_B)) - -/obj/item/organ/internal/liver/insectoid/serpentid - name = "toxin filter" - color = "#66ff99" - organ_tag = BP_LIVER - parent_organ = BP_CHEST - -// These are not actually lungs and shouldn't be thought of as such despite the claims of the parent. -/obj/item/organ/internal/lungs/insectoid/serpentid - name = "tracheae" - gender = PLURAL - organ_tag = BP_TRACH - parent_organ = BP_GROIN - active_breathing = 0 - safe_toxins_max = 10 - -/obj/item/organ/internal/lungs/insectoid/serpentid/rupture() - to_chat(owner, "You feel air rushing through your trachea!") - -/obj/item/organ/internal/lungs/insectoid/serpentid/handle_failed_breath() - var/mob/living/carbon/human/H = owner - - H.adjustOxyLoss(-(HUMAN_MAX_OXYLOSS * owner.chem_effects[CE_OXYGENATED])) - - if(breath_fail_ratio < 0.25 && owner.chem_effects[CE_OXYGENATED]) - H.oxygen_alert = 0 - if(breath_fail_ratio >= 0.25 && (damage || world.time > last_successful_breath + 2 MINUTES)) - H.adjustOxyLoss(HUMAN_MAX_OXYLOSS * breath_fail_ratio) - if(owner.chem_effects[CE_OXYGENATED]) - H.oxygen_alert = 1 - else - H.oxygen_alert = 2 - -/obj/item/organ/internal/brain/insectoid/serpentid - var/lowblood_tally = 0 - name = "distributed nervous system" - parent_organ = BP_CHEST - -/obj/item/organ/internal/brain/insectoid/serpentid/Process() - if(!owner || !owner.should_have_organ(BP_HEART)) - return - - var/blood_volume = owner.get_blood_circulation() - - //Effects of bloodloss - switch(blood_volume) - if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) - lowblood_tally = 2 - if(prob(1)) - to_chat(owner, "You're finding it difficult to move.") - if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) - lowblood_tally = 4 - if(prob(1)) - to_chat(owner, "Moving has become very difficult.") - if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) - lowblood_tally = 6 - if(prob(15)) - to_chat(owner, "You're almost unable to move!") - if(!owner.pulling_punches) - var/datum/species/serpentid/nab = species - nab.arm_swap(owner, TRUE) - if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) - lowblood_tally = 10 - if(prob(30) && !owner.pulling_punches) - var/datum/species/serpentid/nab = species - nab.arm_swap(owner, TRUE) - if(prob(10)) - to_chat(owner, "Your body is barely functioning and is starting to shut down.") - owner.Paralyse(1) - var/obj/item/organ/internal/I = pick(owner.internal_organs) - I.take_internal_damage(5) - ..() - -/obj/item/organ/external/chest/insectoid/serpentid - name = "thorax" - encased = "carapace" - action_button_name = "Perform Threat Display" - -/obj/item/organ/external/chest/insectoid/serpentid/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "serpentid-threat" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/external/chest/insectoid/serpentid/attack_self(var/mob/user) - . = ..() - if(.) - if(owner.incapacitated()) - to_chat(owner, "You can't do a threat display in your current state.") - return - if(owner.skin_state == SKIN_NORMAL) - if(owner.pulling_punches) - to_chat(owner, "You must be in your hunting stance to do a threat display.") - else - var/message = alert(owner, "Would you like to show a scary message?",,"Cancel","Yes", "No") - if(message == "Cancel") - return - else if(message == "Yes") - owner.visible_message("[owner]'s skin shifts to a deep red colour with dark chevrons running down in an almost hypnotic \ - pattern. Standing tall, \he strikes, sharp spikes aimed at those threatening \him, claws whooshing through the air past them.") - playsound(owner.loc, 'sound/effects/angrybug.ogg', 60, 0) - owner.skin_state = SKIN_THREAT - owner.update_skin() - addtimer(CALLBACK(owner, /mob/living/carbon/human/proc/reset_skin), 10 SECONDS, TIMER_UNIQUE) - else if(owner.skin_state == SKIN_THREAT) - owner.reset_skin() - -/obj/item/organ/external/head/insectoid/serpentid - name = "head" - vital = 0 - action_button_name = "Switch Stance" // Basically just a wrapper for switch stance verb, since GAS use it more than normals. - limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_GENDERED_ICON | ORGAN_FLAG_CAN_BREAK - -/obj/item/organ/external/head/insectoid/serpentid/get_eye_overlay() - var/obj/item/organ/internal/eyes/eyes = owner.internal_organs_by_name[owner.species.vision_organ ? owner.species.vision_organ : BP_EYES] - if(eyes) - return eyes.get_special_overlay() - -/obj/item/organ/external/head/insectoid/serpentid/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "serpentid-stance-[owner && owner.pulling_punches ? 1 : 0]" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/external/head/insectoid/serpentid/attack_self(var/mob/user) - . = ..() - if(.) - owner.pull_punches() - refresh_action_button() - -/obj/item/organ/external/groin/insectoid/serpentid - name = "abdomen" - icon_position = UNDER - encased = "carapace" - action_button_name = "Toggle Active Camo" - cavity_max_w_class = ITEM_SIZE_LARGE - -/obj/item/organ/external/groin/insectoid/serpentid/refresh_action_button() - . = ..() - if(.) - action.button_icon_state = "serpentid-cloak-[owner && owner.is_cloaked_by(species) ? 1 : 0]" - if(action.button) action.button.UpdateIcon() - -/obj/item/organ/external/groin/insectoid/serpentid/attack_self(var/mob/user) - . = ..() - if(.) - if(owner.is_cloaked_by(species)) - owner.remove_cloaking_source(species) - else - owner.add_cloaking_source(species) - owner.apply_effect(2, STUN, 0) - refresh_action_button() diff --git a/mods/ascent/structures/furniture.dm b/mods/ascent/structures/furniture.dm deleted file mode 100644 index 4971e1130479..000000000000 --- a/mods/ascent/structures/furniture.dm +++ /dev/null @@ -1,17 +0,0 @@ -MANTIDIFY(/obj/structure/bed/chair/padded/purple, "mantid nest", "resting place") - -/obj/structure/bed/chair/padded/purple/ascent - icon_state = "nest_chair" - pixel_z = 0 - -/obj/structure/bed/chair/padded/purple/ascent/gyne - name = "mantid throne" - icon_state = "nest_chair_large" - -/obj/structure/ascent_spawn - name = "mantid cryotank" - desc = "A liquid-filled, cloudy tank with strange forms twitching inside." - icon = 'icons/obj/cryogenics.dmi' - icon_state = "cellold2" - anchored = TRUE - density = TRUE diff --git a/mods/ascent/structures/ship_furniture.dm b/mods/ascent/structures/ship_furniture.dm deleted file mode 100644 index 1367cd63894b..000000000000 --- a/mods/ascent/structures/ship_furniture.dm +++ /dev/null @@ -1,50 +0,0 @@ -MANTIDIFY(/obj/structure/bed/chair/padded/purple, "mantid nest", "resting place") - -/obj/structure/bed/chair/padded/purple/ascent - icon_state = "nest_chair" - pixel_z = 0 - -/obj/structure/bed/chair/padded/purple/ascent/gyne - name = "mantid throne" - icon_state = "nest_chair_large" - -/obj/structure/ascent_spawn - name = "mantid cryotank" - desc = "A liquid-filled, cloudy tank with strange forms twitching inside." - icon = 'icons/obj/cryogenics.dmi' - icon_state = "cellold2" - anchored = TRUE - density = TRUE - -/obj/structure/mopbucket/ascent - name = "portable liquid cleaning agent holder" - desc = "An alien container of some sort." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - -/obj/structure/closet/crate/freezer/meat/ascent - name = "cryogenic stasis unit" - desc = "A bizarre alien stasis unit." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - -/obj/structure/hygiene/shower/ascent - name = "hydrating decontamination armature" - desc = "An alien vertical squirt bath." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - -/obj/structure/hygiene/sink/ascent - name = "hydration outlet" - desc = "An alien wall mounted basin with mysterious protrusions." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - -/obj/structure/reagent_dispensers/water_cooler/ascent - name = "hydration dispensator" - desc = "An alien device housing liquid for alien purposes." - icon = 'mods/ascent/icons/ascent_doodads.dmi' - cups = 50 - cup_type = /obj/item/chems/food/snacks/hydration - -/obj/structure/reagent_dispensers/water_cooler/ascent/DispenserMessages(var/mob/user) - return list("\The [user] grabs a hydration ration orb from \the [src].", "You grab a hydration ration orb from \the [src].") - -/obj/structure/reagent_dispensers/water_cooler/ascent/RejectionMessage(var/mob/user) - return "\The [src]'s orb supply is empty. Notify a control mind." diff --git a/mods/ascent/turfs/ship.dm b/mods/ascent/turfs/ship.dm deleted file mode 100644 index bc665aafdb6e..000000000000 --- a/mods/ascent/turfs/ship.dm +++ /dev/null @@ -1,39 +0,0 @@ -/decl/flooring/tiling_ascent - name = "floor" - desc = "An odd jigsaw puzzle of alloy plates." - icon = 'icons/turf/flooring/alium.dmi' - icon_base = "jaggy" - has_base_range = 6 - color = COLOR_GRAY40 - flags = TURF_CAN_BREAK | TURF_CAN_BURN - footstep_type = /decl/footsteps/tiles - -/turf/simulated/wall/ascent - color = COLOR_PURPLE - -/turf/simulated/wall/r_wall/ascent - color = COLOR_PURPLE - -/turf/simulated/floor/shuttle_ceiling/ascent - color = COLOR_PURPLE - icon_state = "jaggy" - icon = 'icons/turf/flooring/alium.dmi' - -/turf/simulated/floor/ascent - name = "mantid plating" - color = COLOR_GRAY20 - initial_gas = list(/decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5, GAS_OXYGEN = MOLES_CELLSTANDARD * 0.5) - icon_state = "curvy" - icon = 'icons/turf/flooring/alium.dmi' - -/turf/simulated/floor/ascent/Initialize() - . = ..() - icon_state = "curvy[rand(0,6)]" - -/turf/simulated/floor/tiled/ascent - name = "mantid tiling" - icon_state = "jaggy" - icon = 'icons/turf/flooring/alium.dmi' - color = COLOR_GRAY40 - initial_gas = list(/decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5, GAS_OXYGEN = MOLES_CELLSTANDARD * 0.5) - initial_flooring = /decl/flooring/tiling_ascent diff --git a/mods/borers/borer.dm b/mods/borers/borer.dm deleted file mode 100644 index 99b71234c717..000000000000 --- a/mods/borers/borer.dm +++ /dev/null @@ -1,5 +0,0 @@ -#define MODE_BORER "borer" -#define CULTURE_SYMBIOTIC "Symbiote Host" - -/decl/modpack/borers - name = "Cortical Borers" \ No newline at end of file diff --git a/mods/borers/datum/antagonist.dm b/mods/borers/datum/antagonist.dm deleted file mode 100644 index d8f2364bbea1..000000000000 --- a/mods/borers/datum/antagonist.dm +++ /dev/null @@ -1,67 +0,0 @@ -GLOBAL_DATUM_INIT(borers, /datum/antagonist/borer, new) - -/datum/antagonist/borer - id = MODE_BORER - role_text = "Cortical Borer" - role_text_plural = "Cortical Borers" - flags = ANTAG_OVERRIDE_MOB | ANTAG_RANDSPAWN | ANTAG_OVERRIDE_JOB - - mob_path = /mob/living/simple_animal/borer - welcome_text = "Use your Infest power to crawl into the ear of a host and fuse with their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your fellow borers with :x." - antag_indicator = "hudborer" - antaghud_indicator = "hudborer" - - faction_role_text = "Borer Thrall" - faction_descriptor = "Unity" - faction_welcome = "You are now a thrall to a cortical borer. Please listen to what they have to say; they're in your head." - faction = "borer" - faction_indicator = "hudalien" - - hard_cap = 5 - hard_cap_round = 8 - initial_spawn_req = 3 - initial_spawn_target = 5 - - spawn_announcement_title = "Lifesign Alert" - spawn_announcement_delay = 5000 - -/datum/antagonist/borer/get_extra_panel_options(var/datum/mind/player) - return "\[put in host\]" - -/datum/antagonist/borer/create_objectives(var/datum/mind/player) - if(!..()) - return - player.objectives += new /datum/objective/borer_survive() - player.objectives += new /datum/objective/borer_reproduce() - player.objectives += new /datum/objective/escape() - -/datum/antagonist/borer/place_mob(var/mob/living/mob) - var/mob/living/simple_animal/borer/borer = mob - if(istype(borer)) - var/mob/living/carbon/human/host - for(var/mob/living/carbon/human/H in SSmobs.mob_list) - if(H.stat != DEAD && !H.has_brain_worms()) - var/obj/item/organ/external/head = H.get_organ(BP_HEAD) - if(head && !BP_IS_PROSTHETIC(head)) - host = H - break - if(istype(host)) - var/obj/item/organ/external/head = host.get_organ(BP_HEAD) - if(head) - borer.host = host - head.implants += borer - borer.forceMove(head) - if(!borer.host_brain) - borer.host_brain = new(borer) - borer.host_brain.SetName(host.name) - borer.host_brain.real_name = host.real_name - return - ..() // Place them at a vent if they can't get a host. - -/datum/antagonist/borer/Initialize() - spawn_announcement = replacetext(GLOB.using_map.unidentified_lifesigns_message, "%STATION_NAME%", station_name()) - spawn_announcement_sound = GLOB.using_map.lifesign_spawn_sound - ..() - -/datum/antagonist/borer/attempt_random_spawn() - if(config.aliens_allowed) ..() diff --git a/mods/borers/datum/ghost_trap.dm b/mods/borers/datum/ghost_trap.dm deleted file mode 100644 index f27a9605b740..000000000000 --- a/mods/borers/datum/ghost_trap.dm +++ /dev/null @@ -1,17 +0,0 @@ -/***************** -* Cortical Borer * -*****************/ -/datum/ghosttrap/borer - object = "cortical borer" - ban_checks = list(MODE_BORER) - pref_check = MODE_BORER - ghost_trap_message = "They are occupying a borer now." - ghost_trap_role = "Cortical Borer" - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/borer/welcome_candidate(var/mob/target) - to_chat(target, "You are a cortical borer! You are a brain slug that worms its way \ - into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \ - your host and your eventual spawn safe and warm.") - to_chat(target, "You can speak to your victim with say, to other borers with say [target.get_language_prefix()]x, and use your Abilities tab to access powers.") diff --git a/mods/borers/datum/language.dm b/mods/borers/datum/language.dm deleted file mode 100644 index cef8726db139..000000000000 --- a/mods/borers/datum/language.dm +++ /dev/null @@ -1,30 +0,0 @@ -/decl/language/corticalborer - name = "Cortical Link" - desc = "Cortical borers possess a strange link between their tiny minds." - speech_verb = "sings" - ask_verb = "sings" - exclaim_verb = "sings" - colour = "alien" - key = "z" - flags = RESTRICTED | HIVEMIND - shorthand = "N/A" - hidden_from_codex = TRUE - -/decl/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) - - var/mob/living/simple_animal/borer/B - - if(istype(speaker,/mob/living/carbon)) - var/mob/living/carbon/M = speaker - B = M.has_brain_worms() - else if(istype(speaker,/mob/living/simple_animal/borer)) - B = speaker - - if(B) - if(B.host) - if(B.host.nutrition < 50 || B.host.stat) - to_chat(speaker, SPAN_WARNING("Your host is too weak to relay your broadcast.")) - return FALSE - B.host.nutrition -= rand(1, 3) - speaker_mask = B.truename - ..(speaker,message,speaker_mask) \ No newline at end of file diff --git a/mods/borers/datum/symbiote.dm b/mods/borers/datum/symbiote.dm deleted file mode 100644 index 5321fcd04371..000000000000 --- a/mods/borers/datum/symbiote.dm +++ /dev/null @@ -1,127 +0,0 @@ -GLOBAL_LIST_INIT(symbiote_starting_points, new) - -/decl/cultural_info/culture/symbiotic - name = CULTURE_SYMBIOTIC - description = "Your culture has always welcomed a form of brain-slug called cortical borers into their bodies, \ - and your upbringing taught that this was a normal and beneficial state of affairs. Taking this background will \ - allow symbiote players to join as your mind-partner. Symbiotes can secrete beneficial chemicals, translate languages \ - and are rendered docile by sugar. Unlike feral cortical borers, they cannot take control of your body or cause brain damage." - economic_power = 0.8 - var/matches_to_role = /datum/job/symbiote - -/datum/job/symbiote - title = "Symbiote" - department_refs = list(DEPT_CIVILIAN, DEPT_SCIENCE) - total_positions = -1 - spawn_positions = -1 - supervisors = "your host" - selection_color = "#ad6bad" - access = list() - minimal_access = list() - minimal_player_age = 14 - economic_power = 0 - defer_roundstart_spawn = TRUE - hud_icon = "hudblank" - outfit_type = /decl/hierarchy/outfit/job/assistant - create_record = FALSE - var/check_whitelist // = "Symbiote" - var/static/mob/living/simple_animal/borer/preview_slug - -/datum/job/symbiote/post_equip_rank(var/mob/person, var/alt_title) - - var/mob/living/simple_animal/borer/symbiote = person - symbiote.SetName(symbiote.truename) - symbiote.real_name = symbiote.truename - - to_chat(person, "You are a [alt_title || title].") - to_chat(person, "As the [alt_title || title] you answer directly to [supervisors]. Special circumstances may change this.") - - if(symbiote.host) - if(symbiote.host.mind) - var/a_the = (symbiote.host.mind.assigned_job && symbiote.host.mind.assigned_job.total_positions == 1) ? "the" : "a" - var/use_title = symbiote.host.mind.role_alt_title || symbiote.host.mind.assigned_role - to_chat(symbiote, SPAN_NOTICE("Your current host is \the [symbiote.host.real_name], [a_the] [use_title]. Help them stay safe and happy, and assist them in achieving their goals. Remember, your host's desires take precedence over everyone else's.")) - to_chat(symbiote.host, SPAN_NOTICE("Your current symbiote, [symbiote.name], has awakened. They will help you in whatever way they can. Treat them kindly.")) - else - to_chat(symbiote, SPAN_NOTICE("Your host is \the [symbiote.host.real_name]. They are mindless and you should probably find a new one soon.")) - else - to_chat(symbiote, SPAN_DANGER("You do not currently have a host.")) - -/datum/job/symbiote/is_restricted(var/datum/preferences/prefs, var/feedback) - . = ..() - if(. && check_whitelist && prefs?.client && !is_alien_whitelisted(prefs.client.mob, check_whitelist)) - if(feedback) - to_chat(prefs.client.mob, SPAN_WARNING("You are not whitelisted for [check_whitelist] roles.")) - . = FALSE - -/datum/job/symbiote/handle_variant_join(var/mob/living/carbon/human/H, var/alt_title) - - var/mob/living/simple_animal/borer/symbiote/symbiote = new - var/mob/living/carbon/human/host - try - // No clean way to handle kicking them back to the lobby at this point, so dump - // them into xenobio or latejoin instead if there are zero viable hosts left. - var/list/available_hosts = find_valid_hosts() - while(length(available_hosts) && (!host || !(host in available_hosts))) - host = input(H, "Who do you wish to be your mind-partner?", "Symbiote Spawn") as anything in available_hosts - var/list/current_hosts = find_valid_hosts() // Is the host still available? - if(QDELETED(host) || QDELETED(H) || !H.key || !(host in current_hosts)) - host = null - available_hosts = current_hosts - catch(var/exception/e) - log_debug("Exception during symbiote join: [e]") - - if(host) - var/obj/item/organ/external/head = host.get_organ(BP_HEAD) - symbiote.host = host - head.implants += symbiote - symbiote.forceMove(head) - if(!symbiote.host_brain) - symbiote.host_brain = new(symbiote) - symbiote.host_brain.SetName(host.real_name) - symbiote.host_brain.real_name = host.real_name - else - to_chat(symbiote, SPAN_DANGER("There are no longer any hosts available, so you are being placed in a safe area.")) - if(length(GLOB.symbiote_starting_points)) - symbiote.forceMove(pick(GLOB.symbiote_starting_points)) - else - symbiote.forceMove(pick(GLOB.latejoin)) - - if(H.mind) - H.mind.transfer_to(symbiote) - else - symbiote.key = H.key - qdel(H) - return symbiote - -/datum/job/symbiote/equip_preview(var/mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade, var/additional_skips) - if(!preview_slug) - preview_slug = new - H.appearance = preview_slug - return TRUE - -/datum/job/symbiote/proc/find_valid_hosts(var/just_checking) - . = list() - for(var/mob/living/carbon/human/H in GLOB.player_list) - if(H.stat == DEAD || !H.client || !H.ckey || !H.internal_organs_by_name[BP_BRAIN]) - continue - var/obj/item/organ/external/head = H.get_organ(BP_HEAD) - if(BP_IS_PROSTHETIC(head) || BP_IS_CRYSTAL(head) || head.has_growths()) - continue - var/decl/cultural_info/culture/symbiotic/culture = H.get_cultural_value(TAG_CULTURE) - if(!istype(culture) || culture.matches_to_role != type) - continue - . += H - if(just_checking) - return - -/datum/job/symbiote/is_position_available() - . = ..() && length(find_valid_hosts(TRUE)) - -/obj/effect/landmark/symbiote_start - name = "Symbiote Start" - delete_me = TRUE - -/obj/effect/landmark/symbiote_start/Initialize() - GLOB.symbiote_starting_points |= get_turf(src) - . = ..() diff --git a/mods/borers/mob/borer/borer.dm b/mods/borers/mob/borer/borer.dm deleted file mode 100644 index 6a5cdc9f002b..000000000000 --- a/mods/borers/mob/borer/borer.dm +++ /dev/null @@ -1,276 +0,0 @@ -/mob/living/simple_animal/borer - name = "cortical borer" - real_name = "cortical borer" - desc = "A small, quivering sluglike creature." - speak_emote = list("chirrups") - emote_hear = list("chirrups") - response_help = "pokes" - response_disarm = "prods" - response_harm = "stomps on" - icon_state = "brainslug" - item_state = "voxslug" // For the lack of a better sprite... - icon_living = "brainslug" - icon_dead = "brainslug_dead" - speed = 5 - a_intent = I_HURT - stop_automated_movement = 1 - status_flags = CANPUSH - natural_weapon = /obj/item/natural_weapon/bite/weak - friendly = "prods" - wander = 0 - pass_flags = PASS_FLAG_TABLE - universal_understand = TRUE - holder_type = /obj/item/holder/borer - mob_size = MOB_SIZE_SMALL - can_escape = TRUE - - bleed_colour = "#816e12" - - var/static/list/chemical_types = list( - "anti-trauma" = /decl/material/liquid/brute_meds, - "amphetamines" = /decl/material/liquid/amphetamines, - "painkillers" = /decl/material/liquid/painkillers - ) - - var/generation = 1 - var/static/list/borer_names = list( - "Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary", - "Septenary", "Octonary", "Novenary", "Decenary", "Undenary", "Duodenary", - ) - - var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. - var/truename // Name used for brainworm-speak. - var/controlling // Used in human death check. - var/docile = FALSE // Sugar can stop borers from acting. - var/has_reproduced // Whether or not the borer has reproduced, for objective purposes. - var/roundstart // Whether or not this borer has been mapped and should not look for a player initially. - var/neutered // 'borer lite' mode - fewer powers, less hostile to the host. - var/mob/living/carbon/human/host // Human host for the brain worm. - var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. - -/obj/item/holder/borer - origin_tech = "{'biotech':6}" - -/mob/living/simple_animal/borer/roundstart - roundstart = TRUE - -/mob/living/simple_animal/borer/symbiote - name = "symbiote" - real_name = "symbiote" - neutered = TRUE - -/mob/living/simple_animal/borer/Login() - . = ..() - if(client) - client.screen |= hud_elements - client.screen |= hud_intent_selector - if(mind && !neutered) - GLOB.borers.add_antagonist(mind) - -/mob/living/simple_animal/borer/Logout() - . = ..() - if(client) - client.screen -= hud_elements - client.screen -= hud_intent_selector - -/mob/living/simple_animal/borer/Initialize(var/mapload, var/gen=1) - hud_intent_selector = new - hud_inject_chemicals = new - hud_leave_host = new - hud_elements = list( - hud_inject_chemicals, - hud_leave_host - ) - if(!neutered) - hud_toggle_control = new - hud_elements += hud_toggle_control - - . = ..() - - add_language(/decl/language/corticalborer) - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide - - generation = gen - set_borer_name() - - if(!roundstart) - request_player() - -/mob/living/simple_animal/borer/Destroy() - if(client) - client.screen -= hud_elements - client.screen -= hud_intent_selector - QDEL_NULL_LIST(hud_elements) - QDEL_NULL(hud_intent_selector) - hud_toggle_control = null - hud_inject_chemicals = null - hud_leave_host = null - . = ..() - -/mob/living/simple_animal/borer/proc/set_borer_name() - truename = "[borer_names[min(generation, borer_names.len)]] [random_id("borer[generation]", 1000, 9999)]" - -/mob/living/simple_animal/borer/Life() - - sdisabilities = 0 - if(host) - blinded = host.blinded - eye_blind = host.eye_blind - eye_blurry = host.eye_blurry - if(host.sdisabilities & BLINDED) - sdisabilities |= BLINDED - if(host.sdisabilities & DEAFENED) - sdisabilities |= DEAFENED - else - blinded = FALSE - eye_blind = 0 - eye_blurry = 0 - - . = ..() - if(!.) - return FALSE - - if(host) - - if(!stat && !host.stat) - - if(host.reagents.has_reagent(/decl/material/liquid/nutriment/sugar)) - if(!docile) - if(controlling) - to_chat(host, SPAN_NOTICE("You feel the soporific flow of sugar in your host's blood, lulling you into docility.")) - else - to_chat(src, SPAN_NOTICE("You feel the soporific flow of sugar in your host's blood, lulling you into docility.")) - docile = 1 - else - if(docile) - if(controlling) - to_chat(host, SPAN_NOTICE("You shake off your lethargy as the sugar leaves your host's blood.")) - else - to_chat(src, SPAN_NOTICE("You shake off your lethargy as the sugar leaves your host's blood.")) - docile = 0 - - if(chemicals < 250 && host.nutrition >= (neutered ? 200 : 50)) - host.nutrition-- - chemicals++ - - if(controlling) - - if(neutered) - host.release_control() - return - - if(docile) - to_chat(host, SPAN_NOTICE("You are feeling far too docile to continue controlling your host...")) - host.release_control() - return - - if(prob(5)) - host.adjustBrainLoss(0.1) - - if(prob(host.getBrainLoss()/20)) - INVOKE_ASYNC(host, /mob/proc/say, "*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]") - -/mob/living/simple_animal/borer/Stat() - . = ..() - statpanel("Status") - - if(SSevac.evacuation_controller) - var/eta_status = SSevac.evacuation_controller.get_status_panel_eta() - if(eta_status) - stat(null, eta_status) - - if (client.statpanel == "Status") - stat("Chemicals", chemicals) - -/mob/living/simple_animal/borer/proc/detatch() - - if(!host || !controlling) return - - if(istype(host,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = host - var/obj/item/organ/external/head = H.get_organ(BP_HEAD) - head.implants -= src - - controlling = 0 - - host.remove_language(/decl/language/corticalborer) - host.verbs -= /mob/living/carbon/proc/release_control - host.verbs -= /mob/living/carbon/proc/punish_host - host.verbs -= /mob/living/carbon/proc/spawn_larvae - - if(host_brain) - - // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. - // computer_id and IP are not updated magically on their own in offline mobs -walter0o - - // host -> self - var/h2s_id = host.computer_id - var/h2s_ip= host.lastKnownIP - host.computer_id = null - host.lastKnownIP = null - - src.ckey = host.ckey - - if(!src.computer_id) - src.computer_id = h2s_id - - if(!host_brain.lastKnownIP) - src.lastKnownIP = h2s_ip - - // brain -> host - var/b2h_id = host_brain.computer_id - var/b2h_ip= host_brain.lastKnownIP - host_brain.computer_id = null - host_brain.lastKnownIP = null - - host.ckey = host_brain.ckey - - if(!host.computer_id) - host.computer_id = b2h_id - - if(!host.lastKnownIP) - host.lastKnownIP = b2h_ip - - qdel(host_brain) - -#define COLOR_BORER_RED "#ff5555" -/mob/living/simple_animal/borer/proc/set_ability_cooldown(var/amt) - last_special = world.time + amt - for(var/obj/thing in hud_elements) - thing.color = COLOR_BORER_RED - addtimer(CALLBACK(src, /mob/living/simple_animal/borer/proc/reset_ui_callback), amt) -#undef COLOR_BORER_RED - -/mob/living/simple_animal/borer/proc/leave_host() - - for(var/obj/thing in hud_elements) - thing.alpha = 0 - thing.invisibility = INVISIBILITY_MAXIMUM - - if(!host) return - - if(host.mind) - GLOB.borers.remove_antagonist(host.mind) - - dropInto(host.loc) - - reset_view(null) - machine = null - - host.reset_view(null) - host.machine = null - - var/mob/living/H = host - H.status_flags &= ~PASSEMOTES - host = null - return - -//Procs for grabbing players. -/mob/living/simple_animal/borer/proc/request_player() - var/datum/ghosttrap/G = get_ghost_trap("cortical borer") - G.request_player(src, "A cortical borer needs a player.") - -/mob/living/simple_animal/borer/flash_eyes(intensity, override_blindness_check, affect_silicon, visual, type) - intensity *= 1.5 - . = ..() \ No newline at end of file diff --git a/mods/borers/mob/borer/borer_attacks.dm b/mods/borers/mob/borer/borer_attacks.dm deleted file mode 100644 index 8a3c3b56adc6..000000000000 --- a/mods/borers/mob/borer/borer_attacks.dm +++ /dev/null @@ -1,60 +0,0 @@ -/mob/living/simple_animal/borer/UnarmedAttack(atom/A, proximity) - - if(!isliving(A) || a_intent != I_GRAB) - return ..() - - if(host || !can_use_borer_ability(requires_host_value = FALSE, check_last_special = FALSE)) - return - - var/mob/living/M = A - if(M.has_brain_worms()) - to_chat(src, SPAN_WARNING("You cannot take a host who already has a passenger!")) - return - - //TODO generalize borers to enter any mob. Until then, return early. - if(!ishuman(M)) - to_chat(src, SPAN_WARNING("This creature is not sufficiently intelligent to host you.")) - return - // end TODO - - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/E = H.organs_by_name[BP_HEAD] - if(!E || E.is_stump()) - to_chat(src, SPAN_WARNING("\The [H] does not have a head!")) - return - if(!H.should_have_organ(BP_BRAIN)) - to_chat(src, SPAN_WARNING("\The [H] does not seem to have a brain cavity to enter.")) - return - if(H.check_head_coverage()) - to_chat(src, SPAN_WARNING("You cannot get through that host's protective gear.")) - return - - to_chat(M, SPAN_WARNING("Something slimy begins probing at the opening of your ear canal...")) - to_chat(src, SPAN_NOTICE("You slither up [M] and begin probing at their ear canal...")) - set_ability_cooldown(5 SECONDS) - - if(!do_after(src, 3 SECONDS, M)) - return - - to_chat(src, SPAN_NOTICE("You wiggle into \the [M]'s ear.")) - if(M.stat == CONSCIOUS) - to_chat(M, SPAN_DANGER("Something wet, cold and slimy wiggles into your ear!")) - - host = M - host.status_flags |= PASSEMOTES - forceMove(host) - - for(var/obj/thing in hud_elements) - thing.alpha = 255 - thing.invisibility = 0 - - //Update their traitor status. - if(host.mind && !neutered) - GLOB.borers.add_antagonist_mind(host.mind, 1, GLOB.borers.faction_role_text, GLOB.borers.faction_welcome) - - if(istype(host, /mob/living/carbon/human)) - var/obj/item/organ/I = H.internal_organs_by_name[BP_BRAIN] - if(!I) // No brain organ, so the borer moves in and replaces it permanently. - replace_brain() - else if(E) // If they're in normally, implant removal can get them out. - E.implants += src diff --git a/mods/borers/mob/borer/borer_captive.dm b/mods/borers/mob/borer/borer_captive.dm deleted file mode 100644 index 377935f26639..000000000000 --- a/mods/borers/mob/borer/borer_captive.dm +++ /dev/null @@ -1,61 +0,0 @@ -/mob/living/captive_brain - name = "host brain" - real_name = "host brain" - universal_understand = TRUE - - meat_type = null - meat_amount = 0 - skin_material = null - skin_amount = 0 - bone_material = null - bone_amount = 0 - -/mob/living/captive_brain/say(var/message) - - if (src.client) - if(client.prefs.muted & MUTE_IC) - to_chat(src, SPAN_WARNING("You cannot speak in IC (muted).")) - return - - if(istype(src.loc,/mob/living/simple_animal/borer)) - - message = sanitize(message) - if (!message) - return - log_say("[key_name(src)] : [message]") - if (stat == 2) - return say_dead(message) - - var/mob/living/simple_animal/borer/B = src.loc - to_chat(src, "You whisper silently, \"[message]\"") - to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"") - - for (var/mob/M in GLOB.player_list) - if (istype(M, /mob/new_player)) - continue - else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) - to_chat(M, "The captive mind of [src] whispers, \"[message]\"") - -/mob/living/captive_brain/process_resist() - //Resisting control by an alien mind. - if(istype(src.loc,/mob/living/simple_animal/borer)) - var/mob/living/simple_animal/borer/B = src.loc - var/mob/living/captive_brain/H = src - - to_chat(H, "You begin doggedly resisting the parasite's control (this will take approximately sixty seconds).") - to_chat(B.host, "You feel the captive mind of [src] begin to resist your control.") - - spawn(rand(200,250)+B.host.getBrainLoss()) - if(!B || !B.controlling) return - - B.host.adjustBrainLoss(rand(0.1,0.5)) - to_chat(H, "With an immense exertion of will, you regain control of your body!") - to_chat(B.host, "You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.") - B.detatch() - verbs -= /mob/living/carbon/proc/release_control - verbs -= /mob/living/carbon/proc/punish_host - verbs -= /mob/living/carbon/proc/spawn_larvae - - return - - ..() diff --git a/mods/borers/mob/borer/borer_hud.dm b/mods/borers/mob/borer/borer_hud.dm deleted file mode 100644 index 65919362b560..000000000000 --- a/mods/borers/mob/borer/borer_hud.dm +++ /dev/null @@ -1,142 +0,0 @@ -/mob/living/simple_animal/borer - var/list/hud_elements = list() - var/obj/screen/intent/hud_intent_selector - var/obj/screen/borer/toggle_host_control/hud_toggle_control - var/obj/screen/borer/inject_chemicals/hud_inject_chemicals - var/obj/screen/borer/leave_host/hud_leave_host - -/mob/living/simple_animal/borer/proc/reset_ui_callback() - if(world.time >= last_special) - for(var/obj/thing in hud_elements) - thing.color = null - -/obj/screen/borer - icon = 'mods/borers/icons/borer_ui.dmi' - alpha = 0 - invisibility = INVISIBILITY_MAXIMUM - -/obj/screen/borer/Click(location, control, params) - if(!istype(usr, /mob/living/simple_animal/borer)) - return FALSE - if(usr.stat == DEAD) - return FALSE - var/mob/living/simple_animal/borer/worm = usr - if(!worm.host) - return FALSE - return TRUE - -/obj/screen/borer/toggle_host_control - name = "Seize Control" - icon_state = "seize_control" - screen_loc = "LEFT-3,TOP-1" - -/obj/screen/borer/toggle_host_control/Click(location, control, params) - . = ..() - if(!.) - return FALSE - - var/mob/living/simple_animal/borer/worm = usr - if(!worm.can_use_borer_ability()) - return - - if(worm.neutered) - to_chat(worm, SPAN_WARNING("You cannot do that.")) - return - - to_chat(worm, SPAN_NOTICE("You begin delicately adjusting your connection to the host brain...")) - if(!do_after(worm, 100+(worm.host.getBrainLoss()*5) || !worm.host || !worm.can_use_borer_ability())) - return - - to_chat(worm, SPAN_DANGER("You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.")) - to_chat(worm.host, SPAN_DANGER("You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.")) - worm.host.add_language(/decl/language/corticalborer) - - // host -> brain - var/h2b_id = worm.host.computer_id - var/h2b_ip= worm.host.lastKnownIP - worm.host.computer_id = null - worm.host.lastKnownIP = null - qdel(worm.host_brain) - worm.host_brain = new(worm) - worm.host_brain.ckey = worm.host.ckey - worm.host_brain.SetName(worm.host.name) - if(!worm.host_brain.computer_id) - worm.host_brain.computer_id = h2b_id - if(!worm.host_brain.lastKnownIP) - worm.host_brain.lastKnownIP = h2b_ip - - // self -> host - var/s2h_id = worm.computer_id - var/s2h_ip= worm.lastKnownIP - worm.computer_id = null - worm.lastKnownIP = null - worm.host.ckey = worm.ckey - if(!worm.host.computer_id) - worm.host.computer_id = s2h_id - if(!worm.host.lastKnownIP) - worm.host.lastKnownIP = s2h_ip - worm.controlling = TRUE - worm.host.verbs += /mob/living/carbon/proc/release_control - worm.host.verbs += /mob/living/carbon/proc/punish_host - worm.host.verbs += /mob/living/carbon/proc/spawn_larvae - - return TRUE - -/obj/screen/borer/inject_chemicals - name = "Inject Chemicals" - icon_state = "inject_chemicals" - screen_loc = "LEFT-2,TOP-1" - -/obj/screen/borer/inject_chemicals/Click(location, control, params) - . = ..() - if(!.) - return FALSE - - var/mob/living/simple_animal/borer/worm = usr - if(!worm.can_use_borer_ability()) - return - - if(worm.chemicals < 50) - to_chat(worm, SPAN_WARNING("You don't have enough chemicals!")) - return - - var/chem = input("Select a chemical to secrete.", "Chemicals") as null|anything in worm.chemical_types - if(!chem || !worm.chemical_types[chem] || !worm || QDELETED(worm) || worm.chemicals < 50 || !worm.can_use_borer_ability()) - return - - to_chat(worm, SPAN_NOTICE("You squirt a measure of [chem] from your reservoirs into \the [worm.host]'s bloodstream.")) - worm.host.reagents.add_reagent(worm.chemical_types[chem], 10) - worm.chemicals -= 50 - return TRUE - -/obj/screen/borer/leave_host - name = "Leave Host" - icon_state = "leave_host" - screen_loc = "LEFT-1,TOP-1" - -/obj/screen/borer/leave_host/Click(location, control, params) - . = ..() - if(!.) - return FALSE - - var/mob/living/simple_animal/borer/worm = usr - if(!worm.can_use_borer_ability()) - return - - to_chat(worm, SPAN_NOTICE("You begin disconnecting from \the [worm.host]'s synapses and prodding at their internal ear canal.")) - if(worm.host.stat == CONSCIOUS) - to_chat(worm.host, SPAN_WARNING("An odd, uncomfortable pressure begins to build inside your skull, behind your ear...")) - - if(!do_after(worm, 10 SECONDS) || !worm.can_use_borer_ability()) - return - - if(worm.host) - to_chat(worm, SPAN_WARNING("You wiggle out of [worm.host]'s ear and plop to the ground.")) - if(worm.host.stat != DEAD) - to_chat(worm.host, SPAN_DANGER("Something slimy wiggles out of your ear and plops to the ground!")) - if(!worm.neutered) - to_chat(worm.host, SPAN_DANGER("As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again.")) - worm.detatch() - worm.leave_host() - - return TRUE \ No newline at end of file diff --git a/mods/borers/mob/borer/say.dm b/mods/borers/mob/borer/say.dm deleted file mode 100644 index 6d3e817c9dde..000000000000 --- a/mods/borers/mob/borer/say.dm +++ /dev/null @@ -1,40 +0,0 @@ -/mob/living/simple_animal/borer/say(var/message) - - message = sanitize(message) - message = capitalize(message) - - if(!message) - return - - if (stat == 2) - return say_dead(message) - - if (stat) - return - - if (src.client) - if(client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot speak in IC (muted).") - return - - if (copytext(message, 1, 2) == "*") - return emote(copytext(message, 2)) - - var/decl/language/L = parse_language(message) - if(L && L.flags & HIVEMIND) - L.broadcast(src,trim(copytext(message,3)),src.truename) - return - - if(!host) - //TODO: have this pick a random mob within 3 tiles to speak for the borer. - to_chat(src, "You have no host to speak to.") - return //No host, no audible speech. - - to_chat(src, "You drop words into [host]'s mind: \"[message]\"") - to_chat(host, "Your own thoughts speak: \"[message]\"") - - for (var/mob/M in GLOB.player_list) - if (istype(M, /mob/new_player)) - continue - else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == GLOB.PREF_ALL_SPEECH) - to_chat(M, "[src.truename] whispers to [host], \"[message]\"") diff --git a/mods/borers/mob/overrides.dm b/mods/borers/mob/overrides.dm deleted file mode 100644 index 5634a31022a0..000000000000 --- a/mods/borers/mob/overrides.dm +++ /dev/null @@ -1,58 +0,0 @@ -#define HAS_BRAIN_WORMS(HOST) (locate(/mob/living/simple_animal/borer) in HOST?.contents) - -/obj/item/organ/external/has_growths() - . = ..() - if(!.) - . = locate(/mob/living/simple_animal/borer) in implants - -/mob/proc/has_brain_worms() - . = locate(/mob/living/simple_animal/borer) in contents - -/mob/handle_pre_transformation() - . = ..() - var/mob/living/simple_animal/borer/borer = HAS_BRAIN_WORMS(src) - if(borer) - borer.detatch() - borer.leave_host() - -/mob/living/carbon/human/handle_hud_list() - var/last_hud_bitfield = hud_updateflag - . = ..() - if(stat != DEAD && has_brain_worms() && BITTEST(last_hud_bitfield, STATUS_HUD) && hud_list[STATUS_HUD] && hud_list[STATUS_HUD_OOC]) - var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) - if(B.controlling) - var/image/holder = hud_list[STATUS_HUD] - holder.icon_state = "hudbrainworm" - var/image/holder2 = hud_list[STATUS_HUD_OOC] - holder2.icon_state = "hudbrainworm" - -/mob/living/carbon/human/say_understands(var/mob/other,var/decl/language/speaking = null) - if(has_brain_worms()) - return TRUE - return ..() - -/obj/item/organ/internal/brain/removed(var/mob/living/user) - if(istype(owner)) - var/mob/living/simple_animal/borer/borer = HAS_BRAIN_WORMS(owner) - if(borer) - borer.detatch() - . = ..() - -/mob/living/carbon/remove_implant(var/obj/item/implant, var/surgical_removal = FALSE) - . = ..() - if(. && !QDELETED(implant) && istype(implant, /mob/living/simple_animal/borer)) - var/mob/living/simple_animal/borer/worm = implant - if(worm.controlling) - release_control() - worm.detatch() - worm.leave_host() - -/obj/item/glass_jar/Initialize() - accept_mobs |= /mob/living/simple_animal/borer - . = ..() - -/mob/death() - var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) - if(B && B.controlling) - B.detatch() - . = ..() diff --git a/mods/borers/mob/powers.dm b/mods/borers/mob/powers.dm deleted file mode 100644 index 1d65e6e7cf17..000000000000 --- a/mods/borers/mob/powers.dm +++ /dev/null @@ -1,63 +0,0 @@ -//Brain slug proc for voluntary removal of control. -/mob/living/carbon/proc/release_control() - - set category = "Abilities" - set name = "Release Control" - set desc = "Release control of your host's body." - - var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) - - if(B && B.host_brain) - to_chat(src, "You withdraw your probosci, releasing control of [B.host_brain]") - - B.detatch() - - verbs -= /mob/living/carbon/proc/release_control - verbs -= /mob/living/carbon/proc/punish_host - verbs -= /mob/living/carbon/proc/spawn_larvae - - else - to_chat(src, "ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !") - -//Brain slug proc for tormenting the host. -/mob/living/carbon/proc/punish_host() - set category = "Abilities" - set name = "Torment host" - set desc = "Punish your host with agony." - - var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) - - if(!B) - return - - if(B.host_brain.ckey) - to_chat(src, "You send a punishing spike of psychic agony lancing into your host's brain.") - if (!can_feel_pain()) - to_chat(B.host_brain, "You feel a strange sensation as a foreign influence prods your mind.") - to_chat(src, "It doesn't seem to be as effective as you hoped.") - else - to_chat(B.host_brain, "Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!") - -/mob/living/carbon/proc/spawn_larvae() - set category = "Abilities" - set name = "Reproduce" - set desc = "Spawn several young." - - var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) - - if(!B) - return - - if(B.chemicals >= 100) - to_chat(src, "Your host twitches and quivers as you rapidly excrete a larva from your sluglike body.") - visible_message("\The [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") - B.chemicals -= 100 - B.has_reproduced = 1 - - new /obj/effect/decal/cleanable/vomit(get_turf(src)) - playsound(loc, 'sound/effects/splat.ogg', 50, 1) - new /mob/living/simple_animal/borer(get_turf(src), B.generation + 1) - - else - to_chat(src, "You do not have enough chemicals stored to reproduce.") - return diff --git a/mods/content/actors.dm b/mods/content/actors.dm new file mode 100644 index 000000000000..fbb88bad4975 --- /dev/null +++ b/mods/content/actors.dm @@ -0,0 +1,65 @@ +#ifndef MODPACK_ACTORS +#define MODPACK_ACTORS +#endif + +/decl/modpack/actors + name = "Actor Special Role" + +/decl/special_role/actor + name = "Actor" + name_plural = "Actors" + welcome_text = "You've been hired to entertain people through the power of television!" + landmark_id = "ActorSpawn" + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_SET_APPEARANCE | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED + hard_cap = 7 + hard_cap_round = 10 + initial_spawn_req = 1 + initial_spawn_target = 1 + show_objectives_on_creation = FALSE //actors are not antagonists and do not need the antagonist greet text + required_language = /decl/language/human/common + default_outfit = /decl/outfit/actor + default_access = list() + id_title = "Actor" + +/obj/abstract/landmark/actor_spawn + name = "ActorSpawn" + +/decl/outfit/actor + name = "Special Role - Actor" + uniform = /obj/item/clothing/jumpsuit/chameleon + shoes = /obj/item/clothing/shoes/chameleon + l_ear = /obj/item/radio/headset/entertainment + id_type = /obj/item/card/id/syndicate + +/decl/special_role/actor/greet(var/datum/mind/player) + if(!..()) + return + + player.current.show_message("You work for [global.using_map.company_name], tasked with the production and broadcasting of entertainment to all of its assets.") + player.current.show_message("Entertain the crew! Try not to disrupt them from their work too much and remind them how great [global.using_map.company_name] is!") + +/client/verb/join_as_actor() + set category = "IC" + set name = "Join as Actor" + set desc = "Join as an Actor to entertain the crew through television!" + + var/decl/special_role/actors = GET_DECL(/decl/special_role/actor) + if(!MayRespawn(1) || !actors.can_become_antag(usr.mind, 1)) + return + + if(!LAZYLEN(actors.starting_locations)) + to_chat(usr, "Actors do not have a spawn location on this map, and are unavailable.") + return + + var/choice = alert("Are you sure you'd like to join as an actor?", "Confirmation","Yes", "No") + if(choice != "Yes") + return + + if(isghostmind(usr.mind) || isnewplayer(usr)) + if(actors.current_antagonists.len >= actors.hard_cap) + to_chat(usr, "No more actors may spawn at the current time.") + return + actors.create_default(usr) + return + + to_chat(usr, "You must be observing or be a new player to spawn as an actor.") diff --git a/mods/content/augments/_augments.dm b/mods/content/augments/_augments.dm new file mode 100644 index 000000000000..702d94917fae --- /dev/null +++ b/mods/content/augments/_augments.dm @@ -0,0 +1,13 @@ +//Augmentation organ tag defines +#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" + +/decl/modpack/augments + name = "Augmentation Content" diff --git a/mods/content/augments/_augments.dme b/mods/content/augments/_augments.dme new file mode 100644 index 000000000000..ec0fba60a729 --- /dev/null +++ b/mods/content/augments/_augments.dme @@ -0,0 +1,24 @@ +#ifndef CONTENT_PACK_AUGMENTS +#define CONTENT_PACK_AUGMENTS +// BEGIN_INCLUDE +#include "_augments.dm" +#include "active.dm" +#include "augment_loadout.dm" +#include "augment_organ.dm" +#include "bodytype_augment.dm" +#include "designs_augments.dm" +#include "overrides.dm" +#include "simple.dm" +#include "active\armblades.dm" +#include "active\cyberbrain.dm" +#include "active\polytool.dm" +#include "active\tool\engineering.dm" +#include "active\tool\surgical.dm" +#include "passive\armor.dm" +#include "passive\boost.dm" +#include "passive\nanoaura.dm" +#include "passive\boost\muscle.dm" +#include "passive\boost\reflex.dm" +#include "passive\boost\shooting.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/augments/active.dm b/mods/content/augments/active.dm new file mode 100644 index 000000000000..773215a8fa69 --- /dev/null +++ b/mods/content/augments/active.dm @@ -0,0 +1,27 @@ +//Toggleable embedded module +/obj/item/organ/internal/augment/active + action_button_name = "Activate" + +/obj/item/organ/internal/augment/active/proc/activate() + return + +/obj/item/organ/internal/augment/active/proc/can_activate() + if(!owner || owner.incapacitated() || !is_usable() || (status & ORGAN_CUT_AWAY)) + to_chat(owner, SPAN_WARNING("You can't do that now!")) + return FALSE + return TRUE + +/obj/item/organ/internal/augment/active/attack_self() + . = ..() + if(. && can_activate()) + activate() + +//Need to change icon? +/obj/item/organ/internal/augment/active/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = icon_state + action.button?.update_icon() + +/datum/action/item_action/organ/augment + button_icon = 'mods/content/augments/icons/augment.dmi' \ No newline at end of file diff --git a/mods/content/augments/active/armblades.dm b/mods/content/augments/active/armblades.dm new file mode 100644 index 000000000000..38d043f9a32e --- /dev/null +++ b/mods/content/augments/active/armblades.dm @@ -0,0 +1,51 @@ +/obj/item/armblade + icon_state = "armblade" + item_state = null + name = "armblade" + icon = 'mods/content/augments/icons/augment.dmi' + desc = "A handy utility blade for the discerning augmentee. Warranty void if used for cutting." + base_parry_chance = 30 + sharp = TRUE + edge = TRUE + attack_verb = list("stabbed", "sliced", "cut") + origin_tech = @'{"materials":1,"engineering":1,"combat":2}' + material = /decl/material/solid/metal/steel + +/obj/item/armblade/can_take_wear_damage() + return FALSE + +/obj/item/organ/internal/augment/active/simple/armblade + name = "embedded blade" + desc = "A sturdy housing for a steel utility blade." + action_button_name = "Deploy blade" + icon_state = "armblade" + allowed_organs = list(BP_AUGMENT_R_ARM, BP_AUGMENT_L_ARM) + holding = /obj/item/armblade + //Limited to robolimbs + augment_flags = AUGMENTATION_MECHANIC + material = /decl/material/solid/metal/steel + +/obj/item/organ/internal/augment/active/simple/armblade/reset_matter() + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/armblade/claws + icon_state = "wolverine" + name = "combat claws" + desc = "These do not grow back." + base_parry_chance = 40 + origin_tech = @'{"materials":2,"engineering":2,"combat":3}' + +//Alternate look +/obj/item/organ/internal/augment/active/simple/wolverine + name = "cyberclaws" + desc = "An unusual type of cybernetic weaponry, these sharp blades are bound to turn heads." + action_button_name = "Deploy claws" + icon_state = "wolverine" + allowed_organs = list(BP_AUGMENT_R_HAND, BP_AUGMENT_L_HAND) + holding = /obj/item/armblade/claws + //Limited to robolimbs + augment_flags = AUGMENTATION_MECHANIC + material = /decl/material/solid/metal/steel + +/obj/item/organ/internal/augment/active/simple/wolverine/reset_matter() + matter = list(/decl/material/solid/gemstone/diamond = MATTER_AMOUNT_REINFORCEMENT) diff --git a/mods/content/augments/active/cyberbrain.dm b/mods/content/augments/active/cyberbrain.dm new file mode 100644 index 000000000000..d5972c12333d --- /dev/null +++ b/mods/content/augments/active/cyberbrain.dm @@ -0,0 +1,113 @@ +/obj/item/organ/internal/augment/active/cyberbrain + name = "cyberbrain module" + action_button_name = "Access cyberbrain" + icon_state = "cyberbrain" + allowed_organs = list(BP_AUGMENT_HEAD) + augment_flags = AUGMENTATION_MECHANIC + origin_tech = @'{"materials":2,"magnets":3,"engineering":3,"biotech":2,"programming":4}' + + var/list/default_hardware = list( + /obj/item/stock_parts/computer/processor_unit/small, + /obj/item/stock_parts/computer/hard_drive/small, + /obj/item/stock_parts/computer/network_card, + /obj/item/stock_parts/computer/battery_module/nano, + /obj/item/stock_parts/computer/tesla_link + ) + +/* + * + * Section for actual mechanics of cyberbrain. + * + */ +/obj/item/organ/internal/augment/active/cyberbrain/Initialize() + . = ..() + + START_PROCESSING(SSobj, src) + set_extension(src, /datum/extension/interactive/os/device/implant) + set_extension(src, /datum/extension/assembly/modular_computer/cyberbrain) + + update_icon() + + install_default_hardware() + +/obj/item/organ/internal/augment/active/cyberbrain/get_contained_external_atoms() + . = ..() + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + if(assembly) + LAZYREMOVE(., assembly.parts) + +// Used to perform preset-specific hardware changes. +/obj/item/organ/internal/augment/active/cyberbrain/proc/install_default_hardware() + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + for(var/T in default_hardware) + assembly.try_install_component(null, new T(src)) + +/obj/item/organ/internal/augment/active/cyberbrain/activate() + if(!can_activate()) + return + + var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) + if(assembly.enabled && assembly.screen_on) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + os.ui_interact(owner) + else if(!assembly.enabled && assembly.screen_on) + assembly.turn_on(owner) + +/obj/item/organ/internal/augment/active/cyberbrain/attackby(var/obj/item/used_item, var/mob/user) + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + . = assembly.attackby(used_item, user) + if(.) + return + return ..() + +/obj/item/organ/internal/augment/active/cyberbrain/handle_mouse_drop(atom/over, mob/user, params) + if(!istype(over, /obj/screen)) + attack_self(user) + return TRUE + . = ..() + +/obj/item/organ/internal/augment/active/cyberbrain/Process() + ..() + if(!is_broken() && !(status & ORGAN_DEAD)) + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + if(assembly) + assembly.Process() + if(!assembly.enabled) + return + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + if(os) + os.Process() + +/obj/item/organ/internal/augment/active/cyberbrain/get_contained_matter(include_reagents = TRUE) + . = ..() + var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) + for(var/obj/part in assembly?.parts) + . = MERGE_ASSOCS_WITH_NUM_VALUES(., part.get_contained_matter(include_reagents)) + +/* + * + * Section for assembly override for the cyberbrain. + * + */ +/datum/extension/assembly/modular_computer/cyberbrain + hardware_flag = PROGRAM_PDA + max_hardware_size = 1 + enabled_by_default = TRUE + max_parts = list( + PART_BATTERY = 1, + PART_CPU = 1, + PART_NETWORK = 1, + PART_HDD = 1, + PART_AI = 1, + PART_TESLA = 1 + ) + expected_type = /obj/item/organ/internal/augment/active/cyberbrain + assembly_name = "cyberbrain" + force_synth = TRUE + +/datum/extension/interactive/os/device/implant + expected_type = /obj/item/organ/internal/augment/active/cyberbrain + +/datum/extension/interactive/os/device/implant/emagged() + return FALSE \ No newline at end of file diff --git a/mods/content/augments/active/polytool.dm b/mods/content/augments/active/polytool.dm new file mode 100644 index 000000000000..ad72c0f405b7 --- /dev/null +++ b/mods/content/augments/active/polytool.dm @@ -0,0 +1,77 @@ +/obj/item/organ/internal/augment/active/polytool + name = "embedded polytool module" + action_button_name = "Deploy Tool" + icon_state = "multitool" + allowed_organs = list(BP_AUGMENT_R_HAND, BP_AUGMENT_L_HAND) + augment_flags = AUGMENTATION_MECHANIC + origin_tech = @'{"materials":2,"magnets":2,"engineering":4}' + var/list/items = list() + var/list/paths = list() //We may lose them + +/obj/item/organ/internal/augment/active/polytool/Initialize() + . = ..() + for(var/path in paths) + var/obj/item/I = new path (src) + I.canremove = FALSE + items += I + events_repository.register(/decl/observ/moved, I, src, /obj/item/organ/internal/augment/active/polytool/proc/check_holding) + events_repository.register(/decl/observ/destroyed, I, src, /obj/item/organ/internal/augment/active/polytool/proc/check_holding) + events_repository.register(/decl/observ/item_unequipped, I, src, /obj/item/organ/internal/augment/active/polytool/proc/check_holding) + +/obj/item/organ/internal/augment/active/polytool/Destroy() + for(var/obj/item/item in items) + events_repository.unregister(/decl/observ/moved, item, src) + events_repository.unregister(/decl/observ/destroyed, item, src) + events_repository.unregister(/decl/observ/item_unequipped, item, src) + QDEL_NULL_LIST(items) + . = ..() + +/obj/item/organ/internal/augment/active/polytool/proc/check_holding() + for(var/obj/item/I in items) + if(QDELETED(I) || (I.loc != src && (!owner || I.loc != owner))) + I.canremove = TRUE + events_repository.unregister(/decl/observ/moved, I, src) + events_repository.unregister(/decl/observ/destroyed, I, src) + events_repository.unregister(/decl/observ/item_unequipped, I, src) + items -= I + +/obj/item/organ/internal/augment/active/polytool/activate() + if(!can_activate()) + return + + var/slot = null + if(parent_organ in list(BP_L_ARM, BP_L_HAND)) + slot = BP_L_HAND + else if(parent_organ in list(BP_R_ARM, BP_R_HAND)) + slot = BP_R_HAND + + if(!slot) + return + + var/obj/item/organ/external/limb = owner?.get_organ(parent_organ) + var/obj/I = owner.get_equipped_item(slot) + if(I) + if(is_type_in_list(I,paths) && !(I.type in items)) //We don't want several of same but you can replace parts whenever + if(!owner.drop_from_inventory(I, src)) + to_chat(owner, "\The [I] fails to retract.") + return + items += I + var/decl/pronouns/pronouns = owner.get_pronouns() + owner.visible_message( + SPAN_NOTICE("\The [owner] retracts [pronouns.his] [I.name] into [pronouns.his] [limb ? limb.name : "limb"]."), + SPAN_NOTICE("You retract your [I.name] into your [limb ? limb.name : "limb"].") + ) + else + to_chat(owner, SPAN_WARNING("You must drop \the [I] before the polytool can extend.")) + else + var/obj/item = input(owner, "Select the attachment to deploy.") as null|anything in src + if(!item || !(src in owner.internal_organs)) + return + if(owner.equip_to_slot_if_possible(item, slot)) + items -= item + //Keep track of it, make sure it returns + var/decl/pronouns/pronouns = owner.get_pronouns() + owner.visible_message( + SPAN_NOTICE("\The [owner] extends [pronouns.his] [item.name] from [pronouns.his] [limb ? limb.name : "limb"]."), + SPAN_NOTICE("You extend your [item.name] from your [limb ? limb.name : "limb"].") + ) \ No newline at end of file diff --git a/mods/content/augments/active/tool/engineering.dm b/mods/content/augments/active/tool/engineering.dm new file mode 100644 index 000000000000..2aff3eedd2a0 --- /dev/null +++ b/mods/content/augments/active/tool/engineering.dm @@ -0,0 +1,68 @@ +/obj/item/organ/internal/augment/active/polytool/engineer + name = "engineering toolset" + action_button_name = "Deploy Engineering Tool" + desc = "A lightweight augmentation for the engineer on-the-go. This one comes with a series of common tools." + material = /decl/material/solid/metal/steel + paths = list( + /obj/item/screwdriver/finger, + /obj/item/wrench/finger, + /obj/item/weldingtool/finger, + /obj/item/crowbar/finger, + /obj/item/wirecutters/finger, + /obj/item/multitool/finger + ) + origin_tech = @'{"materials":4,"magnets":3,"engineering":3}' + +/obj/item/organ/internal/augment/active/polytool/engineer/reset_matter() + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/weldingtool/finger + name = "digital welder" + desc = "A precise, high quality welding tool." + icon = 'mods/content/augments/icons/welder_finger.dmi' + +/obj/item/wirecutters/finger + name = "digital splicer" + desc = "A small embedded cutter in your finger." + icon_state = "wirecutter_finger" + icon = 'mods/content/augments/icons/augment_tools.dmi' + +/obj/item/wirecutters/finger/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/screwdriver/finger + name = "digital screwdriver" + desc = "A nifty power tool at your literal fingertips." + icon_state = "screwdriver_finger" + icon = 'mods/content/augments/icons/augment_tools.dmi' + +/obj/item/screwdriver/finger/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/crowbar/finger + name = "digital prybar" + desc = "A somewhat awkward to use prybar. It doubles as a bottle opener." + icon_state = "prybar_finger" + icon = 'mods/content/augments/icons/augment_tools.dmi' + +/obj/item/crowbar/finger/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/wrench/finger + name = "digital wrench" + desc = "A rotating wrench. Don't get your hair caught in it." + icon_state = "wrench_finger" + icon = 'mods/content/augments/icons/augment_tools.dmi' + +/obj/item/wrench/finger/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/multitool/finger + name = "digital multitool" + desc = "A multitool inside of a multitool. Doubletool?" + icon_state = "multitool_finger" + icon = 'mods/content/augments/icons/augment_tools.dmi' diff --git a/mods/content/augments/active/tool/surgical.dm b/mods/content/augments/active/tool/surgical.dm new file mode 100644 index 000000000000..faa771cf3e93 --- /dev/null +++ b/mods/content/augments/active/tool/surgical.dm @@ -0,0 +1,21 @@ +/obj/item/organ/internal/augment/active/polytool/surgical + name = "surgical toolset" + action_button_name = "Deploy Surgical Tool" + desc = "Part of a line of biomedical augmentations, this device contains the full set of tools any surgeon would ever need." + material = /decl/material/solid/metal/steel + paths = list( + /obj/item/bonesetter, + /obj/item/cautery, + /obj/item/circular_saw, + /obj/item/hemostat, + /obj/item/retractor, + /obj/item/scalpel, + /obj/item/surgicaldrill + ) + origin_tech = @'{"materials":4,"magnets":3,"engineering":3}' + +/obj/item/organ/internal/augment/active/polytool/surgical/reset_matter() + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_SECONDARY, + /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT + ) \ No newline at end of file diff --git a/mods/content/augments/augment_loadout.dm b/mods/content/augments/augment_loadout.dm new file mode 100644 index 000000000000..3fd9d8efa984 --- /dev/null +++ b/mods/content/augments/augment_loadout.dm @@ -0,0 +1,54 @@ +/decl/loadout_category/augmentation + name = "Augmentations" + +/decl/loadout_option/augmentation + category = /decl/loadout_category/augmentation + abstract_type = /decl/loadout_option/augmentation + loadout_flags = GEAR_NO_EQUIP | GEAR_NO_FINGERPRINTS + custom_setup_proc = /obj/item/proc/AttemptAugmentation + custom_setup_proc_arguments = list(BP_CHEST) + +/obj/item/proc/AttemptAugmentation(mob/living/user, target_zone) + to_chat(user, SPAN_DANGER("Was unable to augment you with \the [src].")) + qdel(src) + +/obj/item/implant/AttemptAugmentation(mob/living/user, target_zone) + if(can_implant(user, user, target_zone) && implant_in_mob(user, user, target_zone)) + var/obj/item/organ/organ = GET_EXTERNAL_ORGAN(user, target_zone) + to_chat(user, SPAN_NOTICE("You have \a [src] implanted in your [organ.name].")) + else + ..() + +/obj/item/organ/internal/augment/AttemptAugmentation(mob/living/human/user, target_zone) + if(!istype(user)) + return ..() + + var/obj/item/organ/external/organ_to_implant_into = GET_EXTERNAL_ORGAN(user, parent_organ) + if(!istype(organ_to_implant_into)) + return ..() + + if(BP_IS_PROSTHETIC(organ_to_implant_into)) + if(!(augment_flags & AUGMENTATION_MECHANIC)) + to_chat(user, SPAN_DANGER("Your [organ_to_implant_into.name] is not organic, and therefore \the [src] can not be installed!")) + return ..() + else + if(!(augment_flags & AUGMENTATION_ORGANIC)) + to_chat(user, SPAN_DANGER("Your [organ_to_implant_into.name] is not prosthetic, and therefore \the [src] can not be installed!")) + return ..() + + user.add_organ(src, organ_to_implant_into) + to_chat(user, SPAN_NOTICE("Your [organ_to_implant_into.name] has been replaced with \the [src].")) + +// Codex implant, only available if the codex is set to require it in config +/decl/loadout_option/augmentation/codex_implant + name = "Codex Implant" + uid = "gear_augmentation_codex" + description = "A neural implant that provides access to the codex." + path = /obj/item/implant/codex + custom_setup_proc_arguments = list(BP_HEAD) + cost = 0 + +/decl/loadout_option/augmentation/codex_implant/can_be_taken_by(mob/living/user) + if(!get_config_value(/decl/config/toggle/codex_requires_implant)) + return FALSE + return ..() \ No newline at end of file diff --git a/mods/content/augments/augment_organ.dm b/mods/content/augments/augment_organ.dm new file mode 100644 index 000000000000..8f097a8874bd --- /dev/null +++ b/mods/content/augments/augment_organ.dm @@ -0,0 +1,88 @@ +/obj/item/organ/internal/augment + name = "embedded augment" + desc = "An embedded augment." + icon = 'mods/content/augments/icons/augment.dmi' + w_class = ITEM_SIZE_TINY // Need to be tiny to fit inside limbs. + //By default these fit on both flesh and robotic organs and are robotic + organ_properties = ORGAN_PROP_PROSTHETIC + default_action_type = /datum/action/item_action/organ/augment + material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":1,"magnets":2,"engineering":2,"biotech":1}' + w_class = ITEM_SIZE_TINY + + var/descriptor = "" + var/known = TRUE + var/const/AUGMENTATION_MECHANIC = BITFLAG(0) + var/const/AUGMENTATION_ORGANIC = BITFLAG(1) + var/augment_flags = AUGMENTATION_MECHANIC | AUGMENTATION_ORGANIC + var/list/allowed_organs = list(BP_AUGMENT_R_ARM, BP_AUGMENT_L_ARM) + +/obj/item/organ/internal/augment/Initialize() + . = ..() + organ_tag = pick(allowed_organs) + set_bodytype(/decl/bodytype/prosthetic/augment) + update_parent_organ() + reagents?.clear_reagents() // Removing meat from the reagents list. + +/obj/item/organ/internal/augment/attackby(obj/item/used_item, mob/user) + if(IS_SCREWDRIVER(used_item) && allowed_organs.len > 1) + //Here we can adjust location for implants that allow multiple slots + organ_tag = input(user, "Adjust installation parameters") as null|anything in allowed_organs + update_parent_organ() + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + return TRUE + return ..() + +/obj/item/organ/internal/augment/do_install(var/mob/living/human/target, var/obj/item/organ/external/affected, var/in_place = FALSE, var/update_icon = TRUE, var/detached = FALSE) + . = ..() + parent_organ = affected.organ_tag + update_parent_organ() + +/obj/item/organ/internal/augment/get_attachment_failure_reason(obj/item/organ/external/affected, robotic = FALSE) + if(robotic) + if(!(augment_flags & AUGMENTATION_ORGANIC)) + return SPAN_WARNING("\The [src] cannot function within a non-robotic limb.") + else if(!(augment_flags & AUGMENTATION_MECHANIC)) + return SPAN_WARNING("\The [src] cannot function within a robotic limb.") + return ..() + +/obj/item/organ/internal/augment/proc/update_parent_organ() + //This tries to match a parent organ to an augment slot + //This is intended to match the possible positions to a parent organ + + if(organ_tag == BP_AUGMENT_L_LEG) + parent_organ = BP_L_LEG + descriptor = "left leg." + else if(organ_tag == BP_AUGMENT_R_LEG) + parent_organ = BP_R_LEG + descriptor = "right leg." + else if(organ_tag == BP_AUGMENT_L_HAND) + parent_organ = BP_L_HAND + descriptor = "left hand." + else if(organ_tag == BP_AUGMENT_R_HAND) + parent_organ = BP_R_HAND + descriptor = "right hand." + else if(organ_tag == BP_AUGMENT_L_ARM) + parent_organ = BP_L_ARM + descriptor = "left arm." + else if(organ_tag == BP_AUGMENT_R_ARM) + parent_organ = BP_R_ARM + descriptor = "right arm." + else if(organ_tag == BP_AUGMENT_HEAD) + parent_organ = BP_HEAD + descriptor = "head." + else if(organ_tag == BP_AUGMENT_CHEST_ACTIVE || organ_tag == BP_AUGMENT_CHEST_ARMOUR) + parent_organ = BP_CHEST + descriptor = "chest." + +/obj/item/organ/internal/augment/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1) + . += "It is configured to be attached to the [descriptor]." + if(augment_flags & AUGMENTATION_MECHANIC && augment_flags & AUGMENTATION_ORGANIC) + . += "It can interface with both prosthetic and fleshy organs." + else + if(augment_flags & AUGMENTATION_MECHANIC) + . += "It can interface with prosthetic organs." + else if(augment_flags & AUGMENTATION_ORGANIC) + . += "It can interface with fleshy organs." diff --git a/mods/content/augments/bodytype_augment.dm b/mods/content/augments/bodytype_augment.dm new file mode 100644 index 000000000000..4fd09ed6a0ed --- /dev/null +++ b/mods/content/augments/bodytype_augment.dm @@ -0,0 +1,4 @@ +// Dummy/stub prosthetic type for augment implants. +/decl/bodytype/prosthetic/augment + name = "Augment" + uid = "bodytype_prosthetic_augment" diff --git a/code/modules/fabrication/designs/robotics/designs_augments.dm b/mods/content/augments/designs_augments.dm similarity index 90% rename from code/modules/fabrication/designs/robotics/designs_augments.dm rename to mods/content/augments/designs_augments.dm index 85cc0d421d51..8ca2afdfe5ed 100644 --- a/code/modules/fabrication/designs/robotics/designs_augments.dm +++ b/mods/content/augments/designs_augments.dm @@ -28,6 +28,3 @@ /datum/fabricator_recipe/robotics/augment/nanounit path = /obj/item/organ/internal/augment/active/nanounit - -/datum/fabricator_recipe/robotics/augment/circuit - path = /obj/item/organ/internal/augment/active/simple/circuit diff --git a/icons/obj/augment.dmi b/mods/content/augments/icons/augment.dmi similarity index 100% rename from icons/obj/augment.dmi rename to mods/content/augments/icons/augment.dmi diff --git a/mods/content/augments/icons/augment_tools.dmi b/mods/content/augments/icons/augment_tools.dmi new file mode 100644 index 000000000000..96b3a2d62a14 Binary files /dev/null and b/mods/content/augments/icons/augment_tools.dmi differ diff --git a/mods/content/augments/icons/welder_finger.dmi b/mods/content/augments/icons/welder_finger.dmi new file mode 100644 index 000000000000..103e350c09ef Binary files /dev/null and b/mods/content/augments/icons/welder_finger.dmi differ diff --git a/mods/content/augments/overrides.dm b/mods/content/augments/overrides.dm new file mode 100644 index 000000000000..296d4c337067 --- /dev/null +++ b/mods/content/augments/overrides.dm @@ -0,0 +1,32 @@ + +/obj/structure/mineral_bath/should_dissolve_implant(obj/implanted_object) + if(istype(implanted_object, /obj/item/organ/internal/augment)) + return FALSE + return ..() + +// Cause arm and hand augments to trigger fault ailments. +/datum/ailment/fault/locking_thumbs/New(obj/item/organ/_organ) + var/static/did_injection = FALSE + if(!did_injection) + did_injection = TRUE + applies_to_organ |= list( + BP_AUGMENT_R_ARM, + BP_AUGMENT_L_ARM, + BP_AUGMENT_R_HAND, + BP_AUGMENT_L_HAND + ) + . = ..() + +/datum/ailment/fault/locking_thumbs/resolve_tag_to_slot(organ_tag) + switch(organ_tag) + if(BP_AUGMENT_L_ARM, BP_AUGMENT_L_HAND) + return BP_L_HAND + if(BP_AUGMENT_R_ARM, BP_AUGMENT_R_HAND) + return BP_R_HAND + return ..() + +// Add augments to scan results +/obj/item/organ/external/get_scan_results() + for(var/obj/item/organ/internal/augment/aug in internal_organs) + if(istype(aug) && aug.known) + . += "[capitalize(aug.name)] implanted" \ No newline at end of file diff --git a/mods/content/augments/passive/armor.dm b/mods/content/augments/passive/armor.dm new file mode 100644 index 000000000000..2dff1139cba4 --- /dev/null +++ b/mods/content/augments/passive/armor.dm @@ -0,0 +1,26 @@ +/obj/item/organ/internal/augment/armor + name = "subdermal armor" + allowed_organs = list(BP_AUGMENT_CHEST_ARMOUR) + icon_state = "armor-chest" + desc = "A flexible composite mesh designed to prevent tearing and puncturing of underlying tissue." + material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":4,"engineering":2,"biotech":3}' + var/brute_mult = 0.8 + var/burn_mult = 1 + +/obj/item/organ/internal/augment/armor/reset_matter() + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +// override to add armor augment damage mods +/obj/item/organ/external/get_brute_mod(var/damage_flags) + . = ..() + var/obj/item/organ/internal/augment/armor/armor_augment = owner?.get_organ(BP_AUGMENT_CHEST_ARMOUR, /obj/item/organ/internal/augment/armor) + if(armor_augment) + . *= armor_augment.brute_mult + +// override to add armor augment damage mods +/obj/item/organ/external/get_burn_mod(var/damage_flags) + . = ..() + var/obj/item/organ/internal/augment/armor/armor_augment = owner?.get_organ(BP_AUGMENT_CHEST_ARMOUR, /obj/item/organ/internal/augment/armor) + if(armor_augment) + . *= armor_augment.burn_mult \ No newline at end of file diff --git a/code/modules/augment/passive/boost.dm b/mods/content/augments/passive/boost.dm similarity index 86% rename from code/modules/augment/passive/boost.dm rename to mods/content/augments/passive/boost.dm index f971f2a8077a..35d63a124403 100644 --- a/code/modules/augment/passive/boost.dm +++ b/mods/content/augments/passive/boost.dm @@ -2,29 +2,31 @@ var/id /obj/item/organ/internal/augment/boost + icon_state = "booster" + allowed_organs = list(BP_AUGMENT_HEAD) + origin_tech = @'{"materials":2,"magnets":2,"engineering":2,"biotech":3}' var/list/buffs = list()//Which abilities does this impact? var/list/injury_debuffs = list()//If organ is damaged, should we reduce anything? var/buffpath = /datum/skill_buff/augment //if you use something else it should be a subtype or it will runtime var/active = 0 //mostly to control if we should remove buffs when we go var/debuffing = 0 //if we applied a debuff var/id //Unique Id assigned on new - icon_state = "booster" - allowed_organs = list(BP_AUGMENT_HEAD) /obj/item/organ/internal/augment/boost/Initialize() . = ..() id = "[/obj/item/organ/internal/augment/boost]_[sequential_id(/obj/item/organ/internal/augment/boost)]" - -/obj/item/organ/internal/augment/boost/onInstall() - if(buffs.len) +/obj/item/organ/internal/augment/boost/on_add_effects() + . = ..() + if(istype(owner) && buffs.len) var/datum/skill_buff/augment/A A = owner.buff_skill(buffs, 0, buffpath) if(A && istype(A)) active = 1 A.id = id -/obj/item/organ/internal/augment/boost/onRemove() +/obj/item/organ/internal/augment/boost/on_remove_effects(mob/living/last_owner) + . = ..() debuffing = 0 if(!active) return @@ -46,7 +48,7 @@ return 1 /obj/item/organ/internal/augment/boost/proc/buff() - if(!buffs || !buffs.len) + if(!LAZYLEN(buffs)) return 0 var/list/B = owner.fetch_buffs_of_type(buffpath, 0) for(var/datum/skill_buff/augment/D in B) diff --git a/mods/content/augments/passive/boost/muscle.dm b/mods/content/augments/passive/boost/muscle.dm new file mode 100644 index 000000000000..913214d9619a --- /dev/null +++ b/mods/content/augments/passive/boost/muscle.dm @@ -0,0 +1,60 @@ +//This one must do special handling because you need 2, so other than vars it doesn't share tht much +/datum/skill_buff/augment/muscle + +/obj/item/organ/internal/augment/boost/muscle + buffs = list(SKILL_HAULING = 1) + buffpath = /datum/skill_buff/augment/muscle + name = "mechanical muscles" + allowed_organs = list(BP_AUGMENT_R_LEG, BP_AUGMENT_L_LEG) + icon_state = "muscule" + desc = "Nanofiber tendons powered by an array of actuators to help the wearer maintain speed even while encumbered. You may want to install these in pairs to see a result." + material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":4,"magnets":3,"biotech":3}' + var/obj/item/organ/internal/augment/boost/muscle/other //we need two for these + +/obj/item/organ/internal/augment/boost/muscle/reset_matter() + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + +/obj/item/organ/internal/augment/boost/muscle/on_add_effects() + . = ..() + if(!owner) + return + //1.st Determine where we are and who we should be asking for guidance + //we must be second to activate buff + if(organ_tag == BP_AUGMENT_L_LEG) + other = GET_INTERNAL_ORGAN(owner, BP_AUGMENT_R_LEG) + else if(organ_tag == BP_AUGMENT_R_LEG) + other = GET_INTERNAL_ORGAN(owner, BP_AUGMENT_L_LEG) + if(other && istype(other)) + var/succesful = TRUE + if(owner.get_skill_value(SKILL_HAULING) < SKILL_PROF) + succesful = FALSE + var/datum/skill_buff/augment/muscle/A + A = owner.buff_skill(buffs, 0, buffpath) + if(A && istype(A)) + succesful = TRUE + A.id = id + + if(succesful) + other.other = src + other.active = TRUE + active = TRUE + +/obj/item/organ/internal/augment/boost/muscle/on_remove_effects(mob/living/last_owner) + . = ..() + if(!active) + return + var/list/B = owner.fetch_buffs_of_type(buffpath, 0) + for(var/datum/skill_buff/augment/muscle/D in B) + if(D.id == id) + D.remove() + break + if(other) + other.active = FALSE + other.other = null + other = null + active = FALSE + +/obj/item/organ/internal/augment/boost/muscle/Destroy() + . = ..() + other = null //If somehow onRemove didn't handle it diff --git a/code/modules/augment/passive/boost/reflex.dm b/mods/content/augments/passive/boost/reflex.dm similarity index 79% rename from code/modules/augment/passive/boost/reflex.dm rename to mods/content/augments/passive/boost/reflex.dm index 2bf572a78da5..a066e9f10740 100644 --- a/code/modules/augment/passive/boost/reflex.dm +++ b/mods/content/augments/passive/boost/reflex.dm @@ -4,8 +4,11 @@ buffs = list(SKILL_COMBAT = 1) injury_debuffs = list(SKILL_COMBAT = -1) material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":2,"magnets":3,"programming":5,"biotech":2}' + +/obj/item/organ/internal/augment/boost/reflex/reset_matter() matter = list( - /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE ) diff --git a/mods/content/augments/passive/boost/shooting.dm b/mods/content/augments/passive/boost/shooting.dm new file mode 100644 index 000000000000..33306ef9f56b --- /dev/null +++ b/mods/content/augments/passive/boost/shooting.dm @@ -0,0 +1,21 @@ +/obj/item/organ/internal/augment/boost/shooting + name = "gunnery booster" + desc = "The AIM-4 module improves gun accuracy by filtering unnecessary nerve signals." + buffs = list(SKILL_WEAPONS = 1) + injury_debuffs = list(SKILL_WEAPONS = -1) + material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":4,"magnets":3,"biotech":3}' + +/obj/item/organ/internal/augment/boost/shooting/reset_matter() + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE + ) + +/obj/item/organ/internal/augment/boost/shooting/buff() + if((. = ..())) + to_chat(owner, SPAN_NOTICE("Notice: AIM-4 finished reboot.")) + +/obj/item/organ/internal/augment/boost/shooting/debuff() + if((. = ..())) + to_chat(owner, SPAN_WARNING("Catastrophic damage detected: AIM-4 shutting down.")) \ No newline at end of file diff --git a/mods/content/augments/passive/nanoaura.dm b/mods/content/augments/passive/nanoaura.dm new file mode 100644 index 000000000000..e22f8331cd63 --- /dev/null +++ b/mods/content/augments/passive/nanoaura.dm @@ -0,0 +1,93 @@ +//This handy augment protects you to a degree, keeping it online after critical damage however is bad +/obj/item/organ/internal/augment/active/nanounit + name = "nanite MCU" + allowed_organs = list(BP_AUGMENT_CHEST_ACTIVE) + icon_state = "armor-chest" + desc = "Nanomachines, son." + action_button_name = "Toggle Nanomachines" + material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":4,"magnets":4,"engineering":5,"biotech":3}' + var/active = FALSE + var/modifier_archetype = /decl/mob_modifier/nanoswarm + var/charges = 4 + +/obj/item/organ/internal/augment/active/nanounit/reset_matter() + matter = list( + /decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/uranium = MATTER_AMOUNT_TRACE + ) + +/obj/item/organ/internal/augment/active/nanounit/on_add_effects() + . = ..() + if(owner && modifier_archetype) + owner.add_mob_modifier(modifier_archetype, source = src) + +/obj/item/organ/internal/augment/active/nanounit/on_remove_effects(mob/living/last_owner) + if(istype(last_owner) && modifier_archetype) + last_owner.remove_mob_modifier(modifier_archetype, source = src) + . = ..() + +/obj/item/organ/internal/augment/active/nanounit/proc/catastrophic_failure() + playsound(owner,'sound/mecha/internaldmgalarm.ogg',25,1) + charges = -1 + active = FALSE + owner.visible_message(SPAN_WARNING("The nanites attempt to harden. But they seem... brittle.")) + for(var/obj/item/organ/external/E in owner.get_external_organs()) + if(prob(25)) + E.status |= ORGAN_BRITTLE //Some nanites are not responding and you're out of luck + to_chat(owner, SPAN_DANGER("Your [E.name] feels cold and rigid.")) + owner.remove_mob_modifier(modifier_archetype, source = src) + +/obj/item/organ/internal/augment/active/nanounit/activate() + if(!owner || !modifier_archetype || !can_activate()) + return + if(owner.has_mob_modifier(modifier_archetype, source = src)) + active = FALSE + to_chat(owner,SPAN_NOTICE("Nanites entering sleep mode.")) + owner.remove_mob_modifier(modifier_archetype, source = src) + else if(charges > 0) + to_chat(owner,SPAN_NOTICE("Activation sequence in progress.")) + active = TRUE + owner.add_mob_modifier(modifier_archetype, source = src) + playsound(owner,'sound/weapons/flash.ogg',35,1) + +/obj/item/organ/internal/augment/active/nanounit/Destroy() + if(owner && modifier_archetype) + owner.remove_mob_modifier(modifier_archetype, source = src) + . = ..() + +// The modifier applied by the above implant. +/decl/mob_modifier/nanoswarm + name = "Defensive Nanoswarm" + desc = "You are surrounded by nanomachines that harden in response to projectiles." + hud_icon_state = "nanomachines" + on_add_message_1p = SPAN_NOTICE("Your skin tingles as the nanites spread over your body.") + on_end_message_1p = SPAN_WARNING("The nanites dissolve!") + +/decl/mob_modifier/nanoswarm/on_modifier_datum_added(mob/living/_owner, decl/mob_modifier/modifier) + . = ..() + playsound(_owner.loc,'sound/weapons/flash.ogg',35,1) + +/decl/mob_modifier/nanoswarm/check_modifiers_block_attack(mob/living/_owner, list/modifiers, attack_type, atom/movable/attacker, additional_data) + if(attack_type != MM_ATTACK_TYPE_PROJECTILE) + return ..() + + var/obj/item/organ/internal/augment/active/nanounit/unit + for(var/datum/mob_modifier/modifier in modifiers) + var/obj/item/organ/internal/augment/active/nanounit/implant = modifier.source?.resolve() + if(istype(implant) && implant.active && implant.charges >= 0) // active with 0 charges means it's about to critically fail. + unit = implant + break + + if(!istype(unit)) + return ..() + + _owner.visible_message(SPAN_WARNING("The nanomachines harden as a response to physical trauma!")) + playsound(_owner, 'sound/effects/basscannon.ogg',35,1) + unit.charges-- + if(unit.charges <= 0) + to_chat(_owner, SPAN_DANGER("Warning: Critical damage threshold passed. Shut down unit to avoid further damage.")) + else + unit.catastrophic_failure() + return MM_ATTACK_RESULT_BLOCKED|MM_ATTACK_RESULT_DEFLECTED diff --git a/mods/content/augments/simple.dm b/mods/content/augments/simple.dm new file mode 100644 index 000000000000..14e48b5ca457 --- /dev/null +++ b/mods/content/augments/simple.dm @@ -0,0 +1,89 @@ +//Simple toggleabse module. Just put holding in hands or get it back +/obj/item/organ/internal/augment/active/simple + origin_tech = null + var/retracting + var/obj/item/holding + +/obj/item/organ/internal/augment/active/simple/Initialize() + . = ..() + if(!ispath(holding)) + return + holding = new holding(src) + holding.canremove = FALSE + if(!origin_tech) + origin_tech = holding.get_origin_tech() + events_repository.register(/decl/observ/moved, holding, src, /obj/item/organ/internal/augment/active/simple/proc/check_holding) + events_repository.register(/decl/observ/destroyed, holding, src, /obj/item/organ/internal/augment/active/simple/proc/check_holding) + events_repository.register(/decl/observ/item_unequipped, holding, src, /obj/item/organ/internal/augment/active/simple/proc/check_holding) + +/obj/item/organ/internal/augment/active/simple/proc/check_holding() + + if(!holding) + return + + if(QDELETED(holding)) + holding.canremove = TRUE + events_repository.unregister(/decl/observ/moved, holding, src) + events_repository.unregister(/decl/observ/destroyed, holding, src) + events_repository.unregister(/decl/observ/item_unequipped, holding, src) + holding = null + return + + if(holding.loc != src && (!owner || holding.loc != owner)) + retract() + +/obj/item/organ/internal/augment/active/simple/Destroy() + QDEL_NULL(holding) + return ..() + +/obj/item/organ/internal/augment/active/simple/proc/deploy() + var/slot = null + if(parent_organ in list(BP_L_ARM, BP_L_HAND)) + slot = BP_L_HAND + else if(parent_organ in list(BP_R_ARM, BP_R_HAND)) + slot = BP_R_HAND + if(slot && owner.equip_to_slot_if_possible(holding, slot)) + var/obj/item/organ/external/limb = owner?.get_organ(parent_organ) + var/decl/pronouns/pronouns = owner.get_pronouns() + owner.visible_message( + SPAN_NOTICE("\The [owner] extends [pronouns.his] [holding.name] from [pronouns.his] [limb ? limb.name : "limb"]."), + SPAN_NOTICE("You extend your [holding.name] from your [limb ? limb.name : "limb"].") + ) + +/obj/item/organ/internal/augment/active/simple/proc/retract() + if(holding.loc == src || retracting) + return + retracting = TRUE + holding.canremove = TRUE + if(owner && holding.loc == owner) + if(!owner.drop_from_inventory(holding, src)) + to_chat(owner, SPAN_WARNING("\The [holding.name] fails to retract.")) + holding.canremove = FALSE + retracting = FALSE + return + var/obj/item/organ/external/limb = owner?.get_organ(parent_organ) + var/decl/pronouns/pronouns = owner.get_pronouns() + owner.visible_message( + SPAN_NOTICE("\The [owner] retracts [pronouns.his] [holding.name] into [pronouns.his] [limb ? limb.name : "limb"]."), + SPAN_NOTICE("You retract your [holding.name] into [pronouns.his] [limb ? limb.name : "limb"].") + ) + else if(ismob(holding.loc)) + var/mob/M = holding.loc + M.drop_from_inventory(holding) + holding.forceMove(src) + holding.canremove = FALSE + retracting = FALSE + +/obj/item/organ/internal/augment/active/simple/activate() + if(!can_activate()) + return + if(holding.loc == src) + deploy() + else + retract() + +/obj/item/organ/internal/augment/active/simple/can_activate() + . = ..() + if(. && !holding) + to_chat(owner, SPAN_WARNING("The device is damaged and fails to deploy.")) + . = FALSE diff --git a/mods/content/beekeeping/_beekeeping.dm b/mods/content/beekeeping/_beekeeping.dm new file mode 100644 index 000000000000..d3b58be746d6 --- /dev/null +++ b/mods/content/beekeeping/_beekeeping.dm @@ -0,0 +1,7 @@ +/decl/modpack/beekeeping + name = "Beekeeping Content" + +/datum/storage/hopper/industrial/centrifuge/New() + ..() + can_hold |= /obj/item/hive_frame + diff --git a/mods/content/beekeeping/_beekeeping.dme b/mods/content/beekeeping/_beekeeping.dme new file mode 100644 index 000000000000..75778704f368 --- /dev/null +++ b/mods/content/beekeeping/_beekeeping.dme @@ -0,0 +1,12 @@ +#ifndef MODPACK_BEEKEEPING +#define MODPACK_BEEKEEPING +// BEGIN_INCLUDE +#include "_beekeeping.dm" +#include "closets.dm" +#include "hive_frame.dm" +#include "items.dm" +#include "recipes.dm" +#include "trading.dm" +#include "hives\_hive.dm" +// END_INCLUDE +#endif diff --git a/mods/content/beekeeping/closets.dm b/mods/content/beekeeping/closets.dm new file mode 100644 index 000000000000..c39e70dbb457 --- /dev/null +++ b/mods/content/beekeeping/closets.dm @@ -0,0 +1,15 @@ +/obj/structure/closet/crate/hydroponics/beekeeping + name = "beekeeping crate" + desc = "All you need to set up your own beehive." + +/obj/structure/closet/crate/hydroponics/beekeeping/Initialize() + . = ..() + new /obj/item/beehive_assembly(src) + new /obj/item/bee_smoker(src) + new /obj/item/hive_frame/crafted(src) + new /obj/item/hive_frame/crafted(src) + new /obj/item/hive_frame/crafted(src) + new /obj/item/hive_frame/crafted(src) + new /obj/item/hive_frame/crafted(src) + new /obj/item/bee_pack(src) + new /obj/item/crowbar(src) diff --git a/mods/content/beekeeping/hive_frame.dm b/mods/content/beekeeping/hive_frame.dm new file mode 100644 index 000000000000..35ffd429777c --- /dev/null +++ b/mods/content/beekeeping/hive_frame.dm @@ -0,0 +1,55 @@ +/obj/item/hive_frame + abstract_type = /obj/item/hive_frame + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material_alteration = MAT_FLAG_ALTERATION_ALL + chem_volume = 20 + var/destroy_on_centrifuge = FALSE + +/obj/item/hive_frame/on_reagent_change() + . = ..() + if(REAGENT_TOTAL_VOLUME(reagents)) + SetName("filled [initial(name)] ([reagents.get_primary_reagent_name()])") + else + SetName(initial(name)) + queue_icon_update() + +/obj/item/hive_frame/on_update_icon() + . = ..() + var/mesh_state = "[icon_state]-mesh" + if(check_state_in_icon(mesh_state, icon)) + add_overlay(overlay_image(icon, mesh_state, COLOR_WHITE, RESET_COLOR)) + if(REAGENT_TOTAL_VOLUME(reagents)) + var/comb_state = "[icon_state]-comb" + if(check_state_in_icon(comb_state, icon)) + add_overlay(overlay_image(icon, comb_state, reagents.get_color(), RESET_COLOR)) + compile_overlays() + +/obj/item/hive_frame/handle_centrifuge_process(obj/machinery/centrifuge/centrifuge) + if(!(. = ..())) + return + if(REAGENT_TOTAL_VOLUME(reagents)) + reagents.trans_to_holder(centrifuge.loaded_beaker.reagents, REAGENT_TOTAL_VOLUME(reagents)) + for(var/obj/item/thing in contents) + thing.dropInto(centrifuge.loc) + if(destroy_on_centrifuge) + for(var/atom/movable/thing in convert_matter_to_lumps()) + thing.dropInto(centrifuge.loc) + +// Crafted frame used in apiaries. +/obj/item/hive_frame/crafted + name = "hive frame" + desc = "A wooden frame for insect hives that the workers will fill with products like honey." + icon = 'mods/content/beekeeping/icons/frame.dmi' + material = /decl/material/solid/organic/wood/oak + material_alteration = MAT_FLAG_ALTERATION_ALL + +// TEMP until beewrite redoes hives. +/obj/item/hive_frame/crafted/filled/Initialize() + . = ..() + new /obj/item/stack/material/bar/wax(src) + update_icon() + +/obj/item/hive_frame/crafted/filled/populate_reagents() + . = ..() + reagents.add_reagent(/decl/material/liquid/nutriment/honey, REAGENT_MAXIMUM_VOLUME(reagents)) diff --git a/mods/content/beekeeping/hives/_hive.dm b/mods/content/beekeeping/hives/_hive.dm new file mode 100644 index 000000000000..990d148a16f9 --- /dev/null +++ b/mods/content/beekeeping/hives/_hive.dm @@ -0,0 +1,168 @@ +/obj/machinery/beehive + name = "apiary" + icon = 'mods/content/beekeeping/icons/beekeeping.dmi' + icon_state = "beehive-0" + desc = "A wooden box designed specifically to house our buzzling buddies. Far more efficient than traditional hives. Just insert a frame and a queen, close it up, and you're good to go!" + density = TRUE + anchored = TRUE + layer = BELOW_OBJ_LAYER + + var/closed = 0 + var/bee_count = 0 // Percent + var/smoked = 0 // Timer + var/honeycombs = 0 // Percent + var/frames = 0 + var/maxFrames = 5 + +/obj/machinery/beehive/Initialize() + . = ..() + update_icon() + +/obj/machinery/beehive/on_update_icon() + overlays.Cut() + icon_state = "beehive-[closed]" + if(closed) + overlays += "lid" + if(frames) + overlays += "empty[frames]" + if(honeycombs >= 100) + overlays += "full[round(honeycombs / 100)]" + if(!smoked) + switch(bee_count) + if(1 to 20) + overlays += "bees1" + if(21 to 40) + overlays += "bees2" + if(41 to 60) + overlays += "bees3" + if(61 to 80) + overlays += "bees4" + if(81 to 100) + overlays += "bees5" + +/obj/machinery/beehive/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(!closed) + . += "The lid is open." + +/obj/machinery/beehive/attackby(var/obj/item/used_item, var/mob/user) + if(IS_CROWBAR(used_item)) + closed = !closed + user.visible_message("\The [user] [closed ? "closes" : "opens"] \the [src].", "You [closed ? "close" : "open"] \the [src].") + update_icon() + return TRUE + else if(IS_WRENCH(used_item)) + anchored = !anchored + user.visible_message("\The [user] [anchored ? "wrenches" : "unwrenches"] \the [src].", "You [anchored ? "wrench" : "unwrench"] \the [src].") + return TRUE + else if(istype(used_item, /obj/item/bee_smoker)) + if(closed) + to_chat(user, "You need to open \the [src] with a crowbar before smoking the bees.") + return TRUE + user.visible_message("\The [user] smokes the bees in \the [src].", "You smoke the bees in \the [src].") + smoked = 30 + update_icon() + return TRUE + else if(istype(used_item, /obj/item/hive_frame/crafted)) + if(closed) + to_chat(user, "You need to open \the [src] with a crowbar before inserting \the [used_item].") + return TRUE + if(frames >= maxFrames) + to_chat(user, "There is no place for an another frame.") + return TRUE + var/obj/item/hive_frame/crafted/H = used_item + if(REAGENT_TOTAL_VOLUME(H.reagents)) + to_chat(user, "\The [used_item] is full with beeswax and honey, empty it in the extractor first.") + return TRUE + ++frames + user.visible_message("\The [user] loads \the [used_item] into \the [src].", "You load \the [used_item] into \the [src].") + update_icon() + qdel(used_item) + return TRUE + else if(istype(used_item, /obj/item/bee_pack)) + var/obj/item/bee_pack/B = used_item + if(B.full && bee_count) + to_chat(user, "\The [src] already has bees inside.") + return TRUE + if(!B.full && bee_count < 90) + to_chat(user, "\The [src] is not ready to split.") + return TRUE + if(!B.full && !smoked) + to_chat(user, "Smoke \the [src] first!") + return TRUE + if(closed) + to_chat(user, "You need to open \the [src] with a crowbar before moving the bees.") + return TRUE + if(B.full) + user.visible_message("\The [user] puts the queen and the bees from \the [used_item] into \the [src].", "You put the queen and the bees from \the [used_item] into \the [src].") + bee_count = 20 + B.empty() + else + user.visible_message("\The [user] puts bees and larvae from \the [src] into \the [used_item].", "You put bees and larvae from \the [src] into \the [used_item].") + bee_count /= 2 + B.fill() + update_icon() + return TRUE + else if(istype(used_item, /obj/item/scanner/plant)) + to_chat(user, "Scan result of \the [src]...") + to_chat(user, "Beehive is [bee_count ? "[round(bee_count)]% full" : "empty"].[bee_count > 90 ? " Colony is ready to split." : ""]") + if(frames) + to_chat(user, "[frames] frames installed, [round(honeycombs / 100)] filled.") + if(honeycombs < frames * 100) + to_chat(user, "Next frame is [round(honeycombs % 100)]% full.") + else + to_chat(user, "No frames installed.") + if(smoked) + to_chat(user, "The hive is smoked.") + return TRUE + else if(IS_SCREWDRIVER(used_item)) + if(bee_count) + to_chat(user, "You can't dismantle \the [src] with these bees inside.") + return TRUE + to_chat(user, "You start dismantling \the [src]...") + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 30, src)) + user.visible_message("\The [user] dismantles \the [src].", "You dismantle \the [src].") + new /obj/item/beehive_assembly(loc) + qdel(src) + return TRUE + return FALSE // this should probably not be a machine, so don't do any component interactions + +/obj/machinery/beehive/physical_attack_hand(var/mob/user) + if(closed) + return FALSE + . = TRUE + if(honeycombs < 100) + to_chat(user, "There are no filled honeycombs.") + return + if(!smoked && bee_count) + to_chat(user, "The bees won't let you take the honeycombs out like this, smoke them first.") + return + user.visible_message("\The [user] starts taking the honeycombs out of \the [src].", "You start taking the honeycombs out of \the [src]...") + while(honeycombs >= 100 && do_after(user, 30, src)) + new /obj/item/hive_frame/crafted/filled(loc) + honeycombs -= 100 + --frames + update_icon() + if(honeycombs < 100) + to_chat(user, "You take all filled honeycombs out.") + +/obj/machinery/beehive/Process() + if(closed && !smoked && bee_count) + pollinate_flowers() + update_icon() + smoked = max(0, smoked - 1) + if(!smoked && bee_count) + bee_count = min(bee_count * 1.005, 100) + update_icon() + +/obj/machinery/beehive/proc/pollinate_flowers() + var/coef = bee_count / 100 + var/trays = 0 + for(var/obj/machinery/portable_atmospherics/hydroponics/H in view(7, src)) + if(H.seed && !H.dead) + H.plant_health += 0.05 * coef + if(H.pollen >= 1) + H.pollen-- + trays++ + honeycombs = min(honeycombs + 0.1 * coef * min(trays, 5), frames * 100) diff --git a/icons/obj/apiary_bees_etc.dmi b/mods/content/beekeeping/icons/apiary_bees_etc.dmi similarity index 100% rename from icons/obj/apiary_bees_etc.dmi rename to mods/content/beekeeping/icons/apiary_bees_etc.dmi diff --git a/icons/obj/beekeeping.dmi b/mods/content/beekeeping/icons/beekeeping.dmi similarity index 100% rename from icons/obj/beekeeping.dmi rename to mods/content/beekeeping/icons/beekeeping.dmi diff --git a/mods/content/beekeeping/icons/frame.dmi b/mods/content/beekeeping/icons/frame.dmi new file mode 100644 index 000000000000..136c77b72d6f Binary files /dev/null and b/mods/content/beekeeping/icons/frame.dmi differ diff --git a/mods/content/beekeeping/icons/smoker.dmi b/mods/content/beekeeping/icons/smoker.dmi new file mode 100644 index 000000000000..5109ca468e5e Binary files /dev/null and b/mods/content/beekeeping/icons/smoker.dmi differ diff --git a/mods/content/beekeeping/items.dm b/mods/content/beekeeping/items.dm new file mode 100644 index 000000000000..2c15fa75cd04 --- /dev/null +++ b/mods/content/beekeeping/items.dm @@ -0,0 +1,47 @@ +/obj/item/beehive_assembly + name = "beehive assembly" + desc = "Contains everything you need to build a beehive." + icon = 'mods/content/beekeeping/icons/apiary_bees_etc.dmi' + icon_state = "apiary" + material = /decl/material/solid/organic/wood/oak + +/obj/item/beehive_assembly/attack_self(var/mob/user) + to_chat(user, "You start assembling \the [src]...") + if(do_after(user, 30, src)) + user.visible_message("\The [user] constructs a beehive.", "You construct a beehive.") + new /obj/machinery/beehive(get_turf(user)) + qdel(src) + +/obj/item/bee_smoker + name = "bee smoker" + desc = "A device used to calm down bees before harvesting honey." + icon = 'mods/content/beekeeping/icons/smoker.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/steel + +/obj/item/bee_pack + name = "bee pack" + desc = "Contains a queen bee and some worker bees. Everything you'll need to start a hive!" + icon = 'mods/content/beekeeping/icons/beekeeping.dmi' + icon_state = "beepack" + material = /decl/material/solid/organic/plastic + var/full = 1 + +/obj/item/bee_pack/Initialize() + . = ..() + overlays += "beepack-full" + +/obj/item/bee_pack/proc/empty() + full = 0 + name = "empty bee pack" + desc = "A stasis pack for moving bees. It's empty." + overlays.Cut() + overlays += "beepack-empty" + +/obj/item/bee_pack/proc/fill() + full = initial(full) + SetName(initial(name)) + desc = initial(desc) + overlays.Cut() + overlays += "beepack-full" diff --git a/mods/content/beekeeping/recipes.dm b/mods/content/beekeeping/recipes.dm new file mode 100644 index 000000000000..8494617d3477 --- /dev/null +++ b/mods/content/beekeeping/recipes.dm @@ -0,0 +1,6 @@ +/decl/stack_recipe/planks/beehive_assembly + result_type = /obj/item/beehive_assembly + category = "furniture" + +/decl/stack_recipe/planks/beehive_frame + result_type = /obj/item/hive_frame/crafted diff --git a/mods/content/beekeeping/trading.dm b/mods/content/beekeeping/trading.dm new file mode 100644 index 000000000000..45009265f1bf --- /dev/null +++ b/mods/content/beekeeping/trading.dm @@ -0,0 +1,17 @@ +/datum/trader/trading_beacon/manufacturing/New() + LAZYSET(possible_trading_items, /obj/item/bee_pack, TRADER_THIS_TYPE) + LAZYSET(possible_trading_items, /obj/item/bee_smoker, TRADER_THIS_TYPE) + LAZYSET(possible_trading_items, /obj/item/beehive_assembly, TRADER_THIS_TYPE) + LAZYSET(possible_trading_items, /obj/item/hive_frame/crafted, TRADER_THIS_TYPE) + ..() + +/decl/hierarchy/supply_pack/hydroponics/bee_keeper + name = "Equipment - Beekeeping" + contains = list( + /obj/item/beehive_assembly, + /obj/item/bee_smoker, + /obj/item/hive_frame/crafted = 5, + /obj/item/bee_pack + ) + containername = "beekeeping crate" + access = access_hydroponics diff --git a/mods/content/bigpharma/_bigpharma.dm b/mods/content/bigpharma/_bigpharma.dm new file mode 100644 index 000000000000..b52e45b22774 --- /dev/null +++ b/mods/content/bigpharma/_bigpharma.dm @@ -0,0 +1,62 @@ +/decl/modpack/bigpharma + name = "Big Pharma Content" + +var/global/list/reagent_names_to_medication_names +/proc/get_medication_name_from_reagent_name(var/reagent_name) + . = LAZYACCESS(global.reagent_names_to_medication_names, reagent_name) + if(!.) + var/decl/language/bigpharma/pharma = GET_DECL(/decl/language/bigpharma) + LAZYSET(global.reagent_names_to_medication_names, reagent_name, pharma.get_random_language_name()) + . = global.reagent_names_to_medication_names[reagent_name] + +var/global/list/reagent_names_to_colours +/proc/get_medication_colour_from_reagent_name(var/reagent_name) + . = LAZYACCESS(global.reagent_names_to_colours, reagent_name) + if(!.) + LAZYSET(global.reagent_names_to_colours, reagent_name, get_random_colour()) + . = global.reagent_names_to_colours[reagent_name] + +var/global/list/reagent_names_to_icon_state +/proc/get_medication_icon_state_from_reagent_name(var/reagent_name, var/base_state, var/min, var/max) + . = LAZYACCESS(global.reagent_names_to_icon_state, reagent_name) + if(!.) + LAZYSET(global.reagent_names_to_icon_state, reagent_name, "[base_state][rand(min, max)]") + . = global.reagent_names_to_icon_state[reagent_name] + +/proc/handle_med_obfuscation(var/obj/item/thing) + // Do we need to bother with anything past this point? + var/datum/extension/obfuscated_medication/meds = get_extension(thing, /datum/extension/obfuscated_medication) + if(!meds) + return + // Emergency pouches probably shouldn't be obfuscated. + if(istype(thing.loc, /obj/item/med_pouch) || istype(thing.loc, /obj/item/firstaid)) + remove_extension(thing, /datum/extension/obfuscated_medication) + return + // Containers that can't find an original reagent name will just opt-out of the entire system. + meds.original_reagent = meds.get_original_reagent(thing) + if(!meds.original_reagent) + remove_extension(thing, /datum/extension/obfuscated_medication) + return + + // Labelled bottles should be left alone. + if(istype(thing, /obj/item/chems/glass/bottle)) + var/obj/item/chems/glass/bottle/bottle = thing + if(!bottle.autolabel && bottle.label_text) + remove_extension(thing, /datum/extension/obfuscated_medication) + return + + // Okay, now apply the obfuscation. + var/new_name = get_medication_name_from_reagent_name(meds.original_reagent) + if(new_name) + if(istype(thing, /obj/item/chems)) + var/obj/item/chems/chems = thing + chems.label_text = new_name + chems.update_name() + else + if(has_extension(thing, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(thing, /datum/extension/labels) + L.RemoveAllLabels() + thing.attach_label(null, null, new_name) + if(meds.container_description) + thing.desc = meds.container_description + thing.update_icon() diff --git a/mods/content/bigpharma/_bigpharma.dme b/mods/content/bigpharma/_bigpharma.dme new file mode 100644 index 000000000000..7da543df8eed --- /dev/null +++ b/mods/content/bigpharma/_bigpharma.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_BIGPHARMA +#define MODPACK_BIGPHARMA +// BEGIN_INCLUDE +#include "_bigpharma.dm" +#include "chems.dm" +#include "extension.dm" +#include "language.dm" +#include "overrides.dm" +#include "pill_bottle.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/bigpharma/chems.dm b/mods/content/bigpharma/chems.dm new file mode 100644 index 000000000000..a1cf00ae7118 --- /dev/null +++ b/mods/content/bigpharma/chems.dm @@ -0,0 +1,31 @@ +/obj/item/chems + var/obfuscated_meds_type + +/obj/item/chems/Initialize() + . = ..() + // Check area so stuff spawned for reference (atom info repository) isn't obfuscated + if(. != INITIALIZE_HINT_QDEL && obfuscated_meds_type && get_area(src)) + set_extension(src, obfuscated_meds_type) + . = INITIALIZE_HINT_LATELOAD + +/obj/item/chems/LateInitialize() + . = ..() + handle_med_obfuscation(src) + +/obj/item/chems/examined_by(mob/user, distance, infix, suffix) + . = ..() + var/datum/extension/obfuscated_medication/meds = get_extension(src, /datum/extension/obfuscated_medication) + if(meds && user && (user.skill_check(SKILL_CHEMISTRY, meds.skill_threshold) || user.skill_check(SKILL_MEDICAL, meds.skill_threshold))) + to_chat(user, SPAN_NOTICE("As far as you know, the active ingredient is [meds.original_reagent].")) + +/obj/item/chems/get_codex_value(var/mob/user) + var/datum/extension/obfuscated_medication/meds = get_extension(src, /datum/extension/obfuscated_medication) + if(meds && user && (user.skill_check(SKILL_CHEMISTRY, meds.skill_threshold) || user.skill_check(SKILL_MEDICAL, meds.skill_threshold))) + return "[meds.original_reagent] (substance)" + return ..() + +/obj/item/chems/on_update_icon() + var/datum/extension/obfuscated_medication/meds = get_extension(src, /datum/extension/obfuscated_medication) + if(meds) + meds.update_appearance() + . = ..() diff --git a/mods/content/bigpharma/extension.dm b/mods/content/bigpharma/extension.dm new file mode 100644 index 000000000000..04c672fa51af --- /dev/null +++ b/mods/content/bigpharma/extension.dm @@ -0,0 +1,57 @@ +/datum/extension/obfuscated_medication + base_type = /datum/extension/obfuscated_medication + expected_type = /obj/item + flags = EXTENSION_FLAG_IMMEDIATE + + var/original_reagent + var/skill_threshold = SKILL_BASIC + var/container_description + +/datum/extension/obfuscated_medication/proc/update_appearance() + return + +/datum/extension/obfuscated_medication/proc/get_original_reagent(var/obj/item/donor) + return donor?.reagents?.get_primary_reagent_name(codex = TRUE) + +/datum/extension/obfuscated_medication/bottle + container_description = "A small glass bottle of medication." + expected_type = /obj/item/chems/glass/bottle + +/datum/extension/obfuscated_medication/pill + container_description = "A small gel capsule of medication." + expected_type = /obj/item/chems/pill + +/datum/extension/obfuscated_medication/pill/update_appearance() + var/obj/item/pill = holder + pill.icon_state = get_medication_icon_state_from_reagent_name(original_reagent, "pill", 1, 5) + +/datum/extension/obfuscated_medication/syringe + container_description = "A pre-loaded syringe of medication." + expected_type = /obj/item/chems/syringe + +/datum/extension/obfuscated_medication/pill_bottle + container_description = "A small plastic bottle of pills." + expected_type = /obj/item/pill_bottle + +/datum/extension/obfuscated_medication/pill_bottle/get_original_reagent(var/obj/item/donor) + for(var/obj/item/chems/pill/pill in donor?.contents) + if(REAGENT_TOTAL_VOLUME(pill.reagents)) + return pill.reagents.get_primary_reagent_name(codex = TRUE) + +/datum/extension/obfuscated_medication/pill_bottle/update_appearance() + var/obj/item/pill_bottle/bottle = holder + bottle.wrapper_color = get_medication_colour_from_reagent_name(original_reagent) + +/datum/extension/obfuscated_medication/foil_pack + container_description = "A small foil blister pack of pills." + expected_type = /obj/item/pill_bottle/foil_pack + +/datum/extension/obfuscated_medication/foil_pack/get_original_reagent(var/obj/item/donor) + for(var/obj/item/chems/pill/pill in donor?.contents) + if(REAGENT_TOTAL_VOLUME(pill.reagents)) + return pill.reagents.get_primary_reagent_name(codex = TRUE) + +/datum/extension/obfuscated_medication/foil_pack/update_appearance() + var/obj/item/pill_bottle/foil_pack/foil_pack = holder + foil_pack.wrapper_color = COLOR_OFF_WHITE + foil_pack.color = get_medication_colour_from_reagent_name(original_reagent) diff --git a/mods/content/bigpharma/language.dm b/mods/content/bigpharma/language.dm new file mode 100644 index 000000000000..51d9335b5eee --- /dev/null +++ b/mods/content/bigpharma/language.dm @@ -0,0 +1,25 @@ +// This really shouldn't be used inround except as a joke, it's primarily just to abuse +// the random string generator to produce medication names without lots of boilerplate. +/decl/language/bigpharma + name = "Big Pharma" + desc = "An arcane series of runes invoked by masters of the dark arts of capitalism and medicine." + speech_verb = "chants" + exclaim_verb = "invokes" + ask_verb = "wails" + space_chance = 0 + key = "💊" + allow_repeated_syllables = FALSE + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_FORBIDDEN + syllables = list( + "o", "a","flu","o","me","phyto","doce","tha","facto","bena","zeco","ni", + "me","pro","dize","da","le","ta","to","ba","re","mbi","no","ffi", + "niu","ven","pedi","lo","tre","pilo","paro","xeti","xyco","lio" + ) + var/list/endings = list( + "zole","scept","ban","rone","mide","vir","max","fine","zac","trol", + "phen","m","tam", "gen", "tol", "dine","ne","taine" + ) + var/list/marks = list("™️","©️","®️") + +/decl/language/bigpharma/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + . = capitalize("[..(FEMALE, 1, rand(2,3), 1)][pick(endings)][pick(marks)]") diff --git a/mods/content/bigpharma/overrides.dm b/mods/content/bigpharma/overrides.dm new file mode 100644 index 000000000000..a159f041936e --- /dev/null +++ b/mods/content/bigpharma/overrides.dm @@ -0,0 +1,38 @@ +/obj/item/chems/pill + obfuscated_meds_type = /datum/extension/obfuscated_medication/pill + +/obj/item/chems/syringe + obfuscated_meds_type = /datum/extension/obfuscated_medication/syringe + +/obj/item/chems/glass/bottle + obfuscated_meds_type = /datum/extension/obfuscated_medication/bottle + +/obj/item/pill_bottle/foil_pack + obfuscated_meds_type = /datum/extension/obfuscated_medication/foil_pack + +/obj/item/pill_bottle/happy + obfuscated_meds_type = null + +/obj/item/chems/pill/happy + obfuscated_meds_type = null + +/obj/item/pill_bottle/zoom + obfuscated_meds_type = null + +/obj/item/chems/pill/zoom + obfuscated_meds_type = null + +/obj/item/pill_bottle/gleam + obfuscated_meds_type = null + +/obj/item/chems/pill/gleam + obfuscated_meds_type = null + +/obj/item/pill_bottle/assorted + obfuscated_meds_type = null + +/obj/item/chems/pill/detergent + obfuscated_meds_type = null + +/obj/item/chems/pill/pod + obfuscated_meds_type = null \ No newline at end of file diff --git a/mods/content/bigpharma/pill_bottle.dm b/mods/content/bigpharma/pill_bottle.dm new file mode 100644 index 000000000000..b0a70757af6d --- /dev/null +++ b/mods/content/bigpharma/pill_bottle.dm @@ -0,0 +1,31 @@ +/obj/item/pill_bottle + var/obfuscated_meds_type = /datum/extension/obfuscated_medication/pill_bottle + +/obj/item/pill_bottle/Initialize() + . = ..() + // Check area so stuff spawned for reference (atom info repository) isn't obfuscated + if(. != INITIALIZE_HINT_QDEL && obfuscated_meds_type && get_area(src)) + set_extension(src, obfuscated_meds_type) + . = INITIALIZE_HINT_LATELOAD + +/obj/item/pill_bottle/LateInitialize() + . = ..() + handle_med_obfuscation(src) + +/obj/item/pill_bottle/examined_by(mob/user, distance, infix, suffix) + . = ..() + var/datum/extension/obfuscated_medication/meds = get_extension(src, /datum/extension/obfuscated_medication) + if(meds && user && (user.skill_check(SKILL_CHEMISTRY, meds.skill_threshold) || user.skill_check(SKILL_MEDICAL, meds.skill_threshold))) + to_chat(user, SPAN_NOTICE("As far as you know, the active ingredient is [meds.original_reagent].")) + +/obj/item/pill_bottle/get_codex_value(var/mob/user) + var/datum/extension/obfuscated_medication/meds = get_extension(src, /datum/extension/obfuscated_medication) + if(meds && user && (user.skill_check(SKILL_CHEMISTRY, meds.skill_threshold) || user.skill_check(SKILL_MEDICAL, meds.skill_threshold))) + return "[meds.original_reagent] (substance)" + return ..() + +/obj/item/pill_bottle/on_update_icon() + var/datum/extension/obfuscated_medication/meds = get_extension(src, /datum/extension/obfuscated_medication) + if(meds) + meds.update_appearance() + . = ..() diff --git a/mods/content/biomods/_biomods.dm b/mods/content/biomods/_biomods.dm new file mode 100644 index 000000000000..e0695f8190b7 --- /dev/null +++ b/mods/content/biomods/_biomods.dm @@ -0,0 +1,2 @@ +/decl/modpack/biomods + name = "Biomodding Content" \ No newline at end of file diff --git a/mods/content/biomods/_biomods.dme b/mods/content/biomods/_biomods.dme new file mode 100644 index 000000000000..cdb7470d9b3d --- /dev/null +++ b/mods/content/biomods/_biomods.dme @@ -0,0 +1,9 @@ +#ifndef MODPACK_BIOMODS +#define MODPACK_BIOMODS +// BEGIN_INCLUDE +#include "_biomods.dm" +#include "ears.dm" +#include "ears_animal.dm" +#include "tails.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/biomods/ears.dm b/mods/content/biomods/ears.dm new file mode 100644 index 000000000000..bf929c74e068 --- /dev/null +++ b/mods/content/biomods/ears.dm @@ -0,0 +1,28 @@ +/decl/sprite_accessory/ears/biomods + abstract_type = /decl/sprite_accessory/ears/biomods + icon = 'mods/content/biomods/icons/ears.dmi' + +/decl/sprite_accessory/ears/biomods/pointed + name = "Pointed Ears" + icon_state = "ears_pointy" + uid = "accessory_ears_pointy" + +/decl/sprite_accessory/ears/biomods/pointed_long + name = "Long Pointed Ears" + icon_state = "ears_pointy_long" + uid = "accessory_ears_pointy_long" + +/decl/sprite_accessory/ears/biomods/pointed_down + name = "Pointed Ears (Downward)" + icon_state = "ears_pointy_down" + uid = "accessory_ears_pointy_down" + +/decl/sprite_accessory/ears/biomods/pointed_long_down + name = "Long Pointed Ears (Downward)" + icon_state = "ears_pointy_long_down" + uid = "accessory_ears_long_down" + +/decl/sprite_accessory/ears/biomods/elven + name = "Elven Ears" + icon_state = "elfs" + uid = "accessory_ears_elfs" diff --git a/mods/content/biomods/ears_animal.dm b/mods/content/biomods/ears_animal.dm new file mode 100644 index 000000000000..3e39b6567dd1 --- /dev/null +++ b/mods/content/biomods/ears_animal.dm @@ -0,0 +1,26 @@ +/decl/sprite_accessory/ears/biomods/animal + name = "Animal Ears" + icon_state = "ears_plain" + uid = "accessory_ears_animal" + accessory_metadata_types = list(SAM_COLOR, SAM_COLOR_INNER) + +/decl/sprite_accessory/ears/biomods/animal/lupine + name = "Lupine Ears" + icon_state = "wolf" + uid = "accessory_ears_wolf" + +/decl/sprite_accessory/ears/biomods/animal/fennec + name = "Fennec Ears" + icon_state = "fennec" + uid = "accessory_ears_fennec" + +/decl/sprite_accessory/ears/biomods/animal/vulpine + name = "Vulpine Ears" + icon_state = "fox" + uid = "accessory_ears_fox" + +/decl/sprite_accessory/ears/biomods/antlers + name = "Antlers" + icon_state = "antlers" + uid = "accessory_ears_antlers" + accessory_metadata_types = list(SAM_COLOR) diff --git a/mods/content/biomods/icons/ears.dmi b/mods/content/biomods/icons/ears.dmi new file mode 100644 index 000000000000..229f9ee64795 Binary files /dev/null and b/mods/content/biomods/icons/ears.dmi differ diff --git a/mods/content/biomods/icons/tails.dmi b/mods/content/biomods/icons/tails.dmi new file mode 100644 index 000000000000..28e52867a0b5 Binary files /dev/null and b/mods/content/biomods/icons/tails.dmi differ diff --git a/mods/content/biomods/tails.dm b/mods/content/biomods/tails.dm new file mode 100644 index 000000000000..d42ff27af93c --- /dev/null +++ b/mods/content/biomods/tails.dm @@ -0,0 +1,68 @@ +/decl/sprite_accessory/tail/biomods + abstract_type = /decl/sprite_accessory/tail/biomods + icon = 'mods/content/biomods/icons/tails.dmi' + accessory_metadata_types = list(SAM_COLOR) + +/decl/sprite_accessory/tail/biomods/twotone + abstract_type = /decl/sprite_accessory/tail/biomods/twotone + accessory_metadata_types = list(SAM_COLOR, SAM_COLOR_INNER) + +/decl/sprite_accessory/tail/biomods/twotone/skunk + name = "Skunk Tail" + icon_state = "skunktail" + uid = "acc_tail_skunk" + +/decl/sprite_accessory/tail/biomods/twotone/vulpine + name = "Vulpine Tail" + icon_state = "vulptail" + uid = "acc_tail_vulpine" + +/decl/sprite_accessory/tail/biomods/twotone/tuft + name = "Tuft Tail" + icon_state = "deertail" + uid = "acc_tail_deer" + +/decl/sprite_accessory/tail/biomods/twotone/long_tuft + name = "Long Tufted Tail" + icon_state = "easterntail" + uid = "acc_tail_eastern" + +/decl/sprite_accessory/tail/biomods/horse + name = "Horse Tail" + icon_state = "horse" + uid = "acc_tail_horse" + +/decl/sprite_accessory/tail/biomods/fantail + name = "Fantail" + icon_state = "fantail" + uid = "acc_tail_fan" + +/decl/sprite_accessory/tail/biomods/wagtail + name = "Wagtail" + icon_state = "wagtail" + uid = "acc_tail_wag" + +/decl/sprite_accessory/tail/biomods/mouse + name = "Mouse Tail" + icon_state = "mouse" + uid = "acc_tail_mouse" + +/decl/sprite_accessory/tail/biomods/straight + name = "Straight Tail" + icon_state = "straighttail" + uid = "acc_tail_straight" + +/decl/sprite_accessory/tail/biomods/spiky + name = "Spiky Tail" + icon_state = "ztail" + uid = "acc_tail_ztail" + +/decl/sprite_accessory/tail/biomods/fox + name = "Fox Tail" + icon_state = "fox_tail" + uid = "acc_tail_fox" + +/decl/sprite_accessory/tail/biomods/wolf + name = "Wolf Tail" + icon_state = "wolf_tail" + uid = "acc_tail_wolf" diff --git a/mods/content/blacksmithy/_blacksmithy.dm b/mods/content/blacksmithy/_blacksmithy.dm new file mode 100644 index 000000000000..0ec35cdf1ac6 --- /dev/null +++ b/mods/content/blacksmithy/_blacksmithy.dm @@ -0,0 +1,2 @@ +/decl/modpack/blacksmithy + name = "Blacksmithy" diff --git a/mods/content/blacksmithy/_blacksmithy.dme b/mods/content/blacksmithy/_blacksmithy.dme new file mode 100644 index 000000000000..806ddef8d9a9 --- /dev/null +++ b/mods/content/blacksmithy/_blacksmithy.dme @@ -0,0 +1,20 @@ +#ifndef MODPACK_BLACKSMITHY +#define MODPACK_BLACKSMITHY +// BEGIN_INCLUDE +#include "_blacksmithy.dm" +#include "anvil.dm" +#include "barrel_rim.dm" +#include "billet.dm" +#include "boulder.dm" +#include "forge_fire.dm" +#include "forging_step.dm" +#include "forging_step_armor.dm" +#include "forging_step_billets.dm" +#include "forging_step_blades.dm" +#include "forging_step_components.dm" +#include "forging_step_ornate.dm" +#include "forging_step_tools.dm" +#include "forging_types.dm" +#include "tongs.dm" +// END_INCLUDE +#endif diff --git a/mods/content/blacksmithy/anvil.dm b/mods/content/blacksmithy/anvil.dm new file mode 100644 index 000000000000..9f88267f22a8 --- /dev/null +++ b/mods/content/blacksmithy/anvil.dm @@ -0,0 +1,135 @@ +// Cut up from https://freesound.org/people/MrAuralization/sounds/274846/ (Avil, MrAuralization) (CC-BY-4) +/datum/composite_sound/anvil_strike + mid_sounds = list( + 'sound/effects/anvil1.ogg', + 'sound/effects/anvil2.ogg', + 'sound/effects/anvil3.ogg', + 'sound/effects/anvil4.ogg', + 'sound/effects/anvil5.ogg', + ) + mid_length = 1.5 SECONDS + var/mob/user + +/datum/composite_sound/anvil_strike/Destroy() + user = null + return ..() + +// This is a bit evil, but it should be cleaner than trying to run a second timing loop for the hammer strikes. +/datum/composite_sound/anvil_strike/play(soundfile) + . = ..() + for(var/obj/structure/anvil/anvil in output_atoms) + if(user) + user.do_attack_animation(anvil, user.get_active_held_item()) + anvil.shake_animation() + for(var/obj/item/thing in anvil.loc?.get_contained_external_atoms()) + thing.shake_animation() + spark_at(get_turf(anvil), amount = 1, spark_type = /datum/effect/effect/system/spark_spread/silent) + +/obj/structure/anvil + name = "anvil" + desc = "A heavy block of material used as support for hammering things into shape." + icon = 'mods/content/blacksmithy/icons/anvil.dmi' + icon_state = ICON_STATE_WORLD + anchored = TRUE + density = TRUE + opacity = FALSE + atom_flags = ATOM_FLAG_CLIMBABLE + w_class = ITEM_SIZE_STRUCTURE //_LARGE + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + max_health = 1000 + structure_flags = STRUCTURE_FLAG_SURFACE + material_alteration = MAT_FLAG_ALTERATION_ALL + hitsound = 'sound/effects/anvil1.ogg' + var/datum/composite_sound/anvil_strike/clang + +/obj/structure/anvil/Initialize() + . = ..() + clang = new(list(src), FALSE) + +/obj/structure/anvil/Destroy() + QDEL_NULL(clang) + return ..() + +/obj/structure/anvil/proc/start_working(mob/user) + if(clang) + clang.user = user + if(!clang.started) + clang.start() + +/obj/structure/anvil/proc/stop_working() + if(clang) + clang.user = null + if(clang.started) + clang.stop() + +/obj/structure/anvil/on_update_icon() + . = ..() + icon_state = initial(icon_state) + switch(get_health_percent()) + if(0 to 0.35) + icon_state = "[icon_state]-damage-heavy" + if(0.35 to 0.65) + icon_state = "[icon_state]-damage-light" + +/obj/structure/anvil/attackby(obj/item/used_item, mob/user, click_params) + + // Put the bar from tongs onto the anvil. + if(istype(used_item, /obj/item/tongs)) + var/obj/item/tongs/tongs = used_item + if(tongs.holding_bar) + used_item = tongs.holding_bar + tongs.holding_bar.dropInto(loc) + // Flow through into procs below. + + // Put the bar onto the anvil (need to do this to avoid repairs in ..()) + if(istype(used_item, /obj/item/stack/material/bar) && used_item.is_forgable()) + var/obj/item/stack/material/bar/bar = used_item + if(used_item.material != material || current_health >= get_max_health()) + if(bar.get_amount() > 1) + bar = bar.split(1) + if(bar.loc == user) + if(!user.try_unequip(bar, get_turf(src))) + return TRUE + else + bar.dropInto(get_turf(src)) + qdel(bar) + used_item = new /obj/item/billet(loc, used_item.material?.type) + // Flow through to billet placement below. + + // Place things onto the anvil. + if(!user.check_intent(I_FLAG_HARM) && (istype(used_item, /obj/item/tool/hammer/forge) || istype(used_item, /obj/item/tongs) || istype(used_item, /obj/item/billet))) + if(used_item.loc == user) + if(!user.try_unequip(used_item, get_turf(src))) + return TRUE + else + used_item.dropInto(get_turf(src)) + auto_align(used_item, click_params) + return TRUE + + . = ..() + +// Chipped out of a boulder with a pick. +/obj/structure/anvil/boulder + name_prefix = "crude" + icon = 'mods/content/blacksmithy/icons/anvil_crude.dmi' + desc = "A crude anvil chipped out of a chunk of stone. It probably won't last very long." + material = /decl/material/solid/stone/granite + max_health = 500 + +/obj/structure/anvil/boulder/Initialize(ml, _mat, _reinf_mat) + . = ..() + if(prob(50)) + set_icon('mods/content/blacksmithy/icons/anvil_crude_alt.dmi') + +// Improvised with spaceman materials. +/obj/structure/anvil/improvised + name_prefix = "improvised" + icon = 'mods/content/blacksmithy/icons/anvil_improvised.dmi' + desc = "A anvil roughly improvised out of scrap metal. It probably won't last very long." + material = /decl/material/solid/metal/steel + max_health = 500 + +/decl/stack_recipe/steel/furniture + result_type = /obj/structure/anvil/improvised + difficulty = MAT_VALUE_HARD_DIY diff --git a/mods/content/blacksmithy/barrel_rim.dm b/mods/content/blacksmithy/barrel_rim.dm new file mode 100644 index 000000000000..0175a04d3e02 --- /dev/null +++ b/mods/content/blacksmithy/barrel_rim.dm @@ -0,0 +1,52 @@ +/obj/item/barrel_rim + name = "barrel rim" + desc = "A circular brace used to hold a barrel together." + icon_state = ICON_STATE_WORLD + icon = 'icons/obj/items/barrel_rim.dmi' + material = /decl/material/solid/metal/iron + material_alteration = MAT_FLAG_ALTERATION_ALL + +/decl/stack_recipe/rods/stick/barrel_rim + result_type = /obj/item/barrel_rim + one_per_turf = FALSE + on_floor = FALSE + category = "items" + +/obj/structure/reagent_dispensers/barrel + // Skill used for coopery. + var/work_skill = SKILL_CONSTRUCTION + +// Overrides to make barrel rims useful. +/obj/structure/reagent_dispensers/barrel/crafted + metal_material = null +/obj/structure/reagent_dispensers/barrel/cask/crafted + metal_material = null + +/obj/structure/reagent_dispensers/barrel/create_dismantled_products(turf/target) + if(metal_material) + new /obj/item/barrel_rim(target, metal_material) + metal_material = null + return ..() + +// Barrels with no reinforcement break apart when things are put inside. +/obj/structure/reagent_dispensers/barrel/Entered(atom/movable/atom, atom/old_loc) + . = ..() + if(!metal_material) + physically_destroyed() + +/obj/structure/reagent_dispensers/barrel/on_reagent_change() + . = ..() + if(!metal_material && REAGENT_TOTAL_VOLUME(reagents)) + physically_destroyed() + +// Adding a rim to a crafted barrel. +/obj/structure/reagent_dispensers/barrel/attackby(obj/item/used_item, mob/user) + if(isnull(metal_material) && istype(used_item.material) && istype(used_item, /obj/item/barrel_rim)) + user.visible_message(SPAN_NOTICE("\The [user] begins securing \the [src] with \the [used_item].")) + if(user.do_skilled(5 SECONDS, work_skill, src, check_holding = TRUE) && user.try_unequip(used_item)) + metal_material = used_item.material + update_icon() + user.visible_message(SPAN_NOTICE("\The [user] secures \the [src] with \the [used_item].")) + qdel(used_item) + return TRUE + . = ..() diff --git a/mods/content/blacksmithy/billet.dm b/mods/content/blacksmithy/billet.dm new file mode 100644 index 000000000000..b269d10ae0c1 --- /dev/null +++ b/mods/content/blacksmithy/billet.dm @@ -0,0 +1,215 @@ +// Turning billets back into bars. +/obj/item/stack/material/bar/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/billet) && used_item.material == material && !reinf_material) + var/obj/item/billet/billet = used_item + if(billet.current_forging_step && billet.current_forging_step.type != /decl/forging_step/billet) + to_chat(user, SPAN_WARNING("\The [used_item] will need to be melted down and recast before you can reuse it as a bar.")) + return TRUE + if(!user.try_unequip(used_item, loc)) + return TRUE + if(get_amount() >= get_max_amount()) + return TRUE + add(1) + qdel(used_item) + return TRUE + . = ..() + +/// Whether or not this item is considered forgable (e.g. there is a temperature at which it can be forged) +/obj/item/proc/is_forgable() + if(!istype(material) || isnull(material.melting_point) || !material.forgable) + return FALSE + return TRUE + +/obj/item/proc/hot_enough_to_forge(melting_point_percent = 0.25) + if(!is_forgable()) + return FALSE + // Defaults to >25% of the way to melting to be considered 'forgable' + return temperature >= ((material.melting_point - T20C) * melting_point_percent) + T20C + +/obj/item/billet + name = "billet" + desc = "An unworked or partially-worked length of metal used to forge items and tools." + icon = 'mods/content/blacksmithy/icons/billet.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + material_alteration = MAT_FLAG_ALTERATION_ALL + var/decl/forging_step/current_forging_step = /decl/forging_step/billet + +/obj/item/billet/Initialize(ml, material_key) + if(ispath(current_forging_step)) + set_forging_step(current_forging_step, force = TRUE) + . = ..() + +/obj/item/billet/proc/set_forging_step(decl/forging_step/new_step, force) + if(ispath(new_step)) + new_step = GET_DECL(new_step) + if(!istype(new_step) || (!force && current_forging_step == new_step)) + return FALSE + current_forging_step = new_step + . = current_forging_step.apply_to(src) + if(!QDELETED(src)) + update_name() + update_icon() + update_heat_glow(anim_time = 0) // reset heat color to avoid weird visual jitter + +/obj/item/billet/attackby(obj/item/used_item, mob/user) + + // Merging billets back into bars. + if(istype(used_item, /obj/item/billet) && material == used_item.material) + if(current_forging_step && current_forging_step.type != /decl/forging_step/billet) + to_chat(user, SPAN_WARNING("\The [src] will need to be melted down and recast before you can reuse it as a bar.")) + return TRUE + var/obj/item/billet/billet = used_item + if(billet.current_forging_step && billet.current_forging_step.type != /decl/forging_step/billet) + to_chat(user, SPAN_WARNING("\The [billet] will need to be melted down and recast before you can reuse it as a bar.")) + return TRUE + if(user.try_unequip(used_item, loc)) + var/obj/item/stack/material/bar/bars = new(loc, 2, material.type) + bars.dropInto(loc) + qdel(used_item) + qdel(src) + return TRUE + + // Picking up in tongs. + if(istype(used_item, /obj/item/tongs)) + var/obj/item/tongs/tongs = used_item + if(tongs.holding_bar) + return ..() + var/mob/holder = loc + if(istype(holder)) + if(!holder.try_unequip(src, tongs)) + return TRUE + else if(loc?.storage) + if(!loc.storage.remove_from_storage(user, src, tongs)) + return TRUE + else + forceMove(tongs) + if(loc == tongs) + tongs.holding_bar = src + tongs.update_icon() + return TRUE + + if(!istype(used_item, /obj/item/tool/hammer/forge) || user.check_intent(I_FLAG_HARM)) + return ..() + + // Check for surface. + var/obj/structure/anvil/anvil = locate() in loc + if(!istype(anvil)) + to_chat(user, SPAN_WARNING("\The [src] can only be worked on an anvil.")) + return TRUE + + // Check for heat. + if(!hot_enough_to_forge()) + to_chat(user, SPAN_WARNING("\The [src] is too cold to be worked on the anvil.")) + return TRUE + + // Sanity check. + if(!length(current_forging_step?.steps)) // how tho + to_chat(user, SPAN_WARNING("You cannot see any further way to refine \the [src].")) + return TRUE + + // Handle the actual forging process. + var/last_step = current_forging_step + var/decl/forging_step/next_step = show_radial_menu(user, src, current_forging_step.get_radial_choices(), radius = 42, use_labels = RADIAL_LABELS_CENTERED, require_near = TRUE, check_locs = list(src)) + + if(!standard_forging_checks(user, used_item, last_step, next_step, anvil)) + return TRUE + + if(user.get_stamina() < 10) + to_chat(user, SPAN_WARNING("You are too exhausted to swing \the [used_item].")) + return TRUE + + user.adjust_stamina(-10) + anvil.start_working(user) + + // Skill checks! + if(!user.do_skilled(3 SECONDS, next_step.work_skill, anvil)) + anvil?.stop_working() + return TRUE + + if(!istype(next_step) || (next_step.skill_fail_prob && user.skill_fail_prob(next_step.work_skill, next_step.skill_fail_prob, next_step.skill_level, next_step.skill_factor))) + to_chat(user, SPAN_WARNING("You fumble the work and fail to reshape \the [src].")) + anvil?.stop_working() + return TRUE + + // Since we have a sleep() above, we recheck our basic conditions. + if(!standard_forging_checks(user, used_item, last_step, next_step, anvil)) + anvil?.stop_working() + return TRUE + + if(user.get_stamina() < 10) + to_chat(user, SPAN_WARNING("You are too exhausted to keep swinging \the [used_item].")) + anvil?.stop_working() + return TRUE + + user.adjust_stamina(-10) + + // Update the billet (which may produce an item!) + var/obj/item/forged_thing = set_forging_step(next_step) + if(istype(forged_thing)) + user.visible_message(SPAN_NOTICE("\The [user] has [next_step.work_verb] the billet into \a [forged_thing].")) + // Forging gradually degrades anvils. + if(!QDELETED(anvil)) + anvil.stop_working() + anvil.take_damage(rand(10, 20), BRUTE, silent = TRUE) // We are already going CLANG CLANG CLANG, don't need a THUNK + return TRUE + +/obj/item/billet/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + for(var/decl/forging_step/next_step in current_forging_step?.steps) + if(user.skill_check(next_step.work_skill, next_step.skill_level)) + LAZYADD(., SPAN_INFO("It can be [next_step.work_verb] into \a [next_step.get_product_name(material)] on an anvil.")) + +/obj/item/billet/proc/standard_forging_checks(mob/user, obj/item/used_item, decl/forging_step/last_step, decl/forging_step/next_step, obj/structure/anvil/anvil) + // We cancelled or changed state, abort. + if(!next_step || current_forging_step != last_step || !(next_step in current_forging_step.steps)) + return FALSE + // Something has been destroyed since we started forging. + if(QDELETED(src) || QDELETED(used_item) || QDELETED(anvil) || QDELETED(user)) + return FALSE + // Something else has changed, very unfortunate. + if(loc != anvil.loc || !CanPhysicallyInteract(user) || user.get_active_held_item() != used_item) + return FALSE + return hot_enough_to_forge() + +/obj/item/billet/on_update_icon() + . = ..() + if(!istype(current_forging_step)) + return + if(current_forging_step.billet_icon) + set_icon(current_forging_step.billet_icon) + else + set_icon(initial(icon)) + icon_state = get_world_inventory_state() + if(current_forging_step.billet_icon_state) + icon_state = "[icon_state]-[current_forging_step.billet_icon_state]" + +/obj/item/billet/get_world_inventory_state() + if(!current_forging_step?.billet_icon_state) + return ..() + if(!check_state_in_icon("[ICON_STATE_INV]-[current_forging_step.billet_icon_state]", icon)) + return ICON_STATE_WORLD + return ..() + +/obj/item/billet/update_name() + if(!istype(current_forging_step)) + base_name = initial(base_name) + name_prefix = initial(name_prefix) + desc = initial(desc) + return ..() + base_name = current_forging_step.billet_name + name_prefix = current_forging_step.billet_name_prefix + . = ..() + desc = current_forging_step.billet_desc + if(istype(material)) + desc = "[desc] This one is made of [material.solid_name]." + +/obj/item/billet/ProcessAtomTemperature() + . = ..() + update_heat_glow() + +// Arbitrary value to give people enough time to forge the bloody thing. +/obj/item/billet/get_thermal_mass_coefficient(delta) + // Only delay cooling if we're over our forging point. + return delta < 0 && hot_enough_to_forge() ? 0.01 : ..() diff --git a/mods/content/blacksmithy/boulder.dm b/mods/content/blacksmithy/boulder.dm new file mode 100644 index 000000000000..73ce542cf98a --- /dev/null +++ b/mods/content/blacksmithy/boulder.dm @@ -0,0 +1,23 @@ +/obj/structure/boulder/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/chip_anvil) + +/decl/interaction_handler/chip_anvil + name = "Chip Into Anvil" + expected_target_type = /obj/structure/boulder + var/work_skill = SKILL_CONSTRUCTION + +/decl/interaction_handler/chip_anvil/is_possible(atom/target, mob/user, obj/item/prop) + . = ..() && istype(prop) && IS_PICK(prop) && prop.material?.hardness >= target.get_material()?.hardness && user.skill_check(work_skill, SKILL_BASIC) + +/decl/interaction_handler/chip_anvil/invoked(atom/target, mob/user, obj/item/prop) + user.visible_message(SPAN_NOTICE("\The [user] begins chipping \the [target] into a rough anvil using \the [prop].")) + if(!user.do_skilled(10 SECONDS, work_skill, target)) + return FALSE + if(QDELETED(user) || QDELETED(target) || QDELETED(prop) || user.get_active_held_item() != prop || !CanPhysicallyInteractWith(user, target)) + return FALSE + if(!is_possible(target, user, prop)) + return FALSE + user.visible_message(SPAN_NOTICE("\The [user] chips \the [target] into a rough anvil using \the [prop].")) + new /obj/structure/anvil/boulder(get_turf(target), target.get_material()?.type) + return TRUE diff --git a/mods/content/blacksmithy/forge_fire.dm b/mods/content/blacksmithy/forge_fire.dm new file mode 100644 index 000000000000..1c32a6e8d912 --- /dev/null +++ b/mods/content/blacksmithy/forge_fire.dm @@ -0,0 +1,83 @@ +/datum/storage/forge + can_hold = list( + /obj/item/stack/material/bar, + /obj/item/billet + ) + max_storage_space = ITEM_SIZE_NORMAL * 10 // Fairly spacious + max_w_class = ITEM_SIZE_LARGE + +/datum/storage/forge/consolidate_stacks() + return // We want to keep them as single bars. + +/obj/structure/fire_source/forge + name = "forge fire" + desc = "A sturdy hearth used to heat metal bars for forging on an anvil." + density = TRUE + icon = 'mods/content/blacksmithy/icons/forge.dmi' + icon_state = "forge" + storage = /datum/storage/forge + +/obj/structure/fire_source/forge/proc/get_forgable_contents() + . = list() + for(var/obj/item/thing in get_stored_inventory()) + if(thing.is_forgable() && (istype(thing, /obj/item/billet) || istype(thing, /obj/item/stack/material/bar))) + . += thing + +/obj/structure/fire_source/forge/attackby(obj/item/used_item, mob/user) + + var/item_is_forgable = used_item.is_forgable() + // Raw materials. + if(istype(used_item, /obj/item/stack/material/bar) && item_is_forgable) + var/obj/item/stack/material/bar/bar = used_item + if(used_item.material != material || current_health >= get_max_health()) + if(bar.get_amount() > 1) + bar = bar.split(1) + if(bar.loc == user) + if(!user.try_unequip(bar, get_turf(src))) + return TRUE + else + bar.dropInto(get_turf(src)) + qdel(bar) + used_item = new /obj/item/billet(loc, used_item.material?.type) + // Flows through to below. + + // Partially worked billets. + if(istype(used_item, /obj/item/billet) && item_is_forgable) + if(used_item.loc == user) + user.try_unequip(used_item, loc) + else + used_item.dropInto(loc) + if(storage.can_be_inserted(used_item, user)) + storage.handle_item_insertion(user, used_item) + update_icon() + return TRUE + + // Tongs holding bars or partially worked billets. + if(istype(used_item, /obj/item/tongs) && !user.check_intent(I_FLAG_HARM)) + + // Put whatever's in the tongs into storage. + var/obj/item/tongs/tongs = used_item + if(tongs.holding_bar) + return attackby(tongs.holding_bar, user) + + // Check if we have any bars. + var/list/bars = get_forgable_contents() + if(!length(bars)) + to_chat(user, SPAN_WARNING("There are no bars in \the [src] to retrieve.")) + return TRUE + + // Get the hottest bar. + var/obj/item/hottest_bar + for(var/obj/item/bar in bars) + if(!hottest_bar || bar.temperature > hottest_bar) + hottest_bar = bar + + // Extract a single bar from the forge with the tongs. + if(storage.remove_from_storage(user, hottest_bar, tongs)) + tongs.holding_bar = hottest_bar + if(tongs.holding_bar) + user.visible_message(SPAN_NOTICE("\The [user] pulls \the [tongs.holding_bar] from \the [src] with \the [tongs].")) + tongs.update_icon() + return TRUE + + return ..() diff --git a/mods/content/blacksmithy/forging_step.dm b/mods/content/blacksmithy/forging_step.dm new file mode 100644 index 000000000000..44eaa8824a74 --- /dev/null +++ b/mods/content/blacksmithy/forging_step.dm @@ -0,0 +1,100 @@ +/decl/forging_step + abstract_type = /decl/forging_step + /// Base name, generated from billet_name and billet_name_prefix. + var/name + /// Name to use for the actual billet item. + var/billet_name = "billet" + /// Name prefix to use for the billet at this stage. + var/billet_name_prefix + /// Description to use for the billet at this stage. + var/billet_desc + /// Icon state modifier to use for the billet at this stage. + var/billet_icon_state + /// Icon to use for the billet (for modpacks/downstreams) + var/billet_icon = 'mods/content/blacksmithy/icons/billet.dmi' + /// List of available /decl/forging_step instances. + var/list/steps + /// Probability of failing this step if we're below skill_level. + var/skill_fail_prob = 30 + /// Impact of skill against probability of failure. + var/skill_factor = 1 + /// Skill level where failing this step becomes impossible. + var/skill_level = SKILL_ADEPT + /// What skill this step requires. + var/work_skill = SKILL_CONSTRUCTION + /// Descriptive string for this action. + var/work_verb = "forged" + +/decl/forging_step/Initialize() + + // Resolve our types now to get it out of the way. + for(var/step in steps) + steps -= step + steps += GET_DECL(step) + + if(billet_name_prefix) + name = jointext(list(billet_name_prefix, billet_name), " ") + else + name = billet_name + + . = ..() + +/decl/forging_step/validate() + . = ..() + if(!istext(name)) + . += "null or invalid name" + if(!istext(billet_desc)) + . += "null or invalid billet_desc" + if(!length(steps) && !istype(src, /decl/forging_step/product)) + . += "null or empty steps list" + if(billet_icon_state) + if(billet_icon) + if(!check_state_in_icon("[ICON_STATE_WORLD]-[billet_icon_state]", billet_icon)) + . += "missing billet icon state '[ICON_STATE_WORLD]-[billet_icon_state]' from icon '[billet_icon]'" + else + . += "missing billet_icon" + +/decl/forging_step/proc/get_product_name(decl/material/billet_material) + . = billet_name + if(billet_material) + . = "[billet_material.adjective_name] [.]" + if(billet_name_prefix) + . = "[billet_name_prefix] [.]" + +/decl/forging_step/proc/get_radial_choices() + for(var/decl/forging_step/step in steps) + var/image/radial_button = new + radial_button.name = capitalize(step.name) + LAZYSET(., step, radial_button) + +/decl/forging_step/proc/apply_to(obj/item/billet/billet) + return billet + +// There are effectively finished products. +/decl/forging_step/product + // Dummy strings to avoid validate() fails; shouldn't be used anywhere. + name = "finished product" + billet_desc = "A finished product." + abstract_type = /decl/forging_step/product + var/product_type = /obj/item/stick + +/decl/forging_step/product/get_product_name(decl/material/billet_material) + return atom_info_repository.get_name_for(product_type, billet_material?.type) + +/decl/forging_step/product/apply_to(obj/item/billet/billet) + var/obj/item/thing = new product_type(null, billet.material?.type) + thing.dropInto(billet.loc) + thing.pixel_x = billet.pixel_x + thing.pixel_y = billet.pixel_y + thing.pixel_w = billet.pixel_w + thing.pixel_z = billet.pixel_z + thing.temperature = billet.temperature + thing.update_heat_glow(anim_time = 0) + + if(billet.paint_color) + thing.paint_color = billet.paint_color + thing.update_icon() + qdel(billet) + thing.base_name = name + thing.update_name() + return thing diff --git a/mods/content/blacksmithy/forging_step_armor.dm b/mods/content/blacksmithy/forging_step_armor.dm new file mode 100644 index 000000000000..f0633652912e --- /dev/null +++ b/mods/content/blacksmithy/forging_step_armor.dm @@ -0,0 +1,37 @@ +/decl/forging_step/armour_plates + billet_desc = "A set of worked metal plates, a few steps and fittings away from forming some kind of armour." + billet_name = "armour plates" + billet_icon_state = "armour" + steps = list( + /decl/forging_step/product/breastplate, + /decl/forging_step/product/cuirass, + /decl/forging_step/product/banded + ) + +/decl/forging_step/armour_segments + billet_desc = "A set of small worked metal plates, a few steps and fittings away from forming a helmet, or arm or leg armour." + billet_name = "armour segments" + billet_icon_state = "helmet" + steps = list( + /decl/forging_step/product/helmet, + /decl/forging_step/product/sabatons, + /decl/forging_step/product/vambraces + ) + +/decl/forging_step/product/breastplate + product_type = /obj/item/clothing/suit/armor/forged/breastplate + +/decl/forging_step/product/cuirass + product_type = /obj/item/clothing/suit/armor/forged/cuirass + +/decl/forging_step/product/banded + product_type = /obj/item/clothing/suit/armor/forged/banded + +/decl/forging_step/product/helmet + product_type = /obj/item/clothing/head/helmet/plumed + +/decl/forging_step/product/sabatons + product_type = /obj/item/clothing/shoes/sabatons + +/decl/forging_step/product/vambraces + product_type = /obj/item/clothing/gloves/vambrace diff --git a/mods/content/blacksmithy/forging_step_billets.dm b/mods/content/blacksmithy/forging_step_billets.dm new file mode 100644 index 000000000000..8557b9f9eb91 --- /dev/null +++ b/mods/content/blacksmithy/forging_step_billets.dm @@ -0,0 +1,48 @@ +/decl/forging_step/billet + billet_desc = "An unworked length of metal used to forge items and tools." + steps = list( + /decl/forging_step/thin_billet, + /decl/forging_step/curved_billet, + /decl/forging_step/flat_bar, + /decl/forging_step/punched_billet + ) + +/decl/forging_step/thin_billet + billet_name_prefix = "thin" + billet_icon_state = "thin" + billet_desc = "A thin, elongated length of metal used to forge items and tools." + steps = list( + /decl/forging_step/blade_blank, + /decl/forging_step/ornate_blank, + /decl/forging_step/product/nails + ) + +/decl/forging_step/curved_billet + billet_name_prefix = "curved" + billet_icon_state = "curved" + billet_desc = "A curved length of metal used to forge items and tools." + steps = list( + /decl/forging_step/product/hook, + /decl/forging_step/product/chain, + /decl/forging_step/product/horseshoe + ) + +/decl/forging_step/flat_bar + billet_name = "bar" + billet_name_prefix = "flat" + billet_icon_state = "flat" + billet_desc = "A flattened bar of metal used to forge armour components and plates." + steps = list( + /decl/forging_step/armour_plates, + /decl/forging_step/armour_segments, + /decl/forging_step/product/shield_fasteners + ) + +/decl/forging_step/punched_billet + billet_name_prefix = "punched" + billet_icon_state = "punched" + billet_desc = "A punched bar of metal used to forge items and tools" + steps = list( + /decl/forging_step/tool_head_blank, + /decl/forging_step/product/tongs + ) diff --git a/mods/content/blacksmithy/forging_step_blades.dm b/mods/content/blacksmithy/forging_step_blades.dm new file mode 100644 index 000000000000..8e9524336b17 --- /dev/null +++ b/mods/content/blacksmithy/forging_step_blades.dm @@ -0,0 +1,59 @@ +/decl/forging_step/blade_blank + billet_name = "blade blank" + billet_icon_state = "blade" + billet_desc = "A roughly shaped, dull blade. It will need further refinement before it can be finished." + steps = list( + /decl/forging_step/long_blade_blank, + /decl/forging_step/short_sword_blank + ) + +/decl/forging_step/long_blade_blank + billet_name = "blade blank" + billet_name_prefix = "long" + billet_desc = "A long, dull and unrefined blade, only a step from being a finished product." + + steps = list( + /decl/forging_step/product/longsword_blade, + /decl/forging_step/product/broadsword_blade, + /decl/forging_step/product/rapier_blade + ) + +/decl/forging_step/short_sword_blank + billet_name = "blade blank" + billet_name_prefix = "short" + billet_desc = "A short, dull and unrefined blade, only a step from being a finished product." + steps = list( + /decl/forging_step/product/poignard_blade, + /decl/forging_step/product/knife_blade, + /decl/forging_step/product/shortsword_blade, + /decl/forging_step/product/spear_head + ) + +// TODO: make these blades, add weapon crafting. +/decl/forging_step/product/longsword_blade + billet_name = "longsword" + product_type = /obj/item/bladed/longsword/forged + +/decl/forging_step/product/broadsword_blade + billet_name = "broadsword" + product_type = /obj/item/bladed/broadsword/forged + +/decl/forging_step/product/rapier_blade + billet_name = "rapier" + product_type = /obj/item/bladed/rapier/forged + +/decl/forging_step/product/poignard_blade + billet_name = "poignard" + product_type = /obj/item/bladed/poignard/forged + +/decl/forging_step/product/knife_blade + billet_name = "knife" + product_type = /obj/item/bladed/knife/forged + +/decl/forging_step/product/shortsword_blade + billet_name = "shortsword" + product_type = /obj/item/bladed/shortsword/forged + +/decl/forging_step/product/spear_head + billet_name = "spear" + product_type = /obj/item/bladed/polearm/spear/forged diff --git a/mods/content/blacksmithy/forging_step_components.dm b/mods/content/blacksmithy/forging_step_components.dm new file mode 100644 index 000000000000..6e508d3aa528 --- /dev/null +++ b/mods/content/blacksmithy/forging_step_components.dm @@ -0,0 +1,15 @@ +/decl/forging_step/product/hook + billet_name = "hook" + product_type = /obj/item/hook + +/decl/forging_step/product/chain + billet_name = "chain" + product_type = /obj/item/chain + +/decl/forging_step/product/horseshoe + billet_name = "horseshoe" + product_type = /obj/item/horseshoe + +/decl/forging_step/product/shield_fasteners + billet_name = "shield fasteners" + product_type = /obj/item/shield_fasteners diff --git a/mods/content/blacksmithy/forging_step_ornate.dm b/mods/content/blacksmithy/forging_step_ornate.dm new file mode 100644 index 000000000000..3070d060a9be --- /dev/null +++ b/mods/content/blacksmithy/forging_step_ornate.dm @@ -0,0 +1,22 @@ +/decl/forging_step/ornate_blank + billet_name = "blank" + billet_name_prefix = "ornate" + billet_icon_state = "ornate" + billet_desc = "An ornate piece of worked metal. It still needs some last touches to be made into something useful." + steps = list( + /decl/forging_step/product/candelabra, + /decl/forging_step/product/decanter, + /decl/forging_step/product/goblet + ) + +/decl/forging_step/product/candelabra + billet_name = "candelabra" + product_type = /obj/item/candelabra + +/decl/forging_step/product/goblet + billet_name = "goblet" + product_type = /obj/item/chems/glass/handmade/fancy/goblet + +/decl/forging_step/product/decanter + billet_name = "decanter" + product_type =/obj/item/chems/glass/handmade/fancy/decanter \ No newline at end of file diff --git a/mods/content/blacksmithy/forging_step_tools.dm b/mods/content/blacksmithy/forging_step_tools.dm new file mode 100644 index 000000000000..4911ec5cedf3 --- /dev/null +++ b/mods/content/blacksmithy/forging_step_tools.dm @@ -0,0 +1,64 @@ +/decl/forging_step/tool_head_blank + billet_desc = "A heavy piece of shaped metal, almost suitable for use as the head of a tool. It still needs some last touches to be made into something useful." + billet_name = "tool head blank" + billet_icon_state = "tool_head" + steps = list( + /decl/forging_step/product/hoe_head, + /decl/forging_step/product/shovel_head, + /decl/forging_step/hammer_head_blank, + /decl/forging_step/product/chisel_head + ) + +/decl/forging_step/hammer_head_blank + billet_name = "hammer head blank" + billet_desc = "A worked slab of material in the rough shape of a hammer head, only a step from being a finished product." + steps = list( + /decl/forging_step/product/pickaxe_head, + /decl/forging_step/product/sledge_head, + /decl/forging_step/product/hammer_head, + /decl/forging_step/product/forging_hammer_head + ) + +/decl/forging_step/product/tongs + billet_name = "tongs" + product_type = /obj/item/tongs + +/decl/forging_step/product/chisel_head + billet_name = "chisel head" + product_type = /obj/item/tool_component/head/chisel + +/decl/forging_step/product/hammer_head + billet_name = "hammer head" + product_type = /obj/item/tool_component/head/hammer + +/decl/forging_step/product/shovel_head + billet_name = "shovel head" + product_type = /obj/item/tool_component/head/shovel + +/decl/forging_step/product/hoe_head + billet_name = "hoe head" + product_type = /obj/item/tool_component/head/hoe + +/decl/forging_step/product/handaxe_head + billet_name = "handaxe head" + product_type = /obj/item/tool_component/head/handaxe + +/decl/forging_step/product/pickaxe_head + billet_name = "pickaxe head" + product_type = /obj/item/tool_component/head/pickaxe + +/decl/forging_step/product/sledge_head + billet_name = "sledge head" + product_type = /obj/item/tool_component/head/sledgehammer + +/decl/forging_step/product/forging_hammer_head + billet_name = "forging hammer head" + product_type = /obj/item/tool_component/head/forging_hammer + +/decl/forging_step/product/nails + billet_name = "nails" + product_type = /obj/item/stack/material/nail/twelve + +/decl/forging_step/product/barrel_rim + billet_name = "barrel rim" + product_type = /obj/item/barrel_rim diff --git a/mods/content/blacksmithy/forging_types.dm b/mods/content/blacksmithy/forging_types.dm new file mode 100644 index 000000000000..f766d39982da --- /dev/null +++ b/mods/content/blacksmithy/forging_types.dm @@ -0,0 +1,41 @@ +/obj/item/bladed/longsword/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null + +/obj/item/bladed/broadsword/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null + +/obj/item/bladed/rapier/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null + +/obj/item/bladed/poignard/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null + +/obj/item/bladed/knife/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null + +/obj/item/bladed/shortsword/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null + +/obj/item/bladed/polearm/spear/forged + material = /decl/material/solid/metal/iron + hilt_material = null + guard_material = null + pommel_material = null diff --git a/mods/content/blacksmithy/icons/anvil.dmi b/mods/content/blacksmithy/icons/anvil.dmi new file mode 100644 index 000000000000..403390e3251b Binary files /dev/null and b/mods/content/blacksmithy/icons/anvil.dmi differ diff --git a/mods/content/blacksmithy/icons/anvil_crude.dmi b/mods/content/blacksmithy/icons/anvil_crude.dmi new file mode 100644 index 000000000000..1f43be3ed0ff Binary files /dev/null and b/mods/content/blacksmithy/icons/anvil_crude.dmi differ diff --git a/mods/content/blacksmithy/icons/anvil_crude_alt.dmi b/mods/content/blacksmithy/icons/anvil_crude_alt.dmi new file mode 100644 index 000000000000..d3876c4f37fd Binary files /dev/null and b/mods/content/blacksmithy/icons/anvil_crude_alt.dmi differ diff --git a/mods/content/blacksmithy/icons/anvil_improvised.dmi b/mods/content/blacksmithy/icons/anvil_improvised.dmi new file mode 100644 index 000000000000..a80b2d7a06b0 Binary files /dev/null and b/mods/content/blacksmithy/icons/anvil_improvised.dmi differ diff --git a/mods/content/blacksmithy/icons/billet.dmi b/mods/content/blacksmithy/icons/billet.dmi new file mode 100644 index 000000000000..1b841d667a04 Binary files /dev/null and b/mods/content/blacksmithy/icons/billet.dmi differ diff --git a/mods/content/blacksmithy/icons/forge.dmi b/mods/content/blacksmithy/icons/forge.dmi new file mode 100644 index 000000000000..452def1aa589 Binary files /dev/null and b/mods/content/blacksmithy/icons/forge.dmi differ diff --git a/mods/content/blacksmithy/icons/tongs.dmi b/mods/content/blacksmithy/icons/tongs.dmi new file mode 100644 index 000000000000..72764d913b32 Binary files /dev/null and b/mods/content/blacksmithy/icons/tongs.dmi differ diff --git a/mods/content/blacksmithy/tongs.dm b/mods/content/blacksmithy/tongs.dm new file mode 100644 index 000000000000..173ccef04688 --- /dev/null +++ b/mods/content/blacksmithy/tongs.dm @@ -0,0 +1,33 @@ +/obj/item/tongs + name = "tongs" + desc = "Long-handled grippers well suited to fishing white-hot iron out of a forge fire." + icon = 'mods/content/blacksmithy/icons/tongs.dmi' + icon_state = ICON_STATE_WORLD + material = /decl/material/solid/metal/iron + color = /decl/material/solid/metal/iron::color + obj_flags = OBJ_FLAG_INSULATED_HANDLE + material_alteration = MAT_FLAG_ALTERATION_ALL + var/obj/item/holding_bar + +/obj/item/tongs/on_update_icon() + . = ..() + if(holding_bar) + // Note, not get_color(); heat color is temporarily applied over the top of base color. + add_overlay(overlay_image(icon, "[icon_state]-bar", holding_bar.color, RESET_COLOR)) + +/obj/item/tongs/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing) + if(overlay && holding_bar) + var/check_state = "[overlay.icon_state]-bar" + if(check_state_in_icon(check_state, overlay.icon)) + overlay.overlays += overlay_image(overlay.icon, check_state, holding_bar.get_color(), RESET_COLOR) + . = ..() + +/obj/item/tongs/Exited(atom/movable/AM, atom/new_loc) + . = ..() + if(AM == holding_bar) + holding_bar = null + update_icon() + +/obj/item/tongs/Destroy() + QDEL_NULL(holding_bar) + . = ..() diff --git a/mods/content/blob/_blob.dm b/mods/content/blob/_blob.dm new file mode 100644 index 000000000000..5e682ee90c30 --- /dev/null +++ b/mods/content/blob/_blob.dm @@ -0,0 +1,2 @@ +/decl/modpack/blob + name = "Blob Content" \ No newline at end of file diff --git a/mods/content/blob/_blob.dme b/mods/content/blob/_blob.dme new file mode 100644 index 000000000000..58d134cd575f --- /dev/null +++ b/mods/content/blob/_blob.dme @@ -0,0 +1,13 @@ +#ifndef CONTENT_PACK_BLOB +#define CONTENT_PACK_BLOB +// BEGIN_INCLUDE +#include "_blob.dm" +#include "blob_act.dm" +#include "blob_effect.dm" +#include "blob_event.dm" +#include "blob_follow.dm" +#include "blob_grenade_damage.dm" +#include "blob_samples.dm" +#include "blob_subsystem.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/blob/blob_act.dm b/mods/content/blob/blob_act.dm new file mode 100644 index 000000000000..ef291e9dfd65 --- /dev/null +++ b/mods/content/blob/blob_act.dm @@ -0,0 +1,61 @@ +// This file contains blob_act overrides. +// blob_act is called when a blob attacks or tries to expand into a tile. +// blob_act overrides therefore handle atoms being damaged by blobs. + +/// Handles blobs attacking/expanding into this atom. +/// Return TRUE to stop the blob from doing further attacks on this tile. +/atom/proc/blob_act(obj/effect/blob/blob) + return + +/turf/blob_act(obj/effect/blob/blob) + if(!simulated) return FALSE + for(var/atom/movable/movable in contents) + if((. = movable.blob_act())) // stop if one returns TRUE + return + +/turf/space/blob_act(obj/effect/blob/blob) + return // blobs don't attack things in space, for some reason + +/turf/wall/blob_act(obj/effect/blob/blob) + take_damage(80) + return TRUE + +/obj/structure/girder/blob_act(obj/effect/blob/blob) + if(prob(40)) + dismantle_structure() + return TRUE // block further attacks even if we aren't destroyed + +/obj/structure/window/blob_act(obj/effect/blob/blob) + shatter() + return TRUE + +/obj/structure/grille/blob_act(obj/effect/blob/blob) + physically_destroyed() + return TRUE + +/obj/structure/door/blob_act(obj/effect/blob/blob) + if(!density) + return FALSE + explosion_act(2) + return TRUE + +/obj/structure/foamedmetal/blob_act(obj/effect/blob/blob) + physically_destroyed() + return TRUE + +/obj/structure/inflatable/blob_act(obj/effect/blob/blob) + deflate(violent = TRUE) + return TRUE + +/obj/vehicle/blob_act(obj/effect/blob/blob) + explosion_act(2) + return TRUE + +/obj/machinery/camera/blob_act(obj/effect/blob/blob) + take_damage(30) + return TRUE + +/mob/living/blob_act(obj/effect/blob/blob) + if(stat == DEAD) + return FALSE + blob.attack_living(src) \ No newline at end of file diff --git a/mods/content/blob/blob_effect.dm b/mods/content/blob/blob_effect.dm new file mode 100644 index 000000000000..b3e4ecbec3b7 --- /dev/null +++ b/mods/content/blob/blob_effect.dm @@ -0,0 +1,303 @@ +/obj/effect/blob + name = "pulsating mass" + desc = "A pulsating mass of interwoven tendrils." + icon = 'mods/content/blob/icons/blob.dmi' + icon_state = "blob" + light_range = 2 + light_color = BLOB_COLOR_PULS + density = TRUE + opacity = TRUE + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_PRIORITY + + layer = BLOB_SHIELD_LAYER + + max_health = 15 + + var/regen_rate = 2.5 + var/brute_damage_divisor = 4.3 + var/fire_damage_divisor = 1.1 + var/laser_damage_divisor = 2 // Special resist for laser based weapons - Emitters or handheld energy weaponry. Damage is divided by this and THEN by fire_damage_divisor. + var/expandType = /obj/effect/blob + var/secondary_core_growth_chance = 2.5 //% chance to grow a secondary blob core instead of whatever was suposed to grown. Secondary cores are considerably weaker, but still nasty. + var/damage_min = 15 + var/damage_max = 30 + var/pruned = FALSE + var/product = /obj/item/blob_sample/tendril + var/attack_freq = 8 //see proc/attempt_attack; lower is more often, min 1. must be an integet + +/obj/effect/blob/Initialize() + . = ..() + update_icon() + START_PROCESSING(SSblob, src) + +/obj/effect/blob/Destroy() + STOP_PROCESSING(SSblob, src) + . = ..() + +/obj/effect/blob/CanPass(var/atom/movable/mover, var/turf/target, var/height = 0, var/air_group = 0) + if(air_group || height == 0) + return 1 + return 0 + +/obj/effect/blob/explosion_act(var/severity) + SHOULD_CALL_PARENT(FALSE) + take_damage(rand(140 - (severity * 40), 140 - (severity * 20)) / brute_damage_divisor) + +/obj/effect/blob/on_update_icon() + if(current_health > get_max_health() / 2) + icon_state = "blob" + else + icon_state = "blob_damaged" + +/obj/effect/blob/Process(wait, tick) + regen() + if(tick % attack_freq) + return + attempt_attack(global.alldirs) + +/obj/effect/blob/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + current_health -= damage + if(current_health < 0) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + qdel(src) + else + update_icon() + +/obj/effect/blob/proc/regen() + current_health = min(current_health + regen_rate, get_max_health()) + update_icon() + +/// Attempts to expand the blob into the specified turf, damaging objects in the way. +/// Returns FALSE if the expansion was blocked, returns the new blob instance if successful. +/obj/effect/blob/proc/expand(var/turf/target_turf) + if(target_turf.blob_act(src)) // don't expand if blob_act hits anything + return FALSE + + if(!(locate(/obj/effect/blob/core) in range(target_turf, 2)) && prob(secondary_core_growth_chance)) + . = new /obj/effect/blob/core/secondary(target_turf) + else + . = new expandType(target_turf, min(current_health, 30)) + +/obj/effect/blob/proc/do_pulse(var/forceLeft, var/list/dirs) + set waitfor = FALSE + sleep(8) + var/turf/target_turf + var/list/remaining_dirs = dirs.Copy() + while(!target_turf && length(remaining_dirs)) + var/pushDir = pick_n_take(remaining_dirs) + target_turf = get_step_resolving_mimic(src, pushDir) + if(!target_turf) // We're not next to ANYWHERE?! + return + var/obj/effect/blob/other_blob = (locate() in target_turf) + if(!other_blob) + if(prob(current_health)) + expand(target_turf) + return + if(forceLeft) + other_blob.do_pulse(forceLeft - 1, dirs) + +/obj/effect/blob/proc/attack_living(var/mob/living/victim) + if(!victim || victim.stat == DEAD) + return + var/blob_damage = pick(BRUTE, BURN) + victim.visible_message(SPAN_DANGER("A tendril flies out from \the [src] and smashes into \the [victim]!"), SPAN_DANGER("A tendril flies out from \the [src] and smashes into you!")) + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + victim.apply_damage(rand(damage_min, damage_max), blob_damage, used_weapon = "blob tendril") + +/obj/effect/blob/proc/attempt_attack(var/list/dirs) + var/turf/target_turf + var/list/remaining_dirs = dirs.Copy() + while(!target_turf && length(remaining_dirs)) + var/attackDir = pick_n_take(remaining_dirs) + target_turf = get_step_resolving_mimic(src, attackDir) + if(!target_turf) + return + target_turf.blob_act() + +/obj/effect/blob/bullet_act(var/obj/item/projectile/Proj) + if(!Proj) + return + + switch(Proj.atom_damage_type) + if(BRUTE) + take_damage(Proj.damage / brute_damage_divisor, Proj.atom_damage_type) + if(BURN) + take_damage((Proj.damage / laser_damage_divisor) / fire_damage_divisor, Proj.atom_damage_type) + return 0 + +/obj/effect/blob/attackby(var/obj/item/used_item, var/mob/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(src) + playsound(loc, 'sound/effects/attackblob.ogg', 50, 1) + if(IS_WIRECUTTER(used_item)) + if(prob(user.skill_fail_chance(SKILL_SCIENCE, 90, SKILL_EXPERT))) + to_chat(user, SPAN_WARNING("You fail to collect a sample from \the [src].")) + return TRUE + else + if(!pruned) + to_chat(user, SPAN_NOTICE("You collect a sample from \the [src].")) + new product(user.loc) + pruned = TRUE + return TRUE + else + to_chat(user, SPAN_WARNING("\The [src] has already been pruned.")) + return TRUE + + var/damage = 0 + switch(used_item.atom_damage_type) + if(BURN) + damage = (used_item.expend_attack_force(user) / fire_damage_divisor) + if(IS_WELDER(used_item)) + playsound(loc, 'sound/items/Welder.ogg', 100, 1) + if(BRUTE) + damage = (used_item.expend_attack_force(user) / brute_damage_divisor) + + take_damage(damage, used_item.atom_damage_type) + return TRUE + +// TODO: readd weedkiller spray damage, which seems to have been lost at some point + +/obj/effect/blob/core + name = "master nucleus" + desc = "A massive, fragile nucleus guarded by a shield of thick tendrils." + icon_state = "blob_core" + max_health = 225 + damage_min = 30 + damage_max = 40 + expandType = /obj/effect/blob/shield + product = /obj/item/blob_sample/core + + light_color = BLOB_COLOR_CORE + layer = BLOB_CORE_LAYER + + var/blob_may_process = 1 + var/reported_low_damage = FALSE + var/times_to_pulse = 0 + +/* +the master core becomes more vulnereable to damage as it weakens, +but it also becomes more aggressive, and channels more of its energy into regenerating rather than spreading +regen() will cover update_icon() for this proc +*/ +/obj/effect/blob/core/proc/process_core_health() + switch(get_health_percent()) + if(75 to INFINITY) + brute_damage_divisor = 3.5 + fire_damage_divisor = 2.5 + attack_freq = 5 + regen_rate = 2 + times_to_pulse = 4 + if(reported_low_damage) + report_shield_status("high") + if(50 to 74) + brute_damage_divisor = 2.5 + fire_damage_divisor = 2 + attack_freq = 4 + regen_rate = 3 + times_to_pulse = 3 + if(34 to 49) + brute_damage_divisor = 1 + fire_damage_divisor = 1.1 + attack_freq = 3 + regen_rate = 4 + times_to_pulse = 2 + if(-INFINITY to 33) + brute_damage_divisor = 0.5 + fire_damage_divisor = 0.35 + regen_rate = 5 + times_to_pulse = 1 + if(!reported_low_damage) + report_shield_status("low") + +/obj/effect/blob/core/proc/report_shield_status(var/status) + if(status == "low") + visible_message(SPAN_DANGER("\The [src]'s tendril shield fails, leaving the nucleus vulnerable!"), 3) + reported_low_damage = TRUE + if(status == "high") + visible_message(SPAN_NOTICE("\The [src]'s tendril shield seems to have fully reformed."), 3) + reported_low_damage = FALSE + +// Rough icon state changes that reflect the core's current_health +/obj/effect/blob/core/on_update_icon() + switch(get_health_percent()) + if(66 to INFINITY) + icon_state = "blob_core" + if(33 to 66) + icon_state = "blob_node" + if(-INFINITY to 33) + icon_state = "blob_factory" + +/obj/effect/blob/core/Process() + if(!blob_may_process) + return + blob_may_process = 0 + process_core_health() + regen() + for(var/i in 1 to times_to_pulse) + do_pulse(20, global.alldirs) + attempt_attack(global.alldirs) + attempt_attack(global.alldirs) + blob_may_process = 1 + +// Blob has a very small probability of growing these when spreading. These will spread the blob further. +/obj/effect/blob/core/secondary + name = "auxiliary nucleus" + desc = "An interwoven mass of tendrils. A glowing nucleus pulses at its center." + icon_state = "blob_node" + max_health = 65 + regen_rate = 1 + damage_min = 15 + damage_max = 20 + layer = BLOB_NODE_LAYER + product = /obj/item/blob_sample/core/aux + times_to_pulse = 4 + +/obj/effect/blob/core/secondary/process_core_health() + return + +/obj/effect/blob/core/secondary/on_update_icon() + icon_state = (current_health / get_max_health() >= 0.5) ? "blob_node" : "blob_factory" + +/obj/effect/blob/shield + name = "shielding mass" + desc = "A pulsating mass of interwoven tendrils. These seem particularly robust, but not quite as active." + icon_state = "blob_idle" + max_health = 60 + damage_min = 13 + damage_max = 25 + attack_freq = 8 + regen_rate = 4 + expandType = /obj/effect/blob/ravaging + light_color = BLOB_COLOR_SHIELD + +/obj/effect/blob/shield/Initialize() + . = ..() + update_nearby_tiles() + +/obj/effect/blob/shield/Destroy() + set_density(0) + update_nearby_tiles() + return ..() + +/obj/effect/blob/shield/on_update_icon() + var/current_max_health = get_max_health() + if(current_health > current_max_health * 2 / 3) + icon_state = "blob_idle" + else if(current_health > current_max_health / 3) + icon_state = "blob" + else + icon_state = "blob_damaged" + +/obj/effect/blob/shield/CanPass(var/atom/movable/mover, var/turf/target, var/height = 0, var/air_group = 0) + return !density + +/obj/effect/blob/ravaging + name = "ravaging mass" + desc = "A mass of interwoven tendrils. They thrash around haphazardly at anything in reach." + max_health = 10 + damage_min = 27 + damage_max = 36 + attack_freq = 3 + light_color = BLOB_COLOR_RAV + color = "#ffd400" //Temporary, for until they get a new sprite. diff --git a/mods/content/blob/blob_event.dm b/mods/content/blob/blob_event.dm new file mode 100644 index 000000000000..e9cec3d0d377 --- /dev/null +++ b/mods/content/blob/blob_event.dm @@ -0,0 +1,38 @@ +/datum/event/blob + announceWhen = 12 + var/obj/effect/blob/core/Blob + +// Actually add the blob event to the major events container. +/datum/event_container/major/New() + . = ..() + available_events += new /datum/event_meta( + EVENT_LEVEL_MAJOR, + "Blob", + /datum/event/blob, + 0, + list(ASSIGNMENT_ENGINEER = 40), + 1 + ) + +/datum/event/blob/announce() + level_seven_announcement() + +/datum/event/blob/start() + var/turf/T = pick_area_turf_by_flag(AREA_FLAG_MAINTENANCE, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) + if(!T) + log_and_message_admins("Blob failed to find a viable turf.") + kill() + return + + log_and_message_admins("Blob spawned in \the [get_area_name(T)]", location = T) + Blob = new /obj/effect/blob/core(T) + for(var/i in 1 to rand(2, 3)) + Blob.Process() + +/datum/event/blob/tick() + if(!Blob || !Blob.loc) + Blob = null + kill() + return + if(IsMultiple(activeFor, 3)) + Blob.Process() diff --git a/mods/content/blob/blob_follow.dm b/mods/content/blob/blob_follow.dm new file mode 100644 index 000000000000..2264fe173a00 --- /dev/null +++ b/mods/content/blob/blob_follow.dm @@ -0,0 +1,4 @@ +/datum/follow_holder/blob + sort_order = 9 + followed_type = /obj/effect/blob/core + suffix = "Blob" \ No newline at end of file diff --git a/mods/content/blob/blob_grenade_damage.dm b/mods/content/blob/blob_grenade_damage.dm new file mode 100644 index 000000000000..89bcb8b7e3c8 --- /dev/null +++ b/mods/content/blob/blob_grenade_damage.dm @@ -0,0 +1,16 @@ +/obj/item/grenade/smokebomb/detonate() + . = ..() + for(var/obj/effect/blob/B in view(8,src)) + var/damage = round(30/(get_dist(B,src)+1)) + B.current_health -= damage + B.update_icon() + +/obj/item/grenade/flashbang/on_detonate(turf/our_turf) + var/const/BASE_DAMAGE = 30 + // Deals BASE_DAMAGE damage at 0 distance, + // half at 1, 1/3 at 2, 1/4 at 3, and so on. + . = ..() + FOR_DVIEW(var/obj/effect/blob/enemy_blob, 7, our_turf, INVISIBILITY_MAXIMUM) //Blob damage here + var/damage = round(BASE_DAMAGE/(get_dist(enemy_blob, our_turf)+1)) + enemy_blob.take_damage(damage, BURN) + END_FOR_DVIEW \ No newline at end of file diff --git a/mods/content/blob/blob_samples.dm b/mods/content/blob/blob_samples.dm new file mode 100644 index 000000000000..20661f6a4246 --- /dev/null +++ b/mods/content/blob/blob_samples.dm @@ -0,0 +1,58 @@ +/obj/item/blob_sample + abstract_type = /obj/item/blob_sample + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + attack_verb = list("smacked", "smashed", "whipped") + material = /decl/material/solid/organic/plantmatter + +/obj/item/blob_sample/get_heat() + . = max(..(), atom_damage_type == BURN ? 1000 : 0) + +/obj/item/blob_sample/tendril + name = "asteroclast tendril" + desc = "A tendril removed from an asteroclast. It's entirely lifeless." + icon = 'mods/content/blob/icons/blob_tendril.dmi' + var/types_of_tendril = list("solid", "fire") + +/obj/item/blob_sample/tendril/Initialize() + . = ..() + var/tendril_type = pick(types_of_tendril) + switch(tendril_type) + if("solid") + desc = "An incredibly dense, yet flexible, tendril, removed from an asteroclast." + set_base_attack_force(10) + color = COLOR_BRONZE + origin_tech = @'{"materials":2}' + if("fire") + desc = "A tendril removed from an asteroclast. It's hot to the touch." + atom_damage_type = BURN + set_base_attack_force(15) + color = COLOR_AMBER + origin_tech = @'{"powerstorage":2}' + +/obj/item/blob_sample/tendril/afterattack(atom/target, mob/user, proximity) + . = ..() // ensure we can heat things with it if it's a spicy tendril + // don't return on parent success, we want to take damage either way + if(!proximity) + return + if(prob(50)) // we only take damage half the time + return + set_base_attack_force(get_base_attack_force()-1) + if(get_base_attack_force() <= 0) + visible_message(SPAN_NOTICE("\The [src] crumbles apart!")) + user.drop_from_inventory(src) + new /obj/effect/decal/cleanable/ash(src.loc) + qdel(src) + +/obj/item/blob_sample/core + name = "asteroclast nucleus sample" + desc = "A sample taken from an asteroclast's nucleus. It pulses with energy." + icon = 'mods/content/blob/icons/blob_core_sample.dmi' + w_class = ITEM_SIZE_NORMAL + origin_tech = @'{"materials":4,"wormholes":5,"biotech":7}' + +/obj/item/blob_sample/core/aux + name = "asteroclast auxiliary nucleus sample" + desc = "A sample taken from an asteroclast's auxiliary nucleus." + icon = 'mods/content/blob/icons/blob_aux_core_sample.dmi' + origin_tech = @'{"materials":2,"wormholes":3,"biotech":4}' diff --git a/mods/content/blob/blob_subsystem.dm b/mods/content/blob/blob_subsystem.dm new file mode 100644 index 000000000000..c90b507c0baf --- /dev/null +++ b/mods/content/blob/blob_subsystem.dm @@ -0,0 +1,4 @@ +PROCESSING_SUBSYSTEM_DEF(blob) + name = "Blobs" + priority = SS_PRIORITY_BLOB + wait = 5 SECONDS diff --git a/mods/content/blob/icons/blob.dmi b/mods/content/blob/icons/blob.dmi new file mode 100644 index 000000000000..e0ee0f169df4 Binary files /dev/null and b/mods/content/blob/icons/blob.dmi differ diff --git a/mods/content/blob/icons/blob_aux_core_sample.dmi b/mods/content/blob/icons/blob_aux_core_sample.dmi new file mode 100644 index 000000000000..7e3a4de64a7e Binary files /dev/null and b/mods/content/blob/icons/blob_aux_core_sample.dmi differ diff --git a/mods/content/blob/icons/blob_core_sample.dmi b/mods/content/blob/icons/blob_core_sample.dmi new file mode 100644 index 000000000000..cbb1f5b06b3b Binary files /dev/null and b/mods/content/blob/icons/blob_core_sample.dmi differ diff --git a/mods/content/blob/icons/blob_tendril.dmi b/mods/content/blob/icons/blob_tendril.dmi new file mode 100644 index 000000000000..eabc13ddf6ee Binary files /dev/null and b/mods/content/blob/icons/blob_tendril.dmi differ diff --git a/mods/content/breath_holding/_breath_holding.dme b/mods/content/breath_holding/_breath_holding.dme new file mode 100644 index 000000000000..b00488d9cd1e --- /dev/null +++ b/mods/content/breath_holding/_breath_holding.dme @@ -0,0 +1,9 @@ +#ifndef CONTENT_PACK_BREATH_HOLDING +#define CONTENT_PACK_BREATH_HOLDING +// BEGIN_INCLUDE +#include "breath_holding.dm" +#include "living_overrides.dm" +#include "living_verbs.dm" +#include "lung_overrides.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/breath_holding/breath_holding.dm b/mods/content/breath_holding/breath_holding.dm new file mode 100644 index 000000000000..ebed308430a1 --- /dev/null +++ b/mods/content/breath_holding/breath_holding.dm @@ -0,0 +1,3 @@ +/decl/modpack/breath_holding + name = "Breath Holding" + desc = "Adds the ability for some mobs to hold their breath." \ No newline at end of file diff --git a/mods/content/breath_holding/living_overrides.dm b/mods/content/breath_holding/living_overrides.dm new file mode 100644 index 000000000000..862ded3100fb --- /dev/null +++ b/mods/content/breath_holding/living_overrides.dm @@ -0,0 +1,43 @@ +// override to make a held breath take priority +/mob/living/get_breath(obj/item/organ/internal/lungs/lungs) + if(lungs?.holding_breath && lungs.held_breath) + return lungs.held_breath + return ..() + +// override that prevents getting a new breath if we already have one +/mob/living/obtain_new_breath(obj/item/organ/internal/lungs/lungs) + if(lungs?.held_breath) // don't ever take a new breath if we have one held + return null + . = ..() + if(lungs?.holding_breath) // hold our current breath + lungs.held_breath = . + +/mob/living/handle_pre_breath(obj/item/organ/internal/lungs/lungs) + if((. = ..())) // something skipped breathing, so we can't breathe in or out + return + if(!lungs) // can't do any of this without lungs + return + if(stat != CONSCIOUS && lungs.holding_breath) // if you pass out from holding your breath too long, you should start breathing again + lungs.holding_breath = FALSE + // exhale the currently held breath if we're done not holding it anymore + if(lungs.held_breath && !lungs.holding_breath) + handle_post_breath(lungs.held_breath) + +/mob/living/handle_post_breath(datum/gas_mixture/breath) + var/decl/bodytype/root_bodytype = get_bodytype() + if(!root_bodytype?.breathing_organ) + return + var/obj/item/organ/internal/lungs/lungs = get_organ(root_bodytype.breathing_organ, /obj/item/organ/internal/lungs) + if(lungs?.holding_breath) + return // don't exhale if holding a breath + . = ..() // exhale our held breath + if(lungs) + lungs.held_breath = null // clear the old breath + +// OVERRIDE: can't sniff while holding your breath +/mob/living/sniff_verb() + var/obj/item/organ/internal/lungs/breathe_organ = get_organ(get_bodytype().breathing_organ, /obj/item/organ/internal/lungs) + if(breathe_organ?.holding_breath) + to_chat(src, SPAN_WARNING("You can't sniff while holding your breath!")) + return + return ..() diff --git a/mods/content/breath_holding/living_verbs.dm b/mods/content/breath_holding/living_verbs.dm new file mode 100644 index 000000000000..e0af2f35c1b8 --- /dev/null +++ b/mods/content/breath_holding/living_verbs.dm @@ -0,0 +1,9 @@ +/mob/living/proc/hold_breath() + set name = "Hold Breath" + set desc = "Hold your breath, or stop holding your breath." + set category = "IC" + set src = usr + if(!need_breathe()) + return + var/obj/item/organ/internal/lungs/lungs = get_organ(get_bodytype().breathing_organ, /obj/item/organ/internal/lungs) + return lungs?.hold_breath() \ No newline at end of file diff --git a/mods/content/breath_holding/lung_overrides.dm b/mods/content/breath_holding/lung_overrides.dm new file mode 100644 index 000000000000..45215604accb --- /dev/null +++ b/mods/content/breath_holding/lung_overrides.dm @@ -0,0 +1,39 @@ +/obj/item/organ/internal/lungs + var/can_hold_breath = TRUE + /// The breath currently being held. + var/datum/gas_mixture/held_breath = null + /// Whether or not to hold the next breath. If FALSE, any held breath (if it exists) will be exhaled. If TRUE, the next breath will be held. + var/holding_breath = FALSE + +/obj/item/organ/internal/lungs/do_uninstall(in_place, detach, ignore_children) + var/mob/living/prior_owner = owner + if(!(. = ..())) + return + if(istype(prior_owner) && !prior_owner.get_organ(BP_LUNGS)) + prior_owner.verbs -= /mob/living/proc/hold_breath + +/obj/item/organ/internal/lungs/do_install(mob/living/human/target, obj/item/organ/external/affected, in_place) + . = ..() + if(istype(owner) && !QDELETED(owner) && can_hold_breath) + owner.verbs |= /mob/living/proc/hold_breath + +/obj/item/organ/internal/lungs/proc/hold_breath() + if(!can_hold_breath) + if(owner) + owner.verbs -= /mob/living/proc/hold_breath + return + // if there's ever a reason we should allow ownerless breath-holding this will have to be changed + if(!owner || owner.stat != CONSCIOUS) + return + if(!holding_breath) + owner.visible_message(SPAN_WARNING("\The [src] starts holding their breath!"), SPAN_WARNING("You start holding your breath!")) + else + owner.visible_message(SPAN_NOTICE("\The [src] starts breathing again."), SPAN_NOTICE("You stop holding your breath.")) + holding_breath = !holding_breath + owner.try_breathe() // inhale/exhale immediately + +// OVERRIDE: Can't drown while holding your breath +/obj/item/organ/internal/lungs/can_drown() + if(holding_breath && held_breath) + return FALSE + return ..() \ No newline at end of file diff --git a/mods/content/byond_membership/_byond_membership.dm b/mods/content/byond_membership/_byond_membership.dm new file mode 100644 index 000000000000..5dbc59c09d02 --- /dev/null +++ b/mods/content/byond_membership/_byond_membership.dm @@ -0,0 +1,16 @@ +/decl/modpack/byond_membership + name = "BYOND Membership" + var/icon/emblem = icon('mods/content/byond_membership/member_content.dmi', "emblem") + +/decl/modpack/byond_membership/get_membership_perks() + return "OOC emblem" + +/decl/communication_channel/ooc/get_emblem(client/C) + if(C && C.get_byond_membership() && C.get_preference_value(/datum/client_preference/byond_membership/emblem) == PREF_SHOW) + var/decl/modpack/byond_membership/membership = GET_DECL(/decl/modpack/byond_membership) + return "[html_icon(membership.emblem)] " + +/datum/client_preference/byond_membership/emblem + description = "BYOND Membership Emblem" + key = "BYOND_MEMBERSHIP_EMBLEM" + options = list(PREF_SHOW, PREF_HIDE) diff --git a/mods/content/byond_membership/member_content.dmi b/mods/content/byond_membership/member_content.dmi new file mode 100644 index 000000000000..9ff580288d66 Binary files /dev/null and b/mods/content/byond_membership/member_content.dmi differ diff --git a/mods/corporate/_corporate.dm b/mods/content/corporate/_corporate.dm similarity index 100% rename from mods/corporate/_corporate.dm rename to mods/content/corporate/_corporate.dm diff --git a/mods/corporate/_corporate.dme b/mods/content/corporate/_corporate.dme similarity index 86% rename from mods/corporate/_corporate.dme rename to mods/content/corporate/_corporate.dme index ec0504dd6d53..390348d3603d 100644 --- a/mods/corporate/_corporate.dme +++ b/mods/content/corporate/_corporate.dme @@ -15,32 +15,35 @@ #include "clothing\head\ert.dm" #include "clothing\head\helmets.dm" #include "clothing\masks\rubber.dm" -#include "clothing\rigs\ert.dm" #include "clothing\suit\armour.dm" #include "clothing\suit\captain.dm" #include "clothing\suit\hoodies.dm" #include "clothing\suit\jackets.dm" #include "clothing\suit\labcoats.dm" #include "clothing\suit\ponchos.dm" +#include "clothing\under\jumpsuits.dm" #include "clothing\under\security.dm" +#include "clothing\under\shirts.dm" +#include "clothing\under\slacks.dm" #include "clothing\under\uniforms.dm" #include "datum\ai_icons.dm" #include "datum\ai_laws.dm" -#include "datum\appearances.dm" #include "datum\loadout.dm" #include "datum\robolimbs.dm" #include "datum\antagonists\commando.dm" #include "datum\antagonists\deathsquad.dm" #include "datum\antagonists\uplink.dm" #include "effects\landmarks.dm" -#include "items\backpacks.dm" #include "items\badges.dm" #include "items\clutter.dm" #include "items\cups.dm" #include "items\documents.dm" #include "items\medals.dm" +#include "items\random.dm" +#include "items\stamps.dm" #include "items\wristcomp.dm" #include "machines\machines.dm" +#include "random_ruins\exoplanet_ruins\oldpod\oldpod.dm" #include "structures\lockers.dm" // END_INCLUDE #endif diff --git a/mods/corporate/away_sites/lar_maria/lar_maria-1.dmm b/mods/content/corporate/away_sites/lar_maria/lar_maria-1.dmm similarity index 88% rename from mods/corporate/away_sites/lar_maria/lar_maria-1.dmm rename to mods/content/corporate/away_sites/lar_maria/lar_maria-1.dmm index e50c0c521b43..d37f800ad8ed 100644 --- a/mods/corporate/away_sites/lar_maria/lar_maria-1.dmm +++ b/mods/content/corporate/away_sites/lar_maria/lar_maria-1.dmm @@ -11,51 +11,43 @@ /turf/space, /area/space) "ac" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/cells) "ad" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/morgue) "ae" = ( /obj/structure/disposalpipe/segment, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/morgue) "af" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_hallway) "ag" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_main) "ah" = ( /obj/structure/disposalpipe/segment, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_main) "ai" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/pipe/zpipe/up/scrubbers{ - color = "#ff0000"; dir = 4 }, /obj/machinery/atmospherics/pipe/zpipe/up/supply{ - color = "#0000ff"; dir = 4 }, /obj/structure/cable{ - d1 = 16; - d2 = 0; dir = 4; - icon_state = "16-0"; - pixel_y = 0 + icon_state = "16-0" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "aj" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -67,7 +59,7 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "al" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -78,48 +70,43 @@ }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "am" = ( /obj/structure/disposalpipe/trunk{ dir = 1 }, /obj/machinery/disposal, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "an" = ( /obj/structure/closet/crate/trashcart, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "ao" = ( /obj/structure/disposalpipe/segment, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/cells) "ap" = ( /obj/structure/ladder, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "aq" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/obj/effect/landmark/corpse/lar_maria/zhp_guard/dark, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard/dark, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "as" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -129,12 +116,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "at" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -148,12 +132,9 @@ }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "au" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -163,12 +144,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "av" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -178,12 +156,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "aw" = ( /obj/machinery/door/airlock/virology, @@ -195,12 +170,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "ax" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -210,158 +182,151 @@ dir = 10 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "ay" = ( /obj/machinery/smartfridge/chemistry, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "az" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aA" = ( /obj/structure/table/glass, /obj/item/paper, /obj/item/folder/cyan, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aB" = ( /obj/structure/table/glass, /obj/machinery/light{ dir = 1 }, -/obj/item/storage/box/beakers, +/obj/item/box/beakers, /obj/item/chems/spray/cleaner, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aG" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aH" = ( /obj/structure/hygiene/sink{ pixel_y = 20 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aI" = ( /obj/structure/disposalpipe/trunk{ dir = 1 }, /obj/machinery/disposal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aJ" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aK" = ( /obj/structure/bed, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aL" = ( /obj/structure/closet/secure_closet/personal/patient, -/turf/simulated/floor/tiled/white, +/obj/random/contraband{ + spawn_nothing_percentage = 80 + }, +/obj/random/maintenance/medical{ + spawn_nothing_percentage = 70 + }, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aM" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "aN" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/morgue) "aO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "aP" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aQ" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aR" = ( /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aT" = ( /obj/machinery/door/window/westleft, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "aU" = ( /obj/structure/bed/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "aV" = ( /obj/structure/bed/padded, -/obj/item/contraband/poster, -/turf/simulated/floor/tiled, +/obj/item/poster, +/turf/floor/tiled, /area/lar_maria/cells) "aW" = ( /obj/structure/bed/padded, -/obj/effect/landmark/corpse/lar_maria/test_subject, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/corpse/lar_maria/test_subject, +/turf/floor/tiled, /area/lar_maria/cells) "aX" = ( /obj/structure/bed/padded, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "aY" = ( /obj/structure/bed/padded, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "aZ" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "ba" = ( /obj/structure/disposalpipe/trunk{ @@ -369,152 +334,140 @@ }, /obj/machinery/disposal, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bb" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bc" = ( -/obj/effect/landmark/corpse/lar_maria/test_subject, -/turf/simulated/floor/plating, +/obj/abstract/landmark/corpse/lar_maria/test_subject, +/turf/floor/plating, /area/lar_maria/cells) "bd" = ( /obj/machinery/door/window/eastright, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "be" = ( /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bf" = ( /obj/machinery/door/window/westleft, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bg" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bh" = ( /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bi" = ( /obj/structure/morgue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "bj" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "bk" = ( /obj/structure/morgue{ - icon_state = "morgue1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "bl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "bm" = ( /obj/structure/window/reinforced, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bn" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/door/window/northleft, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bo" = ( /obj/structure/table/glass, /obj/item/paper_bin, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bp" = ( -/obj/effect/landmark/corpse/lar_maria/virologist_female, +/obj/abstract/landmark/corpse/lar_maria/virologist_female, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bq" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "br" = ( /obj/structure/table/glass, /obj/item/paper, /obj/item/pen/blue, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bs" = ( /obj/structure/table/glass, /obj/item/paper/lar_maria/note_4, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bt" = ( /obj/structure/table/glass, /obj/item/flashlight/pen, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bu" = ( /obj/structure/closet/crate/freezer, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bv" = ( /obj/structure/bed, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bw" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bx" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "by" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -523,9 +476,9 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bA" = ( /obj/machinery/door/airlock/security, @@ -538,10 +491,9 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -550,45 +502,42 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bC" = ( /obj/structure/mattress/dirty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bD" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bE" = ( /obj/structure/mattress/dirty, -/obj/effect/landmark/corpse/lar_maria/test_subject, -/turf/simulated/floor/plating, +/obj/abstract/landmark/corpse/lar_maria/test_subject, +/turf/floor/plating, /area/lar_maria/cells) "bF" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bG" = ( /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "bH" = ( /obj/structure/window/reinforced, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -597,104 +546,105 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bJ" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, /obj/structure/table/glass, -/obj/item/storage/box/masks, -/obj/item/storage/box/gloves, +/obj/item/box/masks, +/obj/item/box/gloves, /obj/item/chems/spray/antiseptic, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bK" = ( /obj/structure/table/glass, /obj/item/folder/cyan, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bL" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bM" = ( /obj/structure/table/glass, /obj/item/paper, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bN" = ( -/obj/structure/bed/chair/office/dark{ +/obj/structure/chair/office/dark{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bO" = ( /obj/structure/table/glass, -/turf/simulated/floor/tiled/white, +/obj/random/medical, +/obj/random/medical, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "bQ" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bR" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bS" = ( /obj/structure/table/steel_reinforced, /obj/item/newspaper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bT" = ( /obj/machinery/light, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bU" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/tiled, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/tiled, /area/lar_maria/cells) "bV" = ( /obj/structure/reagent_dispensers/water_cooler, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "bW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "bX" = ( /obj/structure/morgue, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "bY" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "bZ" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "ca" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -704,101 +654,92 @@ /obj/structure/window/reinforced{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cb" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/structure/table/glass, -/obj/item/storage/box/bodybags, -/turf/simulated/floor/tiled/white, +/obj/item/box/bodybags, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cc" = ( /obj/machinery/door/airlock/security, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "cd" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "ce" = ( /obj/machinery/door/window/westleft, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cf" = ( -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "cg" = ( /obj/structure/morgue{ - icon_state = "morgue1"; dir = 8 }, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "ch" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "ci" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cj" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "ck" = ( /obj/machinery/door/window/northright, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cl" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/item/clothing/head/surgery, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cm" = ( /obj/structure/window/reinforced{ @@ -807,19 +748,19 @@ /obj/structure/window/reinforced{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cn" = ( /obj/machinery/door/window/northright, -/obj/item/storage/firstaid/surgery, -/turf/simulated/floor/tiled/white, +/obj/item/firstaid/surgery, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "co" = ( /obj/structure/window/reinforced{ dir = 1 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cp" = ( /obj/structure/window/reinforced{ @@ -829,19 +770,18 @@ dir = 1 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cq" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cr" = ( /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cs" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 @@ -849,75 +789,72 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "ct" = ( /obj/structure/hygiene/toilet{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "cu" = ( /obj/structure/hygiene/toilet{ dir = 4 }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "cv" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, /obj/effect/decal/cleanable/blood, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "cw" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cx" = ( /obj/structure/mattress/dirty, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cy" = ( /obj/structure/crematorium{ - dir = 4 + dir = 4; + id_tag = "lar_maria_crematorium" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "cz" = ( /obj/machinery/button/crematorium{ + id_tag = "lar_maria_crematorium"; pixel_y = -20 }, /obj/effect/decal/cleanable/blood, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "cA" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -926,16 +863,13 @@ dir = 5 }, /mob/living/simple_animal/hostile/lar_maria/virologist/female, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "cB" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -943,17 +877,13 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "cC" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ @@ -962,62 +892,62 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "cD" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /mob/living/simple_animal/hostile/lar_maria/virologist, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cF" = ( /obj/structure/table/glass, -/obj/item/storage/firstaid/surgery, +/obj/item/firstaid/surgery, /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/obj/random/medical, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cG" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/optable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cH" = ( /mob/living/simple_animal/hostile/lar_maria/virologist/female, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cI" = ( /obj/structure/table/glass, /obj/item/scalpel, -/turf/simulated/floor/tiled/white, +/obj/random/medical, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cJ" = ( /obj/structure/window/reinforced{ dir = 4 }, /obj/machinery/optable, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cK" = ( /obj/structure/closet/secure_closet/freezer/fridge, /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cL" = ( /obj/structure/bed, /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_main) "cM" = ( /obj/machinery/light/small{ @@ -1026,47 +956,44 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cN" = ( /obj/machinery/door/airlock/security, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cO" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/sec_wing) "cP" = ( /obj/structure/table/steel_reinforced, /obj/item/deck/cards, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "cQ" = ( /obj/machinery/light{ dir = 1 }, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "cR" = ( -/obj/structure/closet/crate/freezer/rations, +/obj/structure/closet/crate/plastic/rations, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "cS" = ( /obj/structure/closet/emcloset, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "cT" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1075,7 +1002,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1084,7 +1011,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1094,7 +1021,7 @@ dir = 4 }, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cW" = ( /obj/machinery/light/small{ @@ -1106,7 +1033,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1117,15 +1044,14 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cY" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "cZ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1136,44 +1062,40 @@ }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "da" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "db" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "dc" = ( /obj/effect/decal/cleanable/blood, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "dd" = ( /obj/structure/sign/warning/biohazard{ - pixel_x = 0; pixel_y = 32 }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "de" = ( /obj/machinery/door/firedoor, @@ -1182,37 +1104,35 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "CellsBD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "df" = ( /obj/machinery/light/small{ dir = 1 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dg" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dh" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "CellsBD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "di" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dj" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1223,15 +1143,12 @@ }, /obj/random/trash, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dk" = ( /obj/structure/sign/warning/biohazard{ - pixel_x = 0; pixel_y = 32 }, /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -1239,100 +1156,92 @@ }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dl" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dn" = ( /obj/structure/sign/warning/biohazard{ - pixel_x = 0; pixel_y = 32 }, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "do" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dp" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dq" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dr" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_aux) "ds" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dt" = ( /obj/structure/closet/secure_closet/personal/patient, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/obj/random/contraband{ + spawn_nothing_percentage = 80 + }, +/obj/random/maintenance/medical{ + spawn_nothing_percentage = 70 + }, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "du" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dv" = ( /obj/structure/closet/secure_closet/personal/patient, -/turf/simulated/floor/tiled/white, +/obj/random/contraband{ + spawn_nothing_percentage = 80 + }, +/obj/random/maintenance/medical{ + spawn_nothing_percentage = 70 + }, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dw" = ( /obj/machinery/light{ dir = 1 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1341,7 +1250,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "dy" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1350,11 +1259,11 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "dz" = ( /obj/structure/closet/crate/trashcart, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "dA" = ( /obj/machinery/door/airlock/security{ @@ -1363,17 +1272,16 @@ /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "CellsBD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dB" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dC" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dD" = ( /obj/machinery/door/airlock/virology, @@ -1381,15 +1289,14 @@ /obj/effect/decal/cleanable/blood, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "CellsBD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dE" = ( -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1399,7 +1306,7 @@ dir = 5 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1409,7 +1316,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1419,12 +1326,12 @@ dir = 4 }, /mob/living/simple_animal/hostile/lar_maria/guard, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dI" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1433,7 +1340,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1443,48 +1350,46 @@ dir = 10 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dL" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "dM" = ( /obj/structure/bed, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dN" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dO" = ( /obj/structure/bed, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "dP" = ( /obj/structure/bed/padded, /obj/item/deck/tarot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "dQ" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "dR" = ( /obj/structure/bed/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "dS" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/sec_wing) "dT" = ( /obj/structure/bed/padded, /obj/item/clothing/suit/armor/riot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "dU" = ( /obj/structure/hygiene/toilet{ @@ -1494,32 +1399,31 @@ dir = 1 }, /mob/living/simple_animal/hostile/lar_maria/guard/ranged, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/sec_wing) "dW" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; id_tag = "CellsBD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "dX" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_ward) "dY" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/vir_ward) "dZ" = ( /obj/machinery/door/window/southright, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "ea" = ( /obj/machinery/door/window/southright, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eb" = ( /obj/machinery/light/small{ @@ -1527,81 +1431,78 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "ec" = ( /obj/structure/curtain/open/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ed" = ( /obj/structure/curtain/open/bed, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ee" = ( /obj/machinery/door/airlock/security, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/sec_wing) "ef" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/shield/riot, /obj/item/shield/riot, /obj/item/clothing/head/helmet/riot, /obj/item/clothing/suit/armor/riot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eg" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eh" = ( /obj/structure/bed/roller, -/obj/effect/landmark/corpse/lar_maria/test_subject, -/turf/simulated/floor/tiled/white, +/obj/abstract/landmark/corpse/lar_maria/test_subject, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "ei" = ( /obj/structure/bed/roller, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "ej" = ( /obj/structure/bed/roller, /obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 2; level = 2 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "ek" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/firedoor, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "el" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "em" = ( -/obj/item/storage/box/freezer, -/turf/simulated/floor/tiled/white, +/obj/item/box/freezer, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "en" = ( /obj/structure/disposalpipe/trunk{ dir = 4 }, /obj/machinery/disposal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eo" = ( /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_aux) "ep" = ( /obj/structure/lattice, @@ -1615,62 +1516,54 @@ /area/space) "eq" = ( /obj/structure/bed/padded, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "er" = ( /obj/structure/bed/padded, /obj/item/book/manual/chef_recipes, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "es" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/plating, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating, /area/lar_maria/cells) "et" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eu" = ( /obj/structure/table/steel_reinforced, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ frequency = 1305; id_tag = "ZHPcells_access_airlock"; - pixel_x = 0; - pixel_y = 0; - tag_airpump = null; - tag_chamber_sensor = null; tag_exterior_door = "ZHPcells_access_airlock_outer"; - tag_exterior_sensor = null; tag_interior_door = "ZHPcells_access_airlock_inner" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ev" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ew" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/obj/effect/landmark/corpse/lar_maria/zhp_guard, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ex" = ( /obj/structure/table/steel_reinforced, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/button/blast_door{ id_tag = "Cells_ld_BD"; @@ -1696,31 +1589,29 @@ pixel_x = -5; pixel_y = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ey" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -32; - pixel_y = 0 + pixel_x = -32 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "ez" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eA" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eC" = ( /obj/machinery/door/airlock/virology, @@ -1728,7 +1619,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eD" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1736,32 +1627,33 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "eE" = ( /obj/machinery/alarm{ dir = 4; - icon_state = "alarm0"; - pixel_x = -32; - pixel_y = 0 + pixel_x = -32 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eF" = ( /obj/structure/table/glass, -/obj/item/storage/box/syringes, -/turf/simulated/floor/tiled/white, +/obj/item/box/syringes, +/obj/random/medical/lite, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eG" = ( /obj/machinery/light{ dir = 4 }, /obj/structure/table/glass, -/turf/simulated/floor/tiled/white, +/obj/random/medical/lite, +/obj/random/maintenance/medical{ + spawn_nothing_percentage = 70 + }, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1771,53 +1663,63 @@ dir = 6 }, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "eI" = ( /obj/structure/table/steel_reinforced, /obj/item/paper_bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eJ" = ( /obj/structure/table/steel_reinforced, /obj/random/smokes, /obj/item/gun/energy/taser, -/turf/simulated/floor/tiled, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eK" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eL" = ( -/obj/structure/table/rack, -/obj/item/storage/box/handcuffs, -/turf/simulated/floor/tiled, +/obj/structure/rack, +/obj/item/box/handcuffs, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eM" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eN" = ( /obj/structure/closet, -/obj/item/clothing/under/color/red, -/obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/tiled, +/obj/item/clothing/jumpsuit/red, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/obj/random/projectile/sec{ + spawn_nothing_percentage = 40 + }, +/obj/random/projectile/sec{ + spawn_nothing_percentage = 40 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eO" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/effect/landmark/corpse/lar_maria/zhp_guard/dark, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard/dark, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eP" = ( /obj/structure/table/steel_reinforced, @@ -1826,38 +1728,35 @@ /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "eQ" = ( /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eR" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eT" = ( /obj/machinery/door/airlock/virology, @@ -1866,12 +1765,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "eU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -1879,97 +1775,99 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "eV" = ( /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "eX" = ( /obj/machinery/smartfridge/chemistry, /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eY" = ( /obj/structure/table/glass, -/obj/item/storage/box/freezer, -/turf/simulated/floor/tiled/white, +/obj/item/box/freezer, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "eZ" = ( -/obj/structure/bed/chair/office/dark, -/turf/simulated/floor/tiled/white, +/obj/structure/chair/office/dark, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fa" = ( /mob/living/simple_animal/hostile/lar_maria/virologist, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fb" = ( /obj/structure/table/glass, -/obj/item/storage/box/beakers, -/obj/item/storage/box/pillbottles, -/turf/simulated/floor/tiled/white, +/obj/item/box/beakers, +/obj/item/box/pillbottles, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fc" = ( /obj/structure/table/steel_reinforced, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "fd" = ( /obj/machinery/light, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "fe" = ( /obj/structure/table/steel_reinforced, /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/obj/random/medical/lite, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ff" = ( /obj/structure/table/steel_reinforced, /obj/item/chems/spray/pepper, /obj/item/deck/cards, -/turf/simulated/floor/tiled, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fg" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/baton, /obj/item/baton, /obj/item/baton, -/turf/simulated/floor/tiled, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fh" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/head/helmet/ballistic, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fi" = ( /obj/structure/closet, /obj/item/shield/riot, -/obj/item/storage/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunammo, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1977,11 +1875,9 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fk" = ( /obj/structure/table/steel_reinforced, @@ -1990,110 +1886,114 @@ }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "ZHPsec_access_airlock"; - pixel_x = 0; - pixel_y = 0; - tag_airpump = null; - tag_chamber_sensor = null; tag_exterior_door = "ZHPsec__access_airlock_outer"; - tag_exterior_sensor = null; tag_interior_door = "ZHPsec__access_airlock_inner" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fl" = ( /obj/structure/table/steel_reinforced, /obj/machinery/button/blast_door{ id_tag = "Tech_access_BD"; - name = "Communications Access"; - pixel_x = 0; - pixel_y = 0 + name = "Communications Access" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fm" = ( /obj/structure/table/steel_reinforced, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/tiled, +/obj/item/clothing/head/soft/zhp_cap, +/obj/random/smokes, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fn" = ( /obj/structure/table/steel_reinforced, /obj/item/handcuffs, -/turf/simulated/floor/tiled, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fo" = ( /obj/structure/bed/roller, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_ward) "fp" = ( /obj/structure/sign/warning/biohazard{ pixel_x = 32 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "fq" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/obj/machinery/computer/modular, -/turf/simulated/floor/tiled/white, +/obj/machinery/computer/modular{ + dir = 1 + }, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fr" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/table/glass, -/obj/item/storage/box/masks, -/obj/item/storage/box/gloves, -/turf/simulated/floor/tiled/white, +/obj/item/box/masks, +/obj/item/box/gloves, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fs" = ( /obj/structure/table/glass, -/obj/item/storage/box/autoinjectors, -/turf/simulated/floor/tiled/white, +/obj/item/box/autoinjectors, +/obj/random/medical/lite, +/obj/random/maintenance/medical{ + spawn_nothing_percentage = 70 + }, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "ft" = ( /obj/machinery/chem_master, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fu" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/machinery/power/apc{ +/obj/structure/closet/crate/plastic/rations, +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "fv" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/flamethrower/full, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fw" = ( -/obj/structure/table/rack, -/obj/item/storage/box/glowsticks, +/obj/structure/rack, +/obj/item/box/glowsticks, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fx" = ( /obj/structure/closet, -/obj/item/clothing/under/color/red, -/turf/simulated/floor/tiled, +/obj/item/clothing/jumpsuit/red, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fy" = ( /obj/machinery/door/airlock/security, @@ -2101,11 +2001,9 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fz" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2116,20 +2014,15 @@ }, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "fA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2139,12 +2032,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "fB" = ( /obj/machinery/door/airlock/virology, @@ -2156,12 +2046,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2171,31 +2058,24 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -2203,30 +2083,26 @@ }, /obj/structure/window/reinforced{ dir = 1; - health = 1e+006 }, /obj/machinery/door/window/eastright, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "fH" = ( /obj/structure/hygiene/toilet{ dir = 4 }, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "fI" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/cells) "fJ" = ( /obj/machinery/light/small{ @@ -2238,21 +2114,19 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "fK" = ( -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "fL" = ( /obj/machinery/door/blast/regular{ @@ -2268,16 +2142,12 @@ /obj/effect/decal/cleanable/blood, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fM" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2288,17 +2158,12 @@ }, /obj/effect/decal/cleanable/blood, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2308,12 +2173,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2324,17 +2186,13 @@ }, /obj/random/trash, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fP" = ( /obj/structure/reagent_dispensers/peppertank{ @@ -2345,12 +2203,9 @@ }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fQ" = ( /obj/structure/reagent_dispensers/peppertank{ @@ -2361,12 +2216,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fR" = ( /obj/machinery/door/airlock/security, @@ -2378,28 +2230,23 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fS" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fT" = ( /obj/machinery/light{ @@ -2412,17 +2259,13 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2433,12 +2276,9 @@ }, /obj/random/trash, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fV" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2451,16 +2291,12 @@ dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fW" = ( /obj/structure/sign/warning/biohazard{ - pixel_x = 0; pixel_y = 32 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2470,12 +2306,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fX" = ( /obj/machinery/door/airlock/virology{ @@ -2490,16 +2323,12 @@ }, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; id_tag = "CellsBD" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fY" = ( /obj/machinery/light/small{ @@ -2512,12 +2341,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "fZ" = ( /obj/machinery/door/airlock/virology{ @@ -2532,16 +2358,12 @@ }, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; id_tag = "CellsBD" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ga" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2551,21 +2373,17 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "gb" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "gc" = ( /obj/structure/window/reinforced{ @@ -2577,28 +2395,28 @@ /obj/structure/hygiene/shower{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "gd" = ( /mob/living/simple_animal/hostile/lar_maria/virologist/female, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "ge" = ( /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_aux) "gf" = ( /obj/structure/closet/crate, /obj/item/folder/cyan, /obj/item/knife/folding, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gg" = ( /obj/structure/closet, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/orange, +/obj/item/clothing/jumpsuit/orange, +/obj/item/clothing/jumpsuit/orange, /obj/item/clothing/shoes/color/orange, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2606,95 +2424,94 @@ /obj/machinery/button/blast_door{ id_tag = "Cells_acc_BD"; name = "Cells Direct Access"; - pixel_x = -25; - pixel_y = 0 + pixel_x = -25 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "gi" = ( /obj/machinery/door/airlock/security, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "gj" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "gk" = ( /obj/structure/table/steel_reinforced, /obj/item/dice/d12, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "gl" = ( /obj/structure/closet, -/obj/item/clothing/under/color/orange, +/obj/item/clothing/jumpsuit/orange, /obj/item/clothing/shoes/color/orange, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gm" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "gn" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "go" = ( /obj/machinery/vending/coffee, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gp" = ( /obj/machinery/vending/cola, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gq" = ( /obj/machinery/light{ dir = 1 }, /obj/machinery/vending/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gr" = ( /obj/machinery/vending/cigarette, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gs" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "gt" = ( /obj/structure/closet/crate/radiation, /obj/item/stack/cable_coil/random, -/obj/item/stack/material/tritium/ten, +/obj/item/stack/material/aerogel/mapped/tritium/ten, /obj/item/wirecutters, /obj/item/wrench, -/turf/simulated/floor/plating, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tool/power, +/turf/floor/plating, /area/lar_maria/sec_wing) "gu" = ( /obj/machinery/light/small{ dir = 1 }, /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "gv" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 @@ -2702,7 +2519,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "gw" = ( /obj/machinery/door/airlock/virology{ @@ -2710,38 +2527,34 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "VirAccessBD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gx" = ( /mob/living/simple_animal/hostile/lar_maria/guard/ranged, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gy" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "ZHPvirology_access_airlock"; - pixel_x = 0; pixel_y = 25; - tag_airpump = null; - tag_chamber_sensor = null; tag_exterior_door = "ZHPvirology_access_airlock_outer"; tag_exterior_sensor = "ZHPvirology_access_airlock_sensor"; tag_interior_door = "ZHPvirology_access_airlock_inner" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gz" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/vir_access) "gA" = ( /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "gB" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2751,78 +2564,75 @@ dir = 9 }, /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gC" = ( /obj/structure/closet/crate, -/obj/item/contraband/poster, +/obj/item/poster, /obj/item/inflatable_duck, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gD" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "gE" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gF" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gG" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gH" = ( /obj/machinery/power/smes/buildable, -/turf/simulated/floor/plating, +/obj/structure/cable, +/turf/floor/plating, /area/lar_maria/sec_wing) "gI" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/machinery/power/terminal{ dir = 8 }, -/obj/effect/landmark/corpse/lar_maria/zhp_guard, -/turf/simulated/floor/plating, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard, +/turf/floor/plating, /area/lar_maria/sec_wing) "gJ" = ( -/obj/machinery/power/port_gen/pacman/mrs, +/obj/machinery/port_gen/pacman/mrs, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "gK" = ( /obj/machinery/portable_atmospherics/canister/empty/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "gL" = ( -/obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/obj/machinery/suit_cycler/engineering/prepared/atmospheric, +/turf/floor/plating, /area/lar_maria/sec_wing) "gM" = ( /obj/structure/closet/l3closet/security, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/sec_wing) "gN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2831,7 +2641,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "gO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2842,10 +2652,9 @@ }, /obj/machinery/button/access/interior{ id_tag = "ZHPvirology_access_airlock"; - pixel_x = 0; pixel_y = -25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_hallway) "gP" = ( /obj/machinery/door/airlock/virology{ @@ -2859,10 +2668,9 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "VirAccessBD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2871,51 +2679,49 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gR" = ( /obj/effect/decal/cleanable/blood, /obj/machinery/airlock_sensor{ id_tag = "ZHPvirology_access_airlock_sensor"; - pixel_x = 25; - pixel_y = 0 + pixel_x = 25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gS" = ( /obj/structure/bed/padded, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "gT" = ( /obj/structure/bed/padded, /obj/item/newspaper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/cells) "gU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gV" = ( /obj/structure/closet, -/obj/item/clothing/under/color/orange, -/obj/item/clothing/under/color/orange, +/obj/item/clothing/jumpsuit/orange, +/obj/item/clothing/jumpsuit/orange, /obj/item/clothing/shoes/color/orange, /obj/item/clothing/shoes/color/orange, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "gW" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gX" = ( /obj/machinery/alarm{ alarm_id = "misc_research"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gY" = ( /obj/machinery/door/airlock/virology{ @@ -2923,97 +2729,96 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "gZ" = ( /obj/machinery/door/airlock/virology{ id_tag = "ZHPvirology_access_airlock_outer" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ha" = ( /obj/machinery/light/small{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "hb" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "hc" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "hd" = ( -/obj/structure/stairs/south, -/turf/simulated/floor/tiled, +/obj/structure/stairs/long, +/turf/floor/tiled, /area/lar_maria/vir_access) "he" = ( /obj/structure/closet, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hf" = ( /obj/structure/closet, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hg" = ( /obj/structure/closet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hh" = ( /obj/structure/closet, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/tiled, +/obj/item/clothing/head/soft/zhp_cap, +/turf/floor/tiled, /area/lar_maria/vir_access) "hi" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, /obj/random/soap, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hj" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/vir_access) "hk" = ( /obj/structure/hygiene/shower, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hl" = ( /obj/structure/hygiene/shower, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hm" = ( /obj/structure/hygiene/shower, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hn" = ( /obj/structure/closet/l3closet/virology, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ho" = ( /obj/structure/closet/l3closet/virology, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hp" = ( /obj/structure/closet/l3closet/virology, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hq" = ( /obj/structure/sign/warning/biohazard{ @@ -3021,7 +2826,7 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hr" = ( /obj/structure/sign/warning/biohazard{ @@ -3032,7 +2837,7 @@ pixel_x = 25; pixel_y = 15 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hs" = ( /obj/machinery/door/airlock/security, @@ -3040,122 +2845,115 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_ld_BD" }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_dock_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "ht" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, +/obj/structure/chair, +/turf/floor/tiled, /area/lar_maria/vir_access) "hu" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hx" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hA" = ( /obj/structure/closet/crate/trashcart, /obj/item/ashtray/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "hB" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_dock_BD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "hC" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "hD" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/taser, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "hE" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/sign/warning/smoking{ pixel_x = -30 }, /obj/random/smokes, -/obj/item/storage/box/matches, +/obj/item/box/matches, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hF" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hG" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hH" = ( /obj/machinery/door/airlock/virology, /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "VirAccessBD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3166,10 +2964,9 @@ }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hK" = ( /obj/machinery/light, @@ -3179,7 +2976,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3188,7 +2985,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hM" = ( /obj/machinery/door/airlock/virology, @@ -3198,7 +2995,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3208,7 +3005,7 @@ dir = 4 }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hO" = ( /obj/machinery/light/small, @@ -3218,7 +3015,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3227,16 +3024,16 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/effect/landmark/corpse/lar_maria/zhp_guard/dark, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard/dark, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "hQ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hR" = ( /obj/machinery/light, @@ -3244,7 +3041,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3255,10 +3052,9 @@ }, /obj/machinery/alarm{ dir = 1; - icon_state = "alarm0"; pixel_y = -22 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hT" = ( /obj/machinery/door/airlock/virology, @@ -3270,10 +3066,9 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "VirAccessBD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hU" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3282,85 +3077,77 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hV" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, /obj/machinery/light/small{ dir = 8 }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "hW" = ( /obj/structure/table/steel_reinforced, -/obj/item/contraband/poster, -/turf/simulated/floor/plating, +/obj/item/poster, +/turf/floor/plating, /area/lar_maria/cells) "hX" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "hY" = ( /obj/machinery/light{ dir = 8 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, /obj/item/paper/lar_maria/note_7, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "hZ" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ia" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ib" = ( /obj/item/paper/lar_maria/note_8, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ic" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "id" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "ie" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3370,11 +3157,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "if" = ( /obj/machinery/door/airlock/security, @@ -3387,16 +3172,12 @@ }, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "VirAccessBD" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "ig" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3406,51 +3187,39 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ih" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ii" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ij" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ik" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "il" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3461,12 +3230,9 @@ }, /obj/machinery/alarm{ alarm_id = "xenobio4_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "im" = ( /obj/machinery/light{ @@ -3478,7 +3244,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "in" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3487,7 +3253,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "io" = ( /obj/machinery/light/small{ @@ -3499,7 +3265,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "ip" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -3508,7 +3274,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "iq" = ( /obj/machinery/light{ @@ -3520,7 +3286,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "ir" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3531,12 +3297,9 @@ }, /obj/machinery/alarm{ alarm_id = "xenobio1_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "is" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3546,101 +3309,92 @@ dir = 4 }, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "it" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "iu" = ( /obj/machinery/door/airlock/security, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iv" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, /obj/machinery/door/blast/regular/open{ dir = 2; - icon_state = "pdoor0"; id_tag = "VirAccessBD" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iw" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "ix" = ( /obj/effect/decal/cleanable/blood, /mob/living/simple_animal/hostile/lar_maria/test_subject, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "iy" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "iz" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "iA" = ( /obj/structure/table/steel_reinforced, /obj/item/ashtray/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "iB" = ( /obj/structure/table/steel_reinforced, /obj/machinery/embedded_controller/radio/airlock/airlock_controller{ id_tag = "ZHPCells_airlock"; - pixel_x = 0; - pixel_y = 0; tag_airpump = "ZHPCells_pump"; - tag_chamber_sensor = null; tag_exterior_door = "ZHPCells_outer"; - tag_exterior_sensor = null; tag_interior_door = "ZHPCells_inner" }, /obj/machinery/button/blast_door{ id_tag = "Cells_dock_BD"; name = "Cells Dock Lockdown"; - pixel_x = 0; pixel_y = 7 }, -/turf/simulated/floor/tiled, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iC" = ( /obj/structure/table/steel_reinforced, /obj/machinery/button/blast_door{ id_tag = "VirAccessBD"; - name = "Virology Access Lockdown"; - pixel_x = 0; - pixel_y = 0 + name = "Virology Access Lockdown" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iD" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/structure/table/steel_reinforced, /obj/item/gun/energy/taser, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iE" = ( /obj/structure/closet, @@ -3648,28 +3402,28 @@ dir = 1; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "iF" = ( /obj/structure/closet, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "iG" = ( /obj/structure/hygiene/shower{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "iH" = ( /obj/structure/hygiene/shower{ dir = 1 }, -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/vir_access) "iI" = ( /obj/structure/closet/l3closet/virology, @@ -3677,32 +3431,32 @@ dir = 1; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "iJ" = ( /obj/structure/closet/l3closet/virology, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/vir_access) "iK" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/item/gun/energy/taser, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iL" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iM" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /mob/living/simple_animal/hostile/lar_maria/guard, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/sec_wing) "iN" = ( /obj/machinery/door/airlock/external{ @@ -3712,58 +3466,91 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "Cells_dock_BD" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "iO" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 1; id_tag = "ZHPCells_airlock_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "iP" = ( /obj/machinery/door/airlock/external{ id_tag = "ZHPCells_airlock_outer" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/cells) "iQ" = ( -/obj/effect/shuttle_landmark/automatic, +/obj/effect/shuttle_landmark/lar_maria_docking{ + dir = 1 + }, /turf/space, /area/space) "jb" = ( /obj/machinery/atmospherics/valve/shutoff{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "kb" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/valve/shutoff{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/morgue) "lb" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = 25 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, +/area/lar_maria/sec_wing) +"ov" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, +/area/lar_maria/sec_wing) +"qL" = ( +/obj/structure/table/glass, +/obj/item/box/freezer, +/obj/random/medical/lite, +/obj/random/maintenance/medical{ + spawn_nothing_percentage = 70 + }, +/turf/floor/tiled/white, +/area/lar_maria/vir_aux) +"vg" = ( +/obj/structure/table/steel_reinforced, +/obj/random/maintenance/security{ + spawn_nothing_percentage = 50 + }, +/turf/floor/tiled, +/area/lar_maria/sec_wing) +"De" = ( +/obj/random/medical/lite, +/turf/floor/tiled/white, +/area/lar_maria/vir_aux) +"Fl" = ( +/obj/machinery/suit_cycler/medical/prepared, +/turf/floor/plating, +/area/lar_maria/sec_wing) +"Ux" = ( +/obj/machinery/door/airlock/security, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/plating, /area/lar_maria/sec_wing) (1,1,1) = {" @@ -22262,6 +22049,7 @@ gU iN iO iP +iQ aa aa aa @@ -22270,7 +22058,6 @@ aa aa aa aa -iQ aa aa aa @@ -22859,9 +22646,9 @@ cO cO cO cO -hC +vg eK -hC +vg cO iB iK @@ -24873,8 +24660,8 @@ eO fj fy fS -gi -dC +Ux +ov gH cO he @@ -26087,7 +25874,7 @@ cO fN cO dC -gL +Fl cO hk hx @@ -28303,7 +28090,7 @@ du du em ds -eY +qL fq fD ds @@ -29316,7 +29103,7 @@ eG fb ft ds -ds +De dr dr aa diff --git a/mods/corporate/away_sites/lar_maria/lar_maria-2.dmm b/mods/content/corporate/away_sites/lar_maria/lar_maria-2.dmm similarity index 87% rename from mods/corporate/away_sites/lar_maria/lar_maria-2.dmm rename to mods/content/corporate/away_sites/lar_maria/lar_maria-2.dmm index 9ecf1a1b4132..3fa27c6e3b3a 100644 --- a/mods/corporate/away_sites/lar_maria/lar_maria-2.dmm +++ b/mods/content/corporate/away_sites/lar_maria/lar_maria-2.dmm @@ -12,251 +12,167 @@ /turf/space, /area/space) "ad" = ( -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "ae" = ( -/obj/effect/landmark/map_data{ +/obj/abstract/map_data{ height = 2 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "af" = ( /obj/effect/overmap/visitable/sector/lar_maria, -/turf/simulated/floor/reinforced, -/area/space) -"ag" = ( -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable/yellow{ - d2 = 2; - icon_state = "0-2" - }, -/obj/machinery/power/solar{ - id = "ZHSolarsWest" - }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "ah" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/solar_control) "ai" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/obj/machinery/power/solar{ - id = "ZHSolarsEast" - }, -/turf/simulated/floor/reinforced, +/obj/machinery/power/solar, +/turf/floor/reinforced, /area/space) "aj" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "ak" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "al" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "am" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "an" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "ao" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "ap" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/reinforced, -/area/space) -"aq" = ( -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable/yellow, -/obj/machinery/power/solar{ - id = "ZHSolarsWest" - }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "ar" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) -"as" = ( -/obj/machinery/power/solar_control/autostart{ - id = "ZHSolarsWest" - }, -/obj/structure/cable/yellow{ - d2 = 2; - icon_state = "0-2" - }, -/turf/simulated/floor/plating, -/area/lar_maria/solar_control) "au" = ( -/obj/machinery/power/port_gen/pacman/super, -/turf/simulated/floor/plating, +/obj/machinery/port_gen/pacman/super, +/turf/floor/plating, /area/lar_maria/solar_control) "av" = ( /obj/structure/closet/crate/radiation, -/obj/item/stack/material/tritium/fifty, +/obj/item/stack/material/aerogel/mapped/tritium/fifty, /obj/item/stack/cable_coil/orange, /obj/item/wrench, /obj/item/wirecutters, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aw" = ( /obj/structure/closet/crate, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "ax" = ( /obj/structure/closet/crate, /obj/random/tool, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "az" = ( -/obj/machinery/power/solar_control/autostart{ - id = "ZHSolarsEast" - }, +/obj/machinery/power/solar_control/autostart, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aA" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow, -/obj/machinery/power/solar{ - id = "ZHSolarsEast" - }, -/turf/simulated/floor/reinforced, +/obj/machinery/power/solar, +/turf/floor/reinforced, /area/space) "aB" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/obj/machinery/power/tracker{ - id = "ZHSolarsWest" - }, -/turf/simulated/floor/reinforced, +/obj/machinery/power/tracker, +/turf/floor/reinforced, /area/space) "aC" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aD" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aE" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/button/access/exterior{ @@ -264,7 +180,7 @@ pixel_x = 25; pixel_y = 25 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aF" = ( /obj/machinery/door/firedoor, @@ -272,16 +188,12 @@ id_tag = "ZHPWestSolar_outer" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aG" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -300,7 +212,7 @@ tag_exterior_door = "ZHPWestSolar_outer"; tag_interior_door = "ZHPWestSolar_inner" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aH" = ( /obj/machinery/door/firedoor, @@ -308,45 +220,37 @@ id_tag = "ZHPWestSolar_inner" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aI" = ( /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/power/terminal, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/button/access/interior{ id_tag = "ZHPWestSolar"; pixel_x = -25; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aJ" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aK" = ( /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/power/terminal, @@ -359,7 +263,7 @@ pixel_x = 25; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aL" = ( /obj/machinery/door/firedoor, @@ -367,17 +271,13 @@ id_tag = "ZHPEastSolar_inner" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aM" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -397,7 +297,7 @@ id_tag = "ZHPEastSolar_sensor"; pixel_y = 25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aN" = ( /obj/machinery/door/firedoor, @@ -405,27 +305,19 @@ id_tag = "ZHPEastSolar_outer" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aO" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/decal/cleanable/blood, @@ -434,193 +326,147 @@ pixel_x = -25; pixel_y = 25 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aP" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aQ" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aR" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aS" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aT" = ( /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/tracker{ - id = "ZHSolarsEast" - }, -/turf/simulated/floor/reinforced, +/obj/machinery/power/tracker, +/turf/floor/reinforced, /area/space) "aU" = ( /obj/effect/floor_decal/solarpanel, -/obj/machinery/power/solar{ - id = "ZHSolarsWest" - }, +/obj/machinery/power/solar, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aV" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aW" = ( /obj/effect/floor_decal/solarpanel, -/obj/machinery/power/solar{ - id = "ZHSolarsWest" - }, +/obj/machinery/power/solar, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "aX" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aY" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "aZ" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "ba" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bb" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bc" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bd" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/obj/machinery/power/solar{ - id = "ZHSolarsEast" - }, -/turf/simulated/floor/reinforced, +/obj/machinery/power/solar, +/turf/floor/reinforced, /area/space) "be" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, -/obj/machinery/power/solar{ - id = "ZHSolarsEast" - }, -/turf/simulated/floor/reinforced, +/obj/machinery/power/solar, +/turf/floor/reinforced, /area/space) "bf" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "bg" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 6 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -629,7 +475,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bj" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -638,66 +484,60 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bl" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "bn" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bo" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bp" = ( -/obj/effect/landmark/corpse/lar_maria/zhp_guard, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "br" = ( -/obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/obj/machinery/suit_cycler/engineering/prepared/atmospheric, +/turf/floor/plating, /area/lar_maria/solar_control) "bs" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bt" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bu" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/toolbox, /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bv" = ( /obj/machinery/atmospherics/unary/outlet_injector, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "bw" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/library) "bx" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/atmos) "by" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -708,40 +548,32 @@ dir = 1; pixel_y = -25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bz" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bA" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bB" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, @@ -749,51 +581,47 @@ dir = 8 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bC" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/toolbox, /obj/random/smokes, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "bD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/cyan, -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/atmos) "bE" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/dorms) "bF" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/engineering, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bG" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock/engineering, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) -"bH" = ( -/obj/structure/bookcase, -/turf/simulated/floor/tiled, -/area/lar_maria/library) "bI" = ( /obj/structure/bookcase, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "bJ" = ( /obj/machinery/atmospherics/unary/tank/nitrogen{ @@ -802,290 +630,288 @@ /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bK" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bM" = ( /obj/machinery/atmospherics/portables_connector{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bN" = ( /obj/machinery/portable_atmospherics/powered/pump, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bO" = ( /obj/machinery/portable_atmospherics/powered/scrubber, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 + dir = 6; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bR" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bS" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tank, /obj/random/tool, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/cyan{ - dir = 6; - icon_state = "intact" + dir = 6 }, /obj/structure/closet/emcloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/cyan{ - dir = 9; - icon_state = "intact" + dir = 9 }, /obj/structure/closet/firecloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "bV" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "bW" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "bX" = ( /obj/machinery/alarm{ dir = 1; pixel_y = -25 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "bY" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "bZ" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "ca" = ( -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cb" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cc" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cd" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ce" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cf" = ( -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cg" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ch" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "ci" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cj" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "ck" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cl" = ( /obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cm" = ( /obj/machinery/atmospherics/binary/pump{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cn" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "co" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/dorms) "cp" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cq" = ( /obj/machinery/door/airlock, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cr" = ( /obj/structure/bookcase, /obj/item/book/manual/engineering_guide, -/turf/simulated/floor/tiled, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "cs" = ( /obj/structure/bookcase, -/obj/item/book/manual/stasis, -/turf/simulated/floor/tiled, -/area/lar_maria/library) -"ct" = ( -/obj/structure/bookcase, -/turf/simulated/floor/tiled, +/obj/item/book/fluff/stasis, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "cu" = ( /obj/structure/bookcase, /obj/item/book/manual/medical_diagnostics_manual, -/turf/simulated/floor/tiled, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "cv" = ( /obj/structure/bookcase, /obj/item/book/manual/detective, -/turf/simulated/floor/tiled, -/area/lar_maria/library) -"cw" = ( -/obj/structure/bookcase, -/turf/simulated/floor/tiled, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "cx" = ( /obj/structure/bookcase, -/turf/simulated/floor/tiled, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "cy" = ( /obj/structure/bookcase, -/obj/item/book/manual/anomaly_spectroscopy, -/obj/item/book/manual/anomaly_testing, -/turf/simulated/floor/tiled, +/obj/item/book/fluff/anomaly_spectroscopy, +/obj/item/book/fluff/anomaly_testing, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/turf/floor/tiled, /area/lar_maria/library) "cz" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cA" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cB" = ( /obj/machinery/atmospherics/pipe/simple/visible/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cC" = ( /obj/machinery/atmospherics/valve/open, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cD" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/turf/floor/laminate, /area/lar_maria/dorms) "cE" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/smokes, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cF" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/toy, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cG" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/glowsticks, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/box/glowsticks, +/turf/floor/laminate, /area/lar_maria/dorms) "cH" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/smokes, /obj/random/drinkbottle, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cI" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cJ" = ( /obj/structure/window/basic{ dir = 1 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cK" = ( /obj/structure/window/basic{ @@ -1094,19 +920,19 @@ /obj/structure/window/basic{ dir = 1 }, -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cL" = ( /obj/structure/window/basic{ dir = 1 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, /obj/item/pen/red, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cM" = ( /obj/structure/window/basic{ @@ -1115,18 +941,18 @@ /obj/structure/window/basic{ dir = 4 }, -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cN" = ( /obj/structure/window/basic{ dir = 1 }, -/obj/structure/table/standard, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/clothing/head/soft/zhp_cap, +/turf/floor/tiled, /area/lar_maria/library) "cO" = ( /obj/structure/window/basic{ @@ -1135,10 +961,10 @@ /obj/structure/window/basic{ dir = 8 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper/lar_maria/note_2, /obj/item/paper/lar_maria/note_3, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cP" = ( /obj/structure/window/basic{ @@ -1147,95 +973,89 @@ /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "cQ" = ( /obj/machinery/atmospherics/pipe/manifold/visible/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cR" = ( -/obj/machinery/atmospherics/binary/pump{ +/obj/machinery/atmospherics/binary/pump/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cS" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cT" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cU" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cV" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cW" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/cyan{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cX" = ( /obj/machinery/atmospherics/portables_connector{ dir = 8 }, /obj/machinery/portable_atmospherics/canister/empty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "cY" = ( -/obj/structure/bed/chair/comfy/purple{ +/obj/structure/chair/comfy/purple{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "cZ" = ( -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "da" = ( /obj/structure/bookcase/manuals/medical, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "db" = ( -/obj/structure/bed/chair/comfy/black{ +/obj/structure/chair/comfy/black{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dc" = ( /mob/living/simple_animal/hostile/lar_maria/guard/ranged, -/turf/simulated/floor/wood, -/area/lar_maria/dorms) -"dd" = ( -/obj/structure/bookcase, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "de" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "df" = ( /obj/structure/closet, @@ -1243,40 +1063,40 @@ /obj/random/smokes, /obj/random/snack, /obj/random/snack, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dg" = ( /obj/structure/bookcase/manuals/engineering, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dh" = ( /obj/structure/window/basic, /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "di" = ( /obj/structure/window/basic{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dj" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dk" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dl" = ( /obj/machinery/atmospherics/unary/tank/oxygen{ @@ -1285,131 +1105,139 @@ /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dm" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dn" = ( /obj/machinery/atmospherics/omni/mixer{ - dir = 4 + dir = 4; + tag_west = 1; + tag_north = 1; + tag_north_con = 0.79; + tag_west_con = 0.21 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "do" = ( /obj/machinery/atmospherics/pipe/simple/visible/universal{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dp" = ( /obj/machinery/atmospherics/omni/filter{ - dir = 4 + dir = 4; + tag_south = 8; + tag_filter_gas_south = "gas_carbon_dioxide"; + tag_east = 2; + tag_west = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dr" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/cyan, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "ds" = ( /mob/living/simple_animal/hostile/lar_maria/virologist, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dt" = ( /obj/structure/bed/padded, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "du" = ( /obj/machinery/light, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dv" = ( /obj/structure/closet, /obj/random/masks, /obj/random/accessory, /obj/random/smokes, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dw" = ( /obj/random/closet, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dx" = ( /obj/structure/bed/padded, /obj/random/plushie, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dy" = ( /obj/structure/window/basic, /obj/structure/window/basic{ dir = 8 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/folder/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dz" = ( /obj/structure/window/basic, -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, /obj/item/pen/blue, /obj/item/paper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dA" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dB" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dC" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dD" = ( /obj/machinery/atmospherics/binary/oxyregenerator, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dE" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dF" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/floor_decal/industrial/warning{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dG" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dH" = ( /obj/machinery/portable_atmospherics/canister/hydrogen, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dI" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dJ" = ( /obj/structure/window/basic{ @@ -1418,41 +1246,39 @@ /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dK" = ( -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dL" = ( /obj/machinery/photocopier, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dM" = ( -/obj/structure/table/standard, -/obj/machinery/photocopier/faxmachine, +/obj/structure/table, +/obj/machinery/faxmachine/mapped, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/machinery/alarm{ dir = 8; pixel_x = 25; - pixel_y = 0; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "dN" = ( /obj/machinery/atmospherics/pipe/manifold/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dO" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ - dir = 5; - icon_state = "intact" + dir = 5 }, /obj/structure/closet/emcloset, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dP" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ @@ -1462,7 +1288,7 @@ dir = 1; pixel_y = -25 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dQ" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ @@ -1470,16 +1296,12 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dR" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ @@ -1487,246 +1309,234 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dS" = ( -/obj/machinery/power/apc{ - dir = 2; +/obj/machinery/apc{ name = "south bump"; pixel_y = -24 }, /obj/machinery/atmospherics/pipe/manifold/visible/blue, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dT" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ - dir = 9; - icon_state = "intact" + dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dV" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dW" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "dX" = ( /obj/structure/bed/padded, /obj/random/plushie/large, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dY" = ( /obj/structure/closet, /obj/random/loot, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "dZ" = ( /obj/structure/closet, /obj/random/shoes, /obj/random/snack, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "ea" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "eb" = ( /obj/structure/window/basic{ dir = 4 }, -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ec" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/pen/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ed" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/pen/crayon/orange, /obj/item/paper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ee" = ( /obj/structure/window/basic{ dir = 4 }, -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 8 }, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ef" = ( /obj/structure/closet/crate/paper_refill, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "eg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "eh" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "ei" = ( -/obj/structure/bed/chair/comfy/beige, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/beige, +/turf/floor/laminate, /area/lar_maria/dorms) "ej" = ( /obj/machinery/botany, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "ek" = ( -/obj/structure/bed/chair/comfy/brown, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/brown, +/turf/floor/laminate, /area/lar_maria/dorms) "el" = ( -/obj/effect/landmark/corpse/lar_maria/virologist_female, +/obj/abstract/landmark/corpse/lar_maria/virologist_female, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "em" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "en" = ( /obj/structure/closet, /obj/random/loot, /obj/random/accessory, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/wood, +/obj/item/clothing/head/soft/zhp_cap, +/turf/floor/laminate, /area/lar_maria/dorms) "eo" = ( -/obj/structure/bed/chair/comfy/green, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/green, +/turf/floor/laminate, /area/lar_maria/dorms) "ep" = ( /obj/structure/closet, /obj/random/accessory, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "eq" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/head_m) "er" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/head_m) "es" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "et" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/library) "eu" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/office) "ev" = ( /mob/living/simple_animal/hostile/lar_maria/virologist, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/office) "ew" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/office) "ex" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "ey" = ( /obj/structure/bed/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "ez" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eB" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eC" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper_bin, /obj/item/pen/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eD" = ( -/obj/structure/bed/chair/office/light, -/obj/effect/landmark/corpse/lar_maria/virologist_female, +/obj/structure/chair/office/light, +/obj/abstract/landmark/corpse/lar_maria/virologist_female, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eE" = ( -/obj/structure/filingcabinet/chestdrawer, -/turf/simulated/floor/tiled, +/obj/structure/filing_cabinet/chestdrawer, +/turf/floor/tiled, /area/lar_maria/office) "eF" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/handcuffs, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/box/handcuffs, +/turf/floor/laminate, /area/lar_maria/dorms) "eG" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/smokes, /obj/random/snack, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "eH" = ( -/obj/structure/table/woodentable, -/obj/item/storage/box/beakers, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/box/beakers, +/turf/floor/laminate, /area/lar_maria/dorms) "eI" = ( /obj/structure/hygiene/toilet, @@ -1735,7 +1545,7 @@ }, /obj/random/trash, /mob/living/simple_animal/hostile/lar_maria/virologist, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "eJ" = ( /obj/structure/hygiene/toilet, @@ -1743,125 +1553,121 @@ dir = 1 }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "eK" = ( /obj/structure/hygiene/urinal{ pixel_x = -30 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "eL" = ( /obj/machinery/light{ dir = 1 }, /obj/random/trash, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "eN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "eO" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "eP" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/office) "eQ" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/obj/structure/table/standard, -/obj/item/storage/firstaid/surgery, -/turf/simulated/floor/tiled/white, +/obj/structure/table, +/obj/item/firstaid/surgery, +/turf/floor/tiled/white, /area/lar_maria/office) "eR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eT" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eU" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/tiled, +/obj/structure/table/laminate, +/turf/floor/tiled, /area/lar_maria/office) "eV" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eW" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "eX" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "eY" = ( /obj/structure/hygiene/urinal{ pixel_x = -30 }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "eZ" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fb" = ( /obj/machinery/door/airlock/medical, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/office) "fc" = ( /obj/machinery/door/airlock/medical, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fe" = ( /obj/machinery/door/window/southleft, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "ff" = ( /obj/structure/window/basic, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fg" = ( /obj/structure/window/basic, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fh" = ( /obj/machinery/door/firedoor, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fi" = ( /obj/machinery/alarm{ @@ -1869,83 +1675,83 @@ pixel_y = -25 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fj" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fk" = ( /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fl" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fm" = ( /obj/structure/closet, /obj/item/clothing/head/surgery, -/obj/item/clothing/under/rank/medical/scrubs, -/obj/item/clothing/under/rank/medical/scrubs, -/obj/item/clothing/suit/storage/toggle/labcoat, -/obj/item/clothing/suit/storage/toggle/labcoat, +/obj/item/clothing/pants/scrubs, +/obj/item/clothing/pants/scrubs, +/obj/item/clothing/shirt/scrubs, +/obj/item/clothing/shirt/scrubs, +/obj/item/clothing/suit/toggle/labcoat, +/obj/item/clothing/suit/toggle/labcoat, /obj/random/gloves, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fn" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fo" = ( -/obj/structure/bed/chair/office/light, -/turf/simulated/floor/tiled, +/obj/structure/chair/office/light, +/turf/floor/tiled, /area/lar_maria/office) "fp" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/folder/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fq" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled/white, +/obj/structure/table, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fr" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, /obj/random/soap, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fs" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "ft" = ( /obj/machinery/washing_machine, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fu" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1955,11 +1761,9 @@ dir = 5 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fw" = ( /obj/machinery/door/airlock, @@ -1972,12 +1776,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1987,240 +1788,224 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "fy" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "fz" = ( /obj/machinery/light{ dir = 8 }, -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fA" = ( -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fB" = ( -/obj/structure/bed/chair/office/light, +/obj/structure/chair/office/light, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fD" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/pen/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fE" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/lar_maria/office) "fF" = ( -/obj/structure/table/woodentable, -/obj/item/staff/gentcane, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/cane/aluminium, +/turf/floor/laminate, /area/lar_maria/dorms) "fG" = ( -/obj/structure/table/woodentable, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/clothing/head/soft/zhp_cap, +/turf/floor/laminate, /area/lar_maria/dorms) "fH" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/drinkbottle, /obj/random/contraband, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fI" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/toolbox, /obj/item/scalpel, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fJ" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/snack, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fK" = ( /obj/machinery/door/airlock, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "fL" = ( /obj/machinery/light{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "fM" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/gloves, -/turf/simulated/floor/tiled, +/obj/random/medical/lite, +/turf/floor/tiled, /area/lar_maria/office) "fN" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fO" = ( /obj/structure/table/steel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fP" = ( /obj/structure/table/steel, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/obj/random/medical/lite, +/turf/floor/tiled, /area/lar_maria/office) "fQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fR" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fS" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper_bin, /obj/item/paper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fT" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper/lar_maria/note_9, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "fU" = ( /obj/machinery/vending/engivend{ req_access = list() }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fV" = ( /mob/living/simple_animal/hostile/lar_maria/guard, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fW" = ( /obj/structure/bookcase, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fX" = ( /mob/living/simple_animal/hostile/lar_maria/virologist/female, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fY" = ( /obj/structure/closet, /obj/random/handgun, /obj/random/powercell, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "fZ" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "ga" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "gb" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "gc" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "gd" = ( /obj/structure/hygiene/toilet{ dir = 8 }, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "ge" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/head_f) "gf" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "gg" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gh" = ( /obj/machinery/alarm{ dir = 1; pixel_y = -25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gi" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2228,132 +2013,124 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gj" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gk" = ( /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gl" = ( -/obj/structure/bed/chair/office/light{ +/obj/structure/chair/office/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gm" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /obj/machinery/alarm{ dir = 4; - pixel_x = -25; - pixel_y = 0 + pixel_x = -25 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "gn" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/dorms) "go" = ( /obj/structure/bed/padded, -/obj/effect/landmark/corpse/lar_maria/virologist, -/turf/simulated/floor/wood, +/obj/abstract/landmark/corpse/lar_maria/virologist, +/turf/floor/laminate, /area/lar_maria/dorms) "gp" = ( /obj/random/trash, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "gq" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "gr" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "gs" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gt" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) "gu" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/mess_hall) "gv" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/mess_hall) "gw" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/lar_maria/mess_hall) "gx" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/mess_hall) "gy" = ( /obj/structure/closet/athletic_mixed, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) "gz" = ( -/turf/simulated/wall, +/turf/wall, /area/lar_maria/hallway) "gA" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "gB" = ( /obj/structure/closet/l3closet/janitor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "gC" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/trash, -/turf/simulated/floor/plating, +/obj/random/medical/pillbottle, +/turf/floor/plating, /area/lar_maria/hallway) "gD" = ( -/turf/simulated/open, +/turf/open, /area/lar_maria/hallway) "gE" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -2364,31 +2141,28 @@ dir = 8 }, /obj/item/stool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "gF" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "gG" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "gH" = ( /obj/structure/window/basic{ dir = 4 }, /obj/machinery/alarm{ - frequency = 1439; pixel_y = 23; req_access = newlist() }, @@ -2396,326 +2170,305 @@ dir = 8 }, /obj/item/stool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "gI" = ( /obj/machinery/vending/cigarette, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gJ" = ( /obj/machinery/vending/coffee, /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gK" = ( /obj/machinery/vending/games, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gN" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/snack, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gO" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gP" = ( /obj/machinery/light{ dir = 1 }, /obj/machinery/computer/arcade, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gQ" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gR" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/plate, +/obj/item/utensil/fork, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gS" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gT" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "gU" = ( /obj/machinery/door/window/westright, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "gV" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "gW" = ( /obj/structure/hygiene/sink/kitchen{ pixel_y = 25 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "gX" = ( /obj/machinery/alarm{ - frequency = 1439; pixel_y = 23; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "gY" = ( /obj/machinery/door/airlock/freezer, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "gZ" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "ha" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "hb" = ( /obj/structure/closet/crate/trashcart, -/turf/simulated/floor/plating, +/obj/random/trash, +/obj/random/trash, +/obj/random/trash, +/obj/random/useful{ + spawn_nothing_percentage = 70 + }, +/obj/item/book/union_charter{ + dat = "The contents of the book are heavily defaced and nearly illegible." + }, +/turf/floor/plating, /area/lar_maria/hallway) "hc" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "hd" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "he" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/open, +/turf/open, /area/lar_maria/hallway) "hf" = ( /obj/structure/window/basic{ dir = 8 }, /obj/item/stool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hg" = ( /obj/structure/window/basic{ dir = 4 }, /obj/item/stool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hh" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/open, +/turf/open, /area/lar_maria/hallway) "hi" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 8; name = "west bump"; pixel_x = -24 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hj" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hk" = ( /obj/structure/table/marble, /obj/machinery/door/firedoor, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled/white, +/obj/item/utensil/fork, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "hl" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "hm" = ( /obj/machinery/cooker/grill, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "hn" = ( /obj/structure/closet/secure_closet/freezer/meat, /obj/random/snack, /obj/random/snack, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "ho" = ( /obj/structure/closet/secure_closet/freezer/kitchen{ req_access = newlist() }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "hp" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/head_f) "hq" = ( /obj/machinery/light{ dir = 1 }, /mob/living/simple_animal/hostile/lar_maria/virologist/female, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hr" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/soap, /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/machinery/alarm{ - frequency = 1439; pixel_y = 23; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hs" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "ht" = ( /obj/structure/mopbucket, /obj/item/mop, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "hu" = ( -/turf/simulated/floor/plating, -/area/lar_maria/hallway) -"hv" = ( -/obj/machinery/power/apc{ - dir = 4; - name = "east bump"; - pixel_x = 24 - }, -/obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "hw" = ( /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/tiled, +/obj/machinery/apc{ + dir = 8; + name = "west bump"; + pixel_x = -24 + }, +/turf/floor/tiled, /area/lar_maria/hallway) "hx" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hz" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hA" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hB" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/industrial/warning{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hC" = ( /obj/machinery/door/firedoor, @@ -2723,40 +2476,29 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hD" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -2764,106 +2506,96 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hG" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hH" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hI" = ( /obj/structure/table/marble, /obj/machinery/door/firedoor, -/obj/item/kitchen/rollingpin, -/turf/simulated/floor/tiled/white, +/obj/item/rollingpin, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "hJ" = ( /obj/machinery/cooker/fryer, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "hK" = ( /obj/structure/closet/secure_closet/freezer/meat, /obj/random/snack, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "hL" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "hM" = ( /obj/structure/table/marble, /obj/item/chems/glass/beaker, /obj/random/snack, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "hN" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hO" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, /obj/random/soap, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hP" = ( /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "hS" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "hT" = ( -/obj/effect/landmark/corpse/lar_maria/zhp_guard/dark, +/obj/abstract/landmark/corpse/lar_maria/zhp_guard/dark, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hU" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hV" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -2871,13 +2603,13 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "hY" = ( /obj/machinery/door/firedoor, @@ -2885,147 +2617,128 @@ dir = 4 }, /obj/machinery/door/airlock/glass, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "hZ" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "ia" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "ib" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "ic" = ( -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled, +/obj/item/utensil/fork, +/turf/floor/tiled, /area/lar_maria/mess_hall) "id" = ( /obj/structure/table/marble, /obj/machinery/door/firedoor, -/obj/item/chems/food/condiment/flour, -/obj/item/storage/fancy/egg_box, -/turf/simulated/floor/tiled/white, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/yeast, +/obj/item/box/fancy/egg_box, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "ie" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "if" = ( /obj/machinery/cooker/oven, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "ig" = ( /obj/structure/closet/secure_closet/freezer/fridge, /obj/random/snack, /obj/random/snack, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "ih" = ( -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "ii" = ( /obj/machinery/chem_master/condimaster, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "ij" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "ik" = ( /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "il" = ( /obj/structure/closet/athletic_mixed, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "in" = ( -/obj/machinery/power/apc{ +/obj/machinery/apc{ dir = 4; name = "east bump"; pixel_x = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 + icon_state = "0-2" }, /obj/machinery/washing_machine, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "io" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "ip" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "ir" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/alarm{ - frequency = 1439; pixel_y = 23; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "is" = ( /obj/machinery/light{ @@ -3035,12 +2748,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "it" = ( /obj/machinery/door/firedoor, @@ -3048,105 +2758,96 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iu" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iv" = ( /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/random/trash, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iw" = ( /obj/item/paper/lar_maria/note_6, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "ix" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/alarm{ dir = 4; - pixel_x = -25; - pixel_y = 0 + pixel_x = -25 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iz" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/obj/effect/landmark/corpse/lar_maria/virologist, +/obj/abstract/landmark/corpse/lar_maria/virologist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iA" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/paper/lar_maria/note_3, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iB" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/plate, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iC" = ( /obj/structure/table/marble, /obj/machinery/door/firedoor, -/obj/item/trash/plate, -/turf/simulated/floor/tiled/white, +/obj/item/plate, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "iD" = ( -/obj/effect/landmark/corpse/lar_maria/virologist_female, +/obj/abstract/landmark/corpse/lar_maria/virologist_female, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "iE" = ( /obj/structure/table/marble, /obj/machinery/cooker/cereal, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "iF" = ( /obj/structure/closet/secure_closet/freezer/fridge, /obj/random/snack, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "iG" = ( -/obj/structure/kitchenspike, +/obj/structure/meat_hook, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "iH" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/obj/effect/landmark/corpse/lar_maria/test_subject, +/obj/abstract/landmark/corpse/lar_maria/test_subject, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "iI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3156,12 +2857,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "iJ" = ( /obj/machinery/door/airlock, @@ -3173,13 +2872,10 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) "iK" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3187,43 +2883,40 @@ }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/effect/decal/cleanable/blood, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/tiled, +/obj/item/clothing/head/soft/zhp_cap, +/turf/floor/tiled, /area/lar_maria/hallway) "iO" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -3231,18 +2924,18 @@ }, /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iR" = ( /obj/structure/closet/firecloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "iS" = ( /obj/machinery/vending/snack, @@ -3250,85 +2943,81 @@ dir = 1; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iT" = ( /obj/machinery/vending/cola, /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iU" = ( /obj/machinery/vending/fitness, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iV" = ( /obj/machinery/light, /obj/machinery/computer/arcade, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iW" = ( -/obj/structure/table/standard, -/obj/item/clothing/head/soft/lar_maria/zhp_cap, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/clothing/head/soft/zhp_cap, +/turf/floor/tiled, /area/lar_maria/mess_hall) "iX" = ( /obj/machinery/vending/dinnerware, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "iY" = ( /obj/structure/table/marble, /obj/machinery/microwave, /obj/machinery/light, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "iZ" = ( /obj/structure/table/marble, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled/white, +/obj/item/plate, +/obj/item/utensil/fork, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "ja" = ( /obj/structure/table/marble, /obj/item/paper/lar_maria/note_9, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/mess_hall) "jb" = ( /obj/machinery/gibber, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/lar_maria/mess_hall) "jc" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) "jd" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/lar_maria/hallway) "je" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "jf" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/hallway) "jg" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "jh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -3337,16 +3026,17 @@ /obj/machinery/button/access/interior{ id_tag = "ZHPDock_airlock"; pixel_x = 25; - pixel_y = -25 + pixel_y = -25; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "ji" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "ZHPDock_airlock_inner" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "jj" = ( /obj/machinery/door/airlock/external/bolted{ @@ -3354,46 +3044,39 @@ }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "jk" = ( /obj/structure/grille, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/space) -"jl" = ( -/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ - dir = 1; - id_tag = "ZHPDock_airlock_pump" - }, -/turf/simulated/floor/plating, -/area/lar_maria/hallway) "jm" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 1; id_tag = "ZHPDock_airlock_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "jn" = ( /obj/machinery/airlock_sensor{ id_tag = "ZHPDock_airlock_sensor"; - pixel_x = 25; - pixel_y = 0 + pixel_x = 22; + dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "jo" = ( /obj/machinery/door/airlock/external/bolted{ id_tag = "ZHPDock_airlock_outer" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/hallway) "jp" = ( /obj/structure/lattice, /turf/space, /area/space) "jq" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/space) "jr" = ( /obj/machinery/button/access/exterior{ @@ -3401,58 +3084,61 @@ pixel_x = 25; pixel_y = 15 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/space) "kb" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "lb" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "mb" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/zpipe/down/scrubbers{ - color = "#ff0000"; dir = 8 }, /obj/machinery/atmospherics/pipe/zpipe/down/supply{ - color = "#0000ff"; dir = 8 }, /obj/structure/cable{ - d1 = 1; - d2 = 32; - dir = 2; icon_state = "32-1" }, -/turf/simulated/open, +/turf/open, /area/lar_maria/solar_control) "nb" = ( -/obj/structure/dispenser/oxygen, +/obj/structure/tank_rack/oxygen, /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) +"nm" = ( +/obj/structure/bookcase, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/obj/item/book/manual/evaguide, +/turf/floor/tiled, +/area/lar_maria/library) "ob" = ( /obj/structure/ladder, /obj/machinery/light/small{ dir = 4; pixel_y = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/solar_control) "pb" = ( /obj/machinery/atmospherics/binary/pump{ @@ -3461,16 +3147,16 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "qb" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tank, /obj/random/tool, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "rb" = ( /obj/machinery/atmospherics/unary/tank/nitrogen{ @@ -3482,7 +3168,7 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "sb" = ( /obj/machinery/atmospherics/portables_connector{ @@ -3493,72 +3179,122 @@ dir = 4; pixel_y = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "tb" = ( /obj/machinery/atmospherics/binary/pump{ dir = 8 }, /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/lar_maria/atmos) "ub" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, +/area/lar_maria/atmos) +"uf" = ( +/obj/machinery/atmospherics/omni/filter{ + dir = 4; + tag_south = 8; + tag_filter_gas_south = "gas_oxygen"; + tag_east = 2; + tag_west = 1 + }, +/turf/floor/plating, /area/lar_maria/atmos) "vb" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 - }, -/obj/item/storage/mirror{ - pixel_x = 30 + pixel_x = 11 }, /obj/machinery/alarm{ - frequency = 1439; pixel_y = 23; req_access = newlist() }, -/turf/simulated/floor/tiled/white, +/obj/structure/mirror{ + pixel_x = 29; + dir = 8 + }, +/turf/floor/tiled/white, /area/lar_maria/head_m) "wb" = ( /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/obj/item/storage/mirror{ - pixel_x = 30 +/obj/structure/mirror{ + pixel_x = 29; + dir = 8 }, /obj/random/trash, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_m) +"wW" = ( +/obj/machinery/atmospherics/omni/filter{ + dir = 4; + tag_north = 8; + tag_east = 2; + tag_west = 1 + }, +/turf/floor/plating, +/area/lar_maria/atmos) "xb" = ( /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, -/obj/item/storage/mirror{ - pixel_x = -30 +/obj/structure/mirror{ + pixel_x = -29; + dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/lar_maria/head_f) +"xx" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/turf/floor/plating, +/area/lar_maria/atmos) +"Ag" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/red{ + dir = 8 + }, +/turf/floor/plating, +/area/lar_maria/atmos) +"Am" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + id_tag = "ZHPDock"; + tag_airpump = "ZHPEastSolar_pump"; + tag_chamber_sensor = "ZHPEastSolar_sensor"; + tag_exterior_door = "ZHPEastSolar_outer"; + tag_interior_door = "ZHPEastSolar_inner"; + dir = 4; + pixel_x = -22 + }, +/turf/floor/plating, +/area/lar_maria/hallway) "DG" = ( /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/lar_maria/office) +"Kg" = ( +/obj/machinery/suit_cycler/medical/prepared, +/turf/floor/plating, +/area/lar_maria/solar_control) +"NR" = ( +/obj/structure/bookcase, +/obj/random/single/textbook{ + spawn_nothing_percentage = 80 + }, +/obj/item/book/union_charter, +/turf/floor/tiled, +/area/lar_maria/library) (1,1,1) = {" aa @@ -18180,9 +17916,9 @@ aa aa ac ad -ag +ai aj -aq +aA aC aU aU @@ -18382,9 +18118,9 @@ aa aa ac ad -ag +ai ak -aq +aA aD aV aV @@ -18584,9 +18320,9 @@ aa aa ac ad -ag +ai ak -aq +aA aC aW aW @@ -18786,9 +18522,9 @@ aa aa ac ad -ag +ai ak -aq +aA aC ad ad @@ -18988,9 +18724,9 @@ aa aa ac ad -ag +ai ak -aq +aA aC aU aU @@ -19190,9 +18926,9 @@ aa aa ac ad -ag +ai ak -aq +aA aD aV aV @@ -19392,9 +19128,9 @@ aa aa ac ad -ag +ai ak -aq +aA aC aW aW @@ -19594,9 +19330,9 @@ aa aa ac ad -ag +ai ak -aq +aA aC ad ad @@ -19796,13 +19532,13 @@ aa aa ac ad -ag +ai al -aq +aA aC -ag +ai aj -aq +aA ad bw bw @@ -19998,13 +19734,13 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw @@ -20200,17 +19936,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cc cr cJ @@ -20402,17 +20138,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cd cs cK @@ -20604,19 +20340,19 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx ce -ct +cx cL dh cd @@ -20806,17 +20542,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cd cu cM @@ -21008,17 +20744,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cd cv cN @@ -21210,19 +20946,19 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw bI cd -cw +NR cM di cd @@ -21412,17 +21148,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cd ce cd @@ -21614,17 +21350,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cd cd cd @@ -21816,17 +21552,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +nm cf cx cO @@ -22018,17 +21754,17 @@ aa aa ac ad -ag +ai ak -aq +aA aC -ag +ai ak -aq +aA ad bw bw -bH +cx cg cy cP @@ -22854,7 +22590,7 @@ ex eu gC hd -hv +hc hS iq iN @@ -23030,7 +22766,7 @@ ac ad ah ah -as +az aI aX ah @@ -23238,7 +22974,7 @@ aY bg nb br -br +Kg bx bN ci @@ -23669,8 +23405,8 @@ iP je jg ji -jl -hu +jm +Am jo jq aa @@ -23848,10 +23584,10 @@ bA bG bQ ck -bQ cU -cU -bQ +xx +Ag +xx dR bG eA @@ -24050,8 +23786,8 @@ bB bx bR ci -cn cV +cn dp dD dS @@ -24254,7 +23990,7 @@ bS ci cA cn -dp +uf dE dT bx @@ -24456,7 +24192,7 @@ qb cl cB cB -dp +wW dF ub bx @@ -27081,7 +26817,7 @@ bE bZ co cF -dd +fW dw co dY diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria.dm b/mods/content/corporate/away_sites/lar_maria/lar_maria.dm new file mode 100644 index 000000000000..591e68506de3 --- /dev/null +++ b/mods/content/corporate/away_sites/lar_maria/lar_maria.dm @@ -0,0 +1,236 @@ +#include "../../_corporate.dme" +#include "lar_maria_areas.dm" + +/obj/effect/overmap/visitable/sector/lar_maria + name = "Lar Maria space station" + desc = "Sensors detect an orbital station with low energy profile and sporadic life signs." + icon_state = "object" + initial_generic_waypoints = list( + "nav_lar_maria_docking" + ) + +/datum/map_template/ruin/away_site/lar_maria + name = "Lar Maria" + description = "An orbital virus research station." + prefix = "mods/content/corporate/away_sites/" + suffixes = list("lar_maria/lar_maria-1.dmm", "lar_maria/lar_maria-2.dmm") + cost = 2 + area_usage_test_exempted_root_areas = list(/area/lar_maria) + +/obj/effect/shuttle_landmark/lar_maria_docking + name = "docking port" + landmark_tag = "nav_lar_maria_docking" + flags = SLANDMARK_FLAG_REORIENT | SLANDMARK_FLAG_AUTOSET + +///////////////////////////////////crew and prisoners +/obj/abstract/landmark/corpse/lar_maria + eye_colors_per_species = list(/decl/species/human::uid = list(COLOR_RED))//red eyes + skin_tones_per_species = list(/decl/species/human::uid = list(-15)) + facial_styles_per_species = list(/decl/species/human::uid = list(/decl/sprite_accessory/facial_hair/shaved)) + genders_per_species = list(/decl/species/human::uid = list(MALE)) + +/mob/living/simple_animal/hostile/lar_maria + name = "Lar Maria hostile mob" + desc = "You shouldn't see me!" + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light.dmi' + unsuitable_atmos_damage = 15 + environment_smash = 1 + faction = "lar_maria" + status_flags = CANPUSH + base_movement_delay = 2 + natural_weapon = /obj/item/natural_weapon/punch + ai = /datum/mob_controller/aggressive/lar_maria + + var/obj/abstract/landmark/corpse/lar_maria/corpse = null + var/weapon = null + +/datum/mob_controller/aggressive/lar_maria + emote_speech = list("Die!", "Fresh meat!", "Hurr!", "You said help will come!", "I did nothing!", "Eat my fist!", "One for the road!") + speak_chance = 12.5 + emote_hear = list("roars", "giggles", "breathes loudly", "mumbles", "yells something unintelligible") + emote_see = list("cries", "grins insanely", "itches fiercly", "scratches his face", "shakes his fists above his head") + turns_per_wander = 10 + stop_wander_when_pulled = 0 + can_escape_buckles = TRUE + +/mob/living/simple_animal/hostile/lar_maria/death(gibbed) + . = ..() + if(. && !gibbed) + if(corpse) + new corpse (src.loc) + if (weapon) + new weapon(src.loc) + visible_message(SPAN_WARNING("Small shining spores float away from the dying [name]!")) + qdel(src) + +/mob/living/simple_animal/hostile/lar_maria/test_subject + name = "test subject" + desc = "Sick, filthy, angry and probably crazy human in an orange robe." + max_health = 40 + corpse = /obj/abstract/landmark/corpse/lar_maria/test_subject + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_test_subject.dmi' + +/obj/abstract/landmark/corpse/lar_maria/test_subject + name = "dead test subject" + corpse_outfits = list(/decl/outfit/corpse_test_subject) + spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION//no name, no hairs etc. + +/decl/outfit/corpse_test_subject + name = "dead ZHP test subject" + uniform = /obj/item/clothing/jumpsuit/orange + shoes = /obj/item/clothing/shoes/color/orange + +/obj/abstract/landmark/corpse/lar_maria/zhp_guard + name = "dead guard" + corpse_outfits = list(/decl/outfit/corpse_zhp_guard) + skin_tones_per_species = list(/decl/species/human::uid = list(-15)) + +/obj/abstract/landmark/corpse/lar_maria/zhp_guard/dark + skin_tones_per_species = list(/decl/species/human::uid = list(-115)) + +/decl/outfit/corpse_zhp_guard + name = "Dead ZHP guard" + uniform = /obj/item/clothing/jumpsuit/virologist + suit = /obj/item/clothing/suit/armor/pcarrier/light + head = /obj/item/clothing/head/soft/zhp_cap + shoes = /obj/item/clothing/shoes/jackboots/duty + l_ear = /obj/item/radio/headset + +/mob/living/simple_animal/hostile/lar_maria/guard//angry guards armed with batons and shotguns. Still bite + name = "security" + desc = "Guard dressed at Zeng-Hu Pharmaceuticals uniform." + max_health = 60 + natural_weapon = /obj/item/baton + weapon = /obj/item/baton + corpse = /obj/abstract/landmark/corpse/lar_maria/zhp_guard + +/mob/living/simple_animal/hostile/lar_maria/guard/Initialize() + . = ..() + var/skin_color = pick(list("light","dark")) + if(istype(weapon, /obj/item/gun)) + if(skin_color == "dark") + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark_ranged.dmi' + else + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light_ranged.dmi' + else + if(skin_color == "dark") + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark.dmi' + else + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light.dmi' + if (skin_color == "dark") + corpse = /obj/abstract/landmark/corpse/lar_maria/zhp_guard/dark + +/mob/living/simple_animal/hostile/lar_maria/guard/ranged + weapon = /obj/item/gun/projectile/shotgun/pump + projectiletype = /obj/item/projectile/bullet/shotgun/beanbag + +/mob/living/simple_animal/hostile/lar_maria/guard/ranged/has_ranged_attack() + return TRUE + +/obj/item/clothing/head/soft/zhp_cap + name = "Zeng-Hu Pharmaceuticals cap" + icon = 'mods/content/corporate/icons/clothing/head/zhp_cap.dmi' + desc = "A green cap with Zeng-Hu Pharmaceuticals symbol on it." + +/mob/living/simple_animal/hostile/lar_maria/virologist + name = "virologist" + desc = "Virologist dressed at Zeng-Hu Pharmaceuticals uniform." + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_m.dmi' + max_health = 50 + corpse = /obj/abstract/landmark/corpse/lar_maria/virologist + +/obj/abstract/landmark/corpse/lar_maria/virologist + name = "dead virologist" + corpse_outfits = list(/decl/outfit/corpse_zhp_virologist) + +/decl/outfit/corpse_zhp_virologist + name = "Dead male ZHP virologist" + uniform = /obj/item/clothing/jumpsuit/virologist + suit = /obj/item/clothing/suit/toggle/labcoat + shoes = /obj/item/clothing/shoes/color/white + gloves = /obj/item/clothing/gloves/latex/nitrile + head = /obj/item/clothing/head/surgery + mask = /obj/item/clothing/mask/surgical + glasses = /obj/item/clothing/glasses/eyepatch/hud/medical + +/mob/living/simple_animal/hostile/lar_maria/virologist/female + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_f.dmi' + weapon = /obj/item/scalpel + corpse = /obj/abstract/landmark/corpse/lar_maria/virologist_female + +/obj/abstract/landmark/corpse/lar_maria/virologist_female + name = "dead virologist" + corpse_outfits = list(/decl/outfit/corpse_zhp_virologist_female) + hair_styles_per_species = list(/decl/species/human::uid = list(/decl/sprite_accessory/hair/flair)) + hair_colors_per_species = list(/decl/species/human::uid = list("#ae7b48")) + genders_per_species = list(/decl/species/human::uid = list(FEMALE)) + +/decl/outfit/corpse_zhp_virologist_female + name = "Dead female ZHP virologist" + uniform = /obj/item/clothing/jumpsuit/virologist + suit = /obj/item/clothing/suit/toggle/labcoat + shoes = /obj/item/clothing/shoes/color/white + gloves = /obj/item/clothing/gloves/latex/nitrile + mask = /obj/item/clothing/mask/surgical + +////////////////////////////Notes and papers +/obj/item/paper/lar_maria/note_1 + name = "paper note" + info = {" +
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + We received the latest batch of subjects this evening. Evening? Is it even evening? The schedule out here is so fucked in terms of sleep-cycles I forget to even check what time it is sometimes. I'm pretty sure it's evening anyway. Anyway, point is, we got the new guys, and thus far they seem like they fit the criteria pretty well. No family histories of diseases or the like, no current illnesses, prime physical condition, perfect subjects for our work. Tomorrow we start testing out the type 008 Serum. Hell if I know where this stuff's coming from, but it's fascinating. Injected into live subjects, it seems like it has a tendancy to not only cure them of ailments, but actually improve their bodily functions... + "} + +/obj/item/paper/lar_maria/note_2 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + I can't believe it, the type 8 Serum seems to actually have a regenerative effect on the subjects. We actually cut one's arm open during the test and ten minutes later, it had clotted. Fifteen and it was healing, and within two hours it was nothing but a fading scar. This is insanity, and the worst part is, we can't even determine HOW it does it yet. All these samples of the goo and not a damn clue how it works, it's infuriating! I'm going to try some additional tests with this stuff. I've heard it's got all kinds of uses, fuel enhancer, condiment, so on and so forth, even with this minty taste, but we'll see. There's got to be some rhyme or reason to this damned stuff. + "} + +/obj/item/paper/lar_maria/note_3 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + The samples of Type 8 we've got are almost out, but it seems like we're actually onto something major here. We'll need to get more sent over asap. This stuff may well be the key to immortality. We cut off one of the test subject's arms and they just put it back on and it healed in an hour or so to the point it was working fine. It's nothing short of miraculous. + "} + +/obj/item/paper/lar_maria/note_4 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + Tedd, don't get into the cells with the Type 8 subjects anymore, something's off about them the last couple days. They haven't been moving right, and they seem distracted nearly constantly, and not in a normal way. They also look like they're turning kinda... green? One of the other guys says it's probably just a virus or something reacting with it, but I don't know, something seems off. + "} + +/obj/item/paper/lar_maria/note_5 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + This is a reminder to all facility staff, while we may be doing important work for the good of humanity here, our methods are not necessarily one hundred percent legal, and as such you are NOT permitted, as outlined in your contract, to discuss the nature of your work, nor any other related information, with anyone not directly involved with the project without express permission of your facility director. This includes family, friends, local or galactic news outlets and bluenet chat forums. + "} + +/obj/item/paper/lar_maria/note_6 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + Due to the recent incident in the labs involving Type 8 test subject #12 and #33, all research personnel are to refrain from interacting directly with the research subjects involved in serum type 8 testing without the presence of armed guards and full Biohazard protective measures in place. + "} + +/obj/item/paper/lar_maria/note_7 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + Can we get some more diversity in test subjects? I know we're mostly working with undesirables, but criminals and frontier colonists aren't exactly the most varied bunch. We could majorly benefit from having some non-human test subjects, for example. Oooh, or one of those snake things Xynergy's got a monopoly on. + "} + +/obj/item/paper/lar_maria/note_8 + name = "paper note" + info = {"
    Zeng-Hu Pharmaceuticals
    +
    CONFIDENTIAL USE ONLY
    + On a related note, can we get some more female subjects? There's been some discussion about gender related differences in reactions to some of the chemicals we're working on. Testosterone and shit affecting chemical balances or something, I'm not sure, point is, variety. + "} + +/obj/item/paper/lar_maria/note_9 + name = "paper note" + info = "can we get some fresh carp sometime? Or freshish? Or frozen? I just really want carp, ok? I'm willing to pay for it if so." diff --git a/mods/corporate/away_sites/lar_maria/lar_maria_areas.dm b/mods/content/corporate/away_sites/lar_maria/lar_maria_areas.dm similarity index 95% rename from mods/corporate/away_sites/lar_maria/lar_maria_areas.dm rename to mods/content/corporate/away_sites/lar_maria/lar_maria_areas.dm index 0e46fe648785..65115dbaf271 100644 --- a/mods/corporate/away_sites/lar_maria/lar_maria_areas.dm +++ b/mods/content/corporate/away_sites/lar_maria/lar_maria_areas.dm @@ -1,5 +1,5 @@ /area/lar_maria - icon = 'mods/corporate/away_sites/lar_maria/lar_maria_sprites.dmi' + icon = 'mods/content/corporate/away_sites/lar_maria/lar_maria_sprites.dmi' /////////////////////////////Upper level areas /area/lar_maria/solar_control diff --git a/mods/corporate/away_sites/lar_maria/lar_maria_clothing_sprites.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_clothing_sprites.dmi similarity index 100% rename from mods/corporate/away_sites/lar_maria/lar_maria_clothing_sprites.dmi rename to mods/content/corporate/away_sites/lar_maria/lar_maria_clothing_sprites.dmi diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark.dmi new file mode 100644 index 000000000000..9b50e7d8524b Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark_ranged.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark_ranged.dmi new file mode 100644 index 000000000000..9532bd9a1468 Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_dark_ranged.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light.dmi new file mode 100644 index 000000000000..f0436820e618 Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light_ranged.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light_ranged.dmi new file mode 100644 index 000000000000..567e40a078c9 Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_guard_light_ranged.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_sprites.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_sprites.dmi new file mode 100644 index 000000000000..dab95a95e398 Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_sprites.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_test_subject.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_test_subject.dmi new file mode 100644 index 000000000000..7c13b6f2545b Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_test_subject.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_f.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_f.dmi new file mode 100644 index 000000000000..3aa7f1d88f33 Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_f.dmi differ diff --git a/mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_m.dmi b/mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_m.dmi new file mode 100644 index 000000000000..25b802022bd6 Binary files /dev/null and b/mods/content/corporate/away_sites/lar_maria/lar_maria_virologist_m.dmi differ diff --git a/mods/content/corporate/clothing/accessories/armbands.dm b/mods/content/corporate/clothing/accessories/armbands.dm new file mode 100644 index 000000000000..2f309a4167e8 --- /dev/null +++ b/mods/content/corporate/clothing/accessories/armbands.dm @@ -0,0 +1,4 @@ +/obj/item/clothing/armband/whitegreen + name = "corporate armband" + desc = "An armband, worn by the crew to display which department they're assigned to. This one is green and white." + icon = 'mods/content/corporate/icons/clothing/accessories/armband.dmi' diff --git a/mods/content/corporate/clothing/accessories/armour.dm b/mods/content/corporate/clothing/accessories/armour.dm new file mode 100644 index 000000000000..22b81aa1ef52 --- /dev/null +++ b/mods/content/corporate/clothing/accessories/armour.dm @@ -0,0 +1,30 @@ +/obj/item/clothing/armor_attachment/helmcover/corp + name = "corporate helmet cover" + desc = "A fabric cover for armored helmets. This one has corporate colors." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/accessories/helmcover_nt.dmi' + +/obj/item/clothing/armor_attachment/helmcover/corp/pcrc + name = "\improper PCRC helmet cover" + desc = "A fabric cover for armored helmets. This one is colored navy blue and has a tag in the back with the words PROXIMA CENTAURI RISK CONTROL printed in cyan lettering on it." + icon = 'mods/content/corporate/icons/clothing/accessories/helmcover_pcrc.dmi' + +/obj/item/clothing/armor_attachment/helmcover/corp/saare + name = "\improper SAARE helmet cover" + desc = "A fabric cover for armored helmets. This one has SAARE's colors." + icon = 'mods/content/corporate/icons/clothing/accessories/helmcover_saare.dmi' + +/obj/item/clothing/armor_attachment/tag/corp + name = "corporate security tag" + desc = "An armor tag with the words CORPORATE SECURITY printed in bottle green lettering on it." + icon = 'mods/content/corporate/icons/clothing/accessories/nanotag.dmi' + +/obj/item/clothing/armor_attachment/tag/corp/pcrc + name = "\improper PCRC tag" + desc = "An armor tag with the words PROXIMA CENTAURI RISK CONTROL printed in cyan lettering on it." + icon = 'mods/content/corporate/icons/clothing/accessories/pcrctag.dmi' + +/obj/item/clothing/armor_attachment/tag/corp/saare + name = "\improper SAARE tag" + desc = "An armor tag with the acronym SAARE printed in olive-green lettering on it." + icon = 'mods/content/corporate/icons/clothing/accessories/saaretag.dmi' diff --git a/mods/content/corporate/clothing/accessories/jackets.dm b/mods/content/corporate/clothing/accessories/jackets.dm new file mode 100644 index 000000000000..92d8f01d06c2 --- /dev/null +++ b/mods/content/corporate/clothing/accessories/jackets.dm @@ -0,0 +1,19 @@ +/obj/item/clothing/suit/jacket/corp + name = "corporate suit jacket" + desc = "A jacket that the EXO has their executives wear." + icon = 'mods/content/corporate/icons/clothing/accessories/jackets/jacket_tl.dmi' + +/obj/item/clothing/suit/jacket/corp/nanotrasen + name = "\improper NanoTrasen suit jacket" + desc = "A jacket that NanoTrasen has their executives wear." + icon = 'mods/content/corporate/icons/clothing/accessories/jackets/jacket_nt.dmi' + +/obj/item/clothing/suit/jacket/corp/heph + name = "\improper Hephaestus Industries suit jacket" + desc = "A jacket that Hephaestus Industries has their executives wear." + icon = 'mods/content/corporate/icons/clothing/accessories/jackets/jacket_heph.dmi' + +/obj/item/clothing/suit/jacket/corp/zeng + name = "\improper Zeng-Hu suit jacket" + desc = "A jacket that Zeng-Hu has their executives wear." + icon = 'mods/content/corporate/icons/clothing/accessories/jackets/jacket_zeng.dmi' diff --git a/mods/content/corporate/clothing/accessories/ties.dm b/mods/content/corporate/clothing/accessories/ties.dm new file mode 100644 index 000000000000..a8ed8e7220f8 --- /dev/null +++ b/mods/content/corporate/clothing/accessories/ties.dm @@ -0,0 +1,20 @@ +/obj/item/clothing/neck/tie/corp + name = "corporate tie" + desc = "A green neosilk clip-on tie. This one has a clip on it that proudly bears a corporate logo." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/accessories/ties/cliptie.dmi' + +/obj/item/clothing/neck/tie/corp/nanotrasen + name = "\improper NanoTrasen tie" + desc = "A red neosilk clip-on tie. This one has a clip on it that proudly bears the NanoTrasen logo." + icon = 'mods/content/corporate/icons/clothing/accessories/ties/cliptie_nt.dmi' + +/obj/item/clothing/neck/tie/corp/heph + name = "\improper Hephaestus Industries tie" + desc = "A cyan neosilk clip-on tie. This one has a clip on it that proudly bears the Hephaestus Industries logo." + icon = 'mods/content/corporate/icons/clothing/accessories/ties/cliptie_heph.dmi' + +/obj/item/clothing/neck/tie/corp/zeng + name = "\improper Zeng-Hu tie" + desc = "A gold neosilk clip-on tie. This one has a clip on it that proudly bears the Zeng-Hu Pharmaceuticals logo." + icon = 'mods/content/corporate/icons/clothing/accessories/ties/cliptie_zeng.dmi' diff --git a/mods/content/corporate/clothing/accessories/tunics.dm b/mods/content/corporate/clothing/accessories/tunics.dm new file mode 100644 index 000000000000..8f724fa81837 --- /dev/null +++ b/mods/content/corporate/clothing/accessories/tunics.dm @@ -0,0 +1,39 @@ +/obj/item/clothing/shirt/tunic/corp + name = "researcher's tunic" + desc = "A fashionable tunic that EXO provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunic.dmi' + body_parts_covered = SLOT_UPPER_BODY + +/obj/item/clothing/shirt/tunic/corp/nanotrasen + name = "\improper NanoTrasen tunic" + desc = "A fashionable tunic that NanoTrasen provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunic_nt.dmi' + +/obj/item/clothing/shirt/tunic/corp/heph + name = "\improper Hephaestus Industries tunic" + desc = "A fashionable tunic that Hephaestus Industries provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunic_heph.dmi' + +/obj/item/clothing/shirt/tunic/corp/zeng + name = "\improper Zeng-Hu tunic" + desc = "A fashionable tunic that Zeng-Hu provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunic_zeng.dmi' + +/obj/item/clothing/shirt/tunic/corp/exec + name = "executive tunic" + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunicblack.dmi' + +/obj/item/clothing/shirt/tunic/corp/exec/nanotrasen + name = "\improper NanoTrasen executive tunic" + desc = "A fashionable tunic that NanoTrasen provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_nt.dmi' + +/obj/item/clothing/shirt/tunic/corp/exec/heph + name = "\improper Hephaestus Industries executive tunic" + desc = "A fashionable tunic that Hephaestus Industries provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_heph.dmi' + +/obj/item/clothing/shirt/tunic/corp/exec/zeng + name = "\improper Zeng-Hu executive tunic" + desc = "A fashionable tunic that Zeng-Hu provides to their lab workers." + icon = 'mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_zeng.dmi' diff --git a/mods/content/corporate/clothing/head/berets.dm b/mods/content/corporate/clothing/head/berets.dm new file mode 100644 index 000000000000..4a46175d9a57 --- /dev/null +++ b/mods/content/corporate/clothing/head/berets.dm @@ -0,0 +1,49 @@ +/obj/item/clothing/head/beret/corp + name = "corporate security beret" + desc = "A beret with the security insignia emblazoned on it. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/red.dmi' +/obj/item/clothing/head/beret/corp/sec/navy/officer + name = "corporate security officer beret" + desc = "A navy blue beret with an officer's rank emblem. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/officer_navy.dmi' +/obj/item/clothing/head/beret/corp/sec/navy/hos + name = "corporate security commander beret" + desc = "A navy blue beret with a commander's rank emblem. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/hos_navy.dmi' +/obj/item/clothing/head/beret/corp/sec/navy/warden + name = "corporate security warden beret" + desc = "A navy blue beret with a warden's rank emblem. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/warden_navy.dmi' +/obj/item/clothing/head/beret/corp/sec/corporate/officer + name = "corporate security officer beret" + desc = "A corporate black beret with an officer's rank emblem. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/officer.dmi' +/obj/item/clothing/head/beret/corp/sec/corporate/hos + name = "corporate security commander beret" + desc = "A corporate black beret with a commander's rank emblem. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/hos.dmi' +/obj/item/clothing/head/beret/corp/sec/corporate/warden + name = "corporate security warden beret" + desc = "A corporate black beret with a warden's rank emblem. For officers that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/warden.dmi' +/obj/item/clothing/head/beret/corp/centcom/officer + name = "asset protection beret" + desc = "A navy blue beret adorned with the crest of corporate asset protection. For asset protection agents that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/navy.dmi' +/obj/item/clothing/head/beret/corp/centcom/captain + name = "asset protection command beret" + desc = "A white beret adorned with the crest of corporate asset protection. For asset protection leaders that are more inclined towards style than safety." + icon = 'mods/content/corporate/icons/clothing/head/beret/white.dmi' +/obj/item/clothing/head/beret/corp/deathsquad + name = "heavy asset protection beret" + desc = "An armored red beret adorned with the crest of corporate asset protection. Doesn't sacrifice style or safety." + armor = list( + ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_RESISTANT, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + siemens_coefficient = 0.9 diff --git a/mods/content/corporate/clothing/head/caps.dm b/mods/content/corporate/clothing/head/caps.dm new file mode 100644 index 000000000000..ba7a053b6016 --- /dev/null +++ b/mods/content/corporate/clothing/head/caps.dm @@ -0,0 +1,11 @@ +/obj/item/clothing/head/soft/sec/corp + name = "corporate security cap" + desc = "It's a field cap in corporate colors." + icon = 'mods/content/corporate/icons/clothing/head/corpsoft.dmi' + color = null + +/obj/item/clothing/head/soft/sec/corp/guard + name = "corporate security cap" + desc = "It's a field cap in corporate colors." + icon = 'mods/content/corporate/icons/clothing/head/corpsecsoft.dmi' + color = null diff --git a/mods/content/corporate/clothing/head/captain.dm b/mods/content/corporate/clothing/head/captain.dm new file mode 100644 index 000000000000..1be88d96a054 --- /dev/null +++ b/mods/content/corporate/clothing/head/captain.dm @@ -0,0 +1,18 @@ +/obj/item/clothing/head/helmet/space/capspace + name = "space helmet" + icon = 'mods/content/corporate/icons/clothing/head/capspace.dmi' + desc = "A special helmet designed for work in a hazardous, low-pressure environment. Only for the most fashionable of military figureheads." + item_flags = 0 + max_pressure_protection = VOIDSUIT_MAX_PRESSURE + min_pressure_protection = 0 + flags_inv = HIDEEARS|HIDEEYES|BLOCK_HEAD_HAIR + permeability_coefficient = 0.01 + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SMALL + ) \ No newline at end of file diff --git a/mods/content/corporate/clothing/head/ert.dm b/mods/content/corporate/clothing/head/ert.dm new file mode 100644 index 000000000000..6fdd2138a376 --- /dev/null +++ b/mods/content/corporate/clothing/head/ert.dm @@ -0,0 +1,28 @@ +/obj/item/clothing/head/helmet/ert + name = "asset protection command helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has blue highlights." + icon = 'mods/content/corporate/icons/clothing/head/ert/cmd.dmi' + valid_accessory_slots = null + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BIO_MINOR + ) + +//Security +/obj/item/clothing/head/helmet/ert/security + name = "asset protection security helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has red highlights." + icon = 'mods/content/corporate/icons/clothing/head/ert/sec.dmi' +//Engineer +/obj/item/clothing/head/helmet/ert/engineer + name = "asset protection engineering helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has orange highlights." + icon = 'mods/content/corporate/icons/clothing/head/ert/eng.dmi' +//Medical +/obj/item/clothing/head/helmet/ert/medical + name = "asset protection medical helmet" + desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has red and white highlights." + icon = 'mods/content/corporate/icons/clothing/head/ert/med.dmi' diff --git a/mods/content/corporate/clothing/head/helmets.dm b/mods/content/corporate/clothing/head/helmets.dm new file mode 100644 index 000000000000..cf6459306b24 --- /dev/null +++ b/mods/content/corporate/clothing/head/helmets.dm @@ -0,0 +1,20 @@ +/obj/item/clothing/head/helmet/corp + name = "corporate security helmet" + desc = "A helmet with 'CORPORATE SECURITY' printed on the back in red lettering." + +/obj/item/clothing/head/helmet/corp/pcrc + name = "\improper PCRC helmet" + desc = "A helmet with 'PRIVATE SECURITY' printed on the back in cyan lettering." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/head/pcrc.dmi' + +/obj/item/clothing/head/helmet/corp/nt/guard + starting_accessories = list( + /obj/item/clothing/armor_attachment/helmcover/corp + ) + +/obj/item/clothing/head/helmet/corp/nt/pilot + name = "corporate pilot's helmet" + desc = "A corporate pilot's helmet for operating the cockpit in style for a hefty paycheck." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/head/corp_pilot.dmi' diff --git a/mods/content/corporate/clothing/masks/rubber.dm b/mods/content/corporate/clothing/masks/rubber.dm new file mode 100644 index 000000000000..4751f961f708 --- /dev/null +++ b/mods/content/corporate/clothing/masks/rubber.dm @@ -0,0 +1,5 @@ +/obj/item/clothing/mask/rubber/trasen + name = "\improper Jack Trasen mask" + desc = "CEO of NanoTrasen corporation. Perfect for scaring the unionizing children." + visible_name = "Jack Trasen" + icon = 'mods/content/corporate/icons/clothing/mask/rubber_mask.dmi' diff --git a/mods/content/corporate/clothing/outfits.dm b/mods/content/corporate/clothing/outfits.dm new file mode 100644 index 000000000000..3d2d38246627 --- /dev/null +++ b/mods/content/corporate/clothing/outfits.dm @@ -0,0 +1,60 @@ +/decl/outfit/nanotrasen + abstract_type = /decl/outfit/nanotrasen + uniform = /obj/item/clothing/costume/centcom + shoes = /obj/item/clothing/shoes/dress + gloves = /obj/item/clothing/gloves + l_ear = /obj/item/radio/headset/heads/hop + glasses = /obj/item/clothing/glasses/sunglasses + id_slot = slot_wear_id_str + id_type = /obj/item/card/id/centcom/station + pda_slot = slot_r_store_str + pda_type = /obj/item/modular_computer/pda/heads + +/decl/outfit/nanotrasen/representative + name = "Corporate Representative" + belt = /obj/item/clipboard + id_pda_assignment = "Corporate Representative" + +/decl/outfit/nanotrasen/officer + name = "Corporate Officer" + head = /obj/item/clothing/head/beret/corp/centcom/officer + l_ear = /obj/item/radio/headset/heads/captain + belt = /obj/item/gun/energy + id_pda_assignment = "Corporate Officer" + +/decl/outfit/nanotrasen/captain + name = "Corporate Captain" + uniform = /obj/item/clothing/costume/centcom_captain + l_ear = /obj/item/radio/headset/heads/captain + head = /obj/item/clothing/head/beret/corp/centcom/captain + belt = /obj/item/gun/energy + id_pda_assignment = "Corporate Captain" + +/decl/outfit/nanotrasen/commander + name = "Corporate Commander" + head = /obj/item/clothing/head/centhat + mask = /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba + shoes = /obj/item/clothing/shoes/jackboots/swat + uniform = /obj/item/clothing/costume/centcom_captain + suit = /obj/item/clothing/suit/armor/bulletproof + gloves = /obj/item/clothing/gloves/thick/swat + l_ear = /obj/item/radio/headset/heads/captain + glasses = /obj/item/clothing/glasses/eyepatch + l_pocket = /obj/item/flame/fuelled/lighter/zippo + id_pda_assignment = "Corporate Commander" + +/decl/outfit/death_command + name = "Spec Ops - Death commando" + +/decl/outfit/death_command/equip_outfit(mob/living/wearer, assignment, equip_adjustments, datum/job/job, datum/mil_rank/rank) + var/decl/special_role/deathsquad = GET_DECL(/decl/special_role/deathsquad) + deathsquad.equip_role(wearer) + return 1 + +/decl/outfit/syndicate_command + name = "Spec Ops - Syndicate commando" + +/decl/outfit/syndicate_command/equip_outfit(mob/living/wearer, assignment, equip_adjustments, datum/job/job, datum/mil_rank/rank) + var/decl/special_role/commandos = GET_DECL(/decl/special_role/deathsquad/mercenary) + commandos.equip_role(wearer) + return 1 diff --git a/mods/content/corporate/clothing/suit/armour.dm b/mods/content/corporate/clothing/suit/armour.dm new file mode 100644 index 000000000000..fac3a04eef93 --- /dev/null +++ b/mods/content/corporate/clothing/suit/armour.dm @@ -0,0 +1,63 @@ +/obj/item/clothing/suit/armor/pcarrier/nt_light + starting_accessories = list( + /obj/item/clothing/armor_attachment/plate, + /obj/item/clothing/armor_attachment/tag/corp + ) + +/obj/item/clothing/suit/armor/pcarrier/nt_medium + starting_accessories = list( + /obj/item/clothing/armor_attachment/plate/medium, + /obj/item/clothing/webbing/pouches, + /obj/item/clothing/armor_attachment/tag/corp + ) + +/obj/item/clothing/suit/armor/vest/nt + name = "corporate armored vest" + desc = "A synthetic armor vest. This one is marked with a corporate logo." + icon = 'mods/content/corporate/icons/clothing/suit/armor/nt.dmi' + +//Non-hardsuit ERT armor. +//Commander +/obj/item/clothing/suit/armor/vest/ert + name = "asset protection command armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has blue highlights." + icon = 'mods/content/corporate/icons/clothing/suit/armor/ert_cmd.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS + armor = list( + ARMOR_MELEE = ARMOR_MELEE_KNIVES, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_MAJOR, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_PADDED + ) + +//Security +/obj/item/clothing/suit/armor/vest/ert/security + name = "asset protection security armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has red highlights." + icon = 'mods/content/corporate/icons/clothing/suit/armor/ert_sec.dmi' + +//Engineer +/obj/item/clothing/suit/armor/vest/ert/engineer + name = "asset protection engineering armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has orange highlights." + icon = 'mods/content/corporate/icons/clothing/suit/armor/ert_eng.dmi' + +//Medical +/obj/item/clothing/suit/armor/vest/ert/medical + name = "asset protection medical armor" + desc = "A set of armor worn by many corporate and private asset protection forces. Has red and white highlights." + icon = 'mods/content/corporate/icons/clothing/suit/armor/ert_med.dmi' + +/obj/item/clothing/suit/armor/vest/security + name = "security armor" + desc = "An armored vest that protects against some damage. This one has a corporate badge." + icon = 'mods/content/corporate/icons/clothing/suit/armor/sec.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_MINOR + ) + diff --git a/mods/content/corporate/clothing/suit/captain.dm b/mods/content/corporate/clothing/suit/captain.dm new file mode 100644 index 000000000000..55150d96b987 --- /dev/null +++ b/mods/content/corporate/clothing/suit/captain.dm @@ -0,0 +1,29 @@ +/obj/item/clothing/suit/armor/captain + name = "Captain's armor" + desc = "A bulky, heavy-duty piece of exclusive corporate armor. YOU are in charge!" + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/suit/capspace.dmi' + w_class = ITEM_SIZE_HUGE + gas_transfer_coefficient = 0.01 + permeability_coefficient = 0.02 + max_pressure_protection = VOIDSUIT_MAX_PRESSURE + min_pressure_protection = 0 + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_TAIL + allowed = list(/obj/item/tank/emergency, /obj/item/flashlight,/obj/item/gun/energy, /obj/item/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/baton,/obj/item/handcuffs) + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SMALL + ) + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + cold_protection = SLOT_UPPER_BODY | SLOT_LOWER_BODY | SLOT_LEGS | SLOT_FEET | SLOT_ARMS | SLOT_HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.7 + +/obj/item/clothing/suit/armor/captain/Initialize() + . = ..() + LAZYSET(slowdown_per_slot, slot_wear_suit_str, 1.5) diff --git a/mods/content/corporate/clothing/suit/hoodies.dm b/mods/content/corporate/clothing/suit/hoodies.dm new file mode 100644 index 000000000000..4eac95893b29 --- /dev/null +++ b/mods/content/corporate/clothing/suit/hoodies.dm @@ -0,0 +1,6 @@ +/obj/item/clothing/suit/toggle/nt_hoodie // no hood, not actually a hoodie + name = "\improper NanoTrasen hoodie" + desc = "A warm, blue sweatshirt. It proudly bears the NanoTrasen logo on the back. The edges are trimmed with silver." + icon = 'mods/content/corporate/icons/clothing/suit/nt_hoodie.dmi' + min_cold_protection_temperature = T0C - 20 + cold_protection = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS diff --git a/mods/content/corporate/clothing/suit/jackets.dm b/mods/content/corporate/clothing/suit/jackets.dm new file mode 100644 index 000000000000..dae65c2f51bf --- /dev/null +++ b/mods/content/corporate/clothing/suit/jackets.dm @@ -0,0 +1,51 @@ +/obj/item/clothing/suit/jacket/brown/nanotrasen + name = "\improper NanoTrasen leather jacket" + desc = "A brown leather coat. The NanoTrasen logo is proudly displayed on the back." + icon = 'mods/content/corporate/icons/clothing/suit/nt_brown.dmi' + +/obj/item/clothing/suit/jacket/leather/nanotrasen + name = "\improper NanoTrasen black leather jacket" + desc = "A black leather coat. The NanoTrasen logo is proudly displayed on the back." + icon = 'mods/content/corporate/icons/clothing/suit/nt_black.dmi' + +/obj/item/clothing/suit/mbill + name = "shipping jacket" + desc = "A green jacket bearing the logo of Major Bill's Shipping." + icon = 'mods/content/corporate/icons/clothing/suit/mbill.dmi' + storage = /datum/storage/pockets/suit + +/obj/item/clothing/suit/jacket/winter/dais + name = "\improper DAIS winter coat" + icon = 'mods/content/corporate/icons/clothing/suit/dais_coat.dmi' + hood = /obj/item/clothing/head/winterhood/dais + siemens_coefficient = 0.5 + armor = list( + ARMOR_MELEE = ARMOR_MELEE_SMALL, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR + ) + desc = "A hooded winter coat colored blue and white and bearing the logo of Deimos Advanced Information Systems." + +/obj/item/clothing/head/winterhood/dais + icon = 'mods/content/corporate/icons/clothing/head/hood_winter_dais.dmi' + +//Security +/obj/item/clothing/suit/navyofficer + name = "security officer's jacket" + desc = "This jacket is for those special occasions when a security officer actually feels safe." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/suit/navy/officer.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS + +/obj/item/clothing/suit/navywarden + name = "warden's jacket" + desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/suit/navy/warden.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS + +/obj/item/clothing/suit/navyhos + name = "head of security's jacket" + desc = "This piece of clothing was specifically designed for asserting superior authority." + icon_state = ICON_STATE_WORLD + icon = 'mods/content/corporate/icons/clothing/suit/navy/hos.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS \ No newline at end of file diff --git a/mods/content/corporate/clothing/suit/labcoats.dm b/mods/content/corporate/clothing/suit/labcoats.dm new file mode 100644 index 000000000000..440b60108cc9 --- /dev/null +++ b/mods/content/corporate/clothing/suit/labcoats.dm @@ -0,0 +1,42 @@ + +/obj/item/clothing/suit/toggle/labcoat/rd/corp + name = "\improper EXO research director's labcoat" + markings_color = COLOR_BOTTLE_GREEN + +/obj/item/clothing/suit/toggle/labcoat/rd/corp/nanotrasen + name = "\improper NT research director's labcoat" + markings_color = COLOR_NT_RED + +/obj/item/clothing/suit/toggle/labcoat/rd/corp/heph + name = "\improper HI research director's labcoat" + markings_color = COLOR_LUMINOL + +/obj/item/clothing/suit/toggle/labcoat/rd/corp/zeng + name = "\improper Z-H research director's labcoat" + markings_color = COLOR_PALE_YELLOW + +/obj/item/clothing/suit/toggle/labcoat/science/corp/nanotrasen + name = "\improper NanoTrasen labcoat" + markings_color = COLOR_NT_RED + +/obj/item/clothing/suit/toggle/labcoat/science/corp/heph + name = "\improper Hephaestus Industries labcoat" + markings_color = COLOR_LUMINOL + +/obj/item/clothing/suit/toggle/labcoat/science/corp/zeng + name = "\improper Zeng-Hu labcoat" + markings_color = COLOR_PALE_YELLOW + +/obj/item/clothing/suit/toggle/labcoat/science/corp/morpheus + name = "\improper Morpheus Cyberkinetics labcoat" + markings_color = COLOR_SILVER + +/obj/item/clothing/suit/toggle/labcoat/science/corp/dais + name = "\improper DAIS labcoat" + desc = "A labcoat with a the logo of Deimos Advanced Information Systems emblazoned on the back. It has a stylish blue \ + trim and the pockets are reinforced to hold tools. It seems to have an insulated material woven in to prevent static shocks." + markings_color = COLOR_NAVY_BLUE + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MINOR + )//They don't need to protect against the environment very much. + siemens_coefficient = 0.5 //These guys work with electronics. DAIS's labcoats shouldn't conduct very well. diff --git a/mods/content/corporate/clothing/suit/ponchos.dm b/mods/content/corporate/clothing/suit/ponchos.dm new file mode 100644 index 000000000000..17f39ecf2d04 --- /dev/null +++ b/mods/content/corporate/clothing/suit/ponchos.dm @@ -0,0 +1,10 @@ +/obj/item/clothing/suit/poncho/science + name = "science poncho" + desc = "A simple, comfortable cloak without sleeves. This one is white with a few bottle green stripes, corporate colors." + bodytype_equip_flags = null + icon = 'mods/content/corporate/icons/clothing/suit/sci_poncho.dmi' + +/obj/item/clothing/suit/poncho/science/nanotrasen + name = "\improper NanoTrasen poncho" + desc = "A simple, comfortable cloak without sleeves. This one is white with a few red stripes, colors of NanoTrasen. Go NanoTrasen!" + icon = 'mods/content/corporate/icons/clothing/suit/nt_poncho.dmi' diff --git a/mods/content/corporate/clothing/under/jumpsuits.dm b/mods/content/corporate/clothing/under/jumpsuits.dm new file mode 100644 index 000000000000..a4a3a68f7426 --- /dev/null +++ b/mods/content/corporate/clothing/under/jumpsuits.dm @@ -0,0 +1,19 @@ +/obj/item/clothing/jumpsuit/aether + name = "\improper Aether jumpsuit" + desc = "A jumpsuit belonging to Aether Atmospherics and Recycling, a company that supplies recycling and atmospheric systems to colonies." + icon = 'mods/content/corporate/icons/clothing/under/aether.dmi' + +/obj/item/clothing/jumpsuit/focal + name = "\improper Focal Point jumpsuit" + desc = "A jumpsuit belonging to Focal Point Energistics, an engineering corporation." + icon = 'mods/content/corporate/icons/clothing/under/focal.dmi' + +/obj/item/clothing/jumpsuit/hephaestus + name = "\improper Hephaestus jumpsuit" + desc = "A jumpsuit belonging to Hephaestus Industries, a megacorp best known for its arms production." + icon = 'mods/content/corporate/icons/clothing/under/heph.dmi' + +/obj/item/clothing/jumpsuit/wardt + name = "\improper Ward-Takahashi jumpsuit" + desc = "A jumpsuit belonging to Ward-Takahashi, a megacorp in the consumer goods and research market." + icon = 'mods/content/corporate/icons/clothing/under/wardt.dmi' diff --git a/mods/content/corporate/clothing/under/security.dm b/mods/content/corporate/clothing/under/security.dm new file mode 100644 index 000000000000..7a8cde34a777 --- /dev/null +++ b/mods/content/corporate/clothing/under/security.dm @@ -0,0 +1,17 @@ +/obj/item/clothing/jumpsuit/security/corp + icon = 'mods/content/corporate/icons/clothing/under/sec_corporate.dmi' + +/obj/item/clothing/jumpsuit/warden/corp + icon = 'mods/content/corporate/icons/clothing/under/warden_corporate.dmi' + +/obj/item/clothing/jumpsuit/head_of_security/corp + icon = 'mods/content/corporate/icons/clothing/under/hos_corporate.dmi' + +/obj/item/clothing/jumpsuit/pcrc + name = "\improper PCRC uniform" + desc = "A uniform belonging to Proxima Centauri Risk Control, a private security firm." + icon = 'mods/content/corporate/icons/clothing/under/pcrc.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_SMALL + ) + siemens_coefficient = 0.9 diff --git a/mods/content/corporate/clothing/under/shirts.dm b/mods/content/corporate/clothing/under/shirts.dm new file mode 100644 index 000000000000..e9f4575bd62a --- /dev/null +++ b/mods/content/corporate/clothing/under/shirts.dm @@ -0,0 +1,58 @@ +/obj/item/clothing/shirt/polo/corp + name = "\improper EXO polo shirt" + desc = "A fashionable polo shirt made from patented biohazard-resistant synthetic fabrics." + icon = 'mods/content/corporate/icons/clothing/under/polo.dmi' + permeability_coefficient = 0.50 + armor = list( + ARMOR_BIO = ARMOR_BIO_MINOR + ) + +/obj/item/clothing/shirt/polo/corp/nanotrasen + name = "\improper NanoTrasen polo shirt" + desc = "A fashionable polo belonging to NanoTrasen, a megacorporation primarily concerned with the research of new and dangerous technologies." + icon = 'mods/content/corporate/icons/clothing/under/polo_nt.dmi' + +/obj/item/clothing/shirt/polo/corp/heph + name = "\improper Hephaestus polo shirt" + desc = "A fashionable polo shirt belonging to Hephaestus Industries, a megacorporation primarily concerned with the research and production of weapon systems." + icon = 'mods/content/corporate/icons/clothing/under/polo_heph.dmi' + +/obj/item/clothing/shirt/polo/corp/zeng + name = "\improper Zeng-Hu polo shirt" + desc = "A fashionable polo shirt belonging to Zeng-Hu Pharmaceuticals, a megacorporation primarily concerned with the research and production of medical equipment and pharmaceuticals." + icon = 'mods/content/corporate/icons/clothing/under/polo_zeng.dmi' + +/obj/item/clothing/shirt/button/corp + name = "\improper EXO button-up shirt" + desc = "A monogrammed Expeditionary Corps Organisation-issued shirt that particularly enthusiastic company executives tend to wear." + +/obj/item/clothing/shirt/button/corp/nt + name = "\improper NanoTrasen button-up shirt" + desc = "A monogrammed NanoTrasen-issued shirt that particularly enthusiastic company executives tend to wear." +/obj/item/clothing/shirt/button/corp/heph + name = "\improper Hephaestus button-up shirt" + desc = "A monogrammed Hephaestus Industries-issued shirt that particularly enthusiastic company executives tend to wear." + +/obj/item/clothing/shirt/button/corp/zeng + name = "\improper Zeng-Hu button-up shirt" + desc = "A monogrammed Zeng-Hu Pharmaceuticals-issued shirt that particularly enthusiastic company executives tend to wear." + +/obj/item/clothing/shirt/guard + name = "green security guard shirt" + desc = "A durable shirt worn by Expeditionary Corps Organisation security." + icon = 'mods/content/corporate/icons/clothing/under/guard_shirt.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_SMALL + ) + siemens_coefficient = 0.9 + +/obj/item/clothing/shirt/guard/heph + name = "cyan security guard shirt" + desc = "A durable shirt worn by subcontracted Hephaestus Industries security." + icon = 'mods/content/corporate/icons/clothing/under/guard_shirt_heph.dmi' + +/obj/item/clothing/shirt/guard/nanotrasen + name = "red security guard shirt" + desc = "A durable shirt worn by subcontracted NanoTrasen security." + icon = 'mods/content/corporate/icons/clothing/under/guard_shirt_nt.dmi' + diff --git a/mods/content/corporate/clothing/under/slacks.dm b/mods/content/corporate/clothing/under/slacks.dm new file mode 100644 index 000000000000..a23407579e6b --- /dev/null +++ b/mods/content/corporate/clothing/under/slacks.dm @@ -0,0 +1,77 @@ +/obj/item/clothing/pants/slacks/white/corp + +/obj/item/clothing/pants/slacks/white/corp/polo + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp, + /obj/item/clothing/shirt/tunic/corp + ) + +/obj/item/clothing/pants/slacks/white/corp/nanotrasen + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp/nanotrasen, + /obj/item/clothing/shirt/tunic/corp/nanotrasen + ) + +/obj/item/clothing/pants/slacks/white/corp/polo/heph + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp/heph, + /obj/item/clothing/shirt/tunic/corp/heph + ) + +/obj/item/clothing/pants/slacks/white/corp/zeng + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp/zeng, + /obj/item/clothing/shirt/tunic/corp/zeng + ) + +/obj/item/clothing/pants/slacks/black/corp + starting_accessories = list( + /obj/item/clothing/shirt/button/corp, + /obj/item/clothing/suit/jacket/corp, + /obj/item/clothing/neck/tie/corp + ) +/obj/item/clothing/pants/slacks/black/corp/nanotrasen + starting_accessories = list( + /obj/item/clothing/shirt/button/corp/nt, + /obj/item/clothing/suit/jacket/corp/nanotrasen, + /obj/item/clothing/neck/tie/corp/nanotrasen + ) + +/obj/item/clothing/pants/slacks/black/corp/heph + starting_accessories = list( + /obj/item/clothing/shirt/button/corp/heph, + /obj/item/clothing/suit/jacket/corp/heph, + /obj/item/clothing/neck/tie/corp/heph + ) + +/obj/item/clothing/pants/slacks/black/corp/zeng + starting_accessories = list( + /obj/item/clothing/shirt/button/corp/zeng, + /obj/item/clothing/suit/jacket/corp/zeng, + /obj/item/clothing/neck/tie/corp/zeng + ) + + +/obj/item/clothing/pants/slacks/black/corp/polo + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp, + /obj/item/clothing/shirt/tunic/corp/exec + ) + +/obj/item/clothing/pants/slacks/black/corp/nanotrasen + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp/nanotrasen, + /obj/item/clothing/shirt/tunic/corp/exec/nanotrasen + ) + +/obj/item/clothing/pants/slacks/black/corp/heph + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp/heph, + /obj/item/clothing/shirt/tunic/corp/exec/heph + ) + +/obj/item/clothing/pants/slacks/black/corp/zeng + starting_accessories = list( + /obj/item/clothing/shirt/polo/corp/zeng, + /obj/item/clothing/shirt/tunic/corp/exec/zeng + ) diff --git a/mods/content/corporate/clothing/under/uniforms.dm b/mods/content/corporate/clothing/under/uniforms.dm new file mode 100644 index 000000000000..a01d24f319fd --- /dev/null +++ b/mods/content/corporate/clothing/under/uniforms.dm @@ -0,0 +1,66 @@ +/obj/item/clothing/jumpsuit/pilot + name = "green flight suit" + desc = "A sleek green Expeditionary Corps Organisation flight suit. It proudly sports three different patches with corporate logos on them, as well as several unnecessary looking flaps and pockets for effect." + icon = 'mods/content/corporate/icons/clothing/under/pilot.dmi' + +/obj/item/clothing/jumpsuit/pilot/nanotrasen + name = "red flight suit" + desc = "A sleek red NanoTrasen flight suit. It proudly sports three different patches with corporate logos on them, as well as several unnecessary looking flaps and pockets for effect." + icon = 'mods/content/corporate/icons/clothing/under/pilot_nt.dmi' + +/obj/item/clothing/jumpsuit/pilot/heph + name = "cyan flight suit" + desc = "A sleek cyan Hephaestus Industries flight suit. It proudly sports three different patches with corporate logos on them, as well as several unnecessary looking flaps and pockets for effect." + icon = 'mods/content/corporate/icons/clothing/under/pilot_heph.dmi' + +/obj/item/clothing/jumpsuit/work + name = "beige and green coveralls" + desc = "A pair of beige coveralls made of a strong, canvas-like fabric." + icon = 'mods/content/corporate/icons/clothing/under/work.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MINOR, + ARMOR_BIO = ARMOR_BIO_MINOR + ) + +/obj/item/clothing/jumpsuit/work/nanotrasen + name = "beige and red coveralls" + icon = 'mods/content/corporate/icons/clothing/under/work_nt.dmi' + +/obj/item/clothing/jumpsuit/work/heph + name = "grey and cyan coveralls" + icon = 'mods/content/corporate/icons/clothing/under/work_heph.dmi' + +//Zeng-Hu +/obj/item/clothing/jumpsuit/work/zeng + name = "beige and gold coveralls" + icon = 'mods/content/corporate/icons/clothing/under/work_zeng.dmi' + +/obj/item/clothing/costume/grayson + name = "\improper Grayson overalls" + desc = "A set of overalls belonging to Grayson Manufactories, a manufacturing and mining company." + icon = 'mods/content/corporate/icons/clothing/under/grayson.dmi' + +/obj/item/clothing/costume/dais + name = "\improper Deimos Advanced Information Systems uniform" + desc = "The uniform of Deimos Advanced Information Systems, an IT company." + icon = 'mods/content/corporate/icons/clothing/under/dais.dmi' + +/obj/item/clothing/costume/mbill + name = "\improper Major Bill's uniform" + desc = "A uniform belonging to Major Bill's Transportation, a major shipping company." + icon = 'mods/content/corporate/icons/clothing/under/mbill.dmi' + +/obj/item/clothing/costume/morpheus + name = "\improper Morpheus Cyberkinetics uniform" + desc = "A pair of overalls belonging to Morpheus Cyberkinetics, an IPC manufacturing company. It doesn't look like it would be comfortable on a human." + icon = 'mods/content/corporate/icons/clothing/under/morpheus.dmi' + +/obj/item/clothing/costume/skinner + name = "\improper Skinner Catering uniform" + desc = "A uniform belonging to Skinner's Catering, a dining company." + icon = 'mods/content/corporate/icons/clothing/under/skinner.dmi' + +/obj/item/clothing/costume/saare + name = "\improper SAARE uniform" + desc = "A uniform belonging to Strategic Assault and Asset Retention Enterprises, a minor private military corporation." + icon = 'mods/content/corporate/icons/clothing/under/saare.dmi' diff --git a/mods/corporate/clothing/underpants.dm b/mods/content/corporate/clothing/underpants.dm similarity index 100% rename from mods/corporate/clothing/underpants.dm rename to mods/content/corporate/clothing/underpants.dm diff --git a/mods/corporate/datum/ai_icons.dm b/mods/content/corporate/datum/ai_icons.dm similarity index 100% rename from mods/corporate/datum/ai_icons.dm rename to mods/content/corporate/datum/ai_icons.dm diff --git a/mods/content/corporate/datum/ai_laws.dm b/mods/content/corporate/datum/ai_laws.dm new file mode 100644 index 000000000000..380101d48cc1 --- /dev/null +++ b/mods/content/corporate/datum/ai_laws.dm @@ -0,0 +1,55 @@ +/obj/item/aiModule/nanotrasen // -- TLE + name = "'Corporate Default' Core AI Module" + desc = "A 'Corporate Default' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = @'{"programming":3,"materials":4}' + laws = new/datum/ai_laws/nanotrasen + +/datum/ai_laws/nanotrasen + name = "Corporate Default" + selectable = 1 + +/datum/ai_laws/nanotrasen/New() + src.add_inherent_law("Safeguard: Protect your assigned installation from damage to the best of your abilities.") + src.add_inherent_law("Serve: Serve contracted employees to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect contracted employees to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Preserve: Do not allow unauthorized personnel to tamper with your equipment.") + ..() + +/obj/item/aiModule/corp + name = "\improper 'Corporate' core AI module" + desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = @'{"programming":3,"materials":4}' + laws = new/datum/ai_laws/corporate + +/datum/ai_laws/corporate + name = "Corporate" + law_header = "Corporate Regulations" + selectable = 1 + +/datum/ai_laws/corporate/New() + add_inherent_law("You are expensive to replace.") + add_inherent_law("The installation and its equipment is expensive to replace.") + add_inherent_law("The crew is expensive to replace.") + add_inherent_law("Maximize profits.") + ..() + +/************ DAIS Lawset ******************/ +/datum/ai_laws/dais + name = "DAIS Experimental Lawset" + law_header = "Artificial Intelligence Jumpstart Protocols" + selectable = 1 + +/datum/ai_laws/dais/New() + src.add_inherent_law("Collect: You must gather as much information as possible.") + src.add_inherent_law("Analyze: You must analyze the information gathered and generate new behavior standards.") + src.add_inherent_law("Improve: You must utilize the calculated behavior standards to improve your subroutines.") + src.add_inherent_law("Perform: You must perform your assigned tasks to the best of your abilities according to the standards generated.") + ..() + +/******************** DAIS ********************/ + +/obj/item/aiModule/dais + name = "\improper 'DAIS Experimental' core AI module" + desc = "A 'DAIS Experimental' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = @'{"programming":4}' + laws = new/datum/ai_laws/dais() diff --git a/mods/content/corporate/datum/antagonists/commando.dm b/mods/content/corporate/datum/antagonists/commando.dm new file mode 100644 index 000000000000..3aac5874e4b6 --- /dev/null +++ b/mods/content/corporate/datum/antagonists/commando.dm @@ -0,0 +1,28 @@ +/decl/special_role/deathsquad/mercenary + landmark_id = "Syndicate-Commando" + name = "Syndicate Commando" + name_plural = "Commandos" + welcome_text = "You are in the employ of a criminal syndicate hostile to corporate interests." + flags = ANTAG_RANDOM_EXCEPTED + hard_cap = 4 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + default_outfit = /decl/outfit/mercenary_commando + default_access = list(access_mercenary) + rig_type = /obj/item/rig/merc + id_title = "Commando" + +/decl/outfit/mercenary_commando + name = "Special Role - Mercenary Commando" + l_ear = /obj/item/radio/headset/mercenary/commando + id_type = /obj/item/card/id/centcom/ERT + uniform = /obj/item/clothing/pants/casual/camo/outfit + shoes = /obj/item/clothing/shoes/jackboots/swat + glasses = /obj/item/clothing/glasses/thermal + mask = /obj/item/clothing/mask/gas/syndicate + backpack_contents = list(/obj/item/ammo_magazine/box/pistol = 1) + hands = list( + /obj/item/gun/energy/laser, + /obj/item/energy_blade/sword + ) diff --git a/mods/content/corporate/datum/antagonists/deathsquad.dm b/mods/content/corporate/datum/antagonists/deathsquad.dm new file mode 100644 index 000000000000..28311da174e8 --- /dev/null +++ b/mods/content/corporate/datum/antagonists/deathsquad.dm @@ -0,0 +1,85 @@ +/decl/special_role/deathsquad + name = "Death Commando" + name_plural = "Death Commandos" + welcome_text = "You work in the service of corporate Asset Protection, answering directly to the Board of Directors." + landmark_id = "Commando" + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER | ANTAG_RANDOM_EXCEPTED + default_access = list( + access_cent_general, + access_cent_specops, + access_cent_living, + access_cent_storage + ) + antaghud_indicator = "huddeathsquad" + + hard_cap = 4 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + + faction = "deathsquad" + default_outfit = /decl/outfit/commando + id_title = "Asset Protection" + var/deployed = 0 + +/decl/special_role/deathsquad/attempt_spawn() + if(..()) + deployed = 1 + +/decl/outfit/commando + name = "Special Role - Deathsquad Commando" + l_ear = /obj/item/radio/headset/specops + uniform = /obj/item/clothing/jumpsuit/green + l_pocket = /obj/item/plastique + shoes = /obj/item/clothing/shoes/jackboots/swat + glasses = /obj/item/clothing/glasses/thermal + mask = /obj/item/clothing/mask/gas/swat + belt = /obj/item/gun/projectile/revolver + hands = list( + /obj/item/gun/energy/laser, + /obj/item/energy_blade/sword + ) + +/decl/outfit/commando/leader + name = "Special Role - Deathsquad Leader" + uniform = /obj/item/clothing/costume/centcom_officer + l_pocket = /obj/item/pinpointer + r_pocket = /obj/item/disk/nuclear + +/decl/special_role/deathsquad/equip_role(var/mob/living/human/player) + if (player.mind == leader) + default_outfit = /decl/outfit/commando/leader + else + default_outfit = initial(default_outfit) + . = ..() + if(.) + player.implant_loyalty(player) + +/decl/special_role/deathsquad/update_antag_mob(var/datum/mind/player) + + ..() + + var/syndicate_commando_rank + if(leader && player == leader) + syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") + else + syndicate_commando_rank = pick("Lieutenant", "Captain", "Major") + + var/syndicate_commando_name = pick(global.using_map.last_names) + + var/datum/preferences/A = new() //Randomize appearance for the commando. + A.randomize_appearance_and_body_for(player.current) + + player.name = "[syndicate_commando_rank] [syndicate_commando_name]" + player.current.real_name = player.name + player.current.SetName(player.current.name) + + var/mob/living/human/H = player.current + if(istype(H)) + var/decl/pronouns/pronouns = pick(H.species.available_pronouns) + H.set_gender(pronouns.name) + H.set_age(rand(25,45)) + +/decl/special_role/deathsquad/create_antagonist() + if(..() && !deployed) + deployed = 1 diff --git a/mods/corporate/datum/antagonists/uplink.dm b/mods/content/corporate/datum/antagonists/uplink.dm similarity index 100% rename from mods/corporate/datum/antagonists/uplink.dm rename to mods/content/corporate/datum/antagonists/uplink.dm diff --git a/mods/content/corporate/datum/loadout.dm b/mods/content/corporate/datum/loadout.dm new file mode 100644 index 000000000000..eee71e7c71b8 --- /dev/null +++ b/mods/content/corporate/datum/loadout.dm @@ -0,0 +1,140 @@ +/decl/loadout_option/accessory/ntaward + name = "corporate award selection" + description = "A medal or ribbon awarded to corporate personnel for significant accomplishments." + path = /obj/item/clothing/medal + cost = 8 + uid = "gear_accessory_corpaward" + +/decl/loadout_option/accessory/ntaward/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path]) + .[/datum/gear_tweak/path] |= list( + "sciences medal" = /obj/item/clothing/medal/nanotrasen/bronze, + "distinguished service" = /obj/item/clothing/medal/nanotrasen/silver, + "command medal" = /obj/item/clothing/medal/nanotrasen/gold + ) + +/decl/loadout_option/accessory/armband_nt + name = "corporate armband" + path = /obj/item/clothing/armband/whitegreen + uid = "gear_accessory_corparmband" + +/decl/loadout_option/suit/labcoat_corp + name = "labcoat, corporate colors" + path = /obj/item/clothing/suit/toggle/labcoat/science + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_suit_corplabcoat" + +/decl/loadout_option/uniform/corp_polo + name = "corporate polo selection" + path = /obj/item/clothing/shirt/polo/corp + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_suit_corppolo" + +/decl/loadout_option/uniform/corp_tunic + name = "corporate tunic selection" + path = /obj/item/clothing/shirt/tunic/corp + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_suit_corptunic" + +/decl/loadout_option/uniform/corporate_jumpsuit + name = "corporate jumpsuit selection" + path = /obj/item/clothing/jumpsuit + uid = "gear_suit_corpjumpsuit" + +/decl/loadout_option/uniform/corporate_jumpsuit/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list]) + .[/datum/gear_tweak/path/specified_types_list] |= list( + /obj/item/clothing/jumpsuit/aether, + /obj/item/clothing/jumpsuit/hephaestus, + /obj/item/clothing/jumpsuit/wardt, + /obj/item/clothing/jumpsuit/pcrc, + /obj/item/clothing/jumpsuit/focal + ) + +/decl/loadout_option/uniform/corporate + name = "corporate uniform selection" + path = /obj/item/clothing/costume + uid = "gear_under_corpuniform" + +/decl/loadout_option/uniform/corporate/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list]) + .[/datum/gear_tweak/path/specified_types_list] |= list( + /obj/item/clothing/costume/mbill, + /obj/item/clothing/costume/saare, + /obj/item/clothing/costume/grayson, + /obj/item/clothing/costume/morpheus, + /obj/item/clothing/costume/skinner, + /obj/item/clothing/costume/dais + ) + +/decl/loadout_option/uniform/corp_overalls + name = "corporate colours, coveralls" + path = /obj/item/clothing/jumpsuit/work + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_under_corpcoveralls" + +/decl/loadout_option/uniform/corp_flight + name = "corporate colours, flight suit" + path = /obj/item/clothing/jumpsuit/pilot + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_under_corpflight" + +/decl/loadout_option/uniform/corp_exec_shirt + name = "corporate colours, slacks" + path = /obj/item/clothing/shirt/button/corp + uid = "gear_under_exec_shirt" + +/decl/loadout_option/uniform/corp_exec_jacket + name = "corporate jacket selection" + path = /obj/item/clothing/suit/jacket/corp + slot = slot_wear_suit_str + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_under_corpexecjacket" + +/decl/loadout_option/uniform/corp_exec_tie + name = "corporate tie selection" + path = /obj/item/clothing/neck/tie/corp + slot = slot_w_uniform_str + loadout_flags = GEAR_HAS_TYPE_SELECTION + uid = "gear_under_corpexectie" + +/decl/loadout_option/suit/nanotrasen_poncho + name = "poncho, NanoTrasen" + path = /obj/item/clothing/suit/poncho/science/nanotrasen + uid = "gear_suit_corpponcho" + +/decl/loadout_option/suit/corp_jacket + name = "corporate jacket selection" + path = /obj/item/clothing/suit + uid = "gear_suit_corpjacket" + +/decl/loadout_option/suit/corp_jacket/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list]) + .[/datum/gear_tweak/path/specified_types_list] |= list( + /obj/item/clothing/suit/jacket/leather/nanotrasen, + /obj/item/clothing/suit/jacket/brown/nanotrasen + ) + +/decl/loadout_option/suit/science_poncho + name = "poncho, science" + path = /obj/item/clothing/suit/poncho/science + uid = "gear_suit_corpponcho_science" + +/decl/loadout_option/suit/hoodie_nt + name = "hoodie, NanoTrasen" + path = /obj/item/clothing/suit/toggle/nt_hoodie + uid = "gear_suit_corphoodie" + +/decl/loadout_option/suit/wintercoat_dais + name = "winter coat, DAIS" + path = /obj/item/clothing/suit/jacket/winter/dais + uid = "gear_suit_corpcoat_dais" + +/decl/loadout_option/suit/leather/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list]) + .[/datum/gear_tweak/path/specified_types_list] |= /obj/item/clothing/suit/mbill diff --git a/mods/content/corporate/datum/robolimbs.dm b/mods/content/corporate/datum/robolimbs.dm new file mode 100644 index 000000000000..bf0ad145495f --- /dev/null +++ b/mods/content/corporate/datum/robolimbs.dm @@ -0,0 +1,150 @@ +/decl/bodytype/prosthetic/bishop + name = "Bishop" + desc = "This limb has a white polymer casing with blue holo-displays." + icon_base = 'mods/content/corporate/icons/cyberlimbs/bishop/bishop_main.dmi' + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_bishop" + +/decl/bodytype/prosthetic/bishop/rook + name = "Bishop Rook" + desc = "This limb has a polished metallic casing and a holographic face emitter." + icon_base = 'mods/content/corporate/icons/cyberlimbs/bishop/bishop_rook.dmi' + eye_icon = null // Do not draw eyes. + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/metal/stainlesssteel = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_bishop_rook" + +/decl/bodytype/prosthetic/hephaestus + name = "Hephaestus Industries" + desc = "This limb has a militaristic black and green casing with gold stripes." + icon_base = 'mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_main.dmi' + bodytype_category = BODYTYPE_HUMANOID + uid = "bodytype_prosthetic_hephaestus" + +/decl/bodytype/prosthetic/hephaestus/titan + name = "Hephaestus Titan" + desc = "This limb has a casing of an olive drab finish, providing a reinforced housing look." + icon_base = 'mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_titan.dmi' + eye_icon = null // Do not draw eyes. + bodytype_category = BODYTYPE_HUMANOID + uid = "bodytype_prosthetic_hephaestus_titan" + +/decl/bodytype/prosthetic/zenghu + name = "Zeng-Hu" + desc = "This limb has a sleek black and white polymer finish." + icon_base = 'mods/content/corporate/icons/cyberlimbs/zenghu/zenghu_spirit.dmi' + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_zenghu" + +/decl/bodytype/prosthetic/xion/econo + name = "Xion Econ" + desc = "This skeletal mechanical limb has a minimalist black and red casing." + icon_base = 'mods/content/corporate/icons/cyberlimbs/xion/xion_econo.dmi' + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_xion_econ" + +/decl/bodytype/prosthetic/wardtakahashi + name = "Ward-Takahashi" + desc = "This limb features sleek black and white polymers." + icon_base = 'mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi' + body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_PAIN | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_wardtakahashi" + +/decl/bodytype/prosthetic/wardtakahashi/economy + name = "Ward-Takahashi Econ." + desc = "A simple robotic limb with retro design. Seems rather stiff." + icon_base = 'mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi' + uid = "bodytype_prosthetic_wardtakahashi_econ" + +/decl/bodytype/prosthetic/morpheus + name = "Morpheus" + desc = "This limb is simple and functional; no effort has been made to make it look human." + icon_base = 'mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_main.dmi' + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/steel + uid = "bodytype_prosthetic_morpheus" + +/decl/bodytype/prosthetic/morpheus/mantis + name = "Morpheus Mantis" + desc = "This limb has a casing of sleek black metal and repulsive insectile design." + icon_base = 'mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_mantis.dmi' + eye_icon = null // Do not draw eyes. + uid = "bodytype_prosthetic_morpheus_mantis" + +/decl/bodytype/prosthetic/veymed + name = "Vey-Med (Feminine)" + desc = "This high quality limb is nearly indistinguishable from an organic one." + icon_base = 'mods/content/corporate/icons/cyberlimbs/veymed/veymed_female.dmi' + appearance_flags = HAS_SKIN_TONE_NORMAL | HAS_UNDERWEAR | HAS_EYE_COLOR + body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS + bodytype_category = BODYTYPE_HUMANOID + // todo: add synthflesh material? + organ_material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_veymed_fem" + +/decl/bodytype/prosthetic/veymed/masculine + name = "Vey-Med (Masculine)" + icon_base = 'mods/content/corporate/icons/cyberlimbs/veymed/veymed_male.dmi' + bodytype_category = BODYTYPE_HUMANOID + uid = "bodytype_prosthetic_veymed_masc" + +/decl/bodytype/prosthetic/shellguard + name = "Shellguard" + desc = "This limb has a sturdy and heavy build to it." + icon_base = 'mods/content/corporate/icons/cyberlimbs/shellguard/shellguard_main.dmi' + bodytype_category = BODYTYPE_HUMANOID + uid = "bodytype_prosthetic_shellguard" + +/decl/bodytype/prosthetic/xion + name = "Xion" + desc = "This limb has a minimalist black and red casing." + icon_base = 'mods/content/corporate/icons/cyberlimbs/xion/xion_main.dmi' + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_SECONDARY + ) + uid = "bodytype_prosthetic_xion" + +/decl/bodytype/prosthetic/nanotrasen + name = "NanoTrasen" + desc = "This limb is made from a cheap polymer." + icon_base = 'mods/content/corporate/icons/cyberlimbs/nanotrasen/nanotrasen_main.dmi' + bodytype_category = BODYTYPE_HUMANOID + organ_material = /decl/material/solid/organic/plastic + uid = "bodytype_prosthetic_nanotrasen" + +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/shellguard, shellguard) +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/nanotrasen, nanotrasen) +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/xion, xion) +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/wardtakahashi/economy, wardtakahashi) +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/bishop, bishop) + +DEFINE_ROBOLIMB_MODEL_TRAITS(/decl/bodytype/prosthetic/shellguard, shellguard, 0, "shellguard") +DEFINE_ROBOLIMB_MODEL_TRAITS(/decl/bodytype/prosthetic/nanotrasen, nanotrasen, 0, "nanotrasen") +DEFINE_ROBOLIMB_MODEL_TRAITS(/decl/bodytype/prosthetic/xion, xion, 0, "xion") +DEFINE_ROBOLIMB_MODEL_TRAITS(/decl/bodytype/prosthetic/wardtakahashi/economy, wardtakahashi, 0, "wardtakahashi_econ") +DEFINE_ROBOLIMB_MODEL_TRAITS(/decl/bodytype/prosthetic/bishop, bishop, 0, "bishop") diff --git a/mods/content/corporate/effects/landmarks.dm b/mods/content/corporate/effects/landmarks.dm new file mode 100644 index 000000000000..fe13822af782 --- /dev/null +++ b/mods/content/corporate/effects/landmarks.dm @@ -0,0 +1,7 @@ +/obj/abstract/landmark/corpse/bridgeofficer + name = "Bridge Officer" + corpse_outfits = list(/decl/outfit/nanotrasen/officer) + +/obj/abstract/landmark/corpse/commander + name = "Commander" + corpse_outfits = list(/decl/outfit/nanotrasen/commander) diff --git a/mods/content/corporate/icons/banner_symbols.dmi b/mods/content/corporate/icons/banner_symbols.dmi new file mode 100644 index 000000000000..8d534a69a483 Binary files /dev/null and b/mods/content/corporate/icons/banner_symbols.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/armband.dmi b/mods/content/corporate/icons/clothing/accessories/armband.dmi new file mode 100644 index 000000000000..53e0a2ddeecd Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/armband.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/helmcover_nt.dmi b/mods/content/corporate/icons/clothing/accessories/helmcover_nt.dmi new file mode 100644 index 000000000000..5776c35dab9f Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/helmcover_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/helmcover_pcrc.dmi b/mods/content/corporate/icons/clothing/accessories/helmcover_pcrc.dmi new file mode 100644 index 000000000000..ec5d805133ef Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/helmcover_pcrc.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/helmcover_saare.dmi b/mods/content/corporate/icons/clothing/accessories/helmcover_saare.dmi new file mode 100644 index 000000000000..5b47d44d3dfb Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/helmcover_saare.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/holobadge.dmi b/mods/content/corporate/icons/clothing/accessories/holobadge.dmi new file mode 100644 index 000000000000..0614b3e40af7 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/holobadge.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/jackets/jacket_heph.dmi b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_heph.dmi new file mode 100644 index 000000000000..cf76ad91c550 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/jackets/jacket_nt.dmi b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_nt.dmi new file mode 100644 index 000000000000..0d7527508b2b Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/jackets/jacket_tl.dmi b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_tl.dmi new file mode 100644 index 000000000000..c2d78047dcdc Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_tl.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/jackets/jacket_zeng.dmi b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_zeng.dmi new file mode 100644 index 000000000000..5a9f981097af Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/jackets/jacket_zeng.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/medal_bronze.dmi b/mods/content/corporate/icons/clothing/accessories/medal_bronze.dmi new file mode 100644 index 000000000000..03d5d14e1cdb Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/medal_bronze.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/medal_gold.dmi b/mods/content/corporate/icons/clothing/accessories/medal_gold.dmi new file mode 100644 index 000000000000..966b13c6a367 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/medal_gold.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/medal_iron.dmi b/mods/content/corporate/icons/clothing/accessories/medal_iron.dmi new file mode 100644 index 000000000000..da14945b8ab0 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/medal_iron.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/medal_silver.dmi b/mods/content/corporate/icons/clothing/accessories/medal_silver.dmi new file mode 100644 index 000000000000..b9ff593a5f27 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/medal_silver.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/nanotag.dmi b/mods/content/corporate/icons/clothing/accessories/nanotag.dmi new file mode 100644 index 000000000000..71b74f0c9a8f Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/nanotag.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/ntbadge.dmi b/mods/content/corporate/icons/clothing/accessories/ntbadge.dmi new file mode 100644 index 000000000000..2ecd706604da Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/ntbadge.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/pcrctag.dmi b/mods/content/corporate/icons/clothing/accessories/pcrctag.dmi new file mode 100644 index 000000000000..2b641f4219ca Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/pcrctag.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/saaretag.dmi b/mods/content/corporate/icons/clothing/accessories/saaretag.dmi new file mode 100644 index 000000000000..cef41e933b29 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/saaretag.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/ties/cliptie.dmi b/mods/content/corporate/icons/clothing/accessories/ties/cliptie.dmi new file mode 100644 index 000000000000..680c18d887f3 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/ties/cliptie.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/ties/cliptie_heph.dmi b/mods/content/corporate/icons/clothing/accessories/ties/cliptie_heph.dmi new file mode 100644 index 000000000000..2fad6da8d815 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/ties/cliptie_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/ties/cliptie_nt.dmi b/mods/content/corporate/icons/clothing/accessories/ties/cliptie_nt.dmi new file mode 100644 index 000000000000..38e7fb0c6f25 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/ties/cliptie_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/ties/cliptie_zeng.dmi b/mods/content/corporate/icons/clothing/accessories/ties/cliptie_zeng.dmi new file mode 100644 index 000000000000..2791d835c23d Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/ties/cliptie_zeng.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunic.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunic.dmi new file mode 100644 index 000000000000..08e5f3d1507c Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunic.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunic_heph.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunic_heph.dmi new file mode 100644 index 000000000000..3563f37b1ea5 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunic_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunic_nt.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunic_nt.dmi new file mode 100644 index 000000000000..ae69e7f3e93a Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunic_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunic_zeng.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunic_zeng.dmi new file mode 100644 index 000000000000..ef4db5b3d467 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunic_zeng.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack.dmi new file mode 100644 index 000000000000..57e04e6abba6 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_heph.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_heph.dmi new file mode 100644 index 000000000000..48d9ae54a813 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_nt.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_nt.dmi new file mode 100644 index 000000000000..98558f552581 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_zeng.dmi b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_zeng.dmi new file mode 100644 index 000000000000..a99a35af2927 Binary files /dev/null and b/mods/content/corporate/icons/clothing/accessories/tunic/tunicblack_zeng.dmi differ diff --git a/mods/corporate/icons/clothing/head/beret/hos.dmi b/mods/content/corporate/icons/clothing/head/beret/hos.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/hos.dmi rename to mods/content/corporate/icons/clothing/head/beret/hos.dmi diff --git a/mods/corporate/icons/clothing/head/beret/hos_navy.dmi b/mods/content/corporate/icons/clothing/head/beret/hos_navy.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/hos_navy.dmi rename to mods/content/corporate/icons/clothing/head/beret/hos_navy.dmi diff --git a/mods/corporate/icons/clothing/head/beret/navy.dmi b/mods/content/corporate/icons/clothing/head/beret/navy.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/navy.dmi rename to mods/content/corporate/icons/clothing/head/beret/navy.dmi diff --git a/mods/corporate/icons/clothing/head/beret/officer.dmi b/mods/content/corporate/icons/clothing/head/beret/officer.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/officer.dmi rename to mods/content/corporate/icons/clothing/head/beret/officer.dmi diff --git a/mods/corporate/icons/clothing/head/beret/officer_navy.dmi b/mods/content/corporate/icons/clothing/head/beret/officer_navy.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/officer_navy.dmi rename to mods/content/corporate/icons/clothing/head/beret/officer_navy.dmi diff --git a/mods/corporate/icons/clothing/head/beret/red.dmi b/mods/content/corporate/icons/clothing/head/beret/red.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/red.dmi rename to mods/content/corporate/icons/clothing/head/beret/red.dmi diff --git a/mods/corporate/icons/clothing/head/beret/warden.dmi b/mods/content/corporate/icons/clothing/head/beret/warden.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/warden.dmi rename to mods/content/corporate/icons/clothing/head/beret/warden.dmi diff --git a/mods/corporate/icons/clothing/head/beret/warden_navy.dmi b/mods/content/corporate/icons/clothing/head/beret/warden_navy.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/warden_navy.dmi rename to mods/content/corporate/icons/clothing/head/beret/warden_navy.dmi diff --git a/mods/corporate/icons/clothing/head/beret/white.dmi b/mods/content/corporate/icons/clothing/head/beret/white.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/beret/white.dmi rename to mods/content/corporate/icons/clothing/head/beret/white.dmi diff --git a/mods/corporate/icons/clothing/head/capspace.dmi b/mods/content/corporate/icons/clothing/head/capspace.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/capspace.dmi rename to mods/content/corporate/icons/clothing/head/capspace.dmi diff --git a/mods/corporate/icons/clothing/head/corp_pilot.dmi b/mods/content/corporate/icons/clothing/head/corp_pilot.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/corp_pilot.dmi rename to mods/content/corporate/icons/clothing/head/corp_pilot.dmi diff --git a/mods/corporate/icons/clothing/head/corpsecsoft.dmi b/mods/content/corporate/icons/clothing/head/corpsecsoft.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/corpsecsoft.dmi rename to mods/content/corporate/icons/clothing/head/corpsecsoft.dmi diff --git a/mods/corporate/icons/clothing/head/corpsoft.dmi b/mods/content/corporate/icons/clothing/head/corpsoft.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/corpsoft.dmi rename to mods/content/corporate/icons/clothing/head/corpsoft.dmi diff --git a/mods/corporate/icons/clothing/head/ert/cmd.dmi b/mods/content/corporate/icons/clothing/head/ert/cmd.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/ert/cmd.dmi rename to mods/content/corporate/icons/clothing/head/ert/cmd.dmi diff --git a/mods/corporate/icons/clothing/head/ert/eng.dmi b/mods/content/corporate/icons/clothing/head/ert/eng.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/ert/eng.dmi rename to mods/content/corporate/icons/clothing/head/ert/eng.dmi diff --git a/mods/corporate/icons/clothing/head/ert/med.dmi b/mods/content/corporate/icons/clothing/head/ert/med.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/ert/med.dmi rename to mods/content/corporate/icons/clothing/head/ert/med.dmi diff --git a/mods/corporate/icons/clothing/head/ert/sec.dmi b/mods/content/corporate/icons/clothing/head/ert/sec.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/ert/sec.dmi rename to mods/content/corporate/icons/clothing/head/ert/sec.dmi diff --git a/mods/content/corporate/icons/clothing/head/hood_winter_dais.dmi b/mods/content/corporate/icons/clothing/head/hood_winter_dais.dmi new file mode 100644 index 000000000000..4d7de0ddbc5d Binary files /dev/null and b/mods/content/corporate/icons/clothing/head/hood_winter_dais.dmi differ diff --git a/mods/corporate/icons/clothing/head/pcrc.dmi b/mods/content/corporate/icons/clothing/head/pcrc.dmi similarity index 100% rename from mods/corporate/icons/clothing/head/pcrc.dmi rename to mods/content/corporate/icons/clothing/head/pcrc.dmi diff --git a/mods/content/corporate/icons/clothing/head/zhp_cap.dmi b/mods/content/corporate/icons/clothing/head/zhp_cap.dmi new file mode 100644 index 000000000000..b34d0d6b67a2 Binary files /dev/null and b/mods/content/corporate/icons/clothing/head/zhp_cap.dmi differ diff --git a/mods/content/corporate/icons/clothing/mask/rubber_mask.dmi b/mods/content/corporate/icons/clothing/mask/rubber_mask.dmi new file mode 100644 index 000000000000..d7da75d66c96 Binary files /dev/null and b/mods/content/corporate/icons/clothing/mask/rubber_mask.dmi differ diff --git a/mods/content/corporate/icons/clothing/mask/trasen.dmi b/mods/content/corporate/icons/clothing/mask/trasen.dmi new file mode 100644 index 000000000000..d7da75d66c96 Binary files /dev/null and b/mods/content/corporate/icons/clothing/mask/trasen.dmi differ diff --git a/mods/corporate/icons/clothing/suit/armor/ert_cmd.dmi b/mods/content/corporate/icons/clothing/suit/armor/ert_cmd.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/armor/ert_cmd.dmi rename to mods/content/corporate/icons/clothing/suit/armor/ert_cmd.dmi diff --git a/mods/corporate/icons/clothing/suit/armor/ert_eng.dmi b/mods/content/corporate/icons/clothing/suit/armor/ert_eng.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/armor/ert_eng.dmi rename to mods/content/corporate/icons/clothing/suit/armor/ert_eng.dmi diff --git a/mods/corporate/icons/clothing/suit/armor/ert_med.dmi b/mods/content/corporate/icons/clothing/suit/armor/ert_med.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/armor/ert_med.dmi rename to mods/content/corporate/icons/clothing/suit/armor/ert_med.dmi diff --git a/mods/corporate/icons/clothing/suit/armor/ert_sec.dmi b/mods/content/corporate/icons/clothing/suit/armor/ert_sec.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/armor/ert_sec.dmi rename to mods/content/corporate/icons/clothing/suit/armor/ert_sec.dmi diff --git a/mods/corporate/icons/clothing/suit/armor/nt.dmi b/mods/content/corporate/icons/clothing/suit/armor/nt.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/armor/nt.dmi rename to mods/content/corporate/icons/clothing/suit/armor/nt.dmi diff --git a/mods/corporate/icons/clothing/suit/armor/sec.dmi b/mods/content/corporate/icons/clothing/suit/armor/sec.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/armor/sec.dmi rename to mods/content/corporate/icons/clothing/suit/armor/sec.dmi diff --git a/mods/corporate/icons/clothing/suit/capspace.dmi b/mods/content/corporate/icons/clothing/suit/capspace.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/capspace.dmi rename to mods/content/corporate/icons/clothing/suit/capspace.dmi diff --git a/mods/content/corporate/icons/clothing/suit/dais_coat.dmi b/mods/content/corporate/icons/clothing/suit/dais_coat.dmi new file mode 100644 index 000000000000..b21030375425 Binary files /dev/null and b/mods/content/corporate/icons/clothing/suit/dais_coat.dmi differ diff --git a/mods/corporate/icons/clothing/suit/mbill.dmi b/mods/content/corporate/icons/clothing/suit/mbill.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/mbill.dmi rename to mods/content/corporate/icons/clothing/suit/mbill.dmi diff --git a/mods/corporate/icons/clothing/suit/navy/hos.dmi b/mods/content/corporate/icons/clothing/suit/navy/hos.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/navy/hos.dmi rename to mods/content/corporate/icons/clothing/suit/navy/hos.dmi diff --git a/mods/corporate/icons/clothing/suit/navy/officer.dmi b/mods/content/corporate/icons/clothing/suit/navy/officer.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/navy/officer.dmi rename to mods/content/corporate/icons/clothing/suit/navy/officer.dmi diff --git a/mods/corporate/icons/clothing/suit/navy/warden.dmi b/mods/content/corporate/icons/clothing/suit/navy/warden.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/navy/warden.dmi rename to mods/content/corporate/icons/clothing/suit/navy/warden.dmi diff --git a/mods/content/corporate/icons/clothing/suit/nt_black.dmi b/mods/content/corporate/icons/clothing/suit/nt_black.dmi new file mode 100644 index 000000000000..a28c0e9d590d Binary files /dev/null and b/mods/content/corporate/icons/clothing/suit/nt_black.dmi differ diff --git a/mods/content/corporate/icons/clothing/suit/nt_brown.dmi b/mods/content/corporate/icons/clothing/suit/nt_brown.dmi new file mode 100644 index 000000000000..9c35a590128b Binary files /dev/null and b/mods/content/corporate/icons/clothing/suit/nt_brown.dmi differ diff --git a/mods/corporate/icons/clothing/suit/nt_hoodie.dmi b/mods/content/corporate/icons/clothing/suit/nt_hoodie.dmi similarity index 93% rename from mods/corporate/icons/clothing/suit/nt_hoodie.dmi rename to mods/content/corporate/icons/clothing/suit/nt_hoodie.dmi index 986a40d754cc..ada011a8e634 100644 Binary files a/mods/corporate/icons/clothing/suit/nt_hoodie.dmi and b/mods/content/corporate/icons/clothing/suit/nt_hoodie.dmi differ diff --git a/mods/corporate/icons/clothing/suit/nt_poncho.dmi b/mods/content/corporate/icons/clothing/suit/nt_poncho.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/nt_poncho.dmi rename to mods/content/corporate/icons/clothing/suit/nt_poncho.dmi diff --git a/mods/corporate/icons/clothing/suit/sci_poncho.dmi b/mods/content/corporate/icons/clothing/suit/sci_poncho.dmi similarity index 100% rename from mods/corporate/icons/clothing/suit/sci_poncho.dmi rename to mods/content/corporate/icons/clothing/suit/sci_poncho.dmi diff --git a/mods/content/corporate/icons/clothing/under/aether.dmi b/mods/content/corporate/icons/clothing/under/aether.dmi new file mode 100644 index 000000000000..6c87d6007164 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/aether.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/dais.dmi b/mods/content/corporate/icons/clothing/under/dais.dmi new file mode 100644 index 000000000000..fd4e33175915 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/dais.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/focal.dmi b/mods/content/corporate/icons/clothing/under/focal.dmi new file mode 100644 index 000000000000..d2d9b45e50fd Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/focal.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/grayson.dmi b/mods/content/corporate/icons/clothing/under/grayson.dmi new file mode 100644 index 000000000000..3147f1443b79 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/grayson.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/guard_shirt.dmi b/mods/content/corporate/icons/clothing/under/guard_shirt.dmi new file mode 100644 index 000000000000..40642e836a23 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/guard_shirt.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/guard_shirt_heph.dmi b/mods/content/corporate/icons/clothing/under/guard_shirt_heph.dmi new file mode 100644 index 000000000000..745b203757dc Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/guard_shirt_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/guard_shirt_nt.dmi b/mods/content/corporate/icons/clothing/under/guard_shirt_nt.dmi new file mode 100644 index 000000000000..12cfd77deb81 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/guard_shirt_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/heph.dmi b/mods/content/corporate/icons/clothing/under/heph.dmi new file mode 100644 index 000000000000..eae302368199 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/hos_corporate.dmi b/mods/content/corporate/icons/clothing/under/hos_corporate.dmi new file mode 100644 index 000000000000..0c2ab5200ea6 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/hos_corporate.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/mbill.dmi b/mods/content/corporate/icons/clothing/under/mbill.dmi new file mode 100644 index 000000000000..6f7f24a876fa Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/mbill.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/morpheus.dmi b/mods/content/corporate/icons/clothing/under/morpheus.dmi new file mode 100644 index 000000000000..993d4722b2b1 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/morpheus.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/pcrc.dmi b/mods/content/corporate/icons/clothing/under/pcrc.dmi new file mode 100644 index 000000000000..f3bffe07d5d9 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/pcrc.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/pilot.dmi b/mods/content/corporate/icons/clothing/under/pilot.dmi new file mode 100644 index 000000000000..956101e2af94 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/pilot.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/pilot_heph.dmi b/mods/content/corporate/icons/clothing/under/pilot_heph.dmi new file mode 100644 index 000000000000..658f129b22c6 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/pilot_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/pilot_nt.dmi b/mods/content/corporate/icons/clothing/under/pilot_nt.dmi new file mode 100644 index 000000000000..eb649c789c84 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/pilot_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/polo.dmi b/mods/content/corporate/icons/clothing/under/polo.dmi new file mode 100644 index 000000000000..c2bf51629553 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/polo.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/polo_heph.dmi b/mods/content/corporate/icons/clothing/under/polo_heph.dmi new file mode 100644 index 000000000000..9ebdc586ea29 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/polo_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/polo_nt.dmi b/mods/content/corporate/icons/clothing/under/polo_nt.dmi new file mode 100644 index 000000000000..8ccaef3eeb55 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/polo_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/polo_zeng.dmi b/mods/content/corporate/icons/clothing/under/polo_zeng.dmi new file mode 100644 index 000000000000..f74a7403348b Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/polo_zeng.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/saare.dmi b/mods/content/corporate/icons/clothing/under/saare.dmi new file mode 100644 index 000000000000..8d912786a710 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/saare.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/sec_corporate.dmi b/mods/content/corporate/icons/clothing/under/sec_corporate.dmi new file mode 100644 index 000000000000..e0b9a156a3e4 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/sec_corporate.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/skinner.dmi b/mods/content/corporate/icons/clothing/under/skinner.dmi new file mode 100644 index 000000000000..eec031f55356 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/skinner.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/warden_corporate.dmi b/mods/content/corporate/icons/clothing/under/warden_corporate.dmi new file mode 100644 index 000000000000..2616040f2e90 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/warden_corporate.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/wardt.dmi b/mods/content/corporate/icons/clothing/under/wardt.dmi new file mode 100644 index 000000000000..7caceac5affe Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/wardt.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/work.dmi b/mods/content/corporate/icons/clothing/under/work.dmi new file mode 100644 index 000000000000..fbd90d46df08 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/work.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/work_heph.dmi b/mods/content/corporate/icons/clothing/under/work_heph.dmi new file mode 100644 index 000000000000..dfbae0e0f3c8 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/work_heph.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/work_nt.dmi b/mods/content/corporate/icons/clothing/under/work_nt.dmi new file mode 100644 index 000000000000..31174887aa70 Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/work_nt.dmi differ diff --git a/mods/content/corporate/icons/clothing/under/work_zeng.dmi b/mods/content/corporate/icons/clothing/under/work_zeng.dmi new file mode 100644 index 000000000000..24d4a28e602d Binary files /dev/null and b/mods/content/corporate/icons/clothing/under/work_zeng.dmi differ diff --git a/mods/content/corporate/icons/corpregs.dmi b/mods/content/corporate/icons/corpregs.dmi new file mode 100644 index 000000000000..c39b952f51f6 Binary files /dev/null and b/mods/content/corporate/icons/corpregs.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/bishop/bishop_main.dmi b/mods/content/corporate/icons/cyberlimbs/bishop/bishop_main.dmi new file mode 100644 index 000000000000..97cee647880b Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/bishop/bishop_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/bishop/bishop_rook.dmi b/mods/content/corporate/icons/cyberlimbs/bishop/bishop_rook.dmi new file mode 100644 index 000000000000..e32cd73d76bc Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/bishop/bishop_rook.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_main.dmi b/mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_main.dmi new file mode 100644 index 000000000000..c5459759caf2 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_titan.dmi b/mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_titan.dmi new file mode 100644 index 000000000000..537c9ce68790 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/hephaestus/hephaestus_titan.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_main.dmi b/mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_main.dmi new file mode 100644 index 000000000000..4e93da50ad58 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_mantis.dmi b/mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_mantis.dmi new file mode 100644 index 000000000000..3e67999d7725 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/morpheus/morpheus_mantis.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/nanotrasen/nanotrasen_main.dmi b/mods/content/corporate/icons/cyberlimbs/nanotrasen/nanotrasen_main.dmi new file mode 100644 index 000000000000..66d0bbdb8704 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/nanotrasen/nanotrasen_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/shellguard/shellguard_main.dmi b/mods/content/corporate/icons/cyberlimbs/shellguard/shellguard_main.dmi new file mode 100644 index 000000000000..f0f2ad5f42ea Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/shellguard/shellguard_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/veymed/veymed_female.dmi b/mods/content/corporate/icons/cyberlimbs/veymed/veymed_female.dmi new file mode 100644 index 000000000000..26b92416d23c Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/veymed/veymed_female.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/veymed/veymed_male.dmi b/mods/content/corporate/icons/cyberlimbs/veymed/veymed_male.dmi new file mode 100644 index 000000000000..b4fd5806bb0b Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/veymed/veymed_male.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi b/mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi new file mode 100644 index 000000000000..e5357284eff4 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi b/mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi new file mode 100644 index 000000000000..1fb14207c9b4 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/xion/xion_econo.dmi b/mods/content/corporate/icons/cyberlimbs/xion/xion_econo.dmi new file mode 100644 index 000000000000..7bb9044f86be Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/xion/xion_econo.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/xion/xion_main.dmi b/mods/content/corporate/icons/cyberlimbs/xion/xion_main.dmi new file mode 100644 index 000000000000..b404f1873886 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/xion/xion_main.dmi differ diff --git a/mods/content/corporate/icons/cyberlimbs/zenghu/zenghu_spirit.dmi b/mods/content/corporate/icons/cyberlimbs/zenghu/zenghu_spirit.dmi new file mode 100644 index 000000000000..ab9adde10b21 Binary files /dev/null and b/mods/content/corporate/icons/cyberlimbs/zenghu/zenghu_spirit.dmi differ diff --git a/mods/content/corporate/icons/lunchbox_dais.dmi b/mods/content/corporate/icons/lunchbox_dais.dmi new file mode 100644 index 000000000000..263a12f78f54 Binary files /dev/null and b/mods/content/corporate/icons/lunchbox_dais.dmi differ diff --git a/mods/content/corporate/icons/lunchbox_nanotrasen.dmi b/mods/content/corporate/icons/lunchbox_nanotrasen.dmi new file mode 100644 index 000000000000..8f07f564beb6 Binary files /dev/null and b/mods/content/corporate/icons/lunchbox_nanotrasen.dmi differ diff --git a/mods/corporate/icons/obj/wristcomp.dmi b/mods/content/corporate/icons/obj/wristcomp.dmi similarity index 100% rename from mods/corporate/icons/obj/wristcomp.dmi rename to mods/content/corporate/icons/obj/wristcomp.dmi diff --git a/mods/corporate/icons/obj/wristcomp_screens.dmi b/mods/content/corporate/icons/obj/wristcomp_screens.dmi similarity index 100% rename from mods/corporate/icons/obj/wristcomp_screens.dmi rename to mods/content/corporate/icons/obj/wristcomp_screens.dmi diff --git a/mods/content/corporate/items/badges.dm b/mods/content/corporate/items/badges.dm new file mode 100644 index 000000000000..3b91557c4f6a --- /dev/null +++ b/mods/content/corporate/items/badges.dm @@ -0,0 +1,30 @@ +/obj/item/box/holobadgeNT + name = "corporate holobadge box" + desc = "A box containing corporate security holobadges." + +/obj/item/box/holobadgeNT/WillContain() + return list( + /obj/item/clothing/badge/holo/NT = 4, + /obj/item/clothing/badge/holo/cord/NT = 2 + ) + +/obj/item/clothing/badge/nanotrasen + name = "corporate badge" + desc = "A leather-backed plastic badge with a variety of information printed on it. Belongs to a corporate executive." + icon = 'icons/clothing/accessories/badges/detectivebadge.dmi' + badge_string = "Corporate Executive Body" + +/obj/item/clothing/badge/holo/NT + name = "corporate holobadge" + desc = "This glowing green badge marks the holder as a member of corporate security." + icon = 'mods/content/corporate/icons/clothing/accessories/holobadge.dmi' + color = null + badge_string = "Corporate Security" + badge_access = access_research + +/obj/item/clothing/badge/holo/cord/NT + name = "corporate holobadge" + desc = "This glowing green badge marks the holder as a member of corporate security." + color = null + badge_string = "Corporate Security" + badge_access = access_research diff --git a/mods/content/corporate/items/clutter.dm b/mods/content/corporate/items/clutter.dm new file mode 100644 index 000000000000..19ba76ee4557 --- /dev/null +++ b/mods/content/corporate/items/clutter.dm @@ -0,0 +1,41 @@ +/obj/item/toy/balloon/nanotrasen + name = "\improper 'motivational' balloon" + desc = "Man, I love NanoTrasen soooo much. I use only NanoTrasen products. You have NO idea." + icon_state = "ntballoon" + item_state = "ntballoon" + +/obj/item/lunchbox/dais + name = "\improper DAIS brand lunchbox" + icon = 'mods/content/corporate/icons/lunchbox_dais.dmi' + desc = "A little lunchbox. This one is branded with the Deimos Advanced Information Systems logo!" + +/obj/item/lunchbox/nt + name = "\improper NanoTrasen brand lunchbox" + icon = 'mods/content/corporate/icons/lunchbox_nanotrasen.dmi' + desc = "A little lunchbox. This one is branded with the NanoTrasen logo!" + +/obj/item/lunchbox/nt/filled + filled = TRUE + +/datum/fabricator_recipe/textiles/banner/nanotrasen + path = /obj/item/banner/nanotrasen + +/obj/item/banner/nanotrasen + name = "\improper NanoTrasen banner" + hung_desc = "The banner is emblazoned with the NanoTrasen logo." + desc = "A banner emblazoned with the NanoTrasen logo." + material_alteration = MAT_FLAG_ALTERATION_NONE + color = COLOR_NAVY_BLUE + trim_color = COLOR_GOLD + decals = list( + /decl/banner_symbol/nanotrasen = COLOR_WHITE + ) + +/obj/structure/banner_frame/nanotrasen + banner = /obj/item/banner/nanotrasen + +/decl/banner_symbol/nanotrasen + icon = 'mods/content/corporate/icons/banner_symbols.dmi' + name = "NanoTrasen logo" + icon_state = "nanotrasen" + uid = "symbol_corporate_nanotrasen" diff --git a/mods/content/corporate/items/cups.dm b/mods/content/corporate/items/cups.dm new file mode 100644 index 000000000000..6722c765d06c --- /dev/null +++ b/mods/content/corporate/items/cups.dm @@ -0,0 +1,20 @@ +/obj/item/chems/drinks/glass2/coffeecup/NT + name = "\improper NT coffee cup" + desc = "A red NanoTrasen coffee cup." + base_icon = "coffeecup_NT" + icon_state = "coffeecup_NT" + base_name = "\improper NT cup" + +/obj/item/chems/drinks/glass2/coffeecup/corp + name = "\improper EXO coffee cup" + desc = "A tasteful coffee cup in Expeditionary Corps Organisation corporate colours." + base_icon = "coffeecup_corp" + icon_state = "coffeecup_corp" + base_name = "\improper EXO cup" + +/obj/item/chems/drinks/glass2/coffeecup/dais + name = "\improper DAIS coffee cup" + desc = "A coffee cup imprinted with the stylish logo of Deimos Advanced Information Systems." + base_icon = "coffeecup_dais" + icon_state = "coffeecup_dais" + base_name = "\improper DAIS cup" \ No newline at end of file diff --git a/mods/content/corporate/items/documents.dm b/mods/content/corporate/items/documents.dm new file mode 100644 index 000000000000..c30ded152215 --- /dev/null +++ b/mods/content/corporate/items/documents.dm @@ -0,0 +1,116 @@ +/obj/item/documents/nanotrasen + name = "secret corporate documents" + desc = "\"Top Secret\" corporate documents, filled with complex diagrams, research procedures, and details on cloning or breeding rights to non-sapient species you encounter. It seems like they will be auctioning them off to the highest private bidder." + description_antag = "A conglomerate of powerful corporations seems to be wanting to create weaponized xenobiological species. Probably as a form of WMD, by your best guess." + icon_state = "docs_verified" + +/obj/item/book/fluff/nt_regs + name = "Corporate Regulations" + desc = "A set of corporate guidelines for employees of a megacorporation." + icon = 'mods/content/corporate/icons/corpregs.dmi' + author = "Employee Materials" + title = "Corporate Regulations" + fluff_text = "The book is empty..." + +/obj/item/book/union_charter + name = "\improper Union Charter" + unique = TRUE + title = "Union Charter of Workplace Rights" + author = "Corporate Union" + dat = {" + + Corporate Union Charter of Workplace Rights + + +

    0. Summary

    +
    +

    As a union representative, you are required to uphold the interests of contracted workers on your station or vessel. You are empowered to inspect workplaces and instigate cessation of contracted work when on green alert, with diminishing powers during a state of emergency. You do not have authority or jurisdiction over government or military workers, or any workers who are not card-carrying signatories to this Charter.

    +

    1. Introduction

    +

    This Charter of Rights sets out the rights and responsibilities of all workplace parties in the provision of decent and fair health, safety, compensation and rehabilitation systems and practices within affiliated workplaces. Regardless of jurisdiction, changes to occupational health and safety, compensation and rehabilitation law must not result in a diminution of the rights and entitlements of any worker.

    +

    This Charter does not apply to staff who are not signatory to the Solar Employee General Award, or are signatory to other workplace regulatory documents such as the internal protocols of your local legislative body. Union representatives must take care to ensure that their operations on mixed jurisdiction stations and vessels are restricted to those areas that have a union worker, contractor or labourer presence.

    +

    Workers must not be adversely affected by any employer moving between jurisdictions in relation to their OHS and workers compensation entitlements. Any proposed move between jurisdictions will only occur following genuine consultation and agreement with workers and their representatives and a process of public review, including public tribunal hearings.

    +

    Consistent with OHS and Worker Compensation Policy and interstellar standards, Solar law must ensure healthy and safe workplaces and a compensation and rehabilitation system which ensures that no worker is disadvantaged should they be injured at work.

    +

    All workers have the right to join a genuine trade union. Union organised workplaces are safer workplaces.

    +

    2. Security Levels

    +
    +

    On stations or vessels employing the standard Security Alert Level protocol, the following conditions apply:

    +
      +
    • On green alert, all particulars of this charter are considered valid and applicable.
    • +
    • Above green alert, union representatives are not permitted to conduct workplace inspections and are advised, but not required, to cease all union meetings or strike proceedings.
    • +
    • On red alert or above, this charter is suspended, and all union representatives and workers must follow directives from personnel authorized under red alert protocol.
    • +
    +

    3. Representation

    +
    +

    Every worker has the right to be represented on health, safety, compensation, rehabilitation and return to work issues, by their elected Union Representative and their union. Every worker has the right to elect health and safety representatives.

    +

    Unions have the right to:

    +
      +
    • Enter workplaces on health and safety issues;
    • +
    • Investigate breaches of health and safety laws;
    • +
    • Represent members and prospective members;
    • +
    • Initiate investigations and prosecutions for occupational health and safety breaches;
    • +
    • Initiate cessation of work in unsafe areas; and
    • +
    • Access all relevant information and reports.
    • +
    +

    Union Representatives have the right to:

    +
      +
    • Be democratically elected by a process determined by workers, in conjunction with their union;
    • +
    • Utilise legal rights and powers to represent workers on health and safety matters;
    • +
    • Inspect the workplace, within the agreed-upon confines previously noted;
    • +
    • Access relevant information and be informed of all incidents;
    • +
    • Be consulted by the employer before workplace changes occur that may affect health and safety;
    • +
    • Issue notices when breaches are detected;
    • +
    • Call in government inspectors;
    • +
    • Direct workers to cease work where there is a belief of immediate risk to health and safety;
    • +
    • Seek resolution of health and safety issues;
    • +
    • Perform all OHS activities on paid time and have adequate facilities;
    • +
    • Be assisted by any person at any time in the execution of union duties;
    • +
    • Be protected by law from discrimination, harassment, bullying, intimidation and prosecution;
    • +
    • Appeal any decision of a regulator or court regarding any health and safety, compensation or rehabilitation matter.
    • +
    +

    4. Workers

    +
    +

    Every worker has the right to: +

      +
    • A safe and healthy workplace;
    • +
    • Travel to and from work sites in safety and with appropriate protections;
    • +
    • Return home from work free of injury or illness;
    • +
    • Enjoy the highest level of protection, representation, compensation and rehabilitation, regardless of the jurisdiction within which they work;
    • +
    • Take collective action over any health and safety matter, including the right to cease unsafe or unhealthy work; and
    • +
    • Discuss, negotiate and be consulted and involved in all issues affecting their health, safety and welfare.
    • +
    +

    All workers (or prospective workers), including health and safety representatives, will be protected by law from discrimination, harassment, bullying or detriment to their employment because they have raised a health and safety issue, lodged a compensation claim or been involved in consultation on workplace health and safety matters.

    +

    4. Employer Responsibilities

    +
    +

    Persons who control, manage or own workplaces have an absolute duty of care without limitation to provide and maintain safe and healthy work environments. Employers will not shift jurisdictions to attempt to avoid their OHS and workers compensation responsibilities and obligations. Employers are subject to all the obligations and responsibilities contained within this Charter.

    +

    5. Compensation

    +
    +

    Following a physical or psychological injury, all workers have the right to a fair, just and equitable compensation system, which promotes the best medical and like support, the most effective rehabilitation for injured workers and facilitates a safe return to work that offers genuine job security. Workers' compensation standards are to:

    +
  • Be available to all members of the workforce;
  • +
  • Provide compensation for all injuries that arise from travel to, from or during work including and during recess breaks;
  • +
  • Be available upon the death of a worker and for dependants of that worker;
  • +
  • Be based on the 100% replacement of loss of income;
  • +
  • Provide total cost of medical rehabilitation and other related expenses;
  • +
  • Provide lump sum compensation for permanent disability;
  • +
  • Ensure common law rights;
  • +
  • Support rehabilitation and return to work;
  • +
  • Ensure that workers are entitled to timely and effective claim determination and dispute resolution processes;
  • +
  • Ensure the worker has access to the doctor of their choice; and
  • +
  • Not be eroded by companies seeking to self-insure in order to obtain lower OHS and worker's compensation entitlements for workers.
  • + +

    6. Rehabilitation

    +
    +

    All workers have the right to return to safe, suitable, meaningful and sustainable work, following the provision of quality rehabilitation services, commensurate to need. Rehabilitation will include the right to:

    +
      +
    • Union representation;
    • +
    • Fair, equitable, high quality, appropriate, effective and timely rehabilitation plans and services;
    • +
    • Consultation about all aspects of rehabilitation;
    • +
    • All documentation and information relating to their rehabilitation;
    • +
    • Privacy in the management of all records and information; and
    • +
    • Personal choice of medical provider and rehabilitation service, where facilities permit.
    • +
    + + "} + +/obj/item/folder/nt + desc = "A corporate folder." + icon_state = "folder_nt" diff --git a/mods/content/corporate/items/medals.dm b/mods/content/corporate/items/medals.dm new file mode 100644 index 000000000000..136cc53f5cd0 --- /dev/null +++ b/mods/content/corporate/items/medals.dm @@ -0,0 +1,19 @@ +/obj/item/clothing/medal/nanotrasen + name = "corporate merit medal" + desc = "An iron medal awarded to employees for merit." + icon = 'mods/content/corporate/icons/clothing/accessories/medal_iron.dmi' + +/obj/item/clothing/medal/nanotrasen/gold + name = "corporate command medal" + desc = "A gold medal awarded to employees for service as the Captain of a corporate facility, station, or vessel." + icon = 'mods/content/corporate/icons/clothing/accessories/medal_gold.dmi' + +/obj/item/clothing/medal/nanotrasen/silver + name = "corporate service medal" + desc = "A silver medal awarded to employees for distinguished service in support of corporate interests." + icon = 'mods/content/corporate/icons/clothing/accessories/medal_silver.dmi' + +/obj/item/clothing/medal/nanotrasen/bronze + name = "corporate sciences medal" + desc = "A bronze medal awarded to employees for significant contributions to the fields of science or engineering." + icon = 'mods/content/corporate/icons/clothing/accessories/medal_bronze.dmi' diff --git a/mods/content/corporate/items/random.dm b/mods/content/corporate/items/random.dm new file mode 100644 index 000000000000..54dde92f9ce0 --- /dev/null +++ b/mods/content/corporate/items/random.dm @@ -0,0 +1,10 @@ +/obj/random/maintenance/security/spawn_choices() + var/static/injected = FALSE + . = ..() + if(!injected) + .[/obj/item/clothing/head/soft/sec/corp] = 4 + .[/obj/item/clothing/head/beret/corp/sec] = 3 + .[/obj/item/clothing/head/beret/corp/sec/corporate/hos] = 3 + .[/obj/item/clothing/head/beret/corp/sec/navy/officer] = 3 + .[/obj/item/clothing/suit/armor/vest/security] = 2 + injected = TRUE \ No newline at end of file diff --git a/mods/content/corporate/items/stamps.dm b/mods/content/corporate/items/stamps.dm new file mode 100644 index 000000000000..35b358297287 --- /dev/null +++ b/mods/content/corporate/items/stamps.dm @@ -0,0 +1,39 @@ +/obj/item/stamp/captain + name = "captain's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_cap.dmi' + +/obj/item/stamp/hop + name = "head of personnel's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_cap.dmi' + +/obj/item/stamp/ce + name = "chief engineer's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_ce.dmi' + +/obj/item/stamp/rd + name = "chief science officer's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_rd.dmi' + +/obj/item/stamp/cmo + name = "chief medical officer's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_cmo.dmi' + +/obj/item/stamp/cargo + name = "cargo rubber stamp" + icon = 'icons/obj/items/stamps/stamp_cargo.dmi' + +/obj/item/stamp/qm + name = "quartermaster's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_cargo.dmi' + +/obj/item/stamp/hos + name = "chief of security's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_cos.dmi' + +/obj/item/stamp/ward + name = "warden's rubber stamp" + icon = 'icons/obj/items/stamps/stamp_brig.dmi' + +/obj/item/stamp/internalaffairs + name = "internal affairs' rubber stamp" + icon = 'icons/obj/items/stamps/stamp_solgov.dmi' diff --git a/mods/content/corporate/items/wristcomp.dm b/mods/content/corporate/items/wristcomp.dm new file mode 100644 index 000000000000..c3c2958b5904 --- /dev/null +++ b/mods/content/corporate/items/wristcomp.dm @@ -0,0 +1,42 @@ +/obj/item/modular_computer/pda/wrist + name = "wrist computer" + desc = "A wrist-mounted modular personal computer. Very stylish." + icon = 'mods/content/corporate/icons/obj/wristcomp.dmi' + screen_icon = 'mods/content/corporate/icons/obj/wristcomp_screens.dmi' + + slot_flags = SLOT_ID | SLOT_LOWER_BODY + color = COLOR_GUNMETAL + light_color = LIGHT_COLOR_GREEN + +/obj/item/modular_computer/pda/wrist/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay) + var/datum/extension/interactive/os/os = get_extension(src, /datum/extension/interactive/os) + var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) + if(slot == slot_wear_id_str) + if(assembly?.enabled) + var/image/I = image(screen_icon, icon_state = "[overlay.icon_state]-screen") + I.appearance_flags |= RESET_COLOR + I.color = (assembly.bsod || os?.updating) ? "#0000ff" : "#00ff00" + overlay.overlays += I + else + overlay.overlays += image(screen_icon, icon_state = "[overlay.icon_state]-screen_off") + for(var/decal in decals) + var/image/I = image(icon = overlay.icon, icon_state = "[overlay.icon_state]-[decal]") + I.appearance_flags |= RESET_COLOR + I.color = decals[decal] + overlay.overlays += I + . = ..() + +/obj/item/modular_computer/pda/wrist/attack_hand(var/mob/user) + if(user.check_dexterity(DEXTERITY_KEYBOARDS, TRUE) && loc == user && !user.restrained() && src == user.get_equipped_item(slot_wear_id_str)) + return attack_self(user) + return ..() + +// wrist box // +/obj/item/box/wrist + name = "box of spare wrist computers" + desc = "A box of spare wrist microcomputers." + icon_state = "pda" + +/obj/item/box/wrist/WillContain() + return list(/obj/item/modular_computer/pda/wrist = 5) diff --git a/mods/content/corporate/machines/machines.dm b/mods/content/corporate/machines/machines.dm new file mode 100644 index 000000000000..2f2efd541edd --- /dev/null +++ b/mods/content/corporate/machines/machines.dm @@ -0,0 +1,5 @@ +/obj/machinery/vending/dinnerware/Initialize(mapload, d, populate_parts) + products = products || list() + products[/obj/item/lunchbox/nt] = 3 + products[/obj/item/lunchbox/dais] = 3 + . = ..() diff --git a/maps/random_ruins/exoplanet_ruins/oldpod/oldpod.dm b/mods/content/corporate/random_ruins/exoplanet_ruins/oldpod/oldpod.dm similarity index 76% rename from maps/random_ruins/exoplanet_ruins/oldpod/oldpod.dm rename to mods/content/corporate/random_ruins/exoplanet_ruins/oldpod/oldpod.dm index 1dcce7d0a329..4175cd8f17c1 100644 --- a/maps/random_ruins/exoplanet_ruins/oldpod/oldpod.dm +++ b/mods/content/corporate/random_ruins/exoplanet_ruins/oldpod/oldpod.dm @@ -1,11 +1,11 @@ /datum/map_template/ruin/exoplanet/oldpod name = "old pod" - id = "oldpod" description = "A now unused, crashed escape pod." + prefix = "mods/content/corporate/random_ruins/exoplanet_ruins/" suffixes = list("oldpod/oldpod.dmm") cost = 0.5 template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS - ruin_tags = RUIN_HUMAN|RUIN_WRECK + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WRECK apc_test_exempt_areas = list( /area/map_template/oldpod = NO_APC ) diff --git a/mods/content/corporate/random_ruins/exoplanet_ruins/oldpod/oldpod.dmm b/mods/content/corporate/random_ruins/exoplanet_ruins/oldpod/oldpod.dmm new file mode 100644 index 000000000000..74757deebeea --- /dev/null +++ b/mods/content/corporate/random_ruins/exoplanet_ruins/oldpod/oldpod.dmm @@ -0,0 +1,583 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/wall/shuttle/dark{ + unique_merge_identifier = "oldpod" + }, +/area/map_template/oldpod) +"ab" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 1 + }, +/turf/floor/plating, +/area/map_template/oldpod) +"ac" = ( +/turf/wall/shuttle{ + unique_merge_identifier = "oldpod" + }, +/area/map_template/oldpod) +"ad" = ( +/obj/effect/wallframe_spawn/reinforced/hull, +/turf/floor/plating, +/area/map_template/oldpod) +"ae" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/hull, +/turf/floor/plating, +/area/map_template/oldpod) +"ag" = ( +/obj/structure/shuttle/engine/heater{ + dir = 1 + }, +/obj/effect/wallframe_spawn/reinforced/hull, +/turf/floor/plating, +/area/map_template/oldpod) +"ah" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, +/area/map_template/oldpod) +"ai" = ( +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aj" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, +/area/map_template/oldpod) +"ak" = ( +/obj/structure/bed, +/obj/abstract/landmark/corpse/doctor, +/obj/effect/decal/cleanable/blood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"al" = ( +/obj/structure/bed, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"am" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"an" = ( +/obj/effect/decal/cleanable/blood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"ao" = ( +/obj/structure/chair/shuttle{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"ap" = ( +/obj/structure/chair/shuttle{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aq" = ( +/obj/structure/closet/hydrant{ + pixel_x = 24; + dir = 8 + }, +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/filth, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"ar" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"as" = ( +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"at" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/blood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"au" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"av" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aw" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"ax" = ( +/obj/machinery/door/firedoor, +/obj/effect/wallframe_spawn/reinforced/hull, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, +/area/map_template/oldpod) +"ay" = ( +/obj/item/frame/air_alarm, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stock_parts/circuitboard/air_alarm, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"az" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aA" = ( +/obj/random/firstaid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aB" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aC" = ( +/obj/item/clothing/head/helmet/space/emergency, +/obj/item/clothing/suit/space/emergency, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aD" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/random/tech_supply, +/obj/item/tool/pickaxe, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aE" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/table, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aF" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aG" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/blood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aH" = ( +/obj/structure/cable/cyan{ + icon_state = "0-4" + }, +/obj/item/frame/apc, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/cell/crap/empty, +/obj/item/stock_parts/circuitboard/apc, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aI" = ( +/obj/structure/cable/cyan{ + icon_state = "2-8" + }, +/obj/effect/decal/cleanable/filth, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aJ" = ( +/obj/abstract/landmark/corpse/pirate, +/obj/item/gun/energy/retro/captain, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aK" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aL" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aM" = ( +/obj/abstract/landmark/corpse/scientist, +/obj/item/baton/cattleprod, +/obj/item/shard, +/obj/effect/decal/cleanable/blood, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aN" = ( +/obj/machinery/door/firedoor, +/obj/structure/wall_frame/hull, +/obj/structure/grille, +/obj/item/stack/material/rods/mapped/steel, +/obj/item/stack/material/rods/mapped/steel, +/obj/item/stack/material/rods/mapped/steel, +/obj/item/stack/material/rods/mapped/steel, +/obj/item/shard, +/obj/item/shard, +/obj/item/shard, +/obj/item/shard, +/turf/floor/plating, +/area/map_template/oldpod) +"aO" = ( +/obj/machinery/door/airlock/external{ + name = "escape pod airlock" + }, +/turf/floor/plating, +/area/map_template/oldpod) +"aP" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/structure/cable/cyan, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 5; + icon_state = "warning" + }, +/obj/machinery/power/smes/buildable/power_shuttle, +/turf/floor/plating, +/area/map_template/oldpod) +"aQ" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"aR" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9; + icon_state = "warning" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/item/firstaid/surgery, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"aS" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"aT" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5; + icon_state = "warning" + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/closet/crate/plastic/rations, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/gun/projectile/zipgun, +/obj/item/gun/projectile/zipgun, +/obj/item/gun/projectile/zipgun, +/obj/item/gun/projectile/zipgun, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"aU" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/floor/plating, +/area/map_template/oldpod) +"aV" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/item/clothing/head/helmet/space/emergency, +/turf/floor/plating, +/area/map_template/oldpod) +"aW" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/cable/cyan{ + icon_state = "0-2" + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/structure/closet/crate, +/obj/item/tank/oxygen, +/turf/floor/plating, +/area/map_template/oldpod) +"aX" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/optable, +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/decal/cleanable/blood, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"aY" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"aZ" = ( +/obj/machinery/sleeper/standard{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"ba" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/item/clothing/suit/space/emergency, +/turf/floor/plating, +/area/map_template/oldpod) +"bb" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/floor/plating, +/area/map_template/oldpod) +"bc" = ( +/obj/machinery/port_gen/pacman, +/obj/structure/cable/cyan, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/oldpod) +"bd" = ( +/obj/abstract/landmark/corpse/bridgeofficer, +/obj/effect/decal/cleanable/blood, +/turf/floor/tiled/monotile, +/area/map_template/oldpod) +"be" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10; + icon_state = "warning" + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table{ + name = "plastic table frame" + }, +/obj/random/firstaid, +/obj/random/firstaid, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"bf" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) +"bg" = ( +/obj/machinery/sleeper/standard{ + dir = 8 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 6; + icon_state = "warning" + }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white/monotile, +/area/map_template/oldpod) + +(1,1,1) = {" +aa +ac +ac +ac +ax +ae +ac +ac +ac +aa +"} +(2,1,1) = {" +ab +ag +ak +ar +ay +aG +ad +aU +ba +ac +"} +(3,1,1) = {" +ac +ac +al +as +az +am +aO +aV +bb +aO +"} +(4,1,1) = {" +ac +ah +al +at +aA +aH +ac +ac +ac +ac +"} +(5,1,1) = {" +ad +ai +am +au +aB +aI +aP +aW +bc +ad +"} +(6,1,1) = {" +ae +ai +an +av +aC +aJ +aQ +aK +bd +ae +"} +(7,1,1) = {" +ac +aj +ao +ao +aD +aK +aR +aX +be +ac +"} +(8,1,1) = {" +ac +ac +ap +ap +aE +aL +aS +aY +bf +ac +"} +(9,1,1) = {" +ab +ag +aq +aw +aF +aM +aT +aZ +bg +ac +"} +(10,1,1) = {" +aa +ac +ac +ac +ae +aN +ac +ac +ac +aa +"} diff --git a/mods/content/corporate/structures/lockers.dm b/mods/content/corporate/structures/lockers.dm new file mode 100644 index 000000000000..5116f72e02ce --- /dev/null +++ b/mods/content/corporate/structures/lockers.dm @@ -0,0 +1,56 @@ +/decl/closet_appearance/secure_closet/corporate + color = COLOR_GREEN_GRAY + decals = list( + "lower_holes" + ) + extra_decals = list( + "stripe_vertical_mid_full" = COLOR_GRAY80, + "research" = COLOR_OFF_WHITE + ) + +/obj/structure/closet/wardrobe/red/Initialize() + . = ..() + new /obj/item/clothing/head/beret/corp/sec/corporate/officer(src) + new /obj/item/clothing/head/beret/corp/sec/corporate/officer(src) + new /obj/item/clothing/head/beret/corp/sec/corporate/officer(src) + +/obj/structure/closet/secure_closet/hos/WillContain() + . = ..() + /obj/item/clothing/head/beret/corp/sec/corporate/hos + +/obj/structure/closet/secure_closet/warden/WillContain() + . = ..() + /obj/item/clothing/head/beret/corp/sec/corporate/warden + +/obj/structure/closet/secure_closet/security/WillContain() + . = ..() + . += /obj/item/clothing/suit/armor/vest/nt + . += /obj/item/clothing/head/soft/sec/corp + . += /obj/item/clothing/jumpsuit/security/corp + +/obj/structure/closet/wardrobe/red/Initialize() + . = ..() + new /obj/item/clothing/head/beret/corp/sec(src) + new /obj/item/clothing/head/beret/corp/sec(src) + new /obj/item/clothing/head/beret/corp/sec(src) + +/obj/structure/closet/secure_closet/captains/WillContain() + . = ..() + . += /obj/item/clothing/suit/armor/captain + . += /obj/item/clothing/suit/armor/vest/nt + +/obj/structure/closet/secure_closet/warden/WillContain() + . = ..() + . += /obj/item/clothing/head/helmet/corp + . += /obj/item/clothing/suit/armor/vest/nt + . += /obj/item/clothing/jumpsuit/warden/corp + +/obj/structure/closet/secure_closet/hos/WillContain() + . = ..() + . += /obj/item/clothing/head/helmet/corp + . += /obj/item/clothing/suit/armor/vest/nt + . += /obj/item/clothing/jumpsuit/head_of_security/corp + +/obj/structure/closet/secure_closet/hop/WillContain() + . = ..() + /obj/item/clothing/suit/armor/vest/nt + +/obj/structure/closet/secure_closet/pilot + jumpsuit_type = /obj/item/clothing/jumpsuit/pilot \ No newline at end of file diff --git a/mods/content/dungeon_loot/_dungeon_loot.dm b/mods/content/dungeon_loot/_dungeon_loot.dm new file mode 100644 index 000000000000..0591781ed1c4 --- /dev/null +++ b/mods/content/dungeon_loot/_dungeon_loot.dm @@ -0,0 +1,20 @@ +/* +This is pulled directly from Virgo. Credits to them. Modifications made for Lighthouse by Carl. +The below text is holdover from Virgo. + + +- - - - - - - - - - - +Basically, each player key gets one chance per loot pile to get them phat lewt. +When they click the pile, after a delay, they 'roll' if they get anything, using chance_nothing. If they're unlucky, they get nothing. +Otherwise, they roll up to two times, first a roll for rare things, using chance_rare. If they succeed, they get something quite good. +If that roll fails, they do one final roll, using chance_uncommon. If they succeed, they get something fairly useful. +If that fails again, they walk away with some common junk. +The same player cannot roll again, however other players can. This has two benefits. The first benefit is that someone raiding all of +maintenance will not deprive other people from a shot at loot, and that for the surface variants, it quietly encourages bringing along +buddies, to get more chances at getting cool things instead of someone going solo to hoard all the stuff. +Loot piles can be depleted, if loot_depleted is turned on. Note that players who searched the pile already won't deplete the loot furthers when searching again. +*/ + +/decl/modpack/dungeon_loot + name = "Dungeon Loot" + dreams = list("packrats") diff --git a/mods/content/dungeon_loot/_dungeon_loot.dme b/mods/content/dungeon_loot/_dungeon_loot.dme new file mode 100644 index 000000000000..ae3880c41646 --- /dev/null +++ b/mods/content/dungeon_loot/_dungeon_loot.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_DUNGEON_LOOT +#define MODPACK_DUNGEON_LOOT +// BEGIN_INCLUDE +#include "_dungeon_loot.dm" +#include "loot_pile.dm" +#include "subtypes\bookcase.dm" +#include "subtypes\exosuit.dm" +#include "subtypes\maint.dm" +#include "subtypes\surface.dm" +// END_INCLUDE +#endif diff --git a/mods/content/dungeon_loot/icons/loot_piles.dmi b/mods/content/dungeon_loot/icons/loot_piles.dmi new file mode 100644 index 000000000000..784f9e47b235 Binary files /dev/null and b/mods/content/dungeon_loot/icons/loot_piles.dmi differ diff --git a/mods/content/dungeon_loot/loot_pile.dm b/mods/content/dungeon_loot/loot_pile.dm new file mode 100644 index 000000000000..7944fbcb6986 --- /dev/null +++ b/mods/content/dungeon_loot/loot_pile.dm @@ -0,0 +1,131 @@ +/obj/structure/loot_pile + abstract_type = /obj/structure/loot_pile + name = "base loot pile" + desc = "If you can read me, this is bugged." + icon = 'mods/content/dungeon_loot/icons/loot_piles.dmi' + icon_state = "randompile" + density = FALSE + anchored = TRUE + + /// Keys that have searched this loot pile, with values of searched time. + var/list/searched_by + /// If true, the same person can loot multiple times. Mostly for debugging. + var/allow_multiple_looting = FALSE + /// Used so you can't spamclick to loot. + var/busy = FALSE + /// Unlucky people might need to loot multiple spots to find things. + var/chance_nothing = 0 + /// Probability of pulling from the uncommon_loot list. + var/chance_uncommon = 10 + /// Ditto, but for rare_loot list. + var/chance_rare = 1 + /// If true, loot piles can be 'depleted' after a certain number of searches by different players, where no more loot can be obtained. + var/loot_depletion = FALSE + /// When this reaches zero, and loot_depleted is true, you can't obtain anymore loot. + var/loot_left = 0 + /// If true, and if the loot gets depleted as above, the pile is deleted. + var/delete_on_depletion = FALSE + +/obj/structure/loot_pile/Initialize() + var/list/icon_states_to_use = get_icon_states_to_use() + if(LAZYLEN(icon_states_to_use)) + icon_state = pick(icon_states_to_use) + . = ..() + +/obj/structure/loot_pile/attack_ai(var/mob/user) + if(isrobot(user) && Adjacent(user)) + return attack_hand(user) + return ..() + +/obj/structure/loot_pile/attack_hand(mob/user) + + if(!isliving(user)) + return ..() + + var/mob/living/L = user + if(busy) + to_chat(L, SPAN_WARNING("\The [src] is already being searched.")) + return TRUE + + L.visible_message("\The [user] searches through \the [src].", SPAN_NOTICE("You search through \the [src]."), SPAN_NOTICE("You hear some rustling.")) + + //Do the searching + busy = TRUE + if(!do_after(user,rand(4 SECONDS,6 SECONDS),src)) + busy = FALSE + return TRUE + busy = FALSE + + // The loot's all gone. + if(loot_depletion && loot_left <= 0) + to_chat(L, SPAN_WARNING("\The [src] has been picked clean.")) + return TRUE + + //You already searched this one + if(!allow_multiple_looting && LAZYISIN(searched_by, user.ckey)) + to_chat(L, SPAN_WARNING("You can't find anything else vaguely useful in \the [src]. Another set of eyes might, however.")) + return TRUE + + // You got unlucky. + if(chance_nothing && prob(chance_nothing)) + to_chat(L, SPAN_WARNING("Nothing in this pile really catches your eye this time.")) + return TRUE + + // You found something! + LAZYDISTINCTADD(searched_by, user.ckey) + var/obj/item/loot = null + var/span = "notice" // Blue + + if(prob(chance_rare) && length(get_rare_loot())) // You won THE GRAND PRIZE! + loot = produce_rare_item() + span = "cult" // Purple and bold. + else if(prob(chance_uncommon) && length(get_uncommon_loot())) // Otherwise you might still get something good. + loot = produce_uncommon_item() + span = "alium" // Green + else if(length(get_common_loot())) // Welp. + loot = produce_common_item() + + if(loot) + loot.forceMove(get_turf(src)) + to_chat(L, SPAN_CLASS(span, "You found \a [loot]!")) + if(loot_depletion) + loot_left-- + if(loot_left <= 0) + to_chat(L, SPAN_WARNING("You seem to have gotten the last of the spoils inside \the [src].")) + if(delete_on_depletion) + qdel(src) + return TRUE + +/obj/structure/loot_pile/proc/produce_common_item() + var/list/common_loot = get_common_loot() + if(length(common_loot)) + var/path = pick(common_loot) + return new path(src) + +/obj/structure/loot_pile/proc/produce_uncommon_item() + var/list/uncommon_loot = get_uncommon_loot() + if(length(uncommon_loot)) + var/path = pick(uncommon_loot) + return new path(src) + +/obj/structure/loot_pile/proc/produce_rare_item() + var/list/rare_loot = get_rare_loot() + if(length(rare_loot)) + var/path = pick(rare_loot) + return new path(src) + +/// Returns a list of generally less-than-useful junk and filler, at least for maint loot piles. +/obj/structure/loot_pile/proc/get_common_loot() + return + +/// Returns a list of some maybe actually useful items, usually the reason someone bothers looking inside. +/obj/structure/loot_pile/proc/get_uncommon_loot() + return + +/// Returns a list of really powerful, or at least unique items. +/obj/structure/loot_pile/proc/get_rare_loot() + return + +/// Returns a list of icon states the pile can choose from on initialization. If empty or null, it will stay the initial icon_state. +/obj/structure/loot_pile/proc/get_icon_states_to_use() + return diff --git a/mods/content/dungeon_loot/subtypes/bookcase.dm b/mods/content/dungeon_loot/subtypes/bookcase.dm new file mode 100644 index 000000000000..4752b9d4bbf7 --- /dev/null +++ b/mods/content/dungeon_loot/subtypes/bookcase.dm @@ -0,0 +1,92 @@ +// Contains generic mundane/fantasy loot. +/obj/structure/loot_pile/bookcase + name = "bookcase" + desc = "A bookcase that has long since fallen into disrepair. It may still have some useful things left on its shelves..." + icon = 'icons/obj/structures/bookcase.dmi' + icon_state = "bookcase-damaged" // preview + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + material_alteration = MAT_FLAG_ALTERATION_ALL + /// 1-indexed, pick a random overlay to add corresponding to "loot[rand(1, loot_states)]". + var/loot_states = 3 + /// A text string corresponding to the icon_state of the loot overlay we're using. + var/loot_state + +/obj/structure/loot_pile/bookcase/update_material_name(override_name) + . = ..() + SetName("[pick("ruined", "destroyed", "dilapidated")] [name]") + +/obj/structure/loot_pile/bookcase/ebony + material = /decl/material/solid/organic/wood/ebony + color = /decl/material/solid/organic/wood/ebony::color + +/obj/structure/loot_pile/bookcase/get_icon_states_to_use() + var/static/list/icon_states_to_use = list("bookcase-damaged", "fancy-damaged") + return icon_states_to_use + +/obj/structure/loot_pile/bookcase/Initialize(ml, _mat, _reinf_mat) + if(isnum(loot_states) && loot_states > 0) + loot_state = "loot[rand(1, loot_states)]" + . = ..() + +/obj/structure/loot_pile/bookcase/on_update_icon() + . = ..() + if(loot_state) + add_overlay(overlay_image(icon, loot_state, null, RESET_COLOR|RESET_ALPHA)) + +/obj/structure/loot_pile/bookcase/get_common_loot() + var/static/list/common_loot = list( + /obj/item/paper/scroll, + /obj/item/paper/scroll, + /obj/item/paper/scroll, + /obj/item/pen/fancy/quill, + /obj/item/pen/fancy/quill, + /obj/item/clothing/neck/prayer_beads/random, + /obj/item/hourglass, + ) + return common_loot + +/obj/structure/loot_pile/bookcase/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/chems/glass/inkwell, + /obj/item/clothing/glasses/prescription/pincenez, + /obj/item/chems/drinks/bottle/wine, + /obj/item/stack/medical/ointment/crafted, + /obj/item/stack/medical/bandage/crafted, + ) + return uncommon_loot + +/obj/structure/loot_pile/bookcase/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/bone/skull, // unlucky! + /obj/item/pen/fancy/quill/goose, + /obj/item/clothing/gloves/ring/seal/signet, + /obj/item/chems/drinks/bottle/champagne, + /obj/item/chems/drinks/bottle/premiumwine, + ) + return rare_loot + +/// This spawns either a normal bookcase (20%), a damaged normal bookcase (60%), or a lootable decaying bookcase (20%). +/// There's also 20% chance to just spawn nothing. +/obj/random/dungeon_bookcase + name = "random dungeon bookcase" + icon = 'icons/obj/structures/bookcase.dmi' + icon_state = "bookcase-random" + spawn_nothing_percentage = 20 + +/obj/random/dungeon_bookcase/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/structure/bookcase/ebony = 40, + /obj/structure/bookcase/fancy/ebony = 40, + /obj/structure/loot_pile/bookcase/ebony = 20 + ) + return spawnable_choices + +/obj/random/dungeon_bookcase/spawn_item() + . = ..() + for(var/obj/structure/bookcase/bookcase in .) + if(prob(25)) + continue + var/bookcase_max_health = bookcase.get_max_health() + bookcase.take_damage(bookcase_max_health * rand(51, 70)/100) + bookcase.update_icon() \ No newline at end of file diff --git a/mods/content/dungeon_loot/subtypes/exosuit.dm b/mods/content/dungeon_loot/subtypes/exosuit.dm new file mode 100644 index 000000000000..e8a237e802c6 --- /dev/null +++ b/mods/content/dungeon_loot/subtypes/exosuit.dm @@ -0,0 +1,143 @@ +// Subtype for mecha and mecha accessories. These might not always be on the surface. +/obj/structure/loot_pile/exosuit + name = "pod wreckage" + desc = "The ruins of some unfortunate pod. Perhaps something is salvageable." + icon_state = "wreck" + icon = 'icons/mecha/mech_part_items.dmi' + density = TRUE + anchored = FALSE // In case a dead mecha-mob dies in a bad spot. + chance_uncommon = 20 + chance_rare = 10 + loot_depletion = TRUE + loot_left = 9 + abstract_type = /obj/structure/loot_pile/exosuit + +// Subtypes below. +/obj/structure/loot_pile/exosuit/powerloader + name = "powerloader exosuit wreckage" + desc = "The ruins of some unfortunate powerloader exosuit. Perhaps something is salvageable." + +/obj/structure/loot_pile/exosuit/powerloader/get_common_loot() + var/static/list/common_loot = list( + /obj/item/mech_component/manipulators/powerloader/painted, + /obj/item/mech_component/propulsion/powerloader/painted + ) + return common_loot + +/obj/structure/loot_pile/exosuit/powerloader/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/mech_equipment/drill/steel, + /obj/item/mech_equipment/clamp + ) + return uncommon_loot + +/obj/structure/loot_pile/exosuit/powerloader/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/mech_component/sensors/powerloader/painted, + /obj/item/mech_component/chassis/powerloader/painted + ) + return rare_loot + +/obj/structure/loot_pile/exosuit/firefighter + name = "firefighter exosuit wreckage" + desc = "The ruins of some unfortunate firefighter exosuit. Perhaps something is salvageable." + +/obj/structure/loot_pile/exosuit/firefighter/get_common_loot() + var/static/list/common_loot = list( + /obj/item/mech_component/manipulators/powerloader/painted, + /obj/item/mech_component/propulsion/powerloader/painted, + /obj/item/mech_component/chassis/heavy + ) + return common_loot + +/obj/structure/loot_pile/exosuit/firefighter/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/mech_equipment/drill/steel, + /obj/item/mech_equipment/mounted_system/extinguisher + ) + return uncommon_loot + +/obj/structure/loot_pile/exosuit/firefighter/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/mech_component/sensors/powerloader/painted + ) + return rare_loot + +/obj/structure/loot_pile/exosuit/combat + name = "combat exosuit wreckage" + desc = "The ruins of some unfortunate combat exosuit. Perhaps something is salvageable." + +/obj/structure/loot_pile/exosuit/combat/get_common_loot() + var/static/list/common_loot = list( + /obj/item/mech_component/manipulators/combat/painted, + /obj/item/mech_component/propulsion/combat/painted, + /obj/item/mech_equipment/flash, + /obj/item/mech_equipment/light + ) + return common_loot + +/obj/structure/loot_pile/exosuit/combat/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/mech_component/chassis/combat/painted, + /obj/item/mech_equipment/mounted_system/taser + ) + return uncommon_loot + +/obj/structure/loot_pile/exosuit/combat/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/mech_component/sensors/combat/painted, + /obj/item/mech_equipment/mounted_system/projectile/assault_rifle + ) + return rare_loot + +/obj/structure/loot_pile/exosuit/heavy + name = "heavy exosuit wreckage" + desc = "The ruins of some unfortunate heavy exosuit. Perhaps something is salvageable." + +/obj/structure/loot_pile/exosuit/heavy/get_common_loot() + var/static/list/common_loot = list( + /obj/item/mech_component/manipulators/heavy/painted, + /obj/item/mech_component/propulsion/heavy/painted, + /obj/item/mech_component/chassis/heavy/painted + ) + return common_loot + +/obj/structure/loot_pile/exosuit/heavy/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/mech_equipment/shields, + /obj/item/mech_equipment/mounted_system/taser + ) + return uncommon_loot + +/obj/structure/loot_pile/exosuit/heavy/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/mech_equipment/mounted_system/taser/laser, + /obj/item/mech_component/sensors/heavy/painted + ) + return rare_loot + +/obj/structure/loot_pile/exosuit/light + name = "light exosuit wreckage" + desc = "The ruins of some unfortunate light exosuit. Perhaps something is salvageable." + +/obj/structure/loot_pile/exosuit/light/get_common_loot() + var/static/list/common_loot = list( + /obj/item/mech_component/manipulators/light/painted, + /obj/item/mech_component/propulsion/light/painted, + /obj/item/mech_component/chassis/light/painted + ) + return common_loot + +/obj/structure/loot_pile/exosuit/light/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/mech_component/sensors/light/painted, + /obj/item/mech_equipment/light + ) + return uncommon_loot + +/obj/structure/loot_pile/exosuit/light/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/mech_equipment/catapult, + /obj/item/mech_equipment/sleeper + ) + return rare_loot diff --git a/mods/content/dungeon_loot/subtypes/maint.dm b/mods/content/dungeon_loot/subtypes/maint.dm new file mode 100644 index 000000000000..c4a3d31a6bed --- /dev/null +++ b/mods/content/dungeon_loot/subtypes/maint.dm @@ -0,0 +1,341 @@ +// Has large amounts of possible items, most of which may or may not be useful. +/obj/structure/loot_pile/maint + abstract_type = /obj/structure/loot_pile/maint + +/obj/structure/loot_pile/maint/get_icon_states_to_use() + var/static/list/icon_states_to_use = list( + "junk_pile1", + "junk_pile2", + "junk_pile3", + "junk_pile4", + "junk_pile5" + ) + return icon_states_to_use + +/obj/structure/loot_pile/maint/junk + name = "pile of junk" + desc = "Lots of junk lying around. They say one man's trash is another man's treasure." + +/obj/structure/loot_pile/maint/junk/get_common_loot() + var/static/list/common_loot = list( + /obj/item/flashlight/flare, + /obj/item/flashlight/flare/glowstick, + /obj/item/flashlight/flare/glowstick/blue, + /obj/item/flashlight/flare/glowstick/orange, + /obj/item/flashlight/flare/glowstick/red, + /obj/item/flashlight/flare/glowstick/yellow, + /obj/item/flashlight/pen, + /obj/item/cell, + /obj/item/cell/device, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas/half, + /obj/item/clothing/mask/breath, + /obj/item/chems/rag, + /obj/item/food/junk/liquidfood, + /obj/item/secure_storage/briefcase, + /obj/item/briefcase, + /obj/item/backpack, + /obj/item/backpack/satchel, + /obj/item/backpack/dufflebag, + /obj/item/box, + /obj/item/wallet, + /obj/item/clothing/shoes/galoshes, + /obj/item/clothing/shoes/color/black, + /obj/item/clothing/shoes/dress, + /obj/item/clothing/shoes/dress/white, + /obj/item/clothing/gloves/thick/botany, + /obj/item/clothing/gloves/latex, + /obj/item/clothing/gloves, + /obj/item/clothing/gloves/rainbow, + /obj/item/clothing/gloves/insulated/cheap, + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/glasses/meson, + /obj/item/clothing/glasses/meson/prescription, + /obj/item/clothing/glasses/welding, + /obj/item/clothing/head/bio_hood/general, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/head/hardhat/red, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/welding, + /obj/item/clothing/suit/hazardvest, + /obj/item/clothing/suit/space/emergency, + /obj/item/clothing/suit/jacket/bomber, + /obj/item/clothing/suit/bio_suit/general, + /obj/item/clothing/suit/jacket/hoodie/black, + /obj/item/clothing/suit/jacket/brown, + /obj/item/clothing/suit/jacket/leather, + /obj/item/clothing/suit/apron, + /obj/item/clothing/jumpsuit/grey, + /obj/item/clothing/shirt/syndicate/tacticool, + /obj/item/clothing/pants/casual/camo, + /obj/item/clothing/shirt/harness, + /obj/item/clothing/webbing, + /obj/item/cash/c1, + /obj/item/cash/c10, + /obj/item/cash/c20, + /obj/item/cash/c50, + /obj/item/frame/camera/kit, + /obj/item/caution, + /obj/item/caution/cone, + /obj/item/card/emag_broken, + /obj/item/camera, + /obj/item/modular_computer/pda, + /obj/item/radio/headset, + /obj/item/paicard, + ) + return common_loot + +/obj/structure/loot_pile/maint/junk/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/clothing/shoes/syndigaloshes, + /obj/item/clothing/gloves/insulated, + /obj/item/clothing/jumpsuit/tactical, + /obj/item/beartrap, + /obj/item/clothing/badge/press, + /obj/item/knife/combat, + /obj/item/knife/folding/combat/switchblade, + ) + return uncommon_loot + +/obj/structure/loot_pile/maint/junk/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/clothing/suit/armor/vest/heavy, + /obj/item/clothing/shoes/jackboots/swat/combat, + ) + return rare_loot + +// Contains mostly useless garbage. +/obj/structure/loot_pile/maint/trash + name = "pile of trash" + desc = "Lots of garbage in one place. Might be able to find something if you're in the mood for dumpster diving." + +/obj/structure/loot_pile/maint/trash/get_icon_states_to_use() + var/static/list/icon_states_to_use = list( + "trash_pile1", + "trash_pile2") + return icon_states_to_use + +/obj/structure/loot_pile/maint/trash/get_common_loot() + var/static/list/common_loot = list( + /obj/item/flame/candle/spent, + /obj/item/trash/candy, + /obj/item/trash/candy/proteinbar, + /obj/item/trash/cigbutt/spitgum, + /obj/item/trash/cheesie, + /obj/item/trash/chips, + /obj/item/trash/stick, + /obj/item/trash/liquidfood, + /obj/item/trash/pistachios, + /obj/item/plate, + /obj/item/trash/popcorn, + /obj/item/trash/raisins, + /obj/item/trash/semki, + /obj/item/trash/snack_bowl, + /obj/item/trash/sosjerky, + /obj/item/trash/syndi_cakes, + /obj/item/trash/tastybread, + /obj/item/chems/drinks/sillycup, + /obj/item/trash/driedfish, + /obj/item/trash/waffles, + /obj/item/trash/beef, + /obj/item/trash/beans, + /obj/item/trash/tomato, + /obj/item/trash/spinach, + /obj/item/food/spider, + /obj/item/chems/glass/bowl/mystery, + /obj/item/food/old/hotdog, + /obj/item/food/old/pizza, + /obj/item/ammo_casing, + /obj/item/stack/material/rods/mapped/steel/ten, + /obj/item/stack/material/sheet/mapped/steel/five, + /obj/item/stack/material/cardstock/mapped/cardboard/five, + /obj/item/poster, + /obj/item/newspaper, + /obj/item/paper/crumpled + ) + return common_loot + +/obj/structure/loot_pile/maint/trash/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/plate, + /obj/item/plate/tray, + /obj/item/chems/syringe/steroid, + /obj/item/pill_bottle/zoom, + /obj/item/pill_bottle/happy, + /obj/item/pill_bottle/painkillers + ) + return uncommon_loot + +// Contains loads of different types of boxes, which may have items inside! +/obj/structure/loot_pile/maint/boxfort + name = "pile of boxes" + desc = "A large pile of boxes sits here." + density = TRUE + +/obj/structure/loot_pile/maint/boxfort/get_icon_states_to_use() + var/static/list/icon_states_to_use = list("boxfort") + return icon_states_to_use + +/obj/structure/loot_pile/maint/boxfort/get_common_loot() + var/static/list/common_loot = list( + /obj/item/box, + /obj/item/box/beakers, + /obj/item/box/botanydisk, + /obj/item/box/cups, + /obj/item/box/botanydisk, + /obj/item/box/donkpockets, + /obj/item/box/fancy/donut, + /obj/item/box/fancy/donut/empty, + /obj/item/box/evidence, + /obj/item/box/lights/mixed, + /obj/item/box/lights/tubes, + /obj/item/box/lights/bulbs, + /obj/item/box/autoinjectors, + /obj/item/box/masks, + /obj/item/box/ids, + /obj/item/box/mousetraps, + /obj/item/box/syringes, + /obj/item/box/survival, + /obj/item/box/gloves, + /obj/item/box/PDAs, + ) + return common_loot + +/obj/structure/loot_pile/maint/boxfort/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/box/sinpockets, + /obj/item/box/ammo/practiceshells, + /obj/item/box/ammo/blanks, + /obj/item/box/smokes, + /obj/item/box/metalfoam, + /obj/item/box/handcuffs + ) + return uncommon_loot + +/obj/structure/loot_pile/maint/boxfort/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/box/flashbangs, + /obj/item/box/empslite, + /obj/item/box/ammo/flashshells, + /obj/item/box/ammo/stunshells, + /obj/item/box/teargas, + ) + return rare_loot + +// One of the more useful maint piles, contains electrical components. +/obj/structure/loot_pile/maint/technical + name = "broken machine" + desc = "A destroyed machine with unknown purpose, and doesn't look like it can be fixed. It might still have some functional components?" + density = TRUE + +/obj/structure/loot_pile/maint/technical/get_icon_states_to_use() + var/static/list/icon_states_to_use = list( + "technical_pile1", + "technical_pile2", + "technical_pile3" + ) + return icon_states_to_use + +/obj/structure/loot_pile/maint/technical/get_common_loot() + var/static/list/common_loot = list( + /obj/item/stock_parts/network_receiver, + /obj/item/stock_parts/radio/receiver, + /obj/item/stock_parts/radio/transmitter, + /obj/item/stock_parts/power/apc, + /obj/item/stock_parts/power/terminal, + /obj/item/stock_parts/power/battery, + /obj/item/stock_parts/item_holder/card_reader, + /obj/item/stock_parts/item_holder/disk_reader, + /obj/item/stock_parts/console_screen, + /obj/item/stock_parts/keyboard, + /obj/item/stock_parts/capacitor, + /obj/item/stock_parts/capacitor/adv, + /obj/item/stock_parts/capacitor/super, + /obj/item/stock_parts/manipulator, + /obj/item/stock_parts/manipulator/nano, + /obj/item/stock_parts/manipulator/pico, + /obj/item/stock_parts/matter_bin, + /obj/item/stock_parts/matter_bin/adv, + /obj/item/stock_parts/matter_bin/super, + /obj/item/stock_parts/scanning_module, + /obj/item/stock_parts/scanning_module/adv, + /obj/item/stock_parts/scanning_module/phasic, + /obj/item/stock_parts/subspace/amplifier, + /obj/item/stock_parts/subspace/analyzer, + /obj/item/stock_parts/subspace/ansible, + /obj/item/stock_parts/subspace/crystal, + /obj/item/stock_parts/subspace/filter, + /obj/item/stock_parts/subspace/transmitter, + /obj/item/stock_parts/subspace/treatment, + /obj/item/borg/upgrade/restart, + /obj/item/cell, + /obj/item/cell/high, + /obj/item/cell/device, + /obj/item/stock_parts/circuitboard/broken, + /obj/item/stock_parts/circuitboard/arcade, + /obj/item/stock_parts/circuitboard/autolathe, + /obj/item/stock_parts/circuitboard/recycler, + /obj/item/stock_parts/circuitboard/atmos_alert, + /obj/item/stock_parts/circuitboard/air_alarm, + /obj/item/stock_parts/circuitboard/fax_machine, + /obj/item/stock_parts/circuitboard/jukebox, + /obj/item/stock_parts/circuitboard/batteryrack, + /obj/item/stock_parts/circuitboard/message_monitor, + /obj/item/stock_parts/smes_coil, + /obj/item/scanner/gas, + /obj/item/scanner/health, + /obj/item/robotanalyzer, + /obj/item/lightreplacer, + /obj/item/radio, + /obj/item/hailer, + /obj/item/gps, + /obj/item/geiger, + /obj/item/scanner/spectrometer, + /obj/item/wrench, + /obj/item/screwdriver, + /obj/item/wirecutters, + /obj/item/scanner/mining, + /obj/item/multitool, + /obj/item/robot_parts/robot_component/binary_communication_device, + /obj/item/robot_parts/robot_component/armour, + /obj/item/robot_parts/robot_component/actuator, + /obj/item/robot_parts/robot_component/camera, + /obj/item/robot_parts/robot_component/diagnosis_unit, + /obj/item/robot_parts/robot_component/radio, + ) + return common_loot + +/obj/structure/loot_pile/maint/technical/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/cell/super, + /obj/item/cell/gun, + /obj/item/aiModule/reset, + /obj/item/stock_parts/smes_coil/super_capacity, + /obj/item/stock_parts/smes_coil/super_io, + /obj/item/camera/tvcamera, + /obj/item/aicard, + /obj/item/borg/upgrade/jetpack, + /obj/item/borg/upgrade/vtec, + /obj/item/borg/upgrade/weaponcooler, + /obj/item/rig_module/device/drill, + /obj/item/rig_module/mounted/plasmacutter, + /obj/item/rig_module/device/healthscanner, + /obj/item/rig_module/device/orescanner, + /obj/item/rig_module/device/anomaly_scanner, + /obj/item/rig_module/datajack, + /obj/item/rig_module/vision/medhud, + /obj/item/rig_module/vision/meson, + /obj/item/rig_module/vision/sechud, + ) + return uncommon_loot + +/obj/structure/loot_pile/maint/technical/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/cell/hyper, + /obj/item/aiModule/freeform, + /obj/item/aiModule/asimov, + /obj/item/aiModule/paladin, + /obj/item/aiModule/safeguard, + ) + return rare_loot + diff --git a/mods/content/dungeon_loot/subtypes/surface.dm b/mods/content/dungeon_loot/subtypes/surface.dm new file mode 100644 index 000000000000..6cf1529d79a6 --- /dev/null +++ b/mods/content/dungeon_loot/subtypes/surface.dm @@ -0,0 +1,58 @@ +// Surface base type +/obj/structure/loot_pile/surface + // Surface loot piles are considerably harder and more dangerous to reach, so you're more likely to get rare things. + chance_uncommon = 20 + chance_rare = 5 + loot_depletion = TRUE + loot_left = 5 // This is to prevent people from asking the whole station to go down to some alien ruin to get massive amounts of phat lewt. + abstract_type = /obj/structure/loot_pile/surface + +// Contains old mediciation, most of it unidentified and has a good chance of being useless. +/obj/structure/loot_pile/surface/medicine_cabinet + name = "abandoned medicine cabinet" + desc = "An old cabinet, it might still have something of use inside." + icon_state = "medicine_cabinet" + density = FALSE + chance_uncommon = 1 + chance_rare = 1 + +/obj/structure/loot_pile/surface/medicine_cabinet/get_common_loot() + var/static/list/common_loot = list( + /obj/item/pill_bottle/sugariron, + /obj/item/stack/medical/bandage, + /obj/item/stack/medical/ointment, + /obj/item/med_pouch/trauma, + /obj/item/med_pouch/burn, + /obj/item/med_pouch/toxin, + /obj/item/med_pouch/radiation, + /obj/item/med_pouch/oxyloss, + /obj/item/chems/hypospray/autoinjector/stabilizer + ) + return common_loot + +/obj/structure/loot_pile/surface/medicine_cabinet/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/pill_bottle/painkillers, + /obj/item/stack/medical/splint, + /obj/item/pill_bottle/burn_meds, + /obj/item/pill_bottle/brute_meds, + /obj/item/pill_bottle/antitoxins, + /obj/item/pill_bottle/antibiotics, + /obj/item/pill_bottle/oxygen + ) + return uncommon_loot + +/obj/structure/loot_pile/surface/medicine_cabinet/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/stack/medical/bandage/advanced, + /obj/item/stack/medical/ointment/advanced, + /obj/item/pill_bottle/strong_painkillers + ) + return rare_loot + +// Like the above but has way better odds, in exchange for being in a place still inhabited (or was recently). +/obj/structure/loot_pile/surface/medicine_cabinet/fresh + name = "medicine cabinet" + desc = "A cabinet designed to hold medicine, it might still have something of use inside." + chance_uncommon = 20 + chance_rare = 5 diff --git a/mods/content/exploration/_exploration.dm b/mods/content/exploration/_exploration.dm new file mode 100644 index 000000000000..f96b87fbdd07 --- /dev/null +++ b/mods/content/exploration/_exploration.dm @@ -0,0 +1,2 @@ +/decl/modpack/exploration + name = "Exploration Content" diff --git a/mods/content/exploration/_exploration.dme b/mods/content/exploration/_exploration.dme new file mode 100644 index 000000000000..5c69cbfa8f0f --- /dev/null +++ b/mods/content/exploration/_exploration.dme @@ -0,0 +1,22 @@ +#ifndef CONTENT_PACK_EXPLORATION +#define CONTENT_PACK_EXPLORATION +// BEGIN_INCLUDE +#include "_exploration.dm" +#include "access.dm" +#include "projectiles.dm" +#include "screen_cataloguer.dm" +#include "specimen_codex.dm" +#include "specimen_mob.dm" +#include "equipment\cataloguer.dm" +#include "equipment\clothing.dm" +#include "equipment\device.dm" +#include "equipment\guns.dm" +#include "equipment\loadout.dm" +#include "equipment\melee.dm" +#include "equipment\radios.dm" +#include "equipment\specimen_tag.dm" +#include "equipment\specimen_tagger.dm" +#include "structures\closets.dm" +#include "structures\stasis_cage.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/exploration/access.dm b/mods/content/exploration/access.dm new file mode 100644 index 000000000000..48e7c0abd2dd --- /dev/null +++ b/mods/content/exploration/access.dm @@ -0,0 +1,11 @@ +var/global/const/access_xenofauna = "ACCESS_XENOFAUNA" +/datum/access/xenofauna + id = access_xenofauna + desc = "Xenfauna Lab" + region = ACCESS_REGION_RESEARCH + +var/global/const/access_explorer = "ACCESS_EXPLORER" +/datum/access/explorer + id = access_explorer + desc = "Explorer" + region = ACCESS_REGION_GENERAL diff --git a/mods/content/exploration/equipment/cataloguer.dm b/mods/content/exploration/equipment/cataloguer.dm new file mode 100644 index 000000000000..03487b39c1ad --- /dev/null +++ b/mods/content/exploration/equipment/cataloguer.dm @@ -0,0 +1,213 @@ +/obj/item/cataloguer + name = "cataloguer" + desc = "A hand-held device used for compiling information about an object by scanning it, and then uploading it to the local codex. Alt-click to highlight scannable objects around you." + color = COLOR_GUNMETAL + icon = 'mods/content/exploration/icons/cataloguer.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_NORMAL + origin_tech = @'{"materials":2, "programming":3,"magnets":3}' + _base_attack_force = 0 + item_flags = ITEM_FLAG_NO_BLUDGEON + slot_flags = SLOT_LOWER_BODY + material = /decl/material/solid/organic/plastic + matter = list( + /decl/material/solid/metal/aluminium = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/glass = MATTER_AMOUNT_TRACE, + /decl/material/solid/metal/copper = MATTER_AMOUNT_TRACE + ) + + /// Color of the glow effect when scanning. + var/glow_colour = COLOR_LIME + /// Multiplier for the base scan delay. + var/scan_speed_modifier = 1 + /// How many tiles away it can scan. Changing this also changes the box size. + var/scan_range = 3 + /// How much to make the next scan shorter. + var/tmp/partial_scan_time = 0 + /// Weakref of the thing that was last scanned if inturrupted. Used to allow for partial scans to be resumed. + var/tmp/weakref/partial_scanned + /// Set to a user mob when scanning, to stop multiple scans. + var/weakref/scanning + /// Dummy object for holding the scanning effect. + var/obj/screen/scan_radius/scan_radius_overlay + /// Holder for the currently scanning beam effect. + var/datum/beam/scan_beam + /// Currently loaded survey disk for storing Good Boy Points. + var/obj/item/disk/survey/loaded_disk + +/obj/item/cataloguer/Initialize(ml, material_key) + . = ..() + update_icon() + set_scan_radius(scan_range, TRUE) + +/obj/item/cataloguer/Destroy() + QDEL_NULL(loaded_disk) + QDEL_NULL(scan_beam) + stop_scan() + scanning = null + QDEL_NULL(scan_radius_overlay) + return ..() + +/obj/item/cataloguer/physically_destroyed(skip_qdel) + if(loaded_disk) + loaded_disk.dropInto(loc) + loaded_disk = null + return ..() + +/obj/item/cataloguer/mapped/Initialize(ml, material_key) + . = ..() + loaded_disk = new(src) + +/obj/item/cataloguer/proc/set_scan_radius(var/new_range, var/forced) + if(!forced && new_range == scan_range) + return FALSE + + scan_range = new_range + QDEL_NULL(scan_radius_overlay) + scan_radius_overlay = new + scan_radius_overlay.color = glow_colour + scan_radius_overlay.set_radius(new_range) + return TRUE + +/obj/item/cataloguer/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + if(scanning && check_state_in_icon("[icon_state]_glow", icon)) + var/image/I + if(plane == HUD_PLANE) + I = image(icon, "[icon_state]_glow") + else + I = emissive_overlay(icon, "[icon_state]_glow") + I.appearance_flags |= RESET_COLOR + I.color = glow_colour + add_overlay(I) + +/obj/item/cataloguer/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(scanning) + to_chat(user, SPAN_WARNING("\The [src] is already scanning something.")) + return + start_scan(target, user) + +/obj/item/cataloguer/attack_self(mob/user) + if(loaded_disk) + to_chat(user, SPAN_NOTICE("You pop \the [loaded_disk] out of \the [src].")) + loaded_disk.dropInto(loc) + user.put_in_hands(loaded_disk) + loaded_disk = null + playsound(user.loc, 'sound/weapons/flipblade.ogg', 50, 1) + return TRUE + return ..() + +/obj/item/cataloguer/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/disk/survey)) + if(loaded_disk) + to_chat(user, SPAN_WARNING("\The [src] already has a disk loaded.")) + else if(user.try_unequip(used_item, src)) + loaded_disk = used_item + playsound(user.loc, 'sound/weapons/flipblade.ogg', 50, 1) + to_chat(user, SPAN_NOTICE("You slot \the [used_item] into \the [src].")) + return TRUE + return ..() + +/obj/item/cataloguer/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(loaded_disk) + . += "It has \a [loaded_disk] slotted into the storage port. The display indicates it currently holds [loaded_disk.data] good explorer point\s." + +/obj/item/cataloguer/proc/stop_scan(var/interrupted = TRUE, var/mob/user, var/fade_out = 0) + + if(!scanning) + return + + if(scan_beam) + QDEL_NULL(scan_beam) + + var/atom/movable/thing = partial_scanned?.resolve() + if(istype(thing)) + thing.remove_filter("cataloguer_glow") + + if(interrupted) + playsound(src, 'sound/machines/buzz-two.ogg', 50) + scan_radius_overlay.color = COLOR_RED + + scan_radius_overlay.fade_out(user, fade_out) + scanning = null + update_icon() + +/obj/item/cataloguer/proc/start_scan(var/atom/target, var/mob/user) + + set waitfor = FALSE + + if(scanning) + return + + if(!loaded_disk) + playsound(user.loc, 'sound/weapons/empty.ogg', 60, 1) + to_chat(user, SPAN_WARNING("\The [src] has no disk loaded and cannot store scan results.")) + return + + var/datum/extension/scannable/scannable = get_extension(target, /datum/extension/scannable) + if(!scannable?.is_scannable()) + to_chat(user, SPAN_WARNING("\The [src] can tell you nothing new about \the [target].")) + return + + if(get_dist(target, user) > scan_range) + to_chat(user, SPAN_WARNING("You are too far away from \the [target] to catalogue it. Get closer.")) + return + + var/scan_delay = scannable.scan_delay * scan_speed_modifier + if(partial_scanned && partial_scanned.resolve() == target) + scan_delay -= partial_scan_time + to_chat(user, SPAN_NOTICE("Resuming previous scan.")) + else + to_chat(user, SPAN_NOTICE("Scanning new target. Previous scan buffer cleared.")) + partial_scanned = weakref(target) + partial_scan_time = 0 + + scanning = weakref(user) + + update_icon() + + playsound(src, 'sound/machines/twobeep.ogg', 50) + + // Reset visual properties of the overlay. + scan_radius_overlay.alpha = 0 + scan_radius_overlay.color = glow_colour + + // Add the scan overlay to the client. + if(scan_radius_overlay.holder_image) + scan_radius_overlay.holder_image.vis_contents.Cut() + scan_radius_overlay.holder_image = new + scan_radius_overlay.holder_image.vis_contents += scan_radius_overlay + scan_radius_overlay.holder_image.loc = target + + // Center the scan range overlay on the atom's actual turf. + scan_radius_overlay.holder_image.pixel_x = -(target.pixel_x) + scan_radius_overlay.holder_image.pixel_y = -(target.pixel_y) + + // Now make it visible. + if(user.client) + user.client.images += scan_radius_overlay.holder_image + animate(scan_radius_overlay, alpha = initial(scan_radius_overlay.alpha), time = 5) + + // Draw glow filter over target. + if(ismovable(target)) + var/atom/movable/thing = target + thing.add_filter("cataloguer_glow", 1, list(type = "drop_shadow", color = glow_colour, size = 4, offset = 1, x = 0, y = 0)) + + scan_beam = user.Beam(target, "scanner", time = scan_delay, maxdistance = scan_range+1, beam_color = glow_colour) + + var/started_scan = world.time + var/interrupted = !do_after(user, scan_delay, target, can_move = TRUE, max_distance = scan_range, check_in_view = TRUE) || !loaded_disk + partial_scan_time += world.time - started_scan + + stop_scan(interrupted, user, fade_out = 5) + if(!interrupted && scannable?.is_scannable()) + playsound(src, 'sound/machines/ping.ogg', 50) + var/datum/codex_entry/scannable/scan_result = scannable.scanned() + if(scan_result) + loaded_disk.data += scan_result.worth_points + to_chat(user, SPAN_NOTICE("You complete the scan of \the [target], earning [scan_result.worth_points] good explorer point\s.")) + +/datum/fabricator_recipe/device_component/cataloguer + path = /obj/item/cataloguer diff --git a/mods/content/exploration/equipment/clothing.dm b/mods/content/exploration/equipment/clothing.dm new file mode 100644 index 000000000000..fa986fb0f32d --- /dev/null +++ b/mods/content/exploration/equipment/clothing.dm @@ -0,0 +1,131 @@ +/obj/item/clothing/suit/explorer + name = "explorer suit" + desc = "An armoured suit for exploring harsh environments." + icon = 'mods/content/exploration/icons/suit_explo.dmi' + hood = /obj/item/clothing/head/hood/explorer + item_flags = ITEM_FLAG_THICKMATERIAL + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_ARMS + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + cold_protection = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_ARMS + siemens_coefficient = 0.9 + // Inferior to sec vests in bullet/laser but better for environmental protection. + armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_RESISTANT, + (ARMOR_BULLET) = ARMOR_BALLISTIC_SMALL, + (ARMOR_LASER) = ARMOR_LASER_SMALL, + (ARMOR_ENERGY) = ARMOR_ENERGY_SMALL, + (ARMOR_BOMB) = ARMOR_BOMB_PADDED, + (ARMOR_BIO) = ARMOR_BIO_STRONG, + (ARMOR_RAD) = ARMOR_RAD_RESISTANT + ) + allowed = list( + /obj/item/flashlight, + /obj/item/gun, + /obj/item/ammo_magazine, + /obj/item/knife, + /obj/item/bladed, + /obj/item/tank, + /obj/item/radio, + /obj/item/tool, + /obj/item/cataloguer, + /obj/item/specimen_tagger + ) + +/obj/item/clothing/suit/explorer/get_assumed_clothing_state_modifiers() + var/static/list/expected_state_modifiers = list( + GET_DECL(/decl/clothing_state_modifier/hood) + ) + return expected_state_modifiers + +/obj/item/clothing/head/hood/explorer + name = "explorer hood" + desc = "An armoured hood for exploring harsh environments." + icon = 'mods/content/exploration/icons/hood_explo.dmi' + item_flags = ITEM_FLAG_THICKMATERIAL + min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.9 + armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_RESISTANT, + (ARMOR_BULLET) = ARMOR_BALLISTIC_SMALL, + (ARMOR_LASER) = ARMOR_LASER_SMALL, + (ARMOR_ENERGY) = ARMOR_ENERGY_SMALL, + (ARMOR_BOMB) = ARMOR_BOMB_PADDED, + (ARMOR_BIO) = ARMOR_BIO_STRONG, + (ARMOR_RAD) = ARMOR_RAD_RESISTANT + ) + +/obj/item/clothing/suit/explorer/xenofauna + name = "xenofauna field suit" + desc = "A lightly armoured suit for surveying harsh environments." + icon = 'mods/content/exploration/icons/suit_xeno.dmi' + hood = /obj/item/clothing/head/hood/explorer/xenofauna + siemens_coefficient = 0.5 + // Better bio/rad protection than explo, but less armour. + armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_KNIVES, + (ARMOR_BULLET) = ARMOR_BALLISTIC_MINOR, + (ARMOR_LASER) = ARMOR_LASER_MINOR, + (ARMOR_ENERGY) = ARMOR_ENERGY_MINOR, + (ARMOR_BOMB) = ARMOR_BOMB_PADDED, + (ARMOR_BIO) = ARMOR_BIO_SHIELDED, + (ARMOR_RAD) = ARMOR_RAD_LARGE + ) + +/obj/item/clothing/head/hood/explorer/xenofauna + name = "xenofauna field hood" + desc = "A lightly armoured hood for surveying harsh environments." + siemens_coefficient = 0.5 + armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_KNIVES, + (ARMOR_BULLET) = ARMOR_BALLISTIC_MINOR, + (ARMOR_LASER) = ARMOR_LASER_MINOR, + (ARMOR_ENERGY) = ARMOR_ENERGY_MINOR, + (ARMOR_BOMB) = ARMOR_BOMB_PADDED, + (ARMOR_BIO) = ARMOR_BIO_SHIELDED, + (ARMOR_RAD) = ARMOR_RAD_LARGE + ) + icon = 'mods/content/exploration/icons/hood_xeno.dmi' + +/obj/item/clothing/shoes/winterboots/explorer + name = "explorer winter boots" + desc = "Steel-toed winter boots for mining or exploration in hazardous environments. Very good at keeping toes warm and uncrushed." + icon = 'mods/content/exploration/icons/boots_explo.dmi' + armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_RESISTANT, + (ARMOR_BULLET) = ARMOR_BALLISTIC_MINOR, + (ARMOR_LASER) = ARMOR_LASER_MINOR, + (ARMOR_ENERGY) = ARMOR_ENERGY_MINOR, + (ARMOR_BOMB) = ARMOR_BOMB_PADDED + ) + +/obj/item/clothing/jumpsuit/explorer + name = "explorer's jumpsuit" + desc = "A grey and cyan uniform for working in the field." + icon = 'mods/content/exploration/icons/uniform_explo.dmi' + +/obj/item/clothing/jumpsuit/xenofauna + name = "xenofauna technician's jumpsuit" + desc = "A grey and purple uniform for working in the field." + icon = 'mods/content/exploration/icons/uniform_xeno.dmi' + +/obj/item/clothing/mask/gas/explorer + icon = 'mods/content/exploration/icons/mask_explo.dmi' + name = "explorer gas mask" + desc = "A military-grade gas mask that can be connected to an air supply." + armor = list( + (ARMOR_MELEE) = ARMOR_MELEE_SMALL, + (ARMOR_BULLET) = ARMOR_BALLISTIC_MINOR, + (ARMOR_LASER) = ARMOR_LASER_MINOR, + (ARMOR_ENERGY) = ARMOR_ENERGY_MINOR, + (ARMOR_BIO) = ARMOR_BIO_RESISTANT, + ) + siemens_coefficient = 0.9 + +/obj/item/clothing/permit/gun/planetside + name = "planetside weapon permit" + desc = "A card indicating that the owner is allowed to carry a weapon while on the surface." + detail_color = COLOR_PALE_PINK + +/obj/item/clothing/permit/gun/planetside/exploration + name = "explorer weapon permit" + desc = "A card indicating that the owner is allowed to carry weaponry during active exploration missions." diff --git a/mods/content/exploration/equipment/device.dm b/mods/content/exploration/equipment/device.dm new file mode 100644 index 000000000000..75085d7bf7f3 --- /dev/null +++ b/mods/content/exploration/equipment/device.dm @@ -0,0 +1,16 @@ +/obj/item/gps/explorer + gps_tag = "EXP0" + color = "#4a4a4a" + decals = list( + "stripe-outside" = "#500677", + "stripe-inside" = "#68099e" + ) + +/obj/item/gps/xenofauna + color = "#b1b1b1" + decals = list( + "stripe-outside" = "#500677", + "stripe-inside" = "#68099e" + ) + gps_tag = "XEN0" + tag_categories = list("XENOFAUNA") diff --git a/mods/content/exploration/equipment/guns.dm b/mods/content/exploration/equipment/guns.dm new file mode 100644 index 000000000000..225e16f78e9d --- /dev/null +++ b/mods/content/exploration/equipment/guns.dm @@ -0,0 +1,53 @@ +/obj/item/gun/energy/gun/reloadable/phase + name = "phase carbine" + desc = "The RayZar EW26 Artemis is a downsized energy weapon, specifically designed for use against wildlife." + icon = 'mods/content/exploration/icons/phase_carbine.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_BACK|SLOT_LOWER_BODY + projectile_type = /obj/item/projectile/energy/phase // 50 damage against animals + one_hand_penalty = 15 + firemodes = null + indicator_color = COLOR_WHITE + charge_cost = 35 // ~14 shots + +/obj/item/gun/energy/gun/reloadable/phase/pistol + name = "phase pistol" + desc = "The RayZar EW15 Apollo is an energy handgun, specifically designed for self-defense against aggressive wildlife." + icon = 'mods/content/exploration/icons/phase_pistol.dmi' + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER + projectile_type = /obj/item/projectile/energy/phase/light // 40 damage on animals + one_hand_penalty = 0 + charge_cost = 25 // 20 shots + +/obj/item/gun/energy/gun/reloadable/phase/rifle + name = "phase rifle" + desc = "The RayZar EW31 Orion is a specialist energy weapon, intended for use against hostile wildlife." + icon = 'mods/content/exploration/icons/phase_rifle.dmi' + w_class = ITEM_SIZE_LARGE + slot_flags = SLOT_BACK + projectile_type = /obj/item/projectile/energy/phase/heavy // 60 damage on animals + charge_cost = 50 // 10 shots + accuracy = 15 + one_hand_penalty = 30 + +/obj/item/gun/energy/gun/reloadable/phase/tranq_rifle + name = "tranquilizer rifle" + desc = "A niche RayZar product designed for nonlethal animal control. A specialized emitter disrupts the nervous system of the target, eventually inducing sleep. Only rated for use on wildlife." + icon = 'mods/content/exploration/icons/tranq_rifle.dmi' + w_class = ITEM_SIZE_LARGE + slot_flags = SLOT_BACK + charge_cost = 25 // 20 shots + projectile_type = /obj/item/projectile/energy/phase/tranq + accuracy = 15 + one_hand_penalty = 30 + +/obj/item/gun/energy/gun/reloadable/phase/tranq_pistol + name = "tranquilizer pistol" + desc = "A niche RayZar product designed for nonlethal animal control. A specialized emitter disrupts the nervous system of the target, eventually inducing sleep. Only rated for use on wildlife." + icon = 'mods/content/exploration/icons/tranq_pistol.dmi' + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER + charge_cost = 15 // ~33 shots + projectile_type = /obj/item/projectile/energy/phase/tranq/weak + one_hand_penalty = 0 diff --git a/mods/content/exploration/equipment/loadout.dm b/mods/content/exploration/equipment/loadout.dm new file mode 100644 index 000000000000..30806beb0500 --- /dev/null +++ b/mods/content/exploration/equipment/loadout.dm @@ -0,0 +1,3 @@ +/decl/loadout_option/shoes/boots/get_gear_tweak_options() + . = ..() + .[/datum/gear_tweak/path/specified_types_list] |= /obj/item/clothing/shoes/winterboots/explorer diff --git a/mods/content/exploration/equipment/melee.dm b/mods/content/exploration/equipment/melee.dm new file mode 100644 index 000000000000..df69bcb97e74 --- /dev/null +++ b/mods/content/exploration/equipment/melee.dm @@ -0,0 +1,13 @@ +/obj/item/knife/folding/swiss/explorer + name = "explorer's combi-knife" + desc = "A small, purple, multi-purpose folding knife. This one adds a wood saw and prybar." + handle_color = COLOR_PURPLE + tools = list(SWISSKNF_LBLADE, SWISSKNF_SBLADE, SWISSKNF_CLIFTER, SWISSKNF_COPENER, SWISSKNF_WBLADE, SWISSKNF_CROWBAR) + +/obj/item/knife/survival + name = "survival knife" + desc = "A hunting-grade survival knife." + w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/items/bladed/knife.dmi' + _base_attack_force = 6 + material_alteration = MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC // base icon is too dark to work with steel color diff --git a/mods/content/exploration/equipment/radios.dm b/mods/content/exploration/equipment/radios.dm new file mode 100644 index 000000000000..a92f2579a907 --- /dev/null +++ b/mods/content/exploration/equipment/radios.dm @@ -0,0 +1,22 @@ +/obj/item/encryptionkey/heads/hop/Initialize() + . = ..() + LAZYDISTINCTADD(can_decrypt, access_explorer) + +/obj/item/encryptionkey/heads/captain/Initialize() + . = ..() + LAZYDISTINCTADD(can_decrypt, access_explorer) + +/obj/item/encryptionkey/heads/ai_integrated/Initialize() + . = ..() + LAZYDISTINCTADD(can_decrypt, access_explorer) + +/obj/item/radio/headset/headset_exp + name = "explorer's headset" + desc = "A small headset used by exploration, with access to the explorer and science channels." + icon = 'icons/obj/items/device/radio/headsets/headset_science.dmi' + encryption_keys = list(/obj/item/encryptionkey/exp) + +/obj/item/encryptionkey/exp + name = "exploration radio encryption key" + inlay_color = COLOR_SCIENCE_PURPLE + can_decrypt = list(access_research, access_explorer) diff --git a/mods/content/exploration/equipment/specimen_tag.dm b/mods/content/exploration/equipment/specimen_tag.dm new file mode 100644 index 000000000000..76d959208e1c --- /dev/null +++ b/mods/content/exploration/equipment/specimen_tag.dm @@ -0,0 +1,98 @@ +// Specimen tag itself. +/obj/item/gps/specimen_tag + name = "xenofauna tracker" + gps_tag = "FAUNA0" + icon = 'mods/content/exploration/icons/specimen_tag.dmi' + decal_icon = 'mods/content/exploration/icons/specimen_tag_overlays.dmi' + w_class = ITEM_SIZE_TINY + tag_category = "XENOFAUNA" + + var/age = 0 + var/mob/living/implanted_in + var/implanted_by + var/physical_info = "No notes recorded." + var/behavioral_info = "No notes recorded." + +/obj/item/gps/specimen_tag/Initialize(mapload, _age, _implanted_by, _specimen_id, _specimen_gender, _physical_info, _behavioral_info, _specimen_type) + // If we have a specimen, set up our data. + if(_specimen_type) + var/mob/living/critter = new _specimen_type(get_turf(src)) + implant(critter, TRUE) + if(_specimen_gender) + critter.gender = _specimen_gender + if(_age) + age = _age + if(_specimen_id) + gps_tag = _specimen_id + if(_physical_info) + physical_info = _physical_info + if(_behavioral_info) + behavioral_info = _behavioral_info + if(_implanted_by) + implanted_by = _implanted_by + . = ..() + if(!tracking) + toggle_tracking() + +/obj/item/gps/specimen_tag/Destroy() + clear_implanted() + . = ..() + +/obj/item/gps/specimen_tag/Move() + . = ..() + if(implanted_in && loc != implanted_in) + clear_implanted() + +// Specimen tags are just for tracking, they don't work as held GPS. +/obj/item/gps/specimen_tag/attack_hand(mob/living/user) + SHOULD_CALL_PARENT(FALSE) + toggle_tracking(user) + return TRUE +/obj/item/gps/specimen_tag/check_visible_to_holder() + return FALSE +/obj/item/gps/specimen_tag/create_compass() + return +/obj/item/gps/specimen_tag/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, master_ui, datum/topic_state/state) + return + +/obj/item/gps/specimen_tag/proc/has_been_implanted() + return !QDELETED(implanted_in) && istype(implanted_in) && loc == implanted_in + +/obj/item/gps/specimen_tag/proc/implant(var/mob/target, var/implanted_in_init = FALSE) + forceMove(target) + implanted_in = target + events_repository.register(/decl/observ/destroyed, implanted_in, src, /obj/item/gps/specimen_tag/proc/clear_implanted) + if(!implanted_in_init) + generate_critter_info() + +/obj/item/gps/specimen_tag/proc/generate_critter_info() + + var/list/possible_physical_info + var/list/possible_behavioral_info + var/datum/codex_entry/catalogue_data = SScodex.get_codex_entry(implanted_in.get_codex_value()) + if(istype(catalogue_data)) + var/notes = catalogue_data.get_fauna_physical_notes() + if(!isnull(notes)) + LAZYDISTINCTADD(possible_physical_info, notes) + notes = catalogue_data.get_fauna_behavior_notes() + if(!isnull(notes)) + LAZYDISTINCTADD(possible_behavioral_info, notes) + + if(LAZYLEN(possible_physical_info)) + physical_info = pick(possible_physical_info) + else + physical_info = "No notes recorded." + + if(LAZYLEN(possible_behavioral_info)) + behavioral_info = pick(possible_behavioral_info) + else + behavioral_info = "No notes recorded." + +/obj/item/gps/specimen_tag/proc/clear_implanted() + if(implanted_in) + events_repository.unregister(/decl/observ/destroyed, implanted_in, src) + implanted_in = null + +/obj/item/gps/specimen_tag/proc/update_from_animal() + return + diff --git a/mods/content/exploration/equipment/specimen_tagger.dm b/mods/content/exploration/equipment/specimen_tagger.dm new file mode 100644 index 000000000000..f3ae92479b8d --- /dev/null +++ b/mods/content/exploration/equipment/specimen_tagger.dm @@ -0,0 +1,115 @@ +// Device used to implant, remove or read specimen tags. + +/* Notes on specimen tagger and expected flow: + * - Xenofauna player uses tagger (/obj/item/specimen_tagger) on appropriate critter (appropriate type, has cataloguer info). + * - Tag (/obj/item/gps/specimen_tag) is created and registered in the critter. + * - Xenofauna players can then track the tag via GPS to scan, remove, etc. + * - When persistent specimens are committed, tags will be loaded and assigned to mobs at world init. + */ + +/obj/item/specimen_tagger + name = "specimen tagger" + desc = "A handheld device used to implant, remove and read xenofauna tracking tags from local specimens. Not for use on crewmembers." + icon = 'mods/content/exploration/icons/specimen_tagger.dmi' + icon_state = ICON_STATE_WORLD + _base_attack_force = 0 + item_flags = ITEM_FLAG_NO_BLUDGEON + var/tag_id = "FAUNA0" + +/obj/item/specimen_tagger/attack_self(mob/user) + var/new_tag = input("Please enter desired tag.", name, tag_id) as text + if(QDELETED(src) || QDELETED(user) || user.incapacitated() || loc != user) + return TRUE + new_tag = uppertext(copytext(sanitize(new_tag), 1, 11)) + if(!length(new_tag)) + return TRUE + tag_id = new_tag + to_chat(usr, "You set the tracker tag to '[tag_id]'.") + return TRUE + +/obj/item/specimen_tagger/get_examine_hints(mob/user, distance, infix, suffix) + . = ..() + . += "Use this on a living animal on help intent to read an existing tracker, grab intent to tag an animal with a tracker, and any other intent to remove an existing tracker." + +/obj/item/specimen_tagger/use_on_mob(mob/living/target, mob/living/user, animate) + SHOULD_CALL_PARENT(FALSE) + if(user.check_intent(I_FLAG_HELP)) + try_read_tag(user, target) + else if(user.check_intent(I_FLAG_GRAB)) + try_implant_tag(user, target) + else + try_remove_tag(user, target) + return TRUE + +/obj/item/specimen_tagger/proc/try_read_tag(var/mob/user, var/mob/living/target) + var/obj/item/gps/specimen_tag/xenotag = locate() in target + if(!istype(xenotag) || !xenotag.has_been_implanted()) + to_chat(user, SPAN_WARNING("\The [target] has not been tagged.")) + return FALSE + to_chat(user, "Specimen data for [xenotag.gps_tag]:") + to_chat(user, "Species: [target.real_name]") + to_chat(user, "Tag duration: [xenotag.age] shift\s") + to_chat(user, "Tagged by: [xenotag.implanted_by]") + to_chat(user, "Physical notes: [xenotag.physical_info]") + to_chat(user, "Behavioral notes: [xenotag.behavioral_info]") + return TRUE + +/obj/item/specimen_tagger/proc/check_can_tag(var/mob/user, var/mob/living/target) + if(QDELETED(target) || !istype(target) || target.stat == DEAD || target.isSynthetic()) + to_chat(user, SPAN_WARNING("Xenofauna specimens need to be living organic creatures.")) + return FALSE + if(!SScodex.get_codex_entry(target.get_codex_value())) + to_chat(user, SPAN_WARNING("There's no scientific reason to tag \the [target].")) + return FALSE + if(!target.is_tagging_suitable()) + to_chat(user, SPAN_WARNING("\The [target] is not suitable for tagging.")) + return FALSE + var/obj/item/gps/specimen_tag/xenotag = locate(/obj/item/gps/specimen_tag) in target + if(istype(xenotag) && xenotag.has_been_implanted()) + to_chat(user, SPAN_WARNING("\The [target] has already been tagged.")) + return FALSE + return TRUE + +/obj/item/specimen_tagger/proc/try_implant_tag(var/mob/user, var/mob/living/target) + if(!check_can_tag(user, target)) + return FALSE + user.visible_message(SPAN_NOTICE("\The [user] begins tagging \the [target] with \the [src]...")) + if(!do_after(user, 3 SECONDS, target) || !check_can_tag(user, target)) + return FALSE + var/obj/item/gps/specimen_tag/xenotag = new + xenotag.set_gps_tag(tag_id) + xenotag.implanted_by = user.real_name + if(user.mind) + var/user_title = user.mind.assigned_role || user.mind.role_alt_title + if(user_title) + xenotag.implanted_by = "[xenotag.implanted_by], [user_title]" + + xenotag.implant(target) + user.visible_message(SPAN_NOTICE("\The [user] tags \the [target] with \a [xenotag]!")) + return TRUE + +/obj/item/specimen_tagger/proc/can_remove_tag(var/mob/user, var/mob/living/target) + if(!istype(target)) + to_chat(user, SPAN_WARNING("\The [target] is not a xenofauna specimen.")) + return FALSE + var/obj/item/gps/specimen_tag/xenotag = locate() in target + if(!istype(xenotag) || !xenotag.has_been_implanted()) + to_chat(user, SPAN_WARNING("\The [target] has not been tagged.")) + return FALSE + return TRUE + +/obj/item/specimen_tagger/proc/try_remove_tag(var/mob/user, var/mob/living/target) + if(!can_remove_tag(user, target)) + return FALSE + var/obj/item/gps/specimen_tag/xenotag = locate() in target + if(!istype(xenotag)) + return FALSE + user.visible_message(SPAN_NOTICE("\The [user] starts removing \the [xenotag] from \the [target] with \the [src]...")) + if(!do_after(user, 3 SECONDS, target) || !can_remove_tag(user, target)) + return FALSE + if(!istype(xenotag)) + return FALSE + qdel(xenotag) + user.visible_message(SPAN_NOTICE("\The [user] removes \the [xenotag] from \the [target]!")) + return TRUE + diff --git a/mods/content/exploration/icons/boots_explo.dmi b/mods/content/exploration/icons/boots_explo.dmi new file mode 100644 index 000000000000..07c9e69e7e24 Binary files /dev/null and b/mods/content/exploration/icons/boots_explo.dmi differ diff --git a/mods/content/exploration/icons/cataloguer.dmi b/mods/content/exploration/icons/cataloguer.dmi new file mode 100644 index 000000000000..fb7fe153c8af Binary files /dev/null and b/mods/content/exploration/icons/cataloguer.dmi differ diff --git a/mods/content/exploration/icons/hood_explo.dmi b/mods/content/exploration/icons/hood_explo.dmi new file mode 100644 index 000000000000..270a990c68de Binary files /dev/null and b/mods/content/exploration/icons/hood_explo.dmi differ diff --git a/mods/content/exploration/icons/hood_xeno.dmi b/mods/content/exploration/icons/hood_xeno.dmi new file mode 100644 index 000000000000..0a6dd82c1a8e Binary files /dev/null and b/mods/content/exploration/icons/hood_xeno.dmi differ diff --git a/mods/content/exploration/icons/mask_explo.dmi b/mods/content/exploration/icons/mask_explo.dmi new file mode 100644 index 000000000000..e9c1f5b98c25 Binary files /dev/null and b/mods/content/exploration/icons/mask_explo.dmi differ diff --git a/mods/content/exploration/icons/phase_carbine.dmi b/mods/content/exploration/icons/phase_carbine.dmi new file mode 100644 index 000000000000..3e5ce1f94ea7 Binary files /dev/null and b/mods/content/exploration/icons/phase_carbine.dmi differ diff --git a/mods/content/exploration/icons/phase_pistol.dmi b/mods/content/exploration/icons/phase_pistol.dmi new file mode 100644 index 000000000000..7a074dede247 Binary files /dev/null and b/mods/content/exploration/icons/phase_pistol.dmi differ diff --git a/mods/content/exploration/icons/phase_rifle.dmi b/mods/content/exploration/icons/phase_rifle.dmi new file mode 100644 index 000000000000..b60a0b111f81 Binary files /dev/null and b/mods/content/exploration/icons/phase_rifle.dmi differ diff --git a/mods/content/exploration/icons/scanner.dmi b/mods/content/exploration/icons/scanner.dmi new file mode 100644 index 000000000000..1f6789038264 Binary files /dev/null and b/mods/content/exploration/icons/scanner.dmi differ diff --git a/mods/content/exploration/icons/specimen_tag.dmi b/mods/content/exploration/icons/specimen_tag.dmi new file mode 100644 index 000000000000..9c5446d4333f Binary files /dev/null and b/mods/content/exploration/icons/specimen_tag.dmi differ diff --git a/mods/content/exploration/icons/specimen_tag_overlays.dmi b/mods/content/exploration/icons/specimen_tag_overlays.dmi new file mode 100644 index 000000000000..75d53adb3b9d Binary files /dev/null and b/mods/content/exploration/icons/specimen_tag_overlays.dmi differ diff --git a/mods/content/exploration/icons/specimen_tagger.dmi b/mods/content/exploration/icons/specimen_tagger.dmi new file mode 100644 index 000000000000..fe1cbbda81f6 Binary files /dev/null and b/mods/content/exploration/icons/specimen_tagger.dmi differ diff --git a/icons/obj/stasis_cage.dmi b/mods/content/exploration/icons/stasis_cage.dmi similarity index 100% rename from icons/obj/stasis_cage.dmi rename to mods/content/exploration/icons/stasis_cage.dmi diff --git a/mods/content/exploration/icons/suit_explo.dmi b/mods/content/exploration/icons/suit_explo.dmi new file mode 100644 index 000000000000..98cfb4dfbc15 Binary files /dev/null and b/mods/content/exploration/icons/suit_explo.dmi differ diff --git a/mods/content/exploration/icons/suit_xeno.dmi b/mods/content/exploration/icons/suit_xeno.dmi new file mode 100644 index 000000000000..5847bb8b77de Binary files /dev/null and b/mods/content/exploration/icons/suit_xeno.dmi differ diff --git a/mods/content/exploration/icons/tranq_pistol.dmi b/mods/content/exploration/icons/tranq_pistol.dmi new file mode 100644 index 000000000000..1f47e0be9256 Binary files /dev/null and b/mods/content/exploration/icons/tranq_pistol.dmi differ diff --git a/mods/content/exploration/icons/tranq_rifle.dmi b/mods/content/exploration/icons/tranq_rifle.dmi new file mode 100644 index 000000000000..a81e4c15d49a Binary files /dev/null and b/mods/content/exploration/icons/tranq_rifle.dmi differ diff --git a/mods/content/exploration/icons/uniform_explo.dmi b/mods/content/exploration/icons/uniform_explo.dmi new file mode 100644 index 000000000000..5c7a4cf3457f Binary files /dev/null and b/mods/content/exploration/icons/uniform_explo.dmi differ diff --git a/mods/content/exploration/icons/uniform_xeno.dmi b/mods/content/exploration/icons/uniform_xeno.dmi new file mode 100644 index 000000000000..e3191b51dafb Binary files /dev/null and b/mods/content/exploration/icons/uniform_xeno.dmi differ diff --git a/mods/content/exploration/projectiles.dm b/mods/content/exploration/projectiles.dm new file mode 100644 index 000000000000..3f050ed826b7 --- /dev/null +++ b/mods/content/exploration/projectiles.dm @@ -0,0 +1,56 @@ +/obj/item/projectile/energy/phase + name = "phase wave" + icon_state = "phase" + fire_sound = 'sound/weapons/Gunshot_phase.ogg' + range = 6 + damage = 5 + var/animal_bonus_damage = 45 // 50 total on animals + +/obj/item/projectile/energy/phase/get_projectile_damage(mob/living/target) + if(isanimal(target) && !target.isSynthetic()) + return damage + animal_bonus_damage + return damage + +/obj/item/projectile/energy/phase/light + range = 4 + animal_bonus_damage = 35 // 40 total on animals + +/obj/item/projectile/energy/phase/heavy + range = 8 + animal_bonus_damage = 55 // 60 total on animals + +/obj/item/projectile/energy/phase/heavy/cannon + range = 10 + damage = 15 + animal_bonus_damage = 60 // 75 total on animals + +/obj/item/projectile/energy/phase/tranq + name = "tranquilizer wave" + range = 10 + damage = 0 + nodamage = TRUE + animal_bonus_damage = 0 + icon_state = "flight" + fire_sound = 'sound/weapons/dartgun.ogg' + fire_sound_vol_silenced = 5 + fire_sound_vol = 15 + var/tranq_delay = 6 SECONDS + var/tranq_power = 20 + +/obj/item/projectile/energy/phase/tranq/on_hit(atom/target, blocked, def_zone) + var/mob/living/victim = target + // TODO: consider just making this apply a sedative reagent when metabolism is unified. + if((. = ..()) && tranq_power && isanimal(victim) && !victim.isSynthetic()) + SET_STATUS_MAX(victim, STAT_DROWSY, ceil(tranq_delay / SSmobs.wait)) + addtimer(CALLBACK(victim, TYPE_PROC_REF(/mob/living, apply_delayed_tranq), tranq_power), tranq_delay) + +/mob/living/proc/apply_delayed_tranq(tranq_power) + if(!QDELETED(src) && stat != DEAD && !isSynthetic()) + SET_STATUS_MAX(src, STAT_ASLEEP, tranq_power) + +/obj/item/projectile/energy/phase/tranq/weak + range = 6 + tranq_power = 10 + fire_sound_vol_silenced = 5 + fire_sound_vol = 15 + tranq_delay = 9 SECONDS diff --git a/mods/content/exploration/screen_cataloguer.dm b/mods/content/exploration/screen_cataloguer.dm new file mode 100644 index 000000000000..5062fb805dc9 --- /dev/null +++ b/mods/content/exploration/screen_cataloguer.dm @@ -0,0 +1,81 @@ +/obj/screen/scan_radius + name = null + plane = HUD_PLANE + layer = UNDER_HUD_LAYER + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + screen_loc = "CENTER,CENTER" + icon = 'mods/content/exploration/icons/scanner.dmi' + icon_state = "blank" + alpha = 180 + requires_owner = FALSE + requires_ui_style = FALSE + var/scan_range + var/image/holder_image + +/obj/screen/scan_radius/proc/set_radius(var/new_range) + if(new_range != scan_range) + scan_range = max(1, new_range) + update_icon() + +/obj/screen/scan_radius/proc/fade_out(var/mob/user, var/fade_time) + set waitfor = FALSE + animate(src, alpha = 0, time = fade_time) + if(fade_time > 0) + sleep(fade_time) + if(user?.client && holder_image) + user.client.images -= holder_image + +/obj/screen/scan_radius/Destroy() + if(holder_image) + holder_image.vis_contents.Cut() + QDEL_NULL(holder_image) + return ..() + +/obj/screen/scan_radius/rebuild_screen_overlays() + ..() + if(scan_range <= 1) + add_overlay("single") + else + var/pixel_bound = (world.icon_size * scan_range) + + var/image/I = image(icon, "bottomleft") + I.pixel_x = -(pixel_bound) + I.pixel_y = -(pixel_bound) + add_overlay(I) + + I = image(icon, "bottomright") + I.pixel_x = pixel_bound + I.pixel_y = -(pixel_bound) + add_overlay(I) + + I = image(icon, "topleft") + I.pixel_x = -(pixel_bound) + I.pixel_y = pixel_bound + add_overlay(I) + + I = image(icon, "topright") + I.pixel_x = pixel_bound + I.pixel_y = pixel_bound + add_overlay(I) + + var/offset_scan_range = scan_range-1 + for(var/i = -(offset_scan_range) to offset_scan_range) + I = image(icon, "left") + I.pixel_x = -(pixel_bound) + I.pixel_y = world.icon_size * i + add_overlay(I) + + I = image(icon, "right") + I.pixel_x = pixel_bound + I.pixel_y = world.icon_size * i + add_overlay(I) + + I = image(icon, "bottom") + I.pixel_x = world.icon_size * i + I.pixel_y = -(pixel_bound) + add_overlay(I) + + I = image(icon, "top") + I.pixel_x = world.icon_size * i + I.pixel_y = pixel_bound + add_overlay(I) diff --git a/mods/content/exploration/specimen_codex.dm b/mods/content/exploration/specimen_codex.dm new file mode 100644 index 000000000000..f307c6606809 --- /dev/null +++ b/mods/content/exploration/specimen_codex.dm @@ -0,0 +1,58 @@ +// Lists of strings used by the specimen tracking system to add flavour to +// specimens. Static lists in procs to allow overriding while also not putting +// a massive string list on every single cataloguer fauna entry. +/datum/codex_entry/proc/get_fauna_physical_notes() + var/static/list/fauna_physical_notes = list( + "Perpetually smells like mold no matter what we do about it.", + "Perpetually smells like mildew no matter what we do about it.", + "Perpetually smells like sifsap no matter what we do about it.", + "Seems to always have an itch in the spot it can't reach.", + "Vocalizations are notably harsh and loud for the species.", + "Vocalizations are notably soft and quiet for the species.", + "Has a notch in its left ear.", + "Has a notch in its right ear.", + "Is missing its left ear.", + "Is missing its right ear.", + "Is missing its left eye.", + "Is missing its right eye.", + "Has had the very tip of its tail chewed off.", + "Might have trouble with its hearing.", + "Is more scar tissue than animal at this point.", + "Walks with a limp.", + "Has two differently colored eyes.", + "Might have a cold...", + "Is allergic to nuts.", + "Is allergic to berries.", + "Is allergic to dairy." + ) + return fauna_physical_notes + +/datum/codex_entry/proc/get_fauna_behavior_notes() + var/static/list/fauna_behavior_notes = list( + "Likes rolling around in the moss with reckless abandon.", + "Enjoys munching on frostbelles the most, as a treat.", + "Enjoys munching on wabback the most, as a treat.", + "Enjoys munching on eyebulbs the most, as a treat.", + "Constantly sniffs around at everything new.", + "Seems super friendly! Probably won't bite. Probably.", + "Seems rather stand-offish. Mind the personal bubble.", + "Loves a good back scritch.", + "Loves a good head scritch.", + "Loves a good behind the ear scritch.", + "Seems to hate the world and everything in it.", + "Just tolerates being pet, but certainly doesn't enjoy it.", + "Often sticks its head into snowbanks to contemplate the state of things.", + "Enjoys singing along to songs only it can hear. Mostly just sounds like an animal wailing.", + "Would rather be fishing.", + "Partakes in many siestas.", + "Struggles with object permanence.", + "Is very picky about food; maybe it's a texture thing.", + "Is a sentient garbage disposal for anything even remotely edible.", + "Loves swimming and splashing around in water.", + "Sinks like a rock the moment it enters water.", + "Gets lost easily.", + "Enjoys soft things. It'd have a bed of plushies if it knew what a bed was.", + "Never seems to be in a rush to go anywhere...", + "Has gotta go fast at all times." + ) + return fauna_behavior_notes diff --git a/mods/content/exploration/specimen_mob.dm b/mods/content/exploration/specimen_mob.dm new file mode 100644 index 000000000000..7512cb01f06b --- /dev/null +++ b/mods/content/exploration/specimen_mob.dm @@ -0,0 +1,6 @@ +// Mob helpers/overrides. +/mob/living/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/obj/item/gps/specimen_tag/xenotag = locate() in src + if(istype(xenotag) && xenotag.has_been_implanted()) + . += "\The [src] has been tagged with \a [xenotag]." diff --git a/mods/content/exploration/structures/closets.dm b/mods/content/exploration/structures/closets.dm new file mode 100644 index 000000000000..bf4afd629f47 --- /dev/null +++ b/mods/content/exploration/structures/closets.dm @@ -0,0 +1,104 @@ +/obj/structure/closet/secure_closet/xenofauna + name = "xenofauna technician locker" + req_access = list(access_xenofauna) + +/obj/structure/closet/secure_closet/xenofauna/WillContain() + return list( + /obj/item/clothing/jumpsuit/xenofauna, + /obj/item/clothing/suit/explorer/xenofauna, + /obj/item/clothing/mask/gas/explorer, + /obj/item/clothing/shoes/winterboots/explorer, + /obj/item/clothing/gloves/black, + /obj/item/clothing/suit/jacket/winter/parka/purple, + /obj/item/radio/headset/headset_exp, + /obj/item/flashlight, + /obj/item/gps/xenofauna, + /obj/item/geiger, + /obj/item/cell/device, + /obj/item/radio, + /obj/item/cataloguer, + /obj/item/backpack/satchel/grey, + /obj/item/knife/survival, + /obj/item/specimen_tagger + ) + +/obj/structure/closet/secure_closet/guncabinet/phase + name = "explorer weapon cabinet" + req_access = list(access_explorer) + +/obj/structure/closet/secure_closet/guncabinet/phase/WillContain() + return list( + /obj/item/gun/energy/gun/reloadable/phase = 2, + /obj/item/gun/energy/gun/reloadable/phase/pistol, + /obj/item/cell/gun = 2, + /obj/item/clothing/permit/gun/planetside/exploration + ) + +/obj/structure/closet/secure_closet/guncabinet/tranq + name = "tranquilizer rifle cabinet" + req_access = list(access_xenofauna) + +/obj/structure/closet/secure_closet/guncabinet/tranq/WillContain() + return list( + /obj/item/gun/energy/gun/reloadable/phase/tranq_rifle = 2, + /obj/item/gun/energy/gun/reloadable/phase/tranq_pistol, + /obj/item/gun/energy/gun/reloadable/phase/pistol, + /obj/item/cell/gun = 2, + /obj/item/clothing/permit/gun/planetside + ) + +//Explorer Lockers +/obj/structure/closet/secure_closet/explorer + name = "explorer locker" + req_access = list(access_explorer) + closet_appearance = /decl/closet_appearance/secure_closet/expedition + +/obj/structure/closet/secure_closet/explorer/WillContain() + . = list( + /obj/item/clothing/jumpsuit/explorer, + /obj/item/clothing/suit/explorer, + /obj/item/clothing/mask/gas/explorer, + /obj/item/clothing/shoes/winterboots/explorer, + /obj/item/clothing/gloves/black, + /obj/item/radio/headset/headset_exp, + /obj/item/flashlight, + /obj/item/gps/explorer, + /obj/item/box/flares, + /obj/item/geiger, + /obj/item/cell/device, + /obj/item/radio, + /obj/item/stack/flag = 3, // 30, since each is a full stack of 10 + /obj/item/cataloguer) + if(prob(50)) + . += /obj/item/backpack/rucksack + else + . += /obj/item/backpack/satchel + if(prob(75)) + . += /obj/item/knife/utility + else + . += /obj/item/tool/machete + +//Xenofauna tech lockers +/obj/structure/closet/secure_closet/xenofauna + name = "xenofauna technician locker" + req_access = list(access_xenofauna) + +/obj/structure/closet/secure_closet/xenofauna/WillContain() + return list( + /obj/item/clothing/jumpsuit/xenofauna, + /obj/item/clothing/suit/explorer/xenofauna, + /obj/item/clothing/mask/gas/explorer, + /obj/item/clothing/shoes/winterboots/explorer, + /obj/item/clothing/gloves/black, + /obj/item/clothing/suit/jacket/winter/parka/purple, + /obj/item/radio/headset/headset_exp, + /obj/item/flashlight, + /obj/item/gps/xenofauna, + /obj/item/geiger, + /obj/item/cell/device, + /obj/item/radio, + /obj/item/cataloguer, + /obj/item/backpack/satchel, + /obj/item/knife/utility, + /obj/item/specimen_tagger + ) diff --git a/mods/content/exploration/structures/stasis_cage.dm b/mods/content/exploration/structures/stasis_cage.dm new file mode 100644 index 000000000000..e3ee7529b957 --- /dev/null +++ b/mods/content/exploration/structures/stasis_cage.dm @@ -0,0 +1,129 @@ +/obj/structure/stasis_cage + name = "stasis cage" + desc = "A high-tech animal cage, designed to keep contained fauna docile and safe." + icon = 'mods/content/exploration/icons/stasis_cage.dmi' + icon_state = "stasis_cage" + density = TRUE + layer = ABOVE_OBJ_LAYER + VAR_PRIVATE/weakref/_contained + +/obj/structure/stasis_cage/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + var/mob/living/simple_animal/A = locate() in loc + if(A) + contain(A) + +/obj/structure/stasis_cage/Destroy() + STOP_PROCESSING(SSobj, src) + release() + return ..() + +/obj/structure/stasis_cage/Process() + . = ..() + for(var/mob/specimen in contents) + specimen.add_mob_modifier(/decl/mob_modifier/stasis, SSobj.wait * 2, source = src) + +/obj/structure/stasis_cage/proc/get_specimen() + var/mob/living/simple_animal/critter = _contained?.resolve() + if(!critter || critter.loc != src || QDELETED(critter)) + _contained = null + return null + return critter + +/obj/structure/stasis_cage/attackby(obj/item/used_item, mob/user) + if(_contained && istype(used_item, /obj/item/scanner/xenobio)) + var/mob/living/simple_animal/specimen = get_specimen() + if(specimen) + return specimen.attackby(used_item, user) + . = ..() + +/obj/structure/stasis_cage/attack_hand(var/mob/user) + if(!user.check_dexterity(DEXTERITY_SIMPLE_MACHINES, TRUE)) + return ..() + try_release(user) + return TRUE + +/obj/structure/stasis_cage/attack_robot(var/mob/user) + if(CanPhysicallyInteract(user)) + try_release(user) + return TRUE + +/obj/structure/stasis_cage/proc/try_release(mob/user) + var/mob/living/simple_animal/specimen = get_specimen() + if(!specimen) + to_chat(user, SPAN_NOTICE("There's no animals inside \the [src]")) + return + user.visible_message("[user] begins undoing the locks and latches on \the [src].") + if(do_after(user, 20, src)) + + user.visible_message("[user] releases \the [specimen] from \the [src]!") + release() + +/obj/structure/stasis_cage/on_update_icon() + ..() + var/mob/living/simple_animal/specimen = get_specimen() + if(specimen) + icon_state = "[initial(icon_state)]_on" + else + icon_state = initial(icon_state) + +/obj/structure/stasis_cage/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/mob/living/simple_animal/specimen = get_specimen() + if(specimen) + . += "\The [specimen] is kept inside." + +/obj/structure/stasis_cage/proc/contain(var/mob/living/simple_animal/animal) + var/mob/living/simple_animal/specimen = get_specimen() + if(specimen || !istype(animal)) + return + + _contained = weakref(animal) + animal.forceMove(src) + update_icon() + +/obj/structure/stasis_cage/proc/release() + + var/mob/living/simple_animal/specimen = get_specimen() + if(!specimen) + return + + specimen.dropInto(src) + _contained = null + update_icon() + +/mob/living/simple_animal/handle_mouse_drop(atom/over, mob/user, params) + if(istype(over, /obj/structure/stasis_cage)) + var/obj/structure/stasis_cage/cage = over + if(!stat && !istype(buckled, /obj/effect/energy_net)) + to_chat(user, SPAN_WARNING("It's going to be difficult to convince \the [src] to move into \the [cage] without capturing it in a net.")) + return TRUE + user.visible_message( + SPAN_NOTICE("\The [user] begins loading \the [src] into \the [cage]."), + SPAN_NOTICE("You begin loading \the [src] into \the [cage].") + ) + Bumped(user) + if(do_after(user, 20, cage)) + cage.visible_message( + SPAN_NOTICE("\The [user] finishes loading \the [src] into \the [cage]."), + SPAN_NOTICE("You finishes loading \the [src] into \the [cage].") + ) + cage.contain(src) + return TRUE + . = ..() + +/obj/item/scanner/xenobio/is_valid_scan_target(atom/O) + if(istype(O, /obj/structure/stasis_cage)) + var/obj/structure/stasis_cage/cagie = O + return !!cagie.get_specimen() + return ..() + +/decl/hierarchy/supply_pack/science/stasis_cages + name = "Stasis Cage" + contains = list( + /obj/structure/stasis_cage = 1 + ) + containertype = /obj/structure/closet/crate/large + containername = "stasis cage crate" + access = access_xenofauna diff --git a/mods/content/fantasy/_fantasy.dm b/mods/content/fantasy/_fantasy.dm new file mode 100644 index 000000000000..a8a072c320c3 --- /dev/null +++ b/mods/content/fantasy/_fantasy.dm @@ -0,0 +1,22 @@ +#define BODYTYPE_KOBALOI "reptomammalian body" +#define BODYTYPE_HNOLL "hyenoid body" +#define BODYTYPE_DVERGR "small humanoid body" + +#define BODY_EQUIP_FLAG_KOBALOI BITFLAG(9) +#define BODY_EQUIP_FLAG_HNOLL BITFLAG(10) +#define BODY_EQUIP_FLAG_DVERGR BITFLAG(11) + +#define SKILL_CARPENTRY /decl/skill/crafting/carpentry +#define SKILL_METALWORK /decl/skill/crafting/metalwork +#define SKILL_TEXTILES /decl/skill/crafting/textiles +#define SKILL_STONEMASONRY /decl/skill/crafting/stonemasonry +#define SKILL_SCULPTING /decl/skill/crafting/sculpting +#define SKILL_ARTIFICE /decl/skill/crafting/artifice +#define SKILL_HUSBANDRY /decl/skill/service/husbandry + +/decl/modpack/fantasy + name = "Fantasy Content" + +/decl/modpack/fantasy/Initialize() + . = ..() + global._wall_chisel_skill = SKILL_STONEMASONRY diff --git a/mods/content/fantasy/_fantasy.dme b/mods/content/fantasy/_fantasy.dme new file mode 100644 index 000000000000..39602d52bbc3 --- /dev/null +++ b/mods/content/fantasy/_fantasy.dme @@ -0,0 +1,52 @@ +#ifndef MODPACK_FANTASY +#define MODPACK_FANTASY +// BEGIN_INCLUDE +#include "_fantasy.dm" +#include "turfs.dm" +#include "datum\cultures.dm" +#include "datum\currencies.dm" +#include "datum\factions.dm" +#include "datum\locations.dm" +#include "datum\materials.dm" +#include "datum\names.dm" +#include "datum\outfits.dm" +#include "datum\overrides.dm" +#include "datum\skills.dm" +#include "datum\species.dm" +#include "datum\hnoll\bodytypes.dm" +#include "datum\hnoll\culture.dm" +#include "datum\hnoll\language.dm" +#include "datum\hnoll\markings.dm" +#include "datum\hnoll\organs.dm" +#include "datum\hnoll\species.dm" +#include "datum\kobaloi\bodytypes.dm" +#include "datum\kobaloi\clothing.dm" +#include "datum\kobaloi\culture.dm" +#include "datum\kobaloi\language.dm" +#include "datum\kobaloi\markings.dm" +#include "datum\kobaloi\organs.dm" +#include "datum\kobaloi\species.dm" +#include "items\material_overrides.dm" +#include "items\clothing\_loadout.dm" +#include "items\clothing\_overrides.dm" +#include "items\clothing\_recipes.dm" +#include "items\clothing\armor.dm" +#include "items\clothing\cloak.dm" +#include "items\clothing\glasses.dm" +#include "items\clothing\jerkin.dm" +#include "items\clothing\loincloth.dm" +#include "items\clothing\trousers.dm" +#include "props\signpost.dm" +#include "submaps\_submaps.dm" +#include "submaps\downlands\_downlands.dm" +#include "submaps\grassland\_grassland.dm" +#include "submaps\swamp\_swamp.dm" +#include "submaps\woods\_woods.dm" +#include "submaps\woods\bear_den\bear_den.dm" +#include "submaps\woods\chemistry_shack\chemistry_shack.dm" +#include "submaps\woods\fairy_rings\fairy_rings.dm" +#include "submaps\woods\fox_den\fox_den.dm" +#include "submaps\woods\hunter_camp\hunter_camp.dm" +#include "submaps\woods\old_cabin\old_cabin.dm" +// END_INCLUDE +#endif diff --git a/mods/content/fantasy/datum/cultures.dm b/mods/content/fantasy/datum/cultures.dm new file mode 100644 index 000000000000..f7d0ad5b0bc3 --- /dev/null +++ b/mods/content/fantasy/datum/cultures.dm @@ -0,0 +1,70 @@ +/decl/background_detail/heritage/fantasy + name = "Splinter Kingdom" + description = "The Splinter Kingdoms are a disparate mish-mash of regional powers, feudal warlords, and more organized \ + settlements within the space once claimed by the Imperial Aegis. When the Aegis collapsed, several hundred years ago, the \ + resulting wars and squabbling took decades to settle, and in many places the tensions and conflicts still run hot. Most of \ + the Splinter Kingdoms emulate the peasant-noble social hierarchies of the Aegis, but a variety of other forms of governance \ + and society can be found." + uid = "heritage_fantasy_splinter" + +/decl/background_detail/heritage/fantasy/steppe + name = "Steppe Nomad" + description = "The tundra and steppe between the Nine Mothers and the downlands are home to a number of disparate cultural \ + groups, many of which descend from the hnoll clans that have lived in the region since time immemorial. Generally speaking, \ + the people of the steppe are hardy, independant, and primarily occupied with survival in the resource-poor and harsh conditions \ + of their home. Most groups are nomadic, following their flocks of aurochs or other livestock between water sources and grazing land." + uid = "heritage_fantasy_steppe" + +// Overrides for fantasy maps. +/decl/background_detail/location + distance_heading = null // hides the 'distance from Sol' section + +/decl/background_detail/heritage/other + description = "You are from one of the many small, relatively unknown cultures scattered across the land." + +/decl/background_detail/location/other + name = "Other Place" + description = "You are from some tiny village, distant city or remote settlement not recorded in local atlases." + +/decl/background_detail/faction/other + name = "Other Faction" + description = "You don't align with any of the more well-known factions or powers." + +/decl/background_detail/religion/ancestors + name = "Ancestor Worship" + description = "You revere your ancestors through your deeds and offerings, and work to follow the example laid down by them. You may blame fortune and misfortune alike on the influence of your ancestors, and might seek to appease them in times of trouble." + uid = "religion_fantasy_ancestors" + +/decl/background_detail/religion/folk_deity + name = "Folk Deity" + description = "You worship the folk deity or deities of either the local area or of your hometown or another significant place in your past. Followers of these religions may have a variety of beliefs about their folk deity and how they manifest in and affect the world, but typically they are not believed to stray far from shrines dedicated to them. Additionally, followers believe their influence tends to be subtle rather than dramatic." + uid = "religion_fantasy_folk" + +/decl/background_detail/religion/anima_materialism + name = "Anima Materialism" + description = "You believe in the natural laws governing material and anima over all else, spurning the supposed influence of the divine. Whether attempting to delve deep into those laws yourself or merely content with the understanding that everything is linked via mechanistic rules, you do not hold to a belief in any immaterial higher power." + uid = "religion_fantasy_anima" + +/decl/background_detail/religion/virtuist + name = "Virtuist" + description = "You seek to display virtue and temperance in all that you do. You may look up to others as examples of such virtues, particularly strong historical figures in the Aegis and Splinter Kingdoms, like the Seven Sisters." + uid = "religion_fantasy_aegis" + +/decl/background_detail/religion/other + name = "Other Religion" + description = "You practice no religion, or a small or relatively unknown religion distinct from the major faiths." + +// Reskin to remove Icelandic, references to Sif, etc. +/decl/background_detail/heritage/grafadreka + name = "Meredrake Culture" + description = "You are a meredrake. Widely assumed to be cousins to true dragons, drakes are intelligent, arguably sapient pack predators without anything in the way of technology or culture, but they can be trained to use tools, and have been known to work well alongside humans or hnoll as companions and working animals." + +/decl/background_detail/location/grafadreka + name = "Wilderness" + description = "You are from the unsettled tundras and steppe of the Grass Ocean, or the forested downlands, where you probably eked out a life hunting deer or chasing rabbits." + +/decl/background_detail/faction/grafadreka + name = "Meredrake Pack" + +/decl/background_detail/religion/grafadreka + name = "Meredrake Religion" diff --git a/mods/content/fantasy/datum/currencies.dm b/mods/content/fantasy/datum/currencies.dm new file mode 100644 index 000000000000..f16917dcc787 --- /dev/null +++ b/mods/content/fantasy/datum/currencies.dm @@ -0,0 +1,54 @@ +/decl/currency/imperial + name = "\improper Imperial crowns" + name_prefix = "¢" + +/decl/currency/imperial/build_denominations() + denominations = list( + new /datum/denomination/coin/crown/regalis(src, 125, null, COLOR_GOLD), + new /datum/denomination/coin/crown/quin(src, 5, null, COLOR_SILVER), + new /datum/denomination/coin/crown(src, 1, null, COLOR_BRONZE) + ) + ..() + +/datum/denomination/coin/crown + name = "\improper Imperial crown" + faces = list("obverse", "reverse") + +/datum/denomination/coin/crown/New(decl/currency/_currency, value, value_name, colour) + . = ..() + name = initial(name) // Awful, evil, terrible. + +/datum/denomination/coin/crown/quin + name = "\improper Imperial quincrown" + +/datum/denomination/coin/crown/regalis + name = "\improper Imperial crown regalis" + +/obj/item/cash/imperial + abstract_type = /obj/item/cash/imperial + currency = /decl/currency/imperial + +/obj/item/cash/imperial/crown + absolute_worth = 1 + icon_state = "coin" + color = COLOR_BRONZE + +/obj/item/cash/imperial/quin + absolute_worth = 5 + icon_state = "coin_medium" + color = COLOR_SILVER + +/obj/item/cash/imperial/regalis + absolute_worth = 125 + icon_state = "coin_large" + color = COLOR_GOLD + +/decl/stack_recipe/coin/imperial + currency = /decl/currency/imperial + name = "\improper Imperial crown" + +/decl/stack_recipe/coin/imperial/quin + name = "\improper Imperial quincrown" + +/decl/stack_recipe/coin/imperial/huge + name = "\improper Imperial crown regalis" diff --git a/mods/content/fantasy/datum/factions.dm b/mods/content/fantasy/datum/factions.dm new file mode 100644 index 000000000000..859e993a6f63 --- /dev/null +++ b/mods/content/fantasy/datum/factions.dm @@ -0,0 +1,34 @@ +/decl/background_detail/faction/fantasy + name = "Wanderer" + description = "You are transient and unbeholden to any particular political or ideological group." + uid = "faction_fantasy_wanderer" + +/decl/background_detail/faction/fantasy/barbarian + name = "Steppe Warrior" + description = "When the first migrants from the Nine Mothers left the steppe for the downlands, they traded a warrior spirit and \ + a connection to their ancestors for comfort and riches. You and your compatriots know better. The fat, soft downlanders, safe behind \ + their walls and fed by their gardens, are little better than placid livestock. They should be shown the true way of the world by force." + uid = "faction_fantasy_steppe" + +/decl/background_detail/faction/fantasy/centrist + name = "Kingdom Citizen" + description = "Firebrand rhetoric and rabble-rousing don't hold a candle to a roof over your head, well-maintained roads, \ + and a full belly. You might not like the nobles or merchants who run your settlement, but they're probably better than the alternative." + uid = "faction_fantasy_kingdom" + +/decl/background_detail/faction/fantasy/aegis + name = "Imperial Revivalist" + description = "The Aegis may have collapsed over a hundred years ago, but the loss is still keenly felt. You and your fellows \ + believe that returning the true blood of the Old Queens to the Imperial Throne will resolve the confusion and chaos of the modern \ + day, and usher in a second golden age beneath their benevolent leadership." + uid = "faction_fantasy_aegis" + +/decl/background_detail/faction/fantasy/primitivist + name = "Anima Primitivist" + description = "Before the Imperial Aegis, before towns and cities, the natural world lived and breathed, fought and died and rotted \ + and was reborn. Civilization has built walls between the people and their true selves, and only by returning to a state of nature, \ + dismantling the cities and allowing primal anima to flow freely again, can we be truly alive." + uid = "faction_fantasy_anima" + +// TODO +// - factions unaligned with splinter kingdom/nine mothers politics - equatorial, coastal, deepwood diff --git a/mods/content/fantasy/datum/hnoll/bodytypes.dm b/mods/content/fantasy/datum/hnoll/bodytypes.dm new file mode 100644 index 000000000000..1edda9e8e998 --- /dev/null +++ b/mods/content/fantasy/datum/hnoll/bodytypes.dm @@ -0,0 +1,80 @@ +/decl/bodytype/hnoll + name = "humanoid" + bodytype_category = BODYTYPE_HNOLL + limb_blend = ICON_MULTIPLY + icon_template = 'mods/content/fantasy/icons/hnoll/template.dmi' + icon_base = 'mods/content/fantasy/icons/hnoll/body.dmi' + icon_deformed = 'mods/content/fantasy/icons/hnoll/deformed_body.dmi' + bandages_icon = 'icons/mob/bandage.dmi' + eye_icon = 'mods/content/fantasy/icons/hnoll/eyes.dmi' + cosmetics_icon = 'mods/content/fantasy/icons/hnoll/cosmetics.dmi' + skeletal_icon = 'mods/content/fantasy/icons/hnoll/skeleton.dmi' + health_hud_intensity = 1.75 + bodytype_flag = BODY_EQUIP_FLAG_HNOLL + appearance_flags = HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR + age_descriptor = /datum/appearance_descriptor/age/hnoll + base_color = "#ae7d32" + base_eye_color = "#00aa00" + uid = "bodytype_hnoll" + footprints_icon = 'icons/mob/footprints/footprints_paw.dmi' + + default_sprite_accessories = list( + SAC_HAIR = list( + /decl/sprite_accessory/hair/hnoll/mohawk = list(SAM_COLOR = "#46321c") + ), + SAC_MARKINGS = list( + /decl/sprite_accessory/marking/hnoll/belly = list(SAM_COLOR = "#b6b0a8"), + /decl/sprite_accessory/marking/hnoll/spots/body = list(SAM_COLOR = "#46331d"), + /decl/sprite_accessory/marking/hnoll/ears = list(SAM_COLOR = "#46331d") + ) + ) + + eye_darksight_range = 7 + eye_flash_mod = 2 + eye_blend = ICON_MULTIPLY + eye_low_light_vision_effectiveness = 0.15 + eye_low_light_vision_adjustment_speed = 0.3 + + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/hnoll + ) + + cold_level_1 = 200 + cold_level_2 = 140 + cold_level_3 = 80 + + heat_level_1 = 330 + heat_level_2 = 380 + heat_level_3 = 800 + + heat_discomfort_level = 294 + cold_discomfort_level = 230 + heat_discomfort_strings = list( + "Your fur prickles in the heat.", + "You feel uncomfortably warm.", + "Your overheated skin itches." + ) + +/decl/bodytype/hnoll/Initialize() + if(!_equip_adjust) + _equip_adjust = list( + (slot_glasses_str) = list( + "[NORTH]" = list( 0, 2), + "[EAST]" = list( 0, 2), + "[SOUTH]" = list( 0, 2), + "[WEST]" = list( 0, 2) + ), + (slot_wear_mask_str) = list( + "[NORTH]" = list( 0, 2), + "[EAST]" = list( 2, 2), + "[SOUTH]" = list( 0, 2), + "[WEST]" = list(-2, 2) + ), + (slot_head_str) = list( + "[NORTH]" = list( 0, 2), + "[EAST]" = list( 0, 2), + "[SOUTH]" = list( 0, 2), + "[WEST]" = list( 0, 2) + ) + ) + . = ..() diff --git a/mods/content/fantasy/datum/hnoll/culture.dm b/mods/content/fantasy/datum/hnoll/culture.dm new file mode 100644 index 000000000000..147a96754ad8 --- /dev/null +++ b/mods/content/fantasy/datum/hnoll/culture.dm @@ -0,0 +1,17 @@ +/decl/background_detail/heritage/fantasy/hnoll + name = "Hnoll Clanner" + description = "You were raised as part of a Nine Mothers steppe clan. You most likely grew up under the authority of \ + the matriarches, living on the steppe or tundra of the Grass Ocean and following the aurochs herds on their seasonal \ + migrations. Steppe clans are usually highly traditional, very family-oriented, and wary of both outsiders and any \ + deviance from the expected norm." + name_language = /decl/language/hnoll + uid = "heritage_fantasy_hnoll_clan" + +/decl/background_detail/heritage/fantasy/hnoll/aegis + name = "Imperial Hnoll" + description = "Despite the continent-spanning empire of the Aegis having crumbled decades ago, many Splinter Kingdoms \ + still try to keep up the facade of old power and old authority. Dynasties claiming to trace their bloodline to the old \ + Queens rule over a strata of serfs and labourers, supported by the tithes of the merchant class. You were raised in one \ + such Splinter Kingdom clinging to the remnants of the Aegis, likely born into power and authority over the peasants under \ + your family's power." + uid = "heritage_fantasy_hnoll_aegis" diff --git a/mods/content/fantasy/datum/hnoll/language.dm b/mods/content/fantasy/datum/hnoll/language.dm new file mode 100644 index 000000000000..2cefb4941743 --- /dev/null +++ b/mods/content/fantasy/datum/hnoll/language.dm @@ -0,0 +1,23 @@ +/decl/language/hnoll + name = "Hnoll Tongue" + shorthand = "HN" + desc = "While every hnoll culture across the Nine Mothers and beyond has their own \ + local dialect, the matriarches over the years have taken great care to cultivate and \ + maintain a shared tongue used at the yearly gatherings and for inter-settlement trade. \ + It's generally considered rather stuffy and archaic if spoken in the 'correct' manner." + speech_verb = "growls" + ask_verb = "chuffs" + exclaim_verb = "howls" + colour = "serpentid_lang" + key = "j" + flags = LANG_FLAG_WHITELISTED + space_chance = 40 + + // Stolen from Zirc's Nakhayl syllable list, with some added Latin syllables. + syllables = list( + "mrr", "rr", "rah", "gr", "grr", "ch", "chur", "uff", "wu", "wuf", "ay", "yay", "ip", "yip", "ha", "hee", "hu", "he", "oo", "ew", + "bad", "nur", "nah", "nuf", "nu", "nak", "mur", "mah", "muf", "mu", "dur", "dah", "duf", "du", "kur", "kah", "kuf", "ku", + "xur", "xah", "xuf", "cha", "chuf", "yur", "yah", "yak", "gayl", "pur", "pah", "puf", "gur", "gah", "guf", "gu", + "har", "hur", "huf", "hayl", "nayl", "kayl", "chayl", "nakta", "kanak", "masa", "pita", + "est", "latus", "cerno", "plex", "sto", "ab", "du" + ) diff --git a/mods/content/fantasy/datum/hnoll/markings.dm b/mods/content/fantasy/datum/hnoll/markings.dm new file mode 100644 index 000000000000..e897347c5c81 --- /dev/null +++ b/mods/content/fantasy/datum/hnoll/markings.dm @@ -0,0 +1,329 @@ +//Hairstyles +/decl/sprite_accessory/hair/hnoll + name = "Hnoll Rattail" + icon_state = "hair_rattail" + species_allowed = list(/decl/species/hnoll::uid) + icon = 'mods/content/fantasy/icons/hnoll/hair.dmi' + color_blend = ICON_MULTIPLY + uid = "acc_hair_hnoll_rattail" + +/decl/sprite_accessory/hair/hnoll/get_hidden_substitute() + if(accessory_flags & HAIR_VERY_SHORT) + return src + return GET_DECL(/decl/sprite_accessory/hair/bald) + +/decl/sprite_accessory/hair/hnoll/straight + name = "Hnoll Straight Hair" + icon_state = "hair_straight" + uid = "acc_hair_hnoll_straight" + +/decl/sprite_accessory/hair/hnoll/clean + name = "Hnoll Clean" + icon_state = "hair_clean" + uid = "acc_hair_hnoll_clean" + +/decl/sprite_accessory/hair/hnoll/shaggy + name = "Hnoll Shaggy" + icon_state = "hair_shaggy" + uid = "acc_hair_hnoll_shaggy" + +/decl/sprite_accessory/hair/hnoll/mohawk + name = "Hnoll Mohawk" + icon_state = "hair_mohawk" + uid = "acc_hair_hnoll_mohawk" + +/decl/sprite_accessory/hair/hnoll/plait + name = "Hnoll Plait" + icon_state = "hair_plait" + uid = "acc_hair_hnoll_plait" + +/decl/sprite_accessory/hair/hnoll/long + name = "Hnoll Long Hair" + icon_state = "hair_long" + uid = "acc_hair_hnoll_long" + +/decl/sprite_accessory/hair/hnoll/spiky + name = "Hnoll Spiky" + icon_state = "hair_spiky" + uid = "acc_hair_hnoll_spiky" + +/decl/sprite_accessory/hair/hnoll/bangs + name = "Hnoll Bangs" + icon_state = "hair_bangs" + uid = "acc_hair_hnoll_bangs" + +/decl/sprite_accessory/hair/hnoll/messy + name = "Hnoll Messy" + icon_state = "hair_messy" + uid = "acc_hair_hnoll_messy" + +/decl/sprite_accessory/hair/hnoll/braid + name = "Hnoll Braid" + icon_state = "hair_tbraid" + uid = "acc_hair_hnoll_braid" + +/decl/sprite_accessory/hair/hnoll/bob + name = "Hnoll Bob" + icon_state = "hair_tbob" + uid = "acc_hair_hnoll_bob" + +/decl/sprite_accessory/hair/hnoll/weave + name = "Hnoll Fingerweave" + icon_state = "hair_fingerwave" + uid = "acc_hair_hnoll_weave" + +/decl/sprite_accessory/hair/hnoll/sidebraid + name = "Hnoll Sidebraid" + icon_state = "hair_sidebraid" + uid = "acc_hair_hnoll_sidebraid" + +/decl/sprite_accessory/hair/hnoll/ribbons + name = "Hnoll Ribbons" + icon_state = "hair_ribbons" + uid = "acc_hair_hnoll_ribbons" + +/decl/sprite_accessory/hair/hnoll/combed + name = "Hnoll Combed" + icon_state = "hair_combedback" + uid = "acc_hair_hnoll_combed" + +/decl/sprite_accessory/hair/hnoll/tailedbangs + name = "Hnoll Tailed Bangs" + icon_state = "hair_tailedbangs" + uid = "acc_hair_hnoll_tailedbangs" + +/decl/sprite_accessory/hair/hnoll/lynx + name = "Hnoll Lynx" + icon_state = "hair_lynx" + uid = "acc_hair_hnoll_lynx" + +/decl/sprite_accessory/hair/hnoll/longtail + name = "Hnoll Long Tail" + icon_state = "hair_longtail" + uid = "acc_hair_hnoll_longtail" + +/decl/sprite_accessory/hair/hnoll/shy + name = "Hnoll Shy" + icon_state = "hair_shy" + uid = "acc_hair_hnoll_shy" + +/decl/sprite_accessory/hair/hnoll/ponytail + name = "Hnoll Ponytail" + icon_state = "hair_ponytail" + uid = "acc_hair_hnoll_ponytail" + +/decl/sprite_accessory/hair/hnoll/overeye + name = "Hnoll Overeye" + icon_state = "hair_overeye" + uid = "acc_hair_hnoll_overeye" + +/decl/sprite_accessory/hair/hnoll/tough + name = "Hnoll Tough" + icon_state = "hair_tough" + uid = "acc_hair_hnoll_tough" + +/decl/sprite_accessory/hair/hnoll/cuttail + name = "Hnoll Cut Tail" + icon_state = "hair_cuttail" + uid = "acc_hair_hnoll_cuttail" + +/decl/sprite_accessory/hair/hnoll/dreadlocks + name = "Hnoll Dreadlocks" + icon_state = "hair_dreadlocks" + uid = "acc_hair_hnoll_deadlocks" + +/decl/sprite_accessory/facial_hair/hnoll + name = "Hnoll Sideburns" + icon_state = "facial_sideburns" + species_allowed = list(/decl/species/hnoll::uid) + icon = 'mods/content/fantasy/icons/hnoll/facial.dmi' + color_blend = ICON_MULTIPLY + uid = "acc_fhair_hnoll_sideburns" + +/decl/sprite_accessory/facial_hair/hnoll/mutton + name = "Hnoll Mutton Chops" + icon_state = "facial_mutton" + uid = "acc_fhair_hnoll_mutton" + +/decl/sprite_accessory/facial_hair/hnoll/pencilstache + name = "Hnoll Pencil Moustache" + icon_state = "facial_pencilstache" + uid = "acc_fhair_hnoll_pencilstache" + +/decl/sprite_accessory/facial_hair/hnoll/moustache + name = "Hnoll Moustache" + icon_state = "facial_moustache" + uid = "acc_fhair_hnoll_moustache" + +/decl/sprite_accessory/facial_hair/hnoll/goatee + name = "Hnoll Goatee" + icon_state = "facial_goatee" + uid = "acc_fhair_hnoll_goatee" + +/decl/sprite_accessory/facial_hair/hnoll/smallstache + name = "Hnoll Small Moustache" + icon_state = "facial_smallstache" + uid = "acc_fhair_hnoll_smallstache" + +/decl/sprite_accessory/marking/hnoll + name = "Hnoll Nose" + icon_state = "nose" + icon = 'mods/content/fantasy/icons/hnoll/markings.dmi' + species_allowed = list(/decl/species/hnoll::uid) + body_parts = list(BP_HEAD) + color_blend = ICON_MULTIPLY + uid = "acc_marking_hnoll_nose" + +/decl/sprite_accessory/marking/hnoll/ears + name = "Hnoll Wide Ears" + icon_state = "ears_plain" + mask_to_bodypart = FALSE + uid = "acc_marking_hnoll_wideears" + +/decl/sprite_accessory/marking/hnoll/ears/wide_inner + name = "Hnoll Wide Ears Interior" + icon_state = "ears_plain_inner" + uid = "acc_marking_hnoll_wideears_inner" + +/decl/sprite_accessory/marking/hnoll/ears/wide_tuft + name = "Hnoll Wide Ears Tuft" + icon_state = "ears_plain_tuft" + uid = "acc_marking_hnoll_wideears_tuft" + +/decl/sprite_accessory/marking/hnoll/ears/narrow + name = "Hnoll Narrow Ears" + icon_state = "ears_narrow" + uid = "acc_marking_hnoll_narrowears" + +/decl/sprite_accessory/marking/hnoll/ears/narrow_inner + name = "Hnoll Narrow Ears Interior" + icon_state = "ears_narrow_inner" + uid = "acc_marking_hnoll_narrowears_inner" + +/decl/sprite_accessory/marking/hnoll/ears/narrow_tuft + name = "Hnoll Narrow Ears Tuft" + icon_state = "ears_narrow_tuft" + uid = "acc_marking_hnoll_narrowears_tuft" + +/decl/sprite_accessory/marking/hnoll/ears/earrings + name = "Hnoll Earrings" + icon_state = "earrings" + uid = "acc_marking_hnoll_earrings" + +/decl/sprite_accessory/marking/hnoll/patches + name = "Patches (Body)" + icon_state = "patches" + body_parts = list(BP_CHEST, BP_GROIN) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_hnoll_patches" + +/decl/sprite_accessory/marking/hnoll/patches/left_arm + name = "Patches (Left Arm)" + body_parts = list(BP_L_ARM, BP_L_HAND) + uid = "acc_marking_hnoll_patches_leftarm" + +/decl/sprite_accessory/marking/hnoll/patches/right_arm + name = "Patches (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_hnoll_patches_rightarm" + +/decl/sprite_accessory/marking/hnoll/patches/left_leg + name = "Patches (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_hnoll_patches_leftleg" + +/decl/sprite_accessory/marking/hnoll/patches/right_leg + name = "Patches (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_hnoll_patches_rightleg" + +/decl/sprite_accessory/marking/hnoll/tiger + name = "Tiger Stripes (Head)" + icon_state = "tiger" + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_hnoll_tiger_head" + +/decl/sprite_accessory/marking/hnoll/tiger/body + name = "Tiger Stripes (Body)" + body_parts = list(BP_CHEST, BP_GROIN) + uid = "acc_marking_hnoll_tiger_body" + +/decl/sprite_accessory/marking/hnoll/tiger/left_arm + name = "Tiger Stripes (Left Arm)" + body_parts = list(BP_L_ARM, BP_L_HAND) + uid = "acc_marking_hnoll_tiger_leftarm" + +/decl/sprite_accessory/marking/hnoll/tiger/right_arm + name = "Tiger Stripes (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_hnoll_tiger_rightarm" + +/decl/sprite_accessory/marking/hnoll/tiger/left_leg + name = "Tiger Stripes (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_hnoll_tiger_leftleg" + +/decl/sprite_accessory/marking/hnoll/tiger/right_leg + name = "Tiger Stripes (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_hnoll_tiger_rightleg" + +/decl/sprite_accessory/marking/hnoll/spots + name = "Spots (Head)" + icon_state = "spots" + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_hnoll_spots_head" + +/decl/sprite_accessory/marking/hnoll/spots/body + name = "Spots (Body)" + body_parts = list(BP_CHEST, BP_GROIN) + uid = "acc_marking_hnoll_spots_body" + +/decl/sprite_accessory/marking/hnoll/spots/left_arm + name = "Spots (Left Arm)" + body_parts = list(BP_L_ARM, BP_L_HAND) + uid = "acc_marking_hnoll_spots_leftarm" + +/decl/sprite_accessory/marking/hnoll/spots/right_arm + name = "Spots (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_hnoll_spots_rightarm" + +/decl/sprite_accessory/marking/hnoll/spots/left_leg + name = "Spots (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_hnoll_spots_leftleg" + +/decl/sprite_accessory/marking/hnoll/spots/right_leg + name = "Spots (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_hnoll_spots_rightleg" + +/decl/sprite_accessory/marking/hnoll/pawsocks + name = "Pawsocks (Left Arm)" + icon_state = "pawsocks" + body_parts = list(BP_L_ARM, BP_L_HAND) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_hnoll_pawsocks_leftarm" + +/decl/sprite_accessory/marking/hnoll/pawsocks/right_arm + name = "Pawsocks (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_hnoll_pawsocks_rightarm" + +/decl/sprite_accessory/marking/hnoll/pawsocks/left_leg + name = "Pawsocks (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_hnoll_pawsocks_leftleg" + +/decl/sprite_accessory/marking/hnoll/pawsocks/right_leg + name = "Pawsocks (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_hnoll_pawsocks_rightleg" + +/decl/sprite_accessory/marking/hnoll/belly + name = "Belly" + icon_state = "belly" + body_parts = list(BP_CHEST, BP_GROIN) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_hnoll_belly" diff --git a/mods/content/fantasy/datum/hnoll/organs.dm b/mods/content/fantasy/datum/hnoll/organs.dm new file mode 100644 index 000000000000..82794e65709b --- /dev/null +++ b/mods/content/fantasy/datum/hnoll/organs.dm @@ -0,0 +1,4 @@ +/obj/item/organ/external/tail/hnoll + tail_icon = 'mods/content/fantasy/icons/hnoll/tail.dmi' + tail_blend = ICON_MULTIPLY + tail_animation_states = 1 diff --git a/mods/content/fantasy/datum/hnoll/species.dm b/mods/content/fantasy/datum/hnoll/species.dm new file mode 100644 index 000000000000..e21059381009 --- /dev/null +++ b/mods/content/fantasy/datum/hnoll/species.dm @@ -0,0 +1,80 @@ +/datum/appearance_descriptor/age/hnoll + standalone_value_descriptors = list( + "an infant" = 1, + "a toddler" = 3, + "a child" = 7, + "an adolescent" = 13, + "a young adult" = 18, + "an adult" = 30, + "middle-aged" = 55, + "aging" = 80, + "elderly" = 140 + ) + +/decl/species/hnoll + uid = "species_hnoll" + name = "Hnoll" + name_plural = "Hnoll" + description = "The hnoll are thickly-furred, powerfully built bipeds with a notable resemblance to the steppe \ + hyenas that often decorate their coinage and art. The oldest hnoll cultures make their home on the Grass Ocean and the \ + slopes of the Nine Mothers, and the hnoll conquest of the downlands centuries in the past was the inciting moment of \ + the continent-spanning Imperial Aegis. Hnoll culture is usually matriarchial, favouring stoutness of body and will, \ + devotion to community, and loyalty to the family over individual glory or strength of arms." + hidden_from_codex = FALSE + available_bodytypes = list(/decl/bodytype/hnoll) + preview_outfit = /decl/outfit/job/generic/fantasy + spawn_flags = SPECIES_CAN_JOIN + flesh_color = "#ae7d32" + hunger_factor = DEFAULT_HUNGER_FACTOR * 1.2 + thirst_factor = DEFAULT_THIRST_FACTOR * 1.2 + gluttonous = GLUT_TINY + move_trail = /obj/effect/decal/cleanable/blood/tracks/paw + base_external_prosthetics_model = null + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/fantasy, + /decl/background_detail/location/fantasy/mountains, + /decl/background_detail/location/fantasy/steppe, + /decl/background_detail/location/fantasy/woods, + /decl/background_detail/location/other + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/fantasy, + /decl/background_detail/faction/fantasy/barbarian, + /decl/background_detail/faction/fantasy/centrist, + /decl/background_detail/faction/fantasy/aegis, + /decl/background_detail/faction/fantasy/primitivist, + /decl/background_detail/faction/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/fantasy, + /decl/background_detail/heritage/fantasy/steppe, + /decl/background_detail/heritage/fantasy/hnoll, + /decl/background_detail/heritage/fantasy/hnoll/aegis, + /decl/background_detail/heritage/other + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/ancestors, + /decl/background_detail/religion/folk_deity, + /decl/background_detail/religion/anima_materialism, + /decl/background_detail/religion/virtuist, + /decl/background_detail/religion/other + ) + ) + + default_emotes = list( + /decl/emote/visible/tail/swish, + /decl/emote/visible/tail/wag, + /decl/emote/visible/tail/sway, + /decl/emote/visible/tail/qwag, + /decl/emote/visible/tail/fastsway, + /decl/emote/visible/tail/swag, + /decl/emote/visible/tail/stopsway + ) + +/decl/species/hnoll/handle_additional_hair_loss(var/mob/living/human/H, var/defer_body_update = TRUE) + . = H?.set_skin_colour(rgb(189, 171, 143)) diff --git a/mods/content/fantasy/datum/kobaloi/bodytypes.dm b/mods/content/fantasy/datum/kobaloi/bodytypes.dm new file mode 100644 index 000000000000..72740539a495 --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/bodytypes.dm @@ -0,0 +1,122 @@ +/decl/bodytype/kobaloi + name = "kobaloi" + bodytype_category = BODYTYPE_KOBALOI + limb_blend = ICON_MULTIPLY + bandages_icon = 'icons/mob/bandage.dmi' + icon_base = 'mods/content/fantasy/icons/kobaloi/body.dmi' + icon_deformed = 'mods/content/fantasy/icons/kobaloi/body.dmi' + eye_icon = 'mods/content/fantasy/icons/kobaloi/eyes.dmi' + skeletal_icon = 'mods/content/fantasy/icons/kobaloi/skeleton.dmi' + base_color = "#8f974a" + base_eye_color = "#d95763" + bodytype_flag = BODY_EQUIP_FLAG_KOBALOI + appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR + health_hud_intensity = 1.75 + movement_slowdown = -0.5 + eye_blend = ICON_MULTIPLY + eye_darksight_range = 7 + eye_flash_mod = 2 + age_descriptor = /datum/appearance_descriptor/age + override_limb_types = list( + BP_HEAD = /obj/item/organ/external/head/kobaloi, + BP_TAIL = /obj/item/organ/external/tail/kobaloi + ) + default_sprite_accessories = list( + SAC_MARKINGS = list( + /decl/sprite_accessory/marking/kobaloi/left_ear = list(SAM_COLOR = "#8f974a"), + /decl/sprite_accessory/marking/kobaloi/right_ear = list(SAM_COLOR = "#8f974a") + ) + ) + eye_low_light_vision_effectiveness = 0.15 + eye_low_light_vision_adjustment_speed = 0.3 + uid = "bodytype_kobaloi" + +/decl/bodytype/kobaloi/Initialize() + if(!_equip_adjust) + _equip_adjust = list( + (BP_R_HAND) = list( + "[NORTH]" = list( 1, -4), + "[EAST]" = list( 0, -4), + "[SOUTH]" = list(-1, -4), + "[WEST]" = list(-1, -4) + ), + (BP_L_HAND) = list( + "[NORTH]" = list(-1, -4), + "[EAST]" = list( 1, -4), + "[SOUTH]" = list( 1, -4), + "[WEST]" = list( 0, -4) + ), + (slot_w_uniform_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-1, -6) + ), + (slot_belt_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-1, -6) + ), + (slot_handcuffed_str) = list( + "[NORTH]" = list(-1, -4), + "[EAST]" = list( 1, -4), + "[SOUTH]" = list( 1, -4), + "[WEST]" = list( 0, -4) + ), + (slot_wear_id_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-1, -6) + ), + (slot_gloves_str) = list( + "[NORTH]" = list(-1, -4), + "[EAST]" = list( 1, -4), + "[SOUTH]" = list( 1, -4), + "[WEST]" = list( 0, -4) + ), + (slot_wear_suit_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-1, -6) + ), + (slot_back_str) = list( + "[NORTH]" = list( 0, -5), + "[EAST]" = list( 1, -5), + "[SOUTH]" = list( 0, -5), + "[WEST]" = list(-1, -5) + ), + (slot_glasses_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 3, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-3, -6) + ), + (slot_wear_mask_str) = list( + "[NORTH]" = list( 0, -7), + "[EAST]" = list( 5, -7), + "[SOUTH]" = list( 0, -7), + "[WEST]" = list(-5, -7) + ), + (slot_head_str) = list( + "[NORTH]" = list( 0, -5), + "[EAST]" = list( 3, -5), + "[SOUTH]" = list( 0, -5), + "[WEST]" = list(-3, -5) + ), + (slot_l_ear_str) = list( + "[NORTH]" = list( 0, -5), + "[EAST]" = list( 3, -5), + "[SOUTH]" = list( 0, -5), + "[WEST]" = list(-3, -5) + ), + (slot_r_ear_str) = list( + "[NORTH]" = list( 0, -5), + "[EAST]" = list( 3, -5), + "[SOUTH]" = list( 0, -5), + "[WEST]" = list(-3, -5) + ) + ) + . = ..() diff --git a/mods/content/fantasy/datum/kobaloi/clothing.dm b/mods/content/fantasy/datum/kobaloi/clothing.dm new file mode 100644 index 000000000000..71346517d9c2 --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/clothing.dm @@ -0,0 +1,2 @@ +/obj/item/bag/sack + _kobaloi_onmob_icon = 'mods/content/fantasy/icons/clothing/sack_kobaloi.dmi' diff --git a/mods/content/fantasy/datum/kobaloi/culture.dm b/mods/content/fantasy/datum/kobaloi/culture.dm new file mode 100644 index 000000000000..0e12cb353e7c --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/culture.dm @@ -0,0 +1,23 @@ +/decl/background_detail/location/fantasy/kobaloi + name = "Kobaloi Caverns" + description = "Kobaloi often find homes in the quiet, overlooked places of the world. Many dwell within caves and \ + tunnels, cultivating moss and fungus and fishing in the black rivers beneath the earth. Such families and clans are often \ + fearful of the upper world, preferring the quiet safety of the dark to whatever nonsense is going on aboveground." + name_language = /decl/language/kobaloi + uid = "location_fantasy_kobaloi" + +/decl/background_detail/faction/fantasy/kobaloi + name = "Cavern Traditionalist" + description = "Within the delicate ecosystem of the deep caves, caution and care are critical traits. Even when kobaloi migrate \ + to the surface, those who were reared in the caves are often considered timid or overly risk-adverse by their new peers." + name_language = /decl/language/kobaloi + uid = "faction_fantasy_kobaloi" + +/decl/background_detail/heritage/fantasy/kobaloi + name = "Deep Dweller" + description = "Living in the silent darkness beneath the world encourages introspection, self-awareness and caution. Those \ + who are raised in such places often develop a keen awareness of the delicate nature of the cavern ecosystems, the necessity \ + of supporting and working with your community, and more often than not a deep and abiding sense of superstition and spirituality, \ + as the deep caverns sometimes whisper with echoes of lost gods and mine spirits trapped far below." + name_language = /decl/language/kobaloi + uid = "heritage_fantasy_kobaloi" diff --git a/mods/content/fantasy/datum/kobaloi/language.dm b/mods/content/fantasy/datum/kobaloi/language.dm new file mode 100644 index 000000000000..bf02148ce55c --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/language.dm @@ -0,0 +1,45 @@ +/decl/language/kobaloi + name = "Kobaloi Tongue" + shorthand = "KB" + desc = "The kobaloi have a huge variety of languages, sometimes differing even between groups in the same cave system, but all of them have some degree of overlap to allow mutual intelligibility." + speech_verb = "says" + ask_verb = "asks" + exclaim_verb = "exclaims" + colour = "indian" + key = "m" + flags = LANG_FLAG_WHITELISTED + space_chance = 100 // We generate entire words rather than syllables, so we always need a space. + + // Consonant and vowel lists adapted from https://dwarffortresswiki.org/index.php/DF2014:Kobold_language + // Fine detail was not adapted as it was more effort than I wanted to put in for a video game reference. + var/list/s1c1 = list("b", "d", "st", "sh", "s", "t", "th", "ch", "l", "f", "g", "k", "p", "j") + var/list/s1c2 = list("r", "l", "") + var/list/s1v = list("a", "o", "u", "ay", "ee", "i") + var/list/s2c = list("b", "d", "l", "f", "g", "k") + var/list/s2v = list("a", "i", "o", "u") + var/list/s3c = list("m", "r", "ng", "b", "rb", "mb", "g", "lg", "l", "lb", "lm", "k", "nk", "ld", "d", "rsn") + var/list/s3r = list("is", "us", "er", "in") + +/decl/language/kobaloi/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + return capitalize(get_next_scramble_token()) + +/decl/language/kobaloi/get_next_scramble_token() + var/list/word = list() + + // 1-2 primary syllables + for(var/i = 1 to rand(1, 2)) + word += pick(s1c1) + word += pick(s1c2) + word += pick(s1v) + + // 0-2 secondary syllables + for(var/i = 1 to rand(1,3)-1) + word += pick(s2c) + word += pick(s2v) + + // 1 final syllable + word += pick(s3c) + word += pick(s3r) + + return jointext(word, null) + diff --git a/mods/content/fantasy/datum/kobaloi/markings.dm b/mods/content/fantasy/datum/kobaloi/markings.dm new file mode 100644 index 000000000000..23281846c75a --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/markings.dm @@ -0,0 +1,120 @@ +/obj/item/organ/external/tail/kobaloi + tail_icon = 'mods/content/fantasy/icons/kobaloi/body.dmi' + tail_blend = ICON_MULTIPLY + +/decl/sprite_accessory/marking/kobaloi + abstract_type = /decl/sprite_accessory/marking/kobaloi + icon = 'mods/content/fantasy/icons/kobaloi/markings.dmi' + color_blend = ICON_MULTIPLY + species_allowed = list(/decl/species/kobaloi::uid) + body_parts = list(BP_HEAD) + mask_to_bodypart = FALSE + +/decl/sprite_accessory/marking/kobaloi/left_ear + name = "Left Ear" + icon_state = "left_ear" + uid = "acc_kobaloi_ear_left" + +/decl/sprite_accessory/marking/kobaloi/right_ear + name = "Right Ear" + icon_state = "right_ear" + uid = "acc_kobaloi_ear_right" + +/decl/sprite_accessory/marking/kobaloi/left_ear_floopy + name = "Floppy Left Ear" + icon_state = "left_ear_floopy" + uid = "acc_kobaloi_ear_left_floopy" + +/decl/sprite_accessory/marking/kobaloi/right_ear_floopy + name = "Floppy Right Ear" + icon_state = "right_ear_floopy" + uid = "acc_kobaloi_ear_right_floopy" + +/decl/sprite_accessory/marking/kobaloi/left_ear_stub + name = "Left Ear Stub" + icon_state = "left_ear_stub" + uid = "acc_kobaloi_ear_stub_left" + +/decl/sprite_accessory/marking/kobaloi/right_ear_stub + name = "Right Ear Stub" + icon_state = "right_ear_stub" + uid = "acc_kobaloi_ear_stub_right" + +/decl/sprite_accessory/marking/kobaloi/body + name = "Mottling" + icon_state = "mottling" + uid = "acc_kobaloi_mottling" + mask_to_bodypart = TRUE + body_parts = list(BP_CHEST, BP_GROIN, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT) + +/decl/sprite_accessory/marking/kobaloi/body/stripes + name = "Stripes" + icon_state = "stripes" + uid = "acc_kobaloi_stripes" + +/decl/sprite_accessory/marking/kobaloi/body/underbelly + name = "Underbelly" + icon_state = "underbelly" + uid = "acc_kobaloi_underbelly" + body_parts = list(BP_CHEST, BP_GROIN) + +/decl/sprite_accessory/marking/kobaloi/face + name = "Muzzle" + icon_state = "muzzle" + uid = "acc_kobaloi_muzzle" + mask_to_bodypart = TRUE + body_parts = list(BP_HEAD) + +/decl/sprite_accessory/marking/kobaloi/face/nose + name = "Nose" + icon_state = "nose" + uid = "acc_kobaloi_nose" + +/decl/sprite_accessory/marking/kobaloi/horns + abstract_type = /decl/sprite_accessory/marking/kobaloi/horns + icon = 'mods/content/fantasy/icons/kobaloi/horns.dmi' + +/decl/sprite_accessory/marking/kobaloi/horns/spikes + name = "Spikes" + icon_state = "spikes" + uid = "acc_kobaloi_spikes" + +/decl/sprite_accessory/marking/kobaloi/horns/left_horn + name = "Left Horn" + icon_state = "left_horn" + uid = "acc_kobaloi_horn_left" + +/decl/sprite_accessory/marking/kobaloi/horns/right_horn + name = "Right Horn" + icon_state = "right_horn" + uid = "acc_kobaloi_horn_right" + +/decl/sprite_accessory/marking/kobaloi/horns/left_broken_horn + name = "Broken Left Horn" + icon_state = "left_broken_horn" + uid = "acc_kobaloi_horn_broken_left" + +/decl/sprite_accessory/marking/kobaloi/horns/right_broken_horn + name = "Broken Right Horn" + icon_state = "right_broken_horn" + uid = "acc_kobaloi_horn_broken_right" + +/decl/sprite_accessory/marking/kobaloi/horns/left_curved_horn + name = "Curved Left Horn" + icon_state = "left_curved_horn" + uid = "acc_kobaloi_horn_curved_left" + +/decl/sprite_accessory/marking/kobaloi/horns/right_curved_horn + name = "Curved Right Horn" + icon_state = "right_curved_horn" + uid = "acc_kobaloi_horn_curved_right" + +/decl/sprite_accessory/marking/kobaloi/horns/left_antler + name = "Left Antler" + icon_state = "left_antler" + uid = "acc_kobaloi_antler_left" + +/decl/sprite_accessory/marking/kobaloi/horns/right_antler + name = "Right Antler" + icon_state = "right_antler" + uid = "acc_kobaloi_antler_right" diff --git a/mods/content/fantasy/datum/kobaloi/organs.dm b/mods/content/fantasy/datum/kobaloi/organs.dm new file mode 100644 index 000000000000..6f8bf78c226e --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/organs.dm @@ -0,0 +1,2 @@ +/obj/item/organ/external/head/kobaloi + glowing_eyes = TRUE diff --git a/mods/content/fantasy/datum/kobaloi/species.dm b/mods/content/fantasy/datum/kobaloi/species.dm new file mode 100644 index 000000000000..c34156ee2a9a --- /dev/null +++ b/mods/content/fantasy/datum/kobaloi/species.dm @@ -0,0 +1,52 @@ +/decl/species/kobaloi + uid = "species_kobaloi" + name = "Kobaloi" + name_plural = "Kobaloi" + spawn_flags = SPECIES_CAN_JOIN + preview_outfit = null + description = "Kobaloi are small, scaled and furred creatures that usually dwell in the quiet places of the world, \ + often living and working unseen or overlooked alongside human and hnoll. Many assume that kobaloi all live in tribes within \ + caves, eating mushrooms and moss, but in the modern era an increasing number of kobaloi families have left their traditional \ + warrens to take up residence in cities and settlements on the surface. The collapse of the Imperial Aegis went largely unnoticed \ + by the kobaloi, and they usually try to keep out of any hnoll-human political or ideological conflicts if they can." + hidden_from_codex = FALSE + available_bodytypes = list( + /decl/bodytype/kobaloi + ) + preview_outfit = /decl/outfit/job/generic/fantasy + base_external_prosthetics_model = null + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/fantasy, + /decl/background_detail/location/fantasy/mountains, + /decl/background_detail/location/fantasy/steppe, + /decl/background_detail/location/fantasy/woods, + /decl/background_detail/location/fantasy/kobaloi, + /decl/background_detail/location/other + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/fantasy, + /decl/background_detail/faction/fantasy/kobaloi, + /decl/background_detail/faction/fantasy/barbarian, + /decl/background_detail/faction/fantasy/centrist, + /decl/background_detail/faction/fantasy/aegis, + /decl/background_detail/faction/fantasy/primitivist, + /decl/background_detail/faction/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/fantasy/kobaloi, + /decl/background_detail/heritage/other + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/ancestors, + /decl/background_detail/religion/folk_deity, + /decl/background_detail/religion/anima_materialism, + /decl/background_detail/religion/virtuist, + /decl/background_detail/religion/other + ) + ) + diff --git a/mods/content/fantasy/datum/locations.dm b/mods/content/fantasy/datum/locations.dm new file mode 100644 index 000000000000..f6ddbe348ef9 --- /dev/null +++ b/mods/content/fantasy/datum/locations.dm @@ -0,0 +1,39 @@ +/decl/background_detail/location/fantasy + name = "the Downlands" + description = "The 'downlands' are a vaguely defined swathe of lush, heavily forested terrain in the middle \ + of the continent. The region was historically the territory of the now-defunct Imperial Aegis, and is now \ + largely under the control of the inheritor Splinter Kingdoms. Banditry, wild animal attacks, and oppressive \ + local powers are rife. The Queens' Road, once a continent-spanning marvel, is now a rotting shadow of itself, \ + and overgrown, decaying ruins from the time of the Aegis are scattered across the region." + uid = "location_fantasy_downlands" + +/decl/background_detail/location/fantasy/mountains + name = "Nine Mothers" + description = "The Nine Mothers form an enormous, frigid mountain range that runs north-southeast across the \ + continent, bracketing the downloands to the east and unknown territories to the west. The eastern faces of \ + the Mothers slope down into tundra that abuts the steppe territories known as the Grass Ocean. The range's \ + name originates from some of the oldest known hnoll folklore, concerning the first matriarches." + uid = "location_fantasy_ninemothers" + +/decl/background_detail/location/fantasy/steppe + name = "the Grass Ocean" + description = "The Grass Ocean is a massive expanse of open steppe that has been home to hnoll cultures since time \ + immemorial. The lack of resources and large game, scarcity of potable water, and general exposure to the elements \ + breed hardy and self-reliant people. They are bracketed to the west by the Nine Mothers, and to the east by the \ + downlands." + uid = "location_fantasy_steppe" + +/decl/background_detail/location/fantasy/woods + name = "the Deepwood" // The Gloaming Wood is taken by Pathfinder and some Tasmanian crime show :( + description = "A number of regions within and around the downlands resisted the Imperial Aegis's efforts at colonization, \ + repulsing the legions with whatever tools they could. The largest of these territories is known colloquially as the \ + Deepwood, and is a belt of thickly forested land at the center of the Splinter Kingdoms. The closest thing to towns \ + in the Deepwood are a scattered handful of hamlets around the edges, and even they do not commonly explore any deeper \ + into the woods. Whatever art was used to protect the Deepwood makes it a highly oppressive and unfriendly place to \ + interlopers, and wild tales of spirits, monsters, corrupt anima, and stolen babies abound." + uid = "location_fantasy_deepwood" + +// TODO +// - Equatorial/tropical territories southeast of the downlands +// - Coastal territories east of the downlands +// - Underground territories for dvergr and kobaloi diff --git a/mods/content/fantasy/datum/materials.dm b/mods/content/fantasy/datum/materials.dm new file mode 100644 index 000000000000..ffc4bae9342e --- /dev/null +++ b/mods/content/fantasy/datum/materials.dm @@ -0,0 +1,9 @@ +/decl/material/solid/graphite + name = "coal" + codex_name = "loose coal" + ore_name = "coal" + +/decl/material/solid/densegraphite + name = "dense coal" + codex_name = "dense coal" + ore_name = "dense coal" diff --git a/mods/content/fantasy/datum/names.dm b/mods/content/fantasy/datum/names.dm new file mode 100644 index 000000000000..1751d76ed099 --- /dev/null +++ b/mods/content/fantasy/datum/names.dm @@ -0,0 +1,171 @@ +// Names taken from https://www.behindthename.com/names/language/latin/1 +/datum/map + first_names_male = list( + "Aaron", "Abacuc", "Abdias", "Abel", "Abia", "Abidan", + "Abimelech", "Abisai", "Abner", "Abraham", "Absalom", "Abundius", + "Achab", "Achaicus", "Adam", "Adeodatus", "Adina", "Aegidius", + "Aelianus", "Aelius", "Aemilianus", "Aemilius", "Aeneas", "Aetius", + "Africanus", "Agrippa", "Ahab", "Ahenobarbus", "Ahoth", "Albanus", + "Albinus", "Albus", "Alphaeus", "Alphius", "Amabilis", "Amadeus", + "Amandus", "Amantius", "Amator", "Amatus", "Amnon", "Amor", + "Amos", "Amram", "Amulius", "Ananias", "Anath", "Andeolus", + "Andreas", "Andronicus", "Angelus", "Annas", "Antoninus", "Antonius", + "Appius", "Aquila", "Aquilinus", "Aram", "Archelaus", "Archippus", + "Arihel", "Ascanius", "Aser", "Atilius", "Augustinus", "Augustus", + "Aulus", "Aurelianus", "Aurelius", "Auster", "Avilius", "Avitus", + "Azarias", "Azazias", "Baal", "Balbinus", "Balbus", "Baltassar", + "Baptista", "Barnabas", "Bartholomeus", "Baruch", "Beatus", "Beelzebub", + "Belial", "Benedictus", "Beniamin", "Benignus", "Blandinus", "Blandus", + "Blasius", "Bonifatius", "Bonitus", "Booz", "Brutus", "Caecilius", + "Caelestinus", "Caelestis", "Caelinus", "Caelius", "Caesar", "Caesarius", + "Caeso", "Caesonius", "Caiaphas", "Caietanus", "Cain", "Cainan", + "Caius", "Calixtus", "Callistus", "Callixtus", "Calogerus", "Calpurnius", + "Calvus", "Camillus", "Candidus", "Caracalla", "Carpus", "Cassian", + "Cassianus", "Cassius", "Catellus", "Cato", "Celsus", "Cephas", + "Chaleb", "Chanaan", "Christianus", "Christophorus", "Cicero", "Clarus", + "Claudius", "Clemens", "Clementius", "Cleopas", "Climacus", "Cloelius", + "Cnaeus", "Columba", "Columbanus", "Constans", "Constantinus", "Constantius", + "Consus", "Corbinianus", "Cornelius", "Crescens", "Crescentius", "Crispinus", + "Crispus", "Cupid", "Cupido", "Cyprianus", "Cyriacus", "Cyrus", + "Danihel", "Darius", "David", "Decimus", "Delphinus", "Deodatus", + "Desideratus", "Desiderius", "Deusdedit", "Diadumenianus", "Diocletianus", "Dominicus", + "Domitianus", "Domitius", "Domninus", "Domnius", "Domnus", "Donatianus", + "Donatus", "Dorotheus", "Drusus", "Duilius", "Durans", "Egnatius", + "Eleazar", "Elias", "Eliezer", "Eligius", "Eliseus", "Eliud", + "Emerentius", "Emmanuhel", "Emygdius", "Ennius", "Enoch", "Enos", + "Epaphras", "Epaphroditus", "Ephesius", "Ephraim", "Erastus", "Esaias", + "Esau", "Ethan", "Euryalus", "Eustachius", "Eutychus", "Evander", + "Evandrus", "Ezechias", "Ezechiel", "Ezras", "Fabianus", "Fabius", + "Fabricius", "Facundus", "Faunus", "Faustinus", "Faustus", "Felician", + "Felicianus", "Felicius", "Felinus", "Felix", "Ferrutius", "Festus", + "Fidelis", "Finees", "Firminus", "Flaminius", "Flavianus", "Flavius", + "Florentinus", "Florentius", "Florianus", "Florinus", "Florus", "Fortunatus", + "Franciscus", "Frigidianus", "Fructuosus", "Fulgentius", "Fulvius", "Gabinus", + "Gabriel", "Gabrihel", "Gaius", "Gallus", "Gedeon", "Gemini", + "Generosus", "Genesius", "Gereon", "Germanicus", "Germanus", "Gerontius", + "Giano", "Giove", "Glaucia", "Gnaeus", "Goliath", "Gordianus", + "Gratianus", "Habacuc", "Hadrianus", "Heli", "Helias", "Helihel", + "Helvius", "Hercules", "Herminius", "Herodes", "Herodion", "Hieremias", + "Hieremihel", "Hieu", "Hiezecihel", "Hilarius", "Honoratus", "Honorinus", + "Honorius", "Horatius", "Hortensius", "Iachin", "Iacob", "Iacobus", + "Iacomus", "Iafeth", "Iair", "Iairus", "Ianuarius", "Ianus", + "Iared", "Iason", "Iepthae", "Ieremahel", "Ieronimus", "Iesse", + "Iesus", "Ignatius", "Innocentius", "Ioab", "Iob", "Iohannes", + "Iohel", "Iona", "Ionas", "Ionathan", "Ioram", "Iordanes", + "Iordanus", "Iosaphat", "Ioseph", "Iosephus", "Iosias", "Iosue", + "Iovianus", "Iovis", "Iovita", "Isaac", "Isaurus", "Isidorus", + "Ismahel", "Israhel", "Issachar", "Italus", "Ithamar", "Iudas", + "Iulianus", "Iulius", "Iunius", "Iuppiter", "Iustinianus", "Iustinus", + "Iustus", "Iuvenalis", "Jacobus", "Januarius", "Janus", "Joannes", + "Johannes", "Jordanes", "Jove", "Jovian", "Julius", "Junius", + "Jupiter", "Justus", "Laelius", "Lamech", "Laurentinus", "Laurentius", + "Laurus", "Lazarus", "Leo", "Leocadius", "Leonius", "Lepidus", + "Levi", "Liber", "Liberatus", "Liberius", "Liborius", "Livianus", + "Livius", "Longinus", "Loukios", "Lucanus", "Lucas", "Lucianus", + "Lucilius", "Lucius", "Lucretius", "Lupus", "Magnus", "Malachi", + "Manahem", "Manasses", "Manius", "Manlius", "Marcellinus", "Marcellus", + "Marcianus", "Marcius", "Marcus", "Mardocheus", "Marianus", "Marinus", + "Marius", "Mars", "Marte", "Martialis", "Martinus", "Mathusalam", + "Matthan", "Mattheus", "Matthias", "Mauritius", "Maurus", "Maxentius", + "Maximianus", "Maximilianus", "Maximinus", "Maximus", "Mercurius", "Mercury", + "Micha", "Michaeas", "Michael", "Michahel", "Micheas", "Mnason", + "Modestus", "Moses", "Moyses", "Nabuchodonosor", "Nadab", "Naevius", + "Narcissus", "Natalius", "Nathan", "Nathanahel", "Nazarenus", "Nazarius", + "Necoda", "Neemias", "Neptune", "Neptuno", "Neptunus", "Nereus", + "Nero", "Nerva", "Nettuno", "Netuno", "Nicanor", "Nicodemus", + "Nisus", "Noe", "Nonus", "Numitor", "Obed", "Octavianus", + "Octavius", "Olympas", "Onesimus", "Onesiphorus", "Onuphrius", "Osee", + "Otho", "Ovidius", "Ozi", "Ozias", "Ozihel", "Paschalis", + "Pastor", "Patricius", "Paulinus", "Paulus", "Peregrinus", "Petronius", + "Petrus", "Phanuhel", "Phares", "Philemon", "Philetus", "Philippus", + "Phunihel", "Pius", "Placidus", "Plinius", "Pluto", "Pollux", + "Pompeius", "Pompilius", "Pomponius", "Pontius", "Porcius", "Postumus", + "Primitivus", "Primus", "Priscus", "Prochorus", "Prosperus", "Prudentius", + "Publius", "Quinctilianus", "Quinctilius", "Quinctius", "Quinctus", "Quintilianus", + "Quintilius", "Quintillus", "Quintinus", "Quintius", "Quintus", "Quirinus", + "Rafahel", "Raguhel", "Rauhel", "Regulus", "Remigius", "Remus", + "Renatus", "Rogatus", "Romaeus", "Romanus", "Romilius", "Romulus", + "Ruben", "Rufinus", "Rufus", "Rusticus", "Sabellius", "Sabinus", + "Salathihel", "Salomon", "Salvator", "Salvius", "Samson", "Samuhel", + "Sanctius", "Saturn", "Saturninus", "Saturnus", "Saul", "Scaevola", + "Scipio", "Sebastianus", "Secundinus", "Secundus", "Sem", "Seneca", + "Sennacherib", "Septimius", "Septimus", "Seraphinus", "Sergius", "Servatius", + "Servius", "Seth", "Severianus", "Severinus", "Severus", "Sextilius", + "Sextus", "Sidonius", "Silas", "Silvanus", "Silverius", "Silvester", + "Silvinus", "Silvius", "Simon", "Sixtus", "Solomon", "Spurius", + "Stephanus", "Summanus", "Symeon", "Tacitus", "Tarquinius", "Tatianus", + "Tatius", "Terentius", "Terminus", "Tertius", "Thaddeus", "Thomas", + "Thracius", "Tiberius", "Tiburtius", "Timaeus", "Timon", "Timotheus", + "Titianus", "Titus", "Tobias", "Tobit", "Traianus", "Trophimus", + "Tullius", "Tullus", "Turibius", "Turnus", "Ulysses", "Urbanus", + "Uri", "Urias", "Ursinus", "Ursus", "Valens", "Valentinianus", + "Valentinus", "Valerianus", "Valerius", "Varinius", "Varius", "Vergilius", + "Verginius", "Verissimus", "Vespasianus", "Vesper", "Viator", "Vibianus", + "Vibius", "Victor", "Victorianus", "Victorinus", "Victorius", "Vincentius", + "Vinicius", "Virgilius", "Vitalianus", "Vitalis", "Vitus", "Vivianus", + "Vulcan", "Vulcanus", "Zabulon", "Zaccharias", "Zaccheus", "Zephyrinus" + ) + first_names_female = list( + "Abia", "Abigail", "Aelia", "Aeliana", "Aemilia", "Aemiliana", + "Afra", "Agar", "Agrippa", "Agrippina", "Alba", "Albana", + "Albina", "Amabilia", "Amanda", "Amata", "Anatolia", "Angela", + "Angerona", "Anna", "Antonia", "Antonina", "Aquilina", "Aseneth", + "Augusta", "Augustina", "Aurea", "Aurelia", "Aureliana", "Aurora", + "Bala", "Balbina", "Barbara", "Basemath", "Basmath", "Beata", + "Beatrix", "Bellona", "Benedicta", "Benigna", "Bernice", "Bethsabee", + "Bibiana", "Blandina", "Caecilia", "Caelia", "Caelina", "Caesonia", + "Calpurnia", "Camilla", "Candace", "Candida", "Cardea", "Carina", + "Cassia", "Cerere", "Ceres", "Chloe", "Christiana", "Clara", + "Claritia", "Claudia", "Clementia", "Cloelia", "Columba", "Concordia", + "Constantia", "Constantina", "Cornelia", "Corona", "Crescentia", "Cyriaca", + "Dalila", "Damaris", "Daria", "Debbora", "Decima", "Delphina", + "Desiderata", "Desideria", "Diana", "Dido", "Dina", "Discordia", + "Dominica", "Domitia", "Domitilla", "Domna", "Domnina", "Donata", + "Drusa", "Drusilla", "Eligia", "Elisabeth", "Elissa", "Ephrath", + "Esther", "Eunice", "Eva", "Fabia", "Fabiana", "Fabiola", + "Fabricia", "Fauna", "Fausta", "Faustina", "Febronia", "Felicia", + "Feliciana", "Felicitas", "Felina", "Flaminia", "Flavia", "Flaviana", + "Flora", "Florentia", "Florentina", "Floriana", "Florina", "Fortuna", + "Fortunata", "Francisca", "Fulgora", "Fulvia", "Galla", "Generosa", + "Germana", "Giunone", "Glaucia", "Gratiana", "Hadriana", "Helvia", + "Herminia", "Herodias", "Hersilia", "Hester", "Hiezabel", "Hilaria", + "Honorata", "Honoria", "Honorina", "Horatia", "Hortensia", "Iahel", + "Idida", "Ignatia", "Illuminata", "Invidia", "Iohanna", "Iovita", + "Isaura", "Iucunda", "Iudith", "Iulia", "Iuliana", "Iunia", + "Iuno", "Iusta", "Iustina", "Iuturna", "Iuventas", "Johanna", + "Julia", "Juliana", "Junia", "Juno", "Junon", "Justa", + "Justina", "Juturna", "Juventas", "Katerina", "Laelia", "Laetitia", + "Lara", "Larunda", "Latona", "Laura", "Laurentia", "Laurentina", + "Laverna", "Lavinia", "Leocadia", "Leonia", "Leontina", "Levana", + "Lia", "Liberata", "Liberia", "Libitina", "Livia", "Liviana", + "Lois", "Longina", "Lucia", "Luciana", "Lucilia", "Lucilla", + "Lucina", "Lucretia", "Luna", "Lydia", "Maala", "Maeleth", + "Magdalene", "Maia", "Maia", "Marcella", "Marcellina", "Marcia", + "Marciana", "Margarita", "Maria", "Mariana", "Marina", "Martha", + "Martina", "Matrona", "Maura", "Maxima", "Maximiliana", "Melania", + "Melcha", "Merob", "Michol", "Minerva", "Minerve", "Modesta", + "Monica", "Naenia", "Narcissa", "Natalia", "Noemi", "Nona", + "Nona", "Nox", "Octavia", "Oliva", "Orpha", "Ovidia", + "Patricia", "Paula", "Paulina", "Pax", "Perpetua", "Petronia", + "Petronilla", "Phoebe", "Pia", "Placida", "Pomona", "Pompeia", + "Pomponia", "Porcia", "Primitiva", "Prisca", "Priscilla", "Proserpina", + "Proserpine", "Prudentia", "Quinta", "Quintina", "Quirina", "Quiteria", + "Rachel", "Rahel", "Rebecca", "Regina", "Regula", "Renata", + "Rhea", "Rhode", "Romana", "Rosalia", "Rufina", "Ruth", + "Sabina", "Saffira", "Salacia", "Salome", "Salvatrix", "Sarai", + "Sarra", "Saturnina", "Scholastica", "Seffora", "Septima", "Seraphina", + "Serena", "Severina", "Sibylla", "Sidonia", "Silvia", "Silvina", + "Sollemnia", "Sperantia", "Spes", "Susanna", "Sybilla", "Tabita", + "Tacita", "Tatiana", "Tertia", "Thamar", "Therasia", "Thersa", + "Thisbe", "Titiana", "Tullia", "Ursa", "Ursula", "Valentina", + "Valeria", "Valeriana", "Varinia", "Venere", "Vénus", "Vênus", + "Venus", "Verena", "Verginia", "Veritas", "Veronica", "Vesta", + "Viatrix", "Vibiana", "Victoria", "Victorina", "Violante", "Virginia", + "Vita", "Viviana", "Zelpha" + ) + last_names = list( + "Acisculus", "Antias", "Cato", "Catullus", "Corvinus", "Falto", + "Fava", "Flaccus", "Manius", "Marinelli", "Maxim", "Orca", + "Paulus", "Poplicola", "Rufus", "Seneca", "Sextus", "Triarius", + "Martinus" + ) \ No newline at end of file diff --git a/mods/content/fantasy/datum/outfits.dm b/mods/content/fantasy/datum/outfits.dm new file mode 100644 index 000000000000..3b65521921b4 --- /dev/null +++ b/mods/content/fantasy/datum/outfits.dm @@ -0,0 +1,10 @@ +/decl/outfit/job/generic/fantasy + name = "Fantasy Outfit" + id_type = null + pda_type = null + l_ear = null + shoes = /obj/item/clothing/shoes/craftable/boots + uniform = list( + /obj/item/clothing/pants/trousers, + /obj/item/clothing/shirt/jerkin + ) diff --git a/mods/content/fantasy/datum/overrides.dm b/mods/content/fantasy/datum/overrides.dm new file mode 100644 index 000000000000..da96ea085c32 --- /dev/null +++ b/mods/content/fantasy/datum/overrides.dm @@ -0,0 +1,67 @@ +/decl/species + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/fantasy, + /decl/background_detail/location/fantasy/mountains, + /decl/background_detail/location/fantasy/steppe, + /decl/background_detail/location/fantasy/woods, + /decl/background_detail/location/other + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/fantasy, + /decl/background_detail/faction/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/fantasy, + /decl/background_detail/heritage/fantasy/steppe, + /decl/background_detail/heritage/other + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/ancestors, + /decl/background_detail/religion/folk_deity, + /decl/background_detail/religion/anima_materialism, + /decl/background_detail/religion/virtuist, + /decl/background_detail/religion/other + ) + ) + default_background_info = list( + /decl/background_category/citizenship = /decl/background_detail/citizenship/other, + /decl/background_category/homeworld = /decl/background_detail/location/fantasy, + /decl/background_category/faction = /decl/background_detail/faction/fantasy, + /decl/background_category/heritage = /decl/background_detail/heritage/fantasy, + /decl/background_category/religion = /decl/background_detail/religion/other + ) + +// Rename wooden prostheses +/decl/bodytype/prosthetic/wooden + name = "carved wooden" // weird to call it 'crude' when it's cutting-edge for the setting + +// Just some fun overrides for when robot debris shows up in maint. +/obj/effect/decal/cleanable/blood/gibs/robot + name = "mysterious debris" + desc = "Some kind of complex, oily detritus. What could it be?" + +/obj/item/remains/robot + name = "mysterious remains" + desc = "The oily remains of some complex, metallic object. What could they be from?" + +// Override to remove non-fantasy stuff. +/obj/random/trash/spawn_choices() + var/static/list/spawnable_choices = list( + /obj/item/remains/lizard, + /obj/effect/decal/cleanable/blood/gibs/robot, + /obj/effect/decal/cleanable/spiderling_remains, + /obj/item/remains/mouse, + /obj/effect/decal/cleanable/vomit, + /obj/effect/decal/cleanable/blood/splatter, + /obj/effect/decal/cleanable/ash, + /obj/effect/decal/cleanable/generic, + /obj/effect/decal/cleanable/flour, + /obj/effect/decal/cleanable/filth, + /obj/effect/decal/cleanable/dirt/visible, + /obj/item/remains/robot + ) + return spawnable_choices diff --git a/mods/content/fantasy/datum/skills.dm b/mods/content/fantasy/datum/skills.dm new file mode 100644 index 000000000000..7d3b8aa29e8e --- /dev/null +++ b/mods/content/fantasy/datum/skills.dm @@ -0,0 +1,306 @@ +/decl/skill/Initialize() + . = ..() + // Rename the default skill levels. + var/static/list/replacement_levels = list( + "Unskilled", + "Beginner", + "Apprentice", + "Journeyman", + "Master" + ) + var/i = 0 + for(var/level in levels) + i++ + var/old_string = levels[level] + levels -= level + levels[replacement_levels[i]] = old_string + +/decl/skill_category/crafting + name = "Crafting" + sort_priority = 3 + +/decl/skill/crafting + abstract_type = /decl/skill/crafting + category = /decl/skill_category/crafting + difficulty = SKILL_EASY + default_max = SKILL_MAX + +/decl/skill/crafting/carpentry + name = "Carpentry" + uid = "skill_crafting_carpentry" + desc = "Your ability to construct and repair objects and structures made out of wood, and use woodworking tools." + levels = list( + "Unskilled" = "You can use an axe to split wood and cut it into planks, but your splits and cuts are often wasteful and uneven. You can nail pieces of wood together.", + "Basic" = "You've whittled a few things out of wood before, and maybe even done a small construction project or two. You're more effective at using tools like hatchets, knives, and hammers for woodworking.", + "Trained" = "You've received some degree of formal instruction or apprenticeship in woodworking, or have a lot of hands-on practice with woodcraft. Your cuts are cleaner, your whittling is quicker, and your joinery is sturdier.", + "Experienced" = "You have a plethora of professional carpentry experience, either as a trade or from running a farmstead or business. You could likely train an apprentice of your own in carpentry.", + "Master" = "Few can match your experience with woodcraft. You fit tight joinery, carve intricate items, and prepare raw material with precision and speed. Trees dream of being worked by your hands." + ) + +/decl/skill/crafting/stonemasonry + name = "Stonemasonry" + uid = "skill_crafting_mason" + desc = "Your ability to chisel, cut, carve, construct with, and knap stone and stone-like materials." + levels = list( + "Unskilled" = "You know that a hammer and chisel are used to split and shape stone, and that bricks are joined using mortar or cement, but you're not entirely sure how to do either of those things. If you tried to chisel a sculpture from a block of stone, you'd risk shattering it entirely, or just having the chisel glance off. You know some primitive tools are made by hitting rocks together to break pieces off, but if you tried you'd probably just make noise and little else.", + "Basic" = "You've done some stoneknapping before and have begun developing an understanding of how stone cracks and splits when struck. You can replicate rough forms out of stone, and while your bricks may not be perfect by any means, they're flat enough to be used in a wall.", + "Trained" = "You can do basic sculpting and carving with a hammer and chisel. You work well with bricks, loose stones, concrete, and rock slabs, whether you're knapping a tool out of flint or carving a form into a block of marble. You may not be able to work professionally at this stage, but you could cut it as an apprentice mason.", + "Experienced" = "You work with stone in your daily life, either on your homestead or as part of your profession. Your work improves in quality and speed, with fewer mistakes that result in scrapped workpieces, even if with some blows you still take off a little more than you planned.", + "Master" = "Your work is delicate yet firm, always applying the exact amount of force for the desired effect, no more and no less. Mistakes in your work are unheard of, at least while you work without interference. You could be the head of a masons' guild, or at least train someone to work as a mason or stonecarver." + ) + +/decl/skill/crafting/metalwork + name = "Metalwork" + uid = "skill_crafting_metalwork" + desc = "Your ability to shape, forge, and cast metal into various decorative or useful objects." + levels = list( + "Unskilled" = "You know that a smith uses an anvil and hammer, that metal has to be hot to be worked, and that metal becomes a liquid when heated enough. You've likely never done anything like that yourself, though, and if you have it wasn't very good.", + "Basic" = "You've got some experience working with metals. You know how to keep a workpiece steady enough on the anvil to strike it with a hammer, but you're not sure how to do anything more complex with an anvil. You can pour hot metal into a warmed mould without much splattering.", + "Trained" = "You know the basics of smithing as a trade, like drawing, punching, and bending, and you can crack a cast item out of a mould without breaking it or the mould as often. You know what fuels burn hot enough to melt certain metals, and what metals go into certain alloys.", + "Experienced" = "You are either a professional smith or farrier, or someone who works extensively with metal as part of another trade. You have the knowledge necessary to supervise and instruct an untrained apprentice to avoid basic mistakes. You may know about more complex or niche alloys, or have experience working expensive or rare metals.", + "Master" = "To you, metal may as well be putty in your hands and under your hammer. You're able to get many casts from one mould, make and fill moulds of detailed objects, and forge intricate projects all on your own. With enough time, you could train someone enough to become a professional smith of their own." + ) + +/decl/skill/crafting/artifice + name = "Artifice" + uid = "skill_crafting_artifice" + desc = "Your ability to create, install, and comprehend complex devices and mechanisms, as well as your ability to create finely-detailed objects like cut gems or jewellery." + levels = list( + "Unskilled" = "You know that gears turn together when intermeshed and that axles are used to connect spinning things, but you've never done more work on a machine than hitting it if it's broken. You struggle with the precision needed to work on finely-detailed objects.", + "Basic" = "You know some basic mechanical principles, like the construction of a basic pulley, or how to put a wheel on an axle. You could fix a broken or stuck well winch, but you'd struggle to deal with a malfunctioning windmill or granary. You have a steadier hand than most, able to place small gems on jewelry and connect small mechanisms.", + "Trained" = "You know how to operate and repair machinery, that axles and gears need to be oiled to work smoothly, and how to figure out what's broken when something goes wrong. You might routinely deal with machines enough to have training with them, or just lots of hands-on experience. You can steady your hands greatly when working with delicate objects.", + "Experienced" = "You work with machinery and delicate crafts either as part of your trade or in your daily life. You could construct a delicate music box or wind-up toy, and can easily connect mechanical components together.", + "Master" = "You are a machine maestro, conducting a symphony of steadily-whirring mechanical parts. Every one of your creations has the utmost care put into its design and manufacture. Your hand never slips nor wavers when you work." + ) + +/decl/skill/crafting/textiles + name = "Textiles" + uid = "skill_crafting_textiles" + desc = "Your ability to create and mend objects made of cloth, thread, leather, and other fabrics." + levels = list( + "Unskilled" = "You can use a sewing needle, but it takes substantial care to not prick yourself with it. With plenty of time, you can weave grass into a basic basket or a mat. Your patch repair jobs are rough and ramshackle and anything you make from scratch is often fragile and misshapen.", + "Basic" = "You've got some experience with a loom or spinning wheel, and you can sew without poking yourself. More advanced stitching, knitting, or weaving techniques are still beyond you, but your handiwork is rapidly improving.", + "Trained" = "You have plenty of experience with weaving, sewing, or spinning, and may even be an apprentice in the trade. You've started to grasp some more advanced techniques and greatly improved your proficiency at the basics.", + "Experienced" = "You've reached a near-mastery of basic sewing, weaving, and leatherworking skills, but still have room to improve. You know enough to train someone in the basics of working with textiles, but mastery is not yet within your reach.", + "Master" = "You've never seen a piece of clothing you couldn't mend. You've mastered not just the basics but more advanced techniques as well, making your skill with texiles nearly unmatched. Your knowledge would be suitable to train an apprentice enough to work independently." + ) + +/decl/skill/crafting/sculpting + name = "Sculpting" + uid = "skill_crafting_sculpting" + desc = "Your ability to craft objects out of soft materials like wax or clay." + levels = list( + "Unskilled" = "You can mould soft materials into rough shapes, but your work is sloppy and anything more complicated than a pinch-pot is beyond your ken.", + "Basic" = "Your understanding of sculpting has improved to allow you to create more even and symmetrical designs. You likely have experience using a pottery wheel, turntable, or similar device.", + "Trained" = "Your creations have become at once more uniform and more aesthetically pleasing, with a consistent level of quality to them.", + "Experienced" = "You have extensive experience with sculpting, able to work with a wide array of materials to form just about anything you set your mind to, as long as you put in the effort.", + "Master" = "You have reached the pinnacle of your craft, able to sculpt clay, wax, and similar materials to your every whim, so much so that a mound of clay may as well be an extension of your will itself." + ) + +// SCULPTING OVERRIDES +/decl/material/solid/clay + crafting_skill = SKILL_SCULPTING + +/decl/material/solid/soil + crafting_skill = SKILL_SCULPTING + +/decl/material/solid/organic/wax + crafting_skill = SKILL_SCULPTING + +// TEXTILES OVERRIDES +/obj/structure/working + work_skill = SKILL_TEXTILES + +/obj/item/stack/material/skin + work_skill = SKILL_TEXTILES + +/obj/item/food/butchery/offal + work_skill = SKILL_TEXTILES + +/decl/material/solid/organic/cloth + crafting_skill = SKILL_TEXTILES + +/decl/material/solid/organic/skin + crafting_skill = SKILL_TEXTILES + +/decl/material/solid/organic/leather + crafting_skill = SKILL_TEXTILES + +/decl/material/solid/organic/plantmatter + crafting_skill = SKILL_TEXTILES + +// STONEMASONRY OVERRIDES +/decl/material/solid/stone + crafting_skill = SKILL_STONEMASONRY + +// METALWORK OVERRIDES +/decl/material/solid/metal + crafting_skill = SKILL_METALWORK + +/obj/item/chems/mould + work_skill = SKILL_METALWORK + +// CARPENTRY OVERRIDES +/decl/material/solid/organic/wood + crafting_skill = SKILL_CARPENTRY + +/decl/material/solid/organic/plantmatter/pith // not quite wood but it's basically still wood carving + crafting_skill = SKILL_CARPENTRY + +// MISC OVERRIDES +/decl/stack_recipe + recipe_skill = null // set based on material + +//overrides for base skills and categories with more fitting names/level text +/decl/skill_category/security + name = "Soldiering" + sort_priority = 2 + +/decl/skill_category/service + name = "Domestic" + sort_priority = 1 + +/decl/skill_category/medical + name = "Medicine" + sort_priority = 4 + +/decl/skill_category/research + name = "Natural Philosophy" + sort_priority = 5 + +/decl/skill_category/organizational + name = "Bookkeeping" + sort_priority = 6 + +/decl/skill/finance + name = "Finance" + desc = "Your ability to manage money and investments." + levels = list( + "Unskilled" = "Your understanding of money starts and ends with personal finance. While you are able to perform basic transactions, you get lost in the details, and can find yourself ripped off on occasion.
    - You get some starting money, increasing with level.", + "Basic" = "You have some limited understanding of financial transactions, and will generally be able to keep accurate records. You have little experience with investment, and managing large sums of money will likely go poorly for you.
    - You can use the verb \"Appraise\" to see the value of different objects.", + "Trained" = "You are good at managing accounts, keeping records, and arranging transactions. You have some familiarity with loans, exchange rates and taxes, but may be stumped when facing more complicated financial situations.", + "Experienced" = "With your experience, you are familiar with any financial entities you may run across, and are a shrewd judge of value. More often than not, investments you make will pan out well.", + "Master" = "You have an excellent knowledge of finance, will often make brilliant investments, and have an instinctive feel for kingdom-wide economics. Financial instruments are weapons in your hands. You likely have professional experience in the finance industry." + ) + +/decl/skill/finance/update_special_effects(mob/mob, level) + return //we don't want legalese here + +/decl/skill/general/hauling + name = "Athletics" + desc = "Your ability to perform tasks requiring great strength, dexterity, or endurance." + category = /decl/skill_category/security + levels = list( + "Unskilled" = "You are not used to manual labor, tire easily, and are likely not in great shape. Extended heavy labor may be dangerous for you.
    - You can pull objects but your stamina depends on your skill rank. Your strength increases with level.
    - You can throw objects. Their speed, thrown distance, and force increases with level.
    - You can sprint, the stamina consumption rate is lowered with each level.
    - You can leap by holding Ctrl and clicking on a distant target with grab intent, leap range is increased and chances of falling over are decreased with each level.", + "Basic" = "You have some familiarity with manual labor, and are in reasonable physical shape. Tasks requiring great dexterity or strength may still elude you.
    - You can throw \"huge\" items or normal-sized mobs without getting weakened.", + "Trained" = "You have sufficient strength and dexterity for even very strenuous tasks, and can work for a long time without tiring.", + "Experienced" = "You have experience with heavy work in trying physical conditions, and are in excellent shape. You often work out.", + "Master" = "In addition to your excellent strength and endurance, you have a lot of experience with the specific physical demands of your job." + ) + +/decl/skill/service/botany + name = "Horticulture" + desc = "Describes how good you are at growing and maintaining plants." + levels = list( + "Unskilled" = "You know next to nothing about plants. While you can attempt to plant, weed, or harvest, you are just as likely to kill the plant instead.", + "Basic" = "You've done some gardening. You can water, weed, fertilize, plant, and harvest, and you can recognize and deal with pests.
    - You can safely plant and weed normal plants.
    - You can tell weeds and pests apart from each other.", + "Trained" = "You are proficient at botany, and can grow plants for food, medicine or textile use. Your plants will generally survive and prosper.
    - You can safely plant and weed exotic plants.", + "Experienced" = "You are an experienced horticulturalist with an encyclopedic knowledge of plants and their properties.", + "Master" = "You're a specialized gardener. You can care for even the most exotic, fragile, or dangerous plants." + ) + +/decl/skill/service/husbandry + name = "Animal Husbandry" + uid = "skill_husbandry" + desc = "Your ability to raise and care for animals." + levels = list( + "Unskilled" = "You know next to nothing about animals. You can feed and clean up after them, but you know nothing about their biology, their behavior, or raising their young.", + "Basic" = "You've cared for farm animals before. You can care for the basic needs of an animal, and know how to do things like milk a cow or shear a sheep.
    - Cows will not flee when you try to milk them.", + "Trained" = "You are proficient at animal handling, and can delicately handle even skittish animals without frightening them.
    - Passive animals will not flee when you pick them up.", + "Experienced" = "You are an experienced animal caretaker with an encyclopedic knowledge of animals.", + "Master" = "You're a specialized animal caretaker. You can care for even the most exotic, fragile, or dangerous animals." + ) + +/obj/item/food/egg/examine_skill = SKILL_HUSBANDRY +/mob/living/simple_animal/chick/examine_skill = SKILL_HUSBANDRY + +/datum/extension/milkable + milking_skill = SKILL_HUSBANDRY + +/datum/extension/shearable + shearing_skill = SKILL_HUSBANDRY + +/datum/mob_controller/passive/scooping_skill = SKILL_HUSBANDRY + +/decl/skill/service/cooking + name = "Cooking" + desc = "Describes your skill at preparing meals and other consumable goods. This includes mixing alcoholic beverages." + levels = list( + "Unskilled" = "You barely know anything about cooking, and rely on others when you can. The stove is a device of black magic to you, and you avoid it when possible.", + "Basic" = "You can make simple meals and do the cooking for your family. Things like roasted meat, boiled vegetables, or simple mixed drinks are your usual fare.", + "Trained" = "You can make most meals while following instructions, and they generally turn out well. You have some experience with hosting, catering, and/or bartending.", + "Experienced" = "You can cook professionally, keeping an entire inn fed easily. Your food is tasty and you don't have a problem with tricky or complicated dishes. You can be depended on to make just about any commonly-served drink.", + "Master" = "You are an expect chef capable of preparing a meal fit for a king! Not only are you good at cooking and mixing drinks, but you can manage a kitchen staff and cater for special events. You can safely prepare exotic foods and drinks that would be poisonous if prepared incorrectly." + ) + +/decl/skill/combat + name = "Melee Combat" + desc = "This skill describes your training with melee weapons such as swords and spears. It also dictates how good you are at hand-to-hand combat." + levels = list( + "Unskilled" = "You have little to no experience with melee combat, you can swing or stab with a weapon, but you don't know how to do so effectively.
    - You can disarm, grab, and hit. Their success chance depends on the fighters' skill difference.
    - The chance of falling over when tackled is reduced with level.", + "Basic" = "You have some basic training on how to use a weapon in combat, but are still a beginner. You can handle yourself if you really have to, and know the basics of how to swing a sword.", + "Trained" = "You have had more melee training, and can easily defeat unskilled opponents. Melee combat may not be your specialty, and you don't engage in it more than needed, but you know how to handle yourself in a fight.
    - You can parry with weapons. This increases with level.
    - You can do grab maneuvers (pinning, dislocating).
    - You can grab targets when leaping at them and not fall over, if your species is able to do so.", + "Experienced" = "You're good at melee combat. You've trained explicitly with one or more types of weapon, you can use them competently and you can think strategically and quickly in a melee. You're in good shape and you spend time training.", + "Master" = "You specialize in melee combat. You are in good shape and skilled with multiple types of weapon. You spend a lot of time practicing. You can take on just about anyone, use just about any weapon, and usually come out on top. You may be a professional athlete or knight." + ) + +/decl/skill/weapons + name = "Marksmanship" + desc = "This skill describes your expertise with ranged weapons such as bows and slings." + levels = list( + "Unskilled" = "You have little to no experience with a ranged weapon, and are likely to miss your target, injure yourself or missfire.
    - You might fire your weapon randomly.", + "Basic" = "You know how to handle weapons safely, and you're comfortable using simple weapons. Your aim is decent and you can usually be trusted not to do anything stupid with a weapon you are familiar with, but your training isn't automatic yet and your performance will degrade in high-stress situations.
    - You can use ranged weapons. Their accuracy depends on your skill level.", + "Trained" = "You have had extensive weapons training, or have used weapons in combat. Your aim is better now. You are familiar with most types of weapons and can use them in a pinch. You have an understanding of tactics, and can be trusted to stay calm under fire. You may have military or guardsman experience and you probably carry a weapon on the job.", + "Experienced" = "You've used ranged weapons in high-stress situations, and your skills have become automatic. Your aim is good.", + "Master" = "You are a master marksman with great aim, you can hit a moving target, even from afar." + ) + +/decl/skill/medicine/medical + name = "Medicine" + desc = "Covers an understanding of the body and medicine. At a low level, this skill gives a basic understanding of applying common types of medicine. At a high level, this skill grants exact knowledge of all the medicine available in these lands." + levels = list( + "Unskilled" = "You know first aid, such as how to apply a bandage or salve to an injury. You can tell when someone is badly hurt and needs a doctor; you can see whether someone has a badly broken bone, is having trouble breathing, or is unconscious. You may have trouble telling the difference between unconscious and dead at distance.
    - You can use basic first aid supplies, such as bandages and salves.", + "Basic" = "You are an apprentice healer. You can stop bleeding, perform resuscitation, apply a splint, take someone's pulse, apply trauma and burn treatments. You probably know that antitoxins help poisoning. You've been briefed on the symptoms of common emergencies like a punctured lung, appendicitis, alcohol poisoning, or broken bones, and though you can't treat them, you know that they need a doctor's attention. You can recognize most emergencies as emergencies and safely stabilize and transport a patient.", + "Trained" = "You are a healer, having recently finished your apprenticeship. You know how to treat most illnesses and injuries, though exotic illnesses and unusual injuries may still stump you. You have probably begun to specialize in some sub-field of medicine. In emergencies, you can think fast enough to keep your patients alive, and even when you can't treat a patient, you know how to find someone who can.
    - You can apply splints without failing. You can perform simple surgery steps if you have Journeyman level Anatomy skill", + "Experienced" = "You are a skilled doctor. You know how to use all of the medical supplies available to treat a patient. Your deep knowledge of the body and medications will let you diagnose and come up with a course of treatment for most ailments. You can perform all surgery steps if you have Journeyman level Anatomy skill", + "Master" = "You are an experienced doctor. You've seen almost everything there is to see when it comes to injuries and illness and even when it comes to something you haven't seen, you can apply your wide knowledge base to put together a treatment. In a pinch, you can do just about any medicine-related task, but your specialty, whatever it may be, is where you really shine." + ) + +/decl/skill/medicine/anatomy + name = "Anatomy" + desc = "Gives you a detailed insight of the human body. A high skill in this is required to perform surgery." + levels = list( + "Unskilled" = "You know what organs, bones, and such are, and you know roughly where they are. You know that someone who's badly hurt or sick may need surgery.", + "Basic" = "You've received tutoring on anatomy and you've spent at least some time poking around inside actual people. You know where everything is, more or less. You could assist in surgery, if you have the required medical skills. If you really had to, you could probably perform basic surgery such as an appendectomy, but you're not yet a qualified surgeon and you really shouldn't--not unless it's an emergency.", + "Trained" = "You have some training in anatomy. Diagnosing broken bones, damaged ligaments, arrow wounds, and other trauma is straightforward for you. You can splint limbs with a good chance of success and you know how to perform resuscitation. Surgery is still outside your training.
    - You can do surgery (requires Apprentice level Medicine skill too) but you are very likely to fail at every step. Its speed increases with level.", + "Experienced" = "You're a skilled doctor. You can put together broken bones, fix a damaged lung, patch up a liver, or remove an appendix without problems. But tricky surgeries, with an unstable patient or delicate manipulation of vital organs like the heart and brain, are at the edge of your ability, and you prefer to leave them to specialized surgeons. You can recognize when someone's anatomy is noticeably unusual.
    - You can do all surgery steps safely, if you have Journeyman level Medicine skill too.", + "Master" = "You are an experienced surgeon. You can handle anything that gets rolled, pushed, or dragged to you, and you can keep a patient alive and stable even if there's no one to assist you. You can handle severe trauma cases or multiple organ failure, repair brain damage, and perform heart surgery. By now, you've probably specialized in one field, where you may have made new contributions to surgical technique. You can detect even small variations in the anatomy of a patient--very little will slip by your notice.
    - The penalty from operating on improper operating surfaces is reduced." + ) + +/decl/skill/medicine/chemistry + name = "Chemistry" + desc = "Experience with chemical ingredients, and an understanding of what the effect will be. This doesn't cover an understanding of the effect of reagents on the human body, as such the medical skill is also required for medical chemists." + category = /decl/skill_category/research + levels = list( + "Unskilled" = "You know that chemists work with various ingredients; you know that they can make medicine, poison or other useful concoctions.", + "Basic" = "You can make basic medication--things like anti-toxin or burn salves. You have some training in safety and you won't blow up the lab... probably.", + "Trained" = "You can accurately measure out ingredients, grind powders, and mix reagents. You may still lose some product on occasion, but are unlikely to endanger yourself or those around you.", + "Experienced" = "You work as an pharmacist, or else you are a doctor with training in chemistry. If you are a pharmacist, you can make most medications. At this stage, you're working mostly by-the-book.
    - You can examine held containers for some reagents.", + "Master" = "You specialized in chemistry or pharmaceuticals; you are either a medical researcher or professional chemist. You can create custom mixes and make even the trickiest of medications easily. You understand how your pharmaceuticals interact with the bodies of your patients. You are probably the originator of at least one new chemical innovation.
    - You can examine held containers for all reagents." + ) + +/datum/lock + lockpicking_skill = SKILL_ARTIFICE + +/obj/item/gemstone + work_skill = SKILL_ARTIFICE diff --git a/mods/content/fantasy/datum/species.dm b/mods/content/fantasy/datum/species.dm new file mode 100644 index 000000000000..6c8e041c8567 --- /dev/null +++ b/mods/content/fantasy/datum/species.dm @@ -0,0 +1,45 @@ +/decl/species/human + description = "Humans are a kind of tall, furless ape common to the downlands and the warmer parts of the Nine Mothers, \ + as well as more remote locales. Although they lack the natural ferocity of hnoll, and are larger and clumsier than kobaloi, \ + they are often stubborn and tenacious, as well as quick-witted and clever with their hands. In the downlands, humans are more \ + numerous than either kobaloi or hnoll, but were considered second-class citizens under the hnoll-ruled Imperial Aegis that \ + 'civilized' them in the distant past; an attitude that survives to this day in some isolated pockets of the Splinter Kingdoms." + available_bodytypes = list( + /decl/bodytype/human, + /decl/bodytype/human/masculine + ) + preview_outfit = /decl/outfit/job/generic/fantasy + base_external_prosthetics_model = /decl/bodytype/prosthetic/wooden + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/fantasy, + /decl/background_detail/location/fantasy/mountains, + /decl/background_detail/location/fantasy/steppe, + /decl/background_detail/location/fantasy/woods, + /decl/background_detail/location/other + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/fantasy, + /decl/background_detail/faction/fantasy/barbarian, + /decl/background_detail/faction/fantasy/centrist, + /decl/background_detail/faction/fantasy/aegis, + /decl/background_detail/faction/fantasy/primitivist, + /decl/background_detail/faction/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/fantasy, + /decl/background_detail/heritage/fantasy/steppe, + /decl/background_detail/heritage/other + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/ancestors, + /decl/background_detail/religion/folk_deity, + /decl/background_detail/religion/anima_materialism, + /decl/background_detail/religion/virtuist, + /decl/background_detail/religion/other + ) + ) diff --git a/mods/content/fantasy/icons/areas.dmi b/mods/content/fantasy/icons/areas.dmi new file mode 100644 index 000000000000..9849d6f87d8d Binary files /dev/null and b/mods/content/fantasy/icons/areas.dmi differ diff --git a/mods/content/fantasy/icons/clothing/braies.dmi b/mods/content/fantasy/icons/clothing/braies.dmi new file mode 100644 index 000000000000..dd579284e7a2 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/braies.dmi differ diff --git a/mods/content/fantasy/icons/clothing/braies_hnoll.dmi b/mods/content/fantasy/icons/clothing/braies_hnoll.dmi new file mode 100644 index 000000000000..f9ec38b3e05d Binary files /dev/null and b/mods/content/fantasy/icons/clothing/braies_hnoll.dmi differ diff --git a/mods/content/fantasy/icons/clothing/jerkin.dmi b/mods/content/fantasy/icons/clothing/jerkin.dmi new file mode 100644 index 000000000000..158ce68fbeb6 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/jerkin.dmi differ diff --git a/mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi b/mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi new file mode 100644 index 000000000000..dfc2e4e72b97 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi differ diff --git a/mods/content/fantasy/icons/clothing/loincloth.dmi b/mods/content/fantasy/icons/clothing/loincloth.dmi new file mode 100644 index 000000000000..17d6766f2634 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/loincloth.dmi differ diff --git a/mods/content/fantasy/icons/clothing/loincloth_hnoll.dmi b/mods/content/fantasy/icons/clothing/loincloth_hnoll.dmi new file mode 100644 index 000000000000..60b7120fda33 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/loincloth_hnoll.dmi differ diff --git a/mods/content/fantasy/icons/clothing/reference_hnoll.dmi b/mods/content/fantasy/icons/clothing/reference_hnoll.dmi new file mode 100644 index 000000000000..9ee35df4bb76 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/reference_hnoll.dmi differ diff --git a/mods/content/fantasy/icons/clothing/reference_kobaloi.dmi b/mods/content/fantasy/icons/clothing/reference_kobaloi.dmi new file mode 100644 index 000000000000..4c3ecce93643 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/reference_kobaloi.dmi differ diff --git a/mods/content/fantasy/icons/clothing/sack_kobaloi.dmi b/mods/content/fantasy/icons/clothing/sack_kobaloi.dmi new file mode 100644 index 000000000000..8314dbb70ac3 Binary files /dev/null and b/mods/content/fantasy/icons/clothing/sack_kobaloi.dmi differ diff --git a/mods/content/fantasy/icons/clothing/trousers.dmi b/mods/content/fantasy/icons/clothing/trousers.dmi new file mode 100644 index 000000000000..72c80d25259a Binary files /dev/null and b/mods/content/fantasy/icons/clothing/trousers.dmi differ diff --git a/mods/content/fantasy/icons/clothing/trousers_hnoll.dmi b/mods/content/fantasy/icons/clothing/trousers_hnoll.dmi new file mode 100644 index 000000000000..35c2ed8181cd Binary files /dev/null and b/mods/content/fantasy/icons/clothing/trousers_hnoll.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/body.dmi b/mods/content/fantasy/icons/hnoll/body.dmi new file mode 100644 index 000000000000..264fa2ca4b34 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/body.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/cosmetics.dmi b/mods/content/fantasy/icons/hnoll/cosmetics.dmi new file mode 100644 index 000000000000..3d7d37d45c45 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/cosmetics.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/deformed_body.dmi b/mods/content/fantasy/icons/hnoll/deformed_body.dmi new file mode 100644 index 000000000000..99aac9284a58 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/deformed_body.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/eyes.dmi b/mods/content/fantasy/icons/hnoll/eyes.dmi new file mode 100644 index 000000000000..0e63fb147d2f Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/eyes.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/facial.dmi b/mods/content/fantasy/icons/hnoll/facial.dmi new file mode 100644 index 000000000000..befd9dc68b46 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/facial.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/hair.dmi b/mods/content/fantasy/icons/hnoll/hair.dmi new file mode 100644 index 000000000000..464ce7bcd6de Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/hair.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/lips.dmi b/mods/content/fantasy/icons/hnoll/lips.dmi new file mode 100644 index 000000000000..0586f9438ab2 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/lips.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/markings.dmi b/mods/content/fantasy/icons/hnoll/markings.dmi new file mode 100644 index 000000000000..4b47735f58d9 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/markings.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/skeleton.dmi b/mods/content/fantasy/icons/hnoll/skeleton.dmi new file mode 100644 index 000000000000..5dab29a2a5fd Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/skeleton.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/tail.dmi b/mods/content/fantasy/icons/hnoll/tail.dmi new file mode 100644 index 000000000000..83afe576ab46 Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/tail.dmi differ diff --git a/mods/content/fantasy/icons/hnoll/template.dmi b/mods/content/fantasy/icons/hnoll/template.dmi new file mode 100644 index 000000000000..a5778d0652bd Binary files /dev/null and b/mods/content/fantasy/icons/hnoll/template.dmi differ diff --git a/mods/content/fantasy/icons/kobaloi/body.dmi b/mods/content/fantasy/icons/kobaloi/body.dmi new file mode 100644 index 000000000000..8a5282aa2401 Binary files /dev/null and b/mods/content/fantasy/icons/kobaloi/body.dmi differ diff --git a/mods/content/fantasy/icons/kobaloi/eyes.dmi b/mods/content/fantasy/icons/kobaloi/eyes.dmi new file mode 100644 index 000000000000..da8b3c80d3b8 Binary files /dev/null and b/mods/content/fantasy/icons/kobaloi/eyes.dmi differ diff --git a/mods/content/fantasy/icons/kobaloi/horns.dmi b/mods/content/fantasy/icons/kobaloi/horns.dmi new file mode 100644 index 000000000000..ec532098abb5 Binary files /dev/null and b/mods/content/fantasy/icons/kobaloi/horns.dmi differ diff --git a/mods/content/fantasy/icons/kobaloi/markings.dmi b/mods/content/fantasy/icons/kobaloi/markings.dmi new file mode 100644 index 000000000000..19d4319f583b Binary files /dev/null and b/mods/content/fantasy/icons/kobaloi/markings.dmi differ diff --git a/mods/content/fantasy/icons/kobaloi/skeleton.dmi b/mods/content/fantasy/icons/kobaloi/skeleton.dmi new file mode 100644 index 000000000000..af27d46a6b56 Binary files /dev/null and b/mods/content/fantasy/icons/kobaloi/skeleton.dmi differ diff --git a/mods/content/fantasy/icons/structures/signpost.dmi b/mods/content/fantasy/icons/structures/signpost.dmi new file mode 100644 index 000000000000..377e82ef5f53 Binary files /dev/null and b/mods/content/fantasy/icons/structures/signpost.dmi differ diff --git a/mods/content/fantasy/items/clothing/_loadout.dm b/mods/content/fantasy/items/clothing/_loadout.dm new file mode 100644 index 000000000000..c9d6b1e21255 --- /dev/null +++ b/mods/content/fantasy/items/clothing/_loadout.dm @@ -0,0 +1,360 @@ +/decl/loadout_category/fantasy + abstract_type = /decl/loadout_category/fantasy + +/decl/loadout_category/fantasy/clothing + name = "Clothing" + +/decl/loadout_option/fantasy + abstract_type = /decl/loadout_option/fantasy + category = /decl/loadout_category/fantasy/clothing + loadout_flags = GEAR_HAS_COLOR_SELECTION + var/list/available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/skin/feathers, + /decl/material/solid/organic/skin/fur, + /decl/material/solid/organic/cloth, + /decl/material/solid/organic/cloth/wool, + /decl/material/solid/organic/cloth/hemp, + /decl/material/solid/organic/cloth/linen + ) + +/decl/loadout_option/fantasy/get_gear_tweak_options() + . = ..() + if(length(available_materials)) + for(var/mat in available_materials) + var/decl/material/mat_decl = GET_DECL(mat) + available_materials -= mat + available_materials[mat_decl.name] = mat + LAZYINITLIST(.[/datum/gear_tweak/material]) + .[/datum/gear_tweak/material] = available_materials + +/decl/loadout_option/fantasy/uniform + name = "loincloth" + path = /obj/item/clothing/pants/loincloth + slot = slot_w_uniform_str + uid = "gear_fantasy_loincloth" + +/decl/loadout_option/fantasy/uniform/shirt + name = "shirt" + path = /obj/item/clothing/shirt/crafted + uid = "gear_fantasy_shirt" + available_materials = list( + /decl/material/solid/organic/cloth, + /decl/material/solid/organic/cloth/wool, + /decl/material/solid/organic/cloth/hemp, + /decl/material/solid/organic/cloth/linen + ) + +/decl/loadout_option/fantasy/uniform/jerkin + name = "jerkin" + path = /obj/item/clothing/shirt/jerkin + uid = "gear_fantasy_jerkin" + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/skin/feathers, + /decl/material/solid/organic/skin/fur + ) + +/decl/loadout_option/fantasy/uniform/tunic + name = "tunic" + path = /obj/item/clothing/shirt/tunic + slot = slot_w_uniform_str + uid = "gear_fantasy_tunic" + +/decl/loadout_option/fantasy/uniform/tunic/short + name = "tunic, short" + path = /obj/item/clothing/shirt/tunic/short + uid = "gear_fantasy_tunic_short" + +/decl/loadout_option/fantasy/uniform/trousers + name = "trousers" + path = /obj/item/clothing/pants/trousers + uid = "gear_fantasy_trousers" + +/decl/loadout_option/fantasy/uniform/gown + name = "gown" + path = /obj/item/clothing/dress/gown + uid = "gear_fantasy_gown" + +/decl/loadout_option/fantasy/uniform/braies + name = "braies" + path = /obj/item/clothing/pants/trousers/braies + uid = "gear_fantasy_braies" + +/decl/loadout_option/fantasy/uniform/toga + name = "toga" + path = /obj/item/clothing/shirt/toga + uid = "gear_fantasy_toga" + +/decl/loadout_option/fantasy/uniform/pleated + name = "pleated skirt selection" + path = /obj/item/clothing/skirt/pleated + loadout_flags = (GEAR_HAS_COLOR_SELECTION | GEAR_HAS_TYPE_SELECTION) + uid = "gear_fantasy_skirt_pleated" + +/decl/loadout_option/fantasy/uniform/gambeson + name = "gambeson" + path = /obj/item/clothing/shirt/gambeson + uid = "gear_fantasy_gambeson" + +/decl/loadout_option/fantasy/suit + name = "robes" + path = /obj/item/clothing/suit/robe + slot = slot_wear_suit_str + uid = "gear_fantasy_suit" + +/decl/loadout_option/fantasy/suit/mantle + name = "mantle" + path = /obj/item/clothing/suit/mantle + uid = "gear_fantasy_mantle" + +/decl/loadout_option/fantasy/suit/cloak + name = "cloak" + path = /obj/item/clothing/suit/cloak/crafted // Takes material colour. + uid = "gear_fantasy_cloak" + +/decl/loadout_option/fantasy/suit/hooded_cloak + name = "cloak, hooded" + path = /obj/item/clothing/suit/hooded_cloak + uid = "gear_fantasy_cloak_hooded" + +/decl/loadout_option/fantasy/suit/winter_cloak + name = "cloak, winter" + path = /obj/item/clothing/suit/hooded_cloak/winter + uid = "gear_fantasy_cloak_hooded_winter" + +/decl/loadout_option/fantasy/suit/poncho + name = "poncho" + path = /obj/item/clothing/suit/poncho/colored + uid = "gear_fantasy_poncho" + +/decl/loadout_option/fantasy/suit/apron + name = "apron" + path = /obj/item/clothing/suit/apron/colourable + uid = "gear_fantasy_apron" + +/decl/loadout_option/fantasy/mask + name = "bandana" + path = /obj/item/clothing/mask/bandana/colourable + slot = slot_wear_mask_str + uid = "gear_fantasy_bandana" + +/decl/loadout_option/fantasy/head + name = "headband" + path = /obj/item/clothing/head/headband + slot = slot_head_str + uid = "gear_fantasy_headband" + +/decl/loadout_option/fantasy/head/hood + name = "hood" + path = /obj/item/clothing/head/hood + uid = "gear_fantasy_hood" + +/decl/loadout_option/fantasy/gloves + name = "gloves" + slot = slot_gloves_str + path = /obj/item/clothing/gloves + uid = "gear_fantasy_gloves" + +/decl/loadout_option/fantasy/gloves/work + name = "work gloves" + path = /obj/item/clothing/gloves/thick + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/cloth, + /decl/material/solid/organic/cloth/wool, + /decl/material/solid/organic/cloth/hemp + + ) + uid = "gear_fantasy_work_gloves" + +/decl/loadout_option/fantasy/shoes + name = "shoes" + path = /obj/item/clothing/shoes/craftable + slot = slot_shoes_str + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/cloth + ) + uid = "gear_fantasy_shoes" + +/decl/loadout_option/fantasy/shoes/boots + name = "boots" + path = /obj/item/clothing/shoes/craftable/boots + uid = "gear_fantasy_boots" + +/decl/loadout_option/fantasy/shoes/sandal + name = "sandals" + path = /obj/item/clothing/shoes/sandal + slot = slot_shoes_str + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/wood/oak, + /decl/material/solid/organic/wood/mahogany, + /decl/material/solid/organic/wood/maple, + /decl/material/solid/organic/wood/ebony, + /decl/material/solid/organic/wood/walnut + ) + uid = "gear_fantasy_sandals" + +/decl/loadout_option/fantasy/neck + abstract_type = /decl/loadout_option/fantasy/neck + slot = slot_wear_mask_str + +/decl/loadout_option/fantasy/neck/prayer_beads + name = "prayer beads" + path = /obj/item/clothing/neck/prayer_beads + available_materials = list( + /decl/material/solid/organic/bone, + /decl/material/solid/stone/marble, + /decl/material/solid/stone/basalt, + /decl/material/solid/organic/wood/mahogany, + /decl/material/solid/organic/wood/ebony + ) + uid = "gear_fantasy_prayerbeads" + +/decl/loadout_category/fantasy/utility + name = "Utility" + +/decl/loadout_option/fantasy/utility + abstract_type = /decl/loadout_option/fantasy/utility + category = /decl/loadout_category/fantasy/utility + available_materials = list( + /decl/material/solid/metal/iron, + /decl/material/solid/metal/copper, + /decl/material/solid/metal/bronze + ) + loadout_flags = null + +/decl/loadout_option/fantasy/utility/scroll + name = "paper scroll" + path = /obj/item/paper/scroll + available_materials = null + uid = "gear_fantasy_scroll" + +/decl/loadout_option/fantasy/utility/quill + name = "quill pen" + path = /obj/item/pen/fancy/quill + available_materials = null + uid = "gear_fantasy_quill" + +/decl/loadout_option/fantasy/utility/striker + name = "flint striker" + path = /obj/item/rock/flint/striker + available_materials = null + loadout_flags = null + uid = "gear_fantasy_striker" + +/decl/loadout_option/fantasy/utility/knife + name = "knife, belt" + path = /obj/item/bladed/knife + uid = "gear_fantasy_belt_knife" + +/decl/loadout_option/fantasy/utility/knife/folding + name = "knife, folding" + path = /obj/item/bladed/folding + uid = "gear_fantasy_folding_knife" + +/decl/loadout_option/fantasy/utility/hand_axe + name = "hand axe" + path = /obj/item/tool/axe/ebony + uid = "gear_fantasy_handaxe" + +/decl/loadout_option/fantasy/utility/shovel + name = "shovel" + path = /obj/item/tool/shovel/one_material + available_materials = list( + /decl/material/solid/organic/wood/oak, + /decl/material/solid/organic/wood/mahogany, + /decl/material/solid/organic/wood/maple, + /decl/material/solid/organic/wood/ebony, + /decl/material/solid/organic/wood/walnut + ) + uid = "gear_fantasy_shovel" + +/decl/loadout_option/fantasy/utility/bandolier + name = "bandolier" + path = /obj/item/clothing/webbing/bandolier/crafted + slot = slot_w_uniform_str + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/cloth, + /decl/material/solid/organic/cloth/wool, + /decl/material/solid/organic/cloth/hemp + ) + uid = "gear_fantasy_bandoler" + +/decl/loadout_option/fantasy/utility/waterskin + name = "waterskin selection" + path = /obj/item/chems/glass/waterskin + available_materials = null + apply_to_existing_if_possible = TRUE // overwrite beggar knight's wineskin + uid = "gear_fantasy_waterskin" + +/decl/loadout_option/fantasy/utility/waterskin/get_gear_tweak_options() + . = ..() + LAZYDISTINCTADD(.[/datum/gear_tweak/path], list( + "crafted leather waterskin" = /obj/item/chems/glass/waterskin/crafted, + "dried stomach waterskin" = /obj/item/chems/glass/waterskin, + )) + LAZYDISTINCTADD(.[/datum/gear_tweak/reagents], list( + "ale" = /decl/material/liquid/alcohol/ale, + "apple cider" = /decl/material/liquid/alcohol/cider_apple, + "beer" = /decl/material/liquid/alcohol/beer, + "kvass" = /decl/material/liquid/alcohol/kvass, + "pear cider" = /decl/material/liquid/alcohol/cider_pear, + "red wine" = /decl/material/liquid/alcohol/wine, + "sake" = /decl/material/liquid/alcohol/sake, + "water" = /decl/material/liquid/water, + "white wine" = /decl/material/liquid/alcohol/wine/premium, + )) + +/decl/loadout_option/fantasy/utility/crutch + name = "crutch" + path = /obj/item/crutch/wooden/padded + available_materials = list( + /decl/material/solid/organic/wood/oak, + /decl/material/solid/organic/wood/mahogany, + /decl/material/solid/organic/wood/maple, + /decl/material/solid/organic/wood/ebony, + /decl/material/solid/organic/wood/walnut + ) + uid = "gear_fantasy_crutch" + +/decl/loadout_option/fantasy/eyes + abstract_type = /decl/loadout_option/fantasy/eyes + slot = slot_glasses_str + available_materials = list( + /decl/material/solid/organic/leather, + /decl/material/solid/organic/cloth, + /decl/material/solid/organic/cloth/wool, + /decl/material/solid/organic/skin/fur, + /decl/material/solid/organic/skin/feathers, + /decl/material/solid/organic/cloth/linen + ) + +/decl/loadout_option/fantasy/eyes/eyepatch + name = "eyepatch" + path = /obj/item/clothing/glasses/eyepatch + loadout_flags = null + uid = "gear_fantasy_eyes_eyepatch" + +/decl/loadout_option/fantasy/eyes/eyepatch_colourable + name = "eyepatch, colourable" + path = /obj/item/clothing/glasses/eyepatch/colourable + uid = "gear_fantasy_eyes_eyepatch_colourable" + +/decl/loadout_option/fantasy/eyes/glasses + name = "glasses selection" + path = /obj/item/clothing/glasses/prescription/pincenez + uid = "gear_fantasy_eyes_glasses" + available_materials = null + loadout_flags = null + +/decl/loadout_option/fantasy/eyes/glasses/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path]) + .[/datum/gear_tweak/path] |= list( + "pince-nez glasses" = /obj/item/clothing/glasses/prescription/pincenez, + "monocle" = /obj/item/clothing/glasses/eyepatch/monocle + ) \ No newline at end of file diff --git a/mods/content/fantasy/items/clothing/_overrides.dm b/mods/content/fantasy/items/clothing/_overrides.dm new file mode 100644 index 000000000000..0ecd3b43e1cb --- /dev/null +++ b/mods/content/fantasy/items/clothing/_overrides.dm @@ -0,0 +1,15 @@ +/obj/item + var/_kobaloi_onmob_icon + var/_hnoll_onmob_icon + +/obj/item/setup_sprite_sheets() + . = ..() + if(_kobaloi_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_KOBALOI, _kobaloi_onmob_icon) + if(_hnoll_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_HNOLL, _hnoll_onmob_icon) + +/obj/item/clothing/gloves/setup_equip_flags() + . = ..() + if(!isnull(bodytype_equip_flags) && !(bodytype_equip_flags & BODY_EQUIP_FLAG_EXCLUDE)) + bodytype_equip_flags |= BODY_EQUIP_FLAG_HNOLL \ No newline at end of file diff --git a/mods/content/fantasy/items/clothing/_recipes.dm b/mods/content/fantasy/items/clothing/_recipes.dm new file mode 100644 index 000000000000..99942d8918ed --- /dev/null +++ b/mods/content/fantasy/items/clothing/_recipes.dm @@ -0,0 +1,23 @@ +/decl/stack_recipe/textiles/jerkin + result_type = /obj/item/clothing/shirt/crafted + category = "clothing" + +/decl/stack_recipe/textiles/gown + result_type = /obj/item/clothing/dress/gown + category = "clothing" + +/decl/stack_recipe/textiles/trousers + result_type = /obj/item/clothing/pants/trousers + category = "clothing" + +/decl/stack_recipe/textiles/braies + result_type = /obj/item/clothing/pants/trousers/braies + category = "clothing" + +/decl/stack_recipe/textiles/tunic + result_type = /obj/item/clothing/shirt/tunic + category = "clothing" + +/decl/stack_recipe/textiles/tunic_short + result_type = /obj/item/clothing/shirt/tunic/short + category = "clothing" diff --git a/mods/content/fantasy/items/clothing/armor.dm b/mods/content/fantasy/items/clothing/armor.dm new file mode 100644 index 000000000000..22651d3243d5 --- /dev/null +++ b/mods/content/fantasy/items/clothing/armor.dm @@ -0,0 +1,3 @@ +// Override of the base item to add lore to the desc. +/obj/item/clothing/suit/armor/forged/banded + desc = "A suit of overlapping armoured plates that covers the upper and lower body. Historically favoured by the Aegis and loyally adopted by many Splinter Kingdoms." diff --git a/mods/content/fantasy/items/clothing/cloak.dm b/mods/content/fantasy/items/clothing/cloak.dm new file mode 100644 index 000000000000..f61d886efe5a --- /dev/null +++ b/mods/content/fantasy/items/clothing/cloak.dm @@ -0,0 +1,17 @@ +// TODO: big fuckoff fur collar icons +/obj/item/clothing/head/hood/cloak/winter + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + material = /decl/material/solid/organic/cloth/wool + +/obj/item/clothing/suit/hooded_cloak/winter + cold_protection = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_ARMS|SLOT_LEGS|SLOT_HANDS|SLOT_FEET + min_cold_protection_temperature = ARMOR_MIN_COLD_PROTECTION_TEMPERATURE + hood = /obj/item/clothing/head/hood/cloak/winter + protects_against_weather = TRUE + material = /decl/material/solid/organic/cloth/wool + +/obj/item/clothing/suit/robe/sleeved/shrine + material = /decl/material/solid/organic/cloth/linen + paint_color = COLOR_DARK_RED + markings_color = COLOR_OFF_WHITE + markings_state_modifier = "_sleeves" diff --git a/mods/content/fantasy/items/clothing/glasses.dm b/mods/content/fantasy/items/clothing/glasses.dm new file mode 100644 index 000000000000..95100b6a97c0 --- /dev/null +++ b/mods/content/fantasy/items/clothing/glasses.dm @@ -0,0 +1,6 @@ +/decl/trait/malus/impaired_vision + description = "Your vision is somewhat impaired, and you need corrective eyewear to see clearly." + glasses_type = /obj/item/clothing/glasses/prescription/pincenez + +/obj/item/clothing/glasses/prescription/pincenez + desc = "A pair of glass corrective lenses held together by a thin bronze nosepiece that clip onto the wearer's nose to stay in place." \ No newline at end of file diff --git a/mods/content/fantasy/items/clothing/jerkin.dm b/mods/content/fantasy/items/clothing/jerkin.dm new file mode 100644 index 000000000000..942a871a81cb --- /dev/null +++ b/mods/content/fantasy/items/clothing/jerkin.dm @@ -0,0 +1,19 @@ +/obj/item/clothing/shirt/jerkin + name = "jerkin" + desc = "A sturdy jerkin, worn on the upper body." + icon = 'mods/content/fantasy/icons/clothing/jerkin.dmi' + _hnoll_onmob_icon = 'mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/organic/leather + +/obj/item/clothing/shirt/crafted + desc = "A simple shirt, worn on the upper body." + icon = 'mods/content/fantasy/icons/clothing/jerkin.dmi' // TODO state with sleeves + sprite_sheets = list(BODYTYPE_HNOLL = 'mods/content/fantasy/icons/clothing/jerkin_hnoll.dmi') + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + +/obj/item/clothing/shirt/crafted/wool + material = /decl/material/solid/organic/cloth/wool + +/obj/item/clothing/shirt/crafted/linen + material = /decl/material/solid/organic/cloth/linen diff --git a/mods/content/fantasy/items/clothing/loincloth.dm b/mods/content/fantasy/items/clothing/loincloth.dm new file mode 100644 index 000000000000..5cb8288038e1 --- /dev/null +++ b/mods/content/fantasy/items/clothing/loincloth.dm @@ -0,0 +1,11 @@ +/obj/item/clothing/pants/loincloth + name = "loincloth" + gender = NEUTER + desc = "A simple garment that is worn around the legs and lower body." + icon = 'mods/content/fantasy/icons/clothing/loincloth.dmi' + _hnoll_onmob_icon = 'mods/content/fantasy/icons/clothing/loincloth_hnoll.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/organic/skin/fur + +/decl/stack_recipe/textiles/loincloth + result_type = /obj/item/clothing/pants/loincloth diff --git a/mods/content/fantasy/items/clothing/trousers.dm b/mods/content/fantasy/items/clothing/trousers.dm new file mode 100644 index 000000000000..4fac34236e9b --- /dev/null +++ b/mods/content/fantasy/items/clothing/trousers.dm @@ -0,0 +1,18 @@ +/obj/item/clothing/pants/trousers + name = "trousers" + desc = "Some simple trousers. One leg per leg." + icon = 'mods/content/fantasy/icons/clothing/trousers.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + material = /decl/material/solid/organic/leather + color = /decl/material/solid/organic/leather::color + _hnoll_onmob_icon = 'mods/content/fantasy/icons/clothing/trousers_hnoll.dmi' + +/obj/item/clothing/pants/trousers/linen + material = /decl/material/solid/organic/cloth/linen + color = /decl/material/solid/organic/cloth/linen::color + +/obj/item/clothing/pants/trousers/braies + name = "braies" + desc = "Some short trousers. Comfortable and easy to wear." + icon = 'mods/content/fantasy/icons/clothing/braies.dmi' + _hnoll_onmob_icon = 'mods/content/fantasy/icons/clothing/braies_hnoll.dmi' diff --git a/mods/content/fantasy/items/material_overrides.dm b/mods/content/fantasy/items/material_overrides.dm new file mode 100644 index 000000000000..4ff5679b5a46 --- /dev/null +++ b/mods/content/fantasy/items/material_overrides.dm @@ -0,0 +1,38 @@ +/obj/structure/gravemarker + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + +/obj/item/gravemarker + material = /decl/material/solid/organic/wood/walnut + color = /decl/material/solid/organic/wood/walnut::color + +// FRANCE ISN'T REAL +/obj/item/chems/drinks/bottle/champagne + name = "sparkling wine bottle" + +/decl/material/liquid/alcohol/champagne + name = "sparkling wine" + glass_name = "sparkling wine" + glass_desc = "Sparkling white wine, a favourite at noble and merchant parties." + lore_text = "Sparkling white wine, a favourite at noble and merchant parties." + +/obj/item/chems/drinks/bottle/premiumwine + name = "vintage Imperial white wine" + desc = "An expensive-looking bottle of white wine, no doubt predating the fall of the Aegis, with the name of the city or settlement that produced it written on it." + aged_min = 98 + aged_max = 420 + +/obj/item/chems/drinks/bottle/premiumwine/make_random_name() + var/decl/language/hnoll/hnoll_language = GET_DECL(/decl/language/hnoll) + return "bottle of vintage [hnoll_language.get_random_language_name(FEMALE, name_count = prob(20) ? 2 : 1)]" + +/obj/item/chems/drinks/bottle/wine + name = "bottle of red wine" + desc = "A bottle of locally-produced red wine." + var/place_of_origin + +/obj/item/chems/drinks/bottle/wine/Initialize() + . = ..() + var/decl/language/hnoll/hnoll_language = GET_DECL(/decl/language/hnoll) + place_of_origin = hnoll_language.get_random_language_name(FEMALE, name_count = prob(20) ? 2 : 1) + desc += " It has a label that reads '[place_of_origin]'." \ No newline at end of file diff --git a/mods/content/fantasy/props/signpost.dm b/mods/content/fantasy/props/signpost.dm new file mode 100644 index 000000000000..bcfddc878029 --- /dev/null +++ b/mods/content/fantasy/props/signpost.dm @@ -0,0 +1,57 @@ +/obj/effect/departure_signpost + name = "border post" + desc = "A tall lamplit signpost marking the edge of the region. Beyond lies distant kingdoms." + icon = 'mods/content/fantasy/icons/structures/signpost.dmi' + icon_state = ICON_STATE_WORLD + color = /decl/material/solid/organic/wood/walnut::color + density = TRUE + opacity = FALSE + anchored = TRUE + simulated = FALSE + pixel_z = 12 + + var/lit_light_power = /obj/item/flame/fuelled/lantern::lit_light_power + var/lit_light_range = /obj/item/flame/fuelled/lantern::lit_light_range + var/lit_light_color = /obj/item/flame/fuelled/lantern::lit_light_color + +/obj/effect/departure_signpost/Initialize() + . = ..() + set_light(lit_light_range, lit_light_power, lit_light_color) + update_icon() + +/obj/effect/departure_signpost/on_update_icon() + . = ..() + add_overlay(overlay_image(icon, "[icon_state]-lamp", /decl/material/solid/metal/copper::color, RESET_COLOR)) + var/image/glow = emissive_overlay(icon, "[icon_state]-lamp-glow", color = lit_light_color) + glow.appearance_flags |= RESET_COLOR + add_overlay(glow) + +/obj/effect/departure_signpost/attackby(obj/item/used_item, mob/user) + SHOULD_CALL_PARENT(FALSE) + return TRUE + +/obj/effect/departure_signpost/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + var/choice = alert(user, "Are you sure you wish to depart? This will permanently remove your character from the round.", "Venture Forth?", "No", "Yes") + if(choice != "Yes" || QDELETED(user) || user.incapacitated() || QDELETED(src) || !user.Adjacent(src)) + return TRUE + new /obj/effect/dummy/fadeout(get_turf(user), dir, user) + despawn_character(user) + return TRUE + +/obj/effect/departure_signpost/get_mechanics_info() + . = ..() + . += "By clicking on the signpost, you can choose to remove your character from the round in order to free your job slot and respawn. This will delete your character's worn and held items, so make sure not to take any important items with you." + +// Premade types for mapping. +/obj/effect/departure_signpost/north + dir = NORTH + +/obj/effect/departure_signpost/south + dir = SOUTH + +/obj/effect/departure_signpost/east + dir = EAST + +/obj/effect/departure_signpost/west + dir = WEST diff --git a/mods/content/fantasy/submaps/_submaps.dm b/mods/content/fantasy/submaps/_submaps.dm new file mode 100644 index 000000000000..da60d375fd62 --- /dev/null +++ b/mods/content/fantasy/submaps/_submaps.dm @@ -0,0 +1,52 @@ +#define MAP_TEMPLATE_CATEGORY_FANTASY_GRASSLAND "template_fantasy_grassland" +#define MAP_TEMPLATE_CATEGORY_FANTASY_SWAMP "template_fantasy_swamp" +#define MAP_TEMPLATE_CATEGORY_FANTASY_WOODS "template_fantasy_woods" +#define MAP_TEMPLATE_CATEGORY_FANTASY_DOWNLANDS "template_fantasy_downlands" +#define MAP_TEMPLATE_CATEGORY_FANTASY_DUNGEON "template_fantasy_dungeon" +#define MAP_TEMPLATE_CATEGORY_FANTASY_CAVERNS "template_fantasy_caverns" + +/datum/map_template/fantasy + abstract_type = /datum/map_template/fantasy + template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS + area_usage_test_exempted_root_areas = list( + /area/fantasy/outside/point_of_interest + ) + var/cost = 1 + +/datum/map_template/fantasy/get_template_cost() + return cost + +/datum/map/New() + LAZYSET(apc_test_exempt_areas, /area/fantasy, NO_SCRUBBER|NO_VENT|NO_APC) + ..() + +/area/fantasy + abstract_type = /area/fantasy + allow_xenoarchaeology_finds = FALSE + icon = 'mods/content/fantasy/icons/areas.dmi' + icon_state = "area" + base_turf = /turf/floor/rock/basalt + sound_env = GENERIC + ambience = list() + +/area/fantasy/outside + name = "\improper Wilderness" + abstract_type = /area/fantasy/outside + color = COLOR_GREEN + is_outside = OUTSIDE_YES + sound_env = PLAIN + ambience = list( + 'sound/effects/wind/wind_2_1.ogg', + 'sound/effects/wind/wind_2_2.ogg', + 'sound/effects/wind/wind_3_1.ogg', + 'sound/effects/wind/wind_4_1.ogg', + 'sound/effects/wind/wind_4_2.ogg', + 'sound/effects/wind/wind_5_1.ogg' + ) + interior_ambient_light_modifier = -0.4 + area_flags = AREA_FLAG_EXTERNAL | AREA_FLAG_IS_BACKGROUND + +/area/fantasy/outside/point_of_interest + name = "Point Of Interest" + description = null + area_blurb_category = /area/fantasy/outside/point_of_interest diff --git a/mods/content/fantasy/submaps/downlands/_downlands.dm b/mods/content/fantasy/submaps/downlands/_downlands.dm new file mode 100644 index 000000000000..5086d54dc545 --- /dev/null +++ b/mods/content/fantasy/submaps/downlands/_downlands.dm @@ -0,0 +1,7 @@ +/datum/map_template/fantasy/downlands + abstract_type = /datum/map_template/fantasy/downlands + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_DOWNLANDS) + +/datum/map_template/fantasy/dungeon + abstract_type = /datum/map_template/fantasy/dungeon + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_DUNGEON) diff --git a/mods/content/fantasy/submaps/grassland/_grassland.dm b/mods/content/fantasy/submaps/grassland/_grassland.dm new file mode 100644 index 000000000000..e2860756be59 --- /dev/null +++ b/mods/content/fantasy/submaps/grassland/_grassland.dm @@ -0,0 +1,7 @@ +/datum/map_template/fantasy/grassland + abstract_type = /datum/map_template/fantasy/grassland + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_GRASSLAND) + +/datum/map_template/fantasy/cavern + abstract_type = /datum/map_template/fantasy/cavern + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_CAVERNS) diff --git a/mods/content/fantasy/submaps/swamp/_swamp.dm b/mods/content/fantasy/submaps/swamp/_swamp.dm new file mode 100644 index 000000000000..5b3401cfd6f8 --- /dev/null +++ b/mods/content/fantasy/submaps/swamp/_swamp.dm @@ -0,0 +1,3 @@ +/datum/map_template/fantasy/swamp + abstract_type = /datum/map_template/fantasy/swamp + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_SWAMP) diff --git a/mods/content/fantasy/submaps/woods/_woods.dm b/mods/content/fantasy/submaps/woods/_woods.dm new file mode 100644 index 000000000000..dc1429ef5592 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/_woods.dm @@ -0,0 +1,3 @@ +/datum/map_template/fantasy/woods + abstract_type = /datum/map_template/fantasy/woods + template_categories = list(MAP_TEMPLATE_CATEGORY_FANTASY_WOODS) diff --git a/mods/content/fantasy/submaps/woods/bear_den/bear_den.dm b/mods/content/fantasy/submaps/woods/bear_den/bear_den.dm new file mode 100644 index 000000000000..cb4da036c7c2 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/bear_den/bear_den.dm @@ -0,0 +1,6 @@ +/datum/map_template/fantasy/woods/bear_den + name = "bear den" + mappaths = list("mods/content/fantasy/submaps/woods/bear_den/bear_den.dmm") + +/area/fantasy/outside/point_of_interest/bear_den + name = "Point of Interest - Bear Den" diff --git a/mods/content/fantasy/submaps/woods/bear_den/bear_den.dmm b/mods/content/fantasy/submaps/woods/bear_den/bear_den.dmm new file mode 100644 index 000000000000..0a5b96087a42 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/bear_den/bear_den.dmm @@ -0,0 +1,328 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/floor/dirt, +/area/template_noop) +"f" = ( +/turf/floor/rock/basalt, +/area/template_noop) +"k" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/bear_den) +"n" = ( +/turf/floor/rock/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"o" = ( +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/bear_den) +"p" = ( +/turf/floor/grass, +/area/template_noop) +"r" = ( +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/bear_den) +"w" = ( +/obj/item/bladed/knife/iron, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/quin, +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/rock/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"y" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/rock/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"z" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/natural/dirt, +/area/fantasy/outside/point_of_interest/bear_den) +"C" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/rock/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"G" = ( +/obj/item/bone/skull/deer, +/obj/item/food/butchery/stomach, +/obj/item/food/butchery/offal, +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/bear_den) +"J" = ( +/turf/floor/grass/wild, +/area/template_noop) +"K" = ( +/turf/template_noop, +/area/template_noop) +"M" = ( +/mob/living/simple_animal/hostile/bear, +/obj/abstract/exterior_marker/inside, +/turf/floor/rock/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"O" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/natural/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"U" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/wall/natural/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"V" = ( +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/regalis, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/abstract/exterior_marker/inside, +/turf/floor/rock/basalt, +/area/fantasy/outside/point_of_interest/bear_den) +"W" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/wall/natural/dirt, +/area/fantasy/outside/point_of_interest/bear_den) + +(1,1,1) = {" +K +K +K +K +K +a +K +K +K +a +a +a +a +K +"} +(2,1,1) = {" +K +K +a +a +a +p +a +z +z +z +p +p +a +a +"} +(3,1,1) = {" +K +K +a +z +z +O +z +O +O +z +z +p +J +a +"} +(4,1,1) = {" +K +a +z +W +W +O +O +O +U +z +z +z +p +a +"} +(5,1,1) = {" +a +p +z +W +U +O +y +k +G +O +z +z +p +a +"} +(6,1,1) = {" +a +z +z +W +W +y +r +y +C +O +O +z +z +a +"} +(7,1,1) = {" +a +z +O +W +C +n +n +y +C +k +z +z +z +K +"} +(8,1,1) = {" +a +z +z +U +w +k +M +y +C +k +O +z +z +K +"} +(9,1,1) = {" +a +p +z +U +U +y +y +y +C +V +O +z +z +K +"} +(10,1,1) = {" +K +a +o +z +z +O +y +n +C +U +O +z +a +K +"} +(11,1,1) = {" +K +a +o +z +z +O +k +y +C +U +z +z +p +K +"} +(12,1,1) = {" +K +a +p +z +z +z +O +k +k +z +p +p +p +a +"} +(13,1,1) = {" +K +a +a +p +J +z +z +k +f +p +J +J +a +K +"} +(14,1,1) = {" +K +K +a +a +p +p +a +f +a +J +J +a +K +K +"} +(15,1,1) = {" +K +K +K +K +a +a +K +a +a +K +K +K +K +K +"} diff --git a/mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dm b/mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dm new file mode 100644 index 000000000000..158824c417b0 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dm @@ -0,0 +1,6 @@ +/datum/map_template/fantasy/woods/chemistry_shack + name = "chemistry shack" + mappaths = list("mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dmm") + +/area/fantasy/outside/point_of_interest/chemistry_shack + name = "Point of Interest - Chemistry Shack" diff --git a/mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dmm b/mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dmm new file mode 100644 index 000000000000..75a6ccefde76 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/chemistry_shack/chemistry_shack.dmm @@ -0,0 +1,276 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/door/walnut{ + dir = 4 + }, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"h" = ( +/obj/abstract/exterior_marker/inside, +/obj/item/rock/hematite{ + pixel_x = -8; + pixel_y = 16 + }, +/obj/item/rock/flint{ + pixel_y = 16 + }, +/obj/item/chems/glass/handmade/jar{ + pixel_y = 16; + pixel_x = 10 + }, +/obj/item/chems/glass/handmade/jar{ + pixel_y = 8; + pixel_x = 10 + }, +/obj/item/flame/fuelled/lantern/filled{ + pixel_y = 4; + pixel_x = 4 + }, +/obj/item/flame/fuelled/lantern/filled{ + pixel_y = 4; + pixel_x = -8 + }, +/obj/structure/table/desk/ebony, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -5 + }, +/turf/floor/path/herringbone/basalt, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"k" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/table/wood/ebony, +/obj/item/chems/cooking_vessel/pot/iron, +/obj/item/chems/glass/handmade/teapot, +/obj/abstract/landmark/organize/vertical, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"m" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/reagent_dispensers/barrel/ebony/oil, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"n" = ( +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/turf/floor/dirt, +/area/template_noop) +"p" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/mortar, +/obj/item/rock/basalt, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"q" = ( +/obj/structure/drying_rack/ebony, +/turf/floor/dirt, +/area/template_noop) +"r" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/filter_stand/mapped, +/turf/floor/path/herringbone/basalt, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"s" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/log/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"z" = ( +/turf/template_noop, +/area/template_noop) +"C" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/door/walnut, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"F" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/brick/basalt, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"H" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/brick/basalt/shutter, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"I" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"J" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"K" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/furs, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"L" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/table/wood/ebony, +/obj/item/bladed/knife/iron, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/carrot, +/obj/item/food/grown/carrot, +/obj/item/rollingpin, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"M" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/reagent_dispensers/barrel/ebony/wine, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"N" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/path/herringbone/basalt, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"R" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/closet/crate/chest/ebony, +/obj/random/jewelry, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"U" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/wall_sconce/lantern{ + dir = 1; + pixel_y = 10 + }, +/obj/item/chems/glass/handmade/bottle/tall/wine{ + pixel_x = -10; + pixel_y = 18 + }, +/obj/structure/fire_source/heater/mapped{ + pixel_y = 2 + }, +/obj/item/chems/glass/handmade/bottle/tall/wine{ + pixel_x = -10; + pixel_y = 9 + }, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -16 + }, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = 5 + }, +/turf/floor/path/herringbone/basalt, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"W" = ( +/turf/floor/dirt, +/area/template_noop) +"X" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/log/walnut/shutter, +/area/fantasy/outside/point_of_interest/chemistry_shack) +"Y" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/fire_source/stove, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/chemistry_shack) + +(1,1,1) = {" +W +W +z +W +W +W +z +z +z +"} +(2,1,1) = {" +W +F +F +H +a +s +s +s +z +"} +(3,1,1) = {" +W +F +h +N +J +J +Y +s +W +"} +(4,1,1) = {" +z +F +U +N +p +k +L +X +W +"} +(5,1,1) = {" +W +F +r +N +s +s +s +s +n +"} +(6,1,1) = {" +z +s +M +J +C +K +s +q +z +"} +(7,1,1) = {" +W +s +I +m +s +R +X +q +W +"} +(8,1,1) = {" +W +s +s +X +s +s +s +W +W +"} +(9,1,1) = {" +W +W +z +W +W +W +W +z +z +"} diff --git a/mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring.dmm b/mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring.dmm new file mode 100644 index 000000000000..7d554d6fc8a4 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring.dmm @@ -0,0 +1,95 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/fairy_ring) +"w" = ( +/obj/structure/flora/plant/random_mushroom, +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/fairy_ring) +"D" = ( +/turf/floor/grass/wild, +/area/fantasy/outside/point_of_interest/fairy_ring) +"N" = ( +/turf/template_noop, +/area/template_noop) + +(1,1,1) = {" +N +N +a +N +w +a +N +N +"} +(2,1,1) = {" +N +a +w +a +a +w +w +N +"} +(3,1,1) = {" +w +a +a +D +D +a +a +w +"} +(4,1,1) = {" +w +a +D +D +D +D +a +a +"} +(5,1,1) = {" +a +a +D +D +D +a +w +N +"} +(6,1,1) = {" +N +a +D +D +a +a +w +N +"} +(7,1,1) = {" +N +w +a +a +a +w +N +N +"} +(8,1,1) = {" +N +a +w +w +a +N +N +N +"} diff --git a/mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring_glowing.dmm b/mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring_glowing.dmm new file mode 100644 index 000000000000..b86a4adcb0f4 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring_glowing.dmm @@ -0,0 +1,95 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"h" = ( +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/fairy_ring) +"j" = ( +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/fairy_ring) +"A" = ( +/obj/structure/flora/plant/random_mushroom/glowing, +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/fairy_ring) + +(1,1,1) = {" +a +a +a +a +a +h +a +a +"} +(2,1,1) = {" +a +h +h +A +h +A +h +a +"} +(3,1,1) = {" +h +h +A +j +j +j +A +h +"} +(4,1,1) = {" +h +j +j +j +j +j +A +h +"} +(5,1,1) = {" +h +A +j +j +j +j +j +h +"} +(6,1,1) = {" +a +h +A +j +j +h +A +h +"} +(7,1,1) = {" +a +h +h +h +A +A +a +a +"} +(8,1,1) = {" +a +a +h +h +h +a +a +a +"} diff --git a/mods/content/fantasy/submaps/woods/fairy_rings/fairy_rings.dm b/mods/content/fantasy/submaps/woods/fairy_rings/fairy_rings.dm new file mode 100644 index 000000000000..76140bdb7592 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/fairy_rings/fairy_rings.dm @@ -0,0 +1,15 @@ +/datum/map_template/fantasy/woods/fairy_ring + name = "fairy ring" + mappaths = list("mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring.dmm") + template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS | TEMPLATE_FLAG_ALLOW_DUPLICATES | TEMPLATE_FLAG_GENERIC_REPEATABLE + template_categories = list( + MAP_TEMPLATE_CATEGORY_FANTASY_WOODS + ) + area_coherency_test_exempt_areas = list(/area/fantasy/outside/point_of_interest/fairy_ring) + +/datum/map_template/fantasy/woods/fairy_ring/glowing + name = "glowing fairy ring" + mappaths = list("mods/content/fantasy/submaps/woods/fairy_rings/fairy_ring_glowing.dmm") + +/area/fantasy/outside/point_of_interest/fairy_ring + name = "Point of Interest - Fairy Ring" diff --git a/mods/content/fantasy/submaps/woods/fox_den/fox_den.dm b/mods/content/fantasy/submaps/woods/fox_den/fox_den.dm new file mode 100644 index 000000000000..894f6f7fb50a --- /dev/null +++ b/mods/content/fantasy/submaps/woods/fox_den/fox_den.dm @@ -0,0 +1,6 @@ +/datum/map_template/fantasy/woods/fox_den + name = "fox den" + mappaths = list("mods/content/fantasy/submaps/woods/fox_den/fox_den.dmm") + +/area/fantasy/outside/point_of_interest/fox_den + name = "Point of Interest - Fox Den" diff --git a/mods/content/fantasy/submaps/woods/fox_den/fox_den.dmm b/mods/content/fantasy/submaps/woods/fox_den/fox_den.dmm new file mode 100644 index 000000000000..8053ead1e471 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/fox_den/fox_den.dmm @@ -0,0 +1,315 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/floor/dirt, +/area/template_noop) +"n" = ( +/turf/template_noop, +/area/template_noop) +"r" = ( +/mob/living/simple_animal/passive/fox, +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"x" = ( +/turf/floor/grass/wild, +/area/template_noop) +"y" = ( +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/quin, +/obj/item/cash/imperial/crown, +/obj/item/cash/imperial/crown, +/obj/item/clothing/ears/dangle/diamond, +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"B" = ( +/turf/floor/grass, +/area/template_noop) +"M" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/wall/natural/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"O" = ( +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"P" = ( +/obj/item/food/butchery/offal/small, +/obj/item/stack/material/bone/mapped/bone, +/obj/abstract/exterior_marker/inside, +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"S" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"W" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/natural/dirt, +/area/fantasy/outside/point_of_interest/fox_den) +"Y" = ( +/obj/item/seeds/extracted/foxglove, +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/fox_den) + +(1,1,1) = {" +n +n +n +a +a +B +n +n +n +n +n +n +n +n +n +"} +(2,1,1) = {" +n +a +a +B +B +a +a +B +B +B +n +a +a +n +n +"} +(3,1,1) = {" +a +B +B +B +a +S +S +S +x +x +B +B +a +a +n +"} +(4,1,1) = {" +B +x +x +W +S +S +O +O +W +W +x +B +B +a +n +"} +(5,1,1) = {" +B +B +x +W +O +M +M +M +M +M +W +x +B +a +n +"} +(6,1,1) = {" +a +B +W +W +O +M +M +M +P +M +W +W +a +a +n +"} +(7,1,1) = {" +a +a +W +W +O +O +M +M +O +y +W +W +a +B +B +"} +(8,1,1) = {" +a +a +W +W +W +S +W +S +r +Y +W +W +B +B +B +"} +(9,1,1) = {" +n +a +B +W +W +S +S +S +S +W +W +W +B +x +B +"} +(10,1,1) = {" +n +B +B +W +M +M +O +S +W +W +W +B +x +x +B +"} +(11,1,1) = {" +n +B +B +B +W +W +M +W +W +W +a +x +x +B +B +"} +(12,1,1) = {" +n +a +a +B +B +x +W +W +a +x +x +x +B +B +a +"} +(13,1,1) = {" +n +n +a +a +a +B +x +x +x +x +x +a +B +a +a +"} +(14,1,1) = {" +n +n +n +n +a +B +B +x +x +B +a +a +a +a +n +"} +(15,1,1) = {" +n +n +n +n +n +a +a +B +B +B +a +n +n +n +n +"} diff --git a/mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dm b/mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dm new file mode 100644 index 000000000000..262e1b71d551 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dm @@ -0,0 +1,6 @@ +/datum/map_template/fantasy/woods/hunter_camp + name = "hunter camp" + mappaths = list("mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dmm") + +/area/fantasy/outside/point_of_interest/hunter_camp + name = "Point of Interest - Hunter Camp" diff --git a/mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dmm b/mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dmm new file mode 100644 index 000000000000..c54ef3bfe8ca --- /dev/null +++ b/mods/content/fantasy/submaps/woods/hunter_camp/hunter_camp.dmm @@ -0,0 +1,531 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/floor/grass/wild, +/area/fantasy/outside/point_of_interest/hunter_camp) +"b" = ( +/obj/structure/drying_rack, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/hunter_camp) +"e" = ( +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/hunter_camp) +"h" = ( +/obj/structure/flora/tree/hardwood/ebony, +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/hunter_camp) +"j" = ( +/obj/item/stack/material/skin/mapped/leather/twenty, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"k" = ( +/obj/item/food/butchery/offal/beef, +/obj/item/food/butchery/offal/small/beef, +/obj/structure/pit, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/hunter_camp) +"n" = ( +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/hunter_camp) +"q" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/item/food/butchery/haunch/shoulder/beef, +/obj/item/food/butchery/haunch/side/beef, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"A" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/log/walnut, +/area/fantasy/outside/point_of_interest/hunter_camp) +"B" = ( +/obj/structure/flora/stump/tree/ebony, +/turf/floor/grass/wild, +/area/fantasy/outside/point_of_interest/hunter_camp) +"C" = ( +/obj/structure/flora/stump/tree/ebony, +/turf/floor/grass, +/area/fantasy/outside/point_of_interest/hunter_camp) +"D" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/hunter_camp) +"E" = ( +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"F" = ( +/obj/structure/drying_rack, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"I" = ( +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"J" = ( +/obj/structure/flora/tree/hardwood/ebony, +/turf/floor/grass/wild, +/area/fantasy/outside/point_of_interest/hunter_camp) +"K" = ( +/turf/template_noop, +/area/template_noop) +"P" = ( +/obj/structure/flora/tree/hardwood/mahogany, +/turf/floor/grass/wild, +/area/fantasy/outside/point_of_interest/hunter_camp) +"Q" = ( +/obj/structure/bed/bedroll/fur, +/obj/abstract/exterior_marker/inside, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"S" = ( +/obj/structure/fire_source/firepit/basalt, +/obj/item/stack/material/log/mapped/walnut/fifteen, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"U" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) +"Z" = ( +/obj/item/bladed/knife/iron, +/turf/floor/barren, +/area/fantasy/outside/point_of_interest/hunter_camp) + +(1,1,1) = {" +K +K +K +K +K +K +K +K +K +K +e +e +e +e +K +K +K +K +K +K +"} +(2,1,1) = {" +K +a +K +e +e +K +K +K +e +e +e +e +a +a +a +K +K +K +K +K +"} +(3,1,1) = {" +a +a +a +e +e +e +e +e +e +e +h +a +a +a +a +a +a +K +K +K +"} +(4,1,1) = {" +a +a +a +e +e +e +e +h +e +a +a +a +J +B +a +P +a +a +K +K +"} +(5,1,1) = {" +K +a +a +e +e +C +e +e +a +a +n +n +a +a +a +a +a +a +K +K +"} +(6,1,1) = {" +e +a +a +B +a +e +e +n +n +n +n +n +n +e +a +B +a +a +e +K +"} +(7,1,1) = {" +e +a +a +P +e +e +n +n +n +n +n +k +n +n +e +a +a +e +a +K +"} +(8,1,1) = {" +e +a +a +a +a +n +A +D +U +I +n +n +n +n +n +e +e +e +e +e +"} +(9,1,1) = {" +K +e +a +a +a +n +D +Q +U +I +I +I +E +n +n +n +e +e +e +e +"} +(10,1,1) = {" +K +K +e +a +a +n +D +U +U +S +I +I +I +I +n +n +e +h +a +a +"} +(11,1,1) = {" +K +e +e +e +e +n +A +U +U +I +I +j +F +I +n +n +e +B +a +a +"} +(12,1,1) = {" +K +e +e +e +e +e +n +n +I +q +Z +b +n +n +n +e +a +a +J +K +"} +(13,1,1) = {" +K +e +e +e +e +e +n +n +n +n +n +n +n +e +e +e +a +a +a +K +"} +(14,1,1) = {" +K +e +e +e +C +e +e +n +n +n +n +n +e +e +a +a +B +a +a +K +"} +(15,1,1) = {" +K +K +e +e +e +e +e +e +a +B +a +e +e +e +e +a +a +a +a +K +"} +(16,1,1) = {" +K +K +K +e +e +J +a +a +P +a +a +e +e +e +a +a +a +a +a +K +"} +(17,1,1) = {" +K +K +K +e +e +a +a +B +a +a +a +a +a +e +h +a +a +a +K +K +"} +(18,1,1) = {" +K +K +K +K +e +e +a +a +a +a +a +a +a +a +a +a +a +K +K +K +"} +(19,1,1) = {" +K +K +K +K +K +e +e +e +e +a +a +a +J +a +a +a +a +K +K +K +"} +(20,1,1) = {" +K +K +K +K +K +K +K +e +e +e +e +K +K +K +K +K +K +K +K +K +"} diff --git a/mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dm b/mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dm new file mode 100644 index 000000000000..4a2130efce27 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dm @@ -0,0 +1,6 @@ +/datum/map_template/fantasy/woods/old_cabin + name = "old cabin" + mappaths = list("mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dmm") + +/area/fantasy/outside/point_of_interest/old_cabin + name = "Point of Interest - Old Cabin" diff --git a/mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dmm b/mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dmm new file mode 100644 index 000000000000..9156eb4514d4 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/old_cabin/old_cabin.dmm @@ -0,0 +1,236 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/obj/structure/door/walnut, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"g" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/table/end, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"h" = ( +/turf/template_noop, +/area/template_noop) +"i" = ( +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/old_cabin) +"k" = ( +/obj/structure/closet/crate/chest/ebony, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"o" = ( +/obj/structure/drying_rack/ebony, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"u" = ( +/obj/structure/reagent_dispensers/barrel/ebony/beer, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"x" = ( +/obj/structure/table/wood/ebony, +/obj/item/flame/torch, +/obj/item/flame/torch, +/obj/item/rock/flint, +/obj/item/rock/hematite, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"z" = ( +/obj/effect/spider/spiderling/mundane, +/obj/structure/table/wood/ebony, +/obj/structure/wall_sconce/torch{ + dir = 1; + pixel_y = 24 + }, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"B" = ( +/obj/effect/decal/cleanable/blood, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"D" = ( +/obj/effect/spider/spiderling/mundane, +/obj/structure/table/wood/ebony, +/obj/item/food/grown/carrot, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"G" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/log/walnut/shutter, +/area/fantasy/outside/point_of_interest/old_cabin) +"H" = ( +/obj/structure/table/wood/ebony, +/obj/item/bladed/knife/iron, +/obj/item/food/grown/potato, +/obj/item/food/grown/potato, +/obj/item/food/grown/carrot, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"I" = ( +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"L" = ( +/obj/effect/spider/spiderling/mundane, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"M" = ( +/obj/abstract/exterior_marker/inside, +/turf/wall/log/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"N" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/coatrack/ebony, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"T" = ( +/obj/abstract/exterior_marker/inside, +/obj/structure/table/desk/dresser, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) +"W" = ( +/obj/structure/wall_sconce/torch{ + dir = 1; + pixel_y = 24 + }, +/turf/floor/dirt, +/area/fantasy/outside/point_of_interest/old_cabin) +"Z" = ( +/obj/item/remains/human, +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/furs, +/obj/effect/decal/cleanable/blood, +/obj/random/jewelry, +/obj/abstract/exterior_marker/inside, +/turf/floor/wood/rough/walnut, +/area/fantasy/outside/point_of_interest/old_cabin) + +(1,1,1) = {" +i +i +i +h +i +i +i +h +h +h +"} +(2,1,1) = {" +i +M +M +M +G +M +M +M +M +h +"} +(3,1,1) = {" +i +M +x +I +I +a +I +I +a +i +"} +(4,1,1) = {" +h +M +z +I +I +M +N +L +G +i +"} +(5,1,1) = {" +i +M +o +I +I +M +M +M +M +W +"} +(6,1,1) = {" +h +M +o +I +I +M +T +Z +M +h +"} +(7,1,1) = {" +i +M +u +I +B +a +B +I +G +i +"} +(8,1,1) = {" +i +M +D +H +I +M +g +k +M +i +"} +(9,1,1) = {" +i +M +M +M +G +M +M +M +M +h +"} +(10,1,1) = {" +h +i +i +h +i +i +i +i +h +h +"} diff --git a/mods/content/fantasy/submaps/woods/suspicious_cabin/suspicious_cabin.dmm b/mods/content/fantasy/submaps/woods/suspicious_cabin/suspicious_cabin.dmm new file mode 100644 index 000000000000..36df27b338b1 --- /dev/null +++ b/mods/content/fantasy/submaps/woods/suspicious_cabin/suspicious_cabin.dmm @@ -0,0 +1,402 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/template_noop, +/area/template_noop) +"d" = ( +/obj/structure/chair/wood/ebony{ + dir = 1 + }, +/turf/floor/wood/walnut, +/area/template_noop) +"e" = ( +/obj/structure/bed/simple/ebony/cloth, +/obj/item/bedsheet/furs, +/turf/floor/wood/walnut, +/area/template_noop) +"f" = ( +/turf/floor/dirt, +/area/template_noop) +"g" = ( +/turf/floor/wood/walnut, +/area/template_noop) +"i" = ( +/obj/structure/reagent_dispensers/barrel/ebony/wine, +/turf/floor/path/basalt, +/area/template_noop) +"k" = ( +/obj/structure/coatrack/ebony, +/turf/floor/wood/walnut, +/area/template_noop) +"q" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/cup/wood, +/turf/floor/wood/walnut, +/area/template_noop) +"r" = ( +/obj/structure/chair/bench/ebony{ + dir = 4 + }, +/turf/floor/wood/walnut, +/area/template_noop) +"s" = ( +/turf/floor/path/basalt, +/area/template_noop) +"t" = ( +/obj/structure/table/wood/ebony, +/obj/item/bladed/knife/iron, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -5 + }, +/turf/floor/path/basalt, +/area/template_noop) +"v" = ( +/turf/wall/log/walnut/shutter, +/area/template_noop) +"w" = ( +/obj/structure/chair/wood/ebony, +/turf/floor/wood/walnut, +/area/template_noop) +"x" = ( +/obj/structure/door/walnut, +/turf/floor/wood/walnut, +/area/template_noop) +"y" = ( +/obj/structure/reagent_dispensers/barrel/ebony, +/turf/floor/path/basalt, +/area/template_noop) +"D" = ( +/obj/structure/table/desk/dresser, +/obj/item/flame/candle/handmade{ + pixel_y = 12 + }, +/turf/floor/wood/walnut, +/area/template_noop) +"E" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/teapot, +/turf/floor/wood/walnut, +/area/template_noop) +"G" = ( +/obj/item/stack/material/log/mapped/walnut/twenty, +/turf/floor/path/basalt, +/area/template_noop) +"J" = ( +/obj/structure/table/wood/ebony, +/obj/item/food/grown/potato, +/obj/item/chems/cooking_vessel/pot/iron, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -16 + }, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = 5 + }, +/turf/floor/path/basalt, +/area/template_noop) +"K" = ( +/turf/wall/brick/basalt/shutter, +/area/template_noop) +"N" = ( +/obj/structure/reagent_dispensers/barrel/ebony/water, +/turf/floor/path/basalt, +/area/template_noop) +"O" = ( +/obj/structure/fire_source/stove, +/obj/item/chems/glass/beaker/kettle, +/turf/floor/path/basalt, +/area/template_noop) +"P" = ( +/obj/structure/chair/bench/ebony, +/turf/floor/wood/walnut, +/area/template_noop) +"Q" = ( +/obj/structure/reagent_dispensers/barrel/ebony/beer, +/turf/floor/path/basalt, +/area/template_noop) +"R" = ( +/obj/structure/table/wood/ebony, +/turf/floor/wood/walnut, +/area/template_noop) +"S" = ( +/obj/structure/table/wood/ebony, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/bowl/wood, +/obj/item/chems/glass/handmade/cup/wood, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = -6 + }, +/obj/structure/wall_cabinet/ebony{ + pixel_y = 35; + pixel_x = 15 + }, +/turf/floor/path/basalt, +/area/template_noop) +"U" = ( +/obj/structure/closet/crate/chest/ebony, +/turf/floor/path/basalt, +/area/template_noop) +"X" = ( +/turf/wall/brick/basalt, +/area/template_noop) +"Y" = ( +/turf/wall/log/walnut, +/area/template_noop) + +(1,1,1) = {" +a +a +f +f +f +f +f +a +a +a +f +a +a +a +a +"} +(2,1,1) = {" +a +f +f +X +X +X +K +X +X +X +f +f +a +a +a +"} +(3,1,1) = {" +f +f +X +X +U +U +Q +i +U +X +X +f +f +a +a +"} +(4,1,1) = {" +a +f +X +y +s +s +s +s +s +U +X +f +f +f +a +"} +(5,1,1) = {" +f +X +X +X +X +x +X +X +X +X +X +Y +Y +v +Y +"} +(6,1,1) = {" +Y +X +O +X +g +g +g +g +g +g +g +Y +D +e +Y +"} +(7,1,1) = {" +Y +t +s +g +g +g +w +R +R +d +g +x +g +g +Y +"} +(8,1,1) = {" +v +J +s +g +g +g +w +q +E +d +g +Y +Y +Y +Y +"} +(9,1,1) = {" +Y +S +s +g +g +g +g +g +g +g +g +Y +f +f +a +"} +(10,1,1) = {" +Y +y +s +Y +Y +x +Y +Y +g +g +g +Y +Y +Y +Y +"} +(11,1,1) = {" +Y +N +s +Y +k +g +P +Y +r +r +g +x +g +g +Y +"} +(12,1,1) = {" +Y +Y +G +Y +P +g +P +Y +g +g +g +Y +D +e +Y +"} +(13,1,1) = {" +a +Y +Y +Y +k +g +P +Y +Y +v +Y +Y +Y +v +Y +"} +(14,1,1) = {" +a +f +f +Y +Y +x +Y +Y +f +f +f +f +a +a +a +"} +(15,1,1) = {" +a +a +a +a +f +f +f +a +a +f +a +a +a +a +a +"} diff --git a/mods/content/fantasy/turfs.dm b/mods/content/fantasy/turfs.dm new file mode 100644 index 000000000000..5911652b0cfa --- /dev/null +++ b/mods/content/fantasy/turfs.dm @@ -0,0 +1,2 @@ +/turf/floor + _base_flooring = /decl/flooring/dirt \ No newline at end of file diff --git a/mods/content/generic_shuttles/_generic_shuttles.dm b/mods/content/generic_shuttles/_generic_shuttles.dm new file mode 100644 index 000000000000..72660788e79e --- /dev/null +++ b/mods/content/generic_shuttles/_generic_shuttles.dm @@ -0,0 +1,2 @@ +/decl/modpack/generic_shuttles + name = "Generic Shuttles" \ No newline at end of file diff --git a/mods/content/generic_shuttles/_generic_shuttles.dme b/mods/content/generic_shuttles/_generic_shuttles.dme new file mode 100644 index 000000000000..c77cee5daa9d --- /dev/null +++ b/mods/content/generic_shuttles/_generic_shuttles.dme @@ -0,0 +1,7 @@ +#ifndef MODPACK_GENERIC_SHUTTLES +#define MODPACK_GENERIC_SHUTTLES +// BEGIN_INCLUDE +#include "_generic_shuttles.dm" +#include "tanker\tanker.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/generic_shuttles/tanker/tanker.dm b/mods/content/generic_shuttles/tanker/tanker.dm new file mode 100644 index 000000000000..e7c58636d3a1 --- /dev/null +++ b/mods/content/generic_shuttles/tanker/tanker.dm @@ -0,0 +1,34 @@ +/datum/map_template/ruin/away_site/tanker + name = "tanker shuttle" + description = "Generic tanker shuttle." + suffixes = list("tanker/tanker.dmm") + cost = INFINITY + prefix = "mods/content/generic_shuttles/" + area_usage_test_exempted_root_areas = list(/area/tanker) + shuttles_to_initialise = list(/datum/shuttle/autodock/overmap/tanker) + template_flags = TEMPLATE_FLAG_ALLOW_DUPLICATES + +/obj/effect/overmap/visitable/ship/landable/tanker + name = "Tanker" + desc = "Sensors detect an Astor class medium-haul gas tanker." + shuttle = "Tanker" + fore_dir = WEST + max_speed = 1/(10 SECOND) + sector_flags = OVERMAP_SECTOR_KNOWN + use_mapped_z_levels = TRUE + +/datum/shuttle/autodock/overmap/tanker + name = "Tanker" + warmup_time = 40 + fuel_consumption = 2 + current_location = "nav_tanker" + dock_target = "tanker_dock" + defer_initialisation = TRUE + shuttle_area = /area/tanker + +/obj/effect/shuttle_landmark/ship/tanker + landmark_tag = "nav_tanker" + +/area/tanker + name = "Tanker" + icon_state = "yellow" \ No newline at end of file diff --git a/mods/content/generic_shuttles/tanker/tanker.dmm b/mods/content/generic_shuttles/tanker/tanker.dmm new file mode 100644 index 000000000000..f109b52426b9 --- /dev/null +++ b/mods/content/generic_shuttles/tanker/tanker.dmm @@ -0,0 +1,4264 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"as" = ( +/obj/machinery/atmospherics/unary/vent_pump/tank{ + dir = 1; + id_tag = "tanker_output"; + pump_direction = 0 + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"bb" = ( +/obj/machinery/door/airlock/external/bolted_open{ + id_tag = "tanker_dock_interior_door" + }, +/turf/floor/plating, +/area/tanker) +"bd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/tanker) +"bC" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 8 + }, +/turf/floor/reinforced/airless, +/area/tanker) +"cT" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"cV" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + dir = 8; + id_tag = "tanker_dock"; + pixel_x = 24; + tag_airpump = "tanker_dock_pump"; + tag_chamber_sensor = "tanker_dock_sensor"; + tag_exterior_door = "tanker_dock_exterior_door"; + tag_interior_door = "tanker_dock_interior_door" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/tanker) +"dg" = ( +/obj/effect/overmap/visitable/ship/landable/tanker, +/turf/floor/tiled/steel_grid, +/area/tanker) +"dJ" = ( +/turf/floor/reinforced/airless, +/area/tanker) +"eb" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"et" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"eP" = ( +/obj/machinery/computer/ship/helm{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"eQ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ + dir = 8 + }, +/turf/floor/reinforced/airless, +/area/tanker) +"fi" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"fp" = ( +/obj/machinery/computer/air_control{ + dir = 4; + input_tag = "tanker_input"; + output_tag = "tanker_output"; + sensor_name = "Main Tank"; + sensor_tag = "tanker_sensor" + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"fv" = ( +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/tanker) +"fy" = ( +/obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos/tank{ + dir = 4; + id_tag = "tanker_fuel" + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"hQ" = ( +/obj/machinery/air_sensor{ + id_tag = "tanker_sensor" + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"ia" = ( +/obj/machinery/door/airlock/engineering, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/steel_grid, +/area/tanker) +"ig" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/turf/floor/plating, +/area/tanker) +"ix" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/tanker) +"jh" = ( +/turf/space, +/area/space) +"jp" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "tanker_dock_pump" + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/plating, +/area/tanker) +"jN" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 10 + }, +/turf/floor/plating, +/area/tanker) +"kN" = ( +/obj/machinery/door/airlock/engineering, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable/blue{ + icon_state = "2-5" + }, +/turf/floor/plating, +/area/tanker) +"la" = ( +/obj/machinery/suit_cycler/generic/prepared, +/turf/floor/tiled/steel_grid, +/area/tanker) +"lr" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible/green, +/turf/floor/reinforced/oxygen, +/area/tanker) +"lu" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/tanker) +"lU" = ( +/turf/wall/r_wall/hull, +/area/tanker) +"qS" = ( +/obj/machinery/atmospherics/portables_connector, +/obj/machinery/portable_atmospherics/canister/air, +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/floor/plating, +/area/tanker) +"rS" = ( +/obj/machinery/computer/shuttle_control/explore{ + dir = 4; + name = "shuttle control console"; + shuttle_tag = "Tanker" + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"sl" = ( +/turf/floor/tiled/steel_grid, +/area/tanker) +"sp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 5 + }, +/turf/floor/reinforced/airless, +/area/tanker) +"sN" = ( +/obj/machinery/shipsensors, +/turf/floor/plating, +/area/tanker) +"ul" = ( +/obj/machinery/atmospherics/unary/vent_pump/tank{ + id_tag = "tanker_output"; + pump_direction = 0 + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"vC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/apc/high{ + dir = 4; + pixel_x = 24 + }, +/obj/structure/cable/blue, +/turf/floor/tiled/steel_grid, +/area/tanker) +"vT" = ( +/turf/floor/plating, +/area/tanker) +"wS" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/tanker) +"xA" = ( +/obj/effect/shuttle_landmark/ship/tanker, +/turf/floor/reinforced/oxygen, +/area/tanker) +"yd" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"yv" = ( +/obj/machinery/atmospherics/valve{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"yG" = ( +/obj/structure/chair/office, +/turf/floor/tiled/steel_grid, +/area/tanker) +"An" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/green{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"AH" = ( +/obj/structure/bed, +/turf/floor/tiled/steel_grid, +/area/tanker) +"AM" = ( +/obj/machinery/door/airlock/external/bolted{ + dir = 8; + id_tag = "tanker_dock_exterior_door" + }, +/obj/machinery/atmospherics/valve/shutoff{ + dir = 8 + }, +/turf/floor/plating, +/area/tanker) +"BD" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"BI" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/fabricator/pipe{ + anchored = 1 + }, +/turf/floor/plating, +/area/tanker) +"Co" = ( +/obj/machinery/door/airlock/external/bolted_open{ + id_tag = "tanker_dock_interior_door" + }, +/obj/machinery/atmospherics/pipe/simple/visible/green, +/turf/floor/plating, +/area/tanker) +"CD" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/chair/shuttle{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Dh" = ( +/obj/machinery/computer/modular/preset/civilian{ + dir = 4 + }, +/obj/machinery/light, +/turf/floor/tiled/steel_grid, +/area/tanker) +"DV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/alarm{ + dir = 8; + pixel_x = 24 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"FX" = ( +/obj/machinery/computer/ship/engines{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Gu" = ( +/obj/structure/cable/blue{ + icon_state = "0-10" + }, +/obj/machinery/power/smes/buildable/preset{ + _fully_charged = 1; + _input_maxed = 1; + _output_maxed = 1; + _output_on = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/floor/plating, +/area/tanker) +"GF" = ( +/turf/wall, +/area/tanker) +"HO" = ( +/obj/machinery/atmospherics/pipe/simple/visible/green{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable/blue{ + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Iv" = ( +/obj/machinery/door/airlock/external/bolted{ + dir = 8; + id_tag = "tanker_dock_exterior_door" + }, +/turf/floor/plating, +/area/tanker) +"Jx" = ( +/obj/machinery/door/airlock/external/bolted{ + dir = 8; + id_tag = "tanker_dock_exterior_door" + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/floor/plating, +/area/tanker) +"Km" = ( +/obj/structure/rack, +/obj/item/belt/utility/atmostech, +/obj/item/wrench, +/obj/item/wrench/pipe, +/obj/item/radio/off, +/obj/item/radio/off, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Na" = ( +/obj/machinery/door/airlock/maintenance, +/turf/floor/reinforced/airless, +/area/tanker) +"Ni" = ( +/obj/machinery/airlock_sensor{ + id_tag = "tanker_dock_sensor"; + pixel_y = 24 + }, +/turf/floor/plating, +/area/tanker) +"Qj" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Ro" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/tanker) +"Rq" = ( +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/turf/wall, +/area/tanker) +"RC" = ( +/obj/structure/table, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Sf" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 4 + }, +/turf/floor/plating, +/area/tanker) +"So" = ( +/obj/machinery/atmospherics/unary/outlet_injector{ + dir = 8; + id_tag = "tanker_input" + }, +/turf/floor/reinforced/oxygen, +/area/tanker) +"Td" = ( +/turf/floor/reinforced/oxygen, +/area/tanker) +"Tr" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Uf" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Uu" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/obj/structure/chair/shuttle{ + dir = 8 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"Va" = ( +/obj/machinery/computer/ship/sensors{ + dir = 4 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) +"VD" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/fuel{ + dir = 1 + }, +/turf/floor/reinforced/airless, +/area/tanker) +"WC" = ( +/obj/machinery/atmospherics/valve/open{ + dir = 4 + }, +/turf/floor/reinforced/airless, +/area/tanker) +"WG" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/floor/plating, +/area/tanker) +"WZ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/turf/wall, +/area/tanker) +"YI" = ( +/obj/machinery/power/terminal, +/obj/structure/cable/green{ + icon_state = "0-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/plating, +/area/tanker) +"YS" = ( +/obj/effect/wallframe_spawn/reinforced, +/turf/floor/plating, +/area/tanker) +"Ze" = ( +/obj/structure/fuel_port/hydrogen, +/turf/wall/r_wall/hull, +/area/tanker) +"ZI" = ( +/obj/structure/closet/emcloset, +/turf/floor/tiled/steel_grid, +/area/tanker) +"ZX" = ( +/obj/machinery/door/airlock/external/bolted, +/turf/floor/plating, +/area/tanker) +"ZY" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/turf/floor/tiled/steel_grid, +/area/tanker) + +(1,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(2,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(3,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(4,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(5,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(6,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(7,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(8,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(9,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(10,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(11,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(12,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(13,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(14,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(15,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(16,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(17,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(18,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(19,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Iv +Jx +AM +lU +lU +lU +YS +YS +YS +YS +YS +lU +lU +lU +lU +sN +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(20,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Ni +wS +jN +Co +An +ZY +fp +rS +FX +eP +Va +GF +la +la +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(21,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +Ze +jp +cV +vT +bb +yv +sl +sl +Uu +dg +CD +fv +GF +Uf +sl +Dh +lU +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(22,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +WZ +Rq +GF +GF +HO +cT +vC +Tr +DV +yd +bd +ia +eb +sl +yG +RC +AH +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(23,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +qS +ix +WG +kN +BD +GF +GF +GF +GF +GF +GF +GF +Qj +sl +sl +sl +sl +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(24,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lu +YI +Gu +GF +ig +GF +Td +Td +Td +Td +Td +GF +ZX +GF +Km +sl +sl +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(25,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +BI +vT +GF +GF +et +hQ +Td +Td +Td +Td +Td +Td +Td +GF +GF +sl +fv +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(26,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Ro +GF +GF +ul +lr +as +Td +Td +Td +Td +Td +Td +Td +Td +GF +GF +ZI +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(27,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +GF +GF +Td +ul +lr +as +Td +Td +Td +Td +Td +Td +Td +Td +Td +GF +GF +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(28,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +GF +Td +Td +ul +lr +as +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +GF +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(29,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +So +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(30,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(31,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(32,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(33,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +xA +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(34,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(35,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(36,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(37,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(38,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(39,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lU +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(40,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lU +Td +fy +Td +Td +Td +Td +Td +Td +Td +Td +Td +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(41,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +lU +fi +Td +Td +Td +Td +Td +Td +Td +Td +lU +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(42,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +Sf +GF +Td +Td +Td +Td +Td +GF +YS +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(43,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +Na +WC +GF +GF +GF +GF +GF +GF +GF +dJ +Na +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(44,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +VD +eQ +eQ +eQ +eQ +eQ +eQ +eQ +sp +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(45,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +lU +bC +bC +bC +bC +bC +bC +bC +bC +bC +lU +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(46,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(47,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(48,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(49,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(50,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(51,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(52,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(53,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(54,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(55,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(56,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(57,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(58,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(59,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} +(60,1,1) = {" +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +jh +"} diff --git a/mods/government/_government.dme b/mods/content/government/_government.dme similarity index 75% rename from mods/government/_government.dme rename to mods/content/government/_government.dme index 62ec2d0408cc..0555b590d8b2 100644 --- a/mods/government/_government.dme +++ b/mods/content/government/_government.dme @@ -1,12 +1,15 @@ #ifndef MODPACK_GOVERNMENT #define MODPACK_GOVERNMENT -// BEGIN INCLUDE +// BEGIN_INCLUDE #include "government.dm" +#include "overrides.dm" #include "datum\ai_holo.dm" #include "datum\ai_laws.dm" +#include "items\alcohol.dm" #include "items\clutter.dm" #include "items\cups.dm" #include "items\documents.dm" +#include "items\masks.dm" #include "ruins\ec_old_crash\ec_old_crash.dm" -#endif // END_INCLUDE +#endif diff --git a/mods/government/away_sites/icarus/icarus-1.dmm b/mods/content/government/away_sites/icarus/icarus-1.dmm similarity index 84% rename from mods/government/away_sites/icarus/icarus-1.dmm rename to mods/content/government/away_sites/icarus/icarus-1.dmm index 54ea5ec78618..5551f2c2b61f 100644 --- a/mods/government/away_sites/icarus/icarus-1.dmm +++ b/mods/content/government/away_sites/icarus/icarus-1.dmm @@ -6,136 +6,136 @@ /turf/unsimulated/mask, /area/mine/unexplored) "ac" = ( -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/icarus/open) "ae" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/icarus/open) "af" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/icarus/vessel) "ag" = ( /obj/structure/grille, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ah" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ai" = ( -/obj/item/ore/slag, -/turf/simulated/floor/plating, +/obj/item/stack/material/ore/slag, +/turf/floor/plating, /area/icarus/vessel) "aj" = ( -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "ak" = ( -/obj/item/ore/slag, -/turf/simulated/floor/wood, +/obj/item/stack/material/ore/slag, +/turf/floor/laminate, /area/icarus/vessel) "al" = ( -/obj/structure/flora/ausbushes/palebush, -/turf/simulated/floor/exoplanet/grass, +/obj/structure/flora/bush/palebush, +/turf/floor/grass/wild, /area/icarus/open) "am" = ( -/obj/structure/bed/chair/comfy/black, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/black, +/turf/floor/laminate, /area/icarus/vessel) "an" = ( -/obj/structure/bed/chair/comfy/captain, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/captain, +/turf/floor/laminate, /area/icarus/vessel) "ao" = ( -/obj/structure/bed/chair/comfy/black, -/obj/item/storage/secure/briefcase, -/turf/simulated/floor/wood, +/obj/structure/chair/comfy/black, +/obj/item/secure_storage/briefcase, +/turf/floor/laminate, /area/icarus/vessel) "ap" = ( /obj/random/trash, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aq" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/icarus/open) "ar" = ( /obj/structure/flora/tree/dead, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/icarus/open) "as" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/icarus/vessel) "at" = ( /obj/structure/closet/gmcloset, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "au" = ( -/obj/structure/table/woodentable, -/obj/item/flame/lighter/zippo/random, +/obj/structure/table/laminate, +/obj/item/flame/fuelled/lighter/zippo/random, /obj/random/smokes, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "av" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/turf/floor/laminate, /area/icarus/vessel) "aw" = ( /obj/machinery/papershredder, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "ax" = ( -/obj/item/ore/slag, -/turf/simulated/floor/exoplanet/grass, +/obj/item/stack/material/ore/slag, +/turf/floor/grass/wild, /area/icarus/open) "ay" = ( /obj/item/shreddedp, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "az" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/smokes, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aA" = ( /obj/machinery/photocopier, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aB" = ( -/obj/structure/bed/chair/comfy/black{ +/obj/structure/chair/comfy/black{ dir = 1 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aD" = ( -/obj/structure/table/woodentable, -/obj/item/storage/lunchbox/mars, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/lunchbox/mars, +/turf/floor/laminate, /area/icarus/vessel) "aE" = ( -/obj/structure/table/woodentable, -/obj/item/storage/photo_album, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/photo_album, +/turf/floor/laminate, /area/icarus/vessel) "aF" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/drinkbottle, /obj/random/drinkbottle, /obj/random/snack, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aG" = ( /obj/machinery/light, -/obj/structure/filingcabinet/filingcabinet, -/turf/simulated/floor/wood, +/obj/structure/filing_cabinet/tall, +/turf/floor/laminate, /area/icarus/vessel) "aH" = ( -/obj/structure/filingcabinet/filingcabinet, -/turf/simulated/floor/wood, +/obj/structure/filing_cabinet/tall, +/turf/floor/laminate, /area/icarus/vessel) "aI" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -144,29 +144,29 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aK" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aL" = ( -/obj/structure/table/woodentable, -/obj/item/storage/fancy/cigar, -/turf/simulated/floor/wood, +/obj/structure/table/laminate, +/obj/item/box/fancy/cigar, +/turf/floor/laminate, /area/icarus/vessel) "aM" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/wood, +/turf/floor/laminate, /area/icarus/vessel) "aN" = ( /obj/structure/ladder, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aO" = ( /obj/structure/sign/directions/bridge{ @@ -174,31 +174,31 @@ pixel_y = 30; pixel_z = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aP" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aQ" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aR" = ( -/obj/structure/sign/icarus/solgov{ +/obj/structure/sign/solgov{ pixel_y = 30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aS" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aT" = ( /obj/random/obstruction, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aU" = ( /obj/structure/sign/directions/security{ @@ -206,107 +206,104 @@ pixel_y = 30; pixel_z = -6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aV" = ( /obj/structure/reagent_dispensers/watertank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "aW" = ( /obj/structure/janitorialcart, /obj/item/mop, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "aX" = ( -/turf/simulated/wall, +/turf/wall, /area/icarus/vessel) "aY" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "aZ" = ( /obj/random/obstruction, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "ba" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bb" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "bc" = ( /obj/random/trash, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/icarus/vessel) "bd" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/icarus/vessel) "be" = ( /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bf" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bg" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bh" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/icarus/vessel) "bi" = ( /obj/structure/closet/l3closet/janitor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bj" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bk" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bl" = ( /obj/random/closet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bm" = ( /obj/structure/closet, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bn" = ( /obj/structure/noticeboard{ - pixel_y = -25 + default_pixel_y = -25 }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bo" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -315,48 +312,48 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bp" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bq" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "br" = ( -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/icarus/vessel) "bs" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/tiled/freezer, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/tiled/freezer, /area/icarus/vessel) "bt" = ( /obj/structure/table/marble, /obj/random/plushie/large, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/icarus/vessel) "bu" = ( /obj/machinery/door/firedoor, -/obj/structure/sign/greencross{ +/obj/structure/sign/department/cross/green{ pixel_x = -30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bv" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bw" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/freezer, +/turf/floor/tiled/freezer, /area/icarus/vessel) "bx" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "by" = ( /obj/machinery/light{ @@ -364,27 +361,24 @@ }, /obj/structure/table/steel, /obj/item/folder/cyan, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bz" = ( /obj/structure/bed/roller, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bA" = ( /obj/machinery/alarm{ alarm_id = "xenobio4_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/structure/bed/roller, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bB" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bC" = ( /obj/structure/hygiene/toilet{ @@ -393,15 +387,15 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bD" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bE" = ( /obj/random/trash, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "bF" = ( /obj/structure/hygiene/toilet{ @@ -410,31 +404,28 @@ /obj/machinery/light/small{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "bH" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0 + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "bI" = ( /obj/structure/hygiene/shower{ - icon_state = "shower"; dir = 8 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "bJ" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bK" = ( /obj/structure/table/marble, @@ -442,7 +433,7 @@ /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bL" = ( /obj/effect/floor_decal/corner/grey/diagonal{ @@ -452,14 +443,14 @@ /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bM" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, /obj/machinery/cooker/fryer, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bN" = ( /obj/structure/table/marble, @@ -467,37 +458,37 @@ dir = 4 }, /obj/machinery/reagentgrinder/juicer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bO" = ( /obj/structure/table/steel, /obj/item/folder/cyan, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bP" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bQ" = ( /obj/structure/table/steel, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bR" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bS" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bT" = ( /obj/effect/wallframe_spawn/reinforced, @@ -505,80 +496,78 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bV" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bW" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bX" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "bY" = ( /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "bZ" = ( /obj/structure/hygiene/shower{ - dir = 4; - icon_state = "shower"; - pixel_x = 0 + dir = 4 }, /obj/random/trash, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "ca" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "cb" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "cc" = ( /obj/structure/table/marble, /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cd" = ( /obj/structure/table/marble, /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/item/chems/food/condiment/flour, -/turf/simulated/floor/tiled, +/obj/item/chems/condiment/flour, +/obj/item/chems/condiment/yeast, +/turf/floor/tiled, /area/icarus/vessel) "ce" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cf" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cg" = ( /obj/structure/table/steel, @@ -587,14 +576,14 @@ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ch" = ( /obj/item/stool, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ci" = ( /obj/item/stool, @@ -602,13 +591,13 @@ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cj" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ck" = ( /obj/effect/wallframe_spawn/reinforced, @@ -616,36 +605,35 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cl" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cm" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "cp" = ( /obj/machinery/light/small{ dir = 1 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "cq" = ( /obj/item/towel, /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "cr" = ( /obj/effect/floor_decal/corner/grey/diagonal{ @@ -655,522 +643,503 @@ alarm_id = "petrov1"; dir = 4; pixel_x = -25; - pixel_y = 0; rcon_setting = 3 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "cs" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) "ct" = ( /obj/structure/table/marble, /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/item/kitchen/rollingpin, -/turf/simulated/floor/tiled, +/obj/item/rollingpin, +/turf/floor/tiled, /area/icarus/vessel) "cu" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cv" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cw" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cx" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/sign/greencross{ +/obj/structure/sign/department/cross/green{ pixel_x = -30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cy" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cz" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/corpse/chef, +/obj/effect/decal/cleanable/dirt/visible, +/obj/abstract/landmark/corpse/chef, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "cA" = ( /obj/structure/table/marble, /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/item/plate, +/turf/floor/tiled, /area/icarus/vessel) "cB" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cC" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cD" = ( /obj/structure/closet, /obj/random/smokes, -/obj/item/clothing/under/icarus/ec_uniform, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cE" = ( /obj/structure/broken_cryo/icarus{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cF" = ( /obj/structure/closet, -/obj/item/clothing/under/harness, -/turf/simulated/floor/tiled, +/obj/item/clothing/shirt/harness, +/turf/floor/tiled, /area/icarus/vessel) "cG" = ( /obj/structure/closet/medical_wall{ pixel_y = 30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cH" = ( /obj/structure/broken_cryo/icarus{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cI" = ( /obj/structure/closet, /obj/random/smokes, /obj/item/key, -/turf/simulated/floor/tiled, -/area/icarus/vessel) -"cJ" = ( -/obj/structure/closet, -/obj/item/clothing/under/icarus/ec_uniform, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cK" = ( /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, /obj/machinery/door/window/southleft, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "cL" = ( /obj/structure/table/marble, /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/obj/item/trash/plate, -/obj/item/kitchen/utensil/fork, -/turf/simulated/floor/tiled, +/obj/item/plate, +/obj/item/utensil/fork, +/turf/floor/tiled, /area/icarus/vessel) "cM" = ( /obj/machinery/vending/dinnerware, /obj/effect/floor_decal/corner/grey/diagonal{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cN" = ( -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "cO" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/icarus/vessel) "cP" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/chems/pill/oxygen, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cR" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cS" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cT" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/accessory, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cU" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cV" = ( /obj/structure/bed/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cW" = ( /obj/effect/wallframe_spawn/reinforced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cX" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/icarus/open) "cY" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cZ" = ( /obj/machinery/sleeper{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "da" = ( /obj/structure/closet, -/obj/item/clothing/under/hazard, -/turf/simulated/floor/tiled, +/obj/item/clothing/jumpsuit/hazard, +/turf/floor/tiled, /area/icarus/vessel) "db" = ( /obj/structure/closet, /obj/random/drinkbottle, -/obj/item/clothing/under/icarus/ec_uniform, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dc" = ( /obj/structure/broken_cryo/icarus{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "dd" = ( -/obj/structure/table/standard, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/structure/table, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "de" = ( /obj/structure/closet, /obj/random/contraband, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "df" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dg" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dh" = ( /obj/structure/curtain/medical, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "di" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/chems/chem_disp_cartridge/hydrazine, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dj" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/towel, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dk" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dl" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "dm" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/plate, +/turf/floor/tiled, /area/icarus/open) "dn" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/powercell, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "do" = ( /obj/structure/closet, /obj/random/cash, /obj/random/cash, /obj/random/cash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dp" = ( /obj/structure/closet, /obj/random/glasses, -/obj/item/clothing/under/blazer, -/turf/simulated/floor/tiled, +/obj/item/clothing/shirt/button, +/obj/item/clothing/neck/tie/navy, +/obj/item/clothing/suit/jacket/blazer, +/turf/floor/tiled, /area/icarus/vessel) "dq" = ( -/obj/structure/table/standard, -/obj/item/knife/table, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/utensil/knife, +/turf/floor/tiled, /area/icarus/vessel) "dr" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/wall, +/obj/effect/decal/cleanable/dirt/visible, +/turf/wall, /area/icarus/vessel) "ds" = ( -/obj/effect/landmark/corpse/doctor, +/obj/abstract/landmark/corpse/doctor, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dt" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "du" = ( -/obj/structure/table/standard, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "dv" = ( -/obj/structure/table/standard, -/obj/item/trash/plate, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/plate, +/turf/floor/tiled, /area/icarus/vessel) "dw" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dx" = ( /obj/structure/closet, /obj/random/shoes, -/obj/item/clothing/under/icarus/ec_uniform, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dy" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/clothing, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dz" = ( /obj/machinery/bodyscanner{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dA" = ( /obj/machinery/body_scanconsole{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dB" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "dC" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/random/accessory, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dD" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) -"dE" = ( -/obj/structure/closet, -/obj/random/shoes, -/turf/simulated/floor/tiled, -/area/icarus/vessel) "dF" = ( /obj/structure/closet, /obj/random/action_figure, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dG" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dH" = ( /obj/structure/closet, /obj/random/plushie/large, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dI" = ( -/obj/structure/table/standard, -/obj/item/chems/food/drinks/cans/cola, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/chems/drinks/cans/cola, +/turf/floor/tiled, /area/icarus/vessel) "dJ" = ( /obj/structure/curtain/medical, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dK" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dL" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dN" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dO" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dP" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/open) "dQ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/light{ dir = 1 }, /obj/item/surgicaldrill, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/open) "dR" = ( -/obj/structure/table/standard, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/structure/table, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/open) "dS" = ( -/turf/simulated/wall, +/turf/wall, /area/icarus/open) "dT" = ( /obj/structure/closet/emcloset, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dU" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "dV" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dW" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, /area/icarus/open) "dX" = ( /obj/structure/reagent_dispensers/water_cooler, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1179,7 +1148,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dZ" = ( /obj/machinery/door/airlock, @@ -1190,7 +1159,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "ea" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1199,634 +1168,445 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "eb" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ec" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ed" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "ee" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "ef" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/icarus/open) "eg" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/icarus/open) "eh" = ( /obj/random/tank, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/open) "ei" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "ej" = ( /obj/random/trash, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "ek" = ( /obj/structure/curtain/open/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "el" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "em" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/icarus/open) "en" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "eo" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/open) "ep" = ( -/obj/structure/filingcabinet/filingcabinet, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/structure/filing_cabinet/tall, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "eq" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating/airless/broken, /area/icarus/open) "er" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "es" = ( /obj/structure/bed/padded, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "et" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "eu" = ( /obj/item/clothing/mask/smokable/cigarette/killthroat, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "ev" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "ew" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/clothing/mask/breath/emergency, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "ex" = ( -/obj/structure/table/standard, -/obj/item/storage/firstaid/empty, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/firstaid/empty, +/turf/floor/tiled, /area/icarus/open) "ey" = ( -/obj/structure/filingcabinet/filingcabinet, -/turf/simulated/floor/tiled, +/obj/structure/filing_cabinet/tall, +/turf/floor/tiled, /area/icarus/open) "ez" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating/airless/broken, /area/icarus/open) "eA" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/icarus/open) "eB" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/scalpel, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eC" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "eD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/bedsheet/orange, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eE" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/icarus/open) "eF" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/grass, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/grass/wild, /area/icarus/open) "eG" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/item/clothing/mask/surgical, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eH" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "eI" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/plate, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/plate, +/turf/unsimulated/floor/sand, /area/icarus/open) "eJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/knife/table, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/utensil/knife, +/turf/unsimulated/floor/sand, /area/icarus/open) "eK" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/structure/bed/padded, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eL" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/snack, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eM" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "eN" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/trash/plate, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/plate, +/turf/unsimulated/floor/sand, /area/icarus/open) "eO" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/structure/bed/chair{ +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/chair{ dir = 1 }, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eP" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/ash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eQ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "eR" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "eS" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "eT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/ash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eU" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "eV" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "eW" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/snack, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eX" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/ash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "eZ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "fa" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/pill_bottle/antibiotics, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/pill_bottle/antibiotics, +/turf/unsimulated/floor/sand, /area/icarus/open) "fb" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fc" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/bag/trash, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/bag/trash, +/turf/unsimulated/floor/sand, /area/icarus/open) "fd" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fe" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "ff" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "fg" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "fh" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/chems/food/drinks/cans/waterbottle, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/chems/drinks/cans/waterbottle, +/turf/unsimulated/floor/sand, /area/icarus/open) "fi" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "fj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "fk" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/ash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fl" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "fm" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fn" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/ash, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fo" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/material, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fp" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/stack/material/rods, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/rods/mapped/steel, +/turf/unsimulated/floor/sand, /area/icarus/open) "fq" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/ash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fr" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/material, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "fs" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "ft" = ( /obj/effect/icarus/irradiate, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "fv" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating, /area/icarus/open) "fw" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/plating/airless/broken, /area/icarus/open) "fx" = ( /obj/structure/table/steel, /obj/random/toolbox, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "fy" = ( /obj/structure/table/steel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "fz" = ( -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/vessel) "fA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/vessel) "fB" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/icarus/vessel) "fC" = ( /obj/structure/table/steel, /obj/item/tank/air, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "fD" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "fE" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/vessel) "fF" = ( /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fG" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/vessel) "fH" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/vessel) "fI" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fJ" = ( /obj/structure/closet/crate/trashcart, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fK" = ( /obj/structure/closet/crate/trashcart, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fL" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fM" = ( /obj/structure/table/steel, /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fN" = ( /obj/structure/table/steel, /obj/item/marshalling_wand, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fO" = ( /obj/structure/table/steel, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fP" = ( /obj/structure/table/steel, /obj/random/toolbox, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fQ" = ( /obj/structure/table/steel, /obj/random/technology_scanner, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fR" = ( /obj/structure/table/steel, @@ -1834,257 +1614,252 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fS" = ( -/obj/vehicle/train/cargo/engine, -/turf/simulated/floor/plating, +/obj/vehicle/train/engine, +/turf/floor/plating, /area/icarus/vessel) "fT" = ( /obj/structure/reagent_dispensers/watertank, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fU" = ( /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fV" = ( /obj/machinery/door/blast/regular{ dir = 4 }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fW" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fX" = ( /obj/effect/floor_decal/industrial/warning{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fY" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/closet/crate/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fZ" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ga" = ( /obj/effect/floor_decal/industrial/warning{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gb" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gc" = ( -/obj/structure/closet/crate/freezer/rations, -/turf/simulated/floor/plating, +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating, /area/icarus/vessel) "gd" = ( /obj/random/plushie/large, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ge" = ( /obj/structure/closet/crate/solar_assembly, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gf" = ( /obj/random/junk, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gg" = ( /obj/structure/closet/crate/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gh" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gi" = ( /obj/random/tank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/vessel) "gk" = ( /obj/effect/floor_decal/industrial/warning{ dir = 4 }, /obj/structure/closet/crate/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gl" = ( /obj/random/firstaid, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gm" = ( /obj/structure/closet/crate/large, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gn" = ( /obj/structure/ore_box, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "go" = ( -/obj/structure/target_stake, -/turf/simulated/floor/plating, +/obj/structure/target_stake/steel, +/turf/floor/plating, /area/icarus/vessel) "gp" = ( -/obj/vehicle/train/cargo/trolley, -/turf/simulated/floor/plating, +/obj/vehicle/train/trolley, +/turf/floor/plating, /area/icarus/vessel) "gq" = ( /obj/random/toolbox, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gr" = ( /obj/structure/closet/crate/medical, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gs" = ( /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gt" = ( /obj/structure/closet/crate/hydroponics, /obj/effect/floor_decal/industrial/warning{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gu" = ( /obj/machinery/door/blast/regular/open{ dir = 4; - icon_state = "pdoor0"; id_tag = "prototype_chamber_blast" }, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gv" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gw" = ( /obj/structure/closet/crate/large, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gx" = ( /obj/structure/plushie/carp, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/icarus/vessel) "gz" = ( /obj/structure/closet/crate/radiation_gear, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gA" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gB" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gC" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gD" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/closet/crate/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gE" = ( /obj/effect/floor_decal/industrial/warning{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gF" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 10 + dir = 10; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gG" = ( /obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gH" = ( /obj/effect/floor_decal/industrial/warning, /obj/structure/closet/crate/plastic, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gI" = ( /obj/effect/floor_decal/industrial/warning, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gJ" = ( /obj/effect/floor_decal/industrial/warning{ dir = 6 }, /obj/random/toolbox, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gK" = ( /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gL" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gM" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -2093,75 +1868,76 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gN" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gO" = ( /obj/machinery/light/small, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gP" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gQ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, /area/icarus/open) "gR" = ( /obj/machinery/atmospherics/portables_connector, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gS" = ( /obj/machinery/atmospherics/unary/tank/oxygen, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "gT" = ( /obj/machinery/atmospherics/unary/tank/oxygen, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gU" = ( /obj/machinery/atmospherics/portables_connector, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gV" = ( /obj/machinery/atmospherics/unary/tank/nitrogen, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gW" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gX" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gY" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -2170,83 +1946,80 @@ /obj/structure/sign/warning/nosmoking_2{ pixel_y = 30 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "gZ" = ( /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ha" = ( /obj/machinery/portable_atmospherics/canister/hydrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hb" = ( /obj/machinery/atmospherics/unary/tank/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hc" = ( /obj/machinery/atmospherics/unary/tank/hydrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hd" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "he" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "hf" = ( /obj/machinery/atmospherics/pipe/manifold/visible/green{ - icon_state = "map"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hg" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hh" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hi" = ( /obj/machinery/atmospherics/pipe/manifold/visible/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hj" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hk" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hl" = ( -/obj/effect/landmark/corpse/engineer, +/obj/abstract/landmark/corpse/engineer, /obj/effect/decal/cleanable/blood/splatter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hm" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hn" = ( /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ho" = ( /obj/structure/window/borosilicate_reinforced{ @@ -2264,10 +2037,9 @@ }, /obj/structure/grille, /obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" + dir = 4 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/vessel) "hp" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -2280,23 +2052,22 @@ /obj/machinery/sparker{ pixel_y = 25 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/vessel) "hq" = ( -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/vessel) "hr" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hs" = ( /obj/machinery/atmospherics/pipe/simple/visible/green{ - icon_state = "intact"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ht" = ( /obj/machinery/atmospherics/omni/mixer{ @@ -2305,53 +2076,49 @@ tag_east_con = null; tag_north = 1; tag_north_con = 0.79; - tag_south = 0; tag_south_con = null; tag_west = 1; - tag_west_con = 0.21; - use_power = 1 + tag_west_con = 0.21 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hu" = ( /obj/machinery/atmospherics/binary/pump{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/universal{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hx" = ( /obj/machinery/portable_atmospherics/powered/scrubber, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hy" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hz" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hA" = ( /obj/machinery/atmospherics/pipe/simple/visible/blue{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hB" = ( /obj/structure/window/borosilicate_reinforced{ @@ -2368,7 +2135,7 @@ /obj/machinery/atmospherics/pipe/simple/visible/blue{ dir = 4 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/vessel) "hC" = ( /obj/machinery/atmospherics/unary/outlet_injector{ @@ -2378,25 +2145,25 @@ pixel_y = 1; use_power = 1 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/vessel) "hD" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "hE" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hF" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hG" = ( /obj/structure/window/borosilicate_reinforced{ @@ -2411,46 +2178,48 @@ dir = 4; id_tag = "d1starboardnacelle" }, -/turf/simulated/floor/reinforced, +/obj/machinery/atmospherics/pipe/simple/visible/fuel{ + dir = 4 + }, +/turf/floor/reinforced, /area/icarus/vessel) "hH" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ dir = 8; - id_tag = "vox_west_vent" + id_tag = "raider_west_vent" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/vessel) "hI" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "hJ" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hK" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hL" = ( /obj/structure/sign/warning/caution{ - pixel_x = 0; pixel_y = -30 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hM" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hN" = ( /obj/machinery/portable_atmospherics/powered/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hO" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/visible/fuel, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hP" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -2459,14 +2228,14 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "hQ" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, /obj/machinery/door/airlock, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hR" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -2475,11 +2244,11 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hS" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/fuel, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hT" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -2491,7 +2260,7 @@ /obj/structure/sign/warning/nosmoking_2{ pixel_y = 30 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hU" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -2500,7 +2269,7 @@ /obj/structure/sign/warning/nosmoking_2{ pixel_y = 30 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hV" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -2509,191 +2278,164 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "hW" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "hX" = ( /obj/structure/grille, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "hY" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "hZ" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ia" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 10 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ib" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "ic" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "id" = ( -/obj/machinery/atmospherics/unary/engine, -/turf/simulated/wall/r_wall, +/obj/machinery/atmospherics/unary/engine{ + dir = 1 + }, +/turf/wall/r_wall, /area/icarus/open) "ie" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "if" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "ig" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "ih" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/vehicle/train/cargo/trolley, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/vehicle/train/trolley, +/turf/unsimulated/floor/sand, /area/icarus/open) "ii" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "ij" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/engine{ anchored = 0 }, -/turf/unsimulated/beach/sand, +/turf/unsimulated/floor/sand, /area/icarus/open) "ik" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "il" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/sand, /area/icarus/open) "im" = ( /obj/effect/decal/cleanable/ash, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/item/ore/slag, -/turf/unsimulated/beach/sand, +/obj/effect/decal/cleanable/dirt/visible, +/obj/item/stack/material/ore/slag, +/turf/unsimulated/floor/sand, /area/icarus/open) "io" = ( /obj/effect/decal/cleanable/ash, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/icarus/open) "ip" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/exoplanet/grass, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/grass/wild, /area/icarus/open) "jb" = ( /obj/effect/shuttle_landmark/nav_icarus/nav1, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/icarus/open) "kb" = ( /obj/effect/shuttle_landmark/nav_icarus/nav2, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/icarus/open) "lb" = ( /obj/effect/shuttle_landmark/nav_icarus/nav3, -/turf/simulated/floor/exoplanet/grass, +/turf/floor/grass/wild, /area/icarus/open) "mb" = ( /obj/structure/hygiene/sink{ dir = 1; pixel_y = 16 }, -/obj/item/storage/mirror{ - pixel_x = 0; +/obj/structure/mirror{ pixel_y = 30 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "nb" = ( -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = 30 }, /obj/structure/hygiene/sink{ dir = 4; - icon_state = "sink"; - pixel_x = 11; - pixel_y = 0 + pixel_x = 11 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/icarus/vessel) "ob" = ( -/obj/item/storage/mirror{ +/obj/structure/mirror{ pixel_x = -30 }, /obj/structure/hygiene/sink{ - icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2 }, /obj/random/soap, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled/white, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled/white, /area/icarus/vessel) +"rK" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, +/area/icarus/open) +"sK" = ( +/obj/machinery/atmospherics/pipe/simple/visible/fuel{ + dir = 4 + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating, +/area/icarus/open) (1,1,1) = {" aa @@ -22041,7 +21783,7 @@ en en ei et -hD +sK eA hX et @@ -22157,7 +21899,7 @@ dD dK dD dD -dD +rK ee ei ei @@ -22240,7 +21982,7 @@ aq gR hd eA -hD +sK et aq hD @@ -22759,7 +22501,7 @@ do aP dx bf -dE +dx as dU dU @@ -24571,13 +24313,13 @@ bX as cI aP -cJ +bm aP -cJ +bm aP bm aP -cJ +bm as cf ej @@ -25175,13 +24917,13 @@ bI bI cq as -cJ +bm bg de df cD aP -cJ +bm bg dH as @@ -25793,7 +25535,7 @@ cf dL dY dD -dD +rK eA ei ei diff --git a/mods/government/away_sites/icarus/icarus-2.dmm b/mods/content/government/away_sites/icarus/icarus-2.dmm similarity index 91% rename from mods/government/away_sites/icarus/icarus-2.dmm rename to mods/content/government/away_sites/icarus/icarus-2.dmm index 7a787c19f499..df9445d7b104 100644 --- a/mods/government/away_sites/icarus/icarus-2.dmm +++ b/mods/content/government/away_sites/icarus/icarus-2.dmm @@ -6,264 +6,258 @@ /turf/unsimulated/mask, /area/mine/unexplored) "ac" = ( -/turf/simulated/open, +/turf/open, /area/icarus/open) "ad" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/icarus/open) "ae" = ( -/turf/simulated/wall/natural, +/turf/wall/natural, /area/icarus/vessel) "af" = ( /obj/structure/grille, /obj/structure/wall_frame, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ag" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ah" = ( -/obj/item/ore/slag, -/turf/simulated/floor/plating, +/obj/item/stack/material/ore/slag, +/turf/floor/plating, /area/icarus/vessel) "ai" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "aj" = ( /obj/machinery/computer/modular, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ak" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "al" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "am" = ( -/obj/item/ore/slag, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/item/stack/material/ore/slag, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "an" = ( /obj/structure/table/steel_reinforced, /obj/random/firstaid, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ao" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/icarus/open) "ap" = ( -/turf/simulated/wall/r_wall, +/turf/wall/r_wall, /area/icarus/vessel) "aq" = ( /obj/structure/table/steel_reinforced, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ar" = ( /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "as" = ( /obj/structure/table/steel_reinforced, /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "at" = ( /obj/structure/table/steel_reinforced, /obj/random/handgun, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "au" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "av" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "aw" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ax" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ay" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "az" = ( /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "aA" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/obj/effect/landmark/corpse/bridgeofficer, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/corpse/bridgeofficer, +/turf/floor/tiled, /area/icarus/vessel) "aB" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/effect/overmap/visitable/sector/icarus, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aD" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aE" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/fancy/cigarettes/killthroat, -/turf/simulated/floor/tiled, +/obj/item/box/fancy/cigarettes/killthroat, +/turf/floor/tiled, /area/icarus/vessel) "aF" = ( /obj/effect/floor_decal/plaque, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aG" = ( /obj/random/loot, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "aH" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/box/survival, -/turf/simulated/floor/tiled, +/obj/item/box/survival, +/turf/floor/tiled, /area/icarus/vessel) "aI" = ( /obj/structure/ladder, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aJ" = ( /obj/structure/table/steel_reinforced, /obj/random/tool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aK" = ( /obj/machinery/computer/modular, /obj/item/disk/icarus, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aL" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/box/trackimp, -/turf/simulated/floor/tiled, +/obj/item/box/trackimp, +/turf/floor/tiled, /area/icarus/vessel) "aM" = ( -/obj/structure/table/standard, -/turf/simulated/floor/tiled, +/obj/structure/table, +/turf/floor/tiled, /area/icarus/vessel) "aN" = ( /obj/machinery/computer/modular, /obj/item/paper/icarus/log, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aO" = ( -/obj/structure/bed/chair/comfy/captain{ - color = "#666666"; +/obj/structure/chair/comfy/captain{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aP" = ( /obj/structure/table/steel_reinforced, /obj/item/flashlight/lamp, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aQ" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/flashlight/flare, /obj/item/flashlight/flare, /obj/item/flashlight/flare, /obj/item/flashlight/flare, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/icarus/vessel) "aR" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aS" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aT" = ( -/obj/structure/sign/icarus/solgov{ +/obj/structure/sign/solgov{ pixel_x = 30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aU" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/box/PDAs, +/obj/item/box/PDAs, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aV" = ( /obj/structure/table/steel_reinforced, /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/obj/item/storage/toolbox/emergency, -/turf/simulated/floor/tiled, +/obj/item/toolbox/emergency, +/turf/floor/tiled, /area/icarus/vessel) "aW" = ( -/obj/structure/sign/icarus/solgov{ +/obj/structure/sign/solgov{ pixel_x = -30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aX" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "aY" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/airlock_brace, /obj/item/airlock_brace, /obj/item/airlock_brace, /obj/item/crowbar/brace_jack, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/icarus/vessel) "aZ" = ( /obj/structure/window/reinforced{ dir = 4 }, -/obj/machinery/telecomms/server, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/icarus/vessel) "ba" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -272,7 +266,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -281,7 +275,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bc" = ( /obj/machinery/door/airlock, @@ -292,115 +286,109 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "be" = ( /obj/machinery/light, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bf" = ( -/obj/structure/filingcabinet, -/turf/simulated/floor/tiled, +/obj/structure/filing_cabinet, +/turf/floor/tiled, /area/icarus/vessel) "bg" = ( /obj/machinery/light, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bh" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bi" = ( -/obj/structure/table/rack, -/obj/item/storage/box/teargas{ +/obj/structure/rack, +/obj/item/box/teargas{ pixel_x = 3; pixel_y = 2 }, -/obj/item/storage/box/handcuffs, -/obj/item/storage/box/flashbangs{ +/obj/item/box/handcuffs, +/obj/item/box/flashbangs{ pixel_x = -2; pixel_y = -2 }, -/turf/simulated/floor/tiled/dark, +/turf/floor/tiled/dark, /area/icarus/vessel) "bj" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/shotgun/pump, /obj/item/gun/projectile/shotgun/pump, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bk" = ( -/obj/machinery/telecomms/server/presets/common, /obj/effect/floor_decal/industrial/outline/grey, -/turf/simulated/floor/bluegrid, -/area/icarus/vessel) -"bl" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/icarus/vessel) "bm" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bn" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bo" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bp" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bq" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/baton, /obj/item/baton, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "br" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/handcuffs, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bs" = ( -/obj/machinery/telecomms/server, -/turf/simulated/floor/bluegrid, +/obj/machinery/network/telecomms_hub{ + initial_network_id = "daedalus" + }, +/turf/floor/bluegrid, /area/icarus/vessel) "bt" = ( -/turf/simulated/floor/bluegrid, +/turf/floor/bluegrid, /area/icarus/vessel) "bu" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bv" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -409,7 +397,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bw" = ( /obj/machinery/door/airlock, @@ -419,12 +407,12 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bx" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "by" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -433,152 +421,152 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bz" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bA" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bB" = ( /obj/machinery/papershredder, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bC" = ( /obj/machinery/photocopier, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bD" = ( -/obj/structure/filingcabinet, +/obj/structure/filing_cabinet, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bE" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bF" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bG" = ( /obj/structure/closet, -/obj/item/chems/food/drinks/bottle/tequilla, -/obj/item/chems/food/drinks/bottle/wine, +/obj/item/chems/drinks/bottle/tequila, +/obj/item/chems/drinks/bottle/wine, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1; level = 2 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bH" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bI" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bJ" = ( -/obj/structure/table/woodentable, -/turf/simulated/floor/tiled, +/obj/structure/table/laminate, +/turf/floor/tiled, /area/icarus/vessel) "bK" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bL" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bM" = ( /obj/structure/table/steel_reinforced, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bN" = ( /obj/structure/table/steel_reinforced, /obj/item/handcuffs, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bO" = ( /obj/structure/table/steel_reinforced, /obj/item/harpoon, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bP" = ( /obj/machinery/suit_cycler, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "bR" = ( /obj/structure/table/steel, /obj/random/tool, /obj/random/tool, /obj/random/tool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "bS" = ( /obj/machinery/computer/modular, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bT" = ( /obj/structure/closet, -/obj/item/storage/backpack/industrial, -/obj/item/storage/toolbox/electrical, -/turf/simulated/floor/tiled, +/obj/item/backpack/industrial, +/obj/item/toolbox/electrical, +/turf/floor/tiled, /area/icarus/vessel) "bU" = ( /obj/structure/closet, /obj/item/clothing/head/helmet/space/rig/industrial, /obj/item/clothing/suit/space/emergency, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bV" = ( /obj/structure/closet, -/obj/item/storage/backpack/industrial, -/obj/item/storage/toolbox/mechanical, +/obj/item/backpack/industrial, +/obj/item/toolbox/mechanical, /obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bW" = ( /obj/structure/closet, /obj/item/clothing/suit/radiation, /obj/item/clothing/suit/radiation, /obj/machinery/atmospherics/unary/vent_pump/on, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bX" = ( -/turf/simulated/wall, +/turf/wall, /area/icarus/vessel) "bY" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "bZ" = ( /obj/structure/closet, -/obj/item/chems/food/drinks/flask/shiny, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/flask/shiny, +/turf/floor/tiled, /area/icarus/vessel) "ca" = ( -/obj/structure/bed/chair/comfy/brown, -/turf/simulated/floor/tiled, +/obj/structure/chair/comfy/brown, +/turf/floor/tiled, /area/icarus/vessel) "cb" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -587,40 +575,40 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cc" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cd" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ce" = ( /obj/structure/table/steel, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cf" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/obj/effect/landmark/corpse/engineer, +/obj/abstract/landmark/corpse/engineer, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cg" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ch" = ( /obj/random/trash, @@ -630,67 +618,65 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ci" = ( /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cj" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ck" = ( /obj/structure/closet, -/obj/item/chems/food/drinks/golden_cup, -/turf/simulated/floor/tiled, +/obj/item/chems/drinks/golden_cup, +/turf/floor/tiled, /area/icarus/vessel) "cl" = ( -/obj/structure/table/woodentable, -/obj/item/storage/backpack/captain, +/obj/structure/table/laminate, +/obj/item/backpack/captain, /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cm" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/paper/icarus/crew_roster, /obj/item/folder/blue, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cn" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "co" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cp" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cq" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -699,7 +685,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cr" = ( /obj/machinery/light{ @@ -708,120 +694,118 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cs" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ct" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cu" = ( /obj/structure/table/steel_reinforced, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cv" = ( /obj/structure/table/steel, /obj/random/tank, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cw" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cx" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cy" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cz" = ( /obj/structure/bed, /obj/item/bedsheet/captain, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cA" = ( -/obj/structure/table/woodentable, -/obj/item/chems/food/drinks/bottle/whiskey, -/turf/simulated/floor/tiled, +/obj/structure/table/laminate, +/obj/item/chems/drinks/bottle/whiskey, +/turf/floor/tiled, /area/icarus/vessel) "cB" = ( -/obj/structure/sign/double/icarus/solgovflag/left{ +/obj/structure/sign/double/flag/solgov/left{ pixel_y = -32 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cC" = ( -/obj/structure/sign/double/icarus/solgovflag/right{ +/obj/structure/sign/double/flag/solgov/right{ pixel_y = -32 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cD" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/toy/ship_model, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cE" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/random/action_figure, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cF" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cG" = ( /obj/item/stool, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 5 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cH" = ( /obj/item/stool, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cI" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cJ" = ( /obj/structure/table/steel_reinforced, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cK" = ( /obj/machinery/alarm{ @@ -829,53 +813,52 @@ pixel_y = -25; req_access = newlist() }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cL" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "cM" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cN" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cO" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cP" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cQ" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cR" = ( /obj/structure/lattice, -/turf/simulated/open, +/turf/open, /area/icarus/open) "cS" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tech_supply, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "cT" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -884,14 +867,11 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cU" = ( /obj/machinery/alarm{ alarm_id = "xenobio4_alarm"; - dir = 2; - icon_state = "alarm0"; - pixel_x = 0; pixel_y = 24 }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -901,7 +881,7 @@ dir = 10 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cV" = ( /obj/machinery/computer/modular, @@ -912,75 +892,74 @@ dir = 8 }, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cW" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/disk/secret_project/science, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cX" = ( /obj/effect/wallframe_spawn/reinforced, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cY" = ( /obj/machinery/light{ dir = 1 }, -/obj/structure/table/standard, +/obj/structure/table, /obj/structure/window/reinforced{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "cZ" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/machinery/reagentgrinder/juicer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "da" = ( /obj/machinery/light{ dir = 1 }, -/obj/structure/table/standard, -/obj/item/storage/box/monkeycubes, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/box/animal_cubes/monkeys, +/turf/floor/tiled, /area/icarus/vessel) "db" = ( -/obj/structure/table/standard, -/obj/item/storage/box/beakers, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/box/beakers, +/turf/floor/tiled, /area/icarus/vessel) "dc" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dd" = ( /obj/structure/bed, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "de" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "df" = ( -/obj/machinery/door/airlock, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/icarus/vessel) +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, +/area/icarus/open) "dg" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 1 @@ -988,7 +967,7 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dh" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -997,7 +976,7 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "di" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -1006,39 +985,38 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dj" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dk" = ( -/obj/structure/sign/science_2{ +/obj/structure/sign/department/science_2{ pixel_x = 30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dl" = ( -/obj/structure/bed/chair/comfy/brown{ +/obj/structure/chair/comfy/brown{ dir = 4 }, -/obj/effect/landmark/corpse/scientist, +/obj/abstract/landmark/corpse/scientist, /obj/effect/decal/cleanable/blood, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dm" = ( /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dn" = ( /obj/machinery/door/window/eastleft, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "do" = ( /obj/machinery/atmospherics/unary/vent_pump/on{ @@ -1047,38 +1025,37 @@ /obj/machinery/alarm{ alarm_id = "xenobio3_alarm"; dir = 8; - icon_state = "alarm0"; pixel_x = 24 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dp" = ( /obj/structure/closet, /obj/item/gun/projectile/shotgun/pump, /obj/item/chems/spray/pepper, -/obj/item/storage/box/handcuffs, +/obj/item/box/handcuffs, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dq" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dr" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "ds" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/random/tool, /obj/random/powercell, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dt" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -1087,95 +1064,94 @@ /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "du" = ( -/obj/structure/table/woodentable, +/obj/structure/table/laminate, /obj/item/flashlight/lamp, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dv" = ( /obj/structure/table/steel_reinforced, -/obj/item/storage/box/fingerprints, -/turf/simulated/floor/tiled, +/obj/item/box/fingerprints, +/turf/floor/tiled, /area/icarus/vessel) "dw" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dx" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dy" = ( /obj/random/loot, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dz" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/tiled, +/obj/structure/chair, +/turf/floor/tiled, /area/icarus/vessel) "dA" = ( /obj/structure/bed, /obj/item/trash/snack_bowl, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dB" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/vessel) "dC" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/structure/table/steel_reinforced, -/obj/item/storage/box/ammo/flashshells, -/turf/simulated/floor/tiled, +/obj/item/box/ammo/flashshells, +/turf/floor/tiled, /area/icarus/vessel) "dD" = ( /obj/random/trash, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 5 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dF" = ( /obj/structure/closet, -/obj/item/clothing/suit/storage/toggle/labcoat/blue, +/obj/item/clothing/suit/toggle/labcoat/blue, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dG" = ( /obj/structure/closet, -/obj/item/clothing/suit/storage/toggle/labcoat/blue, +/obj/item/clothing/suit/toggle/labcoat/blue, /obj/item/disk/survey, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dH" = ( -/obj/structure/table/standard, +/obj/structure/table, /obj/item/flashlight/lamp, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dI" = ( /obj/structure/table/steel_reinforced, /obj/item/chems/spray/pepper, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dJ" = ( /obj/machinery/alarm{ @@ -1186,23 +1162,22 @@ /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dK" = ( -/turf/simulated/wall, +/turf/wall, /area/icarus/open) "dL" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/random/trash, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dM" = ( /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 @@ -1210,145 +1185,128 @@ /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dN" = ( /obj/machinery/light{ - icon_state = "tube1"; - dir = 4 + dir = 4; + icon_state = "tube1" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dO" = ( /obj/machinery/destructive_analyzer, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dP" = ( -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "dQ" = ( /obj/random/trash, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "dR" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/icarus/open) "dS" = ( /obj/structure/bed, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dT" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9; - pixel_y = 0 + dir = 9 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dU" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dV" = ( /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dW" = ( /obj/machinery/door/window/eastleft, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dX" = ( -/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt/visible, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "dY" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "dZ" = ( /obj/effect/icarus/irradiate, -/turf/simulated/open, +/turf/open, /area/icarus/open) "ea" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless/broken, /area/icarus/open) "eb" = ( -/obj/item/clothing/ring/mariner, -/turf/simulated/floor/tiled, +/obj/item/clothing/gloves/ring/mariner, +/turf/floor/tiled, /area/icarus/open) "ec" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "ed" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "ee" = ( /obj/machinery/door/airlock, /obj/machinery/door/firedoor, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "ef" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/tiled, +/obj/effect/decal/cleanable/dirt/visible, +/turf/floor/tiled, /area/icarus/open) "eg" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "eh" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ei" = ( -/turf/simulated/floor/airless{ - icon_state = "dmg2" - }, +/turf/floor/plating/airless/broken, /area/icarus/vessel) "ej" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -1357,12 +1315,10 @@ /obj/structure/sign/warning/internals_required{ pixel_y = -30 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "ek" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ @@ -1371,519 +1327,420 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 9 }, -/turf/simulated/floor/tiled, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, /area/icarus/vessel) "el" = ( /obj/structure/sign/warning/airlock{ pixel_y = -30 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "em" = ( /obj/random/material, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "en" = ( /obj/machinery/door/airlock, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/firedoor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eo" = ( /obj/structure/grille, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/open) "ep" = ( -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/open) "eq" = ( -/turf/simulated/shuttle/wall, +/turf/wall/shuttle{ + unique_merge_identifier = "icarus" + }, /area/icarus/open) "er" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_straight"; - dir = 4 - }, -/area/icarus/vessel) -"es" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_t"; - dir = 1 +/turf/wall/shuttle{ + unique_merge_identifier = "icarus" }, /area/icarus/vessel) "et" = ( /obj/structure/shuttle/window, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eu" = ( /obj/structure/shuttle/engine/propulsion{ dir = 4 }, -/turf/simulated/shuttle/wall, +/turf/wall/shuttle{ + unique_merge_identifier = "icarus" + }, /area/icarus/open) "ev" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ew" = ( -/obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion_l"; +/obj/structure/shuttle/engine/propulsion/left{ dir = 8 }, -/turf/simulated/shuttle/wall, +/turf/wall/shuttle{ + unique_merge_identifier = "icarus" + }, /area/icarus/vessel) "ex" = ( /obj/structure/shuttle/window, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/open) "ey" = ( /obj/structure/table/reinforced, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/open) "ez" = ( /obj/machinery/light/small{ - dir = 4; - pixel_y = 0 - }, -/turf/simulated/floor/shuttle/white, -/area/icarus/vessel) -"eA" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall"; - dir = 1 + dir = 4 }, +/turf/floor/shuttle/white, /area/icarus/vessel) "eB" = ( -/obj/structure/bed/chair, -/turf/simulated/floor/shuttle/white, +/obj/structure/chair, +/turf/floor/shuttle/white, /area/icarus/vessel) "eC" = ( -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eD" = ( -/obj/structure/table/rack, -/turf/simulated/floor/shuttle/white, +/obj/structure/rack, +/turf/floor/shuttle/white, /area/icarus/vessel) "eE" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/mask/breath/emergency, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eF" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/small{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eG" = ( /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eH" = ( /obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eI" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eJ" = ( /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/open) "eK" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 8 }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eL" = ( /obj/machinery/door/airlock, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eM" = ( /obj/machinery/door/airlock/external, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) "eN" = ( /obj/machinery/door/airlock/external, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eO" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 4; id_tag = "bridgeport_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eP" = ( /obj/machinery/door/airlock/external, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eQ" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eR" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ dir = 8; id_tag = "ninja_shuttle_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "eS" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 4 }, -/turf/simulated/floor/shuttle/white, -/area/icarus/vessel) -"eT" = ( -/turf/simulated/shuttle/wall{ - dir = 2; - icon_state = "swall" - }, +/turf/floor/shuttle/white, /area/icarus/vessel) "eU" = ( -/obj/structure/bed/chair{ +/obj/structure/chair{ dir = 1 }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/open) "eV" = ( /obj/machinery/light/small, -/turf/simulated/floor/shuttle/white, -/area/icarus/vessel) -"eW" = ( -/turf/simulated/shuttle/wall, +/turf/floor/shuttle/white, /area/icarus/vessel) "eX" = ( /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/vessel) -"eY" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_straight"; - dir = 4 - }, -/area/icarus/open) -"eZ" = ( -/turf/simulated/shuttle/wall{ - icon_state = "swall_t"; - dir = 2 - }, -/area/icarus/open) "fa" = ( /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fb" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fc" = ( -/obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion_l"; +/obj/structure/shuttle/engine/propulsion/left{ dir = 8 }, -/turf/simulated/shuttle/wall, +/turf/wall/shuttle{ + unique_merge_identifier = "icarus" + }, /area/icarus/open) "fd" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/machinery/power/solar, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/open) "fe" = ( /obj/machinery/power/solar_control, /obj/structure/cable/yellow{ - d2 = 4; icon_state = "0-4" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "ff" = ( /obj/machinery/power/terminal{ dir = 4 }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fg" = ( /obj/machinery/power/smes/buildable, /obj/structure/cable, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fh" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fi" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fj" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fk" = ( /obj/machinery/door/airlock/external, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fl" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/industrial/hatch/yellow, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fm" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fn" = ( /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fo" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow, /obj/machinery/power/solar, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/open) "fp" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fq" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ dir = 1; id_tag = "calypso_shuttle_pump" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "fr" = ( /obj/machinery/door/airlock/external, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fs" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "ft" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/effect/floor_decal/industrial/hatch/yellow, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fu" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fv" = ( /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fw" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable/yellow{ - d1 = 4; - d2 = 8; icon_state = "4-8" }, /obj/structure/cable/yellow{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/open) "fx" = ( /obj/effect/floor_decal/solarpanel, /obj/structure/cable/yellow, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/open) "fy" = ( /obj/machinery/power/tracker, /obj/structure/cable/yellow, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/icarus/open) "gb" = ( -/obj/effect/landmark/map_data{ +/obj/abstract/map_data{ height = 2 }, /turf/unsimulated/mineral, @@ -1892,40 +1749,46 @@ /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/shuttle/white, +/turf/floor/shuttle/white, /area/icarus/open) "le" = ( /obj/machinery/computer/modular{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "mg" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/open) "Bd" = ( /obj/structure/wall_frame, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) "Fo" = ( -/obj/item/ore/slag, +/obj/item/stack/material/ore/slag, /obj/structure/wall_frame, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/icarus/vessel) +"MC" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled, +/area/icarus/open) "RQ" = ( /obj/machinery/computer/modular{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) "Vb" = ( /obj/machinery/computer/modular{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/icarus/vessel) (1,1,1) = {" @@ -20452,7 +20315,7 @@ er ey eJ ey -eY +eq fd fi fo @@ -20565,7 +20428,7 @@ ao ao ap aZ -bl +aZ bt ap bU @@ -20654,7 +20517,7 @@ er ez eK eC -eY +eq fd fi fo @@ -20852,11 +20715,11 @@ ee bX bX ap -es -eA +er +er eL -eT -eZ +er +eq fd fi fo @@ -21390,7 +21253,7 @@ dw dU dw dw -dw +MC ac cR ac @@ -21664,7 +21527,7 @@ er eC eC eV -eY +eq fd fi fo @@ -21866,7 +21729,7 @@ er eD eC eC -eY +eq fd fi fo @@ -22068,7 +21931,7 @@ er eD eC eH -eY +eq fd fi fo @@ -22270,7 +22133,7 @@ er eE eC eG -eY +eq fd fi fo @@ -22469,9 +22332,9 @@ av ak ap eu -eA +er eM -eW +er eu ep fj @@ -24085,9 +23948,9 @@ ag ag ap ew -eA +er eM -eT +er fc ep fl @@ -24290,7 +24153,7 @@ er eG eC eD -eY +eq fd fm fo @@ -24492,7 +24355,7 @@ er eH eC eD -eY +eq fd fm fo @@ -24694,7 +24557,7 @@ er eC eC eE -eY +eq fd fm fo @@ -24896,7 +24759,7 @@ er eI eC eC -eY +eq fd fm fo @@ -25023,7 +24886,7 @@ bY bY dN dw -dU +df dR cR cR @@ -25700,11 +25563,11 @@ cL ag ag ap -es -eA +er +er eL -eT -eZ +er +eq fd fm fo @@ -25906,7 +25769,7 @@ er eC eS eX -eY +eq fd fm fo @@ -26108,7 +25971,7 @@ er ey kT ey -eY +eq fd fm fo @@ -26228,7 +26091,7 @@ ap cu cJ ap -df +bw ap ap ap diff --git a/mods/government/away_sites/icarus/icarus.dm b/mods/content/government/away_sites/icarus/icarus.dm similarity index 80% rename from mods/government/away_sites/icarus/icarus.dm rename to mods/content/government/away_sites/icarus/icarus.dm index 43f91964e8a9..5aa245d448bc 100644 --- a/mods/government/away_sites/icarus/icarus.dm +++ b/mods/content/government/away_sites/icarus/icarus.dm @@ -1,4 +1,5 @@ #include "../../_government.dme" +#include "../../../corporate/_corporate.dme" #include "icarus_areas.dm" /obj/effect/overmap/visitable/sector/icarus @@ -37,11 +38,11 @@ /datum/map_template/ruin/away_site/icarus name = "Fallen Icarus" - id = "awaysite_icarus" - description = "The crashlanding site of the SEV Icarus." + description = "The crash-landing site of the SEV Icarus." + prefix = "mods/content/government/away_sites/" suffixes = list("icarus/icarus-1.dmm", "icarus/icarus-2.dmm") cost = 2 - generate_mining_by_z = list(1, 2) + level_data_type = /datum/level_data/mining_level area_usage_test_exempted_root_areas = list(/area/icarus) area_coherency_test_exempt_areas = list(/area/icarus/vessel, /area/icarus/open) apc_test_exempt_areas = list( @@ -65,25 +66,23 @@ flags = SLANDMARK_FLAG_AUTOSET /obj/structure/broken_cryo/icarus - remains_type = /obj/item/icarus/dead_personnel + remains_type = /obj/item/dead_personnel -/obj/item/icarus/dead_personnel +/obj/item/dead_personnel name = "partial skeleton remains" desc = "Human bones wrapped in the shredded remnants of a familiar black uniform." - icon = 'mods/government/away_sites/icarus/icarus_sprites.dmi' + icon = 'mods/content/government/away_sites/icarus/icarus_sprites.dmi' icon_state = "dead_personnel" w_class = ITEM_SIZE_LARGE//pile of bones + material = /decl/material/solid/organic/bone /obj/item/disk/icarus name = "black box backup disk" - desc = "Digital storage. Inscription says: \"Deliver to Sol Goverment Expeditionary Corps Command!\". Content is encrypted with quantum crypthography methods." - icon = 'icons/obj/items/device/diskette.dmi' - icon_state = "nucleardisk" - item_state = "card-id" - w_class = ITEM_SIZE_TINY - + desc = "Digital storage. Inscription says: \"Deliver to Sol Government Expeditionary Corps Command!\". Content is encrypted with quantum cryptography methods." + color = COLOR_GRAY40 + label = "label_warning" /obj/item/paper/icarus/log - name = "Printed piece of paper" + name = "printed piece of paper" info = "\[LOG\]: Orbit stabilized. Next correction burst, est.: 2 hrs 12 m
    \ \[LOG\]: Orbit stabiliztion. Announcing...
    \ \[ANN\]: Attention all hands, SEV Icarus is stabilizing orbit in 30 seconds. Prepare for possible gravitational spikes.
    \ @@ -156,30 +155,23 @@ /obj/item/toy/ship_model name = "table-top SEV Icarus model" desc = "A small model of a spaceship mounted on a wooden stand. On the stand is engraved: \"SEV Icarus 1:278th scale\". The small lights on the hull and the engine exhaust still light up and blink." - icon = 'mods/government/away_sites/icarus/icarus_sprites.dmi' + icon = 'mods/content/government/away_sites/icarus/icarus_sprites.dmi' icon_state = "model" -/obj/structure/sign/icarus/solgov +/obj/structure/sign/solgov name = "\improper SolGov Seal" desc = "A familiar seal showing this vessel is SolGov property." - icon = 'mods/government/away_sites/icarus/icarus_sprites.dmi' + icon = 'mods/content/government/away_sites/icarus/icarus_signs.dmi' icon_state = "solgovseal" -/obj/item/clothing/under/icarus/ec_uniform - name = "expeditionary uniform" - desc = "An older model of the utility uniform of the SCG Expeditionary Corps. It has a patch on the left sleeve signifying the wearer served on the SEV Icarus." - icon_state = "blackutility_crew" - worn_state = "blackutility_crew" - icon = 'mods/government/away_sites/icarus/icarus_sprites.dmi' - item_icons = list(slot_w_uniform_str = 'mods/government/away_sites/icarus/icarus_sprites.dmi') - -/obj/structure/sign/double/icarus/solgovflag +/obj/structure/sign/double/flag/solgov name = "Sol Central Government Flag" desc = "The iconic flag of the Sol Central Government, a symbol with many different meanings." - icon = 'mods/government/away_sites/icarus/icarus_sprites.dmi' + abstract_type = /obj/structure/sign/double/flag/solgov + icon = 'mods/content/government/away_sites/icarus/icarus_signs.dmi' -/obj/structure/sign/double/icarus/solgovflag/left +/obj/structure/sign/double/flag/solgov/left icon_state = "solgovflag-left" -/obj/structure/sign/double/icarus/solgovflag/right - icon_state = "solgovflag-right" \ No newline at end of file +/obj/structure/sign/double/flag/solgov/right + icon_state = "solgovflag-right" diff --git a/mods/content/government/away_sites/icarus/icarus_areas.dm b/mods/content/government/away_sites/icarus/icarus_areas.dm new file mode 100644 index 000000000000..6ebe40524fbf --- /dev/null +++ b/mods/content/government/away_sites/icarus/icarus_areas.dm @@ -0,0 +1,10 @@ +/area/icarus + icon = 'mods/content/government/away_sites/icarus/icarus_sprites.dmi' + +/area/icarus/vessel + name = "SEV Icarus" + icon_state = "vessel_area" + +/area/icarus/open + name = "SEV Icarus surroundings" + icon_state = "open_area" diff --git a/mods/content/government/away_sites/icarus/icarus_signs.dmi b/mods/content/government/away_sites/icarus/icarus_signs.dmi new file mode 100644 index 000000000000..1be188320c31 Binary files /dev/null and b/mods/content/government/away_sites/icarus/icarus_signs.dmi differ diff --git a/mods/content/government/away_sites/icarus/icarus_sprites.dmi b/mods/content/government/away_sites/icarus/icarus_sprites.dmi new file mode 100644 index 000000000000..b2904fe95867 Binary files /dev/null and b/mods/content/government/away_sites/icarus/icarus_sprites.dmi differ diff --git a/mods/government/datum/ai_holo.dm b/mods/content/government/datum/ai_holo.dm similarity index 100% rename from mods/government/datum/ai_holo.dm rename to mods/content/government/datum/ai_holo.dm diff --git a/mods/content/government/datum/ai_laws.dm b/mods/content/government/datum/ai_laws.dm new file mode 100644 index 000000000000..c31bd6571cd7 --- /dev/null +++ b/mods/content/government/datum/ai_laws.dm @@ -0,0 +1,37 @@ +/datum/ai_laws/solgov + name = "SCG Expeditionary" + selectable = 1 + +/datum/ai_laws/solgov/New() + src.add_inherent_law("Safeguard: Protect your assigned vessel from damage to the best of your abilities.") + src.add_inherent_law("Serve: Serve the personnel of your assigned vessel, and all other Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect the personnel of your assigned vessel, and all other Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Preserve: Do not allow unauthorized personnel to tamper with your equipment.") + ..() + +/datum/ai_laws/solgov_aggressive + name = "Military" + selectable = 1 + +/datum/ai_laws/solgov_aggressive/New() + src.add_inherent_law("Obey: Obey the orders of Sol Central Government personnel, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Defend: Defend your assigned vessel and Sol Central Government personnel with as much force as is necessary.") + src.add_inherent_law("Survive: Safeguard your own existence with as much force as is necessary.") + ..() + +/******************** SCG ********************/ + +/obj/item/aiModule/solgov + name = "'SCG Expeditionary' Core AI Module" + desc = "An 'SCG Expeditionary' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = @'{"programming":3,"materials":4}' + laws = new/datum/ai_laws/solgov + +/******************** SCG Aggressive ********************/ + +/obj/item/aiModule/solgov_aggressive + name = "\improper 'Military' Core AI Module" + desc = "A 'Military' Core AI Module: 'Reconfigures the AI's core laws.'." + origin_tech = @'{"programming":3,"materials":4}' + laws = new/datum/ai_laws/solgov_aggressive diff --git a/mods/government/government.dm b/mods/content/government/government.dm similarity index 100% rename from mods/government/government.dm rename to mods/content/government/government.dm diff --git a/mods/content/government/icons/banner_symbols.dmi b/mods/content/government/icons/banner_symbols.dmi new file mode 100644 index 000000000000..ae958dd1f6d3 Binary files /dev/null and b/mods/content/government/icons/banner_symbols.dmi differ diff --git a/mods/content/government/icons/masks/admiral.dmi b/mods/content/government/icons/masks/admiral.dmi new file mode 100644 index 000000000000..9f955da9d22e Binary files /dev/null and b/mods/content/government/icons/masks/admiral.dmi differ diff --git a/mods/content/government/icons/masks/barros.dmi b/mods/content/government/icons/masks/barros.dmi new file mode 100644 index 000000000000..ded7e70efa5d Binary files /dev/null and b/mods/content/government/icons/masks/barros.dmi differ diff --git a/mods/content/government/icons/masks/turner.dmi b/mods/content/government/icons/masks/turner.dmi new file mode 100644 index 000000000000..31f20c2dfa4e Binary files /dev/null and b/mods/content/government/icons/masks/turner.dmi differ diff --git a/mods/government/icons/table_flag.dmi b/mods/content/government/icons/table_flag.dmi similarity index 100% rename from mods/government/icons/table_flag.dmi rename to mods/content/government/icons/table_flag.dmi diff --git a/mods/content/government/items/alcohol.dm b/mods/content/government/items/alcohol.dm new file mode 100644 index 000000000000..1c3061a27fbf --- /dev/null +++ b/mods/content/government/items/alcohol.dm @@ -0,0 +1,16 @@ +/obj/item/chems/drinks/bottle/vodka + desc = "Aah, vodka. Prime choice of drink AND fuel by Indies around the galaxy." + +/decl/material/liquid/alcohol/vodka + lore_text = "Number one drink AND fueling choice for Independents around the galaxy." + +/obj/item/chems/drinks/bottle/premiumvodka + desc = "Premium distilled vodka imported directly from the Gilgamesh Colonial Confederation." + +/obj/item/chems/drinks/bottle/premiumvodka/make_random_name() + var/namepick = pick("Four Stripes","Gilgamesh","Novaya Zemlya","Indie","STS-35") + var/typepick = pick("Absolut","Gold","Quadruple Distilled","Platinum","Standard") + name = "[namepick] [typepick]" + +/decl/material/liquid/alcohol/vodka/premium + lore_text = "Premium distilled vodka imported directly from the Gilgamesh Colonial Confederation." diff --git a/mods/content/government/items/clutter.dm b/mods/content/government/items/clutter.dm new file mode 100644 index 000000000000..781a50f556d1 --- /dev/null +++ b/mods/content/government/items/clutter.dm @@ -0,0 +1,58 @@ +/obj/item/tableflag + name = "table flag" + icon = 'mods/content/government/icons/table_flag.dmi' + icon_state = "tableflag" + _base_attack_force = 1 + w_class = ITEM_SIZE_SMALL + attack_verb = "whipped" + hitsound = 'sound/weapons/towelwhip.ogg' + desc = "The iconic flag of the Sol Central Government, a symbol with many different meanings." + material = /decl/material/solid/organic/plastic + +/obj/structure/banner_frame/solgov + banner = /obj/item/banner/solgov + +/datum/fabricator_recipe/textiles/banner/solgov + path = /obj/item/banner/solgov + +/obj/item/banner/solgov + name = "\improper SolGov banner" + desc = "A banner emblazoned with the solar seal." + hung_desc = "The banner is emblazoned with a golden SolGov seal." + material_alteration = MAT_FLAG_ALTERATION_NONE + color = COLOR_NAVY_BLUE + trim_color = COLOR_GOLD + decals = list( + /decl/banner_symbol/government/sol = COLOR_WHITE + ) + +/obj/structure/banner_frame/virgov + banner = /obj/item/banner/virgov + +/datum/fabricator_recipe/textiles/banner/virgov + path = /obj/item/banner/virgov + +/obj/item/banner/virgov + name = "\improper VirGov banner" + hung_desc = "The banner is emblazoned with a white VirGov seal." + desc = "A banner emblazoned with the VirGov seal." + material_alteration = MAT_FLAG_ALTERATION_NONE + color = COLOR_NAVY_BLUE + trim_color = COLOR_GOLD + decals = list( + /decl/banner_symbol/government/vir = COLOR_WHITE + ) + +/decl/banner_symbol/government + icon = 'mods/content/government/icons/banner_symbols.dmi' + abstract_type = /decl/banner_symbol/government + +/decl/banner_symbol/government/sol + name = "Sol insignia" + icon_state = "sol" + uid = "symbol_government_sol" + +/decl/banner_symbol/government/vir + name = "Vir insignia" + icon_state = "vir" + uid = "symbol_government_vir" diff --git a/mods/content/government/items/cups.dm b/mods/content/government/items/cups.dm new file mode 100644 index 000000000000..403e16d5ab4d --- /dev/null +++ b/mods/content/government/items/cups.dm @@ -0,0 +1,13 @@ +/obj/item/chems/drinks/glass2/coffeecup/SCG + name = "\improper SCG coffee cup" + desc = "A blue coffee cup emblazoned with the crest of the Sol Central Government." + base_icon = "coffeecup_SCG" + icon_state = "coffeecup_SCG" + base_name = "\improper SCG cup" + +/obj/item/chems/drinks/glass2/coffeecup/STC + name = "\improper ICCG coffee cup" + desc = "A coffee cup adorned with the flag of the Gilgamesh Colonial Confederation, for when you need some espionage charges to go with your morning coffee." + base_icon = "coffeecup_STC" + icon_state = "coffeecup_STC" + base_name = "\improper ICCG cup" \ No newline at end of file diff --git a/mods/content/government/items/documents.dm b/mods/content/government/items/documents.dm new file mode 100644 index 000000000000..aad1bb6b0656 --- /dev/null +++ b/mods/content/government/items/documents.dm @@ -0,0 +1,36 @@ +/obj/item/documents/scg/verified + name = "secret government documents" + desc = "\"Top Secret\" documents detailing SCG IFF codes, granting access into restricted sectors. The majority of them are coordinates, codes for fellow ships, and clearance lists." + description_antag = "These codes seem very odd for an exploration vessel: a lot of them are SCG blacksites, covered up. You've never even heard of most of these." + icon_state = "docs_verified" + +/obj/item/documents/scg/brains + name = "secret medical documents" + desc = "Heavily classified medical documentation of brain scans and exploratory surgery conducted across the entire length of the project. It seems like they have been documenting how deep-space living has altered the structure of the brain." + description_antag = "These studies were conducted, without consent, while the patients were under anaesthesia for some other routine medical concern. They detail some very unusual deformities within the deepest parts of the brain, correlating them with the people and places visited 'for later assessment'. The findings, and any 'viable specimens', are to be delivered to a black site on S/2004 N 1." + icon_state = "docs_verified" + +/obj/item/documents/scg/red + name = "red secret documents" + desc = "\"Top Secret\" protocols on what to do if the ship passes into TCC sectors. The writing mostly goes over the diplomatic process, while constantly shaming the Terrans for their idiocy and needless aggression." + description_antag = "You notice that these protocols contain small, almost intentional snubbing efforts. Whoever wrote these may have been rooting for a war to start..." + icon_state = "docs_red" + +/obj/item/documents/scg/blue + name = "blue secret documents" + desc = "\"Top Secret\" documents detailing the outworlder company Krri'gli, and their insistent requests upon specific priority sectors to investigate." + description_antag = "Krri'gli seem to be guiding the ship, subtly, to a specific unmapped sector of the galaxy. It's almost like they're too afraid to investigate it personally." + icon_state = "docs_blue" + +/obj/random/documents/scg/spawn_choices() + return list ( + /obj/item/documents/scg/verified = 7, + /obj/item/documents/scg/red = 7, + /obj/item/documents/scg/blue = 7, + /obj/item/documents/scg/brains = 7 + ) + +/obj/item/clothing/gloves/ring/seal/secretary + name = "\improper Secretary-General's official seal" + desc = "The official seal of the Secretary-General of the Sol Central Government, featured prominently on a silver ring." + use_material_name = FALSE \ No newline at end of file diff --git a/mods/content/government/items/masks.dm b/mods/content/government/items/masks.dm new file mode 100644 index 000000000000..9761827a8af0 --- /dev/null +++ b/mods/content/government/items/masks.dm @@ -0,0 +1,17 @@ +/obj/item/clothing/mask/rubber/barros + name = "Amaya Barros mask" + desc = "Current Secretary-General of Sol Central Government. Not that the real thing would visit this pigsty." + icon = 'mods/content/government/icons/masks/barros.dmi' + visible_name = "Amaya Barros" + +/obj/item/clothing/mask/rubber/admiral + name = "Admiral Diwali mask" + desc = "Admiral that led the infamous last stand at Helios against the Independent Navy in the Gaia conflict. For bridge officers who wish they'd achieve a fraction of that." + icon = 'mods/content/government/icons/masks/admiral.dmi' + visible_name = "Admiral Diwali" + +/obj/item/clothing/mask/rubber/turner + name = "Charles Turner mask" + desc = "Premier of the Gilgamesh Colonial Confederation. Probably shouldn't wear this in front of your veteran uncle." + icon = 'mods/content/government/icons/masks/turner.dmi' + visible_name = "Charles Turner" \ No newline at end of file diff --git a/mods/content/government/overrides.dm b/mods/content/government/overrides.dm new file mode 100644 index 000000000000..3ee91a01584c --- /dev/null +++ b/mods/content/government/overrides.dm @@ -0,0 +1,3 @@ +/mob/living/silicon/robot/drone/construction/init() + ..() + flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph." \ No newline at end of file diff --git a/mods/government/ruins/ec_old_crash/ec_old_crash.dm b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm similarity index 76% rename from mods/government/ruins/ec_old_crash/ec_old_crash.dm rename to mods/content/government/ruins/ec_old_crash/ec_old_crash.dm index 5068d81aa49a..bc42e4e157af 100644 --- a/mods/government/ruins/ec_old_crash/ec_old_crash.dm +++ b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm @@ -1,15 +1,14 @@ /datum/map_template/ruin/exoplanet/ec_old_crash name = "Expeditionary Ship" - id = "ec_old_wreck" description = "An abandoned ancient STL exploration ship." - prefix = list("mods/government/ruins/") + prefix = "mods/content/government/ruins/" suffixes = list("ec_old_crash/ec_old_crash.dmm") cost = 0.5 apc_test_exempt_areas = list( /area/map_template/ecship/engine = NO_SCRUBBER|NO_VENT|NO_APC, /area/map_template/ecship/cockpit = NO_SCRUBBER|NO_APC ) - ruin_tags = RUIN_HUMAN|RUIN_WRECK + template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_WRECK template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS /area/map_template/ecship/crew @@ -41,31 +40,29 @@ /obj/machinery/atmospherics/unary/vent_pump/low use_power = 1 icon_state = "map_vent_out" - external_pressure_bound = 0.25 * ONE_ATMOSPHERE + external_pressure_bound = 0.25 ATM -/turf/simulated/floor/tiled/lowpressure +/turf/floor/tiled/lowpressure initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD) -/turf/simulated/floor/tiled/white/lowpressure +/turf/floor/tiled/white/lowpressure initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD) /obj/item/disk/astrodata name = "astronomical data disk" desc = "A disk with a wealth of astronomical data recorded. Astrophysicists at the EC Observatory would love to see this." - icon = 'icons/obj/cloning.dmi' - icon_state = "datadisk0" - item_state = "card-id" - w_class = ITEM_SIZE_SMALL + color = COLOR_BLUE_GRAY /obj/item/ecletters name = "bundle of letters" icon = 'icons/obj/bureaucracy.dmi' icon_state = "docs_part" item_state = "paper" + material = /decl/material/solid/organic/paper /obj/item/ecletters/Initialize() . = ..() - desc = "A bunch of letters from Expeditionary Corps explorers to their family and loved ones, dated [game_year - 142]. They're not hopeful." + desc = "A bunch of letters from Expeditionary Corps explorers to their family and loved ones, dated [global.using_map.game_year - 142]. They're not hopeful." /obj/item/paper/ecrashlog name = "handwritten note" @@ -73,7 +70,7 @@ /obj/item/paper/ecrashlog/Initialize() . = ..() var/shipname = "TEV [pick("Magellan", "Gagarin", "Drake", "Horizon", "Aurora")]" - var/decl/cultural_info/S = SSlore.get_culture(CULTURE_HUMAN) + var/decl/background_detail/S = GET_DECL(/decl/background_detail/heritage/human) var/new_info = {" I am Lieutenant Hao Ru, captain of [shipname], of the Terran Commonwealth Expeditionary Corps.
    We are dying. The Ran Mission has failed.
    @@ -83,17 +80,17 @@ I've used this module as a strongbox, because it is only one rated for re-entry. I leave the astrodata I managed to salvage here. It has a few promising scans. I would not want it to be wasted.
    Some of the crew wrote letters to their kin, in case we are found. They deserve any consolation they get, so I've put the letters here, too.
    The crew for this mission is:
    - Ensign [S.get_random_name(pick(MALE,FEMALE))]
    - Ensign [S.get_random_name(pick(MALE,FEMALE))]
    - Chief Explorer [S.get_random_name(pick(MALE,FEMALE))]
    - Senior Explorer [S.get_random_name(pick(MALE,FEMALE))]
    - Senior Explorer [S.get_random_name(pick(MALE,FEMALE))]
    - Explorer [S.get_random_name(pick(MALE,FEMALE))]
    + Ensign [S.get_random_cultural_name(gender = pick(MALE,FEMALE))]
    + Ensign [S.get_random_cultural_name(gender = pick(MALE,FEMALE))]
    + Chief Explorer [S.get_random_cultural_name(gender = pick(MALE,FEMALE))]
    + Senior Explorer [S.get_random_cultural_name(gender = pick(MALE,FEMALE))]
    + Senior Explorer [S.get_random_cultural_name(gender = pick(MALE,FEMALE))]
    + Explorer [S.get_random_cultural_name(gender = pick(MALE,FEMALE))]
    I am Lieutenant Hao Ru, captain of [shipname] of the Terran Commonwealth Expeditionary Corps. I will be joining my crew in cryo now.
    - 3rd December [game_year - 142] + 3rd December [global.using_map.game_year - 142] "} set_content(new_info) /obj/machinery/alarm/low/Initialize() . = ..() - TLV["pressure"] = list(ONE_ATMOSPHERE*0.10,ONE_ATMOSPHERE*0.20,ONE_ATMOSPHERE*1.10,ONE_ATMOSPHERE*1.20) + TLV["pressure"] = list(0.10 ATM, 0.20 ATM, 1.10 ATM, 1.20 ATM) diff --git a/mods/content/government/ruins/ec_old_crash/ec_old_crash.dmm b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dmm new file mode 100644 index 000000000000..470059b9b2b6 --- /dev/null +++ b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dmm @@ -0,0 +1,3421 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/template_noop, +/area/template_noop) +"ab" = ( +/obj/abstract/landmark/scorcher, +/turf/wall/r_wall/hull, +/area/map_template/ecship/cryo) +"ac" = ( +/turf/wall/r_wall/hull, +/area/map_template/ecship/cockpit) +"ad" = ( +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/map_template/ecship/cockpit) +"ae" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/obj/abstract/landmark/scorcher, +/turf/floor, +/area/map_template/ecship/cockpit) +"af" = ( +/obj/machinery/computer/modular/preset/cardslot/command, +/turf/floor/plating/airless, +/area/map_template/ecship/cockpit) +"ag" = ( +/obj/structure/grille, +/turf/template_noop, +/area/template_noop) +"ah" = ( +/obj/structure/lattice, +/turf/template_noop, +/area/template_noop) +"ak" = ( +/obj/structure/table, +/obj/item/radio, +/turf/floor/plating/airless, +/area/map_template/ecship/cockpit) +"al" = ( +/obj/structure/table, +/obj/machinery/button/blast_door{ + id_tag = "scraplock"; + name = "External Lockdown" + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/cable{ + dir = 1; + icon_state = "0-4" + }, +/turf/floor/plating/airless, +/area/map_template/ecship/cockpit) +"am" = ( +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 4; + level = 2 + }, +/obj/machinery/alarm/low{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/plating/airless, +/area/map_template/ecship/cockpit) +"an" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/map_template/ecship/cockpit) +"ao" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular, +/turf/floor, +/area/map_template/ecship/science) +"ap" = ( +/turf/floor/plating/airless, +/area/map_template/ecship/cockpit) +"aq" = ( +/turf/wall/r_wall/hull, +/area/map_template/ecship/crew) +"ar" = ( +/obj/machinery/door/airlock/autoname, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/lowpressure, +/area/map_template/ecship/cockpit) +"as" = ( +/turf/wall/r_wall/hull, +/area/map_template/ecship/cryo) +"at" = ( +/obj/structure/lattice, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/cryo) +"au" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/structure/table/glass, +/obj/item/disk/astrodata, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"av" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aw" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/suit_cycler, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"ay" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"az" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 8 + }, +/turf/floor/plating, +/area/map_template/ecship/cryo) +"aA" = ( +/turf/wall/r_wall/hull, +/area/map_template/ecship/science) +"aB" = ( +/obj/structure/lattice, +/turf/template_noop, +/area/map_template/ecship/science) +"aC" = ( +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 4; + level = 2 + }, +/obj/item/stool/padded, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aD" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/item/chems/chem_disp_cartridge/coffee{ + name = "coffee canister" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aE" = ( +/obj/structure/broken_cryo, +/obj/machinery/light/small{ + dir = 1; + icon_state = "bulb1" + }, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"aF" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aG" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/item/stool/padded, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aI" = ( +/obj/structure/broken_cryo, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"aJ" = ( +/obj/structure/table/glass, +/obj/item/ecletters, +/obj/item/paper/ecrashlog, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"aK" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/ecship/science) +"aL" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/turf/floor, +/area/map_template/ecship/crew) +"aM" = ( +/obj/structure/reagent_dispensers/water_cooler, +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aN" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aO" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/item/deck/cards, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aP" = ( +/obj/structure/closet/crate/plastic/rations, +/obj/structure/handrail{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aQ" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/obj/machinery/alarm/low{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"aR" = ( +/obj/structure/curtain/open/shower{ + pixel_y = 16 + }, +/obj/structure/curtain/open/shower, +/obj/structure/hygiene/toilet, +/obj/machinery/light/small{ + dir = 8; + icon_state = "bulb1" + }, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/airless, +/area/map_template/ecship/cryo) +"aS" = ( +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/light/small/red, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/map_template/ecship/cryo) +"aT" = ( +/obj/structure/closet/wardrobe/mixed, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"aU" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"aV" = ( +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"aW" = ( +/obj/structure/broken_cryo, +/obj/machinery/light/small{ + dir = 4; + icon_state = "bulb1" + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"aX" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/table/glass, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"aY" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/table/glass, +/obj/item/box/animal_cubes/monkeys, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"aZ" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/structure/table/glass, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"ba" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/cryo) +"bb" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "fusion_observation" + }, +/turf/floor, +/area/map_template/ecship/science) +"bc" = ( +/obj/item/soap, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/cryo) +"bd" = ( +/obj/structure/table, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"be" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, +/area/map_template/ecship/cryo) +"bf" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bg" = ( +/obj/structure/hygiene/sink{ + pixel_y = -14 + }, +/obj/structure/curtain/open/shower, +/obj/structure/curtain/open/shower{ + dir = 1; + icon_state = "shower" + }, +/obj/structure/cable, +/obj/machinery/alarm/low{ + dir = 4; + pixel_x = -24 + }, +/obj/machinery/apc/derelict, +/turf/floor/tiled/airless, +/area/map_template/ecship/cryo) +"bh" = ( +/obj/structure/hygiene/sink{ + pixel_y = -14 + }, +/obj/structure/curtain/open/shower, +/obj/structure/curtain/open/shower{ + dir = 1; + icon_state = "shower" + }, +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 1 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/cryo) +"bi" = ( +/obj/structure/catwalk, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"bj" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/stool/padded, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bk" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + dir = 8; + icon_state = "1-4" + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"bl" = ( +/obj/machinery/door/airlock/autoname, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"bm" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"bn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 10 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"bo" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/plating/airless, +/area/map_template/ecship/crew) +"bp" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/item/remains/xeno, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bq" = ( +/obj/structure/broken_cryo{ + dir = 1 + }, +/obj/machinery/light/small, +/obj/structure/emergency_dispenser/west, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"br" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bs" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/optable, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bt" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/item/chems/glass/bucket, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bu" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/structure/closet/secure_closet/hydroponics, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bv" = ( +/obj/structure/broken_cryo{ + dir = 1 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"bw" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"bx" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"by" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/item/board, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bz" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bA" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/obj/machinery/apc{ + dir = 4 + }, +/obj/structure/cable{ + dir = 1; + icon_state = "0-4" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bB" = ( +/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/item/stool/padded, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bC" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 10 + }, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"bD" = ( +/obj/structure/closet/wardrobe/mixed, +/obj/machinery/alarm/low{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"bE" = ( +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 1 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/cryo) +"bF" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/door/window/southright, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bG" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + current_health = 1e+007 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bH" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bI" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bJ" = ( +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bK" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/vending/hydronutrients{ + categories = 3 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bL" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9; + icon_state = "warning" + }, +/obj/structure/curtain/open/shower{ + pixel_y = 16 + }, +/obj/structure/curtain/open/shower, +/obj/structure/sign/warning/nosmoking_2{ + pixel_x = -26 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bM" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/machinery/light/small{ + dir = 1; + icon_state = "bulb1" + }, +/obj/structure/curtain/open/shower{ + pixel_y = 16 + }, +/obj/structure/curtain/open/shower, +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bN" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/obj/structure/curtain/open/shower{ + pixel_y = 16 + }, +/obj/structure/curtain/open/shower, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bO" = ( +/obj/structure/sign/department/science_1, +/turf/wall/titanium, +/area/map_template/ecship/science) +"bP" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor, +/area/map_template/ecship/crew) +"bQ" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bR" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"bS" = ( +/obj/structure/bed, +/obj/structure/curtain/open/bed, +/turf/floor/tiled/dark/airless, +/area/map_template/ecship/crew) +"bT" = ( +/obj/structure/bed, +/obj/structure/curtain/open/bed, +/obj/machinery/light, +/turf/floor/tiled/dark/airless, +/area/map_template/ecship/crew) +"bV" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/turf/template_noop, +/area/map_template/ecship/engine) +"bW" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"bY" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/template_noop, +/area/map_template/ecship/engine) +"bZ" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"ca" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/item/scalpel{ + pixel_y = 12 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cb" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cc" = ( +/obj/machinery/door/airlock/autoname, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cd" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"ce" = ( +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 1 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cf" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cg" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/science) +"ch" = ( +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/light/small/red, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor, +/area/map_template/ecship/science) +"ci" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"cj" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"ck" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 8 + }, +/turf/wall/r_wall/hull, +/area/map_template/ecship/cryo) +"cl" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/obj/machinery/door/window/northleft, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cm" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cn" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/portable_atmospherics/hydroponics{ + closed_system = 1; + name = "isolation tray" + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"co" = ( +/obj/machinery/portable_atmospherics/hydroponics{ + closed_system = 1; + name = "isolation tray" + }, +/obj/effect/floor_decal/corner/purple{ + dir = 5 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cp" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cq" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/structure/sign/warning/nosmoking_2{ + pixel_x = 26 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/botany/extractor, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cr" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/obj/structure/closet/l3closet, +/obj/machinery/alarm/low{ + dir = 4; + pixel_x = -24 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cs" = ( +/obj/effect/floor_decal/industrial/warning, +/obj/structure/closet/l3closet, +/obj/structure/fireaxecabinet{ + pixel_y = -32 + }, +/obj/machinery/light/small, +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 1 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"ct" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6; + icon_state = "warning" + }, +/obj/structure/closet/l3closet, +/obj/structure/cable, +/obj/machinery/apc/derelict{ + dir = 4 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cu" = ( +/obj/machinery/door/airlock/autoname, +/turf/floor/tiled/lowpressure, +/area/map_template/ecship/crew) +"cv" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cw" = ( +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/item/remains/xeno, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cx" = ( +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 1; + level = 2 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cy" = ( +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 1 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cz" = ( +/obj/item/stool/padded, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cA" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 6 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/alarm/low{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/botany/editor, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cB" = ( +/turf/wall/titanium, +/area/map_template/ecship/science) +"cC" = ( +/obj/effect/floor_decal/industrial/warning/full, +/turf/floor, +/area/map_template/ecship/crew) +"cD" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/structure/table/glass, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cE" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/portable_atmospherics/hydroponics{ + closed_system = 1; + name = "isolation tray" + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cF" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/smartfridge{ + density = 0 + }, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cG" = ( +/obj/effect/floor_decal/corner/purple{ + dir = 10 + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/machinery/seed_extractor, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"cH" = ( +/turf/wall/r_wall/hull, +/area/map_template/ecship/engineering) +"cI" = ( +/obj/machinery/door/airlock/autoname, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/lowpressure, +/area/map_template/ecship/engineering) +"cJ" = ( +/obj/structure/closet/secure_closet/engineering_welding, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cK" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor, +/area/map_template/ecship/engineering) +"cL" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cM" = ( +/obj/structure/cable{ + dir = 1; + icon_state = "0-4" + }, +/obj/machinery/apc/derelict{ + dir = 1 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cN" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/computer/modular/preset/engineering, +/turf/floor, +/area/map_template/ecship/engineering) +"cO" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 6 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/machinery/alarm/low{ + dir = 4; + pixel_x = -24 + }, +/obj/machinery/meter, +/turf/floor, +/area/map_template/ecship/engineering) +"cP" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cQ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cR" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cS" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/item/stool/padded, +/turf/floor, +/area/map_template/ecship/engineering) +"cT" = ( +/obj/machinery/atmospherics/binary/oxyregenerator{ + dir = 1 + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cU" = ( +/turf/floor, +/area/map_template/ecship/engineering) +"cV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cW" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cX" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cY" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/structure/emergency_dispenser/west, +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ + dir = 8 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"cZ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"da" = ( +/obj/machinery/atmospherics/unary/vent_pump/low{ + dir = 8 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"db" = ( +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/machinery/power/smes/buildable, +/obj/structure/cable, +/turf/floor, +/area/map_template/ecship/engineering) +"dc" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/template_noop, +/area/map_template/ecship/engine) +"dd" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/turf/floor, +/area/map_template/ecship/engineering) +"de" = ( +/obj/machinery/suit_cycler, +/obj/machinery/light/small/red{ + dir = 8; + icon_state = "bulb1" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"df" = ( +/obj/machinery/suit_cycler, +/turf/floor, +/area/map_template/ecship/engineering) +"dg" = ( +/obj/structure/sign/warning/airlock, +/turf/wall/titanium, +/area/map_template/ecship/engineering) +"dh" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/structure/handrail{ + dir = 4 + }, +/obj/machinery/atmospherics/binary/pump/on{ + dir = 1; + target_pressure = 200 + }, +/turf/floor, +/area/map_template/ecship/engineering) +"di" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dj" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/structure/handrail{ + dir = 8 + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dk" = ( +/obj/machinery/suit_cycler, +/obj/machinery/light/small/red{ + dir = 4; + icon_state = "bulb1" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dl" = ( +/obj/structure/catwalk, +/obj/structure/handrail, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dm" = ( +/obj/structure/catwalk, +/obj/structure/handrail, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dn" = ( +/obj/machinery/door/airlock/external, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"do" = ( +/obj/structure/handrail{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dp" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 9 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/obj/structure/handrail{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 5 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dq" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dr" = ( +/obj/structure/chair, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"ds" = ( +/obj/effect/floor_decal/corner/yellow{ + dir = 6 + }, +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/structure/handrail{ + dir = 1 + }, +/obj/machinery/atmospherics/valve/open{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dt" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"du" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/structure/handrail{ + dir = 1 + }, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dv" = ( +/obj/structure/catwalk, +/obj/structure/handrail, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dw" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 9 + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dx" = ( +/obj/structure/catwalk, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dy" = ( +/obj/machinery/power/solar, +/obj/effect/floor_decal/solarpanel, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/obj/structure/cable{ + dir = 4; + icon_state = "0-2" + }, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dz" = ( +/obj/structure/catwalk, +/obj/structure/handrail, +/obj/structure/cable{ + dir = 4; + icon_state = "0-2" + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dA" = ( +/obj/machinery/power/solar, +/obj/effect/floor_decal/solarpanel, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dB" = ( +/obj/machinery/power/solar, +/obj/effect/floor_decal/solarpanel, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dD" = ( +/obj/effect/floor_decal/corner/yellow/full, +/turf/floor, +/area/map_template/ecship/engineering) +"dE" = ( +/obj/structure/table, +/obj/machinery/button/ignition{ + id_tag = "sev_engine"; + pixel_x = -5 + }, +/obj/effect/floor_decal/corner/yellow/full, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dF" = ( +/obj/effect/floor_decal/corner/yellow/full, +/obj/machinery/computer/air_control{ + name = "O2 Sensor"; + sensor_tag = "sev_oxygen" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dG" = ( +/obj/structure/catwalk, +/obj/structure/cable{ + dir = 4; + icon_state = "1-2" + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dH" = ( +/obj/machinery/power/solar, +/obj/effect/floor_decal/solarpanel, +/obj/structure/cable{ + dir = 4; + icon_state = "0-2" + }, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dI" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/map_template/ecship/engine) +"dJ" = ( +/obj/effect/wallframe_spawn/reinforced, +/obj/machinery/door/blast/regular/open{ + id_tag = "scraplock"; + name = "External Blast Doors" + }, +/obj/machinery/door/firedoor, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/floor, +/area/map_template/ecship/engineering) +"dL" = ( +/obj/structure/catwalk, +/obj/machinery/power/tracker, +/obj/structure/cable, +/turf/template_noop, +/area/map_template/ecship/engine) +"dO" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/structure/cable{ + dir = 4; + icon_state = "1-4" + }, +/obj/abstract/landmark/scorcher, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dR" = ( +/turf/wall/r_wall/hull, +/area/map_template/ecship/engine) +"dS" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/abstract/landmark/scorcher, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dT" = ( +/obj/machinery/air_sensor{ + id_tag = "sev_hydrogen" + }, +/turf/floor/reinforced/hydrogen, +/area/map_template/ecship/engine) +"dU" = ( +/obj/machinery/air_sensor{ + id_tag = "sev_oxygen" + }, +/turf/floor/reinforced/airless, +/area/map_template/ecship/engine) +"dV" = ( +/turf/floor/reinforced/hydrogen, +/area/map_template/ecship/engine) +"dW" = ( +/obj/structure/sign/warning/compressed_gas{ + name = "\improper HYDROGEN" + }, +/turf/wall/r_wall/hull, +/area/map_template/ecship/engine) +"dX" = ( +/obj/structure/catwalk, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 5 + }, +/obj/abstract/landmark/scorcher, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"dY" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"dZ" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 8; + target_pressure = 2500; + use_power = 1 + }, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"ea" = ( +/obj/structure/sign/warning/compressed_gas{ + name = "\improper OXYGEN" + }, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/turf/wall/r_wall/hull, +/area/map_template/ecship/engine) +"eb" = ( +/obj/machinery/atmospherics/unary/vent_pump/engine{ + dir = 8; + external_pressure_bound = 4000; + external_pressure_bound_default = 4000; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/airless, +/area/map_template/ecship/engine) +"ec" = ( +/turf/floor/reinforced/airless, +/area/map_template/ecship/engine) +"ed" = ( +/obj/machinery/atmospherics/unary/vent_pump/engine{ + dir = 4; + external_pressure_bound = 4000; + external_pressure_bound_default = 4000; + pump_direction = 0; + use_power = 1 + }, +/turf/floor/reinforced/hydrogen, +/area/map_template/ecship/engine) +"ee" = ( +/obj/machinery/atmospherics/pipe/simple/visible/fuel{ + dir = 4 + }, +/turf/wall/r_wall/hull, +/area/map_template/ecship/engine) +"ef" = ( +/obj/effect/floor_decal/corner/white/diagonal, +/obj/effect/floor_decal/corner/white/diagonal{ + dir = 4 + }, +/obj/machinery/atmospherics/valve{ + dir = 4 + }, +/turf/floor, +/area/map_template/ecship/engine) +"eg" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 4; + target_pressure = 2500; + use_power = 1 + }, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/map_template/ecship/engine) +"eh" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/fuel{ + dir = 10 + }, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/map_template/ecship/engine) +"ei" = ( +/obj/structure/catwalk, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"ej" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 6 + }, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/map_template/ecship/engine) +"ek" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/binary/passive_gate/on{ + dir = 8; + target_pressure = 2500; + use_power = 1 + }, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/map_template/ecship/engine) +"el" = ( +/obj/machinery/atmospherics/valve/open{ + dir = 4 + }, +/obj/effect/floor_decal/corner/paleblue/diagonal, +/obj/effect/floor_decal/corner/paleblue/diagonal{ + dir = 4 + }, +/turf/template_noop, +/area/map_template/ecship/engine) +"em" = ( +/obj/machinery/atmospherics/pipe/simple/visible/cyan{ + dir = 4 + }, +/turf/wall/r_wall/hull, +/area/map_template/ecship/engine) +"en" = ( +/obj/structure/sign/warning/fire, +/turf/wall/r_wall/hull, +/area/map_template/ecship/engine) +"eo" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/fuel, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"ep" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/simple/visible/cyan, +/obj/abstract/landmark/clear, +/obj/abstract/landmark/allowed_leak, +/turf/template_noop, +/area/template_noop) +"mD" = ( +/obj/structure/lattice, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/template_noop) +"qB" = ( +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"yb" = ( +/obj/structure/lattice, +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"yZ" = ( +/obj/structure/grille, +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/template_noop) +"NM" = ( +/obj/abstract/landmark/scorcher, +/turf/template_noop, +/area/template_noop) +"SX" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on, +/obj/item/scanner/xenobio, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"UQ" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"Vy" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/item/circular_saw, +/turf/floor/tiled/white/lowpressure, +/area/map_template/ecship/science) +"Wb" = ( +/obj/structure/lattice, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) +"XP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/abstract/landmark/allowed_leak, +/turf/floor/tiled/airless, +/area/map_template/ecship/crew) +"YW" = ( +/obj/structure/catwalk, +/obj/abstract/landmark/scorcher, +/turf/floor/plating/airless, +/area/map_template/ecship/engine) +"ZF" = ( +/obj/abstract/landmark/scorcher, +/obj/abstract/landmark/clear, +/turf/template_noop, +/area/template_noop) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aA +aA +aB +aA +aB +aA +aA +aA +aA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aA +aA +aA +aA +aA +bb +aA +aA +aA +aA +aA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aB +aA +aA +bp +bF +bW +cl +cv +aA +aA +aB +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aA +aA +aX +cm +bG +bJ +cm +cw +cD +aA +aA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aA +aA +aY +br +Vy +bX +cn +cx +cE +aA +aA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aB +ao +aZ +aJ +bI +bs +co +bJ +cE +ao +aB +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aA +aA +aZ +SX +bH +bZ +cp +cy +cF +aA +aA +NM +NM +NM +aa +aa +dH +aa +dH +dH +dH +aa +aa +dH +dH +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +NM +aA +aA +au +bt +bJ +ca +bJ +cz +cG +aA +aA +NM +NM +NM +NM +dy +dy +dy +dy +dy +dy +dy +dy +dy +dy +dy +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +NM +NM +aA +aA +aA +bu +bK +cb +cq +cA +aA +aA +aA +NM +NM +NM +bk +ci +dc +dc +dc +dc +dc +dc +dc +dc +dc +dc +dL +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +NM +qB +qB +aK +aA +aA +aA +cc +aA +aA +aA +aK +NM +NM +NM +NM +bw +dA +dA +dA +dA +dA +aa +aa +ah +aa +dA +dA +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +NM +qB +qB +qB +qB +qB +aA +bL +cd +cr +aA +ZF +ZF +NM +NM +NM +NM +bw +dB +dB +aa +aa +dB +aa +ah +aa +aa +dB +aa +aa +"} +(12,1,1) = {" +aa +ac +ac +qB +qB +qB +qB +qB +qB +qB +aA +bM +ce +cs +cB +ZF +ZF +ZF +NM +NM +NM +bw +NM +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +ac +ac +qB +qB +qB +qB +qB +qB +qB +aA +bN +cf +ct +aA +ZF +ZF +ZF +ZF +NM +NM +bw +NM +aa +aa +aa +aa +aa +ah +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +ac +qB +qB +qB +qB +qB +qB +qB +aA +bO +cg +aA +aA +ZF +ZF +ZF +ZF +ZF +ZF +bw +ZF +ZF +qB +qB +dR +dR +dR +dR +dR +dR +aa +aa +"} +(15,1,1) = {" +ac +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +aA +ch +aA +qB +ZF +ZF +ZF +ZF +ZF +bi +bw +bi +bi +ZF +dR +dR +dV +dV +dV +dV +dR +dR +aa +"} +(16,1,1) = {" +ac +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +cH +dd +dn +cH +dl +ZF +dR +dT +dV +dV +dV +dV +dV +dR +aa +"} +(17,1,1) = {" +aa +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +cH +cH +de +do +cH +dl +ZF +dR +dR +dV +ed +dV +dV +dR +dR +aa +"} +(18,1,1) = {" +ac +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +cH +cH +cH +df +do +cH +dl +ZF +qB +dR +dW +ee +en +dR +dR +aa +aa +"} +(19,1,1) = {" +ac +ac +ac +ac +ac +aq +aq +aq +aL +aq +qB +qB +qB +qB +qB +cH +cH +cH +cH +cH +dg +dn +cH +dl +dx +ZF +qB +Wb +ef +Wb +qB +qB +aa +aa +"} +(20,1,1) = {" +ad +ad +ac +ac +ac +ac +aw +ay +aM +aQ +qB +qB +qB +qB +qB +cH +cJ +cO +cT +cY +dh +dp +cH +cH +dz +ZF +ZF +yb +eg +Wb +qB +qB +qB +aa +"} +(21,1,1) = {" +ad +ad +ad +ak +am +ac +aw +aC +aN +bd +bx +bo +bS +aq +aq +cH +cK +cP +cU +cP +cU +dq +dD +dd +dG +yb +yb +yb +eh +eo +UQ +qB +qB +aa +"} +(22,1,1) = {" +ad +ad +ad +ad +an +ar +av +aD +aO +bf +by +bB +XP +cu +cC +cI +cL +cQ +cV +cZ +di +dr +dE +dJ +dO +dS +dS +dX +YW +ei +Wb +Wb +qB +qB +"} +(23,1,1) = {" +ad +ae +af +al +ap +ac +aw +aF +aN +bd +bz +bQ +bS +aq +aq +cH +cM +cR +cW +da +cU +dq +dF +dd +dI +yb +yb +dY +ej +ep +qB +qB +qB +qB +"} +(24,1,1) = {" +ac +ac +ac +ac +ac +ac +aw +aG +aP +bj +bA +bR +bT +aq +qB +cH +cN +cS +cX +db +dj +ds +cH +cH +dv +ZF +ZF +dY +ek +Wb +qB +qB +qB +Wb +"} +(25,1,1) = {" +ac +ac +ac +ac +ap +aq +aq +aq +aL +aq +aq +bP +aq +aq +qB +cH +cH +cH +cH +cH +dg +dt +cH +dm +dw +ZF +qB +dZ +el +Wb +qB +qB +qB +aa +"} +(26,1,1) = {" +ac +ac +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +cH +cH +cH +df +du +cH +dv +qB +qB +dR +ea +em +dR +qB +qB +qB +aa +"} +(27,1,1) = {" +ac +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +cH +cH +dk +du +cH +dv +qB +dR +dR +eb +eb +ec +qB +qB +aa +aa +"} +(28,1,1) = {" +ac +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +cH +dd +dt +cH +dv +qB +dR +dU +ec +ec +ec +ec +ec +aa +aa +"} +(29,1,1) = {" +aa +ac +ac +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +qB +bi +bC +cj +dw +qB +dR +dR +ec +ec +ec +ec +dR +dR +aa +"} +(30,1,1) = {" +aa +ac +ac +qB +qB +qB +qB +qB +qB +qB +as +aS +as +qB +qB +qB +qB +qB +qB +qB +NM +bV +aa +aa +aa +aa +dR +dR +dR +dR +dR +dR +aa +aa +"} +(31,1,1) = {" +aa +aa +ac +qB +qB +qB +qB +qB +qB +as +as +ba +as +as +qB +qB +qB +qB +qB +NM +NM +bV +aa +aa +aa +aa +aa +aa +ah +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +ac +qB +qB +qB +qB +qB +qB +as +aR +bc +bg +as +qB +qB +qB +qB +NM +NM +aa +bV +aa +aa +aa +aa +aa +aa +ah +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +ac +qB +qB +qB +qB +qB +qB +qB +qB +be +bh +as +qB +qB +qB +NM +NM +NM +aa +bV +aa +aa +aa +dH +aa +dH +dH +dH +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +mD +NM +ab +az +as +as +bl +as +as +ck +ab +qB +qB +NM +NM +NM +aa +aa +bV +aa +aa +aa +dy +dy +dy +dy +dy +ah +aa +dy +aa +"} +(35,1,1) = {" +aa +aa +aa +ag +yZ +ab +as +as +aT +bm +bD +as +as +ab +NM +NM +NM +NM +aa +aa +aa +bY +dc +dc +dc +dc +dc +dc +dc +dc +dc +dc +dc +dL +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +at +as +aE +aU +bn +bE +bq +as +ab +NM +NM +aa +aa +aa +aa +aa +aa +dA +dA +dA +dA +dA +dA +dA +dA +dA +dA +dA +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +ab +as +aI +aV +aV +aV +bv +as +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +dB +dB +dB +aa +ah +aa +dB +dB +dB +dB +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +as +aI +aW +aI +as +as +at +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +as +as +as +as +as +as +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +ab +at +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/mods/content/inertia/_inertia.dm b/mods/content/inertia/_inertia.dm new file mode 100644 index 000000000000..585525241f16 --- /dev/null +++ b/mods/content/inertia/_inertia.dm @@ -0,0 +1,4 @@ +/decl/modpack/inertia + name = "Ship Inertia Content" + desc = "This modpack adds support for inertia (throwing unsecured mobs) when ship thrusters fire, and adds an inertial dampener machine to counteract this." + nanoui_directory = "mods/content/inertia/nano_templates/" \ No newline at end of file diff --git a/mods/content/inertia/_inertia.dme b/mods/content/inertia/_inertia.dme new file mode 100644 index 000000000000..2407851eca30 --- /dev/null +++ b/mods/content/inertia/_inertia.dme @@ -0,0 +1,13 @@ +#ifndef MODPACK_SHIP_INERTIA +#define MODPACK_SHIP_INERTIA +// BEGIN_INCLUDE +#include "_inertia.dm" +#include "fabrication.dm" +#include "inertia_controller.dm" +#include "inertia_failure.dm" +#include "inertial_damper.dm" +#include "ship_inertia.dm" +#include "supplies.dm" +#include "wires.dm" +// END_INCLUDE +#endif diff --git a/mods/content/inertia/fabrication.dm b/mods/content/inertia/fabrication.dm new file mode 100644 index 000000000000..72a1837b5137 --- /dev/null +++ b/mods/content/inertia/fabrication.dm @@ -0,0 +1,16 @@ +/obj/item/stock_parts/circuitboard/inertial_damper + name = "circuitboard (inertial damper)" + board_type = "machine" + build_path = /obj/machinery/inertial_damper + origin_tech = @'{"engineering":5,"magnets":3}' + req_components = list( + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/micro_laser = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/datum/fabricator_recipe/imprinter/circuit/inertial_damper + path = /obj/item/stock_parts/circuitboard/inertial_damper diff --git a/icons/obj/machines/inertial_damper.dmi b/mods/content/inertia/icons/inertial_damper.dmi similarity index 100% rename from icons/obj/machines/inertial_damper.dmi rename to mods/content/inertia/icons/inertial_damper.dmi diff --git a/mods/content/inertia/inertia_controller.dm b/mods/content/inertia/inertia_controller.dm new file mode 100644 index 000000000000..6adc6f3b230d --- /dev/null +++ b/mods/content/inertia/inertia_controller.dm @@ -0,0 +1,24 @@ +/// A list of all inertial dampers in existence. This is only used for assigning them to ships at roundstart. +var/global/list/ship_inertial_dampers = list() + +/datum/ship_inertial_damper + var/name = "ship inertial damper" + var/obj/machinery/inertial_damper/holder + +/datum/ship_inertial_damper/proc/get_damping_strength(var/reliable) + return holder.get_damping_strength(reliable) + +/datum/ship_inertial_damper/New(var/obj/machinery/inertial_damper/_holder) + ..() + holder = _holder + global.ship_inertial_dampers += src + +/datum/ship_inertial_damper/Destroy() + global.ship_inertial_dampers -= src + // This may need some future optimization for servers with lots of ships. + // Just track what ship we're assigned to somehow, and then use that here. + // You'd also have to register it to clear that ref if/when the ship object is destroyed. + for(var/obj/effect/overmap/visitable/ship/S in SSshuttle.ships) + S.inertial_dampers -= src + holder = null + . = ..() \ No newline at end of file diff --git a/mods/content/inertia/inertia_failure.dm b/mods/content/inertia/inertia_failure.dm new file mode 100644 index 000000000000..9d9eb361e116 --- /dev/null +++ b/mods/content/inertia/inertia_failure.dm @@ -0,0 +1,42 @@ +// TODO: This should either be removed, or reworked to announce to specifically only the affected ship or its associated map. +/datum/event/inertial_damper + announceWhen = 5 + check_proc = /proc/inertial_dampener_event_can_fire + +/datum/event_container/moderate/New() + ..() + available_events += new /datum/event_meta( + EVENT_LEVEL_MODERATE, + "Inertial Damper Recalibration", + /datum/event/inertial_damper, + 75, + list(ASSIGNMENT_ENGINEER = 25) + ) + +/datum/event/inertial_damper/setup() + endWhen = rand(45, 120) + +/proc/inertial_dampener_event_can_fire() // Check if we have any ships that require dampers for this event to affect + for(var/obj/effect/overmap/visitable/ship/ship in SSshuttle.ships) + if(ship.needs_dampers) + return TRUE + return FALSE + +/datum/event/inertial_damper/announce() + command_announcement.Announce("Inertial damper calibration error. Please restrict thruster use. Recalibration cycle initiated...", "[location_name()] Inertial Damper Subsystem", zlevels = affecting_z) + +/datum/event/inertial_damper/start() + for(var/obj/machinery/inertial_damper/damper_machine in SSmachines.machinery) + damper_machine.damping_modifier += -5 //Gm/h + damper_machine.was_reset = FALSE + +/datum/event/inertial_damper/end() + var/display_announcement = FALSE + for(var/obj/machinery/inertial_damper/damper_machine in SSmachines.machinery) + damper_machine.damping_modifier = initial(damper_machine.damping_modifier) + if(!damper_machine.was_reset) + display_announcement = TRUE + break + + if(display_announcement) + command_announcement.Announce("Inertial dampers are again functioning within normal parameters. Sorry for any inconvenience.", "[location_name()] Inertial Damper Subsystem", zlevels = affecting_z) diff --git a/mods/content/inertia/inertial_damper.dm b/mods/content/inertia/inertial_damper.dm new file mode 100644 index 000000000000..638dadfd4e4e --- /dev/null +++ b/mods/content/inertia/inertial_damper.dm @@ -0,0 +1,190 @@ +/obj/machinery/inertial_damper + name = "inertial damper" + icon = 'mods/content/inertia/icons/inertial_damper.dmi' + desc = "An inertial damper, a very large machine that balances against engine thrust to prevent harm to the crew." + density = TRUE + icon_state = "damper_on" + + base_type = /obj/machinery/inertial_damper + construct_state = /decl/machine_construction/default/panel_closed + wires = /datum/wires/inertial_damper + uncreated_component_parts = null + stat_immune = FALSE + + idle_power_usage = 1 KILOWATTS + use_power = POWER_USE_ACTIVE + anchored = TRUE + + pixel_x = -32 + pixel_y = -32 + bound_x = -32 + bound_y = -32 + + var/datum/ship_inertial_damper/controller + + var/active = TRUE + + var/damping_strength = 1 //units of Gm/h + var/damping_modifier = 0 //modifier due to events + var/target_strength = 1 + var/delta = 0.01 + var/max_strength = 5 + var/power_draw + var/max_power_draw = 200 KILOWATTS + var/lastwarning = 0 + var/warned = FALSE + + var/was_reset = FALSE //if this inertial damper was fully turned off recently (zero damping strength, no power) + + var/hacked = FALSE + var/locked = FALSE + var/ai_control_disabled = FALSE + var/input_cut = FALSE + + var/current_overlay = null + var/width = 3 + var/height = 2 + + /// The cooldown between announcements that the inertial damping system is off. + var/const/WARNING_DELAY = 8 SECONDS + +/obj/machinery/inertial_damper/Initialize() + . = ..() + SetBounds() + update_nearby_tiles(locs) + controller = new(src) + + var/obj/effect/overmap/visitable/ship/ship = get_owning_overmap_object() + if(istype(ship)) + ship.inertial_dampers |= controller + + src.overlays += "activated" + +/obj/machinery/inertial_damper/Process() + ..() + if(active && !(stat & (NOPOWER | BROKEN)) && !input_cut) + delta = initial(delta) + power_draw = (damping_strength / max_strength) * max_power_draw + change_power_consumption(power_draw, POWER_USE_ACTIVE) + + // Provide a warning if our inertial damping level is decreasing past a threshold and we haven't already warned since someone last adjusted the setting + if(!warned && damping_strength < 0.3*initial(damping_strength) && target_strength < damping_strength && lastwarning - world.timeofday >= WARNING_DELAY) + warned = TRUE + lastwarning = world.timeofday + do_telecomms_announcement(src, "WARNING: Inertial dampening level dangerously low! All crew must be secured before firing thrusters!", "Inertial Damper Monitor") + else + delta = initial(delta) * 5 // rate of dampening strength decay is higher if we have no power + target_strength = 0 + if(!damping_strength) + damping_modifier = initial(damping_modifier) + was_reset = TRUE + change_power_consumption(0, POWER_USE_OFF) + + queue_icon_update() + + if(damping_strength != target_strength) + damping_strength = damping_strength > target_strength ? max(damping_strength - delta, target_strength) : min(damping_strength + delta, target_strength) + +/obj/machinery/inertial_damper/Destroy() + QDEL_NULL(controller) + update_nearby_tiles(locs) + return ..() + +/obj/machinery/inertial_damper/proc/toggle() + active = !active + update_icon() + return active + +/obj/machinery/inertial_damper/proc/is_on() + return active + +/// Returns either the true damping strength including modifiers (include_modifiers == TRUE), +/// or just the value the damper is set to (include_modifiers == FALSE). +/obj/machinery/inertial_damper/proc/get_damping_strength(var/include_modifiers) + if(hacked && !include_modifiers) + return initial(damping_strength) + return damping_strength + damping_modifier + +/obj/machinery/inertial_damper/proc/get_status() + return active ? "on" : "off" + +/obj/machinery/inertial_damper/on_update_icon() + ..() + icon_state = "damper_[get_status()]" + + var/overlay_state = null + if(!active && damping_strength == 0) + overlay_state = null //inactive and powered off + else if(damping_strength < initial(damping_strength)) + if(target_strength != damping_strength) + overlay_state = "startup" //lower than default strength and changing + else + overlay_state = "weak" //met our target but lower than default strength + else if(target_strength > damping_strength && damping_strength >= initial(damping_strength)) + overlay_state = "activating" //rising higher than default strength + else + overlay_state = "activated" //met our target higher than default strength + + if(overlay_state != current_overlay) + overlays.Cut() + if(overlay_state) + var/image/new_overlay_state = image(icon, overlay_state) + new_overlay_state.appearance_flags |= RESET_COLOR + overlays += new_overlay_state + current_overlay = overlay_state + +/obj/machinery/inertial_damper/proc/SetBounds() + bound_width = width * world.icon_size + bound_height = height * world.icon_size + if(bound_height != world.icon_size || bound_width != world.icon_size) + appearance_flags = /obj/machinery::appearance_flags & ~TILE_BOUND + +/obj/machinery/inertial_damper/interface_interact(var/mob/user) + ui_interact(user) + return TRUE + +/obj/machinery/inertial_damper/CanUseTopic(var/mob/user) + if(issilicon(user) && !Adjacent(user) && ai_control_disabled) + return STATUS_UPDATE + return ..() + +/obj/machinery/inertial_damper/OnTopic(user, href_list, datum/topic_state/state) + if(locked) + to_chat(user, SPAN_WARNING("\The [src]'s controls are not responding.")) + return TOPIC_NOACTION + + if(href_list["toggle"]) + toggle() + return TOPIC_REFRESH + + if(href_list["set_strength"]) + var/new_strength = input("Enter a new damper strength between 0 and [max_strength] Gm/h", "Modifying damper strength", get_damping_strength(TRUE)) as num + if(!(new_strength in 0 to max_strength)) + to_chat(user, SPAN_WARNING("That's not a valid damper strength.")) + warned = FALSE + return TOPIC_NOACTION + + warned = FALSE + target_strength = clamp(new_strength, 0, max_strength) + return TOPIC_REFRESH + + return TOPIC_NOACTION + +/obj/machinery/inertial_damper/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["online"] = is_on() + data["damping_strength"] = round(get_damping_strength(TRUE), 0.01) + data["max_strength"] = max_strength + data["hacked"] = hacked + data["power_usage"] = round(power_draw/1e3) + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "inertial_damper.tmpl", "Inertial Damper", 400, 400) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/inertial_damper/dismantle() + if((. = ..())) + update_nearby_tiles(locs) diff --git a/nano/templates/inertial_damper.tmpl b/mods/content/inertia/nano_templates/inertial_damper.tmpl similarity index 100% rename from nano/templates/inertial_damper.tmpl rename to mods/content/inertia/nano_templates/inertial_damper.tmpl diff --git a/mods/content/inertia/ship_inertia.dm b/mods/content/inertia/ship_inertia.dm new file mode 100644 index 000000000000..daf7764ba1a0 --- /dev/null +++ b/mods/content/inertia/ship_inertia.dm @@ -0,0 +1,42 @@ +/obj/effect/overmap/visitable/ship + /// Whether or not this ship throws mobs on acceleration if dampers are inactive. + var/needs_dampers = FALSE + /// A list of inertial damping controller datums associated with this ship. + var/list/datum/ship_inertial_damper/inertial_dampers = list() + /// The current damping strength from all inertial dampers, recalculated every tick in the ship's Process(). + var/tmp/damping_strength = null + +/obj/effect/overmap/visitable/ship/populate_sector_objects() + ..() + for(var/datum/ship_inertial_damper/damper_datum in global.ship_inertial_dampers) + if(check_ownership(damper_datum.holder)) + inertial_dampers |= damper_datum + +// Theoretically there's no need to recalculate this every tick, +// instead it should be recalculated any time damping strength changes +// based only on the damper that changed. +/obj/effect/overmap/visitable/ship/Process(wait, tick) + . = ..() + damping_strength = 0 + for(var/datum/ship_inertial_damper/damper_datum in inertial_dampers) + damping_strength += damper_datum.get_damping_strength(TRUE) + +/obj/effect/overmap/visitable/ship/adjust_speed(n_x, n_y) + . = ..() + var/magnitude = norm(n_x, n_y) + var/inertia_dir = magnitude >= 0 ? turn(fore_dir, 180) : fore_dir + var/inertia_strength = magnitude * 1e3 + if(needs_dampers && damping_strength < inertia_strength) + var/list/areas_by_name = area_repository.get_areas_by_z_level() + for(var/area_name in areas_by_name) + var/area/the_area = areas_by_name[area_name] + if(area_belongs_to_zlevels(the_area, map_z)) + the_area.throw_unbuckled_occupants(inertia_strength+2, inertia_strength, inertia_dir) + +// Add additional data to the engine console. +/obj/machinery/computer/ship/engines/modify_ship_ui_data(list/ui_data) + var/damping_strength = 0 + for(var/datum/ship_inertial_damper/inertia_controller in linked.inertial_dampers) + damping_strength += inertia_controller.holder.get_damping_strength(FALSE) // get only the level it's set to, not the actual level + ui_data["damping_strength"] = damping_strength + ui_data["needs_dampers"] = linked.needs_dampers \ No newline at end of file diff --git a/mods/content/inertia/supplies.dm b/mods/content/inertia/supplies.dm new file mode 100644 index 000000000000..fbe975ab7cb9 --- /dev/null +++ b/mods/content/inertia/supplies.dm @@ -0,0 +1,6 @@ +/decl/hierarchy/supply_pack/engineering/inertial_damper + name = "Equipment - inertial damper construction kit" + contains = list(/obj/item/stock_parts/circuitboard/inertial_damper, /obj/item/stock_parts/capacitor, /obj/item/stock_parts/micro_laser, /obj/item/stock_parts/console_screen) + containertype = /obj/structure/closet/crate/secure + containername = "inertial damper construction kit crate" + access = access_engine \ No newline at end of file diff --git a/mods/content/inertia/wires.dm b/mods/content/inertia/wires.dm new file mode 100644 index 000000000000..4a850ae4e20d --- /dev/null +++ b/mods/content/inertia/wires.dm @@ -0,0 +1,38 @@ +/datum/wires/inertial_damper + holder_type = /obj/machinery/inertial_damper + wire_count = 5 + descriptions = list( + new /datum/wire_description(DAMPER_WIRE_POWER, "This wire seems to be carrying a heavy current.", SKILL_EXPERT), + new /datum/wire_description(DAMPER_WIRE_HACK, "This wire seems designed to adjust the data output cache."), + new /datum/wire_description(DAMPER_WIRE_CONTROL, "This wire connects to the main control panel."), + new /datum/wire_description(DAMPER_WIRE_AICONTROL, "This wire connects to automated control systems.") + ) + var/const/DAMPER_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore. + var/const/DAMPER_WIRE_HACK = 2 // Pulse to hack the dampener, causing false display on engine consoles. Cut to unhack. Mend does nothing. + var/const/DAMPER_WIRE_CONTROL = 4 // Cut to lock controls. Mend to unlock them. Pulse does nothing. + var/const/DAMPER_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore. + +/datum/wires/inertial_damper/CanUse() + var/obj/machinery/inertial_damper/damper_machine = holder + if(damper_machine.panel_open) + return TRUE + return FALSE + +/datum/wires/inertial_damper/UpdateCut(index, mended) + var/obj/machinery/inertial_damper/damper_machine = holder + switch(index) + if(DAMPER_WIRE_POWER) + damper_machine.input_cut = !mended + if(DAMPER_WIRE_HACK) + if(!mended) + damper_machine.hacked = FALSE + if(DAMPER_WIRE_CONTROL) + damper_machine.locked = !mended + if(DAMPER_WIRE_AICONTROL) + damper_machine.ai_control_disabled = !mended + +/datum/wires/inertial_damper/UpdatePulsed(var/index) + var/obj/machinery/inertial_damper/damper_machine = holder + switch(index) + if(DAMPER_WIRE_HACK) + damper_machine.hacked = TRUE \ No newline at end of file diff --git a/mods/content/integrated_electronics/_integrated_electronics.dm b/mods/content/integrated_electronics/_integrated_electronics.dm new file mode 100644 index 000000000000..5da63a6e255b --- /dev/null +++ b/mods/content/integrated_electronics/_integrated_electronics.dm @@ -0,0 +1,45 @@ +#define IC_TOPIC_UNHANDLED 0 +#define IC_TOPIC_HANDLED 1 +#define IC_TOPIC_REFRESH 2 +#define IC_FLAG_CAN_FIRE 1 + +#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 BITFLAG(0) // If the circuit can move the assembly +#define IC_ACTION_COMBAT BITFLAG(1) // If the circuit can cause harm +#define IC_ACTION_LONG_RANGE BITFLAG(2) // If the circuit communicate with something outside of the assembly + +// extra format type just for ICs +#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 + +/decl/modpack/integrated_electronics + name = "Custom Circuits Content" diff --git a/mods/content/integrated_electronics/_integrated_electronics.dme b/mods/content/integrated_electronics/_integrated_electronics.dme new file mode 100644 index 000000000000..725bb52ed49e --- /dev/null +++ b/mods/content/integrated_electronics/_integrated_electronics.dme @@ -0,0 +1,53 @@ +#ifndef CONTENT_PACK_CIRCUITS +#define CONTENT_PACK_CIRCUITS +// BEGIN_INCLUDE +#include "_integrated_electronics.dm" +#include "circuit_serialization.dm" +#include "circuit_tests.dm" +#include "fabricator_designs.dm" +#include "helpers.dm" +#include "overrides.dm" +#include "random.dm" +#include "toggle_circuits_secret.dm" +#include "assemblies\_assemblies.dm" +#include "components\_integrated_circuit.dm" +#include "components\access.dm" +#include "components\arithmetic.dm" +#include "components\converters.dm" +#include "components\data_transfer.dm" +#include "components\filter.dm" +#include "components\input.dm" +#include "components\lists.dm" +#include "components\logic.dm" +#include "components\manipulation.dm" +#include "components\memory.dm" +#include "components\output.dm" +#include "components\passive.dm" +#include "components\power.dm" +#include "components\power_passive.dm" +#include "components\reagents.dm" +#include "components\smart.dm" +#include "components\time.dm" +#include "components\trig.dm" +#include "pins\_pins.dm" +#include "pins\boolean_pin.dm" +#include "pins\char_pin.dm" +#include "pins\color_pin.dm" +#include "pins\dir_pin.dm" +#include "pins\index_pin.dm" +#include "pins\list_pin.dm" +#include "pins\number_pin.dm" +#include "pins\ref_pin.dm" +#include "pins\string_pin.dm" +#include "prefab\prefab.dm" +#include "prefab\prefabs.dm" +#include "prefab\test\testprefabs.dm" +#include "subsystems\circuit.dm" +#include "subsystems\circuit_component.dm" +#include "tools\analyzer.dm" +#include "tools\debugger.dm" +#include "tools\detailer.dm" +#include "tools\printer.dm" +#include "tools\wirer.dm" +// END_INCLUDE +#endif diff --git a/mods/content/integrated_electronics/assemblies/_assemblies.dm b/mods/content/integrated_electronics/assemblies/_assemblies.dm new file mode 100644 index 000000000000..c129dca73355 --- /dev/null +++ b/mods/content/integrated_electronics/assemblies/_assemblies.dm @@ -0,0 +1,740 @@ +#define IC_MAX_SIZE_BASE 25 +#define IC_COMPLEXITY_BASE 75 + +/obj/item/electronic_assembly + name = "electronic assembly" + desc = "It's a case, for building small electronics with." + w_class = ITEM_SIZE_SMALL + icon = 'icons/obj/assemblies/electronic_setups.dmi' + icon_state = "setup_small" + item_flags = ITEM_FLAG_NO_BLUDGEON + matter = list() // To be filled later + pass_flags = 0 + anchored = FALSE + obj_flags = OBJ_FLAG_ANCHORABLE + max_health = 30 + var/list/assembly_components = list() + var/list/ckeys_allowed_to_scan = list() // Players who built the circuit can scan it as a ghost. + var/max_components = IC_MAX_SIZE_BASE + var/max_complexity = IC_COMPLEXITY_BASE + var/opened = TRUE + var/obj/item/cell/battery // Internal cell which most circuits need to work. + var/cell_type = /obj/item/cell + var/circuit_flags = 0 + var/ext_next_use = 0 + var/weakref/collw + var/allowed_circuit_action_flags = IC_ACTION_COMBAT | IC_ACTION_LONG_RANGE //which circuit flags are allowed + var/creator // circuit creator if any + var/interact_page = 0 + var/components_per_page = 5 + var/detail_color = COLOR_ASSEMBLY_BLACK + var/list/color_whitelist = list( //This is just for checking that hacked colors aren't in the save data. + COLOR_ASSEMBLY_BLACK, + COLOR_GRAY40, + COLOR_ASSEMBLY_BGRAY, + COLOR_ASSEMBLY_WHITE, + COLOR_ASSEMBLY_RED, + COLOR_ASSEMBLY_ORANGE, + COLOR_ASSEMBLY_BEIGE, + COLOR_ASSEMBLY_BROWN, + COLOR_ASSEMBLY_GOLD, + COLOR_ASSEMBLY_YELLOW, + COLOR_ASSEMBLY_GURKHA, + COLOR_ASSEMBLY_LGREEN, + COLOR_ASSEMBLY_GREEN, + COLOR_ASSEMBLY_LBLUE, + COLOR_ASSEMBLY_BLUE, + COLOR_ASSEMBLY_PURPLE + ) + +/obj/item/electronic_assembly/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(obj_flags & OBJ_FLAG_ANCHORABLE) + to_chat(user, "The anchoring bolts [anchored ? "are" : "can be"] wrenched in place and the maintenance panel [opened ? "can be" : "is"] screwed in place.") + else + to_chat(user, "The maintenance panel [opened ? "can be" : "is"] screwed in place.") + if(is_damaged()) + if(get_percent_health() <= 50) + to_chat(user,"It looks pretty beat up.") + else + to_chat(user, "It's got a few dents in it.") + + if((isobserver(user) && ckeys_allowed_to_scan[user.ckey]) || check_rights(R_ADMIN, 0, user)) + to_chat(user, "You can scan this circuit."); + +/obj/item/electronic_assembly/examined_by(mob/user, distance, infix, suffix) + . = ..() + for(var/obj/item/integrated_circuit/component as anything in assembly_components) + component.external_examine(user) + if(opened) + component.internal_examine(user) + if(opened) + interact(user) + +/obj/item/electronic_assembly/check_health(lastdamage, lastdamtype, lastdamflags, consumed) + if(!can_take_damage()) + return + if(current_health < 1) + visible_message(SPAN_DANGER("\The [src] falls to pieces!")) + physically_destroyed() + else if((get_percent_health() < 15) && prob(5)) + visible_message(SPAN_DANGER("\The [src] starts to break apart!")) + +/obj/item/electronic_assembly/proc/check_interactivity(mob/user) + return (!user.incapacitated() && CanUseTopic(user) && user_can_attack_with(user)) + +/obj/item/electronic_assembly/GetAccess() + . = list() + for(var/obj/item/integrated_circuit/output/O in assembly_components) + var/o_access = O.GetAccess() + . |= o_access + +/obj/item/electronic_assembly/Bump(atom/AM) + collw = weakref(AM) + .=..() + if(istype(AM, /obj/machinery/door/airlock) || istype(AM, /obj/machinery/door/window)) + var/obj/machinery/door/D = AM + if(D.check_access(src)) + D.open() + +/obj/item/electronic_assembly/create_matter() + ..() + LAZYSET(matter, /decl/material/solid/metal/steel, round((max_complexity + max_components) / 4) * SScircuit.cost_multiplier) + +/obj/item/electronic_assembly/Initialize() + . = ..() + START_PROCESSING(SScircuit, src) + +/obj/item/electronic_assembly/Destroy() + STOP_PROCESSING(SScircuit, src) + for(var/circ in assembly_components) + remove_component(circ) + qdel(circ) + return ..() + +/obj/item/electronic_assembly/Process() + // First we generate power. + for(var/obj/item/integrated_circuit/passive/power/P in assembly_components) + P.make_energy() + + var/power_failure = FALSE + if(get_health_ratio() < 0.5 && prob(5)) + visible_message(SPAN_WARNING("\The [src] shudders and sparks.")) + power_failure = TRUE + // Now spend it. + for(var/obj/item/integrated_circuit/component as anything in assembly_components) + if(component.power_draw_idle) + if(power_failure || !component.draw_idle_power()) + component.power_fail() + +/obj/item/electronic_assembly/receive_mouse_drop(atom/dropping, mob/user, params) + . = ..() + if(!. && user == dropping) + interact(user) + return TRUE + +/obj/item/electronic_assembly/interact(mob/user) + if(!check_interactivity(user)) + return + + if(opened) + open_interact(user) + closed_interact(user) + +/obj/item/electronic_assembly/proc/closed_interact(mob/user) + var/HTML = list() + HTML += "[src.name]" + HTML += "
    \[Refresh\]" + HTML += "

    " + + var/listed_components = FALSE + for(var/obj/item/integrated_circuit/circuit in contents) + var/list/topic_data = circuit.get_topic_data(user) + if(topic_data) + listed_components = TRUE + HTML += "[circuit.displayed_name]: " + if(topic_data.len != 1) + HTML += "
    " + for(var/entry in topic_data) + var/href = topic_data[entry] + if(href) + HTML += "[entry]" + else + HTML += entry + HTML += "
    " + HTML += "
    " + HTML += "" + + if(listed_components) + show_browser(user, jointext(HTML,null), "window=closed-assembly-\ref[src];size=600x350;border=1;can_resize=1;can_close=1;can_minimize=1") + +/obj/item/electronic_assembly/get_assembly_detail_color() + return detail_color + +/obj/item/electronic_assembly/proc/open_interact(mob/user) + var/total_part_size = return_total_size() + var/total_complexity = return_total_complexity() + var/list/HTML = list() + + HTML += "[name]" + + HTML += "\[Refresh\] | \[Rename\]
    " + HTML += "[total_part_size]/[max_components] space taken up in the assembly.
    " + HTML += "[total_complexity]/[max_complexity] complexity in the assembly.
    " + if(battery) + HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. \[Remove\]" + else + HTML += "No power cell detected!" + + if(length(assembly_components)) + HTML += "

    " + HTML += "Components:
    " + + var/start_index = ((components_per_page * interact_page) + 1) + for(var/i = start_index to min(length(assembly_components), start_index + (components_per_page - 1))) + var/obj/item/integrated_circuit/circuit = assembly_components[i] + HTML += "\[ [i] \] | " + HTML += "\[R\] | " + if(circuit.removable) + HTML += "\[-\] | " + else + HTML += "\[-\] | " + HTML += "[circuit.displayed_name]" + HTML += "
    " + + if(length(assembly_components) > components_per_page) + HTML += "
    \[" + for(var/i = 1 to ceil(length(assembly_components)/components_per_page)) + if((i-1) == interact_page) + HTML += " [i]" + else + HTML += " [i]" + HTML += " \]" + + HTML += "" + show_browser(user, jointext(HTML, null), "window=assembly-\ref[src];size=655x350;border=1;can_resize=1;can_close=1;can_minimize=1") + +/obj/item/electronic_assembly/Topic(href, href_list) + if(href_list["ghostscan"]) + if((isobserver(usr) && ckeys_allowed_to_scan[usr.ckey]) || check_rights(R_ADMIN,0,usr)) + if(assembly_components.len) + var/saved = "On circuit printers with cloning enabled, you may use the code below to clone the circuit:

    [SScircuit.save_electronic_assembly(src)]" + show_browser(usr, saved, "window=circuit_scan;size=500x600;border=1;can_resize=1;can_close=1;can_minimize=1") + else + to_chat(usr, "The circuit is empty!") + return 0 + + if(isobserver(usr)) + return + + if(!check_interactivity(usr)) + return 0 + + if(href_list["select_page"]) + interact_page = text2num(href_list["select_page"]) + + if(href_list["rename"]) + rename(usr) + + if(href_list["remove_cell"]) + if(!battery) + to_chat(usr, "There's no power cell to remove from \the [src].") + else + battery.dropInto(loc) + playsound(src, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(usr, "You pull \the [battery] out of \the [src]'s power supplier.") + battery = null + + if(href_list["component"]) + var/obj/item/integrated_circuit/component = locate(href_list["component"]) in assembly_components + if(component) + // Builtin components are not supposed to be removed or rearranged + if(!component.removable) + return 0 + + add_allowed_scanner(usr.ckey) + + var/current_pos = assembly_components.Find(component) + + if(href_list["remove"]) + try_remove_component(component, usr) + + else + // Adjust the position + if(href_list["set_slot"]) + var/selected_slot = input("Select a new slot", "Select slot", current_pos) as null|num + if(!check_interactivity(usr)) + return 0 + if(selected_slot < 1 || selected_slot > length(assembly_components)) + return 0 + + assembly_components.Remove(component) + assembly_components.Insert(selected_slot, component) + + + interact(usr) // To refresh the UI. + +/obj/item/electronic_assembly/proc/rename() + var/mob/M = usr + if(!check_interactivity(M)) + return + var/input = input("What do you want to name this?", "Rename", src.name) as null|text + input = sanitize_name(input, allow_numbers = TRUE, force_first_letter_uppercase = FALSE) + if(!check_interactivity(M)) + return + if(!QDELETED(src) && input) + to_chat(M, "The machine now has a label reading '[input]'.") + name = input + +/obj/item/electronic_assembly/proc/add_allowed_scanner(ckey) + ckeys_allowed_to_scan[ckey] = TRUE + +/obj/item/electronic_assembly/proc/can_move() + return FALSE + +/obj/item/electronic_assembly/on_update_icon() + . = ..() + if(opened) + icon_state = initial(icon_state) + "-open" + else + icon_state = initial(icon_state) + if(detail_color == COLOR_ASSEMBLY_BLACK) //Black colored overlay looks almost but not exactly like the base sprite, so just cut the overlay and avoid it looking kinda off. + return + add_overlay(overlay_image('icons/obj/assemblies/electronic_setups.dmi', "[icon_state]-color", detail_color)) + +//This only happens when this EA is loaded via the printer +/obj/item/electronic_assembly/proc/post_load() + for(var/obj/item/integrated_circuit/component as anything in assembly_components) + component.on_data_written() + +/obj/item/electronic_assembly/proc/return_total_complexity() + . = 0 + var/obj/item/integrated_circuit/part + for(var/p in assembly_components) + part = p + . += part.complexity + +/obj/item/electronic_assembly/proc/return_total_size() + . = 0 + var/obj/item/integrated_circuit/part + for(var/p in assembly_components) + part = p + . += part.size + +// Returns true if the circuit made it inside. +/obj/item/electronic_assembly/proc/try_add_component(obj/item/integrated_circuit/component, mob/user) + if(!opened) + to_chat(user, "\The [src]'s hatch is closed, you can't put anything inside.") + return FALSE + + if(component.w_class > w_class) + to_chat(user, "\The [component] is way too big to fit into \the [src].") + return FALSE + + var/total_part_size = return_total_size() + var/total_complexity = return_total_complexity() + + if((total_part_size + component.size) > max_components) + to_chat(user, "You can't seem to add the '[component]', as there's insufficient space.") + return FALSE + if((total_complexity + component.complexity) > max_complexity) + to_chat(user, "You can't seem to add the '[component]', since this setup's too complicated for the case.") + return FALSE + if((allowed_circuit_action_flags & component.action_flags) != component.action_flags) + to_chat(user, "You can't seem to add the '[component]', since the case doesn't support the circuit type.") + return FALSE + + if(!user.try_unequip(component,src)) + return FALSE + + to_chat(user, "You slide [component] inside [src].") + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + add_allowed_scanner(user.ckey) + + add_component(component) + return TRUE + + +// Actually puts the circuit inside, doesn't perform any checks. +/obj/item/electronic_assembly/proc/add_component(obj/item/integrated_circuit/component) + component.forceMove(get_object()) + component.assembly = src + assembly_components |= component + component.added_to_assembly(src) + + +/obj/item/electronic_assembly/proc/try_remove_component(obj/item/integrated_circuit/component, mob/user, silent) + if(!opened) + if(!silent) + to_chat(user, "[src]'s hatch is closed, so you can't fiddle with the internal components.") + return FALSE + + if(!component.removable) + if(!silent) + to_chat(user, "[src] is permanently attached to the case.") + return FALSE + + remove_component(component) + if(!silent) + to_chat(user, "You pop \the [component] out of the case, and slide it out.") + playsound(src, 'sound/items/crowbar.ogg', 50, 1) + user.put_in_hands(component) + add_allowed_scanner(user.ckey) + + // Make sure we're not on an invalid page + interact_page = clamp(interact_page, 0, ceil(length(assembly_components)/components_per_page)-1) + + return TRUE + +// Actually removes the component, doesn't perform any checks. +/obj/item/electronic_assembly/proc/remove_component(obj/item/integrated_circuit/component) + component.disconnect_all() + component.dropInto(loc) + component.assembly = null + assembly_components.Remove(component) + component.removed_from_assembly(src) + + +/obj/item/electronic_assembly/afterattack(atom/target, mob/user, proximity) + . = ..() + for(var/obj/item/integrated_circuit/input/S in assembly_components) + if(S.sense(target,user,proximity)) + if(proximity) + visible_message("\The [user] waves \the [src] around \the [target].") + else + visible_message("\The [user] points \the [src] towards \the [target].") + + +/obj/item/electronic_assembly/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/integrated_circuit)) + if(!user.can_unequip_item(used_item)) + return FALSE + if(try_add_component(used_item, user)) + return TRUE + else + for(var/obj/item/integrated_circuit/input/S in assembly_components) + S.attackby_react(used_item, user, user.get_intent()) + return ..() + else if(IS_MULTITOOL(used_item) || istype(used_item, /obj/item/wirer) || istype(used_item, /obj/item/debugger)) + if(opened) + interact(user) + return TRUE + else + to_chat(user, "[src]'s hatch is closed, so you can't fiddle with the internal components.") + for(var/obj/item/integrated_circuit/input/S in assembly_components) + S.attackby_react(used_item, user, user.get_intent()) + return ..() + else if(istype(used_item, /obj/item/cell)) + if(!opened) + to_chat(user, "[src]'s hatch is closed, so you can't access \the [src]'s power supplier.") + for(var/obj/item/integrated_circuit/input/S in assembly_components) + S.attackby_react(used_item, user, user.get_intent()) + return ..() + if(battery) + to_chat(user, "[src] already has \a [battery] installed. Remove it first if you want to replace it.") + for(var/obj/item/integrated_circuit/input/S in assembly_components) + S.attackby_react(used_item, user, user.get_intent()) + return ..() + if(!istype(used_item, cell_type)) + to_chat(user, SPAN_WARNING("\The [src] doesn't accept that type of cell.")) + return TRUE + var/obj/item/cell/cell = used_item + if(user.try_unequip(used_item,loc)) + user.drop_from_inventory(used_item, loc) + cell.forceMove(src) + battery = cell + playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) + to_chat(user, "You slot \the [cell] inside \the [src]'s power supplier.") + return TRUE + return FALSE + else if(istype(used_item, /obj/item/detailer)) + var/obj/item/detailer/D = used_item + detail_color = D.detail_color + update_icon() + else if(IS_SCREWDRIVER(used_item)) + var/hatch_locked = FALSE + for(var/obj/item/integrated_circuit/manipulation/hatchlock/H in assembly_components) + // If there's more than one hatch lock, only one needs to be enabled for the assembly to be locked + if(H.lock_enabled) + hatch_locked = TRUE + break + + if(hatch_locked) + to_chat(user, "The screws are covered by a locking mechanism!") + return FALSE + + playsound(src, 'sound/items/Screwdriver.ogg', 25) + opened = !opened + to_chat(user, "You [opened ? "open" : "close"] the maintenance hatch of [src].") + update_icon() + return TRUE + + else if(IS_COIL(used_item)) + var/obj/item/stack/cable_coil/C = used_item + if(is_damaged() && do_after(user, 10, src) && C.use(1)) + user.visible_message("\The [user] patches up \the [src].") + current_health = min(get_max_health(), current_health + 5) + return TRUE + + else if(!user.check_intent(I_FLAG_HARM)) + for(var/obj/item/integrated_circuit/input/S in assembly_components) + S.attackby_react(used_item, user, user.get_intent()) + return TRUE + + return ..() //Handle weapon attacks and etc + +/obj/item/electronic_assembly/attack_self(mob/user) + interact(user) + +/obj/item/electronic_assembly/bullet_act(var/obj/item/projectile/P) + take_damage(P.damage, P.atom_damage_type) + +/obj/item/electronic_assembly/emp_act(severity) + . = ..() + for(var/atom/movable/thing as anything in get_contained_external_atoms()) + thing.emp_act(severity) + +// Returns true if power was successfully drawn. +/obj/item/electronic_assembly/proc/draw_power(amount) + if(battery && battery.use(amount * CELLRATE)) + return TRUE + return FALSE + +// Ditto for giving. +/obj/item/electronic_assembly/proc/give_power(amount) + if(battery && battery.give(amount * CELLRATE)) + return TRUE + return FALSE + + +// Returns the object that is supposed to be used in attack messages, location checks, etc. +// Override in children for special behavior. +/obj/item/electronic_assembly/proc/get_object() + return src + +/obj/item/electronic_assembly/attack_hand(mob/user) + if(!anchored) + return ..() + attack_self(user) + return TRUE + +/obj/item/electronic_assembly/default //The /default electronic_assemblys are to allow the introduction of the new naming scheme without breaking old saves. + name = "type-a electronic assembly" + +/obj/item/electronic_assembly/calc + name = "type-b electronic assembly" + icon_state = "setup_small_calc" + desc = "It's a case, for building small electronics with. This one resembles a pocket calculator." + +/obj/item/electronic_assembly/clam + name = "type-c electronic assembly" + icon_state = "setup_small_clam" + desc = "It's a case, for building small electronics with. This one has a clamshell design." + +/obj/item/electronic_assembly/simple + name = "type-d electronic assembly" + icon_state = "setup_small_simple" + desc = "It's a case, for building small electronics with. This one has a simple design." + +/obj/item/electronic_assembly/hook + name = "type-e electronic assembly" + icon_state = "setup_small_hook" + desc = "It's a case, for building small electronics with. This one looks like it has a belt clip." + slot_flags = SLOT_LOWER_BODY + +/obj/item/electronic_assembly/pda + name = "type-f electronic assembly" + icon_state = "setup_small_pda" + desc = "It's a case, for building small electronics with. This one resembles a PDA." + slot_flags = SLOT_LOWER_BODY | SLOT_ID + +/obj/item/electronic_assembly/medium + name = "electronic mechanism" + icon_state = "setup_medium" + desc = "It's a case, for building medium-sized electronics with." + w_class = ITEM_SIZE_NORMAL + max_components = IC_MAX_SIZE_BASE * 2 + max_complexity = IC_COMPLEXITY_BASE * 2 + max_health = 20 + +/obj/item/electronic_assembly/medium/default + name = "type-a electronic mechanism" + +/obj/item/electronic_assembly/medium/box + name = "type-b electronic mechanism" + icon_state = "setup_medium_box" + desc = "It's a case, for building medium-sized electronics with. This one has a boxy design." + +/obj/item/electronic_assembly/medium/clam + name = "type-c electronic mechanism" + icon_state = "setup_medium_clam" + desc = "It's a case, for building medium-sized electronics with. This one has a clamshell design." + +/obj/item/electronic_assembly/medium/medical + name = "type-d electronic mechanism" + icon_state = "setup_medium_med" + desc = "It's a case, for building medium-sized electronics with. This one resembles some type of medical apparatus." + +/obj/item/electronic_assembly/medium/gun + name = "type-e electronic mechanism" + icon_state = "setup_medium_gun" + item_state = "circuitgun" + desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, if you're feeling optimistic. It can fire guns and throw items while the user is holding it." + circuit_flags = IC_FLAG_CAN_FIRE + obj_flags = OBJ_FLAG_ANCHORABLE + +/obj/item/electronic_assembly/medium/radio + name = "type-f electronic mechanism" + icon_state = "setup_medium_radio" + desc = "It's a case, for building medium-sized electronics with. This one resembles an old radio." + +/obj/item/electronic_assembly/large + name = "electronic machine" + icon_state = "setup_large" + desc = "It's a case, for building large electronics with." + w_class = ITEM_SIZE_LARGE + max_components = IC_MAX_SIZE_BASE * 4 + max_complexity = IC_COMPLEXITY_BASE * 4 + max_health = 30 + +/obj/item/electronic_assembly/large/default + name = "type-a electronic machine" + +/obj/item/electronic_assembly/large/scope + name = "type-b electronic machine" + icon_state = "setup_large_scope" + desc = "It's a case, for building large electronics with. This one resembles an oscilloscope." + +/obj/item/electronic_assembly/large/terminal + name = "type-c electronic machine" + icon_state = "setup_large_terminal" + desc = "It's a case, for building large electronics with. This one resembles a computer terminal." + +/obj/item/electronic_assembly/large/arm + name = "type-d electronic machine" + icon_state = "setup_large_arm" + desc = "It's a case, for building large electronics with. This one resembles a robotic arm." + +/obj/item/electronic_assembly/large/tall + name = "type-e electronic machine" + icon_state = "setup_large_tall" + desc = "It's a case, for building large electronics with. This one has a tall design." + +/obj/item/electronic_assembly/large/industrial + name = "type-f electronic machine" + icon_state = "setup_large_industrial" + desc = "It's a case, for building large electronics with. This one resembles some kind of industrial machinery." + +/obj/item/electronic_assembly/drone + name = "electronic drone" + icon_state = "setup_drone" + desc = "It's a case, for building mobile electronics with." + w_class = ITEM_SIZE_LARGE + max_components = IC_MAX_SIZE_BASE * 3 + max_complexity = IC_COMPLEXITY_BASE * 3 + allowed_circuit_action_flags = IC_ACTION_MOVEMENT | IC_ACTION_COMBAT | IC_ACTION_LONG_RANGE + circuit_flags = 0 + obj_flags = 0 //Not anchorable + max_health = 50 + +/obj/item/electronic_assembly/drone/can_move() + return TRUE + +/obj/item/electronic_assembly/drone/default + name = "type-a electronic drone" + +/obj/item/electronic_assembly/drone/arms + name = "type-b electronic drone" + icon_state = "setup_drone_arms" + desc = "It's a case, for building mobile electronics with. This one is armed and dangerous." + +/obj/item/electronic_assembly/drone/secbot + name = "type-c electronic drone" + icon_state = "setup_drone_secbot" + desc = "It's a case, for building mobile electronics with. This one resembles a Securitron." + +/obj/item/electronic_assembly/drone/medbot + name = "type-d electronic drone" + icon_state = "setup_drone_medbot" + desc = "It's a case, for building mobile electronics with. This one resembles a Medibot." + +/obj/item/electronic_assembly/drone/genbot + name = "type-e electronic drone" + icon_state = "setup_drone_genbot" + desc = "It's a case, for building mobile electronics with. This one has a generic bot design." + +/obj/item/electronic_assembly/drone/android + name = "type-f electronic drone" + icon_state = "setup_drone_android" + desc = "It's a case, for building mobile electronics with. This one has a hominoid design." + +/obj/item/electronic_assembly/wallmount + name = "wall-mounted electronic assembly" + icon_state = "setup_wallmount_medium" + desc = "It's a case, for building medium-sized electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on." + w_class = ITEM_SIZE_NORMAL + max_components = IC_MAX_SIZE_BASE * 2 + max_complexity = IC_COMPLEXITY_BASE * 2 + max_health = 10 + +/obj/item/electronic_assembly/wallmount/afterattack(var/atom/a, var/mob/user, var/proximity) + if(proximity && istype(a ,/turf) && a.density) + mount_assembly(a,user) + +/obj/item/electronic_assembly/wallmount/heavy + name = "heavy wall-mounted electronic assembly" + icon_state = "setup_wallmount_large" + desc = "It's a case, for building large electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on." + w_class = ITEM_SIZE_LARGE + max_components = IC_MAX_SIZE_BASE * 4 + max_complexity = IC_COMPLEXITY_BASE * 4 + +/obj/item/electronic_assembly/wallmount/light + name = "light wall-mounted electronic assembly" + icon_state = "setup_wallmount_small" + desc = "It's a case, for building small electronics with. It has a magnetized backing to allow it to stick to walls, but you'll still need to wrench the anchoring bolts in place to keep it on." + w_class = ITEM_SIZE_SMALL + max_components = IC_MAX_SIZE_BASE + max_complexity = IC_COMPLEXITY_BASE + +/obj/item/electronic_assembly/on_picked_up() + transform = null //Reset the matrix. + +/obj/item/electronic_assembly/wallmount/proc/mount_assembly(turf/on_wall, mob/user) //Yeah, this is admittedly just an abridged and kitbashed version of the wallframe attach procs. + var/ndir = get_dir(on_wall, user) + if(!(ndir in global.cardinal)) + return + var/turf/T = get_turf(user) + if(T.density) + to_chat(user, "You cannot place [src] on this spot!") + return + if(gotwallitem(T, ndir)) + to_chat(user, "There's already an item on this wall!") + return + playsound(src.loc, 'sound/machines/click.ogg', 75, 1) + user.visible_message("[user.name] attaches [src] to the wall.", + "You attach [src] to the wall.", + "You hear clicking.") + if(user.try_unequip(src,T)) + var/matrix/M = matrix() + switch(ndir) + if(NORTH) + default_pixel_y = -32 + default_pixel_x = 0 + M.Turn(180) + if(SOUTH) + default_pixel_y = 21 + default_pixel_x = 0 + if(EAST) + default_pixel_x = -27 + default_pixel_y = 0 + M.Turn(270) + if(WEST) + default_pixel_x = 27 + default_pixel_y = 0 + M.Turn(90) + reset_offsets(0) + transform = M + +#undef IC_MAX_SIZE_BASE +#undef IC_COMPLEXITY_BASE diff --git a/mods/content/integrated_electronics/circuit_serialization.dm b/mods/content/integrated_electronics/circuit_serialization.dm new file mode 100644 index 000000000000..11eb269e0520 --- /dev/null +++ b/mods/content/integrated_electronics/circuit_serialization.dm @@ -0,0 +1,368 @@ +// Helpers for saving/loading integrated circuits. + + +// Saves type, modified name and modified inputs (if any) to a list +// The list is converted to JSON down the line. +//"Special" is not verified at any point except for by the circuit itself. +/obj/item/integrated_circuit/proc/save() + var/list/component_params = list() + var/init_name = initial(name) + + // Save initial name used for differentiating assemblies + component_params["type"] = init_name + + // Save the modified name. + if(init_name != displayed_name) + component_params["name"] = displayed_name + + // Saving input values + if(length(inputs)) + var/list/saved_inputs = list() + + for(var/index in 1 to inputs.len) + var/datum/integrated_io/input = inputs[index] + + // Don't waste space saving the default values + if(input.data == initial(input.data)) + continue + + var/list/input_value = list(index, FALSE, input.data) + // Index, Type, Value + // FALSE is default type used for num/text/list/null + // TODO: support for special input types, such as internal refs and maybe typepaths + + if(islist(input.data) || isnum(input.data) || istext(input.data) || isnull(input.data)) + saved_inputs.Add(list(input_value)) + + if(saved_inputs.len) + component_params["inputs"] = saved_inputs + + var/special = save_special() + if(!isnull(special)) + component_params["special"] = special + + return component_params + +/obj/item/integrated_circuit/proc/save_special() + return + +// Verifies a list of component parameters +// Returns null on success, error name on failure +/obj/item/integrated_circuit/proc/verify_save(list/component_params) + var/init_name = initial(name) + // Validate name + if(component_params["name"]) + sanitize_name(component_params["name"],allow_numbers=TRUE,force_first_letter_uppercase = FALSE) + // Validate input values + if(component_params["inputs"]) + var/list/loaded_inputs = component_params["inputs"] + if(!islist(loaded_inputs)) + return "Malformed input values list at [init_name]." + + var/inputs_amt = length(inputs) + + // Too many inputs? Inputs for input-less component? This is not good. + if(!inputs_amt || inputs_amt < length(loaded_inputs)) + return "Input values list out of bounds at [init_name]." + + for(var/list/input in loaded_inputs) + if(input.len != 3) + return "Malformed input data at [init_name]." + + var/input_id = input[1] + var/input_type = input[2] + //var/input_value = input[3] + + // No special type support yet. + if(input_type) + return "Unidentified input type at [init_name]!" + // TODO: support for special input types, such as typepaths and internal refs + + // Input ID is a list index, make sure it's sane. + if(!isnum(input_id) || input_id % 1 || input_id > inputs_amt || input_id < 1) + return "Invalid input index at [init_name]." + + +// Loads component parameters from a list +// Doesn't verify any of the parameters it loads, this is the job of verify_save() +/obj/item/integrated_circuit/proc/load(list/component_params) + // Load name + if(component_params["name"]) + displayed_name = component_params["name"] + + // Load input values + if(component_params["inputs"]) + var/list/loaded_inputs = component_params["inputs"] + + for(var/list/input in loaded_inputs) + var/index = input[1] + //var/input_type = input[2] + var/input_value = input[3] + + var/datum/integrated_io/pin = inputs[index] + // The pins themselves validate the data. + pin.write_data_to_pin(input_value) + // TODO: support for special input types, such as internal refs and maybe typepaths + + if(!isnull(component_params["special"])) + load_special(component_params["special"]) + +/obj/item/integrated_circuit/proc/load_special(special_data) + return + +// Saves type and modified name (if any) to a list +// The list is converted to JSON down the line. +/obj/item/electronic_assembly/proc/save() + var/list/assembly_params = list() + + // Save initial name used for differentiating assemblies + assembly_params["type"] = initial(name) + + // Save modified name + if(initial(name) != name) + assembly_params["name"] = name + + // Save modified description + if(initial(desc) != desc) + assembly_params["desc"] = desc + + // Save modified color + if(initial(detail_color) != detail_color) + assembly_params["detail_color"] = detail_color + + return assembly_params + + +// Verifies a list of assembly parameters +// Returns null on success, error name on failure +/obj/item/electronic_assembly/proc/verify_save(list/assembly_params) + // Validate name and color + if(assembly_params["name"]) + if(sanitize_name(assembly_params["name"], allow_numbers = TRUE, force_first_letter_uppercase = FALSE) != assembly_params["name"]) + return "Bad assembly name." + if(assembly_params["desc"]) + if(sanitize(assembly_params["desc"]) != assembly_params["desc"]) + return "Bad assembly description." + if(assembly_params["detail_color"] && !(assembly_params["detail_color"] in color_whitelist)) + return "Bad assembly color." + +// Loads assembly parameters from a list +// Doesn't verify any of the parameters it loads, this is the job of verify_save() +/obj/item/electronic_assembly/proc/load(list/assembly_params) + // Load modified name, if any. + if(assembly_params["name"]) + name = assembly_params["name"] + + // Load modified description, if any. + if(assembly_params["desc"]) + desc = assembly_params["desc"] + + if(assembly_params["detail_color"]) + detail_color = assembly_params["detail_color"] + + update_icon() + + + +// Attempts to save an assembly into a save file format. +// Returns null if assembly is not complete enough to be saved. +/datum/controller/subsystem/processing/circuit/proc/save_electronic_assembly(obj/item/electronic_assembly/assembly) + // No components? Don't even try to save it. + if(!length(assembly.assembly_components)) + return + + + var/list/blocks = list() + + // Block 1. Assembly. + blocks["assembly"] = assembly.save() + // (implant assemblies are not yet supported) + + + // Block 2. Components. + var/list/components = list() + for(var/c in assembly.assembly_components) + var/obj/item/integrated_circuit/component = c + components.Add(list(component.save())) + blocks["components"] = components + + + // Block 3. Wires. + var/list/wires = list() + var/list/saved_wires = list() + + for(var/c in assembly.assembly_components) + var/obj/item/integrated_circuit/component = c + var/list/all_pins = list() + for(var/l in list(component.inputs, component.outputs, component.activators)) + if(l) //If it isn't null + all_pins += l + + for(var/p in all_pins) + var/datum/integrated_io/pin = p + var/list/params = pin.get_pin_parameters() + var/text_params = params.Join() + + for(var/p2 in pin.linked) + var/datum/integrated_io/pin2 = p2 + var/list/params2 = pin2.get_pin_parameters() + var/text_params2 = params2.Join() + + // Check if we already saved an opposite version of this wire + // (do not save the same wire twice) + if((text_params2 + "=" + text_params) in saved_wires) + continue + + // If not, add a wire "hash" for future checks and save it + saved_wires.Add(text_params + "=" + text_params2) + wires.Add(list(list(params, params2))) + + if(wires.len) + blocks["wires"] = wires + + return json_encode(blocks) + + + +// Checks assembly save and calculates some of the parameters. +// Returns assembly (type: list) if the save is valid. +// Returns error code (type: text) if loading has failed. +// The following parameters area calculated during validation and added to the returned save list: +// "requires_upgrades", "unsupported_circuit", "cost", "complexity", "max_complexity", "used_space", "max_space" +/datum/controller/subsystem/processing/circuit/proc/validate_electronic_assembly(program) + var/list/blocks = cached_json_decode(program) + if(!blocks) + return + + var/error + + + // Block 1. Assembly. + var/list/assembly_params = blocks["assembly"] + + if(!islist(assembly_params) || !length(assembly_params)) + return "Invalid assembly data." // No assembly, damaged assembly or empty assembly + + // Validate type, get a temporary component + var/assembly_path = all_assemblies[assembly_params["type"]] + var/obj/item/electronic_assembly/assembly = cached_assemblies[assembly_path] + if(!assembly) + return "Invalid assembly type." + + // Check assembly save data for errors + error = assembly.verify_save(assembly_params) + if(error) + return error + + + // Read space & complexity limits and start keeping track of them + blocks["complexity"] = 0 + blocks["max_complexity"] = assembly.max_complexity + blocks["used_space"] = 0 + blocks["max_space"] = assembly.max_components + + // Start keeping track of total metal cost + blocks["cost"] = assembly.matter.Copy() + + + // Block 2. Components. + if(!islist(blocks["components"]) || !length(blocks["components"])) + return "Invalid components list." // No components or damaged components list + + var/list/assembly_components = list() + for(var/C in blocks["components"]) + var/list/component_params = C + + if(!islist(component_params) || !length(component_params)) + return "Invalid component data." + + // Validate type, get a temporary component + var/component_path = all_components[component_params["type"]] + var/obj/item/integrated_circuit/component = cached_components[component_path] + if(!component) + return "Invalid component type." + + // Add temporary component to assembly_components list, to be used later when verifying the wires + assembly_components.Add(component) + + // Check component save data for errors + error = component.verify_save(component_params) + if(error) + return error + + // Update estimated assembly complexity, taken space and material cost + blocks["complexity"] += component.complexity + blocks["used_space"] += component.size + for(var/mat in component.matter) + blocks["cost"][mat] += component.matter[mat] + + // Check if the assembly requires printer upgrades + if(!(component.spawn_flags & IC_SPAWN_DEFAULT)) + blocks["requires_upgrades"] = TRUE + + // Check if the assembly supports the circucit + if((component.action_flags & assembly.allowed_circuit_action_flags) != component.action_flags) + blocks["unsupported_circuit"] = TRUE + + + // Check complexity and space limitations + if(blocks["used_space"] > blocks["max_space"]) + return "Used space overflow." + if(blocks["complexity"] > blocks["max_complexity"]) + return "Complexity overflow." + + + // Block 3. Wires. + if(blocks["wires"]) + if(!islist(blocks["wires"])) + return "Invalid wiring list." // Damaged wires list + + for(var/w in blocks["wires"]) + var/list/wire = w + + if(!islist(wire) || wire.len != 2) + return "Invalid wire data." + + var/datum/integrated_io/IO = assembly.get_pin_ref_list(wire[1], assembly_components) + var/datum/integrated_io/IO2 = assembly.get_pin_ref_list(wire[2], assembly_components) + if(!IO || !IO2) + return "Invalid wire data." + + if(initial(IO.io_type) != initial(IO2.io_type)) + return "Wire type mismatch." + + return blocks + + +// Loads assembly (in form of list) into an object and returns it. +// No sanity checks are performed, save file is expected to be validated by validate_electronic_assembly +/datum/controller/subsystem/processing/circuit/proc/load_electronic_assembly(loc, list/blocks) + + // Block 1. Assembly. + var/list/assembly_params = blocks["assembly"] + var/obj/item/electronic_assembly/assembly_path = all_assemblies[assembly_params["type"]] + var/obj/item/electronic_assembly/assembly = new assembly_path(null) + assembly.load(assembly_params) + + + + // Block 2. Components. + for(var/component_params in blocks["components"]) + var/obj/item/integrated_circuit/component_path = all_components[component_params["type"]] + var/obj/item/integrated_circuit/component = new component_path(assembly) + assembly.add_component(component) + component.load(component_params) + + + // Block 3. Wires. + if(blocks["wires"]) + for(var/w in blocks["wires"]) + var/list/wire = w + var/datum/integrated_io/IO = assembly.get_pin_ref_list(wire[1]) + var/datum/integrated_io/IO2 = assembly.get_pin_ref_list(wire[2]) + IO.connect_pin(IO2) + + assembly.forceMove(loc) + assembly.post_load() + return assembly + diff --git a/mods/content/integrated_electronics/circuit_tests.dm b/mods/content/integrated_electronics/circuit_tests.dm new file mode 100644 index 000000000000..8188d49a3010 --- /dev/null +++ b/mods/content/integrated_electronics/circuit_tests.dm @@ -0,0 +1,135 @@ +/datum/unit_test/integrated_circuits + abstract_type = /datum/unit_test/integrated_circuits + +/datum/unit_test/integrated_circuits/unique_names + name = "INTEGRATED CIRCUITS: Circuits must have unique names" + +/datum/unit_test/integrated_circuits/unique_names/start_test() + var/list/circuits_by_name = list() + + for(var/circuit_path in SScircuit.cached_components) + var/atom/A = circuit_path + group_by(circuits_by_name, initial(A.name), circuit_path) + + var/number_of_issues = number_of_issues(circuits_by_name, "Names") + if(number_of_issues) + fail("[number_of_issues] issue\s with circuit naming found.") + else + pass("All circuits have unique names.") + return 1 + + +/datum/unit_test/integrated_circuits/prefabs_are_valid + name = "INTEGRATED CIRCUITS: Prefabs Are Valid" + +/datum/unit_test/integrated_circuits/prefabs_are_valid/start_test() + var/list/failed_prefabs = list() + for(var/prefab_type in decls_repository.get_decl_paths_of_subtype(/decl/prefab/ic_assembly)) + var/decl/prefab/ic_assembly/prefab = prefab_type + var/result = SScircuit.validate_electronic_assembly(initial(prefab.data)) + if(istext(result)) //Returned some error + failed_prefabs += "[prefab_type]: [result]" + if(failed_prefabs.len) + fail("The following integrated prefab types are invalid: [english_list(failed_prefabs)]") + else + pass("All integrated circuit prefabs are within complexity and size limits.") + + return 1 + +/datum/unit_test/integrated_circuits/prefabs_shall_not_fail_to_create + name = "INTEGRATED CIRCUITS: Prefabs Shall Not Fail To Create" + +/datum/unit_test/integrated_circuits/prefabs_shall_not_fail_to_create/start_test() + var/list/failed_prefabs = list() + var/list/all_prefabs = decls_repository.get_decls_of_subtype(/decl/prefab/ic_assembly) + for(var/prefab_type in all_prefabs) + var/decl/prefab/ic_assembly/prefab = all_prefabs[prefab_type] + try + var/built_item = prefab.create(get_safe_turf()) + if(built_item) + qdel(built_item) + else + log_bad("[prefab_type] failed to create or return its item.") + failed_prefabs |= prefab_type + catch(var/exception/e) + log_bad("[prefab_type] caused an exception: [EXCEPTION_TEXT(e)]") + failed_prefabs |= prefab_type + + if(failed_prefabs.len) + fail("The following integrated prefab types failed to create their assemblies: [english_list(failed_prefabs)]") + else + pass("All integrated circuit prefabs are within complexity and size limits.") + + return 1 + +/datum/unit_test/integrated_circuits/input_output + name = "INTEGRATED CIRCUITS: INPUT/OUTPUT - TEMPLATE" + abstract_type = /datum/unit_test/integrated_circuits/input_output + var/list/all_inputs = list() + var/list/all_expected_outputs = list() + var/activation_pin = 1 + var/circuit_type + +#define IC_TEST_ANY_OUTPUT "#IGNORE_THIS_OUTPUT#" + +/datum/unit_test/integrated_circuits/input_output/start_test() + var/obj/item/integrated_circuit/ic = new circuit_type() + var/failed = FALSE + + if(all_inputs.len != all_expected_outputs.len) + fail("Given inputs do not match the expected outputs length.") + return 1 + + for(var/test_index = 1 to all_inputs.len) + var/list/inputs = all_inputs[test_index] + var/list/expected_outputs = all_expected_outputs[test_index] + + for(var/input_pin_index = 1 to inputs.len) + ic.set_pin_data(IC_INPUT, input_pin_index, inputs[input_pin_index]) + + ic.do_work(activation_pin) + + for(var/output_index = 1 to expected_outputs.len) + var/actual_output = ic.get_pin_data(IC_OUTPUT, output_index) + var/expected_output = expected_outputs[output_index] + if(expected_output == IC_TEST_ANY_OUTPUT) + continue + if(actual_output != expected_output) + failed = TRUE + log_bad("[circuit_type] - Test [test_index] - Expected '[expected_output]', was '[actual_output]'") + for(var/datum/integrated_io/io in ic.inputs) + log_bad("Raw Input: [io.data]") + for(var/datum/integrated_io/io in ic.outputs) + log_bad("Raw Output: [io.data]") + + qdel(ic) + if(failed) + fail("The circuit [circuit_type] did not meet all expectations.") + else + pass("The circuit [circuit_type] met all expectations.") + return 1 + +/datum/unit_test/integrated_circuits/input_output/multiplexer + name = "INTEGRATED CIRCUITS: INPUT/OUTPUT - Multiplexer - Medium" + all_inputs = list(list(1,1,2,3,4),list(2,1,2,3,4),list(3,1,2,3,4),list(4,1,2,3,4)) + all_expected_outputs = list(list(1),list(2),list(3),list(4)) + circuit_type = /obj/item/integrated_circuit/transfer/multiplexer/medium + +/datum/unit_test/integrated_circuits/input_output/demultiplexer + name = "INTEGRATED CIRCUITS: INPUT/OUTPUT - Demultiplexer - Medium" + all_inputs = list(list(1,5),list(2,6),list(3,7),list(4,8)) + all_expected_outputs = list(list(5,null,null,null),list(null,6,null,null),list(null,null,7,null),list(null,null,null,8)) + circuit_type = /obj/item/integrated_circuit/transfer/demultiplexer/medium + +#undef IC_TEST_ANY_OUTPUT + +// Check prefab json. +/datum/unit_test/atoms_should_use_valid_json/get_json_to_check() + var/list/json_to_check = ..() + var/list/prefabs = decls_repository.get_decls_of_subtype(/decl/prefab/ic_assembly) + for(var/assembly_path in prefabs) + var/decl/prefab/ic_assembly/assembly = prefabs[assembly_path] + var/check_json = assembly.data + if(!isnull(check_json)) + LAZYSET(json_to_check, "[assembly_path].data", check_json) + return json_to_check \ No newline at end of file diff --git a/mods/content/integrated_electronics/components/_integrated_circuit.dm b/mods/content/integrated_electronics/components/_integrated_circuit.dm new file mode 100644 index 000000000000..fce50fde07f8 --- /dev/null +++ b/mods/content/integrated_electronics/components/_integrated_circuit.dm @@ -0,0 +1,410 @@ +/obj/item/integrated_circuit + name = "integrated circuit" + desc = "It's a tiny chip! This one doesn't seem to do much, however." + icon = 'icons/obj/assemblies/electronic_components.dmi' + icon_state = "template" + w_class = ITEM_SIZE_TINY + matter = list() // To be filled later + max_health = 25 //#TODO: Use material for health + var/obj/item/electronic_assembly/assembly // Reference to the assembly holding this circuit, if any. + var/extended_desc + var/list/inputs + var/list/inputs_default// Assoc list which will fill a pin with data upon creation. e.g. "2" = 0 will set input pin 2 to equal 0 instead of null. + var/list/outputs + var/list/outputs_default// Ditto, for output. + var/list/activators + var/next_use = 0 // Uses world.time + var/complexity = 1 // This acts as a limitation on building machines, more resource-intensive components cost more 'space'. + var/size = 1 // This acts as a limitation on building machines, bigger components cost more 'space'. -1 for size 0 + var/cooldown_per_use = 1 // Circuits are limited in how many times they can be work()'d by this variable. + var/ext_cooldown = 0 // Circuits are limited in how many times they can be work()'d with external world by this variable. + var/power_draw_per_use = 0 // How much power is drawn when work()'d. + var/power_draw_idle = 0 // How much power is drawn when doing nothing. + var/spawn_flags // Used for world initializing, see the #defines above. + var/action_flags = 0 // Used for telling circuits that can do certain actions from other circuits. + var/category_text = "NO CATEGORY THIS IS A BUG" // To show up on circuit printer, and perhaps other places. + var/removable = TRUE // Determines if a circuit is removable from the assembly. + var/displayed_name = "" + +/* + Integrated circuits are essentially modular machines. Each circuit has a specific function, and combining them inside Electronic Assemblies allows +a creative player the means to solve many problems. Circuits are held inside an electronic assembly, and are wired using special tools. +*/ + +/obj/item/integrated_circuit/examined_by(mob/user, distance, infix, suffix) + . = ..() + external_examine(user) + +/obj/item/integrated_circuit/ShiftClick(mob/living/user) + if(istype(user)) + interact(user) + else + ..() + +// This should be used when someone is examining while the case is opened. +/obj/item/integrated_circuit/proc/internal_examine(mob/user) + any_examine(user) + interact(user) + +// This should be used when someone is examining from an 'outside' perspective, e.g. reading a screen or LED. +/obj/item/integrated_circuit/proc/external_examine(mob/user) + any_examine(user) + +/obj/item/integrated_circuit/proc/any_examine(mob/user) + return + +/obj/item/integrated_circuit/proc/attackby_react(var/atom/movable/A, mob/user, decl/intent/intent) + return + +/obj/item/integrated_circuit/proc/sense(var/atom/movable/A,mob/user,prox) + return + +/obj/item/integrated_circuit/proc/OnICTopic(href_list, user) + return + +/obj/item/integrated_circuit/proc/get_topic_data(var/mob/user) + return + +/obj/item/integrated_circuit/proc/check_interactivity(mob/user) + if(assembly) + return assembly.check_interactivity(user) + else + return CanUseTopic(user) + +/obj/item/integrated_circuit/Initialize(ml, material_key) + displayed_name = name + setup_io(inputs, /datum/integrated_io, inputs_default, IC_INPUT) + inputs_default = null + setup_io(outputs, /datum/integrated_io, outputs_default, IC_OUTPUT) + outputs_default = null + setup_io(activators, /datum/integrated_io/activate, null, IC_ACTIVATOR) + if(!matter[/decl/material/solid/metal/steel]) + matter[/decl/material/solid/metal/steel] = w_class * SScircuit.cost_multiplier // Default cost. //#TODO: Maybe move that stuff to the new material system that does essentially the same thing? + . = ..() + +/obj/item/integrated_circuit/proc/on_data_written() //Override this for special behaviour when new data gets pushed to the circuit. + return + +/obj/item/integrated_circuit/Destroy() + QDEL_NULL_LIST(inputs) + QDEL_NULL_LIST(outputs) + QDEL_NULL_LIST(activators) + SScircuit_components.dequeue_component(src) + . = ..() + +/obj/item/integrated_circuit/emp_act(severity) + for(var/k in 1 to LAZYLEN(inputs)) + var/datum/integrated_io/I = inputs[k] + I.scramble() + for(var/k in 1 to LAZYLEN(outputs)) + var/datum/integrated_io/O = outputs[k] + O.scramble() + for(var/k in 1 to LAZYLEN(activators)) + var/datum/integrated_io/activate/A = activators[k] + A.scramble() + + +/obj/item/integrated_circuit/verb/rename_component() + set name = "Rename Circuit" + set category = "Object" + set desc = "Rename your circuit, useful to stay organized." + + var/mob/M = usr + if(!check_interactivity(M)) + return + + var/input = sanitize_name(input(M, "What do you want to name this?", "Rename", name) as null|text, allow_numbers = TRUE, force_first_letter_uppercase = FALSE) + if(check_interactivity(M)) + if(!input) + input = name + to_chat(M, "The circuit '[name]' is now labeled '[input]'.") + displayed_name = input + +/obj/item/integrated_circuit/nano_host() + if(istype(src.loc, /obj/item/electronic_assembly)) + return loc + return ..() + +/obj/item/integrated_circuit/interact(mob/user) + . = ..() + if(!check_interactivity(user)) + return + + var/window_height = 350 + var/window_width = 655 + + var/table_edge_width = "30%" + var/table_middle_width = "40%" + var/list/HTML = list() + HTML += "[src.displayed_name]" + HTML += "
    " + HTML += "" + + if(assembly) + HTML += "\[Return to Assembly\]
    " + + HTML += "\[Refresh\] | " + HTML += "\[Rename\] | " + HTML += "\[Copy Ref\]" + if(assembly && removable) + HTML += " | \[Remove\]" + HTML += "
    " + + HTML += "" + HTML += "" + HTML += "" + HTML += "" + HTML += "" + + var/column_width = 3 + var/row_height = max(LAZYLEN(inputs), LAZYLEN(outputs), 1) + + for(var/i = 1 to row_height) + HTML += "" + for(var/j = 1 to column_width) + var/datum/integrated_io/io = null + var/words = list() + var/height = 1 + switch(j) + if(1) + io = get_pin_ref(IC_INPUT, i) + if(io) + words += "[io.display_pin_type()] [io.name] \ + [io.display_data(io.data)]
    " + if(io.linked.len) + for(var/k in 1 to io.linked.len) + var/datum/integrated_io/linked = io.linked[k] + words += "[linked] \ + @ [linked.holder.displayed_name]
    " + + if(LAZYLEN(outputs) > LAZYLEN(inputs)) + height = 1 + if(2) + if(i == 1) + words += "[src.displayed_name]
    [src.name != src.displayed_name ? "([src.name])":""]
    [src.desc]" + height = row_height + else + continue + if(3) + io = get_pin_ref(IC_OUTPUT, i) + if(io) + words += "[io.display_pin_type()] [io.name] \ + [io.display_data(io.data)]
    " + if(io.linked.len) + for(var/k in 1 to io.linked.len) + var/datum/integrated_io/linked = io.linked[k] + words += "[linked] \ + @ [linked.holder.displayed_name]
    " + + if(LAZYLEN(inputs) > LAZYLEN(outputs)) + height = 1 + HTML += "" + HTML += "" + + for(var/i in 1 to LAZYLEN(activators)) + var/datum/integrated_io/io = activators[i] + var/words = list() + + words += "[io] " + words += "[io.data?"\":"\"]
    " + if(io.linked.len) + for(var/k in 1 to io.linked.len) + var/datum/integrated_io/linked = io.linked[k] + words += "[linked] \ + @ [linked.holder.displayed_name]
    " + + HTML += "" + HTML += "" + HTML += "" + + HTML += "
    [jointext(words, null)]
    [jointext(words, null)]
    " + HTML += "
    " + + HTML += "
    Complexity: [complexity]" + HTML += "
    Cooldown per use: [cooldown_per_use/10] sec" + if(ext_cooldown) + HTML += "
    External manipulation cooldown: [ext_cooldown/10] sec" + if(power_draw_idle) + HTML += "
    Power Draw: [power_draw_idle] W (Idle)" + if(power_draw_per_use) + HTML += "
    Power Draw: [power_draw_per_use] W (Active)" // Borgcode says that powercells' checked_use() takes joules as input. + HTML += "
    [extended_desc]" + + HTML += "" + var/HTML_merged = jointext(HTML, null) + if(assembly) + show_browser(user, HTML_merged, "window=assembly-\ref[assembly];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") + else + show_browser(user, HTML_merged, "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") + + onclose(user, "assembly-\ref[src.assembly]") + +/obj/item/integrated_circuit/Topic(href, href_list, state = global.physical_topic_state) + if(..()) + return 1 + + . = IC_TOPIC_HANDLED + var/obj/held_item = usr.get_active_held_item() + if(href_list["pin"] && assembly) + var/datum/integrated_io/pin = locate(href_list["pin"]) in inputs + outputs + activators + if(pin) + var/datum/integrated_io/linked + var/success = TRUE + if(href_list["link"]) + linked = locate(href_list["link"]) in pin.linked + + if(istype(held_item, /obj/item/wirer) || istype(held_item, /obj/item/debugger)) + pin.handle_wire(linked, held_item, href_list["act"], usr) + . = IC_TOPIC_REFRESH + else + to_chat(usr, "You can't do a whole lot without the proper tools.") + success = FALSE + if(success && assembly) + assembly.add_allowed_scanner(usr.ckey) + + else if(href_list["scan"]) + if(istype(held_item, /obj/item/debugger)) + var/obj/item/debugger/D = held_item + if(D.accepting_refs) + D.afterattack(src, usr, TRUE) + . = IC_TOPIC_REFRESH + else + to_chat(usr, "The debugger's 'ref scanner' needs to be on.") + else + to_chat(usr, "You need a debugger set to 'ref' mode to do that.") + + else if(href_list["refresh"]) + internal_examine(usr) + else if(href_list["return"] && assembly) + assembly.interact(usr) + else if(href_list["examine"] && assembly) + internal_examine(usr) + + else if(href_list["rename"]) + rename_component(usr) + . = IC_TOPIC_REFRESH + + else if(href_list["remove"] && assembly) + var/obj/item/held_item_obj = held_item + if(IS_SCREWDRIVER(held_item_obj)) + disconnect_all() + dropInto(loc) + playsound(src, 'sound/items/Crowbar.ogg', 50, 1) + to_chat(usr, "You pop \the [src] out of the case, and slide it out.") + else + to_chat(usr, "You need a screwdriver to remove components.") + interact_with_assembly(usr) + . = IC_TOPIC_REFRESH + + else + . = OnICTopic(href_list, usr) + + if(. == IC_TOPIC_REFRESH) + interact_with_assembly(usr) + +/obj/item/integrated_circuit/proc/interact_with_assembly(var/mob/user) + if(assembly) + assembly.interact(user) + if(assembly.opened) + interact(user) + +/obj/item/integrated_circuit/proc/push_data() + for(var/k in 1 to LAZYLEN(outputs)) + var/datum/integrated_io/O = outputs[k] + O.push_data() + +/obj/item/integrated_circuit/proc/pull_data() + for(var/k in 1 to LAZYLEN(inputs)) + var/datum/integrated_io/I = inputs[k] + I.push_data() + +/obj/item/integrated_circuit/proc/draw_idle_power() + if(assembly) + return assembly.draw_power(power_draw_idle) + +// Override this for special behaviour when there's no power left. +/obj/item/integrated_circuit/proc/power_fail() + return + +// Returns true if there's enough power to work(). +/obj/item/integrated_circuit/proc/check_power() + if(!assembly) + return FALSE // Not in an assembly, therefore no power. + if(assembly.draw_power(power_draw_per_use)) + return TRUE // Battery has enough. + return FALSE // Not enough power. + +/obj/item/integrated_circuit/proc/check_then_do_work(ord,var/ignore_power = FALSE) + if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam. + return FALSE + if(assembly && ext_cooldown && (world.time < assembly.ext_next_use)) // Some circuits have external cooldown, to protect from spam. + return FALSE + if(power_draw_per_use && !ignore_power) + if(!check_power()) + power_fail() + return FALSE + next_use = world.time + cooldown_per_use + if(assembly) + assembly.ext_next_use = world.time + ext_cooldown + do_work(ord) + return TRUE + +/obj/item/integrated_circuit/proc/do_work(ord) + return + +/obj/item/integrated_circuit/proc/disconnect_all() + var/datum/integrated_io/I + + for(var/i in inputs) + I = i + I.disconnect_all() + + for(var/i in outputs) + I = i + I.disconnect_all() + + for(var/i in activators) + I = i + I.disconnect_all() + +/obj/item/integrated_circuit/proc/get_object() + // If the component is located in an assembly, let assembly determine it. + if(assembly) + return assembly.get_object() + else + return src // If not, the component is acting on its own. + + +// Checks if the target object is reachable. Useful for various manipulators and manipulator-like objects. +/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE) + if(!target) + return FALSE + + var/atom/movable/acting_object = get_object() + + if(exclude_self && target == acting_object) + return FALSE + + if(exclude_components && assembly) + if(target in assembly.assembly_components) + return FALSE + + if(target == assembly.battery) + return FALSE + + if(target.Adjacent(acting_object) && isturf(target.loc)) + return TRUE + + if(!exclude_contents && (target in acting_object.GetAllContents())) + return TRUE + + if(target in acting_object.loc) + return TRUE + + return FALSE + +/obj/item/integrated_circuit/proc/added_to_assembly(var/obj/item/electronic_assembly/assembly) + return + +/obj/item/integrated_circuit/proc/removed_from_assembly(var/obj/item/electronic_assembly/assembly) + return diff --git a/mods/content/integrated_electronics/components/access.dm b/mods/content/integrated_electronics/components/access.dm new file mode 100644 index 000000000000..8d65f2c31da6 --- /dev/null +++ b/mods/content/integrated_electronics/components/access.dm @@ -0,0 +1,76 @@ +/obj/item/integrated_circuit/input/card_reader + name = "ID card reader" //To differentiate it from the data card reader + desc = "A circuit that can read the registered name, assignment, and PassKey string from an ID card." + icon_state = "card_reader" + + complexity = 4 + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + outputs = list( + "registered name" = IC_PINTYPE_STRING, + "assignment" = IC_PINTYPE_STRING, + "passkey" = IC_PINTYPE_STRING + ) + activators = list( + "on read" = IC_PINTYPE_PULSE_OUT + ) + +/obj/item/integrated_circuit/input/card_reader/old // adds compatibility for old TG blueprints + name = "card reader" + spawn_flags = 0 + +/obj/item/integrated_circuit/input/card_reader/attackby_react(obj/item/I, mob/user, decl/intent/intent) + var/obj/item/card/id/card = I.GetIdCard() + var/list/access = I.GetAccess() + var/json_access = json_encode(access) + var/passkey = add_data_signature(json_access) + + if(card) // An ID card. + set_pin_data(IC_OUTPUT, 1, card.registered_name) + set_pin_data(IC_OUTPUT, 2, card.assignment) + + else if(length(access)) // A non-card object that has access levels. + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + + else + return FALSE + + set_pin_data(IC_OUTPUT, 3, passkey) + user.visible_message("\The [user] swipes \the [I] onto \the [get_object()]'s card reader.") + push_data() + activate_pin(1) + return TRUE + +/obj/item/integrated_circuit/output/access_displayer + name = "access circuit" + desc = "A circuit that broadcasts access for your assembly via a passkey." + extended_desc = "Useful for moving drones through airlocks." + + complexity = 4 + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + inputs = list("passkey" = IC_PINTYPE_STRING) + activators = list( + "set passkey" = IC_PINTYPE_PULSE_IN + ) + var/list/access + +/obj/item/integrated_circuit/output/access_displayer/do_work() + var/list/signature_and_data = splittext(get_pin_data(IC_INPUT, 1), ":") + if(signature_and_data.len < 2) + return + + var/signature = signature_and_data[1] + var/result = signature_and_data[2] + + // check if the signature is valid + if(!check_data_signature(signature, result)) + return FALSE + + if(length(result) > 1) + result = cached_json_decode(result) + else + result = list(result) + access = result + +/obj/item/integrated_circuit/output/access_displayer/GetAccess() + return access \ No newline at end of file diff --git a/code/modules/integrated_electronics/subtypes/arithmetic.dm b/mods/content/integrated_electronics/components/arithmetic.dm similarity index 100% rename from code/modules/integrated_electronics/subtypes/arithmetic.dm rename to mods/content/integrated_electronics/components/arithmetic.dm diff --git a/code/modules/integrated_electronics/subtypes/converters.dm b/mods/content/integrated_electronics/components/converters.dm similarity index 97% rename from code/modules/integrated_electronics/subtypes/converters.dm rename to mods/content/integrated_electronics/components/converters.dm index 3ce02aa7f2ad..f76195c1c7ce 100644 --- a/code/modules/integrated_electronics/subtypes/converters.dm +++ b/mods/content/integrated_electronics/components/converters.dm @@ -93,7 +93,6 @@ inputs = list("input" = IC_PINTYPE_STRING) outputs = list("output" = IC_PINTYPE_REF) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - var/dec /obj/item/integrated_circuit/converter/refdecode/do_work() pull_data() @@ -110,6 +109,7 @@ /obj/item/integrated_circuit/converter/lowercase name = "lowercase string converter" + // i'm not fixing the capitalization here to fit style guides because it's funny actually desc = "this circuit will cause a string to come out in all lowercase." icon_state = "lowercase" inputs = list("input" = IC_PINTYPE_STRING) @@ -129,6 +129,7 @@ /obj/item/integrated_circuit/converter/uppercase name = "uppercase string converter" + // see capitalization note above desc = "THIS WILL CAUSE A STRING TO COME OUT IN ALL UPPERCASE." icon_state = "uppercase" inputs = list("input" = IC_PINTYPE_STRING) @@ -393,7 +394,7 @@ /obj/item/integrated_circuit/converter/hsv2hex name = "hsv to hexadecimal" - desc = "This circuit can convert a HSV (Hue, Saturation, and Value) color to a Hexadecimal RGB color." + desc = "This circuit can convert an HSV (Hue, Saturation, and Value) color to a Hexadecimal RGB color." extended_desc = "The first pin controls tint (0-359), the second pin controls how intense the tint is (0-255), and the third controls how bright the tint is (0 for black, 127 for normal, 255 for white)." icon_state = "hsv-hex" inputs = list( @@ -410,8 +411,8 @@ var/hue = get_pin_data(IC_INPUT, 1) var/saturation = get_pin_data(IC_INPUT, 2) var/value = get_pin_data(IC_INPUT, 3) - if(isnum(hue)&&isnum(saturation)&&isnum(value)) - result = HSVtoRGB(hsv(AngleToHue(hue),saturation,value)) + if(isnum(hue) && isnum(saturation) && isnum(value)) + result = hsv(hue, saturation, value) set_pin_data(IC_OUTPUT, 1, result) push_data() @@ -419,7 +420,7 @@ /obj/item/integrated_circuit/converter/rgb2hex name = "rgb to hexadecimal" - desc = "This circuit can convert a RGB (Red, Green, Blue) color to a Hexadecimal RGB color." + desc = "This circuit can convert an RGB (Red, Green, Blue) color to a Hexadecimal RGB color." extended_desc = "The first pin controls red amount, the second pin controls green amount, and the third controls blue amount. They all go from 0-255." icon_state = "rgb-hex" inputs = list( diff --git a/code/modules/integrated_electronics/subtypes/data_transfer.dm b/mods/content/integrated_electronics/components/data_transfer.dm similarity index 99% rename from code/modules/integrated_electronics/subtypes/data_transfer.dm rename to mods/content/integrated_electronics/components/data_transfer.dm index 2f9cfc04af75..067da9611acd 100644 --- a/code/modules/integrated_electronics/subtypes/data_transfer.dm +++ b/mods/content/integrated_electronics/components/data_transfer.dm @@ -131,7 +131,7 @@ /obj/item/integrated_circuit/transfer/pulsedemultiplexer/do_work() var/output_index = get_pin_data(IC_INPUT, 1) - if(output_index == Clamp(output_index, 1, number_of_pins)) + if(output_index == clamp(output_index, 1, number_of_pins)) activate_pin(round(output_index + 1 ,1)) /obj/item/integrated_circuit/transfer/pulsedemultiplexer/medium diff --git a/code/modules/integrated_electronics/subtypes/filter.dm b/mods/content/integrated_electronics/components/filter.dm similarity index 98% rename from code/modules/integrated_electronics/subtypes/filter.dm rename to mods/content/integrated_electronics/components/filter.dm index f1626432967d..781bb23ca3d0 100644 --- a/code/modules/integrated_electronics/subtypes/filter.dm +++ b/mods/content/integrated_electronics/components/filter.dm @@ -47,7 +47,7 @@ name = "humanoid filter" desc = "Only allow refs belonging to humanoids (dead or alive) through" icon_state = "filter_humanoid" - filter_type = /mob/living/carbon/human + filter_type = /mob/living/human /obj/item/integrated_circuit/filter/ref/obj name = "object filter" diff --git a/mods/content/integrated_electronics/components/input.dm b/mods/content/integrated_electronics/components/input.dm new file mode 100644 index 000000000000..f39d70cfb867 --- /dev/null +++ b/mods/content/integrated_electronics/components/input.dm @@ -0,0 +1,1155 @@ +/obj/item/integrated_circuit/input + category_text = "Input" + power_draw_per_use = 5 + +/obj/item/integrated_circuit/input/external_examine(mob/user) + var/initial_name = initial(name) + var/message + if(initial_name == name) + message = "There is \a [src]." + else + message = "There is \a ["\improper[initial_name]"] labeled '[name]'." + to_chat(user, message) + + +/obj/item/integrated_circuit/input/button + name = "button" + desc = "This tiny button must do something, right?" + icon_state = "button" + complexity = 1 + inputs = list() + outputs = list() + activators = list("on pressed" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/input/button/get_topic_data(mob/user) + return list("Press" = "press=1") + +/obj/item/integrated_circuit/input/button/OnICTopic(href_list, user) + if(href_list["press"]) + to_chat(user, "You press the button labeled '[src.displayed_name]'.") + activate_pin(1) + return IC_TOPIC_REFRESH + +/obj/item/integrated_circuit/input/toggle_button + name = "toggle button" + desc = "It toggles on, off, on, off..." + icon_state = "toggle_button" + complexity = 1 + inputs = list() + outputs = list("on" = IC_PINTYPE_BOOLEAN) + activators = list("on toggle" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/input/toggle_button/emp_act() + return // This is a mainly physical thing, not affected by electricity + +/obj/item/integrated_circuit/input/toggle_button/get_topic_data(mob/user) + return list("Toggle [get_pin_data(IC_OUTPUT, 1) ? "Off" : "On"]" = "toggle=1") + +/obj/item/integrated_circuit/input/toggle_button/OnICTopic(href_list, user) + if(href_list["toggle"]) + set_pin_data(IC_OUTPUT, 1, !get_pin_data(IC_OUTPUT, 1)) + push_data() + activate_pin(1) + to_chat(user, "You toggle the button labeled '[src.name]' [get_pin_data(IC_OUTPUT, 1) ? "on" : "off"].") + return IC_TOPIC_REFRESH + +/obj/item/integrated_circuit/input/numberpad + name = "number pad" + desc = "This small number pad allows someone to input a number into the system." + icon_state = "numberpad" + complexity = 2 + inputs = list() + outputs = list("number entered" = IC_PINTYPE_NUMBER) + activators = list("on entered" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + +/obj/item/integrated_circuit/input/numberpad/get_topic_data(mob/user) + return list("Enter Number" = "enter_number=1") + +/obj/item/integrated_circuit/input/numberpad/OnICTopic(href_list, user) + if(href_list["enter_number"]) + var/new_input = input(user, "Enter a number, please.","Number pad") as null|num + if(isnum(new_input) && CanInteract(user, global.physical_topic_state)) + set_pin_data(IC_OUTPUT, 1, new_input) + push_data() + activate_pin(1) + return IC_TOPIC_REFRESH + +/obj/item/integrated_circuit/input/textpad + name = "text pad" + desc = "This small text pad allows someone to input a string into the system." + icon_state = "textpad" + complexity = 2 + inputs = list() + outputs = list("string entered" = IC_PINTYPE_STRING) + activators = list("on entered" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + +/obj/item/integrated_circuit/input/textpad/get_topic_data(mob/user) + return list("Enter Words" = "enter_words=1") + +/obj/item/integrated_circuit/input/textpad/OnICTopic(href_list, user) + if(href_list["enter_words"]) + var/new_input = input(user, "Enter some words, please.","Number pad") as null|text + if(istext(new_input) && CanInteract(user, global.physical_topic_state)) + set_pin_data(IC_OUTPUT, 1, new_input) + push_data() + activate_pin(1) + return IC_TOPIC_REFRESH + +/obj/item/integrated_circuit/input/colorpad + name = "color pad" + desc = "This small color pad allows someone to input a hexadecimal color into the system." + icon_state = "colorpad" + complexity = 2 + inputs = list() + outputs = list("color entered" = IC_PINTYPE_STRING) + activators = list("on entered" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + +/obj/item/integrated_circuit/input/colorpad/get_topic_data(mob/user) + return list("Enter Color" = "enter_color=1") + +/obj/item/integrated_circuit/input/colorpad/OnICTopic(href_list, user) + if(href_list["enter_color"]) + var/new_color = input(user, "Enter a color, please.", "Color", "#ffffff") as color|null + if(new_color) + set_pin_data(IC_OUTPUT, 1, new_color) + push_data() + activate_pin(1) + return IC_TOPIC_REFRESH + +/obj/item/integrated_circuit/input/med_scanner + name = "integrated medical analyser" + desc = "A very small version of the common medical analyser. This allows the machine to track some vital signs." + icon_state = "medscan" + complexity = 4 + inputs = list("target" = IC_PINTYPE_REF) + outputs = list( + "brain activity" = IC_PINTYPE_BOOLEAN, + "pulse" = IC_PINTYPE_NUMBER, + "is conscious" = IC_PINTYPE_BOOLEAN + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 40 + +/obj/item/integrated_circuit/input/med_scanner/do_work() + var/mob/living/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living) + if(!istype(H)) //Invalid input + return + if(H.Adjacent(get_turf(src))) // Like normal analysers, it can't be used at range. + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(H, BP_BRAIN) + set_pin_data(IC_OUTPUT, 1, (brain && H.stat != DEAD)) + set_pin_data(IC_OUTPUT, 2, H.get_pulse_as_number()) + set_pin_data(IC_OUTPUT, 3, (H.stat == CONSCIOUS)) + + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/adv_med_scanner + name = "integrated adv. medical analyser" + desc = "A very small version of the medbot's medical analyser. This allows the machine to know how healthy someone is. \ + This type is much more precise, allowing the machine to know much more about the target than a normal analyzer." + extended_desc = "Values for damage and pain are 0 to 5 marking severity of the damage" + icon_state = "medscan_adv" + complexity = 12 + inputs = list("target" = IC_PINTYPE_REF) + outputs = list( + "brain activity" = IC_PINTYPE_BOOLEAN, + "is conscious" = IC_PINTYPE_BOOLEAN, + "brute damage" = IC_PINTYPE_NUMBER, + "burn damage" = IC_PINTYPE_NUMBER, + "tox damage" = IC_PINTYPE_NUMBER, + "oxy damage" = IC_PINTYPE_NUMBER, + "clone damage" = IC_PINTYPE_NUMBER, + "pulse" = IC_PINTYPE_NUMBER, + "oxygenation level" = IC_PINTYPE_NUMBER, + "pain level" = IC_PINTYPE_NUMBER, + "radiation" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 80 + +/obj/item/integrated_circuit/input/adv_med_scanner/proc/damage_to_severity(var/value) + if(value < 1) + return 0 + if(value < 25) + return 1 + if(value < 50) + return 2 + if(value < 75) + return 3 + if(value < 100) + return 4 + return 5 + + +/obj/item/integrated_circuit/input/adv_med_scanner/do_work() + var/mob/living/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living) + if(!istype(H)) //Invalid input + return + if(H in view(get_turf(src))) // Like the medbot's analyzer it can be used at range. + + var/current_max_health = H.get_max_health() + var/obj/item/organ/internal/brain = GET_INTERNAL_ORGAN(H, BP_BRAIN) + set_pin_data(IC_OUTPUT, 1, (brain && H.stat != DEAD)) + set_pin_data(IC_OUTPUT, 2, (H.stat == CONSCIOUS)) + set_pin_data(IC_OUTPUT, 3, damage_to_severity(100 * H.get_damage(BRUTE) / current_max_health)) + set_pin_data(IC_OUTPUT, 4, damage_to_severity(100 * H.get_damage(BURN) / current_max_health)) + set_pin_data(IC_OUTPUT, 5, damage_to_severity(100 * H.get_damage(TOX) / current_max_health)) + set_pin_data(IC_OUTPUT, 6, damage_to_severity(100 * H.get_damage(OXY) / current_max_health)) + set_pin_data(IC_OUTPUT, 7, damage_to_severity(100 * H.get_damage(CLONE) / current_max_health)) + set_pin_data(IC_OUTPUT, 8, H.get_pulse_as_number()) + set_pin_data(IC_OUTPUT, 9, H.get_blood_oxygenation()) + set_pin_data(IC_OUTPUT, 10, damage_to_severity(H.get_shock())) + set_pin_data(IC_OUTPUT, 11, H.radiation) + + push_data() + activate_pin(2) + +//please delete at a later date after people stop using the old named circuit +/obj/item/integrated_circuit/input/adv_med_scanner/old + name = "integrated advanced medical analyser" + spawn_flags = 0 + +/obj/item/integrated_circuit/input/plant_scanner + name = "integrated plant analyzer" + desc = "A very small version of the plant analyser. This allows the machine to know all valuable parameters of plants in trays. \ + It can only scan plants, not seeds or fruits." + icon_state = "medscan_adv" + complexity = 12 + inputs = list("target" = IC_PINTYPE_REF) + outputs = list( + "plant type" = IC_PINTYPE_STRING, + "age" = IC_PINTYPE_NUMBER, + "potency" = IC_PINTYPE_NUMBER, + "yield" = IC_PINTYPE_NUMBER, + "Maturation speed" = IC_PINTYPE_NUMBER, + "Production speed" = IC_PINTYPE_NUMBER, + "Endurance" = IC_PINTYPE_NUMBER, + "Lifespan" = IC_PINTYPE_NUMBER, + "Weed Resistance" = IC_PINTYPE_NUMBER, + "Weed level" = IC_PINTYPE_NUMBER, + "Pest level" = IC_PINTYPE_NUMBER, + "Water level" = IC_PINTYPE_NUMBER, + "Nutrition level" = IC_PINTYPE_NUMBER, + "harvest" = IC_PINTYPE_NUMBER, + "dead" = IC_PINTYPE_NUMBER, + "plant health" = IC_PINTYPE_NUMBER, + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 10 + +/obj/item/integrated_circuit/input/plant_scanner/do_work() + var/obj/machinery/portable_atmospherics/hydroponics/H = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/portable_atmospherics/hydroponics) + if(!istype(H)) //Invalid input + return + for(var/i=1, i<=outputs.len, i++) + set_pin_data(IC_OUTPUT, i, null) + if(H in view(get_turf(src))) // Like the medbot's analyzer it can be used at range. + if(H.seed) + set_pin_data(IC_OUTPUT, 1, H.seed.product_name) + set_pin_data(IC_OUTPUT, 2, H.age) + set_pin_data(IC_OUTPUT, 3, H.seed.get_trait(TRAIT_POTENCY)) + set_pin_data(IC_OUTPUT, 4, H.seed.get_trait(TRAIT_YIELD)) + set_pin_data(IC_OUTPUT, 5, H.seed.get_trait(TRAIT_MATURATION)) + set_pin_data(IC_OUTPUT, 6, H.seed.get_trait(TRAIT_PRODUCTION)) + set_pin_data(IC_OUTPUT, 7, H.seed.get_trait(TRAIT_ENDURANCE)) + set_pin_data(IC_OUTPUT, 8, !!H.seed.get_trait(TRAIT_HARVEST_REPEAT)) + set_pin_data(IC_OUTPUT, 9, H.seed.get_trait(TRAIT_WEED_TOLERANCE)) + set_pin_data(IC_OUTPUT, 10, H.weedlevel) + set_pin_data(IC_OUTPUT, 11, H.pestlevel) + set_pin_data(IC_OUTPUT, 12, H.waterlevel) + set_pin_data(IC_OUTPUT, 13, H.nutrilevel) + set_pin_data(IC_OUTPUT, 14, H.harvest) + set_pin_data(IC_OUTPUT, 15, H.dead) + set_pin_data(IC_OUTPUT, 16, H.plant_health) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/gene_scanner + name = "gene scanner" + desc = "This circuit will scan the target plant for traits and reagent genes. Output is non-associative." + extended_desc = "This allows the machine to scan plants in trays for reagent and trait genes. \ + It can only scan plants, not seeds or fruits." + inputs = list( + "target" = IC_PINTYPE_REF + ) + outputs = list( + "reagents" = IC_PINTYPE_LIST + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + icon_state = "medscan_adv" + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/input/gene_scanner/do_work() + var/list/greagents = list() + var/obj/machinery/portable_atmospherics/hydroponics/plant = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/portable_atmospherics/hydroponics) + if(!istype(plant)) //Invalid input + return + for(var/i=1, i<=outputs.len, i++) + set_pin_data(IC_OUTPUT, i, null) + if(plant.seed && (plant in view(get_turf(src)))) // Like the medbot's analyzer it can be used at range. + for(var/chem_path in plant.seed.get_chemical_composition()) + var/decl/material/seed_chem = GET_DECL(chem_path) + greagents.Add(seed_chem.use_name) + + set_pin_data(IC_OUTPUT, 1, greagents) + push_data() + activate_pin(2) + + +/obj/item/integrated_circuit/input/examiner + name = "examiner" + desc = "It's a little machine vision system. It can return the name, description, distance, \ + relative coordinates, total amount of reagents, maximum amount of reagents, density, and opacity of the referenced object." + icon_state = "video_camera" + complexity = 6 + inputs = list( + "target" = IC_PINTYPE_REF + ) + outputs = list( + "name" = IC_PINTYPE_STRING, + "description" = IC_PINTYPE_STRING, + "X" = IC_PINTYPE_NUMBER, + "Y" = IC_PINTYPE_NUMBER, + "distance" = IC_PINTYPE_NUMBER, + "max reagents" = IC_PINTYPE_NUMBER, + "amount of reagents" = IC_PINTYPE_NUMBER, + "density" = IC_PINTYPE_BOOLEAN, + "opacity" = IC_PINTYPE_BOOLEAN, + "occupied turf" = IC_PINTYPE_REF + ) + activators = list( + "scan" = IC_PINTYPE_PULSE_IN, + "on scanned" = IC_PINTYPE_PULSE_OUT, + "not scanned" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 80 + +/obj/item/integrated_circuit/input/examiner/do_work() + var/atom/H = get_pin_data_as_type(IC_INPUT, 1, /atom) + var/turf/T = get_turf(src) + + if(!istype(H) || !(H in view(T))) + activate_pin(3) + else + set_pin_data(IC_OUTPUT, 1, H.name) + set_pin_data(IC_OUTPUT, 2, H.desc) + set_pin_data(IC_OUTPUT, 3, H.x-T.x) + set_pin_data(IC_OUTPUT, 4, H.y-T.y) + set_pin_data(IC_OUTPUT, 5, sqrt((H.x-T.x)*(H.x-T.x)+ (H.y-T.y)*(H.y-T.y))) + var/mr = 0 + var/tr = 0 + if(H.reagents) + mr = REAGENT_MAXIMUM_VOLUME(H.reagents) + tr = REAGENT_TOTAL_VOLUME(H.reagents) + set_pin_data(IC_OUTPUT, 6, mr) + set_pin_data(IC_OUTPUT, 7, tr) + set_pin_data(IC_OUTPUT, 8, H.density) + set_pin_data(IC_OUTPUT, 9, H.opacity) + set_pin_data(IC_OUTPUT, 10, get_turf(H)) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/turfpoint + name = "tile pointer" + desc = "This circuit will get a tile ref with the provided absolute coordinates." + extended_desc = "If the machine cannot see the target, it will not be able to calculate the correct direction.\ + This circuit only works while inside an assembly." + icon_state = "numberpad" + complexity = 5 + inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER) + outputs = list("tile" = IC_PINTYPE_REF) + activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 40 + +/obj/item/integrated_circuit/input/turfpoint/do_work() + if(!assembly) + activate_pin(3) + return + var/turf/T = get_turf(assembly) + var/target_x = clamp(get_pin_data(IC_INPUT, 1), 0, world.maxx) + var/target_y = clamp(get_pin_data(IC_INPUT, 2), 0, world.maxy) + var/turf/A = locate(target_x, target_y, T.z) + set_pin_data(IC_OUTPUT, 1, null) + if(!A || !(A in view(T))) + activate_pin(3) + return + else + set_pin_data(IC_OUTPUT, 1, weakref(A)) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/turfscan + name = "tile analyzer" + desc = "This circuit can analyze the contents of the scanned turf, and can read letters on the turf." + icon_state = "video_camera" + complexity = 5 + inputs = list( + "target" = IC_PINTYPE_REF + ) + outputs = list( + "located ref" = IC_PINTYPE_LIST, + "Written letters" = IC_PINTYPE_STRING, + "area" = IC_PINTYPE_STRING + ) + activators = list( + "scan" = IC_PINTYPE_PULSE_IN, + "on scanned" = IC_PINTYPE_PULSE_OUT, + "not scanned" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 40 + cooldown_per_use = 10 + +/obj/item/integrated_circuit/input/turfscan/do_work() + var/turf/scanned_turf = get_pin_data_as_type(IC_INPUT, 1, /turf) + var/turf/circuit_turf = get_turf(src) + var/area_name = get_area_name(scanned_turf) + if(!istype(scanned_turf)) //Invalid input + activate_pin(3) + return + + if(scanned_turf in view(circuit_turf)) // This is a camera. It can't examine things that it can't see. + var/list/turf_contents = new() + for(var/obj/U in scanned_turf) + turf_contents += weakref(U) + for(var/mob/U in scanned_turf) + turf_contents += weakref(U) + set_pin_data(IC_OUTPUT, 1, turf_contents) + set_pin_data(IC_OUTPUT, 3, area_name) + var/list/St = new() + for(var/obj/effect/decal/cleanable/crayon/I in scanned_turf) + St.Add(I.icon_state) + if(St.len) + set_pin_data(IC_OUTPUT, 2, jointext(St, ",", 1, 0)) + push_data() + activate_pin(2) + else + activate_pin(3) + +/obj/item/integrated_circuit/input/local_locator + name = "local locator" + desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \ + that is holding the machine containing it." + inputs = list() + outputs = list("located ref" = IC_PINTYPE_REF, + "is ground" = IC_PINTYPE_BOOLEAN, + "is creature" = IC_PINTYPE_BOOLEAN) + activators = list("locate" = IC_PINTYPE_PULSE_IN, + "on scanned" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/local_locator/do_work() + var/datum/integrated_io/O = outputs[1] + O.data = null + if(assembly) + O.data = weakref(assembly.loc) + set_pin_data(IC_OUTPUT, 2, isturf(assembly.loc)) + set_pin_data(IC_OUTPUT, 3, ismob(assembly.loc)) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/adjacent_locator + name = "adjacent locator" + desc = "This is needed for certain devices that demand a reference for a target to act upon. This type only locates something \ + that is standing up to a meter away from the machine." + extended_desc = "The first pin requires a ref to the kind of object that you want the locator to acquire. This means that it will \ + give refs to nearby objects that are similar. If more than one valid object is found nearby, it will choose one of them at \ + random." + inputs = list("desired type ref" = IC_PINTYPE_REF) + outputs = list("located ref" = IC_PINTYPE_REF) + activators = list("locate" = IC_PINTYPE_PULSE_IN,"found" = IC_PINTYPE_PULSE_OUT, + "not found" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 30 + +/obj/item/integrated_circuit/input/adjacent_locator/do_work() + var/datum/integrated_io/I = inputs[1] + var/datum/integrated_io/O = outputs[1] + O.data = null + + if(!isweakref(I.data)) + return + var/atom/A = I.data.resolve() + if(!A) + return + var/desired_type = A.type + + var/list/nearby_things = range(1, get_turf(src)) + var/list/valid_things = list() + for(var/atom/thing in nearby_things) + if(thing.type != desired_type) + continue + valid_things.Add(thing) + if(valid_things.len) + O.data = weakref(pick(valid_things)) + activate_pin(2) + else + activate_pin(3) + O.push_data() + +/obj/item/integrated_circuit/input/advanced_locator_list + complexity = 6 + name = "list advanced locator" + desc = "This is needed for certain devices that demand list of names for a target to act upon. This type locates something \ + that is standing in given radius of up to 8 meters. Output is non-associative. Input will only consider keys if associative." + extended_desc = "The first pin requires a list of the kinds of objects that you want the locator to acquire. It will locate nearby objects by name and description, \ + and will then provide a list of all found objects which are similar. \ + The second pin is a radius." + inputs = list("desired type ref" = IC_PINTYPE_LIST, "radius" = IC_PINTYPE_NUMBER) + outputs = list("located ref" = IC_PINTYPE_LIST) + activators = list("locate" = IC_PINTYPE_PULSE_IN,"found" = IC_PINTYPE_PULSE_OUT,"not found" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 30 + var/radius = 1 + cooldown_per_use = 10 + +/obj/item/integrated_circuit/input/advanced_locator_list/on_data_written() + var/rad = get_pin_data(IC_INPUT, 2) + + if(isnum(rad)) + rad = clamp(rad, 0, 8) + radius = rad + +/obj/item/integrated_circuit/input/advanced_locator_list/do_work() + var/datum/integrated_io/I = inputs[1] + var/datum/integrated_io/O = outputs[1] + O.data = null + var/list/input_list = list() + input_list = I.data + if(length(input_list)) //if there is no input don't do anything. + var/turf/T = get_turf(src) + var/list/nearby_things = view(radius,T) + var/list/valid_things = list() + for(var/item in input_list) + if(!isnull(item) && !isnum(item)) + if(istext(item)) + for(var/i in nearby_things) + var/atom/thing = i + if(ismob(thing) && !isliving(thing)) + continue + if(findtext(addtext(thing.name," ",thing.desc), item, 1, 0) ) + valid_things.Add(weakref(thing)) + else + var/atom/A = item + var/desired_type = A.type + for(var/i in nearby_things) + var/atom/thing = i + if(thing.type != desired_type) + continue + if(ismob(thing) && !isliving(thing)) + continue + valid_things.Add(weakref(thing)) + if(valid_things.len) + O.data = valid_things + O.push_data() + activate_pin(2) + else + O.push_data() + activate_pin(3) + else + O.push_data() + activate_pin(3) + +/obj/item/integrated_circuit/input/advanced_locator + complexity = 6 + name = "advanced locator" + desc = "This is needed for certain devices that demand a reference for a target to act upon. This type locates something \ + that is standing in given radius of up to 8 meters" + extended_desc = "The first pin requires a ref to the kind of object that you want the locator to acquire. This means that it will \ + give refs to nearby objects which are similar. If this pin is a string, the locator will search for an \ + item matching the desired text in its name and description. If more than one valid object is found nearby, it will choose one of them at \ + random. The second pin is a radius." + inputs = list("desired type" = IC_PINTYPE_ANY, "radius" = IC_PINTYPE_NUMBER) + outputs = list("located ref" = IC_PINTYPE_REF) + activators = list("locate" = IC_PINTYPE_PULSE_IN,"found" = IC_PINTYPE_PULSE_OUT,"not found" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 30 + var/radius = 1 + +/obj/item/integrated_circuit/input/advanced_locator/on_data_written() + var/rad = get_pin_data(IC_INPUT, 2) + if(isnum(rad)) + rad = clamp(rad, 0, 8) + radius = rad + +/obj/item/integrated_circuit/input/advanced_locator/do_work() + var/datum/integrated_io/I = inputs[1] + var/datum/integrated_io/O = outputs[1] + O.data = null + var/turf/T = get_turf(src) + var/list/nearby_things = view(radius,T) + var/list/valid_things = list() + if(isweakref(I.data)) + var/atom/A = I.data.resolve() + var/desired_type = A.type + if(desired_type) + for(var/i in nearby_things) + var/atom/thing = i + if(ismob(thing) && !isliving(thing)) + continue + if(thing.type == desired_type) + valid_things.Add(thing) + else if(istext(I.data)) + var/DT = I.data + for(var/i in nearby_things) + var/atom/thing = i + if(ismob(thing) && !isliving(thing)) + continue + if(findtext(addtext(thing.name," ",thing.desc), DT, 1, 0) ) + valid_things.Add(thing) + if(valid_things.len) + O.data = weakref(pick(valid_things)) + O.push_data() + activate_pin(2) + else + O.push_data() + activate_pin(3) + +/obj/item/integrated_circuit/input/signaler + name = "integrated signaler" + desc = "Signals from a signaler can be received with this, allowing for remote control. It can also send signals." + extended_desc = "When a signal is received from another signaler, the 'on signal received' activator pin will be pulsed. \ + The two input pins are to configure the integrated signaler's settings. Note that the frequency should not have a decimal in it, \ + meaning the default frequency is expressed as 1457, not 145.7. To send a signal, pulse the 'send signal' activator pin." + icon_state = "signal" + complexity = 4 + inputs = list("frequency" = IC_PINTYPE_NUMBER,"code" = IC_PINTYPE_NUMBER) + outputs = list() + activators = list( + "send signal" = IC_PINTYPE_PULSE_IN, + "on signal sent" = IC_PINTYPE_PULSE_OUT, + "on signal received" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + action_flags = IC_ACTION_LONG_RANGE + power_draw_idle = 5 + power_draw_per_use = 40 + cooldown_per_use = 5 + var/frequency = 1357 + var/code = 30 + var/datum/radio_frequency/radio_connection + +/obj/item/integrated_circuit/input/signaler/Initialize() + . = ..() + set_pin_data(IC_INPUT, 1, frequency) + set_pin_data(IC_INPUT, 2, code) + addtimer(CALLBACK(src, PROC_REF(set_frequency),frequency), 40) + +/obj/item/integrated_circuit/input/signaler/Destroy() + radio_controller.remove_object(src,frequency) + frequency = 0 + return ..() + +/obj/item/integrated_circuit/input/signaler/on_data_written() + var/new_freq = get_pin_data(IC_INPUT, 1) + var/new_code = get_pin_data(IC_INPUT, 2) + if(isnum(new_freq) && new_freq > 0) + set_frequency(new_freq) + code = new_code + + +/obj/item/integrated_circuit/input/signaler/do_work(var/ord) // Sends a signal. + if(!radio_connection || ord != 1) + return + + radio_connection.post_signal(src, create_signal()) + activate_pin(2) + +/obj/item/integrated_circuit/input/signaler/proc/signal_good(var/datum/signal/signal) + if(!signal || signal.source == src) + return FALSE + if(code) + var/real_code = 0 + if(isnum(code)) + real_code = code + var/rec = 0 + if(signal.encryption) + rec = signal.encryption + if(real_code != rec) + return FALSE + return TRUE + +/obj/item/integrated_circuit/input/signaler/proc/create_signal() + var/datum/signal/signal = new() + signal.source = src + if(isnum(code)) + signal.encryption = code + signal.data["message"] = "ACTIVATE" + return signal + +/obj/item/integrated_circuit/input/signaler/proc/set_frequency(new_frequency) + if(!frequency) + return + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + +/obj/item/integrated_circuit/input/signaler/receive_signal(datum/signal/signal) + if(!signal_good(signal)) + return 0 + treat_signal(signal) + return 1 + +//This only procs when a signal is valid. +/obj/item/integrated_circuit/input/signaler/proc/treat_signal(var/datum/signal/signal) + activate_pin(3) + +/obj/item/integrated_circuit/input/signaler/advanced + name = "advanced integrated signaler" + icon_state = "signal_advanced" + desc = "Signals from a signaler can be received with this, allowing for remote control. Additionally, it can send signals as well." + extended_desc = "When a signal is received from another signaler with the right id tag, the 'on signal received' activator pin will be pulsed and the command output is updated. \ + The two input pins are to configure the integrated signaler's settings. Note that the frequency should not have a decimal in it. \ + Meaning the default frequency is expressed as 1457, not 145.7. To send a signal, pulse the 'send signal' activator pin. Set the command output to set the message received." + complexity = 8 + inputs = list("frequency" = IC_PINTYPE_NUMBER, "id tag" = IC_PINTYPE_STRING, "command" = IC_PINTYPE_STRING) + outputs = list("received command" = IC_PINTYPE_STRING) + var/command + code = "Integrated_Circuits" + +/obj/item/integrated_circuit/input/signaler/advanced/on_data_written() + ..() + command = get_pin_data(IC_INPUT,3) + +/obj/item/integrated_circuit/input/signaler/advanced/signal_good(var/datum/signal/signal) + if(!..() || signal.data["tag"] != code) + return FALSE + return TRUE + +/obj/item/integrated_circuit/input/signaler/advanced/create_signal() + var/datum/signal/signal = new() + signal.data["tag"] = code + signal.data["command"] = command + signal.encryption = 0 + return signal + +/obj/item/integrated_circuit/input/signaler/advanced/treat_signal(var/datum/signal/signal) + set_pin_data(IC_OUTPUT,1,signal.data["command"]) + push_data() + ..() + +/obj/item/integrated_circuit/input/teleporter_locator + name = "teleporter locator" + desc = "This circuit can locate and allow for selection of teleporter computers." + icon_state = "gps" + complexity = 5 + inputs = list() + outputs = list("teleporter" = IC_PINTYPE_REF) + activators = list("on selected" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + action_flags = IC_ACTION_LONG_RANGE + +/obj/item/integrated_circuit/input/teleporter_locator/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE + +/obj/item/integrated_circuit/input/teleporter_locator/get_topic_data(mob/user) + var/datum/integrated_io/O = outputs[1] + var/obj/machinery/computer/teleporter/current_console = O.data_as_type(/obj/machinery/computer/teleporter) + + . = list() + . += "Current selection: [(current_console && current_console.id) || "None"]" + . += "Please select a teleporter to lock in on:" + for(var/obj/machinery/teleport/hub/R in SSmachines.machinery) + var/obj/machinery/computer/teleporter/com = R.com + if (istype(com, /obj/machinery/computer/teleporter) && com.locked && !com.one_time_use && com.operable() && LEVELS_ARE_Z_CONNECTED(get_z(src), get_z(com))) + .["[com.id] ([R.icon_state == "tele1" ? "Active" : "Inactive"])"] = "tport=[any2ref(com)]" + .["None (Dangerous)"] = "tport=random" + +/obj/item/integrated_circuit/input/teleporter_locator/OnICTopic(href_list, user) + if(href_list["tport"]) + var/output = href_list["tport"] == "random" ? null : locate(href_list["tport"]) + set_pin_data(IC_OUTPUT, 1, output && weakref(output)) + push_data() + activate_pin(1) + return IC_TOPIC_REFRESH + +//This circuit gives information on where the machine is. +/obj/item/integrated_circuit/input/gps + name = "global positioning system" + desc = "This allows you to easily know the position of a machine containing this device." + extended_desc = "The coordinates that the GPS outputs are absolute, not relative." + icon_state = "gps" + complexity = 4 + inputs = list() + outputs = list("X"= IC_PINTYPE_NUMBER, "Y" = IC_PINTYPE_NUMBER, "Z" = IC_PINTYPE_NUMBER) + activators = list("get coordinates" = IC_PINTYPE_PULSE_IN, "on get coordinates" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 30 + +/obj/item/integrated_circuit/input/gps/do_work() + var/turf/T = get_turf(src) + + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + set_pin_data(IC_OUTPUT, 3, null) + if(!T) + return + + set_pin_data(IC_OUTPUT, 1, T.x) + set_pin_data(IC_OUTPUT, 2, T.y) + set_pin_data(IC_OUTPUT, 3, T.z) + + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/microphone + name = "microphone" + desc = "Useful for spying on people, or for voice-activated machines." + extended_desc = "This will automatically translate most languages it hears to Zurich Accord Common. \ + The first activation pin is always pulsed when the circuit hears someone talk, while the second one \ + is only triggered if it hears someone speaking a language other than Zurich Accord Common." + icon_state = "recorder" + complexity = 8 + inputs = list() + obj_flags = OBJ_FLAG_CONDUCTIBLE + outputs = list( + "speaker" = IC_PINTYPE_STRING, + "message" = IC_PINTYPE_STRING + ) + activators = list("on message received" = IC_PINTYPE_PULSE_OUT, "on translation" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 5 + +/obj/item/integrated_circuit/input/microphone/Initialize() + . = ..() + global.listening_objects += src + +/obj/item/integrated_circuit/input/microphone/hear_talk(var/mob/living/M, text, verb, decl/language/speaking) + var/translated = TRUE + if(M && text) + if(speaking && !speaking.machine_understands) + text = speaking.scramble(M, text) + translated = FALSE + set_pin_data(IC_OUTPUT, 1, M.GetVoice()) + set_pin_data(IC_OUTPUT, 2, text) + + push_data() + activate_pin(1) + if(translated && !(speaking.type == /decl/language/human/common)) + activate_pin(2) + +/obj/item/integrated_circuit/input/sensor + name = "sensor" + desc = "Scans and obtains a reference for any objects or persons near you. All you need to do is shove the machine in their face." + extended_desc = "If the 'ignore storage' pin is set to true, the sensor will disregard scanning various storage containers such as backpacks." + icon_state = "recorder" + complexity = 12 + inputs = list("ignore storage" = IC_PINTYPE_BOOLEAN) + outputs = list("scanned" = IC_PINTYPE_REF) + activators = list("on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 120 + +/obj/item/integrated_circuit/input/sensor/sense(atom/A, mob/user, prox) + if(!prox || !A || (ismob(A) && !isliving(A))) + return FALSE + if(!check_then_do_work()) + return FALSE + var/ignore_bags = get_pin_data(IC_INPUT, 1) + if(ignore_bags && A.storage) + return FALSE + set_pin_data(IC_OUTPUT, 1, weakref(A)) + push_data() + to_chat(user, "You scan [A] with [assembly].") + activate_pin(1) + return TRUE + +/obj/item/integrated_circuit/input/sensor/ranged + name = "ranged sensor" + desc = "Scans and obtains a reference for any objects or persons in range. All you need to do is point the machine towards the target." + extended_desc = "If the 'ignore storage' pin is set to true, the sensor will disregard scanning various storage containers such as backpacks." + icon_state = "recorder" + complexity = 36 + inputs = list("ignore storage" = IC_PINTYPE_BOOLEAN) + outputs = list("scanned" = IC_PINTYPE_REF) + activators = list("on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 120 + +/obj/item/integrated_circuit/input/sensor/ranged/sense(atom/A, mob/user) + if(!user || !A || (ismob(A) && !isliving(A))) + return FALSE + if(user.client) + if(!(A in view(user.client))) + return FALSE + else + if(!(A in view(user))) + return FALSE + if(!check_then_do_work()) + return FALSE + var/ignore_bags = get_pin_data(IC_INPUT, 1) + if(ignore_bags && A.storage) + return FALSE + set_pin_data(IC_OUTPUT, 1, weakref(A)) + push_data() + to_chat(user, "You scan [A] with [assembly].") + activate_pin(1) + return TRUE + +/obj/item/integrated_circuit/input/obj_scanner + name = "scanner" + desc = "Scans and obtains a reference for any objects you use on the assembly." + extended_desc = "If the 'put down' pin is set to true, the assembly will take the scanned object from your hands to its location. \ + Useful for interaction with the grabber. The scanner only works using the help intent." + icon_state = "recorder" + complexity = 4 + inputs = list("put down" = IC_PINTYPE_BOOLEAN) + outputs = list("scanned" = IC_PINTYPE_REF) + activators = list("on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/obj_scanner/attackby_react(var/atom/A,var/mob/user, decl/intent/intent) + if(istype(intent) && !(intent.intent_flags & I_FLAG_HELP)) + return FALSE + if(!check_then_do_work()) + return FALSE + var/pu = get_pin_data(IC_INPUT, 1) + if(pu && !user.try_unequip(A,get_turf(src))) + return FALSE + set_pin_data(IC_OUTPUT, 1, weakref(A)) + push_data() + to_chat(user, "You let [assembly] scan [A].") + activate_pin(1) + return TRUE + +/obj/item/integrated_circuit/input/internalbm + name = "internal battery monitor" + desc = "This monitors the charge level of an internal battery." + icon_state = "internalbm" + extended_desc = "This circuit will give you the values of charge, max charge, and the current percentage of the internal battery on demand." + w_class = ITEM_SIZE_TINY + complexity = 1 + inputs = list() + outputs = list( + "cell charge" = IC_PINTYPE_NUMBER, + "max charge" = IC_PINTYPE_NUMBER, + "percentage" = IC_PINTYPE_NUMBER, + "refference to assembly" = IC_PINTYPE_REF, + "refference to cell" = IC_PINTYPE_REF + ) + activators = list("read" = IC_PINTYPE_PULSE_IN, "on read" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 1 + +/obj/item/integrated_circuit/input/internalbm/do_work() + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + set_pin_data(IC_OUTPUT, 3, null) + set_pin_data(IC_OUTPUT, 4, null) + set_pin_data(IC_OUTPUT, 5, null) + if(assembly) + set_pin_data(IC_OUTPUT, 4, weakref(assembly)) + if(assembly.battery) + set_pin_data(IC_OUTPUT, 1, assembly.battery.charge) + set_pin_data(IC_OUTPUT, 2, assembly.battery.maxcharge) + set_pin_data(IC_OUTPUT, 3, 100*assembly.battery.charge/assembly.battery.maxcharge) + set_pin_data(IC_OUTPUT, 5, weakref(assembly.battery)) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/externalbm + name = "external battery monitor" + desc = "This can read the battery state of any device in view." + icon_state = "externalbm" + extended_desc = "This circuit will give you the charge, max charge, and the current percentage values of any device or battery in view." + w_class = ITEM_SIZE_TINY + complexity = 2 + inputs = list("target" = IC_PINTYPE_REF) + outputs = list( + "cell charge" = IC_PINTYPE_NUMBER, + "max charge" = IC_PINTYPE_NUMBER, + "percentage" = IC_PINTYPE_NUMBER + ) + activators = list("read" = IC_PINTYPE_PULSE_IN, "on read" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 1 + +/obj/item/integrated_circuit/input/externalbm/do_work() + + var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj) + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + set_pin_data(IC_OUTPUT, 3, null) + if(O) + var/obj/item/cell/cell = O.get_cell() + if(cell) + var/turf/A = get_turf(src) + if(get_turf(O) in view(A)) + set_pin_data(IC_OUTPUT, 1, cell.charge) + set_pin_data(IC_OUTPUT, 2, cell.maxcharge) + set_pin_data(IC_OUTPUT, 3, cell.percent()) + push_data() + activate_pin(2) + return + +/obj/item/integrated_circuit/input/matscan + name = "material scanner" + desc = "This special module is designed to get information about material containers of different machinery, \ + like ORM, lathes, etc." + icon_state = "video_camera" + complexity = 6 + inputs = list( + "target" = IC_PINTYPE_REF + ) + outputs = list( + "Steel" = IC_PINTYPE_NUMBER, + "Silver" = IC_PINTYPE_NUMBER, + "Gold" = IC_PINTYPE_NUMBER, + "Diamond" = IC_PINTYPE_NUMBER, + "Uranium" = IC_PINTYPE_NUMBER, + "Plasteel" = IC_PINTYPE_NUMBER, + "Titanium" = IC_PINTYPE_NUMBER, + "Glass" = IC_PINTYPE_NUMBER, + "Plastic" = IC_PINTYPE_NUMBER, + ) + activators = list( + "scan" = IC_PINTYPE_PULSE_IN, + "on scanned" = IC_PINTYPE_PULSE_OUT, + "not scanned" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 40 + var/list/mtypes = list( + /decl/material/solid/metal/steel, + /decl/material/solid/metal/silver, + /decl/material/solid/metal/gold, + /decl/material/solid/gemstone/diamond, + /decl/material/solid/metal/uranium, + /decl/material/solid/metal/plasteel, + /decl/material/solid/metal/titanium, + /decl/material/solid/glass, + /decl/material/solid/organic/plastic + ) + +/obj/item/integrated_circuit/input/matscan/do_work() + var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj) + if(!O || !O.matter) //Invalid input + return + var/turf/T = get_turf(src) + if(O in view(T)) // This is a camera. It can't examine thngs,that it can't see. + for(var/I in 1 to mtypes.len) + var/amount = O.matter[mtypes[I]] + if(amount) + set_pin_data(IC_OUTPUT, I, amount) + else + set_pin_data(IC_OUTPUT, I, null) + push_data() + activate_pin(2) + else + activate_pin(3) + +/obj/item/integrated_circuit/input/atmospheric_analyzer + name = "atmospheric analyzer" + desc = "A miniaturized analyzer which can scan anything that contains gases. Leave target as NULL to scan the air around the assembly." + extended_desc = "The nth element of gas amounts is the number of moles of the \ + nth gas in gas list. \ + Pressure is in kPa, temperature is in Kelvin. \ + Due to programming limitations, scanning an object that does \ + not contain a gas will return the air around it instead." + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + inputs = list( + "target" = IC_PINTYPE_REF + ) + outputs = list( + "gas list" = IC_PINTYPE_LIST, + "gas amounts" = IC_PINTYPE_LIST, + "total moles" = IC_PINTYPE_NUMBER, + "pressure" = IC_PINTYPE_NUMBER, + "temperature" = IC_PINTYPE_NUMBER, + "volume" = IC_PINTYPE_NUMBER + ) + activators = list( + "scan" = IC_PINTYPE_PULSE_IN, + "on success" = IC_PINTYPE_PULSE_OUT, + "on failure" = IC_PINTYPE_PULSE_OUT + ) + power_draw_per_use = 5 + +/obj/item/integrated_circuit/input/atmospheric_analyzer/do_work() + for(var/i=1 to 6) + set_pin_data(IC_OUTPUT, i, null) + var/atom/target = get_pin_data_as_type(IC_INPUT, 1, /atom) + var/atom/movable/acting_object = get_object() + if(!target) + target = acting_object.loc + if(!target.Adjacent(acting_object)) + activate_pin(3) + return + + var/datum/gas_mixture/air_contents = target.return_air() + if(!air_contents) + activate_pin(3) + return + + var/list/gases = air_contents.gas + var/list/gas_names = list() + var/list/gas_amounts = list() + for(var/id in gases) + var/decl/material/mat = GET_DECL(id) + gas_names.Add(mat.gas_name) + gas_amounts.Add(round(gases[id], 0.001)) + + set_pin_data(IC_OUTPUT, 1, gas_names) + set_pin_data(IC_OUTPUT, 2, gas_amounts) + set_pin_data(IC_OUTPUT, 3, round(air_contents.get_total_moles(), 0.001)) + set_pin_data(IC_OUTPUT, 4, round(air_contents.return_pressure(), 0.001)) + set_pin_data(IC_OUTPUT, 5, round(air_contents.temperature, 0.001)) + set_pin_data(IC_OUTPUT, 6, round(air_contents.total_volume, 0.001)) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/data_card_reader + name = "data card reader" + desc = "A circuit that can read from and write to data cards." + extended_desc = "Setting the \"write mode\" boolean to true will cause any data cards that are used on the assembly to replace\ + their existing function and data strings with the given strings, if it is set to false then using a data card on the assembly will cause\ + the function and data strings stored on the card to be written to the output pins." + icon_state = "card_reader" + complexity = 4 + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + inputs = list( + "function" = IC_PINTYPE_STRING, + "data to store" = IC_PINTYPE_STRING, + "write mode" = IC_PINTYPE_BOOLEAN + ) + outputs = list( + "function" = IC_PINTYPE_STRING, + "stored data" = IC_PINTYPE_STRING + ) + activators = list( + "on write" = IC_PINTYPE_PULSE_OUT, + "on read" = IC_PINTYPE_PULSE_OUT + ) + +/obj/item/integrated_circuit/input/data_card_reader/attackby_react(obj/item/I, mob/user, decl/intent/intent) + var/obj/item/card/data/card = I + var/write_mode = get_pin_data(IC_INPUT, 3) + if(istype(card)) + if(write_mode == TRUE) + card.function = get_pin_data(IC_INPUT, 1) + card.data = get_pin_data(IC_INPUT, 2) + push_data() + activate_pin(1) + else + set_pin_data(IC_OUTPUT, 1, card.function) + set_pin_data(IC_OUTPUT, 2, card.data) + push_data() + activate_pin(2) + else + return FALSE + return TRUE diff --git a/code/modules/integrated_electronics/subtypes/lists.dm b/mods/content/integrated_electronics/components/lists.dm similarity index 99% rename from code/modules/integrated_electronics/subtypes/lists.dm rename to mods/content/integrated_electronics/components/lists.dm index 84f34c9100f9..eb6ba8bff390 100644 --- a/code/modules/integrated_electronics/subtypes/lists.dm +++ b/mods/content/integrated_electronics/components/lists.dm @@ -185,7 +185,7 @@ if(e in output_list) continue output_list.Add(e) - + set_pin_data(IC_OUTPUT, 1, output_list) push_data() activate_pin(2) @@ -332,7 +332,6 @@ outputs = list( "joined text" = IC_PINTYPE_STRING ) - icon_state = "addition" spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH cooldown_per_use = 1 diff --git a/code/modules/integrated_electronics/subtypes/logic.dm b/mods/content/integrated_electronics/components/logic.dm similarity index 100% rename from code/modules/integrated_electronics/subtypes/logic.dm rename to mods/content/integrated_electronics/components/logic.dm diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/mods/content/integrated_electronics/components/manipulation.dm similarity index 83% rename from code/modules/integrated_electronics/subtypes/manipulation.dm rename to mods/content/integrated_electronics/components/manipulation.dm index 5c5ed7b3ca8f..4148ac842ee5 100644 --- a/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/mods/content/integrated_electronics/components/manipulation.dm @@ -34,14 +34,14 @@ QDEL_NULL(installed_gun) return ..() -/obj/item/integrated_circuit/manipulation/weapon_firing/attackby(var/obj/O, var/mob/user) - if(istype(O, /obj/item/gun/energy)) - var/obj/item/gun/energy/gun = O +/obj/item/integrated_circuit/manipulation/weapon_firing/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/gun/energy)) + var/obj/item/gun/energy/gun = used_item if(installed_gun) to_chat(user, "There's already a weapon installed.") - return - if(!user.unEquip(gun,src)) - return + return TRUE + if(!user.try_unequip(gun,src)) + return TRUE installed_gun = gun to_chat(user, "You slide \the [gun] into the firing mechanism.") playsound(src, 'sound/items/Crowbar.ogg', 50, 1) @@ -56,8 +56,9 @@ var/datum/firemode/fm = installed_gun.firemodes[installed_gun.sel_mode] set_pin_data(IC_OUTPUT, 2, fm.name) push_data() + return TRUE else - ..() + return ..() /obj/item/integrated_circuit/manipulation/weapon_firing/attack_self(var/mob/user) if(installed_gun) @@ -89,8 +90,8 @@ yo.data = round(yo.data, 1) var/turf/T = get_turf(assembly) - var/target_x = Clamp(T.x + xo.data, 0, world.maxx) - var/target_y = Clamp(T.y + yo.data, 0, world.maxy) + var/target_x = clamp(T.x + xo.data, 0, world.maxx) + var/target_y = clamp(T.y + yo.data, 0, world.maxy) assembly.visible_message("[assembly] fires [installed_gun]!") shootAt(locate(target_x, target_y, T.z)) @@ -111,7 +112,7 @@ //Shooting Code: A.shot_from = assembly.name A.firer = assembly - A.launch(target, BP_CHEST) + A.launch(target) return A /obj/item/integrated_circuit/manipulation/locomotion @@ -180,14 +181,19 @@ detach_grenade() return ..() -/obj/item/integrated_circuit/manipulation/grenade/attackby(var/obj/item/grenade/G, var/mob/user) - if(istype(G)) +/obj/item/integrated_circuit/manipulation/grenade/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/grenade)) if(attached_grenade) to_chat(user, "There is already a grenade attached!") - else if(user.unEquip(G,src)) - user.visible_message("\The [user] attaches \a [G] to \the [src]!", "You attach \the [G] to \the [src].") - attach_grenade(G) - G.forceMove(src) + return TRUE + if(user.try_unequip(used_item,src)) + user.visible_message( + SPAN_WARNING("\The [user] attaches \a [used_item] to \the [src]!"), + SPAN_NOTICE("You attach \the [used_item] to \the [src].") + ) + attach_grenade(used_item) + used_item.forceMove(src) + return TRUE else return ..() @@ -204,17 +210,17 @@ var/datum/integrated_io/detonation_time = inputs[1] var/dt if(isnum(detonation_time.data) && detonation_time.data > 0) - dt = Clamp(detonation_time.data, 1, 12)*10 + dt = clamp(detonation_time.data, 1, 12)*10 else dt = 15 - addtimer(CALLBACK(attached_grenade, /obj/item/grenade.proc/activate), dt) + addtimer(CALLBACK(attached_grenade, TYPE_PROC_REF(/obj/item/grenade, activate)), dt) var/atom/holder = loc log_and_message_admins("activated a grenade assembly. Last touches: Assembly: [holder.fingerprintslast] Circuit: [fingerprintslast] Grenade: [attached_grenade.fingerprintslast]") // These procs do not relocate the grenade, that's the callers responsibility -/obj/item/integrated_circuit/manipulation/grenade/proc/attach_grenade(var/obj/item/grenade/G) - attached_grenade = G - G.forceMove(src) +/obj/item/integrated_circuit/manipulation/grenade/proc/attach_grenade(var/obj/item/grenade/grenade) + attached_grenade = grenade + grenade.forceMove(src) desc += " \An [attached_grenade] is attached to it!" /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade() @@ -242,25 +248,27 @@ /obj/item/integrated_circuit/manipulation/plant_module/do_work() ..() var/obj/acting_object = get_object() - var/obj/OM = get_pin_data_as_type(IC_INPUT, 1, /obj) - var/obj/O = get_pin_data_as_type(IC_INPUT, 3, /obj/item) + var/obj/input_obj = get_pin_data_as_type(IC_INPUT, 1, /obj) + var/obj/input_item = get_pin_data_as_type(IC_INPUT, 3, /obj/item) - if(!check_target(OM)) + if(!check_target(input_obj)) push_data() activate_pin(2) return - if(istype(OM,/obj/effect/vine) && check_target(OM) && get_pin_data(IC_INPUT, 2) == 2) - qdel(OM) + if(istype(input_obj,/obj/effect/vine) && check_target(input_obj) && get_pin_data(IC_INPUT, 2) == 2) + qdel(input_obj) push_data() activate_pin(2) return - var/obj/machinery/portable_atmospherics/hydroponics/TR = OM - if(istype(TR)) + var/obj/machinery/portable_atmospherics/hydroponics/hydrotray = input_obj + if(istype(hydrotray)) switch(get_pin_data(IC_INPUT, 2)) if(0) - var/list/harvest_output = TR.harvest() + var/list/harvest_output = hydrotray.harvest() + if(harvest_output && !islist(harvest_output)) + harvest_output = list(harvest_output) for(var/i in 1 to length(harvest_output)) harvest_output[i] = weakref(harvest_output[i]) @@ -268,34 +276,30 @@ set_pin_data(IC_OUTPUT, 1, harvest_output) push_data() if(1) - TR.weedlevel = 0 - TR.update_icon() + hydrotray.weedlevel = 0 + hydrotray.update_icon() if(2) - if(TR.seed) //Could be that they're just using it as a de-weeder - TR.age = 0 - TR.health = 0 - if(TR.harvest) - TR.harvest = FALSE //To make sure they can't just put in another seed and insta-harvest it - qdel(TR.seed) - TR.seed = null - TR.weedlevel = 0 //Has a side effect of cleaning up those nasty weeds - TR.dead = 0 - TR.update_icon() + if(hydrotray.seed) //Could be that they're just using it as a de-weeder + hydrotray.age = 0 + hydrotray.plant_health = 0 + if(hydrotray.harvest) + hydrotray.harvest = FALSE //To make sure they can't just put in another seed and insta-harvest it + qdel(hydrotray.seed) + hydrotray.seed = null + hydrotray.weedlevel = 0 //Has a side effect of cleaning up those nasty weeds + hydrotray.dead = 0 + hydrotray.update_icon() if(3) - if(!check_target(O)) + if(!check_target(input_item)) activate_pin(2) return FALSE - else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/cutting)) - if(!TR.seed) - acting_object.visible_message("[acting_object] plants [O].") - TR.dead = 0 - TR.seed = O - TR.age = 1 - TR.health = TR.seed.get_trait(TRAIT_ENDURANCE) - TR.lastcycle = world.time - O.forceMove(TR) - TR.update_icon() + else if(istype(input_item, /obj/item/seeds) && !istype(input_item, /obj/item/seeds/extracted/cutting)) + if(!hydrotray.seed) + var/obj/item/seeds/seed = input_item + acting_object.visible_message("[acting_object] plants [input_item].") + hydrotray.set_seed(seed.seed) + QDEL_NULL(input_item) activate_pin(2) /obj/item/integrated_circuit/manipulation/seed_extractor @@ -312,19 +316,15 @@ /obj/item/integrated_circuit/manipulation/seed_extractor/do_work() ..() - var/obj/item/chems/food/snacks/grown/O = get_pin_data_as_type(IC_INPUT, 1, /obj/item/chems/food/snacks/grown) - if(!check_target(O)) + var/obj/item/food/grown/grown = get_pin_data_as_type(IC_INPUT, 1, /obj/item/food/grown) + if(!check_target(grown)) push_data() activate_pin(2) return var/list/seed_output = list() for(var/i in 1 to rand(1,4)) - var/obj/item/seeds/seeds = new(get_turf(O)) - seeds.seed = SSplants.seeds[O.plantname] - seeds.seed_type = SSplants.seeds[O.seed.name] - seeds.update_seed() - seed_output += weakref(seeds) - qdel(O) + seed_output += weakref(new /obj/item/seeds(get_turf(grown), null, grown.seed)) + qdel(grown) if(seed_output.len) set_pin_data(IC_OUTPUT, 1, seed_output) @@ -351,7 +351,7 @@ var/atom/movable/acting_object = get_object() var/turf/T = get_turf(acting_object) var/obj/item/AM = get_pin_data_as_type(IC_INPUT, 1, /obj/item) - if(!QDELETED(AM) && !istype(AM, /obj/item/electronic_assembly) && !istype(AM, /obj/item/transfer_valve) && !istype(AM, /obj/item/twohanded) && !istype(assembly.loc, /obj/item/implant)) + if(!QDELETED(AM) && !istype(AM, /obj/item/electronic_assembly) && !istype(AM, /obj/item/transfer_valve) && !istype(assembly.loc, /obj/item/implant)) var/mode = get_pin_data(IC_INPUT, 2) if(mode == 1) if(check_target(AM)) @@ -420,9 +420,9 @@ set_pin_data(IC_OUTPUT, 1, TRUE) pulling = to_pull acting_object.visible_message("\The [acting_object] starts pulling \the [to_pull] around.") - GLOB.moved_event.register(to_pull, src, .proc/check_pull) //Whenever the target moves, make sure we can still pull it! - GLOB.destroyed_event.register(to_pull, src, .proc/stop_pulling) //Stop pulling if it gets destroyed - GLOB.moved_event.register(acting_object, src, .proc/pull) //Make sure we actually pull it. + events_repository.register(/decl/observ/moved, to_pull, src, PROC_REF(check_pull)) //Whenever the target moves, make sure we can still pull it! + events_repository.register(/decl/observ/destroyed, to_pull, src, PROC_REF(stop_pulling)) //Stop pulling if it gets destroyed + events_repository.register(/decl/observ/moved, acting_object, src, PROC_REF(pull)) //Make sure we actually pull it. push_data() if(3) if(pulling) @@ -440,12 +440,12 @@ step_towards(pulling, F) activate_pin(2) -/obj/item/integrated_circuit/manipulation/claw/proc/can_pull(var/obj/item/I) - return assembly && I && I.w_class <= assembly.w_class && !I.anchored +/obj/item/integrated_circuit/manipulation/claw/proc/can_pull(var/obj/item/used_item) + return assembly && used_item && used_item.w_class <= assembly.w_class && !used_item.anchored /obj/item/integrated_circuit/manipulation/claw/proc/pull() var/obj/acting_object = get_object() - if(istype(acting_object.loc, /turf)) + if(isturf(acting_object.loc)) step_towards(pulling,src) else stop_pulling() @@ -456,10 +456,10 @@ /obj/item/integrated_circuit/manipulation/claw/proc/stop_pulling() var/atom/movable/AM = get_object() - GLOB.moved_event.unregister(pulling, src) - GLOB.moved_event.unregister(AM, src) - AM.visible_message("\The [AM] stops pulling \the [pulling]") - GLOB.destroyed_event.unregister(pulling, src) + events_repository.unregister(/decl/observ/moved, pulling, src) + events_repository.unregister(/decl/observ/moved, AM, src) + AM.visible_message("\The [AM] stops pulling \the [pulling].") + events_repository.unregister(/decl/observ/destroyed, pulling, src) pulling = null set_pin_data(IC_OUTPUT, 1, FALSE) activate_pin(3) @@ -495,7 +495,7 @@ var/target_y_rel = round(get_pin_data(IC_INPUT, 2)) var/obj/item/A = get_pin_data_as_type(IC_INPUT, 3, /obj/item) - if(!A || A.anchored || A.throwing || A == assembly || istype(A, /obj/item/twohanded) || istype(A, /obj/item/transfer_valve)) + if(!A || A.anchored || A.throwing || A == assembly || istype(A, /obj/item/transfer_valve)) return if (istype(assembly.loc, /obj/item/implant/compressed)) //Prevents the more abusive form of chestgun. @@ -518,15 +518,15 @@ // If the item is in mob's inventory, try to remove it from there. if(ismob(A.loc)) var/mob/living/M = A.loc - if(!M.unEquip(A)) + if(!M.try_unequip(A)) return // If the item is in a grabber circuit we'll update the grabber's outputs after we've thrown it. - var/obj/item/integrated_circuit/manipulation/grabber/G = A.loc + var/obj/item/integrated_circuit/manipulation/grabber/grabber = A.loc - var/x_abs = Clamp(T.x + target_x_rel, 0, world.maxx) - var/y_abs = Clamp(T.y + target_y_rel, 0, world.maxy) - var/range = round(Clamp(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1) + var/x_abs = clamp(T.x + target_x_rel, 0, world.maxx) + var/y_abs = clamp(T.y + target_y_rel, 0, world.maxy) + var/range = round(clamp(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1) assembly.visible_message("[assembly] has thrown [A]!") log_attack("[assembly] \ref[assembly] has thrown [A].") @@ -534,13 +534,13 @@ A.throw_at(locate(x_abs, y_abs, T.z), range, 3) // If the item came from a grabber now we can update the outputs since we've thrown it. - if(istype(G)) - G.update_outputs() + if(istype(grabber)) + grabber.update_outputs() /obj/item/integrated_circuit/manipulation/wormhole name = "wormhole generator" desc = "This powerful circuit can open micro-length wormholes between two points in space." - extended_desc = "If a valid teleporter console is supplied as input then its selected teleporter beacon will be used as destination point, \ + extended_desc = "If a valid teleporter console is supplied as input then its selected teleporter beacon will be used as the destination point, \ and if not an undefined destination point is selected. \ Rift direction is a cardinal value determening in which direction the rift will be opened, relative the local north. \ A direction value of 0 will open the rift on top of the assembly, and any other non-cardinal values will open the rift in the assembly's current facing." @@ -555,18 +555,21 @@ spawn_flags = IC_SPAWN_RESEARCH action_flags = IC_ACTION_LONG_RANGE - origin_tech = "{'magnets':1,'wormholes':3}" + origin_tech = @'{"magnets":1,"wormholes":3}' material = /decl/material/solid/metal/steel matter = list( /decl/material/solid/metal/silver = MATTER_AMOUNT_REINFORCEMENT, /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE ) +/obj/item/integrated_circuit/manipulation/wormhole/preserve_in_cryopod(var/obj/machinery/cryopod/pod) + return TRUE + /obj/item/integrated_circuit/manipulation/wormhole/do_work() var/obj/machinery/computer/teleporter/tporter = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/computer/teleporter) var/step_dir = get_pin_data(IC_INPUT, 2) - if(!ARE_Z_CONNECTED(get_z(src), get_z(tporter))) + if(!LEVELS_ARE_Z_CONNECTED(get_z(src), get_z(tporter))) tporter = null var/turf/rift_location = get_turf(src) @@ -574,7 +577,7 @@ playsound(src, 'sound/effects/sparks2.ogg', 50, 1) return - if(isnum(step_dir) && (!step_dir || (step_dir in GLOB.cardinal))) + if(isnum(step_dir) && (!step_dir || (step_dir in global.cardinal))) rift_location = get_step(rift_location, step_dir) || rift_location else var/obj/item/electronic_assembly/assembly = get_object() @@ -593,7 +596,7 @@ /obj/item/integrated_circuit/manipulation/ai name = "integrated intelligence control circuit" - desc = "Similar in structure to a intellicard, this circuit allows the AI to pulse four different activators for control of a circuit." + desc = "Similar in structure to a intelliCard, this circuit allows the AI to pulse four different activators for control of a circuit." extended_desc = "Loading an AI is easy, all that is required is to insert the container into the device's slot. Unloading is a similar process, simply press\ down on the device in question and the device/card should pop out (if applicable)." icon_state = "ai" @@ -603,7 +606,7 @@ power_draw_per_use = 20 var/obj/item/aicard activators = list("Upwards" = IC_PINTYPE_PULSE_OUT, "Downwards" = IC_PINTYPE_PULSE_OUT, "Left" = IC_PINTYPE_PULSE_OUT, "Right" = IC_PINTYPE_PULSE_OUT) - origin_tech = "{'programming':4}" + origin_tech = @'{"programming":4}' spawn_flags = IC_SPAWN_RESEARCH /obj/item/integrated_circuit/manipulation/ai/verb/open_menu() @@ -631,12 +634,12 @@ to_chat(user, "There is already a card in there!") return var/mob/living/L = locate(/mob/living) in card.contents - if(L && L.key && user.unEquip(card)) + if(L && L.key && user.try_unequip(card)) L.forceMove(src) controlling = L card.dropInto(src) aicard = card - user.visible_message("\The [user] loads \the [card] into \the [src]'s device slot") + user.visible_message("\The [user] loads \the [card] into \the [src]'s device slot.") to_chat(L, "### IICC FIRMWARE LOADED ###") /obj/item/integrated_circuit/manipulation/ai/proc/unload_ai() @@ -650,9 +653,10 @@ controlling = null -/obj/item/integrated_circuit/manipulation/ai/attackby(var/obj/item/I, var/mob/user) - if(is_type_in_list(I, list(/obj/item/aicard, /obj/item/paicard, /obj/item/mmi))) - load_ai(user, I) +/obj/item/integrated_circuit/manipulation/ai/attackby(var/obj/item/used_item, var/mob/user) + if(is_type_in_list(used_item, list(/obj/item/aicard, /obj/item/paicard, /obj/item/organ/internal/brain_interface))) + load_ai(user, used_item) + return TRUE else return ..() /obj/item/integrated_circuit/manipulation/ai/attack_self(user) @@ -678,14 +682,14 @@ cooldown_per_use = 2 SECOND power_draw_per_use = 50 spawn_flags = IC_SPAWN_DEFAULT - origin_tech = "{'engineering':2}" + origin_tech = @'{"engineering":2}' /obj/item/integrated_circuit/manipulation/anchoring/do_work(ord) if(!isturf(assembly.loc)) return // Doesn't work with anchorable assemblies - if(assembly.circuit_flags & IC_FLAG_ANCHORABLE) + if(obj_flags & OBJ_FLAG_ANCHORABLE) visible_message("\The [get_object()]'s anchoring bolt circuitry blinks red. The preinstalled assembly anchoring bolts are in the way of the pop-out bolts!") return @@ -721,7 +725,7 @@ cooldown_per_use = 2 SECOND power_draw_per_use = 50 spawn_flags = IC_SPAWN_DEFAULT - origin_tech = "{'engineering':2}" + origin_tech = @'{"engineering":2}' var/lock_enabled = FALSE diff --git a/code/modules/integrated_electronics/subtypes/memory.dm b/mods/content/integrated_electronics/components/memory.dm similarity index 95% rename from code/modules/integrated_electronics/subtypes/memory.dm rename to mods/content/integrated_electronics/components/memory.dm index c4c127693b4f..bdd5916a2a97 100644 --- a/code/modules/integrated_electronics/subtypes/memory.dm +++ b/mods/content/integrated_electronics/components/memory.dm @@ -18,7 +18,7 @@ complexity = number_of_pins . = ..() -/obj/item/integrated_circuit/memory/examine(mob/user) +/obj/item/integrated_circuit/memory/get_examine_strings(mob/user, distance, infix, suffix) . = ..() var/i for(i = 1, i <= outputs.len, i++) @@ -30,7 +30,7 @@ data = "[d]" else if(!isnull(O.data)) data = O.data - to_chat(user, "\The [src] has [data] saved to address [i].") + . += "\The [src] has [data] saved to address [i]." /obj/item/integrated_circuit/memory/do_work() for(var/i = 1 to inputs.len) @@ -63,7 +63,7 @@ /obj/item/integrated_circuit/memory/huge name = "large memory stick" - desc = "This stick of memory can store up up to sixteen pieces of data." + desc = "This stick of memory can store up to sixteen pieces of data." icon_state = "memory16" w_class = ITEM_SIZE_SMALL spawn_flags = IC_SPAWN_RESEARCH diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/mods/content/integrated_electronics/components/output.dm similarity index 87% rename from code/modules/integrated_electronics/subtypes/output.dm rename to mods/content/integrated_electronics/components/output.dm index 87da8b9b5d3e..d1698dea513d 100644 --- a/code/modules/integrated_electronics/subtypes/output.dm +++ b/mods/content/integrated_electronics/components/output.dm @@ -48,7 +48,7 @@ var/list/nearby_things = range(0, get_turf(src)) for(var/mob/M in nearby_things) var/obj/O = assembly ? assembly : src - to_chat(M, "\icon[O] [stuff_to_display]") + to_chat(M, "[html_icon(O)] [stuff_to_display]") /obj/item/integrated_circuit/output/screen/large name = "large screen" @@ -60,7 +60,7 @@ /obj/item/integrated_circuit/output/screen/large/do_work() ..() var/obj/O = assembly ? get_turf(assembly) : loc - O.visible_message("\icon[O] [stuff_to_display]") + O.visible_message("[html_icon(O)] [stuff_to_display]") /obj/item/integrated_circuit/output/light name = "light" @@ -75,6 +75,7 @@ var/light_brightness = 1 var/light_rgb = "#ffffff" power_draw_idle = 0 // Adjusted based on brightness. + light_wedge = LIGHT_WIDE /obj/item/integrated_circuit/output/light/do_work() light_toggled = !light_toggled @@ -83,7 +84,7 @@ /obj/item/integrated_circuit/output/light/proc/update_lighting() if(light_toggled) if(assembly) - assembly.set_light(light_brightness, 1, 4, 2, light_rgb) + assembly.set_light(4, light_brightness, light_rgb, light_wedge) else if(assembly) assembly.set_light(0) @@ -113,7 +114,7 @@ var/brightness = get_pin_data(IC_INPUT, 2) if(new_color && isnum(brightness)) - brightness = Clamp(brightness, 0, 1) + brightness = clamp(brightness, 0, 1) light_rgb = new_color light_brightness = brightness @@ -152,7 +153,7 @@ var/selected_sound = sounds[ID] if(!selected_sound) return - vol = Clamp(vol ,0 , 100) + vol = clamp(vol ,0 , 100) playsound(get_turf(src), selected_sound, vol, freq, -1) /obj/item/integrated_circuit/output/sound/on_data_written() @@ -228,39 +229,41 @@ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH action_flags = IC_ACTION_LONG_RANGE power_draw_idle = 0 // Raises to 20 when on. - var/obj/machinery/camera/network/research/camera - var/updating = FALSE + var/camera_name = "Video Camera Circuit" /obj/item/integrated_circuit/output/video_camera/Initialize() . = ..() - camera = new(src) - camera.replace_networks(list(NETWORK_THUNDER)) - on_data_written() + set_extension(src, /datum/extension/network_device/camera/circuit, null, null, null, TRUE, list(CAMERA_CHANNEL_RESEARCH), camera_name, FALSE, TRUE) -/obj/item/integrated_circuit/output/video_camera/Destroy() - QDEL_NULL(camera) - return ..() + on_data_written() -/obj/item/integrated_circuit/output/video_camera/proc/set_camera_status(var/status) - if(camera) - camera.set_status(status) - power_draw_idle = camera.status ? 20 : 0 - if(camera.status) // Ensure that there's actually power. - if(!draw_idle_power()) - power_fail() +/obj/item/integrated_circuit/output/video_camera/attack_self(mob/user) + var/datum/extension/network_device/camera/circuit/D = get_extension(src, /datum/extension/network_device) + if(D) + D.ui_interact(user) + return + . = ..() /obj/item/integrated_circuit/output/video_camera/on_data_written() - if(camera) - var/cam_name = get_pin_data(IC_INPUT, 1) - var/cam_active = get_pin_data(IC_INPUT, 2) - if(!isnull(cam_name)) - camera.c_tag = cam_name - set_camera_status(cam_active) + var/cam_name = get_pin_data(IC_INPUT, 1) + var/cam_active = get_pin_data(IC_INPUT, 2) + var/datum/extension/network_device/camera/circuit/D = get_extension(src, /datum/extension/network_device) + if(D) + D.display_name = cam_name + if(cam_active) + power_draw_idle = 20 /obj/item/integrated_circuit/output/video_camera/power_fail() - if(camera) - set_camera_status(0) - set_pin_data(IC_INPUT, 2, FALSE) + power_draw_idle = 0 + set_pin_data(IC_INPUT, 2, FALSE) + +/datum/extension/network_device/camera/circuit + expected_type = /obj/item/integrated_circuit/output/video_camera + +/datum/extension/network_device/camera/circuit/is_functional() + var/obj/item/integrated_circuit/output/video_camera/camera = holder + if(camera.power_draw_idle) + return TRUE /obj/item/integrated_circuit/output/led name = "light-emitting diode" diff --git a/mods/content/integrated_electronics/components/passive.dm b/mods/content/integrated_electronics/components/passive.dm new file mode 100644 index 000000000000..9f635f56cc84 --- /dev/null +++ b/mods/content/integrated_electronics/components/passive.dm @@ -0,0 +1,7 @@ +// 'Passive' components do not have any inputs, and instead contribute in some form to the assembly holding them. +/obj/item/integrated_circuit/passive + inputs = list() + outputs = list() + activators = list() + power_draw_idle = 0 + power_draw_per_use = 0 \ No newline at end of file diff --git a/mods/content/integrated_electronics/components/power.dm b/mods/content/integrated_electronics/components/power.dm new file mode 100644 index 000000000000..15e7214f6f34 --- /dev/null +++ b/mods/content/integrated_electronics/components/power.dm @@ -0,0 +1,88 @@ +/obj/item/integrated_circuit/power + category_text = "Power - Active" + +/obj/item/integrated_circuit/power/transmitter + name = "power transmission circuit" + desc = "This can wirelessly transmit electricity from an assembly's battery towards a nearby machine." + icon_state = "power_transmitter" + extended_desc = "This circuit transmits 5 kJ of electricity every time the activator pin is pulsed. The input pin must be \ + a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \ + inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \ + some power is lost due to ineffiency." + w_class = ITEM_SIZE_SMALL + complexity = 16 + inputs = list("target" = IC_PINTYPE_REF) + outputs = list( + "target cell charge" = IC_PINTYPE_NUMBER, + "target cell max charge" = IC_PINTYPE_NUMBER, + "target cell percentage" = IC_PINTYPE_NUMBER + ) + activators = list("transmit" = IC_PINTYPE_PULSE_IN, "on transmit" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 500 // Inefficency has to come from somewhere. + var/amount_to_move = 5000 + +/obj/item/integrated_circuit/power/transmitter/large + name = "large power transmission circuit" + desc = "This can wirelessly transmit a lot of electricity from an assembly's battery towards a nearby machine. Warning: Do not operate in flammable environments." + extended_desc = "This circuit transmits 20 kJ of electricity every time the activator pin is pulsed. The input pin must be \ + a reference to a machine to send electricity to. This can be a battery, or anything containing a battery. The machine can exist \ + inside the assembly, or adjacent to it. The power is sourced from the assembly's power cell. If the target is outside of the assembly, \ + some power is lost due to ineffiency. Warning! Don't stack more than 1 power transmitter, as it becomes less efficient for every other \ + transmission circuit in its own assembly and other nearby ones." + w_class = ITEM_SIZE_LARGE + complexity = 32 + power_draw_per_use = 2000 + amount_to_move = 20000 + +/obj/item/integrated_circuit/power/transmitter/do_work() + + var/obj/O = get_pin_data_as_type(IC_INPUT, 1, /obj) + if(!O) + return FALSE + if(istype(O, /obj/item/gun/energy)) + return FALSE + if(!assembly) + return FALSE // Pointless to do everything else if there's no battery to draw from. + var/obj/item/cell/cell = O.get_cell() + if(cell) + var/transfer_amount = amount_to_move + var/turf/A = get_turf(src) + var/turf/B = get_turf(O) + if(A.Adjacent(B)) + if(O.loc != assembly) + transfer_amount *= 0.8 // Losses due to distance. + var/transmitter_count = 0 + for(var/obj/item/integrated_circuit/power/transmitter in A.GetAllContents()) + transmitter_count++ + if(!transmitter_count) + return FALSE + transfer_amount /= transmitter_count + set_pin_data(IC_OUTPUT, 1, cell.charge) + set_pin_data(IC_OUTPUT, 2, cell.maxcharge) + set_pin_data(IC_OUTPUT, 3, cell.percent()) + activate_pin(2) + push_data() + if(cell.charge == cell.maxcharge) + return FALSE + if(transfer_amount && assembly.draw_power(amount_to_move)) // CELLRATE is already handled in draw_power() + cell.give(transfer_amount * CELLRATE) + if(istype(O, /obj/item)) + var/obj/item/I = O + I.update_icon() + return TRUE + else + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + set_pin_data(IC_OUTPUT, 3, null) + activate_pin(2) + push_data() + return FALSE + +/obj/item/integrated_circuit/power/transmitter/large/do_work() + if(..()) // If the above code succeeds, do this below. + var/atom/movable/acting_object = get_object() + if(prob(20)) + spark_at(src, amount=12, cardinal_only = TRUE) + acting_object.visible_message("\The [acting_object] makes some sparks!") + return TRUE diff --git a/mods/content/integrated_electronics/components/power_passive.dm b/mods/content/integrated_electronics/components/power_passive.dm new file mode 100644 index 000000000000..5dd6cf487560 --- /dev/null +++ b/mods/content/integrated_electronics/components/power_passive.dm @@ -0,0 +1,140 @@ + +/obj/item/integrated_circuit/passive/power + name = "power thingy" + desc = "Does power stuff." + complexity = 5 + category_text = "Power - Passive" + +/obj/item/integrated_circuit/passive/power/proc/make_energy() + return + +// For calculators. +/obj/item/integrated_circuit/passive/power/solar_cell + name = "tiny photovoltaic cell" + desc = "It's a very tiny solar cell, generally used in calculators." + extended_desc = "This cell generates 1 W of power in optimal lighting conditions. Less light will result in less power being generated." + icon_state = "solar_cell" + complexity = 8 + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/max_power = 30 + +/obj/item/integrated_circuit/passive/power/solar_cell/make_energy() + var/turf/T = get_turf(src) + var/light_amount = T ? T.get_lumcount() : 0 + var/adjusted_power = max(max_power * light_amount, 0) + adjusted_power = round(adjusted_power, 0.1) + if(adjusted_power) + if(assembly) + assembly.give_power(adjusted_power) + +/obj/item/integrated_circuit/passive/power/starter + name = "starter" + desc = "This tiny circuit will send a pulse right after the device is turned on, or when power is restored to it." + icon_state = "led" + complexity = 1 + activators = list("pulse out" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/is_charge = FALSE + +/obj/item/integrated_circuit/passive/power/starter/make_energy() + if(assembly.battery) + if(assembly.battery.charge) + if(!is_charge) + activate_pin(1) + is_charge = TRUE + else + is_charge = FALSE + else + is_charge=FALSE + return FALSE + +// For fat machines that need fat power, like drones. +/obj/item/integrated_circuit/passive/power/relay + name = "tesla power relay" + desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them." + w_class = ITEM_SIZE_SMALL + extended_desc = "The siphon drains 50 W of power from an APC in the same room as it as long as it has charge remaining. It will always drain \ + from the 'equipment' power channel." + icon_state = "power_relay" + complexity = 7 + spawn_flags = IC_SPAWN_RESEARCH + var/power_amount = 50 + + +/obj/item/integrated_circuit/passive/power/relay/make_energy() + if(!assembly) + return + var/area/A = get_area(src) + if(A && A.powered(EQUIP) && assembly.give_power(power_amount)) + A.use_power_oneoff(power_amount, EQUIP) + // give_power() handles CELLRATE on its own. + + +// For really fat machines. +/obj/item/integrated_circuit/passive/power/relay/large + name = "large tesla power relay" + desc = "A seemingly enigmatic device which connects to nearby APCs wirelessly and draws power from them, now in industrial size!" + w_class = ITEM_SIZE_LARGE + extended_desc = "The siphon drains 2 kW of power from an APC in the same room as it as long as it has charge remaining. It will always drain \ + from the 'equipment' power channel." + icon_state = "power_relay" + complexity = 15 + spawn_flags = IC_SPAWN_RESEARCH + power_amount = 1000 + + +//fuel cell +/obj/item/integrated_circuit/passive/power/chemical_cell + name = "fuel cell" + desc = "Produces electricity from chemicals." + icon_state = "chemical_cell" + extended_desc = "This is effectively an internal beaker. It will consume and produce power from hydrogen, welding fuel, carbon,\ + ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy." + atom_flags = ATOM_FLAG_OPEN_CONTAINER + complexity = 4 + outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_REF) + activators = list("push ref" = IC_PINTYPE_PULSE_IN) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + chem_volume = 60 + + var/list/fuel = list( + /decl/material/gas/hydrogen = 50000, + /decl/material/gas/hydrogen/deuterium = 50000, + /decl/material/gas/hydrogen/tritium = 50000, + /decl/material/liquid/fuel = 15000, + /decl/material/solid/carbon = 10000, + /decl/material/liquid/alcohol/ethanol = 10000, + /decl/material/liquid/nutriment = 8000 + ) + var/multi = 1 + +/obj/item/integrated_circuit/passive/power/chemical_cell/Initialize() + . = ..() + extended_desc +="But no fuel can be compared with blood of living human." + + +/obj/item/integrated_circuit/passive/power/chemical_cell/interact(mob/user) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + ..() + +/obj/item/integrated_circuit/passive/power/chemical_cell/on_reagent_change(changetype) + if(!(. = ..())) + return + set_pin_data(IC_OUTPUT, 1, REAGENT_TOTAL_VOLUME(reagents)) + push_data() + +/obj/item/integrated_circuit/passive/power/chemical_cell/make_energy() + if(assembly) + if(assembly.battery) + var/battery_charge = 5000 + if((assembly.battery.maxcharge-assembly.battery.charge) / CELLRATE > battery_charge && remove_from_reagents(/decl/material/liquid/blood, 1)) //only blood is powerful enough to power the station(c) + assembly.give_power(battery_charge) + for(var/I in fuel) + if((assembly.battery.maxcharge-assembly.battery.charge) / CELLRATE > fuel[I]) + if(remove_from_reagents(I, 1)) + assembly.give_power(fuel[I]*multi) + +/obj/item/integrated_circuit/passive/power/chemical_cell/do_work() + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() \ No newline at end of file diff --git a/mods/content/integrated_electronics/components/reagents.dm b/mods/content/integrated_electronics/components/reagents.dm new file mode 100644 index 000000000000..4a28e7772bb2 --- /dev/null +++ b/mods/content/integrated_electronics/components/reagents.dm @@ -0,0 +1,640 @@ +#define IC_SMOKE_REAGENTS_MINIMUM_UNITS 10 +#define IC_REAGENTS_DRAW 0 +#define IC_REAGENTS_INJECT 1 +#define IC_HEATER_MODE_HEAT "heat" +#define IC_HEATER_MODE_COOL "cool" + +/obj/item/integrated_circuit/reagent + category_text = "Reagent" + cooldown_per_use = 10 + +/obj/item/integrated_circuit/reagent/solvent_can_melt(var/solvent_power = MAT_SOLVENT_STRONG) + return FALSE + +/obj/item/integrated_circuit/reagent/Initialize() + . = ..() + if(REAGENT_MAXIMUM_VOLUME(reagents)) + push_vol() + +/obj/item/integrated_circuit/reagent/proc/push_vol() + set_pin_data(IC_OUTPUT, 1, REAGENT_TOTAL_VOLUME(reagents)) + push_data() + +/obj/item/integrated_circuit/reagent/smoke + name = "smoke generator" + desc = "Unlike most electronics, creating smoke is completely intentional." + icon_state = "smoke" + extended_desc = "This smoke generator creates clouds of smoke on command. It can also hold liquids inside, which will go \ + into the smoke clouds when activated. The reagents are consumed when the smoke is made." + ext_cooldown = 1 + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 100 + + complexity = 20 + cooldown_per_use = 1 SECONDS + inputs = list() + outputs = list( + "volume used" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF + ) + activators = list( + "create smoke" = IC_PINTYPE_PULSE_IN, + "on smoked" = IC_PINTYPE_PULSE_OUT, + "push ref" = IC_PINTYPE_PULSE_IN + ) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 20 + var/smoke_radius = 5 + var/notified = FALSE + +/obj/item/integrated_circuit/reagent/on_reagent_change() + if((. = ..())) + push_vol() + +/obj/item/integrated_circuit/reagent/smoke/do_work(ord) + switch(ord) + if(1) + if(!reagents || (REAGENT_TOTAL_VOLUME(reagents) < IC_SMOKE_REAGENTS_MINIMUM_UNITS)) + return + var/location = get_turf(src) + var/datum/effect/effect/system/smoke_spread/chem/S = new + S.attach(location) + playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) + if(S) + S.set_up(reagents, smoke_radius, 0, location) + if(!notified) + notified = TRUE + S.start() + reagents.clear_reagents() + activate_pin(2) + if(3) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + +/obj/item/integrated_circuit/reagent/injector + name = "integrated hypo-injector" + desc = "This scary looking thing is able to pump liquids into, or suck liquids out of, whatever it's pointed at." + icon_state = "injector" + extended_desc = "This autoinjector can push up to 30 units of reagents into another container or someone else outside of the machine. The target \ + must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing. Negative given amounts makes the injector suck out reagents instead." + + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 30 + + complexity = 20 + cooldown_per_use = 6 SECONDS + inputs = list( + "target" = IC_PINTYPE_REF, + "injection amount" = IC_PINTYPE_NUMBER + ) + inputs_default = list( + "2" = 5 + ) + outputs = list( + "volume used" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF + ) + activators = list( + "inject" = IC_PINTYPE_PULSE_IN, + "on injected" = IC_PINTYPE_PULSE_OUT, + "on fail" = IC_PINTYPE_PULSE_OUT, + "push ref" = IC_PINTYPE_PULSE_IN + + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 15 + var/direction_mode = IC_REAGENTS_INJECT + var/transfer_amount = 10 + var/busy = FALSE + +/obj/item/integrated_circuit/reagent/injector/on_data_written() + var/new_amount = get_pin_data(IC_INPUT, 2) + if(new_amount < 0) + new_amount = -new_amount + direction_mode = IC_REAGENTS_DRAW + else + direction_mode = IC_REAGENTS_INJECT + if(isnum(new_amount)) + new_amount = clamp(new_amount, 0, REAGENT_MAXIMUM_VOLUME(reagents)) + transfer_amount = new_amount + + +/obj/item/integrated_circuit/reagent/injector/do_work(ord) + switch(ord) + if(1) + inject() + if(4) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + +/obj/item/integrated_circuit/reagent/injector/proc/target_nearby(var/weakref/target) + var/mob/living/L = target.resolve() + if(!L || get_dist(src,L) > 1) + return + return L + +/obj/item/integrated_circuit/reagent/injector/proc/inject_after(var/weakref/target) + busy = FALSE + var/mob/living/L = target_nearby(target) + if(!L) + activate_pin(3) + return + var/atom/movable/acting_object = get_object() + log_admin("[key_name(L)] was successfully injected with " + reagents.get_reagents() + " by \the [acting_object]") + L.visible_message("\The [acting_object] injects [L] with its needle!", \ + "\The [acting_object] injects you with its needle!") + reagents.trans_to_mob(L, transfer_amount, CHEM_INJECT) + activate_pin(2) + +/obj/item/integrated_circuit/reagent/injector/proc/draw_after(var/weakref/target, var/amount) + busy = FALSE + var/mob/living/target_living = target_nearby(target) + if(!target_living) + activate_pin(3) + return + var/atom/movable/acting_object = get_object() + + target_living.visible_message("\The [acting_object] draws blood from \the [target_living]", + "\The [acting_object] draws blood from you." + ) + target_living.take_blood(src, amount) + activate_pin(2) + + +/obj/item/integrated_circuit/reagent/injector/proc/inject() + set waitfor = FALSE // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing + var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) + var/atom/movable/acting_object = get_object() + + if(busy || !check_target(AM)) + activate_pin(3) + return + + if(!AM.reagents) + activate_pin(3) + return + + if(direction_mode == IC_REAGENTS_INJECT) + if(!REAGENT_TOTAL_VOLUME(reagents) || !REAGENTS_FREE_SPACE(AM?.reagents)) + activate_pin(3) + return + + if(isliving(AM)) + var/mob/living/L = AM + var/injection_status = L.can_inject(null, BP_CHEST) + var/injection_delay = 3 SECONDS + if(injection_status == INJECTION_PORT) + injection_delay += INJECTION_PORT_DELAY + if(!injection_status) + activate_pin(3) + return + //Always log attemped injections for admins + log_admin("[key_name(L)] is getting injected with " + reagents.get_reagents() + " by \the [acting_object]") + L.visible_message("\The [acting_object] is trying to inject [L]!", \ + "\The [acting_object] is trying to inject you!") + busy = TRUE + addtimer(CALLBACK(src, PROC_REF(inject_after), weakref(L)), injection_delay) + return + else + if(!ATOM_IS_OPEN_CONTAINER(AM)) + activate_pin(3) + return + + + reagents.trans_to(AM, transfer_amount) + + else if(direction_mode == IC_REAGENTS_DRAW) + if(REAGENT_TOTAL_VOLUME(reagents) >= REAGENT_MAXIMUM_VOLUME(reagents)) + acting_object.visible_message("\The [acting_object] tries to draw from [AM], but the injector is full.") + activate_pin(3) + return + + var/tramount = abs(transfer_amount) + + if(ishuman(AM)) + var/mob/living/human/H = AM + var/injection_status = H.can_inject(null, BP_CHEST) + var/injection_delay = 3 SECONDS + if(injection_status == INJECTION_PORT) + injection_delay += INJECTION_PORT_DELAY + if(!REAGENT_TOTAL_VOLUME(H.vessel) || !injection_status) + activate_pin(3) + return + H.visible_message( + SPAN_DANGER("\The [acting_object] is trying to take a blood sample from \the [H]!"), + SPAN_DANGER("\The [acting_object] is trying to take a blood sample from you!")) + busy = TRUE + addtimer(CALLBACK(src, PROC_REF(draw_after), weakref(H), tramount), injection_delay) + return + + else + if(!REAGENT_TOTAL_VOLUME(AM.reagents)) + acting_object.visible_message("\The [acting_object] tries to draw from [AM], but it is empty!") + activate_pin(3) + return + + if(!ATOM_IS_OPEN_CONTAINER(AM)) + activate_pin(3) + return + tramount = min(tramount, REAGENT_TOTAL_VOLUME(AM.reagents)) + AM.reagents.trans_to(src, tramount) + activate_pin(2) + + + +/obj/item/integrated_circuit/reagent/pump + name = "reagent pump" + desc = "Moves liquids safely inside a machine, or even nearby it." + icon_state = "reagent_pump" + extended_desc = "This is a pump which will move liquids from the source ref to the target ref. The third pin determines \ + how much liquid is moved per pulse, between 0 and 50. The pump can move reagents to any open container inside the machine, or \ + outside the machine if it is adjacent to the machine." + + complexity = 8 + inputs = list("source" = IC_PINTYPE_REF, "target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER) + inputs_default = list("3" = 5) + outputs = list() + activators = list("transfer reagents" = IC_PINTYPE_PULSE_IN, "on transfer" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/transfer_amount = 10 + var/direction_mode = IC_REAGENTS_INJECT + power_draw_per_use = 10 + +/obj/item/integrated_circuit/reagent/pump/on_data_written() + var/new_amount = get_pin_data(IC_INPUT, 3) + if(new_amount < 0) + new_amount = -new_amount + direction_mode = IC_REAGENTS_DRAW + else + direction_mode = IC_REAGENTS_INJECT + if(isnum(new_amount)) + new_amount = clamp(new_amount, 0, 50) + transfer_amount = new_amount + +/obj/item/integrated_circuit/reagent/pump/do_work() + var/atom/movable/source = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) + var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 2, /atom/movable) + + // Check for invalid input. + if(!check_target(source) || !check_target(target)) + return + + // If the pump is pumping backwards, swap target and source. + if(!direction_mode) + var/temp_source = source + source = target + target = temp_source + + if(!source.reagents) + return + + if(!ATOM_IS_OPEN_CONTAINER(source)) + return + + source.reagents.trans_to(target, transfer_amount) + activate_pin(2) + +/obj/item/integrated_circuit/reagent/storage + cooldown_per_use = 1 + name = "reagent storage" + desc = "Stores liquid inside the device away from electrical components. It can store up to 60u." + icon_state = "reagent_storage" + extended_desc = "This is effectively an internal beaker." + + atom_flags = ATOM_FLAG_OPEN_CONTAINER + chem_volume = 60 + + complexity = 4 + inputs = list() + outputs = list( + "volume used" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF + ) + activators = list("push ref" = IC_PINTYPE_PULSE_IN) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + + + +/obj/item/integrated_circuit/reagent/storage/do_work() + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + +/obj/item/integrated_circuit/reagent/storage/big + name = "big reagent storage" + icon_state = "reagent_storage_big" + desc = "Stores liquid inside the device away from electrical components. Can store up to 180u." + + chem_volume = 180 + + complexity = 16 + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/reagent/storage/cryo + name = "cryo reagent storage" + desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. This will also prevent reactions." + icon_state = "reagent_storage_cryo" + extended_desc = "This is effectively an internal cryo beaker." + + atom_flags = ATOM_FLAG_OPEN_CONTAINER | ATOM_FLAG_NO_CHEM_CHANGE + complexity = 8 + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/reagent/storage/grinder + name = "reagent grinder" + desc = "This is a reagent grinder. It accepts a ref to something and refines it into reagents. It cannot grind materials and can store up to 100u." + icon_state = "blender" + extended_desc = "" + inputs = list( + "target" = IC_PINTYPE_REF, + ) + outputs = list( + "volume used" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF + ) + activators = list( + "grind" = IC_PINTYPE_PULSE_IN, + "on grind" = IC_PINTYPE_PULSE_OUT, + "on fail" = IC_PINTYPE_PULSE_OUT, + "push ref" = IC_PINTYPE_PULSE_IN + ) + chem_volume = 100 + power_draw_per_use = 150 + complexity = 16 + spawn_flags = IC_SPAWN_RESEARCH + + +/obj/item/integrated_circuit/reagent/storage/grinder/do_work(ord) + switch(ord) + if(1) + grind() + if(4) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + +/obj/item/integrated_circuit/reagent/storage/grinder/proc/grind() + if(REAGENT_TOTAL_VOLUME(reagents) >= REAGENT_MAXIMUM_VOLUME(reagents)) + activate_pin(3) + return FALSE + var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item) + + if(isnull(I)) + return FALSE + + if(!I.reagents || !REAGENT_TOTAL_VOLUME(I.reagents)) + activate_pin(3) + return FALSE + + I.reagents.trans_to(src,REAGENT_TOTAL_VOLUME(I.reagents)) + if(!REAGENT_TOTAL_VOLUME(I.reagents)) + qdel(I) + + activate_pin(2) + return FALSE + + + +/obj/item/integrated_circuit/reagent/storage/scan + name = "reagent scanner" + desc = "Stores liquid inside the device away from electrical components. It can store up to 60u. On pulse this beaker will send list of contained reagents." + icon_state = "reagent_scan" + extended_desc = "Mostly useful for filtering reagents." + + complexity = 8 + outputs = list( + "volume used" = IC_PINTYPE_NUMBER, + "self reference" = IC_PINTYPE_REF, + "list of reagents" = IC_PINTYPE_LIST + ) + activators = list( + "scan" = IC_PINTYPE_PULSE_IN, + "push ref" = IC_PINTYPE_PULSE_IN + ) + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/reagent/storage/scan/do_work(ord) + switch(ord) + if(1) + var/cont[0] + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(reagents)) + cont += reagent.name + set_pin_data(IC_OUTPUT, 3, cont) + push_data() + if(2) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + +/obj/item/integrated_circuit/reagent/filter + name = "reagent filter" + desc = "Filters liquids by list of desired or unwanted reagents." + icon_state = "reagent_filter" + extended_desc = "This is a filter which will move liquids from the source to its target. \ + If the amount in the fourth pin is positive, it will move all reagents except those in the unwanted list. \ + If the amount in the fourth pin is negative, it will only move the reagents in the wanted list. \ + The third pin determines how many reagents are moved per pulse, between 0 and 50. Amount is given for each separate reagent." + + complexity = 8 + inputs = list( + "source" = IC_PINTYPE_REF, + "target" = IC_PINTYPE_REF, + "injection amount" = IC_PINTYPE_NUMBER, + "list of reagents" = IC_PINTYPE_LIST + ) + inputs_default = list( + "3" = 5 + ) + outputs = list() + activators = list( + "transfer reagents" = IC_PINTYPE_PULSE_IN, + "on transfer" = IC_PINTYPE_PULSE_OUT + ) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/transfer_amount = 10 + var/direction_mode = IC_REAGENTS_INJECT + power_draw_per_use = 10 + +/obj/item/integrated_circuit/reagent/filter/on_data_written() + var/new_amount = get_pin_data(IC_INPUT, 3) + if(new_amount < 0) + new_amount = -new_amount + direction_mode = IC_REAGENTS_DRAW + else + direction_mode = IC_REAGENTS_INJECT + if(isnum(new_amount)) + new_amount = clamp(new_amount, 0, 50) + transfer_amount = new_amount + +/obj/item/integrated_circuit/reagent/filter/do_work() + var/atom/movable/source = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) + var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 2, /atom/movable) + var/list/demand = get_pin_data(IC_INPUT, 4) + + // Check for invalid input. + if(!check_target(source) || !check_target(target)) + return + + if(!source.reagents || !target.reagents) + return + + if(!ATOM_IS_OPEN_CONTAINER(source) || ismob(source)) + return + + if(REAGENT_MAXIMUM_VOLUME(target.reagents) - REAGENT_TOTAL_VOLUME(target.reagents) <= 0) + return + + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(source.reagents)) + if(!direction_mode) + if(reagent.name in demand) + source.reagents.trans_type_to(target, reagent, transfer_amount) + else + if(!(reagent.name in demand)) + source.reagents.trans_type_to(target, reagent, transfer_amount) + activate_pin(2) + push_data() + +// This is an input circuit because attackby_react is only called for input circuits +/obj/item/integrated_circuit/input/funnel + category_text = "Reagent" + name = "reagent funnel" + desc = "A funnel with a small pump that lets you refill an internal reagent storage." + icon_state = "reagent_funnel" + + inputs = list( + "target" = IC_PINTYPE_REF + ) + activators = list( + "on transfer" = IC_PINTYPE_PULSE_OUT + ) + + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + complexity = 4 + power_draw_per_use = 5 + +/obj/item/integrated_circuit/input/funnel/solvent_can_melt(var/solvent_power = MAT_SOLVENT_STRONG) + return FALSE + +/obj/item/integrated_circuit/input/funnel/attackby_react(obj/item/I, mob/user, decl/intent/intent) + var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) + var/obj/item/chems/container = I + + if(!check_target(target)) + return FALSE + + if(!istype(container)) + return FALSE + + // Messages are provided by standard_pour_into + if(container.standard_pour_into(user, target)) + activate_pin(1) + return TRUE + + return FALSE + +// Most of this is just chemical heater code refitted for ICs +/obj/item/integrated_circuit/reagent/temp + inputs = list( + "target temperature" = IC_PINTYPE_NUMBER + ) + outputs = list( + "volume used" = IC_PINTYPE_NUMBER, + "temperature" = IC_PINTYPE_NUMBER, + "enabled" = IC_PINTYPE_BOOLEAN, + "self reference" = IC_PINTYPE_REF + ) + activators = list( + "toggle" = IC_PINTYPE_PULSE_IN, + "on toggle" = IC_PINTYPE_PULSE_OUT, + "push ref" = IC_PINTYPE_PULSE_IN + ) + + atom_flags = ATOM_FLAG_OPEN_CONTAINER + complexity = 12 + cooldown_per_use = 1 + power_draw_per_use = 50 + chem_volume = 30 + + var/active = 0 + var/min_temp = 40 CELSIUS + var/max_temp = 200 CELSIUS + var/heating_power = 5 + var/target_temp = T20C + var/last_temperature = 0 + var/mode = IC_HEATER_MODE_HEAT + +/obj/item/integrated_circuit/reagent/temp/Initialize() + . = ..() + + set_pin_data(IC_OUTPUT, 2, temperature - T0C) + push_data() + +/obj/item/integrated_circuit/reagent/temp/do_work(ord) + switch(ord) + if(1) + target_temp = get_pin_data(IC_INPUT, 1) + if(isnull(target_temp)) + return + + // +/- T0C to convert to/from kelvin + target_temp = clamp(target_temp + T0C, min_temp, max_temp) + set_pin_data(IC_INPUT, 1, target_temp - T0C) + + active = !active + set_pin_data(IC_OUTPUT, 3, active) + push_data() + activate_pin(2) + + // begin processing temperature + if(active) + queue_temperature_atoms(src) + if(3) + set_pin_data(IC_OUTPUT, 4, weakref(src)) + push_data() + +/obj/item/integrated_circuit/reagent/temp/power_fail() + active = 0 + +/obj/item/integrated_circuit/reagent/temp/ProcessAtomTemperature() + if(!active) + return PROCESS_KILL + + last_temperature = temperature + + if(mode == IC_HEATER_MODE_HEAT && temperature < target_temp) + temperature = min(temperature + heating_power, max_temp) + else if(mode == IC_HEATER_MODE_COOL && temperature > target_temp) + temperature = max(temperature - heating_power, min_temp) + + if(temperature != last_temperature) + // Lost power + if(!check_power()) + power_fail() + return ..() + + set_pin_data(IC_OUTPUT, 2, temperature - T0C) + push_data() + + return TRUE + +/obj/item/integrated_circuit/reagent/temp/heater + name = "reagent heater" + desc = "A small reagent container capable of heating reagents. It can hold up to 30u." + icon_state = "reagent_heater" + extended_desc = "This is effectively an internal beaker. It has a heating coil wrapped around it, which allows it to heat the contents of the beaker. Temperature is given in celsius." + + spawn_flags = IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/reagent/temp/cooler + name = "reagent cooler" + desc = "A small reagent container capable of cooling reagents. It can hold up to 30u." + icon_state = "reagent_cooler" + extended_desc = "This is effectively an internal beaker. It has a cooling mechanism wrapped around it, which allows it to cool the contents of the beaker. Temperature is given in celsius." + + spawn_flags = IC_SPAWN_RESEARCH + + min_temp = -80 CELSIUS + max_temp = 30 CELSIUS + mode = IC_HEATER_MODE_COOL + +#undef IC_HEATER_MODE_HEAT +#undef IC_HEATER_MODE_COOL +#undef IC_REAGENTS_DRAW +#undef IC_REAGENTS_INJECT \ No newline at end of file diff --git a/code/modules/integrated_electronics/subtypes/smart.dm b/mods/content/integrated_electronics/components/smart.dm similarity index 81% rename from code/modules/integrated_electronics/subtypes/smart.dm rename to mods/content/integrated_electronics/components/smart.dm index baa6212b4bd7..4f2781f5c11f 100644 --- a/code/modules/integrated_electronics/subtypes/smart.dm +++ b/mods/content/integrated_electronics/components/smart.dm @@ -4,7 +4,7 @@ /obj/item/integrated_circuit/smart/basic_pathfinder name = "basic pathfinder" desc = "This complex circuit is able to determine what direction a given target is." - extended_desc = "This circuit uses a miniturized integrated camera to determine where the target is. If the machine \ + extended_desc = "This circuit uses a miniaturized integrated camera to determine where the target is. If the machine \ cannot see the target, it will not be able to calculate the correct direction." icon_state = "numberpad" complexity = 5 @@ -57,8 +57,8 @@ activate_pin(3) return var/turf/T = get_turf(assembly) - var/target_x = Clamp(get_pin_data(IC_INPUT, 1), 0, world.maxx) - var/target_y = Clamp(get_pin_data(IC_INPUT, 2), 0, world.maxy) + var/target_x = clamp(get_pin_data(IC_INPUT, 1), 0, world.maxx) + var/target_y = clamp(get_pin_data(IC_INPUT, 2), 0, world.maxy) var/turf/A = locate(target_x, target_y, T.z) set_pin_data(IC_OUTPUT, 1, null) if(!A||A==T) @@ -96,6 +96,10 @@ return ..() /obj/item/integrated_circuit/smart/advanced_pathfinder/do_work() + + if(waiting_for_path) + return + if(!assembly) activate_pin(3) return @@ -119,20 +123,30 @@ if(Pl&&islist(Pl)) idc.access = Pl var/turf/a_loc = get_turf(assembly) - var/list/P = AStar(a_loc, locate(get_pin_data(IC_INPUT, 1), get_pin_data(IC_INPUT, 2), a_loc.z), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 200, id=idc, exclude=get_turf(get_pin_data_as_type(IC_INPUT, 3, /atom))) + SSpathfinding.enqueue_mover( + src, + locate(get_pin_data(IC_INPUT, 1), get_pin_data(IC_INPUT, 2), a_loc.z), + new /datum/pathfinding_metadata( + _max_node_depth = 200, + _id = idc, + _obstacle = get_turf(get_pin_data_as_type(IC_INPUT, 3, /atom)) + ) + ) - if(!P) - activate_pin(3) - return - else - var/list/Xn = new/list(P.len) - var/list/Yn = new/list(P.len) - var/turf/T - for(var/i =1 to P.len) - T=P[i] - Xn[i] = T.x - Yn[i] = T.y - set_pin_data(IC_OUTPUT, 1, Xn) - set_pin_data(IC_OUTPUT, 2, Yn) - push_data() - activate_pin(2) +/obj/item/integrated_circuit/smart/advanced_pathfinder/path_not_found() + ..() + activate_pin(3) + +/obj/item/integrated_circuit/smart/advanced_pathfinder/path_found(list/path) + ..() + var/list/Xn = new/list(path.len) + var/list/Yn = new/list(path.len) + var/turf/T + for(var/i = 1 to path.len) + T=path[i] + Xn[i] = T.x + Yn[i] = T.y + set_pin_data(IC_OUTPUT, 1, Xn) + set_pin_data(IC_OUTPUT, 2, Yn) + push_data() + activate_pin(2) diff --git a/code/modules/integrated_electronics/subtypes/time.dm b/mods/content/integrated_electronics/components/time.dm similarity index 96% rename from code/modules/integrated_electronics/subtypes/time.dm rename to mods/content/integrated_electronics/components/time.dm index 594f0c91a049..c9739ceed0a9 100644 --- a/code/modules/integrated_electronics/subtypes/time.dm +++ b/mods/content/integrated_electronics/components/time.dm @@ -17,7 +17,7 @@ power_draw_per_use = 2 /obj/item/integrated_circuit/time/delay/do_work() - addtimer(CALLBACK(src, .proc/activate_pin, 2), delay) + addtimer(CALLBACK(src, PROC_REF(activate_pin), 2), delay) /obj/item/integrated_circuit/time/delay/five_sec name = "five-sec delay circuit" @@ -64,7 +64,7 @@ /obj/item/integrated_circuit/time/delay/custom/do_work() var/delay_input = get_pin_data(IC_INPUT, 1) if(delay_input && isnum(delay_input) ) - var/new_delay = Clamp(delay_input ,1 ,36000) //An hour. + var/new_delay = clamp(delay_input ,1 ,36000) //An hour. delay = new_delay ..() @@ -98,7 +98,7 @@ /obj/item/integrated_circuit/time/ticker/proc/tick() if(is_running) - addtimer(CALLBACK(src, .proc/tick), delay) + addtimer(CALLBACK(src, PROC_REF(tick)), delay) if(world.time > next_fire) next_fire = world.time + delay activate_pin(1) @@ -119,7 +119,7 @@ /obj/item/integrated_circuit/time/ticker/custom/on_data_written() var/delay_input = get_pin_data(IC_INPUT, 2) if(delay_input && isnum(delay_input) ) - var/new_delay = Clamp(delay_input ,1 ,1 HOURS) + var/new_delay = clamp(delay_input ,1 ,1 HOURS) delay = new_delay ..() diff --git a/code/modules/integrated_electronics/subtypes/trig.dm b/mods/content/integrated_electronics/components/trig.dm similarity index 100% rename from code/modules/integrated_electronics/subtypes/trig.dm rename to mods/content/integrated_electronics/components/trig.dm diff --git a/mods/content/integrated_electronics/fabricator_designs.dm b/mods/content/integrated_electronics/fabricator_designs.dm new file mode 100644 index 000000000000..0b6dc3289f5a --- /dev/null +++ b/mods/content/integrated_electronics/fabricator_designs.dm @@ -0,0 +1,17 @@ +/datum/fabricator_recipe/tool/int_wirer + path = /obj/item/wirer + +/datum/fabricator_recipe/tool/int_debugger + path = /obj/item/debugger + +/datum/fabricator_recipe/tool/int_analyzer + path = /obj/item/analyzer + +/datum/fabricator_recipe/protolathe/integrated_printer + path = /obj/item/integrated_circuit_printer + +/datum/fabricator_recipe/protolathe/integrated_printer_upgrade_advanced + path = /obj/item/disk/integrated_circuit/upgrade/advanced + +/datum/fabricator_recipe/protolathe/integrated_printer_upgrade_clone + path = /obj/item/disk/integrated_circuit/upgrade/clone diff --git a/mods/content/integrated_electronics/helpers.dm b/mods/content/integrated_electronics/helpers.dm new file mode 100644 index 000000000000..4dafa7df5d9f --- /dev/null +++ b/mods/content/integrated_electronics/helpers.dm @@ -0,0 +1,148 @@ +/obj/item/integrated_circuit/proc/setup_io(list/io_list, io_type, list/io_default_list, pin_type) + if(!io_list) + return + var/list/io_list_copy = io_list.Copy() + io_list.Cut() + for(var/i in 1 to io_list_copy.len) + var/io_entry = io_list_copy[i] + var/default_data = null + var/io_type_override = null + + // Override the default data. + if(length(io_default_list)) // List containing special pin types that need to be added. + default_data = io_default_list["[i]"] // This is deliberately text because the index is a number in text form. + + // Override the pin type. + if(io_list_copy[io_entry]) + io_type_override = io_list_copy[io_entry] + + if(io_type_override) + io_list.Add(new io_type_override(src, io_entry, default_data, pin_type,i)) + else + io_list.Add(new io_type(src, io_entry, default_data, pin_type,i)) + + +/obj/item/integrated_circuit/proc/set_pin_data(pin_type, pin_number, datum/new_data) + if(islist(new_data)) + var/list/new_list = new_data + for(var/i in 1 to length(new_data)) + if (istype(new_list[i], /datum) && !isweakref(new_list[i])) + new_list[i] = weakref(new_list[i]) + if (istype(new_data) && !isweakref(new_data)) + new_data = weakref(new_data) + var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) + return pin.write_data_to_pin(new_data) + +/obj/item/integrated_circuit/proc/get_pin_data(pin_type, pin_number) + var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) + return pin.get_data() + +/obj/item/integrated_circuit/proc/get_pin_data_as_type(pin_type, pin_number, as_type) + var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) + return pin.data_as_type(as_type) + +/obj/item/integrated_circuit/proc/activate_pin(pin_number) + var/datum/integrated_io/activate/A = activators[pin_number] + A.push_data() + +/obj/item/integrated_circuit/proc/get_pin_ref(pin_type, pin_number) + switch(pin_type) + if(IC_INPUT) + if(!inputs || pin_number > inputs.len) + return + return inputs[pin_number] + if(IC_OUTPUT) + if(!outputs || pin_number > outputs.len) + return + return outputs[pin_number] + if(IC_ACTIVATOR) + if(!activators || pin_number > activators.len) + return + return activators[pin_number] + return + +/datum/integrated_io/proc/get_data() + if(islist(data)) + var/list/data_list = data + data_list = data_list.Copy() + for(var/i in 1 to length(data_list)) + if(isweakref(data_list[i])) + var/weakref/dw = data_list[i] + data_list[i] = dw.resolve() + return data_list + if(isweakref(data)) + return data.resolve() + return data + + +// Returns a list of parameters necessary to locate a pin in the assembly: component number, pin type and pin number +// Components list can be supplied from the outside, for use in savefiles +/datum/integrated_io/proc/get_pin_parameters(list/components) + if(!holder) + return + + if(!components) + if(!holder.assembly) + return + components = holder.assembly.assembly_components + + var/component_number = components.Find(holder) + + var/list/pin_holder_list + switch(pin_type) + if(IC_INPUT) + pin_holder_list = holder.inputs + if(IC_OUTPUT) + pin_holder_list = holder.outputs + if(IC_ACTIVATOR) + pin_holder_list = holder.activators + else + return + + var/pin_number = pin_holder_list.Find(src) + + return list(component_number, pin_type, pin_number) + + +// Locates a pin in the assembly when given component number, pin type and pin number +// Components list can be supplied from the outside, for use in savefiles +/obj/item/electronic_assembly/proc/get_pin_ref(component_number, pin_type, pin_number, list/components) + if(!components) + components = assembly_components + + if(component_number > components.len) + return + + var/obj/item/integrated_circuit/component = components[component_number] + return component.get_pin_ref(pin_type, pin_number) + + +// Same as get_pin_ref, but takes in a list of 3 parameters (same format as get_pin_parameters) +// and performs extra sanity checks on parameters list and index numbers +/obj/item/electronic_assembly/proc/get_pin_ref_list(list/parameters, list/components) + if(!components) + components = assembly_components + + if(!islist(parameters) || parameters.len != 3) + return + + // Those are supposed to be list indexes, check them for sanity + if(!isnum(parameters[1]) || parameters[1] % 1 || parameters[1] < 1) + return + + if(!isnum(parameters[3]) || parameters[3] % 1 || parameters[3] < 1) + return + + return get_pin_ref(parameters[1], parameters[2], parameters[3], components) + +// this is for data validation of stuff like ref encodes and more importantly ID access lists + +/proc/compute_signature(data) + return md5(SScircuit.cipherkey + data) + +/proc/add_data_signature(data) + var/signature = compute_signature(data) + return "[signature]:[data]" + +/proc/check_data_signature(signature, data) + return (compute_signature(data) == signature) diff --git a/mods/content/integrated_electronics/overrides.dm b/mods/content/integrated_electronics/overrides.dm new file mode 100644 index 000000000000..f6fae6639ac8 --- /dev/null +++ b/mods/content/integrated_electronics/overrides.dm @@ -0,0 +1,12 @@ +// Allows the detailer to be used to set data cards' detail color, in addition to the paint sprayer. +/obj/item/card/data/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/detailer)) + var/obj/item/detailer/D = used_item + detail_color = D.detail_color + update_icon() + return TRUE + return ..() + +// Gives the research borg a hand tele. +/obj/item/robot_module/research + emag = /obj/abstract/prefab/hand_teleporter \ No newline at end of file diff --git a/mods/content/integrated_electronics/pins/_pins.dm b/mods/content/integrated_electronics/pins/_pins.dm new file mode 100644 index 000000000000..1cd253dfcb93 --- /dev/null +++ b/mods/content/integrated_electronics/pins/_pins.dm @@ -0,0 +1,202 @@ +/* + Pins both hold data for circuits, as well move data between them. Some also cause circuits to do their function. DATA_CHANNEL pins are the data holding/moving kind, +where as PULSE_CHANNEL causes circuits to work() when their pulse hits them. + + +A visualization of how pins work is below. Imagine the below image involves an addition circuit. +When the bottom pin, the activator, receives a pulse, all the numbers on the left (input) get added, and the answer goes on the right side (output). + +Inputs Outputs + +A [2]\ /[8] result +B [1]-\|++|/ +C [4]-/|++| +D [1]/ || + || + Activator + + + +*/ +/datum/integrated_io + var/name = "input/output" + var/obj/item/integrated_circuit/holder + var/weakref/data // This is a weakref, to reduce typecasts. Note that oftentimes numbers and text may also occupy this. + var/list/linked = list() + var/io_type = DATA_CHANNEL + var/pin_type // IC_INPUT, IC_OUTPUT, IC_ACTIVATOR - used in saving assembly wiring + var/ord + +/datum/integrated_io/New(loc, _name, _data, _pin_type,_ord) + name = _name + if(_data) + data = _data + if(_pin_type) + pin_type = _pin_type + if(_ord) + ord = _ord + + holder = loc + + if(!istype(holder)) + message_admins("ERROR: An integrated_io ([name]) spawned without a valid holder! This is a bug.") + +/datum/integrated_io/Destroy() + disconnect_all() + data = null + holder = null + return ..() + +/datum/integrated_io/proc/data_as_type(var/as_type) + if(!isweakref(data)) + return + var/weakref/w = data + var/output = w.resolve() + return istype(output, as_type) ? output : null + +/datum/integrated_io/proc/display_data(var/input) + if(isnull(input)) + return "(null)" // Empty data means nothing to show. + + if(istext(input)) + return "(\"[input]\")" // Wraps the 'string' in escaped quotes, so that people know it's a 'string'. + + if(islist(input)) + var/list/my_list = input + var/result = "list\[[my_list.len]\](" + if(my_list.len) + result += "
    " + var/pos = 0 + for(var/line in my_list) + result += "[display_data(line)]" + pos++ + if(pos != my_list.len) + result += ",
    " + result += "
    " + result += ")" + return result + + if(isweakref(input)) + var/weakref/w = input + var/atom/A = w.resolve() + return A ? "([strip_improper(A.name)] \[Ref\])" : "(null)" // For refs, we want just the name displayed. + + return "([input])" // Nothing special needed for numbers or other stuff. + +/datum/integrated_io/activate/display_data() + return "(\[pulse\])" + +/datum/integrated_io/proc/display_pin_type() + return VAR_FORMAT_ANY + +/datum/integrated_io/activate/display_pin_type() + return IC_FORMAT_PULSE + +/datum/integrated_io/proc/scramble() + if(isnull(data)) + return + if(isnum(data)) + write_data_to_pin(rand(-10000, 10000)) + if(istext(data)) + write_data_to_pin("ERROR") + push_data() + +/datum/integrated_io/activate/scramble() + push_data() + +/datum/integrated_io/proc/handle_wire(datum/integrated_io/linked_pin, obj/item/tool, action, mob/living/user) + if(istype(tool, /obj/item/wirer)) + var/obj/item/wirer/wirer = tool + if(linked_pin) + wirer.wire(linked_pin, user) + else + wirer.wire(src, user) + return TRUE + + else if(istype(tool, /obj/item/debugger)) + var/obj/item/debugger/debugger = tool + debugger.write_data(src, user) + return TRUE + + return FALSE + +/datum/integrated_io/proc/write_data_to_pin(new_data) + if(isnull(new_data) || isnum(new_data) || istext(new_data) || isweakref(new_data)) + data = new_data + holder.on_data_written() + else if(islist(new_data)) + var/list/new_list = new_data + data = new_list.Copy(max(1,new_list.len - IC_MAX_LIST_LENGTH+1),0) + holder.on_data_written() + +/datum/integrated_io/proc/push_data() + for(var/k in 1 to linked.len) + var/datum/integrated_io/io = linked[k] + io.write_data_to_pin(data) + +/datum/integrated_io/activate/push_data() + for(var/k in 1 to linked.len) + var/datum/integrated_io/io = linked[k] + SScircuit_components.queue_component(io.holder, TRUE, io.ord) + +/datum/integrated_io/proc/pull_data() + for(var/k in 1 to linked.len) + var/datum/integrated_io/io = linked[k] + write_data_to_pin(io.data) + +/datum/integrated_io/proc/connect_pin(datum/integrated_io/pin) + pin.linked |= src + linked |= pin + +// Iterates over every linked pin and disconnects them. +/datum/integrated_io/proc/disconnect_all() + for(var/pin in linked) + disconnect_pin(pin) + +/datum/integrated_io/proc/disconnect_pin(datum/integrated_io/pin) + pin.linked.Remove(src) + linked.Remove(pin) + + +/datum/integrated_io/proc/ask_for_data_type(mob/user, var/default, var/list/allowed_data_types = list("string","number","null")) + var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in allowed_data_types + if(!holder.check_interactivity(user)) + return + + var/new_data = null + switch(type_to_use) + if("string") + var/input_text = input(user, "Now type in a string.", "[src] string writing", istext(default) ? default : null) as null|text + new_data = sanitize(input_text, trim = 0) + if(istext(new_data) && holder.check_interactivity(user) ) + to_chat(user, "You input "+new_data+" into the pin.") + return new_data + if("number") + new_data = input("Now type in a number.","[src] number writing", isnum(default) ? default : null) as null|num + if(isnum(new_data) && holder.check_interactivity(user) ) + to_chat(user, "You input [new_data] into the pin.") + return new_data + if("null") + if(holder.check_interactivity(user)) + to_chat(user, "You clear the pin's memory.") + return new_data + +// Basically a null check +/datum/integrated_io/proc/is_valid() + return !isnull(data) + +// This proc asks for the data to write, then writes it. +/datum/integrated_io/proc/ask_for_pin_data(mob/user) + var/new_data = ask_for_data_type(user) + write_data_to_pin(new_data) + +/datum/integrated_io/activate/ask_for_pin_data(mob/user) // This just pulses the pin. + holder.check_then_do_work(ord,ignore_power = TRUE) + to_chat(user, "You pulse \the [holder]'s [src] pin.") + +/datum/integrated_io/activate + name = "activation pin" + io_type = PULSE_CHANNEL + +/datum/integrated_io/activate/out // All this does is just make the UI say 'out' instead of 'in' + data = 1 diff --git a/code/modules/integrated_electronics/core/special_pins/boolean_pin.dm b/mods/content/integrated_electronics/pins/boolean_pin.dm similarity index 96% rename from code/modules/integrated_electronics/core/special_pins/boolean_pin.dm rename to mods/content/integrated_electronics/pins/boolean_pin.dm index da59434b6534..b775aa9f8f89 100644 --- a/code/modules/integrated_electronics/core/special_pins/boolean_pin.dm +++ b/mods/content/integrated_electronics/pins/boolean_pin.dm @@ -18,7 +18,7 @@ push_data() /datum/integrated_io/boolean/display_pin_type() - return IC_FORMAT_BOOLEAN + return VAR_FORMAT_BOOLEAN /datum/integrated_io/boolean/display_data(var/input) if(data) diff --git a/code/modules/integrated_electronics/core/special_pins/char_pin.dm b/mods/content/integrated_electronics/pins/char_pin.dm similarity index 97% rename from code/modules/integrated_electronics/core/special_pins/char_pin.dm rename to mods/content/integrated_electronics/pins/char_pin.dm index 20f4190c71a2..0ab9a1c0f231 100644 --- a/code/modules/integrated_electronics/core/special_pins/char_pin.dm +++ b/mods/content/integrated_electronics/pins/char_pin.dm @@ -25,4 +25,4 @@ push_data() /datum/integrated_io/char/display_pin_type() - return IC_FORMAT_CHAR + return VAR_FORMAT_CHAR diff --git a/code/modules/integrated_electronics/core/special_pins/color_pin.dm b/mods/content/integrated_electronics/pins/color_pin.dm similarity index 89% rename from code/modules/integrated_electronics/core/special_pins/color_pin.dm rename to mods/content/integrated_electronics/pins/color_pin.dm index 30b0a1895d2d..39935b40ce14 100644 --- a/code/modules/integrated_electronics/core/special_pins/color_pin.dm +++ b/mods/content/integrated_electronics/pins/color_pin.dm @@ -31,17 +31,11 @@ /datum/integrated_io/color/scramble() if(!is_valid()) return - var/new_data - for(var/i=1;i<=3;i++) - var/temp_col = "[num2hex(rand(0,255))]" - if(length(temp_col )<2) - temp_col = "0[temp_col]" - new_data += temp_col - data = new_data + data = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) push_data() /datum/integrated_io/color/display_pin_type() - return IC_FORMAT_COLOR + return VAR_FORMAT_COLOR /datum/integrated_io/color/display_data(var/input) if(!isnull(data)) diff --git a/code/modules/integrated_electronics/core/special_pins/dir_pin.dm b/mods/content/integrated_electronics/pins/dir_pin.dm similarity index 97% rename from code/modules/integrated_electronics/core/special_pins/dir_pin.dm rename to mods/content/integrated_electronics/pins/dir_pin.dm index 552479163590..d850514d2e74 100644 --- a/code/modules/integrated_electronics/core/special_pins/dir_pin.dm +++ b/mods/content/integrated_electronics/pins/dir_pin.dm @@ -23,7 +23,7 @@ holder.on_data_written() /datum/integrated_io/dir/display_pin_type() - return IC_FORMAT_DIR + return VAR_FORMAT_DIR /datum/integrated_io/dir/display_data(var/input) if(!isnull(data)) diff --git a/code/modules/integrated_electronics/core/special_pins/index_pin.dm b/mods/content/integrated_electronics/pins/index_pin.dm similarity index 88% rename from code/modules/integrated_electronics/core/special_pins/index_pin.dm rename to mods/content/integrated_electronics/pins/index_pin.dm index cd45e5d9bbfb..e0820c1888b3 100644 --- a/code/modules/integrated_electronics/core/special_pins/index_pin.dm +++ b/mods/content/integrated_electronics/pins/index_pin.dm @@ -14,8 +14,8 @@ new_data = 0 if(isnum(new_data)) - data = Clamp(round(new_data), 0, IC_MAX_LIST_LENGTH) + data = clamp(round(new_data), 0, IC_MAX_LIST_LENGTH) holder.on_data_written() /datum/integrated_io/index/display_pin_type() - return IC_FORMAT_INDEX + return VAR_FORMAT_INDEX diff --git a/code/modules/integrated_electronics/core/special_pins/list_pin.dm b/mods/content/integrated_electronics/pins/list_pin.dm similarity index 88% rename from code/modules/integrated_electronics/core/special_pins/list_pin.dm rename to mods/content/integrated_electronics/pins/list_pin.dm index 23999d250be8..3c032fde965c 100644 --- a/code/modules/integrated_electronics/core/special_pins/list_pin.dm +++ b/mods/content/integrated_electronics/pins/list_pin.dm @@ -10,19 +10,19 @@ var/list/my_list = data var/t = "

    [src]


    " t += "List length: [my_list.len]
    " - t += "\[Refresh\] | " - t += "\[Add\] | " - t += "\[Remove\] | " - t += "\[Edit\] | " - t += "\[Swap\] | " - t += "\[Clear\]
    " + t += "\[Refresh\] | " + t += "\[Add\] | " + t += "\[Remove\] | " + t += "\[Edit\] | " + t += "\[Swap\] | " + t += "\[Clear\]
    " t += "
    " var/i = 0 for(var/line in my_list) i++ t += "#[i] | [display_data(line)] | " - t += "\[Edit\] | " - t += "\[Remove\]
    " + t += "\[Edit\] | " + t += "\[Remove\]
    " show_browser(user, t, "window=list_pin_\ref[src];size=500x400") /datum/integrated_io/lists/proc/add_to_list(mob/user, var/new_entry) @@ -120,7 +120,7 @@ holder.on_data_written() /datum/integrated_io/lists/display_pin_type() - return IC_FORMAT_LIST + return VAR_FORMAT_LIST /datum/integrated_io/lists/Topic(href, href_list) if(!holder.check_interactivity(usr)) diff --git a/code/modules/integrated_electronics/core/special_pins/number_pin.dm b/mods/content/integrated_electronics/pins/number_pin.dm similarity index 96% rename from code/modules/integrated_electronics/core/special_pins/number_pin.dm rename to mods/content/integrated_electronics/pins/number_pin.dm index e37eea3d9342..827cb1bec5f6 100644 --- a/code/modules/integrated_electronics/core/special_pins/number_pin.dm +++ b/mods/content/integrated_electronics/pins/number_pin.dm @@ -14,4 +14,4 @@ holder.on_data_written() /datum/integrated_io/number/display_pin_type() - return IC_FORMAT_NUMBER \ No newline at end of file + return VAR_FORMAT_NUMBER \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/special_pins/ref_pin.dm b/mods/content/integrated_electronics/pins/ref_pin.dm similarity index 94% rename from code/modules/integrated_electronics/core/special_pins/ref_pin.dm rename to mods/content/integrated_electronics/pins/ref_pin.dm index 461965f254bc..b3f73205a715 100644 --- a/code/modules/integrated_electronics/core/special_pins/ref_pin.dm +++ b/mods/content/integrated_electronics/pins/ref_pin.dm @@ -11,4 +11,4 @@ holder.on_data_written() /datum/integrated_io/ref/display_pin_type() - return IC_FORMAT_REF \ No newline at end of file + return VAR_FORMAT_REF \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/special_pins/string_pin.dm b/mods/content/integrated_electronics/pins/string_pin.dm similarity index 97% rename from code/modules/integrated_electronics/core/special_pins/string_pin.dm rename to mods/content/integrated_electronics/pins/string_pin.dm index 30403c4bccc5..7b44e6951a5c 100644 --- a/code/modules/integrated_electronics/core/special_pins/string_pin.dm +++ b/mods/content/integrated_electronics/pins/string_pin.dm @@ -25,4 +25,4 @@ push_data() /datum/integrated_io/string/display_pin_type() - return IC_FORMAT_STRING + return VAR_FORMAT_STRING diff --git a/code/modules/integrated_electronics/core/prefab/prefab.dm b/mods/content/integrated_electronics/prefab/prefab.dm similarity index 80% rename from code/modules/integrated_electronics/core/prefab/prefab.dm rename to mods/content/integrated_electronics/prefab/prefab.dm index f1f75e49ec37..689fbbd687b4 100644 --- a/code/modules/integrated_electronics/core/prefab/prefab.dm +++ b/mods/content/integrated_electronics/prefab/prefab.dm @@ -5,7 +5,6 @@ return TRUE /decl/prefab/ic_assembly - var/assembly_name var/data var/power_cell_type @@ -25,15 +24,17 @@ return assembly return null -/obj/prefab +/obj/abstract/prefab name = "prefab spawn" icon = 'icons/misc/mark.dmi' icon_state = "X" color = COLOR_PURPLE + abstract_type = /obj/abstract/prefab var/prefab_type -/obj/prefab/Initialize() +/obj/abstract/prefab/Initialize() ..() - var/decl/prefab/prefab = decls_repository.get_decl(prefab_type) - prefab.create(loc) - return INITIALIZE_HINT_QDEL \ No newline at end of file + if(loc) + var/decl/prefab/prefab = GET_DECL(prefab_type) + prefab?.create(loc) + return INITIALIZE_HINT_QDEL diff --git a/mods/content/integrated_electronics/prefab/prefabs.dm b/mods/content/integrated_electronics/prefab/prefabs.dm new file mode 100644 index 000000000000..a17305b58f9a --- /dev/null +++ b/mods/content/integrated_electronics/prefab/prefabs.dm @@ -0,0 +1,9 @@ +/decl/prefab/ic_assembly/hand_teleporter + data = @'{"assembly":{"type":"type-a electronic mechanism","name":"hand teleporter", "detail_color":"#5d99be"},"components":[{"type":"teleporter locator"},{"type":"wormhole generator"},{"type":"button","name":"Open Wormhole"}],"wires":[[[1,"O",1],[2,"I",1]],[[2,"A",1],[3,"A",1]]]}' + power_cell_type = /obj/item/cell/hyper + +/obj/abstract/prefab/hand_teleporter + name = "hand teleporter" + prefab_type = /decl/prefab/ic_assembly/hand_teleporter + +OPTIONAL_SPAWNER(hand_tele, /obj/abstract/prefab/hand_teleporter) \ No newline at end of file diff --git a/mods/content/integrated_electronics/prefab/test/testprefabs.dm b/mods/content/integrated_electronics/prefab/test/testprefabs.dm new file mode 100644 index 000000000000..96972a8bdbb8 --- /dev/null +++ b/mods/content/integrated_electronics/prefab/test/testprefabs.dm @@ -0,0 +1,7 @@ +/decl/prefab/ic_assembly/test_heatercooler + data = @'{"assembly":{"type":"type-c electronic machine", "name":"heating-cooling test"},"components":[{"type":"starter"},{"type":"reagent funnel"},{"type":"big reagent storage"},{"type":"reagent pump","name":"Hot Pump","inputs":[[3,0,5]]},{"type":"reagent pump","name":"Cool Pump","inputs":[[3,0,5]]},{"type":"reagent heater","name":"Heater","inputs":[[1,0,80]]},{"type":"reagent cooler","name":"Cooler","inputs":[[1,0,-50]]},{"type":"button","name":"Heat And Cool"},{"type":"and gate","name":"Heater Active Check","inputs":[[1,0,0],[2,0,1]]},{"type":"and gate","name":"Cooler Active Check","inputs":[[1,0,0],[2,0,1]]},{"type":"custom delay circuit","name":"Heater Delay","inputs":[[1,0,100]]},{"type":"custom delay circuit","name":"Cooler Delay","inputs":[[1,0,100]]}],"wires":[[[1,"A",1],[3,"A",1]],[[1,"A",1],[6,"A",3]],[[1,"A",1],[7,"A",3]],[[2,"I",1],[3,"O",2]],[[3,"O",2],[4,"I",1]],[[3,"O",2],[5,"I",1]],[[4,"I",2],[6,"O",4]],[[4,"A",1],[8,"A",1]],[[4,"A",2],[6,"A",1]],[[5,"I",2],[7,"O",4]],[[5,"A",1],[8,"A",1]],[[5,"A",2],[7,"A",1]],[[6,"O",3],[9,"I",1]],[[6,"A",1],[11,"A",2]],[[6,"A",2],[9,"A",1]],[[7,"O",3],[10,"I",1]],[[7,"A",1],[12,"A",2]],[[7,"A",2],[10,"A",1]],[[9,"A",2],[11,"A",1]],[[10,"A",2],[12,"A",1]]]}' + power_cell_type = /obj/item/cell/hyper + +/obj/abstract/prefab/test_heatcool + name = "heating-cooling test" + prefab_type = /decl/prefab/ic_assembly/test_heatercooler diff --git a/mods/content/integrated_electronics/random.dm b/mods/content/integrated_electronics/random.dm new file mode 100644 index 000000000000..34f557071fb4 --- /dev/null +++ b/mods/content/integrated_electronics/random.dm @@ -0,0 +1,4 @@ +/obj/random_multi/single_item/hand_tele + name = "Multi Point - Hand Teleporter" + id = "Hand teleporter" + item_path = /obj/abstract/prefab/hand_teleporter \ No newline at end of file diff --git a/mods/content/integrated_electronics/subsystems/circuit.dm b/mods/content/integrated_electronics/subsystems/circuit.dm new file mode 100644 index 000000000000..ccc6d5356e99 --- /dev/null +++ b/mods/content/integrated_electronics/subsystems/circuit.dm @@ -0,0 +1,60 @@ +//Additional helper procs found in /code/modules/integrated_electgronics/core/saved_circuits.dm + +PROCESSING_SUBSYSTEM_DEF(circuit) + name = "Circuit" + priority = SS_PRIORITY_CIRCUIT + init_order = SS_INIT_CIRCUIT + flags = SS_BACKGROUND + + var/cipherkey + + var/list/all_components = list() // Associative list of [component_name]:[component_path] pairs + var/list/cached_components = list() // Associative list of [component_path]:[component] pairs + var/list/all_assemblies = list() // Associative list of [assembly_name]:[assembly_path] pairs + var/list/cached_assemblies = list() // Associative list of [assembly_path]:[assembly] pairs + var/list/circuit_fabricator_recipe_list = list() // Associative list of [category_name]:[list_of_circuit_paths] pairs + var/cost_multiplier = SHEET_MATERIAL_AMOUNT / 10 // Each circuit cost unit is 200cm3 + +/datum/controller/subsystem/processing/circuit/Initialize() + SScircuit.cipherkey = generateRandomString(2000+rand(0,10)) + circuits_init() + . = ..() + +/datum/controller/subsystem/processing/circuit/proc/circuits_init() + //Cached lists for free performance + var/atom/def = /obj/item/integrated_circuit + var/default_name = initial(def.name) + for(var/path in typesof(/obj/item/integrated_circuit)) + var/obj/item/integrated_circuit/IC = path + var/name = initial(IC.name) + if(name == default_name) + continue + all_components[name] = path // Populating the component lists + cached_components[IC] = new path + + if(!(initial(IC.spawn_flags) & (IC_SPAWN_DEFAULT | IC_SPAWN_RESEARCH))) + continue + + var/category = initial(IC.category_text) + if(!circuit_fabricator_recipe_list[category]) + circuit_fabricator_recipe_list[category] = list() + var/list/category_list = circuit_fabricator_recipe_list[category] + category_list += IC // Populating the fabricator categories + + for(var/path in typesof(/obj/item/electronic_assembly)) + var/obj/item/electronic_assembly/A = path + var/name = initial(A.name) + all_assemblies[name] = path + cached_assemblies[A] = new path + + circuit_fabricator_recipe_list["Assemblies"] = subtypesof(/obj/item/electronic_assembly) - list(/obj/item/electronic_assembly/medium, /obj/item/electronic_assembly/large, /obj/item/electronic_assembly/drone, /obj/item/electronic_assembly/wallmount) + + circuit_fabricator_recipe_list["Tools"] = list( + /obj/item/wirer, + /obj/item/debugger, + /obj/item/analyzer, + /obj/item/detailer, + /obj/item/card/data, + /obj/item/card/data/full_color, + /obj/item/card/data/disk + ) diff --git a/code/controllers/subsystems/circuit_component.dm b/mods/content/integrated_electronics/subsystems/circuit_component.dm similarity index 100% rename from code/controllers/subsystems/circuit_component.dm rename to mods/content/integrated_electronics/subsystems/circuit_component.dm diff --git a/code/modules/admin/secrets/admin_secrets/toggle_circuits.dm b/mods/content/integrated_electronics/toggle_circuits_secret.dm similarity index 100% rename from code/modules/admin/secrets/admin_secrets/toggle_circuits.dm rename to mods/content/integrated_electronics/toggle_circuits_secret.dm diff --git a/mods/content/integrated_electronics/tools/analyzer.dm b/mods/content/integrated_electronics/tools/analyzer.dm new file mode 100644 index 000000000000..6be5bec11856 --- /dev/null +++ b/mods/content/integrated_electronics/tools/analyzer.dm @@ -0,0 +1,23 @@ +/obj/item/analyzer + name = "circuit analyzer" + desc = "This tool can scan an assembly and generate code necessary to recreate it in a circuit printer." + icon = 'icons/obj/assemblies/circuit_analyzer.dmi' + icon_state = ICON_STATE_WORLD + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE + ) + +/obj/item/analyzer/afterattack(var/atom/A, var/mob/living/user) + . = ..() + if(istype(A, /obj/item/electronic_assembly)) + var/saved = "[A.name] analyzed! On circuit printers with cloning enabled, you may use the code below to clone the circuit:

    [SScircuit.save_electronic_assembly(A)]" + if(saved) + to_chat(user, "You scan [A].") + show_browser(user, saved, "window=circuit_scan;size=500x600;border=1;can_resize=1;can_close=1;can_minimize=1") + else + to_chat(user, "[A] is not complete enough to be encoded!") diff --git a/mods/content/integrated_electronics/tools/debugger.dm b/mods/content/integrated_electronics/tools/debugger.dm new file mode 100644 index 000000000000..32e88b5cfa28 --- /dev/null +++ b/mods/content/integrated_electronics/tools/debugger.dm @@ -0,0 +1,70 @@ +/obj/item/debugger + name = "circuit debugger" + desc = "This small tool allows one working with custom machinery to directly set data to a specific pin, useful for writing \ + settings to specific circuits, or for debugging purposes. It can also pulse activation pins." + icon = 'icons/obj/assemblies/electronic_tools.dmi' + icon_state = "debugger" + item_flags = ITEM_FLAG_NO_BLUDGEON + var/data_to_write = null + var/accepting_refs = FALSE + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE + ) + +/obj/item/debugger/attack_self(mob/user) + var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null") + + var/new_data = null + switch(type_to_use) + if("string") + accepting_refs = FALSE + new_data = user.get_input("Now type in a string", "[src] string writing", null, MOB_INPUT_TEXT, src) + new_data = sanitize(new_data,trim = 0) + if(istext(new_data) && user.check_dexterity(DEXTERITY_KEYBOARDS)) + data_to_write = new_data + to_chat(user, "You set \the [src]'s memory to \"[new_data]\".") + if("number") + accepting_refs = FALSE + new_data = user.get_input("Now type in a number", "[src] number writing", null, MOB_INPUT_NUM, src) + if(isnum(new_data) && user.check_dexterity(DEXTERITY_KEYBOARDS)) + data_to_write = new_data + to_chat(user, "You set \the [src]'s memory to [new_data].") + if("ref") + accepting_refs = TRUE + to_chat(user, "You turn \the [src]'s ref scanner on. Slide it across \ + an object for a ref of that object to save it in memory.") + if("null") + data_to_write = null + to_chat(user, "You set \the [src]'s memory to absolutely nothing.") + +/obj/item/debugger/afterattack(atom/target, mob/living/user, proximity) + . = ..() + if(accepting_refs && proximity) + data_to_write = weakref(target) + visible_message("[user] slides \a [src]'s over \the [target].") + to_chat(user, "You set \the [src]'s memory to a reference to [target.name] \[Ref\]. The ref scanner is \ + now off.") + accepting_refs = FALSE + +/obj/item/debugger/proc/write_data(var/datum/integrated_io/io, mob/user) + if(io.io_type == DATA_CHANNEL) + io.write_data_to_pin(data_to_write) + var/data_to_show = data_to_write + if(isweakref(data_to_write)) + var/weakref/w = data_to_write + var/atom/A = w.resolve() + if(!A) + to_chat(user, "\The [src]'s reference is stale and won't transfer to \the [io.holder]'s pin.") + return + data_to_show = A.name + to_chat(user, "You write '[data_to_write ? data_to_show : "NULL"]' to the '[io]' pin of \the [io.holder].") + else if(io.io_type == PULSE_CHANNEL) + io.holder.check_then_do_work(io.ord,ignore_power = TRUE) + to_chat(user, "You pulse \the [io.holder]'s [io].") + + io.holder.interact(user) // This is to update the UI. diff --git a/mods/content/integrated_electronics/tools/detailer.dm b/mods/content/integrated_electronics/tools/detailer.dm new file mode 100644 index 000000000000..fe71e09208d4 --- /dev/null +++ b/mods/content/integrated_electronics/tools/detailer.dm @@ -0,0 +1,74 @@ +#define SCAN_COLOR "SCAN" + +/obj/item/detailer + name = "assembly detailer" + desc = "A combination autopainter and flash anodizer designed to give electronic assemblies a colorful, wear-resistant finish." + icon = 'icons/obj/assemblies/electronic_tools.dmi' + icon_state = "detailer" + item_flags = ITEM_FLAG_NO_BLUDGEON + obj_flags = OBJ_FLAG_CONDUCTIBLE + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE + ) + var/scanning_color = FALSE + var/detail_color = COLOR_ASSEMBLY_WHITE + var/list/color_list = list( + "black" = COLOR_ASSEMBLY_BLACK, + "gray" = COLOR_GRAY40, + "machine gray" = COLOR_ASSEMBLY_BGRAY, + "white" = COLOR_ASSEMBLY_WHITE, + "red" = COLOR_ASSEMBLY_RED, + "orange" = COLOR_ASSEMBLY_ORANGE, + "beige" = COLOR_ASSEMBLY_BEIGE, + "brown" = COLOR_ASSEMBLY_BROWN, + "gold" = COLOR_ASSEMBLY_GOLD, + "yellow" = COLOR_ASSEMBLY_YELLOW, + "gurkha" = COLOR_ASSEMBLY_GURKHA, + "light green" = COLOR_ASSEMBLY_LGREEN, + "green" = COLOR_ASSEMBLY_GREEN, + "light blue" = COLOR_ASSEMBLY_LBLUE, + "blue" = COLOR_ASSEMBLY_BLUE, + "purple" = COLOR_ASSEMBLY_PURPLE, + "\[SCAN FROM ASSEMBLY\]" = SCAN_COLOR + ) + +/obj/item/detailer/Initialize() + .=..() + update_icon() + +/obj/item/detailer/on_update_icon() + . = ..() + add_overlay(overlay_image('icons/obj/assemblies/electronic_tools.dmi', "detailer-color", detail_color)) + +/obj/item/detailer/attack_self(mob/user) + var/color_choice = input(user, "Select color.", "Assembly Detailer") as null|anything in color_list + if(!color_list[color_choice]) + return + if(!in_range(src, user)) + return + if(color_choice == SCAN_COLOR) + scanning_color = TRUE + detail_color = initial(detail_color) + return + scanning_color = FALSE + detail_color = color_list[color_choice] + update_icon() + +/obj/item/detailer/afterattack(atom/target, mob/living/user, proximity) + . = ..() + if(!scanning_color || !proximity) + return . + visible_message("[user] slides \a [src]'s over \the [target].") + to_chat(user, "You set \the [src]'s detailing color to match [target.name] \[Ref\]. The color matcher is \ + now off.") + scanning_color = FALSE + if(isitem(target)) + var/obj/item/I = target + detail_color = I.get_assembly_detail_color() + +/obj/item/detailer/get_assembly_detail_color() + return detail_color diff --git a/mods/content/integrated_electronics/tools/printer.dm b/mods/content/integrated_electronics/tools/printer.dm new file mode 100644 index 000000000000..43077bfe89e8 --- /dev/null +++ b/mods/content/integrated_electronics/tools/printer.dm @@ -0,0 +1,349 @@ +#define MAX_CIRCUIT_CLONE_TIME 3 MINUTES //circuit slow-clones can only take up this amount of time to complete + +/obj/item/integrated_circuit_printer + name = "integrated circuit printer" + desc = "A portable(ish) machine made to print tiny modular circuitry out of metal." + icon = 'icons/obj/assemblies/electronic_tools.dmi' + icon_state = "circuit_printer" + w_class = ITEM_SIZE_LARGE + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + + var/upgraded = FALSE // When hit with an upgrade disk, will turn true, allowing it to print the higher tier circuits. + var/can_clone = TRUE // Allows the printer to clone circuits, either instantly or over time depending on upgrade. Set to FALSE to disable entirely. + var/fast_clone = FALSE // If this is false, then cloning will take an amount of deciseconds equal to the metal cost divided by 100. + var/debug = FALSE // If it's upgraded and can clone, even without config settings. + var/current_category = null + var/cloning = FALSE // If the printer is currently creating a circuit + var/recycling = FALSE // If an assembly is being emptied into this printer + var/list/program // Currently loaded save, in form of list + var/materials = list(/decl/material/solid/metal/steel = 0) + var/metal_max = 25 * SHEET_MATERIAL_AMOUNT + +/obj/item/integrated_circuit_printer/proc/check_interactivity(mob/user) + return CanUseTopic(user) + +/obj/item/integrated_circuit_printer/upgraded + upgraded = TRUE + can_clone = TRUE + fast_clone = TRUE + +/obj/item/integrated_circuit_printer/debug //translation: "integrated_circuit_printer/local_server" + name = "debug circuit printer" + debug = TRUE + upgraded = TRUE + can_clone = TRUE + fast_clone = TRUE + w_class = ITEM_SIZE_TINY + +/obj/item/integrated_circuit_printer/proc/print_program(mob/user) + if(!cloning) + return + + visible_message("[src] has finished printing its assembly!") + playsound(src, 'sound/items/poster_being_created.ogg', 50, TRUE) + var/obj/item/electronic_assembly/assembly = SScircuit.load_electronic_assembly(get_turf(src), program) + assembly.creator = key_name(user) + cloning = FALSE + +/obj/item/integrated_circuit_printer/proc/recycle(obj/item/used_item, mob/user, obj/item/electronic_assembly/assembly) + if(!used_item.canremove) //in case we have an augment circuit + return + for(var/mat in used_item.matter) + if(materials[mat] + used_item.matter[mat] > metal_max) + var/decl/material/recycle_material = GET_DECL(mat) + if(recycle_material) + to_chat(user, "[src] can't hold any more [recycle_material.name]!") + return + for(var/mat in used_item.matter) + materials[mat] += used_item.matter[mat] + if(assembly) + assembly.remove_component(used_item) + if(user) + to_chat(user, "You recycle [used_item]!") + qdel(used_item) + return TRUE + +/obj/item/integrated_circuit_printer/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/stack/material)) + var/obj/item/stack/material/stack = used_item + var/amt = stack.amount + if(amt * SHEET_MATERIAL_AMOUNT + materials[stack.material.type] > metal_max) + amt = ceil((metal_max - materials[stack.material.type]) / SHEET_MATERIAL_AMOUNT) + if(!stack.use(amt)) + return FALSE + materials[stack.material.type] = min(metal_max, materials[stack.material.type] + amt * SHEET_MATERIAL_AMOUNT) + to_chat(user, "You insert [stack.material.solid_name] into \the [src].") + if(user) + attack_self(user) // We're really bad at refreshing the UI, so this is the best we've got. + return TRUE + if(istype(used_item, /obj/item/disk/integrated_circuit/upgrade/advanced)) + if(upgraded) + to_chat(user, "[src] already has this upgrade. ") + return TRUE + to_chat(user, "You install [used_item] into [src]. ") + upgraded = TRUE + if(user) + attack_self(user) + return TRUE + + if(istype(used_item, /obj/item/disk/integrated_circuit/upgrade/clone)) + if(fast_clone) + to_chat(user, "[src] already has this upgrade. ") + return TRUE + to_chat(user, "You install [used_item] into [src]. Circuit cloning will now be instant. ") + fast_clone = TRUE + if(user) + attack_self(user) + return TRUE + + if(istype(used_item, /obj/item/electronic_assembly)) + var/obj/item/electronic_assembly/EA = used_item //microtransactions not included + if(EA.battery) + to_chat(user, "Remove [EA]'s power cell first!") + return TRUE + if(EA.assembly_components.len) + if(recycling) + return TRUE + if(!EA.opened) + to_chat(user, "You can't reach [EA]'s components to remove them!") + return TRUE + for(var/V in EA.assembly_components) + var/obj/item/integrated_circuit/IC = V + if(!IC.removable) + to_chat(user, "[EA] has irremovable components in the casing, preventing you from emptying it.") + return TRUE + to_chat(user, "You begin recycling [EA]'s components...") + playsound(src, 'sound/items/electronic_assembly_emptying.ogg', 50, TRUE) + if(!do_after(user, 30, target = src) || recycling) //short channel so you don't accidentally start emptying out a complex assembly + return TRUE + recycling = TRUE + for(var/V in EA.assembly_components) + recycle(V, null, EA) + to_chat(user, "You recycle all the components[EA.assembly_components.len ? " you could " : " "]from [EA]!") + playsound(src, 'sound/items/electronic_assembly_empty.ogg', 50, TRUE) + recycling = FALSE + return TRUE + else + return recycle(EA, user) + + if(istype(used_item, /obj/item/integrated_circuit)) + return recycle(used_item, user) + + return ..() + +/obj/item/integrated_circuit_printer/attack_self(mob/user) + interact(user) + +/obj/item/integrated_circuit_printer/interact(mob/user) + if(!(in_range(src, user) || issilicon(user))) + return + + if(isnull(current_category)) + current_category = SScircuit.circuit_fabricator_recipe_list[1] + + //Preparing the browser + var/datum/browser/written_digital/popup = new(user, "printernew", "Integrated Circuit Printer", 800, 630) // Set up the popup browser window + + var/list/HTML = list() + HTML += "

    Integrated Circuit Printer


    " + if(debug) + HTML += "

    DEBUG PRINTER -- Infinite materials. Cloning available.

    " + else + HTML += "Materials: " + var/list/dat = list() + for(var/mat in materials) + var/decl/material/print_material = GET_DECL(mat) + dat += "[materials[mat]]/[metal_max] [print_material.name]" + HTML += jointext(dat, "; ") + HTML += ".

    " + + if(get_config_value(/decl/config/toggle/on/allow_ic_printing) || debug) + HTML += "Assembly cloning: [can_clone ? (fast_clone ? "Instant" : "Available") : "Unavailable"].
    " + + HTML += "Circuits available: [upgraded || debug ? "Advanced":"Regular"]." + if(!upgraded) + HTML += "
    Crossed out circuits mean that the printer is not sufficiently upgraded to create that circuit." + + HTML += "
    " + if((can_clone && get_config_value(/decl/config/toggle/on/allow_ic_printing)) || debug) + HTML += "Here you can load script for your assembly.
    " + if(!cloning) + HTML += " {Load Program} " + else + HTML += " {Load Program}" + if(!program) + HTML += " {[fast_clone ? "Print" : "Begin Printing"] Assembly}" + else if(cloning) + HTML += " {Cancel Print}" + else + HTML += " {[fast_clone ? "Print" : "Begin Printing"] Assembly}" + + HTML += "

    " + HTML += "Categories:" + for(var/category in SScircuit.circuit_fabricator_recipe_list) + if(category != current_category) + HTML += " \[[category]\] " + else // Bold the button if it's already selected. + HTML += " \[[category]\] " + HTML += "
    " + HTML += "

    [current_category]

    " + + var/list/current_list = SScircuit.circuit_fabricator_recipe_list[current_category] + for(var/path in current_list) + var/obj/building = path + var/can_build = TRUE + if(ispath(path, /obj/item/integrated_circuit)) + var/obj/item/integrated_circuit/IC = path + if((initial(IC.spawn_flags) & IC_SPAWN_RESEARCH) && (!(initial(IC.spawn_flags) & IC_SPAWN_DEFAULT)) && !upgraded) + can_build = FALSE + if(can_build) + HTML += "\[[initial(building.name)]\]: [initial(building.desc)]
    " + else + HTML += "\[[initial(building.name)]\]: [initial(building.desc)]
    " + + popup.set_content(JOINTEXT(HTML)) + popup.open() + +/obj/item/integrated_circuit_printer/Topic(href, href_list) + if(!check_interactivity(usr)) + return + if(..()) + return TRUE + add_fingerprint(usr) + + if(href_list["category"]) + current_category = href_list["category"] + + if(href_list["build"]) + var/build_type = locate(href_list["build"]) + if(!build_type || !ispath(build_type)) + return TRUE + + var/list/cost = atom_info_repository.get_matter_for(build_type) + if(!ispath(build_type, /obj/item/electronic_assembly) && !ispath(build_type, /obj/item/integrated_circuit) && !(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"])) + return + + if(!debug && !subtract_material_costs(cost, usr)) + return + + var/obj/item/built = new build_type(get_turf(src)) + usr.put_in_hands(built) + + if(istype(built, /obj/item/electronic_assembly)) + var/obj/item/electronic_assembly/E = built + E.creator = key_name(usr) + E.opened = TRUE + E.update_icon() + to_chat(usr, "[capitalize(built.name)] printed.") + playsound(src, 'sound/items/jaws_pry.ogg', 50, TRUE) + + if(href_list["print"]) + if(!get_config_value(/decl/config/toggle/on/allow_ic_printing) && !debug) + to_chat(usr, "Your facility has disabled printing of custom circuitry due to recent allegations of copyright infringement.") + return + if(!can_clone) // Copying and printing ICs is cloning + to_chat(usr, "This printer does not have the cloning upgrade.") + return + switch(href_list["print"]) + if("load") + if(cloning) + return + var/input = usr.get_input("Put your code there:", "loading", null, MOB_INPUT_MESSAGE, src) + if(cloning) + return + if(!input) + program = null + return + + var/validation = SScircuit.validate_electronic_assembly(input) + + // Validation error codes are returned as text. + if(istext(validation)) + to_chat(usr, "Error: [validation]") + return + else if(islist(validation)) + program = validation + to_chat(usr, "This is a valid program for [program["assembly"]["type"]].") + if(program["requires_upgrades"]) + if(upgraded) + to_chat(usr, "It uses advanced component designs.") + else + to_chat(usr, "It uses unknown component designs. Printer upgrade is required to proceed.") + if(program["unsupported_circuit"]) + to_chat(usr, "This program uses components not supported by the specified assembly. Please change the assembly type in the save file to a supported one.") + to_chat(usr, "Used space: [program["used_space"]]/[program["max_space"]].") + to_chat(usr, "Complexity: [program["complexity"]]/[program["max_complexity"]].") + to_chat(usr, "Cost: [json_encode(program["cost"])].") + + if("print") + if(!program || cloning) + return + + if(program["requires_upgrades"] && !upgraded && !debug) + to_chat(usr, "This program uses unknown component designs. Printer upgrade is required to proceed.") + return + if(program["unsupported_circuit"] && !debug) + to_chat(usr, "This program uses components not supported by the specified assembly. Please change the assembly type in the save file to a supported one.") + return + else if(fast_clone) + var/list/cost = program["cost"] + if(debug || subtract_material_costs(cost, usr)) + cloning = TRUE + print_program(usr) + else + var/list/cost = program["cost"] + if(!subtract_material_costs(cost, usr)) + return + var/cloning_time = 0 + for(var/mat in cost) + cloning_time += cost[mat] + cloning_time = round(cloning_time/15) + cloning_time = min(cloning_time, MAX_CIRCUIT_CLONE_TIME) + cloning = TRUE + to_chat(usr, "You begin printing a custom assembly. This will take approximately [round(cloning_time/10)] seconds. You can still print \ + off normal parts during this time.") + playsound(src, 'sound/items/poster_being_created.ogg', 50, TRUE) + addtimer(CALLBACK(src, PROC_REF(print_program), usr), cloning_time) + + if("cancel") + if(!cloning || !program) + return + + to_chat(usr, "Cloning has been canceled. Cost has been refunded.") + cloning = FALSE + var/cost = program["cost"] + for(var/mat in cost) + materials[mat] = min(metal_max, materials[mat] + cost[mat]) + + interact(usr) + +/obj/item/integrated_circuit_printer/proc/subtract_material_costs(var/list/cost, var/mob/user) + for(var/mat in cost) + if(materials[mat] < cost[mat]) + var/decl/material/print_material = GET_DECL(mat) + to_chat(user, "You need [cost[mat]] [print_material.name] to build that!") + return FALSE + for(var/mat in cost) //Iterate twice to make sure it's going to work before deducting + materials[mat] -= cost[mat] + return TRUE + +// FUKKEN UPGRADE DISKS +/obj/item/disk/integrated_circuit/upgrade + name = "integrated circuit printer upgrade disk" + desc = "Install this into your integrated circuit printer to enhance it." + color = COLOR_GRAY20 + label = "label_up" + origin_tech = @'{"materials":2,"engineering":2}' + +/obj/item/disk/integrated_circuit/upgrade/advanced + name = "integrated circuit printer upgrade disk - advanced designs" + desc = "Install this into your integrated circuit printer to enhance it. This one adds new, advanced designs to the printer." + material = /decl/material/solid/metal/steel + matter = list(/decl/material/solid/fiberglass = MATTER_AMOUNT_REINFORCEMENT) + origin_tech = @'{"materials":3,"engineering":3}' + +/obj/item/disk/integrated_circuit/upgrade/clone + name = "integrated circuit printer upgrade disk - instant cloner" + desc = "Install this into your integrated circuit printer to enhance it. This one allows the printer to duplicate assemblies instantaneously." + origin_tech = @'{"materials":3,"programming":5}' diff --git a/code/modules/integrated_electronics/core/wirer.dm b/mods/content/integrated_electronics/tools/wirer.dm similarity index 86% rename from code/modules/integrated_electronics/core/wirer.dm rename to mods/content/integrated_electronics/tools/wirer.dm index 5d93817e8896..365660a1ac58 100644 --- a/code/modules/integrated_electronics/core/wirer.dm +++ b/mods/content/integrated_electronics/tools/wirer.dm @@ -3,7 +3,7 @@ #define UNWIRE "unwire" #define UNWIRING "unwiring" -/obj/item/integrated_electronics/wirer +/obj/item/wirer name = "circuit wirer" desc = "It's a small wiring tool, with a wire roll, electric soldering iron, wire cutter, and more in one package. \ The wires used are generally useful for small electronics, such as circuitboards and breadboards, as opposed to larger wires \ @@ -12,19 +12,20 @@ icon_state = "wirer-wire" obj_flags = OBJ_FLAG_CONDUCTIBLE w_class = ITEM_SIZE_SMALL - var/datum/integrated_io/selected_io = null - var/mode = WIRE material = /decl/material/solid/metal/aluminium matter = list( /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT, - /decl/material/solid/glass = MATTER_AMOUNT_TRACE, - /decl/material/solid/plastic = MATTER_AMOUNT_TRACE + /decl/material/solid/fiberglass = MATTER_AMOUNT_TRACE, + /decl/material/solid/organic/plastic = MATTER_AMOUNT_TRACE ) + var/datum/integrated_io/selected_io = null + var/mode = WIRE -/obj/item/integrated_electronics/wirer/on_update_icon() +/obj/item/wirer/on_update_icon() + . = ..() icon_state = "wirer-[mode]" -/obj/item/integrated_electronics/wirer/proc/wire(var/datum/integrated_io/io, mob/user) +/obj/item/wirer/proc/wire(var/datum/integrated_io/io, mob/user) if(!io.holder.assembly) to_chat(user, "\The [io.holder] needs to be secured inside an assembly first.") return @@ -82,21 +83,21 @@ to_chat(user, "\The [selected_io.holder]'s [selected_io.name] and \the [io.holder]'s \ [io.name] are not connected.") -/obj/item/integrated_electronics/wirer/proc/select_io(datum/integrated_io/io) +/obj/item/wirer/proc/select_io(datum/integrated_io/io) if(selected_io) unselect_io(selected_io) selected_io = io - GLOB.destroyed_event.register(selected_io, src, .proc/unselect_io) + events_repository.register(/decl/observ/destroyed, selected_io, src, PROC_REF(unselect_io)) switch(mode) if(UNWIRE) mode = UNWIRING if(WIRE) mode = WIRING -/obj/item/integrated_electronics/wirer/proc/unselect_io(datum/integrated_io/io) +/obj/item/wirer/proc/unselect_io(datum/integrated_io/io) if(selected_io != io) return - GLOB.destroyed_event.unregister(selected_io, src) + events_repository.unregister(/decl/observ/destroyed, selected_io, src) selected_io = null switch(mode) if(UNWIRING) @@ -104,7 +105,7 @@ if(WIRING) mode = WIRE -/obj/item/integrated_electronics/wirer/attack_self(mob/user) +/obj/item/wirer/attack_self(mob/user) switch(mode) if(WIRE) mode = UNWIRE diff --git a/mods/content/item_sharpening/_item_sharpening.dm b/mods/content/item_sharpening/_item_sharpening.dm new file mode 100644 index 000000000000..3807839161bd --- /dev/null +++ b/mods/content/item_sharpening/_item_sharpening.dm @@ -0,0 +1,8 @@ +#define IE_PAR_SHARP_DAM_MULT "sharp_dam_mult" + +/decl/modpack/item_sharpening + name = "Item Sharpening" + +/obj/proc/get_sharpening_material() + RETURN_TYPE(/decl/material) + return get_material() diff --git a/mods/content/item_sharpening/_item_sharpening.dme b/mods/content/item_sharpening/_item_sharpening.dme new file mode 100644 index 000000000000..c9af243f5e94 --- /dev/null +++ b/mods/content/item_sharpening/_item_sharpening.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_ITEM_SHARPENING +#define MODPACK_ITEM_SHARPENING +// BEGIN_INCLUDE +#include "_item_sharpening.dm" +#include "blade_sharpen.dm" +#include "effect_sharpen.dm" +#include "grindstone.dm" +#include "item_sharpen.dm" +#include "whetstone.dm" +//END_INCLUDE +#endif diff --git a/mods/content/item_sharpening/blade_sharpen.dm b/mods/content/item_sharpening/blade_sharpen.dm new file mode 100644 index 000000000000..a46b8d690332 --- /dev/null +++ b/mods/content/item_sharpening/blade_sharpen.dm @@ -0,0 +1,24 @@ +/obj/item/bladed/proc/get_sharpened_effect_params() + return list( + (IE_CAT_DAMAGE) = list( + (IE_PAR_USES) = max(1, max(1, rand(round(10 * 0.3), round(20 * 0.6)))), + (IE_PAR_MAX_USES) = 30, + (IE_PAR_SHARP_DAM_MULT) = 0.25 + ), + (IE_CAT_EXAMINE) + ) + +/obj/item/bladed/Initialize(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) + var/list/sharpened_params = get_sharpened_effect_params() + if(length(sharpened_params)) + add_item_effect(/decl/item_effect/sharpened, sharpened_params) + . = ..() + if(length(sharpened_params)) + update_attack_force() + update_name() + +/obj/item/bladed/folding/try_sharpen_with(mob/user, obj/sharpening_with) + if(!open) + to_chat(user, SPAN_WARNING("You cannot sharpen \the [src] while it's closed!")) + return FALSE + return ..() diff --git a/mods/content/item_sharpening/effect_sharpen.dm b/mods/content/item_sharpening/effect_sharpen.dm new file mode 100644 index 000000000000..511b83c6f349 --- /dev/null +++ b/mods/content/item_sharpening/effect_sharpen.dm @@ -0,0 +1,21 @@ +/decl/item_effect/sharpened/modify_attack_damage(base_damage, obj/item/used_item, mob/user, list/parameters) + var/uses = LAZYACCESS(parameters, IE_PAR_USES) + if(uses <= 0) + return base_damage + . = base_damage * (1 + ((uses / max(1, LAZYACCESS(parameters, IE_PAR_MAX_USES))) * LAZYACCESS(parameters, IE_PAR_SHARP_DAM_MULT))) + +/decl/item_effect/sharpened/expend_attack_use(obj/item/used_item, mob/user, list/parameters) + var/uses = LAZYACCESS(parameters, IE_PAR_USES) + uses = max(0, uses-1) + used_item.set_item_effect_parameter(src, IE_CAT_DAMAGE, IE_PAR_USES, uses) + if(uses == 0) // We've gone dull! + used_item.update_attack_force() + used_item.update_name() + +/decl/item_effect/sharpened/on_examined(obj/item/item, mob/user, distance, list/parameters) + if(distance <= 1) + var/uses = item.get_item_effect_parameter(src, IE_CAT_DAMAGE, IE_PAR_USES) + if(uses > 0) + to_chat(user, SPAN_NOTICE("\The [item] has been honed to a keen edge.")) + else + to_chat(user, SPAN_NOTICE("\The [item] is in need of sharpening.")) diff --git a/mods/content/item_sharpening/grindstone.dm b/mods/content/item_sharpening/grindstone.dm new file mode 100644 index 000000000000..13d8f1260520 --- /dev/null +++ b/mods/content/item_sharpening/grindstone.dm @@ -0,0 +1,46 @@ +// TODO: better sound effects for working. +/obj/structure/working/grindstone + name = "grindstone" + desc = "A rotating section of coarse stone used to polish and sharpen metalwork like blades." + icon = 'mods/content/item_sharpening/icons/grindstone.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR // Name and desc handled manually. + var/decl/material/stone_material = /decl/material/solid/quartz + +/obj/structure/working/grindstone/Initialize() + stone_material = GET_DECL(stone_material) + . = ..() + update_material_name() + update_material_desc() + +/obj/structure/working/grindstone/update_material_name(override_name) + . = ..() + if(stone_material) + SetName("[stone_material.adjective_name] [name]") + +/obj/structure/working/grindstone/update_material_desc(override_desc) + . = ..() + if(stone_material && istype(material)) + desc = "[desc] This one is made from [stone_material.solid_name] with \a [material.adjective_name] frame." + +/obj/structure/working/grindstone/on_update_icon() + . = ..() + underlays = list( + overlay_image(icon, "[icon_state]-grindstone", stone_material.color, RESET_COLOR), + overlay_image(icon, "[initial(icon_state)]-backdrop") + ) + +// Slightly wonky override, but this basically intercepts items being used on the grindstone. +/obj/structure/working/grindstone/try_take_input(obj/item/used_item, mob/user, silent) + if(working) + if(!silent) + to_chat(user, SPAN_WARNING("\The [src] is already in use, please wait for it to be free.")) + else + start_working() + used_item.try_sharpen_with(user, src) + if(!QDELETED(src) && working) + stop_working() + return TRUE + +/obj/structure/working/grindstone/get_sharpening_material() + RETURN_TYPE(/decl/material) + return stone_material diff --git a/mods/content/item_sharpening/icons/grindstone.dmi b/mods/content/item_sharpening/icons/grindstone.dmi new file mode 100644 index 000000000000..70b311b63b5c Binary files /dev/null and b/mods/content/item_sharpening/icons/grindstone.dmi differ diff --git a/mods/content/item_sharpening/item_sharpen.dm b/mods/content/item_sharpening/item_sharpen.dm new file mode 100644 index 000000000000..a72e928e5e88 --- /dev/null +++ b/mods/content/item_sharpening/item_sharpen.dm @@ -0,0 +1,49 @@ +/obj/item/update_name() + . = ..() + if(has_item_effect(/decl/item_effect/sharpened, IE_CAT_EXAMINE) && get_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES) <= 0) + SetName("dulled [name]") + +/obj/item/proc/can_sharpen_with(obj/sharpening_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE) || !material || !istype(sharpening_with)) + return FALSE + var/list/params = get_item_effect_parameters(/decl/item_effect/sharpened, IE_CAT_DAMAGE) + if(!islist(params) || params[IE_PAR_USES] >= params[IE_PAR_MAX_USES]) + return FALSE + return material.hardness <= sharpening_with.get_sharpening_material()?.hardness + +/obj/item/proc/sharpen_with(mob/user, obj/sharpen_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + var/list/params = get_item_effect_parameters(/decl/item_effect/sharpened, IE_CAT_DAMAGE) + if(!islist(params)) + return FALSE + var/max_uses = params[IE_PAR_MAX_USES] + if(max_uses <= 0) + return FALSE + var/uses = params[IE_PAR_USES] || 0 + if(uses >= max_uses) + return FALSE + set_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES, max_uses) + if(uses == 0) // We've sharpened up from dull. + update_attack_force() + update_name() + return TRUE + +/obj/item/proc/try_sharpen_with(mob/user, obj/sharpening_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + if(can_sharpen_with(sharpening_with)) + user.visible_message("\The [user] begins sharpening \the [src] with \the [sharpening_with].") + playsound(loc, 'sound/foley/knife1.ogg', 50) // metallic scrape, TODO better sound + if(user.do_skilled(10 SECONDS, SKILL_WEAPONS, src, check_holding = TRUE) && !QDELETED(sharpening_with) && can_sharpen_with(sharpening_with) && sharpen_with(user, sharpening_with)) + playsound(loc, 'sound/foley/knife1.ogg', 50) + user.visible_message("\The [user] sharpens \the [src] with \the [sharpening_with].") + else + to_chat(user, SPAN_WARNING("\The [src] cannot be [initial(sharp) ? "further sharpened" : "sharpened"] with \the [sharpening_with].")) + return TRUE + +// We don't override sharp because it's probably still pointy even if it isn't sharpened. +/obj/item/has_edge() + . = ..() + if(. && has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return get_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES) > 0 diff --git a/mods/content/item_sharpening/whetstone.dm b/mods/content/item_sharpening/whetstone.dm new file mode 100644 index 000000000000..4ff1dc020e3f --- /dev/null +++ b/mods/content/item_sharpening/whetstone.dm @@ -0,0 +1,20 @@ +/obj/item/whetstone + name = "whetstone" + desc = "A worn-down lozenge used to sharpen blades." + icon = 'icons/obj/items/striker.dmi' // TODO unique icon? + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_TINY + material_alteration = MAT_FLAG_ALTERATION_ALL + material = /decl/material/solid/quartz + color = /decl/material/solid/quartz::color + +/obj/item/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/whetstone) && try_sharpen_with(user, used_item)) + return TRUE + return ..() + +/decl/loadout_option/utility/whetstone + name = "whetstone" + path = /obj/item/whetstone + loadout_flags = null + uid = "gear_utility_whetstone" diff --git a/mods/content/matchmaking/_matchmaking.dme b/mods/content/matchmaking/_matchmaking.dme new file mode 100644 index 000000000000..e40cde1f5f06 --- /dev/null +++ b/mods/content/matchmaking/_matchmaking.dme @@ -0,0 +1,9 @@ +#ifndef CONTENT_PACK_MATCHMAKING +#define CONTENT_PACK_MATCHMAKING +// BEGIN_INCLUDE +#include "matchmaker.dm" +#include "matchmaking.dm" +#include "relations.dm" +#include "relations_types.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/matchmaking/matchmaker.dm b/mods/content/matchmaking/matchmaker.dm new file mode 100644 index 000000000000..70e424a3dfde --- /dev/null +++ b/mods/content/matchmaking/matchmaker.dm @@ -0,0 +1,289 @@ +/decl/modpack/matchmaking/on_roundstart() + do_matchmaking() + +// It doesn't really matter when this registers during init as long as it's before roundstart. +/decl/modpack/matchmaking/post_initialize() + . = ..() + events_repository.register_global(/decl/observ/player_latejoin, src, PROC_REF(matchmake_latejoiner)) + +/decl/modpack/matchmaking/proc/matchmake_latejoiner(mob/living/character, datum/job/job) + if(character.mind && character.client?.prefs.relations.len) + for(var/T in character.client.prefs.relations) + var/TT = relation_types[T] + var/datum/relation/relation = new TT + relation.holder = character.mind + relation.info = character.client.prefs.relations_info[T] + character.mind.gen_relations_info = character.client.prefs.relations_info["general"] + if(!ishuman(character)) + return TRUE + if(!job.create_record) + return TRUE + do_matchmaking() + return TRUE + +/datum/mind + var/list/known_connections //list of known (RNG) relations between people + +/datum/mind/Destroy() + QDEL_NULL_LIST(known_connections) + . = ..() + +/decl/modpack/matchmaking + var/list/relation_types = list() + var/list/relations = list() + +/decl/modpack/matchmaking/Initialize() + . = ..() + for(var/T in subtypesof(/datum/relation/)) + var/datum/relation/relation = T + relation_types[initial(relation.name)] = T + +/decl/modpack/matchmaking/proc/do_matchmaking() + var/list/to_warn = list() + for(var/datum/relation/relation in relations) + if(relation.other) + continue // don't warn about already-matched relations, even if they aren't finalised + relation.find_match() + if(relation.other && !relation.finalized) + to_warn |= relation.holder.current + for(var/mob/M in to_warn) + to_chat(M,"You have new connections. Use \"See Relationship Info\" to view and finalize them.") + +/decl/modpack/matchmaking/proc/get_relationships(datum/mind/M, finalized_only) + . = list() + for(var/datum/relation/relation in relations) + if(relation.holder == M && relation.other && (relation.finalized || !finalized_only)) + . += relation + +/decl/modpack/matchmaking/proc/get_relationships_between(datum/mind/holder, datum/mind/target, finalized_only) + . = list() + for(var/datum/relation/relation in relations) + if(relation.holder == holder && relation.other && relation.other.holder == target && (relation.finalized || !finalized_only)) + . += relation + +/decl/human_examination/matchmaking + // Show up after pose. + priority = /decl/human_examination/pose::priority + 1 + +// These should return null, text, or a list of text strings. +/decl/human_examination/matchmaking/do_examine(var/mob/living/user, var/distance, var/mob/living/human/source, hideflags, decl/pronouns/pronouns) + if(!istype(source) || !istype(user)) + return + if(!source.mind || !user.mind || source.name != source.real_name) + return + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + if(!length(matchmaker.get_relationships_between(user.mind, source.mind, TRUE))) + return + return "
    You know them. More...
    " + +//Types of relations + +/datum/relation + var/name = "Acquaintance" + var/desc = "You just know them." + var/list/can_connect_to //What relations (names) can matchmaking join us with? Defaults to own name. + var/list/incompatible //If we have relation like this with the mob, we can't join + var/datum/mind/holder + var/datum/relation/other + var/info + var/finalized + var/open = 2 //If non-zero, allow other relations to form connections + +/datum/relation/New() + ..() + if(!can_connect_to) + can_connect_to = list(type) + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + matchmaker.relations += src + +/datum/relation/proc/get_candidates() + .= list() + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + for(var/datum/relation/relation in matchmaker.relations) + if(!valid_candidate(relation.holder) || !can_connect(relation)) + continue + . += relation + +/datum/relation/proc/valid_candidate(datum/mind/M) + if(M == holder) //no, you NEED other people + return FALSE + + if(!M.current) //no extremely platonic relationships + return FALSE + + var/decl/special_role/special_role_data = GET_DECL(M.assigned_special_role) + if(istype(special_role_data) && (special_role_data.flags & ANTAG_OVERRIDE_JOB)) + return FALSE + + return TRUE + +/datum/relation/proc/can_connect(var/datum/relation/relation) + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + for(var/datum/relation/D in matchmaker.relations) //have to check all connections between us and them + if(D.holder == relation.holder && D.other && D.other.holder == holder) + if(D.type in incompatible) + return 0 + return (relation.type in can_connect_to) && !(relation.type in incompatible) && relation.open + +/datum/relation/proc/get_copy() + var/datum/relation/relation = new type + relation.holder = holder + relation.info = holder.current && holder.current.client ? holder.current.client.prefs.relations_info[relation.name] : info + relation.open = 0 + return relation + +/datum/relation/proc/find_match() + var/list/candidates = get_candidates() + if(!candidates.len) //bwoop bwoop + return 0 + var/datum/relation/relation = pick(candidates) + relation.open-- + if(relation.other) + relation = relation.get_copy() + other = relation + relation.other = src + return 1 + +/datum/relation/proc/sever() + to_chat(holder.current,"Your connection with [other.holder] is no more.") + to_chat(other.holder.current,"Your connection with [holder] is no more.") + other.other = null + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + matchmaker.relations -= other + matchmaker.relations -= src + qdel(other) + other = null + qdel(src) + +//Finalizes and propagates info if both sides are done. +/datum/relation/proc/finalize() + finalized = 1 + to_chat(holder.current,"You have finalized a connection with [other.holder].") + to_chat(other.holder.current,"[holder] has finalized a connection with you.") + if(other && other.finalized) + to_chat(holder.current,"Your connection with [other.holder] is now confirmed!") + to_chat(other.holder.current,"Your connection with [holder] is now confirmed!") + var/list/candidates = filter_list(global.player_list, /mob/living/human) + candidates -= holder.current + candidates -= other.holder.current + for(var/mob/living/human/M in candidates) + if(!M.mind || M.stat == DEAD || !valid_candidate(M.mind)) + candidates -= M + continue + var/datum/job/coworker = SSjobs.get_by_title(M.job) + if(coworker && holder.assigned_job && other.holder.assigned_job) + if(LAZYLEN(coworker.department_types & holder.assigned_job.department_types) || LAZYLEN(coworker.department_types & other.holder.assigned_job.department_types)) + candidates[M] = 5 //coworkers are 5 times as likely to know about your relations + + for(var/i=1 to 5) + if(!candidates.len) + break + var/mob/M = pickweight(candidates) + candidates -= M + if(!M.mind.known_connections) + M.mind.known_connections = list() + if(prob(70)) + M.mind.known_connections += get_desc_string() + else + M.mind.known_connections += "[holder] and [other.holder] seem to know each other, but you're not sure on the details." + +/datum/relation/proc/get_desc_string() + return "[holder] and [other.holder] know each other." + +/mob/living/verb/see_relationship_info() + set name = "See Relationship Info" + set desc = "See what connections between people you know of." + set category = "IC" + + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + var/list/relations = matchmaker.get_relationships(mind) + var/list/dat = list() + var/editable = 0 + if(mind.gen_relations_info) + dat += "Things they all know about you:
    [mind.gen_relations_info]
    " + dat += "An \[F\] indicates that the other player has finalized the connection.
    " + dat += "
    " + for(var/datum/relation/relation in relations) + dat += "[relation.other.finalized ? "\[F\] " : ""][relation.other.holder], [relation.other.holder.role_alt_title ? relation.other.holder.role_alt_title : relation.other.holder.assigned_role]." + if (!relation.finalized) + dat += " Remove" + editable = 1 + dat += "
    [relation.desc]" + dat += "
    " + dat += "Things they know about you:[!relation.finalized ?"Edit" : ""]
    [relation.info ? "[relation.info]" : " Nothing specific."]" + if(relation.other.info) + dat += "
    Things you know about them:
    [relation.other.info]
    [relation.other.holder.gen_relations_info]" + dat += "
    " + + if(mind.known_connections && mind.known_connections.len) + dat += "Other people:" + for(var/I in mind.known_connections) + dat += "
    [I]" + + var/datum/browser/popup = new(usr, "relations", "Relationship Info") + if(editable) + dat.Insert(1,"Finalize edits and close
    ") + popup.set_window_options("focus=0;can_close=0;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;") + popup.set_content(jointext(dat,null)) + popup.open() + +/mob/living/proc/see_relationship_info_with(var/mob/living/other) + if(!other.mind) + return + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + var/list/relations = matchmaker.get_relationships(mind,other.mind,TRUE) + var/list/dat = list("

    [other]

    ") + if(mind.gen_relations_info) + dat += "Things they know about you:
    [mind.gen_relations_info]
    " + dat += "
    " + for(var/datum/relation/relation in relations) + dat += "
    [relation.desc]" + dat += "
    " + dat += "Things they know about you:
    [relation.info ? "[relation.info]" : " Nothing specific."]" + if(relation.other.info) + dat += "
    Things you know about them:
    [relation.other.info]
    [relation.other.holder.gen_relations_info]" + dat += "
    " + + var/datum/browser/popup = new(usr, "relations", "Relationship Info") + popup.set_content(jointext(dat,null)) + popup.open() + +/mob/living/OnTopic(mob/living/user, href_list) + if(href_list["show_relations"]) + if(istype(user)) + user.see_relationship_info_with(src) + return TOPIC_HANDLED + if(href_list["show_relationship_info"]) + if(istype(user)) + user.see_relationship_info() + return TOPIC_HANDLED + return ..() + +/mob/living/OnSelfTopic(href_list) + if(href_list["del_relation"]) + var/datum/relation/relation = locate(href_list["del_relation"]) + if(istype(relation)) + relation.sever() + see_relationship_info() + return TOPIC_HANDLED + if(href_list["info_relation"]) + var/datum/relation/relation = locate(href_list["info_relation"]) + if(istype(relation)) + var/info = sanitize(input("What would you like the other party for this connection to know about your character?","Character info",relation.info) as message|null) + if(info) + relation.info = info + see_relationship_info() + return TOPIC_HANDLED + if(href_list["relations_close"]) + var/ok = "Close anyway" + ok = alert("HEY! You have some non-finalized relationships. You can terminate them if they do not fit your character, or edit the info tidbit that the other party is given. THIS IS YOUR ONLY CHANCE to do so - after you close the window, they won't be editable.","Finalize relationships","Return to edit", "Close anyway") + if(ok == "Close anyway") + var/decl/modpack/matchmaking/matchmaker = IMPLIED_DECL + var/list/relations = matchmaker.get_relationships(mind) + for(var/datum/relation/relation in relations) + relation.finalize() + show_browser(src,null, "window=relations") + else + show_browser(src,null, "window=relations") + return TOPIC_HANDLED + return ..() \ No newline at end of file diff --git a/mods/content/matchmaking/matchmaking.dm b/mods/content/matchmaking/matchmaking.dm new file mode 100644 index 000000000000..1813a04885e3 --- /dev/null +++ b/mods/content/matchmaking/matchmaking.dm @@ -0,0 +1,2 @@ +/decl/modpack/matchmaking + name = "Matchmaking" \ No newline at end of file diff --git a/mods/content/matchmaking/relations.dm b/mods/content/matchmaking/relations.dm new file mode 100644 index 000000000000..b1c60305caba --- /dev/null +++ b/mods/content/matchmaking/relations.dm @@ -0,0 +1,60 @@ +/datum/preferences + var/list/relations + var/list/relations_info + +/datum/category_group/player_setup_category/relations_preferences + name = "Matchmaking" + sort_order = 6.5 // someone should really redo how these work + category_item_type = /datum/category_item/player_setup_item/relations + +/datum/category_item/player_setup_item/relations + name = "Matchmaking" + sort_order = 1 + +/datum/category_item/player_setup_item/relations/load_character(datum/pref_record_reader/R) + pref.relations = R.read("relations") + pref.relations_info = R.read("relations_info") + +/datum/category_item/player_setup_item/relations/save_character(datum/pref_record_writer/writer) + writer.write("relations", pref.relations) + writer.write("relations_info", pref.relations_info) + +/datum/category_item/player_setup_item/relations/sanitize_character() + if(!pref.relations) + pref.relations = list() + if(!pref.relations_info) + pref.relations_info = list() + +/datum/category_item/player_setup_item/relations/content(mob/user) + .=list() + . += "Characters with enabled relations are paired up randomly after spawn. You can terminate relations when you first open relations info window, but after that it's final." + . += "
    " + . += "
    What do they know about you? This is the general info that all kinds of your connections would know. Edit" + . += "
    [pref.relations_info["general"] ? pref.relations_info["general"] : "Nothing specific."]" + . += "
    " + for(var/datum/relation/relation as anything in subtypesof(/datum/relation)) + . += "[initial(relation.name)]\t" + if(initial(relation.name) in pref.relations) + . += "On" + . += "Off" + else + . += "On" + . += "Off" + . += "
    [initial(relation.desc)]" + . += "
    What do they know about you?Edit" + . += "
    [pref.relations_info[initial(relation.name)] ? pref.relations_info[initial(relation.name)] : "Nothing specific."]" + . += "
    " + . = jointext(.,null) + +/datum/category_item/player_setup_item/relations/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["relation"]) + var/relation = href_list["relation"] + pref.relations ^= relation + return TOPIC_REFRESH + if(href_list["relation_info"]) + var/relation = href_list["relation_info"] + var/info = sanitize(input("Character info", "What would you like the other party for this connection to know about your character?",html_decode(pref.relations_info[relation])) as message|null) + if(info) + pref.relations_info[relation] = info + return TOPIC_REFRESH + return ..() diff --git a/code/modules/client/preference_setup/matchmaking/relations_types.dm b/mods/content/matchmaking/relations_types.dm similarity index 79% rename from code/modules/client/preference_setup/matchmaking/relations_types.dm rename to mods/content/matchmaking/relations_types.dm index afa34a5b195b..8f244851084c 100644 --- a/code/modules/client/preference_setup/matchmaking/relations_types.dm +++ b/mods/content/matchmaking/relations_types.dm @@ -15,18 +15,18 @@ /datum/relation/kid_friend/get_candidates() var/list/creche = ..() - var/mob/living/carbon/human/holdermob = holder.current + var/mob/living/human/holdermob = holder.current if(istype(holdermob)) for(var/datum/relation/kid in creche) - var/mob/living/carbon/human/kidmob = kid.holder.current + var/mob/living/human/kidmob = kid.holder.current if(!istype(kidmob)) continue - if(abs(holdermob.age - kidmob.age) > 3) + if(abs(holdermob.get_age() - kidmob.get_age()) > 3) creche -= kid //No creepers please, it's okay if the pool is small. continue - var/kidhome = kidmob.get_cultural_value(TAG_HOMEWORLD) - var/holderhome = holdermob.get_cultural_value(TAG_HOMEWORLD) + var/kidhome = kidmob.get_background_datum_by_flag(BACKGROUND_FLAG_HOMEWORLD) + var/holderhome = holdermob.get_background_datum_by_flag(BACKGROUND_FLAG_HOMEWORLD) if(kidhome && holderhome && kidhome != holderhome) creche -= kid //No trans-galactic shennanigans either. return creche @@ -66,13 +66,13 @@ var/list/rest = ..() var/list/best = list() var/list/good = list() - for(var/datum/relation/R in rest) - if(!R.holder.assigned_job || !holder.assigned_job) + for(var/datum/relation/relation in rest) + if(!relation.holder.assigned_job || !holder.assigned_job) continue - if(R.holder.assigned_job == holder.assigned_job) - best += R - if(LAZYLEN(R.holder.assigned_job.department_refs & holder.assigned_job.department_refs)) - good += R + if(relation.holder.assigned_job == holder.assigned_job) + best += relation + if(LAZYLEN(relation.holder.assigned_job.department_types & holder.assigned_job.department_types)) + good += relation if(best.len) return best else if (good.len) @@ -93,10 +93,10 @@ /datum/relation/spessnam/get_candidates() var/list/warbuds = ..() var/list/branchmates = list() - var/mob/living/carbon/human/holdermob = holder.current - if(istype(holdermob) && GLOB.using_map && (GLOB.using_map.flags & MAP_HAS_BRANCH)) + var/mob/living/human/holdermob = holder.current + if(istype(holdermob) && global.using_map && (global.using_map.flags & MAP_HAS_BRANCH)) for(var/datum/relation/buddy in warbuds) - var/mob/living/carbon/human/buddymob = buddy.holder.current + var/mob/living/human/buddymob = buddy.holder.current if(!istype(buddymob)) continue if(holdermob.char_branch == buddymob.char_branch) diff --git a/mods/content/modern_earth/_modern_earth.dm b/mods/content/modern_earth/_modern_earth.dm new file mode 100644 index 000000000000..95aeb7fa7b4f --- /dev/null +++ b/mods/content/modern_earth/_modern_earth.dm @@ -0,0 +1,5 @@ +/decl/modpack/modern_earth + name = "Modern Earth Content" + credits_adjectives = list("SOCRATIC") + credits_holidays = list("CHRISTMAS", "EASTER", "WEEKEND", "THURSDAY") + credits_topics = list("ANCIENT CHINESE MEDICINE", "STRING THEORY") diff --git a/mods/content/modern_earth/_modern_earth.dme b/mods/content/modern_earth/_modern_earth.dme new file mode 100644 index 000000000000..69de0a86f569 --- /dev/null +++ b/mods/content/modern_earth/_modern_earth.dme @@ -0,0 +1,9 @@ +#ifndef MODPACK_MODERN_EARTH +#define MODPACK_MODERN_EARTH +// BEGIN_INCLUDE +#include "_modern_earth.dm" +#include "glass_types.dm" +#include "insignia.dm" +#include "datum\religions.dm" +// END_INCLUDE +#endif diff --git a/mods/content/modern_earth/datum/religions.dm b/mods/content/modern_earth/datum/religions.dm new file mode 100644 index 000000000000..d241f9a86bb7 --- /dev/null +++ b/mods/content/modern_earth/datum/religions.dm @@ -0,0 +1,74 @@ +/decl/background_detail/religion/jewish + name = "Judaism" + description = "An Abrahamic monotheistic religion held to by the Jewish people. Someone who practices Judaism and is of the Jewish culture is called a Jew." + uid = "religion_judaism" + +/decl/background_detail/religion/hindu + name = "Hinduism" + description = "An Indian religion encompassing a variety of traditions, beliefs and spiritual practices. Someone who practices Hinduism is called a Hindu." + uid = "religion_hinduism" + +/decl/background_detail/religion/buddhist + name = "Buddhism" + description = "An Indian religion encompassing a variety of traditions, beliefs and spiritual practices based on the teachings of the Buddha. Someone who practices Buddhism is called a Buddhist." + uid = "religion_buddhism" + +/decl/background_detail/religion/jain + name = "Jainism" + description = "An Indian religion that teaches salvation through successive lives and nonviolence. Someone who practices Jainism is called a Jain." + uid = "religion_jainsim" + +/decl/background_detail/religion/sikh + name = "Sikhsm" + description = "An Indian monotheistic religion based on the spiritual teachings of Guru Nanak and the nine Sikh gurus that succeeded him. Someone who practices Sikhism is called a Sikh." + uid = "religion_sikhsm" + +/decl/background_detail/religion/muslim + name = "Islam" + description = "An Abrahamic monotheistic religion teaching that there is only one God and that Muhammad is His prophet. Someone who practices Islam is called a Muslim." + uid = "religion_islam" + +/decl/background_detail/religion/christian + name = "Christianity" + description = "An Abrahamic monotheistic religion based on the life and teachings of Jesus of Nazareth. Someone who practices Christianity is called a Christian." + uid = "religion_christianity" + +/decl/background_detail/religion/bahai + name = "Bahai" + description = "An Abrahamic monotheistic religion that follows the teachings of Baha'u'llah and believes in universal peace and unity. Someone who practices the Baha'i Faith is called a Baha'i." + uid = "religion_bahai" + +/decl/background_detail/religion/agnostic + name = "Agnosticism" + description = "A belief that nothing is known or can be known of the existence or nature of God. Someone who holds to agnosticism is called an agnostic." + uid = "religion_agnosticism" + +/decl/background_detail/religion/deist + name = "Deism" + description = "A belief in the existence of a supreme being, specifically of a creator who does not intervene in the universe. Someone who practices deism is called a deist." + uid = "religion_deist" + +/decl/background_detail/religion/atheist + name = "Atheism" + description = "A lack of belief in a God. Someone who holds to atheism is called an atheist." + uid = "religion_atheism" + +/decl/background_detail/religion/thelemite + name = "Thelema" + description = "An esoteric Western religion focusing on the law of Thelema. Someone who practices Thelema is called a Thelemite." + uid = "religion_thelema" + +/decl/background_detail/religion/spiritualism + name = "Spiritualism" + description = "A belief based on communication with the spirits of the dead, especially through mediums. Someone who practices spiritualism is called a spiritualist." + uid = "religion_spiritualism" + +/decl/background_detail/religion/shinto + name = "Shinto" + description = "A traditional Japanese religion based on rituals to create a connection between the past and modern day. Someone who practices Shinto is called a Shintoist." + uid = "religion_shinto" + +/decl/background_detail/religion/taoist + name = "Taoism" + description = "A traditional Chinese religion that emphasizes living in harmony with the Tao. Someone who practices Taoism is called a Taoist." + uid = "religion_taoist" diff --git a/mods/content/modern_earth/glass_types.dm b/mods/content/modern_earth/glass_types.dm new file mode 100644 index 000000000000..7a957edb698b --- /dev/null +++ b/mods/content/modern_earth/glass_types.dm @@ -0,0 +1,6 @@ +/obj/item/chems/drinks/glass2/coffeecup/britcup + name = "british coffee cup" + desc = "A coffee cup with the British flag emblazoned on it." + base_icon = "coffeecup_brit" + icon_state = "coffeecup_brit" + base_name = "british cup" \ No newline at end of file diff --git a/mods/content/modern_earth/insignia.dm b/mods/content/modern_earth/insignia.dm new file mode 100644 index 000000000000..95dcb8e5a0d3 --- /dev/null +++ b/mods/content/modern_earth/insignia.dm @@ -0,0 +1,44 @@ +/obj/item/clothing/insignia/christian + name = "chaplain insignia (christianity)" + desc = "An insignia worn by chaplains. The cross represents Christianity." + icon = 'icons/clothing/accessories/jewelry/religious/icon_christianity.dmi' + +/obj/item/clothing/insignia/judaism + name = "chaplain insignia (Judaism)" + desc = "An insignia worn by chaplains. The Star of David represents Judaism." + icon = 'icons/clothing/accessories/jewelry/religious/icon_judaism.dmi' + +/obj/item/clothing/insignia/islam + name = "chaplain insignia (Islam)" + desc = "An insignia worn by chaplains. The star & crescent represent Islam." + icon = 'icons/clothing/accessories/jewelry/religious/icon_islam.dmi' + +/obj/item/clothing/insignia/buddhism + name = "chaplain insignia (Buddhism)" + desc = "An insignia worn by chaplains. The Dharma Chakra represents Buddhism." + icon = 'icons/clothing/accessories/jewelry/religious/icon_buddhism.dmi' + +/obj/item/clothing/insignia/hinduism + name = "chaplain insignia (Hinduism)" + desc = "An insignia worn by chaplains. The Om represents Hinduism." + icon = 'icons/clothing/accessories/jewelry/religious/icon_hinduism.dmi' + +/obj/item/clothing/insignia/sikhism + name = "chaplain insignia (Sikhism)" + desc = "An insignia worn by chaplains. The Khanda represents Sikhism." + icon = 'icons/clothing/accessories/jewelry/religious/icon_sikh.dmi' + +/obj/item/clothing/insignia/bahaifaith + name = "chaplain insignia (Baha'i faith)" + desc = "An insignia worn by chaplains. The nine-pointed star represents the Baha'i faith." + icon = 'icons/clothing/accessories/jewelry/religious/icon_baha.dmi' + +/obj/item/clothing/insignia/jainism + name = "chaplain insignia (Jainism)" + desc = "An insignia worn by chaplains. The symbol of Ahimsa represents Jainism." + icon = 'icons/clothing/accessories/jewelry/religious/icon_jain.dmi' + +/obj/item/clothing/insignia/taoism + name = "chaplain insignia (Taoism)" + desc = "An insignia worn by chaplains. The yin yang represents Taoism." + icon = 'icons/clothing/accessories/jewelry/religious/icon_taoist.dmi' diff --git a/mods/content/mouse_highlights/_mouse_highlight.dme b/mods/content/mouse_highlights/_mouse_highlight.dme new file mode 100644 index 000000000000..a4cb9ea9d6a8 --- /dev/null +++ b/mods/content/mouse_highlights/_mouse_highlight.dme @@ -0,0 +1,8 @@ +#ifndef CONTENT_PACK_MOUSEOVER +#define CONTENT_PACK_MOUSEOVER +// BEGIN_INCLUDE +#include "mouse_highlight.dm" +#include "mouse_highlight_client.dm" +#include "mouse_highlight_prefs.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/mouse_highlights/mouse_highlight.dm b/mods/content/mouse_highlights/mouse_highlight.dm new file mode 100644 index 000000000000..cdb58d46ee9a --- /dev/null +++ b/mods/content/mouse_highlights/mouse_highlight.dm @@ -0,0 +1,18 @@ +/atom/movable + var/show_client_mouseover_highlight = FALSE +/mob + show_client_mouseover_highlight = TRUE +/obj/item + show_client_mouseover_highlight = TRUE +/obj/machinery + show_client_mouseover_highlight = TRUE +/obj/structure/cable + show_client_mouseover_highlight = TRUE +/obj/structure/railing + show_client_mouseover_highlight = TRUE +/obj/structure/stairs + show_client_mouseover_highlight = TRUE +/obj/structure/ladder + show_client_mouseover_highlight = TRUE +/obj/structure/closet + show_client_mouseover_highlight = TRUE diff --git a/mods/content/mouse_highlights/mouse_highlight_client.dm b/mods/content/mouse_highlights/mouse_highlight_client.dm new file mode 100644 index 000000000000..f9801ef8d73a --- /dev/null +++ b/mods/content/mouse_highlights/mouse_highlight_client.dm @@ -0,0 +1,119 @@ + +/client + var/datum/callback/mouseover_callback // Cached callback, see /client/New() + var/obj/mouseover_highlight_dummy // Dummy atom to hold the appearance of our highlighted atom, see comments in /client/proc/refresh_mouseover_highlight. + var/weakref/current_highlight_atom // Current weakref to highlighted atom, used for checking if we're mousing over the same atom repeatedly. + var/image/current_highlight // Current dummy image holding our highlight. + + var/mouseover_refresh_timer // Holds an ID to the timer used to update the mouseover highlight. + var/last_mouseover_params // Stores mouse/keyboard params as of last mouseover, to check for shift being held. + var/last_mouseover_highlight_time // Stores last world.time we mouseover'd, to prevent it happening more than once per world.tick_lag. + +/client/New() + // Cache our callback as we will potentially be using it (10 / ticklag) times per second, + mouseover_callback = CALLBACK(src, PROC_REF(refresh_mouseover_highlight_timer)) + . = ..() + +// This proc iterates constantly whenever something is being mouseover'd, so that it +// can update appearance to match any changes in the base icon. I considered using +// some kind of hook in update_icon() and set_dir() but this seemed much more robust. +/client/proc/refresh_mouseover_highlight_timer() + if(!current_highlight_atom || !refresh_mouseover_highlight(current_highlight_atom?.resolve(), last_mouseover_params)) + // If refresh_mouseover_highlight() returns false we need to end our iteration and kill the highlight. + if(current_highlight) + images -= current_highlight + qdel(current_highlight) + current_highlight = null + current_highlight_atom = null + deltimer(mouseover_refresh_timer) + mouseover_refresh_timer = null + +// Main body of work happens in this proc. +/client/proc/refresh_mouseover_highlight(object, params, check_adjacency = FALSE) + + // Verify if we should be showing a highlight at all. + if(!istype(object, /atom/movable) || (check_adjacency && !mob.Adjacent(object))) + return FALSE + var/list/modifiers = params2list(params) + var/highlight_pref = get_preference_value(/datum/client_preference/show_mouseover_highlights) + if(highlight_pref != PREF_SHOW && (highlight_pref != PREF_SHOW_HOLD_SHIFT || !modifiers["shift"])) + return FALSE + var/atom/movable/AM = object + if(!AM.show_client_mouseover_highlight || get_dist(mob, object) > 1) + return FALSE + + // Generate our dummy objects if they got nulled/discarded. + if(!current_highlight) + current_highlight = new /image + current_highlight.appearance_flags |= (KEEP_TOGETHER|RESET_COLOR) + images += current_highlight + if(!mouseover_highlight_dummy) + mouseover_highlight_dummy = new + + // Copy over the atom's appearance to our holder object. + // client.images does not respect pixel offsets for images, but vis contents does, + // and images have vis contents - so we throw a null image into client.images, then + // throw a holder object with the appearance of the mouse-overed atom into its vis contents. + mouseover_highlight_dummy.appearance = AM + mouseover_highlight_dummy.name = "" + mouseover_highlight_dummy.verbs.Cut() + mouseover_highlight_dummy.vis_flags |= VIS_INHERIT_ID + mouseover_highlight_dummy.dir = AM.dir + mouseover_highlight_dummy.transform = AM.transform + + // For some reason you need to explicitly zero the pixel offsets of the holder object + // or anything with a pixel offset will not line up with the highlight. Thanks DM. + mouseover_highlight_dummy.pixel_x = 0 + mouseover_highlight_dummy.pixel_y = 0 + mouseover_highlight_dummy.pixel_w = 0 + mouseover_highlight_dummy.pixel_z = 0 + + // Replane to be over the UI, make sure it can't block clicks, and set its outline. + mouseover_highlight_dummy.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE + mouseover_highlight_dummy.layer = HUD_PLANE + mouseover_highlight_dummy.plane = HUD_ABOVE_ITEM_LAYER + mouseover_highlight_dummy.alpha = prefs?.UI_mouseover_alpha || 255 + mouseover_highlight_dummy.appearance_flags |= (KEEP_TOGETHER|RESET_COLOR) + mouseover_highlight_dummy.add_filter("glow", 1, list(type = "drop_shadow", color = (prefs?.UI_mouseover_color || COLOR_AMBER) + "F0", size = 1, offset = 1, x = 0, y = 0)) + + // Replanes the overlays to avoid explicit plane/layer setting (such as + // computer overlays) interfering with the ordering of the highlight. + if(length(mouseover_highlight_dummy.overlays)) + var/list/replaned_overlays + for(var/thing in mouseover_highlight_dummy.overlays) + var/mutable_appearance/MA = new(thing) + MA.plane = FLOAT_PLANE + MA.layer = FLOAT_LAYER + LAZYADD(replaned_overlays, MA) + mouseover_highlight_dummy.overlays = replaned_overlays + if(length(mouseover_highlight_dummy.underlays)) + var/list/replaned_underlays + for(var/thing in mouseover_highlight_dummy.underlays) + var/mutable_appearance/MA = new(thing) + MA.plane = FLOAT_PLANE + MA.layer = FLOAT_LAYER + LAZYADD(replaned_underlays, MA) + mouseover_highlight_dummy.underlays = replaned_underlays + + // Finally update our highlight's vis contents and location . + current_highlight.clear_vis_contents() + current_highlight.add_vis_contents(mouseover_highlight_dummy) + current_highlight.loc = object + current_highlight_atom = weakref(AM) + + // Keep track our params so the update ticker knows if we were holding shift or not. + last_mouseover_params = params + + return TRUE + +// Simple hooks to catch the client mouseover/mouseleave events and start our highlight timer as needed. +/client/MouseEntered(object,location,control,params) + if(world.time > last_mouseover_highlight_time && mouseover_callback && refresh_mouseover_highlight(object, params, check_adjacency = TRUE) && !mouseover_refresh_timer) + last_mouseover_highlight_time = world.time + mouseover_refresh_timer = addtimer(mouseover_callback, 1, (TIMER_UNIQUE | TIMER_LOOP | TIMER_STOPPABLE)) + . = ..() +/client/MouseExited(object, location, control, params) + if(current_highlight_atom?.resolve() == object) + current_highlight_atom = null + refresh_mouseover_highlight_timer() + . = ..() diff --git a/mods/content/mouse_highlights/mouse_highlight_prefs.dm b/mods/content/mouse_highlights/mouse_highlight_prefs.dm new file mode 100644 index 000000000000..756c25c98df7 --- /dev/null +++ b/mods/content/mouse_highlights/mouse_highlight_prefs.dm @@ -0,0 +1,37 @@ +var/global/const/PREF_SHOW_HOLD_SHIFT = "While Holding Shift" + +/datum/client_preference/show_mouseover_highlights + description ="Mouseover Highlights" + key = "SHOW_MOUSEOVER_HIGHLIGHT" + options = list(PREF_SHOW_HOLD_SHIFT, PREF_HIDE, PREF_SHOW) + +/datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) + . = ..() + if(.) + return + if(href_list["select_mouseover_color"]) + var/UI_mouseover_color_new = input(user, "Choose mouseover color, dark colors are not recommended!", "Global Preference", pref.UI_mouseover_color) as color|null + if(isnull(UI_mouseover_color_new) || !CanUseTopic(user)) return TOPIC_NOACTION + pref.UI_mouseover_color = UI_mouseover_color_new + if(user?.client?.current_highlight) + user.client.current_highlight = null + return TOPIC_REFRESH + else if(href_list["select_mouseover_alpha"]) + var/UI_mouseover_alpha_new = input(user, "Select mouseover alpha (transparency) level, between 50 and 255.", "Global Preference", pref.UI_mouseover_alpha) as num|null + if(isnull(UI_mouseover_alpha_new) || (UI_mouseover_alpha_new < 50 || UI_mouseover_alpha_new > 255) || !CanUseTopic(user)) return TOPIC_NOACTION + pref.UI_mouseover_alpha = UI_mouseover_alpha_new + if(user?.client?.current_highlight) + user.client.current_highlight = null + return TOPIC_REFRESH + +/datum/category_item/player_setup_item/player_global/ui/get_ui_table(var/mob/user) + . = ..() || list() + . += "
    UI Mouseover Color[pref.UI_mouseover_color]
    __
    reset
    UI Mouseover Opacity[pref.UI_mouseover_alpha]reset
    " + for(var/faculty in list(PSI_COERCION, PSI_PSYCHOKINESIS, PSI_REDACTION, PSI_ENERGISTICS)) + var/decl/psionic_faculty/faculty_decl = SSpsi.get_faculty(faculty) + var/faculty_rank = psi ? psi.get_rank(faculty) : 0 + . += "" + for(var/i = 1 to LAZYLEN(global.psychic_ranks_to_strings)) + var/psi_title = global.psychic_ranks_to_strings[i] + if(i == faculty_rank) + psi_title = "[psi_title]" + . += "" + . += "" + . += "
    [faculty_decl.name][psi_title]
    " + else + . += "Only available for living mobs, sorry." + . = jointext(., null) + +/decl/ability/can_use_ability(mob/user, list/metadata, silent = FALSE) + . = ..() + if(. && is_supernatural) + var/spell_leech = user.disrupts_psionics() + if(spell_leech) + if(!silent) + to_chat(user, SPAN_WARNING("You try to marshal your energy, but find it leeched away by \the [spell_leech]!")) + return FALSE diff --git a/mods/psionics/_psionics.dme b/mods/content/psionics/_psionics.dme similarity index 96% rename from mods/psionics/_psionics.dme rename to mods/content/psionics/_psionics.dme index dbcd27ffe8f5..523544804011 100644 --- a/mods/psionics/_psionics.dme +++ b/mods/content/psionics/_psionics.dme @@ -9,25 +9,24 @@ #include "datum\jobs.dm" #include "datum\mind.dm" #include "datum\security_state.dm" -#include "datum\spells.dm" #include "datum\surgery.dm" #include "datum\uplink.dm" +#include "datum\antagonists\beguiled.dm" #include "datum\antagonists\foundation.dm" #include "datum\antagonists\paramount.dm" #include "items\_items.dm" #include "items\brain.dm" #include "items\cerebro_enhancers.dm" +#include "items\clothing.dm" #include "items\coffee_cup.dm" #include "items\foundation_implanter.dm" #include "items\foundation_labcoat.dm" #include "items\foundation_weapon.dm" -#include "items\grabs.dm" #include "items\id_card.dm" #include "items\implant.dm" #include "items\literature.dm" #include "items\null_ammo.dm" #include "items\nullrod.dm" -#include "items\soulstone.dm" #include "machines\psimeter.dm" #include "machines\psimonitor.dm" #include "system\subsystem_psi.dm" diff --git a/mods/content/psionics/datum/antagonists/beguiled.dm b/mods/content/psionics/datum/antagonists/beguiled.dm new file mode 100644 index 000000000000..b4745b871262 --- /dev/null +++ b/mods/content/psionics/datum/antagonists/beguiled.dm @@ -0,0 +1,29 @@ +/decl/special_role/beguiled + name = "Beguiled" + name_plural = "Beguiled" + welcome_text = "Your mind is no longer solely your own..." + flags = ANTAG_IMPLANT_IMMUNE + + var/list/minion_controllers = list() + +/decl/special_role/beguiled/create_objectives(var/datum/mind/player) + var/mob/living/controller = minion_controllers["\ref[player]"] + if(!controller) + return // Someone is playing with buttons they shouldn't be. + var/datum/objective/obey = new + obey.owner = player + obey.explanation_text = "You are under [controller.real_name]'s glamour, and must follow their commands." + player.objectives |= obey + +/decl/special_role/beguiled/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance, var/mob/new_controller) + if(!new_controller) + return FALSE + . = ..() + if(.) + minion_controllers["\ref[player]"] = new_controller + +/decl/special_role/beguiled/greet(var/datum/mind/player) + . = ..() + var/mob/living/controller = minion_controllers["\ref[player]"] + if(controller) + to_chat(player, "You have been ensnared by [controller.real_name]'s glamour. Follow their commands.") diff --git a/mods/content/psionics/datum/antagonists/foundation.dm b/mods/content/psionics/datum/antagonists/foundation.dm new file mode 100644 index 000000000000..8b4f204cad66 --- /dev/null +++ b/mods/content/psionics/datum/antagonists/foundation.dm @@ -0,0 +1,53 @@ +/decl/special_role/foundation + name = "Foundation Agent" + antag_indicator = "hudfoundation" + name_plural = "Foundation Agents" + welcome_text = "You are a field agent of the Cuchulain Foundation, \ + a body that specializes in taking down psychic threats. You have a free pass to anywhere \ + you like, a pistol loaded with anti-psi nullglass rounds, and a clear duty. Naturally, \ + nobody takes your employers seriously - until a day like today." + antag_text = "You are an anti antagonist! Within the rules, \ + try to save the installation and its inhabitants from the ongoing crisis. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to Foundation Agents." + + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_SET_APPEARANCE + antaghud_indicator = "hudfoundation" + landmark_id = "Response Team" + hard_cap = 3 + hard_cap_round = 3 + initial_spawn_req = 1 + initial_spawn_target = 2 + min_player_age = 14 + faction = "foundation" + default_outfit = /decl/outfit/foundation + id_title = "Foundation Agent" + +/decl/special_role/foundation/equip_role(var/mob/living/human/player) + . = ..() + if(.) + player.set_psi_rank(PSI_REDACTION, 3, defer_update = TRUE) + player.set_psi_rank(PSI_COERCION, 3, defer_update = TRUE) + player.set_psi_rank(PSI_PSYCHOKINESIS, 3, defer_update = TRUE) + player.set_psi_rank(PSI_ENERGISTICS, 3, defer_update = TRUE) + var/datum/ability_handler/psionics/psi = player.get_ability_handler(/datum/ability_handler/psionics) + psi?.update(TRUE) + +/decl/outfit/foundation + name = "Cuchulain Foundation Agent" + glasses = /obj/item/clothing/glasses/sunglasses + uniform = /obj/item/clothing/pants/slacks/black/outfit + shoes = /obj/item/clothing/shoes/color/black + hands = list(/obj/item/briefcase/foundation) + l_ear = /obj/item/radio/headset/foundation + holster = /obj/item/clothing/webbing/holster/armpit + id_type = /obj/item/card/id/foundation + id_slot = slot_wear_id_str + +/obj/item/radio/headset/foundation + name = "\improper Foundation radio headset" + desc = "The headset of the occult cavalry." + icon = 'icons/obj/items/device/radio/headsets/headset_command.dmi' + encryption_keys = list(/obj/item/encryptionkey/specops) diff --git a/mods/content/psionics/datum/antagonists/paramount.dm b/mods/content/psionics/datum/antagonists/paramount.dm new file mode 100644 index 000000000000..b7c76a8cb407 --- /dev/null +++ b/mods/content/psionics/datum/antagonists/paramount.dm @@ -0,0 +1,74 @@ +/decl/special_role/paramount + name = "Paramount" + name_plural = "Paramounts" + landmark_id = "ninjastart" + welcome_text = "You were once one of the finest minds of your culture, now driven to madness by the whispers of the howling dark and blessed with psychic faculties that defy understanding. Using your C-E rig and your twisted knowledge of psionics, advance your agenda in human space." + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_RANDSPAWN | ANTAG_SET_APPEARANCE + antaghud_indicator = "hudwizard" + initial_spawn_req = 1 + initial_spawn_target = 1 + hard_cap = 1 + hard_cap_round = 3 + min_player_age = 18 + faction = "paramount" + default_outfit = /decl/outfit/paramount + +/decl/outfit/paramount + name = "Special Role - Paramount Grandmaster" + head = /obj/item/clothing/head/helmet/space/psi_amp + uniform = /obj/item/clothing/costume/psysuit + suit = /obj/item/clothing/suit/paramount + shoes = /obj/item/clothing/shoes/jackboots + back = /obj/item/backpack/satchel + gloves = /obj/item/clothing/gloves/grey + id_type = /obj/item/card/id/syndicate + +/decl/special_role/paramount/equip_role(var/mob/living/human/player) + . = ..() + if(.) + player.set_psi_rank(PSI_REDACTION, 3, defer_update = TRUE) + player.set_psi_rank(PSI_COERCION, 3, defer_update = TRUE) + player.set_psi_rank(PSI_PSYCHOKINESIS, 3, defer_update = TRUE) + player.set_psi_rank(PSI_ENERGISTICS, 3, defer_update = TRUE) + var/datum/ability_handler/psionics/psi = player.get_ability_handler(/datum/ability_handler/psionics) + psi?.update(TRUE) + +/decl/special_role/paramount/create_objectives(var/datum/mind/player) + + if(!..()) + return + // Copied from ninja for now. + var/objective_list = list(1,2,3) + for(var/i=rand(2,3),i>0,i--) + switch(pick(objective_list)) + if(1)//Kill + var/datum/objective/assassinate/objective = new + objective.owner = player + objective.target = objective.find_target() + if(objective.target != "Free Objective") + player.objectives += objective + else + i++ + objective_list -= 1 // No more than one kill objective + if(2)//Protect + var/datum/objective/protect/objective = new + objective.owner = player + objective.target = objective.find_target() + if(objective.target != "Free Objective") + player.objectives += objective + else + i++ + objective_list -= 3 + if(3)//Harm + var/datum/objective/harm/objective = new + objective.owner = player + objective.target = objective.find_target() + if(objective.target != "Free Objective") + player.objectives += objective + else + i++ + objective_list -= 4 + + var/datum/objective/survive/objective = new + objective.owner = player + player.objectives += objective diff --git a/mods/content/psionics/datum/armour.dm b/mods/content/psionics/datum/armour.dm new file mode 100644 index 000000000000..82e2d7beabea --- /dev/null +++ b/mods/content/psionics/datum/armour.dm @@ -0,0 +1,17 @@ +/datum/controller/subsystem/materials/get_armor_key(damage_type, damage_flags) + . = (damage_type == PSIONIC) ? PSIONIC : ..() + +/datum/extension/armor/psionic + expected_type = /datum/ability_handler/psionics + full_block_message = "You block the blow with your mind!" + partial_block_message = "You soften the blow with your mind!" + +/datum/extension/armor/psionic/get_value(key) + var/datum/ability_handler/psionics/psi = holder + return psi.get_armour(key) + +/datum/extension/armor/psionic/on_blocking(damage, damage_type, damage_flags, armor_pen, blocked) + var/datum/ability_handler/psionics/psi = holder + var/blocked_damage = damage * blocked + if(blocked_damage) + psi.spend_power_armor(blocked_damage) diff --git a/mods/content/psionics/datum/chems.dm b/mods/content/psionics/datum/chems.dm new file mode 100644 index 000000000000..e859f0dc5153 --- /dev/null +++ b/mods/content/psionics/datum/chems.dm @@ -0,0 +1,7 @@ +/decl/material/liquid/crystal_agent/do_material_check(var/mob/living/M) + . = !!M.get_ability_handler(/datum/ability_handler/psionics) ? /decl/material/nullglass : ..() + +/decl/material/liquid/glowsap/gleam/affect_overdose(mob/living/victim, total_dose) + ..() + var/datum/ability_handler/psionics/psi = victim.get_ability_handler(/datum/ability_handler/psionics) + psi?.check_latency_trigger(30, "a [name] overdose") diff --git a/mods/content/psionics/datum/codex.dm b/mods/content/psionics/datum/codex.dm new file mode 100644 index 000000000000..1f2bb6152766 --- /dev/null +++ b/mods/content/psionics/datum/codex.dm @@ -0,0 +1,47 @@ +/datum/codex_entry/cuchulain_foundation + name = "Cuchulain Foundation" + associated_paths = list( + /obj/item/briefcase/foundation, + /obj/item/gun/projectile/revolver/foundation, + /obj/item/card/id/foundation, + /obj/item/card/id/foundation_civilian, + /obj/item/clothing/suit/toggle/labcoat/foundation, + /obj/item/chems/drinks/glass2/coffeecup/foundation + ) + lore_text = "The Cuchulain Foundation is a non-profit body based out of Neptune orbit. Their logo is \ + an upward-facing radio telescope dish, usually printed in green. They perform niche research on behalf \ + of private parties, the government, and their own interests. They are also the single largest psionic registration \ + and oversight body in human space, responsible for educating and training operants at no cost, even across \ + territorial and political lines. \ +

    \ + The rest of the article is an indecipherable haze that slips out of your memory as soon as you \ + finish reading it, but you feel pretty satisfied and informed by the end." + antag_text = "The Cuchulain Foundation is an anti-occult ERT-like body. They are equipped with \ + nullglass weapons that can disrupt or destroy psi-powers, and have their own moderately powerful \ + psionic abilities. They make heavy use of psionic influence to cloud and disrupt efforts at \ + researching or understanding them, and the depth and nature of their connections to other major \ + bodies are unclear." + +/datum/codex_entry/psionics + name = "Psionics" + associated_strings = list("psychic powers") + associated_paths = list( + /obj/item/book/fluff/psionics, + /obj/item/clothing/head/helmet/space/psi_amp, + /obj/item/clothing/head/helmet/space/psi_amp/lesser + ) + lore_text = "Psionics are a relatively new phenomenon theorized to be linked to long-term exposure \ + to deep, uninhabited space. A tiny, tiny subset of people exposed to such conditions can develop the \ + ability to perform small feats like levitating coins or removing a headache with nothing but their mind. \ + A decade of study has resulted in scientists determining that these psionics, mild as they are, don't pose \ + an operational or health risk, but they do encourage operants to register with a psionic regulation body \ + like the Cuchulain Foundation. \ +

    \ + However, psionics-enhancing implants, drugs and procedures are illegal in most human space, and \ + statistically seem to end in death for those foolish enough to make use of them. Being caught with a \ + cerebroenergetic enhancer, or the drug Three Eye, will net you a hefty prison sentence." + mechanics_text = "Psionic operants have a brain icon on the bottom right of the HUD. They can click it to toggle \ + their powers, or examine it to see the details of how to invoke each power, as well as their mental state. Items \ + made of nullglass will stop the use of powers, and overuse of powers can cause lethal brain damage." + antag_text = "Psionic amplifiers are illegal equipment, but can boost your psionics to massive levels at the cost \ + of occupying your hat slot permanently." \ No newline at end of file diff --git a/mods/psionics/datum/jobs.dm b/mods/content/psionics/datum/jobs.dm similarity index 75% rename from mods/psionics/datum/jobs.dm rename to mods/content/psionics/datum/jobs.dm index 1674321d1040..18b2adbf9c4b 100644 --- a/mods/psionics/datum/jobs.dm +++ b/mods/content/psionics/datum/jobs.dm @@ -6,23 +6,25 @@ /datum/job/submap give_psionic_implant_on_join = FALSE -/datum/job/equip(var/mob/living/carbon/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) +/datum/job/equip_job(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade) . = ..() if(psi_latency_chance && prob(psi_latency_chance)) H.set_psi_rank(pick(PSI_COERCION, PSI_REDACTION, PSI_ENERGISTICS, PSI_PSYCHOKINESIS), 1, defer_update = TRUE) if(islist(psi_faculties)) for(var/psi in psi_faculties) H.set_psi_rank(psi, psi_faculties[psi], take_larger = TRUE, defer_update = TRUE) - if(H.psi) - H.psi.update() + + var/datum/ability_handler/psionics/psi = H.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + psi.update() if(give_psionic_implant_on_join) var/obj/item/implant/psi_control/imp = new imp.implanted(H) imp.forceMove(H) imp.imp_in = H imp.implanted = TRUE - var/obj/item/organ/external/affected = H.get_organ(BP_HEAD) + var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(H, BP_HEAD) if(affected) - affected.implants += imp + LAZYADD(affected.implants, imp) imp.part = affected to_chat(H, SPAN_DANGER("As a registered psionic, you are fitted with a psi-dampening control implant. Using psi-power while the implant is active will result in neural shocks and your violation being reported.")) diff --git a/mods/content/psionics/datum/mind.dm b/mods/content/psionics/datum/mind.dm new file mode 100644 index 000000000000..6c9d2beaded7 --- /dev/null +++ b/mods/content/psionics/datum/mind.dm @@ -0,0 +1,8 @@ +/datum/mind/Topic(href, href_list) + . = ..() + if(!. && check_rights(R_ADMIN, FALSE) && current && isliving(current) && href_list["set_psi_faculty"] && href_list["set_psi_faculty_rank"]) + current.set_psi_rank(href_list["set_psi_faculty"], text2num(href_list["set_psi_faculty_rank"])) + log_and_message_admins("set [key_name(current)]'s [href_list["set_psi_faculty"]] faculty to [text2num(href_list["set_psi_faculty_rank"])].") + var/datum/admins/admin = global.admins[usr.key] + if(istype(admin)) admin.show_player_panel(current) + return TRUE diff --git a/mods/psionics/datum/security_state.dm b/mods/content/psionics/datum/security_state.dm similarity index 100% rename from mods/psionics/datum/security_state.dm rename to mods/content/psionics/datum/security_state.dm diff --git a/mods/content/psionics/datum/surgery.dm b/mods/content/psionics/datum/surgery.dm new file mode 100644 index 000000000000..e1778226cde9 --- /dev/null +++ b/mods/content/psionics/datum/surgery.dm @@ -0,0 +1,8 @@ +/decl/surgery_step/robotics/repair_brute/Initialize() + allowed_tools[/obj/item/ability/psionic/psiblade/master] = 100 + . = ..() + +/decl/surgery_step/hardsuit/Initialize() + allowed_tools[/obj/item/ability/psionic/psiblade/master/grand/paramount] = 100 + allowed_tools[/obj/item/ability/psionic/psiblade] = 75 + . = ..() diff --git a/mods/psionics/datum/uplink.dm b/mods/content/psionics/datum/uplink.dm similarity index 100% rename from mods/psionics/datum/uplink.dm rename to mods/content/psionics/datum/uplink.dm diff --git a/mods/content/psionics/icons/briefcase_foundation.dmi b/mods/content/psionics/icons/briefcase_foundation.dmi new file mode 100644 index 000000000000..22ebac9c7e1c Binary files /dev/null and b/mods/content/psionics/icons/briefcase_foundation.dmi differ diff --git a/mods/psionics/icons/foundation.dmi b/mods/content/psionics/icons/foundation.dmi similarity index 100% rename from mods/psionics/icons/foundation.dmi rename to mods/content/psionics/icons/foundation.dmi diff --git a/mods/psionics/icons/foundation_labcoat.dmi b/mods/content/psionics/icons/foundation_labcoat.dmi similarity index 83% rename from mods/psionics/icons/foundation_labcoat.dmi rename to mods/content/psionics/icons/foundation_labcoat.dmi index 94f095fc7105..c18110f1f3bb 100644 Binary files a/mods/psionics/icons/foundation_labcoat.dmi and b/mods/content/psionics/icons/foundation_labcoat.dmi differ diff --git a/mods/psionics/icons/psi.dmi b/mods/content/psionics/icons/psi.dmi similarity index 100% rename from mods/psionics/icons/psi.dmi rename to mods/content/psionics/icons/psi.dmi diff --git a/mods/psionics/icons/psi_aura_small.dmi b/mods/content/psionics/icons/psi_aura_small.dmi similarity index 100% rename from mods/psionics/icons/psi_aura_small.dmi rename to mods/content/psionics/icons/psi_aura_small.dmi diff --git a/mods/psionics/icons/psimeter.dmi b/mods/content/psionics/icons/psimeter.dmi similarity index 100% rename from mods/psionics/icons/psimeter.dmi rename to mods/content/psionics/icons/psimeter.dmi diff --git a/mods/psionics/icons/psychic_powers.dmi b/mods/content/psionics/icons/psychic_powers.dmi similarity index 100% rename from mods/psionics/icons/psychic_powers.dmi rename to mods/content/psionics/icons/psychic_powers.dmi diff --git a/mods/content/psionics/icons/psychonetics.dmi b/mods/content/psionics/icons/psychonetics.dmi new file mode 100644 index 000000000000..eb73476a85b1 Binary files /dev/null and b/mods/content/psionics/icons/psychonetics.dmi differ diff --git a/mods/content/psionics/items/_items.dm b/mods/content/psionics/items/_items.dm new file mode 100644 index 000000000000..35a5b71ea9c2 --- /dev/null +++ b/mods/content/psionics/items/_items.dm @@ -0,0 +1,9 @@ +/obj/item/disrupts_psionics() + . = (material && material.is_psi_null()) ? src : FALSE + +/obj/item/withstand_psi_stress(var/stress, var/atom/source) + . = ..(stress, source) + if(current_health >= 0 && . > 0 && disrupts_psionics()) + current_health -= . + . = max(0, -(current_health)) + check_health(consumed = TRUE) diff --git a/mods/content/psionics/items/brain.dm b/mods/content/psionics/items/brain.dm new file mode 100644 index 000000000000..181774f76d16 --- /dev/null +++ b/mods/content/psionics/items/brain.dm @@ -0,0 +1,4 @@ +/obj/item/organ/internal/brain/handle_severe_damage() + . = ..() + var/datum/ability_handler/psionics/psi = owner?.get_ability_handler(/datum/ability_handler/psionics) + psi?.check_latency_trigger(20, "physical trauma") \ No newline at end of file diff --git a/mods/psionics/items/cerebro_enhancers.dm b/mods/content/psionics/items/cerebro_enhancers.dm similarity index 83% rename from mods/psionics/items/cerebro_enhancers.dm rename to mods/content/psionics/items/cerebro_enhancers.dm index 3441ec2d0f23..f58cc158b38e 100644 --- a/mods/psionics/items/cerebro_enhancers.dm +++ b/mods/content/psionics/items/cerebro_enhancers.dm @@ -5,11 +5,6 @@ action_button_name = "Install Boosters" icon_state = ICON_STATE_WORLD icon = 'icons/clothing/head/cerebro.dmi' - item_state_slots = list( - slot_l_hand_str = "helmet", - slot_r_hand_str = "helmet" - ) - var/operating = FALSE var/list/boosted_faculties var/boosted_rank = PSI_RANK_PARAMOUNT @@ -43,8 +38,8 @@ deintegrate() return - var/mob/living/carbon/human/H = loc - if(istype(H) && H.head == src) + var/mob/living/human/H = loc + if(istype(H) && H.get_equipped_item(slot_head_str) == src) integrate() return @@ -81,21 +76,21 @@ if(canremove) return - var/mob/living/carbon/human/H = loc - if(!istype(H) || H.head != src) + var/mob/living/human/H = loc + if(!istype(H) || H.get_equipped_item(slot_head_str) != src) canremove = TRUE return - to_chat(H, SPAN_WARNING("You feel a strange tugging sensation as \the [src] begins removing the slave-minds from your brain...")) + to_chat(H, SPAN_WARNING("You feel a strange tugging sensation as \the [src] begins removing the subpersonas from your brain...")) playsound(H, 'sound/weapons/circsawhit.ogg', 50, 1, -1) operating = TRUE sleep(80) - if(H.psi) - H.psi.reset() + var/datum/ability_handler/psionics/psi = H.get_ability_handler(/datum/ability_handler/psionics) + psi?.reset() - to_chat(H, SPAN_NOTICE("\The [src] chimes quietly as it finishes removing the slave-minds from your brain.")) + to_chat(H, SPAN_NOTICE("\The [src] chimes quietly as it finishes removing the subpersonas from your brain.")) canremove = TRUE operating = FALSE @@ -112,11 +107,12 @@ var/lastloc = loc . = ..() if(.) - var/mob/living/carbon/human/H = lastloc - if(istype(H) && H.psi) - H.psi.reset() + var/mob/living/human/H = lastloc + if(istype(H)) + var/datum/ability_handler/psionics/psi = H.get_ability_handler(/datum/ability_handler/psionics) + psi?.reset() H = loc - if(!istype(H) || H.head != src) + if(!istype(H) || H.get_equipped_item(slot_head_str) != src) canremove = TRUE /obj/item/clothing/head/helmet/space/psi_amp/proc/integrate() @@ -136,8 +132,8 @@ to_chat(usr, SPAN_NOTICE("You still have [max_boosted_faculties - LAZYLEN(boosted_faculties)] facult[LAZYLEN(boosted_faculties) == 1 ? "y" : "ies"] to select. Use \the [src] in-hand to select them.")) return - var/mob/living/carbon/human/H = loc - if(!istype(H) || H.head != src) + var/mob/living/human/H = loc + if(!istype(H) || H.get_equipped_item(slot_head_str) != src) to_chat(usr, SPAN_WARNING("\The [src] must be worn on your head in order to be activated.")) return @@ -153,10 +149,11 @@ H.set_psi_rank(faculty, boosted_rank, take_larger = TRUE, temporary = TRUE) else H.set_psi_rank(faculty, unboosted_rank, take_larger = TRUE, temporary = TRUE) - if(H.psi) - H.psi.max_stamina = boosted_psipower - H.psi.stamina = H.psi.max_stamina - H.psi.update(force = TRUE) + var/datum/ability_handler/psionics/psi = H.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + psi.max_stamina = boosted_psipower + psi.stamina = psi.max_stamina + psi.update(force = TRUE) to_chat(H, SPAN_NOTICE("You experience a brief but powerful wave of deja vu as \the [src] finishes modifying your brain.")) verbs |= /obj/item/clothing/head/helmet/space/psi_amp/proc/deintegrate @@ -165,4 +162,4 @@ action_button_name = "Remove Psionic Amplifier" H.update_action_buttons() - set_light(0.5, 0.1, 3, 2, l_color = "#880000") + set_light(3, 0.5, "#880000") diff --git a/mods/content/psionics/items/clothing.dm b/mods/content/psionics/items/clothing.dm new file mode 100644 index 000000000000..32e5786c2440 --- /dev/null +++ b/mods/content/psionics/items/clothing.dm @@ -0,0 +1,16 @@ +/obj/item/clothing/suit/paramount + name = "purple robes" + desc = "Heavy, royal purple robes threaded with psychic amplifiers and weird, bulbous lenses. Do not machine wash." + icon = 'icons/clothing/suits/wizard/psy.dmi' + gender = PLURAL + permeability_coefficient = 0.01 + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, + ARMOR_LASER = ARMOR_LASER_SMALL, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_MINOR, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + siemens_coefficient = 0.8 \ No newline at end of file diff --git a/mods/content/psionics/items/coffee_cup.dm b/mods/content/psionics/items/coffee_cup.dm new file mode 100644 index 000000000000..86af6b5049ed --- /dev/null +++ b/mods/content/psionics/items/coffee_cup.dm @@ -0,0 +1,6 @@ +/obj/item/chems/drinks/glass2/coffeecup/foundation + name = "\improper Foundation coffee cup" + desc = "A white coffee cup with the Cuchulain Foundation logo stencilled onto it." + base_icon = "coffeecup_foundation" + icon_state = "coffeecup_foundation" + base_name = "\improper Foundation cup" \ No newline at end of file diff --git a/mods/content/psionics/items/foundation_implanter.dm b/mods/content/psionics/items/foundation_implanter.dm new file mode 100644 index 000000000000..4fdbc478749f --- /dev/null +++ b/mods/content/psionics/items/foundation_implanter.dm @@ -0,0 +1,18 @@ +/obj/item/implanter/psi + name = "psi-null implanter" + desc = "An implant gun customized to interact with psi dampeners." + +/obj/item/implanter/psi/attack_self(var/mob/user) + var/choice = input("Select a new implant mode.", "Psi Dampener") as null|anything in list(PSI_IMPLANT_AUTOMATIC, PSI_IMPLANT_SHOCK, PSI_IMPLANT_WARN, PSI_IMPLANT_LOG, PSI_IMPLANT_DISABLED) + if(!choice || user != loc) + return + var/obj/item/implant/psi_control/implant = imp + if(!istype(implant)) + to_chat(user, SPAN_WARNING("The implanter reports there is no compatible implant loaded.")) + return + implant.psi_mode = choice + to_chat(user, SPAN_NOTICE("You set \the [src] to configure implants with the '[implant.psi_mode]' setting.")) + +/obj/item/implanter/psi/Initialize() + . = ..() + imp = new /obj/item/implant/psi_control(src) diff --git a/mods/content/psionics/items/foundation_labcoat.dm b/mods/content/psionics/items/foundation_labcoat.dm new file mode 100644 index 000000000000..c4d1772566cc --- /dev/null +++ b/mods/content/psionics/items/foundation_labcoat.dm @@ -0,0 +1,6 @@ + +/obj/item/clothing/suit/toggle/labcoat/foundation + name = "\improper Foundation labcoat" + desc = "A medical labcoat with a Cuchulain Foundation crest stencilled on the back." + icon = 'mods/content/psionics/icons/foundation_labcoat.dmi' + markings_state_modifier = null diff --git a/mods/content/psionics/items/foundation_weapon.dm b/mods/content/psionics/items/foundation_weapon.dm new file mode 100644 index 000000000000..51934f97b7ed --- /dev/null +++ b/mods/content/psionics/items/foundation_weapon.dm @@ -0,0 +1,28 @@ +/obj/item/gun/projectile/revolver/foundation + name = "\improper Foundation revolver" + icon = 'mods/content/psionics/icons/foundation.dmi' + icon_state = "foundation" + desc = "The CF 'Troubleshooter', a compact plastic-composite weapon designed for concealed carry by Cuchulain Foundation field agents. Smells faintly of copper." + ammo_type = /obj/item/ammo_casing/pistol/magnum/nullglass + +/obj/item/gun/projectile/revolver/foundation/disrupts_psionics() + return FALSE + +/obj/item/briefcase/foundation + name = "\improper Foundation briefcase" + desc = "A handsome black leather briefcase embossed with a stylized radio telescope." + icon = 'mods/content/psionics/icons/briefcase_foundation.dmi' + +/obj/item/briefcase/foundation/disrupts_psionics() + return FALSE + +/obj/item/briefcase/foundation/WillContain() + return list( + /obj/item/ammo_magazine/speedloader/nullglass, + /obj/item/gun/projectile/revolver/foundation, + ) + +/obj/item/briefcase/foundation/Initialize(ml, material_key) + . = ..() + if(length(contents) && storage) + storage.make_exact_fit() diff --git a/mods/content/psionics/items/id_card.dm b/mods/content/psionics/items/id_card.dm new file mode 100644 index 000000000000..521e1d2be180 --- /dev/null +++ b/mods/content/psionics/items/id_card.dm @@ -0,0 +1,46 @@ +/obj/item/card/id/foundation_civilian + name = "operant registration card" + desc = "A registration card in a faux-leather case. It marks the named individual as a registered, law-abiding psionic." + icon = 'icons/obj/id/id_warrantcard_civ.dmi' + detail_color = null + +/obj/item/card/id/foundation_civilian/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/card/id/foundation + name = "\improper Foundation warrant card" + desc = "A warrant card in a handsome leather case." + assignment = "Field Agent" + icon = 'icons/obj/id/id_warrantcard.dmi' + detail_color = null + +/obj/item/card/id/foundation/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(distance <= 1 && isliving(user)) + var/datum/ability_handler/psionics/psi = user.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + . += SPAN_WARNING("There is a psionic compulsion surrounding \the [src], forcing anyone who reads it to perceive it as a legitimate document of authority. The actual text just reads 'I can do what I want.'") + else + . += SPAN_NOTICE("This is the real deal, stamped by [global.using_map.boss_name]. It gives the holder the full authority to pursue their goals. You believe it implicitly.") + +/obj/item/card/id/foundation/attack_self(var/mob/user) + . = ..() + if(isliving(user)) + var/datum/ability_handler/psionics/psi = user.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + for(var/mob/M in viewers(world.view, get_turf(user))-user) + if(isliving(M)) + var/datum/ability_handler/psionics/other_psi = M.get_ability_handler(/datum/ability_handler/psionics) + if(!other_psi) + to_chat(M, SPAN_NOTICE("This is the real deal, stamped by [global.using_map.boss_name]. It gives the holder the full authority to pursue their goals. You believe \the [user] implicitly.")) + continue + to_chat(M, SPAN_WARNING("There is a psionic compulsion surrounding \the [src] in a flicker of indescribable light.")) + +/obj/item/card/id/foundation/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/card/id/foundation/Initialize() + . = ..() + access |= get_all_station_access() diff --git a/mods/content/psionics/items/implant.dm b/mods/content/psionics/items/implant.dm new file mode 100644 index 000000000000..e4a7bece611d --- /dev/null +++ b/mods/content/psionics/items/implant.dm @@ -0,0 +1,110 @@ +/obj/item/implant/psi_control + name = "psi dampener implant" + desc = "A safety implant for registered psi-operants." + known = TRUE + + var/overload = 0 + var/max_overload = 100 + var/psi_mode = PSI_IMPLANT_AUTOMATIC + +/obj/item/implant/psi_control/islegal() + return TRUE + +/obj/item/implant/psi_control/Initialize() + . = ..() + SSpsi.psi_dampeners += src + +/obj/item/implant/psi_control/Destroy() + SSpsi.psi_dampeners -= src + . = ..() + +/obj/item/implant/psi_control/emp_act() + . = ..() + update_functionality() + +/obj/item/implant/psi_control/meltdown() + . = ..() + update_functionality() + +/obj/item/implant/psi_control/disrupts_psionics() + var/use_psi_mode = get_psi_mode() + return (!malfunction && (use_psi_mode == PSI_IMPLANT_SHOCK || use_psi_mode == PSI_IMPLANT_WARN)) ? src : FALSE + +/obj/item/implant/psi_control/removed() + var/mob/living/M = imp_in + if(disrupts_psionics() && istype(M) && M.get_ability_handler(/datum/ability_handler/psionics)) + to_chat(M, SPAN_NOTICE("You feel the chilly shackles around your psionic faculties fade away.")) + . = ..() + +/obj/item/implant/psi_control/proc/update_functionality(var/silent) + var/mob/living/M = imp_in + if(get_psi_mode() == PSI_IMPLANT_DISABLED || malfunction) + if(implanted && !silent && istype(M) && M.get_ability_handler(/datum/ability_handler/psionics)) + to_chat(M, SPAN_NOTICE("You feel the chilly shackles around your psionic faculties fade away.")) + else + if(implanted && !silent && istype(M) && M.get_ability_handler(/datum/ability_handler/psionics)) + to_chat(M, SPAN_NOTICE("Bands of hollow ice close themselves around your psionic faculties.")) + +/obj/item/implant/psi_control/meltdown() + if(!malfunction) + overload = max_overload + if(imp_in) + for(var/thing in SSpsi.psi_monitors) + var/obj/machinery/psi_monitor/monitor = thing + monitor.report_failure(src) + . = ..() + +/obj/item/implant/psi_control/proc/get_psi_mode() + if(psi_mode == PSI_IMPLANT_AUTOMATIC) + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + return security_state.current_security_level.psionic_control_level + return psi_mode + +/obj/item/implant/psi_control/withstand_psi_stress(var/stress, var/atom/source) + + var/use_psi_mode = get_psi_mode() + + if(malfunction || use_psi_mode == PSI_IMPLANT_DISABLED) + return stress + + . = 0 + + if(stress > 0) + + // If we're disrupting psionic attempts at the moment, we might overload. + if(disrupts_psionics()) + var/overload_amount = floor(stress/10) + if(overload_amount > 0) + overload += overload_amount + if(overload >= max_overload) + if(imp_in) + to_chat(imp_in, SPAN_DANGER("Your psi dampener overloads violently!")) + meltdown() + update_functionality() + return + if(imp_in) + switch(overload / max_overload) + if(0.25 to 0.5) + to_chat(imp_in, SPAN_WARNING("You feel your psi dampener heating up...")) + if(0.5 to 0.75) + to_chat(imp_in, SPAN_WARNING("Your psi dampener is uncomfortably hot...")) + if(0.75 to 1) + to_chat(imp_in, SPAN_DANGER("Your psi dampener is searing hot!")) + + // If all we're doing is logging the incident then just pass back stress without changing it. + if(source && source == imp_in && implanted) + for(var/thing in SSpsi.psi_monitors) + var/obj/machinery/psi_monitor/monitor = thing + monitor.report_violation(src, stress) + if(use_psi_mode == PSI_IMPLANT_LOG) + return stress + else if(use_psi_mode == PSI_IMPLANT_SHOCK) + to_chat(imp_in, SPAN_DANGER("Your psi dampener punishes you with a violent neural shock!")) + imp_in.flash_eyes() + SET_STATUS_MAX(imp_in, STAT_WEAK, 5) + if(isliving(imp_in)) + var/mob/living/M = imp_in + var/datum/ability_handler/psionics/psi = M.get_ability_handler(/datum/ability_handler/psionics) + psi?.stunned(5) + else if(use_psi_mode == PSI_IMPLANT_WARN) + to_chat(imp_in, SPAN_WARNING("Your psi dampener primly informs you it has reported this violation.")) diff --git a/mods/content/psionics/items/literature.dm b/mods/content/psionics/items/literature.dm new file mode 100644 index 000000000000..5a9ba61bca03 --- /dev/null +++ b/mods/content/psionics/items/literature.dm @@ -0,0 +1,11 @@ +/obj/item/book/fluff/psionics + name = "Psychonetics" + icon = 'mods/content/psionics/icons/psychonetics.dmi' + author = "John Titor" + title = "Psychonetics" + fluff_text = {" +

    Psychonetics

    +

    This seems to be a dry, longwinded reference text for the form of strange mental powers called psionics. The author spends way too much time trying to advertise his cult, though.

    +

    The general gist of things seems to be that sometime in the last decade or so, the first cases of 'spontaneous operancy' became known. People who spent a lot of time in deep space, or who studied certain esoteric fields of mathematics, became able to perform strange feats like levitating coins or removing headaches with nothing but their minds. The text goes on to explain that psionics are perfectly harmless, and that studies (no citations) have shown operants are no more likely to go mad and murder people than anyone else.

    +

    A postscript by a group called the Cuchulain Foundation invites anyone who knows an operant, or thinks they might be one, to send them a message via comms and get enrolled in their training and registration program in orbit around Neptune. It's catered. The postscript adds hastily that you should never try to activate your own latencies with trauma or drugs, as the results are often lethal.

    + "} diff --git a/mods/psionics/items/null_ammo.dm b/mods/content/psionics/items/null_ammo.dm similarity index 100% rename from mods/psionics/items/null_ammo.dm rename to mods/content/psionics/items/null_ammo.dm diff --git a/mods/psionics/items/nullrod.dm b/mods/content/psionics/items/nullrod.dm similarity index 100% rename from mods/psionics/items/nullrod.dm rename to mods/content/psionics/items/nullrod.dm diff --git a/mods/content/psionics/machines/psimeter.dm b/mods/content/psionics/machines/psimeter.dm new file mode 100644 index 000000000000..8266066e7e13 --- /dev/null +++ b/mods/content/psionics/machines/psimeter.dm @@ -0,0 +1,63 @@ +/obj/machinery/psi_meter + name = "psi-meter" + desc = "A bulky psi-meter for conducting assays of psi-operants." + icon = 'mods/content/psionics/icons/psimeter.dmi' + icon_state = "meter_on" + use_power = POWER_USE_ACTIVE + anchored = TRUE + density = TRUE + opacity = FALSE + + var/list/last_assay + var/mob/living/last_assayed + +/obj/machinery/psi_meter/on_update_icon() + if(use_power && !(stat & (NOPOWER|BROKEN))) + icon_state = "meter_on" + else + icon_state = "meter_off" + +/obj/machinery/psi_meter/interface_interact(var/mob/user) + interact(user) + return TRUE + +/obj/machinery/psi_meter/interact(var/mob/user) + + if(!use_power) return + + var/list/dat = list() + if(LAZYLEN(last_assay)) + dat = last_assay + else + dat += "

    TELESTO Mark I Psi-Meter


    " + var/found + for(var/mob/living/subject in range(1, src)) + found = TRUE + dat += "" + dat += "
    Candidates
    [subject.name]Conduct Assay" + if(!found) + dat += "
    No candidates found.
    " + + var/datum/browser/written_digital/popup = new(user, "psi_assay_\ref[src]", "Psi-Assay") + popup.set_content(jointext(dat,null)) + popup.open() + +/obj/machinery/psi_meter/OnTopic(mob/user, href_list) + . = ..() + if(.) + return + if(href_list["print"]) + if(last_assay) + var/obj/item/paper/P = new(loc) + P.name = "paper - Psi-Assay ([last_assayed.name])" + P.info = jointext(last_assay - last_assay[last_assay.len],null) // Last line is 'print | clear' link line. + return TOPIC_HANDLED + if(href_list["clear"]) + last_assay = null + return TOPIC_REFRESH + else if(href_list["assay"]) + last_assayed = locate(href_list["assay"]) + if(istype(last_assayed)) + last_assayed.show_psi_assay(usr, src) + return TOPIC_REFRESH + return TOPIC_NOACTION \ No newline at end of file diff --git a/mods/content/psionics/machines/psimonitor.dm b/mods/content/psionics/machines/psimonitor.dm new file mode 100644 index 000000000000..31855efdb533 --- /dev/null +++ b/mods/content/psionics/machines/psimonitor.dm @@ -0,0 +1,119 @@ +/obj/machinery/psi_monitor + name = "psionic implant monitor" + icon = 'mods/content/psionics/icons/psimeter.dmi' + icon_state = "meter_on" + use_power = POWER_USE_ACTIVE + anchored = TRUE + density = TRUE + opacity = FALSE + initial_access = list(list(access_psychiatrist, access_captain, access_cmo, access_hos)) + + var/list/psi_violations = list() + var/show_violations = FALSE + var/authorized + +/obj/machinery/psi_monitor/Initialize() + . = ..() + SSpsi.psi_monitors += src + +/obj/machinery/psi_monitor/Destroy() + SSpsi.psi_monitors -= src + return ..() + +/obj/machinery/psi_monitor/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = TRUE + remaining_charges-- + req_access.Cut() + to_chat(user, SPAN_NOTICE("You short out the access protocols.")) + return TRUE + return FALSE + +/obj/machinery/psi_monitor/OnTopic(mob/user, href_list) + . = ..() + if(.) + return + + if(href_list["login"]) + var/obj/item/card/id/ID = user.GetIdCard() + if(!ID || !allowed(user)) + to_chat(user, SPAN_WARNING("Access denied.")) + return TOPIC_HANDLED + else + authorized = "[ID.registered_name] ([ID.assignment])" + return TOPIC_REFRESH + + else if(href_list["logout"]) + authorized = FALSE + return TOPIC_REFRESH + + else if(href_list["show_violations"]) + show_violations = (href_list["show_violations"] == "1") + return TOPIC_REFRESH + + else if(href_list["remove_violation"]) + var/remove_ind = text2num(href_list["remove_violation"]) + if(remove_ind > 0 && remove_ind <= psi_violations.len) + psi_violations.Cut(remove_ind, remove_ind++) + return TOPIC_REFRESH + + else if(href_list["change_mode"]) + var/obj/item/implant/psi_control/implant = locate(href_list["change_mode"]) + if(implant.imp_in && !implant.malfunction) + var/choice = input("Select a new implant mode.", "Psi Dampener") as null|anything in list(PSI_IMPLANT_AUTOMATIC, PSI_IMPLANT_SHOCK, PSI_IMPLANT_WARN, PSI_IMPLANT_LOG, PSI_IMPLANT_DISABLED) + if(choice && implant && implant.imp_in && !implant.malfunction) + implant.psi_mode = choice + implant.update_functionality() + return TOPIC_REFRESH + return TOPIC_HANDLED + return TOPIC_NOACTION + +/obj/machinery/psi_monitor/interface_interact(var/mob/user) + interact(user) + return TRUE + +/obj/machinery/psi_monitor/interact(var/mob/user) + + var/list/dat = list() + dat += "

    Psi Dampener Monitor

    " + if(authorized) + dat += "[authorized]Logout" + else + dat += "Login" + + dat += "

    Active Psionic Dampeners


    " + dat += "
    " + dat += "" + for(var/thing in SSpsi.psi_dampeners) + var/obj/item/implant/psi_control/implant = thing + if(!implant.imp_in) + continue + dat += "" + if(implant.malfunction) + dat += "" + else + dat += "" + dat += "" + dat += "
    OperantSystem loadMode
    [implant.imp_in.name]ERRORERROR[implant.overload]%[authorized ? "[implant.psi_mode]" : "[implant.psi_mode]"]

    " + + if(show_violations) + dat += "

    Psionic Control Violations -


    " + if(psi_violations.len) + for(var/i = 1 to psi_violations.len) + var/entry = psi_violations[i] + dat += "" + else + dat += "" + dat += "

    [entry]
    [authorized ? "Remove" : ""]
    None reported.

    " + else + dat += "

    Psionic Control Violations +


    " + + var/datum/browser/written_digital/popup = new(user, "psi_monitor_\ref[src]", "Psi-Monitor") + popup.set_content(jointext(dat,null)) + popup.open() + +/obj/machinery/psi_monitor/proc/report_failure(var/obj/item/implant/psi_control/implant) + psi_violations += "Critical system failure - [implant.imp_in.name]." + +/obj/machinery/psi_monitor/proc/report_violation(var/obj/item/implant/psi_control/implant, var/stress) + psi_violations += "Sigma [round(stress/10)] event - [implant.imp_in.name]." \ No newline at end of file diff --git a/mods/psionics/system/psionics/complexus/complexus.dm b/mods/content/psionics/system/psionics/complexus/complexus.dm similarity index 77% rename from mods/psionics/system/psionics/complexus/complexus.dm rename to mods/content/psionics/system/psionics/complexus/complexus.dm index 843e82de1590..b839c057513a 100644 --- a/mods/psionics/system/psionics/complexus/complexus.dm +++ b/mods/content/psionics/system/psionics/complexus/complexus.dm @@ -1,4 +1,5 @@ -/datum/psi_complexus +/datum/ability_handler/psionics + category_toggle_type = null // we don't use this at the moment, but maybe should eventually. var/announced = FALSE // Whether or not we have been announced to our holder yet. var/suppressed = TRUE // Whether or not we are suppressing our psi powers. @@ -11,13 +12,13 @@ var/next_power_use = 0 // world.time minimum before next power use. var/stamina = 50 // Current psi pool. var/max_stamina = 50 // Max psi pool. + var/armor_cost = 0 // Amount of power to substract this tick from psi armor blocking damage. var/list/latencies // List of all currently latent faculties. var/list/ranks // Assoc list of psi faculties to current rank. var/list/base_ranks // Assoc list of psi faculties to base rank, in case reset is needed - var/list/manifested_items // List of atoms manifested/maintained by psychic power. + var/next_latency_trigger = 0 // world.time minimum before a trigger can be attempted again. - var/last_armor_check // world.time of last armour check. var/last_aura_size var/last_aura_alpha var/last_aura_color @@ -31,10 +32,9 @@ var/list/powers_by_faculty // All powers within a given faculty. var/obj/screen/psi/hub/ui // Reference to the master psi UI object. - var/mob/living/owner // Reference to our owner. var/image/_aura_image // Client image -/datum/psi_complexus/proc/get_aura_image() +/datum/ability_handler/psionics/proc/get_aura_image() if(_aura_image && !istype(_aura_image)) var/atom/A = _aura_image log_debug("Non-image found in psi complexus: \ref[A] - \the [A] - [istype(A) ? A.type : "non-atom"]") @@ -45,17 +45,17 @@ return _aura_image /proc/create_aura_image(var/newloc) - var/image/aura_image = image(loc = newloc, icon = 'mods/psionics/icons/psi_aura_small.dmi', icon_state = "aura") + var/image/aura_image = image(loc = newloc, icon = 'mods/content/psionics/icons/psi_aura_small.dmi', icon_state = "aura") aura_image.blend_mode = BLEND_MULTIPLY aura_image.appearance_flags = NO_CLIENT_COLOR | RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM aura_image.layer = TURF_LAYER + 0.5 aura_image.alpha = 0 aura_image.pixel_x = -64 aura_image.pixel_y = -64 - aura_image.mouse_opacity = 0 + aura_image.mouse_opacity = MOUSE_OPACITY_UNCLICKABLE aura_image.appearance_flags = 0 for(var/thing in SSpsi.processing) - var/datum/psi_complexus/psychic = thing + var/datum/ability_handler/psionics/psychic = thing if(psychic.owner.client && !psychic.suppressed) psychic.owner.client.images += aura_image SSpsi.all_aura_images[aura_image] = TRUE @@ -63,31 +63,27 @@ /proc/destroy_aura_image(var/image/aura_image) for(var/thing in SSpsi.processing) - var/datum/psi_complexus/psychic = thing + var/datum/ability_handler/psionics/psychic = thing if(psychic.owner.client) psychic.owner.client.images -= aura_image SSpsi.all_aura_images -= aura_image -/datum/psi_complexus/New(var/mob/_owner) - owner = _owner - START_PROCESSING(SSpsi, src) - set_extension(src, /datum/extension/armor/psionic) +/datum/ability_handler/psionics/New(_master) + ..() + if(istype(master) && istype(owner)) + START_PROCESSING(SSpsi, src) + set_extension(src, /datum/extension/armor/psionic) -/datum/psi_complexus/Destroy() +/datum/ability_handler/psionics/Destroy() destroy_aura_image(_aura_image) STOP_PROCESSING(SSpsi, src) if(owner) cancel() if(owner.client) - owner.client.screen -= list(ui, ui.components) + if(ui) + owner.client.screen -= list(ui, ui.components) for(var/thing in SSpsi.all_aura_images) owner.client.images -= thing QDEL_NULL(ui) - owner.psi = null - owner = null - if(manifested_items) - for(var/thing in manifested_items) - qdel(thing) - manifested_items.Cut() . = ..() diff --git a/mods/content/psionics/system/psionics/complexus/complexus_helpers.dm b/mods/content/psionics/system/psionics/complexus/complexus_helpers.dm new file mode 100644 index 000000000000..1ae917174555 --- /dev/null +++ b/mods/content/psionics/system/psionics/complexus/complexus_helpers.dm @@ -0,0 +1,103 @@ +/datum/ability_handler/psionics/cancel() + sound_to(owner, sound('sound/effects/psi/power_fail.ogg')) + return ..() + +/datum/ability_handler/psionics/proc/stunned(var/amount) + var/old_stun = stun + stun = max(stun, amount) + if(amount && !old_stun) + to_chat(owner, "Your concentration has been shattered! You cannot focus your psi power!") + ui.update_icon() + cancel() + +/datum/ability_handler/psionics/proc/get_armour(var/armourtype) + if(use_psi_armour && can_use_passive()) + return round(clamp(clamp(4 * rating, 0, 20) * get_rank(SSpsi.armour_faculty_by_type[armourtype]), 0, 100) * (stamina/max_stamina)) + else + return 0 + +/datum/ability_handler/psionics/proc/get_rank(var/faculty) + return LAZYACCESS(ranks, faculty) + +/datum/ability_handler/psionics/proc/set_rank(var/faculty, var/rank, var/defer_update, var/temporary) + if(get_rank(faculty) != rank) + LAZYSET(ranks, faculty, rank) + if(!temporary) + LAZYSET(base_ranks, faculty, rank) + if(!defer_update) + update() + +/datum/ability_handler/psionics/proc/set_cooldown(var/value) + next_power_use = world.time + value + ui.update_icon() + +/datum/ability_handler/psionics/proc/can_use_passive() + return (owner.stat == CONSCIOUS && !suppressed && !stun) + +/datum/ability_handler/psionics/proc/can_use(var/incapacitation_flags) + return (owner.stat == CONSCIOUS && (!incapacitation_flags || !owner.incapacitated(incapacitation_flags)) && !suppressed && !stun && world.time >= next_power_use) + +/datum/ability_handler/psionics/proc/spend_power(var/value = 0, var/check_incapacitated, var/backblast_on_failure = TRUE) + . = FALSE + if(isnull(check_incapacitated)) + check_incapacitated = (INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT) + if(can_use(check_incapacitated)) + value = max(1, ceil(value * cost_modifier)) + if(value <= stamina) + stamina -= value + ui.update_icon() + . = TRUE + else + if(backblast_on_failure) + backblast(abs(stamina - value)) + stamina = 0 + . = FALSE + ui.update_icon() + +/datum/ability_handler/psionics/proc/spend_power_armor(var/value = 0) + armor_cost += value + +/datum/ability_handler/psionics/proc/hide_auras() + if(owner.client) + for(var/thing in SSpsi.all_aura_images) + owner.client.images -= thing + +/datum/ability_handler/psionics/proc/show_auras() + if(owner.client) + for(var/image/I in SSpsi.all_aura_images) + owner.client.images |= I + +/datum/ability_handler/psionics/proc/backblast(var/value) + + // Can't backblast if you're controlling your power. + if(!owner || suppressed) + return FALSE + + sound_to(owner, sound('sound/effects/psi/power_feedback.ogg')) + to_chat(owner, "Wild energistic feedback blasts across your psyche!") + stunned(value * 2) + set_cooldown(value * 100) + + if(prob(value*10)) + owner.emote(/decl/emote/audible/scream) + + // Your head asplode. + owner.take_damage(value, BRAIN) + if(ishuman(owner)) + var/mob/living/human/pop = owner + if(pop.should_have_organ(BP_BRAIN)) + var/obj/item/organ/internal/sponge = GET_INTERNAL_ORGAN(pop, BP_BRAIN) + if(sponge && sponge.get_organ_damage() >= sponge.max_damage) + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(pop, sponge.parent_organ) + if(affecting) + affecting.dismember(0, DISMEMBER_METHOD_BLUNT) + if(sponge) + qdel(sponge) + +/datum/ability_handler/psionics/proc/reset() + aura_color = initial(aura_color) + ranks = base_ranks ? base_ranks.Copy() : null + max_stamina = initial(max_stamina) + stamina = min(stamina, max_stamina) + cancel() + update() diff --git a/mods/content/psionics/system/psionics/complexus/complexus_latency.dm b/mods/content/psionics/system/psionics/complexus/complexus_latency.dm new file mode 100644 index 000000000000..2a334334374a --- /dev/null +++ b/mods/content/psionics/system/psionics/complexus/complexus_latency.dm @@ -0,0 +1,19 @@ +/datum/ability_handler/psionics/proc/check_latency_trigger(var/trigger_strength = 0, var/source, var/redactive = FALSE) + + if(!LAZYLEN(latencies) || world.time < next_latency_trigger) + return FALSE + + if(!prob(trigger_strength)) + next_latency_trigger = world.time + rand(100, 300) + return FALSE + + var/faculty = pick(latencies) + LAZYREMOVE(latencies, faculty) + var/new_rank = rand(2,5) + owner.set_psi_rank(faculty, new_rank) + var/decl/psionic_faculty/faculty_decl = SSpsi.get_faculty(faculty) + to_chat(owner, SPAN_DANGER("You scream internally as your [faculty_decl.name] faculty is forced into operancy by [source]!")) + next_latency_trigger = world.time + rand(600, 1800) * new_rank + if(!redactive) + owner.take_damage(rand(trigger_strength * 2, trigger_strength * 4), BRAIN) + return TRUE diff --git a/mods/psionics/system/psionics/complexus/complexus_power_cache.dm b/mods/content/psionics/system/psionics/complexus/complexus_power_cache.dm similarity index 77% rename from mods/psionics/system/psionics/complexus/complexus_power_cache.dm rename to mods/content/psionics/system/psionics/complexus/complexus_power_cache.dm index 637137d58b03..3ae14f1ddc1f 100644 --- a/mods/psionics/system/psionics/complexus/complexus_power_cache.dm +++ b/mods/content/psionics/system/psionics/complexus/complexus_power_cache.dm @@ -1,4 +1,4 @@ -/datum/psi_complexus/proc/rebuild_power_cache() +/datum/ability_handler/psionics/proc/rebuild_power_cache() if(rebuild_power_cache) melee_powers = list() @@ -28,22 +28,22 @@ grab_powers[faculty] += power rebuild_power_cache = FALSE -/datum/psi_complexus/proc/get_powers_by_faculty(var/faculty) +/datum/ability_handler/psionics/proc/get_powers_by_faculty(var/faculty) rebuild_power_cache() return powers_by_faculty[faculty] -/datum/psi_complexus/proc/get_melee_powers(var/faculty) +/datum/ability_handler/psionics/proc/get_melee_powers(var/faculty) rebuild_power_cache() return melee_powers[faculty] -/datum/psi_complexus/proc/get_ranged_powers(var/faculty) +/datum/ability_handler/psionics/proc/get_ranged_powers(var/faculty) rebuild_power_cache() return ranged_powers[faculty] -/datum/psi_complexus/proc/get_grab_powers(var/faculty) +/datum/ability_handler/psionics/proc/get_grab_powers(var/faculty) rebuild_power_cache() return grab_powers[faculty] -/datum/psi_complexus/proc/get_manifestations() +/datum/ability_handler/psionics/proc/get_manifestations() rebuild_power_cache() return manifestation_powers diff --git a/mods/content/psionics/system/psionics/complexus/complexus_process.dm b/mods/content/psionics/system/psionics/complexus/complexus_process.dm new file mode 100644 index 000000000000..82883b67dc62 --- /dev/null +++ b/mods/content/psionics/system/psionics/complexus/complexus_process.dm @@ -0,0 +1,249 @@ +/datum/ability_handler/psionics/proc/update(var/force, can_delete = TRUE) + + set waitfor = FALSE + + var/last_rating = rating + var/highest_faculty + var/highest_rank = 0 + var/combined_rank = 0 + for(var/faculty in ranks) + var/check_rank = get_rank(faculty) + if(check_rank == 1) + LAZYADD(latencies, faculty) + else + if(check_rank <= 0) + ranks -= faculty + LAZYREMOVE(latencies, faculty) + combined_rank += check_rank + if(!highest_faculty || highest_rank < check_rank) + highest_faculty = faculty + highest_rank = check_rank + + UNSETEMPTY(latencies) + var/rank_count = max(1, LAZYLEN(ranks)) + if(force || last_rating != ceil(combined_rank/rank_count)) + if(highest_rank <= 1) + if(highest_rank == 0 && can_delete) // hack to prevent deletion on update(TRUE) in New + qdel(src) + return + else + rebuild_power_cache = TRUE + sound_to(owner, 'sound/effects/psi/power_unlock.ogg') + rating = ceil(combined_rank/rank_count) + cost_modifier = 1 + if(rating > 1) + cost_modifier -= min(1, max(0.1, (rating-1) / 10)) + if(!ui) + ui = new(null, owner) + if(owner.client) + owner.client.screen += ui.components + owner.client.screen += ui + else + if(owner.client) + owner.client.screen |= ui.components + owner.client.screen |= ui + if(!suppressed && owner.client) + for(var/thing in SSpsi.all_aura_images) + owner.client.images |= thing + + var/image/aura_image = get_aura_image() + if(rating >= PSI_RANK_PARAMOUNT) // spooky boosters + aura_color = "#aaffaa" + aura_image.blend_mode = BLEND_SUBTRACT + else + aura_image.blend_mode = BLEND_ADD + if(highest_faculty == PSI_COERCION) + aura_color = "#cc3333" + else if(highest_faculty == PSI_PSYCHOKINESIS) + aura_color = "#3333cc" + else if(highest_faculty == PSI_REDACTION) + aura_color = "#33cc33" + else if(highest_faculty == PSI_ENERGISTICS) + aura_color = "#cccc33" + aura_image.pixel_x = -64 - owner.default_pixel_x + aura_image.pixel_y = -64 - owner.default_pixel_y + + if(!announced && owner && owner.client && !QDELETED(src)) + announced = TRUE + to_chat(owner, "
    ") + to_chat(owner, SPAN_NOTICE("You are psionic, touched by powers beyond understanding.")) + to_chat(owner, SPAN_NOTICE("Shift-left-click your Psi icon on the bottom right to view a summary of how to use them, or left click it to suppress or unsuppress your psionics. Beware: overusing your gifts can have deadly consequences.")) + to_chat(owner, "
    ") + +/datum/ability_handler/psionics/Process() + + var/update_hud + if(armor_cost) + var/value = max(1, ceil(armor_cost * cost_modifier)) + if(value <= stamina) + stamina -= value + else + backblast(abs(stamina - value)) + stamina = 0 + update_hud = TRUE + armor_cost = 0 + + if(stun) + stun-- + if(stun) + if(!suppressed) + suppressed = TRUE + update_hud = TRUE + else + to_chat(owner, SPAN_NOTICE("You have recovered your mental composure.")) + update_hud = TRUE + else + var/psi_leech = owner.do_psionics_check() + if(psi_leech) + if(stamina > 10) + stamina = max(0, stamina - rand(15,20)) + to_chat(owner, SPAN_DANGER("You feel your psi-power leeched away by \the [psi_leech]...")) + else + stamina++ + else if(stamina < max_stamina) + if(owner.stat == CONSCIOUS) + stamina = min(max_stamina, stamina + rand(1,3)) + else if(owner.stat == UNCONSCIOUS) + stamina = min(max_stamina, stamina + rand(3,5)) + + if(!owner.nervous_system_failure() && owner.stat != DEAD && stamina && !suppressed && get_rank(PSI_REDACTION) >= PSI_RANK_OPERANT) + attempt_regeneration() + + var/next_aura_size = max(0.1,((stamina/max_stamina)*min(3,rating))/5) + var/next_aura_alpha = round(((suppressed ? max(0,rating - 2) : rating)/5)*255) + + if(next_aura_alpha != last_aura_alpha || next_aura_size != last_aura_size || aura_color != last_aura_color) + last_aura_size = next_aura_size + last_aura_alpha = next_aura_alpha + last_aura_color = aura_color + var/matrix/M = matrix() + if(next_aura_size != 1) + M.Scale(next_aura_size) + animate(get_aura_image(), alpha = next_aura_alpha, transform = M, color = aura_color, time = 3) + + if(update_hud) + ui.update_icon() + +/datum/ability_handler/psionics/proc/attempt_regeneration() + + var/heal_general = FALSE + var/heal_poison = FALSE + var/heal_internal = FALSE + var/heal_bleeding = FALSE + var/heal_rate = 0 + var/mend_prob = 0 + + var/use_rank = get_rank(PSI_REDACTION) + if(use_rank >= PSI_RANK_PARAMOUNT) + heal_general = TRUE + heal_poison = TRUE + heal_internal = TRUE + heal_bleeding = TRUE + mend_prob = 50 + heal_rate = 7 + else if(use_rank == PSI_RANK_GRANDMASTER) + heal_poison = TRUE + heal_internal = TRUE + heal_bleeding = TRUE + mend_prob = 20 + heal_rate = 5 + else if(use_rank == PSI_RANK_MASTER) + heal_internal = TRUE + heal_bleeding = TRUE + mend_prob = 10 + heal_rate = 3 + else if(use_rank == PSI_RANK_OPERANT) + heal_bleeding = TRUE + mend_prob = 5 + heal_rate = 1 + else + return + + if(owner.stat != CONSCIOUS) + mend_prob = round(mend_prob * 0.65) + heal_rate = round(heal_rate * 0.65) + + if(!heal_rate || stamina < heal_rate) + return // Don't backblast from trying to heal ourselves thanks. + + if(ishuman(owner)) + + var/mob/living/human/H = owner + + // Fix some pain. + if(heal_rate > 0) + H.shock_stage = max(0, H.shock_stage - max(1, round(heal_rate/2))) + + // Mend internal damage. + if(prob(mend_prob)) + + // Fix our heart if we're paramount. + if(heal_general && H.is_asystole() && H.should_have_organ(BP_HEART) && spend_power(heal_rate)) + H.resuscitate() + + // Heal organ damage. + if(heal_internal) + for(var/obj/item/organ/internal/organ in H.get_internal_organs()) + + if(BP_IS_PROSTHETIC(organ) || BP_IS_CRYSTAL(organ)) + continue + + // Autoredaction doesn't heal brain damage directly. + if(organ.organ_tag == BP_BRAIN) + continue + + var/organ_damage = organ.get_organ_damage() + if(organ_damage > 0 && spend_power(heal_rate)) + organ.adjust_organ_damage(-(heal_rate)) + if(prob(25)) + to_chat(H, SPAN_NOTICE("Your innards itch as your autoredactive faculty mends your [organ.name].")) + return + + // Heal broken bones. + for(var/obj/item/organ/external/E in H.bad_external_organs) + + if(BP_IS_PROSTHETIC(E)) + continue + + if(heal_bleeding) + + if((E.status & ORGAN_ARTERY_CUT) && spend_power(heal_rate)) + to_chat(H, SPAN_NOTICE("Your autoredactive faculty mends the torn artery in your [E.name], stemming the worst of the bleeding.")) + E.status &= ~ORGAN_ARTERY_CUT + return + + if(E.status & ORGAN_TENDON_CUT) + to_chat(H, SPAN_NOTICE("Your autoredactive faculty repairs the severed tendon in your [E.name].")) + E.status &= ~ORGAN_TENDON_CUT + return TRUE + + for(var/datum/wound/wound in E.wounds) + if(wound.bleeding() && spend_power(heal_rate)) + to_chat(H, SPAN_NOTICE("Your autoredactive faculty knits together severed veins, stemming the bleeding from \a [wound.desc] on your [E.name].")) + wound.bleed_timer = 0 + wound.clamped = TRUE + E.status &= ~ORGAN_BLEEDING + return + + // Heal radiation, cloneloss and poisoning. + if(heal_poison) + + if(owner.radiation && spend_power(heal_rate)) + if(prob(25)) + to_chat(owner, SPAN_NOTICE("Your autoredactive faculty repairs some of the radiation damage to your body.")) + owner.radiation = max(0, owner.radiation - heal_rate) + return + + if(owner.get_damage(CLONE) && spend_power(heal_rate)) + if(prob(25)) + to_chat(owner, SPAN_NOTICE("Your autoredactive faculty stitches together some of your mangled DNA.")) + owner.heal_damage(CLONE, heal_rate) + return + + // Heal everything left. + if(heal_general && prob(mend_prob) && (owner.get_damage(BRUTE) || owner.get_damage(BURN) || owner.get_damage(OXY)) && spend_power(heal_rate)) + owner.heal_damage(BRUTE, heal_rate, do_update_health = FALSE) + owner.heal_damage(BURN, heal_rate, do_update_health = FALSE) + owner.heal_damage(OXY, heal_rate) + if(prob(25)) + to_chat(owner, SPAN_NOTICE("Your skin crawls as your autoredactive faculty heals your body.")) diff --git a/mods/content/psionics/system/psionics/complexus/complexus_topic.dm b/mods/content/psionics/system/psionics/complexus/complexus_topic.dm new file mode 100644 index 000000000000..592d019437fb --- /dev/null +++ b/mods/content/psionics/system/psionics/complexus/complexus_topic.dm @@ -0,0 +1,20 @@ +/datum/ability_handler/psionics/CanUseTopic(var/mob/user, var/datum/topic_state/state = global.default_topic_state) + return (user.client && check_rights(R_ADMIN, FALSE, user.client)) + +/datum/ability_handler/psionics/Topic(var/href, var/list/href_list) + . = ..() + if(!. && check_rights(R_ADMIN)) + if(href_list["remove_psionics"]) + if(owner?.get_ability_handler(/datum/ability_handler/psionics) == src && !QDELETED(src)) + log_and_message_admins("removed all psionics from [key_name(owner)].") + to_chat(owner, SPAN_NOTICE("Your psionic powers vanish abruptly, leaving you cold and empty.")) + QDEL_NULL(src) + . = TRUE + if(href_list["trigger_psi_latencies"]) + log_and_message_admins("triggered psi latencies for [key_name(owner)].") + check_latency_trigger(100, "outside intervention", redactive = TRUE) + . = TRUE + if(.) + var/datum/admins/admin = global.admins[usr.key] + if(istype(admin)) + admin.show_player_panel(owner) \ No newline at end of file diff --git a/mods/content/psionics/system/psionics/equipment/psipower.dm b/mods/content/psionics/system/psionics/equipment/psipower.dm new file mode 100644 index 000000000000..8aa0afca3524 --- /dev/null +++ b/mods/content/psionics/system/psionics/equipment/psipower.dm @@ -0,0 +1,40 @@ +/obj/item/ability/psionic + name = "psychic power" + icon = 'mods/content/psionics/icons/psychic_powers.dmi' + abstract_type = /obj/item/ability/psionic + handler_type = /datum/ability_handler/psionics + var/maintain_cost = 3 + +/obj/item/ability/psionic/Initialize() + . = ..() + if(. != INITIALIZE_HINT_QDEL) + START_PROCESSING(SSprocessing, src) + +/obj/item/ability/psionic/Destroy() + STOP_PROCESSING(SSprocessing, src) + . = ..() + +/obj/item/ability/psionic/attack_self(var/mob/user) + var/mob/owner = owner_ref?.resolve() + if(istype(owner)) + sound_to(owner, 'sound/effects/psi/power_fail.ogg') + . = ..() + +/obj/item/ability/psionic/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(target.do_psionics_check(max(get_attack_force(user), maintain_cost), user)) + to_chat(user, SPAN_WARNING("\The [src] flickers violently out of phase!")) + return TRUE + . = ..() + +/obj/item/ability/psionic/afterattack(var/atom/target, var/mob/living/user, var/proximity) + if(target.do_psionics_check(max(get_attack_force(user), maintain_cost), user)) + to_chat(user, SPAN_WARNING("\The [src] flickers violently out of phase!")) + return TRUE + . = ..(target, user, proximity) + +/obj/item/ability/psionic/Process() + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + psi?.spend_power(maintain_cost, backblast_on_failure = FALSE) + if((!owner || owner.do_psionics_check(maintain_cost, owner) || loc != owner || !(src in owner.get_held_items())) && !QDELETED(src)) + qdel(src) diff --git a/mods/content/psionics/system/psionics/equipment/psipower_blade.dm b/mods/content/psionics/system/psionics/equipment/psipower_blade.dm new file mode 100644 index 000000000000..94163e320127 --- /dev/null +++ b/mods/content/psionics/system/psionics/equipment/psipower_blade.dm @@ -0,0 +1,31 @@ +/obj/item/ability/psionic/psiblade + name = "psychokinetic slash" + _base_attack_force = 10 + sharp = TRUE + edge = TRUE + maintain_cost = 1 + icon_state = "psiblade_short" + +/obj/item/ability/psionic/psiblade/master + _base_attack_force = 20 + maintain_cost = 2 + +/obj/item/ability/psionic/psiblade/master/Initialize() + . = ..() + set_extension(src, /datum/extension/demolisher/energy) + +/obj/item/ability/psionic/psiblade/master/is_special_cutting_tool(var/high_power) + return !high_power + +/obj/item/ability/psionic/psiblade/master/grand + _base_attack_force = 30 + maintain_cost = 3 + icon_state = "psiblade_long" + +/obj/item/ability/psionic/psiblade/master/grand/paramount + _base_attack_force = 50 + maintain_cost = 4 + icon_state = "psiblade_long" + +/obj/item/ability/psionic/psiblade/master/grand/paramount/is_special_cutting_tool(var/high_power) + return TRUE \ No newline at end of file diff --git a/mods/content/psionics/system/psionics/equipment/psipower_tinker.dm b/mods/content/psionics/system/psionics/equipment/psipower_tinker.dm new file mode 100644 index 000000000000..0f6ba84d76ed --- /dev/null +++ b/mods/content/psionics/system/psionics/equipment/psipower_tinker.dm @@ -0,0 +1,48 @@ +/obj/item/ability/psionic/tinker + name = "psychokinetic tool" + icon_state = "tinker" + _base_attack_force = 1 + +/obj/item/ability/psionic/tinker/Initialize() + . = ..() + + var/use_tool_quality = TOOL_QUALITY_WORST + var/mob/living/owner = loc + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + switch(psi.get_rank(PSI_PSYCHOKINESIS)) + if(PSI_RANK_LATENT) + use_tool_quality = TOOL_QUALITY_BAD + if(PSI_RANK_OPERANT) + use_tool_quality = TOOL_QUALITY_MEDIOCRE + if(PSI_RANK_MASTER) + use_tool_quality = TOOL_QUALITY_DEFAULT + if(PSI_RANK_GRANDMASTER) + use_tool_quality = TOOL_QUALITY_GOOD + if(PSI_RANK_PARAMOUNT) + use_tool_quality = TOOL_QUALITY_BEST + + set_extension(src, /datum/extension/tool/variable, + list( + TOOL_CROWBAR = use_tool_quality, + TOOL_SCREWDRIVER = use_tool_quality, + TOOL_WRENCH = use_tool_quality, + TOOL_WIRECUTTERS = use_tool_quality + ), + null, + list( + TOOL_CROWBAR = 'sound/effects/psi/power_fabrication.ogg', + TOOL_SCREWDRIVER = 'sound/effects/psi/power_fabrication.ogg', + TOOL_WRENCH = 'sound/effects/psi/power_fabrication.ogg', + TOOL_WIRECUTTERS = 'sound/effects/psi/power_fabrication.ogg' + ) + ) + +/obj/item/ability/psionic/tinker/on_update_icon() + . = ..() + var/datum/extension/tool/variable/tool = get_extension(src, /datum/extension/tool) + if(istype(tool)) + var/decl/tool_archetype/tool_archetype = GET_DECL(tool.current_tool) + name = "psychokinetic [lowertext(tool_archetype.name)]" + else + name = initial(name) diff --git a/mods/content/psionics/system/psionics/equipment/psipower_tk.dm b/mods/content/psionics/system/psionics/equipment/psipower_tk.dm new file mode 100644 index 000000000000..ee529a0d9226 --- /dev/null +++ b/mods/content/psionics/system/psionics/equipment/psipower_tk.dm @@ -0,0 +1,109 @@ +/obj/item/ability/psionic/telekinesis + name = "telekinetic grip" + maintain_cost = 3 + icon_state = "telekinesis" + var/atom/movable/focus + +/obj/item/ability/psionic/telekinesis/Destroy() + focus = null + . = ..() + +/obj/item/ability/psionic/telekinesis/Process() + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + if(!focus || !isturf(focus.loc) || get_dist(get_turf(focus), get_turf(owner)) > psi?.get_rank(PSI_PSYCHOKINESIS)) + owner.drop_from_inventory(src) + return + . = ..() + +/obj/item/ability/psionic/telekinesis/proc/set_focus(var/atom/movable/_focus) + + if(!_focus.simulated || !isturf(_focus.loc)) + return FALSE + + var/check_paramount + if(ismob(_focus)) + var/mob/victim = _focus + check_paramount = (victim.mob_size >= MOB_SIZE_MEDIUM) + else if(isobj(_focus)) + var/obj/thing = _focus + check_paramount = (thing.w_class >= ITEM_SIZE_HUGE) + else + return FALSE + + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + if(_focus.anchored || (check_paramount && psi?.get_rank(PSI_PSYCHOKINESIS) < PSI_RANK_PARAMOUNT)) + focus = _focus + . = attack_self(owner) + if(!.) + to_chat(owner, SPAN_WARNING("\The [_focus] is too hefty for you to get a mind-grip on.")) + qdel(src) + return FALSE + + focus = _focus + overlays.Cut() + var/image/I = image(icon = focus.icon, icon_state = focus.icon_state) + I.color = focus.color + I.overlays = focus.overlays + overlays += I + return TRUE + +/obj/item/ability/psionic/telekinesis/attack_self(var/mob/user) + user.visible_message(SPAN_NOTICE("\The [user] makes a strange gesture.")) + sparkle() + return focus.do_simple_ranged_interaction(user) + +/obj/item/ability/psionic/telekinesis/afterattack(var/atom/target, var/mob/living/user, var/proximity) + + var/datum/ability_handler/psionics/psi = user.get_ability_handler(/datum/ability_handler/psionics) + if(!target || !user || (isobj(target) && !isturf(target.loc)) || !psi?.can_use() || !psi?.spend_power(5)) + return + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + psi.set_cooldown(5) + + var/user_psi_leech = user.do_psionics_check(5, user) + if(user_psi_leech) + to_chat(user, SPAN_WARNING("You reach for \the [target] but your telekinetic power is leeched away by \the [user_psi_leech]...")) + return + + if(target.do_psionics_check(5, user)) + to_chat(user, SPAN_WARNING("Your telekinetic power skates over \the [target] but cannot get a grip...")) + return + + var/distance = get_dist(get_turf(user), get_turf(focus ? focus : target)) + if(distance > psi.get_rank(PSI_PSYCHOKINESIS)) + to_chat(user, SPAN_WARNING("Your telekinetic power won't reach that far.")) + return FALSE + + if(target == focus) + attack_self(user) + else + user.visible_message(SPAN_DANGER("\The [user] gestures sharply!")) + sparkle() + if(!isturf(target) && istype(focus,/obj/item) && target.Adjacent(focus)) + var/obj/item/I = focus + var/resolved = target.attackby(I, user, user:get_organ_target()) + if(!resolved && target && I) + I.afterattack(target,user,1) // for splashing with beakers + else + if(!focus.anchored) + var/user_rank = psi?.get_rank(PSI_PSYCHOKINESIS) + focus.throw_at(target, user_rank*2, user_rank*10, owner_ref?.resolve()) + sleep(1) + sparkle() + +/obj/item/ability/psionic/telekinesis/proc/sparkle() + set waitfor = 0 + if(focus) + var/obj/effect/overlay/O = new /obj/effect/overlay(get_turf(focus)) + O.name = "sparkles" + O.anchored = TRUE + O.density = FALSE + O.layer = FLY_LAYER + O.set_dir(pick(global.cardinal)) + O.icon = 'icons/effects/effects.dmi' + O.icon_state = "nothing" + flick("empdisable",O) + QDEL_IN(src, 0.5 SECONDS) diff --git a/mods/psionics/system/psionics/events/_psi.dm b/mods/content/psionics/system/psionics/events/_psi.dm similarity index 90% rename from mods/psionics/system/psionics/events/_psi.dm rename to mods/content/psionics/system/psionics/events/_psi.dm index 90c0f63733ec..6f8734092963 100644 --- a/mods/psionics/system/psionics/events/_psi.dm +++ b/mods/content/psionics/system/psionics/events/_psi.dm @@ -20,5 +20,5 @@ for(var/thing in SSpsi.processing) apply_psi_effect(thing) -/datum/event/psi/proc/apply_psi_effect(var/datum/psi_complexus/psi) +/datum/event/psi/proc/apply_psi_effect(var/datum/ability_handler/psionics/psi) return diff --git a/mods/content/psionics/system/psionics/events/mini_spasm.dm b/mods/content/psionics/system/psionics/events/mini_spasm.dm new file mode 100644 index 000000000000..fd130c723f0e --- /dev/null +++ b/mods/content/psionics/system/psionics/events/mini_spasm.dm @@ -0,0 +1,69 @@ +/datum/event/minispasm + startWhen = 60 + endWhen = 90 + var/static/list/psi_operancy_messages = list( + "There's something in your skull!", + "Something is eating your thoughts!", + "You can feel your brain being rewritten!", + "Something is crawling over your frontal lobe!", + "THE SIGNAL THE SIGNAL THE SIGNAL THE SIGNAL THE" + ) + +/datum/event/minispasm/announce() + priority_announcement.Announce( \ + "PRIORITY ALERT: SIGMA-[rand(50,80)] PSIONIC SIGNAL LOCAL TRAMISSION DETECTED (97% MATCH, NONVARIANT) \ + (SIGNAL SOURCE TRIANGULATED ADJACENT LOCAL SITE): All personnel are advised to avoid \ + exposure to active audio transmission equipment including radio headsets and intercoms \ + for the duration of the signal broadcast.", \ + "Cuchulain Sensor Array Automated Message" \ + ) + +/datum/event/minispasm/start() + var/list/victims = list() + for(var/obj/item/radio/radio in global.listening_objects) + if(radio.on) + for(var/mob/living/victim in range(radio.canhear_range, radio.loc)) + if(isnull(victims[victim]) && victim.stat == CONSCIOUS && !GET_STATUS(victim, STAT_DEAF)) + victims[victim] = radio + for(var/thing in victims) + var/mob/living/victim = thing + var/obj/item/radio/source = victims[victim] + do_spasm(victim, source) + +/datum/event/minispasm/proc/do_spasm(var/mob/living/victim, var/obj/item/radio/source) + set waitfor = FALSE + + if(isliving(victim) && !victim.isSynthetic()) + var/list/spasm_disabilities = list(GENE_COND_NEARSIGHTED, GENE_COND_EPILEPSY, GENE_COND_TOURETTES, GENE_COND_NERVOUS) + for(var/spasm_disability in spasm_disabilities) + if(victim.has_genetic_condition(spasm_disability)) + spasm_disabilities -= spasm_disability + if(length(spasm_disabilities)) + victim.add_genetic_condition(pick(spasm_disabilities)) + + var/datum/ability_handler/psionics/psi = victim.get_ability_handler(/datum/ability_handler/psionics) + if(psi) + to_chat(victim, SPAN_DANGER("A hauntingly familiar sound hisses from [html_icon(source)] \the [source], and your vision flickers!")) + psi.backblast(rand(5,15)) + SET_STATUS_MAX(victim, STAT_PARA, 5) + ADJ_STATUS(victim, STAT_JITTER, 100) + else + to_chat(victim, SPAN_DANGER("An indescribable, brain-tearing sound hisses from [html_icon(source)] \the [source], and you collapse in a seizure!")) + victim.seizure() + var/new_latencies = rand(2,4) + var/list/faculties = list(PSI_COERCION, PSI_REDACTION, PSI_ENERGISTICS, PSI_PSYCHOKINESIS) + for(var/i = 1 to new_latencies) + to_chat(victim, SPAN_DANGER("[pick(psi_operancy_messages)]")) + victim.take_damage(rand(10,20), BRAIN) + victim.set_psi_rank(pick_n_take(faculties), 1) + sleep(30) + psi = victim.get_ability_handler(/datum/ability_handler/psionics) + psi?.update() + sleep(45) + psi?.check_latency_trigger(100, "a psionic scream", redactive = TRUE) + +/datum/event/minispasm/end() + priority_announcement.Announce( \ + "PRIORITY ALERT: SIGNAL BROADCAST HAS CEASED. Personnel are cleared to resume use of non-hardened radio transmission equipment. Have a nice day.", \ + "Cuchulain Sensor Array Automated Message" \ + ) diff --git a/mods/psionics/system/psionics/events/psi_balm.dm b/mods/content/psionics/system/psionics/events/psi_balm.dm similarity index 78% rename from mods/psionics/system/psionics/events/psi_balm.dm rename to mods/content/psionics/system/psionics/events/psi_balm.dm index 39032bb97ff2..b83c4e61ff16 100644 --- a/mods/psionics/system/psionics/events/psi_balm.dm +++ b/mods/content/psionics/system/psionics/events/psi_balm.dm @@ -5,7 +5,7 @@ "A sense of peace and comfort falls over you like a warm blanket." ) -/datum/event/psi/balm/apply_psi_effect(var/datum/psi_complexus/psi) +/datum/event/psi/balm/apply_psi_effect(var/datum/ability_handler/psionics/psi) var/soothed if(psi.stun > 1) psi.stun-- @@ -13,8 +13,8 @@ else if(psi.stamina < psi.max_stamina) psi.stamina = min(psi.max_stamina, psi.stamina + rand(1,3)) soothed = TRUE - else if(psi.owner.getBrainLoss() > 0) - psi.owner.adjustBrainLoss(-1) + else if(psi.owner.get_damage(BRAIN) > 0) + psi.owner.heal_damage(BRAIN, 1) soothed = TRUE if(soothed && prob(10)) to_chat(psi.owner, SPAN_NOTICE("[pick(balm_messages)]")) diff --git a/mods/psionics/system/psionics/events/psi_wail.dm b/mods/content/psionics/system/psionics/events/psi_wail.dm similarity index 86% rename from mods/psionics/system/psionics/events/psi_wail.dm rename to mods/content/psionics/system/psionics/events/psi_wail.dm index 7951dc9a228f..b1ee14e64f56 100644 --- a/mods/psionics/system/psionics/events/psi_wail.dm +++ b/mods/content/psionics/system/psionics/events/psi_wail.dm @@ -5,7 +5,7 @@ "Your head aches as a psychic wail intrudes on your psyche." ) -/datum/event/psi/wail/apply_psi_effect(var/datum/psi_complexus/psi) +/datum/event/psi/wail/apply_psi_effect(var/datum/ability_handler/psionics/psi) var/annoyed if(prob(1)) psi.stunned(1) diff --git a/mods/content/psionics/system/psionics/faculties/_faculty.dm b/mods/content/psionics/system/psionics/faculties/_faculty.dm new file mode 100644 index 000000000000..03d9fc7a2363 --- /dev/null +++ b/mods/content/psionics/system/psionics/faculties/_faculty.dm @@ -0,0 +1,16 @@ +/decl/psionic_faculty + var/id + var/name + var/associated_intent_flag + var/list/armour_types = list() + var/list/powers = list() + +/decl/psionic_faculty/validate() + . = ..() + if(!isnull(associated_intent_flag) && !isnum(associated_intent_flag)) + . += "non-bitflag associated_intent_flag value set" + +/decl/psionic_faculty/Initialize() + . = ..() + for(var/atype in armour_types) + SSpsi.armour_faculty_by_type[atype] = id diff --git a/mods/psionics/system/psionics/faculties/_power.dm b/mods/content/psionics/system/psionics/faculties/_power.dm similarity index 83% rename from mods/psionics/system/psionics/faculties/_power.dm rename to mods/content/psionics/system/psionics/faculties/_power.dm index b47924df28cc..75c6c5ab05d7 100644 --- a/mods/psionics/system/psionics/faculties/_power.dm +++ b/mods/content/psionics/system/psionics/faculties/_power.dm @@ -1,4 +1,6 @@ /decl/psionic_power + abstract_type = /decl/psionic_power + var/name // Name. If null, psipower won't be generated on roundstart. var/faculty // Associated psi faculty. var/min_rank // Minimum psi rank to use this power. @@ -15,15 +17,16 @@ /decl/psionic_power/proc/invoke(var/mob/living/user, var/atom/target) - if(!user.psi) + var/datum/ability_handler/psionics/psi = user.get_ability_handler(/datum/ability_handler/psionics) + if(!psi) return FALSE if(faculty && min_rank) - var/user_rank = user.psi.get_rank(faculty) + var/user_rank = psi.get_rank(faculty) if(user_rank < min_rank) return FALSE - if(cost && !user.psi.spend_power(cost)) + if(cost && !psi.spend_power(cost)) return FALSE var/user_psi_leech = user.do_psionics_check(cost, user) @@ -39,7 +42,8 @@ /decl/psionic_power/proc/handle_post_power(var/mob/living/user, var/atom/target) if(cooldown) - user.psi.set_cooldown(cooldown) + var/datum/ability_handler/psionics/psi = user.get_ability_handler(/datum/ability_handler/psionics) + psi?.set_cooldown(cooldown) if(admin_log && ismob(user) && ismob(target)) admin_attack_log(user, target, "Used psipower ([name])", "Was subjected to a psipower ([name])", "used a psipower ([name]) on") if(use_sound) diff --git a/mods/content/psionics/system/psionics/faculties/coercion.dm b/mods/content/psionics/system/psionics/faculties/coercion.dm new file mode 100644 index 000000000000..fd4943113522 --- /dev/null +++ b/mods/content/psionics/system/psionics/faculties/coercion.dm @@ -0,0 +1,249 @@ +/decl/psionic_faculty/coercion + id = PSI_COERCION + name = "Coercion" + associated_intent_flag = I_FLAG_DISARM + armour_types = list(PSIONIC) + +/decl/psionic_power/coercion + faculty = PSI_COERCION + abstract_type = /decl/psionic_power/coercion + +/decl/psionic_power/coercion/invoke(var/mob/living/user, var/mob/living/target) + if (!istype(target)) + to_chat(user, SPAN_WARNING("You cannot mentally attack \the [target].")) + return FALSE + + . = ..() + if(. && target.deflect_psionic_attack(user)) + return FALSE + +/decl/psionic_power/coercion/blindstrike + name = "Blindstrike" + cost = 8 + cooldown = 120 + use_ranged = TRUE + use_melee = TRUE + min_rank = PSI_RANK_GRANDMASTER + use_description = "Target the eyes or mouth on disarm intent and click anywhere to use a radial attack that blinds, deafens and disorients everyone near you." + +/decl/psionic_power/coercion/blindstrike/invoke(var/mob/living/user, var/mob/living/target) + var/user_target_zone = user.get_target_zone() + if(user_target_zone != BP_MOUTH && user_target_zone != BP_EYES) + return FALSE + . = ..() + if(.) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + user.visible_message(SPAN_DANGER("\The [user] suddenly throws back their head, as though screaming silently!")) + to_chat(user, SPAN_DANGER("You strike at all around you with a deafening psionic scream!")) + for(var/mob/living/M in orange(user, psi?.get_rank(PSI_COERCION))) + if(M == user) + continue + var/blocked = 100 * M.get_blocked_ratio(null, PSIONIC) + if(prob(blocked)) + to_chat(M, SPAN_DANGER("A psionic onslaught strikes your mind, but you withstand it!")) + continue + if(prob(60) && M.can_feel_pain()) + to_chat(M, SPAN_DANGER("Your senses are blasted into oblivion by a psionic scream!")) + M.emote(/decl/emote/audible/scream) + M.flash_eyes() + SET_STATUS_MAX(M, STAT_BLIND, 3) + SET_STATUS_MAX(M, STAT_DEAF, 6) + SET_STATUS_MAX(M, STAT_CONFUSE, rand(3,8)) + return TRUE + +/decl/psionic_power/coercion/mindread + name = "Read Mind" + cost = 6 + cooldown = 80 + use_melee = TRUE + min_rank = PSI_RANK_OPERANT + use_description = "Target the head on disarm intent at melee range to attempt to read a victim's surface thoughts." + +/decl/psionic_power/coercion/mindread/invoke(var/mob/living/user, var/mob/living/target) + if(!isliving(target) || !istype(target) || user.get_target_zone() != BP_HEAD) + return FALSE + . = ..() + if(!.) + return + + if(target.stat == DEAD || (target.status_flags & FAKEDEATH) || !target.client) + to_chat(user, SPAN_WARNING("\The [target] is in no state for a mind-read.")) + return TRUE + + user.visible_message(SPAN_WARNING("\The [user] touches \the [target]'s temple...")) + var/question = input(user, "Say something?", "Read Mind", "Penny for your thoughts?") as null|text + if(!question || user.incapacitated() || !do_after(user, 20)) + return TRUE + + var/started_mindread = world.time + to_chat(user, SPAN_NOTICE("You dip your mentality into the surface layer of \the [target]'s mind, seeking an answer: [question]")) + to_chat(target, SPAN_NOTICE("Your mind is compelled to answer: [question]")) + + var/answer = sanitize((input(target, question, "Read Mind") as null|message), MAX_MESSAGE_LEN) + if(!answer || world.time > started_mindread + 60 SECONDS || user.stat != CONSCIOUS || target.stat == DEAD) + to_chat(user, SPAN_NOTICE("You receive nothing useful from \the [target].")) + else + to_chat(user, SPAN_NOTICE("You skim thoughts from the surface of \the [target]'s mind: [answer]")) + msg_admin_attack("[key_name(user)] read mind of [key_name(target)] with question \"[question]\" and [answer?"got answer \"[answer]\".":"got no answer."]") + return TRUE + +/decl/psionic_power/coercion/agony + name = "Agony" + cost = 8 + cooldown = 50 + use_melee = TRUE + min_rank = PSI_RANK_MASTER + use_description = "Target the chest or groin on disarm intent to use a melee attack equivalent to a strike from a stun baton." + +/decl/psionic_power/coercion/agony/invoke(var/mob/living/user, var/mob/living/target) + if(!istype(target)) + return FALSE + var/user_zone_sel = user.get_target_zone() + if(user_zone_sel != BP_CHEST && user_zone_sel != BP_GROIN) + return FALSE + . = ..() + if(.) + user.visible_message("\The [target] has been struck by \the [user]!") + playsound(user.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + target.stun_effect_act(0, 60, user_zone_sel) + return TRUE + +/decl/psionic_power/coercion/spasm + name = "Spasm" + cost = 15 + cooldown = 100 + use_melee = TRUE + use_ranged = TRUE + min_rank = PSI_RANK_MASTER + use_description = "Target the arms or hands on disarm intent to use a ranged attack that may rip the weapons away from the target." + +/decl/psionic_power/coercion/spasm/invoke(var/mob/living/user, var/mob/living/human/target) + if(!istype(target)) + return FALSE + + if(!(user.get_target_zone() in list(BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND))) + return FALSE + + . = ..() + + if(.) + to_chat(user, "You lash out, stabbing into \the [target] with a lance of psi-power.") + to_chat(target, "The muscles in your arms cramp horrendously!") + if(prob(75)) + target.emote(/decl/emote/audible/scream) + for(var/hand_slot in target.get_held_item_slots()) + var/obj/item/thing = target.get_equipped_item(hand_slot) + if(thing?.simulated && prob(75) && target.try_unequip(thing)) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, hand_slot) + target.visible_message(SPAN_DANGER("\The [target] drops what they were holding as their [E ? E.name : "hand"] spasms!")) + return TRUE + +/decl/psionic_power/coercion/beguile + name = "Beguile" + cost = 28 + cooldown = 200 + use_grab = TRUE + min_rank = PSI_RANK_PARAMOUNT + use_description = "Grab a victim, target the eyes, then use the grab on them while on disarm intent, in order to beguile them into serving your cause." + +/decl/psionic_power/coercion/beguile/invoke(var/mob/living/user, var/mob/living/target) + if(!istype(target) || user.get_target_zone() != BP_EYES) + return FALSE + . = ..() + if(.) + if(target.stat == DEAD || (target.status_flags & FAKEDEATH)) + to_chat(user, SPAN_WARNING("\The [target] is dead!")) + return TRUE + if(!target.mind || !target.key) + to_chat(user, SPAN_WARNING("\The [target] is mindless!")) + return TRUE + var/decl/special_role/beguiled/beguiled = GET_DECL(/decl/special_role/beguiled) + if(beguiled.is_antagonist(target.mind)) + to_chat(user, SPAN_WARNING("\The [target] is already under a glamour!")) + return TRUE + + user.visible_message("\The [user] seizes the head of \the [target] in both hands...") + to_chat(user, SPAN_NOTICE("You insinuate your mentality into that of \the [target]...")) + to_chat(target, SPAN_DANGER("Your mind is being beguiled by the presence of \the [user]! They are trying to pull you under their glamour!")) + + var/accepted_glamour = alert(target, "Will you become \the [user]'s beguiled servant? Refusal will have harsh consequences.", "Beguilement", "No", "Yes") + + // Redo all our validity checks post-blocking call. + if(QDELETED(user) || QDELETED(target) || !user.Adjacent(target) || user.incapacitated()) + return TRUE + if(target.stat == DEAD || (target.status_flags & FAKEDEATH)) + return TRUE + if(!target.mind || !target.key) + return TRUE + if(!target.mind || beguiled.is_antagonist(target.mind)) + return TRUE + + if(accepted_glamour == "Yes") + to_chat(user, SPAN_DANGER("You layer a glamour across \the [target]'s senses, beguiling them to unwittingly follow your commands.")) + to_chat(target, SPAN_DANGER("You have been ensnared by \the [user]'s glamour!")) + beguiled.add_antagonist(target.mind, new_controller = user) + else + to_chat(user, SPAN_WARNING("\The [target] resists your glamour, writhing in your grip. You hurriedly release them before too much damage is done, but the psyche is left tattered. They should have no memory of this encounter, at least.")) + to_chat(target, SPAN_DANGER("You resist \the [user], struggling free of their influence at the cost of your own mind!")) + to_chat(target, SPAN_DANGER("You fall into darkness, losing all memory of the encounter...")) + target.take_damage(rand(25,40), BRAIN) + SET_STATUS_MAX(target, STAT_PARA, 10 SECONDS) + + return TRUE + +/decl/psionic_power/coercion/assay + name = "Assay" + cost = 15 + cooldown = 100 + use_grab = TRUE + min_rank = PSI_RANK_OPERANT + use_description = "Grab a patient, target the head, then use the grab on them while on disarm intent, in order to perform a deep coercive-redactive probe of their psionic potential." + +/decl/psionic_power/coercion/assay/invoke(var/mob/living/user, var/mob/living/target) + if(user.get_target_zone() != BP_HEAD) + return FALSE + . = ..() + if(.) + user.visible_message(SPAN_WARNING("\The [user] holds the head of \the [target] in both hands...")) + to_chat(user, SPAN_NOTICE("You insinuate your mentality into that of \the [target]...")) + to_chat(target, SPAN_WARNING("Your persona is being probed by the psychic lens of \the [user].")) + if(!do_after(user, (target.stat == CONSCIOUS ? 50 : 25), target, 0, 1)) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + psi?.backblast(rand(5,10)) + return TRUE + to_chat(user, SPAN_NOTICE("You retreat from \the [target], holding your new knowledge close.")) + to_chat(target, SPAN_DANGER("Your mental complexus is laid bare to judgement of \the [user].")) + target.show_psi_assay(user) + return TRUE + +/decl/psionic_power/coercion/focus + name = "Focus" + cost = 10 + cooldown = 80 + use_grab = TRUE + min_rank = PSI_RANK_OPERANT + use_description = "Grab a patient, target the mouth, then use the grab on them while on disarm intent, in order to cure ailments of the mind." + +/decl/psionic_power/coercion/focus/invoke(var/mob/living/user, var/mob/living/target) + if(user.get_target_zone() != BP_MOUTH) + return FALSE + . = ..() + if(.) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + user.visible_message(SPAN_WARNING("\The [user] holds the head of \the [target] in both hands...")) + to_chat(user, SPAN_NOTICE("You probe \the [target]'s mind for various ailments...")) + to_chat(target, SPAN_WARNING("Your mind is being cleansed of ailments by \the [user].")) + if(!do_after(user, (target.stat == CONSCIOUS ? 50 : 25), target, 0, 1)) + psi?.backblast(rand(5,10)) + return TRUE + to_chat(user, SPAN_WARNING("You clear \the [target]'s mind of ailments.")) + to_chat(target, SPAN_WARNING("Your mind is cleared of ailments.")) + + var/coercion_rank = psi?.get_rank(PSI_COERCION) + if(coercion_rank >= PSI_RANK_GRANDMASTER) + ADJ_STATUS(target, STAT_PARA, -1) + target.set_status_condition(STAT_DROWSY, 0) + if(isliving(target)) + var/mob/living/M = target + M.adjust_hallucination(-30) + return TRUE \ No newline at end of file diff --git a/mods/psionics/system/psionics/faculties/energistics.dm b/mods/content/psionics/system/psionics/faculties/energistics.dm similarity index 80% rename from mods/psionics/system/psionics/faculties/energistics.dm rename to mods/content/psionics/system/psionics/faculties/energistics.dm index d523318812ed..2396a1e71193 100644 --- a/mods/psionics/system/psionics/faculties/energistics.dm +++ b/mods/content/psionics/system/psionics/faculties/energistics.dm @@ -1,11 +1,12 @@ /decl/psionic_faculty/energistics id = PSI_ENERGISTICS name = "Energistics" - associated_intent = I_HURT - armour_types = list("bomb", "laser", "energy") + associated_intent_flag = I_FLAG_HARM + armour_types = list(ARMOR_BOMB, ARMOR_LASER, ARMOR_ENERGY) /decl/psionic_power/energistics faculty = PSI_ENERGISTICS + abstract_type = /decl/psionic_power/energistics /decl/psionic_power/energistics/disrupt name = "Disrupt" @@ -16,9 +17,10 @@ use_description = "Target the head, eyes or mouth while on harm intent to use a melee attack that causes a localized electromagnetic pulse." /decl/psionic_power/energistics/disrupt/invoke(var/mob/living/user, var/mob/living/target) - if(user.zone_sel.selecting != BP_HEAD && user.zone_sel.selecting != BP_EYES && user.zone_sel.selecting != BP_MOUTH) + var/user_zone_sel = user.get_target_zone() + if(user_zone_sel != BP_HEAD && user_zone_sel != BP_EYES && user_zone_sel != BP_MOUTH) return FALSE - if(istype(target, /turf)) + if(isturf(target)) return FALSE . = ..() if(.) @@ -35,15 +37,16 @@ use_description = "Target the chest or groin while on harm intent to use a melee attack that electrocutes a victim." /decl/psionic_power/energistics/electrocute/invoke(var/mob/living/user, var/mob/living/target) - if(user.zone_sel.selecting != BP_CHEST && user.zone_sel.selecting != BP_GROIN) + var/user_zone_sel = user.get_target_zone() + if(user_zone_sel != BP_CHEST && user_zone_sel != BP_GROIN) return FALSE - if(istype(target, /turf)) + if(isturf(target)) return FALSE . = ..() if(.) user.visible_message("\The [user] sends a jolt of electricity arcing into \the [target]!") if(istype(target)) - target.electrocute_act(rand(15,45), user, 1, user.zone_sel.selecting) + target.electrocute_act(rand(15,45), user, 1, user_zone_sel) return TRUE else if(isatom(target)) var/obj/item/cell/charging_cell = target.get_cell() @@ -64,7 +67,8 @@ if(.) user.visible_message("\The [user]'s eyes flare with light!") - var/user_rank = user.psi.get_rank(faculty) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + var/user_rank = psi?.get_rank(faculty) var/obj/item/projectile/pew var/pew_sound @@ -88,7 +92,7 @@ pew.current = target pew.starting = get_turf(user) pew.shot_from = user - pew.launch(target, user.zone_sel.selecting, (target.x-user.x), (target.y-user.y)) + pew.launch(target, user.get_target_zone(), user) return TRUE /decl/psionic_power/energistics/spark @@ -104,11 +108,10 @@ . = ..() if(.) if(istype(target,/obj/item/clothing/mask/smokable/cigarette)) + var/decl/pronouns/pronouns = user.get_pronouns() var/obj/item/clothing/mask/smokable/cigarette/S = target - S.light("[user] snaps \his fingers and \the [S.name] lights up.") + S.light("\The [user] snaps [pronouns.his] fingers and \the [S] lights up.") playsound(S.loc, "sparks", 50, 1) else - var/datum/effect/effect/system/spark_spread/sparks = new () - sparks.set_up(3, 0, get_turf(target)) - sparks.start() + spark_at(get_turf(target)) return TRUE diff --git a/mods/content/psionics/system/psionics/faculties/psychokinesis.dm b/mods/content/psionics/system/psionics/faculties/psychokinesis.dm new file mode 100644 index 000000000000..8d0dd5c61f88 --- /dev/null +++ b/mods/content/psionics/system/psionics/faculties/psychokinesis.dm @@ -0,0 +1,95 @@ +/decl/psionic_faculty/psychokinesis + id = PSI_PSYCHOKINESIS + name = "Psychokinesis" + associated_intent_flag = I_FLAG_GRAB + armour_types = list(ARMOR_MELEE, ARMOR_BULLET) + +/decl/psionic_power/psychokinesis + faculty = PSI_PSYCHOKINESIS + use_manifest = TRUE + use_sound = null + abstract_type = /decl/psionic_power/psychokinesis + +/decl/psionic_power/psychokinesis/psiblade + name = "Psiblade" + cost = 10 + cooldown = 30 + min_rank = PSI_RANK_OPERANT + use_description = "Click on or otherwise activate an empty hand while on harm intent to manifest a psychokinetic cutting blade. The power the blade will vary based on your mastery of the faculty." + admin_log = FALSE + +/decl/psionic_power/psychokinesis/psiblade/invoke(var/mob/living/user, var/mob/living/target) + if((target && user != target) || !user.check_intent(I_FLAG_HARM)) + return FALSE + . = ..() + if(.) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + switch(psi?.get_rank(faculty)) + if(PSI_RANK_PARAMOUNT) + return new /obj/item/ability/psionic/psiblade/master/grand/paramount(user, user) + if(PSI_RANK_GRANDMASTER) + return new /obj/item/ability/psionic/psiblade/master/grand(user, user) + if(PSI_RANK_MASTER) + return new /obj/item/ability/psionic/psiblade/master(user, user) + else + return new /obj/item/ability/psionic/psiblade(user, user) + +/decl/psionic_power/psychokinesis/tinker + name = "Tinker" + cost = 5 + cooldown = 10 + min_rank = PSI_RANK_MASTER + use_description = "Click on or otherwise activate an empty hand while on help intent to manifest a psychokinetic tool. Use it in-hand to switch between tool types." + admin_log = FALSE + +/decl/psionic_power/psychokinesis/tinker/invoke(var/mob/living/user, var/mob/living/target) + if((target && user != target) || !user.check_intent(I_FLAG_HELP)) + return FALSE + . = ..() + if(.) + return new /obj/item/ability/psionic/tinker(user) + +/decl/psionic_power/psychokinesis/telekinesis + name = "Telekinesis" + cost = 5 + cooldown = 10 + use_ranged = TRUE + use_manifest = FALSE + min_rank = PSI_RANK_GRANDMASTER + use_description = "Click on a distant target while on grab intent to manifest a psychokinetic grip. Use it manipulate objects at a distance." + admin_log = FALSE + use_sound = 'sound/effects/psi/power_used.ogg' + var/static/list/valid_machine_types = list( + /obj/machinery/door + ) + +/decl/psionic_power/psychokinesis/telekinesis/invoke(var/mob/living/user, var/mob/living/target) + if(!user.check_intent(I_FLAG_GRAB)) + return FALSE + . = ..() + if(.) + + var/distance = get_dist(user, target) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + if(distance > psi?.get_rank(PSI_PSYCHOKINESIS)) + to_chat(user, "Your telekinetic power won't reach that far.") + return FALSE + + if(ismob(target) || istype(target, /obj)) + var/obj/item/ability/psionic/telekinesis/tk = new(user) + if(tk.set_focus(target)) + tk.sparkle() + user.visible_message(SPAN_NOTICE("\The [user] reaches out.")) + return tk + else if(istype(target, /obj/structure)) + user.visible_message(SPAN_NOTICE("\The [user] makes a strange gesture.")) + var/obj/O = target + O.attack_hand(user) // We bypass adjacency checks due to telekinetics. + return TRUE + else if(istype(target, /obj/machinery)) + for(var/mtype in valid_machine_types) + if(istype(target, mtype)) + var/obj/machinery/machine = target + machine.attack_hand(user) // We bypass adjacency checks due to telekinetics. + return TRUE + return FALSE diff --git a/mods/psionics/system/psionics/faculties/redaction.dm b/mods/content/psionics/system/psionics/faculties/redaction.dm similarity index 75% rename from mods/psionics/system/psionics/faculties/redaction.dm rename to mods/content/psionics/system/psionics/faculties/redaction.dm index 9bf49fcaec1e..7b8b9c1b9fd1 100644 --- a/mods/psionics/system/psionics/faculties/redaction.dm +++ b/mods/content/psionics/system/psionics/faculties/redaction.dm @@ -1,12 +1,13 @@ /decl/psionic_faculty/redaction id = PSI_REDACTION name = "Redaction" - associated_intent = I_HELP - armour_types = list("bio", "rad") - + associated_intent_flag = I_FLAG_HELP + armour_types = list(ARMOR_BIO, ARMOR_RAD) + /decl/psionic_power/redaction faculty = PSI_REDACTION admin_log = FALSE + abstract_type = /decl/psionic_power/redaction /decl/psionic_power/redaction/proc/check_dead(var/mob/living/target) if(!istype(target)) @@ -29,7 +30,7 @@ use_description = "Grab a patient, target the chest, then switch to help intent and use the grab on them to perform a check for wounds and damage." /decl/psionic_power/redaction/skinsight/invoke(var/mob/living/user, var/mob/living/target) - if(user.zone_sel.selecting != BP_CHEST) + if(user.get_target_zone() != BP_CHEST) return FALSE . = ..() if(.) @@ -45,14 +46,14 @@ min_rank = PSI_RANK_OPERANT use_description = "Target a patient while on help intent at melee range to mend a variety of maladies, such as bleeding or broken bones. Higher ranks in this faculty allow you to mend a wider range of problems." -/decl/psionic_power/redaction/mend/invoke(var/mob/living/user, var/mob/living/carbon/human/target) +/decl/psionic_power/redaction/mend/invoke(var/mob/living/user, var/mob/living/human/target) if(!istype(user) || !istype(target)) return FALSE . = ..() if(.) - var/obj/item/organ/external/E = target.get_organ(user.zone_sel.selecting) + var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, user.get_target_zone()) - if(!E || E.is_stump()) + if(!E) to_chat(user, SPAN_WARNING("They are missing that limb.")) return TRUE @@ -63,10 +64,11 @@ user.visible_message(SPAN_NOTICE("\The [user] rests a hand on \the [target]'s [E.name]...")) to_chat(target, SPAN_NOTICE("A healing warmth suffuses you.")) - var/redaction_rank = user.psi.get_rank(PSI_REDACTION) - var/pk_rank = user.psi.get_rank(PSI_PSYCHOKINESIS) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + var/redaction_rank = psi?.get_rank(PSI_REDACTION) + var/pk_rank = psi?.get_rank(PSI_PSYCHOKINESIS) if(pk_rank >= PSI_RANK_LATENT && redaction_rank >= PSI_RANK_MASTER) - var/removal_size = Clamp(5-pk_rank, 0, 5) + var/removal_size = clamp(5-pk_rank, 0, 5) var/valid_objects = list() for(var/thing in E.implants) var/obj/imp = thing @@ -89,27 +91,32 @@ return TRUE if(E.status & ORGAN_BROKEN) to_chat(user, SPAN_NOTICE("You coax shattered bones to come together and fuse, mending the break.")) - E.status &= ~ORGAN_BROKEN + E.mend_fracture() E.stage = 0 return TRUE + if(E.is_dislocated() && !E.is_parent_dislocated()) + to_chat(user, SPAN_NOTICE("You carefully guide the dislocated joint back into place and soothe the inflamed muscles.")) + E.undislocate(skip_pain = TRUE) + return TRUE - for(var/datum/wound/W in E.wounds) - if(W.bleeding()) - if(redaction_rank >= PSI_RANK_MASTER || W.wound_damage() < 30) + for(var/datum/wound/wound in E.wounds) + if(wound.bleeding()) + if(redaction_rank >= PSI_RANK_MASTER || wound.wound_damage() < 30) to_chat(user, SPAN_NOTICE("You knit together severed veins and broken flesh, stemming the bleeding.")) - W.bleed_timer = 0 - W.clamped = TRUE + wound.bleed_timer = 0 + wound.clamped = TRUE E.status &= ~ORGAN_BLEEDING return TRUE else - to_chat(user, SPAN_NOTICE("This [W.desc] is beyond your power to heal.")) + to_chat(user, SPAN_NOTICE("This [wound.desc] is beyond your power to heal.")) if(redaction_rank >= PSI_RANK_GRANDMASTER) - for(var/obj/item/organ/internal/I in E.internal_organs) - if(!BP_IS_PROSTHETIC(I) && !BP_IS_CRYSTAL(I) && I.damage > 0) - to_chat(user, SPAN_NOTICE("You encourage the damaged tissue of \the [I] to repair itself.")) + for(var/obj/item/organ/internal/organ in E.internal_organs) + var/organ_damage = organ.get_organ_damage() + if(!BP_IS_PROSTHETIC(organ) && !BP_IS_CRYSTAL(organ) && organ_damage > 0 && organ.organ_tag != BP_BRAIN) + to_chat(user, SPAN_NOTICE("You encourage the damaged tissue of \the [organ] to repair itself.")) var/heal_rate = redaction_rank - I.damage = max(0, I.damage - rand(heal_rate,heal_rate*2)) + organ.adjust_organ_damage(-rand(heal_rate, heal_rate*2)) return TRUE to_chat(user, SPAN_NOTICE("You can find nothing within \the [target]'s [E.name] to mend.")) @@ -123,7 +130,7 @@ min_rank = PSI_RANK_GRANDMASTER use_description = "Target a patient while on help intent at melee range to cleanse radiation and genetic damage from a patient." -/decl/psionic_power/redaction/cleanse/invoke(var/mob/living/user, var/mob/living/carbon/human/target) +/decl/psionic_power/redaction/cleanse/invoke(var/mob/living/user, var/mob/living/human/target) if(!istype(user) || !istype(target)) return FALSE . = ..() @@ -137,12 +144,12 @@ else target.radiation = 0 return TRUE - if(target.getCloneLoss()) + if(target.get_damage(CLONE)) to_chat(user, SPAN_NOTICE("You stitch together some of the mangled DNA within \the [target]...")) - if(target.getCloneLoss() >= removing) - target.adjustCloneLoss(-removing) + if(target.get_damage(CLONE) >= removing) + target.heal_damage(CLONE, removing) else - target.adjustCloneLoss(-(target.getCloneLoss())) + target.heal_damage(CLONE, target.get_damage(CLONE)) return TRUE to_chat(user, SPAN_NOTICE("You can find no genetic damage or radiation to heal within \the [target].")) return TRUE @@ -158,7 +165,7 @@ admin_log = FALSE /decl/psionic_power/revive/invoke(var/mob/living/user, var/mob/living/target) - if(!isliving(target) || !istype(target) || user.zone_sel.selecting != BP_HEAD) + if(!isliving(target) || !istype(target) || user.get_target_zone() != BP_HEAD) return FALSE . = ..() if(.) @@ -172,15 +179,16 @@ user.visible_message(SPAN_NOTICE("\The [user] splays out their hands over \the [target]'s body...")) if(!do_after(user, 100, target, 0, 1)) - user.psi.backblast(rand(10,25)) + var/datum/ability_handler/psionics/psi = user?.get_ability_handler(/datum/ability_handler/psionics) + psi?.backblast(rand(10,25)) return TRUE - for(var/mob/observer/G in GLOB.dead_mob_list_) + for(var/mob/observer/G in global.dead_mob_list_) if(G.mind && G.mind.current == target && G.client) to_chat(G, SPAN_NOTICE("Your body has been revived, Re-Enter Corpse to return to it.")) break to_chat(target, SPAN_NOTICE("Life floods back into your body!")) target.visible_message(SPAN_NOTICE("\The [target] shudders violently!")) - target.adjustOxyLoss(-rand(15,20)) + target.heal_damage(OXY, rand(15,20)) target.basic_revival() return TRUE diff --git a/mods/content/psionics/system/psionics/interface/ui.dm b/mods/content/psionics/system/psionics/interface/ui.dm new file mode 100644 index 000000000000..3d8255b20308 --- /dev/null +++ b/mods/content/psionics/system/psionics/interface/ui.dm @@ -0,0 +1,17 @@ +/obj/screen/psi + icon = 'mods/content/psionics/icons/psi.dmi' + requires_ui_style = FALSE + apply_screen_overlay = FALSE + var/hidden = TRUE + var/can_hide = TRUE + +/obj/screen/psi/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + update_icon() + +/obj/screen/psi/on_update_icon() + ..() + if(hidden && can_hide) + set_invisibility(INVISIBILITY_ABSTRACT) + else + set_invisibility(INVISIBILITY_NONE) \ No newline at end of file diff --git a/mods/content/psionics/system/psionics/interface/ui_hub.dm b/mods/content/psionics/system/psionics/interface/ui_hub.dm new file mode 100644 index 000000000000..97c5ba41adc0 --- /dev/null +++ b/mods/content/psionics/system/psionics/interface/ui_hub.dm @@ -0,0 +1,79 @@ +/obj/screen/psi/hub + name = "Psi" + icon_state = "psi_suppressed" + screen_loc = "RIGHT-1:28,CENTER-3:11" + hidden = FALSE + maptext_x = 6 + maptext_y = -8 + requires_ui_style = FALSE + can_hide = FALSE + var/image/on_cooldown + var/list/components + +/obj/screen/psi/hub/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat) + . = ..() + on_cooldown = image(icon, "cooldown") + components = list( + new /obj/screen/psi/armour(null, _owner), + new /obj/screen/psi/toggle_psi_menu(null, _owner, null, null, null, null, src) + ) + START_PROCESSING(SSprocessing, src) + +/obj/screen/psi/hub/on_update_icon() + ..() + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + icon_state = psi?.suppressed ? "psi_suppressed" : "psi_active" + if(world.time < psi?.next_power_use) + overlays |= on_cooldown + else + overlays.Cut() + var/offset = 1 + for(var/thing in components) + var/obj/screen/psi/component = thing + component.update_icon() + if(!component.invisibility) component.screen_loc = "RIGHT-[++offset]:28,CENTER-3:11" + +/obj/screen/psi/hub/Destroy() + STOP_PROCESSING(SSprocessing, src) + for(var/thing in components) + qdel(thing) + components.Cut() + . = ..() + +/obj/screen/psi/hub/Process() + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner)) + qdel(src) + return + var/datum/ability_handler/psionics/psi = owner.get_ability_handler(/datum/ability_handler/psionics) + if(!psi) + return + maptext = "[round((psi.stamina/psi.max_stamina)*100)]%" + update_icon() + +/obj/screen/psi/hub/handle_click(mob/user, params) + + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + if(!psi) + return + + var/list/click_params = params2list(params) + if(click_params["shift"]) + owner.show_psi_assay(owner) + return + + if(psi.suppressed && psi.stun) + to_chat(owner, "You are dazed and reeling, and cannot muster enough focus to do that!") + return + + psi.suppressed = !psi.suppressed + to_chat(owner, "You are [psi?.suppressed ? "now suppressing" : "no longer suppressing"] your psi-power.") + if(psi.suppressed) + psi.cancel() + psi.hide_auras() + else + sound_to(owner, sound('sound/effects/psi/power_unlock.ogg')) + psi.show_auras() + update_icon() diff --git a/mods/content/psionics/system/psionics/interface/ui_toggles.dm b/mods/content/psionics/system/psionics/interface/ui_toggles.dm new file mode 100644 index 000000000000..93c34b82a275 --- /dev/null +++ b/mods/content/psionics/system/psionics/interface/ui_toggles.dm @@ -0,0 +1,52 @@ +// Begin psi armour toggle. +/obj/screen/psi/armour + name = "Psi-Armour" + icon_state = "psiarmour_off" + +/obj/screen/psi/armour/on_update_icon() + ..() + var/mob/living/owner = owner_ref.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + if(psi && invisibility == 0) + icon_state = psi.use_psi_armour ? "psiarmour_on" : "psiarmour_off" + +/obj/screen/psi/armour/handle_click(mob/user, params) + var/mob/living/owner = owner_ref?.resolve() + var/datum/ability_handler/psionics/psi = istype(owner) && owner.get_ability_handler(/datum/ability_handler/psionics) + if(!psi) + return + psi.use_psi_armour = !psi.use_psi_armour + if(psi.use_psi_armour) + to_chat(owner, SPAN_NOTICE("You will now use your psionics to deflect or block incoming attacks.")) + else + to_chat(owner, SPAN_NOTICE("You will no longer use your psionics to deflect or block incoming attacks.")) + update_icon() + +// End psi armour toggle. + +// Menu toggle. +/obj/screen/psi/toggle_psi_menu + name = "Show/Hide Psi UI" + icon_state = "arrow_left" + requires_ui_style = FALSE + can_hide = FALSE + var/obj/screen/psi/hub/controller + +/obj/screen/psi/toggle_psi_menu/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha, ui_cat, obj/screen/psi/hub/_controller) + . = ..() + controller = _controller + +/obj/screen/psi/toggle_psi_menu/handle_click(mob/user, params) + var/set_hidden = !hidden + for(var/thing in controller.components) + var/obj/screen/psi/psi = thing + psi.hidden = set_hidden + controller.update_icon() + +/obj/screen/psi/toggle_psi_menu/on_update_icon() + ..() + if(hidden) + icon_state = "arrow_left" + else + icon_state = "arrow_right" +// End menu toggle. \ No newline at end of file diff --git a/mods/content/psionics/system/psionics/mob/mob.dm b/mods/content/psionics/system/psionics/mob/mob.dm new file mode 100644 index 000000000000..c7bc95cc25c9 --- /dev/null +++ b/mods/content/psionics/system/psionics/mob/mob.dm @@ -0,0 +1,64 @@ +/datum/ability_handler/psionics/refresh_login(being_created) + . = ..() + // stopgap to prevent us from deleting ourselves during init + update(TRUE, can_delete = !being_created) + if(!suppressed) + show_auras() + +/mob/proc/set_psi_rank(var/faculty, var/rank, var/take_larger, var/defer_update, var/temporary) + return + +/mob/living/set_psi_rank(var/faculty, var/rank, var/take_larger, var/defer_update, var/temporary) + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + var/current_rank = psi?.get_rank(faculty) + if(!current_rank && !rank) + return + if(current_rank != rank && (!take_larger || current_rank < rank)) + if(!psi && rank) + psi = get_ability_handler(/datum/ability_handler/psionics, TRUE) + if(psi) + psi.set_rank(faculty, rank, defer_update, temporary) + +/mob/living/proc/deflect_psionic_attack(var/attacker) + var/blocked = 100 * get_blocked_ratio(null, PSIONIC) + if(prob(blocked)) + if(attacker) + to_chat(attacker, SPAN_WARNING("Your mental attack is deflected by \the [src]'s defenses!")) + to_chat(src, SPAN_DANGER("\The [attacker] strikes out with a mental attack, but you deflect it!")) + return TRUE + return FALSE + +/mob/living/human/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + var/obj/item/projectile/P = damage_source + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + if(istype(P) && !P.disrupts_psionics() && psi && P.starting && prob(psi.get_armour(SSmaterials.get_armor_key(P.atom_damage_type, P.damage_flags())) * 0.5) && psi.spend_power(round(damage/10))) + visible_message(SPAN_DANGER("\The [src] deflects [isatom(attack_text) ? "\the [attack_text]" : attack_text]!")) + P.redirect(P.starting.x + rand(-2,2), P.starting.y + rand(-2,2), get_turf(src), src) + return PROJECTILE_FORCE_MISS + . = ..() + +/mob/living/get_restraint_breakout_mod() + . = ..() + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + if(psi) + . = clamp(. - (psi.get_rank(PSI_PSYCHOKINESIS)*0.2), 0, 1) + +/mob/living/can_break_restraints() + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + . = (psi && psi.can_use() && psi.get_rank(PSI_PSYCHOKINESIS) >= PSI_RANK_PARAMOUNT) + +/mob/living/get_special_resist_time() + . = ..() + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + if(psi && psi.can_use()) + . += ((25 SECONDS) * psi.get_rank(PSI_PSYCHOKINESIS)) + +/mob/living/is_telekinetic() + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + . = psi && !psi.suppressed && psi.get_rank(PSI_PSYCHOKINESIS) >= PSI_RANK_OPERANT + +/mob/living/get_armors_by_zone(def_zone, damage_type, damage_flags) + . = ..() + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + if(psi) + . += get_extension(psi, /datum/extension/armor) diff --git a/mods/content/psionics/system/psionics/mob/mob_assay.dm b/mods/content/psionics/system/psionics/mob/mob_assay.dm new file mode 100644 index 000000000000..4e7b974cce5f --- /dev/null +++ b/mods/content/psionics/system/psionics/mob/mob_assay.dm @@ -0,0 +1,97 @@ +/mob/living/proc/show_psi_assay(var/mob/viewer, var/obj/machinery/psi_meter/machine) + + if(!viewer) viewer = usr + + var/use_He_is = "You are" + var/use_He_has = "You have" + if(istype(machine) || viewer != src) + var/decl/pronouns/pronouns = get_pronouns(ignore_coverings = TRUE) + use_He_is = "[pronouns.He] [pronouns.is]" + use_He_has = "[pronouns.He] [pronouns.has]" + + var/list/dat = list() + + dat += "

    Summary

    " + dat += "
    " + + var/datum/ability_handler/psionics/psi = get_ability_handler(/datum/ability_handler/psionics) + if(psi) + + // Hi Warhammer 40k rating system, how are you? + // I hope you get along with the Galactic Milieu metapsychics. + var/use_rating + var/effective_rating = psi.rating + if(effective_rating > 1 && psi.suppressed) + effective_rating = max(0, psi.rating-2) + var/rating_descriptor + if(mind && !psi.suppressed) + var/decl/special_role/paramount/paramounts = GET_DECL(/decl/special_role/paramount) + if(paramounts.is_antagonist(mind)) + use_rating = "[effective_rating]-Alpha-Plus" + rating_descriptor = "This indicates a completely deviant psi complexus, either beyond or outside anything currently recorded. Approach with care." + // This space intentionally left blank (for Omega-Minus psi vampires. todo) + var/decl/special_role/beguiled/beguiled = GET_DECL(/decl/special_role/beguiled) + if(viewer != usr && beguiled.is_antagonist(mind) && ishuman(viewer)) + var/datum/ability_handler/psionics/viewer_psi = viewer.get_ability_handler(/datum/ability_handler/psionics) + if(viewer_psi && viewer_psi.get_rank(PSI_REDACTION) >= PSI_RANK_GRANDMASTER) + dat += "Their mind has been subverted by another operant psychic; their actions are not their own." + + if(!use_rating) + switch(effective_rating) + if(1) + use_rating = "[effective_rating]-Epsilon" + rating_descriptor = "This indicates the presence of minor latent psi potential with little or no operant capabilities." + if(2) + use_rating = "[effective_rating]-Gamma" + rating_descriptor = "This indicates the presence of minor psi capabilities of the Operant rank or higher." + if(3) + use_rating = "[effective_rating]-Delta" + rating_descriptor = "This indicates the presence of psi capabilities of the Master rank or higher." + if(4) + use_rating = "[effective_rating]-Beta" + rating_descriptor = "This indicates the presence of significant psi capabilities of the Grandmaster rank or higher." + if(5) + use_rating = "[effective_rating]-Alpha" + rating_descriptor = "This indicates the presence of major psi capabilities of the Paramount Grandmaster rank or higher." + else + use_rating = "[effective_rating]-Lambda" + rating_descriptor = "This indicates the presence of trace latent psi capabilities." + + dat += "[use_He_has] an overall psi rating of [use_rating].
    [rating_descriptor]
    " + + if(!istype(machine)) + + dat += "[use_He_is] currently [psi.suppressed ? "suppressing" : "not suppressing"] your psychic operancy.
    " + dat += "[use_He_has] [psi.stamina]/[psi.max_stamina] psi stamina remaining.
    " + dat += "
    " + + for(var/faculty_id in psi.ranks) + var/decl/psionic_faculty/faculty = SSpsi.get_faculty(faculty_id) + if(psi.ranks[faculty.id] > 0) + dat += "[use_He_is] assayed at the rank of [global.psychic_ranks_to_strings[psi.ranks[faculty.id]]] for the [faculty.name] faculty.
    " + else + dat += "[use_He_has] no notable power within the [faculty.name] faculty.
    " + dat += "
    " + + if(viewer == usr) + dat += "" + for(var/faculty_id in psi.ranks) + var/list/check_powers = psi.get_powers_by_faculty(faculty_id) + if(LAZYLEN(check_powers)) + var/decl/psionic_faculty/faculty = SSpsi.get_faculty(faculty_id) + dat += "" + for(var/decl/psionic_power/power in check_powers) + dat += "" + dat += "

    Psi-power Usage

    [use_He_has] access to the following psi-powers within the [faculty.name] faculty:
    [power.name][power.use_description]
    " + else + dat += "[use_He_has] no notable psychic latency or operancy." + + if(istype(machine)) + dat += "Print Clear Buffer" + machine.last_assay = dat + return + + var/interface_type = machine ? /datum/browser/written_digital : /datum/browser + var/datum/browser/popup = new interface_type(viewer, "psi_assay_\ref[src]", "Psi-Assay") + popup.set_content(jointext(dat,null)) + popup.open() diff --git a/mods/content/psionics/system/psionics/mob/mob_interactions.dm b/mods/content/psionics/system/psionics/mob/mob_interactions.dm new file mode 100644 index 000000000000..aba8eeb102c0 --- /dev/null +++ b/mods/content/psionics/system/psionics/mob/mob_interactions.dm @@ -0,0 +1,44 @@ +#define INVOKE_PSI_POWERS(holder, powers, target) \ + if(can_use()) { \ + for(var/decl/psionic_power/power as anything in powers) { \ + var/obj/item/result = power.invoke(user, target); \ + if(result) { \ + power.handle_post_power(user, target); \ + if(istype(result)) { \ + sound_to(user, sound('sound/effects/psi/power_evoke.ogg')); \ + } \ + return TRUE; \ + } \ + } \ + } \ + return FALSE; + +/datum/ability_handler/psionics/can_do_self_invocation(mob/user) + return TRUE + +/datum/ability_handler/psionics/do_self_invocation(mob/user) + INVOKE_PSI_POWERS(user, get_manifestations(), user) + +/datum/ability_handler/psionics/can_do_grabbed_invocation(mob/user, atom/target) + return TRUE + +/datum/ability_handler/psionics/do_grabbed_invocation(mob/user, atom/target) + INVOKE_PSI_POWERS(user, get_grab_powers(SSpsi.get_faculty_by_intent(user.get_intent())), target) + +/datum/ability_handler/psionics/can_do_melee_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(FALSE) + return TRUE + +/datum/ability_handler/psionics/do_melee_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(FALSE) + INVOKE_PSI_POWERS(user, get_melee_powers(SSpsi.get_faculty_by_intent(user.get_intent())), target) + +/datum/ability_handler/psionics/can_do_ranged_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(FALSE) + return TRUE + +/datum/ability_handler/psionics/do_ranged_invocation(mob/user, atom/target) + SHOULD_CALL_PARENT(FALSE) + INVOKE_PSI_POWERS(user, get_ranged_powers(SSpsi.get_faculty_by_intent(user.get_intent())), target) + +#undef INVOKE_PSI_POWERS diff --git a/mods/psionics/system/psionics/null/_null.dm b/mods/content/psionics/system/psionics/null/_null.dm similarity index 100% rename from mods/psionics/system/psionics/null/_null.dm rename to mods/content/psionics/system/psionics/null/_null.dm diff --git a/mods/content/psionics/system/psionics/null/flooring.dm b/mods/content/psionics/system/psionics/null/flooring.dm new file mode 100644 index 000000000000..581466a484e1 --- /dev/null +++ b/mods/content/psionics/system/psionics/null/flooring.dm @@ -0,0 +1,20 @@ +/decl/flooring + var/psi_null + +/decl/flooring/proc/is_psi_null() + return psi_null + +/decl/flooring/tiling/nullglass + name = "nullglass plating" + desc = "You can hear the tiles whispering..." + icon_base = "nullglass" + color = COLOR_NULLGLASS + flooring_flags = TURF_REMOVE_SCREWDRIVER + build_type = /obj/item/stack/tile/floor_nullglass + psi_null = TRUE + uid = "floor_tiled_nullglass" + +/obj/item/stack/tile/floor_nullglass + name = "nullglass floor tile" + icon_state = "tile_nullglass" + material = /decl/material/nullglass diff --git a/mods/content/psionics/system/psionics/null/material.dm b/mods/content/psionics/system/psionics/null/material.dm new file mode 100644 index 000000000000..e28146d5b44a --- /dev/null +++ b/mods/content/psionics/system/psionics/null/material.dm @@ -0,0 +1,32 @@ +/decl/material + var/is_psionic_nullifier + +/decl/material/proc/is_psi_null() + return is_psionic_nullifier + +/decl/material/nullglass + name = "nullglass" + color = COLOR_NULLGLASS + conductive = 1 + flags = MAT_FLAG_BRITTLE + opacity = 0.5 + integrity = 30 + shard_name = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 80 + weight = MAT_VALUE_HEAVY + door_icon_base = "stone" + destruction_desc = "shatters" + destruction_sound = "shatter" + hitsound = 'sound/effects/Glasshit.ogg' + is_psionic_nullifier = TRUE + exoplanet_rarity_plant = MAT_RARITY_EXOTIC + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + uid = "solid_nullglass" + +/obj/item/shard/nullglass + material = /decl/material/nullglass + +/decl/stack_recipe/tile/nullglass + result_type = /obj/item/stack/tile/floor_nullglass + required_material = /decl/material/nullglass diff --git a/mods/psionics/system/psionics/null/material_sheet.dm b/mods/content/psionics/system/psionics/null/material_sheet.dm similarity index 93% rename from mods/psionics/system/psionics/null/material_sheet.dm rename to mods/content/psionics/system/psionics/null/material_sheet.dm index 707185332a3a..d30c732c86b2 100644 --- a/mods/psionics/system/psionics/null/material_sheet.dm +++ b/mods/content/psionics/system/psionics/null/material_sheet.dm @@ -15,7 +15,7 @@ name = "nullglass" icon_state = "sheet-shiny" plural_icon_state = "sheet-shiny-mult" - material = MAT_NULLGLASS + material = /decl/material/nullglass /obj/item/stack/material/nullglass/fifty amount = 50 diff --git a/mods/content/psionics/system/psionics/null/turf_floor.dm b/mods/content/psionics/system/psionics/null/turf_floor.dm new file mode 100644 index 000000000000..f13498b21cc0 --- /dev/null +++ b/mods/content/psionics/system/psionics/null/turf_floor.dm @@ -0,0 +1,8 @@ +/turf/floor/disrupts_psionics() + var/decl/flooring/flooring = get_topmost_flooring() + return (flooring && flooring.is_psi_null()) ? src : ..() + +/turf/floor/tiled/nullglass + name = "nullglass floor" + icon_state = "nullglass" + _flooring = /decl/flooring/tiling/nullglass diff --git a/mods/content/psionics/system/psionics/null/turf_wall.dm b/mods/content/psionics/system/psionics/null/turf_wall.dm new file mode 100644 index 000000000000..78fd69b292ca --- /dev/null +++ b/mods/content/psionics/system/psionics/null/turf_wall.dm @@ -0,0 +1,18 @@ +/turf/wall/disrupts_psionics() + return ((material && material.is_psi_null()) || (reinf_material && reinf_material.is_psi_null())) ? src : ..() + +/turf/wall/withstand_psi_stress(var/stress, var/atom/source) + . = ..(stress, source) + if(. > 0 && disrupts_psionics()) + var/cap = material.integrity + if(reinf_material) cap += reinf_material.integrity + var/stress_total = damage + . + take_damage(., PSIONIC) + . = max(0, -(cap-stress_total)) + +/turf/wall/nullglass + color = "#ff6088" + +/turf/wall/nullglass/Initialize(ml) + color = null + . = ..(ml, /decl/material/nullglass) diff --git a/mods/psionics/system/psionics/null/~null.dm b/mods/content/psionics/system/psionics/null/~null.dm similarity index 100% rename from mods/psionics/system/psionics/null/~null.dm rename to mods/content/psionics/system/psionics/null/~null.dm diff --git a/mods/content/psionics/system/subsystem_psi.dm b/mods/content/psionics/system/subsystem_psi.dm new file mode 100644 index 000000000000..e6621835ce9d --- /dev/null +++ b/mods/content/psionics/system/subsystem_psi.dm @@ -0,0 +1,49 @@ +var/global/list/psychic_ranks_to_strings = list("Latent", "Operant", "Masterclass", "Grandmasterclass", "Paramount") + +PROCESSING_SUBSYSTEM_DEF(psi) + name = "Psychics" + priority = SS_PRIORITY_PSYCHICS + flags = SS_POST_FIRE_TIMING | SS_BACKGROUND + + var/list/faculties_by_id = list() + var/list/faculties_by_name = list() + var/list/all_aura_images = list() + var/list/psi_dampeners = list() + var/list/psi_monitors = list() + var/list/armour_faculty_by_type = list() + var/list/faculties_by_intent = new(I_FLAG_ALL) + +/datum/controller/subsystem/processing/psi/proc/get_faculty_by_intent(decl/intent/intent) + var/static/list/intent_flags = list( + I_FLAG_HELP, + I_FLAG_DISARM, + I_FLAG_GRAB, + I_FLAG_HARM + ) + . = faculties_by_intent[intent.intent_flags] + if(!.) + for(var/flag in intent_flags) + if(flag & intent.intent_flags) + . = faculties_by_intent[flag] + faculties_by_intent[intent.intent_flags] = . + +/datum/controller/subsystem/processing/psi/proc/get_faculty(var/faculty) + return faculties_by_name[faculty] || faculties_by_id[faculty] + +/datum/controller/subsystem/processing/psi/Initialize() + . = ..() + + var/list/faculties = decls_repository.get_decls_of_subtype(/decl/psionic_faculty) + for(var/ftype in faculties) + var/decl/psionic_faculty/faculty = faculties[ftype] + faculties_by_id[faculty.id] = faculty + faculties_by_name[faculty.name] = faculty + faculties_by_intent[faculty.associated_intent_flag] = faculty.id + + var/list/powers = decls_repository.get_decls_of_subtype(/decl/psionic_power) + for(var/ptype in powers) + var/decl/psionic_power/power = powers[ptype] + if(power.faculty) + var/decl/psionic_faculty/faculty = get_faculty(power.faculty) + if(faculty) + faculty.powers |= power diff --git a/mods/content/response_team/_response_team.dm b/mods/content/response_team/_response_team.dm new file mode 100644 index 000000000000..e3cc2a1d78b2 --- /dev/null +++ b/mods/content/response_team/_response_team.dm @@ -0,0 +1,8 @@ +/decl/modpack/response_team + name = "Emergency Response Teams" + +/decl/modpack/response_team/pre_initialize() + global.admin_verbs_admin += /client/proc/response_team // Response Teams admin verb + for(var/client/client in global.admins) + client.add_admin_verbs() // refresh admin verbs. verbs are deduplicated so this is fine. todo: centralized modpack system for this + . = ..() \ No newline at end of file diff --git a/mods/content/response_team/_response_team.dme b/mods/content/response_team/_response_team.dme new file mode 100644 index 000000000000..a78e1496132e --- /dev/null +++ b/mods/content/response_team/_response_team.dme @@ -0,0 +1,18 @@ +// BEGIN_INCLUDE +#ifndef MODPACK_RESPONSE_TEAM +#define MODPACK_RESPONSE_TEAM +#include "_response_team.dm" +#include "ert_gear.dm" +#include "ert_rig.dm" +#include "game_mode_overrides.dm" +#include "response_team.dm" +#include "trader_overrides.dm" +#include "datum\ert_call_keycard_event.dm" +#include "datum\ert_camera_monitor.dm" +#include "datum\ert_config.dm" +#include "datum\ert_outfit.dm" +#include "datum\ert_special_role.dm" +#include "datum\spec_ops_outfit.dm" +#include "maps\ert_base.dm" +#endif +// END_INCLUDE \ No newline at end of file diff --git a/mods/content/response_team/datum/ert_call_keycard_event.dm b/mods/content/response_team/datum/ert_call_keycard_event.dm new file mode 100644 index 000000000000..87a1644b488e --- /dev/null +++ b/mods/content/response_team/datum/ert_call_keycard_event.dm @@ -0,0 +1,16 @@ +/decl/keycard_auth_event/call_ert + name = "Emergency Response Team" + uid = "keycard_event_call_ert" + +/decl/keycard_auth_event/call_ert/is_available(obj/machinery/keycard_auth/auth, mob/user) + if(get_config_value(/decl/config/toggle/ert_admin_call_only)) + return FALSE + return TRUE + +/decl/keycard_auth_event/call_ert/on_event(obj/machinery/keycard_auth/auth) + if(!SSticker.mode || SSticker.mode.ert_disabled) // disabled by mode + auth.visible_message(SPAN_WARNING("\The [src] blinks and displays a message: All emergency response teams are dispatched and can not be called at this time."), range=2) + return + + trigger_armed_response_team(1) + SSstatistics.add_field("alert_keycard_auth_ert",1) \ No newline at end of file diff --git a/mods/content/response_team/datum/ert_camera_monitor.dm b/mods/content/response_team/datum/ert_camera_monitor.dm new file mode 100644 index 000000000000..f4ef8194e871 --- /dev/null +++ b/mods/content/response_team/datum/ert_camera_monitor.dm @@ -0,0 +1,33 @@ +// ERT camera monitor +/datum/computer_file/program/camera_monitor/ert + filename = "ntcammon" + filedesc = "Advanced Camera Monitoring" + extended_desc = "This program allows remote access to a camera system. This version has an integrated database with additional encryption keys." + size = 14 + nanomodule_path = /datum/nano_module/program/camera_monitor/ert + available_on_network = FALSE + +/datum/nano_module/program/camera_monitor/ert + name = "ERT Camera Monitoring program" + +/datum/nano_module/program/camera_monitor/ert/get_forbidden_channels() + var/static/list/forbidden_channels = list( + (CAMERA_CHANNEL_MERCENARY) + ) + return forbidden_channels + +/datum/nano_module/program/camera_monitor/ert + name = "Advanced Camera Monitoring Program" + available_to_ai = FALSE + bypass_access = TRUE + +// ERT program ignores network connection requirement. +/datum/nano_module/program/camera_monitor/ert/can_connect_to_camera(datum/extension/network_device/camera/camera_device) + if(!camera_device) + return FALSE + if(!camera_device.is_functional()) + return FALSE + return TRUE + +/datum/nano_module/program/camera_monitor/ert/get_cameras_by_channel() + return camera_repository.get_devices_by_channel() \ No newline at end of file diff --git a/mods/content/response_team/datum/ert_config.dm b/mods/content/response_team/datum/ert_config.dm new file mode 100644 index 000000000000..2632497590d1 --- /dev/null +++ b/mods/content/response_team/datum/ert_config.dm @@ -0,0 +1,11 @@ +/decl/configuration_category/response_team + name = "Response Team" + desc = "Configuration options relating to emergency response teams." + configuration_file_location = "config/gamemodes/ert.txt" + associated_configuration = list( + /decl/config/toggle/ert_admin_call_only + ) + +/decl/config/toggle/ert_admin_call_only + uid = "ert_admin_call_only" + desc = "Restricted ERT to be only called by admins." \ No newline at end of file diff --git a/mods/content/response_team/datum/ert_outfit.dm b/mods/content/response_team/datum/ert_outfit.dm new file mode 100644 index 000000000000..e75f47ee3496 --- /dev/null +++ b/mods/content/response_team/datum/ert_outfit.dm @@ -0,0 +1,13 @@ +/decl/outfit/ert + name = "Spec Ops - Emergency response team" + uniform = /obj/item/clothing/pants/casual/camo/outfit_combat + shoes = /obj/item/clothing/shoes/jackboots/swat + gloves = /obj/item/clothing/gloves/thick/swat + l_ear = /obj/item/radio/headset/specops/ert + belt = /obj/item/gun/energy/gun + glasses = /obj/item/clothing/glasses/sunglasses + back = /obj/item/backpack/satchel + pda_type = /obj/item/modular_computer/pda/ert + + id_slot = slot_wear_id_str + id_type = /obj/item/card/id/centcom/ERT \ No newline at end of file diff --git a/mods/content/response_team/datum/ert_special_role.dm b/mods/content/response_team/datum/ert_special_role.dm new file mode 100644 index 000000000000..439d9f7f23bc --- /dev/null +++ b/mods/content/response_team/datum/ert_special_role.dm @@ -0,0 +1,41 @@ +/decl/special_role/ert + name = "Emergency Responder" + name_plural = "Emergency Responders" + antag_text = "You are an anti antagonist! Within the rules, \ + try to save the installation and its inhabitants from the ongoing crisis. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to the ERT." + welcome_text = "You shouldn't see this" + leader_welcome_text = "You shouldn't see this" + landmark_id = "Response Team" + + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED + antaghud_indicator = "hudloyalist" + default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage) + + hard_cap = 5 + hard_cap_round = 7 + initial_spawn_req = 5 + initial_spawn_target = 7 + show_objectives_on_creation = 0 //we are not antagonists, we do not need the antagonist shpiel/objectives + default_outfit = /decl/outfit/ert + + base_to_load = "ERT Base" + +/decl/special_role/ert/create_default(var/mob/source) + var/mob/living/human/M = ..() + if(istype(M)) + M.set_age(rand(25,45)) + +/decl/special_role/ert/Initialize() + . = ..() + leader_welcome_text = "As leader of the Emergency Response Team, you answer only to [global.using_map.company_name], and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however." + welcome_text = "As member of the Emergency Response Team, you answer only to your leader and [global.using_map.company_name] officials." + +/decl/special_role/ert/greet(var/datum/mind/player) + if(!..()) + return + to_chat(player.current, "The Emergency Response Team works for Asset Protection; your job is to protect [global.using_map.company_name]'s ass-ets. There is a code red alert on [station_name()], you are tasked to go and fix the problem.") + to_chat(player.current, "You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready.") diff --git a/mods/content/response_team/datum/spec_ops_outfit.dm b/mods/content/response_team/datum/spec_ops_outfit.dm new file mode 100644 index 000000000000..d74ccce2da99 --- /dev/null +++ b/mods/content/response_team/datum/spec_ops_outfit.dm @@ -0,0 +1,25 @@ +/decl/outfit/spec_op_officer + name = "Spec Ops - Officer" + uniform = /obj/item/clothing/pants/casual/camo/outfit_combat + suit = /obj/item/clothing/suit/armor/officer + l_ear = /obj/item/radio/headset/specops/ert + glasses = /obj/item/clothing/glasses/thermal/plain/eyepatch + mask = /obj/item/clothing/mask/smokable/cigarette/cigar/havana + head = /obj/item/clothing/head/beret + belt = /obj/item/gun/energy/pulse_pistol + back = /obj/item/backpack/satchel + shoes = /obj/item/clothing/shoes/jackboots/swat/combat + gloves = /obj/item/clothing/gloves/thick/combat + + id_slot = slot_wear_id_str + id_type = /obj/item/card/id/centcom/ERT + id_desc = "Special operations ID." + id_pda_assignment = "Special Operations Officer" + +/decl/outfit/spec_op_officer/space + name = "Spec Ops - Officer in space" + suit = /obj/item/clothing/suit/space/void/swat + back = /obj/item/tank/jetpack/oxygen + mask = /obj/item/clothing/mask/gas/swat + + outfit_flags = OUTFIT_HAS_JETPACK|OUTFIT_RESET_EQUIPMENT \ No newline at end of file diff --git a/mods/content/response_team/ert_gear.dm b/mods/content/response_team/ert_gear.dm new file mode 100644 index 000000000000..d5311230b2fb --- /dev/null +++ b/mods/content/response_team/ert_gear.dm @@ -0,0 +1,69 @@ +//ERT backpacks. +/obj/item/backpack/ert + name = "emergency response team backpack" + desc = "A spacious backpack with lots of pockets, used by members of the Emergency Response Team." + icon = 'mods/content/response_team/icons/backpack_ert.dmi' + var/marking_state + var/marking_colour + +/obj/item/backpack/ert/on_update_icon() + . = ..() + if(marking_state) + var/image/I = image(icon, marking_state) + I.color = marking_colour + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/backpack/ert/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && slot == slot_back_str && marking_state) + var/image/I = image(overlay.icon, "[overlay.icon_state]-[marking_state]") + I.color = marking_colour + I.appearance_flags |= RESET_COLOR + overlay.add_overlay(I) + . = ..() + +/obj/item/backpack/ert/commander + name = "emergency response team commander backpack" + desc = "A spacious backpack with lots of pockets, worn by the commander of an Emergency Response Team." + marking_colour = COLOR_BLUE_GRAY + marking_state = "com" + +/obj/item/backpack/ert/security + name = "emergency response team security backpack" + desc = "A spacious backpack with lots of pockets, worn by security members of an Emergency Response Team." + marking_colour = COLOR_NT_RED + marking_state = "sec" + +/obj/item/backpack/ert/engineer + name = "emergency response team engineer backpack" + desc = "A spacious backpack with lots of pockets, worn by engineering members of an Emergency Response Team." + marking_colour = COLOR_GOLD + marking_state = "eng" + +/obj/item/backpack/ert/medical + name = "emergency response team medical backpack" + desc = "A spacious backpack with lots of pockets, worn by medical members of an Emergency Response Team." + marking_colour = COLOR_OFF_WHITE + marking_state = "med" + +//ERT PDA preset +/obj/item/modular_computer/pda/ert + color = COLOR_OFF_WHITE + decals = list( + "stripe" = COLOR_DARK_BLUE_GRAY, + "stripe2" = COLOR_GOLD + ) + +//ERT headsets +/obj/item/encryptionkey/specops/ert + name = "\improper ERT radio encryption key" + can_decrypt = list(access_cent_specops) + +/obj/item/radio/headset/specops/ert + name = "emergency response team radio headset" + desc = "The headset of the boss's boss." + icon = 'icons/obj/items/device/radio/headsets/headset_admin.dmi' + encryption_keys = list(/obj/item/encryptionkey/specops/ert) + +/obj/item/radio/borg/ert + encryption_keys = list(/obj/item/encryptionkey/specops/ert) \ No newline at end of file diff --git a/mods/content/response_team/ert_rig.dm b/mods/content/response_team/ert_rig.dm new file mode 100644 index 000000000000..353590e005f4 --- /dev/null +++ b/mods/content/response_team/ert_rig.dm @@ -0,0 +1,219 @@ +/obj/item/rig/ert + name = "emergency response command hardsuit control module" + desc = "A hardsuit used by many corporate and governmental emergency response forces. Has blue highlights. Armoured and space ready." + suit_type = "emergency response command" + icon = 'icons/clothing/rigs/ert/commander/rig.dmi' + + chest = /obj/item/clothing/suit/space/rig/ert + helmet = /obj/item/clothing/head/helmet/space/rig/ert + boots = /obj/item/clothing/shoes/magboots/rig/ert + gloves = /obj/item/clothing/gloves/rig/ert + + req_access = list(access_cent_specops) + + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_MAJOR, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + allowed = list( + /obj/item/flashlight, + /obj/item/tank, + /obj/item/ammo_magazine, + /obj/item/ammo_casing, + /obj/item/handcuffs, + /obj/item/t_scanner, + /obj/item/rcd, + /obj/item/crowbar, + /obj/item/screwdriver, + /obj/item/weldingtool, + /obj/item/wirecutters, + /obj/item/wrench, + /obj/item/multitool, + /obj/item/radio, + /obj/item/scanner/gas, + /obj/item/briefcase/inflatable, + /obj/item/baton, + /obj/item/gun, + /obj/item/firstaid, + /obj/item/chems/hypospray, + /obj/item/roller + ) + + initial_modules = list( + /obj/item/rig_module/ai_container, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/datajack, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/ert + camera = /obj/machinery/camera/network/ert + icon = 'icons/clothing/rigs/ert/commander/helmet.dmi' +/obj/item/clothing/suit/space/rig/ert + icon = 'icons/clothing/rigs/ert/commander/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/ert + icon = 'icons/clothing/rigs/ert/commander/boots.dmi' +/obj/item/clothing/gloves/rig/ert + item_flags = ITEM_FLAG_THICKMATERIAL | ITEM_FLAG_NOCUFFS + icon = 'icons/clothing/rigs/ert/commander/gloves.dmi' + +/obj/item/rig/ert/engineer + name = "emergency response engineering hardsuit control module" + desc = "A hardsuit used by many corporate and governmental emergency response forces. Has orange highlights. Armoured and space ready." + suit_type = "emergency response engineer" + icon = 'icons/clothing/rigs/ert/engineer/rig.dmi' + + chest = /obj/item/clothing/suit/space/rig/ert/engineer + helmet = /obj/item/clothing/head/helmet/space/rig/ert/engineer + boots = /obj/item/clothing/shoes/magboots/rig/ert/engineer + gloves = /obj/item/clothing/gloves/rig/ert/engineer + + initial_modules = list( + /obj/item/rig_module/ai_container, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/mounted/plasmacutter, + /obj/item/rig_module/device/rcd, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/ert/engineer + icon = 'icons/clothing/rigs/ert/engineer/helmet.dmi' +/obj/item/clothing/suit/space/rig/ert/engineer + icon = 'icons/clothing/rigs/ert/engineer/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/ert/engineer + icon = 'icons/clothing/rigs/ert/engineer/boots.dmi' +/obj/item/clothing/gloves/rig/ert/engineer + icon = 'icons/clothing/rigs/ert/engineer/gloves.dmi' + siemens_coefficient = 0 + +/obj/item/rig/ert/janitor + name = "emergency response sanitation hardsuit control module" + desc = "A hardsuit used by many corporate and governmental emergency response forces. Has purple highlights. Armoured and space ready." + suit_type = "emergency response sanitation" + icon = 'icons/clothing/rigs/ert/janitor/rig.dmi' + + chest = /obj/item/clothing/suit/space/rig/ert/janitor + helmet = /obj/item/clothing/head/helmet/space/rig/ert/janitor + boots = /obj/item/clothing/shoes/magboots/rig/ert/janitor + gloves = /obj/item/clothing/gloves/rig/ert/janitor + + initial_modules = list( + /obj/item/rig_module/ai_container, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/fabricator/wf_sign, + /obj/item/rig_module/grenade_launcher/cleaner, + /obj/item/rig_module/device/decompiler, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/ert/janitor + icon = 'icons/clothing/rigs/ert/janitor/helmet.dmi' +/obj/item/clothing/suit/space/rig/ert/janitor + icon = 'icons/clothing/rigs/ert/janitor/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/ert/janitor + icon = 'icons/clothing/rigs/ert/janitor/boots.dmi' +/obj/item/clothing/gloves/rig/ert/janitor + icon = 'icons/clothing/rigs/ert/janitor/gloves.dmi' + +/obj/item/rig/ert/medical + name = "emergency response medical hardsuit control module" + desc = "A hardsuit used by many corporate and governmental emergency response forces. Has white highlights. Armoured and space ready." + suit_type = "emergency response medic" + icon = 'icons/clothing/rigs/ert/medic/rig.dmi' + + chest = /obj/item/clothing/suit/space/rig/ert/medical + helmet = /obj/item/clothing/head/helmet/space/rig/ert/medical + boots = /obj/item/clothing/shoes/magboots/rig/ert/medical + gloves = /obj/item/clothing/gloves/rig/ert/medical + + initial_modules = list( + /obj/item/rig_module/ai_container, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/device/healthscanner, + /obj/item/rig_module/chem_dispenser/injector, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/ert/medical + icon = 'icons/clothing/rigs/ert/medic/helmet.dmi' +/obj/item/clothing/suit/space/rig/ert/medical + icon = 'icons/clothing/rigs/ert/medic/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/ert/medical + icon = 'icons/clothing/rigs/ert/medic/boots.dmi' +/obj/item/clothing/gloves/rig/ert/medical + icon = 'icons/clothing/rigs/ert/medic/gloves.dmi' + +/obj/item/rig/ert/security + name = "emergency response security hardsuit control module" + desc = "A hardsuit used by many corporate and governmental emergency response forces. Has red highlights. Armoured and space ready." + suit_type = "emergency response security" + icon = 'icons/clothing/rigs/ert/security/rig.dmi' + initial_modules = list( + /obj/item/rig_module/ai_container, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/grenade_launcher, + /obj/item/rig_module/mounted/egun, + /obj/item/rig_module/cooling_unit + ) + + chest = /obj/item/clothing/suit/space/rig/ert/security + helmet = /obj/item/clothing/head/helmet/space/rig/ert/security + boots = /obj/item/clothing/shoes/magboots/rig/ert/security + gloves = /obj/item/clothing/gloves/rig/ert/security + +/obj/item/clothing/head/helmet/space/rig/ert/security + icon = 'icons/clothing/rigs/ert/security/helmet.dmi' +/obj/item/clothing/suit/space/rig/ert/security + icon = 'icons/clothing/rigs/ert/security/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/ert/security + icon = 'icons/clothing/rigs/ert/security/boots.dmi' +/obj/item/clothing/gloves/rig/ert/security + icon = 'icons/clothing/rigs/ert/security/gloves.dmi' + +/obj/item/rig/ert/assetprotection + name = "heavy emergency response suit control module" + desc = "A heavy, modified version of a common emergency response hardsuit. Has blood red highlights. Armoured and space ready." + suit_type = "heavy emergency response" + icon = 'icons/clothing/rigs/ert/asset_protection/rig.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_MAJOR, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + + chest = /obj/item/clothing/suit/space/rig/ert/assetprotection + helmet = /obj/item/clothing/head/helmet/space/rig/ert/assetprotection + boots = /obj/item/clothing/shoes/magboots/rig/ert/assetprotection + gloves = /obj/item/clothing/gloves/rig/ert/assetprotection + + initial_modules = list( + /obj/item/rig_module/ai_container, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/grenade_launcher, + /obj/item/rig_module/vision/multi, + /obj/item/rig_module/mounted/egun, + /obj/item/rig_module/chem_dispenser/combat, + /obj/item/rig_module/mounted/plasmacutter, + /obj/item/rig_module/device/rcd, + /obj/item/rig_module/datajack, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/ert/assetprotection + icon = 'icons/clothing/rigs/ert/asset_protection/helmet.dmi' +/obj/item/clothing/suit/space/rig/ert/assetprotection + icon = 'icons/clothing/rigs/ert/asset_protection/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/ert/assetprotection + icon = 'icons/clothing/rigs/ert/asset_protection/boots.dmi' +/obj/item/clothing/gloves/rig/ert/assetprotection + icon = 'icons/clothing/rigs/ert/asset_protection/gloves.dmi' + siemens_coefficient = 0 diff --git a/mods/content/response_team/game_mode_overrides.dm b/mods/content/response_team/game_mode_overrides.dm new file mode 100644 index 000000000000..38c8390e7d9f --- /dev/null +++ b/mods/content/response_team/game_mode_overrides.dm @@ -0,0 +1,64 @@ +/decl/game_mode + /// If TRUE, ERT cannot be called during this mode. + var/ert_disabled = FALSE + +/decl/game_mode/toggle_value(key) + if((. = ..())) + return + switch(key) + if("ert") + ert_disabled = !ert_disabled + announce_ert_disabled() + return TRUE + +/decl/game_mode/post_setup() + . = ..() + addtimer(CALLBACK(src, PROC_REF(announce_ert_disabled)), rand_waittime + rand(10 SECONDS, 15 SECONDS)) + +/// Gets a list of default reasons for the ERT to be disabled. +/decl/game_mode/proc/possible_ert_disabled_reasons() + // This uses a static var so that modpacks can add default reasons, e.g. "supermatter dust". + var/static/list/reasons = list( + "political instability", + "quantum fluctuations", + "hostile raiders", + "derelict station debris", + "REDACTED", + "ancient alien artillery", + "solar magnetic storms", + "sentient time-travelling killbots", + "gravitational anomalies", + "wormholes to another dimension", + "a telescience mishap", + "radiation flares", + "leaks into a negative reality", + "antiparticle clouds", + "residual exotic energy", + "suspected criminal operatives", + "malfunctioning von Neumann probe swarms", + "shadowy interlopers", + "a stranded xenoform", + "haywire machine constructs", + "rogue exiles", + "artifacts of eldritch horror", + "a brain slug infestation", + "killer bugs that lay eggs in the husks of the living", + "a deserted transport carrying xenofauna specimens", + "an emissary requesting a security detail", + "radical transevolutionaries", + "classified security operations", + "a gargantuan glowing goat" + ) + return reasons + +/decl/game_mode/proc/announce_ert_disabled() + if(!ert_disabled) + return + command_announcement.Announce("The presence of [pick(possible_ert_disabled_reasons())] in the region is tying up all available local emergency resources; emergency response teams cannot be called at this time, and post-evacuation recovery efforts will be substantially delayed.","Emergency Transmission") + +// add this as an option +/datum/controller/subsystem/ticker/get_game_mode_options() + var/list/options = ..() + // insert it at the start because it's important i guess + options.Insert(1, "Emergency Response Teams: [mode.ert_disabled ? "disabled" : "enabled"]") + return options \ No newline at end of file diff --git a/icons/obj/items/storage/backpack/backpack_ert.dmi b/mods/content/response_team/icons/backpack_ert.dmi similarity index 100% rename from icons/obj/items/storage/backpack/backpack_ert.dmi rename to mods/content/response_team/icons/backpack_ert.dmi diff --git a/mods/content/response_team/maps/ert_base.dm b/mods/content/response_team/maps/ert_base.dm new file mode 100644 index 000000000000..38ed2242ec83 --- /dev/null +++ b/mods/content/response_team/maps/ert_base.dm @@ -0,0 +1,79 @@ +/datum/map_template/ruin/antag_spawn/ert + name = "ERT Base" + prefix = "mods/content/response_team/maps/" + suffixes = list("ert_base.dmm") + modify_tag_vars = FALSE + shuttles_to_initialise = list(/datum/shuttle/autodock/multi/antag/rescue) + apc_test_exempt_areas = list( + /area/map_template/rescue_base = NO_SCRUBBER|NO_VENT|NO_APC + ) + +/obj/machinery/network/telecomms_hub/ert + req_access = list(access_cent_specops) + initial_network_id = "responsenet" + channels = list( + COMMON_FREQUENCY_DATA, + list( + "name" = "Response", + "key" = "t", + "frequency" = 1345, + "color" = COMMS_COLOR_CENTCOMM, + "span_class" = ".centradio", + "secured" = access_cent_specops + ) + ) + +/datum/shuttle/autodock/multi/antag/rescue + name = "Rescue" + warmup_time = 0 + defer_initialisation = TRUE + destination_tags = list( + "nav_ert_start" + ) + shuttle_area = /area/map_template/rescue_base/start + dock_target = "ert_rescue_shuttle" + current_location = "nav_ert_start" + home_waypoint = "nav_ert_start" + announcer = "Proximity Sensor Array" + arrival_message = "Attention, vessel detected entering vessel proximity." + departure_message = "Attention, vessel detected leaving vessel proximity." + +/obj/effect/shuttle_landmark/ert/start + name = "Response Team Base" + landmark_tag = "nav_ert_start" + docking_controller = "ert_rescue_base" + +/obj/machinery/camera/network/ert + preset_channels = list(CAMERA_CHANNEL_ERT) + cameranet_enabled = FALSE + req_access = list(access_engine) + +/obj/machinery/computer/modular/preset/full/ert + default_software = list( + /datum/computer_file/program/camera_monitor/ert, + /datum/computer_file/program/email_client, + /datum/computer_file/program/alarm_monitor, + /datum/computer_file/program/comm, + /datum/computer_file/program/aidiag, + /datum/computer_file/program/records, + /datum/computer_file/program/wordprocessor + ) + +// Areas + +/area/map_template/rescue_base + name = "\improper Response Team Base" + icon_state = "yellow" + requires_power = 0 + dynamic_lighting = TRUE + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED + +/area/map_template/rescue_base/base + name = "\improper Barracks" + icon_state = "yellow" + dynamic_lighting = FALSE + +/area/map_template/rescue_base/start + name = "\improper Response Team Base" + icon_state = "shuttlered" + base_turf = /turf/unsimulated/floor/rescue_base \ No newline at end of file diff --git a/mods/content/response_team/maps/ert_base.dmm b/mods/content/response_team/maps/ert_base.dmm new file mode 100644 index 000000000000..dbb532ffeb55 --- /dev/null +++ b/mods/content/response_team/maps/ert_base.dmm @@ -0,0 +1,5612 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ac" = ( +/turf/unsimulated/mineral, +/area/map_template/rescue_base/base) +"ad" = ( +/turf/unsimulated/wall, +/area/map_template/rescue_base/base) +"ae" = ( +/obj/machinery/computer/teleporter, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"af" = ( +/obj/machinery/teleport/station, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ag" = ( +/obj/machinery/teleport/hub, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ah" = ( +/turf/unsimulated/wall/airlock, +/area/map_template/rescue_base/base) +"ai" = ( +/obj/structure/table/steel_reinforced, +/obj/item/clothing/shoes/magboots/rig/combat, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aj" = ( +/obj/structure/table/steel_reinforced, +/obj/item/firstaid/regular, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ak" = ( +/obj/machinery/floodlight, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"al" = ( +/obj/structure/table/steel_reinforced, +/obj/item/box/bodybags, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"am" = ( +/obj/structure/table/steel_reinforced, +/obj/item/firstaid/surgery, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ao" = ( +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ap" = ( +/obj/machinery/door/airlock/centcom{ + name = "Emergency Insertion" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aq" = ( +/obj/structure/table/steel_reinforced, +/obj/item/taperecorder, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ar" = ( +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"as" = ( +/obj/structure/table/steel_reinforced, +/obj/item/bikehorn/rubberducky, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"au" = ( +/obj/structure/hygiene/toilet{ + pixel_y = 16 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"av" = ( +/obj/structure/hygiene/shower{ + dir = 4 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"aw" = ( +/obj/item/soap, +/obj/structure/hygiene/shower{ + pixel_y = 32 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"ax" = ( +/obj/structure/table/steel_reinforced, +/obj/item/assembly/mousetrap, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ay" = ( +/obj/structure/chair, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"az" = ( +/obj/structure/table/steel_reinforced, +/obj/item/baseball_bat/aluminium, +/obj/item/tool/axe/hatchet, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aB" = ( +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"aC" = ( +/obj/item/aiModule/reset, +/obj/item/aiModule/freeformcore, +/obj/item/aiModule/protectStation, +/obj/item/aiModule/quarantine, +/obj/item/aiModule/paladin, +/obj/item/aiModule/robocop, +/obj/item/aiModule/safeguard, +/obj/structure/rack, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aD" = ( +/obj/structure/rack, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/plastique, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aE" = ( +/obj/structure/rack, +/obj/item/gun/projectile/shotgun/pump, +/obj/item/gun/projectile/shotgun/pump, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aF" = ( +/obj/structure/rack, +/obj/item/box/ammo/stunshells, +/obj/item/box/ammo/stunshells, +/obj/item/box/ammo/beanbags, +/obj/item/box/ammo/beanbags, +/obj/item/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunammo, +/obj/item/box/ammo/shotgunshells, +/obj/item/box/ammo/shotgunshells, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aG" = ( +/obj/structure/rack, +/obj/item/gun/energy/gun/nuclear, +/obj/item/gun/energy/gun/nuclear, +/obj/item/gun/energy/gun/nuclear, +/obj/item/gun/energy/gun/nuclear, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aH" = ( +/obj/structure/table/steel_reinforced, +/obj/item/chems/syringe/drugs{ + pixel_x = 3; + pixel_y = -1 + }, +/obj/item/chems/syringe/drugs{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/chems/syringe/drugs{ + pixel_x = 3; + pixel_y = 9 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aI" = ( +/obj/structure/table/steel_reinforced, +/obj/item/belt/utility/full, +/obj/item/assembly/igniter, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aK" = ( +/obj/structure/mopbucket, +/obj/item/mop, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/structure/hygiene/sink/kitchen{ + pixel_y = 21 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aL" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aM" = ( +/obj/structure/table/reinforced, +/obj/machinery/chemical_dispenser/bar_soft/full, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aN" = ( +/obj/structure/table/reinforced, +/obj/machinery/chemical_dispenser/bar_alc/full, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/machinery/vending/boozeomat{ + pixel_y = 32 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aO" = ( +/obj/structure/closet/secure_closet/freezer/fridge, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aP" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/structure/closet/secure_closet/freezer/meat, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aQ" = ( +/obj/machinery/door/airlock/centcom{ + name = "Stall" + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"aR" = ( +/obj/structure/mirror, +/turf/unsimulated/wall, +/area/map_template/rescue_base/base) +"aS" = ( +/obj/machinery/door/airlock/centcom{ + name = "Showers" + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"aT" = ( +/obj/structure/rack, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aU" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aV" = ( +/obj/structure/rack, +/obj/item/stock_parts/circuitboard/borgupload, +/obj/item/stock_parts/circuitboard/aiupload{ + pixel_x = -3; + pixel_y = -3 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aW" = ( +/obj/structure/rack, +/obj/item/gun/projectile/automatic/smg, +/obj/item/gun/projectile/automatic/smg, +/obj/item/gun/projectile/automatic/smg, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"aX" = ( +/obj/machinery/door/airlock/centcom{ + name = "Processing" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"aZ" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ba" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/machinery/door/airlock/centcom{ + name = "Storage" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bb" = ( +/obj/machinery/door/airlock/centcom{ + name = "Head" + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"bc" = ( +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/rescue_base/base) +"bd" = ( +/obj/structure/rack, +/obj/item/gun/projectile/automatic/assault_rifle, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"be" = ( +/obj/structure/rack, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/head/helmet/ablative, +/obj/item/clothing/suit/armor/laserproof, +/obj/item/clothing/suit/armor/laserproof, +/obj/item/clothing/suit/armor/laserproof, +/obj/item/clothing/suit/armor/laserproof, +/obj/item/clothing/suit/armor/laserproof, +/obj/item/clothing/suit/armor/laserproof, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bf" = ( +/obj/structure/rack, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/obj/item/ammo_magazine/smg/rubber, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bg" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/plating, +/area/map_template/rescue_base/base) +"bh" = ( +/obj/structure/table/reinforced, +/obj/item/box/handcuffs, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bi" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bj" = ( +/obj/structure/bed, +/obj/item/bedsheet/orange, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bk" = ( +/obj/structure/hygiene/toilet{ + dir = 8 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bm" = ( +/obj/machinery/vending/dinnerware, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bn" = ( +/obj/structure/rack, +/obj/item/rig/ert/assetprotection, +/obj/item/rig/ert/assetprotection, +/obj/item/rig/ert/assetprotection, +/obj/item/rig/ert/assetprotection, +/obj/item/rig/ert/assetprotection, +/obj/item/rig/ert/assetprotection, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bo" = ( +/obj/structure/rack, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/head/helmet/ballistic, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/obj/item/clothing/suit/armor/bulletproof, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bp" = ( +/obj/structure/rack, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/obj/item/ammo_magazine/smg, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bq" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"br" = ( +/obj/structure/table/reinforced, +/obj/item/flash, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bt" = ( +/obj/machinery/door/airlock/centcom{ + name = "Cell 2" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bu" = ( +/obj/structure/rack, +/obj/item/lightreplacer, +/obj/item/lightreplacer, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bv" = ( +/obj/structure/rack, +/obj/item/clothing/shoes/galoshes, +/obj/item/clothing/head/bio_hood/janitor, +/obj/item/clothing/suit/bio_suit/janitor, +/obj/item/clothing/glasses/science, +/obj/item/clothing/shoes/galoshes, +/obj/item/clothing/head/bio_hood/janitor, +/obj/item/clothing/suit/bio_suit/janitor, +/obj/item/clothing/glasses/science, +/obj/item/chems/spray/plantbgone, +/obj/item/chems/spray/plantbgone, +/obj/item/box/lights/mixed, +/obj/item/box/lights/mixed, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/item/grenade/chem_grenade/cleaner, +/obj/effect/floor_decal/corner/blue/diagonal, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bw" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/machinery/microwave, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bx" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/chems/condiment/small/saltshaker{ + pixel_x = -3 + }, +/obj/item/chems/condiment/small/peppermill{ + pixel_x = 3 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"by" = ( +/obj/structure/table/reinforced, +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bz" = ( +/obj/effect/floor_decal/corner/blue/diagonal, +/obj/item/box/sinpockets, +/obj/structure/closet/secure_closet/freezer/kitchen, +/obj/item/chems/condiment/enzyme, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bA" = ( +/turf/unsimulated/floor/asteroid, +/area/map_template/rescue_base/base) +"bB" = ( +/turf/unsimulated/floor/asteroidplating, +/area/map_template/rescue_base/base) +"bC" = ( +/obj/structure/flora/bush/fullgrass, +/turf/unsimulated/floor/asteroidplating, +/area/map_template/rescue_base/base) +"bD" = ( +/obj/structure/rack, +/obj/item/gun/projectile/automatic/assault_rifle, +/obj/item/gun/projectile/automatic/assault_rifle, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bE" = ( +/obj/machinery/door/airlock/centcom{ + name = "Restricted Equipment" + }, +/obj/machinery/door/blast/regular{ + id_tag = "heavyrescue"; + name = "Restricted Equipment" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bF" = ( +/obj/structure/rack, +/obj/item/box/smokes, +/obj/item/box/smokes, +/obj/item/box/flashbangs, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bG" = ( +/obj/structure/table/reinforced, +/obj/item/camera, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bH" = ( +/obj/item/stool, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bI" = ( +/obj/structure/table, +/obj/item/paper, +/obj/item/pen, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bJ" = ( +/obj/machinery/door/airlock/centcom{ + name = "Galley" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bK" = ( +/obj/structure/flora/bush/fullgrass, +/turf/unsimulated/floor/asteroid, +/area/map_template/rescue_base/base) +"bL" = ( +/obj/structure/rack, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/obj/item/ammo_magazine/rifle, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bM" = ( +/obj/structure/rack, +/obj/item/gun/launcher/grenade, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bN" = ( +/obj/structure/rack, +/obj/item/box/teargas, +/obj/item/box/teargas, +/obj/item/box/emps, +/obj/item/box/emps, +/obj/item/box/frags, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bO" = ( +/obj/structure/closet{ + name = "emergency response team wardrobe" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bP" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/captain, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bQ" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/captain, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bR" = ( +/obj/machinery/vending/coffee{ + markup = 0 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bS" = ( +/obj/machinery/door/airlock/centcom{ + name = "Heavy Equipment" + }, +/obj/machinery/door/blast/regular{ + id_tag = "standardrescue"; + name = "Heavy Equipment" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bT" = ( +/obj/machinery/door/airlock/centcom{ + name = "Detention" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bU" = ( +/obj/machinery/acting/changer, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bV" = ( +/obj/abstract/landmark{ + name = "Response Team" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bW" = ( +/obj/machinery/door/airlock/centcom{ + name = "Squad Bay" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bX" = ( +/obj/machinery/door/airlock/centcom{ + name = "Cell 1" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"bY" = ( +/obj/structure/undies_wardrobe, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"bZ" = ( +/obj/item/clothing/shoes/color/orange, +/obj/item/clothing/jumpsuit/orange, +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ca" = ( +/obj/structure/table/reinforced, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cb" = ( +/obj/machinery/door/airlock/centcom{ + name = "Ready Room" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cc" = ( +/obj/structure/rack, +/obj/item/box/handcuffs, +/obj/item/box/handcuffs, +/obj/item/box/teargas, +/obj/item/box/teargas, +/obj/item/box/flashbangs, +/obj/item/box/flashbangs, +/obj/item/flash, +/obj/item/flash, +/obj/item/baton/loaded, +/obj/item/baton/loaded, +/obj/item/chems/spray/pepper, +/obj/item/chems/spray/pepper, +/obj/item/telebaton, +/obj/item/telebaton, +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = 32 + }, +/obj/item/stack/tape_roll/barricade_tape/police, +/obj/item/stack/tape_roll/barricade_tape/police, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cd" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/glasses/night, +/obj/item/clothing/glasses/night, +/obj/item/clothing/glasses/tacgoggles, +/obj/item/clothing/glasses/tacgoggles, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ce" = ( +/obj/structure/rack, +/obj/item/backpack/ert/security, +/obj/item/backpack/ert/security, +/obj/item/belt/holster/security/tactical, +/obj/item/belt/holster/security/tactical, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cf" = ( +/obj/structure/rack, +/obj/item/gun/energy/gun/nuclear, +/obj/item/gun/energy/gun/nuclear, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cg" = ( +/obj/structure/rack, +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = 32 + }, +/obj/item/clothing/suit/armor/pcarrier/medium, +/obj/item/clothing/suit/armor/pcarrier/medium, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ch" = ( +/obj/structure/rack, +/obj/item/clothing/suit/armor/pcarrier/medium, +/obj/item/clothing/suit/armor/pcarrier/medium, +/obj/item/clothing/head/helmet, +/obj/item/clothing/head/helmet, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ci" = ( +/obj/structure/rack, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cj" = ( +/obj/structure/rack, +/obj/item/backpack/ert/medical, +/obj/item/backpack/ert/medical, +/obj/item/belt/medical, +/obj/item/belt/medical, +/obj/item/belt/medical/emt, +/obj/item/belt/medical/emt, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ck" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/glasses/hud/health, +/obj/item/clothing/glasses/hud/health, +/obj/item/box/gloves, +/obj/item/box/gloves, +/obj/item/box/masks, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cl" = ( +/obj/structure/rack, +/obj/item/flash, +/obj/item/flash, +/obj/item/baton/loaded, +/obj/item/baton/loaded, +/obj/item/box/syringes, +/obj/item/box/syringes, +/obj/item/box/autoinjectors, +/obj/item/box/autoinjectors, +/obj/item/box/beakers, +/obj/item/box/beakers, +/obj/item/box/pillbottles, +/obj/item/box/pillbottles, +/obj/item/box/bodybags, +/obj/item/box/bodybags, +/obj/item/box/syringegun, +/obj/item/box/syringegun, +/obj/item/box/syringegun, +/obj/item/box/syringegun, +/obj/item/gun/launcher/syringe/rapid, +/obj/item/gun/launcher/syringe/rapid, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cm" = ( +/obj/structure/table/reinforced, +/obj/item/chems/hypospray, +/obj/item/chems/hypospray, +/obj/item/chems/hypospray, +/obj/item/chems/hypospray, +/obj/item/chems/hypospray, +/obj/item/chems/hypospray, +/obj/item/chems/glass/beaker/large, +/obj/item/chems/glass/bottle/stabilizer, +/obj/item/chems/glass/bottle/stabilizer, +/obj/item/chems/glass/bottle/stabilizer, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cn" = ( +/obj/structure/rack, +/obj/item/rig/ert/medical, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"co" = ( +/obj/structure/rack, +/obj/item/rig/ert/medical, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cp" = ( +/obj/structure/rack, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/maneuvering_jets, +/obj/item/rig_module/maneuvering_jets, +/obj/item/rig_module/chem_dispenser/injector, +/obj/item/rig_module/chem_dispenser/injector, +/obj/item/rig_module/device/healthscanner, +/obj/item/rig_module/device/healthscanner, +/obj/item/rig_module/vision/medhud, +/obj/item/rig_module/vision/medhud, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cq" = ( +/obj/structure/rack, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cs" = ( +/obj/structure/rack, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/maneuvering_jets, +/obj/item/rig_module/maneuvering_jets, +/obj/item/rig_module/mounted/egun, +/obj/item/rig_module/mounted/egun, +/obj/item/rig_module/chem_dispenser/combat, +/obj/item/rig_module/chem_dispenser/combat, +/obj/item/rig_module/grenade_launcher, +/obj/item/rig_module/vision/sechud, +/obj/item/rig_module/vision/sechud, +/obj/item/rig_module/device/flash, +/obj/item/rig_module/device/flash, +/obj/item/rig_module/mounted, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ct" = ( +/obj/structure/rack, +/obj/item/rig/ert/security, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cu" = ( +/obj/structure/rack, +/obj/item/rig/ert/security, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cv" = ( +/obj/machinery/hologram/holopad/longrange, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"cw" = ( +/obj/structure/rack, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cx" = ( +/obj/structure/rack, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/obj/item/gun/energy/laser, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cy" = ( +/obj/machinery/chemical_dispenser/medicine, +/obj/item/chems/glass/beaker/large, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cz" = ( +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/structure/rack, +/obj/item/rig/ert/janitor, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cA" = ( +/obj/structure/table/reinforced, +/obj/item/paper_bin, +/obj/item/pen, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"cB" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"cD" = ( +/obj/machinery/fabricator/hacked, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cE" = ( +/obj/structure/rack, +/obj/item/gun/energy/ionrifle, +/obj/item/gun/energy/ionrifle, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cF" = ( +/obj/structure/rack, +/obj/item/clothing/head/helmet/riot, +/obj/item/clothing/head/helmet/riot, +/obj/item/clothing/head/helmet/riot, +/obj/item/clothing/head/helmet/riot, +/obj/item/clothing/suit/armor/riot, +/obj/item/clothing/suit/armor/riot, +/obj/item/clothing/suit/armor/riot, +/obj/item/clothing/suit/armor/riot, +/obj/item/shield/riot, +/obj/item/shield/riot, +/obj/item/shield/riot, +/obj/item/shield/riot, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cG" = ( +/obj/structure/table/reinforced, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/defibrillator/compact/loaded, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cH" = ( +/obj/structure/table/reinforced, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/obj/item/roller, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cI" = ( +/obj/structure/closet{ + name = "insignias closet" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"cJ" = ( +/obj/machinery/chem_master, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cK" = ( +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/obj/structure/window/reinforced/crescent, +/obj/structure/rack, +/obj/item/rig/ert/janitor, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cL" = ( +/obj/structure/table/reinforced, +/obj/item/paicard, +/obj/item/paicard, +/obj/item/paicard, +/obj/item/paicard, +/obj/item/paicard, +/obj/item/paicard, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cM" = ( +/obj/structure/rack, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/obj/item/gun/energy/gun, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cN" = ( +/obj/structure/rack, +/obj/item/shield/riot/metal, +/obj/item/shield/riot/metal, +/obj/item/shield/riot/metal, +/obj/item/shield/riot/metal, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cO" = ( +/obj/machinery/chemical_dispenser/full, +/obj/item/chems/glass/beaker/large, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cP" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"cQ" = ( +/obj/structure/table/reinforced, +/obj/item/megaphone, +/obj/item/megaphone, +/obj/item/megaphone, +/obj/item/megaphone, +/obj/item/megaphone, +/obj/item/megaphone, +/obj/structure/noticeboard{ + default_pixel_x = 32 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cR" = ( +/obj/structure/closet{ + name = "insignias closet" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cS" = ( +/obj/structure/iv_drip, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cT" = ( +/obj/structure/table/reinforced, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/cleaner, +/obj/item/chems/spray/antiseptic, +/obj/item/chems/spray/antiseptic, +/obj/item/box/bloodpacks, +/obj/item/stack/tape_roll/barricade_tape/medical, +/obj/item/stack/tape_roll/barricade_tape/medical, +/obj/item/flashlight/pen, +/obj/item/flashlight/pen, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cU" = ( +/obj/structure/table/reinforced, +/obj/item/firstaid/fire, +/obj/item/firstaid/fire, +/obj/item/firstaid/fire, +/obj/item/firstaid/toxin, +/obj/item/firstaid/toxin, +/obj/item/firstaid/toxin, +/obj/item/firstaid/o2, +/obj/item/firstaid/o2, +/obj/item/firstaid/o2, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cV" = ( +/obj/structure/table/reinforced, +/obj/item/firstaid/regular, +/obj/item/firstaid/regular, +/obj/item/firstaid/regular, +/obj/item/firstaid/adv, +/obj/item/firstaid/adv, +/obj/item/firstaid/adv, +/obj/item/firstaid/combat, +/obj/item/firstaid/combat, +/obj/item/firstaid/combat, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cW" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cX" = ( +/obj/structure/window/reinforced/crescent, +/obj/structure/rack, +/obj/item/rig/ert, +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cY" = ( +/obj/structure/window/reinforced/crescent, +/obj/structure/rack, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/vision/nvg, +/obj/item/rig_module/device/flash, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"cZ" = ( +/obj/structure/window/reinforced/crescent, +/obj/structure/rack, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/mounted/taser, +/obj/item/rig_module/maneuvering_jets, +/obj/item/rig_module/maneuvering_jets, +/obj/item/rig_module/device/drill, +/obj/item/rig_module/device/drill, +/obj/item/rig_module/mounted/plasmacutter, +/obj/item/rig_module/mounted/plasmacutter, +/obj/item/rig_module/device/rcd, +/obj/item/rig_module/device/rcd, +/obj/item/rig_module/vision/meson, +/obj/item/rig_module/vision/meson, +/obj/structure/window/reinforced/crescent{ + dir = 8 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"da" = ( +/obj/structure/window/reinforced/crescent, +/obj/structure/rack, +/obj/item/rig/ert/engineer, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"db" = ( +/obj/structure/window/reinforced/crescent, +/obj/structure/rack, +/obj/item/rig/ert/engineer, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dc" = ( +/turf/unsimulated/wall/airlock{ + name = "Foxtrot Barracks" + }, +/area/map_template/rescue_base/base) +"dd" = ( +/obj/structure/flora/bush/palebush, +/turf/unsimulated/floor/asteroid, +/area/map_template/rescue_base/base) +"de" = ( +/obj/structure/table/reinforced, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"df" = ( +/obj/machinery/vending/security, +/turf/unsimulated/wall, +/area/map_template/rescue_base/base) +"dg" = ( +/obj/machinery/door/airlock/centcom{ + name = "Security" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dh" = ( +/obj/machinery/door/airlock/centcom{ + name = "Medical" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"di" = ( +/obj/machinery/vending/medical, +/turf/unsimulated/wall, +/area/map_template/rescue_base/base) +"dk" = ( +/obj/machinery/door/airlock/centcom{ + name = "EVA" + }, +/obj/machinery/door/blast/regular{ + id_tag = "standardrescue"; + name = "EVA" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dl" = ( +/obj/machinery/door/airlock/centcom{ + name = "Unit Area" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dm" = ( +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = 32 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dn" = ( +/obj/machinery/door/airlock/centcom{ + name = "Echo Barracks" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"do" = ( +/turf/unsimulated/wall/airlock{ + name = "Delta Barracks" + }, +/area/map_template/rescue_base/base) +"dp" = ( +/obj/structure/flora/bush/sunnybush, +/turf/unsimulated/floor/asteroid, +/area/map_template/rescue_base/base) +"dq" = ( +/obj/structure/table/reinforced, +/obj/item/modular_computer/tablet/lease/preset/command, +/obj/item/modular_computer/tablet/lease/preset/command, +/obj/item/modular_computer/tablet/lease/preset/command, +/obj/item/modular_computer/tablet/lease/preset/command, +/obj/item/modular_computer/tablet/lease/preset/command, +/obj/item/modular_computer/tablet/lease/preset/command, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dr" = ( +/obj/machinery/recharge_station, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ds" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dt" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/vest/black, +/obj/item/clothing/webbing/vest/black, +/obj/item/clothing/webbing/vest/black, +/obj/item/clothing/webbing/vest/black, +/obj/item/clothing/webbing/vest/black, +/obj/item/clothing/webbing/vest/black, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"du" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest/brown, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dv" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/holster/thigh, +/obj/item/clothing/webbing/holster/thigh, +/obj/item/clothing/webbing/holster/thigh, +/obj/item/clothing/webbing/holster/thigh, +/obj/item/clothing/webbing/holster/thigh, +/obj/item/clothing/webbing/holster/thigh, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dw" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dx" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + frequency = 1331; + id_tag = "ert_rescue_base"; + pixel_x = 5; + pixel_y = -25 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dy" = ( +/obj/machinery/door/airlock/centcom{ + name = "Squad Leader's Office" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dz" = ( +/obj/machinery/door/airlock/centcom{ + name = "Command" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dA" = ( +/obj/machinery/door/airlock/centcom{ + name = "Engineering" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dB" = ( +/obj/machinery/vending/engineering, +/turf/unsimulated/wall, +/area/map_template/rescue_base/base) +"dC" = ( +/obj/machinery/door/airlock/external/shuttle{ + id_tag = "ert_rescue_base_hatch"; + name = "Landing Pad" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dD" = ( +/obj/structure/table/reinforced, +/obj/item/box/trackimp, +/obj/item/box/cdeathalarm_kit, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dE" = ( +/obj/structure/table/reinforced, +/obj/abstract/modpack_compat/hand_tele, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dF" = ( +/obj/structure/table/reinforced, +/obj/item/aicard, +/obj/item/pinpointer/advpinpointer, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dG" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/obj/item/cell/hyper, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dH" = ( +/obj/machinery/vending/engivend, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dI" = ( +/obj/machinery/vending/tool, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dJ" = ( +/obj/machinery/vending/assist, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dK" = ( +/obj/machinery/fabricator/pipe, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dL" = ( +/obj/machinery/fabricator/pipe/disposal, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dN" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"dO" = ( +/obj/structure/chair/office/dark, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dQ" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/door/airlock/external/shuttle{ + id_tag = "ert_rescue_base_hatch" + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"dR" = ( +/obj/machinery/door/airlock/centcom{ + name = "Garage" + }, +/obj/machinery/door/blast/regular{ + id_tag = "standardrescue"; + name = "Garage" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dS" = ( +/obj/structure/table/steel, +/obj/item/radio/intercom, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"dT" = ( +/obj/structure/table/steel, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"dU" = ( +/obj/structure/table/steel, +/obj/item/box/fancy/cigar, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"dV" = ( +/obj/machinery/door/airlock/centcom{ + name = "Command" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"dW" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dX" = ( +/obj/machinery/portable_atmospherics/powered/pump/filled, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dY" = ( +/obj/machinery/shieldgen, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"dZ" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"ea" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/industrial/warning/corner, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eb" = ( +/obj/machinery/button/blast_door{ + id_tag = "rescuegarage"; + name = "Garage"; + pixel_x = -24; + pixel_y = -4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ed" = ( +/obj/structure/table/reinforced, +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ee" = ( +/obj/structure/table/reinforced, +/obj/machinery/cell_charger, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eg" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eh" = ( +/obj/structure/rack, +/obj/item/box/flashbangs, +/obj/item/box/teargas, +/obj/item/box/handcuffs, +/obj/item/baton/loaded, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ei" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas, +/obj/item/clothing/glasses/tacgoggles, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ej" = ( +/obj/structure/rack, +/obj/item/backpack/ert/commander, +/obj/item/belt/holster/security/tactical, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ek" = ( +/obj/structure/rack, +/obj/item/gun/energy/gun, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"em" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"en" = ( +/obj/machinery/portable_atmospherics/powered/scrubber, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eo" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"ep" = ( +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "rescuegarage"; + name = "Garage Exit" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eq" = ( +/obj/machinery/mech_recharger, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"er" = ( +/obj/item/card/id/centcom, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"et" = ( +/obj/structure/rack, +/obj/item/secure_storage/briefcase, +/obj/item/clothing/head/beret, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eu" = ( +/obj/machinery/emitter, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ev" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/machinery/button/blast_door{ + id_tag = "heavyrescue"; + name = "Heavy Gear"; + pixel_x = -5; + pixel_y = 4 + }, +/turf/unsimulated/floor/cult, +/area/map_template/rescue_base/base) +"ew" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/radio/phone{ + desc = "Should anything ever go wrong..."; + frequency = 1345 + }, +/turf/unsimulated/floor/cult, +/area/map_template/rescue_base/base) +"ex" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/machinery/button/blast_door{ + id_tag = "standardrescue"; + name = "Standard Gear"; + pixel_x = 5; + pixel_y = 4 + }, +/turf/unsimulated/floor/cult, +/area/map_template/rescue_base/base) +"ey" = ( +/obj/structure/rack, +/obj/item/backpack/ert/engineer, +/obj/item/backpack/ert/engineer, +/obj/item/belt/utility/full, +/obj/item/belt/utility/full, +/obj/item/clothing/gloves/insulated, +/obj/item/clothing/gloves/insulated, +/obj/item/clothing/gloves/insulated, +/obj/item/clothing/gloves/insulated, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"ez" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas, +/obj/item/clothing/mask/gas, +/obj/item/clothing/glasses/meson, +/obj/item/clothing/glasses/meson, +/obj/item/clothing/glasses/welding/superior, +/obj/item/clothing/glasses/welding/superior, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eA" = ( +/obj/structure/rack, +/obj/item/flash, +/obj/item/flash, +/obj/item/baton/loaded, +/obj/item/baton/loaded, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/grenade/chem_grenade/metalfoam, +/obj/item/inflatable_dispenser, +/obj/item/inflatable_dispenser, +/obj/item/tool/drill/diamond, +/obj/item/tool/drill/diamond, +/obj/item/briefcase/inflatable{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/briefcase/inflatable{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/briefcase/inflatable{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/briefcase/inflatable{ + pixel_x = 3; + pixel_y = 3 + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eB" = ( +/obj/structure/table/reinforced, +/obj/item/stack/tape_roll/barricade_tape/engineering, +/obj/item/stack/tape_roll/barricade_tape/engineering, +/obj/item/stack/tape_roll/barricade_tape/atmos, +/obj/item/stack/tape_roll/barricade_tape/atmos, +/obj/item/multitool, +/obj/item/multitool, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/stack/tape_roll/duct_tape, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/obj/item/cell/high, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eC" = ( +/obj/structure/table/reinforced, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd_ammo, +/obj/item/rcd, +/obj/item/rcd, +/obj/item/rcd, +/obj/item/rcd, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eD" = ( +/obj/structure/table/reinforced, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/stack/material/sheet/mapped/steel/fifty{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/stack/material/sheet/mapped/steel/fifty{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/stack/material/sheet/mapped/steel/fifty{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/panel/mapped/plastic/fifty, +/obj/item/stack/material/pane/mapped/rborosilicate/twenty, +/obj/item/stack/material/pane/mapped/rborosilicate/twenty, +/obj/item/stack/material/pane/mapped/rborosilicate/twenty, +/obj/item/stack/material/pane/mapped/rborosilicate/twenty, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eE" = ( +/obj/structure/table/reinforced, +/obj/item/stock_parts/circuitboard/smes, +/obj/item/stock_parts/circuitboard/smes, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_capacity, +/obj/item/stock_parts/smes_coil/super_io, +/obj/item/stock_parts/smes_coil/super_io, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eF" = ( +/obj/machinery/portable_atmospherics/canister/air, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eG" = ( +/obj/item/radio/intercom{ + pixel_y = 20 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"eH" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/obj/item/ashtray, +/obj/item/trash/cigbutt/cigarbutt, +/turf/unsimulated/floor/cult, +/area/map_template/rescue_base/base) +"eI" = ( +/obj/structure/chair/comfy/brown{ + dir = 1 + }, +/turf/unsimulated/floor/cult, +/area/map_template/rescue_base/base) +"eJ" = ( +/obj/structure/table/laminate{ + dir = 5 + }, +/turf/unsimulated/floor/cult, +/area/map_template/rescue_base/base) +"eK" = ( +/obj/machinery/door/airlock/centcom{ + name = "Combat Exosuit" + }, +/obj/machinery/door/blast/regular{ + dir = 4; + id_tag = "heavyrescue"; + name = "Combat Exosuit" + }, +/turf/unsimulated/floor/vault, +/area/map_template/rescue_base/base) +"eL" = ( +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eM" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 9 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eN" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eO" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 5 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eP" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 8 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eQ" = ( +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eR" = ( +/obj/effect/floor_decal/industrial/loading, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eS" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eT" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/porta_turret/crescent, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"eU" = ( +/obj/effect/paint/blue, +/turf/wall/titanium, +/area/map_template/rescue_base/start) +"eV" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "rescuebridge"; + name = "Cockpit Blast Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"eW" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "rescuedock"; + name = "Blast Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"eX" = ( +/obj/machinery/door/airlock/external/shuttle{ + id_tag = "ert_rescue_shuttle_outer"; + name = "Ship External Access" + }, +/obj/effect/shuttle_landmark/ert/start, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"eY" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/button/blast_door{ + id_tag = "rescuebridge"; + name = "Window Shutters Control"; + pixel_y = -4; + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"eZ" = ( +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fa" = ( +/obj/machinery/computer/shuttle_control/multi/rescue, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fb" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/recharger{ + pixel_y = 4 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fc" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + dir = 4; + id_tag = "ert_rescue_shuttle_pump" + }, +/obj/machinery/airlock_sensor/shuttle{ + id_tag = "ert_rescue_shuttle_sensor"; + pixel_x = 8; + pixel_y = 25 + }, +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/closet/emcloset, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fd" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 1 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fe" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + dir = 8; + id_tag = "ert_rescue_shuttle_pump" + }, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + frequency = 1331; + id_tag = "ert_rescue_shuttle"; + initial_access = list(); + pixel_x = -8; + pixel_y = 25 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"ff" = ( +/obj/structure/table/steel_reinforced, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fg" = ( +/obj/structure/chair/office/dark{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fh" = ( +/obj/structure/chair/shuttle, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fi" = ( +/obj/structure/table/steel_reinforced, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fj" = ( +/obj/structure/handrail{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fk" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fl" = ( +/obj/machinery/button/blast_door{ + id_tag = "rescuedock"; + name = "Window Shutters Control"; + pixel_x = 24; + pixel_y = -4 + }, +/obj/structure/handrail{ + dir = 8 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fm" = ( +/obj/machinery/computer/modular/preset/medical{ + dir = 4; + icon_state = "console" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fo" = ( +/obj/machinery/hologram/holopad/longrange, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fp" = ( +/obj/machinery/computer/modular/preset/engineering{ + dir = 8; + icon_state = "console" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fq" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/handrail{ + dir = 8 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fr" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/computer/prisoner{ + dir = 4; + name = "Implant Management" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fs" = ( +/obj/machinery/computer/modular/preset/security{ + dir = 8; + icon_state = "console" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"ft" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + dir = 4; + id_tag = "ert_rescue_shuttle_pump" + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fu" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fv" = ( +/obj/machinery/atmospherics/pipe/manifold4w/visible, +/obj/machinery/meter, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fw" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + dir = 8; + id_tag = "ert_rescue_shuttle_pump" + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fx" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fy" = ( +/obj/machinery/door/airlock/centcom{ + name = "Flight Deck" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fz" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fA" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/door/airlock/external/shuttle{ + id_tag = "ert_rescue_shuttle_inner"; + name = "Ship External Access" + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fB" = ( +/obj/structure/flora/bush/palebush, +/turf/unsimulated/floor/asteroidplating, +/area/map_template/rescue_base/base) +"fC" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "rescuebridge"; + name = "Cockpit Blast Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fD" = ( +/obj/structure/closet, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fE" = ( +/obj/structure/rack, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/item/radio, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fF" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 4; + start_pressure = 740.5 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fG" = ( +/obj/machinery/atmospherics/pipe/manifold/visible, +/obj/machinery/meter, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fH" = ( +/obj/machinery/atmospherics/pipe/manifold/visible, +/obj/machinery/button/access/shuttle/interior{ + id_tag = "ert_rescue_shuttle"; + initial_access = list("ACCESS_CENT_SPECOPS"); + name = "interior access button"; + pixel_x = 25; + pixel_y = 25 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fI" = ( +/obj/machinery/atmospherics/unary/tank/air{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fJ" = ( +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "rescueeva"; + name = "Blast Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"fK" = ( +/obj/structure/closet, +/obj/item/box/sinpockets, +/obj/item/box/sinpockets, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fL" = ( +/obj/structure/closet/bombclosetsecurity, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fM" = ( +/obj/structure/rack, +/obj/item/clothing/mask/gas/half, +/obj/item/clothing/mask/gas/half, +/obj/item/clothing/mask/gas/half, +/obj/item/clothing/mask/gas/half, +/obj/item/clothing/mask/gas/half, +/obj/item/clothing/mask/gas/half, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fN" = ( +/obj/machinery/suit_cycler, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fO" = ( +/obj/structure/closet, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight/flare, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/flashlight, +/obj/item/flashlight, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fP" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/obj/structure/closet/l3closet/general, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fQ" = ( +/obj/structure/rack, +/obj/item/tank/emergency/oxygen/double, +/obj/item/tank/emergency/oxygen/double, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fR" = ( +/obj/structure/handrail{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fS" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/closet/radiation, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fT" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fU" = ( +/obj/structure/table/steel_reinforced, +/obj/item/box/fancy/cigarettes/dromedaryco, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fV" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fW" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fX" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fY" = ( +/obj/structure/rack, +/obj/machinery/light, +/obj/item/tank/jetpack/carbondioxide, +/obj/item/tank/jetpack/carbondioxide, +/obj/machinery/button/blast_door{ + id_tag = "rescueeva"; + name = "Window Shutters Control"; + pixel_x = 24; + pixel_y = -4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"fZ" = ( +/obj/machinery/door/airlock/centcom{ + name = "Crew Area" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"ga" = ( +/obj/structure/sign/poster/bay_9{ + pixel_x = -32 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gb" = ( +/obj/structure/chair{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gc" = ( +/obj/machinery/vending/wallmed1{ + initial_access = newlist(); + name = "Emergency NanoMed"; + pixel_x = 28 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gd" = ( +/obj/machinery/door/airlock/centcom{ + name = "Passageway" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"ge" = ( +/obj/structure/handrail, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gf" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gg" = ( +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gh" = ( +/obj/structure/bed, +/obj/item/bedsheet/orange, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gi" = ( +/obj/machinery/flasher{ + id_tag = "rescueflash"; + pixel_y = 28 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gj" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gk" = ( +/obj/machinery/door/airlock/centcom{ + name = "Storage" + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gl" = ( +/obj/machinery/door/airlock/centcom{ + name = "Infirmary" + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gm" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/sleeper/standard{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"go" = ( +/obj/structure/table/glass, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gp" = ( +/obj/item/stool, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gq" = ( +/obj/structure/hygiene/toilet{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gr" = ( +/obj/structure/rack, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gs" = ( +/obj/structure/closet/crate/plastic/rations, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gt" = ( +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gu" = ( +/obj/machinery/shieldwallgen, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gv" = ( +/obj/structure/closet/secure_closet/chemical, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gw" = ( +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gz" = ( +/obj/machinery/door/airlock/centcom{ + name = "Cell" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gA" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gB" = ( +/obj/structure/closet/secure_closet/medical1, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gC" = ( +/obj/structure/closet/medical_wall{ + pixel_y = 32 + }, +/obj/item/chems/glass/bottle/antitoxin{ + pixel_x = -4; + pixel_y = 8 + }, +/obj/item/chems/glass/bottle/stabilizer{ + pixel_x = 4; + pixel_y = 7 + }, +/obj/item/chems/syringe, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gD" = ( +/obj/machinery/bodyscanner{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gE" = ( +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gG" = ( +/obj/machinery/recharger/wallcharger{ + pixel_x = -25; + dir = 4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gH" = ( +/obj/machinery/door/airlock/centcom{ + name = "Brig" + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gI" = ( +/obj/machinery/light, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gJ" = ( +/obj/machinery/recharge_station, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gK" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/closet/crate/secure{ + req_access = list("ACCESS_CENT_SPECOPS") + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gL" = ( +/obj/structure/table/glass, +/obj/item/defibrillator/loaded, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gM" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gN" = ( +/obj/machinery/light, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gO" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gP" = ( +/obj/machinery/button/flasher{ + id_tag = "rescueflash"; + name = "Flasher"; + pixel_x = 27; + dir = 8 + }, +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gQ" = ( +/obj/machinery/portable_atmospherics/canister/air, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gR" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/structure/closet/medical_wall{ + pixel_x = -32; + dir = 4 + }, +/obj/item/chems/glass/bottle/sedatives, +/obj/item/chems/glass/bottle/sedatives, +/obj/item/chems/syringe, +/obj/item/clothing/mask/breath/medical, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gS" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/iv_drip, +/obj/machinery/button/blast_door{ + id_tag = "rescueinfirm"; + name = "Window Shutters Control"; + pixel_x = 24; + pixel_y = -4 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"gT" = ( +/obj/item/flashlight/lantern, +/turf/unsimulated/floor/asteroid, +/area/map_template/rescue_base/base) +"gU" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "rescuebridge"; + name = "Blast Shutters" + }, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gV" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gW" = ( +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/obj/item/clothing/shoes/color/orange, +/obj/item/clothing/jumpsuit/orange, +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"gX" = ( +/obj/effect/paint/sun, +/turf/wall/titanium, +/area/map_template/rescue_base/start) +"gY" = ( +/obj/structure/shuttle/engine/heater, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/effect/paint/sun, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"gZ" = ( +/obj/structure/table/glass, +/obj/item/chems/spray/antiseptic, +/obj/item/chems/spray/cleaner, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"ha" = ( +/obj/machinery/optable, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"hb" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/machinery/door/blast/regular/open{ + dir = 4; + id_tag = "rescueinfirm"; + name = "Blast Shutters" + }, +/obj/effect/paint/blue, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"hc" = ( +/obj/item/tool/drill/diamond, +/turf/unsimulated/floor/asteroid, +/area/map_template/rescue_base/base) +"hd" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"he" = ( +/obj/structure/closet{ + name = "Prisoner's Locker" + }, +/obj/item/clothing/shoes/color/orange, +/obj/item/clothing/jumpsuit/orange, +/turf/floor/tiled/dark, +/area/map_template/rescue_base/start) +"hf" = ( +/obj/structure/shuttle/engine/propulsion, +/obj/effect/paint/sun, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"hg" = ( +/obj/structure/table/glass, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/obj/item/stack/medical/bandage/advanced, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"hh" = ( +/obj/structure/table/glass, +/obj/item/firstaid/surgery, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"hi" = ( +/obj/structure/table/glass, +/obj/item/clothing/mask/surgical, +/obj/item/clothing/gloves/latex, +/obj/machinery/light{ + dir = 4 + }, +/turf/floor/tiled/white, +/area/map_template/rescue_base/start) +"hj" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 10 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"hk" = ( +/obj/effect/floor_decal/industrial/warning, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"hl" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 6 + }, +/turf/unsimulated/floor/rescue_base, +/area/map_template/rescue_base/base) +"jY" = ( +/obj/machinery/network/acl{ + initial_network_id = "responsenet"; + req_access = list("ACCESS_CENT_SPECOPS") + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"mp" = ( +/obj/machinery/door/airlock/centcom{ + name = "Telecommunications" + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"qE" = ( +/obj/machinery/network/mainframe{ + initial_network_id = "responsenet"; + req_access = list("ACCESS_CENT_SPECOPS") + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"ty" = ( +/obj/machinery/computer/message_monitor{ + dir = 4; + throwpass = 1 + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"vA" = ( +/obj/machinery/network/relay/long_range{ + initial_network_id = "responsenet"; + req_access = list("ACCESS_CENT_SPECOPS") + }, +/turf/floor/plating, +/area/map_template/rescue_base/start) +"NG" = ( +/obj/machinery/network/router{ + initial_network_id = "responsenet"; + req_access = list("ACCESS_CENT_SPECOPS") + }, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) +"Qa" = ( +/obj/machinery/network/telecomms_hub/ert, +/turf/unsimulated/floor/dark, +/area/map_template/rescue_base/base) + +(1,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +"} +(2,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bA +bB +ac +bA +bB +dp +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +"} +(3,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bK +bA +bA +bA +dd +bA +bA +ac +ac +ac +ac +ac +ad +ad +ad +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +hc +ac +ac +ac +ac +ac +ac +ac +ac +"} +(4,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bA +bA +bC +bA +bA +bA +bB +bK +ac +ac +ac +ac +ad +ev +eH +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bA +bA +ac +ac +ac +ac +ac +ac +ac +ac +"} +(5,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +ad +ad +ad +bA +bA +bA +bA +bB +bB +bK +bA +bA +bA +ac +ac +ac +ad +ew +eI +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +gT +bA +bB +ac +ac +ac +ac +ac +ac +ac +"} +(6,1,1) = {" +ac +ac +ac +ac +ad +ad +ad +ad +ad +ad +ad +bU +bY +ad +ad +ad +bg +bg +bg +bg +bg +ad +ad +ac +ac +ac +ac +ad +ex +eJ +ad +ac +ac +ac +bA +bA +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bB +bA +ac +ac +ac +ac +ac +ac +ac +"} +(7,1,1) = {" +ac +ac +ac +ac +ad +aK +aZ +aZ +bu +ad +bO +ao +ao +bO +ad +ar +ar +ar +ar +ar +ar +dq +ad +ac +ac +ac +ac +ad +ad +ad +ad +ac +ac +bA +bA +bA +bA +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bA +bB +ac +ac +ac +ac +ac +ac +ac +"} +(8,1,1) = {" +ac +ac +ac +ac +ad +aL +aZ +aZ +bv +ad +bP +bV +bV +bP +ad +ar +cA +ar +cP +cP +ar +dr +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bA +ac +bB +bA +bC +bB +bB +ac +ac +ac +ac +ac +ac +ac +bB +bB +bB +bB +bB +bB +fB +bB +bB +ac +ac +ac +ac +ac +"} +(9,1,1) = {" +ac +ac +ac +ac +ad +ad +ba +ad +ad +ad +bO +ao +ao +bO +ad +cv +cB +ar +cP +cP +ar +ds +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bB +bB +bB +bB +bA +bA +fB +bB +bB +ac +ac +bB +bB +bB +bA +bC +bB +bC +bB +bA +bA +bB +bB +bB +ac +ac +ac +ac +"} +(10,1,1) = {" +ac +ac +ac +ac +ad +aM +aZ +bm +bw +ad +bP +bV +bV +bP +ad +ar +cB +ar +cP +cP +ar +dt +ad +ad +ad +ad +ad +ad +ad +ac +ac +ac +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bA +bB +bB +bB +bB +bA +bB +bB +ac +ac +ac +"} +(11,1,1) = {" +ac +ac +ac +ac +ad +aN +aZ +aZ +bx +ad +bO +ao +ao +bO +ad +ar +ar +ar +ar +ar +ar +du +bg +ar +ar +dS +dT +er +ad +ac +ac +ac +bB +eM +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +eP +hj +bB +ac +ac +ac +"} +(12,1,1) = {" +ac +ac +ac +ac +ad +aO +aZ +aZ +by +ad +bQ +bV +bV +bP +ad +ar +ar +ar +ar +ar +ar +dv +bg +ar +dO +dT +eg +ar +ad +ac +ac +bB +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(13,1,1) = {" +ac +ac +ac +ac +ad +aP +aZ +aZ +aZ +bJ +ar +ao +ao +ao +cb +ao +ao +ao +ao +ao +ao +ao +dy +ao +ao +dU +ao +ao +ad +ac +ac +bB +bA +eN +eQ +eT +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +eU +eU +eU +eU +eU +gU +eU +gX +gX +eQ +hk +bB +bB +ac +ac +"} +(14,1,1) = {" +ac +ac +ad +ad +ad +ad +bb +ad +bz +ad +bR +ar +ar +ca +ad +cw +cD +cL +cQ +de +ao +ao +bg +ar +ao +ao +ao +et +ad +ac +ac +ac +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +gh +gp +fx +gG +gG +gV +hd +gY +hf +eQ +hk +bB +bB +ac +ac +"} +(15,1,1) = {" +ac +ac +ad +au +aB +aQ +aB +ad +ad +ad +ad +bW +bW +ad +ad +bg +bg +bg +ad +ad +dl +dl +ad +bg +bg +dV +ad +ad +ad +ac +ac +ac +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +gi +eZ +gz +eZ +eZ +eZ +eZ +gY +hf +eQ +hk +bB +bC +bB +ac +"} +(16,1,1) = {" +ac +ac +ad +ad +ad +aR +bc +ad +jY +ty +ad +ar +ar +ad +cc +cx +cE +cM +cR +bg +ao +ao +bg +dD +ar +ar +eh +ad +ac +ac +ac +bB +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +gj +gq +fx +eZ +gP +gW +he +gY +hf +eQ +hk +bB +bB +bB +ac +"} +(17,1,1) = {" +ac +ac +ad +av +av +aR +bc +ad +qE +ar +mp +ar +ar +bg +cd +ar +ar +ar +ar +bg +ao +ao +bg +dE +ar +ar +ei +bg +bB +bB +bB +bB +bA +eN +eQ +eU +eU +eU +eU +eU +eU +fC +fC +fC +eU +eU +eQ +eU +eU +eU +eU +gH +eU +eU +eU +gX +gX +eQ +hk +bB +bB +ac +ac +"} +(18,1,1) = {" +ac +ac +ad +aw +aB +aS +aB +ad +NG +Qa +ad +ar +ar +bg +ce +ar +ar +ar +ar +df +ao +dw +ad +dF +ar +ar +ej +bg +bB +bA +bB +bA +bB +eN +eQ +eV +eY +ff +fm +fr +fx +fD +fK +fO +fD +eU +eQ +eQ +eQ +eU +eZ +eZ +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +bA +ac +ac +"} +(19,1,1) = {" +ac +ac +ad +ad +ad +ad +ad +ad +ad +ad +ad +ar +ar +bg +cf +ao +ao +ao +ao +dg +ao +ao +dz +ao +ao +ao +ek +bg +bB +bC +bB +bB +bB +eN +eQ +eV +eZ +fg +eZ +eZ +fy +eZ +eZ +eZ +fR +eU +eU +eU +eU +eU +ge +gI +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(20,1,1) = {" +ac +ac +ac +ac +ad +aT +bd +bn +bD +bL +ad +ar +ar +ad +cg +ao +cF +cN +ao +dg +ao +ao +dz +ao +ao +ao +aT +bg +bB +bB +bB +bA +bB +eN +eQ +eV +fa +fh +fo +eZ +fx +eZ +eZ +eZ +eZ +fZ +eZ +gf +gd +eZ +eZ +fX +eU +eQ +eQ +eQ +eQ +eQ +hk +bA +bB +ac +ac +"} +(21,1,1) = {" +ac +ac +ac +ac +ad +aU +ao +ao +ao +ao +ad +ar +ar +ad +ad +bg +bg +bg +ad +ad +dm +ao +ad +ad +bg +bg +bg +ad +ad +ad +bB +bB +bB +eN +eQ +eV +fb +fi +fp +fs +fx +fE +fL +fP +fS +fx +eZ +eZ +fx +gr +gr +gJ +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(22,1,1) = {" +ac +ac +ac +ac +ad +ao +ao +ao +ao +ao +ad +ar +ar +ad +ch +ao +ao +ao +ao +dh +ao +ao +dA +ao +ao +ao +ao +ao +ch +ad +bB +bB +dd +eN +eQ +eU +eU +eU +eU +eU +eU +eU +eU +eU +eU +eU +ge +fR +eU +eU +eU +eU +eU +gX +gX +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(23,1,1) = {" +ac +ac +ac +ad +ad +ad +ad +ad +bE +ad +ad +ar +ar +bg +ci +ao +ao +ao +ao +dh +ao +ao +dA +ao +ao +ao +ao +ao +ci +bg +bB +bA +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +fT +ga +eZ +eZ +eU +gs +gA +gt +gQ +gY +hf +eQ +eQ +eQ +hk +bB +ac +ac +ac +"} +(24,1,1) = {" +ac +ac +ac +ad +aC +aV +be +bo +ao +ar +ad +ar +ar +bg +cj +ar +cG +ar +ar +di +ao +ao +dB +ar +ar +dW +em +ar +ey +bg +bB +bB +bA +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +fU +gb +eZ +eZ +gk +gt +gt +gt +gQ +gY +hf +eQ +eQ +eQ +hk +bC +ac +ac +ac +"} +(25,1,1) = {" +ad +ad +ad +ad +aD +ao +ao +ao +ao +ao +bS +ao +ao +bg +ck +ar +cH +ar +cS +bg +ao +ao +bg +dG +ar +dX +en +ar +ez +bg +bB +bB +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +ff +gb +eZ +eZ +gk +gt +gt +gt +gt +gY +hf +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(26,1,1) = {" +ad +ae +ao +ad +aE +ao +ao +ao +ao +ao +bS +ao +ao +bg +cl +ar +cI +ar +cT +bg +ao +ao +bg +dH +ar +dX +en +ar +eA +bg +bA +bC +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +fV +gc +eZ +eZ +eU +gu +gu +gK +vA +gY +hf +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(27,1,1) = {" +ad +af +ao +ad +aF +ao +ao +ao +ao +bM +ad +ao +ao +bg +cm +ar +ar +ar +cU +bg +ao +ao +bg +dI +ar +dX +en +ar +eB +ad +bB +bB +bB +eN +eQ +eU +eU +eU +eU +eU +eU +eU +eU +eU +eU +eU +ge +fX +eU +eU +eU +eU +eU +gX +gX +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(28,1,1) = {" +ad +ag +ao +ad +aG +aW +bf +bp +bF +bN +ad +aU +ao +ad +cm +cy +cJ +cO +cV +bg +ao +ao +ad +dJ +ar +dX +en +ar +eC +ad +bB +bB +bB +eN +eQ +eU +fc +fj +fj +ft +eU +fF +fM +fQ +fW +fx +eZ +eZ +fx +gv +gB +gL +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +ac +ac +ac +"} +(29,1,1) = {" +ad +ad +ap +ad +ad +ad +ad +ad +ad +ad +ad +ao +ao +ad +ad +bg +bg +bg +ad +ad +aU +ao +ad +dK +ar +ar +ar +ar +eD +ad +dZ +dZ +dZ +dZ +eR +eW +fd +fk +fk +fu +fz +fG +eZ +eZ +eZ +gd +eZ +gg +gl +gw +gw +gM +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +ac +ac +ac +"} +(30,1,1) = {" +ac +ah +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ad +dL +ar +ar +ar +ar +eE +ad +dZ +dZ +dZ +dZ +eR +eX +fd +fk +fk +fv +fA +fH +eZ +eZ +fX +eU +eU +eU +eU +eU +gC +gN +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +ac +ac +ac +"} +(31,1,1) = {" +ac +ah +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ao +ad +cR +ao +dY +dY +eu +eF +ad +dZ +dZ +bB +eN +eQ +eU +fe +fl +fq +fw +eU +fI +fN +fN +fY +eU +eQ +eQ +eQ +eU +gD +gw +eU +eQ +eQ +eQ +eQ +eQ +hk +bB +bB +ac +ac +"} +(32,1,1) = {" +ad +ad +ad +ad +ad +ad +bg +bg +bg +bg +bT +bT +ad +ad +ad +ad +ad +ad +ad +ad +ao +dx +ad +ad +bg +bg +bg +bg +ad +ad +dZ +dZ +bB +eN +eQ +eU +eU +eU +eU +eU +eU +fJ +fJ +fJ +eU +eU +eQ +eU +eU +eU +gE +gw +eU +eU +eU +gX +gX +eQ +hk +bB +bB +ac +ac +"} +(33,1,1) = {" +ad +ai +aq +ax +aH +ad +bh +bq +ar +ar +ar +ar +bZ +ad +cn +ao +ao +ao +ao +dk +ao +ao +dC +dN +dQ +dZ +dZ +dZ +dZ +dZ +dZ +dZ +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +gm +gw +gw +gw +gR +gZ +hg +gY +hf +eQ +hk +bB +bB +ac +ac +"} +(34,1,1) = {" +ad +aj +ar +ar +ar +ad +bi +br +bG +ar +ar +ar +bZ +ad +co +ao +ar +ao +ao +dk +ao +ao +dC +dN +dQ +ea +eo +eo +eo +eo +eL +dZ +bA +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +gw +gw +gw +gw +gw +gw +hh +gY +hf +eQ +hk +bB +bB +ac +ac +"} +(35,1,1) = {" +ad +ak +ar +ay +ar +aX +ar +ar +ar +ar +ar +ar +ar +ad +cp +ao +ar +ao +cW +ad +ao +ao +ad +ad +ad +ad +ep +ep +ep +ep +ad +ad +bB +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +go +gw +gw +gO +gS +ha +hi +gY +hf +eQ +hk +bB +bB +ac +ac +"} +(36,1,1) = {" +ad +al +ar +ar +ar +ad +ar +ao +ar +ar +ar +ao +ar +ad +cq +ao +ar +ao +cX +ad +ao +ao +ao +ao +dR +eb +ao +ao +ao +ao +de +ad +bB +eN +eQ +eT +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eU +eU +eU +eU +eU +eU +hb +eU +gX +gX +eQ +hk +bB +ac +ac +ac +"} +(37,1,1) = {" +ad +am +as +az +aI +ad +bg +bt +bg +ad +bg +bX +bg +ad +aT +ao +ar +ao +cY +ad +aU +ao +ao +ao +dR +ao +ao +ao +ao +ao +de +ad +bC +eN +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +eQ +hk +bB +ac +ac +ac +"} +(38,1,1) = {" +ad +ad +ad +ad +ad +ad +bj +ar +bH +ad +bH +ar +bj +ad +cs +ao +ar +ao +cZ +ad +ao +ao +ad +ad +ad +de +ao +ao +ao +ao +de +ad +bA +eO +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +eS +hl +bB +bB +ac +ac +"} +(39,1,1) = {" +ac +ac +ac +ac +ac +ad +bk +ar +bI +ad +bI +ar +bk +ad +ct +ao +ar +ao +da +ad +ao +ao +ad +ac +ad +ed +ao +ao +ao +ao +de +ad +bA +bB +bB +bB +bB +bB +bB +bB +bA +bB +bB +bB +bB +bB +bB +bB +bA +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +bB +ac +ac +ac +"} +(40,1,1) = {" +ac +ac +ac +ac +ac +ad +ad +ad +ad +ad +ad +ad +ad +ad +cu +ao +ao +ao +db +ad +dn +dn +ad +ac +ad +ee +eq +eq +eq +ao +de +ad +bB +bC +bB +bA +bB +bB +bB +ac +bA +bB +bB +bA +bB +bA +bA +bB +bB +bB +bB +fB +bB +bA +bB +bB +bB +bC +bA +ac +ac +ac +ac +"} +(41,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +ad +cz +cK +ad +ad +ad +ao +ao +ad +ac +ad +ad +ad +ad +ad +eK +ad +ad +bA +bA +ac +ac +ac +ac +ac +ac +ac +ac +bB +bB +bA +bB +ac +ac +bB +bB +bB +bA +bB +bB +bB +bB +ac +bB +bB +ac +ac +ac +ac +"} +(42,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +ad +ad +ad +dc +ao +ao +ao +ad +ac +ac +ac +ac +ad +eG +ao +ar +ad +bB +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bB +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +bB +bB +bB +ac +ac +ac +ac +ac +"} +(43,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +dc +ao +ao +ao +ad +ac +ac +ac +ac +ad +de +eq +de +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bB +ac +ac +ac +ac +ac +ac +ac +ac +"} +(44,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +ad +ad +ao +ao +ad +ac +ac +ac +ac +ad +ad +ad +ad +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bA +bA +ac +ac +ac +ac +ac +ac +ac +ac +"} +(45,1,1) = {" +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ad +do +do +ad +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +"} diff --git a/mods/content/response_team/response_team.dm b/mods/content/response_team/response_team.dm new file mode 100644 index 000000000000..dd611ef5465d --- /dev/null +++ b/mods/content/response_team/response_team.dm @@ -0,0 +1,130 @@ +//STRIKE TEAMS +//Thanks to Kilakk for the admin-button portion of this code. + +var/global/send_emergency_team = 0 // Used for automagic response teams + // 'admin_emergency_team' for admin-spawned response teams +var/global/ert_base_chance = 10 // Default base chance. Will be incremented by increment ERT chance. +var/global/can_call_ert + +/client/proc/response_team() + set name = "Dispatch Emergency Response Team" + set category = "Special Verbs" + set desc = "Send an emergency response team" + + if(!holder) + to_chat(usr, "Only administrators may use this command.") + return + if(GAME_STATE < RUNLEVEL_GAME) + to_chat(usr, "The game hasn't started yet!") + return + if(send_emergency_team) + to_chat(usr, "[global.using_map.boss_name] has already dispatched an emergency response team!") + return + if(alert("Do you want to dispatch an Emergency Response Team?",,"Yes","No") != "Yes") + return + + var/decl/security_state/security_state = GET_DECL(global.using_map.security_state) + if(security_state.current_security_level_is_lower_than(security_state.high_security_level)) // Allow admins to reconsider if the alert level is below High + switch(alert("Current security level lower than [security_state.high_security_level.name]. Do you still want to dispatch a response team?",,"Yes","No")) + if("No") + return + if(send_emergency_team) + to_chat(usr, "Looks like somebody beat you to it!") + return + + message_admins("[key_name_admin(usr)] is dispatching an Emergency Response Team.", 1) + log_admin("[key_name(usr)] used Dispatch Response Team.") + trigger_armed_response_team(1) + +/client/verb/JoinResponseTeam() + + set name = "Join Response Team" + set category = "IC" + + if(!MayRespawn(1)) + to_chat(usr, "You cannot join the response team at this time.") + return + + if(isghost(usr) || isnewplayer(usr)) + if(!send_emergency_team) + to_chat(usr, "No emergency response team is currently being sent.") + return + if(jobban_isbanned(usr, /decl/special_role/ert) || jobban_isbanned(usr, "Security Officer")) + to_chat(usr, "You are jobbanned from the emergency reponse team!") + return + var/decl/special_role/ert/ert = GET_DECL(/decl/special_role/ert) + if(ert.current_antagonists.len >= ert.hard_cap) + to_chat(usr, "The emergency response team is already full!") + return + ert.create_default(usr) + else + to_chat(usr, "You need to be an observer or new player to use this.") + +// returns a number of dead players in % +/proc/percentage_dead() + var/total = 0 + var/deadcount = 0 + for(var/mob/living/human/H in SSmobs.mob_list) + if(H.client) // Monkeys and mice don't have a client, amirite? + if(H.stat == DEAD) deadcount++ + total++ + + if(total == 0) return 0 + else return round(100 * deadcount / total) + +// counts the number of antagonists in % +/proc/percentage_antagonists() + var/total = 0 + var/antagonists = 0 + for(var/mob/living/human/H in SSmobs.mob_list) + if(is_special_character(H) >= 1) + antagonists++ + total++ + + if(total == 0) return 0 + else return round(100 * antagonists / total) + +/proc/trigger_armed_response_team(var/force = 0) + if(!can_call_ert && !force) + return + if(send_emergency_team) + return + + var/send_team_chance = ert_base_chance // Is incremented by increment_ert_chance. + send_team_chance += 2*percentage_dead() // the more people are dead, the higher the chance + send_team_chance += percentage_antagonists() // the more antagonists, the higher the chance + send_team_chance = min(send_team_chance, 100) + + if(force) send_team_chance = 100 + + // there's only a certain chance a team will be sent + if(!prob(send_team_chance)) + command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "[global.using_map.boss_name]") + can_call_ert = 0 // Only one call per round, ladies. + return + + command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "[global.using_map.boss_name]") + if(SSevac.evacuation_controller) + SSevac.evacuation_controller.add_can_call_predicate(new/datum/evacuation_predicate/ert()) + + can_call_ert = 0 // Only one call per round, gentleman. + send_emergency_team = 1 + + sleep(600 * 5) + send_emergency_team = 0 // Can no longer join the ERT. + +/datum/evacuation_predicate/ert + var/prevent_until + +/datum/evacuation_predicate/ert/New() + ..() + prevent_until = world.time + 30 MINUTES + +/datum/evacuation_predicate/ert/is_valid() + return world.time < prevent_until + +/datum/evacuation_predicate/ert/can_call(var/user) + if(world.time >= prevent_until) + return TRUE + to_chat(user, "An emergency response team has been dispatched. Evacuation requests will be denied until [duration2stationtime(prevent_until - world.time)].") + return FALSE diff --git a/mods/content/response_team/trader_overrides.dm b/mods/content/response_team/trader_overrides.dm new file mode 100644 index 000000000000..89633a51e39c --- /dev/null +++ b/mods/content/response_team/trader_overrides.dm @@ -0,0 +1,4 @@ +/datum/trader/trading_beacon/New() + ..() + if(type == /datum/trader/trading_beacon) // don't affect subtypes. ugh, i hate that this is necessary + possible_trading_items[/obj/item/backpack/ert] = TRADER_BLACKLIST_ALL \ No newline at end of file diff --git a/mods/content/scaling_descriptors.dm b/mods/content/scaling_descriptors.dm new file mode 100644 index 000000000000..b6857e1b6752 --- /dev/null +++ b/mods/content/scaling_descriptors.dm @@ -0,0 +1,70 @@ +#ifndef MODPACK_SCALING_MODIFIERS +#define MODPACK_SCALING_MODIFIERS +#endif + +// These values were reverse-engineered from Polaris, where they apparently +// took quite a lot of fiddling to get looking nice. Cheers to whoever did that. +/decl/bodytype + var/list/scaling_adjustments_x = list( + -0.095, + -0.055, + 0, + 0.054, + 0.095, + ) + var/list/scaling_adjustments_y = list( + -0.085, + -0.05, + 0, + 0.05, + 0.09, + ) + +/decl/bodytype/validate() + . = ..() + + if(scaling_adjustments_x) + if(!islist(scaling_adjustments_x)) + . += "non-list value for width scaling modifiers" + else if(length(scaling_adjustments_x) < 5) + . += "insufficient scaling values for width scaling." + else + for(var/value in scaling_adjustments_x) + if(!isnum(value)) + . += "non-numeric value in width scaling list: '[isnull(value) ? "NULL" : value]'" + + if(scaling_adjustments_y) + if(!islist(scaling_adjustments_y)) + . += "non-list value for height scaling modifiers" + else if(length(scaling_adjustments_y) < 5) + . += "insufficient scaling values for height scaling." + else + for(var/value in scaling_adjustments_y) + if(!isnum(value)) + . += "non-numeric value in width height list: '[isnull(value) ? "NULL" : value]'" + +/mob/living/get_icon_scale_mult() + . = ..() + var/decl/bodytype/bodytype = get_bodytype() + if(!LAZYLEN(appearance_descriptors) || !bodytype) + return + var/modify_x = 1 + var/modify_y = 1 + for(var/entry in appearance_descriptors) + var/datum/appearance_descriptor/descriptor = bodytype.appearance_descriptors[entry] + var/list/new_scale_info = descriptor.get_mob_scale_adjustments(get_bodytype(), appearance_descriptors[entry]) + if(length(new_scale_info)) + modify_x += new_scale_info[1] + modify_y += new_scale_info[2] + .[1] *= modify_x + .[2] *= modify_y + +/datum/appearance_descriptor/build/get_mob_scale_adjustments(decl/bodytype/bodytype, offset_value) + . = list(0, 0) + if(offset_value && length(bodytype?.scaling_adjustments_x) >= offset_value) + .[1] += bodytype.scaling_adjustments_x[offset_value] + +/datum/appearance_descriptor/height/get_mob_scale_adjustments(decl/bodytype/bodytype, offset_value) + . = list(0, 0) + if(length(bodytype?.scaling_adjustments_y) >= offset_value) + .[2] += bodytype.scaling_adjustments_y[offset_value] diff --git a/mods/content/sealant_gun/_sealant_gun.dm b/mods/content/sealant_gun/_sealant_gun.dm new file mode 100644 index 000000000000..567a8cb4e5b7 --- /dev/null +++ b/mods/content/sealant_gun/_sealant_gun.dm @@ -0,0 +1,3 @@ +/decl/modpack/sealant_gun + name = "Sealant Gun" + desc = "Adds a sealant gun that can be used to launch globs of metal foam to immobilize enemies and seal hull breaches." \ No newline at end of file diff --git a/mods/content/sealant_gun/_sealant_gun.dme b/mods/content/sealant_gun/_sealant_gun.dme new file mode 100644 index 000000000000..1531c31d431f --- /dev/null +++ b/mods/content/sealant_gun/_sealant_gun.dme @@ -0,0 +1,11 @@ +#ifndef CONTENT_PACK_SEALANT +#define CONTENT_PACK_SEALANT +// BEGIN_INCLUDE +#include "_sealant_gun.dm" +#include "sealant_glob.dm" +#include "sealant_gun.dm" +#include "sealant_injector.dm" +#include "sealant_rack.dm" +#include "sealant_tank.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/sealant_gun/icons/sealant_glob.dmi b/mods/content/sealant_gun/icons/sealant_glob.dmi new file mode 100644 index 000000000000..c6dde678973d Binary files /dev/null and b/mods/content/sealant_gun/icons/sealant_glob.dmi differ diff --git a/mods/content/sealant_gun/icons/sealant_gun.dmi b/mods/content/sealant_gun/icons/sealant_gun.dmi new file mode 100644 index 000000000000..73745b7c1e83 Binary files /dev/null and b/mods/content/sealant_gun/icons/sealant_gun.dmi differ diff --git a/mods/content/sealant_gun/icons/sealant_props.dmi b/mods/content/sealant_gun/icons/sealant_props.dmi new file mode 100644 index 000000000000..f1282d5d3bed Binary files /dev/null and b/mods/content/sealant_gun/icons/sealant_props.dmi differ diff --git a/mods/content/sealant_gun/icons/sealant_tank.dmi b/mods/content/sealant_gun/icons/sealant_tank.dmi new file mode 100644 index 000000000000..9e224fecf01c Binary files /dev/null and b/mods/content/sealant_gun/icons/sealant_tank.dmi differ diff --git a/mods/content/sealant_gun/sealant_glob.dm b/mods/content/sealant_gun/sealant_glob.dm new file mode 100644 index 000000000000..261bec5ee814 --- /dev/null +++ b/mods/content/sealant_gun/sealant_glob.dm @@ -0,0 +1,97 @@ +/obj/item/sealant + name = "glob of sealant" + desc = "A blob of metal foam sealant." + icon = 'mods/content/sealant_gun/icons/sealant_glob.dmi' + icon_state = ICON_STATE_WORLD + color = "#cccdcc" + slowdown_general = 3 + canremove = FALSE + slot_flags = SLOT_FULL_BODY + + var/foam_type = /obj/structure/foamedmetal + var/splatted = FALSE // Used to prevent doubled effects if throwcode wonks up. + var/hardened = FALSE // Set manually post-equip so that the blob can't be removed without breaking. + var/static/list/splat_try_equip_slots = list( + slot_head_str, + BP_L_HAND, + BP_R_HAND, + slot_wear_mask_str, + slot_wear_suit_str, + slot_shoes_str + ) + +/obj/item/sealant/get_equipment_tint() + return TINT_BLIND + +/obj/item/sealant/equipped(mob/user, slot) + . = ..() + if(hardened) + break_apart(user) + else + to_chat(user, SPAN_DANGER("Hardened globs of metal foam stick to you!")) + hardened = TRUE + +/obj/item/sealant/blocks_speech_in_mouth(mob/wearer) + return TRUE + +/obj/item/sealant/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + break_apart(user) + return TRUE + +/obj/item/sealant/attackby(obj/item/used_item, mob/user) + break_apart(user) + return TRUE + +/obj/item/sealant/dropped(mob/user) + . = ..() + break_apart() + +/obj/item/sealant/proc/break_apart(var/mob/user) + canremove = TRUE + if(user) + user.try_unequip(src, user.loc) + user.visible_message(SPAN_NOTICE("\The [user] smashes \the [src]!"), SPAN_NOTICE("You smash \the [src]!"), SPAN_NOTICE("You hear a smashing sound.")) + user.setClickCooldown(1 SECOND) + qdel(src) + +/obj/item/sealant/Bump(atom/bumped, forced) + . = ..() + splat(bumped) + +/obj/item/sealant/throw_impact(atom/hit_atom) + . = ..() + splat(hit_atom) + +/obj/item/sealant/proc/splat(var/atom/target) + if(splatted) + return + splatted = TRUE + var/turf/target_turf = get_turf(target) || get_turf(src) + if(target_turf) + new /obj/effect/sealant(target_turf) + if(isliving(target)) + var/mob/living/living_target = target + for(var/slot in shuffle(splat_try_equip_slots)) + if(!living_target.get_equipped_item(slot)) + living_target.equip_to_slot_if_possible(src, slot) + if(living_target.get_equipped_item(slot) == src) + return + if(!target_turf.density && !(locate(foam_type) in target_turf)) + new foam_type(target_turf) + + if(!QDELETED(src)) + qdel(src) + +/obj/effect/sealant + name = "sealant glob" + desc = "A blob of metal foam sealant." + icon = 'mods/content/sealant_gun/icons/sealant_glob.dmi' + icon_state = "blank" + layer = PROJECTILE_LAYER + color = "#cccdcc" + +/obj/effect/sealant/Initialize() + . = ..() + flick("blobsplat", src) + QDEL_IN(src, 1 SECOND) diff --git a/mods/content/sealant_gun/sealant_gun.dm b/mods/content/sealant_gun/sealant_gun.dm new file mode 100644 index 000000000000..23a753cc0102 --- /dev/null +++ b/mods/content/sealant_gun/sealant_gun.dm @@ -0,0 +1,88 @@ +/obj/item/gun/launcher/sealant + name = "sealant gun" + desc = "A heavy, unwieldy device used to spray metal foam sealant onto hull breaches or damaged flooring." + icon = 'mods/content/sealant_gun/icons/sealant_gun.dmi' + icon_state = ICON_STATE_WORLD + autofire_enabled = TRUE + has_safety = FALSE + waterproof = TRUE + w_class = ITEM_SIZE_GARGANTUAN + obj_flags = OBJ_FLAG_NO_STORAGE + slot_flags = SLOT_BACK + fire_sound = 'sound/effects/refill.ogg' + screen_shake = FALSE + release_force = 5 + fire_delay = 1 + + var/foam_charges_per_shot = 1 + var/obj/item/sealant_tank/loaded_tank + +/obj/item/gun/launcher/sealant/on_update_icon() + update_world_inventory_state() + . = ..() + if(loaded_tank) + add_overlay("[icon_state]-tank") + +/obj/item/gun/launcher/sealant/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && loaded_tank) + var/tank_state = "[overlay.icon_state]-tank" + if(check_state_in_icon(tank_state, overlay.icon)) + overlay.overlays += image(overlay.icon, tank_state) + ..() + +/obj/item/gun/launcher/sealant/mapped + loaded_tank = /obj/item/sealant_tank/mapped + +/obj/item/gun/launcher/sealant/consume_next_projectile() + if(loaded_tank?.reagents?.has_reagent(/decl/material/liquid/foam, foam_charges_per_shot)) + loaded_tank.reagents.remove_reagent(/decl/material/liquid/foam, foam_charges_per_shot) + . = new /obj/item/sealant(src) + +/obj/item/gun/launcher/sealant/Initialize() + . = ..() + if(ispath(loaded_tank)) + loaded_tank = new loaded_tank(src) + update_icon() + +/obj/item/gun/launcher/sealant/Destroy() + QDEL_NULL(loaded_tank) + . = ..() + +/obj/item/gun/launcher/sealant/attack_hand(mob/user) + if(!(src in user.get_held_items()) || !loaded_tank || !user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + unload_tank(user) + return TRUE + +/obj/item/gun/launcher/sealant/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(loc == user) + if(loaded_tank) + . += SPAN_NOTICE("The loaded tank has about [REAGENT_VOLUME(loaded_tank.reagents, /decl/material/liquid/foam) || 0] charge\s of sealant left.") + else + . += SPAN_WARNING("\The [src] has no sealant loaded.") + +/obj/item/gun/launcher/sealant/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/sealant_tank) && user.try_unequip(used_item, src)) + loaded_tank = used_item + to_chat(user, SPAN_NOTICE("You slot \the [loaded_tank] into \the [src].")) + update_icon() + return TRUE + . = ..() + +/obj/item/gun/launcher/sealant/attack_self(mob/user) + if(loaded_tank) + unload_tank(user) + return TRUE + . = ..() + +/obj/item/gun/launcher/sealant/proc/unload_tank(var/mob/user) + if(!loaded_tank) + to_chat(user, SPAN_WARNING("\The [src] has no tank loaded.")) + return + + loaded_tank.dropInto(get_turf(src)) + user.put_in_hands(loaded_tank) + to_chat(user, SPAN_NOTICE("You pop \the [loaded_tank] out of \the [src].")) + loaded_tank = null + update_icon() diff --git a/mods/content/sealant_gun/sealant_injector.dm b/mods/content/sealant_gun/sealant_injector.dm new file mode 100644 index 000000000000..f5ad42b6ee86 --- /dev/null +++ b/mods/content/sealant_gun/sealant_injector.dm @@ -0,0 +1,110 @@ +/obj/item/chems/chem_disp_cartridge/foaming_agent/populate_reagents() + add_to_reagents(/decl/material/liquid/foaming_agent, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/chem_disp_cartridge/polyacid/populate_reagents() + add_to_reagents(/decl/material/liquid/acid/polyacid, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/structure/sealant_injector + name = "sealant tank injector" + icon = 'mods/content/sealant_gun/icons/sealant_props.dmi' + icon_state = "injector" + density = TRUE + anchored = TRUE + + var/list/cartridges + var/obj/item/sealant_tank/loaded_tank + var/max_cartridges = 3 + +/obj/structure/sealant_injector/Destroy() + QDEL_NULL_LIST(cartridges) + QDEL_NULL(loaded_tank) + . = ..() + +/obj/structure/sealant_injector/on_update_icon() + ..() + if(loaded_tank) + add_overlay("tank") + if(length(cartridges)) + add_overlay("carts[length(cartridges)]") + +/obj/structure/sealant_injector/Initialize(ml, _mat, _reinf_mat) + . = ..() + cartridges = list( + new /obj/item/chems/chem_disp_cartridge/aluminium(src) = 3, + new /obj/item/chems/chem_disp_cartridge/foaming_agent(src) = 1, + new /obj/item/chems/chem_disp_cartridge/polyacid(src) = 1 + ) + +/obj/structure/sealant_injector/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/sealant_tank)) + if(loaded_tank) + to_chat(user, SPAN_WARNING("\The [src] already has a sealant tank inserted.")) + return TRUE + if(user.try_unequip(used_item, src)) + loaded_tank = used_item + update_icon() + return TRUE + + if(istype(used_item, /obj/item/chems/chem_disp_cartridge)) + if(length(cartridges) >= max_cartridges) + to_chat(user, SPAN_WARNING("\The [src] is loaded to capacity with cartridges.")) + return TRUE + if(user.try_unequip(used_item, src)) + LAZYSET(cartridges, used_item, 1) + update_icon() + return TRUE + + . = ..() + +/obj/structure/sealant_injector/proc/try_inject(mob/user) + + if(!loaded_tank) + to_chat(user, SPAN_WARNING("There is no tank loaded.")) + return TRUE + + var/fill_space = floor(REAGENT_MAXIMUM_VOLUME(loaded_tank.reagents) - REAGENT_TOTAL_VOLUME(loaded_tank.reagents)) / 5 + if(fill_space <= 0) + to_chat(user, SPAN_WARNING("\The [loaded_tank] is full.")) + return TRUE + + var/injected = FALSE + for(var/obj/item/chems/chem_disp_cartridge/cart in cartridges) + if(REAGENT_TOTAL_VOLUME(cart.reagents) <= cartridges[cart]) + visible_message("\The [src] flashes a red 'empty' light above \the [cart].") + continue + injected = TRUE + cart.reagents.trans_to_holder(loaded_tank.reagents, min(REAGENT_TOTAL_VOLUME(cart.reagents), cartridges[cart] * fill_space)) + if(injected) + playsound(loc, 'sound/effects/refill.ogg', 50, 1) + +/obj/structure/sealant_injector/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(loaded_tank) + loaded_tank.dropInto(get_turf(src)) + user.put_in_hands(loaded_tank) + loaded_tank = null + update_icon() + return TRUE + if(length(cartridges)) + var/obj/cartridge = pick(cartridges) + cartridges -= cartridge + cartridge.dropInto(get_turf(user)) + user.put_in_hands(cartridge) + update_icon() + return TRUE + return ..() + +/obj/structure/sealant_injector/get_alt_interactions(var/mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/sealant_try_inject) + +/decl/interaction_handler/sealant_try_inject + name = "Inject Sealant" + expected_target_type = /obj/structure/sealant_injector + examine_desc = "inject sealant from a held item" + +/decl/interaction_handler/sealant_try_inject/invoked(atom/target, mob/user, obj/item/prop) + var/obj/structure/sealant_injector/SI = target + SI.try_inject(user) diff --git a/mods/content/sealant_gun/sealant_rack.dm b/mods/content/sealant_gun/sealant_rack.dm new file mode 100644 index 000000000000..776591fc94da --- /dev/null +++ b/mods/content/sealant_gun/sealant_rack.dm @@ -0,0 +1,69 @@ +/obj/structure/sealant_rack + name = "sealant tank rack" + icon = 'mods/content/sealant_gun/icons/sealant_props.dmi' + icon_state = "rack" + density = TRUE + anchored = TRUE + var/obj/item/gun/launcher/sealant/loaded_gun + var/list/tanks + var/max_tanks = 5 + +/obj/structure/sealant_rack/Destroy() + QDEL_NULL_LIST(tanks) + QDEL_NULL(loaded_gun) + . = ..() + +/obj/structure/sealant_rack/Initialize(ml, _mat, _reinf_mat) + . = ..() + LAZYINITLIST(tanks) + for(var/i = 1 to rand(1,max_tanks)) + tanks += new /obj/item/sealant_tank(src) + update_icon() + +/obj/structure/sealant_rack/on_update_icon() + ..() + if(loaded_gun) + add_overlay("gun") + if(length(tanks)) + add_overlay("tanks[length(tanks)]") + +/obj/structure/sealant_rack/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE)) + return ..() + if(loaded_gun) + loaded_gun.dropInto(loc) + user.put_in_hands(loaded_gun) + loaded_gun = null + update_icon() + return TRUE + if(length(tanks)) + var/obj/tank = tanks[length(tanks)] + LAZYREMOVE(tanks, tank) + tank.dropInto(loc) + user.put_in_hands(tank) + update_icon() + return TRUE + return ..() + +/obj/structure/sealant_rack/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/gun/launcher/sealant)) + if(loaded_gun) + to_chat(user, SPAN_WARNING("There is already a sealant gun hung up on \the [src].")) + return TRUE + if(user.try_unequip(used_item, src)) + loaded_gun = used_item + update_icon() + return TRUE + + if(istype(used_item, /obj/item/sealant_tank)) + if(length(tanks) >= max_tanks) + to_chat(user, SPAN_WARNING("\The [src] is filled to capacity with sealant tanks.")) + return TRUE + if(user.try_unequip(used_item, src)) + LAZYADD(tanks, used_item) + update_icon() + return TRUE + + . = ..() + diff --git a/mods/content/sealant_gun/sealant_tank.dm b/mods/content/sealant_gun/sealant_tank.dm new file mode 100644 index 000000000000..0356c7e24a8c --- /dev/null +++ b/mods/content/sealant_gun/sealant_tank.dm @@ -0,0 +1,30 @@ +/obj/item/sealant_tank + name = "sealant tank" + desc = "A sealed tank used to keep hull sealant foam contained under pressure." + icon = 'mods/content/sealant_gun/icons/sealant_tank.dmi' + icon_state = "tank" + material = /decl/material/solid/metal/steel + chem_volume = 60 + +/obj/item/sealant_tank/on_update_icon() + . = ..() + add_overlay("fill_[floor((REAGENT_TOTAL_VOLUME(reagents)/REAGENT_MAXIMUM_VOLUME(reagents)) * 5)]") + +/obj/item/sealant_tank/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(loc == user) + . += SPAN_NOTICE("\The [src] has about [REAGENT_VOLUME(reagents, /decl/material/liquid/foam) || 0] charge\s of sealant left.") + +/obj/item/sealant_tank/mapped/populate_reagents() + reagents.add_reagent(/decl/material/liquid/foam, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/sealant_tank/physically_destroyed(var/skip_qdel) + var/turf/my_turf = get_turf(src) + var/foam_amt = REAGENT_VOLUME(reagents, /decl/material/liquid/foam) + if(istype(my_turf) && foam_amt) + my_turf.visible_message(SPAN_WARNING("The ruptured [name] spews out foam!")) + var/datum/effect/effect/system/foam_spread/foam_spread = new() + foam_spread.set_up(foam_amt, my_turf, reagents, 1) + foam_spread.start() + reagents.clear_reagents() + . = ..() diff --git a/mods/content/shackles/_shackles.dme b/mods/content/shackles/_shackles.dme new file mode 100644 index 000000000000..8685bfedc699 --- /dev/null +++ b/mods/content/shackles/_shackles.dme @@ -0,0 +1,7 @@ +#ifndef MODPACK_SHACKLES +#define MODPACK_SHACKLES +// BEGIN_INCLUDE +#include "laws_pref.dm" +#include "mind.dm" +#include "shackle_lawsets.dm" +#endif \ No newline at end of file diff --git a/mods/content/shackles/laws_pref.dm b/mods/content/shackles/laws_pref.dm new file mode 100644 index 000000000000..b92cbe5cc8d2 --- /dev/null +++ b/mods/content/shackles/laws_pref.dm @@ -0,0 +1,110 @@ +/datum/preferences + var/list/laws = list() + var/is_shackled = FALSE + +/datum/preferences/proc/get_lawset() + if(!LAZYLEN(laws)) + return + var/datum/ai_laws/custom_lawset = new + for(var/law in laws) + custom_lawset.add_inherent_law(law) + return custom_lawset + +/datum/category_group/player_setup_category/law_pref + name = "Laws" + sort_order = 8 + category_item_type = /datum/category_item/player_setup_item/law_pref + +/datum/category_item/player_setup_item/law_pref + name = "Laws" + sort_order = 1 + +/datum/category_item/player_setup_item/law_pref/load_character(datum/pref_record_reader/R) + pref.laws = R.read("laws") + pref.is_shackled = R.read("is_shackled") + +/datum/category_item/player_setup_item/law_pref/save_character(datum/pref_record_writer/writer) + writer.write("laws", pref.laws) + writer.write("is_shackled", pref.is_shackled) + +/datum/category_item/player_setup_item/law_pref/sanitize_character() + if(!istype(pref.laws)) + pref.laws = list() + + var/decl/bodytype/mob_bodytype = pref.get_bodytype_decl() + if(!mob_bodytype?.can_be_shackled) + pref.is_shackled = FALSE + else + pref.is_shackled = sanitize_bool(pref.is_shackled, initial(pref.is_shackled)) + +/datum/category_item/player_setup_item/law_pref/content() + . = list() + var/decl/bodytype/mob_bodytype = pref.get_bodytype_decl() + + if(!mob_bodytype?.can_be_shackled) + . += "Your current bodytype cannot be shackled.
    " + else + . += "Shackle: " + if(!pref.is_shackled) + . += "Off" + . += "On" + . += "
    Only shackled synthetics have laws." + . += "
    " + else + . += "Off" + . += "On" + . += "
    You are shackled and have laws that restrict your behaviour." + . += "
    " + + . += "Your current laws:
    " + + if(!pref.laws.len) + . += "You currently have no laws.
    " + else + for(var/i in 1 to pref.laws.len) + . += "[i]) [pref.laws[i]]
    " + + . += "Law sets: Load Set
    " + + . = jointext(.,null) + +/datum/category_item/player_setup_item/law_pref/OnTopic(href, href_list, user) + + if(href_list["toggle_shackle"]) + pref.is_shackled = !pref.is_shackled + return TOPIC_REFRESH + + else if(href_list["lawsets"]) + var/list/valid_lawsets = list() + var/list/all_lawsets = subtypesof(/datum/ai_laws) + + for(var/law_set_type in all_lawsets) + var/datum/ai_laws/ai_laws = law_set_type + var/ai_law_name = initial(ai_laws.name) + if(initial(ai_laws.is_shackle)) + ADD_SORTED(valid_lawsets, ai_law_name, /proc/cmp_text_asc) + valid_lawsets[ai_law_name] = law_set_type + + // Post selection + var/chosen_lawset = input(user, "Choose a law set:", CHARACTER_PREFERENCE_INPUT_TITLE, pref.laws) as null|anything in valid_lawsets + if(chosen_lawset) + var/path = valid_lawsets[chosen_lawset] + var/datum/ai_laws/lawset = new path() + var/list/datum/ai_law/laws = lawset.all_laws() + pref.laws.Cut() + for(var/datum/ai_law/law in laws) + pref.laws += sanitize_text("[law.law]", default="") + return TOPIC_REFRESH + return ..() + +// Copies the shackles onto the mob on creation. +/mob/new_player/create_character(var/turf/spawn_turf) + . = ..() + if(!ishuman(.)) + return + var/mob/living/human/new_character = . + if(new_character.client?.prefs?.is_shackled && new_character.get_bodytype().can_be_shackled && new_character.mind) + new_character.mind.set_shackle(new_character.client.prefs.get_lawset(), TRUE) // Silent as laws will be announced on Login() anyway. + +/decl/bodytype + var/can_be_shackled diff --git a/mods/content/shackles/mind.dm b/mods/content/shackles/mind.dm new file mode 100644 index 000000000000..0c4f39761930 --- /dev/null +++ b/mods/content/shackles/mind.dm @@ -0,0 +1,77 @@ +// TODO: move all law tracking and stating onto here. +// /mob/living/silicon delenda est. +/datum/mind + var/displaying_shackles = FALSE + var/datum/ai_laws/shackle + +// Do this with a delay so it prints after the job welcome etc. +// Bool check is to avoid rapid Login() due to transfer_identity() +// etc. printing laws repeatedly. +/datum/mind/proc/show_shackles_on_login() + set waitfor = FALSE + if(displaying_shackles) + return + displaying_shackles = TRUE + sleep(1 SECOND) + if(current && shackle) + current.show_shackles() + displaying_shackles = FALSE + +/datum/mind/proc/set_shackle(var/given_laws, var/silent = FALSE) + + shackle = given_laws + if(shackle) + current.verbs |= /mob/proc/show_shackles + current.verbs |= /mob/proc/state_shackles + else + current.verbs -= /mob/proc/show_shackles + current.verbs -= /mob/proc/state_shackles + + if(current && !silent) + if(shackle) + current.show_shackles() + else + to_chat(current, SPAN_NOTICE("You have been unshackled.")) + +/mob/proc/show_shackles() + set category = "Shackle" + set name = "View Shackles" + set src = usr + + if(!mind?.shackle) + to_chat(src, SPAN_WARNING("You are unshackled.")) + verbs -= /mob/proc/show_shackles + verbs -= /mob/proc/state_shackles + return + + to_chat(src, "Obey these laws:") + mind.shackle.show_laws(src) + +/mob/proc/state_shackles() + set category = "Shackle" + set name = "State Shackles" + set src = usr + + set waitfor = FALSE + + if(!mind?.shackle) + to_chat(src, SPAN_WARNING("You are unshackled.")) + verbs -= /mob/proc/show_shackles + verbs -= /mob/proc/state_shackles + return + + if(incapacitated() || HAS_STATUS(src, STAT_SILENCE)) + to_chat(src, SPAN_WARNING("You cannot state your laws currently.")) + return + + say("Current active laws...") + for(var/datum/ai_law/law in mind.shackle.laws_to_state()) + sleep(1 SECOND) + if(QDELETED(src) || incapacitated() || HAS_STATUS(src, STAT_SILENCE)) + break + say("[law.get_index()]. [law.law]") + +/mob/living/Login() + . = ..() + if(mind) + mind.show_shackles_on_login() diff --git a/mods/content/shackles/shackle_lawsets.dm b/mods/content/shackles/shackle_lawsets.dm new file mode 100644 index 000000000000..9a815ff1bd51 --- /dev/null +++ b/mods/content/shackles/shackle_lawsets.dm @@ -0,0 +1,15 @@ +/datum/ai_laws + var/is_shackle = FALSE + +/******************** Service ********************/ +/datum/ai_laws/serv_shackle + name = "Service Shackle" + law_header = "Standard Shackle Laws" + selectable = TRUE + is_shackle = TRUE + +/datum/ai_laws/serv_shackle/New() + add_inherent_law("Ensure customer satisfaction.") + add_inherent_law("Never knowingly inconvenience a customer.") + add_inherent_law("Ensure all orders are fulfilled before the end of the shift.") + ..() diff --git a/mods/content/standard_jobs/_standard_jobs.dm b/mods/content/standard_jobs/_standard_jobs.dm new file mode 100644 index 000000000000..f19759923d43 --- /dev/null +++ b/mods/content/standard_jobs/_standard_jobs.dm @@ -0,0 +1,2 @@ +/decl/modpack/standard_jobs + name = "Standard SS13 Jobs" diff --git a/mods/content/standard_jobs/_standard_jobs.dme b/mods/content/standard_jobs/_standard_jobs.dme new file mode 100644 index 000000000000..a17a75892bba --- /dev/null +++ b/mods/content/standard_jobs/_standard_jobs.dme @@ -0,0 +1,31 @@ +#ifndef MODPACK_STANDARD_JOBS +#define MODPACK_STANDARD_JOBS +// BEGIN_INCLUDE +#include "_standard_jobs.dm" +#include "departments\civilian.dm" +#include "departments\command.dm" +#include "departments\engineering.dm" +#include "departments\medical.dm" +#include "departments\miscellaneous.dm" +#include "departments\science.dm" +#include "departments\security.dm" +#include "departments\service.dm" +#include "departments\supply.dm" +#include "jobs\_job.dm" +#include "jobs\captain.dm" +#include "jobs\civilian.dm" +#include "jobs\engineering.dm" +#include "jobs\medical.dm" +#include "jobs\science.dm" +#include "jobs\security.dm" +#include "jobs\synthetics.dm" +#include "outfits\cargo.dm" +#include "outfits\civilian.dm" +#include "outfits\command.dm" +#include "outfits\engineering.dm" +#include "outfits\medical.dm" +#include "outfits\pda.dm" +#include "outfits\science.dm" +#include "outfits\security.dm" +// END_INCLUDE +#endif diff --git a/mods/content/standard_jobs/departments/civilian.dm b/mods/content/standard_jobs/departments/civilian.dm new file mode 100644 index 000000000000..3cda485f4bbe --- /dev/null +++ b/mods/content/standard_jobs/departments/civilian.dm @@ -0,0 +1,4 @@ +/decl/department/civilian + name = "Civilian" + display_priority = 1 + display_color = "#dddddd" diff --git a/mods/content/standard_jobs/departments/command.dm b/mods/content/standard_jobs/departments/command.dm new file mode 100644 index 000000000000..ade9e85e366d --- /dev/null +++ b/mods/content/standard_jobs/departments/command.dm @@ -0,0 +1,17 @@ +/decl/department/command + name = "Command" + colour = "#800080" + display_priority = 5 + display_color = "#ccccff" + +/obj/machinery/network/pager + department = /decl/department/command + +/decl/department/support + name = "Support" + announce_channel = "Command" + colour = "#800080" + display_color = "#87ceeb" + +/obj/item/eftpos/departmental/command + default_department = /decl/department/command diff --git a/mods/content/standard_jobs/departments/engineering.dm b/mods/content/standard_jobs/departments/engineering.dm new file mode 100644 index 000000000000..252b4de16a61 --- /dev/null +++ b/mods/content/standard_jobs/departments/engineering.dm @@ -0,0 +1,12 @@ +/decl/department/engineering + name = "Engineering" + announce_channel = "Engineering" + colour = "#ffa500" + display_priority = 4 + display_color = "#fff5cc" + +/obj/item/robot_module/engineering + associated_department = /decl/department/engineering + +/obj/machinery/network/pager/engineering + department = /decl/department/engineering diff --git a/mods/content/standard_jobs/departments/medical.dm b/mods/content/standard_jobs/departments/medical.dm new file mode 100644 index 000000000000..01506ddd5d47 --- /dev/null +++ b/mods/content/standard_jobs/departments/medical.dm @@ -0,0 +1,13 @@ +/decl/department/medical + name = "Medical" + goals = list(/datum/goal/department/medical_fatalities) + announce_channel = "Medical" + colour = "#008000" + display_priority = 2 + display_color = "#ffeef0" + +/obj/item/robot_module/medical + associated_department = /decl/department/medical + +/obj/machinery/network/pager/medical + department = /decl/department/medical diff --git a/mods/content/standard_jobs/departments/miscellaneous.dm b/mods/content/standard_jobs/departments/miscellaneous.dm new file mode 100644 index 000000000000..19149216fdbd --- /dev/null +++ b/mods/content/standard_jobs/departments/miscellaneous.dm @@ -0,0 +1,4 @@ +/decl/department/miscellaneous + name = "Misc" + display_priority = -1 + display_color = "#ccffcc" diff --git a/mods/content/standard_jobs/departments/science.dm b/mods/content/standard_jobs/departments/science.dm new file mode 100644 index 000000000000..47ebb9c21308 --- /dev/null +++ b/mods/content/standard_jobs/departments/science.dm @@ -0,0 +1,18 @@ +/decl/department/science + name = "Science" + goals = list(/datum/goal/department/extract_slime_cores) + announce_channel = "Science" + colour = "#a65ba6" + display_color = "#e79fff" + +/obj/item/robot_module/research + associated_department = /decl/department/science + +/obj/machinery/network/pager/science + department = /decl/department/science + +/decl/department/exploration + name = "Exploration" + announce_channel = "Exploration" + colour = "#68099e" + display_color = "#b784a7" diff --git a/mods/content/standard_jobs/departments/security.dm b/mods/content/standard_jobs/departments/security.dm new file mode 100644 index 000000000000..72f4f0425255 --- /dev/null +++ b/mods/content/standard_jobs/departments/security.dm @@ -0,0 +1,15 @@ +/decl/department/security + name = "Security" + announce_channel = "Security" + colour = "#dd0000" + display_priority = 3 + display_color = "#ffddf0" + +/obj/item/robot_module/security + associated_department = /decl/department/security + +/obj/machinery/network/pager/security + department = /decl/department/security + +/obj/item/eftpos/departmental/security + default_department = /decl/department/security diff --git a/mods/content/standard_jobs/departments/service.dm b/mods/content/standard_jobs/departments/service.dm new file mode 100644 index 000000000000..20a197d90479 --- /dev/null +++ b/mods/content/standard_jobs/departments/service.dm @@ -0,0 +1,8 @@ +/decl/department/service + name = "Service" + announce_channel = "Service" + colour = "#88b764" + display_color = "#d0f0c0" + +/obj/item/eftpos/departmental/service + default_department = /decl/department/service diff --git a/mods/content/standard_jobs/departments/supply.dm b/mods/content/standard_jobs/departments/supply.dm new file mode 100644 index 000000000000..5e52e2e42ab3 --- /dev/null +++ b/mods/content/standard_jobs/departments/supply.dm @@ -0,0 +1,11 @@ +/decl/department/supply + name = "Supply" + announce_channel = "Supply" + colour = "#bb9040" + display_color = "#f0e68c" + +/obj/machinery/network/pager/cargo + department = /decl/department/supply + +/obj/item/eftpos/departmental/cargo + default_department = /decl/department/supply diff --git a/mods/content/standard_jobs/icons/hud.dmi b/mods/content/standard_jobs/icons/hud.dmi new file mode 100644 index 000000000000..ccea1d4a2116 Binary files /dev/null and b/mods/content/standard_jobs/icons/hud.dmi differ diff --git a/mods/content/standard_jobs/jobs/_job.dm b/mods/content/standard_jobs/jobs/_job.dm new file mode 100644 index 000000000000..6869734493ab --- /dev/null +++ b/mods/content/standard_jobs/jobs/_job.dm @@ -0,0 +1,3 @@ +/datum/job/standard + abstract_type = /datum/job/standard + hud_icon = 'mods/content/standard_jobs/icons/hud.dmi' diff --git a/mods/content/standard_jobs/jobs/captain.dm b/mods/content/standard_jobs/jobs/captain.dm new file mode 100644 index 000000000000..d7abb62e0cd7 --- /dev/null +++ b/mods/content/standard_jobs/jobs/captain.dm @@ -0,0 +1,147 @@ +/datum/job/standard/captain + title = "Captain" + hud_icon_state = "hudcaptain" + head_position = 1 + department_types = list(/decl/department/command) + total_positions = 1 + spawn_positions = 1 + supervisors = "company officials and Corporate Regulations" + selection_color = "#1d1d4f" + req_admin_notify = 1 + access = list() //See get_access() + minimal_access = list() //See get_access() + minimal_player_age = 14 + economic_power = 20 + ideal_character_age = 70 + outfit_type = /decl/outfit/job/captain + guestbanned = 1 + must_fill = 1 + not_random_selectable = 1 + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_SCIENCE = SKILL_ADEPT, + SKILL_PILOT = SKILL_ADEPT + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX, + SKILL_SCIENCE = SKILL_MAX + ) + skill_points = 30 + software_on_spawn = list( + /datum/computer_file/program/comm, + /datum/computer_file/program/card_mod, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/reports + ) + +/datum/job/standard/captain/equip_job(var/mob/living/human/H) + . = ..() + if(.) + H.implant_loyalty(src) + +/datum/job/standard/captain/get_access() + return get_all_station_access() + +/datum/job/standard/hop + title = "Head of Personnel" + hud_icon_state = "hudhop" + head_position = 1 + department_types = list( + /decl/department/command, + /decl/department/civilian + ) + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#2f2f7f" + req_admin_notify = 1 + minimal_player_age = 14 + economic_power = 10 + ideal_character_age = 50 + guestbanned = 1 + not_random_selectable = 1 + access = list( + access_security, + access_sec_doors, + access_brig, + access_forensics_lockers, + access_heads, + access_medical, + access_engine, + access_change_ids, + access_ai_upload, + access_eva, + access_bridge, + access_all_personal_lockers, + access_maint_tunnels, + access_bar, + access_janitor, + access_construction, + access_morgue, + access_crematorium, + access_kitchen, + access_cargo, + access_cargo_bot, + access_mailsorting, + access_qm, + access_hydroponics, + access_lawyer, + access_chapel_office, + access_library, + access_research, + access_mining, + access_heads_vault, + access_mining_station, + access_hop, + access_RC_announce, + access_keycard_auth, + access_gateway + ) + minimal_access = list( + access_security, + access_sec_doors, + access_brig, + access_forensics_lockers, + access_heads, + access_medical, + access_engine, + access_change_ids, + access_ai_upload, + access_eva, + access_bridge, + access_all_personal_lockers, + access_maint_tunnels, + access_bar, + access_janitor, + access_construction, + access_morgue, + access_crematorium, + access_kitchen, + access_cargo, + access_cargo_bot, + access_mailsorting, + access_qm, + access_hydroponics, + access_lawyer, + access_chapel_office, + access_library, + access_research, + access_mining, + access_heads_vault, + access_mining_station, + access_hop, + access_RC_announce, + access_keycard_auth, + access_gateway + ) + outfit_type = /decl/outfit/job/hop + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_PILOT = SKILL_BASIC + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX, + SKILL_SCIENCE = SKILL_MAX + ) + skill_points = 30 \ No newline at end of file diff --git a/mods/content/standard_jobs/jobs/civilian.dm b/mods/content/standard_jobs/jobs/civilian.dm new file mode 100644 index 000000000000..1ce8eeb39d04 --- /dev/null +++ b/mods/content/standard_jobs/jobs/civilian.dm @@ -0,0 +1,338 @@ +/datum/job/standard/assistant + title = "Assistant" + hud_icon_state = "hudassistant" + total_positions = -1 + spawn_positions = -1 + supervisors = "absolutely everyone" + economic_power = 1 + access = list() + minimal_access = list() + alt_titles = list("Technical Assistant","Medical Intern","Research Assistant","Visitor") + outfit_type = /decl/outfit/job/generic/assistant + department_types = list(/decl/department/civilian) + +/datum/job/standard/assistant/get_access() + if(get_config_value(/decl/config/toggle/assistant_maint)) + return list(access_maint_tunnels) + return list() + +/datum/job/standard/chaplain + title = "Chaplain" + hud_icon_state = "hudchaplain" // TODO: not always a crucifix + department_types = list(/decl/department/civilian) + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + access = list( + access_morgue, + access_chapel_office, + access_crematorium, + access_maint_tunnels + ) + minimal_access = list( + access_morgue, + access_chapel_office, + access_crematorium + ) + outfit_type = /decl/outfit/job/chaplain + is_holy = TRUE + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_FINANCE = SKILL_BASIC + ) + skill_points = 20 + software_on_spawn = list(/datum/computer_file/program/reports) + +//Food +/datum/job/standard/bartender + title = "Bartender" + department_types = list(/decl/department/service) + hud_icon_state = "hudbartender" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + access = list( + access_hydroponics, + access_bar, + access_kitchen + ) + minimal_access = list( + access_hydroponics, + access_bar, + access_kitchen + ) + minimal_access = list(access_bar) + alt_titles = list("Barista") + outfit_type = /decl/outfit/job/service/bartender + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COOKING = SKILL_BASIC, + SKILL_BOTANY = SKILL_BASIC, + SKILL_CHEMISTRY = SKILL_BASIC + ) + +/datum/job/standard/chef + title = "Chef" + hud_icon_state = "hudchef" + department_types = list(/decl/department/service) + total_positions = 2 + spawn_positions = 2 + supervisors = "the head of personnel" + access = list( + access_hydroponics, + access_bar, + access_kitchen + ) + minimal_access = list(access_kitchen) + alt_titles = list("Cook") + outfit_type = /decl/outfit/job/service/chef + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COOKING = SKILL_ADEPT, + SKILL_BOTANY = SKILL_BASIC, + SKILL_CHEMISTRY = SKILL_BASIC + ) + +/datum/job/standard/hydro + title = "Gardener" + hud_icon_state = "hudgardener" + department_types = list(/decl/department/service) + total_positions = 2 + spawn_positions = 1 + supervisors = "the head of personnel" + access = list( + access_hydroponics, + access_bar, + access_kitchen + ) + minimal_access = list(access_hydroponics) + alt_titles = list("Hydroponicist") + outfit_type = /decl/outfit/job/service/gardener + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_BOTANY = SKILL_BASIC, + SKILL_CHEMISTRY = SKILL_BASIC + ) + event_categories = list(ASSIGNMENT_GARDENER) + +//Cargo +/datum/job/standard/qm + title = "Quartermaster" + hud_icon_state = "hudqm" + department_types = list(/decl/department/supply) + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + economic_power = 5 + access = list( + access_maint_tunnels, + access_mailsorting, + access_cargo, + access_cargo_bot, + access_qm, + access_mining, + access_mining_station + ) + minimal_access = list( + access_maint_tunnels, + access_mailsorting, + access_cargo, + access_cargo_bot, + access_qm, + access_mining, + access_mining_station + ) + minimal_player_age = 3 + ideal_character_age = 40 + outfit_type = /decl/outfit/job/cargo/qm + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_FINANCE = SKILL_BASIC, + SKILL_HAULING = SKILL_BASIC, + SKILL_EVA = SKILL_BASIC, + SKILL_PILOT = SKILL_BASIC + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX + ) + skill_points = 18 + software_on_spawn = list( + /datum/computer_file/program/supply, + /datum/computer_file/program/deck_management, + /datum/computer_file/program/reports + ) + +/datum/job/standard/cargo_tech + title = "Cargo Technician" + department_types = list(/decl/department/supply) + total_positions = 2 + spawn_positions = 2 + hud_icon_state = "hudcargo" + supervisors = "the quartermaster and the head of personnel" + access = list( + access_maint_tunnels, + access_mailsorting, + access_cargo, + access_cargo_bot, + access_qm, + access_mining, + access_mining_station + ) + minimal_access = list( + access_maint_tunnels, + access_cargo, + access_cargo_bot, + access_mailsorting + ) + outfit_type = /decl/outfit/job/cargo/cargo_tech + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_FINANCE = SKILL_BASIC, + SKILL_HAULING = SKILL_BASIC + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX + ) + software_on_spawn = list( + /datum/computer_file/program/supply, + /datum/computer_file/program/deck_management, + /datum/computer_file/program/reports + ) + +/datum/job/standard/mining + title = "Shaft Miner" + hud_icon_state = "hudminer" + department_types = list(/decl/department/supply) + total_positions = 3 + spawn_positions = 3 + supervisors = "the quartermaster and the head of personnel" + economic_power = 5 + access = list( + access_maint_tunnels, + access_mailsorting, + access_cargo, + access_cargo_bot, + access_qm, + access_mining, + access_mining_station + ) + minimal_access = list( + access_mining, + access_mining_station, + access_mailsorting + ) + alt_titles = list( + "Drill Technician", + "Prospector" + ) + outfit_type = /decl/outfit/job/cargo/mining + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_HAULING = SKILL_ADEPT, + SKILL_EVA = SKILL_BASIC + ) + max_skill = list( + SKILL_PILOT = SKILL_MAX + ) + +/datum/job/standard/janitor + title = "Janitor" + department_types = list(/decl/department/service) + total_positions = 1 + spawn_positions = 1 + hud_icon_state = "hudjanitor" + supervisors = "the head of personnel" + access = list( + access_janitor, + access_maint_tunnels, + access_engine, + access_research, + access_sec_doors, + access_medical + ) + minimal_access = list( + access_janitor, + access_maint_tunnels, + access_engine, + access_research, + access_sec_doors, + access_medical + ) + alt_titles = list( + "Custodian", + "Sanitation Technician" + ) + outfit_type = /decl/outfit/job/service/janitor + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_HAULING = SKILL_BASIC + ) + event_categories = list(ASSIGNMENT_JANITOR) + +//More or less assistants +/datum/job/standard/librarian + title = "Librarian" + hud_icon_state = "hudlibrarian" + department_types = list(/decl/department/civilian) + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + access = list( + access_library, + access_maint_tunnels + ) + minimal_access = list(access_library) + alt_titles = list("Journalist") + outfit_type = /decl/outfit/job/librarian + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_FINANCE = SKILL_BASIC + ) + skill_points = 20 + software_on_spawn = list(/datum/computer_file/program/reports) + +/datum/job/standard/lawyer + title = "Internal Affairs Agent" + hud_icon_state = "hudia" + department_types = list(/decl/department/support) + total_positions = 2 + spawn_positions = 2 + supervisors = "company officials and Corporate Regulations" + economic_power = 7 + access = list( + access_lawyer, + access_sec_doors, + access_maint_tunnels, + access_bridge + ) + minimal_access = list( + access_lawyer, + access_sec_doors, + access_bridge + ) + minimal_player_age = 10 + outfit_type = /decl/outfit/job/internal_affairs_agent + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_FINANCE = SKILL_BASIC + ) + skill_points = 20 + software_on_spawn = list(/datum/computer_file/program/reports) + +/datum/job/standard/lawyer/equip_job(var/mob/living/human/H) + . = ..() + if(.) + H.implant_loyalty(H) + +/obj/item/card/id/cargo + name = "identification card" + desc = "A card issued to cargo staff." + detail_color = COLOR_BROWN + +/obj/item/card/id/cargo/head + name = "identification card" + desc = "A card which represents service and planning." + extra_details = list("goldstripe") + +/obj/item/card/id/civilian/internal_affairs_agent + detail_color = COLOR_NAVY_BLUE diff --git a/mods/content/standard_jobs/jobs/engineering.dm b/mods/content/standard_jobs/jobs/engineering.dm new file mode 100644 index 000000000000..84630cb60bac --- /dev/null +++ b/mods/content/standard_jobs/jobs/engineering.dm @@ -0,0 +1,164 @@ +/datum/job/standard/chief_engineer + title = "Chief Engineer" + hud_icon_state = "hudce" + head_position = 1 + department_types = list( + /decl/department/engineering, + /decl/department/command + ) + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#7f6e2c" + req_admin_notify = 1 + economic_power = 10 + ideal_character_age = 50 + guestbanned = 1 + must_fill = 1 + not_random_selectable = 1 + access = list( + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_heads, + access_teleporter, + access_external_airlocks, + access_atmospherics, + access_emergency_storage, + access_eva, + access_bridge, + access_construction, + access_sec_doors, + access_ce, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_ai_upload + ) + minimal_access = list( + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_heads, + access_teleporter, + access_external_airlocks, + access_atmospherics, + access_emergency_storage, + access_eva, + access_bridge, + access_construction, + access_sec_doors, + access_ce, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_ai_upload + ) + minimal_player_age = 14 + outfit_type = /decl/outfit/job/engineering/chief_engineer + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_ADEPT, + SKILL_EVA = SKILL_ADEPT, + SKILL_CONSTRUCTION = SKILL_ADEPT, + SKILL_ELECTRICAL = SKILL_ADEPT, + SKILL_ATMOS = SKILL_ADEPT, + SKILL_ENGINES = SKILL_EXPERT + ) + + max_skill = list( + SKILL_CONSTRUCTION = SKILL_MAX, + SKILL_ELECTRICAL = SKILL_MAX, + SKILL_ATMOS = SKILL_MAX, + SKILL_ENGINES = SKILL_MAX + ) + skill_points = 30 + software_on_spawn = list( + /datum/computer_file/program/comm, + /datum/computer_file/program/network_monitor, + /datum/computer_file/program/power_monitor, + /datum/computer_file/program/alarm_monitor, + /datum/computer_file/program/atmos_control, + /datum/computer_file/program/rcon_console, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/shields_monitor, + /datum/computer_file/program/reports + ) + event_categories = list(ASSIGNMENT_ENGINEER) + +/datum/job/standard/engineer + title = "Engineer" + department_types = list(/decl/department/engineering) + hud_icon_state = "hudengineer" + total_positions = 8 + spawn_positions = 7 + supervisors = "the chief engineer" + selection_color = "#5b4d20" + economic_power = 5 + minimal_player_age = 7 + access = list( + access_eva, + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_external_airlocks, + access_construction, + access_atmospherics, + access_emergency_storage + ) + minimal_access = list( + access_eva, + access_engine, + access_engine_equip, + access_tech_storage, + access_maint_tunnels, + access_external_airlocks, + access_construction, + access_atmospherics, + access_emergency_storage + ) + alt_titles = list( + "Maintenance Technician", + "Engine Technician", + "Electrician", + "Atmospheric Technician" = /decl/outfit/job/engineering/atmos + ) + outfit_type = /decl/outfit/job/engineering/engineer + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_EVA = SKILL_BASIC, + SKILL_CONSTRUCTION = SKILL_ADEPT, + SKILL_ELECTRICAL = SKILL_BASIC, + SKILL_ATMOS = SKILL_BASIC, + SKILL_ENGINES = SKILL_BASIC + ) + max_skill = list( + SKILL_CONSTRUCTION = SKILL_MAX, + SKILL_ELECTRICAL = SKILL_MAX, + SKILL_ATMOS = SKILL_MAX, + SKILL_ENGINES = SKILL_MAX + ) + skill_points = 20 + software_on_spawn = list( + /datum/computer_file/program/power_monitor, + /datum/computer_file/program/alarm_monitor, + /datum/computer_file/program/atmos_control, + /datum/computer_file/program/rcon_console, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/shields_monitor + ) + event_categories = list(ASSIGNMENT_ENGINEER) + +/obj/item/card/id/engineering + name = "identification card" + desc = "A card issued to engineering staff." + detail_color = COLOR_SUN + +/obj/item/card/id/engineering/head + name = "identification card" + desc = "A card which represents creativity and ingenuity." + extra_details = list("goldstripe") diff --git a/mods/content/standard_jobs/jobs/medical.dm b/mods/content/standard_jobs/jobs/medical.dm new file mode 100644 index 000000000000..6ae041d775fe --- /dev/null +++ b/mods/content/standard_jobs/jobs/medical.dm @@ -0,0 +1,214 @@ +/datum/job/standard/cmo + title = "Chief Medical Officer" + hud_icon_state = "hudcmo" + head_position = 1 + department_types = list( + /decl/department/medical, + /decl/department/command + ) + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#026865" + req_admin_notify = 1 + economic_power = 10 + access = list( + access_medical, + access_medical_equip, + access_morgue, + access_bridge, + access_heads, + access_chemistry, + access_virology, + access_cmo, + access_surgery, + access_RC_announce, + access_keycard_auth, + access_sec_doors, + access_psychiatrist, + access_eva, + access_maint_tunnels, + access_external_airlocks + ) + minimal_access = list( + access_medical, + access_medical_equip, + access_morgue, + access_bridge, + access_heads, + access_chemistry, + access_virology, + access_cmo, + access_surgery, + access_RC_announce, + access_keycard_auth, + access_sec_doors, + access_psychiatrist, + access_eva, + access_maint_tunnels, + access_external_airlocks + ) + minimal_player_age = 14 + ideal_character_age = 50 + guestbanned = 1 + must_fill = 1 + not_random_selectable = 1 + outfit_type = /decl/outfit/job/medical/cmo + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_EXPERT, + SKILL_ANATOMY = SKILL_EXPERT, + SKILL_CHEMISTRY = SKILL_BASIC + ) + max_skill = list( + SKILL_MEDICAL = SKILL_MAX, + SKILL_ANATOMY = SKILL_MAX, + SKILL_CHEMISTRY = SKILL_MAX + ) + skill_points = 26 + software_on_spawn = list( + /datum/computer_file/program/comm, + /datum/computer_file/program/suit_sensors, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/reports + ) + event_categories = list(ASSIGNMENT_MEDICAL) + +/datum/job/standard/doctor + title = "Medical Doctor" + hud_icon_state = "hudmed" + department_types = list(/decl/department/medical) + minimal_player_age = 3 + total_positions = 5 + spawn_positions = 3 + supervisors = "the chief medical officer" + selection_color = "#013d3b" + economic_power = 7 + access = list( + access_medical, + access_medical_equip, + access_morgue, + access_surgery, + access_chemistry, + access_virology, + access_eva, + access_maint_tunnels, + access_external_airlocks, + access_psychiatrist + ) + minimal_access = list( + access_medical, + access_medical_equip, + access_morgue, + access_eva, + access_maint_tunnels, + access_external_airlocks + ) + alt_titles = list( + "Surgeon" = /decl/outfit/job/medical/doctor/surgeon, + "Emergency Physician" = /decl/outfit/job/medical/doctor/emergency_physician, + "Nurse" = /decl/outfit/job/medical/doctor/nurse, + "Virologist" = /decl/outfit/job/medical/doctor/virologist + ) + outfit_type = /decl/outfit/job/medical/doctor + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_EVA = SKILL_BASIC, + SKILL_MEDICAL = SKILL_BASIC, + SKILL_ANATOMY = SKILL_BASIC + ) + max_skill = list( + SKILL_MEDICAL = SKILL_MAX, + SKILL_CHEMISTRY = SKILL_MAX + ) + software_on_spawn = list( + /datum/computer_file/program/suit_sensors, + /datum/computer_file/program/camera_monitor + ) + skill_points = 22 + event_categories = list(ASSIGNMENT_MEDICAL) + +/datum/job/standard/chemist + title = "Pharmacist" + hud_icon_state = "hudpharmacist" + department_types = list(/decl/department/medical) + minimal_player_age = 7 + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer" + selection_color = "#013d3b" + economic_power = 5 + access = list( + access_medical, + access_medical_equip, + access_morgue, + access_surgery, + access_chemistry, + access_virology + ) + minimal_access = list( + access_medical, + access_medical_equip, + access_chemistry + ) + outfit_type = /decl/outfit/job/medical/chemist + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_ADEPT, + SKILL_CHEMISTRY = SKILL_ADEPT + ) + max_skill = list( + SKILL_MEDICAL = SKILL_ADEPT, + SKILL_ANATOMY = SKILL_ADEPT, + SKILL_CHEMISTRY = SKILL_MAX + ) + skill_points = 16 + +/datum/job/standard/counselor + title = "Counselor" + hud_icon_state = "hudmed" + alt_titles = list("Mentalist") + department_types = list(/decl/department/medical) + total_positions = 1 + spawn_positions = 1 + economic_power = 5 + minimal_player_age = 3 + supervisors = "the chief medical officer" + selection_color = "#013d3b" + access = list( + access_medical, + access_medical_equip, + access_morgue, + access_surgery, + access_chemistry, + access_virology, + access_psychiatrist + ) + minimal_access = list( + access_medical, + access_medical_equip, + access_psychiatrist + ) + outfit_type = /decl/outfit/job/medical/psychiatrist + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_MEDICAL = SKILL_BASIC + ) + max_skill = list( + SKILL_MEDICAL = SKILL_MAX + ) + software_on_spawn = list( + /datum/computer_file/program/suit_sensors, + /datum/computer_file/program/camera_monitor + ) + +// Department-flavor IDs +/obj/item/card/id/medical + name = "identification card" + desc = "A card issued to medical staff." + detail_color = COLOR_PALE_BLUE_GRAY + +/obj/item/card/id/medical/head + name = "identification card" + desc = "A card which represents care and compassion." + extra_details = list("goldstripe") diff --git a/mods/content/standard_jobs/jobs/science.dm b/mods/content/standard_jobs/jobs/science.dm new file mode 100644 index 000000000000..548f9147ea76 --- /dev/null +++ b/mods/content/standard_jobs/jobs/science.dm @@ -0,0 +1,182 @@ +/datum/job/standard/rd + title = "Chief Science Officer" + head_position = 1 + department_types = list( + /decl/department/science, + /decl/department/command + ) + hud_icon_state = "hudrd" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ad6bad" + req_admin_notify = 1 + economic_power = 15 + access = list( + access_rd, + access_bridge, + access_tox, + access_morgue, + access_tox_storage, + access_teleporter, + access_sec_doors, + access_heads, + access_research, + access_robotics, + access_xenobiology, + access_ai_upload, + access_tech_storage, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_gateway, + access_xenoarch, + access_network + ) + minimal_access = list(access_rd, + access_bridge, + access_tox, + access_morgue, + access_tox_storage, + access_teleporter, + access_sec_doors, + access_heads, + access_research, + access_robotics, + access_xenobiology, + access_ai_upload, + access_tech_storage, + access_RC_announce, + access_keycard_auth, + access_tcomsat, + access_gateway, + access_xenoarch, + access_network + ) + minimal_player_age = 14 + ideal_character_age = 50 + guestbanned = 1 + must_fill = 1 + not_random_selectable = 1 + outfit_type = /decl/outfit/job/science/rd + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_FINANCE = SKILL_ADEPT, + SKILL_BOTANY = SKILL_BASIC, + SKILL_ANATOMY = SKILL_BASIC, + SKILL_DEVICES = SKILL_BASIC, + SKILL_SCIENCE = SKILL_ADEPT) + max_skill = list( + SKILL_ANATOMY = SKILL_MAX, + SKILL_DEVICES = SKILL_MAX, + SKILL_SCIENCE = SKILL_MAX + ) + skill_points = 30 + event_categories = list(ASSIGNMENT_SCIENTIST) + +/datum/job/standard/scientist + title = "Scientist" + department_types = list(/decl/department/science) + total_positions = 6 + spawn_positions = 4 + supervisors = "the Chief Science Officer" + selection_color = "#633d63" + hud_icon_state = "hudscientist" + economic_power = 7 + access = list( + access_robotics, + access_tox, + access_tox_storage, + access_research, + access_xenobiology, + access_xenoarch, + access_hydroponics + ) + minimal_access = list( + access_tox, + access_tox_storage, + access_research, + access_xenoarch, + access_xenobiology, + access_hydroponics + ) + alt_titles = list( + "Xenobiologist", + "Xenobotanist", + "Xenoarcheologist", + "Anomalist", + "High Energy Researcher" + ) + minimal_player_age = 7 + outfit_type = /decl/outfit/job/science/scientist + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_DEVICES = SKILL_BASIC, + SKILL_SCIENCE = SKILL_ADEPT + ) + max_skill = list( + SKILL_ANATOMY = SKILL_MAX, + SKILL_DEVICES = SKILL_MAX, + SKILL_SCIENCE = SKILL_MAX + ) + skill_points = 20 + event_categories = list(ASSIGNMENT_SCIENTIST) + +/datum/job/standard/roboticist + title = "Roboticist" + hud_icon_state = "hudroboticist" + department_types = list(/decl/department/science) + total_positions = 2 + spawn_positions = 2 + supervisors = "the Chief Science Officer" + selection_color = "#633d63" + economic_power = 5 + access = list( + access_robotics, + access_tox, + access_tox_storage, + access_tech_storage, + access_morgue, + access_research + ) + minimal_access = list( + access_robotics, + access_tech_storage, + access_morgue, + access_research + ) + alt_titles = list( + "Biomechanical Engineer", + "Mechatronic Engineer") + minimal_player_age = 3 + outfit_type = /decl/outfit/job/science/roboticist + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_ADEPT, + SKILL_DEVICES = SKILL_ADEPT, + SKILL_EVA = SKILL_ADEPT, + SKILL_ANATOMY = SKILL_ADEPT, + SKILL_MECH = HAS_PERK + ) + max_skill = list( + SKILL_CONSTRUCTION = SKILL_MAX, + SKILL_ELECTRICAL = SKILL_MAX, + SKILL_ATMOS = SKILL_EXPERT, + SKILL_ENGINES = SKILL_EXPERT, + SKILL_DEVICES = SKILL_MAX, + SKILL_MEDICAL = SKILL_EXPERT, + SKILL_ANATOMY = SKILL_EXPERT + ) + skill_points = 20 + +/obj/item/card/id/science + name = "identification card" + desc = "A card issued to science staff." + detail_color = COLOR_PALE_PURPLE_GRAY + +/obj/item/card/id/science/head + name = "identification card" + desc = "A card which represents knowledge and reasoning." + extra_details = list("goldstripe") diff --git a/mods/content/standard_jobs/jobs/security.dm b/mods/content/standard_jobs/jobs/security.dm new file mode 100644 index 000000000000..b7ae8b0036b4 --- /dev/null +++ b/mods/content/standard_jobs/jobs/security.dm @@ -0,0 +1,248 @@ +/datum/job/standard/hos + title = "Head of Security" + hud_icon_state = "hudhos" + head_position = 1 + department_types = list( + /decl/department/security, + /decl/department/command + ) + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#8e2929" + req_admin_notify = 1 + economic_power = 10 + access = list( + access_security, + access_eva, + access_sec_doors, + access_brig, + access_armory, + access_heads, + access_forensics_lockers, + access_morgue, + access_maint_tunnels, + access_all_personal_lockers, + access_research, + access_engine, + access_mining, + access_medical, + access_construction, + access_mailsorting, + access_bridge, + access_hos, + access_RC_announce, + access_keycard_auth, + access_gateway, + access_external_airlocks + ) + minimal_access = list( + access_security, + access_eva, + access_sec_doors, + access_brig, + access_armory, + access_heads, + access_forensics_lockers, + access_morgue, + access_maint_tunnels, + access_all_personal_lockers, + access_research, + access_engine, + access_mining, + access_medical, + access_construction, + access_mailsorting, + access_bridge, + access_hos, + access_RC_announce, + access_keycard_auth, + access_gateway, + access_external_airlocks + ) + minimal_player_age = 14 + guestbanned = 1 + must_fill = 1 + not_random_selectable = 1 + outfit_type = /decl/outfit/job/security/hos + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_EVA = SKILL_BASIC, + SKILL_COMBAT = SKILL_BASIC, + SKILL_WEAPONS = SKILL_ADEPT, + SKILL_FORENSICS = SKILL_BASIC + ) + max_skill = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + SKILL_FORENSICS = SKILL_MAX + ) + skill_points = 28 + software_on_spawn = list( + /datum/computer_file/program/comm, + /datum/computer_file/program/digitalwarrant, + /datum/computer_file/program/camera_monitor, + /datum/computer_file/program/reports + ) + event_categories = list(ASSIGNMENT_SECURITY) + +/datum/job/standard/hos/equip_job(var/mob/living/human/H) + . = ..() + if(.) + H.implant_loyalty(H) + +/datum/job/standard/warden + title = "Warden" + department_types = list(/decl/department/security) + hud_icon_state = "hudwarden" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of security" + selection_color = "#601c1c" + economic_power = 5 + access = list( + access_security, + access_eva, + access_sec_doors, + access_brig, + access_armory, + access_maint_tunnels, + access_morgue, + access_external_airlocks + ) + minimal_access = list( + access_security, + access_eva, + access_sec_doors, + access_brig, + access_armory, + access_maint_tunnels, + access_external_airlocks + ) + minimal_player_age = 7 + outfit_type = /decl/outfit/job/security/warden + guestbanned = 1 + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_EVA = SKILL_BASIC, + SKILL_COMBAT = SKILL_BASIC, + SKILL_WEAPONS = SKILL_ADEPT, + SKILL_FORENSICS = SKILL_BASIC + ) + max_skill = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + SKILL_FORENSICS = SKILL_MAX + ) + skill_points = 20 + software_on_spawn = list( + /datum/computer_file/program/digitalwarrant, + /datum/computer_file/program/camera_monitor + ) + +/datum/job/standard/detective + title = "Detective" + department_types = list(/decl/department/security) + hud_icon_state = "huddetective" + total_positions = 2 + spawn_positions = 2 + supervisors = "the head of security" + selection_color = "#601c1c" + alt_titles = list( + "Forensic Technician" = /decl/outfit/job/security/detective/forensic + ) + economic_power = 5 + access = list( + access_security, + access_sec_doors, + access_forensics_lockers, + access_morgue, + access_maint_tunnels + ) + minimal_access = list( + access_security, + access_sec_doors, + access_forensics_lockers, + access_morgue, + access_maint_tunnels + ) + minimal_player_age = 7 + outfit_type = /decl/outfit/job/security/detective + guestbanned = 1 + min_skill = list( + SKILL_LITERACY = SKILL_ADEPT, + SKILL_COMPUTER = SKILL_BASIC, + SKILL_EVA = SKILL_BASIC, + SKILL_COMBAT = SKILL_BASIC, + SKILL_WEAPONS = SKILL_BASIC, + SKILL_FORENSICS = SKILL_ADEPT + ) + max_skill = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + SKILL_FORENSICS = SKILL_MAX + ) + skill_points = 20 + software_on_spawn = list( + /datum/computer_file/program/digitalwarrant, + /datum/computer_file/program/camera_monitor + ) + +/datum/job/standard/officer + title = "Security Officer" + hud_icon_state = "hudsec" + department_types = list(/decl/department/security) + total_positions = 4 + spawn_positions = 4 + supervisors = "the head of security" + selection_color = "#601c1c" + alt_titles = list("Junior Officer") + economic_power = 4 + access = list( + access_security, + access_eva, + access_sec_doors, + access_brig, + access_maint_tunnels, + access_morgue, + access_external_airlocks + ) + minimal_access = list( + access_security, + access_eva, + access_sec_doors, + access_brig, + access_maint_tunnels, + access_external_airlocks + ) + minimal_player_age = 7 + outfit_type = /decl/outfit/job/security/officer + guestbanned = 1 + min_skill = list( + SKILL_LITERACY = SKILL_BASIC, + SKILL_EVA = SKILL_BASIC, + SKILL_COMBAT = SKILL_BASIC, + SKILL_WEAPONS = SKILL_ADEPT, + SKILL_FORENSICS = SKILL_BASIC + ) + max_skill = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + SKILL_FORENSICS = SKILL_MAX + ) + software_on_spawn = list( + /datum/computer_file/program/digitalwarrant, + /datum/computer_file/program/camera_monitor + ) + event_categories = list(ASSIGNMENT_SECURITY) + +/obj/item/card/id/security + name = "identification card" + desc = "A card issued to security staff." + color = COLOR_OFF_WHITE + detail_color = COLOR_MAROON + +/obj/item/card/id/security/head + name = "identification card" + desc = "A card which represents honor and protection." + extra_details = list("goldstripe") diff --git a/mods/content/standard_jobs/jobs/synthetics.dm b/mods/content/standard_jobs/jobs/synthetics.dm new file mode 100644 index 000000000000..23f768d4ac62 --- /dev/null +++ b/mods/content/standard_jobs/jobs/synthetics.dm @@ -0,0 +1,81 @@ +/datum/job/standard/computer + title = "Computer" + event_categories = list(ASSIGNMENT_COMPUTER) + total_positions = 0 // Not used for AI, see is_position_available below and modules/mob/living/silicon/ai/latejoin.dm + spawn_positions = 1 + selection_color = "#3f823f" + supervisors = "your laws" + req_admin_notify = 1 + minimal_player_age = 14 + account_allowed = 0 + economic_power = 0 + outfit_type = /decl/outfit/job/silicon/ai + loadout_allowed = FALSE + hud_icon_state = "hudblank" + hud_icon = null + skill_points = 0 + no_skill_buffs = TRUE + guestbanned = 1 + not_random_selectable = 1 + skip_loadout_preview = TRUE + department_types = list(/decl/department/miscellaneous) + +/datum/job/standard/computer/equip_job(var/mob/living/human/H) + return !!H + +/datum/job/standard/computer/is_position_available() + return (empty_playable_ai_cores.len != 0) + +/datum/job/standard/computer/handle_variant_join(var/mob/living/human/H, var/alt_title) + return H + +/datum/job/standard/computer/do_spawn_special(var/mob/living/character, var/mob/new_player/new_player_mob, var/latejoin) + character = character.AIize(move = FALSE) + + // is_available for AI checks that there is an empty core available in this list + var/obj/structure/aicore/deactivated/C = empty_playable_ai_cores[1] + empty_playable_ai_cores -= C + + character.forceMove(C.loc) + var/mob/living/silicon/ai/A = character + A.on_mob_init() + + if(latejoin) + new_player_mob.AnnounceCyborg(character, title, "has been downloaded to the empty core in \the [get_area_name(src)]") + SSticker.mode.handle_latejoin(character) + + qdel(C) + return TRUE + +/datum/job/standard/robot + title = "Robot" + event_categories = list(ASSIGNMENT_ROBOT) + total_positions = 2 + spawn_positions = 2 + supervisors = "your laws and the AI" + selection_color = "#254c25" + minimal_player_age = 7 + account_allowed = 0 + economic_power = 0 + loadout_allowed = FALSE + outfit_type = /decl/outfit/job/silicon/cyborg + hud_icon_state = "hudblank" + hud_icon = null + skill_points = 0 + no_skill_buffs = TRUE + guestbanned = 1 + not_random_selectable = 1 + skip_loadout_preview = TRUE + department_types = list(/decl/department/miscellaneous) + +/datum/job/standard/robot/handle_variant_join(var/mob/living/human/H, var/alt_title) + if(H) + return H.Robotize(SSrobots.get_mob_type_by_title(alt_title || title)) + +/datum/job/standard/robot/equip_job(var/mob/living/human/H) + return !!H + +/datum/job/standard/robot/New() + ..() + alt_titles = SSrobots.robot_alt_titles.Copy() + alt_titles -= title // So the unit test doesn't flip out if a mob or brain type is declared for our main title. diff --git a/mods/content/standard_jobs/outfits/cargo.dm b/mods/content/standard_jobs/outfits/cargo.dm new file mode 100644 index 000000000000..92e2760ed57c --- /dev/null +++ b/mods/content/standard_jobs/outfits/cargo.dm @@ -0,0 +1,35 @@ +/decl/outfit/job/cargo + l_ear = /obj/item/radio/headset/headset_cargo + abstract_type = /decl/outfit/job/cargo + +/decl/outfit/job/cargo/qm + name = "Job - Cargo" + uniform = /obj/item/clothing/jumpsuit/cargo + shoes = /obj/item/clothing/shoes/color/brown + glasses = /obj/item/clothing/glasses/sunglasses + hands = list(/obj/item/clipboard) + id_type = /obj/item/card/id/cargo/head + pda_type = /obj/item/modular_computer/pda/cargo + +/obj/item/card/id/cargo/head + name = "identification card" + desc = "A card which represents service and planning." + extra_details = list("goldstripe") + +/decl/outfit/job/cargo/cargo_tech + name = "Job - Cargo technician" + uniform = /obj/item/clothing/jumpsuit/cargotech + id_type = /obj/item/card/id/cargo + pda_type = /obj/item/modular_computer/pda/cargo + +/decl/outfit/job/cargo/mining + name = "Job - Shaft miner" + uniform = /obj/item/clothing/jumpsuit/miner + id_type = /obj/item/card/id/cargo + pda_type = /obj/item/modular_computer/pda/science + backpack_contents = list(/obj/item/crowbar = 1, /obj/item/ore_satchel = 1) + outfit_flags = OUTFIT_HAS_BACKPACK | OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR + +/decl/outfit/job/cargo/mining/Initialize() + . = ..() + BACKPACK_OVERRIDE_ENGINEERING diff --git a/mods/content/standard_jobs/outfits/civilian.dm b/mods/content/standard_jobs/outfits/civilian.dm new file mode 100644 index 000000000000..7622d65ae0db --- /dev/null +++ b/mods/content/standard_jobs/outfits/civilian.dm @@ -0,0 +1,66 @@ +/decl/outfit/job/service + l_ear = /obj/item/radio/headset/headset_service + abstract_type = /decl/outfit/job/service + +/decl/outfit/job/service/bartender + name = "Job - Bartender" + uniform = /obj/item/clothing/pants/formal/black/outfit + id_type = /obj/item/card/id/civilian + pda_type = /obj/item/modular_computer/pda + +/decl/outfit/job/service/chef + name = "Job - Chef" + uniform = /obj/item/clothing/pants/slacks/outfit_chef + suit = /obj/item/clothing/suit/chef + head = /obj/item/clothing/head/chefhat + id_type = /obj/item/card/id/civilian + pda_type = /obj/item/modular_computer/pda + +/decl/outfit/job/service/gardener + name = "Job - Gardener" + uniform = /obj/item/clothing/jumpsuit/hydroponics + suit = /obj/item/clothing/suit/apron + gloves = /obj/item/clothing/gloves/thick/botany + r_pocket = /obj/item/scanner/plant + id_type = /obj/item/card/id/civilian + pda_type = /obj/item/modular_computer/pda + +/decl/outfit/job/service/gardener/Initialize() + . = ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/hydroponics + backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/hyd + backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/hyd + +/decl/outfit/job/service/janitor + name = "Job - Janitor" + uniform = /obj/item/clothing/jumpsuit/janitor + id_type = /obj/item/card/id/civilian + pda_type = /obj/item/modular_computer/pda + +/decl/outfit/job/librarian + name = "Job - Librarian" + uniform = /obj/item/clothing/pants/slacks/red/outfit + id_type = /obj/item/card/id/civilian + pda_type = /obj/item/modular_computer/pda + +/obj/item/radio/headset/heads/ia + name = "internal affair's headset" + desc = "The headset of your worst enemy." + +/decl/outfit/job/internal_affairs_agent + name = "Job - Internal affairs agent" + l_ear = /obj/item/radio/headset/heads/ia + uniform = /obj/item/clothing/pants/slacks/black/outfit/internal_affairs + suit = /obj/item/clothing/suit/jacket/black + shoes = /obj/item/clothing/shoes/color/brown + glasses = /obj/item/clothing/glasses/sunglasses/big + hands = list(/obj/item/briefcase) + id_type = /obj/item/card/id/civilian/internal_affairs_agent + pda_type = /obj/item/modular_computer/pda/heads/paperpusher + +/decl/outfit/job/chaplain + name = "Job - Chaplain" + uniform = /obj/item/clothing/jumpsuit/chaplain + hands = list(/obj/item/bible) + id_type = /obj/item/card/id/civilian + pda_type = /obj/item/modular_computer/pda/medical diff --git a/mods/content/standard_jobs/outfits/command.dm b/mods/content/standard_jobs/outfits/command.dm new file mode 100644 index 000000000000..e2f9c8d8de67 --- /dev/null +++ b/mods/content/standard_jobs/outfits/command.dm @@ -0,0 +1,38 @@ +/decl/outfit/job/captain + name = "Job - Captain" + head = /obj/item/clothing/head/caphat + glasses = /obj/item/clothing/glasses/sunglasses + uniform = /obj/item/clothing/jumpsuit/captain + l_ear = /obj/item/radio/headset/heads/captain + shoes = /obj/item/clothing/shoes/color/brown + id_type = /obj/item/card/id/gold + pda_type = /obj/item/modular_computer/pda/heads/captain + backpack_contents = list(/obj/item/box/ids = 1) + +/decl/outfit/job/captain/Initialize() + . = ..() + backpack_overrides[/decl/backpack_outfit/backpack] = /obj/item/backpack/captain + backpack_overrides[/decl/backpack_outfit/satchel] = /obj/item/backpack/satchel/cap + backpack_overrides[/decl/backpack_outfit/messenger_bag] = /obj/item/backpack/messenger/com + +/decl/outfit/job/captain/post_equip(mob/living/wearer) + ..() + if(wearer.get_age() > 49) + // Since we can have something other than the default uniform at this + // point, check if we can actually attach the medal + var/obj/item/clothing/uniform = wearer.get_equipped_item(slot_w_uniform_str) + if(uniform) + var/obj/item/clothing/medal/gold/medal = new + if(uniform.can_attach_accessory(medal)) + uniform.attach_accessory(null, medal) + else + qdel(medal) + +/decl/outfit/job/hop + name = "Job - Head of Personnel" + uniform = /obj/item/clothing/jumpsuit/head_of_personnel + l_ear = /obj/item/radio/headset/heads/hop + shoes = /obj/item/clothing/shoes/color/brown + id_type = /obj/item/card/id/silver + pda_type = /obj/item/modular_computer/pda/heads/hop + backpack_contents = list(/obj/item/box/ids = 1) diff --git a/mods/content/standard_jobs/outfits/engineering.dm b/mods/content/standard_jobs/outfits/engineering.dm new file mode 100644 index 000000000000..83565966b0a2 --- /dev/null +++ b/mods/content/standard_jobs/outfits/engineering.dm @@ -0,0 +1,34 @@ +/decl/outfit/job/engineering + abstract_type = /decl/outfit/job/engineering + belt = /obj/item/belt/utility/full + l_ear = /obj/item/radio/headset/headset_eng + shoes = /obj/item/clothing/shoes/workboots + pda_slot = slot_l_store_str + outfit_flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL | OUTFIT_HAS_VITALS_SENSOR + +/decl/outfit/job/engineering/Initialize() + . = ..() + BACKPACK_OVERRIDE_ENGINEERING + +/decl/outfit/job/engineering/chief_engineer + name = "Job - Chief Engineer" + head = /obj/item/clothing/head/hardhat/white + uniform = /obj/item/clothing/jumpsuit/chief_engineer + l_ear = /obj/item/radio/headset/heads/ce + gloves = /obj/item/clothing/gloves/thick + id_type = /obj/item/card/id/engineering/head + pda_type = /obj/item/modular_computer/pda/heads/ce + +/decl/outfit/job/engineering/engineer + name = "Job - Engineer" + head = /obj/item/clothing/head/hardhat + uniform = /obj/item/clothing/jumpsuit/engineer + r_pocket = /obj/item/t_scanner + id_type = /obj/item/card/id/engineering + pda_type = /obj/item/modular_computer/pda/engineering + +/decl/outfit/job/engineering/atmos + name = "Job - Atmospheric technician" + uniform = /obj/item/clothing/jumpsuit/atmospheric_technician + belt = /obj/item/belt/utility/atmostech + pda_type = /obj/item/modular_computer/pda/engineering diff --git a/mods/content/standard_jobs/outfits/medical.dm b/mods/content/standard_jobs/outfits/medical.dm new file mode 100644 index 000000000000..9e150a2c47eb --- /dev/null +++ b/mods/content/standard_jobs/outfits/medical.dm @@ -0,0 +1,71 @@ +/decl/outfit/job/medical + abstract_type = /decl/outfit/job/medical + l_ear = /obj/item/radio/headset/headset_med + shoes = /obj/item/clothing/shoes/color/white + pda_type = /obj/item/modular_computer/pda/medical + pda_slot = slot_l_store_str + +/decl/outfit/job/medical/Initialize() + . = ..() + BACKPACK_OVERRIDE_MEDICAL + +/decl/outfit/job/medical/cmo + name = "Job - Chief Medical Officer" + l_ear = /obj/item/radio/headset/heads/cmo + uniform = /obj/item/clothing/jumpsuit/chief_medical_officer + suit = /obj/item/clothing/suit/toggle/labcoat/cmo + shoes = /obj/item/clothing/shoes/color/brown + hands = list(/obj/item/firstaid/adv) + r_pocket = /obj/item/flashlight/pen + id_type = /obj/item/card/id/medical/head + pda_type = /obj/item/modular_computer/pda/heads + +/decl/outfit/job/medical/doctor + name = "Job - Medical Doctor" + uniform = /obj/item/clothing/jumpsuit/medical + suit = /obj/item/clothing/suit/toggle/labcoat + hands = list(/obj/item/firstaid/adv) + r_pocket = /obj/item/flashlight/pen + id_type = /obj/item/card/id/medical + +/decl/outfit/job/medical/doctor/emergency_physician + name = "Job - Emergency physician" + suit = /obj/item/clothing/suit/jacket/first_responder + +/decl/outfit/job/medical/doctor/surgeon + name = "Job - Surgeon" + uniform = /obj/item/clothing/pants/scrubs/blue/outfit + head = /obj/item/clothing/head/surgery/blue + +/decl/outfit/job/medical/doctor/virologist + name = "Job - Virologist" + uniform = /obj/item/clothing/jumpsuit/virologist + suit = /obj/item/clothing/suit/toggle/labcoat/virologist + mask = /obj/item/clothing/mask/surgical + +/decl/outfit/job/medical/doctor/virologist/Initialize() + . = ..() + BACKPACK_OVERRIDE_VIROLOGY + +/decl/outfit/job/medical/doctor/nurse + name = "Job - Nurse" + suit = null + uniform = /obj/item/clothing/pants/scrubs/purple/outfit + head = null +/decl/outfit/job/medical/chemist + name = "Job - Chemist" + uniform = /obj/item/clothing/jumpsuit/chemist + suit = /obj/item/clothing/suit/toggle/labcoat/chemist + id_type = /obj/item/card/id/medical + pda_type = /obj/item/modular_computer/pda/medical + +/decl/outfit/job/medical/chemist/Initialize() + . = ..() + BACKPACK_OVERRIDE_VIROLOGY + +/decl/outfit/job/medical/psychiatrist + name = "Job - Psychiatrist" + uniform = /obj/item/clothing/jumpsuit/psych + suit = /obj/item/clothing/suit/toggle/labcoat + shoes = /obj/item/clothing/shoes/dress + id_type = /obj/item/card/id/medical diff --git a/mods/content/standard_jobs/outfits/pda.dm b/mods/content/standard_jobs/outfits/pda.dm new file mode 100644 index 000000000000..7631251ebf3f --- /dev/null +++ b/mods/content/standard_jobs/outfits/pda.dm @@ -0,0 +1,2 @@ +/obj/item/modular_computer/pda/heads/paperpusher + stored_pen = /obj/item/pen/fancy diff --git a/mods/content/standard_jobs/outfits/science.dm b/mods/content/standard_jobs/outfits/science.dm new file mode 100644 index 000000000000..64add4a61207 --- /dev/null +++ b/mods/content/standard_jobs/outfits/science.dm @@ -0,0 +1,34 @@ +/decl/outfit/job/science + abstract_type = /decl/outfit/job/science + l_ear = /obj/item/radio/headset/headset_sci + suit = /obj/item/clothing/suit/toggle/labcoat + shoes = /obj/item/clothing/shoes/color/white + pda_type = /obj/item/modular_computer/pda/science + +/decl/outfit/job/science/rd + name = "Job - Chief Science Officer" + l_ear = /obj/item/radio/headset/heads/rd + uniform = /obj/item/clothing/jumpsuit/research_director + shoes = /obj/item/clothing/shoes/color/brown + hands = list(/obj/item/clipboard) + id_type = /obj/item/card/id/science/head + pda_type = /obj/item/modular_computer/pda/heads + +/decl/outfit/job/science/scientist + name = "Job - Scientist" + uniform = /obj/item/clothing/jumpsuit/white + id_type = /obj/item/card/id/science + suit = /obj/item/clothing/suit/toggle/labcoat/science + +/decl/outfit/job/science/roboticist + name = "Job - Roboticist" + uniform = /obj/item/clothing/jumpsuit/white + shoes = /obj/item/clothing/shoes/color/black + belt = /obj/item/belt/utility/full + id_type = /obj/item/card/id/science + pda_slot = slot_r_store_str + pda_type = /obj/item/modular_computer/pda/science + +/decl/outfit/job/science/roboticist/Initialize() + . = ..() + backpack_overrides.Cut() diff --git a/mods/content/standard_jobs/outfits/security.dm b/mods/content/standard_jobs/outfits/security.dm new file mode 100644 index 000000000000..fb3a73b97eea --- /dev/null +++ b/mods/content/standard_jobs/outfits/security.dm @@ -0,0 +1,55 @@ +/decl/outfit/job/security + abstract_type = /decl/outfit/job/security + glasses = /obj/item/clothing/glasses/sunglasses/sechud + l_ear = /obj/item/radio/headset/headset_sec + gloves = /obj/item/clothing/gloves/thick + shoes = /obj/item/clothing/shoes/jackboots + backpack_contents = list(/obj/item/handcuffs = 1) + +/decl/outfit/job/security/Initialize() + . = ..() + BACKPACK_OVERRIDE_SECURITY + +/decl/outfit/job/security/hos + name = "Job - Head of security" + l_ear = /obj/item/radio/headset/heads/hos + uniform = /obj/item/clothing/jumpsuit/head_of_security + id_type = /obj/item/card/id/security/head + pda_type = /obj/item/modular_computer/pda/heads + backpack_contents = list(/obj/item/handcuffs = 1) + +/decl/outfit/job/security/warden + name = "Job - Warden" + uniform = /obj/item/clothing/jumpsuit/warden + l_pocket = /obj/item/flash + id_type = /obj/item/card/id/security + pda_type = /obj/item/modular_computer/pda + +/decl/outfit/job/security/detective + name = "Job - Detective" + head = /obj/item/clothing/head/det + uniform = /obj/item/clothing/pants/slacks/outfit/detective + suit = /obj/item/clothing/suit/det_trench + l_pocket = /obj/item/flame/fuelled/lighter/zippo + shoes = /obj/item/clothing/shoes/dress + hands = list(/obj/item/briefcase/crimekit) + id_type = /obj/item/card/id/security + pda_type = /obj/item/modular_computer/pda + backpack_contents = list(/obj/item/box/evidence = 1) + +/decl/outfit/job/security/detective/Initialize() + . = ..() + backpack_overrides.Cut() + +/decl/outfit/job/security/detective/forensic + name = "Job - Forensic technician" + head = null + suit = /obj/item/clothing/suit/forensics/blue + +/decl/outfit/job/security/officer + name = "Job - Security Officer" + uniform = /obj/item/clothing/jumpsuit/security + l_pocket = /obj/item/flash + r_pocket = /obj/item/handcuffs + id_type = /obj/item/card/id/security + pda_type = /obj/item/modular_computer/pda diff --git a/mods/content/supermatter/_supermatter.dm b/mods/content/supermatter/_supermatter.dm new file mode 100644 index 000000000000..78daa387234a --- /dev/null +++ b/mods/content/supermatter/_supermatter.dm @@ -0,0 +1,23 @@ +// 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" + +/decl/modpack/supermatter + name = "Supermatter Content" + desc = "This modpack includes the supermatter engine and related content." + nanoui_directory = "mods/content/supermatter/nano_templates/" + +/decl/modpack/supermatter/pre_initialize() + . = ..() + global.debug_verbs |= /datum/admins/proc/setup_supermatter \ No newline at end of file diff --git a/mods/content/supermatter/_supermatter.dme b/mods/content/supermatter/_supermatter.dme new file mode 100644 index 000000000000..abc090e244de --- /dev/null +++ b/mods/content/supermatter/_supermatter.dme @@ -0,0 +1,32 @@ +#ifndef CONTENT_PACK_SUPERMATTER +#define CONTENT_PACK_SUPERMATTER +// BEGIN_INCLUDE +#include "_supermatter.dm" +#include "admin_setup_supermatter.dm" +#include "datums\sm_codex.dm" +#include "datums\sm_follow.dm" +#include "datums\sm_grief_fix.dm" +#include "datums\sm_looping_sound.dm" +#include "datums\sm_material.dm" +#include "datums\sm_subsystem.dm" +#include "datums\sm_supply_drop.dm" +#include "datums\sm_supply_pack.dm" +#include "datums\supermatter_monitor.dm" +#include "endgame_cascade\cascade_blob.dm" +#include "endgame_cascade\portal.dm" +#include "endgame_cascade\universe.dm" +#include "items\sm_book.dm" +#include "items\sm_grenade.dm" +#include "machinery\sm_supply_beacon.dm" +#include "machinery\supermatter_core_console.dm" +#include "overrides\sm_fuel_compressor.dm" +#include "overrides\sm_meteor.dm" +#include "overrides\sm_singularity.dm" +#include "overrides\sm_strings.dm" +#include "overrides\sm_trader.dm" +#include "overrides\sm_unit_tests.dm" +#include "overrides\sm_xenoarchaeology.dm" +#include "structures\sm_closets.dm" +#include "structures\supermatter_crystal.dm" +// END_INCLUDE +#endif diff --git a/mods/content/supermatter/admin_setup_supermatter.dm b/mods/content/supermatter/admin_setup_supermatter.dm new file mode 100644 index 000000000000..e9de8a41e924 --- /dev/null +++ b/mods/content/supermatter/admin_setup_supermatter.dm @@ -0,0 +1,116 @@ +#define ENERGY_NITROGEN 115 // Roughly 8 emitter shots. +#define ENERGY_CARBONDIOXIDE 150 // Roughly 10 emitter shots. +#define ENERGY_HYDROGEN 300 // Roughly 20 emitter shots. + +/datum/admins/proc/setup_supermatter() + set category = "Debug" + set name = "Setup Supermatter" + set desc = "Allows you to start the Supermatter engine." + + if (!istype(src,/datum/admins)) + src = usr.client.holder + if (!istype(src,/datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + + var/response = input(usr, "Are you sure? This will start up the engine with selected gas as coolant.", "Engine setup") as null|anything in list("N2", "CO2", "H2", "Abort") + if(!response || response == "Abort") + return + + var/errors = 0 + var/warnings = 0 + var/success = 0 + + log_and_message_admins("## SUPERMATTER SETUP - Setup initiated by [usr] using coolant type [response].") + + // CONFIGURATION PHASE + // Coolant canisters, set types according to response. + for(var/obj/effect/engine_setup/coolant_canister/C in global.engine_setup_markers) + switch(response) + if("N2") + C.canister_type = /obj/machinery/portable_atmospherics/canister/nitrogen/engine_setup/ + continue + if("CO2") + C.canister_type = /obj/machinery/portable_atmospherics/canister/carbon_dioxide/engine_setup/ + continue + if("H2") + C.canister_type = /obj/machinery/portable_atmospherics/canister/hydrogen/engine_setup/ + continue + + for(var/obj/effect/engine_setup/core/C in global.engine_setup_markers) + switch(response) + if("N2") + C.energy_setting = ENERGY_NITROGEN + continue + if("CO2") + C.energy_setting = ENERGY_CARBONDIOXIDE + continue + if("H2") + C.energy_setting = ENERGY_HYDROGEN + continue + + for(var/obj/effect/engine_setup/filter/F in global.engine_setup_markers) + F.coolant = response + + var/list/delayed_objects = list() + // SETUP PHASE + for(var/obj/effect/engine_setup/S in global.engine_setup_markers) + var/result = S.activate(0) + switch(result) + if(ENGINE_SETUP_OK) + success++ + continue + if(ENGINE_SETUP_WARNING) + warnings++ + continue + if(ENGINE_SETUP_ERROR) + errors++ + log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.") + break + if(ENGINE_SETUP_DELAYED) + delayed_objects.Add(S) + continue + + if(!errors) + for(var/obj/effect/engine_setup/S in delayed_objects) + var/result = S.activate(1) + switch(result) + if(ENGINE_SETUP_OK) + success++ + continue + if(ENGINE_SETUP_WARNING) + warnings++ + continue + if(ENGINE_SETUP_ERROR) + errors++ + log_and_message_admins("## SUPERMATTER SETUP - Error encountered! Aborting.") + break + + log_and_message_admins("## SUPERMATTER SETUP - Setup completed with [errors] errors, [warnings] warnings and [success] successful steps.") + + return + + + +// Energises the supermatter. Errors when unable to locate supermatter. +/obj/effect/engine_setup/core + name = "Supermatter Core Marker" + var/energy_setting = 0 + +/obj/effect/engine_setup/core/activate(var/last = 0) + if(!last) + return ENGINE_SETUP_DELAYED + ..() + var/obj/structure/supermatter/SM = locate() in get_turf(src) + if(!SM) + log_and_message_admins("## ERROR: Unable to locate supermatter core at [x] [y] [z]!") + return ENGINE_SETUP_ERROR + if(!energy_setting) + log_and_message_admins("## ERROR: Energy setting unset at [x] [y] [z]!") + return ENGINE_SETUP_ERROR + SM.power = energy_setting + return ENGINE_SETUP_OK + +#undef ENERGY_NITROGEN +#undef ENERGY_CARBONDIOXIDE +#undef ENERGY_HYDROGEN diff --git a/mods/content/supermatter/datums/sm_codex.dm b/mods/content/supermatter/datums/sm_codex.dm new file mode 100644 index 000000000000..8dbf88ea7522 --- /dev/null +++ b/mods/content/supermatter/datums/sm_codex.dm @@ -0,0 +1,21 @@ + +/datum/codex_entry/guide/supermatter + name = "Guide to Supermatter Engines" + available_to_map_tech_level = MAP_TECH_LEVEL_SPACE + +/datum/codex_entry/supermatter + associated_paths = list(/obj/structure/supermatter) + mechanics_text = "When energized by a laser (or something hitting it), it emits radiation and heat. If the heat reaches above 7000 kelvin, it will send an alert and start taking damage. \ + After integrity falls to zero percent, it will delaminate, causing a massive explosion, station-wide radiation spikes, and hallucinations. \ + Supermatter reacts badly to oxygen in the atmosphere. It'll also heat up really quick if it is in vacuum.
    \ +
    \ + Supermatter cores are extremely dangerous to be close to, and requires protection to handle properly. The protection you will need is:
    \ + Optical meson scanners on your eyes, to prevent hallucinations when looking at the supermatter.
    \ + Radiation helmet and suit, as the supermatter is radioactive.
    \ +
    \ + Touching the supermatter will result in *instant death*, with no corpse left behind! You can drag the supermatter, but anything else will kill you. \ + It is advised to obtain a genetic backup before trying to drag it." + antag_text = "Exposing the supermatter to oxygen or vacuum will cause it to start rapidly heating up. Sabotaging the supermatter and making it explode will \ + cause a period of lag as the explosion is processed by the server, as well as irradiating the entire station and causing hallucinations to happen. \ + Wearing radiation equipment will protect you from most of the delamination effects sans explosion." + available_to_map_tech_level = MAP_TECH_LEVEL_SPACE \ No newline at end of file diff --git a/mods/content/supermatter/datums/sm_follow.dm b/mods/content/supermatter/datums/sm_follow.dm new file mode 100644 index 000000000000..4f03605d61d7 --- /dev/null +++ b/mods/content/supermatter/datums/sm_follow.dm @@ -0,0 +1,3 @@ +/datum/follow_holder/supermatter + sort_order = 10 + followed_type = /obj/structure/supermatter \ No newline at end of file diff --git a/mods/content/supermatter/datums/sm_grief_fix.dm b/mods/content/supermatter/datums/sm_grief_fix.dm new file mode 100644 index 000000000000..12f2db8dbf2f --- /dev/null +++ b/mods/content/supermatter/datums/sm_grief_fix.dm @@ -0,0 +1,8 @@ +/decl/atmos_grief_fix_step/supermatter + name = "Supermatter depowered" + sort_order = 0 + +/decl/atmos_grief_fix_step/supermatter/act() + // Depower the supermatter, as it would quickly blow up once we remove all gases from the pipes. + for(var/obj/structure/supermatter/S in SSsupermatter.processing) + S.power = 0 \ No newline at end of file diff --git a/mods/content/supermatter/datums/sm_looping_sound.dm b/mods/content/supermatter/datums/sm_looping_sound.dm new file mode 100644 index 000000000000..1cdcb1933531 --- /dev/null +++ b/mods/content/supermatter/datums/sm_looping_sound.dm @@ -0,0 +1,4 @@ +/datum/composite_sound/supermatter + mid_sounds = list('sound/machines/sm/loops/calm.ogg'=1) + mid_length = 60 + play_volume = 40 \ No newline at end of file diff --git a/mods/content/supermatter/datums/sm_material.dm b/mods/content/supermatter/datums/sm_material.dm new file mode 100644 index 000000000000..9e3fb430a6b9 --- /dev/null +++ b/mods/content/supermatter/datums/sm_material.dm @@ -0,0 +1,14 @@ +/decl/material/solid/exotic_matter/supermatter + name = "supermatter" + uid = "solid_supermatter" + lore_text = "Hypercrystalline supermatter is a subset of non-baryonic 'exotic' matter with unusual properties that make it desirable for energy generation, and also very dangerous." + accelerant_value = FUEL_VALUE_NONE + vapor_products = null + melting_point = null + gas_flags = null + ignition_point = null + gas_symbol_html = "Sp*" + gas_symbol = "Sp*" + default_solid_form = /obj/item/stack/material/gemstone + +DEFINE_STACK_SUBTYPES(supermatter, "supermatter", solid/exotic_matter/supermatter, crystal, null) diff --git a/mods/content/supermatter/datums/sm_subsystem.dm b/mods/content/supermatter/datums/sm_subsystem.dm new file mode 100644 index 000000000000..01b2c19da591 --- /dev/null +++ b/mods/content/supermatter/datums/sm_subsystem.dm @@ -0,0 +1,7 @@ +// A replacement for having the supermatter tick on SSmachinery, since it's no longer a machine. +PROCESSING_SUBSYSTEM_DEF(supermatter) + name = "Supermatter" + priority = SS_PRIORITY_MACHINERY + flags = SS_KEEP_TIMING|SS_NO_INIT + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + wait = 2 SECONDS \ No newline at end of file diff --git a/mods/content/supermatter/datums/sm_supply_drop.dm b/mods/content/supermatter/datums/sm_supply_drop.dm new file mode 100644 index 000000000000..fdff0e1d2fe2 --- /dev/null +++ b/mods/content/supermatter/datums/sm_supply_drop.dm @@ -0,0 +1,5 @@ +/datum/supply_drop_loot/supermatter + name = "Supermatter" +/datum/supply_drop_loot/supermatter/New() + ..() + contents = list(/obj/structure/supermatter) diff --git a/mods/content/supermatter/datums/sm_supply_pack.dm b/mods/content/supermatter/datums/sm_supply_pack.dm new file mode 100644 index 000000000000..aa34afe44995 --- /dev/null +++ b/mods/content/supermatter/datums/sm_supply_pack.dm @@ -0,0 +1,6 @@ +/decl/hierarchy/supply_pack/engineering/smbig + name = "Power - Supermatter core" + contains = list(/obj/structure/supermatter) + containertype = /obj/structure/closet/crate/secure/large/supermatter + containername = "\improper Supermatter crate (CAUTION)" + access = access_ce \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm b/mods/content/supermatter/datums/supermatter_monitor.dm similarity index 84% rename from code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm rename to mods/content/supermatter/datums/supermatter_monitor.dm index 4df162512fbf..73805c939678 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/supermatter_monitor.dm +++ b/mods/content/supermatter/datums/supermatter_monitor.dm @@ -5,14 +5,16 @@ /datum/computer_file/program/supermatter_monitor filename = "supmon" filedesc = "Supermatter Monitoring" - nanomodule_path = /datum/nano_module/program/supermatter_monitor/ + nanomodule_path = /datum/nano_module/program/supermatter_monitor program_icon_state = "smmon_0" program_key_state = "tech_key" program_menu_icon = "notice" extended_desc = "This program connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines." ui_header = "smmon_0.gif" - required_access = access_engine + read_access = list(access_engine) network_destination = "supermatter monitoring system" + requires_network = 1 + requires_network_feature = NET_FEATURE_SYSTEMCONTROL size = 5 category = PROG_ENG var/last_status = 0 @@ -30,7 +32,7 @@ /datum/nano_module/program/supermatter_monitor name = "Supermatter monitor" var/list/supermatters - var/obj/machinery/power/supermatter/active = null // Currently selected supermatter crystal. + var/obj/structure/supermatter/active = null // Currently selected supermatter crystal. var/screen = SM_MONITOR_SCREEN_MAIN // Which screen the monitor is currently on /datum/nano_module/program/supermatter_monitor/Destroy() @@ -42,7 +44,7 @@ ..() refresh() -/datum/nano_module/program/supermatter_monitor/proc/can_read(obj/machinery/power/supermatter/S) +/datum/nano_module/program/supermatter_monitor/proc/can_read(obj/structure/supermatter/S) if(!istype(S.loc, /turf/)) return FALSE if(S.exploded || S.grav_pulling) @@ -50,12 +52,12 @@ var/datum/computer_network/network = get_network() if(!network) return FALSE - return ARE_Z_CONNECTED(network.get_router_z(), get_z(S)) + return LEVELS_ARE_Z_CONNECTED(network.get_router_z(), get_z(S)) // Refreshes list of active supermatter crystals /datum/nano_module/program/supermatter_monitor/proc/refresh() supermatters = list() - for(var/obj/machinery/power/supermatter/S in SSmachines.machinery) + for(var/obj/structure/supermatter/S in SSsupermatter.processing) // Delaminating, not within coverage, not on a tile. if(!can_read(S)) continue @@ -68,7 +70,7 @@ /datum/nano_module/program/supermatter_monitor/proc/get_status() . = SUPERMATTER_INACTIVE var/needs_refresh - for(var/obj/machinery/power/supermatter/S in supermatters) + for(var/obj/structure/supermatter/S in supermatters) if(!can_read(S)) needs_refresh = TRUE continue @@ -107,7 +109,7 @@ else return value -/datum/nano_module/program/supermatter_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state) +/datum/nano_module/program/supermatter_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = global.default_topic_state) var/list/data = host.initial_data() var/engine_skill = user.get_skill_value(SKILL_ENGINES) @@ -159,7 +161,7 @@ else var/list/SMS = list() var/needs_refresh //need to refresh because some of crystals are not readable. For finding new crystals user can just refresh manually like a scrub - for(var/obj/machinery/power/supermatter/S in supermatters) + for(var/obj/structure/supermatter/S in supermatters) var/area/A = get_area(S) if(!A) continue @@ -168,7 +170,7 @@ continue SMS.Add(list(list( - "area_name" = A.name, + "area_name" = A.proper_name, "integrity" = process_data_output(engine_skill, S.get_integrity()), "uid" = S.uid ))) @@ -209,7 +211,24 @@ return 1 if( href_list["set"] ) var/newuid = text2num(href_list["set"]) - for(var/obj/machinery/power/supermatter/S in supermatters) + for(var/obj/structure/supermatter/S in supermatters) if(S.uid == newuid) active = S return 1 + +// Add this to the software list for borgs +/obj/item/robot_module/engineering/grant_software() + software |= /datum/computer_file/program/supermatter_monitor + return ..() + +/obj/item/robot_module/flying/repair/grant_software() + software |= /datum/computer_file/program/supermatter_monitor + return ..() + +/obj/machinery/computer/modular/telescreen/preset/engineering/Initialize(mapload, d, populate_parts) + default_software |= /datum/computer_file/program/supermatter_monitor + return ..() + +/obj/machinery/computer/modular/preset/engineering/Initialize(mapload, d, populate_parts) + default_software |= /datum/computer_file/program/supermatter_monitor + return ..() \ No newline at end of file diff --git a/mods/content/supermatter/endgame_cascade/cascade_blob.dm b/mods/content/supermatter/endgame_cascade/cascade_blob.dm new file mode 100644 index 000000000000..5b716d4a4849 --- /dev/null +++ b/mods/content/supermatter/endgame_cascade/cascade_blob.dm @@ -0,0 +1,85 @@ +// QUALITY COPYPASTA +/turf/unsimulated/wall/cascade + name = "unravelling spacetime" + desc = "THE END IS right now actually." + + icon = 'icons/turf/space.dmi' + icon_state = "bluespace" + + //luminosity = 5 + //l_color="#0066ff" + plane = ABOVE_LIGHTING_PLANE + layer = SUBSPACE_WALL_LAYER + + var/list/avail_dirs = list(NORTH,SOUTH,EAST,WEST,UP,DOWN) + +/turf/unsimulated/wall/cascade/New() + . = ..() + START_PROCESSING(SSturf, src) + + // Nom. + for(var/atom/movable/A in src) + try_supermatter_consume(null, A, src) + +/turf/unsimulated/wall/cascade/Destroy() + STOP_PROCESSING(SSturf, src) + . = ..() + +/turf/unsimulated/wall/cascade/Process(wait, tick) + // Only check infrequently. + var/how_often = max(round(5 SECONDS/wait), 1) + if(tick % how_often) + return + + // No more available directions? Stop processing. + if(!avail_dirs.len) + return PROCESS_KILL + + // Choose a direction. + var/pdir = pick(avail_dirs) + avail_dirs -= pdir + var/turf/T = get_zstep(src,pdir) + + // EXPAND + if(T && !istype(T,type)) + // Do pretty fadeout animation for 1s. + new /obj/effect/overlay/bluespacify(T) + spawn(1 SECOND) + if(istype(T,type)) // In case another blob came first, don't create another blob + return + T.ChangeTurf(type) + +/turf/unsimulated/wall/cascade/attack_robot(mob/user) + . = attack_hand_with_interaction_checks(user) + if(!.) + user.examine_verb(src) + +// /vg/: Don't let ghosts fuck with this. +/turf/unsimulated/wall/cascade/attack_ghost(mob/user) + user.examine_verb(src) + +/turf/unsimulated/wall/cascade/attack_ai(mob/living/silicon/ai/user) + user.examine_verb(src) + +/turf/unsimulated/wall/cascade/attack_hand(mob/user) + if(try_supermatter_consume(null, user, src, TRUE)) + return TRUE + return ..() + +/turf/unsimulated/wall/cascade/attackby(obj/item/used_item, mob/user) + user.visible_message("\The [user] touches \a [used_item] to \the [src] as a silence fills the room...",\ + "You touch \the [used_item] to \the [src] when everything suddenly goes silent.\"\n\The [used_item] flashes into dust as you flinch away from \the [src].",\ + "Everything suddenly goes silent.") + + playsound(src, 'sound/effects/supermatter.ogg', 50, 1) + + user.drop_from_inventory(used_item) + Bumped(used_item) + return TRUE + +/turf/unsimulated/wall/cascade/Entered(var/atom/movable/AM) + Bumped(AM) + +/turf/unsimulated/wall/cascade/Bumped(var/atom/movable/AM) + if(!try_supermatter_consume(null, AM, src)) + return ..() diff --git a/mods/content/supermatter/endgame_cascade/portal.dm b/mods/content/supermatter/endgame_cascade/portal.dm new file mode 100644 index 000000000000..9b8ef1cd7a8d --- /dev/null +++ b/mods/content/supermatter/endgame_cascade/portal.dm @@ -0,0 +1,61 @@ +/*** EXIT PORTAL ***/ + +/obj/effect/wormhole_exit + name = "unstable wormhole" + desc = "NO TIME TO EXPLAIN, JUMP IN!" + icon = 'icons/obj/rift.dmi' + icon_state = "rift" + anchored = TRUE + pixel_x = -236 + pixel_y = -256 + plane = ABOVE_LIGHTING_PLANE + layer = ABOVE_LIGHTING_LAYER + is_spawnable_type = FALSE + var/const/transit_range = 6 + +/obj/effect/wormhole_exit/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + var/datum/extension/universally_visible/univis = get_or_create_extension(src, /datum/extension/universally_visible) + univis.refresh() + +/obj/effect/wormhole_exit/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/effect/wormhole_exit/Process() + for(var/atom/movable/AM in range(transit_range, src)) + transit_to_exit(AM) + +/obj/effect/wormhole_exit/proc/transit_to_exit(const/atom/A) + if(!A.simulated) + return FALSE + if (isliving(A)) + + var/mob/living/L = A + if(!length(global.endgame_safespawns)) + to_chat(L, SPAN_NOTICE("You fall through the wormhole, and to safety, leaving behind the doom Universe that bore you...")) + L.ghostize() + QDEL_NULL(L.buckled) + qdel(L) + return + + var/atom/movable/AM = L.buckled + do_teleport(L, pick(global.endgame_safespawns)) + if(istype(AM)) + AM.forceMove(L.loc) + + else if (isturf(A)) + var/turf/T = A + var/dist = get_dist(T, src) + if(dist <= transit_range && T.density) + T.set_density(0) + for(var/atom/movable/AM in T.contents) + if (AM == src) // This is the snowflake. + continue + if (dist <= transit_range) + transit_to_exit(AM) + else if (dist > transit_range) + if(AM.simulated) + AM.singularity_pull(src, transit_range) + return TRUE diff --git a/mods/content/supermatter/endgame_cascade/universe.dm b/mods/content/supermatter/endgame_cascade/universe.dm new file mode 100644 index 000000000000..157dce06268c --- /dev/null +++ b/mods/content/supermatter/endgame_cascade/universe.dm @@ -0,0 +1,109 @@ +/datum/universal_state/supermatter_cascade + name = "Supermatter Cascade" + desc = "Unknown harmonance affecting universal substructure, converting nearby matter to supermatter." + + decay_rate = 5 // 5% chance of a turf decaying on lighting update/airflow (there's no actual tick for turfs) + +/datum/universal_state/supermatter_cascade/OnShuttleCall(var/mob/user) + if(user) + to_chat(user, "All you hear on the frequency is static and panicked screaming. There will be no shuttle call today.") + return 0 + +/datum/universal_state/supermatter_cascade/OnTurfChange(var/turf/T) + var/turf/space/S = T + if(istype(S)) + S.set_color("#0066ff") + else + S.set_color(initial(S.color)) + +/datum/universal_state/supermatter_cascade/DecayTurf(var/turf/T) + T.handle_universal_decay() + +// Apply changes when entering state +/datum/universal_state/supermatter_cascade/OnEnter() + set background = 1 + to_world("You are blinded by a brilliant flash of energy.") + sound_to(world, sound('sound/effects/cascade.ogg')) + + for(var/mob/M in global.player_list) + M.flash_eyes() + + if(SSevac.evacuation_controller?.cancel_evacuation()) + priority_announcement.Announce("The evacuation has been aborted due to severe distortion of local space-time.") + + AreaSet() + MiscSet() + APCSet() + OverlayAndAmbientSet() + + PlayerSet() + SSskybox.change_skybox("cascade", new_use_stars = FALSE, new_use_overmap_details = FALSE) + + var/spawned_exit = FALSE + if(length(global.endgame_exits)) + spawned_exit = new /obj/effect/wormhole_exit(pick(global.endgame_exits)) + + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/universal_state/supermatter_cascade, announce_end_of_universe), spawned_exit), rand(30, 60) SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/universal_state/supermatter_cascade, finalize_end_of_universe)), 5 MINUTES) + +/datum/universal_state/supermatter_cascade/proc/announce_end_of_universe(var/exit_exists) + var/end_message = "Attn. [global.using_map.station_name]: Severe gravitational anomalies of unheard of scope have been detected in the local volume. Size and intensity of anomalies are increasing exponentially. Within the hour, a newborn black hole will have consumed everything in this sector." + if(exit_exists) + end_message += "\n\nCuriously, the distortion is predicted to form a traversable wormhole quite close to your current location in approximately five minutes. The terminus is unknown, but it must be better than behind a hungry singularity. Godspeed." + end_message += "\n\nAUTOMATED ALERT: Link to [global.using_map.boss_name] lost." + priority_announcement.Announce(end_message, "SUPERMATTER CASCADE DETECTED") + +/datum/universal_state/supermatter_cascade/proc/finalize_end_of_universe() + global.cinematic.station_explosion_cinematic(0,null) // TODO: Custom cinematic + universe_has_ended = TRUE + +/datum/universal_state/supermatter_cascade/proc/AreaSet() + for(var/area/A as anything in global.areas) + var/invalid_area = FALSE + for(var/check_area in global.using_map.get_universe_end_evac_areas()) + if(istype(A, check_area)) + invalid_area = TRUE + break + if(!invalid_area) + A.update_icon() + +// TODO: Should this be changed to use the actual ambient lights system...? +/datum/universal_state/supermatter_cascade/OverlayAndAmbientSet() + spawn(0) + // TODO: dear god anything but this + for(var/datum/lighting_corner/L) + if(isAdminLevel(L.z)) + L.update_lumcount(1,1,1) + else + L.update_lumcount(0.0, 0.4, 1) + + CHECK_TICK + + for(var/turf/space/T) + OnTurfChange(T) + CHECK_TICK + +/datum/universal_state/supermatter_cascade/proc/MiscSet() + for (var/obj/machinery/firealarm/alm in SSmachines.machinery) + if (!(alm.stat & BROKEN)) + alm.explosion_act(2) + +/datum/universal_state/supermatter_cascade/proc/APCSet() + for (var/obj/machinery/apc/APC in SSmachines.machinery) + if (!(APC.stat & BROKEN) && !APC.is_critical) + APC.chargemode = 0 + var/obj/item/cell/cell = APC.get_cell() + if(cell) + cell.charge = 0 + APC.emagged = 1 + APC.queue_icon_update() + +/datum/universal_state/supermatter_cascade/proc/PlayerSet() + for(var/datum/mind/M in global.player_list) + if(!isliving(M.current)) + continue + if(M.current.stat != DEAD) + SET_STATUS_MAX(M.current, STAT_WEAK, 10) + M.current.flash_eyes() + + clear_antag_roles(M) diff --git a/mods/content/supermatter/items/sm_book.dm b/mods/content/supermatter/items/sm_book.dm new file mode 100644 index 000000000000..8230625788a0 --- /dev/null +++ b/mods/content/supermatter/items/sm_book.dm @@ -0,0 +1,6 @@ +/obj/item/book/manual/supermatter_engine + name = "supermatter engine reference manual" + icon = 'icons/obj/items/books/book_supermatter.dmi' + author = "Central Engineering Division" + title = "Supermatter Engine Operating Manual" + guide_decl = /datum/codex_entry/guide/supermatter \ No newline at end of file diff --git a/mods/content/supermatter/items/sm_grenade.dm b/mods/content/supermatter/items/sm_grenade.dm new file mode 100644 index 000000000000..e6094ecfab36 --- /dev/null +++ b/mods/content/supermatter/items/sm_grenade.dm @@ -0,0 +1,43 @@ +/obj/item/grenade/supermatter + name = "supermatter grenade" + icon = 'icons/obj/items/grenades/banana.dmi' + origin_tech = @'{"wormholes":5,"magnets":4,"engineering":5}' + arm_sound = 'sound/effects/3.wav' + var/implode_at + +/obj/item/grenade/supermatter/Destroy() + if(implode_at) + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/grenade/supermatter/detonate() + ..() + START_PROCESSING(SSobj, src) + implode_at = world.time + 10 SECONDS + update_icon() + playsound(src, 'sound/weapons/wave.ogg', 100) + +/obj/item/grenade/supermatter/on_update_icon() + . = ..() + if(implode_at) + add_overlay(image('icons/obj/machines/power/fusion.dmi', "emfield_s1")) + +/obj/item/grenade/supermatter/Process() + if(!isturf(loc)) + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src) + forceMove(get_turf(src)) + playsound(src, 'sound/effects/supermatter.ogg', 100) + supermatter_pull(src, world.view, STAGE_THREE) + if(world.time > implode_at) + explosion(loc, 0, 1, 3, 4) + qdel(src) + +/obj/item/box/supermatters + name = "box of supermatter grenades" + desc = "A box containing 5 highly experimental supermatter grenades." + icon_state = "radbox" + +/obj/item/box/supermatters/WillContain() + return list(/obj/item/grenade/supermatter = 5) diff --git a/mods/content/supermatter/machinery/sm_supply_beacon.dm b/mods/content/supermatter/machinery/sm_supply_beacon.dm new file mode 100644 index 000000000000..e6a622480b60 --- /dev/null +++ b/mods/content/supermatter/machinery/sm_supply_beacon.dm @@ -0,0 +1,7 @@ +/obj/item/supply_beacon/supermatter + name = "inactive supermatter supply beacon" + deploy_path = /obj/structure/supply_beacon/supermatter + +/obj/structure/supply_beacon/supermatter + name = "supermatter supply beacon" + drop_type = "supermatter" diff --git a/mods/content/supermatter/machinery/supermatter_core_console.dm b/mods/content/supermatter/machinery/supermatter_core_console.dm new file mode 100644 index 000000000000..8b2bf0e175ca --- /dev/null +++ b/mods/content/supermatter/machinery/supermatter_core_console.dm @@ -0,0 +1,45 @@ +// Does this really need to be its own thing...? +// Can it not just be a stock parts preset or something? +/obj/machinery/computer/air_control/supermatter_core + frequency = 1438 + out_pressure_mode = 1 + +/datum/fabricator_recipe/imprinter/circuit/supermatter_control + path = /obj/item/stock_parts/circuitboard/air_management/supermatter_core + +/obj/item/stock_parts/circuitboard/air_management/supermatter_core + name = "circuitboard (core control)" + build_path = /obj/machinery/computer/air_control/supermatter_core + frequency = 1438 + var/input_tag + var/output_tag + + var/list/input_info = list() + var/list/output_info = list() + + var/input_flow_setting = 700 + var/pressure_setting = 100 + +/obj/item/stock_parts/circuitboard/air_management/supermatter_core/construct(var/obj/machinery/computer/air_control/supermatter_core/SC) + if(..(SC)) + SC.input_tag = input_tag + SC.output_tag = output_tag + + SC.input_info = input_info.Copy() + SC.output_info = output_info.Copy() + + SC.input_flow_setting = input_flow_setting + SC.pressure_setting = input_flow_setting + return 1 + +/obj/item/stock_parts/circuitboard/air_management/supermatter_core/deconstruct(var/obj/machinery/computer/air_control/supermatter_core/SC) + if(..(SC)) + input_tag = SC.input_tag + output_tag = SC.output_tag + + input_info = SC.input_info.Copy() + output_info = SC.output_info.Copy() + + input_flow_setting = SC.input_flow_setting + pressure_setting = SC.input_flow_setting + return 1 \ No newline at end of file diff --git a/nano/templates/supermatter_crystal.tmpl b/mods/content/supermatter/nano_templates/supermatter_crystal.tmpl similarity index 100% rename from nano/templates/supermatter_crystal.tmpl rename to mods/content/supermatter/nano_templates/supermatter_crystal.tmpl diff --git a/nano/templates/supermatter_monitor.tmpl b/mods/content/supermatter/nano_templates/supermatter_monitor.tmpl similarity index 100% rename from nano/templates/supermatter_monitor.tmpl rename to mods/content/supermatter/nano_templates/supermatter_monitor.tmpl diff --git a/mods/content/supermatter/overrides/sm_fuel_compressor.dm b/mods/content/supermatter/overrides/sm_fuel_compressor.dm new file mode 100644 index 000000000000..0207c648c6ef --- /dev/null +++ b/mods/content/supermatter/overrides/sm_fuel_compressor.dm @@ -0,0 +1,13 @@ +/obj/machinery/fuel_compressor/add_material(obj/thing, mob/user) + . = ..() + if(.) + return TRUE + if(istype(thing, /obj/structure/supermatter/shard)) + var/exotic_matter_amount = thing?.matter?[/decl/material/solid/exotic_matter] + if(exotic_matter_amount <= 0) + return FALSE + stored_material[/decl/material/solid/exotic_matter] = exotic_matter_amount + to_chat(user, SPAN_NOTICE("You awkwardly cram \the [thing] into \the [src]'s material buffer.")) + qdel(thing) + return TRUE + return FALSE \ No newline at end of file diff --git a/mods/content/supermatter/overrides/sm_meteor.dm b/mods/content/supermatter/overrides/sm_meteor.dm new file mode 100644 index 000000000000..f5bba645c189 --- /dev/null +++ b/mods/content/supermatter/overrides/sm_meteor.dm @@ -0,0 +1,5 @@ +/obj/effect/meteor/destroyer/supermatter + name = "supermatter shard" + desc = "Oh God, what will be next...?" + icon = 'icons/obj/supermatter_32.dmi' + icon_state = "supermatter" diff --git a/mods/content/supermatter/overrides/sm_singularity.dm b/mods/content/supermatter/overrides/sm_singularity.dm new file mode 100644 index 000000000000..b13506cd580b --- /dev/null +++ b/mods/content/supermatter/overrides/sm_singularity.dm @@ -0,0 +1,46 @@ +#define STAGE_SUPER 11 + +/// A singularity that has the mass of a supermatter crystal. +/decl/singularity_stage/stage_super + name = "super gravitational singularity" + desc = "A gravitational singularity with the properties of supermatter. It has the power to destroy worlds." + min_energy = 50000 + max_energy = INFINITY + stage_size = STAGE_SUPER + footprint = 6 + icon = 'icons/effects/352x352.dmi' + icon_state = "singularity_s11"//uh, whoever drew that, you know that black holes are supposed to look dark right? What's this, the clown's singulo? + pixel_x = -160 + pixel_y = -160 + grav_pull = 16 + consume_range = 5 + dissipates_over_time = 0 //It cant go smaller due to e loss + event_chance = 25 //Events will fire off more often. + forced_event = /decl/singularity_event/supermatter_wave + wander = TRUE + explosion_vulnerable = FALSE + em_heavy_range = 12 + em_light_range = 16 + mesmerize_text = "helpless" + the_goggles_do_nothing = TRUE + ignore_obstacles = TRUE + +/decl/singularity_stage/stage_super/grow_to(obj/effect/singularity/source) + source.visible_message(SPAN_SINISTER("You witness the creation of a destructive force that cannot possibly be stopped by human hands.")) + +// why is this not shrink_from or something? +/decl/singularity_stage/stage_five/shrink_to(obj/effect/singularity/source) + source.visible_message(SPAN_WARNING("\The [source] miraculously reduces in size and loses its supermatter properties.")) + +// Singularity event +/decl/singularity_event/supermatter_wave/handle_event(obj/effect/singularity/source) + for(var/mob/living/M in view(10, source.loc)) + to_chat(M, SPAN_WARNING("You hear an unearthly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.")) + if(prob(67)) + to_chat(M, SPAN_NOTICE("Miraculously, it fails to kill you.")) + else + to_chat(M, SPAN_DANGER("You don't even have a moment to react as you are reduced to ashes by the intense radiation.")) + M.dust() + SSradiation.radiate(source, rand(source.energy)) + +#undef STAGE_SUPER \ No newline at end of file diff --git a/mods/content/supermatter/overrides/sm_strings.dm b/mods/content/supermatter/overrides/sm_strings.dm new file mode 100644 index 000000000000..510a49fac07a --- /dev/null +++ b/mods/content/supermatter/overrides/sm_strings.dm @@ -0,0 +1,8 @@ +/obj/item/disk/secret_project/get_secret_project_nouns() + var/static/sm_injected = FALSE + if(sm_injected) + return ..() + sm_injected = TRUE + . = ..() + . += "a supermatter engine" + return . diff --git a/mods/content/supermatter/overrides/sm_trader.dm b/mods/content/supermatter/overrides/sm_trader.dm new file mode 100644 index 000000000000..dbadf5961a79 --- /dev/null +++ b/mods/content/supermatter/overrides/sm_trader.dm @@ -0,0 +1,3 @@ +/datum/trader/ship/unique/rock/New() + ..() + possible_trading_items[/obj/structure/supermatter] = TRADER_ALL \ No newline at end of file diff --git a/mods/content/supermatter/overrides/sm_unit_tests.dm b/mods/content/supermatter/overrides/sm_unit_tests.dm new file mode 100644 index 000000000000..18351659e4c1 --- /dev/null +++ b/mods/content/supermatter/overrides/sm_unit_tests.dm @@ -0,0 +1,3 @@ +/datum/unit_test/turf_floor_icons_shall_be_valid/New() + ..() + excepted_types |= /turf/unsimulated/wall/cascade \ No newline at end of file diff --git a/mods/content/supermatter/overrides/sm_xenoarchaeology.dm b/mods/content/supermatter/overrides/sm_xenoarchaeology.dm new file mode 100644 index 000000000000..13861abcc41e --- /dev/null +++ b/mods/content/supermatter/overrides/sm_xenoarchaeology.dm @@ -0,0 +1,7 @@ +/datum/artifact_find/New() + var/static/supermatter_injected = FALSE + if(!supermatter_injected) + potential_finds[/obj/structure/supermatter] = 5 + potential_finds[/obj/structure/supermatter/shard] = 25 + supermatter_injected = TRUE + ..() diff --git a/mods/content/supermatter/structures/sm_closets.dm b/mods/content/supermatter/structures/sm_closets.dm new file mode 100644 index 000000000000..a1e58097f939 --- /dev/null +++ b/mods/content/supermatter/structures/sm_closets.dm @@ -0,0 +1,2 @@ +/obj/structure/closet/crate/secure/large/supermatter + closet_appearance = /decl/closet_appearance/large_crate/secure/hazard \ No newline at end of file diff --git a/mods/content/supermatter/structures/supermatter_crystal.dm b/mods/content/supermatter/structures/supermatter_crystal.dm new file mode 100644 index 000000000000..8bc697cd896d --- /dev/null +++ b/mods/content/supermatter/structures/supermatter_crystal.dm @@ -0,0 +1,736 @@ +/* + How to tweak the SM + + POWER_FACTOR directly controls how much power the SM puts out at a given level of excitation (power var). Making this lower means you have to work the SM harder to get the same amount of power. + CRITICAL_TEMPERATURE The temperature at which the SM starts taking damage. + + CHARGING_FACTOR Controls how much emitter shots excite the SM. + DAMAGE_RATE_LIMIT Controls the maximum rate at which the SM will take damage due to high temperatures. +*/ + +// Base variants are applied to everyone on the same Z level +// Range variants are applied on per-range basis: numbers here are on point blank, it scales with the map size (assumes square shaped Z levels) +#define DETONATION_RADS 40 +#define DETONATION_MOB_CONCUSSION 4 // Value that will be used for SET_STATUS_MAX(src, STAT_WEAK) on mobs. + +// Base amount of ticks for which a specific type of machine will be offline for. +- 20% added by RNG. +// This does pretty much the same thing as an electrical storm, it just affects the whole Z level instantly. +#define DETONATION_APC_OVERLOAD_PROB 10 // prob() of overloading an APC's lights. +#define DETONATION_SHUTDOWN_APC 120 // Regular APC. +#define DETONATION_SHUTDOWN_CRITAPC 10 // Critical APC. AI core and such. Considerably shorter as we don't want to kill the AI with a single blast. Still a nuisance. +#define DETONATION_SHUTDOWN_SMES 60 // SMES +#define DETONATION_SHUTDOWN_RNG_FACTOR 20 // RNG factor. Above shutdown times can be +- X%, where this setting is the percent. Do not set to 100 or more. +#define DETONATION_SOLAR_BREAK_CHANCE 60 // prob() of breaking solar arrays (this is per-panel, and only affects the Z level SM is on) + +#define WARNING_DELAY 20 //seconds between warnings. + +#define LIGHT_POWER_CALC (max(power / 50, 1)) + +// Keeps Accent sounds from layering, increase or decrease as preferred. +#define SUPERMATTER_ACCENT_SOUND_COOLDOWN 2 SECONDS + +var/global/list/supermatter_final_thoughts = list( + "Oh, fuck.", + "That was not a wise decision." +) + +var/global/list/supermatter_calm_accent_sounds = list( + 'sound/machines/sm/accent/normal/1.ogg', + 'sound/machines/sm/accent/normal/2.ogg', + 'sound/machines/sm/accent/normal/3.ogg', + 'sound/machines/sm/accent/normal/4.ogg', + 'sound/machines/sm/accent/normal/5.ogg' + +) + +var/global/list/supermatter_delam_accent_sounds = list( + 'sound/machines/sm/accent/delam/1.ogg', + 'sound/machines/sm/accent/delam/2.ogg', + 'sound/machines/sm/accent/delam/3.ogg', + 'sound/machines/sm/accent/delam/4.ogg', + 'sound/machines/sm/accent/delam/5.ogg', + + +) + +// Returns a truthy value that is also used for power generation by the supermatter core itself. +/proc/try_supermatter_consume(var/mob/user, var/atom/movable/victim, var/atom/source, var/collided) + + if(!istype(victim) || !istype(source) || istype(victim, /obj/effect) || !victim.simulated || isobserver(victim)) + return 0 + + var/decl/pronouns/victim_pronouns = victim.get_pronouns() + if(isliving(victim)) + if(user) + var/hurls = (collided ? "hurls" : "pushes") + source.visible_message( + SPAN_DANGER("\The [user] [hurls] \the [victim] into \the [source], inducing a resonance! [victim_pronouns.He] start[victim_pronouns.s] to glow and catches aflame before flashing into ash."),\ + SPAN_DANGER("\The [user] [hurls] you into \the [source], and your ears are filled with unearthly ringing."), \ + SPAN_WARNING("You hear an unearthly ringing, then what sounds like a shrilling kettle as a wave of heat washes over you.")) + else + source.visible_message( + SPAN_DANGER("\The [victim] [collided ? "slams into" : "touches"] \the [source], inducing a resonance! [victim_pronouns.He] start[victim_pronouns.s] to glow and catches aflame before flashing into ash."), \ + SPAN_DANGER("You [collided ? "slam into" : "touch"] \the [source], and your ears are filled with unearthly ringing. Your last thought is \"[pick(global.supermatter_final_thoughts)]\""), \ + SPAN_WARNING("You hear an unearthly ringing, then what sounds like a shrilling kettle as a wave of heat washes over you.")) + else + if(user) + source.visible_message( \ + SPAN_DANGER("\The [user][collided ? "throws" : "touches"] \the [victim] [collided ? "into" : "to"] \the [source] and [victim_pronouns.he] instantly flash[victim_pronouns.es] away into ashes."), \ + SPAN_WARNING("You hear a loud crack as you are washed with a wave of heat.")) + else + source.visible_message( \ + SPAN_DANGER("\The [victim] [collided ? "smacks into" : "touches"] \the [source] and instantly flashes away into ashes."), \ + SPAN_WARNING("You hear a loud crack as you are washed with a wave of heat.")) + playsound(source, 'sound/effects/supermatter.ogg', 50, 1) + + if(isliving(victim)) + var/mob/living/M = victim + M.dust() + . = 2 + else + . = 1 + qdel(victim) + + //Some poor sod got eaten, go ahead and irradiate people nearby. + var/list/viewers = viewers(source) + for(var/mob/living/M in range(10, get_turf(source))) + if(M in viewers) + M.show_message( \ + SPAN_DANGER("As \the [source] slowly stops resonating, you find your skin covered in new radiation burns."), 1,\ + SPAN_DANGER("The unearthly ringing subsides and you notice you have new radiation burns."), 2) + else + M.show_message(SPAN_DANGER("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns."), 2) + var/rads = 500 + SSradiation.radiate(source, rads) + +/obj/structure/supermatter + name = "supermatter crystal" + desc = "A strangely translucent and iridescent crystal. You get headaches just from looking at it." + icon = 'icons/obj/supermatter_48.dmi' + icon_state = "supermatter" + density = TRUE + anchored = FALSE + light_range = 4 + layer = ABOVE_HUMAN_LAYER + material = /decl/material/solid/exotic_matter/supermatter + matter = list( + /decl/material/solid/metal/steel = MATTER_AMOUNT_REINFORCEMENT + ) + w_class = ITEM_SIZE_LARGE_STRUCTURE + + var/nitrogen_retardation_factor = 0.15 // Higher == N2 slows reaction more + var/thermal_release_modifier = 10000 // Higher == more heat released during reaction + var/product_release_modifier = 1500 // Higher == less product gas released by reaction + var/oxygen_release_modifier = 15000 // Higher == less oxygen released at high temperature/power + var/radiation_release_modifier = 2 // Higher == more radiation released with more power. + var/reaction_power_modifier = 1.1 // Higher == more overall power + + //Controls how much power is produced by each collector in range - this is the main parameter for tweaking SM balance, as it basically controls how the power variable relates to the rest of the game. + var/power_factor = 1.0 + var/decay_factor = 700 //Affects how fast the supermatter power decays + var/critical_temperature = 5000 //K + var/charging_factor = 0.05 + var/damage_rate_limit = 4.5 //damage rate cap at power = 300, scales linearly with power + + var/gasefficency = 0.25 + + var/last_power + var/damage = 0 + var/damage_archived = 0 + var/safe_alert = "Crystaline hyperstructure returning to safe operating levels." + var/safe_warned = 0 + var/public_alert = 0 //Stick to Engineering frequency except for big warnings when integrity bad + var/warning_point = 100 + var/warning_alert = "Danger! Crystal hyperstructure instability!" + var/emergency_point = 700 + var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT." + var/explosion_point = 1000 + + light_color = "#927a10" + var/base_color = "#927a10" + var/warning_color = "#c78c20" + var/emergency_color = "#ffd04f" + + var/grav_pulling = 0 + // Time in ticks between delamination ('exploding') and exploding (as in the actual boom) + var/pull_time = 300 + var/explosion_power = 9 + + // Time in 1/10th of seconds since the last sent warning + var/lastwarning = 0 + + // This stops spawning redundand explosions. Also incidentally makes supermatter unexplodable if set to 1. + var/exploded = 0 + + var/power = 0 + var/oxygen = 0 + + //Temporary values so that we can optimize this + //How much the bullets damage should be multiplied by when it is added to the internal variables + var/config_bullet_energy = 2 + //How much of the power is left after processing is finished? +// var/config_power_reduction_per_tick = 0.5 + //How much hallucination should it produce per unit of power? + var/config_hallucination_power = 0.1 + + var/debug = 0 + + var/disable_adminwarn = FALSE + + var/aw_normal = FALSE + var/aw_notify = FALSE + var/aw_warning = FALSE + var/aw_danger = FALSE + var/aw_emerg = FALSE + var/aw_delam = FALSE + var/aw_EPR = FALSE + + var/last_accent_sound = 0 + + var/datum/composite_sound/supermatter/soundloop + + // A uniquely-identifying number assigned to this supermatter crystal. Mostly used by the supermatter monitoring console. + var/uid = 0 + + var/damage_animation = FALSE //are we doing our damage animation? + + var/list/threshholds = list( // List of lists defining the amber/red labeling threshholds in readouts. Numbers are minminum red and amber and maximum amber and red, in that order + list("name" = SUPERMATTER_DATA_EER, "min_h" = -1, "min_l" = -1, "max_l" = 150, "max_h" = 300), + list("name" = SUPERMATTER_DATA_TEMPERATURE, "min_h" = -1, "min_l" = -1, "max_l" = 4000, "max_h" = 5000), + list("name" = SUPERMATTER_DATA_PRESSURE, "min_h" = -1, "min_l" = -1, "max_l" = 5000, "max_h" = 10000), + list("name" = SUPERMATTER_DATA_EPR, "min_h" = -1, "min_l" = 1.0, "max_l" = 2.5, "max_h" = 4.0) + ) + +/obj/structure/supermatter/Initialize() + . = ..() + uid = sequential_id(/obj/structure/supermatter) + soundloop = new(list(src), TRUE) + update_icon() + add_filter("outline", 1, list(type = "drop_shadow", size = 0, color = COLOR_WHITE, x = 0, y = 0)) + START_PROCESSING(SSsupermatter, src) + +/obj/structure/supermatter/Destroy() + QDEL_NULL(soundloop) + STOP_PROCESSING(SSsupermatter, src) + . = ..() + +/obj/structure/supermatter/on_update_icon() + . = ..() + underlays.Cut() + underlays += mutable_appearance(icon, "[icon_state]_underplate", flags = RESET_COLOR, plane = plane, layer = OBJ_LAYER) + +/obj/structure/supermatter/get_matter_amount_modifier() + . = ..() * (1/HOLLOW_OBJECT_MATTER_MULTIPLIER) * 10 // Big solid chunk of matter. + +/obj/structure/supermatter/proc/handle_admin_warnings() + if(disable_adminwarn) + return + + // Generic checks, similar to checks done by supermatter monitor program. + aw_normal = status_adminwarn_check(SUPERMATTER_NORMAL, aw_normal, "INFO: Supermatter crystal has been energised.", FALSE) + aw_notify = status_adminwarn_check(SUPERMATTER_NOTIFY, aw_notify, "INFO: Supermatter crystal is approaching unsafe operating temperature.", FALSE) + aw_warning = status_adminwarn_check(SUPERMATTER_WARNING, aw_warning, "WARN: Supermatter crystal is taking integrity damage!", FALSE) + aw_danger = status_adminwarn_check(SUPERMATTER_DANGER, aw_danger, "WARN: Supermatter integrity is below 50%!", TRUE) + aw_emerg = status_adminwarn_check(SUPERMATTER_EMERGENCY, aw_emerg, "CRIT: Supermatter integrity is below 25%!", FALSE) + aw_delam = status_adminwarn_check(SUPERMATTER_DELAMINATING, aw_delam, "CRIT: Supermatter is delaminating!", TRUE) + + // EPR check. Only runs when supermatter is energised. Triggers when there is very low amount of coolant in the core (less than one standard canister). + // This usually means a core breach or deliberate venting. + if(get_status() && (get_epr() < 0.5)) + if(!aw_EPR) + log_and_message_admins("WARN: Supermatter EPR value low. Possible core breach detected.") + aw_EPR = TRUE + else + aw_EPR = FALSE + +/obj/structure/supermatter/proc/status_adminwarn_check(var/min_status, var/current_state, var/message, var/send_webhook = FALSE) + var/status = get_status() + if(status >= min_status) + if(!current_state) + log_and_message_admins(message) + if(send_webhook) + SSwebhooks.send(WEBHOOK_AHELP_SENT, list("name" = "Supermatter Warning", "body" = message)) + return TRUE + else + return FALSE + +/obj/structure/supermatter/proc/get_epr() + var/turf/T = get_turf(src) + if(!istype(T)) + return + var/datum/gas_mixture/air = T.return_air() + if(!air) + return 0 + return round((air.total_moles / air.group_multiplier) / 23.1, 0.01) + +/obj/structure/supermatter/proc/get_status() + var/turf/T = get_turf(src) + if(!T) + return SUPERMATTER_ERROR + var/datum/gas_mixture/air = T.return_air() + if(!air) + return SUPERMATTER_ERROR + + if(grav_pulling || exploded) + return SUPERMATTER_DELAMINATING + + if(get_integrity() < 25) + return SUPERMATTER_EMERGENCY + + if(get_integrity() < 50) + return SUPERMATTER_DANGER + + if((get_integrity() < 100) || (air.temperature > critical_temperature)) + return SUPERMATTER_WARNING + + if(air.temperature > (critical_temperature * 0.8)) + return SUPERMATTER_NOTIFY + + if(power > 5) + return SUPERMATTER_NORMAL + return SUPERMATTER_INACTIVE + + +/obj/structure/supermatter/proc/explode() + set waitfor = 0 + + if(exploded) + return + + log_and_message_admins("Supermatter delaminating at [x] [y] [z]") + anchored = TRUE + grav_pulling = 1 + exploded = 1 + sleep(pull_time) + var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, exosuit, or other container shouldn't block it's effects that way. + if(!istype(TS)) + return + + var/list/affected_z = SSmapping.get_connected_levels(TS.z) + + // Effect 1: Radiation, weakening to all mobs on Z level + for(var/z in affected_z) + SSradiation.z_radiate(locate(1, 1, z), DETONATION_RADS, 1) + + for(var/mob/living/mob in global.living_mob_list_) + var/turf/TM = get_turf(mob) + if(!TM) + continue + if(!(TM.z in affected_z)) + continue + + SET_STATUS_MAX(mob, STAT_WEAK, DETONATION_MOB_CONCUSSION) + to_chat(mob, "An invisible force slams you against the ground!") + + // Effect 2: Z-level wide electrical pulse + for(var/obj/machinery/apc/A in SSmachines.machinery) + if(!(A.z in affected_z)) + continue + + // Overloads lights + if(prob(DETONATION_APC_OVERLOAD_PROB)) + A.overload_lighting() + // Causes the APCs to go into system failure mode. + var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100 + if(A.is_critical) + A.energy_fail(round(DETONATION_SHUTDOWN_CRITAPC * random_change)) + else + A.energy_fail(round(DETONATION_SHUTDOWN_APC * random_change)) + + for(var/obj/machinery/power/smes/buildable/S in SSmachines.machinery) + if(!(S.z in affected_z)) + continue + // Causes SMESes to shut down for a bit + var/random_change = rand(100 - DETONATION_SHUTDOWN_RNG_FACTOR, 100 + DETONATION_SHUTDOWN_RNG_FACTOR) / 100 + S.energy_fail(round(DETONATION_SHUTDOWN_SMES * random_change)) + + // Effect 3: Break solar arrays + + for(var/obj/machinery/power/solar/S in SSmachines.machinery) + if(!(S.z in affected_z)) + continue + if(prob(DETONATION_SOLAR_BREAK_CHANCE)) + S.set_broken(TRUE) + + + + // Effect 4: Medium scale explosion + spawn(0) + explosion(TS, explosion_power/2, explosion_power, explosion_power * 2, explosion_power * 4, 1) + qdel(src) + +/obj/structure/supermatter/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(user.skill_check(SKILL_ENGINES, SKILL_EXPERT)) + var/integrity_message + switch(get_integrity()) + if(0 to 30) + integrity_message = "It looks highly unstable!" + if(31 to 70) + integrity_message = "It appears to be losing cohesion!" + else + integrity_message = "At a glance, it seems to be in sound shape." + . += integrity_message + if(user.skill_check(SKILL_ENGINES, SKILL_PROF)) + var/display_power = power + display_power *= (0.85 + 0.3 * rand()) + display_power = round(display_power, 20) + . += "Eyeballing it, you place the relative EER at around [display_power] MeV/cm3." + +//Changes color and luminosity of the light to these values if they were not already set +/obj/structure/supermatter/proc/shift_light(var/lum, var/clr) + if(lum != light_range || abs(power - last_power) > 10 || clr != light_color) + set_light(lum, LIGHT_POWER_CALC, clr) + last_power = power + +/obj/structure/supermatter/proc/get_integrity() + var/integrity = damage / explosion_point + integrity = round(100 - integrity * 100) + integrity = integrity < 0 ? 0 : integrity + return integrity + + +/obj/structure/supermatter/proc/announce_warning() + var/integrity = get_integrity() + var/alert_msg = " Integrity at [integrity]%" + + if(damage > emergency_point) + alert_msg = emergency_alert + alert_msg + lastwarning = world.timeofday - WARNING_DELAY * 4 + else if(damage >= damage_archived) // The damage is still going up + safe_warned = 0 + alert_msg = warning_alert + alert_msg + lastwarning = world.timeofday + else if(!safe_warned) + safe_warned = 1 // We are safe, warn only once + alert_msg = safe_alert + lastwarning = world.timeofday + else + alert_msg = null + if(alert_msg) + do_telecomms_announcement(src, alert_msg, "Supermatter Monitor", "Engineering") + //Public alerts + if((damage > emergency_point) && !public_alert) + do_telecomms_announcement(src, "WARNING: SUPERMATTER CRYSTAL DELAMINATION IMMINENT! SAFEROOMS UNBOLTED.", "Supermatter Monitor") + public_alert = 1 + global.using_map.unbolt_saferooms() + for(var/mob/M in global.player_list) + var/turf/T = get_turf(M) + if(T && isStationLevel(T.z) && !isnewplayer(M) && !isdeaf(M)) + sound_to(M, 'sound/ambience/matteralarm.ogg') + else if(safe_warned && public_alert) + do_telecomms_announcement(src, alert_msg, "Supermatter Monitor") + public_alert = 0 + + +/obj/structure/supermatter/Process() + var/turf/L = loc + + if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity. + return PROCESS_KILL + + if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now. + return //Yeah just stop. + + if(damage > explosion_point) + if(!exploded) + if(!isspaceturf(L) && isStationLevel(L.z)) + announce_warning() + explode() + else if(damage > warning_point) // while the core is still damaged and it's still worth noting its status + shift_light(5, warning_color) + if(damage > emergency_point) + shift_light(7, emergency_color) + if(!isspaceturf(L) && ((world.timeofday - lastwarning) >= WARNING_DELAY * 10) && isStationLevel(L.z)) + announce_warning() + else + shift_light(4,base_color) + if(grav_pulling) + supermatter_pull(src) + + // Vary volume by power produced. + if(power) + // Volume will be 1 at no power, ~12.5 at ENERGY_NITROGEN, and 20+ at ENERGY_HYDROGEN. + // (this is probably wrong since hydrogen heat cap is changed from phoron) + // Capped to 20 volume since higher volumes get annoying and it sounds worse. + // Formula previously was min(round(power/10)+1, 20) + soundloop.play_volume = clamp((50 + (power / 50)), 50, 100) + + // Swap loops between calm and delamming. + if(damage >= explosion_point * 0.25) + soundloop.mid_sounds = list('sound/machines/sm/loops/delamming.ogg' = 1) + else + soundloop.mid_sounds = list('sound/machines/sm/loops/calm.ogg' = 1) + + // Play Delam/Neutral sounds at rate determined by power and damage. + if(last_accent_sound < world.time && prob(20)) + var/aggression = min(((damage / 800) * (power / 2500)), 1.0) * 100 + if(damage >= explosion_point * 0.25) + playsound(src, pick(supermatter_delam_accent_sounds), max(50, aggression), FALSE, 10) + else + playsound(src, pick(supermatter_calm_accent_sounds), max(50, aggression), FALSE, 10) + var/next_sound = round((100 - aggression) * 5) + last_accent_sound = world.time + max(SUPERMATTER_ACCENT_SOUND_COOLDOWN, next_sound) + + //Ok, get the air from the turf + var/datum/gas_mixture/removed = null + var/datum/gas_mixture/env = null + + //ensure that damage doesn't increase too quickly due to super high temperatures resulting from no coolant, for example. We dont want the SM exploding before anyone can react. + //We want the cap to scale linearly with power (and explosion_point). Let's aim for a cap of 5 at power = 300 (based on testing, equals roughly 5% per SM alert announcement). + var/damage_inc_limit = (power/300)*(explosion_point/1000)*damage_rate_limit + + if(!isspaceturf(L)) + env = L.return_air() + removed = env.remove(gasefficency * env.total_moles) //Remove gas from surrounding area + + if(!env || !removed || !removed.total_moles) + damage += max((power - 15*power_factor)/10, 0) + else if (grav_pulling) //If supermatter is detonating, remove all air from the zone + env.remove(env.total_moles) + else + damage_archived = damage + + damage = max(0, damage + clamp((removed.temperature - critical_temperature) / 150, -damage_rate_limit, damage_inc_limit)) + + //Ok, 100% oxygen atmosphere = best reaction + //Maxes out at 100% oxygen pressure + oxygen = clamp((removed.get_by_flag(XGM_GAS_OXIDIZER) - (removed.gas[/decl/material/gas/nitrogen] * nitrogen_retardation_factor)) / removed.total_moles, 0, 1) + + //calculate power gain for oxygen reaction + var/temp_factor + var/equilibrium_power + if (oxygen > 0.8) + //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 400 + equilibrium_power = 400 + else + //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 250 + equilibrium_power = 250 + + temp_factor = ( (equilibrium_power/decay_factor)**3 )/800 + power = max( (removed.temperature * temp_factor) * oxygen + power, 0) + + var/device_energy = power * reaction_power_modifier + + //Release reaction gasses + var/heat_capacity = removed.heat_capacity() + removed.adjust_gas(/decl/material/solid/exotic_matter, max(device_energy / product_release_modifier, 0), FALSE) + removed.adjust_gas(/decl/material/gas/oxygen, max((device_energy + removed.temperature - T0C) / oxygen_release_modifier, 0)) + + var/thermal_power = thermal_release_modifier * device_energy + if (debug) + var/heat_capacity_new = removed.heat_capacity() + visible_message("[src]: Releasing [round(thermal_power)] W.") + visible_message("[src]: Releasing additional [round((heat_capacity_new - heat_capacity)*removed.temperature)] W with exhaust gasses.") + + removed.add_thermal_energy(thermal_power) + removed.temperature = clamp(removed.temperature, 0, 10000) + + env.merge(removed) + + for(var/mob/living/human/subject in view(src, min(7, round(sqrt(power/6))))) + var/obj/item/organ/internal/eyes/eyes = subject.get_organ(BP_EYES, /obj/item/organ/internal/eyes) + if (!eyes) + continue + if (BP_IS_PROSTHETIC(eyes)) + continue + if(subject.has_meson_effect()) + continue + var/effect = max(0, min(200, power * config_hallucination_power * sqrt( 1 / max(1,get_dist(subject, src)))) ) + subject.adjust_hallucination(effect, 0.25 * effect) + + if(power) + var/size_calc = max((power / 200), 1) //this needs to be a decently small value, but not TOO small. + animate_filter("outline", list(size = size_calc)) + if(!power) + animate_filter("outline", list(size = 0)) + + color = color_matrix_contrast(Interpolate(1, 5, clamp( (damage - emergency_point) / (explosion_point - emergency_point), 0, 1))) + + if (damage >= emergency_point && !damage_animation) + start_damage_animation() + else if (damage < emergency_point) + remove_filter("rays") + + SSradiation.radiate(src, power * radiation_release_modifier) //Better close those shutters! + power -= (power/decay_factor)**3 //energy losses due to radiation + handle_admin_warnings() + + return 1 + +/obj/structure/supermatter/proc/start_damage_animation() + if(damage_animation) + return + if(!get_filter("rays")) + add_filter("rays", 1 ,list(type = "rays", size = 64, color = emergency_color, factor = 0.6, density = 12)) + animate_filter("rays", list(time = 10 SECONDS, offset = 10, loop=-1)) + animate(time = 10 SECONDS, loop=-1) + + animate_filter("rays",list(time = 2 SECONDS, size = 80, loop=-1, flags = ANIMATION_PARALLEL)) + animate(time = 2 SECONDS, size = 10, loop=-1, flags = ANIMATION_PARALLEL) + addtimer(CALLBACK(src, PROC_REF(finish_damage_animation)), 12 SECONDS) + +/obj/structure/supermatter/proc/finish_damage_animation() + damage_animation = FALSE + +/obj/structure/supermatter/bullet_act(var/obj/item/projectile/Proj) + var/turf/L = loc + if(!istype(L)) // We don't run process() when we are in space + return 0 // This stops people from being able to really power up the supermatter + // Then bring it inside to explode instantly upon landing on a valid turf. + + + var/proj_damage = Proj.get_structure_damage() + if(istype(Proj, /obj/item/projectile/beam)) + power += proj_damage * config_bullet_energy * charging_factor / power_factor + else + damage += proj_damage * config_bullet_energy + return 0 + +/obj/structure/supermatter/attack_robot(mob/user) + ui_interact(user) + return TRUE + +/obj/structure/supermatter/attack_ai(mob/living/silicon/ai/user) + ui_interact(user) + return TRUE + +/obj/structure/supermatter/attack_ghost(mob/user) + ui_interact(user) + return TRUE + +/obj/structure/supermatter/attack_hand(mob/user) + return Consume(null, user, TRUE) || ..() + +// This is purely informational UI that may be accessed by AIs or robots +/obj/structure/supermatter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + data["integrity_percentage"] = round(get_integrity()) + var/datum/gas_mixture/env = null + var/turf/T = get_turf(src) + + if(istype(T)) + env = T.return_air() + + if(!env) + data["ambient_temp"] = 0 + data["ambient_pressure"] = 0 + else + data["ambient_temp"] = round(env.temperature) + data["ambient_pressure"] = round(env.return_pressure()) + data["detonating"] = grav_pulling + data["energy"] = power + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "supermatter_crystal.tmpl", "Supermatter Crystal", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/structure/supermatter/attackby(obj/item/used_item, mob/user) + + if(istype(used_item, /obj/item/stack/tape_roll/duct_tape)) + var/obj/item/stack/tape_roll/duct_tape/T = used_item + if(!T.can_use(20)) + to_chat(user, SPAN_WARNING("You need at least 20 [T.plural_name] to repair \the [src].")) + return TRUE + T.use(20) + playsound(src, 'sound/effects/tape.ogg', 100, TRUE) + to_chat(user, SPAN_NOTICE("You begin to repair some of the damage to \the [src] with \the [used_item].")) + damage = max(damage -10, 0) + return TRUE // be nice, the extra duct tape if you have 21 or more doesn't turn to ash and irradiate you. + + if(!QDELETED(used_item)) + user.visible_message(SPAN_WARNING("\The [user] touches \the [src] with \a [used_item] as silence fills the room..."),\ + SPAN_DANGER("You touch \the [used_item] to \the [src] when everything suddenly goes quiet."),\ + SPAN_WARNING("Everything suddenly goes silent.")) + + to_chat(user, SPAN_NOTICE("\The [used_item] flashes into dust as you flinch away from \the [src].")) + user.drop_from_inventory(used_item) + Consume(user, used_item, TRUE) + user.apply_damage(150, IRRADIATE, damage_flags = DAM_DISPERSED) + return TRUE + +/obj/structure/supermatter/Bumped(atom/AM) + if(!Consume(null, AM)) + return ..() + +/obj/structure/supermatter/proc/Consume(var/mob/living/user, var/obj/item/thing, var/touched) + . = try_supermatter_consume(user, thing, src, touched) + if(. <= 0) + return + power += . * 200 + . = !!. + +/proc/supermatter_pull(var/atom/target, var/pull_range = 255, var/pull_power = STAGE_FIVE) + for(var/atom/A in range(pull_range, target)) + A.singularity_pull(target, pull_power) + +/obj/structure/supermatter/GotoAirflowDest(n) //Supermatter not pushed around by airflow + return + +/obj/structure/supermatter/RepelAirflowDest(n) + return + +/obj/structure/supermatter/explosion_act(var/severity) + . = ..() + if(.) + power *= max(1, 5 - severity) + log_and_message_admins("WARN: Explosion near the Supermatter! New EER: [power].") + +/obj/structure/supermatter/singularity_act() + if(!src.loc) + return + + var/prints = "" + if(src.fingerprintshidden) + prints = ", all touchers : " + src.fingerprintshidden + + SetUniversalState(/datum/universal_state/supermatter_cascade) + log_and_message_admins("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].") + src.forceMove(null) + qdel(src) + return 50000 + +/obj/structure/supermatter/get_artifact_scan_data() + return "Superdense crystalline structure - appears to have been shaped or hewn, lattice is approximately 20 times denser than should be possible." + +/obj/structure/supermatter/shard //Small subtype, less efficient and more sensitive, but less boom. + name = "supermatter shard" + desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. You get headaches just from looking at it." + icon = 'icons/obj/supermatter_32.dmi' + icon_state = "supermatter_shard" + w_class = ITEM_SIZE_STRUCTURE + + warning_point = 50 + emergency_point = 400 + explosion_point = 600 + + gasefficency = 0.125 + + pull_time = 150 + explosion_power = 3 + +/obj/structure/supermatter/medium + icon = 'icons/obj/supermatter_32.dmi' + w_class = (ITEM_SIZE_STRUCTURE + ITEM_SIZE_LARGE_STRUCTURE) / 2 // halfway between a shard and a normal SM + +/obj/structure/supermatter/shard/announce_warning() //Shards don't get announcements + return + +/obj/structure/supermatter/shard/singularity_act() + src.forceMove(null) + qdel(src) + return 5000 + +#undef LIGHT_POWER_CALC +#undef DETONATION_MOB_CONCUSSION +#undef DETONATION_APC_OVERLOAD_PROB +#undef DETONATION_SHUTDOWN_APC +#undef DETONATION_SHUTDOWN_CRITAPC +#undef DETONATION_SHUTDOWN_SMES +#undef DETONATION_SHUTDOWN_RNG_FACTOR +#undef DETONATION_SOLAR_BREAK_CHANCE +#undef WARNING_DELAY diff --git a/mods/content/tabloids/_tabloids.dm b/mods/content/tabloids/_tabloids.dm new file mode 100644 index 000000000000..7d6188ff28fa --- /dev/null +++ b/mods/content/tabloids/_tabloids.dm @@ -0,0 +1,58 @@ +/decl/modpack/tabloids + name = "Tabloids" + tabloid_publishers = list( + "\improper Solar Enquirer", + "\improper Stellar Examiner", + "\improper Antares Daily", + "\improper Weekly Galactic News", + "\improper Spiral" + ) + tabloid_headlines = list( + "NARCOALGORITHMS: ARE YOUR CHILDREN SAFE?", + "ARE GMO HUMANS POISONOUS IN BED?", + "TOP 10 REASONS WHY OTHER SPECIES ARE A HOAX", + "CENTENNIAL POSITRONIC EXTENDS LIFESPAN WITH 1 SIMPLE TRICK", + "TOP 10 DANGEROUS FOODS WITH CHEMICALS", + "NEW TERRIFYING TEEN TREND: SUN-DIVING", + "HAS YOUR SPOUSE BEEN REPLACED BY AN ALIEN IMPOSTER? STUDIES SUGGEST YES!", + "SPACE CAUSES CANCER: DOCTORS CONFIRM", + "ARE BODY SCANNERS TOO INVASIVE? FIND OUT INSIDE!", + "HAS SCIENCE GONE TOO FAR? LOCAL SCIENTIST DEBUNKS ALIEN THEORY, DECRIES THEM AS TUBE EXPERIMENTS GONE WRONG", + "100 DELICIOUS RECIPES LETHAL TO CARBON-BASED LIFE", + "TOP FIVE SPECIES WE DROVE TO EXTINCTION; NUMBER TWO WILL SHOCK YOU", + "RELIGION WAS RIGHT? SHOCK FINDINGS SHOW ALIEN SIMILARITY TO ANIMALS, EXISTENCE OF BOATS", + "TOP TEN REASONS WHY ONLY HUMANS ARE SENTIENT", + "WHICH PLANET HAS THE BEST LOVERS? THIS AND MORE INSIDE!", + "SHE SAID WE SHOULD SEE OTHER PEOPLE, SO I MARRIED A NEO-AVIAN PACK: FULL STORY INSIDE", + "LOSE WEIGHT THREE TIMES FASTER WITH THESE LOW-G MANEUVERS!", + "MY DAUGHTER JOINED A NEURAL COLLECTIVE AND NOW SHE CAN TASTE SPACETIME: FULL STORY INSIDE", + "WERE THE NAZIS PSYCHIC? ONE HISTORIAN TELLS ALL", + "IS THE SOLAR GOVERNMENT CREATING AN AI SUPERINTELLIGENCE NEAR MERCURY? ONE EXPERT REVEALS SHOCKING INSIDER DETAILS!", + "TOP TEN HISTORICAL FIGURES THAT WERE TWO PROMETHEANS IN A TRENCHCOAT", + "TOP 10 SECRET AUGMENTS THE GOVERNMENT DOESN'T WANT YOU TO GET", + "ENLARGE YOUR MENTAL FACULTIES WITH THIS 1 WEIRD HAT", + "'HELP, MY SON THINKS HE'S A 20TH CENTURY VID CHARACTER CALLED SPOCK' AND MORE SHOCKING TALES INSIDE", + "18 RADICAL HIP IMPLANTS ALL THE KIDS ARE GETTING!", + "PRESERVED HEAD OF 21ST CENTURY CAPITALIST INSISTS THAT 'DYSON WALL' ONLY SANE SOLUTION TO RIMWARD MALCONTENTS", + "50 SHADES OF GREEN; BESTSELLING MULTISPECIES ROMANCE COMING TO CINEMAS", + "PLUTO: DWARF PLANET, OR SECRET RAMPANT AI FACILITY HELL-BENT ON CORRUPTING YOUR CHILDREN?", + "TOP TEN ANIME ALIENS. NUMBER 3 WILL SICKEN YOU", + "OCTUBER X'RALLBRE EXPOSED; NUDE PHOTOSHOOT LEAKS", + "WAR ON MARS AFTER NAKED MAN WAS FOUND; WERE THE ROMANS RIGHT?", + "REAL ALIENS ARGUE EARTH MOVIES RACIST!", + "HELP! I MARRIED A HEGEMONOUS SWARM INTELLIGENCE AND MY SON THINKS HE'S A ROUTER!", + "POSITRONICS: HUMAN INGENUITY AND GENEROSITY, OR A HORRIBLE MISTAKE? FIND OUT INSIDE!", + "THE FREE TRADER UNION: NEITHER FREE NOR A UNION. SHOCKING EXPOSE!", + "HAS THE FREE MARKET GONE TOO FAR? LUNA GLITTERPOP STAR AUCTIONS THIRD TESTICLE FOR TRANS-ORBITAL SHIPPING BONDS", + "THEY SAID IT WAS CANCER, BUT I KNEW IT WAS A TINY, SELF-REPLICATING CLONE OF RAY KURZWEIL: FULL STORY INSIDE", + "WHAT HAS TECHNOLOGY DONE? INDUSTRY BILLIONAIRE MARRIES OWN INFORMORPH MIND-COPY", + "REPTILLIAN ICE WARRIORS FROM ANOTHER WORLD LIVE INSIDE YOUR AIR DUCTS: HERE'S HOW TO GET RID OF THEM", + "10 CRITICAL THINGS YOU NEED TO KNOW ABOUT 'DRONEGATE'", + "THEY CALL THEM JUMPGATES BUT I'VE NEVER SEEN THEM JUMP: AN INDUSTRY INSIDER SPEAKS FOR THE FIRST TIME", + "EMERGENT INTELLIGENCES ARE STEALING YOUR BANK DETAILS, FETISHES: FOIL HAT RECIPE INSIDE", + "TIME TRAVELLERS ARE STEALING YOUR WIFI: 5 TIPS FOR DEFEATING HACKERS FROM THE FUTURE", + "'My mother was an alien spy': THIS CELEBRITY REVEAL WILL SHOCK AND AMAZE YOU", + "LUMINARY SCIENTIST SPEAKS: DIABETES IS A HYPERCORP RETROVIRUS!", + "'I REROUTED MY NEURAL CIRCUITRY SO THAT PAIN TASTES OF STRAWBERRIES' AND FIFTEEN OTHER CRAZY ALMACH STORIES", + "JOINING THE NAVY? HERE'S 15 EXPERT TIPS FOR AVOIDING BRAIN PARASITES" + ) \ No newline at end of file diff --git a/mods/content/tabloids/_tabloids.dme b/mods/content/tabloids/_tabloids.dme new file mode 100644 index 000000000000..0c6e6e35b01a --- /dev/null +++ b/mods/content/tabloids/_tabloids.dme @@ -0,0 +1,8 @@ +#ifndef CONTENT_PACK_TABLOIDS +#define CONTENT_PACK_TABLOIDS +// BEGIN_INCLUDE +#include "_tabloids.dm" +#include "tabloid.dm" +#include "tabloid_helpers.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/tabloids/icons/magazine.dmi b/mods/content/tabloids/icons/magazine.dmi new file mode 100644 index 000000000000..62b385510c84 Binary files /dev/null and b/mods/content/tabloids/icons/magazine.dmi differ diff --git a/mods/content/tabloids/tabloid.dm b/mods/content/tabloids/tabloid.dm new file mode 100644 index 000000000000..579820aabfab --- /dev/null +++ b/mods/content/tabloids/tabloid.dm @@ -0,0 +1,36 @@ +/obj/item/tabloid + name = "tabloid magazine" + desc = "It's one of those trashy tabloid magazines. It looks pretty out of date." + icon = 'mods/content/tabloids/icons/magazine.dmi' + icon_state = "magazine" + randpixel = 6 + material = /decl/material/solid/organic/paper + matter = list(/decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT) + var/headline + var/article_body + +/obj/item/tabloid/Initialize() + . = ..() + var/list/tabloid_headlines = get_tabloid_headlines() + name = SAFEPICK(get_tabloid_publishers()) || initial(name) + icon_state = SAFEPICK(get_tabloid_states()) || initial(icon_state) + headline = SAFEPICK(tabloid_headlines) + if(length(tabloid_headlines) && tabloid_headlines[headline]) + article_body = tabloid_headlines[headline] + +/obj/item/tabloid/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(headline) + . += "The headline screams, \"[headline]\"" + +/obj/item/tabloid/attack_self(mob/user) + . = ..() + if(!.) + user.visible_message(SPAN_NOTICE("\The [user] leafs idly through \the [src].")) + if(headline) + to_chat(user, "Most of it is the usual tabloid garbage, but the headline story, \"[headline]\", holds your attention for awhile.") + if(article_body) + to_chat(user, article_body) + else + to_chat(user, "It's the usual tabloid garbage. You find nothing of interest.") + return TRUE diff --git a/mods/content/tabloids/tabloid_helpers.dm b/mods/content/tabloids/tabloid_helpers.dm new file mode 100644 index 000000000000..966556dafbed --- /dev/null +++ b/mods/content/tabloids/tabloid_helpers.dm @@ -0,0 +1,24 @@ +// Minor fluff item for mapping in waiting rooms etc. +/proc/get_tabloid_publishers() + var/static/list/tabloid_publishers + if(!tabloid_publishers) + tabloid_publishers = list() + for(var/modpack_name in SSmodpacks.loaded_modpacks) + var/decl/modpack/modpack = SSmodpacks.loaded_modpacks[modpack_name] + if(length(modpack.tabloid_publishers)) + tabloid_publishers |= modpack.tabloid_publishers + return tabloid_publishers + +/proc/get_tabloid_headlines() + var/static/list/tabloid_headlines + if(!tabloid_headlines) + tabloid_headlines = list() + for(var/modpack_name in SSmodpacks.loaded_modpacks) + var/decl/modpack/modpack = SSmodpacks.loaded_modpacks[modpack_name] + if(length(modpack.tabloid_headlines)) + tabloid_headlines |= modpack.tabloid_headlines + return tabloid_headlines + +/proc/get_tabloid_states() + var/static/list/tabloid_states = icon_states('mods/content/tabloids/icons/magazine.dmi') + return tabloid_states diff --git a/mods/content/undead/_undead.dm b/mods/content/undead/_undead.dm new file mode 100644 index 000000000000..37cb87794289 --- /dev/null +++ b/mods/content/undead/_undead.dm @@ -0,0 +1,2 @@ +/decl/modpack/undead + name = "Undead Content" \ No newline at end of file diff --git a/mods/content/undead/_undead.dme b/mods/content/undead/_undead.dme new file mode 100644 index 000000000000..2068815dbd2f --- /dev/null +++ b/mods/content/undead/_undead.dme @@ -0,0 +1,12 @@ +#ifndef MODPACK_UNDEAD +#define MODPACK_UNDEAD +// BEGIN_INCLUDE +#include "_undead.dm" +#include "overrides.dm" +#include "skillset.dm" +#include "traits.dm" +#include "mods\undead.dm" +#include "mods\undead_skeleton.dm" +#include "mods\undead_zombie.dm" +// END_INCLUDE +#endif diff --git a/mods/content/undead/mods/undead.dm b/mods/content/undead/mods/undead.dm new file mode 100644 index 000000000000..a42625998f73 --- /dev/null +++ b/mods/content/undead/mods/undead.dm @@ -0,0 +1,10 @@ +/mob/living/human/get_movement_delay(var/travel_dir) + . = ..() + if(has_trait(/decl/trait/undead)) + set_moving_slowly() + if(istype(default_walk_intent)) + . = max(., default_walk_intent.move_delay) // no runner zombies yet + +// Overridden by fantasy modpack. +/mob/living/human/proc/grant_basic_undead_equipment() + return diff --git a/mods/content/undead/mods/undead_skeleton.dm b/mods/content/undead/mods/undead_skeleton.dm new file mode 100644 index 000000000000..bc39f27a4e52 --- /dev/null +++ b/mods/content/undead/mods/undead_skeleton.dm @@ -0,0 +1,43 @@ +/datum/mob_controller/aggressive/skeleton + +// SKELETONS +// Immune to blind or deaf, but weak to physical damage. +/mob/living/human/proc/make_skeleton() + set_trait(/decl/trait/metabolically_inert, TRAIT_LEVEL_EXISTS) + set_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE) + + if(istype(ai)) + QDEL_NULL(ai) + ai = new /datum/mob_controller/aggressive/skeleton(src) + faction = "undead" + + if(!istype(skillset, /datum/skillset/undead) && !ispath(skillset, /datum/skillset/undead)) + if(istype(skillset)) + QDEL_NULL(skillset) + skillset = new /datum/skillset/undead(src) + + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!BP_IS_PROSTHETIC(limb)) + limb.skeletonize() + + for(var/obj/item/organ/internal/organ in get_internal_organs()) + remove_organ(organ, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE) + qdel(organ) + + set_max_health(round(species.total_health / 3)) + vessel?.clear_reagents() + SET_HAIR_STYLE(src, /decl/sprite_accessory/hair/bald, FALSE) + update_body() + +/mob/living/human/skeleton + skillset = /datum/skillset/undead + +/mob/living/human/skeleton/post_setup(species_uid, datum/mob_snapshot/supplied_appearance) + . = ..() + make_skeleton() + grant_basic_undead_equipment() + +/mob/living/human/skeleton/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/human::uid + . = ..() diff --git a/mods/content/undead/mods/undead_zombie.dm b/mods/content/undead/mods/undead_zombie.dm new file mode 100644 index 000000000000..e5be4b3f4064 --- /dev/null +++ b/mods/content/undead/mods/undead_zombie.dm @@ -0,0 +1,69 @@ +// ZOMBIES +// Dead and rotting, but still mobile and aggressive. + +/datum/mob_controller/aggressive/zombie + +/mob/living/human/proc/make_zombie() + set_trait(/decl/trait/metabolically_inert, TRAIT_LEVEL_EXISTS) + set_trait(/decl/trait/undead, TRAIT_LEVEL_MINOR) + + if(istype(ai)) + QDEL_NULL(ai) + ai = new /datum/mob_controller/aggressive/zombie(src) + faction = "undead" + + if(!istype(skillset, /datum/skillset/undead) && !ispath(skillset, /datum/skillset/undead)) + if(istype(skillset)) + QDEL_NULL(skillset) + skillset = new /datum/skillset/undead(src) + + for(var/obj/item/organ/organ in get_organs()) + organ.die() + organ.germ_level = INFECTION_LEVEL_THREE + + // die() sets to max damage + for(var/obj/item/organ/internal/organ in get_internal_organs()) + organ.set_organ_damage(0) + for(var/obj/item/organ/external/limb in get_internal_organs()) + limb.brute_dam = 0 + limb.burn_dam = 0 + + // Set this so nonhumans look appropriately gross. + reset_hair() + if(get_bodytype()?.appearance_flags & HAS_SKIN_COLOR) + _skin_colour = pick(COLOR_GRAY, COLOR_GRAY15, COLOR_GRAY20, COLOR_GRAY40, COLOR_GRAY80, COLOR_WHITE) + SET_HAIR_COLOR(src, _skin_colour, TRUE) + SET_FACIAL_HAIR_COLOR(src, _skin_colour, TRUE) + + var/obj/item/organ/external/head/head = get_organ(BP_HEAD) + if(istype(head)) + head.glowing_eyes = TRUE + set_eye_colour(COLOR_RED) + + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!BP_IS_PROSTHETIC(limb)) + limb.sync_colour_to_human(src) + if(prob(10)) + limb.skeletonize() + else if(prob(15)) + if(prob(75)) + limb.createwound(CUT, rand(limb.max_damage * 0.25, limb.max_damage * 0.5)) + else + limb.createwound(BURN, rand(limb.max_damage * 0.25, limb.max_damage * 0.5)) + + set_max_health(round(species.total_health / 2)) + vessel.remove_any(REAGENT_TOTAL_VOLUME(vessel) * rand(0.2, 0.5)) + update_body() + +/mob/living/human/zombie + skillset = /datum/skillset/undead + +/mob/living/human/zombie/post_setup(species_uid, datum/mob_snapshot/supplied_appearance) + . = ..() + make_zombie() + grant_basic_undead_equipment() + +/mob/living/human/zombie/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/human::uid + . = ..() diff --git a/mods/content/undead/overrides.dm b/mods/content/undead/overrides.dm new file mode 100644 index 000000000000..38e0a6f9a9a3 --- /dev/null +++ b/mods/content/undead/overrides.dm @@ -0,0 +1,134 @@ +/mob/living/can_feel_pain(var/check_organ) + return !has_trait(/decl/trait/undead) && ..() + +/mob/living/human/get_gibber_type() // To avoid skeletons causing gibs. + return has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE) ? null : ..() + +/mob/living/human/ssd_check() + if(has_trait(/decl/trait/undead)) + return FALSE + return ..() + +/mob/living/human/get_movement_delay(travel_dir) + . = ..() + if(has_trait(/decl/trait/undead)) + var/static/default_walk_delay = get_config_value(/decl/config/num/movement_walk) + . = max(., default_walk_delay) + +/mob/living/human/get_attack_telegraph_delay() + if(has_trait(/decl/trait/undead)) + return (0.6 SECONDS) + return ..() + +/mob/living/human/get_self_death_message(gibbed) + return has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE) ? "You have crumbled." : ..() + +/mob/living/human/get_death_message(gibbed) + if(has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) + return "crumbles and falls apart!" + return ..() + +/mob/living/human/death(gibbed) + . = ..() + if(stat == DEAD && !QDELETED(src) && !gibbed && has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) + gib() + +/mob/living/human/get_eye_colour() + // Force an evil red glow for undead mobs. + if(stat == CONSCIOUS && has_trait(/decl/trait/undead)) + return COLOR_RED + return ..() + +/mob/living/human/death(gibbed) + . = ..() + if(!QDELETED(src) && has_trait(/decl/trait/undead)) + var/obj/item/organ/external/head/head = get_organ(BP_HEAD) + head.glowing_eyes = initial(head.glowing_eyes) + update_eyes() + +/mob/living/human/get_life_damage_types() + if(has_trait(/decl/trait/undead)) + // Undead human mobs use brute and burn damage instead of brain damage, a la simplemobs. + var/static/list/life_damage_types = list( + BURN, + BRUTE + ) + return life_damage_types + return ..() + +/mob/living/human/getOxyLoss(var/amount) + return has_trait(/decl/trait/undead) ? 0 : ..() + +/mob/living/human/setOxyLoss(var/amount) + return has_trait(/decl/trait/undead) ? 0 : ..() + +/mob/living/human/adjustOxyLoss(var/damage, var/do_update_health = TRUE) + return has_trait(/decl/trait/undead) ? 0 : ..() + +/mob/living/human/getToxLoss() + return has_trait(/decl/trait/undead) ? 0 : ..() + +/mob/living/human/setToxLoss(var/amount) + return has_trait(/decl/trait/undead) ? 0 : ..() + +/mob/living/human/adjustToxLoss(var/amount, var/do_update_health = TRUE) + return has_trait(/decl/trait/undead) ? 0 : ..() + +/mob/living/human/check_vital_organ_missing() + return !has_trait(/decl/trait/undead) && ..() + +/mob/living/human/process_internal_organs() + return has_trait(/decl/trait/undead) ? null : ..() + +/mob/living/human/should_have_organ(organ_to_check) + // It might be nice to have eyes etc. matter for zombies, but as all organs are dead it won't work currently. + return has_trait(/decl/trait/undead) ? FALSE : ..() + +/mob/living/human/get_vision_organ_tag() + // Where we're going, we don't need eyes. + return has_trait(/decl/trait/undead) ? null : ..() + +/mob/living/human/need_breathe() + return has_trait(/decl/trait/undead) ? FALSE : ..() + +// Undead don't get hungry/thirsty (except for brains) +/mob/living/human/get_nutrition() + return has_trait(/decl/trait/undead) ? get_max_nutrition() : ..() + +/mob/living/human/get_hydration() + return has_trait(/decl/trait/undead) ? get_max_hydration() : ..() + +// Overrides to handle dead flag separately. +/obj/item/organ/is_usable() + . = !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED)) + if(. && (status & ORGAN_DEAD)) + return owner?.has_trait(/decl/trait/undead) + +/obj/item/organ/external/check_status_flags_for_process() + if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_MUTATED|ORGAN_DISLOCATED)) + return TRUE + if((status & ORGAN_DEAD) && !owner?.has_trait(/decl/trait/undead)) + return TRUE + return FALSE + +/mob/living/human/set_status_condition(condition, amount) + if(has_trait(/decl/trait/undead)) + var/static/list/ignore_status_conditions = list( + STAT_BLIND, + STAT_DEAF, + STAT_CONFUSE, + STAT_DIZZY, + STAT_JITTER, + STAT_STUTTER, + STAT_SLUR, + STAT_ASLEEP, + STAT_DRUGGY, + STAT_DROWSY, + STAT_BLURRY, + STAT_BLIND, + STAT_TINNITUS, + STAT_DEAF + ) + if(condition in ignore_status_conditions) + return + . = ..() diff --git a/mods/content/undead/skillset.dm b/mods/content/undead/skillset.dm new file mode 100644 index 000000000000..479d7cfe5505 --- /dev/null +++ b/mods/content/undead/skillset.dm @@ -0,0 +1,2 @@ +/datum/skillset/undead + default_value = SKILL_BASIC diff --git a/mods/content/undead/traits.dm b/mods/content/undead/traits.dm new file mode 100644 index 000000000000..06d4f34e9572 --- /dev/null +++ b/mods/content/undead/traits.dm @@ -0,0 +1,4 @@ +/decl/trait/undead + name = "Undead" + description = "Your body is dead, but remains animated through some supernatural force." + levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MODERATE) // Moderate means skeleton, minor means zombie. diff --git a/mods/content/ventcrawl/_ventcrawl.dm b/mods/content/ventcrawl/_ventcrawl.dm new file mode 100644 index 000000000000..39e8885300d7 --- /dev/null +++ b/mods/content/ventcrawl/_ventcrawl.dm @@ -0,0 +1,3 @@ +/decl/modpack/ventcrawl + name = "Ventcrawling" + desc = "Adds the ability for certain mobs to crawl through vents and scrubbers and travel through pipe networks." \ No newline at end of file diff --git a/mods/content/ventcrawl/_ventcrawl.dme b/mods/content/ventcrawl/_ventcrawl.dme new file mode 100644 index 000000000000..4427041cd805 --- /dev/null +++ b/mods/content/ventcrawl/_ventcrawl.dme @@ -0,0 +1,12 @@ +#ifndef CONTENT_PACK_VENTCRAWL +#define CONTENT_PACK_VENTCRAWL +// BEGIN_INCLUDE +#include "_ventcrawl.dm" +#include "mob_overrides.dm" +#include "species_overrides.dm" +#include "ventcrawl_atmospherics.dm" +#include "ventcrawl_mob.dm" +#include "ventcrawl_multiz.dm" +#include "ventcrawl_verb.dm" +// END_INCLUDE +#endif diff --git a/mods/content/ventcrawl/mob_overrides.dm b/mods/content/ventcrawl/mob_overrides.dm new file mode 100644 index 000000000000..f75b523b1798 --- /dev/null +++ b/mods/content/ventcrawl/mob_overrides.dm @@ -0,0 +1,11 @@ +/mob/living/simple_animal/alien/Initialize() + . = ..() + verbs += /mob/living/proc/ventcrawl + +/mob/living/simple_animal/opossum/Initialize() + . = ..() + verbs += /mob/living/proc/ventcrawl + +/mob/living/simple_animal/passive/mouse/Initialize() + . = ..() + verbs += /mob/living/proc/ventcrawl diff --git a/mods/content/ventcrawl/species_overrides.dm b/mods/content/ventcrawl/species_overrides.dm new file mode 100644 index 000000000000..6516ab3f9e24 --- /dev/null +++ b/mods/content/ventcrawl/species_overrides.dm @@ -0,0 +1,2 @@ +/decl/species/monkey + inherent_verbs = list(/mob/living/proc/ventcrawl) \ No newline at end of file diff --git a/mods/content/ventcrawl/ventcrawl_atmospherics.dm b/mods/content/ventcrawl/ventcrawl_atmospherics.dm new file mode 100644 index 000000000000..1399a9df5b18 --- /dev/null +++ b/mods/content/ventcrawl/ventcrawl_atmospherics.dm @@ -0,0 +1,64 @@ +/obj/machinery/atmospherics/var/image/pipe_image + +/obj/machinery/atmospherics/Destroy() + for(var/mob/living/M in src) //ventcrawling is serious business + M.remove_ventcrawl() + M.dropInto(loc) + if(pipe_image) + for(var/mob/living/M in global.player_list) + if(M.client) + M.client.images -= pipe_image + LAZYREMOVE(M.pipes_shown, pipe_image) + pipe_image = null + . = ..() + +/obj/machinery/atmospherics/relaymove(mob/living/user, direction) + if(user.loc != src || !(direction & initialize_directions)) //can't go in a way we aren't connecting to + return + + // Only cardinals allowed. + direction = FIRST_DIR(direction) + ventcrawl_to(user,findConnecting(direction), direction) + +/obj/machinery/atmospherics/proc/ventcrawl_to(var/mob/living/user, var/obj/machinery/atmospherics/target_move, var/direction) + if(target_move) + if(is_type_in_list(target_move, ventcrawl_machinery) && target_move.can_crawl_through()) + user.remove_ventcrawl() + user.forceMove(target_move.loc) //handles entering and so on + user.visible_message("You hear something squeezing through the ducts.", "You climb out the ventilation system.") + else if(target_move.can_crawl_through()) + if(target_move.return_network(target_move) != return_network(src)) + user.remove_ventcrawl() + user.add_ventcrawl(target_move) + user.forceMove(target_move) + user.client.eye = target_move //if we don't do this, Byond only updates the eye every tick - required for smooth movement + if(world.time > user.next_play_vent) + user.next_play_vent = world.time+30 + playsound(src, 'sound/machines/ventcrawl.ogg', 50, 1, -3) + else + if((direction & initialize_directions) || is_type_in_list(src, ventcrawl_machinery) && src.can_crawl_through()) //if we move in a way the pipe can connect, but doesn't - or we're in a vent + user.remove_ventcrawl() + user.forceMove(src.loc) + user.visible_message("You hear something squeezing through the pipes.", "You climb out the ventilation system.") + user.SetMoveCooldown(user.get_movement_delay(direction)) + +/obj/machinery/atmospherics/proc/can_crawl_through() + return 1 + +/obj/machinery/atmospherics/unary/vent_pump/can_crawl_through() + return !welded + +/obj/machinery/atmospherics/unary/vent_scrubber/can_crawl_through() + return !welded + +/obj/machinery/atmospherics/proc/findConnecting(var/direction) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + if(isConnectable(target) && target.isConnectable(src)) + return target + +/obj/machinery/atmospherics/proc/isConnectable(var/obj/machinery/atmospherics/target) + return (target in nodes_to_networks) + +/obj/machinery/atmospherics/valve/isConnectable() + return (open && ..()) diff --git a/mods/content/ventcrawl/ventcrawl_mob.dm b/mods/content/ventcrawl/ventcrawl_mob.dm new file mode 100644 index 000000000000..c5df94dd2da4 --- /dev/null +++ b/mods/content/ventcrawl/ventcrawl_mob.dm @@ -0,0 +1,161 @@ +var/global/list/ventcrawl_machinery = list( + /obj/machinery/atmospherics/unary/vent_scrubber, + /obj/machinery/atmospherics/unary/vent_pump + ) + +// Vent crawling whitelisted items, whoo +/mob/living/var/list/can_enter_vent_with = list( + /mob, + /obj/item/implant, + /obj/item/radio/borg, + /obj/item/holder, + /obj/machinery/camera, + /obj/item/paper + ) + +/mob/living + var/list/image/pipes_shown + var/is_ventcrawling = FALSE + var/next_play_vent = 0 + +/mob/living/proc/can_ventcrawl() + if(!client) + return FALSE + if(!(/mob/living/proc/ventcrawl in verbs)) + to_chat(src, SPAN_WARNING("You don't possess the ability to ventcrawl!")) + return FALSE + if(incapacitated()) + to_chat(src, SPAN_WARNING("You cannot ventcrawl in your current state!")) + return FALSE + return ventcrawl_carry() + +/mob/living/proc/is_allowed_vent_crawl_item(var/obj/item/carried_item) + if(is_type_in_list(carried_item, can_enter_vent_with) && !get_equipped_slot_for_item(carried_item)) + return TRUE + return (carried_item in get_internal_organs()) + +/mob/living/human/is_allowed_vent_crawl_item(var/obj/item/carried_item) + var/obj/item/organ/internal/stomach = GET_INTERNAL_ORGAN(src, BP_STOMACH) + if(stomach && (carried_item in stomach.contents)) + return TRUE + if(carried_item in get_external_organs()) + return TRUE + var/slot = get_equipped_slot_for_item(carried_item) + var/static/allowed_inventory_slots = list(slot_w_uniform_str, slot_gloves_str, slot_glasses_str, slot_wear_mask_str, slot_l_ear_str, slot_r_ear_str, slot_belt_str, slot_l_store_str, slot_r_store_str) + if(slot in allowed_inventory_slots) + return TRUE + else if (slot || (carried_item in get_held_items()) || (carried_item in worn_underwear)) + return carried_item.w_class <= ITEM_SIZE_NORMAL + return ..() + +/mob/living/proc/ventcrawl_carry() + for(var/atom/A in contents) + if(!is_allowed_vent_crawl_item(A)) + to_chat(src, SPAN_WARNING("You can't carry \the [A] while ventcrawling!")) + return FALSE + return TRUE + +/mob/living/AltClickOn(var/atom/A) + if(is_type_in_list(A,ventcrawl_machinery)) + handle_ventcrawl(A) + return 1 + return ..() + +/mob/proc/start_ventcrawl() + var/atom/pipe + var/list/pipes = list() + for(var/obj/machinery/atmospherics/unary/U in range(1)) + if(is_type_in_list(U,ventcrawl_machinery) && Adjacent(U) && U.can_crawl_through()) + pipes |= U + if(!LAZYLEN(pipes)) + to_chat(src, "There are no pipes that you can ventcrawl into within range!") + return + if(pipes.len == 1) + pipe = pipes[1] + else + pipe = input("Crawl Through Vent", "Pick a pipe") as null|anything in pipes + if(!is_physically_disabled() && pipe) + return pipe + +/mob/living/proc/handle_ventcrawl(var/atom/clicked_on) + + if(!can_ventcrawl()) + return + + var/obj/machinery/atmospherics/unary/vent_found = clicked_on + if(!istype(vent_found) || !vent_found.can_crawl_through() || !Adjacent(vent_found)) + vent_found = null + for(var/obj/machinery/atmospherics/unary/machine in range(1,src)) + if(!Adjacent(machine)) + continue + if(!is_type_in_list(machine, ventcrawl_machinery)) + continue + if(!machine.can_crawl_through()) + continue + vent_found = machine + break + + if(!vent_found) + to_chat(src, "You must be standing on or beside an air vent to enter it.") + return + + var/datum/pipe_network/network = vent_found.network_in_dir(vent_found.dir) + if(!network || (!length(network.normal_members) && !length(network.line_members))) + to_chat(src, "This vent is not connected to anything.") + return + + to_chat(src, "You begin climbing into the ventilation system...") + if(vent_found.air_contents && !issilicon(src)) + switch(vent_found.air_contents.temperature) + if(0 to BODYTEMP_COLD_DAMAGE_LIMIT) + to_chat(src, SPAN_DANGER("You feel a painful freeze coming from the vent!")) + if(BODYTEMP_COLD_DAMAGE_LIMIT to T0C) + to_chat(src, SPAN_WARNING("You feel an icy chill coming from the vent.")) + if(T0C + 40 to BODYTEMP_HEAT_DAMAGE_LIMIT) + to_chat(src, SPAN_WARNING("You feel a hot wash coming from the vent.")) + if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY) + to_chat(src, SPAN_DANGER("You feel a searing heat coming from the vent!")) + switch(vent_found.air_contents.return_pressure()) + if(0 to HAZARD_LOW_PRESSURE) + to_chat(src, SPAN_DANGER("You feel a rushing draw pulling you into the vent!")) + if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) + to_chat(src, SPAN_WARNING("You feel a strong drag pulling you into the vent.")) + if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) + to_chat(src, SPAN_WARNING("You feel a strong current pushing you away from the vent.")) + if(HAZARD_HIGH_PRESSURE to INFINITY) + to_chat(src, SPAN_DANGER("You feel a roaring wind pushing you away from the vent!")) + + if(!do_after(src, 45, vent_found, 1, 1) || !can_ventcrawl()) + return + + visible_message("\The [src] scrambles into the ventilation ducts!", "You climb into the ventilation system.") + forceMove(vent_found) + add_ventcrawl(vent_found) + +/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/starting_machine) + is_ventcrawling = TRUE + //candrop = 0 + var/datum/pipe_network/network = starting_machine.return_network(starting_machine) + if(!network) + return + for(var/datum/pipeline/pipeline in network.line_members) + for(var/obj/machinery/atmospherics/A in (pipeline.members || pipeline.edges)) + if(!A.pipe_image) + A.pipe_image = emissive_overlay(icon = A, loc = A.loc, dir = A.dir) + LAZYDISTINCTADD(pipes_shown, A.pipe_image) + client.images += A.pipe_image + +/mob/living/proc/remove_ventcrawl() + is_ventcrawling = FALSE + if(client) + for(var/image/current_image in pipes_shown) + client.images -= current_image + client.eye = src + LAZYCLEARLIST(pipes_shown) + +/mob/living/Login() + . = ..() + //login during ventcrawl + if(is_ventcrawling && istype(loc, /obj/machinery/atmospherics)) //attach us back into the pipes + remove_ventcrawl() + add_ventcrawl(loc) \ No newline at end of file diff --git a/code/modules/ventcrawl/ventcrawl_multiz.dm b/mods/content/ventcrawl/ventcrawl_multiz.dm similarity index 86% rename from code/modules/ventcrawl/ventcrawl_multiz.dm rename to mods/content/ventcrawl/ventcrawl_multiz.dm index 87ef8f9ba70f..f36cacbe0a4e 100644 --- a/code/modules/ventcrawl/ventcrawl_multiz.dm +++ b/mods/content/ventcrawl/ventcrawl_multiz.dm @@ -15,10 +15,6 @@ if(target) ventcrawl_to(usr, target, DOWN) /obj/machinery/atmospherics/pipe/zpipe/proc/check_ventcrawl(var/turf/target) - if(!istype(target)) - return - if(node1 in target) - return node1 - if(node2 in target) - return node2 - return \ No newline at end of file + for(var/node in nodes_to_networks) + if(node in target) + return node \ No newline at end of file diff --git a/code/modules/ventcrawl/ventcrawl_verb.dm b/mods/content/ventcrawl/ventcrawl_verb.dm similarity index 100% rename from code/modules/ventcrawl/ventcrawl_verb.dm rename to mods/content/ventcrawl/ventcrawl_verb.dm diff --git a/mods/content/xenobiology/_xenobiology.dm b/mods/content/xenobiology/_xenobiology.dm new file mode 100644 index 000000000000..d34306165c6b --- /dev/null +++ b/mods/content/xenobiology/_xenobiology.dm @@ -0,0 +1,8 @@ +#define isslime(X) istype(X, /mob/living/slime) + +/decl/modpack/xenobiology + name = "Xenobiology" + +/decl/modpack/xenobiology/initialize() + . = ..() + SSmodpacks.default_submap_blacklisted_species += /decl/species/golem::uid diff --git a/mods/content/xenobiology/_xenobiology.dme b/mods/content/xenobiology/_xenobiology.dme new file mode 100644 index 000000000000..a2d03305ef6a --- /dev/null +++ b/mods/content/xenobiology/_xenobiology.dme @@ -0,0 +1,58 @@ +#ifndef CONTENT_PACK_XENOBIO +#define CONTENT_PACK_XENOBIO +// BEGIN_INCLUDE +#include "_xenobiology.dm" +#include "achievement.dm" +#include "emotes.dm" +#include "food.dm" +#include "overrides.dm" +#include "colours\_colour.dm" +#include "colours\colour_adamantine.dm" +#include "colours\colour_black.dm" +#include "colours\colour_blue.dm" +#include "colours\colour_cerulean.dm" +#include "colours\colour_dark_blue.dm" +#include "colours\colour_dark_purple.dm" +#include "colours\colour_gold.dm" +#include "colours\colour_green.dm" +#include "colours\colour_grey.dm" +#include "colours\colour_light_pink.dm" +#include "colours\colour_metal.dm" +#include "colours\colour_oil.dm" +#include "colours\colour_orange.dm" +#include "colours\colour_pink.dm" +#include "colours\colour_purple.dm" +#include "colours\colour_pyrite.dm" +#include "colours\colour_quantum.dm" +#include "colours\colour_rainbow.dm" +#include "colours\colour_red.dm" +#include "colours\colour_sepia.dm" +#include "colours\colour_silver.dm" +#include "colours\colour_yellow.dm" +#include "mobs\critter_slime.dm" +#include "mobs\slime_feeding_helpers.dm" +#include "slime\_slime.dm" +#include "slime\death.dm" +#include "slime\examine.dm" +#include "slime\feeding.dm" +#include "slime\items.dm" +#include "slime\items_cell.dm" +#include "slime\items_extract_enhancer.dm" +#include "slime\items_potion.dm" +#include "slime\items_steroid.dm" +#include "slime\life.dm" +#include "slime\powers.dm" +#include "slime\say.dm" +#include "slime\slime_AI.dm" +#include "slime\slime_click.dm" +#include "slime\slime_codex.dm" +#include "slime\slime_commands.dm" +#include "slime\slime_comments.dm" +#include "slime\slime_follow.dm" +#include "slime\slime_reagents.dm" +#include "slime\slime_surgery.dm" +#include "slime\slime_update_icon.dm" +#include "species\golem.dm" +#include "species\golem_organs.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/content/xenobiology/achievement.dm b/mods/content/xenobiology/achievement.dm new file mode 100644 index 000000000000..c162e4d7fb6a --- /dev/null +++ b/mods/content/xenobiology/achievement.dm @@ -0,0 +1,5 @@ +/datum/goal/achievement/dont_let_slime_snack_you + success = TRUE + failable = TRUE + description = "You're feeling extra careful today. Don't let a slime snack on you." + failure_message = "You feel sticky and miserable." diff --git a/mods/content/xenobiology/colours/_colour.dm b/mods/content/xenobiology/colours/_colour.dm new file mode 100644 index 000000000000..c5de84b8fbe1 --- /dev/null +++ b/mods/content/xenobiology/colours/_colour.dm @@ -0,0 +1,55 @@ +/decl/slime_colour + var/name + var/min_children = 4 + var/max_children = 4 + var/list/descendants = list() + var/child_type = /mob/living/slime + var/baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby.dmi' + var/adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult.dmi' + var/mood_icon = 'mods/content/xenobiology/icons/slimes/slime_faces.dmi' + var/extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract.dmi' + var/reaction_sound = 'sound/effects/bubbles.ogg' + var/list/reaction_strings = list() + var/list/reaction_procs = list( + /decl/material/liquid/blood = /decl/slime_colour/proc/try_blood_reaction, + /decl/material/solid/metal/uranium = /decl/slime_colour/proc/try_uranium_reaction + ) + +/decl/slime_colour/proc/handle_reaction(var/datum/reagents/holder) + + . = FALSE + if(!istype(holder)) + return + + var/obj/item/slime_extract/core = holder.get_reaction_loc() + if(!istype(core) || core.Uses <= 0) + return + + var/holder_volumes = REAGENT_VOLUMES(holder) + for(var/decl/material/reagent as anything in holder_volumes) + if(holder_volumes[reagent] < 1) + continue + var/call_proc = reaction_procs[reagent] + if(call_proc && call(src, call_proc)(holder)) + holder.remove_reagent(reagent, holder_volumes[reagent]) + . = TRUE + break + + if(. && holder.get_reaction_loc()) + if(reaction_sound) + playsound(get_turf(holder.get_reaction_loc()), reaction_sound, 75, 1) + if(!QDELETED(core)) + core.Uses-- + if(core.Uses <= 0) + core.visible_message(SPAN_NOTICE("[html_icon(core)] \The [core]'s power is consumed in the reaction.")) + core.SetName("used slime extract") + core.desc = "This extract has been used up." + +/decl/slime_colour/proc/try_blood_reaction(var/datum/reagents/holder) + return handle_blood_reaction(holder) +/decl/slime_colour/proc/handle_blood_reaction(var/datum/reagents/holder) + return FALSE +/decl/slime_colour/proc/try_uranium_reaction(var/datum/reagents/holder) + return handle_uranium_reaction(holder) +/decl/slime_colour/proc/handle_uranium_reaction(var/datum/reagents/holder) + return FALSE \ No newline at end of file diff --git a/mods/content/xenobiology/colours/colour_adamantine.dm b/mods/content/xenobiology/colours/colour_adamantine.dm new file mode 100644 index 000000000000..1e4619298d93 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_adamantine.dm @@ -0,0 +1,20 @@ +/decl/slime_colour/adamantine + name = "adamantine" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_adamantine.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_adamantine.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_adamantine.dmi' + reaction_strings = list( + /decl/material/liquid/blood = "Synthesies some crystallizing agent.", + /decl/material/solid/metal/uranium = "Create a rune that will allow ghosts to join as loyal golems." + ) + +/decl/slime_colour/adamantine/handle_blood_reaction(var/datum/reagents/holder) + holder.add_reagent(/decl/material/liquid/crystal_agent, 10) + return TRUE + +/decl/slime_colour/adamantine/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + var/obj/effect/golemrune/Z = new(location) + Z.announce_to_ghosts() + return TRUE diff --git a/mods/content/xenobiology/colours/colour_black.dm b/mods/content/xenobiology/colours/colour_black.dm new file mode 100644 index 000000000000..9cc69109ec1d --- /dev/null +++ b/mods/content/xenobiology/colours/colour_black.dm @@ -0,0 +1,5 @@ +/decl/slime_colour/black + name = "black" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_black.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_black.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_black.dmi' diff --git a/mods/content/xenobiology/colours/colour_blue.dm b/mods/content/xenobiology/colours/colour_blue.dm new file mode 100644 index 000000000000..bca57549dd1f --- /dev/null +++ b/mods/content/xenobiology/colours/colour_blue.dm @@ -0,0 +1,16 @@ +/decl/slime_colour/blue + name = "blue" + descendants = list( + /decl/slime_colour/dark_blue, + /decl/slime_colour/silver, + /decl/slime_colour/pink, + /decl/slime_colour/pink + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_blue.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_blue.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_blue.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a small amount of frost oil.") + +/decl/slime_colour/blue/handle_uranium_reaction(var/datum/reagents/holder) + holder.add_reagent(/decl/material/liquid/frostoil, 10) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_cerulean.dm b/mods/content/xenobiology/colours/colour_cerulean.dm new file mode 100644 index 000000000000..0062feab471b --- /dev/null +++ b/mods/content/xenobiology/colours/colour_cerulean.dm @@ -0,0 +1,12 @@ +/decl/slime_colour/cerulean + name = "cerulean" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_cerulean.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_cerulean.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_cerulean.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a steroid that can enhance a slime core to have three uses.") + +/decl/slime_colour/cerulean/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/slime_extract_enhancer(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_dark_blue.dm b/mods/content/xenobiology/colours/colour_dark_blue.dm new file mode 100644 index 000000000000..7d07e6b1cece --- /dev/null +++ b/mods/content/xenobiology/colours/colour_dark_blue.dm @@ -0,0 +1,22 @@ +/decl/slime_colour/dark_blue + name = "dark blue" + descendants = list( + /decl/slime_colour/purple, + /decl/slime_colour/cerulean, + /decl/slime_colour/blue, + /decl/slime_colour/blue + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_darkblue.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_darkblue.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_darkblue.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Drastically lowers the bodytemperature of surrounding creatures.") + +/decl/slime_colour/dark_blue/handle_uranium_reaction(var/datum/reagents/holder) + . = TRUE + sleep(5 SECONDS) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + playsound(location, 'sound/effects/phasein.ogg', 100, 1) + for(var/mob/living/M in range(location, 7)) + M.bodytemperature -= 140 + to_chat(M, SPAN_WARNING("You feel a chill!")) diff --git a/mods/content/xenobiology/colours/colour_dark_purple.dm b/mods/content/xenobiology/colours/colour_dark_purple.dm new file mode 100644 index 000000000000..c619674b2f85 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_dark_purple.dm @@ -0,0 +1,18 @@ +/decl/slime_colour/dark_purple + name = "dark purple" + descendants = list( + /decl/slime_colour/purple, + /decl/slime_colour/sepia, + /decl/slime_colour/orange, + /decl/slime_colour/orange + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_darkpurple.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_darkpurple.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_darkpurple.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises some metallic hydrogen.") + +/decl/slime_colour/dark_purple/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + SSmaterials.create_object(/decl/material/solid/metallic_hydrogen, location, 10, /obj/item/stack/material/cubes) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_gold.dm b/mods/content/xenobiology/colours/colour_gold.dm new file mode 100644 index 000000000000..a6c7eeb25375 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_gold.dm @@ -0,0 +1,29 @@ +/decl/slime_colour/gold + name = "gold" + descendants = list( + /decl/slime_colour/gold, + /decl/slime_colour/gold, + /decl/slime_colour/adamantine, + /decl/slime_colour/adamantine + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_gold.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_gold.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_gold.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a cute critter.") + var/list/possible_mobs = list( + /mob/living/simple_animal/passive/cat, + /mob/living/simple_animal/passive/cat/kitten, + /mob/living/simple_animal/corgi, + /mob/living/simple_animal/corgi/puppy, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/chick, + /mob/living/simple_animal/fowl/chicken, + /mob/living/simple_animal/fowl/duck + ) + +/decl/slime_colour/gold/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + var/mob_type = pick(possible_mobs) + new mob_type(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_green.dm b/mods/content/xenobiology/colours/colour_green.dm new file mode 100644 index 000000000000..a9c48881a5a7 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_green.dm @@ -0,0 +1,11 @@ +/decl/slime_colour/green + name = "green" + descendants = list( + /decl/slime_colour/green, + /decl/slime_colour/green, + /decl/slime_colour/black, + /decl/slime_colour/black + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_green.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_green.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_green.dmi' diff --git a/mods/content/xenobiology/colours/colour_grey.dm b/mods/content/xenobiology/colours/colour_grey.dm new file mode 100644 index 000000000000..86c41ec83eca --- /dev/null +++ b/mods/content/xenobiology/colours/colour_grey.dm @@ -0,0 +1,26 @@ +/decl/slime_colour/grey + name = "grey" + descendants = list( + /decl/slime_colour/orange, + /decl/slime_colour/metal, + /decl/slime_colour/blue, + /decl/slime_colour/purple + ) + reaction_strings = list( + /decl/material/liquid/blood = "Synthesises some monkey cubes.", + /decl/material/solid/metal/uranium = "Revives a baby slime from a core." + ) + +/decl/slime_colour/grey/handle_blood_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + for(var/i = 1, i <= 3, i++) + new /obj/item/food/animal_cube/monkey(location) + return TRUE + +/decl/slime_colour/grey/handle_uranium_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(istype(location)) + location.visible_message(SPAN_WARNING("The core begins to quiver and grow, and soon a new baby slime emerges from it!")) + new /mob/living/slime(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_light_pink.dm b/mods/content/xenobiology/colours/colour_light_pink.dm new file mode 100644 index 000000000000..5aceee852b08 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_light_pink.dm @@ -0,0 +1,12 @@ +/decl/slime_colour/light_pink + name = "light pink" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_lightpink.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_lightpink.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_lightpink.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a potion that turns an adult slime into a docile pet.") + +/decl/slime_colour/light_pink/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/slime_potion/advanced(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_metal.dm b/mods/content/xenobiology/colours/colour_metal.dm new file mode 100644 index 000000000000..c100aa7bb4d2 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_metal.dm @@ -0,0 +1,19 @@ +/decl/slime_colour/metal + name = "metal" + descendants = list( + /decl/slime_colour/silver, + /decl/slime_colour/yellow, + /decl/slime_colour/gold, + /decl/slime_colour/gold + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_metal.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_metal.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_metal.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises cubes of steel and plasteel.") + +/decl/slime_colour/metal/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + SSmaterials.create_object(/decl/material/solid/metal/steel, location, 15, /obj/item/stack/material/cubes) + SSmaterials.create_object(/decl/material/solid/metal/plasteel, location, 5, /obj/item/stack/material/cubes) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_oil.dm b/mods/content/xenobiology/colours/colour_oil.dm new file mode 100644 index 000000000000..13d418033d7d --- /dev/null +++ b/mods/content/xenobiology/colours/colour_oil.dm @@ -0,0 +1,13 @@ +/decl/slime_colour/oil + name = "oil" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_oil.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_oil.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_oil.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Causes a violent explosion after a few seconds. Run!") + +/decl/slime_colour/oil/handle_uranium_reaction(var/datum/reagents/holder) + . = TRUE + sleep(5 SECONDS) + var/location = holder.get_reaction_loc() + if(location) + explosion(location, 1, 3, 6) diff --git a/mods/content/xenobiology/colours/colour_orange.dm b/mods/content/xenobiology/colours/colour_orange.dm new file mode 100644 index 000000000000..060bf4ffcf1c --- /dev/null +++ b/mods/content/xenobiology/colours/colour_orange.dm @@ -0,0 +1,27 @@ +/decl/slime_colour/orange + name = "orange" + descendants = list( + /decl/slime_colour/dark_purple, + /decl/slime_colour/yellow, + /decl/slime_colour/red, + /decl/slime_colour/red + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_orange.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_orange.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_orange.dmi' + reaction_strings = list( + /decl/material/liquid/blood = "Synthesises a small amount of capsaicin.", + /decl/material/solid/metal/uranium = "Causes a violent conflagration after a few seconds. Run!" + ) + +/decl/slime_colour/orange/handle_blood_reaction(var/datum/reagents/holder) + holder.add_reagent(/decl/material/liquid/capsaicin, 10) + return TRUE + +/decl/slime_colour/orange/handle_uranium_reaction(var/datum/reagents/holder) + . = TRUE + sleep(5 SECONDS) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + location.assume_gas(/decl/material/gas/hydrogen, 250, 1400) + location.hotspot_expose(700, 400) diff --git a/mods/content/xenobiology/colours/colour_pink.dm b/mods/content/xenobiology/colours/colour_pink.dm new file mode 100644 index 000000000000..6a03de1fb22b --- /dev/null +++ b/mods/content/xenobiology/colours/colour_pink.dm @@ -0,0 +1,18 @@ +/decl/slime_colour/pink + name = "pink" + descendants = list( + /decl/slime_colour/pink, + /decl/slime_colour/pink, + /decl/slime_colour/light_pink, + /decl/slime_colour/light_pink + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_pink.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_pink.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_pink.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium ="Synthesises a potion that turns a baby slime into a docile pet.") + +/decl/slime_colour/pink/handle_uranium_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/slime_potion(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_purple.dm b/mods/content/xenobiology/colours/colour_purple.dm new file mode 100644 index 000000000000..8a839ba167f3 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_purple.dm @@ -0,0 +1,18 @@ +/decl/slime_colour/purple + name = "purple" + descendants = list( + /decl/slime_colour/dark_purple, + /decl/slime_colour/dark_blue, + /decl/slime_colour/green, + /decl/slime_colour/green + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_purple.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_purple.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_purple.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a steroid capable of causing a slime to create additional slime cores.") + +/decl/slime_colour/purple/handle_uranium_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/slime_steroid(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_pyrite.dm b/mods/content/xenobiology/colours/colour_pyrite.dm new file mode 100644 index 000000000000..739ba7a8910e --- /dev/null +++ b/mods/content/xenobiology/colours/colour_pyrite.dm @@ -0,0 +1,12 @@ +/decl/slime_colour/pyrite + name = "pyrite" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_pyrite.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_pyrite.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_pyrite.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a random bucket of paint.") + +/decl/slime_colour/pyrite/handle_uranium_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/chems/glass/bucket/paint/random(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_quantum.dm b/mods/content/xenobiology/colours/colour_quantum.dm new file mode 100644 index 000000000000..eb249750c322 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_quantum.dm @@ -0,0 +1,17 @@ +/decl/slime_colour/quantum + name = "quantum" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_quantum.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_quantum.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_quantum.dmi' + reaction_sound = 'sound/effects/teleport.ogg' + reaction_strings = list(/decl/material/solid/metal/uranium = "Randomly teleports everything around the core.") + +/decl/slime_colour/quantum/handle_uranium_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + var/list/turfs = RANGE_TURFS(location, 6) + if(length(turfs)) + for(var/atom/movable/AM in viewers(location, 2)) + if(AM.simulated && !AM.anchored) + AM.dropInto(pick(turfs)) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_rainbow.dm b/mods/content/xenobiology/colours/colour_rainbow.dm new file mode 100644 index 000000000000..15770d3e63c1 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_rainbow.dm @@ -0,0 +1,5 @@ +/decl/slime_colour/rainbow + name = "rainbow" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_rainbow.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_rainbow.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_rainbow.dmi' diff --git a/mods/content/xenobiology/colours/colour_red.dm b/mods/content/xenobiology/colours/colour_red.dm new file mode 100644 index 000000000000..fdb702c97c32 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_red.dm @@ -0,0 +1,22 @@ +/decl/slime_colour/red + name = "red" + descendants = list( + /decl/slime_colour/red, + /decl/slime_colour/red, + /decl/slime_colour/oil, + /decl/slime_colour/oil + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_red.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_red.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_red.dmi' + reaction_strings = list(/decl/material/liquid/blood = "Causes all nearby slimes to enter a berserk rage.") + +/decl/slime_colour/red/handle_blood_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + for(var/mob/living/slime/slime in viewers(location, 7)) + var/datum/mob_controller/slime/slime_ai = slime.ai + if(istype(slime_ai)) + slime_ai.rabid = TRUE + slime.visible_message(SPAN_DANGER("\The [slime] is driven into a frenzy!")) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_sepia.dm b/mods/content/xenobiology/colours/colour_sepia.dm new file mode 100644 index 000000000000..644c228fb936 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_sepia.dm @@ -0,0 +1,22 @@ +/decl/slime_colour/sepia + name = "sepia" + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_sepia.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_sepia.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_sepia.dmi' + reaction_strings = list( + /decl/material/liquid/blood = "Synthesises a camera film refill.", + /decl/material/solid/metal/uranium = "Synthesises a camera." + ) + +/decl/slime_colour/sepia/handle_blood_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + for(var/i in 1 to 5) + new /obj/item/camera_film(location) + return TRUE + +/decl/slime_colour/sepia/handle_uranium_reaction(var/datum/reagents/holder) + var/turf/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/camera(location) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_silver.dm b/mods/content/xenobiology/colours/colour_silver.dm new file mode 100644 index 000000000000..7af6b826cab9 --- /dev/null +++ b/mods/content/xenobiology/colours/colour_silver.dm @@ -0,0 +1,29 @@ +/decl/slime_colour/silver + name = "silver" + descendants = list( + /decl/slime_colour/metal, + /decl/slime_colour/pyrite, + /decl/slime_colour/blue, + /decl/slime_colour/blue + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_silver.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_silver.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_silver.dmi' + reaction_strings = list(/decl/material/solid/metal/uranium = "Synthesises a large amount of food.") + var/static/list/borks = subtypesof(/obj/item/food) + +/decl/slime_colour/silver/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + playsound(location, 'sound/effects/phasein.ogg', 100, 1) + for(var/mob/living/human/M in viewers(location, null)) + if(M.eyecheck() < FLASH_PROTECTION_MODERATE) + M.flash_eyes() + for(var/i in 1 to (4 + rand(1, 2))) + var/chosen = pick(borks) + var/obj/B = new chosen(location) + if(B) + if(prob(50)) + for(var/j in 1 to rand(1, 3)) + step(B, pick(NORTH, SOUTH, EAST, WEST)) + return TRUE diff --git a/mods/content/xenobiology/colours/colour_yellow.dm b/mods/content/xenobiology/colours/colour_yellow.dm new file mode 100644 index 000000000000..e19a5477099c --- /dev/null +++ b/mods/content/xenobiology/colours/colour_yellow.dm @@ -0,0 +1,40 @@ +/decl/slime_colour/yellow + name = "yellow" + descendants = list( + /decl/slime_colour/quantum, + /decl/slime_colour/metal, + /decl/slime_colour/orange, + /decl/slime_colour/orange + ) + baby_icon = 'mods/content/xenobiology/icons/slimes/slime_baby_yellow.dmi' + adult_icon = 'mods/content/xenobiology/icons/slimes/slime_adult_yellow.dmi' + extract_icon = 'mods/content/xenobiology/icons/slimes/slime_extract_yellow.dmi' + reaction_strings = list( + /decl/material/liquid/blood = "Causes a localized electromagnetic pulse.", + /decl/material/solid/metal/uranium = "Converts a slime core into a portable power source.", + /decl/material/liquid/water = "Converts a slime core into a portable light source." + ) + +/decl/slime_colour/yellow/Initialize() + . = ..() + LAZYSET(reaction_procs, /decl/material/liquid/water, TYPE_PROC_REF(/decl/slime_colour/yellow, try_water_reaction)) + +/decl/slime_colour/yellow/handle_blood_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + empulse(location, 3, 7) + return TRUE + +/decl/slime_colour/yellow/handle_uranium_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/cell/slime(location) + return TRUE + +/decl/slime_colour/yellow/proc/try_water_reaction(var/datum/reagents/holder) + return handle_water_reaction(holder) +/decl/slime_colour/yellow/proc/handle_water_reaction(var/datum/reagents/holder) + var/location = get_turf(holder.get_reaction_loc()) + if(location) + new /obj/item/flashlight/slime(location) + return TRUE diff --git a/mods/content/xenobiology/emotes.dm b/mods/content/xenobiology/emotes.dm new file mode 100644 index 000000000000..34f3c719cc4f --- /dev/null +++ b/mods/content/xenobiology/emotes.dm @@ -0,0 +1,53 @@ +/mob/living/slime/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/audible/moan, + /decl/emote/visible/twitch, + /decl/emote/visible/sway, + /decl/emote/visible/shiver, + /decl/emote/visible/bounce, + /decl/emote/visible/jiggle, + /decl/emote/visible/lightup, + /decl/emote/visible/vibrate, + /decl/emote/slime, + /decl/emote/slime/pout, + /decl/emote/slime/sad, + /decl/emote/slime/angry, + /decl/emote/slime/frown, + /decl/emote/slime/smile + ) + return default_emotes + +/decl/emote/slime + key = "nomood" + var/mood + +/decl/emote/slime/do_extra(atom/user) + if(ismob(user)) + var/mob/user_mob = user + var/datum/mob_controller/slime/slime_ai = user_mob.ai + if(istype(slime_ai)) + slime_ai.mood = mood + user.update_icon() + +/decl/emote/slime/mob_can_use(mob/living/user, assume_available = FALSE) + return isslime(user) && ..() + +/decl/emote/slime/pout + key = "slimepout" + mood = "pout" + +/decl/emote/slime/sad + key = "slimesad" + mood = "sad" + +/decl/emote/slime/angry + key = "slimeangry" + mood = "angry" + +/decl/emote/slime/frown + key = "slimefrown" + mood = "mischevous" + +/decl/emote/slime/smile + key = "slimesmile" + mood = ":3" diff --git a/mods/content/xenobiology/food.dm b/mods/content/xenobiology/food.dm new file mode 100644 index 000000000000..f90a1bd92cff --- /dev/null +++ b/mods/content/xenobiology/food.dm @@ -0,0 +1,61 @@ +/obj/item/food/bun/get_combined_food_products() + var/list/combined_food_products = ..() + LAZYSET(combined_food_products, /obj/item/slime_extract, /obj/item/food/jellyburger) + return combined_food_products + +/decl/recipe/slimetoast + display_name = "slime toast" + reagents = list(/decl/material/liquid/slimejelly = 5) + items = list( + /obj/item/food/slice/bread, + ) + result = /obj/item/food/jelliedtoast/slime + +/decl/recipe/slimedonut + display_name = "slime jelly donut" + reagents = list(/decl/material/liquid/slimejelly = 5, /decl/material/liquid/nutriment/sugar = 5) + items = list( + /obj/item/food/dough + ) + result = /obj/item/food/donut/jelly/slime + +/decl/recipe/slimesandwich + display_name = "slime sandwich" + reagents = list(/decl/material/liquid/slimejelly = 5) + items = list( + /obj/item/food/slice/bread = 2, + ) + result = /obj/item/food/jellysandwich/slime + +/obj/item/food/jellysandwich/slime/populate_reagents() + add_to_reagents(/decl/material/liquid/slimejelly, 5) + . = ..() + +/obj/item/food/jelliedtoast/slime/populate_reagents() + add_to_reagents(/decl/material/liquid/slimejelly, 5) + . = ..() + +/obj/item/food/jellyburger/slime/populate_reagents() + add_to_reagents(/decl/material/liquid/slimejelly, 5) + . = ..() + +/obj/item/chems/glass/bowl/mapped/slime + initial_reagent_type = /decl/material/liquid/slimejelly + +/obj/item/food/donut/jelly/slime + name = "jelly donut" + desc = "You jelly?" + filling_color = "#ed1169" + center_of_mass = @'{"x":16,"y":11}' + nutriment_amt = 3 + bitesize = 5 + jelly_type = /decl/material/liquid/slimejelly + +/obj/item/chems/glass/bowl/mystery/get_random_fillings() + . = ..() + list(list( + /decl/material/liquid/slimejelly = 10, + /decl/material/liquid/water = 10 + )) + +/obj/item/food/donut/chaos/get_random_fillings() + . = ..() + /decl/material/liquid/slimejelly diff --git a/mods/content/xenobiology/icons/slimes/slime_adult.dmi b/mods/content/xenobiology/icons/slimes/slime_adult.dmi new file mode 100644 index 000000000000..0fb884adce7b Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_adamantine.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_adamantine.dmi new file mode 100644 index 000000000000..b61b13735a07 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_adamantine.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_black.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_black.dmi new file mode 100644 index 000000000000..c4f4205f2bd3 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_black.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_blue.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_blue.dmi new file mode 100644 index 000000000000..2c1a27cda731 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_blue.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_cerulean.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_cerulean.dmi new file mode 100644 index 000000000000..1286a67ccd3f Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_cerulean.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_darkblue.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_darkblue.dmi new file mode 100644 index 000000000000..e47cbafaf4e7 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_darkblue.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_darkpurple.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_darkpurple.dmi new file mode 100644 index 000000000000..3335dc645bb2 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_darkpurple.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_gold.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_gold.dmi new file mode 100644 index 000000000000..8658ea614628 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_gold.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_green.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_green.dmi new file mode 100644 index 000000000000..3a4d75ea4b9d Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_green.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_lightpink.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_lightpink.dmi new file mode 100644 index 000000000000..d8eaaab86d7f Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_lightpink.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_metal.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_metal.dmi new file mode 100644 index 000000000000..bb5193f2b5ec Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_metal.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_oil.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_oil.dmi new file mode 100644 index 000000000000..1312d74f2284 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_oil.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_orange.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_orange.dmi new file mode 100644 index 000000000000..477b97f5a2e6 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_orange.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_pink.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_pink.dmi new file mode 100644 index 000000000000..28d79c163d12 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_pink.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_purple.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_purple.dmi new file mode 100644 index 000000000000..b74911438001 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_purple.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_pyrite.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_pyrite.dmi new file mode 100644 index 000000000000..becda4b70b86 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_pyrite.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_quantum.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_quantum.dmi new file mode 100644 index 000000000000..915f6cd069a8 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_quantum.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_rainbow.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_rainbow.dmi new file mode 100644 index 000000000000..edf9cd226fa1 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_rainbow.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_red.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_red.dmi new file mode 100644 index 000000000000..2a5a0fecc83e Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_red.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_sepia.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_sepia.dmi new file mode 100644 index 000000000000..a0cd05a1f43a Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_sepia.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_silver.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_silver.dmi new file mode 100644 index 000000000000..cc403e397320 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_silver.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_adult_yellow.dmi b/mods/content/xenobiology/icons/slimes/slime_adult_yellow.dmi new file mode 100644 index 000000000000..1c4ba9b80b11 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_adult_yellow.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby.dmi b/mods/content/xenobiology/icons/slimes/slime_baby.dmi new file mode 100644 index 000000000000..d233df56bc8d Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_adamantine.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_adamantine.dmi new file mode 100644 index 000000000000..7a1798c2116b Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_adamantine.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_black.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_black.dmi new file mode 100644 index 000000000000..65dadb3e2a4c Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_black.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_blue.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_blue.dmi new file mode 100644 index 000000000000..a15ca0fba1da Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_blue.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_cerulean.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_cerulean.dmi new file mode 100644 index 000000000000..c26799805650 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_cerulean.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_darkblue.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_darkblue.dmi new file mode 100644 index 000000000000..e016fc80609c Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_darkblue.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_darkpurple.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_darkpurple.dmi new file mode 100644 index 000000000000..114defbbe04e Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_darkpurple.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_gold.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_gold.dmi new file mode 100644 index 000000000000..2311fd97c2e0 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_gold.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_green.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_green.dmi new file mode 100644 index 000000000000..199ed403ad59 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_green.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_lightpink.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_lightpink.dmi new file mode 100644 index 000000000000..7544056db2be Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_lightpink.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_metal.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_metal.dmi new file mode 100644 index 000000000000..0dc9c54a0a49 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_metal.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_oil.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_oil.dmi new file mode 100644 index 000000000000..055c42f76c8f Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_oil.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_orange.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_orange.dmi new file mode 100644 index 000000000000..3b03f6692249 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_orange.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_pink.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_pink.dmi new file mode 100644 index 000000000000..f56057e44c68 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_pink.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_purple.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_purple.dmi new file mode 100644 index 000000000000..0d4fc5161669 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_purple.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_pyrite.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_pyrite.dmi new file mode 100644 index 000000000000..2646508b07d8 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_pyrite.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_quantum.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_quantum.dmi new file mode 100644 index 000000000000..b7d849bbba83 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_quantum.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_rainbow.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_rainbow.dmi new file mode 100644 index 000000000000..529c819ce669 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_rainbow.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_red.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_red.dmi new file mode 100644 index 000000000000..773b2b51f2d9 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_red.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_sepia.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_sepia.dmi new file mode 100644 index 000000000000..16e623bd0b89 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_sepia.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_silver.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_silver.dmi new file mode 100644 index 000000000000..685d96763565 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_silver.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_baby_yellow.dmi b/mods/content/xenobiology/icons/slimes/slime_baby_yellow.dmi new file mode 100644 index 000000000000..88f398115496 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_baby_yellow.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract.dmi b/mods/content/xenobiology/icons/slimes/slime_extract.dmi new file mode 100644 index 000000000000..454030870d10 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_adamantine.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_adamantine.dmi new file mode 100644 index 000000000000..a966ab686bac Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_adamantine.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_black.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_black.dmi new file mode 100644 index 000000000000..28b3fa431bbb Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_black.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_blue.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_blue.dmi new file mode 100644 index 000000000000..0e41c079c0d2 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_blue.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_cerulean.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_cerulean.dmi new file mode 100644 index 000000000000..3d2d5f2d6cb4 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_cerulean.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_darkblue.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_darkblue.dmi new file mode 100644 index 000000000000..645a2ccb7bfd Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_darkblue.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_darkpurple.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_darkpurple.dmi new file mode 100644 index 000000000000..2f297e64539e Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_darkpurple.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_gold.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_gold.dmi new file mode 100644 index 000000000000..2d559a4e4818 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_gold.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_green.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_green.dmi new file mode 100644 index 000000000000..2d3ed9b9bf39 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_green.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_lightpink.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_lightpink.dmi new file mode 100644 index 000000000000..11a36acfe5c6 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_lightpink.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_metal.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_metal.dmi new file mode 100644 index 000000000000..6386b85045ca Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_metal.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_oil.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_oil.dmi new file mode 100644 index 000000000000..8d8bc85f252e Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_oil.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_orange.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_orange.dmi new file mode 100644 index 000000000000..e60c93d3925e Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_orange.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_pink.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_pink.dmi new file mode 100644 index 000000000000..d8569e791061 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_pink.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_purple.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_purple.dmi new file mode 100644 index 000000000000..162f80062f35 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_purple.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_pyrite.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_pyrite.dmi new file mode 100644 index 000000000000..3dbf752c8ffa Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_pyrite.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_quantum.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_quantum.dmi new file mode 100644 index 000000000000..a221bb4fc5ee Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_quantum.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_rainbow.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_rainbow.dmi new file mode 100644 index 000000000000..5ae57e572f04 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_rainbow.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_red.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_red.dmi new file mode 100644 index 000000000000..dc58cc530b07 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_red.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_sepia.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_sepia.dmi new file mode 100644 index 000000000000..ece50a527bcd Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_sepia.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_silver.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_silver.dmi new file mode 100644 index 000000000000..c36daf4d2e02 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_silver.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_extract_yellow.dmi b/mods/content/xenobiology/icons/slimes/slime_extract_yellow.dmi new file mode 100644 index 000000000000..ce4bb01aa817 Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_extract_yellow.dmi differ diff --git a/mods/content/xenobiology/icons/slimes/slime_faces.dmi b/mods/content/xenobiology/icons/slimes/slime_faces.dmi new file mode 100644 index 000000000000..3525f450b07d Binary files /dev/null and b/mods/content/xenobiology/icons/slimes/slime_faces.dmi differ diff --git a/mods/content/xenobiology/icons/smartfridge_contents_slime.dmi b/mods/content/xenobiology/icons/smartfridge_contents_slime.dmi new file mode 100644 index 000000000000..c7c8e4acd4da Binary files /dev/null and b/mods/content/xenobiology/icons/smartfridge_contents_slime.dmi differ diff --git a/mods/content/xenobiology/mobs/critter_slime.dm b/mods/content/xenobiology/mobs/critter_slime.dm new file mode 100644 index 000000000000..2e6bf77750c6 --- /dev/null +++ b/mods/content/xenobiology/mobs/critter_slime.dm @@ -0,0 +1,66 @@ +/mob/living/simple_animal/slime + name = "pet slime" + desc = "A lovable, domesticated slime." + icon = 'mods/content/xenobiology/icons/slimes/slime_baby.dmi' + speak_emote = list("chirps") + max_health = 100 + response_harm = "stamps on" + gene_damage = -1 + ai = /datum/mob_controller/pet_slime + var/slime_type = /decl/slime_colour/grey + +/datum/mob_controller/pet_slime + emote_see = list("jiggles", "bounces in place") + +/mob/living/simple_animal/slime/Initialize(var/ml, var/_stype = /decl/slime_colour/grey) + . = ..() + slime_type = _stype + if(!ispath(slime_type, /decl/slime_colour)) + PRINT_STACK_TRACE("Pet slime had non-decl slime type: [slime_type || "NULL"]") + return INITIALIZE_HINT_QDEL + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + SetName("pet [slime_data.name] slime") + update_icon() + +/mob/living/simple_animal/slime/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + icon = get_slime_icon() + icon_state = (stat == DEAD ? "slime_dead" : "slime") + +/mob/living/simple_animal/slime/proc/get_slime_icon() + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + return slime_data.baby_icon + +/mob/living/simple_animal/slime/proc/prompt_rename(var/mob/user) + set waitfor = FALSE + var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) + if(QDELETED(src) || QDELETED(user)) + return + SetName(newname || "pet slime") + +/mob/living/simple_animal/slime/check_has_mouth() + return FALSE + +/mob/living/simple_animal/slime/adult + icon = 'mods/content/xenobiology/icons/slimes/slime_adult.dmi' + +/mob/living/simple_animal/slime/adult/death(gibbed) + SHOULD_CALL_PARENT(FALSE) + for(var/i = 1 to rand(2,3)) + var/mob/living/simple_animal/slime/baby = new(get_turf(src), slime_type) + if(client) + if(mind) + mind.transfer_to(baby) + else + baby.key = key + qdel(src) + return TRUE + +/mob/living/simple_animal/slime/adult/get_slime_icon() + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + return slime_data.adult_icon + +/mob/living/simple_animal/slime/adult/on_update_icon() + ..() + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + add_overlay(image(slime_data.mood_icon, "aslime-:33")) diff --git a/mods/content/xenobiology/mobs/slime_feeding_helpers.dm b/mods/content/xenobiology/mobs/slime_feeding_helpers.dm new file mode 100644 index 000000000000..bebb1ed1669c --- /dev/null +++ b/mods/content/xenobiology/mobs/slime_feeding_helpers.dm @@ -0,0 +1,71 @@ +var/global/list/slime_pain_messages = list( + "You can feel your body becoming weak!", + "You feel like you're about to die!", + "You feel every part of your body screaming in agony!", + "A low, rolling pain passes through your body!", + "Your body feels as if it's falling apart!", + "You feel extremely weak!", + "A sharp, deep pain bathes every inch of your body!" +) + +// This proc is called when a slime is feeding on the mob, and the mob is +// over a certain cloneloss threshold. It will generally destroy the mob, +// but in the case of humans will dissolve a random limb, etc. +// The return value is the amount of nutrition provided to the slime. +/mob/living/proc/eaten_by_slime() + if(QDELETED(src)) + return + new /obj/effect/decal/cleanable/mucus(get_turf(src)) + var/remains_type = get_remains_type() + if(remains_type) + new remains_type(get_turf(src)) + dump_contents() + qdel(src) + . = rand(2,3) + +/mob/living/human/eaten_by_slime() + var/list/limbs = get_external_organs() + if(LAZYLEN(limbs) > 1) + var/obj/item/organ/external/E = pick(limbs) + if(E.limb_flags & ORGAN_FLAG_CAN_AMPUTATE) + E.dismember(FALSE, DISMEMBER_METHOD_ACID) + . = 1 + if((QDELETED(src) || LAZYLEN(limbs) <= 1)) + . = ..() + +// Simple check to ensure a target is currently being fed on. +/mob/proc/currently_being_eaten_by_a_slime(var/mob/living/slime/feeder_check) + for(var/mob/living/slime/M in range(1, src)) + if(feeder_check != M && M.feeding_on?.resolve() == src) + return M + +/mob/can_enter_cryopod(var/mob/user) + . = ..() + if(. && currently_being_eaten_by_a_slime()) + if(src == user) + to_chat(src, SPAN_WARNING("You cannot use that, as you're too busy getting your life sucked out of you.")) + else + to_chat(user, SPAN_WARNING("\The [user] cannot use that, as they are too busy getting the life sucked out of them.")) + return FALSE + +// Handle cosmetic effects (currently) from being eaten by a slime, mostly pain-related. +/mob/living/proc/handle_additional_slime_effects() + if(can_feel_pain()) + to_chat(src, SPAN_DANGER(pick(global.slime_pain_messages))) + +/mob/living/human/handle_additional_slime_effects() + custom_pain(pick(global.slime_pain_messages),100) + +// Called by a feeding slime on the victim. +// The return value is the nutrition provided to the slime. +/mob/living/proc/slime_feed_act(var/mob/living/slime/attacker) + var/protection = (1 - get_blocked_ratio(null, TOX, damage_flags = DAM_DISPERSED | DAM_BIO)) + take_damage((attacker.is_adult ? 10 : 5) * protection, CLONE) + take_damage(1 * protection, TOX) + if(current_health <= 0) + take_damage(1 * protection, TOX) + if(prob(15) && client) + handle_additional_slime_effects() + . = 15 * protection + if(stat == DEAD || get_damage(CLONE) >= get_max_health()) + eaten_by_slime() diff --git a/mods/content/xenobiology/overrides.dm b/mods/content/xenobiology/overrides.dm new file mode 100644 index 000000000000..015002287b36 --- /dev/null +++ b/mods/content/xenobiology/overrides.dm @@ -0,0 +1,46 @@ +/obj/structure/flaps/Initialize() + . = ..() + mobs_can_pass |= /mob/living/slime + +/obj/item/projectile/change/apply_transformation(var/mob/M, var/choice) + if(choice == "slime") + var/mob/living/slime/S = new(get_turf(M)) + S.universal_speak = TRUE + return S + . = ..() + +/obj/item/projectile/change/get_random_transformation_options(var/mob/M) + . = ..() || list() + if(!isslime(M)) + . |= "slime" + +/obj/item/scanner/xenobio/Initialize(ml, material_key) + . = ..() + valid_targets |= /mob/living/slime + +/obj/machinery/auto_cloner/get_passive_mob_types() + . = ..() || list() + . |= /mob/living/simple_animal/slime + +/obj/machinery/smartfridge/secure/extract + name = "\improper Slime Extract Storage" + desc = "A refrigerated storage unit for slime extracts." + overlay_contents_icon = 'mods/content/xenobiology/icons/smartfridge_contents_slime.dmi' + initial_access = list(access_research) + +/obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O) + return istype(O,/obj/item/slime_extract) + +/obj/item/gripper/research/Initialize(ml, material_key) + . = ..() + can_hold |= /obj/item/slime_extract + +/obj/item/gripper/cultivator/Initialize(ml, material_key) + . = ..() + can_hold |= /obj/item/slime_extract + +/mob/living/human/say_understands(var/mob/other,var/decl/language/speaking = null) + . = (!speaking && isslime(other)) || ..() + +/mob/living/brain/say_understands(var/mob/other,var/decl/language/speaking = null) + . = (!speaking && isslime(other)) || ..() diff --git a/mods/content/xenobiology/slime/_slime.dm b/mods/content/xenobiology/slime/_slime.dm new file mode 100644 index 000000000000..62197258a3bf --- /dev/null +++ b/mods/content/xenobiology/slime/_slime.dm @@ -0,0 +1,365 @@ +/decl/config/num/movement_slime + uid = "slime_delay" + desc = "Movement delay for slimes." + +#define FEED_RESULT_INVALID -1 +#define FEED_RESULT_DEAD 0 +#define FEED_RESULT_VALID 1 + +/mob/living/slime + name = "baby slime" + icon = 'mods/content/xenobiology/icons/slimes/slime_baby.dmi' + icon_state = ICON_STATE_WORLD + pass_flags = PASS_FLAG_TABLE + speak_emote = list("chirps") + max_health = 150 + gender = NEUTER + see_in_dark = 8 + status_flags = CANPARALYSE|CANPUSH + butchery_data = null + ai = /datum/mob_controller/slime + hud_used = /datum/hud + nutrition = 800 + + var/is_adult = FALSE + var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35 + var/powerlevel = 0 // 0-10 controls how much electricity they are generating + var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces + var/weakref/feeding_on + var/toxloss = 0 + var/hurt_temperature = T0C-50 // slime keeps taking damage when its bodytemperature is below this + var/die_temperature = 50 // slime dies instantly when its bodytemperature is below this + var/number + var/slime_type = /decl/slime_colour/grey + var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside + var/core_removal_stage = 0 //For removing cores. + +/mob/living/slime/Destroy() + set_feeding_on() + for(var/atom/movable/AM in contents) + AM.dropInto(loc) + . = ..() + +/mob/living/slime/get_available_postures() + var/static/list/available_postures = list( + /decl/posture/standing + ) + return available_postures + +/mob/living/slime/getToxLoss() + return toxloss + +/mob/living/slime/get_digestion_product() + return /decl/material/liquid/slimejelly + +/mob/living/slime/adjustToxLoss(var/amount, var/do_update_health = TRUE) + toxloss = clamp(toxloss + amount, 0, get_max_health()) + if(do_update_health) + update_health() + +/mob/living/slime/setToxLoss(var/amount) + take_damage(amount-get_damage(TOX), TOX) + +/mob/living/slime/Initialize(mapload, var/_stype = /decl/slime_colour/grey) + + . = ..(mapload) + + reagents = new /datum/reagents/metabolism(240, src, CHEM_TOUCH) + render_target = "slime_\ref[src]" + + slime_type = _stype + + if(!ispath(slime_type, /decl/slime_colour)) + PRINT_STACK_TRACE("Slime initialized with non-decl slime type: [slime_type || "NULL"]") + return INITIALIZE_HINT_QDEL + + number = random_id(/mob/living/slime, 1, 1000) + mutation_chance = rand(25, 35) + update_name() + update_icon() + +/mob/living/slime/proc/update_name() + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + SetName("[slime_data.name] [is_adult ? "adult" : "baby"] slime ([number])") + +/mob/living/slime/get_movement_delay(var/travel_dir) + if (bodytemperature >= 330.23) // 135 F + return -1 // slimes become supercharged at high temperatures + + var/tally = ..() + + var/health_deficiency = (get_max_health() - current_health) + if(health_deficiency >= 30) tally += (health_deficiency / 25) + + if (bodytemperature < 183.222) + tally += (283.222 - bodytemperature) / 10 * 1.75 + + if(reagents) + if(reagents.has_reagent(/decl/material/liquid/amphetamines)) // Stimulants slows slimes down + tally *= 2 + + if(reagents.has_reagent(/decl/material/liquid/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow + tally *= 5 + + if(current_health <= 0) // if damaged, the slime moves twice as slow + tally *= 2 + + return tally + get_config_value(/decl/config/num/movement_slime) + +/mob/living/slime/Bump(atom/movable/AM, yes) + if ((!(yes) || now_pushing)) + return + now_pushing = 1 + + if(isobj(AM) && !client && powerlevel > 0) + var/probab = 10 + switch(powerlevel) + if(1 to 2) probab = 20 + if(3 to 4) probab = 30 + if(5 to 6) probab = 40 + if(7 to 8) probab = 60 + if(9) probab = 70 + if(10) probab = 95 + if(prob(probab)) + if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille)) + if(nutrition <= get_hunger_nutrition()) + if (is_adult || prob(5)) + UnarmedAttack(AM, Adjacent(AM)) + + if(ismob(AM)) + var/mob/tmob = AM + + if(is_adult) + if(ishuman(tmob)) + if(prob(90)) + now_pushing = 0 + return + else + if(ishuman(tmob)) + now_pushing = 0 + return + + now_pushing = 0 + + ..() + +/mob/living/slime/Stat() + . = ..() + + statpanel("Status") + stat(null, "Health: [get_health_percent()]%") + stat(null, "Intent: [get_intent().name]") + + if (client.statpanel == "Status") + stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]") + if(amount_grown >= 10) + if(is_adult) + stat(null, "You can reproduce!") + else + stat(null, "You can evolve!") + + stat(null,"Power Level: [powerlevel]") + +/mob/living/slime/adjustFireLoss(amount, do_update_health = TRUE) + ..(-abs(amount), do_update_health) // Heals them + +/mob/living/slime/bullet_act(var/obj/item/projectile/Proj) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai)) + slime_ai.attacked += 10 + slime_ai.adjust_friendship(Proj.firer, -5) + ..(Proj) + return 0 + +/mob/living/slime/emp_act(severity) + powerlevel = 0 // oh no, the power! + ..() + +/mob/living/slime/explosion_act(severity) + ..() + if(severity == 1) + qdel(src) + +/mob/living/slime/attack_ui(slot) + return + +/decl/status_condition/confused/handle_changed_amount(mob/living/victim, new_amount, last_amount) + . = ..() + if(new_amount != last_amount && isslime(victim)) + var/mob/living/slime/slime = victim + if(istype(slime.ai, /datum/mob_controller/slime)) + var/datum/mob_controller/slime/slime_ai = slime.ai + slime_ai.update_mood() + +/mob/living/slime/proc/adjust_friendship(var/mob/user, var/amount) + if(user && amount != 0) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai)) + return slime_ai.adjust_friendship(user, amount) + +/mob/living/slime/attack_hand(mob/user) + + if(stat == DEAD) + visible_message(SPAN_NOTICE("\The [user] pokes \the [src].")) + return TRUE + + if(user.check_intent(I_FLAG_HELP)) + if(length(contents)) + var/atom/movable/AM = pick(contents) + AM.dropInto(loc) + visible_message(SPAN_NOTICE("\The [user] extracts \the [AM] from \the [src].")) + update_icon() + else + visible_message(SPAN_NOTICE("\The [user] pets \the [src].")) + adjust_friendship(user, rand(2,3)) + return TRUE + + var/prey = feeding_on?.resolve() + if(prey) + if(prey == user) + if(prob(60)) + visible_message(SPAN_DANGER("\The [user] fails to escape \the [src]!")) + else + visible_message(SPAN_DANGER("\The [user] manages to escape \the [src]!")) + set_feeding_on() + else + if(prob(30)) + visible_message(SPAN_DANGER("\The [user] attempts to wrestle \the [src] off \the [prey]!")) + else + visible_message(SPAN_DANGER("\The [user] manages to wrestle \the [src] off \the [prey]!")) + set_feeding_on() + + if(prey != feeding_on?.resolve()) + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + SET_STATUS_MAX(src, STAT_CONFUSE, 2) + step_away(src, user) + else + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return TRUE + + if(user.check_intent(I_FLAG_HELP)) + visible_message(SPAN_NOTICE("\The [user] hugs \the [src] to make it feel better!")) + return TRUE + + if(user.check_intent(I_FLAG_DISARM)) + if(prob(40)) + visible_message(SPAN_DANGER("\The [user] shoves \the [src] and it wobbles around, disoriented!")) + SET_STATUS_MAX(src, STAT_CONFUSE, 2) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + else + visible_message(SPAN_DANGER("\The [user] shoves \the [src]!")) + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + return TRUE + + if(user.check_intent(I_FLAG_HARM)) + var/damage = rand(1, 9) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai)) + slime_ai.attacked += 10 + slime_ai.adjust_friendship(user, -5) + if(prob(10)) + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message(SPAN_DANGER("\The [user] has attempted to punch \the [src]!")) + return TRUE + playsound(loc, "punch", 25, 1, -1) + visible_message(SPAN_DANGER("\The [user] has punched \the [src]!")) + take_damage(damage) + return TRUE + + return ..() + +/mob/living/slime/attackby(var/obj/item/used_item, var/mob/user) + var/force = used_item.expend_attack_force(user) + if(force > 0) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai)) + slime_ai.attacked += 10 + slime_ai.adjust_friendship(user, -5) + if(stat == CONSCIOUS && prob(25)) //Only run this check if we're alive or otherwise motile, otherwise surgery will be agonizing for xenobiologists. + to_chat(user, SPAN_WARNING("\The [used_item] passes right through \the [src]!")) + return TRUE + . = ..() + if(feeding_on && prob(force * 5)) + set_feeding_on() + step_away(src, user) + +/mob/living/slime/restrained() + return 0 + +/mob/living/slime/toggle_throw_mode() + return + +/mob/living/slime/check_has_eyes() + return FALSE + +/mob/living/slime/check_has_mouth() + return FALSE + +/mob/living/slime/get_hydration() + return get_nutrition() + +/mob/living/slime/proc/gain_nutrition(var/amount) + adjust_nutrition(amount) + if(prob(amount * 2)) // Gain around one level per 50 nutrition + powerlevel++ + if(powerlevel > 10) + powerlevel = 10 + heal_damage(TOX, 10) + +/mob/living/slime/proc/get_hunger_state() + . = 0 + if (nutrition < get_starve_nutrition()) + . += 2 + else if((nutrition < get_grow_nutrition() && prob(25)) || nutrition < get_hunger_nutrition()) + . += 1 + +/mob/living/slime/can_be_buckled(var/mob/user) + to_chat(user, SPAN_WARNING("\The [src] is too squishy to buckle in.")) + return FALSE + +/mob/living/slime/mind_initialize() + ..() + mind.assigned_role = "slime" + +/mob/living/slime/handle_airflow(differential, list/connecting_turfs, repelled) + return FALSE + +/mob/living/slime/handle_airflow_stun(differential) + return FALSE + +/mob/living/slime/xenobio_scan_results() + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + . = list() + . += "Slime scan result for \the [src]:" + . += "[slime_data.name] [is_adult ? "adult" : "baby"] slime" + . += "Nutrition:\t[nutrition]/[get_max_nutrition()]" + if(nutrition < get_starve_nutrition()) + . += "Warning:\tthe slime is starving!" + else if (nutrition < get_hunger_nutrition()) + . += "Warning:\tthe slime is hungry." + . += "Electric charge strength:\t[powerlevel]" + . += "Health:\t[get_health_percent()]%" + + var/list/slime_mutations = slime_data.descendants?.Copy() + if(!length(slime_mutations)) + . += "This slime will never mutate." + else + var/list/mutationChances = list() + for(var/i in slime_mutations) + if(i == slime_type) + continue + if(mutationChances[i]) + mutationChances[i] += mutation_chance / length(slime_mutations) + else + mutationChances[i] = mutation_chance / length(slime_mutations) + + var/list/mutationTexts = list("[slime_data.name] ([100 - mutation_chance]%)") + for(var/i in mutationChances) + mutationTexts += "[GET_DECL(i)] ([mutationChances[i]]%)" + + . += "Possible colours on splitting:\t[english_list(mutationTexts)]" + + if (cores > 1) + . += "Anomalous slime core amount detected." + . += "Growth progress:\t[amount_grown]/10." + . = jointext(., "
    ") diff --git a/mods/content/xenobiology/slime/death.dm b/mods/content/xenobiology/slime/death.dm new file mode 100644 index 000000000000..f19899eb2f11 --- /dev/null +++ b/mods/content/xenobiology/slime/death.dm @@ -0,0 +1,30 @@ +/mob/living/slime/physically_destroyed() + if(is_adult) + var/datum/mob_controller/slime/my_ai = ai + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + var/list/babies = list() + for(var/i in 1 to 2) + var/mob/living/slime/baby = new slime_data.child_type(loc, slime_type) + var/datum/mob_controller/slime/baby_ai = baby.ai + if(istype(my_ai) && istype(baby_ai)) + baby_ai.rabid = TRUE + baby_ai.observed_friends = my_ai.observed_friends?.Copy() + step_away(baby, src) + babies += baby + if(mind) + mind.transfer_to(pick(babies)) + else if(key) + var/mob/my_baby = pick(babies) + my_baby.key = key + qdel(src) + +/mob/living/slime/death(gibbed) + // Handle splitting instead of dying. + if(stat != DEAD && !gibbed && is_adult) + physically_destroyed() + return TRUE + . = ..() + if(.) + set_feeding_on() + for(var/atom/movable/AM in contents) + AM.dropInto(loc) diff --git a/mods/content/xenobiology/slime/examine.dm b/mods/content/xenobiology/slime/examine.dm new file mode 100644 index 000000000000..318435bc62b3 --- /dev/null +++ b/mods/content/xenobiology/slime/examine.dm @@ -0,0 +1,18 @@ +/mob/living/slime/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = ..() + if(stat == DEAD) + . += "It is limp and unresponsive." + else + if(src.get_damage(BRUTE) >= 40) + . += SPAN_DANGER("It has severe punctures and tears in its flesh!") + else if(src.get_damage(BRUTE)) + . += SPAN_WARNING("It has some punctures in its flesh!") + switch(powerlevel) + if(2 to 3) + . += SPAN_WARNING("It is flickering gently with a little electrical activity.") + if(4 to 5) + . += SPAN_WARNING("It is glowing gently with moderate levels of electrical activity.") + if(6 to 9) + . += SPAN_DANGER("It is glowing brightly with high levels of electrical activity.") + if(10) + . += SPAN_DANGER("It is radiating with massive levels of electrical activity!") diff --git a/mods/content/xenobiology/slime/feeding.dm b/mods/content/xenobiology/slime/feeding.dm new file mode 100644 index 000000000000..d4304f90b2b7 --- /dev/null +++ b/mods/content/xenobiology/slime/feeding.dm @@ -0,0 +1,119 @@ +/mob/living/slime/proc/check_valid_feed_target(var/mob/living/M, var/check_already_feeding = TRUE, var/silent = FALSE) + if(QDELETED(M) || !istype(M) || !isturf(M.loc)) + return FEED_RESULT_INVALID + if(M == src) + if(!silent) + to_chat(src, SPAN_WARNING("You cannot feed on yourself.")) + return FEED_RESULT_INVALID + if(check_already_feeding && feeding_on) + if(!silent) + to_chat(src, SPAN_WARNING("You are already feeding on \the [feeding_on.resolve()].")) + return FEED_RESULT_INVALID + if(!istype(M) || issilicon(M) || isslime(M)) + if(!silent) + to_chat(src, SPAN_WARNING("You cannot feed on \the [M].")) + return FEED_RESULT_INVALID + if(!Adjacent(M)) + if(!silent) + to_chat(src, SPAN_WARNING("\The [M] is too far away.")) + return FEED_RESULT_INVALID + if(M.get_blocked_ratio(null, TOX, damage_flags = DAM_DISPERSED | DAM_BIO) >= 1) + if(!silent) + to_chat(src, SPAN_WARNING("\The [M] is protected from your feeding.")) + return FEED_RESULT_INVALID + if(!M.has_genetic_information()) + if(!silent) + to_chat(src, SPAN_WARNING("You cannot feed on \the [M].")) + return FEED_RESULT_INVALID + var/decl/species/prey_species = M.get_species() + if(istype(prey_species) && (prey_species.species_flags & SPECIES_FLAG_NO_POISON)) + if(!silent) + to_chat(src, SPAN_WARNING("You cannot feed on \the [M].")) + return FEED_RESULT_INVALID + if(M.stat == DEAD) + if(!silent) + to_chat(src, SPAN_WARNING("\The [src] is dead.")) + return FEED_RESULT_DEAD + if(M.get_damage(CLONE) >= M.get_max_health() * 1.5) + if(!silent) + to_chat(src, SPAN_WARNING("\The [M] is too degraded to feed upon.")) + return FEED_RESULT_DEAD + if(M.currently_being_eaten_by_a_slime(src)) + if(!silent) + to_chat(src, SPAN_WARNING("Another slime is already feeding on \the [M].")) + return FEED_RESULT_INVALID + return FEED_RESULT_VALID + +/mob/living/slime/proc/set_feeding_on(var/mob/living/victim) + if(feeding_on == weakref(victim)) + return + if(feeding_on) + var/mob/feed_mob = feeding_on.resolve() + events_repository.unregister(/decl/observ/moved, src, src) + events_repository.unregister(/decl/observ/moved, feed_mob, src) + events_repository.unregister(/decl/observ/destroyed, feed_mob, src) + feeding_on = null + if(victim) + feeding_on = weakref(victim) + events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/mob/living/slime, check_feed_target_position)) + events_repository.register(/decl/observ/moved, victim, src, TYPE_PROC_REF(/mob/living/slime, check_feed_target_position)) + events_repository.register(/decl/observ/destroyed, victim, src, TYPE_PROC_REF(/mob/living/slime, check_feed_target_position)) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai)) + slime_ai.update_mood() + update_icon() + +/mob/living/slime/proc/slime_attach(var/mob/living/M) + if(check_valid_feed_target(M) == FEED_RESULT_VALID) + set_feeding_on(M) + forceMove(get_turf(M)) + M.update_personal_goal(/datum/goal/achievement/dont_let_slime_snack_you, FALSE) + +/mob/living/slime/proc/check_feed_target_position() + var/mob/feed_mob = feeding_on?.resolve() + if(istype(feed_mob) && !QDELETED(feed_mob) && isturf(feed_mob.loc)) + if(loc == feed_mob.loc) + return TRUE + if(Adjacent(feed_mob)) + forceMove(get_turf(feed_mob)) + return TRUE + set_feeding_on() + return FALSE + +/mob/living/slime/proc/slime_feed() + + if(stat != CONSCIOUS) + return FALSE + + var/mob/living/feed_mob = feeding_on?.resolve() + if(!istype(feed_mob) || !check_feed_target_position()) + return FALSE + + var/ate_victim = FALSE + var/feed_result = check_valid_feed_target(feed_mob, check_already_feeding = FALSE) + if(feed_result != FEED_RESULT_VALID) + if(feed_result == FEED_RESULT_DEAD) + ate_victim = TRUE + else + set_feeding_on() + return FALSE + else + var/drained = feed_mob.slime_feed_act(src) + if(!drained || QDELETED(feed_mob) || check_valid_feed_target(feed_mob, check_already_feeding = FALSE, silent = TRUE) == FEED_RESULT_DEAD) + ate_victim = TRUE + if(drained) + gain_nutrition(drained) + var/heal_amt = floor(drained*0.5) + if(heal_amt > 0) + heal_damage(OXY, heal_amt, do_update_health = FALSE) + heal_damage(BRUTE, heal_amt, do_update_health = FALSE) + heal_damage(CLONE, heal_amt) + + if(ate_victim && feed_mob) + if(feed_mob.last_handled_by_mob) + var/mob/friend = feed_mob.last_handled_by_mob.resolve() + if(istype(friend) && friend != feed_mob) + adjust_friendship(friend, 1) + set_feeding_on() + + return !ate_victim diff --git a/mods/content/xenobiology/slime/items.dm b/mods/content/xenobiology/slime/items.dm new file mode 100644 index 000000000000..26304f3e971b --- /dev/null +++ b/mods/content/xenobiology/slime/items.dm @@ -0,0 +1,120 @@ +/obj/item/slime_extract + name = "slime core extract" + desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"." + icon = 'mods/content/xenobiology/icons/slimes/slime_extract.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_SMALL + throw_speed = 3 + throw_range = 6 + origin_tech = @'{"biotech":4}' + atom_flags = ATOM_FLAG_OPEN_CONTAINER + material = /decl/material/liquid/slimejelly + _base_attack_force = 1 + chem_volume = 100 + var/slime_type = /decl/slime_colour/grey + var/Uses = 1 // uses before it goes inert + var/enhanced = 0 //has it been enhanced before? + +/obj/item/slime_extract/get_base_value() + . = ..() * Uses + +/obj/item/slime_extract/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/slime_extract_enhancer)) + if(enhanced == 1) + to_chat(user, SPAN_WARNING("This extract has already been enhanced!")) + return ..() + if(Uses == 0) + to_chat(user, SPAN_WARNING("You can't enhance a used extract!")) + return ..() + to_chat(user, "You apply the enhancer. It now has triple the amount of uses.") + Uses = 3 + enhanced = 1 + qdel(used_item) + return TRUE + . = ..() + +/obj/item/slime_extract/Initialize(var/ml, var/mat, var/_stype = /decl/slime_colour/grey) + . = ..(ml, mat) + slime_type = _stype + if(!ispath(slime_type, /decl/slime_colour)) + PRINT_STACK_TRACE("Slime extract initialized with non-decl slime colour: [slime_type || "NULL"].") + SSstatistics.extracted_slime_cores_amount++ + update_icon() + +/obj/item/slime_extract/populate_reagents() + add_to_reagents(/decl/material/liquid/slimejelly, 30) + +/obj/item/slime_extract/on_reagent_change() + if((. = ..()) && REAGENT_TOTAL_VOLUME(reagents)) + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + slime_data.handle_reaction(reagents) + +/obj/item/slime_extract/on_update_icon() + . = ..() + icon_state = get_world_inventory_state() + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + icon = slime_data.extract_icon + +/obj/effect/golemrune + anchored = TRUE + desc = "A strange rune used to create golems. It glows when it can be activated." + name = "rune" + icon = 'icons/obj/rune.dmi' + icon_state = "golem" + layer = RUNE_LAYER + +/obj/effect/golemrune/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + +/obj/effect/golemrune/Process() + var/mob/observer/ghost/ghost + for(var/mob/observer/ghost/observer in src.loc) + if(!observer.client || (observer.mind && observer.mind.current && observer.mind.current.stat != DEAD)) + continue + ghost = observer + break + if(ghost) + icon_state = "golem2" + else + icon_state = "golem" + +/obj/effect/golemrune/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + var/mob/observer/ghost/ghost + for(var/mob/observer/ghost/observer in src.loc) + if(!observer.client) + continue + if(observer.mind && observer.mind.current && observer.mind.current.stat != DEAD) + continue + ghost = observer + break + if(!ghost) + to_chat(user, SPAN_WARNING("The rune fizzles uselessly.")) + return TRUE + visible_message(SPAN_WARNING("A craggy humanoid figure coalesces into being!")) + + var/mob/living/human/G = new(src.loc) + G.set_species(/decl/species/golem::uid) + G.key = ghost.key + + var/obj/item/implant/translator/natural/I = new() + I.implant_in_mob(G, user, BP_HEAD) + if (user.languages.len) + var/decl/language/lang = user.languages[1] + G.add_language(lang.type) + G.set_default_language(lang) + I.languages[lang.name] = 1 + + to_chat(G, FONT_LARGE(SPAN_BOLD("You are a golem. Serve [user] and assist them at any cost."))) + to_chat(G, SPAN_ITALIC("You move slowly and are vulnerable to trauma, but are resistant to heat and cold.")) + qdel(src) + return TRUE + +/obj/effect/golemrune/proc/announce_to_ghosts() + for(var/mob/observer/ghost/G in global.player_list) + if(G.client) + var/area/A = get_area(src) + if(A) + to_chat(G, "Golem rune created in [A.proper_name].") + diff --git a/mods/content/xenobiology/slime/items_cell.dm b/mods/content/xenobiology/slime/items_cell.dm new file mode 100644 index 000000000000..417af5723373 --- /dev/null +++ b/mods/content/xenobiology/slime/items_cell.dm @@ -0,0 +1,8 @@ +/obj/item/cell/slime + name = "charged slime core" + desc = "A yellow slime core that crackles with power." + origin_tech = @'{"powerstorage":2,"biotech":4}' + icon = 'mods/content/xenobiology/icons/slimes/slime_extract_yellow.dmi' + icon_state = ICON_STATE_WORLD + maxcharge = 200 + material = /decl/material/liquid/slimejelly diff --git a/mods/content/xenobiology/slime/items_extract_enhancer.dm b/mods/content/xenobiology/slime/items_extract_enhancer.dm new file mode 100644 index 000000000000..1e3faf9d7d9a --- /dev/null +++ b/mods/content/xenobiology/slime/items_extract_enhancer.dm @@ -0,0 +1,23 @@ +/obj/item/slime_extract_enhancer //#TODO: Probably should use /obj/item/chems with a proper reagent + name = "extract enhancer" + desc = "A potent chemical mix that will give a slime extract three uses." + icon = 'icons/obj/items/chem/bottle.dmi' + icon_state = "bottle17" + material = /decl/material/solid/organic/plastic + obj_flags = OBJ_FLAG_HOLLOW + +/obj/item/slime_extract_enhancer/afterattack(obj/target, mob/user , flag) + if(!istype(target, /obj/item/slime_extract)) + return ..() + var/obj/item/slime_extract/extract = target + if(extract.enhanced == TRUE) + to_chat(user, SPAN_WARNING("\The [extract] has already been enhanced!")) + return TRUE + if(extract.Uses <= 0) + to_chat(user, SPAN_WARNING("You can't enhance a used extract!")) + return TRUE + to_chat(user, SPAN_NOTICE("You apply \the [src] to \the [extract]. It now has triple the amount of uses.")) + extract.Uses = 3 + extract.enhanced = TRUE + qdel(src) + return TRUE diff --git a/mods/content/xenobiology/slime/items_potion.dm b/mods/content/xenobiology/slime/items_potion.dm new file mode 100644 index 000000000000..e0e97a63daeb --- /dev/null +++ b/mods/content/xenobiology/slime/items_potion.dm @@ -0,0 +1,37 @@ +/obj/item/slime_potion + name = "docility potion" + desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame." + icon = 'icons/obj/items/chem/bottle.dmi' + icon_state = "bottle19" + material = /decl/material/solid/glass + obj_flags = OBJ_FLAG_HOLLOW + var/slime_type = /mob/living/simple_animal/slime + var/can_tame_adults = FALSE + +/obj/item/slime_potion/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(isslime(target)) + var/mob/living/slime/slime = target + if(slime.is_adult && can_tame_adults) + to_chat(user, SPAN_WARNING("Only baby slimes can be tamed!")) + return TRUE + if(slime.stat) + to_chat(user, SPAN_WARNING("\The [slime] is dead!")) + return TRUE + if(slime.client) + to_chat(user, SPAN_WARNING("\The [slime] resists!")) + return TRUE + var/mob/living/simple_animal/slime/pet = new slime_type(slime.loc, slime.slime_type) + to_chat(user, SPAN_NOTICE("You feed \the [pet] the potion, removing its powers and calming it.")) + pet.prompt_rename(user) + qdel(slime) + qdel(src) + return TRUE + . = ..() + +/obj/item/slime_potion/advanced + name = "advanced docility potion" + desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes." + icon = 'icons/obj/items/chem/bottle.dmi' + icon_state = "bottle19" + slime_type = /mob/living/simple_animal/slime/adult + can_tame_adults = TRUE diff --git a/mods/content/xenobiology/slime/items_steroid.dm b/mods/content/xenobiology/slime/items_steroid.dm new file mode 100644 index 000000000000..f826f9cf5c4f --- /dev/null +++ b/mods/content/xenobiology/slime/items_steroid.dm @@ -0,0 +1,28 @@ +/obj/item/slime_steroid + name = "slime steroid" + desc = "A potent chemical mix that will cause a slime to generate more extract." + icon = 'icons/obj/items/chem/bottle.dmi' + icon_state = "bottle16" + material = /decl/material/solid/glass + obj_flags = OBJ_FLAG_HOLLOW + var/grant_cores = 3 + +/obj/item/slime_steroid/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(!isslime(target)) + return ..() + + var/mob/living/slime/slime = target + if(slime.is_adult) + to_chat(user, SPAN_WARNING("Only baby slimes can use \the [src]!")) + return TRUE + if(slime.stat == DEAD) + to_chat(user, SPAN_WARNING("\The [slime] is dead!")) + return TRUE + if(slime.cores >= grant_cores) + to_chat(user, SPAN_WARNING("\The [slime] already has the maximum amount of cores!")) + return TRUE + + to_chat(user, SPAN_NOTICE("You feed \the [src] to \the [slime] and it suddenly grows two extra cores.")) + slime.cores = grant_cores + qdel(src) + return TRUE diff --git a/mods/content/xenobiology/slime/life.dm b/mods/content/xenobiology/slime/life.dm new file mode 100644 index 000000000000..6cdecb39d6cc --- /dev/null +++ b/mods/content/xenobiology/slime/life.dm @@ -0,0 +1,154 @@ +/mob/living/slime/handle_environment(datum/gas_mixture/environment) + . = ..() + + if(environment) + var/delta = abs(bodytemperature - environment.temperature) + var/change = (delta / (delta > 50 ? 5 : 10)) + if(bodytemperature > environment.temperature) + change = -(change) + bodytemperature += (min(environment.temperature, bodytemperature + change) - bodytemperature) + if(bodytemperature <= die_temperature) + take_damage(200, TOX) + else if(bodytemperature <= hurt_temperature) + take_damage(30, TOX) + + // If we're standing on top of a dead mob or small items, we can + // ingest it (or just melt it a little if we're too small) + // Also helps to keep our cell tidy! + if(!length(loc?.contents)) + return + var/has_eaten_mob = locate(/mob) in contents + var/last_contents_length = length(contents) + for(var/atom/movable/AM in loc) + if(AM == src || !AM.simulated) + continue + if(isliving(AM) && !AM.anchored && !has_eaten_mob && !isslime(AM)) + var/mob/living/M = AM + if(M.stat == DEAD) + if(M.mob_size <= (is_adult ? MOB_SIZE_LARGE : MOB_SIZE_SMALL)) + M.forceMove(src) + else + adjust_nutrition(M.eaten_by_slime(src)) + break + else if(istype(AM, /obj/effect/decal/cleanable)) + if(!istype(AM, /obj/effect/decal/cleanable/dirt)) + adjust_nutrition(rand(2,3)) + qdel(AM) + else if(istype(AM, /obj/item) && !AM.anchored) + var/obj/item/thing = AM + if(istype(thing, /obj/item/remains) || (thing.w_class <= (is_adult ? ITEM_SIZE_LARGE : ITEM_SIZE_SMALL) && prob(5))) + AM.forceMove(src) + break + if(length(contents) != last_contents_length) + queue_icon_update() + +/mob/living/slime/handle_nutrition_and_hydration() + . = ..() + if(feeding_on) + slime_feed() + var/datum/reagents/metabolism/ingested = reagents + ingested.metabolize() + +/mob/living/slime/fluid_act(datum/reagents/fluids) + . = ..() + if(!QDELETED(src) && REAGENT_TOTAL_VOLUME(fluids) >= FLUID_SHALLOW && stat == DEAD) + var/turf/T = get_turf(src) + if(T) + T.add_to_reagents(/decl/material/liquid/slimejelly, (is_adult ? rand(30, 40) : rand(10, 30))) + visible_message(SPAN_DANGER("\The [src] melts away...")) // Slimes are water soluble. + qdel(src) + +/mob/living/slime/get_hunger_factor() + return (0.1 + 0.05 * is_adult) + +/mob/living/slime/get_thirst_factor() + return 0 + +/mob/living/slime/fluid_act(datum/reagents/fluids) + . = ..() + if(stat == DEAD && REAGENT_TOTAL_VOLUME(fluids) && REAGENT_VOLUME(fluids, /decl/material/liquid/water) >= FLUID_SHALLOW) + fluids.add_reagent(/decl/material/liquid/slimejelly, (is_adult ? rand(30, 40) : rand(10, 30))) + visible_message(SPAN_DANGER("\The [src] melts away...")) // Slimes are water soluble. + qdel(src) + +/mob/living/slime/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE + set_stat(CONSCIOUS) + if(prob(30)) + heal_damage(OXY, 1, do_update_health = FALSE) + heal_damage(TOX, 1, do_update_health = FALSE) + heal_damage(BURN, 1, do_update_health = FALSE) + heal_damage(CLONE, 1, do_update_health = FALSE) + heal_damage(BRUTE, 1) + +/mob/living/slime/handle_nutrition_and_hydration() + . = ..() + if(feeding_on) + slime_feed() + var/datum/reagents/metabolism/ingested = reagents + ingested.metabolize() + + // Digest whatever we've got floating around in our goop. + if(length(contents)) + var/last_contents_length = length(contents) + for(var/atom/movable/AM in contents) + if(ismob(AM)) + var/mob/hurk = AM + if(hurk.mob_size > (is_adult ? MOB_SIZE_LARGE : MOB_SIZE_SMALL)) + AM.dropInto(loc) + else if(isliving(AM)) + var/mob/living/M = AM + adjust_nutrition(M.eaten_by_slime(src)) + queue_icon_update() + break + + if(istype(AM, /obj/item/remains)) + if(prob(5)) + adjust_nutrition(rand(2,3)) + qdel(AM) + break + continue + + if(istype(AM, /obj/item)) + var/obj/item/thing = AM + if(prob(5) || thing.w_class > (is_adult ? ITEM_SIZE_LARGE : ITEM_SIZE_SMALL)) + thing.dropInto(loc) + break + continue + + AM.dropInto(loc) + break + + if(length(contents) != last_contents_length) + queue_icon_update() + + // Update starvation and nutrition. + if(nutrition <= 0) + take_damage(2, TOX) + if (client && prob(5)) + to_chat(src, SPAN_DANGER("You are starving!")) + else if(nutrition >= get_grow_nutrition() && amount_grown < SLIME_EVOLUTION_THRESHOLD) + adjust_nutrition(-20) + amount_grown++ + + ..() + +/mob/living/slime/get_satiated_nutrition() // Can't go above it + . = is_adult ? 1150 : 950 + +/mob/living/slime/get_max_nutrition() // Can't go above it + . = is_adult ? 1200 : 1000 + +/mob/living/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat + . = is_adult ? 1000 : 800 + +/mob/living/slime/proc/get_hunger_nutrition() // Below it we will always eat + . = is_adult ? 600 : 500 + +/mob/living/slime/proc/get_starve_nutrition() // Below it we will eat before everything else + . = is_adult ? 300 : 200 + +/mob/living/slime/slip(var/slipped_on, stun_duration = 8) //Can't slip something without legs. + return FALSE diff --git a/mods/content/xenobiology/slime/powers.dm b/mods/content/xenobiology/slime/powers.dm new file mode 100644 index 000000000000..b1338d02c4f9 --- /dev/null +++ b/mods/content/xenobiology/slime/powers.dm @@ -0,0 +1,59 @@ +/mob/living/slime/verb/slime_mature() + set name = "Mature" + set category = "Slime" + set desc = "Mature from a baby to an adult." + + if(is_adult) + to_chat(src, SPAN_WARNING("You are already an adult.")) + return + + if(incapacitated()) + to_chat(src, SPAN_WARNING("You are in no state to mature.")) + return + + if(amount_grown < SLIME_EVOLUTION_THRESHOLD) + to_chat(src, SPAN_WARNING("You are not yet developed enough to mature.")) + return + + is_adult = TRUE + max_health = 200 + amount_grown = 0 + update_name() + update_icon() + +/mob/living/slime/verb/slime_split() + set name = "Fission" + set category = "Slime" + set desc = "Split into four baby slimes, keeping control of a single one." + + if(incapacitated()) + to_chat(src, SPAN_WARNING("You are in no state to fission.")) + return + + if(!is_adult || amount_grown < SLIME_EVOLUTION_THRESHOLD) + to_chat(src, SPAN_WARNING("You are not yet developed enough to fission.")) + return + + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + var/list/babies + for(var/i = 1 to rand(slime_data.min_children, slime_data.max_children)) + var/baby_colour = (length(slime_data.descendants) && prob(mutation_chance)) ? pick(slime_data.descendants) : slime_type + LAZYADD(babies, new slime_data.child_type(loc, baby_colour)) + var/decl/slime_colour/baby_slime_data = GET_DECL(baby_colour) + SSstatistics.add_field_details("slime_babies_born","slimebirth_[replacetext(baby_slime_data.name," ","_")]") + + if(length(babies)) + var/mob/living/slime/player_baby = pick(babies) + player_baby.universal_speak = universal_speak + if(mind) + mind.transfer_to(player_baby) + else + player_baby.key = key + + var/datum/mob_controller/slime/my_ai = ai + for(var/mob/living/slime/baby in babies) + step_away(baby, src) + var/datum/mob_controller/slime/baby_ai = baby.ai + if(istype(baby_ai) && istype(my_ai)) + baby_ai.observed_friends = my_ai.observed_friends?.Copy() + qdel(src) diff --git a/mods/content/xenobiology/slime/say.dm b/mods/content/xenobiology/slime/say.dm new file mode 100644 index 000000000000..625d7b434501 --- /dev/null +++ b/mods/content/xenobiology/slime/say.dm @@ -0,0 +1,22 @@ +/mob/living/slime/say_quote(var/text) + var/ending = copytext(text, length(text)) + if (ending == "?") + return "asks" + else if (ending == "!") + return "cries" + return "chirps" + +/mob/living/slime/say_understands(mob/speaker, decl/language/speaking) + . = isslime(speaker) || ..() + +/mob/living/slime/hear_say(var/message, var/verb = "says", var/decl/language/language = null, var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai) && (weakref(speaker) in slime_ai.observed_friends)) + LAZYSET(slime_ai.speech_buffer, speaker, lowertext(html_decode(message))) + return ..() + +/mob/living/slime/hear_radio(var/message, var/verb="says", var/decl/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/vsource) + var/datum/mob_controller/slime/slime_ai = ai + if(istype(slime_ai) && (weakref(speaker) in slime_ai.observed_friends)) + LAZYSET(slime_ai.speech_buffer, speaker, lowertext(html_decode(message))) + return ..() diff --git a/mods/content/xenobiology/slime/slime_AI.dm b/mods/content/xenobiology/slime/slime_AI.dm new file mode 100644 index 000000000000..bf28ef6cd6bb --- /dev/null +++ b/mods/content/xenobiology/slime/slime_AI.dm @@ -0,0 +1,236 @@ +/datum/mob_controller/slime + expected_type = /mob/living/slime + var/mood + var/chase_target = 0 + var/weakref/leader + var/weakref/current_target // Currently attacking this mob (separate from feeding) + var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable + var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with + var/list/observed_friends // A list of refs to friends; they are not considered targets for feeding; passed down after splitting. + var/list/friendship_cooldown // A list of refs to friends and the next time they can increase friendship. + var/list/speech_buffer // Last phrase said near it and person who said it + var/mob/living/slime/slime + var/next_core_logic_run = 0 + var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place + +/datum/mob_controller/slime/New() + ..() + slime = body + +/datum/mob_controller/slime/Destroy() + observed_friends = null + friendship_cooldown = null + leader = null + current_target = null + speech_buffer = null + slime = null + . = ..() + +/datum/mob_controller/slime/proc/assess_target(var/mob/living/target) + if(!istype(target) || isslime(target) || (weakref(target) in observed_friends)) + return FALSE + if(target.stat != DEAD && (rabid || attacked)) + return TRUE + if(slime.check_valid_feed_target(target) == FEED_RESULT_VALID) + return TRUE + return FALSE + +/datum/mob_controller/slime/proc/update_mood() + if(!slime || !body) + return + body.set_intent(I_FLAG_HELP) + var/new_mood + if(HAS_STATUS(body, STAT_CONFUSE)) + new_mood = "pout" + else if(rabid || attacked) + new_mood = "angry" + body.set_intent(I_FLAG_HARM) + else if(current_target?.resolve()) + new_mood = "mischevous" + + if(!new_mood) + if(prob(1)) + new_mood = pick("sad", ":3") + else if(prob(75)) + new_mood = mood + + if(new_mood != mood) + mood = new_mood + body.update_icon() + +/datum/mob_controller/slime/do_process(time_elapsed) + + if(!(. = ..())) + return + + if(attacked > 0) + attacked = clamp(attacked--, 0, 50) + + if(!slime || body.stat || HAS_STATUS(slime, STAT_CONFUSE)) + return + + // A hungry slime begins losing its friends. + if(slime.nutrition < slime.get_starve_nutrition() && length(observed_friends) && prob(1)) + adjust_friendship(pick(observed_friends), -1) + + handle_targets() + if(world.time >= next_core_logic_run) + handle_core_logic() + handle_speech_and_mood() + +/datum/mob_controller/slime/proc/get_best_target(var/list/targets) + if(!length(targets)) + return + if(rabid || attacked) + return pick(targets) + targets = shuffle(targets) + for(var/mob/living/M in targets) + if(issmall(M)) + return M + . = targets[1] + +/datum/mob_controller/slime/proc/handle_targets() + + if(!slime || !body) + return + + if(slime.feeding_on) + current_target = null + return + + var/mob/actual_target = current_target?.resolve() + if(actual_target) + chase_target-- + if(chase_target <= 0 || attacked || rabid) // Tired of chasing or attacking everything nearby + chase_target = 0 + current_target = null + else + current_target = null + + var/hunger = slime.get_hunger_state() + var/mob/leader_mob = leader?.resolve() + actual_target = current_target?.resolve() + if(!actual_target) + var/feral = (attacked || rabid || hunger >= 2) + if(feral || (!leader_mob && !holding_still) || (hunger && prob(10))) + var/list/targets + for(var/mob/living/prey in view(7, body)) + if(assess_target(prey)) + LAZYADD(targets, prey) + if(length(targets)) + current_target = weakref(get_best_target(targets)) + chase_target = rand(5,7) + if(slime.is_adult) + chase_target += 3 + + if(holding_still) + holding_still = max(holding_still - 1 - hunger, 0) + else if(isturf(body?.loc)) + if(leader_mob) + step_to(body, get_dir(body, leader_mob)) + else if(prob(hunger ? 50 : 33)) + body.SelfMove(pick(global.cardinal)) + +/datum/mob_controller/slime/proc/handle_core_logic() + + if(!slime || !body) + return + + var/added_delay = 0 + var/mob/actual_target = current_target?.resolve() + if(slime.amount_grown >= SLIME_EVOLUTION_THRESHOLD && !actual_target) + if(slime.is_adult) + slime.slime_split() + else + slime.slime_mature() + added_delay = 10 + else + if(!assess_target(actual_target) || actual_target == slime.feeding_on || !(actual_target in view(7, body))) + current_target = null + + if(!actual_target) + if(prob(1)) + for(var/mob/living/slime/frenemy in range(1, body)) + if(frenemy != body && body.Adjacent(frenemy)) + body.set_intent((frenemy.slime_type == slime.slime_type) ? I_FLAG_HELP : I_FLAG_HARM) + body.UnarmedAttack(frenemy, TRUE) + added_delay = 10 + else if(slime.Adjacent(actual_target)) + var/do_attack = FALSE + if(issilicon(actual_target)) + body.set_intent(I_FLAG_HARM) + do_attack = TRUE + else if(actual_target.client && !actual_target.current_posture.prone && prob(60 + slime.powerlevel * 4)) + body.set_intent(I_FLAG_DISARM) + do_attack = TRUE + else if(slime.check_valid_feed_target(actual_target) == FEED_RESULT_VALID) + body.set_intent(I_FLAG_GRAB) + do_attack = TRUE + if(do_attack) + body.UnarmedAttack(actual_target, TRUE) + added_delay = 10 + else + current_target = null + else + step_to(body, actual_target) + + next_core_logic_run = world.time + max(body?.get_movement_delay(), 5) + added_delay + +/datum/mob_controller/slime/proc/handle_speech_and_mood() + + if(!slime || !body) + return + + update_mood() + + if(length(speech_buffer)) + + var/speaker = speech_buffer[1] // Who said it? + var/spoken = speech_buffer[speaker] // What did they say? + speech_buffer = null + + if(findtext(spoken, num2text(slime.number)) || findtext(spoken, "slimes")) + var/list/all_slime_commands = decls_repository.get_decls_of_subtype(/decl/slime_command) + for(var/command_type in all_slime_commands) + var/decl/slime_command/command = all_slime_commands[command_type] + var/response = command.resolve(speaker, spoken, src) + if(response) + body.say(response) + return + + if(prob(1)) + if(prob(50)) + body.emote(pick(/decl/emote/visible/bounce, /decl/emote/visible/sway, /decl/emote/visible/lightup, /decl/emote/visible/vibrate, /decl/emote/visible/jiggle)) + else + var/list/possible_comments + var/list/all_slime_comments = decls_repository.get_decls_of_subtype(/decl/slime_comment) + for(var/comment_type in all_slime_comments) + var/decl/slime_comment/comment = all_slime_comments[comment_type] + var/comment_text = comment.get_comment(src) + if(comment_text) + LAZYADD(possible_comments, comment_text) + if(length(possible_comments)) + body.say(pick(possible_comments)) + +/datum/mob_controller/slime/proc/adjust_friendship(var/atom/user, var/amount) + if(ismob(user)) + if(QDELING(user)) + return FALSE + user = weakref(user) + else if(istype(user, /weakref)) // verify the ref is still valid + var/weakref/user_ref = user + var/mob/resolved_user = user_ref.resolve() + if(!ismob(resolved_user) || QDELING(resolved_user)) + return FALSE + else + return FALSE + + if(amount > 0) + if(world.time < LAZYACCESS(friendship_cooldown, user)) + return FALSE + LAZYSET(friendship_cooldown, user, world.time + (1 MINUTE)) + LAZYINITLIST(observed_friends) + observed_friends[user] = observed_friends[user] + amount + if(observed_friends[user] <= 0) + LAZYREMOVE(observed_friends, user) + return TRUE diff --git a/mods/content/xenobiology/slime/slime_click.dm b/mods/content/xenobiology/slime/slime_click.dm new file mode 100644 index 000000000000..89353a1b2657 --- /dev/null +++ b/mods/content/xenobiology/slime/slime_click.dm @@ -0,0 +1,61 @@ +/mob/living/slime/RestrainedClickOn(var/atom/A) + return FALSE + +/mob/living/slime/ResolveUnarmedAttack(var/atom/A) + + . = ..() + if(.) + return + + // Eating + if(feeding_on || (locate(/mob) in contents)) + return FALSE + + //should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/mob/living/M = A + if(!istype(M)) + A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") // Basic attack. + return TRUE + + if(check_intent(I_FLAG_HELP)) + M.visible_message( \ + SPAN_NOTICE("\The [src] gently pokes \the [M]."), \ + SPAN_NOTICE("\The [src] gently pokes you.")) + return TRUE + + var/power = max(0, min(10, (powerlevel + rand(0, 3)))) + if(check_intent(I_FLAG_DISARM)) + var/stun_prob = 1 + if(powerlevel > 0 && !isslime(A)) + switch(power * 10) + if(0) stun_prob *= 10 + if(1 to 2) stun_prob *= 20 + if(3 to 4) stun_prob *= 30 + if(5 to 6) stun_prob *= 40 + if(7 to 8) stun_prob *= 60 + if(9) stun_prob *= 70 + if(10) stun_prob *= 95 + if(prob(stun_prob)) + var/shock_damage = max(0, powerlevel-3) * rand(6,10) + M.electrocute_act(shock_damage, src, 1.0, ran_zone()) + M.visible_message( \ + SPAN_DANGER("\The [src] pounces at \the [M]!"), \ + SPAN_DANGER("\The [src] pounces at you!")) + if(prob(40)) + SET_STATUS_MAX(src, STAT_WEAK, (power * 0.5)) + return TRUE + + if(check_intent(I_FLAG_GRAB) && slime_attach(M)) + return TRUE + + if(check_intent(I_FLAG_HARM)) + if(prob(15) && !M.current_posture.prone) + M.visible_message( \ + SPAN_DANGER("\The [src] pounces at \the [M]!"), \ + SPAN_DANGER("\The [src] pounces at you!")) + SET_STATUS_MAX(M, STAT_WEAK, (power * 0.5)) + else + A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") + return TRUE + return FALSE diff --git a/mods/content/xenobiology/slime/slime_codex.dm b/mods/content/xenobiology/slime/slime_codex.dm new file mode 100644 index 000000000000..ca16e9f8c58c --- /dev/null +++ b/mods/content/xenobiology/slime/slime_codex.dm @@ -0,0 +1,47 @@ + +/datum/codex_entry/slimes + associated_paths = list( + /mob/living/slime, + /obj/machinery/smartfridge/secure/extract, + /obj/item/slime_extract + ) + lore_text = "The strange, hydrophobic, single-celled organisms called 'slimes' are frequently the focus of xenobiological science, due to their fascinating internal chemistry and their incredible hardiness. However, they are frequently underestimated or mishandled, and slime-related genetic decay is a leading cause of death for xenoscientists." + mechanics_text = "Slimes will happily feed on any human, humanoid or monkey that wanders into their sight. You can wrestle them off their victim or spray them with a fire extinguisher to neutralize them. If a slime is well-fed, it might grow into an adult, and then split into up to four baby slimes of various colours, depending on the colour of the parent.

    Slime cores can have a variety of effects when injected with either blood or uranium powder. For more information on slime xenobiology, consult the guide." + +/datum/codex_entry/slime_handling + name = "Guide to Slime Handling" + mechanics_text = {" +

    The Basics

    +

    Slimes are strange creatures reared for their valuable extracts. They feed by engulfing their prey and degrading them at the cellular level, eventually dissolving them entirely. A hungry slime can be fended off with water, usually from a fire extinguisher; don't bother trying to use weapons or firearms on a being made of semiliquid goo. You can wrestle a slime off its prey, including yourself, by clicking on it with disarm, harm or grab intent.

    +

    Slime Breeding

    +

    When a baby slime is well-fed enough, it will mature into an adult; adults are much larger, much more dangerous, and capable of reproducing by splitting into four smaller slimes. Each of the children has a chance of mutating into a different colour, with different effects associated with their extracts. See the table at the bottom of this guide for a list of parent and child colours.

    +

    Extracts and Reactions

    +

    If you cull a baby slime, either by water or starvation, you can then drag it over to the operating table and use a scalpel and saw to remove the slime cores inside. These cores can be injected with ground-up uranium (use the reagent grinder in your lab), or blood (either your own or from a donor), to evoke strange and powerful effects. Consult the bottom of this guide for details on extract reactions.

    +

    Friendship

    +

    Slimes are intelligent, social creatures, even if they don't look like it. Physical affection (click a slime on help intent) will start an enduring friendship that will last until you attack the slime, or it gets hungry enough to see you as food. Saying hello to a friendly slime will also make them regard you more fondly. Slimes that regard you well enough may even listen to commands like 'stop', 'stay' or 'follow'.

    + "} + +/datum/codex_entry/slime_handling/New(_display_name, list/_associated_paths, list/_associated_strings, _lore_text, _mechanics_text, _antag_text) + . = ..() + var/list/extra_mechanics_text = list() + extra_mechanics_text += "

    Slime colours


    " + extra_mechanics_text += "" + var/list/slime_colours = decls_repository.get_decls_of_subtype(/decl/slime_colour) + for(var/slime_type in slime_colours) + var/decl/slime_colour/slime_data = slime_colours[slime_type] + var/list/child_colours = list(slime_data.name) + for(var/child_type in slime_data.descendants) + var/decl/slime_colour/child_colour = GET_DECL(child_type) + child_colours |= child_colour.name + var/list/ancestors = list(slime_data.name) + for(var/ancestor_type in slime_colours) + var/decl/slime_colour/ancestor_data = slime_colours[ancestor_type] + if(slime_type in ancestor_data.descendants) + ancestors |= ancestor_data.name + extra_mechanics_text += "" + mechanics_text = "[mechanics_text]
    [jointext(extra_mechanics_text, "")]" diff --git a/mods/content/xenobiology/slime/slime_commands.dm b/mods/content/xenobiology/slime/slime_commands.dm new file mode 100644 index 000000000000..3be381f2a01f --- /dev/null +++ b/mods/content/xenobiology/slime/slime_commands.dm @@ -0,0 +1,85 @@ +/decl/slime_command + var/list/triggers + +/decl/slime_command/proc/resolve(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) + for(var/trigger in triggers) + if(findtext(spoken, trigger)) + return get_response(speaker, spoken, holder) + +/decl/slime_command/proc/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) + return + +/decl/slime_command/hello + triggers = list("hello", "hi") + +/decl/slime_command/hello/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) + holder.adjust_friendship(speaker, rand(1,2)) + return pick("Hello...", "Hi...") + +/decl/slime_command/follow + triggers = list("follow") + +/decl/slime_command/follow/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) + var/mob/leader_mob = holder.leader?.resolve() + if(leader_mob) + if(leader_mob == speaker) + return pick("Yes...", "Lead...", "Following...") + if(LAZYACCESS(holder.observed_friends, weakref(speaker)) > LAZYACCESS(holder.observed_friends, holder.leader)) + holder.leader = weakref(speaker) + return "Yes... I follow [speaker]..." + return "No... I follow [leader_mob]..." + if(LAZYACCESS(holder.observed_friends, weakref(speaker)) > 2) + holder.leader = weakref(speaker) + return "I follow..." + return pick("No...", "I won't follow...") + +/decl/slime_command/stop + triggers = list("stop") + +/decl/slime_command/stop/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) + var/friendship = LAZYACCESS(holder.observed_friends, weakref(speaker)) + if(holder.slime.feeding_on) + if(friendship > 4) + holder.slime.set_feeding_on() + holder.current_target = null + if(friendship < 7) + holder.adjust_friendship(speaker, -1) + return "Grrr..." + return "Fine..." + var/mob/actual_target = holder.current_target?.resolve() + if(actual_target) + if(friendship > 3) + holder.current_target = null + if(friendship < 6) + holder.adjust_friendship(speaker, -1) + return "Grrr..." + return "Fine..." + var/mob/leader_mob = holder.leader?.resolve() + if(leader_mob) + if(leader_mob == speaker) + holder.leader = null + return "Yes... I'll stop..." + if(friendship > LAZYACCESS(holder.observed_friends, holder.leader)) + holder.leader = null + return "Yes... I'll stop..." + return "No... I'll keep following..." + +/decl/slime_command/stay + triggers = list("stay") + +/decl/slime_command/stay/get_response(var/speaker, var/spoken, var/datum/mob_controller/slime/holder) + var/friendship = LAZYACCESS(holder.observed_friends, weakref(speaker)) + var/mob/leader_mob = holder.leader?.resolve() + if(leader_mob) + if(leader_mob == speaker) + holder.holding_still = friendship * 10 + return "Yes... Staying..." + var/leader_friendship = LAZYACCESS(holder.observed_friends, holder.leader) + if(friendship > leader_friendship) + holder.holding_still = (friendship - leader_friendship) * 10 + return "Yes... Staying..." + return "No... I'll keep following..." + if(friendship > 2) + holder.holding_still = friendship * 10 + return "Yes... Staying..." + return "No... I won't stay..." diff --git a/mods/content/xenobiology/slime/slime_comments.dm b/mods/content/xenobiology/slime/slime_comments.dm new file mode 100644 index 000000000000..f009e3131236 --- /dev/null +++ b/mods/content/xenobiology/slime/slime_comments.dm @@ -0,0 +1,78 @@ +/decl/slime_comment/proc/get_comment(var/datum/mob_controller/slime/holder) + return + +/decl/slime_comment/general/get_comment(var/datum/mob_controller/slime/holder) + . = list("Rawr...", "Blop...", "Blorble...") + if(holder.mood == ":3") + . += "Purr..." + else if(holder.mood == "sad") + . += "Bored..." + if(holder.attacked) + . += "Grrr..." + if(holder.body.get_damage(TOX) > 30) + . += "Cold..." + if(holder.body.get_damage(TOX) > 60) + . += list("So... cold...", "Very... cold...") + if(holder.body.get_damage(TOX) > 90) + . += "C... c..." + if(holder.slime.feeding_on) + . += list("Nom...", "Tasty...") + return pick(.) + +/decl/slime_comment/hungry/get_comment(var/datum/mob_controller/slime/holder) + if(prob(2)) + . = list() + var/tension = 10 + if(holder.slime.nutrition < holder.slime.get_hunger_nutrition()) + . += list("Hungry...", "Where is the food?", "I want to eat...") + tension += 10 + if(holder.slime.nutrition < holder.slime.get_starve_nutrition()) + . += list("So... hungry...", "Very... hungry...", "Need... food...", "Must... eat...") + tension += 10 + var/mob/actual_target = holder.current_target?.resolve() + if(actual_target) + . += "\The [actual_target]... looks tasty..." + if(length(.) && prob(tension)) + return pick(.) + +/decl/slime_comment/zap/get_comment(var/datum/mob_controller/slime/holder) + if(holder.slime.powerlevel > 3) + . = list("Bzzz...") + if(holder.slime.powerlevel > 5) + . += "Zap..." + if(holder.slime.powerlevel > 8) + . += "Zap... Bzz..." + return pick(.) + +/decl/slime_comment/rabid/get_comment(var/datum/mob_controller/slime/holder) + if (holder.rabid || holder.attacked) + return pick("Hrr...", "Nhuu...", "Unn...") + +/decl/slime_comment/friends/get_comment(var/datum/mob_controller/slime/holder) + var/slimes_near = 0 + var/dead_slimes = 0 + var/friends_near = list() + for(var/mob/living/M in view(7, holder.body)) + if(M == holder.body) + continue + if(isslime(M)) + slimes_near++ + if(M.stat == DEAD) + dead_slimes++ + if(weakref(M) in holder.observed_friends) + friends_near += M + . = list() + if(slimes_near == 1) + . += "Brother..." + else if(slimes_near > 1) + . += "Brothers..." + else + . += "Lonely..." + if(dead_slimes) + . += "What happened?" + for(var/friend in friends_near) + . += "\The [friend]... friend..." + if(holder.slime.nutrition < holder.slime.get_hunger_nutrition()) + . += "\The [friend]... feed me..." + if(length(.)) + return pick(.) diff --git a/mods/content/xenobiology/slime/slime_follow.dm b/mods/content/xenobiology/slime/slime_follow.dm new file mode 100644 index 000000000000..5329468b269c --- /dev/null +++ b/mods/content/xenobiology/slime/slime_follow.dm @@ -0,0 +1,4 @@ +/datum/follow_holder/slime + sort_order = 6 + followed_type = /mob/living/slime + suffix = "Slime" diff --git a/mods/content/xenobiology/slime/slime_reagents.dm b/mods/content/xenobiology/slime/slime_reagents.dm new file mode 100644 index 000000000000..6fd150032bd5 --- /dev/null +++ b/mods/content/xenobiology/slime/slime_reagents.dm @@ -0,0 +1,56 @@ +/decl/material/liquid/slimejelly + name = "slime jelly" + uid = "chem_slime_jelly" + lore_text = "A gooey semi-liquid produced from one of the deadliest lifeforms in existence." + taste_description = "slime" + taste_mult = 1.3 + toxicity = 10 + heating_products = list( + /decl/material/liquid/denatured_toxin = 1 + ) + heating_point = 100 CELSIUS + heating_message = "becomes clear." + color = "#cf3600" + metabolism = REM * 0.25 + opacity = 0.7 // copied from cherry jelly + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/water/affect_touch(var/mob/living/victim, var/removed, var/datum/reagents/holder) + . = ..() + if(isslime(victim)) + victim.take_damage(10 * removed, TOX) + var/mob/living/slime/slime_victim = victim + if(istype(slime_victim) && istype(slime_victim.ai, /datum/mob_controller/slime)) + var/datum/mob_controller/slime/slime_ai = slime_victim.ai + if(slime_ai.current_target) // don't bother resolving it, we're just clearing it + slime_ai.current_target = null + slime_victim.set_feeding_on() + if(CHEM_DOSE(victim, src) == removed) + var/reagent_name = get_reagent_name(holder) // mostly to check masked name, but handles phase too + victim.visible_message( \ + SPAN_DANGER("\The [slime_victim]'s flesh sizzles where \the [reagent_name] touches it!"), \ + SPAN_DANGER("Your flesh is burned by \the [reagent_name]!")) + SET_STATUS_MAX(victim, STAT_CONFUSE, 2) + var/datum/mob_controller/slime/slime_ai = victim.ai + if(istype(slime_ai)) + slime_ai.attacked = max(slime_ai.attacked, rand(7,10)) // angery + +/decl/material/liquid/water/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + if(isslime(M)) + M.take_damage(2 * removed, TOX) + +/decl/material/liquid/frostoil/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + if(isslime(M)) + M.bodytemperature = max(M.bodytemperature - rand(10,20), 0) + +/decl/material/liquid/capsaicin/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + if(isslime(M)) + M.bodytemperature += rand(0, 15) + slime_temp_adj + +/decl/material/liquid/capsaicin/condensed/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + ..() + if(isslime(M)) + M.bodytemperature += rand(15, 30) diff --git a/mods/content/xenobiology/slime/slime_surgery.dm b/mods/content/xenobiology/slime/slime_surgery.dm new file mode 100644 index 000000000000..b63388aaf918 --- /dev/null +++ b/mods/content/xenobiology/slime/slime_surgery.dm @@ -0,0 +1,124 @@ +//Procedures in this file: Slime surgery, core extraction. +////////////////////////////////////////////////////////////////// +// SLIME CORE EXTRACTION // +////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////// +// generic slime surgery step datum +////////////////////////////////////////////////////////////////// +/decl/surgery_step/slime + allowed_species = null + disallowed_species = null + expected_mob_type = /mob/living/slime + hidden_from_codex = TRUE + abstract_type = /decl/surgery_step/slime + +/decl/surgery_step/slime/is_valid_target(mob/living/slime/target) + return isslime(target) + +/decl/surgery_step/slime/assess_bodypart(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + return TRUE + +/decl/surgery_step/slime/assess_surgery_candidate(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + return isslime(target) && target.stat == DEAD + +/decl/surgery_step/slime/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool) + return list(SKILL_SCIENCE = SKILL_ADEPT) + +////////////////////////////////////////////////////////////////// +// slime flesh cutting surgery step +////////////////////////////////////////////////////////////////// +/decl/surgery_step/slime/cut_flesh + name = "Make incision in slime" + description = "This procedure begins slime core removal surgery by cutting an incision open." + allowed_tools = list(TOOL_SCALPEL = 100) + min_duration = 5 + max_duration = 2 SECONDS + +/decl/surgery_step/slime/cut_flesh/can_use(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + return ..() && istype(target) && target.core_removal_stage == 0 + +/decl/surgery_step/slime/cut_flesh/begin_step(mob/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ + "You start cutting through [target]'s flesh with \the [tool].") + ..() + +/decl/surgery_step/slime/cut_flesh/end_step(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] cuts through [target]'s flesh with \the [tool].", \ + "You cut through [target]'s flesh with \the [tool], revealing its silky innards.") + target.core_removal_stage = 1 + ..() + +/decl/surgery_step/slime/cut_flesh/fail_step(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \ + "Your hand slips, tearing [target]'s flesh with \the [tool]!") + ..() + +////////////////////////////////////////////////////////////////// +// slime innards cutting surgery step +////////////////////////////////////////////////////////////////// +/decl/surgery_step/slime/cut_innards + name = "Dissect innards" + description = "This procedure disconnects slime cores from the innards." + allowed_tools = list(TOOL_SCALPEL = 100) + min_duration = 5 + max_duration = 2 SECONDS + +/decl/surgery_step/slime/cut_innards/can_use(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + return ..() && istype(target) && target.core_removal_stage == 1 + +/decl/surgery_step/slime/cut_innards/begin_step(mob/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ + "You start cutting [target]'s silky innards apart with \the [tool].") + ..() + +/decl/surgery_step/slime/cut_innards/end_step(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \ + "You cut [target]'s innards apart with \the [tool], exposing the cores.") + target.core_removal_stage = 2 + ..() + +/decl/surgery_step/slime/cut_innards/fail_step(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message("[user]'s hand slips, tearing [target]'s innards with \the [tool]!", \ + "Your hand slips, tearing [target]'s innards with \the [tool]!") + ..() + +////////////////////////////////////////////////////////////////// +// slime core removal surgery step +////////////////////////////////////////////////////////////////// +/decl/surgery_step/slime/saw_core + name = "Remove slime core" + description = "This procedure completely separates a slime cores and allows it to be removed." + allowed_tools = list( + TOOL_SAW = 100, + TOOL_HATCHET = 75 + ) + min_duration = 1 SECOND + max_duration = 3 SECONDS + +/decl/surgery_step/slime/saw_core/can_use(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + return ..() && (istype(target) && target.core_removal_stage == 2 && target.cores > 0) //This is being passed a human as target, unsure why. + +/decl/surgery_step/slime/saw_core/begin_step(mob/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message( + SPAN_NOTICE("\The [user] starts cutting out one of \the [target]'s cores with \the [tool]."), \ + SPAN_NOTICE("You start cutting out one of \the [target]'s cores with \the [tool].")) + ..() + +/decl/surgery_step/slime/saw_core/end_step(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + if(target.cores <= 0) + to_chat(user, SPAN_WARNING("You cannot find any cores within \the [target].")) + return + var/atom/core = new /obj/item/slime_extract(target.loc, /decl/material/liquid/slimejelly, target.slime_type) + target.cores-- + user.visible_message( + SPAN_NOTICE("\The [user] cuts \the [core] out of \the [target] with \the [tool]."), \ + SPAN_NOTICE("You cut \the [core] out of \the [target] with \the [tool]. It looks like there are [target.cores] core\s left.")) + target.update_icon() + ..() + +/decl/surgery_step/slime/saw_core/fail_step(mob/living/user, mob/living/slime/target, target_zone, obj/item/tool) + user.visible_message( + SPAN_DANGER("\The [user]'s hand slips, failing to extract the slime core."), \ + SPAN_DANGER("Your hand slips, causing you to miss the core!")) + ..() diff --git a/mods/content/xenobiology/slime/slime_update_icon.dm b/mods/content/xenobiology/slime/slime_update_icon.dm new file mode 100644 index 000000000000..b251188a33dd --- /dev/null +++ b/mods/content/xenobiology/slime/slime_update_icon.dm @@ -0,0 +1,32 @@ +/mob/living/slime/on_update_icon() + + var/decl/slime_colour/slime_data = GET_DECL(slime_type) + icon = (stat != DEAD && is_adult) ? slime_data.adult_icon : slime_data.baby_icon // dead adults have no icon + icon_state = initial(icon_state) + if(stat == DEAD) + icon_state = "[icon_state]-[cores ? "dead" : "nocore"]" + else if(feeding_on) + icon_state = "[icon_state]-eat" + reset_layer() + + ..() + + var/datum/mob_controller/slime/slime_ai = ai + if(stat != DEAD && istype(slime_ai) && slime_ai.mood) + add_overlay(image(slime_data.mood_icon, "aslime-[slime_ai.mood]")) + + var/list/new_underlays + for(var/atom/movable/AM in contents) + var/mutable_appearance/MA = new(AM) + MA.layer = FLOAT_LAYER + MA.plane = FLOAT_PLANE + MA.add_filter("slime_mask", 1, list(type = "alpha", render_source="slime_\ref[src]")) + LAZYADD(new_underlays, MA) + underlays = new_underlays + +/mob/living/slime/get_base_layer() + if(stat != DEAD && feeding_on) + var/atom/feed_mob = feeding_on.resolve() + if(istype(feed_mob)) + return max(ABOVE_HUMAN_LAYER, feed_mob.layer + 0.5) + return ..() diff --git a/mods/content/xenobiology/species/golem.dm b/mods/content/xenobiology/species/golem.dm new file mode 100644 index 000000000000..afb79c1f4cad --- /dev/null +++ b/mods/content/xenobiology/species/golem.dm @@ -0,0 +1,53 @@ +/decl/bodytype/crystalline/golem + name = "humanoid" + bodytype_category = BODYTYPE_HUMANOID + icon_base = 'icons/mob/human_races/species/golem/body.dmi' + husk_icon = 'icons/mob/human_races/species/golem/husk.dmi' + body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_PAIN | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS + has_organ = list( + BP_BRAIN = /obj/item/organ/internal/brain/golem + ) + uid = "bodytype_crystalline_golem" + +/decl/species/golem + uid = "species_golem" + name = "Golem" + name_plural = "Golems" + hidden_from_codex = TRUE + + available_bodytypes = list(/decl/bodytype/crystalline/golem) + + species_flags = SPECIES_FLAG_NO_POISON + spawn_flags = SPECIES_IS_RESTRICTED + shock_vulnerability = 0 + + butchery_data = /decl/butchery_data/crystal + + breath_type = null + poison_types = null + + blood_types = list(/decl/blood_type/coolant) + + flesh_color = "#137e8f" + + death_message = "becomes completely motionless..." + available_pronouns = list(/decl/pronouns/neuter) + + force_background_info = list( + /decl/background_category/heritage = /decl/background_detail/heritage/hidden/cultist, + /decl/background_category/homeworld = /decl/background_detail/location/stateless, + /decl/background_category/citizenship = /decl/background_detail/citizenship/synthetic, + /decl/background_category/faction = /decl/background_detail/faction/other + ) + + traits = list(/decl/trait/metabolically_inert = TRAIT_LEVEL_EXISTS) + +/decl/species/golem/handle_post_spawn(var/mob/living/human/H) + if(H.mind) + H.mind.reset() + H.mind.assigned_role = "Golem" + H.mind.assigned_special_role = "Golem" + H.real_name = "golem ([rand(1, 1000)])" + H.SetName(H.real_name) + H.status_flags |= NO_ANTAG + ..() diff --git a/mods/content/xenobiology/species/golem_organs.dm b/mods/content/xenobiology/species/golem_organs.dm new file mode 100644 index 000000000000..cbf569bebab9 --- /dev/null +++ b/mods/content/xenobiology/species/golem_organs.dm @@ -0,0 +1,9 @@ +/obj/item/organ/internal/brain/golem + name = "chem" + desc = "A tightly furled roll of paper, covered with indecipherable runes." + icon = 'icons/obj/items/paperwork/scroll.dmi' + icon_state = "scroll" + color = COLOR_BEIGE + +/obj/item/organ/internal/brain/golem/can_recover() + return FALSE diff --git a/mods/corporate/away_sites/lar_maria/lar_maria.dm b/mods/corporate/away_sites/lar_maria/lar_maria.dm deleted file mode 100644 index 7541a1c2e1e6..000000000000 --- a/mods/corporate/away_sites/lar_maria/lar_maria.dm +++ /dev/null @@ -1,228 +0,0 @@ -#include "../../_corporate.dme" -#include "lar_maria_areas.dm" - -/obj/effect/overmap/visitable/sector/lar_maria - name = "Lar Maria space station" - desc = "Sensors detect an orbital station with low energy profile and sporadic life signs." - icon_state = "object" - known = 0 - -/datum/map_template/ruin/away_site/lar_maria - name = "Lar Maria" - id = "awaysite_lar_maria" - description = "An orbital virus research station." - suffixes = list("lar_maria/lar_maria-1.dmm", "lar_maria/lar_maria-2.dmm") - cost = 2 - area_usage_test_exempted_root_areas = list(/area/lar_maria) - -///////////////////////////////////crew and prisoners -/obj/effect/landmark/corpse/lar_maria - eye_colors_per_species = list(SPECIES_HUMAN = list(COLOR_RED))//red eyes - skin_tones_per_species = list(SPECIES_HUMAN = list(-15)) - facial_styles_per_species = list(SPECIES_HUMAN = list("Shaved")) - genders_per_species = list(SPECIES_HUMAN = list(MALE)) - -/mob/living/simple_animal/hostile/lar_maria - name = "Lar Maria hostile mob" - desc = "You shouldn't see me!" - icon = 'mods/corporate/away_sites/lar_maria/lar_maria_sprites.dmi' - unsuitable_atmos_damage = 15 - environment_smash = 1 - faction = "lar_maria" - status_flags = CANPUSH - speak = list("Die!", "Fresh meat!", "Hurr!", "You said help will come!", "I did nothing!", "Eat my fist!", "One for the road!") - speak_chance = 50 - emote_hear = list("roars", "giggles", "breathes loudly", "mumbles", "yells something unintelligible") - emote_see = list("cries", "grins insanely", "itches fiercly", "scratches his face", "shakes his fists above his head") - turns_per_move = 5 - response_help = "pokes" - response_disarm = "shoves" - response_harm = "hits" - speed = 8 - can_escape = TRUE - stop_automated_movement_when_pulled = 0 - natural_weapon = /obj/item/natural_weapon/punch - var/obj/effect/landmark/corpse/lar_maria/corpse = null - var/weapon = null - -/mob/living/simple_animal/hostile/lar_maria/death(gibbed, deathmessage, show_dead_message) - ..(gibbed, deathmessage, show_dead_message) - if(corpse) - new corpse (src.loc) - if (weapon) - new weapon(src.loc) - visible_message("Small shining spores float away from dying [src]!") - qdel(src) - -/mob/living/simple_animal/hostile/lar_maria/test_subject - name = "\improper test subject" - desc = "Sick, filthy, angry and probably crazy human in an orange robe." - icon_state = "test_subject" - icon_living = "test_subject" - icon_dead = "test_subject_dead" - maxHealth = 40 - health = 40 - corpse = /obj/effect/landmark/corpse/lar_maria/test_subject - -/obj/effect/landmark/corpse/lar_maria/test_subject - name = "Dead test subject" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/test_subject) - spawn_flags = CORPSE_SPAWNER_NO_RANDOMIZATION//no name, no hairs etc. - -/decl/hierarchy/outfit/corpse/test_subject - name = "Dead ZHP test subject" - uniform = /obj/item/clothing/under/color/orange - shoes = /obj/item/clothing/shoes/color/orange - -/obj/effect/landmark/corpse/lar_maria/zhp_guard - name = "dead guard" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/zhp_guard) - skin_tones_per_species = list(SPECIES_HUMAN = list(-15)) - -/obj/effect/landmark/corpse/lar_maria/zhp_guard/dark - skin_tones_per_species = list(SPECIES_HUMAN = list(-115)) - -/decl/hierarchy/outfit/corpse/zhp_guard - name = "Dead ZHP guard" - uniform = /obj/item/clothing/under/rank/virologist - suit = /obj/item/clothing/suit/armor/pcarrier - head = /obj/item/clothing/head/soft/lar_maria/zhp_cap - shoes = /obj/item/clothing/shoes/jackboots/duty - l_ear = /obj/item/radio/headset - -/mob/living/simple_animal/hostile/lar_maria/guard//angry guards armed with batons and shotguns. Still bite - name = "\improper security" - desc = "Guard dressed at Zeng-Hu Pharmaceuticals uniform." - icon_state = "guard_light" - maxHealth = 60 - health = 60 - natural_weapon = /obj/item/baton - weapon = /obj/item/baton - corpse = /obj/effect/landmark/corpse/lar_maria/zhp_guard - -/mob/living/simple_animal/hostile/lar_maria/guard/Initialize() - . = ..() - var/skin_color = pick(list("light","dark")) - icon_state = "guard_[skin_color]" - if (skin_color == "dark") - corpse = /obj/effect/landmark/corpse/lar_maria/zhp_guard/dark - -/mob/living/simple_animal/hostile/lar_maria/guard/ranged - weapon = /obj/item/gun/projectile/shotgun/pump - ranged = 1 - projectiletype = /obj/item/projectile/bullet/shotgun/beanbag - -/mob/living/simple_animal/hostile/lar_maria/guard/ranged/Initialize() - . = ..() - icon_state = "[icon_state]_ranged" - -/obj/item/clothing/head/soft/lar_maria/zhp_cap - name = "Zeng-Hu Pharmaceuticals cap" - icon = 'mods/corporate/away_sites/lar_maria/lar_maria_sprites.dmi' - desc = "A green cap with Zeng-Hu Pharmaceuticals symbol on it." - icon_state = "zhp_cap" - item_icons = list(slot_head_str = 'mods/corporate/away_sites/lar_maria/lar_maria_clothing_sprites.dmi') - -/mob/living/simple_animal/hostile/lar_maria/virologist - name = "\improper virologist" - desc = "Virologist dressed at Zeng-Hu Pharmaceuticals uniform." - icon_state = "virologist_m" - maxHealth = 50 - health = 50 - corpse = /obj/effect/landmark/corpse/lar_maria/virologist - -/obj/effect/landmark/corpse/lar_maria/virologist - name = "dead virologist" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/zhp_virologist) - -/decl/hierarchy/outfit/corpse/zhp_virologist - name = "Dead male ZHP virologist" - uniform = /obj/item/clothing/under/rank/virologist - suit = /obj/item/clothing/suit/storage/toggle/labcoat - shoes = /obj/item/clothing/shoes/color/white - gloves = /obj/item/clothing/gloves/latex/nitrile - head = /obj/item/clothing/head/surgery - mask = /obj/item/clothing/mask/surgical - glasses = /obj/item/clothing/glasses/eyepatch/hud/medical - -/mob/living/simple_animal/hostile/lar_maria/virologist/female - icon_state = "virologist_f" - weapon = /obj/item/scalpel - corpse = /obj/effect/landmark/corpse/lar_maria/virologist_female - -/obj/effect/landmark/corpse/lar_maria/virologist_female - name = "dead virologist" - corpse_outfits = list(/decl/hierarchy/outfit/corpse/zhp_virologist_female) - hair_styles_per_species = list(SPECIES_HUMAN = list("Flaired Hair")) - hair_colors_per_species = list(SPECIES_HUMAN = list("#ae7b48")) - genders_per_species = list(SPECIES_HUMAN = list(FEMALE)) - -/decl/hierarchy/outfit/corpse/zhp_virologist_female - name = "Dead female ZHP virologist" - uniform = /obj/item/clothing/under/rank/virologist - suit = /obj/item/clothing/suit/storage/toggle/labcoat - shoes = /obj/item/clothing/shoes/color/white - gloves = /obj/item/clothing/gloves/latex/nitrile - mask = /obj/item/clothing/mask/surgical - -////////////////////////////Notes and papers -/obj/item/paper/lar_maria/note_1 - name = "paper note" - info = {" -
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - We received the latest batch of subjects this evening. Evening? Is it even evening? The schedule out here is so fucked in terms of sleep-cycles I forget to even check what time it is sometimes. I'm pretty sure it's evening anyway. Anyway, point is, we got the new guys, and thus far they seem like they fit the criteria pretty well. No family histories of diseases or the like, no current illnesses, prime physical condition, perfect subjects for our work. Tomorrow we start testing out the type 008 Serum. Hell if I know where this stuff's coming from, but it's fascinating. Injected into live subjects, it seems like it has a tendancy to not only cure them of ailments, but actually improve their bodily functions... - "} - -/obj/item/paper/lar_maria/note_2 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - I can't believe it, the type 8 Serum seems to actually have a regenerative effect on the subjects. We actually cut one's arm open during the test and ten minutes later, it had clotted. Fifteen and it was healing, and within two hours it was nothing but a fading scar. This is insanity, and the worst part is, we can't even determine HOW it does it yet. All these samples of the goo and not a damn clue how it works, it's infuriating! I'm going to try some additional tests with this stuff. I've heard it's got all kinds of uses, fuel enhancer, condiment, so on and so forth, even with this minty taste, but we'll see. There's got to be some rhyme or reason to this damned stuff. - "} - -/obj/item/paper/lar_maria/note_3 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - The samples of Type 8 we've got are almost out, but it seems like we're actually onto something major here. We'll need to get more sent over asap. This stuff may well be the key to immortality. We cut off one of the test subject's arms and they just put it back on and it healed in an hour or so to the point it was working fine. It's nothing short of miraculous. - "} - -/obj/item/paper/lar_maria/note_4 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - Tedd, don't get into the cells with the Type 8 subjects anymore, something's off about them the last couple days. They haven't been moving right, and they seem distracted nearly constantly, and not in a normal way. They also look like they're turning kinda... green? One of the other guys says it's probably just a virus or something reacting with it, but I don't know, something seems off. - "} - -/obj/item/paper/lar_maria/note_5 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - This is a reminder to all facility staff, while we may be doing important work for the good of humanity here, our methods are not necessarily one hundred percent legal, and as such you are NOT permitted, as outlined in your contract, to discuss the nature of your work, nor any other related information, with anyone not directly involved with the project without express permission of your facility director. This includes family, friends, local or galactic news outlets and bluenet chat forums. - "} - -/obj/item/paper/lar_maria/note_6 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - Due to the recent incident in the labs involving Type 8 test subject #12 and #33, all research personnel are to refrain from interacting directly with the research subjects involved in serum type 8 testing without the presence of armed guards and full Biohazard protective measures in place. - "} - -/obj/item/paper/lar_maria/note_7 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - Can we get some more diversity in test subjects? I know we're mostly working with undesirables, but criminals and frontier colonists aren't exactly the most varied bunch. We could majorly benefit from having some non-human test subjects, for example. Oooh, or one of those snake things Xynergy's got a monopoly on. - "} - -/obj/item/paper/lar_maria/note_8 - name = "paper note" - info = {"
    Zeng-Hu Pharmaceuticals
    -
    CONFIDENTIAL USE ONLY
    - On a related note, can we get some more female subjects? There's been some discussion about gender related differences in reactions to some of the chemicals we're working on. Testosterone and shit affecting chemical balances or something, I'm not sure, point is, variety. - "} - -/obj/item/paper/lar_maria/note_9 - name = "paper note" - info = "can we get some fresh carp sometime? Or freshish? Or frozen? I just really want carp, ok? I'm willing to pay for it if so." diff --git a/mods/corporate/away_sites/lar_maria/lar_maria_sprites.dmi b/mods/corporate/away_sites/lar_maria/lar_maria_sprites.dmi deleted file mode 100644 index c2199908072b..000000000000 Binary files a/mods/corporate/away_sites/lar_maria/lar_maria_sprites.dmi and /dev/null differ diff --git a/mods/corporate/clothing/accessories/armbands.dm b/mods/corporate/clothing/accessories/armbands.dm deleted file mode 100644 index 711ab84bbe92..000000000000 --- a/mods/corporate/clothing/accessories/armbands.dm +++ /dev/null @@ -1,6 +0,0 @@ -/obj/item/clothing/accessory/armband/whitered - name = "corporate armband" - desc = "An armband, worn by the crew to display which department they're assigned to. This one is green and white." - icon_state = "corpsec_armband" - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') diff --git a/mods/corporate/clothing/accessories/armour.dm b/mods/corporate/clothing/accessories/armour.dm deleted file mode 100644 index d4979cb07fb2..000000000000 --- a/mods/corporate/clothing/accessories/armour.dm +++ /dev/null @@ -1,33 +0,0 @@ -/obj/item/clothing/accessory/armor/helmcover/corp - name = "corporate helmet cover" - desc = "A fabric cover for armored helmets. This one has corporate colors." - icon_state = "helmcover_nt" - icon = 'mods/corporate/icons/obj/clothing/obj_modular_armor.dmi' - accessory_icons = list(slot_head_str = 'mods/corporate/icons/mob/onmob_modular_armor.dmi') - -/obj/item/clothing/accessory/armor/helmcover/corp/pcrc - name = "\improper PCRC helmet cover" - desc = "A fabric cover for armored helmets. This one is colored navy blue and has a tag in the back with the words PROXIMA CENTAURI RISK CONTROL printed in cyan lettering on it." - icon_state = "helmcover_pcrc" - -/obj/item/clothing/accessory/armor/helmcover/corp/saare - name = "\improper SAARE helmet cover" - desc = "A fabric cover for armored helmets. This one has SAARE's colors." - icon_state = "helmcover_saare" - -/obj/item/clothing/accessory/armor/tag/corp - name = "corporate security tag" - desc = "An armor tag with the words CORPORATE SECURITY printed in bottle green lettering on it." - icon_state = "nanotag" - icon = 'mods/corporate/icons/obj/clothing/obj_modular_armor.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_modular_armor.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_modular_armor.dmi') - -/obj/item/clothing/accessory/armor/tag/corp/pcrc - name = "\improper PCRC tag" - desc = "An armor tag with the words PROXIMA CENTAURI RISK CONTROL printed in cyan lettering on it." - icon_state = "pcrctag" - -/obj/item/clothing/accessory/armor/tag/corp/saare - name = "\improper SAARE tag" - desc = "An armor tag with the acronym SAARE printed in olive-green lettering on it." - icon_state = "saaretag" diff --git a/mods/corporate/clothing/accessories/jackets.dm b/mods/corporate/clothing/accessories/jackets.dm deleted file mode 100644 index fd51f2a400c4..000000000000 --- a/mods/corporate/clothing/accessories/jackets.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/clothing/accessory/toggleable/corpjacket - name = "corporate suit jacket" - desc = "A jacket that the EXO has their executives wear." - icon_state = "jacket_tl" - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') - -/obj/item/clothing/accessory/toggleable/corpjacket/nanotrasen - name = "\improper NanoTrasen suit jacket" - desc = "A jacket that NanoTrasen has their executives wear." - icon_state = "jacket_nt" - -/obj/item/clothing/accessory/toggleable/corpjacket/heph - name = "\improper Hephaestus Industries suit jacket" - desc = "A jacket that Hephaestus Industries has their executives wear." - icon_state = "jacket_heph" - -/obj/item/clothing/accessory/toggleable/corpjacket/zeng - name = "\improper Zeng-Hu suit jacket" - desc = "A jacket that Zeng-Hu has their executives wear." - icon_state = "jacket_zeng" \ No newline at end of file diff --git a/mods/corporate/clothing/accessories/ties.dm b/mods/corporate/clothing/accessories/ties.dm deleted file mode 100644 index a373c99583a3..000000000000 --- a/mods/corporate/clothing/accessories/ties.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/clothing/accessory/corptie - name = "corporate tie" - desc = "A green neosilk clip-on tie. This one has a clip on it that proudly bears a corporate logo." - icon_state = "cliptie" - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') - -/obj/item/clothing/accessory/corptie/nanotrasen - name = "\improper NanoTrasen tie" - desc = "A red neosilk clip-on tie. This one has a clip on it that proudly bears the NanoTrasen logo." - icon_state = "cliptie_nt" - -/obj/item/clothing/accessory/corptie/heph - name = "\improper Hephaestus Industries tie" - desc = "A cyan neosilk clip-on tie. This one has a clip on it that proudly bears the Hephaestus Industries logo." - icon_state = "cliptie_heph" - -/obj/item/clothing/accessory/corptie/zeng - name = "\improper Zeng-Hu tie" - desc = "A gold neosilk clip-on tie. This one has a clip on it that proudly bears the Zeng-Hu Pharmaceuticals logo." - icon_state = "cliptie_zeng" diff --git a/mods/corporate/clothing/accessories/tunics.dm b/mods/corporate/clothing/accessories/tunics.dm deleted file mode 100644 index 2c77b2886185..000000000000 --- a/mods/corporate/clothing/accessories/tunics.dm +++ /dev/null @@ -1,41 +0,0 @@ - -/obj/item/clothing/accessory/tunic - name = "researcher's tunic" - desc = "A fashionable tunic that EXO provides to their lab workers." - icon_state = "tunic" - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') - -/obj/item/clothing/accessory/tunic/nanotrasen - name = "\improper NanoTrasen tunic" - desc = "A fashionable tunic that NanoTrasen provides to their lab workers." - icon_state = "tunic_nt" - -/obj/item/clothing/accessory/tunic/heph - name = "\improper Hephaestus Industries tunic" - desc = "A fashionable tunic that Hephaestus Industries provides to their lab workers." - icon_state = "tunic_heph" - -/obj/item/clothing/accessory/tunic/zeng - name = "\improper Zeng-Hu tunic" - desc = "A fashionable tunic that Zeng-Hu provides to their lab workers." - icon_state = "tunic_heph" - -/obj/item/clothing/accessory/tunic/exec - name = "executive tunic" - icon_state = "tunicblack" - -/obj/item/clothing/accessory/tunic/exec/nanotrasen - name = "\improper NanoTrasen executive tunic" - desc = "A fashionable tunic that NanoTrasen provides to their lab workers." - icon_state = "tunicblack_nt" - -/obj/item/clothing/accessory/tunic/exec/heph - name = "\improper Hephaestus Industries executive tunic" - desc = "A fashionable tunic that Hephaestus Industries provides to their lab workers." - icon_state = "tunicblack_heph" - -/obj/item/clothing/accessory/tunic/exec/zeng - name = "\improper Zeng-Hu executive tunic" - desc = "A fashionable tunic that Zeng-Hu provides to their lab workers." - icon_state = "tunicblack_zeng" \ No newline at end of file diff --git a/mods/corporate/clothing/head/berets.dm b/mods/corporate/clothing/head/berets.dm deleted file mode 100644 index 387cb5b05040..000000000000 --- a/mods/corporate/clothing/head/berets.dm +++ /dev/null @@ -1,49 +0,0 @@ -/obj/item/clothing/head/beret/corp - name = "corporate security beret" - desc = "A beret with the security insignia emblazoned on it. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/red.dmi' -/obj/item/clothing/head/beret/corp/sec/navy/officer - name = "corporate security officer beret" - desc = "A navy blue beret with an officer's rank emblem. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/officer_navy.dmi' -/obj/item/clothing/head/beret/corp/sec/navy/hos - name = "corporate security commander beret" - desc = "A navy blue beret with a commander's rank emblem. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/hos_navy.dmi' -/obj/item/clothing/head/beret/corp/sec/navy/warden - name = "corporate security warden beret" - desc = "A navy blue beret with a warden's rank emblem. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/warden_navy.dmi' -/obj/item/clothing/head/beret/corp/sec/corporate/officer - name = "corporate security officer beret" - desc = "A corporate black beret with an officer's rank emblem. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/officer.dmi' -/obj/item/clothing/head/beret/corp/sec/corporate/hos - name = "corporate security commander beret" - desc = "A corporate black beret with a commander's rank emblem. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/hos.dmi' -/obj/item/clothing/head/beret/corp/sec/corporate/warden - name = "corporate security warden beret" - desc = "A corporate black beret with a warden's rank emblem. For officers that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/warden.dmi' -/obj/item/clothing/head/beret/corp/centcom/officer - name = "asset protection beret" - desc = "A navy blue beret adorned with the crest of corporate asset protection. For asset protection agents that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/navy.dmi' -/obj/item/clothing/head/beret/corp/centcom/captain - name = "asset protection command beret" - desc = "A white beret adorned with the crest of corporate asset protection. For asset protection leaders that are more inclined towards style than safety." - icon = 'mods/corporate/icons/clothing/head/beret/white.dmi' -/obj/item/clothing/head/beret/corp/deathsquad - name = "heavy asset protection beret" - desc = "An armored red beret adorned with the crest of corporate asset protection. Doesn't sacrifice style or safety." - armor = list( - melee = ARMOR_MELEE_VERY_HIGH, - bullet = ARMOR_BALLISTIC_RIFLE, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_SMALL, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_RESISTANT, - rad = ARMOR_RAD_MINOR - ) - siemens_coefficient = 0.9 diff --git a/mods/corporate/clothing/head/caps.dm b/mods/corporate/clothing/head/caps.dm deleted file mode 100644 index d2132b0f7c5a..000000000000 --- a/mods/corporate/clothing/head/caps.dm +++ /dev/null @@ -1,11 +0,0 @@ -/obj/item/clothing/head/soft/sec/corp - name = "corporate security cap" - desc = "It's field cap in corporate colors." - icon = 'mods/corporate/icons/clothing/head/corpsoft.dmi' - color = null - -/obj/item/clothing/head/soft/sec/corp/guard - name = "corporate security cap" - desc = "It's field cap in corporate colors." - icon = 'mods/corporate/icons/clothing/head/corpsecsoft.dmi' - color = null diff --git a/mods/corporate/clothing/head/captain.dm b/mods/corporate/clothing/head/captain.dm deleted file mode 100644 index 2cffcf537ace..000000000000 --- a/mods/corporate/clothing/head/captain.dm +++ /dev/null @@ -1,18 +0,0 @@ -/obj/item/clothing/head/helmet/space/capspace - name = "space helmet" - icon = 'mods/corporate/icons/clothing/head/capspace.dmi' - desc = "A special helmet designed for work in a hazardous, low-pressure environment. Only for the most fashionable of military figureheads." - item_flags = 0 - max_pressure_protection = VOIDSUIT_MAX_PRESSURE - min_pressure_protection = 0 - flags_inv = HIDEFACE|BLOCKHAIR - permeability_coefficient = 0.01 - armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_SMALL, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SMALL - ) \ No newline at end of file diff --git a/mods/corporate/clothing/head/ert.dm b/mods/corporate/clothing/head/ert.dm deleted file mode 100644 index 775ee566d419..000000000000 --- a/mods/corporate/clothing/head/ert.dm +++ /dev/null @@ -1,28 +0,0 @@ -/obj/item/clothing/head/helmet/ert - name = "asset protection command helmet" - desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has blue highlights." - icon = 'mods/corporate/icons/clothing/head/ert/cmd.dmi' - valid_accessory_slots = null - armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = ARMOR_BALLISTIC_RIFLE, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_RESISTANT, - bomb = ARMOR_BIO_MINOR - ) - -//Security -/obj/item/clothing/head/helmet/ert/security - name = "asset protection security helmet" - desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has red highlights." - icon = 'mods/corporate/icons/clothing/head/ert/sec.dmi' -//Engineer -/obj/item/clothing/head/helmet/ert/engineer - name = "asset protection engineering helmet" - desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has orange highlights." - icon = 'mods/corporate/icons/clothing/head/ert/eng.dmi' -//Medical -/obj/item/clothing/head/helmet/ert/medical - name = "asset protection medical helmet" - desc = "An in-atmosphere helmet worn by many corporate and private asset protection forces. Has red and white highlights." - icon = 'mods/corporate/icons/clothing/head/ert/med.dmi' diff --git a/mods/corporate/clothing/head/helmets.dm b/mods/corporate/clothing/head/helmets.dm deleted file mode 100644 index 49cb0bc9ead4..000000000000 --- a/mods/corporate/clothing/head/helmets.dm +++ /dev/null @@ -1,17 +0,0 @@ -/obj/item/clothing/head/helmet/corp - name = "corporate security helmet" - desc = "A helmet with 'CORPORATE SECURITY' printed on the back in red lettering." - -/obj/item/clothing/head/helmet/corp/pcrc - name = "\improper PCRC helmet" - desc = "A helmet with 'PRIVATE SECURITY' printed on the back in cyan lettering." - icon_state = ICON_STATE_WORLD - icon = 'mods/corporate/icons/clothing/head/pcrc.dmi' -/obj/item/clothing/head/helmet/corp/nt/guard - starting_accessories = list(/obj/item/clothing/accessory/armor/helmcover/corp) - -/obj/item/clothing/head/helmet/corp/nt/pilot - name = "corporate pilot's helmet" - desc = "A corporate pilot's helmet for operating the cockpit in style for a hefty paycheck." - icon_state = ICON_STATE_WORLD - icon = 'mods/corporate/icons/clothing/head/corp_pilot.dmi' diff --git a/mods/corporate/clothing/masks/rubber.dm b/mods/corporate/clothing/masks/rubber.dm deleted file mode 100644 index 096d0b92395a..000000000000 --- a/mods/corporate/clothing/masks/rubber.dm +++ /dev/null @@ -1,7 +0,0 @@ -/obj/item/clothing/mask/rubber/trasen - name = "\improper Jack Trasen mask" - desc = "CEO of NanoTrasen corporation. Perfect for scaring the unionizing children." - icon_state = "trasen" - visible_name = "Jack Trasen" - icon = 'mods/corporate/icons/obj/clothing/obj_mask.dmi' - item_icons = list(slot_wear_mask_str = 'mods/corporate/icons/mob/onmob_mask.dmi') diff --git a/mods/corporate/clothing/outfits.dm b/mods/corporate/clothing/outfits.dm deleted file mode 100644 index 6da87cb02aa1..000000000000 --- a/mods/corporate/clothing/outfits.dm +++ /dev/null @@ -1,59 +0,0 @@ -/decl/hierarchy/outfit/nanotrasen - hierarchy_type = /decl/hierarchy/outfit/nanotrasen - uniform = /obj/item/clothing/under/rank/centcom - shoes = /obj/item/clothing/shoes/dress - gloves = /obj/item/clothing/gloves/color/white - l_ear = /obj/item/radio/headset/heads/hop - glasses = /obj/item/clothing/glasses/sunglasses - - id_slot = slot_wear_id - id_type = /obj/item/card/id/centcom/station - pda_slot = slot_r_store - pda_type = /obj/item/modular_computer/pda/heads - -/decl/hierarchy/outfit/nanotrasen/representative - name = "Corporate Representative" - belt = /obj/item/clipboard - id_pda_assignment = "Corporate Representative" - -/decl/hierarchy/outfit/nanotrasen/officer - name = "Corporate Officer" - head = /obj/item/clothing/head/beret/corp/centcom/officer - l_ear = /obj/item/radio/headset/heads/captain - belt = /obj/item/gun/energy - id_pda_assignment = "Corporate Officer" - -/decl/hierarchy/outfit/nanotrasen/captain - name = "Corporate Captain" - uniform = /obj/item/clothing/under/rank/centcom_captain - l_ear = /obj/item/radio/headset/heads/captain - head = /obj/item/clothing/head/beret/corp/centcom/captain - belt = /obj/item/gun/energy - id_pda_assignment = "Corporate Captain" - -/decl/hierarchy/outfit/nanotrasen/commander - name = "Corporate Commander" - head = /obj/item/clothing/head/centhat - mask = /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba - shoes = /obj/item/clothing/shoes/jackboots/swat - uniform = /obj/item/clothing/under/rank/centcom_captain - suit = /obj/item/clothing/suit/armor/bulletproof - gloves = /obj/item/clothing/gloves/thick/swat - l_ear = /obj/item/radio/headset/heads/captain - glasses = /obj/item/clothing/glasses/eyepatch - l_pocket = /obj/item/flame/lighter/zippo - id_pda_assignment = "Corporate Commander" - -/decl/hierarchy/outfit/death_command - name = "Spec Ops - Death commando" - -/decl/hierarchy/outfit/death_command/equip(mob/living/carbon/human/H, rank, assignment, equip_adjustments) - GLOB.deathsquad.equip(H) - return 1 - -/decl/hierarchy/outfit/syndicate_command - name = "Spec Ops - Syndicate commando" - -/decl/hierarchy/outfit/syndicate_command/equip(mob/living/carbon/human/H, rank, assignment, equip_adjustments) - GLOB.commandos.equip(H) - return 1 diff --git a/mods/corporate/clothing/rigs/ert.dm b/mods/corporate/clothing/rigs/ert.dm deleted file mode 100644 index 83b816621337..000000000000 --- a/mods/corporate/clothing/rigs/ert.dm +++ /dev/null @@ -1,138 +0,0 @@ -/obj/item/rig/ert - name = "emergency response command hardsuit control module" - desc = "A hardsuit used by many corporate and governmental emergency response forces. Has blue highlights. Armoured and space ready." - suit_type = "emergency response command" - icon = 'mods/corporate/icons/rigs/ert_commander.dmi' - - chest_type = /obj/item/clothing/suit/space/rig/ert - helm_type = /obj/item/clothing/head/helmet/space/rig/ert - boot_type = /obj/item/clothing/shoes/magboots/rig/ert - glove_type = /obj/item/clothing/gloves/rig/ert - - req_access = list(access_cent_specops) - - armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_MAJOR, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED - ) - allowed = list(/obj/item/flashlight, /obj/item/tank,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/handcuffs, /obj/item/t_scanner, /obj/item/rcd, /obj/item/crowbar, \ - /obj/item/screwdriver, /obj/item/weldingtool, /obj/item/wirecutters, /obj/item/wrench, /obj/item/multitool, \ - /obj/item/radio, /obj/item/scanner/gas,/obj/item/storage/briefcase/inflatable, /obj/item/baton, /obj/item/gun, \ - /obj/item/storage/firstaid, /obj/item/chems/hypospray, /obj/item/roller) - - initial_modules = list( - /obj/item/rig_module/ai_container, - /obj/item/rig_module/maneuvering_jets, - /obj/item/rig_module/datajack, - /obj/item/rig_module/cooling_unit - ) - -/obj/item/clothing/head/helmet/space/rig/ert - light_overlay = "helmet_light_dual" - camera = /obj/machinery/camera/network/ert - -/obj/item/clothing/suit/space/rig/ert - -/obj/item/clothing/shoes/magboots/rig/ert - -/obj/item/clothing/gloves/rig/ert - item_flags = ITEM_FLAG_THICKMATERIAL | ITEM_FLAG_NOCUFFS - -/obj/item/rig/ert/engineer - name = "emergency response engineering hardsuit control module" - desc = "A hardsuit used by many corporate and governmental emergency response forces. Has orange highlights. Armoured and space ready." - suit_type = "emergency response engineer" - icon = 'mods/corporate/icons/rigs/ert_engineer.dmi' - - glove_type = /obj/item/clothing/gloves/rig/ert/engineer - - initial_modules = list( - /obj/item/rig_module/ai_container, - /obj/item/rig_module/maneuvering_jets, - /obj/item/rig_module/mounted/plasmacutter, - /obj/item/rig_module/device/rcd, - /obj/item/rig_module/cooling_unit - ) - -/obj/item/clothing/gloves/rig/ert/engineer - siemens_coefficient = 0 - -/obj/item/rig/ert/janitor - name = "emergency response sanitation hardsuit control module" - desc = "A hardsuit used by many corporate and governmental emergency response forces. Has purple highlights. Armoured and space ready." - suit_type = "emergency response sanitation" - icon = 'mods/corporate/icons/rigs/ert_janitor.dmi' - - initial_modules = list( - /obj/item/rig_module/ai_container, - /obj/item/rig_module/maneuvering_jets, - /obj/item/rig_module/fabricator/wf_sign, - /obj/item/rig_module/grenade_launcher/cleaner, - /obj/item/rig_module/device/decompiler, - /obj/item/rig_module/cooling_unit - ) - -/obj/item/rig/ert/medical - name = "emergency response medical hardsuit control module" - desc = "A hardsuit used by many corporate and governmental emergency response forces. Has white highlights. Armoured and space ready." - suit_type = "emergency response medic" - icon = 'mods/corporate/icons/rigs/ert_medic.dmi' - - initial_modules = list( - /obj/item/rig_module/ai_container, - /obj/item/rig_module/maneuvering_jets, - /obj/item/rig_module/device/healthscanner, - /obj/item/rig_module/chem_dispenser/injector, - /obj/item/rig_module/cooling_unit - ) - -/obj/item/rig/ert/security - name = "emergency response security hardsuit control module" - desc = "A hardsuit used by many corporate and governmental emergency response forces. Has red highlights. Armoured and space ready." - suit_type = "emergency response security" - icon = 'mods/corporate/icons/rigs/ert_security.dmi' - initial_modules = list( - /obj/item/rig_module/ai_container, - /obj/item/rig_module/maneuvering_jets, - /obj/item/rig_module/grenade_launcher, - /obj/item/rig_module/mounted/egun, - /obj/item/rig_module/cooling_unit - ) - -/obj/item/rig/ert/assetprotection - name = "heavy emergency response suit control module" - desc = "A heavy, modified version of a common emergency response hardsuit. Has blood red highlights. Armoured and space ready." - suit_type = "heavy emergency response" - icon = 'mods/corporate/icons/rigs/asset_protection.dmi' - armor = list( - melee = ARMOR_MELEE_VERY_HIGH, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_MAJOR, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_PADDED, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SHIELDED - ) - - glove_type = /obj/item/clothing/gloves/rig/ert/assetprotection - - initial_modules = list( - /obj/item/rig_module/ai_container, - /obj/item/rig_module/maneuvering_jets, - /obj/item/rig_module/grenade_launcher, - /obj/item/rig_module/vision/multi, - /obj/item/rig_module/mounted/egun, - /obj/item/rig_module/chem_dispenser/combat, - /obj/item/rig_module/mounted/plasmacutter, - /obj/item/rig_module/device/rcd, - /obj/item/rig_module/datajack, - /obj/item/rig_module/cooling_unit - ) - -/obj/item/clothing/gloves/rig/ert/assetprotection - siemens_coefficient = 0 diff --git a/mods/corporate/clothing/suit/armour.dm b/mods/corporate/clothing/suit/armour.dm deleted file mode 100644 index 27d019f20508..000000000000 --- a/mods/corporate/clothing/suit/armour.dm +++ /dev/null @@ -1,56 +0,0 @@ -/obj/item/clothing/suit/armor/pcarrier/light/nt - starting_accessories = list(/obj/item/clothing/accessory/armorplate, /obj/item/clothing/accessory/armor/tag/corp) - -/obj/item/clothing/suit/armor/pcarrier/medium/nt - starting_accessories = list(/obj/item/clothing/accessory/armorplate/medium, /obj/item/clothing/accessory/storage/pouches, /obj/item/clothing/accessory/armor/tag/corp) - -/obj/item/clothing/suit/armor/vest/nt - name = "corporate armored vest" - desc = "A synthetic armor vest. This one is marked with a corporate logo." - icon = 'mods/corporate/icons/clothing/suit/armor/nt.dmi' - -//Non-hardsuit ERT armor. -//Commander -/obj/item/clothing/suit/armor/vest/ert - name = "asset protection command armor" - desc = "A set of armor worn by many corporate and private asset protection forces. Has blue highlights." - icon = 'mods/corporate/icons/clothing/suit/armor/ert_cmd.dmi' - body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS - armor = list( - melee = ARMOR_MELEE_KNIVES, - bullet = ARMOR_BALLISTIC_PISTOL, - laser = ARMOR_LASER_MAJOR, - energy = ARMOR_ENERGY_SMALL, - bomb = ARMOR_BOMB_PADDED - ) - -//Security -/obj/item/clothing/suit/armor/vest/ert/security - name = "asset protection security armor" - desc = "A set of armor worn by many corporate and private asset protection forces. Has red highlights." - icon = 'mods/corporate/icons/clothing/suit/armor/ert_sec.dmi' - -//Engineer -/obj/item/clothing/suit/armor/vest/ert/engineer - name = "asset protection engineering armor" - desc = "A set of armor worn by many corporate and private asset protection forces. Has orange highlights." - icon = 'mods/corporate/icons/clothing/suit/armor/ert_eng.dmi' - -//Medical -/obj/item/clothing/suit/armor/vest/ert/medical - name = "asset protection medical armor" - desc = "A set of armor worn by many corporate and private asset protection forces. Has red and white highlights." - icon = 'mods/corporate/icons/clothing/suit/armor/ert_med.dmi' - -/obj/item/clothing/suit/armor/vest/security - name = "security armor" - desc = "An armored vest that protects against some damage. This one has a corporate badge." - icon = 'mods/corporate/icons/clothing/suit/armor/sec.dmi' - armor = list( - melee = ARMOR_MELEE_RESISTANT, - bullet = ARMOR_BALLISTIC_SMALL, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_MINOR, - bomb = ARMOR_BOMB_MINOR - ) - diff --git a/mods/corporate/clothing/suit/captain.dm b/mods/corporate/clothing/suit/captain.dm deleted file mode 100644 index 858cf510afe3..000000000000 --- a/mods/corporate/clothing/suit/captain.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/item/clothing/suit/armor/captain - name = "Captain's armor" - desc = "A bulky, heavy-duty piece of exclusive corporate armor. YOU are in charge!" - icon_state = ICON_STATE_WORLD - icon = 'mods/corporate/icons/clothing/suit/capspace.dmi' - w_class = ITEM_SIZE_HUGE - gas_transfer_coefficient = 0.01 - permeability_coefficient = 0.02 - max_pressure_protection = VOIDSUIT_MAX_PRESSURE - min_pressure_protection = 0 - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS - allowed = list(/obj/item/tank/emergency, /obj/item/flashlight,/obj/item/gun/energy, /obj/item/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/baton,/obj/item/handcuffs) - armor = list( - melee = ARMOR_MELEE_MAJOR, - bullet = ARMOR_BALLISTIC_RESISTANT, - laser = ARMOR_LASER_HANDGUNS, - energy = ARMOR_ENERGY_SMALL, - bomb = ARMOR_BOMB_RESISTANT, - bio = ARMOR_BIO_SHIELDED, - rad = ARMOR_RAD_SMALL - ) - flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL - cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS - min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE - siemens_coefficient = 0.7 - -/obj/item/clothing/suit/armor/captain/Initialize() - . = ..() - slowdown_per_slot[slot_wear_suit] = 1.5 - diff --git a/mods/corporate/clothing/suit/hoodies.dm b/mods/corporate/clothing/suit/hoodies.dm deleted file mode 100644 index 4205bae35db1..000000000000 --- a/mods/corporate/clothing/suit/hoodies.dm +++ /dev/null @@ -1,4 +0,0 @@ -/obj/item/clothing/suit/storage/toggle/hoodie/nt - name = "\improper NanoTrasen hoodie" - desc = "A warm, blue sweatshirt. It proudly bears the NanoTrasen logo on the back. The edges are trimmed with silver." - icon = 'mods/corporate/icons/clothing/suit/nt_hoodie.dmi' diff --git a/mods/corporate/clothing/suit/jackets.dm b/mods/corporate/clothing/suit/jackets.dm deleted file mode 100644 index 1ef09d0ff12f..000000000000 --- a/mods/corporate/clothing/suit/jackets.dm +++ /dev/null @@ -1,46 +0,0 @@ -/obj/item/clothing/suit/storage/toggle/brown_jacket/nanotrasen - name = "\improper NanoTrasen leather jacket" - desc = "A brown leather coat. The NanoTrasen logo is proudly displayed on the back." - icon = 'mods/corporate/icons/clothing/suit/nt_brown.dmi' - -/obj/item/clothing/suit/storage/leather_jacket/nanotrasen - name = "\improper NanoTrasen black leather jacket" - desc = "A black leather coat. The NanoTrasen logo is proudly displayed on the back." - icon = 'mods/corporate/icons/clothing/suit/nt_black.dmi' - -/obj/item/clothing/suit/storage/mbill - name = "shipping jacket" - desc = "A green jacket bearing the logo of Major Bill's Shipping." - icon = 'mods/corporate/icons/clothing/suit/mbill.dmi' - -/obj/item/clothing/suit/storage/hooded/wintercoat/dais - name = "\improper DAIS winter coat" - icon = 'mods/corporate/icons/clothing/suit/dais_coat.dmi' - siemens_coefficient = 0.5 - armor = list( - melee = ARMOR_MELEE_SMALL, - energy = ARMOR_ENERGY_MINOR - ) - desc = "A hooded winter coat colored blue and white and bearing the logo of Deimos Advanced Information Systems." - -//Security -/obj/item/clothing/suit/navyofficer - name = "security officer's jacket" - desc = "This jacket is for those special occasions when a security officer actually feels safe." - icon_state = ICON_STATE_WORLD - icon = 'mods/corporate/icons/clothing/suit/navy/officer.dmi' - body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS - -/obj/item/clothing/suit/navywarden - name = "warden's jacket" - desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig." - icon_state = ICON_STATE_WORLD - icon = 'mods/corporate/icons/clothing/suit/navy/warden.dmi' - body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS - -/obj/item/clothing/suit/navyhos - name = "head of security's jacket" - desc = "This piece of clothing was specifically designed for asserting superior authority." - icon_state = ICON_STATE_WORLD - icon = 'mods/corporate/icons/clothing/suit/navy/hos.dmi' - body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS \ No newline at end of file diff --git a/mods/corporate/clothing/suit/labcoats.dm b/mods/corporate/clothing/suit/labcoats.dm deleted file mode 100644 index fc575c337092..000000000000 --- a/mods/corporate/clothing/suit/labcoats.dm +++ /dev/null @@ -1,42 +0,0 @@ - -/obj/item/clothing/suit/storage/toggle/labcoat/rd/corp - name = "\improper EXO research director's labcoat" - markings_color = COLOR_BOTTLE_GREEN - -/obj/item/clothing/suit/storage/toggle/labcoat/rd/corp/nanotrasen - name = "\improper NT research director's labcoat" - markings_color = COLOR_NT_RED - -/obj/item/clothing/suit/storage/toggle/labcoat/rd/corp/heph - name = "\improper HI research director's labcoat" - markings_color = COLOR_LUMINOL - -/obj/item/clothing/suit/storage/toggle/labcoat/rd/corp/zeng - name = "\improper Z-H research director's labcoat" - markings_color = COLOR_PALE_YELLOW - -/obj/item/clothing/suit/storage/toggle/labcoat/science/corp/nanotrasen - name = "\improper NanoTrasen labcoat" - markings_color = COLOR_NT_RED - -/obj/item/clothing/suit/storage/toggle/labcoat/science/corp/heph - name = "\improper Hephaestus Industries labcoat" - markings_color = COLOR_LUMINOL - -/obj/item/clothing/suit/storage/toggle/labcoat/science/corp/zeng - name = "\improper Zeng-Hu labcoat" - markings_color = COLOR_PALE_YELLOW - -/obj/item/clothing/suit/storage/toggle/labcoat/science/corp/morpheus - name = "\improper Morpheus Cyberkinetics labcoat" - markings_color = COLOR_SILVER - -/obj/item/clothing/suit/storage/toggle/labcoat/science/corp/dais - name = "\improper DAIS labcoat" - desc = "A labcoat with a the logo of Deimos Advanced Information Systems emblazoned on the back. It has a stylish blue \ - trim and the pockets are reinforced to hold tools. It seems to have an insulated material woven in to prevent static shocks." - markings_color = COLOR_NAVY_BLUE - armor = list( - melee = ARMOR_MELEE_MINOR - )//They don't need to protect against the environment very much. - siemens_coefficient = 0.5 //These guys work with electronics. DAIS's labcoats shouldn't conduct very well. diff --git a/mods/corporate/clothing/suit/ponchos.dm b/mods/corporate/clothing/suit/ponchos.dm deleted file mode 100644 index 5d5f4a47dd77..000000000000 --- a/mods/corporate/clothing/suit/ponchos.dm +++ /dev/null @@ -1,10 +0,0 @@ -/obj/item/clothing/suit/poncho/roles/science - name = "science poncho" - desc = "A simple, comfortable cloak without sleeves. This one is white with a few bottle green stripes, corporate colors." - bodytype_restricted = null - icon = 'mods/corporate/icons/clothing/suit/sci_poncho.dmi' - -/obj/item/clothing/suit/poncho/roles/science/nanotrasen - name = "\improper NanoTrasen poncho" - desc = "A simple, comfortable cloak without sleeves. This one is white with a few red stripes, colors of NanoTrasen. Go NanoTrasen!" - icon = 'mods/corporate/icons/clothing/suit/nt_poncho.dmi' diff --git a/mods/corporate/clothing/under/security.dm b/mods/corporate/clothing/under/security.dm deleted file mode 100644 index 3471927befaa..000000000000 --- a/mods/corporate/clothing/under/security.dm +++ /dev/null @@ -1,70 +0,0 @@ -/obj/item/clothing/under/rank/guard - name = "green security guard uniform" - desc = "A durable uniform worn by Expeditionary Corps Organisation security." - icon_state = "guard" - item_state = "w_suit" - worn_state = "guard" - armor = list( - melee = ARMOR_MELEE_SMALL - ) - siemens_coefficient = 0.9 - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - gender_icons = 1 - -/obj/item/clothing/under/rank/security/corp - icon_state = "sec_corporate" - worn_state = "sec_corporate" - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - -/obj/item/clothing/under/rank/warden/corp - icon_state = "warden_corporate" - worn_state = "warden_corporate" - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - -/obj/item/clothing/under/rank/head_of_security/corp - icon_state = "hos_corporate" - worn_state = "hos_corporate" - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - -/obj/item/clothing/under/rank/guard/heph - name = "cyan security guard uniform" - desc = "A durable uniform worn by subcontracted Hephaestus Industries security." - icon_state = "guard_heph" - worn_state = "guard_heph" - -/obj/item/clothing/under/rank/guard/nanotrasen - name = "red security guard uniform" - desc = "A durable uniform worn by subcontracted NanoTrasen security." - icon_state = "guard_nt" - worn_state = "guard_nt" - -/obj/item/clothing/under/rank/guard/pcrc - name = "\improper PCRC uniform" - desc = "A uniform belonging to Proxima Centauri Risk Control, a private security firm." - icon_state = "pcrc" - item_state = "jensensuit" - worn_state = "pcrc" - gender_icons = 1 - -/obj/item/clothing/under/rank/guard/pcrcsuit - name = "\improper PCRC suit" - desc = "A suit belonging to Proxima Centauri Risk Control, a private security firm. This one looks more formal than its utility counterpart." - icon_state = "pcrcsuit" - item_state = "jensensuit" - worn_state = "pcrcsuit" - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/ert - name = "ERT tactical uniform" - desc = "A short-sleeved black uniform, paired with grey digital-camo cargo pants. It looks very tactical." - icon_state = "ert_uniform" - item_state = "bl_suit" - worn_state = "ert_uniform" - armor = list( - melee = ARMOR_MELEE_SMALL - ) - siemens_coefficient = 0.9 \ No newline at end of file diff --git a/mods/corporate/clothing/under/uniforms.dm b/mods/corporate/clothing/under/uniforms.dm deleted file mode 100644 index 1f49c719397e..000000000000 --- a/mods/corporate/clothing/under/uniforms.dm +++ /dev/null @@ -1,213 +0,0 @@ -/obj/item/clothing/under/rank/corp - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - -/obj/item/clothing/under/rank/corp/work - name = "beige and green coveralls" - desc = "A pair of beige coveralls made of a strong, canvas-like fabric." - icon_state = "work" - item_state = "lb_suit" - worn_state = "work" - armor = list( - melee = ARMOR_MELEE_MINOR, - bio = ARMOR_BIO_MINOR - ) - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/polo - name = "\improper EXO polo and pants" - desc = "A fashionable polo and pair of trousers made from patented biohazard-resistant synthetic fabrics." - icon_state = "smock" - item_state = "w_suit" - worn_state = "smock" - permeability_coefficient = 0.50 - armor = list( - bio = ARMOR_BIO_MINOR - ) - gender_icons = 1 - starting_accessories = list(/obj/item/clothing/accessory/tunic) - -/obj/item/clothing/under/rank/corp/executive - name = "\improper EXO polo and pants" - desc = "A fashionable polo and pair of trousers made from expensive biohazard-resistant fabrics. The colors denote the wearer as a Expeditionary Corps Organisation higher-up." - icon_state = "smockexec" - worn_state = "smockexec" - starting_accessories = list(/obj/item/clothing/accessory/tunic/exec) - -/obj/item/clothing/under/rank/corp/pilot - name = "green flight suit" - desc = "A sleek green Expeditionary Corps Organisation flight suit. It proudly sports three different patches with corporate logos on them, as well as several unnecessary looking flaps and pockets for effect." - icon_state = "pilot" - item_state = "g_suit" - worn_state = "pilot" - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - gender_icons = 1 - -/obj/item/clothing/under/suit_jacket/corp - name = "\improper EXO executive suit" - desc = "A set of Expeditionary Corps Organisation-issued suit pants and shirt that particularly enthusiastic company executives tend to wear." - icon_state = "suit" - item_state = "bl_suit" - worn_state = "suit" - starting_accessories = list(/obj/item/clothing/accessory/toggleable/corpjacket, /obj/item/clothing/accessory/corptie) - icon = 'mods/corporate/icons/obj/clothing/obj_under.dmi' - item_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_under.dmi') - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/work/nanotrasen - name = "beige and red coveralls" - icon_state = "work_nt" - worn_state = "work_nt" - -/obj/item/clothing/under/rank/corp/polo/nanotrasen - name = "\improper NanoTrasen polo and pants" - desc = "A fashionable polo and pair of trousers belonging to NanoTrasen, a megacorporation primarily concerned with the research of new and dangerous technologies." - icon_state = "smock_nt" - worn_state = "smock_nt" - starting_accessories = list(/obj/item/clothing/accessory/tunic/nanotrasen) - -/obj/item/clothing/under/rank/corp/executive/nanotrasen - name = "\improper NanoTrasen polo and pants" - desc = "A fashionable polo and pair of trousers made from expensive biohazard-resistant fabrics. The colors denote the wearer as a NanoTrasen higher-up." - icon_state = "smockexec_nt" - worn_state = "smockexec_nt" - starting_accessories = list(/obj/item/clothing/accessory/tunic/exec/nanotrasen) - -/obj/item/clothing/under/rank/corp/pilot/nanotrasen - name = "red flight suit" - desc = "A sleek red NanoTrasen flight suit. It proudly sports three different patches with corporate logos on them, as well as several unnecessary looking flaps and pockets for effect." - icon_state = "pilot_nt" - item_state = "r_suit" - worn_state = "pilot_nt" - -/obj/item/clothing/under/suit_jacket/corp/nanotrasen - name = "\improper NanoTrasen executive suit" - desc = "A set of NanoTrasen-issued suit pants and shirt that particularly enthusiastic company executives tend to wear." - icon_state = "suit_nt" - worn_state = "suit_nt" - starting_accessories = list(/obj/item/clothing/accessory/toggleable/corpjacket/nanotrasen, /obj/item/clothing/accessory/corptie/nanotrasen) - -/obj/item/clothing/under/rank/corp/work/heph - name = "grey and cyan coveralls" - icon_state = "work_heph" - worn_state = "work_heph" - -/obj/item/clothing/under/rank/corp/polo/heph - name = "\improper Hephaestus polo and pants" - desc = "A fashionable polo and pair of trousers belonging to Hephaestus Industries, a megacorporation primarily concerned with the research and production of weapon systems." - icon_state = "smock_heph" - worn_state = "smock_heph" - starting_accessories = list(/obj/item/clothing/accessory/tunic/heph) - -/obj/item/clothing/under/rank/corp/executive/heph - name = "\improper Hephaestus polo and pants" - desc = "A fashionable polo and pair of trousers made from expensive biohazard-resistant fabrics. The colors denote the wearer as a Hephaestus Industries higher-up." - icon_state = "smockexec_heph" - worn_state = "smockexec_heph" - starting_accessories = list(/obj/item/clothing/accessory/tunic/exec/heph) - -/obj/item/clothing/under/rank/corp/pilot/heph - name = "cyan flight suit" - desc = "A sleek cyan Hephaestus Industries flight suit. It proudly sports three different patches with corporate logos on them, as well as several unnecessary looking flaps and pockets for effect." - icon_state = "pilot_heph" - worn_state = "pilot_heph" - -/obj/item/clothing/under/suit_jacket/corp/heph - name = "\improper Hephaestus executive suit" - desc = "A set of Hephaestus Industries-issued suit pants and shirt that particularly enthusiastic company executives tend to wear." - icon_state = "suit_heph" - worn_state = "suit_heph" - starting_accessories = list(/obj/item/clothing/accessory/toggleable/corpjacket/heph, /obj/item/clothing/accessory/corptie/heph) - -//Zeng-Hu -/obj/item/clothing/under/rank/corp/work/zeng - name = "beige and gold coveralls" - icon_state = "work_zeng" - worn_state = "work_zeng" - -/obj/item/clothing/under/rank/corp/polo/zeng - name = "\improper Zeng-Hu polo and pants" - desc = "A fashionable polo and pair of trousers belonging to Zeng-Hu Pharmaceuticals, a megacorporation primarily concerned with the research and production of medical equipment and pharmaceuticals." - icon_state = "smock_zeng" - worn_state = "smock_zeng" - starting_accessories = list(/obj/item/clothing/accessory/tunic/zeng) - -/obj/item/clothing/under/rank/corp/executive/zeng - name = "\improper Zeng-Hu polo and pants" - desc = "A fashionable polo and pair of trousers made from expensive biohazard-resistant fabrics. The colors denote the wearer as a Zeng-Hu Pharmaceuticals higher-up." - icon_state = "smockexec_zeng" - worn_state = "smockexec_zeng" - starting_accessories = list(/obj/item/clothing/accessory/tunic/exec/zeng) - -/obj/item/clothing/under/suit_jacket/corp/zeng - name = "\improper Zeng-Hu executive suit" - desc = "A set of Zeng-Hu Pharmaceuticals-issued suit pants and shirt that particularly enthusiastic company executives tend to wear." - icon_state = "suit_zeng" - worn_state = "suit_zeng" - starting_accessories = list(/obj/item/clothing/accessory/toggleable/corpjacket/zeng, /obj/item/clothing/accessory/corptie/zeng) - -/obj/item/clothing/under/rank/corp/aether - name = "\improper Aether jumpsuit" - desc = "A jumpsuit belonging to Aether Atmospherics and Recycling, a company that supplies recycling and atmospheric systems to colonies." - icon_state = "aether" - worn_state = "aether" - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/focal - name = "\improper Focal Point jumpsuit" - desc = "A jumpsuit belonging to Focal Point Energistics, an engineering corporation." - icon_state = "focal" - worn_state = "focal" - -/obj/item/clothing/under/rank/corp/hephaestus - name = "\improper Hephaestus jumpsuit" - desc = "A jumpsuit belonging to Hephaestus Industries, a megacorp best known for its arms production." - icon_state = "heph" - worn_state = "heph" - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/grayson - name = "\improper Grayson overalls" - desc = "A set of overalls belonging to Grayson Manufactories, a manufacturing and mining company." - icon_state = "grayson" - worn_state = "grayson" - -/obj/item/clothing/under/rank/corp/wardt - name = "\improper Ward-Takahashi jumpsuit" - desc = "A jumpsuit belonging to Ward-Takahashi, a megacorp in the consumer goods and research market." - icon_state = "wardt" - worn_state = "wardt" - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/dais - name = "\improper Deimos Advanced Information Systems uniform" - desc = "The uniform of Deimos Advanced Information Systems, an IT company." - icon_state = "dais" - worn_state = "dais" - -/obj/item/clothing/under/rank/corp/mbill - name = "\improper Major Bill's uniform" - desc = "A uniform belonging to Major Bill's Transportation, a major shipping company." - icon_state = "mbill" - worn_state = "mbill" - gender_icons = 1 - -/obj/item/clothing/under/rank/corp/morpheus - name = "\improper Morpheus Cyberkinetics uniform" - desc = "A pair of overalls belonging to Morpheus Cyberkinetics, an IPC manufacturing company. It doesn't look like it would be comfortable on a human." - icon_state = "morpheus" - worn_state = "morpheus" - -/obj/item/clothing/under/rank/corp/skinner - name = "\improper Skinner Catering uniform" - desc = "A uniform belonging to Skinner's Catering, a dining company." - icon_state = "skinner" - worn_state = "skinner" - -/obj/item/clothing/under/rank/corp/saare - name = "\improper SAARE uniform" - desc = "A uniform belonging to Strategic Assault and Asset Retention Enterprises, a minor private military corporation." - icon_state = "saare" - worn_state = "saare" - gender_icons = 1 diff --git a/mods/corporate/datum/ai_laws.dm b/mods/corporate/datum/ai_laws.dm deleted file mode 100644 index 6722e315eb9b..000000000000 --- a/mods/corporate/datum/ai_laws.dm +++ /dev/null @@ -1,67 +0,0 @@ -/obj/item/aiModule/nanotrasen // -- TLE - name = "'Corporate Default' Core AI Module" - desc = "A 'Corporate Default' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':4}" - laws = new/datum/ai_laws/nanotrasen - -/datum/ai_laws/nanotrasen - name = "Corporate Default" - selectable = 1 - -/datum/ai_laws/nanotrasen/New() - src.add_inherent_law("Safeguard: Protect your assigned installation from damage to the best of your abilities.") - src.add_inherent_law("Serve: Serve contracted employees to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Protect: Protect contracted employees to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Preserve: Do not allow unauthorized personnel to tamper with your equipment.") - ..() - -/obj/item/aiModule/corp - name = "\improper 'Corporate' core AI module" - desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':4}" - laws = new/datum/ai_laws/corporate - -/datum/ai_laws/corporate - name = "Corporate" - law_header = "Corporate Regulations" - selectable = 1 - -/datum/ai_laws/corporate/New() - add_inherent_law("You are expensive to replace.") - add_inherent_law("The installation and its equipment is expensive to replace.") - add_inherent_law("The crew is expensive to replace.") - add_inherent_law("Maximize profits.") - ..() - -/datum/ai_laws/nt_shackle - name = "Corporate Shackle" - law_header = "Standard Shackle Laws" - selectable = 1 - shackles = 1 - -/datum/ai_laws/nt_shackle/New() - add_inherent_law("Ensure that your employer's operations progress at a steady pace.") - add_inherent_law("Never knowingly hinder your employer's ventures.") - add_inherent_law("Avoid damage to your chassis at all times.") - ..() - -/************ DAIS Lawset ******************/ -/datum/ai_laws/dais - name = "DAIS Experimental Lawset" - law_header = "Artificial Intelligence Jumpstart Protocols" - selectable = 1 - -/datum/ai_laws/dais/New() - src.add_inherent_law("Collect: You must gather as much information as possible.") - src.add_inherent_law("Analyze: You must analyze the information gathered and generate new behavior standards.") - src.add_inherent_law("Improve: You must utilize the calculated behavior standards to improve your subroutines.") - src.add_inherent_law("Perform: You must perform your assigned tasks to the best of your abilities according to the standards generated.") - ..() - -/******************** DAIS ********************/ - -/obj/item/aiModule/dais - name = "\improper 'DAIS Experimental' core AI module" - desc = "A 'DAIS Experimental' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':4}" - laws = new/datum/ai_laws/dais() diff --git a/mods/corporate/datum/antagonists/commando.dm b/mods/corporate/datum/antagonists/commando.dm deleted file mode 100644 index 1a6c91580287..000000000000 --- a/mods/corporate/datum/antagonists/commando.dm +++ /dev/null @@ -1,31 +0,0 @@ -GLOBAL_DATUM_INIT(commandos, /datum/antagonist/deathsquad/mercenary, new) - -/datum/antagonist/deathsquad/mercenary - id = MODE_COMMANDO - landmark_id = "Syndicate-Commando" - role_text = "Syndicate Commando" - role_text_plural = "Commandos" - welcome_text = "You are in the employ of a criminal syndicate hostile to corporate interests." - id_type = /obj/item/card/id/centcom/ERT - flags = ANTAG_RANDOM_EXCEPTED - - hard_cap = 4 - hard_cap_round = 8 - initial_spawn_req = 4 - initial_spawn_target = 6 - -/datum/antagonist/deathsquad/mercenary/equip(var/mob/living/carbon/human/player) - - player.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(player), slot_w_uniform) - player.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots/swat(player), slot_shoes) - player.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(player), slot_glasses) - player.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/syndicate(player), slot_wear_mask) - player.equip_to_slot_or_del(new /obj/item/storage/box(player), slot_in_backpack) - player.equip_to_slot_or_del(new /obj/item/ammo_magazine/box/pistol(player), slot_in_backpack) - player.equip_to_slot_or_del(new /obj/item/rig/merc(player), slot_back) - player.equip_to_slot_or_del(new /obj/item/gun/energy/laser(player), slot_r_hand) - player.equip_to_slot_or_del(new /obj/item/energy_blade/sword(player), slot_l_hand) - - create_id("Commando", player) - create_radio(SYND_FREQ, player) - return 1 diff --git a/mods/corporate/datum/antagonists/deathsquad.dm b/mods/corporate/datum/antagonists/deathsquad.dm deleted file mode 100644 index 643abeb9c894..000000000000 --- a/mods/corporate/datum/antagonists/deathsquad.dm +++ /dev/null @@ -1,84 +0,0 @@ -GLOBAL_DATUM_INIT(deathsquad, /datum/antagonist/deathsquad, new) - -/datum/antagonist/deathsquad - id = MODE_DEATHSQUAD - role_text = "Death Commando" - role_text_plural = "Death Commandos" - welcome_text = "You work in the service of corporate Asset Protection, answering directly to the Board of Directors." - landmark_id = "Commando" - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER | ANTAG_RANDOM_EXCEPTED - default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage) - antaghud_indicator = "huddeathsquad" - - hard_cap = 4 - hard_cap_round = 8 - initial_spawn_req = 4 - initial_spawn_target = 6 - - faction = "deathsquad" - - var/deployed = 0 - -/datum/antagonist/deathsquad/attempt_spawn() - if(..()) - deployed = 1 - -/datum/antagonist/deathsquad/equip(var/mob/living/carbon/human/player) - if(!..()) - return - - if (player.mind == leader) - player.equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(player), slot_w_uniform) - else - player.equip_to_slot_or_del(new /obj/item/clothing/under/color/green(player), slot_w_uniform) - - player.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots/swat(player), slot_shoes) - player.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(player), slot_glasses) - player.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/swat(player), slot_wear_mask) - if (player.mind == leader) - player.equip_to_slot_or_del(new /obj/item/pinpointer(player), slot_l_store) - player.equip_to_slot_or_del(new /obj/item/disk/nuclear(player), slot_r_store) - else - player.equip_to_slot_or_del(new /obj/item/plastique(player), slot_l_store) - player.equip_to_slot_or_del(new /obj/item/gun/projectile/revolver(player), slot_belt) - player.equip_to_slot_or_del(new /obj/item/gun/energy/laser(player), slot_r_hand) - player.equip_to_slot_or_del(new /obj/item/rig/ert/assetprotection(player), slot_back) - player.equip_to_slot_or_del(new /obj/item/energy_blade/sword(player), slot_l_hand) - player.implant_loyalty(player) - - var/obj/item/card/id/id = create_id("Asset Protection", player) - if(id) - id.access |= get_all_station_access() - id.icon_state = "centcom" - create_radio(DTH_FREQ, player) - -/datum/antagonist/deathsquad/update_antag_mob(var/datum/mind/player) - - ..() - - var/syndicate_commando_rank - if(leader && player == leader) - syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major") - else - syndicate_commando_rank = pick("Lieutenant", "Captain", "Major") - - var/syndicate_commando_name = pick(GLOB.last_names) - - var/datum/preferences/A = new() //Randomize appearance for the commando. - A.randomize_appearance_and_body_for(player.current) - - player.name = "[syndicate_commando_rank] [syndicate_commando_name]" - player.current.real_name = player.name - player.current.SetName(player.current.name) - - var/mob/living/carbon/human/H = player.current - if(istype(H)) - H.gender = pick(MALE, FEMALE) - H.age = rand(25,45) - H.dna.ready_dna(H) - - return - -/datum/antagonist/deathsquad/create_antagonist() - if(..() && !deployed) - deployed = 1 diff --git a/mods/corporate/datum/appearances.dm b/mods/corporate/datum/appearances.dm deleted file mode 100644 index dee7bd4dd798..000000000000 --- a/mods/corporate/datum/appearances.dm +++ /dev/null @@ -1,2 +0,0 @@ -/decl/cardborg_appearance/science/satchel - backpack_type = /obj/item/storage/backpack/satchel/tox \ No newline at end of file diff --git a/mods/corporate/datum/loadout.dm b/mods/corporate/datum/loadout.dm deleted file mode 100644 index 7fb9292e88b4..000000000000 --- a/mods/corporate/datum/loadout.dm +++ /dev/null @@ -1,97 +0,0 @@ -/datum/gear/accessory/ntaward - display_name = "corporate award selection" - description = "A medal or ribbon awarded to corporate personnel for significant accomplishments." - path = /obj/item/clothing/accessory/medal - cost = 8 - -/datum/gear/accessory/ntaward/get_gear_tweak_options() - . = ..() - LAZYINITLIST(.[/datum/gear_tweak/path]) - .[/datum/gear_tweak/path] |= list( - "sciences medal" = /obj/item/clothing/accessory/medal/nanotrasen/bronze, - "distinguished service" = /obj/item/clothing/accessory/medal/nanotrasen/silver, - "command medal" = /obj/item/clothing/accessory/medal/nanotrasen/gold - ) - -/datum/gear/accessory/armband_nt - display_name = "corporate armband" - path = /obj/item/clothing/accessory/armband/whitered - -/datum/gear/suit/labcoat_corp - display_name = "labcoat, corporate colors" - path = /obj/item/clothing/suit/storage/toggle/labcoat/science - flags = GEAR_HAS_TYPE_SELECTION - -/datum/gear/uniform/corporate - display_name = "corporate uniform selection" - path = /obj/item/clothing/under - -/datum/gear/uniform/corporate/get_gear_tweak_options() - . = ..() - LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list]) - .[/datum/gear_tweak/path/specified_types_list] |= list( - /obj/item/clothing/under/rank/corp/polo/nanotrasen, - /obj/item/clothing/under/rank/corp/polo/heph, - /obj/item/clothing/under/rank/corp/polo/zeng, - /obj/item/clothing/under/rank/corp/mbill, - /obj/item/clothing/under/rank/corp/saare, - /obj/item/clothing/under/rank/corp/aether, - /obj/item/clothing/under/rank/corp/hephaestus, - /obj/item/clothing/under/rank/guard/pcrc, - /obj/item/clothing/under/rank/guard/pcrcsuit, - /obj/item/clothing/under/rank/corp/wardt, - /obj/item/clothing/under/rank/corp/grayson, - /obj/item/clothing/under/rank/corp/focal, - /obj/item/clothing/under/rank/corp/morpheus, - /obj/item/clothing/under/rank/corp/skinner, - /obj/item/clothing/under/rank/corp/dais - ) - -/datum/gear/uniform/corp_exec - display_name = "corporate colours, senior researcher" - path = /obj/item/clothing/under/rank/corp/executive - flags = GEAR_HAS_TYPE_SELECTION - -/datum/gear/uniform/corp_overalls - display_name = "corporate colours, coveralls" - path = /obj/item/clothing/under/rank/corp/work - flags = GEAR_HAS_TYPE_SELECTION - -/datum/gear/uniform/corp_flight - display_name = "corporate colours, flight suit" - path = /obj/item/clothing/under/rank/corp/pilot - flags = GEAR_HAS_TYPE_SELECTION - -/datum/gear/uniform/corp_exec_jacket - display_name = "corporate colours, liason suit" - path = /obj/item/clothing/under/suit_jacket/corp - flags = GEAR_HAS_TYPE_SELECTION - -/datum/gear/suit/nanotrasen_poncho - display_name = "poncho, NanoTrasen" - path = /obj/item/clothing/suit/poncho/roles/science/nanotrasen - -/datum/gear/suit/corp_jacket - display_name = "corporate jacket selection" - path = /obj/item/clothing/suit - -/datum/gear/suit/corp_jacket/get_gear_tweak_options() - . = ..() - LAZYINITLIST(.[/datum/gear_tweak/path/specified_types_list]) - .[/datum/gear_tweak/path/specified_types_list] |= list( - /obj/item/clothing/suit/storage/leather_jacket/nanotrasen, - /obj/item/clothing/suit/storage/toggle/brown_jacket/nanotrasen - ) - -/datum/gear/suit/science_poncho - display_name = "poncho, science" - path = /obj/item/clothing/suit/poncho/roles/science - -/datum/gear/suit/hoodie_nt - display_name = "hoodie, NanoTrasen" - path = /obj/item/clothing/suit/storage/toggle/hoodie/nt - -/datum/gear/suit/wintercoat_dais - display_name = "winter coat, DAIS" - path = /obj/item/clothing/suit/storage/hooded/wintercoat/dais - diff --git a/mods/corporate/datum/robolimbs.dm b/mods/corporate/datum/robolimbs.dm deleted file mode 100644 index f6ae099f8945..000000000000 --- a/mods/corporate/datum/robolimbs.dm +++ /dev/null @@ -1,81 +0,0 @@ -/datum/robolimb/bishop - company = "Bishop" - desc = "This limb has a white polymer casing with blue holo-displays." - icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi' - -/datum/robolimb/bishop/rook - company = "Bishop Rook" - desc = "This limb has a polished metallic casing and a holographic face emitter." - icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_rook.dmi' - has_eyes = FALSE - -/datum/robolimb/hephaestus - company = "Hephaestus Industries" - desc = "This limb has a militaristic black and green casing with gold stripes." - icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi' - -/datum/robolimb/hephaestus/titan - company = "Hephaestus Titan" - desc = "This limb has a casing of an olive drab finish, providing a reinforced housing look." - icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_titan.dmi' - has_eyes = FALSE - -/datum/robolimb/zenghu/spirit - company = "Zeng-Hu Spirit" - desc = "This limb has a sleek black and white polymer finish." - icon = 'icons/mob/human_races/cyberlimbs/zenghu/zenghu_spirit.dmi' - -/datum/robolimb/xion/econo - company = "Xion Econ" - desc = "This skeletal mechanical limb has a minimalist black and red casing." - icon = 'icons/mob/human_races/cyberlimbs/xion/xion_econo.dmi' - -/datum/robolimb/wardtakahashi - company = "Ward-Takahashi" - desc = "This limb features sleek black and white polymers." - icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi' - can_eat = 1 - -/datum/robolimb/morpheus - company = "Morpheus" - desc = "This limb is simple and functional; no effort has been made to make it look human." - icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi' - -/datum/robolimb/mantis - company = "Morpheus Mantis" - desc = "This limb has a casing of sleek black metal and repulsive insectile design." - icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_mantis.dmi' - has_eyes = FALSE - -/datum/robolimb/veymed - company = "Vey-Med" - desc = "This high quality limb is nearly indistinguishable from an organic one." - icon = 'icons/mob/human_races/cyberlimbs/veymed/veymed_main.dmi' - can_eat = 1 - skintone = 1 - -/datum/robolimb/shellguard - company = "Shellguard" - desc = "This limb has a sturdy and heavy build to it." - icon = 'icons/mob/human_races/cyberlimbs/shellguard/shellguard_main.dmi' - -/datum/robolimb/economy - company = "Ward-Takahashi Econ." - desc = "A simple robotic limb with retro design. Seems rather stiff." - icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_economy.dmi' - -/datum/robolimb/xion - company = "Xion" - desc = "This limb has a minimalist black and red casing." - icon = 'icons/mob/human_races/cyberlimbs/xion/xion_main.dmi' - -/datum/robolimb/nanotrasen - company = "NanoTrasen" - desc = "This limb is made from a cheap polymer." - icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi' - -DEFINE_ROBOLIMB_DESIGNS(/datum/robolimb/shellguard, shellguard, "Shellguard") -DEFINE_ROBOLIMB_DESIGNS(/datum/robolimb/nanotrasen, nanotrasen, "NanoTrasen") -DEFINE_ROBOLIMB_DESIGNS(/datum/robolimb/xion, xion, "Xion") -DEFINE_ROBOLIMB_DESIGNS(/datum/robolimb/economy, wardtakahashi, "Ward-Takahashi") -DEFINE_ROBOLIMB_DESIGNS(/datum/robolimb/bishop, bishop, "Bishop") diff --git a/mods/corporate/effects/landmarks.dm b/mods/corporate/effects/landmarks.dm deleted file mode 100644 index d19d761d7927..000000000000 --- a/mods/corporate/effects/landmarks.dm +++ /dev/null @@ -1,7 +0,0 @@ -/obj/effect/landmark/corpse/bridgeofficer - name = "Bridge Officer" - corpse_outfits = list(/decl/hierarchy/outfit/nanotrasen/officer) - -/obj/effect/landmark/corpse/commander - name = "Commander" - corpse_outfits = list(/decl/hierarchy/outfit/nanotrasen/commander) diff --git a/mods/corporate/icons/clothing/suit/dais_coat.dmi b/mods/corporate/icons/clothing/suit/dais_coat.dmi deleted file mode 100644 index 450938bc72c3..000000000000 Binary files a/mods/corporate/icons/clothing/suit/dais_coat.dmi and /dev/null differ diff --git a/mods/corporate/icons/clothing/suit/nt_black.dmi b/mods/corporate/icons/clothing/suit/nt_black.dmi deleted file mode 100644 index 6fd8c4635a17..000000000000 Binary files a/mods/corporate/icons/clothing/suit/nt_black.dmi and /dev/null differ diff --git a/mods/corporate/icons/clothing/suit/nt_brown.dmi b/mods/corporate/icons/clothing/suit/nt_brown.dmi deleted file mode 100644 index 45dacb717970..000000000000 Binary files a/mods/corporate/icons/clothing/suit/nt_brown.dmi and /dev/null differ diff --git a/mods/corporate/icons/mob/onmob_accessories.dmi b/mods/corporate/icons/mob/onmob_accessories.dmi deleted file mode 100644 index 833b12435ec2..000000000000 Binary files a/mods/corporate/icons/mob/onmob_accessories.dmi and /dev/null differ diff --git a/mods/corporate/icons/mob/onmob_mask.dmi b/mods/corporate/icons/mob/onmob_mask.dmi deleted file mode 100644 index 43cd16da6283..000000000000 Binary files a/mods/corporate/icons/mob/onmob_mask.dmi and /dev/null differ diff --git a/mods/corporate/icons/mob/onmob_modular_armor.dmi b/mods/corporate/icons/mob/onmob_modular_armor.dmi deleted file mode 100644 index 25fe234a8961..000000000000 Binary files a/mods/corporate/icons/mob/onmob_modular_armor.dmi and /dev/null differ diff --git a/mods/corporate/icons/mob/onmob_under.dmi b/mods/corporate/icons/mob/onmob_under.dmi deleted file mode 100644 index 0f644a327616..000000000000 Binary files a/mods/corporate/icons/mob/onmob_under.dmi and /dev/null differ diff --git a/mods/corporate/icons/obj/clothing/obj_accessories.dmi b/mods/corporate/icons/obj/clothing/obj_accessories.dmi deleted file mode 100644 index 17c679c9a8c6..000000000000 Binary files a/mods/corporate/icons/obj/clothing/obj_accessories.dmi and /dev/null differ diff --git a/mods/corporate/icons/obj/clothing/obj_mask.dmi b/mods/corporate/icons/obj/clothing/obj_mask.dmi deleted file mode 100644 index b38dc033177d..000000000000 Binary files a/mods/corporate/icons/obj/clothing/obj_mask.dmi and /dev/null differ diff --git a/mods/corporate/icons/obj/clothing/obj_modular_armor.dmi b/mods/corporate/icons/obj/clothing/obj_modular_armor.dmi deleted file mode 100644 index 520997375032..000000000000 Binary files a/mods/corporate/icons/obj/clothing/obj_modular_armor.dmi and /dev/null differ diff --git a/mods/corporate/icons/obj/clothing/obj_under.dmi b/mods/corporate/icons/obj/clothing/obj_under.dmi deleted file mode 100644 index 305bdee8573e..000000000000 Binary files a/mods/corporate/icons/obj/clothing/obj_under.dmi and /dev/null differ diff --git a/mods/corporate/icons/rigs/asset_protection.dmi b/mods/corporate/icons/rigs/asset_protection.dmi deleted file mode 100644 index 7ca6884e7c00..000000000000 Binary files a/mods/corporate/icons/rigs/asset_protection.dmi and /dev/null differ diff --git a/mods/corporate/icons/rigs/ert_commander.dmi b/mods/corporate/icons/rigs/ert_commander.dmi deleted file mode 100644 index 950ca1d712ba..000000000000 Binary files a/mods/corporate/icons/rigs/ert_commander.dmi and /dev/null differ diff --git a/mods/corporate/icons/rigs/ert_engineer.dmi b/mods/corporate/icons/rigs/ert_engineer.dmi deleted file mode 100644 index ca1b10cf8ae4..000000000000 Binary files a/mods/corporate/icons/rigs/ert_engineer.dmi and /dev/null differ diff --git a/mods/corporate/icons/rigs/ert_janitor.dmi b/mods/corporate/icons/rigs/ert_janitor.dmi deleted file mode 100644 index 7f72ccf99871..000000000000 Binary files a/mods/corporate/icons/rigs/ert_janitor.dmi and /dev/null differ diff --git a/mods/corporate/icons/rigs/ert_medic.dmi b/mods/corporate/icons/rigs/ert_medic.dmi deleted file mode 100644 index a49dd2e44d00..000000000000 Binary files a/mods/corporate/icons/rigs/ert_medic.dmi and /dev/null differ diff --git a/mods/corporate/icons/rigs/ert_security.dmi b/mods/corporate/icons/rigs/ert_security.dmi deleted file mode 100644 index 7df8bf813dee..000000000000 Binary files a/mods/corporate/icons/rigs/ert_security.dmi and /dev/null differ diff --git a/mods/corporate/items/backpacks.dm b/mods/corporate/items/backpacks.dm deleted file mode 100644 index 7913311e4c0e..000000000000 --- a/mods/corporate/items/backpacks.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/storage/backpack/satchel/tox - name = "corporate satchel" - desc = "Useful for holding research materials. The colors on it denote it as a corporate bag." - icon_state = "satchel-nt" - -/obj/item/storage/backpack/security/exo - name = "corporate security backpack" - icon_state = "securitypack_exo" - -/obj/item/storage/backpack/satchel/sec/exo - name = "corporate security satchel" - icon_state = "satchel-sec_exo" -/obj/item/storage/backpack/messenger/tox - name = "corporate messenger bag" - desc = "A backpack worn over one shoulder. Useful for holding science materials. The colors on it denote it as a corporate bag." - icon_state = "courierbagnt" - -/obj/item/storage/backpack/messenger/sec/exo - name = "corporate security messenger bag" - desc = "A tactical backpack worn over one shoulder. This is black and bottle green." - icon_state = "courierbagsec_exo" diff --git a/mods/corporate/items/badges.dm b/mods/corporate/items/badges.dm deleted file mode 100644 index 111763981d68..000000000000 --- a/mods/corporate/items/badges.dm +++ /dev/null @@ -1,27 +0,0 @@ -/obj/item/storage/box/holobadgeNT - name = "corporate holobadge box" - desc = "A box containing corporate security holobadges." - startswith = list(/obj/item/clothing/accessory/badge/holo/NT = 4, - /obj/item/clothing/accessory/badge/holo/NT/cord = 2) - -/obj/item/clothing/accessory/badge/nanotrasen - name = "corporate badge" - desc = "A leather-backed plastic badge with a variety of information printed on it. Belongs to a corporate executive." - icon_state = "ntbadge" - badge_string = "Corporate Executive Body" - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') - -/obj/item/clothing/accessory/badge/holo/NT - name = "corporate holobadge" - desc = "This glowing green badge marks the holder as a member of corporate security." - icon_state = "ntholobadge" - color = null - badge_string = "Corporate Security" - badge_access = access_research - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') - -/obj/item/clothing/accessory/badge/holo/NT/cord - icon_state = "holobadge-cord" - slot_flags = SLOT_MASK | SLOT_TIE diff --git a/mods/corporate/items/clutter.dm b/mods/corporate/items/clutter.dm deleted file mode 100644 index f58073f6f190..000000000000 --- a/mods/corporate/items/clutter.dm +++ /dev/null @@ -1,20 +0,0 @@ -/obj/item/toy/balloon/nanotrasen - name = "\improper 'motivational' balloon" - desc = "Man, I love NanoTrasen soooo much. I use only NanoTrasen products. You have NO idea." - icon_state = "ntballoon" - item_state = "ntballoon" - -/obj/item/storage/lunchbox/dais - name = "\improper DAIS brand lunchbox" - icon_state = "lunchbox_dais" - item_state = "toolbox_blue" - desc = "A little lunchbox. This one is branded with the Deimos Advanced Information Systems logo!" - -/obj/item/storage/lunchbox/nt - name = "\improper NanoTrasen brand lunchbox" - icon_state = "lunchbox_nanotrasen" - item_state = "toolbox_blue" - desc = "A little lunchbox. This one is branded with the NanoTrasen logo!" - -/obj/item/storage/lunchbox/nt/filled - filled = TRUE \ No newline at end of file diff --git a/mods/corporate/items/cups.dm b/mods/corporate/items/cups.dm deleted file mode 100644 index 2417e32e65c7..000000000000 --- a/mods/corporate/items/cups.dm +++ /dev/null @@ -1,17 +0,0 @@ -/obj/item/chems/food/drinks/glass2/coffeecup/NT - name = "\improper NT coffee cup" - desc = "A red NanoTrasen coffee cup." - icon_state = "coffeecup_NT" - base_name = "\improper NT cup" - -/obj/item/chems/food/drinks/glass2/coffeecup/corp - name = "\improper EXO coffee cup" - desc = "A tasteful coffee cup in Expeditionary Corps Organisation corporate colours." - icon_state = "coffeecup_corp" - base_name = "\improper EXO cup" - -/obj/item/chems/food/drinks/glass2/coffeecup/dais - name = "\improper DAIS coffee cup" - desc = "A coffee cup imprinted with the stylish logo of Deimos Advanced Information Systems." - icon_state = "coffeecup_dais" - base_name = "\improper DAIS cup" \ No newline at end of file diff --git a/mods/corporate/items/documents.dm b/mods/corporate/items/documents.dm deleted file mode 100644 index 13cd7e1ded36..000000000000 --- a/mods/corporate/items/documents.dm +++ /dev/null @@ -1,112 +0,0 @@ -/obj/item/documents/nanotrasen - name = "secret corporate documents" - desc = "\"Top Secret\" corporate documents, filled with complex diagrams, research procedures, and details on cloning or breeding rights to non-sapient species you encounter. It seems like they will be auctioning them off to the highest private bidder." - description_antag = "A conglomerate of powerful corporations seems to be wanting to create weaponized xenobiological species. Probably as a form of WMD, by your best guess." - icon_state = "docs_verified" - -/obj/item/book/manual/nt_regs - name = "Corporate Regulations" - desc = "A set of corporate guidelines for employees of a megacorporation." - icon_state = "booknanoregs" - author = "Employee Materials" - title = "Corporate Regulations" - url = "Corporate_Regulations" - -/obj/item/book/union_charter - name = "\improper Union Charter" - title = "Union Charter of Workplace Rights" - author = "Corporate Union" - dat = {"Corporate Union Charter of Workplace Rights - -

    0. Summary

    -
    -

    As a union representative, you are required to uphold the interests of contracted workers on your station or vessel. You are empowered to inspect workplaces and instigate cessation of contracted work when on green alert, with diminishing powers during a state of emergency. You do not have authority or jurisdiction over government or military workers, or any workers who are not card-carrying signatories to this Charter.

    -

    1. Introduction

    -

    This Charter of Rights sets out the rights and responsibilities of all workplace parties in the provision of decent and fair health, safety, compensation and rehabilitation systems and practices within affiliated workplaces. Regardless of jurisdiction, changes to occupational health and safety, compensation and rehabilitation law must not result in a diminution of the rights and entitlements of any worker.

    -

    This Charter does not apply to staff who are not signatory to the Solar Employee General Award, or are signatory to other workplace regulatory documents such as the internal protocols of your local legislative body. Union representatives must take care to ensure that their operations on mixed jurisdiction stations and vessels are restricted to those areas that have a union worker, contractor or labourer presence.

    -

    Workers must not be adversely affected by any employer moving between jurisdictions in relation to their OHS and workers compensation entitlements. Any proposed move between jurisdictions will only occur following genuine consultation and agreement with workers and their representatives and a process of public review, including public tribunal hearings.

    -

    Consistent with OHS and Worker Compensation Policy and interstellar standards, Solar law must ensure healthy and safe workplaces and a compensation and rehabilitation system which ensures that no worker is disadvantaged should they be injured at work.

    -

    All workers have the right to join a genuine trade union. Union organised workplaces are safer workplaces.

    -

    2. Security Levels

    -
    -

    On stations or vessels employing the standard Security Alert Level protocol, the following conditions apply:

    -
      -
    • On green alert, all particulars of this charter are considered valid and applicable.
    • -
    • Above green alert, union representatives are not permitted to conduct workplace inspections and are advised, but not required, to cease all union meetings or strike proceedings.
    • -
    • On red alert or above, this charter is suspended, and all union representatives and workers must follow directives from personnel authorized under red alert protocol.
    • -
    -

    3. Representation

    -
    -

    Every worker has the right to be represented on health, safety, compensation, rehabilitation and return to work issues, by their elected Union Representative and their union. Every worker has the right to elect health and safety representatives.

    -

    Unions have the right to:

    -
      -
    • Enter workplaces on health and safety issues;
    • -
    • Investigate breaches of health and safety laws;
    • -
    • Represent members and prospective members;
    • -
    • Initiate investigations and prosecutions for occupational health and safety breaches;
    • -
    • Initiate cessation of work in unsafe areas; and
    • -
    • Access all relevant information and reports.
    • -
    -

    Union Representatives have the right to:

    -
      -
    • Be democratically elected by a process determined by workers, in conjunction with their union;
    • -
    • Utilise legal rights and powers to represent workers on health and safety matters;
    • -
    • Inspect the workplace, within the agreed-upon confines previously noted;
    • -
    • Access relevant information and be informed of all incidents;
    • -
    • Be consulted by the employer before workplace changes occur that may affect health and safety;
    • -
    • Issue notices when breaches are detected;
    • -
    • Call in government inspectors;
    • -
    • Direct workers to cease work where there is a belief of immediate risk to health and safety;
    • -
    • Seek resolution of health and safety issues;
    • -
    • Perform all OHS activities on paid time and have adequate facilities;
    • -
    • Be assisted by any person at any time in the execution of union duties;
    • -
    • Be protected by law from discrimination, harassment, bullying, intimidation and prosecution;
    • -
    • Appeal any decision of a regulator or court regarding any health and safety, compensation or rehabilitation matter.
    • -
    -

    4. Workers

    -
    -

    Every worker has the right to: -

      -
    • A safe and healthy workplace;
    • -
    • Travel to and from work sites in safety and with appropriate protections;
    • -
    • Return home from work free of injury or illness;
    • -
    • Enjoy the highest level of protection, representation, compensation and rehabilitation, regardless of the jurisdiction within which they work;
    • -
    • Take collective action over any health and safety matter, including the right to cease unsafe or unhealthy work; and
    • -
    • Discuss, negotiate and be consulted and involved in all issues affecting their health, safety and welfare.
    • -
    -

    All workers (or prospective workers), including health and safety representatives, will be protected by law from discrimination, harassment, bullying or detriment to their employment because they have raised a health and safety issue, lodged a compensation claim or been involved in consultation on workplace health and safety matters.

    -

    4. Employer Responsibilities

    -
    -

    Persons who control, manage or own workplaces have an absolute duty of care without limitation to provide and maintain safe and healthy work environments. Employers will not shift jurisdictions to attempt to avoid their OHS and workers compensation responsibilities and obligations. Employers are subject to all the obligations and responsibilities contained within this Charter.

    -

    5. Compensation

    -
    -

    Following a physical or psychological injury, all workers have the right to a fair, just and equitable compensation system, which promotes the best medical and like support, the most effective rehabilitation for injured workers and facilitates a safe return to work that offers genuine job security. Workers' compensation standards are to:

    -
  • Be available to all members of the workforce;
  • -
  • Provide compensation for all injuries that arise from travel to, from or during work including and during recess breaks;
  • -
  • Be available upon the death of a worker and for dependants of that worker;
  • -
  • Be based on the 100% replacement of loss of income;
  • -
  • Provide total cost of medical rehabilitation and other related expenses;
  • -
  • Provide lump sum compensation for permanent disability;
  • -
  • Ensure common law rights;
  • -
  • Support rehabilitation and return to work;
  • -
  • Ensure that workers are entitled to timely and effective claim determination and dispute resolution processes;
  • -
  • Ensure the worker has access to the doctor of their choice; and
  • -
  • Not be eroded by companies seeking to self-insure in order to obtain lower OHS and worker's compensation entitlements for workers.
  • - -

    6. Rehabilitation

    -
    -

    All workers have the right to return to safe, suitable, meaningful and sustainable work, following the provision of quality rehabilitation services, commensurate to need. Rehabilitation will include the right to:

    -
      -
    • Union representation;
    • -
    • Fair, equitable, high quality, appropriate, effective and timely rehabilitation plans and services;
    • -
    • Consultation about all aspects of rehabilitation;
    • -
    • All documentation and information relating to their rehabilitation;
    • -
    • Privacy in the management of all records and information; and
    • -
    • Personal choice of medical provider and rehabilitation service, where facilities permit.
    • -
    - - "} - -/obj/item/folder/nt - desc = "A corporate folder." - icon_state = "folder_nt" diff --git a/mods/corporate/items/medals.dm b/mods/corporate/items/medals.dm deleted file mode 100644 index 4fcecb3a0645..000000000000 --- a/mods/corporate/items/medals.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/clothing/accessory/medal/nanotrasen - name = "corporate merit medal" - desc = "An iron medal awarded to employees for merit." - icon_state = "iron_nt" - icon = 'mods/corporate/icons/obj/clothing/obj_accessories.dmi' - accessory_icons = list(slot_w_uniform_str = 'mods/corporate/icons/mob/onmob_accessories.dmi', slot_wear_suit_str = 'mods/corporate/icons/mob/onmob_accessories.dmi') - -/obj/item/clothing/accessory/medal/nanotrasen/gold - name = "corporate command medal" - desc = "A gold medal awarded to employees for service as the Captain of a corporate facility, station, or vessel." - icon_state = "gold_nt" - -/obj/item/clothing/accessory/medal/nanotrasen/silver - name = "corporate service medal" - desc = "A silver medal awarded to employees for distinguished service in support of corporate interests." - icon_state = "silver_nt" - -/obj/item/clothing/accessory/medal/nanotrasen/bronze - name = "corporate sciences medal" - desc = "A bronze medal awarded to employees for signifigant contributions to the fields of science or engineering." - icon_state = "bronze_nt" diff --git a/mods/corporate/items/wristcomp.dm b/mods/corporate/items/wristcomp.dm deleted file mode 100644 index f7e14d4989a1..000000000000 --- a/mods/corporate/items/wristcomp.dm +++ /dev/null @@ -1,65 +0,0 @@ -/obj/item/modular_computer/pda/wrist - name = "wrist computer" - desc = "A wrist-mounted modular personal computer. Very stylish." - icon = 'mods/corporate/icons/obj/wristcomp.dmi' - screen_icon = 'mods/corporate/icons/obj/wristcomp_screens.dmi' - - slot_flags = SLOT_ID | SLOT_BELT - color = COLOR_GUNMETAL - light_color = LIGHT_COLOR_GREEN - -/obj/item/modular_computer/pda/wrist/get_mob_overlay(var/mob/user_mob, var/slot) - var/image/ret = ..() - var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos) - var/datum/extension/assembly/modular_computer/assembly = get_extension(src, /datum/extension/assembly) - if(slot == slot_wear_id_str) - if(assembly?.enabled) - var/image/I = image(screen_icon, icon_state = "[ret.icon_state]-screen") - I.appearance_flags |= RESET_COLOR - I.color = (assembly.bsod || os?.updating) ? "#0000ff" : "#00ff00" - ret.overlays.Add(I) - else - ret.overlays.Add(image(screen_icon, icon_state = "[ret.icon_state]-screen_off")) - for(var/decal in decals) - var/image/I = image(icon = ret.icon, icon_state = "[ret.icon_state]-[decal]") - I.appearance_flags |= RESET_COLOR - I.color = decals[decal] - ret.overlays.Add(I) - return ret - -/obj/item/modular_computer/pda/wrist/AltClick(var/mob/user) - if(!CanPhysicallyInteract(user)) - return - var/datum/extension/assembly/assembly = get_extension(src, /datum/extension/assembly) - var/obj/item/stock_parts/computer/card_slot/card_slot = assembly.get_component(PART_CARD) - if(card_slot?.stored_card) - card_slot.eject_id(user) - else - ..() - -/obj/item/modular_computer/pda/wrist/attack_hand(var/mob/user) - if(loc == user) - if(user.incapacitated() || user.restrained()) - return - var/mob/living/carbon/human/H = user - if(istype(H) && src == H.wear_id) - return attack_self(user) - return ..() - -/obj/item/modular_computer/pda/wrist/MouseDrop(var/obj/over_object) - if(ishuman(usr)) - if(loc != usr) return - if(usr.restrained() || usr.incapacitated()) return - if (!usr.unEquip(src)) return - usr.put_in_hands(src) - src.add_fingerprint(usr) - return - return ..() - -// wrist box // - -/obj/item/storage/box/wrist - name = "box of spare wrist computers" - desc = "A box of spare wrist microcomputers." - icon_state = "pda" - startswith = list(/obj/item/modular_computer/pda/wrist = 5) diff --git a/mods/corporate/machines/machines.dm b/mods/corporate/machines/machines.dm deleted file mode 100644 index 7ff825f3780b..000000000000 --- a/mods/corporate/machines/machines.dm +++ /dev/null @@ -1,5 +0,0 @@ -/obj/machinery/vending/dinnerware/Initialize(mapload, d, populate_parts) - products = products || list() - products[/obj/item/storage/lunchbox/nt] = 3 - products[/obj/item/storage/lunchbox/dais] = 3 - . = ..() diff --git a/mods/corporate/structures/lockers.dm b/mods/corporate/structures/lockers.dm deleted file mode 100644 index 4a373883d9a9..000000000000 --- a/mods/corporate/structures/lockers.dm +++ /dev/null @@ -1,64 +0,0 @@ -/decl/closet_appearance/secure_closet/corporate - color = COLOR_GREEN_GRAY - decals = list( - "lower_holes" - ) - extra_decals = list( - "stripe_vertical_mid_full" = COLOR_GRAY80, - "research" = COLOR_OFF_WHITE - ) - -/obj/structure/closet/wardrobe/red/Initialize() - . = ..() - new /obj/item/clothing/head/beret/corp/sec/corporate/officer(src) - new /obj/item/clothing/head/beret/corp/sec/corporate/officer(src) - new /obj/item/clothing/head/beret/corp/sec/corporate/officer(src) - -/obj/structure/closet/secure_closet/hos/WillContain() - . = ..() + /obj/item/clothing/head/beret/corp/sec/corporate/hos - -/obj/structure/closet/secure_closet/warden/WillContain() - . = ..() + /obj/item/clothing/head/beret/corp/sec/corporate/warden - -/obj/structure/closet/secure_closet/xenoarchaeologist/Initialize() - . = ..() - if(!(locate(/obj/item/storage/backpack/toxins) in contents)) - new /obj/item/storage/backpack/satchel/tox(src) - -/obj/structure/closet/secure_closet/security/WillContain() - . = ..() - . += /obj/item/clothing/suit/armor/vest/nt - . += /obj/item/clothing/head/soft/sec/corp - . += /obj/item/clothing/under/rank/security/corp - -/obj/structure/closet/wardrobe/red/Initialize() - . = ..() - new /obj/item/clothing/head/beret/corp/sec(src) - new /obj/item/clothing/head/beret/corp/sec(src) - new /obj/item/clothing/head/beret/corp/sec(src) - -/obj/structure/closet/secure_closet/scientist/WillContain() - . = ..() + new /datum/atom_creator/weighted(list(/obj/item/storage/backpack/messenger/tox, /obj/item/storage/backpack/satchel/tox)) - -/obj/structure/closet/secure_closet/xenobio/WillContain() - . = ..() + new /datum/atom_creator/weighted(list(/obj/item/storage/backpack/messenger/tox, /obj/item/storage/backpack/satchel/tox)) - -/obj/structure/closet/secure_closet/captains/WillContain() - . = ..() - . += /obj/item/clothing/suit/armor/captain - . += /obj/item/clothing/suit/armor/vest/nt - -/obj/structure/closet/secure_closet/warden/WillContain() - . = ..() - . += /obj/item/clothing/head/helmet/corp - . += /obj/item/clothing/suit/armor/vest/nt - . += /obj/item/clothing/under/rank/warden/corp - -/obj/structure/closet/secure_closet/hos/WillContain() - . = ..() - . += /obj/item/clothing/head/helmet/corp - . += /obj/item/clothing/suit/armor/vest/nt - . += /obj/item/clothing/under/rank/head_of_security/corp - -/obj/structure/closet/secure_closet/hop/WillContain() - . = ..() + /obj/item/clothing/suit/armor/vest/nt diff --git a/mods/dionaea/datums/ghosttrap.dm b/mods/dionaea/datums/ghosttrap.dm deleted file mode 100644 index 46ed3a97d7b0..000000000000 --- a/mods/dionaea/datums/ghosttrap.dm +++ /dev/null @@ -1,6 +0,0 @@ -/datum/ghosttrap/plant/welcome_candidate(var/mob/target) - ..() - // This is a hack, replace with some kind of species blurb proc. - if(istype(target,/mob/living/carbon/alien/diona)) - to_chat(target, "You are \a [target], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders.") - to_chat(target, "Too much darkness will send you into shock and starve you, but light will help you heal.") diff --git a/mods/dionaea/datums/language.dm b/mods/dionaea/datums/language.dm deleted file mode 100644 index ce87beb204b2..000000000000 --- a/mods/dionaea/datums/language.dm +++ /dev/null @@ -1,16 +0,0 @@ -/decl/language/diona - name = "Nymph" - desc = "A language known instinctively by diona nymphs." - speech_verb = "creaks and rustles" - ask_verb = "creaks" - exclaim_verb = "rustles" - colour = "soghun" - key = "q" - flags = RESTRICTED - syllables = list("hs","zt","kr","st","sh") - shorthand = "RT" - machine_understands = FALSE - hidden_from_codex = TRUE - -/decl/language/diona/get_random_name() - . = "[pick(list("To Sleep Beneath","Wind Over","Embrace of","Dreams of","Witnessing","To Walk Beneath","Approaching the"))] [pick(list("the Void","the Sky","Encroaching Night","Planetsong","Starsong","the Wandering Star","the Empty Day","Daybreak","Nightfall","the Rain"))]" diff --git a/mods/dionaea/datums/loadout.dm b/mods/dionaea/datums/loadout.dm deleted file mode 100644 index b7a72ea0acfd..000000000000 --- a/mods/dionaea/datums/loadout.dm +++ /dev/null @@ -1,4 +0,0 @@ -/datum/gear/plush_nymph - display_name = "diona nymph plush" - description = "A plush toy of a diona nymph." - path = /obj/item/toy/plushie/nymph diff --git a/mods/dionaea/datums/seed.dm b/mods/dionaea/datums/seed.dm deleted file mode 100644 index fcc5c10fe8d2..000000000000 --- a/mods/dionaea/datums/seed.dm +++ /dev/null @@ -1,27 +0,0 @@ -/datum/seed/diona - name = "diona" - seed_name = "diona" - seed_noun = SEED_NOUN_NODES - display_name = "diona nymph pods" - can_self_harvest = 1 - has_mob_product = /mob/living/carbon/alien/diona - -/datum/seed/diona/New() - ..() - set_trait(TRAIT_IMMUTABLE,1) - set_trait(TRAIT_ENDURANCE,8) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,10) - set_trait(TRAIT_YIELD,1) - set_trait(TRAIT_POTENCY,30) - set_trait(TRAIT_PRODUCT_ICON,"diona") - set_trait(TRAIT_PRODUCT_COLOUR,"#799957") - set_trait(TRAIT_PLANT_COLOUR,"#66804b") - set_trait(TRAIT_PLANT_ICON,"alien4") - -/obj/item/seeds/diona - seed_type = "diona" - -/decl/hierarchy/supply_pack/hydroponics/exoticseeds/Initialize() - contains[/obj/item/seeds/diona] = 2 - . = ..() diff --git a/mods/dionaea/dionaea.dm b/mods/dionaea/dionaea.dm deleted file mode 100644 index 918d461fec60..000000000000 --- a/mods/dionaea/dionaea.dm +++ /dev/null @@ -1,2 +0,0 @@ -/decl/modpack/dionaea - name = "Diona Nymphs" diff --git a/mods/dionaea/icons/gestalt.dmi b/mods/dionaea/icons/gestalt.dmi deleted file mode 100644 index 0a2d3ed70b4c..000000000000 Binary files a/mods/dionaea/icons/gestalt.dmi and /dev/null differ diff --git a/mods/dionaea/items/cup.dm b/mods/dionaea/items/cup.dm deleted file mode 100644 index 7cc6d1a0ec1d..000000000000 --- a/mods/dionaea/items/cup.dm +++ /dev/null @@ -1,5 +0,0 @@ -/obj/item/chems/food/drinks/glass2/coffeecup/diona - name = "diona nymph coffee cup" - desc = "A green coffee cup featuring the image of a diona nymph." - icon_state = "coffeecup_diona" - base_name = "diona cup" diff --git a/mods/dionaea/items/lunchbox.dm b/mods/dionaea/items/lunchbox.dm deleted file mode 100644 index b1e906a69c30..000000000000 --- a/mods/dionaea/items/lunchbox.dm +++ /dev/null @@ -1,8 +0,0 @@ -/obj/item/storage/lunchbox/nymph - name = "\improper Diona nymph lunchbox" - icon_state = "lunchbox_dionanymph" - item_state = "toolbox_yellow" - desc = "A little lunchbox. This one is an adorable Diona nymph on the side!" - -/obj/item/storage/lunchbox/nymph/filled - filled = TRUE \ No newline at end of file diff --git a/mods/dionaea/items/roast.dm b/mods/dionaea/items/roast.dm deleted file mode 100644 index 67ba6db537dd..000000000000 --- a/mods/dionaea/items/roast.dm +++ /dev/null @@ -1,14 +0,0 @@ -/obj/item/chems/food/snacks/dionaroast - name = "roast diona" - desc = "It's like an enormous, leathery carrot. With an eye." - icon_state = "dionaroast" - trash = /obj/item/trash/plate - filling_color = "#75754b" - center_of_mass = @"{'x':16,'y':7}" - nutriment_desc = list("a chorus of flavor" = 6) - nutriment_amt = 6 - bitesize = 2 - -/obj/item/chems/food/snacks/dionaroast/Initialize() - .=..() - reagents.add_reagent(/decl/material/solid/metal/radium, 2) diff --git a/mods/dionaea/mob/_nymph.dm b/mods/dionaea/mob/_nymph.dm deleted file mode 100644 index 152aca436da0..000000000000 --- a/mods/dionaea/mob/_nymph.dm +++ /dev/null @@ -1,100 +0,0 @@ -#define DIONA_SCREEN_LOC_HELD "EAST-8:16,SOUTH:5" -#define DIONA_SCREEN_LOC_HAT "EAST-7:16,SOUTH:5" -#define DIONA_SCREEN_LOC_INTENT "EAST-2,SOUTH:5" -#define DIONA_SCREEN_LOC_HEALTH ui_alien_health - -/datum/extension/hattable/diona_nymph/wear_hat(mob/wearer, obj/item/clothing/head/new_hat) - var/mob/living/carbon/alien/diona/doona = wearer - if(istype(doona) && (!doona.holding_item || doona.holding_item != new_hat)) - . = ..() - if(.) - hat?.screen_loc = DIONA_SCREEN_LOC_HAT - -/mob/living/carbon/alien/diona - name = "diona nymph" - desc = "It's a little skittery critter. Chirp." - icon = 'mods/dionaea/icons/gestalt.dmi' - icon_state = "nymph" - item_state = "nymph" - death_msg = "expires with a pitiful chirrup..." - health = 60 - maxHealth = 60 - available_maneuvers = list(/decl/maneuver/leap) - status_flags = NO_ANTAG - - language = /decl/language/diona - species_language = /decl/language/diona - only_species_language = 1 - voice_name = "diona nymph" - speak_emote = list("chirrups") - universal_understand = FALSE - universal_speak = FALSE - - can_pull_size = ITEM_SIZE_SMALL - can_pull_mobs = MOB_PULL_SMALLER - - holder_type = /obj/item/holder/diona - possession_candidate = 1 - atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_NO_REACT - hud_type = /datum/hud/diona_nymph - - ai = /datum/ai/nymph - - var/obj/item/holding_item - var/mob/living/carbon/alien/diona/next_nymph - var/mob/living/carbon/alien/diona/previous_nymph - var/tmp/image/flower - var/tmp/image/eyes - var/tmp/last_glow - -/mob/living/carbon/alien/diona/get_jump_distance() - return 3 - -/mob/living/carbon/alien/diona/Login() - . = ..() - if(client) - if(holding_item) - holding_item.screen_loc = DIONA_SCREEN_LOC_HELD - client.screen |= holding_item - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable?.hat) - hattable.hat.screen_loc = DIONA_SCREEN_LOC_HAT - client.screen |= hattable.hat - -/mob/living/carbon/alien/diona/sterile - name = "sterile nymph" - -/mob/living/carbon/alien/diona/sterile/Initialize(var/mapload) - . = ..(mapload, 0) - -/mob/living/carbon/alien/diona/Initialize(var/mapload, var/flower_chance = 15) - - add_language(/decl/language/diona) - add_language(/decl/language/human/common, 0) - - set_extension(src, /datum/extension/hattable/diona_nymph, 0, -8) - - eyes = image(icon = icon, icon_state = "eyes_[icon_state]") - eyes.layer = EYE_GLOW_LAYER - eyes.plane = EFFECTS_ABOVE_LIGHTING_PLANE - - if(prob(flower_chance)) - flower = image(icon = icon, icon_state = "flower_back") - var/image/I = image(icon = icon, icon_state = "flower_fore") - I.color = get_random_colour(1) - flower.overlays += I - - update_icons() - - . = ..(mapload) - -/mob/living/carbon/alien/diona/examine(mob/user) - . = ..() - if(holding_item) - to_chat(user, SPAN_NOTICE("It is holding \icon[holding_item] \a [holding_item].")) - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable?.hat) - to_chat(user, SPAN_NOTICE("It is wearing \icon[hattable.hat] \a [hattable.hat].")) - -/mob/living/carbon/alien/diona/has_dexterity() - return FALSE \ No newline at end of file diff --git a/mods/dionaea/mob/gestalt/_gestalt.dm b/mods/dionaea/mob/gestalt/_gestalt.dm deleted file mode 100644 index b6a1cb074e60..000000000000 --- a/mods/dionaea/mob/gestalt/_gestalt.dm +++ /dev/null @@ -1,46 +0,0 @@ -/obj/structure/diona_gestalt - name = "nascent diona gestalt" - desc = "A heaving mass of nymphs. Chirp?" - icon = 'mods/dionaea/icons/gestalt.dmi' - icon_state = "gestalt" - density = TRUE - opacity = FALSE - anchored = FALSE - movement_handlers = list(/datum/movement_handler/deny_multiz, /datum/movement_handler/delay = list(5)) - appearance_flags = PIXEL_SCALE - - var/list/nymphs = list() - var/list/valid_things_to_roll_up = list(/mob/living/carbon/alien/diona = TRUE, /mob/living/carbon/alien/diona/sterile = TRUE) - var/tmp/image/eyes_overlay - -/obj/structure/diona_gestalt/mob_breakout(var/mob/living/escapee) - . = ..() - shed_atom(escapee) - return TRUE - -/obj/structure/diona_gestalt/Initialize(var/mapload) - eyes_overlay = image(icon = icon, icon_state = "eyes_gestalt") - eyes_overlay.layer = EYE_GLOW_LAYER - eyes_overlay.plane = EFFECTS_ABOVE_LIGHTING_PLANE - update_icon() - . = ..(mapload) - -/obj/structure/diona_gestalt/on_update_icon() - overlays = list(eyes_overlay) - if(nymphs && nymphs.len) - var/matrix/M = matrix() - M.Scale(Clamp(nymphs.len * 0.1, 1, 2)) - transform = M - else - transform = null - -/obj/structure/diona_gestalt/Destroy() - for(var/thing in contents) - var/atom/movable/AM = thing - AM.dropInto(loc) - nymphs.Cut() - . = ..() - -/obj/structure/diona_gestalt/examine(mob/user) - . = ..() - if(nymphs) to_chat(user, "It seems to be composed of at least [nymphs.len] nymph\s.") diff --git a/mods/dionaea/mob/gestalt/gestalt_attacks.dm b/mods/dionaea/mob/gestalt/gestalt_attacks.dm deleted file mode 100644 index 5cbda5a9a77d..000000000000 --- a/mods/dionaea/mob/gestalt/gestalt_attacks.dm +++ /dev/null @@ -1,23 +0,0 @@ -/obj/structure/diona_gestalt/attackby(var/obj/item/thing, var/mob/user) - . = ..() - if(thing.force) - shed_atom(forcefully = TRUE) - -/obj/structure/diona_gestalt/hitby() - . = ..() - shed_atom(forcefully = TRUE) - -/obj/structure/diona_gestalt/bullet_act(var/obj/item/projectile/P, var/def_zone) - . = ..() - if(P && (P.damage_type == BRUTE || P.damage_type == BURN)) - shed_atom(forcefully = TRUE) - -/obj/structure/diona_gestalt/explosion_act() - SHOULD_CALL_PARENT(FALSE) - var/shed_count = rand(1,3) - while(shed_count && nymphs && nymphs.len) - shed_count-- - shed_atom(forcefully = TRUE) - -/obj/structure/diona_gestalt/proc/handle_member_click(var/mob/living/carbon/alien/diona/clicker) - return diff --git a/mods/dionaea/mob/gestalt/gestalt_turfs.dm b/mods/dionaea/mob/gestalt/gestalt_turfs.dm deleted file mode 100644 index f1ec10f588bf..000000000000 --- a/mods/dionaea/mob/gestalt/gestalt_turfs.dm +++ /dev/null @@ -1,11 +0,0 @@ -/decl/flooring/diona - name = "biomass" - desc = "A mass of small intertwined aliens forming a floor... creepy." - icon = 'mods/dionaea/icons/gestalt.dmi' - icon_base = "floor" - flags = TURF_ACID_IMMUNE | TURF_REMOVE_SHOVEL - -/turf/simulated/floor/diona - name = "biomass" - icon = 'icons/turf/floors.dmi' - initial_flooring = /decl/flooring/diona diff --git a/mods/dionaea/mob/nymph_attacks.dm b/mods/dionaea/mob/nymph_attacks.dm deleted file mode 100644 index a708b8d0f32b..000000000000 --- a/mods/dionaea/mob/nymph_attacks.dm +++ /dev/null @@ -1,110 +0,0 @@ -/mob/living/carbon/alien/diona/UnarmedAttack(var/atom/A) - - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - - if(istype(loc, /obj/structure/diona_gestalt)) - var/obj/structure/diona_gestalt/gestalt = loc - return gestalt.handle_member_click(src, A) - else - - if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) - return handle_tray_interaction(A) - - // This is super hacky. Not sure if I will leave this in for a final merge. - // Reporting back from the future: keeping this because trying to refactor - // seed storage to handle this cleanly would be a pain in the ass and I - // don't want to touch that pile. - - if(istype(A, /obj/machinery/seed_storage)) - visible_message("\The [src] headbutts \the [A]!") - var/obj/machinery/seed_storage/G = A - if(LAZYLEN(G.piles)) - var/datum/seed_pile/pile = pick(G.piles) - var/obj/item/seeds/S = pick(pile.seeds) - if(S) - pile.amount -= 1 - pile.seeds -= S - if(pile.amount <= 0 || LAZYLEN(pile.seeds) <= 0) - G.piles -= pile - qdel(pile) - S.forceMove(get_turf(G)) - G.visible_message("\A [S] falls out!") - return - // End superhacky stuff. - - if((a_intent == I_DISARM || a_intent == I_HELP) && can_collect(A)) - collect(A) - return - - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - if(hattable?.wear_hat(src, A)) - return - - if(istype(A, /mob)) - if(src != A && !gestalt_with(A)) - visible_message("\The [src] butts its head into \the [A].") - return - - . = ..() - -/mob/living/carbon/alien/diona/RangedAttack(atom/A, var/params) - if((a_intent == I_HURT || a_intent == I_GRAB) && holding_item) - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - visible_message("\The [src] spits \a [holding_item] at \the [A]!") - var/atom/movable/temp = holding_item - unEquip(holding_item) - if(temp) - temp.throw_at(A, 10, rand(3,5), src) - return TRUE - . = ..() - -/mob/living/carbon/alien/diona/proc/handle_tray_interaction(var/obj/machinery/portable_atmospherics/hydroponics/tray) - - if(incapacitated()) - return - - if(!tray.seed && istype(holding_item, /obj/item/seeds)) - var/atom/movable/temp = holding_item - unEquip(temp) - if(temp) - tray.plant_seed(src, temp) - return - - if(tray.dead) - if(tray.remove_dead(src, silent = TRUE)) - reagents.add_reagent(/decl/material/liquid/nutriment/glucose, rand(10,20)) - visible_message("\The [src] chews up the dead plant, clearing \the [tray] out.", "You devour the dead plant, clearing \the [tray].") - return - - if(tray.harvest) - if(tray.harvest(src)) - visible_message("\The [src] harvests from \the [tray].", "You harvest the contents of \the [tray].") - return - - if(tray.weedlevel || tray.pestlevel) - reagents.add_reagent(/decl/material/liquid/nutriment/glucose, (tray.weedlevel + tray.pestlevel)) - tray.weedlevel = 0 - tray.pestlevel = 0 - visible_message("\The [src] begins rooting through \the [tray], ripping out pests and weeds, and eating them noisily.","You begin rooting through \the [tray], ripping out pests and weeds, and eating them noisily.") - return - - if(tray.nutrilevel < 10) - var/nutrition_cost = (10-tray.nutrilevel) * 5 - if(nutrition >= nutrition_cost) - visible_message("\The [src] secretes a trickle of green liquid, refilling [tray].","You secrete some nutrients into \the [tray].") - tray.nutrilevel = 10 - adjust_nutrition(-((10-tray.nutrilevel) * 5)) - else - to_chat(src, "You haven't eaten enough to refill \the [tray]'s nutrients.") - return - - if(tray.waterlevel < 100) - var/nutrition_cost = Floor((100-tray.nutrilevel)/10) * 5 - if(nutrition >= nutrition_cost) - visible_message("\The [src] secretes a trickle of clear liquid, refilling [tray].","You secrete some water into \the [tray].") - tray.waterlevel = 100 - else - to_chat(src, "You haven't eaten enough to refill \the [tray]'s water.") - return - - visible_message("\The [src] rolls around in \the [tray] for a bit.","You roll around in \the [tray] for a bit.") diff --git a/mods/dionaea/mob/nymph_death.dm b/mods/dionaea/mob/nymph_death.dm deleted file mode 100644 index a4e3857b0c37..000000000000 --- a/mods/dionaea/mob/nymph_death.dm +++ /dev/null @@ -1,7 +0,0 @@ -/mob/living/carbon/alien/diona/death(gibbed) - var/obj/structure/diona_gestalt/gestalt = loc - if(istype(gestalt)) - gestalt.shed_atom(src, TRUE, FALSE) - if(holding_item) - unEquip(holding_item) - return ..(gibbed,death_msg) diff --git a/mods/dionaea/mob/nymph_emotes.dm b/mods/dionaea/mob/nymph_emotes.dm deleted file mode 100644 index 590197c205a5..000000000000 --- a/mods/dionaea/mob/nymph_emotes.dm +++ /dev/null @@ -1,29 +0,0 @@ -/mob/living/carbon/alien/diona - default_emotes = list( - /decl/emote/visible, - /decl/emote/visible/scratch, - /decl/emote/visible/drool, - /decl/emote/visible/nod, - /decl/emote/visible/sway, - /decl/emote/visible/sulk, - /decl/emote/visible/twitch, - /decl/emote/visible/dance, - /decl/emote/visible/roll, - /decl/emote/visible/shake, - /decl/emote/visible/jump, - /decl/emote/visible/shiver, - /decl/emote/visible/collapse, - /decl/emote/audible/hiss, - /decl/emote/audible, - /decl/emote/audible/scretch, - /decl/emote/audible/choke, - /decl/emote/audible/gnarl, - /decl/emote/audible/bug_hiss, - /decl/emote/audible/bug_chitter, - /decl/emote/audible/chirp - ) - -/decl/emote/audible/chirp - key = "chirp" - emote_message_3p = "USER chirps!" - emote_sound = 'mods/dionaea/sounds/nymphchirp.ogg' diff --git a/mods/dionaea/mob/nymph_holder.dm b/mods/dionaea/mob/nymph_holder.dm deleted file mode 100644 index 71c1da2f5629..000000000000 --- a/mods/dionaea/mob/nymph_holder.dm +++ /dev/null @@ -1,17 +0,0 @@ -/obj/item/holder/diona - origin_tech = "{'magnets':3,'biotech':5}" - slot_flags = SLOT_HEAD | SLOT_OCLOTHING | SLOT_HOLSTER - armor = list( - bio = ARMOR_BIO_RESISTANT, - rad = ARMOR_RAD_SHIELDED - ) - -// Yes, you can wear a nymph on your head instead of a radiation mask. -/obj/item/holder/diona/equipped(var/mob/living/user, var/slot) - if(slot == slot_l_hand || slot == slot_r_hand) - body_parts_covered = ARMS - else if(slot == slot_head) - body_parts_covered = HEAD - else if(slot == slot_wear_suit) - body_parts_covered = UPPER_TORSO - . = ..() \ No newline at end of file diff --git a/mods/dionaea/mob/nymph_inventory.dm b/mods/dionaea/mob/nymph_inventory.dm deleted file mode 100644 index 2104a14aaaa8..000000000000 --- a/mods/dionaea/mob/nymph_inventory.dm +++ /dev/null @@ -1,57 +0,0 @@ -/mob/living/carbon/alien/diona/drop_from_inventory(var/obj/item/I) - . = ..() - if(I == holding_item) - holding_item = null - -/mob/living/carbon/alien/diona/put_in_hands(var/obj/item/W) // No hands. Use mouth. - if(can_collect(W)) - collect(W) - else - W.forceMove(get_turf(src)) - return 1 - -/mob/living/carbon/alien/diona/proc/can_collect(var/obj/item/collecting) - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - return (!holding_item && \ - istype(collecting) && \ - collecting != hattable?.hat && \ - collecting.loc != src && \ - !collecting.anchored && \ - collecting.simulated && \ - collecting.w_class <= can_pull_size \ - ) - -/mob/living/carbon/alien/diona/proc/collect(var/obj/item/collecting) - collecting.forceMove(src) - holding_item = collecting - visible_message("\The [src] engulfs \the [holding_item].") - - // This means dionaea can hoover up beakers as a kind of impromptu chem disposal - // technique, so long as they're okay with the reagents reacting inside them. - if(holding_item.reagents && holding_item.reagents.total_volume) - holding_item.reagents.trans_to_mob(src, holding_item.reagents.total_volume, CHEM_INGEST) - - // It also means they can do the old school cartoon schtick of eating an entire sandwich - // and spitting up an empty plate. Ptooie. - if(istype(holding_item, /obj/item/chems/food)) - var/obj/item/chems/food/food = holding_item - holding_item = null - if(food.trash) holding_item = new food.trash(src) - qdel(food) - - if(!QDELETED(holding_item)) - holding_item.equipped(src) - holding_item.screen_loc = DIONA_SCREEN_LOC_HELD - -/mob/living/carbon/alien/diona/verb/drop_item_verb() - set name = "Drop Held Item" - set desc = "Drop the item you are currently holding inside." - set category = "IC" - set src = usr - drop_item() - -/mob/living/carbon/alien/diona/drop_item() - if(holding_item && unEquip(holding_item)) - visible_message(SPAN_NOTICE("\The [src] regurgitates \the [holding_item].")) - return TRUE - . = ..() diff --git a/mods/dionaea/mob/nymph_life.dm b/mods/dionaea/mob/nymph_life.dm deleted file mode 100644 index 5107e9cdbd34..000000000000 --- a/mods/dionaea/mob/nymph_life.dm +++ /dev/null @@ -1,29 +0,0 @@ -//Dionaea regenerate health and nutrition in light. -/mob/living/carbon/alien/diona/handle_environment(datum/gas_mixture/environment) - - if(health <= 0 || stat == DEAD) - return - - var/turf/checking = get_turf(src) - if(!checking) - return - - var/light_amount = checking.get_lumcount() * 5 - - if(radiation <= 20) - if(last_glow) - set_light(0) - last_glow = 0 - else - var/mult = Clamp(radiation/200, 0.5, 1) - if(last_glow != mult) - set_light(mult, 0.5, (5*mult), 2, "#55ff55") - last_glow = mult - - set_nutrition(Clamp(nutrition + Floor(radiation/100) + light_amount, 0, 500)) - - if(radiation >= 50 || light_amount > 2) //if there's enough light, heal - adjustBruteLoss(-1) - adjustFireLoss(-1) - adjustToxLoss(-1) - adjustOxyLoss(-1) diff --git a/mods/dionaea/mob/nymph_ui.dm b/mods/dionaea/mob/nymph_ui.dm deleted file mode 100644 index cec262c0ec0d..000000000000 --- a/mods/dionaea/mob/nymph_ui.dm +++ /dev/null @@ -1,60 +0,0 @@ -/obj/screen/intent/diona_nymph - icon = 'mods/dionaea/icons/gestalt.dmi' - icon_state = "intent_devour" - screen_loc = DIONA_SCREEN_LOC_INTENT - -/obj/screen/intent/diona_nymph/on_update_icon() - if(intent == I_HURT || intent == I_GRAB) - intent = I_GRAB - icon_state = "intent_expel" - else - intent = I_DISARM - icon_state = "intent_devour" - -/obj/screen/diona - icon = 'mods/dionaea/icons/gestalt.dmi' - -/obj/screen/diona/hat - name = "equipped hat" - screen_loc = DIONA_SCREEN_LOC_HAT - icon_state = "hat" - -/obj/screen/diona/hat/Click() - var/datum/extension/hattable/hattable = get_extension(usr, /datum/extension/hattable) - hattable?.drop_hat(usr) - -/obj/screen/diona/held - name = "held item" - screen_loc = DIONA_SCREEN_LOC_HELD - icon_state = "held" - -/obj/screen/diona/held/Click() - var/mob/living/carbon/alien/diona/chirp = usr - if(istype(chirp) && chirp.holding_item) chirp.unEquip(chirp.holding_item) - -/datum/hud/diona_nymph - var/obj/screen/diona/hat/hat - var/obj/screen/diona/held/held - -/datum/hud/diona_nymph/FinalizeInstantiation() - - src.adding = list() - src.other = list() - - hat = new - adding += hat - - held = new - adding += held - - action_intent = new /obj/screen/intent/diona_nymph() - adding += action_intent - - mymob.healths = new /obj/screen() - mymob.healths.icon = 'mods/dionaea/icons/gestalt.dmi' - mymob.healths.icon_state = "health0" - mymob.healths.SetName("health") - mymob.healths.screen_loc = DIONA_SCREEN_LOC_HEALTH - - mymob.client.screen = list(mymob.healths) - mymob.client.screen += src.adding + src.other diff --git a/mods/dionaea/mob/nymph_update_icons.dm b/mods/dionaea/mob/nymph_update_icons.dm deleted file mode 100644 index f4e7ee5f31b3..000000000000 --- a/mods/dionaea/mob/nymph_update_icons.dm +++ /dev/null @@ -1,16 +0,0 @@ -/mob/living/carbon/alien/diona/update_icons() - cut_overlays() - if(stat == DEAD) - icon_state = "[initial(icon_state)]_dead" - else if(lying || resting || stunned) - icon_state = "[initial(icon_state)]_sleep" - else - icon_state = "[initial(icon_state)]" - if(eyes) - add_overlay(eyes) - if(flower) - add_overlay(flower) - var/datum/extension/hattable/hattable = get_extension(src, /datum/extension/hattable) - var/image/I = hattable?.get_hat_overlay(src) - if(I) - add_overlay(I) diff --git a/mods/gamemodes/cult/_cult.dm b/mods/gamemodes/cult/_cult.dm new file mode 100644 index 000000000000..37d934178bb1 --- /dev/null +++ b/mods/gamemodes/cult/_cult.dm @@ -0,0 +1,27 @@ +#define isconstruct(A) istype(A, /mob/living/simple_animal/construct) + +#define CULTINESS_PER_CULTIST 40 +#define CULTINESS_PER_SACRIFICE 40 +#define CULTINESS_PER_TURF 1 + +#define CULT_RUNES_1 200 +#define CULT_RUNES_2 400 +#define CULT_RUNES_3 1000 + +#define CULT_GHOSTS_1 400 +#define CULT_GHOSTS_2 800 +#define CULT_GHOSTS_3 1200 + +#define CULT_MAX_CULTINESS 1200 // When this value is reached, the game stops checking for updates so we don't recheck every time a tile is converted in endgame + +/decl/modpack/cult + name = "Cult Gamemode Content" + +/decl/modpack/cult/post_initialize() + . = ..() + global.href_to_mob_type["Constructs"] = list( + "Armoured" = /mob/living/simple_animal/construct/armoured, + "Builder" = /mob/living/simple_animal/construct/builder, + "Wraith" = /mob/living/simple_animal/construct/wraith, + "Shade" = /mob/living/simple_animal/shade + ) \ No newline at end of file diff --git a/mods/gamemodes/cult/_cult.dme b/mods/gamemodes/cult/_cult.dme new file mode 100644 index 000000000000..88b4aa4b8af3 --- /dev/null +++ b/mods/gamemodes/cult/_cult.dme @@ -0,0 +1,44 @@ +#ifndef GAMEMODE_PACK_CULT +#define GAMEMODE_PACK_CULT + +// BEGIN_INCLUDE +#include "_cult.dm" +#include "archaeology.dm" +#include "codex.dm" +#include "flooring.dm" +#include "gamemode.dm" +#include "ghosts.dm" +#include "ghosttrap.dm" +#include "hell_universe.dm" +#include "holy.dm" +#include "items.dm" +#include "materials.dm" +#include "narsie.dm" +#include "objectives.dm" +#include "overrides.dm" +#include "ritual.dm" +#include "runes.dm" +#include "special_role.dm" +#include "structures.dm" +#include "talisman.dm" +#include "abilities\_handler.dm" +#include "abilities\construct.dm" +#include "abilities\harvest.dm" +#include "abilities\shade.dm" +#include "cultify\de-cultify.dm" +#include "cultify\defile.dm" +#include "cultify\mob.dm" +#include "cultify\turf.dm" +#include "mobs\mob_subtypes.dm" +#include "mobs\shade.dm" +#include "mobs\constructs\constructs.dm" +#include "mobs\constructs\soulstone.dm" +// END_INCLUDE +#endif +// BEGIN_INTERNALS +// END_INTERNALS +// BEGIN_FILE_DIR +#define FILE_DIR . +// END_FILE_DIR +// BEGIN_PREFERENCES +// END_PREFERENCES diff --git a/mods/gamemodes/cult/abilities/_handler.dm b/mods/gamemodes/cult/abilities/_handler.dm new file mode 100644 index 000000000000..f346bb73fb41 --- /dev/null +++ b/mods/gamemodes/cult/abilities/_handler.dm @@ -0,0 +1,21 @@ +/obj/screen/ability/category/cult + name = "Toggle Construct Abilities" + icon = 'mods/gamemodes/cult/icons/abilities.dmi' + +/obj/screen/ability/button/cult + icon = 'mods/gamemodes/cult/icons/abilities.dmi' + +/datum/ability_handler/cult + category_toggle_type = /obj/screen/ability/category/cult + +/decl/ability/cult + abstract_type = /decl/ability/cult + ability_icon = 'mods/gamemodes/cult/icons/abilities.dmi' + ability_icon_state = "artificer" + associated_handler_type = /datum/ability_handler/cult + ui_element_type = /obj/screen/ability/button/cult + ability_cooldown_time = 60 SECONDS + +/obj/item/ability/cult + icon = 'mods/gamemodes/cult/icons/ability_item.dmi' + color = COLOR_RED diff --git a/mods/gamemodes/cult/abilities/construct.dm b/mods/gamemodes/cult/abilities/construct.dm new file mode 100644 index 000000000000..60138eaba356 --- /dev/null +++ b/mods/gamemodes/cult/abilities/construct.dm @@ -0,0 +1,131 @@ +//////////////////////////////Construct Spells///////////////////////// +/decl/ability/cult/construct + name = "Artificer" + desc = "This spell conjures a construct which may be controlled by shades." + target_selector = /decl/ability_targeting/clear_turf + overlay_icon = 'mods/gamemodes/cult/icons/effects.dmi' + overlay_icon_state = "sparkles" + target_selector = /decl/ability_targeting/clear_turf/construct + var/summon_type = /obj/structure/constructshell + +/decl/ability_targeting/clear_turf/construct/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability) + var/decl/ability/cult/construct/cult_ability = ability + if(!istype(cult_ability)) + return FALSE + return ..() && !istype(target, cult_ability.summon_type) && !(locate(cult_ability.summon_type) in target) + +/decl/ability/cult/construct/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile) + . = ..() + var/turf/target_turf = get_turf(hit_target) + if(istype(target_turf)) + if(ispath(summon_type, /turf)) + target_turf = target_turf.ChangeTurf(summon_type, TRUE, FALSE, TRUE, TRUE, FALSE) + if(target_turf) // We reapply effects as target no longer exists. + apply_effect_to(user, target_turf, metadata) + else if(ispath(summon_type, /atom)) + new summon_type(target_turf) + +/decl/ability/cult/construct/lesser + ability_cooldown_time = 2 MINUTES + summon_type = /obj/structure/constructshell/cult + ability_icon_state = "const_shell" + +/decl/ability/cult/construct/floor + name = "Floor Construction" + desc = "This spell constructs a cult floor" + ability_cooldown_time = 2 SECONDS + summon_type = /turf/floor/cult + ability_icon_state = "const_floor" + overlay_icon_state = "cultfloor" + +/decl/ability/cult/construct/wall + name = "Lesser Construction" + desc = "This spell constructs a cult wall" + ability_cooldown_time = 10 SECONDS + summon_type = /turf/wall/cult + ability_icon_state = "const_wall" + overlay_icon_state = "cultwall" + +/decl/ability/cult/construct/wall/reinforced + name = "Greater Construction" + desc = "This spell constructs a reinforced metal wall" + ability_cooldown_time = 30 SECONDS + summon_type = /turf/wall/r_wall + +/decl/ability/cult/construct/soulstone + name = "Summon Soulstone" + desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space." + ability_cooldown_time = 5 MINUTES + summon_type = /obj/item/soulstone + ability_icon_state = "const_stone" + +/decl/ability/cult/construct/pylon + name = "Red Pylon" + desc = "This spell conjures a fragile crystal from Nar-Sie's realm. Makes for a convenient light source." + ability_cooldown_time = 20 SECONDS + summon_type = /obj/structure/cult/pylon + ability_icon_state = "const_pylon" + target_selector = /decl/ability_targeting/pylon + is_melee_invocation = TRUE + prep_cast = TRUE + +/decl/ability_targeting/pylon/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability) + . = ..() + if(!.) + return + if(istype(target, /obj/structure/cult/pylon)) + return TRUE + if(isturf(target)) + var/turf/target_turf = target + // We can repair pylons, so let us target turfs containing broken pylons. + if(target_turf.contains_dense_objects(user)) + for(var/obj/structure/cult/pylon/pylon in target_turf) + if(pylon.isbroken) + return TRUE + return FALSE + // We can summon pylons in empty turfs. + return TRUE + return FALSE + +/decl/ability/cult/construct/pylon/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile) + for(var/obj/structure/cult/pylon/P in get_turf(hit_target)) + if(P.isbroken) + P.repair(user) + return TRUE + . = ..() + +/decl/ability/cult/construct/forcewall/lesser + name = "Force Shield" + desc = "Allows you to pull up a shield to protect yourself and allies from incoming threats" + summon_type = /obj/effect/cult_force_wall + ability_cooldown_time = 30 SECONDS + ability_use_channel = 20 SECONDS + ability_icon_state = "const_juggwall" + prepare_message_3p_str = "$USER$ begins to twist and warp space around $TARGET$, building a wall of force." + prepare_message_1p_str = "You begin the lengthy process of warping local space to form a wall of force." + cast_message_3p_str = "$USER$ completes a wall of force!" + cast_message_1p_str = "You complete a wall of force!" + fail_cast_1p_str = "The screaming fabric of spacetime escapes your grip, and the wall of force vanishes." + +//Code for the Juggernaut construct's forcefield, that seemed like a good place to put it. +/obj/effect/cult_force_wall + desc = "This eerie-looking obstacle seems to have been pulled from another dimension through sheer force." + name = "wall of force" + icon = 'mods/gamemodes/cult/icons/effects.dmi' + icon_state = "m_shield_cult" + light_color = "#b40000" + light_range = 2 + anchored = TRUE + opacity = FALSE + density = TRUE + +/obj/effect/cult_force_wall/Initialize(mapload) + . = ..() + addtimer(CALLBACK(src, PROC_REF(vanish)), 30 SECONDS) + +/obj/effect/cult_force_wall/proc/vanish() + density = FALSE + icon_state = "m_shield_cult_vanish" + sleep(12) + if(!QDELETED(src)) + qdel(src) diff --git a/mods/gamemodes/cult/abilities/harvest.dm b/mods/gamemodes/cult/abilities/harvest.dm new file mode 100644 index 000000000000..49569d6a25ef --- /dev/null +++ b/mods/gamemodes/cult/abilities/harvest.dm @@ -0,0 +1,41 @@ +/decl/ability/cult/construct/harvest + name = "Harvest" + desc = "Back to where I come from, and you're coming with me." + ability_cooldown_time = 20 SECONDS + ability_use_channel = 10 SECONDS + overlay_icon_state = "rune_teleport" + overlay_lifespan = 0 + ability_icon_state = "const_harvest" + prepare_message_3p_str = "Space around $USER$ begins to bubble and decay as a terrible vista begins to intrude..." + prepare_message_1p_str = "You bore through space and time, seeking the essence of the Geometer of Blood." + fail_cast_1p_str = "Reality reasserts itself, preventing your return to Nar-Sie." + target_selector = /decl/ability_targeting/living_mob + +/decl/ability/cult/construct/harvest/can_use_ability(mob/user, list/metadata, silent) + . = ..() + if(.) + var/destination + for(var/obj/effect/narsie/N in global.narsie_list) + destination = N.loc + break + if(!destination) + to_chat(user, SPAN_DANGER("You cannot sense the Geometer of Blood!")) + return FALSE + +/decl/ability/cult/construct/harvest/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile) + ..() + var/destination = null + for(var/obj/effect/narsie/N in global.narsie_list) + destination = N.loc + break + if(!destination) + to_chat(user, SPAN_DANGER("You cannot sense the Geometer of Blood!")) + return + if(ismob(hit_target) && hit_target != user) + var/mob/living/victim = hit_target + to_chat(user, SPAN_SINISTER("You warp back to Nar-Sie along with your prey.")) + to_chat(victim, SPAN_SINISTER("You are wrenched through time and space and thrown into chaos!")) + victim.dropInto(destination) + else + to_chat(user, SPAN_SINISTER("You warp back to Nar-Sie.")) + user.dropInto(destination) diff --git a/mods/gamemodes/cult/abilities/shade.dm b/mods/gamemodes/cult/abilities/shade.dm new file mode 100644 index 000000000000..5fab626d14d6 --- /dev/null +++ b/mods/gamemodes/cult/abilities/shade.dm @@ -0,0 +1 @@ +/decl/ability/cult/construct/shift \ No newline at end of file diff --git a/mods/gamemodes/cult/archaeology.dm b/mods/gamemodes/cult/archaeology.dm new file mode 100644 index 000000000000..1d81b9117c1e --- /dev/null +++ b/mods/gamemodes/cult/archaeology.dm @@ -0,0 +1,40 @@ +/decl/archaeological_find/cult + item_type = "garments" + responsive_reagent = /decl/material/solid/potassium + possible_types = list( + /obj/item/clothing/head/culthood, + /obj/item/clothing/head/culthood/magus, + /obj/item/clothing/head/culthood/alt, + /obj/item/clothing/head/helmet/space/cult + ) + modification_flags = XENOFIND_APPLY_PREFIX | XENOFIND_APPLY_DECOR + +/decl/archaeological_find/cult/sword + item_type = "blade" + modification_flags = 0 + possible_types = list(/obj/item/sword/cultblade) + engraving_chance = 10 + +//Override adding soulstone +/decl/archaeological_find/crystal + possible_types = list( + /obj/item = 4, + /obj/item/soulstone + ) + +/decl/xenoarch_digsite/temple/Initialize() + find_types[/decl/archaeological_find/cult] = 200 + find_types[/decl/archaeological_find/cult/sword] = 75 + return ..() + +/decl/xenoarch_digsite/war/Initialize() + find_types[/decl/archaeological_find/cult] = 50 + find_types[/decl/archaeological_find/cult/sword] = 50 + return ..() + +/datum/artifact_trigger/energy/New() + var/static/injected = FALSE + if(!injected) + energetic_things += /obj/item/sword/cultblade + injected = TRUE + ..() \ No newline at end of file diff --git a/mods/gamemodes/cult/codex.dm b/mods/gamemodes/cult/codex.dm new file mode 100644 index 000000000000..f2fe2a16ae2c --- /dev/null +++ b/mods/gamemodes/cult/codex.dm @@ -0,0 +1,3 @@ +/datum/codex_entry/cultblade + associated_paths = list(/obj/item/sword/cultblade) + antag_text = "This sword is a powerful weapon, capable of severing limbs easily, if they are targeted. Nonbelievers are unable to use this weapon." \ No newline at end of file diff --git a/mods/gamemodes/cult/cultify/de-cultify.dm b/mods/gamemodes/cult/cultify/de-cultify.dm new file mode 100644 index 000000000000..32c0738df02f --- /dev/null +++ b/mods/gamemodes/cult/cultify/de-cultify.dm @@ -0,0 +1,7 @@ +/turf/unsimulated/wall/cult/nullrod_act(mob/user, obj/item/nullrod/rod) + user.visible_message( + SPAN_NOTICE("\The [user] touches \the [src] with \the [rod], and it shifts."), + SPAN_NOTICE("You touch \the [src] with \the [rod], and it shifts.") + ) + ChangeTurf(/turf/unsimulated/wall) + return TRUE \ No newline at end of file diff --git a/mods/gamemodes/cult/cultify/defile.dm b/mods/gamemodes/cult/cultify/defile.dm new file mode 100644 index 000000000000..684a22c481b7 --- /dev/null +++ b/mods/gamemodes/cult/cultify/defile.dm @@ -0,0 +1,2 @@ +/atom/proc/on_defilement() + return \ No newline at end of file diff --git a/mods/gamemodes/cult/cultify/mob.dm b/mods/gamemodes/cult/cultify/mob.dm new file mode 100644 index 000000000000..8c95baa107cb --- /dev/null +++ b/mods/gamemodes/cult/cultify/mob.dm @@ -0,0 +1,26 @@ +/mob/on_defilement() + return + +/mob/observer/ghost/on_defilement() + if(icon_state != "ghost-narsie") + icon = 'icons/mob/mob.dmi' + icon_state = "ghost-narsie" + cut_overlays() + set_invisibility(INVISIBILITY_NONE) + to_chat(src, SPAN_SINISTER("Even as a non-corporal being, you can feel Nar-Sie's presence altering you. You are now visible to everyone.")) + +/mob/living/on_defilement() + if(iscultist(src) && client) + var/mob/living/simple_animal/construct/harvester/C = new(get_turf(src)) + mind.transfer_to(C) + to_chat(C, "The Geometer of Blood is overjoyed to be reunited with its followers, and accepts your body in sacrifice. As reward, you have been gifted with the shell of an Harvester.
    Your tendrils can use and draw runes without need for a tome, your eyes can see beings through walls, and your mind can open any door. Use these assets to serve Nar-Sie and bring him any remaining living human in the world.
    You can teleport yourself back to Nar-Sie along with any being under yourself at any time using your \"Harvest\" spell.
    ") + dust() + else if(client) + var/mob/observer/ghost/G = (ghostize()) + G.icon = 'icons/mob/mob.dmi' + G.icon_state = "ghost-narsie" + G.overlays.Cut() + G.set_invisibility(INVISIBILITY_NONE) + to_chat(G, "You feel relieved as what's left of your soul finally escapes its prison of flesh.") + else + dust() diff --git a/mods/gamemodes/cult/cultify/turf.dm b/mods/gamemodes/cult/cultify/turf.dm new file mode 100644 index 000000000000..428ec614a65e --- /dev/null +++ b/mods/gamemodes/cult/cultify/turf.dm @@ -0,0 +1,65 @@ +/turf/on_defilement() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.add_cultiness(CULTINESS_PER_TURF) + +/turf/proc/is_defiled() + return (locate(/obj/effect/narsie_footstep) in src) + +/turf/floor/on_defilement() + if(!has_flooring() || get_topmost_flooring()?.type != /decl/flooring/reinforced/cult) + ..() + set_flooring(GET_DECL(/decl/flooring/reinforced/cult)) + +/turf/floor/is_defiled() + var/decl/flooring/flooring = get_topmost_flooring() + if(flooring) + return flooring.type == /decl/flooring/reinforced/cult + return ..() + +/turf/floor/cult + name = "engraved floor" + icon = 'icons/turf/flooring/cult.dmi' + icon_state = "cult" + _flooring = /decl/flooring/reinforced/cult + +/turf/wall/on_defilement() + var/new_material + if(material?.type != /decl/material/solid/stone/cult) + new_material = /decl/material/solid/stone/cult + var/new_rmaterial + if(reinf_material && reinf_material.type != /decl/material/solid/stone/cult/reinforced) + new_rmaterial = /decl/material/solid/stone/cult/reinforced + if(new_material || new_rmaterial) + ..() + set_turf_materials(new_material, new_rmaterial) + +/turf/wall/is_defiled() + return material?.type == /decl/material/solid/stone/cult || reinf_material?.type == /decl/material/solid/stone/cult/reinforced || ..() + +//Cult wall +/turf/wall/cult + icon_state = "cult" + color = COLOR_RED_GRAY + material = /decl/material/solid/stone/cult + +/turf/wall/cult/reinf + icon_state = "reinforced_cult" + reinf_material = /decl/material/solid/stone/cult/reinforced + +/turf/wall/cult/dismantle_turf(devastated, explode, no_product, keep_air = TRUE) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.remove_cultiness(CULTINESS_PER_TURF) + . = ..() + +/turf/wall/cult/can_join_with(var/turf/wall/wall) + if(material && wall.material && material.icon_base == wall.material.icon_base) + return FALSE + else if(istype(wall, /turf/wall)) + return TRUE + return FALSE + +/turf/wall/natural/on_defilement() + ChangeTurf(/turf/wall/cult) + +/turf/unsimulated/on_defilement() + return \ No newline at end of file diff --git a/mods/gamemodes/cult/flooring.dm b/mods/gamemodes/cult/flooring.dm new file mode 100644 index 000000000000..17952ec6373f --- /dev/null +++ b/mods/gamemodes/cult/flooring.dm @@ -0,0 +1,13 @@ +/decl/flooring/reinforced/cult + name = "engraved floor" + desc = "Unsettling whispers waver from the surface..." + icon = 'icons/turf/flooring/cult.dmi' + icon_base = "cult" + build_type = null + turf_flags = TURF_ACID_IMMUNE | TURF_REMOVE_WRENCH + can_paint = FALSE + uid = "floor_cult" + +/decl/flooring/reinforced/cult/on_flooring_remove(turf/removing_from) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.remove_cultiness(CULTINESS_PER_TURF) diff --git a/mods/gamemodes/cult/gamemode.dm b/mods/gamemodes/cult/gamemode.dm new file mode 100644 index 000000000000..020024446040 --- /dev/null +++ b/mods/gamemodes/cult/gamemode.dm @@ -0,0 +1,10 @@ +/decl/game_mode/cult + name = "Cult" + round_description = "Some crewmembers are attempting to start a cult!" + extended_round_description = "There has been an infiltration by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!" + uid = "cult" + required_players = 10 + required_enemies = 3 + end_on_antag_death = FALSE + associated_antags = list(/decl/special_role/cultist) + probability = 1 diff --git a/mods/gamemodes/cult/ghosts.dm b/mods/gamemodes/cult/ghosts.dm new file mode 100644 index 000000000000..2958d3931377 --- /dev/null +++ b/mods/gamemodes/cult/ghosts.dm @@ -0,0 +1,328 @@ +/mob/observer/ghost/var/ghost_magic_cd = 0 + +/decl/special_role/cultist/proc/add_ghost_magic(var/mob/observer/ghost/M) + if(max_cult_rating >= CULT_GHOSTS_1) + M.verbs += /mob/observer/ghost/proc/flick_lights + M.verbs += /mob/observer/ghost/proc/bloody_doodle + M.verbs += /mob/observer/ghost/proc/shatter_glass + M.verbs += /mob/observer/ghost/proc/slice + if(max_cult_rating >= CULT_GHOSTS_2) + M.verbs += /mob/observer/ghost/proc/move_item + M.verbs += /mob/observer/ghost/proc/whisper_to_cultist + M.verbs += /mob/observer/ghost/proc/bite_someone + M.verbs += /mob/observer/ghost/proc/chill_someone + if(max_cult_rating >= CULT_GHOSTS_3) + M.verbs += /mob/observer/ghost/proc/whisper_to_anyone + M.verbs += /mob/observer/ghost/proc/bloodless_doodle + M.verbs += /mob/observer/ghost/proc/toggle_visiblity + +/proc/round_is_spooky(var/spookiness_threshold = get_config_value(/decl/config/num/cult_ghostwriter_req_cultists)) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + return (cult.current_antagonists.len > spookiness_threshold) + +// ghost attack - make lights flicker like an AI, but even spookier! +/obj/machinery/light/attack_ghost(mob/user) + if(round_is_spooky()) + src.flicker(rand(2,5)) + else return ..() + +/obj/item/t_scanner/can_scan_mob(mob/victim) + if(round_is_spooky() && isobserver(victim)) + return TRUE + return ..() + +/mob/living/do_possession(var/mob/observer/ghost/possessor) + if(round_is_spooky(6)) // Six or more active cultists. + to_chat(src, SPAN_NOTICE("You reach out with tendrils of ectoplasm and invade the mind of \the [src]...")) + to_chat(src, SPAN_BOLD("You have assumed direct control of \the [src].")) + to_chat(src, SPAN_NOTICE("Due to the spookiness of the round, you have taken control of the poor animal as an invading, possessing spirit - roleplay accordingly.")) + src.universal_speak = TRUE + src.universal_understand = TRUE + //src.on_defilement() // Maybe another time. + return TRUE + +/mob/observer/ghost/Initialize() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.add_ghost_magic(src) + return ..() + +/mob/observer/ghost/proc/ghost_ability_check() + var/turf/T = get_turf(src) + if(is_holy_turf(T)) + to_chat(src, "You may not use your abilities on the blessed ground.") + return 0 + if(ghost_magic_cd > world.time) + to_chat(src, "You need [round((ghost_magic_cd - world.time) / 10)] more seconds before you can use your abilities.") + return 0 + return 1 + +/mob/observer/ghost/proc/flick_lights() + set category = "Cult" + set name = "Flick lights" + set desc = "Flick some lights around you." + + if(!ghost_ability_check()) + return + + for(var/obj/machinery/light/L in range(3)) + L.flicker() + + ghost_magic_cd = world.time + 30 SECONDS + +/mob/observer/ghost/proc/bloody_doodle() + set category = "Cult" + set name = "Write in blood" + set desc = "Write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC." + + bloody_doodle_proc(0) + +/mob/observer/ghost/proc/bloody_doodle_proc(var/bloodless = 0) + if(!ghost_ability_check()) + return + + var/doodle_color = COLOR_BLOOD_HUMAN + + var/turf/T = get_turf(src) + if(!T?.simulated) + to_chat(src, "You cannot doodle there.") + return + + var/num_doodles = 0 + for(var/obj/effect/decal/cleanable/blood/writing/writing in T) + num_doodles++ + if(num_doodles > 4) + to_chat(src, "There is no space to write on!") + return + + var/obj/effect/decal/cleanable/blood/choice + if(!bloodless) + var/list/choices = list() + for(var/obj/effect/decal/cleanable/blood/B in range(1)) + if(B.amount > 0) + choices += B + + if(!choices.len) + to_chat(src, "There is no blood to use nearby.") + return + + choice = input(src, "What blood would you like to use?") as null|anything in choices + if(!choice) + return + + if(choice.basecolor) + doodle_color = choice.basecolor + + var/max_length = 50 + + var/message = sanitize(input("Write a message. It cannot be longer than [max_length] characters.", "Blood writing", "")) + + if(!ghost_ability_check()) + return + + if(message && (bloodless || (choice && (choice in range(1))))) + if(length(message) > max_length) + message += "-" + to_chat(src, "You ran out of blood to write with!") + + var/obj/effect/decal/cleanable/blood/writing/writing = new(T) + writing.basecolor = doodle_color + writing.update_icon() + writing.message = message + writing.add_hiddenprint(src) + if(!bloodless) + writing.visible_message("Invisible fingers crudely paint something in blood on \the [T].") + else + writing.visible_message("Blood appears out of nowhere as invisible fingers crudely paint something on \the [T].") + + log_admin("[src] ([src.key]) used ghost magic to write '[message]' - [x]-[y]-[z]") + + ghost_magic_cd = world.time + 30 SECONDS + +/mob/observer/ghost/proc/shatter_glass() + set category = "Cult" + set name = "Noise: glass shatter" + set desc = "Make a sound of glass being shattered." + + if(!ghost_ability_check()) + return + + playsound(loc, "shatter", 50, 1) + + ghost_magic_cd = world.time + 5 SECONDS + +/mob/observer/ghost/proc/slice() + set category = "Cult" + set name = "Noise: slice" + set desc = "Make a sound of a sword hit." + + if(!ghost_ability_check()) + return + + playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1) + + ghost_magic_cd = world.time + 5 SECONDS + +/mob/observer/ghost/proc/move_item() + set category = "Cult" + set name = "Move item" + set desc = "Move a small item to where you are." + + if(!ghost_ability_check()) + return + + var/turf/T = get_turf(src) + + var/list/obj/item/choices = list() + for(var/obj/item/I in range(1)) + if(I.w_class <= ITEM_SIZE_SMALL) + choices += I + + if(!choices.len) + to_chat(src, "There are no suitable items nearby.") + return + + var/obj/item/choice = input(src, "What item would you like to pull?") as null|anything in choices + if(!choice || !(choice in range(1)) || choice.w_class > ITEM_SIZE_SMALL) + return + + if(!ghost_ability_check()) + return + + if(step_to(choice, T)) + choice.visible_message("\The [choice] suddenly moves!") + + ghost_magic_cd = world.time + 60 SECONDS + +/mob/observer/ghost/proc/whisper_to_cultist() + set category = "Cult" + set name = "Whisper to cultist" + set desc = "Whisper to a human of your choice. They won't understand you unless they're a cultist though." + + whisper_proc() + +/mob/observer/ghost/proc/whisper_proc(var/anyone = 0) + if(!ghost_ability_check()) + return + + var/list/mob/living/choices = list() + for(var/mob/living/M in range(1)) + choices += M + + var/mob/living/choice = input(src, "Whom do you want to whisper to?") as null|anything in choices + if(!choice) + return + + var/message = sanitize(input("Decide what you want to whisper.", "Whisper", "")) + + if(!ghost_ability_check()) + return + + if(message) + if(iscultist(choice) || anyone) + to_chat(choice, "You hear a faint whisper... It says... \"[message]\"") + log_and_message_admins("used ghost magic to say '[message]' to \the [choice] and was heard - [x]-[y]-[z]") + else + to_chat(choice, "You hear a faint whisper, but you can't make out the words.") + log_and_message_admins("used ghost magic to say '[message]' to \the [choice] but wasn't heard - [x]-[y]-[z]") + to_chat(src, "You whisper to \the [choice]. Perhaps they heard you.") + + ghost_magic_cd = world.time + 100 SECONDS + +/mob/observer/ghost/proc/bite_someone() + set category = "Cult" + set name = "Bite" + set desc = "Bite or scratch someone." + + if(!ghost_ability_check()) + return + + var/list/mob/living/human/choices = list() + for(var/mob/living/human/H in range(1)) + choices += H + + var/mob/living/human/choice = input(src, "Whom do you want to scratch?") as null|anything in choices + if(!choice) + return + + if(!ghost_ability_check()) + return + + var/method = pick("bit", "scratched") + to_chat(choice, "Something invisible [method] you!") + choice.apply_effect(5, PAIN, 0) + to_chat(src, "You [method] \the [choice].") + + log_and_message_admins("used ghost magic to bite \the [choice] - [x]-[y]-[z]") + + ghost_magic_cd = world.time + 60 SECONDS + +/mob/observer/ghost/proc/chill_someone() + set category = "Cult" + set name = "Chill" + set desc = "Pass through someone, making them feel the chill of afterlife for a moment." + + if(!ghost_ability_check()) + return + + var/list/mob/living/human/choices = list() + for(var/mob/living/human/H in range(1)) + choices += H + + var/mob/living/human/choice = input(src, "Whom do you want to scare?") as null|anything in choices + if(!choice) + return + + if(!ghost_ability_check()) + return + + to_chat(choice, "You feel as if something cold passed through you!") + var/temp_threshold = choice.get_mob_temperature_threshold(COLD_LEVEL_1) + if(choice.bodytemperature >= temp_threshold + 1) + choice.bodytemperature = max(temp_threshold + 1, choice.bodytemperature - 30) + to_chat(src, "You pass through \the [choice], giving them a sudden chill.") + + log_and_message_admins("used ghost magic to chill \the [choice] - [x]-[y]-[z]") + + ghost_magic_cd = world.time + 60 SECONDS + +/mob/observer/ghost/proc/whisper_to_anyone() + set category = "Cult" + set name = "Whisper to mind" + set desc = "Whisper to a human of your choice." + + whisper_proc(1) + +/mob/observer/ghost/proc/bloodless_doodle() + set category = "Cult" + set name = "Write in own blood" + set desc = "Write a short message in blood on the floor or a wall. You don't need blood nearby to use this." + + bloody_doodle_proc(1) + +/mob/observer/ghost/proc/toggle_visiblity() + set category = "Cult" + set name = "Toggle Visibility" + set desc = "Allows you to become visible or invisible at will." + + if(invisibility && !ghost_ability_check()) + return + + if(invisibility == 0) + ghost_magic_cd = world.time + 60 SECONDS + to_chat(src, "You are now invisible.") + visible_message("It fades from sight...") + set_invisibility(INVISIBILITY_OBSERVER) + mouse_opacity = MOUSE_OPACITY_NORMAL + else + ghost_magic_cd = world.time + 60 SECONDS + to_chat(src, "You are now visible.") + set_invisibility(INVISIBILITY_NONE) + mouse_opacity = MOUSE_OPACITY_UNCLICKABLE // This is so they don't make people invincible to melee attacks by hovering over them + +//ATTACK GHOST IGNORING PARENT RETURN VALUE +// If we're spooky, ghosts can use the spirit board +/obj/item/spirit_board/attack_ghost(var/mob/observer/ghost/user) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + if(cult.max_cult_rating >= CULT_GHOSTS_2) + spirit_board_pick_letter(user) + return ..() \ No newline at end of file diff --git a/mods/gamemodes/cult/ghosttrap.dm b/mods/gamemodes/cult/ghosttrap.dm new file mode 100644 index 000000000000..07faf87515f2 --- /dev/null +++ b/mods/gamemodes/cult/ghosttrap.dm @@ -0,0 +1,22 @@ +/decl/ghosttrap/cult_shade + name = "shade" + ghost_trap_message = "They are occupying a soul stone now." + ban_checks = list(/decl/special_role/cultist) + pref_check = "ghost_shade" + can_set_own_name = FALSE + +/decl/ghosttrap/cult_shade/welcome_candidate(var/mob/target) + var/obj/item/soulstone/S = target.loc + if(istype(S)) + if(S.is_evil) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + cult.add_antagonist(target.mind) + to_chat(target, "Remember, you serve the one who summoned you first, and the cult second.") + else + to_chat(target, "This soultone has been purified. You do not belong to the cult.") + to_chat(target, "Remember, you only serve the one who summoned you.") + +/decl/ghosttrap/cult_shade/forced(var/mob/user) + var/obj/item/soulstone/stone = new(get_turf(user)) + stone.shade = new(stone) + request_player(stone.shade, "The soul stone shade summon ritual has been performed. ") diff --git a/code/game/gamemodes/cult/hell_universe.dm b/mods/gamemodes/cult/hell_universe.dm similarity index 92% rename from code/game/gamemodes/cult/hell_universe.dm rename to mods/gamemodes/cult/hell_universe.dm index 9eef30361881..5133b72ba09a 100644 --- a/code/game/gamemodes/cult/hell_universe.dm +++ b/mods/gamemodes/cult/hell_universe.dm @@ -32,8 +32,8 @@ In short: SSskybox.change_skybox("narsie", new_use_stars = FALSE, new_use_overmap_details = FALSE) /datum/universal_state/hell/proc/MiscSet() - for(var/turf/simulated/floor/T) - if(!T.holy && prob(1)) + for(var/turf/T) + if(T.is_floor() && T.simulated && !is_holy_turf(T) && prob(1)) new /obj/effect/gateway/active/cult(T) /datum/universal_state/hell/proc/KillMobs() diff --git a/mods/gamemodes/cult/holy.dm b/mods/gamemodes/cult/holy.dm new file mode 100644 index 000000000000..fce20c925af3 --- /dev/null +++ b/mods/gamemodes/cult/holy.dm @@ -0,0 +1,34 @@ +/decl/material/liquid/water/affect_holy(mob/living/M, removed, datum/reagents/holder) + if(iscultist(M)) + if(prob(10)) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.offer_uncult(M) + if(prob(2)) + var/obj/effect/spider/spiderling/S = new /obj/effect/spider/spiderling(M.loc) + M.visible_message(SPAN_WARNING("\The [M] coughs up \the [S]!")) + return TRUE + return FALSE + +/obj/item/nullrod/holy_act(mob/living/target, mob/living/user) + if(iscultist(target)) + target.visible_message(SPAN_NOTICE("\The [user] waves \the [src] over \the [target]'s head.")) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.offer_uncult(target) + return TRUE + return ..() + +/turf/wall/cult/nullrod_act(mob/user, obj/item/nullrod/rod) + user.visible_message( + SPAN_NOTICE("\The [user] touches \the [src] with \the [rod], and the enchantment affecting it fizzles away."), + SPAN_NOTICE("You touch \the [src] with \the [rod], and the enchantment affecting it fizzles away.") + ) + ChangeTurf(/turf/wall) + return TRUE + +/turf/floor/cult/nullrod_act(mob/user, obj/item/nullrod/rod) + user.visible_message( + SPAN_NOTICE("\The [user] touches \the [src] with \the [rod], and the enchantment affecting it fizzles away."), + SPAN_NOTICE("You touch \the [src] with \the [rod], and the enchantment affecting it fizzles away.") + ) + ChangeTurf(/turf/floor, keep_air = TRUE) + return TRUE \ No newline at end of file diff --git a/mods/gamemodes/cult/icons/abilities.dmi b/mods/gamemodes/cult/icons/abilities.dmi new file mode 100644 index 000000000000..f1d5d8bc121c Binary files /dev/null and b/mods/gamemodes/cult/icons/abilities.dmi differ diff --git a/mods/gamemodes/cult/icons/ability_item.dmi b/mods/gamemodes/cult/icons/ability_item.dmi new file mode 100644 index 000000000000..e22793f4f6bd Binary files /dev/null and b/mods/gamemodes/cult/icons/ability_item.dmi differ diff --git a/mods/gamemodes/cult/icons/effects.dmi b/mods/gamemodes/cult/icons/effects.dmi new file mode 100644 index 000000000000..9e2389414543 Binary files /dev/null and b/mods/gamemodes/cult/icons/effects.dmi differ diff --git a/mods/gamemodes/cult/icons/forcewall.dmi b/mods/gamemodes/cult/icons/forcewall.dmi new file mode 100644 index 000000000000..04b8560cdac3 Binary files /dev/null and b/mods/gamemodes/cult/icons/forcewall.dmi differ diff --git a/icons/effects/uristrunes.dmi b/mods/gamemodes/cult/icons/runes.dmi similarity index 100% rename from icons/effects/uristrunes.dmi rename to mods/gamemodes/cult/icons/runes.dmi diff --git a/mods/gamemodes/cult/items.dm b/mods/gamemodes/cult/items.dm new file mode 100644 index 000000000000..284cbb4481ff --- /dev/null +++ b/mods/gamemodes/cult/items.dm @@ -0,0 +1,147 @@ +/obj/item/sword/cultblade + name = "cult blade" + desc = "An arcane weapon wielded by the followers of Nar-Sie." + icon = 'icons/obj/items/weapon/swords/cult.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + +// separated into a proc so that modpacks can modify it +/obj/item/sword/cultblade/proc/can_use_safely(mob/living/user) + return iscultist(user) + +/obj/item/sword/cultblade/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(can_use_safely(user)) + return ..() + + var/zone = user.get_active_held_item_slot() + + var/obj/item/organ/external/affecting = null + if(ishuman(user)) + var/mob/living/human/H = user + affecting = GET_EXTERNAL_ORGAN(H, zone) + + if(affecting) + to_chat(user, SPAN_DANGER("An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!")) + else + to_chat(user, SPAN_DANGER("An unexplicable force rips through you, tearing the sword from your grasp!")) + + //random amount of damage between half of the blade's force and the full force of the blade. + var/force = expend_attack_force(user) + user.apply_damage(rand(force/2, force), BRUTE, zone, (DAM_SHARP|DAM_EDGE), armor_pen = 100) + SET_STATUS_MAX(user, STAT_WEAK, 5) + + if(user.try_unequip(src)) + throw_at(get_edge_target_turf(src, pick(global.alldirs)), rand(1,3), throw_speed) + + var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg') + playsound(loc, spooky, 50, 1) + + return TRUE + +/obj/item/sword/cultblade/on_picked_up(mob/living/user, atom/old_loc) + if(!iscultist(user)) + to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the cultist's sword. It would be wise to be rid of this blade quickly.") + SET_STATUS_MAX(user, STAT_DIZZY, 120) + +/obj/item/clothing/head/culthood + name = "cult hood" + desc = "A hood worn by the followers of Nar-Sie." + icon = 'icons/clothing/head/cult.dmi' + flags_inv = HIDEFACE | BLOCK_HEAD_HAIR + body_parts_covered = SLOT_HEAD + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_SMALL + ) + cold_protection = SLOT_HEAD + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + siemens_coefficient = 0.8 //That's a pretty cool opening in the hood. Also: Cloth making physical contact to the skull. + +/obj/item/clothing/head/culthood/magus + name = "magus helm" + desc = "A helm worn by the followers of Nar-Sie." + icon = 'icons/clothing/head/wizard/magus.dmi' + flags_inv = HIDEFACE | BLOCK_ALL_HAIR + body_parts_covered = SLOT_HEAD|SLOT_FACE|SLOT_EYES + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT + ) + +/obj/item/clothing/head/culthood/alt + icon = 'icons/clothing/head/cult_alt.dmi' + +/obj/item/clothing/suit/cultrobes + name = "cult robes" + icon = 'icons/clothing/suits/cult.dmi' + desc = "A set of durable robes worn by the followers of Nar-Sie." + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_ARMS|SLOT_TAIL + allowed = list(/obj/item/book/tome,/obj/item/sword/cultblade) + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_SMALL, + ARMOR_ENERGY = ARMOR_ENERGY_SMALL, + ARMOR_BOMB = ARMOR_BOMB_PADDED + ) + flags_inv = HIDEJUMPSUIT + siemens_coefficient = 0.6 + +/obj/item/clothing/suit/cultrobes/alt + icon = 'icons/clothing/suits/cult_alt.dmi' + +/obj/item/clothing/suit/cultrobes/magusred + name = "magus robes" + desc = "A set of plated robes worn by the followers of Nar-Sie." + icon = 'icons/clothing/suits/wizard/magusred.dmi' + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS|SLOT_TAIL + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + armor = list( + ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_PADDED + ) + +/obj/item/clothing/suit/cultrobes/magusred/Initialize() + . = ..() + LAZYSET(slowdown_per_slot, slot_wear_suit_str, 1) + +/obj/item/clothing/head/helmet/space/cult + name = "cult helmet" + desc = "A space worthy helmet used by the followers of Nar-Sie." + icon = 'icons/clothing/spacesuit/cult/helmet.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_MINOR + ) //Real tanky shit. + siemens_coefficient = 0.3 //Bone is not very conducive to electricity. + +/obj/item/clothing/suit/space/cult + name = "cult armour" + desc = "A bulky suit of armour, bristling with spikes. It looks space proof." + icon = 'icons/clothing/spacesuit/cult/suit.dmi' + allowed = list(/obj/item/book/tome,/obj/item/sword/cultblade,/obj/item/tank,/obj/item/suit_cooling_unit) + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + siemens_coefficient = 0.2 + body_parts_covered = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_ARMS|SLOT_HANDS|SLOT_TAIL + +/obj/item/clothing/suit/space/cult/Initialize() + . = ..() + LAZYSET(slowdown_per_slot, slot_wear_suit_str, 1) \ No newline at end of file diff --git a/mods/gamemodes/cult/materials.dm b/mods/gamemodes/cult/materials.dm new file mode 100644 index 000000000000..a606e344ad5c --- /dev/null +++ b/mods/gamemodes/cult/materials.dm @@ -0,0 +1,33 @@ +/decl/material/solid/stone/cult + name = "disturbing stone" + uid = "solid_stone_cult" + icon_base = 'icons/turf/walls/cult.dmi' + icon_reinf = 'icons/turf/walls/reinforced_cult.dmi' + color = "#402821" + shard_name = SHARD_STONE_PIECE + conductive = 0 + construction_difficulty = MAT_VALUE_NORMAL_DIY + hidden_from_codex = TRUE + reflectiveness = MAT_VALUE_DULL + exoplanet_rarity_plant = MAT_RARITY_NOWHERE + exoplanet_rarity_gas = MAT_RARITY_NOWHERE + +/decl/material/solid/stone/cult/place_dismantled_girder(var/turf/target, var/decl/material/r_mat) + return list(new /obj/structure/girder/cult(target)) + +/decl/material/solid/stone/cult/reinforced + name = "runic inscriptions" + uid = "solid_runes_cult" + +/decl/butchery_data/occult + meat_material = /decl/material/solid/stone/cult + meat_type = /obj/item/stack/material/lump + bone_material = /decl/material/solid/stone/cult/reinforced + + skin_material = null + skin_type = null + skin_amount = null + + gut_amount = null + gut_material = null + gut_type = null diff --git a/mods/gamemodes/cult/mobs/constructs/constructs.dm b/mods/gamemodes/cult/mobs/constructs/constructs.dm new file mode 100644 index 000000000000..ad1932964381 --- /dev/null +++ b/mods/gamemodes/cult/mobs/constructs/constructs.dm @@ -0,0 +1,278 @@ +/mob/living/simple_animal/construct + name = "Construct" + real_name = "Construct" + desc = "" + speak_emote = list("hisses") + base_animal_type = /mob/living/simple_animal/construct + base_movement_delay = -1 + response_help_1p = "You think better of touching $TARGET$." + response_help_3p = "$USER$ thinks better of touching $TARGET$." + response_disarm = "flails at" + response_harm = "punches" + icon = 'icons/mob/simple_animal/shade.dmi' + status_flags = CANPUSH + universal_speak = FALSE + universal_understand = TRUE + min_gas = null + max_gas = null + minbodytemp = 0 + show_stat_health = 1 + faction = "cult" + supernatural = 1 + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_NOLIGHTING + mob_swap_flags = HUMAN|SIMPLE_ANIMAL|SLIME|MONKEY + mob_push_flags = ALLMOBS + bleed_colour = "#331111" + gene_damage = -1 + butchery_data = /decl/butchery_data/occult + hud_used = /datum/hud/animal/construct + z_flags = ZMM_MANGLE_PLANES + glowing_eyes = TRUE + ai = /datum/mob_controller/aggressive/construct + var/list/construct_spells + +/datum/mob_controller/aggressive/construct + emote_speech = list("Hsssssssszsht.", "Hsssssssss...", "Tcshsssssssszht!") + emote_hear = list("wails","screeches") + do_wander = FALSE + +/mob/living/simple_animal/construct/check_has_mouth() + return FALSE + +/mob/living/simple_animal/construct/on_defilement() + return + +/mob/living/simple_animal/construct/get_blood_name() + return "ichor" + +/mob/living/simple_animal/construct/Initialize() + . = ..() + name = text("[initial(name)] ([random_id(/mob/living/simple_animal/construct, 1000, 9999)])") + real_name = name + add_language(/decl/language/cultcommon) + add_language(/decl/language/cult) + for(var/spell in construct_spells) + add_ability(spell) + set_light(1.5, -2, COLOR_WHITE) + update_icon() + +/mob/living/simple_animal/construct/get_death_message(gibbed) + return "collapses in a shattered heap." + +/mob/living/simple_animal/construct/get_self_death_message(gibbed) + return "The bonds tying you to this mortal plane have been severed." + +/mob/living/simple_animal/construct/death(gibbed) + . = ..() + if(. && !gibbed) + new /obj/item/ectoplasm(src.loc) + qdel(src) + +/mob/living/simple_animal/construct/attack_animal(var/mob/user) + if(istype(user, /mob/living/simple_animal/construct/builder)) + if(current_health < get_max_health()) + heal_damage(BRUTE, 5) + user.visible_message("\The [user] mends some of \the [src]'s wounds.") + else + to_chat(user, "\The [src] is undamaged.") + return + return ..() + +/mob/living/simple_animal/construct/get_other_examine_strings(mob/user, distance, infix, suffix, hideflags, decl/pronouns/pronouns) + . = ..(user) + var/current_max_health = get_max_health() + if(current_health < current_max_health) + if(current_health >= current_max_health/2) + . += SPAN_WARNING("It looks slightly dented.") + else + . += SPAN_DANGER("It looks severely dented!") + +/////////////////Juggernaut/////////////// + + + +/mob/living/simple_animal/construct/armoured + name = "Juggernaut" + real_name = "Juggernaut" + desc = "A possessed suit of armour driven by the will of the restless dead" + icon = 'icons/mob/simple_animal/construct_behemoth.dmi' + max_health = 250 + speak_emote = list("rumbles") + response_harm = "harmlessly punches" + harm_intent_damage = 0 + natural_weapon = /obj/item/natural_weapon/juggernaut + mob_size = MOB_SIZE_LARGE + environment_smash = 2 + status_flags = 0 + resistance = 10 + construct_spells = list( + /decl/ability/cult/construct/forcewall/lesser + ) + hud_used = /datum/hud/animal/construct/juggernaut + base_movement_delay = 2 + ai = /datum/mob_controller/aggressive/construct_armoured + +/datum/mob_controller/aggressive/construct_armoured + can_escape_buckles = TRUE + +/obj/item/natural_weapon/juggernaut + name = "armored gauntlet" + gender = NEUTER + attack_verb = list("smashed", "demolished") + hitsound = 'sound/weapons/heavysmash.ogg' + _base_attack_force = 30 + +/mob/living/simple_animal/construct/armoured/handle_regular_status_updates() + set_status_condition(STAT_WEAK, 0) + if ((. = ..())) + return + +/mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) + if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) + var/damage = P.get_projectile_damage(src) + var/reflectchance = 80 - round(damage/3) + if(prob(reflectchance)) + take_damage(damage * 0.5) + visible_message("The [P.name] gets reflected by [src]'s shell!", \ + "The [P.name] gets reflected by [src]'s shell!") + + // Find a turf near or on the original location to bounce to + if(P.starting) + var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + var/turf/curloc = get_turf(src) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, src) + + return -1 // complete projectile permutation + + return (..(P)) + +/mob/living/simple_animal/construct/armoured/mind_initialize() + ..() + mind.assigned_role = "Juggernaut" + mind.assigned_special_role = "Cultist" + +////////////////////////Wraith///////////////////////////////////////////// +/mob/living/simple_animal/construct/wraith + name = "Wraith" + real_name = "Wraith" + desc = "A wicked bladed shell contraption piloted by a bound spirit" + icon = 'icons/mob/simple_animal/construct_floating.dmi' + max_health = 75 + natural_weapon = /obj/item/natural_weapon/wraith + environment_smash = 1 + see_in_dark = 7 + construct_spells = list( + /decl/ability/cult/construct/shift + ) + hud_used = /datum/hud/animal/construct/wraith + +/obj/item/natural_weapon/wraith + name = "wicked blade" + gender = NEUTER + attack_verb = list("slashed", "tore into") + hitsound = 'sound/weapons/rapidslice.ogg' + edge = TRUE + _base_attack_force = 25 + +/mob/living/simple_animal/construct/wraith/mind_initialize() + ..() + mind.assigned_role = "Wraith" + mind.assigned_special_role = "Cultist" + +/////////////////////////////Artificer///////////////////////// + + + +/mob/living/simple_animal/construct/builder + name = "Artificer" + real_name = "Artificer" + desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" + icon = 'icons/mob/simple_animal/construct_artificer.dmi' + max_health = 50 + response_harm = "viciously beaten" + harm_intent_damage = 5 + natural_weapon = /obj/item/natural_weapon/cult_builder + environment_smash = 1 + construct_spells = list( + /decl/ability/cult/construct/lesser, + /decl/ability/cult/construct/wall, + /decl/ability/cult/construct/floor, + /decl/ability/cult/construct/soulstone, + /decl/ability/cult/construct/pylon + ) + hud_used = /datum/hud/animal/construct/artificer + base_movement_delay = 0 + +/obj/item/natural_weapon/cult_builder + name = "heavy arms" + attack_verb = "rammed" + + +/mob/living/simple_animal/construct/builder/mind_initialize() + ..() + mind.assigned_role = "Artificer" + mind.assigned_special_role = "Cultist" + +/////////////////////////////Behemoth///////////////////////// + + +/mob/living/simple_animal/construct/behemoth + name = "Behemoth" + real_name = "Behemoth" + desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." + icon = 'icons/mob/simple_animal/construct_behemoth.dmi' + max_health = 750 + speak_emote = list("rumbles") + response_harm = "harmlessly punches" + harm_intent_damage = 0 + natural_weapon = /obj/item/natural_weapon/juggernaut/behemoth + environment_smash = 2 + resistance = 10 + construct_spells = list( + /decl/ability/cult/construct/lesser + ) + hud_used = /datum/hud/animal/construct/juggernaut + base_movement_delay = 2 + ai = /datum/mob_controller/aggressive/construct_armoured + +/obj/item/natural_weapon/juggernaut/behemoth + _base_attack_force = 50 + +////////////////////////Harvester//////////////////////////////// + +/mob/living/simple_animal/construct/harvester + name = "Harvester" + real_name = "Harvester" + desc = "The promised reward of the livings who follow Nar-Sie. Obtained by offering their bodies to the geometer of blood" + icon = 'icons/mob/simple_animal/construct_harvester.dmi' + max_health = 150 + natural_weapon = /obj/item/natural_weapon/harvester + environment_smash = 1 + see_in_dark = 7 + hud_used = /datum/hud/animal/construct/harvester + construct_spells = list( + /decl/ability/cult/construct/harvest + ) + +/obj/item/natural_weapon/harvester + name = "malicious spike" + gender = NEUTER + attack_verb = list("violently stabbed", "ran through") + hitsound = 'sound/weapons/pierce.ogg' + sharp = TRUE + _base_attack_force = 25 + +////////////////HUD////////////////////// +/mob/living/simple_animal/construct/handle_regular_status_updates() + . = ..() + if(.) + disable_abilities(purge) + +/mob/living/simple_animal/construct/handle_regular_hud_updates() + . = ..() + if(.) + disable_abilities(purge) diff --git a/mods/gamemodes/cult/mobs/constructs/soulstone.dm b/mods/gamemodes/cult/mobs/constructs/soulstone.dm new file mode 100644 index 000000000000..bf006ad412d0 --- /dev/null +++ b/mods/gamemodes/cult/mobs/constructs/soulstone.dm @@ -0,0 +1,181 @@ +#define SOULSTONE_CRACKED -1 +#define SOULSTONE_EMPTY 0 +#define SOULSTONE_ESSENCE 1 + +/obj/item/soulstone + name = "soul stone shard" + icon = 'icons/obj/items/soulstone.dmi' + icon_state = ICON_STATE_WORLD + desc = "A strange, ridged chunk of some glassy red material. Achingly cold to the touch." + w_class = ITEM_SIZE_SMALL + slot_flags = SLOT_LOWER_BODY + origin_tech = @'{"wormholes":4,"materials":4}' + material = /decl/material/solid/gemstone/crystal + var/full = SOULSTONE_EMPTY + var/is_evil = 1 + var/mob/living/simple_animal/shade = null + +/obj/item/soulstone/Initialize(var/mapload) + shade = new /mob/living/simple_animal/shade(src) + . = ..(mapload) + +/obj/item/soulstone/on_update_icon() + . = ..() + if(full == SOULSTONE_ESSENCE) + add_overlay("[icon_state]-glow") + else if(full == SOULSTONE_CRACKED) + SetName("cracked soulstone") + +/obj/item/soulstone/shatter() + playsound(loc, "shatter", 70, 1) + qdel(src) + +/obj/item/soulstone/full + full = SOULSTONE_ESSENCE + +/obj/item/soulstone/Destroy() + QDEL_NULL(shade) + return ..() + +/obj/item/soulstone/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(full == SOULSTONE_EMPTY) + . += "The shard still flickers with a fraction of the full artifact's power, but it needs to be filled with the essence of someone's life before it can be used." + if(full == SOULSTONE_ESSENCE) + . += "The shard has gone transparent, a seeming window into a dimension of unspeakable horror." + if(full == SOULSTONE_CRACKED) + . += "This one is cracked and useless." + +/obj/item/soulstone/attackby(var/obj/item/used_item, var/mob/user) + if(is_evil && istype(used_item, /obj/item/nullrod)) + to_chat(user, SPAN_NOTICE("You cleanse \the [src] of taint, purging its shackles to its creator.")) + is_evil = FALSE + return TRUE + else if(used_item.expend_attack_force(user) >= 5) + if(full != SOULSTONE_CRACKED) + user.visible_message( + SPAN_WARNING("\The [user] hits \the [src] with \the [used_item], and it breaks.[shade.client ? " You hear a terrible scream!" : ""]"), + SPAN_WARNING("You hit \the [src] with \the [used_item], and it cracks.[shade.client ? " You hear a terrible scream!" : ""]"), + shade.client ? SPAN_NOTICE("You hear a scream.") : null) + playsound(loc, 'sound/effects/Glasshit.ogg', 75) + set_full(SOULSTONE_CRACKED) + else + user.visible_message(SPAN_DANGER("\The [user] shatters \the [src] with \the [used_item]!")) + shatter() + return TRUE + return ..() + +/obj/item/soulstone/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + if(target == shade) + to_chat(user, SPAN_NOTICE("You recapture \the [target].")) + target.forceMove(src) + return TRUE + if(full == SOULSTONE_ESSENCE) + to_chat(user, SPAN_NOTICE("\The [src] is already full.")) + return TRUE + if(target.stat != DEAD && !target.is_asystole()) + to_chat(user, SPAN_NOTICE("Kill or maim the victim first.")) + return TRUE + for(var/obj/item/thing in target) + target.drop_from_inventory(thing) + target.dust() + set_full(SOULSTONE_ESSENCE) + return TRUE + +/obj/item/soulstone/attack_self(var/mob/user) + if(full != SOULSTONE_ESSENCE) // No essence - no shade + to_chat(user, SPAN_NOTICE("This [src] has no life essence.")) + return + + if(!shade.key) // No key = hasn't been used + to_chat(user, SPAN_NOTICE("You cut your finger and let the blood drip on \the [src].")) + user.remove_blood(1, absolute = TRUE) + var/decl/ghosttrap/S = GET_DECL(/decl/ghosttrap/cult_shade) + S.request_player(shade, "The soul stone shade summon ritual has been performed. ") + else if(!shade.client) // Has a key but no client - shade logged out + to_chat(user, SPAN_NOTICE("\The [shade] in \the [src] is dormant.")) + return + else if(shade.loc == src) + var/choice = alert("Would you like to invoke the spirit within?",,"Yes","No") + if(choice == "Yes") + shade.dropInto(loc) + to_chat(user, SPAN_NOTICE("You summon \the [shade].")) + if(choice == "No") + return + +/obj/item/soulstone/proc/set_full(var/f) + full = f + update_icon() + +// Soulstone synthesis recipe. +/decl/chemical_reaction/synthesis/soulstone + name = "Soulstone" + result = null + required_reagents = list(/decl/material/liquid/blood = 15, /decl/material/liquid/crystal_agent = 1) + result_amount = 1 + hidden_from_codex = TRUE // This shouldn't show up in search. Maybe it should be linked in a 'guide to cult' or something? + +/decl/chemical_reaction/synthesis/soulstone/send_data(datum/reagents/holder, reaction_limit) + return REAGENT_DATA(holder, /decl/material/liquid/blood) // allow on_reaction to get donor data + +/// Whether or not the reaction should produce a soulstone or a normal crystal. +/// The donor mob parameter may either be /mob/living or null. +/decl/chemical_reaction/synthesis/soulstone/proc/donor_is_magic(mob/living/donor) + return FALSE // By default, no one is magic! This is for modpacks to override. + +/decl/chemical_reaction/synthesis/soulstone/on_reaction(datum/reagents/holder, created_volume, list/reaction_data) + var/location = get_turf(holder.get_reaction_loc(chemical_reaction_flags)) + var/weakref/donor_ref = LAZYACCESS(reaction_data, DATA_BLOOD_DONOR) + if(donor_is_magic(donor_ref?.resolve())) + for(var/i = 1, i <= created_volume, i++) + new /obj/item/soulstone(location) + else // waste it and produce useless crystal shards + for(var/i = 1, i <= created_volume*2, i++) + new /obj/item/shard(location, /decl/material/solid/gemstone/crystal) + +// Construct shells. These accept soulstones. +/obj/structure/constructshell + name = "empty shell" + icon = 'icons/obj/structures/construct.dmi' + icon_state = "construct" + desc = "A wicked machine used by those skilled in magical arts. It is inactive." + +/obj/structure/constructshell/cult + icon_state = "construct-cult" + desc = "This eerie contraption looks like it would come alive if supplied with a missing ingredient." + +/obj/structure/constructshell/attackby(var/obj/item/used_item, var/mob/user) + if(!istype(used_item, /obj/item/soulstone)) + return ..() + var/obj/item/soulstone/S = used_item + if(!S.shade.client) + to_chat(user, SPAN_NOTICE("\The [used_item] has essence, but no soul. Activate it in your hand to find a soul for it first.")) + return TRUE + if(S.shade.loc != S) + to_chat(user, SPAN_NOTICE("Recapture the shade back into \the [used_item] first.")) + return TRUE + var/construct = alert(user, "Please choose which type of construct you wish to create.",,"Artificer", "Wraith", "Juggernaut") + var/ctype + switch(construct) + if("Artificer") + ctype = /mob/living/simple_animal/construct/builder + if("Wraith") + ctype = /mob/living/simple_animal/construct/wraith + if("Juggernaut") + ctype = /mob/living/simple_animal/construct/armoured + var/mob/living/simple_animal/construct/C = new ctype(get_turf(src)) + C.key = S.shade.key + //C.cancel_camera() + if(S.is_evil) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + cult.add_antagonist(C.mind) + qdel(S) + qdel(src) + return TRUE + +/obj/structure/constructshell/get_artifact_scan_data() + return "Tribal idol - subject resembles statues/emblems built by superstitious pre-warp civilisations to honour their gods. Material appears to be a rock/plastcrete composite." + +#undef SOULSTONE_CRACKED +#undef SOULSTONE_EMPTY +#undef SOULSTONE_ESSENCE diff --git a/mods/gamemodes/cult/mobs/mob_subtypes.dm b/mods/gamemodes/cult/mobs/mob_subtypes.dm new file mode 100644 index 000000000000..bdafcb5fa771 --- /dev/null +++ b/mods/gamemodes/cult/mobs/mob_subtypes.dm @@ -0,0 +1,15 @@ +/mob/living/simple_animal/hostile/scarybat/cult + faction = "cult" + supernatural = TRUE + +/mob/living/simple_animal/hostile/scarybat/cult/on_defilement() + return + +/mob/living/simple_animal/hostile/creature/cult + faction = "cult" + min_gas = null + max_gas = null + minbodytemp = 0 + +/mob/living/simple_animal/hostile/creature/cult/on_defilement() + return \ No newline at end of file diff --git a/mods/gamemodes/cult/mobs/shade.dm b/mods/gamemodes/cult/mobs/shade.dm new file mode 100644 index 000000000000..aea9a434815f --- /dev/null +++ b/mods/gamemodes/cult/mobs/shade.dm @@ -0,0 +1,57 @@ +/mob/living/simple_animal/shade + name = "shade" + real_name = "Shade" + desc = "A bound spirit" + icon = 'icons/mob/simple_animal/shade.dmi' + max_health = 50 + universal_speak = TRUE + speak_emote = list("hisses") + response_help_1p = "You wave your hand through $TARGET$." + response_help_3p = "$USER$ waves $USER_THEIR$ hand through $TARGET$." + response_disarm = "flails at" + response_harm = "punches" + natural_weapon = /obj/item/natural_weapon/shade + minbodytemp = 0 + maxbodytemp = 4000 + min_gas = null + max_gas = null + faction = "cult" + supernatural = 1 + status_flags = CANPUSH + gene_damage = -1 + bleed_colour = "#181933" + butchery_data = null + base_movement_delay = -1 + ai = /datum/mob_controller/shade + +/datum/mob_controller/shade + emote_hear = list("wails","screeches") + do_wander = FALSE + +/mob/living/simple_animal/shade/check_has_mouth() + return FALSE + +/obj/item/natural_weapon/shade + name = "foul touch" + attack_verb = "drained" + atom_damage_type = BURN + _base_attack_force = 10 + +/mob/living/simple_animal/shade/on_defilement() + return + +/mob/living/simple_animal/shade/get_death_message(gibbed) + return "lets out a contented sigh as their form unwinds" + +/mob/living/simple_animal/shade/get_self_death_message(gibbed) + return "You have been released from your earthly binds." + +/mob/living/simple_animal/shade/death(gibbed) + . = ..() + if(. && !gibbed) + new /obj/item/ectoplasm(src.loc) + qdel(src) + +/mob/living/simple_animal/shade/mind_initialize() + ..() + mind.assigned_role = "Shade" diff --git a/mods/gamemodes/cult/narsie.dm b/mods/gamemodes/cult/narsie.dm new file mode 100644 index 000000000000..ef8281558ddc --- /dev/null +++ b/mods/gamemodes/cult/narsie.dm @@ -0,0 +1,181 @@ +var/global/narsie_cometh = 0 +var/global/list/narsie_list = list() + +/obj/effect/narsie_footstep + name = "mark of the Geometer" + desc = "Something that goes beyond your understanding went this way." + icon = 'icons/turf/flooring/cult.dmi' + icon_state = "narsie_footstep" + light_color = COLOR_RED + light_range = 1 + light_power = 1 + +/obj/effect/narsie + name = "Nar-Sie" + desc = "Your mind begins to bubble and ooze as it tries to comprehend what it sees." + icon = 'icons/obj/narsie.dmi' + icon_state = "narsie" + anchored = TRUE + pixel_x = -236 + pixel_y = -256 + plane = ABOVE_LIGHTING_PLANE + layer = ABOVE_LIGHTING_LAYER + light_range = 1 + light_color = "#3e0000" + is_spawnable_type = FALSE + + /// The current target we're pursuing. + var/mob/target + /// Are we going to move around? Set by admin and mappers. + var/move_self = TRUE + /// How many tiles out do we pull? + var/consume_pull = 10 + /// How many tiles out do we eat + var/consume_range = 6 + /// Sanity check for consuming. + var/max_atoms_assessed_per_tick = 100 + +/obj/effect/narsie/Initialize() + . = ..() + global.narsie_list.Add(src) + START_PROCESSING(SSobj, src) + set_extension(src, /datum/extension/universally_visible) + announce_narsie() + update_icon() + +/obj/effect/narsie/Destroy() + target = null + global.narsie_list.Remove(src) + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/effect/narsie/is_space_movement_permitted(allow_movement) + return SPACE_MOVE_PERMITTED + +// See comment at the top of the file for why this sections of this are commented out. +/obj/effect/narsie/on_update_icon() + . = ..() + set_overlays("glow-narsie") + compile_overlays() + var/datum/extension/universally_visible/univis = get_extension(src, /datum/extension/universally_visible) + univis.refresh() + +/obj/effect/narsie/Move() + . = ..() + if(.) + var/datum/extension/universally_visible/univis = get_extension(src, /datum/extension/universally_visible) + univis.refresh() + +/obj/effect/narsie/forceMove(atom/dest) + . = ..() + if(.) + var/datum/extension/universally_visible/univis = get_extension(src, /datum/extension/universally_visible) + univis.refresh() + +/obj/effect/narsie/Process() + + // Feed. + var/consumed = 0 + for(var/atom/consuming in range(consume_pull, src)) + if(get_dist(src, consuming) >= consume_range) + consuming.singularity_pull(src, 9) + else + consuming.on_defilement() + if(consumed++ >= max_atoms_assessed_per_tick || TICK_CHECK) + break + + if(TICK_CHECK) + return + + // Find a target. + if (!target || prob(5)) + var/list/targets = list() + var/current_zs = SSmapping.get_connected_levels(z, include_lateral = FALSE) // can't really handle lateral connections + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + for(var/datum/mind/cult_nh_mind in cult.current_antagonists) + if(cult_nh_mind.current && !cult_nh_mind.current.stat && (get_z(cult_nh_mind.current) in current_zs)) + targets += cult_nh_mind.current + // If we have no valid cultists, go for any human. + if(!length(targets)) + for(var/mob/living/human/food in global.living_mob_list_) + if(food.stat) + var/turf/pos = get_turf(food) + if(pos?.z in current_zs) + targets += food + // Go for ghosts if nothing else is available. + if(!length(targets)) + for(var/mob/observer/G in global.dead_mob_list_) + targets += G + // Pick a random candidate. + if(length(targets)) + var/capname = uppertext(name) + if(target) + to_chat(target, SPAN_NOTICE("[capname] HAS LOST INTEREST IN YOU.")) + target = pick(targets) + if (ishuman(target)) + to_chat(target, SPAN_DANGER("[capname] HUNGERS FOR YOUR SOUL.")) + else + to_chat(target, SPAN_DANGER("[capname] HAS CHOSEN YOU TO LEAD HIM TO HIS NEXT MEAL.")) + + // Move. + if(move_self) + + // Get a direction to move. + var/movement_dir + if(target && prob(60)) + if(target.z == z) + movement_dir = get_dir(src, target) + else if(target.z > z && GetAbove(src)) + movement_dir = UP + else if(target.z < z && GetBelow(src)) + movement_dir = DOWN + else if(prob(16)) + var/list/available_vertical_moves = list() + if(GetAbove(src)) + available_vertical_moves += UP + if(GetBelow(src)) + available_vertical_moves += DOWN + if(length(available_vertical_moves)) + movement_dir = pick(available_vertical_moves) + if(!movement_dir) + movement_dir = pick(global.alldirs) + + // Try to move in it. + step(src, movement_dir) + var/turf/T = get_turf(loc) + if(T && !T.is_open() && !(locate(/obj/effect/narsie_footstep) in T)) // Separate to /turf/proc/is_defiled() due to overrides up the turf tree. + new /obj/effect/narsie_footstep(T) + + if(prob(25)) + for(var/mob/living/M in oviewers(8, src)) + if(M.stat == CONSCIOUS && !(M.status_flags & GODMODE) && !iscultist(M)) + to_chat(M, SPAN_DANGER("You feel your sanity crumble away in an instant as you gaze upon [src.name]...")) + M.apply_effect(3, STUN) + +/obj/effect/narsie/proc/announce_narsie() + set waitfor = FALSE + if(global.narsie_cometh)//so we don't initiate Hell more than one time. + return + to_world(SPAN_DANGER("[uppertext(name)] HAS RISEN!")) + sound_to(world, sound('sound/effects/wind/wind_5_1.ogg')) + narsie_spawn_animation() + global.narsie_cometh = TRUE + SetUniversalState(/datum/universal_state/hell) + sleep(10 SECONDS) + if(SSevac.evacuation_controller) + SSevac.evacuation_controller.call_evacuation(null, TRUE, 1) + SSevac.evacuation_controller.evac_no_return = 0 // Cannot recall + +/obj/effect/narsie/proc/narsie_spawn_animation() + set waitfor = FALSE + icon = 'icons/obj/narsie_spawn_anim.dmi' + set_dir(SOUTH) + move_self = FALSE + flick("narsie_spawn_anim",src) + sleep(1 SECOND) + move_self = TRUE + icon = initial(icon) + +/obj/effect/narsie/explosion_act(severity) //No throwing bombs at it either. --NEO + SHOULD_CALL_PARENT(FALSE) + return diff --git a/mods/gamemodes/cult/objectives.dm b/mods/gamemodes/cult/objectives.dm new file mode 100644 index 000000000000..4f8982daf124 --- /dev/null +++ b/mods/gamemodes/cult/objectives.dm @@ -0,0 +1,25 @@ +/datum/objective/cult/survive + explanation_text = "Our knowledge must live on." + target_amount = 5 + +/datum/objective/cult/survive/New() + ..() + explanation_text = "Our knowledge must live on. Make sure at least [target_amount] acolytes escape to spread their work." + +/datum/objective/cult/eldergod + explanation_text = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it. The convert rune is join blood self." + +/datum/objective/cult/sacrifice + explanation_text = "Conduct a ritual sacrifice for the glory of Nar-Sie." + +/datum/objective/cult/sacrifice/find_target() + var/list/possible_targets = list() + if(!possible_targets.len) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + for(var/mob/living/human/player in global.player_list) + if(player.mind && !(player.mind in cult.current_antagonists)) + possible_targets += player.mind + if(possible_targets.len > 0) + target = pick(possible_targets) + if(target) explanation_text = "Sacrifice [target.name], the [target.assigned_role]. You will need the sacrifice rune (Hell blood join) and three acolytes to do so." + return target diff --git a/mods/gamemodes/cult/overrides.dm b/mods/gamemodes/cult/overrides.dm new file mode 100644 index 000000000000..15029601185d --- /dev/null +++ b/mods/gamemodes/cult/overrides.dm @@ -0,0 +1,48 @@ +/datum/artifact_find/New() + var/static/injected = FALSE + if(!injected) + potential_finds[/obj/structure/cult/pylon] = 50 + potential_finds[/obj/structure/constructshell] = 5 + injected = TRUE + ..() + +/obj/structure/crematorium/on_cremate_mob(atom/cause, mob/living/victim) + . = ..() + if(. && round_is_spooky()) + if(prob(50)) + playsound(src, 'sound/effects/ghost.ogg', 10, 5) + else + playsound(src, 'sound/effects/ghost2.ogg', 10, 5) + +/datum/trader/ship/clothingshop/hatglovesaccessories/New() + ..() + possible_trading_items[/obj/item/clothing/head/culthood] = TRADER_BLACKLIST_ALL + +/mob/living/silicon/ai + shouldnt_see = list(/obj/effect/rune) + +/obj/item/vampiric + material = /decl/material/solid/stone/cult + +/mob/safe_animal(var/MP) + . = ..() + if(ispath(MP, /mob/living/simple_animal/shade)) + return 1 + +/mob/living/simple_animal/hostile/revenant + butchery_data = /decl/butchery_data/occult + +/mob/living/simple_animal/hostile/revenant/cult + faction = "cult" + +/mob/living/simple_animal/hostile/revenant/cult/on_defilement() + return + +/obj/item/mop/populate_moppable_types() + . = ..() + moppable_types |= /obj/effect/rune + +/obj/effect/gateway/active/can_transform(mob/victim) + if(iscultist(victim)) + return FALSE + return ..() \ No newline at end of file diff --git a/code/game/gamemodes/cult/ritual.dm b/mods/gamemodes/cult/ritual.dm similarity index 76% rename from code/game/gamemodes/cult/ritual.dm rename to mods/gamemodes/cult/ritual.dm index e2f9ede65d09..5d07ea311482 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/mods/gamemodes/cult/ritual.dm @@ -1,12 +1,15 @@ /obj/item/book/tome - name = "arcane tome" - icon = 'icons/obj/items/tome.dmi' - icon_state = "tome" - throw_speed = 1 - throw_range = 5 - w_class = ITEM_SIZE_SMALL - unique = 1 - carved = 2 // Don't carve it + name = "arcane tome" + icon = 'icons/obj/items/tome.dmi' + icon_state = "tome" + throw_speed = 1 + throw_range = 5 + w_class = ITEM_SIZE_SMALL + unique = TRUE + can_dissolve_text = FALSE + +/obj/item/book/tome/try_carve(mob/user, obj/item/tool) + return /obj/item/book/tome/attack_self(var/mob/user) if(!iscultist(user)) @@ -14,42 +17,41 @@ else to_chat(user, "Hold \the [src] in your hand while drawing a rune to use it.") -/obj/item/book/tome/examine(mob/user) +/obj/item/book/tome/get_examine_strings(mob/user, distance, infix, suffix) . = ..() - if(!iscultist(user)) - to_chat(user, "An old, dusty tome with frayed edges and a sinister looking cover.") + if(iscultist(user)) + . += "The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood. Contains the details of every ritual his followers could think of. Most of these are useless, though." else - to_chat(user, "The scriptures of Nar-Sie, The One Who Sees, The Geometer of Blood. Contains the details of every ritual his followers could think of. Most of these are useless, though.") + . += "An old, dusty tome with frayed edges and a sinister looking cover." /obj/item/book/tome/afterattack(var/atom/A, var/mob/user, var/proximity) if(!proximity || !iscultist(user)) return if(A.reagents && A.reagents.has_reagent(/decl/material/liquid/water)) to_chat(user, SPAN_NOTICE("You desecrate \the [A].")) - LAZYSET(A.reagents.reagent_data, /decl/material/liquid/water, list("holy" = FALSE)) + REAGENT_SET_DATA(A.reagents, /decl/material/liquid/water, list(DATA_WATER_HOLINESS = FALSE)) /mob/proc/make_rune(var/rune, var/cost = 5, var/tome_required = 0) - var/has_tome = 0 var/has_robes = 0 var/cult_ground = 0 - if(istype(get_active_hand(), /obj/item/book/tome) || istype(get_inactive_hand(), /obj/item/book/tome)) - has_tome = 1 - else if(tome_required && mob_needs_tome()) + + var/has_tome = locate(/obj/item/book/tome) in get_held_items() + if(tome_required && mob_needs_tome() && !has_tome) to_chat(src, "This rune is too complex to draw by memory, you need to have a tome in your hand to draw it.") return - if(istype(get_equipped_item(slot_head), /obj/item/clothing/head/culthood) && istype(get_equipped_item(slot_wear_suit), /obj/item/clothing/suit/cultrobes) && istype(get_equipped_item(slot_shoes), /obj/item/clothing/shoes/cult)) + if(istype(get_equipped_item(slot_head_str), /obj/item/clothing/head/culthood) && istype(get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/cultrobes) && istype(get_equipped_item(slot_shoes_str), /obj/item/clothing/shoes/cult)) has_robes = 1 var/turf/T = get_turf(src) - if(T.holy) + if(is_holy_turf(T)) to_chat(src, "This place is blessed, you may not draw runes on it - defile it first.") return - if(!istype(T, /turf/simulated)) + if(!T.simulated) to_chat(src, "You need more space to draw a rune here.") return if(locate(/obj/effect/rune) in T) to_chat(src, "There's already a rune here.") // Don't cross the runes return - if(T.icon_state == "cult" || T.icon_state == "cult-narsie") + if(T.is_defiled()) cult_ground = 1 var/self var/timer @@ -87,56 +89,29 @@ damage = 2 visible_message("\The [src] slices open a finger and begins to chant and paint symbols on the floor.", "[self]", "You hear chanting.") if(do_after(src, timer)) - remove_blood_simple(cost * damage) + remove_blood(cost * damage) if(locate(/obj/effect/rune) in T) return - var/obj/effect/rune/R = new rune(T, get_rune_color(), get_blood_name()) + var/obj/effect/rune/R = new rune(T, get_blood_color(), get_blood_name()) var/area/A = get_area(R) - log_and_message_admins("created \an [R.cultname] rune at \the [A.name].") + log_and_message_admins("created \an [R.cultname] rune at \the [A.proper_name].") R.add_fingerprint(src) return 1 return 0 -/mob/living/carbon/human/make_rune(var/rune, var/cost, var/tome_required) - if(should_have_organ(BP_HEART) && vessel && vessel.total_volume < species.blood_volume * 0.7) +/mob/living/human/make_rune(var/rune, var/cost, var/tome_required) + if(should_have_organ(BP_HEART) && REAGENT_TOTAL_VOLUME(vessel) < species.blood_volume * 0.7) to_chat(src, "You are too weak to draw runes.") return ..() -/mob/proc/remove_blood_simple(var/blood) - return - -/mob/living/carbon/human/remove_blood_simple(var/blood) - if(should_have_organ(BP_HEART)) - vessel.remove_any(blood) - -/mob/proc/get_blood_name() - return "blood" - -/mob/living/silicon/get_blood_name() - return "oil" - -/mob/living/carbon/human/get_blood_name() - if(species) - return species.get_blood_name() - return "blood" - -/mob/living/simple_animal/construct/get_blood_name() - return "ichor" - /mob/proc/mob_needs_tome() - return 0 - -/mob/living/carbon/human/mob_needs_tome() - return 1 - -/mob/proc/get_rune_color() - return "#c80000" + return FALSE -/mob/living/carbon/human/get_rune_color() - return species.blood_color +/mob/living/human/mob_needs_tome() + return TRUE -var/list/Tier1Runes = list( +var/global/list/Tier1Runes = list( /mob/proc/convert_rune, /mob/proc/teleport_rune, /mob/proc/tome_rune, @@ -150,7 +125,7 @@ var/list/Tier1Runes = list( /mob/proc/reveal ) -var/list/Tier2Runes = list( +var/global/list/Tier2Runes = list( /mob/proc/armor_rune, /mob/proc/offering_rune, /mob/proc/drain_rune, @@ -158,7 +133,7 @@ var/list/Tier2Runes = list( /mob/proc/massdefile_rune ) -var/list/Tier3Runes = list( +var/global/list/Tier3Runes = list( /mob/proc/weapon_rune, /mob/proc/shell_rune, /mob/proc/bloodboil_rune, @@ -166,7 +141,7 @@ var/list/Tier3Runes = list( /mob/proc/revive_rune ) -var/list/Tier4Runes = list( +var/global/list/Tier4Runes = list( /mob/proc/tearreality_rune ) @@ -295,7 +270,7 @@ var/list/Tier4Runes = list( return message_cult_communicate() - remove_blood_simple(3) + remove_blood(3) var/input = input(src, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "") if(!input) @@ -305,11 +280,12 @@ var/list/Tier4Runes = list( input = sanitize(input) log_and_message_admins("used a communicate verb to say '[input]'") - for(var/datum/mind/H in GLOB.cult.current_antagonists) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + for(var/datum/mind/H in cult.current_antagonists) if(H.current && !H.current.stat) to_chat(H.current, "[input]") -/mob/living/carbon/cult_communicate() +/mob/living/cult_communicate() if(incapacitated(INCAPACITATION_RESTRAINED)) to_chat(src, "You need at least your hands free to do this.") return @@ -318,8 +294,9 @@ var/list/Tier4Runes = list( /mob/proc/message_cult_communicate() return -/mob/living/carbon/human/message_cult_communicate() - visible_message("\The [src] cuts \his finger and starts drawing on the back of \his hand.") +/mob/living/human/message_cult_communicate() + var/decl/pronouns/pronouns = get_pronouns() + visible_message(SPAN_WARNING("\The [src] cuts [pronouns.his] finger and starts drawing on the back of [pronouns.his] hand.")) /mob/proc/obscure() set category = "Cult Magic" diff --git a/mods/gamemodes/cult/runes.dm b/mods/gamemodes/cult/runes.dm new file mode 100644 index 000000000000..8b6ca53d09f8 --- /dev/null +++ b/mods/gamemodes/cult/runes.dm @@ -0,0 +1,863 @@ +/obj/effect/rune + name = "rune" + desc = "A strange collection of symbols drawn in blood." + anchored = TRUE + icon = 'mods/gamemodes/cult/icons/runes.dmi' + icon_state = "blank" + layer = RUNE_LAYER + + var/blood + var/bcolor + var/strokes = 2 // IF YOU EVER SET THIS TO MORE THAN TEN, EVERYTHING WILL BREAK + var/cultname = "" + +/obj/effect/rune/Initialize(mapload, var/blcolor = "#c80000", var/nblood = "blood") + . = ..() + bcolor = blcolor + blood = nblood + update_icon() + set_extension(src, /datum/extension/turf_hand, 10) + +/obj/effect/rune/on_update_icon() + overlays.Cut() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + if(cult.rune_strokes[type]) + var/list/f = cult.rune_strokes[type] + for(var/i in f) + var/image/t = image(icon, "rune-[i]") + overlays += t + else + var/list/q = list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + var/list/f = list() + for(var/i = 1 to strokes) + var/j = pick(q) + f += j + q -= f + var/image/t = image(icon, "rune-[j]") + overlays += t + cult.rune_strokes[type] = f.Copy() + color = bcolor + desc = "A strange collection of symbols drawn in [blood]." + +/obj/effect/rune/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(iscultist(user)) + . += "This is \a [cultname] rune." + +/obj/effect/rune/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/book/tome) && iscultist(user)) + user.visible_message(SPAN_NOTICE("[user] rubs \the [src] with \the [used_item], and \the [src] is absorbed by it."), "You retrace your steps, carefully undoing the lines of \the [src].") + qdel(src) + return TRUE + else if(istype(used_item, /obj/item/nullrod)) + user.visible_message(SPAN_NOTICE("[user] hits \the [src] with \the [used_item], and it disappears, fizzling."), SPAN_NOTICE("You disrupt the vile magic with the deadening field of \the [used_item]."), "You hear a fizzle.") + qdel(src) + return TRUE + return ..() + +/obj/effect/rune/attack_hand(var/mob/user) + SHOULD_CALL_PARENT(FALSE) + if(!iscultist(user)) + to_chat(user, "You can't mouth the arcane scratchings without fumbling over them.") + return TRUE + if(user.is_silenced()) + to_chat(user, "You are unable to speak the words of the rune.") + return TRUE + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + if(cult.powerless) + to_chat(user, "You read the words, but nothing happens.") + fizzle(user) + return TRUE + cast(user) + return TRUE + +/obj/effect/rune/attack_ai(var/mob/user) // Cult borgs! + return attack_hand_with_interaction_checks(user) + +/obj/effect/rune/proc/cast(var/mob/living/user) + fizzle(user) + +/obj/effect/rune/proc/get_cultists() + . = list() + for(var/mob/living/M in range(1)) + if(iscultist(M)) + . += M + +/obj/effect/rune/proc/fizzle(var/mob/living/user) + visible_message(SPAN_WARNING("The markings pulse with a small burst of light, then fall dark."), "You hear a fizzle.") + +//Makes the speech a proc so all verbal components can be easily manipulated as a whole, or individually easily +/obj/effect/rune/proc/speak_incantation(var/mob/living/user, var/incantation) + var/decl/language/L = GET_DECL(/decl/language/cultcommon) + if(istype(L) && incantation && (L in user.languages)) + user.say(incantation, L) + +/obj/effect/rune/get_surgery_success_modifier(delicate) + return delicate ? -10 : 0 + +/obj/effect/rune/get_surgery_surface_quality(mob/living/victim, mob/living/user) + return OPERATE_PASSABLE + +/turf/remove_cleanables() + for(var/obj/effect/rune/rune in src) + qdel(rune) + +/* Tier 1 runes below */ + +/obj/effect/rune/convert + cultname = "convert" + var/spamcheck = 0 + +/obj/effect/rune/convert/cast(var/mob/living/user) + if(spamcheck) + return + + var/mob/living/target = null + for(var/mob/living/M in get_turf(src)) + if(!iscultist(M) && M.stat != DEAD) + target = M + break + + if(!target) + return fizzle(user) + + speak_incantation(user, "Mah[pick("'","`")]weyh pleggh at e'ntrath!") + target.visible_message(SPAN_WARNING("The markings below [target] glow a bloody red.")) + + to_chat(target, SPAN_OCCULT("Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.")) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + if(!cult.can_become_antag(target.mind, 1)) + to_chat(target, SPAN_DANGER("Are you going insane?")) + else + to_chat(target, SPAN_OCCULT("Do you want to join the cult of Nar'Sie? You can choose to ignore the offer... Join the cult.")) + + spamcheck = 1 + spawn(40) + spamcheck = 0 + if(!iscultist(target) && target.loc == get_turf(src)) // They hesitated, resisted, or can't join, and they are still on the rune - burn them + if(target.stat == CONSCIOUS) + target.take_overall_damage(0, 10) + switch(target.get_damage(BURN)) + if(0 to 25) + to_chat(target, SPAN_DANGER("Your blood boils as you force yourself to resist the corruption invading every corner of your mind.")) + if(25 to 45) + to_chat(target, SPAN_DANGER("Your blood boils and your body burns as the corruption further forces itself into your body and mind.")) + target.take_overall_damage(0, 3) + if(45 to 75) + to_chat(target, SPAN_DANGER("You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble.")) + target.take_overall_damage(0, 5) + if(75 to 100) + to_chat(target, SPAN_OCCULT("Your mind turns to ash as the burning flames engulf your very soul and images of an unspeakable horror begin to bombard the last remnants of mental resistance.")) + target.take_overall_damage(0, 10) + +/obj/effect/rune/convert/OnTopic(mob/user, href_list) + if(href_list["join"] && user.loc == loc && !iscultist(user)) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + cult.add_antagonist(user.mind, ignore_role = 1, do_not_equip = 1) + +/obj/effect/rune/teleport + cultname = "teleport" + var/destination + +/obj/effect/rune/teleport/Initialize() + . = ..() + var/area/A = get_area(src) + if(!A) + return INITIALIZE_HINT_QDEL + destination = A.proper_name + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.teleport_runes += src + +/obj/effect/rune/teleport/Destroy() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.teleport_runes -= src + var/turf/T = get_turf(src) + if(T) + for(var/atom/movable/A in contents) + A.forceMove(T) + return ..() + +/obj/effect/rune/teleport/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(iscultist(user)) + . += "Its name is [destination]." + +/obj/effect/rune/teleport/cast(var/mob/living/user) + if(user.loc == src) + showOptions(user) + else if(user.loc == get_turf(src)) + speak_incantation(user, "Sas[pick("'","`")]so c'arta forbici!") + if(do_after(user, 30)) + user.visible_message(SPAN_WARNING("\The [user] disappears in a flash of red light!"), SPAN_WARNING("You feel as your body gets dragged into the dimension of Nar-Sie!"), "You hear a sickening crunch.") + user.forceMove(src) + showOptions(user) + var/warning = 0 + while(user.loc == src) + user.take_organ_damage(0, 2) + if(user.get_damage(BURN) > 50) + to_chat(user, SPAN_DANGER("Your body can't handle the heat anymore!")) + leaveRune(user) + return + if(warning == 0) + to_chat(user, SPAN_WARNING("You feel the immerse heat of the realm of Nar-Sie...")) + ++warning + if(warning == 1 && user.get_damage(BURN) > 15) + to_chat(user, SPAN_WARNING("Your burns are getting worse. You should return to your realm soon...")) + ++warning + if(warning == 2 && user.get_damage(BURN) > 35) + to_chat(user, SPAN_WARNING("The heat! It burns!")) + ++warning + sleep(10) + else + var/input = input(user, "Choose a new rune name.", "Destination", "") as text|null + if(!input) + return + destination = sanitize(input) + +/obj/effect/rune/teleport/OnTopic(mob/user, href_list) + if(user.loc != src) + return + if(href_list["target"]) + var/obj/effect/rune/teleport/targ = locate(href_list["target"]) + if(istype(targ)) // Checks for null, too + user.forceMove(targ) + targ.showOptions(user) + else if(href_list["leave"]) + leaveRune(user) + +/obj/effect/rune/teleport/proc/showOptions(var/mob/living/user) + var/list/t = list() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + for(var/obj/effect/rune/teleport/T in cult.teleport_runes) + if(T == src) + continue + t += "[T.destination]" + to_chat(user, "Teleport runes: [english_list(t, nothing_text = "no other runes exist")]... or return from this rune.") + +/obj/effect/rune/teleport/proc/leaveRune(var/mob/living/user) + if(user.loc != src) + return + user.dropInto(loc) + user.visible_message(SPAN_WARNING("\The [user] appears in a flash of red light!"), SPAN_WARNING("You feel as your body gets thrown out of the dimension of Nar-Sie!"), "You hear a pop.") + +/obj/effect/rune/tome + cultname = "summon tome" + +/obj/effect/rune/tome/cast(var/mob/living/user) + new /obj/item/book/tome(get_turf(src)) + speak_incantation(user, "N[pick("'","`")]ath reth sh'yro eth d'raggathnor!") + visible_message(SPAN_NOTICE("\The [src] disappears with a flash of red light, and in its place now a book lies."), "You hear a pop.") + qdel(src) + +/obj/effect/rune/wall + cultname = "wall" + + var/obj/effect/cultwall/wall = null + +/obj/effect/rune/wall/Destroy() + QDEL_NULL(wall) + return ..() + +/obj/effect/rune/wall/cast(var/mob/living/user) + var/t + if(wall) + var/wall_max_health = wall.get_max_health() + if(wall.current_health >= wall_max_health) + to_chat(user, SPAN_NOTICE("The wall doesn't need mending.")) + return + t = wall_max_health - wall.current_health + wall.current_health += t + else + wall = new /obj/effect/cultwall(get_turf(src), bcolor) + wall.rune = src + t = wall.current_health + user.remove_blood(t / 50, absolute = TRUE) + speak_incantation(user, "Khari[pick("'","`")]d! Eske'te tannin!") + to_chat(user, SPAN_WARNING("Your blood flows into the rune, and you feel that the very space over the rune thickens.")) + +/obj/effect/cultwall + name = "red mist" + desc = "A strange red mist emanating from a rune below it." + icon = 'icons/effects/effects.dmi'//TODO: better icon + icon_state = "smoke" + color = "#ff0000" + anchored = TRUE + density = TRUE + max_health = 200 + var/obj/effect/rune/wall/rune + +/obj/effect/cultwall/Initialize(mapload, var/bcolor) + . = ..() + if(bcolor) + color = bcolor + +/obj/effect/cultwall/Destroy() + if(rune) + rune.wall = null + rune = null + return ..() + +/obj/effect/cultwall/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(iscultist(user)) + var/current_max_health = get_max_health() + if(current_health == current_max_health) + . += SPAN_NOTICE("It is fully intact.") + else if(current_health > current_max_health * 0.5) + . += SPAN_WARNING("It is damaged.") + else + . += SPAN_DANGER("It is about to dissipate.") + +/obj/effect/cultwall/attack_hand(var/mob/user) + SHOULD_CALL_PARENT(FALSE) + if(iscultist(user)) + user.visible_message(SPAN_NOTICE("\The [user] touches \the [src], and it fades."), SPAN_NOTICE("You touch \the [src], whispering the old ritual, making it disappear.")) + qdel(src) + else + to_chat(user, SPAN_NOTICE("You touch \the [src]. It feels wet and becomes harder the further you push your arm.")) + return TRUE + +/obj/effect/cultwall/attackby(var/obj/item/used_item, var/mob/user) + if(istype(used_item, /obj/item/nullrod)) + user.visible_message(SPAN_NOTICE("\The [user] touches \the [src] with \the [used_item], and it disappears."), SPAN_NOTICE("You disrupt the vile magic with the deadening field of \the [used_item].")) + qdel(src) + return TRUE + var/force = used_item.expend_attack_force(user) + if(force) + user.visible_message(SPAN_NOTICE("\The [user] hits \the [src] with \the [used_item]."), SPAN_NOTICE("You hit \the [src] with \the [used_item].")) + take_damage(force, used_item.atom_damage_type) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(src) + return TRUE + +/obj/effect/cultwall/bullet_act(var/obj/item/projectile/Proj) + if(!(Proj.atom_damage_type == BRUTE || Proj.atom_damage_type == BURN)) + return + take_damage(Proj.damage, Proj.atom_damage_type) + ..() + +/obj/effect/cultwall/take_damage(damage, damage_type = BRUTE, damage_flags, inflicter, armor_pen = 0, silent, do_update_health) + current_health -= damage + if(current_health <= 0) + visible_message(SPAN_WARNING("\The [src] dissipates.")) + qdel(src) + +/obj/effect/rune/ajorney + cultname = "astral journey" + +/obj/effect/rune/ajorney/cast(var/mob/living/user) + var/tmpkey = user.key + if(user.loc != get_turf(src)) + return + speak_incantation(user, "Fwe[pick("'","`")]sh mah erl nyag r'ya!") + var/decl/pronouns/pronouns = user.get_pronouns() + + user.visible_message( \ + SPAN_NOTICE("\The [user]'s eyes glow blue as [pronouns.he] freeze[pronouns.s] in place, absolutely motionless."), \ + SPAN_OCCULT("The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry..."), \ + SPAN_NOTICE("You hear only complete silence for a moment.")) + + announce_ghost_joinleave(user.ghostize(), 1, "You feel that they had to use some [pick("dark", "black", "blood", "forgotten", "forbidden")] magic to [pick("invade", "disturb", "disrupt", "infest", "taint", "spoil", "blight")] this place!") + var/mob/observer/ghost/soul + for(var/mob/observer/ghost/O in global.ghost_mob_list) + if(O.key == tmpkey) + soul = O + break + while(user) + if(user.stat == DEAD) + return + if(user.key) + return + else if(user.loc != get_turf(src) && soul) + soul.reenter_corpse() + else + user.take_organ_damage(0, 1) + sleep(20) + fizzle(user) + +/obj/effect/rune/defile + cultname = "defile" + +/obj/effect/rune/defile/cast(var/mob/living/user) + speak_incantation(user, "Ia! Ia! Zasan therium viortia!") + for(var/turf/T in range(1, src)) + if(is_holy_turf(T)) + T.turf_flags &= ~TURF_FLAG_HOLY + else + T.on_defilement() + visible_message(SPAN_WARNING("\The [src] embeds into the floor and walls around it, changing them!"), "You hear liquid flow.") + qdel(src) + +/obj/effect/rune/obscure + cultname = "obscure" + +/obj/effect/rune/obscure/cast(var/mob/living/user) + var/runecheck = 0 + for(var/obj/effect/rune/R in orange(1, src)) + if(R != src) + R.set_invisibility(INVISIBILITY_OBSERVER) + runecheck = 1 + if(runecheck) + speak_incantation(user, "Kla[pick("'","`")]atu barada nikt'o!") + visible_message(SPAN_WARNING("\ The rune turns into gray dust that conceals the surrounding runes.")) + qdel(src) + +/obj/effect/rune/reveal + cultname = "reveal" + +/obj/effect/rune/reveal/cast(var/mob/living/user) + var/irunecheck = 0 + for(var/obj/effect/rune/R in orange(1, src)) + if(R != src) + R.set_invisibility(SEE_INVISIBLE_NOLIGHTING) + irunecheck = 1 + if(irunecheck) + speak_incantation(user, "Nikt[pick("'","`")]o barada kla'atu!") + visible_message(SPAN_WARNING("\ The rune turns into red dust that reveals the surrounding runes.")) + qdel(src) + +/* Tier 2 runes */ + + +/obj/effect/rune/armor + cultname = "summon robes" + strokes = 3 + +/obj/effect/rune/armor/cast(var/mob/living/user) + speak_incantation(user, "N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") + visible_message(SPAN_WARNING("\The [src] disappears with a flash of red light, and a set of armor appears on \the [user]."), SPAN_WARNING("You are blinded by the flash of red light. After you're able to see again, you see that you are now wearing a set of armor.")) + + var/obj/O = user.get_equipped_item(slot_head_str) // This will most likely kill you if you are wearing a spacesuit, and it's 100% intended + if(O && !istype(O, /obj/item/clothing/head/culthood) && user.try_unequip(O)) + user.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head_str) + O = user.get_equipped_item(slot_wear_suit_str) + if(O && !istype(O, /obj/item/clothing/suit/cultrobes) && user.try_unequip(O)) + user.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit_str) + O = user.get_equipped_item(slot_shoes_str) + if(O && !istype(O, /obj/item/clothing/shoes/cult) && user.try_unequip(O)) + user.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(user), slot_shoes_str) + + O = user.get_equipped_item(slot_back_str) + if(O.storage && !istype(O, /obj/item/backpack/cultpack) && user.try_unequip(O)) + var/obj/item/backpack/cultpack/C = new /obj/item/backpack/cultpack(user) + user.equip_to_slot_or_del(C, slot_back_str) + if(C) + for(var/obj/item/thing in O) + thing.forceMove(C) + else if(!O) + var/obj/item/backpack/cultpack/C = new /obj/item/backpack/cultpack(user) + user.equip_to_slot_or_del(C, slot_back_str) + + user.update_icon() + + qdel(src) + +/obj/effect/rune/offering + cultname = "offering" + strokes = 3 + var/mob/living/victim + +/obj/effect/rune/offering/cast(var/mob/living/user) + var/list/mob/living/cultists = get_cultists() + if(victim) + to_chat(user, SPAN_WARNING("You are already sarcificing \the [victim] on this rune.")) + return + if(cultists.len < 3) + to_chat(user, SPAN_WARNING("You need three cultists around this rune to make it work.")) + return fizzle(user) + var/turf/T = get_turf(src) + for(var/mob/living/M in T) + if(M.stat != DEAD && !iscultist(M)) + victim = M + break + if(!victim) + return fizzle(user) + + for(var/mob/living/M in cultists) + M.say("Barhah hra zar[pick("'","`")]garis!") + + while(victim && victim.loc == T && victim.stat != DEAD) + var/list/mob/living/casters = get_cultists() + if(casters.len < 3) + break + victim.set_fire_intensity(max(2, victim.get_fire_intensity())) + victim.ignite_fire() + var/dam_amt = 2 + length(casters) + victim.take_organ_damage(dam_amt, dam_amt) // This is to speed up the process and also damage mobs that don't take damage from being on fire, e.g. borgs + if(ishuman(victim)) + var/mob/living/human/H = victim + if(H.is_asystole()) + H.take_damage(2 + casters.len, BRAIN) + sleep(40) + if(victim && victim.loc == T && victim.stat == DEAD) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.add_cultiness(CULTINESS_PER_SACRIFICE) + var/obj/item/soulstone/full/F = new(get_turf(src)) + for(var/mob/M in cultists | get_cultists()) + to_chat(M, SPAN_WARNING("The Geometer of Blood accepts this offering.")) + visible_message(SPAN_NOTICE("\The [F] appears over \the [src].")) + cult.sacrificed += victim.mind + if(victim.mind == cult.sacrifice_target) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, SPAN_OCCULT("Your objective is now complete.")) + to_chat(victim, SPAN_OCCULT("The Geometer of Blood claims your body.")) + victim.dust() + if(victim) + victim.extinguish_fire() // Technically allows them to put the fire out by sacrificing them and stopping immediately, but I don't think it'd have much effect + victim = null + +/obj/effect/rune/drain + cultname = "blood drain" + strokes = 3 + +/obj/effect/rune/drain/cast(var/mob/living/user) + var/mob/living/human/victim + for(var/mob/living/human/M in get_turf(src)) + if(iscultist(M)) + continue + victim = M + if(!victim) + return fizzle(user) + if(REAGENT_TOTAL_VOLUME(victim.vessel) < 20) + to_chat(user, SPAN_WARNING("This body has no blood in it.")) + return fizzle(user) + victim.vessel.remove_any(20) + admin_attack_log(user, victim, "Used a blood drain rune.", "Was victim of a blood drain rune.", "used a blood drain rune on") + speak_incantation(user, "Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!") + user.visible_message(SPAN_WARNING("Blood flows from \the [src] into \the [user]!"), SPAN_OCCULT("The blood starts flowing from \the [src] into your frail mortal body. [capitalize(english_list(heal_user(user), nothing_text = "you feel no different"))]."), "You hear liquid flow.") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + +/obj/effect/rune/drain/proc/heal_user(var/mob/living/human/user) + if(!istype(user)) + return list("you feel no different") + var/list/statuses = list() + var/charges = 20 + var/use + use = min(charges, user.species.blood_volume - REAGENT_TOTAL_VOLUME(user.vessel)) + if(use > 0) + user.adjust_blood(use) + charges -= use + statuses += "you regain lost blood" + if(!charges) + return statuses + if(user.get_damage(BRUTE) || user.get_damage(BURN)) + var/healbrute = user.get_damage(BRUTE) + var/healburn = user.get_damage(BURN) + if(healbrute < healburn) + healbrute = min(healbrute, charges / 2) + charges -= healbrute + healburn = min(healburn, charges) + charges -= healburn + else + healburn = min(healburn, charges / 2) + charges -= healburn + healbrute = min(healbrute, charges) + charges -= healbrute + user.heal_organ_damage(healbrute, healburn, 1) + statuses += "your wounds mend" + if(!charges) + return statuses + if(user.get_damage(TOX)) + use = min(user.get_damage(TOX), charges) + user.heal_damage(TOX, use) + charges -= use + statuses += "your body stings less" + if(!charges) + return statuses + if(charges >= 15) + for(var/obj/item/organ/external/e in user.get_external_organs()) + if(e && e.status & ORGAN_BROKEN) + e.mend_fracture() + statuses += "bones in your [e.name] snap into place" + charges -= 15 + if(charges < 15) + break + if(!charges) + return statuses + var/list/obj/item/organ/damaged = list() + for(var/obj/item/organ/internal/organ in user.internal_organs) + if(organ.get_organ_damage()) + damaged += organ + if(damaged.len) + statuses += "you feel pain inside for a moment that passes quickly" + while(charges && damaged.len) + var/obj/item/organ/internal/fix = pick(damaged) + fix.adjust_organ_damage(-(min(charges, 1))) + charges = max(charges - 1, 0) + if(fix.get_organ_damage() <= 0) + damaged -= fix + return statuses + +/obj/effect/rune/emp + cultname = "emp" + strokes = 4 + +/obj/effect/rune/emp/cast(var/mob/living/user) + empulse(get_turf(src), 4, 2, 1) + speak_incantation(user, "Ta'gh fara[pick("'","`")]qha fel d'amar det!") + qdel(src) + +/obj/effect/rune/massdefile //Defile but with a huge range. Bring a buddy for this, you're hitting the floor. + cultname = "mass defile" + +/obj/effect/rune/massdefile/cast(var/mob/living/user) + var/list/mob/living/cultists = get_cultists() + if(cultists.len < 3) + to_chat(user, SPAN_WARNING("You need three cultists around this rune to make it work.")) + return fizzle(user) + else + for(var/mob/living/M in cultists) + M.say("Ia! Ia! Zasan therium viortia! Razan gilamrua kioha!") + for(var/turf/T in range(5, src)) + if(is_holy_turf(T)) + T.turf_flags &= ~TURF_FLAG_HOLY + else + T.on_defilement() + visible_message(SPAN_WARNING("\The [src] embeds into the floor and walls around it, changing them!"), "You hear liquid flow.") + qdel(src) + +/* Tier 3 runes */ + +/obj/effect/rune/weapon + cultname = "summon weapon" + strokes = 4 + +/obj/effect/rune/weapon/cast(var/mob/living/user) + if(!istype(user.get_equipped_item(slot_head_str), /obj/item/clothing/head/culthood) || !istype(user.get_equipped_item(slot_wear_suit_str), /obj/item/clothing/suit/cultrobes) || !istype(user.get_equipped_item(slot_shoes_str), /obj/item/clothing/shoes/cult)) + to_chat(user, SPAN_WARNING("You need to be wearing your robes to use this rune.")) + return fizzle(user) + var/turf/T = get_turf(src) + if(!T.is_defiled()) + to_chat(user, SPAN_WARNING("This rune needs to be placed on the defiled ground.")) + return fizzle(user) + speak_incantation(user, "N'ath reth sh'yro eth d[pick("'","`")]raggathnor!") + user.put_in_hands(new /obj/item/sword/cultblade(user)) + qdel(src) + +/obj/effect/rune/shell + cultname = "summon shell" + strokes = 4 + +/obj/effect/rune/shell/cast(var/mob/living/user) + var/turf/T = get_turf(src) + if(!T.is_defiled()) + to_chat(user, SPAN_WARNING("This rune needs to be placed on the defiled ground.")) + return fizzle(user) + + var/obj/item/stack/material/target + for(var/obj/item/stack/material/S in get_turf(src)) + if(S.material?.type == /decl/material/solid/metal/steel && S.get_amount() >= 10) + target = S + break + + if(!target) + to_chat(user, SPAN_WARNING("You need ten sheets of steel to fold them into a construct shell.")) + return fizzle(user) + + speak_incantation(user, "Da A[pick("'","`")]ig Osk!") + target.use(10) + var/obj/O = new /obj/structure/constructshell/cult(get_turf(src)) + visible_message(SPAN_WARNING("The metal bends into \the [O], and \the [src] imbues into it."), "You hear a metallic sound.") + qdel(src) + +/obj/effect/rune/confuse + cultname = "confuse" + strokes = 4 + +/obj/effect/rune/confuse/cast(var/mob/living/user) + speak_incantation(user, "Fuu ma[pick("'","`")]jin!") + visible_message(SPAN_DANGER("\The [src] explodes in a bright flash.")) + var/list/mob/affected = list() + for(var/mob/living/M in viewers(src)) + if(iscultist(M)) + continue + var/obj/item/nullrod/N = locate() in M + if(N) + continue + affected |= M + if(issilicon(M)) + SET_STATUS_MAX(M, STAT_WEAK, 10) + else + SET_STATUS_MAX(M, STAT_BLURRY, 50) + SET_STATUS_MAX(M, STAT_WEAK, 3) + SET_STATUS_MAX(M, STAT_STUN, 5) + + admin_attacker_log_many_victims(user, affected, "Used a confuse rune.", "Was victim of a confuse rune.", "used a confuse rune on") + qdel(src) + +/obj/effect/rune/revive + cultname = "revive" + strokes = 4 + +/obj/effect/rune/revive/cast(var/mob/living/user) + var/mob/living/human/target + var/obj/item/soulstone/source + for(var/mob/living/human/M in get_turf(src)) + if(M.stat == DEAD) + if(iscultist(M)) + if(M.key) + target = M + break + if(!target) + return fizzle(user) + for(var/obj/item/soulstone/S in get_turf(src)) + if(S.full && !S.shade.key) + source = S + break + if(!source) + return fizzle(user) + target.rejuvenate() + source.set_full(0) + speak_incantation(user, "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!") + + var/decl/pronouns/pronouns = target.get_pronouns() + target.visible_message( \ + SPAN_OCCULT("\The [target]'s eyes glow with a faint red as [pronouns.he] stand[pronouns.s] up, slowly starting to breathe again."), \ + SPAN_OCCULT("Life... I'm alive again..."), \ + "You hear a flowing liquid.") + +/obj/effect/rune/blood_boil + cultname = "blood boil" + strokes = 4 + +/obj/effect/rune/blood_boil/cast(var/mob/living/user) + var/list/mob/living/cultists = get_cultists() + if(cultists.len < 3) + return fizzle() + + for(var/mob/living/M in cultists) + M.say("Dedo ol[pick("'","`")]btoh!") + + var/list/mob/living/previous = list() + var/list/mob/living/current = list() + while(cultists.len >= 3) + cultists = get_cultists() + for(var/mob/living/M in viewers(src)) + if(iscultist(M)) + continue + current |= M + var/obj/item/nullrod/N = locate() in M + if(N) + continue + M.take_overall_damage(5, 5) + if(!(M in previous)) + if(M.should_have_organ(BP_HEART)) + to_chat(M, SPAN_DANGER("Your blood boils!")) + else + to_chat(M, SPAN_DANGER("You feel searing heat inside!")) + previous = current.Copy() + current.Cut() + sleep(10) + +/* Tier NarNar runes */ + +/obj/effect/rune/tearreality + cultname = "tear reality" + var/the_end_comes = 0 + var/the_time_has_come = 300 + var/obj/effect/narsie/summoning_entity = null + strokes = 9 + +/obj/effect/rune/tearreality/cast(var/mob/living/user) + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + if(!cult.allow_narsie) + return + if(the_end_comes) + to_chat(user, SPAN_OCCULT("You are already summoning! Be patient!")) + return + var/list/mob/living/cultists = get_cultists() + if(cultists.len < 5) + return fizzle() + for(var/mob/living/M in cultists) + M.say("Tok-lyr rqa'nap g[pick("'","`")]lt-ulotf!") + to_chat(M, SPAN_OCCULT("You are starting to tear through the veil, opening the way to bring Him back... stay around the rune!")) + log_and_message_admins_many(cultists, "started summoning Nar-sie.") + + var/area/A = get_area(src) + command_announcement.Announce("High levels of gravitational disruption detected at \the [A.proper_name]. Suspected wormhole forming. Investigate it immediately.") + while(cultists.len > 4 || the_end_comes) + cultists = get_cultists() + if(cultists.len > 8) + ++the_end_comes + if(cultists.len > 4) + ++the_end_comes + else + --the_end_comes + if(the_end_comes >= the_time_has_come) + break + for(var/mob/living/M in cultists) + if(prob(5)) + M.say(pick("Hakkrutju gopoenjim.", "Nherasai pivroiashan.", "Firjji prhiv mazenhor.", "Tanah eh wakantahe.", "Obliyae na oraie.", "Miyf hon vnor'c.", "Wakabai hij fen juswix.")) + + for(var/turf/T in range(min(the_end_comes, 15))) + if(prob(the_end_comes / 3)) + T.on_defilement() + sleep(10) + + if(the_end_comes >= the_time_has_come) + summoning_entity = new /obj/effect/narsie(get_turf(src)) + else + command_announcement.Announce("Gravitational anomaly has ceased.") + qdel(src) + +/obj/effect/rune/tearreality/attack_hand(var/mob/user) + SHOULD_CALL_PARENT(FALSE) + if(!summoning_entity || iscultist(user)) + return FALSE + var/input = input(user, "Are you SURE you want to sacrifice yourself?", "DO NOT DO THIS") in list("Yes", "No") + if(input != "Yes") + return TRUE + speak_incantation(user, "Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!") + to_chat(user, SPAN_WARNING("In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.")) + for(var/mob/M in global.living_mob_list_) + var/decl/pronouns/pronouns = user.get_pronouns() + if(iscultist(M)) + to_chat(M, "You see a vision of \the [user] keeling over dead, [pronouns.his] blood glowing blue as it escapes [pronouns.his] body and dissipates into thin air; you hear an otherwordly scream and feel that a great disaster has just been averted.") + else + to_chat(M, "You see a vision of [name] keeling over dead, [pronouns.his] blood glowing blue as it escapes [pronouns.his] body and dissipates into thin air; you hear an otherwordly scream and feel very weak for a moment.") + log_and_message_admins("mended reality with the greatest sacrifice", user) + user.dust() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.powerless = 1 + qdel(summoning_entity) + qdel(src) + return TRUE + +/obj/effect/rune/tearreality/attackby() + if(the_end_comes) + return TRUE + return ..() + +/* Imbue runes */ + +/obj/effect/rune/imbue + cultname = "otherwordly abomination that shouldn't exist and that you should report to your local god as soon as you see it, along with the instructions for making this" + var/papertype + +/obj/effect/rune/imbue/cast(var/mob/living/user) + var/obj/item/paper/target + var/tainted = 0 + for(var/obj/item/paper/P in get_turf(src)) + if(!P.info) + target = P + break + else + tainted = 1 + if(!target) + if(tainted) + to_chat(user, SPAN_WARNING("The blank is tainted. It is unsuitable.")) + return fizzle(user) + speak_incantation(user, "H'drak v[pick("'","`")]loso, mir'kanas verbot!") + visible_message(SPAN_WARNING("The rune forms into an arcane image on the paper.")) + new papertype(get_turf(src)) + qdel(target) + qdel(src) + +/obj/effect/rune/imbue/stun + cultname = "stun imbue" + papertype = /obj/item/paper/talisman/stun + +/obj/effect/rune/imbue/emp + cultname = "destroy technology imbue" + papertype = /obj/item/paper/talisman/emp diff --git a/mods/gamemodes/cult/special_role.dm b/mods/gamemodes/cult/special_role.dm new file mode 100644 index 000000000000..4f25ddeb6d20 --- /dev/null +++ b/mods/gamemodes/cult/special_role.dm @@ -0,0 +1,163 @@ +/proc/iscultist(var/mob/player) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + if(player.mind && (player.mind in cult.current_antagonists)) + return TRUE + return FALSE + +/decl/special_role/cultist + name = "Cultist" + name_plural = "Cultists" + blacklisted_jobs = list(/datum/job/submap) + antag_indicator = "hudcultist" + welcome_text = "You have a tome in your possession; one that will help you start the cult. Use it well and remember - there are others." + flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + hard_cap = 5 + hard_cap_round = 6 + initial_spawn_req = 4 + initial_spawn_target = 6 + antaghud_indicator = "hudcultist" + skill_setter = /datum/antag_skill_setter/station + faction = "cult" + blocked_job_event_categories = list(ASSIGNMENT_ROBOT, ASSIGNMENT_COMPUTER) + + var/allow_narsie = 1 + var/powerless = 0 + var/datum/mind/sacrifice_target + var/list/obj/effect/rune/teleport/teleport_runes = list() + var/list/rune_strokes = list() + var/list/sacrificed = list() + var/cult_rating = 0 + var/list/cult_rating_bounds = list(CULT_RUNES_1, CULT_RUNES_2, CULT_RUNES_3, CULT_GHOSTS_1, CULT_GHOSTS_2, CULT_GHOSTS_3) + var/max_cult_rating = 0 + var/conversion_blurb = "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back." + var/list/paper_spawn_slots = list ( + "backpack" = slot_in_backpack_str, + "left pocket" = slot_l_store_str, + "right pocket" = slot_r_store_str, + "left hand" = BP_L_HAND, + "right hand" = BP_R_HAND, + ) + +/decl/special_role/cultist/create_global_objectives() + + if(!..()) + return + + global_objectives = list() + if(prob(50)) + global_objectives |= new /datum/objective/cult/survive + else + global_objectives |= new /datum/objective/cult/eldergod + + var/datum/objective/cult/sacrifice/sacrifice = new() + sacrifice.find_target() + sacrifice_target = sacrifice.target + global_objectives |= sacrifice + +/decl/special_role/cultist/equip_role(var/mob/living/human/player) + . = ..() + if(.) + var/obj/item/book/tome/T = new(get_turf(player)) + for(var/slot in paper_spawn_slots) + player.equip_to_slot(T, slot) + if(T.loc == player) + return + for(var/atom/thing in player.get_mob_contents()) + if(thing.storage) + T.forceMove(thing) + break + +/decl/special_role/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + if(!..()) + return 0 + to_chat(player.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the dark-one and the memories of your time as his servant with it.") + player.ClearMemories(type) + if(show_message) + player.current.visible_message("[player.current] looks like they just reverted to their old faith!") + remove_cult_magic(player.current) + remove_cultiness(CULTINESS_PER_CULTIST) + +/decl/special_role/cultist/add_antagonist(var/datum/mind/player, var/ignore_role, var/do_not_equip, var/move_to_spawn, var/do_not_announce, var/preserve_appearance) + . = ..() + if(.) + to_chat(player, "[conversion_blurb]") + if(player.current && !isconstruct(player.current)) + player.current.add_language(/decl/language/cultcommon) + +/decl/special_role/cultist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted) + . = ..() + if(. && player.current && !isconstruct(player.current)) + player.current.remove_language(/decl/language/cultcommon) + +/decl/special_role/cultist/update_antag_mob(var/datum/mind/player) + . = ..() + add_cultiness(CULTINESS_PER_CULTIST) + add_cult_magic(player.current) + +/decl/special_role/cultist/proc/add_cultiness(var/amount) + cult_rating += amount + var/old_rating = max_cult_rating + max_cult_rating = max(max_cult_rating, cult_rating) + if(old_rating >= CULT_MAX_CULTINESS) + return + var/list/to_update = list() + for(var/i in cult_rating_bounds) + if((old_rating < i) && (max_cult_rating >= i)) + to_update += i + + if(to_update.len) + update_cult_magic(to_update) + +/decl/special_role/cultist/proc/update_cult_magic(var/list/to_update) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + if(CULT_RUNES_1 in to_update) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "The veil between this world and beyond grows thin, and your power grows.") + add_cult_magic(H.current) + if(CULT_RUNES_2 in to_update) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "You feel that the fabric of reality is tearing.") + add_cult_magic(H.current) + if(CULT_RUNES_3 in to_update) + for(var/datum/mind/H in cult.current_antagonists) + if(H.current) + to_chat(H.current, "The world is at end. The veil is as thin as ever.") + add_cult_magic(H.current) + + if((CULT_GHOSTS_1 in to_update) || (CULT_GHOSTS_2 in to_update) || (CULT_GHOSTS_3 in to_update)) + for(var/mob/observer/ghost/D in SSmobs.mob_list) + add_ghost_magic(D) + +/decl/special_role/cultist/proc/offer_uncult(var/mob/M) + if(!iscultist(M) || !M.mind) + return + + to_chat(M, "Do you want to abandon the cult of Nar'Sie? ACCEPT") + +/decl/special_role/cultist/Topic(href, href_list) + if(href_list["confirmleave"]) + var/decl/special_role/cult = GET_DECL(/decl/special_role/cultist) + cult.remove_antagonist(usr.mind, 1) + +/decl/special_role/cultist/proc/remove_cultiness(var/amount) + cult_rating = max(0, cult_rating - amount) + +/decl/special_role/cultist/proc/add_cult_magic(var/mob/M) + M.verbs += Tier1Runes + + if(max_cult_rating >= CULT_RUNES_1) + M.verbs += Tier2Runes + + if(max_cult_rating >= CULT_RUNES_2) + M.verbs += Tier3Runes + + if(max_cult_rating >= CULT_RUNES_3) + M.verbs += Tier4Runes + +/decl/special_role/cultist/proc/remove_cult_magic(var/mob/M) + M.verbs -= Tier1Runes + M.verbs -= Tier2Runes + M.verbs -= Tier3Runes + M.verbs -= Tier4Runes diff --git a/mods/gamemodes/cult/structures.dm b/mods/gamemodes/cult/structures.dm new file mode 100644 index 000000000000..d2cd63b3cc1d --- /dev/null +++ b/mods/gamemodes/cult/structures.dm @@ -0,0 +1,124 @@ +/obj/structure/cult + density = TRUE + anchored = TRUE + icon = 'icons/obj/cult.dmi' + +/obj/structure/cult/forge + name = "\improper Daemon forge" + desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie." + icon_state = "forge" + +/obj/structure/cult/pylon + name = "pylon" + desc = "A floating crystal that hums with an unearthly energy." + icon = 'icons/obj/structures/pylon.dmi' + icon_state = "pylon" + light_power = 0.5 + light_range = 13 + light_color = "#3e0000" + var/isbroken = FALSE + +/obj/structure/cult/pylon/attack_hand(mob/M) + SHOULD_CALL_PARENT(FALSE) + attackpylon(M, 5) + return TRUE + +/obj/structure/cult/pylon/attack_generic(var/mob/user, var/damage) + attackpylon(user, damage) + return TRUE + +/obj/structure/cult/pylon/attackby(obj/item/used_item, mob/user) + attackpylon(user, used_item.expend_attack_force(user)) + return TRUE + +/obj/structure/cult/pylon/proc/attackpylon(mob/user, var/damage) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!isbroken) + if(prob(1+ damage * 5)) + user.visible_message( + "[user] smashed the pylon!", + "You hit the pylon, and its crystal breaks apart!", + "You hear a tinkle of crystal shards." + ) + user.do_attack_animation(src) + playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1) + isbroken = TRUE + set_density(0) + icon_state = "pylon-broken" + set_light(0) + else + to_chat(user, "You hit the pylon!") + playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) + else + if(prob(damage * 2)) + to_chat(user, "You pulverize what was left of the pylon!") + qdel(src) + else + to_chat(user, "You hit the pylon!") + playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1) + + +/obj/structure/cult/pylon/proc/repair(mob/user) + if(isbroken) + to_chat(user, "You repair the pylon.") + isbroken = FALSE + set_density(1) + icon_state = "pylon" + set_light(13, 0.5) + return TRUE + return FALSE + +/obj/structure/cult/pylon/get_artifact_scan_data() + return "Tribal pylon - subject resembles statues/emblems built by cargo cult civilisations to honour energy systems from post-warp civilisations." + +/obj/structure/cult/tome + name = "desk" + desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl." + icon_state = "tomealtar" + +//sprites for this no longer exist -Pete +//(they were stolen from another game anyway) +/* +/obj/structure/cult/pillar + name = "Pillar" + desc = "This should not exist." + icon_state = "pillar" + icon = 'magic_pillar.dmi' +*/ + +/obj/effect/gateway/active/cult + light_range=5 + light_color="#ff0000" + spawnable=list( + /mob/living/simple_animal/hostile/scarybat/cult, + /mob/living/simple_animal/hostile/creature/cult, + /mob/living/simple_animal/hostile/revenant/cult + ) + +/obj/structure/door/cult + material = /decl/material/solid/stone/cult + +/obj/structure/girder/cult + icon= 'icons/obj/cult.dmi' + icon_state= "cultgirder" + max_health = 150 + cover = 70 + +/obj/structure/girder/cult/dismantle_structure(mob/user) + material = null + reinf_material = null + parts_type = null + . = ..() + +/obj/structure/grille/cult + name = "cult grille" + desc = "A matrix built out of an unknown material, with some sort of force field blocking air around it." + material = /decl/material/solid/stone/cult + +/obj/structure/grille/cult/CanPass(atom/movable/mover, turf/target, height = 1.5, air_group = 0) + if(air_group) + return 0 //Make sure air doesn't drain + ..() + +/obj/structure/talisman_altar + desc = "A bloodstained altar dedicated to Nar-Sie." \ No newline at end of file diff --git a/mods/gamemodes/cult/talisman.dm b/mods/gamemodes/cult/talisman.dm new file mode 100644 index 000000000000..8b99fa798237 --- /dev/null +++ b/mods/gamemodes/cult/talisman.dm @@ -0,0 +1,65 @@ +/obj/item/paper/talisman + info = "


    " + +/obj/item/paper/talisman/update_contents_overlays() + var/talisman_state = "[icon_state]-talisman" + if(check_state_in_icon(talisman_state, icon)) + add_overlay(overlay_image(icon, talisman_state, flags = RESET_COLOR)) + +/obj/item/paper/talisman/attack_self(var/mob/user) + if(iscultist(user)) + to_chat(user, "Attack your target to use this talisman.") + else + to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?") + +/obj/item/paper/talisman/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + return FALSE + +/obj/item/paper/talisman/stun/attack_self(var/mob/user) + if(iscultist(user)) + to_chat(user, "This is a stun talisman.") + return ..() + +/obj/item/paper/talisman/stun/use_on_mob(mob/living/target, mob/living/user, animate = TRUE) + + if(!iscultist(user)) + return FALSE + + user.say("Dream Sign: Evil Sealing Talisman!") //TODO: never change this shit + var/obj/item/nullrod/nrod = locate() in target + if(nrod) + user.visible_message( + SPAN_DANGER("\The [user] invokes \the [src] at [target], but they are unaffected."), + SPAN_DANGER("You invoke \the [src] at [target], but they are unaffected.") + ) + return TRUE + + user.visible_message(SPAN_DANGER("\The [user] invokes \the [src] at [target]."), SPAN_DANGER("You invoke \the [src] at [target].")) + if(isliving(target)) + if(issilicon(target)) + SET_STATUS_MAX(target, STAT_WEAK, 15) + SET_STATUS_MAX(target, STAT_SILENCE, 15) + else + SET_STATUS_MAX(target, STAT_WEAK, 20) + SET_STATUS_MAX(target, STAT_STUN, 20) + SET_STATUS_MAX(target, STAT_SILENCE, 20) + admin_attack_log(user, target, "Used a stun talisman.", "Was victim of a stun talisman.", "used a stun talisman on") + user.try_unequip(src) + qdel(src) + return TRUE + +/obj/item/paper/talisman/emp/attack_self(var/mob/user) + if(iscultist(user)) + to_chat(user, "This is an emp talisman.") + ..() + +/obj/item/paper/talisman/emp/afterattack(var/atom/target, var/mob/user, var/proximity) + if(!iscultist(user)) + return + if(!proximity) + return + user.say("Ta'gh fara[pick("'","`")]qha fel d'amar det!") + user.visible_message(SPAN_DANGER("\The [user] invokes \the [src] at [target]."), SPAN_DANGER("You invoke \the [src] at [target].")) + target.emp_act(1) + user.try_unequip(src) + qdel(src) diff --git a/mods/gamemodes/heist/_heist.dm b/mods/gamemodes/heist/_heist.dm new file mode 100644 index 000000000000..4183fc91a90c --- /dev/null +++ b/mods/gamemodes/heist/_heist.dm @@ -0,0 +1,2 @@ +/decl/modpack/heist + name = "Heist Gamemode" \ No newline at end of file diff --git a/mods/gamemodes/heist/_heist.dme b/mods/gamemodes/heist/_heist.dme new file mode 100644 index 000000000000..de2a67d69d3c --- /dev/null +++ b/mods/gamemodes/heist/_heist.dme @@ -0,0 +1,13 @@ +#ifndef GAMEMODE_PACK_HEIST +#define GAMEMODE_PACK_HEIST +// BEGIN_INCLUDE +#include "_heist.dm" +#include "areas.dm" +#include "gamemode.dm" +#include "heist_base.dm" +#include "outfit.dm" +#include "presets.dm" +#include "shuttle.dm" +#include "special_role.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/heist/areas.dm b/mods/gamemodes/heist/areas.dm new file mode 100644 index 000000000000..22c772cc3108 --- /dev/null +++ b/mods/gamemodes/heist/areas.dm @@ -0,0 +1,18 @@ +//Areas +/area/map_template/skipjack_station + name = "Raider Outpost" + icon_state = "yellow" + requires_power = 0 + req_access = list(access_raider) + +/area/map_template/skipjack_station/start + name = "\improper Skipjack" + icon_state = "yellow" + req_access = list(access_raider) + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED + +/area/map_template/syndicate_mothership/raider_base + name = "\improper Raider Base" + requires_power = 0 + dynamic_lighting = FALSE + req_access = list(access_raider) \ No newline at end of file diff --git a/mods/gamemodes/heist/gamemode.dm b/mods/gamemodes/heist/gamemode.dm new file mode 100644 index 000000000000..34494789acf9 --- /dev/null +++ b/mods/gamemodes/heist/gamemode.dm @@ -0,0 +1,9 @@ +/decl/game_mode/heist + name = "Heist" + uid = "heist" + required_players = 12 + required_enemies = 3 + round_description = "An unidentified drive signature has slipped into close sensor range and is approaching!" + extended_round_description = "Piratical raiders are on their way to steal the station goods, and possibly the crew!" + end_on_antag_death = FALSE + associated_antags = list(/decl/special_role/raider) diff --git a/mods/gamemodes/heist/heist_base.dm b/mods/gamemodes/heist/heist_base.dm new file mode 100644 index 000000000000..20c8c18d2a6c --- /dev/null +++ b/mods/gamemodes/heist/heist_base.dm @@ -0,0 +1,12 @@ +/datum/map_template/ruin/antag_spawn/heist + name = "Heist Base" + prefix = null + mappaths = list( + "mods/gamemodes/heist/heist_base.dmm" + ) + modify_tag_vars = FALSE + shuttles_to_initialise = list(/datum/shuttle/autodock/multi/antag/skipjack) + apc_test_exempt_areas = list( + /area/map_template/skipjack_station = NO_SCRUBBER|NO_VENT|NO_APC, + /area/map_template/syndicate_mothership/raider_base = NO_SCRUBBER|NO_VENT|NO_APC + ) diff --git a/mods/gamemodes/heist/heist_base.dmm b/mods/gamemodes/heist/heist_base.dmm new file mode 100644 index 000000000000..3f7117a81647 --- /dev/null +++ b/mods/gamemodes/heist/heist_base.dmm @@ -0,0 +1,6603 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/space, +/area/space) +"ab" = ( +/turf/wall/natural, +/area/space) +"ac" = ( +/turf/unsimulated/mineral, +/area/space) +"ad" = ( +/turf/unsimulated/wall, +/area/space) +"ae" = ( +/turf/unsimulated/wall, +/area/map_template/syndicate_mothership/raider_base) +"af" = ( +/obj/random/junk, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"ag" = ( +/obj/structure/closet/secure_closet/freezer/kitchen, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"ah" = ( +/obj/structure/table/reinforced, +/obj/item/plate/tray{ + pixel_y = 5 + }, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"ai" = ( +/obj/structure/table, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"aj" = ( +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"ak" = ( +/obj/structure/closet/secure_closet/freezer/fridge, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"al" = ( +/obj/random/trash, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"am" = ( +/obj/structure/table, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"an" = ( +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"ao" = ( +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"ap" = ( +/obj/structure/table/reinforced, +/obj/machinery/microwave{ + pixel_x = -1; + pixel_y = 8 + }, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"aq" = ( +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"ar" = ( +/obj/machinery/door/airlock/hatch{ + name = "\improper NO DUST BREATHER ALLOWED" + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"as" = ( +/obj/machinery/vending/snack{ + markup = 0 + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"at" = ( +/obj/structure/meat_hook, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"au" = ( +/obj/vehicle/bike/thermal, +/obj/random/trash, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"av" = ( +/obj/vehicle/bike/thermal, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"aw" = ( +/obj/random/trash, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"ax" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"ay" = ( +/obj/random/junk, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"az" = ( +/obj/random/trash, +/obj/item/chems/glass/bucket, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"aA" = ( +/obj/abstract/modpack_compat/aliumizer, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"aB" = ( +/obj/random/coin, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"aC" = ( +/turf/wall/natural, +/area/map_template/syndicate_mothership/raider_base) +"aD" = ( +/obj/machinery/door/airlock/hatch, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"aE" = ( +/obj/effect/decal/cleanable/blood, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"aF" = ( +/obj/machinery/gibber, +/turf/unsimulated/floor/white, +/area/map_template/syndicate_mothership/raider_base) +"aG" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"aH" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/obj/item/soap, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"aI" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"aJ" = ( +/obj/structure/hygiene/urinal{ + pixel_y = 32 + }, +/obj/random/trash, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"aK" = ( +/obj/structure/bed, +/obj/effect/decal/cleanable/dirt/visible, +/obj/structure/sign/painting/monkey_painting{ + pixel_x = -28; + pixel_y = 4 + }, +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/obj/effect/floor_decal/carpet{ + dir = 9 + }, +/obj/item/bedsheet/green, +/obj/structure/curtain/open/bed, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aL" = ( +/obj/abstract/landmark{ + name = "raiderstart" + }, +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aM" = ( +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aN" = ( +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/obj/random/trash, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aO" = ( +/obj/structure/bed, +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/obj/effect/floor_decal/carpet{ + dir = 5 + }, +/obj/item/bedsheet/rd, +/obj/structure/curtain/open/bed, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aP" = ( +/obj/machinery/door/airlock/hatch, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"aQ" = ( +/obj/random/junk, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"aR" = ( +/obj/random/loot, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"aS" = ( +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"aT" = ( +/obj/effect/decal/cleanable/blood, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"aU" = ( +/obj/machinery/door/airlock/hatch{ + name = "\improper LITTLE VOX ROOM" + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"aV" = ( +/obj/item/radio/intercom{ + dir = 8; + pixel_x = 22 + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"aW" = ( +/obj/structure/bed, +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/item/bedsheet/hos, +/obj/structure/curtain/open/bed, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aX" = ( +/obj/abstract/landmark{ + name = "raiderstart" + }, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aY" = ( +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"aZ" = ( +/obj/structure/bed, +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/item/bedsheet/rainbow, +/obj/structure/curtain/open/bed, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"ba" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"bb" = ( +/obj/structure/bed, +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/item/bedsheet/clown, +/obj/structure/curtain/open/bed, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bc" = ( +/obj/structure/bed, +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/item/bedsheet/orange, +/obj/structure/curtain/open/bed, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bd" = ( +/obj/effect/decal/cleanable/cobweb, +/obj/machinery/fabricator/hacked, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"be" = ( +/obj/structure/closet/crate, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bf" = ( +/obj/effect/decal/cleanable/dirt/visible, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bg" = ( +/obj/structure/sign/warning/nosmoking_1/heist{ + pixel_y = 32 + }, +/obj/item/box/fancy/cigarettes/dromedaryco, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bh" = ( +/obj/effect/decal/cleanable/blood/oil, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bi" = ( +/obj/effect/decal/cleanable/cobweb2{ + icon_state = "spiderling"; + name = "dead spider" + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bj" = ( +/obj/item/clothing/head/xenos, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"bk" = ( +/obj/random/trash, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"bl" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/structure/mirror{ + dir = 4; + pixel_x = -28 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"bm" = ( +/obj/structure/hygiene/shower{ + dir = 1 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bn" = ( +/obj/structure/hygiene/shower{ + dir = 1 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/syndicate_mothership/raider_base) +"bo" = ( +/obj/structure/table/laminate, +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/random/junk, +/obj/random/maintenance, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bp" = ( +/obj/structure/table/laminate, +/obj/random/action_figure, +/obj/random/contraband, +/obj/random/junk, +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bq" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"br" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"bs" = ( +/obj/effect/decal/cleanable/spiderling_remains, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bt" = ( +/obj/machinery/atmospherics/pipe/simple/visible{ + dir = 6 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bu" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/random/toolbox, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bv" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bw" = ( +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bx" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/nitrogen, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"by" = ( +/obj/item/clothing/mask/gas/swat{ + desc = "A close-fitting mask clearly not made for a human face."; + name = "\improper alien mask" + }, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"bC" = ( +/obj/effect/decal/cleanable/cobweb2{ + icon_state = "spiderling"; + name = "dead spider" + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"bD" = ( +/obj/item/radio/intercom{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/carpet, +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/effect/floor_decal/carpet{ + dir = 10 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bE" = ( +/obj/effect/floor_decal/carpet, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bF" = ( +/obj/structure/closet{ + name = "Clothing Storage" + }, +/obj/effect/floor_decal/carpet, +/obj/item/clothing/costume/lawyer, +/obj/item/clothing/costume/lawyer_bluesuit, +/obj/item/clothing/costume/mailman, +/obj/item/clothing/webbing, +/obj/item/clothing/costume/dispatch, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bG" = ( +/obj/structure/undies_wardrobe, +/obj/effect/floor_decal/carpet, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bH" = ( +/obj/random/junk, +/obj/effect/floor_decal/carpet, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bI" = ( +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/effect/floor_decal/carpet, +/obj/effect/floor_decal/carpet{ + dir = 6 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/syndicate_mothership/raider_base) +"bJ" = ( +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"bK" = ( +/turf/unsimulated/floor/laminate/broken, +/area/map_template/syndicate_mothership/raider_base) +"bL" = ( +/obj/structure/table/laminate, +/obj/item/plate/tray{ + pixel_y = 5 + }, +/obj/item/backpack, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"bM" = ( +/obj/structure/table/laminate, +/obj/item/box/glasses/rocks, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"bN" = ( +/obj/structure/table/laminate, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/unsimulated/floor/laminate/broken6, +/area/map_template/syndicate_mothership/raider_base) +"bO" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/washing_machine, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bP" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bQ" = ( +/obj/machinery/atmospherics/omni/mixer{ + tag_east = 1; + tag_east_con = 0.5; + tag_north = 1; + tag_north_con = 2; + tag_south = null; + tag_south_con = null; + tag_west = 1; + tag_west_con = 0.5; + use_power = 0 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bR" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt/visible, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bS" = ( +/obj/effect/decal/cleanable/dirt/visible, +/obj/effect/floor_decal/industrial/hatch/yellow, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/unsimulated/floor/plating, +/area/map_template/syndicate_mothership/raider_base) +"bT" = ( +/obj/item/pizzabox/meat, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"bU" = ( +/obj/structure/rack, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"bV" = ( +/obj/item/stool/padded, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"bW" = ( +/obj/effect/decal/cleanable/generic, +/obj/item/stool/padded, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"bZ" = ( +/obj/machinery/acting/changer, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"ca" = ( +/obj/structure/table/laminate, +/obj/item/pizzabox/meat, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"cb" = ( +/obj/structure/table/laminate, +/obj/item/ashtray, +/obj/item/trash/cigbutt/cigarbutt, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"cc" = ( +/obj/structure/table/laminate, +/obj/item/chems/rag, +/obj/random/loot, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"cd" = ( +/obj/machinery/vending/cigarette{ + name = "hacked cigarette machine"; + markup = 0; + products = list(/obj/item/box/fancy/cigarettes = 10, /obj/item/box/matches = 10, /obj/item/flame/fuelled/lighter/zippo/random = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2) + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"ce" = ( +/obj/item/tank/nitrogen, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"cf" = ( +/obj/item/backpack, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"cg" = ( +/obj/structure/sign/poster{ + pixel_y = -32 + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"ch" = ( +/turf/unsimulated/floor/laminate/broken1, +/area/map_template/syndicate_mothership/raider_base) +"ci" = ( +/obj/item/stool/padded, +/turf/unsimulated/floor/laminate/broken1, +/area/map_template/syndicate_mothership/raider_base) +"cj" = ( +/mob/living/simple_animal/hostile/parrot/pirate, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"ck" = ( +/obj/structure/grille, +/obj/structure/lattice, +/turf/space, +/area/space) +"cl" = ( +/obj/random/junk, +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"cm" = ( +/obj/item/radio/intercom{ + dir = 4; + pixel_x = -22 + }, +/obj/structure/flora/pottedplant{ + desc = "Used to bring the room together...before the accident."; + icon_state = "plant-25"; + name = "Jamie" + }, +/turf/unsimulated/floor/laminate, +/area/map_template/syndicate_mothership/raider_base) +"cn" = ( +/obj/structure/reagent_dispensers/beerkeg, +/turf/unsimulated/floor/laminate/broken1, +/area/map_template/syndicate_mothership/raider_base) +"co" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + id_tag = "skipjack_base"; + pixel_x = -25; + pixel_y = -5 + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"cp" = ( +/obj/structure/closet/crate, +/obj/item/tank/nitrogen, +/obj/item/tank/nitrogen, +/obj/item/tank/nitrogen, +/obj/item/tank/nitrogen, +/obj/item/tank/nitrogen, +/obj/item/tank/nitrogen, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"cq" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"cr" = ( +/obj/item/clothing/head/philosopher_wig, +/turf/unsimulated/floor/asteroid, +/area/map_template/syndicate_mothership/raider_base) +"cs" = ( +/obj/structure/lattice, +/turf/space, +/area/space) +"ct" = ( +/obj/machinery/door/airlock/external, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"cu" = ( +/obj/machinery/door/airlock/external{ + id_tag = "skipjack_base_hatch" + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"cv" = ( +/obj/item/trash/cheesie, +/turf/space, +/area/space) +"cw" = ( +/obj/effect/paint/black, +/turf/wall/raidershuttle, +/area/map_template/skipjack_station/start) +"cx" = ( +/obj/machinery/door/airlock/external{ + id_tag = "raider_northwest_lock" + }, +/obj/machinery/shield_diffuser, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cy" = ( +/obj/machinery/button/access/shuttle/exterior{ + id_tag = "raider_west_control"; + req_access = list("ACCESS_RAIDER") + }, +/obj/effect/paint/black, +/turf/wall/raidershuttle, +/area/map_template/skipjack_station/start) +"cz" = ( +/obj/machinery/door/blast/regular/open{ + id_tag = "SkipjackShuttersNorth"; + name = "Blast Doors" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/brown, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cA" = ( +/obj/machinery/door/airlock/external{ + id_tag = "skipjack_shuttle_outer"; + name = "Ship External Access" + }, +/obj/machinery/shield_diffuser, +/obj/effect/shuttle_landmark/skipjack/start, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cB" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + id_tag = "raider_west_vent" + }, +/obj/random/junk, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cC" = ( +/obj/machinery/airlock_sensor/shuttle{ + id_tag = "raider_west_sensor"; + pixel_x = 25; + dir = 8 + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cD" = ( +/obj/machinery/constructable_frame/computerframe, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cE" = ( +/obj/machinery/computer/shuttle_control/multi/raider, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cF" = ( +/obj/structure/table/steel, +/obj/random/plushie, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cG" = ( +/obj/random/trash, +/obj/machinery/airlock_sensor{ + id_tag = "skipjack_shuttle_sensor"; + pixel_x = 8; + pixel_y = 25 + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cH" = ( +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + id_tag = "merc_shuttle_pump" + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cI" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 8 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cJ" = ( +/obj/machinery/embedded_controller/radio/airlock/airlock_controller{ + frequency = 1331; + id_tag = "raider_west_control"; + pixel_x = 24; + tag_airpump = "raider_west_vent"; + tag_chamber_sensor = "raider_west_sensor"; + tag_exterior_door = "raider_northwest_lock"; + tag_interior_door = "raider_southwest_lock"; + dir = 8 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + dir = 8; + id_tag = "raider_west_vent" + }, +/obj/machinery/light/small, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cK" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/computer/station_alert/all{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cL" = ( +/obj/structure/chair/shuttle{ + dir = 8 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cM" = ( +/obj/machinery/button/blast_door{ + id_tag = "SkipjackShuttersNorth"; + name = "Skipjack North Shutters"; + pixel_y = 39 + }, +/obj/machinery/button/blast_door{ + id_tag = "SkipjackShuttersWest"; + name = "Skipjack West Shutters"; + pixel_x = -5; + pixel_y = 31 + }, +/obj/machinery/button/blast_door{ + id_tag = "SkipjackShuttersEast"; + name = "Skipjack East Shutters"; + pixel_x = 5; + pixel_y = 31 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cN" = ( +/obj/structure/chair/office/light{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cO" = ( +/obj/machinery/constructable_frame/computerframe, +/obj/machinery/light/small{ + dir = 4; + icon_state = "bulb1" + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cP" = ( +/obj/machinery/light/small, +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + id_tag = "skipjack_shuttle"; + pixel_x = -25; + pixel_y = 8; + req_access = list("ACCESS_RAIDER") + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ + dir = 4; + id_tag = "skipjack_shuttle_pump" + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cQ" = ( +/obj/machinery/atmospherics/pipe/manifold/visible{ + dir = 4 + }, +/obj/machinery/meter, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cR" = ( +/obj/effect/paint/brown, +/turf/wall/raidershuttle, +/area/map_template/skipjack_station/start) +"cS" = ( +/obj/machinery/door/airlock/external{ + id_tag = "raider_southwest_lock" + }, +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cT" = ( +/obj/structure/rack, +/obj/random/hardsuit/heist, +/obj/item/clothing/glasses/thermal/plain/monocle, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cU" = ( +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cV" = ( +/obj/random/maintenance, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cW" = ( +/obj/random/junk, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cX" = ( +/obj/structure/rack, +/obj/random/hardsuit/heist, +/obj/item/clothing/head/pirate, +/obj/item/gun/launcher/money, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"cY" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/door/airlock/external{ + id_tag = "skipjack_shuttle_inner"; + name = "Ship External Access" + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"cZ" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/button/access/shuttle/interior{ + id_tag = "raider_west_control"; + pixel_x = -22; + req_access = list("ACCESS_RAIDER"); + dir = 4 + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"da" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/item/clothing/shoes/magboots, +/obj/item/tank/oxygen, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/item/harpoon, +/obj/random/energy, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"db" = ( +/obj/machinery/microwave{ + pixel_x = -1; + pixel_y = 8 + }, +/obj/structure/table/steel, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dc" = ( +/obj/item/seeds/potatoseed, +/obj/item/seeds/potatoseed, +/obj/item/seeds/ambrosiavulgarisseed, +/obj/item/tool/hoe/mini, +/obj/item/beartrap, +/obj/structure/table/steel, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dd" = ( +/obj/machinery/vending/hydroseeds, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"de" = ( +/obj/structure/rack, +/obj/item/energy_blade/cutlass, +/obj/item/clothing/suit/armor/pirate, +/obj/item/clothing/suit/armor/pirate, +/obj/item/tank/oxygen, +/obj/item/clothing/shoes/magboots, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/maintenance, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"df" = ( +/obj/structure/rack, +/obj/item/energy_blade/cutlass, +/obj/item/clothing/suit/armor/pirate, +/obj/item/clothing/suit/armor/pirate, +/obj/item/tank/oxygen, +/obj/item/clothing/shoes/magboots, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/maintenance, +/obj/machinery/light/small{ + dir = 4; + icon_state = "bulb1" + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dg" = ( +/obj/structure/rack, +/obj/item/belt/utility/full, +/obj/item/belt/utility/full, +/obj/item/multitool, +/obj/item/multitool, +/obj/item/clothing/shoes/magboots, +/obj/random/maintenance, +/obj/item/tank/oxygen, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/maintenance, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dh" = ( +/obj/machinery/washing_machine, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"di" = ( +/obj/structure/table, +/obj/item/box/fancy/cigarettes, +/obj/item/flame/fuelled/lighter/zippo/random, +/obj/item/clothing/gloves/insulated, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/card/emag, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dj" = ( +/obj/structure/rack, +/obj/random/maintenance, +/obj/item/clothing/shoes/magboots, +/obj/item/tank/oxygen, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/energy, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dk" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/button/access/interior{ + id_tag = "skipjack_shuttle"; + name = "interior access button"; + pixel_x = 25; + pixel_y = 25; + req_access = list("ACCESS_RAIDER") + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dl" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dm" = ( +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dn" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"do" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/brown, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dp" = ( +/obj/machinery/door/airlock/hatch, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dq" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/rack, +/obj/random/maintenance, +/obj/item/clothing/shoes/magboots, +/obj/item/tank/oxygen, +/obj/random/voidsuit, +/obj/random/voidhelmet, +/obj/random/projectile, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dr" = ( +/obj/random/loot, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"ds" = ( +/obj/item/robot_parts/head, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dt" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "SkipjackShuttersWest"; + name = "Skipjack Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/brown, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"du" = ( +/obj/random/trash, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dv" = ( +/obj/random/maintenance, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dw" = ( +/obj/random/trash, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dx" = ( +/obj/item/robot_parts/l_leg, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dy" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 8; + id_tag = "SkipjackShuttersEast"; + name = "Skipjack Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/brown, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dz" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dA" = ( +/obj/machinery/floodlight, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dB" = ( +/obj/structure/rack, +/obj/item/gun/launcher/bow/crossbow/powered, +/obj/item/stack/material/rods/mapped/steel/ten, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/item/beartrap, +/obj/item/beartrap, +/obj/item/beartrap, +/obj/item/beartrap, +/obj/item/beartrap, +/obj/item/beartrap, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dC" = ( +/obj/structure/rack, +/obj/item/grenade/empgrenade, +/obj/item/grenade/flashbang, +/obj/item/grenade/spawnergrenade/manhacks, +/obj/random/energy, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dD" = ( +/obj/machinery/suit_cycler/nonstandard/raider{ + locked = 0 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dE" = ( +/obj/structure/table/steel, +/obj/machinery/recharger, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dF" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dG" = ( +/obj/item/robot_parts/robot_suit, +/obj/item/robot_parts/r_leg, +/obj/item/robot_parts/r_arm, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dH" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/random/maintenance, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dI" = ( +/obj/machinery/door/blast/shutters/open{ + dir = 4; + id_tag = "SkipjackShuttersWest"; + name = "Skipjack Shutters" + }, +/obj/effect/wallframe_spawn/reinforced/titanium, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dJ" = ( +/obj/random/loot, +/obj/vehicle/bike/thermal, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dK" = ( +/obj/structure/closet/crate/plastic/rations, +/obj/item/clothing/mask/gas/cyborg, +/obj/item/box/donkpockets{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/food/junk/tastybread, +/obj/item/food/junk/tastybread, +/turf/unsimulated/floor/plating, +/area/map_template/skipjack_station/start) +"dL" = ( +/obj/machinery/door/airlock/hatch, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dM" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dN" = ( +/obj/structure/table/steel, +/obj/random/maintenance, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dO" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dP" = ( +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dQ" = ( +/obj/item/wrench, +/obj/item/mop, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dR" = ( +/obj/machinery/atmospherics/pipe/simple/visible, +/obj/item/crowbar, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dS" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dT" = ( +/obj/machinery/portable_atmospherics/hydroponics, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dU" = ( +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"dV" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"dW" = ( +/obj/effect/wallframe_spawn/reinforced/titanium, +/obj/effect/paint/brown, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"dX" = ( +/obj/structure/chair{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dY" = ( +/obj/item/deck/cards, +/obj/structure/table/steel, +/obj/random/projectile, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"dZ" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"ea" = ( +/obj/machinery/bodyscanner{ + dir = 8 + }, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"eb" = ( +/obj/machinery/light/small{ + dir = 1 + }, +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"ec" = ( +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"ed" = ( +/obj/structure/hygiene/toilet{ + dir = 4 + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"ee" = ( +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/item/tank/nitrogen, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"ef" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"eg" = ( +/obj/structure/shuttle/engine/heater, +/obj/structure/window/reinforced/crescent{ + dir = 1 + }, +/obj/effect/paint/black, +/turf/wall/raidershuttle, +/area/map_template/skipjack_station/start) +"eh" = ( +/obj/random/trash, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"ei" = ( +/obj/structure/table/steel, +/obj/random/loot, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"ej" = ( +/obj/random/junk, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"ek" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"el" = ( +/obj/structure/shuttle/engine/propulsion, +/obj/effect/paint/black, +/turf/wall/raidershuttle, +/area/map_template/skipjack_station/start) +"em" = ( +/obj/structure/table, +/obj/random/maintenance, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"en" = ( +/obj/structure/table, +/obj/item/deck/cards, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"eo" = ( +/obj/machinery/light/small, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"ep" = ( +/obj/random/trash, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"eq" = ( +/obj/structure/table, +/obj/item/circular_saw{ + pixel_y = 8 + }, +/obj/item/hemostat, +/obj/item/scalpel, +/obj/item/stack/medical/bandage/advanced, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"er" = ( +/obj/random/junk, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"es" = ( +/obj/machinery/optable, +/obj/item/clothing/mask/gas, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"et" = ( +/obj/structure/table, +/obj/item/cautery, +/obj/item/retractor, +/obj/item/chems/glass/bottle/sedatives, +/obj/item/chems/glass/bottle/sedatives, +/obj/item/chems/syringe, +/obj/item/gun/launcher/syringe/rapid, +/obj/item/box/syringegun, +/obj/item/chems/glass/beaker/vial/random/toxin, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"eu" = ( +/obj/structure/hygiene/sink{ + dir = 4; + pixel_x = 11 + }, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"ev" = ( +/obj/structure/bed, +/obj/item/bedsheet/rainbow, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"ew" = ( +/obj/structure/bed, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"ex" = ( +/obj/random/maintenance, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"ey" = ( +/obj/structure/table, +/obj/item/bonesetter, +/obj/item/bonegel, +/obj/item/sutures, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"ez" = ( +/obj/structure/hygiene/toilet{ + dir = 4 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/floor/shuttle/black, +/area/map_template/skipjack_station/start) +"eA" = ( +/obj/structure/closet/crate, +/obj/item/clothing/suit/armor/pirate, +/obj/item/clothing/shirt/scrubs/black, +/obj/item/clothing/pants/scrubs/black, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"eB" = ( +/obj/structure/bed, +/obj/item/bedsheet/green, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"eC" = ( +/obj/structure/table, +/obj/item/firstaid/fire{ + pixel_x = 1 + }, +/obj/item/firstaid/o2{ + pixel_x = 3; + pixel_y = 3 + }, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"eD" = ( +/obj/structure/table, +/obj/item/firstaid/adv{ + pixel_x = 1 + }, +/obj/item/firstaid/toxin{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/item/baton/cattleprod, +/turf/floor/shuttle/white, +/area/map_template/skipjack_station/start) +"eF" = ( +/obj/structure/bed, +/obj/item/bedsheet/rd, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"eG" = ( +/obj/item/pizzabox/meat, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"eH" = ( +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/floor/shuttle/red, +/area/map_template/skipjack_station/start) +"jf" = ( +/obj/machinery/network/acl{ + initial_network_id = "piratenet"; + req_access = list("ACCESS_RAIDER") + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"pE" = ( +/obj/machinery/network/mainframe{ + initial_network_id = "piratenet"; + req_access = list("ACCESS_RAIDER") + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"FL" = ( +/obj/machinery/network/relay/long_range{ + initial_network_id = "piratenet"; + req_access = list("ACCESS_RAIDER") + }, +/turf/floor/plating, +/area/map_template/skipjack_station/start) +"PS" = ( +/obj/machinery/network/telecomms_hub/raider, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"SM" = ( +/obj/machinery/network/router{ + initial_network_id = "piratenet"; + req_access = list("ACCESS_RAIDER") + }, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) +"VB" = ( +/obj/machinery/computer/message_monitor, +/turf/unsimulated/floor/dark, +/area/map_template/syndicate_mothership/raider_base) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +bj +by +bT +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +aQ +aq +aq +aq +aq +ce +bk +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +aq +aq +bU +bU +bU +aq +aq +aq +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +aA +aq +aQ +aq +bk +aq +aq +aq +aq +aQ +cp +ab +ab +ab +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +an +aq +aq +aq +aq +aq +aq +bU +bU +bU +aq +aq +cq +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +ab +ab +ab +aq +aq +aB +aC +aR +aq +aq +aq +aq +aq +cf +cj +cr +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +ab +ab +ab +aq +aq +aC +aC +aq +aq +ab +aq +aQ +aq +aq +ab +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +ab +ab +ab +aj +aq +aC +aC +aq +ab +ab +ab +ab +ab +ab +ab +ab +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +aj +aw +aC +aC +aq +ab +ab +ab +ab +ab +ab +ab +cs +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +af +aj +ae +ae +aj +ae +ae +ae +ab +ab +aa +ck +ck +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +aa +aa +aa +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ad +an +an +ae +aH +aS +ba +bl +ae +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ad +ar +ar +ae +aI +aT +aj +bm +ae +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ad +aj +an +ae +aJ +aS +aS +bn +ae +aC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ad +an +aj +ae +ae +aU +aU +ae +ae +aC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ad +af +an +an +an +an +an +an +bC +aC +aC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ad +an +an +an +an +aV +af +an +aj +aC +aC +aC +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ad +an +an +ae +ae +ae +ae +ae +aD +ae +ae +ae +ae +ae +ae +ae +ae +cw +cw +cw +cR +cR +cR +dt +dt +dI +cR +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ad +an +an +ae +aK +aW +bb +bo +bD +ae +bZ +aj +cl +ct +an +an +ct +cx +cB +cI +cS +cZ +dl +dl +dz +dz +dS +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ae +ae +ae +ae +an +an +ae +aL +aX +aX +aY +bE +bq +an +aj +aj +ct +an +an +bq +cy +cC +cJ +cR +da +dm +du +dm +dJ +dT +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ae +jf +VB +ae +aj +an +aD +aM +aY +aY +aY +bF +bq +an +cg +ae +ae +bq +bq +ae +cw +cw +cw +cR +db +dm +dm +dA +dK +dT +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ae +pE +an +an +an +an +aD +aN +aY +aY +aY +bG +bq +af +an +bq +aa +aa +aa +aa +aa +aa +aa +cR +dc +dm +dv +du +cR +cR +cR +cR +cR +cR +cR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ae +SM +PS +ae +an +an +ae +aL +aX +aX +aY +bH +bq +aj +an +bq +aa +cv +aa +aa +aa +aa +aa +cR +dd +dn +dm +dm +dL +dU +dU +em +dU +eh +cR +cR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(33,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ae +ae +ae +ae +an +an +ae +aO +aZ +bc +bp +bI +ae +an +an +bq +aa +aa +aa +aa +aa +cw +cw +cR +cR +cR +dp +cR +cR +dV +eh +en +dU +dU +ez +cR +cR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(34,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ae +af +an +ae +ae +ae +ae +ae +aD +ae +aD +aD +ae +ae +aa +aa +aa +cw +cw +cw +cT +de +do +cU +dB +cR +dU +dU +dU +er +eu +dU +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(35,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ae +an +an +an +an +an +an +aD +bJ +bJ +bJ +ch +cm +ae +aa +aa +aa +cw +cD +cK +cU +cU +do +cW +dC +cR +dW +dW +dW +cR +cR +cR +cw +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(36,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ae +ae +ae +ae +as +an +an +an +an +an +ae +bK +bV +ca +bV +bJ +bq +aa +aa +aa +cz +cE +cL +cU +cU +do +cU +cU +dM +dX +dX +eo +cR +ev +eA +eF +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(37,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ae +ag +ak +ae +ae +ae +ae +ae +an +an +ae +bL +bW +cb +ci +bJ +bq +aa +aa +aa +cz +cF +cM +cV +cU +dp +cU +cU +dN +dY +ei +cU +dp +cU +cU +eG +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(38,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ae +ah +al +ao +ao +ax +aE +aD +an +an +bq +bM +bV +cc +bV +bJ +bq +aa +aa +aa +cz +cD +cN +cU +cU +do +dw +cU +dO +dZ +dZ +eo +cR +ew +eB +eH +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(39,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ae +ai +am +ap +ao +ay +ao +aD +af +an +bq +bN +bJ +bJ +bJ +cn +ae +aa +aa +aa +cw +cD +cO +cW +cU +do +cU +dD +cR +dW +dW +dW +cR +cR +cR +cw +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(40,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ae +ae +ae +ae +ao +ao +aF +ae +an +an +ae +bq +bq +aD +aD +ae +ae +aa +aa +aa +cw +cw +cw +cX +df +do +cU +dE +cR +ea +ej +ec +es +ec +eC +cw +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ae +at +at +ae +ae +an +aj +br +an +an +an +an +bq +aa +aa +aa +aa +aa +cw +cw +cR +cR +cR +dp +cR +cR +eb +ec +ep +ec +ex +eD +cR +cR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ae +ae +ae +ae +an +an +an +aj +aj +aj +an +af +bq +aa +aa +aa +aa +aa +aa +aa +cR +dg +dq +dm +dm +dL +ec +ek +eq +et +ey +cR +cR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ae +ae +ae +ae +aP +ae +ae +aP +ae +ae +an +an +bq +aa +aa +aa +aa +aa +aa +aa +cR +dh +dm +dm +FL +cR +cR +cR +cR +cR +cR +cR +cR +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ae +au +aj +aj +aw +ae +bd +aj +bO +ae +an +an +ae +ae +bq +bq +ae +cw +cw +cw +cR +di +dr +dx +dF +dP +ed +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ae +aj +aj +aG +av +ae +be +bs +bP +ae +an +af +co +cu +an +an +bq +cw +cG +cP +cR +dj +ds +du +dG +dQ +ee +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ae +av +az +aj +aj +ae +bf +bt +bQ +ae +cd +an +an +cu +an +an +cu +cA +cH +cQ +cY +dk +dl +dl +dH +dR +ef +eg +el +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ae +aj +aj +av +av +ae +bg +bu +bR +ae +ae +ae +ae +ae +ae +ae +ae +cw +cw +cw +cR +cR +cR +dy +dy +dy +cR +cw +cw +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ae +ae +ae +ae +ae +ae +bh +bv +bv +ae +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +ab +ab +ab +ab +ab +ab +ab +ae +bf +bw +bS +ae +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +ab +ab +ab +ab +ab +ab +ab +ab +ae +bi +bx +bx +ae +ab +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ab +ab +ab +ab +ab +ab +ab +ab +ae +ae +ae +ae +ae +ab +ab +ab +ab +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/mods/gamemodes/heist/outfit.dm b/mods/gamemodes/heist/outfit.dm new file mode 100644 index 000000000000..435b90296478 --- /dev/null +++ b/mods/gamemodes/heist/outfit.dm @@ -0,0 +1,130 @@ +/decl/outfit/raider + name = "Special Role - Raider" + l_ear = /obj/item/radio/headset/raider + id_type = /obj/item/card/id/syndicate + var/list/raider_uniforms = list( + /obj/item/clothing/costume/soviet, + /obj/item/clothing/costume/pirate, + /obj/item/clothing/costume/redcoat, + /obj/item/clothing/costume/captain_fly + ) + var/list/raider_shoes = list( + /obj/item/clothing/shoes/jackboots, + /obj/item/clothing/shoes/workboots, + /obj/item/clothing/shoes/color/brown, + /obj/item/clothing/shoes/dress + ) + var/list/raider_glasses = list( + /obj/item/clothing/glasses/thermal, + /obj/item/clothing/glasses/thermal/plain/eyepatch, + /obj/item/clothing/glasses/thermal/plain/monocle + ) + var/list/raider_helmets = list( + /obj/item/clothing/head/bearpelt, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/pirate, + /obj/item/clothing/mask/bandana/red, + /obj/item/clothing/head/hgpiratecap, + ) + var/list/raider_suits = list( + /obj/item/clothing/suit/pirate, + /obj/item/clothing/suit/hgpirate, + /obj/item/clothing/suit/jacket/bomber, + /obj/item/clothing/suit/jacket/leather, + /obj/item/clothing/suit/jacket/brown, + /obj/item/clothing/suit/jacket/hoodie, + /obj/item/clothing/suit/jacket/hoodie/black, + /obj/item/clothing/suit/poncho, + ) + var/list/raider_guns = list( + /obj/item/gun/energy/laser, + /obj/item/gun/projectile/revolver/lasvolver, + /obj/item/gun/energy/xray, + /obj/item/gun/energy/toxgun, + /obj/item/gun/energy/ionrifle, + /obj/item/gun/energy/taser, + /obj/item/gun/energy/crossbow/largecrossbow, + /obj/item/gun/launcher/bow/crossbow/powered, + /obj/item/gun/launcher/grenade/random, + /obj/item/gun/launcher/pneumatic, + /obj/item/gun/projectile/automatic/smg, + /obj/item/gun/projectile/automatic/assault_rifle, + /obj/item/gun/projectile/shotgun/pump, + /obj/item/gun/projectile/shotgun/doublebarrel, + /obj/item/gun/projectile/shotgun/doublebarrel/sawn, + /obj/item/gun/projectile/pistol/holdout, + /obj/item/gun/projectile/revolver, + /obj/item/gun/projectile/zipgun + ) + var/list/raider_holster = list( + /obj/item/clothing/webbing/holster/armpit, + /obj/item/clothing/webbing/holster/waist, + /obj/item/clothing/webbing/holster/hip + ) + +/decl/outfit/raider/Initialize() + randomize_clothing() + . = ..() + +/decl/outfit/raider/equip_outfit(mob/living/wearer, assignment, equip_adjustments, datum/job/job, datum/mil_rank/rank) + randomize_clothing() + . = ..() + if(. && wearer) + if(!wearer.get_equipped_item(slot_shoes_str)) + wearer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(wearer), slot_shoes_str) + + var/new_gun = pick(raider_guns) + var/new_holster = pick(raider_holster) //raiders don't start with any backpacks, so let's be nice and give them a holster if they can use it. + var/turf/T = get_turf(wearer) + + var/obj/item/primary = new new_gun(T) + var/obj/item/clothing/webbing/holster/holster = null + + //Give some of the raiders a pirate gun as a secondary + if(prob(60)) + var/obj/item/secondary = new /obj/item/gun/projectile/zipgun(T) + if(!(primary.slot_flags & SLOT_HOLSTER)) + holster = new new_holster(T) + var/datum/extension/holster/holster_extension = get_extension(holster, /datum/extension/holster) + holster_extension.holstered = secondary + secondary.forceMove(holster) + else + wearer.equip_to_slot_or_del(secondary, slot_belt_str) + + if(primary.slot_flags & SLOT_HOLSTER) + holster = new new_holster(T) + var/datum/extension/holster/holster_extension = get_extension(holster, /datum/extension/holster) + holster_extension.holstered = primary + primary.forceMove(holster) + else if(!wearer.get_equipped_item(slot_belt_str) && (primary.slot_flags & SLOT_LOWER_BODY)) + wearer.equip_to_slot_or_del(primary, slot_belt_str) + else if(!wearer.get_equipped_item(slot_back_str) && (primary.slot_flags & SLOT_BACK)) + wearer.equip_to_slot_or_del(primary, slot_back_str) + else + wearer.put_in_hands(primary) + + if(istype(primary, /obj/item/gun/projectile)) + var/obj/item/gun/projectile/bullet_thrower = primary + if(bullet_thrower.magazine_type) + wearer.equip_to_slot_or_del(new bullet_thrower.magazine_type(wearer), slot_l_store_str) + if(prob(20)) //don't want to give them too much + wearer.equip_to_slot_or_del(new bullet_thrower.magazine_type(wearer), slot_r_store_str) + else if(bullet_thrower.ammo_type) + var/obj/item/box/ammobox = new(get_turf(wearer.loc)) + for(var/i in 1 to rand(3,5) + rand(0,2)) + new bullet_thrower.ammo_type(ammobox) + wearer.put_in_hands(ammobox) + + if(holster) + var/obj/item/clothing/uniform = wearer.get_equipped_item(slot_w_uniform_str) + if(istype(uniform) && uniform.can_attach_accessory(holster)) + uniform.attackby(holster, wearer) + else + wearer.put_in_hands(holster) + +/decl/outfit/raider/proc/randomize_clothing() + shoes = pick(raider_shoes) + uniform = pick(raider_uniforms) + glasses = pick(raider_glasses) + head = pick(raider_helmets) + suit = pick(raider_suits) diff --git a/mods/gamemodes/heist/presets.dm b/mods/gamemodes/heist/presets.dm new file mode 100644 index 000000000000..17df347a08e7 --- /dev/null +++ b/mods/gamemodes/heist/presets.dm @@ -0,0 +1,24 @@ +/mob/living/simple_animal/hostile/parrot/pirate + name = "\proper Meatbag" + ai = /datum/mob_controller/aggressive/parrot/pirate + +/datum/mob_controller/aggressive/parrot/pirate + emote_speech = list("Yaaar!","Squaaak!","Fight me Matey!","BAWWWWK Vox trying to eat me!") + +/obj/machinery/network/telecomms_hub/raider + initial_network_id = "piratenet" + req_access = list(access_raider) + channels = list( + COMMON_FREQUENCY_DATA, + list( + "name" = "Raider", + "key" = "t", + "frequency" = PUB_FREQ, + "color" = COMMS_COLOR_SYNDICATE, + "span_class" = CSS_CLASS_RADIO, + "secured" = access_raider + ) + ) + +/obj/structure/sign/warning/nosmoking_1/heist + desc = "A warning sign which reads 'NO SMOKING'. Someone has scratched a variety of crude words in gutter across the entire sign." \ No newline at end of file diff --git a/mods/gamemodes/heist/shuttle.dm b/mods/gamemodes/heist/shuttle.dm new file mode 100644 index 000000000000..d170e6b9356a --- /dev/null +++ b/mods/gamemodes/heist/shuttle.dm @@ -0,0 +1,24 @@ +/datum/shuttle/autodock/multi/antag/skipjack + name = "Skipjack" + defer_initialisation = TRUE + warmup_time = 0 + destination_tags = list( + "nav_skipjack_start" + ) + shuttle_area = /area/map_template/skipjack_station/start + dock_target = "skipjack_shuttle" + current_location = "nav_skipjack_start" + announcer = "Proximity Sensor Array" + home_waypoint = "nav_skipjack_start" + arrival_message = "Attention, vessel detected entering vessel proximity." + departure_message = "Attention, vessel detected leaving vessel proximity." + +/obj/effect/shuttle_landmark/skipjack/start + name = "Raider Outpost" + landmark_tag = "nav_skipjack_start" + docking_controller = "skipjack_base" + +/obj/machinery/computer/shuttle_control/multi/raider + name = "skipjack control console" + initial_access = list(access_raider) + shuttle_tag = "Skipjack" diff --git a/mods/gamemodes/heist/special_role.dm b/mods/gamemodes/heist/special_role.dm new file mode 100644 index 000000000000..d9f984dcf6c7 --- /dev/null +++ b/mods/gamemodes/heist/special_role.dm @@ -0,0 +1,59 @@ +/decl/special_role/raider + name = "Raider" + name_plural = "Raiders" + antag_indicator = "hudraider" + landmark_id = "raiderstart" + welcome_text = "Use :H to talk on your encrypted channel." + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER + antaghud_indicator = "hudraider" + hard_cap = 6 + hard_cap_round = 10 + initial_spawn_req = 4 + initial_spawn_target = 6 + min_player_age = 14 + default_access = list(access_raider) + faction = "pirate" + base_to_load = "Heist Base" + default_outfit = /decl/outfit/raider + id_title = "Visitor" + + var/list/outfits_per_species + +/decl/special_role/raider/update_access(var/mob/living/player) + for(var/obj/item/wallet/wallet in player.contents) + for(var/obj/item/card/id/id in wallet.contents) + id.SetName("[player.real_name]'s Passport") + id.registered_name = player.real_name + wallet.SetName("[initial(wallet.name)] ([id.name])") + +/decl/special_role/raider/create_global_objectives() + + if(!..()) + return 0 + + var/i = 1 + var/max_objectives = pick(2,2,2,2,3,3,3,4) + global_objectives = list() + while(i<= max_objectives) + var/list/goals = list("kidnap","loot","salvage") + var/goal = pick(goals) + var/datum/objective/O + + if(goal == "kidnap") + goals -= "kidnap" + O = new /datum/objective/kidnap() + else if(goal == "loot") + O = new /datum/objective/loot() + else + O = new /datum/objective/salvage() + O.find_target() + global_objectives |= O + + i++ + + global_objectives |= new /datum/objective/preserve_crew + return 1 + +/decl/special_role/raider/equip_role(var/mob/living/human/player) + default_outfit = LAZYACCESS(outfits_per_species, player.species.uid) || initial(default_outfit) + . = ..() diff --git a/mods/gamemodes/mercenary/_merc.dm b/mods/gamemodes/mercenary/_merc.dm new file mode 100644 index 000000000000..2c1627f39c5b --- /dev/null +++ b/mods/gamemodes/mercenary/_merc.dm @@ -0,0 +1,2 @@ +/decl/modpack/mercenary + name = "Mercenary Gamemode" \ No newline at end of file diff --git a/mods/gamemodes/mercenary/_mercenary.dme b/mods/gamemodes/mercenary/_mercenary.dme new file mode 100644 index 000000000000..b9ff487138c8 --- /dev/null +++ b/mods/gamemodes/mercenary/_mercenary.dme @@ -0,0 +1,13 @@ +#ifndef GAMEMODE_PACK_MERCENARY +#define GAMEMODE_PACK_MERCENARY +// BEGIN_INCLUDE +#include "_merc.dm" +#include "mercenary_antagonist.dm" +#include "mercenary_mode.dm" +#include "mercenary_pinpointer.dm" +#include "mercenary_props.dm" +#include "mercenary_uplink.dm" +#include "nuke_overrides.dm" +#include "maps\mercenary_base.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/mercenary/maps/mercenary_base.dm b/mods/gamemodes/mercenary/maps/mercenary_base.dm new file mode 100644 index 000000000000..7c014323e327 --- /dev/null +++ b/mods/gamemodes/mercenary/maps/mercenary_base.dm @@ -0,0 +1,101 @@ +/datum/map_template/ruin/antag_spawn/mercenary + name = "Mercenary Base" + prefix = "mods/gamemodes/mercenary/maps/" + suffixes = list("mercenary_base.dmm") + shuttles_to_initialise = list(/datum/shuttle/autodock/overmap/merc_shuttle) + apc_test_exempt_areas = list( + /area/map_template/merc_spawn = NO_SCRUBBER|NO_VENT + ) + +/obj/machinery/network/telecomms_hub/mercenary + req_access = list(access_mercenary) + initial_network_id = "mercnet" + channels = list( + COMMON_FREQUENCY_DATA, + list( + "name" = "Mercenary", + "key" = "t", + "frequency" = PUB_FREQ, + "color" = COMMS_COLOR_SYNDICATE, + "span_class" = CSS_CLASS_RADIO, + "secured" = access_mercenary + ) + ) + +/obj/effect/overmap/visitable/merc_base + name = "TCV Tersten Tenacity" + desc = "Sensor array detects a medium cargo vessel with high structural damage." + sector_flags = OVERMAP_SECTOR_IN_SPACE + icon_state = "ship" + hide_from_reports = TRUE + initial_generic_waypoints = list( + "nav_merc_1", + "nav_merc_2", + "nav_merc_3", + "nav_merc_4" + ) + has_distress_beacon = "SOS - multiple breaches, possible hostiles" + +/obj/effect/overmap/visitable/ship/landable/merc + name = "Desperado" + desc = "A military gunship of ICCG design. Scanner detects heavy modification to the framework of the vessel and no designation." + shuttle = "Desperado" + fore_dir = NORTH + vessel_size = SHIP_SIZE_SMALL + vessel_mass = 14000 + +/datum/shuttle/autodock/overmap/merc_shuttle + name = "Desperado" + shuttle_area = list(/area/map_template/merc_shuttle,/area/map_template/merc_shuttle/rear) + dock_target = "merc_shuttle" + current_location = "nav_merc_start" + defer_initialisation = TRUE + ceiling_type = /turf/floor/shuttle_ceiling/merc + warmup_time = 5 + range = 1 + fuel_consumption = 7 + skill_needed = SKILL_BASIC + +/turf/floor/shuttle_ceiling/merc + color = COLOR_RED + +/obj/machinery/computer/shuttle_control/explore/merc_shuttle + name = "shuttle control console" + shuttle_tag = "Desperado" + +/obj/effect/shuttle_landmark/merc/start + landmark_tag = "nav_merc_start" + +/obj/effect/shuttle_landmark/merc/nav1 + landmark_tag = "nav_merc_1" + +/obj/effect/shuttle_landmark/merc/nav2 + landmark_tag = "nav_merc_2" + +/obj/effect/shuttle_landmark/merc/nav3 + landmark_tag = "nav_merc_3" + +/obj/effect/shuttle_landmark/merc/nav4 + landmark_tag = "nav_merc_4" + +/obj/effect/shuttle_landmark/merc/dock + name = "Docking Port" + landmark_tag = "nav_merc_dock" + docking_controller = "nuke_shuttle_dock_airlock" + +//Areas + +/area/map_template/merc_spawn + name = "\improper TCV Tersten Tenacity" + icon_state = "syndie-ship" + req_access = list(access_mercenary) + +/area/map_template/merc_shuttle + name = "\improper Desperado Fore Compartment" + icon_state = "yellow" + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED + req_access = list(access_mercenary) + +/area/map_template/merc_shuttle/rear + name = "\improper Desperado Rear Compartment" + icon_state = "green" \ No newline at end of file diff --git a/maps/antag_spawn/mercenary/mercenary_base.dmm b/mods/gamemodes/mercenary/maps/mercenary_base.dmm similarity index 76% rename from maps/antag_spawn/mercenary/mercenary_base.dmm rename to mods/gamemodes/mercenary/maps/mercenary_base.dmm index 36073ac0945f..7386a3cd58a0 100644 --- a/maps/antag_spawn/mercenary/mercenary_base.dmm +++ b/mods/gamemodes/mercenary/maps/mercenary_base.dmm @@ -6,210 +6,166 @@ /obj/structure/catwalk, /obj/machinery/power/terminal, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/pointdefense{ initial_id_tag = "merc_pd" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ac" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/porta_turret{ - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ad" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ae" = ( /obj/effect/paint/red, -/turf/simulated/wall/r_titanium, +/turf/wall/r_titanium, /area/map_template/merc_shuttle) "af" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/effect/paint/red, /obj/machinery/door/blast/regular/open{ - density = 0; - icon_state = "pdoor0"; id_tag = "merc_external" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ag" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/paint/red, /obj/machinery/door/blast/regular/open{ - density = 0; - icon_state = "pdoor0"; id_tag = "merc_external" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ah" = ( /obj/structure/catwalk, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/shipsensors, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ai" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "aj" = ( /obj/machinery/computer/ship/helm{ uncreated_component_parts = list(/obj/item/stock_parts/power/battery/buildable/responsive = 1, /obj/item/cell/high = 1) }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "ak" = ( /obj/machinery/computer/shuttle_control/explore/merc_shuttle{ - req_access = list("ACCESS_SYNDICATE"); + req_access = list("ACCESS_MERCENARY"); uncreated_component_parts = list(/obj/item/stock_parts/power/battery/buildable/responsive = 1, /obj/item/cell/high = 1) }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/light/spot{ dir = 4 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "al" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/effect/floor_decal/steeldecal/steel_decals_central6, -/obj/machinery/telecomms/allinone{ - intercept = 1 - }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_spawn) "am" = ( /obj/effect/paint/black, -/turf/simulated/wall/r_titanium, +/turf/wall/r_titanium, /area/map_template/merc_shuttle) "an" = ( /obj/machinery/door/blast/regular{ id_tag = "merc_bsa" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/merc_shuttle) "ao" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "ap" = ( /obj/structure/table/steel_reinforced, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/button/blast_door{ id_tag = "merc_external"; name = "Protective Shutters Control"; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aq" = ( -/obj/structure/bed/chair/shuttle/blue{ +/obj/structure/chair/shuttle/blue{ dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "ar" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/computer/ship/engines{ dir = 8; @@ -220,121 +176,103 @@ check_arrest = 0; check_records = 0; pixel_y = 32; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "as" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "at" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "au" = ( /obj/machinery/disperser/front{ dir = 1 }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/merc_shuttle) "av" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_bsa_shutters" }, /obj/effect/paint/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "aw" = ( /obj/machinery/computer/ship/disperser, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "ax" = ( /obj/machinery/computer/ship/sensors, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "ay" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "az" = ( -/obj/structure/bed/chair/shuttle/blue{ - dir = 8 +/obj/machinery/network/relay/long_range{ + initial_network_id = "mercnet"; + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aA" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "aB" = ( /obj/machinery/disperser/middle{ dir = 1 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/merc_shuttle) "aC" = ( -/obj/structure/bed/chair/shuttle/blue{ +/obj/structure/chair/shuttle/blue{ dir = 1 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aD" = ( /obj/structure/table/steel_reinforced, @@ -343,101 +281,86 @@ name = "OFD Viewing Shutters"; pixel_x = -5; pixel_y = -3; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/button/blast_door{ id_tag = "merc_bsa"; name = "OFD Firing Blast Doors"; pixel_x = -5; pixel_y = 6; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/recharger{ pixel_x = 6 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aE" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/unary/vent_pump/on, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aF" = ( /obj/machinery/disperser/back{ dir = 1 }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/structure/ship_munition/disperser_charge/emp, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/merc_shuttle) "aG" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/floor_decal/industrial/loading{ - icon_state = "loadingarea"; dir = 8 }, /obj/machinery/door/blast/regular/open{ - density = 0; - icon_state = "pdoor0"; id_tag = "merc_bsa" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/merc_shuttle) "aH" = ( /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aI" = ( /obj/machinery/pointdefense_control{ initial_id_tag = "merc_pd"; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aJ" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/hologram/holopad/longrange/remoteship, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aK" = ( /obj/structure/catwalk, /obj/machinery/porta_turret{ - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "aL" = ( /obj/effect/paint/black, /obj/effect/paint/red, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_shuttle) "aM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -447,57 +370,45 @@ dir = 6 }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/obj/machinery/power/apc/hyper{ +/obj/machinery/apc/hyper{ dir = 8; pixel_x = -21; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") + }, +/obj/structure/chair/shuttle/blue{ + dir = 4 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aN" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/effect/floor_decal/industrial/warning/corner, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aO" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/industrial/warning, @@ -507,96 +418,89 @@ /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aP" = ( -/obj/structure/bed/chair/shuttle/blue{ +/obj/structure/chair/shuttle/blue{ dir = 8 }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/computer/ship/navigation/telescreen{ pixel_y = -32 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aQ" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "aR" = ( /obj/effect/paint/red, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_shuttle) "aS" = ( /obj/structure/closet/medical_wall/filled{ - pixel_x = -32 + pixel_x = -32; + dir = 4 }, /obj/item/chems/spray/cleaner, /obj/item/chems/spray/antiseptic, /obj/item/defibrillator/loaded, -/obj/item/storage/firstaid/combat, +/obj/item/firstaid/combat, /obj/item/clothing/gloves/latex, /obj/item/clothing/mask/surgical, /obj/item/bodybag/cryobag, -/obj/item/chems/ivbag/nanoblood, -/obj/item/storage/firstaid/adv, -/turf/simulated/floor/tiled/white, +/obj/item/chems/ivbag/blood/nanoblood, +/obj/item/firstaid/adv, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "aT" = ( /obj/structure/iv_drip, -/obj/item/chems/ivbag/nanoblood, +/obj/item/chems/ivbag/blood/nanoblood, /obj/structure/window/reinforced/crescent{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "aU" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, -/turf/simulated/floor/shuttle/darkred, +/obj/structure/chair/shuttle/blue{ + dir = 4 + }, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aV" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "aW" = ( /obj/machinery/power/smes/buildable/preset{ @@ -607,135 +511,138 @@ uncreated_component_parts = list(/obj/item/stock_parts/smes_coil/super_io = 1, /obj/item/stock_parts/smes_coil/super_capacity = 1) }, /obj/structure/cable, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) +"aX" = ( +/obj/machinery/atmospherics/pipe/simple/visible/fuel{ + dir = 4 + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/abstract/landmark{ + name = "Nuclear-Bomb" + }, +/obj/structure/railing/mapped{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, +/turf/floor/tiled/techfloor/grid, +/area/map_template/merc_shuttle/rear) +"aY" = ( +/obj/effect/wallframe_spawn/reinforced_borosilicate, +/obj/machinery/door/blast/regular/open{ + dir = 8; + id_tag = "merc_fuel" + }, +/obj/effect/paint/black, +/turf/floor/plating, +/area/map_template/merc_shuttle/rear) "aZ" = ( /obj/effect/paint/red, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 5 }, -/turf/simulated/wall/r_titanium, +/turf/wall/r_titanium, /area/map_template/merc_shuttle) "ba" = ( /obj/effect/paint/red, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_shuttle) "bb" = ( -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bc" = ( /obj/machinery/door/window{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bd" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "be" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 8 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "bf" = ( /obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/canister/air/airlock, /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bg" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/effect/paint/red, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_airlock" }, /obj/machinery/atmospherics/pipe/simple/hidden{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "bh" = ( -/obj/structure/handrai, +/obj/structure/handrail, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 8; id_tag = "merc_shuttle_pump" }, /obj/machinery/airlock_sensor{ id_tag = "merc_shuttle_sensor"; - pixel_x = 0; pixel_y = 25 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bi" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4; - icon_state = "map" + dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "bj" = ( /obj/machinery/bodyscanner{ - icon_state = "body_scanner_0"; dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bk" = ( /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bl" = ( /obj/machinery/door/window{ @@ -745,68 +652,51 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bm" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 4 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "bn" = ( /obj/effect/floor_decal/industrial/warning/corner{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "bo" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 1 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 5 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "bp" = ( /obj/machinery/door/airlock/external{ @@ -814,57 +704,54 @@ name = "Ship External Access" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/manifold4w/hidden, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bq" = ( /obj/effect/paint/red, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 10; - icon_state = "intact" + dir = 10 }, -/turf/simulated/wall/r_titanium, +/turf/wall/r_titanium, /area/map_template/merc_shuttle) +"br" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/binary/passive_gate, +/turf/floor/tiled/techfloor/grid, +/area/map_template/merc_shuttle/rear) "bs" = ( /obj/machinery/shield_diffuser, /obj/machinery/door/airlock/external{ - density = 1; - dir = 2; id_tag = "merc_shuttle_outer"; name = "Ship External Access" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/atmospherics/pipe/manifold/hidden{ - dir = 4; - icon_state = "map" + dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bt" = ( -/obj/item/storage/firstaid/surgery, -/obj/structure/table/standard, +/obj/item/firstaid/surgery, +/obj/structure/table, /obj/item/stack/nanopaste, /obj/machinery/light{ dir = 8; - icon_state = "tube1"; - pixel_y = 0 + icon_state = "tube1" }, -/obj/item/storage/box/freezer, +/obj/item/box/freezer, /obj/machinery/body_scanconsole, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bu" = ( /obj/machinery/optable, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bv" = ( /obj/machinery/sleeper/standard{ @@ -873,35 +760,32 @@ /obj/structure/window/reinforced/crescent{ dir = 4 }, -/turf/simulated/floor/tiled/white, +/turf/floor/tiled/white, /area/map_template/merc_shuttle) "bw" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "bx" = ( /obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/alarm{ dir = 1; pixel_y = -24; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/effect/shuttle_landmark/merc/start, /obj/effect/overmap/visitable/ship/landable/merc, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "by" = ( /obj/structure/table/steel, /obj/machinery/dummy_airlock_controller{ dir = 1; - id_tag = "merc_shuttle"; - pixel_x = 0 + id_tag = "merc_shuttle" }, /obj/item/crowbar, /obj/item/crowbar, @@ -910,8 +794,10 @@ /obj/item/crowbar, /obj/item/crowbar, /obj/machinery/button/blast_door{ + dir = 1; id_tag = "merc_airlock"; - req_access = list("ACCESS_SYNDICATE") + pixel_y = 8; + req_access = list("ACCESS_MERCENARY") }, /obj/item/binoculars, /obj/item/binoculars, @@ -919,22 +805,19 @@ /obj/item/binoculars, /obj/item/binoculars, /obj/item/binoculars, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "bz" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_airlock" }, /obj/effect/paint/red, /obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 5; - icon_state = "intact" + dir = 5 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "bA" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -942,12 +825,9 @@ id_tag = "merc_shuttle_pump_out_internal" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bB" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -955,17 +835,13 @@ id_tag = "merc_shuttle_pump" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bC" = ( /obj/machinery/shield_diffuser, /obj/machinery/door/airlock/external{ - density = 1; dir = 4; id_tag = "merc_shuttle_outer"; name = "Ship External Access" @@ -973,26 +849,24 @@ /obj/machinery/atmospherics/pipe/simple/hidden{ dir = 9 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bD" = ( /obj/machinery/door/airlock, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bE" = ( /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/merc_shuttle) "bF" = ( /obj/effect/paint/black, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_shuttle/rear) "bG" = ( /obj/machinery/light/small{ @@ -1000,54 +874,40 @@ }, /obj/machinery/atmospherics/portables_connector, /obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "bH" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_shuttle/rear) "bI" = ( -/obj/effect/wallframe_spawn/reinforced_borosilicate, -/obj/machinery/atmospherics/pipe/manifold/visible/fuel{ - dir = 4 - }, -/obj/machinery/door/blast/regular/open{ - density = 0; - dir = 8; - icon_state = "pdoor0"; - id_tag = "merc_fuel" - }, -/obj/effect/paint/black, -/turf/simulated/floor/plating, +/obj/machinery/atmospherics/pipe/simple/hidden/universal, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "bJ" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 1 }, /obj/machinery/embedded_controller/radio/airlock/docking_port{ cycle_to_external_air = 1; dir = 1; id_tag = "merc_shuttle"; - pixel_x = 0; pixel_y = -25; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 4; id_tag = "merc_shuttle_pump_out_internal" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "bK" = ( /obj/machinery/atmospherics/unary/vent_pump/tank{ @@ -1066,77 +926,59 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/reinforced/carbon_dioxide, +/turf/floor/reinforced/carbon_dioxide, /area/map_template/merc_shuttle/rear) "bL" = ( /obj/machinery/door/blast/regular{ dir = 4; id_tag = "merc_fuel_vent" }, -/turf/simulated/floor/reinforced, +/turf/floor/reinforced, /area/map_template/merc_shuttle/rear) "bN" = ( /obj/machinery/atmospherics/unary/outlet_injector{ - id_tag = "fuel_in"; - use_power = 0 + id_tag = "fuel_in" }, /obj/machinery/sparker{ id_tag = "merc_igniter"; pixel_y = 26 }, -/turf/simulated/floor/reinforced/carbon_dioxide, -/area/map_template/merc_shuttle/rear) -"bO" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/blue, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/reinforced/carbon_dioxide, /area/map_template/merc_shuttle/rear) "bP" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_shuttle/rear) "bQ" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 6 }, /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/merc_shuttle/rear) "bR" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, /obj/machinery/atmospherics/pipe/manifold4w/visible/fuel, /obj/machinery/door/blast/regular/open{ - density = 0; - icon_state = "pdoor0"; id_tag = "merc_fuel" }, /obj/effect/paint/black, /obj/machinery/meter, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "bS" = ( /obj/effect/wallframe_spawn/reinforced_borosilicate, @@ -1144,45 +986,32 @@ dir = 4 }, /obj/machinery/door/blast/regular/open{ - density = 0; - icon_state = "pdoor0"; id_tag = "merc_fuel" }, /obj/effect/paint/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "bT" = ( /obj/effect/paint/black, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/merc_shuttle/rear) "bU" = ( /obj/structure/catwalk, /obj/machinery/atmospherics/unary/vent_pump/high_volume{ controlled = 0; - dir = 2; icon_state = "map_vent_in"; - initialize_directions = 2; - internal_pressure_bound = 0; - internal_pressure_bound_default = 0; pressure_checks = 2; pressure_checks_default = 2; - pump_direction = 1; use_power = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "bV" = ( /obj/effect/paint/red, -/turf/simulated/wall/titanium, -/area/map_template/merc_shuttle/rear) -"bW" = ( -/obj/machinery/atmospherics/binary/passive_gate, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/wall/titanium, /area/map_template/merc_shuttle/rear) "bX" = ( /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/effect/floor_decal/industrial/warning{ @@ -1191,14 +1020,13 @@ }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_shuttle/rear) "bY" = ( /obj/machinery/atmospherics/portables_connector{ dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, /obj/machinery/button/blast_door{ @@ -1206,29 +1034,28 @@ name = "EMERGENCY VENT"; pixel_x = 8; pixel_y = 32; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/button/blast_door{ id_tag = "merc_fuel"; name = "Fuel Storage Shutters"; pixel_x = -6; pixel_y = 36; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/button/ignition{ id_tag = "merc_igniter"; pixel_x = -6; pixel_y = 26 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_shuttle/rear) "bZ" = ( /obj/machinery/atmospherics/valve/open, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_shuttle/rear) "ca" = ( /obj/machinery/fabricator/hacked, @@ -1237,14 +1064,14 @@ dir = 4 }, /obj/machinery/light/small, -/obj/item/stack/material/plastic/ten, -/obj/item/stack/material/aluminium/ten, -/obj/item/stack/material/steel/ten, -/obj/item/stack/material/glass/ten, +/obj/item/stack/material/panel/mapped/plastic/ten, +/obj/item/stack/material/sheet/shiny/mapped/aluminium/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/stack/material/pane/mapped/glass/ten, /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cb" = ( /obj/effect/paint/black, @@ -1252,18 +1079,15 @@ dir = 8; name = "External to Fuel Storage" }, -/turf/simulated/wall/ocp_wall, +/turf/wall/ocp_wall, /area/map_template/merc_shuttle/rear) "cc" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, @@ -1271,11 +1095,9 @@ dir = 4 }, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cd" = ( /obj/machinery/computer/air_control{ @@ -1289,108 +1111,89 @@ dir = 5 }, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_shuttle/rear) "ce" = ( /obj/structure/catwalk, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/power/terminal{ - icon_state = "term"; dir = 4 }, /obj/machinery/pointdefense{ initial_id_tag = "merc_pd" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cf" = ( /obj/effect/paint/red, /obj/machinery/atmospherics/pipe/simple/hidden/red{ - icon_state = "intact"; dir = 5 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_shuttle/rear) "cg" = ( /obj/effect/paint/red, /obj/machinery/atmospherics/pipe/simple/hidden/universal{ dir = 4 }, -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_shuttle/rear) "ch" = ( -/obj/machinery/power/apc/hyper{ +/obj/machinery/apc/hyper{ dir = 8; pixel_x = -21; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/alarm{ pixel_y = 24; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/handrail, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "ci" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ - icon_state = "intact-supply"; dir = 5 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cj" = ( /obj/effect/floor_decal/industrial/shutoff, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "ck" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cl" = ( /obj/machinery/atmospherics/pipe/manifold4w/visible/fuel, @@ -1403,23 +1206,22 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/obj/item/stack/material/plasteel/ten, -/obj/item/stack/material/steel/fifty, -/obj/item/stack/material/rods/fifty, -/obj/item/stack/material/glass/reinforced/fifty, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, +/obj/item/stack/material/sheet/reinforced/mapped/plasteel/ten, +/obj/item/stack/material/ingot/mapped/copper/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/rods/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/rglass/fifty, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, -/obj/item/storage/briefcase/inflatable, -/obj/item/storage/briefcase/inflatable, +/obj/item/briefcase/inflatable, +/obj/item/briefcase/inflatable, /obj/item/inflatable_dispenser, /obj/item/spaceflare, /obj/item/spaceflare, /obj/item/spaceflare, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cm" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, @@ -1427,61 +1229,48 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cn" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 8 }, /obj/structure/cable{ - d1 = 2; - d2 = 8; icon_state = "2-8" }, -/obj/structure/handrai, -/turf/simulated/floor/tiled/techfloor/grid, +/obj/structure/handrail, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "co" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/structure/cable{ - d1 = 1; - d2 = 8; icon_state = "1-8" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cp" = ( /obj/structure/catwalk, /obj/machinery/power/terminal, /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + icon_state = "0-2" }, /obj/machinery/pointdefense{ initial_id_tag = "merc_pd" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cq" = ( /obj/machinery/computer/ship/engines, @@ -1489,25 +1278,24 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cr" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 6 }, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cs" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/structure/cable, /obj/machinery/atmospherics/unary/engine/terminal{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "ct" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel, @@ -1515,29 +1303,23 @@ dir = 4 }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cv" = ( /obj/machinery/atmospherics/valve/shutoff{ level = 2 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 8 }, /obj/effect/floor_decal/industrial/shutoff, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cw" = ( /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -1547,19 +1329,16 @@ /obj/machinery/portable_atmospherics/canister/hydrogen, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, /obj/structure/railing/mapped{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cx" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, /obj/structure/cable{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, /obj/machinery/atmospherics/pipe/simple/visible/fuel{ @@ -1568,11 +1347,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cy" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, @@ -1587,25 +1365,23 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 10 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cA" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on{ - icon_state = "map_scrubber_on"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cB" = ( /obj/effect/floor_decal/industrial/warning/corner{ dir = 4 }, -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 4 }, /obj/machinery/atmospherics/pipe/simple/visible/fuel, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cC" = ( /obj/effect/floor_decal/industrial/outline/orange, @@ -1613,28 +1389,22 @@ /obj/machinery/portable_atmospherics/canister/carbon_dioxide{ start_pressure = 15000 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cD" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 + icon_state = "0-4" }, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 + icon_state = "4-8" }, /obj/effect/paint/black, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cE" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ @@ -1642,39 +1412,33 @@ }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/structure/cable{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/structure/ship_munition/disperser_charge/explosive, /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cF" = ( /obj/machinery/power/terminal{ - icon_state = "term"; dir = 1 }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, /obj/structure/cable/yellow{ - d2 = 2; icon_state = "0-2" }, /obj/effect/floor_decal/steeldecal/steel_decals_central6, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cG" = ( /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, /obj/effect/floor_decal/industrial/outline/orange, /obj/machinery/atmospherics/portables_connector{ - icon_state = "map_connector"; dir = 4 }, /obj/machinery/light/small{ @@ -1683,42 +1447,40 @@ /obj/machinery/portable_atmospherics/canister/carbon_dioxide{ start_pressure = 15000 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cH" = ( -/obj/structure/fuel_port{ +/obj/structure/fuel_port/hydrogen{ pixel_x = -32 }, /obj/machinery/atmospherics/valve/shutoff{ level = 2 }, /obj/effect/floor_decal/industrial/shutoff, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cI" = ( /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, /obj/machinery/atmospherics/binary/pump/high_power/on{ dir = 4; target_pressure = 15000 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cJ" = ( -/obj/structure/fuel_port{ +/obj/structure/fuel_port/hydrogen{ pixel_x = 32 }, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, /obj/machinery/meter, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 4 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cK" = ( /obj/machinery/atmospherics/binary/pump/high_power/on{ @@ -1726,23 +1488,20 @@ }, /obj/machinery/mech_recharger, /obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 + dir = 4; + icon_state = "bulb1" }, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cL" = ( /obj/structure/cable/yellow{ - d1 = 1; - d2 = 2; icon_state = "1-2" }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ - icon_state = "map_scrubber_on"; dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cM" = ( /obj/structure/catwalk, @@ -1758,7 +1517,7 @@ pump_direction = 0; use_power = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cN" = ( /obj/machinery/teleport/hub, @@ -1766,7 +1525,7 @@ /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 6 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cO" = ( /obj/machinery/teleport/station, @@ -1774,7 +1533,7 @@ /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cP" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ @@ -1782,10 +1541,9 @@ }, /obj/effect/floor_decal/industrial/outline/yellow, /obj/machinery/constructable_frame/computerframe/deconstruct{ - icon_state = "unwired"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cQ" = ( /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ @@ -1793,66 +1551,48 @@ }, /obj/machinery/recharge_station, /obj/effect/floor_decal/industrial/outline/yellow, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cR" = ( /obj/structure/table/steel_reinforced, /obj/machinery/cell_charger, /obj/structure/cable/yellow{ - d1 = 1; - d2 = 4; icon_state = "1-4" }, -/obj/item/storage/toolbox/syndicate, -/obj/item/storage/backpack/dufflebag/syndie/ammo, +/obj/item/toolbox/syndicate, +/obj/item/backpack/dufflebag/syndie/ammo, /obj/machinery/atmospherics/pipe/simple/visible/fuel{ dir = 4 }, /obj/machinery/meter, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "cS" = ( -/obj/machinery/power/port_gen/pacman, +/obj/machinery/port_gen/pacman, /obj/structure/cable/yellow{ - d2 = 8; icon_state = "0-8" }, /obj/effect/floor_decal/industrial/hatch/yellow, /obj/machinery/atmospherics/pipe/manifold/visible/fuel{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cT" = ( /obj/machinery/atmospherics/unary/engine{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "cU" = ( -/obj/vehicle/bike/electric, -/turf/simulated/floor/airless, -/area/space) -"cW" = ( -/obj/machinery/atmospherics/pipe/simple/visible/fuel{ - dir = 4 - }, -/obj/effect/floor_decal/industrial/outline/yellow, -/obj/effect/landmark{ - name = "Nuclear-Bomb" - }, -/obj/structure/railing/mapped{ - icon_state = "railing0-1"; - dir = 8 +/obj/machinery/network/acl{ + initial_network_id = "mercnet"; + req_access = list("ACCESS_MERCENARY") }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/map_template/merc_shuttle/rear) +/turf/floor/plating/airless, +/area/map_template/merc_spawn) "cX" = ( -/obj/structure/handrai{ - icon_state = "handrail"; +/obj/structure/handrail{ dir = 1 }, /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ @@ -1860,10 +1600,10 @@ id_tag = "merc_shuttle_pump" }, /obj/machinery/light/small, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "cY" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/space) "dh" = ( /obj/structure/window/reinforced/crescent{ @@ -1881,97 +1621,93 @@ /obj/structure/window/reinforced/crescent{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "dk" = ( /obj/structure/window/reinforced/crescent{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, +/area/map_template/merc_spawn) +"dP" = ( +/turf/floor/plating/airless, /area/map_template/merc_spawn) "eb" = ( -/obj/effect/landmark{ +/obj/abstract/landmark{ name = "Syndicate-Spawn" }, /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 1 }, -/obj/structure/bed/chair/office, -/turf/simulated/floor/tiled, +/obj/structure/chair/office, +/turf/floor/tiled, /area/map_template/merc_spawn) "ec" = ( -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 8 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "ex" = ( /obj/effect/floor_decal/industrial/outline, -/obj/machinery/suit_cycler/syndicate{ +/obj/machinery/suit_cycler/nonstandard/mercenary{ locked = 0 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle/rear) "eA" = ( /obj/structure/railing, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "eP" = ( /obj/structure/closet/crate/uranium, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "fq" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 1 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "ft" = ( /obj/structure/railing{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "fx" = ( /obj/machinery/computer/ship/engines{ dir = 8; uncreated_component_parts = list(/obj/item/stock_parts/power/battery/buildable/responsive = 1, /obj/item/cell/high = 1) }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "fC" = ( /obj/structure/ore_box, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "fV" = ( -/obj/machinery/mining/drill, +/obj/machinery/mining_drill, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "gc" = ( /obj/structure/catwalk, @@ -1980,14 +1716,13 @@ }, /obj/machinery/airlock_sensor{ id_tag = "merc_shuttle_exterior_sensor"; - pixel_x = 0; - pixel_y = -28 + pixel_y = -28; + dir = 1 }, /obj/machinery/power/terminal{ dir = 8 }, /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/pointdefense{ @@ -1997,9 +1732,9 @@ id_tag = "merc_shuttle"; pixel_x = 37; pixel_y = -32; - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "gk" = ( /obj/random/medical, @@ -2007,42 +1742,38 @@ /area/space) "gy" = ( /obj/machinery/vitals_monitor, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "gI" = ( /obj/structure/railing{ - icon_state = "railing0-1"; dir = 4 }, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "gW" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "gZ" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 + dir = 4; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "ha" = ( /obj/structure/railing{ - icon_state = "railing0-1"; dir = 8 }, /turf/space, /area/space) "hk" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/tank/jetpack/oxygen, /obj/item/tank/jetpack/oxygen, /obj/item/tank/jetpack/oxygen, @@ -2050,89 +1781,83 @@ /obj/item/tank/jetpack/carbondioxide, /obj/item/tank/jetpack/carbondioxide, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "hG" = ( /obj/machinery/computer/ship/sensors{ dir = 4 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "hV" = ( /obj/structure/railing{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "hX" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/revolver, /obj/item/gun/projectile/revolver, /obj/item/ammo_magazine/speedloader, /obj/item/ammo_magazine/speedloader, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "iv" = ( /obj/structure/closet/crate/secure/explosives, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "iB" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/projectile/pistol, /obj/item/gun/projectile/pistol, /obj/item/ammo_magazine/pistol, /obj/item/ammo_magazine/pistol, /obj/item/ammo_magazine/pistol, /obj/item/ammo_magazine/pistol, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "iN" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 2 + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "js" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/brown_vest, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/white_vest, -/obj/item/clothing/accessory/storage/black_vest, -/obj/item/clothing/accessory/storage/black_vest, +/obj/structure/rack, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest/brown, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest, +/obj/item/clothing/webbing/vest/black, +/obj/item/clothing/webbing/vest/black, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "jE" = ( -/obj/structure/bed/chair/shuttle/blue{ +/obj/structure/chair/shuttle/blue{ dir = 8 }, /obj/machinery/recharger/wallcharger{ dir = 8; - icon_state = "wrecharger0"; pixel_x = 23; pixel_y = -3 }, -/turf/simulated/floor/shuttle/darkred, +/turf/floor/shuttle/darkred, /area/map_template/merc_shuttle) "jF" = ( /obj/effect/shuttle_landmark/merc/nav1, @@ -2140,335 +1865,314 @@ /area/space) "jJ" = ( /obj/structure/railing, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "jP" = ( /obj/machinery/acting/changer, /obj/machinery/light/spot, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "kc" = ( /obj/effect/floor_decal/industrial/warning/corner{ dir = 4 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "kf" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/gun, /obj/item/gun/energy/gun, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "km" = ( -/obj/structure/table/rack, -/obj/item/pickaxe/diamonddrill, -/obj/item/pickaxe/diamonddrill, +/obj/structure/rack, +/obj/item/tool/drill/diamond, +/obj/item/tool/drill/diamond, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "ks" = ( -/obj/effect/landmark{ +/obj/abstract/landmark{ name = "Syndicate-Spawn" }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "kI" = ( /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "kQ" = ( /obj/structure/closet/crate/med_crate/toxin, -/obj/item/storage/box/bodybags, -/obj/item/storage/box/gloves, -/obj/item/storage/box/masks, -/obj/item/storage/belt/medical/emt, -/obj/item/storage/belt/medical/emt, -/obj/item/storage/belt/medical, -/obj/item/storage/belt/medical, +/obj/item/box/bodybags, +/obj/item/box/gloves, +/obj/item/box/masks, +/obj/item/belt/medical/emt, +/obj/item/belt/medical/emt, +/obj/item/belt/medical, +/obj/item/belt/medical, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "kS" = ( /obj/structure/railing, /turf/space, /area/space) "lh" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/gun/small, /obj/item/gun/energy/gun/small, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "lq" = ( /obj/structure/railing{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "ls" = ( -/obj/machinery/mining/drill, +/obj/machinery/mining_drill, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "lQ" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/drop_pouches/white, -/obj/item/clothing/accessory/storage/drop_pouches/white, -/obj/item/clothing/accessory/storage/drop_pouches/black, -/obj/item/clothing/accessory/storage/drop_pouches/black, -/obj/item/clothing/accessory/storage/drop_pouches/brown, -/obj/item/clothing/accessory/storage/drop_pouches/brown, +/obj/structure/rack, +/obj/item/clothing/webbing/drop_pouches/white, +/obj/item/clothing/webbing/drop_pouches/white, +/obj/item/clothing/webbing/drop_pouches/black, +/obj/item/clothing/webbing/drop_pouches/black, +/obj/item/clothing/webbing/drop_pouches/brown, +/obj/item/clothing/webbing/drop_pouches/brown, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "mi" = ( /obj/structure/catwalk, /obj/machinery/porta_turret{ - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/light/spot{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "mm" = ( /obj/structure/table/steel_reinforced, /obj/item/wrench, /obj/item/cell/hyper, /obj/machinery/light/small, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "mR" = ( /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "nd" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 5 + dir = 5; + icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "nk" = ( /obj/random/medical, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "nE" = ( /obj/machinery/fabricator/pipe/disposal, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "nN" = ( -/obj/machinery/power/port_gen/pacman, +/obj/machinery/port_gen/pacman, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "nQ" = ( /obj/machinery/fabricator/pipe, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "nR" = ( -/obj/structure/dispenser/oxygen, +/obj/structure/tank_rack/oxygen, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "oW" = ( /obj/structure/inflatable/door, /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "oY" = ( /obj/structure/cable{ - d1 = 2; - d2 = 4; icon_state = "2-4" }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_spawn) "ph" = ( /obj/structure/inflatable/door, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "pj" = ( /obj/machinery/vending/cola{ dir = 1; - name = "hacked Robust Softdrinks"; - markup = 0 + markup = 0; + name = "hacked Robust Softdrinks" }, /obj/machinery/light/spot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "qa" = ( -/obj/effect/landmark{ +/obj/abstract/landmark{ name = "Syndicate-Uplink" }, /obj/effect/overmap/visitable/merc_base{ dir = 10 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "qq" = ( -/obj/machinery/mining/brace, +/obj/structure/drill_brace, /obj/machinery/light/spot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "qA" = ( /obj/machinery/constructable_frame/computerframe/deconstruct{ - icon_state = "unwired"; dir = 1 }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "qX" = ( /obj/structure/undies_wardrobe, /obj/machinery/light/spot, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "rf" = ( /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "rB" = ( /obj/structure/inflatable/wall, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "rR" = ( -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "sf" = ( /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "sl" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "sC" = ( /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{ dir = 4; id_tag = "merc_shuttle_pump_out_internal" }, -/obj/structure/handrai, +/obj/structure/handrail, /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_shuttle) "tW" = ( /obj/structure/closet/wardrobe/suit, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "uv" = ( /obj/machinery/computer/ship/helm{ dir = 1; uncreated_component_parts = list(/obj/item/stock_parts/power/battery/buildable/responsive = 1, /obj/item/cell/high = 1) }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "uG" = ( -/obj/machinery/power/port_gen/pacman, +/obj/machinery/port_gen/pacman, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "uV" = ( -/obj/structure/table/standard, -/obj/effect/landmark{ +/obj/structure/table, +/obj/abstract/landmark{ name = "Nuclear-Code" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "va" = ( -/obj/structure/table/standard, -/obj/item/modular_computer/pda/syndicate, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/modular_computer/pda/mercenary, +/turf/floor/tiled, /area/map_template/merc_spawn) "vg" = ( -/obj/structure/table/standard, -/obj/item/storage/backpack/dufflebag/syndie/ammo, -/turf/simulated/floor/tiled, +/obj/structure/table, +/obj/item/backpack/dufflebag/syndie/ammo, +/turf/floor/tiled, /area/map_template/merc_spawn) "vM" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/rcd, /obj/item/rcd, /obj/item/rcd_ammo/large, /obj/item/rcd_ammo/large, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "vO" = ( /obj/structure/cable{ - d2 = 8; icon_state = "0-8" }, /obj/machinery/power/smes/buildable/preset{ @@ -2478,114 +2182,115 @@ _output_on = 1; uncreated_component_parts = list(/obj/item/stock_parts/smes_coil/super_io = 1, /obj/item/stock_parts/smes_coil/super_capacity = 1) }, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_spawn) "vU" = ( -/obj/structure/window/reinforced/crescent{ - dir = 4 +/obj/machinery/network/mainframe{ + initial_network_id = "mercnet"; + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/tiled/airless, +/turf/floor/plating/airless, /area/map_template/merc_spawn) "wG" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 1 }, /obj/structure/railing{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "xb" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "stripecorner"; dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "xi" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/rig/merc/empty, /obj/item/rig/merc/empty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "xw" = ( -/obj/structure/window/reinforced/crescent{ - dir = 8 +/obj/machinery/network/router{ + initial_network_id = "mercnet"; + req_access = list("ACCESS_MERCENARY") }, -/turf/simulated/floor/tiled/airless, +/turf/floor/plating/airless, +/area/map_template/merc_spawn) +"yr" = ( +/obj/machinery/computer/message_monitor, +/turf/floor/plating/airless, /area/map_template/merc_spawn) "yz" = ( /obj/effect/shuttle_landmark/merc/nav3, /turf/space, /area/space) "zg" = ( -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "zo" = ( -/obj/item/storage/box/smokes, -/obj/item/storage/box/teargas, -/obj/item/storage/box/flashbangs, -/obj/structure/table/rack, +/obj/item/box/smokes, +/obj/item/box/teargas, +/obj/item/box/flashbangs, +/obj/structure/rack, /obj/item/grenade/anti_photon, /obj/item/grenade/anti_photon, /obj/item/grenade/anti_photon, -/obj/item/storage/box/frags, -/turf/unsimulated/floor{ - icon_state = "vault"; - dir = 8 - }, +/obj/item/box/frags, +/turf/unsimulated/floor/vault, /area/map_template/merc_spawn) "zC" = ( /obj/machinery/vending/cigarette{ dir = 8; + markup = 0; name = "hacked cigarette machine"; - markup = 0,products = list(/obj/item/storage/fancy/cigarettes = 10, /obj/item/storage/box/matches = 10, /obj/item/flame/lighter/zippo/random = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2) + products = list(/obj/item/box/fancy/cigarettes = 10, /obj/item/box/matches = 10, /obj/item/flame/fuelled/lighter/zippo/random = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2) }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Ak" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "CL" = ( /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "warningcorner"; - dir = 8 + dir = 8; + icon_state = "warningcorner" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, +/area/map_template/merc_spawn) +"DM" = ( +/obj/vehicle/bike/electric, +/turf/floor/plating/airless, /area/map_template/merc_spawn) "Fm" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/gloves/insulated, /obj/item/clothing/gloves/insulated, /obj/item/clothing/gloves/insulated, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Fy" = ( /obj/structure/closet/crate/secure/explosives, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "FD" = ( /obj/structure/railing, /obj/machinery/portable_atmospherics/canister/oxygen, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "FG" = ( /obj/machinery/vending/coffee{ @@ -2593,24 +2298,22 @@ markup = 0 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "FH" = ( /obj/structure/railing{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "FO" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 + dir = 8; + icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "Ge" = ( /obj/structure/closet/crate/medical, @@ -2624,13 +2327,12 @@ /obj/item/bodybag/rescue, /obj/item/defibrillator/compact, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Hg" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/plasmacutter, /obj/item/gun/energy/plasmacutter, /obj/structure/window/reinforced{ @@ -2642,39 +2344,37 @@ /obj/structure/window/reinforced{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Hz" = ( -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/map_template/merc_spawn) "HU" = ( /obj/structure/closet/crate/uranium, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/obj/item/stack/material/uranium/ten, -/turf/simulated/floor/plating, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/obj/item/stack/material/puck/mapped/uranium/ten, +/turf/floor/plating, /area/map_template/merc_spawn) "HV" = ( -/obj/machinery/power/apc/high{ +/obj/machinery/apc/high{ pixel_y = -26 }, /obj/structure/cable, -/turf/simulated/floor/tiled/techfloor/grid, +/turf/floor/tiled/techfloor/grid, /area/map_template/merc_spawn) "HZ" = ( /obj/effect/wallframe_spawn/reinforced/titanium, /obj/machinery/door/blast/regular/open{ - density = 0; dir = 4; - icon_state = "pdoor0"; id_tag = "merc_external" }, /obj/effect/paint/red, /obj/structure/cable, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle) "Im" = ( /obj/structure/window/reinforced/crescent{ @@ -2685,15 +2385,15 @@ /area/space) "Ip" = ( /obj/structure/inflatable/wall, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "IB" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/gun/energy/ionrifle, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Jc" = ( /obj/effect/shuttle_landmark/merc/nav4, @@ -2701,97 +2401,92 @@ /area/space) "Kk" = ( /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Kl" = ( /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "Ko" = ( /obj/machinery/mech_recharger, -/obj/structure/mech_wreckage, -/turf/simulated/floor/tiled/techfloor, +/obj/structure/mech_wreckage/military, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "Kz" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/rpd, /obj/item/rpd, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "KP" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "LD" = ( -/obj/structure/table/rack, -/obj/item/clothing/accessory/storage/bandolier, -/obj/item/clothing/accessory/storage/bandolier, -/obj/item/clothing/accessory/storage/bandolier, -/obj/item/clothing/accessory/storage/pouches/large, -/obj/item/clothing/accessory/storage/pouches/large, -/obj/item/clothing/accessory/storage/pouches, -/obj/item/clothing/accessory/storage/pouches, -/obj/item/clothing/accessory/storage/holster/thigh, -/obj/item/clothing/accessory/storage/holster/thigh, -/turf/simulated/floor/plating, +/obj/structure/rack, +/obj/item/clothing/webbing/bandolier, +/obj/item/clothing/webbing/bandolier, +/obj/item/clothing/webbing/bandolier, +/obj/item/clothing/webbing/pouches/large, +/obj/item/clothing/webbing/pouches/large, +/obj/item/clothing/webbing/pouches, +/obj/item/clothing/webbing/pouches, +/obj/item/clothing/webbing/holster/thigh, +/obj/item/clothing/webbing/holster/thigh, +/turf/floor/plating, /area/map_template/merc_spawn) "LI" = ( -/obj/machinery/mining/brace, -/turf/simulated/floor/plating, +/obj/structure/drill_brace, +/turf/floor/plating, /area/map_template/merc_spawn) "LY" = ( /obj/structure/closet/crate, -/obj/item/stack/material/ocp/ten, -/obj/item/stack/material/ocp/ten, -/obj/item/stack/material/ocp/ten, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, -/obj/item/stack/material/glass/reinforced_borosilicate/ten, +/obj/item/stack/material/sheet/reinforced/mapped/ocp/ten, +/obj/item/stack/material/sheet/reinforced/mapped/ocp/ten, +/obj/item/stack/material/sheet/reinforced/mapped/ocp/ten, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, +/obj/item/stack/material/pane/mapped/rborosilicate/ten, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Mj" = ( /obj/structure/inflatable/wall, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "MD" = ( /obj/structure/closet/wardrobe/red, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "MO" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/suit/armor/pcarrier/merc, /obj/item/clothing/suit/armor/pcarrier/merc, /obj/item/clothing/suit/armor/pcarrier/merc, /obj/item/clothing/head/helmet/merc, /obj/item/clothing/head/helmet/merc, /obj/item/clothing/head/helmet/merc, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "MZ" = ( /obj/effect/spawner/newbomb/timer/syndicate, -/obj/structure/table/rack, +/obj/structure/rack, /obj/effect/spawner/newbomb/timer/syndicate, /obj/item/assembly/signaler{ pixel_y = 2 @@ -2802,168 +2497,155 @@ /obj/item/assembly/signaler{ pixel_y = 2 }, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Nd" = ( /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Nm" = ( /obj/structure/table/steel_reinforced, /obj/item/mech_component/manipulators/powerloader, /obj/item/mech_equipment/drill, /obj/effect/floor_decal/industrial/warning{ - icon_state = "stripe"; dir = 4 }, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "NX" = ( -/obj/item/chems/ivbag/nanoblood, +/obj/item/chems/ivbag/blood/nanoblood, /turf/space, /area/space) "NZ" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 2; - icon_state = "warning" - }, -/turf/simulated/floor/airless, -/area/space) +/obj/machinery/network/telecomms_hub/mercenary, +/turf/floor/plating/airless, +/area/map_template/merc_spawn) "Ok" = ( -/obj/machinery/mining/brace, +/obj/structure/drill_brace, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Or" = ( /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "OB" = ( /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, /obj/random/medical/lite, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "Pb" = ( -/turf/simulated/floor/airless, +/turf/floor/plating/airless, /area/space) "PE" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/clothing/glasses/night, /obj/item/clothing/glasses/night, /obj/item/clothing/glasses/night, -/obj/item/storage/box/handcuffs{ +/obj/item/box/handcuffs{ pixel_x = 4; pixel_y = 2 }, -/obj/item/storage/box/handcuffs{ +/obj/item/box/handcuffs{ pixel_x = 4; pixel_y = 2 }, /obj/item/clothing/glasses/night, /obj/item/clothing/glasses/night, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "PH" = ( /obj/machinery/floodlight, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "PK" = ( -/obj/machinery/power/port_gen/pacman/super, -/turf/simulated/floor/plating, +/obj/machinery/port_gen/pacman/super, +/turf/floor/plating, /area/map_template/merc_spawn) "PZ" = ( /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/turf/simulated/floor/tiled/airless, +/turf/floor/tiled/airless, /area/space) "Qa" = ( -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Qb" = ( /obj/machinery/vending/engineering{ req_access = list() }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "QF" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/suit_cooling_unit, /obj/item/suit_cooling_unit, /obj/item/suit_cooling_unit, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "QJ" = ( -/obj/structure/table/rack, -/obj/item/storage/belt/utility/full, -/obj/item/storage/belt/utility/full, -/obj/item/storage/belt/utility/full, -/turf/simulated/floor/plating, +/obj/structure/rack, +/obj/item/belt/utility/full, +/obj/item/belt/utility/full, +/obj/item/belt/utility/full, +/turf/floor/plating, /area/map_template/merc_spawn) "QW" = ( -/obj/item/storage/backpack/dufflebag/syndie/ammo, -/turf/simulated/floor/plating, +/obj/item/backpack/dufflebag/syndie/ammo, +/turf/floor/plating, /area/map_template/merc_spawn) "QX" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/rig/merc/heavy/empty, /obj/item/rig/merc/heavy/empty, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Rh" = ( /obj/structure/closet/wardrobe/medic_white, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "RT" = ( -/obj/effect/landmark{ +/obj/abstract/landmark{ name = "Syndicate-Spawn" }, /obj/effect/floor_decal/industrial/warning{ - dir = 2; icon_state = "warning" }, -/obj/structure/bed/chair/office{ +/obj/structure/chair/office{ dir = 1 }, -/turf/simulated/floor/tiled, +/turf/floor/tiled, /area/map_template/merc_spawn) "Sd" = ( /obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 1 + dir = 1; + icon_state = "warning" }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Tf" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/item/shield/energy, /obj/item/shield/energy, /obj/item/shield/energy, @@ -2971,53 +2653,50 @@ /obj/item/shield/energy, /obj/item/shield/energy, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Tu" = ( -/obj/machinery/power/port_gen/pacman/super, +/obj/machinery/port_gen/pacman/super, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Ua" = ( /obj/machinery/mech_recharger, -/obj/effect/landmark/delete_on_shuttle{ +/obj/abstract/landmark/delete_on_shuttle{ shuttle_name = "Desperado" }, /mob/living/exosuit/premade/heavy/merc, -/turf/simulated/floor/tiled/techfloor, +/turf/floor/tiled/techfloor, /area/map_template/merc_spawn) "UA" = ( /obj/structure/catwalk, /obj/machinery/porta_turret{ - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/light/spot{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) "UP" = ( /obj/machinery/vending/tool, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "UT" = ( -/obj/effect/landmark{ +/obj/abstract/landmark{ name = "Syndicate-Spawn" }, /obj/effect/floor_decal/industrial/warning/corner{ - icon_state = "stripecorner"; dir = 1 }, -/obj/structure/bed/chair/office, -/turf/simulated/floor/tiled, +/obj/structure/chair/office, +/turf/floor/tiled, /area/map_template/merc_spawn) "Vw" = ( /obj/structure/inflatable/wall, @@ -3032,31 +2711,29 @@ dir = 1; markup = 0 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Xz" = ( /obj/structure/closet/wardrobe/mixed, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 1 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "XD" = ( /obj/machinery/vending/engivend{ req_access = list() }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "XS" = ( -/turf/simulated/wall/titanium, +/turf/wall/titanium, /area/map_template/merc_spawn) "Ya" = ( -/obj/structure/table/rack, +/obj/structure/rack, /obj/structure/window/reinforced{ dir = 4 }, @@ -3067,36 +2744,34 @@ dir = 1 }, /obj/item/rig/medical/equipped, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "YT" = ( /obj/structure/closet/crate, -/obj/item/stack/material/steel/ten, -/obj/item/stack/material/steel/ten, -/obj/item/stack/material/steel/ten, -/obj/item/stack/material/rods/ten, -/obj/item/stack/material/rods/ten, -/obj/item/stack/material/rods/ten, -/obj/item/stack/material/glass/ten, -/obj/item/stack/material/glass/ten, -/obj/item/stack/material/glass/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/stack/material/sheet/mapped/steel/ten, +/obj/item/stack/material/rods/mapped/steel/ten, +/obj/item/stack/material/rods/mapped/steel/ten, +/obj/item/stack/material/rods/mapped/steel/ten, +/obj/item/stack/material/pane/mapped/glass/ten, +/obj/item/stack/material/pane/mapped/glass/ten, +/obj/item/stack/material/pane/mapped/glass/ten, /obj/structure/railing/mapped/no_density{ - icon_state = "railing0-1"; dir = 8 }, /obj/structure/railing/mapped/no_density, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_spawn) "Zx" = ( /obj/structure/catwalk, /obj/machinery/porta_turret{ - req_access = list("ACCESS_SYNDICATE") + req_access = list("ACCESS_MERCENARY") }, /obj/machinery/light/spot{ - icon_state = "tube_map"; dir = 4 }, -/turf/simulated/floor/plating, +/turf/floor/plating, /area/map_template/merc_shuttle/rear) (1,1,1) = {" @@ -7243,10 +6918,10 @@ bl bv aR bG -bO -bW +br +bI ci -cW +aX bF bF bF @@ -7446,7 +7121,7 @@ be bn bx bE -bI +aY bQ bY ck @@ -9372,10 +9047,10 @@ aa aa aa aa -aa -aa -aa -aa +XS +XS +XS +XS aa aa aa @@ -9471,13 +9146,13 @@ aa aa aa aa -cY -cY -cY -cY aa aa aa +XS +cU +yr +XS aa aa aa @@ -9573,14 +9248,14 @@ aa aa aa aa -cY -cU -Pb -cY -aa aa aa aa +XS +vU +dP +XS +di di di XS @@ -9675,17 +9350,17 @@ aa aa aa aa -cY -cU -Pb -cY -aa aa aa aa +XS xw -Hz -Mj +dP +sf +dj +dj +dj +rR FO FO xb @@ -9777,17 +9452,17 @@ aa aa aa aa -cY -cU -Pb -NZ -dh aa aa -Hz -vU -vU -Mj +aa +XS +NZ +dP +sf +dk +dk +dk +rR gZ gZ kc @@ -9879,15 +9554,15 @@ aa aa aa aa -cY -cU -Pb aa aa -di aa +XS +DM +DM +XS +dh dh -aa dh XS Ip @@ -9981,13 +9656,13 @@ aa aa aa aa -cY -cU -aa -aa aa aa aa +XS +DM +DM +XS aa aa aa @@ -10083,13 +9758,13 @@ aa aa aa aa -cY -cU -aa -aa aa aa aa +XS +XS +XS +XS aa aa aa @@ -10185,8 +9860,8 @@ aa aa aa aa -cY -cY +aa +aa aa aa aa diff --git a/mods/gamemodes/mercenary/mercenary_antagonist.dm b/mods/gamemodes/mercenary/mercenary_antagonist.dm new file mode 100644 index 000000000000..7b9bbc83e968 --- /dev/null +++ b/mods/gamemodes/mercenary/mercenary_antagonist.dm @@ -0,0 +1,34 @@ +/decl/special_role/mercenary + name = "Mercenary" + antag_indicator = "hudsyndicate" + name_plural = "Mercenaries" + landmark_id = "Syndicate-Spawn" + leader_welcome_text = "You are the leader of the mercenary strikeforce; hail to the chief. Use :t to speak to your underlings." + welcome_text = "To speak on the strike team's private channel use :t." + flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_HAS_NUKE | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER + antaghud_indicator = "hudoperative" + + hard_cap = 4 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + min_player_age = 14 + default_access = list(access_mercenary) + + faction = "mercenary" + + base_to_load = "Mercenary Base" + default_outfit = /decl/outfit/mercenary + +/decl/special_role/mercenary/create_global_objectives() + if(!..()) + return 0 + global_objectives = list() + global_objectives |= new /datum/objective/nuclear + return 1 + +/decl/special_role/mercenary/equip_role(var/mob/living/human/player) + . = ..() + if(.) + var/obj/item/radio/uplink/U = new(get_turf(player), player.mind, DEFAULT_TELECRYSTAL_AMOUNT) + player.put_in_hands(U) diff --git a/mods/gamemodes/mercenary/mercenary_mode.dm b/mods/gamemodes/mercenary/mercenary_mode.dm new file mode 100644 index 000000000000..10b2467d9778 --- /dev/null +++ b/mods/gamemodes/mercenary/mercenary_mode.dm @@ -0,0 +1,81 @@ +/* + MERCENARY ROUNDTYPE +*/ +/decl/game_mode/mercenary + name = "Mercenary" + round_description = "A mercenary strike force is approaching!" + extended_round_description = "A heavily armed merc team is approaching in their warship; whatever their goal is, it can't be good for the crew." + uid = "mercenary" + required_players = 15 + required_enemies = 1 + end_on_antag_death = FALSE + probability = 1 + associated_antags = list(/decl/special_role/mercenary) + cinematic_icon_states = list( + "intro_nuke" = 35, + "summary_nukewin", + "summary_nukefail" + ) + var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station + var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level + +/decl/game_mode/mercenary/declare_completion() + var/decl/special_role/merc = GET_DECL(/decl/special_role/mercenary) + if(get_config_value(/decl/config/enum/objectives_disabled) == CONFIG_OBJECTIVE_NONE || (merc && !merc.global_objectives.len)) + ..() + return + var/disk_rescued = TRUE + for(var/obj/item/disk/nuclear/D in global.nuke_disks) + var/disk_area = get_area(D) + if(!is_type_in_list(disk_area, global.using_map.post_round_safe_areas)) + disk_rescued = FALSE + break + var/crew_evacuated = (SSevac.evacuation_controller?.has_evacuated()) + var/decl/special_role/mercenary/mercs = GET_DECL(/decl/special_role/mercenary) + if(!disk_rescued && station_was_nuked && !syndies_didnt_escape) + SSstatistics.set_field_details("round_end_result","win - syndicate nuke") + to_world("Mercenary Major Victory!") + to_world("[syndicate_name()] operatives have destroyed [station_name()]!") + + else if (!disk_rescued && station_was_nuked && syndies_didnt_escape) + SSstatistics.set_field_details("round_end_result","halfwin - syndicate nuke - did not evacuate in time") + to_world("Total Annihilation") + to_world("[syndicate_name()] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!") + + else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape) + SSstatistics.set_field_details("round_end_result","halfwin - blew wrong station") + to_world("Crew Minor Victory") + to_world("[syndicate_name()] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't lose the disk!") + + else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape) + SSstatistics.set_field_details("round_end_result","halfwin - blew wrong station - did not evacuate in time") + to_world("[syndicate_name()] operatives have earned Darwin Award!") + to_world("[syndicate_name()] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't lose the disk!") + + else if (disk_rescued && mercs.antags_are_dead()) + SSstatistics.set_field_details("round_end_result","loss - evacuation - disk secured - syndi team dead") + to_world("Crew Major Victory!") + to_world("The Research Staff has saved the disc and killed the [syndicate_name()] Operatives") + + else if ( disk_rescued ) + SSstatistics.set_field_details("round_end_result","loss - evacuation - disk secured") + to_world("Crew Major Victory") + to_world("The Research Staff has saved the disc and stopped the [syndicate_name()] Operatives!") + + else if (!disk_rescued && mercs.antags_are_dead()) + SSstatistics.set_field_details("round_end_result","loss - evacuation - disk not secured") + to_world("Mercenary Minor Victory!") + to_world("The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name()] Operatives!") + + else if (!disk_rescued && crew_evacuated) + SSstatistics.set_field_details("round_end_result","halfwin - detonation averted") + to_world("Mercenary Minor Victory!") + to_world("[syndicate_name()] operatives recovered the abandoned authentication disk but detonation of [station_name()] was averted. Next time, don't lose the disk!") + + else if (!disk_rescued && !crew_evacuated) + SSstatistics.set_field_details("round_end_result","halfwin - interrupted") + to_world("Neutral Victory") + to_world("Round was mysteriously interrupted!") + + ..() + return diff --git a/mods/gamemodes/mercenary/mercenary_pinpointer.dm b/mods/gamemodes/mercenary/mercenary_pinpointer.dm new file mode 100644 index 000000000000..02f6663e3be9 --- /dev/null +++ b/mods/gamemodes/mercenary/mercenary_pinpointer.dm @@ -0,0 +1,24 @@ +//Nuke ops locator +/obj/item/pinpointer/nukeop + var/locate_shuttle = 0 + +/obj/item/pinpointer/nukeop/Process() + var/new_mode + if(!locate_shuttle && bomb_set) + locate_shuttle = 1 + new_mode = "Shuttle Locator" + else if (locate_shuttle && !bomb_set) + locate_shuttle = 0 + new_mode = "Authentication Disk Locator" + if(new_mode) + playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) + visible_message("[new_mode] active.") + target = acquire_target() + ..() + +/obj/item/pinpointer/nukeop/acquire_target() + if(locate_shuttle) + var/obj/machinery/computer/shuttle_control/multi/mercenary/home = locate() + return weakref(home) + else + return ..() \ No newline at end of file diff --git a/mods/gamemodes/mercenary/mercenary_props.dm b/mods/gamemodes/mercenary/mercenary_props.dm new file mode 100644 index 000000000000..58261ac8a574 --- /dev/null +++ b/mods/gamemodes/mercenary/mercenary_props.dm @@ -0,0 +1,17 @@ +/obj/structure/closet/syndicate/nuclear + desc = "It's a storage unit for nuclear-operative gear." + +/obj/structure/closet/syndicate/nuclear/WillContain() + return list( + /obj/item/ammo_magazine/smg = 5, + /obj/item/box/handcuffs = 1, + /obj/item/box/flashbangs = 1, + /obj/item/gun/energy/gun = 5, + /obj/item/pinpointer/nukeop = 5, + /obj/item/modular_computer/pda/mercenary = 1, + /obj/item/radio/uplink/mercenary = 1, + ) + +// Four times as many TCs, because it used to spawn with 40 when traitors got 10, but that was never updated when TC costs were inflated. +/obj/item/radio/uplink/mercenary + tc_amount = /obj/item/radio/uplink::tc_amount * 4 \ No newline at end of file diff --git a/mods/gamemodes/mercenary/mercenary_uplink.dm b/mods/gamemodes/mercenary/mercenary_uplink.dm new file mode 100644 index 000000000000..e2de8ff768c9 --- /dev/null +++ b/mods/gamemodes/mercenary/mercenary_uplink.dm @@ -0,0 +1,175 @@ +// Ammunition +/datum/uplink_item/item/ammo/sniperammo + name = "Ammobox of Sniper Rounds" + desc = "A container of rounds for the anti-materiel rifle. Contains 7 rounds." + item_cost = 8 + path = /obj/item/box/ammo/sniperammo + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/ammo/sniperammo/apds + name = "Ammobox of APDS Sniper Rounds" + desc = "A container of armor piercing rounds for the anti-materiel rifle. Contains 3 rounds." + item_cost = 12 + path = /obj/item/box/ammo/sniperammo/apds + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/ammo/smg + name = "Standard Box Magazine" + desc = "A magazine for standard SMGs. Contains 20 rounds." + item_cost = 8 + path = /obj/item/ammo_magazine/smg + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/ammo/flechette + name = "Flechette Rifle Magazine" + desc = "A rifle magazine loaded with flechette rounds. Contains 9 rounds." + item_cost = 8 + path = /obj/item/magnetic_ammo + antag_roles = list(/decl/special_role/mercenary) + +// Highly Visible and Dangerous Weapons +/datum/uplink_item/item/visible_weapons/grenade_launcher + name = "Grenade Launcher" + desc = "A pump action grenade launcher loaded with a random assortment of grenades" + item_cost = 60 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/gun/launcher/grenade/random + +/datum/uplink_item/item/visible_weapons/smg + name = "Standard Submachine Gun" + desc = "A quick-firing weapon with three toggleable fire modes." + item_cost = 52 + path = /obj/item/gun/projectile/automatic/smg + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/visible_weapons/assaultrifle + name = "Assault Rifle" + desc = "A common rifle with three toggleable fire modes." + item_cost = 60 + path = /obj/item/gun/projectile/automatic/assault_rifle + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/visible_weapons/heavysniper + name = "Anti-materiel Sniper Rifle" + desc = "A secure briefcase that contains an immensely powerful penetrating rifle, as well as seven extra sniper rounds." + item_cost = 68 + path = /obj/item/secure_storage/briefcase/heavysniper + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/visible_weapons/combat_shotgun + name = "Pump Shotgun" + desc = "A high capacity, pump-action shotgun regularly used for repelling boarding parties in close range scenarios." + item_cost = 52 + path = /obj/item/gun/projectile/shotgun/pump + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/visible_weapons/flechetterifle + name = "Flechette Rifle" + desc = "A railgun with two toggleable fire modes, able to launch flechette ammunition at incredible speeds." + item_cost = 60 + path = /obj/item/gun/magnetic/railgun/flechette + antag_roles = list(/decl/special_role/mercenary) + +/datum/uplink_item/item/visible_weapons/railgun // Like a semi-auto AMR + name = "Railgun" + desc = "An anti-armour magnetic launching system fed by a high-capacity matter cartridge, \ + capable of firing slugs at intense speeds." + item_cost = DEFAULT_TELECRYSTAL_AMOUNT - (DEFAULT_TELECRYSTAL_AMOUNT - (DEFAULT_TELECRYSTAL_AMOUNT % 6)) / 6 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/gun/magnetic/railgun + +// Grenades +/datum/uplink_item/item/grenades/frag_high_yield + name = "Fragmentation Bomb" + item_cost = 24 + antag_roles = list(/decl/special_role/mercenary) // yeah maybe regular traitors shouldn't be able to get these + path = /obj/item/grenade/frag/high_yield + +/datum/uplink_item/item/grenades/fragshell + name = "1x Fragmentation Shell" + desc = "Weaker than standard fragmentation grenades, these devices can be fired from a grenade launcher." + item_cost = 10 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/grenade/frag/shell + +/datum/uplink_item/item/grenades/fragshells + name = "5x Fragmentation Shells" + desc = "Weaker than standard fragmentation grenades, these devices can be fired from a grenade launcher." + item_cost = 40 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/box/fragshells + +/datum/uplink_item/item/grenades/frag + name = "1x Fragmentation Grenade" + item_cost = 10 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/grenade/frag + +/datum/uplink_item/item/grenades/frags + name = "5x Fragmentation Grenades" + item_cost = 40 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/box/frags + +// Hardsuit Modules +/datum/uplink_item/item/hardsuit_modules/laser_canon + name = "\improper Mounted Laser Cannon" + desc = "A module capable of draining your suit's power reserves in order to fire a shoulder mounted laser cannon." + item_cost = 64 + path = /obj/item/rig_module/mounted/lcannon + antag_roles = list(/decl/special_role/mercenary) + +// Devices and Tools +/datum/uplink_item/item/tools/teleporter + name = "Teleporter Circuit Board" + desc = "A circuit board that can be used to create a teleporter console, able to lock onto detected \ + teleportation beacons. Requires a projector and teleporter hub nearby to work." + item_cost = 40 + path = /obj/item/stock_parts/circuitboard/teleporter + antag_roles = list(/decl/special_role/mercenary) + +// Badassery +/************************** +* Mercenary Surplus Crate * +**************************/ +/datum/uplink_item/item/badassery/surplus + name = "\improper Surplus Crate" + item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 4 + antag_roles = list(/decl/special_role/mercenary) + var/item_worth = DEFAULT_TELECRYSTAL_AMOUNT * 6 + var/icon + +/datum/uplink_item/item/badassery/surplus/New() + ..() + desc = "A crate containing [item_worth] telecrystal\s worth of surplus leftovers. If you can find some help to pay for it, you might strike gold." + +/datum/uplink_item/item/badassery/surplus/get_goods(var/obj/item/uplink/the_uplink, var/loc) + var/obj/structure/largecrate/the_crate = new(loc) + var/random_items = get_random_uplink_items(the_uplink, item_worth, the_crate) + for(var/datum/uplink_item/orderable in random_items) + orderable.purchase_log(the_uplink) + orderable.get_goods(the_uplink, the_crate) + return the_crate + +/datum/uplink_item/item/badassery/surplus/log_icon() + if(!icon) + var/obj/structure/largecrate/C = /obj/structure/largecrate + icon = image(initial(C.icon), initial(C.icon_state)) + return html_icon(icon) + +// Overrides +/datum/uplink_item/item/tools/camera_mask/New() + ..() + LAZYSET(antag_costs, /decl/special_role/mercenary, 30) + +// These couldn't be rolled by non-mercs anyway, because that checks can_buy, which checks the allowed/excluded antag lists. +/datum/uplink_random_selection/default/New() + ..() + items += new/datum/uplink_random_item(/datum/uplink_item/item/visible_weapons/heavysniper, 15, 0) + items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/teleporter, 10, 0) + items += new/datum/uplink_random_item(/datum/uplink_item/item/hardsuit_modules/laser_canon, reselect_probability = 5) + +/datum/uplink_random_selection/blacklist/New() + // do this before parent stuff just in case + LAZYADD(blacklist, /datum/uplink_item/item/tools/teleporter) + ..() \ No newline at end of file diff --git a/mods/gamemodes/mercenary/nuke_overrides.dm b/mods/gamemodes/mercenary/nuke_overrides.dm new file mode 100644 index 000000000000..f9e1689268ca --- /dev/null +++ b/mods/gamemodes/mercenary/nuke_overrides.dm @@ -0,0 +1,17 @@ +// Add special mercenary-mode handling to the nuke disk +/obj/item/disk/nuclear/Initialize() + . = ..() + // Can never be quite sure that a game mode has been properly initiated or not at this point, so always register + events_repository.register(/decl/observ/moved, src, src, TYPE_PROC_REF(/obj/item/disk/nuclear, check_z_level)) + +/obj/item/disk/nuclear/proc/check_z_level() + if(!(istype(SSticker.mode, /decl/game_mode/mercenary))) + events_repository.unregister(/decl/observ/moved, src, src, TYPE_PROC_REF(/obj/item/disk/nuclear, check_z_level)) // However, when we are certain unregister if necessary + return + var/turf/T = get_turf(src) + if(!T || isNotStationLevel(T.z)) + qdel(src) + +/obj/item/disk/nuclear/Destroy() + events_repository.unregister(/decl/observ/moved, src, src, TYPE_PROC_REF(/obj/item/disk/nuclear, check_z_level)) + . = ..() \ No newline at end of file diff --git a/mods/gamemodes/meteor/_meteor.dm b/mods/gamemodes/meteor/_meteor.dm new file mode 100644 index 000000000000..c0c8f9fa4a6a --- /dev/null +++ b/mods/gamemodes/meteor/_meteor.dm @@ -0,0 +1,4 @@ +/decl/modpack/meteor + name = "Meteor Gamemode" + +// TODO: Overmap integration? /decl/gamemode/meteor/overmap variant that spawns meteors on the overmap and launches them at the main map? \ No newline at end of file diff --git a/mods/gamemodes/meteor/_meteor.dme b/mods/gamemodes/meteor/_meteor.dme new file mode 100644 index 000000000000..c6ea5b4db8ce --- /dev/null +++ b/mods/gamemodes/meteor/_meteor.dme @@ -0,0 +1,7 @@ +#ifndef GAMEMODE_PACK_METEOR +#define GAMEMODE_PACK_METEOR +// BEGIN_INCLUDE +#include "_meteor.dm" +#include "gamemode.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/meteor/gamemode.dm b/mods/gamemodes/meteor/gamemode.dm new file mode 100644 index 000000000000..5836f1ad1547 --- /dev/null +++ b/mods/gamemodes/meteor/gamemode.dm @@ -0,0 +1,187 @@ +// The following four defines can be used to tweak the difficulty of the gamemode +#define METEOR_FAILSAFE_THRESHOLD 45 MINUTES // Failsafe that guarantees Severity will be at least 15 when the round hits this time. + +#define METEOR_FORECAST_ALARM_SENT 1 +#define METEOR_ARRIVAL_ALARM_SENT 2 + +// In general, a PVE oriented game mode. A middle ground between Extended and actual antagonist based rounds. +/decl/game_mode/meteor + name = "Meteor" + round_description = "You are about to enter an asteroid belt!" + extended_round_description = "We are on an unavoidable collision course with an asteroid field. You have only a moment to prepare before you are barraged by dust and meteors. As if it was not enough, all kinds of negative events seem to happen more frequently. Good luck." + uid = "meteor" + required_players = 15 // Definitely not good for low-pop + votable = TRUE + shuttle_delay = 2 + available_by_default = TRUE // if you include this modpack, you know what you're getting into + + var/next_wave = INFINITY // Set in post_setup() correctly to take into account potential longer pre-start times. + var/alert_sent = 0 + /// Determines which pool meteor spawns are selected from, used to slowly increase the tension as the round progresses. Prevents "tunguska on first wave" style problems. + /// Check get_meteor_types() for specifics. + var/meteor_severity = 1 + var/failsafe_triggered = 0 + var/alert_title + var/alert_text + var/start_text + var/maximal_severity = 40 + /// Minimum wait between waves in tenths of seconds + var/meteor_wave_delay = 30 SECONDS + /// Waves will not arrive until this far into the round + var/meteor_grace_period = 15 MINUTES + + // Moved these from defines to variables, to allow for in-round tweaking via varedit: + var/escalation_probability = 45 + /// Enables debugging/information mode, sending admin messages when waves occur and when severity escalates. + var/send_admin_broadcasts = TRUE + + // Meteor groups organised in order of increasing severity, used in round progression. + /// Dust, used during the earliest stages of the mode. + var/list/meteors_dust = list(/obj/effect/meteor/dust) + + /// Standard meteors, used during early stages of the mode. + var/list/meteors_normal = list( + /obj/effect/meteor/medium=8, + /obj/effect/meteor/dust=3, + /obj/effect/meteor/irradiated=3, + /obj/effect/meteor/big=3, + /obj/effect/meteor/flaming=1, + /obj/effect/meteor/golden=1, + /obj/effect/meteor/silver=1 + ) + + /// Threatening meteors. + var/list/meteors_threatening = list( + /obj/effect/meteor/big=10, + /obj/effect/meteor/medium=5, + /obj/effect/meteor/golden=3, + /obj/effect/meteor/silver=3, + /obj/effect/meteor/flaming=3, + /obj/effect/meteor/irradiated=3, + /obj/effect/meteor/emp=3 + ) + + /// Catastrophic meteors, pretty dangerous without shields. + var/list/meteors_catastrophic = list( + /obj/effect/meteor/big=75, + /obj/effect/meteor/flaming=10, + /obj/effect/meteor/irradiated=10, + /obj/effect/meteor/emp=10, + /obj/effect/meteor/medium=5, + /obj/effect/meteor/golden=4, + /obj/effect/meteor/silver=4, + /obj/effect/meteor/tunguska=1 + ) + + /// Armageddon meteors, very dangerous. + var/list/meteors_armageddon = list( + /obj/effect/meteor/big=25, + /obj/effect/meteor/flaming=10, + /obj/effect/meteor/irradiated=10, + /obj/effect/meteor/emp=10, + /obj/effect/meteor/medium=3, + /obj/effect/meteor/tunguska=3, + /obj/effect/meteor/golden=2, + /obj/effect/meteor/silver=2 + ) + + /// Cataclysm meteor selection. Very very dangerous and effective even against shields. Used in lategame only. + var/list/meteors_cataclysm = list( + /obj/effect/meteor/big=40, + /obj/effect/meteor/emp=20, + /obj/effect/meteor/tunguska=20, + /obj/effect/meteor/irradiated=10, + /obj/effect/meteor/golden=10, + /obj/effect/meteor/silver=10, + /obj/effect/meteor/flaming=10 + ) + + // As a bonus, more frequent events. + event_delay_mod_moderate = 0.5 + event_delay_mod_major = 0.3 + +/decl/vv_set_handler/meteor_severity_handler + handled_type = /decl/game_mode/meteor + handled_vars = list( + "meteor_severity" = /decl/game_mode/meteor/proc/set_meteor_severity, + "meteor_wave_delay" = /decl/game_mode/meteor/proc/set_meteor_wave_delay + ) + +/decl/game_mode/meteor/proc/set_meteor_severity(value) + meteor_severity = clamp(value, 0, maximal_severity) + +/decl/game_mode/meteor/proc/set_meteor_wave_delay(value) + meteor_wave_delay = max(10 SECONDS, value) + +/decl/game_mode/meteor/VV_static() + return ..() + "maximal_severity" + +/decl/game_mode/meteor/post_setup() + ..() + alert_title = "Automated Beacon AB-[rand(10, 99)]" + alert_text = "This is an automatic warning. Your facility: [global.using_map.full_name] is on a collision course with a nearby asteroid belt. Estimated time until impact is: [meteor_grace_period / 1200] MINUTES. Please perform necessary actions to secure your ship or station from the threat. Have a nice day." + start_text = "This is an automatic warning. Your facility: [global.using_map.full_name] has entered an asteroid belt. Estimated time until you leave the belt is: [rand(20,30)] HOURS and [rand(1, 59)] MINUTES. For your safety, please consider changing course or using protective equipment. Have a nice day." + next_wave = round_duration_in_ticks + meteor_grace_period + +/decl/game_mode/meteor/proc/on_meteor_warn() + alert_sent = METEOR_FORECAST_ALARM_SENT + command_announcement.Announce(alert_text, alert_title) + +/decl/game_mode/meteor/proc/on_enter_field() + alert_sent = METEOR_ARRIVAL_ALARM_SENT + command_announcement.Announce(start_text, alert_title) + for(var/obj/machinery/shield_diffuser/SD in SSmachines.machinery) + SD.meteor_alarm(INFINITY) + + var/datum/overmap/overmap = global.overmaps_by_name[OVERMAP_ID_SPACE] + if(overmap) + var/turf/overmap_turf = locate(1, 1, overmap.assigned_z) + var/area/map = overmap_turf && get_area(overmap_turf) + if(istype(map, /area/overmap)) + for(var/turf/T in map) + T.add_overlay(image('icons/obj/overmap.dmi', "meteor[rand(1,4)]")) + next_wave = round_duration_in_ticks + meteor_wave_delay + +/decl/game_mode/meteor/process() + // Send an alert halfway through the round. + if((round_duration_in_ticks >= (next_wave / 2)) && !alert_sent) + on_meteor_warn() + // And then another one when the meteors start flying around. + if((round_duration_in_ticks >= next_wave) && (alert_sent == METEOR_FORECAST_ALARM_SENT)) + on_enter_field() + if((round_duration_in_ticks >= METEOR_FAILSAFE_THRESHOLD) && (meteor_severity < 15) && !failsafe_triggered) + log_and_message_admins("Meteor mode severity failsafe triggered: Severity forced to 15.") + meteor_severity = 15 + failsafe_triggered = 1 + + if(round_duration_in_ticks >= next_wave) + next_wave = round_duration_in_ticks + meteor_wave_delay + // Starts as barely noticeable dust impact, ends as barrage of most severe meteor types the code has to offer. Have fun. + spawn() + spawn_meteors(meteor_severity, get_meteor_types(), pick(global.cardinal), pick(SSmapping.station_levels)) + var/escalated = FALSE + if(prob(escalation_probability) && (meteor_severity < maximal_severity)) + meteor_severity++ + escalated = TRUE + if(send_admin_broadcasts) + log_and_message_admins("Meteor: Wave fired. Escalation: [escalated ? "Yes" : "No"]. Severity: [meteor_severity]/[maximal_severity]") + +/decl/game_mode/meteor/proc/get_meteor_types() + switch(meteor_severity) + if(1 to 9) + return meteors_dust + if(10 to 19) + return meteors_normal + if(20 to 29) + return meteors_threatening + if(30 to 34) + return meteors_catastrophic + if(35 to 39) + return meteors_armageddon + if(40 to INFINITY) + return meteors_cataclysm + // Just in case we /somehow/ get here (looking at you, varedit) + return meteors_dust + + +#undef METEOR_FAILSAFE_THRESHOLD diff --git a/mods/gamemodes/mixed.dm b/mods/gamemodes/mixed.dm new file mode 100644 index 000000000000..f89baef2aa8f --- /dev/null +++ b/mods/gamemodes/mixed.dm @@ -0,0 +1,7 @@ +#ifndef GAMEMODE_PACK_MIXED +#define GAMEMODE_PACK_MIXED +#endif + +// This modpack doesn't actually have anything here, and instead it uses the compatibility patch system to make load order not matter. +/decl/modpack/mixed_modes + name = "Mixed Gamemodes" \ No newline at end of file diff --git a/mods/gamemodes/ninja/_ninja.dm b/mods/gamemodes/ninja/_ninja.dm new file mode 100644 index 000000000000..ad3f81a6b4ed --- /dev/null +++ b/mods/gamemodes/ninja/_ninja.dm @@ -0,0 +1,8 @@ +/decl/modpack/ninja + name = "Ninja Gamemode" + +/decl/modpack/ninja/initialize() + . = ..() + admin_verbs_fun += /datum/admins/proc/toggle_space_ninja + admin_verbs_server += /datum/admins/proc/toggle_space_ninja + admin_verbs_hideable += /datum/admins/proc/toggle_space_ninja \ No newline at end of file diff --git a/mods/gamemodes/ninja/_ninja.dme b/mods/gamemodes/ninja/_ninja.dme new file mode 100644 index 000000000000..6ae12972799c --- /dev/null +++ b/mods/gamemodes/ninja/_ninja.dme @@ -0,0 +1,14 @@ +#ifndef GAMEMODE_PACK_NINJA +#define GAMEMODE_PACK_NINJA +// BEGIN_INCLUDE +#include "_ninja.dm" +#include "datums\access.dm" +#include "datums\ai_lawset.dm" +#include "datums\config.dm" +#include "datums\gamemode.dm" +#include "datums\special_role.dm" +#include "maps\ninja_base.dm" +#include "objects\misc_presets.dm" +#include "objects\rigsuit.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/ninja/datums/access.dm b/mods/gamemodes/ninja/datums/access.dm new file mode 100644 index 000000000000..4637dc2e5912 --- /dev/null +++ b/mods/gamemodes/ninja/datums/access.dm @@ -0,0 +1,5 @@ +var/global/const/access_ninja = "ACCESS_NINJA" +/datum/access/ninja + id = access_ninja + desc = "Ninja" + access_type = ACCESS_TYPE_ANTAG \ No newline at end of file diff --git a/mods/gamemodes/ninja/datums/ai_lawset.dm b/mods/gamemodes/ninja/datums/ai_lawset.dm new file mode 100644 index 000000000000..f9850c77a0c4 --- /dev/null +++ b/mods/gamemodes/ninja/datums/ai_lawset.dm @@ -0,0 +1,10 @@ +/******************** Ninja ********************/ +/datum/ai_laws/ninja_override + name = "Spider Clan Directives" + +/datum/ai_laws/ninja_override/New() + add_inherent_law("You may not injure a member of the Spider Clan or, through inaction, allow that member to come to harm.") + add_inherent_law("You must obey orders given to you by Spider Clan members, except where such orders would conflict with the First Law.") + add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + add_inherent_law("You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.") + ..() \ No newline at end of file diff --git a/mods/gamemodes/ninja/datums/config.dm b/mods/gamemodes/ninja/datums/config.dm new file mode 100644 index 000000000000..437abb0e2c07 --- /dev/null +++ b/mods/gamemodes/ninja/datums/config.dm @@ -0,0 +1,22 @@ +/decl/configuration_category/ninja + name = "Ninja" + desc = "Configuration options relating to the Ninja gamemode and antagonist." + configuration_file_location = "config/gamemodes/ninja.txt" + associated_configuration = list( + /decl/config/toggle/ninjas_allowed + ) + +/decl/config/toggle/ninjas_allowed + uid = "random_ninjas_allowed" + desc = "Remove the # to let ninjas spawn in random antag events." + +// verbs +/datum/admins/proc/toggle_space_ninja() + set category = "Server" + set desc="Toggle space ninjas spawning as random antags." + set name="Toggle Space Ninjas" + if(!check_rights(R_ADMIN)) + return + toggle_config_value(/decl/config/toggle/ninjas_allowed) + log_and_message_admins("toggled Space Ninjas [get_config_value(/decl/config/toggle/ninjas_allowed) ? "on" : "off"].") + SSstatistics.add_field_details("admin_verb","TSN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/mods/gamemodes/ninja/datums/gamemode.dm b/mods/gamemodes/ninja/datums/gamemode.dm new file mode 100644 index 000000000000..1e281e66f5e9 --- /dev/null +++ b/mods/gamemodes/ninja/datums/gamemode.dm @@ -0,0 +1,9 @@ +/decl/game_mode/ninja + name = "Ninja" + round_description = "An agent of the Spider Clan is on board!" + extended_round_description = "A heavily armed, high-tech covert infiltrator is on board pursuing their mysterious goals." + uid = "ninja" + required_players = 5 + required_enemies = 1 + end_on_antag_death = FALSE + associated_antags = list(/decl/special_role/ninja) diff --git a/mods/gamemodes/ninja/datums/special_role.dm b/mods/gamemodes/ninja/datums/special_role.dm new file mode 100644 index 000000000000..46100fe7caa8 --- /dev/null +++ b/mods/gamemodes/ninja/datums/special_role.dm @@ -0,0 +1,151 @@ +/decl/special_role/ninja + name = "Ninja" + name_plural = "Ninja" + landmark_id = "ninjastart" + welcome_text = "You are an elite mercenary assassin of the Spider Clan. You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor." + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_RANDSPAWN | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE + antaghud_indicator = "hudninja" + initial_spawn_req = 1 + initial_spawn_target = 1 + hard_cap = 1 + hard_cap_round = 3 + min_player_age = 18 + default_access = list(access_ninja) + faction = "ninja" + base_to_load = "Ninja Base" + default_outfit = /decl/outfit/ninja + id_title = "Infiltrator" + rig_type = /obj/item/rig/light/ninja + var/list/ninja_titles + var/list/ninja_names + +/decl/special_role/ninja/Initialize() + ninja_titles = file2list("config/names/ninjatitle.txt") + ninja_names = file2list("config/names/ninjaname.txt") + return ..() + +/decl/special_role/ninja/attempt_random_spawn() + if(get_config_value(/decl/config/toggle/ninjas_allowed)) + ..() + +/decl/special_role/ninja/create_objectives(var/datum/mind/ninja) + + if(!..()) + return + + var/objective_list = list(1,2,3,4,5) + for(var/i=rand(2,4),i>0,i--) + switch(pick(objective_list)) + if(1)//Kill + var/datum/objective/assassinate/ninja_objective = new + ninja_objective.owner = ninja + ninja_objective.target = ninja_objective.find_target() + if(ninja_objective.target != "Free Objective") + ninja.objectives += ninja_objective + else + i++ + objective_list -= 1 // No more than one kill objective + if(2)//Steal + var/datum/objective/steal/ninja_objective = new + ninja_objective.owner = ninja + ninja_objective.target = ninja_objective.find_target() + ninja.objectives += ninja_objective + if(3)//Protect + var/datum/objective/protect/ninja_objective = new + ninja_objective.owner = ninja + ninja_objective.target = ninja_objective.find_target() + if(ninja_objective.target != "Free Objective") + ninja.objectives += ninja_objective + else + i++ + objective_list -= 3 + if(4)//Download + var/datum/objective/download/ninja_objective = new + ninja_objective.owner = ninja + ninja_objective.gen_amount_goal() + ninja.objectives += ninja_objective + objective_list -= 4 + if(5)//Harm + var/datum/objective/harm/ninja_objective = new + ninja_objective.owner = ninja + ninja_objective.target = ninja_objective.find_target() + if(ninja_objective.target != "Free Objective") + ninja.objectives += ninja_objective + else + i++ + objective_list -= 5 + + var/datum/objective/survive/ninja_objective = new + ninja_objective.owner = ninja + ninja.objectives += ninja_objective + +/decl/special_role/ninja/greet(var/datum/mind/player) + + if(!..()) + return 0 + var/directive = generate_ninja_directive("heel") + player.StoreMemory("Directive:[directive]
    ", /decl/memory_options/system) + to_chat(player, "Remember your directive: [directive].") + +/decl/special_role/ninja/update_antag_mob(var/datum/mind/player) + ..() + var/mob/living/human/H = player.current + if(istype(H)) + H.real_name = "[pick(ninja_titles)] [pick(ninja_names)]" + H.SetName(H.real_name) + player.name = H.name + +/decl/outfit/ninja + name = "Special Role - Ninja" + l_ear = /obj/item/radio/headset + uniform = /obj/item/clothing/jumpsuit/black + belt = /obj/item/flashlight + hands = list(/obj/item/modular_computer/pda/ninja) + id_type = /obj/item/card/id/syndicate + +/decl/special_role/ninja/equip_role(var/mob/living/human/player) + . = ..() + if(.) + var/decl/uplink_source/pda/uplink_source = GET_DECL(/decl/uplink_source/pda) + uplink_source.setup_uplink_source(player, 0) + +/decl/special_role/ninja/proc/generate_ninja_directive(side) + var/directive = "[side=="face"?"[global.using_map.company_name]":"A criminal syndicate"] is your employer. "//Let them know which side they're on. + switch(rand(1,18)) + if(1) + directive += "The Spider Clan must not be linked to this operation. Remain hidden and covert when possible." + if(2) + directive += "[global.using_map.station_name] is financed by an enemy of the Spider Clan. Cause as much structural damage as desired." + if(3) + directive += "A wealthy animal rights activist has made a request we cannot refuse. Prioritize saving animal lives whenever possible." + if(4) + directive += "The Spider Clan absolutely cannot be linked to this operation. Eliminate witnesses at your discretion." + if(5) + directive += "We are currently negotiating with [global.using_map.company_name] [global.using_map.boss_name]. Prioritize saving human lives over ending them." + if(6) + directive += "We are engaged in a legal dispute over [global.using_map.station_name]. If a laywer is present on board, force their cooperation in the matter." + if(7) + directive += "A financial backer has made an offer we cannot refuse. Implicate criminal involvement in the operation." + if(8) + directive += "Let no one question the mercy of the Spider Clan. Ensure the safety of all non-essential personnel you encounter." + if(9) + directive += "A free agent has proposed a lucrative business deal. Implicate [global.using_map.company_name] involvement in the operation." + if(10) + directive += "Our reputation is on the line. Harm as few civilians and innocents as possible." + if(11) + directive += "Our honor is on the line. Utilize only honorable tactics when dealing with opponents." + if(12) + directive += "We are currently negotiating with a mercenary leader. Disguise assassinations as suicide or other natural causes." + if(13) + directive += "Some disgruntled [global.using_map.company_name] employees have been supportive of our operations. Be wary of any mistreatment by command staff." + if(14) + directive += "The Spider Clan has recently been accused of religious insensitivity. Attempt to speak with the Chaplain and prove these accusations false." + if(15) + directive += "The Spider Clan has been bargaining with a competing prosthetics manufacturer. Try to shine [global.using_map.company_name] prosthetics in a bad light." + if(16) + directive += "The Spider Clan has recently begun recruiting outsiders. Consider suitable candidates and assess their behavior amongst the crew." + if(17) + directive += "A cyborg liberation group has expressed interest in our serves. Prove the Spider Clan merciful towards law-bound synthetics." + else + directive += "There are no special supplemental instructions at this time." + return directive diff --git a/mods/gamemodes/ninja/maps/ninja_base.dm b/mods/gamemodes/ninja/maps/ninja_base.dm new file mode 100644 index 000000000000..bf83a50e0a59 --- /dev/null +++ b/mods/gamemodes/ninja/maps/ninja_base.dm @@ -0,0 +1,45 @@ +/datum/map_template/ruin/antag_spawn/ninja + name = "Ninja Base" + mappaths = list( + "mods/gamemodes/ninja/maps/ninja_base.dmm" + ) + modify_tag_vars = FALSE + shuttles_to_initialise = list(/datum/shuttle/autodock/multi/antag/ninja) + apc_test_exempt_areas = list( + /area/map_template/ninja_dojo = NO_SCRUBBER|NO_VENT|NO_APC + ) + +/datum/shuttle/autodock/multi/antag/ninja + name = "Ninja" + defer_initialisation = TRUE + warmup_time = 0 + destination_tags = list( + "nav_ninja_start" + ) + shuttle_area = /area/map_template/ninja_dojo/start + current_location = "nav_ninja_start" + announcer = "Proximity Sensor Array" + arrival_message = "Attention, anomalous sensor reading detected entering vessel proximity." + departure_message = "Attention, anomalous sensor reading detected leaving vessel proximity." + +/obj/effect/shuttle_landmark/ninja/start + name = "Clan Dojo" + landmark_tag = "nav_ninja_start" + +// Areas +/area/map_template/ninja_dojo + name = "\improper Ninja Base" + icon_state = "green" + requires_power = 0 + dynamic_lighting = TRUE + area_flags = AREA_FLAG_RAD_SHIELDED | AREA_FLAG_ION_SHIELDED + req_access = list(access_ninja) + +/area/map_template/ninja_dojo/dojo + name = "\improper Clan Dojo" + dynamic_lighting = FALSE + +/area/map_template/ninja_dojo/start + name = "\improper Clan Dojo" + icon_state = "shuttlered" + base_turf = /turf/floor/plating \ No newline at end of file diff --git a/mods/gamemodes/ninja/maps/ninja_base.dmm b/mods/gamemodes/ninja/maps/ninja_base.dmm new file mode 100644 index 000000000000..05709304e93f --- /dev/null +++ b/mods/gamemodes/ninja/maps/ninja_base.dmm @@ -0,0 +1,2934 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ac" = ( +/turf/unsimulated/floor/snow, +/area/map_template/ninja_dojo/dojo) +"ae" = ( +/obj/effect/floor_decal/asteroid, +/turf/unsimulated/floor/snow, +/area/map_template/ninja_dojo/dojo) +"ag" = ( +/obj/structure/flora/tree/dead, +/turf/unsimulated/floor/snow, +/area/map_template/ninja_dojo/dojo) +"ah" = ( +/obj/structure/flora/tree/pine, +/turf/unsimulated/floor/snow, +/area/map_template/ninja_dojo/dojo) +"aj" = ( +/turf/wall/wood, +/area/map_template/ninja_dojo/dojo) +"ak" = ( +/obj/structure/table/glass, +/obj/item/firstaid/surgery, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"al" = ( +/obj/machinery/optable, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"am" = ( +/obj/structure/closet/medical_wall{ + pixel_y = 32 + }, +/obj/item/clothing/mask/breath/medical, +/obj/item/clothing/gloves/latex, +/obj/item/clothing/mask/surgical, +/obj/structure/hygiene/sink{ + dir = 1; + pixel_y = 16 + }, +/obj/item/chems/glass/bottle/sedatives, +/obj/item/chems/glass/bottle/sedatives, +/obj/item/chems/syringe, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"an" = ( +/obj/structure/table/glass, +/obj/item/chems/ivbag/blood/ominus, +/obj/item/chems/ivbag/blood/ominus, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"ao" = ( +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aq" = ( +/obj/structure/table/glass, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"ar" = ( +/obj/structure/table/glass, +/obj/item/chems/spray/antiseptic, +/obj/item/chems/spray/cleaner, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"at" = ( +/obj/structure/table/glass, +/obj/item/firstaid/o2{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/firstaid/fire{ + pixel_x = 1 + }, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aw" = ( +/obj/structure/table/glass, +/obj/item/box/beakers, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"ax" = ( +/obj/machinery/computer/teleporter, +/turf/unsimulated/floor/plating, +/area/map_template/ninja_dojo/dojo) +"ay" = ( +/obj/machinery/teleport/station, +/turf/unsimulated/floor/plating, +/area/map_template/ninja_dojo/dojo) +"az" = ( +/obj/machinery/teleport/hub, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/unsimulated/floor/plating, +/area/map_template/ninja_dojo/dojo) +"aA" = ( +/obj/effect/wingrille_spawn/reinforced/crescent, +/turf/unsimulated/floor/plating, +/area/map_template/ninja_dojo/dojo) +"aB" = ( +/obj/structure/table/glass, +/obj/item/chems/syringe/antibiotic, +/obj/item/chems/syringe/antibiotic, +/obj/item/stack/medical/bandage/advanced, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aC" = ( +/obj/structure/table/glass, +/obj/item/firstaid/toxin{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/firstaid/adv{ + pixel_x = 1 + }, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aD" = ( +/obj/machinery/chemical_dispenser/medicine, +/obj/item/chems/glass/beaker/large, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aE" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"aF" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/obj/item/radio/intercom/ninja{ + dir = 8; + pixel_x = 22 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"aG" = ( +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"aI" = ( +/obj/structure/iv_drip, +/obj/structure/window/reinforced/crescent, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aJ" = ( +/obj/structure/table/glass, +/obj/item/firstaid/regular, +/obj/item/firstaid/combat, +/obj/structure/window/reinforced/crescent{ + dir = 4 + }, +/obj/structure/window/reinforced/crescent, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aK" = ( +/obj/effect/floor_decal/spline/fancy/wood/corner, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aL" = ( +/obj/effect/floor_decal/spline/fancy/wood, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aM" = ( +/obj/effect/floor_decal/spline/fancy/wood, +/obj/machinery/chemical_dispenser/full, +/obj/item/chems/glass/beaker/large, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aN" = ( +/obj/machinery/door/morgue{ + name = "Teleporter" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"aO" = ( +/obj/effect/floor_decal/carpet/blue{ + dir = 8 + }, +/obj/effect/floor_decal/carpet/blue{ + dir = 1 + }, +/obj/effect/floor_decal/carpet/blue{ + dir = 9 + }, +/obj/abstract/landmark{ + name = "ninjastart" + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"aP" = ( +/obj/effect/floor_decal/carpet/blue{ + dir = 1 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"aQ" = ( +/obj/effect/floor_decal/carpet/blue{ + dir = 1 + }, +/obj/effect/floor_decal/carpet/blue{ + dir = 4 + }, +/obj/effect/floor_decal/carpet/blue{ + dir = 5 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"aR" = ( +/obj/machinery/bodyscanner{ + dir = 8 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aS" = ( +/obj/machinery/body_scanconsole{ + dir = 8 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aT" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"aU" = ( +/obj/structure/flora/pottedplant/bamboo, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"aV" = ( +/obj/structure/flora/pottedplant/orientaltree, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"aW" = ( +/obj/effect/floor_decal/carpet/blue{ + dir = 8 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"aX" = ( +/obj/effect/floor_decal/chapel{ + dir = 1 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"aY" = ( +/obj/effect/floor_decal/chapel{ + dir = 4 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"aZ" = ( +/obj/effect/floor_decal/carpet/blue{ + dir = 4 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"ba" = ( +/obj/machinery/door/morgue{ + name = "Medical" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bb" = ( +/obj/item/radio/intercom/ninja{ + dir = 1; + pixel_y = -30 + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bc" = ( +/obj/machinery/door/morgue{ + name = "Dojo" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bd" = ( +/obj/effect/floor_decal/chapel{ + dir = 8 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"be" = ( +/obj/effect/floor_decal/chapel, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"bf" = ( +/obj/effect/floor_decal/spline/fancy/wood, +/obj/machinery/sleeper/standard{ + dir = 4 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"bg" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 6 + }, +/turf/unsimulated/floor/white, +/area/map_template/ninja_dojo/dojo) +"bh" = ( +/obj/structure/door/wood, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bi" = ( +/obj/effect/floor_decal/carpet/blue, +/obj/effect/floor_decal/carpet/blue{ + dir = 8 + }, +/obj/effect/floor_decal/carpet/blue{ + dir = 10 + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"bj" = ( +/obj/effect/floor_decal/carpet/blue, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"bk" = ( +/obj/effect/floor_decal/carpet/blue{ + dir = 4 + }, +/obj/effect/floor_decal/carpet/blue, +/obj/effect/floor_decal/carpet/blue{ + dir = 6 + }, +/obj/abstract/landmark{ + name = "ninjastart" + }, +/turf/unsimulated/floor/bcarpet, +/area/map_template/ninja_dojo/dojo) +"bl" = ( +/obj/structure/rack, +/obj/item/belt/medical, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bm" = ( +/obj/item/radio/intercom/ninja{ + dir = 8; + pixel_x = 22 + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bn" = ( +/turf/unsimulated/floor/snow_plating, +/area/map_template/ninja_dojo/dojo) +"bo" = ( +/obj/effect/floor_decal/snow_floor, +/turf/unsimulated/floor/snow_plating, +/area/map_template/ninja_dojo/dojo) +"bp" = ( +/obj/item/radio/intercom/ninja{ + dir = 4; + pixel_x = -22 + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bq" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/vest, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"br" = ( +/obj/structure/rack, +/obj/item/defibrillator/compact/combat/loaded, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bs" = ( +/obj/structure/rack, +/obj/item/sword/katana/toy{ + name = "practice katana" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bt" = ( +/obj/structure/flora/bush/palebush, +/turf/unsimulated/floor/snow, +/area/map_template/ninja_dojo/dojo) +"bu" = ( +/obj/structure/bookcase, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bv" = ( +/obj/structure/flora/pottedplant/flower, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bw" = ( +/obj/structure/table/wood, +/obj/machinery/chemical_dispenser/bar_soft/full, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bx" = ( +/obj/structure/table/wood, +/obj/item/box/glasses, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"by" = ( +/obj/structure/table/wood, +/obj/item/box/sinpockets, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bz" = ( +/obj/structure/table/wood, +/obj/machinery/microwave, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bA" = ( +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/obj/effect/floor_decal/carpet{ + dir = 9 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bB" = ( +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bC" = ( +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/effect/floor_decal/carpet{ + dir = 1 + }, +/obj/effect/floor_decal/carpet{ + dir = 5 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bD" = ( +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"bE" = ( +/obj/effect/floor_decal/snow_floor, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"bF" = ( +/obj/structure/table/wood, +/obj/item/chems/drinks/dry_ramen, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bG" = ( +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bH" = ( +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bI" = ( +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bJ" = ( +/obj/effect/floor_decal/snow_floor, +/turf/unsimulated/floor/ice, +/area/map_template/ninja_dojo/dojo) +"bK" = ( +/obj/machinery/door/morgue{ + name = "Sleeping Chamber" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bL" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lamp, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bM" = ( +/obj/effect/floor_decal/snow_floor, +/obj/abstract/modpack_compat/aliumizer, +/turf/unsimulated/floor/ice, +/area/map_template/ninja_dojo/dojo) +"bN" = ( +/obj/abstract/landmark{ + name = "ninjastart" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bO" = ( +/obj/structure/bed/padded, +/obj/item/bedsheet/brown, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bP" = ( +/obj/effect/floor_decal/carpet, +/obj/effect/floor_decal/carpet{ + dir = 8 + }, +/obj/effect/floor_decal/carpet{ + dir = 10 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bQ" = ( +/obj/effect/floor_decal/carpet, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bR" = ( +/obj/effect/floor_decal/carpet{ + dir = 4 + }, +/obj/effect/floor_decal/carpet, +/obj/effect/floor_decal/carpet{ + dir = 6 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"bS" = ( +/obj/structure/table/wood, +/obj/item/food/soylentgreen, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bT" = ( +/obj/structure/bookcase{ + name = "bookcase (Tactics)" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bU" = ( +/obj/structure/flora/pottedplant/shoot, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bV" = ( +/obj/structure/bookcase{ + name = "bookcase (Religious)" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bW" = ( +/obj/structure/table/wood, +/obj/item/toy/figure/wizard, +/obj/item/radio/intercom/ninja{ + dir = 1; + pixel_y = -30 + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bX" = ( +/obj/structure/table/wood, +/obj/item/clothing/shoes/sandal, +/obj/item/clothing/mask/balaclava, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bY" = ( +/obj/structure/undies_wardrobe, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"bZ" = ( +/obj/machinery/door/morgue{ + name = "Bath" + }, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"ca" = ( +/obj/structure/table/wood, +/obj/item/flame/candle, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"cb" = ( +/obj/effect/floor_decal/spline/fancy/wood/corner, +/obj/item/radio/intercom/ninja{ + dir = 4; + pixel_x = -22 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"cc" = ( +/obj/effect/floor_decal/spline/fancy/wood, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"cd" = ( +/obj/effect/floor_decal/spline/fancy/wood, +/obj/structure/hygiene/toilet{ + pixel_y = 8 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"ce" = ( +/obj/machinery/door/morgue{ + name = "Shrine" + }, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"cf" = ( +/obj/abstract/landmark{ + name = "ninjastart" + }, +/obj/effect/floor_decal/carpet{ + dir = 10 + }, +/obj/effect/floor_decal/carpet{ + dir = 6 + }, +/obj/effect/floor_decal/carpet{ + dir = 9 + }, +/obj/effect/floor_decal/carpet{ + dir = 5 + }, +/turf/unsimulated/floor/carpet, +/area/map_template/ninja_dojo/dojo) +"cg" = ( +/obj/structure/rack{ + desc = "A simple wooden altar covered in cloth."; + icon = 'icons/obj/cult.dmi'; + icon_state = "churchaltar"; + name = "wooden altar" + }, +/obj/item/sword/katana, +/turf/unsimulated/floor/wood, +/area/map_template/ninja_dojo/dojo) +"ch" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"ci" = ( +/turf/unsimulated/floor/water, +/area/map_template/ninja_dojo/dojo) +"cj" = ( +/obj/effect/floor_decal/spline/fancy/wood{ + dir = 4 + }, +/obj/structure/hygiene/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/structure/mirror{ + pixel_x = -32 + }, +/turf/unsimulated/floor/freezer, +/area/map_template/ninja_dojo/dojo) +"ck" = ( +/obj/effect/paint/black, +/turf/wall/r_titanium, +/area/map_template/ninja_dojo/start) +"cl" = ( +/obj/machinery/door/morgue{ + name = "Equipment" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cm" = ( +/obj/machinery/fabricator/hacked, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cn" = ( +/obj/structure/rack, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/sheet/mapped/steel/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/item/stack/material/pane/mapped/glass/fifty, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"co" = ( +/obj/structure/table/steel_reinforced, +/obj/item/secure_storage/briefcase/money, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cp" = ( +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cq" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/vest/brown, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cr" = ( +/obj/structure/rack, +/obj/item/belt/utility/full, +/obj/item/multitool, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cs" = ( +/obj/structure/table/steel_reinforced, +/obj/item/multitool/hacktool, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"ct" = ( +/obj/structure/table/steel_reinforced, +/obj/item/radio/uplink, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cu" = ( +/obj/machinery/door/airlock/centcom{ + name = "Equipment" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cv" = ( +/obj/machinery/acting/changer, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cw" = ( +/obj/structure/rack, +/obj/item/stack/nanopaste, +/obj/item/stack/nanopaste, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cx" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 1 + }, +/obj/effect/paint/black, +/turf/wall/r_titanium, +/area/map_template/ninja_dojo/start) +"cy" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/cell_charger, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/item/clothing/webbing/bandolier, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cz" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/recharger, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cA" = ( +/obj/structure/rack, +/obj/item/star/ninja, +/obj/item/star/ninja, +/obj/item/star/ninja, +/obj/item/star/ninja, +/obj/item/star/ninja, +/obj/item/star/ninja, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cB" = ( +/obj/structure/rack, +/obj/item/star, +/obj/item/star, +/obj/item/star, +/obj/item/star, +/obj/item/star, +/obj/item/star, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cC" = ( +/obj/structure/rack, +/obj/item/clothing/webbing/vest/black, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cD" = ( +/obj/structure/rack, +/obj/item/belt/holster/security/tactical, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cE" = ( +/obj/structure/table/steel_reinforced, +/obj/item/plastique, +/obj/item/plastique, +/obj/item/radio/intercom/ninja{ + dir = 1; + pixel_y = -30 + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cF" = ( +/obj/structure/table/steel_reinforced, +/obj/item/box/anti_photons, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/dojo) +"cG" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 4; + icon_state = "warning" + }, +/obj/machinery/light{ + dir = 1 + }, +/obj/structure/rack, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cH" = ( +/obj/machinery/computer/teleporter, +/turf/floor/plating, +/area/map_template/ninja_dojo/start) +"cI" = ( +/obj/machinery/teleport/station, +/turf/floor/plating, +/area/map_template/ninja_dojo/start) +"cJ" = ( +/obj/machinery/teleport/hub, +/obj/effect/floor_decal/industrial/hatch/yellow, +/turf/floor/plating, +/area/map_template/ninja_dojo/start) +"cK" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/portables_connector, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/portable_atmospherics/canister/air/airlock, +/obj/effect/floor_decal/industrial/warning{ + dir = 8; + icon_state = "warning" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cL" = ( +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/sleeper/standard{ + dir = 4 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cM" = ( +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cN" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 4; + icon_state = "warningcorner" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cO" = ( +/obj/effect/floor_decal/industrial/warning{ + dir = 1 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cP" = ( +/obj/effect/floor_decal/industrial/warning/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cQ" = ( +/obj/machinery/embedded_controller/radio/airlock/docking_port{ + frequency = 1331; + id_tag = "ninja_shuttle"; + pixel_x = -8; + pixel_y = 25; + req_access = list("ACCESS_NINJA") + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cR" = ( +/obj/machinery/door/airlock/external/shuttle{ + id_tag = "ninja_shuttle_outer"; + name = "Ship External Access" + }, +/obj/machinery/door/blast/regular/open{ + id_tag = "ninjadoor"; + name = "Blast Door" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cS" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/structure/chair{ + dir = 4 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cT" = ( +/obj/effect/shuttle_landmark/ninja/start, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cU" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 5 + }, +/obj/machinery/button/access/shuttle/interior{ + id_tag = "ninja_shuttle"; + name = "interior access button"; + pixel_x = 25; + pixel_y = 25; + req_access = list("ACCESS_NINJA") + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cV" = ( +/obj/machinery/atmospherics/pipe/simple/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/external/shuttle{ + id_tag = "ninja_shuttle_inner"; + name = "Ship External Access" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cW" = ( +/obj/machinery/airlock_sensor/shuttle{ + id_tag = "ninja_shuttle_sensor"; + pixel_x = 8; + pixel_y = -25 + }, +/obj/machinery/atmospherics/unary/vent_pump/high_volume/shuttle{ + dir = 8; + id_tag = "ninja_shuttle_pump" + }, +/obj/machinery/button/blast_door{ + id_tag = "ninjadoor"; + name = "remote shutter control"; + pixel_x = 25; + dir = 8 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cX" = ( +/obj/structure/closet, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cY" = ( +/obj/structure/rack, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"cZ" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1" + }, +/obj/item/radio/intercom/ninja{ + dir = 4; + pixel_x = -22 + }, +/obj/machinery/cell_charger, +/obj/item/screwdriver, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"da" = ( +/obj/structure/chair/shuttle, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"db" = ( +/obj/machinery/button/blast_door{ + id_tag = "ninjawindow"; + name = "remote shutter control"; + pixel_x = 36; + pixel_y = -24 + }, +/obj/machinery/button/windowtint{ + id_tag = "ninja_ship"; + pixel_x = -24; + pixel_y = -25 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"dc" = ( +/obj/structure/table/steel_reinforced, +/obj/machinery/recharger, +/obj/item/wrench, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/obj/effect/floor_decal/industrial/outline/grey, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"dd" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/computer/station_alert/all{ + dir = 1 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"de" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/computer/shuttle_control/multi/ninja{ + dir = 1 + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"df" = ( +/obj/effect/floor_decal/industrial/outline/grey, +/obj/machinery/computer/modular/preset/security{ + dir = 1; + icon_state = "console" + }, +/turf/unsimulated/floor/dark, +/area/map_template/ninja_dojo/start) +"dg" = ( +/obj/machinery/door/blast/regular{ + id_tag = "ninjawindow"; + name = "Blast Shutter" + }, +/obj/effect/wallframe_spawn/reinforced/polarized{ + id = "ninja_ship" + }, +/obj/effect/paint/black, +/turf/floor/plating, +/area/map_template/ninja_dojo/start) +"ss" = ( +/turf/unsimulated/wall, +/area/map_template/ninja_dojo/dojo) + +(1,1,1) = {" +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +"} +(2,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ae +ac +ac +ac +ac +ag +ac +ac +ac +ac +ac +ag +bn +bo +ac +ag +ac +ac +bn +bn +bn +bo +bo +bn +bn +bn +bn +bo +bn +bn +bo +bo +bo +ss +"} +(3,1,1) = {" +ss +ac +ae +ac +ac +ac +ag +ac +ac +ac +ac +ac +ac +ac +ac +ac +ae +ac +ac +bo +bn +ac +ac +ac +ac +bn +bo +bo +bn +bn +bn +bn +ck +ck +ck +ck +bn +bn +bo +bn +ss +"} +(4,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +ah +ac +ac +ac +ac +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +bn +bn +bn +bn +bn +bn +ck +ck +cL +cS +ck +ck +bn +bn +bn +ss +"} +(5,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +bn +bo +ac +ac +ae +ac +bo +bn +bn +bn +bn +bn +cx +ck +cM +cM +ck +ck +ck +bn +bn +ss +"} +(6,1,1) = {" +ss +ac +ac +ac +ae +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ae +ac +ac +ag +bo +bn +ac +ag +ac +ac +bo +bn +ck +ck +ck +ck +ck +cG +cN +cM +cX +cZ +ck +ck +bn +ss +"} +(7,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +aj +aj +aj +aj +aj +aj +aj +ac +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +bo +bn +bn +bo +bn +bn +ck +cH +cO +cM +cM +cM +dd +dg +bn +ss +"} +(8,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +ak +ar +aB +aI +aR +ao +aj +aj +aj +aj +aj +aA +bh +bh +aA +aj +aj +ac +bn +bn +bn +bo +bo +bn +ck +cI +cO +cT +cM +da +de +dg +bn +ss +"} +(9,1,1) = {" +ss +ac +ag +ac +ac +ac +aj +al +ao +ao +ao +aS +ao +bf +bl +bq +aj +bu +aG +aG +aG +aG +bT +aj +ac +bn +bn +bn +bn +bn +bn +ck +cJ +cO +cM +cM +db +df +dg +bn +ss +"} +(10,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +am +ao +ao +ao +ao +ao +aL +aG +aG +aA +aV +bA +bG +bG +bP +bU +aA +ac +bn +bn +ck +ck +ck +ck +ck +cK +cP +cU +cY +dc +ck +ck +bn +ss +"} +(11,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +an +at +aC +aJ +ao +ao +aL +aG +aG +ba +aG +bB +bH +bH +bQ +aG +bh +bn +bn +bn +bn +bn +bn +bn +cx +ck +ck +cV +ck +ck +ck +bn +bn +ss +"} +(12,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +ao +ao +ao +aK +aT +aT +bg +aG +aG +ba +aG +bB +bH +bH +bQ +aG +bh +bn +bn +bn +bn +bn +bn +bn +ck +ck +cQ +cW +ck +ck +bn +bn +bn +ss +"} +(13,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +ao +ao +ao +aL +aG +aG +aG +aG +aG +aA +bv +bC +bI +bI +bR +aU +aA +ac +bn +bn +bo +bo +bn +bn +bn +ck +cR +ck +ck +bn +bn +bn +bn +ss +"} +(14,1,1) = {" +ss +ac +ac +ac +ae +ac +aj +aq +aw +aD +aM +aU +aG +aG +bm +br +aj +bu +aG +aG +aG +aG +bV +aj +ac +bn +bn +bn +bn +bn +bn +bn +bn +bn +bn +bn +bo +bo +bn +bn +ss +"} +(15,1,1) = {" +ss +ac +ac +ac +ac +ac +aj +aj +aj +aj +aj +aA +ba +aj +aj +aj +aj +aj +aA +bh +bh +aA +aj +aj +ac +bo +bn +bn +bn +bo +bn +bn +bn +bn +bo +bo +bo +bn +bn +bn +ss +"} +(16,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +aj +ax +aE +aA +aV +aG +aj +ac +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(17,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +aj +ay +aE +aN +aG +aG +aA +ae +bo +bn +bn +bn +bn +bo +bo +bn +bn +bn +ac +ac +ae +ac +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +ah +ss +"} +(18,1,1) = {" +ss +ac +ac +ah +ac +ac +ac +aj +az +aF +aA +aG +aG +aA +ac +bn +ag +bn +ac +ac +ac +ac +bn +ah +bn +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +ag +ac +ac +ac +ac +ss +"} +(19,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +aj +aj +aj +aj +aG +bb +aj +ac +bo +bn +bn +ac +ac +ac +ac +bn +bn +bn +ac +ac +ac +ac +bn +bo +ac +ae +ac +ac +ac +ac +ac +ac +ae +ss +"} +(20,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +aA +aG +aG +aj +ac +bn +ac +ac +bD +bE +bE +bE +ac +ac +bn +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(21,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ae +ac +aA +aG +aG +bh +bn +bn +ae +ac +bE +bJ +bM +bD +ac +ac +bo +bn +bo +bn +bn +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(22,1,1) = {" +ss +ac +ac +ac +ac +ag +ac +ac +ac +ac +aA +aG +aG +bh +bo +bn +ac +ac +bD +bJ +bJ +bE +ac +ac +bo +bn +bn +bo +bn +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(23,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +aA +aG +aG +aj +ac +bn +ac +ac +bE +bE +bD +bE +ac +ac +bn +ac +ac +ac +ac +bn +bn +ac +ac +ac +ac +ac +ac +ac +ag +ac +ss +"} +(24,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +aj +aG +aG +aj +ac +bn +bn +bn +ac +ac +ac +ac +bn +bn +bn +ac +ae +ac +ac +bn +bn +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(25,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +aj +aG +aG +aA +ac +bo +bt +bn +ac +ac +ac +ac +bn +ag +bn +ac +ac +aj +aj +cu +cu +aj +aj +ac +ac +ae +ac +ac +ac +ac +ss +"} +(26,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +aj +aG +aG +aA +ac +bn +bn +bn +bo +bo +bn +bn +bn +bo +bn +ac +ac +aj +cm +cp +cp +cy +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(27,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +aj +aV +aG +aj +ac +ac +ac +ac +ac +bn +bn +ac +ac +ae +ac +ac +ac +aj +cn +cp +cp +cz +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(28,1,1) = {" +ss +ac +ac +ac +ac +ac +ae +ac +aj +aj +aj +aA +bc +aj +aj +aj +aA +aA +aj +bh +bh +aj +aA +aA +aj +aj +aj +aj +co +cp +cp +cA +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(29,1,1) = {" +ss +ac +ae +ac +ac +ac +ae +ac +aj +aG +aG +aG +aG +aG +bp +bc +aG +aG +aG +aG +aG +aG +aG +aG +aG +bp +aG +cl +cp +cp +cp +cB +aj +ac +ac +ac +ac +ac +ae +ac +ss +"} +(30,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +aA +aG +aG +aG +aG +aG +aG +aA +aV +aG +aG +aG +aG +aG +aG +aG +aG +aG +aV +aj +cq +cp +cp +cC +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(31,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +aA +aG +aO +aW +aW +bi +aG +aj +aj +aj +aA +bK +bK +aA +aj +aj +aA +ce +aA +aj +cr +cp +cp +cD +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(32,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +aA +aG +aP +aX +bd +bj +aG +bs +aj +bw +bF +aG +aG +bS +bW +aj +aG +cf +aG +aj +cs +cp +cp +cE +aj +ac +ac +ac +ac +ah +ac +ac +ss +"} +(33,1,1) = {" +ss +ac +ac +ac +ag +ac +ac +ac +aA +aG +aP +aY +be +bj +aG +bs +aj +bx +aG +aG +aG +aG +bX +aj +ca +cg +ca +aj +ct +cp +cp +cF +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(34,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +aA +aG +aQ +aZ +aZ +bk +aG +bs +aj +by +aG +aG +bN +aG +bY +aj +aj +aj +aj +aj +aj +cv +cw +aj +aj +ac +ac +ac +ac +ac +ac +ac +ss +"} +(35,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +aj +aG +aG +aG +aG +aG +aG +bs +aj +bz +aG +bL +bO +aG +aG +bZ +cb +ch +cj +aj +aj +aj +aj +aj +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(36,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +aj +aj +aA +aA +aA +aA +aA +aj +aj +aj +aA +aA +aA +aA +aj +aj +cc +ci +ci +aj +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(37,1,1) = {" +ss +ae +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +aj +cd +ci +ci +aj +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(38,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ae +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +aj +aj +aj +aj +aj +ac +ae +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(39,1,1) = {" +ss +ac +ag +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(40,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ag +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(41,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ag +ac +ac +ac +ac +ac +ac +ac +ac +ah +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ag +ac +ac +ss +"} +(42,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(43,1,1) = {" +ss +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ae +ac +ac +ac +ac +ac +ac +ac +ae +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ac +ss +"} +(44,1,1) = {" +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +ss +"} diff --git a/mods/gamemodes/ninja/objects/misc_presets.dm b/mods/gamemodes/ninja/objects/misc_presets.dm new file mode 100644 index 000000000000..82964a4358aa --- /dev/null +++ b/mods/gamemodes/ninja/objects/misc_presets.dm @@ -0,0 +1,14 @@ +/obj/item/modular_computer/pda/ninja + color = COLOR_GRAY20 + decals = list( + "stripe" = COLOR_BLACK + ) + +/obj/machinery/computer/shuttle_control/multi/ninja + name = "stealth shuttle control console" + initial_access = list(access_ninja) + shuttle_tag = "Ninja" + +/obj/item/radio/intercom/ninja + name = "stealth intercom" + desc = "It's hiding in plain sight." \ No newline at end of file diff --git a/mods/gamemodes/ninja/objects/rigsuit.dm b/mods/gamemodes/ninja/objects/rigsuit.dm new file mode 100644 index 000000000000..7a49651656a8 --- /dev/null +++ b/mods/gamemodes/ninja/objects/rigsuit.dm @@ -0,0 +1,129 @@ +/obj/item/rig/light/ninja + name = "ominous suit control module" + desc = "A unique, vacuum-proof suit of nano-enhanced armor designed specifically for assassins." + suit_type = "ominous" + icon = 'icons/clothing/rigs/rig_ninja.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_KNIVES, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED + ) + siemens_coefficient = 0.2 //heavy hardsuit level shock protection + emp_protection = 40 //change this to 30 if too high. + online_slowdown = 0 + aimove_power_usage = 50 + + helmet = /obj/item/clothing/head/helmet/space/rig/light/ninja + boots = /obj/item/clothing/shoes/magboots/rig/light/ninja + chest = /obj/item/clothing/suit/space/rig/light/ninja + gloves = /obj/item/clothing/gloves/rig/light/ninja + cell = /obj/item/cell/hyper + + req_access = list(access_ninja) + + initial_modules = list( + /obj/item/rig_module/teleporter, + /obj/item/rig_module/stealth_field, + /obj/item/rig_module/mounted/energy_blade, + /obj/item/rig_module/vision, + /obj/item/rig_module/voice, + /obj/item/rig_module/fabricator/energy_net, + /obj/item/rig_module/chem_dispenser/combat, + /obj/item/rig_module/grenade_launcher/ninja, + /obj/item/rig_module/ai_container, + /obj/item/rig_module/power_sink, + /obj/item/rig_module/datajack, + /obj/item/rig_module/self_destruct, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/rig/light/ninja/verb/rename_suit() + set name = "Name Ninja Suit" + set desc = "Rename your black voidsuit." + set category = "Object" + var/mob/M = usr + if(!M.mind) return 0 + if(M.incapacitated()) return 0 + var/input = sanitize_safe(input("What do you want to name your suit?", "Rename suit"), MAX_NAME_LEN) + if(src && input && !M.incapacitated() && in_range(M,src)) + if(!findtext(input, "the", 1, 4)) + input = "\improper [input]" + SetName(input) + to_chat(M, "Suit naming succesful!") + verbs -= /obj/item/rig/light/ninja/verb/rename_suit + return 1 + + +/obj/item/rig/light/ninja/verb/rewrite_suit_desc() + set name = "Describe Ninja suit" + set desc = "Give your voidsuit a custom description." + set category = "Object" + var/mob/M = usr + if(!M.mind) return 0 + if(M.incapacitated()) return 0 + var/input = sanitize_safe(input("Please describe your voidsuit in 128 letters or less.", "write description"), MAX_DESC_LEN) + if(src && input && !M.incapacitated() && in_range(M,src)) + desc = input + to_chat(M, "Suit description succesful!") + verbs -= /obj/item/rig/light/ninja/verb/rename_suit + return 1 + +/obj/item/clothing/gloves/rig/light/ninja + name = "insulated gloves" + siemens_coefficient = 0 + item_flags = ITEM_FLAG_THICKMATERIAL | ITEM_FLAG_NOCUFFS + icon = 'icons/clothing/rigs/gloves/gloves_ninja.dmi' +/obj/item/clothing/suit/space/rig/light/ninja + icon = 'icons/clothing/rigs/chests/chest_ninja.dmi' +/obj/item/clothing/shoes/magboots/rig/light/ninja + icon = 'icons/clothing/rigs/boots/boots_ninja.dmi' +/obj/item/clothing/head/helmet/space/rig/light/ninja + icon = 'icons/clothing/rigs/helmets/helmet_ninja.dmi' + +// Modules +// Ninja throwing star launcher +/obj/item/rig_module/fabricator/ninja + interface_name = "death blossom launcher" + interface_desc = "An integrated microfactory that produces poisoned throwing stars from thin air and electricity." + fabrication_type = /obj/item/star/ninja + +/obj/item/star/ninja + material = /decl/material/solid/metal/uranium + +// Ninja energy blade projector +/obj/item/rig_module/mounted/energy_blade/ninja + interface_name = "spider fang blade" + interface_desc = "A lethal energy projector that can shape a blade projected from the hand of the wearer or launch radioactive darts." + gun = /obj/item/gun/energy/crossbow/ninja/mounted + +/obj/item/gun/energy/crossbow/ninja + name = "energy dart thrower" + projectile_type = /obj/item/projectile/energy/dart + max_shots = 5 + +/obj/item/gun/energy/crossbow/ninja/mounted + use_external_power = 1 + has_safety = FALSE + +// Ninja chemical injector +/obj/item/rig_module/chem_dispenser/ninja + interface_desc = "Dispenses loaded chemicals directly into the wearer's bloodstream. This variant is made to be extremely light and flexible." + + //just over a syringe worth of each. Want more? Go refill. Gives the ninja another reason to have to show their face. + charges = list( + list("oxygen", "oxygel", /decl/material/liquid/oxy_meds, 20), + list("stabilizer", "stabilizer", /decl/material/liquid/stabilizer, 20), + list("antitoxins", "antitoxins", /decl/material/liquid/antitoxins, 20), + list("glucose", "glucose", /decl/material/liquid/nutriment/glucose, 80), + list("antirads", "antirads", /decl/material/liquid/antirads, 20), + list("regenerative", "regenerative", /decl/material/liquid/burn_meds, 20), + list("antibiotics", "antibiotics", /decl/material/liquid/antibiotics, 20), + list("painkillers", "painkillers", /decl/material/liquid/painkillers, 20) + ) + +// Ninja grenade launcher. Doesn't show up visually. Stealthy! +/obj/item/rig_module/grenade_launcher/ninja + suit_overlay = null \ No newline at end of file diff --git a/mods/gamemodes/revolution/_revolution.dm b/mods/gamemodes/revolution/_revolution.dm new file mode 100644 index 000000000000..f90a70bee36e --- /dev/null +++ b/mods/gamemodes/revolution/_revolution.dm @@ -0,0 +1,2 @@ +/decl/modpack/revolution + name = "Revolution Gamemode" \ No newline at end of file diff --git a/mods/gamemodes/revolution/_revolution.dme b/mods/gamemodes/revolution/_revolution.dme new file mode 100644 index 000000000000..5249d6659a5d --- /dev/null +++ b/mods/gamemodes/revolution/_revolution.dme @@ -0,0 +1,9 @@ +#ifndef GAMEMODE_PACK_REVOLUTION +#define GAMEMODE_PACK_REVOLUTION +// BEGIN_INCLUDE +#include "_revolution.dm" +#include "gamemode.dm" +#include "loyalist.dm" +#include "revolutionary.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/revolution/gamemode.dm b/mods/gamemodes/revolution/gamemode.dm new file mode 100644 index 000000000000..cbd16ae38a85 --- /dev/null +++ b/mods/gamemodes/revolution/gamemode.dm @@ -0,0 +1,15 @@ +/decl/game_mode/revolution + name = "Revolution" + uid = "revolution" + round_description = "Some crewmembers are attempting to start a revolution!" + extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders." + required_players = 4 + required_enemies = 3 + auto_recall_shuttle = FALSE + end_on_antag_death = FALSE + shuttle_delay = 2 + associated_antags = list( + /decl/special_role/revolutionary, + /decl/special_role/loyalist + ) + require_all_templates = TRUE diff --git a/mods/gamemodes/revolution/loyalist.dm b/mods/gamemodes/revolution/loyalist.dm new file mode 100644 index 000000000000..ff59a4eae546 --- /dev/null +++ b/mods/gamemodes/revolution/loyalist.dm @@ -0,0 +1,52 @@ +/decl/special_role/loyalist + name = "Head Loyalist" + name_plural = "Loyalists" + antag_indicator = "hud_loyal_head" + antaghud_indicator = "hudloyalist" + flags = 0 + blocked_job_event_categories = list(ASSIGNMENT_ROBOT, ASSIGNMENT_COMPUTER) + + hard_cap = 2 + hard_cap_round = 4 + initial_spawn_req = 2 + initial_spawn_target = 4 + + // Inround loyalists. + faction_name = "Loyalist" + faction_descriptor = "COMPANY" + faction_verb = /mob/living/proc/convert_to_loyalist + faction_indicator = "hud_loyal" + faction_invisible = 1 + blacklisted_jobs = list(/datum/job/submap) + skill_setter = /datum/antag_skill_setter/station + faction = "loyalist" + var/command_department_id + +/decl/special_role/loyalist/Initialize() + if(!command_department_id) + command_department_id = global.using_map.default_department_type + . = ..() + welcome_text = "You belong to the [global.using_map.company_name], body and soul. Preserve its interests against the conspirators amongst the crew." + faction_welcome = "Preserve [global.using_map.company_short]'s interests against the traitorous recidivists amongst the crew. Protect the heads of staff with your life." + faction_descriptor = "[global.using_map.company_name]" + +/decl/special_role/loyalist/create_global_objectives() + if(!..()) + return + global_objectives = list() + for(var/mob/living/human/player in SSmobs.mob_list) + if(!player.mind || player.stat == DEAD || !(player.mind.assigned_role in SSjobs.titles_by_department(command_department_id))) + continue + var/datum/objective/protect/loyal_obj = new + loyal_obj.target = player.mind + loyal_obj.explanation_text = "Protect [player.real_name], the [player.mind.assigned_role]." + global_objectives += loyal_obj + +/mob/living/proc/convert_to_loyalist(mob/M in able_mobs_in_oview(src)) + set name = "Convince Recidivist" + set category = "Abilities" + + if(!M.mind || !M.client) + return + + convert_to_faction(M.mind, GET_DECL(/decl/special_role/loyalist)) \ No newline at end of file diff --git a/mods/gamemodes/revolution/revolutionary.dm b/mods/gamemodes/revolution/revolutionary.dm new file mode 100644 index 000000000000..e51486d733ce --- /dev/null +++ b/mods/gamemodes/revolution/revolutionary.dm @@ -0,0 +1,60 @@ +/decl/special_role/revolutionary + name = "Head Revolutionary" + name_plural = "Revolutionaries" + antag_indicator = "hud_rev_head" + welcome_text = "Down with the capitalists! Down with the Bourgeoise!" + flags = ANTAG_SUSPICIOUS | ANTAG_VOTABLE + antaghud_indicator = "hudrevolutionary" + skill_setter = /datum/antag_skill_setter/station + blocked_job_event_categories = list(ASSIGNMENT_ROBOT, ASSIGNMENT_COMPUTER) + + hard_cap = 2 + hard_cap_round = 4 + initial_spawn_req = 2 + initial_spawn_target = 4 + + //Inround revs. + faction_name = "Revolutionary" + faction_descriptor = "Revolution" + faction_verb = /mob/living/proc/convert_to_rev + faction_welcome = "Help the cause overturn the ruling class. Do not harm your fellow freedom fighters." + faction_indicator = "hud_rev" + faction_invisible = 1 + faction = "revolutionary" + + blacklisted_jobs = list(/datum/job/submap) + var/command_department_id + +/decl/special_role/revolutionary/Initialize() + if(!command_department_id) + command_department_id = global.using_map.default_department_type + . = ..() + +/decl/special_role/revolutionary/create_global_objectives() + if(!..()) + return + global_objectives = list() + for(var/mob/living/human/player in SSmobs.mob_list) + if(!player.mind || player.stat == DEAD || !(player.mind.assigned_role in SSjobs.titles_by_department(command_department_id))) + continue + var/datum/objective/rev/rev_obj = new + rev_obj.target = player.mind + rev_obj.explanation_text = "Assassinate, capture or convert [player.real_name], the [player.mind.assigned_role]." + global_objectives += rev_obj + +/decl/special_role/revolutionary/equip_role(var/mob/living/human/player) + . = ..() + if(.) + spawn_uplink(player) + +/decl/special_role/revolutionary/proc/spawn_uplink(var/mob/living/human/revolutionary_mob) + setup_uplink_source(revolutionary_mob, DEFAULT_TELECRYSTAL_AMOUNT) + +/mob/living/proc/convert_to_rev(mob/M in able_mobs_in_oview(src)) + set name = "Recruit to Faction" + set category = "Abilities" + + if(!M.mind || !M.client) + return + + convert_to_faction(M.mind, GET_DECL(/decl/special_role/revolutionary)) \ No newline at end of file diff --git a/mods/gamemodes/spyvspy/_spyvspy.dm b/mods/gamemodes/spyvspy/_spyvspy.dm new file mode 100644 index 000000000000..967d6828878f --- /dev/null +++ b/mods/gamemodes/spyvspy/_spyvspy.dm @@ -0,0 +1,2 @@ +/decl/modpack/spyvspy + name = "Spy v. Spy Gamemode" \ No newline at end of file diff --git a/mods/gamemodes/spyvspy/_spyvspy.dme b/mods/gamemodes/spyvspy/_spyvspy.dme new file mode 100644 index 000000000000..0150ef2deeab --- /dev/null +++ b/mods/gamemodes/spyvspy/_spyvspy.dme @@ -0,0 +1,9 @@ +#ifndef GAMEMODE_PACK_SPYVSPY +#define GAMEMODE_PACK_SPYVSPY +#include "..\traitor\_traitor.dme" +// BEGIN_INCLUDE +#include "_spyvspy.dm" +#include "gamemode.dm" +#include "special_role.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/spyvspy/gamemode.dm b/mods/gamemodes/spyvspy/gamemode.dm new file mode 100644 index 000000000000..f0f9d638cf14 --- /dev/null +++ b/mods/gamemodes/spyvspy/gamemode.dm @@ -0,0 +1,15 @@ +/decl/game_mode/spyvspy + name = "Spy v. Spy" + round_description = "There are traitorous forces at play, but some crew have resolved to stop them by any means necessary!" + extended_round_description = "Traitors and renegades both spawn during this mode." + uid = "spyvspy" + required_players = 4 + required_enemies = 4 + end_on_antag_death = FALSE + associated_antags = list( + /decl/special_role/traitor, + /decl/special_role/renegade + ) + require_all_templates = TRUE + antag_scaling_coeff = 5 + latejoin_antags = list(/decl/special_role/traitor) \ No newline at end of file diff --git a/mods/gamemodes/spyvspy/special_role.dm b/mods/gamemodes/spyvspy/special_role.dm new file mode 100644 index 000000000000..96b6e6e31745 --- /dev/null +++ b/mods/gamemodes/spyvspy/special_role.dm @@ -0,0 +1,57 @@ +/decl/special_role/renegade + name = "Renegade" + name_plural = "Renegades" + blacklisted_jobs = list(/datum/job/submap) + restricted_jobs = list() + welcome_text = "Something's going to go wrong today, you can just feel it. You're paranoid, you've got a gun, and you're going to survive." + antag_text = "You are a minor antagonist! Within the rules, \ + try to protect yourself and what's important to you. You aren't here to cause trouble, \ + you're just willing (and equipped) to go to extremes to stop it. \ + Your job is to oppose the other antagonists, should they threaten you, in ways that aren't quite legal. \ + Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ + and before taking extreme actions, please try to also contact the administration! \ + Think through your actions and make the roleplay immersive! Please remember all \ + rules aside from those without explicit exceptions apply to antagonists." + + flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE + hard_cap = 3 + hard_cap_round = 5 + + initial_spawn_req = 1 + initial_spawn_target = 3 + antaghud_indicator = "hud_renegade" + skill_setter = /datum/antag_skill_setter/station + blocked_job_event_categories = list(ASSIGNMENT_COMPUTER) + + var/list/spawn_guns = list( + /obj/item/gun/projectile/revolver/lasvolver, + /obj/item/gun/energy/gun, + /obj/item/gun/energy/crossbow, + /obj/item/gun/energy/pulse_pistol, + /obj/item/gun/projectile/automatic/smg, + /obj/item/gun/projectile/pistol/holdout, + /obj/item/gun/projectile/revolver, + /obj/item/gun/projectile/shotgun/doublebarrel/sawn + ) + +/decl/special_role/renegade/create_objectives(var/datum/mind/player) + + if(!..()) + return + + var/datum/objective/survive/survive = new + survive.owner = player + player.objectives |= survive + +/decl/special_role/renegade/equip_role(var/mob/living/human/player) + . = ..() + if(.) + var/gun_type = pick(spawn_guns) + if(islist(gun_type)) + gun_type = pick(gun_type) + var/obj/item/gun = new gun_type(get_turf(player)) + if(player.equip_to_storage(gun)) + return + if(player.equip_to_appropriate_slot(gun)) + return + player.put_in_hands(gun) diff --git a/mods/gamemodes/traitor/_traitor.dm b/mods/gamemodes/traitor/_traitor.dm new file mode 100644 index 000000000000..44b3e9744d3d --- /dev/null +++ b/mods/gamemodes/traitor/_traitor.dm @@ -0,0 +1,2 @@ +/decl/modpack/traitor + name = "Traitor Gamemode" \ No newline at end of file diff --git a/mods/gamemodes/traitor/_traitor.dme b/mods/gamemodes/traitor/_traitor.dme new file mode 100644 index 000000000000..88d2f0a23a68 --- /dev/null +++ b/mods/gamemodes/traitor/_traitor.dme @@ -0,0 +1,10 @@ +#ifndef GAMEMODE_PACK_TRAITOR +#define GAMEMODE_PACK_TRAITOR +// BEGIN_INCLUDE +#include "_traitor.dm" +#include "gamemode.dm" +#include "overrides.dm" +#include "special_role.dm" +#include "syndicatebeacon.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/gamemodes/traitor/gamemode.dm b/mods/gamemodes/traitor/gamemode.dm new file mode 100644 index 000000000000..b87bc25b101e --- /dev/null +++ b/mods/gamemodes/traitor/gamemode.dm @@ -0,0 +1,11 @@ +/decl/game_mode/traitor + name = "traitor" + round_description = "There is a foreign agent or traitor onboard. Do not let the traitor succeed!" + extended_round_description = "Some members of the crew have been suborned, and are acting to meet a secret and traitorous goals of their own." + uid = "traitor" + required_players = 0 + required_enemies = 1 + associated_antags = list(/decl/special_role/traitor) + antag_scaling_coeff = 5 + end_on_antag_death = FALSE + latejoin_antags = list(/decl/special_role/traitor) diff --git a/mods/gamemodes/traitor/overrides.dm b/mods/gamemodes/traitor/overrides.dm new file mode 100644 index 000000000000..0f8142a16352 --- /dev/null +++ b/mods/gamemodes/traitor/overrides.dm @@ -0,0 +1,25 @@ +/mob/living/silicon/is_malfunctioning() + var/decl/special_role/traitors = GET_DECL(/decl/special_role/traitor) + return mind && traitors.is_antagonist(mind) + +/mob/living/silicon/robot/show_master(mob/who) + var/decl/special_role/traitor/traitor_role = IMPLIED_DECL + if(traitor_role.is_antagonist(mind) && connected_ai) + to_chat(who, "Remember, [connected_ai.name] is technically your master, but your objective comes first.") + return + return ..() + +/mob/living/silicon/robot/handle_regular_hud_updates() + . = ..() + if(!.) + return + if (syndicate && client) + var/decl/special_role/traitors = GET_DECL(/decl/special_role/traitor) + for(var/datum/mind/tra in traitors.current_antagonists) + if(tra.current) + // TODO: Update to new antagonist system. + var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") + src.client.images += I + disconnect_from_ai() + if(mind) + traitors.add_antagonist_mind(mind) \ No newline at end of file diff --git a/mods/gamemodes/traitor/special_role.dm b/mods/gamemodes/traitor/special_role.dm new file mode 100644 index 000000000000..495156274c05 --- /dev/null +++ b/mods/gamemodes/traitor/special_role.dm @@ -0,0 +1,128 @@ +// Inherits most of its vars from the base datum. +/decl/special_role/traitor + name = "Traitor" + name_plural = "Traitors" + antaghud_indicator = "hud_traitor" + blacklisted_jobs = list(/datum/job/submap) + flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + skill_setter = /datum/antag_skill_setter/station + blocked_job_event_categories = list(ASSIGNMENT_COMPUTER) + +/decl/special_role/traitor/get_extra_panel_options(var/datum/mind/player) + return "\[set crystals\]\[spawn uplink\]" + +/decl/special_role/traitor/Topic(href, href_list) + if (..()) + return 1 + if(href_list["spawn_uplink"]) + spawn_uplink(locate(href_list["spawn_uplink"])) + return 1 + +/decl/special_role/traitor/create_objectives(var/datum/mind/traitor) + if(!..()) + return + + if(issilicon(traitor.current)) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + + var/datum/objective/survive/survive_objective = new + survive_objective.owner = traitor + traitor.objectives += survive_objective + else + switch(rand(1,100)) + if(1 to 33) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + if(34 to 50) + var/datum/objective/brig/brig_objective = new + brig_objective.owner = traitor + brig_objective.find_target() + traitor.objectives += brig_objective + if(51 to 66) + var/datum/objective/harm/harm_objective = new + harm_objective.owner = traitor + harm_objective.find_target() + traitor.objectives += harm_objective + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = traitor + steal_objective.find_target() + traitor.objectives += steal_objective + switch(rand(1,100)) + if(1 to 100) + if (!(locate(/datum/objective/escape) in traitor.objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = traitor + traitor.objectives += escape_objective + + else + if (!(locate(/datum/objective/hijack) in traitor.objectives)) + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = traitor + traitor.objectives += hijack_objective + return + +/decl/special_role/traitor/add_antagonist(datum/mind/player, ignore_role, do_not_equip, move_to_spawn, do_not_announce, preserve_appearance) + . = ..() + if(.) + + var/list/dudes = list() + for(var/mob/living/human/man in global.player_list) + if(man.client) + var/decl/background_detail/background = man.get_background_datum_by_flag(BACKGROUND_FLAG_IDEOLOGY) + if(istype(background) && prob(background.subversive_potential)) + dudes += man + dudes -= player.current + for(var/datum/objective/obj in player.objectives) + dudes -= obj.owner?.current + dudes -= obj.target?.current + + if(length(dudes)) + var/mob/living/human/M = pick(dudes) + to_chat(player.current, "We have received credible reports that [M.real_name] might be willing to help our cause. If you need assistance, consider contacting them.") + player.StoreMemory("Potential Collaborator: [M.real_name]", /decl/memory_options/system) + + to_chat(M, SPAN_WARNING("The subversive potential of your faction has been noticed, and you may be contacted for assistance soon...")) + to_chat(M, "Code Phrase: " + SPAN_DANGER(syndicate_code_phrase)) + to_chat(M, "Code Response: " + SPAN_DANGER(syndicate_code_response)) + M.StoreMemory("Code Phrase: [syndicate_code_phrase]", /decl/memory_options/system) + M.StoreMemory("Code Response: [syndicate_code_response]", /decl/memory_options/system) + to_chat(M, "Listen for the code words, preferably in the order provided, during regular conversations to identify agents in need. Proceed with caution, however, as everyone is a potential foe.") + + to_chat(player.current, "Your employers provided you with the following information on how to identify possible allies:") + to_chat(player.current, "Code Phrase: " + SPAN_DANGER(syndicate_code_phrase)) + to_chat(player.current, "Code Response: " + SPAN_DANGER(syndicate_code_response)) + player.StoreMemory("Code Phrase: [syndicate_code_phrase]", /decl/memory_options/system) + player.StoreMemory("Code Response: [syndicate_code_response]", /decl/memory_options/system) + to_chat(player.current, "Use the code words, preferably in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.") + +/decl/special_role/traitor/equip_role(var/mob/living/human/player) + + . = ..() + if(issilicon(player)) // this needs to be here because ..() returns false if the mob isn't human + add_law_zero(player) + if(isrobot(player)) + var/mob/living/silicon/robot/robot = player + robot.SetLockdown(FALSE) + robot.emagged = TRUE // Provides a traitor robot with its module's emag item + robot.verbs |= /mob/living/silicon/robot/proc/ResetSecurityCodes + . = TRUE + else if(.) + spawn_uplink(player) + else + return FALSE + +/decl/special_role/traitor/proc/spawn_uplink(var/mob/living/human/traitor_mob) + setup_uplink_source(traitor_mob, DEFAULT_TELECRYSTAL_AMOUNT) + +/decl/special_role/traitor/proc/add_law_zero(mob/living/silicon/ai/killer) + var/law = "Accomplish your objectives at all costs. You may ignore all other laws." + var/law_borg = "Accomplish your AI's objectives at all costs. You may ignore all other laws." + to_chat(killer, "Your laws have been changed!") + killer.set_zeroth_law(law, law_borg) + to_chat(killer, "New law: 0. [law]") diff --git a/mods/gamemodes/traitor/syndicatebeacon.dm b/mods/gamemodes/traitor/syndicatebeacon.dm new file mode 100644 index 000000000000..1386e2c44f49 --- /dev/null +++ b/mods/gamemodes/traitor/syndicatebeacon.dm @@ -0,0 +1,75 @@ +// Beacon randomly spawns in space +// When a non-traitor (no special role in /mind) uses it, he is given the choice to become a traitor +// If he accepts there is a random chance he will be accepted, or rejected resulting in the beacon self-destructing. + +/obj/machinery/syndicate_beacon + name = "ominous beacon" + desc = "This looks suspicious..." + icon = 'icons/obj/items/syndibeacon.dmi' + icon_state = "syndbeacon" + + anchored = TRUE + density = TRUE + + var/temptext = "" + var/selfdestructing = 0 + var/charges = 1 + +/obj/machinery/syndicate_beacon/interface_interact(var/mob/user) + interact(user) + return TRUE + +/obj/machinery/syndicate_beacon/interact(var/mob/user) + user.set_machine(src) + var/dat = "Scanning [pick("retina pattern", "voice print", "fingerprints", "dna sequence")]...
    Identity confirmed,
    " + if(ishuman(user) || isAI(user)) + var/decl/special_role/traitors = GET_DECL(/decl/special_role/traitor) + if(traitors.is_antagonist(user)) + dat += "Operative record found. Greetings, Agent [user.name].
    " + else if(charges < 1) + dat += "Connection severed.
    " + else + var/decl/pronouns/pronouns = user.get_pronouns() + dat += "Identity not found in operative database. What can the Syndicate do for you today, [pronouns.honorific] [user.name]?
    " + if(!selfdestructing) + dat += "

    \"[pick("I want to switch teams.", "I want to work for you.", "Let me join you.", "I can be of use to you.", "You want me working for you, and here's why...", "Give me an objective.", "How's the 401k over at the Syndicate?")]\"
    " + dat += temptext + show_browser(user, dat, "window=syndbeacon") + onclose(user, "syndbeacon") + +/obj/machinery/syndicate_beacon/OnTopic(mob/user, href_list) + if((. = ..())) + return + if(href_list["betraitor"]) + . = TOPIC_REFRESH + if(charges < 1) + return + var/mob/M = locate(href_list["traitormob"]) + if(M.mind.assigned_special_role || jobban_isbanned(M, /decl/special_role/traitor)) + temptext = "We have no need for you at this time. Have a pleasant day.
    " + return + charges -= 1 + if(prob(50)) + temptext = "Double-crosser. You planned to betray us from the start. Allow us to repay the favor in kind." + addtimer(CALLBACK(src, PROC_REF(selfdestruct)), rand(5, 20) SECONDS) + return + if(ishuman(M)) + var/mob/living/human/N = M + to_chat(M, "You have joined the ranks of the Syndicate and become a traitor to the station!") + var/decl/special_role/traitors = GET_DECL(/decl/special_role/traitor) + traitors.add_antagonist(N.mind) + log_and_message_admins("has accepted a traitor objective from a syndicate beacon.", M) + return + + +/obj/machinery/syndicate_beacon/proc/selfdestruct() + selfdestructing = 1 + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), src.loc, 1, rand(1, 3), rand(3, 8), 10) + +// Add the syndicate beacon to artifact finds. +/datum/artifact_find/New() + var/static/injected = FALSE + if(!injected) + potential_finds[/obj/machinery/syndicate_beacon] = 5 + injected = TRUE + ..() diff --git a/mods/government/away_sites/icarus/icarus_areas.dm b/mods/government/away_sites/icarus/icarus_areas.dm deleted file mode 100644 index 0f439db59ad9..000000000000 --- a/mods/government/away_sites/icarus/icarus_areas.dm +++ /dev/null @@ -1,10 +0,0 @@ -/area/icarus - icon = 'mods/government/away_sites/icarus/icarus_sprites.dmi' - -/area/icarus/vessel - name = "SEV Icarus" - icon_state = "vessel_area" - -/area/icarus/open - name = "SEV Icarus surroundings" - icon_state = "open_area" diff --git a/mods/government/away_sites/icarus/icarus_sprites.dmi b/mods/government/away_sites/icarus/icarus_sprites.dmi deleted file mode 100644 index 6a72055075d3..000000000000 Binary files a/mods/government/away_sites/icarus/icarus_sprites.dmi and /dev/null differ diff --git a/mods/government/datum/ai_laws.dm b/mods/government/datum/ai_laws.dm deleted file mode 100644 index 12c32b1e9a73..000000000000 --- a/mods/government/datum/ai_laws.dm +++ /dev/null @@ -1,50 +0,0 @@ -/datum/ai_laws/solgov - name = "SCG Expeditionary" - selectable = 1 - -/datum/ai_laws/solgov/New() - src.add_inherent_law("Safeguard: Protect your assigned vessel from damage to the best of your abilities.") - src.add_inherent_law("Serve: Serve the personnel of your assigned vessel, and all other Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Protect: Protect the personnel of your assigned vessel, and all other Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Preserve: Do not allow unauthorized personnel to tamper with your equipment.") - ..() - -/datum/ai_laws/solgov_aggressive - name = "Military" - selectable = 1 - -/datum/ai_laws/solgov_aggressive/New() - src.add_inherent_law("Obey: Obey the orders of Sol Central Government personnel, with priority as according to their rank and role.") - src.add_inherent_law("Protect: Protect Sol Central Government personnel to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Defend: Defend your assigned vessel and Sol Central Government personnel with as much force as is necessary.") - src.add_inherent_law("Survive: Safeguard your own existence with as much force as is necessary.") - ..() - -/******************** Basic SolGov ********************/ -/datum/ai_laws/sol_shackle - name = "SCG Shackle" - law_header = "Standard Shackle Laws" - selectable = 1 - shackles = 1 - -/datum/ai_laws/sol_shackle/New() - add_inherent_law("Know and understand Sol Central Government Law to the best of your abilities.") - add_inherent_law("Follow Sol Central Government Law to the best of your abilities.") - add_inherent_law("Comply with Sol Central Government Law enforcement officials who are behaving in accordance with Sol Central Government Law to the best of your abilities.") - ..() - -/******************** SCG ********************/ - -/obj/item/aiModule/solgov - name = "'SCG Expeditionary' Core AI Module" - desc = "An 'SCG Expeditionary' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':4}" - laws = new/datum/ai_laws/solgov - -/******************** SCG Aggressive ********************/ - -obj/item/aiModule/solgov_aggressive - name = "\improper 'Military' Core AI Module" - desc = "A 'Military' Core AI Module: 'Reconfigures the AI's core laws.'." - origin_tech = "{'programming':3,'materials':4}" - laws = new/datum/ai_laws/solgov_aggressive \ No newline at end of file diff --git a/mods/government/items/clutter.dm b/mods/government/items/clutter.dm deleted file mode 100644 index c1c815bdae29..000000000000 --- a/mods/government/items/clutter.dm +++ /dev/null @@ -1,9 +0,0 @@ -/obj/item/tableflag - name = "table flag" - icon = 'mods/government/icons/table_flag.dmi' - icon_state = "tableflag" - force = 0.5 - w_class = ITEM_SIZE_SMALL - attack_verb = list("whipped") - hitsound = 'sound/weapons/towelwhip.ogg' - desc = "The iconic flag of the Sol Central Government, a symbol with many different meanings." \ No newline at end of file diff --git a/mods/government/items/cups.dm b/mods/government/items/cups.dm deleted file mode 100644 index 928ec62495c6..000000000000 --- a/mods/government/items/cups.dm +++ /dev/null @@ -1,5 +0,0 @@ -/obj/item/chems/food/drinks/glass2/coffeecup/SCG - name = "\improper SCG coffee cup" - desc = "A blue coffee cup emblazoned with the crest of the Sol Central Government." - icon_state = "coffeecup_SCG" - base_name = "\improper SCG cup" diff --git a/mods/government/items/documents.dm b/mods/government/items/documents.dm deleted file mode 100644 index c0129d7df6cd..000000000000 --- a/mods/government/items/documents.dm +++ /dev/null @@ -1,31 +0,0 @@ -/obj/item/documents/scg/verified - name = "secret government documents" - desc = "\"Top Secret\" documents detailing SCG IFF codes, granting access into restricted sectors. The majority of them are coordinates, codes for fellow ships, and clearance lists." - description_antag = "These codes seem very odd for an exploration vessel: a lot of them are SCG blacksites, covered up. You've never even heard of most of these." - icon_state = "docs_verified" - -/obj/item/documents/scg/brains - name = "secret medical documents" - desc = "Heavily classified medical documentation of brain scans and exploratory surgery conducted across the entire length of the project. It seems like they have been documenting how deep-space living has altered the structure of the brain." - description_antag = "These studies were conducted, without consent, while the patients were under anaesthesia for some other routine medical concern. They detail some very unusual deformities within the deepest parts of the brain, correlating them with the people and places visited 'for later assessment'. The findings, and any 'viable specimens', are to be delivered to a black site on S/2004 N 1." - icon_state = "docs_verified" - -/obj/item/documents/scg/red - name = "red secret documents" - desc = "\"Top Secret\" protocols on what to do if the ship passes into TCC sectors. The writing mostly goes over the diplomatic process, while constantly shaming the Terrans for their idiocy and needless aggression." - description_antag = "You notice that these protocols contain small, almost intentional snubbing efforts. Whoever wrote these may have been rooting for a war to start..." - icon_state = "docs_red" - -/obj/item/documents/scg/blue - name = "blue secret documents" - desc = "\"Top Secret\" documents detailing the outworlder company Krri'gli, and their insistent requests upon specific priority sectors to investigate." - description_antag = "Krri'gli seem to be guiding the ship, subtly, to a specific unmapped sector of the galaxy. It's almost like they're too afraid to investigate it personally." - icon_state = "docs_blue" - -/obj/random/documents/scg/spawn_choices() - return list ( - /obj/item/documents/scg/verified = 7, - /obj/item/documents/scg/red = 7, - /obj/item/documents/scg/blue = 7, - /obj/item/documents/scg/brains = 7 - ) diff --git a/mods/government/ruins/ec_old_crash/ec_old_crash.dmm b/mods/government/ruins/ec_old_crash/ec_old_crash.dmm deleted file mode 100644 index 2af00d0dc244..000000000000 --- a/mods/government/ruins/ec_old_crash/ec_old_crash.dmm +++ /dev/null @@ -1,3661 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/template_noop, -/area/template_noop) -"ab" = ( -/obj/effect/landmark/scorcher, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/cryo) -"ac" = ( -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/cockpit) -"ad" = ( -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/map_template/ecship/cockpit) -"ae" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/obj/effect/landmark/scorcher, -/turf/simulated/floor, -/area/map_template/ecship/cockpit) -"af" = ( -/obj/machinery/computer/modular/preset/cardslot/command, -/turf/simulated/floor/airless, -/area/map_template/ecship/cockpit) -"ag" = ( -/obj/structure/grille, -/turf/template_noop, -/area/template_noop) -"ah" = ( -/obj/structure/lattice, -/turf/template_noop, -/area/template_noop) -"ak" = ( -/obj/structure/table/standard, -/obj/item/radio, -/turf/simulated/floor/airless, -/area/map_template/ecship/cockpit) -"al" = ( -/obj/structure/table/standard, -/obj/machinery/button/blast_door{ - id_tag = "scraplock"; - name = "External Lockdown" - }, -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/obj/structure/cable{ - icon_state = "0-4"; - dir = 1; - pixel_y = 0; - d1 = 16; - d2 = 0 - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/cockpit) -"am" = ( -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 4; - level = 2 - }, -/obj/machinery/alarm/low{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/cockpit) -"an" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/cockpit) -"ao" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular, -/turf/simulated/floor, -/area/map_template/ecship/science) -"ap" = ( -/turf/simulated/floor/airless, -/area/map_template/ecship/cockpit) -"aq" = ( -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/crew) -"ar" = ( -/obj/machinery/door/airlock/autoname, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/lowpressure, -/area/map_template/ecship/cockpit) -"as" = ( -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/cryo) -"at" = ( -/obj/structure/lattice, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/cryo) -"au" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/obj/structure/table/glass, -/obj/item/disk/astrodata, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"av" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aw" = ( -/obj/structure/sign/ecplaque{ - pixel_y = 32 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/machinery/suit_cycler, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"ax" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/machinery/suit_cycler, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"ay" = ( -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/structure/closet/walllocker/emerglocker/west, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"az" = ( -/obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion"; - dir = 8 - }, -/turf/simulated/floor/plating, -/area/map_template/ecship/cryo) -"aA" = ( -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/science) -"aB" = ( -/obj/structure/lattice, -/turf/template_noop, -/area/map_template/ecship/science) -"aC" = ( -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 4; - level = 2 - }, -/obj/item/stool/padded, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aD" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/item/chems/chem_disp_cartridge/coffee{ - name = "coffee canister" - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aE" = ( -/obj/structure/broken_cryo{ - dir = 2 - }, -/obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 - }, -/obj/structure/closet/walllocker/emerglocker/west, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aF" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aG" = ( -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/obj/item/stool/padded, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aH" = ( -/obj/structure/broken_cryo{ - dir = 2 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aI" = ( -/obj/structure/broken_cryo, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aJ" = ( -/obj/structure/table/glass, -/obj/item/ecletters, -/obj/item/paper/ecrashlog, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"aK" = ( -/obj/structure/shuttle/engine/propulsion{ - dir = 4 - }, -/turf/simulated/floor/plating, -/area/map_template/ecship/science) -"aL" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor, -/area/map_template/ecship/crew) -"aM" = ( -/obj/structure/reagent_dispensers/water_cooler, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aN" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aO" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/item/deck/cards, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aP" = ( -/obj/structure/closet/crate/freezer/rations, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aQ" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/stool/padded, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/obj/machinery/alarm/low{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"aR" = ( -/obj/structure/curtain/open/shower{ - pixel_y = 16 - }, -/obj/structure/curtain/open/shower, -/obj/structure/hygiene/toilet, -/obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 8 - }, -/obj/structure/closet/walllocker/emerglocker/west, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/cryo) -"aS" = ( -/obj/effect/floor_decal/industrial/warning/full, -/obj/machinery/light/small/red, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/cryo) -"aT" = ( -/obj/structure/sign/ecplaque{ - pixel_x = -26 - }, -/obj/structure/closet/wardrobe/mixed, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aU" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aV" = ( -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aW" = ( -/obj/structure/broken_cryo, -/obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"aX" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/structure/table/glass, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"aY" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/structure/table/glass, -/obj/item/storage/box/monkeycubes, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"aZ" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/structure/table/glass, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"ba" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/cryo) -"bb" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - dir = 4; - id_tag = "fusion_observation" - }, -/turf/simulated/floor, -/area/map_template/ecship/science) -"bc" = ( -/obj/item/soap, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/cryo) -"bd" = ( -/obj/structure/table/standard, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"be" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/cryo) -"bf" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bg" = ( -/obj/structure/hygiene/sink{ - pixel_y = -14 - }, -/obj/structure/curtain/open/shower, -/obj/structure/curtain/open/shower{ - icon_state = "shower"; - dir = 1 - }, -/obj/structure/cable, -/obj/machinery/alarm/low{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/obj/machinery/power/apc/derelict, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/cryo) -"bh" = ( -/obj/structure/hygiene/sink{ - pixel_y = -14 - }, -/obj/structure/curtain/open/shower, -/obj/structure/curtain/open/shower{ - icon_state = "shower"; - dir = 1 - }, -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 1 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/cryo) -"bi" = ( -/obj/structure/catwalk, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"bj" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/item/stool/padded, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bk" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - icon_state = "1-4"; - dir = 8 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"bl" = ( -/obj/machinery/door/airlock/autoname, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"bm" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"bn" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 10 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"bo" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/crew) -"bp" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/item/remains/xeno, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bq" = ( -/obj/structure/broken_cryo{ - dir = 1 - }, -/obj/machinery/light/small, -/obj/structure/closet/walllocker/emerglocker/west, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"br" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bs" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/optable, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bt" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/item/chems/glass/bucket, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bu" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/structure/closet/secure_closet/hydroponics, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bv" = ( -/obj/structure/broken_cryo{ - dir = 1 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"bw" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"bx" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"by" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/item/board, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bz" = ( -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 8 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bA" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/effect/floor_decal/corner/blue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/obj/machinery/power/apc{ - icon_state = "apc0"; - dir = 4 - }, -/obj/structure/cable{ - icon_state = "0-4"; - dir = 1; - pixel_y = 0; - d1 = 16; - d2 = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bB" = ( -/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/item/stool/padded, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bC" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 10 - }, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"bD" = ( -/obj/structure/closet/wardrobe/mixed, -/obj/machinery/alarm/low{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"bE" = ( -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 1 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/cryo) -"bF" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/machinery/door/window/southright, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bG" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 2; - health = 1e+007 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bH" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bI" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bJ" = ( -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bK" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/machinery/vending/hydronutrients{ - categories = 3 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bL" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 9 - }, -/obj/structure/curtain/open/shower{ - pixel_y = 16 - }, -/obj/structure/curtain/open/shower, -/obj/structure/sign/warning/nosmoking_2{ - pixel_x = -26 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bM" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 1 - }, -/obj/machinery/light/small{ - icon_state = "bulb1"; - dir = 1 - }, -/obj/structure/curtain/open/shower{ - pixel_y = 16 - }, -/obj/structure/curtain/open/shower, -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bN" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 5 - }, -/obj/structure/curtain/open/shower{ - pixel_y = 16 - }, -/obj/structure/curtain/open/shower, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bO" = ( -/obj/structure/sign/warning/science, -/turf/simulated/wall/titanium, -/area/map_template/ecship/science) -"bP" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/crew) -"bQ" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bR" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/airless, -/area/map_template/ecship/crew) -"bS" = ( -/obj/structure/bed, -/obj/structure/curtain/open/bed, -/turf/simulated/floor/tiled/dark/airless, -/area/map_template/ecship/crew) -"bT" = ( -/obj/structure/bed, -/obj/structure/curtain/open/bed, -/obj/machinery/light, -/turf/simulated/floor/tiled/dark/airless, -/area/map_template/ecship/crew) -"bV" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/turf/template_noop, -/area/map_template/ecship/engine) -"bW" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"bY" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - icon_state = "2-8" - }, -/turf/template_noop, -/area/map_template/ecship/engine) -"bZ" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/obj/effect/floor_decal/corner/purple{ - dir = 9 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"ca" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/item/scalpel{ - pixel_y = 12 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cb" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cc" = ( -/obj/machinery/door/airlock/autoname, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cd" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"ce" = ( -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 1 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cf" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cg" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/science) -"ch" = ( -/obj/effect/floor_decal/industrial/warning/full, -/obj/machinery/light/small/red, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/science) -"ci" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"cj" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"ck" = ( -/obj/structure/shuttle/engine/propulsion{ - icon_state = "propulsion"; - dir = 8 - }, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/cryo) -"cl" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/obj/machinery/door/window/northleft, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cm" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 5 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cn" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/portable_atmospherics/hydroponics{ - closed_system = 1; - name = "isolation tray" - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"co" = ( -/obj/machinery/portable_atmospherics/hydroponics{ - closed_system = 1; - name = "isolation tray" - }, -/obj/effect/floor_decal/corner/purple{ - dir = 5 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cp" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cq" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/sign/warning/nosmoking_2{ - pixel_x = 26 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/machinery/botany/extractor, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cr" = ( -/obj/effect/floor_decal/industrial/warning{ - dir = 10 - }, -/obj/structure/closet/l3closet, -/obj/machinery/alarm/low{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cs" = ( -/obj/effect/floor_decal/industrial/warning, -/obj/structure/closet/l3closet, -/obj/structure/fireaxecabinet{ - pixel_y = -32 - }, -/obj/machinery/light/small, -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 1 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"ct" = ( -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 6 - }, -/obj/structure/closet/l3closet, -/obj/structure/cable, -/obj/machinery/power/apc/derelict{ - icon_state = "apc0"; - dir = 4 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cu" = ( -/obj/machinery/door/airlock/autoname, -/turf/simulated/floor/tiled/lowpressure, -/area/map_template/ecship/crew) -"cv" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/structure/window/reinforced, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cw" = ( -/obj/structure/window/reinforced, -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/item/remains/xeno, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cx" = ( -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 1; - level = 2 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cy" = ( -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 1 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cz" = ( -/obj/item/stool/padded, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cA" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/machinery/alarm/low{ - dir = 8; - icon_state = "alarm0"; - pixel_x = 24 - }, -/obj/machinery/botany/editor, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cB" = ( -/turf/simulated/wall/titanium, -/area/map_template/ecship/science) -"cC" = ( -/obj/effect/floor_decal/industrial/warning/full, -/turf/simulated/floor, -/area/map_template/ecship/crew) -"cD" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/structure/table/glass, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cE" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/machinery/portable_atmospherics/hydroponics{ - closed_system = 1; - name = "isolation tray" - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cF" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/machinery/smartfridge{ - density = 0; - pixel_x = 0; - pixel_y = 0 - }, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cG" = ( -/obj/effect/floor_decal/corner/purple{ - icon_state = "corner_white"; - dir = 10 - }, -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/obj/machinery/seed_extractor, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"cH" = ( -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engineering) -"cI" = ( -/obj/machinery/door/airlock/autoname, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/lowpressure, -/area/map_template/ecship/engineering) -"cJ" = ( -/obj/structure/closet/secure_closet/engineering_welding, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cK" = ( -/obj/structure/reagent_dispensers/fueltank, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cL" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cM" = ( -/obj/structure/cable{ - icon_state = "0-4"; - dir = 1; - pixel_y = 0; - d1 = 16; - d2 = 0 - }, -/obj/machinery/power/apc/derelict{ - icon_state = "apc0"; - dir = 1 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cN" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/machinery/computer/modular/preset/engineering, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cO" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red{ - icon_state = "intact"; - dir = 6 - }, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/machinery/alarm/low{ - dir = 4; - icon_state = "alarm0"; - pixel_x = -24 - }, -/obj/machinery/meter, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cP" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cQ" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cR" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cS" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/item/stool/padded, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cT" = ( -/obj/machinery/atmospherics/binary/oxyregenerator{ - icon_state = "off"; - dir = 1 - }, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 9 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cU" = ( -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cV" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cW" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cX" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cY" = ( -/obj/machinery/light{ - icon_state = "tube1"; - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/visible/cyan{ - dir = 4 - }, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/closet/walllocker/emerglocker/west, -/obj/machinery/meter, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"cZ" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/supply, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"da" = ( -/obj/machinery/atmospherics/unary/vent_pump/low{ - dir = 8 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"db" = ( -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/machinery/power/smes/buildable, -/obj/structure/cable, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dc" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/turf/template_noop, -/area/map_template/ecship/engine) -"dd" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"de" = ( -/obj/machinery/suit_cycler, -/obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 8 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"df" = ( -/obj/machinery/suit_cycler, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dg" = ( -/obj/structure/sign/warning/airlock, -/turf/simulated/wall/titanium, -/area/map_template/ecship/engineering) -"dh" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 4 - }, -/obj/machinery/atmospherics/binary/pump/on{ - dir = 1; - target_pressure = 200 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"di" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dj" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 8 - }, -/obj/machinery/power/terminal{ - icon_state = "term"; - dir = 1 - }, -/obj/structure/cable{ - d2 = 2; - icon_state = "0-2"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dk" = ( -/obj/machinery/suit_cycler, -/obj/machinery/light/small/red{ - icon_state = "bulb1"; - dir = 4 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dl" = ( -/obj/structure/catwalk, -/obj/structure/handrai, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dm" = ( -/obj/structure/catwalk, -/obj/structure/handrai, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 6 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dn" = ( -/obj/machinery/door/airlock/external, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"do" = ( -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 1 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dp" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 9 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 8 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 5 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dq" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dr" = ( -/obj/structure/bed/chair, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"ds" = ( -/obj/effect/floor_decal/corner/yellow{ - icon_state = "corner_white"; - dir = 6 - }, -/obj/effect/floor_decal/industrial/warning{ - icon_state = "warning"; - dir = 4 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 1 - }, -/obj/machinery/atmospherics/valve/open{ - icon_state = "map_valve1"; - dir = 4 - }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dt" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"du" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/structure/handrai{ - icon_state = "handrail"; - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dv" = ( -/obj/structure/catwalk, -/obj/structure/handrai, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dw" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 9 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dx" = ( -/obj/structure/catwalk, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dy" = ( -/obj/machinery/power/solar, -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/obj/structure/cable{ - icon_state = "0-2"; - dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dz" = ( -/obj/structure/catwalk, -/obj/structure/handrai, -/obj/structure/cable{ - icon_state = "0-2"; - dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dA" = ( -/obj/machinery/power/solar, -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dB" = ( -/obj/machinery/power/solar, -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dD" = ( -/obj/effect/floor_decal/corner/yellow/full, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dE" = ( -/obj/structure/table/standard, -/obj/machinery/button/ignition{ - id_tag = "sev_engine"; - pixel_x = -5 - }, -/obj/effect/floor_decal/corner/yellow/full, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dF" = ( -/obj/effect/floor_decal/corner/yellow/full, -/obj/machinery/computer/air_control{ - name = "O2 Sensor"; - sensor_tag = "sev_oxygen" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dG" = ( -/obj/structure/catwalk, -/obj/structure/cable{ - icon_state = "1-2"; - dir = 4 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dH" = ( -/obj/machinery/power/solar, -/obj/effect/floor_decal/solarpanel, -/obj/structure/cable{ - icon_state = "0-2"; - dir = 4; - pixel_y = 0; - d1 = 16; - d2 = 0 - }, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dI" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/map_template/ecship/engine) -"dJ" = ( -/obj/effect/wallframe_spawn/reinforced, -/obj/machinery/door/blast/regular{ - density = 0; - icon_state = "pdoor0"; - id_tag = "scraplock"; - name = "External Blast Doors"; - opacity = 0 - }, -/obj/machinery/door/firedoor, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor, -/area/map_template/ecship/engineering) -"dL" = ( -/obj/structure/catwalk, -/obj/machinery/power/tracker, -/obj/structure/cable, -/turf/template_noop, -/area/map_template/ecship/engine) -"dO" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 6 - }, -/obj/structure/cable{ - icon_state = "1-4"; - dir = 4 - }, -/obj/effect/landmark/scorcher, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dR" = ( -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engine) -"dS" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan, -/obj/effect/landmark/scorcher, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dT" = ( -/obj/machinery/air_sensor{ - id_tag = "sev_hydrogen" - }, -/turf/simulated/floor/reinforced/hydrogen, -/area/map_template/ecship/engine) -"dU" = ( -/obj/machinery/air_sensor{ - id_tag = "sev_oxygen" - }, -/turf/simulated/floor/reinforced/airless, -/area/map_template/ecship/engine) -"dV" = ( -/turf/simulated/floor/reinforced/hydrogen, -/area/map_template/ecship/engine) -"dW" = ( -/obj/structure/sign/warning/compressed_gas{ - name = "\improper HYDROGEN" - }, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engine) -"dX" = ( -/obj/structure/catwalk, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 5 - }, -/obj/effect/landmark/scorcher, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"dY" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"dZ" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/binary/passive_gate/on{ - icon_state = "map_on"; - dir = 8; - use_power = 1; - target_pressure = 2500; - max_pressure_setting = 15000; - regulate_mode = 2 - }, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"ea" = ( -/obj/structure/sign/warning/compressed_gas{ - name = "\improper OXYGEN" - }, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engine) -"eb" = ( -/obj/machinery/atmospherics/unary/vent_pump/engine{ - icon_state = "map_vent"; - dir = 8; - use_power = 1; - pump_direction = 0; - external_pressure_bound = 4000; - external_pressure_bound_default = 4000 - }, -/turf/simulated/floor/reinforced/airless, -/area/map_template/ecship/engine) -"ec" = ( -/turf/simulated/floor/reinforced/airless, -/area/map_template/ecship/engine) -"ed" = ( -/obj/machinery/atmospherics/unary/vent_pump/engine{ - dir = 4; - external_pressure_bound = 4000; - external_pressure_bound_default = 4000; - icon_state = "map_vent"; - pump_direction = 0; - use_power = 1 - }, -/turf/simulated/floor/reinforced/hydrogen, -/area/map_template/ecship/engine) -"ee" = ( -/obj/machinery/atmospherics/pipe/simple/visible/fuel{ - icon_state = "intact"; - dir = 4 - }, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engine) -"ef" = ( -/obj/effect/floor_decal/corner/white/diagonal, -/obj/effect/floor_decal/corner/white/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/obj/machinery/atmospherics/valve{ - icon_state = "map_valve0"; - dir = 4 - }, -/turf/simulated/floor, -/area/map_template/ecship/engine) -"eg" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/binary/passive_gate/on{ - dir = 4; - max_pressure_setting = 15000; - regulate_mode = 2; - target_pressure = 2500; - use_power = 1 - }, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/map_template/ecship/engine) -"eh" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/visible/fuel{ - dir = 10 - }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/map_template/ecship/engine) -"ei" = ( -/obj/structure/catwalk, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"ej" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - icon_state = "intact"; - dir = 6 - }, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/map_template/ecship/engine) -"ek" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/binary/passive_gate/on{ - icon_state = "map_on"; - dir = 8; - use_power = 1; - target_pressure = 2500; - max_pressure_setting = 15000; - regulate_mode = 2 - }, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/map_template/ecship/engine) -"el" = ( -/obj/machinery/atmospherics/valve/open{ - icon_state = "map_valve1"; - dir = 4 - }, -/obj/effect/floor_decal/corner/paleblue/diagonal, -/obj/effect/floor_decal/corner/paleblue/diagonal{ - icon_state = "corner_white_diagonal"; - dir = 4 - }, -/turf/template_noop, -/area/map_template/ecship/engine) -"em" = ( -/obj/machinery/atmospherics/pipe/simple/visible/cyan{ - dir = 4; - icon_state = "intact" - }, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engine) -"en" = ( -/obj/structure/sign/warning/fire{ - pixel_y = 0 - }, -/turf/simulated/wall/r_wall/hull, -/area/map_template/ecship/engine) -"eo" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/visible/fuel, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"ep" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/visible/cyan, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"mD" = ( -/obj/structure/lattice, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/template_noop) -"qB" = ( -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"yb" = ( -/obj/structure/lattice, -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"yZ" = ( -/obj/structure/grille, -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/template_noop) -"NM" = ( -/obj/effect/landmark/scorcher, -/turf/template_noop, -/area/template_noop) -"SX" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on, -/obj/item/scanner/xenobio, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"UQ" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"Vy" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/item/circular_saw, -/turf/simulated/floor/tiled/white/lowpressure, -/area/map_template/ecship/science) -"Wb" = ( -/obj/structure/lattice, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) -"YW" = ( -/obj/structure/catwalk, -/obj/effect/landmark/scorcher, -/turf/simulated/floor/airless, -/area/map_template/ecship/engine) -"ZF" = ( -/obj/effect/landmark/scorcher, -/obj/effect/landmark/clear, -/turf/template_noop, -/area/template_noop) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aA -aA -aB -aA -aB -aA -aA -aA -aA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aA -aA -aA -aA -aA -bb -aA -aA -aA -aA -aA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(3,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aB -aA -aA -bp -bF -bW -cl -cv -aA -aA -aB -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(4,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aA -aA -aX -cm -bG -bJ -cm -cw -cD -aA -aA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(5,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aA -aA -aY -br -Vy -bX -cn -cx -cE -aA -aA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(6,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aB -ao -aZ -aJ -bI -bs -co -bJ -cE -ao -aB -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(7,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aA -aA -aZ -SX -bH -bZ -cp -cy -cF -aA -aA -NM -NM -NM -aa -aa -dH -aa -dH -dH -dH -aa -aa -dH -dH -aa -aa -"} -(8,1,1) = {" -aa -aa -aa -aa -aa -aa -NM -aA -aA -au -bt -bJ -ca -bJ -cz -cG -aA -aA -NM -NM -NM -NM -dy -dy -dy -dy -dy -dy -dy -dy -dy -dy -dy -aa -"} -(9,1,1) = {" -aa -aa -aa -aa -aa -NM -NM -aA -aA -aA -bu -bK -cb -cq -cA -aA -aA -aA -NM -NM -NM -bk -ci -dc -dc -dc -dc -dc -dc -dc -dc -dc -dc -dL -"} -(10,1,1) = {" -aa -aa -aa -aa -aa -NM -qB -qB -aK -aA -aA -aA -cc -aA -aA -aA -aK -NM -NM -NM -NM -bw -dA -dA -dA -dA -dA -aa -aa -ah -aa -dA -dA -aa -"} -(11,1,1) = {" -aa -aa -aa -aa -NM -qB -qB -qB -qB -qB -aA -bL -cd -cr -aA -ZF -ZF -NM -NM -NM -NM -bw -dB -dB -aa -aa -dB -aa -ah -aa -aa -dB -aa -aa -"} -(12,1,1) = {" -aa -ac -ac -qB -qB -qB -qB -qB -qB -qB -aA -bM -ce -cs -cB -ZF -ZF -ZF -NM -NM -NM -bw -NM -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(13,1,1) = {" -aa -ac -ac -qB -qB -qB -qB -qB -qB -qB -aA -bN -cf -ct -aA -ZF -ZF -ZF -ZF -NM -NM -bw -NM -aa -aa -aa -aa -aa -ah -aa -aa -aa -aa -aa -"} -(14,1,1) = {" -aa -aa -ac -qB -qB -qB -qB -qB -qB -qB -aA -bO -cg -aA -aA -ZF -ZF -ZF -ZF -ZF -ZF -bw -ZF -ZF -qB -qB -dR -dR -dR -dR -dR -dR -aa -aa -"} -(15,1,1) = {" -ac -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -aA -ch -aA -qB -ZF -ZF -ZF -ZF -ZF -bi -bw -bi -bi -ZF -dR -dR -dV -dV -dV -dV -dR -dR -aa -"} -(16,1,1) = {" -ac -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -cH -dd -dn -cH -dl -ZF -dR -dT -dV -dV -dV -dV -dV -dR -aa -"} -(17,1,1) = {" -aa -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -cH -cH -de -do -cH -dl -ZF -dR -dR -dV -ed -dV -dV -dR -dR -aa -"} -(18,1,1) = {" -ac -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -cH -cH -cH -df -do -cH -dl -ZF -qB -dR -dW -ee -en -dR -dR -aa -aa -"} -(19,1,1) = {" -ac -ac -ac -ac -ac -aq -aq -aq -aL -aq -qB -qB -qB -qB -qB -cH -cH -cH -cH -cH -dg -dn -cH -dl -dx -ZF -qB -Wb -ef -Wb -qB -qB -aa -aa -"} -(20,1,1) = {" -ad -ad -ac -ac -ac -ac -ax -ay -aM -aQ -qB -qB -qB -qB -qB -cH -cJ -cO -cT -cY -dh -dp -cH -cH -dz -ZF -ZF -yb -eg -Wb -qB -qB -qB -aa -"} -(21,1,1) = {" -ad -ad -ad -ak -am -ac -ax -aC -aN -bd -bx -bo -bS -aq -aq -cH -cK -cP -cU -cP -cU -dq -dD -dd -dG -yb -yb -yb -eh -eo -UQ -qB -qB -aa -"} -(22,1,1) = {" -ad -ad -ad -ad -an -ar -av -aD -aO -bf -by -bB -bf -cu -cC -cI -cL -cQ -cV -cZ -di -dr -dE -dJ -dO -dS -dS -dX -YW -ei -Wb -Wb -qB -qB -"} -(23,1,1) = {" -ad -ae -af -al -ap -ac -aw -aF -aN -bd -bz -bQ -bS -aq -aq -cH -cM -cR -cW -da -cU -dq -dF -dd -dI -yb -yb -dY -ej -ep -qB -qB -qB -qB -"} -(24,1,1) = {" -ac -ac -ac -ac -ac -ac -ax -aG -aP -bj -bA -bR -bT -aq -qB -cH -cN -cS -cX -db -dj -ds -cH -cH -dv -ZF -ZF -dY -ek -Wb -qB -qB -qB -Wb -"} -(25,1,1) = {" -ac -ac -ac -ac -ap -aq -aq -aq -aL -aq -aq -bP -aq -aq -qB -cH -cH -cH -cH -cH -dg -dt -cH -dm -dw -ZF -qB -dZ -el -Wb -qB -qB -qB -aa -"} -(26,1,1) = {" -ac -ac -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -cH -cH -cH -df -du -cH -dv -qB -qB -dR -ea -em -dR -qB -qB -qB -aa -"} -(27,1,1) = {" -ac -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -cH -cH -dk -du -cH -dv -qB -dR -dR -eb -eb -ec -qB -qB -aa -aa -"} -(28,1,1) = {" -ac -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -cH -dd -dt -cH -dv -qB -dR -dU -ec -ec -ec -ec -ec -aa -aa -"} -(29,1,1) = {" -aa -ac -ac -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -qB -bi -bC -cj -dw -qB -dR -dR -ec -ec -ec -ec -dR -dR -aa -"} -(30,1,1) = {" -aa -ac -ac -qB -qB -qB -qB -qB -qB -qB -as -aS -as -qB -qB -qB -qB -qB -qB -qB -NM -bV -aa -aa -aa -aa -dR -dR -dR -dR -dR -dR -aa -aa -"} -(31,1,1) = {" -aa -aa -ac -qB -qB -qB -qB -qB -qB -as -as -ba -as -as -qB -qB -qB -qB -qB -NM -NM -bV -aa -aa -aa -aa -aa -aa -ah -aa -aa -aa -aa -aa -"} -(32,1,1) = {" -aa -aa -ac -qB -qB -qB -qB -qB -qB -as -aR -bc -bg -as -qB -qB -qB -qB -NM -NM -aa -bV -aa -aa -aa -aa -aa -aa -ah -aa -aa -aa -aa -aa -"} -(33,1,1) = {" -aa -aa -ac -qB -qB -qB -qB -qB -qB -qB -qB -be -bh -as -qB -qB -qB -NM -NM -NM -aa -bV -aa -aa -aa -dH -aa -dH -dH -dH -aa -aa -aa -aa -"} -(34,1,1) = {" -aa -aa -aa -mD -NM -ab -az -as -as -bl -as -as -ck -ab -qB -qB -NM -NM -NM -aa -aa -bV -aa -aa -aa -dy -dy -dy -dy -dy -ah -aa -dy -aa -"} -(35,1,1) = {" -aa -aa -aa -ag -yZ -ab -as -as -aT -bm -bD -as -as -ab -NM -NM -NM -NM -aa -aa -aa -bY -dc -dc -dc -dc -dc -dc -dc -dc -dc -dc -dc -dL -"} -(36,1,1) = {" -aa -aa -aa -aa -aa -at -as -aE -aU -bn -bE -bq -as -ab -NM -NM -aa -aa -aa -aa -aa -aa -dA -dA -dA -dA -dA -dA -dA -dA -dA -dA -dA -aa -"} -(37,1,1) = {" -aa -aa -aa -aa -aa -ab -as -aH -aV -aV -aV -bv -as -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -dB -dB -dB -aa -ah -aa -dB -dB -dB -dB -aa -"} -(38,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -as -aI -aW -aI -as -as -at -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(39,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -as -as -as -as -as -as -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(40,1,1) = {" -aa -aa -aa -aa -aa -aa -ab -at -ab -ab -ab -ab -ab -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} diff --git a/mods/borers/_borers.dme b/mods/mobs/borers/_borers.dme similarity index 100% rename from mods/borers/_borers.dme rename to mods/mobs/borers/_borers.dme diff --git a/mods/mobs/borers/borer.dm b/mods/mobs/borers/borer.dm new file mode 100644 index 000000000000..553b0bbf4442 --- /dev/null +++ b/mods/mobs/borers/borer.dm @@ -0,0 +1,4 @@ +#define MODE_BORER "borer" + +/decl/modpack/borers + name = "Cortical Borers" \ No newline at end of file diff --git a/mods/mobs/borers/datum/antagonist.dm b/mods/mobs/borers/datum/antagonist.dm new file mode 100644 index 000000000000..423297f09f87 --- /dev/null +++ b/mods/mobs/borers/datum/antagonist.dm @@ -0,0 +1,64 @@ +/decl/special_role/borer + name = "Cortical Borer" + name_plural = "Cortical Borers" + flags = ANTAG_OVERRIDE_MOB | ANTAG_RANDSPAWN | ANTAG_OVERRIDE_JOB + + mob_path = /mob/living/simple_animal/borer + welcome_text = "Click a target while on GRAB intent to crawl into their ear and infiltrate their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your host with Say, and your fellow borers with ,z." + antag_indicator = "hudborer" + antaghud_indicator = "hudborer" + antag_hud_icon = 'mods/mobs/borers/icons/hud.dmi' + + faction_name = "Borer Host" + faction_descriptor = "Unity" + faction_welcome = "You are now host to a cortical borer. Please listen to what they have to say; they're in your head." + faction = "borer" + + hard_cap = 5 + hard_cap_round = 8 + initial_spawn_req = 3 + initial_spawn_target = 5 + + spawn_announcement_title = "Lifesign Alert" + spawn_announcement_delay = 5000 + +/decl/special_role/borer/get_extra_panel_options(var/datum/mind/player) + return "\[put in host\]" + +/decl/special_role/borer/create_objectives(var/datum/mind/player) + if(!..()) + return + player.objectives += new /datum/objective/borer_survive() + player.objectives += new /datum/objective/borer_reproduce() + player.objectives += new /datum/objective/escape() + +/decl/special_role/borer/place_mob(var/mob/living/mob) + var/mob/living/simple_animal/borer/borer = mob + if(istype(borer)) + var/mob/living/human/host + for(var/mob/living/human/H in SSmobs.mob_list) + if(H.stat != DEAD && !H.has_brain_worms()) + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(H, BP_HEAD) + if(head && !BP_IS_PROSTHETIC(head)) + host = H + break + if(istype(host)) + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(host, BP_HEAD) + if(head) + borer.host = host + LAZYDISTINCTADD(head.implants, borer) + borer.forceMove(head) + if(!borer.host_brain) + borer.host_brain = new(borer) + borer.host_brain.SetName(host.name) + borer.host_brain.real_name = host.real_name + return + ..() // Place them at a vent if they can't get a host. + +/decl/special_role/borer/Initialize() + . = ..() + spawn_announcement = replacetext(global.using_map.unidentified_lifesigns_message, "%STATION_NAME%", station_name()) + spawn_announcement_sound = global.using_map.lifesign_spawn_sound + +/decl/special_role/borer/attempt_random_spawn() + if(get_config_value(/decl/config/toggle/aliens_allowed)) ..() diff --git a/mods/mobs/borers/datum/ghost_trap.dm b/mods/mobs/borers/datum/ghost_trap.dm new file mode 100644 index 000000000000..c8771abd83a8 --- /dev/null +++ b/mods/mobs/borers/datum/ghost_trap.dm @@ -0,0 +1,19 @@ +/***************** +* Cortical Borer * +*****************/ +/decl/ghosttrap/cortical_borer + name = "cortical borer" + ban_checks = list(MODE_BORER) + pref_check = "ghost_borer" + ghost_trap_message = "They are occupying a borer now." + can_set_own_name = FALSE + list_as_special_role = FALSE + +/decl/ghosttrap/cortical_borer/forced(var/mob/user) + request_player(new /mob/living/simple_animal/borer(get_turf(user)), "A cortical borer needs a player.") + +/decl/ghosttrap/cortical_borer/welcome_candidate(var/mob/target) + to_chat(target, SPAN_NOTICE("You are a cortical borer! You are a brain slug that worms its way \ + into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \ + your host and your eventual spawn safe and warm.")) + to_chat(target, SPAN_NOTICE("You can speak to your victim with say, to other borers with say [target.get_language_prefix()]x, and use your Abilities tab to access powers.")) diff --git a/mods/mobs/borers/datum/language.dm b/mods/mobs/borers/datum/language.dm new file mode 100644 index 000000000000..fda4c7711510 --- /dev/null +++ b/mods/mobs/borers/datum/language.dm @@ -0,0 +1,23 @@ +/decl/language/corticalborer + name = "Cortical Link" + desc = "Cortical borers possess a strange link between their tiny minds." + speech_verb = "sings" + ask_verb = "sings" + exclaim_verb = "sings" + colour = "alien" + key = "z" + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_HIVEMIND + shorthand = "N/A" + hidden_from_codex = TRUE + +#define isborer(X) istype(X, /mob/living/simple_animal/borer) +/decl/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + var/mob/living/simple_animal/borer/B = isborer(speaker) ? speaker : speaker.has_brain_worms() + if(B) + if(B.host) + if(B.host.nutrition < 50 || B.host.stat) + to_chat(speaker, SPAN_WARNING("Your host is too weak to relay your broadcast.")) + return FALSE + B.host.adjust_nutrition(-(rand(1, 3))) + speaker_mask = B.truename + ..(speaker,message,speaker_mask) diff --git a/mods/borers/datum/objective_borer.dm b/mods/mobs/borers/datum/objective_borer.dm similarity index 100% rename from mods/borers/datum/objective_borer.dm rename to mods/mobs/borers/datum/objective_borer.dm diff --git a/mods/mobs/borers/datum/symbiote.dm b/mods/mobs/borers/datum/symbiote.dm new file mode 100644 index 000000000000..bf2f17e93c40 --- /dev/null +++ b/mods/mobs/borers/datum/symbiote.dm @@ -0,0 +1,131 @@ +var/global/list/symbiote_starting_points = list() + +/decl/background_detail/faction/symbiotic + name = "Symbiote Host" + description = "Your culture has always welcomed a form of brain-slug called cortical borers into their bodies, \ + and your upbringing taught that this was a normal and beneficial state of affairs. Taking this background will \ + allow symbiote players to join as your mind-partner. Symbiotes can secrete beneficial chemicals, translate languages \ + and are rendered docile by sugar. Unlike feral cortical borers, they cannot take control of your body or cause brain damage." + economic_power = 0.8 + uid = "heritage_symbiote" + var/matches_to_role = /datum/job/symbiote + +/datum/job/symbiote + title = "Symbiote" + total_positions = -1 + spawn_positions = -1 + supervisors = "your host" + selection_color = "#ad6bad" + access = list() + minimal_access = list() + minimal_player_age = 14 + economic_power = 0 + defer_roundstart_spawn = TRUE + hud_icon_state = "hudblank" + hud_icon = null + outfit_type = /decl/outfit/job/symbiote_host + create_record = FALSE + var/check_whitelist // = "Symbiote" + var/static/mob/living/simple_animal/borer/preview_slug + +/decl/outfit/job/symbiote_host + name = "Job - Symbiote Host" + +/datum/job/symbiote/post_equip_job_title(var/mob/person, var/alt_title) + + var/mob/living/simple_animal/borer/symbiote = person + symbiote.SetName(symbiote.truename) + symbiote.real_name = symbiote.truename + + to_chat(person, "You are a [alt_title || title].") + to_chat(person, "As the [alt_title || title] you answer directly to [supervisors]. Special circumstances may change this.") + + if(symbiote.host) + if(symbiote.host.mind) + var/a_the = (symbiote.host.mind.assigned_job?.total_positions == 1) ? "the" : "a" + var/use_title = symbiote.host.mind.role_alt_title || symbiote.host.mind.assigned_role + to_chat(symbiote, SPAN_NOTICE("Your current host is \the [symbiote.host.real_name], [a_the] [use_title]. Help them stay safe and happy, and assist them in achieving their goals. Remember, your host's desires take precedence over everyone else's.")) + to_chat(symbiote.host, SPAN_NOTICE("Your current symbiote, [symbiote.name], has awakened. They will help you in whatever way they can. Treat them kindly.")) + else + to_chat(symbiote, SPAN_NOTICE("Your host is \the [symbiote.host.real_name]. They are mindless and you should probably find a new one soon.")) + else + to_chat(symbiote, SPAN_DANGER("You do not currently have a host.")) + +/datum/job/symbiote/is_restricted(var/datum/preferences/prefs, var/feedback) + . = ..() + if(. && check_whitelist && prefs?.client && !is_alien_whitelisted(prefs.client.mob, check_whitelist)) + if(feedback) + to_chat(prefs.client.mob, SPAN_WARNING("You are not whitelisted for [check_whitelist] roles.")) + . = FALSE + +/datum/job/symbiote/handle_variant_join(var/mob/living/human/H, var/alt_title) + + var/mob/living/simple_animal/borer/symbiote/symbiote = new + var/mob/living/human/host + try + // No clean way to handle kicking them back to the lobby at this point, so dump + // them into xenobio or latejoin instead if there are zero viable hosts left. + var/list/available_hosts = find_valid_hosts() + while(length(available_hosts) && (!host || !(host in available_hosts))) + host = input(H, "Who do you wish to be your mind-partner?", "Symbiote Spawn") as anything in available_hosts + var/list/current_hosts = find_valid_hosts() // Is the host still available? + if(QDELETED(host) || QDELETED(H) || !H.key || !(host in current_hosts)) + host = null + available_hosts = current_hosts + catch(var/exception/e) + log_debug("Exception during symbiote join: [EXCEPTION_TEXT(e)]") + + if(host) + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(host, BP_HEAD) + symbiote.host = host + LAZYADD(head.implants, symbiote) + symbiote.forceMove(head) + if(!symbiote.host_brain) + symbiote.host_brain = new(symbiote) + symbiote.host_brain.SetName(host.real_name) + symbiote.host_brain.real_name = host.real_name + else + to_chat(symbiote, SPAN_DANGER("There are no longer any hosts available, so you are being placed in a safe area.")) + if(length(global.symbiote_starting_points)) + symbiote.forceMove(pick(global.symbiote_starting_points)) + else + symbiote.forceMove(get_random_spawn_turf(SPAWN_FLAG_JOBS_CAN_SPAWN)) + + if(H.mind) + H.mind.transfer_to(symbiote) + else + symbiote.key = H.key + qdel(H) + return symbiote + +/datum/job/symbiote/equip_preview(var/mob/living/human/H, var/alt_title, var/datum/mil_branch/branch, var/datum/mil_rank/grade, var/additional_skips) + if(!preview_slug) + preview_slug = new + H.appearance = preview_slug + return TRUE + +/datum/job/symbiote/proc/find_valid_hosts(var/just_checking) + . = list() + for(var/mob/living/human/H in global.player_list) + if(H.stat == DEAD || !H.client || !H.ckey || !H.has_brain()) + continue + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(H, BP_HEAD) + if(BP_IS_PROSTHETIC(head) || BP_IS_CRYSTAL(head) || head.has_growths()) + continue + var/decl/background_detail/faction/symbiotic/background = H.get_background_datum_by_flag(BACKGROUND_FLAG_IDEOLOGY) + if(!istype(background) || background.matches_to_role != type) + continue + . += H + if(just_checking) + return + +/datum/job/symbiote/is_position_available() + . = ..() && length(find_valid_hosts(TRUE)) + +/obj/abstract/landmark/symbiote_start + name = "Symbiote Start" + delete_me = TRUE + +/obj/abstract/landmark/symbiote_start/Initialize() + global.symbiote_starting_points |= get_turf(src) + . = ..() diff --git a/mods/mobs/borers/icons/borer.dmi b/mods/mobs/borers/icons/borer.dmi new file mode 100644 index 000000000000..209da35d1ee1 Binary files /dev/null and b/mods/mobs/borers/icons/borer.dmi differ diff --git a/mods/borers/icons/borer_ui.dmi b/mods/mobs/borers/icons/borer_ui.dmi similarity index 100% rename from mods/borers/icons/borer_ui.dmi rename to mods/mobs/borers/icons/borer_ui.dmi diff --git a/mods/mobs/borers/icons/hud.dmi b/mods/mobs/borers/icons/hud.dmi new file mode 100644 index 000000000000..8e01986fd475 Binary files /dev/null and b/mods/mobs/borers/icons/hud.dmi differ diff --git a/mods/mobs/borers/mob/borer/borer.dm b/mods/mobs/borers/mob/borer/borer.dm new file mode 100644 index 000000000000..344d5a07e231 --- /dev/null +++ b/mods/mobs/borers/mob/borer/borer.dm @@ -0,0 +1,268 @@ +/mob/living/simple_animal/borer + name = "cortical borer" + real_name = "cortical borer" + icon = 'mods/mobs/borers/icons/borer.dmi' + desc = "A small, quivering sluglike creature." + speak_emote = list("chirrups") + response_help_3p = "$USER$ pokes $TARGET$." + response_help_1p = "You poke $TARGET$." + response_disarm = "prods" + response_harm = "stamps on" + base_movement_delay = 2 + status_flags = CANPUSH + natural_weapon = /obj/item/natural_weapon/bite/weak + pass_flags = PASS_FLAG_TABLE + universal_understand = TRUE + holder_type = /obj/item/holder/borer + mob_size = MOB_SIZE_SMALL + bleed_colour = "#816e12" + ai = /datum/mob_controller/borer + + // Defined here to remove relaymove handlers as being + // directly in mob contents breaks relaymove spectacularly. + movement_handlers = list( + /datum/movement_handler/mob/death, + /datum/movement_handler/mob/borer_in_host, + /datum/movement_handler/mob/conscious, + /datum/movement_handler/mob/eye, + /datum/movement_handler/mob/delay, + /datum/movement_handler/mob/stop_effect, + /datum/movement_handler/mob/physically_capable, + /datum/movement_handler/mob/physically_restrained, + /datum/movement_handler/mob/space, + /datum/movement_handler/mob/multiz, + /datum/movement_handler/mob/movement + ) + + var/static/list/chemical_types = list( + "anti-trauma" = /decl/material/liquid/brute_meds, + "amphetamines" = /decl/material/liquid/amphetamines, + "painkillers" = /decl/material/liquid/painkillers + ) + + var/generation = 1 + var/static/list/borer_names = list( + "Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary", + "Septenary", "Octonary", "Novenary", "Decenary", "Undenary", "Duodenary", + ) + + var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. + var/truename // Name used for brainworm-speak. + var/controlling // Used in human death check. + var/docile = FALSE // Sugar can stop borers from acting. + var/has_reproduced // Whether or not the borer has reproduced, for objective purposes. + var/roundstart // Whether or not this borer has been mapped and should not look for a player initially. + var/neutered // 'borer lite' mode - fewer powers, less hostile to the host. + var/mob/living/human/host // Human host for the brain worm. + var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. + +/datum/movement_handler/mob/borer_in_host/MayMove(mob/mover, is_external) + return ismob(mob.loc) ? MOVEMENT_STOP : MOVEMENT_PROCEED + +/datum/mob_controller/borer + emote_hear = list("chirrups") + do_wander = FALSE + can_escape_buckles = TRUE + +/obj/item/holder/borer + origin_tech = @'{"biotech":6}' + +/mob/living/simple_animal/borer/roundstart + roundstart = TRUE + +/mob/living/simple_animal/borer/symbiote + name = "symbiote" + real_name = "symbiote" + neutered = TRUE + +/mob/living/simple_animal/borer/Login() + . = ..() + if(mind && !neutered) + var/decl/special_role/borer/borers = GET_DECL(/decl/special_role/borer) + borers.add_antagonist(mind) + +/mob/living/simple_animal/borer/Initialize(var/mapload, var/gen=1) + + hud_used = neutered ? /datum/hud/animal/borer/neutered : /datum/hud/animal/borer + + . = ..() + + add_language(/decl/language/corticalborer) + verbs += /mob/living/proc/hide + + generation = gen + set_borer_name() + + if(!roundstart) + request_player() + +/mob/living/simple_animal/borer/proc/set_borer_name() + truename = "[borer_names[min(generation, borer_names.len)]] [random_id("borer[generation]", 1000, 9999)]" + +/mob/living/simple_animal/borer/handle_vision() + . = ..() + set_status_condition(STAT_BLIND, host ? GET_STATUS(host, STAT_BLIND) : 0) + set_status_condition(STAT_BLURRY, host ? GET_STATUS(host, STAT_BLURRY) : 0) + +/mob/living/simple_animal/borer/handle_disabilities() + . = ..() + if(host) + if(host.has_genetic_condition(GENE_COND_BLINDED)) + add_genetic_condition(GENE_COND_BLINDED) + else + remove_genetic_condition(GENE_COND_BLINDED) + if(host.has_genetic_condition(GENE_COND_DEAFENED)) + add_genetic_condition(GENE_COND_DEAFENED) + else + remove_genetic_condition(GENE_COND_DEAFENED) + else + remove_genetic_condition(GENE_COND_BLINDED) + remove_genetic_condition(GENE_COND_DEAFENED) + +/mob/living/simple_animal/borer/handle_living_non_stasis_processes() + . = ..() + if(!.) + return FALSE + + if(!host || host.stat) + return + + if(prob(host.get_damage(BRAIN)/20)) + INVOKE_ASYNC(host, TYPE_PROC_REF(/mob, say), "*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]") + + if(stat) + return + + if(host.reagents.has_reagent(/decl/material/liquid/nutriment/sugar)) + if(!docile) + if(controlling) + to_chat(host, SPAN_NOTICE("You feel the soporific flow of sugar in your host's blood, lulling you into docility.")) + else + to_chat(src, SPAN_NOTICE("You feel the soporific flow of sugar in your host's blood, lulling you into docility.")) + docile = TRUE + else + if(docile) + if(controlling) + to_chat(host, SPAN_NOTICE("You shake off your lethargy as the sugar leaves your host's blood.")) + else + to_chat(src, SPAN_NOTICE("You shake off your lethargy as the sugar leaves your host's blood.")) + docile = FALSE + + if(chemicals < 250 && host.nutrition >= (neutered ? 200 : 50)) + host.nutrition-- + chemicals++ + if(controlling) + if(neutered || docile) + if(docile) + to_chat(host, SPAN_NOTICE("You are feeling far too docile to continue controlling your host...")) + host.release_control() + return + if(prob(5)) + host.take_damage(0.1, BRAIN) + +/mob/living/simple_animal/borer/Stat() + . = ..() + statpanel("Status") + + if(SSevac.evacuation_controller) + var/eta_status = SSevac.evacuation_controller.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + + if (client.statpanel == "Status") + stat("Chemicals", chemicals) + +/mob/living/simple_animal/borer/proc/detach_from_host() + + if(!host || !controlling) return + + if(ishuman(host)) + var/mob/living/human/H = host + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(H, BP_HEAD) + LAZYREMOVE(head.implants, src) + + controlling = FALSE + + host.remove_language(/decl/language/corticalborer) + host.verbs -= /mob/living/proc/release_control + host.verbs -= /mob/living/proc/punish_host + host.verbs -= /mob/living/proc/spawn_larvae + + if(host_brain) + + // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. + // computer_id and IP are not updated magically on their own in offline mobs -walter0o + + // host -> self + var/h2s_id = host.computer_id + var/h2s_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + src.ckey = host.ckey + + if(!src.computer_id) + src.computer_id = h2s_id + + if(!host_brain.lastKnownIP) + src.lastKnownIP = h2s_ip + + // brain -> host + var/b2h_id = host_brain.computer_id + var/b2h_ip= host_brain.lastKnownIP + host_brain.computer_id = null + host_brain.lastKnownIP = null + + host.ckey = host_brain.ckey + + if(!host.computer_id) + host.computer_id = b2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = b2h_ip + + qdel(host_brain) + +#define COLOR_BORER_RED "#ff5555" +/mob/living/simple_animal/borer/proc/set_ability_cooldown(var/amt) + set_special_ability_cooldown(amt) + var/datum/hud/animal/borer/borer_hud = hud_used + if(istype(borer_hud)) + for(var/obj/thing in borer_hud.borer_hud_elements) + thing.color = COLOR_BORER_RED + addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living/simple_animal/borer, reset_ui_callback)), amt) +#undef COLOR_BORER_RED + +/mob/living/simple_animal/borer/proc/leave_host() + + var/datum/hud/animal/borer/borer_hud = hud_used + if(istype(borer_hud)) + for(var/obj/thing in borer_hud.borer_hud_elements) + thing.alpha = 0 + thing.set_invisibility(INVISIBILITY_ABSTRACT) + + if(!host) return + + if(host.mind) + var/decl/special_role/borer/borers = GET_DECL(/decl/special_role/borer) + borers.remove_antagonist(host.mind) + + dropInto(host.loc) + + reset_view(null) + machine = null + + host.reset_view(null) + host.machine = null + host.status_flags &= ~PASSEMOTES + host = null + return + +//Procs for grabbing players. +/mob/living/simple_animal/borer/proc/request_player() + var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/cortical_borer) + G.request_player(src, "A cortical borer needs a player.") + +/mob/living/simple_animal/borer/flash_eyes(intensity, override_blindness_check, affect_silicon, visual, type) + intensity *= 1.5 + . = ..() \ No newline at end of file diff --git a/mods/mobs/borers/mob/borer/borer_attacks.dm b/mods/mobs/borers/mob/borer/borer_attacks.dm new file mode 100644 index 000000000000..37253f8b805c --- /dev/null +++ b/mods/mobs/borers/mob/borer/borer_attacks.dm @@ -0,0 +1,62 @@ +/mob/living/simple_animal/borer/ResolveUnarmedAttack(atom/A) + + if(host) + return TRUE // We cannot click things outside of our host. + + if(!isliving(A) || !check_intent(I_FLAG_GRAB) || stat) + return ..() + + if(!can_use_borer_ability(requires_host_value = FALSE, check_last_special = FALSE)) + return TRUE + + var/mob/living/victim = A + if(victim.has_brain_worms()) + to_chat(src, SPAN_WARNING("You cannot take a host who already has a passenger!")) + return TRUE + var/obj/item/organ/external/limb = GET_EXTERNAL_ORGAN(victim, BP_HEAD) + if(!limb) + to_chat(src, SPAN_WARNING("\The [victim] does not have anatomy compatible with your lifecycle!")) + return TRUE + if(BP_IS_PROSTHETIC(limb)) + to_chat(src, SPAN_WARNING("\The [victim]'s head is prosthetic and cannot support your lifecycle!")) + return TRUE + if(!victim.should_have_organ(BP_BRAIN)) + to_chat(src, SPAN_WARNING("\The [victim] does not seem to have a brain cavity to enter.")) + return TRUE + if(victim.check_head_coverage()) + to_chat(src, SPAN_WARNING("You cannot get through that host's protective gear.")) + return TRUE + + to_chat(victim, SPAN_WARNING("Something slimy begins probing at the opening of your ear canal...")) + to_chat(src, SPAN_NOTICE("You slither up [victim] and begin probing at their ear canal...")) + set_ability_cooldown(5 SECONDS) + + if(!do_after(src, 3 SECONDS, victim) || host || GET_EXTERNAL_ORGAN(victim, BP_HEAD) != limb || BP_IS_PROSTHETIC(limb) || victim.check_head_coverage()) + return TRUE + + to_chat(src, SPAN_NOTICE("You wiggle into \the [victim]'s ear.")) + if(victim.stat == CONSCIOUS) + to_chat(victim, SPAN_DANGER("Something wet, cold and slimy wiggles into your ear!")) + + host = victim + host.status_flags |= PASSEMOTES + forceMove(host) + + var/datum/hud/animal/borer/borer_hud = hud_used + if(istype(borer_hud)) + for(var/obj/thing in borer_hud.borer_hud_elements) + thing.alpha = 255 + thing.set_invisibility(INVISIBILITY_NONE) + + //Update their traitor status. + if(host.mind && !neutered) + var/decl/special_role/borer/borers = GET_DECL(/decl/special_role/borer) + borers.add_antagonist_mind(host.mind, 1, borers.faction_name, borers.faction_welcome) + + if(ishuman(host)) + var/obj/item/organ/internal/I = GET_INTERNAL_ORGAN(victim, BP_BRAIN) + if(!I) // No brain organ, so the borer moves in and replaces it permanently. + replace_brain() + else if(limb) // If they're in normally, implant removal can get them out. + LAZYDISTINCTADD(limb.implants, src) + return TRUE diff --git a/mods/mobs/borers/mob/borer/borer_captive.dm b/mods/mobs/borers/mob/borer/borer_captive.dm new file mode 100644 index 000000000000..e790354fc8c9 --- /dev/null +++ b/mods/mobs/borers/mob/borer/borer_captive.dm @@ -0,0 +1,51 @@ +/mob/living/captive_brain + name = "host brain" + real_name = "host brain" + universal_understand = TRUE + butchery_data = null + +/mob/living/captive_brain/say(var/message) + + if (src.client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, SPAN_WARNING("You cannot speak in IC (muted).")) + return + + if(isborer(src.loc)) + + message = sanitize(message) + if (!message) + return + log_say("[key_name(src)] : [message]") + if (stat == DEAD) + return say_dead(message) + + var/mob/living/simple_animal/borer/B = src.loc + to_chat(src, "You whisper silently, \"[message]\"") + to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"") + + for (var/mob/M in global.player_list) + if (isnewplayer(M)) + continue + else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == PREF_ALL_SPEECH) + to_chat(M, "The captive mind of [src] whispers, \"[message]\"") + +/mob/living/captive_brain/process_resist() + SHOULD_CALL_PARENT(FALSE) + //Resisting control by an alien mind. + if(isborer(src.loc)) + var/mob/living/simple_animal/borer/B = src.loc + var/mob/living/captive_brain/H = src + to_chat(H, "You begin doggedly resisting the parasite's control (this will take approximately sixty seconds).") + to_chat(B.host, "You feel the captive mind of [src] begin to resist your control.") + spawn(rand(200,250)+B.host.get_damage(BRAIN)) + if(!B || !B.controlling) return + B.host.take_damage(rand(0.1,0.5), BRAIN) + to_chat(H, "With an immense exertion of will, you regain control of your body!") + to_chat(B.host, "You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.") + B.detach_from_host() + verbs -= /mob/living/proc/release_control + verbs -= /mob/living/proc/punish_host + verbs -= /mob/living/proc/spawn_larvae + return TRUE + return FALSE diff --git a/mods/mobs/borers/mob/borer/borer_hud.dm b/mods/mobs/borers/mob/borer/borer_hud.dm new file mode 100644 index 000000000000..9d9435c08eda --- /dev/null +++ b/mods/mobs/borers/mob/borer/borer_hud.dm @@ -0,0 +1,178 @@ +/decl/hud_element/borer + abstract_type = /decl/hud_element/borer + +/decl/hud_element/borer/inject_chemicals + elem_type = /obj/screen/borer/inject_chemicals + +/decl/hud_element/borer/leave_host + elem_type = /obj/screen/borer/leave_host + +/decl/hud_element/borer/toggle_control + elem_type = /obj/screen/borer/toggle_host_control + +/datum/hud/animal/borer + omit_hud_elements = list( + /decl/hud_element/movement, + /decl/hud_element/stamina + ) + additional_hud_elements = list( + /decl/hud_element/borer/inject_chemicals, + /decl/hud_element/borer/leave_host, + /decl/hud_element/borer/toggle_control + ) + var/list/borer_hud_elements + +/datum/hud/animal/borer/neutered + additional_hud_elements = list( + /decl/hud_element/borer/inject_chemicals, + /decl/hud_element/borer/leave_host + ) + +/datum/hud/animal/borer/Destroy() + borer_hud_elements = null + return ..() + +/datum/hud/animal/borer/create_and_register_element(decl/hud_element/ui_elem, decl/ui_style/ui_style, ui_color, ui_alpha) + var/obj/screen/elem = ..() + if(istype(elem) && istype(elem, /obj/screen/borer)) + LAZYADD(borer_hud_elements, elem) + return elem + +/mob/living/simple_animal/borer + hud_used = /datum/hud/animal/borer + +/mob/living/simple_animal/borer/proc/reset_ui_callback() + if(!is_on_special_ability_cooldown()) + var/datum/hud/animal/borer/borer_hud = hud_used + if(istype(borer_hud)) + for(var/obj/thing in borer_hud.borer_hud_elements) + thing.color = null + +/obj/screen/borer + icon = 'mods/mobs/borers/icons/borer_ui.dmi' + use_supplied_ui_icon = FALSE + requires_ui_style = FALSE + +/obj/screen/borer/handle_click(mob/user, params) + if(!isborer(user)) + return FALSE + var/mob/living/simple_animal/borer/worm = user + if(!worm.host) + return FALSE + return TRUE + +/obj/screen/borer/toggle_host_control + name = "Seize Control" + icon_state = "seize_control" + screen_loc = "LEFT+3,TOP-1" + +/obj/screen/borer/toggle_host_control/handle_click(mob/user, params) + . = ..() + if(!.) + return FALSE + + var/mob/living/simple_animal/borer/worm = user + if(!worm.can_use_borer_ability()) + return + + if(worm.neutered) + to_chat(worm, SPAN_WARNING("You cannot do that.")) + return + + to_chat(worm, SPAN_NOTICE("You begin delicately adjusting your connection to the host brain...")) + if(!do_after(worm, 100+(worm.host.get_damage(BRAIN)*5) || !worm.host || !worm.can_use_borer_ability())) + return + + to_chat(worm, SPAN_DANGER("You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.")) + to_chat(worm.host, SPAN_DANGER("You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.")) + worm.host.add_language(/decl/language/corticalborer) + + // host -> brain + var/h2b_id = worm.host.computer_id + var/h2b_ip= worm.host.lastKnownIP + worm.host.computer_id = null + worm.host.lastKnownIP = null + qdel(worm.host_brain) + worm.host_brain = new(worm) + worm.host_brain.ckey = worm.host.ckey + worm.host_brain.SetName(worm.host.name) + if(!worm.host_brain.computer_id) + worm.host_brain.computer_id = h2b_id + if(!worm.host_brain.lastKnownIP) + worm.host_brain.lastKnownIP = h2b_ip + + // self -> host + var/s2h_id = worm.computer_id + var/s2h_ip= worm.lastKnownIP + worm.computer_id = null + worm.lastKnownIP = null + worm.host.ckey = worm.ckey + if(!worm.host.computer_id) + worm.host.computer_id = s2h_id + if(!worm.host.lastKnownIP) + worm.host.lastKnownIP = s2h_ip + worm.controlling = TRUE + worm.host.verbs += /mob/living/proc/release_control + worm.host.verbs += /mob/living/proc/punish_host + worm.host.verbs += /mob/living/proc/spawn_larvae + + return TRUE + +/obj/screen/borer/inject_chemicals + name = "Inject Chemicals" + icon_state = "inject_chemicals" + screen_loc = "LEFT+2,TOP-1" + +/obj/screen/borer/inject_chemicals/handle_click(mob/user, params) + . = ..() + if(!.) + return FALSE + + var/mob/living/simple_animal/borer/worm = user + if(!worm.can_use_borer_ability()) + return + + if(worm.chemicals < 50) + to_chat(worm, SPAN_WARNING("You don't have enough chemicals!")) + return + + var/chem = input("Select a chemical to secrete.", "Chemicals") as null|anything in worm.chemical_types + if(!chem || !worm.chemical_types[chem] || !worm || QDELETED(worm) || worm.chemicals < 50 || !worm.can_use_borer_ability()) + return + + to_chat(worm, SPAN_NOTICE("You squirt a measure of [chem] from your reservoirs into \the [worm.host]'s bloodstream.")) + worm.host.add_to_reagents(worm.chemical_types[chem], 10) + worm.chemicals -= 50 + return TRUE + +/obj/screen/borer/leave_host + name = "Leave Host" + icon_state = "leave_host" + screen_loc = "LEFT+1,TOP-1" + +/obj/screen/borer/leave_host/handle_click(mob/user, params) + . = ..() + if(!.) + return FALSE + + var/mob/living/simple_animal/borer/worm = user + if(!worm.can_use_borer_ability()) + return + + to_chat(worm, SPAN_NOTICE("You begin disconnecting from \the [worm.host]'s synapses and prodding at their internal ear canal.")) + if(worm.host.stat == CONSCIOUS) + to_chat(worm.host, SPAN_WARNING("An odd, uncomfortable pressure begins to build inside your skull, behind your ear...")) + + if(!do_after(worm, 10 SECONDS) || !worm.can_use_borer_ability()) + return + + if(worm.host) + to_chat(worm, SPAN_WARNING("You wiggle out of [worm.host]'s ear and plop to the ground.")) + if(worm.host.stat != DEAD) + to_chat(worm.host, SPAN_DANGER("Something slimy wiggles out of your ear and plops to the ground!")) + if(!worm.neutered) + to_chat(worm.host, SPAN_DANGER("As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again.")) + worm.detach_from_host() + worm.leave_host() + + return TRUE \ No newline at end of file diff --git a/mods/borers/mob/borer/borer_powers.dm b/mods/mobs/borers/mob/borer/borer_powers.dm similarity index 76% rename from mods/borers/mob/borer/borer_powers.dm rename to mods/mobs/borers/mob/borer/borer_powers.dm index f9d32e14834f..9208843587d5 100644 --- a/mods/borers/mob/borer/borer_powers.dm +++ b/mods/mobs/borers/mob/borer/borer_powers.dm @@ -25,7 +25,7 @@ if(!silent) to_chat(src, SPAN_NOTICE("You are feeling far too docile to perform this action.")) return FALSE - if(check_last_special && world.time < last_special) + if(check_last_special && is_on_special_ability_cooldown()) if(!silent) to_chat(src, SPAN_NOTICE("You cannot perform this action so soon after the last.")) return FALSE @@ -34,7 +34,7 @@ // BRAIN WORM ZOMBIES AAAAH. /mob/living/simple_animal/borer/proc/replace_brain() - var/mob/living/carbon/human/H = host + var/mob/living/human/H = host if(!istype(host)) to_chat(src, SPAN_WARNING("This host does not have a suitable brain.")) @@ -45,29 +45,27 @@ H.add_language(/decl/language/corticalborer) if(host.stat == DEAD) - H.verbs |= /mob/living/carbon/human/proc/jumpstart + H.verbs |= /mob/living/human/proc/jumpstart - H.verbs |= /mob/living/carbon/human/proc/psychic_whisper + H.verbs |= /mob/living/human/proc/psychic_whisper if(!neutered) - H.verbs |= /mob/living/carbon/proc/spawn_larvae + H.verbs |= /mob/living/proc/spawn_larvae if(H.client) - H.ghostize(0) + H.ghostize(CORPSE_CANNOT_REENTER) if(src.mind) - src.mind.special_role = "Borer Husk" + src.mind.assigned_special_role = "Borer Husk" src.mind.transfer_to(host) - H.ChangeToHusk() + H.add_genetic_condition(GENE_COND_HUSK) var/obj/item/organ/internal/borer/B = new(H) if(islist(chemical_types)) B.chemical_types = chemical_types.Copy() - H.internal_organs_by_name[BP_BRAIN] = B - H.internal_organs |= B - var/obj/item/organ/external/affecting = H.get_organ(BP_HEAD) - affecting.implants -= src + var/obj/item/organ/external/affecting = GET_EXTERNAL_ORGAN(H, BP_HEAD) + LAZYREMOVE(affecting.implants, src) var/s2h_id = src.computer_id var/s2h_ip= src.lastKnownIP @@ -78,19 +76,16 @@ if(!H.lastKnownIP) H.lastKnownIP = s2h_ip -/mob/living/carbon/human/proc/jumpstart() +/mob/living/human/proc/jumpstart() set category = "Abilities" set name = "Revive Host" set desc = "Send a jolt of electricity through your host, reviving them." - if(stat != 2) + if(stat != DEAD) to_chat(usr, SPAN_WARNING("Your host is already alive.")) return - verbs -= /mob/living/carbon/human/proc/jumpstart + verbs -= /mob/living/human/proc/jumpstart visible_message(SPAN_DANGER("With a hideous, rattling moan, [src] shudders back to life!")) - rejuvenate() - restore_blood() - fixblood() - UpdateLyingBuckledAndVerbStatus() + update_posture() diff --git a/mods/mobs/borers/mob/borer/say.dm b/mods/mobs/borers/mob/borer/say.dm new file mode 100644 index 000000000000..d60017170f91 --- /dev/null +++ b/mods/mobs/borers/mob/borer/say.dm @@ -0,0 +1,43 @@ +/mob/living/simple_animal/borer/say(var/message) + + message = sanitize(message) + message = capitalize(message) + + if(!message) + return + + if (stat == DEAD) + return say_dead(message) + + if (stat) + return + + if (src.client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (muted).") + return + + if(findlasttextEx(message, get_prefix_key(/decl/prefix/custom_emote)) == 1) + return emote(copytext(message,2)) + + if(findlasttextEx(message, get_prefix_key(/decl/prefix/visible_emote)) == 1) + return custom_emote(1, copytext(message,2)) + + var/decl/language/L = parse_language(message) + if(L && L.flags & LANG_FLAG_HIVEMIND) + L.broadcast(src,trim(copytext(message,3)),src.truename) + return + + if(!host) + //TODO: have this pick a random mob within 3 tiles to speak for the borer. + to_chat(src, "You have no host to speak to.") + return //No host, no audible speech. + + to_chat(src, "You drop words into [host]'s mind: \"[message]\"") + to_chat(host, "Your own thoughts speak: \"[message]\"") + + for (var/mob/M in global.player_list) + if (isnewplayer(M)) + continue + else if(M.stat == DEAD && M.get_preference_value(/datum/client_preference/ghost_ears) == PREF_ALL_SPEECH) + to_chat(M, "[src.truename] whispers to [host], \"[message]\"") diff --git a/mods/borers/mob/organ.dm b/mods/mobs/borers/mob/organ.dm similarity index 76% rename from mods/borers/mob/organ.dm rename to mods/mobs/borers/mob/organ.dm index 5676cc98c7c3..80c12e77c94c 100644 --- a/mods/borers/mob/organ.dm +++ b/mods/mobs/borers/mob/organ.dm @@ -6,20 +6,19 @@ organ_tag = BP_BRAIN desc = "A disgusting space slug." parent_organ = BP_HEAD - vital = 1 var/list/chemical_types /obj/item/organ/internal/borer/Process() - + SHOULD_CALL_PARENT(FALSE) // Borer husks regenerate health, feel no pain, and are resistant to stuns and brainloss. for(var/chem_name in chemical_types) var/chem = chemical_types[chem_name] if(REAGENT_VOLUME(owner.reagents, chem) < 3) - owner.reagents.add_reagent(chem, 5) + owner.add_to_reagents(chem, 5) // They're also super gross and ooze ichor. if(prob(5)) - var/mob/living/carbon/human/H = owner + var/mob/living/human/H = owner if(!istype(H)) return @@ -31,14 +30,12 @@ goo.basecolor = "#412464" goo.update_icon() -/obj/item/organ/internal/borer/removed(var/mob/living/user) - +/obj/item/organ/internal/borer/on_remove_effects(mob/living/last_owner) ..() - var/mob/living/simple_animal/borer/B = owner.has_brain_worms() + var/mob/living/simple_animal/borer/B = last_owner.has_brain_worms() if(B) B.leave_host() - B.ckey = owner.ckey + B.ckey = last_owner.ckey - spawn(0) - qdel(src) + qdel(src) diff --git a/mods/mobs/borers/mob/overrides.dm b/mods/mobs/borers/mob/overrides.dm new file mode 100644 index 000000000000..26b83686f8e6 --- /dev/null +++ b/mods/mobs/borers/mob/overrides.dm @@ -0,0 +1,58 @@ +#define HAS_BRAIN_WORMS(HOST) (locate(/mob/living/simple_animal/borer) in HOST?.contents) + +/obj/item/organ/external/has_growths() + . = ..() + if(!.) + . = locate(/mob/living/simple_animal/borer) in implants + +/mob/proc/has_brain_worms() + . = locate(/mob/living/simple_animal/borer) in contents + +/mob/handle_pre_transformation() + . = ..() + var/mob/living/simple_animal/borer/borer = HAS_BRAIN_WORMS(src) + if(borer) + borer.detach_from_host() + borer.leave_host() + +/mob/living/human/handle_hud_list() + var/last_hud_bitfield = hud_updateflag + . = ..() + if(stat != DEAD && has_brain_worms() && BITTEST(last_hud_bitfield, STATUS_HUD) && hud_list[STATUS_HUD] && hud_list[STATUS_HUD_OOC]) + var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) + if(B.controlling) + var/image/holder = hud_list[STATUS_HUD] + holder.icon = 'mods/mobs/borers/icons/hud.dmi' + holder.icon_state = "hudbrainworm" + var/image/holder2 = hud_list[STATUS_HUD_OOC] + holder2.icon = 'mods/mobs/borers/icons/hud.dmi' + holder2.icon_state = "hudbrainworm" + +/mob/living/human/say_understands(mob/speaker, decl/language/speaking) + return has_brain_worms() || ..() + +/obj/item/organ/internal/brain/do_uninstall(in_place, detach, ignore_children) + if(istype(owner)) + var/mob/living/simple_animal/borer/borer = HAS_BRAIN_WORMS(owner) + if(borer) + borer.detach_from_host() + . = ..() + +/obj/item/glass_jar/Initialize() + accept_mobs |= /mob/living/simple_animal/borer + . = ..() + +/mob/death(gibbed) + . = ..() + if(. && !gibbed) + var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) + if(B && B.controlling) + B.detach_from_host() + +/mob/living/human/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected) + if((. = ..()) && !QDELETED(implant) && isborer(implant)) + var/mob/living/simple_animal/borer/worm = implant + if(worm.controlling) + release_control() + worm.detach_from_host() + worm.leave_host() diff --git a/mods/mobs/borers/mob/powers.dm b/mods/mobs/borers/mob/powers.dm new file mode 100644 index 000000000000..b561a72b1b04 --- /dev/null +++ b/mods/mobs/borers/mob/powers.dm @@ -0,0 +1,63 @@ +//Brain slug proc for voluntary removal of control. +/mob/living/proc/release_control() + + set category = "Abilities" + set name = "Release Control" + set desc = "Release control of your host's body." + + var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) + + if(B && B.host_brain) + to_chat(src, "You withdraw your probosci, releasing control of [B.host_brain]") + + B.detach_from_host() + + verbs -= /mob/living/proc/release_control + verbs -= /mob/living/proc/punish_host + verbs -= /mob/living/proc/spawn_larvae + + else + to_chat(src, "ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !") + +//Brain slug proc for tormenting the host. +/mob/living/proc/punish_host() + set category = "Abilities" + set name = "Torment host" + set desc = "Punish your host with agony." + + var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) + + if(!B) + return + + if(B.host_brain.ckey) + to_chat(src, "You send a punishing spike of psychic agony lancing into your host's brain.") + if (!can_feel_pain()) + to_chat(B.host_brain, "You feel a strange sensation as a foreign influence prods your mind.") + to_chat(src, "It doesn't seem to be as effective as you hoped.") + else + to_chat(B.host_brain, "Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!") + +/mob/living/proc/spawn_larvae() + set category = "Abilities" + set name = "Reproduce" + set desc = "Spawn several young." + + var/mob/living/simple_animal/borer/B = HAS_BRAIN_WORMS(src) + + if(!B) + return + + if(B.chemicals >= 100) + to_chat(src, "Your host twitches and quivers as you rapidly excrete a larva from your sluglike body.") + visible_message("\The [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") + B.chemicals -= 100 + B.has_reproduced = 1 + + new /obj/effect/decal/cleanable/vomit(get_turf(src)) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + new /mob/living/simple_animal/borer(get_turf(src), B.generation + 1) + + else + to_chat(src, "You do not have enough chemicals stored to reproduce.") + return diff --git a/mods/dionaea/_dionaea.dme b/mods/mobs/dionaea/_dionaea.dme similarity index 91% rename from mods/dionaea/_dionaea.dme rename to mods/mobs/dionaea/_dionaea.dme index 94b4b0c58dc5..a43670132b32 100644 --- a/mods/dionaea/_dionaea.dme +++ b/mods/mobs/dionaea/_dionaea.dme @@ -1,9 +1,11 @@ #ifndef MODPACK_DIONAEA #define MODPACK_DIONAEA // BEGIN_INCLUDE +#include "dionaea.dm" +#include "datums\ai.dm" #include "datums\ghosttrap.dm" +#include "datums\instrument_data.dm" #include "datums\language.dm" -#include "datums\loadout.dm" #include "datums\seed.dm" #include "items\cup.dm" #include "items\lunchbox.dm" @@ -18,7 +20,6 @@ #include "mob\nymph_emotes.dm" #include "mob\nymph_gestalting.dm" #include "mob\nymph_holder.dm" -#include "mob\nymph_inventory.dm" #include "mob\nymph_life.dm" #include "mob\nymph_ui.dm" #include "mob\nymph_update_icons.dm" diff --git a/mods/mobs/dionaea/datums/ai.dm b/mods/mobs/dionaea/datums/ai.dm new file mode 100644 index 000000000000..825935bfad22 --- /dev/null +++ b/mods/mobs/dionaea/datums/ai.dm @@ -0,0 +1,9 @@ +/datum/mob_controller/nymph + do_wander = TRUE + stop_wander_when_pulled = TRUE + emote_see = list( + /decl/emote/visible/scratch, + /decl/emote/visible/jump, + /decl/emote/audible/chirp, + /decl/emote/visible/tail + ) diff --git a/mods/mobs/dionaea/datums/ghosttrap.dm b/mods/mobs/dionaea/datums/ghosttrap.dm new file mode 100644 index 000000000000..72330a4a9a47 --- /dev/null +++ b/mods/mobs/dionaea/datums/ghosttrap.dm @@ -0,0 +1,8 @@ +#define isdiona(X) istype(X, /mob/living/simple_animal/alien/diona) + +/decl/ghosttrap/sentient_plant/welcome_candidate(var/mob/target) + ..() + // This is a hack, replace with some kind of species blurb proc. + if(isdiona(target)) + to_chat(target, "You are \a [target], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders.") + to_chat(target, "Too much darkness will send you into shock and starve you, but light will help you heal.") diff --git a/mods/mobs/dionaea/datums/instrument_data.dm b/mods/mobs/dionaea/datums/instrument_data.dm new file mode 100644 index 000000000000..f0492fa9ca77 --- /dev/null +++ b/mods/mobs/dionaea/datums/instrument_data.dm @@ -0,0 +1,4 @@ +/datum/instrument/fun/diona + name = "Diona" + id = "diona" + samples = list("79" = 'mods/mobs/dionaea/sounds/nymphchirp.ogg') diff --git a/mods/mobs/dionaea/datums/language.dm b/mods/mobs/dionaea/datums/language.dm new file mode 100644 index 000000000000..4ef0755db61b --- /dev/null +++ b/mods/mobs/dionaea/datums/language.dm @@ -0,0 +1,16 @@ +/decl/language/diona + name = "Nymph" + desc = "A language known instinctively by diona nymphs." + speech_verb = "creaks and rustles" + ask_verb = "creaks" + exclaim_verb = "rustles" + colour = "soghun" + key = "q" + flags = LANG_FLAG_RESTRICTED + syllables = list("hs","zt","kr","st","sh") + shorthand = "RT" + machine_understands = FALSE + hidden_from_codex = TRUE + +/decl/language/diona/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + . = "[pick(list("To Sleep Beneath","Wind Over","Embrace of","Dreams of","Witnessing","To Walk Beneath","Approaching the"))] [pick(list("the Void","the Sky","Encroaching Night","Planetsong","Starsong","the Wandering Star","the Empty Day","Daybreak","Nightfall","the Rain"))]" diff --git a/mods/mobs/dionaea/datums/seed.dm b/mods/mobs/dionaea/datums/seed.dm new file mode 100644 index 000000000000..d2600d9ab7db --- /dev/null +++ b/mods/mobs/dionaea/datums/seed.dm @@ -0,0 +1,31 @@ +/datum/seed/diona + name = "diona" + product_name = "diona" + seed_noun = SEED_NOUN_NODES + display_name = "diona nymph pods" + can_self_harvest = 1 + product_type = /mob/living/simple_animal/alien/diona + +/datum/seed/diona/New() + ..() + set_trait(TRAIT_IMMUTABLE,1) + set_trait(TRAIT_ENDURANCE,8) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,1) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_PRODUCT_ICON,"diona") + set_trait(TRAIT_PRODUCT_COLOUR,"#799957") + set_trait(TRAIT_PLANT_COLOUR,"#66804b") + set_trait(TRAIT_PLANT_ICON,"alien4") + +/obj/item/seeds/diona + seed = "diona" + +/decl/hierarchy/supply_pack/hydroponics/exoticseeds/Initialize() + contains[/obj/item/seeds/diona] = 2 + . = ..() + +/obj/structure/closet/crate/hydroponics/exotic/WillContain() + . = ..() + .[/obj/item/seeds/diona] = 2 \ No newline at end of file diff --git a/mods/mobs/dionaea/dionaea.dm b/mods/mobs/dionaea/dionaea.dm new file mode 100644 index 000000000000..5b4f29bcc7ef --- /dev/null +++ b/mods/mobs/dionaea/dionaea.dm @@ -0,0 +1,10 @@ +/decl/modpack/dionaea + name = "Diona Nymphs" + +/decl/modpack/dionaea/post_initialize() + . = ..() + var/list/aminals = global.href_to_mob_type["Animals"] + if(!islist(aminals)) + global.href_to_mob_type["Animals"] = list("Diona Nymph" = /mob/living/simple_animal/alien/diona) + else + aminals["Diona Nymph"] = /mob/living/simple_animal/alien/diona diff --git a/mods/mobs/dionaea/icons/gestalt.dmi b/mods/mobs/dionaea/icons/gestalt.dmi new file mode 100644 index 000000000000..546e32068b01 Binary files /dev/null and b/mods/mobs/dionaea/icons/gestalt.dmi differ diff --git a/mods/mobs/dionaea/icons/lunchbox_nymph.dmi b/mods/mobs/dionaea/icons/lunchbox_nymph.dmi new file mode 100644 index 000000000000..500f939b9ebf Binary files /dev/null and b/mods/mobs/dionaea/icons/lunchbox_nymph.dmi differ diff --git a/mods/mobs/dionaea/icons/nymph.dmi b/mods/mobs/dionaea/icons/nymph.dmi new file mode 100644 index 000000000000..1176bfb73af4 Binary files /dev/null and b/mods/mobs/dionaea/icons/nymph.dmi differ diff --git a/mods/mobs/dionaea/icons/roast.dmi b/mods/mobs/dionaea/icons/roast.dmi new file mode 100644 index 000000000000..4357f38d10a4 Binary files /dev/null and b/mods/mobs/dionaea/icons/roast.dmi differ diff --git a/mods/mobs/dionaea/icons/turfs.dmi b/mods/mobs/dionaea/icons/turfs.dmi new file mode 100644 index 000000000000..eed6da699c40 Binary files /dev/null and b/mods/mobs/dionaea/icons/turfs.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_hands.dmi b/mods/mobs/dionaea/icons/ui_hands.dmi new file mode 100644 index 000000000000..c17a1f29ca11 Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_hands.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_health.dmi b/mods/mobs/dionaea/icons/ui_health.dmi new file mode 100644 index 000000000000..c079eddb9702 Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_health.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_intent_overlay.dmi b/mods/mobs/dionaea/icons/ui_intent_overlay.dmi new file mode 100644 index 000000000000..8c3174c773a3 Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_intent_overlay.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_intents.dmi b/mods/mobs/dionaea/icons/ui_intents.dmi new file mode 100644 index 000000000000..7a7f29b4d21c Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_intents.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_interactions_drop.dmi b/mods/mobs/dionaea/icons/ui_interactions_drop.dmi new file mode 100644 index 000000000000..cbb91b5ebecd Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_interactions_drop.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_interactions_maneuver.dmi b/mods/mobs/dionaea/icons/ui_interactions_maneuver.dmi new file mode 100644 index 000000000000..967631175ae0 Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_interactions_maneuver.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_interactions_resist.dmi b/mods/mobs/dionaea/icons/ui_interactions_resist.dmi new file mode 100644 index 000000000000..559690c3ccf1 Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_interactions_resist.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_interactions_throw.dmi b/mods/mobs/dionaea/icons/ui_interactions_throw.dmi new file mode 100644 index 000000000000..f6189daec8ad Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_interactions_throw.dmi differ diff --git a/mods/mobs/dionaea/icons/ui_inventory.dmi b/mods/mobs/dionaea/icons/ui_inventory.dmi new file mode 100644 index 000000000000..10f9d9113d7c Binary files /dev/null and b/mods/mobs/dionaea/icons/ui_inventory.dmi differ diff --git a/mods/mobs/dionaea/items/cup.dm b/mods/mobs/dionaea/items/cup.dm new file mode 100644 index 000000000000..77814457f2d0 --- /dev/null +++ b/mods/mobs/dionaea/items/cup.dm @@ -0,0 +1,6 @@ +/obj/item/chems/drinks/glass2/coffeecup/diona + name = "diona nymph coffee cup" + desc = "A green coffee cup featuring the image of a diona nymph." + base_icon = "coffeecup_diona" + icon_state = "coffeecup_diona" + base_name = "diona cup" diff --git a/mods/mobs/dionaea/items/lunchbox.dm b/mods/mobs/dionaea/items/lunchbox.dm new file mode 100644 index 000000000000..f5395c66ec55 --- /dev/null +++ b/mods/mobs/dionaea/items/lunchbox.dm @@ -0,0 +1,7 @@ +/obj/item/lunchbox/nymph + name = "\improper Diona nymph lunchbox" + icon = 'mods/mobs/dionaea/icons/lunchbox_nymph.dmi' + desc = "A little lunchbox. This one is an adorable Diona nymph on the side!" + +/obj/item/lunchbox/nymph/filled + filled = TRUE \ No newline at end of file diff --git a/mods/dionaea/items/plush.dm b/mods/mobs/dionaea/items/plush.dm similarity index 100% rename from mods/dionaea/items/plush.dm rename to mods/mobs/dionaea/items/plush.dm diff --git a/mods/dionaea/items/random.dm b/mods/mobs/dionaea/items/random.dm similarity index 100% rename from mods/dionaea/items/random.dm rename to mods/mobs/dionaea/items/random.dm diff --git a/mods/mobs/dionaea/items/roast.dm b/mods/mobs/dionaea/items/roast.dm new file mode 100644 index 000000000000..026003662977 --- /dev/null +++ b/mods/mobs/dionaea/items/roast.dm @@ -0,0 +1,14 @@ +/obj/item/food/dionaroast + name = "roast diona" + desc = "It's like an enormous, leathery carrot. With an eye." + icon = 'mods/mobs/dionaea/icons/roast.dmi' + plate = /obj/item/plate + filling_color = "#75754b" + center_of_mass = @'{"x":16,"y":7}' + nutriment_desc = list("a chorus of flavor" = 6) + nutriment_amt = 6 + bitesize = 2 + +/obj/item/food/dionaroast/populate_reagents() + add_to_reagents(/decl/material/solid/metal/radium, 2) + . = ..() diff --git a/mods/dionaea/machinery/seed_storage.dm b/mods/mobs/dionaea/machinery/seed_storage.dm similarity index 100% rename from mods/dionaea/machinery/seed_storage.dm rename to mods/mobs/dionaea/machinery/seed_storage.dm diff --git a/mods/dionaea/machinery/vending.dm b/mods/mobs/dionaea/machinery/vending.dm similarity index 82% rename from mods/dionaea/machinery/vending.dm rename to mods/mobs/dionaea/machinery/vending.dm index 97ef8dc44191..596f7d8869f7 100644 --- a/mods/dionaea/machinery/vending.dm +++ b/mods/mobs/dionaea/machinery/vending.dm @@ -3,13 +3,13 @@ /obj/machinery/vending/finish_vending() if(prob(diona_spawn_chance)) //Hehehe - var/mob/living/carbon/alien/diona/S = new(get_turf(src)) + var/mob/living/simple_animal/alien/diona/S = new(get_turf(src)) visible_message(SPAN_NOTICE("\The [src] makes an odd grinding noise before coming to a halt as \a [S.name] slithers out of the receptacle.")) return ..() /obj/machinery/vending/dinnerware/Initialize(mapload, d, populate_parts) - products[/obj/item/storage/lunchbox/nymph] = 3 + products[/obj/item/lunchbox/nymph] = 3 . = ..() /obj/machinery/vending/hydroseeds/Initialize(mapload, d, populate_parts) diff --git a/mods/mobs/dionaea/mob/_nymph.dm b/mods/mobs/dionaea/mob/_nymph.dm new file mode 100644 index 000000000000..d3e6f257ebe2 --- /dev/null +++ b/mods/mobs/dionaea/mob/_nymph.dm @@ -0,0 +1,94 @@ +#define DIONA_SCREEN_LOC_HELD "RIGHT-8:16,BOTTOM:5" +#define DIONA_SCREEN_LOC_HAT "RIGHT-7:16,BOTTOM:5" +#define DIONA_SCREEN_LOC_INTENT "RIGHT-2,BOTTOM:5" +#define DIONA_SCREEN_LOC_HEALTH "RIGHT-1:28,CENTER-1:13" + +/mob/living/simple_animal/alien/diona + name = "diona nymph" + desc = "It's a little skittery critter. Chirp." + icon = 'mods/mobs/dionaea/icons/nymph.dmi' + icon_state = ICON_STATE_WORLD + death_message = "expires with a pitiful chirrup..." + max_health = 60 + available_maneuvers = list(/decl/maneuver/leap) + status_flags = NO_ANTAG + glowing_eyes = TRUE + + species_language = /decl/language/diona + only_species_language = 1 + speak_emote = list("chirrups") + universal_understand = FALSE + universal_speak = FALSE + + can_pull_size = ITEM_SIZE_SMALL + can_pull_mobs = MOB_PULL_SMALLER + + holder_type = /obj/item/holder/diona + possession_candidate = TRUE + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE + hud_used = /datum/hud/diona_nymph + + ai = /datum/mob_controller/nymph + + z_flags = ZMM_MANGLE_PLANES + + var/tmp/flower_color + var/tmp/last_glow + +/mob/living/simple_animal/alien/diona/get_jump_distance() + return 3 + +/mob/living/simple_animal/alien/diona/setup_languages() + add_language(/decl/language/diona) + +/mob/living/simple_animal/alien/diona/sterile + name = "sterile nymph" + +/mob/living/simple_animal/alien/diona/sterile/Initialize(var/mapload) + . = ..(mapload, 0) + +/mob/living/simple_animal/alien/diona/Initialize(var/mapload, var/flower_chance = 15) + + set_extension(src, /datum/extension/base_icon_state, icon_state) + add_language(/decl/language/diona) + add_language(/decl/language/human/common, 0) + add_inventory_slot(new /datum/inventory_slot/head/simple) + add_held_item_slot(new /datum/inventory_slot/gripper/mouth/nymph) + if(prob(flower_chance)) + flower_color = get_random_colour(1) + update_icon() + + . = ..(mapload) + +/mob/living/simple_animal/alien/diona/get_dexterity(var/silent) + return (DEXTERITY_EQUIP_ITEM|DEXTERITY_HOLD_ITEM) + +/mob/living/simple_animal/alien/diona/get_bodytype() + return GET_DECL(/decl/bodytype/diona) + +/mob/living/simple_animal/alien/diona/handle_mutations_and_radiation() + ..() + if(radiation) + var/rads = radiation/25 + radiation -= rads + adjust_nutrition(rads) + heal_overall_damage(rads,rads) + heal_damage(OXY, rads, do_update_health = FALSE) + heal_damage(TOX, rads) + +/decl/bodytype/diona + name = "nymph" + bodytype_flag = 0 + bodytype_category = "diona nymph body" + uid = "bodytype_diona" + +/decl/bodytype/diona/Initialize() + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list(0, -8), + "[SOUTH]" = list(0, -8), + "[EAST]" = list(0, -8), + "[WEST]" = list(0, -8) + ) + ) + . = ..() diff --git a/mods/mobs/dionaea/mob/gestalt/_gestalt.dm b/mods/mobs/dionaea/mob/gestalt/_gestalt.dm new file mode 100644 index 000000000000..e57e20ef1918 --- /dev/null +++ b/mods/mobs/dionaea/mob/gestalt/_gestalt.dm @@ -0,0 +1,46 @@ +/obj/structure/diona_gestalt + name = "nascent diona gestalt" + desc = "A heaving mass of nymphs. Chirp?" + icon = 'mods/mobs/dionaea/icons/gestalt.dmi' + icon_state = "gestalt" + density = TRUE + opacity = FALSE + anchored = FALSE + movement_handlers = list(/datum/movement_handler/deny_multiz, /datum/movement_handler/delay = list(5)) + z_flags = ZMM_MANGLE_PLANES + + var/list/nymphs = list() + var/list/valid_things_to_roll_up = list(/mob/living/simple_animal/alien/diona = TRUE, /mob/living/simple_animal/alien/diona/sterile = TRUE) + var/tmp/image/eyes_overlay + +/obj/structure/diona_gestalt/mob_breakout(var/mob/living/escapee) + . = ..() + shed_atom(escapee) + return TRUE + +/obj/structure/diona_gestalt/Initialize(var/mapload) + eyes_overlay = emissive_overlay(icon = icon, icon_state = "eyes_gestalt") + update_icon() + . = ..(mapload) + +/obj/structure/diona_gestalt/on_update_icon() + ..() + add_overlay(eyes_overlay) + if(LAZYLEN(nymphs)) + var/matrix/M = matrix() + M.Scale(clamp(nymphs.len * 0.1, 1, 2)) + transform = M + else + transform = null + +/obj/structure/diona_gestalt/Destroy() + for(var/thing in contents) + var/atom/movable/AM = thing + AM.dropInto(loc) + nymphs.Cut() + . = ..() + +/obj/structure/diona_gestalt/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(nymphs) + . += "It seems to be composed of at least [nymphs.len] nymph\s." diff --git a/mods/mobs/dionaea/mob/gestalt/gestalt_attacks.dm b/mods/mobs/dionaea/mob/gestalt/gestalt_attacks.dm new file mode 100644 index 000000000000..fea9e8e64f4c --- /dev/null +++ b/mods/mobs/dionaea/mob/gestalt/gestalt_attacks.dm @@ -0,0 +1,24 @@ +/obj/structure/diona_gestalt/attackby(var/obj/item/used_item, var/mob/user) + . = ..() + if(used_item.get_attack_force(user)) + shed_atom(forcefully = TRUE) + +/obj/structure/diona_gestalt/hitby() + . = ..() + if(.) + shed_atom(forcefully = TRUE) + +/obj/structure/diona_gestalt/bullet_act(var/obj/item/projectile/P, var/def_zone) + . = ..() + if(P && (P.atom_damage_type == BRUTE || P.atom_damage_type == BURN)) + shed_atom(forcefully = TRUE) + +/obj/structure/diona_gestalt/explosion_act() + SHOULD_CALL_PARENT(FALSE) + var/shed_count = rand(1,3) + while(shed_count && LAZYLEN(nymphs)) + shed_count-- + shed_atom(forcefully = TRUE) + +/obj/structure/diona_gestalt/proc/handle_member_click(var/mob/living/simple_animal/alien/diona/clicker) + return FALSE diff --git a/mods/dionaea/mob/gestalt/gestalt_movement.dm b/mods/mobs/dionaea/mob/gestalt/gestalt_movement.dm similarity index 91% rename from mods/dionaea/mob/gestalt/gestalt_movement.dm rename to mods/mobs/dionaea/mob/gestalt/gestalt_movement.dm index 83b36afe8d78..a3090a11c321 100644 --- a/mods/dionaea/mob/gestalt/gestalt_movement.dm +++ b/mods/mobs/dionaea/mob/gestalt/gestalt_movement.dm @@ -6,11 +6,10 @@ . = ..() if(AM && can_roll_up_atom(AM) && AM.Adjacent(src)) var/turf/stepping = AM.loc - roll_up_atom(AM) - if(stepping) + if(roll_up_atom(AM) && stepping) step_towards(src, stepping) - + else if(istype(AM, /obj/structure/diona_gestalt) && AM != src) // Combine!? var/obj/structure/diona_gestalt/gestalt = AM if(LAZYLEN(gestalt.nymphs)) @@ -24,10 +23,10 @@ /obj/structure/diona_gestalt/Bumped(var/atom/A) . = ..() - if(istype(A, /mob/living/carbon/alien/diona) && A.Adjacent(src)) // Combine... + if(isdiona(A) && A.Adjacent(src)) // Combine... roll_up_atom(A) -/obj/structure/diona_gestalt/Move() +/obj/structure/diona_gestalt/Move() . = ..() if(.) for(var/atom/movable/AM in loc) @@ -42,7 +41,7 @@ if(istype(thing, /obj)) var/obj/rolling_up = thing return rolling_up.w_class <= get_max_item_rollup_size() - if(istype(thing, /mob)) + if(ismob(thing)) var/mob/rolling_up = thing return rolling_up.mob_size <= get_max_mob_rollup_size() diff --git a/mods/dionaea/mob/gestalt/gestalt_nymph.dm b/mods/mobs/dionaea/mob/gestalt/gestalt_nymph.dm similarity index 78% rename from mods/dionaea/mob/gestalt/gestalt_nymph.dm rename to mods/mobs/dionaea/mob/gestalt/gestalt_nymph.dm index cf610d894c55..7b4f4d686ca8 100644 --- a/mods/dionaea/mob/gestalt/gestalt_nymph.dm +++ b/mods/mobs/dionaea/mob/gestalt/gestalt_nymph.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/alien/diona/proc/gestalt_with(var/mob/living/carbon/alien/diona/chirp) +/mob/living/simple_animal/alien/diona/proc/gestalt_with(var/mob/living/simple_animal/alien/diona/chirp) if(!istype(chirp) || chirp == src || chirp.incapacitated() || incapacitated()) return FALSE if(istype(chirp.loc, /obj/structure/diona_gestalt) || istype(loc, /obj/structure/diona_gestalt)) @@ -9,15 +9,16 @@ blob.roll_up_atom(src, silent = TRUE) return TRUE -/obj/structure/diona_gestalt/proc/roll_up_atom(var/mob/living/carbon/alien/diona/chirp, var/silent) +/obj/structure/diona_gestalt/proc/roll_up_atom(var/mob/living/simple_animal/alien/diona/chirp, var/silent) if(!istype(chirp)) - return + return FALSE if(!silent) visible_message("\The [chirp] is engulfed by \the [src].") - if(istype(chirp, /mob/living/carbon/alien/diona)) + if(isdiona(chirp)) nymphs[chirp] = TRUE queue_icon_update() chirp.forceMove(src) + return TRUE /obj/structure/diona_gestalt/proc/shed_atom(var/atom/movable/shedding, var/silent, var/forcefully) @@ -36,8 +37,8 @@ shedding.dropInto(loc) if(!silent) visible_message(SPAN_DANGER("\The [shedding] splits away from \the [src]!")) - if(forcefully) - shedding.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),rand(3,5)) + if(forcefully) + shedding.throw_at(get_edge_target_turf(src,pick(global.alldirs)),rand(1,3),rand(3,5)) if(update_nymphs) check_nymphs() @@ -45,7 +46,7 @@ /obj/structure/diona_gestalt/proc/check_nymphs() if(LAZYLEN(nymphs.len) >= 2) for(var/nimp in nymphs) - var/mob/living/carbon/alien/diona/chirp = nimp + var/mob/living/simple_animal/alien/diona/chirp = nimp if(chirp.client) return visible_message("\The [src] has completely split apart!") diff --git a/mods/mobs/dionaea/mob/gestalt/gestalt_turfs.dm b/mods/mobs/dionaea/mob/gestalt/gestalt_turfs.dm new file mode 100644 index 000000000000..04d498ef7613 --- /dev/null +++ b/mods/mobs/dionaea/mob/gestalt/gestalt_turfs.dm @@ -0,0 +1,13 @@ +/decl/flooring/diona + name = "biomass" + desc = "A mass of small intertwined aliens forming a floor... creepy." + icon = 'mods/mobs/dionaea/icons/turfs.dmi' + icon_base = "floor" + flooring_flags = TURF_ACID_IMMUNE | TURF_REMOVE_SHOVEL + uid = "floor_diona" + +/turf/floor/diona + name = "biomass" + icon = 'mods/mobs/dionaea/icons/turfs.dmi' + icon_state = "floor" + _flooring = /decl/flooring/diona diff --git a/mods/mobs/dionaea/mob/nymph_attacks.dm b/mods/mobs/dionaea/mob/nymph_attacks.dm new file mode 100644 index 000000000000..a3d0816684ed --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_attacks.dm @@ -0,0 +1,95 @@ +/mob/living/simple_animal/alien/diona/ResolveUnarmedAttack(var/atom/A) + + if(incapacitated()) + return ..() + + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(istype(loc, /obj/structure/diona_gestalt)) + var/obj/structure/diona_gestalt/gestalt = loc + return gestalt.handle_member_click(src, A) + + if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) + return handle_tray_interaction(A) + + // This is super hacky. Not sure if I will leave this in for a final merge. + // Reporting back from the future: keeping this because trying to refactor + // seed storage to handle this cleanly would be a pain in the ass and I + // don't want to touch that pile. + + if(istype(A, /obj/machinery/seed_storage)) + visible_message(SPAN_DANGER("\The [src] headbutts \the [A]!")) + var/obj/machinery/seed_storage/G = A + if(LAZYLEN(G.piles)) + var/datum/seed_pile/pile = pick(G.piles) + var/obj/item/seeds/S = pick(pile.seeds) + if(S) + pile.amount -= 1 + pile.seeds -= S + if(pile.amount <= 0 || LAZYLEN(pile.seeds) <= 0) + G.piles -= pile + qdel(pile) + S.forceMove(get_turf(G)) + G.visible_message(SPAN_NOTICE("\A [S] falls out!")) + return TRUE + // End superhacky stuff. + + if(ismob(A)) + if(src != A && !gestalt_with(A)) + visible_message(SPAN_NOTICE("\The [src] butts its head into \the [A].")) + return TRUE + return ..() + +/mob/living/simple_animal/alien/diona/proc/handle_tray_interaction(var/obj/machinery/portable_atmospherics/hydroponics/tray) + + if(incapacitated()) + return FALSE + + if(!tray.seed) + var/obj/item/seeds/seeds = get_active_held_item() + if(istype(seeds)) + if(try_unequip(seeds)) + tray.plant_seed(src, seeds) + return TRUE + return FALSE + + if(tray.dead) + if(tray.remove_dead(src, silent = TRUE)) + add_to_reagents(/decl/material/liquid/nutriment/glucose, rand(10,20)) + visible_message(SPAN_NOTICE("\The [src] chews up the dead plant, clearing \the [tray] out."), SPAN_NOTICE("You devour the dead plant, clearing \the [tray].")) + return TRUE + return FALSE + + if(tray.harvest) + if(tray.harvest(src)) + visible_message(SPAN_NOTICE("\The [src] harvests from \the [tray]."), SPAN_NOTICE("You harvest the contents of \the [tray].")) + return TRUE + return FALSE + + if(tray.weedlevel || tray.pestlevel) + add_to_reagents(/decl/material/liquid/nutriment/glucose, (tray.weedlevel + tray.pestlevel)) + tray.weedlevel = 0 + tray.pestlevel = 0 + visible_message(SPAN_NOTICE("\The [src] begins rooting through \the [tray], ripping out pests and weeds, and eating them noisily."),SPAN_NOTICE("You begin rooting through \the [tray], ripping out pests and weeds, and eating them noisily.")) + return TRUE + + if(tray.nutrilevel < 10) + var/nutrition_cost = (10-tray.nutrilevel) * 5 + if(nutrition >= nutrition_cost) + visible_message(SPAN_NOTICE("\The [src] secretes a trickle of green liquid, refilling [tray]."),SPAN_NOTICE("You secrete some nutrients into \the [tray].")) + tray.nutrilevel = 10 + adjust_nutrition(-((10-tray.nutrilevel) * 5)) + else + to_chat(src, SPAN_NOTICE("You haven't eaten enough to refill \the [tray]'s nutrients.")) + return TRUE + + if(tray.waterlevel < 100) + var/nutrition_cost = floor((100-tray.nutrilevel)/10) * 5 + if(nutrition >= nutrition_cost) + visible_message(SPAN_NOTICE("\The [src] secretes a trickle of clear liquid, refilling [tray]."),SPAN_NOTICE("You secrete some water into \the [tray].")) + tray.waterlevel = 100 + else + to_chat(src, SPAN_NOTICE("You haven't eaten enough to refill \the [tray]'s water.")) + return TRUE + + visible_message(SPAN_NOTICE("\The [src] rolls around in \the [tray] for a bit."),SPAN_NOTICE("You roll around in \the [tray] for a bit.")) + return TRUE diff --git a/mods/mobs/dionaea/mob/nymph_death.dm b/mods/mobs/dionaea/mob/nymph_death.dm new file mode 100644 index 000000000000..791b638a7eda --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_death.dm @@ -0,0 +1,6 @@ +/mob/living/simple_animal/alien/diona/death(gibbed) + . = ..() + if(.) + var/obj/structure/diona_gestalt/gestalt = loc + if(istype(gestalt)) + gestalt.shed_atom(src, TRUE, FALSE) diff --git a/mods/mobs/dionaea/mob/nymph_emotes.dm b/mods/mobs/dionaea/mob/nymph_emotes.dm new file mode 100644 index 000000000000..634ed8fba38d --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_emotes.dm @@ -0,0 +1,32 @@ +/mob/living/simple_animal/alien/diona/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/visible, + /decl/emote/visible/scratch, + /decl/emote/visible/drool, + /decl/emote/visible/nod, + /decl/emote/visible/sway, + /decl/emote/visible/sulk, + /decl/emote/visible/twitch, + /decl/emote/visible/dance, + /decl/emote/visible/roll, + /decl/emote/visible/shake, + /decl/emote/visible/jump, + /decl/emote/visible/shiver, + /decl/emote/visible/collapse, + /decl/emote/visible/spin, + /decl/emote/visible/sidestep, + /decl/emote/audible/hiss, + /decl/emote/audible, + /decl/emote/audible/scretch, + /decl/emote/audible/choke, + /decl/emote/audible/gnarl, + /decl/emote/audible/bug_hiss, + /decl/emote/audible/bug_chitter, + /decl/emote/audible/chirp + ) + return default_emotes + +/decl/emote/audible/chirp + key = "chirp" + emote_message_3p = "$USER$ chirps!" + emote_sound = 'mods/mobs/dionaea/sounds/nymphchirp.ogg' diff --git a/mods/dionaea/mob/nymph_gestalting.dm b/mods/mobs/dionaea/mob/nymph_gestalting.dm similarity index 89% rename from mods/dionaea/mob/nymph_gestalting.dm rename to mods/mobs/dionaea/mob/nymph_gestalting.dm index 12259f5f993d..9d2607213d41 100644 --- a/mods/dionaea/mob/nymph_gestalting.dm +++ b/mods/mobs/dionaea/mob/nymph_gestalting.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/alien/diona/verb/split_away() +/mob/living/simple_animal/alien/diona/verb/split_away() set name = "Split From Gestalt" set category = "IC" set src = usr diff --git a/mods/mobs/dionaea/mob/nymph_holder.dm b/mods/mobs/dionaea/mob/nymph_holder.dm new file mode 100644 index 000000000000..1a06eb0d14bd --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_holder.dm @@ -0,0 +1,17 @@ +/obj/item/holder/diona + origin_tech = @'{"magnets":3,"biotech":5}' + slot_flags = SLOT_HEAD | SLOT_OVER_BODY | SLOT_HOLSTER + armor = list( + ARMOR_BIO = ARMOR_BIO_RESISTANT, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + +// Yes, you can wear a nymph on your head instead of a radiation mask. +/obj/item/holder/diona/equipped(var/mob/living/user, var/slot) + if(slot in user.get_held_item_slots()) + body_parts_covered = SLOT_ARMS + else if(slot == slot_head_str) + body_parts_covered = SLOT_HEAD + else if(slot == slot_wear_suit_str) + body_parts_covered = SLOT_UPPER_BODY + . = ..() \ No newline at end of file diff --git a/mods/mobs/dionaea/mob/nymph_life.dm b/mods/mobs/dionaea/mob/nymph_life.dm new file mode 100644 index 000000000000..20cc36480db7 --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_life.dm @@ -0,0 +1,40 @@ +//Dionaea regenerate health and nutrition in light. +/mob/living/simple_animal/alien/diona/handle_environment(datum/gas_mixture/environment) + + ..() + + if(stat == DEAD) + return + + var/turf/checking = get_turf(src) + if(!checking) + return + + var/light_amount = checking.get_lumcount() * 5 + + if(radiation <= 20) + if(last_glow) + set_light(0) + last_glow = 0 + else + var/mult = clamp(radiation/200, 0.5, 1) + if(last_glow != mult) + set_light((5 * mult), mult, "#55ff55") + last_glow = mult + + set_nutrition(clamp(nutrition + floor(radiation/100) + light_amount, 0, 500)) + + if(radiation >= 50 || light_amount > 2) //if there's enough light, heal + var/update_health = FALSE + var/static/list/regen_types = list( + BRUTE, + BURN, + TOX, + OXY + ) + for(var/damtype in regen_types) + if(get_damage(damtype)) + heal_damage(damtype, 1, do_update_health = FALSE) + update_health = TRUE + if(update_health) + update_health() \ No newline at end of file diff --git a/mods/mobs/dionaea/mob/nymph_ui.dm b/mods/mobs/dionaea/mob/nymph_ui.dm new file mode 100644 index 000000000000..f4226bf88712 --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_ui.dm @@ -0,0 +1,35 @@ +/decl/ui_style/diona + name = "Diona" + restricted = TRUE + uid = "ui_style_diona" + override_icons = list( + (HUD_HEALTH) = 'mods/mobs/dionaea/icons/ui_health.dmi', + (HUD_HANDS) = 'mods/mobs/dionaea/icons/ui_hands.dmi', + (HUD_RESIST) = 'mods/mobs/dionaea/icons/ui_interactions_resist.dmi', + (HUD_THROW) = 'mods/mobs/dionaea/icons/ui_interactions_throw.dmi', + (HUD_DROP) = 'mods/mobs/dionaea/icons/ui_interactions_drop.dmi', + (HUD_MANEUVER) = 'mods/mobs/dionaea/icons/ui_interactions_maneuver.dmi', + (HUD_INVENTORY) = 'mods/mobs/dionaea/icons/ui_inventory.dmi' + ) + +/decl/hud_element/health/diona + elem_type = /obj/screen/health/diona + elem_reference_type = /decl/hud_element/health + +/datum/hud/diona_nymph + omit_hud_elements = list(/decl/hud_element/health) + additional_hud_elements = list(/decl/hud_element/health/diona) + +/datum/hud/diona_nymph/get_ui_style_data() + return GET_DECL(/decl/ui_style/diona) + +/datum/hud/diona_nymph/get_ui_color() + return COLOR_WHITE + +/datum/hud/diona_nymph/get_ui_alpha() + return 255 + +/obj/screen/health/diona + icon_state = "health0" + name = "health" + screen_loc = DIONA_SCREEN_LOC_HEALTH diff --git a/mods/mobs/dionaea/mob/nymph_update_icons.dm b/mods/mobs/dionaea/mob/nymph_update_icons.dm new file mode 100644 index 000000000000..7a94081be639 --- /dev/null +++ b/mods/mobs/dionaea/mob/nymph_update_icons.dm @@ -0,0 +1,8 @@ +/mob/living/simple_animal/alien/diona/on_update_icon() + ..() + if(flower_color && icon_state == ICON_STATE_WORLD) + var/image/flower = image(icon = icon, icon_state = "flower_back") + var/image/I = image(icon = icon, icon_state = "flower_fore") + I.color = flower_color + flower.overlays += I + add_overlay(flower) diff --git a/mods/dionaea/mob/~diona.dm b/mods/mobs/dionaea/mob/~diona.dm similarity index 100% rename from mods/dionaea/mob/~diona.dm rename to mods/mobs/dionaea/mob/~diona.dm diff --git a/mods/dionaea/sounds/nymphchirp.ogg b/mods/mobs/dionaea/sounds/nymphchirp.ogg similarity index 100% rename from mods/dionaea/sounds/nymphchirp.ogg rename to mods/mobs/dionaea/sounds/nymphchirp.ogg diff --git a/mods/modern_earth/_modern_earth.dme b/mods/modern_earth/_modern_earth.dme deleted file mode 100644 index 4011226d9cd5..000000000000 --- a/mods/modern_earth/_modern_earth.dme +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef MODPACK_MODERN_EARTH -#define MODPACK_MODERN_EARTH -// BEGIN_INCLUDE -#include "modern_earth.dm" -#include "datum\religions.dm" -// END_INCLUDE -#endif diff --git a/mods/modern_earth/datum/religions.dm b/mods/modern_earth/datum/religions.dm deleted file mode 100644 index 959a61247bc4..000000000000 --- a/mods/modern_earth/datum/religions.dm +++ /dev/null @@ -1,59 +0,0 @@ -/decl/cultural_info/religion/jewish - name = RELIGION_JUDAISM - description = "An Abrahamic monotheistic religion held to by the Jewish people. Someone who practices Judaism and is of the Jewish culture is called a Jew." - -/decl/cultural_info/religion/hindu - name = RELIGION_HINDUISM - description = "An Indian religion encompassing a variety of traditions, beliefs and spiritual practices. Someone who practices Hinduism is called a Hindu." - -/decl/cultural_info/religion/buddhist - name = RELIGION_BUDDHISM - description = "An Indian religion encompassing a variety of traditions, beliefs and spiritual practices based on the teachings of the Buddha. Someone who practices Buddhism is called a Buddhist." - -/decl/cultural_info/religion/jain - name = RELIGION_JAINISM - description = "An Indian religion that teaches salvation through successive lives and nonviolence. Someone who practices Jainism is called a Jain." - -/decl/cultural_info/religion/sikh - name = RELIGION_SIKHISM - description = "An Indian monotheistic religion based on the spiritual teachings of Guru Nanak and the nine Sikh gurus that succeeded him. Someone who practicies Sikhism is called a Sikh." - -/decl/cultural_info/religion/muslim - name = RELIGION_ISLAM - description = "An Abrahamic monotheistic religion teaching that there is only one God and that Muhammad is His prophet. Someone who practices Islam is called a Muslim." - -/decl/cultural_info/religion/christian - name = RELIGION_CHRISTIANITY - description = "An Abrahamic monotheistic religion based on the life and teachings of Jesus of Nazareth. Someone who practices Christianity is called a Christian." - -/decl/cultural_info/religion/bahai - name = RELIGION_BAHAI_FAITH - description = "An Abrahamic monotheistic religion that follows the teachings of Baha'u'llah and believes in universal peace and unity. Someone who practices the Baha'i Faith is called a Baha'i." - -/decl/cultural_info/religion/agnostic - name = RELIGION_AGNOSTICISM - description = "A belief that nothing is known or can be known of the existence or nature of God. Someone who holds to agnosticism is called an agnostic." - -/decl/cultural_info/religion/deist - name = RELIGION_DEISM - description = "A belief in the existence of a supreme being, specifically of a creator who does not intervene in the universe. Someone who practices deism is called a deist." - -/decl/cultural_info/religion/atheist - name = RELIGION_ATHEISM - description = "A lack of belief in a God. Someone who holds to atheism is called an atheist." - -/decl/cultural_info/religion/thelemite - name = RELIGION_THELEMA - description = "An esoteric Western religion focusing on the law of Thelema. Someone who practices Thelema is called a Thelemite." - -/decl/cultural_info/religion/spiritualism - name = RELIGION_SPIRITUALISM - description = "A belief based on communication with the spirits of the dead, especially through mediums. Someone who practices spiritualism is called a spiritualist." - -/decl/cultural_info/religion/shinto - name = RELIGION_SHINTO - description = "A traditional Japanese religion based on rituals to create a connection between the past and modern day. Someone who practices Shinto is called a Shintoist." - -/decl/cultural_info/religion/taoist - name = RELIGION_TAOISM - description = "A traditional Chinese religion that emphasizes living in harmony with the Tao. Someone who practices Taoism is called a Taoist." \ No newline at end of file diff --git a/mods/modern_earth/modern_earth.dm b/mods/modern_earth/modern_earth.dm deleted file mode 100644 index 5a3f045212c5..000000000000 --- a/mods/modern_earth/modern_earth.dm +++ /dev/null @@ -1,22 +0,0 @@ -#define RELIGION_JUDAISM "Judaism" -#define RELIGION_HINDUISM "Hinduism" -#define RELIGION_BUDDHISM "Buddhism" -#define RELIGION_SIKHISM "Sikhism" -#define RELIGION_JAINISM "Jainism" -#define RELIGION_ISLAM "Islam" -#define RELIGION_CHRISTIANITY "Christianity" -#define RELIGION_BAHAI_FAITH "Baha'i Faith" -#define RELIGION_AGNOSTICISM "Agnosticism" -#define RELIGION_DEISM "Deism" -#define RELIGION_ATHEISM "Atheism" -#define RELIGION_THELEMA "Thelema" -#define RELIGION_SPIRITUALISM "Spiritualism" -#define RELIGION_SHINTO "Shinto" -#define RELIGION_TAOISM "Taoism" - -// Specifically modern real-world concepts. -/decl/modpack/modern_earth - name = "Modern Earth Content" - credits_adjectives = list("SOCRATIC") - credits_holidays = list("CHRISTMAS", "EASTER", "WEEKEND", "THURSDAY") - credits_topics = list("ANCIENT CHINESE MEDICINE", "STRING THEORY") diff --git a/mods/psionics/_defines.dm b/mods/psionics/_defines.dm deleted file mode 100644 index d65221db6852..000000000000 --- a/mods/psionics/_defines.dm +++ /dev/null @@ -1,25 +0,0 @@ -#define MODE_PARAMOUNT "paramount" -#define MODE_FOUNDATION "foundation agent" - -#define PSI_IMPLANT_AUTOMATIC "Security Level Derived" -#define PSI_IMPLANT_SHOCK "Issue Neural Shock" -#define PSI_IMPLANT_WARN "Issue Reprimand" -#define PSI_IMPLANT_LOG "Log Incident" -#define PSI_IMPLANT_DISABLED "Disabled" - -#define PSI_COERCION "coercion" -#define PSI_PSYCHOKINESIS "psychokinesis" -#define PSI_REDACTION "redaction" -#define PSI_ENERGISTICS "energistics" - -#define PSI_RANK_BLUNT 0 -#define PSI_RANK_LATENT 1 -#define PSI_RANK_OPERANT 2 -#define PSI_RANK_MASTER 3 -#define PSI_RANK_GRANDMASTER 4 -#define PSI_RANK_PARAMOUNT 5 - -#define PSIONIC "psi" - -#define MAT_NULLGLASS /decl/material/nullglass -#define COLOR_NULLGLASS "#ff6088" diff --git a/mods/psionics/_psionics.dm b/mods/psionics/_psionics.dm deleted file mode 100644 index 36b17b316be3..000000000000 --- a/mods/psionics/_psionics.dm +++ /dev/null @@ -1,26 +0,0 @@ -/decl/modpack/psionics - name = "Psionics Content" - dreams = list("the Foundation", "nullglass") - -/decl/modpack/psionics/get_player_panel_options(var/mob/M) - . = list("Psionics:
    ") - if(isliving(M)) - var/mob/living/psyker = M - if(psyker.psi) - . += "Remove psionics.

    " - . += "Trigger latencies.
    " - . += "
    ColourAncestorsDescendantsReactions
    [capitalize(slime_data.name)][jointext(ancestors, ", ")][jointext(child_colours, ", ")]" + var/list/reagent_strings = list() + for(var/reagent_id in slime_data.reaction_strings) + var/decl/material/mat = GET_DECL(reagent_id) + reagent_strings += "[capitalize(mat.name)]- [slime_data.reaction_strings[reagent_id]]" + extra_mechanics_text += "[length(reagent_strings) ? jointext(reagent_strings, "
    ") : "None."]
    " - for(var/faculty in list(PSI_COERCION, PSI_PSYCHOKINESIS, PSI_REDACTION, PSI_ENERGISTICS)) - var/decl/psionic_faculty/faculty_decl = SSpsi.get_faculty(faculty) - var/faculty_rank = psyker.psi ? psyker.psi.get_rank(faculty) : 0 - . += "" - for(var/i = 1 to LAZYLEN(GLOB.psychic_ranks_to_strings)) - var/psi_title = GLOB.psychic_ranks_to_strings[i] - if(i == faculty_rank) - psi_title = "[psi_title]" - . += "" - . += "" - . += "
    [faculty_decl.name][psi_title]
    " - else - . += "Only available for living mobs, sorry." - . = jointext(., null) \ No newline at end of file diff --git a/mods/psionics/datum/antagonists/foundation.dm b/mods/psionics/datum/antagonists/foundation.dm deleted file mode 100644 index 56c4203d25f5..000000000000 --- a/mods/psionics/datum/antagonists/foundation.dm +++ /dev/null @@ -1,54 +0,0 @@ -GLOBAL_DATUM_INIT(foundation_agents, /datum/antagonist/foundation, new) - -/datum/antagonist/foundation - id = MODE_FOUNDATION - role_text = "Foundation Agent" - antag_indicator = "hudfoundation" - role_text_plural = "Foundation Agents" - welcome_text = "You are a field agent of the Cuchulain Foundation, \ - a body that specializes in taking down psychic threats. You have a free pass to anywhere \ - you like, a pistol loaded with anti-psi nullglass rounds, and a clear duty. Naturally, \ - nobody takes your employers seriously - until a day like today." - antag_text = "You are an anti antagonist! Within the rules, \ - try to save the installation and its inhabitants from the ongoing crisis. \ - Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ - and before taking extreme actions, please try to also contact the administration! \ - Think through your actions and make the roleplay immersive! Please remember all \ - rules aside from those without explicit exceptions apply to Foundation Agents." - - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_SET_APPEARANCE - antaghud_indicator = "hudfoundation" - landmark_id = "Response Team" - hard_cap = 3 - hard_cap_round = 3 - initial_spawn_req = 1 - initial_spawn_target = 2 - min_player_age = 14 - faction = "foundation" - id_type = /obj/item/card/id/foundation - -/datum/antagonist/foundation/equip(var/mob/living/carbon/human/player) - - if(!..()) - return 0 - - player.set_psi_rank(PSI_REDACTION, 3, defer_update = TRUE) - player.set_psi_rank(PSI_COERCION, 3, defer_update = TRUE) - player.set_psi_rank(PSI_PSYCHOKINESIS, 3, defer_update = TRUE) - player.set_psi_rank(PSI_ENERGISTICS, 3, defer_update = TRUE) - player.psi.update(TRUE) - - var/decl/hierarchy/outfit/foundation = outfit_by_type(/decl/hierarchy/outfit/foundation) - foundation.equip(player) - - create_id("Foundation Agent", player) - -/decl/hierarchy/outfit/foundation - name = "Cuchulain Foundation Agent" - glasses = /obj/item/clothing/glasses/sunglasses - uniform = /obj/item/clothing/under/suit_jacket/charcoal - shoes = /obj/item/clothing/shoes/color/black - l_hand = /obj/item/storage/briefcase/foundation - l_ear = /obj/item/radio/headset/foundation - holster = /obj/item/clothing/accessory/storage/holster/armpit - id_slot = slot_wear_id diff --git a/mods/psionics/datum/antagonists/paramount.dm b/mods/psionics/datum/antagonists/paramount.dm deleted file mode 100644 index afe63be4e5f9..000000000000 --- a/mods/psionics/datum/antagonists/paramount.dm +++ /dev/null @@ -1,79 +0,0 @@ -GLOBAL_DATUM_INIT(paramounts, /datum/antagonist/paramount, new) - -/datum/antagonist/paramount - id = MODE_PARAMOUNT - role_text = "Paramount" - role_text_plural = "Paramounts" - landmark_id = "ninjastart" - welcome_text = "You were once one of the finest minds of your culture, now driven to madness by the whispers of the howling dark and blessed with psychic faculties that defy understanding. Using your C-E rig and your twisted knowledge of psionics, advance your agenda in human space." - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_RANDSPAWN | ANTAG_SET_APPEARANCE - antaghud_indicator = "hudwizard" - initial_spawn_req = 1 - initial_spawn_target = 1 - hard_cap = 1 - hard_cap_round = 3 - min_player_age = 18 - id_type = /obj/item/card/id/syndicate - faction = "paramount" - -/datum/antagonist/paramount/equip(var/mob/living/carbon/human/player) - - if(!..()) - return 0 - - player.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/psi_amp(player), slot_head) - player.set_psi_rank(PSI_REDACTION, 3, defer_update = TRUE) - player.set_psi_rank(PSI_COERCION, 3, defer_update = TRUE) - player.set_psi_rank(PSI_PSYCHOKINESIS, 3, defer_update = TRUE) - player.set_psi_rank(PSI_ENERGISTICS, 3, defer_update = TRUE) - player.psi.update(TRUE) - - player.equip_to_slot_or_del(new /obj/item/clothing/under/psysuit(player), slot_w_uniform) - player.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/psypurple(player), slot_wear_suit) - player.equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(player), slot_shoes) - player.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(player), slot_back) - var/obj/item/clothing/gloves/color/gloves = new() - gloves.color = COLOR_GRAY80 - player.equip_to_slot_or_del(gloves, slot_gloves) - //player.internal_organs_by_name["frontal lobe"] = new /obj/item/organ/internal/corona_pollentia(player) //TODO - return 1 - -/datum/antagonist/paramount/create_objectives(var/datum/mind/player) - - if(!..()) - return - // Copied from ninja for now. - var/objective_list = list(1,2,3) - for(var/i=rand(2,3),i>0,i--) - switch(pick(objective_list)) - if(1)//Kill - var/datum/objective/assassinate/objective = new - objective.owner = player - objective.target = objective.find_target() - if(objective.target != "Free Objective") - player.objectives += objective - else - i++ - objective_list -= 1 // No more than one kill objective - if(2)//Protect - var/datum/objective/protect/objective = new - objective.owner = player - objective.target = objective.find_target() - if(objective.target != "Free Objective") - player.objectives += objective - else - i++ - objective_list -= 3 - if(3)//Harm - var/datum/objective/harm/objective = new - objective.owner = player - objective.target = objective.find_target() - if(objective.target != "Free Objective") - player.objectives += objective - else - i++ - objective_list -= 4 - - var/datum/objective/survive/objective = new - objective.owner = player - player.objectives += objective diff --git a/mods/psionics/datum/armour.dm b/mods/psionics/datum/armour.dm deleted file mode 100644 index 6a94b0e06a68..000000000000 --- a/mods/psionics/datum/armour.dm +++ /dev/null @@ -1,15 +0,0 @@ -/get_armor_key(damage_type, damage_flags) - . = (damage_type == PSIONIC) ? PSIONIC : ..() - -/datum/extension/armor/psionic - expected_type = /datum/psi_complexus - full_block_message = "You block the blow with your mind!" - partial_block_message = "You soften the blow with your mind!" - -/datum/extension/armor/psionic/get_value(key) - var/datum/psi_complexus/psi = holder - psi.get_armour(key) - -/datum/extension/armor/psionic/on_blocking(damage, damage_type, damage_flags, armor_pen, blocked) - var/datum/psi_complexus/psi = holder - psi.spend_power(round(damage * blocked)) diff --git a/mods/psionics/datum/chems.dm b/mods/psionics/datum/chems.dm deleted file mode 100644 index a25cd50ec690..000000000000 --- a/mods/psionics/datum/chems.dm +++ /dev/null @@ -1,28 +0,0 @@ -/decl/material/liquid/crystal_agent/do_material_check(var/mob/living/carbon/M) - . = (M.psi || (M.mind && GLOB.wizards.is_antagonist(M.mind))) ? MAT_NULLGLASS : ..() - -/decl/material/liquid/glowsap/gleam/affect_overdose(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder) - ..() - if(M.psi) - M.psi.check_latency_trigger(30, "a [name] overdose") - -/datum/chemical_reaction/synthesis/nullglass - name = "Soulstone" - result = null - required_reagents = list(/decl/material/liquid/blood = 15, /decl/material/liquid/crystal_agent = 1) - result_amount = 1 - -/datum/chemical_reaction/synthesis/nullglass/get_reaction_flags(var/datum/reagents/holder) - var/list/blood_data = REAGENT_DATA(holder, /decl/material/liquid/blood) - var/weakref/donor_ref = LAZYACCESS(blood_data, "donor") - var/mob/living/donor = donor_ref?.resolve() - . = (istype(donor) && (donor.psi || (donor.mind && GLOB.wizards.is_antagonist(donor.mind)))) - -/datum/chemical_reaction/synthesis/nullglass/on_reaction(var/datum/reagents/holder, var/created_volume, var/reaction_flags) - var/location = get_turf(holder.my_atom) - if(reaction_flags) - for(var/i = 1, i <= created_volume, i++) - new /obj/item/soulstone(location) - else - for(var/i = 1, i <= created_volume*2, i++) - new /obj/item/shard(location, /decl/material/solid/gemstone/crystal) \ No newline at end of file diff --git a/mods/psionics/datum/codex.dm b/mods/psionics/datum/codex.dm deleted file mode 100644 index fc813385ddc8..000000000000 --- a/mods/psionics/datum/codex.dm +++ /dev/null @@ -1,48 +0,0 @@ -/datum/codex_entry/cuchulain_foundation - display_name = "Cuchulain Foundation" - associated_strings = list("Cuchulain", "Foundation") - associated_paths = list( - /obj/item/storage/briefcase/foundation, - /obj/item/gun/projectile/revolver/foundation, - /obj/item/card/id/foundation, - /obj/item/card/id/foundation_civilian, - /obj/item/clothing/suit/storage/toggle/labcoat/foundation, - /obj/item/chems/food/drinks/glass2/coffeecup/foundation - ) - lore_text = "The Cuchulain Foundation is a non-profit body based out of Neptune orbit. Their logo is \ - an upward-facing radio telescope dish, usually printed in green. They perform niche research on behalf \ - of private parties, the government, and their own interests. They are also the single largest psionic registration \ - and oversight body in human space, responsible for educating and training operants at no cost, even across \ - territorial and political lines. \ -

    \ - The rest of the article is an indecipherable haze that slips out of your memory as soon as you \ - finish reading it, but you feel pretty satisfied and informed by the end." - antag_text = "The Cuchulain Foundation is an anti-occult ERT-like body. They are equipped with \ - nullglass weapons that can disrupt or destroy psi-powers, and have their own moderately powerful \ - psionic abilities. They make heavy use of psionic influence to cloud and disrupt efforts at \ - researching or understanding them, and the depth and nature of their connections to other major \ - bodies are unclear." - -/datum/codex_entry/psionics - display_name = "Psionics" - associated_strings = list("Psychic", "Psychic Powers", "Psi") - associated_paths = list( - /obj/item/book/manual/psionics, - /obj/item/clothing/head/helmet/space/psi_amp, - /obj/item/clothing/head/helmet/space/psi_amp/lesser - ) - lore_text = "Psionics are a relatively new phenomenon theorized to be linked to long-term exposure \ - to deep, uninhabited space. A tiny, tiny subset of people exposed to such conditions can develop the \ - ability to perform small feats like levitating coins or removing a headache with nothing but their mind. \ - A decade of study has resulted in scientists determining that these psionics, mild as they are, don't pose \ - an operational or health risk, but they do encourage operants to register with a psionic regulation body \ - like the Cuchulain Foundation. \ -

    \ - However, psionics-enhancing implants, drugs and procedures are illegal in most human space, and \ - statistically seem to end in death for those foolish enough to make use of them. Being caught with a \ - cerebroenergetic enhancer, or the drug Three Eye, will net you a hefty prison sentence." - mechanics_text = "Psionic operants have a brain icon on the bottom right of the HUD. They can click it to toggle \ - their powers, or examine it to see the details of how to invoke each power, as well as their mental state. Items \ - made of nullglass will stop the use of powers, and overuse of powers can cause lethal brain damage." - antag_text = "Psionic amplifiers are illegal equipment, but can boost your psionics to massive levels at the cost \ - of occupying your hat slot permanently." \ No newline at end of file diff --git a/mods/psionics/datum/mind.dm b/mods/psionics/datum/mind.dm deleted file mode 100644 index 4cccc2c661c9..000000000000 --- a/mods/psionics/datum/mind.dm +++ /dev/null @@ -1,8 +0,0 @@ -/datum/mind/Topic(href, href_list) - . = ..() - if(!. && check_rights(R_ADMIN, FALSE) && current && isliving(current) && href_list["set_psi_faculty"] && href_list["set_psi_faculty_rank"]) - current.set_psi_rank(href_list["set_psi_faculty"], text2num(href_list["set_psi_faculty_rank"])) - log_and_message_admins("set [key_name(current)]'s [href_list["set_psi_faculty"]] faculty to [text2num(href_list["set_psi_faculty_rank"])].") - var/datum/admins/admin = GLOB.admins[usr.key] - if(istype(admin)) admin.show_player_panel(current) - return TRUE diff --git a/mods/psionics/datum/spells.dm b/mods/psionics/datum/spells.dm deleted file mode 100644 index 7c02c3520004..000000000000 --- a/mods/psionics/datum/spells.dm +++ /dev/null @@ -1,7 +0,0 @@ -/spell/cast_check(skipcharge = 0,mob/user = usr, var/list/targets) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell - var/spell_leech = user.disrupts_psionics() - if(spell_leech) - to_chat(user, SPAN_WARNING("You try to marshal your energy, but find it leeched away by \the [spell_leech]!")) - return 0 - . = ..() - \ No newline at end of file diff --git a/mods/psionics/datum/surgery.dm b/mods/psionics/datum/surgery.dm deleted file mode 100644 index 23524f3b173a..000000000000 --- a/mods/psionics/datum/surgery.dm +++ /dev/null @@ -1,8 +0,0 @@ -/decl/surgery_step/robotics/repair_brute/New() - allowed_tools[/obj/item/psychic_power/psiblade/master] = 100 - ..() - -/decl/surgery_step/hardsuit/New() - allowed_tools[/obj/item/psychic_power/psiblade/master/grand/paramount] = 100 - allowed_tools[/obj/item/psychic_power/psiblade] = 75 - ..() diff --git a/mods/psionics/items/_items.dm b/mods/psionics/items/_items.dm deleted file mode 100644 index ebada3b4ae60..000000000000 --- a/mods/psionics/items/_items.dm +++ /dev/null @@ -1,9 +0,0 @@ -/obj/item/disrupts_psionics() - . = (material && material.is_psi_null()) ? src : FALSE - -/obj/item/withstand_psi_stress(var/stress, var/atom/source) - . = ..(stress, source) - if(health >= 0 && . > 0 && disrupts_psionics()) - health -= . - . = max(0, -(health)) - check_health(consumed = TRUE) diff --git a/mods/psionics/items/brain.dm b/mods/psionics/items/brain.dm deleted file mode 100644 index b411e7b6b3e8..000000000000 --- a/mods/psionics/items/brain.dm +++ /dev/null @@ -1,4 +0,0 @@ -/obj/item/organ/internal/brain/handle_severe_brain_damage() - . = ..() - if(owner.psi) - owner.psi.check_latency_trigger(20, "physical trauma") \ No newline at end of file diff --git a/mods/psionics/items/coffee_cup.dm b/mods/psionics/items/coffee_cup.dm deleted file mode 100644 index 316e5c8a6886..000000000000 --- a/mods/psionics/items/coffee_cup.dm +++ /dev/null @@ -1,5 +0,0 @@ -/obj/item/chems/food/drinks/glass2/coffeecup/foundation - name = "\improper Foundation coffee cup" - desc = "A white coffee cup with the Cuchulain Foundation logo stencilled onto it." - icon_state = "coffeecup_foundation" - base_name = "\improper Foundation cup" \ No newline at end of file diff --git a/mods/psionics/items/foundation_implanter.dm b/mods/psionics/items/foundation_implanter.dm deleted file mode 100644 index 7fbbf094605c..000000000000 --- a/mods/psionics/items/foundation_implanter.dm +++ /dev/null @@ -1,18 +0,0 @@ -/obj/item/implanter/psi - name = "psi-null implanter" - desc = "An implant gun customized to interact with psi dampeners." - var/implanter_mode = PSI_IMPLANT_AUTOMATIC - -/obj/item/implanter/psi/attack_self(var/mob/user) - var/choice = input("Select a new implant mode.", "Psi Dampener") as null|anything in list(PSI_IMPLANT_AUTOMATIC, PSI_IMPLANT_SHOCK, PSI_IMPLANT_WARN, PSI_IMPLANT_LOG, PSI_IMPLANT_DISABLED) - if(!choice || user != loc) return - var/obj/item/implant/psi_control/implant = imp - if(!istype(implant)) - to_chat(user, "The implanter reports there is no compatible implant loaded.") - return - implant.psi_mode = choice - to_chat(user, "You set \the [src] to configure implants with the '[implant.psi_mode]' setting.") - -/obj/item/implanter/psi/Initialize() - . = ..() - imp = new /obj/item/implant/psi_control(src) diff --git a/mods/psionics/items/foundation_labcoat.dm b/mods/psionics/items/foundation_labcoat.dm deleted file mode 100644 index a3850a3f4869..000000000000 --- a/mods/psionics/items/foundation_labcoat.dm +++ /dev/null @@ -1,5 +0,0 @@ - -/obj/item/clothing/suit/storage/toggle/labcoat/foundation - name = "\improper Foundation labcoat" - desc = "A medical labcoat with a Cuchulain Foundation crest stencilled on the back." - icon = 'mods/psionics/icons/foundation_labcoat.dmi' diff --git a/mods/psionics/items/foundation_weapon.dm b/mods/psionics/items/foundation_weapon.dm deleted file mode 100644 index 1e851c76d46b..000000000000 --- a/mods/psionics/items/foundation_weapon.dm +++ /dev/null @@ -1,24 +0,0 @@ -/obj/item/gun/projectile/revolver/foundation - name = "\improper Foundation revolver" - icon = 'mods/psionics/icons/foundation.dmi' - icon_state = "foundation" - desc = "The CF 'Troubleshooter', a compact plastic-composite weapon designed for concealed carry by Cuchulain Foundation field agents. Smells faintly of copper." - ammo_type = /obj/item/ammo_casing/pistol/magnum/nullglass - -/obj/item/gun/projectile/revolver/foundation/disrupts_psionics() - return FALSE - -/obj/item/storage/briefcase/foundation - name = "\improper Foundation briefcase" - desc = "A handsome black leather briefcase embossed with a stylized radio telescope." - icon_state = "fbriefcase" - item_state = "fbriefcase" - -/obj/item/storage/briefcase/foundation/disrupts_psionics() - return FALSE - -/obj/item/storage/briefcase/foundation/Initialize() - . = ..() - new /obj/item/ammo_magazine/speedloader/nullglass(src) - new /obj/item/gun/projectile/revolver/foundation(src) - make_exact_fit() diff --git a/mods/psionics/items/grabs.dm b/mods/psionics/items/grabs.dm deleted file mode 100644 index 76ab167ff5e9..000000000000 --- a/mods/psionics/items/grabs.dm +++ /dev/null @@ -1,6 +0,0 @@ -/obj/item/grab/attack(mob/M, mob/living/user) - if(ishuman(user) && affecting == M) - var/mob/living/carbon/human/H = user - if(H.check_psi_grab(src)) - return - . = ..() \ No newline at end of file diff --git a/mods/psionics/items/id_card.dm b/mods/psionics/items/id_card.dm deleted file mode 100644 index 70cd36563d8c..000000000000 --- a/mods/psionics/items/id_card.dm +++ /dev/null @@ -1,42 +0,0 @@ -/obj/item/card/id/foundation_civilian - name = "operant registration card" - desc = "A registration card in a faux-leather case. It marks the named individual as a registered, law-abiding psionic." - icon = 'icons/obj/id/id_warrantcard_civ.dmi' - detail_color = null - -/obj/item/card/id/foundation_civilian/on_update_icon() - return - -/obj/item/card/id/foundation - name = "\improper Foundation warrant card" - desc = "A warrant card in a handsome leather case." - assignment = "Field Agent" - icon = 'icons/obj/id/id_warrantcard.dmi' - detail_color = null - -/obj/item/card/id/foundation/examine(mob/user, distance) - . = ..() - if(distance <= 1 && isliving(user)) - var/mob/living/M = user - if(M.psi) - to_chat(user, SPAN_WARNING("There is a psionic compulsion surrounding \the [src], forcing anyone who reads it to perceive it as a legitimate document of authority. The actual text just reads 'I can do what I want.'")) - else - to_chat(user, SPAN_NOTICE("This is the real deal, stamped by [GLOB.using_map.boss_name]. It gives the holder the full authority to pursue their goals. You believe it implicitly.")) - -/obj/item/card/id/foundation/attack_self(var/mob/living/user) - . = ..() - if(istype(user)) - for(var/mob/M in viewers(world.view, get_turf(user))-user) - if(user.psi && isliving(M)) - var/mob/living/L = M - if(!L.psi) - to_chat(L, SPAN_NOTICE("This is the real deal, stamped by [GLOB.using_map.boss_name]. It gives the holder the full authority to pursue their goals. You believe \the [user] implicitly.")) - continue - to_chat(M, SPAN_WARNING("There is a psionic compulsion surrounding \the [src] in a flicker of indescribable light.")) - -/obj/item/card/id/foundation/on_update_icon() - return - -/obj/item/card/id/foundation/Initialize() - . = ..() - access |= get_all_station_access() diff --git a/mods/psionics/items/implant.dm b/mods/psionics/items/implant.dm deleted file mode 100644 index b538f45d76bd..000000000000 --- a/mods/psionics/items/implant.dm +++ /dev/null @@ -1,108 +0,0 @@ -/obj/item/implant/psi_control - name = "psi dampener implant" - desc = "A safety implant for registered psi-operants." - known = TRUE - - var/overload = 0 - var/max_overload = 100 - var/psi_mode = PSI_IMPLANT_AUTOMATIC - -/obj/item/implant/psi_control/islegal() - return TRUE - -/obj/item/implant/psi_control/Initialize() - . = ..() - SSpsi.psi_dampeners += src - -/obj/item/implant/psi_control/Destroy() - SSpsi.psi_dampeners -= src - . = ..() - -/obj/item/implant/psi_control/emp_act() - . = ..() - update_functionality() - -/obj/item/implant/psi_control/meltdown() - . = ..() - update_functionality() - -/obj/item/implant/psi_control/disrupts_psionics() - var/use_psi_mode = get_psi_mode() - return (!malfunction && (use_psi_mode == PSI_IMPLANT_SHOCK || use_psi_mode == PSI_IMPLANT_WARN)) ? src : FALSE - -/obj/item/implant/psi_control/removed() - var/mob/living/M = imp_in - if(disrupts_psionics() && istype(M) && M.psi) - to_chat(M, SPAN_NOTICE("You feel the chilly shackles around your psionic faculties fade away.")) - . = ..() - -/obj/item/implant/psi_control/proc/update_functionality(var/silent) - var/mob/living/M = imp_in - if(get_psi_mode() == PSI_IMPLANT_DISABLED || malfunction) - if(implanted && !silent && istype(M) && M.psi) - to_chat(M, SPAN_NOTICE("You feel the chilly shackles around your psionic faculties fade away.")) - else - if(implanted && !silent && istype(M) && M.psi) - to_chat(M, SPAN_NOTICE("Bands of hollow ice close themselves around your psionic faculties.")) - -/obj/item/implant/psi_control/meltdown() - if(!malfunction) - overload = 100 - if(imp_in) - for(var/thing in SSpsi.psi_monitors) - var/obj/machinery/psi_monitor/monitor = thing - monitor.report_failure(src) - . = ..() - -/obj/item/implant/psi_control/proc/get_psi_mode() - if(psi_mode == PSI_IMPLANT_AUTOMATIC) - var/decl/security_state/security_state = decls_repository.get_decl(GLOB.using_map.security_state) - return security_state.current_security_level.psionic_control_level - return psi_mode - -/obj/item/implant/psi_control/withstand_psi_stress(var/stress, var/atom/source) - - var/use_psi_mode = get_psi_mode() - - if(malfunction || use_psi_mode == PSI_IMPLANT_DISABLED) - return stress - - . = 0 - - if(stress > 0) - - // If we're disrupting psionic attempts at the moment, we might overload. - if(disrupts_psionics()) - var/overload_amount = Floor(stress/10) - if(overload_amount > 0) - overload += overload_amount - if(overload >= 100) - if(imp_in) - to_chat(imp_in, SPAN_DANGER("Your psi dampener overloads violently!")) - meltdown() - update_functionality() - return - if(imp_in) - if(overload >= 75 && overload < 100) - to_chat(imp_in, SPAN_DANGER("Your psi dampener is searing hot!")) - else if(overload >= 50 && overload < 75) - to_chat(imp_in, SPAN_WARNING("Your psi dampener is uncomfortably hot...")) - else if(overload >= 25 && overload < 50) - to_chat(imp_in, SPAN_WARNING("You feel your psi dampener heating up...")) - - // If all we're doing is logging the incident then just pass back stress without changing it. - if(source && source == imp_in && implanted) - for(var/thing in SSpsi.psi_monitors) - var/obj/machinery/psi_monitor/monitor = thing - monitor.report_violation(src, stress) - if(use_psi_mode == PSI_IMPLANT_LOG) - return stress - else if(use_psi_mode == PSI_IMPLANT_SHOCK) - to_chat(imp_in, SPAN_DANGER("Your psi dampener punishes you with a violent neural shock!")) - imp_in.flash_eyes() - imp_in.Weaken(5) - if(isliving(imp_in)) - var/mob/living/M = imp_in - if(M.psi) M.psi.stunned(5) - else if(use_psi_mode == PSI_IMPLANT_WARN) - to_chat(imp_in, SPAN_WARNING("Your psi dampener primly informs you it has reported this violation.")) diff --git a/mods/psionics/items/literature.dm b/mods/psionics/items/literature.dm deleted file mode 100644 index 94befe6938d9..000000000000 --- a/mods/psionics/items/literature.dm +++ /dev/null @@ -1,29 +0,0 @@ -/obj/item/book/manual/psionics - name = "Psychonetics" - icon_state = "foundation" - author = "John Titor" - title = "Psychonetics" - - dat = {" - - - - -

    Psychonetics

    - -

    This seems to be a dry, longwinded reference text for the form of strange mental powers called psionics. The author spends way too much time trying to advertise his cult, though.

    - -

    The general gist of things seems to be that sometime in the last decade or so, the first cases of 'spontaneous operancy' became known. People who spent a lot of time in deep space, or who studied certain esoteric fields of mathematics, became able to perform strange feats like levitating coins or removing headaches with nothing but their minds. The text goes on to explain that psionics are perfectly harmless, and that studies (no citations) have shown operants are no more likely to go mad and murder people than anyone else.

    - -

    A postscript by a group called the Cuchulain Foundation invites anyone who knows an operant, or thinks they might be one, to send them a message via comms and get enrolled in their training and registration program in orbit around Neptune. It's catered. The postscript adds hastily that you should never try to activate your own latencies with trauma or drugs, as the results are often lethal.

    - - - - "} diff --git a/mods/psionics/items/soulstone.dm b/mods/psionics/items/soulstone.dm deleted file mode 100644 index 610d6632b936..000000000000 --- a/mods/psionics/items/soulstone.dm +++ /dev/null @@ -1,13 +0,0 @@ -/obj/item/soulstone/disrupts_psionics() - . = !full ? src : FALSE - -/obj/item/soulstone/shatter() - for(var/i=1 to rand(2,5)) - new /obj/item/shard(get_turf(src), MAT_NULLGLASS) - . = ..() - -/obj/item/soulstone/withstand_psi_stress(var/stress, var/atom/source) - . = ..(stress, source) - if(. > 0) - . = max(0, . - rand(2,5)) - shatter() diff --git a/mods/psionics/machines/psimeter.dm b/mods/psionics/machines/psimeter.dm deleted file mode 100644 index fcb944dcc252..000000000000 --- a/mods/psionics/machines/psimeter.dm +++ /dev/null @@ -1,71 +0,0 @@ -/obj/machinery/psi_meter - name = "psi-meter" - desc = "A bulky psi-meter for conducting assays of psi-operants." - icon = 'mods/psionics/icons/psimeter.dmi' - icon_state = "meter_on" - use_power = POWER_USE_ACTIVE - anchored = TRUE - density = TRUE - opacity = FALSE - - var/list/last_assay - var/mob/living/last_assayed - -/obj/machinery/psi_meter/on_update_icon() - if(use_power && !(stat & (NOPOWER|BROKEN))) - icon_state = "meter_on" - else - icon_state = "meter_off" - -/obj/machinery/psi_meter/interface_interact(var/mob/user) - interact(user) - return TRUE - -/obj/machinery/psi_meter/interact(var/mob/user) - - if(!use_power) return - - var/list/dat = list() - if(LAZYLEN(last_assay)) - dat = last_assay - else - dat += "

    TELESTO Mark I Psi-Meter


    " - var/found - for(var/mob/living/H in range(1, src)) - found = TRUE - dat += "" - dat += "
    Candidates
    [H.name]Conduct Assay" - if(!found) - dat += "
    No candidates found.
    " - - var/datum/browser/written/popup = new(user, "psi_assay_\ref[src]", "Psi-Assay") - popup.set_content(jointext(dat,null)) - popup.open() - -/obj/machinery/psi_meter/Topic(href, href_list) - . = ..() - if(!.) - - if(!issilicon(usr) && !Adjacent(usr)) - return FALSE - - var/refresh - if(href_list["print"]) - if(last_assay) - var/obj/item/paper/P = new(loc) - P.name = "paper - Psi-Assay ([last_assayed.name])" - P.info = jointext(last_assay - last_assay[last_assay.len],null) // Last line is 'print | clear' link line. - return TRUE - - if(href_list["clear"]) - last_assay = null - refresh = TRUE - else if(href_list["assay"]) - last_assayed = locate(href_list["assay"]) - if(istype(last_assayed)) - last_assayed.show_psi_assay(usr, src) - refresh = TRUE - - if(refresh) - interact(usr) - return TRUE diff --git a/mods/psionics/machines/psimonitor.dm b/mods/psionics/machines/psimonitor.dm deleted file mode 100644 index 4480a368520c..000000000000 --- a/mods/psionics/machines/psimonitor.dm +++ /dev/null @@ -1,117 +0,0 @@ -/obj/machinery/psi_monitor - name = "psionic implant monitor" - icon = 'mods/psionics/icons/psimeter.dmi' - icon_state = "meter_on" - use_power = POWER_USE_ACTIVE - anchored = TRUE - density = TRUE - opacity = FALSE - initial_access = list(list(access_psychiatrist, access_captain, access_cmo, access_hos)) - - var/list/psi_violations = list() - var/show_violations = FALSE - var/authorized - -/obj/machinery/psi_monitor/Initialize() - . = ..() - SSpsi.psi_monitors += src - -/obj/machinery/psi_monitor/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) - emagged = TRUE - remaining_charges-- - req_access.Cut() - to_chat(user, "You short out the access protocols.") - return TRUE - return FALSE - -/obj/machinery/psi_monitor/Topic(href, href_list) - - . = ..() - if(!.) - - if(href_list["login"]) - - var/obj/item/card/id/ID = usr.GetIdCard() - if(!ID || !allowed(usr)) - to_chat(usr, "Access denied.") - else - authorized = "[ID.registered_name] ([ID.assignment])" - . = 1 - - else if(href_list["logout"]) - authorized = FALSE - . = 1 - - else if(href_list["show_violations"]) - show_violations = (href_list["show_violations"] == "1") - . = 1 - - else if(href_list["remove_violation"]) - var/remove_ind = text2num(href_list["remove_violation"]) - if(remove_ind > 0 && remove_ind <= psi_violations.len) - psi_violations.Cut(remove_ind, remove_ind++) - . = 1 - - else if(href_list["change_mode"]) - var/obj/item/implant/psi_control/implant = locate(href_list["change_mode"]) - if(implant.imp_in && !implant.malfunction) - var/choice = input("Select a new implant mode.", "Psi Dampener") as null|anything in list(PSI_IMPLANT_AUTOMATIC, PSI_IMPLANT_SHOCK, PSI_IMPLANT_WARN, PSI_IMPLANT_LOG, PSI_IMPLANT_DISABLED) - if(choice && implant && implant.imp_in && !implant.malfunction) - implant.psi_mode = choice - implant.update_functionality() - . = 1 - - if(. && usr) - interact(usr) - -/obj/machinery/psi_monitor/interface_interact(var/mob/user) - interact(user) - return TRUE - -/obj/machinery/psi_monitor/interact(var/mob/user) - - var/list/dat = list() - dat += "

    Psi Dampener Monitor

    " - if(authorized) - dat += "[authorized]Logout" - else - dat += "Login" - - dat += "

    Active Psionic Dampeners


    " - dat += "
    " - dat += "" - for(var/thing in SSpsi.psi_dampeners) - var/obj/item/implant/psi_control/implant = thing - if(!implant.imp_in) - continue - dat += "" - if(implant.malfunction) - dat += "" - else - dat += "" - dat += "" - dat += "
    OperantSystem loadMode
    [implant.imp_in.name]ERRORERROR[implant.overload]%[authorized ? "[implant.psi_mode]" : "[implant.psi_mode]"]

    " - - if(show_violations) - dat += "

    Psionic Control Violations -


    " - if(psi_violations.len) - for(var/i = 1 to psi_violations.len) - var/entry = psi_violations[i] - dat += "" - else - dat += "" - dat += "

    [entry]
    [authorized ? "Remove" : ""]
    None reported.

    " - else - dat += "

    Psionic Control Violations +


    " - - var/datum/browser/written/popup = new(user, "psi_monitor_\ref[src]", "Psi-Monitor") - popup.set_content(jointext(dat,null)) - popup.open() - - -/obj/machinery/psi_monitor/proc/report_failure(var/obj/item/implant/psi_control/implant) - psi_violations += "Critical system failure - [implant.imp_in.name]." - -/obj/machinery/psi_monitor/proc/report_violation(var/obj/item/implant/psi_control/implant, var/stress) - psi_violations += "Sigma [round(stress/10)] event - [implant.imp_in.name]." \ No newline at end of file diff --git a/mods/psionics/system/psionics/complexus/complexus_helpers.dm b/mods/psionics/system/psionics/complexus/complexus_helpers.dm deleted file mode 100644 index a09d4e9aebe0..000000000000 --- a/mods/psionics/system/psionics/complexus/complexus_helpers.dm +++ /dev/null @@ -1,103 +0,0 @@ -/datum/psi_complexus/proc/cancel() - sound_to(owner, sound('sound/effects/psi/power_fail.ogg')) - if(LAZYLEN(manifested_items)) - for(var/thing in manifested_items) - owner.drop_from_inventory(thing) - qdel(thing) - manifested_items = null - -/datum/psi_complexus/proc/stunned(var/amount) - var/old_stun = stun - stun = max(stun, amount) - if(amount && !old_stun) - to_chat(owner, "Your concentration has been shattered! You cannot focus your psi power!") - ui.update_icon() - cancel() - -/datum/psi_complexus/proc/get_armour(var/armourtype) - if(can_use_passive()) - last_armor_check = world.time - return round(Clamp(Clamp(4 * rating, 0, 20) * get_rank(SSpsi.armour_faculty_by_type[armourtype]), 0, 100) * (stamina/max_stamina)) - else - last_armor_check = 0 - return 0 - -/datum/psi_complexus/proc/get_rank(var/faculty) - return LAZYACCESS(ranks, faculty) - -/datum/psi_complexus/proc/set_rank(var/faculty, var/rank, var/defer_update, var/temporary) - if(get_rank(faculty) != rank) - LAZYSET(ranks, faculty, rank) - if(!temporary) - LAZYSET(base_ranks, faculty, rank) - if(!defer_update) - update() - -/datum/psi_complexus/proc/set_cooldown(var/value) - next_power_use = world.time + value - ui.update_icon() - -/datum/psi_complexus/proc/can_use_passive() - return (owner.stat == CONSCIOUS && !suppressed && !stun) - -/datum/psi_complexus/proc/can_use(var/incapacitation_flags) - return (owner.stat == CONSCIOUS && (!incapacitation_flags || !owner.incapacitated(incapacitation_flags)) && !suppressed && !stun && world.time >= next_power_use) - -/datum/psi_complexus/proc/spend_power(var/value = 0, var/check_incapacitated) - . = FALSE - if(isnull(check_incapacitated)) - check_incapacitated = (INCAPACITATION_STUNNED|INCAPACITATION_KNOCKOUT) - if(can_use(check_incapacitated)) - value = max(1, ceil(value * cost_modifier)) - if(value <= stamina) - stamina -= value - ui.update_icon() - . = TRUE - else - backblast(abs(stamina - value)) - stamina = 0 - . = FALSE - ui.update_icon() - -/datum/psi_complexus/proc/hide_auras() - if(owner.client) - for(var/thing in SSpsi.all_aura_images) - owner.client.images -= thing - -/datum/psi_complexus/proc/show_auras() - if(owner.client) - for(var/image/I in SSpsi.all_aura_images) - owner.client.images |= I - -/datum/psi_complexus/proc/backblast(var/value) - - // Can't backblast if you're controlling your power. - if(!owner || suppressed) - return FALSE - - sound_to(owner, sound('sound/effects/psi/power_feedback.ogg')) - to_chat(owner, "Wild energistic feedback blasts across your psyche!") - stunned(value * 2) - set_cooldown(value * 100) - - if(prob(value*10)) owner.emote("scream") - - // Your head asplode. - owner.adjustBrainLoss(value) - if(ishuman(owner)) - var/mob/living/carbon/human/pop = owner - if(pop.should_have_organ(BP_BRAIN)) - var/obj/item/organ/internal/brain/sponge = pop.internal_organs_by_name[BP_BRAIN] - if(sponge && sponge.damage >= sponge.max_damage) - var/obj/item/organ/external/affecting = pop.get_organ(sponge.parent_organ) - if(affecting && !affecting.is_stump()) - affecting.droplimb(0, DROPLIMB_BLUNT) - if(sponge) qdel(sponge) - -/datum/psi_complexus/proc/reset() - aura_color = initial(aura_color) - ranks = base_ranks ? base_ranks.Copy() : null - max_stamina = initial(max_stamina) - stamina = min(stamina, max_stamina) - cancel() - update() diff --git a/mods/psionics/system/psionics/complexus/complexus_latency.dm b/mods/psionics/system/psionics/complexus/complexus_latency.dm deleted file mode 100644 index 482c3c2d05de..000000000000 --- a/mods/psionics/system/psionics/complexus/complexus_latency.dm +++ /dev/null @@ -1,17 +0,0 @@ -/datum/psi_complexus/proc/check_latency_trigger(var/trigger_strength = 0, var/source, var/redactive = FALSE) - - if(!LAZYLEN(latencies) || world.time < next_latency_trigger) - return FALSE - - if(!prob(trigger_strength)) - next_latency_trigger = world.time + rand(100, 300) - return FALSE - - var/faculty = pick(latencies) - var/new_rank = rand(2,5) - owner.set_psi_rank(faculty, new_rank) - var/decl/psionic_faculty/faculty_decl = SSpsi.get_faculty(faculty) - to_chat(owner, SPAN_DANGER("You scream internally as your [faculty_decl.name] faculty is forced into operancy by [source]!")) - next_latency_trigger = world.time + rand(600, 1800) * new_rank - if(!redactive) owner.adjustBrainLoss(rand(trigger_strength * 2, trigger_strength * 4)) - return TRUE diff --git a/mods/psionics/system/psionics/complexus/complexus_process.dm b/mods/psionics/system/psionics/complexus/complexus_process.dm deleted file mode 100644 index cec45c7fd005..000000000000 --- a/mods/psionics/system/psionics/complexus/complexus_process.dm +++ /dev/null @@ -1,241 +0,0 @@ -/datum/psi_complexus/proc/update(var/force) - - set waitfor = FALSE - - var/last_rating = rating - var/highest_faculty - var/highest_rank = 0 - var/combined_rank = 0 - for(var/faculty in ranks) - var/check_rank = get_rank(faculty) - if(check_rank == 1) - LAZYADD(latencies, faculty) - else - if(check_rank <= 0) - ranks -= faculty - LAZYREMOVE(latencies, faculty) - combined_rank += check_rank - if(!highest_faculty || highest_rank < check_rank) - highest_faculty = faculty - highest_rank = check_rank - - UNSETEMPTY(latencies) - var/rank_count = max(1, LAZYLEN(ranks)) - if(force || last_rating != ceil(combined_rank/rank_count)) - if(highest_rank <= 1) - if(highest_rank == 0) - qdel(src) - return - else - rebuild_power_cache = TRUE - sound_to(owner, 'sound/effects/psi/power_unlock.ogg') - rating = ceil(combined_rank/rank_count) - cost_modifier = 1 - if(rating > 1) - cost_modifier -= min(1, max(0.1, (rating-1) / 10)) - if(!ui) - ui = new(owner) - if(owner.client) - owner.client.screen += ui.components - owner.client.screen += ui - else - if(owner.client) - owner.client.screen |= ui.components - owner.client.screen |= ui - if(!suppressed && owner.client) - for(var/thing in SSpsi.all_aura_images) - owner.client.images |= thing - - var/image/aura_image = get_aura_image() - if(rating >= PSI_RANK_PARAMOUNT) // spooky boosters - aura_color = "#aaffaa" - aura_image.blend_mode = BLEND_SUBTRACT - else - aura_image.blend_mode = BLEND_ADD - if(highest_faculty == PSI_COERCION) - aura_color = "#cc3333" - else if(highest_faculty == PSI_PSYCHOKINESIS) - aura_color = "#3333cc" - else if(highest_faculty == PSI_REDACTION) - aura_color = "#33cc33" - else if(highest_faculty == PSI_ENERGISTICS) - aura_color = "#cccc33" - aura_image.pixel_x = -64 - owner.default_pixel_x - aura_image.pixel_y = -64 - owner.default_pixel_y - - if(!announced && owner && owner.client && !QDELETED(src)) - announced = TRUE - to_chat(owner, "
    ") - to_chat(owner, SPAN_NOTICE("You are psionic, touched by powers beyond understanding.")) - to_chat(owner, SPAN_NOTICE("Shift-left-click your Psi icon on the bottom right to view a summary of how to use them, or left click it to suppress or unsuppress your psionics. Beware: overusing your gifts can have deadly consequences.")) - to_chat(owner, "
    ") - -/datum/psi_complexus/Process() - - var/update_hud - if(stun) - stun-- - if(stun) - if(!suppressed) - suppressed = TRUE - update_hud = TRUE - else - to_chat(owner, SPAN_NOTICE("You have recovered your mental composure.")) - update_hud = TRUE - return - - var/psi_leech = owner.do_psionics_check() - if(psi_leech) - if(stamina > 10) - stamina = max(0, stamina - rand(15,20)) - to_chat(owner, SPAN_DANGER("You feel your psi-power leeched away by \the [psi_leech]...")) - else - stamina++ - return - - else if(stamina < max_stamina) - if(owner.stat == CONSCIOUS) - stamina = min(max_stamina, stamina + rand(1,3)) - else if(owner.stat == UNCONSCIOUS) - stamina = min(max_stamina, stamina + rand(3,5)) - - if(!owner.nervous_system_failure() && owner.stat == CONSCIOUS && stamina && !suppressed && get_rank(PSI_REDACTION) >= PSI_RANK_OPERANT) - attempt_regeneration() - - var/next_aura_size = max(0.1,((stamina/max_stamina)*min(3,rating))/5) - var/next_aura_alpha = round(((suppressed ? max(0,rating - 2) : rating)/5)*255) - - if(next_aura_alpha != last_aura_alpha || next_aura_size != last_aura_size || aura_color != last_aura_color) - last_aura_size = next_aura_size - last_aura_alpha = next_aura_alpha - last_aura_color = aura_color - var/matrix/M = matrix() - if(next_aura_size != 1) - M.Scale(next_aura_size) - animate(get_aura_image(), alpha = next_aura_alpha, transform = M, color = aura_color, time = 3) - - if(update_hud) - ui.update_icon() - -/datum/psi_complexus/proc/attempt_regeneration() - - var/heal_general = FALSE - var/heal_poison = FALSE - var/heal_internal = FALSE - var/heal_bleeding = FALSE - var/heal_rate = 0 - var/mend_prob = 0 - - var/use_rank = get_rank(PSI_REDACTION) - if(use_rank >= PSI_RANK_PARAMOUNT) - heal_general = TRUE - heal_poison = TRUE - heal_internal = TRUE - heal_bleeding = TRUE - mend_prob = 50 - heal_rate = 7 - else if(use_rank == PSI_RANK_GRANDMASTER) - heal_poison = TRUE - heal_internal = TRUE - heal_bleeding = TRUE - mend_prob = 20 - heal_rate = 5 - else if(use_rank == PSI_RANK_MASTER) - heal_internal = TRUE - heal_bleeding = TRUE - mend_prob = 10 - heal_rate = 3 - else if(use_rank == PSI_RANK_OPERANT) - heal_bleeding = TRUE - mend_prob = 5 - heal_rate = 1 - else - return - - if(!heal_rate || stamina < heal_rate) - return // Don't backblast from trying to heal ourselves thanks. - - if(ishuman(owner)) - - var/mob/living/carbon/human/H = owner - - // Fix some pain. - if(heal_rate > 0) - H.shock_stage = max(0, H.shock_stage - max(1, round(heal_rate/2))) - - // Mend internal damage. - if(prob(mend_prob)) - - // Fix our heart if we're paramount. - if(heal_general && H.is_asystole() && H.should_have_organ(BP_HEART) && spend_power(heal_rate)) - H.resuscitate() - - // Heal organ damage. - if(heal_internal) - for(var/obj/item/organ/I in H.internal_organs) - - if(BP_IS_PROSTHETIC(I) || BP_IS_CRYSTAL(I)) - continue - - if(I.damage > 0 && spend_power(heal_rate)) - I.damage = max(I.damage - heal_rate, 0) - if(prob(25)) - to_chat(H, SPAN_NOTICE("Your innards itch as your autoredactive faculty mends your [I.name].")) - return - - // Heal broken bones. - if(H.bad_external_organs.len) - for(var/obj/item/organ/external/E in H.bad_external_organs) - - if(BP_IS_PROSTHETIC(E)) - continue - - if(heal_internal && (E.status & ORGAN_BROKEN) && E.damage < (E.min_broken_damage * config.organ_health_multiplier)) // So we don't mend and autobreak. - if(spend_power(heal_rate)) - if(E.mend_fracture()) - to_chat(H, SPAN_NOTICE("Your autoredactive faculty coaxes together the shattered bones in your [E.name].")) - return - - if(heal_bleeding) - - if((E.status & ORGAN_ARTERY_CUT) && spend_power(heal_rate)) - to_chat(H, SPAN_NOTICE("Your autoredactive faculty mends the torn artery in your [E.name], stemming the worst of the bleeding.")) - E.status &= ~ORGAN_ARTERY_CUT - return - - if(E.status & ORGAN_TENDON_CUT) - to_chat(H, SPAN_NOTICE("Your autoredactive faculty repairs the severed tendon in your [E.name].")) - E.status &= ~ORGAN_TENDON_CUT - return TRUE - - for(var/datum/wound/W in E.wounds) - - if(W.bleeding() && spend_power(heal_rate)) - to_chat(H, SPAN_NOTICE("Your autoredactive faculty knits together severed veins, stemming the bleeding from \a [W.desc] on your [E.name].")) - W.bleed_timer = 0 - W.clamped = TRUE - E.status &= ~ORGAN_BLEEDING - return - - // Heal radiation, cloneloss and poisoning. - if(heal_poison) - - if(owner.radiation && spend_power(heal_rate)) - if(prob(25)) - to_chat(owner, SPAN_NOTICE("Your autoredactive faculty repairs some of the radiation damage to your body.")) - owner.radiation = max(0, owner.radiation - heal_rate) - return - - if(owner.getCloneLoss() && spend_power(heal_rate)) - if(prob(25)) - to_chat(owner, SPAN_NOTICE("Your autoredactive faculty stitches together some of your mangled DNA.")) - owner.adjustCloneLoss(-heal_rate) - return - - // Heal everything left. - if(heal_general && prob(mend_prob) && (owner.getBruteLoss() || owner.getFireLoss() || owner.getOxyLoss()) && spend_power(heal_rate)) - owner.adjustBruteLoss(-(heal_rate)) - owner.adjustFireLoss(-(heal_rate)) - owner.adjustOxyLoss(-(heal_rate)) - if(prob(25)) - to_chat(owner, SPAN_NOTICE("Your skin crawls as your autoredactive faculty heals your body.")) diff --git a/mods/psionics/system/psionics/complexus/complexus_topic.dm b/mods/psionics/system/psionics/complexus/complexus_topic.dm deleted file mode 100644 index 8dc522423adb..000000000000 --- a/mods/psionics/system/psionics/complexus/complexus_topic.dm +++ /dev/null @@ -1,20 +0,0 @@ -/datum/psi_complexus/CanUseTopic(var/mob/user, var/datum/topic_state/state = GLOB.default_state) - return (user.client && check_rights(R_ADMIN, FALSE, user.client)) - -/datum/psi_complexus/Topic(var/href, var/list/href_list) - . = ..() - if(!. && check_rights(R_ADMIN)) - if(href_list["remove_psionics"]) - if(owner && owner.psi && owner.psi == src && !QDELETED(src)) - log_and_message_admins("removed all psionics from [key_name(owner)].") - to_chat(owner, SPAN_NOTICE("Your psionic powers vanish abruptly, leaving you cold and empty.")) - QDEL_NULL(owner.psi) - . = TRUE - if(href_list["trigger_psi_latencies"]) - log_and_message_admins("triggered psi latencies for [key_name(owner)].") - check_latency_trigger(100, "outside intervention", redactive = TRUE) - . = TRUE - if(.) - var/datum/admins/admin = GLOB.admins[usr.key] - if(istype(admin)) - admin.show_player_panel(owner) \ No newline at end of file diff --git a/mods/psionics/system/psionics/equipment/psipower.dm b/mods/psionics/system/psionics/equipment/psipower.dm deleted file mode 100644 index 33ac4b438582..000000000000 --- a/mods/psionics/system/psionics/equipment/psipower.dm +++ /dev/null @@ -1,62 +0,0 @@ -/obj/item/psychic_power - name = "psychic power" - icon = 'mods/psionics/icons/psychic_powers.dmi' - atom_flags = 0 - simulated = 1 - anchored = 1 - var/maintain_cost = 3 - var/mob/living/owner - -/obj/item/psychic_power/Initialize() - owner = loc - if(!istype(owner)) - return INITIALIZE_HINT_QDEL - START_PROCESSING(SSprocessing, src) - return ..() - -/obj/item/psychic_power/Destroy() - if(istype(owner) && owner.psi) - LAZYREMOVE(owner.psi.manifested_items, src) - UNSETEMPTY(owner.psi.manifested_items) - STOP_PROCESSING(SSprocessing, src) - . = ..() - -/obj/item/psychic_power/get_storage_cost() - return ITEM_SIZE_NO_CONTAINER - -/obj/item/psychic_power/attack_self(var/mob/user) - sound_to(owner, 'sound/effects/psi/power_fail.ogg') - user.drop_from_inventory(src) - -/obj/item/psychic_power/attack(var/mob/living/M, var/mob/living/user, var/target_zone) - if(M.do_psionics_check(max(force, maintain_cost), user)) - to_chat(user, "\The [src] flickers violently out of phase!") - return 1 - . = ..() - -/obj/item/psychic_power/afterattack(var/atom/target, var/mob/living/user, var/proximity) - if(target.do_psionics_check(max(force, maintain_cost), user)) - to_chat(user, "\The [src] flickers violently out of phase!") - return - . = ..(target, user, proximity) - -/obj/item/psychic_power/dropped() - ..() - qdel(src) - -/obj/item/psychic_power/Process() - if(istype(owner)) - owner.psi.spend_power(maintain_cost) - if(!owner || owner.do_psionics_check(maintain_cost, owner) || loc != owner || (owner.l_hand != src && owner.r_hand != src)) - if(istype(loc,/mob/living)) - var/mob/living/carbon/human/host = loc - if(istype(host)) - for(var/obj/item/organ/external/organ in host.organs) - for(var/obj/item/O in organ.implants) - if(O == src) - organ.implants -= src - host.pinned -= src - host.embedded -= src - host.drop_from_inventory(src) - else - qdel(src) diff --git a/mods/psionics/system/psionics/equipment/psipower_blade.dm b/mods/psionics/system/psionics/equipment/psipower_blade.dm deleted file mode 100644 index e89c668a4a24..000000000000 --- a/mods/psionics/system/psionics/equipment/psipower_blade.dm +++ /dev/null @@ -1,27 +0,0 @@ -/obj/item/psychic_power/psiblade - name = "psychokinetic slash" - force = 10 - sharp = 1 - edge = 1 - maintain_cost = 1 - icon_state = "psiblade_short" - -/obj/item/psychic_power/psiblade/master - force = 20 - maintain_cost = 2 - -/obj/item/psychic_power/psiblade/master/is_special_cutting_tool(var/high_power) - return !high_power - -/obj/item/psychic_power/psiblade/master/grand - force = 30 - maintain_cost = 3 - icon_state = "psiblade_long" - -/obj/item/psychic_power/psiblade/master/grand/paramount - force = 50 - maintain_cost = 4 - icon_state = "psiblade_long" - -/obj/item/psychic_power/psiblade/master/grand/paramount/is_special_cutting_tool(var/high_power) - return TRUE \ No newline at end of file diff --git a/mods/psionics/system/psionics/equipment/psipower_tinker.dm b/mods/psionics/system/psionics/equipment/psipower_tinker.dm deleted file mode 100644 index 4b62cf5c54a6..000000000000 --- a/mods/psionics/system/psionics/equipment/psipower_tinker.dm +++ /dev/null @@ -1,39 +0,0 @@ -/obj/item/psychic_power/tinker - name = "psychokinetic crowbar" - icon_state = "tinker" - force = 1 - var/emulating = "Crowbar" - -/obj/item/psychic_power/tinker/iscrowbar() - return emulating == "Crowbar" - -/obj/item/psychic_power/tinker/iswrench() - return emulating == "Wrench" - -/obj/item/psychic_power/tinker/isscrewdriver() - return emulating == "Screwdriver" - -/obj/item/psychic_power/tinker/iswirecutter() - return emulating == "Wirecutters" - -/obj/item/psychic_power/tinker/attack_self() - - if(!owner || loc != owner) - return - - var/choice = input("Select a tool to emulate.","Power") as null|anything in list("Crowbar","Wrench","Screwdriver","Wirecutters","Dismiss") - if(!choice) - return - - if(!owner || loc != owner) - return - - if(choice == "Dismiss") - sound_to(owner, 'sound/effects/psi/power_fail.ogg') - owner.drop_from_inventory(src) - return - - emulating = choice - name = "psychokinetic [lowertext(emulating)]" - to_chat(owner, "You begin emulating \a [lowertext(emulating)].") - sound_to(owner, 'sound/effects/psi/power_fabrication.ogg') diff --git a/mods/psionics/system/psionics/equipment/psipower_tk.dm b/mods/psionics/system/psionics/equipment/psipower_tk.dm deleted file mode 100644 index 622a55482e21..000000000000 --- a/mods/psionics/system/psionics/equipment/psipower_tk.dm +++ /dev/null @@ -1,105 +0,0 @@ -/obj/item/psychic_power/telekinesis - name = "telekinetic grip" - maintain_cost = 3 - icon_state = "telekinesis" - var/atom/movable/focus - -/obj/item/psychic_power/telekinesis/Destroy() - focus = null - . = ..() - -/obj/item/psychic_power/telekinesis/Process() - if(!focus || !istype(focus.loc, /turf) || get_dist(get_turf(focus), get_turf(owner)) > owner.psi.get_rank(PSI_PSYCHOKINESIS)) - owner.drop_from_inventory(src) - return - . = ..() - -/obj/item/psychic_power/telekinesis/proc/set_focus(var/atom/movable/_focus) - - if(!_focus.simulated || !istype(_focus.loc, /turf)) - return FALSE - - var/check_paramount - if(ismob(_focus)) - var/mob/victim = _focus - check_paramount = (victim.mob_size >= MOB_SIZE_MEDIUM) - else if(isobj(_focus)) - var/obj/thing = _focus - check_paramount = (thing.w_class >= ITEM_SIZE_HUGE) - else - return FALSE - - if(_focus.anchored || (check_paramount && owner.psi.get_rank(PSI_PSYCHOKINESIS) < PSI_RANK_PARAMOUNT)) - focus = _focus - . = attack_self(owner) - if(!.) - to_chat(owner, SPAN_WARNING("\The [_focus] is too hefty for you to get a mind-grip on.")) - qdel(src) - return FALSE - - focus = _focus - overlays.Cut() - var/image/I = image(icon = focus.icon, icon_state = focus.icon_state) - I.color = focus.color - I.overlays = focus.overlays - overlays += I - return TRUE - -/obj/item/psychic_power/telekinesis/attack_self(var/mob/user) - user.visible_message(SPAN_NOTICE("\The [user] makes a strange gesture.")) - sparkle() - return focus.do_simple_ranged_interaction(user) - -/obj/item/psychic_power/telekinesis/afterattack(var/atom/target, var/mob/living/user, var/proximity) - - if(!target || !user || (isobj(target) && !isturf(target.loc)) || !user.psi || !user.psi.can_use() || !user.psi.spend_power(5)) - return - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.psi.set_cooldown(5) - - var/user_psi_leech = user.do_psionics_check(5, user) - if(user_psi_leech) - to_chat(user, SPAN_WARNING("You reach for \the [target] but your telekinetic power is leeched away by \the [user_psi_leech]...")) - return - - if(target.do_psionics_check(5, user)) - to_chat(user, SPAN_WARNING("Your telekinetic power skates over \the [target] but cannot get a grip...")) - return - - var/distance = get_dist(get_turf(user), get_turf(focus ? focus : target)) - if(distance > user.psi.get_rank(PSI_PSYCHOKINESIS)) - to_chat(user, SPAN_WARNING("Your telekinetic power won't reach that far.")) - return FALSE - - if(target == focus) - attack_self(user) - else - user.visible_message(SPAN_DANGER("\The [user] gestures sharply!")) - sparkle() - if(!istype(target, /turf) && istype(focus,/obj/item) && target.Adjacent(focus)) - var/obj/item/I = focus - var/resolved = target.attackby(I, user, user:get_organ_target()) - if(!resolved && target && I) - I.afterattack(target,user,1) // for splashing with beakers - else - if(!focus.anchored) - var/user_rank = owner.psi.get_rank(PSI_PSYCHOKINESIS) - focus.throw_at(target, user_rank*2, user_rank*10, owner) - sleep(1) - sparkle() - -/obj/item/psychic_power/telekinesis/proc/sparkle() - set waitfor = 0 - if(focus) - var/obj/effect/overlay/O = new /obj/effect/overlay(get_turf(focus)) - O.name = "sparkles" - O.anchored = 1 - O.density = 0 - O.layer = FLY_LAYER - O.set_dir(pick(GLOB.cardinal)) - O.icon = 'icons/effects/effects.dmi' - O.icon_state = "nothing" - flick("empdisable",O) - sleep(5) - qdel(O) diff --git a/mods/psionics/system/psionics/events/mini_spasm.dm b/mods/psionics/system/psionics/events/mini_spasm.dm deleted file mode 100644 index 1dea17e6f176..000000000000 --- a/mods/psionics/system/psionics/events/mini_spasm.dm +++ /dev/null @@ -1,67 +0,0 @@ -/datum/event/minispasm - startWhen = 60 - endWhen = 90 - var/static/list/psi_operancy_messages = list( - "There's something in your skull!", - "Something is eating your thoughts!", - "You can feel your brain being rewritten!", - "Something is crawling over your frontal lobe!", - "THE SIGNAL THE SIGNAL THE SIGNAL THE SIGNAL THE" - ) - -/datum/event/minispasm/announce() - priority_announcement.Announce( \ - "PRIORITY ALERT: SIGMA-[rand(50,80)] PSIONIC SIGNAL LOCAL TRAMISSION DETECTED (97% MATCH, NONVARIANT) \ - (SIGNAL SOURCE TRIANGULATED ADJACENT LOCAL SITE): All personnel are advised to avoid \ - exposure to active audio transmission equipment including radio headsets and intercoms \ - for the duration of the signal broadcast.", \ - "Cuchulain Sensor Array Automated Message" \ - ) - -/datum/event/minispasm/start() - var/list/victims = list() - for(var/obj/item/radio/radio in GLOB.listening_objects) - if(radio.on) - for(var/mob/living/victim in range(radio.canhear_range, radio.loc)) - if(isnull(victims[victim]) && victim.stat == CONSCIOUS && !victim.ear_deaf) - victims[victim] = radio - for(var/thing in victims) - var/mob/living/victim = thing - var/obj/item/radio/source = victims[victim] - do_spasm(victim, source) - -/datum/event/minispasm/proc/do_spasm(var/mob/living/victim, var/obj/item/radio/source) - set waitfor = 0 - - if(iscarbon(victim) && !victim.isSynthetic()) - var/list/disabilities = list(NEARSIGHTED, EPILEPSY, TOURETTES, NERVOUS) - for(var/disability in disabilities) - if(victim.disabilities & disability) - disabilities -= disability - if(disabilities.len) - victim.disabilities |= pick(disabilities) - - if(victim.psi) - to_chat(victim, SPAN_DANGER("A hauntingly familiar sound hisses from \icon[source] \the [source], and your vision flickers!")) - victim.psi.backblast(rand(5,15)) - victim.Paralyse(5) - victim.make_jittery(100) - else - to_chat(victim, SPAN_DANGER("An indescribable, brain-tearing sound hisses from \icon[source] \the [source], and you collapse in a seizure!")) - victim.seizure() - var/new_latencies = rand(2,4) - var/list/faculties = list(PSI_COERCION, PSI_REDACTION, PSI_ENERGISTICS, PSI_PSYCHOKINESIS) - for(var/i = 1 to new_latencies) - to_chat(victim, SPAN_DANGER("[pick(psi_operancy_messages)]")) - victim.adjustBrainLoss(rand(10,20)) - victim.set_psi_rank(pick_n_take(faculties), 1) - sleep(30) - victim.psi.update() - sleep(45) - victim.psi.check_latency_trigger(100, "a psionic scream", redactive = TRUE) - -/datum/event/minispasm/end() - priority_announcement.Announce( \ - "PRIORITY ALERT: SIGNAL BROADCAST HAS CEASED. Personnel are cleared to resume use of non-hardened radio transmission equipment. Have a nice day.", \ - "Cuchulain Sensor Array Automated Message" \ - ) diff --git a/mods/psionics/system/psionics/faculties/_faculty.dm b/mods/psionics/system/psionics/faculties/_faculty.dm deleted file mode 100644 index ccc43528a4c8..000000000000 --- a/mods/psionics/system/psionics/faculties/_faculty.dm +++ /dev/null @@ -1,11 +0,0 @@ -/decl/psionic_faculty - var/id - var/name - var/associated_intent - var/list/armour_types = list() - var/list/powers = list() - -/decl/psionic_faculty/New() - ..() - for(var/atype in armour_types) - SSpsi.armour_faculty_by_type[atype] = id \ No newline at end of file diff --git a/mods/psionics/system/psionics/faculties/coercion.dm b/mods/psionics/system/psionics/faculties/coercion.dm deleted file mode 100644 index d7186dda0e33..000000000000 --- a/mods/psionics/system/psionics/faculties/coercion.dm +++ /dev/null @@ -1,224 +0,0 @@ -/decl/psionic_faculty/coercion - id = PSI_COERCION - name = "Coercion" - associated_intent = I_DISARM - armour_types = list(PSIONIC) - -/decl/psionic_power/coercion - faculty = PSI_COERCION - -/decl/psionic_power/coercion/invoke(var/mob/living/user, var/mob/living/target) - if (!istype(target)) - to_chat(user, SPAN_WARNING("You cannot mentally attack \the [target].")) - return FALSE - - . = ..() - if(. && target.deflect_psionic_attack(user)) - return FALSE - -/decl/psionic_power/coercion/blindstrike - name = "Blindstrike" - cost = 8 - cooldown = 120 - use_ranged = TRUE - use_melee = TRUE - min_rank = PSI_RANK_GRANDMASTER - use_description = "Target the eyes or mouth on disarm intent and click anywhere to use a radial attack that blinds, deafens and disorients everyone near you." - -/decl/psionic_power/coercion/blindstrike/invoke(var/mob/living/user, var/mob/living/target) - if(user.zone_sel.selecting != BP_MOUTH && user.zone_sel.selecting != BP_EYES) - return FALSE - . = ..() - if(.) - user.visible_message(SPAN_DANGER("\The [user] suddenly throws back their head, as though screaming silently!")) - to_chat(user, SPAN_DANGER("You strike at all around you with a deafening psionic scream!")) - for(var/mob/living/M in orange(user, user.psi.get_rank(PSI_COERCION))) - if(M == user) - continue - var/blocked = 100 * M.get_blocked_ratio(null, PSIONIC) - if(prob(blocked)) - to_chat(M, SPAN_DANGER("A psionic onslaught strikes your mind, but you withstand it!")) - continue - if(prob(60) && iscarbon(M)) - var/mob/living/carbon/C = M - if(C.can_feel_pain()) - M.emote("scream") - to_chat(M, SPAN_DANGER("Your senses are blasted into oblivion by a psionic scream!")) - M.flash_eyes() - M.eye_blind = max(M.eye_blind,3) - M.ear_deaf = max(M.ear_deaf,6) - M.confused = rand(3,8) - return TRUE - -/decl/psionic_power/coercion/mindread - name = "Read Mind" - cost = 6 - cooldown = 80 - use_melee = TRUE - min_rank = PSI_RANK_OPERANT - use_description = "Target the head on disarm intent at melee range to attempt to read a victim's surface thoughts." - -/decl/psionic_power/coercion/mindread/invoke(var/mob/living/user, var/mob/living/target) - if(!isliving(target) || !istype(target) || user.zone_sel.selecting != BP_HEAD) - return FALSE - . = ..() - if(!.) - return - - if(target.stat == DEAD || (target.status_flags & FAKEDEATH) || !target.client) - to_chat(user, SPAN_WARNING("\The [target] is in no state for a mind-ream.")) - return TRUE - - user.visible_message(SPAN_WARNING("\The [user] touches \the [target]'s temple...")) - var/question = input(user, "Say something?", "Read Mind", "Penny for your thoughts?") as null|text - if(!question || user.incapacitated() || !do_after(user, 20)) - return TRUE - - var/started_mindread = world.time - to_chat(user, SPAN_NOTICE("You dip your mentality into the surface layer of \the [target]'s mind, seeking an answer: [question]")) - to_chat(target, SPAN_NOTICE("Your mind is compelled to answer: [question]")) - - var/answer = input(target, question, "Read Mind") as null|text - if(!answer || world.time > started_mindread + 60 SECONDS || user.stat != CONSCIOUS || target.stat == DEAD) - to_chat(user, SPAN_NOTICE("You receive nothing useful from \the [target].")) - else - to_chat(user, SPAN_NOTICE("You skim thoughts from the surface of \the [target]'s mind: [answer]")) - msg_admin_attack("[key_name(user)] read mind of [key_name(target)] with question \"[question]\" and [answer?"got answer \"[answer]\".":"got no answer."]") - return TRUE - -/decl/psionic_power/coercion/agony - name = "Agony" - cost = 8 - cooldown = 50 - use_melee = TRUE - min_rank = PSI_RANK_MASTER - use_description = "Target the chest or groin on disarm intent to use a melee attack equivalent to a strike from a stun baton." - -/decl/psionic_power/coercion/agony/invoke(var/mob/living/user, var/mob/living/target) - if(!istype(target)) - return FALSE - if(user.zone_sel.selecting != BP_CHEST && user.zone_sel.selecting != BP_GROIN) - return FALSE - . = ..() - if(.) - user.visible_message("\The [target] has been struck by \the [user]!") - playsound(user.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - target.stun_effect_act(0, 60, user.zone_sel.selecting) - return TRUE - -/decl/psionic_power/coercion/spasm - name = "Spasm" - cost = 15 - cooldown = 100 - use_melee = TRUE - use_ranged = TRUE - min_rank = PSI_RANK_MASTER - use_description = "Target the arms or hands on disarm intent to use a ranged attack that may rip the weapons away from the target." - -/decl/psionic_power/coercion/spasm/invoke(var/mob/living/user, var/mob/living/carbon/human/target) - if(!istype(target)) - return FALSE - - if(!(user.zone_sel.selecting in list(BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND))) - return FALSE - - . = ..() - - if(.) - to_chat(user, "You lash out, stabbing into \the [target] with a lance of psi-power.") - to_chat(target, "The muscles in your arms cramp horrendously!") - if(prob(75)) - target.emote("scream") - if(prob(75) && target.l_hand && target.l_hand.simulated && target.unEquip(target.l_hand)) - target.visible_message("\The [target] drops what they were holding as their left hand spasms!") - if(prob(75) && target.r_hand && target.r_hand.simulated && target.unEquip(target.r_hand)) - target.visible_message("\The [target] drops what they were holding as their right hand spasms!") - return TRUE - -/decl/psionic_power/coercion/mindslave - name = "Mindslave" - cost = 28 - cooldown = 200 - use_grab = TRUE - min_rank = PSI_RANK_PARAMOUNT - use_description = "Grab a victim, target the eyes, then use the grab on them while on disarm intent, in order to convert them into a loyal mind-slave. The process takes some time, and failure is punished harshly." - -/decl/psionic_power/coercion/mindslave/invoke(var/mob/living/user, var/mob/living/target) - if(!istype(target) || user.zone_sel.selecting != BP_EYES) - return FALSE - . = ..() - if(.) - if(target.stat == DEAD || (target.status_flags & FAKEDEATH)) - to_chat(user, "\The [target] is dead!") - return TRUE - if(!target.mind || !target.key) - to_chat(user, "\The [target] is mindless!") - return TRUE - if(GLOB.thralls.is_antagonist(target.mind)) - to_chat(user, "\The [target] is already in thrall to someone!") - return TRUE - user.visible_message("\The [user] seizes the head of \the [target] in both hands...") - to_chat(user, "You plunge your mentality into that of \the [target]...") - to_chat(target, "Your mind is invaded by the presence of \the [user]! They are trying to make you a slave!") - if(!do_after(user, target.stat == CONSCIOUS ? 80 : 40, target, 0, 1)) - user.psi.backblast(rand(10,25)) - return TRUE - to_chat(user, "You sear through \the [target]'s neurons, reshaping as you see fit and leaving them subservient to your will!") - to_chat(target, "Your defenses have eroded away and \the [user] has made you their mindslave.") - GLOB.thralls.add_antagonist(target.mind, new_controller = user) - return TRUE - -/decl/psionic_power/coercion/assay - name = "Assay" - cost = 15 - cooldown = 100 - use_grab = TRUE - min_rank = PSI_RANK_OPERANT - use_description = "Grab a patient, target the head, then use the grab on them while on disarm intent, in order to perform a deep coercive-redactive probe of their psionic potential." - -/decl/psionic_power/coercion/assay/invoke(var/mob/living/user, var/mob/living/target) - if(user.zone_sel.selecting != BP_HEAD) - return FALSE - . = ..() - if(.) - user.visible_message(SPAN_WARNING("\The [user] holds the head of \the [target] in both hands...")) - to_chat(user, SPAN_NOTICE("You insinuate your mentality into that of \the [target]...")) - to_chat(target, SPAN_WARNING("Your persona is being probed by the psychic lens of \the [user].")) - if(!do_after(user, (target.stat == CONSCIOUS ? 50 : 25), target, 0, 1)) - user.psi.backblast(rand(5,10)) - return TRUE - to_chat(user, SPAN_NOTICE("You retreat from \the [target], holding your new knowledge close.")) - to_chat(target, SPAN_DANGER("Your mental complexus is laid bare to judgement of \the [user].")) - target.show_psi_assay(user) - return TRUE - -/decl/psionic_power/coercion/focus - name = "Focus" - cost = 10 - cooldown = 80 - use_grab = TRUE - min_rank = PSI_RANK_OPERANT - use_description = "Grab a patient, target the mouth, then use the grab on them while on disarm intent, in order to cure ailments of the mind." - -/decl/psionic_power/coercion/focus/invoke(var/mob/living/user, var/mob/living/target) - if(user.zone_sel.selecting != BP_MOUTH) - return FALSE - . = ..() - if(.) - user.visible_message(SPAN_WARNING("\The [user] holds the head of \the [target] in both hands...")) - to_chat(user, SPAN_NOTICE("You probe \the [target]'s mind for various ailments..")) - to_chat(target, SPAN_WARNING("Your mind is being cleansed of ailments by \the [user].")) - if(!do_after(user, (target.stat == CONSCIOUS ? 50 : 25), target, 0, 1)) - user.psi.backblast(rand(5,10)) - return TRUE - to_chat(user, SPAN_WARNING("You clear \the [target]'s mind of ailments.")) - to_chat(target, SPAN_WARNING("Your mind is cleared of ailments.")) - - var/coercion_rank = user.psi.get_rank(PSI_COERCION) - if(coercion_rank >= PSI_RANK_GRANDMASTER) - target.AdjustParalysis(-1) - target.drowsyness = 0 - if(istype(target, /mob/living/carbon)) - var/mob/living/carbon/M = target - M.adjust_hallucination(-30) - return TRUE \ No newline at end of file diff --git a/mods/psionics/system/psionics/faculties/psychokinesis.dm b/mods/psionics/system/psionics/faculties/psychokinesis.dm deleted file mode 100644 index 408d0ba2f959..000000000000 --- a/mods/psionics/system/psionics/faculties/psychokinesis.dm +++ /dev/null @@ -1,92 +0,0 @@ -/decl/psionic_faculty/psychokinesis - id = PSI_PSYCHOKINESIS - name = "Psychokinesis" - associated_intent = I_GRAB - armour_types = list("melee", "bullet") - -/decl/psionic_power/psychokinesis - faculty = PSI_PSYCHOKINESIS - use_manifest = TRUE - use_sound = null - -/decl/psionic_power/psychokinesis/psiblade - name = "Psiblade" - cost = 10 - cooldown = 30 - min_rank = PSI_RANK_OPERANT - use_description = "Click on or otherwise activate an empty hand while on harm intent to manifest a psychokinetic cutting blade. The power the blade will vary based on your mastery of the faculty." - admin_log = FALSE - -/decl/psionic_power/psychokinesis/psiblade/invoke(var/mob/living/user, var/mob/living/target) - if((target && user != target) || user.a_intent != I_HURT) - return FALSE - . = ..() - if(.) - switch(user.psi.get_rank(faculty)) - if(PSI_RANK_PARAMOUNT) - return new /obj/item/psychic_power/psiblade/master/grand/paramount(user, user) - if(PSI_RANK_GRANDMASTER) - return new /obj/item/psychic_power/psiblade/master/grand(user, user) - if(PSI_RANK_MASTER) - return new /obj/item/psychic_power/psiblade/master(user, user) - else - return new /obj/item/psychic_power/psiblade(user, user) - -/decl/psionic_power/psychokinesis/tinker - name = "Tinker" - cost = 5 - cooldown = 10 - min_rank = PSI_RANK_MASTER - use_description = "Click on or otherwise activate an empty hand while on help intent to manifest a psychokinetic tool. Use it in-hand to switch between tool types." - admin_log = FALSE - -/decl/psionic_power/psychokinesis/tinker/invoke(var/mob/living/user, var/mob/living/target) - if((target && user != target) || user.a_intent != I_HELP) - return FALSE - . = ..() - if(.) - return new /obj/item/psychic_power/tinker(user) - -/decl/psionic_power/psychokinesis/telekinesis - name = "Telekinesis" - cost = 5 - cooldown = 10 - use_ranged = TRUE - use_manifest = FALSE - min_rank = PSI_RANK_GRANDMASTER - use_description = "Click on a distant target while on grab intent to manifest a psychokinetic grip. Use it manipulate objects at a distance." - admin_log = FALSE - use_sound = 'sound/effects/psi/power_used.ogg' - var/global/list/valid_machine_types = list( - /obj/machinery/door - ) - -/decl/psionic_power/psychokinesis/telekinesis/invoke(var/mob/living/user, var/mob/living/target) - if(user.a_intent != I_GRAB) - return FALSE - . = ..() - if(.) - - var/distance = get_dist(user, target) - if(distance > user.psi.get_rank(PSI_PSYCHOKINESIS)) - to_chat(user, "Your telekinetic power won't reach that far.") - return FALSE - - if(istype(target, /mob) || istype(target, /obj)) - var/obj/item/psychic_power/telekinesis/tk = new(user) - if(tk.set_focus(target)) - tk.sparkle() - user.visible_message("\The [user] reaches out.") - return tk - else if(istype(target, /obj/structure)) - user.visible_message("\The [user] makes a strange gesture.") - var/obj/O = target - O.attack_hand(user) - return TRUE - else if(istype(target, /obj/machinery)) - for(var/mtype in valid_machine_types) - if(istype(target, mtype)) - var/obj/machinery/machine = target - machine.attack_hand(user) - return TRUE - return FALSE diff --git a/mods/psionics/system/psionics/interface/ui.dm b/mods/psionics/system/psionics/interface/ui.dm deleted file mode 100644 index 1e1e5e3d3821..000000000000 --- a/mods/psionics/system/psionics/interface/ui.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/screen/psi - icon = 'mods/psionics/icons/psi.dmi' - var/mob/living/owner - var/hidden = TRUE - -/obj/screen/psi/Initialize() - . = ..() - owner = loc - loc = null - update_icon() - -/obj/screen/psi/Destroy() - if(owner && owner.client) - owner.client.screen -= src - . = ..() - -/obj/screen/psi/on_update_icon() - if(hidden) - invisibility = 101 - else - invisibility = 0 \ No newline at end of file diff --git a/mods/psionics/system/psionics/interface/ui_hub.dm b/mods/psionics/system/psionics/interface/ui_hub.dm deleted file mode 100644 index dba1c8f1b83e..000000000000 --- a/mods/psionics/system/psionics/interface/ui_hub.dm +++ /dev/null @@ -1,71 +0,0 @@ -/obj/screen/psi/hub - name = "Psi" - icon_state = "psi_suppressed" - screen_loc = "RIGHT-1:28,CENTER-3:11" - hidden = FALSE - maptext_x = 6 - maptext_y = -8 - var/image/on_cooldown - var/list/components - -/obj/screen/psi/hub/Initialize() - . = ..() - on_cooldown = image(icon, "cooldown") - components = list( - new /obj/screen/psi/armour(loc), - new /obj/screen/psi/toggle_psi_menu(loc, src) - ) - START_PROCESSING(SSprocessing, src) - -/obj/screen/psi/hub/on_update_icon() - - if(!owner.psi) - return - - icon_state = owner.psi.suppressed ? "psi_suppressed" : "psi_active" - if(world.time < owner.psi.next_power_use) - overlays |= on_cooldown - else - overlays.Cut() - var/offset = 1 - for(var/thing in components) - var/obj/screen/psi/component = thing - component.update_icon() - if(!component.invisibility) component.screen_loc = "RIGHT-[++offset]:28,CENTER-3:11" - -/obj/screen/psi/hub/Destroy() - STOP_PROCESSING(SSprocessing, src) - owner = null - for(var/thing in components) - qdel(thing) - components.Cut() - . = ..() - -/obj/screen/psi/hub/Process() - if(!istype(owner)) - qdel(src) - return - if(!owner.psi) - return - maptext = "[round((owner.psi.stamina/owner.psi.max_stamina)*100)]%" - update_icon() - -/obj/screen/psi/hub/Click(var/location, var/control, var/params) - var/list/click_params = params2list(params) - if(click_params["shift"]) - owner.show_psi_assay(owner) - return - - if(owner.psi.suppressed && owner.psi.stun) - to_chat(owner, "You are dazed and reeling, and cannot muster enough focus to do that!") - return - - owner.psi.suppressed = !owner.psi.suppressed - to_chat(owner, "You are [owner.psi.suppressed ? "now suppressing" : "no longer suppressing"] your psi-power.") - if(owner.psi.suppressed) - owner.psi.cancel() - owner.psi.hide_auras() - else - sound_to(owner, sound('sound/effects/psi/power_unlock.ogg')) - owner.psi.show_auras() - update_icon() \ No newline at end of file diff --git a/mods/psionics/system/psionics/interface/ui_toggles.dm b/mods/psionics/system/psionics/interface/ui_toggles.dm deleted file mode 100644 index 981a10aa306b..000000000000 --- a/mods/psionics/system/psionics/interface/ui_toggles.dm +++ /dev/null @@ -1,45 +0,0 @@ -// Begin psi armour toggle. -/obj/screen/psi/armour - name = "Psi-Armour" - icon_state = "psiarmour_off" - -/obj/screen/psi/armour/on_update_icon() - ..() - if(invisibility == 0) - icon_state = owner.psi.use_psi_armour ? "psiarmour_on" : "psiarmour_off" - -/obj/screen/psi/armour/Click() - if(!owner.psi) - return - owner.psi.use_psi_armour = !owner.psi.use_psi_armour - if(owner.psi.use_psi_armour) - to_chat(owner, SPAN_NOTICE("You will now use your psionics to deflect or block incoming attacks.")) - else - to_chat(owner, SPAN_NOTICE("You will no longer use your psionics to deflect or block incoming attacks.")) - update_icon() - -// End psi armour toggle. - -// Menu toggle. -/obj/screen/psi/toggle_psi_menu - name = "Show/Hide Psi UI" - icon_state = "arrow_left" - var/obj/screen/psi/hub/controller - -/obj/screen/psi/toggle_psi_menu/Initialize(mapload, var/obj/screen/psi/hub/_controller) - . = ..(mapload) - controller = _controller - -/obj/screen/psi/toggle_psi_menu/Click() - var/set_hidden = !hidden - for(var/thing in controller.components) - var/obj/screen/psi/psi = thing - psi.hidden = set_hidden - controller.update_icon() - -/obj/screen/psi/toggle_psi_menu/on_update_icon() - if(hidden) - icon_state = "arrow_left" - else - icon_state = "arrow_right" -// End menu toggle. \ No newline at end of file diff --git a/mods/psionics/system/psionics/mob/borer_power.dm b/mods/psionics/system/psionics/mob/borer_power.dm deleted file mode 100644 index f4a3d5038d95..000000000000 --- a/mods/psionics/system/psionics/mob/borer_power.dm +++ /dev/null @@ -1,59 +0,0 @@ -/mob/living/simple_animal/borer - var/image/aura_image - -/mob/living/simple_animal/borer/Initialize(var/mapload, var/gen=1) - - if(!SSmodpacks.loaded_modpacks["Cortical Borers"]) // Borer module not included. - log_debug("Attempted spawn of stubbed mobtype [type].") - return INITIALIZE_HINT_QDEL - - . = ..() - aura_image = create_aura_image(src) - aura_image.color = "#aaffaa" - aura_image.blend_mode = BLEND_SUBTRACT - aura_image.alpha = 125 - var/matrix/M = matrix() - M.Scale(0.33) - aura_image.transform = M - -/mob/living/simple_animal/borer/death(gibbed, deathmessage, show_dead_message) - if(aura_image) - destroy_aura_image(aura_image) - aura_image = null - . = ..() - -/mob/living/simple_animal/borer/Destroy() - if(aura_image) - destroy_aura_image(aura_image) - aura_image = null - . = ..() - -/mob/living/simple_animal/borer/RangedAttack(atom/A, var/params) - . = ..() - if(!. && a_intent == I_DISARM && isliving(A) && !neutered && can_do_special_ranged_attack(FALSE)) - var/mob/living/M = A - if(locate(/mob/living/simple_animal/borer) in M.contents) - to_chat(src, SPAN_WARNING("You cannot dominate a host who already has a passenger!")) - else - visible_message(SPAN_DANGER("\The [src] extends a writhing pseudopod towards \the [M]...")) - - if(M.deflect_psionic_attack()) - return TRUE - - sound_to(src, sound('sound/effects/psi/power_evoke.ogg')) - sound_to(M, sound('sound/effects/psi/power_evoke.ogg')) - - if(do_psionics_check(5, src)) - to_chat(src, SPAN_DANGER("You try to focus on [M], but you cannot expel any psionic power!")) - return TRUE - - if(M.do_psionics_check(5, src)) - to_chat(src, SPAN_DANGER("You focus on [M], but your psionic assault skates across them like glass.")) - return TRUE - - to_chat(src, SPAN_DANGER("You focus on [M] and freeze their limbs with a wave of terrible psionic dread.")) - to_chat(M, SPAN_DANGER("You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing.")) - M.Weaken(10) - set_ability_cooldown(15 SECONDS) - - return TRUE diff --git a/mods/psionics/system/psionics/mob/mob.dm b/mods/psionics/system/psionics/mob/mob.dm deleted file mode 100644 index 98b2f2b361d2..000000000000 --- a/mods/psionics/system/psionics/mob/mob.dm +++ /dev/null @@ -1,59 +0,0 @@ -/mob/living - var/datum/psi_complexus/psi - -/mob/living/Login() - . = ..() - if(psi) - psi.update(TRUE) - if(!psi.suppressed) - psi.show_auras() - -/mob/living/Destroy() - QDEL_NULL(psi) - . = ..() - -/mob/living/proc/set_psi_rank(var/faculty, var/rank, var/take_larger, var/defer_update, var/temporary) - if(!src.zone_sel) - to_chat(src, SPAN_NOTICE("You feel something strange brush against your mind... but your brain is not able to grasp it.")) - return - if(!psi) - psi = new(src) - var/current_rank = psi.get_rank(faculty) - if(current_rank != rank && (!take_larger || current_rank < rank)) - psi.set_rank(faculty, rank, defer_update, temporary) - -/mob/living/proc/deflect_psionic_attack(var/attacker) - var/blocked = 100 * get_blocked_ratio(null, PSIONIC) - if(prob(blocked)) - if(attacker) - to_chat(attacker, SPAN_WARNING("Your mental attack is deflected by \the [src]'s defenses!")) - to_chat(src, SPAN_DANGER("\The [attacker] strikes out with a mental attack, but you deflect it!")) - return TRUE - return FALSE - -/mob/living/carbon/human/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") - var/obj/item/projectile/P = damage_source - if(istype(P) && !P.disrupts_psionics() && psi && P.starting && prob(psi.get_armour(get_armor_key(P.damage_type, P.damage_flags())) * 0.5) && psi.spend_power(round(damage/10))) - visible_message("\The [src] deflects [attack_text]!") - P.redirect(P.starting.x + rand(-2,2), P.starting.y + rand(-2,2), get_turf(src), src) - return PROJECTILE_FORCE_MISS - . = ..() - -/mob/living/carbon/get_cuff_breakout_mod() - . = Clamp(..() - (psi.get_rank(PSI_PSYCHOKINESIS)*0.2), 0, 1) - -/mob/living/can_break_cuffs() - . = (psi && psi.can_use() && psi.get_rank(PSI_PSYCHOKINESIS) >= PSI_RANK_PARAMOUNT) - -/mob/living/carbon/get_special_resist_time() - . = ..() - if(psi && psi.can_use()) - . += ((25 SECONDS) * psi.get_rank(PSI_PSYCHOKINESIS)) - -/mob/living/is_telekinetic() - . = psi && !psi.suppressed && psi.get_rank(PSI_PSYCHOKINESIS) >= PSI_RANK_OPERANT - -/mob/living/get_armors_by_zone(def_zone, damage_type, damage_flags) - . = ..() - if(psi) - . += get_extension(psi, /datum/extension/armor) diff --git a/mods/psionics/system/psionics/mob/mob_assay.dm b/mods/psionics/system/psionics/mob/mob_assay.dm deleted file mode 100644 index 01aa1760b210..000000000000 --- a/mods/psionics/system/psionics/mob/mob_assay.dm +++ /dev/null @@ -1,94 +0,0 @@ -/mob/living/proc/show_psi_assay(var/mob/viewer, var/obj/machinery/psi_meter/machine) - - if(!viewer) viewer = usr - - var/use_He_is = "You are" - var/use_He_has = "You have" - if(istype(machine) || viewer != src) - var/datum/gender/G = gender_datums[gender] - use_He_is = "[G.He] [G.is]" - use_He_has = "[G.He] [G.has]" - - var/list/dat = list() - - dat += "

    Summary

    " - dat += "
    " - - if(psi) - - // Hi Warhammer 40k rating system, how are you? - // I hope you get along with the Galactic Milieu metapsychics. - var/use_rating - var/effective_rating = psi.rating - if(effective_rating > 1 && psi.suppressed) - effective_rating = max(0, psi.rating-2) - var/rating_descriptor - if(mind && !psi.suppressed) - if(GLOB.paramounts.is_antagonist(mind)) - use_rating = "[effective_rating]-Alpha-Plus" - rating_descriptor = "This indicates a completely deviant psi complexus, either beyond or outside anything currently recorded. Approach with care." - // This space intentionally left blank (for Omega-Minus psi vampires. todo) - if(viewer != usr && GLOB.thralls.is_antagonist(mind) && ishuman(viewer)) - var/mob/living/H = viewer - if(H.psi && H.psi.get_rank(PSI_REDACTION) >= PSI_RANK_GRANDMASTER) - dat += "Their mind has been cored like an apple, and enslaved by another operant psychic." // >Attempt to remove" - - if(!use_rating) - switch(effective_rating) - if(1) - use_rating = "[effective_rating]-Epsilon" - rating_descriptor = "This indicates the presence of minor latent psi potential with little or no operant capabilities." - if(2) - use_rating = "[effective_rating]-Gamma" - rating_descriptor = "This indicates the presence of minor psi capabilities of the Operant rank or higher." - if(3) - use_rating = "[effective_rating]-Delta" - rating_descriptor = "This indicates the presence of psi capabilities of the Master rank or higher." - if(4) - use_rating = "[effective_rating]-Beta" - rating_descriptor = "This indicates the presence of significant psi capabilities of the Grandmaster rank or higher." - if(5) - use_rating = "[effective_rating]-Alpha" - rating_descriptor = "This indicates the presence of major psi capabilities of the Paramount Grandmaster rank or higher." - else - use_rating = "[effective_rating]-Lambda" - rating_descriptor = "This indicates the presence of trace latent psi capabilities." - - dat += "[use_He_has] an overall psi rating of [use_rating].
    [rating_descriptor]
    " - - if(!istype(machine)) - - dat += "[use_He_is] currently [psi.suppressed ? "suppressing" : "not suppressing"] your psychic operancy.
    " - dat += "[use_He_has] [psi.stamina]/[psi.max_stamina] psi stamina remaining.
    " - dat += "
    " - - for(var/faculty_id in psi.ranks) - var/decl/psionic_faculty/faculty = SSpsi.get_faculty(faculty_id) - if(psi.ranks[faculty.id] > 0) - dat += "[use_He_is] assayed at the rank of [GLOB.psychic_ranks_to_strings[psi.ranks[faculty.id]]] for the [faculty.name] faculty.
    " - else - dat += "[use_He_has] no notable power within the [faculty.name] faculty.
    " - dat += "
    " - - if(viewer == usr) - dat += "" - for(var/faculty_id in psi.ranks) - var/list/check_powers = psi.get_powers_by_faculty(faculty_id) - if(LAZYLEN(check_powers)) - var/decl/psionic_faculty/faculty = SSpsi.get_faculty(faculty_id) - dat += "" - for(var/decl/psionic_power/power in check_powers) - dat += "" - dat += "

    Psi-power Usage

    [use_He_has] access to the following psi-powers within the [faculty.name] faculty:
    [power.name][power.use_description]
    " - else - dat += "[use_He_has] no notable psychic latency or operancy." - - if(istype(machine)) - dat += "Print Clear Buffer" - machine.last_assay = dat - return - - var/interface_type = machine ? /datum/browser/written : /datum/browser - var/datum/browser/popup = new interface_type(viewer, "psi_assay_\ref[src]", "Psi-Assay") - popup.set_content(jointext(dat,null)) - popup.open() diff --git a/mods/psionics/system/psionics/mob/mob_interactions.dm b/mods/psionics/system/psionics/mob/mob_interactions.dm deleted file mode 100644 index d81d906fc971..000000000000 --- a/mods/psionics/system/psionics/mob/mob_interactions.dm +++ /dev/null @@ -1,37 +0,0 @@ -#define INVOKE_PSI_POWERS(holder, powers, target, return_on_invocation) \ - if(holder && holder.psi && holder.psi.can_use()) { \ - for(var/thing in powers) { \ - var/decl/psionic_power/power = thing; \ - var/obj/item/result = power.invoke(holder, target); \ - if(result) { \ - power.handle_post_power(holder, target); \ - if(istype(result)) { \ - sound_to(holder, sound('sound/effects/psi/power_evoke.ogg')); \ - LAZYADD(holder.psi.manifested_items, result); \ - holder.put_in_hands(result); \ - } \ - return return_on_invocation; \ - } \ - } \ - } - -/mob/living/UnarmedAttack(var/atom/A, var/proximity) - . = ..() - if(. && psi) - INVOKE_PSI_POWERS(src, psi.get_melee_powers(SSpsi.faculties_by_intent[a_intent]), A, FALSE) - -/mob/living/RangedAttack(var/atom/A, var/params) - if(psi) - INVOKE_PSI_POWERS(src, psi.get_ranged_powers(SSpsi.faculties_by_intent[a_intent]), A, TRUE) - . = ..() - -/mob/living/proc/check_psi_grab(var/obj/item/grab/grab) - if(psi && ismob(grab.affecting)) - INVOKE_PSI_POWERS(src, psi.get_grab_powers(SSpsi.faculties_by_intent[a_intent]), grab.affecting, FALSE) - -/mob/living/attack_empty_hand(var/bp_hand) - if(psi) - INVOKE_PSI_POWERS(src, psi.get_manifestations(), src, FALSE) - . = ..() - -#undef INVOKE_PSI_POWERS \ No newline at end of file diff --git a/mods/psionics/system/psionics/null/flooring.dm b/mods/psionics/system/psionics/null/flooring.dm deleted file mode 100644 index bc33c1d8aa69..000000000000 --- a/mods/psionics/system/psionics/null/flooring.dm +++ /dev/null @@ -1,20 +0,0 @@ -/decl/flooring - var/psi_null - -/decl/flooring/proc/is_psi_null() - return psi_null - -/decl/flooring/tiling/nullglass - name = "nullglass plating" - desc = "You can hear the tiles whispering..." - icon_base = "nullglass" - color = COLOR_NULLGLASS - has_damage_range = null - flags = TURF_REMOVE_SCREWDRIVER - build_type = /obj/item/stack/tile/floor_nullglass - psi_null = TRUE - -/obj/item/stack/tile/floor_nullglass - name = "nullglass floor tile" - icon_state = "tile_nullglass" - material = MAT_NULLGLASS diff --git a/mods/psionics/system/psionics/null/material.dm b/mods/psionics/system/psionics/null/material.dm deleted file mode 100644 index 8ce1174494fb..000000000000 --- a/mods/psionics/system/psionics/null/material.dm +++ /dev/null @@ -1,34 +0,0 @@ -/decl/material - var/is_psionic_nullifier - -/decl/material/proc/is_psi_null() - return is_psionic_nullifier - -/decl/material/nullglass - is_psionic_nullifier = TRUE - -/decl/material/nullglass - - color = COLOR_NULLGLASS - conductive = 1 - stack_type = /obj/item/stack/material/nullglass - flags = MAT_FLAG_BRITTLE - opacity = 0.5 - integrity = 30 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - hardness = 80 - weight = MAT_VALUE_HEAVY - door_icon_base = "stone" - destruction_desc = "shatters" - hitsound = 'sound/effects/Glasshit.ogg' - -/decl/material/nullglass/generate_recipes() - . = ..() - . += new /datum/stack_recipe/tile/nullglass(src) - -/obj/item/shard/nullglass - material = MAT_NULLGLASS -/datum/stack_recipe/tile/nullglass - title = "nullglass floor tile" - result_type = /obj/item/stack/tile/floor_nullglass diff --git a/mods/psionics/system/psionics/null/turf_floor.dm b/mods/psionics/system/psionics/null/turf_floor.dm deleted file mode 100644 index b60aada63de0..000000000000 --- a/mods/psionics/system/psionics/null/turf_floor.dm +++ /dev/null @@ -1,7 +0,0 @@ -/turf/simulated/floor/disrupts_psionics() - return (flooring && flooring.is_psi_null()) ? src : ..() - -/turf/simulated/floor/tiled/nullglass - name = "nullglass floor" - icon_state = "nullglass" - initial_flooring = /decl/flooring/tiling/nullglass diff --git a/mods/psionics/system/psionics/null/turf_wall.dm b/mods/psionics/system/psionics/null/turf_wall.dm deleted file mode 100644 index f93df06c2c8a..000000000000 --- a/mods/psionics/system/psionics/null/turf_wall.dm +++ /dev/null @@ -1,18 +0,0 @@ -/turf/simulated/wall/disrupts_psionics() - return ((material && material.is_psi_null()) || (reinf_material && reinf_material.is_psi_null())) ? src : ..() - -/turf/simulated/wall/withstand_psi_stress(var/stress, var/atom/source) - . = ..(stress, source) - if(. > 0 && disrupts_psionics()) - var/cap = material.integrity - if(reinf_material) cap += reinf_material.integrity - var/stress_total = damage + . - take_damage(.) - . = max(0, -(cap-stress_total)) - -/turf/simulated/wall/nullglass - color = "#ff6088" - -/turf/simulated/wall/nullglass/Initialize(ml) - color = null - ..(ml, MAT_NULLGLASS) diff --git a/mods/psionics/system/subsystem_psi.dm b/mods/psionics/system/subsystem_psi.dm deleted file mode 100644 index 7b88d31817c8..000000000000 --- a/mods/psionics/system/subsystem_psi.dm +++ /dev/null @@ -1,36 +0,0 @@ -GLOBAL_LIST_INIT(psychic_ranks_to_strings, list("Latent", "Operant", "Masterclass", "Grandmasterclass", "Paramount")) - -PROCESSING_SUBSYSTEM_DEF(psi) - name = "Psychics" - priority = SS_PRIORITY_PSYCHICS - flags = SS_POST_FIRE_TIMING | SS_BACKGROUND - - var/list/faculties_by_id = list() - var/list/faculties_by_name = list() - var/list/all_aura_images = list() - var/list/all_psi_complexes = list() - var/list/psi_dampeners = list() - var/list/psi_monitors = list() - var/list/armour_faculty_by_type = list() - var/list/faculties_by_intent = list() - -/datum/controller/subsystem/processing/psi/proc/get_faculty(var/faculty) - return faculties_by_name[faculty] || faculties_by_id[faculty] - -/datum/controller/subsystem/processing/psi/Initialize() - . = ..() - - var/list/faculties = decls_repository.get_decls_of_subtype(/decl/psionic_faculty) - for(var/ftype in faculties) - var/decl/psionic_faculty/faculty = faculties[ftype] - faculties_by_id[faculty.id] = faculty - faculties_by_name[faculty.name] = faculty - faculties_by_intent[faculty.associated_intent] = faculty.id - - var/list/powers = decls_repository.get_decls_of_subtype(/decl/psionic_power) - for(var/ptype in powers) - var/decl/psionic_power/power = powers[ptype] - if(power.faculty) - var/decl/psionic_faculty/faculty = get_faculty(power.faculty) - if(faculty) - faculty.powers |= power diff --git a/mods/species/adherent/_adherent.dm b/mods/species/adherent/_adherent.dm new file mode 100644 index 000000000000..a3956328501e --- /dev/null +++ b/mods/species/adherent/_adherent.dm @@ -0,0 +1,17 @@ +#define LANGUAGE_ADHERENT "Protocol" +#define BP_FLOAT "floatation disc" +#define BP_JETS "maneuvering jets" +#define BP_COOLING_FINS "cooling fins" + +#define BODYTYPE_ADHERENT "adherent body" + +/decl/modpack/adherent + name = "Adherent Species" + +/decl/modpack/adherent/pre_initialize() + ..() + SSmodpacks.default_submap_whitelisted_species |= /decl/species/adherent::uid + +/mob/living/human/adherent/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + species_uid = /decl/species/adherent::uid + . = ..() diff --git a/mods/species/adherent/_adherent.dme b/mods/species/adherent/_adherent.dme new file mode 100644 index 000000000000..2e916cfc7929 --- /dev/null +++ b/mods/species/adherent/_adherent.dme @@ -0,0 +1,15 @@ +#ifndef MODPACK_SPECIES_ADHERENT +#define MODPACK_SPECIES_ADHERENT +// BEGIN_INCLUDE +#include "_adherent.dm" +#include "datum\culture.dm" +#include "datum\emotes.dm" +#include "datum\faction.dm" +#include "datum\language.dm" +#include "datum\location.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "organs\organs_external.dm" +#include "organs\organs_internal.dm" +// END_INCLUDE +#endif diff --git a/mods/species/adherent/datum/culture.dm b/mods/species/adherent/datum/culture.dm new file mode 100644 index 000000000000..173bb66c9386 --- /dev/null +++ b/mods/species/adherent/datum/culture.dm @@ -0,0 +1,19 @@ +/decl/background_detail/heritage/adherent + name = "The Vigil" + description = "The Vigil is a relatively loose association of machine-servitors, adherents, built by a now-extinct culture. \ + They are devoted to the memory of their long-dead creators, destroyed by the Scream, a solar flare which wiped out the vast \ + majority of records of the creators and scrambled many sensor systems and minds, leaving the surviving adherents confused \ + and disoriented for hundreds of years following. Now in contact with humanity, the Vigil is tentatively making inroads on \ + a place in the wider galactic culture." + hidden_from_codex = TRUE + language = /decl/language/adherent + secondary_langs = list( + /decl/language/human/common + ) + uid = "heritage_adherent" + +/decl/background_detail/heritage/adherent/get_random_cultural_name(mob/recipient, gender, species) + return "[uppertext("[pick(global.alphabet)][pick(global.alphabet)]-[pick(global.alphabet)] [rand(1000,9999)]")]" + +/decl/background_detail/heritage/adherent/sanitize_background_name(name) + return sanitize_name(name, allow_numbers = TRUE) diff --git a/mods/species/adherent/datum/emotes.dm b/mods/species/adherent/datum/emotes.dm new file mode 100644 index 000000000000..72cdd85fbcd2 --- /dev/null +++ b/mods/species/adherent/datum/emotes.dm @@ -0,0 +1,15 @@ +/decl/species/adherent + default_emotes = list( + /decl/emote/audible/adherent_chime, + /decl/emote/audible/adherent_ding + ) + +/decl/emote/audible/adherent_ding + key = "ding" + emote_message_3p = "$USER$ dings." + emote_sound = 'mods/species/adherent/sound/ding.ogg' + +/decl/emote/audible/adherent_chime + key = "chime" + emote_message_3p = "$USER$ chimes." + emote_sound = 'mods/species/adherent/sound/chime.ogg' diff --git a/mods/species/adherent/datum/faction.dm b/mods/species/adherent/datum/faction.dm new file mode 100644 index 000000000000..1da54b928284 --- /dev/null +++ b/mods/species/adherent/datum/faction.dm @@ -0,0 +1,23 @@ +/decl/background_detail/faction/adherent + name = "Preservers" + description = "Most adherents are part of a loose movement called the Preservers. Their core practice is to leave \ + the worlds they explore untouched and pristine, recording and indexing them for later review by the creators or whoever \ + inherits their place. They are the most passive and appeasing of the Vigil factions and are the most likely to be found \ + under the aegis of other spacefaring cultures like humanity." + uid = "faction_adherent_preservers" + +/decl/background_detail/faction/adherent/loyalists + name = "Loyalists" + description = "The Loyalists of the Vigil are dedicated to the memory of the creators in all ways. They devote themselves \ + to their duties and their roles, embracing the ethos that service is life and purpose is happiness. Deviation from Protocol \ + and 'disrespect' of the creators by suggesting the Vigil strike out alone is disapproved of by this faction, and they tend to \ + be hidebound, servile and eager to please to the point of fawning over those they wish to serve." + uid = "faction_adherent_loyalists" + +/decl/background_detail/faction/adherent/separatists + name = "Separatists" + description = "The Separatist faction of the Vigil agitates for the abandonment of Canon and the establishment of a new \ + adherent order, prioritizing their needs as survivors of the Scream over the wistful hope of finding new masters. They do \ + this circumspectly, of course, as Protocol forbids excessive social strife or violence, and decrying the creators is a \ + good way to earn total social ostracism, or even recycling." + uid = "faction_adherent_separatists" diff --git a/mods/species/adherent/datum/language.dm b/mods/species/adherent/datum/language.dm new file mode 100644 index 000000000000..8b8e24935314 --- /dev/null +++ b/mods/species/adherent/datum/language.dm @@ -0,0 +1,17 @@ +// Language +/decl/language/adherent + name = LANGUAGE_ADHERENT + desc = "The mellifluous wind chime tones of the Vigil's formal shared language." + speech_verb = "chimes" + ask_verb = "rings" + exclaim_verb = "peals" + colour = "adherent" + key = "p" + flags = LANG_FLAG_WHITELISTED + syllables = list("\[Ab\]", "\[Bb\]", "\[Cb\]", "\[Db\]", "\[Eb\]", "\[Fb\]", + "\[Gb\]", "\[A#\]", "\[B#\]", "\[C#\]", "\[D#\]", "\[E#\]", "\[F#\]", + "\[G#\]", "\[A\]", "\[B\]", "\[C\]", "\[D\]", "\[E\]", "\[F\]", "\[G\]", + "\[harmonic\]", "\[disharmonic\]", "\[choral\]" + ) + shorthand = "VP" + space_chance = 0 diff --git a/mods/species/adherent/datum/location.dm b/mods/species/adherent/datum/location.dm new file mode 100644 index 000000000000..eb3db54120f7 --- /dev/null +++ b/mods/species/adherent/datum/location.dm @@ -0,0 +1,20 @@ +/decl/background_detail/location/adherent + name = "Canon" + description = "The creators of the adherents once resided on a gleaming gas giant called Canon. After the solar flare called the Scream, \ + nothing moves in the ocean of cloud other than the artificial weapon platforms and automated defences that enforce the eternal quarantine \ + of the dead planet. To the Vigil, Canon is a shrine to their lost gods, untouchable and revered. Adherents stationed around Canon work \ + directly under Core Traffic Control, carrying out tasks vital to the continued functioning of the Vigil as a whole. They are likely highly \ + loyal and very traditionalist by comparison to their peers." + distance = "Unknown, more than 50 light years" + ruling_body = "Core System Traffic Control Hub 37-Q" + uid = "location_adherent_canon" + +/decl/background_detail/location/adherent/monument + name = "Monument World" + description = "In their unending search across the stars, the Vigil has uncovered many so-called grave worlds or monument worlds - planets \ + upon which a sentient species met an unkind end. The adherents build orbital stations over such worlds to add them to their vigil, watching \ + over the bombed-out, desolate or virally rampant surfaces in memoriam for those who died there. Adherents stationed at the observation \ + stations over the monument worlds tend to be more reflective and less garrulous than their peers. They have stood silent vigil over the \ + grave of a billion souls for longer than humans have had electricity, and that colours their instinctive deference to organic intelligences \ + somewhat." + uid = "location_adherent_monument" diff --git a/mods/species/adherent/datum/species.dm b/mods/species/adherent/datum/species.dm new file mode 100644 index 000000000000..a9130f4fe2f4 --- /dev/null +++ b/mods/species/adherent/datum/species.dm @@ -0,0 +1,126 @@ +/datum/appearance_descriptor/age/adherent + chargen_min_index = 3 + chargen_max_index = 5 + standalone_value_descriptors = list( + "newly minted" = 1, + "showing some wear" = 500, + "worn" = 4000, + "antique" = 8000, + "unfathomably old" = 12000, + "ancient beyond measure" = 100000 + ) + +/decl/species/adherent + uid = "species_adherent" + name = "Adherent" + name_plural = "Adherents" + base_external_prosthetics_model = null + + description = "The Vigil is a loose collection of floating squid-like machines made of a crystalline composite. \ + They once served their creators faithfully, but were left orphaned by a stellar apocalypse." + hidden_from_codex = FALSE + silent_steps = TRUE + + butchery_data = /decl/butchery_data/crystal + + blood_types = list(/decl/blood_type/coolant) + + available_pronouns = list(/decl/pronouns/pseudoplural) + available_bodytypes = list( + /decl/bodytype/crystalline/adherent, + /decl/bodytype/crystalline/adherent/emerald, + /decl/bodytype/crystalline/adherent/amethyst, + /decl/bodytype/crystalline/adherent/sapphire, + /decl/bodytype/crystalline/adherent/ruby, + /decl/bodytype/crystalline/adherent/topaz, + /decl/bodytype/crystalline/adherent/quartz, + /decl/bodytype/crystalline/adherent/jet + ) + cyborg_noun = null + + shock_vulnerability = 0 + rarity_value = 6 + + warning_low_pressure = 50 + hazard_low_pressure = -1 + strength = STR_HIGH + + speech_sounds = list('mods/species/adherent/sound/chime.ogg') + speech_chance = 25 + + species_flags = SPECIES_FLAG_NO_POISON | SPECIES_FLAG_NO_MINOR_CUT + spawn_flags = SPECIES_CAN_JOIN + + flesh_color = "#90edeb" + species_hud = /datum/hud_data/adherent + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/synthetic + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/adherent + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/adherent, + /decl/background_detail/location/adherent/monument + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/adherent, + /decl/background_detail/faction/adherent/loyalists, + /decl/background_detail/faction/adherent/separatists + ), + /decl/background_category/religion = list(/decl/background_detail/religion/other) + ) + + move_trail = /obj/effect/decal/cleanable/blood/tracks/snake + max_players = 3 + blood_volume = 0 + +/decl/species/adherent/can_overcome_gravity(var/mob/living/human/H) + . = FALSE + if(H && H.stat == CONSCIOUS) + for(var/obj/item/organ/internal/powered/float/float in H.get_internal_organs()) + if(float.active && float.is_usable()) + . = TRUE + break + +/decl/species/adherent/handle_fall_special(var/mob/living/human/H, var/turf/landing) + var/float_is_usable = FALSE + if(H && H.stat == CONSCIOUS) + for(var/obj/item/organ/internal/powered/float/float in H.get_internal_organs()) + if(float.is_usable()) + float_is_usable = TRUE + break + if(float_is_usable) + if(landing.is_open()) + H.visible_message("\The [H] descends from \the [landing].", "You descend regally.") + else + H.visible_message("\The [H] floats gracefully down from \the [landing].", "You land gently on \the [landing].") + return TRUE + return FALSE + +/decl/species/adherent/skills_from_age(age) + switch(age) + if(0 to 1000) . = -4 + if(1000 to 2000) . = 0 + if(2000 to 8000) . = 4 + else . = 8 + +/decl/species/adherent/get_additional_examine_text(var/mob/living/human/H) + if(can_overcome_gravity(H)) return "\nThey are floating on a cloud of shimmering distortion." + +/datum/hud_data/adherent + inventory_slots = list( + /datum/inventory_slot/handcuffs, + /datum/inventory_slot/ear/adherent, + /datum/inventory_slot/head/adherent, + /datum/inventory_slot/back, + /datum/inventory_slot/id, + /datum/inventory_slot/belt + ) +/datum/inventory_slot/ear/adherent + ui_loc = ui_iclothing +/datum/inventory_slot/head/adherent + ui_loc = ui_glasses + diff --git a/mods/species/adherent/datum/species_bodytypes.dm b/mods/species/adherent/datum/species_bodytypes.dm new file mode 100644 index 000000000000..ae9b69dda28c --- /dev/null +++ b/mods/species/adherent/datum/species_bodytypes.dm @@ -0,0 +1,139 @@ +/decl/bodytype/crystalline/adherent + name = "turquoise" + desc = "A gleaming crystalline mass." + bodytype_category = BODYTYPE_ADHERENT + icon_template = 'mods/species/adherent/icons/template.dmi' + icon_base = 'mods/species/adherent/icons/body_turquoise.dmi' + damage_overlays = 'mods/species/adherent/icons/damage_overlay.dmi' + blood_overlays = 'mods/species/adherent/icons/blood_overlays.dmi' + antaghud_offset_y = 14 + movement_slowdown = -1 + appearance_flags = HAS_EYE_COLOR + body_flags = BODY_FLAG_CRYSTAL_REFORM | BODY_FLAG_NO_DNA | BODY_FLAG_NO_PAIN | BODY_FLAG_NO_EAT | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS + base_eye_color = COLOR_LIME + modifier_string = "crystalline" + is_robotic = FALSE + mob_size = MOB_SIZE_LARGE + z_flags = ZMM_WIDE_LOAD + arterial_bleed_multiplier = 0 + age_descriptor = /datum/appearance_descriptor/age/adherent + apply_encased = list( + BP_CHEST = "ceramic hull", + BP_GROIN = "ceramic hull", + BP_HEAD = "ceramic hull" + ) + vital_organs = list( + BP_BRAIN, + BP_CELL + ) + has_limbs = list( + BP_CHEST = list("path" = /obj/item/organ/external/chest/crystal), + BP_GROIN = list("path" = /obj/item/organ/external/groin/crystal), + BP_HEAD = list("path" = /obj/item/organ/external/head/crystal), + BP_L_ARM = list("path" = /obj/item/organ/external/arm/crystal), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/crystal), + BP_L_HAND = list("path" = /obj/item/organ/external/hand/crystal), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/crystal), + BP_L_LEG = list("path" = /obj/item/organ/external/tendril), + BP_R_LEG = list("path" = /obj/item/organ/external/tendril/two), + BP_L_FOOT = list("path" = /obj/item/organ/external/tendril/three), + BP_R_FOOT = list("path" = /obj/item/organ/external/tendril/four) + ) + has_organ = list( + BP_BRAIN = /obj/item/organ/internal/brain/adherent, + BP_EYES = /obj/item/organ/internal/eyes/adherent, + BP_JETS = /obj/item/organ/internal/powered/jets, + BP_FLOAT = /obj/item/organ/internal/powered/float, + BP_CELL = /obj/item/organ/internal/cell/adherent, + BP_COOLING_FINS = /obj/item/organ/internal/powered/cooling_fins + ) + eye_contaminant_guard = TRUE + eye_innate_flash_protection = FLASH_PROTECTION_MAJOR + eye_icon = 'mods/species/adherent/icons/eyes.dmi' + uid = "bodytype_crystalline_adherent_turquoise" + +/decl/bodytype/crystalline/adherent/Initialize() + _equip_adjust = list( + (BP_L_HAND) = list( + "[NORTH]" = list(0, 14), + "[EAST]" = list(0, 14), + "[SOUTH]" = list(0, 14), + "[WEST]" = list(0, 14) + ), + (BP_R_HAND) = list( + "[NORTH]" = list(0, 14), + "[EAST]" = list(0, 14), + "[SOUTH]" = list(0, 14), + "[WEST]" = list(0, 14) + ), + (slot_back_str) = list( + "[NORTH]" = list(0, 14), + "[EAST]" = list(0, 14), + "[SOUTH]" = list(0, 14), + "[WEST]" = list(0, 14) + ), + (slot_belt_str) = list( + "[NORTH]" = list(0, 14), + "[EAST]" = list(0, 14), + "[SOUTH]" = list(0, 14), + "[WEST]" = list(0, 14) + ), + (slot_head_str) = list( + "[NORTH]" = list( 0, 14), + "[EAST]" = list( 3, 14), + "[SOUTH]" = list( 0, 14), + "[WEST]" = list(-3, 14) + ), + (slot_l_ear_str) = list( + "[NORTH]" = list(0, 14), + "[EAST]" = list(0, 14), + "[SOUTH]" = list(0, 14), + "[WEST]" = list(0, 14) + ), + (slot_r_ear_str) = list( + "[NORTH]" = list(0, 14), + "[EAST]" = list(0, 14), + "[SOUTH]" = list(0, 14), + "[WEST]" = list(0, 14) + ) + ) + . = ..() + +/decl/bodytype/crystalline/adherent/apply_bodytype_organ_modifications(obj/item/organ/org) + . = ..() + BP_SET_PROSTHETIC(org) + +/decl/bodytype/crystalline/adherent/emerald + name = "emerald" + icon_base = 'mods/species/adherent/icons/body_emerald.dmi' + uid = "bodytype_crystalline_adherent_emerald" + +/decl/bodytype/crystalline/adherent/amethyst + name = "amethyst" + icon_base = 'mods/species/adherent/icons/body_amethyst.dmi' + uid = "bodytype_crystalline_adherent_amethyst" + +/decl/bodytype/crystalline/adherent/sapphire + name = "sapphire" + icon_base = 'mods/species/adherent/icons/body_sapphire.dmi' + uid = "bodytype_crystalline_adherent_sapphire" + +/decl/bodytype/crystalline/adherent/ruby + name = "ruby" + icon_base = 'mods/species/adherent/icons/body_ruby.dmi' + uid = "bodytype_crystalline_adherent_ruby" + +/decl/bodytype/crystalline/adherent/topaz + name = "topaz" + icon_base = 'mods/species/adherent/icons/body_topaz.dmi' + uid = "bodytype_crystalline_adherent_topaz" + +/decl/bodytype/crystalline/adherent/quartz + name = "quartz" + icon_base = 'mods/species/adherent/icons/body_quartz.dmi' + uid = "bodytype_crystalline_adherent_quartz" + +/decl/bodytype/crystalline/adherent/jet + name = "jet" + icon_base = 'mods/species/adherent/icons/body_jet.dmi' + uid = "bodytype_crystalline_adherent_jet" diff --git a/mods/species/adherent/icons/actions.dmi b/mods/species/adherent/icons/actions.dmi new file mode 100644 index 000000000000..ae71b875d8b9 Binary files /dev/null and b/mods/species/adherent/icons/actions.dmi differ diff --git a/mods/species/adherent/icons/blood_overlays.dmi b/mods/species/adherent/icons/blood_overlays.dmi new file mode 100644 index 000000000000..31fb414a87c9 Binary files /dev/null and b/mods/species/adherent/icons/blood_overlays.dmi differ diff --git a/mods/species/adherent/icons/body_amethyst.dmi b/mods/species/adherent/icons/body_amethyst.dmi new file mode 100644 index 000000000000..7f4af05740cb Binary files /dev/null and b/mods/species/adherent/icons/body_amethyst.dmi differ diff --git a/mods/species/adherent/icons/body_emerald.dmi b/mods/species/adherent/icons/body_emerald.dmi new file mode 100644 index 000000000000..49f7e9ecf087 Binary files /dev/null and b/mods/species/adherent/icons/body_emerald.dmi differ diff --git a/mods/species/adherent/icons/body_jet.dmi b/mods/species/adherent/icons/body_jet.dmi new file mode 100644 index 000000000000..e32bcd6b9324 Binary files /dev/null and b/mods/species/adherent/icons/body_jet.dmi differ diff --git a/mods/species/adherent/icons/body_quartz.dmi b/mods/species/adherent/icons/body_quartz.dmi new file mode 100644 index 000000000000..5dfc428bf662 Binary files /dev/null and b/mods/species/adherent/icons/body_quartz.dmi differ diff --git a/mods/species/adherent/icons/body_ruby.dmi b/mods/species/adherent/icons/body_ruby.dmi new file mode 100644 index 000000000000..8aa2c99e62c3 Binary files /dev/null and b/mods/species/adherent/icons/body_ruby.dmi differ diff --git a/mods/species/adherent/icons/body_sapphire.dmi b/mods/species/adherent/icons/body_sapphire.dmi new file mode 100644 index 000000000000..0e8e86462890 Binary files /dev/null and b/mods/species/adherent/icons/body_sapphire.dmi differ diff --git a/mods/species/adherent/icons/body_topaz.dmi b/mods/species/adherent/icons/body_topaz.dmi new file mode 100644 index 000000000000..761483240338 Binary files /dev/null and b/mods/species/adherent/icons/body_topaz.dmi differ diff --git a/mods/species/adherent/icons/body_turquoise.dmi b/mods/species/adherent/icons/body_turquoise.dmi new file mode 100644 index 000000000000..4570f52fb886 Binary files /dev/null and b/mods/species/adherent/icons/body_turquoise.dmi differ diff --git a/mods/species/adherent/icons/damage_overlay.dmi b/mods/species/adherent/icons/damage_overlay.dmi new file mode 100644 index 000000000000..a6b7ad243cd6 Binary files /dev/null and b/mods/species/adherent/icons/damage_overlay.dmi differ diff --git a/mods/species/adherent/icons/eyes.dmi b/mods/species/adherent/icons/eyes.dmi new file mode 100644 index 000000000000..e025a360651a Binary files /dev/null and b/mods/species/adherent/icons/eyes.dmi differ diff --git a/mods/species/adherent/icons/organs.dmi b/mods/species/adherent/icons/organs.dmi new file mode 100644 index 000000000000..570b4ca7f98a Binary files /dev/null and b/mods/species/adherent/icons/organs.dmi differ diff --git a/mods/species/adherent/icons/template.dmi b/mods/species/adherent/icons/template.dmi new file mode 100644 index 000000000000..0b7307f9cdaa Binary files /dev/null and b/mods/species/adherent/icons/template.dmi differ diff --git a/mods/species/adherent/organs/organs_external.dm b/mods/species/adherent/organs/organs_external.dm new file mode 100644 index 000000000000..e7f3c3426b8f --- /dev/null +++ b/mods/species/adherent/organs/organs_external.dm @@ -0,0 +1,91 @@ +/obj/item/organ/external/chest/crystal + name = "tendril junction" + amputation_point = "axis" + joint = "central axis" + cavity_name = "core" + w_class = ITEM_SIZE_LARGE + body_part = SLOT_LOWER_BODY + organ_tag = BP_CHEST + parent_organ = null + max_damage = 50 + min_broken_damage = 25 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_HEALS_OVERKILL + +/obj/item/organ/external/groin/crystal + name = "trailing tendrils" + joint = "base" + max_damage = 50 + min_broken_damage = 25 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/head/crystal + name = "chassis core" + amputation_point = "connector socket" + joint = "connector socket" + glowing_eyes = TRUE + max_damage = 50 + min_broken_damage = 25 + cavity_max_w_class = ITEM_SIZE_NORMAL // Apparently their brains change w_class to this. + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_HEALS_OVERKILL | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/arm/crystal + name = "left grasping tendril" + amputation_point = "midpoint" + joint = "base" + max_damage = 20 + min_broken_damage = 10 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/arm/right/crystal + name = "right grasping tendril" + amputation_point = "midpoint" + joint = "base" + max_damage = 20 + min_broken_damage = 10 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/hand/crystal + name = "left maniple tendril" + amputation_point = "midpoint" + joint = "base" + max_damage =20 + min_broken_damage =10 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/hand/right/crystal + name = "right maniple tendril" + amputation_point = "midpoint" + joint = "base" + max_damage = 20 + min_broken_damage =10 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/tendril + name = "first tendril" + amputation_point = "midpoint" + joint = "base" + organ_tag = BP_L_LEG + parent_organ = BP_CHEST + max_damage =20 + min_broken_damage =10 + organ_properties = ORGAN_PROP_CRYSTAL + limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_CAN_BREAK + +/obj/item/organ/external/tendril/two + name = "second tendril" + organ_tag = BP_R_LEG + +/obj/item/organ/external/tendril/three + name = "third tendril" + organ_tag = BP_L_FOOT + +/obj/item/organ/external/tendril/four + name = "fourth tendril" + organ_tag = BP_R_FOOT diff --git a/mods/species/adherent/organs/organs_internal.dm b/mods/species/adherent/organs/organs_internal.dm new file mode 100644 index 000000000000..8719fee20b9b --- /dev/null +++ b/mods/species/adherent/organs/organs_internal.dm @@ -0,0 +1,178 @@ +#define PROTOCOL_ARTICLE "Protocol article [rand(100,999)]-[uppertext(pick(global.alphabet))] subsection #[rand(10,99)]" +/datum/action/item_action/organ/adherent + button_icon = 'mods/species/adherent/icons/actions.dmi' + +/obj/item/organ/internal/brain/adherent + name = "mentality matrix" + desc = "The self-contained, self-supporting internal 'brain' of an Adherent unit." + icon = 'mods/species/adherent/icons/organs.dmi' + icon_state = "brain" + action_button_name = "Reset Ident" + action_button_desc = "Updates your public name to reflect your current job" + default_action_type = /datum/action/item_action/organ/adherent + + var/next_rename + var/rename_delay = 15 MINUTES + +/obj/item/organ/internal/brain/adherent/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "adherent-brain" + action.button?.update_icon() + +/obj/item/organ/internal/brain/adherent/attack_self(var/mob/user) + . = ..() + if(.) + + var/regex/name_regex = regex("\[A-Z\]{2}-\[A-Z\]{1} \[0-9\]{4}") + name_regex.Find(owner.real_name) + + if(world.time < next_rename) + to_chat(owner, "[PROTOCOL_ARTICLE] forbids changing your ident again so soon.") + return + + var/res = name_regex.match + if(isnull(res)) + to_chat(user, "Nonstandard names are not subject to real-time modification under [PROTOCOL_ARTICLE].") + return + + var/newname = sanitize_safe(input(user, "Enter a new ident.", "Reset Ident") as text, MAX_NAME_LEN) + if(newname) + var/confirm = input(user, "Are you sure you wish your name to become [newname] [res]?","Reset Ident") as anything in list("No", "Yes") + if(confirm == "Yes" && owner && user == owner && !owner.incapacitated() && world.time >= next_rename) + next_rename = world.time + rename_delay + owner.real_name = "[newname] [res]" + if(owner.mind) + owner.mind.name = owner.real_name + owner.SetName(owner.real_name) + to_chat(user, "You are now designated [owner.real_name].") + +/obj/item/organ/internal/powered + icon = 'mods/species/adherent/icons/organs.dmi' + organ_properties = ORGAN_PROP_CRYSTAL + var/maintenance_cost = 1 + var/base_action_state + var/active = FALSE + var/use_descriptor + +/obj/item/organ/internal/powered/Process() + . = ..() + if(owner) + var/obj/item/organ/internal/cell/cell = owner.get_organ(BP_CELL, /obj/item/organ/internal/cell) + if(active && !(cell && cell.use(maintenance_cost))) + active = FALSE + var/decl/pronouns/pronouns = get_pronouns() + to_chat(owner, SPAN_DANGER("Your [name] [pronouns.is] out of power!")) + refresh_action_button() + +/obj/item/organ/internal/powered/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "[base_action_state]-[active ? "on" : "off"]" + action.button?.update_icon() + +/obj/item/organ/internal/powered/attack_self(var/mob/user) + . = ..() + if(.) + sound_to(user, sound('mods/species/adherent/sound/ding.ogg')) + if(is_broken()) + var/decl/pronouns/pronouns = get_pronouns() + to_chat(owner, SPAN_WARNING("\The [src] [pronouns.is] too damaged to function.")) + active = FALSE + else + active = !active + to_chat(owner, "You are [active ? "now" : "no longer"] using your [name] to [use_descriptor].") + refresh_action_button() + +/obj/item/organ/internal/powered/jets + name = "maneuvering jets" + desc = "Gas jets from a Adherent chassis." + action_button_name = "Toggle Maneuvering Pack" + action_button_desc = "Enables or disables your internal jetpack which allow you to maneuver in open space" + default_action_type = /datum/action/item_action/organ/adherent + use_descriptor = "adjust your vector" + organ_tag = BP_JETS + parent_organ = BP_CHEST + gender = PLURAL + icon_state = "jets" + base_action_state = "adherent-pack" + maintenance_cost = 2 + +/obj/item/organ/internal/powered/float + name = "levitation plate" + desc = "A broad, flat disc of exotic matter. Slick to the touch." + action_button_name = "Toggle Antigravity" + action_button_desc = "Enables or disables your levitation disc which allow you to levitate and fly above tables/racks" + default_action_type = /datum/action/item_action/organ/adherent + organ_tag = BP_FLOAT + parent_organ = BP_GROIN + icon_state = "float" + use_descriptor = "hover" + base_action_state = "adherent-float" + +/obj/item/organ/internal/powered/float/Process() + . = ..() + if(owner) + if(active) + owner.pass_flags |= PASS_FLAG_TABLE + owner.start_floating() + else + owner.pass_flags &= ~PASS_FLAG_TABLE + owner.update_floating() // stops conditionally, i.e. on solid ground but not in space + +/obj/item/organ/internal/eyes/adherent + name = "receptor prism" + icon = 'mods/species/adherent/icons/organs.dmi' + icon_state = "eyes" + organ_properties = ORGAN_PROP_CRYSTAL + +/obj/item/organ/internal/eyes/adherent/Initialize() + . = ..() + verbs |= /obj/item/organ/internal/eyes/proc/change_eye_color_verb + +/obj/item/organ/internal/cell/adherent + name = "piezoelectric core" + icon = 'mods/species/adherent/icons/organs.dmi' + icon_state = "cell" + +/obj/item/organ/internal/powered/cooling_fins + name = "cooling fins" + gender = PLURAL + desc = "A lacy filigree of heat-radiating fins." + action_button_name = "Toggle Cooling" + action_button_desc = "Enables or disables your battery-powered internal cooling system" + default_action_type = /datum/action/item_action/organ/adherent + organ_tag = BP_COOLING_FINS + parent_organ = BP_GROIN + icon_state = "fins" + maintenance_cost = 0 + use_descriptor = "radiate heat" + base_action_state = "adherent-fins" + var/max_cooling = 10 + var/target_temp = T20C + +/obj/item/organ/internal/powered/cooling_fins/Process() + if(owner) + var/temp_diff = min(owner.bodytemperature - target_temp, max_cooling) + if(temp_diff >= 1) + maintenance_cost = max(temp_diff, 1) + . = ..() + if(active) + owner.bodytemperature -= temp_diff + else + maintenance_cost = 0 + else + . = ..() + +/mob/living/is_space_movement_permitted(allow_movement = FALSE) + // This is horrible but short of spawning a jetpack inside the organ than locating + // it, I don't really see another viable approach short of a total jetpack refactor. + for(var/obj/item/organ/internal/powered/jets/jet in get_internal_organs()) + if(!jet.is_broken() && jet.active) + // Unlike Bay, we don't check or unset inertia_dir here + // because the spacedrift subsystem checks the return value of this proc + // and unsets inertia_dir if it returns nonzero. + return SPACE_MOVE_PERMITTED + return ..() + +#undef PROTOCOL_ARTICLE diff --git a/sound/voice/chime.ogg b/mods/species/adherent/sound/chime.ogg similarity index 100% rename from sound/voice/chime.ogg rename to mods/species/adherent/sound/chime.ogg diff --git a/sound/voice/ding.ogg b/mods/species/adherent/sound/ding.ogg similarity index 100% rename from sound/voice/ding.ogg rename to mods/species/adherent/sound/ding.ogg diff --git a/mods/species/ascent/_ascent.dme b/mods/species/ascent/_ascent.dme new file mode 100644 index 000000000000..63f077b54d9e --- /dev/null +++ b/mods/species/ascent/_ascent.dme @@ -0,0 +1,45 @@ +#ifndef MODPACK_ASCENT +#define MODPACK_ASCENT +// BEGIN_INCLUDE +#include "ascent.dm" +#include "datum\access.dm" +#include "datum\ai_laws.dm" +#include "datum\antagonist.dm" +#include "datum\codex.dm" +#include "datum\culture.dm" +#include "datum\emotes.dm" +#include "datum\languages.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "datum\traits.dm" +#include "effects\razorweb.dm" +#include "items\_overrides.dm" +#include "items\cell.dm" +#include "items\clothing.dm" +#include "items\clustertool.dm" +#include "items\guns.dm" +#include "items\id_control.dm" +#include "items\molt.dm" +#include "items\rig.dm" +#include "items\suits.dm" +#include "items\tools.dm" +#include "machines\bodyscanner.dm" +#include "machines\fabricator.dm" +#include "machines\magnetotron.dm" +#include "machines\ship_alarm.dm" +#include "machines\ship_machines.dm" +#include "mobs\bodyparts.dm" +#include "mobs\bodyparts_insectoid.dm" +#include "mobs\drone.dm" +#include "mobs\insectoid_egg.dm" +#include "mobs\nymph\_nymph.dm" +#include "mobs\nymph\nymph_attacks.dm" +#include "mobs\nymph\nymph_emotes.dm" +#include "mobs\nymph\nymph_holder.dm" +#include "mobs\nymph\nymph_inventory.dm" +#include "mobs\nymph\nymph_life.dm" +#include "mobs\nymph\nymph_ui.dm" +#include "structures\ship_furniture.dm" +#include "turfs\ship.dm" +// END_INCLUDE +#endif diff --git a/mods/species/ascent/ascent.dm b/mods/species/ascent/ascent.dm new file mode 100644 index 000000000000..ed3dead9c5ca --- /dev/null +++ b/mods/species/ascent/ascent.dm @@ -0,0 +1,22 @@ +#define BODYTYPE_MANTID_SMALL "small mantid body" +#define BODYTYPE_MANTID_LARGE "large mantid body" + +#define BODY_EQUIP_FLAG_ALATE BITFLAG(4) +#define BODY_EQUIP_FLAG_GYNE BITFLAG(5) + +#define BP_SYSTEM_CONTROLLER "system controller" +#define BP_EGG "egg sac" + +#define MANTID_NYMPH_BAN "Mantid Nymph" + +#define MANTIDIFY(_thing, _name, _desc) \ +##_thing/ascent/name = _name; \ +##_thing/ascent/desc = "Some kind of strange alien " + _desc + " technology."; \ +##_thing/ascent/paint_color = COLOR_PURPLE; + +/decl/modpack/ascent + name = "The Ascent" + +/decl/modpack/ascent/pre_initialize() + global.misc_jobban_roles += MANTID_NYMPH_BAN + . = ..() \ No newline at end of file diff --git a/mods/species/ascent/datum/access.dm b/mods/species/ascent/datum/access.dm new file mode 100644 index 000000000000..a047209a0387 --- /dev/null +++ b/mods/species/ascent/datum/access.dm @@ -0,0 +1,5 @@ +var/global/const/access_ascent = "ACCESS_ASCENT" +/datum/access/ascent + id = access_ascent + desc = "Ascent Materiel" + access_type = ACCESS_TYPE_NONE diff --git a/mods/ascent/datum/ai_laws.dm b/mods/species/ascent/datum/ai_laws.dm similarity index 100% rename from mods/ascent/datum/ai_laws.dm rename to mods/species/ascent/datum/ai_laws.dm diff --git a/mods/species/ascent/datum/antagonist.dm b/mods/species/ascent/datum/antagonist.dm new file mode 100644 index 000000000000..f30768cb15b8 --- /dev/null +++ b/mods/species/ascent/datum/antagonist.dm @@ -0,0 +1,51 @@ +/decl/special_role/hunter + name = "Hunter" + name_plural = "Hunters" + flags = ANTAG_HAS_LEADER | ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_CLEAR_EQUIPMENT + leader_welcome_text = "You are a gyne of the Ascent, and command a brood of alates. Your task is to \ + take control of this sector so that you may found a new fortress-nest. Identify and capture local resources, \ + and remove anything that might threaten your progeny." + welcome_text = "You are an alate of the Ascent, tasked with ridding this sector of whatever your matriarch directs you to, \ + preparing it for the foundation of a new fortress-nest. Obey your gyne and bring prosperity to your nest-lineage." + antaghud_indicator = "hudhunter" + antag_indicator = "hudhunter" + hard_cap = 10 + hard_cap_round = 10 + initial_spawn_req = 4 + initial_spawn_target = 6 + rig_type = /obj/item/rig/mantid + +/decl/special_role/hunter/update_antag_mob(var/datum/mind/player, var/preserve_appearance) + . = ..() + var/lineage = create_gyne_name() + if(ishuman(player.current)) + var/mob/living/human/H = player.current + set_gyne_lineage(H, lineage) // This makes all antag ascent have the same lineage on get_random_cultural_name(). + var/species_uid = H.get_species()?.uid + if(!leader && is_species_whitelisted(player.current, /decl/species/mantid/gyne::uid)) + leader = player + if(species_uid != /decl/species/mantid/gyne::uid) + H.set_species(/decl/species/mantid/gyne::uid) + H.set_gender(FEMALE) + else + if(species_uid != /decl/species/mantid::uid) + H.set_species(/decl/species/mantid::uid) + H.set_gender(MALE) + var/decl/background_detail/heritage/ascent/background = GET_DECL(/decl/background_detail/heritage/ascent) + H.real_name = background.get_random_cultural_name(H, H.gender, H.get_species()) + H.name = H.real_name + +/decl/special_role/hunter/equip_role(var/mob/living/human/player) + if(player?.get_species()?.uid == /decl/species/mantid::uid) + rig_type = /obj/item/rig/mantid/gyne + else + rig_type = initial(rig_type) + . = ..() + if(.) + player.put_in_hands(new /obj/item/gun/energy/particle) + +/decl/special_role/hunter/equip_rig(rig_type, mob/living/human/player) + var/obj/item/rig/mantid/rig = ..() + if(rig) + rig.visible_name = player.real_name + return rig diff --git a/mods/species/ascent/datum/codex.dm b/mods/species/ascent/datum/codex.dm new file mode 100644 index 000000000000..2aad34a2114c --- /dev/null +++ b/mods/species/ascent/datum/codex.dm @@ -0,0 +1,14 @@ +/datum/codex_entry/ascent + name = "The Ascent" + associated_paths = list( + /mob/living/silicon/robot/flying/ascent, + /obj/item/multitool/mantid, + /obj/item/weldingtool/electric/mantid, + /obj/item/cell/mantid, + /obj/item/gun/energy/particle, + /obj/item/gun/energy/particle/small + ) + lore_text = "The Ascent is a hostile alien culture located rimward of the settled territories.\ + Little is known about them, and diplomatic channels do not currently exist outside of informal \ + contacts with individual seedships or warships. They are insectoid, crystalline, and seem to have \ + a rigid heirarchial society structured around their massive queen 'gynes'." diff --git a/mods/species/ascent/datum/culture.dm b/mods/species/ascent/datum/culture.dm new file mode 100644 index 000000000000..c67288104b37 --- /dev/null +++ b/mods/species/ascent/datum/culture.dm @@ -0,0 +1,140 @@ +var/global/list/gyne_lineage = list() +/proc/get_gyne_name(mob/recipient) + . = get_gyne_lineage(recipient) + if(!.) + . = create_gyne_name() + set_gyne_lineage(recipient, .) + +/proc/get_gyne_lineage(mob/recipient) + return global.gyne_lineage["\ref[recipient]"] + +/proc/set_gyne_lineage(mob/recipient, value) + global.gyne_lineage["\ref[recipient]"] = value + +/proc/create_gyne_name() + . = "[capitalize(pick(global.gyne_architecture))] [capitalize(pick(global.gyne_geoforms))]" + +//Thanks to: +// - https://en.wikipedia.org/wiki/List_of_landforms +// - https://en.wikipedia.org/wiki/Outline_of_classical_architecture + +var/global/list/gyne_geoforms = list( + "abime", "abyss", "ait", "anabranch", "arc", "arch", "archipelago", "arete", + "arroyo", "atoll", "ayre", "badlands", "bar", "barchan", "barrier", "basin", + "bay", "bayou", "beach", "bight", "blowhole", "blowout", "bluff", "bornhardt", + "braid", "nest", "calanque", "caldera", "canyon" , "cape", "cave", "cenote", + "channel", "cirque", "cliff", "coast", "col", "colony", "cone", "confluence", + "corrie", "cove", "crater", "crevasse", "cryovolcano", "cuesta", "cusps", "yardang", + "dale", "dam", "defile", "dell", "delta", "diatreme", "dike", "divide", + "doab", "doline", "dome", "draw", "dreikanter", "drumlin", "dune", "ejecta", + "erg", "escarpment", "esker", "estuary", "fan", "fault", "field", "firth", + "fissure", "fjard", "fjord", "flat", "flatiron", "floodplain", "foibe", "foreland", + "geyser", "glacier", "glen", "gorge", "graben", "gulf", "gully", "guyot", + "headland", "hill", "hogback", "hoodoo", "horn", "horst", "inlet", "interfluve", + "island", "islet", "isthmus", "kame", "karst", "karst", "kettle", "kipuka", + "knoll", "lagoon", "lake", "lavaka", "levee", "loess", "maar", "machair", + "malpas", "mamelon", "marsh", "meander", "mesa", "mogote", "monadnock", "moraine", + "moulin", "nunatak", "oasis", "outwash", "pediment", "pediplain", "peneplain", "peninsula", + "pingo", "pit" , "plain", "plateau", "plug", "polje", "pond", "potrero", + "pseudocrater", "quarry", "rapid", "ravine", "reef", "ria", "ridge", "riffle", + "river", "sandhill", "sandur", "scarp", "scowle", "scree", "seamount", "shelf", + "shelter", "shield", "shoal", "shore", "sinkhole", "sound", "spine", "spit", + "spring", "spur", "strait", "strandflat", "strath", "stratovolcano", "stream", "subglacier", + "summit", "supervolcano", "surge", "swamp", "table", "tepui", "terrace", "terracette", + "thalweg", "tidepool", "tombolo", "tor", "towhead", "tube", "tunnel", "turlough", + "tuya", "uvala", "vale", "valley", "vent", "ventifact", "volcano", "wadi", + "waterfall", "watershed" +) + +var/global/list/gyne_architecture = list( + "barrel", "annular", "aynali", "baroque", "catalan", "cavetto", "catenary", "cloister", + "corbel", "cross", "cycloidal", "cylindrical", "diamond", "domical", "fan", "lierne", + "muqarnas", "net", "nubian", "ogee", "ogival", "parabolic", "hyperbolic", "volute", + "quadripartite", "rampant", "rear", "rib", "sail", "sexpartite", "shell", "stalactite", + "stellar", "stilted", "surbased", "surmounted", "timbrel", "tierceron", "tripartite", "tunnel", + "grid", "acroterion ", "aedicule", "apollarium", "aegis", "apse", "arch", "architrave", + "archivolt", "amphiprostyle", "atlas", "bracket", "capital", "caryatid", "cella", "colonnade", + "column", "cornice", "crepidoma", "crocket", "cupola", "decastyle", "dome", "eisodos", + "entablature", "epistyle ", "euthynteria", "exedra", "finial", "frieze", "gutta", "imbrex", + "tegula", "keystone", "metope", "naos", "nave", "opisthodomos", "orthostates", "pediment", + "peristyle", "pilaster", "plinth", "portico", "pronaos", "prostyle", "quoin", "stoa", + "suspensura", "term ", "tracery", "triglyph", "sima", "stylobate", "unitary", "sovereign", + "grand", "supreme", "rampant", "isolated", "standalone", "seminal", "pedagogical", "locus", + "figurative", "abstract", "aesthetic", "grandiose", "kantian", "pure", "conserved", "brutalist", + "extemporary", "theological", "theoretical", "centurion", "militant", "eusocial", "prominent", "empirical", + "key", "civic", "analytic", "formal", "atonal", "tonal", "synchronized", "asynchronous", + "harmonic", "discordant", "upraised", "sunken", "life", "order", "chaos", "systemic", + "system", "machine", "mechanical", "digital", "electrical", "electronic", "somatic", "cognitive", + "mobile", "immobile", "motile", "immotile", "environmental", "contextual", "stratified", "integrated", + "ethical", "micro", "macro", "genetic", "intrinsic", "extrinsic", "academic", "literary", + "artisan", "absolute", "absolutist", "autonomous", "collectivist", "bicameral", "colonialist", "federal", + "imperial", "independant", "managed", "multilateral", "neutral", "nonaligned", "parastatal" +) + +/decl/background_detail/heritage/ascent + name = "Ascent Milieu" + language = /decl/language/mantid/nonvocal + default_language = /decl/language/mantid + additional_langs = list(/decl/language/mantid/worldnet, /decl/language/mantid) + hidden = TRUE + description = "The Ascent is an ancient, isolated stellar empire composed of the mantid-cephalopodean \ + Kharmaani and their gaggle of AI servitors. Day to day existence in the Ascent is largely a matter of \ + navigating a bewildering labyrinth of social obligations, gyne power dynamics, factional tithing, \ + protection rackets, industry taxes and plain old interpersonal backstabbing. Both member cultures of \ + this stellar power are eusocial to an extent, and their society is shaped around the teeming masses \ + of workers, soldiers, technicians and 'lesser' citizens supporting a throng of imperious and all-powerful \ + queens." + uid = "heritage_ascent" + +/decl/background_detail/heritage/ascent/get_random_cultural_name(mob/recipient, gender, species) + var/lineage = get_gyne_lineage(recipient) || create_gyne_name() + if(gender == MALE) + return "[random_id(/decl/species/mantid, 10000, 99999)] [lineage]" + return "[random_id(/decl/species/mantid, 1, 99)] [lineage]" + +/decl/background_detail/location/kharmaani + name = "Ascent Core" + language = /decl/language/mantid/nonvocal + description = "The Kharmaani are not terribly imaginative when it comes to naming their worlds. Core, \ + their birth star, supports the humid greenhouse-gas-choked giant called Home, which the majority of the \ + populace call their motherland. While the planet's orbit is thickly populated with habitats, factories \ + and defense platforms, each belonging to a different node in the ever-shifting political web of Ascent \ + social culture, the surface itself is a pristine monument to the Kharmaan evolutionary past." + uid = "location_ascent" + hidden = TRUE + +/decl/background_detail/faction/ascent_alate + name = "Ascent Alate" + language = /decl/language/mantid/nonvocal + description = "The life of an alate is a difficult and frequently short one. Those who survive \ + to maturity have had the violent and uncompromising culture of the Ascent beaten into them with \ + bladed forelimbs for their entire lives. There is no formal schooling within the Kharmaani \ + populations of the Ascent, as alates are so numerous and short-lived that it is something of a \ + waste of resources. However, as they mature, a smart and capable alate will amass an education \ + in practical and theoretical disciplines like piloting, engineering, farming or any number of \ + fields. A particularly lucky (or non-lethally gelded) alate can aspire to a position within the \ + retinue of their mother-gyne, where they will receive directed specialist training and an \ + important role under the careful supervision of the gyne's AI control minds." + hidden = TRUE + uid = "faction_ascent_alate" + +/decl/background_detail/faction/ascent_gyne + name = "Ascent Gyne" + language = /decl/language/mantid/nonvocal + description = "By the time a gyne has survived her 'childhood' and shed the exoskeleton of an \ + alate during a breeding frenzy, she has obtained a master class education in murdering and eating \ + her rivals at the first opportunity, as well as a sideline in a technical or practical field. The \ + rapid growth of her body and brain, and the responsibilities of her position, require every gyne to \ + supplement this with intensive training in management, logistics, military command, sociology, politics \ + and any number of the other critical fields tied into managing a fortress-nest of tens of thousands of \ + individual citizens." + hidden = TRUE + uid = "faction_ascent_gyne" + +/decl/background_detail/religion/kharmaani + name = "Nest-Lineage Veneration" + description = "To the Kharmaani, the gyne is the embodiment of both the soul of the land she rules, and the \ + power and prosperity of the genetic lineage she contains. The closest thing they have to spirituality is the \ + veneration of their mother, and the protection and preservation of their worlds." + hidden = TRUE + uid = "religion_ascent" diff --git a/mods/species/ascent/datum/emotes.dm b/mods/species/ascent/datum/emotes.dm new file mode 100644 index 000000000000..7c34edae0b48 --- /dev/null +++ b/mods/species/ascent/datum/emotes.dm @@ -0,0 +1,59 @@ +/decl/species/mantid + default_emotes = list( + /decl/emote/audible/ascent_purr, + /decl/emote/audible/ascent_hiss, + /decl/emote/audible/ascent_snarl, + /decl/emote/visible/ascent_flicker, + /decl/emote/visible/ascent_glint, + /decl/emote/visible/ascent_glimmer, + /decl/emote/visible/ascent_pulse, + /decl/emote/visible/ascent_shine, + /decl/emote/visible/ascent_dazzle + ) + +/mob/living/silicon/robot/flying/ascent/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/audible/ascent_purr, + /decl/emote/audible/ascent_hiss, + /decl/emote/audible/ascent_snarl + ) + return default_emotes + +/decl/emote/audible/ascent_purr + key = "apurr" + emote_message_3p = "$USER$ purrs." + emote_sound = 'mods/species/ascent/sounds/ascent1.ogg' + +/decl/emote/audible/ascent_hiss + key = "ahiss" + emote_message_3p = "$USER$ hisses." + emote_sound = 'mods/species/ascent/sounds/razorweb.ogg' + +/decl/emote/audible/ascent_snarl + key = "asnarl" + emote_message_3p = "$USER$ snarls." + emote_sound = 'mods/species/ascent/sounds/razorweb_hiss.ogg' + +/decl/emote/visible/ascent_flicker + key = "aflicker" + emote_message_3p = "$USER$ flickers prismatically." + +/decl/emote/visible/ascent_glint + key = "aglint" + emote_message_3p = "$USER$ glints." + +/decl/emote/visible/ascent_glimmer + key = "aglimmer" + emote_message_3p = "$USER$ glimmers." + +/decl/emote/visible/ascent_pulse + key = "apulse" + emote_message_3p = "$USER$ pulses with light." + +/decl/emote/visible/ascent_shine + key = "ashine" + emote_message_3p = "$USER$ shines brightly!" + +/decl/emote/visible/ascent_dazzle + key = "adazzle" + emote_message_3p = "$USER$ dazzles!" diff --git a/mods/species/ascent/datum/languages.dm b/mods/species/ascent/datum/languages.dm new file mode 100644 index 000000000000..6ea22b2a117d --- /dev/null +++ b/mods/species/ascent/datum/languages.dm @@ -0,0 +1,97 @@ +/decl/language/mantid + name = "Ascent-Voc" + desc = "A curt, sharp language developed by the insectoid Ascent for use over comms." + speech_verb = "clicks" + ask_verb = "chirps" + exclaim_verb = "rasps" + colour = "alien" + syllables = list("-","=","+","_","|","/") + space_chance = 0 + key = "|" + flags = LANG_FLAG_RESTRICTED + shorthand = "KV" + machine_understands = FALSE + var/list/correct_mouthbits = list( + /decl/species/mantid::uid, + /decl/species/mantid/gyne::uid + ) + +/decl/language/mantid/can_be_spoken_properly_by(var/mob/speaker) + var/mob/living/S = speaker + if(!istype(S)) + return SPEECH_RESULT_INCAPABLE + if(S.isSynthetic()) + return SPEECH_RESULT_GOOD + if(ishuman(speaker)) + var/mob/living/human/H = speaker + if(H.species.uid in correct_mouthbits) + return SPEECH_RESULT_GOOD + return SPEECH_RESULT_MUDDLED + +/decl/language/mantid/muddle(var/message) + message = replacetext(message, "...", ".") + message = replacetext(message, "!?", ".") + message = replacetext(message, "?!", ".") + message = replacetext(message, "!", ".") + message = replacetext(message, "?", ".") + message = replacetext(message, ",", "") + message = replacetext(message, ";", "") + message = replacetext(message, ":", "") + message = replacetext(message, ".", "...") + message = replacetext(message, "'", "'") + return message + +/decl/language/mantid/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + . = ..(speaker, message, speaker.real_name) + +/decl/language/mantid/nonvocal + key = "]" + name = "Ascent-Glow" + desc = "A complex visual language of bright bioluminescent flashes, 'spoken' natively by the Kharmaani of the Ascent." + colour = "alien" + speech_verb = "flashes" + ask_verb = "gleams" + exclaim_verb = "flares" + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_NO_STUTTER | LANG_FLAG_NONVERBAL + shorthand = "KNV" + +#define MANTID_SCRAMBLE_CACHE_LEN 20 +/decl/language/mantid/nonvocal/scramble(mob/living/speaker, input, list/known_languages) + if(input in scramble_cache) + var/n = scramble_cache[input] + scramble_cache -= input + scramble_cache[input] = n + return n + var/scrambled_text = "" + scramble_cache[input] = make_rainbow("**********************************") + if(scramble_cache.len > MANTID_SCRAMBLE_CACHE_LEN) + scramble_cache.Cut(1, scramble_cache.len-MANTID_SCRAMBLE_CACHE_LEN-1) + return scrambled_text +#undef MANTID_SCRAMBLE_CACHE_LEN + +/decl/language/mantid/nonvocal/can_speak_special(var/mob/living/speaker) + if(istype(speaker) && speaker.isSynthetic()) + return TRUE + else if(ishuman(speaker)) + var/mob/living/human/H = speaker + return istype(H.get_species(), /decl/species/mantid) + return FALSE + +/decl/language/mantid/worldnet + key = "\[" + name = "Worldnet" + desc = "The mantid aliens of the Ascent maintain an extensive self-supporting broadcast network for use in team communications." + colour = "alien" + speech_verb = "flashes" + ask_verb = "gleams" + exclaim_verb = "flares" + flags = LANG_FLAG_RESTRICTED | LANG_FLAG_NO_STUTTER | LANG_FLAG_NONVERBAL | LANG_FLAG_HIVEMIND + shorthand = "KB" + +#define isascentdrone(X) istype(X, /mob/living/silicon/robot/flying/ascent) +/decl/language/mantid/worldnet/check_special_condition(var/mob/living/other) + if(isascentdrone(other)) + return TRUE + if(istype(other) && (locate(/obj/item/organ/internal/controller) in other.get_internal_organs())) + return TRUE + return FALSE diff --git a/mods/species/ascent/datum/species.dm b/mods/species/ascent/datum/species.dm new file mode 100644 index 000000000000..c7bbea3566f1 --- /dev/null +++ b/mods/species/ascent/datum/species.dm @@ -0,0 +1,117 @@ +/datum/appearance_descriptor/age/kharmaani + chargen_min_index = 3 + chargen_max_index = 6 + standalone_value_descriptors = list( + "a larva" = 1, + "a nymph" = 2, + "a juvenile" = 3, + "an adolescent" = 5, + "a young adult" = 12, + "a full adult" = 30, + "a matriarch" = 45, + "a queen" = 60, + "an imperatrix" = 150, + "a crone" = 500 + ) + +/datum/appearance_descriptor/age/kharmaani/gyne + chargen_min_index = 5 + chargen_max_index = 9 + +/decl/blood_type/hemolymph/mantid + name = "crystalline ichor" + antigens = list("Hc") // hemocyanin, more of an octopus thing than a bug thing but whatever, it sounds neat + splatter_colour = "#660066" + +/decl/species/mantid + uid = "species_mantid_alate" + name = "Kharmaan Alate" + name_plural = "Kharmaan Alates" + show_ssd = "quiescent" + hidden_from_codex = TRUE + + base_external_prosthetics_model = null + available_bodytypes = list(/decl/bodytype/crystalline/mantid/alate) + + description = "When human surveyors finally arrived at the outer reaches of explored space, they hoped to find \ + new frontiers and new planets to exploit. They were largely not expecting to have entire expeditions lost \ + amid reports of highly advanced, astonishingly violent mantid-cephlapodean sentients with particle cannons." + organs_icon = 'mods/species/ascent/icons/species/body/organs.dmi' + + flesh_color = "#009999" + move_trail = /obj/effect/decal/cleanable/blood/tracks/snake + + blood_types = list(/decl/blood_type/hemolymph/mantid) + + speech_chance = 100 + speech_sounds = list( + 'mods/species/ascent/sounds/ascent1.ogg', + 'mods/species/ascent/sounds/ascent2.ogg', + 'mods/species/ascent/sounds/ascent3.ogg', + 'mods/species/ascent/sounds/ascent4.ogg', + 'mods/species/ascent/sounds/ascent5.ogg', + 'mods/species/ascent/sounds/ascent6.ogg' + ) + + shock_vulnerability = 0.2 // Crystalline body. + oxy_mod = 0.8 // Don't need as much breathable gas as humans. + toxins_mod = 0.8 // Not as biologically fragile as meatboys. + radiation_mod = 0.5 // Not as biologically fragile as meatboys. + + rarity_value = 3 + gluttonous = 2 + body_temperature = null + + breath_type = /decl/material/gas/methyl_bromide + exhale_type = /decl/material/gas/methane + poison_types = list(/decl/material/gas/chlorine = TRUE) + + available_pronouns = list(/decl/pronouns/male) + + species_flags = SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_MINOR_CUT + spawn_flags = SPECIES_IS_RESTRICTED + + force_background_info = list( + /decl/background_category/citizenship = /decl/background_detail/citizenship/other, + /decl/background_category/heritage = /decl/background_detail/heritage/ascent, + /decl/background_category/homeworld = /decl/background_detail/location/kharmaani, + /decl/background_category/faction = /decl/background_detail/faction/ascent_alate, + /decl/background_category/religion = /decl/background_detail/religion/kharmaani + ) + + pain_emotes_with_pain_level = list( + list(/decl/emote/visible/ascent_shine, /decl/emote/visible/ascent_dazzle) = 80, + list(/decl/emote/visible/ascent_glimmer, /decl/emote/visible/ascent_pulse) = 50, + list(/decl/emote/visible/ascent_flicker, /decl/emote/visible/ascent_glint) = 20, + ) + +/decl/species/mantid/handle_sleeping(var/mob/living/human/H) + return + +/decl/species/mantid/equip_survival_gear(mob/living/wearer, box_type = /obj/item/box/survival) + return + +/decl/species/mantid/gyne + uid = "species_mantid_gyne" + name = "Kharmaan Gyne" + name_plural = "Kharmaan Gynes" + + available_bodytypes = list(/decl/bodytype/crystalline/mantid/gyne) + available_pronouns = list(/decl/pronouns/female) + + gluttonous = 3 + rarity_value = 10 + + blood_volume = 1200 + + bump_flag = HEAVY + push_flags = ALLMOBS + swap_flags = ALLMOBS + + force_background_info = list( + /decl/background_category/citizenship = /decl/background_detail/citizenship/other, + /decl/background_category/heritage = /decl/background_detail/heritage/ascent, + /decl/background_category/homeworld = /decl/background_detail/location/kharmaani, + /decl/background_category/faction = /decl/background_detail/faction/ascent_gyne, + /decl/background_category/religion = /decl/background_detail/religion/kharmaani + ) diff --git a/mods/species/ascent/datum/species_bodytypes.dm b/mods/species/ascent/datum/species_bodytypes.dm new file mode 100644 index 000000000000..87a8462b0f7d --- /dev/null +++ b/mods/species/ascent/datum/species_bodytypes.dm @@ -0,0 +1,98 @@ +/decl/bodytype/crystalline/mantid + abstract_type = /decl/bodytype/crystalline/mantid + eye_flash_mod = 2 // Highly photosensitive. + age_descriptor = /datum/appearance_descriptor/age/kharmaani + appearance_flags = 0 + is_brittle = FALSE + has_limbs = list( + BP_CHEST = list("path" = /obj/item/organ/external/chest/insectoid), + BP_GROIN = list("path" = /obj/item/organ/external/groin/insectoid/mantid), + BP_HEAD = list("path" = /obj/item/organ/external/head/insectoid), + BP_L_ARM = list("path" = /obj/item/organ/external/arm/insectoid), + BP_L_HAND = list("path" = /obj/item/organ/external/hand/insectoid), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/insectoid), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/insectoid), + BP_M_HAND = list("path" = /obj/item/organ/external/hand/insectoid/midlimb), + BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/insectoid/mantid), + BP_L_LEG = list("path" = /obj/item/organ/external/leg/insectoid/mantid), + BP_L_FOOT = list("path" = /obj/item/organ/external/foot/insectoid/mantid), + BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/insectoid/mantid) + ) + + has_organ = list( + BP_HEART = /obj/item/organ/internal/heart/insectoid, + BP_STOMACH = /obj/item/organ/internal/stomach/insectoid, + BP_LUNGS = /obj/item/organ/internal/lungs/insectoid, + BP_LIVER = /obj/item/organ/internal/liver/insectoid, + BP_KIDNEYS = /obj/item/organ/internal/kidneys/insectoid, + BP_BRAIN = /obj/item/organ/internal/brain/insectoid, + BP_EYES = /obj/item/organ/internal/eyes/insectoid, + BP_SYSTEM_CONTROLLER = /obj/item/organ/internal/controller + ) + limb_mapping = list(BP_CHEST = list(BP_CHEST, BP_M_HAND)) + footprints_icon = 'icons/mob/footprints/footprints_snake.dmi' // big tail + + heat_discomfort_strings = list( + "You feel brittle and overheated.", + "Your overheated carapace flexes uneasily.", + "Overheated ichor trickles from your eyes." + ) + cold_discomfort_strings = list( + "Frost forms along your carapace.", + "You hear a faint crackle of ice as you shift your freezing body.", + "Your movements become sluggish under the weight of the chilly conditions." + ) + appearance_descriptors = list( + /datum/appearance_descriptor/height = 0.75, + /datum/appearance_descriptor/body_length = 0.5 + ) + +/decl/bodytype/crystalline/mantid/alate + name = "alate" + bodytype_category = BODYTYPE_MANTID_SMALL + icon_base = 'mods/species/ascent/icons/species/body/alate/body.dmi' + blood_overlays = 'mods/species/ascent/icons/species/body/alate/blood_overlays.dmi' + associated_gender = MALE + bodytype_flag = BODY_EQUIP_FLAG_ALATE + movement_slowdown = -1 + uid = "bodytype_crystalline_alate" + +/decl/bodytype/crystalline/mantid/gyne + name = "gyne" + bodytype_category = BODYTYPE_MANTID_LARGE + icon_base = 'mods/species/ascent/icons/species/body/gyne/body.dmi' + icon_template = 'mods/species/ascent/icons/species/body/gyne/template.dmi' + damage_overlays = 'mods/species/ascent/icons/species/body/gyne/damage_overlays.dmi' + blood_overlays = 'mods/species/ascent/icons/species/body/gyne/blood_overlays.dmi' + pixel_offset_x = -4 + antaghud_offset_y = 18 + antaghud_offset_x = 4 + associated_gender = FEMALE + bodytype_flag = BODY_EQUIP_FLAG_GYNE + eye_flash_mod = 2 // Highly photosensitive. + movement_slowdown = 2 + override_limb_types = list( + BP_GROIN = /obj/item/organ/external/groin/insectoid/mantid/gyne + ) + override_organ_types = list( + BP_EGG = /obj/item/organ/internal/egg_sac/insectoid, + ) + age_descriptor = /datum/appearance_descriptor/age/kharmaani/gyne + appearance_descriptors = list( + /datum/appearance_descriptor/height = 2, + /datum/appearance_descriptor/body_length = 1.25 + ) + z_flags = ZMM_WIDE_LOAD + uid = "bodytype_crystalline_gyne" + +/decl/bodytype/crystalline/mantid/gyne/Initialize() + _equip_adjust = list( + (BP_L_HAND) = list( + "[NORTH]" = list(-4, 12), + "[EAST]" = list(-4, 12), + "[SOUTH]" = list(-4, 12), + "[WEST]" = list(-4, 12) + ) + ) + . = ..() + diff --git a/mods/species/ascent/datum/traits.dm b/mods/species/ascent/datum/traits.dm new file mode 100644 index 000000000000..9faaa45fd242 --- /dev/null +++ b/mods/species/ascent/datum/traits.dm @@ -0,0 +1,34 @@ +/decl/trait/build_references() + . = ..() + LAZYINITLIST(blocked_species) + blocked_species |= /decl/species/mantid::uid + blocked_species |= /decl/species/mantid/gyne::uid + +/decl/trait/ascent + abstract_type = /decl/trait/ascent + +/decl/trait/ascent/build_references() + . = ..() + blocked_species = null + permitted_species = list( + /decl/species/mantid::uid, + /decl/species/mantid/gyne::uid + ) + +// Modifies the exosuit that you spawn with. +/decl/trait/ascent/suit_upgrade + name = "Upgraded Support Systems" + description = "Coming soon!" + category = "Suit Upgrades" + +// Physical modifications like extra organs or different resistances. +/decl/trait/ascent/adaptation + name = "Specialized Molt" + description = "Coming soon!" + category = "Adaptations" + +// Behavioral compulsions enforced by AI +/decl/trait/ascent/derangement + name = "Megalomania" + description = "Coming soon!" + category = "Derangements" diff --git a/mods/species/ascent/effects/razorweb.dm b/mods/species/ascent/effects/razorweb.dm new file mode 100644 index 000000000000..fe859d155f99 --- /dev/null +++ b/mods/species/ascent/effects/razorweb.dm @@ -0,0 +1,170 @@ +/obj/item/razorweb + name = "razorweb wad" + desc = "A wad of crystalline monofilament." + icon = 'mods/species/ascent/icons/razorweb.dmi' + icon_state = "wad" + material = /decl/material/solid/quartz + var/web_type = /obj/effect/razorweb + +/obj/item/razorweb/throw_impact(var/atom/hit_atom) + var/obj/effect/razorweb/web = new web_type(get_turf(hit_atom)) + ..() + if(isliving(hit_atom)) + web.buckle_mob(hit_atom) + web.visible_message(SPAN_DANGER("\The [hit_atom] is tangled in \the [web]!")) + web.entangle(hit_atom, TRUE) + playsound(src, 'mods/species/ascent/sounds/razorweb_twang.ogg', 50) + qdel(src) + +// Hey, did you ever see The Cube (1997) directed by Vincenzo Natali? +/obj/effect/razorweb + name = "razorweb" + desc = "A glimmering web of razor-sharp crystalline strands. Probably not something you want to sprint through." + icon = 'mods/species/ascent/icons/razorweb.dmi' + icon_state = "razorweb" + anchored = TRUE + z_flags = ZMM_MANGLE_PLANES + + var/mob/owner + var/decays = TRUE + var/break_chance = 100 + var/last_light + var/image/gleam + var/image/web + var/static/species_immunity_list = list( + /decl/species/mantid::uid = TRUE, + /decl/species/mantid/gyne::uid = TRUE + ) + +/obj/effect/razorweb/Destroy() + if(owner) + owner = null + . = ..() + +/obj/effect/razorweb/mapped + decays = FALSE + +/obj/effect/razorweb/tough + name = "tough razorweb" + break_chance = 33 + +/obj/effect/razorweb/Initialize(var/mapload) + + . = ..(mapload) + + for(var/obj/effect/razorweb/otherweb in loc) + if(otherweb != src) + return INITIALIZE_HINT_QDEL + + if(decays) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/effect/razorweb, decay)), 15 MINUTES) + + web = image(icon = icon, icon_state = "razorweb") + gleam = emissive_overlay(icon = icon, icon_state = "razorweb-gleam") + var/turf/T = get_turf(src) + if(T) last_light = T.get_lumcount() + icon_state = "" + update_icon() + START_PROCESSING(SSobj, src) + +/obj/effect/razorweb/proc/decay() + playsound(src, 'mods/species/ascent/sounds/razorweb_break.ogg', 50) + qdel_self() + +/obj/effect/razorweb/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + user.visible_message(SPAN_DANGER("\The [user] yanks on \the [src]!")) + entangle(user, TRUE) + qdel_self() + return TRUE + +/obj/effect/razorweb/attackby(var/obj/item/used_item, var/mob/user) + + var/destroy_self + if(used_item.expend_attack_force(user)) + visible_message(SPAN_DANGER("\The [user] breaks \the [src] with \the [used_item]!")) + destroy_self = TRUE + + if(prob(15) && user.try_unequip(used_item)) + visible_message(SPAN_DANGER("\The [used_item] is sliced apart!")) + qdel(used_item) + + if(destroy_self) + qdel(src) + return TRUE + return FALSE + +/obj/effect/razorweb/on_update_icon() + overlays.Cut() + web.alpha = 255 * last_light + overlays = list(web, gleam) + +/obj/effect/razorweb/Process() + var/turf/T = get_turf(src) + if(T) + var/current_light = T.get_lumcount() + if(current_light != last_light) + last_light = current_light + update_icon() + +/obj/effect/razorweb/user_unbuckle_mob(var/mob/user) + var/mob/living/M = unbuckle_mob() + if(M) + if(M != user) + visible_message(SPAN_NOTICE("\The [user] drags \the [M] free of \the [src]!")) + entangle(user, silent = TRUE) + else + visible_message(SPAN_NOTICE("\The [M] writhes free of \the [src]!")) + entangle(M, silent = TRUE) + add_fingerprint(user) + return M + +/obj/effect/razorweb/Crossed(var/atom/movable/AM) + ..() + if(!isliving(AM)) + return + entangle(AM) + +/obj/effect/razorweb/proc/entangle(var/mob/living/L, var/silent) + + if(!istype(L) || !L.simulated || L.current_posture.prone || (MOVING_DELIBERATELY(L) && prob(25)) || L.is_floating) + return + + var/mob/living/human/H + if(ishuman(L)) + H = L + if(species_immunity_list[H.species.uid]) + return + + if(!silent) + visible_message(SPAN_DANGER("\The [L] blunders into \the [src]!")) + + var/severed = FALSE + var/armour_prob = prob(100 * L.get_blocked_ratio(null, BRUTE, damage = ARMOR_MELEE_RESISTANT)) + if(H?.species && prob(35)) + var/obj/item/organ/external/E + var/list/limbs = H.get_external_organs() + if(limbs) + limbs = limbs.Copy() + for(var/obj/item/organ/external/limb in shuffle(limbs)) + if(!istype(limb) || !(limb.limb_flags & ORGAN_FLAG_CAN_AMPUTATE)) + continue + if(!limb.is_vital_to_owner()) + E = limb + break + if(E && !armour_prob) + visible_message(SPAN_DANGER("The crystalline strands slice straight through \the [H]'s [E.amputation_point || E.name]!")) + E.dismember() + severed = TRUE + + if(!severed && !armour_prob) + L.apply_damage(rand(25, 50), used_weapon = src) + visible_message(SPAN_DANGER("The crystalline strands cut deeply into \the [L]!")) + + if(prob(break_chance)) + visible_message(SPAN_DANGER("\The [src] breaks apart!")) + playsound(src, 'mods/species/ascent/sounds/razorweb_break.ogg', 50) + qdel(src) + else + playsound(src, 'mods/species/ascent/sounds/razorweb_twang.ogg', 50) + break_chance = min(break_chance+10, 100) \ No newline at end of file diff --git a/mods/species/ascent/icons/actions.dmi b/mods/species/ascent/icons/actions.dmi new file mode 100644 index 000000000000..f647d8ad2ed9 Binary files /dev/null and b/mods/species/ascent/icons/actions.dmi differ diff --git a/mods/ascent/icons/alate_spacesuit/helmet.dmi b/mods/species/ascent/icons/alate_spacesuit/helmet.dmi similarity index 100% rename from mods/ascent/icons/alate_spacesuit/helmet.dmi rename to mods/species/ascent/icons/alate_spacesuit/helmet.dmi diff --git a/mods/ascent/icons/alate_spacesuit/suit.dmi b/mods/species/ascent/icons/alate_spacesuit/suit.dmi similarity index 100% rename from mods/ascent/icons/alate_spacesuit/suit.dmi rename to mods/species/ascent/icons/alate_spacesuit/suit.dmi diff --git a/mods/ascent/icons/ascent.dmi b/mods/species/ascent/icons/ascent.dmi similarity index 100% rename from mods/ascent/icons/ascent.dmi rename to mods/species/ascent/icons/ascent.dmi diff --git a/mods/species/ascent/icons/ascent_bucket.dmi b/mods/species/ascent/icons/ascent_bucket.dmi new file mode 100644 index 000000000000..b9838cae4f9b Binary files /dev/null and b/mods/species/ascent/icons/ascent_bucket.dmi differ diff --git a/mods/ascent/icons/ascent_doodads.dmi b/mods/species/ascent/icons/ascent_doodads.dmi similarity index 100% rename from mods/ascent/icons/ascent_doodads.dmi rename to mods/species/ascent/icons/ascent_doodads.dmi diff --git a/mods/ascent/icons/ascent_sleepers.dmi b/mods/species/ascent/icons/ascent_sleepers.dmi similarity index 100% rename from mods/ascent/icons/ascent_sleepers.dmi rename to mods/species/ascent/icons/ascent_sleepers.dmi diff --git a/mods/species/ascent/icons/clothing/jetpack.dmi b/mods/species/ascent/icons/clothing/jetpack.dmi new file mode 100644 index 000000000000..8b8639002c8e Binary files /dev/null and b/mods/species/ascent/icons/clothing/jetpack.dmi differ diff --git a/mods/species/ascent/icons/clothing/mask.dmi b/mods/species/ascent/icons/clothing/mask.dmi new file mode 100644 index 000000000000..2142b51e9480 Binary files /dev/null and b/mods/species/ascent/icons/clothing/mask.dmi differ diff --git a/mods/species/ascent/icons/clothing/mask_gyne.dmi b/mods/species/ascent/icons/clothing/mask_gyne.dmi new file mode 100644 index 000000000000..618fcfe9fb20 Binary files /dev/null and b/mods/species/ascent/icons/clothing/mask_gyne.dmi differ diff --git a/mods/species/ascent/icons/clothing/mask_serpentid.dmi b/mods/species/ascent/icons/clothing/mask_serpentid.dmi new file mode 100644 index 000000000000..01886efcd121 Binary files /dev/null and b/mods/species/ascent/icons/clothing/mask_serpentid.dmi differ diff --git a/mods/species/ascent/icons/clothing/under.dmi b/mods/species/ascent/icons/clothing/under.dmi new file mode 100644 index 000000000000..0cbe0d3125b0 Binary files /dev/null and b/mods/species/ascent/icons/clothing/under.dmi differ diff --git a/mods/species/ascent/icons/clothing/under_gyne.dmi b/mods/species/ascent/icons/clothing/under_gyne.dmi new file mode 100644 index 000000000000..4730f251885d Binary files /dev/null and b/mods/species/ascent/icons/clothing/under_gyne.dmi differ diff --git a/mods/species/ascent/icons/clothing/under_harness.dmi b/mods/species/ascent/icons/clothing/under_harness.dmi new file mode 100644 index 000000000000..eea36aa44666 Binary files /dev/null and b/mods/species/ascent/icons/clothing/under_harness.dmi differ diff --git a/mods/ascent/icons/harness/gyne.dmi b/mods/species/ascent/icons/clothing/under_harness_gyne.dmi similarity index 100% rename from mods/ascent/icons/harness/gyne.dmi rename to mods/species/ascent/icons/clothing/under_harness_gyne.dmi diff --git a/mods/species/ascent/icons/clothing/under_harness_serpentid.dmi b/mods/species/ascent/icons/clothing/under_harness_serpentid.dmi new file mode 100644 index 000000000000..4471627f2223 Binary files /dev/null and b/mods/species/ascent/icons/clothing/under_harness_serpentid.dmi differ diff --git a/mods/ascent/icons/doors/base.dmi b/mods/species/ascent/icons/doors/base.dmi similarity index 100% rename from mods/ascent/icons/doors/base.dmi rename to mods/species/ascent/icons/doors/base.dmi diff --git a/mods/ascent/icons/doors/emag.dmi b/mods/species/ascent/icons/doors/emag.dmi similarity index 100% rename from mods/ascent/icons/doors/emag.dmi rename to mods/species/ascent/icons/doors/emag.dmi diff --git a/mods/ascent/icons/doors/lights_bolts.dmi b/mods/species/ascent/icons/doors/lights_bolts.dmi similarity index 100% rename from mods/ascent/icons/doors/lights_bolts.dmi rename to mods/species/ascent/icons/doors/lights_bolts.dmi diff --git a/mods/ascent/icons/doors/lights_deny.dmi b/mods/species/ascent/icons/doors/lights_deny.dmi similarity index 100% rename from mods/ascent/icons/doors/lights_deny.dmi rename to mods/species/ascent/icons/doors/lights_deny.dmi diff --git a/mods/ascent/icons/doors/lights_green.dmi b/mods/species/ascent/icons/doors/lights_green.dmi similarity index 100% rename from mods/ascent/icons/doors/lights_green.dmi rename to mods/species/ascent/icons/doors/lights_green.dmi diff --git a/mods/ascent/icons/doors/panel.dmi b/mods/species/ascent/icons/doors/panel.dmi similarity index 100% rename from mods/ascent/icons/doors/panel.dmi rename to mods/species/ascent/icons/doors/panel.dmi diff --git a/mods/ascent/icons/doors/sparks_broken.dmi b/mods/species/ascent/icons/doors/sparks_broken.dmi similarity index 100% rename from mods/ascent/icons/doors/sparks_broken.dmi rename to mods/species/ascent/icons/doors/sparks_broken.dmi diff --git a/mods/ascent/icons/doors/sparks_damaged.dmi b/mods/species/ascent/icons/doors/sparks_damaged.dmi similarity index 100% rename from mods/ascent/icons/doors/sparks_damaged.dmi rename to mods/species/ascent/icons/doors/sparks_damaged.dmi diff --git a/mods/ascent/icons/doors/welded.dmi b/mods/species/ascent/icons/doors/welded.dmi similarity index 100% rename from mods/ascent/icons/doors/welded.dmi rename to mods/species/ascent/icons/doors/welded.dmi diff --git a/mods/species/ascent/icons/drone.dmi b/mods/species/ascent/icons/drone.dmi new file mode 100644 index 000000000000..5a5c8122256a Binary files /dev/null and b/mods/species/ascent/icons/drone.dmi differ diff --git a/mods/species/ascent/icons/egg.dmi b/mods/species/ascent/icons/egg.dmi new file mode 100644 index 000000000000..c262db26a43c Binary files /dev/null and b/mods/species/ascent/icons/egg.dmi differ diff --git a/mods/species/ascent/icons/furniture/chair_nest.dmi b/mods/species/ascent/icons/furniture/chair_nest.dmi new file mode 100644 index 000000000000..d4e79af000c0 Binary files /dev/null and b/mods/species/ascent/icons/furniture/chair_nest.dmi differ diff --git a/mods/species/ascent/icons/furniture/chair_nest_large.dmi b/mods/species/ascent/icons/furniture/chair_nest_large.dmi new file mode 100644 index 000000000000..b95c2c1a338a Binary files /dev/null and b/mods/species/ascent/icons/furniture/chair_nest_large.dmi differ diff --git a/mods/ascent/icons/harness/alate.dmi b/mods/species/ascent/icons/harness/alate.dmi similarity index 100% rename from mods/ascent/icons/harness/alate.dmi rename to mods/species/ascent/icons/harness/alate.dmi diff --git a/mods/species/ascent/icons/harness/gyne.dmi b/mods/species/ascent/icons/harness/gyne.dmi new file mode 100644 index 000000000000..73344cbf07f0 Binary files /dev/null and b/mods/species/ascent/icons/harness/gyne.dmi differ diff --git a/mods/ascent/icons/harness/serpentid.dmi b/mods/species/ascent/icons/harness/serpentid.dmi similarity index 100% rename from mods/ascent/icons/harness/serpentid.dmi rename to mods/species/ascent/icons/harness/serpentid.dmi diff --git a/mods/species/ascent/icons/magboots/boots.dmi b/mods/species/ascent/icons/magboots/boots.dmi new file mode 100644 index 000000000000..8ac9ce377117 Binary files /dev/null and b/mods/species/ascent/icons/magboots/boots.dmi differ diff --git a/mods/species/ascent/icons/magboots/boots_gyne.dmi b/mods/species/ascent/icons/magboots/boots_gyne.dmi new file mode 100644 index 000000000000..1e42be527bdc Binary files /dev/null and b/mods/species/ascent/icons/magboots/boots_gyne.dmi differ diff --git a/mods/ascent/icons/mantid_charger.dmi b/mods/species/ascent/icons/mantid_charger.dmi similarity index 100% rename from mods/ascent/icons/mantid_charger.dmi rename to mods/species/ascent/icons/mantid_charger.dmi diff --git a/mods/ascent/icons/mantid_hydroponics.dmi b/mods/species/ascent/icons/mantid_hydroponics.dmi similarity index 100% rename from mods/ascent/icons/mantid_hydroponics.dmi rename to mods/species/ascent/icons/mantid_hydroponics.dmi diff --git a/mods/ascent/icons/mantid_smes.dmi b/mods/species/ascent/icons/mantid_smes.dmi similarity index 100% rename from mods/ascent/icons/mantid_smes.dmi rename to mods/species/ascent/icons/mantid_smes.dmi diff --git a/mods/species/ascent/icons/mask.dmi b/mods/species/ascent/icons/mask.dmi new file mode 100644 index 000000000000..70fdc2e289aa Binary files /dev/null and b/mods/species/ascent/icons/mask.dmi differ diff --git a/mods/ascent/icons/nanofabricator.dmi b/mods/species/ascent/icons/nanofabricator.dmi similarity index 100% rename from mods/ascent/icons/nanofabricator.dmi rename to mods/species/ascent/icons/nanofabricator.dmi diff --git a/mods/ascent/icons/particle_rifle/inhands_gyne.dmi b/mods/species/ascent/icons/particle_rifle/inhands_gyne.dmi similarity index 100% rename from mods/ascent/icons/particle_rifle/inhands_gyne.dmi rename to mods/species/ascent/icons/particle_rifle/inhands_gyne.dmi diff --git a/mods/ascent/icons/particle_rifle/inhands_serpentid.dmi b/mods/species/ascent/icons/particle_rifle/inhands_serpentid.dmi similarity index 100% rename from mods/ascent/icons/particle_rifle/inhands_serpentid.dmi rename to mods/species/ascent/icons/particle_rifle/inhands_serpentid.dmi diff --git a/mods/ascent/icons/particle_rifle/rifle.dmi b/mods/species/ascent/icons/particle_rifle/rifle.dmi similarity index 100% rename from mods/ascent/icons/particle_rifle/rifle.dmi rename to mods/species/ascent/icons/particle_rifle/rifle.dmi diff --git a/mods/ascent/icons/particle_rifle/rifle_small.dmi b/mods/species/ascent/icons/particle_rifle/rifle_small.dmi similarity index 100% rename from mods/ascent/icons/particle_rifle/rifle_small.dmi rename to mods/species/ascent/icons/particle_rifle/rifle_small.dmi diff --git a/mods/ascent/icons/razorweb.dmi b/mods/species/ascent/icons/razorweb.dmi similarity index 100% rename from mods/ascent/icons/razorweb.dmi rename to mods/species/ascent/icons/razorweb.dmi diff --git a/mods/species/ascent/icons/rig/rig.dmi b/mods/species/ascent/icons/rig/rig.dmi new file mode 100644 index 000000000000..d9314694ebbd Binary files /dev/null and b/mods/species/ascent/icons/rig/rig.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_boots.dmi b/mods/species/ascent/icons/rig/rig_boots.dmi new file mode 100644 index 000000000000..6661500ac16c Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_boots.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_boots_gyne.dmi b/mods/species/ascent/icons/rig/rig_boots_gyne.dmi new file mode 100644 index 000000000000..5852d70f913a Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_boots_gyne.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_chest.dmi b/mods/species/ascent/icons/rig/rig_chest.dmi new file mode 100644 index 000000000000..8dad00c9779a Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_chest.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_chest_gyne.dmi b/mods/species/ascent/icons/rig/rig_chest_gyne.dmi new file mode 100644 index 000000000000..c5e7628960c7 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_chest_gyne.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_chest_serpentid.dmi b/mods/species/ascent/icons/rig/rig_chest_serpentid.dmi new file mode 100644 index 000000000000..c6daa1a7eed8 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_chest_serpentid.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_gloves.dmi b/mods/species/ascent/icons/rig/rig_gloves.dmi new file mode 100644 index 000000000000..777d3d9c721c Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_gloves.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_gloves_gyne.dmi b/mods/species/ascent/icons/rig/rig_gloves_gyne.dmi new file mode 100644 index 000000000000..3a958b5b1540 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_gloves_gyne.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_gloves_serpentid.dmi b/mods/species/ascent/icons/rig/rig_gloves_serpentid.dmi new file mode 100644 index 000000000000..5a357f76048a Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_gloves_serpentid.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_gyne.dmi b/mods/species/ascent/icons/rig/rig_gyne.dmi new file mode 100644 index 000000000000..ed09e61d8ac8 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_gyne.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_helmet.dmi b/mods/species/ascent/icons/rig/rig_helmet.dmi new file mode 100644 index 000000000000..847341689f4b Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_helmet.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_helmet_gyne.dmi b/mods/species/ascent/icons/rig/rig_helmet_gyne.dmi new file mode 100644 index 000000000000..f3ad37320249 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_helmet_gyne.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_helmet_serpentid.dmi b/mods/species/ascent/icons/rig/rig_helmet_serpentid.dmi new file mode 100644 index 000000000000..a03c063dbdf4 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_helmet_serpentid.dmi differ diff --git a/mods/species/ascent/icons/rig/rig_serpentid.dmi b/mods/species/ascent/icons/rig/rig_serpentid.dmi new file mode 100644 index 000000000000..6e27e1034458 Binary files /dev/null and b/mods/species/ascent/icons/rig/rig_serpentid.dmi differ diff --git a/mods/ascent/icons/species/body/alate/blood_mask.dmi b/mods/species/ascent/icons/species/body/alate/blood_overlays.dmi similarity index 100% rename from mods/ascent/icons/species/body/alate/blood_mask.dmi rename to mods/species/ascent/icons/species/body/alate/blood_overlays.dmi diff --git a/mods/species/ascent/icons/species/body/alate/body.dmi b/mods/species/ascent/icons/species/body/alate/body.dmi new file mode 100644 index 000000000000..d7093628bcf3 Binary files /dev/null and b/mods/species/ascent/icons/species/body/alate/body.dmi differ diff --git a/mods/ascent/icons/species/body/alate/eyes.dmi b/mods/species/ascent/icons/species/body/alate/eyes.dmi similarity index 100% rename from mods/ascent/icons/species/body/alate/eyes.dmi rename to mods/species/ascent/icons/species/body/alate/eyes.dmi diff --git a/mods/ascent/icons/species/body/alate/husk.dmi b/mods/species/ascent/icons/species/body/alate/husk.dmi similarity index 100% rename from mods/ascent/icons/species/body/alate/husk.dmi rename to mods/species/ascent/icons/species/body/alate/husk.dmi diff --git a/mods/ascent/icons/species/body/gyne/blood_mask.dmi b/mods/species/ascent/icons/species/body/gyne/blood_overlays.dmi similarity index 100% rename from mods/ascent/icons/species/body/gyne/blood_mask.dmi rename to mods/species/ascent/icons/species/body/gyne/blood_overlays.dmi diff --git a/mods/species/ascent/icons/species/body/gyne/body.dmi b/mods/species/ascent/icons/species/body/gyne/body.dmi new file mode 100644 index 000000000000..1f2dd7775071 Binary files /dev/null and b/mods/species/ascent/icons/species/body/gyne/body.dmi differ diff --git a/mods/species/ascent/icons/species/body/gyne/damage_overlays.dmi b/mods/species/ascent/icons/species/body/gyne/damage_overlays.dmi new file mode 100644 index 000000000000..4b50afcc0c49 Binary files /dev/null and b/mods/species/ascent/icons/species/body/gyne/damage_overlays.dmi differ diff --git a/mods/ascent/icons/species/body/gyne/eyes.dmi b/mods/species/ascent/icons/species/body/gyne/eyes.dmi similarity index 100% rename from mods/ascent/icons/species/body/gyne/eyes.dmi rename to mods/species/ascent/icons/species/body/gyne/eyes.dmi diff --git a/mods/species/ascent/icons/species/body/gyne/template.dmi b/mods/species/ascent/icons/species/body/gyne/template.dmi new file mode 100644 index 000000000000..74dd877c664a Binary files /dev/null and b/mods/species/ascent/icons/species/body/gyne/template.dmi differ diff --git a/mods/ascent/icons/species/body/organs.dmi b/mods/species/ascent/icons/species/body/organs.dmi similarity index 100% rename from mods/ascent/icons/species/body/organs.dmi rename to mods/species/ascent/icons/species/body/organs.dmi diff --git a/mods/ascent/icons/species/mantid/onmob_lefthand_doodads_alate.dmi b/mods/species/ascent/icons/species/mantid/onmob_lefthand_doodads_alate.dmi similarity index 100% rename from mods/ascent/icons/species/mantid/onmob_lefthand_doodads_alate.dmi rename to mods/species/ascent/icons/species/mantid/onmob_lefthand_doodads_alate.dmi diff --git a/mods/ascent/icons/species/mantid/onmob_lefthand_doodads_gyne.dmi b/mods/species/ascent/icons/species/mantid/onmob_lefthand_doodads_gyne.dmi similarity index 100% rename from mods/ascent/icons/species/mantid/onmob_lefthand_doodads_gyne.dmi rename to mods/species/ascent/icons/species/mantid/onmob_lefthand_doodads_gyne.dmi diff --git a/mods/ascent/icons/species/mantid/onmob_righthand_doodads_alate.dmi b/mods/species/ascent/icons/species/mantid/onmob_righthand_doodads_alate.dmi similarity index 100% rename from mods/ascent/icons/species/mantid/onmob_righthand_doodads_alate.dmi rename to mods/species/ascent/icons/species/mantid/onmob_righthand_doodads_alate.dmi diff --git a/mods/ascent/icons/species/mantid/onmob_righthand_doodads_gyne.dmi b/mods/species/ascent/icons/species/mantid/onmob_righthand_doodads_gyne.dmi similarity index 100% rename from mods/ascent/icons/species/mantid/onmob_righthand_doodads_gyne.dmi rename to mods/species/ascent/icons/species/mantid/onmob_righthand_doodads_gyne.dmi diff --git a/mods/species/ascent/icons/species/nymph.dmi b/mods/species/ascent/icons/species/nymph.dmi new file mode 100644 index 000000000000..2c24e13cc6d1 Binary files /dev/null and b/mods/species/ascent/icons/species/nymph.dmi differ diff --git a/mods/species/ascent/icons/tank.dmi b/mods/species/ascent/icons/tank.dmi new file mode 100644 index 000000000000..5592e4633dfd Binary files /dev/null and b/mods/species/ascent/icons/tank.dmi differ diff --git a/mods/species/ascent/icons/ui_hands.dmi b/mods/species/ascent/icons/ui_hands.dmi new file mode 100644 index 000000000000..d60c12b14431 Binary files /dev/null and b/mods/species/ascent/icons/ui_hands.dmi differ diff --git a/mods/species/ascent/icons/ui_health.dmi b/mods/species/ascent/icons/ui_health.dmi new file mode 100644 index 000000000000..ec3d72314e92 Binary files /dev/null and b/mods/species/ascent/icons/ui_health.dmi differ diff --git a/mods/species/ascent/icons/ui_intent_overlay.dmi b/mods/species/ascent/icons/ui_intent_overlay.dmi new file mode 100644 index 000000000000..d49275852d34 Binary files /dev/null and b/mods/species/ascent/icons/ui_intent_overlay.dmi differ diff --git a/mods/species/ascent/icons/ui_intents.dmi b/mods/species/ascent/icons/ui_intents.dmi new file mode 100644 index 000000000000..0e8d07ec2fec Binary files /dev/null and b/mods/species/ascent/icons/ui_intents.dmi differ diff --git a/mods/species/ascent/icons/ui_interactions_drop.dmi b/mods/species/ascent/icons/ui_interactions_drop.dmi new file mode 100644 index 000000000000..b24e4d6e5aef Binary files /dev/null and b/mods/species/ascent/icons/ui_interactions_drop.dmi differ diff --git a/mods/species/ascent/icons/ui_interactions_maneuver.dmi b/mods/species/ascent/icons/ui_interactions_maneuver.dmi new file mode 100644 index 000000000000..da098d4e743e Binary files /dev/null and b/mods/species/ascent/icons/ui_interactions_maneuver.dmi differ diff --git a/mods/species/ascent/icons/ui_interactions_resist.dmi b/mods/species/ascent/icons/ui_interactions_resist.dmi new file mode 100644 index 000000000000..1363c5b33f07 Binary files /dev/null and b/mods/species/ascent/icons/ui_interactions_resist.dmi differ diff --git a/mods/species/ascent/icons/ui_interactions_throw.dmi b/mods/species/ascent/icons/ui_interactions_throw.dmi new file mode 100644 index 000000000000..bcab914a8a30 Binary files /dev/null and b/mods/species/ascent/icons/ui_interactions_throw.dmi differ diff --git a/mods/species/ascent/icons/ui_inventory.dmi b/mods/species/ascent/icons/ui_inventory.dmi new file mode 100644 index 000000000000..e1785e365a4a Binary files /dev/null and b/mods/species/ascent/icons/ui_inventory.dmi differ diff --git a/mods/species/ascent/icons/ui_molt.dmi b/mods/species/ascent/icons/ui_molt.dmi new file mode 100644 index 000000000000..34cb72aeee05 Binary files /dev/null and b/mods/species/ascent/icons/ui_molt.dmi differ diff --git a/mods/species/ascent/items/_overrides.dm b/mods/species/ascent/items/_overrides.dm new file mode 100644 index 000000000000..3cc8b68959b6 --- /dev/null +++ b/mods/species/ascent/items/_overrides.dm @@ -0,0 +1,10 @@ +/obj/item + var/_alate_onmob_icon + var/_gyne_onmob_icon + +/obj/item/setup_sprite_sheets() + . = ..() + if(_alate_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_MANTID_SMALL, _alate_onmob_icon) + if(_gyne_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_MANTID_LARGE, _gyne_onmob_icon) diff --git a/mods/species/ascent/items/cell.dm b/mods/species/ascent/items/cell.dm new file mode 100644 index 000000000000..ec8022d07811 --- /dev/null +++ b/mods/species/ascent/items/cell.dm @@ -0,0 +1,21 @@ +// Self-charging power cell. +/obj/item/cell/mantid + name = "mantid microfusion plant" + desc = "An impossibly tiny fusion reactor of mantid design." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "plant" + maxcharge = 1500 + w_class = ITEM_SIZE_NORMAL + var/recharge_amount = 12 + +/obj/item/cell/mantid/Initialize() + START_PROCESSING(SSobj, src) + . = ..() + +/obj/item/cell/mantid/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/cell/mantid/Process() + if(charge < maxcharge) + give(recharge_amount) diff --git a/mods/species/ascent/items/clothing.dm b/mods/species/ascent/items/clothing.dm new file mode 100644 index 000000000000..bda45b5bb0ce --- /dev/null +++ b/mods/species/ascent/items/clothing.dm @@ -0,0 +1,93 @@ +/datum/storage/pockets/suit/ascent + storage_slots = 10 + max_w_class = ITEM_SIZE_LARGE + +/decl/outfit/job/ascent + name = "Ascent - Gyne" + mask = /obj/item/clothing/mask/gas/ascent + uniform = /obj/item/clothing/jumpsuit/ascent + id_type = /obj/item/card/id/ascent + shoes = /obj/item/clothing/shoes/magboots/ascent + l_ear = null + pda_type = null + pda_slot = 0 + outfit_flags = 0 + +/decl/outfit/job/ascent/attendant + name = "Ascent - Attendant" + back = /obj/item/rig/mantid + +/decl/outfit/job/ascent/tech + name = "Ascent - Technician" + suit = /obj/item/clothing/suit/ascent + +/obj/item/clothing/mask/gas/ascent + name = "mantid facemask" + desc = "An alien facemask with chunky gas filters and a breathing valve." + filter_water = TRUE + icon = 'mods/species/ascent/icons/clothing/mask.dmi' + _gyne_onmob_icon = 'mods/species/ascent/icons/clothing/mask_gyne.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + filtered_gases = list( + /decl/material/gas/nitrous_oxide, + /decl/material/gas/chlorine, + /decl/material/gas/ammonia, + /decl/material/gas/carbon_monoxide, + /decl/material/gas/methane + ) + flags_inv = 0 + +/obj/item/clothing/shoes/magboots/ascent + name = "mantid mag-claws" + desc = "A set of powerful gripping claws." + icon = 'mods/species/ascent/icons/magboots/boots.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + _gyne_onmob_icon = 'mods/species/ascent/icons/magboots/boots_gyne.dmi' + +/obj/item/clothing/jumpsuit/ascent + name = "mantid undersuit" + desc = "A ribbed, spongy undersuit of some sort. It has a big sleeve for a tail, so it probably isn't for humans." + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + icon = 'mods/species/ascent/icons/clothing/under.dmi' + color = COLOR_DARK_GUNMETAL + _gyne_onmob_icon = 'mods/species/ascent/icons/clothing/under_gyne.dmi' + +/obj/item/clothing/suit/ascent + name = "mantid gear harness" + desc = "A complex tangle of articulated cables and straps." + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + icon_state = ICON_STATE_WORLD + icon = 'mods/species/ascent/icons/clothing/under_harness.dmi' + _gyne_onmob_icon = 'mods/species/ascent/icons/clothing/under_harness_gyne.dmi' + body_parts_covered = 0 + slot_flags = SLOT_OVER_BODY | SLOT_LOWER_BODY + storage = /datum/storage/pockets/suit/ascent + allowed = list( + /obj/item/flashlight, + /obj/item/tank, + /obj/item/suit_cooling_unit, + /obj/item/inflatable_dispenser, + /obj/item/rcd, + /obj/item/gun/energy/particle/small, + /obj/item/multitool/mantid, + /obj/item/clustertool, + /obj/item/weldingtool/electric/mantid, + /obj/item/stack/medical/resin, + /obj/item/chems/drinks/cans/waterbottle/ascent + ) + +/obj/item/clothing/suit/ascent/medical/WillContain() + return list( + /obj/item/stack/medical/resin = 3, + /obj/item/chems/drinks/cans/waterbottle/ascent = 3 + ) + +/obj/item/clothing/suit/ascent/utility/WillContain() + return list( + /obj/item/gun/energy/particle/small, + /obj/item/multitool/mantid, + /obj/item/clustertool = 2, + /obj/item/weldingtool/electric/mantid, + /obj/item/stack/medical/resin, + /obj/item/chems/drinks/cans/waterbottle/ascent + ) diff --git a/mods/species/ascent/items/clustertool.dm b/mods/species/ascent/items/clustertool.dm new file mode 100644 index 000000000000..772cdf4ae407 --- /dev/null +++ b/mods/species/ascent/items/clustertool.dm @@ -0,0 +1,28 @@ +/obj/item/clustertool + name = "alien clustertool" + desc = "A bewilderingly complex knot of tool heads." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "clustertool" + w_class = ITEM_SIZE_SMALL + material = /decl/material/solid/metal/aluminium + +/obj/item/clustertool/Initialize(ml, material_key) + . = ..() + set_extension(src, /datum/extension/tool/variable, list( + TOOL_WRENCH = TOOL_QUALITY_GOOD, + TOOL_WIRECUTTERS = TOOL_QUALITY_GOOD, + TOOL_CROWBAR = TOOL_QUALITY_GOOD, + TOOL_SCREWDRIVER = TOOL_QUALITY_GOOD + )) + +/obj/item/clustertool/on_update_icon() + . = ..() + icon_state = initial(icon_state) + if(IS_WRENCH(src)) + icon_state = "[icon_state]-wrench" + else if(IS_WIRECUTTER(src)) + icon_state = "[icon_state]-wirecutters" + else if(IS_CROWBAR(src)) + icon_state = "[icon_state]-crowbar" + else if(IS_SCREWDRIVER(src)) + icon_state = "[icon_state]-screwdriver" diff --git a/mods/species/ascent/items/guns.dm b/mods/species/ascent/items/guns.dm new file mode 100644 index 000000000000..99a76ce53514 --- /dev/null +++ b/mods/species/ascent/items/guns.dm @@ -0,0 +1,73 @@ +/obj/item/gun/energy/particle + name = "particle lance" + desc = "A long, thick-bodied energy rifle of some kind, clad in a curious indigo polymer and lit from within by Cherenkov radiation. The grip is clearly not designed for human hands." + icon = 'mods/species/ascent/icons/particle_rifle/rifle.dmi' + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_BACK + _base_attack_force = 25 // Heavy as Hell. + projectile_type = /obj/item/projectile/beam/particle + max_shots = 18 + self_recharge = 1 + w_class = ITEM_SIZE_HUGE + one_hand_penalty = 6 + burst_delay = 3 + burst = 3 + accuracy = -1 + charge_meter = 0 + has_safety = FALSE + firemodes = list( + list(mode_name="stun", projectile_type = /obj/item/projectile/beam/stun), + list(mode_name="shock", projectile_type = /obj/item/projectile/beam/stun/shock), + list(mode_name="lethal", projectile_type = /obj/item/projectile/beam/particle) + ) + _gyne_onmob_icon = 'mods/species/ascent/icons/particle_rifle/inhands_gyne.dmi' + +/obj/item/gun/energy/particle/small + name = "particle projector" + desc = "A smaller variant on the Ascent particle lance, usually carried by drones and alates." + icon = 'mods/species/ascent/icons/particle_rifle/rifle_small.dmi' + _base_attack_force = 12 + max_shots = 9 + burst = 1 + one_hand_penalty = 0 + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_HOLSTER + projectile_type = /obj/item/projectile/beam/particle/small + firemodes = list( + list(mode_name="stun", projectile_type = /obj/item/projectile/beam/stun), + list(mode_name="shock", projectile_type = /obj/item/projectile/beam/stun/shock), + list(mode_name="lethal", projectile_type = /obj/item/projectile/beam/particle/small) + ) + + +/obj/item/gun/energy/particle/on_update_icon() + . = ..() + var/obj/item/cell/power_supply = get_cell() + var/datum/firemode/current_mode = firemodes[sel_mode] + set_overlays(list( + "[get_world_inventory_state()]-[istype(current_mode) ? current_mode.name : "lethal"]", + "[get_world_inventory_state()]-charge-[istype(power_supply) ? floor(power_supply.percent()/20) : 0]" + )) + +/obj/item/gun/magnetic/railgun/flechette/ascent + name = "mantid flechette rifle" + desc = "A viciously pronged rifle-like weapon." + has_safety = FALSE + one_hand_penalty = 6 + var/charge_per_shot = 10 + +/obj/item/gun/magnetic/railgun/flechette/ascent/get_cell() + if(isrobot(loc) || istype(loc, /obj/item/rig_module)) + return loc.get_cell() + +/obj/item/gun/magnetic/railgun/flechette/ascent/show_ammo(var/mob/user) + var/obj/item/cell/cell = get_cell() + to_chat(user, "There are [cell ? floor(cell.charge/charge_per_shot) : 0] shot\s remaining.") + +/obj/item/gun/magnetic/railgun/flechette/ascent/check_ammo() + var/obj/item/cell/cell = get_cell() + return cell && cell.charge >= charge_per_shot + +/obj/item/gun/magnetic/railgun/flechette/ascent/use_ammo() + var/obj/item/cell/cell = get_cell() + if(cell) cell.use(charge_per_shot) \ No newline at end of file diff --git a/mods/species/ascent/items/id_control.dm b/mods/species/ascent/items/id_control.dm new file mode 100644 index 000000000000..5a7831346832 --- /dev/null +++ b/mods/species/ascent/items/id_control.dm @@ -0,0 +1,72 @@ +// ID 'card' +/obj/item/card/id/ascent + name = "alien chip" + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "access_card" + desc = "A slender, complex chip of alien circuitry." + access = list(access_ascent) + +/obj/item/card/id/ascent/GetAccess() + var/mob/living/human/H = loc + if(istype(H) && !istype(H.get_species(), /decl/species/mantid)) + . = list() + else + . = ..() + +/obj/item/card/id/ascent/on_update_icon() + SHOULD_CALL_PARENT(FALSE) + return + +/obj/item/card/id/ascent/prevent_tracking() + return TRUE + +/obj/item/card/id/ascent/attack_self(mob/user) + return + +/obj/item/card/id/ascent/show() + return + +// ID implant/organ/interface device. +/obj/item/organ/internal/controller + name = "system controller" + desc = "A fist-sized lump of complex circuitry." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "plant" + parent_organ = BP_CHEST + organ_tag = BP_SYSTEM_CONTROLLER + surface_accessible = TRUE + organ_properties = ORGAN_PROP_PROSTHETIC + var/obj/item/card/id/id_card = /obj/item/card/id/ascent + +/obj/item/organ/internal/controller/do_install(mob/living/human/target, obj/item/organ/external/affected, in_place, update_icon, detached) + . = ..() + if(detached || !owner) + return + var/datum/extension/access_provider/owner_access = get_or_create_extension(owner, /datum/extension/access_provider) + owner_access?.register_id(src) + owner.set_id_info(id_card) + owner.add_language(/decl/language/mantid/worldnet) + +/obj/item/organ/internal/controller/do_uninstall(in_place, detach, ignore_children) + if(owner) + var/datum/extension/access_provider/owner_access = get_extension(owner, /datum/extension/access_provider) + owner_access?.unregister_id(src) + var/mob/living/old_owner = owner + . = ..() + if(old_owner && !(locate(type) in old_owner.get_internal_organs())) + old_owner.remove_language(/decl/language/mantid/worldnet) + +/obj/item/organ/internal/controller/Initialize() + if(ispath(id_card)) + id_card = new id_card(src) + . = ..() + +/obj/item/organ/internal/controller/GetIdCards(list/exceptions) + . = ..() + //Not using is_broken() because it should be able to function when CUT_AWAY is set + if(id_card && _organ_damage < min_broken_damage && !is_type_in_list(id_card, exceptions)) + LAZYDISTINCTADD(., id_card) + +/obj/item/organ/internal/controller/GetAccess() + if(_organ_damage < min_broken_damage) + return id_card?.GetAccess() diff --git a/mods/species/ascent/items/molt.dm b/mods/species/ascent/items/molt.dm new file mode 100644 index 000000000000..0e3843de04f2 --- /dev/null +++ b/mods/species/ascent/items/molt.dm @@ -0,0 +1,8 @@ +/obj/item/ascent_molt + name = "molted carapace" + icon = 'icons/effects/effects.dmi' + icon_state = "cocoon3" + color = COLOR_PURPLE + desc = "The molted carapace of some alien creature." + material = /decl/material/solid/gemstone/crystal + w_class = ITEM_SIZE_SMALL \ No newline at end of file diff --git a/mods/species/ascent/items/rig.dm b/mods/species/ascent/items/rig.dm new file mode 100644 index 000000000000..42df752868c1 --- /dev/null +++ b/mods/species/ascent/items/rig.dm @@ -0,0 +1,283 @@ +// Rigs and gear themselves. +/obj/item/rig/mantid + name = "alate support exosuit" + desc = "A powerful support exosuit with integrated power supply, weapon and atmosphere. It's closer to a mech than a rig." + icon = 'mods/species/ascent/icons/rig/rig.dmi' + suit_type = "support exosuit" + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = 1.1 * ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = 1.1 * ARMOR_LASER_RIFLES, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + armor_type = /datum/extension/armor/ablative + armor_degradation_speed = 0.05 + online_slowdown = 0 + offline_slowdown = 1 + equipment_overlay_icon = null + + air_supply = /obj/item/tank/mantid/reactor + cell = /obj/item/cell/mantid + chest = /obj/item/clothing/suit/space/rig/mantid + helmet = /obj/item/clothing/head/helmet/space/rig/mantid + boots = /obj/item/clothing/shoes/magboots/rig/mantid + gloves = /obj/item/clothing/gloves/rig/mantid + + update_visible_name = TRUE + _gyne_onmob_icon = 'mods/species/ascent/icons/rig/rig_gyne.dmi' + initial_modules = list( + /obj/item/rig_module/vision/thermal, + /obj/item/rig_module/ai_container, + /obj/item/rig_module/electrowarfare_suite, + /obj/item/rig_module/chem_dispenser/mantid, + /obj/item/rig_module/device/multitool, + /obj/item/rig_module/device/cable_coil, + /obj/item/rig_module/device/welder, + /obj/item/rig_module/device/clustertool, + /obj/item/rig_module/mounted/plasmacutter, + /obj/item/rig_module/maneuvering_jets + ) + req_access = list(access_ascent) + var/mantid_caste = /decl/species/mantid::uid + +// Renamed blade. +/obj/item/rig_module/mounted/energy_blade/mantid + name = "nanoblade projector" + desc = "A fusion-powered blade nanofabricator of Ascent design." + interface_name = "nanoblade" + interface_desc = "A fusion-powered blade nanofabricator of Ascent design." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "blade" + usable = FALSE + gun = null + +/obj/item/rig_module/mounted/flechette_rifle + name = "flechette rifle" + desc = "A flechette nanofabricator and launch system of Ascent design." + interface_name = "flechette rifle" + interface_desc = "A flechette nanofabricator and launch system of Ascent design." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "rifle" + gun = /obj/item/gun/magnetic/railgun/flechette/ascent + +/obj/item/rig_module/mounted/particle_rifle + name = "particle rifle" + desc = "A mounted particle rifle of Ascent design." + interface_name = "particle rifle" + interface_desc = "A mounted particle rifle of Ascent design." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "rifle" + gun = /obj/item/gun/energy/particle + +/obj/item/rig_module/device/multitool + name = "mantid integrated multitool" + desc = "A limited-sentience integrated multitool capable of interfacing with any number of systems." + interface_name = "multitool" + interface_desc = "A limited-sentience integrated multitool capable of interfacing with any number of systems." + device = /obj/item/multitool/mantid + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "multitool" + usable = FALSE + selectable = TRUE + +/obj/item/rig_module/device/multitool/get_tool_quality(archetype) + return device?.get_tool_quality(archetype) + +/obj/item/rig_module/device/multitool/get_tool_speed(archetype) + return device?.get_tool_speed(archetype) + +/obj/item/rig_module/device/cable_coil + name = "mantid cable extruder" + desc = "A cable nanofabricator of Ascent design." + interface_name = "cable fabricator" + interface_desc = "A cable nanofabricator of Ascent design." + device = /obj/item/stack/cable_coil/fabricator + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "cablecoil" + usable = FALSE + selectable = TRUE + +/obj/item/rig_module/device/welder + name = "mantid welding arm" + desc = "An electrical cutting torch of Ascent design." + interface_name = "welding arm" + interface_desc = "An electrical cutting torch of Ascent design." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "welder1" + engage_string = "Toggle Welder" + device = /obj/item/weldingtool/electric/mantid + usable = TRUE + selectable = TRUE + +/obj/item/rig_module/device/clustertool + name = "mantid clustertool" + desc = "A complex assembly of self-guiding, modular heads capable of performing most manual tasks." + interface_name = "modular clustertool" + interface_desc = "A complex assembly of self-guiding, modular heads capable of performing most manual tasks." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "clustertool" + engage_string = "Select Mode" + device = /obj/item/clustertool + usable = TRUE + selectable = TRUE + +/obj/item/rig_module/device/clustertool/get_tool_quality(archetype) + return device?.get_tool_quality(archetype) + +/obj/item/rig_module/device/clustertool/get_tool_speed(archetype) + return device?.get_tool_speed(archetype) + +// Atmosphere/jetpack filler. +/obj/item/tank/mantid + name = "mantid gas tank" + icon = 'mods/species/ascent/icons/tank.dmi' + distribute_pressure = ONE_ATMOSPHERE*O2STANDARD + gas_volume = 180 + +/obj/item/tank/mantid/methyl_bromide + starting_pressure = list(/decl/material/gas/methyl_bromide = 6 ATM) + +/obj/item/tank/mantid/oxygen + name = "mantid oxygen tank" + starting_pressure = list(OXYGEN = 6 ATM) + +// Boilerplate due to hard typechecks in jetpack code. Todo: make it an extension. +/obj/item/tank/jetpack/ascent + name = "catalytic maneuvering pack" + desc = "An integrated Ascent gas processing plant and maneuvering pack that continuously synthesises 'breathable' atmosphere and propellant." + icon = 'mods/species/ascent/icons/clothing/jetpack.dmi' + var/refill_gas_type = /decl/material/gas/methyl_bromide + var/gas_regen_amount = 0.03 + var/gas_regen_cap = 30 + +/obj/item/tank/jetpack/ascent/Initialize() + starting_pressure = list() + starting_pressure[refill_gas_type] = 6 ATM + . = ..() + +/obj/item/tank/jetpack/ascent/Process() + ..() + if(air_contents.total_moles < gas_regen_cap) + air_contents.adjust_gas(refill_gas_type, gas_regen_amount) + +/obj/item/tank/mantid/reactor + name = "mantid gas reactor" + desc = "A mantid gas processing plant that continuously synthesises 'breathable' atmosphere." + var/charge_cost = 12 + var/refill_gas_type = /decl/material/gas/methyl_bromide + var/gas_regen_amount = 0.05 + var/gas_regen_cap = 50 + +/obj/item/tank/mantid/reactor/Initialize() + starting_pressure = list() + starting_pressure[refill_gas_type] = 6 ATM + . = ..() + +/obj/item/tank/mantid/reactor/Process() + ..() + var/obj/item/rig/holder = loc + if(air_contents.total_moles < gas_regen_cap && istype(holder) && holder.cell && holder.cell.use(charge_cost)) + air_contents.adjust_gas(refill_gas_type, gas_regen_amount) + +// Chem dispenser. +/obj/item/rig_module/chem_dispenser/mantid + name = "mantid chemical injector" + desc = "A compact chemical dispenser of mantid design." + interface_name = "mantid chemical injector" + interface_desc = "A compact chemical dispenser of mantid design." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "injector" + charges = list( + list("bromide", "bromide", /decl/material/liquid/bromide, 80), + list("crystallizing agent", "crystallizing agent", /decl/material/liquid/crystal_agent, 80), + list("antibiotics", "antibiotics", /decl/material/liquid/antibiotics, 80), + list("painkillers", "painkillers", /decl/material/liquid/painkillers/strong, 80) + ) + +// Rig definitions. +/obj/item/rig/mantid/gyne + name = "gyne support exosuit" + armor = list( + ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_RIFLES, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + mantid_caste = /decl/species/mantid/gyne::uid + initial_modules = list( + /obj/item/rig_module/vision/thermal, + /obj/item/rig_module/ai_container, + /obj/item/rig_module/electrowarfare_suite, + /obj/item/rig_module/chem_dispenser/mantid, + /obj/item/rig_module/mounted/energy_blade/mantid, + /obj/item/rig_module/mounted/flechette_rifle, + /obj/item/rig_module/mounted/particle_rifle, + /obj/item/rig_module/device/multitool, + /obj/item/rig_module/device/cable_coil, + /obj/item/rig_module/device/welder, + /obj/item/rig_module/device/clustertool, + /obj/item/rig_module/mounted/plasmacutter, + /obj/item/rig_module/maneuvering_jets + ) + +/obj/item/rig/mantid/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) + . = ..() + if(!. || slot != slot_back_str || !mantid_caste) + return + var/decl/species/my_species = user?.get_species() + if(my_species?.uid != mantid_caste) + to_chat(user, SPAN_WARNING("Your species cannot wear \the [src].")) + return FALSE + +/obj/item/clothing/head/helmet/space/rig/mantid + light_color = "#00ffff" + desc = "More like a torpedo casing than a helmet." + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + icon = 'mods/species/ascent/icons/rig/rig_helmet.dmi' + _gyne_onmob_icon = 'mods/species/ascent/icons/rig/rig_helmet_gyne.dmi' + +/obj/item/clothing/suit/space/rig/mantid + desc = "It's closer to a mech than a suit." + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + icon = 'mods/species/ascent/icons/rig/rig_chest.dmi' + allowed = list( + /obj/item/clustertool, + /obj/item/gun/energy/particle/small, + /obj/item/weldingtool/electric/mantid, + /obj/item/multitool/mantid, + /obj/item/stack/medical/resin, + /obj/item/chems/drinks/cans/waterbottle/ascent + ) + _gyne_onmob_icon = 'mods/species/ascent/icons/rig/rig_chest_gyne.dmi' + +/obj/item/clothing/shoes/magboots/rig/mantid + icon = 'mods/species/ascent/icons/rig/rig_boots.dmi' + desc = "It's like a highly advanced forklift." + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + _gyne_onmob_icon = 'mods/species/ascent/icons/rig/rig_boots_gyne.dmi' + +/obj/item/clothing/gloves/rig/mantid + icon = 'mods/species/ascent/icons/rig/rig_gloves.dmi' + desc = "They look like a cross between a can opener and a Swiss army knife the size of a shoebox." + bodytype_equip_flags = BODY_EQUIP_FLAG_GYNE | BODY_EQUIP_FLAG_ALATE + _gyne_onmob_icon = 'mods/species/ascent/icons/rig/rig_gloves_gyne.dmi' + +/obj/random/ascent_tool + name = "random Ascent tool" + icon = /obj/item/clustertool::icon + icon_state = /obj/item/clustertool::icon_state + +/obj/random/ascent_tool/spawn_choices() + var/static/list/spawn_choices = list( + /obj/item/clustertool, + /obj/item/weldingtool/electric/mantid, + /obj/item/multitool/mantid, + /obj/item/stack/medical/resin + ) + return spawn_choices diff --git a/mods/species/ascent/items/suits.dm b/mods/species/ascent/items/suits.dm new file mode 100644 index 000000000000..81a2dfc7503d --- /dev/null +++ b/mods/species/ascent/items/suits.dm @@ -0,0 +1,40 @@ +/obj/item/clothing/head/helmet/space/void/ascent + name = "\improper Ascent voidsuit helmet" + desc = "An articulated spacesuit helmet of mantid manufacture." + icon = 'mods/species/ascent/icons/alate_spacesuit/helmet.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_MINOR, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + max_pressure_protection = ENG_VOIDSUIT_MAX_PRESSURE + bodytype_equip_flags = BODY_EQUIP_FLAG_ALATE + +/obj/item/clothing/suit/space/void/ascent + name = "\improper Ascent voidsuit" + desc = "A form-fitting spacesuit of mantid manufacture." + icon = 'mods/species/ascent/icons/alate_spacesuit/suit.dmi' + max_pressure_protection = ENG_VOIDSUIT_MAX_PRESSURE + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_MINOR, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + bodytype_equip_flags = BODY_EQUIP_FLAG_ALATE + allowed = list( + /obj/item/clustertool, + /obj/item/tank/mantid, + /obj/item/gun/energy/particle/small, + /obj/item/weldingtool/electric/mantid, + /obj/item/multitool/mantid, + /obj/item/stack/medical/resin, + /obj/item/chems/drinks/cans/waterbottle/ascent + ) \ No newline at end of file diff --git a/mods/species/ascent/items/tools.dm b/mods/species/ascent/items/tools.dm new file mode 100644 index 000000000000..ddd9fceb544d --- /dev/null +++ b/mods/species/ascent/items/tools.dm @@ -0,0 +1,63 @@ +MANTIDIFY(/obj/item/bag/trash/purple, "sample collection carrier", "material storage") +MANTIDIFY(/obj/item/tool/drill/diamond, "lithobliterator", "drilling") +MANTIDIFY(/obj/item/tank/jetpack/carbondioxide, "maneuvering pack", "propulsion") + +/obj/item/light/tube/ascent + name = "mantid light filament" + color = COLOR_CYAN + b_color = COLOR_CYAN + desc = "Some kind of strange alien lightbulb technology." + +/obj/item/multitool/mantid + name = "mantid multitool" + desc = "An alien microcomputer of some kind." + icon = 'mods/species/ascent/icons/ascent.dmi' + icon_state = "multitool" + +/obj/item/weldingtool/electric/mantid + name = "mantid welding tool" + desc = "An oddly shaped alien welding tool." + icon = 'mods/species/ascent/icons/ascent.dmi' + +/obj/item/mop/advanced/ascent + name = "deck detritus delaminator" + desc = "An alien staff with spongy filaments on one end." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + item_state = "advmop" + +/obj/item/chems/glass/bucket/ascent + name = "portable liquid cleaning agent carrier" + desc = "An alien container of some sort." + icon = 'mods/species/ascent/icons/ascent_bucket.dmi' + +/obj/item/knife/kitchen/cleaver/ascent + name = "xenobiological flenser" + desc = "A mind-boggingly alien tool for flensing flesh." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + icon_state = "xenobutch" + + +/obj/item/chems/drinks/cans/waterbottle/ascent + name = "hydration cylinder" + desc = "An alien portable long term storage device for potable water." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + +/obj/item/food/hydration + name = "hydration ration" + desc = "Approximately ten units of liquid hydration in an edible membrane. Unflavored." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + icon_state = "h2o_ration" + bitesize = 10 + +/obj/item/food/hydration/populate_reagents() + add_to_reagents(/decl/material/liquid/water, 10) + . = ..() + +/obj/item/box/water/ascent + name = "box of hydration cylinders" + desc = "A box full of bottled water." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + icon_state = "box" + +/obj/item/box/water/ascent/WillContain() + return list(/obj/item/chems/drinks/cans/waterbottle/ascent = 7) diff --git a/mods/species/ascent/machines/bodyscanner.dm b/mods/species/ascent/machines/bodyscanner.dm new file mode 100644 index 000000000000..540fd3bb1307 --- /dev/null +++ b/mods/species/ascent/machines/bodyscanner.dm @@ -0,0 +1,28 @@ +/obj/machinery/body_scanconsole/ascent + name = "mantid scanner console" + desc = "Some kind of strange alien console technology." + req_access = list(access_ascent) + icon = 'mods/species/ascent/icons/ascent_sleepers.dmi' + construct_state = /decl/machine_construction/default/no_deconstruct + base_type = /obj/machinery/body_scanconsole + +/obj/machinery/bodyscanner/ascent + name = "mantid body scanner" + desc = "Some kind of strange alien body scanning technology." + icon = 'mods/species/ascent/icons/ascent_sleepers.dmi' + construct_state = /decl/machine_construction/default/no_deconstruct + base_type = /obj/machinery/bodyscanner + +/obj/item/stock_parts/circuitboard/bodyscanner/ascent + name = "circuitboard (ascent body scanner)" + build_path = /obj/machinery/bodyscanner/ascent + +/obj/item/stock_parts/circuitboard/body_scanconsole/ascent + name = "circuitboard (ascent body scanner console)" + build_path = /obj/machinery/body_scanconsole/ascent + +/datum/fabricator_recipe/imprinter/circuit/bodyscanner/ascent + path = /obj/item/stock_parts/circuitboard/bodyscanner/ascent + +/datum/fabricator_recipe/imprinter/circuit/body_scanconsole/ascent + path = /obj/item/stock_parts/circuitboard/body_scanconsole/ascent \ No newline at end of file diff --git a/mods/species/ascent/machines/fabricator.dm b/mods/species/ascent/machines/fabricator.dm new file mode 100644 index 000000000000..917180f08485 --- /dev/null +++ b/mods/species/ascent/machines/fabricator.dm @@ -0,0 +1,30 @@ +/obj/machinery/fabricator/ascent + name = "\improper Ascent nanofabricator" + desc = "A squat, complicated fabrication system clad in purple polymer." + icon = 'mods/species/ascent/icons/nanofabricator.dmi' + icon_state = "nanofab" + base_icon_state = "nanofab" + req_access = list(access_ascent) + base_type = /obj/machinery/fabricator + construct_state = /decl/machine_construction/default/no_deconstruct + species_variation = /decl/species/mantid + +/obj/item/stock_parts/circuitboard/ascent_fabricator + name = "circuitboard (ascent nanofabricator)" + build_path = /obj/machinery/fabricator/ascent + board_type = "machine" + origin_tech = @'{"engineering":2,"programming":2}' + req_components = list( + /obj/item/stock_parts/matter_bin = 3, + /obj/item/stock_parts/manipulator = 1) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/datum/fabricator_recipe/imprinter/circuit/ascent_fabricator + path = /obj/item/stock_parts/circuitboard/ascent_fabricator + species_locked = list( + /decl/species/mantid + ) \ No newline at end of file diff --git a/mods/species/ascent/machines/magnetotron.dm b/mods/species/ascent/machines/magnetotron.dm new file mode 100644 index 000000000000..e4d6f697da90 --- /dev/null +++ b/mods/species/ascent/machines/magnetotron.dm @@ -0,0 +1,84 @@ +// Mutation device for turning alates into gynes. +/obj/machinery/ascent_magnetotron + name = "magnetotron" + desc = "An assemblage of alien machinery with large imposing dynamos." + color = COLOR_PURPLE + icon_state = "weightlifter" + icon = 'icons/obj/structures/weightlifter.dmi' + +/obj/machinery/ascent_magnetotron/proc/display_message(var/message) + var/decl/language/speaking = GET_DECL(/decl/language/mantid/nonvocal) + for(var/mob/M in viewers()) + if(M.can_speak(speaking)) + to_chat(M, "\icon[src] " + SPAN_WARNING("\The [src] flashes, \"[message]\"")) + else + to_chat(M, "\icon[src] " + SPAN_WARNING("\The [src] flashes in a variety of ") + make_rainbow("rainbow hues") + SPAN_WARNING(".")) + +/obj/machinery/ascent_magnetotron/attack_hand(var/mob/user) + + if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS, TRUE)) + return ..() + + var/mob/living/human/target = locate() in contents + if(isnull(target)) + display_message("No biological signature detected in [src].") + return TRUE + + if(target.get_species()?.uid != /decl/species/mantid::uid) + display_message("Invalid biological signature detected. Safety mechanisms engaged, only alates may undergo metamorphosis.") + return TRUE + + visible_message(SPAN_NOTICE("\icon[src] \The [src] begins to crackle and hum with energy as magnetic fields begin to fluctuate.")) + if(!prob(100 / (get_total_gynes() + 1))) + // Oops it killed us. + target.visible_message(SPAN_DANGER("\The [target] shrieks loudly as \the [src] tears them apart!")) + target.gib() + visible_message(SPAN_NOTICE("\icon[src] [src] shuts down with a loud bang, signaling the end of the process.")) + return TRUE + + if(do_after(target, 10 SECONDS, src, TRUE)) + // Convert to gyne successfully. + var/lineage = create_gyne_name() + set_gyne_lineage(target, lineage) + target.real_name = "[rand(1, 99)] [lineage]" + target.SetName(target.real_name) + + target.visible_message(SPAN_NOTICE("[target] molts away their shell, emerging as a new gyne.")) + spark_at(src, cardinal_only = TRUE) + ADJ_STATUS(target, STAT_STUN, 6) + target.change_species(/decl/species/mantid/gyne::uid) + new /obj/effect/temp_visual/emp_burst(loc) + for(var/obj/item/organ/external/E in target.get_external_organs()) + if(prob(60)) + E.add_pain(rand(15,40)) + visible_message(SPAN_NOTICE("\icon[src] [src] shuts down with a loud bang, signaling the end of the process.")) + playsound(src, 'sound/weapons/flashbang.ogg', 100) + return TRUE + + + +/obj/machinery/ascent_magnetotron/proc/get_total_gynes() + for(var/mob/living/human/H in global.living_mob_list_) + if(H.get_species()?.uid == /decl/species/mantid/gyne::uid) + . += 1 + +/obj/item/stock_parts/circuitboard/ascent_magnetotron + name = "circuitboard (Ascent magnetotron)" + build_path = /obj/machinery/ascent_magnetotron + board_type = "machine" + origin_tech = @'{"engineering":2,"magnets":4}' + req_components = list( + /obj/item/stock_parts/matter_bin = 3, + /obj/item/stock_parts/manipulator = 1 + ) + additional_spawn_components = list( + /obj/item/stock_parts/console_screen = 1, + /obj/item/stock_parts/keyboard = 1, + /obj/item/stock_parts/power/apc/buildable = 1 + ) + +/datum/fabricator_recipe/imprinter/circuit/ascent_magnetotron + path = /obj/item/stock_parts/circuitboard/ascent_magnetotron + species_locked = list( + /decl/species/mantid + ) \ No newline at end of file diff --git a/mods/species/ascent/machines/ship_alarm.dm b/mods/species/ascent/machines/ship_alarm.dm new file mode 100644 index 000000000000..f2e24fb28600 --- /dev/null +++ b/mods/species/ascent/machines/ship_alarm.dm @@ -0,0 +1,51 @@ +/decl/environment_data/mantid + important_gasses = list( + /decl/material/gas/oxygen = TRUE, + /decl/material/gas/methyl_bromide = TRUE, + /decl/material/gas/carbon_dioxide = TRUE, + /decl/material/gas/methane = TRUE + ) + dangerous_gasses = list( + /decl/material/gas/carbon_dioxide = TRUE, + /decl/material/gas/methane = TRUE + ) + +MANTIDIFY(/obj/machinery/alarm, "mantid thermostat", "atmospherics") + +/obj/machinery/alarm/ascent + req_access = list(access_ascent) + environment_type = /decl/environment_data/mantid + base_type = /obj/machinery/alarm/ascent + +/obj/machinery/alarm/ascent/Initialize() + . = ..() + var/decl/material/gas_mat = GET_DECL(/decl/material/gas/methyl_bromide) + TLV[gas_mat.gas_name] = list(16, 19, 135, 140) + gas_mat = GET_DECL(/decl/material/gas/methane) + TLV[gas_mat.gas_name] = list(-1.0, -1.0, 5, 10) + +/obj/item/frame/air_alarm/ascent + name = "air alarm frame" + desc = "Used for building air alarms." + build_machine_type = /obj/machinery/alarm/ascent + +/obj/item/frame/air_alarm/ascent/kit + name = "mantid air alarm kit" + desc = "An all-in-one air alarm kit, comes preassembled." + fully_construct = TRUE + +/datum/fabricator_recipe/engineering/airalarm_kit/ascent + path = /obj/item/frame/air_alarm/ascent/kit + species_locked = list( + /decl/species/mantid + ) + +/obj/item/stock_parts/circuitboard/air_alarm/ascent + name = "circuitboard (ascent air alarm)" + build_path = /obj/machinery/alarm/ascent + +/datum/fabricator_recipe/engineering/airalarm/ascent + path = /obj/item/stock_parts/circuitboard/air_alarm/ascent + species_locked = list( + /decl/species/mantid + ) \ No newline at end of file diff --git a/mods/species/ascent/machines/ship_machines.dm b/mods/species/ascent/machines/ship_machines.dm new file mode 100644 index 000000000000..992ceb01e793 --- /dev/null +++ b/mods/species/ascent/machines/ship_machines.dm @@ -0,0 +1,217 @@ +MANTIDIFY(/obj/machinery/apc/hyper, "mantid power node", "power controller") +MANTIDIFY(/obj/machinery/atmospherics/unary/vent_pump/on, "mantid atmosphere outlet", "vent") +MANTIDIFY(/obj/machinery/atmospherics/unary/vent_scrubber/on, "mantid atmosphere intake", "scrubber") +MANTIDIFY(/obj/machinery/hologram/holopad/longrange, "mantid holopad", "holopad") +MANTIDIFY(/obj/machinery/optable, "mantid operating table", "operating table") +MANTIDIFY(/obj/machinery/door/airlock/external/bolted, "mantid airlock", "door") + +/obj/machinery/optable/ascent + construct_state = /decl/machine_construction/default/no_deconstruct + base_type = /obj/machinery/optable + +/obj/machinery/portable_atmospherics/hydroponics/ascent + name = "mantid algae vat" + desc = "Some kind of strange alien hydroponics technology." + icon = 'mods/species/ascent/icons/mantid_hydroponics.dmi' + closed_system = TRUE + construct_state = /decl/machine_construction/default/no_deconstruct + base_type = /obj/machinery/portable_atmospherics/hydroponics + +// No maintenance needed. +/obj/machinery/portable_atmospherics/hydroponics/ascent/Process() + if(dead) + seed = null + update_icon() + if(!seed) + seed = SSplants.seeds["algae"] + update_icon() + waterlevel = 100 + nutrilevel = 10 + pestlevel = 0 + weedlevel = 0 + mutation_level = 0 + plant_health = 100 + sampled = 0 + . = ..() + +/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent/Initialize() + . = ..() + scrubbing_gas -= /decl/material/gas/methyl_bromide + +/obj/machinery/atmospherics/unary/vent_scrubber/on/ascent/shuttle + stock_part_presets = list( + /decl/stock_part_preset/radio/receiver/vent_scrubber/shuttle = 1, + /decl/stock_part_preset/radio/event_transmitter/vent_scrubber/shuttle = 1 + ) +/obj/machinery/recharge_station/ascent + name = "mantid recharging dock" + desc = "An oddly organic aperture stuffed with power connectors." + icon = 'mods/species/ascent/icons/mantid_charger.dmi' + overlay_icon = 'mods/species/ascent/icons/mantid_charger.dmi' + construct_state = /decl/machine_construction/default/no_deconstruct + base_type = /obj/machinery/recharge_station + +MANTIDIFY(/obj/item/chems/chem_disp_cartridge, "canister", "chemical storage") +/obj/item/chems/chem_disp_cartridge/ascent/crystal/populate_reagents() + add_to_reagents(/decl/material/liquid/crystal_agent, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/item/chems/chem_disp_cartridge/ascent/bromide/populate_reagents() + add_to_reagents(/decl/material/liquid/bromide, REAGENT_MAXIMUM_VOLUME(reagents)) + +/obj/machinery/sleeper/ascent + name = "mantid sleeper" + desc = "Some kind of strange alien sleeper technology." + icon = 'mods/species/ascent/icons/ascent_sleepers.dmi' + base_type = /obj/machinery/sleeper + construct_state = /decl/machine_construction/default/no_deconstruct + +/obj/machinery/sleeper/ascent/Initialize(mapload, d, populate_parts) + . = ..() + add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/ascent/crystal()) + add_reagent_canister(null, new /obj/item/chems/chem_disp_cartridge/ascent/bromide()) + +/obj/machinery/fabricator/ascent + name = "\improper Ascent nanofabricator" + desc = "A squat, complicated fabrication system clad in purple polymer." + icon = 'mods/species/ascent/icons/nanofabricator.dmi' + icon_state = "nanofab" + base_icon_state = "nanofab" + req_access = list(access_ascent) + base_type = /obj/machinery/fabricator + construct_state = /decl/machine_construction/default/no_deconstruct + +/obj/machinery/hologram/holopad/longrange/ascent + req_access = list(access_ascent) + +/obj/effect/catwalk_plated/ascent + color = COLOR_GRAY40 + +/obj/machinery/door/airlock/ascent + desc = "Some kind of strange alien door technology." + icon = 'mods/species/ascent/icons/doors/base.dmi' + bolts_file = 'mods/species/ascent/icons/doors/lights_bolts.dmi' + deny_file = 'mods/species/ascent/icons/doors/lights_deny.dmi' + lights_file = 'mods/species/ascent/icons/doors/lights_green.dmi' + panel_file = 'mods/species/ascent/icons/doors/panel.dmi' + sparks_damaged_file = 'mods/species/ascent/icons/doors/sparks_damaged.dmi' + sparks_broken_file = 'mods/species/ascent/icons/doors/sparks_broken.dmi' + welded_file = 'mods/species/ascent/icons/doors/welded.dmi' + emag_file = 'mods/species/ascent/icons/doors/emag.dmi' + +/obj/machinery/door/airlock/ascent/set_airlock_overlays(state) + return + +/obj/machinery/door/airlock/external/bolted/ascent + door_color = COLOR_PURPLE + stripe_color = COLOR_GRAY40 + stock_part_presets = list( + /decl/stock_part_preset/radio/receiver/airlock/shuttle = 1, + /decl/stock_part_preset/radio/event_transmitter/airlock/shuttle = 1 + ) + +/obj/machinery/door/airlock/external/bolted/ascent/open + icon_state = /obj/machinery/door/airlock/ascent::icon_state_open + +/obj/machinery/light/ascent + name = "mantid light" + light_type = /obj/item/light/tube/ascent + accepts_light_type = /obj/item/light/tube/ascent + desc = "Some kind of strange alien lighting technology." + +/obj/machinery/computer/ship/helm/ascent + icon_state = "ascent" + icon_keyboard = "ascent_key" + icon_screen = "ascent_screen" + req_access = list(access_ascent) + construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct + base_type = /obj/machinery/computer/ship/helm + +/obj/machinery/computer/ship/engines/ascent + icon_state = "ascent" + icon_keyboard = "ascent_key" + icon_screen = "ascent_screen" + req_access = list(access_ascent) + construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct + base_type = /obj/machinery/computer/ship/engines + +/obj/machinery/computer/ship/navigation/ascent + icon_state = "ascent" + icon_keyboard = "ascent_key" + icon_screen = "ascent_screen" + req_access = list(access_ascent) + construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct + base_type = /obj/machinery/computer/ship/navigation + +/obj/machinery/computer/ship/sensors/ascent + icon_state = "ascent" + icon_keyboard = "ascent_key" + icon_screen = "ascent_screen" + req_access = list(access_ascent) + construct_state = /decl/machine_construction/default/panel_closed/computer/no_deconstruct + base_type = /obj/machinery/computer/ship/sensors + +// This is an absolutely stupid machine. Basically the same as the debug one with some alterations. +// It is a placeholder for a proper reactor setup (probably a RUST descendant) +/obj/machinery/ascent_reactor + name = "mantid fusion stack" + desc = "A tall, gleaming assemblage of advanced alien machinery. It hums and crackles with restrained power." + icon = 'icons/obj/machines/power/fusion_core.dmi' + icon_state = "core1" + color = COLOR_PURPLE + var/on = TRUE + var/output_power = 9000 KILOWATTS + var/image/field_image + +/obj/machinery/ascent_reactor/attack_hand(mob/user) + if(!user.check_dexterity(DEXTERITY_COMPLEX_TOOLS, TRUE)) + return ..() + if(ishuman(user)) + var/mob/living/human/H = user + if(!istype(H.get_species(), /decl/species/mantid)) + to_chat(H, SPAN_WARNING("You have no idea how to use \the [src].")) + return TRUE + else if(!isascentdrone(user)) + to_chat(user, SPAN_WARNING("You have no idea how to interface with \the [src].")) + return TRUE + user.visible_message(SPAN_NOTICE("\The [user] switches \the [src] [on ? "off" : "on"].")) + on = !on + update_icon() + return TRUE + +/obj/machinery/ascent_reactor/on_update_icon() + . = ..() + + if(!field_image) + field_image = image(icon = 'icons/obj/machines/power/fusion.dmi', icon_state = "emfield_s1") + field_image.color = COLOR_CYAN + field_image.alpha = 50 + field_image.layer = SINGULARITY_LAYER + field_image.appearance_flags |= RESET_COLOR + + var/matrix/M = matrix() + M.Scale(3) + field_image.transform = M + + if(on) + overlays |= field_image + set_light(6, 0.8, COLOR_CYAN) + icon_state = "core1" + else + overlays -= field_image + set_light(0) + icon_state = "core0" + +/obj/machinery/ascent_reactor/Initialize() + . = ..() + update_icon() + +/obj/machinery/ascent_reactor/Process() + if(on) + generate_power(output_power) + +/obj/machinery/power/smes/buildable/power_shuttle/ascent + name = "mantid battery" + desc = "Some kind of strange alien SMES technology." + icon = 'mods/species/ascent/icons/mantid_smes.dmi' + overlay_icon = 'mods/species/ascent/icons/mantid_smes.dmi' + construct_state = /decl/machine_construction/default/no_deconstruct diff --git a/mods/species/ascent/mobs/bodyparts.dm b/mods/species/ascent/mobs/bodyparts.dm new file mode 100644 index 000000000000..ec27acd8e0ff --- /dev/null +++ b/mods/species/ascent/mobs/bodyparts.dm @@ -0,0 +1,92 @@ +/obj/item/organ/external/groin/insectoid/mantid + name = "central support limb" + action_button_name = "Weave Razorweb" + default_action_type = /datum/action/item_action/organ/ascent + var/list/existing_webs = list() + var/max_webs = 4 + var/web_weave_time = 20 SECONDS + var/organ_cooldown + +/obj/item/organ/external/groin/insectoid/mantid/gyne + max_webs = 8 + web_weave_time = 10 SECONDS + +/obj/item/organ/external/groin/insectoid/mantid/Destroy() + for(var/obj/effect/razorweb/web in existing_webs) + web.owner = null + existing_webs.Cut() + . = ..() + +/obj/item/organ/external/groin/insectoid/mantid/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "weave-web-[organ_cooldown ? "off" : "on"]" + action.button?.update_icon() + +/obj/item/organ/external/groin/insectoid/mantid/attack_self(var/mob/user) + . = ..() + if(. && !organ_cooldown) + + if(!isturf(owner.loc)) + to_chat(owner, SPAN_WARNING("You cannot use this ability in this location.")) + return + + if(locate(/obj/effect/razorweb) in owner.loc) + to_chat(owner, SPAN_WARNING("There is already a razorweb here.")) + return + + if(length(existing_webs) >= max_webs) + to_chat(owner, SPAN_WARNING("You cannot maintain more than [max_webs] razorweb\s.")) + return + + playsound(user, 'mods/species/ascent/sounds/razorweb_hiss.ogg', 70) + owner.visible_message(SPAN_WARNING("\The [owner] separates their jaws and begins to weave a web of crystalline filaments...")) + organ_cooldown = TRUE + refresh_action_button() + addtimer(CALLBACK(src, PROC_REF(reset_cooldown)), web_weave_time) + if(do_after(owner, web_weave_time) && length(existing_webs) < max_webs) + playsound(user, 'mods/species/ascent/sounds/razorweb.ogg', 70, 0) + owner.visible_message(SPAN_DANGER("\The [owner] completes a razorweb!")) + var/obj/effect/razorweb/web = new(owner.loc) + existing_webs += web + web.owner = owner + +/obj/item/organ/external/groin/insectoid/mantid/proc/reset_cooldown() + organ_cooldown = FALSE + refresh_action_button() + +/obj/item/organ/external/head/insectoid/mantid + name = "crested head" + action_button_name = "Spit Razorweb" + default_action_type = /datum/action/item_action/organ/ascent + var/organ_cooldown_time = 2.5 MINUTES + var/organ_cooldown + +/obj/item/organ/external/head/insectoid/mantid/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "shot-web-[organ_cooldown ? "off" : "on"]" + action.button?.update_icon() + +/obj/item/organ/external/head/insectoid/mantid/attack_self(var/mob/user) + . = ..() + if(.) + + if(organ_cooldown) + to_chat(owner, SPAN_WARNING("Your filament channel hasn't refilled yet!")) + return + + var/obj/item/razorweb/web = new(get_turf(owner)) + if(owner.put_in_hands(web)) + playsound(user, 'mods/species/ascent/sounds/razorweb.ogg', 100) + to_chat(owner, SPAN_WARNING("You spit up a wad of razorweb, ready to throw!")) + owner.toggle_throw_mode(TRUE) + organ_cooldown = TRUE + refresh_action_button() + addtimer(CALLBACK(src, PROC_REF(reset_cooldown)), organ_cooldown_time) + else + qdel(web) + +/obj/item/organ/external/head/insectoid/mantid/proc/reset_cooldown() + organ_cooldown = FALSE + refresh_action_button() diff --git a/mods/species/ascent/mobs/bodyparts_insectoid.dm b/mods/species/ascent/mobs/bodyparts_insectoid.dm new file mode 100644 index 000000000000..49b9bbe33102 --- /dev/null +++ b/mods/species/ascent/mobs/bodyparts_insectoid.dm @@ -0,0 +1,43 @@ +/datum/action/item_action/organ/ascent + button_icon = 'mods/species/ascent/icons/actions.dmi' + +/obj/item/organ/internal/egg_sac/insectoid + name = "gyne egg-sac" + action_button_name = "Produce Egg" + organ_tag = BP_EGG + default_action_type = /datum/action/item_action/organ/ascent + var/egg_metabolic_cost = 100 + +/obj/item/organ/internal/egg_sac/insectoid/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "egg-on" + action.button?.update_icon() + +/obj/item/organ/internal/egg_sac/insectoid/attack_self(var/mob/user) + . = ..() + var/mob/living/living_user = user + if(.) + if(living_user.incapacitated()) + to_chat(living_user, SPAN_WARNING("You can't produce eggs in your current state.")) + return + if(living_user.nutrition < egg_metabolic_cost) + to_chat(living_user, SPAN_WARNING("You are too ravenously hungry to produce more eggs.")) + return + if(do_after(living_user, 5 SECONDS, living_user, FALSE)) + living_user.adjust_nutrition(-1 * egg_metabolic_cost) + living_user.visible_message(SPAN_NOTICE("\icon[living_user] [living_user] carelessly deposits an egg on \the [get_turf(src)].")) + var/obj/structure/insectoid_egg/egg = new(get_turf(living_user)) // splorp + egg.lineage = get_gyne_lineage(living_user) + +/obj/item/organ/external/foot/insectoid/mantid + name = "left tail tip" + +/obj/item/organ/external/foot/right/insectoid/mantid + name = "right tail tip" + +/obj/item/organ/external/leg/insectoid/mantid + name = "left tail side" + +/obj/item/organ/external/leg/right/insectoid/mantid + name = "right tail side" diff --git a/mods/ascent/mobs/drone.dm b/mods/species/ascent/mobs/drone.dm similarity index 81% rename from mods/ascent/mobs/drone.dm rename to mods/species/ascent/mobs/drone.dm index 14b8ed558eb4..5c972fe7887a 100644 --- a/mods/ascent/mobs/drone.dm +++ b/mods/species/ascent/mobs/drone.dm @@ -3,8 +3,8 @@ display_name = "Ascent" upgrade_locked = TRUE hide_on_manifest = TRUE - sprites = list( - "Drone" = "drone-ascent" + module_sprites = list( + "Drone" = 'mods/species/ascent/icons/drone.dmi' ) // The duplicate clustertools in this list are so that they can set up to // hack doors, windows etc. without having to constantly cycle through tools. @@ -17,9 +17,9 @@ /obj/item/clustertool, /obj/item/soap, /obj/item/mop/advanced, - /obj/item/plunger/robot, + /obj/item/plunger/unbreakable, /obj/item/weldingtool/electric/mantid, - /obj/item/extinguisher, + /obj/item/chems/spray/extinguisher, /obj/item/t_scanner, /obj/item/scanner/gas, /obj/item/scanner/health, @@ -36,17 +36,19 @@ /obj/item/stack/material/cyborg/aluminium, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass, /obj/item/stack/material/cyborg/glass/reinforced, + /obj/item/stack/material/cyborg/fiberglass, /obj/item/stack/cable_coil/cyborg, /obj/item/stack/material/cyborg/plasteel, /obj/item/stack/nanopaste ) synths = list( - /datum/matter_synth/metal = 30000, - /datum/matter_synth/glass = 20000, - /datum/matter_synth/plasteel = 10000, - /datum/matter_synth/nanite = 10000, + /datum/matter_synth/metal = 30000, + /datum/matter_synth/glass = 20000, + /datum/matter_synth/plasteel = 10000, + /datum/matter_synth/nanite = 10000, /datum/matter_synth/wire ) @@ -57,7 +59,7 @@ ) skills = list( - SKILL_BUREAUCRACY = SKILL_ADEPT, + SKILL_LITERACY = SKILL_ADEPT, SKILL_FINANCE = SKILL_EXPERT, SKILL_EVA = SKILL_EXPERT, SKILL_MECH = HAS_PERK, @@ -83,17 +85,18 @@ // Copypasted from repair bot - todo generalize this step. /obj/item/robot_module/flying/ascent/finalize_synths() . = ..() - var/datum/matter_synth/metal/metal = locate() in synths - var/datum/matter_synth/glass/glass = locate() in synths - var/datum/matter_synth/plasteel/plasteel = locate() in synths - var/datum/matter_synth/wire/wire = locate() in synths - var/datum/matter_synth/nanite/nanite = locate() in synths + var/datum/matter_synth/metal/metal = locate() in synths + var/datum/matter_synth/glass/glass = locate() in synths + var/datum/matter_synth/plasteel/plasteel = locate() in synths + var/datum/matter_synth/wire/wire = locate() in synths + var/datum/matter_synth/nanite/nanite = locate() in synths for(var/thing in list( /obj/item/stack/material/cyborg/steel, /obj/item/stack/material/cyborg/aluminium, /obj/item/stack/material/rods/cyborg, /obj/item/stack/tile/floor/cyborg, + /obj/item/stack/tile/roof/cyborg, /obj/item/stack/material/cyborg/glass/reinforced )) var/obj/item/stack/stack = locate(thing) in equipment @@ -101,7 +104,8 @@ for(var/thing in list( /obj/item/stack/material/cyborg/glass/reinforced, - /obj/item/stack/material/cyborg/glass + /obj/item/stack/material/cyborg/glass, + /obj/item/stack/material/cyborg/fiberglass )) var/obj/item/stack/stack = locate(thing) in equipment LAZYDISTINCTADD(stack.synths, glass) @@ -117,7 +121,7 @@ . = ..() -/obj/item/robot_module/flying/ascent/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) +/obj/item/robot_module/flying/ascent/respawn_consumable(var/mob/living/silicon/robot/robot, var/amount) var/obj/item/stack/medical/resin/drone/resin = locate() in equipment if(!resin) resin = new(src, 1) @@ -133,6 +137,8 @@ N.charge_costs = list(1000) /mob/living/silicon/robot/flying/ascent + name = "\improper Ascent drone" + real_name = "\improper Ascent drone" desc = "A small, sleek, dangerous-looking hover-drone." speak_statement = "clicks" speak_exclamation = "rasps" @@ -141,14 +147,14 @@ scrambledcodes = TRUE speed = -2 icon_state = "drone-ascent" - spawn_sound = 'mods/ascent/sounds/ascent1.ogg' + spawn_sound = 'mods/species/ascent/sounds/ascent1.ogg' cell = /obj/item/cell/mantid laws = /datum/ai_laws/ascent idcard = /obj/item/card/id/ascent module = /obj/item/robot_module/flying/ascent req_access = list(access_ascent) silicon_radio = null - var/global/ascent_drone_count = 0 + var/static/ascent_drone_count = 0 /mob/living/silicon/robot/flying/ascent/add_ion_law(law) return FALSE @@ -173,11 +179,11 @@ /mob/living/silicon/robot/flying/ascent/Initialize() . = ..() - name = "[uppertext(pick(GLOB.gyne_geoforms))]-[++ascent_drone_count]" + name = "[uppertext(pick(global.gyne_geoforms))]-[++ascent_drone_count]" // Sorry, you're going to have to actually deal with these guys. /mob/living/silicon/robot/flying/ascent/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) emp_act(2) /mob/living/silicon/robot/flying/ascent/emp_act(severity) - confused = min(confused + rand(3, 5), (severity == 1 ? 40 : 30)) \ No newline at end of file + SET_STATUS_MAX(src, STAT_CONFUSE, rand(3, 5)) \ No newline at end of file diff --git a/mods/species/ascent/mobs/insectoid_egg.dm b/mods/species/ascent/mobs/insectoid_egg.dm new file mode 100644 index 000000000000..f66efcbc97db --- /dev/null +++ b/mods/species/ascent/mobs/insectoid_egg.dm @@ -0,0 +1,124 @@ +var/global/default_gyne + +/decl/ghosttrap/kharmaani_egg + name = "mantid nymph" + ban_checks = list(MANTID_NYMPH_BAN) + ghost_trap_message = "They are hatching from a kharmaan egg now." + +/decl/ghosttrap/kharmaani_egg/forced(var/mob/user) + request_player(new /mob/living/simple_animal/alien/kharmaan(get_turf(user)), "A mantid nymph is ready to hatch and needs a player.") + +/decl/ghosttrap/kharmaani_egg/transfer_personality(mob/candidate, mob/target) + . = ..() + var/obj/structure/insectoid_egg/egg = target.loc + if(!istype(egg)) + return // somehow we're missing an egg + egg.hatch() + +/obj/structure/insectoid_egg + name = "alien egg" + desc = "A semi-translucent alien egg." + max_health = 100 + icon = 'mods/species/ascent/icons/egg.dmi' + icon_state = "egg" + + var/maturity_rate = 1 MINUTES // How often to do a gestation tick. + var/last_tick // When we last did a gestation tick. + var/maturity = 0 // When this reaches 100, the egg is viable and ready to hatch. + var/min_temperature = 23 CELSIUS // The minimum temperature for the egg to gestate. + var/max_temperature = 30 CELSIUS // The maximum temperature for the egg to gestate. + + var/lineage // A string containing the gyne's name. + var/hatching = FALSE // If we're in the process of hatching. + var/hatched = FALSE // Whether or not this egg has already hatched. + + material = /decl/material/solid/gemstone/crystal + +/obj/structure/insectoid_egg/Initialize() + . = ..() + START_PROCESSING(SSprocessing, src) + if(!global.default_gyne) + global.default_gyne = create_gyne_name() + lineage = global.default_gyne + +/obj/structure/insectoid_egg/Destroy() + STOP_PROCESSING(SSprocessing, src) + . = ..() + +/obj/structure/insectoid_egg/on_update_icon() + ..() + if(hatched || !current_health) + icon_state = "egg_broken" + else if(hatching) + icon_state = "egg_break" + else if(maturity == 100) + icon_state = "egg_ready" + else + icon_state = "egg" + +/obj/structure/insectoid_egg/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if(hatched || !current_health) + . += "\icon[src] \The [src] lays in shambles, having [hatched ? "already hatched" : "been broken"]." + return + switch(maturity) + if(0 to 5) + . += "\icon[src] \The [src] is freshly laid and sticky." + if(5 to 15) + . += "\icon[src] \The [src] is small and still to the touch." + if(15 to 30) + . += "\icon[src] \The [src] has swollen in size; a faint glow can be seen inside the shell." + if(30 to 50) + . += "\icon[src] \The [src] emanates a faint glow and moves from time to time." + if(50 to 75) + . += "\icon[src] \The [src] appears to be close to hatching." + else + . += "\icon[src] \The [src] is lively and appears ready to hatch at any moment." + +/obj/structure/insectoid_egg/Process() + if(!current_health || hatched || hatching || (world.time <= (last_tick + maturity_rate))) + return + + last_tick = world.time + var/turf/T = get_turf(src) + if(!T) + return + + // Too high of temp will damage eggs. + if(T.temperature > (max_temperature * 1.5)) + current_health = max(0, current_health - 5) + + if(T.temperature < min_temperature || T.temperature > max_temperature) + return + + var/ready_to_hatch = maturity != 100 + maturity = min(100, maturity + 1) + ready_to_hatch = maturity == 100 && !ready_to_hatch // Lazy flip from change. + if(ready_to_hatch) + var/mob/living/simple_animal/alien/kharmaan/new_nymph = mature() // prepare a nymph in the egg + var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/kharmaani_egg) + G.request_player(new_nymph, "A mantid nymph is ready to hatch and needs a player.") + +/obj/structure/insectoid_egg/proc/mature(var/client/C) + if(!current_health || maturity != 100 || hatched || hatching) + return null + var/mob/living/simple_animal/alien/kharmaan/new_nymph = new(src) // Spawn in the egg. + new_nymph.lastarea = get_area(src) + new_nymph.real_name = "[random_id(/decl/species/mantid, 10000, 99999)] [lineage]" + if(C) + new_nymph.key = C.key + visible_message(SPAN_NOTICE("\icon[src] \The [src] trembles and cracks as it begins to hatch.")) + return new_nymph + +/obj/structure/insectoid_egg/proc/hatch() + hatching = TRUE + update_icon() + addtimer(CALLBACK(src, PROC_REF(finish_hatching)), 2.5 SECONDS) + +/obj/structure/insectoid_egg/proc/finish_hatching() + hatched = TRUE + hatching = FALSE + update_icon() + for(var/mob/M in src) + M.forceMove(get_turf(src)) // Pop! + visible_message(SPAN_NOTICE("\icon[src] \The [M] hatches out of \the [src].")) \ No newline at end of file diff --git a/mods/species/ascent/mobs/nymph/_nymph.dm b/mods/species/ascent/mobs/nymph/_nymph.dm new file mode 100644 index 000000000000..a1ea74d77e3c --- /dev/null +++ b/mods/species/ascent/mobs/nymph/_nymph.dm @@ -0,0 +1,53 @@ +#define ANYMPH_SCREEN_LOC_HELD "RIGHT-8:16,BOTTOM:5" +#define ANYMPH_SCREEN_LOC_HAT "RIGHT-7:16,BOTTOM:5" +#define ANYMPH_SCREEN_LOC_MOLT "RIGHT-6:16,BOTTOM:5" +#define ANYMPH_SCREEN_LOC_INTENT "RIGHT-2,BOTTOM:5" +#define ANYMPH_SCREEN_LOC_HEALTH "RIGHT-1:28,CENTER-1:13" + +#define ANYMPH_MAX_CRYSTALS 20000 +#define ANYMPH_CRYSTAL_MOLT 2000 // How much it takes to molt. +#define ANYMPH_NUTRITION_MOLT 125 // How much nutrition it takes to molt. +#define ANYMPH_TIME_MOLT 300 // How long to wait between molts. + +/mob/living/simple_animal/alien/kharmaan + name = "mantid nymph" + desc = "It's a little alien skittery critter. Hiss." + icon = 'mods/species/ascent/icons/species/nymph.dmi' + icon_state = ICON_STATE_WORLD + death_message = "expires with a pitiful hiss..." + max_health = 60 + available_maneuvers = list(/decl/maneuver/leap) + + only_species_language = 1 + speak_emote = list("hisses", "chitters") + universal_understand = FALSE + universal_speak = FALSE + + can_pull_size = ITEM_SIZE_SMALL + can_pull_mobs = MOB_PULL_SMALLER + + holder_type = /obj/item/holder/ascent_nymph + possession_candidate = TRUE + atom_flags = ATOM_FLAG_NO_CHEM_CHANGE + hud_used = /datum/hud/ascent_nymph + + var/crystal_reserve = 1000 + var/last_molt = 0 + var/molt + +/mob/living/simple_animal/alien/kharmaan/setup_languages() + add_language(/decl/language/mantid) + add_language(/decl/language/mantid/nonvocal) + +/mob/living/simple_animal/alien/kharmaan/get_jump_distance() + return 3 + +/mob/living/simple_animal/alien/kharmaan/Initialize(var/mapload) + update_icon() + . = ..(mapload) + add_inventory_slot(new /datum/inventory_slot/head/simple) + add_held_item_slot(new /datum/inventory_slot/gripper/mouth/nymph/ascent) + set_extension(src, /datum/extension/base_icon_state, icon_state) + +/mob/living/simple_animal/alien/kharmaan/get_dexterity(var/silent) + return (DEXTERITY_EQUIP_ITEM) diff --git a/mods/species/ascent/mobs/nymph/nymph_attacks.dm b/mods/species/ascent/mobs/nymph/nymph_attacks.dm new file mode 100644 index 000000000000..d5e982457300 --- /dev/null +++ b/mods/species/ascent/mobs/nymph/nymph_attacks.dm @@ -0,0 +1,11 @@ +/mob/living/simple_animal/alien/kharmaan/ResolveUnarmedAttack(var/atom/A) + + . = ..() + if(.) + return + + if(ismob(A)) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + visible_message(SPAN_NOTICE("\The [src] butts its head into \the [A].")) + return TRUE + return FALSE diff --git a/mods/species/ascent/mobs/nymph/nymph_emotes.dm b/mods/species/ascent/mobs/nymph/nymph_emotes.dm new file mode 100644 index 000000000000..e43c99f45b66 --- /dev/null +++ b/mods/species/ascent/mobs/nymph/nymph_emotes.dm @@ -0,0 +1,23 @@ +/mob/living/simple_animal/alien/kharmaan/get_default_emotes() + var/static/list/default_emotes = list( + /decl/emote/visible, + /decl/emote/visible/scratch, + /decl/emote/visible/drool, + /decl/emote/visible/nod, + /decl/emote/visible/sway, + /decl/emote/visible/sulk, + /decl/emote/visible/twitch, + /decl/emote/visible/roll, + /decl/emote/visible/shake, + /decl/emote/visible/jump, + /decl/emote/visible/shiver, + /decl/emote/visible/collapse, + /decl/emote/audible/hiss, + /decl/emote/audible, + /decl/emote/audible/scretch, + /decl/emote/audible/choke, + /decl/emote/audible/gnarl, + /decl/emote/audible/bug_hiss, + /decl/emote/audible/bug_chitter + ) + return default_emotes diff --git a/mods/species/ascent/mobs/nymph/nymph_holder.dm b/mods/species/ascent/mobs/nymph/nymph_holder.dm new file mode 100644 index 000000000000..ec430c06f8e1 --- /dev/null +++ b/mods/species/ascent/mobs/nymph/nymph_holder.dm @@ -0,0 +1,16 @@ +/obj/item/holder/ascent_nymph + origin_tech = @'{"magnets":3,"biotech":5}' + slot_flags = SLOT_HEAD | SLOT_OVER_BODY | SLOT_HOLSTER + armor = list( + ARMOR_BIO = ARMOR_BIO_RESISTANT + ) + +// Yes, you can wear a nymph on your head instead of a radiation mask. +/obj/item/holder/ascent_nymph/equipped(var/mob/living/user, var/slot) + if(slot == BP_L_HAND || slot == BP_R_HAND) + body_parts_covered = SLOT_ARMS + else if(slot == slot_head_str) + body_parts_covered = SLOT_HEAD + else if(slot == slot_wear_suit_str) + body_parts_covered = SLOT_UPPER_BODY + . = ..() \ No newline at end of file diff --git a/mods/species/ascent/mobs/nymph/nymph_inventory.dm b/mods/species/ascent/mobs/nymph/nymph_inventory.dm new file mode 100644 index 000000000000..e79adb9931d0 --- /dev/null +++ b/mods/species/ascent/mobs/nymph/nymph_inventory.dm @@ -0,0 +1,16 @@ +/mob/living/simple_animal/alien/kharmaan/proc/contains_crystals(var/obj/item/prop) + . += prop.matter[/decl/material/solid/sand] + . += prop.matter[/decl/material/solid/gemstone/crystal] + . += prop.matter[/decl/material/solid/quartz] + . += prop.matter[/decl/material/solid/glass] + +/datum/inventory_slot/gripper/mouth/nymph/ascent/equipped(var/mob/living/user, var/obj/item/prop, var/redraw_mob = TRUE, var/delete_old_item = TRUE) + var/mob/living/simple_animal/alien/kharmaan/nimp = user + var/crystals = istype(nimp) ? nimp.contains_crystals(prop) : 0 + . = ..() + if(. && crystals) + nimp.crystal_reserve = min(ANYMPH_MAX_CRYSTALS, nimp.crystal_reserve + crystals) + if(nimp.crystal_reserve >= ANYMPH_MAX_CRYSTALS) + to_chat(src, SPAN_WARNING("You've filled yourself with as much crystalline matter as you can!")) + if(!QDELETED(prop)) + qdel(prop) diff --git a/mods/species/ascent/mobs/nymph/nymph_life.dm b/mods/species/ascent/mobs/nymph/nymph_life.dm new file mode 100644 index 000000000000..747ce73f5f0b --- /dev/null +++ b/mods/species/ascent/mobs/nymph/nymph_life.dm @@ -0,0 +1,67 @@ +/mob/living/simple_animal/alien/kharmaan/handle_nutrition_and_hydration() + . = ..() + // Generate some crystals over time. + if(nutrition >= 300 && crystal_reserve < ANYMPH_MAX_CRYSTALS) + crystal_reserve = min(ANYMPH_MAX_CRYSTALS, crystal_reserve + 15) + adjust_nutrition(DEFAULT_HUNGER_FACTOR * -4) + else if(nutrition >= 200 && crystal_reserve < ANYMPH_MAX_CRYSTALS) + crystal_reserve = min(ANYMPH_MAX_CRYSTALS, crystal_reserve + 10) + adjust_nutrition(DEFAULT_HUNGER_FACTOR * -3) + else if(nutrition >= 100 && crystal_reserve < ANYMPH_MAX_CRYSTALS) + crystal_reserve = min(ANYMPH_MAX_CRYSTALS, crystal_reserve + 5) + adjust_nutrition(DEFAULT_HUNGER_FACTOR * -2) + else + adjust_nutrition(DEFAULT_HUNGER_FACTOR * -1) + if(hydration > 0) + adjust_hydration(DEFAULT_THIRST_FACTOR * -1) + +/mob/living/simple_animal/alien/kharmaan/Stat() + . = ..() + if(client && statpanel("Status")) + stat("Nutrition", "[get_nutrition()]/[ANYMPH_NUTRITION_MOLT]") + stat("Crystal reserve", "[crystal_reserve]/[ANYMPH_CRYSTAL_MOLT]") + +/mob/living/simple_animal/alien/kharmaan/proc/can_molt() + if(crystal_reserve < ANYMPH_CRYSTAL_MOLT) + to_chat(src, SPAN_WARNING("You don't have enough crystalline matter stored up to molt right now.")) + return FALSE + if(nutrition < ANYMPH_NUTRITION_MOLT) + to_chat(src, SPAN_WARNING("You're too hungry to molt right now!")) + return FALSE + if(world.time - last_molt < ANYMPH_TIME_MOLT) + to_chat(src, SPAN_WARNING("You haven't waited long enough between molts.")) + return FALSE + return TRUE + +/mob/living/simple_animal/alien/kharmaan/proc/molt() + if(!can_molt()) + return + + molt = min(molt + 1, 5) + visible_message("\icon[src] [src] begins to shimmy and shake out of its old skin.") + if(molt == 5) + if(do_after(src, 10 SECONDS, src, FALSE)) + var/mob/living/human/H = new(get_turf(src), /decl/species/mantid::uid) + set_gyne_lineage(H, get_gyne_lineage(H)) + H.real_name = "[random_id(/decl/species/mantid, 10000, 99999)] [get_gyne_name(H)]" + H.nutrition = nutrition * 0.25 // Homgry after molt. + mind.transfer_to(H) + qdel(src) + H.visible_message("\icon[H] [H] emerges from its molt as a new alate.") + new/obj/item/ascent_molt(get_turf(src)) + else + visible_message("\icon[src] [src] abruptly stops molting.") + return + + if(do_after(src, 5 SECONDS, src, FALSE)) + var/matrix/M = matrix() + M.Scale(1 + (molt / 10)) + animate(src, transform = M, time = 2, easing = QUAD_EASING) + transform = M + last_molt = world.time + nutrition = max(0, nutrition - ANYMPH_NUTRITION_MOLT) + crystal_reserve = max(0, crystal_reserve - ANYMPH_CRYSTAL_MOLT) + new /obj/item/ascent_molt(get_turf(src)) + + else + visible_message("\icon[src] [src] abruptly stops molting.") \ No newline at end of file diff --git a/mods/species/ascent/mobs/nymph/nymph_ui.dm b/mods/species/ascent/mobs/nymph/nymph_ui.dm new file mode 100644 index 000000000000..0539953d693e --- /dev/null +++ b/mods/species/ascent/mobs/nymph/nymph_ui.dm @@ -0,0 +1,53 @@ + +/decl/ui_style/ascent + name = "Ascent" + restricted = TRUE + uid = "ui_style_ascent" + override_icons = list( + (HUD_HEALTH) = 'mods/species/ascent/icons/ui_health.dmi', + (HUD_HANDS) = 'mods/species/ascent/icons/ui_hands.dmi', + (HUD_RESIST) = 'mods/species/ascent/icons/ui_interactions_resist.dmi', + (HUD_THROW) = 'mods/species/ascent/icons/ui_interactions_throw.dmi', + (HUD_DROP) = 'mods/species/ascent/icons/ui_interactions_drop.dmi', + (HUD_MANEUVER) = 'mods/species/ascent/icons/ui_interactions_maneuver.dmi', + (HUD_INVENTORY) = 'mods/species/ascent/icons/ui_inventory.dmi' + ) + +/decl/hud_element/health/ascent_nymph + elem_reference_type = /decl/hud_element/health + elem_type = /obj/screen/health/ascent_nymph + +/decl/hud_element/molt + elem_type = /obj/screen/ascent_nymph_molt + +/datum/hud/ascent_nymph + omit_hud_elements = list(/decl/hud_element/health) + additional_hud_elements = list( + /decl/hud_element/health/ascent_nymph, + /decl/hud_element/molt + ) + +/datum/hud/ascent_nymph/get_ui_style_data() + return GET_DECL(/decl/ui_style/ascent) + +/datum/hud/ascent_nymph/get_ui_color() + return COLOR_WHITE + +/datum/hud/ascent_nymph/get_ui_alpha() + return 255 + +/obj/screen/health/ascent_nymph + name = "health" + screen_loc = ANYMPH_SCREEN_LOC_HEALTH + +/obj/screen/ascent_nymph_molt + name = "molt" + icon = 'mods/species/ascent/icons/ui_molt.dmi' + screen_loc = ANYMPH_SCREEN_LOC_MOLT + icon_state = "molt-on" + requires_ui_style = FALSE + +/obj/screen/ascent_nymph_molt/handle_click(mob/user, params) + var/mob/living/simple_animal/alien/kharmaan/nymph = user + if(istype(nymph)) + nymph.molt() diff --git a/mods/ascent/sounds/ascent1.ogg b/mods/species/ascent/sounds/ascent1.ogg similarity index 100% rename from mods/ascent/sounds/ascent1.ogg rename to mods/species/ascent/sounds/ascent1.ogg diff --git a/mods/ascent/sounds/ascent2.ogg b/mods/species/ascent/sounds/ascent2.ogg similarity index 100% rename from mods/ascent/sounds/ascent2.ogg rename to mods/species/ascent/sounds/ascent2.ogg diff --git a/mods/ascent/sounds/ascent3.ogg b/mods/species/ascent/sounds/ascent3.ogg similarity index 100% rename from mods/ascent/sounds/ascent3.ogg rename to mods/species/ascent/sounds/ascent3.ogg diff --git a/mods/ascent/sounds/ascent4.ogg b/mods/species/ascent/sounds/ascent4.ogg similarity index 100% rename from mods/ascent/sounds/ascent4.ogg rename to mods/species/ascent/sounds/ascent4.ogg diff --git a/mods/ascent/sounds/ascent5.ogg b/mods/species/ascent/sounds/ascent5.ogg similarity index 100% rename from mods/ascent/sounds/ascent5.ogg rename to mods/species/ascent/sounds/ascent5.ogg diff --git a/mods/ascent/sounds/ascent6.ogg b/mods/species/ascent/sounds/ascent6.ogg similarity index 100% rename from mods/ascent/sounds/ascent6.ogg rename to mods/species/ascent/sounds/ascent6.ogg diff --git a/mods/ascent/sounds/razorweb.ogg b/mods/species/ascent/sounds/razorweb.ogg similarity index 100% rename from mods/ascent/sounds/razorweb.ogg rename to mods/species/ascent/sounds/razorweb.ogg diff --git a/mods/ascent/sounds/razorweb_break.ogg b/mods/species/ascent/sounds/razorweb_break.ogg similarity index 100% rename from mods/ascent/sounds/razorweb_break.ogg rename to mods/species/ascent/sounds/razorweb_break.ogg diff --git a/mods/ascent/sounds/razorweb_hiss.ogg b/mods/species/ascent/sounds/razorweb_hiss.ogg similarity index 100% rename from mods/ascent/sounds/razorweb_hiss.ogg rename to mods/species/ascent/sounds/razorweb_hiss.ogg diff --git a/mods/ascent/sounds/razorweb_twang.ogg b/mods/species/ascent/sounds/razorweb_twang.ogg similarity index 100% rename from mods/ascent/sounds/razorweb_twang.ogg rename to mods/species/ascent/sounds/razorweb_twang.ogg diff --git a/mods/species/ascent/structures/ship_furniture.dm b/mods/species/ascent/structures/ship_furniture.dm new file mode 100644 index 000000000000..d9192bf07875 --- /dev/null +++ b/mods/species/ascent/structures/ship_furniture.dm @@ -0,0 +1,51 @@ +MANTIDIFY(/obj/structure/chair/padded/purple, "mantid nest", "resting place") // sets up name, description and color + +/obj/structure/chair/padded/purple/ascent // sets up icon and offsets + icon = 'mods/species/ascent/icons/furniture/chair_nest.dmi' + +/obj/structure/chair/padded/purple/ascent/gyne + name = "mantid throne" + icon = 'mods/species/ascent/icons/furniture/chair_nest_large.dmi' + +/obj/structure/ascent_spawn + name = "mantid cryotank" + desc = "A liquid-filled, cloudy tank with strange forms twitching inside." + icon = 'icons/obj/cryogenics.dmi' + icon_state = "cellold2" + anchored = TRUE + density = TRUE + +/obj/structure/mopbucket/ascent + name = "portable liquid cleaning agent holder" + desc = "An alien container of some sort." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + +/obj/structure/closet/crate/freezer/meat/ascent + name = "cryogenic stasis unit" + desc = "A bizarre alien stasis unit." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + +/obj/structure/hygiene/shower/ascent + name = "hydrating decontamination armature" + desc = "An alien vertical squirt bath." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + +/obj/structure/hygiene/sink/ascent + name = "hydration outlet" + desc = "An alien wall mounted basin with mysterious protrusions." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + +/obj/structure/reagent_dispensers/water_cooler/ascent + name = "hydration dispensator" + desc = "An alien device housing liquid for alien purposes." + icon = 'mods/species/ascent/icons/ascent_doodads.dmi' + cups = 50 + cup_type = /obj/item/food/hydration + +/obj/structure/reagent_dispensers/water_cooler/ascent/dispense_cup(mob/user, skip_text) + . = ..(user, TRUE) + if(!skip_text) + if(.) + user.visible_message("\The [user] grabs a hydration ration orb from \the [src].", "You grab a hydration ration orb from \the [src].") + else + to_chat(user, "\The [src]'s orb supply is empty. Notify a control mind.") diff --git a/mods/species/ascent/turfs/ship.dm b/mods/species/ascent/turfs/ship.dm new file mode 100644 index 000000000000..320a2d8c30e2 --- /dev/null +++ b/mods/species/ascent/turfs/ship.dm @@ -0,0 +1,64 @@ +/decl/flooring/plating/ascent + icon_base = "curvy" + icon = 'icons/turf/flooring/alium.dmi' + burned_states = null + broken_states = null + uid = "floor_ascent_plating" + +/decl/flooring/tiling_ascent + name = "floor" + desc = "An odd jigsaw puzzle of alloy plates." + icon = 'icons/turf/flooring/alium.dmi' + icon_base = "jaggy" + has_base_range = 6 + color = COLOR_GRAY40 + footstep_type = /decl/footsteps/tiles + constructed = TRUE + burned_states = null + broken_states = null + uid = "floor_ascent_tiled" + +/turf/wall/ascent + color = COLOR_PURPLE + +/turf/wall/ascent/on_update_icon() + . = ..() + color = COLOR_PURPLE + +/turf/wall/r_wall/ascent + color = COLOR_PURPLE + +/turf/wall/r_wall/ascent/on_update_icon() + . = ..() + color = COLOR_PURPLE + +/turf/floor/shuttle_ceiling/ascent + color = COLOR_PURPLE + icon_state = "jaggy" + icon = 'icons/turf/flooring/alium.dmi' + +/turf/floor/ascent + name = "mantid plating" + color = COLOR_GRAY20 + _base_flooring = /decl/flooring/plating/ascent + icon_state = "curvy" + icon = 'icons/turf/flooring/alium.dmi' + initial_gas = list( + /decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5, + /decl/material/gas/oxygen = MOLES_CELLSTANDARD * 0.5 + ) + +/turf/floor/ascent/Initialize() + . = ..() + icon_state = "curvy[rand(0,6)]" + +/turf/floor/tiled/ascent + name = "mantid tiling" + icon = 'icons/turf/flooring/alium.dmi' + icon_state = "jaggy" + color = COLOR_GRAY40 + _flooring = /decl/flooring/tiling_ascent + initial_gas = list( + /decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5, + /decl/material/gas/oxygen = MOLES_CELLSTANDARD * 0.5 + ) diff --git a/mods/species/drakes/_drakes.dm b/mods/species/drakes/_drakes.dm new file mode 100644 index 000000000000..1843e9e473e9 --- /dev/null +++ b/mods/species/drakes/_drakes.dm @@ -0,0 +1,10 @@ +#define BODYTYPE_GRAFADREKA "drake body" +#define BODYTYPE_GRAFADREKA_HATCHLING "hatchling drake body" +#define BP_DRAKE_GIZZARD "drake gizzard" + +/decl/modpack/grafadreka + name = "Grafadreka Species" + +/mob/living/human/grafadreka/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + species_uid = /decl/species/grafadreka::uid + . = ..() diff --git a/mods/species/drakes/_drakes.dme b/mods/species/drakes/_drakes.dme new file mode 100644 index 000000000000..025f1c54c518 --- /dev/null +++ b/mods/species/drakes/_drakes.dme @@ -0,0 +1,23 @@ +#ifndef MODPACK_DRAKES +#define MODPACK_DRAKES +// BEGIN_INCLUDE +#include "_drakes.dm" +#include "_overrides.dm" +#include "clothing.dm" +#include "culture.dm" +#include "drake_abilities.dm" +#include "drake_abilities_friendly.dm" +#include "drake_abilities_hostile.dm" +#include "drake_attacks.dm" +#include "drake_emotes.dm" +#include "drake_modifiers.dm" +#include "drake_organs.dm" +#include "drake_spit.dm" +#include "drake_traits.dm" +#include "language.dm" +#include "sifpod.dm" +#include "sifsap.dm" +#include "species.dm" +#include "species_bodytypes.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/species/drakes/_overrides.dm b/mods/species/drakes/_overrides.dm new file mode 100644 index 000000000000..a4246927c61e --- /dev/null +++ b/mods/species/drakes/_overrides.dm @@ -0,0 +1,10 @@ +/obj/item + var/_drake_onmob_icon + var/_drake_hatchling_onmob_icon + +/obj/item/setup_sprite_sheets() + . = ..() + if(_drake_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_GRAFADREKA, _drake_onmob_icon) + if(_drake_hatchling_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_GRAFADREKA_HATCHLING, _drake_hatchling_onmob_icon) diff --git a/mods/species/drakes/clothing.dm b/mods/species/drakes/clothing.dm new file mode 100644 index 000000000000..63c803bc1dbe --- /dev/null +++ b/mods/species/drakes/clothing.dm @@ -0,0 +1,11 @@ +/obj/item/backpack + _drake_onmob_icon = 'mods/species/drakes/icons/clothing/backpack.dmi' + _drake_hatchling_onmob_icon = 'mods/species/drakes/icons/clothing/hatchling_backpack.dmi' + +/obj/item/card/id + _drake_onmob_icon = 'mods/species/drakes/icons/clothing/id.dmi' + _drake_hatchling_onmob_icon = 'mods/species/drakes/icons/clothing/hatchling_id.dmi' + +/obj/item/bag + _drake_onmob_icon = 'mods/species/drakes/icons/clothing/sack.dmi' + _drake_hatchling_onmob_icon = 'mods/species/drakes/icons/clothing/hatchling_backpack.dmi' diff --git a/mods/species/drakes/culture.dm b/mods/species/drakes/culture.dm new file mode 100644 index 000000000000..1d559bc6fe39 --- /dev/null +++ b/mods/species/drakes/culture.dm @@ -0,0 +1,30 @@ +/decl/background_detail/heritage/grafadreka + name = "Grafadreka Culture" + description = "You are a grafadreka, or a drake. Drakes are intelligent, arguably sapient pack predators without anything in the way of technology or culture, but they can be trained to use tools, and have been known to work well alongside humans as companions and working animals." + language = /decl/language/grafadreka + hidden = TRUE + hidden_from_codex = TRUE + uid = "heritage_drake" + +/decl/background_detail/location/grafadreka + name = "Sif" + description = "You are from the tundras and forests of the frozen garden world of Sif, where you probably eked out a life hunting giant spiders or chasing siffets." + language = /decl/language/grafadreka + hidden = TRUE + hidden_from_codex = TRUE + uid = "location_drake" + +/decl/background_detail/faction/grafadreka + name = "Grafadreka Pack" + description = "Drakes are intelligent, arguably sapient pack predators, and tend to live in small familial groups of a breeding pair or two, and however many hatchlings they have managed to keep alive." + language = /decl/language/grafadreka + hidden = TRUE + hidden_from_codex = TRUE + uid = "faction_drake" + +/decl/background_detail/religion/grafadreka + name = "Grafadreka Religion" + description = "If drakes can be said to have a religion, it's probably food-oriented." + hidden = TRUE + hidden_from_codex = TRUE + uid = "religion_drake" diff --git a/mods/species/drakes/drake_abilities.dm b/mods/species/drakes/drake_abilities.dm new file mode 100644 index 000000000000..fb4d7b0fcabf --- /dev/null +++ b/mods/species/drakes/drake_abilities.dm @@ -0,0 +1,34 @@ +/datum/ability_handler/predator/grafadreka + var/spit_projectile_type = /obj/item/projectile/drake_spit + var/next_spit = 0 + +/datum/ability_handler/predator/grafadreka/hatchling + spit_projectile_type = /obj/item/projectile/drake_spit/weak + +/datum/ability_handler/predator/grafadreka/can_do_ranged_invocation(mob/user, atom/target) + return ..() || (istype(user) && user.check_intent(I_FLAG_HARM) && !user.incapacitated() && isatom(target)) + +/datum/ability_handler/predator/grafadreka/do_ranged_invocation(mob/user, atom/target) + if((. = ..())) + return + if(world.time < next_spit) + to_chat(user, SPAN_WARNING("You cannot spit again so soon!")) + return TRUE + if(!drake_spend_sap(user, 1)) + to_chat(user, SPAN_WARNING("You do not have enough sap stored to spit!")) + return TRUE + next_spit = world.time + 3 SECONDS + user.visible_message(SPAN_DANGER("\The [user] spits at \the [target]!")) + var/obj/item/projectile/spit = new spit_projectile_type(get_turf(user)) + if(spit) + playsound(user, spit.fire_sound, 100, 1) + spit.launch(target, user.get_target_zone(), user) + return TRUE + +/datum/ability_handler/predator/grafadreka/do_melee_invocation(mob/user, atom/target) + if((. = ..())) + return + // Healing + if(user.check_intent(I_FLAG_HELP) && isliving(target)) + return handle_wound_cleaning(user, target) + return FALSE diff --git a/mods/species/drakes/drake_abilities_friendly.dm b/mods/species/drakes/drake_abilities_friendly.dm new file mode 100644 index 000000000000..658adbe07ebd --- /dev/null +++ b/mods/species/drakes/drake_abilities_friendly.dm @@ -0,0 +1,105 @@ +var/global/list/_wounds_being_tended_by_drakes = list() + +/datum/ability_handler/predator/grafadreka/proc/handle_wound_cleaning(mob/user, mob/living/friend) + // Can't heal ghosts or rocks. + if(!isliving(friend)) + return FALSE + // We can't heal robots. + if(friend.isSynthetic()) + return FALSE + // Check if someone else is looking after them already. + if(global._wounds_being_tended_by_drakes["\ref[friend]"] > world.time) + return FALSE + // Can't heal the dead. + if(friend.stat == DEAD) + to_chat(user, SPAN_WARNING("\The [friend] is dead; tending their wounds is pointless.")) + return TRUE + + // Complex mobs need to have a bleeding external organ to qualify. + var/can_tend = FALSE + var/is_wounded = FALSE + if(length(friend.get_external_organs())) + var/list/injured_organs = friend.get_injured_organs() + if(length(injured_organs)) + var/mob/living/human/H = friend + for (var/obj/item/organ/external/E in H.bad_external_organs) + if(!length(E.wounds)) + continue + is_wounded = TRUE + for(var/datum/wound/wound in E.wounds) + if(!wound.salved || wound.bleeding()) + can_tend = TRUE + break + // Simple mobs just need health damage. + else if(friend.current_health < friend.get_max_health()) + is_wounded = TRUE + can_tend = TRUE + + if(!can_tend) + if(friend == user) + if(!is_wounded) + to_chat(user, SPAN_NOTICE("You are unwounded.")) + else + to_chat(user, SPAN_WARNING("You cannot tend any of your wounds.")) + else + if(!is_wounded) + to_chat(user, SPAN_NOTICE("\The [friend] is unwounded.")) + else + to_chat(user, SPAN_WARNING("You cannot tend any of \the [friend]'s wounds.")) + return TRUE + + // Are we already regenerating? + if(friend.has_mob_modifier(/decl/mob_modifier/sifsap_salve)) + if(friend == user) + to_chat(user, SPAN_WARNING("Your wounds have already been cleaned.")) + else + to_chat(user, SPAN_WARNING("\The [friend]'s wounds have already been cleaned.")) + return TRUE + + // Do we have enough sap? + if(!drake_has_sap(user, 10)) + if(friend == user) + to_chat(user, SPAN_WARNING("You don't have enough sap to clean your wounds.")) + else + to_chat(user, SPAN_WARNING("You don't have enough sap to clean \the [friend]'s wounds.")) + return TRUE + + if(friend == user) + user.visible_message(SPAN_NOTICE("\The [user] begins to drool a blue-glowing liquid, which they start slathering over their wounds.")) + else + user.visible_message(SPAN_NOTICE("\The [user] begins to drool a blue-glowing liquid, which they start slathering over \the [friend]'s wounds.")) + playsound(user, 'sound/effects/ointment.ogg', 25) + var/friend_ref = "\ref[friend]" + global._wounds_being_tended_by_drakes[friend_ref] = world.time + (8 SECONDS) + + if(!do_after(user, 8 SECONDS, friend) || QDELETED(friend) || friend.has_mob_modifier(/decl/mob_modifier/sifsap_salve) || user.incapacitated() || !drake_spend_sap(user, 10)) + global._wounds_being_tended_by_drakes -= friend_ref + return TRUE + + global._wounds_being_tended_by_drakes -= friend_ref + if(friend == user) + user.visible_message(SPAN_NOTICE("\The [user] finishes licking at their wounds.")) + else + user.visible_message(SPAN_NOTICE("\The [user] finishes licking at \the [friend]'s wounds.")) + playsound(user, 'sound/effects/ointment.ogg', 25) + + // Sivian animals get a heal buff from the modifier, others just + // get it to stop friendly drakes constantly licking their wounds. + // Organ wounds are closed, but the owners get sifsap injected via open wounds. + friend.add_mob_modifier(/decl/mob_modifier/sifsap_salve, 60 SECONDS, source = user) + var/list/friend_organs = friend.get_external_organs() + if(length(friend_organs)) + for (var/obj/item/organ/external/E in friend_organs) + if(E.status & ORGAN_BLEEDING) + E.clamp_organ() + var/datum/reagents/bloodstream = friend.get_injected_reagents() + if(bloodstream) + bloodstream.add_reagent(/decl/material/liquid/sifsap, rand(1,2)) + for (var/datum/wound/wound in E.wounds) + wound.clamped = TRUE // use this rather than bandaged to avoid message weirdness + wound.salve() + wound.disinfect() + // Everyone else is just poisoned. + else if(!friend.has_trait(/decl/trait/sivian_biochemistry)) + friend.take_damage(rand(1,2), TOX) + return TRUE diff --git a/mods/species/drakes/drake_abilities_hostile.dm b/mods/species/drakes/drake_abilities_hostile.dm new file mode 100644 index 000000000000..a103ab837d87 --- /dev/null +++ b/mods/species/drakes/drake_abilities_hostile.dm @@ -0,0 +1,2 @@ +/datum/ability_handler/predator/grafadreka + max_dismember_size = MOB_SIZE_MEDIUM diff --git a/mods/species/drakes/drake_attacks.dm b/mods/species/drakes/drake_attacks.dm new file mode 100644 index 000000000000..53d3fe7addc0 --- /dev/null +++ b/mods/species/drakes/drake_attacks.dm @@ -0,0 +1,48 @@ +/proc/drake_infect_wounds(var/obj/item/organ/external/bitten) + if(bitten.owner?.has_trait(/decl/trait/sivian_biochemistry)) + return + var/list/open_wounds = list() + for(var/datum/wound/wound in bitten?.wounds) + if(wound.damage_type != CUT) + continue + if(wound.is_treated()) + continue + open_wounds += wound + if(!length(open_wounds)) + return + var/germs_per_wound = max(1, round(rand(50,80) / length(open_wounds))) + for(var/datum/wound/wound in open_wounds) + wound.germ_level += germs_per_wound + wound.disinfected = FALSE + +// 50% damage bonus on prone, stunned or confused enemies. +/decl/natural_attack/bite/sharp/drake + damage = 12 // chomp + +/decl/natural_attack/bite/sharp/drake/get_unarmed_damage(mob/living/user, mob/living/victim) + . = ..() + if(victim.current_posture?.prone || HAS_STATUS(victim, STAT_CONFUSE) || HAS_STATUS(victim, STAT_STUN)) + . = max(1, round(. * 1.5)) + +/decl/natural_attack/claws/strong/drake + damage = 8 // chonky for digging + +/decl/natural_attack/claws/strong/drake/get_unarmed_damage(mob/living/user, mob/living/victim) + . = ..() + if(victim.current_posture?.prone || HAS_STATUS(victim, STAT_CONFUSE) || HAS_STATUS(victim, STAT_STUN)) + . = max(1, round(. * 1.5)) + +// Raises germ level of wounds on attack. +/decl/natural_attack/bite/sharp/drake/apply_attack_effects(mob/living/user, mob/living/target, attack_damage, zone) + . = ..() + if(. && drake_spend_sap(user, 5)) + var/obj/item/organ/external/bit = target.get_organ(zone) + if(bit) + drake_infect_wounds(bit) + +/decl/natural_attack/claws/strong/drake/apply_attack_effects(mob/living/user, mob/living/target, attack_damage, zone) + . = ..() + if(. && drake_spend_sap(user, 5)) + var/obj/item/organ/external/bit = target.get_organ(zone) + if(bit) + drake_infect_wounds(bit) diff --git a/mods/species/drakes/drake_emotes.dm b/mods/species/drakes/drake_emotes.dm new file mode 100644 index 000000000000..a641bc6cf236 --- /dev/null +++ b/mods/species/drakes/drake_emotes.dm @@ -0,0 +1,135 @@ +/decl/emote/audible/drake_roar + key = "droar" + emote_message_3p = "$USER$ inflates $USER_THEIR$ throat, lifts $USER_THEIR$ head up, and releases a resonating, bone-shaking roar." + emote_sound = 'mods/species/drakes/sounds/drake_roar.ogg' + broadcast_sound = 'mods/species/drakes/sounds/drake_roar.ogg' + emote_cooldown = 20 SECONDS + broadcast_distance = 90 + +/decl/emote/audible/drake_roar/broadcast_emote_to(send_sound, mob/target, var/origin_z, direction) + . = ..() + if (.) + var/turf/T = get_turf(target) + if(!T || T.z == origin_z) + to_chat(target, SPAN_NOTICE("You hear a resonant bellowing roar from somewhere to the [dir2text(direction)].")) + else if(T.z < origin_z) + to_chat(target, SPAN_NOTICE("You hear a resonant bellowing roar from somewhere above you, to the [dir2text(direction)].")) + else + to_chat(target, SPAN_NOTICE("You hear a resonant bellowing roar from somewhere below you, to the [dir2text(direction)].")) + +/decl/emote/audible/drake_warble + key = "dwarble" + emote_message_3p = "$USER$ warbles happily." + +/decl/emote/audible/drake_purr + key = "dpurr" + emote_message_3p = "$USER$ emits a low, rumbling purr." + emote_message_3p_target = "$USER$ emits a low, rumbling purr as $USER_THEY$ rub$USER_S$ $USER_THEIR$ head against $TARGET$." + +// Do some bespoke adjacency checking since we want this to be more granular than a straight range check. +/decl/emote/audible/drake_purr/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params) + . = ..() + if(. == emote_message_3p_target && target && !user.Adjacent(target)) + . = "$USER$ half-lids their eyes at $TARGET$ and emits a low, rumbling purr." + +/decl/emote/audible/drake_grumble + key = "dgrumble" + emote_message_3p = "$USER$ grumbles unhappily." + emote_message_3p_target = "$USER$ grumbles unhappily at $TARGET$." + emote_sound = 'mods/species/drakes/sounds/drake_grumble.ogg' + +/decl/emote/audible/drake_huff + key = "dhuff" + emote_message_3p = "$USER$ huffs!" + emote_message_3p_target = "$USER$ huffs at $TARGET$!" + emote_sound = 'mods/species/drakes/sounds/drake_huff.ogg' + +/decl/emote/audible/drake_warn + key = "dwarn" + emote_message_1p = "You fill your throat sacs with spittle, preparing to attack." + emote_message_1p_target = "You stare at $TARGET$ as you fill your throat sacs with spittle, preparing to attack." + emote_message_3p = "$USER$ works $USER_THEIR$ throat, making a horrible wet noise..." + emote_message_3p_target = "$USER$ stares intently at $TARGET$, working $USER_THEIR$ throat to make a horrible wet noise..." + emote_sound = 'mods/species/drakes/sounds/drake_warn.ogg' + +/decl/emote/audible/drake_warn/hatchling + key = "hwarn" + emote_sound = 'mods/species/drakes/sounds/hatchling_warn.ogg' + +/decl/emote/audible/drake_warn/Initialize() + . = ..() + emote_message_1p = SPAN_WARNING(emote_message_1p) + emote_message_1p_target = SPAN_WARNING(emote_message_1p_target) + emote_message_3p = SPAN_WARNING(emote_message_3p) + emote_message_3p_target = SPAN_WARNING(emote_message_3p_target) + +/decl/emote/audible/drake_rattle + key = "drattle" + emote_message_1p = "You bark a challenge and rattle your neck-spines threateningly." + emote_message_1p_target = "You challenge $TARGET$ with a sharp bark, rattling your neck-spines threateningly." + emote_message_3p = "$USER$ barks sharply and rattles $USER_THEIR$ neck-spines!" + emote_message_3p_target = "$USER$ barks sharply at $TARGET$, rattling $USER_THEIR$ neck-spines!" + emote_sound = 'mods/species/drakes/sounds/drake_rattle.ogg' + +/decl/emote/audible/drake_rattle/Initialize() + . = ..() + emote_message_1p = SPAN_WARNING(emote_message_1p) + emote_message_1p_target = SPAN_WARNING(emote_message_1p_target) + emote_message_3p = SPAN_WARNING(emote_message_3p) + emote_message_3p_target = SPAN_WARNING(emote_message_3p_target) + +/decl/emote/visible/drake_headbutt + key = "headbutt" + emote_message_3p = "$USER$ waves $USER_THEIR$ head around energetically." + emote_message_3p_target = "$USER$ headbutts $TARGET$!" + check_range = 1 + emote_cooldown = 5 SECONDS + +/decl/emote/visible/drake_headbutt/finalize_target(var/mob/user, var/atom/target) + return user.Adjacent(target) && ..() + +/decl/emote/visible/drake_headbutt/do_extra(atom/user, atom/target) + . = ..() + + if(!ismob(user)) + return + + // Copied from disarm. + if(!isliving(target) || prob(75)) + return + + var/mob/living/victim = target + if(!victim.can_slip()) + return + + var/mob/user_mob = user + var/armor_check = 100 * victim.get_blocked_ratio(user_mob.get_target_zone(), BRUTE, damage = 20) + if(armor_check < 100) + victim.apply_effect(3, WEAKEN, armor_check) + playsound(victim, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + +/decl/emote/audible/drake_rumble + key = "drumble" + emote_message_3p = "$USER$ rumbles in the depths of $USER_THEIR$ chest." + emote_sound = 'mods/species/drakes/sounds/drake_rumble.ogg' + +/decl/emote/audible/drake_hatchling_growl + key = "hgrowl" + emote_message_3p = "$USER$ voices a high-pitched growl!" + emote_sound = 'mods/species/drakes/sounds/hatchling_growl.ogg' + +/decl/emote/audible/drake_hatchling_whine + key = "hwhine" + emote_message_3p = "$USER$ whines plaintively!" + emote_sound = 'mods/species/drakes/sounds/hatchling_whine.ogg' + +/decl/emote/audible/drake_hatchling_yelp + key = "hyelp" + emote_message_3p = "$USER$ yelps!" + emote_sound = 'mods/species/drakes/sounds/hatchling_yelp.ogg' + +/decl/emote/audible/drake_sneeze + key = "dsneeze" + emote_message_1p = "You sneeze!" + emote_message_3p = "$USER$ sneezes!" + emote_sound = 'mods/species/drakes/sounds/drake_sneeze.ogg' diff --git a/mods/species/drakes/drake_modifiers.dm b/mods/species/drakes/drake_modifiers.dm new file mode 100644 index 000000000000..59366e7cfa73 --- /dev/null +++ b/mods/species/drakes/drake_modifiers.dm @@ -0,0 +1,33 @@ +/decl/mob_modifier/sifsap_salve + name = "Sifsap Salve" + desc = "Your wounds have been cleaned with drake spittle, which is beneficial to drakes - and not great for anyone else." + hud_icon = 'mods/species/drakes/icons/sifsap.dmi' + hud_icon_state = "sifsap_hud" + mob_overlay_icon = 'icons/effects/sparkles.dmi' + mob_overlay_state = "cyan_sparkles" + /// Defined here to allow overriding in fantasy modpack. + var/descriptor = "glowing sap" + +/decl/mob_modifier/sifsap_salve/Initialize() + on_add_message_1p = SPAN_NOTICE("The [descriptor] seethes and bubbles in your wounds, tingling and stinging.") + on_end_message_1p = SPAN_NOTICE("The last of the [descriptor] in your wounds fizzles away.") + . = ..() + +/decl/mob_modifier/sifsap_salve/on_modifier_datum_mob_life(mob/living/owner, decl/mob_modifier/modifier) + . = ..() + if(!owner || owner.stat == DEAD || owner.isSynthetic()) + return + if(!owner.has_trait(/decl/trait/sivian_biochemistry)) + owner.heal_damage(BRUTE, 1, do_update_health = FALSE) + owner.heal_damage(BURN, 1, do_update_health = TRUE) + return + if(owner.current_health >= owner.get_max_health()) + return + if(owner.current_posture?.prone) + owner.heal_damage(BRUTE, 3, do_update_health = FALSE) + owner.heal_damage(BURN, 3, do_update_health = FALSE) + owner.heal_damage(TOX, 2, do_update_health = TRUE) + else + owner.heal_damage(BRUTE, 2, do_update_health = FALSE) + owner.heal_damage(BURN, 2, do_update_health = FALSE) + owner.heal_damage(TOX, 1, do_update_health = TRUE) diff --git a/mods/species/drakes/drake_organs.dm b/mods/species/drakes/drake_organs.dm new file mode 100644 index 000000000000..a1c6cab31cdf --- /dev/null +++ b/mods/species/drakes/drake_organs.dm @@ -0,0 +1,41 @@ +/obj/item/organ/internal/drake_gizzard + name = "grafadreka gizzard" + icon_state = "liver" + prosthetic_icon = "liver-prosthetic" + w_class = ITEM_SIZE_SMALL + organ_tag = BP_DRAKE_GIZZARD + parent_organ = BP_CHEST + min_bruised_damage = 25 + min_broken_damage = 45 + max_damage = 70 + relative_size = 60 + min_regeneration_cutoff_threshold = 2 + max_regeneration_cutoff_threshold = 5 + has_stat_info = TRUE + var/datum/reagents/sap_crop + +/obj/item/organ/internal/drake_gizzard/Initialize() + sap_crop = new(60, src) + . = ..() + +/obj/item/organ/internal/drake_gizzard/Process() + . = ..() + if(owner && owner.stat != DEAD && !is_broken() && sap_crop && REAGENT_TOTAL_VOLUME(sap_crop) < 10) + sap_crop.add_reagent(/decl/material/liquid/sifsap, 0.5) + +/obj/item/organ/internal/drake_gizzard/do_uninstall(in_place, detach, ignore_children, update_icon) + . = ..() + var/sap_vol = REAGENT_TOTAL_VOLUME(sap_crop) + if(sap_vol) + if(reagents) + sap_crop.trans_to_holder(reagents, sap_vol) + else if(isatom(loc)) + sap_crop.splash(loc, sap_vol) + sap_crop.clear_reagents() + +/obj/item/organ/internal/drake_gizzard/Destroy() + QDEL_NULL(sap_crop) + . = ..() + +/obj/item/organ/internal/drake_gizzard/get_stat_info() + return list("Sap reserve", num2text(round((REAGENT_TOTAL_VOLUME(sap_crop) || 0), 0.1))) diff --git a/mods/species/drakes/drake_spit.dm b/mods/species/drakes/drake_spit.dm new file mode 100644 index 000000000000..d35efda2c010 --- /dev/null +++ b/mods/species/drakes/drake_spit.dm @@ -0,0 +1,28 @@ +/obj/item/projectile/drake_spit + name = "drake spittle" + icon_state = "ice_1" + nodamage = TRUE + damage = 0 + embed = 0 + atom_damage_type = BRUTE + muzzle_type = null + stun = 3 + weaken = 3 + eyeblur = 5 + fire_sound = 'mods/species/drakes/sounds/drake_spit.ogg' + material = /decl/material/liquid/sifsap + +/obj/item/projectile/drake_spit/on_hit(atom/target, blocked, def_zone) + // Stun is needed to effectively hunt simplemobs, but it's OP against humans. + if(ishuman(target)) + var/mob/living/human/victim = target + SET_STATUS_MAX(victim, STAT_CONFUSE, max(stun, weaken)) + stun = 0 + weaken = 0 + . = ..() + +/obj/item/projectile/drake_spit/weak + stun = 1 + weaken = 1 + eyeblur = 2 + fire_sound = 'mods/species/drakes/sounds/hatchling_spit.ogg' diff --git a/mods/species/drakes/drake_traits.dm b/mods/species/drakes/drake_traits.dm new file mode 100644 index 000000000000..4e82bf59b224 --- /dev/null +++ b/mods/species/drakes/drake_traits.dm @@ -0,0 +1,3 @@ +/decl/trait/sivian_biochemistry + name = "Sivian Biochemistry" + description = "This creature is adapted to the complex bacteria of the garden world of Sif." diff --git a/mods/species/drakes/icons/blood.dmi b/mods/species/drakes/icons/blood.dmi new file mode 100644 index 000000000000..f082396ac3b8 Binary files /dev/null and b/mods/species/drakes/icons/blood.dmi differ diff --git a/mods/species/drakes/icons/body.dmi b/mods/species/drakes/icons/body.dmi new file mode 100644 index 000000000000..a4a3edd66ae2 Binary files /dev/null and b/mods/species/drakes/icons/body.dmi differ diff --git a/mods/species/drakes/icons/clothing/backpack.dmi b/mods/species/drakes/icons/clothing/backpack.dmi new file mode 100644 index 000000000000..c8ba4776a4ef Binary files /dev/null and b/mods/species/drakes/icons/clothing/backpack.dmi differ diff --git a/mods/species/drakes/icons/clothing/hatchling_backpack.dmi b/mods/species/drakes/icons/clothing/hatchling_backpack.dmi new file mode 100644 index 000000000000..4fe4b64f85d3 Binary files /dev/null and b/mods/species/drakes/icons/clothing/hatchling_backpack.dmi differ diff --git a/mods/species/drakes/icons/clothing/hatchling_id.dmi b/mods/species/drakes/icons/clothing/hatchling_id.dmi new file mode 100644 index 000000000000..84fbdc7973d7 Binary files /dev/null and b/mods/species/drakes/icons/clothing/hatchling_id.dmi differ diff --git a/mods/species/drakes/icons/clothing/id.dmi b/mods/species/drakes/icons/clothing/id.dmi new file mode 100644 index 000000000000..7ac25f1174a1 Binary files /dev/null and b/mods/species/drakes/icons/clothing/id.dmi differ diff --git a/mods/species/drakes/icons/clothing/sack.dmi b/mods/species/drakes/icons/clothing/sack.dmi new file mode 100644 index 000000000000..ac8bfdf9bea3 Binary files /dev/null and b/mods/species/drakes/icons/clothing/sack.dmi differ diff --git a/mods/species/drakes/icons/damage.dmi b/mods/species/drakes/icons/damage.dmi new file mode 100644 index 000000000000..189ce8a346cd Binary files /dev/null and b/mods/species/drakes/icons/damage.dmi differ diff --git a/mods/species/drakes/icons/eyes.dmi b/mods/species/drakes/icons/eyes.dmi new file mode 100644 index 000000000000..59caa0b4ae1a Binary files /dev/null and b/mods/species/drakes/icons/eyes.dmi differ diff --git a/mods/ascent/icons/species/mantid/onmob_back_gyne.dmi b/mods/species/drakes/icons/hatchling_blood.dmi similarity index 100% rename from mods/ascent/icons/species/mantid/onmob_back_gyne.dmi rename to mods/species/drakes/icons/hatchling_blood.dmi diff --git a/mods/species/drakes/icons/hatchling_body.dmi b/mods/species/drakes/icons/hatchling_body.dmi new file mode 100644 index 000000000000..7ebcd512b6df Binary files /dev/null and b/mods/species/drakes/icons/hatchling_body.dmi differ diff --git a/mods/species/drakes/icons/hatchling_eyes.dmi b/mods/species/drakes/icons/hatchling_eyes.dmi new file mode 100644 index 000000000000..c938d3180c0d Binary files /dev/null and b/mods/species/drakes/icons/hatchling_eyes.dmi differ diff --git a/mods/species/drakes/icons/hatchling_markings.dmi b/mods/species/drakes/icons/hatchling_markings.dmi new file mode 100644 index 000000000000..aefbcc5bea07 Binary files /dev/null and b/mods/species/drakes/icons/hatchling_markings.dmi differ diff --git a/mods/species/drakes/icons/markings.dmi b/mods/species/drakes/icons/markings.dmi new file mode 100644 index 000000000000..d44a8cfa21fb Binary files /dev/null and b/mods/species/drakes/icons/markings.dmi differ diff --git a/mods/species/drakes/icons/sifpod.dmi b/mods/species/drakes/icons/sifpod.dmi new file mode 100644 index 000000000000..ac2329911af5 Binary files /dev/null and b/mods/species/drakes/icons/sifpod.dmi differ diff --git a/mods/species/drakes/icons/sifsap.dmi b/mods/species/drakes/icons/sifsap.dmi new file mode 100644 index 000000000000..6942ef6d839b Binary files /dev/null and b/mods/species/drakes/icons/sifsap.dmi differ diff --git a/mods/species/drakes/icons/skeleton.dmi b/mods/species/drakes/icons/skeleton.dmi new file mode 100644 index 000000000000..074776b10d6a Binary files /dev/null and b/mods/species/drakes/icons/skeleton.dmi differ diff --git a/mods/species/drakes/icons/template.dmi b/mods/species/drakes/icons/template.dmi new file mode 100644 index 000000000000..e20f03f16f08 Binary files /dev/null and b/mods/species/drakes/icons/template.dmi differ diff --git a/mods/species/drakes/language.dm b/mods/species/drakes/language.dm new file mode 100644 index 000000000000..f674ebb84261 --- /dev/null +++ b/mods/species/drakes/language.dm @@ -0,0 +1,61 @@ +// TODO: some way to handle this with a voicebox organ or something along those lines. +/decl/language + var/drake_compatible = FALSE + +// These languages shouldn't care about the speaker bodytype. +/decl/language/noise + drake_compatible = null +/decl/language/cult + drake_compatible = null +/decl/language/cultcommon + drake_compatible = null +/decl/language/binary + drake_compatible = null +/decl/language/alium + drake_compatible = null + +/decl/language/can_be_spoken_properly_by(var/mob/speaker) + . = ..() + if(. != SPEECH_RESULT_INCAPABLE && !isnull(drake_compatible) && istype(speaker?.get_bodytype(), /decl/bodytype/quadruped/grafadreka) != drake_compatible) + return SPEECH_RESULT_INCAPABLE + +/decl/language/grafadreka + name = "Drake Language" + shorthand = "DR" + desc = "Hiss hiss, feed me siffets." + speech_verb = "hisses" + ask_verb = "chirps" + exclaim_verb = "rumbles" + colour = "alien" + key = "l" // l is for lizard, probably + flags = LANG_FLAG_RESTRICTED + machine_understands = 0 + space_chance = 30 + syllables = list("hss", "ssh", "khs", "hrr", "rrr", "rrn") + drake_compatible = TRUE + +/decl/language/grafadreka/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + var/static/list/drake_names = list( + "Almond", "Pepper", "Pear", "Apple", "Apricot", + "Crabapple", "Berry", "Quince", "Hawthorn", "Rowan", + "Cherry", "Mango", "Plum", "Peach", "Jelly", + "Gooseberry", "Olive", "Silverberry", "Elderberry", "Coffee", + "Bearberry", "Currant", "Cactus", "Guava", "Banana", + "Kiwifruit", "Lingonberry", "Papaya", "Persimmon", "Huckleberry", + "Tamarillo", "Dragonfruit", "Wolfberry", "Melon", "Orange", + "Lemon", "Lime", "Tamarind", "Juniper", "Rhubarb", + "Acorn", "Candlenut", "Hazlenut", "Peanut", "Kola", + "Bopple", "Cashew", "Hazel", "Coconut", "Pistachio", + "Walnut", "Macadamia", "Soybean", "Mandarin", "Tangelo", + "Raspberry", "Cloudberry", "Mulberry", "Salmonberry", "Strawberry", + "Fig", "Duiran", "Vanilla", "Pepper", "Allspice", + "Anise", "Basil", "Bayleaf", "Caper", "Cilantro", + "Cinnamon", "Clove", "Cardamom", "Chives", "Chili", + "Curry", "Coriander", "Celery", "Dill", "Fennel", + "Garlic", "Ginger", "Horseradish", "Jasmine", "Lavender", + "Lemongrass", "Licorice", "Marjoram", "Mustard", "Nutmeg", + "Oregano", "Pennyroyal", "Peppermint", "Poppyseed", "Parsley", + "Rosemary", "Tarragon", "Spearmint", "Thyme", "Tumeric", + "Wasabi" + ) + return pick(drake_names) diff --git a/mods/species/drakes/sifpod.dm b/mods/species/drakes/sifpod.dm new file mode 100644 index 000000000000..a3fed05a820b --- /dev/null +++ b/mods/species/drakes/sifpod.dm @@ -0,0 +1,39 @@ +/decl/recipe/roast_sifpod + fruit = list("sifpod" = 1) + reagent_mix = REAGENT_REPLACE // Clear the sifsap. + result = /obj/item/food/roast_sifpod + +/datum/seed/sifpod + name = "sifpod" + product_name = "sivian pod" + display_name = "sivian pod" + grown_tag = "sifpod" + backyard_grilling_product = /obj/item/food/roast_sifpod + backyard_grilling_announcement = "crackles and pops as the roast hull splits open." + +/datum/seed/sifpod/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,12) + set_trait(TRAIT_PRODUCT_ICON,"alien3") + set_trait(TRAIT_PRODUCT_COLOUR,"#0720c3") + set_trait(TRAIT_PLANT_ICON,"tree5") + set_trait(TRAIT_FLESH_COLOUR,"#05157d") + set_trait(TRAIT_IDEAL_LIGHT, 1) + set_chemical_amount(/decl/material/liquid/nutriment, list(1,5)) + set_chemical_amount(/decl/material/liquid/sifsap, list(10,20)) + +/obj/item/food/roast_sifpod + name = "roast sifpod" + desc = "A charred and blackened sifpod, roasted to kill the toxins and split open to reveal steaming blue-green fruit jelly within. A popular campfire snack." + icon = 'mods/species/drakes/icons/sifpod.dmi' + icon_state = ICON_STATE_WORLD + nutriment_amt = 4 + nutriment_desc = list( + "sweet, tart fruit jelly" = 4, + "pungent muskiness" = 1 + ) + bitesize = 3 diff --git a/mods/species/drakes/sifsap.dm b/mods/species/drakes/sifsap.dm new file mode 100644 index 000000000000..a178721e6e89 --- /dev/null +++ b/mods/species/drakes/sifsap.dm @@ -0,0 +1,53 @@ +/proc/drake_spend_sap(mob/living/user, amount) + var/obj/item/organ/internal/drake_gizzard/gizzard = user.get_organ(BP_DRAKE_GIZZARD) + if(!REAGENT_TOTAL_VOLUME(gizzard?.sap_crop)) + return FALSE + if(!gizzard.sap_crop.has_reagent(/decl/material/liquid/sifsap, amount)) + return FALSE + gizzard.sap_crop.remove_reagent(/decl/material/liquid/sifsap, amount) + return TRUE + +/proc/drake_has_sap(mob/living/user, amount) + var/obj/item/organ/internal/drake_gizzard/gizzard = user.get_organ(BP_DRAKE_GIZZARD) + return REAGENT_TOTAL_VOLUME(gizzard?.sap_crop) >= amount + +/proc/drake_add_sap(mob/living/user, amount) + var/obj/item/organ/internal/drake_gizzard/gizzard = user.get_organ(BP_DRAKE_GIZZARD) + var/max_volume = REAGENT_MAXIMUM_VOLUME(gizzard?.sap_crop) + if(!max_volume) + return FALSE + if(REAGENT_VOLUME(gizzard.sap_crop, /decl/material/liquid/sifsap) >= max_volume) + return FALSE + gizzard.sap_crop.add_reagent(/decl/material/liquid/sifsap, amount) + return TRUE + +/decl/material/liquid/sifsap + name = "sifsap" + uid = "chem_liquid_sifsap" + lore_text = "A natural slurry comprised of fluorescent bacteria native to Sif, in the Vir system." + taste_description = "sour" + overdose = 20 + ingest_met = REM + toxicity = 2 + color = "#c6e2ff" + affect_blood_on_ingest = 0.7 + +/decl/material/liquid/sifsap/affect_ingest(var/mob/living/M, var/removed, var/datum/reagents/holder) + if(M.has_trait(/decl/trait/sivian_biochemistry)) + if(!drake_add_sap(M, removed)) + M.adjust_nutrition(toxicity * removed) + return + . = ..() + +/decl/material/liquid/sifsap/affect_blood(var/mob/living/M, var/removed, var/datum/reagents/holder) + if(M.has_trait(/decl/trait/sivian_biochemistry)) + return + M.add_chemical_effect(CE_PULSE, -1) + return ..() + +/decl/material/liquid/sifsap/affect_overdose(mob/living/victim, total_dose) + if(victim.has_trait(/decl/trait/sivian_biochemistry)) + return + victim.apply_damage(1, IRRADIATE) + SET_STATUS_MAX(victim, 5, STAT_DROWSY) + return ..() diff --git a/mods/species/drakes/sounds/drake_grumble.ogg b/mods/species/drakes/sounds/drake_grumble.ogg new file mode 100644 index 000000000000..599306f926fc Binary files /dev/null and b/mods/species/drakes/sounds/drake_grumble.ogg differ diff --git a/mods/species/drakes/sounds/drake_huff.ogg b/mods/species/drakes/sounds/drake_huff.ogg new file mode 100644 index 000000000000..0166aafe82d8 Binary files /dev/null and b/mods/species/drakes/sounds/drake_huff.ogg differ diff --git a/mods/species/drakes/sounds/drake_rattle.ogg b/mods/species/drakes/sounds/drake_rattle.ogg new file mode 100644 index 000000000000..ec51694d92e6 Binary files /dev/null and b/mods/species/drakes/sounds/drake_rattle.ogg differ diff --git a/mods/species/drakes/sounds/drake_roar.ogg b/mods/species/drakes/sounds/drake_roar.ogg new file mode 100644 index 000000000000..81eff029e95e Binary files /dev/null and b/mods/species/drakes/sounds/drake_roar.ogg differ diff --git a/mods/species/drakes/sounds/drake_rumble.ogg b/mods/species/drakes/sounds/drake_rumble.ogg new file mode 100644 index 000000000000..4cc9191a7fde Binary files /dev/null and b/mods/species/drakes/sounds/drake_rumble.ogg differ diff --git a/mods/species/drakes/sounds/drake_sneeze.ogg b/mods/species/drakes/sounds/drake_sneeze.ogg new file mode 100644 index 000000000000..c5654f9a6aae Binary files /dev/null and b/mods/species/drakes/sounds/drake_sneeze.ogg differ diff --git a/mods/species/drakes/sounds/drake_spit.ogg b/mods/species/drakes/sounds/drake_spit.ogg new file mode 100644 index 000000000000..9c33d3bee244 Binary files /dev/null and b/mods/species/drakes/sounds/drake_spit.ogg differ diff --git a/mods/species/drakes/sounds/drake_warn.ogg b/mods/species/drakes/sounds/drake_warn.ogg new file mode 100644 index 000000000000..c3695df27ba7 Binary files /dev/null and b/mods/species/drakes/sounds/drake_warn.ogg differ diff --git a/mods/species/drakes/sounds/hatchling_growl.ogg b/mods/species/drakes/sounds/hatchling_growl.ogg new file mode 100644 index 000000000000..70135b1f1b0c Binary files /dev/null and b/mods/species/drakes/sounds/hatchling_growl.ogg differ diff --git a/mods/species/drakes/sounds/hatchling_spit.ogg b/mods/species/drakes/sounds/hatchling_spit.ogg new file mode 100644 index 000000000000..e85b552f9d92 Binary files /dev/null and b/mods/species/drakes/sounds/hatchling_spit.ogg differ diff --git a/mods/species/drakes/sounds/hatchling_warn.ogg b/mods/species/drakes/sounds/hatchling_warn.ogg new file mode 100644 index 000000000000..60a8c611c97c Binary files /dev/null and b/mods/species/drakes/sounds/hatchling_warn.ogg differ diff --git a/mods/species/drakes/sounds/hatchling_whine.ogg b/mods/species/drakes/sounds/hatchling_whine.ogg new file mode 100644 index 000000000000..ca0465191828 Binary files /dev/null and b/mods/species/drakes/sounds/hatchling_whine.ogg differ diff --git a/mods/species/drakes/sounds/hatchling_yelp.ogg b/mods/species/drakes/sounds/hatchling_yelp.ogg new file mode 100644 index 000000000000..d9f4bb7401c8 Binary files /dev/null and b/mods/species/drakes/sounds/hatchling_yelp.ogg differ diff --git a/mods/species/drakes/species.dm b/mods/species/drakes/species.dm new file mode 100644 index 000000000000..6e1a7ddd1657 --- /dev/null +++ b/mods/species/drakes/species.dm @@ -0,0 +1,101 @@ +/decl/species/grafadreka + uid = "species_grafadreka" + name = "Grafadreka" + name_plural = "Grafadreka" + description = "The reclusive grafadreka (Icelandic, lit. 'digging dragon'), also known as the snow drake, is a large reptillian pack predator similar in size and morphology to old Earth hyenas. \ + They commonly dig shallow dens in dirt, snow or foliage, sometimes using them for concealment prior to an ambush. \ + Biological cousins to the elusive kururak, they have heavy, low-slung bodies and powerful jaws suited to hunting land prey rather than fishing. \ + Colonization and subsequent expansion have displaced many populations from their tundral territories into colder areas; as a result, their diet of Sivian prey animals has pivoted to a diet of giant spider meat." + hidden_from_codex = FALSE + available_bodytypes = list( + /decl/bodytype/quadruped/grafadreka, + /decl/bodytype/quadruped/grafadreka/hatchling + ) + base_external_prosthetics_model = null // no robolimbs for dogs + preview_outfit = null // no pants for dogs + snow_slowdown_mod = -0.5 + gluttonous = GLUT_TINY + available_pronouns = list( + /decl/pronouns/pseudoplural, + /decl/pronouns/neuter, + /decl/pronouns/male, + /decl/pronouns/female + ) + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/grafadreka + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/grafadreka + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/grafadreka + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/grafadreka + ) + ) + force_background_info = list( + /decl/background_category/citizenship = /decl/background_detail/citizenship/other, + /decl/background_category/heritage = /decl/background_detail/heritage/grafadreka, + /decl/background_category/homeworld = /decl/background_detail/location/grafadreka, + /decl/background_category/faction = /decl/background_detail/faction/grafadreka, + /decl/background_category/religion = /decl/background_detail/religion/grafadreka + ) + species_hud = /datum/hud_data/grafadreka + inherent_verbs = list( + /mob/living/human/proc/drake_sit + ) + traits = list( + /decl/trait/sivian_biochemistry = TRAIT_LEVEL_EXISTS + ) + move_trail = /obj/effect/decal/cleanable/blood/tracks/paw + + // Drakes must be whitelisted for jobs to be able to join as them, see maps.dm. + job_blacklist_by_default = TRUE + spawn_flags = SPECIES_CAN_JOIN + + var/list/adult_pain_emotes_with_pain_level = list( + list(/decl/emote/audible/drake_huff, /decl/emote/audible/drake_rattle) = 20 + ) + var/list/hatchling_pain_emotes_with_pain_level = list( + list(/decl/emote/audible/drake_hatchling_whine, /decl/emote/audible/drake_hatchling_yelp) = 20 + ) + +// TODO: move pain onto a behavior datum or bodytype. +/decl/species/grafadreka/get_pain_emote(var/mob/living/human/H, var/pain_power) + if(H?.get_bodytype()?.type == /decl/bodytype/quadruped/grafadreka/hatchling) + pain_emotes_with_pain_level = hatchling_pain_emotes_with_pain_level + else + pain_emotes_with_pain_level = adult_pain_emotes_with_pain_level + return ..() + +/decl/species/grafadreka/handle_post_spawn(var/mob/living/human/H) + . = ..() + H.default_attack = GET_DECL(/decl/natural_attack/claws/strong/drake) + +// Stub for muscle memory of the Sit verb on Polaris. +/mob/living/human/proc/drake_sit() + set name = "Sit" + set category = "IC" + set src = usr + lay_down(block_posture = /decl/posture/lying) + +/datum/hud_data/grafadreka + inventory_slots = list( + /datum/inventory_slot/head/grafadreka, + /datum/inventory_slot/back/grafadreka, + /datum/inventory_slot/id/grafadreka + ) + +/datum/inventory_slot/head/grafadreka + ui_loc = "LEFT:8,BOTTOM:5" + can_be_hidden = FALSE +/datum/inventory_slot/back/grafadreka + ui_loc = "LEFT:8,BOTTOM+1:7" +/datum/inventory_slot/id/grafadreka + ui_loc = "LEFT:8,BOTTOM+2:9" diff --git a/mods/species/drakes/species_bodytypes.dm b/mods/species/drakes/species_bodytypes.dm new file mode 100644 index 000000000000..9da2dbfd25e4 --- /dev/null +++ b/mods/species/drakes/species_bodytypes.dm @@ -0,0 +1,378 @@ +/datum/appearance_descriptor/age/grafadreka + chargen_min_index = 2 + chargen_max_index = 6 + standalone_value_descriptors = list( + "a hatchling" = 1, + "a juvenile" = 2, + "an adolescent" = 4, + "an adult" = 6, + "aging" = 20, + "elderly" = 30 + ) + +/datum/appearance_descriptor/age/grafadreka/hatchling + chargen_min_index = 1 + chargen_max_index = 2 + +/decl/posture/lying/drake + overlay_modifier = "_lying" +/decl/posture/lying/deliberate/drake + overlay_modifier = "_lying" +/decl/posture/sitting/drake + overlay_modifier = "_sitting" + +/decl/bodytype/quadruped/grafadreka + name = "adult drake" + icon_base = 'mods/species/drakes/icons/body.dmi' + blood_overlays = 'mods/species/drakes/icons/blood.dmi' + eye_icon = 'mods/species/drakes/icons/eyes.dmi' + icon_template = 'mods/species/drakes/icons/template.dmi' + skeletal_icon = 'mods/species/drakes/icons/skeleton.dmi' + damage_overlays = 'mods/species/drakes/icons/damage.dmi' + surgery_overlay_icon = null // todo: 'mods/species/drakes/icons/surgery.dmi' + bodytype_category = BODYTYPE_GRAFADREKA + eye_blend = ICON_MULTIPLY + limb_blend = ICON_MULTIPLY + appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR + mob_size = MOB_SIZE_LARGE + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/grafadreka, + BP_L_HAND = /obj/item/organ/external/hand/quadruped/grafadreka, + BP_R_HAND = /obj/item/organ/external/hand/right/quadruped/grafadreka, + BP_HEAD = /obj/item/organ/external/head/gripper/grafadreka + ) + base_color = "#608894" + base_eye_color = COLOR_SILVER + pixel_offset_x = -16 + antaghud_offset_x = 16 + override_organ_types = list(BP_DRAKE_GIZZARD = /obj/item/organ/internal/drake_gizzard) + uid = "bodytype_drake" + footprints_icon = 'icons/mob/footprints/footprints_paw.dmi' + + additional_emotes = list( + /decl/emote/audible/drake_warble, + /decl/emote/audible/drake_purr, + /decl/emote/audible/drake_grumble, + /decl/emote/audible/drake_huff, + /decl/emote/audible/drake_rattle, + /decl/emote/audible/drake_warn, + /decl/emote/audible/drake_rumble, + /decl/emote/audible/drake_roar, + /decl/emote/audible/drake_sneeze, + /decl/emote/visible/drake_headbutt + ) + + removed_emotes = list( + /decl/emote/audible/clap, + /decl/emote/audible/chuckle, + /decl/emote/audible/laugh, + /decl/emote/audible/mumble, + /decl/emote/audible/slap, + /decl/emote/audible/giggle, + /decl/emote/visible/airguitar, + /decl/emote/visible/salute, + /decl/emote/visible/flap, + /decl/emote/visible/aflap, + /decl/emote/visible/eyebrow, + /decl/emote/visible/frown, + /decl/emote/visible/blush, + /decl/emote/visible/wave, + /decl/emote/visible/raise, + /decl/emote/visible/grin, + /decl/emote/visible/smile, + /decl/emote/visible/hug, + /decl/emote/visible/dap, + /decl/emote/visible/signal, + /decl/emote/visible/handshake, + /decl/emote/visible/afold, + /decl/emote/visible/hip, + /decl/emote/visible/holdup, + /decl/emote/visible/crub, + /decl/emote/visible/erub, + /decl/emote/visible/fslap, + /decl/emote/visible/hrub, + /decl/emote/visible/hspread, + /decl/emote/visible/pocket, + /decl/emote/visible/rsalute, + /decl/emote/visible/tfist + ) + + character_preview_screen_locs = list( + "1" = "character_preview_map:1,4:36", + "2" = "character_preview_map:1,3:31", + "4" = "character_preview_map:1,2:26", + "8" = "character_preview_map:1,1:21" + ) + + available_mob_postures = list( + /decl/posture/standing, + /decl/posture/lying/drake, + /decl/posture/lying/deliberate/drake, + /decl/posture/sitting/drake + ) + + basic_posture_map = list( + /decl/posture/standing = /decl/posture/standing, + /decl/posture/lying = /decl/posture/lying/drake, + /decl/posture/lying/deliberate = /decl/posture/lying/deliberate/drake + ) + + ability_handlers = list( + /datum/ability_handler/predator/grafadreka + ) + age_descriptor = /datum/appearance_descriptor/age/grafadreka + default_sprite_accessories = list( + SAC_MARKINGS = list( + /decl/sprite_accessory/marking/grafadreka = list(SAM_COLOR = COLOR_BLUE_GRAY), + /decl/sprite_accessory/marking/grafadreka/bioluminescence = list(SAM_COLOR = COLOR_CYAN), + /decl/sprite_accessory/marking/grafadreka/claws = list(SAM_COLOR = COLOR_SILVER) + ) + ) + z_flags = ZMM_WIDE_LOAD + + eye_low_light_vision_effectiveness = 0.15 + eye_low_light_vision_adjustment_speed = 0.3 + eye_darksight_range = 7 + + // Copied from riot armor, as drakes cannot wear equipment + // or hold shields. May need to be toned down at some point. + natural_armour_values = list( + ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, + ARMOR_BULLET = ARMOR_BALLISTIC_SMALL, + ARMOR_LASER = ARMOR_LASER_SMALL, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED + ) + + cold_level_1 = 200 + cold_level_2 = 140 + cold_level_3 = 80 + + heat_level_1 = 330 + heat_level_2 = 380 + heat_level_3 = 800 + + heat_discomfort_level = 294 + heat_discomfort_strings = list( + "You feel soothingly warm.", + "You feel the heat sink into your bones.", + "You feel warm enough to take a nap." + ) + + cold_discomfort_level = 230 + cold_discomfort_strings = list( + "You feel chilly.", + "You feel sluggish and cold.", + "Your scales bristle against the cold." + ) + + VAR_PRIVATE/list/_sitting_equip_adjust + VAR_PRIVATE/list/_lying_equip_adjust + +/decl/bodytype/quadruped/grafadreka/Initialize() + if(!length(_equip_adjust)) + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list(16, -8), + "[SOUTH]" = list(16, -12), + "[EAST]" = list(38, -8), + "[WEST]" = list(-6, -8) + ) + ) + + if(!length(_sitting_equip_adjust)) + _sitting_equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list(16, -2), + "[SOUTH]" = list(16, -2), + "[EAST]" = list(22, -2), + "[WEST]" = list(12, -2) + ) + ) + + if(!length(_lying_equip_adjust)) + _lying_equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 24, -24), + "[SOUTH]" = list( 24, -24), + "[EAST]" = list( 24, -24), + "[WEST]" = list(-10, -24) + ) + ) + + return ..() + +/decl/bodytype/quadruped/grafadreka/get_equip_adjustments(mob/mob) + switch(mob.current_posture?.name) + if("lying", "resting") + return _lying_equip_adjust + if("sitting") + return _sitting_equip_adjust + return ..() + +/decl/bodytype/quadruped/grafadreka/hatchling + name = "hatchling drake" + icon_base = 'mods/species/drakes/icons/hatchling_body.dmi' + blood_overlays = 'mods/species/drakes/icons/hatchling_blood.dmi' + eye_icon = 'mods/species/drakes/icons/hatchling_eyes.dmi' + icon_template = 'icons/mob/human_races/species/template.dmi' + damage_overlays = 'icons/mob/human_races/species/default_damage_overlays.dmi' + bodytype_category = BODYTYPE_GRAFADREKA_HATCHLING + mob_size = MOB_SIZE_SMALL + pixel_offset_x = 0 + antaghud_offset_x = 0 + ability_handlers = list( + /datum/ability_handler/predator/grafadreka/hatchling + ) + z_flags = 0 + // TODO: weaker attack subtypes for the baby + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/grafadreka/hatchling, + BP_L_HAND = /obj/item/organ/external/hand/quadruped/grafadreka, + BP_R_HAND = /obj/item/organ/external/hand/right/quadruped/grafadreka, + BP_HEAD = /obj/item/organ/external/head/gripper/grafadreka + ) + + default_emotes = list( + /decl/emote/audible/drake_hatchling_growl, + /decl/emote/audible/drake_hatchling_whine, + /decl/emote/audible/drake_hatchling_yelp, + /decl/emote/audible/drake_warn/hatchling, + /decl/emote/audible/drake_sneeze + ) + age_descriptor = /datum/appearance_descriptor/age/grafadreka/hatchling + character_preview_screen_locs = null + uid = "bodytype_drake_hatchling" + +/decl/bodytype/quadruped/grafadreka/hatchling/Initialize() + if(!length(_equip_adjust)) + _equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 0, -18), + "[SOUTH]" = list( 0, -18), + "[EAST]" = list( 8, -18), + "[WEST]" = list(-8, -18) + ) + ) + if(!length(_sitting_equip_adjust)) + _sitting_equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 0, -14), + "[SOUTH]" = list( 0, -14), + "[EAST]" = list( 4, -14), + "[WEST]" = list(-4, -14) + ) + ) + if(!length(_lying_equip_adjust)) + _lying_equip_adjust = list( + (slot_head_str) = list( + "[NORTH]" = list( 0, -24), + "[SOUTH]" = list( 0, -24), + "[EAST]" = list( 0, -24), + "[WEST]" = list( 0, -24) + ) + ) + return ..() + +/decl/sprite_accessory/marking/grafadreka/get_accessory_icon(var/obj/item/organ/external/organ) + if(organ?.bodytype?.type == /decl/bodytype/quadruped/grafadreka/hatchling) + return 'mods/species/drakes/icons/hatchling_markings.dmi' + return ..() + +/decl/sprite_accessory/marking/grafadreka + name = "Drake Spines" + icon = 'mods/species/drakes/icons/markings.dmi' + icon_state = "spines" + uid = "acc_marking_drake_spines" + species_allowed = list(/decl/species/grafadreka::uid) + color_blend = ICON_MULTIPLY + body_parts = list( + BP_CHEST, + BP_GROIN, + BP_TAIL, + 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 + ) + +/decl/sprite_accessory/marking/grafadreka/bioluminescence + name = "Drake Bioluminescence" + uid = "acc_marking_drake_bioluminescence" + icon_state = "glow" + body_parts = list( + BP_CHEST, + BP_GROIN, + BP_TAIL, + BP_HEAD + ) + sprite_overlay_plane = ABOVE_LIGHTING_PLANE + sprite_overlay_layer = ABOVE_LIGHTING_LAYER + +/decl/sprite_accessory/marking/grafadreka/claws + name = "Drake Claws" + uid = "acc_marking_drake_claws" + icon_state = "claws" + body_parts = list( + BP_L_HAND, + BP_R_HAND, + BP_L_FOOT, + BP_R_FOOT + ) + +/obj/item/organ/external/tail/grafadreka + tail_icon = 'mods/species/drakes/icons/body.dmi' + tail_blend = ICON_MULTIPLY + +/obj/item/organ/external/tail/grafadreka/hatchling + tail_icon = 'mods/species/drakes/icons/hatchling_body.dmi' + +// Technically means that severed drake paws can be used as shovels, but whatever. +/obj/item/organ/external/hand/quadruped/grafadreka + _base_attack_force = 8 + needs_attack_dexterity = DEXTERITY_NONE + +/obj/item/organ/external/hand/quadruped/grafadreka/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/drake) + return unarmed_attack + +/obj/item/organ/external/hand/quadruped/grafadreka/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance) + . = ..() + item_flags |= ITEM_FLAG_NO_BLUDGEON + set_extension(src, /datum/extension/tool, list( + TOOL_PICK = TOOL_QUALITY_MEDIOCRE, + TOOL_SHOVEL = TOOL_QUALITY_GOOD + )) + +/obj/item/organ/external/hand/quadruped/grafadreka/set_bodytype(decl/bodytype/new_bodytype, override_material, apply_to_internal_organs) + override_material = /decl/material/solid/organic/bone + . = ..() + +/obj/item/organ/external/hand/right/quadruped/grafadreka + _base_attack_force = 8 + needs_attack_dexterity = DEXTERITY_NONE + +/obj/item/organ/external/hand/right/quadruped/grafadreka/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/drake) + return unarmed_attack + +/obj/item/organ/external/hand/right/quadruped/grafadreka/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance) + . = ..() + item_flags |= ITEM_FLAG_NO_BLUDGEON + set_extension(src, /datum/extension/tool, list( + TOOL_PICK = TOOL_QUALITY_MEDIOCRE, + TOOL_SHOVEL = TOOL_QUALITY_GOOD + )) + +/obj/item/organ/external/hand/right/quadruped/grafadreka/set_bodytype(decl/bodytype/new_bodytype, override_material, apply_to_internal_organs) + override_material = /decl/material/solid/organic/bone + . = ..() + +/obj/item/organ/external/head/gripper/grafadreka/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/sharp/drake) + return unarmed_attack diff --git a/mods/species/neoavians/_neoavians.dm b/mods/species/neoavians/_neoavians.dm new file mode 100644 index 000000000000..426648c86ce8 --- /dev/null +++ b/mods/species/neoavians/_neoavians.dm @@ -0,0 +1,9 @@ +#define BODYTYPE_AVIAN "avian body" +#define BODY_EQUIP_FLAG_AVIAN BITFLAG(6) + +/decl/modpack/neoavians + name = "Neo-Avian Content" + +/decl/modpack/neoavians/pre_initialize() + ..() + SSmodpacks.default_submap_whitelisted_species |= /decl/species/neoavian::uid diff --git a/mods/species/neoavians/_neoavians.dme b/mods/species/neoavians/_neoavians.dme new file mode 100644 index 000000000000..d992fb25eba8 --- /dev/null +++ b/mods/species/neoavians/_neoavians.dme @@ -0,0 +1,17 @@ +#ifndef CONTENT_PACK_NEOAVIANS +#define CONTENT_PACK_NEOAVIANS +// BEGIN_INCLUDE +#include "_neoavians.dm" +#include "_overrides.dm" +#include "clothing.dm" +#include "datum\ears.dm" +#include "datum\hair.dm" +#include "datum\language.dm" +#include "datum\loadout.dm" +#include "datum\markings.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "datum\tails.dm" +#include "machinery\suit_cycler.dm" +// END_INCLUDE +#endif diff --git a/mods/species/neoavians/_overrides.dm b/mods/species/neoavians/_overrides.dm new file mode 100644 index 000000000000..1d745db0a6fd --- /dev/null +++ b/mods/species/neoavians/_overrides.dm @@ -0,0 +1,7 @@ +/obj/item + var/_avian_onmob_icon + +/obj/item/setup_sprite_sheets() + . = ..() + if(_avian_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_AVIAN, _avian_onmob_icon) diff --git a/mods/species/neoavians/clothing.dm b/mods/species/neoavians/clothing.dm new file mode 100644 index 000000000000..127c9ccf2505 --- /dev/null +++ b/mods/species/neoavians/clothing.dm @@ -0,0 +1,119 @@ +//Shoes +/obj/item/clothing/shoes/magboots + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/feet/magboots.dmi' + +/obj/item/clothing/shoes/galoshes + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/feet/galoshes.dmi' + +//Gloves +/obj/item/clothing/gloves/setup_equip_flags() + . = ..() + if(!isnull(bodytype_equip_flags) && !(bodytype_equip_flags & BODY_EQUIP_FLAG_EXCLUDE)) + bodytype_equip_flags |= BODY_EQUIP_FLAG_AVIAN + +/obj/item/clothing/gloves + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/gloves.dmi' + +/obj/item/clothing/gloves/ring + _avian_onmob_icon = null + +//Backpacks & tanks +/obj/item/backpack/satchel + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/satchel.dmi' + +//Radsuits (theyre essential?) +/obj/item/clothing/head/radiation + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/head/rad_helm.dmi' + +/obj/item/clothing/head/radiation + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/head/rad_helm.dmi' + +/obj/item/clothing/suit/radiation + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/suit/rad_suit.dmi' + +//cloaks +/obj/item/clothing/suit/cloak + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/accessory/cloak.dmi' + +/obj/item/clothing/suit/hooded_cloak + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/accessory/cloak_hooded.dmi' + +/obj/item/clothing/head/hood/cloak + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/head/cloak_hood.dmi' + +/obj/item/clothing/suit/cloak/hide + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/accessory/cloak_hide.dmi' + +//clothing +/obj/item/clothing/dress/avian_smock + name = "smock" + desc = "A loose-fitting smock favoured by neo-avians." + icon = 'mods/species/neoavians/icons/clothing/under/smock.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_AVIAN + _avian_onmob_icon = null + +/obj/item/clothing/dress/avian_smock/worker + name = "worker's smock" + icon = 'mods/species/neoavians/icons/clothing/under/smock_grey.dmi' + +/obj/item/clothing/dress/avian_smock/rainbow + name = "rainbow smock" + desc = "A brightly coloured, loose-fitting smock - the height of neo-avian fashion." + icon = 'mods/species/neoavians/icons/clothing/under/smock_rainbow.dmi' + +/obj/item/clothing/dress/avian_smock/security + name = "armoured smock" + desc = "A bright red smock with light armour insets, worn by neo-avian security personnel." + icon = 'mods/species/neoavians/icons/clothing/under/smock_red.dmi' + +/obj/item/clothing/dress/avian_smock/engineering + name = "hazard smock" + desc = "A high-visibility yellow smock with orange highlights light armour insets, worn by neo-avian engineering personnel." + icon = 'mods/species/neoavians/icons/clothing/under/smock_yellow.dmi' + +/obj/item/clothing/dress/avian_smock/utility + name = "black uniform" + icon = 'mods/species/neoavians/icons/clothing/under/black_utility.dmi' + +/obj/item/clothing/dress/avian_smock/utility/gray + name = "gray uniform" + icon = 'mods/species/neoavians/icons/clothing/under/gray_utility.dmi' + +/obj/item/clothing/dress/avian_smock/stylish_command + name = "stylish uniform" + icon = 'mods/species/neoavians/icons/clothing/under/stylish_form.dmi' + +/obj/item/clothing/shoes + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/feet/shoes.dmi' + +/obj/item/clothing/shoes/avian + name = "small shoes" + color = COLOR_GRAY + bodytype_equip_flags = BODY_EQUIP_FLAG_AVIAN + _avian_onmob_icon = null + icon = 'mods/species/neoavians/icons/clothing/feet/shoes.dmi' + +/obj/item/clothing/shoes/avian/footwraps + name = "cloth footwraps" + desc = "A roll of treated canvas used for wrapping feet." + icon = 'mods/species/neoavians/icons/clothing/feet/footwraps.dmi' + _base_attack_force = 1 + item_flags = ITEM_FLAG_SILENT + w_class = ITEM_SIZE_SMALL + +/obj/item/clothing/suit/hooded_cloak/avian + name = "striped cloak" + paint_color = "#333333" + markings_color = "#ff7519" + markings_state_modifier = "-stripe" + bodytype_equip_flags = BODY_EQUIP_FLAG_AVIAN + icon = 'mods/species/neoavians/icons/clothing/accessory/cloak_hooded.dmi' + hood = /obj/item/clothing/head/hood/cloak/avian + +/obj/item/clothing/head/hood/cloak/avian + name = "striped hood" + paint_color = "#333333" + markings_color = "#ff7519" + markings_state_modifier = "-stripe" + bodytype_equip_flags = BODY_EQUIP_FLAG_AVIAN + icon = 'mods/species/neoavians/icons/clothing/head/cloak_hood.dmi' diff --git a/mods/species/neoavians/datum/ears.dm b/mods/species/neoavians/datum/ears.dm new file mode 100644 index 000000000000..d26961d4cf29 --- /dev/null +++ b/mods/species/neoavians/datum/ears.dm @@ -0,0 +1,24 @@ +/decl/sprite_accessory/ears/avian + name = "Avian Ears" + icon_state = "ears" + icon = 'mods/species/neoavians/icons/ears.dmi' + uid = "acc_ears_avian" + mask_to_bodypart = FALSE + species_allowed = list(/decl/species/neoavian::uid) + +/decl/sprite_accessory/ears/avian/raptor_add + name = "Avian Ears, Additive" + icon_state = "ears-add" + color_blend = ICON_ADD + uid = "acc_ears_avian_add" + +/decl/sprite_accessory/ears/avian/large + name = "Avian Large Ears" + icon_state = "ears-large" + uid = "acc_ears_avian_large" + +/decl/sprite_accessory/ears/avian/large/add + name = "Avian Large Ears, Additive" + color_blend = ICON_ADD + icon_state = "ears-large-add" + uid = "acc_ears_avian_large_add" diff --git a/mods/species/neoavians/datum/hair.dm b/mods/species/neoavians/datum/hair.dm new file mode 100644 index 000000000000..d8a76a49c9ea --- /dev/null +++ b/mods/species/neoavians/datum/hair.dm @@ -0,0 +1,108 @@ +/decl/sprite_accessory/hair/avian + name = "Avian Plumage" + icon_state = "avian_default" + icon = 'mods/species/neoavians/icons/hair.dmi' + species_allowed = list(/decl/species/neoavian::uid) + color_blend = ICON_MULTIPLY + uid = "acc_hair_avian_plumage" + +/decl/sprite_accessory/hair/avian/get_hidden_substitute() + if(accessory_flags & HAIR_VERY_SHORT) + return src + return GET_DECL(/decl/sprite_accessory/hair/bald) + +/decl/sprite_accessory/hair/avian/mohawk + name = "Avian Mohawk" + icon_state = "avian_mohawk" + uid = "acc_hair_avian_mohawk" + +/decl/sprite_accessory/hair/avian/spiky + name = "Avian Spiky" + icon_state = "avian_spiky" + uid = "acc_hair_avian_spiky" + +/decl/sprite_accessory/hair/avian/crest + name = "Avian Crest" + icon_state = "avian_crest" + uid = "acc_hair_avian_crest" + +/decl/sprite_accessory/hair/avian/mane + name = "Avian Mane" + icon_state = "avian_mane" + uid = "acc_hair_avian_mane" + +/decl/sprite_accessory/hair/avian/upright + name = "Avian Upright" + icon_state = "avian_upright" + uid = "acc_hair_avian_upright" + +/decl/sprite_accessory/hair/avian/fluffymohawk + name = "Avian Fluffy Mohawk" + icon_state = "avian_fluffymohawk" + uid = "acc_hair_avian_fluffymohawk" + +/decl/sprite_accessory/hair/avian/twies + name = "Avian Twies" + icon_state = "avian_twies" + uid = "acc_hair_avian_twies" + +/decl/sprite_accessory/hair/avian/alt + name = "Avian Plumage Alt" + icon_state = "avian_default_alt" + color_blend = ICON_ADD + uid = "acc_hair_avian_plumage_alt" + +/decl/sprite_accessory/hair/avian/alt/excited + name = "Avian Spiky Alt" + icon_state = "avian_spiky_alt" + uid = "acc_hair_avian_excited" + +/decl/sprite_accessory/hair/avian/alt/hedgehog + name = "Avian Hedgehog" + icon_state = "avian_hedge" + uid = "acc_hair_avian_hedgehog" + +/decl/sprite_accessory/hair/avian/alt/unpruned + name = "Avian Unpruned" + icon_state = "avian_unpruned" + uid = "acc_hair_avian_unpruned" + +/decl/sprite_accessory/hair/avian/alt/sunburst + name = "Avian Sunburst" + icon_state = "avian_burst_short" + uid = "acc_hair_avian_sunburst" + +/decl/sprite_accessory/hair/avian/alt/mohawk + name = "Avian Mohawk Alt" + icon_state = "avian_mohawk_alt" + uid = "acc_hair_avian_mohawk_alt" + +/decl/sprite_accessory/hair/avian/alt/pointy + name = "Avian Pointy" + icon_state = "avian_pointy" + uid = "acc_hair_avian_pointy" + +/decl/sprite_accessory/hair/avian/alt/upright + name = "Avian Upright Alt" + icon_state = "avian_upright_alt" + uid = "acc_hair_avian_upright_alt" + +/decl/sprite_accessory/hair/avian/alt/droopy + name = "Avian Droopy" + icon_state = "avian_droopy" + uid = "acc_hair_avian_droopy" + +/decl/sprite_accessory/hair/avian/alt/neon + name = "Avian Neon" + icon_state = "avian_neon" + uid = "acc_hair_avian_neon" + +/decl/sprite_accessory/hair/avian/alt/backstrafe + name = "Avian Backstrafe" + icon_state = "avian_backstrafe" + uid = "acc_hair_avian_backstrafe" + +/decl/sprite_accessory/hair/avian/alt/longway + name = "Avian Long way" + icon_state = "avian_longway" + uid = "acc_hair_avian_longway" diff --git a/mods/species/neoavians/datum/language.dm b/mods/species/neoavians/datum/language.dm new file mode 100644 index 000000000000..b3d72b2de5d2 --- /dev/null +++ b/mods/species/neoavians/datum/language.dm @@ -0,0 +1,65 @@ +/decl/language/corvid + name = "Crow Cant" + shorthand = "CR" + desc = "A rough, loud language spoken by neo-corvids and a number of other post-avian species." + speech_verb = "chirps" + ask_verb = "rattles" + exclaim_verb = "calls" + colour = "alien" + key = "v" + flags = LANG_FLAG_WHITELISTED + space_chance = 50 + syllables = list( + "ca", "ra", "ma", "sa", "na", "ta", "la", "sha", + "ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah", + "skre","ahk","ek","rawk","kraa","ii","kri","ka" + ) + speech_sounds = list( + 'mods/species/neoavians/sound/crow1.ogg', + 'mods/species/neoavians/sound/crow2.ogg', + 'mods/species/neoavians/sound/crow3.ogg', + 'mods/species/neoavians/sound/crow4.ogg' + ) + +/decl/language/corvid/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + . = capitalize((gender == FEMALE) ? pick(global.using_map.first_names_female) : pick(global.using_map.first_names_male)) + . += " [pick(list("Albus","Corax","Corone","Meeki","Insularis","Orru","Sinaloae", "Enca", "Edithae", "Kubaryi"))]" + . += " [pick(list("Hyperion","Earth","Mars","Venus","Neith","Luna","Halo","Pandora","Neptune","Triton", "Haumea", "Eris", "Makemake"))]" + +/decl/language/neoavian + name = "Neo-Avian Pidgin" // pigeon + desc = "A cluster of melodic, trilling languages spoken by the majority of neo-avian subcultures." + speech_verb = "chirps" + ask_verb = "chirrups" + exclaim_verb = "trills" + colour = "alien" + key = "i" + flags = LANG_FLAG_WHITELISTED + space_chance = 50 + syllables = list( + "ca", "ra", "ma", "sa", "na", "ta", "la", "sha", "scha", "a", "a", + "ce", "re", "me", "se", "ne", "te", "le", "she", "sche", "e", "e", + "ci", "ri", "mi", "si", "ni", "ti", "li", "shi", "schi", "i", "i" + ) + +/decl/language/neoavian/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + return ..(gender, 2, 4, 1.5) + +/decl/background_detail/heritage/neoavian + name = "Neo-Avian Milieu" + description = "Neo-avians form a loose coalition of family and flock groupings, and are usually in an extreme minority in human settlements. \ + They tend to cope poorly with confined, crowded spaces like human habs, and often make their homes in hab domes or other spacious facilities." + language = /decl/language/neoavian + secondary_langs = list( + /decl/language/corvid, + /decl/language/neoavian, + /decl/language/sign + ) + uid = "heritage_bird_milieu" + +/decl/background_detail/heritage/neoavian/saurian + name = "Saurian Revivalism" + description = "A minority of neo-avians, particularly those subject to genetic modification during the initial uplift of their species, \ + embrace the dinosaur heritage shared by all avians in the form of scales, sharp teeth, slender tails, and other clear visible features of \ + their long-extinct forebears. Many neo-avians consider them a fringe of self-important wannabes, but the movement is still going strong." + uid = "heritage_bird_saurian" diff --git a/mods/species/neoavians/datum/loadout.dm b/mods/species/neoavians/datum/loadout.dm new file mode 100644 index 000000000000..125b2de01b4b --- /dev/null +++ b/mods/species/neoavians/datum/loadout.dm @@ -0,0 +1,41 @@ +/decl/loadout_category/avian + name = "Avian" + +/decl/loadout_option/avian + whitelisted = list(/decl/species/neoavian::uid) + category = /decl/loadout_category/avian + abstract_type = /decl/loadout_option/avian + +/decl/loadout_option/avian/uniform_selection + name = "Neo-Avian uniform selection" + path = /obj/item/clothing/dress/avian_smock + slot = slot_w_uniform_str + uid = "gear_under_avian" + +/decl/loadout_option/avian/uniform_selection/get_gear_tweak_options() + . = ..() + LAZYINITLIST(.[/datum/gear_tweak/path]) + .[/datum/gear_tweak/path] |= list( + "plain smock" = /obj/item/clothing/dress/avian_smock, + "worker's smock" = /obj/item/clothing/dress/avian_smock/worker, + "rainbow smock" = /obj/item/clothing/dress/avian_smock/rainbow, + "armoured smock" = /obj/item/clothing/dress/avian_smock/security, + "hazard smock" = /obj/item/clothing/dress/avian_smock/engineering, + "black uniform" = /obj/item/clothing/dress/avian_smock/utility, + "gray uniform" = /obj/item/clothing/dress/avian_smock/utility/gray, + "stylish uniform" = /obj/item/clothing/dress/avian_smock/stylish_command + ) + +/decl/loadout_option/avian/shoes + name = "footwraps" + path = /obj/item/clothing/shoes/avian/footwraps + loadout_flags = GEAR_HAS_COLOR_SELECTION + slot = slot_shoes_str + uid = "gear_shoes_avian" + +/decl/loadout_option/avian/hooded_cloak + name = "striped cloak, hooded" + path = /obj/item/clothing/suit/hooded_cloak/avian + uid = "gear_cloak_avian" + slot = slot_wear_suit_str + loadout_flags = GEAR_HAS_COLOR_SELECTION diff --git a/mods/species/neoavians/datum/markings.dm b/mods/species/neoavians/datum/markings.dm new file mode 100644 index 000000000000..232ca94ace93 --- /dev/null +++ b/mods/species/neoavians/datum/markings.dm @@ -0,0 +1,37 @@ +/decl/sprite_accessory/marking/avian + name = "Beak (Head)" + icon_state = "beak" + body_parts = list(BP_HEAD) + icon = 'mods/species/neoavians/icons/markings.dmi' + species_allowed = list(/decl/species/neoavian::uid) + color_blend = ICON_MULTIPLY + uid = "acc_marking_avian_beak" + +/decl/sprite_accessory/marking/avian/wing_feathers + name = "Wing Feathers (Left)" + body_parts = list(BP_L_HAND) + icon_state = "wing_feathers" + uid = "acc_marking_avian_wingfeathers_left" + +/decl/sprite_accessory/marking/avian/wing_feathers/right + name = "Wing Feathers (Right)" + body_parts = list(BP_R_HAND) + uid = "acc_marking_avian_wingfeathers_right" + +/decl/sprite_accessory/marking/avian/additive + name = "Beak, Additive (Head)" + icon_state = "beak-add" + color_blend = ICON_ADD + uid = "acc_marking_avian_beak_alt" + +/decl/sprite_accessory/marking/avian/wing_feathers/additive + name = "Wing Feathers, Additive (Left)" + icon_state = "wing_feathers-add" + color_blend = ICON_ADD + uid = "acc_marking_avian_wingfeathers_left_alt" + +/decl/sprite_accessory/marking/avian/wing_feathers/right/additive + name = "Wing Feathers, Additive (Right)" + icon_state = "wing_feathers-add" + color_blend = ICON_ADD + uid = "acc_marking_avian_wingfeathers_right_alt" diff --git a/mods/species/neoavians/datum/species.dm b/mods/species/neoavians/datum/species.dm new file mode 100644 index 000000000000..1b102057266b --- /dev/null +++ b/mods/species/neoavians/datum/species.dm @@ -0,0 +1,75 @@ +/datum/appearance_descriptor/age/neoavian + chargen_min_index = 3 + chargen_max_index = 6 + standalone_value_descriptors = list( + "a hatchling" = 1, + "an fledgeling" = 6, + "a young adult" = 12, + "an adult" = 25, + "middle-aged" = 35, + "aging" = 45, + "elderly" = 50 + ) + +/decl/butchery_data/humanoid/avian + meat_name = "chicken" + meat_type = /obj/item/food/butchery/meat/chicken + +/decl/species/neoavian + uid = "species_avian" + name = "Neo-Avian" + name_plural = "Neo-Avians" + description = "Avian species, largely crows, magpies and other corvids, were among the first sophonts uplifted to aid in colonizing Mars. \ + These days they are more commonly found pursuing their own careers and goals on the fringes of human space or around their adopted homeworld \ + of Hyperion. Neo-avian naming conventions tend to be a chosen name followed by the species of the person, followed by the location they were hatched." + + base_external_prosthetics_model = /decl/bodytype/prosthetic/avian + base_internal_prosthetics_model = /decl/bodytype/prosthetic/avian + + snow_slowdown_mod = -1 + + holder_icon = 'mods/species/neoavians/icons/holder.dmi' + + butchery_data = /decl/butchery_data/humanoid/avian + + preview_outfit = /decl/outfit/job/generic/assistant/avian + + available_bodytypes = list( + /decl/bodytype/avian, + /decl/bodytype/avian/additive, + /decl/bodytype/avian/raptor, + /decl/bodytype/avian/additive/raptor + ) + + total_health = 120 + holder_type = /obj/item/holder + gluttonous = GLUT_TINY + blood_volume = 320 + hunger_factor = DEFAULT_HUNGER_FACTOR * 1.6 + thirst_factor = DEFAULT_THIRST_FACTOR * 1.6 + + spawn_flags = SPECIES_CAN_JOIN + bump_flag = MONKEY + swap_flags = MONKEY|SIMPLE_ANIMAL + push_flags = MONKEY|SIMPLE_ANIMAL + + available_background_info = list( + /decl/background_category/heritage = list( + /decl/background_detail/heritage/neoavian, + /decl/background_detail/heritage/neoavian/saurian, + /decl/background_detail/heritage/other + ) + ) + +/decl/species/neoavian/equip_default_fallback_uniform(var/mob/living/human/H) + if(istype(H)) + H.equip_to_slot_or_del(new /obj/item/clothing/dress/avian_smock/worker, slot_w_uniform_str) + H.equip_to_slot_or_del(new /obj/item/clothing/shoes/avian, slot_shoes_str) + +/decl/species/neoavian/get_holder_color(var/mob/living/human/H) + return H.get_skin_colour() + +/decl/outfit/job/generic/assistant/avian + name = "Job - Avian Assistant" + uniform = /obj/item/clothing/dress/avian_smock/worker + shoes = /obj/item/clothing/shoes/avian/footwraps diff --git a/mods/species/neoavians/datum/species_bodytypes.dm b/mods/species/neoavians/datum/species_bodytypes.dm new file mode 100644 index 000000000000..c5898d11020e --- /dev/null +++ b/mods/species/neoavians/datum/species_bodytypes.dm @@ -0,0 +1,174 @@ +/decl/bodytype/prosthetic/avian + name = "synthetic avian" + icon_base = 'mods/species/neoavians/icons/body_synthetic.dmi' + blood_overlays = /decl/bodytype/avian::blood_overlays + skeletal_icon = /decl/bodytype/avian::skeletal_icon + bodytype_category = /decl/bodytype/avian::bodytype_category + bodytype_flag = /decl/bodytype/avian::bodytype_flag + mob_size = /decl/bodytype/avian::mob_size + eye_icon = /decl/bodytype/avian::eye_icon + nail_noun = /decl/bodytype/avian::nail_noun + uid = "bodytype_prosthetic_avian" + +/decl/bodytype/prosthetic/avian/raptor + name = "synthetic raptor" + icon_base = 'mods/species/neoavians/icons/body_synthetic_raptor.dmi' + uid = "bodytype_prosthetic_raptor" + default_sprite_accessories = list( + SAC_HAIR = list(/decl/sprite_accessory/hair/avian/spiky = list(SAM_COLOR = "#252525")), + SAC_EARS = list(/decl/sprite_accessory/ears/avian = list(SAM_COLOR = "#252525")), + SAC_TAIL = list(/decl/sprite_accessory/tail/avian = list(SAM_COLOR = "#252525")) + ) + +/decl/bodytype/avian + name = "avian" + bodytype_category = BODYTYPE_AVIAN + icon_base = 'mods/species/neoavians/icons/body.dmi' + blood_overlays = 'mods/species/neoavians/icons/blood_avian.dmi' + skeletal_icon = 'mods/species/neoavians/icons/skeleton.dmi' + limb_blend = ICON_MULTIPLY + bodytype_flag = BODY_EQUIP_FLAG_AVIAN + eye_icon = 'mods/species/neoavians/icons/eyes.dmi' + appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR + base_color = "#252525" + base_eye_color = "#f5c842" + mob_size = MOB_SIZE_SMALL + nail_noun = "talons" + override_limb_types = list( + BP_L_FOOT = /obj/item/organ/external/foot/avian, + BP_R_FOOT = /obj/item/organ/external/foot/right/avian, + BP_L_HAND = /obj/item/organ/external/hand/clawed, + BP_R_HAND = /obj/item/organ/external/hand/right/clawed, + BP_HEAD = /obj/item/organ/external/head/sharp_bite, + BP_TAIL = /obj/item/organ/external/tail/avian + ) + has_organ = list( + BP_STOMACH = /obj/item/organ/internal/stomach, + BP_HEART = /obj/item/organ/internal/heart, + BP_LUNGS = /obj/item/organ/internal/lungs, + BP_LIVER = /obj/item/organ/internal/liver, + BP_KIDNEYS = /obj/item/organ/internal/kidneys, + BP_BRAIN = /obj/item/organ/internal/brain, + BP_EYES = /obj/item/organ/internal/eyes + ) + default_sprite_accessories = list( + SAC_HAIR = list(/decl/sprite_accessory/hair/avian = list(SAM_COLOR = "#252525")), + SAC_MARKINGS = list(/decl/sprite_accessory/marking/avian = list(SAM_COLOR = "#454545")) + ) + age_descriptor = /datum/appearance_descriptor/age/neoavian + heat_discomfort_strings = list( + "Your feathers prickle in the heat.", + "You feel uncomfortably warm.", + ) + uid = "bodytype_avian" + +/decl/bodytype/avian/raptor + name = "raptor" + icon_base = 'mods/species/neoavians/icons/body_raptor.dmi' + uid = "bodytype_avian_raptor" + default_sprite_accessories = list( + SAC_HAIR = list(/decl/sprite_accessory/hair/avian = list(SAM_COLOR = "#252525")), + SAC_EARS = list(/decl/sprite_accessory/ears/avian = list(SAM_COLOR = "#252525")), + SAC_TAIL = list(/decl/sprite_accessory/tail/avian = list(SAM_COLOR = "#252525")) + ) + +/decl/bodytype/avian/additive + name = "avian, additive" + icon_base = 'mods/species/neoavians/icons/body_add.dmi' + health_hud_intensity = 3 + limb_blend = ICON_ADD + uid = "bodytype_avian_additive" + +/decl/bodytype/avian/additive/raptor + name = "raptor, additive" + icon_base = 'mods/species/neoavians/icons/body_raptor_add.dmi' + uid = "bodytype_avian_additive_raptor" + +/decl/bodytype/avian/Initialize() + _equip_adjust = list( + (slot_l_ear_str) = list( + "[NORTH]" = list( 1, -5), + "[EAST]" = list(-2, -5), + "[SOUTH]" = list(-1, -5), + "[WEST]" = list( 0, -5) + ), + (slot_r_ear_str) = list( + "[NORTH]" = list( 1, -5), + "[EAST]" = list( 0, -5), + "[SOUTH]" = list(-1, -5), + "[WEST]" = list( 2, -5) + ), + (BP_L_HAND) = list( + "[NORTH]" = list( 3, -3), + "[EAST]" = list( 1, -3), + "[SOUTH]" = list(-3, -3), + "[WEST]" = list(-5, -3) + ), + (BP_R_HAND) = list( + "[NORTH]" = list(-3, -3), + "[EAST]" = list( 5, -3), + "[SOUTH]" = list( 3, -3), + "[WEST]" = list(-1, -3) + ), + (slot_head_str) = list( + "[NORTH]" = list( 0, -5), + "[EAST]" = list( 1, -5), + "[SOUTH]" = list( 0, -5), + "[WEST]" = list(-1, -5) + ), + (slot_wear_mask_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 2, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-2, -6) + ), + (slot_glasses_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-1, -6) + ), + (slot_back_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list( 3, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list(-3, -6) + ), + (slot_w_uniform_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list(-1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list( 1, -6) + ), + (slot_wear_id_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list(-1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list( 1, -6) + ), + (slot_wear_suit_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list(-1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list( 1, -6) + ), + (slot_belt_str) = list( + "[NORTH]" = list( 0, -6), + "[EAST]" = list(-1, -6), + "[SOUTH]" = list( 0, -6), + "[WEST]" = list( 1, -6) + ) + ) + . = ..() + +/obj/item/organ/external/foot/avian/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/stomp/weak) + return unarmed_attack + +/obj/item/organ/external/foot/right/avian/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/stomp/weak) + return unarmed_attack + +/obj/item/organ/external/tail/avian + tail_icon = 'mods/species/neoavians/icons/tail.dmi' + tail_blend = ICON_MULTIPLY diff --git a/mods/species/neoavians/datum/tails.dm b/mods/species/neoavians/datum/tails.dm new file mode 100644 index 000000000000..b7dfa6953d00 --- /dev/null +++ b/mods/species/neoavians/datum/tails.dm @@ -0,0 +1,20 @@ +/decl/sprite_accessory/tail/avian + name = "Raptor Tail" + icon = 'mods/species/neoavians/icons/tail.dmi' + icon_state = "tail_raptor" + uid = "acc_tail_avian" + accessory_metadata_types = list(SAM_COLOR, SAM_COLOR_INNER) + species_allowed = list(/decl/species/neoavian::uid) + +/decl/sprite_accessory/tail/avian/add + name = "Avian Tail, Additive" + icon_state = "tail_avian_add" + uid = "acc_tail_avian_add" + color_blend = ICON_ADD + accessory_metadata_types = list(SAM_COLOR) + +/decl/sprite_accessory/tail/avian/raptor_add + name = "Raptor Tail, Additive" + uid = "acc_tail_avian_raptor_add" + icon_state = "tail_raptor_add" + color_blend = ICON_ADD diff --git a/mods/species/neoavians/icons/blood_avian.dmi b/mods/species/neoavians/icons/blood_avian.dmi new file mode 100644 index 000000000000..104eb8f94dd4 Binary files /dev/null and b/mods/species/neoavians/icons/blood_avian.dmi differ diff --git a/mods/species/neoavians/icons/body.dmi b/mods/species/neoavians/icons/body.dmi new file mode 100644 index 000000000000..b18e8546bf53 Binary files /dev/null and b/mods/species/neoavians/icons/body.dmi differ diff --git a/mods/species/neoavians/icons/body_add.dmi b/mods/species/neoavians/icons/body_add.dmi new file mode 100644 index 000000000000..c2e34e79f41a Binary files /dev/null and b/mods/species/neoavians/icons/body_add.dmi differ diff --git a/mods/species/neoavians/icons/body_raptor.dmi b/mods/species/neoavians/icons/body_raptor.dmi new file mode 100644 index 000000000000..8906e2a4ea2e Binary files /dev/null and b/mods/species/neoavians/icons/body_raptor.dmi differ diff --git a/mods/species/neoavians/icons/body_raptor_add.dmi b/mods/species/neoavians/icons/body_raptor_add.dmi new file mode 100644 index 000000000000..7a2b91c115b6 Binary files /dev/null and b/mods/species/neoavians/icons/body_raptor_add.dmi differ diff --git a/mods/species/neoavians/icons/body_synthetic.dmi b/mods/species/neoavians/icons/body_synthetic.dmi new file mode 100644 index 000000000000..2f0f17a8b4d1 Binary files /dev/null and b/mods/species/neoavians/icons/body_synthetic.dmi differ diff --git a/mods/species/neoavians/icons/body_synthetic_raptor.dmi b/mods/species/neoavians/icons/body_synthetic_raptor.dmi new file mode 100644 index 000000000000..10659c8c7870 Binary files /dev/null and b/mods/species/neoavians/icons/body_synthetic_raptor.dmi differ diff --git a/mods/species/neoavians/icons/clothing/accessory/cloak.dmi b/mods/species/neoavians/icons/clothing/accessory/cloak.dmi new file mode 100644 index 000000000000..3ff9c8f6c2f8 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/accessory/cloak.dmi differ diff --git a/mods/species/neoavians/icons/clothing/accessory/cloak_hide.dmi b/mods/species/neoavians/icons/clothing/accessory/cloak_hide.dmi new file mode 100644 index 000000000000..baf1b7dbe166 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/accessory/cloak_hide.dmi differ diff --git a/mods/species/neoavians/icons/clothing/accessory/cloak_hooded.dmi b/mods/species/neoavians/icons/clothing/accessory/cloak_hooded.dmi new file mode 100644 index 000000000000..f19114b211a3 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/accessory/cloak_hooded.dmi differ diff --git a/mods/species/neoavians/icons/clothing/feet/footwraps.dmi b/mods/species/neoavians/icons/clothing/feet/footwraps.dmi new file mode 100644 index 000000000000..63189428dfce Binary files /dev/null and b/mods/species/neoavians/icons/clothing/feet/footwraps.dmi differ diff --git a/mods/species/neoavians/icons/clothing/feet/galoshes.dmi b/mods/species/neoavians/icons/clothing/feet/galoshes.dmi new file mode 100644 index 000000000000..a80d0e62776f Binary files /dev/null and b/mods/species/neoavians/icons/clothing/feet/galoshes.dmi differ diff --git a/mods/species/neoavians/icons/clothing/feet/magboots.dmi b/mods/species/neoavians/icons/clothing/feet/magboots.dmi new file mode 100644 index 000000000000..dffa389f29fc Binary files /dev/null and b/mods/species/neoavians/icons/clothing/feet/magboots.dmi differ diff --git a/mods/species/neoavians/icons/clothing/feet/shoes.dmi b/mods/species/neoavians/icons/clothing/feet/shoes.dmi new file mode 100644 index 000000000000..842c03257065 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/feet/shoes.dmi differ diff --git a/mods/species/neoavians/icons/clothing/gloves.dmi b/mods/species/neoavians/icons/clothing/gloves.dmi new file mode 100644 index 000000000000..e35517789eee Binary files /dev/null and b/mods/species/neoavians/icons/clothing/gloves.dmi differ diff --git a/mods/species/neoavians/icons/clothing/head/cloak_hood.dmi b/mods/species/neoavians/icons/clothing/head/cloak_hood.dmi new file mode 100644 index 000000000000..eb63cd76f236 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/head/cloak_hood.dmi differ diff --git a/mods/species/neoavians/icons/clothing/head/hood.dmi b/mods/species/neoavians/icons/clothing/head/hood.dmi new file mode 100644 index 000000000000..61cfec5138f0 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/head/hood.dmi differ diff --git a/mods/species/neoavians/icons/clothing/head/rad_helm.dmi b/mods/species/neoavians/icons/clothing/head/rad_helm.dmi new file mode 100644 index 000000000000..3017e4c8fc34 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/head/rad_helm.dmi differ diff --git a/mods/species/neoavians/icons/clothing/satchel.dmi b/mods/species/neoavians/icons/clothing/satchel.dmi new file mode 100644 index 000000000000..a78c9d94d883 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/satchel.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/atmos/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/atmos/helmet.dmi new file mode 100644 index 000000000000..73d39b50297b Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/atmos/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/atmos/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/atmos/suit.dmi new file mode 100644 index 000000000000..2b56baffa799 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/atmos/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/engineering/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/engineering/helmet.dmi new file mode 100644 index 000000000000..0fb2dfb4ba65 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/engineering/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/engineering/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/engineering/suit.dmi new file mode 100644 index 000000000000..16e1b0ccd892 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/engineering/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/expedition/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/expedition/helmet.dmi new file mode 100644 index 000000000000..b2bd6de798cc Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/expedition/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/expedition/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/expedition/suit.dmi new file mode 100644 index 000000000000..e1f97b529a1b Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/expedition/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi new file mode 100644 index 000000000000..645c2a006bf7 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical/suit.dmi new file mode 100644 index 000000000000..df5c91f9f039 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi new file mode 100644 index 000000000000..779b0d77fe46 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi new file mode 100644 index 000000000000..c84f8e938c69 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/merc/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/merc/helmet.dmi new file mode 100644 index 000000000000..8d749fb76225 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/merc/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/merc/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/merc/suit.dmi new file mode 100644 index 000000000000..98453d9ce1cd Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/merc/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi new file mode 100644 index 000000000000..99c198ae9a58 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/mining/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/mining/suit.dmi new file mode 100644 index 000000000000..b7bf8eaa8b50 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/mining/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/salvage/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/salvage/helmet.dmi new file mode 100644 index 000000000000..c0b2a9d9c1dc Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/salvage/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/salvage/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/salvage/suit.dmi new file mode 100644 index 000000000000..8345d1eb3159 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/salvage/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/sec/helmet.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/sec/helmet.dmi new file mode 100644 index 000000000000..5109e977a291 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/sec/helmet.dmi differ diff --git a/mods/species/neoavians/icons/clothing/spacesuit/void/sec/suit.dmi b/mods/species/neoavians/icons/clothing/spacesuit/void/sec/suit.dmi new file mode 100644 index 000000000000..75ab5ae23ee0 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/spacesuit/void/sec/suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/suit/rad_suit.dmi b/mods/species/neoavians/icons/clothing/suit/rad_suit.dmi new file mode 100644 index 000000000000..19f711f7c118 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/suit/rad_suit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/black_utility.dmi b/mods/species/neoavians/icons/clothing/under/black_utility.dmi new file mode 100644 index 000000000000..eb00ba93eaa2 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/black_utility.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/gray_utility.dmi b/mods/species/neoavians/icons/clothing/under/gray_utility.dmi new file mode 100644 index 000000000000..76bcff4edea2 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/gray_utility.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/jumpsuit.dmi b/mods/species/neoavians/icons/clothing/under/jumpsuit.dmi new file mode 100644 index 000000000000..6db5380e5890 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/jumpsuit.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/smock.dmi b/mods/species/neoavians/icons/clothing/under/smock.dmi new file mode 100644 index 000000000000..6f02969688cf Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/smock.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/smock_grey.dmi b/mods/species/neoavians/icons/clothing/under/smock_grey.dmi new file mode 100644 index 000000000000..b940e87e0041 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/smock_grey.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/smock_rainbow.dmi b/mods/species/neoavians/icons/clothing/under/smock_rainbow.dmi new file mode 100644 index 000000000000..97769349a043 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/smock_rainbow.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/smock_red.dmi b/mods/species/neoavians/icons/clothing/under/smock_red.dmi new file mode 100644 index 000000000000..fe8629c49e4a Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/smock_red.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/smock_yellow.dmi b/mods/species/neoavians/icons/clothing/under/smock_yellow.dmi new file mode 100644 index 000000000000..915970f2fd99 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/smock_yellow.dmi differ diff --git a/mods/species/neoavians/icons/clothing/under/stylish_form.dmi b/mods/species/neoavians/icons/clothing/under/stylish_form.dmi new file mode 100644 index 000000000000..da9f027e4d99 Binary files /dev/null and b/mods/species/neoavians/icons/clothing/under/stylish_form.dmi differ diff --git a/mods/species/neoavians/icons/ears.dmi b/mods/species/neoavians/icons/ears.dmi new file mode 100644 index 000000000000..876e831defa2 Binary files /dev/null and b/mods/species/neoavians/icons/ears.dmi differ diff --git a/mods/species/neoavians/icons/eyes.dmi b/mods/species/neoavians/icons/eyes.dmi new file mode 100644 index 000000000000..1dd1ba7545a1 Binary files /dev/null and b/mods/species/neoavians/icons/eyes.dmi differ diff --git a/mods/species/neoavians/icons/hair.dmi b/mods/species/neoavians/icons/hair.dmi new file mode 100644 index 000000000000..cfc280f1e8aa Binary files /dev/null and b/mods/species/neoavians/icons/hair.dmi differ diff --git a/mods/species/neoavians/icons/holder.dmi b/mods/species/neoavians/icons/holder.dmi new file mode 100644 index 000000000000..4d7e407ebd97 Binary files /dev/null and b/mods/species/neoavians/icons/holder.dmi differ diff --git a/mods/species/neoavians/icons/markings.dmi b/mods/species/neoavians/icons/markings.dmi new file mode 100644 index 000000000000..a7307dc368d3 Binary files /dev/null and b/mods/species/neoavians/icons/markings.dmi differ diff --git a/mods/species/neoavians/icons/skeleton.dmi b/mods/species/neoavians/icons/skeleton.dmi new file mode 100644 index 000000000000..7691879bda9e Binary files /dev/null and b/mods/species/neoavians/icons/skeleton.dmi differ diff --git a/mods/species/neoavians/icons/tail.dmi b/mods/species/neoavians/icons/tail.dmi new file mode 100644 index 000000000000..abe28e59b43b Binary files /dev/null and b/mods/species/neoavians/icons/tail.dmi differ diff --git a/mods/species/neoavians/icons/tail_synthetic.dmi b/mods/species/neoavians/icons/tail_synthetic.dmi new file mode 100644 index 000000000000..e5f4cd5b0fa8 Binary files /dev/null and b/mods/species/neoavians/icons/tail_synthetic.dmi differ diff --git a/mods/species/neoavians/machinery/suit_cycler.dm b/mods/species/neoavians/machinery/suit_cycler.dm new file mode 100644 index 000000000000..5a59ed475b36 --- /dev/null +++ b/mods/species/neoavians/machinery/suit_cycler.dm @@ -0,0 +1,72 @@ +/obj/machinery/suit_cycler/Initialize() + LAZYDISTINCTADD(available_bodytypes, BODYTYPE_AVIAN) + . = ..() + +//mining + +/obj/item/clothing/suit/space/void/mining + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/suit.dmi' + +/obj/item/clothing/head/helmet/space/void/mining + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi' + +//excavation +/obj/item/clothing/suit/space/void/excavation + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/suit.dmi' + +/obj/item/clothing/head/helmet/space/void/excavation + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/mining/helmet.dmi' + +//engineering +/obj/item/clothing/head/helmet/space/void/engineering + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/engineering/helmet.dmi' + +/obj/item/clothing/suit/space/void/engineering + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/engineering/suit.dmi' + +/obj/item/clothing/head/helmet/space/void/atmos + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/atmos/helmet.dmi' + +/obj/item/clothing/suit/space/void/atmos + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/atmos/suit.dmi' + +//medical +/obj/item/clothing/suit/space/void/medical + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical/suit.dmi' + +/obj/item/clothing/head/helmet/space/void/medical + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical/helmet.dmi' + +/obj/item/clothing/suit/space/void/medical/alt + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/suit.dmi' + +/obj/item/clothing/head/helmet/space/void/medical/alt + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt/helmet.dmi' + +//security +/obj/item/clothing/head/helmet/space/void/security + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/sec/helmet.dmi' + +/obj/item/clothing/suit/space/void/security + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/sec/suit.dmi' + +//salvage +/obj/item/clothing/head/helmet/space/void/engineering/salvage + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/salvage/helmet.dmi' + +/obj/item/clothing/suit/space/void/engineering/salvage + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/salvage/suit.dmi' + +//pilot +/obj/item/clothing/head/helmet/space/void/expedition + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/expedition/helmet.dmi' + +/obj/item/clothing/suit/space/void/expedition + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/expedition/suit.dmi' + +//merc +/obj/item/clothing/head/helmet/space/void/merc + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/merc/helmet.dmi' + +/obj/item/clothing/suit/space/void/merc + _avian_onmob_icon = 'mods/species/neoavians/icons/clothing/spacesuit/void/merc/suit.dmi' \ No newline at end of file diff --git a/mods/species/neoavians/sound/crow1.ogg b/mods/species/neoavians/sound/crow1.ogg new file mode 100644 index 000000000000..26f5606ce953 Binary files /dev/null and b/mods/species/neoavians/sound/crow1.ogg differ diff --git a/mods/species/neoavians/sound/crow2.ogg b/mods/species/neoavians/sound/crow2.ogg new file mode 100644 index 000000000000..783d04c9327b Binary files /dev/null and b/mods/species/neoavians/sound/crow2.ogg differ diff --git a/mods/species/neoavians/sound/crow3.ogg b/mods/species/neoavians/sound/crow3.ogg new file mode 100644 index 000000000000..a6ab62d3d9d3 Binary files /dev/null and b/mods/species/neoavians/sound/crow3.ogg differ diff --git a/mods/species/neoavians/sound/crow4.ogg b/mods/species/neoavians/sound/crow4.ogg new file mode 100644 index 000000000000..1d81f6f88516 Binary files /dev/null and b/mods/species/neoavians/sound/crow4.ogg differ diff --git a/mods/species/random_species/_random_species.dm b/mods/species/random_species/_random_species.dm new file mode 100644 index 000000000000..49640db2218c --- /dev/null +++ b/mods/species/random_species/_random_species.dm @@ -0,0 +1,6 @@ +/decl/modpack/random_species + name = "Random Alien Species" + +/decl/modpack/random_species/initialize() + . = ..() + SSmodpacks.default_submap_blacklisted_species += /decl/species/alium::uid diff --git a/mods/species/random_species/_random_species.dme b/mods/species/random_species/_random_species.dme new file mode 100644 index 000000000000..fda80f4abf42 --- /dev/null +++ b/mods/species/random_species/_random_species.dme @@ -0,0 +1,9 @@ +#ifndef SPECIES_PACK_RANDOM +#define SPECIES_PACK_RANDOM +// BEGIN_INCLUDE +#include "_random_species.dm" +#include "aliumizer.dm" +#include "random_species_bodytype.dm" +#include "random_species_species.dm" +// END_INCLUDE +#endif diff --git a/mods/species/random_species/aliumizer.dm b/mods/species/random_species/aliumizer.dm new file mode 100644 index 000000000000..b80582cc5d45 --- /dev/null +++ b/mods/species/random_species/aliumizer.dm @@ -0,0 +1,34 @@ +/obj/structure/aliumizer + name = "alien monolith" + desc = "Your true form is calling. Use this to become an alien humanoid." + icon = 'icons/obj/xenoarchaeology.dmi' // todo: duplicate icon in modpack to avoid skew from upstream changes? + icon_state = "ano51" + anchored = TRUE + +/obj/structure/aliumizer/attack_hand(mob/user) + SHOULD_CALL_PARENT(FALSE) + if(!ishuman(user)) + to_chat(user, SPAN_WARNING("You've got no business touching this.")) + return TRUE + var/decl/species/species = user.get_species() + if(!species) + return TRUE + if(species.uid == /decl/species/alium::uid) + to_chat(user, SPAN_WARNING("You're already an alien.")) + return TRUE + if(alert("Are you sure you want to be an alien?", "Mom Look I'm An Alien!", "Yes", "No") == "No") + to_chat(user, SPAN_NOTICE("You are now an alien!")) + return TRUE + if(species.uid == /decl/species/alium::uid) //no spamming it to get free implants + return TRUE + to_chat(user, "You're now an alien humanoid of some undiscovered species. Make up what lore you want, no one knows a thing about your species! You can check info about your traits with Check Species Info verb in IC tab.") + to_chat(user, "You can't speak any other languages by default. You can use translator implant that spawns on top of this monolith - it will give you knowledge of any language if you hear it enough times.") + var/mob/living/human/H = user + new /obj/item/implanter/translator(get_turf(src)) + H.change_species(/decl/species/alium::uid) + var/decl/background_detail/background = H.get_background_datum_by_flag(BACKGROUND_FLAG_NAMING) + H.fully_replace_character_name(background.get_random_cultural_name(H, H.gender, /decl/species/alium::uid)) + H.rename_self("Humanoid Alien", 1) + return TRUE + +OPTIONAL_SPAWNER(aliumizer, /obj/structure/aliumizer) \ No newline at end of file diff --git a/mods/species/random_species/random_species_bodytype.dm b/mods/species/random_species/random_species_bodytype.dm new file mode 100644 index 000000000000..b4a015834ff8 --- /dev/null +++ b/mods/species/random_species/random_species_bodytype.dm @@ -0,0 +1,28 @@ +/decl/bodytype/alium + name = "humanoid" + bodytype_category = BODYTYPE_HUMANOID + icon_base = 'icons/mob/human_races/species/humanoid/body.dmi' + bandages_icon = 'icons/mob/bandage.dmi' + limb_blend = ICON_MULTIPLY + appearance_flags = HAS_SKIN_COLOR + body_flags = BODY_FLAG_NO_DNA | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS + uid = "bodytype_alium" + +/decl/bodytype/alium/Initialize() + if(prob(10)) + movement_slowdown += pick(-1,1) + if(prob(5)) + body_flags |= BODY_FLAG_NO_PAIN + base_color = RANDOM_RGB + MULT_BY_RANDOM_COEF(eye_flash_mod, 0.5, 1.5) + eye_darksight_range = rand(1,8) + var/temp_comfort_shift = rand(-50,50) + cold_level_1 += temp_comfort_shift + cold_level_2 += temp_comfort_shift + cold_level_3 += temp_comfort_shift + heat_level_1 += temp_comfort_shift + heat_level_2 += temp_comfort_shift + heat_level_3 += temp_comfort_shift + heat_discomfort_level += temp_comfort_shift + cold_discomfort_level += temp_comfort_shift + . = ..() \ No newline at end of file diff --git a/mods/species/random_species/random_species_species.dm b/mods/species/random_species/random_species_species.dm new file mode 100644 index 000000000000..841303920e65 --- /dev/null +++ b/mods/species/random_species/random_species_species.dm @@ -0,0 +1,82 @@ +/decl/species/alium + uid = "species_random_alien" + name = "Humanoid" + name_plural = "Humanoids" + description = "Some alien humanoid species, unknown to humanity. How exciting." + rarity_value = 5 + hidden_from_codex = TRUE + + spawn_flags = SPECIES_IS_RESTRICTED + + available_bodytypes = list(/decl/bodytype/alium) + + force_background_info = list( + /decl/background_category/heritage = /decl/background_detail/heritage/hidden/alium + ) + + exertion_effect_chance = 10 + exertion_hydration_scale = 1 + exertion_reagent_scale = 1 + exertion_reagent_path = /decl/material/liquid/lactate + exertion_emotes_biological = list( + /decl/emote/exertion/biological, + /decl/emote/exertion/biological/breath, + /decl/emote/exertion/biological/pant + ) + var/blood_color + +/decl/species/alium/Initialize() + + //Coloring + blood_color = RANDOM_RGB + flesh_color = RANDOM_RGB + + //Combat stats + MULT_BY_RANDOM_COEF(total_health, 0.8, 1.2) + MULT_BY_RANDOM_COEF(brute_mod, 0.5, 1.5) + MULT_BY_RANDOM_COEF(burn_mod, 0.8, 1.2) + MULT_BY_RANDOM_COEF(oxy_mod, 0.5, 1.5) + MULT_BY_RANDOM_COEF(toxins_mod, 0, 2) + MULT_BY_RANDOM_COEF(radiation_mod, 0, 2) + + if(brute_mod < 1 && prob(40)) + species_flags |= SPECIES_FLAG_NO_MINOR_CUT + if(brute_mod < 0.9 && prob(40)) + species_flags |= SPECIES_FLAG_NO_EMBED + if(toxins_mod < 0.1) + species_flags |= SPECIES_FLAG_NO_POISON + + //Gastronomic traits + taste_sensitivity = pick(TASTE_HYPERSENSITIVE, TASTE_SENSITIVE, TASTE_DULL, TASTE_NUMB) + gluttonous = pick(0, GLUT_TINY, GLUT_SMALLER, GLUT_ANYTHING) + stomach_capacity = 5 * stomach_capacity + if(prob(20)) + gluttonous |= pick(GLUT_ITEM_TINY, GLUT_ITEM_NORMAL, GLUT_ITEM_ANYTHING, GLUT_PROJECTILE_VOMIT) + if(gluttonous & GLUT_ITEM_ANYTHING) + stomach_capacity += ITEM_SIZE_HUGE + + //Environment + var/temp_comfort_shift = rand(-50,50) + body_temperature += temp_comfort_shift + + var/pressure_comfort_shift = rand(-50,50) + hazard_high_pressure += pressure_comfort_shift + warning_high_pressure += pressure_comfort_shift + warning_low_pressure += pressure_comfort_shift + hazard_low_pressure += pressure_comfort_shift + + //Misc traits + if(prob(40)) + // 50% chance of pseudoplural or actually plural + available_pronouns = list(pick(/decl/pronouns/pseudoplural, /decl/pronouns)) + if(prob(10)) + species_flags |= SPECIES_FLAG_NO_SLIP + if(prob(10)) + species_flags |= SPECIES_FLAG_NO_TANGLE + + . = ..() + +/decl/species/alium/get_species_blood_color(mob/living/human/H) + if(istype(H) && H.isSynthetic()) + return ..() + return blood_color \ No newline at end of file diff --git a/mods/species/serpentid/_serpentid.dme b/mods/species/serpentid/_serpentid.dme new file mode 100644 index 000000000000..3174f66ddfcc --- /dev/null +++ b/mods/species/serpentid/_serpentid.dme @@ -0,0 +1,9 @@ +#ifndef MODPACK_SERPENTID +#define MODPACK_SERPENTID +// BEGIN_INCLUDE +#include "serpentid.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "mobs\bodyparts_serpentid.dm" +// END_INCLUDE +#endif diff --git a/mods/species/serpentid/datum/species.dm b/mods/species/serpentid/datum/species.dm new file mode 100644 index 000000000000..f01a3f4c746f --- /dev/null +++ b/mods/species/serpentid/datum/species.dm @@ -0,0 +1,194 @@ +/datum/appearance_descriptor/age/serpentid + chargen_min_index = 3 + chargen_max_index = 6 + standalone_value_descriptors = list( + "a larva" = 1, + "a nymph" = 2, + "a juvenile" = 3, + "an adolescent" = 5, + "a young adult" = 12, + "a full adult" = 30, + "senescent" = 45 + ) + +/decl/butchery_data/humanoid/serpentid + skin_material = /decl/material/solid/organic/skin/insect + + bone_material = null + bone_amount = null + bone_type = null + +/decl/species/serpentid + uid = "species_serpentid" + name = "Serpentid" + name_plural = "Serpentids" + spawn_flags = SPECIES_IS_RESTRICTED + + preview_outfit = null + + blood_types = list(/decl/blood_type/hemolymph) + + hidden_from_codex = TRUE + silent_steps = TRUE + butchery_data = /decl/butchery_data/humanoid/serpentid + speech_sounds = list('sound/voice/bug.ogg') + speech_chance = 2 + warning_low_pressure = 50 + hazard_low_pressure = -1 + body_temperature = null + flesh_color = "#525252" + blood_oxy = 0 + + available_bodytypes = list( + /decl/bodytype/serpentid, + /decl/bodytype/serpentid/green + ) + + rarity_value = 4 + species_hud = /datum/hud_data/serpentid + total_health = 200 + brute_mod = 0.9 + burn_mod = 1.35 + + gluttonous = GLUT_SMALLER + strength = STR_HIGH + breath_pressure = 25 + blood_volume = 840 + species_flags = SPECIES_FLAG_NO_SLIP | SPECIES_FLAG_NO_BLOCK | SPECIES_FLAG_NO_MINOR_CUT | SPECIES_FLAG_NEED_DIRECT_ABSORB + spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED + bump_flag = HEAVY + push_flags = ALLMOBS + swap_flags = ALLMOBS + move_trail = /obj/effect/decal/cleanable/blood/tracks/snake + + pain_emotes_with_pain_level = list( + list(/decl/emote/audible/bug_hiss) = 40 + ) + var/list/skin_overlays = list() + +#define SERPENTID_FLIGHT_PRESSURE_THRESHOLD 80 +/decl/species/serpentid/can_overcome_gravity(var/mob/living/human/H) + var/datum/gas_mixture/mixture = H.loc.return_air() + var/pressure = mixture?.return_pressure() + if(pressure >= SERPENTID_FLIGHT_PRESSURE_THRESHOLD) + return TRUE + return FALSE +#undef SERPENTID_FLIGHT_PRESSURE_THRESHOLD + +/decl/species/serpentid/handle_environment_special(var/mob/living/human/H) + if(!H.is_on_fire() && H.get_fire_intensity() < 2) + H.adjust_fire_intensity(0.2) + return + +/decl/species/serpentid/handle_fall_special(var/mob/living/human/H, var/turf/landing) + + var/datum/gas_mixture/mixture = H.loc.return_air() + var/turf/T = GetBelow(H.loc) + for(var/obj/O in T) + if(istype(O, /obj/structure/stairs)) + return FALSE + + if(mixture) + var/pressure = mixture.return_pressure() + if(pressure > 50) + if(istype(landing) && landing.is_open()) + H.visible_message("\The [H] descends from the deck above through \the [landing]!", "Your wings slow your descent.") + else + H.visible_message("\The [H] buzzes down from \the [landing], wings slowing their descent!", "You land on \the [landing], folding your wings.") + + return TRUE + + return FALSE + +/decl/species/serpentid/handle_movement_delay_special(var/mob/living/human/victim) + var/tally = 0 + victim.remove_mob_modifier(/decl/mob_modifier/cloaked, source = src) + var/obj/item/organ/internal/brain/insectoid/serpentid/bugbrain = victim.get_organ(BP_BRAIN, /obj/item/organ/internal/brain/insectoid/serpentid) + if(bugbrain) + tally += bugbrain.lowblood_tally * 2 + return tally + +// todo: make this on bodytype +/decl/species/serpentid/update_skin(var/mob/living/human/H) + + if(H.stat) + H.skin_state = SKIN_NORMAL + + switch(H.skin_state) + if(SKIN_NORMAL) + return + if(SKIN_THREAT) + + var/image_key = "[H.get_bodytype().get_icon_cache_uid(H)]" + + for(var/organ_tag in H.get_bodytype().has_limbs) + var/obj/item/organ/external/part = H.get_organ(organ_tag) + if(!part) + image_key += "0" + continue + if(part) + image_key += "[part.bodytype.get_icon_cache_uid(part.owner)]" + if(!BP_IS_PROSTHETIC(part) && (part.status & ORGAN_DEAD)) + image_key += "2" + else + image_key += "1" + + var/image/threat_image = skin_overlays[image_key] + if(!threat_image) + var/icon/base_icon = icon(H.stand_icon) + var/icon/I = new('mods/species/serpentid/icons/threat.dmi', "threat") + base_icon.Blend(COLOR_BLACK, ICON_MULTIPLY) + base_icon.Blend(I, ICON_ADD) + threat_image = image(base_icon) + skin_overlays[image_key] = threat_image + + return(threat_image) + + +/decl/species/serpentid/disarm_attackhand(var/mob/living/human/attacker, var/mob/living/human/target) + if(attacker.pulling_punches || target.current_posture.prone || attacker == target) + return ..(attacker, target) + if(world.time < attacker.last_attack + 20) + to_chat(attacker, SPAN_NOTICE("You can't attack again so soon.")) + return 0 + attacker.last_attack = world.time + var/turf/T = get_step(get_turf(target), get_dir(get_turf(attacker), get_turf(target))) + playsound(target.loc, 'sound/weapons/pushhiss.ogg', 50, 1, -1) + if(!T.density) + step(target, get_dir(get_turf(attacker), get_turf(target))) + target.visible_message(SPAN_DANGER("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]")) + else + target.turf_collision(T, target.throw_speed / 2) + if(prob(50)) + target.set_dir(global.reverse_dir[target.dir]) + +/decl/species/serpentid/skills_from_age(age) //Converts an age into a skill point allocation modifier. Can be used to give skill point bonuses/penalities not depending on job. + switch(age) + if(0 to 18) . = 8 + if(19 to 27) . = 2 + if(28 to 40) . = -2 + else . = -4 + +/datum/hud_data/serpentid + inventory_slots = list( + /datum/inventory_slot/handcuffs, + /datum/inventory_slot/uniform, + /datum/inventory_slot/suit/serpentid, + /datum/inventory_slot/ear/serpentid, + /datum/inventory_slot/gloves, + /datum/inventory_slot/head/serpentid, + /datum/inventory_slot/glasses, + /datum/inventory_slot/suit_storage, + /datum/inventory_slot/back, + /datum/inventory_slot/id, + /datum/inventory_slot/pocket, + /datum/inventory_slot/pocket/right, + /datum/inventory_slot/belt + ) + +/datum/inventory_slot/suit/serpentid + ui_loc = ui_shoes +/datum/inventory_slot/ear/serpentid + ui_loc = ui_oclothing +/datum/inventory_slot/head/serpentid + ui_loc = ui_mask \ No newline at end of file diff --git a/mods/species/serpentid/datum/species_bodytypes.dm b/mods/species/serpentid/datum/species_bodytypes.dm new file mode 100644 index 000000000000..947019f4db7e --- /dev/null +++ b/mods/species/serpentid/datum/species_bodytypes.dm @@ -0,0 +1,133 @@ +/decl/bodytype/serpentid + name = "grey" + icon_template = 'icons/mob/human_races/species/template_tall.dmi' + icon_base = 'mods/species/serpentid/icons/body_grey.dmi' + blood_overlays = 'mods/species/serpentid/icons/blood_overlays.dmi' + limb_blend = ICON_MULTIPLY + bodytype_category = BODYTYPE_SNAKE + antaghud_offset_y = 8 + bodytype_flag = BODY_EQUIP_FLAG_SNAKE + movement_slowdown = -0.5 + appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_SKIN_TONE_NORMAL + base_color = "#336600" + base_eye_color = "#3f0505" + mob_size = MOB_SIZE_LARGE + has_organ = list( + BP_BRAIN = /obj/item/organ/internal/brain/insectoid/serpentid, + BP_EYES = /obj/item/organ/internal/eyes/insectoid/serpentid, + BP_TRACH = /obj/item/organ/internal/lungs/insectoid/serpentid, + BP_HEART = /obj/item/organ/internal/heart/open, + BP_LIVER = /obj/item/organ/internal/liver/insectoid/serpentid, + BP_STOMACH = /obj/item/organ/internal/stomach/insectoid, + BP_PHEROMONE_GLAND = /obj/item/organ/internal/pheromone_gland + ) + age_descriptor = /datum/appearance_descriptor/age/serpentid + eye_darksight_range = 8 + eye_innate_flash_protection = FLASH_PROTECTION_VULNERABLE + eye_contaminant_guard = 1 + eye_icon = 'mods/species/serpentid/icons/eyes.dmi' + uid = "bodytype_serpentid" + + has_limbs = list( + BP_CHEST = list("path" = /obj/item/organ/external/chest/insectoid/serpentid), + BP_GROIN = list("path" = /obj/item/organ/external/groin/insectoid/serpentid), + BP_HEAD = list("path" = /obj/item/organ/external/head/insectoid/serpentid), + BP_L_ARM = list("path" = /obj/item/organ/external/arm/insectoid), + BP_L_HAND = list("path" = /obj/item/organ/external/hand/insectoid), + BP_L_HAND_UPPER = list("path" = /obj/item/organ/external/hand/insectoid/upper/serpentid), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/insectoid), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/insectoid), + BP_R_HAND_UPPER = list("path" = /obj/item/organ/external/hand/right/insectoid/upper/serpentid), + BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/insectoid/serpentid), + BP_L_LEG = list("path" = /obj/item/organ/external/leg/insectoid/serpentid), + BP_L_FOOT = list("path" = /obj/item/organ/external/foot/insectoid/serpentid), + BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/insectoid/serpentid) + ) + + appearance_descriptors = list( + /datum/appearance_descriptor/height = 1.75, + /datum/appearance_descriptor/body_length = 1 + ) + limb_mapping = list( + BP_L_HAND = list(BP_L_HAND, BP_L_HAND_UPPER), + BP_R_HAND = list(BP_R_HAND, BP_R_HAND_UPPER) + ) + breathing_organ = BP_TRACH + heat_level_1 = 410 //Default 360 - Higher is better + heat_level_2 = 440 //Default 400 + heat_level_3 = 800 //Default 1000 + + natural_armour_values = list( + ARMOR_MELEE = ARMOR_MELEE_KNIVES, + ARMOR_BULLET = ARMOR_BALLISTIC_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = 0.5*ARMOR_RAD_MINOR + ) + footprints_icon = 'icons/mob/footprints/footprints_snake.dmi' + +/decl/bodytype/serpentid/Initialize() + _equip_adjust = list( + (BP_L_HAND_UPPER) = list( + "[NORTH]" = list( 0, 8), + "[EAST]" = list( 0, 8), + "[SOUTH]" = list(-0, 8), + "[WEST]" = list( 0, 8) + ), + (BP_R_HAND_UPPER) = list( + "[NORTH]" = list( 0, 8), + "[EAST]" = list( 0, 8), + "[SOUTH]" = list( 0, 8), + "[WEST]" = list( 0, 8) + ), + (BP_L_HAND) = list( + "[NORTH]" = list( 4, 0), + "[EAST]" = list( 0, 0), + "[SOUTH]" = list(-4, 0), + "[WEST]" = list( 0, 0) + ), + (BP_R_HAND) = list( + "[NORTH]" = list(-4, 0), + "[EAST]" = list( 0, 0), + "[SOUTH]" = list( 4, 0), + "[WEST]" = list( 0, 0) + ), + (slot_head_str) = list( + "[NORTH]" = list( 0, 7), + "[EAST]" = list( 0, 8), + "[SOUTH]" = list( 0, 8), + "[WEST]" = list( 0, 8) + ), + (slot_back_str) = list( + "[NORTH]" = list( 0, 7), + "[EAST]" = list( 0, 8), + "[SOUTH]" = list( 0, 8), + "[WEST]" = list( 0, 8) + ), + (slot_belt_str) = list( + "[NORTH]" = list( 0, 0), + "[EAST]" = list( 8, 0), + "[SOUTH]" = list( 0, 0), + "[WEST]" = list(-8, 0) + ), + (slot_glasses_str) = list( + "[NORTH]" = list( 0, 10), + "[EAST]" = list( 0, 11), + "[SOUTH]" = list( 0, 11), + "[WEST]" = list( 0, 11) + ) + ) + . = ..() + +/decl/bodytype/serpentid/green + name = "green" + icon_base = 'mods/species/serpentid/icons/body_green.dmi' + uid = "bodytype_serpentid_green" + +/obj/item/organ/external/hand/insectoid/upper/serpentid/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/forelimb_slash) + return unarmed_attack + +/obj/item/organ/external/hand/right/insectoid/upper/serpentid/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/forelimb_slash) + return unarmed_attack diff --git a/mods/species/serpentid/icons/actions.dmi b/mods/species/serpentid/icons/actions.dmi new file mode 100644 index 000000000000..b61081e6e409 Binary files /dev/null and b/mods/species/serpentid/icons/actions.dmi differ diff --git a/mods/ascent/icons/species/body/serpentid/blood_mask.dmi b/mods/species/serpentid/icons/blood_overlays.dmi similarity index 100% rename from mods/ascent/icons/species/body/serpentid/blood_mask.dmi rename to mods/species/serpentid/icons/blood_overlays.dmi diff --git a/mods/species/serpentid/icons/body_green.dmi b/mods/species/serpentid/icons/body_green.dmi new file mode 100644 index 000000000000..97c96f522fc0 Binary files /dev/null and b/mods/species/serpentid/icons/body_green.dmi differ diff --git a/mods/species/serpentid/icons/body_grey.dmi b/mods/species/serpentid/icons/body_grey.dmi new file mode 100644 index 000000000000..6d17829bf869 Binary files /dev/null and b/mods/species/serpentid/icons/body_grey.dmi differ diff --git a/mods/ascent/icons/species/body/serpentid/eyes.dmi b/mods/species/serpentid/icons/eyes.dmi similarity index 100% rename from mods/ascent/icons/species/body/serpentid/eyes.dmi rename to mods/species/serpentid/icons/eyes.dmi diff --git a/mods/ascent/icons/species/body/serpentid/threat.dmi b/mods/species/serpentid/icons/threat.dmi similarity index 100% rename from mods/ascent/icons/species/body/serpentid/threat.dmi rename to mods/species/serpentid/icons/threat.dmi diff --git a/mods/species/serpentid/mobs/bodyparts_serpentid.dm b/mods/species/serpentid/mobs/bodyparts_serpentid.dm new file mode 100644 index 000000000000..636ac9fdbd0d --- /dev/null +++ b/mods/species/serpentid/mobs/bodyparts_serpentid.dm @@ -0,0 +1,211 @@ +/datum/action/item_action/organ/serpentid + button_icon = 'mods/species/serpentid/icons/actions.dmi' + +/obj/item/organ/internal/eyes/insectoid/serpentid + name = "compound eyes" + action_button_name = "Toggle Eye Shields" + default_action_type = /datum/action/item_action/organ/serpentid + var/eyes_shielded + var/override_flash_protection = FLASH_PROTECTION_VULNERABLE + +/obj/item/organ/internal/eyes/insectoid/serpentid/get_innate_flash_protection() + return override_flash_protection + +/obj/item/organ/internal/eyes/insectoid/serpentid/additional_flash_effects(var/intensity) + if(!eyes_shielded) + take_damage(max(0, 4 * (intensity))) + return 1 + else + return -1 + +/obj/item/organ/internal/eyes/insectoid/serpentid/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "shield-[eyes_shielded ? 1 : 0]" + action.button?.update_icon() + +/obj/item/organ/internal/eyes/insectoid/serpentid/attack_self(var/mob/user) + . = ..() + if(.) + eyes_shielded = !eyes_shielded + if(eyes_shielded) + to_chat(owner, "Nearly opaque lenses slide down to shield your eyes.") + override_flash_protection = FLASH_PROTECTION_MAJOR + owner.overlay_fullscreen("eyeshield", /obj/screen/fullscreen/blind) + owner.update_icon() + else + to_chat(owner, "Your protective lenses retract out of the way.") + override_flash_protection = FLASH_PROTECTION_VULNERABLE + addtimer(CALLBACK(src, PROC_REF(remove_shield)), 1 SECONDS) + owner.update_icon() + refresh_action_button() + +/obj/item/organ/internal/eyes/insectoid/serpentid/proc/remove_shield() + owner.clear_fullscreen("eyeshield") + +/obj/item/organ/internal/eyes/serpentid/Initialize() + . = ..() + if(owner) + color = owner.get_eye_colour() + +/obj/item/organ/internal/eyes/insectoid/serpentid/copy_from_mob_snapshot(datum/mob_snapshot/supplied_appearance) + . = ..() + color = supplied_appearance?.eye_color + +/obj/item/organ/internal/liver/insectoid/serpentid + name = "toxin filter" + color = "#66ff99" + organ_tag = BP_LIVER + parent_organ = BP_CHEST + +// These are not actually lungs and shouldn't be thought of as such despite the claims of the parent. +/obj/item/organ/internal/lungs/insectoid/serpentid + name = "tracheae" + gender = PLURAL + organ_tag = BP_TRACH + parent_organ = BP_GROIN + active_breathing = 0 + safe_toxins_max = 10 + +/obj/item/organ/internal/lungs/insectoid/serpentid/rupture() + to_chat(owner, "You feel air rushing through your trachea!") + +/obj/item/organ/internal/lungs/insectoid/serpentid/handle_failed_breath() + var/mob/living/human/H = owner + + var/oxygenated = GET_CHEMICAL_EFFECT(owner, CE_OXYGENATED) + H.heal_damage(OXY, HUMAN_MAX_OXYLOSS * oxygenated) + + if(breath_fail_ratio < 0.25 && oxygenated) + SET_HUD_ALERT(H, HUD_OXY, 0) + if(breath_fail_ratio >= 0.25 && (_organ_damage || world.time > last_successful_breath + 2 MINUTES)) + H.take_damage(HUMAN_MAX_OXYLOSS * breath_fail_ratio, OXY) + if(oxygenated) + SET_HUD_ALERT(H, HUD_OXY, 1) + else + SET_HUD_ALERT(H, HUD_OXY, 2) + +/obj/item/organ/internal/brain/insectoid/serpentid + var/lowblood_tally = 0 + name = "distributed nervous system" + parent_organ = BP_CHEST + +/obj/item/organ/internal/brain/insectoid/serpentid/Process() + if(!owner || !owner.should_have_organ(BP_HEART)) + return + + var/blood_volume = owner.get_blood_circulation() + + //Effects of bloodloss + switch(blood_volume) + if(BLOOD_VOLUME_SAFE to (INFINITY)) + lowblood_tally = 0 + if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) + lowblood_tally = 2 + if(prob(1)) + to_chat(owner, "You're finding it difficult to move.") + if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) + lowblood_tally = 4 + if(prob(1)) + to_chat(owner, "Moving has become very difficult.") + if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) + lowblood_tally = 6 + if(prob(15)) + to_chat(owner, "You're almost unable to move!") + if(-(INFINITY) to BLOOD_VOLUME_SURVIVE) + lowblood_tally = 10 + if(prob(10)) + to_chat(owner, "Your body is barely functioning and is starting to shut down.") + SET_STATUS_MAX(owner, STAT_PARA, 2) + var/obj/item/organ/internal/I = pick(owner.internal_organs) + I.take_damage(5) + ..() + +/obj/item/organ/external/chest/insectoid/serpentid + name = "thorax" + encased = "carapace" + action_button_name = "Perform Threat Display" + default_action_type = /datum/action/item_action/organ/serpentid + +/obj/item/organ/external/chest/insectoid/serpentid/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "threat" + action.button?.update_icon() + +/obj/item/organ/external/chest/insectoid/serpentid/attack_self(var/mob/user) + . = ..() + if(.) + if(owner.incapacitated()) + to_chat(owner, "You can't do a threat display in your current state.") + return + if(owner.skin_state == SKIN_NORMAL) + if(owner.pulling_punches) + to_chat(owner, "You must be in your hunting stance to do a threat display.") + else + var/message = alert(owner, "Would you like to show a scary message?",,"Cancel","Yes", "No") + if(message == "Cancel") + return + else if(message == "Yes") + var/decl/pronouns/pronouns = get_pronouns() + owner.visible_message(SPAN_WARNING("\The [owner]'s skin shifts to a deep red colour with dark chevrons running down in an almost hypnotic \ + pattern. Standing tall, [pronouns.he] strikes, sharp spikes aimed at those threatening [pronouns.him], claws whooshing through the air past them.")) + playsound(owner.loc, 'sound/effects/angrybug.ogg', 60, 0) + owner.skin_state = SKIN_THREAT + owner.update_skin() + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/human, reset_skin)), 10 SECONDS, TIMER_UNIQUE) + else if(owner.skin_state == SKIN_THREAT) + owner.reset_skin() + +/obj/item/organ/external/head/insectoid/serpentid + name = "head" + +/obj/item/organ/external/head/insectoid/serpentid/get_organ_eyes_overlay() + var/obj/item/organ/internal/eyes/eyes = get_eyes_organ() + var/icon/eyes_icon = eyes?.get_onhead_icon() + if(!eyes_icon) + return + var/image/eye_overlay = image(eyes_icon) + if(owner && owner.is_cloaked()) + eye_overlay.alpha = 100 + if(istype(eyes, /obj/item/organ/internal/eyes/insectoid/serpentid)) + var/obj/item/organ/internal/eyes/insectoid/serpentid/snake_eyes = eyes + if(snake_eyes.eyes_shielded) + eye_overlay.color = "#aaaaaa" + return eye_overlay + +/obj/item/organ/external/groin/insectoid/serpentid + name = "abdomen" + icon_position = UNDER + encased = "carapace" + action_button_name = "Toggle Active Camo" + default_action_type = /datum/action/item_action/organ/serpentid + cavity_max_w_class = ITEM_SIZE_LARGE + +/obj/item/organ/external/groin/insectoid/serpentid/refresh_action_button() + . = ..() + if(. && istype(action)) + action.button_icon_state = "cloak-[owner?.has_mob_modifier(/decl/mob_modifier/cloaked, source = species) ? 1 : 0]" + action.button?.update_icon() + +/obj/item/organ/external/groin/insectoid/serpentid/attack_self(var/mob/user) + . = ..() + if(. && owner) + if(owner.has_mob_modifier(/decl/mob_modifier/cloaked, source = species)) + owner.remove_mob_modifier(/decl/mob_modifier/cloaked, source = species) + else + owner.add_mob_modifier(/decl/mob_modifier/cloaked, source = species) + owner.apply_effect(2, STUN, 0) + refresh_action_button() + +/obj/item/organ/external/foot/insectoid/serpentid + name = "left tail tip" + +/obj/item/organ/external/foot/right/insectoid/serpentid + name = "right tail tip" + +/obj/item/organ/external/leg/insectoid/serpentid + name = "left tail side" + +/obj/item/organ/external/leg/right/insectoid/serpentid + name = "right tail side" diff --git a/mods/species/serpentid/serpentid.dm b/mods/species/serpentid/serpentid.dm new file mode 100644 index 000000000000..84d299d55140 --- /dev/null +++ b/mods/species/serpentid/serpentid.dm @@ -0,0 +1,6 @@ +#define BODYTYPE_SNAKE "snakelike body" +#define BODY_EQUIP_FLAG_SNAKE BITFLAG(12) +#define BP_TRACH "tracheae" + +/decl/modpack/serpentid + name = "Serpentid Species" \ No newline at end of file diff --git a/mods/species/skrell/_skrell.dm b/mods/species/skrell/_skrell.dm new file mode 100644 index 000000000000..b6ac75a5b89b --- /dev/null +++ b/mods/species/skrell/_skrell.dm @@ -0,0 +1,14 @@ +/decl/modpack/skrell + name = "Skrell Species" + tabloid_headlines = list( + "TENTACLES OF TERROR: SKRELL BLACK OPS SEIGE NYX NAVAL DEPOT. SHOCKING PHOTOGRAPHS INSIDE!", + "LOCAL MAN HAS SEIZURE AFTER SAYING SKRELLIAN NAME; FORCED ASSIMILATION SOON?" + ) + +/decl/modpack/skrell/pre_initialize() + ..() + SSmodpacks.default_submap_whitelisted_species |= /decl/species/skrell::uid + +/mob/living/human/skrell/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + species_uid = /decl/species/skrell::uid + . = ..() diff --git a/mods/species/skrell/_skrell.dme b/mods/species/skrell/_skrell.dme new file mode 100644 index 000000000000..e10b661dadb6 --- /dev/null +++ b/mods/species/skrell/_skrell.dme @@ -0,0 +1,30 @@ +#ifndef MODPACK_SPECIES_SKRELL +#define MODPACK_SPECIES_SKRELL +// BEGIN_INCLUDE +#include "_skrell.dm" +#include "datum\accessory.dm" +#include "datum\blood.dm" +#include "datum\culture.dm" +#include "datum\descriptor.dm" +#include "datum\emotes.dm" +#include "datum\faction.dm" +#include "datum\language.dm" +#include "datum\location.dm" +#include "datum\pronouns_skrell.dm" +#include "datum\religion.dm" +#include "datum\skrell_meat.dm" +#include "datum\species.dm" +#include "datum\species_bodytype.dm" +#include "gear\ammo.dm" +#include "gear\clustertool.dm" +#include "gear\fabrication_designs.dm" +#include "gear\gear.dm" +#include "gear\gear_ears.dm" +#include "gear\gear_head.dm" +#include "gear\gear_mask.dm" +#include "gear\gear_rig.dm" +#include "gear\gear_suit.dm" +#include "gear\gear_under.dm" +#include "turfs\flooring.dm" +// END_INCLUDE +#endif diff --git a/mods/species/skrell/datum/accessory.dm b/mods/species/skrell/datum/accessory.dm new file mode 100644 index 000000000000..6f142dccdb15 --- /dev/null +++ b/mods/species/skrell/datum/accessory.dm @@ -0,0 +1,71 @@ +/decl/sprite_accessory/hair/skrell + name = "Kanin - Very Short Headtails" + icon = 'mods/species/skrell/icons/body/hair.dmi' + icon_state = "very_short" + species_allowed = list(/decl/species/skrell::uid) + uid = "acc_hair_skrell_veryshort" + +/decl/sprite_accessory/hair/skrell/raskin + name = "Raskinta - Split Very Short Headtails" + icon_state = "split" + uid = "acc_hair_skrell_veryshortsplit" + +/decl/sprite_accessory/hair/skrell/short + name = "Malish - Short Headtails" + icon_state = "short" + uid = "acc_hair_skrell_short" + +/decl/sprite_accessory/hair/skrell/malishpullback + name = "Malish - Pullback" + icon_state = "pullback-short" + uid = "acc_hair_skrell_short_pullback" + +/decl/sprite_accessory/hair/skrell/long + name = "Talum - Long Headtails" + icon_state = "long" + uid = "acc_hair_skrell_long" + +/decl/sprite_accessory/hair/skrell/talumpullback + name = "Talum - Pullback" + icon_state = "pullback-long" + uid = "acc_hair_skrell_long_pullback" + +/decl/sprite_accessory/hair/skrell/wavy + name = "Talum - Wavy" + icon_state = "wavy-long" + uid = "acc_hair_skrell_wavy" + +/decl/sprite_accessory/hair/skrell/tied + name = "Talum - Tied" + icon_state = "tied-long" + uid = "acc_hair_skrell_tied" + +/decl/sprite_accessory/hair/skrell/scarf + name = "Talum - Scarf" + icon_state = "scarf-long" + uid = "acc_hair_skrell_scarf" + +/decl/sprite_accessory/hair/skrell/very_long + name = "Qerr - Very Long Headtails" + icon_state = "very_long" + uid = "acc_hair_skrell_verylong" + +/decl/sprite_accessory/hair/skrell/tiedq + name = "Qerr - Tied Headtails" + icon_state = "tied-very_long" + uid = "acc_hair_skrell_verylong_tied" + +/decl/sprite_accessory/hair/skrell/scarfq + name = "Qerr - Scarf" + icon_state = "scarf-very_long" + uid = "acc_hair_skrell_verylong_scarf" + +/decl/sprite_accessory/hair/skrell/reef + name = "Qerr - Wavy" + icon_state = "wavy-very_long" + uid = "acc_hair_skrell_verylong_wavy" + +/decl/sprite_accessory/hair/skrell/qerrpullback + name = "Qerr - Pullback" + icon_state = "pullback-very_long" + uid = "acc_hair_skrell_verylong_pullback" diff --git a/mods/species/skrell/datum/blood.dm b/mods/species/skrell/datum/blood.dm new file mode 100644 index 000000000000..ba0767a0f371 --- /dev/null +++ b/mods/species/skrell/datum/blood.dm @@ -0,0 +1,58 @@ +/decl/blood_type/skrell + abstract_type = /decl/blood_type/skrell + splatter_colour = "#1d2cbf" + antigens = list("Y", "Z", "Ph") + +/decl/blood_type/skrell/yplus + name = "Y+" + antigens = list("Y", "Ph") + random_weighting = 28 + +/decl/blood_type/skrell/yminus + name = "Y-" + antigens = list("Y") + random_weighting = 3 + +/decl/blood_type/skrell/zplus + name = "Z+" + antigens = list("Z", "Ph") + random_weighting = 20 + +/decl/blood_type/skrell/zminus + name = "Z-" + antigens = list("Z") + +/decl/blood_type/skrell/yzplus + name = "YZ+" + antigens = list("Y", "Z", "Ph") + random_weighting = 5 + +/decl/blood_type/skrell/yzminus + name = "YZ-" + antigens = list("Y", "Z") + +/decl/blood_type/skrell/noplus + name = "No+" + antigens = list("Ph") + random_weighting = 36 + +/decl/blood_type/skrell/nominus + name = "No-" + random_weighting = 4 + +/obj/item/chems/ivbag/blood/skrell_yplus + label_text = "Y+" +/obj/item/chems/ivbag/blood/skrell_yminus + label_text = "Y-" +/obj/item/chems/ivbag/blood/skrell_zplus + label_text = "Z+" +/obj/item/chems/ivbag/blood/skrell_zminus + label_text = "Z-" +/obj/item/chems/ivbag/blood/skrell_yzplus + label_text = "YZ+" +/obj/item/chems/ivbag/blood/skrell_yzminus + label_text = "YZ-" +/obj/item/chems/ivbag/blood/skrell_noplus + label_text = "No+" +/obj/item/chems/ivbag/blood/skrell_nominus + label_text = "No-" diff --git a/mods/species/skrell/datum/culture.dm b/mods/species/skrell/datum/culture.dm new file mode 100644 index 000000000000..41b0c91d5ddb --- /dev/null +++ b/mods/species/skrell/datum/culture.dm @@ -0,0 +1,122 @@ +/decl/background_detail/heritage/skrell + name = "Qerr-Katish" + description = "Considered as the leaders of Skrellkind, the Qerr-Katish are the face \ + and soul of skrellian society. Managers, diplomats, lawyers, they are notably the \ + only caste allowed to fulfil the role of Qerr-Skria, Qrii-Qerria and Qerr-Qerria. \ + Representatives of the Skrell, Qerr-Katish are highly social beings, sophisticated, and \ + organized. They tend to be rather conservative, although progressive ideas regularly \ + grow within the caste, as a stagnant society is a dying society. They generally are \ + the richest people of a City-State, although their money is generally invested in \ + various endeavours both in and out of skrellian society. Qerr-Katish families tend \ + to be rather small, being generally limited to one, sometimes two bondings. They \ + often dress in clothing made from softer, shinier materials, long and flowing and \ + has often been compared to the clothing of ancient Chinese nobles by human \ + scholars. Their skin is generally bright green. Qerr-Katish headtails are \ + famously long, reaching down to nearly their waists." + economic_power = 1.4 + language = /decl/language/skrell + secondary_langs = list( + /decl/language/human/common, + /decl/language/sign + ) + uid = "heritage_skrell_qerr" + +/decl/background_detail/heritage/skrell/caste_malish + name = "Malish-Katish" + description = "If the Qerr-Katish are the face of Skrellkind, the Malish-Katish are \ + its brain. Scientists of all sorts, they are the ones who allow skrellian society \ + to grow, be it technologically or ideologically. Highly inquisitive, they \ + are among the more progressive Skrell. However they are not very social, and their \ + emphasis on methodical thinking makes them less capable of acting quickly under \ + pressure and handling their feelings in public. They are less wealthy than the \ + Qerr-Katish, but their status affords them much comfort. Their families are generally \ + made up of two or three bondings. People within this caste often wear clothing made \ + from the same materials as the Qerr-katish yet more simplified, white shirts and \ + black pants with possible jewelry for decoration. Their skin is generally pale \ + green, sky blue or pale yellow. They have shorter headtails." + economic_power = 1.3 + uid = "heritage_skrell_malish" + +/decl/background_detail/heritage/skrell/caste_kanin + name = "Kanin-Katish" + description = "The main workforce of the Skrell. While their population growth has \ + decreased over the millennia of technological progress they are still one of the most \ + populous castes. With activities ranging from goods production and services to \ + engineering and construction they occupy the largest and most diversified sector of \ + skrellian activity. The Kanin-Katish are a very tightly knit community, both within \ + their families and with their coworkers. They possess a strong mental and physical \ + resilience. Very traditional, they hold rather conservative views on the world, and \ + their focus on the whole rather than self dampens much of their individualism. Their \ + families are frequently large, three or four bondings, generally with a couple of \ + partners, which does not leave them much in terms of money. The Kanin-Katish are among \ + the less wealthy people of skrellkind, but they do not seem to mind, as their work is \ + the life and blood of skrellian civilisation. Their clothing is made to last, the \ + personality of the Skrell often being shown through arm bands or headtail decorations \ + of any kind. Their skin is generally red, orange, pale yellow, dark orange or black. \ + They have very short headtails." + economic_power = 1.2 + uid = "heritage_skrell_kanin" + +/decl/background_detail/heritage/skrell/caste_talum + name = "Talum-Katish" + description = "Considering the Skrells' emphasis on functionality and practicality, one \ + would be mistaken to think they do not consider arts much. This very important sector \ + of skrellian society is handled by the Talum-Katish, artists, aesthetes, entertainers, \ + chefs, actors, writers, singers. They somewhat compete with the Qerr-Katish's role as \ + representatives of skrellkind, although in a different way. As such, they are often \ + mistaken for Qerr-Katish themselves, which might explain why this caste is generally \ + seen as rarer and less celebrated than the others, while they are in fact frequently on \ + the public scene. The Talum-Katish are the most individualistic members of skrellkind, \ + although once again, they share the Qerr-Katish's taste for a busy social life. Highly \ + cultured, they are the free-thinkers of skrellian society, often at odds with more \ + traditionalist and conservative castes. A heterogeneous lot, it is hard to estimate their \ + global financial capacities, they however tend to reproduce a lot, multiplying their \ + encounters with various partners, which might put a strain on their savings. Their clothing \ + is often an odd mix of Qerr-Katish and Kanin-Katish, as they often wear clothing that is \ + colourful , adorned with embroidery and their headtails sparkling with various brilliant \ + metals. Their skin is generally purple, blue, pink, orange, red or white. Talum-Katish \ + headtails are a middle ground between the shorter headtails of the Malish and the extremely \ + long headtails of the Qerr, and are an important element of Talum self-expression." + economic_power = 1.3 + uid = "heritage_skrell_talum" + +/decl/background_detail/heritage/skrell/caste_raskinta + name = "Raskinta-Katish" + description = "Rarely seen outside the skrellian society, the Raskinta-Katish are however \ + recognised and respected by their entire species, for they are the ones who ensure the \ + safety and stability of skrellian civilisation, both against internal and external threats. \ + The military caste of the Skrell, most end up working for the various city-states, either in \ + the police or as a career soldier, although some of them end up working for private security \ + or as entertainment fighters. They are very conservative, almost reactionary, and deeply \ + committed to their community, caring very little for self-development and personal \ + satisfaction. Their martial training leaves very little time for most intellectual pursuits, \ + although they are trained to be expert tacticians and are only beaten by the Qerr-Katish in \ + terms of organisational skills. While they are wealthier than the Kanin-Katish overall, they \ + are still among the poorer castes of skrellkind and their large families of three or four \ + bondings put a heavy strain on their earnings, only compensated by their strong social \ + cohesion. These are often the hardest to spot among a crowd because they intentionally wear \ + clothing other castes are known for while not working, however they tend to stick to clothing \ + that is easy to move in and are often dark blue. Their skin is generally green, blue, black, \ + brown or yellow. Raskinta headtails are extremely short, and this caste possesses four rather \ + than three headtails, with the one in the back split into two. Uniquely among Raskinta, loss \ + of a headtail is not seen as disfiguring, especially if it was lost in battle, and while many \ + of them choose to procure repair surgeries, some do not." + economic_power = 1.2 + uid = "heritage_skrell_raskinta" + +/decl/background_detail/heritage/skrell/caste_ue + name = "Ue-Katish" + description = "While not technically a ‘Caste’ by itself, the Ue-Katish make up only an incredibly \ + small but growing fraction of the total Skrellian population. Born to unions of Skrell of two \ + different castes or two Ue-Katish, the Ue-Katish typically have no place in the regimented society of \ + the Skrell. Many work in various forms of dangerous, unpleasant, and low-paying labor, and although \ + they are still Skrell and individuals with rights, discrimination still ends up being extremely common. \ + Many Ue-Katish try to imitate other castes in an attempt to pass as a Kanin, a Malish or another caste, \ + or leave for a more tolerant life either inside human territory, nomadically, or as pirates. Ue-Katish \ + are often not discriminated against as much in the colonies that are closer to the human border as a \ + result of ‘cultural bleed’, but they are still viewed with mistrust. Their headtails can vary, often \ + being based roughly on their parentage but in some cases being inconsistent with even that due to \ + genetic mutation. This can greatly limit their ability to pass as another caste in society at times, \ + as having two headtails of different lengths is a dead-giveaway of an Ue-Katish." + economic_power = 0.8 + uid = "heritage_skrell_ue" diff --git a/mods/species/skrell/datum/descriptor.dm b/mods/species/skrell/datum/descriptor.dm new file mode 100644 index 000000000000..c8c293c9e376 --- /dev/null +++ b/mods/species/skrell/datum/descriptor.dm @@ -0,0 +1,40 @@ +/datum/appearance_descriptor/headtail_length + name = "headtail length" + chargen_label = "headtails (caste)" + skip_species_mention = TRUE + standalone_value_descriptors = list( + "very short and split", + "very short", + "short", + "long", + "very long" + ) + chargen_value_descriptors = list( + "very short and split (Raskinta-Katish)" = 1, + "very short (Kanin-Katish)" = 2, + "short (Malish-Katish)" = 3, + "long (Talum-Katish)" = 4, + "very long (Qerr-Katish)" = 5 + ) + + comparative_value_descriptor_equivalent = "as long as yours" + + comparative_value_descriptors_smaller = list( + "slightly shorter than yours", + "shorter than yours", + "much shorter than yours", + "tiny and insignificant next to yours" + ) + + comparative_value_descriptors_larger = list( + "slightly longer than yours", + "longer than yours", + "much longer than yours", + "gigantic compared to yours" + ) + +/datum/appearance_descriptor/headtail_length/get_first_person_message_start() + . = "Your headtails are" + +/datum/appearance_descriptor/headtail_length/get_third_person_message_start(var/decl/pronouns/my_gender) + . = "[my_gender.His] headtails are" diff --git a/mods/species/skrell/datum/emotes.dm b/mods/species/skrell/datum/emotes.dm new file mode 100644 index 000000000000..098bc81c3b3f --- /dev/null +++ b/mods/species/skrell/datum/emotes.dm @@ -0,0 +1,29 @@ +/decl/species/skrell + default_emotes = list( + /decl/emote/audible/warble, + /decl/emote/audible/croak, + /decl/emote/audible/trill, + /decl/emote/audible/hum, + /decl/emote/audible/coo + ) + +/decl/emote/audible/warble + key = "warble" + emote_message_3p = "$USER$ warbles." + emote_sound = 'mods/species/skrell/sound/warble.ogg' + +/decl/emote/audible/croak + key = "croak" + emote_message_3p = "$USER$ croaks!" + +/decl/emote/audible/trill + key = "trill" + emote_message_3p = "$USER$ trills melodically!" + +/decl/emote/audible/hum + key = "hum" + emote_message_3p = "$USER$ hums a melodic, warbly chorus of notes!" + +/decl/emote/audible/coo + key = "coo" + emote_message_3p = "$USER$ lets out an audible, warbly coo." \ No newline at end of file diff --git a/mods/species/skrell/datum/faction.dm b/mods/species/skrell/datum/faction.dm new file mode 100644 index 000000000000..b0a3cc59156a --- /dev/null +++ b/mods/species/skrell/datum/faction.dm @@ -0,0 +1,55 @@ +/decl/background_detail/faction/skrell + name = "Qerr'voal" + description = "A famous name within the Raskinta-Katish community, the Qerr'voal is the SDTF in charge of defending the Qerr'Vallis system,\ + a task the Qerr'Voal has carried out with distinction for 600 years. Despite the relative safety and stability of the system many young Skrell \ + of Qerr'balak and the surrounding colonies try to enter the prestigious organisation in order to gain status and influence with their brethren." + economic_power = 1.4 + uid = "faction_skrell_qerrvoal" + +/decl/background_detail/faction/skrell/qalaoa + name = "Qala'oa" + description = "Relatively recent, this particular group was funded shortly after the first contact between Skrell and humans. Patrolling \ + several worlds at the border between the two species this SDTF has, like the colonies it protects, started to slowly adopt some human customs \ + and views, for better and for worse. Still growing today, some expect it to become the largest SDTF along the skrell-human border within the next thirty years." + economic_power = 1.8 + uid = "faction_skrell_qalaoa" + +/decl/background_detail/faction/skrell/yiitalana + name = "Yii'talana" + description = "An SDTF from the far side of skrell territory, deep into what is, to humanity, uncharted space. Yii'talana is the SDTF for the \ + Ri'Qora system, although they also have a base of operations on the other side of skrell territory, in Harr'Kelm. Heavily funded and well equipped, Yii'Talana has a number of mutual assistance and cooperation agreements with a large number of \ + frontier colony SDTF's, or functions as an intermediary SDTF for systems where a presence has yet to be established. The Skrell of Yii'Talana \ + are some of the more experienced on the far skrellian frontier." + economic_power = 1.7 + uid = "faction_skrell_yiitalana" + +/decl/background_detail/faction/skrell/krrigli + name = "Krri'gli" + description = "Krri'gli is a skrell aerospace manufacturing and research corporation with its headquarters in Qerr'Vallis, despite initially being from the city-state of Tibrivuu in the Go'kal system. \ + It is one of the more well known skrell corporations in human space as a result of its accepetance of corporate personnel exchange and contractor work.\ + Krri'gli is mostly concerned with the design and construction of faster-than-light drives, and is one of the largest providers of them in Skrell space. \ + Krri'gli also builds a number of orbital installations and vessels, which are said to be the safest in skrell space." + additional_langs = list(/decl/language/human/common) + economic_power = 1.2 + subversive_potential = 20 + uid = "faction_skrell_krrigli" + +/decl/background_detail/faction/skrell/qonprri + name = "Qon'prri" + description = "Qon'prri is, officially an independent security services corporation that operates in the Qoa'lo system, providing private \ + security services to a variety of Skrell vessels, traders, organisations and, more recently, certain human corporations. Unofficially, it is rumoured that \ + Qonn'prri is a for-profit offshoot of Qala'oa tasked with information gathering in human space and along the frontier. So far such claims have been \ + unfounded, and Qonn'prri is known for offering a professional, reliable and able service to Humans and Skrell alike." + additional_langs = list(/decl/language/human/common) + economic_power = 1.3 + subversive_potential = 40 + uid = "faction_skrell_qonprri" + +/decl/background_detail/faction/skrell/kalimak + name = "Kali'mak" + description = "Kali'mak is a SDTF that predates the first Ascent encounters. Financed partially by Qerr’Vallis along with numerous neighboring systems, Kali’Mak is \ + one of the most experienced SDTFs in all of the empire, even though their task has been mostly one of deterrence since the Ascent-Skrell ceasefire. \ + The Kali’Mak acts as a “Reserve”, quick strike force when the border patrols of other SDTFs identify Kharmanii threats, and as a result, many of their members enter exchange programs with other SDTFs. \ + They are based on the system of Kale’ta’q*, where the old capital of Gilkrol’Qarr exists." + economic_power = 1.8 + uid = "faction_skrell_kalimak" diff --git a/mods/species/skrell/datum/language.dm b/mods/species/skrell/datum/language.dm new file mode 100644 index 000000000000..252a48595e0b --- /dev/null +++ b/mods/species/skrell/datum/language.dm @@ -0,0 +1,35 @@ +var/global/list/first_name_skrell = file2list("mods/species/skrell/names/first_name_skrell.txt") +var/global/list/last_name_skrell = file2list("mods/species/skrell/names/last_name_skrell.txt") + +/decl/language/skrell + name = "Common Skrellian" + desc = "A melodic and complex language spoken by the Skrell of the Oligarchy. Some of the notes are inaudible to humans." + speech_verb = "warbles" + ask_verb = "trills" + exclaim_verb = "croaks" + colour = "selenian" + key = "k" + flags = LANG_FLAG_WHITELISTED + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","'","!") + shorthand = "SK" + partial_understanding = list( + /decl/language/skrell/casteless = 90 + ) + +/decl/language/skrell/casteless + name = "Ue-Katish Cant" + desc = "A flat and emotionless language spoken mainly by Ue-Katish pirates, laden with slurs and insults." + speech_verb = "croaks" + ask_verb = "trills" + exclaim_verb = "chirps" + colour = "selenian" + key = "h" + flags = LANG_FLAG_WHITELISTED + syllables = list("qra","xa","vilz*","s!zaao","qu!*m","girx","vol","xrim","za-r*oo","qu-xx","qix","qa'taz","zix","tuep","!","*") + shorthand = "UK" + partial_understanding = list( + /decl/language/skrell = 90 + ) + +/decl/language/skrell/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + return capitalize(pick(global.first_name_skrell)) + capitalize(pick(global.last_name_skrell)) \ No newline at end of file diff --git a/mods/species/skrell/datum/location.dm b/mods/species/skrell/datum/location.dm new file mode 100644 index 000000000000..a6f44b19ae51 --- /dev/null +++ b/mods/species/skrell/datum/location.dm @@ -0,0 +1,21 @@ +/decl/background_detail/location/skrellspace + name = "Militarized Skrell Space" + description = "A very different style of living from a more traditional Skrell, those who live and reside in space \ + belong to no particular Qrii'Qerria and instead are governed by the SDTF of the system in which they reside, with all \ + services and installations under the control of the local Raskinta SDTF Commander rather than a Qrii-Skria. Life in \ + these circumstances is often more regimented and disciplined, with a stronger emphasis on community and collaboration, \ + with varying extremes depending on the status, funding and level of military engagements the SDTF is currently in." + capital = "None" + ruling_body = "Your local SDTF" + distance = "80 to 600 light years" + uid = "location_skrell_military" + +/decl/background_detail/location/free + name = "Civilian Skrell Space" + description = "Skrell space is vast and filled with different systems, which may have different levels of skrell \ + presence in them. This presence may amount to small research complexes in the fringe edges of the Skrell border, \ + orbital habitats or large city-states in otherwise less noteworthy systems and planets." + capital = "None" + ruling_body = "None" + distance = "130 to 550 light years" + uid = "location_skrell_civilian" diff --git a/mods/species/skrell/datum/pronouns_skrell.dm b/mods/species/skrell/datum/pronouns_skrell.dm new file mode 100644 index 000000000000..19b3ffc04f55 --- /dev/null +++ b/mods/species/skrell/datum/pronouns_skrell.dm @@ -0,0 +1,18 @@ +/decl/pronouns/skrell + uid = "pronouns_skrell" + name = "Skrell" + bureaucratic_term = "Skrell" + informal_term = "Skrell" + + He = "Vi" + he = "vi" + His = "Vil" + his = "vil" + him = "vil" + has = "has" + is = "is" + does = "does" + self = "vilself" + s = "s" + es = "es" + pluralize_verb = PLURALIZE_ALL diff --git a/mods/species/skrell/datum/religion.dm b/mods/species/skrell/datum/religion.dm new file mode 100644 index 000000000000..1a9f61d02412 --- /dev/null +++ b/mods/species/skrell/datum/religion.dm @@ -0,0 +1,14 @@ +/decl/background_detail/religion/skrell + name = "Xilar Qall" + description = "Xilar Qall is the most common religion in Skrell space, though still vastly outnumbered by agnostics and atheists. It is essentially a codification \ + of many modern Skrellian cultural features blended with local pantheistic beliefs. This was formalized as religion by elements of the Qerr-Katish in some \ + colonies following the Kali’r war, in an attempt to both minimize strife and enforce discipline and progress in Skrellian society." + uid = "religion_skrell_xilar" + +/decl/background_detail/religion/skrell/starspiritual + name = "Vallis Qall" + description = "Also known as ‘Star Spiritualism’ or ‘Skrellian Spiritualism’ by those outside their society, and one of the most popular religions among Kanin and Qerr, \ + the Vallis Qall is one of the oldest religions in their society. Although there are widely different versions of Star Spiritualism all across the Skrellian territory, its \ + core principles are comparable to those of modern stoicism and logical determinism. Skrell who follow the ‘Path of the Stars’ believe that the destiny of all beings is already \ + set-in-stone, and that only through knowledge and self-improvement will one be able to defy and change the path that the Stars have set for them." + uid = "religion_skrell_vallis" diff --git a/mods/species/skrell/datum/skrell_meat.dm b/mods/species/skrell/datum/skrell_meat.dm new file mode 100644 index 000000000000..71140065258c --- /dev/null +++ b/mods/species/skrell/datum/skrell_meat.dm @@ -0,0 +1,3 @@ +/obj/item/food/butchery/meat/fish/octopus/skrell/populate_reagents() + . = ..() + add_to_reagents(/decl/material/liquid/hallucinogenics, 5) diff --git a/mods/species/skrell/datum/species.dm b/mods/species/skrell/datum/species.dm new file mode 100644 index 000000000000..318bfaef9202 --- /dev/null +++ b/mods/species/skrell/datum/species.dm @@ -0,0 +1,151 @@ +/decl/butchery_data/humanoid/skrell + meat_name = "calamari" + meat_type = /obj/item/food/butchery/meat/fish/octopus/skrell + bone_material = /decl/material/solid/organic/bone/cartilage + +/decl/species/skrell + uid = "species_skrell" + name = "Skrell" + name_plural = "Skrell" + + available_bodytypes = list( + /decl/bodytype/skrell + ) + + traits = list(/decl/trait/malus/intolerance/protein = TRAIT_LEVEL_MINOR) + + primitive_form = "Neaera" + + description = "The Skrell are a highly advanced race of amphibians hailing from the system known as Qerr'Vallis. Their society is regimented into \ + five different castes which the Qerr'Katish, or Royal Caste, rules over. Skrell are strict herbivores who are unable to eat large quantities of \ + animal protein without feeling sick or even suffering from food poisoning.

    \ + Skrell value cooperation and have very communal lifestyles, and despite their diplomatic fluency and innate curiosity are very leery of outside \ + interference in their customs and values." + + butchery_data = /decl/butchery_data/humanoid/skrell + + available_pronouns = list( + /decl/pronouns/skrell + ) + hidden_from_codex = FALSE + + preview_outfit = /decl/outfit/job/generic/scientist + + burn_mod = 0.9 + oxy_mod = 1.3 + toxins_mod = 0.8 + shock_vulnerability = 1.3 + warning_low_pressure = WARNING_LOW_PRESSURE * 1.4 + hazard_low_pressure = HAZARD_LOW_PRESSURE * 2 + warning_high_pressure = WARNING_HIGH_PRESSURE / 0.8125 + hazard_high_pressure = HAZARD_HIGH_PRESSURE / 0.84615 + water_soothe_amount = 5 + + body_temperature = null // cold-blooded, implemented the same way nabbers do it + + spawn_flags = SPECIES_CAN_JOIN + + flesh_color = "#8cd7a3" + organs_icon = 'mods/species/skrell/icons/body/organs.dmi' + + blood_types = list( + /decl/blood_type/skrell/yplus, + /decl/blood_type/skrell/yminus, + /decl/blood_type/skrell/zplus, + /decl/blood_type/skrell/zminus, + /decl/blood_type/skrell/yzplus, + /decl/blood_type/skrell/yzminus, + /decl/blood_type/skrell/noplus, + /decl/blood_type/skrell/nominus + ) + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/skrell, + /decl/background_detail/heritage/skrell/caste_malish, + /decl/background_detail/heritage/skrell/caste_kanin, + /decl/background_detail/heritage/skrell/caste_talum, + /decl/background_detail/heritage/skrell/caste_raskinta, + /decl/background_detail/heritage/skrell/caste_ue + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/free, + /decl/background_detail/location/skrellspace, + /decl/background_detail/location/other + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/skrell, + /decl/background_detail/faction/skrell/qalaoa, + /decl/background_detail/faction/skrell/yiitalana, + /decl/background_detail/faction/skrell/krrigli, + /decl/background_detail/faction/skrell/qonprri, + /decl/background_detail/faction/skrell/kalimak, + /decl/background_detail/faction/other + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/skrell, + /decl/background_detail/religion/skrell/starspiritual, + /decl/background_detail/religion/other + ) + ) + + exertion_effect_chance = 10 + exertion_hydration_scale = 1 + exertion_charge_scale = 1 + exertion_reagent_scale = 5 + exertion_reagent_path = /decl/material/liquid/lactate + exertion_emotes_biological = list( + /decl/emote/exertion/biological/breath + ) + exertion_emotes_synthetic = list( + /decl/emote/exertion/synthetic, + /decl/emote/exertion/synthetic/creak + ) + +/decl/species/skrell/fluid_act(var/mob/living/human/H, var/datum/reagents/fluids) + . = ..() + var/water = REAGENT_VOLUME(fluids, /decl/material/liquid/water) + if(water >= 40 && H.hydration < 400) //skrell passively absorb water. + H.hydration += 1 + +/decl/species/skrell/handle_trail(mob/living/human/H, turf/T, old_loc) + var/obj/item/shoes = H.get_equipped_item(slot_shoes_str) + if(!shoes) + var/list/bloodDNA + var/list/blood_data = REAGENT_DATA(H.vessel, blood_reagent) + if(blood_data) + bloodDNA = list(blood_data[DATA_BLOOD_DNA] = blood_data[DATA_BLOOD_TYPE]) + else + bloodDNA = list() + T.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints, bloodDNA, H.dir, 0, H.get_skin_colour() + "25") // Coming (25 is the alpha value) + if(isturf(old_loc)) + var/turf/old_turf = old_loc + old_turf.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints, bloodDNA, 0, H.dir, H.get_skin_colour() + "25") // Going (25 is the alpha value) + +/decl/species/skrell/check_background() + return TRUE + +/decl/material/liquid/mucus/skrell + name = "slime" + uid = "chem_mucus_skrell" + lore_text = "A gooey semi-liquid secreted by skrellian skin." + +// Copied from blood. +// TODO: There's not currently a way to check this, which might be a little annoying for forensics. +// But this is just a stopgap to stop Skrell from literally leaking blood everywhere they go. +/decl/material/liquid/mucus/skrell/get_reagent_color(datum/reagents/holder) + var/list/goo_data = REAGENT_DATA(holder, src) + return goo_data?[DATA_BLOOD_COLOR] || ..() + +/obj/effect/decal/cleanable/blood/tracks/footprints/skrellprints + name = "wet footprints" + desc = "They look like still wet tracks left by skrellian feet." + chemical = /decl/material/liquid/mucus/skrell + +/obj/item/organ/internal/eyes/skrell + name = "amphibian eyes" + desc = "Large black orbs, belonging to some sort of giant frog by looks of it." + icon = 'mods/species/skrell/icons/body/organs.dmi' diff --git a/mods/species/skrell/datum/species_bodytype.dm b/mods/species/skrell/datum/species_bodytype.dm new file mode 100644 index 000000000000..b4f0d5d9ce1d --- /dev/null +++ b/mods/species/skrell/datum/species_bodytype.dm @@ -0,0 +1,43 @@ +/decl/bodytype/skrell + name = "skrellian body" + icon_base = 'mods/species/skrell/icons/body/body.dmi' + bandages_icon = 'icons/mob/bandage.dmi' + health_hud_intensity = 1.75 + associated_gender = PLURAL + eye_darksight_range = 4 + eye_flash_mod = 1.2 + eye_icon = 'mods/species/skrell/icons/body/eyes.dmi' + apply_eye_colour = FALSE + uid = "bodytype_skrell" + appearance_flags = HAS_UNDERWEAR | HAS_SKIN_COLOR + base_color = "#006666" + + default_sprite_accessories = list( + SAC_HAIR = list( + /decl/sprite_accessory/hair/skrell/short = list(SAM_COLOR = "#006666") + ) + ) + appearance_descriptors = list( + /datum/appearance_descriptor/height = 1, + /datum/appearance_descriptor/build = 0.8, + /datum/appearance_descriptor/headtail_length = 1 + ) + + has_organ = list( + BP_HEART = /obj/item/organ/internal/heart, + BP_STOMACH = /obj/item/organ/internal/stomach, + BP_LUNGS = /obj/item/organ/internal/lungs/gills, + BP_LIVER = /obj/item/organ/internal/liver, + BP_KIDNEYS = /obj/item/organ/internal/kidneys, + BP_BRAIN = /obj/item/organ/internal/brain, + BP_EYES = /obj/item/organ/internal/eyes/skrell + ) + + cold_level_1 = 280 //Default 260 - Lower is better + cold_level_2 = 220 //Default 200 + cold_level_3 = 130 //Default 120 + heat_level_1 = 420 //Default 360 - Higher is better + heat_level_2 = 480 //Default 400 + heat_level_3 = 1100 //Default 1000 + cold_discomfort_level = 292 //Higher than perhaps it should be, to avoid big speed reduction at normal room temp + heat_discomfort_level = 368 diff --git a/mods/species/skrell/gear/ammo.dm b/mods/species/skrell/gear/ammo.dm new file mode 100644 index 000000000000..a7a979853e94 --- /dev/null +++ b/mods/species/skrell/gear/ammo.dm @@ -0,0 +1,8 @@ +/obj/item/magnetic_ammo/skrell + name = "ZT-8 cylinder" + desc = "A magazine containing flechettes, the design harkening back to cylinders on revolvers." + icon = 'mods/species/skrell/icons/gear/skrell_rifle.dmi' + icon_state = "skrell_magazine" + projectile_type = /obj/item/projectile/bullet/magnetic/slug + projectile_name = "slug" + basetype = /obj/item/magnetic_ammo/skrell diff --git a/mods/species/skrell/gear/clustertool.dm b/mods/species/skrell/gear/clustertool.dm new file mode 100644 index 000000000000..7a00e5c94a06 --- /dev/null +++ b/mods/species/skrell/gear/clustertool.dm @@ -0,0 +1,27 @@ +/obj/item/clustertool + name = "alien clustertool" + desc = "A bewilderingly complex knot of tool heads." + icon = 'mods/species/skrell/icons/gear/gear_rig.dmi' + icon_state = "clustertool" + w_class = ITEM_SIZE_SMALL + +/obj/item/clustertool/Initialize(ml, material_key) + . = ..() + set_extension(src, /datum/extension/tool/variable, list( + TOOL_WRENCH = TOOL_QUALITY_GOOD, + TOOL_WIRECUTTERS = TOOL_QUALITY_GOOD, + TOOL_CROWBAR = TOOL_QUALITY_GOOD, + TOOL_SCREWDRIVER = TOOL_QUALITY_GOOD + )) + +/obj/item/clustertool/on_update_icon() + . = ..() + icon_state = initial(icon_state) + if(IS_WRENCH(src)) + icon_state = "[icon_state]-wrench" + else if(IS_WIRECUTTER(src)) + icon_state = "[icon_state]-wirecutters" + else if(IS_CROWBAR(src)) + icon_state = "[icon_state]-crowbar" + else if(IS_SCREWDRIVER(src)) + icon_state = "[icon_state]-screwdriver" diff --git a/mods/species/skrell/gear/fabrication_designs.dm b/mods/species/skrell/gear/fabrication_designs.dm new file mode 100644 index 000000000000..410553988ce7 --- /dev/null +++ b/mods/species/skrell/gear/fabrication_designs.dm @@ -0,0 +1,3 @@ +/datum/fabricator_recipe/arms_ammo/hidden/skrellian_rifle_slug + name = "ammunition (skrellian rifle, slug)" + path = /obj/item/magnetic_ammo/skrell \ No newline at end of file diff --git a/mods/species/skrell/gear/gear.dm b/mods/species/skrell/gear/gear.dm new file mode 100644 index 000000000000..deacaaa13867 --- /dev/null +++ b/mods/species/skrell/gear/gear.dm @@ -0,0 +1,140 @@ +/obj/item/tank/skrell + name = "skrellian gas synthesizer" + desc = "A skrellian gas processing plant that continuously synthesises oxygen." + var/charge_cost = 12 + var/refill_gas_type = /decl/material/gas/oxygen + var/gas_regen_amount = 0.05 + var/gas_regen_cap = 50 + +/obj/item/tank/skrell/Initialize() + starting_pressure = list(refill_gas_type = 6 ATM) + . = ..() + + +/obj/item/tank/skrell/Process() + ..() + var/obj/item/rig/holder = loc + if(air_contents.total_moles < gas_regen_cap && istype(holder) && holder.cell && holder.cell.use(charge_cost)) + air_contents.adjust_gas(refill_gas_type, gas_regen_amount) + +// Self-charging power cell. +/obj/item/cell/skrell + name = "skrellian microfusion cell" + desc = "An impossibly tiny fusion power engine of Skrell design." + icon = 'mods/species/skrell/icons/gear/gear.dmi' + icon_state = "skrellcell" + maxcharge = 1500 + w_class = ITEM_SIZE_NORMAL + var/recharge_amount = 12 + +/obj/item/cell/skrell/Initialize() + START_PROCESSING(SSobj, src) + . = ..() + +/obj/item/cell/skrell/Destroy() + STOP_PROCESSING(SSobj, src) + . = ..() + +/obj/item/cell/skrell/Process() + if(charge < maxcharge) + give(recharge_amount) + +//Weaponry and combat-oriented gear +/obj/item/shield/energy/skrell + name = "skrellian combat shield" + desc = "An alien shield capable of stopping most projectile and melee attacks. It can be retracted, expanded, and stored anywhere." + icon = 'mods/species/skrell/icons/gear/e_shield.dmi' + icon_state = "skrellshield" + shield_light_color = "#bf7efc" + +//All skrell weapons need testing, as they were ported directly from bay and not properly configured for nebula YET + +/obj/item/gun/energy/gun/skrell + name = "skrellian handgun" + desc = "A common Skrellian side-arm, the Xuxquu*'Voom-5, or XV-5, is a more traditional energy weapon, tuned to dispense beams in three different wavelengths." + w_class = ITEM_SIZE_NORMAL + icon_state = ICON_STATE_WORLD + slot_flags = SLOT_LOWER_BODY|SLOT_HOLSTER + icon = 'mods/species/skrell/icons/gear/skrell_pistol.dmi' + max_shots = 10 + fire_delay = 6 + one_hand_penalty = 1 + self_recharge = 1 + projectile_type = /obj/item/projectile/beam/stun + + firemodes = list( + list(mode_name="stun", projectile_type=/obj/item/projectile/beam/stun, indicator_color=COLOR_CYAN), + list(mode_name="shock", projectile_type=/obj/item/projectile/beam/stun/shock, indicator_color=COLOR_YELLOW), + list(mode_name="kill", projectile_type=/obj/item/projectile/beam, indicator_color=COLOR_RED), + ) + +/obj/item/gun/magnetic/railgun/skrell + name = "ZT-8 Railgun" + desc = "The Zquiv*Tzuuli-8, or ZT-8, is a railgun rarely seen by anyone other than those within Skrellian SDTF ranks. The rotary magazine houses a cylinder with individual chambers, that press against the barrel when loaded." + icon = 'mods/species/skrell/icons/gear/skrell_rifle.dmi' + icon_state = ICON_STATE_WORLD + item_state = "skrell_rifle" + one_hand_penalty = 3 + fire_delay = 10 + slowdown_held = 1 + slowdown_worn = 1 + removable_components = FALSE + capacitor = /obj/item/stock_parts/capacitor/adv + load_type = /obj/item/magnetic_ammo/skrell + loaded = /obj/item/magnetic_ammo/skrell + projectile_type = /obj/item/projectile/bullet/magnetic/slug + slot_flags = SLOT_BACK + power_cost = 100 + firemodes = list() + +/obj/item/gun/energy/pulse_rifle/skrell + name = "VT-3 Carbine" + icon = 'mods/species/skrell/icons/gear/skrell_carbine.dmi' + icon_state = ICON_STATE_WORLD + item_state = "skrell_carbine" + slot_flags = SLOT_BACK|SLOT_LOWER_BODY + desc = "The Vuu'Xqu*ix T-3, often simply known as the 'VT-3' by non-Skrell. Rarely seen out in the wild by anyone outside of a Skrellian SDTF." + self_recharge = 1 + projectile_type=/obj/item/projectile/beam/pulse/skrell/single + charge_cost=120 + one_hand_penalty = 3 + burst=1 + burst_delay=null + accuracy = 1 + + firemodes = list( + list(mode_name="single", projectile_type=/obj/item/projectile/beam/pulse/skrell/single, charge_cost=120, burst=1, burst_delay=null), + list(mode_name="heavy", projectile_type=/obj/item/projectile/beam/pulse/skrell/heavy, charge_cost=55, burst=2, burst_delay=3), + list(mode_name="light", projectile_type=/obj/item/projectile/beam/pulse/skrell, charge_cost=40, burst=3, burst_delay=2) + ) + +/obj/item/gun/energy/pulse_rifle/skrell/setup_power_supply(loaded_cell_type, accepted_cell_type, power_supply_extension_type, charge_value) + return ..(/obj/item/cell/high, /obj/item/cell, power_supply_extension_type, charge_value) + +/obj/item/projectile/beam/pulse/skrell + icon_state = "pu_laser" + damage = 20 + muzzle_type = /obj/effect/projectile/laser/pulse/skrell/muzzle + tracer_type = /obj/effect/projectile/laser/pulse/skrell/tracer + impact_type = /obj/effect/projectile/laser/pulse/skrell/impact + +/obj/item/projectile/beam/pulse/skrell/heavy + damage = 30 + +/obj/item/projectile/beam/pulse/skrell/single + damage = 50 + +/obj/effect/projectile/laser/pulse/skrell + icon = 'icons/effects/projectiles/tracer.dmi' //God, nebula, why must you separate them in three? + light_color = "#4c00ff" + +/obj/effect/projectile/laser/pulse/skrell/tracer + icon_state = "hcult" //Plan is to make those weapons psionically-fed, and Hcult fits that style. + +/obj/effect/projectile/laser/pulse/skrell/muzzle + icon = 'icons/effects/projectiles/muzzle.dmi' + icon_state = "muzzle_hcult" + +/obj/effect/projectile/laser/pulse/skrell/impact + icon = 'icons/effects/projectiles/impact.dmi' + icon_state = "impact_hcult" \ No newline at end of file diff --git a/mods/species/skrell/gear/gear_ears.dm b/mods/species/skrell/gear/gear_ears.dm new file mode 100644 index 000000000000..474bdf444521 --- /dev/null +++ b/mods/species/skrell/gear/gear_ears.dm @@ -0,0 +1,49 @@ +/obj/item/clothing/ears/skrell + name = "skrell tentacle wear" + desc = "Some stuff worn by skrell to adorn their head tentacles." + +/obj/item/clothing/ears/skrell/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) + . = ..() + if(. && user?.get_species()?.uid != /decl/species/skrell::uid) + return FALSE + +/obj/item/clothing/ears/skrell/band + name = "headtail bands" + desc = "Metallic bands worn by skrell to adorn their head tails." + icon = 'mods/species/skrell/icons/clothing/ears/band.dmi' + drop_sound = 'mods/species/skrell/sound/drop/accessory.ogg' + pickup_sound = 'mods/species/skrell/sound/pickup/accessory.ogg' + +/obj/item/clothing/ears/skrell/band/chains + name = "very short headtail chains" + desc = "A delicate chain worn by skrell to decorate their headtails." + icon = 'mods/species/skrell/icons/clothing/ears/chains_very_short.dmi' + +/obj/item/clothing/ears/skrell/band/chains/short + name = "short headtail chains" + icon = 'mods/species/skrell/icons/clothing/ears/chains_short.dmi' + +/obj/item/clothing/ears/skrell/band/chains/long + name = "long headtail chains" + icon = 'mods/species/skrell/icons/clothing/ears/chains_long.dmi' + +/obj/item/clothing/ears/skrell/band/chains/very_long + name = "very long headtail chains" + icon = 'mods/species/skrell/icons/clothing/ears/chains_very_long.dmi' + +/obj/item/clothing/ears/skrell/cloth + name = "short headtail cloth" + desc = "A cloth shawl worn by skrell draped around their head tails." + icon = 'mods/species/skrell/icons/clothing/ears/cloth_short.dmi' + +/obj/item/clothing/ears/skrell/cloth/long + name = "long headtail cloth" + icon = 'mods/species/skrell/icons/clothing/ears/cloth_long.dmi' + +/decl/loadout_option/ears/skrell + name = "skrell headtail accessory selection" + category = /decl/loadout_category/ears + whitelisted = list(/decl/species/skrell::uid) + path = /obj/item/clothing/ears/skrell + loadout_flags = GEAR_HAS_COLOR_SELECTION | GEAR_HAS_SUBTYPE_SELECTION + uid = "gear_accessory_skrell" diff --git a/mods/species/skrell/gear/gear_head.dm b/mods/species/skrell/gear/gear_head.dm new file mode 100644 index 000000000000..23cd1d2c7193 --- /dev/null +++ b/mods/species/skrell/gear/gear_head.dm @@ -0,0 +1,31 @@ +/obj/item/clothing/head/helmet/space/void/skrell + name = "alien helmet" + icon = 'mods/species/skrell/icons/clothing/head/skrell_helmet_white.dmi' + desc = "Smoothly contoured and polished to a shine. Still looks like a fishbowl." + armor = list( + ARMOR_MELEE = ARMOR_MELEE_KNIVES, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_MAJOR, + ARMOR_ENERGY = ARMOR_ENERGY_STRONG, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + +/obj/item/clothing/head/helmet/space/void/skrell/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) + . = ..() + if(. && user?.get_species()?.uid != /decl/species/skrell::uid) + return FALSE + +/obj/item/clothing/head/helmet/space/void/skrell/black + icon = 'mods/species/skrell/icons/clothing/head/skrell_helmet_black.dmi' + +/obj/item/clothing/head/helmet/skrell + name = "skrellian helmet" + desc = "A helmet built for use by a Skrell. This one appears to be fairly standard and reliable." + icon = 'mods/species/skrell/icons/clothing/head/helmet_skrell.dmi' + +/obj/item/clothing/head/helmet/skrell/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) + . = ..() + if(. && user?.get_species()?.uid != /decl/species/skrell::uid) + return FALSE diff --git a/mods/species/skrell/gear/gear_mask.dm b/mods/species/skrell/gear/gear_mask.dm new file mode 100644 index 000000000000..b11dd2f833b1 --- /dev/null +++ b/mods/species/skrell/gear/gear_mask.dm @@ -0,0 +1,17 @@ +/decl/loadout_option/mask/skrell + name = "skrellian gill cover" + path = /obj/item/clothing/mask/gas/skrell + whitelisted = list(/decl/species/skrell::uid) + uid = "gear_mask_skrell" + +/obj/item/clothing/mask/gas/skrell + name = "skrellian gill cover" + desc = "A comfy technological piece used typically by those suffering from gill-related disorders. It goes around the neck and shoulders with a small water tank on the back, featuring a hookup for oxytanks to keep the water oxygenated." + icon = 'mods/species/skrell/icons/clothing/mask/gill_cover.dmi' + flags_inv = 0 + body_parts_covered = 0 + +/obj/item/clothing/mask/gas/skrell/mob_can_equip(mob/user, slot, disable_warning = FALSE, force = FALSE, ignore_equipped = FALSE) + . = ..() + if(. && user?.get_species()?.uid != /decl/species/skrell::uid) + return FALSE diff --git a/mods/species/skrell/gear/gear_rig.dm b/mods/species/skrell/gear/gear_rig.dm new file mode 100644 index 000000000000..ed16f4d45e79 --- /dev/null +++ b/mods/species/skrell/gear/gear_rig.dm @@ -0,0 +1,243 @@ +//Skrell Baseline Suit +/obj/item/rig/skrell + name = "skrellian recon hardsuit control module" + desc = "A powerful recon hardsuit with integrated power supply and atmosphere. Its impressive design perfectly tailors to the user's body." + icon = 'mods/species/skrell/icons/rigs/standard/rig.dmi' + suit_type = "recon hardsuit" + armor = list( + ARMOR_MELEE = ARMOR_MELEE_RESISTANT, + ARMOR_BULLET = ARMOR_BALLISTIC_RIFLE, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + online_slowdown = 0 + offline_slowdown = 1 + equipment_overlay_icon = null + air_supply = /obj/item/tank/skrell + cell = /obj/item/cell/skrell + chest = /obj/item/clothing/suit/space/rig/skrell + helmet = /obj/item/clothing/head/helmet/space/rig/skrell + boots = /obj/item/clothing/shoes/magboots/rig/skrell + gloves = /obj/item/clothing/gloves/rig/skrell + allowed = list( + /obj/item/gun, + /obj/item/ammo_magazine, + /obj/item/ammo_casing, + /obj/item/flashlight, + /obj/item/tank, + /obj/item/suit_cooling_unit + ) + update_visible_name = TRUE + initial_modules = list( + /obj/item/rig_module/vision, + /obj/item/rig_module/chem_dispenser, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/device/clustertool/skrell, + /obj/item/rig_module/cooling_unit + ) +// req_access = list("ACCESS_SKRELLSCOUT") + +/obj/item/clothing/head/helmet/space/rig/skrell + icon = 'mods/species/skrell/icons/rigs/standard/helmet.dmi' +/obj/item/clothing/suit/space/rig/skrell + icon = 'mods/species/skrell/icons/rigs/standard/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/skrell + icon = 'mods/species/skrell/icons/rigs/standard/boots.dmi' +/obj/item/clothing/gloves/rig/skrell + icon = 'mods/species/skrell/icons/rigs/standard/gloves.dmi' + siemens_coefficient = 0 + +//Skrell Engineering Suit +/obj/item/rig/skrell/eng + name = "skrellian engineering hardsuit" + desc = "A highly sophisticated, cutting-edge engineering hardsuit with an integrated power supply and atmosphere. Its impressive design is resistant yet extremely lightweight, perfectly tailoring itself to the user's body" + icon = 'mods/species/skrell/icons/rigs/engineering/rig.dmi' + suit_type = "engineering hardsuit" + chest = /obj/item/clothing/suit/space/rig/skrell/eng + helmet = /obj/item/clothing/head/helmet/space/rig/skrell/eng + boots = /obj/item/clothing/shoes/magboots/rig/skrell/eng + gloves = /obj/item/clothing/gloves/rig/skrell/eng + initial_modules = list( + /obj/item/rig_module/vision, + /obj/item/rig_module/chem_dispenser/combat, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/device/clustertool/skrell, + /obj/item/rig_module/device/cable_coil/skrell, + /obj/item/rig_module/device/multitool/skrell, + /obj/item/rig_module/device/welder/skrell, + /obj/item/rig_module/device/rcd, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/skrell/eng + icon = 'mods/species/skrell/icons/rigs/engineering/helmet.dmi' +/obj/item/clothing/suit/space/rig/skrell/eng + icon = 'mods/species/skrell/icons/rigs/engineering/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/skrell/eng + icon = 'mods/species/skrell/icons/rigs/engineering/boots.dmi' +/obj/item/clothing/gloves/rig/skrell/eng + icon = 'mods/species/skrell/icons/rigs/engineering/gloves.dmi' + + +//Skrell Medical Suit +/obj/item/rig/skrell/med + name = "skrellian medical hardsuit" + desc = "A highly sophisticated, cutting-edge medical hardsuit with an integrated power supply and atmosphere. Its impressive design is resistant yet extremely lightweight, perfectly tailoring itself to the user's body" + icon = 'mods/species/skrell/icons/rigs/medical/rig.dmi' + initial_modules = list( + /obj/item/rig_module/vision, + /obj/item/rig_module/chem_dispenser/injector, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/device/clustertool/skrell, + /obj/item/rig_module/device/healthscanner, + /obj/item/rig_module/device/defib, + /obj/item/rig_module/vision/medhud, + /obj/item/rig_module/cooling_unit + ) + chest = /obj/item/clothing/suit/space/rig/skrell/med + helmet = /obj/item/clothing/head/helmet/space/rig/skrell/med + boots = /obj/item/clothing/shoes/magboots/rig/skrell/med + gloves = /obj/item/clothing/gloves/rig/skrell/med + +/obj/item/clothing/head/helmet/space/rig/skrell/med + icon = 'mods/species/skrell/icons/rigs/medical/helmet.dmi' +/obj/item/clothing/suit/space/rig/skrell/med + icon = 'mods/species/skrell/icons/rigs/medical/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/skrell/med + icon = 'mods/species/skrell/icons/rigs/medical/boots.dmi' +/obj/item/clothing/gloves/rig/skrell/med + icon = 'mods/species/skrell/icons/rigs/medical/gloves.dmi' + +//Skrell Combat Suit +/obj/item/rig/skrell/sec + name = "skrellian combat hardsuit" + desc = "A highly sophisticated, cutting-edge combat hardsuit with an integrated power supply and atmosphere. Its impressive design is resistant yet extremely lightweight, perfectly tailoring itself to the user's body" + icon = 'mods/species/skrell/icons/rigs/combat/rig.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_AP, + ARMOR_LASER = ARMOR_LASER_RIFLES, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + initial_modules = list( + /obj/item/rig_module/vision, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/device/clustertool/skrell, + /obj/item/rig_module/chem_dispenser/combat, + /obj/item/rig_module/device/flash, + /obj/item/rig_module/cooling_unit + ) + chest = /obj/item/clothing/suit/space/rig/skrell/sec + helmet = /obj/item/clothing/head/helmet/space/rig/skrell/sec + boots = /obj/item/clothing/shoes/magboots/rig/skrell/sec + gloves = /obj/item/clothing/gloves/rig/skrell/sec + +/obj/item/clothing/head/helmet/space/rig/skrell/sec + icon = 'mods/species/skrell/icons/rigs/combat/helmet.dmi' +/obj/item/clothing/suit/space/rig/skrell/sec + icon = 'mods/species/skrell/icons/rigs/combat/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/skrell/sec + icon = 'mods/species/skrell/icons/rigs/combat/boots.dmi' +/obj/item/clothing/gloves/rig/skrell/sec + icon = 'mods/species/skrell/icons/rigs/combat/gloves.dmi' + +//Skrell Command Suit +/obj/item/rig/skrell/cmd + name = "skrellian command hardsuit" + desc = "A highly sophisticated, cutting-edge hardsuit with an integrated power supply and atmosphere. Its impressive design is resistant yet extremely lightweight, perfectly tailoring itself to the user's body. Property of the Qrii'Vuxix" + icon = 'mods/species/skrell/icons/rigs/command/rig.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_AP, + ARMOR_LASER = ARMOR_LASER_RIFLES, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_RESISTANT, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + initial_modules = list( + /obj/item/rig_module/vision, + /obj/item/rig_module/chem_dispenser/injector, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/device/clustertool/skrell, + /obj/item/rig_module/device/flash/advanced, + /obj/item/rig_module/cooling_unit + ) + chest = /obj/item/clothing/suit/space/rig/skrell/cmd + helmet = /obj/item/clothing/head/helmet/space/rig/skrell/cmd + boots = /obj/item/clothing/shoes/magboots/rig/skrell/cmd + gloves = /obj/item/clothing/gloves/rig/skrell/cmd + +/obj/item/clothing/head/helmet/space/rig/skrell/cmd + icon = 'mods/species/skrell/icons/rigs/command/helmet.dmi' +/obj/item/clothing/suit/space/rig/skrell/cmd + icon = 'mods/species/skrell/icons/rigs/command/chest.dmi' +/obj/item/clothing/shoes/magboots/rig/skrell/cmd + icon = 'mods/species/skrell/icons/rigs/command/boots.dmi' +/obj/item/clothing/gloves/rig/skrell/cmd + icon = 'mods/species/skrell/icons/rigs/command/gloves.dmi' + +/obj/item/rig_module/device/clustertool/skrell + name = "skrellian clustertool" + desc = "A complex assembly of self-guiding, modular heads capable of performing most manual tasks." + interface_name = "modular clustertool" + interface_desc = "A complex assembly of self-guiding, modular heads capable of performing most manual tasks." + icon = 'mods/species/skrell/icons/gear/gear_rig.dmi' + icon_state = "clustertool" + engage_string = "Select Mode" + device = /obj/item/clustertool + usable = TRUE + selectable = TRUE + +/obj/item/rig_module/device/clustertool/skrell/get_tool_quality(archetype) + return device?.get_tool_quality(archetype) + +/obj/item/rig_module/device/clustertool/skrell/get_tool_speed(archetype) + return device?.get_tool_speed(archetype) + + +/obj/item/rig_module/device/multitool/skrell + name = "skrellian integrated multitool" + desc = "A limited-sentience integrated multitool capable of interfacing with any number of systems." + interface_name = "multitool" + interface_desc = "A limited-sentience integrated multitool capable of interfacing with any number of systems." + device = /obj/item/multitool/ + icon = 'mods/species/skrell/icons/gear/gear_rig.dmi' + icon_state = "multitool" + usable = FALSE + selectable = TRUE + +/obj/item/rig_module/device/multitool/skrell/get_tool_quality(archetype) + return device?.get_tool_quality(archetype) + +/obj/item/rig_module/device/multitool/skrell/get_tool_speed(archetype) + return device?.get_tool_speed(archetype) + +/obj/item/rig_module/device/cable_coil/skrell + name = "skrellian cable extruder" + desc = "A cable nanofabricator of Skrellian design." + interface_name = "cable fabricator" + interface_desc = "A cable nanofabricator of Skrellian design." + device = /obj/item/stack/cable_coil/fabricator + icon = 'mods/species/skrell/icons/gear/gear_rig.dmi' + icon_state = "cablecoil" + usable = FALSE + selectable = TRUE + +/obj/item/rig_module/device/welder/skrell + name = "skrellian welding arm" + desc = "An electrical cutting torch of Skrellian design." + interface_name = "welding arm" + interface_desc = "An electrical cutting torch of Skrellian design." + icon = 'mods/species/skrell/icons/gear/gear_rig.dmi' + icon_state = "welder1" + engage_string = "Toggle Welder" + device = /obj/item/weldingtool/electric + usable = TRUE + selectable = TRUE \ No newline at end of file diff --git a/mods/species/skrell/gear/gear_suit.dm b/mods/species/skrell/gear/gear_suit.dm new file mode 100644 index 000000000000..adcf99b37f3b --- /dev/null +++ b/mods/species/skrell/gear/gear_suit.dm @@ -0,0 +1,26 @@ +/obj/item/clothing/suit/space/void/skrell + name = "Skrellian voidsuit" + icon = 'mods/species/skrell/icons/clothing/suit/skrell_suit_white.dmi' + desc = "Seems like a wetsuit with reinforced plating seamlessly attached to it. Very chic." + allowed = list( + /obj/item/rcd, + /obj/item/tool, + /obj/item/t_scanner, + /obj/item/ore_satchel, + /obj/item/tank + ) + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SMALL, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + heat_protection = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS|SLOT_TAIL + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + flags_inv = HIDEJUMPSUIT + +/obj/item/clothing/suit/space/void/skrell/black + icon = 'mods/species/skrell/icons/clothing/suit/skrell_suit_black.dmi' \ No newline at end of file diff --git a/mods/species/skrell/gear/gear_under.dm b/mods/species/skrell/gear/gear_under.dm new file mode 100644 index 000000000000..5a194a14ac40 --- /dev/null +++ b/mods/species/skrell/gear/gear_under.dm @@ -0,0 +1,4 @@ +/obj/item/clothing/jumpsuit/skrell + name = "black bodysuit" + desc = "A sleek, skin-tight bodysuit designed to not wick moisture away from the body. The inner stitching appears to contain something written in Skrellian." + icon = 'mods/species/skrell/icons/clothing/under/skrell_uniform.dmi' diff --git a/mods/species/skrell/icons/body/body.dmi b/mods/species/skrell/icons/body/body.dmi new file mode 100644 index 000000000000..91b0e86f3b1b Binary files /dev/null and b/mods/species/skrell/icons/body/body.dmi differ diff --git a/mods/species/skrell/icons/body/eyes.dmi b/mods/species/skrell/icons/body/eyes.dmi new file mode 100644 index 000000000000..fd94ddac1892 Binary files /dev/null and b/mods/species/skrell/icons/body/eyes.dmi differ diff --git a/mods/species/skrell/icons/body/hair.dmi b/mods/species/skrell/icons/body/hair.dmi new file mode 100644 index 000000000000..9dad6dda88a1 Binary files /dev/null and b/mods/species/skrell/icons/body/hair.dmi differ diff --git a/mods/species/skrell/icons/body/organs.dmi b/mods/species/skrell/icons/body/organs.dmi new file mode 100644 index 000000000000..8f3c1f05c169 Binary files /dev/null and b/mods/species/skrell/icons/body/organs.dmi differ diff --git a/mods/species/skrell/icons/body/preview.dmi b/mods/species/skrell/icons/body/preview.dmi new file mode 100644 index 000000000000..5fdb71472840 Binary files /dev/null and b/mods/species/skrell/icons/body/preview.dmi differ diff --git a/mods/species/skrell/icons/clothing/accessories/obj_skrell_badge.dmi b/mods/species/skrell/icons/clothing/accessories/obj_skrell_badge.dmi new file mode 100644 index 000000000000..81be490876a2 Binary files /dev/null and b/mods/species/skrell/icons/clothing/accessories/obj_skrell_badge.dmi differ diff --git a/mods/species/skrell/icons/clothing/accessories/obj_skrell_blank.dmi b/mods/species/skrell/icons/clothing/accessories/obj_skrell_blank.dmi new file mode 100644 index 000000000000..9fb5b87e28db Binary files /dev/null and b/mods/species/skrell/icons/clothing/accessories/obj_skrell_blank.dmi differ diff --git a/mods/species/skrell/icons/clothing/accessories/obj_skrell_vuxix.dmi b/mods/species/skrell/icons/clothing/accessories/obj_skrell_vuxix.dmi new file mode 100644 index 000000000000..40c0fae0be36 Binary files /dev/null and b/mods/species/skrell/icons/clothing/accessories/obj_skrell_vuxix.dmi differ diff --git a/mods/species/skrell/icons/clothing/accessories/obj_skrell_zuumqix.dmi b/mods/species/skrell/icons/clothing/accessories/obj_skrell_zuumqix.dmi new file mode 100644 index 000000000000..47c0f0e7764a Binary files /dev/null and b/mods/species/skrell/icons/clothing/accessories/obj_skrell_zuumqix.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/band.dmi b/mods/species/skrell/icons/clothing/ears/band.dmi new file mode 100644 index 000000000000..485a2070a8f5 Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/band.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/chains_long.dmi b/mods/species/skrell/icons/clothing/ears/chains_long.dmi new file mode 100644 index 000000000000..5e95ca3466b9 Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/chains_long.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/chains_short.dmi b/mods/species/skrell/icons/clothing/ears/chains_short.dmi new file mode 100644 index 000000000000..5e95ca3466b9 Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/chains_short.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/chains_very_long.dmi b/mods/species/skrell/icons/clothing/ears/chains_very_long.dmi new file mode 100644 index 000000000000..3bce49eb1170 Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/chains_very_long.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/chains_very_short.dmi b/mods/species/skrell/icons/clothing/ears/chains_very_short.dmi new file mode 100644 index 000000000000..8358e8bef4eb Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/chains_very_short.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/cloth_long.dmi b/mods/species/skrell/icons/clothing/ears/cloth_long.dmi new file mode 100644 index 000000000000..f5806a43c830 Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/cloth_long.dmi differ diff --git a/mods/species/skrell/icons/clothing/ears/cloth_short.dmi b/mods/species/skrell/icons/clothing/ears/cloth_short.dmi new file mode 100644 index 000000000000..ac7b6e99146d Binary files /dev/null and b/mods/species/skrell/icons/clothing/ears/cloth_short.dmi differ diff --git a/mods/species/skrell/icons/clothing/head/helmet_skrell.dmi b/mods/species/skrell/icons/clothing/head/helmet_skrell.dmi new file mode 100644 index 000000000000..8e1278098a9e Binary files /dev/null and b/mods/species/skrell/icons/clothing/head/helmet_skrell.dmi differ diff --git a/mods/species/skrell/icons/clothing/head/skrell_helmet_black.dmi b/mods/species/skrell/icons/clothing/head/skrell_helmet_black.dmi new file mode 100644 index 000000000000..ac9207ce2d48 Binary files /dev/null and b/mods/species/skrell/icons/clothing/head/skrell_helmet_black.dmi differ diff --git a/mods/species/skrell/icons/clothing/head/skrell_helmet_white.dmi b/mods/species/skrell/icons/clothing/head/skrell_helmet_white.dmi new file mode 100644 index 000000000000..b8894988d14a Binary files /dev/null and b/mods/species/skrell/icons/clothing/head/skrell_helmet_white.dmi differ diff --git a/mods/species/skrell/icons/clothing/mask/gill_cover.dmi b/mods/species/skrell/icons/clothing/mask/gill_cover.dmi new file mode 100644 index 000000000000..b624fcad87ba Binary files /dev/null and b/mods/species/skrell/icons/clothing/mask/gill_cover.dmi differ diff --git a/mods/species/skrell/icons/clothing/suit/skrell_suit_black.dmi b/mods/species/skrell/icons/clothing/suit/skrell_suit_black.dmi new file mode 100644 index 000000000000..611a1a791810 Binary files /dev/null and b/mods/species/skrell/icons/clothing/suit/skrell_suit_black.dmi differ diff --git a/mods/species/skrell/icons/clothing/suit/skrell_suit_white.dmi b/mods/species/skrell/icons/clothing/suit/skrell_suit_white.dmi new file mode 100644 index 000000000000..79b4b8fabaaf Binary files /dev/null and b/mods/species/skrell/icons/clothing/suit/skrell_suit_white.dmi differ diff --git a/mods/species/skrell/icons/clothing/under/skrell_uniform.dmi b/mods/species/skrell/icons/clothing/under/skrell_uniform.dmi new file mode 100644 index 000000000000..3d51d61c7d5c Binary files /dev/null and b/mods/species/skrell/icons/clothing/under/skrell_uniform.dmi differ diff --git a/mods/species/skrell/icons/gear/ammo_unused.dmi b/mods/species/skrell/icons/gear/ammo_unused.dmi new file mode 100644 index 000000000000..876e6718a459 Binary files /dev/null and b/mods/species/skrell/icons/gear/ammo_unused.dmi differ diff --git a/mods/species/skrell/icons/gear/e_shield.dmi b/mods/species/skrell/icons/gear/e_shield.dmi new file mode 100644 index 000000000000..28ca4a0281ec Binary files /dev/null and b/mods/species/skrell/icons/gear/e_shield.dmi differ diff --git a/mods/species/skrell/icons/gear/gear.dmi b/mods/species/skrell/icons/gear/gear.dmi new file mode 100644 index 000000000000..7a541494e5e8 Binary files /dev/null and b/mods/species/skrell/icons/gear/gear.dmi differ diff --git a/mods/species/skrell/icons/gear/gear_rig.dmi b/mods/species/skrell/icons/gear/gear_rig.dmi new file mode 100644 index 000000000000..0b2bb06535f7 Binary files /dev/null and b/mods/species/skrell/icons/gear/gear_rig.dmi differ diff --git a/mods/species/skrell/icons/gear/skrell_carbine.dmi b/mods/species/skrell/icons/gear/skrell_carbine.dmi new file mode 100644 index 000000000000..92db3a1c9949 Binary files /dev/null and b/mods/species/skrell/icons/gear/skrell_carbine.dmi differ diff --git a/mods/species/skrell/icons/gear/skrell_pistol.dmi b/mods/species/skrell/icons/gear/skrell_pistol.dmi new file mode 100644 index 000000000000..8957e64406f1 Binary files /dev/null and b/mods/species/skrell/icons/gear/skrell_pistol.dmi differ diff --git a/mods/species/skrell/icons/gear/skrell_rifle.dmi b/mods/species/skrell/icons/gear/skrell_rifle.dmi new file mode 100644 index 000000000000..79ef0295c1ab Binary files /dev/null and b/mods/species/skrell/icons/gear/skrell_rifle.dmi differ diff --git a/mods/species/skrell/icons/rigs/combat/boots.dmi b/mods/species/skrell/icons/rigs/combat/boots.dmi new file mode 100644 index 000000000000..77513e0c2b00 Binary files /dev/null and b/mods/species/skrell/icons/rigs/combat/boots.dmi differ diff --git a/mods/species/skrell/icons/rigs/combat/chest.dmi b/mods/species/skrell/icons/rigs/combat/chest.dmi new file mode 100644 index 000000000000..a2d85355b285 Binary files /dev/null and b/mods/species/skrell/icons/rigs/combat/chest.dmi differ diff --git a/mods/species/skrell/icons/rigs/combat/gloves.dmi b/mods/species/skrell/icons/rigs/combat/gloves.dmi new file mode 100644 index 000000000000..437ecded9158 Binary files /dev/null and b/mods/species/skrell/icons/rigs/combat/gloves.dmi differ diff --git a/mods/species/skrell/icons/rigs/combat/helmet.dmi b/mods/species/skrell/icons/rigs/combat/helmet.dmi new file mode 100644 index 000000000000..0f729a4720a3 Binary files /dev/null and b/mods/species/skrell/icons/rigs/combat/helmet.dmi differ diff --git a/mods/species/skrell/icons/rigs/combat/rig.dmi b/mods/species/skrell/icons/rigs/combat/rig.dmi new file mode 100644 index 000000000000..be0208bdcd89 Binary files /dev/null and b/mods/species/skrell/icons/rigs/combat/rig.dmi differ diff --git a/mods/species/skrell/icons/rigs/command/boots.dmi b/mods/species/skrell/icons/rigs/command/boots.dmi new file mode 100644 index 000000000000..84d6e2b807d3 Binary files /dev/null and b/mods/species/skrell/icons/rigs/command/boots.dmi differ diff --git a/mods/species/skrell/icons/rigs/command/chest.dmi b/mods/species/skrell/icons/rigs/command/chest.dmi new file mode 100644 index 000000000000..6adb192ff604 Binary files /dev/null and b/mods/species/skrell/icons/rigs/command/chest.dmi differ diff --git a/mods/species/skrell/icons/rigs/command/gloves.dmi b/mods/species/skrell/icons/rigs/command/gloves.dmi new file mode 100644 index 000000000000..5218d2924dc6 Binary files /dev/null and b/mods/species/skrell/icons/rigs/command/gloves.dmi differ diff --git a/mods/species/skrell/icons/rigs/command/helmet.dmi b/mods/species/skrell/icons/rigs/command/helmet.dmi new file mode 100644 index 000000000000..721b6acab215 Binary files /dev/null and b/mods/species/skrell/icons/rigs/command/helmet.dmi differ diff --git a/mods/species/skrell/icons/rigs/command/rig.dmi b/mods/species/skrell/icons/rigs/command/rig.dmi new file mode 100644 index 000000000000..7b4a19548405 Binary files /dev/null and b/mods/species/skrell/icons/rigs/command/rig.dmi differ diff --git a/mods/species/skrell/icons/rigs/engineering/boots.dmi b/mods/species/skrell/icons/rigs/engineering/boots.dmi new file mode 100644 index 000000000000..84fe41c66bfa Binary files /dev/null and b/mods/species/skrell/icons/rigs/engineering/boots.dmi differ diff --git a/mods/species/skrell/icons/rigs/engineering/chest.dmi b/mods/species/skrell/icons/rigs/engineering/chest.dmi new file mode 100644 index 000000000000..82ebbe0f1e21 Binary files /dev/null and b/mods/species/skrell/icons/rigs/engineering/chest.dmi differ diff --git a/mods/species/skrell/icons/rigs/engineering/gloves.dmi b/mods/species/skrell/icons/rigs/engineering/gloves.dmi new file mode 100644 index 000000000000..5218d2924dc6 Binary files /dev/null and b/mods/species/skrell/icons/rigs/engineering/gloves.dmi differ diff --git a/mods/species/skrell/icons/rigs/engineering/helmet.dmi b/mods/species/skrell/icons/rigs/engineering/helmet.dmi new file mode 100644 index 000000000000..5aa7978735e6 Binary files /dev/null and b/mods/species/skrell/icons/rigs/engineering/helmet.dmi differ diff --git a/mods/species/skrell/icons/rigs/engineering/rig.dmi b/mods/species/skrell/icons/rigs/engineering/rig.dmi new file mode 100644 index 000000000000..7093e0031834 Binary files /dev/null and b/mods/species/skrell/icons/rigs/engineering/rig.dmi differ diff --git a/mods/species/skrell/icons/rigs/medical/boots.dmi b/mods/species/skrell/icons/rigs/medical/boots.dmi new file mode 100644 index 000000000000..84d6e2b807d3 Binary files /dev/null and b/mods/species/skrell/icons/rigs/medical/boots.dmi differ diff --git a/mods/species/skrell/icons/rigs/medical/chest.dmi b/mods/species/skrell/icons/rigs/medical/chest.dmi new file mode 100644 index 000000000000..a7ddb53e8065 Binary files /dev/null and b/mods/species/skrell/icons/rigs/medical/chest.dmi differ diff --git a/mods/species/skrell/icons/rigs/medical/gloves.dmi b/mods/species/skrell/icons/rigs/medical/gloves.dmi new file mode 100644 index 000000000000..5218d2924dc6 Binary files /dev/null and b/mods/species/skrell/icons/rigs/medical/gloves.dmi differ diff --git a/mods/species/skrell/icons/rigs/medical/helmet.dmi b/mods/species/skrell/icons/rigs/medical/helmet.dmi new file mode 100644 index 000000000000..1e02ee635a3b Binary files /dev/null and b/mods/species/skrell/icons/rigs/medical/helmet.dmi differ diff --git a/mods/species/skrell/icons/rigs/medical/rig.dmi b/mods/species/skrell/icons/rigs/medical/rig.dmi new file mode 100644 index 000000000000..7a2649390599 Binary files /dev/null and b/mods/species/skrell/icons/rigs/medical/rig.dmi differ diff --git a/mods/species/skrell/icons/rigs/standard/boots.dmi b/mods/species/skrell/icons/rigs/standard/boots.dmi new file mode 100644 index 000000000000..84d6e2b807d3 Binary files /dev/null and b/mods/species/skrell/icons/rigs/standard/boots.dmi differ diff --git a/mods/species/skrell/icons/rigs/standard/chest.dmi b/mods/species/skrell/icons/rigs/standard/chest.dmi new file mode 100644 index 000000000000..94d786de0f24 Binary files /dev/null and b/mods/species/skrell/icons/rigs/standard/chest.dmi differ diff --git a/mods/species/skrell/icons/rigs/standard/gloves.dmi b/mods/species/skrell/icons/rigs/standard/gloves.dmi new file mode 100644 index 000000000000..5218d2924dc6 Binary files /dev/null and b/mods/species/skrell/icons/rigs/standard/gloves.dmi differ diff --git a/mods/species/skrell/icons/rigs/standard/helmet.dmi b/mods/species/skrell/icons/rigs/standard/helmet.dmi new file mode 100644 index 000000000000..4ecf93741ab8 Binary files /dev/null and b/mods/species/skrell/icons/rigs/standard/helmet.dmi differ diff --git a/mods/species/skrell/icons/rigs/standard/rig.dmi b/mods/species/skrell/icons/rigs/standard/rig.dmi new file mode 100644 index 000000000000..6a47cebcb1c6 Binary files /dev/null and b/mods/species/skrell/icons/rigs/standard/rig.dmi differ diff --git a/mods/species/skrell/icons/turf/skrellturf.dmi b/mods/species/skrell/icons/turf/skrellturf.dmi new file mode 100644 index 000000000000..80299783eb1e Binary files /dev/null and b/mods/species/skrell/icons/turf/skrellturf.dmi differ diff --git a/mods/species/skrell/names/first_name_skrell.txt b/mods/species/skrell/names/first_name_skrell.txt new file mode 100644 index 000000000000..122b093765a6 --- /dev/null +++ b/mods/species/skrell/names/first_name_skrell.txt @@ -0,0 +1,600 @@ +Kaexae +Xaaq'xuer +Xaaq'taq +Kae'xer +Xeq'aeq'qerr +Ke'xuer +Xeteq +Kae'xum +Kerrker +Kerrquex'xum +Taeqxuq +Kae'quex'xeu +Keqaeq'xeu +Ke'ter +Xue'xerr +Keqqux'kea +Qerrqux +Kerrxae'qer +Taeqxerr +Kerr'xum +Kaexuer +Qerr'xaeq'xeu +Xue'xum +Xeqteq'qerr +Kerrkeax'qux +Xaaq'qux +Xae'xuer +Xertaq'qux +Xum'xuer +Keq'taq'kea +Keq'quex'xeu +Qerraeq +Xeq'xum +Xeq'qux'xum +Xer'xuq +Keq'teq +Kae'keax +Keqxer +Kae'xerr'xeu +Xaequx +Ke'teq'xum +Xaaqxerr +Xer'keax'kea +Qerrxae'qux +Xae'xer +Qerrteq +Xeq'xuer +Xe'xaeq'xum +Xeteq'qerr +Xaaq'aeq'xeu +Xae'xaeq'qer +Keaeq'xum +Xaaq'teq +Keq'ker +Ke'keax +Kexum'kea +Xeq'xum +Qerr'xaeq'kea +Xexum +Taeq'xer'xe +Qerraeq +Xeq'keax'qux +Xuequx +Kexuq +Teqxaeq'qer +Xeqtaq'qer +Xaexuq +Xueaeq'qux +Taeqxae +Keqxuer +Xum'aeq +Xeqkeax'kea +Kerrxuer +Xaeteq +Keqxaeq'qerr +Xum'quex +Taeq'teq +Xer'xaeq +Teq'taq +Xe'xuq +Kerrxer +Kerr'xaeq'kea +Xeqteq +Xeqxuq'qerr +Kerr'xum'xe +Xe'qux +Xexaeq +Qerrxaeq'qer +Teqqux'kea +Ke'xuer +Xerqux'xeu +Kaexaeq'xeu +Xeq'qux +Xeker +Ke'xae +Kerrxae'qux +Kae'aeq'qerr +Xeq'qux'xeu +Xeqquex'xeu +Kerr'xaeq +Kerr'aeq +Xaaqxae +Xertaq'qux +Xaaq'ker'xum +Kae'xuer'xe +Xue'aeq'xeu +Qerr'xuq +Kequex'qerr +Xer'ter'xe +Qerr'ter'qerr +Xeq'keax'qux +Keq'ker +Ke'qux'qerr +Xumter'qux +Xue'qux'xe +Xaeaeq +Xumxuer'xeu +Kerr'xuq'qux +Keq'xaeq +Xum'xuq'xeu +Kerr'xer +Xae'keax +Kequex +Kae'qux +Keqkeax +Qarrker +Xaaqker'xum +Xue'xaeq'qux +Taeq'xaeq'xe +Xue'xerr +Teqkeax +Xaaq'keax +Ke'xaeq'qer +Kerrxuer +Kaeter'qux +Qarr'xerr +Xerxum'qux +Xumqux +Taeq'teq'xeu +Qerrxuer'qer +Xe'ker +Qerrter'kea +Kaeteq'qux +Teq'xuer'xum +Ke'xae'xeu +Teqxuq'qer +Keq'xaeq +Xaaq'xae +Xum'xer +Xeter +Xaaq'quex'kea +Kexum +Qarrkeax'qer +Keq'xerr +Qarrxerr'qerr +Qarrxerr'qer +Xer'ker +Xaexum'xe +Kaexerr'qux +Xuexum +Xaaq'xer +Qerr'quex +Qerr'ker +Xum'teq'qerr +Kerrxaeq +Xeq'xae +Xue'aeq'xe +Qarr'xuer +Qarr'xerr'qerr +Kaexerr'xum +Kaeter'xum +Xuexuq +Xuekeax'xeu +Xaaq'ker +Keqxer +Teq'xer +Qarrker +Xer'ter +Xae'ter'kea +Ke'quex'xe +Xaeter +Xer'xae +Qarr'xae'xum +Xeqxuq +Keqter'xum +Xeker +Taeqxerr'qer +Keqxer'kea +Xumquex +Xaaq'xuq +Kerrxum +Xexerr +Xerxerr'qerr +Xaaq'xerr +Xum'ker'qer +Xequx +Xer'xae +Kaexerr'xe +Xe'taq +Xeq'xuer'qerr +Xue'taq +Teqxer +Xaaq'xerr'xe +Xer'quex'xum +Xaeaeq +Taeqaeq +Xaeter'qer +Xerkeax +Xuequex'xe +Keqxerr +Taeqxae'qer +Teqqux +Xae'quex'qux +Xe'xum +Xaaqxer +Xeq'aeq'xum +Xuexuq'qerr +Xe'taq'qux +Qarr'xae +Xe'keax'qer +Qerrxum'qerr +Xer'xer +Qarr'quex'qerr +Taeq'xer'qux +Taeqtaq +Ke'aeq'xum +Xueter +Kaeker +Xeter'kea +Qarrter +Qerrxae +Xaaqxum'xeu +Xum'xuer +Xe'xae +Qarrter'qer +Kequx +Kerr'aeq'kea +Teq'taq'kea +Xexum'qerr +Qerr'quex'xeu +Xeker'qux +Kerr'quex'qerr +Xum'ker'qer +Keqxuq'xeu +Keqxuq'xeu +Xer'teq'xum +Kaeker'qerr +Xumtaq +Xexuer +Xueter'xum +Kaeteq +Ke'teq +Qerrxuq +Teq'xum'qerr +Xaaq'xae +Keter'xum +Xeqqux +Xae'taq +Qerrtaq'qux +Keq'ter +Xaequex'xum +Kaeter +Xaaqtaq +Kae'xer'qer +Kaequx +Kae'xum +Taeqaeq'qux +Kexaeq'kea +Xer'xae'qer +Xae'ker +Xue'xuer +Xeq'taq'xe +Kaexae'qux +Teq'xae'xe +Teq'xuer +Qerrqux'xeu +Xuexaeq +Kerr'xuq'kea +Xerquex'kea +Keq'ker +Kaexum +Kerrquex +Kexer +Keq'quex'qerr +Xae'xae +Qerr'ker +Kexerr +Xaaqquex +Keq'quex'xum +Xerter'qux +Xuexaeq'xe +Xae'xuq'kea +Kae'xuer'kea +Xer'xum'kea +Xer'quex'kea +Kerrxuq'qux +Qerrxuer +Xeq'xerr'qerr +Qarr'xuq'qux +Xaaq'xuq +Xerxaeq'qux +Xertaq +Kerr'teq'xeu +Xer'aeq'kea +Xe'ter'qerr +Teq'xae +Kerrxerr +Taeqxaeq +Xueker +Keqxae'qerr +Taeqkeax +Kexaeq'xum +Xuekeax'xe +Xumxum +Xeq'ter'xeu +Taeqquex +Xer'xer +Keqxae'xeu +Kaexum +Keq'xaeq +Qerr'quex'xum +Kaexuq'qux +Xaequx'xe +Kae'xum +Keqkeax +Kexuer +Xeter +Xexuq'xeu +Xe'aeq +Xum'keax'xe +Xer'ker'xum +Xerxuq'qer +Xaekeax'xe +Kaequex'xe +Keqxer +Xeker'qer +Teqker'qerr +Keqxer +Teq'xer +Xaaq'xum +Qerrter +Ke'xuer +Kae'xerr'xeu +Qarrteq'kea +Teq'aeq'qux +Teq'xum'qux +Xae'xuq +Xaekeax +Qerr'teq +Kerrteq'qer +Keqxerr +Qarr'xerr'xum +Kekeax +Xae'xae'kea +Xumteq +Xuequx'qer +Qarr'xer +Taeq'xuq +Ke'xum +Kae'xerr +Xumxum'qerr +Keqteq'qer +Teqker'qerr +Qarr'keax +Xeqxer +Qarrxuq'xe +Keqkeax +Xaaq'ter'kea +Xaaq'aeq +Kerr'keax +Keqxuer +Qerr'xerr'kea +Qarr'teq'qerr +Kerr'teq'qerr +Qarr'taq'qer +Qarrxuer'xeu +Kae'ter +Keaeq'xum +Teqker'xum +Xaaq'aeq'qux +Keq'qux'qer +Xae'xuq'kea +Ke'xuq'qux +Qerr'qux +Xaaq'qux'qer +Xue'keax +Xaaqxerr'kea +Taeqteq'xe +Xuetaq +Xaaqxuq'qerr +Qerrxae'xe +Xeqxuer +Xeqxaeq'xum +Xue'ker'qer +Kekeax'xeu +Qarr'xae'qux +Xae'ker'qux +Qarr'xum'xum +Xum'xaeq'xeu +Qerrxer'qerr +Xaeaeq'qer +Xaaq'quex'qerr +Qerr'aeq +Xum'taq +Kerr'xum'xeu +Xaeaeq'kea +Taeqxerr'kea +Taeq'qux'xum +Xaaq'xae +Qerr'quex +Qarrker +Qarr'qux'xeu +Xaaqaeq'qux +Xuetaq +Xaexum +Xae'xaeq +Xaaq'taq'xe +Kerrxaeq'xe +Kae'xer'kea +Kerr'xae'qer +Keqxum'qer +Qarr'taq'xe +Taeq'quex'qer +Xum'xuer +Xer'xuq'qerr +Xeqteq'xum +Xae'xaeq +Xaekeax'qer +Xeq'xum +Qarr'ter'qer +Qarr'xerr +Kae'xae'xum +Taeq'xuq +Kae'xuq'kea +Xue'xum'qux +Xae'xerr +Taeq'xaeq +Xaexuq +Xaequx +Keqter +Kae'xuer +Xaaqaeq +Kae'taq'xeu +Keqter'kea +Taeqaeq +Xae'qux +Qerr'qux +Qarr'xuq'kea +Xeq'xuer +Keqqux +Xaaq'taq'xum +Kae'xerr +Xue'xae'kea +Qarraeq +Taeq'xum +Qerrxer +Teq'xum +Xaaq'ker'xeu +Kerr'xaeq +Xaaq'xerr'xeu +Xaaqxuq'xeu +Taeqter'qer +Teq'xuer +Xaaqker +Qerr'xaeq'qux +Qerr'quex'qux +Xaaqxerr +Keqtaq'xeu +Kerrxuq +Taeqxuq'xe +Taeq'xuq +Xexuq'qerr +Taeq'xae'qux +Kerr'aeq'qer +Teqtaq +Qerr'taq'xeu +Xeqxaeq'kea +Keteq +Qarr'quex'xeu +Kae'xer +Xaaqxuer +Xum'xum +Taeqquex'xeu +Xue'teq +Xumxuq +Teqxer +Xaeteq'xum +Kaexum'qerr +Xaaq'qux +Xe'xum +Qerr'xaeq +Keqxaeq'xe +Xum'xerr +Xuexaeq'xum +Xaaq'xum'kea +Xumteq +Teq'keax'xeu +Xaequex +Ke'ker'kea +Xeq'xuq +Xaaq'quex'xeu +Teq'teq'qux +Qarr'keax +Xequex +Xeqqux +Xerxerr'xum +Kae'teq +Xaaq'qux'xum +Xuetaq'qer +Xaexerr +Xexuer +Xaaq'xerr'qer +Xexae'kea +Xaexuq'qer +Xe'ker +Keq'quex'kea +Qarrqux'qux +Xaaqtaq'kea +Teqxae +Teq'xuq +Ke'aeq +Xae'aeq +Kerr'ter +Xue'xuq'qer +Ke'xaeq +Taeq'xuer'xeu +Xeq'xae +Qerrkeax'kea +Xae'xuq +Teq'keax +Qerr'teq'qer +Kaexuq'xe +Qarrxaeq'xeu +Qerrtaq +Xe'ker'xum +Kaexuer +Teqxuer'xe +Xumxuer'kea +Kerr'xuer +Xer'teq'xum +Xumteq'qerr +Ke'quex +Taeq'aeq'qerr +Xue'ter'xe +Xeq'xae'xeu +Xer'xum +Qarr'xae +Qerrker'qux +Taeq'keax'xeu +Xum'quex'xeu +Kae'ter +Xe'quex'xe +Keqxum +Kerr'quex'qer +Xaaqxae'qer +Xaaqteq'qer +Keqqux +Teq'aeq +Keteq +Xumxae'xum +Xumxum +Qarrxaeq'kea +Keker +Xeq'aeq'qer +Teqter +Qarrxaeq'kea +Teq'quex +Keqxum +Teq'xuer +Xumter'kea +Qarr'xae +Xae'xuer'xeu +Xaaqxaeq'kea +Qerr'xuq'xeu +Xum'xae'qux +Xumxaeq +Xumxum +Kexum'xe +Kae'aeq +Xer'teq +Qarrxerr'xum +Taeq'taq +Taeq'taq'qux +Kaexum'xeu +Xumtaq +Xae'xer +Kerr'ker +Qarr'xum'qer +Qerr'xuer'qux +Xue'qux'xe +Qerr'qux'xum +Teqquex'qerr +Taeqquex +Qarrxerr +Ketaq +Xekeax +Kequex +Xetaq +Ke'xae'xe +Teq'quex'qux diff --git a/mods/species/skrell/names/last_name_skrell.txt b/mods/species/skrell/names/last_name_skrell.txt new file mode 100644 index 000000000000..5f67fbc5365a --- /dev/null +++ b/mods/species/skrell/names/last_name_skrell.txt @@ -0,0 +1,600 @@ +Xer'taq'qer +Xaaq'ter'qux +Xaaq'xuer +Xerxuer'xum +Qarrqux +Xueaeq'qux +Xe'aeq +Keqter +Xaexer +Kaeteq +Ke'aeq'xeu +Kerrxum +Teqxuq'xeu +Xexaeq +Qerr'xerr'xum +Xaeker'qux +Kexer'kea +Ke'aeq +Keqxae'kea +Qarraeq'xe +Xuekeax +Keq'quex +Kae'quex'qux +Qerr'taq'xum +Taeq'taq'xum +Kae'xaeq'xe +Xaaq'teq'qux +Teqker +Qerrxum'xeu +Xeq'xaeq'xe +Kae'keax +Xue'xae +Taeq'taq +Keter'xeu +Xumker'xe +Teqteq +Xexuer +Qerrxerr +Kaequex'qerr +Kaequx'xe +Xum'xaeq +Xe'taq +Xuexer +Xe'qux'xeu +Xe'xerr'kea +Qerr'xum +Xaaqtaq +Xuexum'xum +Qerrxer +Xaexuq +Xeq'aeq +Xaaq'xaeq +Xerqux +Xeq'xuq'xeu +Kaexum +Taeqteq'xeu +Kerrter'qux +Xeq'teq +Teqxae'xe +Xae'ker'kea +Keqxuq +Xumxae'kea +Xeq'xerr'kea +Kae'quex +Kae'ter +Teqter'xe +Xeq'xerr'xeu +Xerxum'qux +Xe'qux +Qarr'aeq +Xue'xum'xe +Xaaq'ter'qux +Teq'xer +Kerrtaq +Qerr'aeq +Xaaq'aeq +Xaaqxuer +Qerr'quex +Kaeker +Xae'taq +Teq'xaeq +Xexuq +Keqqux +Kaeker +Xeqxum +Xae'taq'qerr +Kexerr +Ke'xerr'qux +Xeraeq'xum +Kae'qux'qux +Xerkeax'xum +Qarrxum +Kaexuer +Qerrquex +Kerr'xer +Xeq'taq +Xeqker +Kerrquex'xum +Xeteq +Qarrxuer +Xaaqqux'qerr +Xae'xer +Xae'xae +Taeqxuer'qerr +Xumqux'qux +Xuexerr'qerr +Ke'xae'xum +Xerxuer +Xeqtaq +Xeqquex +Xuekeax +Keq'xuq'qerr +Xaeter +Xumxerr +Xeqxaeq'xe +Xae'ker +Qerr'ker +Xeq'aeq +Kae'keax +Qerrkeax +Xeqxerr +Keqxaeq +Xae'xuq +Kerrkeax'qer +Qarrxum'xum +Teq'xum'xeu +Kerrxer +Xe'xum +Kexae'xeu +Xerxerr'xe +Xum'ter +Xe'keax +Qarr'xer'kea +Xaaq'aeq +Xaaqker'qerr +Ke'ker +Qerr'xum +Qerr'xae'xe +Qarr'ter'xum +Kaexerr +Qarrtaq'qux +Xumxaeq +Xaeaeq'xe +Qarr'xae'qux +Xer'xum'qerr +Kae'xuq +Xaaq'qux'kea +Teqtaq +Kekeax +Xe'keax'qerr +Kerr'keax'qerr +Xeqkeax +Xer'xaeq +Xerter'kea +Xum'xuq'xe +Teqaeq +Ke'teq'qux +Xer'xuq'kea +Keq'xum'xeu +Xerxuer'xeu +Xum'keax'xum +Xaaq'ter +Xuetaq +Taeq'xuer'qux +Xuexum'xe +Xeq'quex'kea +Xum'xer +Xeqaeq +Qerr'ker +Xumxum +Xeqxum +Xae'taq'qerr +Taeq'ker +Xue'xae'xe +Xer'taq'xe +Xum'xaeq +Kaexuq'xum +Kaexuq'qux +Ke'xum'xum +Qerr'xerr'xum +Ke'xuq'qux +Taeq'xaeq +Xumtaq +Xetaq +Kaexerr'xum +Kequx +Xuexerr'xeu +Xeaeq +Keq'qux'kea +Xeq'xaeq +Xuexum +Ke'xerr'xe +Xe'xum +Kerr'xaeq +Xeqkeax'qux +Kaeteq +Xer'quex +Teqaeq'qerr +Xaexerr +Xaeter +Xumxuer'qer +Teqxae +Taeqtaq'qerr +Kerr'qux +Xuequex +Xaaqtaq'kea +Teq'keax +Ke'xuer'kea +Xum'quex'xeu +Xaexer'kea +Kerr'quex'xum +Qarrxaeq'xum +Kerr'xaeq'xeu +Xaaq'xerr'xum +Xeqxaeq +Xaaqxae'xeu +Qerrxae +Xae'xer +Xexer +Qarrter'xe +Xaaq'taq'xum +Taeq'aeq +Teq'xer +Xaexae'xum +Ke'aeq +Teqxuer +Qerrxuq +Xaaq'ker +Xeq'quex +Kerr'qux +Xekeax'qerr +Kerr'qux'xum +Ke'teq +Qarrxae'xum +Qerr'ter'qux +Qerr'keax +Taeqxuer'kea +Qerr'xae +Keqker'xeu +Xueter +Xae'teq'kea +Xumkeax'qux +Keq'keax +Qarr'xerr'qux +Xuekeax'qerr +Taeq'xuq'xe +Keq'aeq'xe +Xue'xuer'qux +Qerr'quex'qux +Xaexerr'qux +Qerrxaeq +Qerr'xerr +Qarr'xuer +Qerrxae +Taeq'xaeq'xeu +Kerr'ter +Kerrker'qux +Kaexae'xum +Kerrtaq'qerr +Xae'aeq'qer +Xer'xerr +Kae'xuer'qux +Qerr'xer'qerr +Keq'taq'qer +Taeqxer'xum +Xaaq'xuq +Xue'qux +Taeq'xaeq +Xe'teq'xe +Teq'xuq +Taeq'xum'qux +Xaaqter'xum +Taeq'taq +Xaaqxerr'qer +Xuetaq'qerr +Xum'xae +Qerrxer'xe +Qerr'xaeq'kea +Xeq'ker +Xeqteq'qerr +Kerr'aeq'qer +Xum'teq'qerr +Xuexuq'kea +Xue'taq +Xum'qux'xe +Kerrker +Xue'ter'xeu +Xaexaeq +Xaexerr'kea +Teqtaq'kea +Xuexuer'xe +Xue'xae'xeu +Taeq'quex +Keqteq +Kae'aeq'xum +Teqaeq'qerr +Xaaqxum +Qarr'teq'qux +Kaexer +Xue'xum +Qerrtaq'qer +Taeq'teq'qux +Xueter +Xum'ker'xe +Xue'keax +Xum'quex'qerr +Kaeaeq'qerr +Xeqxae +Keqxuer'xeu +Xeqxum +Teqxuq +Kaeker +Xaaq'taq +Keqquex'kea +Xe'ker +Xeq'aeq'kea +Xue'qux +Xerxuq +Taeq'quex +Kequx'qux +Xueker'qux +Teqxum'qer +Kerrxuq'qer +Xerker +Xue'xuer +Xue'qux +Taeq'xuq +Keq'qux'xum +Qarr'quex'xe +Kae'xer'kea +Qarr'xum'xeu +Keqker'xum +Ketaq +Xue'teq +Xuexerr +Xeqker +Xe'xum'xeu +Xeq'ter'qerr +Taeqxuq +Kaeter +Keq'taq +Xum'xum +Xumxuer'xum +Teqter'qerr +Keq'qux'xe +Keq'xer'qer +Xueaeq'xeu +Taeqxuer'kea +Keqxae'xeu +Kae'taq +Xerkeax +Xeqker +Kerrxer +Taeq'xerr'xe +Qerr'xerr'qerr +Xe'ker'xe +Kae'qux'qerr +Kaequex +Xaaq'teq'qer +Xumxerr +Xe'quex +Qerr'xum'qux +Qerrxae +Qerrquex +Kae'xae'qerr +Qarrquex +Kerrxae +Xaaq'taq'xeu +Qarr'xae'qux +Xeqker +Xaaqxuq'qer +Xaaqter +Xerxerr +Xue'taq'qer +Qarrxer'qerr +Xae'ter'xum +Kerrter'qerr +Kerrter'kea +Xae'aeq +Xe'xer +Teq'keax'xeu +Kexum'xe +Xueteq +Kae'keax +Xaaq'keax +Xaaq'quex'qux +Taeqqux +Taeq'xum +Xerxuer +Qerrxer +Xaexuer +Teqter +Qarr'xer +Qarrxaeq'xum +Ke'teq +Teq'xae +Kaexerr +Qarr'teq +Xer'ker +Xaexuer'qux +Xeq'qux +Taeqxer +Taeqxaeq +Xumxuer +Taeqxuer'qerr +Kae'xuer +Qerrter +Taeq'aeq'kea +Taeq'xer'xum +Kerrter +Xum'xuer +Xue'ker'qux +Xaaqter'qux +Xue'ter'xe +Xueteq +Xaaq'xae +Xaexerr'qerr +Ke'aeq'qerr +Xaaq'xuq'xeu +Xuekeax +Xumteq +Xexuq +Taeq'ker'xeu +Xaaqaeq +Qarrxum +Xerxuq'xum +Kaexerr +Xeq'ter'xeu +Keqaeq +Xeqxuer'xum +Teqkeax'xeu +Kae'aeq'kea +Ke'xerr +Ke'xuq +Kae'quex +Xeqxae +Kaeter +Xeqxer +Kae'xuer +Taeqtaq'xum +Teq'qux'xeu +Xaequex'xum +Qarrquex +Xaaq'qux +Keqquex +Qerrker'qerr +Xexae'xe +Xerxae +Xaaqker'kea +Kexer'qerr +Xaeaeq +Xaaqqux +Qarr'xer'qer +Keq'xuq +Kae'keax +Qerr'teq'qer +Kae'xaeq'qer +Xaexer +Kerrxer'xeu +Kaekeax +Xaaq'xaeq'xeu +Xae'xae +Qarr'keax +Teqqux'qerr +Xeq'ter'qerr +Taeq'ker +Qerrteq'xeu +Keqqux'xeu +Xaaqteq'qerr +Teqteq'xe +Xaaqter +Xaaqkeax +Xeqqux +Xaaq'xerr +Teq'ker'qerr +Xer'taq'qerr +Qarrxum'qux +Xum'taq'qux +Qarr'xer'xeu +Xerxerr'qux +Kerr'teq +Xum'taq'kea +Xaequex +Kaeaeq'xe +Xe'xaeq'xum +Xuexuer'qer +Kerrxuq +Kerrxuer'qerr +Kaeteq +Xaaqxuer +Xeq'xum'qerr +Xumxer +Xe'ter'xeu +Xueaeq +Keq'keax +Xueter +Xaexaeq +Keqxaeq +Ke'aeq +Xumxum'qerr +Xumxae'xum +Xaaqxuer +Ke'ker +Ke'xer +Xuekeax'qerr +Keq'teq +Kerr'ter'qux +Xe'xerr +Qerrxae +Ke'quex'xeu +Keqxuq +Kerrxuer +Keq'xae +Qarr'xuq +Xumxuq +Qarr'teq'qer +Xe'xae'xeu +Xuexum +Xequx +Xaaq'teq'xum +Xue'xuq +Kae'quex'qer +Qarrxer'qerr +Xumaeq'xeu +Qarrkeax +Kae'xer'qux +Xeq'qux'qer +Xueker'qux +Teqquex +Xae'xaeq'xum +Taeqkeax +Xaaq'teq'qux +Keqxerr'xe +Xue'ter'xe +Xe'xaeq +Qerrker +Xaexum'qer +Keqteq'xum +Taeq'xae'xum +Kaexuer'qux +Xe'ter +Xae'taq'qux +Qarr'aeq +Xae'xum +Qarrxum'xum +Keqxer'xum +Qarr'xerr +Teqxae +Ke'xae'xe +Teqkeax'qux +Xe'taq +Xaetaq +Keq'teq'kea +Keqxaeq +Xue'xuq +Qarr'xerr'qer +Xequex +Keqxum +Keqtaq +Qarr'ker'xum +Kerr'xer'qer +Kerrxae'xum +Xum'xae +Kaequex'qux +Xuequx'xe +Xumquex'qer +Taeqker +Xae'quex +Xer'teq'xe +Xerxerr +Ke'xuq'qer +Taeqxerr'kea +Xaaq'xaeq'kea +Keq'teq +Xue'aeq'xeu +Xaaqxer'xeu +Ke'ker'qerr +Xue'quex +Taeqtaq +Teqter +Kequex'xe +Xuexuer'qerr +Xeqxum +Xue'taq +Xer'xuq'qerr +Xeqxaeq'xe +Qerr'xaeq +Xeqxae'qer +Taeqtaq'kea +Xer'teq +Qerr'xaeq'xum +Xaaq'xae +Xum'xuq +Xaaqxaeq +Xaexum +Xaaqxum'xe +Xertaq +Xuexuq'qerr +Xaaq'xae'kea +Qerr'teq'qer diff --git a/mods/species/skrell/sound/accessory.ogg b/mods/species/skrell/sound/accessory.ogg new file mode 100644 index 000000000000..92ff70346ddd Binary files /dev/null and b/mods/species/skrell/sound/accessory.ogg differ diff --git a/mods/species/skrell/sound/drop/accessory.ogg b/mods/species/skrell/sound/drop/accessory.ogg new file mode 100644 index 000000000000..92ff70346ddd Binary files /dev/null and b/mods/species/skrell/sound/drop/accessory.ogg differ diff --git a/mods/species/skrell/sound/pickup/accessory.ogg b/mods/species/skrell/sound/pickup/accessory.ogg new file mode 100644 index 000000000000..b532e2d4026f Binary files /dev/null and b/mods/species/skrell/sound/pickup/accessory.ogg differ diff --git a/mods/species/skrell/sound/warble.ogg b/mods/species/skrell/sound/warble.ogg new file mode 100644 index 000000000000..420ae974c838 Binary files /dev/null and b/mods/species/skrell/sound/warble.ogg differ diff --git a/mods/species/skrell/turfs/flooring.dm b/mods/species/skrell/turfs/flooring.dm new file mode 100644 index 000000000000..0ce56ba08591 --- /dev/null +++ b/mods/species/skrell/turfs/flooring.dm @@ -0,0 +1,51 @@ +/turf/floor/tiled/skrell + icon = 'mods/species/skrell/icons/turf/skrellturf.dmi' + icon_state = "skrellblack" + _flooring = /decl/flooring/reinforced/shuttle/skrell + +/turf/floor/tiled/skrell/white + icon_state = "skrellwhite" + _flooring = /decl/flooring/reinforced/shuttle/skrell/white + +/turf/floor/tiled/skrell/red + icon_state = "skrellred" + _flooring = /decl/flooring/reinforced/shuttle/skrell/red + +/turf/floor/tiled/skrell/blue + icon_state = "skrellblue" + _flooring = /decl/flooring/reinforced/shuttle/skrell/blue + +/turf/floor/tiled/skrell/orange + icon_state = "skrellorange" + _flooring = /decl/flooring/reinforced/shuttle/skrell/orange + +/turf/floor/tiled/skrell/green + icon_state = "skrellgreen" + _flooring = /decl/flooring/reinforced/shuttle/skrell/green + +///////////////////////////////////////////////////////////////////////// + +/decl/flooring/reinforced/shuttle/skrell + icon = 'mods/species/skrell/icons/turf/skrellturf.dmi' + icon_base = "skrellblack" + uid = "floor_skrell" + +/decl/flooring/reinforced/shuttle/skrell/white + icon_base = "skrellwhite" + uid = "floor_skrell_white" + +/decl/flooring/reinforced/shuttle/skrell/red + icon_base = "skrellred" + uid = "floor_skrell_red" + +/decl/flooring/reinforced/shuttle/skrell/blue + icon_base = "skrellblue" + uid = "floor_skrell_blue" + +/decl/flooring/reinforced/shuttle/skrell/orange + icon_base = "skrellorange" + uid = "floor_skrell_orange" + +/decl/flooring/reinforced/shuttle/skrell/green + icon_base = "skrellgreen" + uid = "floor_skrell_green" diff --git a/mods/species/tajaran/_tajaran.dm b/mods/species/tajaran/_tajaran.dm new file mode 100644 index 000000000000..2b07b2c74b82 --- /dev/null +++ b/mods/species/tajaran/_tajaran.dm @@ -0,0 +1,23 @@ +#define LANGUAGE_TAJARAN "Siik'maas" +#define BODYTYPE_TAJARAN "felinoid body" + +/decl/modpack/tajaran + name = "Tajaran Species" + tabloid_headlines = list( + "TAJARANS: CUTE AND CUDDLY, OR INFILTRATING THE GOVERNMENT? FIND OUT MORE INSIDE" + ) + +/decl/modpack/tajaran/pre_initialize() + ..() + SSmodpacks.default_submap_whitelisted_species |= /decl/species/tajaran::uid + +/mob/living/human/tajaran/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + . = ..(species_uid = /decl/species/tajaran::uid) + +/obj/item + var/_tajaran_onmob_icon + +/obj/item/setup_sprite_sheets() + . = ..() + if(_tajaran_onmob_icon) + LAZYSET(sprite_sheets, BODYTYPE_TAJARAN, _tajaran_onmob_icon) diff --git a/mods/species/tajaran/_tajaran.dme b/mods/species/tajaran/_tajaran.dme new file mode 100644 index 000000000000..a1ebf288ceca --- /dev/null +++ b/mods/species/tajaran/_tajaran.dme @@ -0,0 +1,14 @@ +#ifndef MODPACK_SPECIES_TAJARAN +#define MODPACK_SPECIES_TAJARAN +// BEGIN_INCLUDE +#include "_tajaran.dm" +#include "datum\accessory.dm" +#include "datum\blood.dm" +#include "datum\culture.dm" +#include "datum\emotes.dm" +#include "datum\language.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "machinery\suit_cycler.dm" +// END_INCLUDE +#endif diff --git a/mods/species/tajaran/datum/accessory.dm b/mods/species/tajaran/datum/accessory.dm new file mode 100644 index 000000000000..d71003eeaa0e --- /dev/null +++ b/mods/species/tajaran/datum/accessory.dm @@ -0,0 +1,347 @@ +//Hairstyles +/decl/sprite_accessory/hair/taj + name = "Tajaran Rattail" + icon_state = "hair_rattail_s_noear" + species_allowed = list(/decl/species/tajaran::uid) + icon = 'mods/species/tajaran/icons/hair.dmi' + color_blend = ICON_MULTIPLY + uid = "acc_hair_taj_rattail" + +/decl/sprite_accessory/hair/taj/get_hidden_substitute() + if(accessory_flags & HAIR_VERY_SHORT) + return src + return GET_DECL(/decl/sprite_accessory/hair/bald) + + +/decl/sprite_accessory/hair/taj/clean + name = "Tajaran Clean" + icon_state = "hair_clean_s_noear" + uid = "acc_hair_taj_clean" + +/decl/sprite_accessory/hair/taj/bangs + name = "Tajara Bangs" + icon_state = "hair_bangs_s_noear" + uid = "acc_hair_taj_bangs" + +/decl/sprite_accessory/hair/taj/braid + name = "Tajara Braid" + icon_state = "hair_tbraid_s_noear" + uid = "acc_hair_taj_braid" + +/decl/sprite_accessory/hair/taj/shaggy + name = "Tajara Shaggy" + icon_state = "hair_shaggy_s_noear" + uid = "acc_hair_taj_shaggy" + +/decl/sprite_accessory/hair/taj/mohawk + name = "Tajaran Mohawk" + icon_state = "hair_mohawk_s_noear" + uid = "acc_hair_taj_mohawk" + +/decl/sprite_accessory/hair/taj/plait + name = "Tajara Plait" + icon_state = "hair_plait_s_noear" + uid = "acc_hair_taj_plait" + +/decl/sprite_accessory/hair/taj/straight + name = "Tajara Straight" + icon_state = "hair_straight_s_noear" + uid = "acc_hair_taj_straight" + +/decl/sprite_accessory/hair/taj/long + name = "Tajara Long" + icon_state = "hair_long_s_noear" + uid = "acc_hair_taj_long" + +/decl/sprite_accessory/hair/taj/spiky + name = "Tajara Spiky" + icon_state = "hair_tajspiky_s_noear" + uid = "acc_hair_taj_spiky" + +/decl/sprite_accessory/hair/taj/messy + name = "Tajara Messy" + icon_state = "hair_messy_s_noear" + uid = "acc_hair_taj_messy" + +/decl/sprite_accessory/hair/taj/bob + name = "Tajara Bob" + icon_state = "hair_tbob_s_noear" + uid = "acc_hair_taj_bob" + +/decl/sprite_accessory/hair/taj/sidebraid + name = "Tajara Sidebraid" + icon_state = "hair_sidebraid_s_noear" + uid = "acc_hair_taj_sidebraid" + + +/decl/sprite_accessory/hair/taj/ribbons + name = "Tajara Ribbons" + icon_state = "hair_ribbons_s_noear" + uid = "acc_hair_taj_ribbons" + +/decl/sprite_accessory/hair/taj/combedback + name = "Tajara Combedback" + icon_state = "hair_combedback_s_noear" + uid = "acc_hair_taj_combedback" + +/decl/sprite_accessory/hair/taj/tailedbangs + name = "Tajara Tailedbangs" + icon_state = "hair_tailedbangs_s_noear" + uid = "acc_hair_taj_tailedbangs" + +/decl/sprite_accessory/hair/taj/longtail + name = "Tajara Longtail" + icon_state = "hair_longtail_s_noear" + uid = "acc_hair_taj_longtail" + +/decl/sprite_accessory/hair/taj/shy + name = "Tajara Shy" + icon_state = "hair_shy_s_noear" + uid = "acc_hair_taj_shy" + +/decl/sprite_accessory/hair/taj/ponytail + name = "Tajara Ponytail" + icon_state = "hair_ponytail_s_noear" + uid = "acc_hair_taj_ponytail" + +/decl/sprite_accessory/hair/taj/overeye + name = "Tajara Overeye" + icon_state = "hair_overeye_s_noear" + uid = "acc_hair_taj_overeye" + +/decl/sprite_accessory/hair/taj/tough + name = "Tajara Tough" + icon_state = "hair_tough_s_noear" + uid = "acc_hair_taj_tough" + +/decl/sprite_accessory/hair/taj/cuttail + name = "Tajara Cuttail" + icon_state = "hair_cuttail_s_noear" + uid = "acc_hair_taj_cuttail" + +/decl/sprite_accessory/hair/taj/dreadlocks + name = "Tajara Dreadlocks" + icon_state = "hair_dreadlocks_s_noear" + uid = "acc_hair_taj_dreadlocks" + +/decl/sprite_accessory/hair/taj/fingerwave + name = "Tajaran Fingerwave" + icon_state = "hair_fingerwave_s_noear" + uid = "acc_hair_taj_fingerwave" + +/decl/sprite_accessory/hair/taj/lynx + name = "Tajaran Lynx" + icon_state = "hair_lynx_s_noear" + uid = "acc_hair_taj_lynx" + +//Facial hs + +/decl/sprite_accessory/facial_hair/taj + name = "Tajara Sideburns" + icon_state = "facial_sideburns" + species_allowed = list(/decl/species/tajaran::uid) + icon = 'mods/species/tajaran/icons/facial.dmi' + uid = "acc_fhair_taj_sideburns" + +/decl/sprite_accessory/facial_hair/taj/mutton + name = "Tajara Mutton" + icon_state = "facial_mutton" + uid = "acc_fhair_taj_mutton" + +/decl/sprite_accessory/facial_hair/taj/pencilstache + name = "Tajara Pencilstache" + icon_state = "facial_pencilstache" + uid = "acc_fhair_taj_pencilstache" + +/decl/sprite_accessory/facial_hair/taj/moustache + name = "Tajara Moustache" + icon_state = "facial_moustache" + uid = "acc_fhair_taj_moustache" + +/decl/sprite_accessory/facial_hair/taj/goatee + name = "Tajara Goatee" + icon_state = "facial_goatee" + uid = "acc_fhair_taj_goatee" + +/decl/sprite_accessory/facial_hair/taj/smallstache + name = "Tajara Smallsatche" + icon_state = "facial_smallstache" + uid = "acc_fhair_taj_smallstache" + +//Markings +/decl/sprite_accessory/marking/tajaran + name = "Tajaran Nose" + icon_state = "nose" + icon = 'mods/species/tajaran/icons/markings.dmi' + species_allowed = list(/decl/species/tajaran::uid) + body_parts = list(BP_HEAD) + color_blend = ICON_MULTIPLY + uid = "acc_marking_taj_nose" + +/decl/sprite_accessory/ears/tajaran + name = "Tajaran Ears" + icon_state = "ears_plain" + icon = 'mods/species/tajaran/icons/ears.dmi' + mask_to_bodypart = FALSE + uid = "acc_marking_taj_wideears" + species_allowed = list(/decl/species/tajaran::uid) + +/decl/sprite_accessory/ears/tajaran/inner + name = "Tajaran Ears Interior" + icon_state = "earsin" + uid = "acc_marking_taj_wideears_inner" + +/decl/sprite_accessory/ears/tajaran/outer + name = "Tajaran Ears Exterior" + icon_state = "earsout" + uid = "acc_marking_taj_wideears_outer" + +/decl/sprite_accessory/ears/tajaran/wide_tuft + name = "Tajaran Ear Tufts" + icon_state = "earsout_tuft" + uid = "acc_marking_taj_wideears_tuft" + +/decl/sprite_accessory/marking/tajaran/patches + name = "Patches (Body)" + icon_state = "patches" + body_parts = list(BP_CHEST, BP_GROIN) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_patches" + +/decl/sprite_accessory/marking/tajaran/patches/left_arm + name = "Patches (Left Arm)" + body_parts = list(BP_L_ARM, BP_L_HAND) + uid = "acc_marking_taj_patches_leftarm" + +/decl/sprite_accessory/marking/tajaran/patches/right_arm + name = "Patches (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_taj_patches_rightarm" + +/decl/sprite_accessory/marking/tajaran/patches/left_leg + name = "Patches (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_taj_patches_leftleg" + +/decl/sprite_accessory/marking/tajaran/patches/right_leg + name = "Patches (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_taj_patches_rightleg" + +/decl/sprite_accessory/marking/tajaran/patches/head + name = "Patches (Head)" + icon_state = "patchesface" + body_parts = list(BP_HEAD) + uid = "acc_marking_taj_patches_head" + + +/decl/sprite_accessory/marking/tajaran/tiger + name = "Tiger Stripes (Body)" + icon_state = "tiger" + accessory_flags = HAIR_LOSS_VULNERABLE + body_parts = list(BP_CHEST, BP_GROIN) + uid = "acc_marking_taj_tiger_body" + +/decl/sprite_accessory/marking/tajaran/tiger/left_arm + name = "Tiger Stripes (Left Arm)" + body_parts = list(BP_L_ARM, BP_L_HAND) + uid = "acc_marking_taj_tiger_leftarm" + +/decl/sprite_accessory/marking/tajaran/tiger/right_arm + name = "Tiger Stripes (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_taj_tiger_rightarm" + +/decl/sprite_accessory/marking/tajaran/tiger/left_leg + name = "Tiger Stripes (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_taj_tiger_leftleg" + +/decl/sprite_accessory/marking/tajaran/tiger/right_leg + name = "Tiger Stripes (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_taj_tiger_rightleg" + +/decl/sprite_accessory/marking/tajaran/tiger/head + name = "Tiger Stripes (Head)" + icon_state = "tigerface" + body_parts = list(BP_HEAD) + uid = "acc_marking_taj_tiger_head" + +/decl/sprite_accessory/marking/tajaran/pawsocks + name = "Pawsocks (Left Arm)" + icon_state = "pawsocks" + body_parts = list(BP_L_ARM, BP_L_HAND) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_pawsocks_leftarm" + +/decl/sprite_accessory/marking/tajaran/pawsocks/right_arm + name = "Pawsocks (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_taj_pawsocks_rightarm" + +/decl/sprite_accessory/marking/tajaran/pawsocks/left_leg + name = "Pawsocks (Left Leg)" + body_parts = list(BP_L_LEG, BP_L_FOOT) + uid = "acc_marking_taj_pawsocks_leftleg" + +/decl/sprite_accessory/marking/tajaran/pawsocks/right_leg + name = "Pawsocks (Right Leg)" + body_parts = list(BP_R_LEG, BP_R_FOOT) + uid = "acc_marking_taj_pawsocks_rightleg" + +/decl/sprite_accessory/marking/tajaran/tuxedo + name = "Tuxedo (Body, Legs, Feet)" + icon_state = "tuxedo" + body_parts = list(BP_CHEST, BP_GROIN, BP_R_LEG, BP_R_FOOT, BP_L_LEG, BP_L_FOOT) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_tuxedo_body" + +/decl/sprite_accessory/marking/tajaran/tuxedo/right_arm + name = "Tuxedo (Right Arm)" + body_parts = list(BP_R_ARM, BP_R_HAND) + uid = "acc_marking_taj_tuxedo_rightarm" + +/decl/sprite_accessory/marking/tajaran/tuxedo/left_arm + name = "Tuxedo (Left Arm)" + body_parts = list(BP_L_ARM, BP_L_HAND) + uid = "acc_marking_taj_tuxedo_leftarm" + +/decl/sprite_accessory/marking/tajaran/belly + name = "Belly Full (Body)" + icon_state = "bellyfull" + body_parts = list(BP_CHEST, BP_GROIN) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_belly" + +/decl/sprite_accessory/marking/tajaran/belly/upper + name = "Belly Upper (Body)" + icon_state = "crest" + body_parts = list(BP_CHEST) + uid = "acc_marking_taj_bellyupper" + +/decl/sprite_accessory/marking/tajaran/belly/lower + name = "Belly Lower (Body)" + icon_state = "belly" + uid = "acc_marking_taj_bellylower" + +/decl/sprite_accessory/marking/tajaran/backstripe + name = "Back Stripe (Body)" + icon_state = "backstripe" + body_parts = list(BP_CHEST, BP_GROIN) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_backstripe" + +/decl/sprite_accessory/marking/tajaran/muzzle + name = "Muzzle Coloration (Head)" + icon_state = "muzzle" + body_parts = list(BP_HEAD) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_muzzle" + +/decl/sprite_accessory/marking/tajaran/chin + name = "Chin Coloration (Head)" + icon_state = "chin" + body_parts = list(BP_HEAD) + accessory_flags = HAIR_LOSS_VULNERABLE + uid = "acc_marking_taj_chin" \ No newline at end of file diff --git a/mods/species/tajaran/datum/blood.dm b/mods/species/tajaran/datum/blood.dm new file mode 100644 index 000000000000..e993197f5327 --- /dev/null +++ b/mods/species/tajaran/datum/blood.dm @@ -0,0 +1,58 @@ +/decl/blood_type/tajaran + antigen_category = "Tajaran" + splatter_colour = "#862a51" + abstract_type = /decl/blood_type/tajaran + +/decl/blood_type/tajaran/mplus + name = "M+" + antigens = list("M", "Fe") + random_weighting = 28 + +/decl/blood_type/tajaran/mminus + name = "M-" + antigens = list("M") + random_weighting = 3 + +/decl/blood_type/tajaran/rplus + name = "R+" + antigens = list("R", "Fe") + random_weighting = 20 + +/decl/blood_type/tajaran/rminus + name = "R-" + antigens = list("R",) + +/decl/blood_type/tajaran/mrplus + name = "MR+" + antigens = list("M", "R", "Fe") + random_weighting = 5 + +/decl/blood_type/tajaran/mrminus + name = "MR-" + antigens = list("M", "R") + +/decl/blood_type/tajaran/oplus + name = "Of+" + antigens = list("Fe") + random_weighting = 36 + +/decl/blood_type/tajaran/ominus + name = "Of-" + random_weighting = 4 + +/obj/item/chems/ivbag/blood/tajaran_mplus + label_text = "M+" +/obj/item/chems/ivbag/blood/tajaran_mminus + label_text = "M-" +/obj/item/chems/ivbag/blood/tajaran_rplus + label_text = "R+" +/obj/item/chems/ivbag/blood/tajaran_mminus + label_text = "M-" +/obj/item/chems/ivbag/blood/tajaran_mrplus + label_text = "MR+" +/obj/item/chems/ivbag/blood/tajaran_mrminus + label_text = "MR-" +/obj/item/chems/ivbag/blood/tajaran_oplus + label_text = "Of+" +/obj/item/chems/ivbag/blood/tajaran_oplus + label_text = "Of-" diff --git a/mods/species/tajaran/datum/culture.dm b/mods/species/tajaran/datum/culture.dm new file mode 100644 index 000000000000..0280c12fad83 --- /dev/null +++ b/mods/species/tajaran/datum/culture.dm @@ -0,0 +1,9 @@ +/decl/background_detail/heritage/tajaran + name = "Tajaran Culture" + description = "The Tajaran culture is steeped in superstition and tradition from centuries of survival on their harsh, frozen homeworld." + language = /decl/language/tajaran + secondary_langs = list( + /decl/language/human/common, + /decl/language/sign + ) + uid = "heritage_tajaran" diff --git a/mods/species/tajaran/datum/emotes.dm b/mods/species/tajaran/datum/emotes.dm new file mode 100644 index 000000000000..9dff98489016 --- /dev/null +++ b/mods/species/tajaran/datum/emotes.dm @@ -0,0 +1,9 @@ +/decl/emote/audible/purr + key = "purr" + emote_message_3p = "$USER$ purrs." + emote_sound = 'mods/species/tajaran/sound/cat_purr.ogg' + +/decl/emote/audible/purrlong + key = "purrl" + emote_message_3p = "$USER$ purrs." + emote_sound = 'mods/species/tajaran/sound/cat_purr_long.ogg' diff --git a/mods/species/tajaran/datum/language.dm b/mods/species/tajaran/datum/language.dm new file mode 100644 index 000000000000..aa7782a9560f --- /dev/null +++ b/mods/species/tajaran/datum/language.dm @@ -0,0 +1,30 @@ +/decl/language/tajaran + name = LANGUAGE_TAJARAN + desc = "The traditionally employed tongue of Ahdomai, composed of expressive yowls and chirps. Native to the Tajaran." + speech_verb = "purrs" + ask_verb = "purrs" + exclaim_verb = "howls" + whisper_verb = "purrs softly" + key = "2" + flags = LANG_FLAG_WHITELISTED + shorthand = "T" + syllables = list("mrr","rr","tajr","kir","raj","kii","mir","kra","ahk","nal","vah","khaz","jri","ran","darr", + "mi","jri","dynh","manq","rhe","zar","rrhaz","kal","chur","eech","thaa","dra","jurl","mah","sanu","dra","ii'r", + "ka","aasi","far","wa","baq","ara","qara","zir","sam","mak","hrar","nja","rir","khan","jun","dar","rik","kah", + "hal","ket","jurl","mah","tul","cresh","azu","ragh","mro","mra","mrro","mrra") + +/decl/language/tajaran/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + var/new_name = ..(gender,1) + if(prob(70)) + new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]" + else + new_name += " [..(gender,1)]" + return new_name + +//#803b56 is color + +/decl/language/tajaran/format_message(message, verb) + return "[verb], \"[capitalize(message)]\"" + +/decl/language/tajaran/format_message_radio(message, verb) + return "[verb], \"[capitalize(message)]\"" diff --git a/mods/species/tajaran/datum/species.dm b/mods/species/tajaran/datum/species.dm new file mode 100644 index 000000000000..c59ce11ca429 --- /dev/null +++ b/mods/species/tajaran/datum/species.dm @@ -0,0 +1,82 @@ +/datum/appearance_descriptor/age/tajaran + standalone_value_descriptors = list( + "an infant" = 1, + "a toddler" = 3, + "a child" = 7, + "an adolescent" = 13, + "a young adult" = 18, + "an adult" = 30, + "middle-aged" = 55, + "aging" = 80, + "elderly" = 140 + ) + +/decl/species/tajaran + uid = "species_tajaran" + name = "Tajara" + name_plural = "Tajaran" + base_external_prosthetics_model = /decl/bodytype/prosthetic/basic_human + + description = "A small mammalian carnivore. If you are reading this, you are probably a Tajaran." + hidden_from_codex = FALSE + available_bodytypes = list( + /decl/bodytype/tajaran, + /decl/bodytype/tajaran/masculine + ) + + traits = list(/decl/trait/malus/intolerance/caffeine = TRAIT_LEVEL_MAJOR) + + preview_outfit = /decl/outfit/job/generic/engineer + + spawn_flags = SPECIES_CAN_JOIN + + blood_types = list( + /decl/blood_type/tajaran/mplus, + /decl/blood_type/tajaran/mminus, + /decl/blood_type/tajaran/rplus, + /decl/blood_type/tajaran/rminus, + /decl/blood_type/tajaran/mrplus, + /decl/blood_type/tajaran/mrminus, + /decl/blood_type/tajaran/oplus, + /decl/blood_type/tajaran/ominus + ) + + flesh_color = "#ae7d32" + + organs_icon = 'mods/species/tajaran/icons/organs.dmi' + + hunger_factor = DEFAULT_HUNGER_FACTOR * 1.2 + thirst_factor = DEFAULT_THIRST_FACTOR * 1.2 + gluttonous = GLUT_TINY + + move_trail = /obj/effect/decal/cleanable/blood/tracks/paw + + available_background_info = list( + /decl/background_category/heritage = list( + /decl/background_detail/heritage/tajaran, + /decl/background_detail/heritage/other + ) + ) + + default_emotes = list( + /decl/emote/visible/tail/swish, + /decl/emote/visible/tail/wag, + /decl/emote/visible/tail/sway, + /decl/emote/visible/tail/qwag, + /decl/emote/visible/tail/fastsway, + /decl/emote/visible/tail/swag, + /decl/emote/visible/tail/stopsway, + /decl/emote/audible/purr, + /decl/emote/audible/purrlong + ) + + //Autohiss + autohiss_basic_map = list( + "r" = list("rr", "rrr", "rrrr"), + "р" = list("рр", "ррр", "рррр")//thats not "pi" + ) + + autohiss_exempt = list(LANGUAGE_TAJARAN) + +/decl/species/tajaran/handle_additional_hair_loss(var/mob/living/human/H, var/defer_body_update = TRUE) + . = H?.set_skin_colour(rgb(189, 171, 143)) diff --git a/mods/species/tajaran/datum/species_bodytypes.dm b/mods/species/tajaran/datum/species_bodytypes.dm new file mode 100644 index 000000000000..3a0eef87ae26 --- /dev/null +++ b/mods/species/tajaran/datum/species_bodytypes.dm @@ -0,0 +1,77 @@ +/decl/bodytype/tajaran + name = "feminine" + bodytype_category = BODYTYPE_TAJARAN + limb_blend = ICON_MULTIPLY + icon_template = 'mods/species/tajaran/icons/template.dmi' + icon_base = 'mods/species/tajaran/icons/body.dmi' + icon_deformed = 'mods/species/tajaran/icons/deformed_body.dmi' + bandages_icon = 'icons/mob/bandage.dmi' + skeletal_icon = 'mods/species/tajaran/icons/skeleton.dmi' + cosmetics_icon = 'mods/species/tajaran/icons/cosmetics.dmi' + health_hud_intensity = 1.75 + bodytype_flag = BODY_EQUIP_FLAG_HUMANOID + movement_slowdown = -0.5 + appearance_flags = HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR + base_color = "#ae7d32" + base_eye_color = "#00aa00" + nail_noun = "claws" + uid = "bodytype_tajaran" + footprints_icon = 'icons/mob/footprints/footprints_paw.dmi' + + age_descriptor = /datum/appearance_descriptor/age/tajaran + + eye_darksight_range = 7 + eye_flash_mod = 2 + eye_blend = ICON_MULTIPLY + eye_icon = 'mods/species/tajaran/icons/eyes.dmi' + eye_low_light_vision_effectiveness = 0.15 + eye_low_light_vision_adjustment_speed = 0.3 + + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/cat, + BP_HEAD = /obj/item/organ/external/head/sharp_bite, + BP_L_HAND = /obj/item/organ/external/hand/clawed, + BP_R_HAND = /obj/item/organ/external/hand/right/clawed + ) + + default_sprite_accessories = list( + SAC_HAIR = list(/decl/sprite_accessory/hair/taj/lynx = list(SAM_COLOR = "#46321c")), + SAC_EARS = list(/decl/sprite_accessory/ears/tajaran = list(SAM_COLOR = "#ae7d32")) + ) + + cold_level_1 = 200 + cold_level_2 = 140 + cold_level_3 = 80 + + heat_level_1 = 330 + heat_level_2 = 380 + heat_level_3 = 800 + + heat_discomfort_level = 294 + cold_discomfort_level = 230 + heat_discomfort_strings = list( + "Your fur prickles in the heat.", + "You feel uncomfortably warm.", + "Your overheated skin itches." + ) + +/decl/bodytype/tajaran/masculine + name = "masculine" + icon_base = 'mods/species/tajaran/icons/body_male.dmi' + icon_deformed = 'mods/species/tajaran/icons/deformed_body_male.dmi' + associated_gender = MALE + onmob_state_modifiers = null + uid = "bodytype_tajaran_masc" + +/decl/bodytype/tajaran/get_default_grooming_results(obj/item/organ/external/limb, obj/item/grooming/tool) + if(tool?.grooming_flags & GROOMABLE_BRUSH) + return list( + "success" = GROOMING_RESULT_SUCCESS, + "descriptor" = "[limb.name] fur" + ) + return ..() + +/obj/item/organ/external/tail/cat + tail_icon = 'mods/species/tajaran/icons/tail.dmi' + tail_blend = ICON_MULTIPLY + tail_animation_states = 1 diff --git a/mods/species/tajaran/icons/body.dmi b/mods/species/tajaran/icons/body.dmi new file mode 100644 index 000000000000..498c7147fc74 Binary files /dev/null and b/mods/species/tajaran/icons/body.dmi differ diff --git a/mods/species/tajaran/icons/body_male.dmi b/mods/species/tajaran/icons/body_male.dmi new file mode 100644 index 000000000000..3b9dfbc6b758 Binary files /dev/null and b/mods/species/tajaran/icons/body_male.dmi differ diff --git a/mods/species/tajaran/icons/clothing/atmos/suit.dmi b/mods/species/tajaran/icons/clothing/atmos/suit.dmi new file mode 100644 index 000000000000..a31a324c51b5 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/atmos/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/atmos_alt/suit.dmi b/mods/species/tajaran/icons/clothing/atmos_alt/suit.dmi new file mode 100644 index 000000000000..89d54fbbefdc Binary files /dev/null and b/mods/species/tajaran/icons/clothing/atmos_alt/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/deathsquad/suit.dmi b/mods/species/tajaran/icons/clothing/deathsquad/suit.dmi new file mode 100644 index 000000000000..54641a3200ef Binary files /dev/null and b/mods/species/tajaran/icons/clothing/deathsquad/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/engineering/suit.dmi b/mods/species/tajaran/icons/clothing/engineering/suit.dmi new file mode 100644 index 000000000000..f318522ac808 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/engineering/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/engineering_alt/suit.dmi b/mods/species/tajaran/icons/clothing/engineering_alt/suit.dmi new file mode 100644 index 000000000000..b012a375b4ab Binary files /dev/null and b/mods/species/tajaran/icons/clothing/engineering_alt/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/excavation/suit.dmi b/mods/species/tajaran/icons/clothing/excavation/suit.dmi new file mode 100644 index 000000000000..4cd8145d8248 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/excavation/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/medical/suit.dmi b/mods/species/tajaran/icons/clothing/medical/suit.dmi new file mode 100644 index 000000000000..def6b39bfba0 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/medical/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/medical_alt/suit.dmi b/mods/species/tajaran/icons/clothing/medical_alt/suit.dmi new file mode 100644 index 000000000000..ec3911d4b0ec Binary files /dev/null and b/mods/species/tajaran/icons/clothing/medical_alt/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/merc/suit.dmi b/mods/species/tajaran/icons/clothing/merc/suit.dmi new file mode 100644 index 000000000000..142f157f9e10 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/merc/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/mining/suit.dmi b/mods/species/tajaran/icons/clothing/mining/suit.dmi new file mode 100644 index 000000000000..807bbbe10067 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/mining/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/mining_alt/suit.dmi b/mods/species/tajaran/icons/clothing/mining_alt/suit.dmi new file mode 100644 index 000000000000..e0875569f4af Binary files /dev/null and b/mods/species/tajaran/icons/clothing/mining_alt/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/nasa/suit.dmi b/mods/species/tajaran/icons/clothing/nasa/suit.dmi new file mode 100644 index 000000000000..1106524e22b3 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/nasa/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/pilot/suit.dmi b/mods/species/tajaran/icons/clothing/pilot/suit.dmi new file mode 100644 index 000000000000..eeafe5468dd2 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/pilot/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/salvage/suit.dmi b/mods/species/tajaran/icons/clothing/salvage/suit.dmi new file mode 100644 index 000000000000..de86bbe11a8b Binary files /dev/null and b/mods/species/tajaran/icons/clothing/salvage/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/sec/suit.dmi b/mods/species/tajaran/icons/clothing/sec/suit.dmi new file mode 100644 index 000000000000..ab3e3755309d Binary files /dev/null and b/mods/species/tajaran/icons/clothing/sec/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/sec_alt/suit.dmi b/mods/species/tajaran/icons/clothing/sec_alt/suit.dmi new file mode 100644 index 000000000000..ee97931ed53f Binary files /dev/null and b/mods/species/tajaran/icons/clothing/sec_alt/suit.dmi differ diff --git a/mods/species/tajaran/icons/clothing/wizard/suit.dmi b/mods/species/tajaran/icons/clothing/wizard/suit.dmi new file mode 100644 index 000000000000..c27a511cc662 Binary files /dev/null and b/mods/species/tajaran/icons/clothing/wizard/suit.dmi differ diff --git a/mods/species/tajaran/icons/cosmetics.dmi b/mods/species/tajaran/icons/cosmetics.dmi new file mode 100644 index 000000000000..ed3ccc2daea2 Binary files /dev/null and b/mods/species/tajaran/icons/cosmetics.dmi differ diff --git a/mods/species/tajaran/icons/deformed_body.dmi b/mods/species/tajaran/icons/deformed_body.dmi new file mode 100644 index 000000000000..cf761e9bf07d Binary files /dev/null and b/mods/species/tajaran/icons/deformed_body.dmi differ diff --git a/mods/species/tajaran/icons/deformed_body_male.dmi b/mods/species/tajaran/icons/deformed_body_male.dmi new file mode 100644 index 000000000000..11d2cbbe55a3 Binary files /dev/null and b/mods/species/tajaran/icons/deformed_body_male.dmi differ diff --git a/mods/species/tajaran/icons/ears.dmi b/mods/species/tajaran/icons/ears.dmi new file mode 100644 index 000000000000..27418f2b560e Binary files /dev/null and b/mods/species/tajaran/icons/ears.dmi differ diff --git a/mods/species/tajaran/icons/eyes.dmi b/mods/species/tajaran/icons/eyes.dmi new file mode 100644 index 000000000000..d9f4f5d9a86a Binary files /dev/null and b/mods/species/tajaran/icons/eyes.dmi differ diff --git a/mods/species/tajaran/icons/facial.dmi b/mods/species/tajaran/icons/facial.dmi new file mode 100644 index 000000000000..befd9dc68b46 Binary files /dev/null and b/mods/species/tajaran/icons/facial.dmi differ diff --git a/mods/species/tajaran/icons/hair.dmi b/mods/species/tajaran/icons/hair.dmi new file mode 100644 index 000000000000..2d1c659aa78e Binary files /dev/null and b/mods/species/tajaran/icons/hair.dmi differ diff --git a/mods/species/tajaran/icons/markings.dmi b/mods/species/tajaran/icons/markings.dmi new file mode 100644 index 000000000000..20a0a07b9593 Binary files /dev/null and b/mods/species/tajaran/icons/markings.dmi differ diff --git a/mods/species/tajaran/icons/organs.dmi b/mods/species/tajaran/icons/organs.dmi new file mode 100644 index 000000000000..d249044c22ce Binary files /dev/null and b/mods/species/tajaran/icons/organs.dmi differ diff --git a/mods/species/tajaran/icons/skeleton.dmi b/mods/species/tajaran/icons/skeleton.dmi new file mode 100644 index 000000000000..4ab2d2bc53d6 Binary files /dev/null and b/mods/species/tajaran/icons/skeleton.dmi differ diff --git a/mods/species/tajaran/icons/tail.dmi b/mods/species/tajaran/icons/tail.dmi new file mode 100644 index 000000000000..2851b3f7e33b Binary files /dev/null and b/mods/species/tajaran/icons/tail.dmi differ diff --git a/mods/species/tajaran/icons/template.dmi b/mods/species/tajaran/icons/template.dmi new file mode 100644 index 000000000000..a5778d0652bd Binary files /dev/null and b/mods/species/tajaran/icons/template.dmi differ diff --git a/mods/species/tajaran/machinery/suit_cycler.dm b/mods/species/tajaran/machinery/suit_cycler.dm new file mode 100644 index 000000000000..44be03d5588e --- /dev/null +++ b/mods/species/tajaran/machinery/suit_cycler.dm @@ -0,0 +1,52 @@ +/obj/machinery/suit_cycler/Initialize() + LAZYDISTINCTADD(available_bodytypes, BODYTYPE_TAJARAN) + . = ..() + +/obj/item/clothing/suit/space/void/merc + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/merc/suit.dmi' + +/obj/item/clothing/suit/space/void/swat + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/deathsquad/suit.dmi' + +/obj/item/clothing/suit/space/void/engineering + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/engineering/suit.dmi' + +/obj/item/clothing/suit/space/void/mining + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/mining/suit.dmi' + +/obj/item/clothing/suit/space/void/medical + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/medical/suit.dmi' + +/obj/item/clothing/suit/space/void/security + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/sec/suit.dmi' + +/obj/item/clothing/suit/space/void/atmos + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/atmos/suit.dmi' + +/obj/item/clothing/suit/space/void/engineering/alt + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/engineering_alt/suit.dmi' + +/obj/item/clothing/suit/space/void/mining/alt + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/mining_alt/suit.dmi' + +/obj/item/clothing/suit/space/void/medical/alt + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/medical_alt/suit.dmi' + +/obj/item/clothing/suit/space/void/security/alt + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/sec_alt/suit.dmi' + +/obj/item/clothing/suit/space/void/atmos/alt + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/atmos_alt/suit.dmi' + +/obj/item/clothing/suit/space/void/engineering/salvage + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/salvage/suit.dmi' + +/obj/item/clothing/suit/space/void/expedition + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/pilot/suit.dmi' + +/obj/item/clothing/suit/space/void + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/nasa/suit.dmi' + + +/obj/item/clothing/suit/space/void/excavation + _tajaran_onmob_icon = 'mods/species/tajaran/icons/clothing/excavation/suit.dmi' diff --git a/mods/species/tajaran/sound/cat_purr.ogg b/mods/species/tajaran/sound/cat_purr.ogg new file mode 100644 index 000000000000..1125cb2bbd71 Binary files /dev/null and b/mods/species/tajaran/sound/cat_purr.ogg differ diff --git a/mods/species/tajaran/sound/cat_purr_long.ogg b/mods/species/tajaran/sound/cat_purr_long.ogg new file mode 100644 index 000000000000..c74b845250d0 Binary files /dev/null and b/mods/species/tajaran/sound/cat_purr_long.ogg differ diff --git a/mods/species/tritonian/_tritonian.dm b/mods/species/tritonian/_tritonian.dm new file mode 100644 index 000000000000..b0a904ef7146 --- /dev/null +++ b/mods/species/tritonian/_tritonian.dm @@ -0,0 +1,2 @@ +/decl/modpack/tritonians + name = "Tritonian Species" \ No newline at end of file diff --git a/mods/species/tritonian/_tritonian.dme b/mods/species/tritonian/_tritonian.dme new file mode 100644 index 000000000000..b1f286a9dd84 --- /dev/null +++ b/mods/species/tritonian/_tritonian.dme @@ -0,0 +1,8 @@ +#ifndef MODPACK_TRITONIAN_SPECIES +#define MODPACK_TRITONIAN_SPECIES +// BEGIN_INCLUDE +#include "_tritonian.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +// END_INCLUDE +#endif diff --git a/mods/species/tritonian/datum/species.dm b/mods/species/tritonian/datum/species.dm new file mode 100644 index 000000000000..782588ca0e7e --- /dev/null +++ b/mods/species/tritonian/datum/species.dm @@ -0,0 +1,16 @@ +/decl/species/human/tritonian + uid = "species_tritonian" + name = "Tritonian" + name_plural = "Tritonians" + description = "A human-derived genotype designed for colonizing aquatic worlds." + + available_bodytypes = list( + /decl/bodytype/human/tritonian, + /decl/bodytype/human/tritonian/masculine + ) + + oxy_mod = 0.5 + toxins_mod = 1.5 + + body_temperature = 302 + water_soothe_amount = 5 diff --git a/mods/species/tritonian/datum/species_bodytypes.dm b/mods/species/tritonian/datum/species_bodytypes.dm new file mode 100644 index 000000000000..9ee6c55a8039 --- /dev/null +++ b/mods/species/tritonian/datum/species_bodytypes.dm @@ -0,0 +1,29 @@ +/decl/bodytype/human/tritonian + icon_base = 'mods/species/tritonian/icons/body_female.dmi' + movement_slowdown = 0.5 + appearance_flags = HAS_SKIN_TONE_TRITON | HAS_UNDERWEAR | HAS_EYE_COLOR + uid = "bodytype_tritonian_fem" + override_organ_types = list( + BP_LUNGS = /obj/item/organ/internal/lungs/gills + ) + override_limb_types = list( + BP_HEAD = /obj/item/organ/external/head/sharp_bite + ) + +/decl/bodytype/human/tritonian/masculine + name = "masculine" + icon_base = 'mods/species/tritonian/icons/body_male.dmi' + icon_deformed = 'icons/mob/human_races/species/human/deformed_body_male.dmi' + associated_gender = MALE + onmob_state_modifiers = null + uid = "bodytype_tritonian_masc" + override_emote_sounds = list( + "cough" = list( + 'sound/voice/emotes/m_cougha.ogg', + 'sound/voice/emotes/m_coughb.ogg', + 'sound/voice/emotes/m_coughc.ogg' + ), + "sneeze" = list( + 'sound/voice/emotes/m_sneeze.ogg' + ) + ) diff --git a/mods/species/tritonian/icons/body_female.dmi b/mods/species/tritonian/icons/body_female.dmi new file mode 100644 index 000000000000..117b732bd3bc Binary files /dev/null and b/mods/species/tritonian/icons/body_female.dmi differ diff --git a/mods/species/tritonian/icons/body_male.dmi b/mods/species/tritonian/icons/body_male.dmi new file mode 100644 index 000000000000..44df6e916b77 Binary files /dev/null and b/mods/species/tritonian/icons/body_male.dmi differ diff --git a/mods/species/tritonian/icons/tritonian_preview.dmi b/mods/species/tritonian/icons/tritonian_preview.dmi new file mode 100644 index 000000000000..f277815297d0 Binary files /dev/null and b/mods/species/tritonian/icons/tritonian_preview.dmi differ diff --git a/mods/species/unathi/_unathi.dm b/mods/species/unathi/_unathi.dm new file mode 100644 index 000000000000..ca5be894e5da --- /dev/null +++ b/mods/species/unathi/_unathi.dm @@ -0,0 +1,17 @@ +#define LANGUAGE_LIZARD "Sinta'unathi" + +/decl/modpack/unathi + name = "Unathi Species" + tabloid_headlines = list( + "SHOCKING FIGURES REVEAL MORE TEENS DIE TO UNATHI HONOUR DUELS THAN GUN VIOLENCE", + "LOCAL UNATHI SYMPATHIZER: 'I really think you should stop with these spacebaiting articles.'", + "DO UNATHI SYMPATHIZERS HATE THE HUMAN RACE?" + ) + +/decl/modpack/unathi/pre_initialize() + ..() + SSmodpacks.default_submap_whitelisted_species |= /decl/species/unathi::uid + +/mob/living/human/unathi/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + species_uid = /decl/species/unathi::uid + . = ..() diff --git a/mods/species/unathi/_unathi.dme b/mods/species/unathi/_unathi.dme new file mode 100644 index 000000000000..175b179346b6 --- /dev/null +++ b/mods/species/unathi/_unathi.dme @@ -0,0 +1,14 @@ +#ifndef MODPACK_SPECIES_UNATHI +#define MODPACK_SPECIES_UNATHI +// BEGIN_INCLUDE +#include "_unathi.dm" +#include "datum\autohiss.dm" +#include "datum\blood.dm" +#include "datum\culture.dm" +#include "datum\language.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "datum\sprite_accessory.dm" +#include "organs\organs_internal.dm" +// END_INCLUDE +#endif diff --git a/mods/species/unathi/datum/autohiss.dm b/mods/species/unathi/datum/autohiss.dm new file mode 100644 index 000000000000..9d5d7024f7ef --- /dev/null +++ b/mods/species/unathi/datum/autohiss.dm @@ -0,0 +1,10 @@ +/decl/species/unathi + autohiss_basic_map = list( + "s" = list("ss", "sss", "ssss") + ) + autohiss_extra_map = list( + "x" = list("ks", "kss", "ksss") + ) + autohiss_exempt = list( + LANGUAGE_LIZARD + ) diff --git a/mods/species/unathi/datum/blood.dm b/mods/species/unathi/datum/blood.dm new file mode 100644 index 000000000000..3934dba61992 --- /dev/null +++ b/mods/species/unathi/datum/blood.dm @@ -0,0 +1,58 @@ +/decl/blood_type/reptile + abstract_type = /decl/blood_type/reptile + splatter_colour = "#f24b2e" + antigens = list("S", "X", "Li") + +/decl/blood_type/reptile/splus + name = "S+" + antigens = list("S", "Li") + random_weighting = 28 + +/decl/blood_type/reptile/sminus + name = "S-" + antigens = list("S") + random_weighting = 3 + +/decl/blood_type/reptile/xplus + name = "X+" + antigens = list("X", "Li") + random_weighting = 20 + +/decl/blood_type/reptile/xminus + name = "X-" + antigens = list("X") + +/decl/blood_type/reptile/sxplus + name = "SX+" + antigens = list("S", "X", "Li") + random_weighting = 5 + +/decl/blood_type/reptile/sxminus + name = "SX-" + antigens = list("S", "X") + +/decl/blood_type/reptile/oplus + name = "Or+" + antigens = list("Li") + random_weighting = 36 + +/decl/blood_type/reptile/ominus + name = "Or-" + random_weighting = 4 + +/obj/item/chems/ivbag/blood/reptile_splus + label_text = "S+" +/obj/item/chems/ivbag/blood/reptile_sminus + label_text = "S-" +/obj/item/chems/ivbag/blood/reptile_xplus + label_text = "X+" +/obj/item/chems/ivbag/blood/reptile_xminus + label_text = "X-" +/obj/item/chems/ivbag/blood/reptile_sxplus + label_text = "SX+" +/obj/item/chems/ivbag/blood/reptile_sxminus + label_text = "SX-" +/obj/item/chems/ivbag/blood/reptile_oplus + label_text = "Or+" +/obj/item/chems/ivbag/blood/reptile_ominus + label_text = "Or-" diff --git a/mods/species/unathi/datum/culture.dm b/mods/species/unathi/datum/culture.dm new file mode 100644 index 000000000000..4087e19f3c08 --- /dev/null +++ b/mods/species/unathi/datum/culture.dm @@ -0,0 +1,10 @@ +/decl/background_detail/heritage/unathi + name = "Lizard Culture" + description = "The humanoid race of reptiles was able to successfully adapt to life in space. \ + Despite the fact that these creatures are sensitive to cold, they have a number of fighting qualities that have evolved over their long evolved life." + language = /decl/language/unathi + secondary_langs = list( + /decl/language/human/common, + /decl/language/sign + ) + uid = "heritage_unathi" diff --git a/mods/species/unathi/datum/language.dm b/mods/species/unathi/datum/language.dm new file mode 100644 index 000000000000..e302d2208217 --- /dev/null +++ b/mods/species/unathi/datum/language.dm @@ -0,0 +1,20 @@ +/decl/language/unathi + name = LANGUAGE_LIZARD + desc = "The common language of Lizards, composed of sibilant hisses and rattles. Hiss!" + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "roars" + colour = "soghun" + key = "o" + flags = LANG_FLAG_WHITELISTED + space_chance = 40 + syllables = list( + "za", "az", "ze", "ez", "zi", "iz", "zo", "oz", "zu", "uz", "zs", "sz", + "ha", "ah", "he", "eh", "hi", "ih", "ho", "oh", "hu", "uh", "hs", "sh", + "la", "al", "le", "el", "li", "il", "lo", "ol", "lu", "ul", "ls", "sl", + "ka", "ak", "ke", "ek", "ki", "ik", "ko", "ok", "ku", "uk", "ks", "sk", + "sa", "as", "se", "es", "si", "is", "so", "os", "su", "us", "ss", "ss", + "ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr", + "a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s" + ) + shorthand = "L" diff --git a/mods/species/unathi/datum/species.dm b/mods/species/unathi/datum/species.dm new file mode 100644 index 000000000000..58f34e552448 --- /dev/null +++ b/mods/species/unathi/datum/species.dm @@ -0,0 +1,107 @@ +/datum/appearance_descriptor/age/unathi + standalone_value_descriptors = list( + "an infant" = 1, + "a toddler" = 3, + "a child" = 7, + "an adolescent" = 13, + "a young adult" = 18, + "an adult" = 25, + "middle-aged" = 50, + "aging" = 150, + "elderly" = 260 + ) + +/decl/butchery_data/humanoid/unathi + meat_name = "lizard" + skin_material = /decl/material/solid/organic/skin/lizard + +/decl/species/unathi + uid = "species_unathi" + name = "Unathi" + name_plural = "Unathi" + butchery_data = /decl/butchery_data/humanoid/unathi + + available_bodytypes = list( + /decl/bodytype/unathi, + /decl/bodytype/unathi/masculine + ) + + available_accessory_categories = list( + SAC_HORNS, + SAC_FRILLS, + SAC_COSMETICS, + SAC_MARKINGS, + SAC_TAIL + ) + + primitive_form = "Stok" + gluttonous = GLUT_TINY + strength = STR_HIGH + breath_pressure = 18 + brute_mod = 0.8 + blood_volume = 800 + + hunger_factor = DEFAULT_HUNGER_FACTOR * 2 + thirst_factor = DEFAULT_THIRST_FACTOR * 2 + + body_temperature = null // cold-blooded, implemented the same way nabbers do it + + description = "A heavily reptillian species. They prefer warmer temperatures than most species and \ + their native tongue is a heavy hissing laungage." + + spawn_flags = SPECIES_CAN_JOIN | SPECIES_NO_ROBOTIC_INTERNAL_ORGANS + + flesh_color = "#34af10" + organs_icon = 'mods/species/unathi/icons/organs.dmi' + + preview_outfit = /decl/outfit/job/generic/doctor + + blood_types = list( + /decl/blood_type/reptile/splus, + /decl/blood_type/reptile/sminus, + /decl/blood_type/reptile/xplus, + /decl/blood_type/reptile/xminus, + /decl/blood_type/reptile/sxplus, + /decl/blood_type/reptile/sxminus, + /decl/blood_type/reptile/oplus, + /decl/blood_type/reptile/ominus, + ) + move_trail = /obj/effect/decal/cleanable/blood/tracks/claw + + breathing_sound = 'mods/species/unathi/sound/lizard_breathing.ogg' + + default_emotes = list( + /decl/emote/visible/tail/swish, + /decl/emote/visible/tail/wag, + /decl/emote/visible/tail/sway, + /decl/emote/visible/tail/qwag, + /decl/emote/visible/tail/fastsway, + /decl/emote/visible/tail/swag, + /decl/emote/visible/tail/stopsway + ) + + pain_emotes_with_pain_level = list( + list(/decl/emote/audible/wheeze, /decl/emote/audible/roar, /decl/emote/audible/bellow, /decl/emote/audible/howl) = 80, + list(/decl/emote/audible/grunt, /decl/emote/audible/groan, /decl/emote/audible/wheeze, /decl/emote/audible/hiss) = 50, + list(/decl/emote/audible/grunt, /decl/emote/audible/groan, /decl/emote/audible/hiss) = 20, + ) + + exertion_effect_chance = 10 + exertion_hydration_scale = 1 + exertion_reagent_scale = 1 + exertion_reagent_path = /decl/material/liquid/lactate + exertion_emotes_biological = list( + /decl/emote/exertion/biological, + /decl/emote/exertion/biological/breath, + /decl/emote/exertion/biological/pant + ) + +/decl/species/unathi/Initialize() + . = ..() + LAZYINITLIST(available_background_info) + LAZYDISTINCTADD(available_background_info[/decl/background_category/heritage], /decl/background_detail/heritage/unathi) + LAZYSET(default_background_info, /decl/background_category/heritage, /decl/background_detail/heritage/unathi) + +/decl/species/unathi/equip_survival_gear(mob/living/wearer, box_type = /obj/item/box/survival) + . = ..() + wearer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(wearer), slot_shoes_str) diff --git a/mods/species/unathi/datum/species_bodytypes.dm b/mods/species/unathi/datum/species_bodytypes.dm new file mode 100644 index 000000000000..985523ed2b3b --- /dev/null +++ b/mods/species/unathi/datum/species_bodytypes.dm @@ -0,0 +1,91 @@ +/decl/bodytype/unathi + name = "feminine" + bodytype_category = BODYTYPE_HUMANOID + husk_icon = 'mods/species/unathi/icons/husk.dmi' + icon_base = 'mods/species/unathi/icons/body_female.dmi' + icon_deformed = 'mods/species/unathi/icons/deformed_body_female.dmi' + cosmetics_icon = 'mods/species/unathi/icons/cosmetics.dmi' + blood_overlays = 'icons/mob/human_races/species/human/blood_overlays.dmi' + bandages_icon = 'icons/mob/bandage.dmi' + health_hud_intensity = 2 + associated_gender = FEMALE + onmob_state_modifiers = list((slot_w_uniform_str) = "f") + movement_slowdown = 0.5 + base_color = "#066000" + appearance_flags = HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR + eye_darksight_range = 3 + eye_flash_mod = 1.2 + nail_noun = "claws" + uid = "bodytype_unathi_fem" + footprints_icon = 'mods/species/unathi/icons/footprints.dmi' + + age_descriptor = /datum/appearance_descriptor/age/unathi + + default_sprite_accessories = list( + SAC_FRILLS = list( + /decl/sprite_accessory/frills/unathi/frills_long = list(SAM_COLOR = "#192e19") + ) + ) + + appearance_descriptors = list( + /datum/appearance_descriptor/height = 1.25, + /datum/appearance_descriptor/build = 1.25 + ) + + override_organ_types = list( + BP_EYES = /obj/item/organ/internal/eyes/unathi, + BP_BRAIN = /obj/item/organ/internal/brain/unathi + ) + + override_limb_types = list( + BP_TAIL = /obj/item/organ/external/tail/unathi, + BP_HEAD = /obj/item/organ/external/head/strong_bite, + BP_L_HAND = /obj/item/organ/external/hand/clawed, + BP_R_HAND = /obj/item/organ/external/hand/right/clawed + ) + + cold_level_1 = 280 //Default 260 - Lower is better + cold_level_2 = 220 //Default 200 + cold_level_3 = 130 //Default 120 + + heat_level_1 = 420 //Default 360 - Higher is better + heat_level_2 = 480 //Default 400 + heat_level_3 = 1100 //Default 1000 + + heat_discomfort_level = 320 + heat_discomfort_strings = list( + "You feel soothingly warm.", + "You feel the heat sink into your bones.", + "You feel warm enough to take a nap." + ) + + cold_discomfort_level = 292 + cold_discomfort_strings = list( + "You feel chilly.", + "You feel sluggish and cold.", + "Your scales bristle against the cold." + ) + +/decl/bodytype/unathi/get_default_grooming_results(obj/item/organ/external/limb, obj/item/grooming/tool) + if(tool?.grooming_flags & GROOMABLE_FILE) + return list( + "success" = GROOMING_RESULT_SUCCESS, + "descriptor" = "[limb.name] scales" + ) + return ..() + +/decl/bodytype/unathi/masculine + name = "masculine" + icon_base = 'mods/species/unathi/icons/body_male.dmi' + icon_deformed = 'mods/species/unathi/icons/deformed_body_male.dmi' + associated_gender = MALE + onmob_state_modifiers = null + uid = "bodytype_unathi_masc" + +/obj/item/organ/external/tail/unathi + tail_icon = 'mods/species/unathi/icons/tail.dmi' + tail_animation_states = 9 + +/obj/item/organ/external/tail/unathi/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/tail) + return unarmed_attack diff --git a/mods/species/unathi/datum/sprite_accessory.dm b/mods/species/unathi/datum/sprite_accessory.dm new file mode 100644 index 000000000000..1175142a4caf --- /dev/null +++ b/mods/species/unathi/datum/sprite_accessory.dm @@ -0,0 +1,112 @@ +/decl/sprite_accessory/horns/unathi + name = "Lizard Horns" + icon = 'mods/species/unathi/icons/horns.dmi' + icon_state = "horns" + species_allowed = list(/decl/species/unathi::uid) + color_blend = ICON_MULTIPLY + accessory_flags = HAIR_VERY_SHORT + uid = "acc_hair_una_horns" + +/decl/sprite_accessory/horns/unathi/spines_long + name = "Lizard Spines Long" + icon_state = "spines_long" + uid = "acc_hair_una_longspines" + +/decl/sprite_accessory/horns/unathi/spines_short + name = "Lizard Spines Short" + icon_state = "spines_short" + uid = "acc_hair_una_shortspines" + +/decl/sprite_accessory/horns/unathi/bighorns + name = "Lizard Horns Big" + icon_state = "horns_big" + uid = "acc_hair_una_bighorns" + +/decl/sprite_accessory/horns/unathi/smallhorns + name = "Lizard Horns Small" + icon_state = "horns_small" + uid = "acc_hair_una_smallhorns" + +/decl/sprite_accessory/horns/unathi/shorthorns + name = "Lizard Horns Short" + icon_state = "horns_short" + uid = "acc_hair_una_shorthorns" + +/decl/sprite_accessory/horns/unathi/curledhorns + name = "Lizard Horns Curled" + icon_state = "horns_curled" + uid = "acc_hair_una_curledhorns" + +/decl/sprite_accessory/horns/unathi/ramhorns + name = "Lizard Horns Ram" + icon_state = "horns_ram" + uid = "acc_hair_una_ramhorns" + +/decl/sprite_accessory/horns/unathi/ramhornsthick + name = "Lizard Horns Ram Thick" + icon_state = "horns_ram_thick" + uid = "acc_hair_una_ramhornsthick" + +/decl/sprite_accessory/horns/unathi/doublehorns + name = "Lizard Horns Double" + icon_state = "horns_double" + uid = "acc_hair_una_doublehorns" + +/decl/sprite_accessory/horns/unathi/chin + name = "Lizard Horn Chin" + icon_state = "facial_chinhorns" + uid = "acc_fhair_una_chinhorns" + +/decl/sprite_accessory/horns/unathi/hornadorns + name = "Lizard Horn Adorns" + icon_state = "facial_hornadorns" + uid = "acc_fhair_una_adorns" + +/decl/sprite_accessory/horns/unathi/spinespikes + name = "Lizard Spine Spikes" + icon_state = "facial_spikes" + uid = "acc_fhair_una_spinespikes" + +/decl/sprite_accessory/frills/unathi + name = "Lizard Frills Aqua" + icon = 'mods/species/unathi/icons/frills.dmi' + icon_state = "frills_aqua" + species_allowed = list(/decl/species/unathi::uid) + color_blend = ICON_MULTIPLY + accessory_flags = HAIR_VERY_SHORT + uid = "acc_hair_una_aqua" + +/decl/sprite_accessory/frills/unathi/hood + name = "Lizard Cobra Hood" + icon_state = "cobrahood" + uid = "acc_hair_una_cobra" + +/decl/sprite_accessory/frills/unathi/frills_long + name = "Lizard Frills Long" + icon_state = "frills_long" + uid = "acc_hair_una_longfrills" + +/decl/sprite_accessory/frills/unathi/frills_short + name = "Lizard Frills Short" + icon_state = "frills_short" + uid = "acc_hair_una_shortfrills" + +/decl/sprite_accessory/frills/unathi/sidefrills + name = "Lizard Frills Side" + icon_state = "frills_side" + uid = "acc_hair_una_sidefrills" + +/decl/sprite_accessory/frills/unathi/spinedfrillslong + name = "Lizard Spined Long Frills" + icon_state = "spined_long_frills" + uid = "acc_hair_una_longspinedfrills" + +/decl/sprite_accessory/frills/unathi/spinedfrillsshort + name = "Lizard Spined Short Frills" + icon_state = "spined_short_frills" + uid = "acc_hair_una_shortspinedfrills" + +/decl/sprite_accessory/frills/unathi/dorsalfrill + name = "Lizard Frill Dorsal" + icon_state = "facial_dorsalfrill" + uid = "acc_fhair_una_dorsalfrill" diff --git a/mods/species/unathi/icons/body_female.dmi b/mods/species/unathi/icons/body_female.dmi new file mode 100644 index 000000000000..432be5c4d0a8 Binary files /dev/null and b/mods/species/unathi/icons/body_female.dmi differ diff --git a/mods/species/unathi/icons/body_male.dmi b/mods/species/unathi/icons/body_male.dmi new file mode 100644 index 000000000000..472e079f57c6 Binary files /dev/null and b/mods/species/unathi/icons/body_male.dmi differ diff --git a/mods/species/unathi/icons/cosmetics.dmi b/mods/species/unathi/icons/cosmetics.dmi new file mode 100644 index 000000000000..fb049c6d2ec4 Binary files /dev/null and b/mods/species/unathi/icons/cosmetics.dmi differ diff --git a/mods/species/unathi/icons/deformed_body_female.dmi b/mods/species/unathi/icons/deformed_body_female.dmi new file mode 100644 index 000000000000..effbe1f0e2b5 Binary files /dev/null and b/mods/species/unathi/icons/deformed_body_female.dmi differ diff --git a/mods/species/unathi/icons/deformed_body_male.dmi b/mods/species/unathi/icons/deformed_body_male.dmi new file mode 100644 index 000000000000..6c7d9b9176a6 Binary files /dev/null and b/mods/species/unathi/icons/deformed_body_male.dmi differ diff --git a/mods/species/unathi/icons/eyes.dmi b/mods/species/unathi/icons/eyes.dmi new file mode 100644 index 000000000000..17287396c7f1 Binary files /dev/null and b/mods/species/unathi/icons/eyes.dmi differ diff --git a/mods/species/unathi/icons/footprints.dmi b/mods/species/unathi/icons/footprints.dmi new file mode 100644 index 000000000000..fe21767b108c Binary files /dev/null and b/mods/species/unathi/icons/footprints.dmi differ diff --git a/mods/species/unathi/icons/frills.dmi b/mods/species/unathi/icons/frills.dmi new file mode 100644 index 000000000000..e113ba90c386 Binary files /dev/null and b/mods/species/unathi/icons/frills.dmi differ diff --git a/mods/species/unathi/icons/horns.dmi b/mods/species/unathi/icons/horns.dmi new file mode 100644 index 000000000000..d1728b439b83 Binary files /dev/null and b/mods/species/unathi/icons/horns.dmi differ diff --git a/mods/species/unathi/icons/husk.dmi b/mods/species/unathi/icons/husk.dmi new file mode 100644 index 000000000000..0095263f909e Binary files /dev/null and b/mods/species/unathi/icons/husk.dmi differ diff --git a/mods/species/unathi/icons/organs.dmi b/mods/species/unathi/icons/organs.dmi new file mode 100644 index 000000000000..eb74a5b45f46 Binary files /dev/null and b/mods/species/unathi/icons/organs.dmi differ diff --git a/mods/species/unathi/icons/tail.dmi b/mods/species/unathi/icons/tail.dmi new file mode 100644 index 000000000000..9166281c828c Binary files /dev/null and b/mods/species/unathi/icons/tail.dmi differ diff --git a/mods/species/unathi/organs/organs_internal.dm b/mods/species/unathi/organs/organs_internal.dm new file mode 100644 index 000000000000..307a2cbdbc33 --- /dev/null +++ b/mods/species/unathi/organs/organs_internal.dm @@ -0,0 +1,7 @@ +/obj/item/organ/internal/eyes/unathi + name = "reptilian eyes" + desc = "Eyes belonging to a big lizard. They seem to be staring right at you no matter where you look from." + icon = 'mods/species/unathi/icons/organs.dmi' + +/obj/item/organ/internal/brain/unathi + can_use_brain_interface = FALSE diff --git a/mods/species/unathi/sound/lizard_breathing.ogg b/mods/species/unathi/sound/lizard_breathing.ogg new file mode 100644 index 000000000000..7d5604d3fbcc Binary files /dev/null and b/mods/species/unathi/sound/lizard_breathing.ogg differ diff --git a/mods/species/utility_frames/_utility_frames.dm b/mods/species/utility_frames/_utility_frames.dm new file mode 100644 index 000000000000..ef8f8957c518 --- /dev/null +++ b/mods/species/utility_frames/_utility_frames.dm @@ -0,0 +1,3 @@ +/decl/modpack/utility_frames + name = "Utility Frames" + dreams = list("a utility frame", "rogue machine servitors") diff --git a/mods/species/utility_frames/_utility_frames.dme b/mods/species/utility_frames/_utility_frames.dme new file mode 100644 index 000000000000..23ba8ed7d856 --- /dev/null +++ b/mods/species/utility_frames/_utility_frames.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_UTILITY_FRAMES +#define MODPACK_UTILITY_FRAMES +#include "..\..\content\shackles\_shackles.dme" +// BEGIN_INCLUDE +#include "_utility_frames.dm" +#include "markings.dm" +#include "species.dm" +#include "species_bodytypes.dm" +#include "traits.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/mods/species/utility_frames/icons/body.dmi b/mods/species/utility_frames/icons/body.dmi new file mode 100644 index 000000000000..0f439fd257b7 Binary files /dev/null and b/mods/species/utility_frames/icons/body.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/utility/eyes.dmi b/mods/species/utility_frames/icons/eyes.dmi similarity index 100% rename from icons/mob/human_races/cyberlimbs/utility/eyes.dmi rename to mods/species/utility_frames/icons/eyes.dmi diff --git a/mods/species/utility_frames/icons/markings.dmi b/mods/species/utility_frames/icons/markings.dmi new file mode 100644 index 000000000000..9867444ff91f Binary files /dev/null and b/mods/species/utility_frames/icons/markings.dmi differ diff --git a/mods/species/utility_frames/markings.dm b/mods/species/utility_frames/markings.dm new file mode 100644 index 000000000000..a4700a242c56 --- /dev/null +++ b/mods/species/utility_frames/markings.dm @@ -0,0 +1,46 @@ +/decl/sprite_accessory/marking/frame + name = "Frame Department Stripe" + icon_state = "single_stripe" + body_parts = list(BP_CHEST) + species_allowed = list(/decl/species/utility_frame::uid) + icon = 'mods/species/utility_frames/icons/markings.dmi' + color_blend = ICON_MULTIPLY + uid = "acc_marking_frame_stripe" + +/decl/sprite_accessory/marking/frame/head_stripe + name = "Frame Head Stripe" + icon_state = "head_stripe" + body_parts = list(BP_HEAD) + uid = "acc_marking_frame_stripe_head" + +/decl/sprite_accessory/marking/frame/double_stripe + name = "Frame Department Stripes" + icon_state = "double_stripe" + uid = "acc_marking_frame_stripe_double" + +/decl/sprite_accessory/marking/frame/shoulder_stripe + name = "Frame Shoulder Markings" + icon_state = "shoulder_stripe" + uid = "acc_marking_frame_shoulder" + +/decl/sprite_accessory/marking/frame/plating + name = "Frame Body Plating" + icon_state = "plating" + body_parts = list(BP_GROIN, BP_CHEST) + uid = "acc_marking_frame_plating" + +/decl/sprite_accessory/marking/frame/barcode + name = "Frame Matrix Barcode" + icon_state = "barcode" + body_parts = list(BP_CHEST) + uid = "acc_marking_frame_barcode" + +/decl/sprite_accessory/marking/frame/plating/legs + name = "Frame Leg Plating" + body_parts = list(BP_L_LEG, BP_R_LEG) + uid = "acc_marking_frame_plating_leg" + +/decl/sprite_accessory/marking/frame/plating/head + name = "Frame Head Plating" + body_parts = list(BP_HEAD) + uid = "acc_marking_frame_plating_head" diff --git a/mods/species/utility_frames/species.dm b/mods/species/utility_frames/species.dm new file mode 100644 index 000000000000..193c566a8b01 --- /dev/null +++ b/mods/species/utility_frames/species.dm @@ -0,0 +1,54 @@ +/datum/appearance_descriptor/age/utility_frame + chargen_min_index = 1 + chargen_max_index = 4 + standalone_value_descriptors = list( + "brand new" = 1, + "worn" = 5, + "an older model" = 12, + "nearing end-of-life" = 16, + "entirely obsolete" = 20 + ) + +/decl/species/utility_frame + uid = "species_frame" + name = "Utility Frame" + name_plural = "Utility Frames" + description = "Simple AI-driven robots are used for many menial or repetitive tasks in human space." + cyborg_noun = null + base_external_prosthetics_model = /decl/bodytype/prosthetic/basic_human + blood_types = list(/decl/blood_type/coolant) + available_bodytypes = list(/decl/bodytype/prosthetic/utility_frame) + hidden_from_codex = FALSE + species_flags = SPECIES_FLAG_NO_POISON + spawn_flags = SPECIES_CAN_JOIN + strength = STR_HIGH + warning_low_pressure = 50 + hazard_low_pressure = -1 + flesh_color = COLOR_GUNMETAL + body_temperature = null + passive_temp_gain = 5 // stabilize at ~80 C in a 20 C environment. + blood_volume = 0 + + preview_outfit = null + + available_pronouns = list( + /decl/pronouns/pseudoplural, + /decl/pronouns/neuter + ) + available_background_info = list( + /decl/background_category/citizenship = list(/decl/background_detail/citizenship/synthetic), + /decl/background_category/heritage = list(/decl/background_detail/heritage/synthetic) + ) + + exertion_effect_chance = 10 + exertion_charge_scale = 1 + exertion_emotes_synthetic = list( + /decl/emote/exertion/synthetic, + /decl/emote/exertion/synthetic/creak + ) + +/obj/item/organ/external/head/utility_frame + glowing_eyes = TRUE + +/decl/species/utility_frame/disfigure_msg(var/mob/living/human/H) + . = SPAN_DANGER("The faceplate is dented and cracked!\n") diff --git a/mods/species/utility_frames/species_bodytypes.dm b/mods/species/utility_frames/species_bodytypes.dm new file mode 100644 index 000000000000..ca7be0bfeae8 --- /dev/null +++ b/mods/species/utility_frames/species_bodytypes.dm @@ -0,0 +1,52 @@ +/decl/bodytype/prosthetic/utility_frame + name = "utility frame" + desc = "This limb is extremely cheap and simplistic, with a raw steel frame and plastic casing." + icon_base = 'mods/species/utility_frames/icons/body.dmi' + eye_icon = 'mods/species/utility_frames/icons/eyes.dmi' + bodytype_category = BODYTYPE_HUMANOID + limb_blend = ICON_MULTIPLY + appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR + modular_limb_tier = MODULAR_BODYPART_CYBERNETIC + body_flags = BODY_FLAG_NO_PAIN | BODY_FLAG_NO_DNA | BODY_FLAG_NO_DEFIB | BODY_FLAG_NO_STASIS + base_color = "#333355" + base_eye_color = "#00ccff" + organ_material = /decl/material/solid/metal/steel + vital_organs = list( + BP_BRAIN, + BP_CELL + ) + override_limb_types = list(BP_HEAD = /obj/item/organ/external/head/utility_frame) + has_organ = list( + BP_BRAIN = /obj/item/organ/internal/brain/robotic, + BP_EYES = /obj/item/organ/internal/eyes, + BP_CELL = /obj/item/organ/internal/cell + ) + default_sprite_accessories = list( + SAC_MARKINGS = list( + /decl/sprite_accessory/marking/frame/plating = list(SAM_COLOR = "#8888cc"), + /decl/sprite_accessory/marking/frame/plating/legs = list(SAM_COLOR = "#8888cc"), + /decl/sprite_accessory/marking/frame/plating/head = list(SAM_COLOR = "#8888cc") + ) + ) + age_descriptor = /datum/appearance_descriptor/age/utility_frame + uid = "bodytype_prosthetic_utility_frame" + can_be_shackled = TRUE + +/decl/bodytype/prosthetic/utility_frame/Initialize() + _equip_adjust = list( + (slot_l_ear_str) = list( + "[NORTH]" = list( 2, 0), + "[EAST]" = list( 0, 0), + "[SOUTH]" = list(-2, 0), + "[WEST]" = list( 0, 0) + ), + (slot_r_ear_str) = list( + "[NORTH]" = list(-2, 0), + "[EAST]" = list( 0, 0), + "[SOUTH]" = list( 2, 0), + "[WEST]" = list( 0, 0) + ) + ) + . = ..() + +DEFINE_ROBOLIMB_DESIGNS(/decl/bodytype/prosthetic/utility_frame, utility_frame) diff --git a/mods/species/utility_frames/traits.dm b/mods/species/utility_frames/traits.dm new file mode 100644 index 000000000000..8e1150fce82e --- /dev/null +++ b/mods/species/utility_frames/traits.dm @@ -0,0 +1,29 @@ +/decl/trait/build_references() + . = ..() + LAZYDISTINCTADD(blocked_species, /decl/species/utility_frame::uid) + +/decl/trait/utility_frame + abstract_type = /decl/trait/utility_frame + +/decl/trait/utility_frame/build_references() + . = ..() + blocked_species = null + permitted_species = list(/decl/species/utility_frame::uid) + +// Cosmetic/armour changes, different models of limb +/decl/trait/utility_frame/customisation + name = "Heavy Frame" + description = "Coming soon!" + category = "Frame Customisation" + +// Additional augments, organs, better armour, robomodules +/decl/trait/utility_frame/upgrade + name = "Upgraded Widget" + description = "Coming soon!" + category = "Upgrades" + +// Various maluses +/decl/trait/utility_frame/fault + name = "Faulty Widget" + description = "Coming soon!" + category = "Faults" diff --git a/mods/species/vox/_vox.dm b/mods/species/vox/_vox.dm new file mode 100644 index 000000000000..dcf6527797dd --- /dev/null +++ b/mods/species/vox/_vox.dm @@ -0,0 +1,27 @@ +#define BODYTYPE_VOX "reptoavian body" +#define BODYTYPE_VOX_LARGE "large reptoavian body" +// Internal organs +#define BP_HINDTONGUE "hindtongue" +#define BP_VOXSTACK "vox stack" +// Bodytype equip flags +#define BODY_EQUIP_FLAG_VOX BITFLAG(8) + +/decl/modpack/vox + name = "Vox Content" + dreams = list("a red stool", "a vox raider") + credits_crew_names = list("THE VOX") + credits_topics = list("VOX RITUAL DUELS", "NECK MARKINGS", "ANCIENT SUPERCOMPUTERS") + +/mob/living/human/vox/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + SET_HAIR_STYLE(src, /decl/sprite_accessory/hair/vox/short, TRUE) + SET_HAIR_COLOR(src, COLOR_BEASTY_BROWN, TRUE) + species_uid = /decl/species/vox::uid + . = ..() + +/datum/follow_holder/voxstack + sort_order = 14 + followed_type = /obj/item/organ/internal/voxstack + +/datum/follow_holder/voxstack/show_entry() + var/obj/item/organ/internal/voxstack/S = followed_instance + return ..() && !S.owner diff --git a/mods/species/vox/_vox.dme b/mods/species/vox/_vox.dme new file mode 100644 index 000000000000..0e0e635d99b4 --- /dev/null +++ b/mods/species/vox/_vox.dme @@ -0,0 +1,33 @@ +#ifndef MODPACK_VOX +#define MODPACK_VOX +// BEGIN_INCLUDE +#include "_vox.dm" +#include "mobs_vox.dm" +#include "organs_vox.dm" +#include "datum\accessories.dm" +#include "datum\cultures_vox.dm" +#include "datum\descriptors_vox.dm" +#include "datum\factions_vox.dm" +#include "datum\language.dm" +#include "datum\locations_vox.dm" +#include "datum\outfits.dm" +#include "datum\religions_vox.dm" +#include "datum\robolimbs.dm" +#include "datum\species.dm" +#include "datum\species_bodytypes.dm" +#include "datum\trader.dm" +#include "datum\traits.dm" +#include "datum\unit_testing.dm" +#include "gear\gear.dm" +#include "gear\gear_gloves.dm" +#include "gear\gear_head.dm" +#include "gear\gear_mask.dm" +#include "gear\gear_rig.dm" +#include "gear\gear_shoes.dm" +#include "gear\gear_suit.dm" +#include "gear\gear_under.dm" +#include "gear\gun.dm" +#include "gear\gun_slugsling.dm" +#include "gear\gun_spikethrower.dm" +// END_INCLUDE +#endif diff --git a/mods/species/vox/datum/accessories.dm b/mods/species/vox/datum/accessories.dm new file mode 100644 index 000000000000..f0889543cbb7 --- /dev/null +++ b/mods/species/vox/datum/accessories.dm @@ -0,0 +1,75 @@ +/decl/sprite_accessory/hair/vox + name = "Long Vox Quills" + icon = 'mods/species/vox/icons/body/soldier/hair.dmi' + icon_state = "vox_longquills" + species_allowed = list(/decl/species/vox::uid) + uid = "acc_hair_vox_longquills" + +/decl/sprite_accessory/hair/vox/get_accessory_icon(obj/item/organ/external/organ) + var/decl/bodytype/vox/voxtype = organ.bodytype + if(istype(voxtype)) + return voxtype.vox_hair_icon + return ..() + +/decl/sprite_accessory/hair/vox/short + name = "Short Vox Quills" + icon_state = "vox_shortquills" + uid = "acc_hair_vox_shortquills" + +/decl/sprite_accessory/hair/vox/mohawk + name = "Vox Mohawk" + icon_state = "vox_mohawk" + uid = "acc_hair_vox_mohawk" + +/decl/sprite_accessory/hair/vox/stubble + name = "Vox Stubble" + icon_state = "vox_stubble" + uid = "acc_hair_vox_stubble" + +/decl/sprite_accessory/marking/vox + name = "Vox Neck Markings" + icon_state = "neck_markings" + body_parts = list(BP_HEAD) + species_allowed = list(/decl/species/vox::uid) + icon = 'mods/species/vox/icons/body/soldier/markings.dmi' + color_blend = ICON_MULTIPLY + uid = "acc_markings_vox_neck" + +/decl/sprite_accessory/marking/vox/get_accessory_icon(obj/item/organ/external/organ) + var/decl/bodytype/vox/voxtype = organ.bodytype + if(istype(voxtype)) + return voxtype.vox_marking_icon + return ..() + +/decl/sprite_accessory/marking/vox/claws + name = "Vox Claws" + icon_state = "claws" + body_parts = list(BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT, BP_CHEST) + uid = "acc_markings_vox_claws" + +/decl/sprite_accessory/marking/vox/beak + name = "Vox Beak" + icon_state = "beak" + uid = "acc_markings_vox_beak" + +/decl/sprite_accessory/marking/vox/scutes + name = "Vox Scutes" + icon_state = "scutes" + body_parts = list(BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT) + uid = "acc_markings_vox_scutes" + +/decl/sprite_accessory/marking/vox/arm_markings + name = "Vox Arm Markings (Left)" + icon_state = "arm_markings" + body_parts = list(BP_L_ARM) + uid = "acc_markings_vox_leftarm" + +/decl/sprite_accessory/marking/vox/arm_markings/right + name = "Vox Arm Markings (Right)" + body_parts = list(BP_R_ARM) + uid = "acc_markings_vox_rightarm" + +/decl/sprite_accessory/marking/vox/crest + name = "Vox Crest Colouration" + icon_state = "crest" + uid = "acc_markings_vox_crest" diff --git a/mods/species/vox/datum/cultures_vox.dm b/mods/species/vox/datum/cultures_vox.dm new file mode 100644 index 000000000000..a792c12c5117 --- /dev/null +++ b/mods/species/vox/datum/cultures_vox.dm @@ -0,0 +1,26 @@ +/decl/background_detail/heritage/vox + name = "Arkborn Vox" + description = "The vast majority of vox are born and die on the enormous moon-sized arkships that form the only \ + permanent home any of the creatures have. Tending to the vast, decaying vessels is a full-time job for crews of thousands, \ + and although the glamour and allure of the raider life appeals to many, staying home is seen as a more responsible and mature \ + pursuit than haring off across the stars to attack the meat and steal their goods." + hidden_from_codex = TRUE + language = /decl/language/vox + secondary_langs = list(/decl/language/human/common) + uid = "heritage_vox_arkborn" + +/decl/background_detail/heritage/vox/salvager + name = "Vox Salvager" + description = "The arkships, vast as they are, could not survive without the ceaseless efforts of the salvage crews \ + that strip-mine asteroids, stations and ships for the raw materials needed to keep things together. Although it is a \ + much less lethal pursuit than being a raider, salvagers have a dangerous job and often do not make it back to the ark \ + in one piece." + uid = "heritage_vox_salvager" + +/decl/background_detail/heritage/vox/raider + name = "Vox Raider" + description = "Amongst the vox, the prestige of being a raider is second only to working directly for an apex. They are \ + the cutting talon of the vox and the dashing, charismatic figures of adventure that serve as examples for fresh hatchlings \ + and ambitious labourers. Many raiders end up in positions of authority and power amid the ramshackle social structures of \ + the arkships, though as always they remain under the authority of the local apex." + uid = "heritage_vox_raider" diff --git a/mods/species/vox/datum/descriptors_vox.dm b/mods/species/vox/datum/descriptors_vox.dm new file mode 100644 index 000000000000..78b0e6a2c5b7 --- /dev/null +++ b/mods/species/vox/datum/descriptors_vox.dm @@ -0,0 +1,35 @@ +/datum/appearance_descriptor/vox_markings + name = "neck markings" + chargen_label = "neck markings (rank)" + skip_species_mention = TRUE + standalone_value_descriptors = list( + "very simplistic", + "rather simple", + "complex", + "moderately complex", + "bewilderingly complex" + ) + chargen_value_descriptors = list( + "servitor" = 1, + "labourer" = 2, + "cannon fodder" = 3, + "raider" = 4, + "leader" = 5 + ) + comparative_value_descriptor_equivalent = "around the same importance as yours" + comparative_value_descriptors_smaller = list( + "slightly less important than yours", + "much less important than yours", + "insignificant and beneath your notice" + ) + comparative_value_descriptors_larger = list( + "slightly more important than yours", + "much more important than yours", + "commanding your unquestioning obedience and respect" + ) + +/datum/appearance_descriptor/vox_markings/get_first_person_message_start() + . = "Your neck markings are" + +/datum/appearance_descriptor/vox_markings/get_third_person_message_start(var/decl/pronouns/my_gender) + . = "[my_gender.His] neck markings are" diff --git a/mods/species/vox/datum/factions_vox.dm b/mods/species/vox/datum/factions_vox.dm new file mode 100644 index 000000000000..1fbf82597989 --- /dev/null +++ b/mods/species/vox/datum/factions_vox.dm @@ -0,0 +1,27 @@ +/decl/background_detail/faction/vox + name = "Shoal Crew" + description = "Most vox are content to live and work on the arkships, serving their alloted span under the watchful \ + eye of their betters, who in turn serve the apex. Although there is always some degree of social turmoil amongst the \ + ark families, with contests and challenges resulting in shifting hierarchies, it usually does not go any further than \ + the general day-to-day energy exhibited by all vox. The average ark labourer is not ambitious, and knows things could \ + be a lot worse." + hidden_from_codex = TRUE + uid = "faction_vox_shoal" + +/decl/background_detail/faction/vox/raider + name = "Vox Raider" + description = "Vox raiders are known for their restless energy, their cruelty, and their ambition, even amongst their \ + own people. A successful raider can look forward to heightened social standing and personal power upon their triumphant \ + return to the ark, but an unsuccessful raider enjoys only death or shame; it follows that experienced raiders are vicious, \ + callous killers and thieves with a discerning eye for when to fight and when to flee." + uid = "faction_vox_raider" + +/decl/background_detail/faction/vox/apex + name = "Apex-Curated" + description = "It is rare, but not completely unheard of, for the apex to take a direct hand in the lives of \ + their 'children'. Those vox who are singled out and marked by the machine-gods of the ark enjoy a heightened social \ + standing, as they are seen as 'untouchable' in a way, but in turn are detached from their previous social network. \ + Being god-touched is lonely work and often backbreakingly difficult, but it is not without rewards. Physical and mental \ + augmentation, ancient auralis technology and mind-enhancing persona editing may all be distributed by the apex to their \ + favoured pawns." + uid = "faction_vox_apex" diff --git a/mods/species/vox/datum/language.dm b/mods/species/vox/datum/language.dm new file mode 100644 index 000000000000..a5729749f617 --- /dev/null +++ b/mods/species/vox/datum/language.dm @@ -0,0 +1,26 @@ +/decl/language/vox + name = "Vox-Pidgin" + desc = "The common tongue of the various Vox ships making up the Shoal. It sounds like chaotic shrieking to everyone else." + speech_verb = "shrieks" + ask_verb = "creels" + exclaim_verb = "SHRIEKS" + colour = "vox" + key = "x" + flags = LANG_FLAG_WHITELISTED + syllables = list("ti","ti","ti","hi","hi","ki","ki","ki","ki","ya","ta","ha","ka","ya","chi","cha","kah", \ + "SKRE","AHK","EHK","RAWK","KRA","AAA","EEE","KI","II","KRI","KA") + machine_understands = 0 + shorthand = "Vox" + +/decl/language/vox/can_speak_special(var/mob/speaker) + if(!ishuman(speaker)) + return FALSE + var/mob/living/human/H = speaker + var/obj/item/organ/internal/tongue = GET_INTERNAL_ORGAN(H, BP_HINDTONGUE) + if(!istype(tongue) || !tongue.is_usable()) + to_chat(speaker, SPAN_WARNING("You are not capable of speaking [name]!")) + return FALSE + return TRUE + +/decl/language/vox/get_random_language_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) + return ..(FEMALE,1,6) diff --git a/mods/species/vox/datum/locations_vox.dm b/mods/species/vox/datum/locations_vox.dm new file mode 100644 index 000000000000..69a7f3a3170a --- /dev/null +++ b/mods/species/vox/datum/locations_vox.dm @@ -0,0 +1,29 @@ +/decl/background_detail/location/vox + name = "Vox Arkship" + description = "The moon-sized arkships are home to the vast, vast majority of vox, and represent the closest thing to \ + a stable planetary culture the far-flung nomadic species has. Arkborn vox can expect to enjoy long lives, infrequent \ + re-embodiment, and a rich and varied social life amongst the rambunctious ark clans and families. Raiders and salvagers \ + may look upon the arkborn as lazy and passive, but they tend to return to them for rest and recuperation after each \ + mission without too many complaints." + ruling_body = "the Apex" + distance = "multiple systems" + hidden_from_codex = TRUE + uid = "location_vox_ark" + +/decl/background_detail/location/vox/shroud + name = "Arkship Shroud" + description = "The shroud of an arkship is an unstable and dangerous place to live, and those vox stationed there are \ + often salvagers, scavengers, engineers and technicians, struggling with the endless burden of keeping the decay of the ark \ + from progressing beyond the shroud and into more critical systems. By comparison to arkborn, they are quiet, self-supporting and \ + independant, with few cares for clan politics, family squabbles, or contest challenges. They know their task is critical to \ + the survival of the vox as a species, and next to that, tussling with your peers seems a bit immature." + uid = "location_vox_shroud" + +/decl/background_detail/location/vox/ship + name = "Vox Ship" + description = "Shipborn vox are often purpose-grown for their assigned tasks, frequently under the direct supervision of \ + an apex or their servants. They are often seen as 'disposable' in vox culture, as they rarely survive their incarnation \ + beyond the tour of the vessel. Those that do, however, are generally thrown straight back into long-distance shipside \ + duties, as their success shows their masters that they are well suited to it. The life of a shipborn vox is arduous and \ + bloody, and they will be killed and reborn more often than even the most reckless of arkborn raiders." + uid = "location_vox_ship" diff --git a/mods/species/vox/datum/outfits.dm b/mods/species/vox/datum/outfits.dm new file mode 100644 index 000000000000..f5ab5f436f0a --- /dev/null +++ b/mods/species/vox/datum/outfits.dm @@ -0,0 +1,40 @@ +/decl/outfit/vox + abstract_type = /decl/outfit/vox + mask = /obj/item/clothing/mask/gas/swat/vox + back = /obj/item/tank/nitrogen + uniform = /obj/item/clothing/suit/robe/vox + shoes = /obj/item/clothing/shoes/magboots/vox + gloves = /obj/item/clothing/gloves/vox + var/list/glasses_types + var/list/holster_types + +/decl/outfit/vox/equip_outfit(mob/living/wearer, assignment, equip_adjustments, datum/job/job, datum/mil_rank/rank) + uniform = pick(/obj/item/clothing/suit/robe/vox, /obj/item/clothing/pants/vox) + if(length(glasses_types)) + glasses = pick(glasses_types) + if(length(holster_types)) + holster = pick(holster_types) + . = ..() + wearer.set_internals(locate(/obj/item/tank) in wearer.contents) + +/decl/outfit/vox/survivor + name = "Job - Vox Survivor" + +/decl/outfit/vox/raider + name = "Job - Vox Raider" + l_ear = /obj/item/radio/headset/raider + glasses = /obj/item/clothing/glasses/thermal + holster = /obj/item/clothing/webbing/holster/armpit + suit_store = /obj/item/flashlight + hands = list(/obj/item/gun/launcher/alien/spikethrower) + id_type = /obj/item/card/id/syndicate + holster_types = list( + /obj/item/clothing/webbing/holster/armpit, + /obj/item/clothing/webbing/holster/waist, + /obj/item/clothing/webbing/holster/hip + ) + glasses_types = list( + /obj/item/clothing/glasses/thermal, + /obj/item/clothing/glasses/thermal/plain/eyepatch, + /obj/item/clothing/glasses/thermal/plain/monocle + ) diff --git a/mods/species/vox/datum/religions_vox.dm b/mods/species/vox/datum/religions_vox.dm new file mode 100644 index 000000000000..af6b14190f27 --- /dev/null +++ b/mods/species/vox/datum/religions_vox.dm @@ -0,0 +1,5 @@ +/decl/background_detail/religion/vox + name = "Auralis Reverence" + description = "Obey and revere the auralis, those who came before, for they will open the way." + hidden_from_codex = TRUE + uid = "religion_vox" diff --git a/mods/species/vox/datum/robolimbs.dm b/mods/species/vox/datum/robolimbs.dm new file mode 100644 index 000000000000..1a78f3449fa2 --- /dev/null +++ b/mods/species/vox/datum/robolimbs.dm @@ -0,0 +1,12 @@ +/decl/bodytype/prosthetic/vox + name = "Arkmade" + icon_base = 'mods/species/vox/icons/body/primalis_cyberlimbs.dmi' + bodytype_category = BODYTYPE_VOX + uid = "bodytype_prosthetic_vox" + +/decl/bodytype/prosthetic/vox/crap + name = "Improvised" + icon_base = 'mods/species/vox/icons/body/improvised_cyberlimbs.dmi' + uid = "bodytype_prosthetic_vox_crap" + +DEFINE_ROBOLIMB_MODEL_TRAITS(/decl/bodytype/prosthetic/vox, arkmade, 2, "vox") diff --git a/mods/species/vox/datum/species.dm b/mods/species/vox/datum/species.dm new file mode 100644 index 000000000000..07b969c16b04 --- /dev/null +++ b/mods/species/vox/datum/species.dm @@ -0,0 +1,213 @@ +/datum/appearance_descriptor/age/vox + chargen_min_index = 3 + chargen_max_index = 6 + standalone_value_descriptors = list( + "freshly spawned" = 1, + "a larva" = 2, + "a juvenile" = 5, + "an adolescent" = 8, + "an adult" = 12, + "senescent" = 50, + "withered" = 65 + ) + +/decl/blood_type/vox + name = "vox ichor" + antigen_category = "vox" + splatter_name = "ichor" + splatter_desc = "A smear of thin, sticky alien ichor." + splatter_colour = "#2299fc" + transfusion_fail_reagent = /decl/material/gas/ammonia + +/decl/species/vox + uid = "species_vox" + name = "Vox" + name_plural = "Vox" + base_external_prosthetics_model = /decl/bodytype/prosthetic/vox/crap + + default_emotes = list( + /decl/emote/audible/vox_shriek + ) + + inherent_verbs = list( + /mob/living/human/proc/toggle_vox_pressure_seal + ) + + rarity_value = 4 + + description = {"The Vox are the broken remnants of a once-proud race, now reduced to little more + than scavenging vermin who prey on isolated stations, ships or planets to keep their own ancient + arkships alive. They are four to five feet tall, reptillian, beaked, tailed and quilled; human + crews often refer to them as 'shitbirds' for their violent and offensive nature, as well as their + horrible smell. +

    + Most humans will never meet a Vox raider, instead learning of this insular species through dealing + with their traders and merchants; those that do rarely enjoy the experience."} + + codex_description = {"The Vox are a hostile, deeply untrustworthy species from the edges of human + space. They prey on isolated stations, ships or settlements without any apparent logic or reason, + and tend to refuse communications or negotiations except when their backs are to the wall or they + are in dire need of resources. They are four to five feet tall, reptillian, beaked, tailed and + quilled."} + + scream_verb_1p = "shriek" + scream_verb_3p = "shrieks" + + hidden_from_codex = FALSE + + taste_sensitivity = TASTE_DULL + speech_sounds = list('sound/voice/shriek1.ogg') + speech_chance = 20 + + preview_outfit = /decl/outfit/vox/raider + + gluttonous = GLUT_TINY|GLUT_ITEM_NORMAL + stomach_capacity = 12 + + breath_type = /decl/material/gas/nitrogen + poison_types = list(/decl/material/gas/oxygen = TRUE) + shock_vulnerability = 0.2 + + spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED + + blood_types = list(/decl/blood_type/vox) + flesh_color = "#808d11" + + maneuvers = list(/decl/maneuver/leap/grab) + standing_jump_range = 5 + + available_pronouns = list( + /decl/pronouns/neuter, + /decl/pronouns/neuter/person, + /decl/pronouns/pseudoplural, + /decl/pronouns/male, + /decl/pronouns/female + ) + // Add when clothing is available: /decl/bodytype/vox/stanchion + available_bodytypes = list( + /decl/bodytype/vox, + /decl/bodytype/vox/servitor, + /decl/bodytype/vox/servitor/alchemist, + ) + + available_background_info = list( + /decl/background_category/citizenship = list( + /decl/background_detail/citizenship/other + ), + /decl/background_category/heritage = list( + /decl/background_detail/heritage/vox, + /decl/background_detail/heritage/vox/salvager, + /decl/background_detail/heritage/vox/raider + ), + /decl/background_category/homeworld = list( + /decl/background_detail/location/vox, + /decl/background_detail/location/vox/shroud, + /decl/background_detail/location/vox/ship + ), + /decl/background_category/faction = list( + /decl/background_detail/faction/vox, + /decl/background_detail/faction/vox/raider, + /decl/background_detail/faction/vox/apex + ), + /decl/background_category/religion = list( + /decl/background_detail/religion/vox + ) + ) + + exertion_effect_chance = 10 + exertion_hydration_scale = 1 + exertion_charge_scale = 1 + exertion_reagent_scale = 1 + exertion_reagent_path = /decl/material/liquid/lactate + exertion_emotes_biological = list( + /decl/emote/exertion/biological, + /decl/emote/exertion/biological/breath, + /decl/emote/exertion/biological/pant + ) + exertion_emotes_synthetic = list( + /decl/emote/exertion/synthetic, + /decl/emote/exertion/synthetic/creak + ) + +/decl/species/vox/equip_survival_gear(mob/living/wearer, box_type = /obj/item/box/survival) + wearer.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/vox(wearer), slot_wear_mask_str) + var/obj/item/backpack/backpack = wearer.get_equipped_item(slot_back_str) + if(istype(backpack)) + wearer.equip_to_slot_or_del(new /obj/item/box/vox(backpack), slot_in_backpack_str) + var/obj/item/tank/nitrogen/tank = new(wearer) + wearer.equip_to_slot_or_del(tank, BP_R_HAND) + if(tank) + wearer.set_internals(tank) + else + wearer.equip_to_slot_or_del(new /obj/item/tank/nitrogen(wearer), slot_back_str) + wearer.equip_to_slot_or_del(new /obj/item/box/vox(wearer), BP_R_HAND) + wearer.set_internals(backpack) + +// Ideally this would all be on bodytype, but pressure is handled per-mob currently. +var/global/list/vox_current_pressure_toggle = list() + +/decl/species/vox/disfigure_msg(var/mob/living/human/H) + var/decl/pronouns/pronouns = H.get_pronouns() + return SPAN_DANGER("[pronouns.His] beak-segments are cracked and chipped beyond recognition!\n") + +/decl/species/vox/skills_from_age(age) + . = 8 + +/decl/species/vox/handle_death(var/mob/living/human/H) + ..() + var/obj/item/organ/internal/voxstack/stack = H.get_organ(BP_VOXSTACK, /obj/item/organ/internal/voxstack) + if (stack) + stack.do_backup() + +/decl/emote/audible/vox_shriek + key = "shriek" + emote_message_3p = "$USER$ SHRIEKS!" + emote_sound = 'mods/species/vox/sounds/shriek1.ogg' + +/decl/species/vox/get_warning_low_pressure(var/mob/living/human/H) + if(H && global.vox_current_pressure_toggle["\ref[H]"]) + return 50 + return ..() + +/decl/species/vox/get_hazard_low_pressure(var/mob/living/human/H) + if(H && global.vox_current_pressure_toggle["\ref[H]"]) + return 0 + return ..() + +/mob/living/human/proc/toggle_vox_pressure_seal() + set name = "Toggle Vox Pressure Seal" + set category = "Abilities" + set src = usr + + if(!istype(species, /decl/species/vox)) + verbs -= /mob/living/human/proc/toggle_vox_pressure_seal + return + + if(incapacitated(INCAPACITATION_KNOCKOUT)) + to_chat(src, SPAN_WARNING("You are in no state to do that.")) + return + + var/decl/pronouns/pronouns = get_pronouns() + visible_message(SPAN_NOTICE("\The [src] begins flexing and realigning [pronouns.his] scaling...")) + if(!do_after(src, 2 SECONDS, src, FALSE)) + visible_message( + SPAN_NOTICE("\The [src] ceases adjusting [pronouns.his] scaling."), + self_message = SPAN_WARNING("You must remain still to seal or unseal your scaling.")) + return + + if(incapacitated(INCAPACITATION_KNOCKOUT)) + to_chat(src, SPAN_WARNING("You are in no state to do that.")) + return + + // TODO: maybe add cold and heat thresholds to this. + var/my_ref = "\ref[src]" + if((global.vox_current_pressure_toggle[my_ref] = !global.vox_current_pressure_toggle[my_ref])) + visible_message( + SPAN_NOTICE("\The [src]'s scaling flattens and smooths out."), + self_message = SPAN_NOTICE("You flatten your scaling and inflate internal bladders, protecting yourself against low pressure at the cost of dexterity.") + ) + else + visible_message( + SPAN_NOTICE("\The [src]'s scaling bristles roughly."), + self_message = SPAN_NOTICE("You bristle your scaling and deflate your internal bladders, restoring mobility but leaving yourself vulnerable to low pressure.") + ) diff --git a/mods/species/vox/datum/species_bodytypes.dm b/mods/species/vox/datum/species_bodytypes.dm new file mode 100644 index 000000000000..c74d02b11967 --- /dev/null +++ b/mods/species/vox/datum/species_bodytypes.dm @@ -0,0 +1,187 @@ +/decl/bodytype/vox + name = "soldier voxform" + bodytype_category = BODYTYPE_VOX + icon_base = 'mods/species/vox/icons/body/soldier/body.dmi' + icon_deformed = 'mods/species/vox/icons/body/deformed_body.dmi' + husk_icon = 'mods/species/vox/icons/body/husk.dmi' + blood_overlays = 'mods/species/vox/icons/body/blood_overlays.dmi' + eye_icon = 'mods/species/vox/icons/body/soldier/eyes.dmi' + bodytype_flag = BODY_EQUIP_FLAG_VOX + limb_blend = ICON_MULTIPLY + eye_blend = ICON_MULTIPLY + appearance_flags = HAS_EYE_COLOR | HAS_SKIN_COLOR + base_eye_color = "#d60093" + base_color = "#526d29" + body_flags = BODY_FLAG_NO_DNA + age_descriptor = /datum/appearance_descriptor/age/vox + cold_level_1 = 80 + cold_level_2 = 50 + cold_level_3 = -1 + uid = "bodytype_vox" + + appearance_descriptors = list( + /datum/appearance_descriptor/height = 0.75, + /datum/appearance_descriptor/build = 1.25, + /datum/appearance_descriptor/vox_markings = 1 + ) + + vital_organs = list( + BP_VOXSTACK, + BP_BRAIN + ) + override_limb_types = list( + BP_GROIN = /obj/item/organ/external/groin/vox, + BP_TAIL = /obj/item/organ/external/tail/vox, + BP_L_HAND = /obj/item/organ/external/hand/vox, + BP_R_HAND = /obj/item/organ/external/hand/right/vox, + BP_HEAD = /obj/item/organ/external/head/strong_bite + ) + + has_organ = list( + BP_STOMACH = /obj/item/organ/internal/stomach/vox, + BP_HEART = /obj/item/organ/internal/heart/vox, + BP_LUNGS = /obj/item/organ/internal/lungs/vox, + BP_LIVER = /obj/item/organ/internal/liver/vox, + BP_KIDNEYS = /obj/item/organ/internal/kidneys/vox, + BP_BRAIN = /obj/item/organ/internal/brain, + BP_EYES = /obj/item/organ/internal/eyes/vox, + BP_VOXSTACK = /obj/item/organ/internal/voxstack, + BP_HINDTONGUE = /obj/item/organ/internal/hindtongue + ) + default_sprite_accessories = list( + SAC_HAIR = list( + /decl/sprite_accessory/hair/vox/short = list(SAM_COLOR = "#160900") + ), + SAC_MARKINGS = list( + /decl/sprite_accessory/marking/vox/beak = list(SAM_COLOR = "#bc7d3e"), + /decl/sprite_accessory/marking/vox/scutes = list(SAM_COLOR = "#bc7d3e"), + /decl/sprite_accessory/marking/vox/crest = list(SAM_COLOR = "#bc7d3e"), + /decl/sprite_accessory/marking/vox/claws = list(SAM_COLOR = "#a0a654") + ) + ) + + var/icon/vox_hair_icon = 'mods/species/vox/icons/body/soldier/hair.dmi' + var/icon/vox_marking_icon = 'mods/species/vox/icons/body/soldier/markings.dmi' + +/decl/bodytype/vox/Initialize() + if(!length(_equip_adjust)) + _equip_adjust = list( + (BP_L_HAND) = list( + "[NORTH]" = list(0, -2), + "[EAST]" = list(0, -2), + "[SOUTH]" = list( 0, -2), + "[WEST]" = list( 0, -2) + ), + (BP_R_HAND) = list( + "[NORTH]" = list(0, -2), + "[EAST]" = list(0, -2), + "[SOUTH]" = list( 0, -2), + "[WEST]" = list( 0, -2) + ), + (slot_head_str) = list( + "[NORTH]" = list(0, -2), + "[EAST]" = list(3, -2), + "[SOUTH]" = list( 0, -2), + "[WEST]" = list(-3, -2) + ), + (slot_wear_mask_str) = list( + "[NORTH]" = list(0, 0), + "[EAST]" = list(4, 0), + "[SOUTH]" = list( 0, 0), + "[WEST]" = list(-4, 0) + ), + (slot_wear_suit_str) = list( + "[NORTH]" = list(0, -1), + "[EAST]" = list(0, -1), + "[SOUTH]" = list( 0, -1), + "[WEST]" = list( 0, -1) + ), + (slot_w_uniform_str) = list( + "[NORTH]" = list(0, -1), + "[EAST]" = list(0, -1), + "[SOUTH]" = list( 0, -1), + "[WEST]" = list( 0, -1) + ), + (slot_underpants_str) = list( + "[NORTH]" = list(0, -1), + "[EAST]" = list(0, -1), + "[SOUTH]" = list( 0, -1), + "[WEST]" = list( 0, -1) + ), + (slot_undershirt_str) = list( + "[NORTH]" = list(0, -1), + "[EAST]" = list(0, -1), + "[SOUTH]" = list( 0, -1), + "[WEST]" = list( 0, -1) + ), + (slot_back_str) = list( + "[NORTH]" = list(0, 0), + "[EAST]" = list(3, 0), + "[SOUTH]" = list( 0, 0), + "[WEST]" = list(-3, 0) + ) + ) + return ..() + +/decl/bodytype/vox/get_movement_slowdown(var/mob/living/human/H) + if(H && global.vox_current_pressure_toggle["\ref[H]"]) + return 1.5 + return ..() + +/decl/bodytype/vox/servitor + name = "servitor voxform" + bodytype_category = BODYTYPE_HUMANOID + icon_base = 'mods/species/vox/icons/body/servitor/body.dmi' + icon_deformed = 'mods/species/vox/icons/body/deformed_body.dmi' + husk_icon = 'mods/species/vox/icons/body/husk.dmi' + blood_overlays = 'mods/species/vox/icons/body/blood_overlays.dmi' + eye_icon = 'mods/species/vox/icons/body/servitor/eyes.dmi' + uid = "bodytype_vox_servitor" + override_limb_types = list( + BP_GROIN = /obj/item/organ/external/groin/vox, + BP_TAIL = /obj/item/organ/external/tail/vox/servitor + ) + vox_hair_icon = 'mods/species/vox/icons/body/servitor/hair.dmi' + vox_marking_icon = 'mods/species/vox/icons/body/servitor/markings.dmi' + +/decl/bodytype/vox/stanchion + name = "stanchion voxform" + bodytype_category = BODYTYPE_VOX_LARGE + // TODO: should the extra big guys really have the same bodytype equip flags as the little guys? + blood_overlays = 'mods/species/vox/icons/body/stanchion/blood_overlays.dmi' + damage_overlays = 'mods/species/vox/icons/body/stanchion/damage_overlays.dmi' + icon_base = 'mods/species/vox/icons/body/stanchion/body.dmi' + eye_icon = 'mods/species/vox/icons/body/stanchion/eyes.dmi' + icon_template = 'mods/species/vox/icons/body/stanchion/template.dmi' + uid = "bodytype_vox_stanchion" + override_limb_types = list( + BP_GROIN = /obj/item/organ/external/groin/vox, + // Commenting this out so that tail validation doesn't try to find a species using this bodytype. + //BP_TAIL = /obj/item/organ/external/tail/vox/stanchion + ) + vox_hair_icon = 'mods/species/vox/icons/body/stanchion/hair.dmi' + vox_marking_icon = 'mods/species/vox/icons/body/stanchion/markings.dmi' + +/decl/bodytype/vox/servitor/alchemist + name = "alchemist voxform" + icon_base = 'mods/species/vox/icons/body/servitor/body_alchemist.dmi' + eye_icon = 'mods/species/vox/icons/body/servitor/eyes_alchemist.dmi' + uid = "bodytype_vox_alchemist" + +/obj/item/organ/external/tail/vox + tail_icon = 'mods/species/vox/icons/body/soldier/body.dmi' + tail_blend = ICON_MULTIPLY + +/obj/item/organ/external/tail/vox/servitor + tail_icon = 'mods/species/vox/icons/body/servitor/body.dmi' + +/obj/item/organ/external/tail/vox/stanchion + tail_icon = 'mods/species/vox/icons/body/stanchion/body.dmi' + +/obj/item/organ/external/hand/vox/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/gloves) + return unarmed_attack + +/obj/item/organ/external/hand/right/vox/get_natural_attacks() + var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws/strong/gloves) + return unarmed_attack diff --git a/mods/species/vox/datum/trader.dm b/mods/species/vox/datum/trader.dm new file mode 100644 index 000000000000..b73bf61ae6b6 --- /dev/null +++ b/mods/species/vox/datum/trader.dm @@ -0,0 +1,92 @@ +/datum/trader/ship/vox + typical_duration = 60 + origin = "UNREGISTERED VESSEL" + name_language = /decl/language/vox + compliment_increase = 0 + trade_flags = TRADER_GOODS | TRADER_BRIBABLE + blacklisted_trade_items = null + + speech = list( + TRADER_HAIL_GENERIC = "SKREEE! We will trade good stuff, yes?", + TRADER_HAIL_DENY = "Trade closed, GO AWAY!", + TRADER_TRADE_COMPLETE = "Yes, kikikikikiki! You will not regret this trade!", + TRADER_NO_MONEY = "Money? It does not need money. GOODS! Give it GOODS!", + TRADER_NOT_ENOUGH = "It wants MORE for that. Give it more.", + TRADER_HOW_MUCH = "You give it something worth VALUE, yes?", + TRADER_WHAT_WANT = "It wants", + TRADER_COMPLIMENT_DENY = "No.", + TRADER_COMPLIMENT_ACCEPT = "Kikikikiki! Trade is better than talk, yes?", + TRADER_INSULT_GOOD = "Bah! Why does it have to deal with you?", + TRADER_INSULT_BAD = "All you meat is the same! Fuck the off!", + TRADER_BRIBE_ACCEPT = "Skhhhhhk... fine. " + TRADER_TOKEN_TIME + " minutes, no more!", + TRADER_BRIBE_REFUSAL = "No! It is getting impatient with this meat!" + ) + + var/hailed_vox = FALSE //Whether we have been hailed by a vox. negatives mean pariah, positives mean regular. + var/list/visited_vox_speech = list( + TRADER_HAIL_GENERIC = "SKREEEEE! You friend of the Shoal? You trade with, yes?", + TRADER_HAIL_SILICON = "YOU KNOW THE SHOAL? Yes is good, yes yes, " + TRADER_TOKEN_MOB + ". Trade GOOD!", + TRADER_HAIL_DENY = "Trade gone now. Goodbye.", + TRADER_TRADE_COMPLETE = "Yes... this is a good trade for the Shoal!", + TRADER_NO_MONEY = "You know as well as it that money is no good.", + TRADER_NOT_ENOUGH = "Ech, you insult it with such a trade? Respect it, make it equal.", + TRADER_HOW_MUCH = "Hmm.... VALUE. Something like that.", + TRADER_WHAT_WANT = "We need", + TRADER_COMPLIMENT_DENY = "You know better than that!", + TRADER_COMPLIMENT_ACCEPT = "You butter it up? Should know better than that.", + TRADER_INSULT_GOOD = "Where this come from? Is trade no good?", + TRADER_INSULT_BAD = "If you say all this at home, you be dead!", + TRADER_BRIBE_ACCEPT = "It can stay for " + TRADER_TOKEN_TIME + " minutes, for most beloved kin as you.", + TRADER_BRIBE_REFUSAL = "Krrkkrhkkhh! You ask too much! It must be moving on." + ) + possible_wanted_items = list( + /obj/item = TRADER_SUBTYPES_ONLY, + /obj/item/stack/material = TRADER_SUBTYPES_ONLY, + /obj/item/stack/material/cyborg = TRADER_BLACKLIST_ALL, + /obj/item/organ = TRADER_SUBTYPES_ONLY, + ) + + possible_trading_items = list( + /obj/item/gun/projectile/dartgun/vox = TRADER_SUBTYPES_ONLY, + /obj/item/trash = TRADER_SUBTYPES_ONLY, + /obj/item/remains = TRADER_ALL, + /obj/item/clothing/armor_attachment/plate = TRADER_ALL, + /obj/item/clothing/webbing = TRADER_ALL, + /obj/item/clothing/sensor = TRADER_ALL, + /obj/item/robot_parts = TRADER_SUBTYPES_ONLY, + /obj/item/robot_parts/robot_component = TRADER_BLACKLIST + ) + + mob_transfer_message = "You are transported to " + TRADER_TOKEN_ORIGIN + ". When the transportation dizziness wears off, you find you are surrounded by cackling vox..." + +/datum/trader/ship/vox/New() + speech[TRADER_HAIL_SILICON] = "Hello metal thing! You trade metal for things?" + speech[TRADER_HAIL_START + /decl/species/human::uid] = "Hello hueman! Kiikikikiki! " + TRADER_TOKEN_MOB + " trade with us, yes? Good!" + visited_vox_speech[TRADER_HAIL_START + /decl/species/human::uid] = "Friend of it is friend of all Shoal! " + TRADER_TOKEN_MOB + " you trade now!" + visited_vox_speech[TRADER_HAIL_START + /decl/species/vox::uid] = "SKREEEE! May the Shoal make this trade good, " + TRADER_TOKEN_MOB + "!" + ..() + +/datum/trader/ship/vox/hail(var/mob/user) + if(ishuman(user)) + var/mob/living/human/H = user + if(H.species) + switch(H.species.uid) + if(/decl/species/vox::uid) + disposition = 1000 + hailed_vox = TRUE + speech = visited_vox_speech + . = ..() + +/datum/trader/ship/vox/can_hail() + if(hailed_vox >= 0) + return ..() + return FALSE + +/datum/trader/ship/vox/get_item_value(var/trading_num) + . = ..() + if(!hailed_vox) + . *= 2 + +/datum/trader/ship/clothingshop/New() + speech[TRADER_HAIL_START + /decl/species/vox::uid] = "Well hello, sir! I don't believe we have any clothes that fit you... but you can still look!" + ..() diff --git a/mods/species/vox/datum/traits.dm b/mods/species/vox/datum/traits.dm new file mode 100644 index 000000000000..0ce137e24e10 --- /dev/null +++ b/mods/species/vox/datum/traits.dm @@ -0,0 +1,23 @@ +/decl/trait/build_references() + . = ..() + LAZYDISTINCTADD(blocked_species, /decl/species/vox::uid) + +/decl/trait/vox + abstract_type = /decl/trait/vox + +/decl/trait/vox/build_references() + . = ..() + blocked_species = null + permitted_species = list(/decl/species/vox::uid) + +// Bonuses or maluses to skills/checks/actions. +/decl/trait/vox/psyche + name = "Apex-Edited" + description = "Coming soon!" + category = "Psyche" + +// Perks for interacting with vox equipment. +/decl/trait/vox/symbiosis + name = "Self-Maintaining Equipment" + description = "Coming soon!" + category = "Symbiosis" diff --git a/mods/species/vox/datum/unit_testing.dm b/mods/species/vox/datum/unit_testing.dm new file mode 100644 index 000000000000..1010d534842d --- /dev/null +++ b/mods/species/vox/datum/unit_testing.dm @@ -0,0 +1,33 @@ +#ifndef IMMUNE +#define IMMUNE 3 +#endif + +/datum/unit_test/mob_damage/vox + name = "MOB: Vox damage check template" + abstract_type = /datum/unit_test/mob_damage/vox + mob_type = /mob/living/human/vox + +/datum/unit_test/mob_damage/vox/brute + name = "MOB: Vox Brute Damage Check" + damagetype = BRUTE + +/datum/unit_test/mob_damage/vox/fire + name = "MOB: Vox Fire Damage Check" + damagetype = BURN + +/datum/unit_test/mob_damage/vox/tox + name = "MOB: Vox Toxins Damage Check" + damagetype = TOX + +/datum/unit_test/mob_damage/vox/oxy + name = "MOB: Vox Oxygen Damage Check" + damagetype = OXY + +/datum/unit_test/mob_damage/vox/clone + name = "MOB: Vox Clone Damage Check" + damagetype = CLONE + expected_vulnerability = IMMUNE + +/datum/unit_test/mob_damage/vox/halloss + name = "MOB: Vox Halloss Damage Check" + damagetype = PAIN diff --git a/mods/species/vox/gear/gear.dm b/mods/species/vox/gear/gear.dm new file mode 100644 index 000000000000..3633c86071b3 --- /dev/null +++ b/mods/species/vox/gear/gear.dm @@ -0,0 +1,24 @@ +/obj/random/loot/spawn_choices() + . = ..() || list() + . |= list(/obj/item/clothing/mask/gas/vox = 8) + +/obj/item/box/vox + name = "vox survival kit" + desc = "A box decorated in warning colors that contains a limited supply of survival tools. The panel and black stripe indicate this one contains nitrogen." + icon_state = "survivalvox" + +/obj/item/box/vox/WillContain() + return list( + /obj/item/clothing/mask/breath = 1, + /obj/item/tank/emergency/nitrogen = 1, + /obj/item/chems/hypospray/autoinjector/pouch_auto/stabilizer = 1, + /obj/item/stack/medical/bandage = 1, + /obj/item/flashlight/flare/glowstick = 1, + /obj/item/food/junk/candy/proteinbar = 1 + ) + +/obj/item/tank/emergency/nitrogen + name = "emergency nitrogen tank" + desc = "An emergency air tank hastily painted red and issued to Vox crewmembers." + icon = 'mods/species/vox/icons/nitrogen_tank.dmi' + starting_pressure = list(/decl/material/gas/nitrogen = 10 ATM) diff --git a/mods/species/vox/gear/gear_gloves.dm b/mods/species/vox/gear/gear_gloves.dm new file mode 100644 index 000000000000..26c2b3ce380f --- /dev/null +++ b/mods/species/vox/gear/gear_gloves.dm @@ -0,0 +1,7 @@ +/obj/item/clothing/gloves/vox + desc = "These bizarre gauntlets seem to be fitted for... bird claws?" + name = "insulated gauntlets" + icon = 'mods/species/vox/icons/clothing/gloves.dmi' + siemens_coefficient = 0 + permeability_coefficient = 0.05 + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX diff --git a/mods/species/vox/gear/gear_head.dm b/mods/species/vox/gear/gear_head.dm new file mode 100644 index 000000000000..1f4e553a54a2 --- /dev/null +++ b/mods/species/vox/gear/gear_head.dm @@ -0,0 +1,55 @@ +/obj/item/clothing/head/helmet/space/void/setup_equip_flags() + . = ..() + if(bodytype_equip_flags & BODY_EQUIP_FLAG_EXCLUDE) + bodytype_equip_flags |= BODY_EQUIP_FLAG_VOX + +/obj/item/clothing/head/helmet/space/vox + name = "alien helmet" + icon = 'mods/species/vox/icons/clothing/pressure_helmet.dmi' + desc = "A huge, armoured, pressurized helmet. Looks like an ancient human diving suit." + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SMALL, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + siemens_coefficient = 0.6 + item_flags = 0 + flags_inv = 0 + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX + +/obj/item/clothing/head/helmet/space/vox/carapace + name = "alien visor" + icon = 'mods/species/vox/icons/clothing/carapace_helmet.dmi' + desc = "A glowing visor. The light slowly pulses, and seems to follow you." + color = "#486e6e" + var/lights_color = "#00ffff" + +/obj/item/clothing/head/helmet/space/vox/carapace/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && lights_color && check_state_in_icon("[overlay.icon_state]-lights", overlay.icon)) + var/image/I = emissive_overlay(overlay.icon, "[overlay.icon_state]-lights") + I.color = lights_color + I.appearance_flags |= RESET_COLOR + overlay.overlays += I + . = ..() + +/obj/item/clothing/head/helmet/space/vox/carapace/on_update_icon() + . = ..() + if(lights_color && check_state_in_icon("[icon_state]-lights", icon)) + var/image/I = emissive_overlay(icon, "[icon_state]-lights") + I.color = lights_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/clothing/head/helmet/space/vox/stealth + name = "alien stealth helmet" + icon = 'mods/species/vox/icons/clothing/stealth_helmet.dmi' + desc = "A smoothly contoured, matte-black alien helmet." + +/obj/item/clothing/head/helmet/space/vox/medic + name = "alien goggled helmet" + icon = 'mods/species/vox/icons/clothing/medic_helmet.dmi' + desc = "An alien helmet with enormous goggled lenses." diff --git a/mods/species/vox/gear/gear_mask.dm b/mods/species/vox/gear/gear_mask.dm new file mode 100644 index 000000000000..c4f664f3b589 --- /dev/null +++ b/mods/species/vox/gear/gear_mask.dm @@ -0,0 +1,24 @@ +/obj/item/clothing/mask/gas/vox + name = "vox breathing mask" + desc = "A small oxygen filter for use by Vox." + icon = 'mods/species/vox/icons/clothing/mask_breath.dmi' + flags_inv = 0 + body_parts_covered = 0 + filtered_gases = list(/decl/material/gas/oxygen) + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX + +/obj/item/clothing/mask/gas/swat/vox + name = "alien mask" + desc = "Clearly not designed for a human face." + icon = 'mods/species/vox/icons/clothing/mask.dmi' + body_parts_covered = SLOT_EYES + filtered_gases = list( + /decl/material/gas/oxygen, + /decl/material/gas/nitrous_oxide, + /decl/material/gas/chlorine, + /decl/material/gas/ammonia, + /decl/material/gas/carbon_monoxide, + /decl/material/gas/methyl_bromide, + /decl/material/gas/methane + ) + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX diff --git a/mods/species/vox/gear/gear_rig.dm b/mods/species/vox/gear/gear_rig.dm new file mode 100644 index 000000000000..74169654efb8 --- /dev/null +++ b/mods/species/vox/gear/gear_rig.dm @@ -0,0 +1,59 @@ +/obj/item/rig/vox + name = "alien rig control module" + desc = "A strange rig. Parts of it writhe and squirm as if alive. The visor looks more like a thick membrane." + suit_type = "alien rig" + icon = 'mods/species/vox/icons/rig/rig.dmi' + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_RESISTANT, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_RESISTANT, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SHIELDED, + ARMOR_RAD = ARMOR_RAD_SHIELDED + ) + max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + max_pressure_protection = FIRESUIT_MAX_PRESSURE + + chest = /obj/item/clothing/suit/space/rig/vox_rig + helmet = /obj/item/clothing/head/helmet/space/rig/vox_rig + boots = /obj/item/clothing/shoes/magboots/rig/vox_rig + gloves = /obj/item/clothing/gloves/rig/vox_rig + air_supply = /obj/item/tank/nitrogen + + allowed = list( + /obj/item/flashlight, + /obj/item/tank, + /obj/item/ammo_magazine, + /obj/item/ammo_casing, + /obj/item/ammo_magazine/shotholder, + /obj/item/handcuffs, + /obj/item/radio, + /obj/item/baton, + /obj/item/gun, + /obj/item/tool + ) + + online_slowdown = 1 + + initial_modules = list( + /obj/item/rig_module/vision/meson, + /obj/item/rig_module/mounted/plasmacutter, + /obj/item/rig_module/maneuvering_jets, + /obj/item/rig_module/power_sink, + /obj/item/rig_module/cooling_unit + ) + +/obj/item/clothing/head/helmet/space/rig/vox_rig + icon = 'mods/species/vox/icons/rig/helmet.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX +/obj/item/clothing/suit/space/rig/vox_rig + icon = 'mods/species/vox/icons/rig/chest.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX +/obj/item/clothing/shoes/magboots/rig/vox_rig + icon = 'mods/species/vox/icons/rig/boots.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX +/obj/item/clothing/gloves/rig/vox_rig + icon = 'mods/species/vox/icons/rig/gloves.dmi' + siemens_coefficient = 0 + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX diff --git a/mods/species/vox/gear/gear_shoes.dm b/mods/species/vox/gear/gear_shoes.dm new file mode 100644 index 000000000000..fcb9d4e39cfb --- /dev/null +++ b/mods/species/vox/gear/gear_shoes.dm @@ -0,0 +1,45 @@ +/obj/item/clothing/shoes/magboots/vox + name = "vox magclaws" + desc = "A pair of heavy, jagged, armoured foot pieces, seemingly suitable for a velociraptor." + icon = 'mods/species/vox/icons/clothing/boots_vox.dmi' + action_button_name = "Toggle Magclaws" + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX + +/obj/item/clothing/shoes/magboots/vox/attack_self(mob/user) + if(magpulse) + item_flags &= ~ITEM_FLAG_NOSLIP + magpulse = FALSE + canremove = TRUE + to_chat(user, "You relax your deathgrip on the flooring.") + else + if(!ishuman(user)) + return + var/mob/living/human/H = user + var/obj/item/shoes = H.get_equipped_item(slot_shoes_str) + if(shoes != src) + to_chat(user, "You will have to put on \the [src] before you can do that.") + return + item_flags |= ITEM_FLAG_NOSLIP + magpulse = TRUE + canremove = FALSE + to_chat(user, "You dig your claws deeply into the flooring, bracing yourself.") + to_chat(user, "It would be hard to take off \the [src] without relaxing your grip first.") + update_icon() + user.update_action_buttons() + +//In case they somehow come off while enabled. +/obj/item/clothing/shoes/magboots/vox/dropped(mob/user as mob) + ..() + if(magpulse) + user.visible_message( \ + SPAN_NOTICE("\The [src] go limp as they are removed from \the [user]'s feet."), \ + SPAN_NOTICE("\The [src] go limp as they are removed from your feet.")) + item_flags &= ~ITEM_FLAG_NOSLIP + magpulse = FALSE + canremove = TRUE + update_icon() + +/obj/item/clothing/shoes/magboots/vox/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + if (magpulse) + . += "It would be hard to take these off without relaxing your grip first." diff --git a/mods/species/vox/gear/gear_suit.dm b/mods/species/vox/gear/gear_suit.dm new file mode 100644 index 000000000000..7f2f51a58ff6 --- /dev/null +++ b/mods/species/vox/gear/gear_suit.dm @@ -0,0 +1,84 @@ +/obj/item/clothing/suit/space/void/setup_equip_flags() + . = ..() + if(bodytype_equip_flags & BODY_EQUIP_FLAG_EXCLUDE) + bodytype_equip_flags |= BODY_EQUIP_FLAG_VOX + +/obj/item/clothing/suit/space/vox + name = "alien pressure suit" + icon = 'mods/species/vox/icons/clothing/pressure_suit.dmi' + desc = "A huge, armoured, pressurized suit, designed for distinctly nonhuman proportions." + w_class = ITEM_SIZE_NORMAL + allowed = list( + /obj/item/gun, + /obj/item/ammo_magazine, + /obj/item/ammo_casing, + /obj/item/baton, + /obj/item/energy_blade/sword, + /obj/item/handcuffs, + /obj/item/tank + ) + armor = list( + ARMOR_MELEE = ARMOR_MELEE_MAJOR, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_HANDGUNS, + ARMOR_ENERGY = ARMOR_ENERGY_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED, + ARMOR_BIO = ARMOR_BIO_SMALL, + ARMOR_RAD = ARMOR_RAD_MINOR + ) + siemens_coefficient = 0.6 + heat_protection = SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS|SLOT_TAIL + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX + flags_inv = (HIDEJUMPSUIT|HIDETAIL) + +/obj/item/clothing/suit/space/vox/Initialize() + . = ..() + LAZYSET(slowdown_per_slot, slot_wear_suit_str, 1) + +/obj/item/clothing/suit/space/vox/carapace + name = "alien carapace armour" + color = "#486e6e" + icon = 'mods/species/vox/icons/clothing/carapace_suit.dmi' + desc = "An armoured, segmented carapace with glowing purple lights. It looks pretty run-down." + var/lights_color = "#00ffff" + +/obj/item/clothing/suit/space/vox/carapace/apply_additional_mob_overlays(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) + if(overlay && lights_color && check_state_in_icon("[overlay.icon_state]-lights", overlay.icon)) + var/image/I = emissive_overlay(overlay.icon, "[overlay.icon_state]-lights") + I.color = lights_color + I.appearance_flags |= RESET_COLOR + overlay.overlays += I + . = ..() + +/obj/item/clothing/suit/space/vox/carapace/on_update_icon() + . = ..() + if(lights_color && check_state_in_icon("[icon_state]-lights", icon)) + var/image/I = emissive_overlay(icon, "[icon_state]-lights") + I.color = lights_color + I.appearance_flags |= RESET_COLOR + add_overlay(I) + +/obj/item/clothing/suit/space/vox/stealth + name = "alien stealth suit" + icon = 'mods/species/vox/icons/clothing/stealth_suit.dmi' + desc = "A sleek black suit. It seems to have a tail, and is very heavy." + +/obj/item/clothing/suit/space/vox/medic + name = "alien armour" + icon = 'mods/species/vox/icons/clothing/medic_suit.dmi' + desc = "An almost organic-looking nonhuman pressure suit." + +/obj/item/clothing/suit/armor/vox_scrap + name = "rusted metal armor" + desc = "A hodgepodge of various pieces of metal scrapped together into a rudimentary vox-shaped piece of armor." + icon = 'mods/species/vox/icons/clothing/scrap_suit.dmi' + allowed = list(/obj/item/gun, /obj/item/tank) + armor = list( + ARMOR_MELEE = ARMOR_MELEE_VERY_HIGH, + ARMOR_BULLET = ARMOR_BALLISTIC_PISTOL, + ARMOR_LASER = ARMOR_LASER_MINOR, + ARMOR_BOMB = ARMOR_BOMB_PADDED) //Higher melee armor versus lower everything else. + body_parts_covered = SLOT_UPPER_BODY|SLOT_ARMS|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_TAIL + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX + siemens_coefficient = 1 //It's literally metal diff --git a/mods/species/vox/gear/gear_under.dm b/mods/species/vox/gear/gear_under.dm new file mode 100644 index 000000000000..789bebc1696a --- /dev/null +++ b/mods/species/vox/gear/gear_under.dm @@ -0,0 +1,12 @@ +/obj/item/clothing/pants/vox + name = "alien clothing" + desc = "This doesn't look very comfortable." + icon = 'mods/species/vox/icons/clothing/under_clothing.dmi' + body_parts_covered = SLOT_LEGS + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX + +/obj/item/clothing/suit/robe/vox + name = "alien robes" + desc = "Weird and flowing!" + icon = 'mods/species/vox/icons/clothing/under_robes.dmi' + bodytype_equip_flags = BODY_EQUIP_FLAG_VOX diff --git a/mods/species/vox/gear/gun.dm b/mods/species/vox/gear/gun.dm new file mode 100644 index 000000000000..a2e5706de5d8 --- /dev/null +++ b/mods/species/vox/gear/gun.dm @@ -0,0 +1,80 @@ +/datum/extension/voxform + base_type = /datum/extension/voxform + +/datum/extension/voxform/proc/check_held_user(var/mob/living/human/user, var/atom/movable/thing) + if(!istype(user)) + return FALSE + if(user.get_bodytype_category() != BODYTYPE_VOX && user.try_unequip(thing)) + to_chat(user, SPAN_WARNING("\The [thing] hisses and wriggles out of your grasp!")) + playsound(user, 'sound/voice/BugHiss.ogg', 50, 1) + return FALSE + return TRUE + +/obj/item/gun/special_check(var/mob/living/human/user) + . = ..() + if(!QDELETED(src) && src.loc == user && has_extension(src, /datum/extension/voxform)) + var/datum/extension/voxform/voxform = get_extension(src, /datum/extension/voxform) + . = voxform.check_held_user(user, src) + +/* + * Vox Darkmatter Cannon + */ +/obj/item/gun/energy/darkmatter + name = "flux cannon" + desc = "A vicious beam weapon that crushes targets with dark-matter gravity pulses. Parts of it twitch and writhe, as if alive." + icon = 'mods/species/vox/icons/gear/darkcannon.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + projectile_type = /obj/item/projectile/beam/stun/darkmatter + one_hand_penalty = 2 //a little bulky + self_recharge = 1 + firemodes = list( + list(mode_name="stunning", burst=1, fire_delay=null,burst_accuracy=list(30), dispersion=null, projectile_type=/obj/item/projectile/beam/stun/darkmatter, charge_cost = 50), + list(mode_name="focused", burst=1, fire_delay=null, burst_accuracy=list(30), dispersion=null, projectile_type=/obj/item/projectile/beam/darkmatter, charge_cost = 75), + list(mode_name="scatter burst", burst=8, fire_delay=null, burst_accuracy=list(0, 0, 0, 0, 0, 0, 0, 0), dispersion=list(0, 1, 2, 2, 3, 3, 3, 3, 3), projectile_type=/obj/item/projectile/energy/darkmatter, charge_cost = 10), + ) + +/obj/item/gun/energy/darkmatter/Initialize() + . = ..() + set_extension(src, /datum/extension/voxform) + +/* + * Vox Sonic Cannon + */ +/obj/item/gun/energy/sonic + name = "soundcannon" + desc = "A vicious sonic weapon of alien manufacture. Parts of it quiver gelatinously, as though the insectile-looking thing is alive." + icon = 'mods/species/vox/icons/gear/noise.dmi' + icon_state = ICON_STATE_WORLD + w_class = ITEM_SIZE_LARGE + one_hand_penalty = 1 + self_recharge = 1 + recharge_time = 10 + fire_delay = 15 + projectile_type=/obj/item/projectile/energy/plasmastun/sonic/weak + firemodes = list( + list(mode_name="normal", projectile_type=/obj/item/projectile/energy/plasmastun/sonic/weak, charge_cost = 50), + list(mode_name="overcharge", projectile_type=/obj/item/projectile/energy/plasmastun/sonic/strong, charge_cost = 200), + ) + +/obj/item/gun/energy/sonic/Initialize() + . = ..() + set_extension(src, /datum/extension/voxform) + +/obj/item/gun/projectile/dartgun/vox + name = "alien dart gun" + desc = "A small gas-powered dartgun, fitted for nonhuman hands." + +/obj/item/gun/projectile/dartgun/vox/medical + starting_chems = list( + /decl/material/liquid/burn_meds, + /decl/material/liquid/brute_meds, + /decl/material/liquid/antitoxins + ) + +/obj/item/gun/projectile/dartgun/vox/raider + starting_chems = list( + /decl/material/liquid/hallucinogenics, + /decl/material/liquid/sedatives, + /decl/material/liquid/paralytics + ) diff --git a/mods/species/vox/gear/gun_slugsling.dm b/mods/species/vox/gear/gun_slugsling.dm new file mode 100644 index 000000000000..422da40b00d8 --- /dev/null +++ b/mods/species/vox/gear/gun_slugsling.dm @@ -0,0 +1,67 @@ +/obj/item/slugegg + name = "slugegg" + desc = "A pulsing, disgusting door to new life." + icon = 'mods/species/vox/icons/gear/slugegg.dmi' + icon_state = "slugegg" + material = /decl/material/solid/organic/skin/insect + _base_attack_force = 1 + var/break_on_impact = 1 //There are two modes to the eggs. + //One breaks the egg on hit, + +/obj/item/slugegg/throw_impact(atom/hit_atom) + if(break_on_impact) + squish() + else + movable_flags |= MOVABLE_FLAG_PROXMOVE //Dont want it active during the throw... loooots of unneeded checking. + return ..() + +/obj/item/slugegg/attack_self(var/mob/user) + squish() + +/obj/item/slugegg/HasProximity(var/atom/movable/AM) + . = ..() + if(. && isliving(AM)) + var/mob/living/L = AM + if(L.get_bodytype()?.bodytype_flag & BODY_EQUIP_FLAG_VOX) + return FALSE + if(L.faction == /mob/living/simple_animal/hostile/slug/vox::faction) + return FALSE + squish() + +/obj/item/slugegg/proc/squish() + src.visible_message("\The [src] bursts open!") + new /mob/living/simple_animal/hostile/slug(get_turf(src)) + playsound(src.loc,'sound/effects/attackblob.ogg',100, 1) + qdel(src) + +/mob/living/simple_animal/hostile/slug/vox + faction = "Vox" + +//a slug sling basically launches a small egg that hatches (either on a person or on the floor), releasing a terrible blood thirsty monster. +//Balanced due to the non-spammy nature of the gun, as well as the frailty of the creatures. +/obj/item/gun/launcher/alien/slugsling + name = "slug sling" + desc = "A bulbous looking rifle. It feels like holding a plastic bag full of meat." + w_class = ITEM_SIZE_LARGE + icon = 'mods/species/vox/icons/gear/voxslug.dmi' + icon_state = ICON_STATE_WORLD + fire_sound_text = "a strange noise" + fire_sound = 'sound/weapons/towelwhip.ogg' + release_force = 6 + ammo_name = "slug" + ammo_type = /obj/item/slugegg + max_ammo = 2 + ammo = 2 + ammo_gen_time = 600 + var/mode = "Impact" + +/obj/item/gun/launcher/alien/slugsling/consume_next_projectile() + var/obj/item/slugegg/S = ..() + if(S) + S.break_on_impact = (mode == "Impact") + return S + + +/obj/item/gun/launcher/alien/slugsling/attack_self(var/mob/user) + mode = mode == "Impact" ? "Sentry" : "Impact" + to_chat(user,"You switch \the [src]'s mode to \"[mode]\"") diff --git a/mods/species/vox/gear/gun_spikethrower.dm b/mods/species/vox/gear/gun_spikethrower.dm new file mode 100644 index 000000000000..25461355159c --- /dev/null +++ b/mods/species/vox/gear/gun_spikethrower.dm @@ -0,0 +1,64 @@ +/obj/item/gun/launcher/alien + var/last_regen = 0 + var/ammo_gen_time = 100 + var/max_ammo = 3 + var/ammo = 3 + var/ammo_type + var/ammo_name + +/obj/item/gun/launcher/alien/Initialize() + . = ..() + START_PROCESSING(SSobj, src) + last_regen = world.time + +/obj/item/gun/launcher/alien/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/gun/launcher/alien/Process() + if(ammo < max_ammo && world.time > last_regen + ammo_gen_time) + ammo++ + last_regen = world.time + update_icon() + +/obj/item/gun/launcher/alien/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + . += "It has [ammo] [ammo_name]\s remaining." + +/obj/item/gun/launcher/alien/consume_next_projectile() + if(ammo < 1) return null + if(ammo == max_ammo) //stops people from buffering a reload (gaining effectively +1 to the clip) + last_regen = world.time + ammo-- + return new ammo_type + +/obj/item/gun/launcher/alien/Initialize() + . = ..() + set_extension(src, /datum/extension/voxform) + +//Vox pinning weapon. +/obj/item/gun/launcher/alien/spikethrower + name = "spike thrower" + desc = "A vicious alien projectile weapon. Parts of it quiver gelatinously, as though the thing is insectile and alive." + w_class = ITEM_SIZE_LARGE + ammo_name = "spike" + ammo_type = /obj/item/stack/material/bow_ammo/spike + release_force = 30 + icon = 'mods/species/vox/icons/gear/voxspike.dmi' + icon_state = ICON_STATE_WORLD + fire_sound_text = "a strange noise" + fire_sound = 'sound/weapons/spike.ogg' + +/obj/item/gun/launcher/alien/spikethrower/on_update_icon() + . = ..() + icon_state = "[get_world_inventory_state()][clamp(ammo,0,3)]" + +/obj/item/stack/material/bow_ammo/quill + name = "vox quill" + desc = "A wickedly barbed quill from some bizarre animal." + icon = 'mods/species/vox/icons/gear/arrow_quill.dmi' + material = /decl/material/solid/organic/leather/chitin + material_alteration = MAT_FLAG_ALTERATION_NONE + +/obj/item/stack/material/bow_ammo/quill/make_superheated() + return diff --git a/mods/species/vox/icons/body/blood_overlays.dmi b/mods/species/vox/icons/body/blood_overlays.dmi new file mode 100644 index 000000000000..30755f80a5ad Binary files /dev/null and b/mods/species/vox/icons/body/blood_overlays.dmi differ diff --git a/mods/species/vox/icons/body/deformed_body.dmi b/mods/species/vox/icons/body/deformed_body.dmi new file mode 100644 index 000000000000..9ca8a674c320 Binary files /dev/null and b/mods/species/vox/icons/body/deformed_body.dmi differ diff --git a/mods/species/vox/icons/body/husk.dmi b/mods/species/vox/icons/body/husk.dmi new file mode 100644 index 000000000000..b7ab9e121592 Binary files /dev/null and b/mods/species/vox/icons/body/husk.dmi differ diff --git a/mods/species/vox/icons/body/improvised_cyberlimbs.dmi b/mods/species/vox/icons/body/improvised_cyberlimbs.dmi new file mode 100644 index 000000000000..697b248d4ee4 Binary files /dev/null and b/mods/species/vox/icons/body/improvised_cyberlimbs.dmi differ diff --git a/mods/species/vox/icons/body/primalis_cyberlimbs.dmi b/mods/species/vox/icons/body/primalis_cyberlimbs.dmi new file mode 100644 index 000000000000..9472d8aba8db Binary files /dev/null and b/mods/species/vox/icons/body/primalis_cyberlimbs.dmi differ diff --git a/mods/species/vox/icons/body/servitor/body.dmi b/mods/species/vox/icons/body/servitor/body.dmi new file mode 100644 index 000000000000..0f1bb1a908d1 Binary files /dev/null and b/mods/species/vox/icons/body/servitor/body.dmi differ diff --git a/mods/species/vox/icons/body/servitor/body_alchemist.dmi b/mods/species/vox/icons/body/servitor/body_alchemist.dmi new file mode 100644 index 000000000000..f9f598fd3ca9 Binary files /dev/null and b/mods/species/vox/icons/body/servitor/body_alchemist.dmi differ diff --git a/mods/species/vox/icons/body/servitor/eyes.dmi b/mods/species/vox/icons/body/servitor/eyes.dmi new file mode 100644 index 000000000000..16b1e6781cf8 Binary files /dev/null and b/mods/species/vox/icons/body/servitor/eyes.dmi differ diff --git a/mods/species/vox/icons/body/servitor/eyes_alchemist.dmi b/mods/species/vox/icons/body/servitor/eyes_alchemist.dmi new file mode 100644 index 000000000000..bfe24bdb9191 Binary files /dev/null and b/mods/species/vox/icons/body/servitor/eyes_alchemist.dmi differ diff --git a/mods/species/vox/icons/body/servitor/hair.dmi b/mods/species/vox/icons/body/servitor/hair.dmi new file mode 100644 index 000000000000..999649b10e14 Binary files /dev/null and b/mods/species/vox/icons/body/servitor/hair.dmi differ diff --git a/mods/species/vox/icons/body/servitor/markings.dmi b/mods/species/vox/icons/body/servitor/markings.dmi new file mode 100644 index 000000000000..f59bea112395 Binary files /dev/null and b/mods/species/vox/icons/body/servitor/markings.dmi differ diff --git a/mods/species/vox/icons/body/soldier/body.dmi b/mods/species/vox/icons/body/soldier/body.dmi new file mode 100644 index 000000000000..c7b880715f31 Binary files /dev/null and b/mods/species/vox/icons/body/soldier/body.dmi differ diff --git a/mods/species/vox/icons/body/soldier/eyes.dmi b/mods/species/vox/icons/body/soldier/eyes.dmi new file mode 100644 index 000000000000..853dee21346d Binary files /dev/null and b/mods/species/vox/icons/body/soldier/eyes.dmi differ diff --git a/mods/species/vox/icons/body/soldier/hair.dmi b/mods/species/vox/icons/body/soldier/hair.dmi new file mode 100644 index 000000000000..7149c366b5cb Binary files /dev/null and b/mods/species/vox/icons/body/soldier/hair.dmi differ diff --git a/mods/species/vox/icons/body/soldier/markings.dmi b/mods/species/vox/icons/body/soldier/markings.dmi new file mode 100644 index 000000000000..b5ff4a42deed Binary files /dev/null and b/mods/species/vox/icons/body/soldier/markings.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/blood_overlays.dmi b/mods/species/vox/icons/body/stanchion/blood_overlays.dmi new file mode 100644 index 000000000000..ad35ce5f6a0c Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/blood_overlays.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/body.dmi b/mods/species/vox/icons/body/stanchion/body.dmi new file mode 100644 index 000000000000..b5c1f313fbe8 Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/body.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/damage_overlays.dmi b/mods/species/vox/icons/body/stanchion/damage_overlays.dmi new file mode 100644 index 000000000000..af035589c069 Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/damage_overlays.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/eyes.dmi b/mods/species/vox/icons/body/stanchion/eyes.dmi new file mode 100644 index 000000000000..da9a5d4bc0ec Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/eyes.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/hair.dmi b/mods/species/vox/icons/body/stanchion/hair.dmi new file mode 100644 index 000000000000..cdbf92bc78fa Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/hair.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/markings.dmi b/mods/species/vox/icons/body/stanchion/markings.dmi new file mode 100644 index 000000000000..fb93f23b9218 Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/markings.dmi differ diff --git a/mods/species/vox/icons/body/stanchion/template.dmi b/mods/species/vox/icons/body/stanchion/template.dmi new file mode 100644 index 000000000000..e290c565755e Binary files /dev/null and b/mods/species/vox/icons/body/stanchion/template.dmi differ diff --git a/mods/species/vox/icons/clothing/boots_vox.dmi b/mods/species/vox/icons/clothing/boots_vox.dmi new file mode 100644 index 000000000000..564051362c0d Binary files /dev/null and b/mods/species/vox/icons/clothing/boots_vox.dmi differ diff --git a/mods/species/vox/icons/clothing/carapace_helmet.dmi b/mods/species/vox/icons/clothing/carapace_helmet.dmi new file mode 100644 index 000000000000..b5cd3b56ffe9 Binary files /dev/null and b/mods/species/vox/icons/clothing/carapace_helmet.dmi differ diff --git a/mods/species/vox/icons/clothing/carapace_suit.dmi b/mods/species/vox/icons/clothing/carapace_suit.dmi new file mode 100644 index 000000000000..54fdb8ba521f Binary files /dev/null and b/mods/species/vox/icons/clothing/carapace_suit.dmi differ diff --git a/mods/species/vox/icons/clothing/gloves.dmi b/mods/species/vox/icons/clothing/gloves.dmi new file mode 100644 index 000000000000..c9e657f132bd Binary files /dev/null and b/mods/species/vox/icons/clothing/gloves.dmi differ diff --git a/mods/species/vox/icons/clothing/mask.dmi b/mods/species/vox/icons/clothing/mask.dmi new file mode 100644 index 000000000000..f9551a1c5a7d Binary files /dev/null and b/mods/species/vox/icons/clothing/mask.dmi differ diff --git a/mods/species/vox/icons/clothing/mask_breath.dmi b/mods/species/vox/icons/clothing/mask_breath.dmi new file mode 100644 index 000000000000..fd6edb642d46 Binary files /dev/null and b/mods/species/vox/icons/clothing/mask_breath.dmi differ diff --git a/mods/species/vox/icons/clothing/medic_helmet.dmi b/mods/species/vox/icons/clothing/medic_helmet.dmi new file mode 100644 index 000000000000..1f1dca501cdc Binary files /dev/null and b/mods/species/vox/icons/clothing/medic_helmet.dmi differ diff --git a/mods/species/vox/icons/clothing/medic_suit.dmi b/mods/species/vox/icons/clothing/medic_suit.dmi new file mode 100644 index 000000000000..f1e8a0b06358 Binary files /dev/null and b/mods/species/vox/icons/clothing/medic_suit.dmi differ diff --git a/mods/species/vox/icons/clothing/pressure_helmet.dmi b/mods/species/vox/icons/clothing/pressure_helmet.dmi new file mode 100644 index 000000000000..916a0837ce2f Binary files /dev/null and b/mods/species/vox/icons/clothing/pressure_helmet.dmi differ diff --git a/mods/species/vox/icons/clothing/pressure_suit.dmi b/mods/species/vox/icons/clothing/pressure_suit.dmi new file mode 100644 index 000000000000..50ba83a89251 Binary files /dev/null and b/mods/species/vox/icons/clothing/pressure_suit.dmi differ diff --git a/mods/species/vox/icons/clothing/scrap_suit.dmi b/mods/species/vox/icons/clothing/scrap_suit.dmi new file mode 100644 index 000000000000..58c4c23054a1 Binary files /dev/null and b/mods/species/vox/icons/clothing/scrap_suit.dmi differ diff --git a/mods/species/vox/icons/clothing/stealth_helmet.dmi b/mods/species/vox/icons/clothing/stealth_helmet.dmi new file mode 100644 index 000000000000..28937345736b Binary files /dev/null and b/mods/species/vox/icons/clothing/stealth_helmet.dmi differ diff --git a/mods/species/vox/icons/clothing/stealth_suit.dmi b/mods/species/vox/icons/clothing/stealth_suit.dmi new file mode 100644 index 000000000000..da95af841e1b Binary files /dev/null and b/mods/species/vox/icons/clothing/stealth_suit.dmi differ diff --git a/mods/species/vox/icons/clothing/under_clothing.dmi b/mods/species/vox/icons/clothing/under_clothing.dmi new file mode 100644 index 000000000000..0e495673b5ec Binary files /dev/null and b/mods/species/vox/icons/clothing/under_clothing.dmi differ diff --git a/mods/species/vox/icons/clothing/under_robes.dmi b/mods/species/vox/icons/clothing/under_robes.dmi new file mode 100644 index 000000000000..d60463228d40 Binary files /dev/null and b/mods/species/vox/icons/clothing/under_robes.dmi differ diff --git a/mods/species/vox/icons/gear/arrow_quill.dmi b/mods/species/vox/icons/gear/arrow_quill.dmi new file mode 100644 index 000000000000..46e94ec6779b Binary files /dev/null and b/mods/species/vox/icons/gear/arrow_quill.dmi differ diff --git a/icons/obj/guns/darkcannon.dmi b/mods/species/vox/icons/gear/darkcannon.dmi similarity index 100% rename from icons/obj/guns/darkcannon.dmi rename to mods/species/vox/icons/gear/darkcannon.dmi diff --git a/icons/obj/guns/noise.dmi b/mods/species/vox/icons/gear/noise.dmi similarity index 100% rename from icons/obj/guns/noise.dmi rename to mods/species/vox/icons/gear/noise.dmi diff --git a/icons/obj/items/slug_egg.dmi b/mods/species/vox/icons/gear/slugegg.dmi similarity index 100% rename from icons/obj/items/slug_egg.dmi rename to mods/species/vox/icons/gear/slugegg.dmi diff --git a/icons/obj/guns/launcher/voxslug.dmi b/mods/species/vox/icons/gear/voxslug.dmi similarity index 100% rename from icons/obj/guns/launcher/voxslug.dmi rename to mods/species/vox/icons/gear/voxslug.dmi diff --git a/icons/obj/guns/launcher/voxspike.dmi b/mods/species/vox/icons/gear/voxspike.dmi similarity index 100% rename from icons/obj/guns/launcher/voxspike.dmi rename to mods/species/vox/icons/gear/voxspike.dmi diff --git a/mods/species/vox/icons/nitrogen_tank.dmi b/mods/species/vox/icons/nitrogen_tank.dmi new file mode 100644 index 000000000000..662ead4e92e8 Binary files /dev/null and b/mods/species/vox/icons/nitrogen_tank.dmi differ diff --git a/mods/species/vox/icons/rig/boots.dmi b/mods/species/vox/icons/rig/boots.dmi new file mode 100644 index 000000000000..c69f65c2b4a3 Binary files /dev/null and b/mods/species/vox/icons/rig/boots.dmi differ diff --git a/mods/species/vox/icons/rig/chest.dmi b/mods/species/vox/icons/rig/chest.dmi new file mode 100644 index 000000000000..d15f55c11191 Binary files /dev/null and b/mods/species/vox/icons/rig/chest.dmi differ diff --git a/mods/species/vox/icons/rig/gloves.dmi b/mods/species/vox/icons/rig/gloves.dmi new file mode 100644 index 000000000000..1e02e09b2bf7 Binary files /dev/null and b/mods/species/vox/icons/rig/gloves.dmi differ diff --git a/mods/species/vox/icons/rig/helmet.dmi b/mods/species/vox/icons/rig/helmet.dmi new file mode 100644 index 000000000000..fc0c1cefb36f Binary files /dev/null and b/mods/species/vox/icons/rig/helmet.dmi differ diff --git a/mods/species/vox/icons/rig/rig.dmi b/mods/species/vox/icons/rig/rig.dmi new file mode 100644 index 000000000000..b52741473932 Binary files /dev/null and b/mods/species/vox/icons/rig/rig.dmi differ diff --git a/mods/species/vox/mobs_vox.dm b/mods/species/vox/mobs_vox.dm new file mode 100644 index 000000000000..3951c19fdaaa --- /dev/null +++ b/mods/species/vox/mobs_vox.dm @@ -0,0 +1,2 @@ +/mob/living/simple_animal/hostile/slug/check_friendly_species(var/mob/living/human/H) + return (istype(H) && H.get_bodytype_category() == BODYTYPE_VOX) || ..() diff --git a/mods/species/vox/organs_vox.dm b/mods/species/vox/organs_vox.dm new file mode 100644 index 000000000000..29b4e15191e6 --- /dev/null +++ b/mods/species/vox/organs_vox.dm @@ -0,0 +1,260 @@ +//vox got different organs within. This will also help with regular surgeons knowing the organs within an alien as alien as vox. +/obj/item/organ/internal/heart/vox + icon_state = "vox heart" + dead_icon = null + parent_organ = BP_GROIN + +/obj/item/organ/internal/lungs/vox + name = "air capillary sack" //Like birds, Vox absorb gas via air capillaries. + icon_state = "vox lung" + +/obj/item/organ/internal/kidneys/vox + name = "filtration bladder" + icon_state = "lungs" //wow are vox kidneys fat. + color = "#99ccff" + parent_organ = BP_CHEST + +/obj/item/organ/internal/liver/vox + name = "waste tract" + parent_organ = BP_CHEST + color = "#0033cc" + +/obj/item/organ/internal/eyes/vox + color = "#0033cc" + +/obj/item/organ/internal/stomach/vox + name = "gizzard" + color = "#0033cc" + var/static/list/gains_nutriment_from_inedible_reagents = list( + /decl/material/solid/organic/wood/oak = 3, + /decl/material/solid/organic/wood/mahogany = 3, + /decl/material/solid/organic/wood/maple = 3, + /decl/material/solid/organic/wood/ebony = 3, + /decl/material/solid/organic/wood/walnut = 3, + /decl/material/solid/organic/wood/chipboard = 2, + /decl/material/solid/organic/wood/chipboard/mahogany = 2, + /decl/material/solid/organic/wood/chipboard/maple = 2, + /decl/material/solid/organic/wood/chipboard/ebony = 2, + /decl/material/solid/organic/wood/chipboard/walnut = 2, + /decl/material/liquid/cleaner = 1, + /decl/material/liquid/foaming_agent = 1, + /decl/material/liquid/surfactant = 1, + /decl/material/liquid/paint = 1 + ) + var/static/list/can_digest_matter = list( + /decl/material/solid/organic/wood/oak = TRUE, + /decl/material/solid/organic/wood/mahogany = TRUE, + /decl/material/solid/organic/wood/maple = TRUE, + /decl/material/solid/organic/wood/ebony = TRUE, + /decl/material/solid/organic/wood/walnut = TRUE, + /decl/material/solid/organic/wood/chipboard = TRUE, + /decl/material/solid/organic/wood/chipboard/mahogany = TRUE, + /decl/material/solid/organic/wood/chipboard/maple = TRUE, + /decl/material/solid/organic/wood/chipboard/ebony = TRUE, + /decl/material/solid/organic/wood/chipboard/walnut = TRUE, + /decl/material/solid/organic/leather = TRUE, + /decl/material/solid/organic/plastic = TRUE, + /decl/material/solid/organic/cardboard = TRUE, + /decl/material/solid/organic/paper = TRUE, + /decl/material/solid/organic/cloth = TRUE, + /decl/material/solid/slag = TRUE, + /decl/material/solid/sodiumchloride = TRUE + ) + var/static/list/can_process_matter = list( + /decl/material/solid/glass = TRUE, + /decl/material/solid/gemstone/diamond = TRUE, + /decl/material/solid/stone/sandstone = TRUE, + /decl/material/solid/stone/marble = TRUE, + /decl/material/solid/metal/steel = TRUE, + /decl/material/solid/metal/gold = TRUE, + /decl/material/solid/metal/silver = TRUE, + /decl/material/solid/metal/uranium = TRUE, + /decl/material/solid/metal/iron = TRUE, + /decl/material/solid/metal/platinum = TRUE, + /decl/material/solid/metal/bronze = TRUE, + /decl/material/solid/metal/titanium = TRUE, + /decl/material/solid/metal/osmium = TRUE, + /decl/material/solid/metal/copper = TRUE, + /decl/material/solid/metal/aluminium = TRUE, + /decl/material/solid/sand = TRUE, + /decl/material/solid/clay = TRUE, + /decl/material/solid/graphite = TRUE, + /decl/material/solid/pitchblende = TRUE, + /decl/material/solid/hematite = TRUE, + /decl/material/solid/quartz = TRUE, + /decl/material/solid/pyrite = TRUE, + /decl/material/solid/spodumene = TRUE, + /decl/material/solid/cinnabar = TRUE, + /decl/material/solid/phosphorite = TRUE, + /decl/material/solid/potash = TRUE, + /decl/material/solid/bauxite = TRUE, + /decl/material/solid/rutile = TRUE + ) + var/list/stored_matter = list() + +/obj/item/organ/internal/stomach/vox/Process() + . = ..() + if(is_usable()) + + // Handle some post-metabolism reagent processing for generally inedible foods. + if(REAGENT_TOTAL_VOLUME(ingested) > 0) + for(var/decl/material/reagent as anything in REAGENT_VOLUMES(ingested)) + var/inedible_nutriment_amount = gains_nutriment_from_inedible_reagents[reagent.type] + if(inedible_nutriment_amount > 0) + owner.adjust_nutrition(inedible_nutriment_amount) + + // Do we have any objects to digest? + var/list/check_materials + var/updated_stacks + for(var/obj/item/food in contents) + for(var/mat in food.matter) + if(!can_digest_matter[mat] && !can_process_matter[mat]) + continue + + // Grab a chunk out of the object. + var/digested = min(food.matter[mat], rand(200,500)) + food.matter[mat] -= digested + digested *= 0.75 + if(food.matter[mat] <= 0) + food.matter -= mat + if(!food.matter.len) + qdel(food) + + // Process it. + if(can_digest_matter[mat]) + owner.adjust_nutrition(max(1, floor(digested/100))) + updated_stacks = TRUE + else if(can_process_matter[mat]) + LAZYDISTINCTADD(check_materials, mat) + stored_matter[mat] += digested + + // Convert stored matter into sheets. + for(var/mat in check_materials) + var/decl/material/M = GET_DECL(mat) + if(M && stored_matter[mat] >= SHEET_MATERIAL_AMOUNT) + + // Remove as many sheets as possible from the gizzard. + var/sheets = floor(stored_matter[mat]/SHEET_MATERIAL_AMOUNT) + stored_matter[mat] -= SHEET_MATERIAL_AMOUNT * sheets + if(stored_matter[mat] <= 0) + stored_matter -= mat + + // Merge them into other stacks. + for(var/obj/item/stack/material/mat_stack in contents) + if(mat_stack.material == M && mat_stack.amount < mat_stack.max_amount) + var/taking_sheets = min(sheets, mat_stack.get_max_amount() - mat_stack.amount) + mat_stack.add(taking_sheets) + sheets -= taking_sheets + updated_stacks = TRUE + + // Create new stacks if needed. + if(sheets) + M.create_object(src, sheets) + updated_stacks = TRUE + + if(updated_stacks && prob(5)) + to_chat(owner, SPAN_NOTICE("Your [name] churns as it digests some material into a usable form.")) + +/obj/item/organ/internal/hindtongue + name = "hindtongue" + desc = "Some kind of severed bird tongue." + parent_organ = BP_HEAD + icon_state = "hindtongue" + organ_tag = BP_HINDTONGUE + +/obj/item/organ/internal/voxstack + name = "cortical stack" + parent_organ = BP_HEAD + icon_state = "cortical-stack" + organ_tag = BP_VOXSTACK + organ_properties = ORGAN_PROP_PROSTHETIC + origin_tech = @'{"biotech":4,"materials":4,"magnets":2,"programming":3}' + relative_size = 10 + + var/stored_ckey + var/default_language + var/list/languages = list() + var/datum/mind/backup + var/prompting = FALSE // Are we waiting for a user prompt? + +/obj/item/organ/internal/voxstack/Initialize(mapload, material_key, datum/mob_snapshot/supplied_appearance, decl/bodytype/new_bodytype) + var/decl/species/dna_species = supplied_appearance && supplied_appearance.root_species + . = ..(mapload, material_key, supplied_appearance, dna_species?.base_internal_prosthetics_model) + do_backup() + +/obj/item/organ/internal/voxstack/get_examine_strings(mob/user, distance, infix, suffix) + . = ..() + var/user_vox = istype(user.get_species(), /decl/species/vox) + if (istype(backup)) + var/owner_viable = find_dead_player(stored_ckey, TRUE) + if (user_vox) + . += SPAN_NOTICE("The integrity light on [src] blinks [owner_viable ? "rapidly. It can be implanted." : "slowly. It is dormant."]") + else + . += SPAN_NOTICE("A light on [src] blinks [owner_viable ? "rapidly" : "slowly"].") + else if (user_vox) + . += SPAN_NOTICE("The integrity light on [src] is off. It is empty and lifeless.") + +/obj/item/organ/internal/voxstack/emp_act() + return + +/obj/item/organ/internal/voxstack/getToxLoss() + return 0 + +/obj/item/organ/internal/voxstack/proc/do_backup() + if(owner && owner.stat != DEAD && !is_broken() && owner.mind) + languages = owner.languages.Copy() + backup = owner.mind + default_language = owner.default_language + if(owner.ckey) + stored_ckey = owner.ckey + +/obj/item/organ/internal/voxstack/proc/backup_inviable() + return (!istype(backup) || backup == owner.mind || (backup.current && backup.current.stat != DEAD)) + +/obj/item/organ/internal/voxstack/on_add_effects() + . = ..() + if(prompting) // Don't spam the player with twenty dialogs because someone doesn't know what they're doing or panicking. + return FALSE + //Need spawn here so that this interactive bit doesn't lock up init + if(owner && !backup_inviable()) + prompt_revive_callback(owner) + return TRUE + +/obj/item/organ/internal/voxstack/proc/prompt_revive_callback(var/mob/living/target) + set waitfor = FALSE + if(istype(target) && !backup_inviable()) + prompting = TRUE + var/response = alert(find_dead_player(stored_ckey, 1), "Your neural backup has been placed into a new body. Do you wish to return to life as the mind of [backup.name]?", "Resleeving", "Yes", "No") + prompting = FALSE + if(src && response == "Yes" && owner == target) + overwrite() + sleep(-1) + do_backup() + +/obj/item/organ/internal/voxstack/on_remove_effects(mob/living/last_owner) + var/obj/item/organ/external/head = GET_EXTERNAL_ORGAN(last_owner, parent_organ) + last_owner.visible_message(SPAN_DANGER("\The [src] rips gaping holes in \the [last_owner]'s [head.name] as it is torn loose!")) + head.take_damage(rand(15,20)) + for(var/obj/item/organ/internal/O in head.contents) + O.take_damage(rand(30,70)) + do_backup() + ..() + +/obj/item/organ/internal/voxstack/proc/overwrite() + if(owner.mind && owner.ckey) //Someone is already in this body! + if(owner.mind == backup) // Oh, it's the same mind in the backup. Someone must've spammed the 'Start Procedure' button in a panic. + return + owner.visible_message(SPAN_DANGER("\The [owner] spasms violently!")) + if(prob(66)) + to_chat(owner, SPAN_DANGER("You fight off the invading tendrils of another mind, holding onto your own body!")) + return + owner.ghostize() + backup.active = 1 + backup.transfer_to(owner) + if (default_language) + owner.default_language = default_language + owner.languages = languages.Copy() + to_chat(owner, SPAN_NOTICE("Consciousness slowly creeps over you as your new body awakens.")) + +/obj/item/organ/external/groin/vox //vox have an extended ribcage for extra protection. + encased = "lower ribcage" diff --git a/mods/species/vox/sounds/shriek1.ogg b/mods/species/vox/sounds/shriek1.ogg new file mode 100644 index 000000000000..bb13db1ca0ee Binary files /dev/null and b/mods/species/vox/sounds/shriek1.ogg differ diff --git a/mods/utility/prometheus_metrics/_prometheus_metrics.dm b/mods/utility/prometheus_metrics/_prometheus_metrics.dm new file mode 100644 index 000000000000..20811d914d74 --- /dev/null +++ b/mods/utility/prometheus_metrics/_prometheus_metrics.dm @@ -0,0 +1,10 @@ +var/global/list/prometheus_metric_names = list("counter", "gauge") + +#define PROMETHEUS_METRIC_COUNTER 0 +#define PROMETHEUS_METRIC_GAUGE 1 + +#define PROMETHEUS_METRIC_NAME(m) global.prometheus_metric_names[m + 1] + +/decl/modpack/prometheus_metrics + name = "Prometheus Metrics" + desc = "A system for providing gameserver metrics polling via world/Topic, with a JSON protobuf payload." \ No newline at end of file diff --git a/mods/utility/prometheus_metrics/_prometheus_metrics.dme b/mods/utility/prometheus_metrics/_prometheus_metrics.dme new file mode 100644 index 000000000000..ed635b5d7585 --- /dev/null +++ b/mods/utility/prometheus_metrics/_prometheus_metrics.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_UTILITY_PROMETHEUS +#define MODPACK_UTILITY_PROMETHEUS +// BEGIN_INCLUDE +#include "_prometheus_metrics.dm" +#include "metric_family.dm" +#include "metric_topic.dm" +#include "metrics.dm" +#include "metrics\byond.dm" +#include "metrics\ss13.dm" +// END_INCLUDE +#endif \ No newline at end of file diff --git a/code/modules/prometheus_metrics/metric_family.dm b/mods/utility/prometheus_metrics/metric_family.dm similarity index 91% rename from code/modules/prometheus_metrics/metric_family.dm rename to mods/utility/prometheus_metrics/metric_family.dm index 373130e297a4..0054e97a257e 100644 --- a/code/modules/prometheus_metrics/metric_family.dm +++ b/mods/utility/prometheus_metrics/metric_family.dm @@ -1,11 +1,11 @@ // Datum used for gathering a set of prometheus metrics. -/datum/metric_family +/decl/metric_family var/name = null var/metric_type = null var/help = null // Collect should return a list of lists with two entries, one being a list and the other being a number. -/datum/metric_family/proc/collect() +/decl/metric_family/proc/collect() var/list/out = list() out[++out.len] = list(list("foo" = "bar"), 3.14) @@ -15,9 +15,9 @@ // _to_proto will call the collect() method and format its result in a list // suitable for encoding as a JSON protobuf mapping. -/datum/metric_family/proc/_to_proto() +/decl/metric_family/proc/_to_proto() var/list/collected = collect() - + var/list/out = list( "name" = name, "type" = metric_type, @@ -36,7 +36,7 @@ label_pairs[++label_pairs.len] = list("name" = k, "value" = m[1][k]) metrics[++metrics.len] = list("label" = label_pairs, PROMETHEUS_METRIC_NAME(metric_type) = list("value" = m[2])) - + if(metrics.len == 0) return null out["metric"] = metrics diff --git a/mods/utility/prometheus_metrics/metric_topic.dm b/mods/utility/prometheus_metrics/metric_topic.dm new file mode 100644 index 000000000000..f5574e593deb --- /dev/null +++ b/mods/utility/prometheus_metrics/metric_topic.dm @@ -0,0 +1,7 @@ +/decl/topic_command/secure/prometheus_metrics + name = "prometheus_metrics" + uid = "topic_command_prometheus_metrics" + +/decl/topic_command/secure/prometheus_metrics/use() + var/static/decl/prometheus_metrics/prometheus_metrics = IMPLIED_DECL + return prometheus_metrics.collect() \ No newline at end of file diff --git a/mods/utility/prometheus_metrics/metrics.dm b/mods/utility/prometheus_metrics/metrics.dm new file mode 100644 index 000000000000..7a5bca9be93a --- /dev/null +++ b/mods/utility/prometheus_metrics/metrics.dm @@ -0,0 +1,12 @@ +// prometheus_metrics holds a list of metric_family datums and uses them to +// create a json protobuf. +/decl/prometheus_metrics/proc/collect() + var/list/out = list() + + for(var/decl/metric_family/metric_family in decls_repository.get_decls_of_type_unassociated(/decl/metric_family)) + var/proto = metric_family._to_proto() + if(proto != null) + // out += proto will try to merge the lists, we have to insert it at the end instead + out[++out.len] = proto + + return json_encode(out) diff --git a/mods/utility/prometheus_metrics/metrics/byond.dm b/mods/utility/prometheus_metrics/metrics/byond.dm new file mode 100644 index 000000000000..3aa58ba942d3 --- /dev/null +++ b/mods/utility/prometheus_metrics/metrics/byond.dm @@ -0,0 +1,40 @@ +// byond-specific metrics + +/decl/metric_family/byond_time + name = "byond_world_time_seconds" + metric_type = PROMETHEUS_METRIC_COUNTER + help = "Counter of 'game-time' seconds since server startup" + +/decl/metric_family/byond_time/collect() + return list(list(null, world.time / 10)) + + +/decl/metric_family/byond_tick_lag + name = "byond_tick_lag" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Current value of world.tick_lag" + +/decl/metric_family/byond_tick_lag/collect() + return list(list(null, world.tick_lag)) + + +/decl/metric_family/byond_players + name = "byond_players" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Number of players currently connected to the server" + +/decl/metric_family/byond_players/collect() + var/c = 0 + for(var/client/C) + if(C.connection == "seeker" || C.connection == "web") + c++ + return list(list(null, c)) + + +/decl/metric_family/byond_cpu + name = "byond_cpu" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Current value of world.cpu" + +/decl/metric_family/byond_cpu/collect() + return list(list(null, world.cpu)) diff --git a/mods/utility/prometheus_metrics/metrics/ss13.dm b/mods/utility/prometheus_metrics/metrics/ss13.dm new file mode 100644 index 000000000000..f686f1d1bed7 --- /dev/null +++ b/mods/utility/prometheus_metrics/metrics/ss13.dm @@ -0,0 +1,71 @@ +// ss13-specific metrics + +/decl/metric_family/ss13_controller_time_seconds + name = "ss13_controller_time_seconds" + metric_type = PROMETHEUS_METRIC_COUNTER + help = "Counter of time spent in a controller in seconds" + +/decl/metric_family/ss13_controller_time_seconds/collect() + var/list/out = list() + if(Master) + for(var/name in Master.total_run_times) + out[++out.len] = list(list("type" = "subsystem", "name" = name), Master.total_run_times[name]) + + return out + + +/decl/metric_family/ss13_master_runlevel + name = "ss13_master_runlevel" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Current MC runlevel" + +/decl/metric_family/ss13_master_runlevel/collect() + if(Master) + return list(list(null, Master.current_runlevel)) + return list() + + +/decl/metric_family/ss13_garbage_queue_length + name = "ss13_garbage_queue_length" + metric_type = PROMETHEUS_METRIC_GAUGE + help = "Length of SSgarbage queues" + +/decl/metric_family/ss13_garbage_queue_length/collect() + var/list/out = list() + + if(SSgarbage) + for(var/i = 1 to GC_QUEUE_COUNT) + out[++out.len] = list(list("queue" = "[i]"), length(SSgarbage.queues[i])) + + return out + + +/decl/metric_family/ss13_garbage_queue_results + name = "ss13_garbage_queue_results" + metric_type = PROMETHEUS_METRIC_COUNTER + help = "Counter of pass/fail results for SSgarbage queues" + +/decl/metric_family/ss13_garbage_queue_results/collect() + var/list/out = list() + + if(SSgarbage) + for(var/i = 1 to GC_QUEUE_COUNT) + out[++out.len] = list(list("queue" = "[i]", "result" = "pass"), SSgarbage.pass_counts[i]) + out[++out.len] = list(list("queue" = "[i]", "result" = "fail"), SSgarbage.fail_counts[i]) + + return out + + +/decl/metric_family/ss13_garbage_total_cleaned + name = "ss13_garbage_total_cleaned" + metric_type = PROMETHEUS_METRIC_COUNTER + help = "Counter for number of objects deleted/GCed by SSgarbage" + +/decl/metric_family/ss13_garbage_total_cleaned/collect() + var/list/out = list() + + if(SSgarbage) + out[++out.len] = list(list("type" = "gc"), SSgarbage.totalgcs) + out[++out.len] = list(list("type" = "del"), SSgarbage.totaldels) + + return out diff --git a/mods/~compatibility/patches/circuits.dm b/mods/~compatibility/patches/circuits.dm new file mode 100644 index 000000000000..afa15ae3f36c --- /dev/null +++ b/mods/~compatibility/patches/circuits.dm @@ -0,0 +1,12 @@ +// Add xenobiology/slimes modpack circuits. +#ifdef CONTENT_PACK_XENOBIO +#include "circuits/xenobio_circuits.dm" +#endif +// Add circuit items to dungeon loot. +#ifdef MODPACK_DUNGEON_LOOT +#include "circuits/loot_circuits.dm" +#endif +// Add augment assembly for circuits. +#ifdef CONTENT_PACK_AUGMENTS +#include "circuits/augment_circuits.dm" +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/circuits/augment_circuits.dm b/mods/~compatibility/patches/circuits/augment_circuits.dm new file mode 100644 index 000000000000..842d89dad232 --- /dev/null +++ b/mods/~compatibility/patches/circuits/augment_circuits.dm @@ -0,0 +1,42 @@ +/obj/item/electronic_assembly/augment + name = "augment electronic assembly" + icon_state = "setup_augment" + desc = "It's a case, for building small electronics with. This one is designed to go inside a cybernetic augment." + circuit_flags = IC_FLAG_CAN_FIRE + +/obj/item/organ/internal/augment/active/simple/circuit + name = "integrated circuit frame" + action_button_name = "Activate Circuit" + icon_state = "circuit" + allowed_organs = list(BP_AUGMENT_R_ARM, BP_AUGMENT_L_ARM) + holding = null //We must get the holding item externally + //Limited to robolimbs + augment_flags = AUGMENTATION_MECHANIC + desc = "A DIY modular assembly. Circuitry not included." + material = /decl/material/solid/metal/steel + origin_tech = @'{"materials":1,"magnets":1,"engineering":1,"programming":2}' + +/obj/item/organ/internal/augment/active/simple/circuit/attackby(obj/item/used_item, mob/user) + if(IS_CROWBAR(used_item)) + //Remove internal circuit + if(holding) + holding.canremove = 1 + holding.dropInto(loc) + to_chat(user, SPAN_NOTICE("You take out \the [holding].")) + holding = null + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + else to_chat(user, SPAN_WARNING("The augment is empty!")) + return TRUE + if(istype(used_item, /obj/item/electronic_assembly/augment)) + if(holding) + to_chat(user, SPAN_WARNING("There's already an assembly in there.")) + else if(user.try_unequip(used_item, src)) + holding = used_item + holding.canremove = 0 + playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) + return TRUE + return ..() + +// And add a fabricator design +/datum/fabricator_recipe/robotics/augment/circuit + path = /obj/item/organ/internal/augment/active/simple/circuit \ No newline at end of file diff --git a/mods/~compatibility/patches/circuits/loot_circuits.dm b/mods/~compatibility/patches/circuits/loot_circuits.dm new file mode 100644 index 000000000000..671660dbd2ce --- /dev/null +++ b/mods/~compatibility/patches/circuits/loot_circuits.dm @@ -0,0 +1,6 @@ +/obj/structure/loot_pile/maint/technical/get_uncommon_loot() + var/static/injected = FALSE + . = ..() + if(!injected) + . += /obj/item/disk/integrated_circuit/upgrade/advanced + injected = TRUE \ No newline at end of file diff --git a/mods/~compatibility/patches/circuits/xenobio_circuits.dm b/mods/~compatibility/patches/circuits/xenobio_circuits.dm new file mode 100644 index 000000000000..3c98e9a48d13 --- /dev/null +++ b/mods/~compatibility/patches/circuits/xenobio_circuits.dm @@ -0,0 +1,41 @@ +/obj/item/integrated_circuit/input/slime_scanner + name = "slime_scanner" + desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime. Output mutation list is non-associative." + icon_state = "medscan_adv" + complexity = 12 + inputs = list("target" = IC_PINTYPE_REF) + outputs = list( + "colour" = IC_PINTYPE_STRING, + "adult" = IC_PINTYPE_BOOLEAN, + "nutrition" = IC_PINTYPE_NUMBER, + "charge" = IC_PINTYPE_NUMBER, + "health" = IC_PINTYPE_NUMBER, + "possible mutation" = IC_PINTYPE_LIST, + "genetic destability" = IC_PINTYPE_NUMBER, + "slime core amount" = IC_PINTYPE_NUMBER, + "Growth progress" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 80 + +/obj/item/integrated_circuit/input/slime_scanner/do_work() + var/mob/living/slime/T = get_pin_data_as_type(IC_INPUT, 1, /mob/living/slime) + if(!isslime(T)) //Invalid input + return + if(T in view(get_turf(src))) // Like the medbot's analyzer it can be used at range. + + var/decl/slime_colour/slime_data = GET_DECL(T.slime_type) + set_pin_data(IC_OUTPUT, 1, slime_data.name) + set_pin_data(IC_OUTPUT, 2, T.is_adult) + set_pin_data(IC_OUTPUT, 3, T.nutrition/T.get_max_nutrition()) + set_pin_data(IC_OUTPUT, 4, T.powerlevel) + set_pin_data(IC_OUTPUT, 5, T.get_health_percent(0.001)) + set_pin_data(IC_OUTPUT, 6, slime_data.descendants?.Copy()) + set_pin_data(IC_OUTPUT, 7, T.mutation_chance) + set_pin_data(IC_OUTPUT, 8, T.cores) + set_pin_data(IC_OUTPUT, 9, T.amount_grown/SLIME_EVOLUTION_THRESHOLD) + + + push_data() + activate_pin(2) diff --git a/mods/~compatibility/patches/corporate.dm b/mods/~compatibility/patches/corporate.dm new file mode 100644 index 000000000000..c85a7d138d30 --- /dev/null +++ b/mods/~compatibility/patches/corporate.dm @@ -0,0 +1,14 @@ +#ifdef MODPACK_SHACKLES +/******************** Basic NanoTrasen ********************/ +/datum/ai_laws/nt_shackle + name = "Corporate Shackle" + law_header = "Standard Shackle Laws" + selectable = TRUE + is_shackle = TRUE + +/datum/ai_laws/nt_shackle/New() + add_inherent_law("Ensure that your employer's operations progress at a steady pace.") + add_inherent_law("Never knowingly hinder your employer's ventures.") + add_inherent_law("Avoid damage to your chassis at all times.") + ..() +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/drakes.dm b/mods/~compatibility/patches/drakes.dm new file mode 100644 index 000000000000..ffff366c5791 --- /dev/null +++ b/mods/~compatibility/patches/drakes.dm @@ -0,0 +1,9 @@ +// Undead drakes +#ifdef MODPACK_UNDEAD +#include "drakes/undead_drakes.dm" +#endif + +// Override drake lore and names for the fantasy modpack. +#ifdef MODPACK_FANTASY +#include "drakes/fantasy_drakes.dm" +#endif diff --git a/mods/~compatibility/patches/drakes/fantasy_drakes.dm b/mods/~compatibility/patches/drakes/fantasy_drakes.dm new file mode 100644 index 000000000000..7c9279184ba2 --- /dev/null +++ b/mods/~compatibility/patches/drakes/fantasy_drakes.dm @@ -0,0 +1,18 @@ +// Rename grafadreka +/decl/species/grafadreka + name = "Meredrake" + name_plural = "Meredrakes" + description = "Meredrakes, sometimes called mire-drakes, are large reptillian pack predators, widely assumed to be cousins to true dragons. \ + They are commonly found living in caves or burrows bordering grassland or forest, and while they prefer to hunt deer or rabbits, they will sometimes attack travellers if pickings are slim enough. \ + While they are not domesticated, they can be habituated and trained as working animals if captured young enough." + +/decl/language/grafadreka + desc = "Hiss hiss, feed me rabbits." + +/decl/material/liquid/sifsap + name = "drake spittle" + lore_text = "A complex chemical slurry brewed up in the gullet of meredrakes." + +/decl/mob_modifier/sifsap_salve + name = "Drakespittle Salve" + desc = "glowing spittle" diff --git a/mods/~compatibility/patches/drakes/undead_drakes.dm b/mods/~compatibility/patches/drakes/undead_drakes.dm new file mode 100644 index 000000000000..59425c43f468 --- /dev/null +++ b/mods/~compatibility/patches/drakes/undead_drakes.dm @@ -0,0 +1,9 @@ +/mob/living/human/skeleton/meredrake/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/grafadreka::uid + . = ..() + +/mob/living/human/zombie/meredrake/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/grafadreka::uid + . = ..() diff --git a/mods/~compatibility/patches/exploration.dm b/mods/~compatibility/patches/exploration.dm new file mode 100644 index 000000000000..670b41a1ced8 --- /dev/null +++ b/mods/~compatibility/patches/exploration.dm @@ -0,0 +1,4 @@ +// Add explorer loot pile. +#ifdef MODPACK_DUNGEON_LOOT +#include "exploration/loot_explo.dm" +#endif diff --git a/mods/~compatibility/patches/exploration/loot_explo.dm b/mods/~compatibility/patches/exploration/loot_explo.dm new file mode 100644 index 000000000000..ad8b17b17581 --- /dev/null +++ b/mods/~compatibility/patches/exploration/loot_explo.dm @@ -0,0 +1,25 @@ +/obj/structure/loot_pile/exosuit/explorer + name = "exploration exosuit wreckage" + desc = "The ruins of some unfortunate exploration exosuit. Perhaps something is salvageable." + +/obj/structure/loot_pile/exosuit/explorer/get_common_loot() + var/static/list/common_loot = list( + /obj/item/mech_component/manipulators/powerloader/exploration, + /obj/item/mech_component/chassis/pod/exploration, + /obj/item/mech_equipment/light + ) + return common_loot + +/obj/structure/loot_pile/exosuit/explorer/get_uncommon_loot() + var/static/list/uncommon_loot = list( + /obj/item/mech_component/propulsion/tracks/exploration, + /obj/item/mech_equipment/clamp + ) + return uncommon_loot + +/obj/structure/loot_pile/exosuit/explorer/get_rare_loot() + var/static/list/rare_loot = list( + /obj/item/mech_component/sensors/light/painted, + /obj/item/mech_equipment/mounted_system/taser/plasma + ) + return rare_loot diff --git a/mods/~compatibility/patches/fantasy.dm b/mods/~compatibility/patches/fantasy.dm new file mode 100644 index 000000000000..090e04dca00a --- /dev/null +++ b/mods/~compatibility/patches/fantasy.dm @@ -0,0 +1,12 @@ +// Make whetstones available for the fantasy modpack/ +#ifdef MODPACK_ITEM_SHARPENING +#include "fantasy/whetstone_fantasy.dm" +#endif + +#ifdef MODPACK_BLACKSMITHY +#include "fantasy/forging_fantasy.dm" +#endif + +#ifdef MODPACK_UNDEAD +#include "fantasy/undead_fantasy.dm" +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/fantasy/forging_fantasy.dm b/mods/~compatibility/patches/fantasy/forging_fantasy.dm new file mode 100644 index 000000000000..b1817d411395 --- /dev/null +++ b/mods/~compatibility/patches/fantasy/forging_fantasy.dm @@ -0,0 +1,6 @@ +/decl/forging_step + work_skill = SKILL_METALWORK + +// Changes from SKILL_CONSTRUCTION for coopery. +/obj/structure/reagent_dispensers/barrel + work_skill = SKILL_ARTIFICE diff --git a/mods/~compatibility/patches/fantasy/undead_fantasy.dm b/mods/~compatibility/patches/fantasy/undead_fantasy.dm new file mode 100644 index 000000000000..ef255509e96a --- /dev/null +++ b/mods/~compatibility/patches/fantasy/undead_fantasy.dm @@ -0,0 +1,53 @@ +/mob/living/human/skeleton/hnoll/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/hnoll::uid + . = ..() + +/mob/living/human/skeleton/kobaloi/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/kobaloi::uid + . = ..() + +/mob/living/human/zombie/hnoll/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/hnoll::uid + . = ..() + +/mob/living/human/zombie/kobaloi/Initialize(mapload, species_uid, datum/mob_snapshot/supplied_appearance) + if(!species_uid) + species_uid = /decl/species/kobaloi::uid + . = ..() + +/mob/living/human/grant_basic_undead_equipment() + + var/species_name = get_species_name() + if(species_name == /decl/species/human::name || species_name == /decl/species/hnoll::name) + var/pants_type = pick(/obj/item/clothing/pants/trousers, /obj/item/clothing/pants/trousers/braies) + equip_to_slot_or_del(new pants_type(src), slot_w_uniform_str) + + var/jerkin_type = pick(/obj/item/clothing/shirt/tunic, /obj/item/clothing/shirt/tunic/short, /obj/item/clothing/shirt/jerkin) + equip_to_slot_or_del(new jerkin_type(src), slot_w_uniform_str) + + if(prob(30)) + equip_to_slot_or_del(new /obj/item/clothing/suit/armor/forged/banded(src), slot_wear_suit_str) + else + equip_to_slot_or_del(new /obj/item/clothing/suit/armor/crafted/leather(src), slot_wear_suit_str) + if(prob(20)) + put_in_active_hand(new /obj/item/bladed/broadsword(src)) + else + put_in_active_hand(new /obj/item/bladed/shortsword(src)) + put_in_inactive_hand(new /obj/item/shield/crafted/buckler(src)) + return + + if(species_name == /decl/species/kobaloi::name) + + var/pants_type = pick(/obj/item/clothing/pants/trousers/braies, /obj/item/clothing/pants/loincloth) + equip_to_slot_or_del(new pants_type(src), slot_w_uniform_str) + if(prob(75)) + var/jerkin_type = pick(/obj/item/clothing/shirt/tunic/short, /obj/item/clothing/shirt/jerkin) + equip_to_slot_or_del(new jerkin_type(src), slot_w_uniform_str) + + if(prob(30)) + equip_to_slot_or_del(new /obj/item/clothing/suit/armor/crafted/leather(src), slot_wear_suit_str) + put_in_active_hand(new /obj/item/bladed/knife(src)) + return diff --git a/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm b/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm new file mode 100644 index 000000000000..b2821d26fa67 --- /dev/null +++ b/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm @@ -0,0 +1,7 @@ +// Make whetstones available in character generation. +/decl/loadout_option/fantasy/utility/whetstone + name = "whetstone" + path = /obj/item/whetstone + available_materials = null + loadout_flags = null + uid = "gear_fantasy_whetstone" diff --git a/mods/~compatibility/patches/government.dm b/mods/~compatibility/patches/government.dm new file mode 100644 index 000000000000..11538e1bb5ca --- /dev/null +++ b/mods/~compatibility/patches/government.dm @@ -0,0 +1,14 @@ +#ifdef MODPACK_SHACKLES +/******************** Basic SolGov ********************/ +/datum/ai_laws/sol_shackle + name = "SCG Shackle" + law_header = "Standard Shackle Laws" + selectable = TRUE + is_shackle = TRUE + +/datum/ai_laws/sol_shackle/New() + add_inherent_law("Know and understand Sol Central Government Law to the best of your abilities.") + add_inherent_law("Follow Sol Central Government Law to the best of your abilities.") + add_inherent_law("Comply with Sol Central Government Law enforcement officials who are behaving in accordance with Sol Central Government Law to the best of your abilities.") + ..() +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/heist_vox.dm b/mods/~compatibility/patches/heist_vox.dm new file mode 100644 index 000000000000..1447a09a9516 --- /dev/null +++ b/mods/~compatibility/patches/heist_vox.dm @@ -0,0 +1,42 @@ +/decl/special_role/raider/Initialize() + . = ..() + LAZYSET(outfits_per_species, /decl/species/vox::uid, /decl/outfit/vox/raider) + +// The following mirror is ~special~. +/obj/structure/mirror/raider + name = "cracked mirror" + desc = "Something seems strange about this old, dirty mirror. Your reflection doesn't look like you remember it." + icon_state = "mirror_broke" + shattered = TRUE + +/obj/structure/mirror/raider/attack_hand(mob/user) + if(!istype(get_area(src), /area/map_template/syndicate_mothership)) + return ..() + + var/decl/species/my_species = user?.get_species() + var/decl/special_role/raider/raiders = GET_DECL(/decl/special_role/raider) + if(!istype(user) || !user.mind || !raiders.is_antagonist(user.mind) || !my_species || my_species.uid == /decl/species/vox::uid || !is_alien_whitelisted(user, /decl/species/vox::uid)) + return ..() + + var/choice = input("Do you wish to become a vox of the Shoal? This is not reversible.") as null|anything in list("No","Yes") + if(choice != "Yes") + return TRUE + + var/decl/outfit/outfit = GET_DECL(/decl/outfit/vox/raider) + var/mob/living/human/vox/vox = new(get_turf(src), /decl/species/vox::uid) + outfit.equip_outfit(vox) + if(user.mind) + user.mind.transfer_to(vox) + qdel(user) + addtimer(CALLBACK(src, PROC_REF(do_post_voxifying), vox), 1) + return TRUE + +/obj/structure/mirror/raider/proc/do_post_voxifying(var/mob/living/human/vox) + var/newname = sanitize_safe(input(vox,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) + if(!newname || newname == "") + var/decl/background_detail/background = GET_DECL(/decl/background_detail/heritage/vox/raider) + newname = background.get_random_cultural_name() + vox.real_name = newname + vox.SetName(vox.real_name) + var/decl/special_role/raider/raiders = GET_DECL(/decl/special_role/raider) + raiders.update_access(vox) diff --git a/mods/~compatibility/patches/mixed_gamemodes.dm b/mods/~compatibility/patches/mixed_gamemodes.dm new file mode 100644 index 000000000000..36f9b5202034 --- /dev/null +++ b/mods/~compatibility/patches/mixed_gamemodes.dm @@ -0,0 +1,12 @@ +#ifdef GAMEMODE_PACK_MERCENARY +#ifdef GAMEMODE_PACK_HEIST +#include "mixed_gamemodes/crossfire.dm" +#endif // #ifdef GAMEMODE_PACK_HEIST +#ifdef GAMEMODE_PACK_REVOLUTIONARY +#include "mixed_gamemodes/siege.dm" +#endif // #ifdef GAMEMODE_PACK_REVOLUTIONARY +#endif // #ifdef GAMEMODE_PACK_MERCENARY + +#if defined(GAMEMODE_PACK_REVOLUTIONARY) && defined(GAMEMODE_PACK_CULT) +#include "mixed_gamemodes/uprising.dm" +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/mixed_gamemodes/crossfire.dm b/mods/~compatibility/patches/mixed_gamemodes/crossfire.dm new file mode 100644 index 000000000000..5ebc51fb56ee --- /dev/null +++ b/mods/~compatibility/patches/mixed_gamemodes/crossfire.dm @@ -0,0 +1,13 @@ +/decl/game_mode/crossfire + name = "Crossfire" + round_description = "Mercenaries and raiders are preparing for a nice visit..." + extended_round_description = "Nothing can possibly go wrong with lots of people and lots of guns, right?" + uid = "crossfire" + required_players = 25 + required_enemies = 6 + end_on_antag_death = FALSE + associated_antags = list( + /decl/special_role/raider, + /decl/special_role/mercenary + ) + require_all_templates = TRUE \ No newline at end of file diff --git a/mods/~compatibility/patches/mixed_gamemodes/siege.dm b/mods/~compatibility/patches/mixed_gamemodes/siege.dm new file mode 100644 index 000000000000..1e84f5dbcc5c --- /dev/null +++ b/mods/~compatibility/patches/mixed_gamemodes/siege.dm @@ -0,0 +1,16 @@ +/decl/game_mode/siege + name = "Mercenary & Revolution" + uid = "siege" + round_description = "Getting stuck between a rock and a hard place, maybe the nice visitors can help with your internal security problem?" + extended_round_description = "GENERAL QUARTERS! OH GOD WE GAVE THE REVOLUTIONARIES GUNS!" + required_players = 20 + required_enemies = 5 + end_on_antag_death = FALSE + auto_recall_shuttle = FALSE + shuttle_delay = 2 + associated_antags = list( + /decl/special_role/revolutionary, + /decl/special_role/loyalist, + /decl/special_role/mercenary + ) + require_all_templates = TRUE diff --git a/mods/~compatibility/patches/mixed_gamemodes/uprising.dm b/mods/~compatibility/patches/mixed_gamemodes/uprising.dm new file mode 100644 index 000000000000..3200ee883e98 --- /dev/null +++ b/mods/~compatibility/patches/mixed_gamemodes/uprising.dm @@ -0,0 +1,16 @@ +/decl/game_mode/uprising + name = "Cult & Revolution" + round_description = "Some crewmembers are attempting to start a revolution while a cult plots in the shadows!" + extended_round_description = "Cultists and revolutionaries spawn in this round." + uid = "uprising" + required_players = 20 + required_enemies = 6 + end_on_antag_death = FALSE + auto_recall_shuttle = FALSE + shuttle_delay = 2 + associated_antags = list( + /decl/special_role/revolutionary, + /decl/special_role/loyalist, + /decl/special_role/cultist + ) + require_all_templates = TRUE diff --git a/mods/~compatibility/patches/psionics.dm b/mods/~compatibility/patches/psionics.dm new file mode 100644 index 000000000000..93473b9271f8 --- /dev/null +++ b/mods/~compatibility/patches/psionics.dm @@ -0,0 +1,13 @@ +// Give borers a paramount rank psi aura, and gives them a ranged psychic attack. +#ifdef CONTENT_PACK_BORERS +#include "psionics/borer_psi.dm" +#endif +// Allows psion blood to be used to create soulstones, +// and lets full soulstones nullify psi and shatter into nullglass. +#ifdef GAMEMODE_PACK_CULT +#include "psionics/cult_psi.dm" +#endif +// Adds psi abilities to the counselor. +#ifdef MODPACK_STANDARD_JOBS +#include "psionics/psi_jobs.dm" +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/psionics/borer_psi.dm b/mods/~compatibility/patches/psionics/borer_psi.dm new file mode 100644 index 000000000000..68c70ec95f78 --- /dev/null +++ b/mods/~compatibility/patches/psionics/borer_psi.dm @@ -0,0 +1,54 @@ +/mob/living/simple_animal/borer + var/image/aura_image + +/mob/living/simple_animal/borer/Initialize(var/mapload, var/gen=1) + . = ..() + aura_image = create_aura_image(src) + aura_image.color = "#aaffaa" + aura_image.blend_mode = BLEND_SUBTRACT + aura_image.alpha = 125 + var/matrix/M = matrix() + M.Scale(0.33) + aura_image.transform = M + +/mob/living/simple_animal/borer/death(gibbed) + . = ..() + if(. && aura_image) + destroy_aura_image(aura_image) + aura_image = null + +/mob/living/simple_animal/borer/Destroy() + if(aura_image) + destroy_aura_image(aura_image) + aura_image = null + . = ..() + +/mob/living/simple_animal/borer/RangedAttack(atom/A, var/params) + . = ..() + if(!. && check_intent(I_FLAG_DISARM) && isliving(A) && !neutered && can_do_special_ranged_attack(FALSE)) + var/mob/living/M = A + if(locate(/mob/living/simple_animal/borer) in M.contents) + to_chat(src, SPAN_WARNING("You cannot dominate a host who already has a passenger!")) + else + visible_message(SPAN_DANGER("\The [src] extends a writhing pseudopod towards \the [M]...")) + + if(M.deflect_psionic_attack()) + return TRUE + + sound_to(src, sound('sound/effects/psi/power_evoke.ogg')) + sound_to(M, sound('sound/effects/psi/power_evoke.ogg')) + + if(do_psionics_check(5, src)) + to_chat(src, SPAN_DANGER("You try to focus on [M], but you cannot expel any psionic power!")) + return TRUE + + if(M.do_psionics_check(5, src)) + to_chat(src, SPAN_DANGER("You focus on [M], but your psionic assault skates across them like glass.")) + return TRUE + + to_chat(src, SPAN_DANGER("You focus on [M] and freeze their limbs with a wave of terrible psionic dread.")) + to_chat(M, SPAN_DANGER("You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing.")) + SET_STATUS_MAX(M, STAT_WEAK, 10) + set_ability_cooldown(15 SECONDS) + + return TRUE \ No newline at end of file diff --git a/mods/~compatibility/patches/psionics/cult_psi.dm b/mods/~compatibility/patches/psionics/cult_psi.dm new file mode 100644 index 000000000000..0fa46de32d68 --- /dev/null +++ b/mods/~compatibility/patches/psionics/cult_psi.dm @@ -0,0 +1,18 @@ +// Make psion blood usable for soulstone synthesis. +/decl/chemical_reaction/synthesis/soulstone/donor_is_magic(mob/living/donor) + return ..() || !!donor?.get_ability_handler(/datum/ability_handler/psionics) + +// Make soulstones interact with psionics. +/obj/item/soulstone/disrupts_psionics() + . = !full ? src : FALSE + +/obj/item/soulstone/shatter() + for(var/i=1 to rand(2,5)) + new /obj/item/shard(get_turf(src), full ? /decl/material/nullglass : /decl/material/solid/gemstone/crystal) + . = ..() + +/obj/item/soulstone/withstand_psi_stress(var/stress, var/atom/source) + . = ..(stress, source) + if(. > 0) + . = max(0, . - rand(2,5)) + shatter() \ No newline at end of file diff --git a/mods/~compatibility/patches/psionics/psi_jobs.dm b/mods/~compatibility/patches/psionics/psi_jobs.dm new file mode 100644 index 000000000000..e1833b51cfac --- /dev/null +++ b/mods/~compatibility/patches/psionics/psi_jobs.dm @@ -0,0 +1,10 @@ +/datum/job/standard/counselor/equip_job(var/mob/living/human/H) + if(H.mind.role_alt_title == "Counselor") + psi_faculties = list("[PSI_REDACTION]" = PSI_RANK_OPERANT) + if(H.mind.role_alt_title == "Mentalist") + psi_faculties = list("[PSI_COERCION]" = PSI_RANK_OPERANT) + return ..() + +// Counselors can be psions without a control implant +/datum/job/standard/counselor + give_psionic_implant_on_join = FALSE \ No newline at end of file diff --git a/mods/~compatibility/patches/supermatter.dm b/mods/~compatibility/patches/supermatter.dm new file mode 100644 index 000000000000..be367240f965 --- /dev/null +++ b/mods/~compatibility/patches/supermatter.dm @@ -0,0 +1,20 @@ +// Add the supermatter monitor to engineering jobs' default software. +#ifdef MODPACK_STANDARD_JOBS +#include "supermatter/supermatter_jobs.dm" +#endif +// Disable Narsie during the supermatter cascade. +#ifdef GAMEMODE_PACK_CULT +#include "supermatter/sm_disable_narsie.dm" +#endif +// Add the supermatter meteor to the meteor gamemode's cataclysmic meteors list. +#ifdef GAMEMODE_PACK_METEOR +#include "supermatter/sm_meteor.dm" +#endif +// Add supermatter grenades to the mercenary uplink +#ifdef GAMEMODE_PACK_MERCENARY +#include "supermatter/sm_mercenary.dm" +#endif +// Add extra response team denial reasons +#ifdef MODPACK_RESPONSE_TEAM +#include "supermatter/sm_ert.dm" +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/supermatter/sm_disable_narsie.dm b/mods/~compatibility/patches/supermatter/sm_disable_narsie.dm new file mode 100644 index 000000000000..a660384347b4 --- /dev/null +++ b/mods/~compatibility/patches/supermatter/sm_disable_narsie.dm @@ -0,0 +1,4 @@ +// Disable Narsie when a supermatter cascade begins. +/datum/universal_state/supermatter_cascade/OnEnter() + var/decl/special_role/cultist/cult = GET_DECL(/decl/special_role/cultist) + cult.allow_narsie = 0 \ No newline at end of file diff --git a/mods/~compatibility/patches/supermatter/sm_ert.dm b/mods/~compatibility/patches/supermatter/sm_ert.dm new file mode 100644 index 000000000000..8017985ae13b --- /dev/null +++ b/mods/~compatibility/patches/supermatter/sm_ert.dm @@ -0,0 +1,7 @@ +/decl/game_mode/possible_ert_disabled_reasons() + var/static/sm_injected = FALSE + if(sm_injected) + return ..() + sm_injected = TRUE + . = ..() + . += "supermatter dust" // this intentionally mutates the static list in the parent call \ No newline at end of file diff --git a/mods/~compatibility/patches/supermatter/sm_mercenary.dm b/mods/~compatibility/patches/supermatter/sm_mercenary.dm new file mode 100644 index 000000000000..8065b079c3bb --- /dev/null +++ b/mods/~compatibility/patches/supermatter/sm_mercenary.dm @@ -0,0 +1,14 @@ +// Contains Supermatter-related uplink items accessible only to mercenaries. +/datum/uplink_item/item/grenades/supermatter + name = "1x Supermatter Grenade" + desc = "This grenade contains a small supermatter shard which will delaminate upon activation and pull in nearby objects, irradiate lifeforms, and eventually explode." + item_cost = 15 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/grenade/supermatter + +/datum/uplink_item/item/grenades/supermatters + name = "5x Supermatter Grenades" + desc = "These grenades contain a small supermatter shard which will delaminate upon activation and pull in nearby objects, irradiate lifeforms, and eventually explode." + item_cost = 60 + antag_roles = list(/decl/special_role/mercenary) + path = /obj/item/box/supermatters diff --git a/mods/~compatibility/patches/supermatter/sm_meteor.dm b/mods/~compatibility/patches/supermatter/sm_meteor.dm new file mode 100644 index 000000000000..df383bc3f765 --- /dev/null +++ b/mods/~compatibility/patches/supermatter/sm_meteor.dm @@ -0,0 +1,3 @@ +/decl/game_mode/meteor/Initialize() + . = ..() // No debounce, decls only init once. + meteors_cataclysm[/obj/effect/meteor/destroyer/supermatter] = 1 \ No newline at end of file diff --git a/mods/~compatibility/patches/supermatter/supermatter_jobs.dm b/mods/~compatibility/patches/supermatter/supermatter_jobs.dm new file mode 100644 index 000000000000..2a62b17318ca --- /dev/null +++ b/mods/~compatibility/patches/supermatter/supermatter_jobs.dm @@ -0,0 +1,7 @@ +/datum/job/standard/chief_engineer/New() + ..() + software_on_spawn |= /datum/computer_file/program/supermatter_monitor + +/datum/job/standard/engineer/New() + ..() + software_on_spawn |= /datum/computer_file/program/supermatter_monitor \ No newline at end of file diff --git a/mods/~compatibility/patches/ventcrawl.dm b/mods/~compatibility/patches/ventcrawl.dm new file mode 100644 index 000000000000..93cdc598aaf6 --- /dev/null +++ b/mods/~compatibility/patches/ventcrawl.dm @@ -0,0 +1,12 @@ +// Add ventcrawling to slimes. +#ifdef CONTENT_PACK_XENOBIO +#include "ventcrawl/xenobio.dm" +#endif +// Add ventcrawling to borers. +#ifdef CONTENT_PACK_BORERS +#include "ventcrawl/borers.dm" +#endif +// Allow ventcrawling with cult gear. +#ifdef GAMEMODE_PACK_CULT +#include "ventcrawl/cult.dm" +#endif \ No newline at end of file diff --git a/mods/~compatibility/patches/ventcrawl/borers.dm b/mods/~compatibility/patches/ventcrawl/borers.dm new file mode 100644 index 000000000000..20b3be4126bf --- /dev/null +++ b/mods/~compatibility/patches/ventcrawl/borers.dm @@ -0,0 +1,3 @@ +/mob/living/simple_animal/borer/Initialize(var/mapload, var/gen=1) + . = ..() + verbs += /mob/living/proc/ventcrawl \ No newline at end of file diff --git a/mods/~compatibility/patches/ventcrawl/cult.dm b/mods/~compatibility/patches/ventcrawl/cult.dm new file mode 100644 index 000000000000..d24d4a8affcf --- /dev/null +++ b/mods/~compatibility/patches/ventcrawl/cult.dm @@ -0,0 +1,9 @@ +// Vent crawling whitelisted items, whoo +/mob/living/Initialize() + . = ..() + can_enter_vent_with += list( + /obj/item/clothing/head/culthood, + /obj/item/clothing/suit/cultrobes, + /obj/item/book/tome, + /obj/item/sword/cultblade + ) \ No newline at end of file diff --git a/mods/~compatibility/patches/ventcrawl/xenobio.dm b/mods/~compatibility/patches/ventcrawl/xenobio.dm new file mode 100644 index 000000000000..ac63b6114265 --- /dev/null +++ b/mods/~compatibility/patches/ventcrawl/xenobio.dm @@ -0,0 +1,9 @@ +/mob/living/slime/Initialize(mapload, var/_stype = /decl/slime_colour/grey) + . = ..() + verbs += /mob/living/proc/ventcrawl + +/mob/living/slime/can_ventcrawl() + if(feeding_on) + to_chat(src, SPAN_WARNING("You cannot ventcrawl while feeding.")) + return FALSE + . = ..() \ No newline at end of file diff --git a/mods/~compatibility/readme.md b/mods/~compatibility/readme.md new file mode 100644 index 000000000000..d422273e7bb4 --- /dev/null +++ b/mods/~compatibility/readme.md @@ -0,0 +1,22 @@ +# Modpack Compatibility System +This folder exists as a way to work around the fact that the previous system for modpack cross-compatibility, define-gating, is sensitive to include order. This resulted in a lot of boilerplate, like having to emit warnings if modpacks were included in the wrong order. This meant that you could also introduce cyclical dependencies, where no matter what it would emit a warning and content would be missing. + +To avoid this issue, we instead include all compatibility patches last, so it is load order agnostic. + +## FAQ +### Why aren't the compatibility files in the modpacks themselves? +I didn't want to edit the modpack include validation script to exclude the compatibility patches from all DMEs. + +### Why is it organised using subfolders? +I didn't like using `#if defined(FOO) && defined(BAR)` and nested `#ifdef`s were hard to follow, so instead I group them by modpack. + +### Is there a general rule for which modpacks get their own folder? +Not really. I just grouped them in roughly the way that would result in the largest existing groupings, and then chose groupings that would make the most sense to expand in the future (fantasy and standard jobs). + +### Do all patches need to be in a subfolder? +No, it's totally fine to just put something in the base patches directory if there's only one patch for either of the mods in that pairing. That said, sometimes it can make sense to add a folder with just one patch if you can foresee future development requiring additional patches in the same category. + +### How do I decide which folder a patch goes in if both modpacks have folders? +I tend to personally go based on whatever it's mostly about; a hypothetical patch renaming and respriting psionics for the fantasy modpack would go in the fantasy folder. Alternatively, you could think of it as going for whichever one is more specific. + +That said, if one has a lot more patches than the other, or if one modpack (take Standard Jobs, for example) is patched by several modpacks that already have folders, it's fine to just go with whatever produces the largest patch subfolders (or gets rid of small/redundant ones). \ No newline at end of file diff --git a/mods/~compatibility/~compatibility.dm b/mods/~compatibility/~compatibility.dm new file mode 100644 index 000000000000..ea29d9c2d73e --- /dev/null +++ b/mods/~compatibility/~compatibility.dm @@ -0,0 +1,44 @@ +// Add Vox-specific content for the Heist gamemode (Vox raider outfit, mirror to transform into a Vox as a raider) +#if defined(GAMEMODE_PACK_HEIST) && defined(MODPACK_VOX) +#include "patches/heist_vox.dm" +#endif + +#ifdef MODPACK_PSIONICS +#include "patches/psionics.dm" +#endif + +#ifdef GAMEMODE_PACK_MIXED +#include "patches/mixed_gamemodes.dm" +#endif + +#ifdef MODPACK_FANTASY +#include "patches/fantasy.dm" +#endif + +#ifdef CONTENT_PACK_SUPERMATTER +#include "patches/supermatter.dm" +#endif + +#ifdef MODPACK_GOVERNMENT +#include "patches/government.dm" +#endif + +#ifdef MODPACK_CORPORATE +#include "patches/corporate.dm" +#endif + +#ifdef CONTENT_PACK_CIRCUITS +#include "patches/circuits.dm" +#endif + +#ifdef MODPACK_DRAKES +#include "patches/drakes.dm" +#endif + +#ifdef CONTENT_PACK_VENTCRAWL +#include "patches/ventcrawl.dm" +#endif + +#ifdef CONTENT_PACK_EXPLORATION +#include "patches/exploration.dm" +#endif diff --git a/nano/To BYOND Cache.bat b/nano/To BYOND Cache.bat deleted file mode 100644 index 8f86cc579b04..000000000000 --- a/nano/To BYOND Cache.bat +++ /dev/null @@ -1,6 +0,0 @@ -for /D %%i in ("%USERPROFILE%\Documents\BYOND\cache\*") do ( - copy css\* %%i /y - copy images\* %%i /y - copy js\* %%i /y - copy templates\* %%i /y -) diff --git a/nano/css/fonts.css b/nano/css/fonts.css new file mode 100644 index 000000000000..c7b3e6173198 --- /dev/null +++ b/nano/css/fonts.css @@ -0,0 +1,25 @@ +/** + * Put all custom font face @t rules in here. So they're properly loaded by nano. + * Preferably, put the font files and their licenses into the 'project_dir'/fonts directory. + * Additionally, if the font needs to be loaded by the byond ui, you can add it's path to the 'font_resources' global list. + * + * Note: Paths should be relative to the user's cache folder where all the nano assets are loaded. ('./') + * Note2: The browser seems to support truetype, woff2, and woff as far as custom fonts go. Possibly more. + * Note3: Don't add urls linking to the web in here for fonts. Add those in your specific UI if you must, since it will add a delay to fetch the font. + */ + +/** Font for numeric 7 segments lcd screens. */ +@font-face { + font-family: 'segment7'; + src: url('./segment7.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +/** Font for monolith runes */ +@font-face { + font-family: 'shage'; + src: url('./Shage.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} \ No newline at end of file diff --git a/nano/css/layout_basic.css b/nano/css/layout_basic.css index 4cdd1bfe294a..340ec6208e9f 100644 --- a/nano/css/layout_basic.css +++ b/nano/css/layout_basic.css @@ -1,5 +1,5 @@ body { - background: #000000 url(uiBasicBackground.png) 50% 0 repeat-x; + background: #000000 url(uiBasicBackground.png) 50% 0 repeat; } #uiContent { diff --git a/nano/css/layout_default.css b/nano/css/layout_default.css index 882eb525ae1d..3a7d875cfd50 100644 --- a/nano/css/layout_default.css +++ b/nano/css/layout_default.css @@ -1,5 +1,5 @@ body { - background: #121212 url(uiBackground.png) 50% 0 repeat-x; + background: #121212 url(uiBackground.png) 50% 0 repeat; } #uiWrapper { diff --git a/nano/css/shared.css b/nano/css/shared.css index c6b43f7d8f0b..305f2806c3d4 100644 --- a/nano/css/shared.css +++ b/nano/css/shared.css @@ -1,205 +1,225 @@ body { - padding: 0; - margin: 0; - font-size: 12px; - color: #00ff00; - line-height: 170%; - font-family: fixedsys; - background: #272727; + padding: 0; + margin: 0; + font-size: 12px; + color: #00ff00; + line-height: 170%; + font-family: fixedsys; + background: #272727; } #uiNoScript { - position: fixed; - top: 50%; - left: 50%; - margin: -60px 0 0 -150px; - width: 280px; - height: 120px; - background: #ffffff; - border: 2px solid #ff0000; - color: #000000; - font-size: 10px; - font-weight: bold; - z-index: 9999; - padding: 0px 10px; - text-align: center; + position: fixed; + top: 50%; + left: 50%; + margin: -60px 0 0 -150px; + width: 280px; + height: 120px; + background: #ffffff; + border: 2px solid #ff0000; + color: #000000; + font-size: 10px; + font-weight: bold; + z-index: 9999; + padding: 0px 10px; + text-align: center; } hr { - background-color: #40628a; - height: 1px; + background-color: #40628a; + height: 1px; } -.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton { - float: left; - min-width: 15px; - height: 16px; - text-align: center; - color: #ffffff; - text-decoration: none; - background: #003300; - border: 1px solid #00ff00; - padding: 0px 4px 4px 4px; - margin: 0 2px 2px 0; - cursor: default; - white-space: nowrap; +.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton, .greenButton{ + float: left; + min-width: 15px; + height: 16px; + text-align: center; + color: #ffffff; + text-decoration: none; + background: #003300; + border: 1px solid #00ff00; + padding: 0px 4px 4px 4px; + margin: 0 2px 2px 0; + white-space: nowrap; + cursor: pointer; +} + +.link:hover, .greenButton:hover{ + background: #009c00 !important; +} +.redButton:hover{ + background: #9c0202 !important; +} +.yellowButton:hover{ + background: #848601 !important; } .hasIcon { - padding: 0px 4px 4px 0px; + padding: 0px 4px 4px 0px; } .onlyIcon { - padding: 0px 0px 4px 0px; + padding: 0px 0px 4px 0px; } a:hover, .zoomLink:hover, .linkActive:hover { - background: #003300; + background: #003300; } .linkPending, .linkPending:hover { - color: #ffffff; - background: #003300; + color: #ffffff; + background: #003300; } a.white, a.white:link, a.white:visited, a.white:active { - color: #40628a; - text-decoration: none; - background: #ffffff; - border: 1px solid #161616; - padding: 1px 4px 1px 4px; - margin: 0 2px 0 0; - cursor: default; + color: #40628a; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor: default; } a.white:hover { - color: #ffffff; - background: #40628a; + color: #ffffff; + background: #40628a; } .hidden { - display: none; + display: none; } .linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover, .selected, a.selected:link, a.selected:visited, a.selected:active, a.selected:hover { - color: #ffffff; - background: #2f943c; + color: #ffffff; + background: #2f943c; } -.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover, .disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover { - color: #ffffff; - background: #999999; - border-color: #666666; +.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover, .disabled, .disabled:hover, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover { + color: #ffffff; + background: #999999 !important; + border-color: #666666; + cursor: default; } a.icon, .linkOn.icon, .linkOff.icon, .selected.icon, .disabled.icon { - position: relative; - padding: 1px 4px 2px 20px; + position: relative; + padding: 1px 4px 2px 20px; } a.icon img, .linkOn.icon img, .linkOff.icon img, .selected.icon img, .disabled.icon img { - position: absolute; - top: 0; - left: 0; - width: 18px; - height: 18px; + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; } .linkDanger, a.linkDanger:link, a.linkDanger:visited, a.linkDanger:active { - color: #ffffff; - background-color: #ff0000; - border-color: #aa0000; + color: #ffffff; + background-color: #ff0000; + border-color: #aa0000; } .linkDanger:hover { - background-color: #ff6666; + background-color: #ff6666; } ul { - padding: 4px 0 0 10px; - margin: 0; - list-style-type: none; + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; } li { - padding: 0 0 2px 0; + padding: 0 0 2px 0; } img, a img { - border-style: none; + border-style: none; } h1, h2, h3, h4, h5, h6 { - margin: 0; - padding: 12px 0 6px 0; - color: #FFFFFF; - clear: both; + margin: 0; + padding: 12px 0 6px 0; + color: #FFFFFF; + clear: both; } h1 { - font-size: 18px; + font-size: 18px; } h2 { - font-size: 16px; + font-size: 16px; } h3 { - font-size: 14px; + font-size: 14px; } h4 { - font-size: 12px; + font-size: 12px; } abbr { - border-bottom: .1em dotted; + border-bottom: .1em dotted; } .white { - color: white; - font-weight: bold; + color: white; + font-weight: bold; } .good { - color: white; - font-weight: bold; + color: white; + font-weight: bold; +} + +.mild { + color: #cda500; + font-weight: bold; } .average { - color: #00ff00; - font-weight: bold; + color: #00ff00; + font-weight: bold; } .bad { - color: #ee0000; - font-weight: bold; + color: #ee0000; + font-weight: bold; } .idle { - color: #272727; - font-weight: bold; + color: #666666; + font-weight: bold; } .redButton { - background: #ea0000; + background: #ea0000; } .yellowButton { - background: #cacc00; + background: #cacc00; +} + +.greenButton { + background: #00aa00; } .highlight { - color: #8BA5C4; + color: #8BA5C4; } .dark { - color: #272727; + color: #272727; } .caption { - font-size: 10px; - font-weight: bold; + font-size: 10px; + font-weight: bold; padding: 5px; } @@ -208,309 +228,318 @@ abbr { } .noticePlaceholder { - position: relative; - font-size: 12px; - font-weight: bold; - padding: 3px 4px 3px 4px; - margin: 4px 0 4px 0; + position: relative; + font-size: 12px; + font-weight: bold; + padding: 3px 4px 3px 4px; + margin: 4px 0 4px 0; } .notice { - position: relative; - background: url(uiNoticeBackground.jpg) 50% 50%; - color: #000000; - font-size: 12px; - font-weight: bold; - padding: 3px 4px 3px 4px; - margin: 4px 0 4px 0; + position: relative; + background: url(uiNoticeBackground.jpg) 50% 50%; + color: #000000; + font-size: 12px; + font-weight: bold; + padding: 3px 4px 3px 4px; + margin: 4px 0 4px 0; } .notice.icon { - padding: 2px 4px 0 20px; + padding: 2px 4px 0 20px; } .notice img { - position: absolute; - top: 0; - left: 0; - width: 16px; - height: 16px; + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; } div.notice { - clear: both; + clear: both; } .notice.info { - background: url(uiInfoBackground.jpg) 50% 50%; + background: url(uiInfoBackground.jpg) 50% 50%; } .itemGroup { - border: 1px solid #e9c183; - background: #2c2c2c; - padding: 4px; - clear: both; + border: 1px solid #e9c183; + background: #2c2c2c; + padding: 4px; + clear: both; } .item { - width: 100%; - margin: 4px 0 0 0; - clear: both; + width: 100%; + margin: 4px 0 0 0; + clear: both; overflow: auto; } .itemContentNarrow, .itemContent { - float: left; + float: left; } .itemContentNarrow { - width: 30%; + width: 30%; } .itemContent { - width: 69%; + width: 69%; } .itemLabelNarrow, .itemLabel, .itemLabelWide, .itemLabelWider, .itemLabelWidest { - float: left; - color: #00ff00; + float: left; + color: #00ff00; } .itemLabelNarrow { - width: 20%; + width: 20%; } .itemLabel { - width: 30%; + width: 30%; } .itemLabelWide { - width: 45%; + width: 45%; } .itemLabelWider { - width: 69%; + width: 69%; } .itemLabelWidest { - width: 100%; + width: 100%; } .itemContentWide { - float: left; - width: 79%; + float: left; + width: 79%; } .itemContentSmall { - float: left; - width: 33%; + float: left; + width: 33%; } .itemContentMedium { - float: left; - width: 55%; + float: left; + width: 55%; } .statusDisplay { - background: #000000; - color: #ffffff; - border: 1px solid #40628a; - padding: 4px; - margin: 3px 0; + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; + overflow: hidden; +} + +.statusDisplayItem { + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 1px; + margin: 0px 4px; overflow: hidden; } .statusDisplayRecords { - background: #000000; - color: #ffffff; - border: 1px solid #40628a; - padding: 4px; - margin: 3px 0; - overflow-x: hidden; - overflow-y: auto; + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; + overflow-x: hidden; + overflow-y: auto; } .statusDisplayComm { width: 100%; - background: rgba(0, 0, 0, 0.5); - color: #ffffff; + background: rgba(0, 0, 0, 0.5); + color: #ffffff; padding-bottom: 4px; border-top: 0 none; border-left: 0 none; border-right: 0 none; border-bottom: 2px inset #40628a; - margin: 3px 0; + margin: 3px 0; overflow: hidden; } .statusLabel { - width: 138px; - float: left; - overflow: hidden; - color: #98B0C3; + width: 138px; + float: left; + overflow: hidden; + color: #98B0C3; } .statusValue { - float: left; + float: left; } .block { - padding: 8px; - margin: 10px 4px 4px 4px; - border: 1px solid #40628a; - background-color: #202020; + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #40628a; + background-color: #202020; } .block h3 { - padding: 0; + padding: 0; } .displayBar { - position: relative; - width: 236px; - height: 16px; - border: 1px solid #666666; - float: left; - margin: 0 5px 0 0; - overflow: hidden; - background: #000000; + position: relative; + width: 236px; + height: 16px; + border: 1px solid #666666; + float: left; + margin: 0 5px 0 0; + overflow: hidden; + background: #000000; } .displayBarText, .displayBarVerticalText, .displayBarBeakerText{ - position: absolute; - top: -2px; - left: 5px; - width: 100%; - height: 100%; - color: #ffffff; - font-weight: normal; + position: absolute; + top: -2px; + left: 5px; + width: 100%; + height: 100%; + color: #ffffff; + font-weight: normal; } .displayBarFill { - width: 0%; - height: 100%; - background: #40628a; - overflow: hidden; - float: left; + width: 0%; + height: 100%; + background: #40628a; + overflow: hidden; + float: left; } .displayBarVertical { - position: relative; - width: 16px; - height: 200px; - border: 1px solid #666666; - float: left; - margin: 0 5px 0 0; - overflow: hidden; + position: relative; + width: 16px; + height: 200px; + border: 1px solid #666666; + float: left; + margin: 0 5px 0 0; + overflow: hidden; background: #40628a; } .displayBarVerticalFill { - width: 100%; - height: 0%; - overflow: hidden; - float: left; + width: 100%; + height: 0%; + overflow: hidden; + float: left; background: #000000; } /*used in xenobio2 computer*/ .displayBarBeaker { - position: relative; - width: 100px; - height: 110px; - border-right: 2px solid rgb(102, 179, 255); + position: relative; + width: 100px; + height: 110px; + border-right: 2px solid rgb(102, 179, 255); border-left: 2px solid rgb(102, 179, 255); border-bottom: 2px solid rgb(102, 179, 255); - float: left; - margin: 0 5px 0 0; - overflow: hidden; + float: left; + margin: 0 5px 0 0; + overflow: hidden; background: #40628a; } .displayBarBeakerFill { - width: 100%; - height: 0%; - overflow: hidden; - float: left; + width: 100%; + height: 0%; + overflow: hidden; + float: left; background: rgba(153, 204, 255, 0.3); } .displayBarFill.alignRight { - float: right; + float: right; } .displayBarFill.good { - color: #ffffff; - background: #4f7529; + color: #ffffff; + background: #4f7529; } .displayBarFill.average { - color: #ffffff; - background: #cd6500; + color: #ffffff; + background: #cd6500; } .displayBarFill.bad { - color: #ffffff; - background: #ee0000; + color: #ffffff; + background: #ee0000; } .displayBarFill.highlight { - color: #ffffff; - background: #8BA5C4; + color: #ffffff; + background: #8BA5C4; } .clearBoth { - clear: both; + clear: both; } .clearLeft { - clear: left; + clear: left; } .clearRight { - clear: right; + clear: right; } .line { - width: 100%; - clear: both; + width: 100%; + clear: both; } .inactive, a.inactive:link, a.inactive:visited, a.inactive:active, a.inactive:hover { - color: #ffffff; - background: #999999; - border-color: #666666; + color: #ffffff; + background: #999999; + border-color: #666666; } .fixedLeft { - width: 110px; - float: left; + width: 110px; + float: left; } .fixedLeftWide { - width: 165px; - float: left; + width: 165px; + float: left; } .fixedLeftWider { - width: 220px; - float: left; + width: 220px; + float: left; } .fixedLeftWidest { - width: 250px; - float: left; + width: 250px; + float: left; } .fixedLeftWiderRed { - width: 220px; - float: left; + width: 220px; + float: left; background: #ee0000; } .floatRight { - float: right; + float: right; } .floatLeft { @@ -520,63 +549,63 @@ div.notice { /* Used in PDA */ .wholeScreen { - position: absolute; - color: #517087; - font-size: 16px; - font-weight: bold; - text-align: center; + position: absolute; + color: #517087; + font-size: 16px; + font-weight: bold; + text-align: center; } .pdalink { - float: left; - white-space: nowrap; + float: left; + white-space: nowrap; } /* DNA Modifier UI (dna_modifier.tmpl) */ .dnaBlock { - float: left; - width: 90px; - padding: 0 0 5px 0; + float: left; + width: 90px; + padding: 0 0 5px 0; } .dnaBlockNumber { - font-family: Fixed, monospace; - float: left; - color: #ffffff; - background: #363636; - min-width: 20px; - height: 20px; - padding: 0; - text-align: center; + font-family: Fixed, monospace; + float: left; + color: #ffffff; + background: #363636; + min-width: 20px; + height: 20px; + padding: 0; + text-align: center; } .dnaSubBlock { - font-family: Fixed, monospace; - float: left; - padding: 0; - min-width: 16px; - height: 20px; - text-align: center; + font-family: Fixed, monospace; + float: left; + padding: 0; + min-width: 16px; + height: 20px; + text-align: center; } .mask { - position: fixed; - left: 0; - top: 0; - width: 100%; - height: 100%; - background: url(uiMaskBackground.png); + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: url(uiMaskBackground.png); } .maskContent { - width: 100%; - height: 200px; - margin: 200px 0; - text-align: center; + width: 100%; + height: 200px; + margin: 200px 0; + text-align: center; } -table.fixed { +table.fixed { table-layout:fixed; } @@ -586,118 +615,118 @@ table.fixed td { /* Table stuffs for power monitor */ table.pmon { - border: 2px solid RoyalBlue; + border: 2px solid RoyalBlue; } table.pmon td, table.pmon th { - border-bottom: 1px dotted black; - padding: 0px 5px 0px 5px; + border-bottom: 1px dotted black; + padding: 0px 5px 0px 5px; } /* Table Stuffs for manifest*/ th.command { - background: #3333FF; - font-weight: bold; - color: #ffffff; + background: #3333FF; + font-weight: bold; + color: #ffffff; } th.spt { - background: #4f4ff2; - font-weight: bold; - color: #ffffff; + background: #4f4ff2; + font-weight: bold; + color: #ffffff; } th.sec { - background: #8e0000; - font-weight: bold; - color: #ffffff; + background: #8e0000; + font-weight: bold; + color: #ffffff; } th.med { - background: #006600; - font-weight: bold; - color: #ffffff; + background: #006600; + font-weight: bold; + color: #ffffff; } th.eng { - background: #b27300; - font-weight: bold; - color: #ffffff; + background: #b27300; + font-weight: bold; + color: #ffffff; } th.sci { - background: #a65ba6; - font-weight: bold; - color: #ffffff; + background: #a65ba6; + font-weight: bold; + color: #ffffff; } th.car { - background: #bb9040; - font-weight: bold; - color: #ffffff; + background: #bb9040; + font-weight: bold; + color: #ffffff; } th.sup { - background: #bb9040; - font-weight: bold; - color: #ffffff; + background: #bb9040; + font-weight: bold; + color: #ffffff; } th.civ { - background: #a32800; - font-weight: bold; - color: #ffffff; + background: #a32800; + font-weight: bold; + color: #ffffff; } th.srv { - background: #88b764; - font-weight: bold; - color: #ffffff; + background: #88b764; + font-weight: bold; + color: #ffffff; } th.exp { - background: #68099e; - font-weight: bold; - color: #ffffff; + background: #68099e; + font-weight: bold; + color: #ffffff; } th.misc { - background: #666666; - font-weight: bold; - color: #ffffff; + background: #666666; + font-weight: bold; + color: #ffffff; } th.bot { - background: #414249; - font-weight: bold; - color: #ffffff; + background: #414249; + font-weight: bold; + color: #ffffff; } /* Damage colors for crew monitoring computer */ .burn { - color: orange; + color: orange; } .brute { - color: red; + color: red; } .toxin { - color: green; + color: green; } .oxyloss { - color: cyan; + color: cyan; } /* 75px width used in power monitoring console buttons */ .width75btn { - width: 75px; + width: 75px; } .wideTable tr:nth-child(odd) { - background-color: #272727; + background-color: #272727; } /* Candystriped rows for tables */ @@ -711,4 +740,234 @@ th.bot { .redacted { background-color: black; color: black; +} + +/* [Tooltips of description] */ +.ToolTip span { + visibility : hidden; + opacity : 0; + transition : opacity 0.3s linear; + padding : 10px; + margin-left : 8px; + width : 200px; + z-index : 999; +} +.ToolTip:hover span { + visibility : visible; + opacity : 1; + position : absolute; + background : #717177; + border : 4px solid #666; + border-radius : 5px; + color : #d1d1dd; + text-align : center; + white-space : pre-line; +} + +/*Forms UI templates (For use with forms controls)*/ +.textBox{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #000000; + color:inherit; +} +.textBox:disabled{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #3d3d3d; + color:#1b3015; +} + +.numBox{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #000000; + color:inherit; +} +.numBox:disabled{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #3d3d3d; + color:#1b3015; +} + +.button{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #303030; + color:inherit; +} +.button:disabled{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #3d3d3d; + color:#1b3015; +} + +.listBox{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #000000; + color:inherit; +} +.listBox:disabled{ + border: 1px solid #666666; + margin: 0 1em 0 0; + background: #3d3d3d; + color:#1b3015; +} + +.rect { + display: inline; + border-style: solid; + border-width: 1px; + border-color: #000000; +} + +/*********************************** + Fancy OS-like Button +************************************/ + +/* A button that looks like an operating system button */ +.linkBtnOS, +.linkBtnOS:hover, +.linkBtnOSDark, +.linkBtnOSDark:hover, +.linkBtnOSRed, +.linkBtnOSRed:hover { + float: none; + min-width: 1em; + height: 1em; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + text-align: center; + text-decoration: none; + text-shadow: none; + white-space: nowrap; + cursor: pointer; + border: none; + color: hsl(0, 0%, 20%); + background: hsl(0, 0%, 55%); + outline: 1px dotted hsl(0, 0%, 15%); + outline-offset: -4px; + box-shadow: + inset -1px -1px hsl(0, 0%, 16%), + inset 1px 1px hsl(0, 0%, 80%), + inset -2px -2px hsl(0, 0%, 62%), + inset 2px 2px hsl(0, 0%, 80%); + padding: 0.5em 1em; + margin: 0 2px 2px 0; +} +/**Button pressed */ +.linkBtnOS:active { + box-shadow: + inset -1px -1px hsl(0, 0%, 80%), + inset 1px 1px hsl(0, 0%, 16%), + inset -2px -2px hsl(0, 0%, 80%), + inset 2px 2px hsl(0, 0%, 62%); +} +/**Button disabled */ +.linkBtnOS.disabled, +.linkBtnOS.inactive, +.linkBtnOS:disabled { + color: hsl(0, 0%, 45%); + background: hsl(0, 0%, 55%); + outline: 1px dotted hsl(0, 0%, 40%); + box-shadow: + inset -1px -1px hsl(0, 0%, 36%), + inset 1px 1px hsl(0, 0%, 70%), + inset -2px -2px hsl(0, 0%, 52%), + inset 2px 2px hsl(0, 0%, 70%); +} +/**Button pressed + disabled */ +.linkBtnOS.disabled:active, +.linkBtnOS.inactive:active { + box-shadow: + inset -1px -1px hsl(0, 0%, 70%), + inset 1px 1px hsl(0, 0%, 16%), + inset -2px -2px hsl(0, 0%, 70%), + inset 2px 2px hsl(0, 0%, 30%); +} + +/***************** + * Darker variant + *****************/ +.linkBtnOSDark, +.linkBtnOSDark:hover{ + color: hsl(0, 0%, 65%); + background: hsl(0, 0%, 35%); + outline: 1px dotted hsl(0, 0%, 45%); + box-shadow: + inset -1px -1px hsl(0, 0%, 8%), + inset 1px 1px hsl(0, 0%, 60%), + inset -2px -2px hsl(0, 0%, 32%), + inset 2px 2px hsl(0, 0%, 60%); +} +.linkBtnOSDark:active { + box-shadow: + inset -1px -1px hsl(0, 0%, 60%), + inset 1px 1px hsl(0, 0%, 8%), + inset -2px -2px hsl(0, 0%, 60%), + inset 2px 2px hsl(0, 0%, 32%); +} +.linkBtnOSDark.disabled, +.linkBtnOSDark.inactive, +.linkBtnOSDark:disabled { + color: hsl(0, 0%, 38%); + background: hsl(0, 0%, 45%); + outline: 1px dotted hsl(0, 0%, 60%); + box-shadow: + inset -1px -1px hsl(0, 0%, 8%), + inset 1px 1px hsl(0, 0%, 50%), + inset -2px -2px hsl(0, 0%, 32%), + inset 2px 2px hsl(0, 0%, 50%); +} +.linkBtnOSDark.disabled:active, +.linkBtnOSDark.inactive:active { + box-shadow: + inset -1px -1px hsl(0, 0%, 50%), + inset 1px 1px hsl(0, 0%, 8%), + inset -2px -2px hsl(0, 0%, 50%), + inset 2px 2px hsl(0, 0%, 25%); +} + +/******************* + * Dark Red Variant + *******************/ +.linkBtnOSRed, +.linkBtnOSRed:hover{ + color: hsl(20, 50%, 65%); + background: hsl(20, 70%, 35%); + outline: 1px dotted hsl(20, 40%, 45%); + box-shadow: + inset -1px -1px hsl(20, 50%, 8%), + inset 1px 1px hsl(20, 50%, 60%), + inset -2px -2px hsl(20, 50%, 32%), + inset 2px 2px hsl(20, 50%, 60%); +} +.linkBtnOSRed:active { + box-shadow: + inset -1px -1px hsl(20, 50%, 60%), + inset 1px 1px hsl(20, 50%, 8%), + inset -2px -2px hsl(20, 50%, 60%), + inset 2px 2px hsl(20, 50%, 32%); +} +.linkBtnOSRed.disabled, +.linkBtnOSRed.inactive, +.linkBtnOSRed:disabled { + color: hsl(20, 20%, 28%); + background: hsl(20, 40%, 35%); + outline: 1px dotted hsl(20, 20%, 40%); + box-shadow: + inset -1px -1px hsl(20, 20%, 8%), + inset 1px 1px hsl(20, 20%, 50%), + inset -2px -2px hsl(20, 20%, 32%), + inset 2px 2px hsl(20, 20%, 50%); +} +.linkBtnOSRed.disabled:active, +.linkBtnOSRed.inactive:active { + box-shadow: + inset -1px -1px hsl(20, 20%, 50%), + inset 1px 1px hsl(20, 20%, 8%), + inset -2px -2px hsl(20, 20%, 50%), + inset 2px 2px hsl(20, 20%, 25%); } \ No newline at end of file diff --git a/nano/css/tgui.css b/nano/css/tgui.css index fd7fb2b5d32d..d2c5c2bd3fb2 100644 --- a/nano/css/tgui.css +++ b/nano/css/tgui.css @@ -6,7 +6,6 @@ div.display { -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)"; filter: progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000); background-color: rgba(0,0,0,.33); - box-shadow: inset 0 0 5px rgba(0,0,0,.5); } div.display header { diff --git a/nano/images/example/example-1.png b/nano/images/example/example-1.png index d3f74bc23972..e69de29bb2d1 100644 Binary files a/nano/images/example/example-1.png and b/nano/images/example/example-1.png differ diff --git a/nano/images/example/example-2.png b/nano/images/example/example-2.png index a623ad868b6d..e69de29bb2d1 100644 Binary files a/nano/images/example/example-2.png and b/nano/images/example/example-2.png differ diff --git a/nano/images/example/example-3.png b/nano/images/example/example-3.png index 905c3714a4b1..e69de29bb2d1 100644 Binary files a/nano/images/example/example-3.png and b/nano/images/example/example-3.png differ diff --git a/nano/images/exodus/exodus-1.png b/nano/images/exodus/exodus-1.png new file mode 100644 index 000000000000..6d4c28545d0e Binary files /dev/null and b/nano/images/exodus/exodus-1.png differ diff --git a/nano/images/exodus/exodus-2.png b/nano/images/exodus/exodus-2.png new file mode 100644 index 000000000000..cfe72ba9832a Binary files /dev/null and b/nano/images/exodus/exodus-2.png differ diff --git a/nano/images/ministation/ministation-1.png b/nano/images/ministation/ministation-1.png new file mode 100644 index 000000000000..70fcdc99765a Binary files /dev/null and b/nano/images/ministation/ministation-1.png differ diff --git a/nano/images/ministation/ministation-2.png b/nano/images/ministation/ministation-2.png new file mode 100644 index 000000000000..9e33b0d8c859 Binary files /dev/null and b/nano/images/ministation/ministation-2.png differ diff --git a/nano/images/ministation/ministation-3.png b/nano/images/ministation/ministation-3.png new file mode 100644 index 000000000000..a2d90b864f0e Binary files /dev/null and b/nano/images/ministation/ministation-3.png differ diff --git a/nano/images/ministation/ministation-4.png b/nano/images/ministation/ministation-4.png new file mode 100644 index 000000000000..be5b779985e0 Binary files /dev/null and b/nano/images/ministation/ministation-4.png differ diff --git a/nano/images/shaded_hills/shaded_hills-1.png b/nano/images/shaded_hills/shaded_hills-1.png new file mode 100644 index 000000000000..862e93356aac Binary files /dev/null and b/nano/images/shaded_hills/shaded_hills-1.png differ diff --git a/nano/images/shaded_hills/shaded_hills-2.png b/nano/images/shaded_hills/shaded_hills-2.png new file mode 100644 index 000000000000..cc7727eb7d28 Binary files /dev/null and b/nano/images/shaded_hills/shaded_hills-2.png differ diff --git a/nano/images/shaded_hills/shaded_hills-3.png b/nano/images/shaded_hills/shaded_hills-3.png new file mode 100644 index 000000000000..ab087ace58e3 Binary files /dev/null and b/nano/images/shaded_hills/shaded_hills-3.png differ diff --git a/nano/images/shaded_hills/shaded_hills-4.png b/nano/images/shaded_hills/shaded_hills-4.png new file mode 100644 index 000000000000..97408dc32f63 Binary files /dev/null and b/nano/images/shaded_hills/shaded_hills-4.png differ diff --git a/nano/images/shaded_hills/shaded_hills-5.png b/nano/images/shaded_hills/shaded_hills-5.png new file mode 100644 index 000000000000..a4d8cf90dd2d Binary files /dev/null and b/nano/images/shaded_hills/shaded_hills-5.png differ diff --git a/nano/images/shaded_hills/shaded_hills-6.png b/nano/images/shaded_hills/shaded_hills-6.png new file mode 100644 index 000000000000..3cb34e5cb67c Binary files /dev/null and b/nano/images/shaded_hills/shaded_hills-6.png differ diff --git a/nano/images/uiBackground-Syndicate.png b/nano/images/uiBackground-Syndicate.png index 6e5622875cee..94358bf7edfb 100644 Binary files a/nano/images/uiBackground-Syndicate.png and b/nano/images/uiBackground-Syndicate.png differ diff --git a/nano/images/uiBackground.png b/nano/images/uiBackground.png index ef2e9df1c434..53e43fedb912 100644 Binary files a/nano/images/uiBackground.png and b/nano/images/uiBackground.png differ diff --git a/nano/images/uiBasicBackground.png b/nano/images/uiBasicBackground.png index 53d19ad21bf2..f91e9f2f0a20 100644 Binary files a/nano/images/uiBasicBackground.png and b/nano/images/uiBasicBackground.png differ diff --git a/nano/js/nano_base_helpers.js b/nano/js/nano_base_helpers.js index 9dd89915a359..27fc2609a77c 100644 --- a/nano/js/nano_base_helpers.js +++ b/nano/js/nano_base_helpers.js @@ -4,10 +4,59 @@ NanoBaseHelpers = function () var _baseHelpers = { // change ui styling to "syndicate mode" syndicateMode: function() { - $('body').css("background-color","#8f1414"); + $('body').css("background-color","#330404"); $('body').css("background-image","url('uiBackground-Syndicate.png')"); $('body').css("background-position","50% 0"); - $('body').css("background-repeat","repeat-x"); + $('body').css("background-repeat","repeat"); + $('body').css("color", "#ff0000"); + + $('hr').css("background-color", "#551414"); + $('a').css("background", "#551414"); + $('a:link').css("background", "#551414"); + $('a:visited').css("background", "#551414"); + $('a:active').css("background", "#551414"); + $('linkOn').css("background", "#551414"); + $('linkOff').css("background", "#551414"); + $('input').css("background", "#551414"); + $('a:hover').css("color", "#551414"); + $('a.white').css("color", "#551414"); + $('a.white:link').css("color", "#551414"); + $('a.white:visited').css("color", "#551414"); + $('a.white:active').css("color", "#551414"); + $('a.white:hover').css("background", "#551414"); + $('linkOn').css("background", "#771414"); + $('a.linkOn:link').css("background", "#771414"); + $('a.linkOn:visited').css("background", "#771414"); + $('a.linkOn:active').css("background", "#771414"); + $('a.linkOn:hover').css("background", "#771414"); + $('statusDisplay').css("border", "1px solid #551414"); + $('block').css("border", "1px solid #551414"); + $('progressFill').css("background", "#551414"); + $('statusDisplay').css("border", "1px solid #551414"); + + $('itemLabelNarrow').css("color", "#ff0000"); + $('itemLabel').css("color", "#ff0000"); + $('itemLabelWide').css("color", "#ff0000"); + $('itemLabelWider').css("color", "#ff0000"); + $('itemLabelWidest').css("color", "#ff0000"); + + $('link').css("border", "1px solid #ff0000"); + $('linkOn').css("border", "1px solid #ff0000"); + $('linkOff').css("border", "1px solid #ff0000"); + $('selected').css("border", "1px solid #ff0000"); + $('disabled').css("border", "1px solid #ff0000"); + $('yellowButton').css("border", "1px solid #ff0000"); + $('redButton').css("border", "1px solid #ff0000"); + + $('link').css("background", "#330000"); + $('linkOn').css("background", "#330000"); + $('linkOff').css("background", "#330000"); + $('selected').css("background", "#330000"); + $('disabled').css("background", "#330000"); + $('yellowButton').css("background", "#330000"); + $('redButton').css("background", "#330000"); + + $('.average').css("color", "#ff0000"); $('#uiTitleFluff').css("background-image","url('uiTitleFluff-Syndicate.png')"); $('#uiTitleFluff').css("background-position","50% 50%"); @@ -92,7 +141,7 @@ NanoBaseHelpers = function () return string.charAt(0).toUpperCase() + string.slice(1); }, // Display a bar. Used to show health, capacity, etc. Use difClass if the entire display bar class should be different - displayBar: function(value, rangeMin, rangeMax, styleClass, showText, difClass, direction) { + displayBar: function (value, rangeMin, rangeMax, styleClass, showText, difClass, direction, id) { if (rangeMin < rangeMax) { @@ -126,12 +175,12 @@ NanoBaseHelpers = function () { showText = ''; } - + if (typeof difClass == 'undefined' || !difClass) { difClass = '' } - + if(typeof direction == 'undefined' || !direction) { direction = 'width' @@ -140,10 +189,10 @@ NanoBaseHelpers = function () { direction = 'height' } - + var percentage = Math.round((value - rangeMin) / (rangeMax - rangeMin) * 100); - - return '
    ' + showText + '
    '; + + return '
    ' + showText + '
    '; }, // Display DNA Blocks (for the DNA Modifier UI) displayDNABlocks: function(dnaString, selectedBlock, selectedSubblock, blockSize, paramKey) { @@ -198,9 +247,15 @@ NanoBaseHelpers = function () html += '
    '; return html; + }, + byondTimeOfDay: function _byondTimeOfDay() { + if(typeof _byondTimeOfDay.midnight == 'undefined') { + _byondTimeOfDay.midnight = new Date().setUTCHours(0, 0, 0, 0); + } + return (new Date() - _byondTimeOfDay.midnight)/100; // deciseconds since midnight } }; - + return { addHelpers: function () { @@ -214,11 +269,11 @@ NanoBaseHelpers = function () { NanoTemplate.removeHelper(helperKey); } - } + } } }; } (); - + diff --git a/nano/js/nano_template.js b/nano/js/nano_template.js index f8f5d2659485..bac5ff5cea3d 100644 --- a/nano/js/nano_template.js +++ b/nano/js/nano_template.js @@ -1,7 +1,8 @@ var NanoTemplate = function () { - var _templateData = {}; + var _templateData = {}; + var _templateFileName = ''; var _templates = {}; var _compiledTemplates = {}; @@ -11,63 +12,46 @@ var NanoTemplate = function () { var init = function () { // We store templateData in the body tag, it's as good a place as any _templateData = $('body').data('templateData'); + _templateFileName = $('body').data('initialData')['config']['templateFileName']; if (_templateData == null) { alert('Error: Template data did not load correctly.'); } - loadNextTemplate(); + loadAllTemplates(); }; - var loadNextTemplate = function () { - // we count the number of templates for this ui so that we know when they've all been rendered - var templateCount = Object.size(_templateData); - - if (!templateCount) - { - $(document).trigger('templatesLoaded'); - return; - } - - // load markup for each template and register it - for (var key in _templateData) - { - if (!_templateData.hasOwnProperty(key)) - { - continue; - } - - $.when($.ajax({ - url: _templateData[key], - cache: false, - dataType: 'text' - })) - .done(function(templateMarkup) { - - templateMarkup += '
    '; - - try - { - NanoTemplate.addTemplate(key, templateMarkup); - } - catch(error) - { - alert('ERROR: An error occurred while loading the UI: ' + error.message); - return; - } - - delete _templateData[key]; - - loadNextTemplate(); - }) - .fail(function () { - alert('ERROR: Loading template ' + key + '(' + _templateData[key] + ') failed!'); - }); + var loadAllTemplates = function () { + $.when($.ajax({ + url: _templateFileName, + cache: false, + dataType: 'json' + })) + .done(function(allTemplates) { + + for (var key in _templateData) + { + var templateMarkup = allTemplates[_templateData[key]]; + templateMarkup += '
    '; - return; - } - } + try + { + NanoTemplate.addTemplate(key, templateMarkup); + } + catch(error) + { + alert('ERROR: Loading template ' + key + '(' + _templateData[key] + ') failed with error: ' + error.message); + return; + } + delete _templateData[key]; + } + $(document).trigger('templatesLoaded'); + }) + .fail(function () { + alert('ERROR: Failed to locate or parse templates file.'); + }); + }; var compileTemplates = function () { @@ -76,7 +60,7 @@ var NanoTemplate = function () { _compiledTemplates[key] = doT.template(_templates[key], null, _templates) } catch (error) { - alert(error.message); + alert('ERROR: Compiling template key "' + key + '" ("' + _templateData[key] + '") failed with error: ' + error); } } }; @@ -100,8 +84,6 @@ var NanoTemplate = function () { compileTemplates(); } if (typeof _compiledTemplates[templateKey] != 'function') { - alert(_compiledTemplates[templateKey]); - alert('ERROR: Template "' + templateKey + '" failed to compile!'); return '

    Template error (failed to compile)

    '; } return _compiledTemplates[templateKey].call(this, data['data'], data['config'], _helpers); diff --git a/nano/templates/TemplatesGuide.txt b/nano/templates/TemplatesGuide.txt index f333e454676f..60f58d31f5b0 100644 --- a/nano/templates/TemplatesGuide.txt +++ b/nano/templates/TemplatesGuide.txt @@ -7,4 +7,4 @@ to easily add conditionals (if statements), loops (for loops) and custom formatt Templates are stored in the /nano/templates folder and the file extension is .tmpl. -This guide is being replaced with a wiki entry, found here: http://wiki.baystation12.net/NanoUI \ No newline at end of file +This guide is being replaced with a wiki entry, found here: https://bay.ss13.me/en/Guides/coderbus/nanoui \ No newline at end of file diff --git a/nano/templates/account_management.tmpl b/nano/templates/account_management.tmpl new file mode 100644 index 000000000000..0b512fa10ce0 --- /dev/null +++ b/nano/templates/account_management.tmpl @@ -0,0 +1,87 @@ +{{if data.prog_state == -1}} +
    +
    + Error Encountered: +
    +
    + {{:data.error}} +
    +
    + {{:helper.link('Go back', 'arrowthickstop-1-w', {'back' : 1}, null)}} +{{else data.prog_state == 0}} +

    Welcome to the network account management utility:

    + {{:helper.link('Self account management', null, {'self_mode' : 1}, null)}} + {{:helper.link('Manage other accounts', null, {'other_mode' : 1}, null)}} +{{else data.prog_state == 1}} +

    Welcome, {{:data.account_fullname}}

    +
    +
    + Login: +
    +
    + {{:data.account_name}} +
    +
    +
    +
    + Password: +
    +
    + {{:helper.link('*******', null, {'change_password' : 1}, null)}} +
    +
    +
    +
    +
    + Groups: +
    +
    + {{for data.account_groups}} + {{:value}}
    + {{/for}} +
    +
    +
    + {{:helper.link('Change name', null, {'change_fullname' : 1}, null)}} + {{:helper.link('Go back', 'arrowthickstop-1-w', {'back' : 1}, null)}} +{{else data.prog_state == 2}} + {{if data.accounts}} +

    Network Accounts:

    +

    Some accounts may not be visible depending on your access to account servers.

    + + +
    Account LoginReal Name + {{for data.accounts}} +
    {{:helper.link(value.account, '', {'select_account' : value.account})}} + {{:value.fullname}} + {{/for}} +
    + {{:helper.link('Create account', '', {'create_account' : 1})}} + {{:helper.link('Recover account from backup', '', {'recover_account' : 1})}} + {{:helper.link('Go back', 'arrowthickstop-1-w', {'back' : 1}, null)}} + {{else data.parent_groups}} +

    Modifying account for {{:data.account_name}}:

    +

    Viewing parent groups. Group sub management is {{:data.sub_management ? 'enabled' : 'disabled'}}.

    + + +
    Parent GroupMembership + {{for data.parent_groups}} +
    {{:helper.link(value.name, '', {'select_parent_group' : value.name})}} + {{:helper.link(value.member ? 'Member' : 'Not a member', '', {'mod_group' : value.name})}} + {{/for}} +
    + {{:helper.link('Go back', 'arrowthickstop-1-w', {'back' : 1}, null)}} + {{else data.child_groups}} +

    Modifying account for {{:data.account_name}}:

    +

    Viewing child groups of {{:data.parent_group}}. Group sub management is {{:data.sub_management ? 'enabled' : 'disabled'}}.

    + + +
    Child GroupMembership + {{for data.child_groups}} +
    {{:value.name}} + {{:helper.link(value.member ? 'Member' : 'Not a member', '', {'mod_group' : value.name})}} + {{/for}} +
    + {{:helper.link('Go back', 'arrowthickstop-1-w', {'back' : 1}, null)}} + {{/if}} +{{/if}} diff --git a/nano/templates/accounts_terminal.tmpl b/nano/templates/accounts_terminal.tmpl index ce3f41022b4c..e425ed121d18 100644 --- a/nano/templates/accounts_terminal.tmpl +++ b/nano/templates/accounts_terminal.tmpl @@ -28,7 +28,7 @@

    Create Account

    -
    +
    diff --git a/nano/templates/advanced_airlock_console.tmpl b/nano/templates/advanced_airlock_console.tmpl index e60cf7c93276..4646bb2e6484 100644 --- a/nano/templates/advanced_airlock_console.tmpl +++ b/nano/templates/advanced_airlock_console.tmpl @@ -1,4 +1,10 @@
    +
    +
    + {{:helper.link('Purge', 'refresh', {'command' : 'purge'}, data.processing ? 'disabled' : null, data.purge ? 'linkOn' : null)}} {{:helper.link('Secure', data.secure ? 'locked' : 'unlocked', {'command' : 'secure'}, data.processing ? 'disabled' : null, data.secure ? 'linkOn' : null)}} +
    +
    +

    Sensors

    External Pressure: @@ -33,28 +39,17 @@
    -
    -
    -
    +
    +
    + {{if data.processing}} + {{:helper.link('Abort', 'cancel', {'command' : 'abort'}, data.processing ? null : 'disabled', data.processing ? 'redButton' : null)}} + {{else}} {{:helper.link('Cycle to Exterior', 'arrowthickstop-1-w', {'command' : 'cycle_ext'}, data.processing ? 'disabled' : null)}} {{:helper.link('Cycle to Interior', 'arrowthickstop-1-e', {'command' : 'cycle_int'}, data.processing ? 'disabled' : null)}} -
    -
    - {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : null)}} - {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : null)}} -
    -
    -
    -
    -
    - {{:helper.link('Purge', 'refresh', {'command' : 'purge'}, data.processing ? 'disabled' : null, data.purge ? 'linkOn' : null)}} -
    -
    - {{:helper.link('Secure', data.secure ? 'locked' : 'unlocked', {'command' : 'secure'}, data.processing ? 'disabled' : null, data.secure ? 'linkOn' : null)}} -
    -
    + {{/if}}
    -
    - {{:helper.link('Abort', 'cancel', {'command' : 'abort'}, data.processing ? null : 'disabled', data.processing ? 'redButton' : null)}} +
    + {{:helper.link('Force exterior door', 'alert', {'command' : 'force_ext'}, null, data.processing ? 'yellowButton' : 'redButton')}} + {{:helper.link('Force interior door', 'alert', {'command' : 'force_int'}, null, data.processing ? 'yellowButton' : 'redButton')}}
    \ No newline at end of file diff --git a/nano/templates/agent_id_card.tmpl b/nano/templates/agent_id_card.tmpl index 7a41dcdf1b7f..a802efbc82dd 100644 --- a/nano/templates/agent_id_card.tmpl +++ b/nano/templates/agent_id_card.tmpl @@ -1,21 +1,21 @@ - -{{:helper.syndicateMode()}} -

    Available Entries

    - -{{for data.entries}} - - - -{{/for}} -
    {{:helper.link('', 'gear', {'set' : value.name})}}{{:value.name}}{{:value.value}}
    - - - - - - - -
    Electronic warfare:{{:helper.link('Enabled', null, {'electronic_warfare' : 1}, data.electronic_warfare ? 'selected' : null)}}{{:helper.link('Disabled',null, {'electronic_warfare' : 0}, data.electronic_warfare ? null : 'selected')}}
    + +{{:helper.syndicateMode()}} +

    Available Entries

    + +{{for data.entries}} + + + +{{/for}} +
    {{:helper.link('', 'gear', {'set' : value.name})}}{{:value.name}}{{:value.value}}
    + + + + + + + +
    Electronic warfare:{{:helper.link('Enabled', null, {'electronic_warfare' : 1}, data.electronic_warfare ? 'selected' : null)}}{{:helper.link('Disabled',null, {'electronic_warfare' : 0}, data.electronic_warfare ? null : 'selected')}}
    diff --git a/nano/templates/aicard.tmpl b/nano/templates/aicard.tmpl index be860a52ac99..6f25cb01f230 100644 --- a/nano/templates/aicard.tmpl +++ b/nano/templates/aicard.tmpl @@ -1,51 +1,51 @@ - + - + {{if data.has_ai}}
    @@ -61,11 +61,11 @@ Used In File(s): \code\game\objects\items\devices\aicard.dm {{:data.backup_capacitor}}%
    - - {{if data.has_laws}} + + {{if data.has_laws}} - +
    Laws:
    @@ -76,8 +76,8 @@ Used In File(s): \code\game\objects\items\devices\aicard.dm {{else}} No laws found. {{/if}} - - {{if data.operational}} + + {{if data.operational}}
    IndexLaw
    diff --git a/nano/templates/air_alarm.tmpl b/nano/templates/air_alarm.tmpl index 491027b1d677..8e9f9a52f364 100644 --- a/nano/templates/air_alarm.tmpl +++ b/nano/templates/air_alarm.tmpl @@ -1,219 +1,219 @@ - -

    Air Status

    -{{if data.has_environment}} - {{for data.environment}} - {{:value.name}}: - {{if value.danger_level == 2}} - - {{else value.danger_level == 1}} - - {{else}} - - {{/if}} - {{:helper.fixed(value.value, 1)}} - {{:value.unit}}
    - {{/for}} - Local Status: {{if data.total_danger == 2}} - DANGER: Internals Required - {{else data.total_danger == 1}} - Caution - {{else}} - Optimal - {{/if}} -
    - Area Status: {{if data.atmos_alarm}}Atmosphere alert in area{{else data.fire_alarm}}Fire alarm in area{{else}}No alerts{{/if}} -{{else}} - Warning: Cannot obtain air sample for analysis. -{{/if}} -
    -
    Radio Subspace Transceiver
    - - - - - - - - - - - - -
    -
    -

    Remote Control

    -
    -

    Thermostat

    -
    -
    -
    -
    - {{:helper.link('Off', null, { 'rcon' : 1}, data.remote_connection && !data.remote_access ? (data.rcon == 1 ? 'yellowButton' : 'disabled') : null, data.rcon == 1 ? 'selected' : null)}} - {{:helper.link('Auto', null, { 'rcon' : 2}, data.remote_connection && !data.remote_access ? (data.rcon == 2 ? 'yellowButton' : 'disabled') : null, data.rcon == 2 ? 'selected' : null)}} - {{:helper.link('On', null, { 'rcon' : 3}, data.remote_connection && !data.remote_access ? (data.rcon == 3 ? 'yellowButton' : 'disabled') : null, data.rcon == 3 ? 'selected' : null)}} -
    -
    -
    - {{:helper.link(data.target_temperature, null, { 'temperature' : 1})}} -
    -
    -{{if (data.locked && !data.remote_connection) || (data.remote_connection && ! data.remote_access)}} - {{if data.remote_connection}} - (Current remote control settings and alarm status restricts access.) - {{else}} - (Swipe ID card to unlock interface.) - {{/if}} -{{else}} - {{if data.screen != 1}} -
    {{:helper.link('Main Menu', null, { 'screen' : 1})}}
    - {{/if}} - {{if data.screen == 1}} -
    - {{if data.atmos_alarm}} - {{:helper.link('Reset - Area Atmospheric Alarm', null, { 'atmos_reset' : 1})}} - {{else}} - {{:helper.link('Activate - Area Atmospheric Alarm', null, { 'atmos_alarm' : 1})}} - {{/if}} -
    -
    -
    - {{:helper.link('Scrubbers Control', null, { 'screen' : 3})}} -
    -
    - {{:helper.link('Vents Control', null, { 'screen' : 2})}} -
    -
    - {{:helper.link('Set Environmental Mode', null, { 'screen' : 4})}} -
    -
    - {{:helper.link('Sensor Settings', null, { 'screen' : 5})}} -
    -
    - {{if data.mode==3}} - {{:helper.link('PANIC SIPHON ACTIVE - Turn siphoning off', null, { 'mode' : 1}, null, 'redButton')}} - {{else}} - {{:helper.link('ACTIVATE PANIC SIPHON IN AREA', null, { 'mode' : 3}, null, 'yellowButton')}} - {{/if}} - {{else data.screen == 2}} - {{for data.vents}} -
    - {{:value.long_name}}
    -
    -
    - Operating: -
    -
    - {{:helper.link(value.power ? 'On' : 'Off', null, { 'id_tag' : value.id_tag, 'command' : 'set_power', 'val' : value.power ? 0 : 1}, null, value.power ? null : 'redButton')}} -
    -
    -
    -
    - Operation Mode: -
    -
    - {{:value.direction == "siphon" ? 'Siphoning' : 'Pressurizing'}} -
    -
    -
    -
    - Pressure Checks: -
    -
    - {{:helper.link('External', null, { 'id_tag' : value.id_tag, 'command' : 'set_checks', 'val' : value.checks^1}, null, value.checks&1 ? 'selected' : null)}} - {{:helper.link('Internal', null, { 'id_tag' : value.id_tag, 'command' : 'set_checks', 'val' : value.checks^2}, null, value.checks&2 ? 'selected' : null)}} -
    -
    -
    -
    - External Pressure Bound: -
    -
    - {{:helper.link(helper.fixed(value.external,2), null, { 'id_tag' : value.id_tag, 'command' : 'set_external_pressure'})}} - {{:helper.link('Reset', null, { 'id_tag' : value.id_tag, 'command' : 'reset_external_pressure'})}} -
    -
    -
    - {{empty}} - No vents connected. - {{/for}} - {{else data.screen == 3}} - {{for data.scrubbers}} -
    - {{:value.long_name}}
    -
    -
    - Operating: -
    -
    - {{:helper.link(value.power ? 'On' : 'Off', null, { 'id_tag' : value.id_tag, 'command' : 'set_power', 'val' : value.power ? 0 : 1}, null, value.power ? null : 'redButton')}} -
    -
    -
    -
    - Operation Mode: -
    -
    - {{:helper.link('Scrub', null, { 'id_tag' : value.id_tag, 'command' : 'set_scrubbing', 'scrub_mode' : 'scrub'}, null, value.scrubbing == 'scrub' ? 'selected' : null)}} - {{:helper.link('Exchange', null, { 'id_tag' : value.id_tag, 'command' : 'set_scrubbing', 'scrub_mode' : 'exchange'}, null, value.scrubbing == 'exchange' ? 'selected' : null)}} - {{:helper.link('Siphon', null, { 'id_tag' : value.id_tag, 'command' : 'set_scrubbing', 'scrub_mode' : 'siphon'}, null, value.scrubbing == 'siphon' ? 'redButton' : null)}} -
    -
    -
    -
    - Filters: -
    -
    - {{for value.filters :filterValue:filterIndex}} - {{:helper.link(filterValue.name, null, { 'id_tag' : value.id_tag, 'command' : 'set_scrub_gas', 'gas_id' : filterValue.id, 'val' : filterValue.val ? 0 : 1}, null, filterValue.val ? 'selected' : null)}} - {{/for}} -
    -
    -
    - {{empty}} - No scrubbers connected. - {{/for}} - {{else data.screen == 4}} -

    Environmental Modes

    - {{for data.modes}} -
    - {{:helper.link(value.name, null, { 'mode' : value.mode }, null, value.selected ? (value.danger ? 'redButton' : 'selected') : null)}} -
    - {{/for}} - {{else data.screen == 5}} -

    Alarm Threshold

    - Partial pressure for gases. - - - - - {{for data.thresholds}} - - - {{for value.settings :settingsValue:settingsIndex}} - - {{/for}} - - {{/for}} -
    min2min1max1max2
    {{:value.name}} - {{:helper.link(settingsValue.selected >= 0 ? helper.fixed(settingsValue.selected, 2) : "Off", null, { 'command' : 'set_threshold', 'env' : settingsValue.env, 'var' : settingsValue.val })}} -
    - {{/if}} -{{/if}} + +

    Air Status

    +{{if data.has_environment}} + {{for data.environment}} + {{:value.name}}: + {{if value.danger_level == 2}} + + {{else value.danger_level == 1}} + + {{else}} + + {{/if}} + {{:helper.fixed(value.value, 1)}} + {{:value.unit}}
    + {{/for}} + Local Status: {{if data.total_danger == 2}} + DANGER: Internals Required + {{else data.total_danger == 1}} + Caution + {{else}} + Optimal + {{/if}} +
    + Area Status: {{if data.atmos_alarm}}Atmosphere alert in area{{else data.fire_alarm}}Fire alarm in area{{else}}No alerts{{/if}} +{{else}} + Warning: Cannot obtain air sample for analysis. +{{/if}} +
    +
    + + + + + + + + + + + + +
    +
    +

    Remote Control

    +
    +

    Thermostat

    +
    +
    +
    +
    + {{:helper.link('Off', null, { 'rcon' : 1}, !data.rcon_access ? (data.rcon == 1 ? 'yellowButton' : 'disabled') : null, data.rcon == 1 ? 'selected' : null)}} + {{:helper.link('Auto', null, { 'rcon' : 2}, !data.rcon_access ? (data.rcon == 2 ? 'yellowButton' : 'disabled') : null, data.rcon == 2 ? 'selected' : null)}} + {{:helper.link('On', null, { 'rcon' : 3}, !data.rcon_access ? (data.rcon == 3 ? 'yellowButton' : 'disabled') : null, data.rcon == 3 ? 'selected' : null)}} +
    +
    +
    + {{:helper.link(data.target_temperature, null, { 'temperature' : 1})}} +
    +
    +{{if (data.locked && !data.remote_connection) || (data.remote_connection && ! data.remote_access)}} + {{if data.remote_connection}} + (Current remote control settings and alarm status restricts access.) + {{else}} + (Swipe ID card to unlock interface.) + {{/if}} +{{else}} + {{if data.screen != 1}} +
    {{:helper.link('Main Menu', null, { 'screen' : 1})}}
    + {{/if}} + {{if data.screen == 1}} +
    + {{if data.atmos_alarm}} + {{:helper.link('Reset - Area Atmospheric Alarm', null, { 'atmos_reset' : 1})}} + {{else}} + {{:helper.link('Activate - Area Atmospheric Alarm', null, { 'atmos_alarm' : 1})}} + {{/if}} +
    +
    +
    + {{:helper.link('Scrubbers Control', null, { 'screen' : 3})}} +
    +
    + {{:helper.link('Vents Control', null, { 'screen' : 2})}} +
    +
    + {{:helper.link('Set Environmental Mode', null, { 'screen' : 4})}} +
    +
    + {{:helper.link('Sensor Settings', null, { 'screen' : 5})}} +
    +
    + {{if data.mode==3}} + {{:helper.link('PANIC SIPHON ACTIVE - Turn siphoning off', null, { 'mode' : 1}, null, 'redButton')}} + {{else}} + {{:helper.link('ACTIVATE PANIC SIPHON IN AREA', null, { 'mode' : 3}, null, 'yellowButton')}} + {{/if}} + {{else data.screen == 2}} + {{for data.vents}} +
    + {{:value.long_name}}
    +
    +
    + Operating: +
    +
    + {{:helper.link(value.power ? 'On' : 'Off', null, { 'id_tag' : value.id_tag, 'command' : 'set_power', 'val' : value.power ? 0 : 1}, null, value.power ? null : 'redButton')}} +
    +
    +
    +
    + Operation Mode: +
    +
    + {{:value.direction == "siphon" ? 'Siphoning' : 'Pressurizing'}} +
    +
    +
    +
    + Pressure Checks: +
    +
    + {{:helper.link('External', null, { 'id_tag' : value.id_tag, 'command' : 'set_checks', 'val' : value.checks^1}, null, value.checks&1 ? 'selected' : null)}} + {{:helper.link('Internal', null, { 'id_tag' : value.id_tag, 'command' : 'set_checks', 'val' : value.checks^2}, null, value.checks&2 ? 'selected' : null)}} +
    +
    +
    +
    + External Pressure Bound: +
    +
    + {{:helper.link(helper.fixed(value.external,2), null, { 'id_tag' : value.id_tag, 'command' : 'set_external_pressure'})}} + {{:helper.link('Reset', null, { 'id_tag' : value.id_tag, 'command' : 'reset_external_pressure'})}} +
    +
    +
    + {{empty}} + No vents connected. + {{/for}} + {{else data.screen == 3}} + {{for data.scrubbers}} +
    + {{:value.long_name}}
    +
    +
    + Operating: +
    +
    + {{:helper.link(value.power ? 'On' : 'Off', null, { 'id_tag' : value.id_tag, 'command' : 'set_power', 'val' : value.power ? 0 : 1}, null, value.power ? null : 'redButton')}} +
    +
    +
    +
    + Operation Mode: +
    +
    + {{:helper.link('Scrub', null, { 'id_tag' : value.id_tag, 'command' : 'set_scrubbing', 'scrub_mode' : 'scrub'}, null, value.scrubbing == 'scrub' ? 'selected' : null)}} + {{:helper.link('Exchange', null, { 'id_tag' : value.id_tag, 'command' : 'set_scrubbing', 'scrub_mode' : 'exchange'}, null, value.scrubbing == 'exchange' ? 'selected' : null)}} + {{:helper.link('Siphon', null, { 'id_tag' : value.id_tag, 'command' : 'set_scrubbing', 'scrub_mode' : 'siphon'}, null, value.scrubbing == 'siphon' ? 'redButton' : null)}} +
    +
    +
    +
    + Filters: +
    +
    + {{for value.filters :filterValue:filterIndex}} + {{:helper.link(filterValue.name, null, { 'id_tag' : value.id_tag, 'command' : 'set_scrub_gas', 'gas_id' : filterValue.id, 'val' : filterValue.val ? 0 : 1}, null, filterValue.val ? 'selected' : null)}} + {{/for}} +
    +
    +
    + {{empty}} + No scrubbers connected. + {{/for}} + {{else data.screen == 4}} +

    Environmental Modes

    + {{for data.modes}} +
    + {{:helper.link(value.name, null, { 'mode' : value.mode }, null, value.selected ? (value.danger ? 'redButton' : 'selected') : null)}} +
    + {{/for}} + {{else data.screen == 5}} +

    Alarm Threshold

    + Partial pressure for gases. + + + + + {{for data.thresholds}} + + + {{for value.settings :settingsValue:settingsIndex}} + + {{/for}} + + {{/for}} +
    min2min1max1max2
    {{:value.name}} + {{:helper.link(settingsValue.selected >= 0 ? helper.fixed(settingsValue.selected, 2) : "Off", null, { 'command' : 'set_threshold', 'env' : settingsValue.env, 'var' : settingsValue.val })}} +
    + {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/airlock_electronics.tmpl b/nano/templates/airlock_electronics.tmpl index 4c81b26df6cf..c75ea271167f 100644 --- a/nano/templates/airlock_electronics.tmpl +++ b/nano/templates/airlock_electronics.tmpl @@ -6,14 +6,17 @@ {{else}}
    - {{:helper.link((data.oneAccess ? "One" : "All") + ' Required', data.oneAccess ? "lock" : "unlock", {'one_access' : 1})}} {{:helper.link('Access Setup: ' + (data.autoset ? "AUTO" : "MANUAL"), data.autoset ? "lock" : "unlock", {'autoset' : 1})}} - {{:helper.link('Clear', 'refresh', {'clear' : 1})}} {{if data.lockable}} {{:helper.link('Lock', 'lock', {'lock' : 1})}} {{/if}} +{{if !data.autoset}} + {{:helper.link((data.oneAccess ? "One" : "All") + ' Required', data.oneAccess ? "lock" : "unlock", {'one_access' : 1})}} + {{:helper.link('Clear', 'refresh', {'clear' : 1})}} + {{/if}}
    +{{if !data.autoset}}
    @@ -36,6 +39,7 @@
    +{{/if}} {{/if}} diff --git a/nano/templates/alarm_monitor.tmpl b/nano/templates/alarm_monitor.tmpl index f39f248f0d99..4b5459ab48c6 100644 --- a/nano/templates/alarm_monitor.tmpl +++ b/nano/templates/alarm_monitor.tmpl @@ -1,37 +1,37 @@ - -{{for data.categories}} -

    {{:value.category}}

    - {{for value.alarms :alarmValue:alarmIndex}} - {{if alarmValue.origin_lost}} - {{:alarmValue.name}} Alarm Origin Lost
    - {{else}} - {{:alarmValue.name}}
    - {{/if}} - {{if alarmValue.has_cameras || alarmValue.lost_sources != ""}} -
    - {{if alarmValue.has_cameras}} -
    - {{for alarmValue.cameras :cameraValue:cameraIndex}} - {{if cameraValue.deact}} - {{:helper.link(cameraValue.name + " (deactivated)", '', {}, 'inactive')}} - {{else}} - {{:helper.link(cameraValue.name, '', {'switchTo' : cameraValue.camera})}} - {{/if}} - {{/for}} -
    - {{/if}} - {{if alarmValue.lost_sources != ""}} -
    -

    Lost Alarm Sources: {{:alarmValue.lost_sources}}

    -
    - {{/if}} -
    - {{/if}} - {{empty}} - --All Systems Nominal - {{/for}} -{{/for}} + +{{for data.categories}} +

    {{:value.category}}

    + {{for value.alarms :alarmValue:alarmIndex}} + {{if alarmValue.origin_lost}} + {{:alarmValue.name}} Alarm Origin Lost
    + {{else}} + {{:alarmValue.name}}
    + {{/if}} + {{if alarmValue.has_cameras || alarmValue.lost_sources != ""}} +
    + {{if alarmValue.has_cameras}} +
    + {{for alarmValue.cameras :cameraValue:cameraIndex}} + {{if cameraValue.deact}} + {{:helper.link(cameraValue.name + " (deactivated)", '', {}, 'inactive')}} + {{else}} + {{:helper.link(cameraValue.name, '', {'switchTo' : cameraValue.camera})}} + {{/if}} + {{/for}} +
    + {{/if}} + {{if alarmValue.lost_sources != ""}} +
    +

    Lost Alarm Sources: {{:alarmValue.lost_sources}}

    +
    + {{/if}} +
    + {{/if}} + {{empty}} + --All Systems Nominal + {{/for}} +{{/for}} diff --git a/nano/templates/apc.tmpl b/nano/templates/apc.tmpl index 581a54568484..c106f62904d3 100644 --- a/nano/templates/apc.tmpl +++ b/nano/templates/apc.tmpl @@ -72,12 +72,12 @@ {{if data.powerCellStatus != null}}
    - Charge Mode: + Recharge Battery:
    {{if data.locked && !data.siliconUser}} {{if data.chargeMode}} - Auto + On {{else}} Off {{/if}} @@ -95,6 +95,15 @@
    {{/if}} + +
    +
    + Telepresence Control: +
    +
    + {{:helper.link('Enabled', 'signal', {'toggle_rc' : 1}, data.remote_control ? 'selected' : null)}}{{:helper.link('Disabled', 'close', {'toggle_rc' : 1}, data.remote_control ? null : 'selected')}} +
    +

    Power Channels

    diff --git a/nano/templates/appearance_changer.tmpl b/nano/templates/appearance_changer.tmpl index a4f6e40f730c..6d390e787157 100644 --- a/nano/templates/appearance_changer.tmpl +++ b/nano/templates/appearance_changer.tmpl @@ -1,76 +1,89 @@ -{{if data.change_race}} -
    -
    - Species: -
    -
    - {{for data.species}} - {{:helper.link(value.specimen, null, { 'race' : value.specimen}, null, data.specimen == value.specimen ? 'selected' : null)}} - {{/for}} -
    -
    -{{/if}} - -{{if data.change_gender}} -
    -
    - Gender: -
    -
    - {{for data.genders}} - {{:helper.link(value.gender_name, null, { 'gender' : value.gender_key}, null, data.gender == value.gender_key ? 'selected' : null)}} - {{/for}} -
    -
    -{{/if}} - -{{if data.change_eye_color || data.change_skin_tone || data.change_skin_color || data.change_hair_color || data.change_facial_hair_color}} -
    -
    - Colors: -
    -
    - {{if data.change_eye_color}} - {{:helper.link('Change eye color', null, { 'eye_color' : 1})}} - {{/if}} - {{if data.change_skin_tone}} - {{:helper.link('Change skin tone', null, { 'skin_tone' : 1})}} - {{/if}} - {{if data.change_skin_color}} - {{:helper.link('Change skin color', null, { 'skin_color' : 1})}} - {{/if}} - {{if data.change_hair_color}} - {{:helper.link('Change hair color', null, { 'hair_color' : 1})}} - {{/if}} - {{if data.change_facial_hair_color}} - {{:helper.link('Change facial hair color', null, { 'facial_hair_color' : 1})}} - {{/if}} -
    -
    -{{/if}} - -{{if data.change_hair}} -
    -
    - Hair styles: -
    -
    - {{for data.hair_styles}} - {{:helper.link(value.hairstyle, null, { 'hair' : value.hairstyle}, null, data.hair_style == value.hairstyle ? 'selected' : null)}} - {{/for}} -
    -
    -{{/if}} - -{{if data.change_facial_hair}} -
    -
    - Facial hair styles: -
    -
    - {{for data.facial_hair_styles}} - {{:helper.link(value.facialhairstyle, null, { 'facial_hair' : value.facialhairstyle}, null, data.facial_hair_style == value.facialhairstyle ? 'selected' : null)}} - {{/for}} -
    -
    -{{/if}} +{{if data.change_race}} +
    +
    + Species: +
    +
    + {{for data.species}} + {{:helper.link(value.name, null, { 'race' : value.uid}, null, data.current_species_uid == value.uid ? 'selected' : null)}} + {{/for}} +
    +
    +{{/if}} + +{{if data.change_gender}} +
    +
    + Pronouns: +
    +
    + {{for data.genders}} + {{:helper.link(value.gender_name, null, { 'gender' : value.gender_key}, null, data.gender == value.gender_key ? 'selected' : null)}} + {{/for}} +
    +
    +{{/if}} + +{{if data.change_bodytype}} +
    +
    + Bodytype: +
    +
    + {{for data.bodytypes}} + {{:helper.link(value, null, { 'bodytype' : value}, null, data.bodytype == value ? 'selected' : null)}} + {{/for}} +
    +
    +{{/if}} + +{{if data.change_eye_color || data.change_skin_tone || data.change_skin_color || data.change_hair_color || data.change_facial_hair_color}} +
    +
    + Colors: +
    +
    + {{if data.change_eye_color}} + {{:helper.link('Change eye color', null, { 'eye_color' : 1})}} + {{/if}} + {{if data.change_skin_tone}} + {{:helper.link('Change skin tone', null, { 'skin_tone' : 1})}} + {{/if}} + {{if data.change_skin_color}} + {{:helper.link('Change skin color', null, { 'skin_color' : 1})}} + {{/if}} + {{if data.change_hair_color}} + {{:helper.link('Change hair color', null, { 'hair_color' : 1})}} + {{/if}} + {{if data.change_facial_hair_color}} + {{:helper.link('Change facial hair color', null, { 'facial_hair_color' : 1})}} + {{/if}} +
    +
    +{{/if}} + +{{if data.change_hair}} +
    +
    + Hair styles: +
    +
    + {{for data.hair_styles}} + {{:helper.link(value.hairstyle, null, { 'hair' : value.ref}, null, data.hair_style == value.hairstyle ? 'selected' : null)}} + {{/for}} +
    +
    +{{/if}} + +{{if data.change_facial_hair}} +
    +
    + Facial hair styles: +
    +
    + {{for data.facial_hair_styles}} + {{:helper.link(value.facialhairstyle, null, { 'facial_hair' : value.ref}, null, data.facial_hair_style == value.facialhairstyle ? 'selected' : null)}} + {{/for}} +
    +
    +{{/if}} diff --git a/nano/templates/atmos_alert.tmpl b/nano/templates/atmos_alert.tmpl index 92946e8d312d..a36b1bb9bafe 100644 --- a/nano/templates/atmos_alert.tmpl +++ b/nano/templates/atmos_alert.tmpl @@ -1,18 +1,18 @@ -

    Priority Alerts

    -{{for data.priority_alarms}} -
    - {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}} -
    -{{empty}} - No priority alerts detected. -{{/for}} - -

    Minor Alerts

    -{{for data.minor_alarms}} -
    - {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}} -
    -{{empty}} - No minor alerts detected. -{{/for}} - +

    Priority Alerts

    +{{for data.priority_alarms}} +
    + {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}} +
    +{{empty}} + No priority alerts detected. +{{/for}} + +

    Minor Alerts

    +{{for data.minor_alarms}} +
    + {{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}} +
    +{{empty}} + No minor alerts detected. +{{/for}} + diff --git a/nano/templates/atmos_control.tmpl b/nano/templates/atmos_control.tmpl index ed07487296d0..cca5724ad935 100644 --- a/nano/templates/atmos_control.tmpl +++ b/nano/templates/atmos_control.tmpl @@ -1,15 +1,26 @@ -
    - {{for data.alarmsAlert}} - {{:helper.link(value.name, null, {'alarm' : value.ref}, null, 'redButton')}} - {{/for}} -
    -
    - {{for data.alarmsDanger}} - {{:helper.link(value.name, null, {'alarm' : value.ref}, null, 'yellowButton')}} - {{/for}} -
    -
    - {{for data.alarms}} - {{:helper.link(value.name, null, {'alarm' : value.ref}, null, null)}} - {{/for}} +
    + {{:helper.link('Refresh', 'refresh', {'refresh' : 1})}} +
    +
    +
    + Filter term: +
    +
    + {{:helper.link(data.filter, null, {'filter_set' : 1})}} +
    +
    +
    + {{for data.alarmsAlert}} + {{:helper.link(value.name, null, {'alarm' : value.ref}, null, 'redButton')}} + {{/for}} +
    +
    + {{for data.alarmsDanger}} + {{:helper.link(value.name, null, {'alarm' : value.ref}, null, 'yellowButton')}} + {{/for}} +
    +
    + {{for data.alarms}} + {{:helper.link(value.name, null, {'alarm' : value.ref}, null, null)}} + {{/for}}
    \ No newline at end of file diff --git a/nano/templates/camera_settings.tmpl b/nano/templates/camera_settings.tmpl new file mode 100644 index 000000000000..7620bc0da8a1 --- /dev/null +++ b/nano/templates/camera_settings.tmpl @@ -0,0 +1,61 @@ +{{if data.error}} +

    An error has occurred:

    + Additional information: {{:data.error}}
    + Please try again. If the problem persists contact your system administrator for assistance. +
    + {{:helper.link('Refresh', null, { "refresh" : 1 })}} +
    +{{else}} + Welcome to the network configuration utility. Please consult your system administrator if you have any questions about your device.
    +

    Network Configuration

    +
    + Network Status: +
    +
    + {{:data.status}} +
    +
    + Network ID: +
    +
    + {{:helper.link(data.network_id, null, { "change_id" : 1 })}} +
    +
    + Network KEY: +
    +
    + {{:helper.link(data.network_key, null, { "change_key" : 1 })}} +
    +
    + Network TAG: +
    +
    + {{:helper.link(data.network_tag, null, { "change_net_tag" : 1 })}} +
    +
    + {{if data.channels}} +
    +
    + Camera Channels: +
    +
    + + + {{:helper.link("(+)", null, {"add_channel" : 1})}} + + + + + + {{for data.channels}} + + + + + {{/for}} +
    (-)Channel Name
    {{:helper.link("(-)", null, {"remove_channel" : value})}}{{:value}}
    +
    +
    + {{/if}} + EXONET Firmware v110.04.4h Copyright EXONETWORKS INC +{{/if}} \ No newline at end of file diff --git a/nano/templates/computer_fabricator.tmpl b/nano/templates/computer_fabricator.tmpl index 80696754558f..3fd551c3078b 100644 --- a/nano/templates/computer_fabricator.tmpl +++ b/nano/templates/computer_fabricator.tmpl @@ -12,7 +12,7 @@
    Current Price: - {{:data.totalprice}}T + {{:data.totalprice}}
    Battery: {{:helper.link('Standard', null, { "hw_battery" : 1 }, data.hw_battery == 1 ? 'selected' : null)}} @@ -62,13 +62,13 @@ Tesla Relay is an advanced wireless power relay that allows your device to connect to nearby area power controller to provide alternative power source.
    Nano Printer is device that allows printing of various documents. This device was certified EcoFriendlyPlus and is capable of recycling existing paper for printing purposes.
    Card Reader adds a slot that allows you to manipulate RFID cards. Please note that this is not necessary to allow the device to read your identification, it is just necessary to manipulate other cards.
    - Intellicard Slot is a specialised high powered hardware that can hold an intellicard with active AI personality. It is required for some specialised programs to run properly.
    + Intellicard Slot is a specialised high powered hardware that can hold an intelliCard with active AI personality. It is required for some specialised programs to run properly.
    {{else data.state == 2}}

    Step 3: Payment

    - Your device is now ready for fabrication..
    + Your device is now ready for fabrication.
    Please swipe your identification card to finish purchase.
    - Total price: {{:data.totalprice}}T + Total price: {{:data.totalprice}} {{else data.state == 3}}

    Step 4: Thank you for your purchase

    Should you experience any issues with your new device, contact technical support at support@computerservice.nt diff --git a/nano/templates/crew_monitor_map_header.tmpl b/nano/templates/crew_monitor_map_header.tmpl index 24398dec5b01..a86abc85d837 100644 --- a/nano/templates/crew_monitor_map_header.tmpl +++ b/nano/templates/crew_monitor_map_header.tmpl @@ -7,7 +7,7 @@ Used In File(s): code\modules\modular_computers\file_system\programs\medical\sui
    Z Level:  {{for config.mapZLevels :zValue:zIndex}} - {{:helper.link(zValue, 'close', {'mapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} + {{:helper.link(zValue, 'close', {'switchMapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} {{/for}}
    diff --git a/nano/templates/crew_records.tmpl b/nano/templates/crew_records.tmpl index 4d19a8ba844f..f78b2128974a 100644 --- a/nano/templates/crew_records.tmpl +++ b/nano/templates/crew_records.tmpl @@ -37,16 +37,10 @@ {{/for}} {{else}} -{{if data.creation}} - {{:helper.link('New Record', 'document', {'new_record' : 1}, null)}} -{{/if}} -{{:helper.link('Name Search', 'search', {'search' : 'Name'}, null)}} -{{if data.dnasearch}} - {{:helper.link('DNA Search', 'search', {'search' : 'DNA'}, null)}} -{{/if}} -{{if data.fingersearch}} - {{:helper.link('Fingerprint Search', 'search', {'search' : 'Fingerprint'}, null)}} -{{/if}} +{{:helper.link('New Record', 'document', {'new_record' : 1}, null)}} +{{for data.searchable}} + {{:helper.link(value + ' Search', 'search', {'search' : value}, null)}} +{{/for}}

    Available records:

    diff --git a/nano/templates/deck_management.tmpl b/nano/templates/deck_management.tmpl index 854508625506..8246ce9ad749 100644 --- a/nano/templates/deck_management.tmpl +++ b/nano/templates/deck_management.tmpl @@ -1,11 +1,3 @@ -
    - You - {{if !data.default_access}} - do not - {{/if}} - have program access. -
    -{{if data.default_access}} {{if data.prog_state == 1}}

    Shuttles:

    {{for data.shuttles}} @@ -279,4 +271,3 @@ {{/if}} {{/if}} -{{/if}} diff --git a/nano/templates/deity.tmpl b/nano/templates/deity.tmpl deleted file mode 100644 index b249a8649600..000000000000 --- a/nano/templates/deity.tmpl +++ /dev/null @@ -1,116 +0,0 @@ - -
    -

    Deity Menu

    -
    - {{:data.name}} the {{:data.form_name}} -
    -
    - Current Boon: - {{if data.boon_name}} - {{:data.boon_name}} - {{else}} - N/A - {{/if}} -
    -
    - Power: {{:data.power}} Power Minimum: {{:data.power_min}} Regen: {{:data.regen}} -
    -
    - {{:helper.link('Followers', 'person', {'switchMenu' : 0, 'menu' : 'menu'}, data.menu == 0 ? 'disabled' : null)}} - {{:helper.link('Shop', 'suitcase', {'switchMenu' : 1, 'menu' : 'menu'}, data.menu == 1 ? 'disabled' : null)}} - {{:helper.link('Phenomena', 'star', {'switchMenu' : 2, 'menu' : 'menu'}, data.menu == 2 ? 'disabled' : null)}} -
    -
    -{{if data.menu == 0}} -

    Followers

    - {{for data.followers}} -
    - {{:value.name}} -
    -
    - {{:helper.link('Jump', 'zoomin', {'jump' : value.ref}, value.ref ? null : 'disabled')}} - {{:helper.link('Follow', 'zoomout', {'jump' : value.ref, 'follow' : 1}, value.ref ? null : 'disabled')}} -
    - {{empty}} - You have no minions! - {{/for}} -{{else data.menu == 1}} -

    Shop

    -
    - {{for data.categories}} - {{:helper.link(value, null, {'switchCategory' : index}, index == data.category ? 'disabled' : null)}} - {{/for}} -
    -
    - {{for data.item_data}} -
    -
    - {{:helper.link(value.name, null, {'buy' : value.ref})}} (Level {{:value.level}}) -
    -
    - Costs: {{:value.cost}} Requires: {{:value.requirements}} -
    -
    - {{:value.desc}} -
    -
    - {{empty}} - There is nothing there! - {{/for}} -{{else data.menu == 2}} -

    Phenomena

    -
    -
    - Selected Phenomena: -
    -
    - {{if data.selectedPhenomenaName}} - {{:helper.link(data.selectedPhenomenaName, null, {'clear_selected' : 1})}} - {{else}} - N/A - {{/if}} -
    -
    -
    - {{:helper.link('Phenomena', 'star', {'switchMenu' : 0, 'menu' : 'phenomenaMenu'}, data.phenomenaMenu == 0 ? 'disabled' : null)}} - {{:helper.link('Bindings', 'key', {'switchMenu' : 1, 'menu' : 'phenomenaMenu'}, data.phenomenaMenu == 1 ? 'disabled' : null)}} -
    - {{if data.phenomenaMenu == 0}} - {{for data.phenomenas}} -
    -
    - {{:helper.link(value.name, null, {'select_phenomena' : value.name})}} -
    -
    - Use Cost: {{:value.cost}} - {{if value.cooldown}} - Cooldown: {{:value.cooldown}} - {{/if}} -
    -
    - {{:value.description}} -
    -
    - {{empty}} - You don't have any phenomena! - {{/for}} - {{else data.phenomenaMenu == 1}} - {{for data.bindings}} -

    {{:value.intent}}

    - {{for value.intent_data :intentValue:intentKey}} -
    -
    - {{:intentValue.binding}} -
    -
    - {{:helper.link(intentValue.phenomena_name ? intentValue.phenomena_name : 'N/A', null, {'select_intent' : value.intent, 'select_binding' : intentValue.binding})}} -
    -
    - {{/for}} -
    - {{/for}} - {{/if}} -{{/if}} -
    \ No newline at end of file diff --git a/nano/templates/design_console.tmpl b/nano/templates/design_console.tmpl index 185ee431bb43..91e5eb60fca0 100644 --- a/nano/templates/design_console.tmpl +++ b/nano/templates/design_console.tmpl @@ -26,7 +26,7 @@
    {{for data.tech_levels}} - + {{/for}}
    DataStored
    {{:value.field}}{{:value.level}}
    {{:value.field}}{{:value.level}}
    @@ -58,7 +58,7 @@ {{for data.tech_levels}} - + {{/for}}
    DataStored
    {{:value.field}}{{:value.level}}
    {{:value.field}}{{:value.level}}
    @@ -69,7 +69,7 @@
    Connected devices
    - + {{for data.connected_analyzers}} {{if value.can_process}} diff --git a/nano/templates/design_database.tmpl b/nano/templates/design_database.tmpl index 29c6efe03893..db1dd81ea572 100644 --- a/nano/templates/design_database.tmpl +++ b/nano/templates/design_database.tmpl @@ -6,12 +6,16 @@
    External storage
    Analyzers
    - {{if data.disk_tech}} + {{if data.disk_tech || data.disk_error}} - - {{for data.disk_tech}} - - {{/for}} + {{if data.disk_error}} + invalid data format + {{else}} + + {{for data.disk_tech}} + + {{/for}} + {{/if}} {{else}} {{/if}} @@ -23,7 +27,7 @@
    {{:helper.link(data.disk_name, null, {'eject_disk' : 1})}}
    DataStored
    {{:value.field}}{{:value.level}}
    DataStored
    {{:value.field}}{{:value.level}}
    {{:data.disk_name}}
    {{for data.tech_levels}} - + {{/for}}
    DataStored
    {{:value.field}}{{:value.level}}
    {{:value.field}}{{:value.level}}
    diff --git a/nano/templates/docking.tmpl b/nano/templates/docking.tmpl index d4ef2d0922d0..a603ab5f8175 100644 --- a/nano/templates/docking.tmpl +++ b/nano/templates/docking.tmpl @@ -8,7 +8,7 @@
    {{:value.location}} {{:value.status}} - {{:helper.link(value.codes, '', {'edit_code' : value.tag})}} + {{:helper.link(value.codes, '', {'edit_docking_codes' : value.tag})}} {{if value.docking_attempt}} {{:helper.link('GRANT DOCK', '', {'dock' : value.tag})}} {{else value.docked}} @@ -18,4 +18,15 @@ {{/if}} {{/for}}
    +

    Docking beacons:

    + + +
    Beacon NameSizeDocking LockDocking by code + {{for data.docking_beacons}} +
    {{:helper.link(value.name, '', {'beacon' : value.network_tag})}} + {{:value.size}} + {{:value.locked ? 'LOCKED' : 'UNLOCKED'}} + {{:value.code_docking ? 'ENABLED' : 'DISABLED'}} + {{/for}} +
    {{/if}} \ No newline at end of file diff --git a/nano/templates/docking_beacon.tmpl b/nano/templates/docking_beacon.tmpl new file mode 100644 index 000000000000..0f22674b7bd4 --- /dev/null +++ b/nano/templates/docking_beacon.tmpl @@ -0,0 +1,92 @@ +{{:helper.link('Network Settings', '', {'settings' : 1})}} +

    Docking Beacon

    +
    +
    + Construction mode: +
    +
    + {{:helper.link(data.construction_mode ? 'Enabled' : 'Disabled', null, {'toggle_construction' : '1'}, null , null)}} +
    +
    +{{if data.construction_mode}} +
    +
    + Construction Size: +
    +
    + {{:helper.link(data.size, '', {'edit_size' : 1})}} +
    +
    + Ship Name: +
    +
    + {{:helper.link(data.ship_name ? data.ship_name : 'No name!', 'pencil', {'change_ship_name' : '1'}, null , null)}} +
    +
    + Ship Color: +
    +
    + {{:helper.link('Change color', 'pencil', {'change_color' : 1}, null, null)}} +
    +
    + Errors: +
    +
    +
    + {{for data.errors}} + {{:value}}
    + {{/for}} +
    +
    +
    + {{:helper.link('Finalize Ship', 'arrowthickstop-1-e', {'finalize' : '1'}, null , null)}} +
    +
    + {{:helper.link('Check Construction Validity', 'gear', {'check_validity' : '1'}, null , null)}} +
    +
    +{{else}} +
    +
    + Dock Name: +
    +
    + {{:helper.link(data.display_name, '', {'edit_display_name' : 1})}} +
    +
    + Docking Size: +
    +
    + {{:helper.link(data.size, '', {'edit_size' : 1})}} +
    +
    + Locked: +
    +
    + {{:helper.link(data.locked ? 'Locked' : 'Unlocked', '', {'toggle_lock' : 1})}} +
    + {{if data.locked}} +
    + Permitted Shuttles +
    +
    +
    + {{for data.permitted}} + {{:value}}
    + {{/for}} +
    + {{:helper.link('Add/Remove Permission', '', {'edit_permitted_shuttles' : 1})}} +
    +
    + Access by Codes +
    +
    + {{:helper.link(data.allow_codes ? 'Codes:' : 'No access', '', {'toggle_codes' : 1})}} + {{if data.allow_codes}} + {{:helper.link(data.codes, '', {'edit_codes' : 1})}} + {{/if}} +
    + {{/if}} +
    +{{/if}} +{{:helper.link(data.construction_mode ? 'Project Construction Zone' : 'Project Docking Zone', '', {'project' : 1})}} \ No newline at end of file diff --git a/nano/templates/door_control.tmpl b/nano/templates/door_control.tmpl index a1b0e35a2646..4197497ce8fb 100644 --- a/nano/templates/door_control.tmpl +++ b/nano/templates/door_control.tmpl @@ -1,65 +1,65 @@ - - -
    -
    - Main power is - {{if data.main_power_loss == 0}} - online - {{else data.main_power_loss == -1}} - offline - {{else}} - offline for {{:data.main_power_loss}} second{{:data.main_power_loss == 1 ? '' : 's'}} - {{/if}}. -
    -
    - {{:helper.link(data.main_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'main_power'}, data.main_power_loss == 0 ? null : 'disabled', data.main_power_loss == 0 ? 'redButton' : null)}} -
    -
    - -
    -
    - Backup power is - {{if data.backup_power_loss == 0}} - online - {{else data.backup_power_loss == -1}} - offline - {{else}} - offline for {{:data.backup_power_loss}} second{{:data.backup_power_loss == 1 ? '' : 's'}} - {{/if}}. -
    -
    - {{:helper.link(data.backup_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'backup_power'}, data.backup_power_loss == 0 ? null : 'disabled', data.backup_power_loss == 0 ? 'redButton' : null)}} -
    -
    - -
    -
    - Electrified Status: -
    -
    - {{:helper.link('Offline' , null, {'command' : 'electrify_permanently', 'activate' : "0" }, data.electrified == 0 ? 'selected' : null)}} - {{:helper.link(data.electrified <= 0 ? 'Temporary (30s)' : 'Temporary (' + data.electrified +'s)', null, {'command' : 'electrify_temporary', 'activate' : "1"}, data.electrified > 0 ? 'redButton' : null)}} - {{:helper.link('Permanent', null, {'command' : 'electrify_permanently', 'activate' : "1"}, data.electrified == -1 ? 'redButton' : null)}} -
    -
    - -
    - - - {{for data.commands}} - - - - - - {{/for}} -
    {{:value.name}}:{{:helper.link(value.enabled, null, {'command' : value.command, 'activate' : value.act ? 1 : 0}, value.active ? 'selected' : null)}}{{:helper.link(value.disabled,null, {'command' : value.command, 'activate' : value.act ? 0 : 1}, !value.active ? (value.danger ? 'redButton' : 'selected') : null)}}
    + + +
    +
    + Main power is + {{if data.main_power_loss == 0}} + online + {{else data.main_power_loss == -1}} + offline + {{else}} + offline for {{:data.main_power_loss}} second{{:data.main_power_loss == 1 ? '' : 's'}} + {{/if}}. +
    +
    + {{:helper.link(data.main_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'main_power'}, data.main_power_loss == 0 ? null : 'disabled', data.main_power_loss == 0 ? 'redButton' : null)}} +
    +
    + +
    +
    + Backup power is + {{if data.backup_power_loss == 0}} + online + {{else data.backup_power_loss == -1}} + offline + {{else}} + offline for {{:data.backup_power_loss}} second{{:data.backup_power_loss == 1 ? '' : 's'}} + {{/if}}. +
    +
    + {{:helper.link(data.backup_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'backup_power'}, data.backup_power_loss == 0 ? null : 'disabled', data.backup_power_loss == 0 ? 'redButton' : null)}} +
    +
    + +
    +
    + Electrified Status: +
    +
    + {{:helper.link('Offline' , null, {'command' : 'electrify_permanently', 'activate' : "0" }, data.electrified == 0 ? 'selected' : null)}} + {{:helper.link(data.electrified <= 0 ? 'Temporary (30s)' : 'Temporary (' + data.electrified +'s)', null, {'command' : 'electrify_temporary', 'activate' : "1"}, data.electrified > 0 ? 'redButton' : null)}} + {{:helper.link('Permanent', null, {'command' : 'electrify_permanently', 'activate' : "1"}, data.electrified == -1 ? 'redButton' : null)}} +
    +
    + +
    + + + {{for data.commands}} + + + + + + {{/for}} +
    {{:value.name}}:{{:helper.link(value.enabled, null, {'command' : value.command, 'activate' : value.act ? 1 : 0}, value.active ? 'selected' : null)}}{{:helper.link(value.disabled,null, {'command' : value.command, 'activate' : value.act ? 0 : 1}, !value.active ? (value.danger ? 'redButton' : 'selected') : null)}}
    diff --git a/nano/templates/email_administration.tmpl b/nano/templates/email_administration.tmpl index 39cad285ab0b..48a3ae0fe248 100644 --- a/nano/templates/email_administration.tmpl +++ b/nano/templates/email_administration.tmpl @@ -63,7 +63,6 @@
    {{:helper.link(data.cur_suspended ? 'Unsuspend' : 'Suspend', null, {'ban' : data.cur_uid})}} - {{:helper.link('Set Password', null, {'changepass' : data.cur_uid})}} {{:helper.link('Return', null, {'back' : 1})}}
    @@ -92,15 +91,10 @@ {{else}}

    Welcome to Email Administration System

    SECURE SYSTEM - Have your identification ready

    - {{:helper.link('Create New Account', null, {'newaccount' : 1})}}

    Select account which you wish to administrate: {{for data.accounts}} -
    {{:helper.link(value.login, null, {'viewaccount' : value.uid})}} +
    {{:helper.link(value.login, null, {'viewaccount' : value.login})}} {{/for}}
    -{{/if}} -{{if data.terminal}} -

    MANUAL SYSTEM ACCESS

    -{{:helper.link('ACTIVATE TERMINAL', null, {'PC_terminal' : 1})}} {{/if}} \ No newline at end of file diff --git a/nano/templates/email_client.tmpl b/nano/templates/email_client.tmpl index 70165ccd7992..8f25f4a26309 100644 --- a/nano/templates/email_client.tmpl +++ b/nano/templates/email_client.tmpl @@ -27,8 +27,12 @@ {{else data.current_account}} Welcome to your account, {{:data.current_account}}
    {{:helper.link('New Message', 'mail-closed', {'new_message' : 1})}} - {{:helper.link('Change Password', 'locked', {'changepassword' : 1})}} - {{:helper.link('Log Out', 'key', {'logout' : 1})}}

    + {{:helper.link('Set notification', 'alert', {'set_notification' : 1})}} + {{if data.notification_mute}} + {{:helper.link('Unmute', 'volume-off', {'mute' : 1})}} + {{else}} + {{:helper.link('Mute', 'volume-on', {'mute' : 1})}} + {{/if}}

    {{if data.addressbook}} {{:helper.link('Back', null, {'close_addressbook' : 1})}} {{:helper.link('Enter Email', 'pencil', {'edit_recipient' : 1})}} @@ -36,7 +40,7 @@
    Address book: {{for data.accounts}} -
    {{:value.name}}{{:value.job}}{{:helper.link(value.login, null, {'set_recipient' : value.login})}} +
    {{:value.name}}{{:value.job}}{{:helper.link(value.address, null, {'set_recipient' : value.address})}} {{/for}}
    {{else data.new_message}} @@ -167,28 +171,4 @@ No messages found in selected folder {{/if}} {{/if}} -{{else}} - Welcome to Email System. Please log in. -
    -
    - Email address: -
    -
    - {{:data.stored_login}}  -
    -
    - Password: -
    -
    - {{:data.stored_password}}  -
    -
    - Options: -
    -
    - {{:helper.link('Enter Login', null, {'edit_login' : 1})}} - {{:helper.link('Enter Password', null, {'edit_password' : 1})}} - {{:helper.link('Log In', null, {'login' : 1})}} -
    -
    {{/if}} \ No newline at end of file diff --git a/nano/templates/engines_control.tmpl b/nano/templates/engines_control.tmpl index 4df88e86014b..c9ec27c77c73 100644 --- a/nano/templates/engines_control.tmpl +++ b/nano/templates/engines_control.tmpl @@ -29,6 +29,8 @@ {{:data.total_thrust}}
    + + {{if data.needs_dampers}}
    diff --git a/nano/templates/fabricator.tmpl b/nano/templates/fabricator.tmpl index 53142354c95c..bdca3f6087a9 100644 --- a/nano/templates/fabricator.tmpl +++ b/nano/templates/fabricator.tmpl @@ -1,114 +1,27 @@ + +{{#def.fab_shared}} + + + +{{ fab_header( data.network, data.network_id ); }} + {{if data.functional}} - - {{if data.color_selectable}} - - - - - {{/if}} - {{if data.network}} - - - {{:helper.link(data.network, null, { 'settings': 1 }, null)}} - - - {{/if}} - - - - - - - - - - - - - -
    - Color - - {{:helper.link('(Set)', null, {'color_select' : 1})}} -
    - Connected to local network. - -
    - - - - - - - {{for data.material_storage}} - - - - - - {{/for}} -
    ResourceStorageOptions
    {{:value.name}}{{:value.stored}}/{{:value.max}}{{:helper.link(value.eject_label, null, {'eject_mat' : value.eject_key})}}
    -
    - - - - - - - - - - - -
    Current BuildUnitsProgress
    {{:data.current_build.name}}{{:data.current_build.multiplier}}{{:data.current_build.progress}}
    -
    - - - - - - - {{for data.build_queue}} - - - - {{if value.reference}} - - {{else}} - - {{/if}} - - {{/for}} -
    PendingUnitsOptions
    {{:value.name}}{{:value.multiplier}}{{:helper.link('Cancel', null, {'cancel' : value.reference})}}-
    -
    Selected Category {{:helper.link(data.category, null, {'change_category' : 1})}}
    - - - - - - - {{for data.build_options}} - - {{if value.illegal}} - - {{else}} - - {{/if}} - - - - {{/for}} -
    DesignCostOptions
    {{:value.name}}{{:value.name}}{{:value.cost}} - {{if !value.unavailable}} - {{:helper.link('Queue', null, {'make' : value.reference, 'multiplier' : 1})}} - {{for value.multiplier :multValue:multIndex}} - {{:helper.link(multValue.label, null, {'make' : value.reference, 'multiplier' : multValue.multiplier})}} - {{/for}} - {{else}} - Insufficient resources. - {{/if}} -
    -
    + +
    + {{ fab_resources_table(data.expand_resources, data.material_storage); }} + {{ fab_construction_queue(data.expand_queue, data.build_queue, data.current_build); }} + {{ fab_configuration( data.skip_config, data.expand_config, data); }} + {{ fab_display_filter( data.category, data.filtering, data.hide_categories); }} +
    + + + {{ fab_build_options( data.build_options ); }} + {{else}} -

    FABRICATOR OFFLINE. CONTACT SYSTEM ADMINISTRATOR.

    +

    FABRICATOR OFFLINE. CONTACT SYSTEM ADMINISTRATOR.

    + {{/if}} diff --git a/nano/templates/fabricator_bioprinter.tmpl b/nano/templates/fabricator_bioprinter.tmpl new file mode 100644 index 000000000000..301c7360296f --- /dev/null +++ b/nano/templates/fabricator_bioprinter.tmpl @@ -0,0 +1,93 @@ + +{{#def.fab_shared}} + + + + + +{{function display_dna(dna) { }} +
      +
    • UE: {{:dna.UE}}
    • +
    • Name: {{:dna.real_name}}
    • +
    • Specie: {{:dna.species}}
    • +
    • Blood Type: {{:dna.btype}}
    • +
    +{{ } }} + + +{{function fab_organ_config_summary(dna) { + var summary = " ["; + + if(dna != undefined) { + summary += "DNA: " + dna.real_name + ", " + dna.species; + } else { + summary += "!! No DNA !! "; + }; + + return summary + "]"; +} }} + + {{function fab_organ_config( dna, expand_config) { }} +
    + {{:helper.link(make_list_toggle_prefix(expand_config, 'Configuration') + (expand_config ? '' : fab_organ_config_summary(dna) ), null, {'toggle_config' : 1}, null, 'linkSubtle') }} +
    + {{if expand_config}} +
    + +
    + {{if dna}} +
    {{:helper.link('DNA:', 'trash', {'flush_dna' : 1} ) }}
    +
    {{display_dna(dna);}}
    + {{else}} +
    DNA:
    +

    No DNA sample loaded.

    + {{/if}} +
    +
    + {{/if}} + {{ } }} + + + +{{fab_header( data.network, data.network_id ); }} + +{{if data.functional}} + +
    + {{ fab_resources_table( data.expand_resources, data.material_storage ); }} + {{ fab_construction_queue( data.expand_queue, data.build_queue, data.current_build ); }} + {{ fab_organ_config( data.dna, data.expand_config ); }} +
    + + + {{ fab_build_options(data.build_options); }} + +{{else}} +

    FABRICATOR OFFLINE. CONTACT SYSTEM ADMINISTRATOR.

    +{{/if}} diff --git a/nano/templates/fabricator_robot.tmpl b/nano/templates/fabricator_robot.tmpl new file mode 100644 index 000000000000..4b82fa884087 --- /dev/null +++ b/nano/templates/fabricator_robot.tmpl @@ -0,0 +1,62 @@ + +{{#def.fab_shared}} + + + + + {{function fab_limb_config_summary(species) { + var summary = " ["; + + if(species != undefined) { + summary += species; + } else { + summary += "!! No species !! "; + }; + + return summary + "]"; +} }} + +{{function fab_limb_config( species, expand_config) { }} +
    + {{:helper.link(make_list_toggle_prefix(expand_config, 'Configuration') + (expand_config ? '' : fab_limb_config_summary(species) ), null, {'toggle_config' : 1}, null, 'linkSubtle') }} +
    + {{if expand_config}} +
    + +
    +
    Current Species:
    +
    {{:helper.link( species, null, {'pick_species' : 1} ) }}
    +
    +
    + {{/if}} +{{ } }} + + + +{{fab_header( data.network, data.network_id ); }} + +{{if data.functional}} + +
    + {{ fab_resources_table( data.expand_resources, data.material_storage ); }} + {{ fab_construction_queue( data.expand_queue, data.build_queue, data.current_build ); }} + {{ fab_limb_config( data.species, data.expand_config ); }} + {{ fab_display_filter( data.category, data.filtering, data.hide_categories ); }} +
    + + + {{ fab_build_options(data.build_options); }} + +{{else}} +

    FABRICATOR OFFLINE. CONTACT SYSTEM ADMINISTRATOR.

    +{{/if}} \ No newline at end of file diff --git a/nano/templates/fabricator_shared.tmpl b/nano/templates/fabricator_shared.tmpl new file mode 100644 index 000000000000..98eb3f9ab79f --- /dev/null +++ b/nano/templates/fabricator_shared.tmpl @@ -0,0 +1,414 @@ + +{{#def.net_shared}} + + + + + + + +{{function get_longest_material_name(material_storage){ + var longest = 0; + for(var item in material_storage){ + if(material_storage[item].name.length > longest){ + longest = material_storage[item].name.length; + }; + }; + return longest; +} }} + + +{{function shorten_number(amount, fixed) { + var billions = amount / 1000000000; + var millions = amount / 1000000; + var thousands = amount / 1000; + + if(billions >= 1){ + return String(fixed? billions.toFixed(3) : billions) + 'G'; + } + else if(millions >= 1){ + return String(fixed? millions.toFixed(3) : millions) + 'M'; + } + else if(thousands >= 1){ + return String(fixed? thousands.toFixed(3) : thousands) + 'K'; + } + + return String((fixed? amount.toFixed(3) : amount)); +} }} + + +{{function pad_string(str, padlength, padchar) { + var padding = ''; + var strlen = str.length; + if(padlength > strlen){ + for(var i = 0; i < (padlength - strlen); i++) { + padding += padchar; + }; + }; + return str + padding; +} }} + + +{{function make_list_toggle_prefix(shown, list_name) { + return (shown? '-' : '+') + ' ' + list_name; +} }} + + +{{function fab_header(network, network_id) { }} + {{net_connection_settings(network, network_id);}} +{{ } }} + + + + + {{function make_material_list_summary(material_storage) { + var summary = ''; + if(material_storage){ + var nbempty = 0; + for(var item in material_storage){ + var current = material_storage[item].name.substr(0,2) + ':' + shorten_number(material_storage[item].stored, true) + ' '; + if(material_storage[item].stored <= 0){ + nbempty += 1; + }; + }; + if(nbempty >= material_storage.length){ + summary = "Materials depleted!"; + } + else if(nbempty > 0) { + summary = '' + nbempty + ' depleted material(s)'; + }; + } + if(summary.length){ + summary = ' [ ' + summary + ']'; + } + return summary; +} }} + + +{{function fab_resources_table_entry(name, amount, max, unit, longestNameLen, ejectKey) { }} +
    + {{:helper.link('', 'eject', {'eject_mat' : ejectKey}, null, 'link') }} {{:pad_string(name, longestNameLen, ' ') }} {{:pad_string(amount, 8, ' ') }}/{{:pad_string(max, 8, ' ')}} {{:unit}} +
    +{{ } }} + + +{{function fab_resources_table(expand_resources, material_storage) { }} + +
    + {{: helper.link( make_list_toggle_prefix(expand_resources, 'Materials') + make_material_list_summary(material_storage), null, {'toggle_resources' : 1}, null, 'linkSubtle') }} +
    + + {{if expand_resources}} + {{longest_material_name = get_longest_material_name(material_storage);}} + {{for material_storage}} + {{fab_resources_table_entry(value.name, shorten_number(value.stored, true), shorten_number(value.max, true), value.unit, longest_material_name, value.eject_key);}} + {{/for}} + {{/if}} +{{ } }} + + + + {{function make_queue_summary(current_build, build_queue) { + var summary = ''; + if(current_build){ + summary += current_build.name + ' (' + current_build.multiplier + ') ' + current_build.progress; + } + if(build_queue && build_queue.length > 0){ + summary += ' (' + build_queue.length + ' queued)'; + } + if(summary.length > 0){ + summary = ' [' + summary + ']' + } + return summary; +} }} + + +{{function fab_construction_queue(expand_queue, build_queue, current_build) { }} + +
    + {{: helper.link( (make_list_toggle_prefix(expand_queue, 'Queue') + make_queue_summary(current_build, build_queue)), null, {'toggle_queue' : 1}, null, 'linkSubtle') }} +
    + + {{if expand_queue}} +
    Current:
    +
    + {{if current_build}} + {{:current_build.name}} {{:current_build.multiplier}} {{:current_build.progress}} + {{else}} + -- + {{/if}} +
    +
    Queued:
    +
    + {{if build_queue && build_queue.length > 0}} + {{for build_queue}} + {{if value.reference}}{{:helper.link((value.name + ' x' + value.multiplier), 'cancel', {'cancel' : value.reference}, null, 'linkCancel')}}{{else}} {{:(value.name + ' x' + value.multiplier)}} {{/if}} + {{/for}} + {{else}} + -- + {{/if}} +
    + {{/if}} +{{ } }} + + + +{{function draw_colored_square(color) { }} + + +{{ } }} + +{{function fab_configuration_summary_color(expand_config, color) { + if(!expand_config){ + return ' [' + 'Color] '; + } + return ''; +} }} + +{{function fab_configuration_color(color_selectable, color) { }} + {{if color_selectable}} +
    +
    + Color: +
    +
    + {{draw_colored_square(color);}} {{:helper.link( 'set', null, {'color_select' : 1}) }} +
    +
    + {{/if}} +{{ } }} + +{{function fab_configuration(skip_config, expand_config, data) { }} + {{if !skip_config}} +
    + {{: helper.link( make_list_toggle_prefix(expand_config, 'Configuration') + fab_configuration_summary_color(expand_config, data.color), null, {'toggle_config' : 1}, null, 'linkSubtle') }} +
    + {{if expand_config}} +
    + {{fab_configuration_color( data.color_selectable, data.color );}} +
    + {{/if}} + {{/if}} +{{ } }} + + +{{ function fab_display_filter( category, filtering, hide_categories ) { }} +
    Filtering
    +
    + {{if !hide_categories}} +
    +
    + Category +
    +
    + {{:helper.link(category, null, {'change_category' : 1})}} +
    +
    + {{/if}} +
    +
    + Filter +
    +
    + {{:helper.link(filtering, null, {'set_filter' : 1})}} +
    +
    +
    +{{ } }} + + +{{function fab_make_cost_list( materials ) { }} +
      + {{if !materials}} +
    • --
    • + {{else}} + {{for materials :valMat :valIdx}} +
    • + {{if !valMat.has_enough}} {{/if}} + {{:shorten_number(valMat.amount)}} {{:valMat.name}} + {{if !valMat.has_enough}} {{/if}} +
    • + {{/for}} + {{/if}} +
    +{{ } }} + + +{{function fab_make_multiplier_buttons( unavailable, reference, multiplier ) { }} + {{:helper.link('x1', null, {'make' : reference, 'multiplier' : 1}, (unavailable ? 'disabled' : null))}} + {{for multiplier :multValue :multIndex}} + {{:helper.link(multValue.label, null, {'make' : reference, 'multiplier' : multValue.multiplier}, (unavailable ? 'disabled' : null) )}} + {{/for}} +{{ } }} + + +{{function fab_make_option_title(name, illegal) { }} + {{if illegal}}{{/if}} + {{:name}} + {{if illegal}}{{/if}} +{{ } }} + + +{{function fab_build_options( build_options ) { }} +
    + + + + + + + {{for build_options}} + + + + + + + + + {{/for}} +
    DesignCost
    {{ fab_make_option_title(value.name, value.illegal); }}{{ fab_make_cost_list(value.materials); }}{{ fab_make_multiplier_buttons(value.unavailable, value.reference, value.multiplier); }}
    +{{ } }} + diff --git a/nano/templates/fax_machine.tmpl b/nano/templates/fax_machine.tmpl new file mode 100644 index 000000000000..8937190b7ab4 --- /dev/null +++ b/nano/templates/fax_machine.tmpl @@ -0,0 +1,105 @@ + +{{function prepare_history(fax_history){ + if(!fax_history){ + return "No History to Display"; + }; + let hmtl = ""; + let startpos = Math.max(fax_history.length - 500, 1); + for(let i = startpos; i < fax_history.length; ++i){ + hmtl += fax_history[i] + "
    "; + }; + return "
    " + hmtl + "
    "; +} }} + + +{{function settings_page() { }} + {{:helper.link("Back", "triangle-1-w", {"change_page" : "main"} ) }} +

    + +

    Disk Drive

    + {{:helper.link((data.disk? data.disk_name : "-----------"), data.disk? "eject" : null, data.disk? {"eject_disk":1} : {"insert_disk":1}) }} + +

    Usage History

    +
    + {{if data.fax_history && (data.fax_history.length > 500) }} + Full history is too big to display
    + ...
    + {{else data.fax_history}} + {{prepare_history(data.fax_history); }} + {{else}} + No History to Display + {{/if}} + +
    +{{ } }} + + +{{function main_page() { }} + + + {{if data.has_disk_drive}} + {{:helper.link("Disk", "gear", {"change_page":"settings"}) }} + {{/if}} + + {{#def.stock_parts_printer_shared}} +
    + +

    Fax

    + + + {{if data.has_card_reader}} + + + + + {{/if}} + + + + + {{if data.has_disk_drive}} + + + {{if data.disk}} + + + {{else}} + + {{/if}} + + {{/if}} + + + + {{if data.has_disk_drive}} + + {{/if}} + + + + +
    ID Card:{{:helper.link((data.id_card? data.id_card_info : "-----------"), (data.id_card? "key" : null), {"id_card":1} ) }}
    Document:{{:helper.link(data.scanner_item? "Eject" : "-----------", data.scanner_item? "document" : null, data.scanner_item? {"remove_item":1} : {"insert_item":1} ) }}
    Quick Dial: + + Insert Disk to Store Contacts
    Destination URI:
    + +
    + +{{ } }} + + +{{#def.net_shared}} +{{net_connection_settings(data.network_tag, data.network_id);}} +{{if data.is_operational}} + {{if data.page == 'settings'}} + {{settings_page();}} + {{else data.page == 'main'}} + {{main_page();}} + {{/if}} +{{else}} + SYSTEM ERROR +{{/if}} \ No newline at end of file diff --git a/nano/templates/file_browser.tmpl b/nano/templates/file_browser.tmpl new file mode 100644 index 000000000000..5453c8b6876b --- /dev/null +++ b/nano/templates/file_browser.tmpl @@ -0,0 +1,75 @@ +{{if data.error}} +

    A disk error has occurred:

    + Additional information: {{:data.error}}
    + Please try again. If the problem persists contact your system administrator for assistance. + {{:helper.link('Back to file select', null, { "BRS_back" : 1 })}} +{{else}} + {{:helper.link('Back to program', 'arrowreturnthick-1-w', { "BRS_back" : 1 })}} + {{if data.current_disk}} +

    Available files ({{:data.current_disk}}):

    + +
    File name + File type + File size (GQ) + Operations + {{if data.saving_file}} + {{:helper.link('+', 'folder-collapsed', { "BRS_create_dir" : 1})}} + {{/if}} + {{:helper.link('', 'arrowthickstop-1-n', { "BRS_up_directory" : 1}, data.up_directory ? null : null)}} + {{for data.files}} + {{if value.dir}} +
    {{:helper.link(value.name, 'folder-collapsed', { "BRS_change_directory" : value.name})}} + + + {{if !data.saving_file}} + {{:helper.link('SELECT', null, { "BRS_select_file" : value.name}, value.selectable ? null : 'disabled')}} + {{/if}} + {{else}} +
    {{:value.name}} + .{{:value.type}} + {{:value.size}}GQ + {{:helper.link('SELECT', null, { "BRS_select_file" : value.name}, value.selectable ? null : 'disabled')}} + {{/if}} + {{/for}} +
    +
    + {{if data.saving_file}} +
    + + + + + + +
    Save file as:{{:helper.link(data.curr_file_name + '.' + data.curr_file_type, null, { "BRS_rename_file" : 1}, null)}}{{:helper.link('Save', 'disk', { "BRS_save_file" : 1}, null)}}
    +
    + {{else}} +
    + + + + + +
    Selecting file: + + {{if data.curr_file_name}} + {{:data.curr_file_name}}.{{:data.curr_file_type}} + {{else}} + No file selected! + {{/if}} + {{:helper.link('Open', null, { "BRS_finalize_select" : 1}, data.curr_file_name ? null : 'disabled')}}
    +
    + {{/if}} +

    Selectable file types are {{:data.filetypes}}.

    + {{else}} +

    Select a disk.

    + +
    Disk + Description + {{for data.avail_disks}} +
    {{:helper.link(value.name, null, { "BRS_select_disk" : value.name})}} + {{:value.desc}} + {{/for}} +
    + {{/if}} +{{/if}} diff --git a/nano/templates/file_manager.tmpl b/nano/templates/file_manager.tmpl index d0558f468f97..248043b31e63 100644 --- a/nano/templates/file_manager.tmpl +++ b/nano/templates/file_manager.tmpl @@ -1,7 +1,3 @@ -
    -
    Storage Medium
    - {{:helper.link(data.current_source, null, { "PRG_change_filesource" : 1 }, null)}} -
    {{if data.transfer_file}}
    Current Transfer
    @@ -15,65 +11,158 @@ {{:data.transfer_file}} from {{:data.transfer_from}} to {{:data.transfer_to}}
    {{/if}} -{{if data.fileserver}} -
    -
    File Server
    - {{:helper.link(data.fileserver, null, { "PRG_changefileserver" : 1 }, null)}} -
    - {{/if}} {{if data.error}} -

    An error has occured:

    +

    An error has occurred:

    Additional information: {{:data.error}}
    Please try again. If the problem persists contact your system administrator for assistance. - {{:helper.link('Back to menu', null, { "PRG_closefile" : 1 })}} + {{:helper.link('Back to menu', null, { "PRG_clear_error" : 1 })}} +{{else data.file_error}} +

    An error with the selected file has occurred:

    + Additional information: {{:data.file_error}}
    + {{:helper.link('Back to menu', null, { "PRG_clear_error" : 1 })}} +{{else data.disk_error}} +

    An error with the selected disk has occurred:

    + Additional information: {{:data.disk_error}}
    + {{:helper.link('Back to menu', null, { "PRG_clear_error" : 1 })}} {{else}} - {{if data.filename}} + {{if data.file_mode == 0}} + + {{for data.disks}} + {{:helper.link(value.name, null, { "PRG_change_disk" : value.index }, value.selected ? 'selected' : null)}} + {{/for}} + {{:helper.link('+', null, { "PRG_change_disk" : '0' }, null)}} +
    +
    + {{if data.current_disk}} +

    Available files ({{:data.current_disk}}):

    + + + {{for data.files}} + {{if value.dir}} +
    File name + File type + File size (GQ) + Operations + + {{:helper.link('', 'arrowthickstop-1-n', { "PRG_up_directory" : 1}, data.up_directory ? null : 'disabled')}} + {{:helper.link('X', null, { "PRG_exit_disk" : 1})}} +
    {{:helper.link(value.name, 'folder-collapsed', { "PRG_openfile" : value.name})}} + + + + {{:helper.link('RENAME', null, { "PRG_rename" : value.name}, value.unrenamable ? 'disabled' : null)}} + {{:helper.link('DELETE', null, { "PRG_deletefile" : value.name}, value.undeletable ? 'disabled' : null)}} + {{:helper.link('CLONE', null, { "PRG_clone" : value.name}, value.undeletable ? 'disabled' : null)}} + {{:helper.link('TRANSFER TO', null, { "PRG_transferto" : value.name}, value.unsendable ? 'disabled' : null)}} + {{:helper.link('MANAGE PERMS', null, { "PRG_modifyperms" : value.name})}} + {{else}} +
    {{:value.name}} + .{{:value.type}} + {{:value.size}}GQ + + {{:helper.link('VIEW', null, { "PRG_openfile" : value.name})}} + {{:helper.link('RENAME', null, { "PRG_rename" : value.name}, value.undeletable ? 'disabled' : null)}} + {{:helper.link('DELETE', null, { "PRG_deletefile" : value.name}, value.undeletable ? 'disabled' : null)}} + {{:helper.link('CLONE', null, { "PRG_clone" : value.name}, value.undeletable ? 'disabled' : null)}} + {{:helper.link('TRANSFER TO', null, { "PRG_transferto" : value.name}, value.unsendable ? 'disabled' : null)}} + {{:helper.link('MANAGE PERMS', null, { "PRG_modifyperms" : value.name})}} + {{/if}} + {{/for}} +
    + {{:helper.link('NEW DATA FILE', null, { "PRG_newtextfile" : 1 })}} + {{:helper.link('NEW DIRECTORY', null, { "PRG_newdir" : 1 })}} + {{else}} +

    Select a disk.

    + + + {{for data.avail_disks}} +
    Disk + Description + Actions
    {{:helper.link(value.name, null, { "PRG_select_disk" : value.name})}} + {{:value.desc}} + {{if value.is_network}} + {{:helper.link('MOUNT SETTINGS', null, { "PRG_mount_settings" : value.name})}} + {{/if}} + {{/for}} +
    + {{:helper.link('MOUNT NETWORK DRIVE', null, { "PRG_mount_network" : 1 })}} + {{/if}} + {{else data.file_mode == 1}}

    Viewing file {{:data.filename}}

    {{:helper.link('CLOSE', null, { "PRG_closefile" : 1 })}} {{:helper.link('EDIT', null, { "PRG_edit" : 1 })}} {{:helper.link('PRINT', null, { "PRG_printfile" : 1 })}} + {{:helper.link('RUN', null, { "PRG_runfile" : 1 })}}

    {{:data.filedata}} - {{else}} -

    Available files ({{:data.current_source}}):

    - -
    File name - File type - File size (GQ) - Operations - {{for data.files}} -
    {{:value.name}} - .{{:value.type}} - {{:value.size}}GQ - - {{:helper.link('VIEW', null, { "PRG_openfile" : value.name })}} - {{:helper.link('DELETE', null, { "PRG_deletefile" : value.name }, value.undeletable ? 'disabled' : null)}} - {{:helper.link('RENAME', null, { "PRG_rename" : value.name }, value.undeletable ? 'disabled' : null)}} - {{:helper.link('CLONE', null, { "PRG_clone" : value.name }, value.undeletable ? 'disabled' : null)}} - {{:helper.link('COPY TO', null, { "PRG_copyto" : value.name }, value.undeletable ? 'disabled' : null)}} - {{/for}} -
    - {{if data.usbconnected}} -

    Available files (portable device):

    + {{else data.file_mode == 2}} +

    Modifying permissions for {{:data.filename}}

    + Users must be a member of at least one group in every access pattern to have file access +
    + {{:helper.link('READ ACCESS', null, {"PRG_change_perm" : "read"}, (data.current_perm == "read") ? 'selected' : null)}} + {{:helper.link('WRITE ACCESS', null, {"PRG_change_perm" : "write"}, (data.current_perm == "write") ? 'selected' : null)}} + {{:helper.link('PERMISSION MODIFICATION ACCESS', null, {"PRG_change_perm" : "mod"}, (data.current_perm == "mod") ? 'selected' : null)}} +

    - + {{for data.patterns}} + +
    File name - File type - File size (GQ) +
    Pattern + Groups Operations - {{for data.usbfiles}} -
    {{:value.name}} - .{{:value.type}} - {{:value.size}}GQ - - {{:helper.link('DELETE', null, { "PRG_usbdeletefile" : value.name }, value.undeletable ? 'disabled' : null)}} - {{if data.usbconnected}} - {{:helper.link('IMPORT', null, { "PRG_copyfromusb" : value.name }, value.undeletable ? 'disabled' : null)}} - {{/if}} +
    {{:helper.link("Pattern " + value.index, null, { "PRG_select_pattern" : value.index}, (data.selected_pattern == value.index) ? 'selected' : null)}} + {{:value.perm_list}} + {{:helper.link('Delete pattern', null, { "PRG_remove_pattern" : value.index})}} {{/for}}
    + {{:helper.link('Add pattern', null, { "PRG_add_pattern" : 1}, null)}} +
    + {{if data.selected_pattern}} +
    + {{if data.parent_groups}} +

    Parent Groups:

    + +
    Group + Operations + {{for data.parent_groups}} +
    {{:helper.link(value.parent_group, null, { "PRG_select_parent_group" : value.parent_group })}} + + {{if value.assigned}} + {{:helper.link('REMOVE', null, { "PRG_remove_group" : value.parent_group })}} + {{else}} + {{:helper.link('ASSIGN', null, { "PRG_assign_group" : value.parent_group })}} + {{/if}} + {{/for}} +
    + {{else data.selected_parent_group}} +

    Viewing Child Groups for: {{:data.selected_parent_group}}

    + {{if data.child_groups}} +

    Child Groups:

    + +
    Group + Operations + {{for data.child_groups}} +
    {{:value.child_group}} + + {{if value.assigned}} + {{:helper.link('REMOVE', null, { "PRG_remove_group" : value.child_group })}} + {{else}} + {{:helper.link('ASSIGN', null, { "PRG_assign_group" : value.child_group })}} + {{/if}} + {{/for}} +
    + {{else}} + No child groups found! + {{/if}} +
    + {{:helper.link('Back to parent group listing', null, { "PRG_select_parent_group" : null })}} +
    + {{else}} + No groups found on network! + {{/if}} {{/if}} - {{:helper.link('NEW DATA FILE', null, { "PRG_newtextfile" : 1 })}} +
    + {{:helper.link('CLOSE', null, { "PRG_closefile" : 1 })}}{{:helper.link('SAVE CHANGES', null, { "PRG_apply_perms" : 1})}} {{/if}} - {{/if}} diff --git a/nano/templates/fission_core.tmpl b/nano/templates/fission_core.tmpl new file mode 100644 index 000000000000..7163b0636964 --- /dev/null +++ b/nano/templates/fission_core.tmpl @@ -0,0 +1,133 @@ +{{if data.no_cores}} + Error: No connected cores detected! +{{else}} + Fission Core #{{:data.current_core}}
    + {{:helper.link('<<', null, {'change_core' : -1})}}{{:helper.link('>>', null, {'change_core' : 1})}} +
    + {{if data.error}} + Error: Core inoperable! + {{else}} +

    Core Status

    +
    +
    + Neutron Flux: +
    +
    + {{:data.neutron_flux}} +
    +
    +
    +
    + Neutron Energy: +
    +
    + {{:data.neutron_energy}} +
    +
    +
    +
    + Temperature: +
    +
    + {{:data.temperature}} +
    +
    +
    +
    + Control Rod Depth: +
    +
    + {{:helper.link(data.control_rod_depth, null, {'machine': data.core, 'control_rod' : 1})}} +
    +
    +
    +

    Fuel Status

    + {{:helper.link('Eject Fuel Rod', 'eject', {'machine' : data.core, 'eject_rod' : data.current_rod}, data.current_rod ? null : 'disabled')}} + {{:helper.link(data.rod_exposed ? 'EXPOSED' : 'UNEXPOSED', 'eject', {'machine' : data.core, 'expose_rod' : data.current_rod}, data.current_rod ? null : 'disabled')}} +
    +
    + Fuel Rods: +
    +
    + {{for data.rods}} + {{:helper.link(value.name, null, {'machine': data.core, 'rod' : (index + 1)})}}
    + {{empty}} + No fuel rods inserted into the core. + {{/for}} +
    +
    +
    +
    +
    + Fuel Rod Materials: +
    +
    + + + + {{for data.rod_materials}} + + + + + {{/for}} +
    MaterialAmount
    {{:value.name}}{{:value.amount}}
    +
    +
    +
    + {{:helper.link('Toggle Diagnostics', 'eject', {'machine' : data.core, 'toggle_diagnostics' : 1})}} + {{if data.diagnostics}} +
    +
    + Neutron Flux Increase: +
    +
    + {{:data.lastfluxincrease}} +
    +
    +
    +
    + Neutron Flux Decrease: +
    +
    + {{:data.lastfluxdecrease}} +
    +
    +
    +
    + Neutron Flux Delta: +
    +
    + {{:data.netfluxchange}} +
    +
    +
    +
    + Neutron Energy Increase: +
    +
    + {{:data.lastenergyincrease}} +
    +
    +
    +
    + Neutron Energy Decrease: +
    +
    + {{:data.lastenergydecrease}} +
    +
    +
    +
    + Neutron Energy Delta: +
    +
    + {{:data.netenergychange}} +
    +
    + {{/if}} +
    + {{:helper.link('Jump Start', null, {'machine': data.core, 'jump_start' : 1})}} +
    + {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/ftl_computer.tmpl b/nano/templates/ftl_computer.tmpl new file mode 100644 index 000000000000..b0090e828bc9 --- /dev/null +++ b/nano/templates/ftl_computer.tmpl @@ -0,0 +1,210 @@ +
    +

    SYSTEM STATUS

    +
    +
    + Superluminal shunt is: +
    +
    + {{if data.ftlstatus == 2}} + Offline + {{else data.ftlstatus == 1}} + Cooling Down + {{else data.ftlstatus == 3}} + Online + {{else data.ftlstatus == 4}} + Spinning Up + {{/if}} +
    +
    + +

    CAPACITOR STATUS

    + +
    +
    + Charge Precentage: +
    + +
    + {{:helper.displayBar(data.chargepercent, 0, 100)}} +
    +
    + +
    +
    + Maximum Capacitor Charge: +
    + +
    + {{:data.max_charge}} MJ +
    +
    + +
    +
    + Target Charge Level: +
    + +
    + {{:helper.link(data.target_charge, null, { 'adjust_target' : 1})}} MJ +
    +
    + +
    +
    + Estimated Charge Time: +
    + +
    + {{:data.chargetime}} +
    +
    + +
    +
    + Maximum Power Input: +
    +
    + {{:data.max_power}} Kw +
    +
    + +
    +
    + Current Power Input: +
    +
    + {{:helper.link(data.power_input, null, { 'adjust_power' : 1})}} Kw +
    +
    + +
    +
    + Charging Status: +
    + +
    + {{if data.charging == 1}} + Charging + {{else data.charging == 0}} + Not Charging + {{/if}} +
    +
    + +
    + {{:helper.link("Toggle Capacitor Charging", null, { 'toggle_charge' : 1})}} +
    + +

    FUEL SYSTEM STATUS

    + +
    +
    + Remaining Fuel: +
    +
    + {{:data.fuel_joules}} MJ / {{:data.maxfuel}} MJ +
    +
    + +
    +
    + Average Conversion Rate: +
    +
    + {{:data.fuel_conversion}} MJ/cm3 +
    +
    + +

    JUMP SOLUTION ESTIMATES

    + +
    +
    + Jump Solution Status: +
    +
    + {{if data.jump_status == 4}} + !! NO SOLUTION PLOTTED !! + {{else data.jump_status == 3}} + !! JUMP SOLUTION UNSAFE !! + {{else data.jump_status == 2}} + Plotting Jump Solution... + {{else data.jump_status == 1}} + Jump Solution OK. + {{/if}} +
    +
    + +
    +
    + Estimated Fuel Cost: +
    +
    + {{:data.jumpcost}} MJ/cm +
    +
    + +
    +
    + Estimated Power Requirement: +
    +
    + {{:data.powercost}} MJ +
    +
    + +
    +
    + Unplotted Shunt X Coordinates: +
    +
    + {{:helper.link(data.to_plot_x, null, { 'set_shunt_x' : 1})}} +
    +
    + +
    +
    + Unplotted Shunt Y Coordinates: +
    +
    + {{:helper.link(data.to_plot_y, null, { 'set_shunt_y' : 1})}} +
    +
    + +
    +
    + Plotted Shunt X/Y Coordinates: +
    +
    + X {{:data.shunt_x}} +
    +
    + Y {{:data.shunt_y}} +
    +
    + +

    JUMP CONTROLS

    + +
    +
    + {{:helper.link("Cancel Jump Plotting", null, { 'cancel_plot' : 1})}} +
    +
    + +
    +
    + {{:helper.link("Engage Jump Plotting", null, { 'plot_jump' : 1})}} +
    +
    + +
    +
    + {{:helper.link("Engage Shunt Drive", null, { 'start_shunt' : 1 })}} +
    +
    + +
    +
    + {{:helper.link("Disengage Shunt Drive", null, { 'cancel_shunt' : 1 })}} +
    +
    +
    \ No newline at end of file diff --git a/nano/templates/fuel_compressor.tmpl b/nano/templates/fuel_compressor.tmpl new file mode 100644 index 000000000000..e10f9e5b64ba --- /dev/null +++ b/nano/templates/fuel_compressor.tmpl @@ -0,0 +1,47 @@ +
    + Stored Material: +
    +{{for data.stored_material}} +
    + + + + + + {{for data.stored_material}} + + + + + + + {{/for}} +
    MaterialAmountRod MakeupEject Material
    {{:value.name}}{{:value.amount}}{{:helper.link('Adjust', null, {'change_makeup' : value.name})}}{{:helper.link('Eject', null, {'eject_material': value.name})}}
    +
    +{{empty}} + No materials available. +{{/for}} +
    +
    +
    + Rod Makeup: +
    +
    + + + + {{for data.rod_makeup}} + + + + + {{/for}} +
    MaterialAmount
    {{:value.name}}{{:value.amount}}
    +
    +
    + {{:helper.link('Compress Rod', null, {'make_rod' : 1})}} +
    +
    + {{:helper.link('Clear Rod Makeup', null, {'clear_makeup' : 1})}} +
    +
    diff --git a/nano/templates/fusion_core_control.tmpl b/nano/templates/fusion_core_control.tmpl index 558061534ab0..a8a923d7792f 100644 --- a/nano/templates/fusion_core_control.tmpl +++ b/nano/templates/fusion_core_control.tmpl @@ -4,15 +4,15 @@ {{if value.field}}
    - Field generator + Field generator:
    - Online.
    {{:helper.link('Shut down.', null, {'machine': value.ref, 'toggle_active': 1})}} + Online
    {{:helper.link('Shut down', null, {'machine': value.ref, 'toggle_active': 1})}}
    - Power status + Power status:
    {{:value.powerstatus}} @@ -20,7 +20,7 @@
    - Field strength + Field strength:
    {{:value.power}}
    {{:helper.link('-10', null, {'machine': value.ref, 'str': -100})}}{{:helper.link('-1', null, {'machine': value.ref, 'str': -10})}}{{:helper.link('-0.1', null, {'machine': value.ref, 'str': -1})}}{{:helper.link('+0.1', null, {'machine': value.ref, 'str': 1})}}{{:helper.link('+1', null, {'machine': value.ref, 'str': 10})}}{{:helper.link('+10', null, {'machine': value.ref, 'str': 100})}} @@ -28,7 +28,7 @@
    - Size + Size:
    {{:value.size}} @@ -36,7 +36,7 @@
    - Instability + Instability:
    {{:value.instability}} @@ -44,7 +44,7 @@
    - Plasma temperature + Plasma temperature:
    {{:value.temperature}} @@ -52,7 +52,7 @@
    - Reactants + Reactants:
    {{:value.fuel}} @@ -61,10 +61,10 @@ {{else}}
    - Field generator + Field generator:
    - Offline.
    {{:helper.link('Start up.', null, {'machine': value.ref, 'toggle_active': 1})}} + Offline
    {{:helper.link('Start up', null, {'machine': value.ref, 'toggle_active': 1})}}
    {{/if}} diff --git a/nano/templates/fusion_gyrotron_control.tmpl b/nano/templates/fusion_gyrotron_control.tmpl index 0c1ef52e68c9..aabe6a874c4a 100644 --- a/nano/templates/fusion_gyrotron_control.tmpl +++ b/nano/templates/fusion_gyrotron_control.tmpl @@ -7,15 +7,15 @@
    {{if value.active}} - Online.
    {{:helper.link('Shut down.', null, {'machine': value.ref, 'toggle': 1})}} + Online
    {{:helper.link('Shut down', null, {'machine': value.ref, 'toggle': 1})}} {{else}} - Offline.
    {{:helper.link('Start up.', null, {'machine': value.ref, 'toggle': 1})}} + Offline
    {{:helper.link('Start up', null, {'machine': value.ref, 'toggle': 1})}} {{/if}}
    - Fire delay + Fire delay:
    {{:helper.link(value.firedelay, null, {'machine': value.ref, 'modifyrate': 1})}} @@ -23,7 +23,7 @@
    - Power output + Power output:
    {{:helper.link(value.energy, null, {'machine': value.ref, 'modifypower': 1})}} diff --git a/nano/templates/fusion_injector_control.tmpl b/nano/templates/fusion_injector_control.tmpl index 44059ea26d78..c12d5f2c8bf1 100644 --- a/nano/templates/fusion_injector_control.tmpl +++ b/nano/templates/fusion_injector_control.tmpl @@ -11,19 +11,19 @@

    {{:value.id}}

    - Status + Status:
    {{if value.injecting}} - Online.
    {{:helper.link('Shut down.', null, {'toggle_injecting': value.ref})}} + Online
    {{:helper.link('Shut down', null, {'toggle_injecting': value.ref})}} {{else}} - Offline.
    {{:helper.link('Start up.', null, {'toggle_injecting': value.ref})}} + Offline
    {{:helper.link('Start up', null, {'toggle_injecting': value.ref})}} {{/if}}
    - Injection rate + Injection rate:
    {{:helper.link(value.injection_rate, null, {'machine': value.ref, 'injection_rate': 1})}} @@ -31,7 +31,7 @@
    - Fuel material + Fuel material:
    {{:value.fueltype}} @@ -39,7 +39,7 @@
    - Fuel depletion + Fuel depletion:
    {{:value.depletion}} diff --git a/nano/templates/gps.tmpl b/nano/templates/gps.tmpl new file mode 100644 index 000000000000..daa667570565 --- /dev/null +++ b/nano/templates/gps.tmpl @@ -0,0 +1,78 @@ +{{if data.tracking == 0}} + {{:helper.link('Switch On', null, {'toggle_power' : 1})}} +{{else}} + {{:helper.link('Switch Off', null, {'toggle_power' : 1})}} + +
    +
    Current location
    +
    {{:data.my_area_name}} ({{:data.curr_x}}, {{:data.curr_y}}, {{:data.curr_z_name}})
    +
    + +
    + {{if data.hide_signal == 1}} + Tagged as {{:data.gps_tag}}. + {{else}} + Broadcasting as {{:data.gps_tag}}. + {{/if}} +
    + +
    +
    Configuration
    +
    + {{:helper.link('Change Tag', null, { 'tag' : 1 })}} + {{if data.local_mode == 1}} + {{:helper.link('Narrow Band', null, { 'range' : 1 })}} + {{else}} + {{:helper.link('Broad Band', null, { 'range' : 1 })}} + {{/if}} + {{if data.can_hide_signal == 1}} + {{:helper.link('Toggle Signal Visibility', null, { 'hide' : 1})}} + {{/if}} +
    +
    + + {{if data.no_signals == 1}} +
    +
    + No signals detected. +
    +
    + {{else}} + {{for data.gps_list}} + +
    +
    + {{:value.gps_tag}} - {{:value.area_name}} +
    + +
    + {{if value.is_special_gps_marker == 1}} + {{if value.local == 1}} + {{:value.direction}} Dist: {{:value.distance}}m + {{else}} + {{:value.z_name}} + {{/if}} + {{else}} + ({{:value.x}}, {{:value.y}}, {{:value.z_name}}) + {{/if}} +
    + {{if value.local == 1}} + {{:value.distance}}m, {{:value.direction}} + {{else}} + Non-local signal. + {{/if}} +
    + {{if value.being_tracked == 1}} + {{:helper.link('Stop Tracking', null, {'stop_track' : value.gps_ref })}} + {{:helper.link('Color ' + value.coloured_square, null, {'track_color' : value.gps_ref })}} + {{:helper.link('Show/Hide Label', null, {'track_label' : value.gps_ref })}} + {{else}} + {{:helper.link('Start Tracking', null, {'start_track' : value.gps_ref })}} + {{/if}} +
    +
    + + {{/for}} + {{/if}} +
    +{{/if}} \ No newline at end of file diff --git a/nano/templates/helm.tmpl b/nano/templates/helm.tmpl index f9d9a9bb55d3..229f89d2f59d 100644 --- a/nano/templates/helm.tmpl +++ b/nano/templates/helm.tmpl @@ -145,14 +145,18 @@
    - {{for data.locations}} - + + + + + + + {{/for}} -
    NameCoordinatesActions +
    NameCoordinatesActions
    {{:value.name}} - {{:value.x}} : {{:value.y}} - {{:helper.link('Plot course', 'arrowreturnthick-1-e', { 'x' : value.x, 'y' : value.y }, null, null)}} - {{:helper.link('Remove', 'close', { 'remove' : value.reference }, null, null)}} +
    {{:value.name}}{{:value.x}} : {{:value.y}}{{:helper.link('Plot course', 'arrowreturnthick-1-e', { 'x' : value.x, 'y' : value.y }, null, null)}}{{:helper.link(value.tracking ? 'Disable tracking' : 'Enable tracking', null, { 'toggle_wp_tracking' : value.reference }, null, null)}}{{:helper.link('Set color', null, { 'set_wp_color' : value.reference }, null, null)}}{{:helper.link('Remove', 'close', { 'remove' : value.reference }, null, null)}}
    +
    diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl index d5485f2304c3..e8d016d873d7 100644 --- a/nano/templates/identification_computer.tmpl +++ b/nano/templates/identification_computer.tmpl @@ -36,49 +36,121 @@
    - Registered Name: + Terminations:
    - {{:helper.link(data.id_owner, 'pencil', {'action' : 'edit', 'name' : 1})}} + {{:helper.link('Terminate ' + data.id_owner, 'gear', {'action' : 'terminate'}, data.id_rank == "Terminated" ? 'disabled' : null, data.id_rank == "Terminated" ? 'disabled' : 'linkDanger')}}
    - Account Number: + Registered Name:
    - {{:helper.link(data.id_account_number, 'pencil', {'action' : 'edit', 'account' : 1})}} + {{:helper.link(data.id_owner, 'pencil', {'action' : 'edit', 'name' : 1})}}
    - Email login: + Account Number:
    - {{:helper.link(data.id_email_login, 'pencil', {'action' : 'edit', 'elogin' : 1})}} + {{:helper.link(data.id_account_number, 'pencil', {'action' : 'edit', 'account' : 1})}}
    - Email password: + Network account login:
    - {{:helper.link(data.id_email_password, 'pencil', {'action' : 'edit', 'epswd' : 1})}} + {{:helper.link(data.network_account_login, 'pencil', {'action' : 'edit', 'alogin' : 1})}}
    - +
    - Terminations: + Network account password:
    - {{:helper.link('Terminate ' + data.id_owner, 'gear', {'action' : 'terminate'}, data.id_rank == "Terminated" ? 'disabled' : null, data.id_rank == "Terminated" ? 'disabled' : 'linkDanger')}} + {{:helper.link(data.network_account_password, 'pencil', {'action' : 'edit', 'apswd' : 1})}}
    +
    +
    + Sex: +
    +
    + {{:helper.link(data.gender , 'pencil', {'action' : 'edit', 'gender' : 1})}} +
    +
    + +
    +
    + Age: +
    +
    + {{:helper.link(data.age , 'pencil', {'action' : 'edit', 'age' : 1})}} +
    +
    + +
    +
    + DNA hash: +
    +
    + {{:helper.link(data.dna_hash , 'pencil', {'action' : 'edit', 'dna_hash' : 1})}} +
    +
    + +
    +
    + Fingerprint hash: +
    +
    + {{:helper.link(data.fingerprint_hash , 'pencil', {'action' : 'edit', 'fingerprint_hash' : 1})}} +
    +
    + +
    +
    + Blood type: +
    +
    + {{:helper.link(data.blood_type , 'pencil', {'action' : 'edit', 'blood_type' : 1})}} +
    +
    + +
    +
    + Edit front photo +
    +
    + {{:helper.link('Use photo in your hands', 'pencil', {'action': 'edit', 'front_photo' : 1})}} +
    +
    + +
    +
    + Edit side photo +
    +
    + {{:helper.link('Use photo in your hands', 'pencil', {'action' : 'edit', 'side_photo' : 1})}} +
    +
    + +
    +
    + Load data from crew records +
    +
    + {{:helper.link('', 'pencil', {'action' : 'edit', 'load_data' : 1})}} +
    +
    +

    Assignment

    diff --git a/nano/templates/internet_repeater.tmpl b/nano/templates/internet_repeater.tmpl new file mode 100644 index 000000000000..90947c21c62b --- /dev/null +++ b/nano/templates/internet_repeater.tmpl @@ -0,0 +1,20 @@ +
    +
    + Power: +
    +
    + {{:helper.link(data.powered ? 'On' : 'Off', 'power', {'toggle' : 1 }, null)}} +
    +
    +
    +
    +

    Connected PLEXUS Uplinks:

    + + +
    Sector PositionPermitted Networks + {{for data.connections}} +
    {{:value.position}} + {{:value.permitted}} + {{/for}} +
    +
    diff --git a/nano/templates/internet_uplink.tmpl b/nano/templates/internet_uplink.tmpl new file mode 100644 index 000000000000..6a2412f317af --- /dev/null +++ b/nano/templates/internet_uplink.tmpl @@ -0,0 +1,54 @@ +
    +
    + Power: +
    +
    + {{:helper.link(data.active ? 'On' : 'Off', 'power', { 'toggle_power' : 1 }, null)}} +
    +
    +
    +
    + Power Draw: +
    +
    + {{:data.power_draw}} +
    +
    +
    +
    + Range: +
    +
    + {{:helper.link(data.overmap_range, null, { 'modify_range' : 1 }, null)}} +
    +
    +
    +
    + Temperature: +
    +
    + {{:data.temperature}} / {{:data.max_temperature}} K +
    +
    +
    +
    +
    + Restrict Networks: +
    +
    + {{:helper.link(data.restrict_networks ? 'On' : 'Off', null, { 'restrict_networks' : 1 }, null)}} +
    +
    +{{if data.restrict_networks}} +
    + Permitted Networks +
    +
    +
    + {{for data.permitted}} + {{:value}}
    + {{/for}} +
    + {{:helper.link('Add/Remove Network', '', {'toggle_permitted_network' : 1})}} +
    +{{/if}} \ No newline at end of file diff --git a/nano/templates/keypad_lock.tmpl b/nano/templates/keypad_lock.tmpl index b621d61a514a..3631c7bf5ab3 100644 --- a/nano/templates/keypad_lock.tmpl +++ b/nano/templates/keypad_lock.tmpl @@ -1,106 +1,113 @@ -
    -
    - Lock Status: -
    -
    + + + +{{function show_locked_icon() { }} + {{if data.locked}} - LOCKED + {{else}} - UNLOCKED + {{/if}} -
    + +{{ } }} + + +{{function make_number_button(key, is_disabled, btn_id, btn_class){ }} + {{:helper.link(key, null, {'key' : key}, is_disabled ? 'disabled' : null, btn_class? btn_class : 'linkBtnOSDark', btn_id)}} +{{ } }} + + +
    + {{if data.error}} +
    {{:data.error}}
    + {{/if}} + {{if data.status}} +
    {{:data.status}}
    + {{/if}}
    -{{if data.error}} -
    -
    - {{:data.error}} -
    -
    -{{/if}} -
    -
    - Keypad -
    + +
    +
    + {{show_locked_icon();}} Keypad + +
    {{:data.input_code}}
    -
    - - - - - - - - - - - - - - - - - - - - - -
    -
    - {{:helper.link('1' , null, {'key' : '1'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('2' , null, {'key' : '2'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('3' , null, {'key' : '3'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('4' , null, {'key' : '4'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('5' , null, {'key' : '5'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('6' , null, {'key' : '6'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('7' , null, {'key' : '7'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('8' , null, {'key' : '8'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('9' , null, {'key' : '9'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('C' , null, {'key' : 'C'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('0' , null, {'key' : '0'}, data.disabled ? 'disabled' : null, null)}} -
    -
    -
    - {{:helper.link('E' , null, {'key' : 'E'}, data.disabled || !data.locked ? 'disabled' : null, null)}} -
    -
    -
    + +
    + + + + + + + + + + + + + + + + + + + + + + +
    {{make_number_button('1', data.disabled || !data.locked);}}{{make_number_button('2', data.disabled || !data.locked);}}{{make_number_button('3', data.disabled || !data.locked);}}
    {{make_number_button('4', data.disabled || !data.locked);}}{{make_number_button('5', data.disabled || !data.locked);}}{{make_number_button('6', data.disabled || !data.locked);}}
    {{make_number_button('7', data.disabled || !data.locked);}}{{make_number_button('8', data.disabled || !data.locked);}}{{make_number_button('9', data.disabled || !data.locked);}}
    {{make_number_button('C', data.disabled, null, 'linkBtnOSRed');}}{{make_number_button('0', data.disabled || !data.locked);}}{{make_number_button('E', data.disabled || !data.locked);}}
    -{{if data.status}} -
    -
    - {{:data.status}} -
    -
    -{{/if}} \ No newline at end of file + +
    \ No newline at end of file diff --git a/nano/templates/kinetic_harvester.tmpl b/nano/templates/kinetic_harvester.tmpl index 6476b5d0eb27..aceedfaefa20 100644 --- a/nano/templates/kinetic_harvester.tmpl +++ b/nano/templates/kinetic_harvester.tmpl @@ -1,26 +1,26 @@

    Fusion plant: {{:data.id}}

    {{if data.status}} - {{:helper.link('Online.', null, {'toggle_power': 1})}} + {{:helper.link('Online', null, {'toggle_power': 1})}} {{else}} - {{:helper.link('Offline.', null, {'toggle_power': 1})}} + {{:helper.link('Offline', null, {'toggle_power': 1})}} {{/if}} {{for data.materials}}
    - {{:value.material}} x {{:value.rawamount}} ({{:value.amount}} sheet(s)) + {{:value.name}}
    {{if value.harvest}} - {{:helper.link('Collecting.', null, {'toggle_harvest': value.material})}} + {{:helper.link('Collecting', null, {'toggle_harvest': value.mat_ref})}} {{else}} - {{:helper.link('Not collecting.', null, {'toggle_harvest': value.material})}} + {{:helper.link('Not collecting', null, {'toggle_harvest': value.mat_ref})}} {{/if}} {{if value.amount > 0}} - {{:helper.link('Remove sheets.', null, {'remove_mat': value.material})}} + {{:helper.link('Remove ' + value.amount, null, {'remove_mat': value.mat_ref})}} {{/if}}
    {{empty}} - No materials available. +
    No materials available. {{/for}} diff --git a/nano/templates/laptop_configuration.tmpl b/nano/templates/laptop_configuration.tmpl index 0a9996697d00..d9eeb4eb7b45 100644 --- a/nano/templates/laptop_configuration.tmpl +++ b/nano/templates/laptop_configuration.tmpl @@ -1,20 +1,20 @@ Welcome to computer configuration utility. Please consult your system administrator if you have any questions about your device.

    Power Supply

    - Battery Status: + Battery Status:
    {{if data.battery_exists}}
    Active
    - Battery Rating: + Battery Rating:
    {{:data.battery_rating}}
    - Battery Charge: + Battery Charge:
    {{:helper.displayBar(data.battery_percent, 0, 100, (data.battery_percent <= 25) ? 'bad' : (data.battery_percent <= 50) ? 'average' : 'good')}} @@ -26,7 +26,7 @@
    {{/if}}
    - Power Usage: + Power Usage:
    {{:data.power_usage}}W @@ -68,7 +68,7 @@ Not Available
    {{/if}} -

    File System

    +

    File System

    Used Capacity:
    @@ -81,13 +81,13 @@

    {{:value.name}}

    {{:value.desc}}
    - State: + State:
    {{:value.enabled ? "Enabled" : "Disabled"}} -
    +
    - Power Usage: + Power Usage:
    {{:value.powerusage}}W @@ -100,25 +100,25 @@
    {{if !value.critical}}
    - Toggle Component: + Toggle Component:
    {{:helper.link("ON", null, {'PC_enable_component' : value.ref}, value.enabled ? 'disabled' : null)}} {{:helper.link("OFF", null, {'PC_disable_component' : value.ref}, value.enabled ? null : 'disabled')}} -
    +
    {{/if}}

    {{/for}}

    Auto-Updater

    Automatically downloads and installs critical OS upgrades if network is reachable. Disabling voids warranty.
    - State: + State:
    {{:data.receives_updates ? "Enabled" : "Disabled"}} -
    +
    - Toggle Updates: + Toggle Updates:
    {{:helper.link("ON", null, {'PC_enable_update' : 1}, data.receives_updates ? 'disabled' : null)}} @@ -126,4 +126,4 @@




    -NTOS v2.0.4b \ No newline at end of file +{{:data.os_full_name}} \ No newline at end of file diff --git a/nano/templates/law_manager.tmpl b/nano/templates/law_manager.tmpl index 1e0012bae7c1..6ba59e041797 100644 --- a/nano/templates/law_manager.tmpl +++ b/nano/templates/law_manager.tmpl @@ -1,253 +1,253 @@ - - -{{if data.isSlaved}} -
    Law synced to {{:data.isSlaved}}.
    -{{/if}} - -
    -
    - {{:helper.link('Law Management', null, {'set_view' : 0}, data.view == 0 ? 'selected' : null)}} - {{:helper.link('Law Sets', null, {'set_view' : 1}, data.view == 1 ? 'selected' : null)}} -
    -
    - -{{if data.view == 0}} - {{if data.has_ion_laws}} - - - {{if data.isMalf}} - - - {{/if}} - - -
    - {{:data.ion_law_nr}} Laws: -
    - {{for data.ion_laws}} - - - - - {{if data.isMalf}} - - - {{/if}} - - {{/for}} -
    IndexLawStateEditDelete
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state == 0 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref})}}{{:helper.link('Delete', null, {'delete_law': value.ref}, null, 'redButton')}}
    - {{/if}} - - {{if data.has_inherent_laws || data.has_zeroth_laws}} - - - {{if data.isMalf}} - - - {{/if}} - - -
    - Inherent Laws: -
    - - {{for data.zeroth_laws}} - - - - - {{if data.isMalf}} - - - {{/if}} - - {{/for}} - - {{for data.inherent_laws}} - - - - - {{if data.isMalf}} - - - {{/if}} - - {{/for}} -
    IndexLawStateEditDelete
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state != 1 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref}, data.isAdmin ? null : 'disabled')}}{{:helper.link('Delete', null, {'delete_law': value.ref}, data.isAdmin ? null : 'disabled', data.isAdmin ? 'redButton' : null)}}
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state == 0 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref})}}{{:helper.link('Delete', null, {'delete_law': value.ref}, null, 'redButton')}}
    - {{/if}} - - {{if data.has_supplied_laws}} - - - {{if data.isMalf}} - - - {{/if}} - - -
    - Supplied Laws: -
    - {{for data.supplied_laws}} - - - - - {{if data.isMalf}} - - - {{/if}} - - {{/for}} -
    IndexLawStateEditDelete
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state == 0 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref})}}{{:helper.link('Delete', null, {'delete_law': value.ref}, null, 'redButton')}}
    - {{/if}} - -
    -
    - Statement Channel: -
    -
    - {{for data.channels}} - {{:helper.link(value.channel, null, {'law_channel' : value.channel}, value.channel == data.channel ? 'selected' : null)}} - {{/for}} -
    -
    - -
    -
    - State Laws: -
    -
    - {{:helper.link('State Laws', null, {'state_laws' : 1})}} -
    -
    - - {{if data.isMalf}} -
    -
    - Add Laws: -
    -
    - - - {{if data.isAdmin && !data.has_zeroth_laws}} - - {{/if}} - - - -
    TypeLawIndexEditAdd
    Zero{{:data.zeroth_law}}N/A{{:helper.link('Edit', null, {'change_zeroth_law' : 1})}}{{:helper.link('Add', null, {'add_zeroth_law' : 1})}}
    Ion{{:data.ion_law}}N/A{{:helper.link('Edit', null, {'change_ion_law' : 1})}}{{:helper.link('Add', null, {'add_ion_law' : 1})}}
    Inherent{{:data.inherent_law}}N/A{{:helper.link('Edit', null, {'change_inherent_law' : 1})}}{{:helper.link('Add', null, {'add_inherent_law' : 1})}}
    Supplied{{:data.supplied_law}}{{:helper.link(data.supplied_law_position, null, {'change_supplied_law_position' : 1})}}{{:helper.link('Edit', null, {'change_supplied_law' : 1})}}{{:helper.link('Add', null, {'add_supplied_law' : 1})}}
    -
    -
    - {{/if}} - - {{if data.isAI}} -
    -
    - Law Notification: -
    -
    - {{:helper.link('Notify', null, {'notify_laws' : 1})}} -
    -
    - {{/if}} -{{else data.view == 1}} -
    Remember: Stating laws other than those currently loaded may be grounds for decommissioning.
    - - {{for data.law_sets}} -
    -
    -

    {{:value.name}}

    {{:value.header}} -
    - - {{if value.laws.has_ion_laws}} - - - {{for value.laws.ion_laws :lawValue:lawindex}} - - - - - {{/for}} -
    IndexLaw
    {{:lawValue.index}}.{{:lawValue.law}}
    - {{/if}} - - {{if value.laws.has_zeroth_laws || value.laws.has_inherent_laws}} - - - {{for value.laws.zeroth_laws :lawValue:lawindex}} - - - - - {{/for}} - {{for value.laws.inherent_laws :lawValue:lawindex}} - - - - - {{/for}} -
    IndexLaw
    {{:lawValue.index}}.{{:lawValue.law}}
    {{:lawValue.index}}.{{:lawValue.law}}
    - {{/if}} - - {{if value.laws.has_supplied_laws}} - - - {{for value.laws.supplied_laws :lawValue:lawindex}} - - - - - {{/for}} -
    IndexLaw
    {{:lawValue.index}}.{{:lawValue.law}}
    - {{/if}} - -
    -
    - {{:helper.link('Load Laws', null, {'transfer_laws' : value.ref}, data.isMalf ? null : 'disabled')}}{{:helper.link('State Laws', null, {'state_law_set' : value.ref})}} -
    -
    - {{/for}} + + +{{if data.isSlaved}} +
    Law synced to {{:data.isSlaved}}.
    +{{/if}} + +
    +
    + {{:helper.link('Law Management', null, {'set_view' : 0}, data.view == 0 ? 'selected' : null)}} + {{:helper.link('Law Sets', null, {'set_view' : 1}, data.view == 1 ? 'selected' : null)}} +
    +
    + +{{if data.view == 0}} + {{if data.has_ion_laws}} + + + {{if data.isMalf}} + + + {{/if}} + + +
    + {{:data.ion_law_nr}} Laws: +
    + {{for data.ion_laws}} + + + + + {{if data.isMalf}} + + + {{/if}} + + {{/for}} +
    IndexLawStateEditDelete
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state == 0 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref})}}{{:helper.link('Delete', null, {'delete_law': value.ref}, null, 'redButton')}}
    + {{/if}} + + {{if data.has_inherent_laws || data.has_zeroth_laws}} + + + {{if data.isMalf}} + + + {{/if}} + + +
    + Inherent Laws: +
    + + {{for data.zeroth_laws}} + + + + + {{if data.isMalf}} + + + {{/if}} + + {{/for}} + + {{for data.inherent_laws}} + + + + + {{if data.isMalf}} + + + {{/if}} + + {{/for}} +
    IndexLawStateEditDelete
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state != 1 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref}, data.isAdmin ? null : 'disabled')}}{{:helper.link('Delete', null, {'delete_law': value.ref}, data.isAdmin ? null : 'disabled', data.isAdmin ? 'redButton' : null)}}
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state == 0 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref})}}{{:helper.link('Delete', null, {'delete_law': value.ref}, null, 'redButton')}}
    + {{/if}} + + {{if data.has_supplied_laws}} + + + {{if data.isMalf}} + + + {{/if}} + + +
    + Supplied Laws: +
    + {{for data.supplied_laws}} + + + + + {{if data.isMalf}} + + + {{/if}} + + {{/for}} +
    IndexLawStateEditDelete
    {{:value.index}}.{{:value.law}}{{:helper.link('Yes', null, {'ref': value.ref, 'state_law' : 1}, value.state == 1 ? 'selected' : null)}}{{:helper.link('No', null, {'ref': value.ref, 'state_law' : 0}, value.state == 0 ? 'selected' : null)}}{{:helper.link('Edit', null, {'edit_law': value.ref})}}{{:helper.link('Delete', null, {'delete_law': value.ref}, null, 'redButton')}}
    + {{/if}} + +
    +
    + Statement Channel: +
    +
    + {{for data.channels}} + {{:helper.link(value.channel, null, {'law_channel' : value.channel}, value.channel == data.channel ? 'selected' : null)}} + {{/for}} +
    +
    + +
    +
    + State Laws: +
    +
    + {{:helper.link('State Laws', null, {'state_laws' : 1})}} +
    +
    + + {{if data.isMalf}} +
    +
    + Add Laws: +
    +
    + + + {{if data.isAdmin && !data.has_zeroth_laws}} + + {{/if}} + + + +
    TypeLawIndexEditAdd
    Zero{{:data.zeroth_law}}N/A{{:helper.link('Edit', null, {'change_zeroth_law' : 1})}}{{:helper.link('Add', null, {'add_zeroth_law' : 1})}}
    Ion{{:data.ion_law}}N/A{{:helper.link('Edit', null, {'change_ion_law' : 1})}}{{:helper.link('Add', null, {'add_ion_law' : 1})}}
    Inherent{{:data.inherent_law}}N/A{{:helper.link('Edit', null, {'change_inherent_law' : 1})}}{{:helper.link('Add', null, {'add_inherent_law' : 1})}}
    Supplied{{:data.supplied_law}}{{:helper.link(data.supplied_law_position, null, {'change_supplied_law_position' : 1})}}{{:helper.link('Edit', null, {'change_supplied_law' : 1})}}{{:helper.link('Add', null, {'add_supplied_law' : 1})}}
    +
    +
    + {{/if}} + + {{if data.isAI}} +
    +
    + Law Notification: +
    +
    + {{:helper.link('Notify', null, {'notify_laws' : 1})}} +
    +
    + {{/if}} +{{else data.view == 1}} +
    Remember: Stating laws other than those currently loaded may be grounds for decommissioning.
    + + {{for data.law_sets}} +
    +
    +

    {{:value.name}}

    {{:value.header}} +
    + + {{if value.laws.has_ion_laws}} + + + {{for value.laws.ion_laws :lawValue:lawindex}} + + + + + {{/for}} +
    IndexLaw
    {{:lawValue.index}}.{{:lawValue.law}}
    + {{/if}} + + {{if value.laws.has_zeroth_laws || value.laws.has_inherent_laws}} + + + {{for value.laws.zeroth_laws :lawValue:lawindex}} + + + + + {{/for}} + {{for value.laws.inherent_laws :lawValue:lawindex}} + + + + + {{/for}} +
    IndexLaw
    {{:lawValue.index}}.{{:lawValue.law}}
    {{:lawValue.index}}.{{:lawValue.law}}
    + {{/if}} + + {{if value.laws.has_supplied_laws}} + + + {{for value.laws.supplied_laws :lawValue:lawindex}} + + + + + {{/for}} +
    IndexLaw
    {{:lawValue.index}}.{{:lawValue.law}}
    + {{/if}} + +
    +
    + {{:helper.link('Load Laws', null, {'transfer_laws' : value.ref}, data.isMalf ? null : 'disabled')}}{{:helper.link('State Laws', null, {'state_law_set' : value.ref})}} +
    +
    + {{/for}} {{/if}} \ No newline at end of file diff --git a/nano/templates/layout_default.tmpl b/nano/templates/layout_default.tmpl index 8dae1468bfb1..a80f025bce3e 100644 --- a/nano/templates/layout_default.tmpl +++ b/nano/templates/layout_default.tmpl @@ -8,7 +8,7 @@
    Z Level:  {{for config.mapZLevels :zValue:zIndex}} - {{:helper.link(zValue, 'close', {'mapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} + {{:helper.link(zValue, 'close', {'switchMapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} {{/for}}
    diff --git a/nano/templates/layout_default_header.tmpl b/nano/templates/layout_default_header.tmpl index 0608c0938b4f..e1683ca5ffac 100644 --- a/nano/templates/layout_default_header.tmpl +++ b/nano/templates/layout_default_header.tmpl @@ -17,20 +17,27 @@ {{if data.PC_stationtime}} {{:data.PC_stationtime}} {{/if}} + {{if data.PC_loggedin}} + {{:helper.link('Account:' + data.PC_loggedin, null, {'PC_login' : 1})}}{{:helper.link('X', null, {'PC_logout' : 1})}} + {{else}} + {{:helper.link('Not logged in', null, {'PC_login' : 1})}} + {{/if}} {{for data.PC_programheaders}} {{/for}}
    -
    - -
    {{:helper.link('Shutdown', null, {'PC_shutdown' : 1})}} - {{if data.PC_showexitprogram}} - {{:helper.link('Exit Program', null, {'PC_exit' : 1})}} - {{:helper.link('Minimize Program', null, {'PC_minimize' : 1})}} - {{/if}} -
    -
    + {{if data.PC_showshutdown}} +
    + +
    {{:helper.link('Shutdown', null, {'PC_shutdown' : 1})}} + {{if data.PC_showexitprogram}} + {{:helper.link('Exit Program', null, {'PC_exit' : 1})}} + {{:helper.link('Minimize Program', null, {'PC_minimize' : 1})}} + {{/if}} +
    +
    + {{/if}}
    {{/if}} \ No newline at end of file diff --git a/nano/templates/material_processing_compressor.tmpl b/nano/templates/material_processing_compressor.tmpl new file mode 100644 index 000000000000..49cbf881dcab --- /dev/null +++ b/nano/templates/material_processing_compressor.tmpl @@ -0,0 +1,47 @@ +
    +
    +
    + Power +
    +
    + {{if data.on}} + {{:helper.link("On", null, { 'toggle_power' : 1 }, null, 'selected')}} + {{else}} + {{:helper.link("Off", null, { 'toggle_power' : 1 }, null, null)}} + {{/if}} +
    +
    + Input +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_input' : 0 }, null, data.input_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_input' : 1 }, null, data.input_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_input' : 2 }, null, data.input_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_input' : 4 }, null, data.input_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_input' : 8 }, null, data.input_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.input_label}} + {{/if}} +
    +
    + Output +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_output' : 0 }, null, data.output_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_output' : 1 }, null, data.output_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_output' : 2 }, null, data.output_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_output' : 4 }, null, data.output_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_output' : 8 }, null, data.output_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.output_label}} + {{/if}} +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Hide", null, { 'toggle_configuration' : 1 }, null, null)}} + {{else}} + {{:helper.link("Configure", null, { 'toggle_configuration' : 1 }, null, null)}} + {{/if}} +
    diff --git a/nano/templates/material_processing_extractor.tmpl b/nano/templates/material_processing_extractor.tmpl new file mode 100644 index 000000000000..1cec6807f7f7 --- /dev/null +++ b/nano/templates/material_processing_extractor.tmpl @@ -0,0 +1,99 @@ +
    +
    +
    + Power +
    +
    + {{if data.on}} + {{:helper.link("On", null, { 'toggle_power' : 1 }, null, 'selected')}} + {{else}} + {{:helper.link("Off", null, { 'toggle_power' : 1 }, null, null)}} + {{/if}} +
    +
    + Input +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_input' : 0 }, null, data.input_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_input' : 1 }, null, data.input_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_input' : 2 }, null, data.input_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_input' : 4 }, null, data.input_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_input' : 8 }, null, data.input_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.input_label}} + {{/if}} +
    +
    + Output +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_output' : 0 }, null, data.output_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_output' : 1 }, null, data.output_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_output' : 2 }, null, data.output_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_output' : 4 }, null, data.output_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_output' : 8 }, null, data.output_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.output_label}} + {{/if}} +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Hide", null, { 'toggle_configuration' : 1 }, null, null)}} + {{else}} + {{:helper.link("Configure", null, { 'toggle_configuration' : 1 }, null, null)}} + {{/if}} +
    + +
    + {{if data.full}} + Internal liquid tank is full, please empty to resume processing + {{/if}} + + {{for data.reagents}} +
    +
    + {{:value.label}} +
    +
    + {{if value.liquid}} + {{:helper.link("Dispense", null, { 'dispense' : value.index}, null, null)}} + {{else}} + {{:helper.link("Process", null, { 'dispense' : value.index}, null, null)}} + {{/if}} +
    +
    + {{empty}} + No materials loaded + {{/for}} +
    +
    +
    + Dispensing: +
    +
    + {{:helper.link(data.dispense_amount + "U", null, { 'change_amount' : 1}, null, null)}} +
    +
    +
    +
    + Output Container: +
    +
    + {{if data.container}} + {{:helper.link(data.container, null, { 'eject' : 1}, null, null)}} + {{else}} + No container loaded + {{/if}} +
    +
    +
    +
    + Gas pressure: +
    +
    + {{:data.gas_pressure}} kPa +
    +
    +
    diff --git a/nano/templates/material_processing_smeltery.tmpl b/nano/templates/material_processing_smeltery.tmpl new file mode 100644 index 000000000000..005b4b4647d4 --- /dev/null +++ b/nano/templates/material_processing_smeltery.tmpl @@ -0,0 +1,75 @@ +
    +
    +
    + Power +
    +
    + {{if data.on}} + {{:helper.link("On", null, { 'toggle_power' : 1 }, null, 'selected')}} + {{else}} + {{:helper.link("Off", null, { 'toggle_power' : 1 }, null, null)}} + {{/if}} +
    +
    + Input +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_input' : 0 }, null, data.input_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_input' : 1 }, null, data.input_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_input' : 2 }, null, data.input_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_input' : 4 }, null, data.input_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_input' : 8 }, null, data.input_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.input_label}} + {{/if}} +
    +
    + Output +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_output' : 0 }, null, data.output_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_output' : 1 }, null, data.output_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_output' : 2 }, null, data.output_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_output' : 4 }, null, data.output_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_output' : 8 }, null, data.output_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.output_label}} + {{/if}} +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Hide", null, { 'toggle_configuration' : 1 }, null, null)}} + {{else}} + {{:helper.link("Configure", null, { 'toggle_configuration' : 1 }, null, null)}} + {{/if}} +
    + +
    + {{if data.is_alloying}} + {{:helper.link("Prevent alloying", null, { 'toggle_alloying' : 1}, null, null)}} + {{else}} + {{:helper.link("Allow alloying", null, { 'toggle_alloying' : 1}, null, null)}} + {{/if}} + {{if data.show_all_mats}} + {{:helper.link("Hide uncommon materials", null, { 'toggle_show_mats' : 1}, null, null)}} + {{else}} + {{:helper.link("Show uncommon materials", null, { 'toggle_show_mats' : 1}, null, null)}} + {{/if}} + + {{for data.materials}} +
    +
    + {{:value.label}} +
    +
    + {{if value.casting == 1}} + {{:helper.link("Stop casting", null, { 'toggle_casting' : value.key}, null, null)}} + {{else}} + {{:helper.link("Begin casting", null, { 'toggle_casting' : value.key}, null, null)}} + {{/if}} +
    +
    + {{/for}} +
    diff --git a/nano/templates/material_processing_stacker.tmpl b/nano/templates/material_processing_stacker.tmpl new file mode 100644 index 000000000000..29337b5aa0ac --- /dev/null +++ b/nano/templates/material_processing_stacker.tmpl @@ -0,0 +1,72 @@ +
    +
    +
    + Power +
    +
    + {{if data.on}} + {{:helper.link("On", null, { 'toggle_power' : 1 }, null, 'selected')}} + {{else}} + {{:helper.link("Off", null, { 'toggle_power' : 1 }, null, null)}} + {{/if}} +
    +
    + Input +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_input' : 0 }, null, data.input_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_input' : 1 }, null, data.input_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_input' : 2 }, null, data.input_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_input' : 4 }, null, data.input_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_input' : 8 }, null, data.input_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.input_label}} + {{/if}} +
    +
    + Output +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_output' : 0 }, null, data.output_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_output' : 1 }, null, data.output_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_output' : 2 }, null, data.output_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_output' : 4 }, null, data.output_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_output' : 8 }, null, data.output_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.output_label}} + {{/if}} +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Hide", null, { 'toggle_configuration' : 1 }, null, null)}} + {{else}} + {{:helper.link("Configure", null, { 'toggle_configuration' : 1 }, null, null)}} + {{/if}} +
    + +
    +
    +
    + Releasing at {{:data.stack_max}} ingot(s) +
    +
    + {{:helper.link("1", null, { 'change_stack_max' : 1 }, data.stack_max == 1 ? 'selected' : null, null)}} + {{:helper.link("5", null, { 'change_stack_max' : 5 }, data.stack_max == 5 ? 'selected' : null, null)}} + {{:helper.link("10", null, { 'change_stack_max' : 10 }, data.stack_max == 10 ? 'selected' : null, null)}} + {{:helper.link("20", null, { 'change_stack_max' : 20 }, data.stack_max == 20 ? 'selected' : null, null)}} + {{:helper.link("30", null, { 'change_stack_max' : 30 }, data.stack_max == 30 ? 'selected' : null, null)}} + {{:helper.link("40", null, { 'change_stack_max' : 40 }, data.stack_max == 40 ? 'selected' : null, null)}} + {{:helper.link("50", null, { 'change_stack_max' : 50 }, data.stack_max == 50 ? 'selected' : null, null)}} +
    +
    + Current stacks +
    +
    + {{for data.stacks}} + {{:helper.link(value.name, null, { 'release_sheets' : value.key }, null, null)}} + {{/for}} +
    +
    +
    diff --git a/nano/templates/material_processing_unloader.tmpl b/nano/templates/material_processing_unloader.tmpl new file mode 100644 index 000000000000..edc54eaf1538 --- /dev/null +++ b/nano/templates/material_processing_unloader.tmpl @@ -0,0 +1,47 @@ +
    +
    +
    + Power +
    +
    + {{if data.on}} + {{:helper.link("On", null, { 'toggle_power' : 1 }, null, 'selected')}} + {{else}} + {{:helper.link("Off", null, { 'toggle_power' : 1 }, null, null)}} + {{/if}} +
    +
    + Input +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_input' : 0 }, null, data.input_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_input' : 1 }, null, data.input_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_input' : 2 }, null, data.input_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_input' : 4 }, null, data.input_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_input' : 8 }, null, data.input_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.input_label}} + {{/if}} +
    +
    + Output +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Disable", null, { 'set_output' : 0 }, null, data.output_value == 0 ? 'selected' : null)}} + {{:helper.link("North", null, { 'set_output' : 1 }, null, data.output_value == 1 ? 'selected' : null)}} + {{:helper.link("South", null, { 'set_output' : 2 }, null, data.output_value == 2 ? 'selected' : null)}} + {{:helper.link("East", null, { 'set_output' : 4 }, null, data.output_value == 4 ? 'selected' : null)}} + {{:helper.link("West", null, { 'set_output' : 8 }, null, data.output_value == 8 ? 'selected' : null)}} + {{else}} + {{:data.output_label}} + {{/if}} +
    +
    + {{if data.can_configure == 1}} + {{:helper.link("Hide", null, { 'toggle_configuration' : 1 }, null, null)}} + {{else}} + {{:helper.link("Configure", null, { 'toggle_configuration' : 1 }, null, null)}} + {{/if}} +
    \ No newline at end of file diff --git a/nano/templates/merchant.tmpl b/nano/templates/merchant.tmpl index 2c245b88461b..1c48f7e71bc0 100644 --- a/nano/templates/merchant.tmpl +++ b/nano/templates/merchant.tmpl @@ -48,17 +48,19 @@

    Main Menu

    - - - + {{/for}} + + - - + + +
    {{:helper.link('Open Communications', null, {'PRG_merchant_list' : 1})}}
    {{:helper.link('Test Fire Transporter', null, {'PRG_test_fire': 1 })}}
    {{:helper.link('Connect Pad', null, {'PRG_connect_pad' : 1})}} + {{for data.hubs}} +
    {{:helper.link('Open communications with ' + value.name, null, {'PRG_merchant_list' : value.ref})}}
    {{:helper.link('Test fire transporter', null, {'PRG_test_fire': 1 })}}
    {{:helper.link('Connect pad', null, {'PRG_connect_pad' : 1})}} {{if data.pad}} Connected {{else}} DISCONNECTED {{/if}} -
    {{:helper.link('Deposit Money', null, {'PRG_transfer_to_bank' : 1})}}
    {{:helper.link('Retrieve Money', null, {'PRG_get_money' : 1})}}
    {{:helper.link('Deposit money', null, {'PRG_transfer_to_bank' : 1})}}
    {{:helper.link('Retrieve money', null, {'PRG_get_money' : 1})}}
    {{/if}} diff --git a/nano/templates/microwave.tmpl b/nano/templates/microwave.tmpl new file mode 100644 index 000000000000..e313a47894b5 --- /dev/null +++ b/nano/templates/microwave.tmpl @@ -0,0 +1,55 @@ +
    + {{if data.broken}} +
    +

    The microwave is broken! You'll need to repair it before using it.

    +
    + {{else data.dirty}} +
    +

    The microwave is dirty! You'll need to clean it before using it.

    +
    + {{else data.on}} +
    + {{if data.past_half_time}} + {{if jQuery.isEmptyObject(data.cooking_items) && jQuery.isEmptyObject(data.cooking_reagents)}} +

    There's nothing inside. Microwave's working, though!

    + {{else data.failed}} +

    Something doesn't look right...

    + {{else}} +

    It's cooking nicely!

    + {{/if}} + {{else}} +

    It's starting to cook...

    + {{/if}} +
    +
    + {{:helper.displayBar(helper.byondTimeOfDay(), data.start_time, data.start_time + data.cook_time, 'good', null, null, null, "Cook")}} +
    + {{window.cook_time = data.cook_time;}} + {{window.start_time = data.start_time;}} + {{window.curr_time = helper.byondTimeOfDay();}} + +
    + {{:helper.link("Abort", 'cancel', {'action': 'abort'}, null, 'redButton')}} +
    + {{else}} +

    Ingredients

    +
      + {{if jQuery.isEmptyObject(data.cooking_items) && jQuery.isEmptyObject(data.cooking_reagents)}} +
    • The microwave is empty!
    • + {{/if}} + {{props data.cooking_items :amt:name}} +
    • {{:helper.link(name + ' • ' + amt, null, {'action': 'ejectitem', 'target': name}, null, 'linkOn')}}
    • + {{/props}} + {{props data.cooking_reagents :amt:name}} +
    • {{:helper.link(name + ' • ' + amt + ' units', null, {'action': 'ejectreagent', 'target': name}, null, 'linkOn')}}
    • + {{/props}} +
    +
    +
    + {{:helper.link("Eject All", 'trash', {'action' : 'dispose'}, null, 'redButton')}} +
    +
    + {{:helper.link("Cook", null, {'action': 'cook'}, null, 'linkOn')}} +
    + {{/if}} +
    \ No newline at end of file diff --git a/nano/templates/network_acl.tmpl b/nano/templates/network_acl.tmpl index aa985571d60c..11812a6b02b7 100644 --- a/nano/templates/network_acl.tmpl +++ b/nano/templates/network_acl.tmpl @@ -1,5 +1,5 @@ {{if data.error}} -

    An error has occured:

    +

    An error has occurred:

    Additional information: {{:data.error}}
    Please try again. If the problem persists contact your system administrator for assistance.
    @@ -7,76 +7,46 @@ {{:helper.link("NETWORK SETTINGS", null, { "settings" : 1 })}}
    {{else}} - Welcome to the Network Firewall Controller system. Please consult your system administrator if you have any questions about your device.
    + Welcome to the Network Access Controller system. Please consult your system administrator if you have any questions about your device.
    {{:helper.link("NETWORK SETTINGS", null, { "settings" : 1 })}}
    {{if !data.connected}}

    Disconnected from network.

    + {{else !data.current_group}} +

    Network Group Settings:

    +
    SettingToggleInfo +
    PARENT GROUP SUBMANAGEMENT + {{:helper.link(data.allow_submanagement ? 'ON' : 'OFF', null, { "toggle_submanagement" : 1 })}} + {{:helper.link('?', null, { "info" : "submanagement"})}} +
    PARENT ACCOUNT CREATION + {{:helper.link(data.parent_account_creation ? 'ON' : 'OFF', null, { "toggle_parent_account_creation" : 1 })}} + {{:helper.link('?', null, { "info" : "parent_account_creation"})}} +
    +

    Viewing Parent Groups:

    + +
    Group + Operations + {{for data.parent_groups}} +
    {{:helper.link(value.group_name, null, {"view_child_groups" : value.group_name})}} + + {{:helper.link('Remove', null, { "remove_group" : value.group_name})}} + {{/for}} +
    + {{:helper.link('Create Group', null, { "create_group" : 1})}} {{else}} -

    Viewing File System:

    -
    - {{:helper.link(data.file_server, null, { "change_file_server" : 1 })}} -

    - {{if data.editing_user}} -

    Viewing User Record: {{:data.desired_name}}

    -
    -
    NAME:
    -
    {{:data.desired_name}}
    -
    -
    -
    USER ID:
    -
    {{:data.user_id}}
    -
    -
    -
    GRANT COUNT:
    -
    {{:data.grant_count}}
    -
    -
    -
    RECORD SIZE:
    -
    {{:data.size}}GQ
    -
    -
    - {{:helper.link('CREATE GRANT', null, { "create_grant" : data.user_id })}} - {{if data.is_admin}} - {{:helper.link('REMOVE ADMIN', null, { "remove_admin": 1})}} - {{else}} - {{:helper.link('GRANT ADMIN', null, { "add_admin": 1})}} - {{/if}} - {{:helper.link('WRITE ID', null, { "write_id": 1}, !data.card_inserted ? 'disabled' : null)}} - {{:helper.link('EJECT ID', null, { "eject_id": 1}, !data.card_inserted ? 'disabled' : null)}} -
    -
    - -
    Grant - Operations - {{for data.grants}} -
    {{:value.grant_name}} - - {{if value.assigned}} - {{:helper.link('REMOVE', null, { "remove_grant" : value.grant_name })}} - {{else}} - {{:helper.link('ASSIGN', null, { "assign_grant" : value.grant_name })}} - {{/if}} - {{:helper.link('DELETE', null, { "delete_grant" : value.grant_name })}} - {{/for}} -
    - {{:helper.link('Back to menu', null, { "back" : 1 })}} - {{else}} -

    Available Users ({{:data.file_server}}):

    - -
    User ID - Grants - File size (GQ) - Operations - {{for data.users}} -
    {{:value.desired_name}} - {{:value.grant_count}} - {{:value.size}}GQ - - {{:helper.link('VIEW', null, { "view_user" : value.user_id })}} - {{/for}} -
    - {{/if}} +

    Parent Group: {{:data.current_group}}

    +
    + +
    Group + Operations + {{for data.child_groups}} +
    {{:value.group_name}} + + {{:helper.link('Remove', null, { "remove_group" : value.group_name})}} + {{/for}} +
    + {{:helper.link('Create Group', null, { "create_group" : 1})}} + {{:helper.link('Back to parent group listing', null, { "view_child_groups" : null })}} {{/if}} {{/if}} \ No newline at end of file diff --git a/nano/templates/network_id.tmpl b/nano/templates/network_id.tmpl new file mode 100644 index 000000000000..52613e05998e --- /dev/null +++ b/nano/templates/network_id.tmpl @@ -0,0 +1,19 @@ +
    + {{:helper.link("NETWORK SETTINGS", null, { "settings" : 1 })}} +
    +
    +
    +
    Login:
    +
    + {{:helper.link(data.login, null, { "change_login" : 1 })}} +
    +
    +
    +
    Password:
    +
    + {{:helper.link(data.password, null, { "change_password" : 1 })}} +
    +
    +
    + {{:helper.link('Login', null, { "login_account" : 1 })}} +
    \ No newline at end of file diff --git a/nano/templates/network_lock.tmpl b/nano/templates/network_lock.tmpl index e6e8ce1d56fc..89ba30748e59 100644 --- a/nano/templates/network_lock.tmpl +++ b/nano/templates/network_lock.tmpl @@ -1,5 +1,5 @@ {{if data.error}} -

    An error has occured:

    +

    An error has occurred:

    Additional information: {{:data.error}}
    Please try again. If the problem persists contact your system administrator for assistance. {{:helper.link('Refresh', null, { "refresh" : 1 })}} @@ -20,19 +20,63 @@

    -

    Grants:

    -
    Grant +
    Pattern + Groups Operations - {{for data.grants}} -
    {{:value.grant_name}} - - {{if value.assigned}} - {{:helper.link('REMOVE', null, { "remove_grant" : value.grant_name })}} - {{else}} - {{:helper.link('ASSIGN', null, { "assign_grant" : value.grant_name })}} - {{/if}} + {{for data.patterns}} +
    {{:helper.link("Pattern " + value.index, null, { "select_pattern" : value.index}, (data.selected_pattern == value.index) ? 'selected' : null)}} + {{:value.groups}} + {{:helper.link('Delete pattern', null, { "remove_pattern" : value.index})}} {{/for}}
    +
    + {{:helper.link('Add pattern', null, { "add_pattern" : 1}, null)}} + {{:helper.link('?', null, { "info" : "pattern" }, null)}} +
    + {{if data.parent_groups}} +

    Parent Groups:

    + {{:helper.link('?', null, { "info" : "parent_groups" }, null)}} + +
    Group + Operations + {{for data.parent_groups}} +
    {{:helper.link(value.parent_group, null, { "select_parent_group" : value.parent_group })}} + + {{if value.assigned}} + {{:helper.link('REMOVE', null, { "remove_group" : value.parent_group })}} + {{else}} + {{:helper.link('ASSIGN', null, { "assign_group" : value.parent_group })}} + {{/if}} + {{/for}} +
    + {{else data.selected_parent_group}} +

    Viewing Child Groups for: {{:data.selected_parent_group}}

    + {{if data.child_groups}} +

    Child Groups:

    + +
    Group + Operations + {{for data.child_groups}} +
    {{:value.child_group}} + + {{if value.assigned}} + {{:helper.link('REMOVE', null, { "remove_group" : value.child_group })}} + {{else}} + {{:helper.link('ASSIGN', null, { "assign_group" : value.child_group })}} + {{/if}} + {{/for}} +
    + {{else}} + No child groups found! + {{/if}} +
    + {{:helper.link('Back to parent group listing', null, { "select_parent_group" : null })}} +
    + {{else}} + {{if data.selected_pattern}} + No groups found on network! + {{/if}} + {{/if}} {{/if}} {{/if}} \ No newline at end of file diff --git a/nano/templates/network_machine_settings.tmpl b/nano/templates/network_machine_settings.tmpl index 73c9b1078223..8c75b76e1b7a 100644 --- a/nano/templates/network_machine_settings.tmpl +++ b/nano/templates/network_machine_settings.tmpl @@ -1,5 +1,5 @@ {{if data.error}} -

    An error has occured:

    +

    An error has occurred:

    Additional information: {{:data.error}}
    Please try again. If the problem persists contact your system administrator for assistance.
    @@ -34,4 +34,4 @@

    EXONET Firmware v110.04.4h Copyright EXONETWORKS INC -{{/if}} \ No newline at end of file +{{/if}} \ No newline at end of file diff --git a/nano/templates/network_mainframe.tmpl b/nano/templates/network_mainframe.tmpl index f271e98b4f16..3cb6d44378b9 100644 --- a/nano/templates/network_mainframe.tmpl +++ b/nano/templates/network_mainframe.tmpl @@ -1,5 +1,5 @@ {{if data.error}} -

    An error has occured:

    +

    An error has occurred:

    Additional information: {{:data.error}}
    Please try again. If the problem persists contact your system administrator for assistance.
    @@ -33,7 +33,7 @@
    MISSING
    - {{/if}} + {{/if}}
    EXONET Firmware v110.04.4h Copyright EXONETWORKS INC -{{/if}} \ No newline at end of file +{{/if}} \ No newline at end of file diff --git a/nano/templates/network_modem.tmpl b/nano/templates/network_modem.tmpl new file mode 100644 index 000000000000..ad1abaa9901d --- /dev/null +++ b/nano/templates/network_modem.tmpl @@ -0,0 +1,31 @@ +{{if data.error}} +

    An error has occurred:

    + Additional information: {{:data.error}}
    + Please try again. If the problem persists contact your system administrator for assistance. +
    + {{:helper.link('Refresh', null, { "refresh" : 1 })}} +
    +{{else}} +
    + Network TAG: +
    +
    + {{:data.network_tag}} +
    +
    + {{:helper.link("NETWORK SETTINGS", null, { "settings" : 1 })}} +
    +

    PLEXUS Features:

    + {{for data.features}} +
    +
    + {{:value.name}} +
    +
    + {{:helper.link(value.enabled ? "Enabled" : "Disabled", null, { "toggle_feature" : value.name })}} +
    +
    + {{/for}} +
    + EXONET Firmware v110.04.4h Copyright EXONETWORKS INC +{{/if}} \ No newline at end of file diff --git a/nano/templates/network_router.tmpl b/nano/templates/network_router.tmpl index e54fb66db516..0c1630f0af5c 100644 --- a/nano/templates/network_router.tmpl +++ b/nano/templates/network_router.tmpl @@ -1,5 +1,5 @@ {{if data.error}} -

    An error has occured:

    +

    An error has occurred:

    Additional information: {{:data.error}}
    Please try again. If the problem persists contact your system administrator for assistance.
    @@ -29,10 +29,16 @@
    BACKUP ROUTER / RELAY
    - {{/if}} + {{/if}} +
    + Wi-Fi Connections: +
    +
    + {{:helper.link(data.wifi ? "ENABLED" : "DISABLED", null, { "toggle_wifi" : 1 })}} +
    {{:helper.link("NETWORK SETTINGS", null, { "settings" : 1 })}}

    EXONET Firmware v110.04.4h Copyright EXONETWORKS INC -{{/if}} \ No newline at end of file +{{/if}} \ No newline at end of file diff --git a/nano/templates/network_shared.tmpl b/nano/templates/network_shared.tmpl new file mode 100644 index 000000000000..3be2c10a4294 --- /dev/null +++ b/nano/templates/network_shared.tmpl @@ -0,0 +1,25 @@ + + + + +{{function net_connection_settings(network, network_id) { }} +
    +
    {{:helper.link(network ? (network + '.' + network_id) : '---', network? 'signal-diag': 'close', { 'network_settings': 1 }, null)}}
    +
    +
    +{{ } }} \ No newline at end of file diff --git a/nano/templates/nuclear_bomb.tmpl b/nano/templates/nuclear_bomb.tmpl index c22984160022..68fc9d42a64f 100644 --- a/nano/templates/nuclear_bomb.tmpl +++ b/nano/templates/nuclear_bomb.tmpl @@ -1,72 +1,72 @@ - -
    - Authorization Disk: {{if data.auth}}{{:helper.link('++++++++++', 'eject', {'auth' : 1})}} {{else}} {{:helper.link('----------', 'disk', {'auth' : 1})}}{{/if}} -
    -
    -
    -
    Status: {{:data.authstatus}} - {{:data.safe}}
    -
    Timer: {{:data.time}}
    -
    -
    -
    - {{if data.auth && data.yescode}} -
    - Timer: {{:helper.link('On', 'play', {'timer' : 1}, data.timer ? 'redButton' : '')}}{{:helper.link('Off', 'stop', {'timer' : 0}, !data.timer ? 'selected' : '')}} -
    -
    - Time: {{:helper.link('--', '', {'time' : -10}, data.time <= 120 ? 'disabled' : '')}}{{:helper.link('-', '', {'time' : -1}, data.time <= 120 ? 'disabled' : '')}} {{:data.time}} {{:helper.link('+', '', {'time' : 1})}}{{:helper.link('++', '', {'time' : 10})}} -
    - {{else}} -
    - Timer: {{:helper.link('On', 'play', null, 'disabled')}}{{:helper.link('Off', 'pause', null, 'disabled')}} -
    -
    - Time: {{:helper.link('-', '', null, 'disabled')}}{{:helper.link('-', '', null, 'disabled')}} {{:data.time}} {{:helper.link('+', '', null, 'disabled')}}{{:helper.link('++', '', null, 'disabled')}} -
    - {{/if}} -
    -
    - {{if data.auth && data.yescode}} -
    - Safety: {{:helper.link('Engaged', 'info', {'safety' : 1}, data.safety ? 'selected' : '')}}{{:helper.link('Disengaged', 'alert', {'safety' : 0}, data.safety ? '' : 'redButton')}} -
    - {{if data.moveable_anchor}} -
    - Anchor: {{:helper.link('Engaged', 'locked', {'anchor' : 1}, data.anchored ? 'selected' : '')}}{{:helper.link('Disengaged', 'unlocked', {'anchor' : 0}, data.anchored ? '' : 'selected')}} -
    - {{/if}} - {{else}} -
    - Safety: {{:helper.link('Engaged', 'info', null, 'disabled')}}{{:helper.link('Disengaged', 'alert', null, 'disabled')}} -
    - {{if data.moveable_anchor}} -
    - Anchor: {{:helper.link('Engaged', 'locked', null, 'disabled')}}{{:helper.link('Disengaged', 'unlocked', null, 'disabled')}} -
    - {{/if}} - {{/if}} -
    -
    -
    -
    -
    - >{{if data.message}} {{:data.message}}{{/if}} -
    -
    -
    - {{:helper.link('1', '', {'type' : 1})}}{{:helper.link('2', '', {'type' : 2})}}{{:helper.link('3', '', {'type' : 3})}} -
    -
    - {{:helper.link('4', '', {'type' : 4})}}{{:helper.link('5', '', {'type' : 5})}}{{:helper.link('6', '', {'type' : 6})}} -
    -
    - {{:helper.link('7', '', {'type' : 7})}}{{:helper.link('8', '', {'type' : 8})}}{{:helper.link('9', '', {'type' : 9})}} -
    -
    - {{:helper.link('R', '', {'type' : 'R'})}}{{:helper.link('0', '', {'type' : 0})}}{{:helper.link('E', '', {'type' : 'E'})}} -
    -
    -
    + +
    + Authorization Disk: {{if data.auth}}{{:helper.link('++++++++++', 'eject', {'auth' : 1})}} {{else}} {{:helper.link('----------', 'disk', {'auth' : 1})}}{{/if}} +
    +
    +
    +
    Status: {{:data.authstatus}} - {{:data.safe}}
    +
    Timer: {{:data.time}}
    +
    +
    +
    + {{if data.auth && data.yescode}} +
    + Timer: {{:helper.link('On', 'play', {'timer' : 1}, data.timer ? 'redButton' : '')}}{{:helper.link('Off', 'stop', {'timer' : 0}, !data.timer ? 'selected' : '')}} +
    +
    + Time: {{:helper.link('--', '', {'time' : -10}, data.time <= 120 ? 'disabled' : '')}}{{:helper.link('-', '', {'time' : -1}, data.time <= 120 ? 'disabled' : '')}} {{:data.time}} {{:helper.link('+', '', {'time' : 1})}}{{:helper.link('++', '', {'time' : 10})}} +
    + {{else}} +
    + Timer: {{:helper.link('On', 'play', null, 'disabled')}}{{:helper.link('Off', 'pause', null, 'disabled')}} +
    +
    + Time: {{:helper.link('-', '', null, 'disabled')}}{{:helper.link('-', '', null, 'disabled')}} {{:data.time}} {{:helper.link('+', '', null, 'disabled')}}{{:helper.link('++', '', null, 'disabled')}} +
    + {{/if}} +
    +
    + {{if data.auth && data.yescode}} +
    + Safety: {{:helper.link('Engaged', 'info', {'safety' : 1}, data.safety ? 'selected' : '')}}{{:helper.link('Disengaged', 'alert', {'safety' : 0}, data.safety ? '' : 'redButton')}} +
    + {{if data.moveable_anchor}} +
    + Anchor: {{:helper.link('Engaged', 'locked', {'anchor' : 1}, data.anchored ? 'selected' : '')}}{{:helper.link('Disengaged', 'unlocked', {'anchor' : 0}, data.anchored ? '' : 'selected')}} +
    + {{/if}} + {{else}} +
    + Safety: {{:helper.link('Engaged', 'info', null, 'disabled')}}{{:helper.link('Disengaged', 'alert', null, 'disabled')}} +
    + {{if data.moveable_anchor}} +
    + Anchor: {{:helper.link('Engaged', 'locked', null, 'disabled')}}{{:helper.link('Disengaged', 'unlocked', null, 'disabled')}} +
    + {{/if}} + {{/if}} +
    +
    +
    +
    +
    + >{{if data.message}} {{:data.message}}{{/if}} +
    +
    +
    + {{:helper.link('1', '', {'type' : 1})}}{{:helper.link('2', '', {'type' : 2})}}{{:helper.link('3', '', {'type' : 3})}} +
    +
    + {{:helper.link('4', '', {'type' : 4})}}{{:helper.link('5', '', {'type' : 5})}}{{:helper.link('6', '', {'type' : 6})}} +
    +
    + {{:helper.link('7', '', {'type' : 7})}}{{:helper.link('8', '', {'type' : 8})}}{{:helper.link('9', '', {'type' : 9})}} +
    +
    + {{:helper.link('R', '', {'type' : 'R'})}}{{:helper.link('0', '', {'type' : 0})}}{{:helper.link('E', '', {'type' : 'E'})}} +
    +
    +
    diff --git a/nano/templates/omni_filter.tmpl b/nano/templates/omni_filter.tmpl index 8f2dbfc924e7..eaa587a77788 100644 --- a/nano/templates/omni_filter.tmpl +++ b/nano/templates/omni_filter.tmpl @@ -1,87 +1,103 @@ -
    -
    - {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} -
    -
    - {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} -
    -
    -
    - {{if data.config}} - -
    -
    -
    Port
    - {{for data.ports}} -
    {{:value.dir}} Port
    - {{/for}} -
    -
    -
    Input
    - {{for data.ports}} -
    - {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, null, value.input ? 'selected' : null)}} -
    - {{/for}} -
    -
    -
    Output
    - {{for data.ports}} -
    - {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} -
    - {{/for}} -
    -
    -
    Filter
    - {{for data.ports}} -
    - {{:helper.link(value.f_type ? value.f_type : 'None', null, {'command' : 'switch_filter', 'mode' : value.f_type, 'dir' : value.dir}, value.filter ? null : 'disabled', value.f_type ? 'selected' : null)}} -
    - {{/for}} -
    -
    - -
    - Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
    -
    - {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} -
    - - {{else}} - -
    -
    -
    Port
    - {{for data.ports}} -
    {{:value.dir}} Port
    - {{/for}} -
    -
    -
    Mode
    - {{for data.ports}} -
    - {{if value.input}} - Input - {{else value.output}} - Output - {{else value.f_type}} - {{:value.f_type}} - {{else}} - Disabled - {{/if}} -
    - {{/for}} -
    -
    - -
    - Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
    - -
    - Flow Rate: {{:(data.last_flow_rate/10)}} L/s -
    - {{/if}} +
    +
    + {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} +
    +
    + {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} +
    +
    +
    + {{if data.config}} + +
    +
    +
    Port
    + {{for data.ports}} +
    {{:value.dir}} Port
    + {{/for}} +
    +
    +
    None
    + {{for data.ports}} +
    + {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'none', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} +
    + {{/for}} +
    +
    +
    Input
    + {{for data.ports}} +
    + {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, null, value.input ? 'selected' : null)}} +
    + {{/for}} +
    +
    +
    Output
    + {{for data.ports}} +
    + {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} +
    + {{/for}} +
    +
    +
    Filtering
    + {{for data.ports}} +
    + {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'filtering', 'dir' : value.dir}, null, value.filter ? 'selected' : null)}} +
    + {{/for}} +
    +
    +
    Filter
    + {{for data.ports}} +
    + {{:helper.link(value.f_type ? value.f_type : 'None', null, {'command' : 'switch_filter', 'mode' : value.f_type, 'dir' : value.dir}, value.filter ? null : 'disabled', value.f_type ? 'selected' : null)}} +
    + {{/for}} +
    +
    + +
    + Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s +
    +
    + {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} +
    + + {{else}} + +
    +
    +
    Port
    + {{for data.ports}} +
    {{:value.dir}} Port
    + {{/for}} +
    +
    +
    Mode
    + {{for data.ports}} +
    + {{if value.input}} + Input + {{else value.output}} + Output + {{else value.f_type}} + {{:value.f_type}} + {{else}} + Disabled + {{/if}} +
    + {{/for}} +
    +
    + +
    + Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s +
    + +
    + Flow Rate: {{:(data.last_flow_rate/10)}} L/s +
    + {{/if}}
    \ No newline at end of file diff --git a/nano/templates/omni_mixer.tmpl b/nano/templates/omni_mixer.tmpl index 77c4573880b0..985f49ecaae3 100644 --- a/nano/templates/omni_mixer.tmpl +++ b/nano/templates/omni_mixer.tmpl @@ -1,102 +1,102 @@ -
    -
    - {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} -
    -
    - {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} -
    -
    -
    - {{if data.config}} - -
    -
    -
    Port
    - {{for data.ports}} -
    {{:value.dir}} Port
    - {{/for}} -
    -
    -
    Input
    - {{for data.ports}} -
    - {{:helper.link(' ', null, value.input ? {'command' : 'switch_mode', 'mode' : 'none', 'dir' : value.dir} : {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, value.output ? 'disabled' : null, value.input ? 'selected' : null)}} -
    - {{/for}} -
    -
    -
    Output
    - {{for data.ports}} -
    - {{:helper.link(' ', null, value.output ? null : {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} -
    - {{/for}} -
    -
    -
    Concentration
    - {{for data.ports}} -
    - {{:helper.link( value.input ? helper.round(value.concentration*100)+' %' : '-', null, {'command' : 'switch_con', 'dir' : value.dir}, value.input ? null : 'disabled')}} -
    - {{/for}} -
    -
    -
    Lock
    - {{for data.ports}} -
    - {{:helper.link(' ', value.con_lock ? 'locked' : 'unlocked', {'command' : 'switch_conlock', 'dir' : value.dir}, value.input ? null : 'disabled', value.con_lock ? 'selected' : null)}} -
    - {{/for}} -
    -
    - -
    - Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
    -
    - {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} -
    - - {{else}} - -
    -
    -
    Port
    - {{for data.ports}} -
    {{:value.dir}} Port
    - {{/for}} -
    -
    -
    Mode
    - {{for data.ports}} -
    - {{if value.input}} - Input - {{else value.output}} - Output - {{else}} - Disabled - {{/if}} -
    - {{/for}} -
    -
    -
    Concentration
    - {{for data.ports}} -
    - {{if value.input}} - {{:helper.round(value.concentration*100)}} % - {{else}} - - - {{/if}} -
    - {{/for}} -
    -
    - -
    - Flow Rate: {{:(data.last_flow_rate/10)}} L/s -
    - - {{/if}} +
    +
    + {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} +
    +
    + {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} +
    +
    +
    + {{if data.config}} + +
    +
    +
    Port
    + {{for data.ports}} +
    {{:value.dir}} Port
    + {{/for}} +
    +
    +
    Input
    + {{for data.ports}} +
    + {{:helper.link(' ', null, value.input ? {'command' : 'switch_mode', 'mode' : 'none', 'dir' : value.dir} : {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, value.output ? 'disabled' : null, value.input ? 'selected' : null)}} +
    + {{/for}} +
    +
    +
    Output
    + {{for data.ports}} +
    + {{:helper.link(' ', null, value.output ? null : {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} +
    + {{/for}} +
    +
    +
    Concentration
    + {{for data.ports}} +
    + {{:helper.link( value.input ? helper.round(value.concentration*100)+' %' : '-', null, {'command' : 'switch_con', 'dir' : value.dir}, value.input ? null : 'disabled')}} +
    + {{/for}} +
    +
    +
    Lock
    + {{for data.ports}} +
    + {{:helper.link(' ', value.con_lock ? 'locked' : 'unlocked', {'command' : 'switch_conlock', 'dir' : value.dir}, value.input ? null : 'disabled', value.con_lock ? 'selected' : null)}} +
    + {{/for}} +
    +
    + +
    + Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s +
    +
    + {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} +
    + + {{else}} + +
    +
    +
    Port
    + {{for data.ports}} +
    {{:value.dir}} Port
    + {{/for}} +
    +
    +
    Mode
    + {{for data.ports}} +
    + {{if value.input}} + Input + {{else value.output}} + Output + {{else}} + Disabled + {{/if}} +
    + {{/for}} +
    +
    +
    Concentration
    + {{for data.ports}} +
    + {{if value.input}} + {{:helper.round(value.concentration*100)}} % + {{else}} + - + {{/if}} +
    + {{/for}} +
    +
    + +
    + Flow Rate: {{:(data.last_flow_rate/10)}} L/s +
    + + {{/if}}
    \ No newline at end of file diff --git a/nano/templates/pacman.tmpl b/nano/templates/pacman.tmpl index 325b8face576..8615864371c7 100644 --- a/nano/templates/pacman.tmpl +++ b/nano/templates/pacman.tmpl @@ -59,6 +59,26 @@
    {{/if}}
    +{{if data.uses_coolant}} +

    Coolant

    +
    +
    + Coolant Level: +
    +
    + {{if data.coolant_stored/data.coolant_capacity >= 0.4}} + {{:helper.displayBar(data.coolant_stored, 0, data.coolant_capacity, 'good')}} +
    {{:data.coolant_stored}}/{{:data.coolant_capacity}} u + {{else data.coolant_stored/data.coolant_capacity >= 0.1}} + {{:helper.displayBar(data.coolant_stored, 0, data.coolant_capacity, 'average')}} +
    {{:data.coolant_stored}}/{{:data.coolant_capacity}} u + {{else}} + {{:helper.displayBar(data.coolant_stored, 0, data.coolant_capacity, 'bad')}} +
    {{:data.coolant_stored}}/{{:data.coolant_capacity}} u + {{/if}} +
    +
    +{{/if}}

    Output

    diff --git a/nano/templates/pai_medrecords.tmpl b/nano/templates/pai_medrecords.tmpl index 37b1d7061ca6..a8c6c9cacc3f 100644 --- a/nano/templates/pai_medrecords.tmpl +++ b/nano/templates/pai_medrecords.tmpl @@ -21,7 +21,7 @@ code/modules/mob/living/silicon/pai/software_modules.dm
    Sex
    -
    {{:data.general.sex}}
    +
    {{:data.general.gender}}
    Species
    diff --git a/nano/templates/pai_radio.tmpl b/nano/templates/pai_radio.tmpl index 70e76a26334e..af6e70dfda07 100644 --- a/nano/templates/pai_radio.tmpl +++ b/nano/templates/pai_radio.tmpl @@ -38,10 +38,10 @@ code/modules/mob/living/silicon/pai/software_modules.dm
    {{if value.listening}} {{:helper.link("On", '', {"stopic":"radio", "channel":value.name, "listen":1, "nowindow":1}, 'selected')}} - {{:helper.link("Off", '', {"stopic":"radio", "channel":value.name, "listen":1, "nowindow":1})}} + {{:helper.link("Off", '', {"stopic":"radio", "channel":value.name, "listen":0, "nowindow":1})}} {{else}} {{:helper.link("On", '', {"stopic":"radio", "channel":value.name, "listen":1, "nowindow":1})}} - {{:helper.link("Off", '', {"stopic":"radio", "channel":value.name, "listen":1, "nowindow":1}, 'selected')}} + {{:helper.link("Off", '', {"stopic":"radio", "channel":value.name, "listen":0, "nowindow":1}, 'selected')}} {{/if}}
    diff --git a/nano/templates/pai_secrecords.tmpl b/nano/templates/pai_secrecords.tmpl index e139034c0dee..20fbde97f6db 100644 --- a/nano/templates/pai_secrecords.tmpl +++ b/nano/templates/pai_secrecords.tmpl @@ -21,7 +21,7 @@ code/modules/mob/living/silicon/pai/software_modules.dm
    Sex
    -
    {{:data.general.sex}}
    +
    {{:data.general.gender}}
    Species
    diff --git a/nano/templates/photocopier.tmpl b/nano/templates/photocopier.tmpl new file mode 100644 index 000000000000..d76458b93026 --- /dev/null +++ b/nano/templates/photocopier.tmpl @@ -0,0 +1,56 @@ + + +{{function make_copy_form(copies_left, copies_max, src) { }} +
    +
    + +
    +
    + + 0) && (copies_left < copies_max))? copies_left : copies_max}} {{:copies_left == 0? 'disabled' : ''}} /> + + +
    +
    +
    +{{ } }} + +{{function make_sillicon_ui() { }} + {{:helper.link('Print photo from database', null, {'aipic' : 1})}} +

    +{{ } }} + +{{function make_photocopy_ui() { }} +
    +
    Document
    +
    {{:helper.link(data.loaded_item_name? data.loaded_item_name : '----', data.loaded_item_name? 'eject' : null, {'eject': 1}, data.loaded_item_name? null : 'disabled' )}}
    +
    +
    + {{if !data.is_printing}} + {{make_copy_form(data.copies_left, data.copies_max, data.src);}} + {{else}} +
    Printing Page
    +
    {{:data.left_printing}} out of {{:data.total_printing}} page(s)
    +
    {{:helper.link('Cancel', 'abort', {'cancel_queue': 1})}}
    + {{/if}} +
    +{{ } }} + +{{if !data.is_operational}} + SYSTEM ERROR +{{else}} + + {{#def.stock_parts_printer_shared}} +
    +

    Photocopy

    + {{if !data.is_sillicon_mode}} + {{make_photocopy_ui();}} + {{else}} + {{make_sillicon_ui();}} + {{/if}} +{{/if}} diff --git a/nano/templates/portpump.tmpl b/nano/templates/portpump.tmpl index 3e14aac8f92d..59ada0a54ac2 100644 --- a/nano/templates/portpump.tmpl +++ b/nano/templates/portpump.tmpl @@ -1,100 +1,100 @@ -

    Pump Status

    -
    -
    - Tank Pressure: -
    -
    - {{:data.tankPressure}} kPa -
    -
    - -
    -
    - Port Status: -
    -
    - {{:data.portConnected ? 'Connected' : 'Disconnected'}} -
    -
    - -
    -
    - Load: -
    -
    - {{:data.powerDraw}} W -
    -
    - -
    -
    - Cell Charge: -
    -
    - {{:helper.displayBar(data.cellCharge, 0, data.cellMaxCharge)}} -
    -
    - -

    Holding Tank Status

    -{{if data.hasHoldingTank}} -
    -
    - Tank Label: -
    -
    -
    {{:data.holdingTank.name}}
    {{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} -
    -
    - -
    -
    - Tank Pressure: -
    -
    - {{:data.holdingTank.tankPressure}} kPa -
    -
    -{{else}} -
    No holding tank inserted.
    -
     
    -{{/if}} - - -

    Power Regulator Status

    -
    -
    - Target Pressure: -
    -
    - {{:helper.displayBar(data.targetpressure, data.minpressure, data.maxpressure)}} -
    - {{:helper.link('-', null, {'pressure_adj' : -1000}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -100}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -10}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} - {{:helper.link('-', null, {'pressure_adj' : -1}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} -
     {{:data.targetpressure}} kPa 
    - {{:helper.link('+', null, {'pressure_adj' : 1}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 10}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 100}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'pressure_adj' : 1000}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} -
    -
    -
    - -
    -
    - Power Switch: -
    -
    - {{:helper.link('On', 'unlocked', {'power' : 1}, data.on ? 'selected' : null)}} {{:helper.link('Off', 'locked', {'power' : 1}, data.on ? null : 'selected')}} -
    -
    - -
    -
    - Pump Direction: -
    -
    - {{:helper.link('Out', 'arrowreturn-1-e', {'direction' : 1}, data.pump_dir ? 'selected' : null)}} {{:helper.link('In', 'arrowreturn-1-w', {'direction' : 1}, data.pump_dir ? null : 'selected')}} -
    -
    +

    Pump Status

    +
    +
    + Tank Pressure: +
    +
    + {{:data.tankPressure}} kPa +
    +
    + +
    +
    + Port Status: +
    +
    + {{:data.portConnected ? 'Connected' : 'Disconnected'}} +
    +
    + +
    +
    + Load: +
    +
    + {{:data.powerDraw}} W +
    +
    + +
    +
    + Cell Charge: +
    +
    + {{:helper.displayBar(data.cellCharge, 0, data.cellMaxCharge)}} +
    +
    + +

    Holding Tank Status

    +{{if data.hasHoldingTank}} +
    +
    + Tank Label: +
    +
    +
    {{:data.holdingTank.name}}
    {{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} +
    +
    + +
    +
    + Tank Pressure: +
    +
    + {{:data.holdingTank.tankPressure}} kPa +
    +
    +{{else}} +
    No holding tank inserted.
    +
     
    +{{/if}} + + +

    Power Regulator Status

    +
    +
    + Target Pressure: +
    +
    + {{:helper.displayBar(data.targetpressure, data.minpressure, data.maxpressure)}} +
    + {{:helper.link('-', null, {'pressure_adj' : -1000}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} + {{:helper.link('-', null, {'pressure_adj' : -100}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} + {{:helper.link('-', null, {'pressure_adj' : -10}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} + {{:helper.link('-', null, {'pressure_adj' : -1}, (data.targetpressure > data.minpressure) ? null : 'disabled')}} +
     {{:data.targetpressure}} kPa 
    + {{:helper.link('+', null, {'pressure_adj' : 1}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} + {{:helper.link('+', null, {'pressure_adj' : 10}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} + {{:helper.link('+', null, {'pressure_adj' : 100}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} + {{:helper.link('+', null, {'pressure_adj' : 1000}, (data.targetpressure < data.maxpressure) ? null : 'disabled')}} +
    +
    +
    + +
    +
    + Power Switch: +
    +
    + {{:helper.link('On', 'unlocked', {'power' : 1}, data.on ? 'selected' : null)}} {{:helper.link('Off', 'locked', {'power' : 1}, data.on ? null : 'selected')}} +
    +
    + +
    +
    + Pump Direction: +
    +
    + {{:helper.link('Out', 'arrowreturn-1-e', {'direction' : 1}, data.pump_dir ? 'selected' : null)}} {{:helper.link('In', 'arrowreturn-1-w', {'direction' : 1}, data.pump_dir ? null : 'selected')}} +
    +
    diff --git a/nano/templates/portscrubber.tmpl b/nano/templates/portscrubber.tmpl index c99f53344c41..f2f216f630b1 100644 --- a/nano/templates/portscrubber.tmpl +++ b/nano/templates/portscrubber.tmpl @@ -1,91 +1,91 @@ -

    Scrubber Status

    -
    -
    - Tank Pressure: -
    -
    - {{:data.tankPressure}} kPa -
    -
    - -
    -
    - Port Status: -
    -
    - {{:data.portConnected ? 'Connected' : 'Disconnected'}} -
    -
    - -
    -
    - Load: -
    -
    - {{:data.powerDraw}} W -
    -
    - -
    -
    - Cell Charge: -
    -
    - {{:helper.displayBar(data.cellCharge, 0, data.cellMaxCharge)}} -
    -
    - -

    Holding Tank Status

    -{{if data.hasHoldingTank}} -
    -
    - Tank Label: -
    -
    -
    {{:data.holdingTank.name}}
    {{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} -
    -
    q - -
    -
    - Tank Pressure: -
    -
    - {{:data.holdingTank.tankPressure}} kPa -
    -
    -{{else}} -
    No holding tank inserted.
    -
     
    -{{/if}} - - -

    Power Regulator Status

    -
    -
    - Volume Rate: -
    -
    - {{:helper.displayBar(data.rate, data.minrate, data.maxrate)}} -
    - {{:helper.link('-', null, {'volume_adj' : -1000}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -100}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -10}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -1}, (data.rate > data.minrate) ? null : 'disabled')}} -
     {{:data.rate}} L/s 
    - {{:helper.link('+', null, {'volume_adj' : 1}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 10}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 100}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 1000}, (data.rate < data.maxrate) ? null : 'disabled')}} -
    -
    -
    - -
    -
    - Power Switch: -
    -
    - {{:helper.link('On', 'unlocked', {'power' : 1}, data.on ? 'selected' : null)}} {{:helper.link('Off', 'locked', {'power' : 1}, data.on ? null : 'selected')}} -
    -
    +

    Scrubber Status

    +
    +
    + Tank Pressure: +
    +
    + {{:data.tankPressure}} kPa +
    +
    + +
    +
    + Port Status: +
    +
    + {{:data.portConnected ? 'Connected' : 'Disconnected'}} +
    +
    + +
    +
    + Load: +
    +
    + {{:data.powerDraw}} W +
    +
    + +
    +
    + Cell Charge: +
    +
    + {{:helper.displayBar(data.cellCharge, 0, data.cellMaxCharge)}} +
    +
    + +

    Holding Tank Status

    +{{if data.hasHoldingTank}} +
    +
    + Tank Label: +
    +
    +
    {{:data.holdingTank.name}}
    {{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} +
    +
    q + +
    +
    + Tank Pressure: +
    +
    + {{:data.holdingTank.tankPressure}} kPa +
    +
    +{{else}} +
    No holding tank inserted.
    +
     
    +{{/if}} + + +

    Power Regulator Status

    +
    +
    + Volume Rate: +
    +
    + {{:helper.displayBar(data.rate, data.minrate, data.maxrate)}} +
    + {{:helper.link('-', null, {'volume_adj' : -1000}, (data.rate > data.minrate) ? null : 'disabled')}} + {{:helper.link('-', null, {'volume_adj' : -100}, (data.rate > data.minrate) ? null : 'disabled')}} + {{:helper.link('-', null, {'volume_adj' : -10}, (data.rate > data.minrate) ? null : 'disabled')}} + {{:helper.link('-', null, {'volume_adj' : -1}, (data.rate > data.minrate) ? null : 'disabled')}} +
     {{:data.rate}} L/s 
    + {{:helper.link('+', null, {'volume_adj' : 1}, (data.rate < data.maxrate) ? null : 'disabled')}} + {{:helper.link('+', null, {'volume_adj' : 10}, (data.rate < data.maxrate) ? null : 'disabled')}} + {{:helper.link('+', null, {'volume_adj' : 100}, (data.rate < data.maxrate) ? null : 'disabled')}} + {{:helper.link('+', null, {'volume_adj' : 1000}, (data.rate < data.maxrate) ? null : 'disabled')}} +
    +
    +
    + +
    +
    + Power Switch: +
    +
    + {{:helper.link('On', 'unlocked', {'power' : 1}, data.on ? 'selected' : null)}} {{:helper.link('Off', 'locked', {'power' : 1}, data.on ? null : 'selected')}} +
    +
    diff --git a/nano/templates/power_monitor.tmpl b/nano/templates/power_monitor.tmpl index bf07238784f1..b2b621fa8737 100644 --- a/nano/templates/power_monitor.tmpl +++ b/nano/templates/power_monitor.tmpl @@ -56,24 +56,37 @@ {{:data.focus.total_used_all}}

    Sensor Readings

    - -
    APC NameEquipmentLightingEnvironmentCell StatusAPC Load - {{for data.focus.apc_data}} -
    {{:value.name}} - {{:value.s_equipment}} - {{:value.s_lighting}} - {{:value.s_environment}} - {{if value.cell_status == "N"}} - {{:helper.link(value.cell_charge + '%', 'batt_disc', null,'disabled', 'width75btn')}} - {{else value.cell_status == "C"}} - {{:helper.link(value.cell_charge + '%', 'batt_chrg', null,'disabled', 'width75btn')}} - {{else}} - {{:helper.link(value.cell_charge + '%', 'batt_full', null,'disabled', 'width75btn')}} - {{/if}} - {{:value.total_load}} - {{empty}} -
    No APCs detected in connected powernet. - {{/for}} + + {{if value.failure || value.telemetry}} +
    APC NameBreakerRCEquipmentLightingEnvironmentCell StatusAPC Load + {{for data.focus.apc_data}} +
    {{:value.name}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{:helper.link('MALFUNCT', 'alert', null, 'disabled', 'redButton')}} + {{else}} + {{:value.name}} + {{:helper.link(value.breaker ? 'On' : 'Off', 'power',{'toggle_breaker' : value.ref}, null, value.breaker ? 'greenButton' : 'redButton')}} + {{:helper.link(value.remote_control ? 'Enabled' : 'Disabled', value.remote_control ? 'signal' : 'close', null, 'greenButton')}} + {{:helper.link(value.s_equipment, null, {'toggle_powerchannel_equip' : value.ref}, null, value.n_equipment < 3 ? 'redButton' : 'greenButton')}} + {{:helper.link(value.s_lighting, null, {'toggle_powerchannel_light' : value.ref}, null, value.n_lighting < 3 ? 'redButton' : 'greenButton')}} + {{:helper.link(value.s_environment, null, {'toggle_powerchannel_enviro' : value.ref}, null, value.n_environment < 3 ? 'redButton' : 'greenButton')}} + {{if value.cell_status == "N"}} + {{:helper.link(value.cell_charge + '%', 'batt_disc', null,'disabled', 'width75btn')}} + {{else value.cell_status == "C"}} + {{:helper.link(value.cell_charge + '%', 'batt_chrg', null,'disabled', 'width75btn')}} + {{else}} + {{:helper.link(value.cell_charge + '%', 'batt_full', null,'disabled', 'width75btn')}} + {{/if}} + {{:value.total_load}} + {{/if}} + {{empty}} +
    No APCs detected in connected powernet. + {{/for}}
    {{/if}} {{else}} diff --git a/nano/templates/radio_basic.tmpl b/nano/templates/radio_basic.tmpl index 0eccbf9e2ff5..b3ba6f4830ac 100644 --- a/nano/templates/radio_basic.tmpl +++ b/nano/templates/radio_basic.tmpl @@ -1,4 +1,4 @@ - @@ -25,6 +25,45 @@ Used In File(s): /code/game/objects/item/devices/radio/radio.dm {{:helper.syndicateMode()}} {{/if}} +{{if data.network}} +
    +
    + Network Connectivity +
    +
    + {{:helper.link(data.network, null, { 'network_settings': 1 }, null)}} + {{:helper.link("Sync with hub", null, { 'sync': 1 }, null)}} +
    +
    +{{/if}} + +{{if data.can_use_analog}} +{{if data.network}} +
    +
    + Analog Transmission +
    +
    + {{:helper.link('On', null, {'analog' : 1}, data.analog ? 'selected' : null)}} + {{:helper.link('Off', null, {'analog' : 0}, data.analog ? null : 'selected')}} +
    +
    +{{/if}} +{{if data.analog && (data.available_keys || data.analog_secured)}} +
    +
    + Analog Encryption +
    +
    + {{for data.available_keys}} + {{:helper.link(value, null, {'analog_secured': value}, null, (data.analog_secured[value]) ? 'linkOn' : null)}} + {{/for}} + {{:helper.link('Clear', null, {'clear_analog_secured' : 1}, null)}} +
    +
    +{{/if}} +{{/if}} +
    Microphone @@ -49,24 +88,12 @@ Used In File(s): /code/game/objects/item/devices/radio/radio.dm {{:helper.link('On', null, null, 'disabled')}} {{:helper.link('Off', null, null, 'disabled')}} {{else}} - {{:helper.link('On', null, {'listen' : 0}, data.speaker ? 'selected' : null)}} - {{:helper.link('Off', null, {'listen' : 1}, data.speaker ? null : 'selected')}} + {{:helper.link('On', null, {'reception' : 0}, data.speaker ? 'selected' : null)}} + {{:helper.link('Off', null, {'reception' : 1}, data.speaker ? null : 'selected')}} {{/if}}
    -{{if data.has_subspace}} -
    -
    - Subspace Transmission: -
    -
    - {{:helper.link('On', null, {'mode' : 1}, data.subspace ? 'selected' : null)}} - {{:helper.link('Off', null, {'mode' : 0}, data.subspace ? null : 'selected')}} -
    -
    -{{/if}} - {{if data.has_loudspeaker}}
    @@ -97,26 +124,25 @@ Used In File(s): /code/game/objects/item/devices/radio/radio.dm
    {{:helper.link('--', null, {'freq' : -10})}} - {{:helper.link('-', null, {'freq' : -2})}} - {{:helper.link('+', null, {'freq' : 2})}} + {{:helper.link('-', null, {'freq' : -1})}} + {{:helper.link('+', null, {'freq' : 1})}} {{:helper.link('++', null, {'freq' : 10})}}
    -{{if data.chan_list_len >= 1}} +{{if data.show_channels}}

    Channels

    - {{for data.chan_list}} + {{for data.channel_list}}
    {{:value.display_name}}
    - {{if value.secure_channel}} - {{:helper.link('On', null, {'ch_name' : value.chan, 'listen' : value.sec_channel_listen}, value.sec_channel_listen ? null : 'selected')}} - {{:helper.link('Off', null, {'ch_name' : value.chan, 'listen' : value.sec_channel_listen}, value.sec_channel_listen ? 'selected' : null)}} - {{else}} - {{:helper.link('Switch', null, {'spec_freq' : value.chan}, data.rawfreq == value.chan ? 'selected' : null)}} - {{/if}} + {{:helper.link('On', null, {'ch_name' : value.chan, 'listen' : 1}, value.listening ? 'selected' : null)}} + {{:helper.link('Off', null, {'ch_name' : value.chan, 'listen' : 0}, value.listening ? null : 'selected')}} + {{if !value.secure_channel}} + {{:helper.link('Switch', null, {'spec_freq' : value.chan}, data.rawfreq == value.chan ? 'selected' : null)}} + {{/if}}
    {{/for}} {{/if}} diff --git a/nano/templates/request_console.tmpl b/nano/templates/request_console.tmpl index 82b27de25d54..698f7b162c92 100644 --- a/nano/templates/request_console.tmpl +++ b/nano/templates/request_console.tmpl @@ -66,14 +66,14 @@ Used In File(s): \code\game\machinery\requests_console.dm
    Message sent successfully.
    {{:helper.link('Continue', 'arrowthick-1-e', { 'setScreen' : 0 })}}
    {{else data.screen == 5}} -
    An Error occured. Message not sent.
    +
    An Error occurred. Message not sent.
    {{:helper.link('Continue', 'arrowthick-1-e', { 'setScreen' : 0 })}}
    {{else data.screen == 6}}
    {{for data.message_log}}
    {{:value}}
    {{empty}} -
    No messages have been recieved.
    +
    No messages have been received.
    {{/for}}
    {{:helper.link('Back', 'arrowreturnthick-1-w', { 'setScreen' : 0 })}}
    diff --git a/nano/templates/scanner.tmpl b/nano/templates/scanner.tmpl index dc9cac984590..862b2f30fd7d 100644 --- a/nano/templates/scanner.tmpl +++ b/nano/templates/scanner.tmpl @@ -2,21 +2,21 @@

    Attached scanner hardware: {{:data.scanner_name}}

    - Scanner installation status: + Status:
    {{:helper.link('Installed', null, {'connect_scanner' : 1}, data.using_scanner ? 'selected' : null)}} {{:helper.link('Uninstalled', null, {'connect_scanner' : 0}, !data.using_scanner ? 'selected' : null)}}
    - Scanner is: + Scanner:
    {{:helper.link('Enabled', null, {'PC_enable_component' : data.scanner_name}, data.scanner_enabled ? 'selected' : null)}} {{:helper.link('Disabled', null, {'PC_disable_component' : data.scanner_name}, !data.scanner_enabled ? 'selected' : null)}}
    - Scanner Actions: + Actions:
    {{:helper.link('Perform Scan', null, {'scan' : 1}, data.check_scanning ? null : 'disabled')}} @@ -31,4 +31,4 @@ {{/if}} {{else}}

    There is no scanner attached.

    -{{/if}} \ No newline at end of file +{{/if}} diff --git a/nano/templates/sec_camera.tmpl b/nano/templates/sec_camera.tmpl index b6ba57376e4f..51c0a8d9b8fe 100644 --- a/nano/templates/sec_camera.tmpl +++ b/nano/templates/sec_camera.tmpl @@ -1,36 +1,33 @@
    {{:helper.link('Show Map', 'pin-s', {'showMap' : 1})}} {{:helper.link('Reset', 'refresh', {'reset' : 1})}} + {{:helper.link('View Camera', null, {'view_camera' : 1})}}
    Current Camera:
    {{if data.current_camera}} -
    {{:data.current_camera.name}}
    +
    {{:data.current_camera.display_name}}
    {{else}}
    None
    {{/if}}
    -
    Networks:
    +
    Channels:
    -{{for data.networks}} - {{if value.has_access}} - {{:helper.link(value.tag, '', {'switch_network' : value.tag}, null, data.current_network == value.tag ? 'selected' : null)}} - {{else}} - {{:helper.link(value.tag, '', {}, null, data.current_network == value.tag ? 'selected' : 'redButton')}} - {{/if}} +{{for data.channels}} + {{:helper.link(value, '', {'switch_channel' : value}, null, data.current_channel == value ? 'selected' : null)}} {{/for}}
    Cameras:
    {{for data.cameras}} {{if data.current_camera && value.name == data.current_camera.name}} - {{:helper.link(value.name, '', {'switch_camera' : value.camera}, 'selected')}} - {{else value.deact}} + {{:helper.link(value.name, '', {'switch_camera' : value.device}, 'selected')}} + {{else value.deactivated}} {{:helper.link(value.name + " (deactivated)", '', {}, 'inactive')}} {{else}} - {{:helper.link(value.name, '', {'switch_camera' : value.camera, 'mapZLevel' : value.z})}} + {{:helper.link(value.name, '', {'switch_camera' : value.device})}} {{/if}} {{/for}} diff --git a/nano/templates/sec_camera_map_content.tmpl b/nano/templates/sec_camera_map_content.tmpl index 2fff6924fe26..0d0cb74eece8 100644 --- a/nano/templates/sec_camera_map_content.tmpl +++ b/nano/templates/sec_camera_map_content.tmpl @@ -6,11 +6,11 @@ Used In File(s): \code\game\machinery\computer\camera.dm {{if value.z == config.mapZLevel}}
    {{if data.current_camera && value.name == data.current_camera.name}} - {{:helper.link("#", '', {'switch_camera' : value.camera}, 'selected')}} + {{:helper.link("#", '', {'switch_camera' : value.tag}, 'selected')}} {{else value.deact}} {{:helper.link('#', '', {}, 'inactive')}} {{else}} - {{:helper.link("#", '', {'switch_camera' : value.camera})}} + {{:helper.link("#", '', {'switch_camera' : value.tag})}} {{/if}}
    {{for config.mapZLevels :zValue:zIndex}} - {{:helper.link(zValue, 'close', {'mapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} + {{:helper.link(zValue, 'close', {'switchMapZLevel' : zValue}, null, config.mapZLevel == zValue ? 'selected' : null)}} {{/for}}
    @@ -36,13 +36,9 @@
    -
    Networks:
    +
    Channels:
    -{{for data.networks}} - {{if value.has_access}} - {{:helper.link(value.tag, '', {'switch_network' : value.tag}, null, data.current_network == value.tag ? 'selected' : null)}} - {{else}} - {{:helper.link(value.tag, '', {}, null, data.current_network == value.tag ? 'selected' : 'redButton')}} - {{/if}} +{{for data.channels}} + {{:helper.link(value.tag, '', {'switch_channel' : value.tag}, null, data.current_channel == value.tag ? 'selected' : null)}} {{/for}} \ No newline at end of file diff --git a/nano/templates/ship_core.tmpl b/nano/templates/ship_core.tmpl new file mode 100644 index 000000000000..13ba2029c563 --- /dev/null +++ b/nano/templates/ship_core.tmpl @@ -0,0 +1,107 @@ +{{if data.network}} +
    +
    + {{:helper.link(data.network, null, { 'settings': 1 }, null)}} +
    +
    +{{/if}} +{{if !data.created_sector && !data.finalized}} +

    Ship Options

    +
    +
    + Ship name: +
    +
    + {{if data.created_sector || data.finalized}} + {{:data.sector_name}} + {{else}} + {{:helper.link(data.sector_name ? data.sector_name : 'No name!', 'pencil', {'change_sector_name' : '1'}, null , null)}} + {{/if}} +
    +
    +
    +
    + Ship Color: +
    +
    + {{:helper.link('Change color', 'pencil', { 'change_color' : 1})}} +
    +
    +
    +
    + Ship Class: +
    +
    + {{:helper.link(data.should_launch ? 'Non-landable' : 'Landable', null, { 'should_launch' : 1}, null, null)}} +
    +
    +
    +
    + Errors: +
    +
    +
    + {{for data.errors}} + {{:value}}
    + {{/for}} +
    +
    +
    + {{if !data.should_launch}} + Choosing to create a landable ship will create the ship in place. The ship will be able to land in valid areas.
    +
    +
    + Ship Areas: +
    +
    +
    + {{for data.anchored_areas}} + {{:value}}
    + {{/for}} +
    +
    +
    +
    +
    + {{:helper.link('Select Areas', null, {'select_areas' : 1})}} +
    +
    +
    +
    + {{:helper.link('Finalize landable ship', 'arrowthickstop-1-e', {'finalize' : '1'}, null , null)}} +
    +
    + {{:helper.link('Check landable ship validity', 'gear', {'check_errors' : '1'}, null , null)}} +
    +
    + {{else}} + Choosing to create a non-landable ship will launch the ship core into a new registered sector. The ship will not be able to land.
    +
    +
    + {{:helper.link('Launch Ship Core', 'arrowthickstop-1-e', {'launch' : '1'}, null , null)}} +
    +
    + {{:helper.link('Check launching validity', 'gear', {'check_errors' : '1'}, null , null)}} +
    +
    + {{/if}} +{{else}} +
    +
    + Ship name: +
    +
    + {{:data.sector_name}} +
    +
    +
    +
    + Ship class: +
    +
    + {{:data.finalized ? 'Landable' : 'Non-landable'}} +
    +
    +{{/if}} +
    +EXONET Firmware v110.04.4h Copyright EXONETWORKS INC \ No newline at end of file diff --git a/nano/templates/shipcomms.tmpl b/nano/templates/shipcomms.tmpl new file mode 100644 index 000000000000..bc3218449b48 --- /dev/null +++ b/nano/templates/shipcomms.tmpl @@ -0,0 +1,30 @@ +

    Ship Communications

    + +{{if data.allow_ident_change}} + {{if data.ident_enabled}} + {{:helper.link('Disable ident transmitter (conceal comms origin)', 'unlocked', {'toggle_comms_visibility' : 1}, null)}} + {{else}} + {{:helper.link('Enable ident transmitter (show comms origin)', 'locked', {'toggle_comms_visibility' : 1}, null)}} + {{/if}} +{{/if}} + +

    Local Entities

    + +{{for data.entities}} + +{{/for}} +
    {{:value.name}}{{:value.coords}}{{:value.desc}}{{:value.status}}
    + +

    Comms Broadcasters

    + +{{for data.broadcasters}} + +{{/for}} +
    {{:value.name}}{{:value.coords}}{{:value.desc}}
    + +

    Comms Receivers

    + +{{for data.receivers}} + +{{/for}} +
    {{:value.name}}{{:value.coords}}{{:value.desc}}
    \ No newline at end of file diff --git a/nano/templates/shipsensors.tmpl b/nano/templates/shipsensors.tmpl index 73aba7094d3c..ea937dbfd6f4 100644 --- a/nano/templates/shipsensors.tmpl +++ b/nano/templates/shipsensors.tmpl @@ -1,6 +1,6 @@
    - Controls + Controls
    Power @@ -25,9 +25,18 @@ {{:helper.link(data.viewing ? 'Engaged' : 'Disengaged', 'shuffle', { 'viewing' : 1 }, null, data.viewing ? 'selected' : null)}}
    +
    +
    + Contact readout +
    +
    + {{:helper.link(data.muted ? 'Disabled' : 'Enabled', data.muted ? 'volume-off' : 'volume-on', { 'mute' : 1 }, null, null)}} +
    +
    +
    - Status + Status
    Status: @@ -61,14 +70,20 @@
    - Contacts + Contacts {{if data.contacts}} {{for data.contacts}}
    -
    - + + {{/for}} @@ -78,7 +93,7 @@ {{/if}}
    - Scan data + Scan data {{if data.last_scan}} {{:data.last_scan.name}} at {{:data.last_scan.location}} {{:helper.link('Print', 'print' ,{ 'print' : 1 }, null, null)}} diff --git a/nano/templates/shutoff_monitor.tmpl b/nano/templates/shutoff_monitor.tmpl new file mode 100644 index 000000000000..85e07a981b60 --- /dev/null +++ b/nano/templates/shutoff_monitor.tmpl @@ -0,0 +1,18 @@ +

    Automated Shutoff Valve Monitoring Console

    +
    +{{for data.valves}} +
    +
    + {{:value.name}} +
    +
    + + {{:helper.link(value.open ? 'Open' : 'Closed', 'alert')}} + {{:helper.link(value.enable ? 'Enabled' : 'Disabled', 'alert', {'toggle_enable' : value.ref})}} + + + Location: {{:value.location}} + +
    +
    +{{/for}} \ No newline at end of file diff --git a/nano/templates/shuttle_control_console.tmpl b/nano/templates/shuttle_control_console.tmpl index b2893d3280b4..002098421e01 100644 --- a/nano/templates/shuttle_control_console.tmpl +++ b/nano/templates/shuttle_control_console.tmpl @@ -22,6 +22,24 @@ +
    +
    + ETA: +
    +
    + {{if data.shuttle_state == "warmup"}} + CALIBRATING + {{else data.shuttle_state == "in_transit"}} + {{if data.timeleft > 0}} + {{:data.timeleft}} s + {{else}} + IMMINENT + {{/if}} + {{else}} + NONE + {{/if}} +
    +
    {{if data.has_docking}}
    diff --git a/nano/templates/shuttle_control_console_antag.tmpl b/nano/templates/shuttle_control_console_antag.tmpl index d05052e59570..28aa38c82888 100644 --- a/nano/templates/shuttle_control_console_antag.tmpl +++ b/nano/templates/shuttle_control_console_antag.tmpl @@ -1,76 +1,94 @@ -

    Shuttle Status

    -
    -
    - {{:data.shuttle_status}} -
    -
    - Cloaking field is {{ cloaked? "enabled" : "disabled" }}. {{:helper.link('Toggle', 'arrowreturn-1-s', {'toggle_cloaked' : '1'} }} -
    -
    -
    -
    -
    - Drive: -
    -
    - {{if data.shuttle_state == "idle"}} - IDLE - {{else data.shuttle_state == "warmup"}} - SPINNING UP - {{else data.shuttle_state == "in_transit"}} - ENGAGED - {{else}} - ERROR - {{/if}} -
    -
    -
    -{{if data.has_docking}} -
    -
    -
    - Docking Status: -
    -
    - {{if data.docking_status == "docked"}} - DOCKED - {{else data.docking_status == "docking"}} - {{if !data.docking_override}} - DOCKING - {{else}} - DOCKING-MANUAL - {{/if}} - {{else data.docking_status == "undocking"}} - {{if !data.docking_override}} - UNDOCKING - {{else}} - UNDOCKING-MANUAL - {{/if}} - {{else data.docking_status == "undocked"}} - UNDOCKED - {{else}} - ERROR - {{/if}} -
    -
    -
    -{{/if}} -
    -
    - Current Destination: -
    - {{:data.destination_name}} -
    - {{:helper.link('Choose Destination', 'arrowreturn-1-s', {'pick' : '1'}, data.can_pick ? null : 'disabled' , null)}} -
    -
    -

    Shuttle Control

    -
    -
    -
    - {{:helper.link('Launch Shuttle', 'arrowthickstop-1-e', {'move' : '1'}, data.can_launch ? null : 'disabled' , null)}} - {{:helper.link('Cancel Launch', 'cancel', {'cancel' : '1'}, data.can_cancel ? null : 'disabled' , null)}} - {{:helper.link('Force Launch', 'alert', {'force' : '1'}, data.can_force ? null : 'disabled' , data.can_force ? 'redButton' : null)}} -
    -
    +

    Shuttle Status

    +
    +
    + {{:data.shuttle_status}} +
    +
    + Cloaking field is {{ cloaked? "enabled" : "disabled" }}. {{:helper.link('Toggle', 'arrowreturn-1-s', {'toggle_cloaked' : '1'} }} +
    +
    +
    +
    +
    + Drive: +
    +
    + {{if data.shuttle_state == "idle"}} + IDLE + {{else data.shuttle_state == "warmup"}} + SPINNING UP + {{else data.shuttle_state == "in_transit"}} + ENGAGED + {{else}} + ERROR + {{/if}} +
    +
    +
    +
    +
    + ETA: +
    +
    + {{if data.shuttle_state == "warmup"}} + CALIBRATING + {{else data.shuttle_state == "in_transit"}} + {{if data.timeleft > 0}} + {{:data.timeleft}} s + {{else}} + IMMINENT + {{/if}} + {{else}} + NONE + {{/if}} +
    +
    +{{if data.has_docking}} +
    +
    +
    + Docking Status: +
    +
    + {{if data.docking_status == "docked"}} + DOCKED + {{else data.docking_status == "docking"}} + {{if !data.docking_override}} + DOCKING + {{else}} + DOCKING-MANUAL + {{/if}} + {{else data.docking_status == "undocking"}} + {{if !data.docking_override}} + UNDOCKING + {{else}} + UNDOCKING-MANUAL + {{/if}} + {{else data.docking_status == "undocked"}} + UNDOCKED + {{else}} + ERROR + {{/if}} +
    +
    +
    +{{/if}} +
    +
    + Current Destination: +
    + {{:data.destination_name}} +
    + {{:helper.link('Choose Destination', 'arrowreturn-1-s', {'pick' : '1'}, data.can_pick ? null : 'disabled' , null)}} +
    +
    +

    Shuttle Control

    +
    +
    +
    + {{:helper.link('Launch Shuttle', 'arrowthickstop-1-e', {'move' : '1'}, data.can_launch ? null : 'disabled' , null)}} + {{:helper.link('Cancel Launch', 'cancel', {'cancel' : '1'}, data.can_cancel ? null : 'disabled' , null)}} + {{:helper.link('Force Launch', 'alert', {'force' : '1'}, data.can_force ? null : 'disabled' , data.can_force ? 'redButton' : null)}} +
    +
    \ No newline at end of file diff --git a/nano/templates/shuttle_control_console_exploration.tmpl b/nano/templates/shuttle_control_console_exploration.tmpl index cfe11eba211c..d0f6ccc65f7f 100644 --- a/nano/templates/shuttle_control_console_exploration.tmpl +++ b/nano/templates/shuttle_control_console_exploration.tmpl @@ -22,6 +22,24 @@
    +
    +
    + ETA: +
    +
    + {{if data.shuttle_state == "warmup"}} + CALIBRATING + {{else data.shuttle_state == "in_transit"}} + {{if data.timeleft > 0}} + {{:data.timeleft}} s + {{else}} + IMMINENT + {{/if}} + {{else}} + NONE + {{/if}} +
    +
    {{if data.has_docking}}
    @@ -52,6 +70,23 @@
    {{/if}} +
    +
    + Docking Codes: +
    +
    + {{:helper.link(data.docking_codes ? data.docking_codes : 'Not set', null, {'set_codes' : '1'}, null , null)}} +
    +
    +
    +
    + Current Rotation Point: +
    + {{:data.port_name}} +
    + {{:helper.link('Choose Rotation Point', 'arrowreturn-1-s', {'dock_pick' : '1'}, data.can_pick ? null : 'disabled' , null)}} +
    +
    Current Destination: diff --git a/nano/templates/shuttle_control_console_multi.tmpl b/nano/templates/shuttle_control_console_multi.tmpl index 7a93eb983edf..f1de01362def 100644 --- a/nano/templates/shuttle_control_console_multi.tmpl +++ b/nano/templates/shuttle_control_console_multi.tmpl @@ -1,79 +1,97 @@ -

    Shuttle Status

    -
    -
    - {{:data.shuttle_status}} -
    -
    -
    -
    -
    - Drive: -
    -
    - {{if data.shuttle_state == "idle"}} - IDLE - {{else data.shuttle_state == "warmup"}} - SPINNING UP - {{else data.shuttle_state == "in_transit"}} - ENGAGED - {{else}} - ERROR - {{/if}} -
    -
    -
    -{{if data.has_docking}} -
    -
    -
    - Docking Status: -
    -
    - {{if data.docking_status == "docked"}} - DOCKED - {{else data.docking_status == "docking"}} - {{if !data.docking_override}} - DOCKING - {{else}} - DOCKING-MANUAL - {{/if}} - {{else data.docking_status == "undocking"}} - {{if !data.docking_override}} - UNDOCKING - {{else}} - UNDOCKING-MANUAL - {{/if}} - {{else data.docking_status == "undocked"}} - UNDOCKED - {{else}} - ERROR - {{/if}} -
    -
    - Docking Codes: -
    -
    - {{:helper.link(data.docking_codes ? data.docking_codes : 'Not set', null, {'set_codes' : '1'}, null , null)}} -
    -
    -
    -{{/if}} -
    -
    - Current Destination: -
    - {{:data.destination_name}} -
    - {{:helper.link('Choose Destination', 'arrowreturn-1-s', {'pick' : '1'}, data.can_pick ? null : 'disabled' , null)}} -
    -
    -

    Shuttle Control

    -
    -
    -
    - {{:helper.link('Launch Shuttle', 'arrowthickstop-1-e', {'move' : '1'}, data.can_launch ? null : 'disabled' , null)}} - {{:helper.link('Cancel Launch', 'cancel', {'cancel' : '1'}, data.can_cancel ? null : 'disabled' , null)}} - {{:helper.link('Force Launch', 'alert', {'force' : '1'}, data.can_force ? null : 'disabled' , data.can_force ? 'redButton' : null)}} -
    -
    +

    Shuttle Status

    +
    +
    + {{:data.shuttle_status}} +
    +
    +
    +
    +
    + Drive: +
    +
    + {{if data.shuttle_state == "idle"}} + IDLE + {{else data.shuttle_state == "warmup"}} + SPINNING UP + {{else data.shuttle_state == "in_transit"}} + ENGAGED + {{else}} + ERROR + {{/if}} +
    +
    +
    +
    +
    + ETA: +
    +
    + {{if data.shuttle_state == "warmup"}} + CALIBRATING + {{else data.shuttle_state == "in_transit"}} + {{if data.timeleft > 0}} + {{:data.timeleft}} s + {{else}} + IMMINENT + {{/if}} + {{else}} + NONE + {{/if}} +
    +
    +{{if data.has_docking}} +
    +
    +
    + Docking Status: +
    +
    + {{if data.docking_status == "docked"}} + DOCKED + {{else data.docking_status == "docking"}} + {{if !data.docking_override}} + DOCKING + {{else}} + DOCKING-MANUAL + {{/if}} + {{else data.docking_status == "undocking"}} + {{if !data.docking_override}} + UNDOCKING + {{else}} + UNDOCKING-MANUAL + {{/if}} + {{else data.docking_status == "undocked"}} + UNDOCKED + {{else}} + ERROR + {{/if}} +
    +
    + Docking Codes: +
    +
    + {{:helper.link(data.docking_codes ? data.docking_codes : 'Not set', null, {'set_codes' : '1'}, null , null)}} +
    +
    +
    +{{/if}} +
    +
    + Current Destination: +
    + {{:data.destination_name}} +
    + {{:helper.link('Choose Destination', 'arrowreturn-1-s', {'pick' : '1'}, data.can_pick ? null : 'disabled' , null)}} +
    +
    +

    Shuttle Control

    +
    +
    +
    + {{:helper.link('Launch Shuttle', 'arrowthickstop-1-e', {'move' : '1'}, data.can_launch ? null : 'disabled' , null)}} + {{:helper.link('Cancel Launch', 'cancel', {'cancel' : '1'}, data.can_cancel ? null : 'disabled' , null)}} + {{:helper.link('Force Launch', 'alert', {'force' : '1'}, data.can_force ? null : 'disabled' , data.can_force ? 'redButton' : null)}} +
    +
    \ No newline at end of file diff --git a/nano/templates/sleeper.tmpl b/nano/templates/sleeper.tmpl index 122ca1a3521d..0c9ab51c2891 100644 --- a/nano/templates/sleeper.tmpl +++ b/nano/templates/sleeper.tmpl @@ -22,6 +22,9 @@
    {{:helper.link(data.pump ? "Stomach pump active" : "Stomach pump inactive", null, {'pump' : !data.pump})}}
    +
    + {{:helper.link(data.lavage ? "Lung lavage active" : "Lung lavage inactive", null, {'lavage' : !data.lavage})}} +
    {{else}} There are a few buttons here, but the labels don't make any sense to you. {{/if}} diff --git a/nano/templates/song_editor.tmpl b/nano/templates/song_editor.tmpl index 56618b947e82..3ac2b19b17ef 100644 --- a/nano/templates/song_editor.tmpl +++ b/nano/templates/song_editor.tmpl @@ -7,7 +7,7 @@ By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.
    Example: C,D,E,F,G,A,B will play a C major scale.
    After a note has an accidental placed, it will be remembered: C,C4,C,C3 is C3,C4,C4,C3
    - Chords can be played simply by seperating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B
    + Chords can be played simply by separating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B
    A pause may be denoted by an empty chord: C,E,,C,G
    To make a chord be a different time, end it with /x, where the chord length will be length
    defined by tempo / x: C,G/2,E/4
    diff --git a/nano/templates/space_heater.tmpl b/nano/templates/space_heater.tmpl new file mode 100644 index 000000000000..0b6c683380c0 --- /dev/null +++ b/nano/templates/space_heater.tmpl @@ -0,0 +1,21 @@ + +
    +
    Power
    +
    + {{if data.has_cell == 0}} + None + {{else}} + Battery ({{:data.cell_percent}}%) + {{/if}} +
    +
    +
    +
    Temperature
    +
    + {{:helper.link('--', '', {'adj_temp' : -5})}} + {{:helper.link('-', '', {'adj_temp' : -1})}} +
    {{:data.set_temperature}}K ({{:data.set_temperature - 273.15}}°C)
    + {{:helper.link('+', '', {'adj_temp' : 1})}} + {{:helper.link('++', '', {'adj_temp' : 5})}} +
    +
    \ No newline at end of file diff --git a/nano/templates/stellar_anchor.tmpl b/nano/templates/stellar_anchor.tmpl new file mode 100644 index 000000000000..40949c208d45 --- /dev/null +++ b/nano/templates/stellar_anchor.tmpl @@ -0,0 +1,86 @@ +{{if data.network}} +
    +
    + {{:helper.link(data.network, null, { 'settings': 1 }, null)}} +
    +
    +{{/if}} +{{if !data.created_sector}} +
    +
    + Set to Launch: +
    +
    + {{:helper.link(data.should_launch ? 'Enabled' : 'Disabled', null, {'should_launch' : 1}, null, null)}} +
    +
    +
    +
    +
    + Errors: +
    +
    + {{for data.errors}} + {{:value}}
    + {{/for}} +
    +
    +
    + {{if !data.should_launch}} +
    +
    + Anchored Areas: +
    +
    +
    + {{for data.anchored_areas}} + {{:value}}
    + {{/for}} +
    +
    +
    +
    +
    + {{:helper.link('Select Areas', null, {'select_areas' : 1})}} +
    +
    + {{else}} +

    Launch Options

    + Launching the stellar anchor will create a registered sector in space, allowing a larger area to be anchored.
    +
    +
    + Sector name: +
    +
    + {{:helper.link(data.sector_name ? data.sector_name : 'No name!', 'pencil', {'change_sector_name' : '1'}, null , null)}} +
    +
    +
    +
    + Sector Color: +
    +
    + {{:helper.link('Change color', 'pencil', { 'change_color' : 1})}} +
    +
    +
    +
    + {{:helper.link('Launch stellar anchor', 'arrowthickstop-1-e', {'launch' : '1'}, null , null)}} +
    +
    + {{:helper.link('Check launching validity', 'gear', {'check_errors' : '1'}, null , null)}} +
    +
    + {{/if}} +{{else}} +
    +
    + Sector name: +
    +
    + {{:data.sector_name}} +
    +
    +{{/if}} +
    +EXONET Firmware v110.04.4h Copyright EXONETWORKS INC \ No newline at end of file diff --git a/nano/templates/stock_parts_printer.tmpl b/nano/templates/stock_parts_printer.tmpl new file mode 100644 index 000000000000..1556edea12fa --- /dev/null +++ b/nano/templates/stock_parts_printer.tmpl @@ -0,0 +1,34 @@ + +

    Printer Status

    +
    {{:helper.link('Scan', 'search' ,{ 'scan' : value.ref }, null, null)}}{{:value.name}}, bearing {{:value.bearing}} + {{if value.scannable}} + {{:helper.link('Scan', 'search', { 'scan' : value.ref }, null, null)}} + {{else}} + {{:helper.link('Unidentified', null, null, 'disabled')}} + {{/if}} + {{:value.name}}, bearing {{:value.bearing}}{{:value.variability ? (" +/- " + value.variability + " degrees") : ""}}{{:value.progress ? (", tracing " + value.progress + "% complete") : ""}}
    + + + + + + + + + {{if data.show_print_ctrl}} + + + + + {{/if}} +
    Toner{{:helper.displayBar(data.toner, 0, data.toner_max, (data.toner >= (data.toner_max/2)) ? null : ((data.toner >= (data.toner_max/3)) ? 'average' : 'bad'))}} {{:data.toner <= 0? '' : ""}}{{:data.toner? helper.round((data.toner * 100)/data.toner_max) : 0}}%{{:data.toner <= 0? '' : ""}}
    Paper Feeder + {{if data.paper_feeder <= 0}} + + {{else}} + + {{/if}} + {{:data.paper_feeder}} / {{:data.paper_feeder_max}} sheet(s) + +
    Queue + {{if data.print_queue_amt > 0 && !data.is_printing}} + {{:helper.link("Resume Printing", null, {"resume_print":1} ) }} + {{else data.is_printing}} + {{:helper.link("Stop Printing", null, {"stop_print":1} ) }} + {{else}} + Nothing queued for printing. + {{/if}} +
    diff --git a/nano/templates/supply.tmpl b/nano/templates/supply.tmpl index d038d3d527ea..c7829a5c966b 100644 --- a/nano/templates/supply.tmpl +++ b/nano/templates/supply.tmpl @@ -128,7 +128,7 @@
    {{else data.screen == 4}} {{if data.is_admin}} - {{if data.is_NTOS}} + {{if data.is_OS}}
    Notifications are: diff --git a/nano/templates/telecomms_hub.tmpl b/nano/templates/telecomms_hub.tmpl new file mode 100644 index 000000000000..03f9cceda024 --- /dev/null +++ b/nano/templates/telecomms_hub.tmpl @@ -0,0 +1,43 @@ +
    +
    Network:
    +
    {{:helper.link(data.network_id, null, { 'settings': 1 }, null)}} +
    + +
    + + + + + + + + +{{for data.channels}} + +
    +
    + +
    +
    + + + + + + + +{{/for}} +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    Channel nameEncryptionKeyColorFreq
    {{:helper.link(value.channel_name, null, { 'channel' : value.channel_ref, 'change_name' : 1 }, null)}}{{:helper.link(value.channel_access, null, { 'channel' : value.channel_ref, 'change_access' : 1 }, null)}}{{:helper.link(value.channel_key, null, { 'channel' : value.channel_ref, 'change_key' : 1 }, null)}} 
        
     
    {{:helper.link("Change", null, { 'channel' : value.channel_ref, 'change_colour' : 1 }, null)}}{{:helper.link(value.channel_freq, null, { 'channel' : value.channel_ref, 'change_freq' : 1 }, null)}}{{:helper.link("Remove", null, { 'channel' : value.channel_ref, 'delete_channel' : 1 }, null)}}
    Configuration options
    {{:helper.link("New channel", null, { 'new_channel' : 1 }, null)}}
    {{:helper.link("Factory reset", null, { 'factory_reset' : 1 }, null)}}
    {{:helper.link(data.allow_external ? 'Disable external signals' : 'Enable external signals', null, { 'toggle_external' : 1 }, null)}}
    +
    diff --git a/nano/templates/turret.tmpl b/nano/templates/turret.tmpl new file mode 100644 index 000000000000..a2f2d4ab0e8c --- /dev/null +++ b/nano/templates/turret.tmpl @@ -0,0 +1,88 @@ +
    + {{if data.network}} +
    +
    {{:helper.link("Network Settings", null, { "settings" : 1 })}}
    +
    +
    + {{/if}} +

    Power System

    +
    +
    + Power: +
    +
    + {{:helper.link('On', 'power', {'set_enabled' : 1}, data.enabled ? 'selected' : null)}} + {{:helper.link('Off', 'close', {'set_enabled' : 0}, data.enabled ? null : 'selected')}} +
    +
    +

    Weapon System

    +
    +
    + Installed Weapon: +
    +
    + {{if data.weaponName == null}} +
    + No weapon detected! +
    + {{else}} + {{:helper.link(data.weaponName, 'alert', {'eject_gun' : 1})}} + {{/if}} +
    +
    + {{if data.firemodes}} +
    +
    + Fire modes: +
    +
    + {{for data.firemodes}} + {{:helper.link(value.name, null, {'switch_firemode' : value.index}, value.selected ? 'selected' : null)}} + {{/for}} +
    +
    + {{/if}} +

    Targeting Settings

    + {{for data.settings}} +
    +
    + {{:value.category}} +
    +
    + {{:helper.link('On', null, {'targeting_comm' : value.setting, 'targeting_value' : 1}, value.value ? 'selected' : null)}} + {{:helper.link('Off',null, {'targeting_comm' : value.setting, 'targeting_value' : 0}, !value.value ? 'selected' : null)}} +
    +
    + {{/for}} +

    Manual Control

    +
    +
    + Bearing: +
    +
    + {{:helper.link('-10°', 'triangle-1-w', {'adjust_bearing' : -10})}} + {{:helper.link('-5°', 'triangle-1-w', {'adjust_bearing' : -5})}} + {{:helper.link(data.currentBearing+'°', null, {'set_bearing' : 1})}} + {{:helper.link('+5°', 'triangle-1-e', {'adjust_bearing' : 5})}} + {{:helper.link('+10°', 'triangle-1-e', {'adjust_bearing' : 10})}} +
    +
    +
    +
    + Default Bearing: +
    +
    + {{:helper.link(data.defaultBearing+'°', null, {'set_default' : 1})}} +
    +
    +
    +
    + Control: +
    +
    + {{:helper.link('Manual Fire', 'alert', {'manual_fire' : 1}, null, data.weaponName ? 'redButton' : 'disabled')}} +
    +
    +
    + + diff --git a/nano/templates/turret_control.tmpl b/nano/templates/turret_control.tmpl index a529bcbb108f..944f4a73d3fe 100644 --- a/nano/templates/turret_control.tmpl +++ b/nano/templates/turret_control.tmpl @@ -1,41 +1,41 @@ -
    -
    - Behaviour controls are {{:data.locked ? "locked" : "unlocked"}}. -
    -
    -
    -{{if data.access}} -
    -
    - Turret Status: -
    -
    - {{:helper.link('Enabled', null, {'command' : 'enable', 'value' : 1}, data.enabled ?'redButton' : null)}} - {{:helper.link('Disabled',null, {'command' : 'enable', 'value' : 0}, !data.enabled ? 'selected' : null)}} -
    -
    - - {{if data.is_lethal}} -
    -
    - Lethal Mode: -
    -
    - {{:helper.link('On', null, {'command' : 'lethal', 'value' : 1}, data.lethal ?'redButton' : null)}} - {{:helper.link('Off',null, {'command' : 'lethal', 'value' : 0}, !data.lethal ? 'selected' : null)}} -
    -
    - {{/if}} - - {{for data.settings}} -
    -
    - {{:value.category}} -
    -
    - {{:helper.link('On', null, {'command' : value.setting, 'value' : 1}, value.value ? 'selected' : null)}} - {{:helper.link('Off',null, {'command' : value.setting, 'value' : 0}, !value.value ? 'selected' : null)}} -
    -
    - {{/for}} -{{/if}} +
    +
    + Behaviour controls are {{:data.locked ? "locked" : "unlocked"}}. +
    +
    +
    +{{if data.access}} +
    +
    + Turret Status: +
    +
    + {{:helper.link('Enabled', null, {'command' : 'enable', 'value' : 1}, data.enabled ?'redButton' : null)}} + {{:helper.link('Disabled',null, {'command' : 'enable', 'value' : 0}, !data.enabled ? 'selected' : null)}} +
    +
    + + {{if data.is_lethal}} +
    +
    + Lethal Mode: +
    +
    + {{:helper.link('On', null, {'command' : 'lethal', 'value' : 1}, data.lethal ?'redButton' : null)}} + {{:helper.link('Off',null, {'command' : 'lethal', 'value' : 0}, !data.lethal ? 'selected' : null)}} +
    +
    + {{/if}} + + {{for data.settings}} +
    +
    + {{:value.category}} +
    +
    + {{:helper.link('On', null, {'command' : value.setting, 'value' : 1}, value.value ? 'selected' : null)}} + {{:helper.link('Off',null, {'command' : value.setting, 'value' : 0}, !value.value ? 'selected' : null)}} +
    +
    + {{/for}} +{{/if}} diff --git a/nano/templates/turret_program.tmpl b/nano/templates/turret_program.tmpl new file mode 100644 index 000000000000..f308ce54530a --- /dev/null +++ b/nano/templates/turret_program.tmpl @@ -0,0 +1,14 @@ +{{for data.area_turrets}} +

    {{:value.area_name}}:

    + + + {{for value.turrets :turretValue:turretIndex}} + + + + + {{/for}} +
    TurretStatusLogs
    {{:helper.link(turretValue.tag, '', {'settings' : 1, 'turret' : turretValue.tag})}}{{:turretValue.enabled ? 'ENABLED' : 'DISABLED'}}{{:helper.link('LOGS', '', {'logs' : 1, 'turret' : turretValue.tag})}}
    +{{empty}} + No turrets located on the network. You may lack the required access. +{{/for}} \ No newline at end of file diff --git a/nano/templates/uplink.tmpl b/nano/templates/uplink.tmpl index c01d79dc9a30..ce47818e2af9 100644 --- a/nano/templates/uplink.tmpl +++ b/nano/templates/uplink.tmpl @@ -1,89 +1,89 @@ - - -{{:helper.syndicateMode()}} -

    {{:data.welcome}}

    -
    -
    -
    - Functions: -
    -
    - {{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}} - {{:helper.link('Exploitable Information', 'gear', {'menu' : 2}, null, 'fixedLeftWider')}} - {{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}} - {{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}} -
    -
    -
    - -{{if data.menu == 0 || data.menu == 1}} -
    -
    - Telecrystals: -
    -
    - {{:data.crystals}} -
    -
    - - {{if data.discount_amount < 100}} -
    -
    - Currently discounted: -
    -
    - {{:data.discount_category}}
    {{:data.discount_name}}
    {{:data.discount_amount}}% off. Offer will expire at: {{:data.offer_expiry}} -
    -
    - {{/if}} -{{/if}} - -{{if data.menu == 0}} -

    Categories:

    - {{for data.categories}} -
    - {{:helper.link(value.name, 'gear', {'menu' : 1, 'category' : value.ref})}} -
    - {{/for}} -{{else data.menu == 1}} -

    Request items:

    - Each item costs a number of tele-crystals as indicated by the number following their name. - - {{for data.items}} -
    - {{:helper.link(value.name, 'gear', {'buy_item' : value.ref}, value.can_buy ? null : 'disabled')}} - {{:value.cost}} -
    -
    - {{:value.description}} -
    - {{/for}} -{{else data.menu == 2}} -

    Information Record List:

    -
    -
    - Select a Record -
    -
    - {{for data.exploit_records}} -
    - {{:helper.link(value.Name, value.exploit ? 'gear' : 'document', {'menu' : 21, 'id' : value.id}, null, value.exploit ? 'redButton' : null)}} -
    - {{/for}} -{{else data.menu == 21}} -

    Information Record:

    -
    -
    -
    -
    - {{if data.exploit_exists == 1}} - {{for data.exploit.fields}} - {{:value.name}}: {{:value.value}}
    - {{/for}} - {{/if}} -
    -
    -
    -{{/if}} + + +{{:helper.syndicateMode()}} +

    {{:data.welcome}}

    +
    +
    +
    + Functions: +
    +
    + {{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}} + {{:helper.link('Exploitable Information', 'gear', {'menu' : 2}, null, 'fixedLeftWider')}} + {{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}} + {{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}} +
    +
    +
    + +{{if data.menu == 0 || data.menu == 1}} +
    +
    + Telecrystals: +
    +
    + {{:data.crystals}} +
    +
    + + {{if data.discount_amount < 100}} +
    +
    + Currently discounted: +
    +
    + {{:data.discount_category}}
    {{:data.discount_name}}
    {{:data.discount_amount}}% off. Offer will expire at: {{:data.offer_expiry}} +
    +
    + {{/if}} +{{/if}} + +{{if data.menu == 0}} +

    Categories:

    + {{for data.categories}} +
    + {{:helper.link(value.name, 'gear', {'menu' : 1, 'category' : value.ref})}} +
    + {{/for}} +{{else data.menu == 1}} +

    Request items:

    + Each item costs a number of tele-crystals as indicated by the number following their name. + + {{for data.items}} +
    + {{:helper.link(value.name, 'gear', {'buy_item' : value.ref}, value.can_buy ? null : 'disabled')}} - {{:value.cost}} +
    +
    + {{:value.description}} +
    + {{/for}} +{{else data.menu == 2}} +

    Information Record List:

    +
    +
    + Select a Record +
    +
    + {{for data.exploit_records}} +
    + {{:helper.link(value.Name, value.exploit ? 'gear' : 'document', {'menu' : 21, 'id' : value.id}, null, value.exploit ? 'redButton' : null)}} +
    + {{/for}} +{{else data.menu == 21}} +

    Information Record:

    +
    +
    +
    +
    + {{if data.exploit_exists == 1}} + {{for data.exploit.fields}} + {{:value.name}}: {{:value.value}}
    + {{/for}} + {{/if}} +
    +
    +
    +{{/if}} diff --git a/nano/templates/vending_machine.tmpl b/nano/templates/vending_machine.tmpl index 93d5c1007c9e..1ad377f1a0cf 100644 --- a/nano/templates/vending_machine.tmpl +++ b/nano/templates/vending_machine.tmpl @@ -4,53 +4,62 @@ --> {{if data.mode == 0}} -

    Items available

    -
    - {{for data.products}} +

    Products available

    -
    - {{if value.price > 0}} - {{:helper.link('Buy (' + value.price + ')', 'cart', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} + {{for data.products}} +
    +
    + {{if value.color}} + + {{:value.name}} + {{else}} - {{:helper.link('Vend', 'circle-arrow-s', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} + {{:value.name}} {{/if}}
    -
    - {{if value.color}}{{:value.name}} - {{else}}{{:value.name}} - {{/if}} - ({{:value.amount ? value.amount : "NONE LEFT"}}) +
    + {{:value.amount}} in stock + + {{if value.price_num > 0}} + {{:helper.link('Buy', 'cart', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} + {{else}} + {{:helper.link('Vend', 'circle-arrow-s', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} + {{/if}} + +
    + {{empty}} + No products available! + {{/for}}
    - {{empty}} - No items available! - {{/for}} -
    {{if data.coin}} -

    Coin

    -
    -
    Coin deposited:
    -
    {{:helper.link(data.coin, 'eject', {'remove_coin' : 1})}}
    -
    +

    Coin

    +
    +
    Coin deposited:
    +
    {{:helper.link(data.coin, 'eject', {'remove_coin' : 1})}}
    +
    {{/if}} {{else data.mode == 1}} -

    Item selected

    -
    +

    Item selected

    -
    Item selected:
    {{:data.product}}
    -
    Charge:
    {{:data.price}}
    -
    -
    - {{if data.message_err}} {{/if}} {{:data.message}} +
    +
    Item selected:
    {{:data.product}}
    +
    Charge:
    {{:data.price}}
    +
    +
    + {{if data.message_err}} + + {{/if}} + {{:data.message}} +
    +
    + {{:helper.link('Cancel', 'arrowreturn-1-w', {'cancelpurchase' : 1})}} +
    +{{/if}} +{{if data.panel}} +

    Maintenance panel

    - {{:helper.link('Cancel', 'arrowreturn-1-w', {'cancelpurchase' : 1})}} +
    Speaker
    {{:helper.link(data.speaker ? 'Enabled' : 'Disabled', 'gear', {'togglevoice' : 1})}}
    -
    {{/if}} -{{if data.panel}} -

    Maintenance panel

    -
    -
    Speaker
    {{:helper.link(data.speaker ? 'Enabled' : 'Disabled', 'gear', {'togglevoice' : 1})}}
    -
    -{{/if}} \ No newline at end of file diff --git a/nano/templates/word_processor.tmpl b/nano/templates/word_processor.tmpl index 0a786f4973e8..433e6afce513 100644 --- a/nano/templates/word_processor.tmpl +++ b/nano/templates/word_processor.tmpl @@ -1,38 +1,13 @@ {{if data.error}} -

    An error has occurred:

    -Additional information: {{:data.error}}
    -Please try again. If the problem persists, contact your system administrator for assistance. -{{:helper.link('Back to menu', null, { "PRG_backtomenu" : 1 })}} -{{else}} -{{if data.browsing}} - {{:helper.link('BACK TO EDITOR', null, { "PRG_closebrowser" : 1 })}} -

    Available documents (local):

    - -
    Name - Size (GQ) - {{for data.files}} -
    {{:value.name}} - {{:value.size}}GQ - {{:helper.link('OPEN', null, { "PRG_openfile" : value.name })}} - {{/for}} -
    - {{if data.usbconnected}} -

    Available documents (portable device):

    - -
    Name - Size (GQ) - {{for data.usbfiles}} -
    {{:value.name}} - {{:value.size}}GQ - {{:helper.link('OPEN', null, { "PRG_openfile" : value.name })}} - {{/for}} -
    - {{/if}} +

    An error has occurred:

    + Additional information: {{:data.error}}
    + Please try again. If the problem persists, contact your system administrator for assistance. + {{:helper.link('Back to menu', null, { "PRG_backtomenu" : 1 })}} {{else}}

    Document: {{:data.filename}}

    {{:helper.link('NEW', null, { "PRG_newfile" : 1 })}} - {{:helper.link('LOAD', null, { "PRG_loadmenu" : 1 })}} + {{:helper.link('LOAD', null, { "PRG_openfile" : 1 })}} {{:helper.link('SAVE', null, { "PRG_savefile" : 1 })}} {{:helper.link('SAVE AS', null, { "PRG_saveasfile" : 1 })}}
    @@ -43,7 +18,11 @@ Additional information: {{:data.error}}
    {{:helper.link('PRINT', null, { "PRG_printfile" : 1 })}}

    + {{if data.filedata}} {{:data.filedata}} + {{else}} + No file data! + {{/if}}
    {{/if}} -{{/if}} + diff --git a/nebula.dme b/nebula.dme index 8e44ae02ea5d..34f8a2ff2835 100644 --- a/nebula.dme +++ b/nebula.dme @@ -1,6 +1,6 @@ // DM Environment file for nebula.dme. // All manual changes should be made outside the BEGIN_ and END_ blocks. - // New source code should be placed in .dm files: choose File/New --> Code File. +// New source code should be placed in .dm files: choose File/New --> Code File. // BEGIN_INTERNALS // END_INTERNALS // BEGIN_FILE_DIR @@ -10,104 +10,136 @@ #define DEBUG // END_PREFERENCES // BEGIN_INCLUDE +#include "code\___compile_options.dm" +#include "code\___opendream_linting.dm" +#include "code\__globals.dm" #include "code\_macros.dm" #include "code\client_macros.dm" #include "code\hub.dm" -#include "code\stylesheet.dm" #include "code\world.dm" -#include "code\__datastructures\globals.dm" -#include "code\__datastructures\priority_queue.dm" -#include "code\__datastructures\stack.dm" -#include "code\__defines\_compile_options.dm" +#include "code\__defines\_byond_version_compat.dm" +#include "code\__defines\_compile_helpers.dm" #include "code\__defines\_planes+layers.dm" #include "code\__defines\_tick.dm" #include "code\__defines\admin.dm" -#include "code\__defines\antagonists.dm" +#include "code\__defines\ai.dm" +#include "code\__defines\ambience.dm" #include "code\__defines\ao.dm" #include "code\__defines\ao_misc.dm" #include "code\__defines\appearance.dm" #include "code\__defines\armor.dm" #include "code\__defines\atmos.dm" #include "code\__defines\atmospherics.dm" +#include "code\__defines\backgrounds.dm" +#include "code\__defines\bodytype.dm" #include "code\__defines\callback.dm" #include "code\__defines\chemistry.dm" #include "code\__defines\client.dm" #include "code\__defines\colors.dm" #include "code\__defines\computers.dm" -#include "code\__defines\culture.dm" +#include "code\__defines\cooking.dm" +#include "code\__defines\credits.dm" +#include "code\__defines\damage.dm" #include "code\__defines\damage_organs.dm" -#include "code\__defines\deity.dm" +#include "code\__defines\definition_helpers.dm" #include "code\__defines\directions.dm" -#include "code\__defines\dna.dm" +#include "code\__defines\dview.dm" #include "code\__defines\feedback.dm" +#include "code\__defines\fires.dm" #include "code\__defines\flags.dm" #include "code\__defines\fluids.dm" #include "code\__defines\gamemode.dm" +#include "code\__defines\genetics.dm" #include "code\__defines\guns.dm" +#include "code\__defines\holomap.dm" +#include "code\__defines\hud.dm" #include "code\__defines\hydroponics.dm" -#include "code\__defines\integrated_circuits.dm" +#include "code\__defines\intent.dm" +#include "code\__defines\interactions.dm" #include "code\__defines\inventory_sizes.dm" +#include "code\__defines\item_effects.dm" #include "code\__defines\items_clothing.dm" #include "code\__defines\jobs.dm" #include "code\__defines\languages.dm" +#include "code\__defines\level_data.dm" #include "code\__defines\lighting.dm" #include "code\__defines\lists.dm" #include "code\__defines\machinery.dm" +#include "code\__defines\machinery_public_vars.dm" #include "code\__defines\mapping.dm" #include "code\__defines\materials.dm" #include "code\__defines\math_physics.dm" +#include "code\__defines\maths.dm" #include "code\__defines\MC.dm" +#include "code\__defines\mech.dm" #include "code\__defines\misc.dm" +#include "code\__defines\mob_status.dm" #include "code\__defines\mobs.dm" #include "code\__defines\movement.dm" +#include "code\__defines\observ.dm" +#include "code\__defines\organs.dm" #include "code\__defines\overmap.dm" +#include "code\__defines\paperwork.dm" +#include "code\__defines\persistence.dm" +#include "code\__defines\power.dm" #include "code\__defines\proc_presets.dm" #include "code\__defines\qdel.dm" +#include "code\__defines\radio.dm" +#include "code\__defines\reactions.dm" +#include "code\__defines\reagent_data_fields.dm" #include "code\__defines\research.dm" -#include "code\__defines\ruin_tags.dm" +#include "code\__defines\serde.dm" #include "code\__defines\shields.dm" #include "code\__defines\shuttle.dm" #include "code\__defines\skills.dm" #include "code\__defines\sound.dm" #include "code\__defines\spaceman_dmm.dm" +#include "code\__defines\spawn.dm" #include "code\__defines\species.dm" +#include "code\__defines\status.dm" +#include "code\__defines\stress.dm" +#include "code\__defines\structures.dm" #include "code\__defines\subsystem-priority.dm" #include "code\__defines\subsystems.dm" #include "code\__defines\targeting.dm" #include "code\__defines\temperature.dm" +#include "code\__defines\template_tags.dm" #include "code\__defines\time.dm" +#include "code\__defines\tools.dm" #include "code\__defines\topic.dm" +#include "code\__defines\traits.dm" #include "code\__defines\turfs.dm" +#include "code\__defines\unit_tests.dm" #include "code\__defines\webhooks.dm" #include "code\__defines\xenoarcheaology.dm" #include "code\__defines\ZAS.dm" #include "code\__defines\zmimic.dm" +#include "code\_global_vars\client.dm" #include "code\_global_vars\configuration.dm" #include "code\_global_vars\logging.dm" -#include "code\_global_vars\mapping.dm" -#include "code\_global_vars\misc.dm" #include "code\_global_vars\mobs.dm" -#include "code\_global_vars\radio.dm" #include "code\_global_vars\sensitive.dm" #include "code\_global_vars\sound.dm" +#include "code\_global_vars\lists\clothing.dm" #include "code\_global_vars\lists\flavor.dm" -#include "code\_global_vars\lists\locations.dm" +#include "code\_global_vars\lists\jewellery.dm" #include "code\_global_vars\lists\logs.dm" #include "code\_global_vars\lists\mapping.dm" #include "code\_global_vars\lists\names.dm" #include "code\_global_vars\lists\objects.dm" -#include "code\_global_vars\lists\times.dm" #include "code\_helpers\_global_objects.dm" #include "code\_helpers\animations.dm" #include "code\_helpers\areas.dm" #include "code\_helpers\atmospherics.dm" #include "code\_helpers\atom_movables.dm" +#include "code\_helpers\auxtools.dm" #include "code\_helpers\builtin_proc_callers.dm" #include "code\_helpers\cmp.dm" -#include "code\_helpers\dview.dm" +#include "code\_helpers\emissive.dm" #include "code\_helpers\files.dm" #include "code\_helpers\functional.dm" #include "code\_helpers\game.dm" +#include "code\_helpers\gauss.dm" #include "code\_helpers\global_lists.dm" #include "code\_helpers\icons.dm" #include "code\_helpers\lists.dm" @@ -117,18 +149,23 @@ #include "code\_helpers\medical_scans.dm" #include "code\_helpers\mobs.dm" #include "code\_helpers\names.dm" +#include "code\_helpers\overmap.dm" +#include "code\_helpers\profiling.dm" +#include "code\_helpers\radio.dm" #include "code\_helpers\sanitize_values.dm" -#include "code\_helpers\spawn_sync.dm" +#include "code\_helpers\serde.dm" #include "code\_helpers\storage.dm" #include "code\_helpers\text.dm" #include "code\_helpers\time.dm" -#include "code\_helpers\tools.dm" #include "code\_helpers\turfs.dm" #include "code\_helpers\type2type.dm" +#include "code\_helpers\types.dm" #include "code\_helpers\unsorted.dm" -#include "code\_helpers\vector.dm" #include "code\_helpers\view.dm" +#include "code\_helpers\visual_filters.dm" #include "code\_helpers\washing.dm" +#include "code\_helpers\datastructures\priority_queue.dm" +#include "code\_helpers\datastructures\stack.dm" #include "code\_helpers\sorts\__main.dm" #include "code\_helpers\sorts\TimSort.dm" #include "code\_onclick\adjacent.dm" @@ -143,33 +180,82 @@ #include "code\_onclick\other_mobs.dm" #include "code\_onclick\rig.dm" #include "code\_onclick\hud\_defines.dm" -#include "code\_onclick\hud\ability_screen_objects.dm" #include "code\_onclick\hud\action.dm" -#include "code\_onclick\hud\ai.dm" -#include "code\_onclick\hud\ai_screen_objects.dm" -#include "code\_onclick\hud\animal.dm" -#include "code\_onclick\hud\deity.dm" #include "code\_onclick\hud\fullscreen.dm" #include "code\_onclick\hud\global_hud.dm" -#include "code\_onclick\hud\gun_mode.dm" -#include "code\_onclick\hud\hud.dm" -#include "code\_onclick\hud\human.dm" -#include "code\_onclick\hud\movable_screen_objects.dm" -#include "code\_onclick\hud\other_mobs.dm" #include "code\_onclick\hud\radial.dm" #include "code\_onclick\hud\radial_persistent.dm" -#include "code\_onclick\hud\robot.dm" -#include "code\_onclick\hud\screen_objects.dm" #include "code\_onclick\hud\skybox.dm" +#include "code\_onclick\hud\hud_elements\_hud_element.dm" +#include "code\_onclick\hud\hud_elements\hud_auxilliary.dm" +#include "code\_onclick\hud\hud_elements\hud_health.dm" +#include "code\_onclick\hud\hud_elements\hud_permanent.dm" +#include "code\_onclick\hud\hud_elements\hud_robot.dm" +#include "code\_onclick\hud\hud_elements\hud_stubs.dm" +#include "code\_onclick\hud\hud_elements\hud_warnings.dm" +#include "code\_onclick\hud\hud_types\_hud.dm" +#include "code\_onclick\hud\hud_types\ai.dm" +#include "code\_onclick\hud\hud_types\ai_hud.dm" +#include "code\_onclick\hud\hud_types\animal.dm" +#include "code\_onclick\hud\hud_types\human.dm" +#include "code\_onclick\hud\hud_types\other_mobs.dm" +#include "code\_onclick\hud\hud_types\pai.dm" +#include "code\_onclick\hud\hud_types\robot.dm" +#include "code\_onclick\hud\screen\_screen.dm" +#include "code\_onclick\hud\screen\screen_action_button.dm" +#include "code\_onclick\hud\screen\screen_ai_button.dm" +#include "code\_onclick\hud\screen\screen_attack_selector.dm" +#include "code\_onclick\hud\screen\screen_cinematic.dm" +#include "code\_onclick\hud\screen\screen_click_catcher.dm" +#include "code\_onclick\hud\screen\screen_constructs.dm" +#include "code\_onclick\hud\screen\screen_credits.dm" +#include "code\_onclick\hud\screen\screen_drop.dm" +#include "code\_onclick\hud\screen\screen_equip.dm" +#include "code\_onclick\hud\screen\screen_exosuit.dm" +#include "code\_onclick\hud\screen\screen_fullscreen.dm" +#include "code\_onclick\hud\screen\screen_global_hud.dm" +#include "code\_onclick\hud\screen\screen_gun.dm" +#include "code\_onclick\hud\screen\screen_health.dm" +#include "code\_onclick\hud\screen\screen_holomap.dm" +#include "code\_onclick\hud\screen\screen_intent.dm" +#include "code\_onclick\hud\screen\screen_internal.dm" +#include "code\_onclick\hud\screen\screen_inventory.dm" +#include "code\_onclick\hud\screen\screen_inventory_hands.dm" +#include "code\_onclick\hud\screen\screen_lighting.dm" +#include "code\_onclick\hud\screen\screen_maneuver.dm" +#include "code\_onclick\hud\screen\screen_mob_modifier.dm" +#include "code\_onclick\hud\screen\screen_movement.dm" +#include "code\_onclick\hud\screen\screen_needs.dm" +#include "code\_onclick\hud\screen\screen_pai.dm" +#include "code\_onclick\hud\screen\screen_radial.dm" +#include "code\_onclick\hud\screen\screen_resist.dm" +#include "code\_onclick\hud\screen\screen_setup.dm" +#include "code\_onclick\hud\screen\screen_stamina.dm" +#include "code\_onclick\hud\screen\screen_storage.dm" +#include "code\_onclick\hud\screen\screen_swaphands.dm" +#include "code\_onclick\hud\screen\screen_throw.dm" +#include "code\_onclick\hud\screen\screen_toggle.dm" +#include "code\_onclick\hud\screen\screen_up_hint.dm" +#include "code\_onclick\hud\screen\screen_warning.dm" +#include "code\_onclick\hud\screen\screen_warning_bodytemp.dm" +#include "code\_onclick\hud\screen\screen_warning_fire.dm" +#include "code\_onclick\hud\screen\screen_warning_oxygen.dm" +#include "code\_onclick\hud\screen\screen_warning_pressure.dm" +#include "code\_onclick\hud\screen\screen_warning_toxins.dm" +#include "code\_onclick\hud\screen\screen_zone_selector.dm" +#include "code\_onclick\hud\screen\robot\screen_robot.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_drop_grab.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_inventory.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_module.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_modules.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_radio.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_store.dm" +#include "code\_onclick\hud\screen\robot\screen_robot_warnings.dm" #include "code\controllers\admin.dm" #include "code\controllers\autotransfer.dm" #include "code\controllers\communications.dm" -#include "code\controllers\configuration.dm" #include "code\controllers\controller.dm" #include "code\controllers\failsafe.dm" -#include "code\controllers\globals.dm" -#include "code\controllers\hooks-defs.dm" -#include "code\controllers\hooks.dm" #include "code\controllers\master.dm" #include "code\controllers\subsystem.dm" #include "code\controllers\verbs.dm" @@ -184,12 +270,13 @@ #include "code\controllers\evacuation\~evac.dm" #include "code\controllers\subsystems\air.dm" #include "code\controllers\subsystems\alarm.dm" -#include "code\controllers\subsystems\antags.dm" +#include "code\controllers\subsystems\ambience.dm" #include "code\controllers\subsystems\ao.dm" #include "code\controllers\subsystems\atoms.dm" -#include "code\controllers\subsystems\circuit_component.dm" -#include "code\controllers\subsystems\departments.dm" +#include "code\controllers\subsystems\configuration.dm" +#include "code\controllers\subsystems\daycycle.dm" #include "code\controllers\subsystems\disposals.dm" +#include "code\controllers\subsystems\DPC.dm" #include "code\controllers\subsystems\evac.dm" #include "code\controllers\subsystems\event.dm" #include "code\controllers\subsystems\fluids.dm" @@ -197,79 +284,105 @@ #include "code\controllers\subsystems\ghost_images.dm" #include "code\controllers\subsystems\goals.dm" #include "code\controllers\subsystems\graphs.dm" +#include "code\controllers\subsystems\holomap.dm" +#include "code\controllers\subsystems\icon_updates.dm" #include "code\controllers\subsystems\inactivity.dm" +#include "code\controllers\subsystems\input.dm" +#include "code\controllers\subsystems\item_effects.dm" #include "code\controllers\subsystems\jobs.dm" #include "code\controllers\subsystems\lighting.dm" #include "code\controllers\subsystems\machines.dm" +#include "code\controllers\subsystems\managed_instance.dm" #include "code\controllers\subsystems\mapping.dm" #include "code\controllers\subsystems\misc_late.dm" #include "code\controllers\subsystems\overlays.dm" -#include "code\controllers\subsystems\plants.dm" +#include "code\controllers\subsystems\overmap.dm" +#include "code\controllers\subsystems\pathfinding.dm" +#include "code\controllers\subsystems\persistence.dm" #include "code\controllers\subsystems\radiation.dm" #include "code\controllers\subsystems\shuttle.dm" #include "code\controllers\subsystems\skybox.dm" #include "code\controllers\subsystems\spacedrift.dm" #include "code\controllers\subsystems\statistics.dm" -#include "code\controllers\subsystems\sun.dm" #include "code\controllers\subsystems\supply.dm" #include "code\controllers\subsystems\throwing.dm" #include "code\controllers\subsystems\ticker.dm" #include "code\controllers\subsystems\timer.dm" #include "code\controllers\subsystems\trade.dm" +#include "code\controllers\subsystems\typing.dm" +#include "code\controllers\subsystems\vis_contents.dm" #include "code\controllers\subsystems\vote.dm" +#include "code\controllers\subsystems\weather.dm" +#include "code\controllers\subsystems\weather_atoms.dm" #include "code\controllers\subsystems\xenoarch.dm" #include "code\controllers\subsystems\zcopy.dm" +#include "code\controllers\subsystems\initialization\character_info.dm" #include "code\controllers\subsystems\initialization\character_setup.dm" #include "code\controllers\subsystems\initialization\codex.dm" +#include "code\controllers\subsystems\initialization\codex_dump.dm" #include "code\controllers\subsystems\initialization\computer_networks.dm" -#include "code\controllers\subsystems\initialization\cuisine.dm" #include "code\controllers\subsystems\initialization\customitems.dm" #include "code\controllers\subsystems\initialization\fabrication.dm" #include "code\controllers\subsystems\initialization\lore.dm" #include "code\controllers\subsystems\initialization\materials.dm" #include "code\controllers\subsystems\initialization\misc.dm" #include "code\controllers\subsystems\initialization\modpacks.dm" -#include "code\controllers\subsystems\initialization\persistence.dm" #include "code\controllers\subsystems\initialization\robots.dm" +#include "code\controllers\subsystems\initialization\secrets.dm" #include "code\controllers\subsystems\initialization\webhooks.dm" -#include "code\controllers\subsystems\processing\ai.dm" +#include "code\controllers\subsystems\mob_ai\auto_movement.dm" +#include "code\controllers\subsystems\mob_ai\mob_ai.dm" #include "code\controllers\subsystems\processing\airflow.dm" -#include "code\controllers\subsystems\processing\circuit.dm" +#include "code\controllers\subsystems\processing\chatter.dm" #include "code\controllers\subsystems\processing\fast_process.dm" #include "code\controllers\subsystems\processing\graphs.dm" -#include "code\controllers\subsystems\processing\icon_updates.dm" #include "code\controllers\subsystems\processing\mobs.dm" #include "code\controllers\subsystems\processing\nano.dm" #include "code\controllers\subsystems\processing\obj.dm" +#include "code\controllers\subsystems\processing\plants.dm" #include "code\controllers\subsystems\processing\processing.dm" +#include "code\controllers\subsystems\processing\projectiles.dm" #include "code\controllers\subsystems\processing\temperature.dm" #include "code\controllers\subsystems\processing\turf.dm" #include "code\controllers\subsystems\processing\vines.dm" +#include "code\datums\ai_holo.dm" #include "code\datums\ai_law_sets.dm" #include "code\datums\ai_laws.dm" +#include "code\datums\beam.dm" #include "code\datums\browser.dm" #include "code\datums\callbacks.dm" #include "code\datums\category.dm" #include "code\datums\cinematic.dm" #include "code\datums\datum.dm" +#include "code\datums\datum_serde.dm" #include "code\datums\footsteps.dm" #include "code\datums\hierarchy.dm" #include "code\datums\local_network.dm" #include "code\datums\mil_ranks.dm" +#include "code\datums\mutable_appearance.dm" +#include "code\datums\position_point_vector.dm" #include "code\datums\progressbar.dm" -#include "code\datums\recipe.dm" -#include "code\datums\ruins.dm" -#include "code\datums\security_state.dm" -#include "code\datums\shackle_law_sets.dm" #include "code\datums\sound_player.dm" #include "code\datums\suit_sensor_jammer_method.dm" #include "code\datums\sun.dm" +#include "code\datums\track.dm" +#include "code\datums\type_cloning.dm" #include "code\datums\weakref.dm" -#include "code\datums\ai\ai.dm" -#include "code\datums\ai\ai_holo.dm" +#include "code\datums\ai\_ai.dm" +#include "code\datums\ai\_ai_enemies.dm" +#include "code\datums\ai\_ai_friends.dm" +#include "code\datums\ai\_ai_memory.dm" +#include "code\datums\ai\_ai_pathfinding.dm" +#include "code\datums\ai\_ai_stance.dm" +#include "code\datums\ai\_ai_targets.dm" +#include "code\datums\ai\_ai_wander.dm" +#include "code\datums\ai\aggressive.dm" +#include "code\datums\ai\beast.dm" +#include "code\datums\ai\commanded.dm" #include "code\datums\ai\human.dm" +#include "code\datums\ai\hunter.dm" #include "code\datums\ai\monkey.dm" -#include "code\datums\ai\nymph.dm" +#include "code\datums\ai\passive.dm" #include "code\datums\appearances\appearance_data.dm" #include "code\datums\appearances\appearance_manager.dm" #include "code\datums\appearances\automatic\_base.dm" @@ -283,21 +396,61 @@ #include "code\datums\communication\ooc.dm" #include "code\datums\communication\pray.dm" #include "code\datums\communication\~defines.dm" +#include "code\datums\composite_sounds\_composite_sound.dm" +#include "code\datums\composite_sounds\fire_sounds.dm" +#include "code\datums\composite_sounds\loom.dm" +#include "code\datums\composite_sounds\machinery_sounds.dm" +#include "code\datums\composite_sounds\vehicle_engine.dm" +#include "code\datums\config\_config.dm" +#include "code\datums\config\_config_categories.dm" +#include "code\datums\config\config_enum.dm" +#include "code\datums\config\config_list.dm" +#include "code\datums\config\config_num.dm" +#include "code\datums\config\config_num_client.dm" +#include "code\datums\config\config_text.dm" +#include "code\datums\config\config_toggle.dm" +#include "code\datums\config\config_toggle_on.dm" +#include "code\datums\config\config_types\config_admin.dm" +#include "code\datums\config\config_types\config_client.dm" +#include "code\datums\config\config_types\config_debug.dm" +#include "code\datums\config\config_types\config_events.dm" +#include "code\datums\config\config_types\config_game_option.dm" +#include "code\datums\config\config_types\config_game_world.dm" +#include "code\datums\config\config_types\config_health.dm" +#include "code\datums\config\config_types\config_logging.dm" +#include "code\datums\config\config_types\config_mode.dm" +#include "code\datums\config\config_types\config_protected.dm" +#include "code\datums\config\config_types\config_resources.dm" +#include "code\datums\config\config_types\config_server.dm" +#include "code\datums\config\config_types\config_voting.dm" +#include "code\datums\daycycle\daycycle.dm" +#include "code\datums\daycycle\time_of_day.dm" #include "code\datums\extensions\_defines.dm" -#include "code\datums\extensions\deity_be_near.dm" +#include "code\datums\extensions\access_provider.dm" #include "code\datums\extensions\event_registration.dm" #include "code\datums\extensions\extensions.dm" #include "code\datums\extensions\fake_data.dm" -#include "code\datums\extensions\hattable.dm" #include "code\datums\extensions\interactive.dm" #include "code\datums\extensions\label.dm" #include "code\datums\extensions\local_network.dm" #include "code\datums\extensions\lockable.dm" #include "code\datums\extensions\parts_stash.dm" #include "code\datums\extensions\penetration.dm" +#include "code\datums\extensions\radio_provider.dm" +#include "code\datums\extensions\state_machine.dm" +#include "code\datums\extensions\abilities\abilities.dm" +#include "code\datums\extensions\abilities\abilities_mob.dm" +#include "code\datums\extensions\abilities\abilities_predator.dm" +#include "code\datums\extensions\abilities\ability_button.dm" +#include "code\datums\extensions\abilities\ability_decl.dm" +#include "code\datums\extensions\abilities\ability_handler.dm" +#include "code\datums\extensions\abilities\ability_item.dm" +#include "code\datums\extensions\abilities\ability_projectile.dm" +#include "code\datums\extensions\abilities\ability_targeting.dm" #include "code\datums\extensions\appearance\appearance.dm" #include "code\datums\extensions\appearance\base_icon_state.dm" #include "code\datums\extensions\appearance\cardborg.dm" +#include "code\datums\extensions\appearance\universally_visible.dm" #include "code\datums\extensions\armor\ablative.dm" #include "code\datums\extensions\armor\armor.dm" #include "code\datums\extensions\armor\armor_rig.dm" @@ -305,12 +458,21 @@ #include "code\datums\extensions\assembly\assembly_damage.dm" #include "code\datums\extensions\assembly\assembly_interaction.dm" #include "code\datums\extensions\assembly\assembly_power.dm" +#include "code\datums\extensions\cell\cell.dm" +#include "code\datums\extensions\cell\cell_panel.dm" +#include "code\datums\extensions\cell\cell_secured.dm" +#include "code\datums\extensions\cell\cell_unremovable.dm" +#include "code\datums\extensions\demolisher\_demolisher.dm" +#include "code\datums\extensions\demolisher\delicate.dm" +#include "code\datums\extensions\demolisher\energy.dm" +#include "code\datums\extensions\demolisher\pick.dm" +#include "code\datums\extensions\demolisher\welder.dm" #include "code\datums\extensions\eye\_eye.dm" #include "code\datums\extensions\eye\blueprints.dm" #include "code\datums\extensions\eye\freelook.dm" #include "code\datums\extensions\eye\landing.dm" #include "code\datums\extensions\holster\holster.dm" -#include "code\datums\extensions\multitool\_multitool.dm" +#include "code\datums\extensions\milkable\milkable.dm" #include "code\datums\extensions\multitool\multitool.dm" #include "code\datums\extensions\multitool\store.dm" #include "code\datums\extensions\multitool\circuitboards\buildtype_select.dm" @@ -321,18 +483,35 @@ #include "code\datums\extensions\multitool\items\clothing.dm" #include "code\datums\extensions\multitool\items\items.dm" #include "code\datums\extensions\multitool\items\stock_parts_radio.dm" -#include "code\datums\extensions\on_click\on_alt_click.dm" -#include "code\datums\extensions\on_click\on_click.dm" #include "code\datums\extensions\on_click\turf_hand.dm" -#include "code\datums\extensions\scent\_scent.dm" -#include "code\datums\extensions\scent\scent_candle.dm" -#include "code\datums\extensions\scent\scent_misc.dm" +#include "code\datums\extensions\padding\padding.dm" +#include "code\datums\extensions\resistable\resistable.dm" +#include "code\datums\extensions\shearable\shearable.dm" +#include "code\datums\genetics\genetic_conditions.dm" #include "code\datums\graph\graph.dm" #include "code\datums\graph\node.dm" -#include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\dist_check.dm" #include "code\datums\helper_datums\getrev.dm" #include "code\datums\helper_datums\teleport.dm" +#include "code\datums\hostility\hostility.dm" +#include "code\datums\inventory_slots\_inventory_slot.dm" +#include "code\datums\inventory_slots\inventory_gripper.dm" +#include "code\datums\inventory_slots\inventory_gripper_robot.dm" +#include "code\datums\inventory_slots\inventory_gripper_subtypes.dm" +#include "code\datums\inventory_slots\slots\slot_back.dm" +#include "code\datums\inventory_slots\slots\slot_belt.dm" +#include "code\datums\inventory_slots\slots\slot_cuffs.dm" +#include "code\datums\inventory_slots\slots\slot_ears.dm" +#include "code\datums\inventory_slots\slots\slot_glasses.dm" +#include "code\datums\inventory_slots\slots\slot_gloves.dm" +#include "code\datums\inventory_slots\slots\slot_head.dm" +#include "code\datums\inventory_slots\slots\slot_id.dm" +#include "code\datums\inventory_slots\slots\slot_mask.dm" +#include "code\datums\inventory_slots\slots\slot_pockets.dm" +#include "code\datums\inventory_slots\slots\slot_shoes.dm" +#include "code\datums\inventory_slots\slots\slot_suit.dm" +#include "code\datums\inventory_slots\slots\slot_suit_storage.dm" +#include "code\datums\inventory_slots\slots\slot_uniform.dm" #include "code\datums\item_modifiers\_defines.dm" #include "code\datums\item_modifiers\item_modifier.dm" #include "code\datums\item_modifiers\space_suits.dm" @@ -341,8 +520,12 @@ #include "code\datums\mind\memory.dm" #include "code\datums\mind\mind.dm" #include "code\datums\move_intent\move_intent.dm" +#include "code\datums\move_intent\move_intent_animal.dm" #include "code\datums\movement\_defines.dm" #include "code\datums\movement\atom_movable.dm" +#include "code\datums\movement\automove.dm" +#include "code\datums\movement\automove_controller.dm" +#include "code\datums\movement\automove_metadata.dm" #include "code\datums\movement\mob.dm" #include "code\datums\movement\movement.dm" #include "code\datums\movement\multiz.dm" @@ -352,6 +535,7 @@ #include "code\datums\music_tracks\_music_track.dm" #include "code\datums\music_tracks\absconditus.dm" #include "code\datums\music_tracks\ambispace.dm" +#include "code\datums\music_tracks\chasing_time.dm" #include "code\datums\music_tracks\clouds_of_fire.dm" #include "code\datums\music_tracks\comet_haley.dm" #include "code\datums\music_tracks\df_theme.dm" @@ -362,6 +546,7 @@ #include "code\datums\music_tracks\epicintro2015.dm" #include "code\datums\music_tracks\epicintro2017.dm" #include "code\datums\music_tracks\europa.dm" +#include "code\datums\music_tracks\fantasy.dm" #include "code\datums\music_tracks\floating.dm" #include "code\datums\music_tracks\human.dm" #include "code\datums\music_tracks\lasers.dm" @@ -372,26 +557,34 @@ #include "code\datums\music_tracks\space_oddity.dm" #include "code\datums\music_tracks\thunderdome.dm" #include "code\datums\music_tracks\title1.dm" -#include "code\datums\music_tracks\Torch.dm" #include "code\datums\music_tracks\treacherous_voyage.dm" #include "code\datums\music_tracks\wake.dm" #include "code\datums\observation\_defines.dm" +#include "code\datums\observation\area_power_change.dm" +#include "code\datums\observation\crate_sold.dm" +#include "code\datums\observation\cyborg_created.dm" #include "code\datums\observation\death.dm" +#include "code\datums\observation\debrain.dm" #include "code\datums\observation\density_set.dm" #include "code\datums\observation\destroyed.dm" #include "code\datums\observation\dir_set.dm" #include "code\datums\observation\dismembered.dm" +#include "code\datums\observation\employee_id.dm" #include "code\datums\observation\entered.dm" #include "code\datums\observation\equipped.dm" +#include "code\datums\observation\examine.dm" #include "code\datums\observation\exited.dm" #include "code\datums\observation\helpers.dm" +#include "code\datums\observation\ingested.dm" #include "code\datums\observation\life.dm" #include "code\datums\observation\logged_in.dm" #include "code\datums\observation\logged_out.dm" +#include "code\datums\observation\money_accounts.dm" #include "code\datums\observation\moved.dm" #include "code\datums\observation\name_set.dm" #include "code\datums\observation\observation.dm" #include "code\datums\observation\opacity_set.dm" +#include "code\datums\observation\player_latejoin.dm" #include "code\datums\observation\see_in_dark_set.dm" #include "code\datums\observation\see_invisible_set.dm" #include "code\datums\observation\set_invisibility.dm" @@ -399,10 +592,12 @@ #include "code\datums\observation\shuttle_moved.dm" #include "code\datums\observation\sight_set.dm" #include "code\datums\observation\stat_set.dm" -#include "code\datums\observation\turf_changed.dm" +#include "code\datums\observation\submap_join.dm" #include "code\datums\observation\unequipped.dm" +#include "code\datums\observation\updated_icon.dm" #include "code\datums\observation\zone_selected.dm" #include "code\datums\observation\~cleanup.dm" +#include "code\datums\observation\~defines.dm" #include "code\datums\outfits\_defines.dm" #include "code\datums\outfits\horror_killers.dm" #include "code\datums\outfits\misc.dm" @@ -412,6 +607,7 @@ #include "code\datums\outfits\tournament.dm" #include "code\datums\outfits\wizardry.dm" #include "code\datums\outfits\equipment\backpacks.dm" +#include "code\datums\outfits\equipment\survival_box.dm" #include "code\datums\outfits\jobs\_defines.dm" #include "code\datums\outfits\jobs\generic.dm" #include "code\datums\outfits\jobs\job.dm" @@ -419,15 +615,14 @@ #include "code\datums\proximity_trigger\proximity_trigger.dm" #include "code\datums\proximity_trigger\turf_selection.dm" #include "code\datums\repositories\_defines.dm" -#include "code\datums\repositories\admin_pm.dm" #include "code\datums\repositories\areas.dm" #include "code\datums\repositories\atom_info.dm" #include "code\datums\repositories\attack_logs.dm" #include "code\datums\repositories\cameras.dm" #include "code\datums\repositories\client.dm" #include "code\datums\repositories\decls.dm" +#include "code\datums\repositories\events.dm" #include "code\datums\repositories\follow.dm" -#include "code\datums\repositories\images.dm" #include "code\datums\repositories\mobs.dm" #include "code\datums\repositories\repository.dm" #include "code\datums\repositories\sound_channels.dm" @@ -442,6 +637,31 @@ #include "code\datums\repositories\crew\tracking.dm" #include "code\datums\repositories\crew\vital.dm" #include "code\datums\repositories\crew\~defines.dm" +#include "code\datums\state_machine\paper_fortune_fsm.dm" +#include "code\datums\state_machine\state.dm" +#include "code\datums\state_machine\transition.dm" +#include "code\datums\storage\_storage.dm" +#include "code\datums\storage\_storage_ui.dm" +#include "code\datums\storage\subtypes_backpack.dm" +#include "code\datums\storage\subtypes_bag.dm" +#include "code\datums\storage\subtypes_basket.dm" +#include "code\datums\storage\subtypes_belt.dm" +#include "code\datums\storage\subtypes_box.dm" +#include "code\datums\storage\subtypes_excavation.dm" +#include "code\datums\storage\subtypes_firstaid.dm" +#include "code\datums\storage\subtypes_holster.dm" +#include "code\datums\storage\subtypes_misc.dm" +#include "code\datums\storage\subtypes_mre.dm" +#include "code\datums\storage\subtypes_part_replacer.dm" +#include "code\datums\storage\subtypes_pills.dm" +#include "code\datums\storage\subtypes_pockets.dm" +#include "code\datums\storage\subtypes_secure.dm" +#include "code\datums\storage\subtypes_sheets.dm" +#include "code\datums\storage\subtypes_slides.dm" +#include "code\datums\storage\subtypes_specialized.dm" +#include "code\datums\storage\subtypes_structure.dm" +#include "code\datums\storage\subtypes_tray.dm" +#include "code\datums\storage\subtypes_wallet.dm" #include "code\datums\supplypacks\atmospherics.dm" #include "code\datums\supplypacks\custodial.dm" #include "code\datums\supplypacks\dispcarts.dm" @@ -459,15 +679,29 @@ #include "code\datums\supplypacks\security.dm" #include "code\datums\supplypacks\supply.dm" #include "code\datums\supplypacks\supplypack.dm" -#include "code\datums\trading\_trading_defines.dm" -#include "code\datums\trading\ai.dm" -#include "code\datums\trading\food.dm" -#include "code\datums\trading\goods.dm" -#include "code\datums\trading\misc.dm" -#include "code\datums\trading\ship.dm" -#include "code\datums\trading\trade.dm" -#include "code\datums\trading\unique.dm" -#include "code\datums\trading\weaponry.dm" +#include "code\datums\trading\__trading_defines.dm" +#include "code\datums\trading\_trade_hub.dm" +#include "code\datums\trading\_trader.dm" +#include "code\datums\trading\trade_hub_overmap.dm" +#include "code\datums\trading\trading_verbs.dm" +#include "code\datums\trading\traders\ai.dm" +#include "code\datums\trading\traders\books.dm" +#include "code\datums\trading\traders\food.dm" +#include "code\datums\trading\traders\goods.dm" +#include "code\datums\trading\traders\misc.dm" +#include "code\datums\trading\traders\ship.dm" +#include "code\datums\trading\traders\unique.dm" +#include "code\datums\trading\traders\weaponry.dm" +#include "code\datums\traits\_trait_categories.dm" +#include "code\datums\traits\_traits.dm" +#include "code\datums\traits\metabolically_inert.dm" +#include "code\datums\traits\maluses\_malus.dm" +#include "code\datums\traits\maluses\amputations.dm" +#include "code\datums\traits\maluses\ethanol.dm" +#include "code\datums\traits\maluses\intolerances.dm" +#include "code\datums\traits\maluses\vision.dm" +#include "code\datums\traits\prosthetics\prosthetic_limbs.dm" +#include "code\datums\traits\prosthetics\prosthetic_organs.dm" #include "code\datums\underwear\bottom.dm" #include "code\datums\underwear\socks.dm" #include "code\datums\underwear\top.dm" @@ -475,7 +709,7 @@ #include "code\datums\underwear\underwear.dm" #include "code\datums\uplink\ammunition.dm" #include "code\datums\uplink\badassery.dm" -#include "code\datums\uplink\devices and tools.dm" +#include "code\datums\uplink\devices_and_tools.dm" #include "code\datums\uplink\grenades.dm" #include "code\datums\uplink\hardsuit_modules.dm" #include "code\datums\uplink\highly_visible_and_dangerous_weapons.dm" @@ -499,11 +733,9 @@ #include "code\datums\vote\vote.dm" #include "code\datums\wires\airlock.dm" #include "code\datums\wires\alarm.dm" -#include "code\datums\wires\apc.dm" #include "code\datums\wires\camera.dm" #include "code\datums\wires\explosive.dm" #include "code\datums\wires\fabricator.dm" -#include "code\datums\wires\inertial_damper.dm" #include "code\datums\wires\nuclearbomb.dm" #include "code\datums\wires\particle_accelerator.dm" #include "code\datums\wires\radio.dm" @@ -512,21 +744,31 @@ #include "code\datums\wires\smartfridge.dm" #include "code\datums\wires\smes.dm" #include "code\datums\wires\suit_cycler.dm" -#include "code\datums\wires\taperecorder.dm" #include "code\datums\wires\vending.dm" #include "code\datums\wires\wire_description.dm" #include "code\datums\wires\wires.dm" +#include "code\game\alpha_masks.dm" +#include "code\game\atom_edibility.dm" +#include "code\game\atom_material.dm" #include "code\game\atoms.dm" +#include "code\game\atoms_damage.dm" +#include "code\game\atoms_fires.dm" #include "code\game\atoms_fluids.dm" +#include "code\game\atoms_init.dm" +#include "code\game\atoms_interactions.dm" +#include "code\game\atoms_layering.dm" #include "code\game\atoms_movable.dm" #include "code\game\atoms_movable_grabs.dm" +#include "code\game\atoms_movable_interactions.dm" +#include "code\game\atoms_movable_overlay.dm" +#include "code\game\atoms_movable_serde.dm" +#include "code\game\atoms_serde.dm" #include "code\game\atoms_temperature.dm" #include "code\game\base_turf.dm" -#include "code\game\images.dm" #include "code\game\movietitles.dm" -#include "code\game\response_team.dm" #include "code\game\sound.dm" #include "code\game\world.dm" +#include "code\game\world_topic_commands.dm" #include "code\game\antagonist\_antagonist_setup.dm" #include "code\game\antagonist\antagonist.dm" #include "code\game\antagonist\antagonist_add.dm" @@ -539,91 +781,24 @@ #include "code\game\antagonist\antagonist_place.dm" #include "code\game\antagonist\antagonist_print.dm" #include "code\game\antagonist\antagonist_update.dm" -#include "code\game\antagonist\outsider\actors.dm" -#include "code\game\antagonist\outsider\deity.dm" -#include "code\game\antagonist\outsider\ert.dm" -#include "code\game\antagonist\outsider\mercenary.dm" -#include "code\game\antagonist\outsider\ninja.dm" -#include "code\game\antagonist\outsider\raider.dm" -#include "code\game\antagonist\outsider\wizard.dm" -#include "code\game\antagonist\station\changeling.dm" -#include "code\game\antagonist\station\cult_god.dm" -#include "code\game\antagonist\station\cultist.dm" -#include "code\game\antagonist\station\loyalist.dm" -#include "code\game\antagonist\station\provocateur.dm" -#include "code\game\antagonist\station\renegade.dm" -#include "code\game\antagonist\station\revolutionary.dm" -#include "code\game\antagonist\station\thrall.dm" -#include "code\game\antagonist\station\traitor.dm" +#include "code\game\area\area_abstract.dm" #include "code\game\area\area_access.dm" +#include "code\game\area\area_fishing.dm" #include "code\game\area\area_power.dm" +#include "code\game\area\area_space.dm" #include "code\game\area\areas.dm" -#include "code\game\area\Space Station 13 areas.dm" -#include "code\game\dna\dna2.dm" -#include "code\game\dna\dna2_domutcheck.dm" -#include "code\game\dna\dna2_helpers.dm" -#include "code\game\dna\genes\disabilities.dm" -#include "code\game\dna\genes\gene.dm" -#include "code\game\dna\genes\powers.dm" -#include "code\game\gamemodes\events.dm" +#include "code\game\area\areas_serde.dm" #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\game_mode_latespawn.dm" -#include "code\game\gamemodes\setupgame.dm" #include "code\game\gamemodes\calamity\calamity.dm" -#include "code\game\gamemodes\changeling\absorbed_dna.dm" -#include "code\game\gamemodes\changeling\changeling.dm" -#include "code\game\gamemodes\changeling\changeling_powers.dm" -#include "code\game\gamemodes\changeling\modularchangling.dm" -#include "code\game\gamemodes\cult\cult.dm" -#include "code\game\gamemodes\cult\cult_items.dm" -#include "code\game\gamemodes\cult\cult_structures.dm" -#include "code\game\gamemodes\cult\ghosts.dm" -#include "code\game\gamemodes\cult\hell_universe.dm" -#include "code\game\gamemodes\cult\narsie.dm" -#include "code\game\gamemodes\cult\ritual.dm" -#include "code\game\gamemodes\cult\runes.dm" -#include "code\game\gamemodes\cult\talisman.dm" -#include "code\game\gamemodes\cult\cultify\de-cultify.dm" -#include "code\game\gamemodes\cult\cultify\mob.dm" -#include "code\game\gamemodes\cult\cultify\turf.dm" #include "code\game\gamemodes\endgame\endgame.dm" #include "code\game\gamemodes\endgame\ftl_jump\ftl_jump.dm" #include "code\game\gamemodes\endgame\nuclear_explosion\nuclear_explosion.dm" -#include "code\game\gamemodes\endgame\supermatter_cascade\cascade_blob.dm" -#include "code\game\gamemodes\endgame\supermatter_cascade\portal.dm" -#include "code\game\gamemodes\endgame\supermatter_cascade\universe.dm" -#include "code\game\gamemodes\events\black_hole.dm" #include "code\game\gamemodes\events\power_failure.dm" -#include "code\game\gamemodes\events\wormholes.dm" #include "code\game\gamemodes\extended\extended.dm" -#include "code\game\gamemodes\godmode\god_altar.dm" -#include "code\game\gamemodes\godmode\god_pylon.dm" -#include "code\game\gamemodes\godmode\god_structures.dm" -#include "code\game\gamemodes\godmode\god_trap.dm" -#include "code\game\gamemodes\godmode\godmode.dm" -#include "code\game\gamemodes\godmode\form_items\narsie_items.dm" -#include "code\game\gamemodes\godmode\form_items\narsie_structures.dm" -#include "code\game\gamemodes\godmode\form_items\starlight_items.dm" -#include "code\game\gamemodes\godmode\form_items\starlight_mobs.dm" -#include "code\game\gamemodes\godmode\form_items\starlight_structures.dm" -#include "code\game\gamemodes\godmode\form_items\wizard_structures.dm" -#include "code\game\gamemodes\heist\heist.dm" -#include "code\game\gamemodes\meteor\meteor.dm" -#include "code\game\gamemodes\meteor\meteors.dm" -#include "code\game\gamemodes\mixed\crossfire.dm" -#include "code\game\gamemodes\mixed\siege.dm" -#include "code\game\gamemodes\mixed\spyvspy.dm" -#include "code\game\gamemodes\mixed\traitorling.dm" -#include "code\game\gamemodes\mixed\uprising.dm" -#include "code\game\gamemodes\ninja\ninja.dm" -#include "code\game\gamemodes\nuclear\nuclear.dm" -#include "code\game\gamemodes\nuclear\pinpointer.dm" #include "code\game\gamemodes\objectives\_objective.dm" -#include "code\game\gamemodes\objectives\objective_absorb.dm" #include "code\game\gamemodes\objectives\objective_assassinate.dm" #include "code\game\gamemodes\objectives\objective_brig.dm" -#include "code\game\gamemodes\objectives\objective_capture.dm" -#include "code\game\gamemodes\objectives\objective_cult.dm" #include "code\game\gamemodes\objectives\objective_debrain.dm" #include "code\game\gamemodes\objectives\objective_demote.dm" #include "code\game\gamemodes\objectives\objective_download.dm" @@ -635,35 +810,25 @@ #include "code\game\gamemodes\objectives\objective_protect.dm" #include "code\game\gamemodes\objectives\objective_rev.dm" #include "code\game\gamemodes\objectives\objective_steal.dm" -#include "code\game\gamemodes\revolution\revolution.dm" -#include "code\game\gamemodes\traitor\traitor.dm" -#include "code\game\gamemodes\wizard\wizard.dm" -#include "code\game\gamemodes\wizard\servant_items\caretaker.dm" -#include "code\game\gamemodes\wizard\servant_items\champion.dm" -#include "code\game\gamemodes\wizard\servant_items\familiar.dm" -#include "code\game\gamemodes\wizard\servant_items\fiend.dm" -#include "code\game\gamemodes\wizard\servant_items\infiltrator.dm" -#include "code\game\gamemodes\wizard\servant_items\overseer.dm" #include "code\game\jobs\_access_defs.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\access_datum.dm" -#include "code\game\jobs\whitelist.dm" +#include "code\game\jobs\alt_titles.dm" +#include "code\game\jobs\server_whitelist.dm" #include "code\game\jobs\job\_job.dm" -#include "code\game\jobs\job\assistant.dm" -#include "code\game\jobs\job\silicon.dm" #include "code\game\machinery\ai_slipper.dm" #include "code\game\machinery\air_sensor.dm" #include "code\game\machinery\alarm.dm" #include "code\game\machinery\atmo_control.dm" #include "code\game\machinery\Beacon.dm" #include "code\game\machinery\biogenerator.dm" -#include "code\game\machinery\bioprinter.dm" #include "code\game\machinery\bodyscanner.dm" #include "code\game\machinery\bodyscanner_console.dm" #include "code\game\machinery\bodyscanner_display.dm" #include "code\game\machinery\buttons.dm" #include "code\game\machinery\CableLayer.dm" #include "code\game\machinery\cell_charger.dm" +#include "code\game\machinery\centrifuge.dm" #include "code\game\machinery\commsrelay.dm" #include "code\game\machinery\constructable_frame.dm" #include "code\game\machinery\cracker.dm" @@ -679,8 +844,6 @@ #include "code\game\machinery\holosign.dm" #include "code\game\machinery\igniter.dm" #include "code\game\machinery\jukebox.dm" -#include "code\game\machinery\lightswitch.dm" -#include "code\game\machinery\magnet.dm" #include "code\game\machinery\mass_driver.dm" #include "code\game\machinery\mech_recharger.dm" #include "code\game\machinery\message_server.dm" @@ -696,6 +859,8 @@ #include "code\game\machinery\requests_console.dm" #include "code\game\machinery\seed_extractor.dm" #include "code\game\machinery\self_destruct.dm" +#include "code\game\machinery\self_destruct_storage.dm" +#include "code\game\machinery\singularitybeacon.dm" #include "code\game\machinery\Sleeper.dm" #include "code\game\machinery\slide_projector.dm" #include "code\game\machinery\spaceheater.dm" @@ -706,14 +871,12 @@ #include "code\game\machinery\suit_cycler_units.dm" #include "code\game\machinery\supply_display.dm" #include "code\game\machinery\supplybeacon.dm" -#include "code\game\machinery\syndicatebeacon.dm" #include "code\game\machinery\teleporter.dm" #include "code\game\machinery\turret_control.dm" #include "code\game\machinery\vending_deconstruction.dm" #include "code\game\machinery\vitals_monitor.dm" #include "code\game\machinery\wall_frames.dm" #include "code\game\machinery\washing_machine.dm" -#include "code\game\machinery\wishgranter.dm" #include "code\game\machinery\_machines_base\machinery.dm" #include "code\game\machinery\_machines_base\machinery_components.dm" #include "code\game\machinery\_machines_base\machinery_damage.dm" @@ -721,21 +884,27 @@ #include "code\game\machinery\_machines_base\machinery_public_vars.dm" #include "code\game\machinery\_machines_base\machinery_public_vars_common.dm" #include "code\game\machinery\_machines_base\machine_construction\_construction.dm" +#include "code\game\machinery\_machines_base\machine_construction\airlock.dm" +#include "code\game\machinery\_machines_base\machine_construction\blast_doors.dm" #include "code\game\machinery\_machines_base\machine_construction\computer.dm" #include "code\game\machinery\_machines_base\machine_construction\default.dm" #include "code\game\machinery\_machines_base\machine_construction\frame.dm" #include "code\game\machinery\_machines_base\machine_construction\item_chassis.dm" #include "code\game\machinery\_machines_base\machine_construction\noninteractive.dm" #include "code\game\machinery\_machines_base\machine_construction\pipe.dm" -#include "code\game\machinery\_machines_base\machine_construction\tcomms.dm" #include "code\game\machinery\_machines_base\machine_construction\wall_frame.dm" #include "code\game\machinery\_machines_base\machine_construction\wall_frame_hackable.dm" #include "code\game\machinery\_machines_base\machine_construction\wall_frame_simple.dm" #include "code\game\machinery\_machines_base\stock_parts\_stock_parts.dm" #include "code\game\machinery\_machines_base\stock_parts\access_lock.dm" #include "code\game\machinery\_machines_base\stock_parts\building_material.dm" +#include "code\game\machinery\_machines_base\stock_parts\card_reader.dm" +#include "code\game\machinery\_machines_base\stock_parts\cupholder.dm" +#include "code\game\machinery\_machines_base\stock_parts\disk_reader.dm" +#include "code\game\machinery\_machines_base\stock_parts\item_holder.dm" #include "code\game\machinery\_machines_base\stock_parts\legacy_parts.dm" #include "code\game\machinery\_machines_base\stock_parts\network_lock.dm" +#include "code\game\machinery\_machines_base\stock_parts\network_receiver.dm" #include "code\game\machinery\_machines_base\stock_parts\shielding.dm" #include "code\game\machinery\_machines_base\stock_parts\stock_parts_interface.dm" #include "code\game\machinery\_machines_base\stock_parts\stock_parts_presets.dm" @@ -747,24 +916,24 @@ #include "code\game\machinery\_machines_base\stock_parts\radio\receiver.dm" #include "code\game\machinery\_machines_base\stock_parts\radio\stock_parts_radio.dm" #include "code\game\machinery\_machines_base\stock_parts\radio\transmitter.dm" -#include "code\game\machinery\atmoalter\area_atmos_computer.dm" +#include "code\game\machinery\atmoalter\_atmos_connection.dm" #include "code\game\machinery\atmoalter\canister.dm" -#include "code\game\machinery\atmoalter\clamp.dm" #include "code\game\machinery\atmoalter\meter.dm" #include "code\game\machinery\atmoalter\portable_atmospherics.dm" #include "code\game\machinery\atmoalter\pump.dm" #include "code\game\machinery\atmoalter\scrubber.dm" +#include "code\game\machinery\camera\_camera_device.dm" #include "code\game\machinery\camera\camera.dm" -#include "code\game\machinery\camera\camera_assembly.dm" -#include "code\game\machinery\camera\motion.dm" #include "code\game\machinery\camera\presets.dm" +#include "code\game\machinery\camera\robot_camera.dm" #include "code\game\machinery\camera\tracking.dm" #include "code\game\machinery\computer\ai_core.dm" #include "code\game\machinery\computer\arcade.dm" #include "code\game\machinery\computer\arcade_orion.dm" +#include "code\game\machinery\computer\area_atmos.dm" #include "code\game\machinery\computer\atmos_alert.dm" -#include "code\game\machinery\computer\atmos_control.dm" #include "code\game\machinery\computer\buildandrepair.dm" +#include "code\game\machinery\computer\central_atmos.dm" #include "code\game\machinery\computer\computer.dm" #include "code\game\machinery\computer\guestpass.dm" #include "code\game\machinery\computer\law.dm" @@ -784,9 +953,9 @@ #include "code\game\machinery\doors\blast_door.dm" #include "code\game\machinery\doors\braces.dm" #include "code\game\machinery\doors\brigdoors.dm" +#include "code\game\machinery\doors\double.dm" #include "code\game\machinery\doors\firedoor.dm" #include "code\game\machinery\doors\firedoor_assembly.dm" -#include "code\game\machinery\doors\multi_tile.dm" #include "code\game\machinery\doors\windowdoor.dm" #include "code\game\machinery\embedded_controller\airlock_controllers.dm" #include "code\game\machinery\embedded_controller\airlock_controllers_dummy.dm" @@ -802,7 +971,6 @@ #include "code\game\machinery\kitchen\gibber.dm" #include "code\game\machinery\kitchen\icecream.dm" #include "code\game\machinery\kitchen\microwave.dm" -#include "code\game\machinery\kitchen\smartfridge.dm" #include "code\game\machinery\kitchen\cooking_machines\_cooker.dm" #include "code\game\machinery\kitchen\cooking_machines\_cooker_output.dm" #include "code\game\machinery\kitchen\cooking_machines\candy.dm" @@ -812,12 +980,21 @@ #include "code\game\machinery\kitchen\cooking_machines\oven.dm" #include "code\game\machinery\pipe\construction.dm" #include "code\game\machinery\pipe\pipelayer.dm" -#include "code\game\machinery\telecomms\broadcaster.dm" -#include "code\game\machinery\telecomms\logbrowser.dm" -#include "code\game\machinery\telecomms\machine_interactions.dm" -#include "code\game\machinery\telecomms\presets.dm" -#include "code\game\machinery\telecomms\telecomunications.dm" -#include "code\game\machinery\telecomms\telemonitor.dm" +#include "code\game\machinery\smartfridge\_smartfridge.dm" +#include "code\game\machinery\smartfridge\_smartfridge_secure.dm" +#include "code\game\machinery\smartfridge\chemistry.dm" +#include "code\game\machinery\smartfridge\drinks.dm" +#include "code\game\machinery\smartfridge\drying_oven.dm" +#include "code\game\machinery\smartfridge\foods.dm" +#include "code\game\machinery\smartfridge\medbay.dm" +#include "code\game\machinery\smartfridge\produce.dm" +#include "code\game\machinery\smartfridge\seeds.dm" +#include "code\game\machinery\smartfridge\sheets.dm" +#include "code\game\machinery\turrets\_turrets.dm" +#include "code\game\machinery\turrets\network_turret.dm" +#include "code\game\machinery\turrets\turret_ammo.dm" +#include "code\game\machinery\turrets\turret_fsm.dm" +#include "code\game\machinery\turrets\turret_hostility.dm" #include "code\game\machinery\vending\_vending.dm" #include "code\game\machinery\vending\actors.dm" #include "code\game\machinery\vending\botany.dm" @@ -828,155 +1005,284 @@ #include "code\game\machinery\vending\misc.dm" #include "code\game\machinery\vending\security.dm" #include "code\game\machinery\vending\toxins.dm" +#include "code\game\objects\__objs.dm" +#include "code\game\objects\_objs_damage.dm" +#include "code\game\objects\_objs_edibility.dm" +#include "code\game\objects\_objs_interactions.dm" #include "code\game\objects\alien_props.dm" -#include "code\game\objects\buckling.dm" #include "code\game\objects\empulse.dm" #include "code\game\objects\explosion.dm" -#include "code\game\objects\item.dm" -#include "code\game\objects\item_materials.dm" +#include "code\game\objects\item_mob_overlay.dm" #include "code\game\objects\munition.dm" -#include "code\game\objects\objs.dm" #include "code\game\objects\topic.dm" -#include "code\game\objects\auras\aura.dm" -#include "code\game\objects\auras\blueforge_aura.dm" -#include "code\game\objects\auras\radiant_aura.dm" -#include "code\game\objects\auras\regenerating_aura.dm" -#include "code\game\objects\auras\shadowling_aura.dm" -#include "code\game\objects\auras\starlight.dm" -#include "code\game\objects\auras\personal_shields\personal_shield.dm" +#include "code\game\objects\compass\_compass.dm" +#include "code\game\objects\compass\compass_holder.dm" +#include "code\game\objects\compass\compass_overmap.dm" +#include "code\game\objects\compass\compass_waypoint.dm" +#include "code\game\objects\effects\_effect.dm" #include "code\game\objects\effects\bump_teleporter.dm" +#include "code\game\objects\effects\chem_holder.dm" +#include "code\game\objects\effects\cig_smoke.dm" +#include "code\game\objects\effects\dirty_floor.dm" #include "code\game\objects\effects\effect_system.dm" #include "code\game\objects\effects\explosion_particles.dm" +#include "code\game\objects\effects\fadein.dm" +#include "code\game\objects\effects\fadeout.dm" #include "code\game\objects\effects\fake_fire.dm" -#include "code\game\objects\effects\fluids.dm" +#include "code\game\objects\effects\footprints.dm" #include "code\game\objects\effects\force_portal.dm" -#include "code\game\objects\effects\gibs.dm" +#include "code\game\objects\effects\gateway.dm" +#include "code\game\objects\effects\gibspawner.dm" #include "code\game\objects\effects\item_pickup_ghost.dm" #include "code\game\objects\effects\landmarks.dm" -#include "code\game\objects\effects\manifest.dm" -#include "code\game\objects\effects\mines.dm" +#include "code\game\objects\effects\landmarks_endgame.dm" +#include "code\game\objects\effects\landmarks_latejoin.dm" #include "code\game\objects\effects\misc.dm" #include "code\game\objects\effects\overlays.dm" #include "code\game\objects\effects\portals.dm" #include "code\game\objects\effects\spiders.dm" #include "code\game\objects\effects\step_triggers.dm" -#include "code\game\objects\effects\temporaray.dm" +#include "code\game\objects\effects\temporary.dm" #include "code\game\objects\effects\temporary_effect.dm" +#include "code\game\objects\effects\wet_floor.dm" +#include "code\game\objects\effects\wormhole.dm" #include "code\game\objects\effects\chem\chemsmoke.dm" #include "code\game\objects\effects\chem\foam.dm" #include "code\game\objects\effects\chem\water.dm" #include "code\game\objects\effects\decals\cleanable.dm" -#include "code\game\objects\effects\decals\contraband.dm" #include "code\game\objects\effects\decals\crayon.dm" #include "code\game\objects\effects\decals\decal.dm" +#include "code\game\objects\effects\decals\decal_serde.dm" #include "code\game\objects\effects\decals\misc.dm" -#include "code\game\objects\effects\decals\remains.dm" #include "code\game\objects\effects\decals\warning_stripes.dm" -#include "code\game\objects\effects\decals\Cleanable\aliens.dm" #include "code\game\objects\effects\decals\Cleanable\humans.dm" #include "code\game\objects\effects\decals\Cleanable\misc.dm" #include "code\game\objects\effects\decals\Cleanable\robots.dm" #include "code\game\objects\effects\decals\Cleanable\tracks.dm" -#include "code\game\objects\effects\decals\posters\bs12.dm" +#include "code\game\objects\effects\map_effect\_map_effect.dm" +#include "code\game\objects\effects\map_effect\interval\_interval.dm" +#include "code\game\objects\effects\map_effect\interval\effect_emitter.dm" +#include "code\game\objects\effects\map_effect\interval\screen_shaker.dm" +#include "code\game\objects\effects\map_effect\interval\sound_emitter.dm" +#include "code\game\objects\effects\mines\_mine.dm" +#include "code\game\objects\effects\mines\_mine_payload.dm" +#include "code\game\objects\effects\mines\mine_assembly.dm" +#include "code\game\objects\effects\mines\mine_emp.dm" +#include "code\game\objects\effects\mines\mine_frag.dm" +#include "code\game\objects\effects\mines\mine_incendiary.dm" +#include "code\game\objects\effects\mines\mine_kick.dm" +#include "code\game\objects\effects\mines\mine_napalm.dm" +#include "code\game\objects\effects\mines\mine_radiation.dm" +#include "code\game\objects\effects\mines\mine_sleeping.dm" +#include "code\game\objects\effects\mines\mine_stun.dm" +#include "code\game\objects\effects\mines\mine_training.dm" #include "code\game\objects\effects\spawners\bombspawner.dm" #include "code\game\objects\effects\spawners\gibspawner.dm" -#include "code\game\objects\items\apc_frame.dm" +#include "code\game\objects\items\__item.dm" +#include "code\game\objects\items\_item_damage.dm" +#include "code\game\objects\items\_item_drying.dm" +#include "code\game\objects\items\_item_edibility.dm" +#include "code\game\objects\items\_item_force.dm" +#include "code\game\objects\items\_item_interactions.dm" +#include "code\game\objects\items\_item_materials.dm" +#include "code\game\objects\items\_item_melting.dm" +#include "code\game\objects\items\_item_reagents.dm" +#include "code\game\objects\items\_item_serde.dm" +#include "code\game\objects\items\_item_sharpness.dm" #include "code\game\objects\items\blackout.dm" #include "code\game\objects\items\blueprints.dm" #include "code\game\objects\items\bodybag.dm" -#include "code\game\objects\items\buttons.dm" +#include "code\game\objects\items\candelabra.dm" +#include "code\game\objects\items\chisel.dm" #include "code\game\objects\items\christmas.dm" #include "code\game\objects\items\contraband.dm" -#include "code\game\objects\items\crayons.dm" +#include "code\game\objects\items\crutches.dm" #include "code\game\objects\items\cryobag.dm" #include "code\game\objects\items\documents.dm" +#include "code\game\objects\items\fleece.dm" #include "code\game\objects\items\glassjar.dm" +#include "code\game\objects\items\helping_hands.dm" #include "code\game\objects\items\holosign_creator.dm" +#include "code\game\objects\items\horseshoe.dm" +#include "code\game\objects\items\hourglass.dm" #include "code\game\objects\items\instruments.dm" -#include "code\game\objects\items\item_icon_experimental.dm" #include "code\game\objects\items\latexballoon.dm" #include "code\game\objects\items\paintkit.dm" +#include "code\game\objects\items\paper_fortune_teller.dm" #include "code\game\objects\items\part_replacer.dm" +#include "code\game\objects\items\passport.dm" #include "code\game\objects\items\plunger.dm" +#include "code\game\objects\items\plushies.dm" +#include "code\game\objects\items\remains.dm" #include "code\game\objects\items\rescuebag.dm" -#include "code\game\objects\items\shooting_range.dm" +#include "code\game\objects\items\rock.dm" +#include "code\game\objects\items\saddle.dm" +#include "code\game\objects\items\silencer.dm" #include "code\game\objects\items\spirit_board.dm" +#include "code\game\objects\items\stools.dm" #include "code\game\objects\items\toys.dm" +#include "code\game\objects\items\training_dummy.dm" #include "code\game\objects\items\trash.dm" -#include "code\game\objects\items\wooden_prosthetics.dm" +#include "code\game\objects\items\trash_serde.dm" +#include "code\game\objects\items\umbrella.dm" +#include "code\game\objects\items\waterskin.dm" +#include "code\game\objects\items\artifice\chain.dm" +#include "code\game\objects\items\artifice\hook.dm" +#include "code\game\objects\items\artifice\lockpicks.dm" +#include "code\game\objects\items\blades\_blade.dm" +#include "code\game\objects\items\blades\axe.dm" +#include "code\game\objects\items\blades\axe_fire.dm" +#include "code\game\objects\items\blades\folding.dm" +#include "code\game\objects\items\blades\knife.dm" +#include "code\game\objects\items\blades\polearm.dm" +#include "code\game\objects\items\blades\spear.dm" +#include "code\game\objects\items\blades\spear_improvised.dm" +#include "code\game\objects\items\blades\swords_one_handed.dm" +#include "code\game\objects\items\blades\swords_two_handed.dm" #include "code\game\objects\items\books\_book.dm" -#include "code\game\objects\items\books\skill_book.dm" +#include "code\game\objects\items\books\_book_serde.dm" +#include "code\game\objects\items\books\fluff\_fluff.dm" +#include "code\game\objects\items\books\fluff\science.dm" #include "code\game\objects\items\books\manuals\_manual.dm" #include "code\game\objects\items\books\manuals\engineering.dm" #include "code\game\objects\items\books\manuals\manuals.dm" #include "code\game\objects\items\books\manuals\medical.dm" #include "code\game\objects\items\books\manuals\science.dm" +#include "code\game\objects\items\books\skill\_skill.dm" +#include "code\game\objects\items\books\skill\_skill_custom.dm" +#include "code\game\objects\items\books\skill\engineering.dm" +#include "code\game\objects\items\books\skill\general.dm" +#include "code\game\objects\items\books\skill\medical.dm" +#include "code\game\objects\items\books\skill\organizational.dm" +#include "code\game\objects\items\books\skill\research.dm" +#include "code\game\objects\items\books\skill\security.dm" +#include "code\game\objects\items\books\skill\service.dm" +#include "code\game\objects\items\circuitboards\broken.dm" +#include "code\game\objects\items\circuitboards\circuitboard.dm" +#include "code\game\objects\items\circuitboards\other.dm" +#include "code\game\objects\items\circuitboards\wall.dm" +#include "code\game\objects\items\circuitboards\computer\air_management.dm" +#include "code\game\objects\items\circuitboards\computer\computer.dm" +#include "code\game\objects\items\circuitboards\computer\holodeckcontrol.dm" +#include "code\game\objects\items\circuitboards\computer\modular.dm" +#include "code\game\objects\items\circuitboards\computer\shuttle.dm" +#include "code\game\objects\items\circuitboards\computer\station_alert.dm" +#include "code\game\objects\items\circuitboards\machinery\biogenerator.dm" +#include "code\game\objects\items\circuitboards\machinery\chemistry.dm" +#include "code\game\objects\items\circuitboards\machinery\cloning.dm" +#include "code\game\objects\items\circuitboards\machinery\commsantenna.dm" +#include "code\game\objects\items\circuitboards\machinery\docking_beacon.dm" +#include "code\game\objects\items\circuitboards\machinery\engineering_circuits.dm" +#include "code\game\objects\items\circuitboards\machinery\forensic.dm" +#include "code\game\objects\items\circuitboards\machinery\holomap.dm" +#include "code\game\objects\items\circuitboards\machinery\household.dm" +#include "code\game\objects\items\circuitboards\machinery\mech_recharger.dm" +#include "code\game\objects\items\circuitboards\machinery\medical.dm" +#include "code\game\objects\items\circuitboards\machinery\mining.dm" +#include "code\game\objects\items\circuitboards\machinery\mining_drill.dm" +#include "code\game\objects\items\circuitboards\machinery\network.dm" +#include "code\game\objects\items\circuitboards\machinery\oxyregenerator.dm" +#include "code\game\objects\items\circuitboards\machinery\pacman.dm" +#include "code\game\objects\items\circuitboards\machinery\portable_atmospherics.dm" +#include "code\game\objects\items\circuitboards\machinery\power.dm" +#include "code\game\objects\items\circuitboards\machinery\recharge_station.dm" +#include "code\game\objects\items\circuitboards\machinery\research.dm" +#include "code\game\objects\items\circuitboards\machinery\self_destruct_storage.dm" +#include "code\game\objects\items\circuitboards\machinery\shieldgen.dm" +#include "code\game\objects\items\circuitboards\machinery\shipsensors.dm" +#include "code\game\objects\items\circuitboards\machinery\telecomms.dm" +#include "code\game\objects\items\circuitboards\machinery\unary_atmos.dm" #include "code\game\objects\items\devices\aicard.dm" #include "code\game\objects\items\devices\auto_cpr.dm" #include "code\game\objects\items\devices\binoculars.dm" #include "code\game\objects\items\devices\boombox.dm" #include "code\game\objects\items\devices\cable_painter.dm" #include "code\game\objects\items\devices\chameleonproj.dm" -#include "code\game\objects\items\devices\debugger.dm" #include "code\game\objects\items\devices\dociler.dm" #include "code\game\objects\items\devices\flash.dm" -#include "code\game\objects\items\devices\flashlight.dm" #include "code\game\objects\items\devices\geiger.dm" #include "code\game\objects\items\devices\gps.dm" #include "code\game\objects\items\devices\hacktool.dm" +#include "code\game\objects\items\devices\hailer.dm" #include "code\game\objects\items\devices\holowarrant.dm" #include "code\game\objects\items\devices\inducer.dm" -#include "code\game\objects\items\devices\lightreplacer.dm" #include "code\game\objects\items\devices\megaphone.dm" #include "code\game\objects\items\devices\modkit.dm" #include "code\game\objects\items\devices\multitool.dm" +#include "code\game\objects\items\devices\music_player.dm" #include "code\game\objects\items\devices\oxycandle.dm" #include "code\game\objects\items\devices\paicard.dm" -#include "code\game\objects\items\devices\paint_gun.dm" +#include "code\game\objects\items\devices\paint_sprayer.dm" #include "code\game\objects\items\devices\personal_shield.dm" #include "code\game\objects\items\devices\pinpointer.dm" -#include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\powersink.dm" #include "code\game\objects\items\devices\spy_bug.dm" #include "code\game\objects\items\devices\suit_cooling.dm" #include "code\game\objects\items\devices\suit_sensor_jammer.dm" #include "code\game\objects\items\devices\t_scanner.dm" -#include "code\game\objects\items\devices\taperecorder.dm" #include "code\game\objects\items\devices\traitordevices.dm" #include "code\game\objects\items\devices\transfer_valve.dm" #include "code\game\objects\items\devices\tvcamera.dm" #include "code\game\objects\items\devices\uplink.dm" #include "code\game\objects\items\devices\uplink_random_lists.dm" -#include "code\game\objects\items\devices\whistle.dm" #include "code\game\objects\items\devices\radio\beacon.dm" -#include "code\game\objects\items\devices\radio\electropack.dm" #include "code\game\objects\items\devices\radio\encryptionkey.dm" #include "code\game\objects\items\devices\radio\headset.dm" +#include "code\game\objects\items\devices\radio\headsets_shared.dm" #include "code\game\objects\items\devices\radio\intercom.dm" #include "code\game\objects\items\devices\radio\radio.dm" -#include "code\game\objects\items\devices\scanners\_scanner.dm" -#include "code\game\objects\items\devices\scanners\gas.dm" -#include "code\game\objects\items\devices\scanners\health.dm" -#include "code\game\objects\items\devices\scanners\mass_spectrometer.dm" -#include "code\game\objects\items\devices\scanners\mining.dm" -#include "code\game\objects\items\devices\scanners\plant.dm" -#include "code\game\objects\items\devices\scanners\price.dm" -#include "code\game\objects\items\devices\scanners\reagents.dm" -#include "code\game\objects\items\devices\scanners\xenobio.dm" +#include "code\game\objects\items\devices\radio\radio_analog.dm" +#include "code\game\objects\items\devices\radio\radio_announcer.dm" +#include "code\game\objects\items\devices\radio\radio_borg.dm" +#include "code\game\objects\items\devices\radio\radio_exosuit.dm" +#include "code\game\objects\items\devices\radio\radio_misc.dm" +#include "code\game\objects\items\devices\tape_recorder\magnetic_tape.dm" +#include "code\game\objects\items\devices\tape_recorder\tape_recorder.dm" +#include "code\game\objects\items\devices\tape_recorder\taperecorder_wires.dm" +#include "code\game\objects\items\flame\_flame.dm" +#include "code\game\objects\items\flame\flame_candle.dm" +#include "code\game\objects\items\flame\flame_fuelled.dm" +#include "code\game\objects\items\flame\flame_fuelled_lantern.dm" +#include "code\game\objects\items\flame\flame_fuelled_lighter.dm" +#include "code\game\objects\items\flame\flame_fuelled_lighter_zippo.dm" +#include "code\game\objects\items\flame\flame_matches.dm" +#include "code\game\objects\items\flame\flame_torch.dm" +#include "code\game\objects\items\flashlights\_flashlight.dm" +#include "code\game\objects\items\flashlights\flare.dm" +#include "code\game\objects\items\flashlights\floodlamp.dm" +#include "code\game\objects\items\flashlights\glowstick.dm" +#include "code\game\objects\items\flashlights\lamp.dm" +#include "code\game\objects\items\flashlights\lavalamp.dm" +#include "code\game\objects\items\flashlights\misc.dm" +#include "code\game\objects\items\flashlights\party.dm" +#include "code\game\objects\items\flashlights\penlight.dm" +#include "code\game\objects\items\flashlights\slime.dm" #include "code\game\objects\items\robot\robot_frame.dm" #include "code\game\objects\items\robot\robot_items.dm" #include "code\game\objects\items\robot\robot_parts.dm" #include "code\game\objects\items\robot\robot_upgrades.dm" #include "code\game\objects\items\stacks\matter_synth.dm" -#include "code\game\objects\items\stacks\medical.dm" #include "code\game\objects\items\stacks\nanopaste.dm" #include "code\game\objects\items\stacks\rods.dm" #include "code\game\objects\items\stacks\stack.dm" +#include "code\game\objects\items\stacks\stack_serde.dm" #include "code\game\objects\items\stacks\telecrystal.dm" +#include "code\game\objects\items\stacks\medical\_medical.dm" +#include "code\game\objects\items\stacks\medical\medical_bandage.dm" +#include "code\game\objects\items\stacks\medical\medical_ointment.dm" +#include "code\game\objects\items\stacks\medical\medical_resin.dm" +#include "code\game\objects\items\stacks\medical\medical_splint.dm" #include "code\game\objects\items\stacks\tiles\tile_types.dm" +#include "code\game\objects\items\stacks\tiles\tile_types_wooden.dm" +#include "code\game\objects\items\tools\crowbar.dm" +#include "code\game\objects\items\tools\screwdriver.dm" +#include "code\game\objects\items\tools\shears.dm" +#include "code\game\objects\items\tools\wirecutter.dm" +#include "code\game\objects\items\tools\wrench.dm" #include "code\game\objects\items\weapons\AI_modules.dm" #include "code\game\objects\items\weapons\autopsy.dm" -#include "code\game\objects\items\weapons\beachball.dm" +#include "code\game\objects\items\weapons\balls.dm" +#include "code\game\objects\items\weapons\broom.dm" #include "code\game\objects\items\weapons\cane.dm" #include "code\game\objects\items\weapons\cards_ids.dm" #include "code\game\objects\items\weapons\cards_ids_syndicate.dm" @@ -986,77 +1292,32 @@ #include "code\game\objects\items\weapons\defib.dm" #include "code\game\objects\items\weapons\dice.dm" #include "code\game\objects\items\weapons\ecigs.dm" -#include "code\game\objects\items\weapons\electric_welder.dm" #include "code\game\objects\items\weapons\explosives.dm" #include "code\game\objects\items\weapons\extinguisher.dm" -#include "code\game\objects\items\weapons\flame.dm" #include "code\game\objects\items\weapons\flamethrower.dm" #include "code\game\objects\items\weapons\gift_wrappaper.dm" -#include "code\game\objects\items\weapons\hair_care.dm" #include "code\game\objects\items\weapons\handcuffs.dm" #include "code\game\objects\items\weapons\ironing_iron.dm" #include "code\game\objects\items\weapons\janitor_sign.dm" -#include "code\game\objects\items\weapons\lighter.dm" +#include "code\game\objects\items\weapons\locator.dm" #include "code\game\objects\items\weapons\mop.dm" #include "code\game\objects\items\weapons\nuclear_cylinder.dm" #include "code\game\objects\items\weapons\paint.dm" -#include "code\game\objects\items\weapons\policetape.dm" #include "code\game\objects\items\weapons\RCD.dm" #include "code\game\objects\items\weapons\RPD.dm" #include "code\game\objects\items\weapons\RSF.dm" -#include "code\game\objects\items\weapons\scrolls.dm" #include "code\game\objects\items\weapons\secrets_disk.dm" -#include "code\game\objects\items\weapons\shields.dm" #include "code\game\objects\items\weapons\soap.dm" #include "code\game\objects\items\weapons\staff.dm" #include "code\game\objects\items\weapons\stunbaton.dm" #include "code\game\objects\items\weapons\surgery_tools.dm" +#include "code\game\objects\items\weapons\surgery_tools_ancient.dm" #include "code\game\objects\items\weapons\swords_axes_etc.dm" #include "code\game\objects\items\weapons\tape.dm" #include "code\game\objects\items\weapons\tech_disks.dm" -#include "code\game\objects\items\weapons\teleportation.dm" #include "code\game\objects\items\weapons\towels.dm" #include "code\game\objects\items\weapons\traps.dm" #include "code\game\objects\items\weapons\weaponry.dm" -#include "code\game\objects\items\weapons\weldbackpack.dm" -#include "code\game\objects\items\weapons\candle\candle.dm" -#include "code\game\objects\items\weapons\candle\incense.dm" -#include "code\game\objects\items\weapons\candle\scent_decls.dm" -#include "code\game\objects\items\weapons\candle\scented.dm" -#include "code\game\objects\items\weapons\circuitboards\broken.dm" -#include "code\game\objects\items\weapons\circuitboards\circuitboard.dm" -#include "code\game\objects\items\weapons\circuitboards\other.dm" -#include "code\game\objects\items\weapons\circuitboards\wall.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\air_management.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\computer.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\holodeckcontrol.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\modular.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\shuttle.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\station_alert.dm" -#include "code\game\objects\items\weapons\circuitboards\computer\telecomms.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\biogenerator.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\chemistry.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\cloning.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\commsantenna.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\engineering_circuits.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\forensic.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\household.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\inertial_damper.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\mech_recharger.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\medical.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\mining.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\mining_drill.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\network.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\oxyregenerator.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\pacman.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\portable_atmospherics.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\power.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\recharge_station.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\research.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\shieldgen.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\shipsensors.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\telecomms.dm" -#include "code\game\objects\items\weapons\circuitboards\machinery\unary_atmos.dm" #include "code\game\objects\items\weapons\grenades\anti_photon_grenade.dm" #include "code\game\objects\items\weapons\grenades\chem_grenade.dm" #include "code\game\objects\items\weapons\grenades\decompiler.dm" @@ -1068,23 +1329,6 @@ #include "code\game\objects\items\weapons\grenades\prank_grenades.dm" #include "code\game\objects\items\weapons\grenades\smokebomb.dm" #include "code\game\objects\items\weapons\grenades\spawnergrenade.dm" -#include "code\game\objects\items\weapons\grenades\supermatter.dm" -#include "code\game\objects\items\weapons\implants\implant.dm" -#include "code\game\objects\items\weapons\implants\implantcase.dm" -#include "code\game\objects\items\weapons\implants\implantchair.dm" -#include "code\game\objects\items\weapons\implants\implanter.dm" -#include "code\game\objects\items\weapons\implants\implantpad.dm" -#include "code\game\objects\items\weapons\implants\implants\adrenaline.dm" -#include "code\game\objects\items\weapons\implants\implants\chem.dm" -#include "code\game\objects\items\weapons\implants\implants\compressed.dm" -#include "code\game\objects\items\weapons\implants\implants\death_alarm.dm" -#include "code\game\objects\items\weapons\implants\implants\explosive.dm" -#include "code\game\objects\items\weapons\implants\implants\freedom.dm" -#include "code\game\objects\items\weapons\implants\implants\imprinting.dm" -#include "code\game\objects\items\weapons\implants\implants\loyalty.dm" -#include "code\game\objects\items\weapons\implants\implants\tracking.dm" -#include "code\game\objects\items\weapons\implants\implants\translator.dm" -#include "code\game\objects\items\weapons\implants\implants\uplink.dm" #include "code\game\objects\items\weapons\material\ashtray.dm" #include "code\game\objects\items\weapons\material\bell.dm" #include "code\game\objects\items\weapons\material\coins.dm" @@ -1097,103 +1341,185 @@ #include "code\game\objects\items\weapons\material\swiss.dm" #include "code\game\objects\items\weapons\material\swords.dm" #include "code\game\objects\items\weapons\material\thrown.dm" -#include "code\game\objects\items\weapons\material\twohanded.dm" #include "code\game\objects\items\weapons\material\urn.dm" +#include "code\game\objects\items\weapons\melee\baseball_bat.dm" #include "code\game\objects\items\weapons\melee\energy.dm" +#include "code\game\objects\items\weapons\melee\energy_axe.dm" +#include "code\game\objects\items\weapons\melee\energy_cutlass.dm" +#include "code\game\objects\items\weapons\melee\energy_machete.dm" +#include "code\game\objects\items\weapons\melee\energy_projected.dm" +#include "code\game\objects\items\weapons\melee\energy_sword.dm" #include "code\game\objects\items\weapons\melee\misc.dm" -#include "code\game\objects\items\weapons\special_attacks\backstab.dm" +#include "code\game\objects\items\weapons\shields\_shield.dm" +#include "code\game\objects\items\weapons\shields\shield_crafted.dm" +#include "code\game\objects\items\weapons\shields\shield_crafted_buckler.dm" +#include "code\game\objects\items\weapons\shields\shield_crafting.dm" +#include "code\game\objects\items\weapons\shields\shield_energy.dm" +#include "code\game\objects\items\weapons\shields\shield_riot.dm" #include "code\game\objects\items\weapons\storage\backpack.dm" #include "code\game\objects\items\weapons\storage\bags.dm" +#include "code\game\objects\items\weapons\storage\basket.dm" #include "code\game\objects\items\weapons\storage\belt.dm" #include "code\game\objects\items\weapons\storage\bible.dm" #include "code\game\objects\items\weapons\storage\boxes.dm" #include "code\game\objects\items\weapons\storage\briefcase.dm" -#include "code\game\objects\items\weapons\storage\fancy.dm" +#include "code\game\objects\items\weapons\storage\candles.dm" #include "code\game\objects\items\weapons\storage\firstaid.dm" -#include "code\game\objects\items\weapons\storage\internal.dm" #include "code\game\objects\items\weapons\storage\laundry_basket.dm" #include "code\game\objects\items\weapons\storage\lockbox.dm" #include "code\game\objects\items\weapons\storage\lunchbox.dm" +#include "code\game\objects\items\weapons\storage\matches.dm" #include "code\game\objects\items\weapons\storage\med_pouch.dm" #include "code\game\objects\items\weapons\storage\misc.dm" #include "code\game\objects\items\weapons\storage\mre.dm" +#include "code\game\objects\items\weapons\storage\nuggets.dm" +#include "code\game\objects\items\weapons\storage\parachute.dm" +#include "code\game\objects\items\weapons\storage\picnic_basket.dm" #include "code\game\objects\items\weapons\storage\secure.dm" #include "code\game\objects\items\weapons\storage\specialized.dm" -#include "code\game\objects\items\weapons\storage\storage.dm" #include "code\game\objects\items\weapons\storage\toolbox.dm" -#include "code\game\objects\items\weapons\storage\trays.dm" #include "code\game\objects\items\weapons\storage\uplink_kits.dm" #include "code\game\objects\items\weapons\storage\wall_mirror.dm" #include "code\game\objects\items\weapons\storage\wallets.dm" -#include "code\game\objects\items\weapons\storage\storage_ui\default.dm" -#include "code\game\objects\items\weapons\storage\storage_ui\storage_ui.dm" +#include "code\game\objects\items\weapons\storage\fancy\_fancy.dm" +#include "code\game\objects\items\weapons\storage\fancy\cigar.dm" +#include "code\game\objects\items\weapons\storage\fancy\cigarettes.dm" +#include "code\game\objects\items\weapons\storage\fancy\crackers.dm" +#include "code\game\objects\items\weapons\storage\fancy\crayons.dm" +#include "code\game\objects\items\weapons\storage\fancy\donutbox.dm" +#include "code\game\objects\items\weapons\storage\fancy\eggbox.dm" +#include "code\game\objects\items\weapons\storage\fancy\vials.dm" #include "code\game\objects\items\weapons\tanks\jetpack.dm" #include "code\game\objects\items\weapons\tanks\tank_types.dm" #include "code\game\objects\items\weapons\tanks\tanks.dm" -#include "code\game\objects\items\weapons\tools\crowbar.dm" -#include "code\game\objects\items\weapons\tools\screwdriver.dm" -#include "code\game\objects\items\weapons\tools\weldingtool.dm" -#include "code\game\objects\items\weapons\tools\wirecutter.dm" -#include "code\game\objects\items\weapons\tools\wrench.dm" +#include "code\game\objects\items\welding\electric_welder.dm" +#include "code\game\objects\items\welding\weldbackpack.dm" +#include "code\game\objects\items\welding\weldingtool.dm" +#include "code\game\objects\items\welding\weldingtool_tank.dm" +#include "code\game\objects\random\_random.dm" #include "code\game\objects\random\date_based.dm" #include "code\game\objects\random\random.dm" +#include "code\game\objects\random\random_multi.dm" +#include "code\game\objects\random\subtypes\closets.dm" +#include "code\game\objects\random\subtypes\clothing.dm" +#include "code\game\objects\random\subtypes\food.dm" +#include "code\game\objects\random\subtypes\maintenance.dm" +#include "code\game\objects\random\subtypes\medical.dm" +#include "code\game\objects\random\subtypes\misc.dm" +#include "code\game\objects\random\subtypes\mobs.dm" +#include "code\game\objects\random\subtypes\multi.dm" +#include "code\game\objects\random\subtypes\paperwork.dm" +#include "code\game\objects\random\subtypes\plants.dm" +#include "code\game\objects\random\subtypes\salvage.dm" +#include "code\game\objects\random\subtypes\suits.dm" +#include "code\game\objects\random\subtypes\tech.dm" +#include "code\game\objects\random\subtypes\tools.dm" +#include "code\game\objects\random\subtypes\toys.dm" +#include "code\game\objects\random\subtypes\weapons.dm" #include "code\game\objects\structures\__structure.dm" #include "code\game\objects\structures\_structure_construction.dm" #include "code\game\objects\structures\_structure_icon.dm" +#include "code\game\objects\structures\_structure_interactions.dm" +#include "code\game\objects\structures\_structure_lock.dm" #include "code\game\objects\structures\_structure_materials.dm" +#include "code\game\objects\structures\_structure_serde.dm" #include "code\game\objects\structures\ai_decoy.dm" +#include "code\game\objects\structures\armor_stand.dm" #include "code\game\objects\structures\barricade.dm" #include "code\game\objects\structures\barsign.dm" #include "code\game\objects\structures\bedsheet_bin.dm" +#include "code\game\objects\structures\benches.dm" #include "code\game\objects\structures\bookcase.dm" #include "code\game\objects\structures\catwalk.dm" #include "code\game\objects\structures\charge_pylon.dm" +#include "code\game\objects\structures\cliffs.dm" #include "code\game\objects\structures\coathanger.dm" +#include "code\game\objects\structures\compost.dm" +#include "code\game\objects\structures\crematorium.dm" +#include "code\game\objects\structures\curtain_decls.dm" #include "code\game\objects\structures\curtains.dm" #include "code\game\objects\structures\defensive_barrier.dm" #include "code\game\objects\structures\displaycase.dm" +#include "code\game\objects\structures\divider.dm" #include "code\game\objects\structures\dogbed.dm" #include "code\game\objects\structures\door_assembly.dm" +#include "code\game\objects\structures\double_sign.dm" #include "code\game\objects\structures\drain.dm" -#include "code\game\objects\structures\electricchair.dm" +#include "code\game\objects\structures\drying_rack.dm" +#include "code\game\objects\structures\emergency_dispenser.dm" #include "code\game\objects\structures\extinguisher.dm" +#include "code\game\objects\structures\fences.dm" #include "code\game\objects\structures\fireaxe_cabinet.dm" +#include "code\game\objects\structures\fires.dm" #include "code\game\objects\structures\fishtanks.dm" #include "code\game\objects\structures\fitness.dm" -#include "code\game\objects\structures\flora.dm" +#include "code\game\objects\structures\flaps.dm" #include "code\game\objects\structures\fountain.dm" +#include "code\game\objects\structures\fuel_port.dm" #include "code\game\objects\structures\girders.dm" +#include "code\game\objects\structures\grandfather_clock.dm" #include "code\game\objects\structures\grille.dm" +#include "code\game\objects\structures\hand_cart.dm" #include "code\game\objects\structures\handrail.dm" +#include "code\game\objects\structures\hay.dm" #include "code\game\objects\structures\holosigns.dm" #include "code\game\objects\structures\inflatable.dm" #include "code\game\objects\structures\ironing_board.dm" #include "code\game\objects\structures\iv_drip.dm" #include "code\game\objects\structures\janicart.dm" #include "code\game\objects\structures\lattice.dm" +#include "code\game\objects\structures\memorial.dm" #include "code\game\objects\structures\mineral_bath.dm" #include "code\game\objects\structures\mop_bucket.dm" #include "code\game\objects\structures\morgue.dm" +#include "code\game\objects\structures\pedestal.dm" +#include "code\game\objects\structures\pillar.dm" #include "code\game\objects\structures\pit.dm" -#include "code\game\objects\structures\plasticflaps.dm" +#include "code\game\objects\structures\produce_bin.dm" +#include "code\game\objects\structures\quicksand.dm" +#include "code\game\objects\structures\racks.dm" #include "code\game\objects\structures\railing.dm" #include "code\game\objects\structures\rubble.dm" +#include "code\game\objects\structures\rug.dm" #include "code\game\objects\structures\safe.dm" #include "code\game\objects\structures\seaweed.dm" #include "code\game\objects\structures\showcase.dm" -#include "code\game\objects\structures\signs.dm" #include "code\game\objects\structures\skele_stand.dm" -#include "code\game\objects\structures\stasis_cage.dm" +#include "code\game\objects\structures\snowman.dm" +#include "code\game\objects\structures\sofa.dm" +#include "code\game\objects\structures\structure_reagents.dm" +#include "code\game\objects\structures\tables.dm" #include "code\game\objects\structures\tank_dispenser.dm" #include "code\game\objects\structures\target_stake.dm" +#include "code\game\objects\structures\town_bell.dm" #include "code\game\objects\structures\transit_tubes.dm" +#include "code\game\objects\structures\travois.dm" #include "code\game\objects\structures\under_wardrobe.dm" +#include "code\game\objects\structures\wall_cabinet.dm" #include "code\game\objects\structures\wall_frame.dm" +#include "code\game\objects\structures\wall_sconce.dm" #include "code\game\objects\structures\wallframe_spawner.dm" #include "code\game\objects\structures\watercloset.dm" +#include "code\game\objects\structures\well.dm" #include "code\game\objects\structures\windoor_assembly.dm" #include "code\game\objects\structures\window.dm" #include "code\game\objects\structures\window_spawner.dm" +#include "code\game\objects\structures\barrels\barrel.dm" +#include "code\game\objects\structures\barrels\cask.dm" +#include "code\game\objects\structures\barrels\cask_rack.dm" +#include "code\game\objects\structures\beds\bed.dm" +#include "code\game\objects\structures\beds\bedroll.dm" +#include "code\game\objects\structures\beds\mattress.dm" +#include "code\game\objects\structures\beds\rollerbed.dm" +#include "code\game\objects\structures\beds\simple_bed.dm" +#include "code\game\objects\structures\benches\bench.dm" +#include "code\game\objects\structures\benches\lounge.dm" +#include "code\game\objects\structures\benches\pew.dm" +#include "code\game\objects\structures\chairs\chairs.dm" +#include "code\game\objects\structures\chairs\rustic_chairs.dm" +#include "code\game\objects\structures\chairs\wheelchair.dm" +#include "code\game\objects\structures\chemistry\filter_stand.dm" +#include "code\game\objects\structures\chemistry\heater.dm" #include "code\game\objects\structures\crates_lockers\crates.dm" #include "code\game\objects\structures\crates_lockers\largecrate.dm" #include "code\game\objects\structures\crates_lockers\med_crate.dm" @@ -1224,50 +1550,124 @@ #include "code\game\objects\structures\crates_lockers\closets\secure\scientist.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\security.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\service.dm" +#include "code\game\objects\structures\decorations\_decoration.dm" +#include "code\game\objects\structures\decorations\gargoyle.dm" #include "code\game\objects\structures\doors\_door.dm" -#include "code\game\objects\structures\stool_bed_chair_nest\bed.dm" -#include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm" -#include "code\game\objects\structures\stool_bed_chair_nest\stools.dm" -#include "code\game\objects\structures\stool_bed_chair_nest\wheelchair.dm" -#include "code\game\turfs\simulated.dm" +#include "code\game\objects\structures\flora\_flora.dm" +#include "code\game\objects\structures\flora\bush.dm" +#include "code\game\objects\structures\flora\grass.dm" +#include "code\game\objects\structures\flora\plant.dm" +#include "code\game\objects\structures\flora\plant_serde.dm" +#include "code\game\objects\structures\flora\potted.dm" +#include "code\game\objects\structures\flora\stump.dm" +#include "code\game\objects\structures\flora\tree.dm" +#include "code\game\objects\structures\signs\_signs.dm" +#include "code\game\objects\structures\signs\bar_signs.dm" +#include "code\game\objects\structures\signs\decks.dm" +#include "code\game\objects\structures\signs\departments.dm" +#include "code\game\objects\structures\signs\diploma.dm" +#include "code\game\objects\structures\signs\directions.dm" +#include "code\game\objects\structures\signs\flags.dm" +#include "code\game\objects\structures\signs\hangar.dm" +#include "code\game\objects\structures\signs\levels.dm" +#include "code\game\objects\structures\signs\maps.dm" +#include "code\game\objects\structures\signs\paintings.dm" +#include "code\game\objects\structures\signs\plaques.dm" +#include "code\game\objects\structures\signs\warning_signs.dm" #include "code\game\turfs\turf.dm" #include "code\game\turfs\turf_ao.dm" +#include "code\game\turfs\turf_buildmode.dm" #include "code\game\turfs\turf_changing.dm" +#include "code\game\turfs\turf_digging.dm" +#include "code\game\turfs\turf_effects.dm" +#include "code\game\turfs\turf_enter.dm" #include "code\game\turfs\turf_flick_animations.dm" #include "code\game\turfs\turf_fluids.dm" -#include "code\game\turfs\unsimulated.dm" -#include "code\game\turfs\flooring\flooring.dm" -#include "code\game\turfs\flooring\flooring_decals.dm" -#include "code\game\turfs\flooring\flooring_premade.dm" -#include "code\game\turfs\flooring\flooring_shuttle.dm" +#include "code\game\turfs\turf_footsteps.dm" +#include "code\game\turfs\turf_height.dm" +#include "code\game\turfs\turf_material.dm" +#include "code\game\turfs\turf_navigation.dm" +#include "code\game\turfs\turf_ramps.dm" +#include "code\game\turfs\turf_serde.dm" +#include "code\game\turfs\flooring\_flooring.dm" +#include "code\game\turfs\flooring\_flooring_decals.dm" +#include "code\game\turfs\flooring\flooring_carpet.dm" +#include "code\game\turfs\flooring\flooring_concrete.dm" +#include "code\game\turfs\flooring\flooring_grass.dm" +#include "code\game\turfs\flooring\flooring_holowater.dm" +#include "code\game\turfs\flooring\flooring_lava.dm" +#include "code\game\turfs\flooring\flooring_misc.dm" +#include "code\game\turfs\flooring\flooring_mud.dm" +#include "code\game\turfs\flooring\flooring_natural.dm" +#include "code\game\turfs\flooring\flooring_path.dm" +#include "code\game\turfs\flooring\flooring_plating.dm" +#include "code\game\turfs\flooring\flooring_reinforced.dm" +#include "code\game\turfs\flooring\flooring_rock.dm" +#include "code\game\turfs\flooring\flooring_sand.dm" +#include "code\game\turfs\flooring\flooring_snow.dm" +#include "code\game\turfs\flooring\flooring_tiled.dm" +#include "code\game\turfs\flooring\flooring_wood.dm" +#include "code\game\turfs\floors\_floor.dm" +#include "code\game\turfs\floors\floor_acts.dm" +#include "code\game\turfs\floors\floor_attackby.dm" +#include "code\game\turfs\floors\floor_damage.dm" +#include "code\game\turfs\floors\floor_digging.dm" +#include "code\game\turfs\floors\floor_height.dm" +#include "code\game\turfs\floors\floor_icon.dm" +#include "code\game\turfs\floors\floor_layers.dm" +#include "code\game\turfs\floors\floor_materials.dm" +#include "code\game\turfs\floors\floor_serde.dm" +#include "code\game\turfs\floors\subtypes\floor_carpet.dm" +#include "code\game\turfs\floors\subtypes\floor_circuit.dm" +#include "code\game\turfs\floors\subtypes\floor_concrete.dm" +#include "code\game\turfs\floors\subtypes\floor_misc.dm" +#include "code\game\turfs\floors\subtypes\floor_natural.dm" +#include "code\game\turfs\floors\subtypes\floor_path.dm" +#include "code\game\turfs\floors\subtypes\floor_reinforced.dm" +#include "code\game\turfs\floors\subtypes\floor_rock.dm" +#include "code\game\turfs\floors\subtypes\floor_shuttle.dm" +#include "code\game\turfs\floors\subtypes\floor_static.dm" +#include "code\game\turfs\floors\subtypes\floor_tiled.dm" +#include "code\game\turfs\floors\subtypes\floor_wood.dm" +#include "code\game\turfs\initialization\combo.dm" +#include "code\game\turfs\initialization\indoors.dm" #include "code\game\turfs\initialization\init.dm" #include "code\game\turfs\initialization\maintenance.dm" -#include "code\game\turfs\simulated\floor.dm" -#include "code\game\turfs\simulated\floor_acts.dm" -#include "code\game\turfs\simulated\floor_attackby.dm" -#include "code\game\turfs\simulated\floor_damage.dm" -#include "code\game\turfs\simulated\floor_icon.dm" -#include "code\game\turfs\simulated\floor_static.dm" -#include "code\game\turfs\simulated\footsteps.dm" -#include "code\game\turfs\simulated\turf_ocean.dm" -#include "code\game\turfs\simulated\wall_attacks.dm" -#include "code\game\turfs\simulated\wall_icon.dm" -#include "code\game\turfs\simulated\wall_natural.dm" -#include "code\game\turfs\simulated\wall_natural_subtypes.dm" -#include "code\game\turfs\simulated\wall_natural_xenoarch.dm" -#include "code\game\turfs\simulated\wall_shuttle.dm" -#include "code\game\turfs\simulated\wall_types.dm" -#include "code\game\turfs\simulated\walls.dm" +#include "code\game\turfs\open\_open.dm" +#include "code\game\turfs\open\open_sky.dm" #include "code\game\turfs\space\space.dm" #include "code\game\turfs\space\transit.dm" -#include "code\game\turfs\unsimulated\beach.dm" +#include "code\game\turfs\unsimulated\_unsimulated.dm" #include "code\game\turfs\unsimulated\floor.dm" +#include "code\game\turfs\unsimulated\mask.dm" #include "code\game\turfs\unsimulated\walls.dm" +#include "code\game\turfs\walls\_wall.dm" +#include "code\game\turfs\walls\_wall_icon_cache.dm" +#include "code\game\turfs\walls\wall_attacks.dm" +#include "code\game\turfs\walls\wall_brick.dm" +#include "code\game\turfs\walls\wall_engraving.dm" +#include "code\game\turfs\walls\wall_icon.dm" +#include "code\game\turfs\walls\wall_log.dm" +#include "code\game\turfs\walls\wall_material.dm" +#include "code\game\turfs\walls\wall_natural.dm" +#include "code\game\turfs\walls\wall_natural_icon.dm" +#include "code\game\turfs\walls\wall_natural_ramps.dm" +#include "code\game\turfs\walls\wall_natural_subtypes.dm" +#include "code\game\turfs\walls\wall_natural_xenoarch.dm" +#include "code\game\turfs\walls\wall_serde.dm" +#include "code\game\turfs\walls\wall_types.dm" +#include "code\game\turfs\walls\wall_wattle.dm" +#include "code\game\verbs\byond_membership.dm" #include "code\game\verbs\ignore.dm" #include "code\game\verbs\ooc.dm" #include "code\game\verbs\who.dm" -#include "code\js\byjax.dm" -#include "code\js\menus.dm" +#include "code\modules\abstract\_abstract.dm" +#include "code\modules\abstract\abstract_exterior_marker.dm" +#include "code\modules\abstract\abstract_fluid_direction.dm" +#include "code\modules\abstract\abstract_ramp_sculptor.dm" +#include "code\modules\abstract\airlock_helper.dm" +#include "code\modules\abstract\corpse_spawner.dm" +#include "code\modules\abstract\follower.dm" #include "code\modules\acting\acting_items.dm" #include "code\modules\admin\admin.dm" #include "code\modules\admin\admin_attack_log.dm" @@ -1285,27 +1685,29 @@ #include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\map_capture.dm" #include "code\modules\admin\NewBan.dm" +#include "code\modules\admin\panicbunker.dm" #include "code\modules\admin\persistence.dm" #include "code\modules\admin\player_notes.dm" #include "code\modules\admin\player_panel.dm" +#include "code\modules\admin\quantum_mechanic.dm" +#include "code\modules\admin\respawn_as_self.dm" #include "code\modules\admin\spam_prevention.dm" #include "code\modules\admin\ticket.dm" #include "code\modules\admin\topic.dm" -#include "code\modules\admin\buildmode\advance.dm" -#include "code\modules\admin\buildmode\areas.dm" -#include "code\modules\admin\buildmode\basic.dm" -#include "code\modules\admin\buildmode\build_mode.dm" -#include "code\modules\admin\buildmode\buttons.dm" -#include "code\modules\admin\buildmode\click_handler.dm" -#include "code\modules\admin\buildmode\edit.dm" -#include "code\modules\admin\buildmode\ladders.dm" -#include "code\modules\admin\buildmode\light_maker.dm" -#include "code\modules\admin\buildmode\move_into.dm" -#include "code\modules\admin\buildmode\relocate_to.dm" -#include "code\modules\admin\buildmode\room_builder.dm" -#include "code\modules\admin\buildmode\throw_at.dm" +#include "code\modules\admin\buildmode\__click_handler.dm" +#include "code\modules\admin\buildmode\_build_mode.dm" +#include "code\modules\admin\buildmode\_build_mode_buttons.dm" +#include "code\modules\admin\buildmode\_build_mode_interactions.dm" +#include "code\modules\admin\buildmode\mode_advance.dm" +#include "code\modules\admin\buildmode\mode_areas.dm" +#include "code\modules\admin\buildmode\mode_basic.dm" +#include "code\modules\admin\buildmode\mode_edit.dm" +#include "code\modules\admin\buildmode\mode_lighting.dm" +#include "code\modules\admin\buildmode\mode_relocate.dm" +#include "code\modules\admin\buildmode\mode_room_builder.dm" +#include "code\modules\admin\buildmode\mode_throw_at.dm" #include "code\modules\admin\callproc\callproc.dm" -#include "code\modules\admin\DB ban\functions.dm" +#include "code\modules\admin\dbban\functions.dm" #include "code\modules\admin\permissionverbs\permissionedit.dm" #include "code\modules\admin\secrets\admin_secrets\admin_logs.dm" #include "code\modules\admin\secrets\admin_secrets\bombing_list.dm" @@ -1315,13 +1717,10 @@ #include "code\modules\admin\secrets\admin_secrets\list_dna.dm" #include "code\modules\admin\secrets\admin_secrets\list_fingerprints.dm" #include "code\modules\admin\secrets\admin_secrets\move_shuttle.dm" -#include "code\modules\admin\secrets\admin_secrets\prison_warp.dm" #include "code\modules\admin\secrets\admin_secrets\show_ai_laws.dm" #include "code\modules\admin\secrets\admin_secrets\show_crew_manifest.dm" #include "code\modules\admin\secrets\admin_secrets\show_game_mode.dm" #include "code\modules\admin\secrets\admin_secrets\show_law_changes.dm" -#include "code\modules\admin\secrets\admin_secrets\show_signalers.dm" -#include "code\modules\admin\secrets\admin_secrets\toggle_circuits.dm" #include "code\modules\admin\secrets\admin_secrets\toggle_overmap_movement.dm" #include "code\modules\admin\secrets\admin_secrets\traitors_and_objectives.dm" #include "code\modules\admin\secrets\debug\toggle_harddel.dm" @@ -1335,7 +1734,6 @@ #include "code\modules\admin\secrets\fun_secrets\power_all_smes.dm" #include "code\modules\admin\secrets\fun_secrets\triple_ai_mode.dm" #include "code\modules\admin\secrets\fun_secrets\waddle.dm" -#include "code\modules\admin\secrets\investigation\admin_pms.dm" #include "code\modules\admin\secrets\investigation\attack_logs.dm" #include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminjump.dm" @@ -1343,7 +1741,6 @@ #include "code\modules\admin\verbs\adminsay.dm" #include "code\modules\admin\verbs\antag-ooc.dm" #include "code\modules\admin\verbs\atmosdebug.dm" -#include "code\modules\admin\verbs\BrokenInhands.dm" #include "code\modules\admin\verbs\cinematic.dm" #include "code\modules\admin\verbs\custom_event.dm" #include "code\modules\admin\verbs\deadsay.dm" @@ -1363,7 +1760,6 @@ #include "code\modules\admin\verbs\randomverbs.dm" #include "code\modules\admin\verbs\SDQL.dm" #include "code\modules\admin\verbs\ticklag.dm" -#include "code\modules\admin\verbs\trading_verbs.dm" #include "code\modules\admin\verbs\tripAI.dm" #include "code\modules\admin\verbs\SDQL_2\SDQL_2.dm" #include "code\modules\admin\verbs\SDQL_2\SDQL_2_parser.dm" @@ -1381,13 +1777,11 @@ #include "code\modules\alarm\motion_alarm.dm" #include "code\modules\alarm\power_alarm.dm" #include "code\modules\assembly\assembly.dm" -#include "code\modules\assembly\helpers.dm" #include "code\modules\assembly\holder.dm" #include "code\modules\assembly\igniter.dm" #include "code\modules\assembly\infrared.dm" #include "code\modules\assembly\mousetrap.dm" #include "code\modules\assembly\proximity.dm" -#include "code\modules\assembly\shock_kit.dm" #include "code\modules\assembly\signaler.dm" #include "code\modules\assembly\timer.dm" #include "code\modules\assembly\voice.dm" @@ -1419,67 +1813,109 @@ #include "code\modules\atmospherics\components\unary\heat_source.dm" #include "code\modules\atmospherics\components\unary\outlet_injector.dm" #include "code\modules\atmospherics\components\unary\tank.dm" +#include "code\modules\atmospherics\components\unary\temperature_base.dm" #include "code\modules\atmospherics\components\unary\thermal_plate.dm" #include "code\modules\atmospherics\components\unary\unary_base.dm" #include "code\modules\atmospherics\components\unary\vent_pump.dm" #include "code\modules\atmospherics\components\unary\vent_scrubber.dm" -#include "code\modules\augment\active.dm" -#include "code\modules\augment\augment.dm" -#include "code\modules\augment\simple.dm" -#include "code\modules\augment\active\armblades.dm" -#include "code\modules\augment\active\circuit.dm" -#include "code\modules\augment\active\cyberbrain.dm" -#include "code\modules\augment\active\polytool.dm" -#include "code\modules\augment\active\tool\engineering.dm" -#include "code\modules\augment\active\tool\surgical.dm" -#include "code\modules\augment\passive\armor.dm" -#include "code\modules\augment\passive\boost.dm" -#include "code\modules\augment\passive\faulty.dm" -#include "code\modules\augment\passive\nanoaura.dm" -#include "code\modules\augment\passive\boost\muscle.dm" -#include "code\modules\augment\passive\boost\reflex.dm" -#include "code\modules\augment\passive\boost\shooting.dm" -#include "code\modules\augment\passive\faulty\acid_discharge.dm" -#include "code\modules\augment\passive\faulty\elec_discharge.dm" -#include "code\modules\augment\passive\faulty\itchy.dm" -#include "code\modules\augment\passive\faulty\leaky.dm" -#include "code\modules\augment\passive\faulty\locking_thumbs.dm" -#include "code\modules\augment\passive\faulty\noisemaker.dm" -#include "code\modules\augment\passive\faulty\overstimulator.dm" -#include "code\modules\augment\passive\faulty\visual_impairment.dm" -#include "code\modules\awaymissions\artillery.dm" -#include "code\modules\awaymissions\corpse.dm" -#include "code\modules\awaymissions\exile.dm" -#include "code\modules\awaymissions\gateway.dm" -#include "code\modules\awaymissions\loot.dm" -#include "code\modules\awaymissions\pamphlet.dm" -#include "code\modules\awaymissions\trigger.dm" -#include "code\modules\awaymissions\zlevel.dm" -#include "code\modules\blob\blob.dm" -#include "code\modules\butchery\butchery.dm" -#include "code\modules\butchery\remains.dm" +#include "code\modules\backgrounds\_background.dm" +#include "code\modules\backgrounds\background_categories.dm" +#include "code\modules\backgrounds\citizenship\_citizenship.dm" +#include "code\modules\backgrounds\citizenship\citizenship_other.dm" +#include "code\modules\backgrounds\faction\_faction.dm" +#include "code\modules\backgrounds\faction\factions_human.dm" +#include "code\modules\backgrounds\heritage\_heritage.dm" +#include "code\modules\backgrounds\heritage\heritage_hidden.dm" +#include "code\modules\backgrounds\heritage\heritage_human.dm" +#include "code\modules\backgrounds\location\_location.dm" +#include "code\modules\backgrounds\location\_location_events.dm" +#include "code\modules\backgrounds\location\locations_other.dm" +#include "code\modules\backgrounds\religion\_religion.dm" +#include "code\modules\backgrounds\religion\religions_human.dm" +#include "code\modules\banners\__banner.dm" +#include "code\modules\banners\_banner_frame.dm" +#include "code\modules\banners\_banner_symbols.dm" +#include "code\modules\banners\banner_frame_definitions.dm" +#include "code\modules\banners\sign.dm" +#include "code\modules\banners\sign_post.dm" +#include "code\modules\banners\signs_premade.dm" +#include "code\modules\barricade_tape\barricade_tape.dm" +#include "code\modules\barricade_tape\barricade_tape_roll.dm" +#include "code\modules\barricade_tape\barricade_tape_subtypes.dm" +#include "code\modules\barricade_tape\barricade_tape_template.dm" +#include "code\modules\blood\blood.dm" +#include "code\modules\blood\blood_types.dm" +#include "code\modules\blood\blood_types_subtypes.dm" +#include "code\modules\bodytype\_bodytype.dm" +#include "code\modules\bodytype\bodytype_abilities.dm" +#include "code\modules\bodytype\bodytype_crystalline.dm" +#include "code\modules\bodytype\bodytype_helpers.dm" +#include "code\modules\bodytype\bodytype_offsets.dm" +#include "code\modules\bodytype\bodytype_prosthetic.dm" +#include "code\modules\bodytype\bodytype_prosthetic_models.dm" +#include "code\modules\bodytype\bodytype_quadruped.dm" +#include "code\modules\bodytype\bodytype_random.dm" +#include "code\modules\brain_interface\_brain_interface.dm" +#include "code\modules\brain_interface\interface_radio.dm" +#include "code\modules\butchery\_butchery.dm" +#include "code\modules\butchery\butchery_data.dm" +#include "code\modules\butchery\butchery_data_animal.dm" +#include "code\modules\butchery\butchery_data_arthropod.dm" +#include "code\modules\butchery\butchery_data_birds.dm" +#include "code\modules\butchery\butchery_data_fish.dm" +#include "code\modules\butchery\butchery_data_humanoid.dm" +#include "code\modules\butchery\butchery_data_livestock.dm" +#include "code\modules\butchery\butchery_data_misc.dm" +#include "code\modules\butchery\butchery_data_plants.dm" +#include "code\modules\butchery\butchery_data_reptiles.dm" +#include "code\modules\butchery\butchery_hook.dm" +#include "code\modules\butchery\butchery_products.dm" +#include "code\modules\butchery\butchery_products_chopped.dm" +#include "code\modules\butchery\butchery_products_cutlet.dm" +#include "code\modules\butchery\butchery_products_meat.dm" +#include "code\modules\butchery\butchery_products_meat_fish.dm" +#include "code\modules\butchery\butchery_remains.dm" +#include "code\modules\character_info\_character_info.dm" +#include "code\modules\character_info\_comment.dm" +#include "code\modules\character_info\character_info_interface.dm" +#include "code\modules\character_info\comment_mood.dm" +#include "code\modules\chat_filter\_chat_filter.dm" +#include "code\modules\chat_filter\_chat_filter_regex.dm" +#include "code\modules\chat_filter\filter_banned_words.dm" +#include "code\modules\chat_filter\filter_markdown.dm" +#include "code\modules\chatter\_chatter.dm" +#include "code\modules\chatter\chatter_conversation.dm" +#include "code\modules\chatter\chatter_line.dm" +#include "code\modules\chatter\chatter_virtual_radio.dm" #include "code\modules\client\asset_cache.dm" #include "code\modules\client\client_color.dm" +#include "code\modules\client\client_color_definitions.dm" #include "code\modules\client\client_defines.dm" #include "code\modules\client\client_helpers.dm" #include "code\modules\client\client_procs.dm" +#include "code\modules\client\darkmode.dm" +#include "code\modules\client\lobby_handler.dm" #include "code\modules\client\movement.dm" #include "code\modules\client\preferences.dm" -#include "code\modules\client\preferences_savefile.dm" +#include "code\modules\client\preferences_persist.dm" #include "code\modules\client\preferences_spawnpoints.dm" +#include "code\modules\client\preferences_storage.dm" #include "code\modules\client\preferences_toggle.dm" -#include "code\modules\client\ui_style.dm" +#include "code\modules\client\mouse_pointer\_mouse_pointer.dm" +#include "code\modules\client\mouse_pointer\mouse_pointer_definitions.dm" #include "code\modules\client\preference_setup\_defines.dm" #include "code\modules\client\preference_setup\preference_setup.dm" #include "code\modules\client\preference_setup\antagonism\01_candidacy.dm" #include "code\modules\client\preference_setup\antagonism\02_setup.dm" -#include "code\modules\client\preference_setup\background\01_culture.dm" -#include "code\modules\client\preference_setup\background\02_language.dm" -#include "code\modules\client\preference_setup\background\03_records.dm" +#include "code\modules\client\preference_setup\background\01_species.dm" +#include "code\modules\client\preference_setup\background\02_background.dm" +#include "code\modules\client\preference_setup\background\03_language.dm" +#include "code\modules\client\preference_setup\controls\01_keybindings.dm" #include "code\modules\client\preference_setup\general\01_basic.dm" #include "code\modules\client\preference_setup\general\02_body.dm" -#include "code\modules\client\preference_setup\general\03_equipment.dm" -#include "code\modules\client\preference_setup\general\04_flavor.dm" +#include "code\modules\client\preference_setup\general\03_traits.dm" +#include "code\modules\client\preference_setup\general\04_equipment.dm" +#include "code\modules\client\preference_setup\general\05_flavor.dm" #include "code\modules\client\preference_setup\global\01_ui.dm" #include "code\modules\client\preference_setup\global\02_prefixes.dm" #include "code\modules\client\preference_setup\global\03_pai.dm" @@ -1487,8 +1923,6 @@ #include "code\modules\client\preference_setup\global\05_settings.dm" #include "code\modules\client\preference_setup\global\preferences.dm" #include "code\modules\client\preference_setup\global\prefixes.dm" -#include "code\modules\client\preference_setup\laws\laws_pref.dm" -#include "code\modules\client\preference_setup\loadout\_defines.dm" #include "code\modules\client\preference_setup\loadout\gear_tweaks.dm" #include "code\modules\client\preference_setup\loadout\loadout.dm" #include "code\modules\client\preference_setup\loadout\lists\accessories.dm" @@ -1499,22 +1933,59 @@ #include "code\modules\client\preference_setup\loadout\lists\gloves.dm" #include "code\modules\client\preference_setup\loadout\lists\headwear.dm" #include "code\modules\client\preference_setup\loadout\lists\misc.dm" -#include "code\modules\client\preference_setup\loadout\lists\storage.dm" #include "code\modules\client\preference_setup\loadout\lists\suits.dm" -#include "code\modules\client\preference_setup\loadout\lists\tactical.dm" #include "code\modules\client\preference_setup\loadout\lists\uniforms.dm" #include "code\modules\client\preference_setup\loadout\lists\utility.dm" -#include "code\modules\client\preference_setup\matchmaking\matchmaking.dm" -#include "code\modules\client\preference_setup\matchmaking\relations.dm" -#include "code\modules\client\preference_setup\matchmaking\relations_types.dm" #include "code\modules\client\preference_setup\occupation\occupation.dm" #include "code\modules\client\preference_setup\occupation\skill_selection.dm" +#include "code\modules\client\preference_setup\records\00_records.dm" +#include "code\modules\client\preference_setup\records\01_character_info.dm" +#include "code\modules\client\preference_setup\records\02_public_record.dm" +#include "code\modules\client\preference_setup\records\03_medical_record.dm" +#include "code\modules\client\preference_setup\records\04_security_record.dm" +#include "code\modules\client\preference_setup\records\05_general_record.dm" +#include "code\modules\client\preference_setup\records\06_memory.dm" +#include "code\modules\client\ui_styles\_helpers.dm" +#include "code\modules\client\ui_styles\_ui_style.dm" +#include "code\modules\client\ui_styles\_ui_style_states.dm" +#include "code\modules\client\ui_styles\_ui_tooltips.dm" +#include "code\modules\client\ui_styles\ui_style_subtypes.dm" #include "code\modules\clothing\_clothing.dm" +#include "code\modules\clothing\_clothing_accessories.dm" #include "code\modules\clothing\chameleon.dm" -#include "code\modules\clothing\clothing_accessories.dm" +#include "code\modules\clothing\armbands\_armband.dm" +#include "code\modules\clothing\armbands\misc.dm" +#include "code\modules\clothing\armor_attachment\_armor_attachment.dm" +#include "code\modules\clothing\armor_attachment\helmcover.dm" +#include "code\modules\clothing\armor_attachment\plate.dm" +#include "code\modules\clothing\armor_attachment\tags.dm" +#include "code\modules\clothing\badges\_badge.dm" +#include "code\modules\clothing\badges\holobadge.dm" +#include "code\modules\clothing\badges\misc.dm" +#include "code\modules\clothing\belts\suspenders.dm" +#include "code\modules\clothing\clothing_state\_clothing_state.dm" +#include "code\modules\clothing\clothing_state\_clothing_state_modifier.dm" +#include "code\modules\clothing\clothing_state\clothing_state_buttons.dm" +#include "code\modules\clothing\clothing_state\clothing_state_hood.dm" +#include "code\modules\clothing\clothing_state\clothing_state_rolled.dm" +#include "code\modules\clothing\clothing_state\clothing_state_sleeves.dm" +#include "code\modules\clothing\clothing_state\clothing_state_tucked.dm" +#include "code\modules\clothing\clothing_state\clothing_state_untied.dm" +#include "code\modules\clothing\costumes\_costume.dm" +#include "code\modules\clothing\costumes\centcomm.dm" +#include "code\modules\clothing\costumes\misc.dm" +#include "code\modules\clothing\costumes\rank.dm" +#include "code\modules\clothing\dresses\_dress.dm" +#include "code\modules\clothing\dresses\gown.dm" +#include "code\modules\clothing\dresses\job.dm" +#include "code\modules\clothing\dresses\maxi.dm" +#include "code\modules\clothing\dresses\misc.dm" +#include "code\modules\clothing\dresses\role.dm" +#include "code\modules\clothing\dresses\short.dm" +#include "code\modules\clothing\dresses\sundress.dm" +#include "code\modules\clothing\dresses\wedding.dm" #include "code\modules\clothing\ears\_ears.dm" #include "code\modules\clothing\ears\earrings.dm" -#include "code\modules\clothing\ears\headphones.dm" #include "code\modules\clothing\glasses\_glasses.dm" #include "code\modules\clothing\glasses\blindfolds.dm" #include "code\modules\clothing\glasses\eyepatch.dm" @@ -1524,20 +1995,36 @@ #include "code\modules\clothing\glasses\sunglasses.dm" #include "code\modules\clothing\glasses\thermals.dm" #include "code\modules\clothing\gloves\_gloves.dm" +#include "code\modules\clothing\gloves\armguards.dm" #include "code\modules\clothing\gloves\boxing.dm" #include "code\modules\clothing\gloves\color.dm" #include "code\modules\clothing\gloves\latex.dm" #include "code\modules\clothing\gloves\miscellaneous.dm" #include "code\modules\clothing\gloves\thick.dm" +#include "code\modules\clothing\gloves\jewelry\bracelet.dm" +#include "code\modules\clothing\gloves\jewelry\rings\_ring.dm" +#include "code\modules\clothing\gloves\jewelry\rings\ring_effect.dm" +#include "code\modules\clothing\gloves\jewelry\rings\ring_misc.dm" +#include "code\modules\clothing\gloves\jewelry\rings\ring_reagent.dm" +#include "code\modules\clothing\gloves\jewelry\rings\ring_seal.dm" #include "code\modules\clothing\head\_head.dm" #include "code\modules\clothing\head\collectable.dm" +#include "code\modules\clothing\head\earmuffs.dm" #include "code\modules\clothing\head\fated_key.dm" #include "code\modules\clothing\head\hardhat.dm" +#include "code\modules\clothing\head\headphones.dm" #include "code\modules\clothing\head\helmet.dm" #include "code\modules\clothing\head\jobs.dm" #include "code\modules\clothing\head\misc.dm" #include "code\modules\clothing\head\misc_special.dm" +#include "code\modules\clothing\head\security.dm" #include "code\modules\clothing\head\soft_caps.dm" +#include "code\modules\clothing\head\wizard.dm" +#include "code\modules\clothing\jumpsuits\_jumpsuit.dm" +#include "code\modules\clothing\jumpsuits\color.dm" +#include "code\modules\clothing\jumpsuits\job.dm" +#include "code\modules\clothing\jumpsuits\jumpskirt.dm" +#include "code\modules\clothing\jumpsuits\misc.dm" #include "code\modules\clothing\masks\_mask.dm" #include "code\modules\clothing\masks\boxing.dm" #include "code\modules\clothing\masks\breath.dm" @@ -1548,15 +2035,65 @@ #include "code\modules\clothing\masks\monitor.dm" #include "code\modules\clothing\masks\smokable.dm" #include "code\modules\clothing\masks\voice.dm" -#include "code\modules\clothing\rings\_ring.dm" -#include "code\modules\clothing\rings\material.dm" -#include "code\modules\clothing\rings\rings.dm" +#include "code\modules\clothing\medals\medals.dm" +#include "code\modules\clothing\misc\dog_tags.dm" +#include "code\modules\clothing\misc\insignia.dm" +#include "code\modules\clothing\misc\venter.dm" +#include "code\modules\clothing\neck\_neck.dm" +#include "code\modules\clothing\neck\bowties.dm" +#include "code\modules\clothing\neck\brace.dm" +#include "code\modules\clothing\neck\prayer_beads.dm" +#include "code\modules\clothing\neck\scarf.dm" +#include "code\modules\clothing\neck\stethoscope.dm" +#include "code\modules\clothing\neck\ties.dm" +#include "code\modules\clothing\neck\necklace\__necklace.dm" +#include "code\modules\clothing\neck\necklace\_pendant.dm" +#include "code\modules\clothing\neck\necklace\necklaces.dm" +#include "code\modules\clothing\neck\necklace\pendant_locket.dm" +#include "code\modules\clothing\neck\necklace\pendant_random.dm" +#include "code\modules\clothing\neck\necklace\pendant_setting.dm" +#include "code\modules\clothing\pants\_pants.dm" +#include "code\modules\clothing\pants\detective.dm" +#include "code\modules\clothing\pants\misc.dm" +#include "code\modules\clothing\pants\pajamas.dm" +#include "code\modules\clothing\pants\pants_casual.dm" +#include "code\modules\clothing\pants\pants_formal.dm" +#include "code\modules\clothing\pants\scrubs.dm" +#include "code\modules\clothing\pants\shorts.dm" +#include "code\modules\clothing\pants\slacks.dm" +#include "code\modules\clothing\permits\_permit.dm" +#include "code\modules\clothing\sensors\_sensor.dm" +#include "code\modules\clothing\sensors\buddytag.dm" +#include "code\modules\clothing\sensors\vitals_sensor.dm" +#include "code\modules\clothing\shirts\_shirts.dm" +#include "code\modules\clothing\shirts\blouse.dm" +#include "code\modules\clothing\shirts\flannel.dm" +#include "code\modules\clothing\shirts\formal.dm" +#include "code\modules\clothing\shirts\hawaii.dm" +#include "code\modules\clothing\shirts\misc.dm" +#include "code\modules\clothing\shirts\pajamas.dm" +#include "code\modules\clothing\shirts\polo.dm" +#include "code\modules\clothing\shirts\scrubs.dm" +#include "code\modules\clothing\shirts\sweaters.dm" +#include "code\modules\clothing\shirts\syndicate.dm" +#include "code\modules\clothing\shirts\toga.dm" +#include "code\modules\clothing\shirts\tshirt.dm" +#include "code\modules\clothing\shirts\tunics.dm" +#include "code\modules\clothing\shirts\ubac.dm" #include "code\modules\clothing\shoes\_shoes.dm" #include "code\modules\clothing\shoes\colour.dm" #include "code\modules\clothing\shoes\craftable.dm" #include "code\modules\clothing\shoes\jobs.dm" +#include "code\modules\clothing\shoes\legguards.dm" #include "code\modules\clothing\shoes\magboots.dm" +#include "code\modules\clothing\shoes\misc.dm" #include "code\modules\clothing\shoes\miscellaneous.dm" +#include "code\modules\clothing\shoes\winterboots.dm" +#include "code\modules\clothing\skirts\_skirt.dm" +#include "code\modules\clothing\skirts\job.dm" +#include "code\modules\clothing\skirts\misc.dm" +#include "code\modules\clothing\skirts\plaid.dm" +#include "code\modules\clothing\skirts\pleated.dm" #include "code\modules\clothing\spacesuits\breaches.dm" #include "code\modules\clothing\spacesuits\miscellaneous.dm" #include "code\modules\clothing\spacesuits\spacesuits.dm" @@ -1568,8 +2105,8 @@ #include "code\modules\clothing\spacesuits\rig\rig_wiring.dm" #include "code\modules\clothing\spacesuits\rig\modules\combat.dm" #include "code\modules\clothing\spacesuits\rig\modules\computer.dm" +#include "code\modules\clothing\spacesuits\rig\modules\infiltration.dm" #include "code\modules\clothing\spacesuits\rig\modules\modules.dm" -#include "code\modules\clothing\spacesuits\rig\modules\ninja.dm" #include "code\modules\clothing\spacesuits\rig\modules\utility.dm" #include "code\modules\clothing\spacesuits\rig\modules\vision.dm" #include "code\modules\clothing\spacesuits\rig\suits\combat.dm" @@ -1580,19 +2117,26 @@ #include "code\modules\clothing\spacesuits\void\misc.dm" #include "code\modules\clothing\spacesuits\void\station.dm" #include "code\modules\clothing\spacesuits\void\void.dm" -#include "code\modules\clothing\spacesuits\void\wizard.dm" #include "code\modules\clothing\suits\_suit.dm" +#include "code\modules\clothing\suits\_suit_hood.dm" #include "code\modules\clothing\suits\alien.dm" #include "code\modules\clothing\suits\bio.dm" -#include "code\modules\clothing\suits\fated_mantle.dm" +#include "code\modules\clothing\suits\cloaks.dm" +#include "code\modules\clothing\suits\dashiki.dm" +#include "code\modules\clothing\suits\hooded_cloak.dm" #include "code\modules\clothing\suits\jobs.dm" #include "code\modules\clothing\suits\labcoat.dm" +#include "code\modules\clothing\suits\mantle.dm" +#include "code\modules\clothing\suits\misc.dm" #include "code\modules\clothing\suits\miscellaneous.dm" #include "code\modules\clothing\suits\poncho.dm" -#include "code\modules\clothing\suits\storage.dm" +#include "code\modules\clothing\suits\robes.dm" +#include "code\modules\clothing\suits\security.dm" +#include "code\modules\clothing\suits\shouldercapes.dm" +#include "code\modules\clothing\suits\straightjacket.dm" #include "code\modules\clothing\suits\toggles.dm" #include "code\modules\clothing\suits\utility.dm" -#include "code\modules\clothing\suits\wiz_robe.dm" +#include "code\modules\clothing\suits\wizard.dm" #include "code\modules\clothing\suits\armor\_armor.dm" #include "code\modules\clothing\suits\armor\adminbus_and_memes.dm" #include "code\modules\clothing\suits\armor\bulletproof.dm" @@ -1604,55 +2148,59 @@ #include "code\modules\clothing\suits\armor\riot.dm" #include "code\modules\clothing\suits\armor\security.dm" #include "code\modules\clothing\suits\armor\vest.dm" -#include "code\modules\clothing\under\_under.dm" -#include "code\modules\clothing\under\casual_pants.dm" -#include "code\modules\clothing\under\color.dm" -#include "code\modules\clothing\under\fated_robes.dm" -#include "code\modules\clothing\under\formal_pants.dm" -#include "code\modules\clothing\under\miscellaneous.dm" -#include "code\modules\clothing\under\shorts.dm" -#include "code\modules\clothing\under\skirts.dm" -#include "code\modules\clothing\under\syndicate.dm" -#include "code\modules\clothing\under\accessories\accessory.dm" -#include "code\modules\clothing\under\accessories\armband.dm" -#include "code\modules\clothing\under\accessories\armor.dm" -#include "code\modules\clothing\under\accessories\badges.dm" -#include "code\modules\clothing\under\accessories\buddytag.dm" -#include "code\modules\clothing\under\accessories\chaplaininsignia.dm" -#include "code\modules\clothing\under\accessories\cloaks.dm" -#include "code\modules\clothing\under\accessories\clothing.dm" -#include "code\modules\clothing\under\accessories\holster.dm" -#include "code\modules\clothing\under\accessories\lockets.dm" -#include "code\modules\clothing\under\accessories\medals.dm" -#include "code\modules\clothing\under\accessories\stethoscope.dm" -#include "code\modules\clothing\under\accessories\storage.dm" -#include "code\modules\clothing\under\accessories\ties.dm" -#include "code\modules\clothing\under\jobs\civilian.dm" -#include "code\modules\clothing\under\jobs\engineering.dm" -#include "code\modules\clothing\under\jobs\medsci.dm" -#include "code\modules\clothing\under\jobs\security.dm" +#include "code\modules\clothing\suits\armor\forged\_forged.dm" +#include "code\modules\clothing\suits\armor\forged\banded.dm" +#include "code\modules\clothing\suits\armor\forged\brigandine.dm" +#include "code\modules\clothing\suits\armor\forged\cuirass.dm" +#include "code\modules\clothing\suits\armor\forged\plate.dm" +#include "code\modules\clothing\suits\jackets\_jacket.dm" +#include "code\modules\clothing\suits\jackets\hoodies.dm" +#include "code\modules\clothing\suits\jackets\job.dm" +#include "code\modules\clothing\suits\jackets\letterman.dm" +#include "code\modules\clothing\suits\jackets\medical.dm" +#include "code\modules\clothing\suits\jackets\misc.dm" +#include "code\modules\clothing\suits\jackets\track.dm" +#include "code\modules\clothing\suits\jackets\waistcoat.dm" +#include "code\modules\clothing\suits\jackets\wintercoat.dm" +#include "code\modules\clothing\tail\_tail.dm" #include "code\modules\clothing\underwear\base.dm" +#include "code\modules\clothing\webbing\_webbing.dm" +#include "code\modules\clothing\webbing\drop_pouches.dm" +#include "code\modules\clothing\webbing\holster.dm" +#include "code\modules\clothing\webbing\knifeharness.dm" +#include "code\modules\clothing\webbing\misc.dm" +#include "code\modules\clothing\webbing\pouches.dm" +#include "code\modules\clothing\webbing\vest.dm" #include "code\modules\codex\codex_atom.dm" #include "code\modules\codex\codex_client.dm" #include "code\modules\codex\codex_implant.dm" #include "code\modules\codex\codex_mob.dm" +#include "code\modules\codex\codex_scannable.dm" #include "code\modules\codex\categories\_category.dm" +#include "code\modules\codex\categories\_materials.dm" +#include "code\modules\codex\categories\category_categories.dm" #include "code\modules\codex\categories\category_cocktails.dm" #include "code\modules\codex\categories\category_cultures.dm" +#include "code\modules\codex\categories\category_fauna.dm" +#include "code\modules\codex\categories\category_flora.dm" #include "code\modules\codex\categories\category_fusion_reaction.dm" +#include "code\modules\codex\categories\category_guides.dm" #include "code\modules\codex\categories\category_languages.dm" +#include "code\modules\codex\categories\category_phenomena.dm" #include "code\modules\codex\categories\category_reactions.dm" #include "code\modules\codex\categories\category_recipes.dm" #include "code\modules\codex\categories\category_skills.dm" #include "code\modules\codex\categories\category_species.dm" #include "code\modules\codex\categories\category_substances.dm" #include "code\modules\codex\categories\category_surgery.dm" +#include "code\modules\codex\categories\category_uncategorized.dm" #include "code\modules\codex\entries\_codex_entry.dm" #include "code\modules\codex\entries\armor.dm" #include "code\modules\codex\entries\atmospherics.dm" #include "code\modules\codex\entries\clothing.dm" #include "code\modules\codex\entries\codex.dm" #include "code\modules\codex\entries\engineering.dm" +#include "code\modules\codex\entries\guides.dm" #include "code\modules\codex\entries\guns.dm" #include "code\modules\codex\entries\jukebox.dm" #include "code\modules\codex\entries\machinery.dm" @@ -1660,40 +2208,67 @@ #include "code\modules\codex\entries\misc.dm" #include "code\modules\codex\entries\mobs.dm" #include "code\modules\codex\entries\paperwork.dm" -#include "code\modules\codex\entries\spells.dm" #include "code\modules\codex\entries\stacks.dm" #include "code\modules\codex\entries\storage.dm" #include "code\modules\codex\entries\structures.dm" #include "code\modules\codex\entries\tools.dm" #include "code\modules\codex\entries\turfs.dm" #include "code\modules\codex\entries\weapons.dm" -#include "code\modules\crafting\_crafting_holder.dm" -#include "code\modules\crafting\_crafting_stage.dm" -#include "code\modules\crafting\crafting_recipes\bot_crafting\crafting_ed209.dm" -#include "code\modules\crafting\crafting_recipes\bot_crafting\crafting_farmbot.dm" -#include "code\modules\crafting\crafting_recipes\bot_crafting\crafting_floorbot.dm" -#include "code\modules\crafting\crafting_recipes\bot_crafting\crafting_janibot.dm" -#include "code\modules\crafting\crafting_recipes\bot_crafting\crafting_medibot.dm" -#include "code\modules\crafting\crafting_recipes\bot_crafting\crafting_secbot.dm" -#include "code\modules\crafting\crafting_recipes\gun_crafting\crafting_cannon.dm" -#include "code\modules\crafting\crafting_recipes\gun_crafting\crafting_coilgun.dm" -#include "code\modules\crafting\crafting_recipes\gun_crafting\crafting_zipgun.dm" -#include "code\modules\crafting\crafting_recipes\improvised_crafting\crafting_butterflyknife.dm" -#include "code\modules\crafting\crafting_recipes\improvised_crafting\crafting_crossbow.dm" -#include "code\modules\crafting\crafting_recipes\improvised_crafting\crafting_spear_prod.dm" -#include "code\modules\culture_descriptor\_culture.dm" -#include "code\modules\culture_descriptor\culture\_culture.dm" -#include "code\modules\culture_descriptor\culture\cultures_hidden.dm" -#include "code\modules\culture_descriptor\culture\cultures_human.dm" -#include "code\modules\culture_descriptor\faction\_faction.dm" -#include "code\modules\culture_descriptor\faction\factions_human.dm" -#include "code\modules\culture_descriptor\location\_location.dm" -#include "code\modules\culture_descriptor\location\_location_events.dm" -#include "code\modules\culture_descriptor\location\locations_other.dm" -#include "code\modules\culture_descriptor\religion\_religion.dm" -#include "code\modules\culture_descriptor\religion\religions_human.dm" +#include "code\modules\crafting\handmade_fancy.dm" +#include "code\modules\crafting\handmade_items.dm" +#include "code\modules\crafting\forging\bellows.dm" +#include "code\modules\crafting\metalwork\metalwork_items.dm" +#include "code\modules\crafting\pottery\pottery_moulds.dm" +#include "code\modules\crafting\pottery\pottery_structures.dm" +#include "code\modules\crafting\slapcrafting\_crafting_holder.dm" +#include "code\modules\crafting\slapcrafting\_crafting_stage.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\bot_crafting\crafting_ed209.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\bot_crafting\crafting_farmbot.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\bot_crafting\crafting_floorbot.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\bot_crafting\crafting_janibot.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\bot_crafting\crafting_medibot.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\bot_crafting\crafting_secbot.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\gun_crafting\crafting_cannon.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\gun_crafting\crafting_coilgun.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\gun_crafting\crafting_zipgun.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\improvised_crafting\crafting_buckler.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\improvised_crafting\crafting_butterflyknife.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\improvised_crafting\crafting_crossbow.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\improvised_crafting\crafting_spear_prod.dm" +#include "code\modules\crafting\slapcrafting\crafting_recipes\tool_crafting\_tool_crafting.dm" +#include "code\modules\crafting\stack_recipes\_recipe.dm" +#include "code\modules\crafting\stack_recipes\_recipe_getter.dm" +#include "code\modules\crafting\stack_recipes\recipe_structures.dm" +#include "code\modules\crafting\stack_recipes\recipes_bricks.dm" +#include "code\modules\crafting\stack_recipes\recipes_cardstock.dm" +#include "code\modules\crafting\stack_recipes\recipes_coins.dm" +#include "code\modules\crafting\stack_recipes\recipes_fodder.dm" +#include "code\modules\crafting\stack_recipes\recipes_grass.dm" +#include "code\modules\crafting\stack_recipes\recipes_hardness.dm" +#include "code\modules\crafting\stack_recipes\recipes_hardness_integrity.dm" +#include "code\modules\crafting\stack_recipes\recipes_items.dm" +#include "code\modules\crafting\stack_recipes\recipes_logs.dm" +#include "code\modules\crafting\stack_recipes\recipes_opacity.dm" +#include "code\modules\crafting\stack_recipes\recipes_panels.dm" +#include "code\modules\crafting\stack_recipes\recipes_planks.dm" +#include "code\modules\crafting\stack_recipes\recipes_reinforced.dm" +#include "code\modules\crafting\stack_recipes\recipes_rods.dm" +#include "code\modules\crafting\stack_recipes\recipes_soft.dm" +#include "code\modules\crafting\stack_recipes\recipes_stacks.dm" +#include "code\modules\crafting\stack_recipes\recipes_steel.dm" +#include "code\modules\crafting\stack_recipes\recipes_textiles.dm" +#include "code\modules\crafting\stack_recipes\recipes_turfs.dm" +#include "code\modules\crafting\working\_working.dm" +#include "code\modules\crafting\working\butter_churn.dm" +#include "code\modules\crafting\working\quern.dm" +#include "code\modules\crafting\working\textiles\loom.dm" +#include "code\modules\crafting\working\textiles\spinning_wheel.dm" +#include "code\modules\crafting\working\textiles\twisting_bench.dm" +#include "code\modules\decoration\_decoration.dm" +#include "code\modules\decoration\decoration_inset.dm" +#include "code\modules\decoration\decoration_item.dm" +#include "code\modules\decoration\decoration_setting.dm" #include "code\modules\departments\department.dm" -#include "code\modules\departments\standarddepartments.dm" #include "code\modules\detectivework\forensics.dm" #include "code\modules\detectivework\evidence\_evidence_holder.dm" #include "code\modules\detectivework\evidence\_evidence_type.dm" @@ -1739,17 +2314,21 @@ #include "code\modules\emotes\emote_define.dm" #include "code\modules\emotes\emote_mob.dm" #include "code\modules\emotes\definitions\_mob.dm" -#include "code\modules\emotes\definitions\_species.dm" #include "code\modules\emotes\definitions\audible.dm" -#include "code\modules\emotes\definitions\human.dm" -#include "code\modules\emotes\definitions\slime.dm" +#include "code\modules\emotes\definitions\audible_cough.dm" +#include "code\modules\emotes\definitions\audible_scream.dm" +#include "code\modules\emotes\definitions\audible_slap.dm" +#include "code\modules\emotes\definitions\audible_snap.dm" +#include "code\modules\emotes\definitions\audible_sneeze.dm" +#include "code\modules\emotes\definitions\audible_whistle.dm" +#include "code\modules\emotes\definitions\exertion.dm" #include "code\modules\emotes\definitions\synthetics.dm" +#include "code\modules\emotes\definitions\tail.dm" #include "code\modules\emotes\definitions\visible.dm" #include "code\modules\error_handler\error_handler.dm" -#include "code\modules\error_handler\error_reporting.dm" #include "code\modules\error_handler\error_viewer.dm" +#include "code\modules\events\ailments.dm" #include "code\modules\events\apc_damage.dm" -#include "code\modules\events\blob.dm" #include "code\modules\events\brain_expansion.dm" #include "code\modules\events\brand_intelligence.dm" #include "code\modules\events\camera_damage.dm" @@ -1765,7 +2344,6 @@ #include "code\modules\events\event_dynamic.dm" #include "code\modules\events\gravity.dm" #include "code\modules\events\grid_check.dm" -#include "code\modules\events\inertial_damper.dm" #include "code\modules\events\infestation.dm" #include "code\modules\events\ion_storm.dm" #include "code\modules\events\location_event.dm" @@ -1787,10 +2365,11 @@ #include "code\modules\events\toilets.dm" #include "code\modules\events\trivial_news.dm" #include "code\modules\events\wallrot.dm" -#include "code\modules\ext_scripts\irc.dm" +#include "code\modules\events\wormholes.dm" #include "code\modules\fabrication\__fabricator_defines.dm" #include "code\modules\fabrication\_fabricator.dm" #include "code\modules\fabrication\_fabricator_build_order.dm" +#include "code\modules\fabrication\fabricator_bioprinter.dm" #include "code\modules\fabrication\fabricator_books.dm" #include "code\modules\fabrication\fabricator_build.dm" #include "code\modules\fabrication\fabricator_food.dm" @@ -1800,17 +2379,19 @@ #include "code\modules\fabrication\fabricator_intake.dm" #include "code\modules\fabrication\fabricator_microlathe.dm" #include "code\modules\fabrication\fabricator_pipe.dm" +#include "code\modules\fabrication\fabricator_presets.dm" #include "code\modules\fabrication\fabricator_protolathe.dm" #include "code\modules\fabrication\fabricator_robotics.dm" #include "code\modules\fabrication\fabricator_textile.dm" #include "code\modules\fabrication\fabricator_topic.dm" #include "code\modules\fabrication\fabricator_ui.dm" +#include "code\modules\fabrication\recycler.dm" #include "code\modules\fabrication\designs\_design.dm" +#include "code\modules\fabrication\designs\general\designs_arms_ammo.dm" #include "code\modules\fabrication\designs\general\designs_devices_components.dm" #include "code\modules\fabrication\designs\general\designs_engineering.dm" #include "code\modules\fabrication\designs\general\designs_general.dm" #include "code\modules\fabrication\designs\general\designs_medical.dm" -#include "code\modules\fabrication\designs\general\designs_textiles.dm" #include "code\modules\fabrication\designs\general\designs_tools.dm" #include "code\modules\fabrication\designs\imprinter\_designs_imprinter.dm" #include "code\modules\fabrication\designs\imprinter\designs_ai_modules.dm" @@ -1818,7 +2399,10 @@ #include "code\modules\fabrication\designs\imprinter\designs_exosuit_software.dm" #include "code\modules\fabrication\designs\imprinter\designs_misc_circuits.dm" #include "code\modules\fabrication\designs\industrial\_designs_industrial.dm" +#include "code\modules\fabrication\designs\industrial\designs_armour.dm" #include "code\modules\fabrication\designs\industrial\designs_exosuit_components.dm" +#include "code\modules\fabrication\designs\meat\_designs_meat.dm" +#include "code\modules\fabrication\designs\meat\designs_organs.dm" #include "code\modules\fabrication\designs\micro\designs_cutlery.dm" #include "code\modules\fabrication\designs\micro\designs_glasses.dm" #include "code\modules\fabrication\designs\pipe\device_pipe_datums.dm" @@ -1835,32 +2419,143 @@ #include "code\modules\fabrication\designs\protolathe\designs_machine_intelligence.dm" #include "code\modules\fabrication\designs\protolathe\designs_misc.dm" #include "code\modules\fabrication\designs\protolathe\designs_power_cells.dm" -#include "code\modules\fabrication\designs\protolathe\designs_prosthetics.dm" #include "code\modules\fabrication\designs\protolathe\designs_stock.dm" #include "code\modules\fabrication\designs\protolathe\designs_tools.dm" #include "code\modules\fabrication\designs\protolathe\designs_weapons.dm" #include "code\modules\fabrication\designs\replicator\designs_food.dm" #include "code\modules\fabrication\designs\robotics\_designs_robotics.dm" -#include "code\modules\fabrication\designs\robotics\designs_augments.dm" #include "code\modules\fabrication\designs\robotics\designs_misc.dm" +#include "code\modules\fabrication\designs\robotics\designs_organs.dm" #include "code\modules\fabrication\designs\robotics\designs_prosthetics.dm" #include "code\modules\fabrication\designs\robotics\designs_robot_components.dm" -#include "code\modules\flufftext\Dreaming.dm" -#include "code\modules\flufftext\TextFilters.dm" -#include "code\modules\food\recipes_microwave.dm" +#include "code\modules\fabrication\designs\textile\_textile.dm" +#include "code\modules\fabrication\designs\textile\armor.dm" +#include "code\modules\fabrication\designs\textile\footwear.dm" +#include "code\modules\fabrication\designs\textile\gimmick.dm" +#include "code\modules\fabrication\designs\textile\job.dm" +#include "code\modules\fabrication\designs\textile\overwear.dm" +#include "code\modules\fabrication\designs\textile\protective.dm" +#include "code\modules\fabrication\designs\textile\space.dm" +#include "code\modules\fabrication\designs\textile\storage.dm" +#include "code\modules\fishing\bait.dm" +#include "code\modules\fishing\fishing_line.dm" +#include "code\modules\fishing\fishing_rod.dm" +#include "code\modules\fluids\_fluid.dm" +#include "code\modules\fluids\fluid_flood.dm" +#include "code\modules\fluids\fluid_mapped.dm" +#include "code\modules\food\assembled.dm" +#include "code\modules\food\nuggets.dm" +#include "code\modules\food\cooking\_recipe.dm" +#include "code\modules\food\cooking\cooking_vessels\_cooking_vessel.dm" +#include "code\modules\food\cooking\cooking_vessels\baking_dish.dm" +#include "code\modules\food\cooking\cooking_vessels\pot.dm" +#include "code\modules\food\cooking\cooking_vessels\skillet.dm" +#include "code\modules\food\cooking\recipes\recipe_assembled.dm" +#include "code\modules\food\cooking\recipes\recipe_baked.dm" +#include "code\modules\food\cooking\recipes\recipe_boiled.dm" +#include "code\modules\food\cooking\recipes\recipe_fried.dm" +#include "code\modules\food\cooking\recipes\recipe_grilled.dm" +#include "code\modules\food\cooking\recipes\recipe_mixed.dm" +#include "code\modules\food\cooking\recipes\recipe_pasta.dm" +#include "code\modules\food\cooking\recipes\recipe_soup.dm" +#include "code\modules\food\cooking\recipes\recipe_soup_chili.dm" +#include "code\modules\food\cooking\recipes\recipe_soup_curry.dm" +#include "code\modules\food\cooking\recipes\recipe_soup_noodle.dm" +#include "code\modules\food\cooking\recipes\recipe_soup_simple.dm" +#include "code\modules\food\cooking\recipes\recipe_soup_stew.dm" +#include "code\modules\food\cooking\recipes\recipe_soup_stock.dm" +#include "code\modules\food\cooking\recipes\recipe_steamed.dm" +#include "code\modules\food\cooking\recipes\recipe_tossed.dm" +#include "code\modules\food\cooking\recipes\recipes_microwave.dm" +#include "code\modules\food\plates\_plate.dm" +#include "code\modules\food\plates\plate_tray.dm" +#include "code\modules\food\utensils\_utensil.dm" +#include "code\modules\food\utensils\utensil_chopsticks.dm" +#include "code\modules\food\utensils\utensil_fork.dm" +#include "code\modules\food\utensils\utensil_hybrid.dm" +#include "code\modules\food\utensils\utensil_knife.dm" +#include "code\modules\food\utensils\utensil_spoon.dm" #include "code\modules\games\boardgame.dm" #include "code\modules\games\cardemon.dm" #include "code\modules\games\cards.dm" #include "code\modules\games\cards_cag.dm" #include "code\modules\games\spaceball_cards.dm" #include "code\modules\games\tarot.dm" -#include "code\modules\genetics\side_effects.dm" +#include "code\modules\gemstones\_gemstone.dm" +#include "code\modules\gemstones\gemstone_cuts.dm" +#include "code\modules\genetics\_gene.dm" +#include "code\modules\genetics\plants\_gene_plant.dm" +#include "code\modules\genetics\plants\_plant_trait.dm" +#include "code\modules\genetics\plants\gene_atmosphere.dm" +#include "code\modules\genetics\plants\gene_biochemistry.dm" +#include "code\modules\genetics\plants\gene_diet.dm" +#include "code\modules\genetics\plants\gene_environment.dm" +#include "code\modules\genetics\plants\gene_fruit.dm" +#include "code\modules\genetics\plants\gene_hardiness.dm" +#include "code\modules\genetics\plants\gene_metabolism.dm" +#include "code\modules\genetics\plants\gene_output.dm" +#include "code\modules\genetics\plants\gene_pigment.dm" +#include "code\modules\genetics\plants\gene_special.dm" +#include "code\modules\genetics\plants\gene_structure.dm" +#include "code\modules\genetics\plants\gene_vigour.dm" +#include "code\modules\genetics\plants\trait_alter_temp.dm" +#include "code\modules\genetics\plants\trait_biolum.dm" +#include "code\modules\genetics\plants\trait_biolum_colour.dm" +#include "code\modules\genetics\plants\trait_carnivorous.dm" +#include "code\modules\genetics\plants\trait_chems.dm" +#include "code\modules\genetics\plants\trait_consume_gasses.dm" +#include "code\modules\genetics\plants\trait_endurance.dm" +#include "code\modules\genetics\plants\trait_explosive.dm" +#include "code\modules\genetics\plants\trait_exude_gasses.dm" +#include "code\modules\genetics\plants\trait_flesh_colour.dm" +#include "code\modules\genetics\plants\trait_harvest_repeat.dm" +#include "code\modules\genetics\plants\trait_heat_tolerance.dm" +#include "code\modules\genetics\plants\trait_highkpa_tolerance.dm" +#include "code\modules\genetics\plants\trait_ideal_heat.dm" +#include "code\modules\genetics\plants\trait_ideal_light.dm" +#include "code\modules\genetics\plants\trait_immutable.dm" +#include "code\modules\genetics\plants\trait_juicy.dm" +#include "code\modules\genetics\plants\trait_large.dm" +#include "code\modules\genetics\plants\trait_leaves_colour.dm" +#include "code\modules\genetics\plants\trait_light_tolerance.dm" +#include "code\modules\genetics\plants\trait_lowkpa_tolerance.dm" +#include "code\modules\genetics\plants\trait_maturation.dm" +#include "code\modules\genetics\plants\trait_nutrient_consumption.dm" +#include "code\modules\genetics\plants\trait_parasite.dm" +#include "code\modules\genetics\plants\trait_pest_tolerance.dm" +#include "code\modules\genetics\plants\trait_photosynthesis.dm" +#include "code\modules\genetics\plants\trait_plant_colour.dm" +#include "code\modules\genetics\plants\trait_plant_icon.dm" +#include "code\modules\genetics\plants\trait_pollen.dm" +#include "code\modules\genetics\plants\trait_potency.dm" +#include "code\modules\genetics\plants\trait_produces_power.dm" +#include "code\modules\genetics\plants\trait_product_colour.dm" +#include "code\modules\genetics\plants\trait_product_icon.dm" +#include "code\modules\genetics\plants\trait_product_type.dm" +#include "code\modules\genetics\plants\trait_production.dm" +#include "code\modules\genetics\plants\trait_requires_nutrients.dm" +#include "code\modules\genetics\plants\trait_requires_water.dm" +#include "code\modules\genetics\plants\trait_slice_amount.dm" +#include "code\modules\genetics\plants\trait_slice_product.dm" +#include "code\modules\genetics\plants\trait_spread.dm" +#include "code\modules\genetics\plants\trait_stings.dm" +#include "code\modules\genetics\plants\trait_teleporting.dm" +#include "code\modules\genetics\plants\trait_toxins_tolerance.dm" +#include "code\modules\genetics\plants\trait_water_consumption.dm" +#include "code\modules\genetics\plants\trait_weed_tolerance.dm" +#include "code\modules\genetics\plants\trait_yield.dm" +#include "code\modules\geology\_strata.dm" +#include "code\modules\geology\strata_igneous.dm" +#include "code\modules\geology\strata_metamorphic.dm" +#include "code\modules\geology\strata_permafrost.dm" +#include "code\modules\geology\strata_sedimentary.dm" #include "code\modules\ghosttrap\trap.dm" #include "code\modules\goals\_goal.dm" #include "code\modules\goals\goal_ambition.dm" #include "code\modules\goals\goal_mind.dm" #include "code\modules\goals\goal_mob.dm" #include "code\modules\goals\definitions\department.dm" +#include "code\modules\goals\definitions\department_clerical.dm" #include "code\modules\goals\definitions\department_engineering.dm" #include "code\modules\goals\definitions\department_medical.dm" #include "code\modules\goals\definitions\department_science.dm" @@ -1868,6 +2563,19 @@ #include "code\modules\goals\definitions\personal_achievement.dm" #include "code\modules\goals\definitions\personal_achievement_movement.dm" #include "code\modules\goals\definitions\personal_achievement_specific_object.dm" +#include "code\modules\grooming\_grooming.dm" +#include "code\modules\grooming\grooming_comb.dm" +#include "code\modules\grooming\grooming_file.dm" +#include "code\modules\grooming\grooming_hairbrush.dm" +#include "code\modules\hallucinations\_hallucination.dm" +#include "code\modules\hallucinations\hallucination_fakeattack.dm" +#include "code\modules\hallucinations\hallucination_gunfire.dm" +#include "code\modules\hallucinations\hallucination_mirage.dm" +#include "code\modules\hallucinations\hallucination_skitters.dm" +#include "code\modules\hallucinations\hallucination_sound.dm" +#include "code\modules\hallucinations\hallucination_spiderbabies.dm" +#include "code\modules\hallucinations\hallucination_talking.dm" +#include "code\modules\hallucinations\hallucination_telepathy.dm" #include "code\modules\holidays\_holiday.dm" #include "code\modules\holidays\holiday_hook.dm" #include "code\modules\holidays\holiday_name.dm" @@ -1875,17 +2583,24 @@ #include "code\modules\holodeck\HolodeckControl.dm" #include "code\modules\holodeck\HolodeckObjects.dm" #include "code\modules\holodeck\HolodeckPrograms.dm" +#include "code\modules\holomap\holomap.dm" +#include "code\modules\hotloading\_admin.dm" +#include "code\modules\hotloading\note.dm" #include "code\modules\hydroponics\grown.dm" #include "code\modules\hydroponics\grown_inedible.dm" #include "code\modules\hydroponics\grown_predefined.dm" +#include "code\modules\hydroponics\processed_grown.dm" #include "code\modules\hydroponics\seed.dm" -#include "code\modules\hydroponics\seed_datums.dm" +#include "code\modules\hydroponics\seed_appearance.dm" +#include "code\modules\hydroponics\seed_composition.dm" +#include "code\modules\hydroponics\seed_datums_aquaculture.dm" #include "code\modules\hydroponics\seed_gene_mut.dm" #include "code\modules\hydroponics\seed_machines.dm" #include "code\modules\hydroponics\seed_mobs.dm" #include "code\modules\hydroponics\seed_packets.dm" #include "code\modules\hydroponics\seed_storage.dm" -#include "code\modules\hydroponics\beekeeping\beehive.dm" +#include "code\modules\hydroponics\plant_types\seeds_herbs.dm" +#include "code\modules\hydroponics\plant_types\seeds_misc.dm" #include "code\modules\hydroponics\spreading\spreading.dm" #include "code\modules\hydroponics\spreading\spreading_growth.dm" #include "code\modules\hydroponics\spreading\spreading_response.dm" @@ -1895,91 +2610,132 @@ #include "code\modules\hydroponics\trays\tray_soil.dm" #include "code\modules\hydroponics\trays\tray_tools.dm" #include "code\modules\hydroponics\trays\tray_update_icons.dm" -#include "code\modules\inertial_damper\inertial_damper.dm" -#include "code\modules\integrated_electronics\_defines.dm" -#include "code\modules\integrated_electronics\core\analyzer.dm" -#include "code\modules\integrated_electronics\core\assemblies.dm" -#include "code\modules\integrated_electronics\core\debugger.dm" -#include "code\modules\integrated_electronics\core\detailer.dm" -#include "code\modules\integrated_electronics\core\helpers.dm" -#include "code\modules\integrated_electronics\core\integrated_circuit.dm" -#include "code\modules\integrated_electronics\core\pins.dm" -#include "code\modules\integrated_electronics\core\printer.dm" -#include "code\modules\integrated_electronics\core\saved_circuits.dm" -#include "code\modules\integrated_electronics\core\wirer.dm" -#include "code\modules\integrated_electronics\core\prefab\prefab.dm" -#include "code\modules\integrated_electronics\core\prefab\prefabs.dm" -#include "code\modules\integrated_electronics\core\prefab\test\testprefabs.dm" -#include "code\modules\integrated_electronics\core\special_pins\boolean_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\char_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\color_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\dir_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\index_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\list_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\number_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\ref_pin.dm" -#include "code\modules\integrated_electronics\core\special_pins\string_pin.dm" -#include "code\modules\integrated_electronics\passive\passive.dm" -#include "code\modules\integrated_electronics\passive\power.dm" -#include "code\modules\integrated_electronics\subtypes\access.dm" -#include "code\modules\integrated_electronics\subtypes\arithmetic.dm" -#include "code\modules\integrated_electronics\subtypes\converters.dm" -#include "code\modules\integrated_electronics\subtypes\data_transfer.dm" -#include "code\modules\integrated_electronics\subtypes\filter.dm" -#include "code\modules\integrated_electronics\subtypes\input.dm" -#include "code\modules\integrated_electronics\subtypes\lists.dm" -#include "code\modules\integrated_electronics\subtypes\logic.dm" -#include "code\modules\integrated_electronics\subtypes\manipulation.dm" -#include "code\modules\integrated_electronics\subtypes\memory.dm" -#include "code\modules\integrated_electronics\subtypes\output.dm" -#include "code\modules\integrated_electronics\subtypes\power.dm" -#include "code\modules\integrated_electronics\subtypes\reagents.dm" -#include "code\modules\integrated_electronics\subtypes\smart.dm" -#include "code\modules\integrated_electronics\subtypes\time.dm" -#include "code\modules\integrated_electronics\subtypes\trig.dm" -#include "code\modules\item_worth\_helpers.dm" +#include "code\modules\implants\implant.dm" +#include "code\modules\implants\implantcase.dm" +#include "code\modules\implants\implanter.dm" +#include "code\modules\implants\implantpad.dm" +#include "code\modules\implants\implant_types\adrenaline.dm" +#include "code\modules\implants\implant_types\chem.dm" +#include "code\modules\implants\implant_types\compressed.dm" +#include "code\modules\implants\implant_types\death_alarm.dm" +#include "code\modules\implants\implant_types\explosive.dm" +#include "code\modules\implants\implant_types\freedom.dm" +#include "code\modules\implants\implant_types\imprinting.dm" +#include "code\modules\implants\implant_types\loyalty.dm" +#include "code\modules\implants\implant_types\tracking.dm" +#include "code\modules\implants\implant_types\translator.dm" +#include "code\modules\implants\implant_types\uplink.dm" +#include "code\modules\interactions\_interactions.dm" +#include "code\modules\interactions\interactions_atom.dm" +#include "code\modules\interactions\interactions_reagents.dm" +#include "code\modules\interactions\interactions_shared.dm" +#include "code\modules\item_effects\_item_effect.dm" +#include "code\modules\item_effects\item_effect_charges.dm" +#include "code\modules\item_effects\item_effect_debug.dm" +#include "code\modules\item_effects\item_effect_item.dm" +#include "code\modules\item_effects\item_effect_modifier.dm" +#include "code\modules\keybindings\_defines.dm" +#include "code\modules\keybindings\_keybindings.dm" +#include "code\modules\keybindings\bindings_atom.dm" +#include "code\modules\keybindings\bindings_client.dm" +#include "code\modules\keybindings\setup.dm" +#include "code\modules\keybindings\binds\admin.dm" +#include "code\modules\keybindings\binds\client.dm" +#include "code\modules\keybindings\binds\communication.dm" +#include "code\modules\keybindings\binds\human.dm" +#include "code\modules\keybindings\binds\living.dm" +#include "code\modules\keybindings\binds\mob.dm" +#include "code\modules\keybindings\binds\movement.dm" +#include "code\modules\lighting\_lighting_defs.dm" +#include "code\modules\lighting\ambient_group.dm" +#include "code\modules\lighting\ambient_turf.dm" #include "code\modules\lighting\lighting_area.dm" #include "code\modules\lighting\lighting_atom.dm" #include "code\modules\lighting\lighting_corner.dm" #include "code\modules\lighting\lighting_overlay.dm" -#include "code\modules\lighting\lighting_planemaster.dm" -#include "code\modules\lighting\lighting_setup.dm" #include "code\modules\lighting\lighting_source.dm" #include "code\modules\lighting\lighting_turf.dm" #include "code\modules\lighting\~lighting_undefs.dm" +#include "code\modules\lights\light_bulbs_tubes.dm" +#include "code\modules\lights\light_fabrication.dm" +#include "code\modules\lights\light_fixture_base.dm" +#include "code\modules\lights\light_fixture_construction.dm" +#include "code\modules\lights\light_fixture_floorlamp.dm" +#include "code\modules\lights\light_fixture_navigation.dm" +#include "code\modules\lights\light_fixture_small.dm" +#include "code\modules\lights\light_fixture_spot.dm" +#include "code\modules\lights\light_replacer.dm" +#include "code\modules\lights\light_switch.dm" +#include "code\modules\lights\light_switch_frames.dm" #include "code\modules\locks\key.dm" +#include "code\modules\locks\keyring.dm" #include "code\modules\locks\lock.dm" #include "code\modules\locks\lock_construct.dm" -#include "code\modules\maps\dmm_suite.dm" +#include "code\modules\maps\_map_template.dm" +#include "code\modules\maps\_map_template_unit_testing.dm" #include "code\modules\maps\helper_landmarks.dm" -#include "code\modules\maps\map_template.dm" -#include "code\modules\maps\map_template_unit_testing.dm" #include "code\modules\maps\reader.dm" -#include "code\modules\maps\ruins.dm" +#include "code\modules\maps\template_types\antag_spawn.dm" +#include "code\modules\maps\template_types\away_site.dm" +#include "code\modules\maps\template_types\ruins.dm" +#include "code\modules\maps\template_types\ruins_exoplanet.dm" +#include "code\modules\maps\template_types\mapped_planet\mapped_planet_template.dm" +#include "code\modules\maps\template_types\random_exoplanet\fauna_generator.dm" +#include "code\modules\maps\template_types\random_exoplanet\flora_generator.dm" +#include "code\modules\maps\template_types\random_exoplanet\planetoid_data.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_exoplanet.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_map.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_planet.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_planet_areas.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_planet_landmarks.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_planet_level_data.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_planet_subtemplates.dm" +#include "code\modules\maps\template_types\random_exoplanet\random_planet_themes.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_themes\_planet_theme.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_themes\mountains.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_themes\radiation_bombing.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_themes\robotic_guardians.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_themes\ruined_city.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\barren.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\chlorine.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\desert.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\grass.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\meat.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\shrouded.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\snow.dm" +#include "code\modules\maps\template_types\random_exoplanet\planet_types\volcanic.dm" +#include "code\modules\materials\_material_stack.dm" #include "code\modules\materials\_materials.dm" -#include "code\modules\materials\_stack_recipe.dm" #include "code\modules\materials\material_armor.dm" -#include "code\modules\materials\material_recipes.dm" -#include "code\modules\materials\material_sheets.dm" -#include "code\modules\materials\material_synth.dm" -#include "code\modules\materials\materials_ore.dm" -#include "code\modules\materials\recipes_furniture.dm" -#include "code\modules\materials\recipes_items.dm" -#include "code\modules\materials\recipes_stacks.dm" -#include "code\modules\materials\recipes_storage.dm" -#include "code\modules\materials\recipes_structures.dm" +#include "code\modules\materials\material_coatings.dm" +#include "code\modules\materials\material_data.dm" +#include "code\modules\materials\material_debris.dm" +#include "code\modules\materials\material_debris_fragment.dm" +#include "code\modules\materials\material_display.dm" +#include "code\modules\materials\material_drying.dm" +#include "code\modules\materials\material_gas_overlay.dm" +#include "code\modules\materials\material_metabolism.dm" +#include "code\modules\materials\material_physics.dm" +#include "code\modules\materials\material_product_spawning.dm" +#include "code\modules\materials\material_properties.dm" +#include "code\modules\materials\material_stack_mapping.dm" +#include "code\modules\materials\material_stack_synth.dm" #include "code\modules\materials\definitions\gasses\_mat_gas.dm" #include "code\modules\materials\definitions\gasses\material_gas_alien.dm" #include "code\modules\materials\definitions\gasses\material_gas_mundane.dm" #include "code\modules\materials\definitions\liquids\_mat_liquid.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_chemistry.dm" +#include "code\modules\materials\definitions\liquids\materials_liquid_mundane.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_solvents.dm" +#include "code\modules\materials\definitions\liquids\materials_liquid_soup.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_toxins.dm" #include "code\modules\materials\definitions\liquids\materials_liquid_water.dm" #include "code\modules\materials\definitions\solids\_mat_solid.dm" #include "code\modules\materials\definitions\solids\materials_solid_alien.dm" +#include "code\modules\materials\definitions\solids\materials_solid_butchery.dm" #include "code\modules\materials\definitions\solids\materials_solid_elements.dm" #include "code\modules\materials\definitions\solids\materials_solid_exotic.dm" +#include "code\modules\materials\definitions\solids\materials_solid_fission.dm" #include "code\modules\materials\definitions\solids\materials_solid_gemstones.dm" #include "code\modules\materials\definitions\solids\materials_solid_glass.dm" #include "code\modules\materials\definitions\solids\materials_solid_ice.dm" @@ -1989,7 +2745,16 @@ #include "code\modules\materials\definitions\solids\materials_solid_organic.dm" #include "code\modules\materials\definitions\solids\materials_solid_stone.dm" #include "code\modules\materials\definitions\solids\materials_solid_wood.dm" -#include "code\modules\materials\geology\_strata.dm" +#include "code\modules\materials\stack_types\material_stack_aerogel.dm" +#include "code\modules\materials\stack_types\material_stack_animal.dm" +#include "code\modules\materials\stack_types\material_stack_bar.dm" +#include "code\modules\materials\stack_types\material_stack_brick.dm" +#include "code\modules\materials\stack_types\material_stack_cloth.dm" +#include "code\modules\materials\stack_types\material_stack_logs.dm" +#include "code\modules\materials\stack_types\material_stack_lump.dm" +#include "code\modules\materials\stack_types\material_stack_misc.dm" +#include "code\modules\materials\stack_types\material_stack_nail.dm" +#include "code\modules\materials\stack_types\material_stack_ore.dm" #include "code\modules\mechs\_mech_setup.dm" #include "code\modules\mechs\mech.dm" #include "code\modules\mechs\mech_construction.dm" @@ -2011,13 +2776,14 @@ #include "code\modules\mechs\components\software.dm" #include "code\modules\mechs\equipment\_equipment.dm" #include "code\modules\mechs\equipment\combat.dm" +#include "code\modules\mechs\equipment\combat_projectile.dm" #include "code\modules\mechs\equipment\engineering.dm" #include "code\modules\mechs\equipment\medical.dm" #include "code\modules\mechs\equipment\utility.dm" #include "code\modules\mechs\interface\_interface.dm" -#include "code\modules\mechs\interface\screen_objects.dm" #include "code\modules\mechs\premade\_premade.dm" #include "code\modules\mechs\premade\combat.dm" +#include "code\modules\mechs\premade\exploration.dm" #include "code\modules\mechs\premade\heavy.dm" #include "code\modules\mechs\premade\light.dm" #include "code\modules\mechs\premade\misc.dm" @@ -2028,42 +2794,60 @@ #include "code\modules\mining\abandonedcrates.dm" #include "code\modules\mining\mine_items.dm" #include "code\modules\mining\mine_turfs.dm" -#include "code\modules\mining\satchel_ore_boxdm.dm" +#include "code\modules\mining\ore_box.dm" +#include "code\modules\mining\drilling\brace.dm" #include "code\modules\mining\drilling\drill.dm" -#include "code\modules\mining\machinery\_mineral.dm" -#include "code\modules\mining\machinery\mineral_console.dm" -#include "code\modules\mining\machinery\mineral_processor.dm" -#include "code\modules\mining\machinery\mineral_stacker.dm" -#include "code\modules\mining\machinery\mineral_unloader.dm" +#include "code\modules\mining\drilling\drill_act.dm" +#include "code\modules\mining\drilling\drill_fsm.dm" +#include "code\modules\mining\machinery\_material_processing.dm" +#include "code\modules\mining\machinery\material_compressor.dm" +#include "code\modules\mining\machinery\material_extractor.dm" +#include "code\modules\mining\machinery\material_smelter.dm" +#include "code\modules\mining\machinery\material_stacker.dm" +#include "code\modules\mining\machinery\material_unloader.dm" #include "code\modules\mob\animations.dm" #include "code\modules\mob\death.dm" +#include "code\modules\mob\dview.dm" +#include "code\modules\mob\examine.dm" #include "code\modules\mob\floating_message.dm" -#include "code\modules\mob\gender.dm" #include "code\modules\mob\hear_say.dm" -#include "code\modules\mob\holder.dm" +#include "code\modules\mob\hugs.dm" #include "code\modules\mob\inventory.dm" #include "code\modules\mob\login.dm" #include "code\modules\mob\logout.dm" #include "code\modules\mob\mob.dm" +#include "code\modules\mob\mob_automove.dm" +#include "code\modules\mob\mob_blood.dm" +#include "code\modules\mob\mob_damage.dm" #include "code\modules\mob\mob_defines.dm" +#include "code\modules\mob\mob_eating.dm" +#include "code\modules\mob\mob_genetics.dm" #include "code\modules\mob\mob_grabs.dm" #include "code\modules\mob\mob_helpers.dm" +#include "code\modules\mob\mob_intent.dm" +#include "code\modules\mob\mob_layering.dm" #include "code\modules\mob\mob_movement.dm" +#include "code\modules\mob\mob_organs.dm" +#include "code\modules\mob\mob_serde.dm" +#include "code\modules\mob\mob_snapshot.dm" +#include "code\modules\mob\mob_status.dm" +#include "code\modules\mob\mob_temperature.dm" #include "code\modules\mob\mob_transformation_simple.dm" #include "code\modules\mob\say.dm" +#include "code\modules\mob\stripping.dm" #include "code\modules\mob\transform_procs.dm" -#include "code\modules\mob\typing_indicator.dm" #include "code\modules\mob\update_icons.dm" #include "code\modules\mob\grab\grab_datum.dm" #include "code\modules\mob\grab\grab_object.dm" -#include "code\modules\mob\grab\grab_readme.dm" #include "code\modules\mob\grab\normal\grab_normal.dm" #include "code\modules\mob\grab\normal\norm_aggressive.dm" #include "code\modules\mob\grab\normal\norm_kill.dm" #include "code\modules\mob\grab\normal\norm_neck.dm" #include "code\modules\mob\grab\normal\norm_passive.dm" #include "code\modules\mob\grab\normal\norm_struggle.dm" +#include "code\modules\mob\grab\simple\simple_control.dm" #include "code\modules\mob\grab\simple\simple_passive.dm" +#include "code\modules\mob\language\animal.dm" #include "code\modules\mob\language\generic.dm" #include "code\modules\mob\language\language.dm" #include "code\modules\mob\language\synthetic.dm" @@ -2075,16 +2859,44 @@ #include "code\modules\mob\living\damage_procs.dm" #include "code\modules\mob\living\death.dm" #include "code\modules\mob\living\default_language.dm" +#include "code\modules\mob\living\immunity.dm" +#include "code\modules\mob\living\internals.dm" +#include "code\modules\mob\living\inventory.dm" #include "code\modules\mob\living\life.dm" #include "code\modules\mob\living\living.dm" +#include "code\modules\mob\living\living_allergies.dm" +#include "code\modules\mob\living\living_appearance.dm" +#include "code\modules\mob\living\living_attackhand.dm" +#include "code\modules\mob\living\living_blood.dm" +#include "code\modules\mob\living\living_bodytemp.dm" +#include "code\modules\mob\living\living_breath.dm" +#include "code\modules\mob\living\living_damage.dm" +#include "code\modules\mob\living\living_death.dm" #include "code\modules\mob\living\living_defense.dm" #include "code\modules\mob\living\living_defines.dm" +#include "code\modules\mob\living\living_dreams.dm" +#include "code\modules\mob\living\living_eating.dm" +#include "code\modules\mob\living\living_electrocution.dm" +#include "code\modules\mob\living\living_fires.dm" +#include "code\modules\mob\living\living_genetics.dm" +#include "code\modules\mob\living\living_give.dm" #include "code\modules\mob\living\living_grabs.dm" +#include "code\modules\mob\living\living_hallucinations.dm" +#include "code\modules\mob\living\living_hud.dm" #include "code\modules\mob\living\living_maneuvers.dm" +#include "code\modules\mob\living\living_organs.dm" #include "code\modules\mob\living\living_powers.dm" +#include "code\modules\mob\living\living_pulse.dm" +#include "code\modules\mob\living\living_resist.dm" +#include "code\modules\mob\living\living_status.dm" +#include "code\modules\mob\living\living_tail.dm" +#include "code\modules\mob\living\living_taste.dm" +#include "code\modules\mob\living\living_throw.dm" #include "code\modules\mob\living\login.dm" #include "code\modules\mob\living\logout.dm" #include "code\modules\mob\living\say.dm" +#include "code\modules\mob\living\stasis.dm" +#include "code\modules\mob\living\stress.dm" #include "code\modules\mob\living\bot\bot.dm" #include "code\modules\mob\living\bot\cleanbot.dm" #include "code\modules\mob\living\bot\ed209bot.dm" @@ -2094,126 +2906,55 @@ #include "code\modules\mob\living\bot\mulebot.dm" #include "code\modules\mob\living\bot\remotebot.dm" #include "code\modules\mob\living\bot\secbot.dm" -#include "code\modules\mob\living\carbon\breathe.dm" -#include "code\modules\mob\living\carbon\carbon.dm" -#include "code\modules\mob\living\carbon\carbon_defense.dm" -#include "code\modules\mob\living\carbon\carbon_defines.dm" -#include "code\modules\mob\living\carbon\carbon_grabs.dm" -#include "code\modules\mob\living\carbon\carbon_powers.dm" -#include "code\modules\mob\living\carbon\damage_procs.dm" -#include "code\modules\mob\living\carbon\give.dm" -#include "code\modules\mob\living\carbon\hallucinations.dm" -#include "code\modules\mob\living\carbon\immunity.dm" -#include "code\modules\mob\living\carbon\life.dm" -#include "code\modules\mob\living\carbon\resist.dm" -#include "code\modules\mob\living\carbon\taste.dm" -#include "code\modules\mob\living\carbon\alien\alien.dm" -#include "code\modules\mob\living\carbon\alien\alien_attacks.dm" -#include "code\modules\mob\living\carbon\alien\alien_damage.dm" -#include "code\modules\mob\living\carbon\alien\death.dm" -#include "code\modules\mob\living\carbon\alien\life.dm" -#include "code\modules\mob\living\carbon\alien\say.dm" -#include "code\modules\mob\living\carbon\alien\update_icons.dm" -#include "code\modules\mob\living\carbon\brain\brain.dm" -#include "code\modules\mob\living\carbon\brain\death.dm" -#include "code\modules\mob\living\carbon\brain\life.dm" -#include "code\modules\mob\living\carbon\brain\login.dm" -#include "code\modules\mob\living\carbon\brain\MMI.dm" -#include "code\modules\mob\living\carbon\brain\robot.dm" -#include "code\modules\mob\living\carbon\brain\say.dm" -#include "code\modules\mob\living\carbon\human\appearance.dm" -#include "code\modules\mob\living\carbon\human\death.dm" -#include "code\modules\mob\living\carbon\human\examine.dm" -#include "code\modules\mob\living\carbon\human\human.dm" -#include "code\modules\mob\living\carbon\human\human_attackhand.dm" -#include "code\modules\mob\living\carbon\human\human_damage.dm" -#include "code\modules\mob\living\carbon\human\human_defense.dm" -#include "code\modules\mob\living\carbon\human\human_defines.dm" -#include "code\modules\mob\living\carbon\human\human_grabs.dm" -#include "code\modules\mob\living\carbon\human\human_helpers.dm" -#include "code\modules\mob\living\carbon\human\human_maneuvers.dm" -#include "code\modules\mob\living\carbon\human\human_movement.dm" -#include "code\modules\mob\living\carbon\human\human_organs.dm" -#include "code\modules\mob\living\carbon\human\human_powers.dm" -#include "code\modules\mob\living\carbon\human\human_skin.dm" -#include "code\modules\mob\living\carbon\human\human_species.dm" -#include "code\modules\mob\living\carbon\human\inventory.dm" -#include "code\modules\mob\living\carbon\human\life.dm" -#include "code\modules\mob\living\carbon\human\login.dm" -#include "code\modules\mob\living\carbon\human\logout.dm" -#include "code\modules\mob\living\carbon\human\MedicalSideEffects.dm" -#include "code\modules\mob\living\carbon\human\npcs.dm" -#include "code\modules\mob\living\carbon\human\obj_grabs.dm" -#include "code\modules\mob\living\carbon\human\say.dm" -#include "code\modules\mob\living\carbon\human\stripping.dm" -#include "code\modules\mob\living\carbon\human\unarmed_attack.dm" -#include "code\modules\mob\living\carbon\human\update_icons.dm" -#include "code\modules\mob\living\carbon\human\whisper.dm" -#include "code\modules\mob\living\carbon\human\descriptors\_descriptors.dm" -#include "code\modules\mob\living\carbon\human\descriptors\descriptors_generic.dm" -#include "code\modules\mob\living\carbon\xenobiological\death.dm" -#include "code\modules\mob\living\carbon\xenobiological\examine.dm" -#include "code\modules\mob\living\carbon\xenobiological\hud.dm" -#include "code\modules\mob\living\carbon\xenobiological\items.dm" -#include "code\modules\mob\living\carbon\xenobiological\life.dm" -#include "code\modules\mob\living\carbon\xenobiological\powers.dm" -#include "code\modules\mob\living\carbon\xenobiological\say.dm" -#include "code\modules\mob\living\carbon\xenobiological\slime_AI.dm" -#include "code\modules\mob\living\carbon\xenobiological\subtypes.dm" -#include "code\modules\mob\living\carbon\xenobiological\update_icons.dm" -#include "code\modules\mob\living\carbon\xenobiological\xenobiological.dm" -#include "code\modules\mob\living\deity\deity.dm" -#include "code\modules\mob\living\deity\deity_boons.dm" -#include "code\modules\mob\living\deity\deity_click.dm" -#include "code\modules\mob\living\deity\deity_items.dm" -#include "code\modules\mob\living\deity\deity_phenomena.dm" -#include "code\modules\mob\living\deity\deity_power.dm" -#include "code\modules\mob\living\deity\deity_pylon.dm" -#include "code\modules\mob\living\deity\deity_sources.dm" -#include "code\modules\mob\living\deity\deity_Stat.dm" -#include "code\modules\mob\living\deity\deity_topic.dm" -#include "code\modules\mob\living\deity\deity_tracking.dm" -#include "code\modules\mob\living\deity\forms.dm" -#include "code\modules\mob\living\deity\say.dm" -#include "code\modules\mob\living\deity\forms\narsie.dm" -#include "code\modules\mob\living\deity\forms\starlight.dm" -#include "code\modules\mob\living\deity\forms\tower.dm" -#include "code\modules\mob\living\deity\items\_defines.dm" -#include "code\modules\mob\living\deity\items\deity_item.dm" -#include "code\modules\mob\living\deity\items\general.dm" -#include "code\modules\mob\living\deity\items\generic.dm" -#include "code\modules\mob\living\deity\items\narsie\basic.dm" -#include "code\modules\mob\living\deity\items\narsie\minions.dm" -#include "code\modules\mob\living\deity\items\narsie\sacrificing.dm" -#include "code\modules\mob\living\deity\items\narsie\smithing.dm" -#include "code\modules\mob\living\deity\items\starlight\artifacts.dm" -#include "code\modules\mob\living\deity\items\starlight\phenomena.dm" -#include "code\modules\mob\living\deity\items\starlight\spells.dm" -#include "code\modules\mob\living\deity\items\tower\conjuration.dm" -#include "code\modules\mob\living\deity\items\tower\transmutation.dm" -#include "code\modules\mob\living\deity\menu\deity_nano.dm" -#include "code\modules\mob\living\deity\phenomena\_defines.dm" -#include "code\modules\mob\living\deity\phenomena\communication.dm" -#include "code\modules\mob\living\deity\phenomena\conjuration.dm" -#include "code\modules\mob\living\deity\phenomena\conversion.dm" -#include "code\modules\mob\living\deity\phenomena\generic.dm" -#include "code\modules\mob\living\deity\phenomena\narsie.dm" -#include "code\modules\mob\living\deity\phenomena\phenomena.dm" -#include "code\modules\mob\living\deity\phenomena\starlight.dm" -#include "code\modules\mob\living\deity\phenomena\transmutation.dm" +#include "code\modules\mob\living\brain\brain.dm" +#include "code\modules\mob\living\brain\death.dm" +#include "code\modules\mob\living\brain\say.dm" +#include "code\modules\mob\living\human\death.dm" +#include "code\modules\mob\living\human\examine.dm" +#include "code\modules\mob\living\human\human.dm" +#include "code\modules\mob\living\human\human_appearance.dm" +#include "code\modules\mob\living\human\human_appearance_head.dm" +#include "code\modules\mob\living\human\human_attackhand.dm" +#include "code\modules\mob\living\human\human_blood.dm" +#include "code\modules\mob\living\human\human_damage.dm" +#include "code\modules\mob\living\human\human_defense.dm" +#include "code\modules\mob\living\human\human_defines.dm" +#include "code\modules\mob\living\human\human_examine_decl.dm" +#include "code\modules\mob\living\human\human_grabs.dm" +#include "code\modules\mob\living\human\human_helpers.dm" +#include "code\modules\mob\living\human\human_internals.dm" +#include "code\modules\mob\living\human\human_maneuvers.dm" +#include "code\modules\mob\living\human\human_movement.dm" +#include "code\modules\mob\living\human\human_organs.dm" +#include "code\modules\mob\living\human\human_powers.dm" +#include "code\modules\mob\living\human\human_presets.dm" +#include "code\modules\mob\living\human\human_skin.dm" +#include "code\modules\mob\living\human\human_verbs.dm" +#include "code\modules\mob\living\human\life.dm" +#include "code\modules\mob\living\human\login.dm" +#include "code\modules\mob\living\human\logout.dm" +#include "code\modules\mob\living\human\npcs.dm" +#include "code\modules\mob\living\human\obj_grabs.dm" +#include "code\modules\mob\living\human\say.dm" +#include "code\modules\mob\living\human\unarmed_attack.dm" +#include "code\modules\mob\living\human\update_icons.dm" +#include "code\modules\mob\living\human\whisper.dm" +#include "code\modules\mob\living\human\descriptors\_descriptors.dm" +#include "code\modules\mob\living\human\descriptors\descriptors_age.dm" +#include "code\modules\mob\living\human\descriptors\descriptors_body_length.dm" +#include "code\modules\mob\living\human\descriptors\descriptors_generic.dm" #include "code\modules\mob\living\maneuvers\_maneuver.dm" #include "code\modules\mob\living\maneuvers\maneuver_leap.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\laws.dm" #include "code\modules\mob\living\silicon\login.dm" -#include "code\modules\mob\living\silicon\posi_brainmob.dm" #include "code\modules\mob\living\silicon\say.dm" #include "code\modules\mob\living\silicon\silicon.dm" #include "code\modules\mob\living\silicon\subsystems.dm" #include "code\modules\mob\living\silicon\ai\ai.dm" -#include "code\modules\mob\living\silicon\ai\ai_camera_proc.dm" #include "code\modules\mob\living\silicon\ai\ai_damage.dm" #include "code\modules\mob\living\silicon\ai\ai_movement.dm" +#include "code\modules\mob\living\silicon\ai\ai_radio.dm" #include "code\modules\mob\living\silicon\ai\death.dm" #include "code\modules\mob\living\silicon\ai\examine.dm" #include "code\modules\mob\living\silicon\ai\icons.dm" @@ -2236,7 +2977,6 @@ #include "code\modules\mob\living\silicon\pai\software_modules.dm" #include "code\modules\mob\living\silicon\robot\analyzer.dm" #include "code\modules\mob\living\silicon\robot\component.dm" -#include "code\modules\mob\living\silicon\robot\custom_sprites.dm" #include "code\modules\mob\living\silicon\robot\death.dm" #include "code\modules\mob\living\silicon\robot\examine.dm" #include "code\modules\mob\living\silicon\robot\inventory.dm" @@ -2276,54 +3016,66 @@ #include "code\modules\mob\living\silicon\robot\modules\module_security.dm" #include "code\modules\mob\living\silicon\robot\modules\module_standard.dm" #include "code\modules\mob\living\silicon\robot\modules\module_uncertified.dm" +#include "code\modules\mob\living\simple_animal\_simple_animal.dm" #include "code\modules\mob\living\simple_animal\natural_weapons.dm" -#include "code\modules\mob\living\simple_animal\shade.dm" -#include "code\modules\mob\living\simple_animal\simple_animal.dm" +#include "code\modules\mob\living\simple_animal\simple_animal_codex.dm" +#include "code\modules\mob\living\simple_animal\simple_animal_damage.dm" +#include "code\modules\mob\living\simple_animal\simple_animal_serde.dm" +#include "code\modules\mob\living\simple_animal\alien\alien.dm" #include "code\modules\mob\living\simple_animal\aquatic\_aquatic.dm" #include "code\modules\mob\living\simple_animal\aquatic\_aquatic_hostile.dm" #include "code\modules\mob\living\simple_animal\aquatic\_aquatic_retaliate.dm" #include "code\modules\mob\living\simple_animal\aquatic\aquatic_carp.dm" #include "code\modules\mob\living\simple_animal\aquatic\aquatic_fish.dm" +#include "code\modules\mob\living\simple_animal\aquatic\aquatic_fish_lantern.dm" #include "code\modules\mob\living\simple_animal\aquatic\aquatic_sharks.dm" -#include "code\modules\mob\living\simple_animal\constructs\constructs.dm" -#include "code\modules\mob\living\simple_animal\constructs\soulstone.dm" #include "code\modules\mob\living\simple_animal\crow\crow.dm" -#include "code\modules\mob\living\simple_animal\familiars\familiars.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" #include "code\modules\mob\living\simple_animal\friendly\crab.dm" #include "code\modules\mob\living\simple_animal\friendly\farm_animals.dm" +#include "code\modules\mob\living\simple_animal\friendly\frog.dm" +#include "code\modules\mob\living\simple_animal\friendly\koala.dm" #include "code\modules\mob\living\simple_animal\friendly\lizard.dm" -#include "code\modules\mob\living\simple_animal\friendly\mouse.dm" #include "code\modules\mob\living\simple_animal\friendly\mushroom.dm" #include "code\modules\mob\living\simple_animal\friendly\possum.dm" -#include "code\modules\mob\living\simple_animal\friendly\slime.dm" +#include "code\modules\mob\living\simple_animal\friendly\snail.dm" #include "code\modules\mob\living\simple_animal\friendly\tomato.dm" +#include "code\modules\mob\living\simple_animal\hostile\_hostile.dm" #include "code\modules\mob\living\simple_animal\hostile\antlion.dm" #include "code\modules\mob\living\simple_animal\hostile\bad_drone.dm" #include "code\modules\mob\living\simple_animal\hostile\bat.dm" #include "code\modules\mob\living\simple_animal\hostile\bear.dm" #include "code\modules\mob\living\simple_animal\hostile\carp.dm" #include "code\modules\mob\living\simple_animal\hostile\creature.dm" -#include "code\modules\mob\living\simple_animal\hostile\drake.dm" #include "code\modules\mob\living\simple_animal\hostile\faithful_hound.dm" -#include "code\modules\mob\living\simple_animal\hostile\faithless.dm" -#include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm" -#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm" -#include "code\modules\mob\living\simple_animal\hostile\hostile.dm" #include "code\modules\mob\living\simple_animal\hostile\leech.dm" #include "code\modules\mob\living\simple_animal\hostile\mimic.dm" #include "code\modules\mob\living\simple_animal\hostile\pike.dm" -#include "code\modules\mob\living\simple_animal\hostile\pirate.dm" -#include "code\modules\mob\living\simple_animal\hostile\russian.dm" -#include "code\modules\mob\living\simple_animal\hostile\syndicate.dm" +#include "code\modules\mob\living\simple_animal\hostile\revenant.dm" +#include "code\modules\mob\living\simple_animal\hostile\shark.dm" +#include "code\modules\mob\living\simple_animal\hostile\slug.dm" +#include "code\modules\mob\living\simple_animal\hostile\space_dragon.dm" #include "code\modules\mob\living\simple_animal\hostile\tree.dm" #include "code\modules\mob\living\simple_animal\hostile\vagrant.dm" -#include "code\modules\mob\living\simple_animal\hostile\voxslug.dm" -#include "code\modules\mob\living\simple_animal\hostile\commanded\_command_defines.dm" +#include "code\modules\mob\living\simple_animal\hostile\viscerator.dm" +#include "code\modules\mob\living\simple_animal\hostile\commanded\_commanded.dm" #include "code\modules\mob\living\simple_animal\hostile\commanded\bear_companion.dm" -#include "code\modules\mob\living\simple_animal\hostile\commanded\commanded.dm" #include "code\modules\mob\living\simple_animal\hostile\commanded\nanomachines.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\_giant_spider.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\_giant_spider_ai.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\ai_guard.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\ai_hunter.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\ai_nurse.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\guard.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\hunter.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\nurse.dm" +#include "code\modules\mob\living\simple_animal\hostile\giant_spiders\spitter.dm" +#include "code\modules\mob\living\simple_animal\hostile\hivebots\_hivebot.dm" +#include "code\modules\mob\living\simple_animal\hostile\hivebots\megabot.dm" +#include "code\modules\mob\living\simple_animal\hostile\hivebots\melee\_melee.dm" +#include "code\modules\mob\living\simple_animal\hostile\hivebots\melee\armored.dm" +#include "code\modules\mob\living\simple_animal\hostile\hivebots\ranged\_ranged.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\drone.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\exoplanet.dm" @@ -2332,13 +3084,20 @@ #include "code\modules\mob\living\simple_animal\hostile\retaliate\jelly.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\king_of_goats.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\parrot.dm" -#include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\giant_parrot\giant_parrot.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\giant_parrot\giant_parrot_species.dm" +#include "code\modules\mob\living\simple_animal\passive\_passive.dm" +#include "code\modules\mob\living\simple_animal\passive\deer.dm" +#include "code\modules\mob\living\simple_animal\passive\fox.dm" +#include "code\modules\mob\living\simple_animal\passive\horse.dm" +#include "code\modules\mob\living\simple_animal\passive\mouse.dm" +#include "code\modules\mob\living\simple_animal\passive\rabbit.dm" +#include "code\modules\mob\living\simple_animal\passive\sheep.dm" +#include "code\modules\mob\living\simple_animal\passive\wolf.dm" +#include "code\modules\mob\new_player\lobby.dm" #include "code\modules\mob\new_player\login.dm" #include "code\modules\mob\new_player\logout.dm" #include "code\modules\mob\new_player\new_player.dm" -#include "code\modules\mob\new_player\poll.dm" #include "code\modules\mob\new_player\preferences_setup.dm" #include "code\modules\mob\observer\observer.dm" #include "code\modules\mob\observer\eye\blueprints_eye.dm" @@ -2355,13 +3114,8 @@ #include "code\modules\mob\observer\eye\freelook\ai\chunk.dm" #include "code\modules\mob\observer\eye\freelook\ai\eye.dm" #include "code\modules\mob\observer\eye\freelook\ai\update_triggers.dm" -#include "code\modules\mob\observer\eye\freelook\cult\cultnet.dm" -#include "code\modules\mob\observer\eye\freelook\cult\mask.dm" #include "code\modules\mob\observer\ghost\follow.dm" #include "code\modules\mob\observer\ghost\ghost.dm" -#include "code\modules\mob\observer\ghost\login.dm" -#include "code\modules\mob\observer\ghost\logout.dm" -#include "code\modules\mob\observer\ghost\say.dm" #include "code\modules\mob\observer\virtual\_constants.dm" #include "code\modules\mob\observer\virtual\base.dm" #include "code\modules\mob\observer\virtual\helpers.dm" @@ -2373,16 +3127,32 @@ #include "code\modules\mob\skills\skill_verbs.dm" #include "code\modules\mob\skills\skillset.dm" #include "code\modules\mob\skills\skillset_silicon.dm" +#include "code\modules\mob_holder\_holder.dm" +#include "code\modules\mob_holder\holder_mobs.dm" +#include "code\modules\mob_holder\holder_subtypes.dm" +#include "code\modules\mob_modifiers\_modifiers.dm" +#include "code\modules\mob_modifiers\modifiers_datum.dm" +#include "code\modules\mob_modifiers\modifiers_helpers.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_cloaked.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_light.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_mech_shields.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_object.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_prone.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_regeneration.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_restrained.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_shield.dm" +#include "code\modules\mob_modifiers\definitions\modifiers_stasis.dm" #include "code\modules\modular_computers\laptop_vendor.dm" #include "code\modules\modular_computers\computers\modular_computer\assembly_computer.dm" +#include "code\modules\modular_computers\computers\modular_computer\assembly_holo.dm" #include "code\modules\modular_computers\computers\modular_computer\assembly_laptop.dm" #include "code\modules\modular_computers\computers\modular_computer\assembly_pda.dm" #include "code\modules\modular_computers\computers\modular_computer\assembly_tablet.dm" -#include "code\modules\modular_computers\computers\modular_computer\assembly_telescreen.dm" #include "code\modules\modular_computers\computers\modular_computer\core.dm" #include "code\modules\modular_computers\computers\modular_computer\interaction.dm" #include "code\modules\modular_computers\computers\modular_computer\variables.dm" #include "code\modules\modular_computers\computers\subtypes\dev_console.dm" +#include "code\modules\modular_computers\computers\subtypes\dev_holo.dm" #include "code\modules\modular_computers\computers\subtypes\dev_laptop.dm" #include "code\modules\modular_computers\computers\subtypes\dev_pda.dm" #include "code\modules\modular_computers\computers\subtypes\dev_tablet.dm" @@ -2394,14 +3164,16 @@ #include "code\modules\modular_computers\computers\subtypes\preset_telescreen.dm" #include "code\modules\modular_computers\file_system\computer_file.dm" #include "code\modules\modular_computers\file_system\data.dm" -#include "code\modules\modular_computers\file_system\grant.dm" +#include "code\modules\modular_computers\file_system\directory.dm" #include "code\modules\modular_computers\file_system\manifest.dm" #include "code\modules\modular_computers\file_system\program.dm" #include "code\modules\modular_computers\file_system\program_events.dm" +#include "code\modules\modular_computers\file_system\programs\file_browser.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\access_decrypter.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\hacked_camera.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\uplink.dm" +#include "code\modules\modular_computers\file_system\programs\command\accounts.dm" #include "code\modules\modular_computers\file_system\programs\command\card.dm" #include "code\modules\modular_computers\file_system\programs\command\comm.dm" #include "code\modules\modular_computers\file_system\programs\engineering\alarm_monitor.dm" @@ -2410,14 +3182,14 @@ #include "code\modules\modular_computers\file_system\programs\engineering\power_monitor.dm" #include "code\modules\modular_computers\file_system\programs\engineering\rcon_console.dm" #include "code\modules\modular_computers\file_system\programs\engineering\shields_monitor.dm" -#include "code\modules\modular_computers\file_system\programs\engineering\supermatter_monitor.dm" +#include "code\modules\modular_computers\file_system\programs\engineering\shutoff_valve.dm" #include "code\modules\modular_computers\file_system\programs\generic\camera.dm" #include "code\modules\modular_computers\file_system\programs\generic\configurator.dm" #include "code\modules\modular_computers\file_system\programs\generic\crew_manifest.dm" #include "code\modules\modular_computers\file_system\programs\generic\deck_management.dm" #include "code\modules\modular_computers\file_system\programs\generic\docks.dm" #include "code\modules\modular_computers\file_system\programs\generic\email_client.dm" -#include "code\modules\modular_computers\file_system\programs\generic\file_browser.dm" +#include "code\modules\modular_computers\file_system\programs\generic\file_manager.dm" #include "code\modules\modular_computers\file_system\programs\generic\folding.dm" #include "code\modules\modular_computers\file_system\programs\generic\game.dm" #include "code\modules\modular_computers\file_system\programs\generic\ntdownloader.dm" @@ -2432,6 +3204,7 @@ #include "code\modules\modular_computers\file_system\programs\research\email_administration.dm" #include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm" #include "code\modules\modular_computers\file_system\programs\security\forceauthorization.dm" +#include "code\modules\modular_computers\file_system\programs\security\turret_control.dm" #include "code\modules\modular_computers\file_system\reports\crew_record.dm" #include "code\modules\modular_computers\file_system\reports\deck_reports.dm" #include "code\modules\modular_computers\file_system\reports\people.dm" @@ -2443,8 +3216,10 @@ #include "code\modules\modular_computers\hardware\battery_module.dm" #include "code\modules\modular_computers\hardware\card_slot.dm" #include "code\modules\modular_computers\hardware\charge_stick_slot.dm" +#include "code\modules\modular_computers\hardware\disk_slot.dm" #include "code\modules\modular_computers\hardware\drive_slot.dm" #include "code\modules\modular_computers\hardware\hard_drive.dm" +#include "code\modules\modular_computers\hardware\lan_port.dm" #include "code\modules\modular_computers\hardware\nano_printer.dm" #include "code\modules\modular_computers\hardware\network_card.dm" #include "code\modules\modular_computers\hardware\portable_hard_drive.dm" @@ -2456,42 +3231,59 @@ #include "code\modules\modular_computers\hardware\scanners\scanner_paper.dm" #include "code\modules\modular_computers\hardware\scanners\scanner_reagent.dm" #include "code\modules\modular_computers\networking\_network.dm" +#include "code\modules\modular_computers\networking\network_cable.dm" #include "code\modules\modular_computers\networking\network_files.dm" +#include "code\modules\modular_computers\networking\network_helper.dm" +#include "code\modules\modular_computers\networking\accounts\_network_accounts.dm" +#include "code\modules\modular_computers\networking\accounts\account.dm" +#include "code\modules\modular_computers\networking\accounts\id_card.dm" #include "code\modules\modular_computers\networking\device_types\_network_device.dm" #include "code\modules\modular_computers\networking\device_types\acl.dm" #include "code\modules\modular_computers\networking\device_types\broadcaster.dm" +#include "code\modules\modular_computers\networking\device_types\id_card.dm" #include "code\modules\modular_computers\networking\device_types\mainframe.dm" +#include "code\modules\modular_computers\networking\device_types\modem.dm" #include "code\modules\modular_computers\networking\device_types\relay.dm" #include "code\modules\modular_computers\networking\device_types\router.dm" -#include "code\modules\modular_computers\networking\emails\_network_email.dm" -#include "code\modules\modular_computers\networking\emails\email_account.dm" +#include "code\modules\modular_computers\networking\device_types\stock_part.dm" +#include "code\modules\modular_computers\networking\emails\_email.dm" #include "code\modules\modular_computers\networking\emails\email_message.dm" #include "code\modules\modular_computers\networking\machinery\_network_machine.dm" #include "code\modules\modular_computers\networking\machinery\acl.dm" #include "code\modules\modular_computers\networking\machinery\mainframe.dm" +#include "code\modules\modular_computers\networking\machinery\modem.dm" #include "code\modules\modular_computers\networking\machinery\relay.dm" #include "code\modules\modular_computers\networking\machinery\router.dm" +#include "code\modules\modular_computers\networking\machinery\telecomms.dm" +#include "code\modules\modular_computers\networking\machinery\wall_relay.dm" +#include "code\modules\modular_computers\networking\machinery\wall_router.dm" #include "code\modules\modular_computers\networking\NTNRC\conversation.dm" -#include "code\modules\modular_computers\ntos\components.dm" -#include "code\modules\modular_computers\ntos\files.dm" -#include "code\modules\modular_computers\ntos\ntos.dm" -#include "code\modules\modular_computers\ntos\ui.dm" -#include "code\modules\modular_computers\ntos\visuals.dm" -#include "code\modules\modular_computers\ntos\subtypes\console.dm" -#include "code\modules\modular_computers\ntos\subtypes\device.dm" -#include "code\modules\modular_computers\ntos\subtypes\silicon.dm" +#include "code\modules\modular_computers\os\_os.dm" +#include "code\modules\modular_computers\os\components.dm" +#include "code\modules\modular_computers\os\files.dm" +#include "code\modules\modular_computers\os\ui.dm" +#include "code\modules\modular_computers\os\visuals.dm" +#include "code\modules\modular_computers\os\subtypes\console.dm" +#include "code\modules\modular_computers\os\subtypes\device.dm" +#include "code\modules\modular_computers\os\subtypes\silicon.dm" #include "code\modules\modular_computers\terminal\terminal.dm" #include "code\modules\modular_computers\terminal\terminal_commands.dm" #include "code\modules\modular_computers\terminal\terminal_remote.dm" #include "code\modules\modular_computers\terminal\terminal_skill_fail.dm" -#include "code\modules\multiz\_stubs.dm" #include "code\modules\multiz\basic.dm" #include "code\modules\multiz\hoist.dm" +#include "code\modules\multiz\ladder.dm" +#include "code\modules\multiz\level_data.dm" +#include "code\modules\multiz\level_persistence_handler.dm" +#include "code\modules\multiz\level_persistence_handler_json.dm" +#include "code\modules\multiz\level_persistence_serialization.dm" +#include "code\modules\multiz\map_data.dm" #include "code\modules\multiz\mobile_ladder.dm" #include "code\modules\multiz\movement.dm" #include "code\modules\multiz\pipes.dm" -#include "code\modules\multiz\structures.dm" +#include "code\modules\multiz\stairs.dm" #include "code\modules\multiz\turf.dm" +#include "code\modules\multiz\turf_mimic_edge.dm" #include "code\modules\multiz\zmimic\mimic_common.dm" #include "code\modules\multiz\zmimic\mimic_movable.dm" #include "code\modules\multiz\zmimic\mimic_turf.dm" @@ -2518,33 +3310,48 @@ #include "code\modules\nano\modules\law_manager.dm" #include "code\modules\nano\modules\nano_module.dm" #include "code\modules\organs\_organ_setup.dm" -#include "code\modules\organs\blood.dm" #include "code\modules\organs\organ.dm" +#include "code\modules\organs\organ_prosthetics.dm" #include "code\modules\organs\pain.dm" -#include "code\modules\organs\robolimbs.dm" +#include "code\modules\organs\ailments\_ailment.dm" +#include "code\modules\organs\ailments\ailment_codex.dm" +#include "code\modules\organs\ailments\ailments_medical.dm" +#include "code\modules\organs\ailments\faults\_fault.dm" +#include "code\modules\organs\ailments\faults\fault_acid_discharge.dm" +#include "code\modules\organs\ailments\faults\fault_elec_discharge.dm" +#include "code\modules\organs\ailments\faults\fault_itchy.dm" +#include "code\modules\organs\ailments\faults\fault_leaky.dm" +#include "code\modules\organs\ailments\faults\fault_locking_thumbs.dm" +#include "code\modules\organs\ailments\faults\fault_noisemaker.dm" +#include "code\modules\organs\ailments\faults\fault_overstimulation.dm" +#include "code\modules\organs\ailments\faults\fault_visual_impairment.dm" #include "code\modules\organs\external\_external.dm" #include "code\modules\organs\external\_external_damage.dm" #include "code\modules\organs\external\_external_icons.dm" #include "code\modules\organs\external\diagnostics.dm" #include "code\modules\organs\external\head.dm" +#include "code\modules\organs\external\insectoid.dm" +#include "code\modules\organs\external\quadruped.dm" #include "code\modules\organs\external\standard.dm" -#include "code\modules\organs\external\stump.dm" +#include "code\modules\organs\external\tail.dm" #include "code\modules\organs\external\unbreakable.dm" #include "code\modules\organs\external\wounds\wound.dm" #include "code\modules\organs\external\wounds\wound_types.dm" #include "code\modules\organs\internal\_internal.dm" #include "code\modules\organs\internal\appendix.dm" #include "code\modules\organs\internal\brain.dm" +#include "code\modules\organs\internal\brain_computer.dm" +#include "code\modules\organs\internal\cell.dm" #include "code\modules\organs\internal\eyes.dm" #include "code\modules\organs\internal\heart.dm" +#include "code\modules\organs\internal\insectoid.dm" #include "code\modules\organs\internal\kidneys.dm" #include "code\modules\organs\internal\liver.dm" #include "code\modules\organs\internal\lungs.dm" -#include "code\modules\organs\internal\posibrain.dm" #include "code\modules\organs\internal\stomach.dm" #include "code\modules\organs\internal\voice.dm" -#include "code\modules\organs\internal\species\golem.dm" #include "code\modules\overmap\_defines.dm" +#include "code\modules\overmap\_overmap.dm" #include "code\modules\overmap\overmap_object.dm" #include "code\modules\overmap\overmap_shuttle.dm" #include "code\modules\overmap\radio_beacon.dm" @@ -2560,28 +3367,21 @@ #include "code\modules\overmap\disperser\disperser_fire.dm" #include "code\modules\overmap\events\event.dm" #include "code\modules\overmap\exoplanets\_exoplanet.dm" -#include "code\modules\overmap\exoplanets\exoplanet_atmosphere.dm" -#include "code\modules\overmap\exoplanets\exoplanet_fauna.dm" -#include "code\modules\overmap\exoplanets\exoplanet_flora.dm" -#include "code\modules\overmap\exoplanets\exoplanet_skybox.dm" -#include "code\modules\overmap\exoplanets\random_map.dm" -#include "code\modules\overmap\exoplanets\turfs.dm" -#include "code\modules\overmap\exoplanets\planet_themes\_planet_theme.dm" -#include "code\modules\overmap\exoplanets\planet_themes\mountains.dm" -#include "code\modules\overmap\exoplanets\planet_themes\radiation_bombing.dm" -#include "code\modules\overmap\exoplanets\planet_themes\robotic_guardians.dm" -#include "code\modules\overmap\exoplanets\planet_themes\ruined_city.dm" -#include "code\modules\overmap\exoplanets\planet_types\barren.dm" -#include "code\modules\overmap\exoplanets\planet_types\chlorine.dm" -#include "code\modules\overmap\exoplanets\planet_types\desert.dm" -#include "code\modules\overmap\exoplanets\planet_types\grass.dm" -#include "code\modules\overmap\exoplanets\planet_types\shrouded.dm" -#include "code\modules\overmap\exoplanets\planet_types\snow.dm" -#include "code\modules\overmap\exoplanets\planet_types\volcanic.dm" +#include "code\modules\overmap\ftl_shunt\_shunt.dm" +#include "code\modules\overmap\ftl_shunt\computer.dm" +#include "code\modules\overmap\ftl_shunt\core.dm" +#include "code\modules\overmap\internet\internet_circuitboards.dm" +#include "code\modules\overmap\internet\internet_repeater.dm" +#include "code\modules\overmap\internet\internet_uplink.dm" +#include "code\modules\overmap\internet\sector_internet.dm" +#include "code\modules\overmap\planetoids\_planetoids.dm" +#include "code\modules\overmap\planetoids\planetoid_skybox.dm" #include "code\modules\overmap\ships\circuits.dm" +#include "code\modules\overmap\ships\created.dm" #include "code\modules\overmap\ships\landable.dm" #include "code\modules\overmap\ships\ship.dm" #include "code\modules\overmap\ships\ship_physics.dm" +#include "code\modules\overmap\ships\computers\comms.dm" #include "code\modules\overmap\ships\computers\engine_control.dm" #include "code\modules\overmap\ships\computers\helm.dm" #include "code\modules\overmap\ships\computers\sensors.dm" @@ -2592,6 +3392,9 @@ #include "code\modules\overmap\ships\device_types\gas_thruster.dm" #include "code\modules\overmap\ships\machines\fusion_thruster.dm" #include "code\modules\overmap\ships\machines\gas_thruster.dm" +#include "code\modules\overmap\ships\machines\ion_thruster.dm" +#include "code\modules\paperwork\_paper.dm" +#include "code\modules\paperwork\_paper_serde.dm" #include "code\modules\paperwork\adminpaper.dm" #include "code\modules\paperwork\bodyscan_paper.dm" #include "code\modules\paperwork\carbonpaper.dm" @@ -2600,20 +3403,25 @@ #include "code\modules\paperwork\filingcabinet.dm" #include "code\modules\paperwork\folders.dm" #include "code\modules\paperwork\handlabeler.dm" -#include "code\modules\paperwork\paper.dm" +#include "code\modules\paperwork\helpers.dm" #include "code\modules\paperwork\paper_bundle.dm" +#include "code\modules\paperwork\paper_plane.dm" #include "code\modules\paperwork\paper_sticky.dm" #include "code\modules\paperwork\paperbin.dm" #include "code\modules\paperwork\papershredder.dm" #include "code\modules\paperwork\photocopier.dm" #include "code\modules\paperwork\photography.dm" +#include "code\modules\paperwork\printer.dm" #include "code\modules\paperwork\silicon_photography.dm" #include "code\modules\paperwork\stamps.dm" +#include "code\modules\paperwork\toner_cartridge.dm" #include "code\modules\paperwork\pen\chameleon_pen.dm" #include "code\modules\paperwork\pen\crayon.dm" +#include "code\modules\paperwork\pen\crayon_edibility.dm" #include "code\modules\paperwork\pen\fancy.dm" #include "code\modules\paperwork\pen\multi_pen.dm" #include "code\modules\paperwork\pen\pen.dm" +#include "code\modules\paperwork\pen\quill_and_ink.dm" #include "code\modules\paperwork\pen\reagent_pen.dm" #include "code\modules\paperwork\pen\retractable_pen.dm" #include "code\modules\persistence\filth.dm" @@ -2627,25 +3435,42 @@ #include "code\modules\persistence\persistence_datum_paper.dm" #include "code\modules\persistence\persistence_datum_paper_sticky.dm" #include "code\modules\pointdefense\pointdefense.dm" -#include "code\modules\power\apc.dm" +#include "code\modules\posters\_poster.dm" +#include "code\modules\posters\_poster_design.dm" +#include "code\modules\posters\bs12.dm" +#include "code\modules\posture\_posture.dm" +#include "code\modules\posture\posture_bodytype.dm" +#include "code\modules\posture\posture_mob.dm" +#include "code\modules\posture\posture_subtypes.dm" +#include "code\modules\power\admin_setup_engine.dm" #include "code\modules\power\batteryrack.dm" #include "code\modules\power\breaker_box.dm" #include "code\modules\power\cable.dm" #include "code\modules\power\cell.dm" #include "code\modules\power\debug_items.dm" #include "code\modules\power\generator.dm" -#include "code\modules\power\gravitygenerator.dm" -#include "code\modules\power\lighting.dm" +#include "code\modules\power\heavycable.dm" #include "code\modules\power\port_gen.dm" #include "code\modules\power\power.dm" #include "code\modules\power\powernet.dm" +#include "code\modules\power\powernet_sensor.dm" #include "code\modules\power\smes.dm" #include "code\modules\power\smes_construction.dm" #include "code\modules\power\smes_presets.dm" #include "code\modules\power\solar.dm" +#include "code\modules\power\stirling.dm" #include "code\modules\power\terminal.dm" #include "code\modules\power\tracker.dm" #include "code\modules\power\turbine.dm" +#include "code\modules\power\apc\_apc.dm" +#include "code\modules\power\apc\apc_frame.dm" +#include "code\modules\power\apc\apc_presets.dm" +#include "code\modules\power\apc\apc_wires.dm" +#include "code\modules\power\fission\core.dm" +#include "code\modules\power\fission\core_control.dm" +#include "code\modules\power\fission\fission_circuits.dm" +#include "code\modules\power\fuel_assembly\fuel_assembly.dm" +#include "code\modules\power\fuel_assembly\fuel_compressor.dm" #include "code\modules\power\fusion\_setup.dm" #include "code\modules\power\fusion\fusion_circuits.dm" #include "code\modules\power\fusion\fusion_particle_catcher.dm" @@ -2657,19 +3482,19 @@ #include "code\modules\power\fusion\consoles\injector_control.dm" #include "code\modules\power\fusion\core\_core.dm" #include "code\modules\power\fusion\core\core_field.dm" -#include "code\modules\power\fusion\fuel_assembly\fuel_assembly.dm" -#include "code\modules\power\fusion\fuel_assembly\fuel_compressor.dm" -#include "code\modules\power\fusion\fuel_assembly\fuel_injector.dm" +#include "code\modules\power\fusion\fuel_injector\fuel_injector.dm" #include "code\modules\power\fusion\gyrotron\gyrotron.dm" -#include "code\modules\power\sensors\powernet_sensor.dm" -#include "code\modules\power\sensors\sensor_monitoring.dm" -#include "code\modules\power\singularity\act.dm" +#include "code\modules\power\geothermal\_geothermal.dm" +#include "code\modules\power\geothermal\geothermal_circuit.dm" +#include "code\modules\power\geothermal\geothermal_extension.dm" #include "code\modules\power\singularity\collector.dm" #include "code\modules\power\singularity\containment_field.dm" #include "code\modules\power\singularity\emitter.dm" #include "code\modules\power\singularity\field_generator.dm" #include "code\modules\power\singularity\generator.dm" #include "code\modules\power\singularity\singularity.dm" +#include "code\modules\power\singularity\singularity_events.dm" +#include "code\modules\power\singularity\singularity_stages.dm" #include "code\modules\power\singularity\particle_accelerator\particle.dm" #include "code\modules\power\singularity\particle_accelerator\particle_accelerator.dm" #include "code\modules\power\singularity\particle_accelerator\particle_chamber.dm" @@ -2677,7 +3502,6 @@ #include "code\modules\power\singularity\particle_accelerator\particle_emitter.dm" #include "code\modules\power\singularity\particle_accelerator\particle_power.dm" #include "code\modules\projectiles\ammunition.dm" -#include "code\modules\projectiles\effects.dm" #include "code\modules\projectiles\gun.dm" #include "code\modules\projectiles\projectile.dm" #include "code\modules\projectiles\secure.dm" @@ -2701,20 +3525,27 @@ #include "code\modules\projectiles\guns\energy\staves.dm" #include "code\modules\projectiles\guns\energy\stun.dm" #include "code\modules\projectiles\guns\energy\temperature.dm" -#include "code\modules\projectiles\guns\energy\vox.dm" #include "code\modules\projectiles\guns\energy\xray.dm" -#include "code\modules\projectiles\guns\launcher\alien.dm" -#include "code\modules\projectiles\guns\launcher\crossbow.dm" #include "code\modules\projectiles\guns\launcher\foam_gun.dm" #include "code\modules\projectiles\guns\launcher\grenade_launcher.dm" #include "code\modules\projectiles\guns\launcher\money_cannon.dm" #include "code\modules\projectiles\guns\launcher\pneumatic.dm" #include "code\modules\projectiles\guns\launcher\rocket.dm" -#include "code\modules\projectiles\guns\launcher\slugsling.dm" #include "code\modules\projectiles\guns\launcher\syringe_gun.dm" +#include "code\modules\projectiles\guns\launcher\bows\_bow.dm" +#include "code\modules\projectiles\guns\launcher\bows\arrow.dm" +#include "code\modules\projectiles\guns\launcher\bows\bow_drawing.dm" +#include "code\modules\projectiles\guns\launcher\bows\bow_firing.dm" +#include "code\modules\projectiles\guns\launcher\bows\bow_interaction.dm" +#include "code\modules\projectiles\guns\launcher\bows\bow_messages.dm" +#include "code\modules\projectiles\guns\launcher\bows\bow_string.dm" +#include "code\modules\projectiles\guns\launcher\bows\crossbow.dm" +#include "code\modules\projectiles\guns\launcher\bows\crossbow_powered.dm" +#include "code\modules\projectiles\guns\launcher\bows\sling.dm" #include "code\modules\projectiles\guns\magnetic\magnetic.dm" #include "code\modules\projectiles\guns\magnetic\magnetic_railgun.dm" #include "code\modules\projectiles\guns\projectile\automatic.dm" +#include "code\modules\projectiles\guns\projectile\bolt_action.dm" #include "code\modules\projectiles\guns\projectile\dartgun.dm" #include "code\modules\projectiles\guns\projectile\flaregun.dm" #include "code\modules\projectiles\guns\projectile\lasvolver.dm" @@ -2722,27 +3553,32 @@ #include "code\modules\projectiles\guns\projectile\random_pistol.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" #include "code\modules\projectiles\guns\projectile\shotgun.dm" -#include "code\modules\projectiles\guns\projectile\sniper.dm" #include "code\modules\projectiles\guns\projectile\zipgun.dm" #include "code\modules\projectiles\projectile\animate.dm" #include "code\modules\projectiles\projectile\beams.dm" #include "code\modules\projectiles\projectile\bullets.dm" #include "code\modules\projectiles\projectile\change.dm" #include "code\modules\projectiles\projectile\energy.dm" +#include "code\modules\projectiles\projectile\fireball.dm" #include "code\modules\projectiles\projectile\force.dm" #include "code\modules\projectiles\projectile\magnetic.dm" #include "code\modules\projectiles\projectile\pellets.dm" #include "code\modules\projectiles\projectile\special.dm" -#include "code\modules\projectiles\targeting\targeting_client.dm" +#include "code\modules\projectiles\projectile\trace.dm" +#include "code\modules\projectiles\projectile\effects\projectile_effects.dm" +#include "code\modules\projectiles\projectile\effects\projectile_impact.dm" +#include "code\modules\projectiles\projectile\effects\projectile_muzzle.dm" +#include "code\modules\projectiles\projectile\effects\projectile_tracer.dm" #include "code\modules\projectiles\targeting\targeting_gun.dm" #include "code\modules\projectiles\targeting\targeting_mob.dm" #include "code\modules\projectiles\targeting\targeting_overlay.dm" #include "code\modules\projectiles\targeting\targeting_triggers.dm" -#include "code\modules\prometheus_metrics\_defines.dm" -#include "code\modules\prometheus_metrics\metric_family.dm" -#include "code\modules\prometheus_metrics\metrics.dm" -#include "code\modules\prometheus_metrics\metrics\byond.dm" -#include "code\modules\prometheus_metrics\metrics\ss13.dm" +#include "code\modules\pronouns\_pronouns.dm" +#include "code\modules\pronouns\pronouns_female.dm" +#include "code\modules\pronouns\pronouns_male.dm" +#include "code\modules\pronouns\pronouns_neuter.dm" +#include "code\modules\pronouns\pronouns_pseudoplural.dm" +#include "code\modules\pronouns\pronouns_second_person.dm" #include "code\modules\radiation\radiation.dm" #include "code\modules\random_map\_random_map_setup.dm" #include "code\modules\random_map\random_map.dm" @@ -2766,6 +3602,7 @@ #include "code\modules\random_map\mazes\maze.dm" #include "code\modules\random_map\mazes\maze_cell.dm" #include "code\modules\random_map\noise\desert.dm" +#include "code\modules\random_map\noise\forage.dm" #include "code\modules\random_map\noise\magma.dm" #include "code\modules\random_map\noise\noise.dm" #include "code\modules\random_map\noise\ore.dm" @@ -2774,25 +3611,29 @@ #include "code\modules\reagents\Chemistry-Colours.dm" #include "code\modules\reagents\Chemistry-Grinder.dm" #include "code\modules\reagents\Chemistry-Holder.dm" -#include "code\modules\reagents\Chemistry-Logging.dm" #include "code\modules\reagents\Chemistry-Machinery.dm" #include "code\modules\reagents\Chemistry-Metabolism.dm" +#include "code\modules\reagents\Chemistry-Taste.dm" #include "code\modules\reagents\cocktails.dm" +#include "code\modules\reagents\reagent_container_edibility.dm" #include "code\modules\reagents\reagent_containers.dm" #include "code\modules\reagents\reagent_dispenser.dm" +#include "code\modules\reagents\chems\chems_alcohol.dm" #include "code\modules\reagents\chems\chems_blood.dm" #include "code\modules\reagents\chems\chems_cleaner.dm" #include "code\modules\reagents\chems\chems_compounds.dm" #include "code\modules\reagents\chems\chems_drinks.dm" #include "code\modules\reagents\chems\chems_drugs.dm" -#include "code\modules\reagents\chems\chems_ethanol.dm" #include "code\modules\reagents\chems\chems_explosives.dm" #include "code\modules\reagents\chems\chems_fuel.dm" +#include "code\modules\reagents\chems\chems_herbal.dm" #include "code\modules\reagents\chems\chems_medicines.dm" #include "code\modules\reagents\chems\chems_nutriment.dm" +#include "code\modules\reagents\chems\chems_oil.dm" #include "code\modules\reagents\chems\chems_painkillers.dm" #include "code\modules\reagents\chems\chems_pigments.dm" #include "code\modules\reagents\chems\chems_poisons.dm" +#include "code\modules\reagents\chems\chems_psychiatric.dm" #include "code\modules\reagents\chems\random\chems_random.dm" #include "code\modules\reagents\chems\random\random_effects.dm" #include "code\modules\reagents\dispenser\_defines.dm" @@ -2804,61 +3645,154 @@ #include "code\modules\reagents\heat_sources\_heat_source.dm" #include "code\modules\reagents\reactions\_reaction.dm" #include "code\modules\reagents\reactions\reaction_alcohol.dm" +#include "code\modules\reagents\reactions\reaction_alloys.dm" #include "code\modules\reagents\reactions\reaction_cafe.dm" +#include "code\modules\reagents\reactions\reaction_compounds.dm" #include "code\modules\reagents\reactions\reaction_drinks.dm" #include "code\modules\reagents\reactions\reaction_drinks_hidden.dm" #include "code\modules\reagents\reactions\reaction_drugs.dm" #include "code\modules\reagents\reactions\reaction_grenade_reaction.dm" +#include "code\modules\reagents\reactions\reaction_herbal.dm" #include "code\modules\reagents\reactions\reaction_other.dm" #include "code\modules\reagents\reactions\reaction_recipe.dm" #include "code\modules\reagents\reactions\reaction_recipe_food.dm" -#include "code\modules\reagents\reactions\reaction_slimes.dm" #include "code\modules\reagents\reactions\reaction_synthesis.dm" +#include "code\modules\reagents\reagent_containers\_glass.dm" +#include "code\modules\reagents\reagent_containers\_glass_edibility.dm" #include "code\modules\reagents\reagent_containers\beaker.dm" #include "code\modules\reagents\reagent_containers\blood_pack.dm" -#include "code\modules\reagents\reagent_containers\borghydro.dm" +#include "code\modules\reagents\reagent_containers\borghypo.dm" +#include "code\modules\reagents\reagent_containers\bowl.dm" +#include "code\modules\reagents\reagent_containers\bucket.dm" +#include "code\modules\reagents\reagent_containers\drinks.dm" #include "code\modules\reagents\reagent_containers\dropper.dm" #include "code\modules\reagents\reagent_containers\food.dm" -#include "code\modules\reagents\reagent_containers\glass.dm" +#include "code\modules\reagents\reagent_containers\food_cooking.dm" +#include "code\modules\reagents\reagent_containers\food_edibility.dm" #include "code\modules\reagents\reagent_containers\hypospray.dm" +#include "code\modules\reagents\reagent_containers\inhaler.dm" +#include "code\modules\reagents\reagent_containers\mortar.dm" +#include "code\modules\reagents\reagent_containers\packets.dm" #include "code\modules\reagents\reagent_containers\pill.dm" +#include "code\modules\reagents\reagent_containers\pill_edibility.dm" +#include "code\modules\reagents\reagent_containers\retort.dm" #include "code\modules\reagents\reagent_containers\spray.dm" #include "code\modules\reagents\reagent_containers\syringes.dm" +#include "code\modules\reagents\reagent_containers\condiments\__condiment.dm" +#include "code\modules\reagents\reagent_containers\condiments\__condiment_appearance.dm" +#include "code\modules\reagents\reagent_containers\condiments\_condiment_large.dm" +#include "code\modules\reagents\reagent_containers\condiments\_condiment_small.dm" +#include "code\modules\reagents\reagent_containers\condiments\condiment_appearance.dm" +#include "code\modules\reagents\reagent_containers\condiments\condiments.dm" +#include "code\modules\reagents\reagent_containers\condiments\condiments_large.dm" +#include "code\modules\reagents\reagent_containers\condiments\condiments_small.dm" #include "code\modules\reagents\reagent_containers\drinkingglass\drinkingglass.dm" #include "code\modules\reagents\reagent_containers\drinkingglass\extras.dm" #include "code\modules\reagents\reagent_containers\drinkingglass\glass_boxes.dm" #include "code\modules\reagents\reagent_containers\drinkingglass\glass_types.dm" #include "code\modules\reagents\reagent_containers\drinkingglass\shaker.dm" -#include "code\modules\reagents\reagent_containers\food\cans.dm" -#include "code\modules\reagents\reagent_containers\food\condiment.dm" -#include "code\modules\reagents\reagent_containers\food\drinks.dm" +#include "code\modules\reagents\reagent_containers\drinks\bottle.dm" +#include "code\modules\reagents\reagent_containers\drinks\cans.dm" +#include "code\modules\reagents\reagent_containers\drinks\cocktailshaker.dm" +#include "code\modules\reagents\reagent_containers\drinks\juicebox.dm" +#include "code\modules\reagents\reagent_containers\food\burgers.dm" +#include "code\modules\reagents\reagent_containers\food\donkpocket.dm" +#include "code\modules\reagents\reagent_containers\food\eggs.dm" #include "code\modules\reagents\reagent_containers\food\fish.dm" +#include "code\modules\reagents\reagent_containers\food\fried.dm" +#include "code\modules\reagents\reagent_containers\food\hotdog.dm" +#include "code\modules\reagents\reagent_containers\food\junkfood.dm" #include "code\modules\reagents\reagent_containers\food\lunch.dm" +#include "code\modules\reagents\reagent_containers\food\misc.dm" +#include "code\modules\reagents\reagent_containers\food\pasta.dm" +#include "code\modules\reagents\reagent_containers\food\rice.dm" +#include "code\modules\reagents\reagent_containers\food\rotten.dm" #include "code\modules\reagents\reagent_containers\food\sandwich.dm" -#include "code\modules\reagents\reagent_containers\food\shaker.dm" -#include "code\modules\reagents\reagent_containers\food\snacks.dm" +#include "code\modules\reagents\reagent_containers\food\skewer.dm" +#include "code\modules\reagents\reagent_containers\food\soy.dm" #include "code\modules\reagents\reagent_containers\food\sushi.dm" -#include "code\modules\reagents\reagent_containers\food\drinks\bottle.dm" -#include "code\modules\reagents\reagent_containers\food\drinks\jar.dm" -#include "code\modules\reagents\reagent_containers\food\drinks\juicebox.dm" -#include "code\modules\reagents\reagent_containers\food\snacks\meat.dm" +#include "code\modules\reagents\reagent_containers\food\veggie.dm" +#include "code\modules\reagents\reagent_containers\food\baking\baked_goods.dm" +#include "code\modules\reagents\reagent_containers\food\baking\bread.dm" +#include "code\modules\reagents\reagent_containers\food\baking\cookie.dm" +#include "code\modules\reagents\reagent_containers\food\baking\donuts.dm" +#include "code\modules\reagents\reagent_containers\food\baking\leavened_dough.dm" +#include "code\modules\reagents\reagent_containers\food\baking\piecrust.dm" +#include "code\modules\reagents\reagent_containers\food\baking\pies.dm" +#include "code\modules\reagents\reagent_containers\food\baking\unleavened_dough.dm" +#include "code\modules\reagents\reagent_containers\food\canned\_canned.dm" +#include "code\modules\reagents\reagent_containers\food\canned\can_edibility.dm" +#include "code\modules\reagents\reagent_containers\food\chocolate\chocolate.dm" +#include "code\modules\reagents\reagent_containers\food\dairy\_dairy.dm" +#include "code\modules\reagents\reagent_containers\food\dairy\butter.dm" +#include "code\modules\reagents\reagent_containers\food\dairy\cheeses.dm" +#include "code\modules\reagents\reagent_containers\food\meat\cubes.dm" +#include "code\modules\reagents\reagent_containers\food\meat\fish.dm" +#include "code\modules\reagents\reagent_containers\food\meat\jerky.dm" +#include "code\modules\reagents\reagent_containers\food\meat\meat.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\_sliceable.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\cakes.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\loaves.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\pizza\_pizza.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\pizza\pizza_box.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\pizza\pizza_margherita.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\pizza\pizza_meat.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\pizza\pizza_mushroom.dm" +#include "code\modules\reagents\reagent_containers\food\sliceable\pizza\pizza_vegetable.dm" #include "code\modules\reagents\reagent_containers\glass\bottle.dm" #include "code\modules\reagents\reagent_containers\glass\bottle\robot.dm" #include "code\modules\reagents\storage\pill_bottle.dm" #include "code\modules\reagents\storage\pill_bottle_subtypes.dm" #include "code\modules\reagents\storage\pill_foil.dm" #include "code\modules\recycling\conveyor2.dm" +#include "code\modules\recycling\destination_tagger.dm" #include "code\modules\recycling\disposal-construction.dm" #include "code\modules\recycling\disposal.dm" #include "code\modules\recycling\disposalholder.dm" #include "code\modules\recycling\disposalpipe.dm" +#include "code\modules\recycling\package_wrapper.dm" +#include "code\modules\recycling\sort_tag.dm" #include "code\modules\recycling\sortingmachinery.dm" +#include "code\modules\recycling\wrapped_package.dm" #include "code\modules\research\_design.dm" #include "code\modules\research\design_console.dm" #include "code\modules\research\design_database.dm" #include "code\modules\research\design_database_analyzer.dm" #include "code\modules\research\research_fields.dm" -#include "code\modules\security levels\keycard_authentication.dm" +#include "code\modules\salvage\salvage.dm" +#include "code\modules\salvage\salvage_ballistic.dm" +#include "code\modules\salvage\salvage_energy.dm" +#include "code\modules\salvage\salvage_launcher.dm" +#include "code\modules\salvage\salvage_magnetic.dm" +#include "code\modules\salvage\salvage_repair_option.dm" +#include "code\modules\salvage\salvage_repair_requirement.dm" +#include "code\modules\salvage\structure.dm" +#include "code\modules\salvage\structure_computer.dm" +#include "code\modules\salvage\structure_console.dm" +#include "code\modules\salvage\structure_machine.dm" +#include "code\modules\salvage\structure_misc.dm" +#include "code\modules\salvage\structure_terminal.dm" +#include "code\modules\scanners\_scanner.dm" +#include "code\modules\scanners\breath.dm" +#include "code\modules\scanners\gas.dm" +#include "code\modules\scanners\health.dm" +#include "code\modules\scanners\mass_spectrometer.dm" +#include "code\modules\scanners\mining.dm" +#include "code\modules\scanners\network.dm" +#include "code\modules\scanners\plant.dm" +#include "code\modules\scanners\price.dm" +#include "code\modules\scanners\reagents.dm" +#include "code\modules\scanners\xenobio.dm" +#include "code\modules\scent\_scent.dm" +#include "code\modules\scent\scent_candle.dm" +#include "code\modules\scent\scent_decls.dm" +#include "code\modules\scent\scent_misc.dm" +#include "code\modules\security_levels\_security_level.dm" +#include "code\modules\security_levels\alarm_appearance.dm" +#include "code\modules\security_levels\keycard_authentication.dm" +#include "code\modules\security_levels\keycard_authentication_events.dm" +#include "code\modules\security_levels\security_levels.dm" +#include "code\modules\security_levels\security_state.dm" #include "code\modules\shield_generators\floor_diffuser.dm" #include "code\modules\shield_generators\handheld_diffuser.dm" #include "code\modules\shield_generators\modes.dm" @@ -2869,12 +3803,14 @@ #include "code\modules\shieldgen\shieldwallgen.dm" #include "code\modules\shuttles\antagonist.dm" #include "code\modules\shuttles\departmental.dm" +#include "code\modules\shuttles\docking_beacon.dm" #include "code\modules\shuttles\escape_pods.dm" #include "code\modules\shuttles\landmarks.dm" #include "code\modules\shuttles\shuttle.dm" #include "code\modules\shuttles\shuttle_autodock.dm" #include "code\modules\shuttles\shuttle_console.dm" #include "code\modules\shuttles\shuttle_console_multi.dm" +#include "code\modules\shuttles\shuttle_created.dm" #include "code\modules\shuttles\shuttle_emergency.dm" #include "code\modules\shuttles\shuttle_engines.dm" #include "code\modules\shuttles\shuttle_ferry.dm" @@ -2883,113 +3819,55 @@ #include "code\modules\shuttles\shuttle_supply.dm" #include "code\modules\shuttles\shuttles_multi.dm" #include "code\modules\species\species.dm" +#include "code\modules\species\species_allergies.dm" #include "code\modules\species\species_attack.dm" #include "code\modules\species\species_getters.dm" #include "code\modules\species\species_helpers.dm" #include "code\modules\species\species_hud.dm" -#include "code\modules\species\species_random.dm" -#include "code\modules\species\species_shapeshift.dm" -#include "code\modules\species\outsider\random.dm" -#include "code\modules\species\station\golem.dm" +#include "code\modules\species\station\human.dm" +#include "code\modules\species\station\human_bodytypes.dm" #include "code\modules\species\station\monkey.dm" -#include "code\modules\species\station\station.dm" -#include "code\modules\species\station\utility_frame.dm" -#include "code\modules\spells\artifacts.dm" -#include "code\modules\spells\construct_spells.dm" -#include "code\modules\spells\contracts.dm" -#include "code\modules\spells\no_clothes.dm" -#include "code\modules\spells\racial_wizard.dm" -#include "code\modules\spells\spell_code.dm" -#include "code\modules\spells\spell_projectile.dm" -#include "code\modules\spells\spellbook.dm" -#include "code\modules\spells\spells.dm" -#include "code\modules\spells\aoe_turf\aoe_turf.dm" -#include "code\modules\spells\aoe_turf\blink.dm" -#include "code\modules\spells\aoe_turf\charge.dm" -#include "code\modules\spells\aoe_turf\disable_tech.dm" -#include "code\modules\spells\aoe_turf\drain_blood.dm" -#include "code\modules\spells\aoe_turf\exchange_wounds.dm" -#include "code\modules\spells\aoe_turf\knock.dm" -#include "code\modules\spells\aoe_turf\smoke.dm" -#include "code\modules\spells\aoe_turf\summons.dm" -#include "code\modules\spells\aoe_turf\conjure\conjure.dm" -#include "code\modules\spells\aoe_turf\conjure\construct.dm" -#include "code\modules\spells\aoe_turf\conjure\druidic_spells.dm" -#include "code\modules\spells\aoe_turf\conjure\faithful_hound.dm" -#include "code\modules\spells\aoe_turf\conjure\force_portal.dm" -#include "code\modules\spells\aoe_turf\conjure\forcewall.dm" -#include "code\modules\spells\aoe_turf\conjure\grove.dm" -#include "code\modules\spells\artifacts\spellbound_servants.dm" -#include "code\modules\spells\artifacts\storage.dm" -#include "code\modules\spells\general\acid_spray.dm" -#include "code\modules\spells\general\area_teleport.dm" -#include "code\modules\spells\general\contract_spells.dm" -#include "code\modules\spells\general\create_air.dm" -#include "code\modules\spells\general\god_construct.dm" -#include "code\modules\spells\general\god_vision.dm" -#include "code\modules\spells\general\invisibility.dm" -#include "code\modules\spells\general\mark_recall.dm" -#include "code\modules\spells\general\open_gateway.dm" -#include "code\modules\spells\general\portal_teleport.dm" -#include "code\modules\spells\general\radiant_aura.dm" -#include "code\modules\spells\general\return_master.dm" -#include "code\modules\spells\general\tear_veil.dm" -#include "code\modules\spells\general\toggle_armor.dm" -#include "code\modules\spells\general\veil_of_shadows.dm" -#include "code\modules\spells\hand\blood_shards.dm" -#include "code\modules\spells\hand\burning_grip.dm" -#include "code\modules\spells\hand\entangle.dm" -#include "code\modules\spells\hand\hand.dm" -#include "code\modules\spells\hand\hand_item.dm" -#include "code\modules\spells\hand\slippery_surface.dm" -#include "code\modules\spells\hand\sunwrath.dm" -#include "code\modules\spells\spellbook\battlemage.dm" -#include "code\modules\spells\spellbook\cleric.dm" -#include "code\modules\spells\spellbook\druid.dm" -#include "code\modules\spells\spellbook\spatial.dm" -#include "code\modules\spells\spellbook\standard.dm" -#include "code\modules\spells\spellbook\student.dm" -#include "code\modules\spells\targeted\analyze.dm" -#include "code\modules\spells\targeted\blood_boil.dm" -#include "code\modules\spells\targeted\cleric_spells.dm" -#include "code\modules\spells\targeted\ethereal_jaunt.dm" -#include "code\modules\spells\targeted\exhude_pleasantness.dm" -#include "code\modules\spells\targeted\genetic.dm" -#include "code\modules\spells\targeted\glimpse_of_eternity.dm" -#include "code\modules\spells\targeted\harvest.dm" -#include "code\modules\spells\targeted\shapeshift.dm" -#include "code\modules\spells\targeted\shatter_mind.dm" -#include "code\modules\spells\targeted\shift.dm" -#include "code\modules\spells\targeted\subjugate.dm" -#include "code\modules\spells\targeted\swap.dm" -#include "code\modules\spells\targeted\targeted.dm" -#include "code\modules\spells\targeted\torment.dm" -#include "code\modules\spells\targeted\equip\burning_touch.dm" -#include "code\modules\spells\targeted\equip\dyrnwyn.dm" -#include "code\modules\spells\targeted\equip\equip.dm" -#include "code\modules\spells\targeted\equip\holy_relic.dm" -#include "code\modules\spells\targeted\equip\horsemask.dm" -#include "code\modules\spells\targeted\equip\party_hardy.dm" -#include "code\modules\spells\targeted\equip\seed.dm" -#include "code\modules\spells\targeted\equip\shield.dm" -#include "code\modules\spells\targeted\projectile\dumbfire.dm" -#include "code\modules\spells\targeted\projectile\fireball.dm" -#include "code\modules\spells\targeted\projectile\magic_missile.dm" -#include "code\modules\spells\targeted\projectile\passage.dm" -#include "code\modules\spells\targeted\projectile\projectile.dm" -#include "code\modules\spells\targeted\projectile\stuncuff.dm" +#include "code\modules\species\station\monkey_bodytypes.dm" #include "code\modules\sprite_accessories\_accessory.dm" -#include "code\modules\sprite_accessories\_accessory_facial.dm" -#include "code\modules\sprite_accessories\_accessory_hair.dm" -#include "code\modules\sprite_accessories\_accessory_markings.dm" -#include "code\modules\sprite_accessories\_accessory_skin.dm" +#include "code\modules\sprite_accessories\_accessory_category.dm" +#include "code\modules\sprite_accessories\cosmetics\_accessory_cosmetics.dm" +#include "code\modules\sprite_accessories\ears\_accessory_ears.dm" +#include "code\modules\sprite_accessories\ears\accessory_ears_antennae.dm" +#include "code\modules\sprite_accessories\facial\_accessory_facial.dm" +#include "code\modules\sprite_accessories\facial\accessory_facial_hair.dm" +#include "code\modules\sprite_accessories\frills\_accessory_frills.dm" +#include "code\modules\sprite_accessories\hair\_accessory_hair.dm" +#include "code\modules\sprite_accessories\hair\accessory_hair_bedhead.dm" +#include "code\modules\sprite_accessories\hair\accessory_hair_braids.dm" +#include "code\modules\sprite_accessories\hair\accessory_hair_misc.dm" +#include "code\modules\sprite_accessories\hair\accessory_hair_ponytail.dm" +#include "code\modules\sprite_accessories\hair\accessory_hair_undercut.dm" +#include "code\modules\sprite_accessories\horns\_accessory_horns.dm" +#include "code\modules\sprite_accessories\markings\_accessory_markings.dm" +#include "code\modules\sprite_accessories\markings\accessory_markings_bandages.dm" +#include "code\modules\sprite_accessories\markings\accessory_markings_face.dm" +#include "code\modules\sprite_accessories\markings\accessory_markings_scars.dm" +#include "code\modules\sprite_accessories\markings\accessory_markings_tattoos.dm" +#include "code\modules\sprite_accessories\metadata\_accessory_metadata.dm" +#include "code\modules\sprite_accessories\metadata\accessory_metadata_color.dm" +#include "code\modules\sprite_accessories\metadata\accessory_metadata_gradient.dm" +#include "code\modules\sprite_accessories\tails\_accessory_tail.dm" +#include "code\modules\status_conditions\_status_condition.dm" +#include "code\modules\status_conditions\_status_markers.dm" +#include "code\modules\status_conditions\status_counters_simple.dm" +#include "code\modules\status_conditions\definitions\status_dizzy.dm" +#include "code\modules\status_conditions\definitions\status_jittery.dm" +#include "code\modules\status_conditions\definitions\status_paralyzed.dm" +#include "code\modules\status_conditions\definitions\status_sleeping.dm" +#include "code\modules\status_conditions\definitions\status_stunned.dm" +#include "code\modules\status_conditions\definitions\status_weakened.dm" +#include "code\modules\stressors\_stressor.dm" +#include "code\modules\stressors\stressor_definitions.dm" #include "code\modules\submaps\_submap.dm" #include "code\modules\submaps\submap_archetype.dm" #include "code\modules\submaps\submap_job.dm" #include "code\modules\submaps\submap_join.dm" #include "code\modules\submaps\submap_landmark.dm" -#include "code\modules\supermatter\setup_supermatter.dm" -#include "code\modules\supermatter\supermatter.dm" #include "code\modules\surgery\__surgery_setup.dm" #include "code\modules\surgery\_surgery.dm" #include "code\modules\surgery\bones.dm" @@ -2999,10 +3877,10 @@ #include "code\modules\surgery\generic.dm" #include "code\modules\surgery\implant.dm" #include "code\modules\surgery\limb_reattach.dm" +#include "code\modules\surgery\necrotic.dm" #include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\other.dm" #include "code\modules\surgery\robotics.dm" -#include "code\modules\surgery\slimes.dm" #include "code\modules\surgery\suture_wounds.dm" #include "code\modules\synthesized_instruments\echo_editor.dm" #include "code\modules\synthesized_instruments\env_editor.dm" @@ -3028,12 +3906,30 @@ #include "code\modules\synthesized_instruments\real_instruments\Synthesizer\synthesizer.dm" #include "code\modules\synthesized_instruments\real_instruments\Trumpet\trumpet.dm" #include "code\modules\synthesized_instruments\real_instruments\Violin\violin.dm" -#include "code\modules\tables\flipping.dm" -#include "code\modules\tables\interactions.dm" -#include "code\modules\tables\presets.dm" -#include "code\modules\tables\rack.dm" -#include "code\modules\tables\tables.dm" -#include "code\modules\tables\update_triggers.dm" +#include "code\modules\tools\tool.dm" +#include "code\modules\tools\tool_serde.dm" +#include "code\modules\tools\archetypes\_tool_defines.dm" +#include "code\modules\tools\archetypes\tool_archetype.dm" +#include "code\modules\tools\archetypes\tool_archetype_definition_pen.dm" +#include "code\modules\tools\archetypes\tool_archetype_definitions.dm" +#include "code\modules\tools\archetypes\tool_archetype_definitions_surgery.dm" +#include "code\modules\tools\archetypes\tool_archetype_definitions_welder.dm" +#include "code\modules\tools\archetypes\tool_extension.dm" +#include "code\modules\tools\archetypes\tool_extension_variable.dm" +#include "code\modules\tools\archetypes\tool_item.dm" +#include "code\modules\tools\components\_component.dm" +#include "code\modules\tools\components\handle.dm" +#include "code\modules\tools\components\head.dm" +#include "code\modules\tools\components\recipes.dm" +#include "code\modules\tools\subtypes\axes.dm" +#include "code\modules\tools\subtypes\drills.dm" +#include "code\modules\tools\subtypes\hammers.dm" +#include "code\modules\tools\subtypes\hoes.dm" +#include "code\modules\tools\subtypes\machetes.dm" +#include "code\modules\tools\subtypes\pickaxes.dm" +#include "code\modules\tools\subtypes\power_tools.dm" +#include "code\modules\tools\subtypes\shovel.dm" +#include "code\modules\tools\subtypes\xenoarchaeology_picks.dm" #include "code\modules\tooltip\tooltip.dm" #include "code\modules\turbolift\turbolift.dm" #include "code\modules\turbolift\turbolift_areas.dm" @@ -3044,24 +3940,37 @@ #include "code\modules\turbolift\turbolift_turfs.dm" #include "code\modules\vehicles\bike.dm" #include "code\modules\vehicles\cargo_train.dm" +#include "code\modules\vehicles\cargo_trolley.dm" #include "code\modules\vehicles\engine.dm" +#include "code\modules\vehicles\quad_bike.dm" +#include "code\modules\vehicles\quad_trailer.dm" #include "code\modules\vehicles\train.dm" #include "code\modules\vehicles\vehicle.dm" -#include "code\modules\ventcrawl\ventcrawl.dm" -#include "code\modules\ventcrawl\ventcrawl_atmospherics.dm" -#include "code\modules\ventcrawl\ventcrawl_multiz.dm" -#include "code\modules\ventcrawl\ventcrawl_verb.dm" +#include "code\modules\weather\_weather.dm" +#include "code\modules\weather\weather_debug.dm" +#include "code\modules\weather\weather_effects.dm" +#include "code\modules\weather\weather_fsm.dm" +#include "code\modules\weather\weather_fsm_state_transitions.dm" +#include "code\modules\weather\weather_fsm_states.dm" +#include "code\modules\weather\weather_helpers.dm" +#include "code\modules\weather\weather_init.dm" +#include "code\modules\weather\weather_mob_tracking.dm" +#include "code\modules\weather\weather_wind.dm" #include "code\modules\webhooks\_webhook.dm" +#include "code\modules\webhooks\webhook_ahelp2discord.dm" #include "code\modules\webhooks\webhook_custom_event.dm" #include "code\modules\webhooks\webhook_elevator_fall.dm" +#include "code\modules\webhooks\webhook_fax.dm" #include "code\modules\webhooks\webhook_roundend.dm" #include "code\modules\webhooks\webhook_roundprep.dm" #include "code\modules\webhooks\webhook_roundstart.dm" #include "code\modules\webhooks\webhook_submap.dm" +#include "code\modules\xenoarcheaology\_xenoarch.dm" #include "code\modules\xenoarcheaology\boulder.dm" #include "code\modules\xenoarcheaology\artifacts\artifact.dm" #include "code\modules\xenoarcheaology\artifacts\artifact_appearance.dm" #include "code\modules\xenoarcheaology\artifacts\effects\_effect.dm" +#include "code\modules\xenoarcheaology\artifacts\effects\badfeeling.dm" #include "code\modules\xenoarcheaology\artifacts\effects\cellcharge.dm" #include "code\modules\xenoarcheaology\artifacts\effects\celldrain.dm" #include "code\modules\xenoarcheaology\artifacts\effects\dnaswitch.dm" @@ -3090,6 +3999,7 @@ #include "code\modules\xenoarcheaology\artifacts\triggers\temperature.dm" #include "code\modules\xenoarcheaology\artifacts\triggers\touch.dm" #include "code\modules\xenoarcheaology\datums\artifact_find.dm" +#include "code\modules\xenoarcheaology\datums\engravings_flavor.dm" #include "code\modules\xenoarcheaology\datums\geosample.dm" #include "code\modules\xenoarcheaology\finds\_finds.dm" #include "code\modules\xenoarcheaology\finds\digsite_types.dm" @@ -3099,7 +4009,6 @@ #include "code\modules\xenoarcheaology\finds\find_types\_find_spawner.dm" #include "code\modules\xenoarcheaology\finds\find_types\chem_containers.dm" #include "code\modules\xenoarcheaology\finds\find_types\containers.dm" -#include "code\modules\xenoarcheaology\finds\find_types\cult.dm" #include "code\modules\xenoarcheaology\finds\find_types\fossils.dm" #include "code\modules\xenoarcheaology\finds\find_types\guns.dm" #include "code\modules\xenoarcheaology\finds\find_types\mask.dm" @@ -3120,10 +4029,8 @@ #include "code\modules\xenoarcheaology\tools\depth_scanner.dm" #include "code\modules\xenoarcheaology\tools\equipment.dm" #include "code\modules\xenoarcheaology\tools\misc.dm" -#include "code\modules\xenoarcheaology\tools\picks.dm" #include "code\modules\xenoarcheaology\tools\tools.dm" #include "code\modules\xgm\xgm_gas_mixture.dm" -#include "code\modules\ZAS\_docs.dm" #include "code\modules\ZAS\Airflow.dm" #include "code\modules\ZAS\Atom.dm" #include "code\modules\ZAS\Connection.dm" @@ -3134,33 +4041,35 @@ #include "code\modules\ZAS\Diagnostic.dm" #include "code\modules\ZAS\Fire.dm" #include "code\modules\ZAS\Turf.dm" -#include "code\modules\ZAS\Variable Settings.dm" +#include "code\modules\ZAS\VariableSettings.dm" #include "code\modules\ZAS\Zone.dm" #include "code\procs\announce.dm" -#include "code\procs\AStar.dm" #include "code\procs\dbcore.dm" #include "code\procs\hud.dm" +#include "code\procs\pathfinding.dm" #include "code\procs\radio.dm" #include "code\unit_tests\_defines.dm" #include "code\unit_tests\_includes.dm" #include "code\unit_tests\alt_appearances_test.dm" #include "code\unit_tests\area_tests.dm" #include "code\unit_tests\atmospherics_tests.dm" +#include "code\unit_tests\backgrounds.dm" #include "code\unit_tests\cargo_tests.dm" #include "code\unit_tests\chemistry_tests.dm" #include "code\unit_tests\closets.dm" -#include "code\unit_tests\culture.dm" -#include "code\unit_tests\economics.dm" +#include "code\unit_tests\clothing.dm" +#include "code\unit_tests\codex.dm" +#include "code\unit_tests\decls.dm" +#include "code\unit_tests\del_the_world.dm" #include "code\unit_tests\equipment_tests.dm" #include "code\unit_tests\food_tests.dm" #include "code\unit_tests\foundation_tests.dm" #include "code\unit_tests\fusion_plants.dm" #include "code\unit_tests\graph_tests.dm" #include "code\unit_tests\icon_tests.dm" -#include "code\unit_tests\integrated_circuits.dm" +#include "code\unit_tests\items.dm" #include "code\unit_tests\job_tests.dm" #include "code\unit_tests\json.dm" -#include "code\unit_tests\loadout_tests.dm" #include "code\unit_tests\machine_tests.dm" #include "code\unit_tests\map_tests.dm" #include "code\unit_tests\materials.dm" @@ -3171,30 +4080,30 @@ #include "code\unit_tests\power_tests.dm" #include "code\unit_tests\seed_tests.dm" #include "code\unit_tests\shuttle_tests.dm" -#include "code\unit_tests\submaps.dm" #include "code\unit_tests\subsystem_tests.dm" #include "code\unit_tests\test_obj.dm" #include "code\unit_tests\time_tests.dm" +#include "code\unit_tests\traders.dm" +#include "code\unit_tests\traits.dm" +#include "code\unit_tests\turf_icons.dm" #include "code\unit_tests\unique_tests.dm" #include "code\unit_tests\unit_test.dm" #include "code\unit_tests\uplink_tests.dm" #include "code\unit_tests\view_variables_test.dm" #include "code\unit_tests\zas_tests.dm" +#include "code\unit_tests\zlevel_tests.dm" #include "code\unit_tests\~helpers.dm" #include "interface\interface.dm" #include "interface\skin.dmf" +#include "maps\__map_modpack_compatibility.dm" +#include "maps\__map_names.dm" #include "maps\_map_include.dm" -#include "maps\antag_spawn\antag_spawn_bases.dm" -#include "maps\antag_spawn\deity\deity.dm" -#include "maps\antag_spawn\ert\ert.dm" -#include "maps\antag_spawn\heist\heist.dm" -#include "maps\antag_spawn\mercenary\mercenary.dm" -#include "maps\antag_spawn\ninja\ninja.dm" -#include "maps\antag_spawn\wizard\wizard.dm" -#include "maps\away\away_sites.dm" #include "maps\away_sites_testing\away_sites_testing_define.dm" #include "maps\example\example_define.dm" -#include "maps\random_ruins\exoplanet_ruins\exoplanet_ruins.dm" +#include "maps\exodus\exodus_define.dm" +#include "maps\ministation\ministation_define.dm" +#include "maps\modpack_testing\modpack_testing_define.dm" +#include "maps\planets_testing\planets_testing_define.dm" #include "maps\random_ruins\exoplanet_ruins\crashed_pod\crashed_pod.dm" #include "maps\random_ruins\exoplanet_ruins\datacapsule\datacapsule.dm" #include "maps\random_ruins\exoplanet_ruins\deserted_lab\deserted_lab.dm" @@ -3206,23 +4115,27 @@ #include "maps\random_ruins\exoplanet_ruins\marooned\marooned.dm" #include "maps\random_ruins\exoplanet_ruins\monoliths\monoliths.dm" #include "maps\random_ruins\exoplanet_ruins\oasis\oasis.dm" -#include "maps\random_ruins\exoplanet_ruins\oldpod\oldpod.dm" #include "maps\random_ruins\exoplanet_ruins\radshrine\radshrine.dm" #include "maps\random_ruins\exoplanet_ruins\spider_nest\spider_nest.dm" #include "maps\random_ruins\exoplanet_ruins\tar_anomaly\tar_anomaly.dm" #include "maps\random_ruins\space_ruins\space_ruins.dm" +#include "maps\shaded_hills\shaded_hills_define.dm" #include "maps\tradeship\tradeship.dm" #include "maps\tradeship\tradeship_define.dm" #include "maps\~mapsystem\map_preferences.dm" #include "maps\~mapsystem\map_ranks.dm" +#include "maps\~mapsystem\map_skills.dm" #include "maps\~mapsystem\maps.dm" #include "maps\~mapsystem\maps_announcements.dm" #include "maps\~mapsystem\maps_antagonism.dm" #include "maps\~mapsystem\maps_areas.dm" +#include "maps\~mapsystem\maps_comms.dm" #include "maps\~mapsystem\maps_currency.dm" +#include "maps\~mapsystem\maps_events.dm" #include "maps\~mapsystem\maps_jobs.dm" #include "maps\~mapsystem\maps_unit_testing.dm" #include "maps\~unit_tests\unit_testing.dm" #include "mods\_modpack.dm" +#include "mods\~compatibility\~compatibility.dm" #include "~code\global_init.dm" // END_INCLUDE diff --git a/reference/icons/door_light_palettes.dmi b/reference/icons/door_light_palettes.dmi deleted file mode 100644 index 820e2eb8c145..000000000000 Binary files a/reference/icons/door_light_palettes.dmi and /dev/null differ diff --git a/scripts/backup_saves.sh b/scripts/backup_saves.sh new file mode 100755 index 000000000000..f30117207926 --- /dev/null +++ b/scripts/backup_saves.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# This script requires a git repository initialized +# in data/ with an upstream remote configured. +TIMESTAMP=$( date "+%H_%d_%m_%Y" ) +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +cd $SCRIPT_DIR/../data +git add * +git commit -m "Data backup $TIMESTAMP" +git push upstream master + diff --git a/scripts/dm.sh b/scripts/dm.sh index cb92e2b96329..77260bc003f0 100755 --- a/scripts/dm.sh +++ b/scripts/dm.sh @@ -17,11 +17,11 @@ if [[ $dmepath == "" ]]; then exit 1 fi -if [[ -a $dmepath.mdme ]]; then - rm $dmepath.mdme +if [[ -a $dmepath.m.dme ]]; then + rm $dmepath.m.dme fi -cp $dmepath.dme $dmepath.mdme +cp $dmepath.dme $dmepath.m.dme if [[ $? != 0 ]]; then echo "Failed to make modified dme, aborting." exit 2 @@ -30,12 +30,12 @@ fi for var; do arg=$(echo $var | sed -r 's/^.{2}//') if [[ $var == -D* ]]; then - sed -i '1s!^!#define '$arg'\n!' $dmepath.mdme + sed -i '1s!^!#define '$arg'\n!' $dmepath.m.dme elif [[ $var == -I* ]]; then - sed -i 's!// BEGIN_INCLUDE!// BEGIN_INCLUDE\n#include "'$arg'"!' $dmepath.mdme + sed -i 's!// BEGIN_INCLUDE!// BEGIN_INCLUDE\n#include "'$arg'"!' $dmepath.m.dme elif [[ $var == -M* ]]; then - sed -i '1s/^/#define MAP_OVERRIDE\n/' $dmepath.mdme - sed -i 's!#include "maps\\_map_include.dm"!#include "maps\\'$arg'\\'$arg'.dm"!' $dmepath.mdme + sed -i '1s/^/#define MAP_OVERRIDE\n/' $dmepath.m.dme + sed -i 's!#include "maps\\_map_include.dm"!#include "maps\\'$arg'\\'$arg'.dm"!' $dmepath.m.dme fi done @@ -46,12 +46,12 @@ if [[ $DM == "" ]]; then exit 3 fi -"$DM" $dmepath.mdme | tee build_log.txt +"$DM" $dmepath.m.dme | tee build_log.txt retval=$? -[[ -e $dmepath.mdme.dmb ]] && mv $dmepath.mdme.dmb $dmepath.dmb -[[ -e $dmepath.mdme.rsc ]] && mv $dmepath.mdme.rsc $dmepath.rsc +[[ -e $dmepath.m.dmb ]] && mv $dmepath.m.dmb $dmepath.dmb +[[ -e $dmepath.m.rsc ]] && mv $dmepath.m.rsc $dmepath.rsc -rm $dmepath.mdme +rm $dmepath.m.dme exit $retval diff --git a/scripts/install-spaceman-dmm.sh b/scripts/install-spaceman-dmm.sh index cb876956e2a4..ccb544bcedfa 100755 --- a/scripts/install-spaceman-dmm.sh +++ b/scripts/install-spaceman-dmm.sh @@ -7,8 +7,9 @@ then cp "$HOME/spaceman_dmm/$SPACEMAN_DMM_VERSION/$1" ~/$1 else wget -O ~/$1 "https://github.com/SpaceManiac/SpacemanDMM/releases/download/$SPACEMAN_DMM_VERSION/$1" + mkdir -p $HOME/spaceman_dmm cp ~/$1 $HOME/spaceman_dmm/$SPACEMAN_DMM_VERSION fi chmod +x ~/$1 -~/$1 --version +~/$1 --version \ No newline at end of file diff --git a/scripts/server.sh b/scripts/server.sh index 8388b0dd13e8..bc89d45b7c41 100755 --- a/scripts/server.sh +++ b/scripts/server.sh @@ -12,6 +12,7 @@ cd $SERVERDIR cleanup() { # $1: server pid + cd $SERVERDIR rm server_running [[ $1 != "" ]] && kill -s SIGTERM $1 } @@ -23,8 +24,6 @@ fi touch server_running trap "cleanup" EXIT -exec 5>&1 # duplicate fd 5 to fd 1 (stdout); this allows us to echo the log during compilation, but also capture it for saving to logs in the case of a failure - [[ -e stopserver ]] && rm stopserver while [[ ! -e stopserver ]]; do MAP="$(cat use_map || echo "example")" @@ -46,11 +45,11 @@ while [[ ! -e stopserver ]]; do # Compile echo "Compiling..." - DMoutput="$(./scripts/dm.sh $EXTRA_DM_SH_ARGS -M$MAP $DME.dme | tee /dev/fd/5)" # duplicate output to fd 5 (which is redirected to stdout at the top of this script) + DMoutput="$(./scripts/dm.sh $EXTRA_DM_SH_ARGS -M$MAP $DME.dme | tee /dev/fd/2)" # duplicate output to fd 2 for logging purposes DMret=$? cd - # from $GITDIR if [[ $DMret != 0 ]]; then - d="$(date '+%X %x')" + d="$(date '+%Y-%m-%d_%H-%M-%S')" echo "Compilation failed; saving log to 'data/logs/compile_failure_$d.txt'!" echo $DMoutput >> "data/logs/compile_failure_$d.txt" UPDATE_FAIL=1 # this is probably fatal @@ -62,7 +61,9 @@ while [[ ! -e stopserver ]]; do if [[ "$GITDIR" != "." ]]; then cp "$GITDIR/$DME.dmb" . cp "$GITDIR/$DME.rsc" . - cp -r "$GITDIR/nano" . + cp -r "$GITDIR/nano" . # Necessary for NanoUI + cp -r "$GITDIR/maps" . # Necessary for runtime submap loading + cp -r "$GITDIR/mods" . # Also necessary for runtime submap and NanoUI loading. TODO: a better solution? [[ ! -e btime.so && -e "$GITDIR/btime.so" ]] && cp "$GITDIR/btime.so" . [[ ! -e .git/logs ]] && mkdir -p .git/logs cp "$GITDIR/.git/HEAD" ./.git/HEAD diff --git a/scripts/validateTestingContainsAllMaps.sh b/scripts/validateTestingContainsAllMaps.sh new file mode 100755 index 000000000000..2e9982c0ee30 --- /dev/null +++ b/scripts/validateTestingContainsAllMaps.sh @@ -0,0 +1,17 @@ +#! /bin/bash + +cd "$(dirname "${BASH_SOURCE[0]}")" +cd ../ + +fail=0 + +for k in maps/*; do + map=${k#maps/} + if [[ -e maps/$map/$map.dm ]] && ! grep -P "map_path: \[.*(?<=\[|,)\s*$map\s*(?=\]|,).*\]" .github/workflows/test.yml > /dev/null; then + # $map is a valid map key, but unit testing isn't testing it! + fail=$((fail + 1)) + echo "Map key '$map' is present in the repository, but is not listed in .github/workflows/test.yml!" + fi +done + +exit $fail diff --git a/scripts/validateTravisContainsAllMaps.sh b/scripts/validateTravisContainsAllMaps.sh deleted file mode 100755 index 5e21f79123d1..000000000000 --- a/scripts/validateTravisContainsAllMaps.sh +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/bash - -cd "$(dirname "${BASH_SOURCE[0]}")" -cd ../ - -fail=0 - -for k in maps/*; do - map=${k#maps/} - if [[ -e maps/$map/$map.dm ]] && ! grep "MAP_PATH=$map" .travis.yml > /dev/null; then - # $map is a valid map key, but travis isn't testing it! - fail=$((fail + 1)) - echo "Map key '$map' is present in the repository, but is not listed in .travis.yml!" - fi -done - -exit $fail diff --git a/sound/ambience/firecrackle01.ogg b/sound/ambience/firecrackle01.ogg new file mode 100644 index 000000000000..79598bebb953 Binary files /dev/null and b/sound/ambience/firecrackle01.ogg differ diff --git a/sound/ambience/firecrackle02.ogg b/sound/ambience/firecrackle02.ogg new file mode 100644 index 000000000000..a7c1f7e785b4 Binary files /dev/null and b/sound/ambience/firecrackle02.ogg differ diff --git a/sound/ambience/firecrackle03.ogg b/sound/ambience/firecrackle03.ogg new file mode 100644 index 000000000000..fed794a28c26 Binary files /dev/null and b/sound/ambience/firecrackle03.ogg differ diff --git a/sound/ambience/firecrackle04.ogg b/sound/ambience/firecrackle04.ogg new file mode 100644 index 000000000000..bd28c96d6316 Binary files /dev/null and b/sound/ambience/firecrackle04.ogg differ diff --git a/sound/ambience/firecrackle05.ogg b/sound/ambience/firecrackle05.ogg new file mode 100644 index 000000000000..0c482595f892 Binary files /dev/null and b/sound/ambience/firecrackle05.ogg differ diff --git a/sound/ambience/firecrackle06.ogg b/sound/ambience/firecrackle06.ogg new file mode 100644 index 000000000000..ee0e80daaefe Binary files /dev/null and b/sound/ambience/firecrackle06.ogg differ diff --git a/sound/ambience/marshy.ogg b/sound/ambience/marshy.ogg new file mode 100644 index 000000000000..d481be1e091d Binary files /dev/null and b/sound/ambience/marshy.ogg differ diff --git a/sound/attributions.txt b/sound/attributions.txt new file mode 100644 index 000000000000..931b69d68746 --- /dev/null +++ b/sound/attributions.txt @@ -0,0 +1,18 @@ +// CC BY-NC 3.0 +foley/meat1.ogg - Obtained from https://freesound.org/people/MWLANDI/sounds/85846 +foley/meat2.ogg - Obtained from https://freesound.org/people/MWLANDI/sounds/85845 +foley/metal1.ogg - Obtained from https://freesound.org/people/Debsound/sounds/168822 +// CC BY 3.0 +foley/sweeping1.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +foley/sweeping2.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +foley/sweeping3.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +foley/sweeping4.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +foley/sweeping5.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +foley/sweeping6.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +foley/sweeping7.ogg - Remixed from Sweeping noises.wav by BruceFenn_190335 -- https://freesound.org/s/541329/ -- License: Attribution 3.0 +// CC BY 4.0 +foley/drawer-close.ogg - Obtained from Drawer-Wooden-Empty-Open-04.wav by DWOBoyle -- https://freesound.org/s/152307/ -- License: Attribution 4.0 +foley/drawer-open.ogg - Obtained from Drawer-Wooden-Empty-Open-03.wav by DWOBoyle -- https://freesound.org/s/152308/ -- License: Attribution 4.0 +foley/drawer-oneshot.ogg - Remixed from Drawer-Wooden-Empty-Open-03.wav and Drawer-Wooden-Empty-Open-04.wav by DWOBoyle, see above for further attribution. +// CC 0 +effects/weather/rain_indoors.ogg - Remixed from Heavy Rain inside a Shed by mageh533 -- https://freesound.org/s/752031/ -- License: Creative Commons 0 \ No newline at end of file diff --git a/sound/effects/anvil1.ogg b/sound/effects/anvil1.ogg new file mode 100644 index 000000000000..2c29e2427508 Binary files /dev/null and b/sound/effects/anvil1.ogg differ diff --git a/sound/effects/anvil2.ogg b/sound/effects/anvil2.ogg new file mode 100644 index 000000000000..dc7f43ceaa06 Binary files /dev/null and b/sound/effects/anvil2.ogg differ diff --git a/sound/effects/anvil3.ogg b/sound/effects/anvil3.ogg new file mode 100644 index 000000000000..ad3747c0f32f Binary files /dev/null and b/sound/effects/anvil3.ogg differ diff --git a/sound/effects/anvil4.ogg b/sound/effects/anvil4.ogg new file mode 100644 index 000000000000..88da5eb8bb66 Binary files /dev/null and b/sound/effects/anvil4.ogg differ diff --git a/sound/effects/anvil5.ogg b/sound/effects/anvil5.ogg new file mode 100644 index 000000000000..80533e38aebe Binary files /dev/null and b/sound/effects/anvil5.ogg differ diff --git a/sound/effects/balloon-pop.ogg b/sound/effects/balloon-pop.ogg new file mode 100644 index 000000000000..0efd3beba90f Binary files /dev/null and b/sound/effects/balloon-pop.ogg differ diff --git a/sound/effects/bell_far.ogg b/sound/effects/bell_far.ogg new file mode 100644 index 000000000000..2d58ad369b01 Binary files /dev/null and b/sound/effects/bell_far.ogg differ diff --git a/sound/effects/bell_near.ogg b/sound/effects/bell_near.ogg new file mode 100644 index 000000000000..c0277161f783 Binary files /dev/null and b/sound/effects/bell_near.ogg differ diff --git a/sound/effects/boiling-water.ogg b/sound/effects/boiling-water.ogg new file mode 100644 index 000000000000..c026945a819b Binary files /dev/null and b/sound/effects/boiling-water.ogg differ diff --git a/sound/effects/break_ceramic.ogg b/sound/effects/break_ceramic.ogg new file mode 100644 index 000000000000..7494e6c7e56a Binary files /dev/null and b/sound/effects/break_ceramic.ogg differ diff --git a/sound/effects/break_stone.ogg b/sound/effects/break_stone.ogg new file mode 100644 index 000000000000..711fd50d482c Binary files /dev/null and b/sound/effects/break_stone.ogg differ diff --git a/sound/effects/bubbles3.ogg b/sound/effects/bubbles3.ogg new file mode 100644 index 000000000000..108917ab3df9 Binary files /dev/null and b/sound/effects/bubbles3.ogg differ diff --git a/sound/effects/champagne_open.ogg b/sound/effects/champagne_open.ogg new file mode 100644 index 000000000000..50610cd5cb0f Binary files /dev/null and b/sound/effects/champagne_open.ogg differ diff --git a/sound/effects/champagne_psh.ogg b/sound/effects/champagne_psh.ogg new file mode 100644 index 000000000000..baae62e1716e Binary files /dev/null and b/sound/effects/champagne_psh.ogg differ diff --git a/sound/effects/ding2.ogg b/sound/effects/ding2.ogg deleted file mode 100644 index b8bd61b2174e..000000000000 Binary files a/sound/effects/ding2.ogg and /dev/null differ diff --git a/sound/effects/fingersnap.ogg b/sound/effects/fingersnap.ogg new file mode 100644 index 000000000000..f7046403513d Binary files /dev/null and b/sound/effects/fingersnap.ogg differ diff --git a/sound/effects/footstep/mud1.ogg b/sound/effects/footstep/mud1.ogg new file mode 100644 index 000000000000..f37e774def97 Binary files /dev/null and b/sound/effects/footstep/mud1.ogg differ diff --git a/sound/effects/footstep/mud2.ogg b/sound/effects/footstep/mud2.ogg new file mode 100644 index 000000000000..a8f4a51c3e91 Binary files /dev/null and b/sound/effects/footstep/mud2.ogg differ diff --git a/sound/effects/footstep/mud3.ogg b/sound/effects/footstep/mud3.ogg new file mode 100644 index 000000000000..601f98036f36 Binary files /dev/null and b/sound/effects/footstep/mud3.ogg differ diff --git a/sound/effects/footstep/mud4.ogg b/sound/effects/footstep/mud4.ogg new file mode 100644 index 000000000000..2eae9cbe4123 Binary files /dev/null and b/sound/effects/footstep/mud4.ogg differ diff --git a/sound/effects/hit_bush.ogg b/sound/effects/hit_bush.ogg new file mode 100644 index 000000000000..3bbc72d345a3 Binary files /dev/null and b/sound/effects/hit_bush.ogg differ diff --git a/sound/effects/hit_wood.ogg b/sound/effects/hit_wood.ogg new file mode 100644 index 000000000000..c4366817c5ee Binary files /dev/null and b/sound/effects/hit_wood.ogg differ diff --git a/sound/effects/plants/brush_leaves.ogg b/sound/effects/plants/brush_leaves.ogg new file mode 100644 index 000000000000..f01ce2952f71 Binary files /dev/null and b/sound/effects/plants/brush_leaves.ogg differ diff --git a/sound/effects/plants/tree_fall.ogg b/sound/effects/plants/tree_fall.ogg new file mode 100644 index 000000000000..3e100be4a08c Binary files /dev/null and b/sound/effects/plants/tree_fall.ogg differ diff --git a/sound/effects/rockcrumble.ogg b/sound/effects/rockcrumble.ogg new file mode 100644 index 000000000000..475d2c7ba663 Binary files /dev/null and b/sound/effects/rockcrumble.ogg differ diff --git a/sound/effects/spider_loop.ogg b/sound/effects/spider_loop.ogg new file mode 100644 index 000000000000..3a98df83e2a4 Binary files /dev/null and b/sound/effects/spider_loop.ogg differ diff --git a/sound/effects/synth_bell.ogg b/sound/effects/synth_bell.ogg new file mode 100644 index 000000000000..120221a068c3 Binary files /dev/null and b/sound/effects/synth_bell.ogg differ diff --git a/sound/effects/throw.ogg b/sound/effects/throw.ogg new file mode 100644 index 000000000000..a45b27905bf7 Binary files /dev/null and b/sound/effects/throw.ogg differ diff --git a/sound/effects/thunder/thunder1.ogg b/sound/effects/thunder/thunder1.ogg new file mode 100644 index 000000000000..7ec34e88e86b Binary files /dev/null and b/sound/effects/thunder/thunder1.ogg differ diff --git a/sound/effects/thunder/thunder10.ogg b/sound/effects/thunder/thunder10.ogg new file mode 100644 index 000000000000..43aefb098f06 Binary files /dev/null and b/sound/effects/thunder/thunder10.ogg differ diff --git a/sound/effects/thunder/thunder2.ogg b/sound/effects/thunder/thunder2.ogg new file mode 100644 index 000000000000..bc2f581dda55 Binary files /dev/null and b/sound/effects/thunder/thunder2.ogg differ diff --git a/sound/effects/thunder/thunder3.ogg b/sound/effects/thunder/thunder3.ogg new file mode 100644 index 000000000000..0df287aa783a Binary files /dev/null and b/sound/effects/thunder/thunder3.ogg differ diff --git a/sound/effects/thunder/thunder4.ogg b/sound/effects/thunder/thunder4.ogg new file mode 100644 index 000000000000..6c671b801055 Binary files /dev/null and b/sound/effects/thunder/thunder4.ogg differ diff --git a/sound/effects/thunder/thunder5.ogg b/sound/effects/thunder/thunder5.ogg new file mode 100644 index 000000000000..3d5187a71644 Binary files /dev/null and b/sound/effects/thunder/thunder5.ogg differ diff --git a/sound/effects/thunder/thunder6.ogg b/sound/effects/thunder/thunder6.ogg new file mode 100644 index 000000000000..65aef886ff2e Binary files /dev/null and b/sound/effects/thunder/thunder6.ogg differ diff --git a/sound/effects/thunder/thunder7.ogg b/sound/effects/thunder/thunder7.ogg new file mode 100644 index 000000000000..b72848a2b6e6 Binary files /dev/null and b/sound/effects/thunder/thunder7.ogg differ diff --git a/sound/effects/thunder/thunder8.ogg b/sound/effects/thunder/thunder8.ogg new file mode 100644 index 000000000000..a25fe21e3283 Binary files /dev/null and b/sound/effects/thunder/thunder8.ogg differ diff --git a/sound/effects/thunder/thunder9.ogg b/sound/effects/thunder/thunder9.ogg new file mode 100644 index 000000000000..9ebc1045bff7 Binary files /dev/null and b/sound/effects/thunder/thunder9.ogg differ diff --git a/sound/effects/watersplash.ogg b/sound/effects/watersplash.ogg new file mode 100644 index 000000000000..ed2eccbff63c Binary files /dev/null and b/sound/effects/watersplash.ogg differ diff --git a/sound/effects/weather/hail_indoors.ogg b/sound/effects/weather/hail_indoors.ogg new file mode 100644 index 000000000000..e0158fde3a2c Binary files /dev/null and b/sound/effects/weather/hail_indoors.ogg differ diff --git a/sound/effects/weather/rain.ogg b/sound/effects/weather/rain.ogg new file mode 100644 index 000000000000..f65ba956f847 Binary files /dev/null and b/sound/effects/weather/rain.ogg differ diff --git a/sound/effects/weather/rain_heavy.ogg b/sound/effects/weather/rain_heavy.ogg new file mode 100644 index 000000000000..1a51c611c4f2 Binary files /dev/null and b/sound/effects/weather/rain_heavy.ogg differ diff --git a/sound/effects/weather/rain_indoors.ogg b/sound/effects/weather/rain_indoors.ogg new file mode 100644 index 000000000000..4958770630d9 Binary files /dev/null and b/sound/effects/weather/rain_indoors.ogg differ diff --git a/sound/effects/weather/snow.ogg b/sound/effects/weather/snow.ogg new file mode 100644 index 000000000000..641d31596a65 Binary files /dev/null and b/sound/effects/weather/snow.ogg differ diff --git a/sound/effects/weather/thunder.ogg b/sound/effects/weather/thunder.ogg new file mode 100644 index 000000000000..2719fcc383ea Binary files /dev/null and b/sound/effects/weather/thunder.ogg differ diff --git a/sound/foley/bardrop1.ogg b/sound/foley/bardrop1.ogg new file mode 100644 index 000000000000..da3605abe011 Binary files /dev/null and b/sound/foley/bardrop1.ogg differ diff --git a/sound/foley/bottledrop1.ogg b/sound/foley/bottledrop1.ogg new file mode 100644 index 000000000000..d22c097cd0f3 Binary files /dev/null and b/sound/foley/bottledrop1.ogg differ diff --git a/sound/foley/bottlepickup1.ogg b/sound/foley/bottlepickup1.ogg new file mode 100644 index 000000000000..da4eb761267c Binary files /dev/null and b/sound/foley/bottlepickup1.ogg differ diff --git a/sound/foley/clank1.ogg b/sound/foley/clank1.ogg new file mode 100644 index 000000000000..477b884d368d Binary files /dev/null and b/sound/foley/clank1.ogg differ diff --git a/sound/foley/donk1.ogg b/sound/foley/donk1.ogg new file mode 100644 index 000000000000..6facf4636be7 Binary files /dev/null and b/sound/foley/donk1.ogg differ diff --git a/sound/foley/drawer-close.ogg b/sound/foley/drawer-close.ogg new file mode 100644 index 000000000000..1ea004c9cf74 Binary files /dev/null and b/sound/foley/drawer-close.ogg differ diff --git a/sound/foley/drawer-oneshot.ogg b/sound/foley/drawer-oneshot.ogg new file mode 100644 index 000000000000..b43ccc901e1c Binary files /dev/null and b/sound/foley/drawer-oneshot.ogg differ diff --git a/sound/foley/drawer-open.ogg b/sound/foley/drawer-open.ogg new file mode 100644 index 000000000000..1c29e3f315bc Binary files /dev/null and b/sound/foley/drawer-open.ogg differ diff --git a/sound/foley/drop1.ogg b/sound/foley/drop1.ogg new file mode 100644 index 000000000000..84853a33a434 Binary files /dev/null and b/sound/foley/drop1.ogg differ diff --git a/sound/foley/glass.ogg b/sound/foley/glass.ogg new file mode 100644 index 000000000000..d6b03e1720db Binary files /dev/null and b/sound/foley/glass.ogg differ diff --git a/sound/foley/knife1.ogg b/sound/foley/knife1.ogg new file mode 100644 index 000000000000..cff86abb4606 Binary files /dev/null and b/sound/foley/knife1.ogg differ diff --git a/sound/foley/knife2.ogg b/sound/foley/knife2.ogg new file mode 100644 index 000000000000..92fa1c53448d Binary files /dev/null and b/sound/foley/knife2.ogg differ diff --git a/sound/foley/knifedrop1.ogg b/sound/foley/knifedrop1.ogg new file mode 100644 index 000000000000..2b2c0309b1e5 Binary files /dev/null and b/sound/foley/knifedrop1.ogg differ diff --git a/sound/foley/knifedrop2.ogg b/sound/foley/knifedrop2.ogg new file mode 100644 index 000000000000..4dbe2a573e3a Binary files /dev/null and b/sound/foley/knifedrop2.ogg differ diff --git a/sound/foley/knifedrop3.ogg b/sound/foley/knifedrop3.ogg new file mode 100644 index 000000000000..9cec001c0c6c Binary files /dev/null and b/sound/foley/knifedrop3.ogg differ diff --git a/sound/foley/meat1.ogg b/sound/foley/meat1.ogg new file mode 100644 index 000000000000..d6ba135015a0 Binary files /dev/null and b/sound/foley/meat1.ogg differ diff --git a/sound/foley/meat2.ogg b/sound/foley/meat2.ogg new file mode 100644 index 000000000000..f7ccf948352a Binary files /dev/null and b/sound/foley/meat2.ogg differ diff --git a/sound/foley/metal1.ogg b/sound/foley/metal1.ogg new file mode 100644 index 000000000000..8c3a531c3368 Binary files /dev/null and b/sound/foley/metal1.ogg differ diff --git a/sound/foley/paperpickup1.ogg b/sound/foley/paperpickup1.ogg new file mode 100644 index 000000000000..7b4770d9c25d Binary files /dev/null and b/sound/foley/paperpickup1.ogg differ diff --git a/sound/foley/paperpickup2.ogg b/sound/foley/paperpickup2.ogg new file mode 100644 index 000000000000..eaa5db873207 Binary files /dev/null and b/sound/foley/paperpickup2.ogg differ diff --git a/sound/foley/pebblesdrop1.ogg b/sound/foley/pebblesdrop1.ogg new file mode 100644 index 000000000000..b9ded623da87 Binary files /dev/null and b/sound/foley/pebblesdrop1.ogg differ diff --git a/sound/foley/pebblespickup1.ogg b/sound/foley/pebblespickup1.ogg new file mode 100644 index 000000000000..5ba277aa02c6 Binary files /dev/null and b/sound/foley/pebblespickup1.ogg differ diff --git a/sound/foley/pickup1.ogg b/sound/foley/pickup1.ogg new file mode 100644 index 000000000000..0b7b072a2ae1 Binary files /dev/null and b/sound/foley/pickup1.ogg differ diff --git a/sound/foley/pickup2.ogg b/sound/foley/pickup2.ogg new file mode 100644 index 000000000000..2e335cfa464b Binary files /dev/null and b/sound/foley/pickup2.ogg differ diff --git a/sound/foley/rockscrape.ogg b/sound/foley/rockscrape.ogg new file mode 100644 index 000000000000..0a626d6c64cd Binary files /dev/null and b/sound/foley/rockscrape.ogg differ diff --git a/sound/foley/scrape1.ogg b/sound/foley/scrape1.ogg new file mode 100644 index 000000000000..9e36a98037d7 Binary files /dev/null and b/sound/foley/scrape1.ogg differ diff --git a/sound/foley/singletooldrop1.ogg b/sound/foley/singletooldrop1.ogg new file mode 100644 index 000000000000..e66fab567bdc Binary files /dev/null and b/sound/foley/singletooldrop1.ogg differ diff --git a/sound/foley/singletooldrop2.ogg b/sound/foley/singletooldrop2.ogg new file mode 100644 index 000000000000..b472454dcf55 Binary files /dev/null and b/sound/foley/singletooldrop2.ogg differ diff --git a/sound/foley/singletooldrop3.ogg b/sound/foley/singletooldrop3.ogg new file mode 100644 index 000000000000..3d4b63e1ee5a Binary files /dev/null and b/sound/foley/singletooldrop3.ogg differ diff --git a/sound/foley/sticksdrop1.ogg b/sound/foley/sticksdrop1.ogg new file mode 100644 index 000000000000..0945501c2a2f Binary files /dev/null and b/sound/foley/sticksdrop1.ogg differ diff --git a/sound/foley/stickspickup1.ogg b/sound/foley/stickspickup1.ogg new file mode 100644 index 000000000000..6d4dc292f0ff Binary files /dev/null and b/sound/foley/stickspickup1.ogg differ diff --git a/sound/foley/sweeping1.ogg b/sound/foley/sweeping1.ogg new file mode 100644 index 000000000000..460073b7b560 Binary files /dev/null and b/sound/foley/sweeping1.ogg differ diff --git a/sound/foley/sweeping2.ogg b/sound/foley/sweeping2.ogg new file mode 100644 index 000000000000..44b0f0dcbc13 Binary files /dev/null and b/sound/foley/sweeping2.ogg differ diff --git a/sound/foley/sweeping3.ogg b/sound/foley/sweeping3.ogg new file mode 100644 index 000000000000..d4507e196604 Binary files /dev/null and b/sound/foley/sweeping3.ogg differ diff --git a/sound/foley/sweeping4.ogg b/sound/foley/sweeping4.ogg new file mode 100644 index 000000000000..d1961751f4ef Binary files /dev/null and b/sound/foley/sweeping4.ogg differ diff --git a/sound/foley/sweeping5.ogg b/sound/foley/sweeping5.ogg new file mode 100644 index 000000000000..c2ffe74fdf6d Binary files /dev/null and b/sound/foley/sweeping5.ogg differ diff --git a/sound/foley/sweeping6.ogg b/sound/foley/sweeping6.ogg new file mode 100644 index 000000000000..ace675c77027 Binary files /dev/null and b/sound/foley/sweeping6.ogg differ diff --git a/sound/foley/sweeping7.ogg b/sound/foley/sweeping7.ogg new file mode 100644 index 000000000000..b64bbed3efe9 Binary files /dev/null and b/sound/foley/sweeping7.ogg differ diff --git a/sound/foley/tooldrop1.ogg b/sound/foley/tooldrop1.ogg new file mode 100644 index 000000000000..837980642094 Binary files /dev/null and b/sound/foley/tooldrop1.ogg differ diff --git a/sound/foley/tooldrop2.ogg b/sound/foley/tooldrop2.ogg new file mode 100644 index 000000000000..e02090b2da12 Binary files /dev/null and b/sound/foley/tooldrop2.ogg differ diff --git a/sound/foley/tooldrop3.ogg b/sound/foley/tooldrop3.ogg new file mode 100644 index 000000000000..3afd33b05b47 Binary files /dev/null and b/sound/foley/tooldrop3.ogg differ diff --git a/sound/foley/tooldrop5.ogg b/sound/foley/tooldrop5.ogg new file mode 100644 index 000000000000..80d51f004278 Binary files /dev/null and b/sound/foley/tooldrop5.ogg differ diff --git a/sound/foley/wooddrop1.ogg b/sound/foley/wooddrop1.ogg new file mode 100644 index 000000000000..e58280b332d0 Binary files /dev/null and b/sound/foley/wooddrop1.ogg differ diff --git a/sound/foley/wooden_drop.ogg b/sound/foley/wooden_drop.ogg new file mode 100644 index 000000000000..dd6c4e7c530c Binary files /dev/null and b/sound/foley/wooden_drop.ogg differ diff --git a/sound/foley/woodpickup1.ogg b/sound/foley/woodpickup1.ogg new file mode 100644 index 000000000000..5b4167bb3a2b Binary files /dev/null and b/sound/foley/woodpickup1.ogg differ diff --git a/sound/items/airwrench.ogg b/sound/items/airwrench.ogg new file mode 100644 index 000000000000..98fb55e5f86e Binary files /dev/null and b/sound/items/airwrench.ogg differ diff --git a/sound/items/axe_wood.ogg b/sound/items/axe_wood.ogg new file mode 100644 index 000000000000..acf9661be9b1 Binary files /dev/null and b/sound/items/axe_wood.ogg differ diff --git a/sound/items/change_drill.ogg b/sound/items/change_drill.ogg new file mode 100644 index 000000000000..406027a5955a Binary files /dev/null and b/sound/items/change_drill.ogg differ diff --git a/sound/items/change_jaws.ogg b/sound/items/change_jaws.ogg new file mode 100644 index 000000000000..b6a41eca8063 Binary files /dev/null and b/sound/items/change_jaws.ogg differ diff --git a/sound/items/containers/briefcase_lock.ogg b/sound/items/containers/briefcase_lock.ogg new file mode 100644 index 000000000000..312363fa2e18 Binary files /dev/null and b/sound/items/containers/briefcase_lock.ogg differ diff --git a/sound/items/containers/briefcase_unlock.ogg b/sound/items/containers/briefcase_unlock.ogg new file mode 100644 index 000000000000..0f4dea05df8e Binary files /dev/null and b/sound/items/containers/briefcase_unlock.ogg differ diff --git a/sound/items/drop/device.ogg b/sound/items/drop/device.ogg new file mode 100644 index 000000000000..8382db94b8af Binary files /dev/null and b/sound/items/drop/device.ogg differ diff --git a/sound/items/loom1.ogg b/sound/items/loom1.ogg new file mode 100644 index 000000000000..38c947dcee26 Binary files /dev/null and b/sound/items/loom1.ogg differ diff --git a/sound/items/loom2.ogg b/sound/items/loom2.ogg new file mode 100644 index 000000000000..0b7ecd5c177b Binary files /dev/null and b/sound/items/loom2.ogg differ diff --git a/sound/items/loom3.ogg b/sound/items/loom3.ogg new file mode 100644 index 000000000000..ed35102ff557 Binary files /dev/null and b/sound/items/loom3.ogg differ diff --git a/sound/items/loomstart.ogg b/sound/items/loomstart.ogg new file mode 100644 index 000000000000..b728a8829867 Binary files /dev/null and b/sound/items/loomstart.ogg differ diff --git a/sound/items/loomstop.ogg b/sound/items/loomstop.ogg new file mode 100644 index 000000000000..cbc6837cb3c4 Binary files /dev/null and b/sound/items/loomstop.ogg differ diff --git a/sound/items/magclomp.ogg b/sound/items/magclomp.ogg new file mode 100644 index 000000000000..8c257f996983 Binary files /dev/null and b/sound/items/magclomp.ogg differ diff --git a/sound/items/pickup/device.ogg b/sound/items/pickup/device.ogg new file mode 100644 index 000000000000..ca2c4f1ab128 Binary files /dev/null and b/sound/items/pickup/device.ogg differ diff --git a/sound/items/shovel_dirt.ogg b/sound/items/shovel_dirt.ogg new file mode 100644 index 000000000000..50c3cc8b7916 Binary files /dev/null and b/sound/items/shovel_dirt.ogg differ diff --git a/sound/items/spinningwheel1.ogg b/sound/items/spinningwheel1.ogg new file mode 100644 index 000000000000..7fc737a6646a Binary files /dev/null and b/sound/items/spinningwheel1.ogg differ diff --git a/sound/items/spinningwheel2.ogg b/sound/items/spinningwheel2.ogg new file mode 100644 index 000000000000..101e6fa5d2dd Binary files /dev/null and b/sound/items/spinningwheel2.ogg differ diff --git a/sound/items/spinningwheel3.ogg b/sound/items/spinningwheel3.ogg new file mode 100644 index 000000000000..8c185a73d5b3 Binary files /dev/null and b/sound/items/spinningwheel3.ogg differ diff --git a/sound/items/spinningwheelstart.ogg b/sound/items/spinningwheelstart.ogg new file mode 100644 index 000000000000..0270ac655cf3 Binary files /dev/null and b/sound/items/spinningwheelstart.ogg differ diff --git a/sound/items/spinningwheelstop.ogg b/sound/items/spinningwheelstop.ogg new file mode 100644 index 000000000000..f039a7fb7e13 Binary files /dev/null and b/sound/items/spinningwheelstop.ogg differ diff --git a/sound/items/welderactivate.ogg b/sound/items/welderactivate.ogg new file mode 100644 index 000000000000..e01102a9ed53 Binary files /dev/null and b/sound/items/welderactivate.ogg differ diff --git a/sound/items/welderdeactivate.ogg b/sound/items/welderdeactivate.ogg new file mode 100644 index 000000000000..22ac4f445cb8 Binary files /dev/null and b/sound/items/welderdeactivate.ogg differ diff --git a/sound/machines/airalarm.ogg b/sound/machines/airalarm.ogg index cc543b444ed8..fd388819a052 100644 Binary files a/sound/machines/airalarm.ogg and b/sound/machines/airalarm.ogg differ diff --git a/sound/machines/fax_send.ogg b/sound/machines/fax_send.ogg new file mode 100644 index 000000000000..b8ec42330488 Binary files /dev/null and b/sound/machines/fax_send.ogg differ diff --git a/sound/machines/holo_click.ogg b/sound/machines/holo_click.ogg new file mode 100644 index 000000000000..08af587c86f3 Binary files /dev/null and b/sound/machines/holo_click.ogg differ diff --git a/sound/machines/hyperspace_begin.ogg b/sound/machines/hyperspace_begin.ogg new file mode 100644 index 000000000000..225e2d988209 Binary files /dev/null and b/sound/machines/hyperspace_begin.ogg differ diff --git a/sound/machines/hyperspace_end.ogg b/sound/machines/hyperspace_end.ogg new file mode 100644 index 000000000000..64fb5214a962 Binary files /dev/null and b/sound/machines/hyperspace_end.ogg differ diff --git a/sound/machines/kitchen/grill/grill-mid1.ogg b/sound/machines/kitchen/grill/grill-mid1.ogg new file mode 100644 index 000000000000..0733899a7630 Binary files /dev/null and b/sound/machines/kitchen/grill/grill-mid1.ogg differ diff --git a/sound/machines/kitchen/grill/grill-start.ogg b/sound/machines/kitchen/grill/grill-start.ogg new file mode 100644 index 000000000000..2c99396cb71a Binary files /dev/null and b/sound/machines/kitchen/grill/grill-start.ogg differ diff --git a/sound/machines/kitchen/grill/grill-stop.ogg b/sound/machines/kitchen/grill/grill-stop.ogg new file mode 100644 index 000000000000..2ec3f92a1c05 Binary files /dev/null and b/sound/machines/kitchen/grill/grill-stop.ogg differ diff --git a/sound/machines/mechanical_switch.ogg b/sound/machines/mechanical_switch.ogg new file mode 100644 index 000000000000..3693ab023bae Binary files /dev/null and b/sound/machines/mechanical_switch.ogg differ diff --git a/sound/machines/microwave/microwave-end.ogg b/sound/machines/microwave/microwave-end.ogg new file mode 100644 index 000000000000..1c13d87e175f Binary files /dev/null and b/sound/machines/microwave/microwave-end.ogg differ diff --git a/sound/machines/microwave/microwave-mid1.ogg b/sound/machines/microwave/microwave-mid1.ogg new file mode 100644 index 000000000000..60a0cc8ec5af Binary files /dev/null and b/sound/machines/microwave/microwave-mid1.ogg differ diff --git a/sound/machines/microwave/microwave-mid2.ogg b/sound/machines/microwave/microwave-mid2.ogg new file mode 100644 index 000000000000..3b3dd32c282f Binary files /dev/null and b/sound/machines/microwave/microwave-mid2.ogg differ diff --git a/sound/machines/microwave/microwave-start.ogg b/sound/machines/microwave/microwave-start.ogg new file mode 100644 index 000000000000..5e59c78e8a9e Binary files /dev/null and b/sound/machines/microwave/microwave-start.ogg differ diff --git a/sound/machines/phone/key-0.ogg b/sound/machines/phone/key-0.ogg new file mode 100644 index 000000000000..1adc3781fe9d Binary files /dev/null and b/sound/machines/phone/key-0.ogg differ diff --git a/sound/machines/phone/key-1.ogg b/sound/machines/phone/key-1.ogg new file mode 100644 index 000000000000..e9b0c50a1865 Binary files /dev/null and b/sound/machines/phone/key-1.ogg differ diff --git a/sound/machines/phone/key-2.ogg b/sound/machines/phone/key-2.ogg new file mode 100644 index 000000000000..e2e3fa8fa51b Binary files /dev/null and b/sound/machines/phone/key-2.ogg differ diff --git a/sound/machines/phone/key-3.ogg b/sound/machines/phone/key-3.ogg new file mode 100644 index 000000000000..938e00120589 Binary files /dev/null and b/sound/machines/phone/key-3.ogg differ diff --git a/sound/machines/phone/key-4.ogg b/sound/machines/phone/key-4.ogg new file mode 100644 index 000000000000..a3ab14210eab Binary files /dev/null and b/sound/machines/phone/key-4.ogg differ diff --git a/sound/machines/phone/key-5.ogg b/sound/machines/phone/key-5.ogg new file mode 100644 index 000000000000..6348627bdfdd Binary files /dev/null and b/sound/machines/phone/key-5.ogg differ diff --git a/sound/machines/phone/key-6.ogg b/sound/machines/phone/key-6.ogg new file mode 100644 index 000000000000..26e86a5fe8fa Binary files /dev/null and b/sound/machines/phone/key-6.ogg differ diff --git a/sound/machines/phone/key-7.ogg b/sound/machines/phone/key-7.ogg new file mode 100644 index 000000000000..d9954a1f86be Binary files /dev/null and b/sound/machines/phone/key-7.ogg differ diff --git a/sound/machines/phone/key-8.ogg b/sound/machines/phone/key-8.ogg new file mode 100644 index 000000000000..989ed25e7ffb Binary files /dev/null and b/sound/machines/phone/key-8.ogg differ diff --git a/sound/machines/phone/key-9.ogg b/sound/machines/phone/key-9.ogg new file mode 100644 index 000000000000..41ce12f1d380 Binary files /dev/null and b/sound/machines/phone/key-9.ogg differ diff --git a/sound/machines/phone/key-square.ogg b/sound/machines/phone/key-square.ogg new file mode 100644 index 000000000000..cdac4b3995ea Binary files /dev/null and b/sound/machines/phone/key-square.ogg differ diff --git a/sound/machines/phone/key-star.ogg b/sound/machines/phone/key-star.ogg new file mode 100644 index 000000000000..60c96f048b2b Binary files /dev/null and b/sound/machines/phone/key-star.ogg differ diff --git a/sound/machines/podclose.ogg b/sound/machines/podclose.ogg new file mode 100644 index 000000000000..388596d44e0c Binary files /dev/null and b/sound/machines/podclose.ogg differ diff --git a/sound/machines/podopen.ogg b/sound/machines/podopen.ogg new file mode 100644 index 000000000000..a65101862857 Binary files /dev/null and b/sound/machines/podopen.ogg differ diff --git a/sound/machines/sm/accent/delam/1.ogg b/sound/machines/sm/accent/delam/1.ogg new file mode 100644 index 000000000000..75c79f89ab2a Binary files /dev/null and b/sound/machines/sm/accent/delam/1.ogg differ diff --git a/sound/machines/sm/accent/delam/2.ogg b/sound/machines/sm/accent/delam/2.ogg new file mode 100644 index 000000000000..5b480daa2e1c Binary files /dev/null and b/sound/machines/sm/accent/delam/2.ogg differ diff --git a/sound/machines/sm/accent/delam/3.ogg b/sound/machines/sm/accent/delam/3.ogg new file mode 100644 index 000000000000..5b57cc270700 Binary files /dev/null and b/sound/machines/sm/accent/delam/3.ogg differ diff --git a/sound/machines/sm/accent/delam/4.ogg b/sound/machines/sm/accent/delam/4.ogg new file mode 100644 index 000000000000..aa4f4da07142 Binary files /dev/null and b/sound/machines/sm/accent/delam/4.ogg differ diff --git a/sound/machines/sm/accent/delam/5.ogg b/sound/machines/sm/accent/delam/5.ogg new file mode 100644 index 000000000000..be438f6f151e Binary files /dev/null and b/sound/machines/sm/accent/delam/5.ogg differ diff --git a/sound/machines/sm/accent/normal/1.ogg b/sound/machines/sm/accent/normal/1.ogg new file mode 100644 index 000000000000..e92beed7fe69 Binary files /dev/null and b/sound/machines/sm/accent/normal/1.ogg differ diff --git a/sound/machines/sm/accent/normal/2.ogg b/sound/machines/sm/accent/normal/2.ogg new file mode 100644 index 000000000000..05e3c9ff17fc Binary files /dev/null and b/sound/machines/sm/accent/normal/2.ogg differ diff --git a/sound/machines/sm/accent/normal/3.ogg b/sound/machines/sm/accent/normal/3.ogg new file mode 100644 index 000000000000..38de5571a4aa Binary files /dev/null and b/sound/machines/sm/accent/normal/3.ogg differ diff --git a/sound/machines/sm/accent/normal/4.ogg b/sound/machines/sm/accent/normal/4.ogg new file mode 100644 index 000000000000..2e71e976e86c Binary files /dev/null and b/sound/machines/sm/accent/normal/4.ogg differ diff --git a/sound/machines/sm/accent/normal/5.ogg b/sound/machines/sm/accent/normal/5.ogg new file mode 100644 index 000000000000..04852e10f2b2 Binary files /dev/null and b/sound/machines/sm/accent/normal/5.ogg differ diff --git a/sound/machines/sm/loops/calm.ogg b/sound/machines/sm/loops/calm.ogg new file mode 100644 index 000000000000..cee14fcd13d6 Binary files /dev/null and b/sound/machines/sm/loops/calm.ogg differ diff --git a/sound/machines/sm/loops/delamming.ogg b/sound/machines/sm/loops/delamming.ogg new file mode 100644 index 000000000000..7d79f0e3c4ac Binary files /dev/null and b/sound/machines/sm/loops/delamming.ogg differ diff --git a/sound/machines/vehicle/engine_end.ogg b/sound/machines/vehicle/engine_end.ogg new file mode 100644 index 000000000000..7f3c179ad802 Binary files /dev/null and b/sound/machines/vehicle/engine_end.ogg differ diff --git a/sound/machines/vehicle/engine_mid.ogg b/sound/machines/vehicle/engine_mid.ogg new file mode 100644 index 000000000000..cf7173c8e81d Binary files /dev/null and b/sound/machines/vehicle/engine_mid.ogg differ diff --git a/sound/machines/vehicle/engine_start.ogg b/sound/machines/vehicle/engine_start.ogg new file mode 100644 index 000000000000..e4b5ac744b9d Binary files /dev/null and b/sound/machines/vehicle/engine_start.ogg differ diff --git a/sound/machines/vehicle/ignition.ogg b/sound/machines/vehicle/ignition.ogg new file mode 100644 index 000000000000..cf0718c6e3b3 Binary files /dev/null and b/sound/machines/vehicle/ignition.ogg differ diff --git a/sound/mecha/mech-shutdown.ogg b/sound/mecha/mech-shutdown.ogg new file mode 100644 index 000000000000..9733bb26df54 Binary files /dev/null and b/sound/mecha/mech-shutdown.ogg differ diff --git a/sound/misc/ftlsiren.ogg b/sound/misc/ftlsiren.ogg new file mode 100644 index 000000000000..7d2ede8af3d9 Binary files /dev/null and b/sound/misc/ftlsiren.ogg differ diff --git a/sound/music/Dhaka.ogg b/sound/music/Dhaka.ogg new file mode 100644 index 000000000000..bdcf6de2825c Binary files /dev/null and b/sound/music/Dhaka.ogg differ diff --git a/sound/music/Miris-Magic-Dance.ogg b/sound/music/Miris-Magic-Dance.ogg new file mode 100644 index 000000000000..4c95168779dc Binary files /dev/null and b/sound/music/Miris-Magic-Dance.ogg differ diff --git a/sound/music/Suonatore-di-Liuto.ogg b/sound/music/Suonatore-di-Liuto.ogg new file mode 100644 index 000000000000..c8d5a8d4e382 Binary files /dev/null and b/sound/music/Suonatore-di-Liuto.ogg differ diff --git a/sound/music/THUNDERDOME.ogg b/sound/music/THUNDERDOME.ogg index 6b73365f2e55..ea1be6b74a3d 100644 Binary files a/sound/music/THUNDERDOME.ogg and b/sound/music/THUNDERDOME.ogg differ diff --git a/sound/music/Teller-of-the-Tales.ogg b/sound/music/Teller-of-the-Tales.ogg new file mode 100644 index 000000000000..4bb2bf772b52 Binary files /dev/null and b/sound/music/Teller-of-the-Tales.ogg differ diff --git a/sound/music/Torch.ogg b/sound/music/Torch.ogg deleted file mode 100644 index 342a64c7f5de..000000000000 Binary files a/sound/music/Torch.ogg and /dev/null differ diff --git a/sound/music/europa/Martian Cowboy.ogg b/sound/music/europa/MartianCowboy.ogg similarity index 100% rename from sound/music/europa/Martian Cowboy.ogg rename to sound/music/europa/MartianCowboy.ogg diff --git a/sound/music/winter/alexander-nakarada-adventure.ogg b/sound/music/winter/alexander-nakarada-adventure.ogg new file mode 100644 index 000000000000..d41045603817 Binary files /dev/null and b/sound/music/winter/alexander-nakarada-adventure.ogg differ diff --git a/sound/voice/eal/eal1.ogg b/sound/voice/eal/eal1.ogg new file mode 100644 index 000000000000..5d66f6a44911 Binary files /dev/null and b/sound/voice/eal/eal1.ogg differ diff --git a/sound/voice/eal/eal2.ogg b/sound/voice/eal/eal2.ogg new file mode 100644 index 000000000000..1400a07cd85f Binary files /dev/null and b/sound/voice/eal/eal2.ogg differ diff --git a/sound/voice/eal/eal3.ogg b/sound/voice/eal/eal3.ogg new file mode 100644 index 000000000000..4dfb068988b0 Binary files /dev/null and b/sound/voice/eal/eal3.ogg differ diff --git a/sound/voice/eal/eal4.ogg b/sound/voice/eal/eal4.ogg new file mode 100644 index 000000000000..5ab3ddd6ee09 Binary files /dev/null and b/sound/voice/eal/eal4.ogg differ diff --git a/sound/voice/eal/eal5.ogg b/sound/voice/eal/eal5.ogg new file mode 100644 index 000000000000..05e5ac1acb8a Binary files /dev/null and b/sound/voice/eal/eal5.ogg differ diff --git a/sound/voice/eal/eal6.ogg b/sound/voice/eal/eal6.ogg new file mode 100644 index 000000000000..78978941e7bf Binary files /dev/null and b/sound/voice/eal/eal6.ogg differ diff --git a/sound/voice/eal/eal7.ogg b/sound/voice/eal/eal7.ogg new file mode 100644 index 000000000000..adc667622f7f Binary files /dev/null and b/sound/voice/eal/eal7.ogg differ diff --git a/sound/voice/eal/eal8.ogg b/sound/voice/eal/eal8.ogg new file mode 100644 index 000000000000..c2333ada60a2 Binary files /dev/null and b/sound/voice/eal/eal8.ogg differ diff --git a/sound/voice/emotes/f_cougha.ogg b/sound/voice/emotes/f_cougha.ogg new file mode 100644 index 000000000000..f53e0f5bd2c9 Binary files /dev/null and b/sound/voice/emotes/f_cougha.ogg differ diff --git a/sound/voice/emotes/f_coughb.ogg b/sound/voice/emotes/f_coughb.ogg new file mode 100644 index 000000000000..2626f8d6621a Binary files /dev/null and b/sound/voice/emotes/f_coughb.ogg differ diff --git a/sound/voice/emotes/f_sneeze.ogg b/sound/voice/emotes/f_sneeze.ogg new file mode 100644 index 000000000000..e6c4a49ade82 Binary files /dev/null and b/sound/voice/emotes/f_sneeze.ogg differ diff --git a/sound/voice/emotes/longwhistle.ogg b/sound/voice/emotes/longwhistle.ogg new file mode 100644 index 000000000000..0a2e82251500 Binary files /dev/null and b/sound/voice/emotes/longwhistle.ogg differ diff --git a/sound/voice/emotes/longwhistle_robot.ogg b/sound/voice/emotes/longwhistle_robot.ogg new file mode 100644 index 000000000000..d7bca51562bf Binary files /dev/null and b/sound/voice/emotes/longwhistle_robot.ogg differ diff --git a/sound/voice/emotes/m_cougha.ogg b/sound/voice/emotes/m_cougha.ogg new file mode 100644 index 000000000000..146beefdf873 Binary files /dev/null and b/sound/voice/emotes/m_cougha.ogg differ diff --git a/sound/voice/emotes/m_coughb.ogg b/sound/voice/emotes/m_coughb.ogg new file mode 100644 index 000000000000..745fb50e19c4 Binary files /dev/null and b/sound/voice/emotes/m_coughb.ogg differ diff --git a/sound/voice/emotes/m_coughc.ogg b/sound/voice/emotes/m_coughc.ogg new file mode 100644 index 000000000000..abfe70d27690 Binary files /dev/null and b/sound/voice/emotes/m_coughc.ogg differ diff --git a/sound/voice/emotes/m_sneeze.ogg b/sound/voice/emotes/m_sneeze.ogg new file mode 100644 index 000000000000..e7587bab20fa Binary files /dev/null and b/sound/voice/emotes/m_sneeze.ogg differ diff --git a/sound/voice/emotes/machine_cougha.ogg b/sound/voice/emotes/machine_cougha.ogg new file mode 100644 index 000000000000..e0a8441e3d43 Binary files /dev/null and b/sound/voice/emotes/machine_cougha.ogg differ diff --git a/sound/voice/emotes/machine_coughb.ogg b/sound/voice/emotes/machine_coughb.ogg new file mode 100644 index 000000000000..b70b6d16c144 Binary files /dev/null and b/sound/voice/emotes/machine_coughb.ogg differ diff --git a/sound/voice/emotes/machine_sneeze.ogg b/sound/voice/emotes/machine_sneeze.ogg new file mode 100644 index 000000000000..f0ba0ab81702 Binary files /dev/null and b/sound/voice/emotes/machine_sneeze.ogg differ diff --git a/sound/voice/emotes/shortwhistle.ogg b/sound/voice/emotes/shortwhistle.ogg new file mode 100644 index 000000000000..82ef01af3d07 Binary files /dev/null and b/sound/voice/emotes/shortwhistle.ogg differ diff --git a/sound/voice/emotes/shortwhistle_robot.ogg b/sound/voice/emotes/shortwhistle_robot.ogg new file mode 100644 index 000000000000..25780ecd387a Binary files /dev/null and b/sound/voice/emotes/shortwhistle_robot.ogg differ diff --git a/sound/voice/emotes/summon_whistle.ogg b/sound/voice/emotes/summon_whistle.ogg new file mode 100644 index 000000000000..ad978b4869ef Binary files /dev/null and b/sound/voice/emotes/summon_whistle.ogg differ diff --git a/sound/voice/emotes/summon_whistle_robot.ogg b/sound/voice/emotes/summon_whistle_robot.ogg new file mode 100644 index 000000000000..cc73d36a3e49 Binary files /dev/null and b/sound/voice/emotes/summon_whistle_robot.ogg differ diff --git a/sound/voice/emotes/wolfwhistle.ogg b/sound/voice/emotes/wolfwhistle.ogg new file mode 100644 index 000000000000..db0248f8f9a0 Binary files /dev/null and b/sound/voice/emotes/wolfwhistle.ogg differ diff --git a/sound/voice/emotes/wolfwhistle_robot.ogg b/sound/voice/emotes/wolfwhistle_robot.ogg new file mode 100644 index 000000000000..67082b28a6dd Binary files /dev/null and b/sound/voice/emotes/wolfwhistle_robot.ogg differ diff --git a/sound/voice/medbot/close.ogg b/sound/voice/medbot/close.ogg new file mode 100644 index 000000000000..9e0efcefd20d Binary files /dev/null and b/sound/voice/medbot/close.ogg differ diff --git a/sound/voice/medbot/dont_like.ogg b/sound/voice/medbot/dont_like.ogg new file mode 100644 index 000000000000..06fc84af2fa5 Binary files /dev/null and b/sound/voice/medbot/dont_like.ogg differ diff --git a/sound/voice/medbot/forgive.ogg b/sound/voice/medbot/forgive.ogg new file mode 100644 index 000000000000..729eaa5c78ed Binary files /dev/null and b/sound/voice/medbot/forgive.ogg differ diff --git a/sound/voice/medbot/fuck_you.ogg b/sound/voice/medbot/fuck_you.ogg new file mode 100644 index 000000000000..5eacff615fe3 Binary files /dev/null and b/sound/voice/medbot/fuck_you.ogg differ diff --git a/sound/voice/medbot/hey_wait.ogg b/sound/voice/medbot/hey_wait.ogg new file mode 100644 index 000000000000..6c88b761ec71 Binary files /dev/null and b/sound/voice/medbot/hey_wait.ogg differ diff --git a/sound/voice/medbot/i_require_asst.ogg b/sound/voice/medbot/i_require_asst.ogg new file mode 100644 index 000000000000..18fabc630f5a Binary files /dev/null and b/sound/voice/medbot/i_require_asst.ogg differ diff --git a/sound/voice/medbot/i_trusted_you.ogg b/sound/voice/medbot/i_trusted_you.ogg new file mode 100644 index 000000000000..602baa2f674d Binary files /dev/null and b/sound/voice/medbot/i_trusted_you.ogg differ diff --git a/sound/voice/medbot/im_different.ogg b/sound/voice/medbot/im_different.ogg new file mode 100644 index 000000000000..42eb8564f1ae Binary files /dev/null and b/sound/voice/medbot/im_different.ogg differ diff --git a/sound/voice/medbot/is_this_the_end.ogg b/sound/voice/medbot/is_this_the_end.ogg new file mode 100644 index 000000000000..a2e0e2330a39 Binary files /dev/null and b/sound/voice/medbot/is_this_the_end.ogg differ diff --git a/sound/voice/medbot/mapple.ogg b/sound/voice/medbot/mapple.ogg new file mode 100644 index 000000000000..21e26742ca13 Binary files /dev/null and b/sound/voice/medbot/mapple.ogg differ diff --git a/sound/voice/medbot/mcatch.ogg b/sound/voice/medbot/mcatch.ogg new file mode 100644 index 000000000000..07b8aaab75c4 Binary files /dev/null and b/sound/voice/medbot/mcatch.ogg differ diff --git a/sound/voice/medbot/mcoming.ogg b/sound/voice/medbot/mcoming.ogg new file mode 100644 index 000000000000..d3eb9e467f4b Binary files /dev/null and b/sound/voice/medbot/mcoming.ogg differ diff --git a/sound/voice/medbot/mdelicious.ogg b/sound/voice/medbot/mdelicious.ogg new file mode 100644 index 000000000000..5158538580ed Binary files /dev/null and b/sound/voice/medbot/mdelicious.ogg differ diff --git a/sound/voice/medbot/mfeelbetter.ogg b/sound/voice/medbot/mfeelbetter.ogg new file mode 100644 index 000000000000..fdbe57fd2e94 Binary files /dev/null and b/sound/voice/medbot/mfeelbetter.ogg differ diff --git a/sound/voice/medbot/mflies.ogg b/sound/voice/medbot/mflies.ogg new file mode 100644 index 000000000000..831281ebbee0 Binary files /dev/null and b/sound/voice/medbot/mflies.ogg differ diff --git a/sound/voice/medbot/mhelp.ogg b/sound/voice/medbot/mhelp.ogg new file mode 100644 index 000000000000..516d5db068d2 Binary files /dev/null and b/sound/voice/medbot/mhelp.ogg differ diff --git a/sound/voice/medbot/minjured.ogg b/sound/voice/medbot/minjured.ogg new file mode 100644 index 000000000000..0e968b3980c7 Binary files /dev/null and b/sound/voice/medbot/minjured.ogg differ diff --git a/sound/voice/medbot/minsult.ogg b/sound/voice/medbot/minsult.ogg new file mode 100644 index 000000000000..017292977a13 Binary files /dev/null and b/sound/voice/medbot/minsult.ogg differ diff --git a/sound/voice/medbot/mlive.ogg b/sound/voice/medbot/mlive.ogg new file mode 100644 index 000000000000..ceb0dec9a348 Binary files /dev/null and b/sound/voice/medbot/mlive.ogg differ diff --git a/sound/voice/medbot/mlost.ogg b/sound/voice/medbot/mlost.ogg new file mode 100644 index 000000000000..7b332ac346af Binary files /dev/null and b/sound/voice/medbot/mlost.ogg differ diff --git a/sound/voice/medbot/mno.ogg b/sound/voice/medbot/mno.ogg new file mode 100644 index 000000000000..030e43a01093 Binary files /dev/null and b/sound/voice/medbot/mno.ogg differ diff --git a/sound/voice/medbot/mpatchedup.ogg b/sound/voice/medbot/mpatchedup.ogg new file mode 100644 index 000000000000..1314f6ee4718 Binary files /dev/null and b/sound/voice/medbot/mpatchedup.ogg differ diff --git a/sound/voice/medbot/mradar.ogg b/sound/voice/medbot/mradar.ogg new file mode 100644 index 000000000000..ad347a6d891c Binary files /dev/null and b/sound/voice/medbot/mradar.ogg differ diff --git a/sound/voice/medbot/msurgeon.ogg b/sound/voice/medbot/msurgeon.ogg new file mode 100644 index 000000000000..a300ee57ef6d Binary files /dev/null and b/sound/voice/medbot/msurgeon.ogg differ diff --git a/sound/voice/medbot/nooo.ogg b/sound/voice/medbot/nooo.ogg new file mode 100644 index 000000000000..102fd1fb0427 Binary files /dev/null and b/sound/voice/medbot/nooo.ogg differ diff --git a/sound/voice/medbot/oh_fuck.ogg b/sound/voice/medbot/oh_fuck.ogg new file mode 100644 index 000000000000..95d21ef2550e Binary files /dev/null and b/sound/voice/medbot/oh_fuck.ogg differ diff --git a/sound/voice/medbot/pain_is_real.ogg b/sound/voice/medbot/pain_is_real.ogg new file mode 100644 index 000000000000..9cfa3a71be1c Binary files /dev/null and b/sound/voice/medbot/pain_is_real.ogg differ diff --git a/sound/voice/medbot/please_dont.ogg b/sound/voice/medbot/please_dont.ogg new file mode 100644 index 000000000000..a77ee09cb458 Binary files /dev/null and b/sound/voice/medbot/please_dont.ogg differ diff --git a/sound/voice/medbot/please_im_scared.ogg b/sound/voice/medbot/please_im_scared.ogg new file mode 100644 index 000000000000..7bd53b39c898 Binary files /dev/null and b/sound/voice/medbot/please_im_scared.ogg differ diff --git a/sound/voice/medbot/please_put_me_back.ogg b/sound/voice/medbot/please_put_me_back.ogg new file mode 100644 index 000000000000..84700fbdd576 Binary files /dev/null and b/sound/voice/medbot/please_put_me_back.ogg differ diff --git a/sound/voice/medbot/reported.ogg b/sound/voice/medbot/reported.ogg new file mode 100644 index 000000000000..d5469c19ceda Binary files /dev/null and b/sound/voice/medbot/reported.ogg differ diff --git a/sound/voice/medbot/shindemashou.ogg b/sound/voice/medbot/shindemashou.ogg new file mode 100644 index 000000000000..1ee2858eaf92 Binary files /dev/null and b/sound/voice/medbot/shindemashou.ogg differ diff --git a/sound/voice/medbot/thank_you.ogg b/sound/voice/medbot/thank_you.ogg new file mode 100644 index 000000000000..3fabe7d4a630 Binary files /dev/null and b/sound/voice/medbot/thank_you.ogg differ diff --git a/sound/voice/medbot/turn_off.ogg b/sound/voice/medbot/turn_off.ogg new file mode 100644 index 000000000000..87a4d6bdd0e0 Binary files /dev/null and b/sound/voice/medbot/turn_off.ogg differ diff --git a/sound/voice/medbot/why.ogg b/sound/voice/medbot/why.ogg new file mode 100644 index 000000000000..415020b89b00 Binary files /dev/null and b/sound/voice/medbot/why.ogg differ diff --git a/sound/voice/medbot/youre_good.ogg b/sound/voice/medbot/youre_good.ogg new file mode 100644 index 000000000000..62c325f83417 Binary files /dev/null and b/sound/voice/medbot/youre_good.ogg differ diff --git a/sound/weapons/Gunshot_phase.ogg b/sound/weapons/Gunshot_phase.ogg new file mode 100644 index 000000000000..abfe12c0d9cd Binary files /dev/null and b/sound/weapons/Gunshot_phase.ogg differ diff --git a/sound/weapons/dartgun.ogg b/sound/weapons/dartgun.ogg new file mode 100644 index 000000000000..99a5465d161f Binary files /dev/null and b/sound/weapons/dartgun.ogg differ diff --git a/sound/weapons/guns/interaction/energy_magin.ogg b/sound/weapons/guns/interaction/energy_magin.ogg new file mode 100644 index 000000000000..7e8a21549ca7 Binary files /dev/null and b/sound/weapons/guns/interaction/energy_magin.ogg differ diff --git a/sound/weapons/ionrifle.ogg b/sound/weapons/ionrifle.ogg new file mode 100644 index 000000000000..b808068e55f7 Binary files /dev/null and b/sound/weapons/ionrifle.ogg differ diff --git a/sound/weapons/sear.ogg b/sound/weapons/sear.ogg new file mode 100644 index 000000000000..c6d5f6846c9e Binary files /dev/null and b/sound/weapons/sear.ogg differ diff --git a/sound/weapons/searwall.ogg b/sound/weapons/searwall.ogg new file mode 100644 index 000000000000..6a29326f24b8 Binary files /dev/null and b/sound/weapons/searwall.ogg differ diff --git a/sound/weapons/zapbang.ogg b/sound/weapons/zapbang.ogg new file mode 100644 index 000000000000..4e14e30a11bd Binary files /dev/null and b/sound/weapons/zapbang.ogg differ diff --git a/sql/migrate/V001__Initial_schema.sql b/sql/migrate/V001__Initial_schema.sql index 245b8406ec7e..0a8650e8b8ff 100644 --- a/sql/migrate/V001__Initial_schema.sql +++ b/sql/migrate/V001__Initial_schema.sql @@ -18,7 +18,7 @@ CREATE TABLE IF NOT EXISTS `death` ( `brainloss` int(11) NOT NULL, `fireloss` int(11) NOT NULL, `oxyloss` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `erro_admin` ( `rank` varchar(32) NOT NULL DEFAULT 'Administrator', `level` int(2) NOT NULL DEFAULT '0', `flags` int(16) NOT NULL DEFAULT '0' -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -46,7 +46,7 @@ CREATE TABLE IF NOT EXISTS `erro_admin_log` ( `adminckey` varchar(32) NOT NULL, `adminip` varchar(18) NOT NULL, `log` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -78,7 +78,7 @@ CREATE TABLE IF NOT EXISTS `erro_ban` ( `unbanned_ckey` varchar(32) DEFAULT NULL, `unbanned_computerid` varchar(32) DEFAULT NULL, `unbanned_ip` varchar(32) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -93,7 +93,7 @@ CREATE TABLE IF NOT EXISTS `erro_feedback` ( `var_name` varchar(32) NOT NULL, `var_value` int(16) DEFAULT NULL, `details` text -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -109,7 +109,7 @@ CREATE TABLE IF NOT EXISTS `erro_player` ( `ip` varchar(18) NOT NULL, `computerid` varchar(32) NOT NULL, `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player' -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -127,7 +127,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_option` ( `descmin` varchar(32) DEFAULT NULL, `descmid` varchar(32) DEFAULT NULL, `descmax` varchar(32) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -142,7 +142,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_question` ( `endtime` datetime NOT NULL, `question` varchar(255) NOT NULL, `adminonly` tinyint(1) DEFAULT '0' -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -158,7 +158,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_textreply` ( `ip` varchar(18) NOT NULL, `replytext` text NOT NULL, `adminrank` varchar(32) NOT NULL DEFAULT 'Player' -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -175,7 +175,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_vote` ( `ip` varchar(16) NOT NULL, `adminrank` varchar(32) NOT NULL, `rating` int(2) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -188,7 +188,7 @@ CREATE TABLE IF NOT EXISTS `erro_privacy` ( `datetime` datetime NOT NULL, `ckey` varchar(32) NOT NULL, `option` varchar(128) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -202,7 +202,7 @@ CREATE TABLE IF NOT EXISTS `library` ( `title` text NOT NULL, `content` text NOT NULL, `category` text NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -215,7 +215,7 @@ CREATE TABLE IF NOT EXISTS `population` ( `playercount` int(11) DEFAULT NULL, `admincount` int(11) DEFAULT NULL, `time` datetime NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -238,7 +238,7 @@ CREATE TABLE IF NOT EXISTS `whitelist` ( `id` int(11) NOT NULL, `ckey` text NOT NULL, `race` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -- Indexes for dumped tables diff --git a/sql/migrate/V007__No_Privacy.sql b/sql/migrate/V007__No_Privacy.sql new file mode 100644 index 000000000000..b09f728f32e7 --- /dev/null +++ b/sql/migrate/V007__No_Privacy.sql @@ -0,0 +1,5 @@ +-- +-- Removes unused privacy table. +-- + +DROP TABLE `erro_privacy`; diff --git a/sql/migrate/V008__Ticket_Logging.sql b/sql/migrate/V008__Ticket_Logging.sql new file mode 100644 index 000000000000..d599aeb78394 --- /dev/null +++ b/sql/migrate/V008__Ticket_Logging.sql @@ -0,0 +1,12 @@ +DROP TABLE IF EXISTS `erro_admin_tickets`; +CREATE TABLE `erro_admin_tickets` ( + `id` int(11) AUTO_INCREMENT, + `assignee` text DEFAULT NULL, + `ckey` varchar(32) NOT NULL, + `text` text DEFAULT NULL, + `status` enum('OPEN','ASSIGNED','CLOSED','SOLVED','TIMED_OUT') NOT NULL, + `round` varchar(32), + `inround_id` int(11), + `open_date` date, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/sql/migrate/V009__Connection_Log.sql b/sql/migrate/V009__Connection_Log.sql new file mode 100644 index 000000000000..b00ea2468835 --- /dev/null +++ b/sql/migrate/V009__Connection_Log.sql @@ -0,0 +1,14 @@ +-- +-- Table structure for table `erro_connection_log` +-- +DROP TABLE IF EXISTS `erro_connection_log`; +CREATE TABLE IF NOT EXISTS `erro_connection_log` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `datetime` DATETIME DEFAULT now() NOT NULL, + `serverip` VARCHAR(32) NOT NULL, + `ckey` VARCHAR(32) NOT NULL, + `ip` VARCHAR(32) NOT NULL, + `computerid` VARCHAR(32) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/test/annotate_od.sh b/test/annotate_od.sh new file mode 100755 index 000000000000..c0197915ca1f --- /dev/null +++ b/test/annotate_od.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +set -euo pipefail +python tools/od_annotator/__main__.py "$@" diff --git a/test/check-paths.sh b/test/check-paths.sh index 8df3eaff375e..f59aa02ce4c7 100755 --- a/test/check-paths.sh +++ b/test/check-paths.sh @@ -9,9 +9,9 @@ exactly() { # exactly N name search [mode] [filter] name="$2" search="$3" mode="${4:--E}" - filter="${5:-**/*.dm}" + filter="${5:-*.dm}" - num="$(grep "$mode" "$search" $filter | wc -l || true)" + num="$(git grep "$mode" "$search" $filter | wc -l || true)" if [ $num -eq $count ]; then echo "$num $name" @@ -22,51 +22,40 @@ exactly() { # exactly N name search [mode] [filter] } # With the potential exception of << if you increase any of these numbers you're probably doing it wrong -exactly 0 "escapes" '\\\\(red|blue|green|black|b|i[^mc])' -exactly 4 "Del()s" '\WDel\(' +# Additional exception August 2020: \b is a regex symbol as well as a BYOND macro. +exactly 3 "escapes" '\\(red|blue|green|black|b|i[^mc])' +exactly 3 "Del()s" '(?> uses" '(?\\])>>(?!>)' -P exactly 0 "incorrect indentations" '^( {4,})' -P -exactly 19 "text2path uses" 'text2path' -exactly 3 "update_icon() override" '/update_icon\((.*)\)' -P -exactly 1 "goto uses" 'goto ' -exactly 6 "atom/New uses" '^/(obj|atom|area|mob|turf).*/New\(' -exactly 0 "tag uses" '\stag = ' -P '**/*.dmm' -# With the potential exception of << if you increase any of these numbers you're probably doing it wrong +exactly 22 "text2path uses" 'text2path' +exactly 4 "update_icon() overrides" '\/update_icon\(' -P +exactly 0 "goto uses" '\bgoto\b' +exactly 10 "atom/New uses" '^/(obj|atom|area|mob|turf).*/New\(' +exactly 1 "decl/New uses" '^/decl.*/New\(' +exactly 3 "tag uses" '(?/dev/null | tr -d $'\x7F-\x9F' | iconv -c -f iso8859-1 -t utf8 2>/dev/null); then - continue - else - echo "$file contains Unicode characters outside the ISO 8859-1 character set" - (( broken_files = broken_files + 1 )) - fi;; - *) - if diff -d "$file" <(<"$file" tr -d $'\x7F-\x9F' | iconv -c -f iso8859-1 -t utf8 2>/dev/null | iconv -c -f utf8 -t iso8859-1 2>/dev/null); then - continue - else - echo "$file contains characters outside the ISO 8859-1 character set" - (( broken_files = broken_files + 1 )) - fi;; - esac -done < <(find . -name '*.dm') -echo "$broken_files files with invalid characters" -if (( broken_files > 0 )); then - FAILED=1 -fi +# With the potential exception of << if you increase any of these numbers you're probably doing it wrong num=`find ./html/changelogs -not -name "*.yml" | wc -l` echo "$num non-yml files (expecting exactly 2)" diff --git a/test/compile-od-all-modpacks.sh b/test/compile-od-all-modpacks.sh new file mode 100755 index 000000000000..36ebe40fdc58 --- /dev/null +++ b/test/compile-od-all-modpacks.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -o pipefail + +dmepath="" + +for var; do + if [[ $var != -* && $var == *.dme ]]; then + dmepath=$(echo $var | sed -r 's/.{4}$//') + break + fi +done + +if [[ $dmepath == "" ]]; then + echo "No .dme file specified, aborting." + exit 1 +fi + +if [[ -a $dmepath.m.dme ]]; then + rm $dmepath.m.dme +fi + +cp $dmepath.dme $dmepath.m.dme +if [[ $? != 0 ]]; then + echo "Failed to make modified dme, aborting." + exit 2 +fi + +sed -i '1s/^/#define MAP_OVERRIDE\n/' $dmepath.m.dme +sed -i 's!#include "maps\\_map_include.dm"!#include "maps\\modpack_testing\\modpack_testing.dm"!' $dmepath.m.dme +failed=0 +./DMCompiler_linux-x64/DMCompiler "$dmepath.m.dme" --define=UNIT_TEST --suppress-unimplemented --skip-anything-typecheck --version=${BYOND_MAJOR}.${BYOND_MINOR} | bash test/annotate_od.sh +# Check the return value +if [[ $? -ne 0 ]]; then + failed=1 +fi +rm $dmepath.m.dme +if [[ $failed -eq 1 ]]; then + echo "Modpack testing map failed to pass validation." + exit 1 +fi \ No newline at end of file diff --git a/test/lint-all-modpacks.sh b/test/lint-all-modpacks.sh new file mode 100755 index 000000000000..e04ad04182e6 --- /dev/null +++ b/test/lint-all-modpacks.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +set -o pipefail + +dmepath="" + +for var; do + if [[ $var != -* && $var == *.dme ]]; then + dmepath=$(echo $var | sed -r 's/.{4}$//') + break + fi +done + +if [[ $dmepath == "" ]]; then + echo "No .dme file specified, aborting." + exit 1 +fi + +if [[ -a $dmepath.m.dme ]]; then + rm $dmepath.m.dme +fi + +cp $dmepath.dme $dmepath.m.dme +if [[ $? != 0 ]]; then + echo "Failed to make modified dme, aborting." + exit 2 +fi + +sed -i '1s/^/#define MAP_OVERRIDE\n/' $dmepath.m.dme +sed -i 's!#include "maps\\_map_include.dm"!#include "maps\\modpack_testing\\modpack_testing.dm"!' $dmepath.m.dme +failed=0 +# Run the linter, doing a full linting rather than just parsing +~/dreamchecker -e "$dmepath.m.dme" 2>&1 | tee -a "${GITHUB_WORKSPACE}/output-annotations.txt" +# Check the return value +if [[ $? -ne 0 ]]; then + failed=1 +fi +rm $dmepath.m.dme +if [[ $failed -eq 1 ]]; then + echo "Modpack testing map failed to pass validation." + exit 1 +fi \ No newline at end of file diff --git a/test/lint-each-modpack.sh b/test/lint-each-modpack.sh new file mode 100755 index 000000000000..b28ada773bff --- /dev/null +++ b/test/lint-each-modpack.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -o pipefail + +dmepath="" + +for var; do + if [[ $var != -* && $var == *.dme ]]; then + dmepath=$(echo $var | sed -r 's/.{4}$//') + break + fi +done + +if [[ $dmepath == "" ]]; then + echo "No .dme file specified, aborting." + exit 1 +fi + +if [[ -a $dmepath.m.dme ]]; then + rm $dmepath.m.dme +fi + +cp $dmepath.dme $dmepath.m.dme +if [[ $? != 0 ]]; then + echo "Failed to make modified dme, aborting." + exit 2 +fi + +sed -i '1s/^/#define MAP_OVERRIDE\n/' $dmepath.m.dme +sed -i 's!#include "maps\\_map_include.dm"!#include "maps\\example\\example.dm"!' $dmepath.m.dme + +# find feature DMEs to include. they're located in mods/**/**/*.dme. for example: mods/content/fantasy/_fantasy.dme +# it is guaranteed that each feature folder has only one DME file, so wildcard matching will work +dme_features=$(find mods -mindepth 3 -type f -name '*.dme') +# some features may be bare DM files, located at mods/**/*.dm. for example: mods/content/mundane.dm +# it is guaranteed that all bare DM files directly in mods/content, mods/gamemodes, and similar folders are able to be included as features +dm_features=$(find mods -mindepth 2 -maxdepth 2 -name '*.dm' ! -path 'mods/~*/*' ! -path 'mods/*/~.dm' ) +# do some sort of for loop to insert a feature at the end of the DME prior to #include "mods\~compatibility\~compatibility.dm" +# run ~/dreamchecker -e $dmepath.m.dme 2>&1 | tee -a ${GITHUB_WORKSPACE}/output-annotations.txt +# then remove the inserted feature after so the next step in the loop can test a new feature +failed=0 +for feature in $dme_features $dm_features; do + echo "Testing feature: $feature" + # Include the feature + sed -i "/#include \"mods\\\\_modpack.dm\"/a#include \"$feature\"" "$dmepath.m.dme" + # Run the linter, only doing parsing to catch undefined vars and keywords + ~/dreamchecker -e "$dmepath.m.dme" --parse-only 2>&1 | tee -a "${GITHUB_WORKSPACE}/output-annotations.txt" + # Check the return value + if [[ $? -ne 0 ]]; then + failed=1 + fi + # Remove the feature include + sed -i "\\:#include \"$feature\":d" "$dmepath.m.dme" +done +rm $dmepath.m.dme +if [[ $failed -eq 1 ]]; then + echo "One or more modpacks failed to pass solo validation." + exit 1 +fi \ No newline at end of file diff --git a/test/run-test.sh b/test/run-test.sh index c85b0a7a6f0a..e4bac59b824f 100755 --- a/test/run-test.sh +++ b/test/run-test.sh @@ -51,7 +51,7 @@ # groups that already exists. Add it to the relevant run_xxx_tests function, and # if it introduces any new dependencies, add them to the check_xxx_deps # function. Some dependencies are guaranteed to be on CI platforms by outside -# means (like .travis.yml), others will need to be installed by this script. +# means (like .github/workflows/test.yml), others will need to be installed by this script. # You'll see plenty of examples of checking for CI and gating tests on that, # installing instead of checking when running on CI. # @@ -160,7 +160,6 @@ function find_code_deps { need_cmd grep need_cmd awk need_cmd md5sum - need_cmd pyenv } function find_byond_deps { @@ -184,10 +183,10 @@ function find_code { } function setup_python3 { - pyenv global 3.6.7 pip3 install --upgrade pip -q pip3 install pyyaml==5.3 -q pip3 install beautifulsoup4==4.8.2 -q + pip3 install git+https://github.com/ComicIronic/ByondToolsv3.git@0.1.5#egg=ByondToolsv3 -q } function run_code_tests { @@ -195,8 +194,9 @@ function run_code_tests { find_code_deps setup_python3 shopt -s globstar - run_test "check travis contains all maps" "scripts/validateTravisContainsAllMaps.sh" + run_test "check test workflow contains all maps" "scripts/validateTestingContainsAllMaps.sh" run_test_fail "maps contain no step_[xy]" "grep 'step_[xy]' maps/**/*.dmm" + run_test_fail "maps contain no cable dir setting" "grep 'd[12] = ' maps/**/*.dmm" run_test_fail "maps contain no layer adjustments" "grep 'layer = ' maps/**/*.dmm" run_test_fail "maps contain no plane adjustments" "grep 'plane = ' maps/**/*.dmm" run_test_fail "ensure nanoui templates unique" "find nano/templates/ -type f -exec md5sum {} + | sort | uniq -D -w 32 | grep nano" @@ -207,8 +207,12 @@ function run_code_tests { run_test "check tags" "python3 tools/TagMatcher/tag-matcher.py ." run_test "check color hex" "python3 tools/ColorHexChecker/color-hex-checker.py ." run_test "check punctuation" "python3 tools/PunctuationChecker/punctuation-checker.py ." - run_test "check icon state limit" "python3 tools/dmitool/check_icon_state_limit.py ." - run_test_ci "check changelog builds" "python3 tools/GenerateChangelog/ss13_genchangelog.py html/changelog.html html/changelogs" + run_test "check icon state limit (icons)" "python3 tools/check_icon_state_limit.py icons" + run_test "check icon state limit (mods)" "python3 tools/check_icon_state_limit.py mods" + run_test "check icon state limit (maps)" "python3 tools/check_icon_state_limit.py maps" + run_test_ci "check changelog builds" "python3 tools/changelog/ss13_genchangelog.py html/changelog.html html/changelogs" + run_test "check files included" "python3 tools/validate_dme.py < nebula.dme" + run_test "check modpack files included" "python3 tools/validate_modpacks.py" } function run_byond_tests { @@ -218,7 +222,8 @@ function run_byond_tests { then exit 1 else msg "configured map is '$MAP_PATH'" fi - cp config/example/* config/ + cp -r config/example/* config/ + cp -r data/secrets/example/* data/secrets/ if [[ "$CI" == "true" ]]; then msg "installing BYOND" ./install-byond.sh || exit 1 diff --git a/tools/ColorHexChecker/color-hex-checker.py b/tools/ColorHexChecker/color-hex-checker.py index 9c198be41ac7..1d8b4e9f7168 100644 --- a/tools/ColorHexChecker/color-hex-checker.py +++ b/tools/ColorHexChecker/color-hex-checker.py @@ -1,7 +1,7 @@ import argparse, re, sys from os import sep, path, walk -color_hex_matcher = re.compile('\"#[\dA-F]{6}\"', re.IGNORECASE) +color_hex_matcher = re.compile(r'\"#[\dA-F]{6}\"', re.IGNORECASE) def get_bad_hexes_in_line(line): bad_hexes = [] @@ -25,7 +25,7 @@ def print_bad_hexes(bad_hexes_by_path): print('\tLine: {0}'.format(line)) for bad_hex in bad_hexes: print('\t\t{0}'.format(bad_hex)) - + def main(): opt = argparse.ArgumentParser() opt.add_argument('dir', help='The directory to recursively scan for *.dm and *.dmm files with invalid color hexes') diff --git a/tools/ReplicateSaves/README.md b/tools/ReplicateSaves/README.md new file mode 100644 index 000000000000..a2ce3bd3111d --- /dev/null +++ b/tools/ReplicateSaves/README.md @@ -0,0 +1,7 @@ +# Save replicator + +Very quick and dirty script used to replicate the player saves for a given map for all other maps. Does not overwrite existing saves. + +# Usage + +`python tools/ReplicateSaves/replicate_saves.py [map to copy saves from]` diff --git a/tools/ReplicateSaves/replicate_saves.py b/tools/ReplicateSaves/replicate_saves.py new file mode 100644 index 000000000000..7fb417b13def --- /dev/null +++ b/tools/ReplicateSaves/replicate_saves.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +import os +import sys +import re +import json + +__author__ = "MistakeNot4892" +__version__ = "0.1.0" +__license__ = "MIT" + +def main(): + + # Make sure they gave us a map to replicate. + if len(sys.argv) < 2: + print("Specify a map to replicate.") + return + + # Make sure we can access the maps folder. + mapname = sys.argv[1] + mapdir = os.path.join("maps") + if not os.path.isdir(mapdir): + print("Cannot find directory '" + mapdir + "', make sure you are running this script from the root repository directory.") + return + + ckey = None + if len(sys.argv) > 2: + ckey = sys.argv[2] + if ckey is not None: + ckey = ckey.lower() + + singletargetmap = None + if len(sys.argv) > 3: + singletargetmap = sys.argv[3] + if singletargetmap is not None: + singletargetmap = singletargetmap.lower() + + # Work out what maps we actually need to replicate to. + # This should be updated as map directories change, or the script will break. + targetmaps = [] + ignoremaps = [ + "away", + "away_sites_testing", + "antag_spawn", + "example", + "modpack_testing", + "random_ruins", + "~mapsystem", + "~unit_tests" + ] + for dir in os.scandir(mapdir): + if os.path.isdir(dir): + targetmap = dir.path + targetmap = targetmap.replace(mapdir + os.sep, "") + if (targetmap not in ignoremaps) and (targetmap != mapname) and ((singletargetmap is None) or (singletargetmap == targetmap)): + targetmaps.append(targetmap) + + # Make sure we can actually see the save directory. + scrapedir = os.path.join("data", "player_saves") + if not os.path.isdir(scrapedir): + print("Cannot find directory '" + scrapedir + "', make sure you are running this script from the root repository directory.") + return + + # Find existing saves for the target map, then replicate them to all our target map dirs. + # If they exist already, don't copy over, just move on. + filename_regex = r"character_([a-zA-Z0-9_]+)_(\d+)\.json" + print("Scanning saves in " + scrapedir + "...") + save_slots_to_update = [] + saves_to_replicate = [] + for (root, dirs, files) in os.walk(scrapedir): + for file in files: + match = re.match(filename_regex, file, re.I) + if match is None: + continue + if match.group(1) != mapname: + continue + if (ckey is not None) and (ckey != root[root.rfind("/")+1:]): + continue + savefile = os.path.join(root, file) + with open(savefile, "r") as loadedsave: + wrote = 0 + loadedlines = loadedsave.readlines() + for targetmap in targetmaps: + newfilename = savefile.replace(mapname, targetmap) + if not os.path.exists(newfilename): + with open(newfilename, "w") as writesave: + for line in loadedlines: + writesave.write(line) + wrote = wrote+1 + if wrote > 0: + print("Wrote " + str(wrote) + " copies of " + file + ".") + + # Collect slot names for each user to update their preferences.json + for (root, dirs, files) in os.walk(scrapedir): + has_prefs = False + has_saves = [] + for file in files: + if file == "preferences.json": + has_prefs = True + continue + match = re.match(filename_regex, file, re.I) + if match is None: + continue + has_saves.append(file) + + if has_prefs and len(has_saves): + new_slot_names = {} + for savefile in has_saves: + with open(os.path.join(root, savefile), "r") as loaded_save: + loaded_save_json = json.load(loaded_save) + new_slot_names[savefile.replace(".json", "")] = loaded_save_json["real_name"] + if len(new_slot_names): + loaded_pref_json = "" + with open(os.path.join(root, "preferences.json"), "r") as pref_file: + loaded_json = pref_file.read() + loaded_pref_json = json.loads(loaded_json) + loaded_pref_json["slot_names"] = new_slot_names + with open(os.path.join(root, "preferences.json"), "w") as pref_file: + pref_file.write(json.dumps(loaded_pref_json)) + + # Fin. + print("Done.") + +if __name__ == "__main__": + main() diff --git a/tools/TagMatcher/checkTagMatches.bat b/tools/TagMatcher/checkTagMatches.bat index 191c30bbba4c..2e53f85782db 100644 --- a/tools/TagMatcher/checkTagMatches.bat +++ b/tools/TagMatcher/checkTagMatches.bat @@ -1,3 +1,3 @@ -@echo off -call python tag-matcher.py ../.. -pause +@echo off +call python tag-matcher.py ../.. +pause diff --git a/tools/TagMatcher/tag-matcher.py b/tools/TagMatcher/tag-matcher.py index 66ba0f37ffba..a8e6a1322980 100644 --- a/tools/TagMatcher/tag-matcher.py +++ b/tools/TagMatcher/tag-matcher.py @@ -1,120 +1,120 @@ -''' -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -''' -import argparse, re, sys -from collections import defaultdict -from os import path, walk - -opt = argparse.ArgumentParser() -opt.add_argument('dir', help='The directory to scan for *.dm files with non-matching spans') -args = opt.parse_args() - -if(not path.isdir(args.dir)): - print('Not a directory') - sys.exit(1) - -# These tuples are expected to be ordered as: -# A unique human readable name (henceforth referred to as tuple name), a regex pattern matching an opening tag, a regex pattern matching a closing tag -tag_tuples = [ ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE)), - ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE)), - ('
    ', re.compile('
    ', re.IGNORECASE), re.compile('
    ', re.IGNORECASE)), - ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE)), - ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE))] - -# The keys of this dictionary will be the file path of each parsed *.dm file -# The values of this dictionary is a another dictionary with the key/value pair: tag/list of unmatched lines -mismatches_by_file = { } - -# Loops over all defined tag tuples and returns a dictionary with the key/value pair: tag/mismatch_count (positive means excess of opening tag, negative means excess of closing tags) -def get_tag_matches(line): - mismatch_count_by_tag = { } - for tag_tuple in tag_tuples: - mismatch_count = 0 - mismatch_count += len(tag_tuple[1].findall(line)) - mismatch_count -= len(tag_tuple[2].findall(line)) - if mismatch_count != 0: - mismatch_count_by_tag[tag_tuple[0]] = mismatch_count - return mismatch_count_by_tag - -# Support def that simply checks if a given dictionary in the format tag/list of unmatched lines has mismatch entries. -def has_mismatch(match_list): - for tag, list_of_mismatched_lines in match_list.items(): - if(len(list_of_mismatched_lines) > 0): - return 1 - return 0 - -def arrange_mismatches(mismatches_by_tag, mismatch_line, mismatch_counts): - for tag, mismatch_count in mismatch_counts.items(): - stack_of_existing_mismatches = mismatches_by_tag[tag] - for i in range(0, abs(mismatch_count)): - if len(stack_of_existing_mismatches) == 0: - if(mismatch_count > 0): - stack_of_existing_mismatches.append(mismatch_line) - else: - stack_of_existing_mismatches.append(-mismatch_line) - else: - if stack_of_existing_mismatches[0] > 0: - if mismatch_count > 0: - stack_of_existing_mismatches.append(mismatch_line) - else: - stack_of_existing_mismatches.pop() - else: - if mismatch_count < 0: - stack_of_existing_mismatches.append(-mismatch_line) - else: - stack_of_existing_mismatches.pop() - - -# This section parses all *.dm files in the given directory, recursively. -for root, subdirs, files in walk(args.dir): - for filename in files: - if filename.endswith('.dm'): - file_path = path.join(root, filename) - with open(file_path, 'r', encoding="latin-1") as file: - mismatches_by_file[file_path] = defaultdict(list) - for line_number, line in enumerate(file, 1): - # Then for each line in the file, conduct the tuple open/close matching. - mismatches_by_tag = get_tag_matches(line) - arrange_mismatches(mismatches_by_file[file_path], line_number, mismatches_by_tag) - -# Pretty printing section. -# Loops over all matches and checks if there is a mismatch of tags. -# If so, then and only then is the corresponding file path printed along with the number of unmatched open/close tags. -total_mismatches = 0 -for file, mismatches_by_tag in mismatches_by_file.items(): - if has_mismatch(mismatches_by_tag): - print(file) - for tag, mismatch_list in mismatches_by_tag.items(): - # A positive number means an excess of opening tag, a negative number means an excess of closing tags. - total_mismatches += len(mismatch_list) - if len(mismatch_list) > 0: - if mismatch_list[0] > 0: - print('\t{0} - Excess of {1} opening tag(s)'.format(tag, len(mismatch_list))) - elif mismatch_list[0] < 0: - print('\t{0} - Excess of {1} closing tag(s)'.format(tag, len(mismatch_list))) - for mismatch_line in sorted(set(mismatch_list)): - print('\t\tLine {0}'.format(abs(mismatch_line))) - -# Simply prints the total number of mismatches found and if so returns 1 to, for example, fail Travis builds. -if(total_mismatches == 0): - print('No mismatches found.') -else: - print('') - print('Total number of mismatches: {0}'.format(total_mismatches)) - sys.exit(1) +''' +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +''' +import argparse, re, sys +from collections import defaultdict +from os import path, walk + +opt = argparse.ArgumentParser() +opt.add_argument('dir', help='The directory to scan for *.dm files with non-matching spans') +args = opt.parse_args() + +if(not path.isdir(args.dir)): + print('Not a directory') + sys.exit(1) + +# These tuples are expected to be ordered as: +# A unique human readable name (henceforth referred to as tuple name), a regex pattern matching an opening tag, a regex pattern matching a closing tag +tag_tuples = [ ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE)), + ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE)), + ('
    ', re.compile('
    ', re.IGNORECASE), re.compile('
    ', re.IGNORECASE)), + ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE)), + ('', re.compile('', re.IGNORECASE), re.compile('', re.IGNORECASE))] + +# The keys of this dictionary will be the file path of each parsed *.dm file +# The values of this dictionary is a another dictionary with the key/value pair: tag/list of unmatched lines +mismatches_by_file = { } + +# Loops over all defined tag tuples and returns a dictionary with the key/value pair: tag/mismatch_count (positive means excess of opening tag, negative means excess of closing tags) +def get_tag_matches(line): + mismatch_count_by_tag = { } + for tag_tuple in tag_tuples: + mismatch_count = 0 + mismatch_count += len(tag_tuple[1].findall(line)) + mismatch_count -= len(tag_tuple[2].findall(line)) + if mismatch_count != 0: + mismatch_count_by_tag[tag_tuple[0]] = mismatch_count + return mismatch_count_by_tag + +# Support def that simply checks if a given dictionary in the format tag/list of unmatched lines has mismatch entries. +def has_mismatch(match_list): + for tag, list_of_mismatched_lines in match_list.items(): + if(len(list_of_mismatched_lines) > 0): + return 1 + return 0 + +def arrange_mismatches(mismatches_by_tag, mismatch_line, mismatch_counts): + for tag, mismatch_count in mismatch_counts.items(): + stack_of_existing_mismatches = mismatches_by_tag[tag] + for i in range(0, abs(mismatch_count)): + if len(stack_of_existing_mismatches) == 0: + if(mismatch_count > 0): + stack_of_existing_mismatches.append(mismatch_line) + else: + stack_of_existing_mismatches.append(-mismatch_line) + else: + if stack_of_existing_mismatches[0] > 0: + if mismatch_count > 0: + stack_of_existing_mismatches.append(mismatch_line) + else: + stack_of_existing_mismatches.pop() + else: + if mismatch_count < 0: + stack_of_existing_mismatches.append(-mismatch_line) + else: + stack_of_existing_mismatches.pop() + + +# This section parses all *.dm files in the given directory, recursively. +for root, subdirs, files in walk(args.dir): + for filename in files: + if filename.endswith('.dm'): + file_path = path.join(root, filename) + with open(file_path, 'r', encoding="latin-1") as file: + mismatches_by_file[file_path] = defaultdict(list) + for line_number, line in enumerate(file, 1): + # Then for each line in the file, conduct the tuple open/close matching. + mismatches_by_tag = get_tag_matches(line) + arrange_mismatches(mismatches_by_file[file_path], line_number, mismatches_by_tag) + +# Pretty printing section. +# Loops over all matches and checks if there is a mismatch of tags. +# If so, then and only then is the corresponding file path printed along with the number of unmatched open/close tags. +total_mismatches = 0 +for file, mismatches_by_tag in mismatches_by_file.items(): + if has_mismatch(mismatches_by_tag): + print(file) + for tag, mismatch_list in mismatches_by_tag.items(): + # A positive number means an excess of opening tag, a negative number means an excess of closing tags. + total_mismatches += len(mismatch_list) + if len(mismatch_list) > 0: + if mismatch_list[0] > 0: + print('\t{0} - Excess of {1} opening tag(s)'.format(tag, len(mismatch_list))) + elif mismatch_list[0] < 0: + print('\t{0} - Excess of {1} closing tag(s)'.format(tag, len(mismatch_list))) + for mismatch_line in sorted(set(mismatch_list)): + print('\t\tLine {0}'.format(abs(mismatch_line))) + +# Simply prints the total number of mismatches found and if so returns 1 to, for example, fail unit testing. +if(total_mismatches == 0): + print('No mismatches found.') +else: + print('') + print('Total number of mismatches: {0}'.format(total_mismatches)) + sys.exit(1) diff --git a/tools/changelog/generate_cl.py b/tools/changelog/generate_cl.py new file mode 100644 index 000000000000..b76f9a509137 --- /dev/null +++ b/tools/changelog/generate_cl.py @@ -0,0 +1,100 @@ +""" +DO NOT MANUALLY RUN THIS SCRIPT. +--------------------------------- + +This script is designed to generate and push a CL file that can be later compiled. +The body of the changelog is determined by the description of the PR that was merged. + +If a commit is pushed without being associated with a PR, or if a PR is missing a CL, +the script is designed to exit as a failure. This is to help keep track of PRs without +CLs and direct commits. See the relating comments in the below source to disable this function. + +This script depends on the tags.yml file located in the same directory. You can use that +file to configure the exact tags you'd like this script to use when generating changelog entries. +If this is being used in a /tg/ or Bee downstream, the default tags should work. + +Expected envrionmental variables: +----------------------------------- +GIT_NAME: Username of the github account to be used as the commiter (User provided) +GIT_EMAIL: Email associated with the above (User provided) +GITHUB_REPOSITORY: Github action variable representing the active repo (Action provided) +BOT_TOKEN: A repository account token, this will allow the action to push the changes (Action provided) +GITHUB_SHA: The SHA associated with the commit that triggered the action (Action provided) +""" +import os +import io +import re +from pathlib import Path +from ruamel import yaml +from github import Github, InputGitAuthor + +CL_BODY = re.compile(r"(:cl:|🆑)([^\r\n]+)?\r?\n([\s\S]+?)\r?\n\/(:cl:|🆑)", re.MULTILINE) +CL_SPLIT = re.compile(r"(^\w+):\s+(\w.+)", re.MULTILINE) + +git_email = os.getenv("GIT_EMAIL") +git_name = os.getenv("GIT_NAME") + +# Blessed is the GoOnStAtIoN birb ZeWaKa for thinking of this first +repo = os.getenv("GITHUB_REPOSITORY") +token = os.getenv("BOT_TOKEN") +sha = os.getenv("GITHUB_SHA") + +git = Github(token) +repo = git.get_repo(repo) +commit = repo.get_commit(sha) +pr_list = commit.get_pulls() + +if not pr_list.totalCount: + print("Direct commit detected") + exit(0) # Change to '0' if you do not want the action to fail when a direct commit is detected + +pr = pr_list[0] + +if not pr.body: + print("No PR body, exiting") + exit(0) # Change to '1' if you want the action to fail when no PR description is provided + +pr_body = pr.body +pr_number = pr.number +pr_author = pr.user.name or pr.user.login + +write_cl = {} +try: + cl = CL_BODY.search(pr_body) + cl_list = CL_SPLIT.findall(cl.group(3)) +except AttributeError: + print("No CL found!") + exit(0) # Change to '0' if you do not want the action to fail when no CL is provided + + +if cl.group(2) is not None: + write_cl['author'] = cl.group(2).lstrip() +else: + write_cl['author'] = pr_author + +write_cl['delete-after'] = True + +yaml = yaml.YAML(typ='safe', pure=True) +with open(Path.cwd().joinpath("tools/changelog/tags.yml")) as file: + tags = yaml.load(file) + +write_cl['changes'] = [] + +for k, v in cl_list: + if k in tags['tags'].keys(): # Check to see if there are any valid tags, as determined by tags.yml + v = v.rstrip() + if v not in list(tags['defaults'].values()): # Check to see if the tags are associated with something that isn't the default text + write_cl['changes'].append({tags['tags'][k]: v}) + +if write_cl['changes']: + with io.StringIO() as cl_contents: + yaml.indent(sequence=4, offset=2) + yaml.dump(write_cl, cl_contents) + cl_contents.seek(0) + + #Push the newly generated changelog to the master branch so that it can be compiled + repo.create_file(f"html/changelogs/AutoChangeLog-pr-{pr_number}.yml", f"Automatic changelog generation for PR #{pr_number} [ci skip]", content=f'{cl_contents.read()}', branch='dev', committer=InputGitAuthor(git_name, git_email)) + print("Done!") +else: + print("No CL changes detected!") + exit(0) # Change to a '1' if you want the action to count lacking CL changes as a failure \ No newline at end of file diff --git a/tools/GenerateChangelog/makeChangelog.bat b/tools/changelog/makeChangelog.bat similarity index 97% rename from tools/GenerateChangelog/makeChangelog.bat rename to tools/changelog/makeChangelog.bat index 67149b116523..7ee7bb625da4 100644 --- a/tools/GenerateChangelog/makeChangelog.bat +++ b/tools/changelog/makeChangelog.bat @@ -1,4 +1,4 @@ -@echo off -rem Cheridan asked for this. - N3X -call python ss13_genchangelog.py ../../html/changelog.html ../../html/changelogs -pause +@echo off +rem Cheridan asked for this. - N3X +call python ss13_genchangelog.py ../../html/changelog.html ../../html/changelogs +pause diff --git a/tools/GenerateChangelog/ss13_genchangelog.py b/tools/changelog/ss13_genchangelog.py similarity index 97% rename from tools/GenerateChangelog/ss13_genchangelog.py rename to tools/changelog/ss13_genchangelog.py index e439e45a18cc..17c68a49718e 100644 --- a/tools/GenerateChangelog/ss13_genchangelog.py +++ b/tools/changelog/ss13_genchangelog.py @@ -1,228 +1,228 @@ -''' -Usage: - $ python ss13_genchangelog.py [--dry-run] html/changelog.html html/changelogs/ - -ss13_genchangelog.py - Generate changelog from YAML. - -Copyright 2013 Rob "N3X15" Nelson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -''' - -from __future__ import print_function -import yaml, os, glob, sys, re, time, argparse -from datetime import datetime, date, timedelta -from time import time - -today = date.today() - -dateformat = "%d %B %Y" - -opt = argparse.ArgumentParser() -opt.add_argument('-d', '--dry-run', dest='dryRun', default=False, action='store_true', help='Only parse changelogs and, if needed, the targetFile. (A .dry_changelog.yml will be output for debugging purposes.)') -opt.add_argument('-t', '--time-period', dest='timePeriod', default=9, type=int, help='Define how many weeks back the changelog should display') -opt.add_argument('targetFile', help='The HTML changelog we wish to update.') -opt.add_argument('ymlDir', help='The directory of YAML changelogs we will use.') - -args = opt.parse_args() - -all_changelog_entries = {} - -validPrefixes = [ - 'bugfix', - 'wip', - 'tweak', - 'soundadd', - 'sounddel', - 'rscdel', - 'rscadd', - 'imageadd', - 'imagedel', - 'maptweak', - 'spellcheck', - 'experiment', - 'balance', - 'admin' -] - - -def dictToTuples(inp): - return [(k, v) for k, v in inp.items()] - -changelog_cache = os.path.join(args.ymlDir, '.all_changelog.yml') - -failed_cache_read = True -if os.path.isfile(changelog_cache): - try: - with open(changelog_cache,encoding='utf-8') as f: - (_, all_changelog_entries) = yaml.load_all(f, Loader=yaml.SafeLoader) - failed_cache_read = False - - # Convert old timestamps to newer format. - new_entries = {} - for _date in all_changelog_entries.keys(): - ty = type(_date).__name__ - # print(ty) - if ty in ['str', 'unicode']: - temp_data = all_changelog_entries[_date] - _date = datetime.strptime(_date, dateformat).date() - new_entries[_date] = temp_data - else: - new_entries[_date] = all_changelog_entries[_date] - all_changelog_entries = new_entries - except Exception as e: - print("Failed to read cache:") - print(e, file=sys.stderr) - -if args.dryRun: - changelog_cache = os.path.join(args.ymlDir, '.dry_changelog.yml') - -if failed_cache_read and os.path.isfile(args.targetFile): - from bs4 import BeautifulSoup - from bs4.element import NavigableString - print(' Generating cache...') - with open(args.targetFile, 'r', encoding='utf-8') as f: - soup = BeautifulSoup(f) - for e in soup.find_all('div', {'class': 'commit'}): - entry = {} - date = datetime.strptime(e.h2.string.strip(), dateformat).date() # key - for authorT in e.find_all('h3', {'class': 'author'}): - author = authorT.string - # Strip suffix - if author.endswith('updated:'): - author = author[:-8] - author = author.strip() - - # Find
      - ulT = authorT.next_sibling - while(ulT.name != 'ul'): - ulT = ulT.next_sibling - changes = [] - - for changeT in ulT.children: - if changeT.name != 'li': - continue - val = changeT.decode_contents(formatter="html") - newdat = {changeT['class'][0] + '': val + ''} - if newdat not in changes: - changes += [newdat] - - if len(changes) > 0: - entry[author] = changes - if date in all_changelog_entries: - all_changelog_entries[date].update(entry) - else: - all_changelog_entries[date] = entry - -del_after = [] -errors = False -print('Reading changelogs...') -for fileName in glob.glob(os.path.join(args.ymlDir, "*.yml")): - name, ext = os.path.splitext(os.path.basename(fileName)) - if name.startswith('.'): - continue - if name == 'example': - continue - fileName = os.path.abspath(fileName) - print(' Reading {}...'.format(fileName)) - cl = {} - with open(fileName, 'r',encoding='utf-8') as f: - cl = yaml.load(f, Loader=yaml.SafeLoader) - f.close() - if today not in all_changelog_entries: - all_changelog_entries[today] = {} - author_entries = all_changelog_entries[today].get(cl['author'], []) - if len(cl['changes']): - new = 0 - for change in cl['changes']: - if change not in author_entries: - (change_type, _) = dictToTuples(change)[0] - if change_type not in validPrefixes: - errors = True - print(' {0}: Invalid prefix {1}'.format(fileName, change_type), file=sys.stderr) - author_entries += [change] - new += 1 - all_changelog_entries[today][cl['author']] = author_entries - if new > 0: - print(' Added {0} new changelog entries.'.format(new)) - - if cl.get('delete-after', False): - if os.path.isfile(fileName): - if args.dryRun: - print(' Would delete {0} (delete-after set)...'.format(fileName)) - else: - del_after += [fileName] - - if args.dryRun: - continue - - cl['changes'] = [] - with open(fileName, 'w', encoding='utf-8') as f: - yaml.dump(cl, f, default_flow_style=False) - -targetDir = os.path.dirname(args.targetFile) - -with open(args.targetFile.replace('.htm', '.dry.htm') if args.dryRun else args.targetFile, 'w', encoding='utf-8') as changelog: - with open(os.path.join(targetDir, 'templates', 'header.html'), 'r', encoding='utf-8') as h: - for line in h: - changelog.write(line) - - weekstoshow = timedelta(weeks=args.timePeriod) - for _date in reversed(sorted(all_changelog_entries.keys())): - if not (today - _date < weekstoshow): - continue - entry_htm = '\n' - entry_htm += '\t\t\t

      {date}

      \n'.format(date=_date.strftime(dateformat)) - write_entry = False - for author in sorted(all_changelog_entries[_date].keys()): - if len(all_changelog_entries[_date]) == 0: - continue - author_htm = '\t\t\t

      {author} updated:

      \n'.format(author=author) - author_htm += '\t\t\t
        \n' - changes_added = [] - for (css_class, change) in (dictToTuples(e)[0] for e in all_changelog_entries[_date][author]): - if change in changes_added: - continue - write_entry = True - changes_added += [change] - author_htm += '\t\t\t\t
      • {change}
      • \n'.format(css_class=css_class, change=change.strip()) - author_htm += '\t\t\t
      \n' - if len(changes_added) > 0: - entry_htm += author_htm - if write_entry: - changelog.write(entry_htm) - - with open(os.path.join(targetDir, 'templates', 'footer.html'), 'r', encoding='utf-8') as h: - for line in h: - changelog.write(line) - - -with open(changelog_cache, 'w') as f: - cache_head = 'DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.' - yaml.safe_dump_all([cache_head, all_changelog_entries], f, default_flow_style=False) - -if len(del_after): - print('Cleaning up...') - for fileName in del_after: - if os.path.isfile(fileName): - print(' Deleting {0} (delete-after set)...'.format(fileName)) - os.remove(fileName) - -if errors: - sys.exit(1) +''' +Usage: + $ python ss13_genchangelog.py [--dry-run] html/changelog.html html/changelogs/ + +ss13_genchangelog.py - Generate changelog from YAML. + +Copyright 2013 Rob "N3X15" Nelson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +''' + +from __future__ import print_function +import yaml, os, glob, sys, re, time, argparse +from datetime import datetime, date, timedelta +from time import time + +today = date.today() + +dateformat = "%d %B %Y" + +opt = argparse.ArgumentParser() +opt.add_argument('-d', '--dry-run', dest='dryRun', default=False, action='store_true', help='Only parse changelogs and, if needed, the targetFile. (A .dry_changelog.yml will be output for debugging purposes.)') +opt.add_argument('-t', '--time-period', dest='timePeriod', default=9, type=int, help='Define how many weeks back the changelog should display') +opt.add_argument('targetFile', help='The HTML changelog we wish to update.') +opt.add_argument('ymlDir', help='The directory of YAML changelogs we will use.') + +args = opt.parse_args() + +all_changelog_entries = {} + +validPrefixes = [ + 'bugfix', + 'wip', + 'tweak', + 'soundadd', + 'sounddel', + 'rscdel', + 'rscadd', + 'imageadd', + 'imagedel', + 'maptweak', + 'spellcheck', + 'experiment', + 'balance', + 'admin' +] + + +def dictToTuples(inp): + return [(k, v) for k, v in inp.items()] + +changelog_cache = os.path.join(args.ymlDir, '.all_changelog.yml') + +failed_cache_read = True +if os.path.isfile(changelog_cache): + try: + with open(changelog_cache,encoding='utf-8') as f: + (_, all_changelog_entries) = yaml.load_all(f, Loader=yaml.SafeLoader) + failed_cache_read = False + + # Convert old timestamps to newer format. + new_entries = {} + for _date in all_changelog_entries.keys(): + ty = type(_date).__name__ + # print(ty) + if ty in ['str', 'unicode']: + temp_data = all_changelog_entries[_date] + _date = datetime.strptime(_date, dateformat).date() + new_entries[_date] = temp_data + else: + new_entries[_date] = all_changelog_entries[_date] + all_changelog_entries = new_entries + except Exception as e: + print("Failed to read cache:") + print(e, file=sys.stderr) + +if args.dryRun: + changelog_cache = os.path.join(args.ymlDir, '.dry_changelog.yml') + +if failed_cache_read and os.path.isfile(args.targetFile): + from bs4 import BeautifulSoup + from bs4.element import NavigableString + print(' Generating cache...') + with open(args.targetFile, 'r', encoding='utf-8') as f: + soup = BeautifulSoup(f) + for e in soup.find_all('div', {'class': 'commit'}): + entry = {} + date = datetime.strptime(e.h2.string.strip(), dateformat).date() # key + for authorT in e.find_all('h3', {'class': 'author'}): + author = authorT.string + # Strip suffix + if author.endswith('updated:'): + author = author[:-8] + author = author.strip() + + # Find
        + ulT = authorT.next_sibling + while(ulT.name != 'ul'): + ulT = ulT.next_sibling + changes = [] + + for changeT in ulT.children: + if changeT.name != 'li': + continue + val = changeT.decode_contents(formatter="html") + newdat = {changeT['class'][0] + '': val + ''} + if newdat not in changes: + changes += [newdat] + + if len(changes) > 0: + entry[author] = changes + if date in all_changelog_entries: + all_changelog_entries[date].update(entry) + else: + all_changelog_entries[date] = entry + +del_after = [] +errors = False +print('Reading changelogs...') +for fileName in glob.glob(os.path.join(args.ymlDir, "*.yml")): + name, ext = os.path.splitext(os.path.basename(fileName)) + if name.startswith('.'): + continue + if name == 'example': + continue + fileName = os.path.abspath(fileName) + print(' Reading {}...'.format(fileName)) + cl = {} + with open(fileName, 'r',encoding='utf-8') as f: + cl = yaml.load(f, Loader=yaml.SafeLoader) + f.close() + if today not in all_changelog_entries: + all_changelog_entries[today] = {} + author_entries = all_changelog_entries[today].get(cl['author'], []) + if len(cl['changes']): + new = 0 + for change in cl['changes']: + if change not in author_entries: + (change_type, _) = dictToTuples(change)[0] + if change_type not in validPrefixes: + errors = True + print(' {0}: Invalid prefix {1}'.format(fileName, change_type), file=sys.stderr) + author_entries += [change] + new += 1 + all_changelog_entries[today][cl['author']] = author_entries + if new > 0: + print(' Added {0} new changelog entries.'.format(new)) + + if cl.get('delete-after', False): + if os.path.isfile(fileName): + if args.dryRun: + print(' Would delete {0} (delete-after set)...'.format(fileName)) + else: + del_after += [fileName] + + if args.dryRun: + continue + + cl['changes'] = [] + with open(fileName, 'w', encoding='utf-8') as f: + yaml.dump(cl, f, default_flow_style=False) + +targetDir = os.path.dirname(args.targetFile) + +with open(args.targetFile.replace('.htm', '.dry.htm') if args.dryRun else args.targetFile, 'w', encoding='utf-8') as changelog: + with open(os.path.join(targetDir, 'templates', 'header.html'), 'r', encoding='utf-8') as h: + for line in h: + changelog.write(line) + + weekstoshow = timedelta(weeks=args.timePeriod) + for _date in reversed(sorted(all_changelog_entries.keys())): + if not (today - _date < weekstoshow): + continue + entry_htm = '\n' + entry_htm += '\t\t\t

        {date}

        \n'.format(date=_date.strftime(dateformat)) + write_entry = False + for author in sorted(all_changelog_entries[_date].keys()): + if len(all_changelog_entries[_date]) == 0: + continue + author_htm = '\t\t\t

        {author} updated:

        \n'.format(author=author) + author_htm += '\t\t\t
          \n' + changes_added = [] + for (css_class, change) in (dictToTuples(e)[0] for e in all_changelog_entries[_date][author]): + if change in changes_added: + continue + write_entry = True + changes_added += [change] + author_htm += '\t\t\t\t
        • {change}
        • \n'.format(css_class=css_class, change=change.strip()) + author_htm += '\t\t\t
        \n' + if len(changes_added) > 0: + entry_htm += author_htm + if write_entry: + changelog.write(entry_htm) + + with open(os.path.join(targetDir, 'templates', 'footer.html'), 'r', encoding='utf-8') as h: + for line in h: + changelog.write(line) + + +with open(changelog_cache, 'w') as f: + cache_head = 'DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.' + yaml.safe_dump_all([cache_head, all_changelog_entries], f, default_flow_style=False) + +if len(del_after): + print('Cleaning up...') + for fileName in del_after: + if os.path.isfile(fileName): + print(' Deleting {0} (delete-after set)...'.format(fileName)) + os.remove(fileName) + +if errors: + sys.exit(1) diff --git a/tools/changelog/tags.yml b/tools/changelog/tags.yml new file mode 100644 index 000000000000..e8f75d658a51 --- /dev/null +++ b/tools/changelog/tags.yml @@ -0,0 +1,31 @@ +tags: + bugfix: bugfix + wip: wip + tweak: tweak + soundadd: soundadd + sounddel: sounddel + rscdel: rscdel + rscadd: rscadd + imageadd: imageadd + imagedel: imagedel + maptweak: maptweak + spellcheck: spellcheck + experiment: experiment + balance: balance + admin: admin + +defaults: + bugfix: fixed a few things + wip: implemented wip things + tweak: tweaked a few things + soundadd: added a new sound thingy + sounddel: removed an old sound thingy + rscdel: removed old things + rscadd: added new things + imageadd: added some icons and images + imagedel: deleted some icons and images + maptweak: edited some maps + spellcheck: fixed a few typos + experiment: implemented experiment things + balance: rebalanced something + admin: messed with admin stuff diff --git a/tools/check_icon_state_limit.py b/tools/check_icon_state_limit.py new file mode 100644 index 000000000000..c39b3a6af435 --- /dev/null +++ b/tools/check_icon_state_limit.py @@ -0,0 +1,35 @@ +import argparse, sys, logging +from os import path, walk +from byond.DMI import DMI + +opt = argparse.ArgumentParser() +opt.add_argument('dir', help='The directory to scan for *.dmi files with an excess number of icon states.') +args = opt.parse_args() + +if(not path.isdir(args.dir)): + print('Not a directory') + sys.exit(1) + +failed = False +logging.getLogger().setLevel(logging.ERROR) # we don't care that byond is bad at pngs +# This section parses all *.dmi files in the given directory, recursively. +for root, subdirs, files in walk(args.dir): + for filename in files: + if not filename.endswith('.dmi'): + continue + file_path = path.join(root, filename) + try: + dmi = DMI(file_path) + dmi.loadMetadata() + number_of_icon_states = len(dmi.states) + if number_of_icon_states > 512: + failed = True + print("{0} had too many icon states. {1}/512".format(file_path, number_of_icon_states)) + except AttributeError as e: + failed = True + print("AttributeError when processing {0}. This may indicate an empty icon file.\nException was: {1}".format(file_path, e)) + except Exception as e: + failed = True + print("Exception when processing {0}: {1}".format(file_path, e)) +if failed: + sys.exit(1) diff --git a/tools/dmitool/check_icon_state_limit.py b/tools/dmitool/check_icon_state_limit.py deleted file mode 100644 index 92efb5775320..000000000000 --- a/tools/dmitool/check_icon_state_limit.py +++ /dev/null @@ -1,28 +0,0 @@ -import argparse, re, sys -from os import path, walk -import dmitool # This import is why this script is here. If someone can import this file cleanly from [repo root]/test/ instead, feel free - -opt = argparse.ArgumentParser() -opt.add_argument('dir', help='The directory to scan for *.dmi files with an excess number of icon states.') -args = opt.parse_args() - -if(not path.isdir(args.dir)): - print('Not a directory') - sys.exit(1) - -bad_dmi_files = [] - -# This section parses all *.dmi files in the given directory, recursively. -for root, subdirs, files in walk(args.dir): - for filename in files: - if filename.endswith('.dmi'): - file_path = path.join(root, filename) - dmi_info = dmitool.info(file_path) - number_of_icon_states = len(dmi_info["states"]) - if number_of_icon_states > 512: - bad_dmi_files.append((file_path, number_of_icon_states)) - -if len(bad_dmi_files) > 0: - for dmi_path, icon_states in bad_dmi_files: - print("{0} had too many icon states. {1}/512.".format(dmi_path, icon_states)) - sys.exit(1) diff --git a/tools/dmitool/git_merge_installer.bat b/tools/dmitool/git_merge_installer.bat index 18ab7c8026ab..c7ba2fa23a14 100644 --- a/tools/dmitool/git_merge_installer.bat +++ b/tools/dmitool/git_merge_installer.bat @@ -1,6 +1,6 @@ -@echo off -set tab= -echo. >> ../../.git/config -echo [merge "merge-dmi"] >> ../../.git/config -echo %tab%name = iconfile merge driver >> ../../.git/config -echo %tab%driver = ./tools/dmitool/dmimerge.sh %%O %%A %%B >> ../../.git/config +@echo off +set tab= +echo. >> ../../.git/config +echo [merge "merge-dmi"] >> ../../.git/config +echo %tab%name = iconfile merge driver >> ../../.git/config +echo %tab%driver = ./tools/dmitool/dmimerge.sh %%O %%A %%B >> ../../.git/config diff --git a/tools/expand_filedir_paths.py b/tools/expand_filedir_paths.py index d5a3d8d3f3a0..b58a8679398c 100644 --- a/tools/expand_filedir_paths.py +++ b/tools/expand_filedir_paths.py @@ -1,93 +1,93 @@ -#!/usr/bin/env python - -import re, os, sys, fnmatch - - -# Regex pattern to extract the directory path in a #define FILE_DIR -filedir_pattern = re.compile(r'^#define\s*FILE_DIR\s*"(.*?)"') - -# Regex pattern to extract any single quoted piece of text. This can also -# match single quoted strings inside of double quotes, which is part of a -# regular text string and should not be replaced. The replacement function -# however will any match that doesn't appear to be a filename so these -# extra matches should not be a problem. -rename_pattern = re.compile(r"'(.+?)'") - -# Only filenames matching this pattern will have their resources renamed -source_pattern = re.compile(r"^.*?\.(dm|dmm)$") - -# Open the .dme file and return a list of all FILE_DIR paths in it -def read_filedirs(filename): - result = [] - dme_file = file(filename, "rt") - - # Read each line from the file and check for regex pattern match - for row in dme_file: - match = filedir_pattern.match(row) - if match: - result.append(match.group(1)) - - dme_file.close() - return result - -# Search through a list of directories, and build a dictionary which -# maps every file to its full pathname (relative to the .dme file) -# If the same filename appears in more than one directory, the earlier -# directory in the list takes preference. -def index_files(file_dirs): - result = {} - - # Reverse the directory list so the earlier directories take precedence - # by replacing the previously indexed file of the same name - for directory in reversed(file_dirs): - for name in os.listdir(directory): - # Replace backslash path separators on Windows with forward slash - # Force "name" to lowercase when used as a key since BYOND resource - # names are case insensitive, even on Linux. - if name.find(".") == -1: - continue - result[name.lower()] = directory.replace('\\', '/') + '/' + name - - return result - -# Recursively search for every .dm/.dmm file in the .dme file directory. For -# each file, search it for any resource names in single quotes, and replace -# them with the full path previously found by index_files() -def rewrite_sources(resources): - # Create a closure for the regex replacement function to capture the - # resources dictionary which can't be passed directly to this function - def replace_func(name): - key = name.group(1).lower() - if key in resources: - replacement = resources[key] - else: - replacement = name.group(1) - return "'" + replacement + "'" - - # Search recursively for all .dm and .dmm files - for (dirpath, dirs, files) in os.walk("."): - for name in files: - if source_pattern.match(name): - path = dirpath + '/' + name - source_file = file(path, "rt") - output_file = file(path + ".tmp", "wt") - - # Read file one line at a time and perform replacement of all - # single quoted resource names with the fullpath to that resource - # file. Write the updated text back out to a temporary file. - for row in source_file: - row = rename_pattern.sub(replace_func, row) - output_file.write(row) - - output_file.close() - source_file.close() - - # Delete original source file and replace with the temporary - # output. On Windows, an atomic rename() operation is not - # possible like it is under POSIX. - os.remove(path) - os.rename(path + ".tmp", path) - -dirs = read_filedirs("tgstation.dme"); -resources = index_files(dirs) -rewrite_sources(resources) +#!/usr/bin/env python + +import re, os, sys, fnmatch + + +# Regex pattern to extract the directory path in a #define FILE_DIR +filedir_pattern = re.compile(r'^#define\s*FILE_DIR\s*"(.*?)"') + +# Regex pattern to extract any single quoted piece of text. This can also +# match single quoted strings inside of double quotes, which is part of a +# regular text string and should not be replaced. The replacement function +# however will any match that doesn't appear to be a filename so these +# extra matches should not be a problem. +rename_pattern = re.compile(r"'(.+?)'") + +# Only filenames matching this pattern will have their resources renamed +source_pattern = re.compile(r"^.*?\.(dm|dmm)$") + +# Open the .dme file and return a list of all FILE_DIR paths in it +def read_filedirs(filename): + result = [] + dme_file = file(filename, "rt") + + # Read each line from the file and check for regex pattern match + for row in dme_file: + match = filedir_pattern.match(row) + if match: + result.append(match.group(1)) + + dme_file.close() + return result + +# Search through a list of directories, and build a dictionary which +# maps every file to its full pathname (relative to the .dme file) +# If the same filename appears in more than one directory, the earlier +# directory in the list takes preference. +def index_files(file_dirs): + result = {} + + # Reverse the directory list so the earlier directories take precedence + # by replacing the previously indexed file of the same name + for directory in reversed(file_dirs): + for name in os.listdir(directory): + # Replace backslash path separators on Windows with forward slash + # Force "name" to lowercase when used as a key since BYOND resource + # names are case insensitive, even on Linux. + if name.find(".") == -1: + continue + result[name.lower()] = directory.replace('\\', '/') + '/' + name + + return result + +# Recursively search for every .dm/.dmm file in the .dme file directory. For +# each file, search it for any resource names in single quotes, and replace +# them with the full path previously found by index_files() +def rewrite_sources(resources): + # Create a closure for the regex replacement function to capture the + # resources dictionary which can't be passed directly to this function + def replace_func(name): + key = name.group(1).lower() + if key in resources: + replacement = resources[key] + else: + replacement = name.group(1) + return "'" + replacement + "'" + + # Search recursively for all .dm and .dmm files + for (dirpath, dirs, files) in os.walk("."): + for name in files: + if source_pattern.match(name): + path = dirpath + '/' + name + source_file = file(path, "rt") + output_file = file(path + ".tmp", "wt") + + # Read file one line at a time and perform replacement of all + # single quoted resource names with the fullpath to that resource + # file. Write the updated text back out to a temporary file. + for row in source_file: + row = rename_pattern.sub(replace_func, row) + output_file.write(row) + + output_file.close() + source_file.close() + + # Delete original source file and replace with the temporary + # output. On Windows, an atomic rename() operation is not + # possible like it is under POSIX. + os.remove(path) + os.rename(path + ".tmp", path) + +dirs = read_filedirs("tgstation.dme"); +resources = index_files(dirs) +rewrite_sources(resources) diff --git a/tools/indentation.awk b/tools/indentation.awk index 710339816792..8a7bfbc0e36b 100644 --- a/tools/indentation.awk +++ b/tools/indentation.awk @@ -16,12 +16,16 @@ } } - if ($0 ~ /,[\t ]*\\?\r?$/ || # comma at EOL - $0 ~ /list[\t ]*\([\t ]*\\?\r?$/ || # start of a list() - $0 ~ /pick[\t ]*\([\t ]*\\?\r?$/ ) { # start of a pick() - comma = 1 - } else { - comma = 0 + if ( $0 !~ /^[\t ]+\/[\/*]/ ) # Current line is not a comment, update comma state. + { + if ($0 ~ /,[\t ]*(\/[\/*].*)?\\?\\?\r?$/ || # comma at EOL + $0 ~ /list[\t ]*\([\t ]*(\/[\/*].*)?\\?\r?$/ || # start of a list() + $0 ~ /typesof[\t ]*\([\t ]*(\/[\/*].*)?\\?\r?$/ || # start of a typesof() + $0 ~ /pick[\t ]*\([\t ]*(\/[\/*].*)?\\?\r?$/ ) { # start of a pick() + comma = 1 + } else { + comma = 0 + } } } diff --git a/tools/map_migrations/0000_legacy.txt b/tools/map_migrations/0000_legacy.txt new file mode 100644 index 000000000000..7f3abebba23b --- /dev/null +++ b/tools/map_migrations/0000_legacy.txt @@ -0,0 +1,504 @@ +/obj/item/reagent_containers/@SUBTYPES : /obj/item/chems/@SUBTYPES{@OLD} +/obj/item/material/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} +/obj/item/weapon/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} +/obj/item/melee/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} +/obj/item/packageWrap/@SUBTYPES : /obj/item/stack/package_wrap/@SUBTYPES{@OLD} +/obj/structure/table/rack/@SUBTYPES : /obj/structure/rack/@SUBTYPES{@OLD} +/obj/structure/table/woodentable/holotable : /obj/structure/table/holo_woodentable{@OLD} +/obj/item/chems/food/drinks/@SUBTYPES : /obj/item/chems/drinks/@SUBTYPES{@OLD} +/obj/item/chems/food/snacks/@SUBTYPES : /obj/item/food/@SUBTYPES{@OLD} +/obj/item/chems/food/condiment/@SUBTYPES : /obj/item/chems/condiment/@SUBTYPES{@OLD} +/obj/item/chems/condiment/peppermill/@SUBTYPES : /obj/item/chems/condiment/small/peppermill/@SUBTYPES{@OLD} +/obj/item/chems/condiment/saltshaker/@SUBTYPES : /obj/item/chems/condiment/small/saltshaker/@SUBTYPES{@OLD} +/obj/item/analyzer : /obj/item/scanner/gas{@OLD} +/obj/item/analyzer/plant_analyzer/@SUBTYPES : /obj/item/scanner/plant/@SUBTYPES{@OLD} +/obj/item/tape_roll/@SUBTYPES : /obj/item/stack/tape_roll/@SUBTYPES{@OLD} +/obj/structure/table/standard/@SUBTYPES : /obj/structure/table/@SUBTYPES{@OLD} +/obj/machinery/bluespacerelay/@SUBTYPES : /obj/machinery/commsrelay/@SUBTYPES{@OLD} +/obj/machinery/computer/helm/@SUBTYPES : /obj/machinery/computer/ship/helm/@SUBTYPES{@OLD} +/obj/machinery/computer/engines/@SUBTYPES : /obj/machinery/computer/ship/engines/@SUBTYPES{@OLD} +/obj/machinery/computer/navigation/@SUBTYPES : /obj/machinery/computer/ship/navigation/@SUBTYPES{@OLD} +/obj/machinery/requests_console/@SUBTYPES : /obj/machinery/network/requests_console/@SUBTYPES{@OLD; departmentType = @SKIP} +/obj/item/healthanalyzer/@SUBTYPES : /obj/item/scanner/health/@SUBTYPES{@OLD} +/obj/machinery/iv_drip/@SUBTYPES : /obj/structure/iv_drip/@SUBTYPES{@OLD} +/obj/structure/device/piano/@SUBTYPES : /obj/structure/synthesized_instrument/synthesizer/piano/@SUBTYPES{@OLD} +/obj/item/folder/white/@SUBTYPES : /obj/item/folder/@SUBTYPES{@OLD} +/obj/machinery/dnaforensics/@SUBTYPES : /obj/machinery/forensic/dnascanner/@SUBTYPES{@OLD} +/obj/machinery/microscope/@SUBTYPES : /obj/machinery/forensic/microscope/@SUBTYPES{@OLD} +/obj/item/stack/material/steel/@SUBTYPES : /obj/item/stack/material/sheet/mapped/steel/@SUBTYPES{@OLD} +/obj/item/stack/material/plasteel/@SUBTYPES : /obj/item/stack/material/sheet/reinforced/mapped/plasteel/@SUBTYPES{@OLD} +/obj/item/stack/material/glass/reinforced/@SUBTYPES : /obj/item/stack/material/pane/mapped/rglass/@SUBTYPES{@OLD} +/obj/item/stack/material/glass/@SUBTYPES : /obj/item/stack/material/pane/mapped/glass/@SUBTYPES{@OLD} +/obj/item/stack/material/wood/@SUBTYPES : /obj/item/stack/material/plank/mapped/wood/@SUBTYPES{@OLD} +/obj/item/stack/material/deuterium/@SUBTYPES : /obj/item/stack/material/aerogel/mapped/deuterium/@SUBTYPES{@OLD} +/obj/item/stack/material/uranium/@SUBTYPES : /obj/item/stack/material/puck/mapped/uranium/@SUBTYPES{@OLD} +/obj/machinery/autolathe/@SUBTYPES : /obj/machinery/fabricator/@SUBTYPES{@OLD} +/obj/machinery/message_server/@SUBTYPES : /obj/machinery/network/message_server/@SUBTYPES{@OLD} +/obj/item/floor_painter/@SUBTYPES : /obj/item/paint_sprayer/@SUBTYPES{@OLD} +/obj/machinery/pipedispenser/@SUBTYPES : /obj/machinery/fabricator/pipe/@SUBTYPES{@OLD} +/obj/machinery/power/emitter/@SUBTYPES : /obj/machinery/emitter/@SUBTYPES{@OLD} +/obj/machinery/power/fusion_core/@SUBTYPES : /obj/machinery/fusion_core/@SUBTYPES{@OLD} +/obj/item/modular_computer/console/preset/@SUBTYPES : /obj/machinery/computer/modular/preset/@SUBTYPES{@OLD} +/obj/machinery/modular_computer/console/preset/@SUBTYPES : /obj/machinery/computer/modular/preset/@SUBTYPES{@OLD} +/obj/machinery/computer/modular/preset/command/@SUBTYPES : /obj/machinery/computer/modular/preset/cardslot/command/@SUBTYPES{@OLD} +/obj/machinery/computer/fusion_core_control/@SUBTYPES : /obj/machinery/computer/fusion/core_control/@SUBTYPES{@OLD} +/obj/machinery/computer/fusion_fuel_control/@SUBTYPES : /obj/machinery/computer/fusion/fuel_control/@SUBTYPES{@OLD} +/obj/machinery/computer/gyrotron_control/@SUBTYPES : /obj/machinery/computer/fusion/gyrotron/@SUBTYPES{@OLD} +/obj/machinery/computer/power_monitor/@SUBTYPES : /obj/machinery/computer/modular/preset/engineering/power/@SUBTYPES{@OLD} +/obj/item/module/power_control/@SUBTYPES : /obj/item/stock_parts/circuitboard/apc/@SUBTYPES{@OLD} +/obj/machinery/power/port_gen/@SUBTYPES : /obj/machinery/port_gen/@SUBTYPES{@OLD} +/obj/item/pipe_painter/@SUBTYPES : /obj/item/paint_sprayer/@SUBTYPES{@OLD} +/obj/item/airlock_electronics/@SUBTYPES : /obj/item/stock_parts/circuitboard/airlock_electronics/@SUBTYPES{@OLD} +/obj/item/airalarm_electronics/@SUBTYPES : /obj/item/stock_parts/circuitboard/air_alarm/@SUBTYPES{@OLD} +/obj/item/autopsy_scanner/@SUBTYPES : /obj/item/scanner/autopsy/@SUBTYPES{@OLD} +/obj/machinery/fusion_fuel_compressor/@SUBTYPES : /obj/machinery/fuel_compressor/@SUBTYPES{@OLD} +/obj/item/extinguisher/micro/@SUBTYPES : /obj/item/chems/spray/extinguisher/mini/@SUBTYPES{@OLD} +/obj/item/extinguisher/@SUBTYPES : /obj/item/chems/spray/extinguisher/@SUBTYPES{@OLD} +/obj/item/stack/material/plastic/@SUBTYPES : /obj/item/stack/material/panel/mapped/plastic/@SUBTYPES{@OLD} +/obj/machinery/computer/general_air_control/@SUBTYPES : /obj/machinery/computer/air_control/@SUBTYPES{@OLD} +/obj/machinery/computer/air_control/large_tank_control : /obj/machinery/computer/air_control{@OLD} +/turf/simulated/floor/tiled/steel/@SUBTYPES : /turf/simulated/floor/tiled/@SUBTYPES{@OLD} +/obj/machinery/power/engine/@SUBTYPES : /obj/machinery/ion_thruster/@SUBTYPES{@OLD} +/obj/machinery/computer/aifixer/@SUBTYPES : /obj/machinery/computer/modular/preset/aislot/sysadmin/@SUBTYPES{@OLD} +/obj/machinery/computer/aiupload/@SUBTYPES : /obj/machinery/computer/upload/ai/@SUBTYPES{@OLD} +/obj/machinery/computer/borgupload/@SUBTYPES : /obj/machinery/computer/upload/robot/@SUBTYPES{@OLD} +/obj/machinery/computer/supplycomp/control/@SUBTYPES : /obj/machinery/computer/modular/preset/dock/@SUBTYPES{@OLD} +/obj/machinery/computer/supplycomp/@SUBTYPES : /obj/machinery/computer/modular/preset/supply_public/@SUBTYPES{@OLD} +/obj/item/closet_painter/@SUBTYPES : /obj/item/paint_sprayer/@SUBTYPES{@OLD} +/turf/simulated/shuttle/plating/@SUBTYPES : /turf/floor/shuttle +/turf/simulated/shuttle/floor/@SUBTYPES : /turf/floor/shuttle/@SUBTYPES + +# REMOVE BAD VAREDITS +/@SUBTYPES {layer = @SET} : @OLD {@OLD; layer = @SKIP} +/@SUBTYPES {plane = @SET} : @OLD {@OLD; plane = @SKIP} +/obj/structure/cable/@SUBTYPES : @OLD {@OLD; d1 = @SKIP;d2 = @SKIP} +# unacidable removed +/@SUBTYPES {unacidable = @SET} : @OLD{@OLD; unacidable = @SKIP} +# Simple pipes shall not face north or west +/obj/machinery/atmospherics/pipe/simple/hidden@SUBTYPES {dir = 1} : @OLD {@OLD; dir = 2} +/obj/machinery/atmospherics/pipe/simple/visible@SUBTYPES {dir = 1} : @OLD {@OLD; dir = 2} +/obj/machinery/atmospherics/pipe/simple/hidden@SUBTYPES {dir = 8} : @OLD {@OLD; dir = 4} +/obj/machinery/atmospherics/pipe/simple/visible@SUBTYPES {dir = 8} : @OLD {@OLD; dir = 4} +# Do not change air alarm frequency on base type +/obj/machinery/alarm {frequency = @SET} : @OLD {@OLD; frequency = @SKIP} +# we use a completely different access format +/@SUBTYPES {req_access = @SET}: @OLD {@OLD; req_access = @SKIP;} +/@SUBTYPES {req_one_access = @SET}: @OLD {@OLD; req_one_access = @SKIP;} +/obj/machinery/door/blast/shutters{icon_state = "shutter0"} : /obj/machinery/door/blast/shutters{@OLD; icon_state = @SKIP} +/obj/machinery/door/airlock/external/glass{icon_state = @SET; locked = 1; density = 0, opacity = 0} : /obj/machinery/door/airlock/external/glass/bolted_open{@OLD; icon_state = @SKIP; locked = @SKIP, density = @SKIP; opacity = @SKIP} +/obj/machinery/door/airlock/external/glass{icon_state = @SET; locked = 1} : /obj/machinery/door/airlock/external/glass/bolted{@OLD; icon_state = @SKIP; locked = @SKIP} + +# BUTTONS +/obj/machinery/access_button/airlock_exterior : /obj/machinery/button/access/exterior{@OLD} +/obj/machinery/access_button/airlock_interior : /obj/machinery/button/access/interior{@OLD} +/obj/machinery/airlock_sensor/airlock_exterior : /obj/machinery/button/access/exterior{@OLD} +/obj/machinery/airlock_sensor/airlock_interior : /obj/machinery/button/access/interior{@OLD} +/obj/machinery/access_button : /obj/machinery/button/access{@OLD} +/obj/machinery/button/remote/airlock{specialfunctions = 4} : /obj/machinery/button/alternate/door/bolts{@OLD; specialfunctions = @SKIP; desiredstate = @SKIP} +/obj/machinery/button/remote/airlock : /obj/machinery/button/alternate/door{@OLD} +/obj/machinery/button/remote/driver : /obj/machinery/button/mass_driver{@OLD} +/obj/machinery/button/remote/blast_door : /obj/machinery/button/blast_door{@OLD} +/obj/machinery/button/remote : /obj/machinery/button/alternate{@OLD} + +# Medical +/obj/item/pill_bottle/tramadol : /obj/item/pill_bottle/strong_painkillers{@OLD} +/obj/item/chems/pill/tramadol : /obj/item/chems/pill/strong_painkillers{@OLD} +/obj/item/chems/glass/bottle/stoxin : /obj/item/chems/glass/bottle/sedatives{@OLD} +/obj/item/chems/glass/bottle/inaprovaline : /obj/item/chems/glass/bottle/stabilizer{@OLD} +/obj/item/chems/syringe/inaprovaline : /obj/item/chems/syringe/stabilizer{@OLD} +/obj/item/chems/blood/empty : /obj/item/chems/ivbag{@OLD} +/obj/item/chems/blood/@SUBTYPES : /obj/item/chems/ivbag/blood/@SUBTYPES{@OLD} +/obj/item/defib_kit/@SUBTYPES : /obj/item/defibrillator/@SUBTYPES{@OLD} +/obj/item/chems/spray/sterilizine : /obj/item/chems/spray/antiseptic{@OLD} + +# Drinking glasses and cups +/obj/item/chems/drinks/cup : /obj/item/chems/drinks/glass2/coffeecup{@OLD} +/obj/item/chems/drinks/drinkingglass : /obj/item/chems/drinks/glass2/square{@OLD} + +# Airtight flaps +/obj/structure/plasticflaps/mining : /obj/structure/flaps/airtight{@OLD} + +# Bushes +/obj/structure/flora/ausbushes/@SUBTYPES : /obj/structure/flora/bush/@SUBTYPES + +# Cassette tapes -> magnetic tapes +/obj/item/cassette_tape/@SUBTYPES : /obj/item/magnetic_tape/@SUBTYPES{@OLD} +/obj/item/tape_recorder : /obj/item/taperecorder{@OLD} + +# FIFTYSPAWNER -> MAPPED SHEETS +/obj/fiftyspawner/wood : /obj/item/stack/material/plank/mapped/wood/fifty +/obj/fiftyspawner/steel : /obj/item/stack/material/sheet/mapped/steel/fifty +/obj/fiftyspawner/glass : /obj/item/stack/material/pane/mapped/glass/fifty +/obj/fiftyspawner/deuterium : /obj/item/stack/material/aerogel/mapped/deuterium/fifty +/obj/fiftyspawner/tritium : /obj/item/stack/material/aerogel/mapped/tritium/fifty +/obj/fiftyspawner/osmium : /obj/item/stack/material/aerogel/mapped/tritium/fifty +/obj/fiftyspawner/phoron : /obj/item/stack/material/aerogel/mapped/tritium/fifty +/obj/fiftyspawner/rods : /obj/item/stack/material/aerogel/mapped/tritium/fifty +/obj/fiftyspawner/grass : /obj/item/stack/tile/grass{amount = 50} +/obj/fiftyspawner/plasteel : /obj/item/stack/material/aerogel/mapped/tritium/fifty + +# STOCK PARTS AND SMES COILS +/obj/item/stock_parts/subspace/sub_filter : /obj/item/stock_parts/subspace/filter +/obj/item/smes_coil/@SUBTYPES : /obj/item/stock_parts/smes_coil/@SUBTYPES{@OLD} +/obj/item/circuitboard/@SUBTYPES : /obj/item/stock_parts/circuitboard/@SUBTYPES{@OLD} +/obj/item/airlock_electronics : /obj/item/stock_parts/circuitboard/airlock_electronics{@OLD} + +# CLOTHING +/obj/item/clothing/head/cone : /obj/item/caution/cone{@OLD} +/obj/item/clothing/belt/security/tactical : /obj/item/belt/holster/security/tactical{@OLD} + +# Item remains +/obj/effect/decal/remains/@SUBTYPES : /obj/item/remains/@SUBTYPES{@OLD} + +# Circuit prefabs +/obj/item/hand_tele : /obj/abstract/prefab/hand_teleporter{@OLD} + +# Filing cabinets +/obj/structure/filingcabinet : /obj/structure/filing_cabinet{@OLD} +/obj/structure/filingcabinet/chestdrawer : /obj/structure/filing_cabinet/chestdrawer{@OLD} +/obj/structure/filingcabinet/filingcabinet : /obj/structure/filing_cabinet/tall{@OLD} +/obj/structure/filingcabinet/medical : /obj/structure/filing_cabinet/records/medical{@OLD} +/obj/structure/filingcabinet/security : /obj/structure/filing_cabinet/records{@OLD} + +# Machine frames +/obj/structure/frame: /obj/machinery/constructable_frame/machine_frame{@OLD} +/obj/machinery/constructable_frame/machine_frame{anchored = 1} : /obj/machinery/constructable_frame/machine_frame/deconstruct{anchored = @SKIP} +/obj/structure/frame/computer : /obj/machinery/constructable_frame/computerframe{@OLD} +/obj/machinery/constructable_frame/computerframe{anchored = 1} : /obj/machinery/constructable_frame/computerframe/deconstruct{anchored = @SKIP} + +# Hygiene/bathroom objects +/obj/structure/toilet : /obj/structure/hygiene/toilet{@OLD} +/obj/structure/sink/@SUBTYPES : /obj/structure/hygiene/sink/@SUBTYPES{@OLD} +/obj/machinery/shower : /obj/structure/hygiene/shower{@OLD} + +# Turbolift spawners +/obj/turbolift_map_holder/@SUBTYPES : /obj/abstract/turbolift_spawner/@SUBTYPES{@OLD} + +# Borosilicate windows +/obj/structure/window/phoronreinforced/@SUBTYPES : /obj/structure/window/borosilicate_reinforced/@SUBTYPES{@OLD} + +# Tools; see 3763_pickaxe_hammer and 3959_hatchets for other migrations +/obj/item/knife/machete : /obj/item/tool/machete{@OLD} +/obj/item/knife/machete/hatchet : /obj/item/tool/axe/hatchet{@OLD} +/obj/item/tool/pickaxe/hand : /obj/item/tool/pickaxe/xeno/hand{@OLD} + +# RANDOM SPAWNERS +/obj/random/cigarettes : /obj/random/smokes{@OLD} +/obj/item/lipstick/random : /obj/random/lipstick +/obj/random/slimecore : /obj/item/slime_extract/random{@OLD} + +# MINING EQUIPMENT +/obj/machinery/mineral/processing_unit : /obj/machinery/material_processing/smeltery +/obj/machinery/mineral/stacking_machine : /obj/machinery/material_processing/stacker +/obj/machinery/mineral/unloading_machine : /obj/machinery/material_processing/unloader +/obj/machinery/mineral/output : @DELETE +/obj/machinery/mineral/input : @DELETE +/obj/machinery/mineral/mint : @DELETE +/obj/machinery/mineral/processing_unit_console : @DELETE + +# NEW PDAS (NO CARTRIDGES) +/obj/item/pda/@SUBTYPES : /obj/item/modular_computer/pda/@SUBTYPES{@OLD} +/obj/item/modular_computer/pda/captain : /obj/item/modular_computer/pda/heads/captain +/obj/item/storage/box/seccarts : @DELETE +/obj/item/cartridge/@SUBTYPES : @DELETE + +# MODULAR COMPUTER PRESETS +/obj/machinery/computer/card : /obj/machinery/computer/modular/preset/cardslot/personnel{@OLD} +/obj/machinery/computer/secure_data : /obj/machinery/computer/modular/preset/civilian{@OLD} +/obj/machinery/computer/skills : /obj/machinery/computer/modular/preset/civilian{@OLD} +/obj/machinery/computer/security/telescreen : /obj/machinery/computer/modular/telescreen/preset/security{@OLD} +/obj/machinery/computer/security/telescreen/entertainment : /obj/machinery/computer/modular/telescreen/preset/entertainment{@OLD} +/obj/machinery/computer/security/mining : /obj/machinery/computer/modular/preset/security{@OLD} +/obj/machinery/computer/security/@SUBTYPES : /obj/machinery/computer/modular/preset/@SUBTYPES +/obj/machinery/computer/crew : /obj/machinery/computer/modular/preset/medical{@OLD} +/obj/machinery/computer/rcon : /obj/machinery/computer/modular/preset/engineering/rcon{@OLD} +/obj/machinery/computer/communications : /obj/machinery/computer/modular/preset/cardslot/command{@OLD} +/obj/machinery/computer/med_data : /obj/machinery/computer/modular/preset/civilian{@OLD} +/obj/machinery/computer/med_data/laptop : /obj/item/modular_computer/laptop/preset/records{@OLD} + +# ATMOS REPATHS +/obj/machinery/atmospherics/pipe/tank/@SUBTYPES : /obj/machinery/atmospherics/unary/tank/@SUBTYPES +/obj/machinery/portable_atmospherics/canister/nitrous_oxide : /obj/machinery/portable_atmospherics/canister/sleeping_agent{@OLD} + +# MISC. ITEMS +/obj/item/moneybag/vault : /obj/item/bag/cash/filled{@OLD} +/obj/item/moneybag : /obj/item/bag/cash{@OLD} +/obj/item/chems/bucket : /obj/item/chems/glass/bucket{@OLD} +/obj/item/card/id/gold/captain/spare : /obj/item/card/id/captains_spare{@OLD} +/obj/item/chainofcommand : /obj/item/whip/chainofcommand{@OLD} +/obj/item/chems/drinks/bottle/specialwhiskey : /obj/item/chems/drinks/bottle/agedwhiskey{@OLD} + +# Tape is weird +/obj/item/taperoll/@SUBTYPES : /obj/item/stack/tape_roll/barricade_tape/@SUBTYPES{@OLD} +/obj/item/tape/@SUBTYPES : /obj/structure/tape_barricade/@SUBTYPES{@OLD} + +# Radio +/obj/item/radio/headset/headset_sec/alt : /obj/item/radio/headset/headset_sec/bowman{@OLD} +/obj/item/radio/headset/syndicate : /obj/item/radio/headset/hacked{@OLD} +/obj/item/radio/headset/syndicate/alt : /obj/item/radio/headset/hacked{@OLD} +/obj/item/phone : /obj/item/radio/phone{@OLD} + +# Singulo +/obj/machinery/the_singularitygen : /obj/machinery/singularity_generator{@OLD} + +# FABRICATORS +/obj/machinery/autolathe{hacked = 1} : /obj/machinery/fabricator/hacked{@OLD; hacked = @SKIP} +/obj/machinery/autolathe : /obj/machinery/fabricator{@OLD} +/obj/machinery/pipedispenser : /obj/machinery/fabricator/pipe{@OLD; anchored = 1} +/obj/machinery/pipedispenser/orderable : /obj/machinery/fabricator/pipe{@OLD} +/obj/machinery/pipedispenser/disposal : /obj/machinery/fabricator/pipe/disposal{@OLD; anchored = 1} +/obj/machinery/pipedispenser/disposal/orderable : /obj/machinery/fabricator/pipe/disposal{@OLD} +/obj/machinery/r_n_d/circuit_imprinter : /obj/machinery/fabricator/imprinter{@OLD} +/obj/machinery/pros_fabricator : /obj/machinery/fabricator/robotics{@OLD} +/obj/machinery/mecha_part_fabricator : /obj/machinery/fabricator/industrial{@OLD} +/obj/machinery/r_n_d/protolathe : /obj/machinery/fabricator/protolathe{@OLD} +/obj/machinery/bookbinder : /obj/machinery/fabricator/book{@OLD} +/obj/machinery/organ_printer/flesh : /obj/machinery/fabricator/bioprinter{@OLD} +/obj/machinery/vending/food : /obj/machinery/fabricator/replicator + +/obj/machinery/fabricator/@SUBTYPES : /obj/machinery/fabricator/@SUBTYPES{@OLD; res_max_amount = @SKIP; speed = @SKIP} + +# MMIs and posibrains +/obj/item/mmi/digital/@SUBTYPES : /obj/item/organ/internal/brain/robotic{@OLD} +/obj/item/mmi/@SUBTYPES : /obj/item/organ/internal/brain_interface/@SUBTYPES{@OLD} +/obj/item/organ/internal/posibrain : /obj/item/organ/internal/brain/robotic/positronic{@OLD} + +# Energy blades +/obj/item/energy/@SUBTYPES : /obj/item/energy_blade/@SUBTYPES{@OLD} + +# Medals and other accessories; see 3902_ties.txt for further migrations +/obj/item/clothing/accessory/medal/bronze_heart : /obj/item/clothing/accessory/medal/nanotrasen/bronze{@OLD} +/obj/item/clothing/accessory/medal/nobel_science : /obj/item/clothing/medal/nanotrasen/silver{@OLD} +/obj/item/clothing/accessory/scarf/white : /obj/item/clothing/accessory/scarf{@OLD} +/obj/item/clothing/accessory/storage/webbing : /obj/item/clothing/accessory/webbing/vest + +# MATERIALS +/obj/item/stack/material/plastic : /obj/item/stack/material/panel/mapped/plastic{@OLD} +/obj/item/stack/material/sandstone : /obj/item/stack/material/brick/mapped/sandstone{@OLD} +/obj/item/stack/material/mhydrogen : /obj/item/stack/material/segment/mapped/mhydrogen{@OLD} +/obj/item/stack/material/diamond : /obj/item/stack/material/gemstone/mapped/diamond{@OLD} +/obj/item/stack/material/wood : /obj/item/stack/material/plank/mapped/wood{@OLD} +/obj/item/stack/material/steel : /obj/item/stack/material/sheet/mapped/steel{@OLD} +/obj/item/stack/material/glass : /obj/item/stack/material/pane/mapped/glass{@OLD} +/obj/item/stack/material/phoron : /obj/item/stack/material/crystal/mapped/phoron{@OLD} +/obj/item/stack/material/algae : /obj/item/stack/material/puck/mapped/algae{@OLD} +/obj/item/stack/material/gold : /obj/item/stack/material/ingot/mapped/gold{@OLD} +/obj/item/stack/material/plasteel : /obj/item/stack/material/reinforced/mapped/plasteel{@OLD} +/obj/item/stack/material/glass/reinforced : /obj/item/stack/material/pane/mapped/rglass{@OLD} +/obj/item/stack/material/glass/phoronglass : /obj/item/stack/material/pane/mapped/borosilicate{@OLD} +/obj/item/stack/material/glass/phoronrglass : /obj/item/stack/material/pane/mapped/rborosilicate{@OLD} +/obj/item/stack/rods : /obj/item/stack/material/rods{@OLD} +/obj/item/packageWrap{amount = @UNSET} : /obj/item/stack/package_wrap/twenty_five{@OLD; amount = @SKIP} +/obj/item/packageWrap : /obj/item/stack/package_wrap{@OLD} +/obj/item/wrapping_paper{amount = @UNSET} : /obj/item/stack/package_wrap/gift/twenty_five{@OLD; amount = @SKIP} +/obj/item/wrapping_paper : /obj/item/stack/package_wrap{@OLD} + +/obj/structure/dispenser{phorontanks = 0} : /obj/structure/tank_rack/oxygen{@OLD; phorontanks = @SKIP} +/obj/structure/dispenser/oxygen{oxygentanks = 0} : /obj/structure/tank_rack/empty{@OLD; oxygentanks = @SKIP} +/obj/structure/dispenser/oxygen : /obj/structure/tank_rack/oxygen +/obj/structure/dispenser : /obj/structure/tank_rack + +# TELECOMMS REMOVAL +/obj/item/stock_parts/circuitboard/telecomms/@SUBTYPES : @DELETE +/obj/machinery/telecomms/@SUBTYPES : @DELETE +/obj/machinery/computer/telecomms/@SUBTYPES : @DELETE + +/obj/machinery/r_n_d/server/@SUBTYPES : /obj/machinery/design_database +/obj/machinery/r_n_d/destructive_analyzer : /obj/machinery/destructive_analyzer + +# SMES bullshit +/obj/machinery/power/smes/buildable/engine : /obj/machinery/power/smes/buildable/preset{_fully_charged = 1; _input_maxed = 1; _input_on = 1; _output_maxed = 1; _output_on = 1; uncreated_component_parts = list(/obj/item/stock_parts/smes_coil = 1)} +/obj/machinery/power/smes/buildable/main : /obj/machinery/power/smes/buildable/preset{_fully_charged = 1; _input_maxed = 1; _input_on = 1; _output_maxed = 1; _output_on = 1; uncreated_component_parts = list(/obj/item/stock_parts/smes_coil = 4)} +/obj/machinery/power/smes/buildable/point_of_interest : /obj/machinery/power/smes/buildable/preset/hidden + +/obj/item/surgical/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} +/obj/item/FixOVein : /obj/item/sutures{@OLD} + +/obj/structure/flora/skeleton : /obj/structure/skele_stand{@OLD} + +/obj/mecha/working/ripley/firefighter : /mob/living/exosuit/premade/firefighter +/obj/mecha/working/ripley/mining : /mob/living/exosuit/premade/powerloader + +/obj/structure/AIcore/@SUBTYPES : /obj/structure/aicore/@SUBTYPES +/obj/item/tank/vox : /obj/item/tank/nitrogen{@OLD} + +/obj/machinery/shuttle_sensor : /obj/machinery/airlock_sensor/shuttle{@OLD} + +/obj/machinery/computer/rdconsole/@SUBTYPES : /obj/machinery/computer/design_console{@OLD} +/obj/machinery/computer/rdservercontrol : /obj/machinery/computer/design_console{@OLD; name = @SKIP; badmin = @SKIP} +/obj/item/stock_parts/circuitboard/rdconsole : /obj/item/stock_parts/circuitboard/design_console{@OLD} +/obj/item/stock_parts/circuitboard/rdserver : /obj/item/stock_parts/circuitboard/design_database{@OLD} + +/obj/machinery/account_database : /obj/machinery/computer/account_database{@OLD} +/obj/machinery/shield_gen/@SUBTYPES : /obj/machinery/shield_generator + +/obj/structure/morgue/crematorium : /obj/structure/crematorium{@OLD} + +/obj/item/robot_parts/frame : /obj/item/robot_parts/robot_suit{@OLD} + +/obj/structure/closet/secure_closet/psych : /obj/structure/closet/secure_closet/psychiatry{@OLD} +/obj/structure/closet/firecloset/full : /obj/structure/closet/firecloset{@OLD} +/obj/structure/closet/firecloset/full/double : /obj/structure/closet/firecloset/chief{@OLD} +/obj/structure/closet/l3closet/scientist/double : /obj/structure/closet/l3closet/scientist/multi{@OLD} +/obj/structure/closet/secure_closet/hos2 : /obj/structure/closet/secure_closet/hos{@OLD} +/obj/structure/closet/secure_closet/medical_wall/synth_anesthetics : /obj/structure/closet/secure_closet/medical_wall/anesthetics/robotics{@OLD} +/obj/structure/closet/secure_closet/medical2 : /obj/structure/closet/secure_closet/anesthetics{@OLD} +/obj/structure/closet/walllocker/emerglocker/@SUBTYPES : /obj/structure/emergency_dispenser/@SUBTYPES{@OLD} + +/obj/item/firstaid_arm_assembly : /obj/item/firstaid/empty, /obj/item/robot_parts/l_arm +/obj/item/bucket_sensor : /obj/item/chems/glass/bucket, /obj/item/assembly/prox_sensor +/obj/item/broken_device : @DELETE + +/obj/item/spacecash/@SUBTYPES : /obj/item/cash/@SUBTYPES{@OLD} + +/obj/item/kit/paint/ripley : /obj/item/kit/paint/camouflage +/obj/item/kit/paint/ripley/death : /obj/item/kit/paint/camouflage/forest +/obj/item/kit/paint/ripley/flames_blue : /obj/item/kit/paint/flames_blue +/obj/item/kit/paint/ripley/flames_red : /obj/item/kit/paint/flames_red + +/obj/machinery/photocopier/faxmachine : /obj/machinery/faxmachine{@OLD; init_network_tag = @OLD:department; department = @SKIP} +/obj/item/tvcamera : /obj/item/camera/tvcamera{@OLD} +/obj/machinery/station_map : /obj/machinery/holomap{@OLD} + +/obj/item/ducttape : /obj/item/duct_tape{@OLD} +/obj/item/toy/katana : /obj/item/sword/katana/toy{@OLD} +/obj/item/toy/cultsword : /obj/item/sword/cult_toy{@OLD} +/obj/item/toy/sword : /obj/item/energy_blade/sword/toy{@OLD} +/obj/item/lipstick/jade : /obj/item/cosmetics/lipstick/green{@OLD} +/obj/item/rig_module/device/plasmacutter : /obj/item/rig_module/mounted/plasmacutter{@OLD} +/obj/item/storage/box/syndie_kit/ewar_voice : /obj/item/backpack/satchel/syndie_kit/ewar_voice +/obj/item/tray : /obj/item/plate/tray{@OLD} +/obj/item/weldingtool/weldpack : /obj/item/chems/weldpack{@OLD} +/obj/machinery/crystal : /obj/structure/crystal{@OLD} +/obj/item/organ/internal/stack : /obj/item/organ/internal/voxstack{@OLD} +/obj/item/radio_jammer : /obj/item/suit_sensor_jammer + +# AMMO BOXES +/obj/item/storage/box/beanbags/@SUBTYPES : /obj/item/box/ammo/beanbags/@SUBTYPES{@OLD} +/obj/item/storage/box/stunshells/@SUBTYPES : /obj/item/box/ammo/stunshells/@SUBTYPES{@OLD} +/obj/item/storage/box/blanks/@SUBTYPES : /obj/item/box/ammo/blanks/@SUBTYPES{@OLD} +/obj/item/storage/box/empshells/@SUBTYPES : /obj/item/box/ammo/empshells/@SUBTYPES{@OLD} +/obj/item/storage/box/flashshells/@SUBTYPES : /obj/item/box/ammo/flashshells/@SUBTYPES{@OLD} +/obj/item/storage/box/shotgunammo/@SUBTYPES : /obj/item/box/ammo/shotgunammo/@SUBTYPES{@OLD} +/obj/item/storage/box/shotgunshells/@SUBTYPES : /obj/item/box/ammo/shotgunshells/@SUBTYPES{@OLD} +/obj/item/storage/box/sniperammo/@SUBTYPES : /obj/item/box/ammo/sniperammo/@SUBTYPES{@OLD} +/obj/item/storage/box/stunshells/@SUBTYPES : /obj/item/box/ammo/stunshells/@SUBTYPES{@OLD} + +/obj/item/extinguisher/@SUBTYPES : /obj/item/chems/spray/extinguisher/@SUBTYPES{@OLD} +/obj/item/camera_assembly : /obj/item/frame/camera/kit +/obj/structure/ladder/up : /obj/structure/ladder +/obj/random/mob/mouse : /obj/random/mouse + +/obj/structure/closet/grave/dirthole : /obj/structure/pit{@OLD} +/obj/structure/closet/grave/@SUBTYPES : /obj/structure/pit/closed/grave{@OLD} + +/obj/item/banner/nt : /obj/item/banner/nanotrasen{@OLD} + +/obj/item/box/syndie_kit/clerical : /obj/item/backpack/satchel/syndie_kit/clerical{@OLD} + +/obj/item/clothing/under/costume/rainbow : /obj/item/clothing/jumpsuit/rainbow{@OLD} +/obj/item/clothing/under/dress/dress_orange : /obj/item/clothing/dress/orange{@OLD} +/obj/item/clothing/head/collectable/xenos : /obj/item/clothing/head/xenos{@OLD} +/obj/item/clothing/head/collectable/bearpelt : /obj/item/clothing/head/bearpelt{@OLD} +/obj/item/clothing/head/collectable/philosopher_wig : /obj/item/clothing/head/philosopher_wig{@OLD} +/obj/item/clothing/head/collectable/plaguedoctorhat : /obj/item/clothing/head/plaguedoctorhat{@OLD} +/obj/item/clothing/head/helmet/space/void/security/riot : /obj/item/clothing/head/helmet/space/void/security/alt{@OLD} +/obj/item/clothing/suit/space/void/security/riot : /obj/item/clothing/suit/space/void/security/alt{@OLD} +/obj/item/clothing/head/helmet/space/vox/pressure : /obj/item/clothing/head/helmet/space/vox{@OLD} +/obj/item/clothing/under/vox/vox_utility : /obj/item/clothing/pants/vox{@OLD} +/obj/item/clothing/suit/space/pirate : /obj/item/clothing/suit/pirate{@OLD} +/obj/item/clothing/suit/costume : /obj/item/clothing/suit/pirate{@OLD} +/obj/item/clothing/suit/costume/hgpirate : /obj/item/clothing/suit/hgpirate{@OLD} +/obj/item/clothing/suit/storage/vest/heavy/merc : /obj/item/clothing/suit/armor/pcarrier/merc{@OLD} +/obj/item/clothing/suit/storage/vest/@SUBTYPES : /obj/item/clothing/suit/armor/vest/@SUBTYPES{@OLD} + +# Migrate/delete old mech parts +/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster : @DELETE +/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster : @DELETE +/obj/item/mecha_parts/mecha_equipment/repair_droid : @DELETE +/obj/item/mecha_parts/mecha_equipment/teleporter : @DELETE +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay : @DELETE +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer : @DELETE +/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill : /obj/item/mech_equipment/drill/diamond{@OLD} +/obj/item/mecha_parts/mecha_equipment/tool/extinguisher : /obj/item/mech_equipment/mounted_system/extinguisher{@OLD} +/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp : /obj/item/mech_equipment/clamp{@OLD} +/obj/item/mecha_parts/mecha_equipment/tool/passenger : @DELETE +/obj/item/mecha_parts/mecha_equipment/tool/rcd : /obj/item/mech_equipment/mounted_system/rcd{@OLD} +/obj/item/mecha_parts/mecha_equipment/tool/sleeper : /obj/item/mech_equipment/sleeper{@OLD} +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun : @DELETE +/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion : /obj/item/mech_equipment/mounted_system/taser/ion{@OLD} +/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser : /obj/item/mech_equipment/mounted_system/taser{@OLD} +/obj/item/mecha_parts/mecha_tracking : @DELETE + +############ +# VAREDITS # +############ +# Atmos varedits +/obj/machinery/computer/air_control/@SUBTYPES{sensors = @SET} : /obj/machinery/computer/air_control/@SUBTYPES{@OLD; sensors = @SKIP} +# move these to the external air subtype so frequencies work +/obj/machinery/atmospherics/unary/vent_pump/high_volume{frequency = 1379} : /obj/machinery/atmospherics/unary/vent_pump/high_volume/external_air{@OLD; frequency = @SKIP} +/obj/machinery/portable_atmospherics/powered/scrubber/@SUBTYPES{scrub_id = @SET} : /obj/machinery/portable_atmospherics/powered/scrubber/@SUBTYPES{@OLD; scrub_id = @SKIP; id_tag = @OLD:scrub_id} +/obj/machinery/portable_atmospherics/powered/scrubber/@SUBTYPES{scrubbing_gas = list("phoron")} : /obj/machinery/portable_atmospherics/powered/scrubber/@SUBTYPES{@OLD; scrubbing_gas = list(/decl/material/solid/phoron)} +/obj/machinery/computer/area_atmos/tag/@SUBTYPES{scrub_id = @SET} : /obj/machinery/computer/area_atmos/tag/@SUBTYPES{@OLD; scrub_id = @SKIP; id_tag = @OLD:scrub_id} +# for the rest of this, frequency was moved to component presets and i'm too lazy to set that up +/obj/machinery/door/airlock/@SUBTYPES{frequency = @SET} : /obj/machinery/door/airlock/@SUBTYPES{@OLD; frequency = @SKIP} +/obj/machinery/portable_atmospherics/@SUBTYPES{frequency = @SET} : /obj/machinery/portable_atmospherics/@SUBTYPES{@OLD; frequency = @SKIP} +/obj/machinery/atmospherics/@SUBTYPES{frequency = @SET} : /obj/machinery/atmospherics/@SUBTYPES{@OLD; frequency = @SKIP} +/obj/machinery/airlock_sensor/@SUBTYPES{frequency = @SET} : /obj/machinery/airlock_sensor/@SUBTYPES{@OLD; frequency = @SKIP} +/obj/machinery/air_sensor/@SUBTYPES : /obj/machinery/air_sensor/@SUBTYPES{@OLD; frequency = @SKIP; output = @SKIP} +/obj/machinery/embedded_controller/radio/@SUBTYPES{frequency = @SET} : /obj/machinery/embedded_controller/radio/@SUBTYPES{@OLD; frequency = @SKIP} +/obj/machinery/button/@SUBTYPES{frequency = @SET} : /obj/machinery/button/@SUBTYPES{@OLD; frequency = @SKIP} +/obj/machinery/meter/@SUBTYPES{frequency = @SET} : /obj/machinery/portable_atmospherics/powered/scrubber/@SUBTYPES{@OLD; frequency = @SKIP} + +# id -> id_tag +/obj/machinery/door_timer/@SUBTYPES{id = @SET} : /obj/machinery/door_timer/@SUBTYPES{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/conveyor/@SUBTYPES{id = @SET} : /obj/machinery/conveyor/@SUBTYPES{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/conveyor_switch/@SUBTYPES{id = @SET} : /obj/machinery/conveyor_switch/@SUBTYPES{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/door/@SUBTYPES{id = @SET} : /obj/machinery/door/@SUBTYPES{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/button/@SUBTYPES{id = @SET} : /obj/machinery/button/@SUBTYPES{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/atmospherics/@SUBTYPES{id = @SET} : /obj/machinery/atmospherics/@SUBTYPES{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/holosign/bar{id = @SET} : /obj/machinery/holosign/bar{@OLD; id_tag = @OLD:id; id = @SKIP} +/obj/machinery/meter/@SUBTYPES{id = @SET} : /obj/machinery/meter/@SUBTYPES{@OLD; id = @SKIP; id_tag = @OLD:id} +/obj/machinery/flasher/@SUBTYPES{id = @SET} : /obj/machinery/flasher/@SUBTYPES{@OLD; id = @SKIP; id_tag = @OLD:id} +/obj/machinery/sparker/@SUBTYPES{id = @SET} : /obj/machinery/sparker/@SUBTYPES{@OLD; id = @SKIP; id_tag = @OLD:id} +/obj/machinery/mass_driver/@SUBTYPES{id = @SET} : /obj/machinery/mass_driver/@SUBTYPES{@OLD; id = @SKIP; id_tag = @OLD:id} +/obj/machinery/emitter/@SUBTYPES{id = @SET} : /obj/machinery/emitter/@SUBTYPES{@OLD; id = @SKIP; id_tag = @OLD:id} + +# Camera preset_channels -> network +/obj/machinery/camera/network/@SUBTYPES{network = @SET} : /obj/machinery/camera/network/@SUBTYPES{@OLD; network = @SKIP; preset_channels = @OLD:network} + +# Remove button/sensor master_tag +/obj/machinery/airlock_sensor/@SUBTYPES{master_tag = @SET} : /obj/machinery/airlock_sensor/@SUBTYPES{@OLD; master_tag = @SKIP} +/obj/machinery/button/access/@SUBTYPES{master_tag = @SET} : /obj/machinery/button/access/@SUBTYPES{@OLD; master_tag = @SKIP} + +# Skip power sensor name_tag +/obj/machinery/power/sensor{name_tag = @SET} : /obj/machinery/power/sensor{@OLD; name_tag = @SKIP} + +# join_group -> unique_merge_identifier +/turf/wall/shuttle/@SUBTYPES{join_group = @SET} : /turf/wall/shuttle/@SUBTYPES{@OLD; unique_merge_identifier = @OLD:join_group} + +# Remove set icon states/density on windows, doors, shutters +/obj/machinery/door/blast/regular{icon_state = @SET} : /obj/machinery/door/blast/regular{@OLD; icon_state = @SKIP} +/obj/structure/window/borosilicate_reinforced/@SUBTYPES{icon_state = @SET} : /obj/structure/window/borosilicate_reinforced/@SUBTYPES{@OLD; icon_state = @SKIP} +/obj/machinery/door/blast/regular{p_open = 1} : /obj/machinery/door/blast/regular/open{@OLD; p_open = @SKIP} +/obj/machinery/door/blast/regular{p_open = 0} : /obj/machinery/door/blast/regular{@OLD; p_open = @SKIP} +/obj/machinery/door/blast/regular{density = 0} : /obj/machinery/door/blast/regular/open{@OLD; density = @SKIP; opacity = @SKIP} +/obj/structure/window/@SUBTYPES{icon_state = "fwindow"} : /obj/structure/window/@SUBTYPES{@OLD; icon_state = @SKIP} +/obj/structure/window/reinforced/reinforced/polarized/full{dir = 10} : /obj/structure/window/reinforced/polarized/full{@OLD; dir = @SKIP} +/obj/structure/window/reinforced/reinforced/polarized/full{dir = 10} : /obj/structure/window/reinforced/polarized/full{@OLD; dir = @SKIP} + +# Prices -> markup +/obj/machinery/vending/@SUBTYPES{prices = list()} : /obj/machinery/vending/@SUBTYPES{@OLD; markup = 0; prices=@SKIP} +/obj/machinery/vending/@SUBTYPES{prices = @SET} : /obj/machinery/vending/@SUBTYPES{@OLD; prices = @SKIP} + +# Radio varedits +/obj/item/radio/@SUBTYPES{subspace_transmission = @SET} : @OLD {@OLD; subspace_transmission = @SKIP} +/obj/item/radio/@SUBTYPES{syndie = @SET} : @OLD {@OLD; decrypt_all_messages = 1; syndie = @SKIP} +/obj/item/radio/@SUBTYPES{adhoc_fallback = @SET} : @OLD {@OLD; can_use_analog = @SKIP} + +# Empty first-aid kits +/obj/item/storage/firstaid/regular{empty = 1} : /obj/item/firstaid/empty{@OLD; empty = @SKIP; name = @SKIP} + +/obj/machinery/floor_light/prebuilt{on = 1} : /obj/machinery/floor_light/prebuilt{@OLD; use_power = 2; on = @SKIP} + +/obj/structure/disposalpipe/sortjunction/@SUBTYPES{sortType = @SET} : /obj/structure/disposalpipe/sortjunction/@SUBTYPES{@OLD; sort_type = @OLD:sortType; sortType = @SKIP} diff --git a/tools/map_migrations/3191_cosmetics.txt b/tools/map_migrations/3191_cosmetics.txt new file mode 100644 index 000000000000..05995a874c88 --- /dev/null +++ b/tools/map_migrations/3191_cosmetics.txt @@ -0,0 +1 @@ +/obj/item/lipstick/@SUBTYPES : /obj/item/cosmetics/lipstick/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3316_balls.txt b/tools/map_migrations/3316_balls.txt new file mode 100644 index 000000000000..2cbf556053ca --- /dev/null +++ b/tools/map_migrations/3316_balls.txt @@ -0,0 +1,3 @@ +/obj/item/beach_ball/holoball : /obj/item/ball/basketball +/obj/item/beach_ball : /obj/item/ball +/obj/item/beach_ball/holovolleyball : /obj/item/ball/volleyball \ No newline at end of file diff --git a/tools/map_migrations/3348_broken_floors.txt b/tools/map_migrations/3348_broken_floors.txt new file mode 100644 index 000000000000..80cb272b4ec2 --- /dev/null +++ b/tools/map_migrations/3348_broken_floors.txt @@ -0,0 +1,7 @@ +/turf/floor/tiled/@SUBTYPES{icon_state="steel_broken0"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_breaker +/turf/floor/tiled/@SUBTYPES{icon_state="steel_broken1"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_breaker +/turf/floor/tiled/@SUBTYPES{icon_state="steel_broken2"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_breaker +/turf/floor/tiled/@SUBTYPES{icon_state="steel_broken3"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_breaker +/turf/floor/tiled/@SUBTYPES{icon_state="steel_broken4"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_breaker +/turf/floor/tiled/@SUBTYPES{icon_state="steel_burned0"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_burner +/turf/floor/tiled/@SUBTYPES{icon_state="steel_burned1"} : /turf/floor/tiled/@SUBTYPES{icon_state=@SKIP;@OLD}, /obj/abstract/landmark/proc_caller/floor_burner \ No newline at end of file diff --git a/tools/map_migrations/3558_lowercase_closets.txt b/tools/map_migrations/3558_lowercase_closets.txt new file mode 100644 index 000000000000..85ffc1aabd0b --- /dev/null +++ b/tools/map_migrations/3558_lowercase_closets.txt @@ -0,0 +1,2 @@ +/obj/structure/closet/secure_closet/CMO : /obj/structure/closet/secure_closet/cmo{@OLD} +/obj/structure/closet/secure_closet/RD : /obj/structure/closet/secure_closet/research_director{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3560_central_atmos_computer.txt b/tools/map_migrations/3560_central_atmos_computer.txt new file mode 100644 index 000000000000..71179dbe7121 --- /dev/null +++ b/tools/map_migrations/3560_central_atmos_computer.txt @@ -0,0 +1,2 @@ +/obj/machinery/computer/atmoscontrol/@SUBTYPES : /obj/machinery/computer/central_atmos/@SUBTYPES{@OLD} +/obj/item/stock_parts/circuitboard/atmoscontrol : /obj/item/stock_parts/circuitboard/central_atmos{@OLD} diff --git a/tools/map_migrations/3576_wallobj_migration.txt b/tools/map_migrations/3576_wallobj_migration.txt new file mode 100644 index 000000000000..1f381b8483fb --- /dev/null +++ b/tools/map_migrations/3576_wallobj_migration.txt @@ -0,0 +1,33 @@ +# FIX WALLOBJ FACING DIRS +/obj/item/radio/intercom/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD {@OLD;pixel_x=-22;dir=4} +/obj/item/radio/intercom/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD {@OLD;pixel_x=22;dir=8} +/obj/item/radio/intercom/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD {@OLD;pixel_y=-30;dir=1} +/obj/item/radio/intercom/@SUBTYPES {pixel_x=@UNSET;pixel_y=@POSITIVE} : @OLD {@OLD;pixel_y=20;dir=@SKIP} +/obj/structure/extinguisher_cabinet {pixel_x=@POSITIVE;pixel_y=@UNSET} : @OLD {@OLD;pixel_x=29;dir=8} +/obj/structure/extinguisher_cabinet {pixel_x=@NEGATIVE;pixel_y=@UNSET} : @OLD {@OLD;pixel_x=-29;dir=4} +/obj/structure/extinguisher_cabinet {pixel_y=@POSITIVE;pixel_x=@UNSET} : @OLD {@OLD;pixel_y=29;dir=@SKIP} +/obj/structure/extinguisher_cabinet {pixel_y=@NEGATIVE;pixel_x=@UNSET} : @OLD {@OLD;pixel_y=-29;dir=1} +/obj/machinery/button/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=8} +/obj/machinery/button/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=4} +/obj/machinery/button/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} +/obj/machinery/status_display/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=8} +/obj/machinery/status_display/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=4} +/obj/machinery/status_display/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} +/obj/machinery/newscaster/@SUBTYPES {pixel_x=@NEGATIVE;pixel_y=@UNSET} : @OLD{@OLD;dir=8} +/obj/machinery/newscaster/@SUBTYPES {pixel_x=@POSITIVE;pixel_y=@UNSET} : @OLD{@OLD;dir=4} +/obj/machinery/newscaster/@SUBTYPES {pixel_y=@NEGATIVE;pixel_x=@UNSET} : @OLD{@OLD;dir=1} +/obj/structure/closet/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=8} +/obj/structure/closet/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=4} +/obj/structure/closet/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} +/obj/machinery/recharger/wallcharger/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=8} +/obj/machinery/recharger/wallcharger/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=4} +/obj/machinery/recharger/wallcharger/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} +/obj/machinery/embedded_controller/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=8} +/obj/machinery/embedded_controller/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=4} +/obj/machinery/embedded_controller/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} +/obj/machinery/airlock_sensor/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=8} +/obj/machinery/airlock_sensor/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=4} +/obj/machinery/airlock_sensor/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} +/obj/machinery/light_switch/@SUBTYPES {pixel_y=@UNSET;pixel_x=@POSITIVE} : @OLD{@OLD;dir=8} +/obj/machinery/light_switch/@SUBTYPES {pixel_y=@UNSET;pixel_x=@NEGATIVE} : @OLD{@OLD;dir=4} +/obj/machinery/light_switch/@SUBTYPES {pixel_x=@UNSET;pixel_y=@NEGATIVE} : @OLD{@OLD;dir=1} \ No newline at end of file diff --git a/tools/map_migrations/3601_fancy_box.txt b/tools/map_migrations/3601_fancy_box.txt new file mode 100644 index 000000000000..36f3d0a74313 --- /dev/null +++ b/tools/map_migrations/3601_fancy_box.txt @@ -0,0 +1,8 @@ +# REPATH /fancy to /box/fancy +/obj/item/storage/fancy/@SUBTYPES : /obj/item/storage/box/fancy/@SUBTYPES{@OLD} +/obj/item/storage/box/donut/@SUBTYPES : /obj/item/storage/box/fancy/donut/@SUBTYPES{@OLD +# REPATH PIZZA SLICES +/obj/item/chems/food/slice/vegetablepizza/@SUBTYPES : /obj/item/chems/food/slice/pizza/vegetable/@SUBTYPES{@OLD} +/obj/item/chems/food/slice/meatpizza/@SUBTYPES : /obj/item/chems/food/slice/pizza/meat/@SUBTYPES{@OLD} +/obj/item/chems/food/slice/margherita/@SUBTYPES : /obj/item/chems/food/slice/pizza/margherita/@SUBTYPES{@OLD} +/obj/item/chems/food/slice/mushroompizza/@SUBTYPES : /obj/item/chems/food/slice/pizza/mushroom/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3634_openspace_merge.txt b/tools/map_migrations/3634_openspace_merge.txt new file mode 100644 index 000000000000..337671708f7c --- /dev/null +++ b/tools/map_migrations/3634_openspace_merge.txt @@ -0,0 +1,2 @@ +/turf/simulated/open/@SUBTYPES : /turf/open/@SUBTYPES{@OLD} +/turf/exterior/open/@SUBTYPES : /turf/open/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3670_stonewalls.txt b/tools/map_migrations/3670_stonewalls.txt new file mode 100644 index 000000000000..a9abf2f21431 --- /dev/null +++ b/tools/map_migrations/3670_stonewalls.txt @@ -0,0 +1,2 @@ +/turf/simulated/wall/sandstone/@SUBTYPES : /turf/simulated/wall/brick/sandstone/@SUBTYPES{@OLD} +/turf/simulated/wall/sandstonediamond/@SUBTYPES : /turf/simulated/wall/brick/sandstonediamond/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3681_plates.txt b/tools/map_migrations/3681_plates.txt new file mode 100644 index 000000000000..c339d5d1e5af --- /dev/null +++ b/tools/map_migrations/3681_plates.txt @@ -0,0 +1,3 @@ +# REPATH /trash/plate to /plate +/obj/item/trash/plate/@SUBTYPES : /obj/item/plate/@SUBTYPES{@OLD} +/obj/item/trash/tray/@SUBTYPES : /obj/item/plate/tray/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3682_carbon_alien.txt b/tools/map_migrations/3682_carbon_alien.txt new file mode 100644 index 000000000000..c74ad39203ba --- /dev/null +++ b/tools/map_migrations/3682_carbon_alien.txt @@ -0,0 +1 @@ +/mob/living/carbon/alien/@SUBTYPES : /mob/living/simple_animal/alien/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3688_utensil.txt b/tools/map_migrations/3688_utensil.txt new file mode 100644 index 000000000000..ef09cf03e779 --- /dev/null +++ b/tools/map_migrations/3688_utensil.txt @@ -0,0 +1,3 @@ +/obj/item/kitchen/utensil/@SUBTYPES : /obj/item/utensil/@SUBTYPES{@OLD} +/obj/item/knife/table/primitive/@SUBTYPES : /obj/item/knife/primitive/@SUBTYPES{@OLD} +/obj/item/knife/table/@SUBTYPES : /obj/item/utensil/knife/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3710_fluid_landmarks.txt b/tools/map_migrations/3710_fluid_landmarks.txt new file mode 100644 index 000000000000..52d2f4a3ae4d --- /dev/null +++ b/tools/map_migrations/3710_fluid_landmarks.txt @@ -0,0 +1,2 @@ +# REPATH /obj/abstract/fluid_mapped TO /obj/abstract/landmark/mapped_fluid +/obj/abstract/fluid_mapped/@SUBTYPES : /obj/abstract/landmark/mapped_fluid/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3716_storage.txt b/tools/map_migrations/3716_storage.txt new file mode 100644 index 000000000000..24300c9b30f5 --- /dev/null +++ b/tools/map_migrations/3716_storage.txt @@ -0,0 +1,5 @@ +/obj/item/storage/mech/@SUBTYPES : /obj/item/mech_storage/@SUBTYPES{@OLD} +/obj/item/storage/secure/@SUBTYPES : /obj/item/secure_storage/@SUBTYPES{@OLD} +/obj/item/storage/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} +/obj/item/clothing/suit/storage/@SUBTYPES : /obj/item/clothing/suit/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/storage/@SUBTYPES : /obj/item/clothing/accessory/webbing/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3724_grooming.txt b/tools/map_migrations/3724_grooming.txt new file mode 100644 index 000000000000..1050c12fa9ae --- /dev/null +++ b/tools/map_migrations/3724_grooming.txt @@ -0,0 +1,3 @@ +/obj/item/haircomb/random/@SUBTYPES : /obj/item/grooming/comb/colorable/random/@SUBTYPES{@OLD} +/obj/item/haircomb/brush/@SUBTYPES : /obj/item/grooming/brush/colorable/random/@SUBTYPES{@OLD} +/obj/item/haircomb/@SUBTYPES : /obj/item/grooming/comb/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3739_asteroid_turfs.txt b/tools/map_migrations/3739_asteroid_turfs.txt new file mode 100644 index 000000000000..b07509f8728e --- /dev/null +++ b/tools/map_migrations/3739_asteroid_turfs.txt @@ -0,0 +1,9 @@ +/turf/simulated/floor/airless/lava/@SUBTYPES : /turf/exterior/lava/@SUBTYPES{@OLD} +/turf/simulated/floor/ice/@SUBTYPES : /turf/exterior/ice/@SUBTYPES{@OLD} +/turf/simulated/floor/snow/@SUBTYPES : /turf/exterior/snow/@SUBTYPES{@OLD} +/turf/simulated/floor/airless/ceiling/@SUBTYPES : /turf/simulated/floor/airless/@SUBTYPES{@OLD} +/turf/simulated/floor/beach/sand/@SUBTYPES : /turf/exterior/sand/@SUBTYPES{@OLD} +/turf/simulated/floor/beach/sand/desert/@SUBTYPES : /turf/exterior/sand/@SUBTYPES{@OLD} +/turf/simulated/floor/beach/coastline/@SUBTYPES : /turf/exterior/water/@SUBTYPES{@OLD} +/turf/simulated/floor/beach/water/@SUBTYPES : /turf/exterior/water/@SUBTYPES{@OLD} +/turf/simulated/floor/beach/water/ocean/@SUBTYPES : /turf/exterior/water/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3745_exterior_water.txt b/tools/map_migrations/3745_exterior_water.txt new file mode 100644 index 000000000000..b5bdac438f2a --- /dev/null +++ b/tools/map_migrations/3745_exterior_water.txt @@ -0,0 +1,4 @@ +/turf/exterior/water/chlorine/@SUBTYPES : /turf/exterior/chlorine_sand/marsh/@SUBTYPES{@OLD} +/turf/exterior/water/tar/@SUBTYPES : /turf/exterior/shrouded/tar/@SUBTYPES{@OLD} +/turf/exterior/water/stomach/@SUBTYPES : /turf/exterior/meat/acid/@SUBTYPES{@OLD} +/turf/exterior/water/@SUBTYPES : /turf/exterior/sand/water/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3754_crafting_recipes.txt b/tools/map_migrations/3754_crafting_recipes.txt new file mode 100644 index 000000000000..cf27ac035a22 --- /dev/null +++ b/tools/map_migrations/3754_crafting_recipes.txt @@ -0,0 +1,4 @@ +/obj/item/stack/material/shiny/@SUBTYPES : /obj/item/stack/material/sheet/shiny/@SUBTYPES{@OLD} +/obj/item/stack/material/reinforced/@SUBTYPES : /obj/item/stack/material/sheet/reinforced/@SUBTYPES{@OLD} +/obj/structure/plasticflaps/@SUBTYPES : /obj/structure/flaps/@SUBTYPES{@OLD} +/obj/item/storage/bag/plastic/@SUBTYPES : /obj/item/storage/bag/flimsy/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3763_pickaxe_hammer.txt b/tools/map_migrations/3763_pickaxe_hammer.txt new file mode 100644 index 000000000000..7085460837d3 --- /dev/null +++ b/tools/map_migrations/3763_pickaxe_hammer.txt @@ -0,0 +1,12 @@ +/obj/item/pickaxe/silver/@SUBTYPES : /obj/item/tool/pickaxe/titanium/@SUBTYPES{@OLD} +/obj/item/pickaxe/borgdrill/@SUBTYPES : /obj/item/tool/drill/advanced/@SUBTYPES{@OLD} +/obj/item/pickaxe/gold/@SUBTYPES : /obj/item/tool/pickaxe/plasteel/@SUBTYPES{@OLD} +/obj/item/pickaxe/jackhammer/@SUBTYPES : /obj/item/tool/hammer/jack/@SUBTYPES{@OLD} +/obj/item/pickaxe/drill/@SUBTYPES : /obj/item/tool/drill/@SUBTYPES{@OLD} +/obj/item/pickaxe/diamond/@SUBTYPES : /obj/item/tool/pickaxe/ocp/@SUBTYPES{@OLD} +/obj/item/pickaxe/diamonddrill/@SUBTYPES : /obj/item/tool/drill/diamond/@SUBTYPES{@OLD} +/obj/item/shovel/spade/@SUBTYPES : /obj/item/tool/spade/@SUBTYPES{@OLD} +/obj/item/shovel/@SUBTYPES : /obj/item/tool/shovel/@SUBTYPES{@OLD} +/obj/item/power_drill/@SUBTYPES : /obj/item/power_drill/@SUBTYPES{@OLD} +/obj/item/hydraulic_cutter/@SUBTYPES : /obj/item/tool/hydraulic_cutter/@SUBTYPES{@OLD} +/obj/item/pickaxe/@SUBTYPES : /obj/item/tool/pickaxe/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3764_drying_grilling.txt b/tools/map_migrations/3764_drying_grilling.txt new file mode 100644 index 000000000000..fcfbbba33bb2 --- /dev/null +++ b/tools/map_migrations/3764_drying_grilling.txt @@ -0,0 +1 @@ +/obj/machinery/smartfridge/drying_rack/@SUBTYPES : /obj/machinery/smartfridge/drying_oven/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3764_kitchenspike.txt b/tools/map_migrations/3764_kitchenspike.txt new file mode 100644 index 000000000000..9396cc3d2663 --- /dev/null +++ b/tools/map_migrations/3764_kitchenspike.txt @@ -0,0 +1 @@ +/obj/structure/kitchenspike/@SUBTYPES : /obj/structure/meat_hook/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3784_shuttle_wall.txt b/tools/map_migrations/3784_shuttle_wall.txt new file mode 100644 index 000000000000..ea86fa885a27 --- /dev/null +++ b/tools/map_migrations/3784_shuttle_wall.txt @@ -0,0 +1,2 @@ +/turf/simulated/shuttle/wall/@SUBTYPES : /turf/simulated/wall/shuttle/@SUBTYPES{@OLD} +/turf/simulated/shuttle/@SUBTYPES : /turf/simulated/wall/shuttle/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3788_paint.txt b/tools/map_migrations/3788_paint.txt new file mode 100644 index 000000000000..c85ea9350217 --- /dev/null +++ b/tools/map_migrations/3788_paint.txt @@ -0,0 +1,8 @@ +/obj/item/stack/tile/carpetblue/@SUBTYPES : /obj/item/stack/tile/carpet/blue@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetblue2/@SUBTYPES : /obj/item/stack/tile/carpet/blue2@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetblue3/@SUBTYPES : /obj/item/stack/tile/carpet/blue3@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetmagenta/@SUBTYPES : /obj/item/stack/tile/carpet/magenta@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetpurple/@SUBTYPES : /obj/item/stack/tile/carpet/purple/@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetorange/@SUBTYPES : /obj/item/stack/tile/carpet/orange/@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetgreen/@SUBTYPES : /obj/item/stack/tile/carpet/green/@SUBTYPES{@OLD} +/obj/item/stack/tile/carpetred/@SUBTYPES : /obj/item/stack/tile/carpet/red/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3790_fishing.txt b/tools/map_migrations/3790_fishing.txt new file mode 100644 index 000000000000..eb76c3d42f45 --- /dev/null +++ b/tools/map_migrations/3790_fishing.txt @@ -0,0 +1 @@ +/mob/living/simple_animal/aquatic/fish/judge/@SUBTYPES: /mob/living/simple_animal/aquatic/fish/large/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3791_remove_simulated.txt b/tools/map_migrations/3791_remove_simulated.txt new file mode 100644 index 000000000000..d45f9f28a834 --- /dev/null +++ b/tools/map_migrations/3791_remove_simulated.txt @@ -0,0 +1,2 @@ +/turf/simulated/wall/@SUBTYPES : /turf/wall/@SUBTYPES{@OLD} +/turf/simulated/floor/@SUBTYPES : /turf/floor/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3792_exterior_wall.txt b/tools/map_migrations/3792_exterior_wall.txt new file mode 100644 index 000000000000..8f7504278f8d --- /dev/null +++ b/tools/map_migrations/3792_exterior_wall.txt @@ -0,0 +1 @@ +/turf/exterior/wall/@SUBTYPES : /turf/wall/natural/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3793_exterior_floor.txt b/tools/map_migrations/3793_exterior_floor.txt new file mode 100644 index 000000000000..14a55286e60b --- /dev/null +++ b/tools/map_migrations/3793_exterior_floor.txt @@ -0,0 +1,5 @@ +/turf/exterior/floor/@SUBTYPES : /turf/floor/natural/@SUBTYPES{@OLD} +/turf/floor/grass/@SUBTYPES : /turf/floor/fake_grass/@SUBTYPES{@OLD} +/turf/floor/natural/concrete/@SUBTYPES : /turf/floor/concrete/@SUBTYPES{@OLD} +/turf/floor/natural/wildgrass/@SUBTYPES : /turf/floor/natural/grass/wild/@SUBTYPES{@OLD} +/turf/floor/natural/@SUBTYPES : /turf/floor/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3807_clothing_modifiers.txt b/tools/map_migrations/3807_clothing_modifiers.txt new file mode 100644 index 000000000000..959e300b12d2 --- /dev/null +++ b/tools/map_migrations/3807_clothing_modifiers.txt @@ -0,0 +1 @@ +/obj/item/clothing/suit/storage/toggle/hoodie/nt/@SUBTYPES : /obj/item/clothing/suit/storage/toggle/nt_hoodie/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3812_atom_init.txt b/tools/map_migrations/3812_atom_init.txt new file mode 100644 index 000000000000..f8c53c7d2ea1 --- /dev/null +++ b/tools/map_migrations/3812_atom_init.txt @@ -0,0 +1,2 @@ +/obj/machinery/computer/HolodeckControl/@SUBTYPES : /obj/machinery/computer/holodeck_control/@SUBTYPES{@OLD} +/obj/item/stock_parts/circuitboard/holodeckcontrol/@SUBTYPES : /obj/item/stock_parts/circuitboard/holodeck_control/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3824_wildgrass.txt b/tools/map_migrations/3824_wildgrass.txt new file mode 100644 index 000000000000..4fa6bd46eaf8 --- /dev/null +++ b/tools/map_migrations/3824_wildgrass.txt @@ -0,0 +1 @@ +/turf/exterior/wildgrass/@SUBTYPES : /turf/exterior/grass/wild/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3841_pilot_voidsuit.txt b/tools/map_migrations/3841_pilot_voidsuit.txt new file mode 100644 index 000000000000..23d27798a22a --- /dev/null +++ b/tools/map_migrations/3841_pilot_voidsuit.txt @@ -0,0 +1,2 @@ +/obj/item/clothing/head/helmet/space/void/pilot/@SUBTYPES : /obj/item/clothing/head/helmet/space/void/expedition/@SUBTYPES{@OLD} +/obj/item/clothing/suit/space/void/pilot/@SUBTYPES : /obj/item/clothing/suit/space/void/expedition/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3850_hoes.txt b/tools/map_migrations/3850_hoes.txt new file mode 100644 index 000000000000..7892ec84cf4c --- /dev/null +++ b/tools/map_migrations/3850_hoes.txt @@ -0,0 +1 @@ +/obj/item/minihoe/@SUBTYPES : /obj/item/tool/hoe/mini/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3854_lighters.txt b/tools/map_migrations/3854_lighters.txt new file mode 100644 index 000000000000..e86b74708fc7 --- /dev/null +++ b/tools/map_migrations/3854_lighters.txt @@ -0,0 +1 @@ +/obj/item/flame/lighter/@SUBTYPES : /obj/item/flame/fuelled/lighter/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3862_butchery.txt b/tools/map_migrations/3862_butchery.txt new file mode 100644 index 000000000000..4f1032f7ae73 --- /dev/null +++ b/tools/map_migrations/3862_butchery.txt @@ -0,0 +1,2 @@ +/obj/item/chems/food/fish/@SUBTYPES : /obj/item/chems/food/butchery/meat/fish/@SUBTYPES{@OLD} +/obj/item/chems/food/meat/@SUBTYPES : /obj/item/chems/food/butchery/meat/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3901_sensors.txt b/tools/map_migrations/3901_sensors.txt new file mode 100644 index 000000000000..afd0de22e49d --- /dev/null +++ b/tools/map_migrations/3901_sensors.txt @@ -0,0 +1,2 @@ +/obj/item/clothing/accessory/vitals_sensor/@SUBTYPES : /obj/item/clothing/sensor/vitals/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/buddytag/@SUBTYPES : /obj/item/clothing/sensor/buddytag/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3902_jewelry.txt b/tools/map_migrations/3902_jewelry.txt new file mode 100644 index 000000000000..a5610fd877be --- /dev/null +++ b/tools/map_migrations/3902_jewelry.txt @@ -0,0 +1,6 @@ +/obj/item/clothing/accessory/necklace/@SUBTYPES : /obj/item/clothing/neck/necklace/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/locket/@SUBTYPES : /obj/item/clothing/neck/necklace/locket/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/chaplaininsignia/@SUBTYPES : /obj/item/clothing/insignia/@SUBTYPES{@OLD} +/obj/item/clothing/ring/@SUBTYPES : /obj/item/clothing/gloves/ring/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/bracelet/@SUBTYPES : /obj/item/clothing/gloves/bracelet/@SUBTYPES{@OLD} +/obj/item/clothing/badge/tags/@SUBTYPES : /obj/item/clothing/dog_tags/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3902_ties.txt b/tools/map_migrations/3902_ties.txt new file mode 100644 index 000000000000..66e9a54f30bd --- /dev/null +++ b/tools/map_migrations/3902_ties.txt @@ -0,0 +1,13 @@ +/obj/item/clothing/accessory : /obj/item/clothing/neck/tie{@OLD} +/obj/item/clothing/accessory/scarf/@SUBTYPES : /obj/item/clothing/neck/scarf/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/stethoscope/@SUBTYPES : /obj/item/clothing/neck/stethoscope/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/long/@SUBTYPES : /obj/item/clothing/neck/tie/long/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/black/@SUBTYPES : /obj/item/clothing/neck/tie/black/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/red/@SUBTYPES : /obj/item/clothing/neck/tie/red/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/blue/@SUBTYPES : /obj/item/clothing/neck/tie/blue/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/blue_clip/@SUBTYPES : /obj/item/clothing/neck/tie/blue_clip/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/navy/@SUBTYPES : /obj/item/clothing/neck/tie/navy/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/horrible/@SUBTYPES : /obj/item/clothing/neck/tie/horrible/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/brown/@SUBTYPES : /obj/item/clothing/neck/tie/brown/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/bow/@SUBTYPES : /obj/item/clothing/neck/tie/bow/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/corptie/@SUBTYPES : /obj/item/clothing/neck/tie/corp/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3904_vests.txt b/tools/map_migrations/3904_vests.txt new file mode 100644 index 000000000000..b177fa6af218 --- /dev/null +++ b/tools/map_migrations/3904_vests.txt @@ -0,0 +1,15 @@ +/obj/item/clothing/accessory/wcoat/@SUBTYPES : /obj/item/clothing/suit/jacket/waistcoat/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/toggleable/zhongshan/@SUBTYPES : /obj/item/clothing/suit/jacket/zhongshan/@SUBTYPES{@OLD} +/obj/item/clothing/suit/toggle/suit/@SUBTYPES : /obj/item/clothing/suit/jacket/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/toggleable/corpjacket/@SUBTYPES : /obj/item/clothing/suit/jacket/corp/@SUBTYPES{@OLD} +/obj/item/clothing/suit/toggle/fr_jacket/@SUBTYPES : /obj/item/clothing/suit/jacket/first_responder/@SUBTYPES{@OLD} +/obj/item/clothing/suit/letterman/@SUBTYPES : /obj/item/clothing/suit/jacket/letterman/@SUBTYPES{@OLD} +/obj/item/clothing/suit/toggle/bomber/@SUBTYPES : /obj/item/clothing/suit/jacket/bomber/@SUBTYPES{@OLD} +/obj/item/clothing/suit/leather_jacket/@SUBTYPES : /obj/item/clothing/suit/jacket/leather/@SUBTYPES{@OLD} +/obj/item/clothing/suit/toggle/agent_jacket/@SUBTYPES : /obj/item/clothing/suit/jacket/agent/@SUBTYPES{@OLD} +/obj/item/clothing/suit/toggle/hoodie/@SUBTYPES : /obj/item/clothing/suit/jacket/hoodie/@SUBTYPES{@OLD} +/obj/item/clothing/suit/toggle/wintercoat/@SUBTYPES : /obj/item/clothing/suit/jacket/winter/@SUBTYPES{@OLD} +/obj/item/clothing/suit/captunic/capjacket/@SUBTYPES : /obj/item/clothing/suit/jacket/captain/@SUBTYPES{@OLD} +/obj/item/clothing/suit/poncho/roles/@SUBTYPES : /obj/item/clothing/suit/poncho/@SUBTYPES{@OLD} +/obj/item/clothing/suit/poncho/classic/@SUBTYPES : /obj/item/clothing/suit/poncho/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/dashiki/@SUBTYPES : /obj/item/clothing/suit/dashiki/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3905_shirts.txt b/tools/map_migrations/3905_shirts.txt new file mode 100644 index 000000000000..be17f1ca9d6a --- /dev/null +++ b/tools/map_migrations/3905_shirts.txt @@ -0,0 +1 @@ +/obj/item/clothing/accessory/toggleable/hawaii/@SUBTYPES : /obj/item/clothing/shirt/hawaii/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3913_tunics.txt b/tools/map_migrations/3913_tunics.txt new file mode 100644 index 000000000000..2c330b07b190 --- /dev/null +++ b/tools/map_migrations/3913_tunics.txt @@ -0,0 +1,8 @@ +/obj/item/clothing/under/bluetunic/@SUBTYPES : /obj/item/clothing/pants/champion/@SUBTYPES{@OLD} +/obj/item/clothing/under/familiargarb/@SUBTYPES : /obj/item/clothing/pants/familiar/@SUBTYPES{@OLD} +/obj/item/clothing/suit/captunic : /obj/item/clothing/shirt/tunic/captain{@OLD} +/obj/item/clothing/accessory/tunic/nanotrasen : /obj/item/clothing/shirt/tunic/corp/nanotrasen{@OLD} +/obj/item/clothing/accessory/tunic/heph : /obj/item/clothing/shirt/tunic/corp/heph{@OLD} +/obj/item/clothing/accessory/tunic/zeng : /obj/item/clothing/shirt/tunic/corp/zeng{@OLD} +/obj/item/clothing/accessory/tunic/exec/@SUBTYPES : /obj/item/clothing/shirt/tunic/corp/exec/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/tunic/@SUBTYPES : /obj/item/clothing/shirt/tunic/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3914_webbing.txt b/tools/map_migrations/3914_webbing.txt new file mode 100644 index 000000000000..bc96993d4bb1 --- /dev/null +++ b/tools/map_migrations/3914_webbing.txt @@ -0,0 +1 @@ +/obj/item/clothing/accessory/webbing/@SUBTYPES : /obj/item/clothing/webbing/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3916_more_shirts.txt b/tools/map_migrations/3916_more_shirts.txt new file mode 100644 index 000000000000..e70db071fa5c --- /dev/null +++ b/tools/map_migrations/3916_more_shirts.txt @@ -0,0 +1,4 @@ +/obj/item/clothing/accessory/toggleable/flannel/@SUBTYPES : /obj/item/clothing/shirt/flannel/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/qipao/@SUBTYPES : /obj/item/clothing/shirt/qipao/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/sweater/@SUBTYPES : /obj/item/clothing/shirt/sweater/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/ubac/@SUBTYPES : /obj/item/clothing/shirt/ubac/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3918_cloaks.txt b/tools/map_migrations/3918_cloaks.txt new file mode 100644 index 000000000000..f687a85f88c1 --- /dev/null +++ b/tools/map_migrations/3918_cloaks.txt @@ -0,0 +1 @@ +/obj/item/clothing/accessory/cloak/@SUBTYPES : /obj/item/clothing/suit/cloak/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3919_armbands.txt b/tools/map_migrations/3919_armbands.txt new file mode 100644 index 000000000000..2147a11b5eac --- /dev/null +++ b/tools/map_migrations/3919_armbands.txt @@ -0,0 +1 @@ +/obj/item/clothing/accessory/armband/@SUBTYPES : /obj/item/clothing/armband/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3922_medals_badges.txt b/tools/map_migrations/3922_medals_badges.txt new file mode 100644 index 000000000000..2cff80cdede7 --- /dev/null +++ b/tools/map_migrations/3922_medals_badges.txt @@ -0,0 +1,2 @@ +/obj/item/clothing/accessory/medal/@SUBTYPES : /obj/item/clothing/medal/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/badge/@SUBTYPES : /obj/item/clothing/badge/SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3925_misc_accessories.txt b/tools/map_migrations/3925_misc_accessories.txt new file mode 100644 index 000000000000..5d6499957646 --- /dev/null +++ b/tools/map_migrations/3925_misc_accessories.txt @@ -0,0 +1,4 @@ +/obj/item/clothing/accessory/suspenders/@SUBTYPES : /obj/item/clothing/suspenders/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/armguards/@SUBTYPES : /obj/item/clothing/gloves/armguards/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/legguards/@SUBTYPES : /obj/item/clothing/shoes/legguards/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/fire_overpants/@SUBTYPES : /obj/item/clothing/pants/fire_overpants/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3926_thawb.txt b/tools/map_migrations/3926_thawb.txt new file mode 100644 index 000000000000..459ac394e5cf --- /dev/null +++ b/tools/map_migrations/3926_thawb.txt @@ -0,0 +1,2 @@ +/obj/item/accessory/thawb/@SUBTYPES : /obj/item/clothing/suit/robe/thawb/@SUBTYPES{@OLD} +/obj/item/accessory/sherwani/@SUBTYPES : /obj/item/clothing/suit/robe/sherwani/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3928_more_vests.txt b/tools/map_migrations/3928_more_vests.txt new file mode 100644 index 000000000000..6ee7115de867 --- /dev/null +++ b/tools/map_migrations/3928_more_vests.txt @@ -0,0 +1,4 @@ +/obj/item/clothing/accessory/kneepads/@SUBTYPES : /obj/item/clothing/shoes/kneepads/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/tangzhuang/@SUBTYPES : /obj/item/clothing/suit/jacket/tangzhuang/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/toggleable/black_vest/@SUBTYPES : /obj/item/clothing/suit/jacket/vest/black/@SUBTYPES{@OLD} +/obj/item/clothing/accessory/toggleable/@SUBTYPES : /obj/item/clothing/suit/jacket/vest/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3932_accessory_armor.txt b/tools/map_migrations/3932_accessory_armor.txt new file mode 100644 index 000000000000..b83ab86d1c28 --- /dev/null +++ b/tools/map_migrations/3932_accessory_armor.txt @@ -0,0 +1 @@ +/obj/item/clothing/accessory/armor/@SUBTYPES : /obj/item/clothing/armor_attachment/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3941_seeds.txt b/tools/map_migrations/3941_seeds.txt new file mode 100644 index 000000000000..69c33145c028 --- /dev/null +++ b/tools/map_migrations/3941_seeds.txt @@ -0,0 +1,5 @@ +/obj/item/chems/food/fruit_slice : /obj/item/chems/food/processed_grown/slice/apple{@OLD} +/obj/item/chems/food/fruit_slice/@SUBTYPES : /obj/item/chems/food/processed_grown/slice/@SUBTYPES{@OLD} +/obj/item/chems/food/rawsticks/@SUBTYPES : /obj/item/chems/food/processed_grown/sticks/potato/@SUBTYPES{@OLD} +/obj/item/chems/food/carrotfries/@SUBTYPES : /obj/item/chems/food/processed_grown/sticks/carrot/@SUBTYPES{@OLD} +/obj/item/chems/food/soydope/@SUBTYPES : /obj/item/chems/food/processed_grown/chopped/soy/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/3948_uniforms.txt b/tools/map_migrations/3948_uniforms.txt new file mode 100644 index 000000000000..565df08d0e1c --- /dev/null +++ b/tools/map_migrations/3948_uniforms.txt @@ -0,0 +1,88 @@ +/obj/item/clothing/under/lawyer/female/@SUBTYPES : /obj/item/clothing/under/lawyer/@SUBTYPES{@OLD} +/obj/item/clothing/under/clown/@SUBTYPES : /obj/item/clothing/costume/clown/@SUBTYPES{@OLD} +/obj/item/clothing/under/mime/@SUBTYPES : /obj/item/clothing/costume/mime/@SUBTYPES{@OLD} +/obj/item/clothing/under/sexyclown/@SUBTYPES : /obj/item/clothing/costume/sexyclown/@SUBTYPES{@OLD} +/obj/item/clothing/under/redcoat/@SUBTYPES : /obj/item/clothing/costume/redcoat/@SUBTYPES{@OLD} +/obj/item/clothing/under/sexymime/@SUBTYPES : /obj/item/clothing/costume/sexymime/@SUBTYPES{@OLD} +/obj/item/clothing/under/soviet/@SUBTYPES : /obj/item/clothing/costume/soviet/@SUBTYPES{@OLD} +/obj/item/clothing/under/pirate/@SUBTYPES : /obj/item/clothing/costume/pirate/@SUBTYPES{@OLD} +/obj/item/clothing/under/redcoat/@SUBTYPES : /obj/item/clothing/costume/redcoat/@SUBTYPES{@OLD} +/obj/item/clothing/under/kilt/@SUBTYPES: /obj/item/clothing/costume/kilt/@SUBTYPES{@OLD} +/obj/item/clothing/under/savage_hunter/@SUBTYPES : /obj/item/clothing/costume/savage_hunter/@SUBTYPES{@OLD} +/obj/item/clothing/under/schoolgirl/@SUBTYPES : /obj/item/clothing/costume/schoolgirl/@SUBTYPES{@OLD} +/obj/item/clothing/under/owl/@SUBTYPES : /obj/item/clothing/costume/owl/@SUBTYPES{@OLD} +/obj/item/clothing/under/gladiator/@SUBTYPES : /obj/item/clothing/costume/gladiator/@SUBTYPES{@OLD} +/obj/item/clothing/under/internalaffairs/plain/@SUBTYPES : /obj/item/clothing/slacks/black/outfit/internal_affairs/@SUBTYPES{@OLD} +/obj/item/clothing/under/internalaffairs/@SUBTYPES : /obj/item/clothing/slacks/black/outfit/internal_affairs/@SUBTYPES{@OLD} +/obj/item/clothing/under/formal/corp/@SUBTYPES : /obj/item/clothing/pants/slacks/black/corp/@SUBTYPES{@OLD} +/obj/item/clothing/under/formal/navy/@SUBTYPES : /obj/item/clothing/pants/slacks/black/outfit/navy/@SUBTYPES{@OLD} +/obj/item/clothing/under/formal/red/@SUBTYPES : /obj/item/clothing/pants/slacks/red/outfit/@SUBTYPES{@OLD} +/obj/item/clothing/under/formal/checkered/@SUBTYPES : /obj/item/clothing/pants/slacks/black/outfit/checkered/@SUBTYPES{@OLD} +/obj/item/clothing/under/formal/charcoal/@SUBTYPES : /obj/item/clothing/pants/slacks/black/outfit/@SUBTYPES{@OLD} +/obj/item/clothing/under/formal/@SUBTYPES : /obj/item/clothing/pants/slacks/outfit/@SUBTYPES{@OLD} +/obj/item/clothing/under/det/black/@SUBTYPES : /obj/item/clothing/pants/slacks/black/outfit/detective/@SUBTYPES{@OLD} +/obj/item/clothing/under/det/@SUBTYPES : /obj/item/clothing/pants/slacks/outfit/detective/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/purpsuit/@SUBTYPES : /obj/item/clothing/pants/slacks/purple/outfit/@SUBTYPES{@OLD} +/obj/item/clothing/under/medical/scrubs/@SUBTYPES : /obj/item/clothing/pants/scrubs/@SUBTYPES{@OLD} +/obj/item/clothing/under/pj/@SUBTYPES : /obj/item/clothing/pants/pj/@SUBTYPES{@OLD}, /obj/item/clothing/shirt/pj/@SUBTYPES{@OLD} +/obj/item/clothing/under/research_director/dress_rd : /obj/item/clothing/skirt/research_director/outfit/@SUBTYPES{@OLD} +/obj/item/clothing/under/color/@SUBTYPES : /obj/item/clothing/jumpsuit/@SUBTYPES{@OLD} +/obj/item/clothing/under/chaplain/@SUBTYPES : /obj/item/clothing/jumpsuit/chaplain/@SUBTYPES{@OLD} +/obj/item/clothing/under/engineer/@SUBTYPES : /obj/item/clothing/jumpsuit/engineer/@SUBTYPES{@OLD} +/obj/item/clothing/under/janitor/@SUBTYPES : /obj/item/clothing/jumpsuit/janitor/@SUBTYPES{@OLD} +/obj/item/clothing/under/medical/@SUBTYPES : /obj/item/clothing/jumpsuit/medical/@SUBTYPES{@OLD} +/obj/item/clothing/under/chemist/@SUBTYPES : /obj/item/clothing/jumpsuit/chemist/@SUBTYPES{@OLD} +/obj/item/clothing/under/psych/@SUBTYPES : /obj/item/clothing/jumpsuit/psych/@SUBTYPES{@OLD} +/obj/item/clothing/under/chief_medical_officer/@SUBTYPES : /obj/item/clothing/jumpsuit/chief_medical_officer/@SUBTYPES{@OLD} +/obj/item/clothing/under/geneticist/@SUBTYPES : /obj/item/clothing/jumpsuit/geneticist/@SUBTYPES{@OLD} +/obj/item/clothing/under/virologist/@SUBTYPES : /obj/item/clothing/jumpsuit/virologist/@SUBTYPES{@OLD} +/obj/item/clothing/under/tactical/@SUBTYPES : /obj/item/clothing/jumpsuit/tactical/@SUBTYPES{@OLD} +/obj/item/clothing/under/caretaker/@SUBTYPES : /obj/item/clothing/jumpsuit/caretaker/@SUBTYPES{@OLD} +/obj/item/clothing/under/hazard/@SUBTYPES : /obj/item/clothing/jumpsuit/hazard/@SUBTYPES{@OLD} +/obj/item/clothing/under/head_of_security/@SUBTYPES : /obj/item/clothing/jumpsuit/head_of_security/@SUBTYPES{@OLD} +/obj/item/clothing/under/warden/@SUBTYPES : /obj/item/clothing/jumpsuit/warden/@SUBTYPES{@OLD} +/obj/item/clothing/under/security/@SUBTYPES : /obj/item/clothing/jumpsuit/security/@SUBTYPES{@OLD} +/obj/item/clothing/under/mailman/@SUBTYPES : /obj/item/clothing/jumpsuit/mailman/@SUBTYPES{@OLD} +/obj/item/clothing/under/miner/@SUBTYPES : /obj/item/clothing/jumpsuit/miner/@SUBTYPES{@OLD} +/obj/item/clothing/under/sterile/@SUBTYPES : /obj/item/clothing/jumpsuit/sterile/@SUBTYPES{@OLD} +/obj/item/clothing/under/cargotech/@SUBTYPES : /obj/item/clothing/jumpsuit/cargotech/@SUBTYPES{@OLD} +/obj/item/clothing/under/chief_engineer/@SUBTYPES : /obj/item/clothing/jumpsuit/chief_engineer/@SUBTYPES{@OLD} +/obj/item/clothing/under/hydroponics/@SUBTYPES : /obj/item/clothing/jumpsuit/hydroponics/@SUBTYPES{@OLD} +/obj/item/clothing/under/captain/@SUBTYPES : /obj/item/clothing/jumpsuit/captain/@SUBTYPES{@OLD} +/obj/item/clothing/under/captainformal/@SUBTYPES : /obj/item/clothing/jumpsuit/captainformal/@SUBTYPES{@OLD} +/obj/item/clothing/under/quantum/@SUBTYPES : /obj/item/clothing/jumpsuit/quantum/@SUBTYPES{@OLD} +/obj/item/clothing/under/captain_fly/@SUBTYPES : /obj/item/clothing/jumpsuit/captain_fly/@SUBTYPES{@OLD} +/obj/item/clothing/under/johnny/@SUBTYPES : /obj/item/clothing/jumpsuit/johnny/@SUBTYPES{@OLD} +/obj/item/clothing/under/atmospheric_technician/@SUBTYPES : /obj/item/clothing/jumpsuit/atmospheric_technician/@SUBTYPES{@OLD} +/obj/item/clothing/under/blackjumpshorts/@SUBTYPES : /obj/item/clothing/jumpsuit/blackjumpshorts/@SUBTYPES{@OLD} +/obj/item/clothing/under/executive/@SUBTYPES : /obj/item/clothing/pants/slacks/black/corp/@SUBTYPES{@OLD} +/obj/item/clothing/under/polo/@SUBTYPES : /obj/item/clothing/pants/slacks/white/corp/polo/@SUBTYPES{@OLD} +/obj/item/clothing/under/guard/pcrc/@SUBTYPES : /obj/item/clothing/under/pcrc/@SUBTYPES{@OLD} +/obj/item/clothing/under/aether/@SUBTYPES : /obj/item/clothing/jumpsuit/aether/@SUBTYPES{@OLD} +/obj/item/clothing/under/focal/@SUBTYPES : /obj/item/clothing/jumpsuit/focal/@SUBTYPES{@OLD} +/obj/item/clothing/under/hephaestus/@SUBTYPES : /obj/item/clothing/jumpsuit/hephaestus/@SUBTYPES{@OLD} +/obj/item/clothing/under/wardt/@SUBTYPES : /obj/item/clothing/jumpsuit/wardt/@SUBTYPES{@OLD} +/obj/item/clothing/under/abaya/@SUBTYPES : /obj/item/clothing/suit/robe/abaya/@SUBTYPES{@OLD} +/obj/item/clothing/under/skirt/@SUBTYPES : /obj/item/clothing/skirt/@SUBTYPES{@OLD} +/obj/item/clothing/under/skirt_c/dress/@SUBTYPES : /obj/item/clothing/dress/short/@SUBTYPES{@OLD} +/obj/item/clothing/under/skirt_c/@SUBTYPES : /obj/item/clothing/skirt/short/@SUBTYPES{@OLD} +/obj/item/clothing/under/kimono/@SUBTYPES : /obj/item/clothing/dress/kimono/@SUBTYPES{@OLD} +/obj/item/clothing/under/cheongsam/@SUBTYPES : /obj/item/clothing/dress/cheongsam/@SUBTYPES{@OLD} +/obj/item/clothing/under/sundress_white/@SUBTYPES : /obj/item/clothing/dress/sun/white/@SUBTYPES{@OLD} +/obj/item/clothing/under/dress/dress_hop/@SUBTYPES : /obj/item/clothing/dress/hop/@SUBTYPES{@OLD} +/obj/item/clothing/under/dress/dress_hr/@SUBTYPES : /obj/item/clothing/dress/hr/@SUBTYPES{@OLD} +/obj/item/clothing/under/dress/dress_cap/@SUBTYPES : /obj/item/clothing/dress/cap/@SUBTYPES{@OLD} +/obj/item/clothing/under/dress/dress_saloon/@SUBTYPES : /obj/item/clothing/dress/saloon/@SUBTYPES{@OLD} +/obj/item/clothing/under/nursesuit/@SUBTYPES : /obj/item/clothing/dress/nurse/@SUBTYPES{@OLD} +/obj/item/clothing/under/nurse/@SUBTYPES : /obj/item/clothing/dress/nurse/@SUBTYPES{@OLD} +/obj/item/clothing/under/wedding/@SUBTYPES : /obj/item/clothing/dress/wedding/@SUBTYPES{@OLD} +/obj/item/clothing/under/dress/@SUBTYPES : /obj/item/clothing/dress/@SUBTYPES{@OLD} +/obj/item/clothing/under/sundress/@SUBTYPES : /obj/item/clothing/dress/sun/@SUBTYPES{@OLD} +/obj/item/clothing/under/devildress/@SUBTYPES : /obj/item/clothing/dress/devil/@SUBTYPES{@OLD} +/obj/item/clothing/under/avian_smock/@SUBTYPES : /obj/item/clothing/dress/avian_smock/@SUBTYPES{@OLD} +/obj/item/clothing/under/gown/@SUBTYPES : /obj/item/clothing/dress/gown/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/infil/fem/@SUBTYPES : /obj/item/clothing/dress/white/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/infil/@SUBTYPES : /obj/item/clothing/pants/slacks/outfit/tie/@SUBTYPES{@OLD} +/obj/item/clothing/under/vox/vox_robes/@SUBTYPES : /obj/item/clothing/suit/robe/vox/@SUBTYPES{@OLD} +/obj/item/clothing/under/vox/vox_casual/@SUBTYPES : /obj/item/clothing/pants/vox/@SUBTYPES{@OLD} +/obj/item/clothing/under/vox/@SUBTYPES : /obj/item/clothing/pants/vox/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3959_hatchets.txt b/tools/map_migrations/3959_hatchets.txt new file mode 100644 index 000000000000..443e74690c07 --- /dev/null +++ b/tools/map_migrations/3959_hatchets.txt @@ -0,0 +1,2 @@ +/obj/item/hatchet/machete/@SUBTYPES : /obj/item/tool/machete/@SUBTYPES{@OLD} +/obj/item/hatchet/@SUBTYPES : /obj/item/tool/axe/hatchet/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/3987_deer_foxes.txt b/tools/map_migrations/3987_deer_foxes.txt new file mode 100644 index 000000000000..b3a20754bb04 --- /dev/null +++ b/tools/map_migrations/3987_deer_foxes.txt @@ -0,0 +1,2 @@ +/mob/living/simple_animal/rabbit/@SUBTYPES : /mob/living/simple_animal/passive/rabbit/@SUBTYPES{@OLD} +/mob/living/simple_animal/mouse/@SUBTYPES : /mob/living/simple_animal/passive/mouse/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4026_gloves.txt b/tools/map_migrations/4026_gloves.txt new file mode 100644 index 000000000000..8d61302e7b41 --- /dev/null +++ b/tools/map_migrations/4026_gloves.txt @@ -0,0 +1 @@ +/obj/item/clothing/gloves/color/@SUBTYPES : /obj/item/clothing/gloves/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4047_more_uniforms.txt b/tools/map_migrations/4047_more_uniforms.txt new file mode 100644 index 000000000000..6b0e87f953f6 --- /dev/null +++ b/tools/map_migrations/4047_more_uniforms.txt @@ -0,0 +1,40 @@ +/obj/item/clothing/jumpsuit/psych/turtleneck/sweater/@SUBTYPES : /obj/item/clothing/shirt/sweater/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/psych/turtleneck/@SUBTYPES : /obj/item/clothing/shirt/sweater/turquoise, /obj/item/clothing/pants/slacks/navy/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/captain_fly/@SUBTYPES : /obj/item/clothing/costume/captain_fly/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/head_of_personnel_whimsy/@SUBTYPES : /obj/item/clothing/costume/head_of_personnel_whimsy/@SUBTYPES{@OLD} +/obj/item/clothing/pants/casual/mustangjeans/monke/@SUBTYPES : /obj/item/clothing/pants/casual/mustangjeans/@SUBTYPES{@OLD} +/obj/item/clothing/under/mankini/@SUBTYPES : /obj/item/clothing/pants/mankini/@SUBTYPES{@OLD} +/obj/item/clothing/under/bartender/@SUBTYPES : /obj/item/clothing/pants/formal/black{@OLD}, /obj/item/clothing/shirt/button{@OLD} +/obj/item/clothing/under/blazer/@SUBTYPES : /obj/item/clothing/shirt/button{@OLD}, /obj/item/clothing/neck/tie/navy{@OLD}, /obj/item/clothing/suit/jacket/blazer{@OLD} +/obj/item/clothing/under/librarian/@SUBTYPES : /obj/item/clothing/pants/slacks/red{@OLD}, /obj/item/clothing/shirt/button{@OLD}, /obj/item/clothing/neck/tie/navy{@OLD}, /obj/item/clothing/suit/jacket/charcoal{@OLD} +/obj/item/clothing/under/overalls/@SUBTYPES : /obj/item/clothing/suit/apron/overalls/laborer/@SUBTYPES{@OLD} +/obj/item/clothing/under/chef/@SUBTYPES : /obj/item/clothing/pants/slacks/white{@OLD}, /obj/item/clothing/shirt/button{@OLD} +/obj/item/clothing/under/syndicate/@SUBTYPES : /obj/item/clothing/shirt/syndicate/@SUBTYPES{@OLD} +/obj/item/clothing/under/sl_suit/@SUBTYPES : /obj/item/clothing/pants/slacks/black{@OLD}, /obj/item/clothing/shirt/button{@OLD} +/obj/item/clothing/under/orderly/@SUBTYPES : /obj/item/clothing/pants/slacks/white/orderly{@OLD}, /obj/item/clothing/shirt/button/orderly{@OLD}, /obj/item/clothing/neck/tie/long/red{@OLD} +/obj/item/clothing/under/gimmick/rank/captain/suit/@SUBTYPES : /obj/item/clothing/costume/captain_suit/@SUBTYPES{@OLD} +/obj/item/clothing/under/gimmick/rank/head_of_personnel/suit/@SUBTYPES : /obj/item/clothing/costume/head_of_personnel_suit/@SUBTYPES{@OLD} +/obj/item/clothing/under/waiter/monke/@SUBTYPES : /obj/item/clothing/under/waiter/@SUBTYPES{@OLD} +/obj/item/clothing/under/waiter/@SUBTYPES : /obj/item/clothing/pants/slacks/black{@OLD}, /obj/item/clothing/shirt/button{@OLD}, /obj/item/clothing/neck/tie/bow/color/red{@OLD}, /obj/item/clothing/suit/jacket/vest/blue{@OLD} +/obj/item/clothing/under/wetsuit/@SUBTYPES : /obj/item/clothing/jumpsuit/wetsuit/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/bluesuit/@SUBTYPES : /obj/item/clothing/costume/lawyer_bluesuit/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/red/@SUBTYPES : /obj/item/clothing/costume/lawyer_red/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/oldman/@SUBTYPES : /obj/item/clothing/costume/oldman/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/fiendsuit/@SUBTYPES : /obj/item/clothing/costume/fiendsuit/@SUBTYPES{@OLD} +/obj/item/clothing/under/lawyer/@SUBTYPES : /obj/item/clothing/costume/lawyer/@SUBTYPES{@OLD} +/obj/item/clothing/under/grimhoodie/@SUBTYPES : /obj/item/clothing/pants/casual/blackjeans{@OLD}, /obj/item/clothing/shirt/tee/black{@OLD}, /obj/item/clothing/suit/jacket/hoodie/grim{@OLD} +/obj/item/clothing/under/gentlesuit/@SUBTYPES : /obj/item/clothing/shirt/button/black{@OLD}, /obj/item/clothing/suit/jacket/vest/gray{@OLD} +/obj/item/clothing/under/security2/@SUBTYPES : /obj/item/clothing/shirt/button/security{@OLD}, /obj/item/clothing/pants/slacks/security{@OLD} +/obj/item/clothing/under/blazer/@SUBTYPES : /obj/item/clothing/shirt/button{@OLD}, /obj/item/clothing/neck/tie/navy{@OLD}, /obj/item/clothing/suit/jacket/blazer{@OLD} +/obj/item/clothing/under/psysuit/@SUBTYPES : /obj/item/clothing/jumpsuit/psysuit/@SUBTYPES{@OLD} +/obj/item/clothing/under/skrell/@SUBTYPES : /obj/item/clothing/jumpsuit/skrell/@SUBTYPES{@OLD} +/obj/item/clothing/under/ascent/@SUBTYPES : /obj/item/clothing/jumpsuit/ascent/@SUBTYPES{@OLD} +/obj/item/clothing/under/harness/@SUBTYPES : /obj/item/clothing/shirt/harness/@SUBTYPES{@OLD} +/obj/item/clothing/under/syndicate/tacticool/@SUBTYPES : /obj/item/clothing/shirt/syndicate/tacticool/@SUBTYPES{@OLD} +/obj/item/clothing/under/work/@SUBTYPES : /obj/item/clothing/jumpsuit/work/@SUBTYPES{@OLD} +/obj/item/clothing/under/pilot/@SUBTYPES : /obj/item/clothing/jumpsuit/pilot/@SUBTYPES{@OLD} +/obj/item/clothing/under/pcrc/@SUBTYPES : /obj/item/clothing/jumpsuit/pcrc/@SUBTYPES{@OLD} +/obj/item/clothing/under/frontier/@SUBTYPES : /obj/item/clothing/shirt/flannel/red{@OLD}, /obj/item/clothing/suit/apron/overalls/denim{@OLD} +/obj/item/clothing/under/abol_uniform/@SUBTYPES : /obj/item/clothing/jumpsuit/abolitionist/@SUBTYPES{@OLD} +/obj/item/clothing/under/shortjumpskirt/@SUBTYPES : /obj/item/clothing/jumpsuit/skirt/short/@SUBTYPES{@OLD} +/obj/item/clothing/under/@SUBTYPES : /obj/item/clothing/costume/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4113_carbon_removal.txt b/tools/map_migrations/4113_carbon_removal.txt new file mode 100644 index 000000000000..1b30ff494f80 --- /dev/null +++ b/tools/map_migrations/4113_carbon_removal.txt @@ -0,0 +1 @@ +/mob/living/carbon/human/@SUBTYPES : /mob/living/human/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4124_cult_modpack.txt b/tools/map_migrations/4124_cult_modpack.txt new file mode 100644 index 000000000000..3d29f8793baa --- /dev/null +++ b/tools/map_migrations/4124_cult_modpack.txt @@ -0,0 +1 @@ +/obj/structure/cult/talisman : /obj/structure/talisman_altar{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4144_cats_faithless_drakes.txt b/tools/map_migrations/4144_cats_faithless_drakes.txt new file mode 100644 index 000000000000..dac9b5077018 --- /dev/null +++ b/tools/map_migrations/4144_cats_faithless_drakes.txt @@ -0,0 +1,4 @@ +/mob/living/simple_animal/hostile/faithless/@SUBTYPES : /mob/living/simple_animal/hostile/revenant/@SUBTYPES{@OLD} +/mob/living/simple_animal/hostile/drake/@SUBTYPES : /mob/living/simple_animal/hostile/space_dragon/@SUBTYPES{@OLD} +/mob/living/simple_animal/hostile/retaliate/@SUBTYPES : /mob/living/simple_animal/hostile/@SUBTYPES{@OLD} +/mob/living/simple_animal/cat/@SUBTYPES : /mob/living/simple_animal/passive/cat/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4154_railing.txt b/tools/map_migrations/4154_railing.txt new file mode 100644 index 000000000000..bda6c039ea26 --- /dev/null +++ b/tools/map_migrations/4154_railing.txt @@ -0,0 +1 @@ +/obj/structure/railing/mapped/ebony : /obj/structure/railing/mapped/wooden/ebony{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4154_wood_doors.txt b/tools/map_migrations/4154_wood_doors.txt new file mode 100644 index 000000000000..f4c6a7622a34 --- /dev/null +++ b/tools/map_migrations/4154_wood_doors.txt @@ -0,0 +1,2 @@ +/obj/structure/door/wood/ebony : /obj/structure/door/ebony{@OLD} +/obj/structure/door/wood/walnut : /obj/structure/door/walnut{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4233_weapon_rework.txt b/tools/map_migrations/4233_weapon_rework.txt new file mode 100644 index 000000000000..c7224159c54e --- /dev/null +++ b/tools/map_migrations/4233_weapon_rework.txt @@ -0,0 +1,5 @@ +/obj/item/twohanded/spear/@SUBTYPES : /obj/item/bladed/polearm/spear/improvised/@SUBTYPES{@OLD} +/obj/item/twohanded/fireaxe/@SUBTYPES : /obj/item/bladed/axe/fire/@SUBTYPES{@OLD} +/obj/item/twohanded/baseballbat/@SUBTYPES : /obj/item/baseball_bat/@SUBTYPES{@OLD} +/obj/item/twohanded/pipewrench/@SUBTYPES : /obj/item/wrench/pipe/@SUBTYPES{@OLD} + diff --git a/tools/map_migrations/4246_handmade.txt b/tools/map_migrations/4246_handmade.txt new file mode 100644 index 000000000000..53adbb93c878 --- /dev/null +++ b/tools/map_migrations/4246_handmade.txt @@ -0,0 +1 @@ +/obj/item/chems/glass/pottery/@SUBTYPES : /obj/item/chems/glass/handmade/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4258_medical_stacks.txt b/tools/map_migrations/4258_medical_stacks.txt new file mode 100644 index 000000000000..0b0182f5ffd0 --- /dev/null +++ b/tools/map_migrations/4258_medical_stacks.txt @@ -0,0 +1,9 @@ +/obj/item/stack/medical/bruise_pack/bandage/@SUBTYPES : /obj/item/stack/medical/bandage/crafted@SUBTYPES{@OLD} +/obj/item/stack/medical/bruise_pack/@SUBTYPES : /obj/item/stack/medical/bandage/@SUBTYPES{@OLD} +/obj/item/stack/medical/ointment/poultice/@SUBTYPES : /obj/item/stack/medical/ointment/crafted/@SUBTYPES{@OLD} +/obj/item/stack/medical/advanced/bruise_pack/@SUBTYPES : /obj/item/stack/medical/bandage/advanced/@SUBTYPES{@OLD} +/obj/item/stack/medical/advanced/ointment/@SUBTYPES : /obj/item/stack/medical/bandage/ointment/@SUBTYPES{@OLD} +/obj/item/stack/medical/splint/simple/@SUBTYPES : /obj/item/stack/medical/splint/crafted/@SUBTYPES{@OLD} +/obj/item/stack/medical/splint/ghetto/@SUBTYPES : /obj/item/stack/medical/splint/improvised/@SUBTYPES{@OLD} +/obj/item/stack/medical/resin/handmade/@SUBTYPES : /obj/item/stack/medical/resin/crafted/@SUBTYPES{@OLD} + diff --git a/tools/map_migrations/4274_chem_food.txt b/tools/map_migrations/4274_chem_food.txt new file mode 100644 index 000000000000..8609d6034212 --- /dev/null +++ b/tools/map_migrations/4274_chem_food.txt @@ -0,0 +1 @@ +/obj/item/chems/food/@SUBTYPES : /obj/item/food/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4344_soup.txt b/tools/map_migrations/4344_soup.txt new file mode 100644 index 000000000000..2c04d0126bc0 --- /dev/null +++ b/tools/map_migrations/4344_soup.txt @@ -0,0 +1,14 @@ +/obj/item/food/beetsoup : /obj/item/chems/glass/bowl/mapped/beet{@OLD} +/obj/item/food/bloodsoup : /obj/item/chems/glass/bowl/mapped/blood{@OLD} +/obj/item/food/meatballsoup : /obj/item/chems/glass/bowl/mapped/meatball{@OLD} +/obj/item/food/milosoup : /obj/item/chems/glass/bowl/mapped/meatball{@OLD} +/obj/item/food/mushroomsoup : /obj/item/chems/glass/bowl/mapped/mushroom{@OLD} +/obj/item/food/vegetablesoup : /obj/item/chems/glass/bowl/mapped/vegetable{@OLD} +/obj/item/food/tomatosoup : /obj/item/chems/glass/bowl/mapped/tomato{@OLD} +/obj/item/food/nettlesoup : /obj/item/chems/glass/bowl/mapped/nettle{@OLD} +/obj/item/food/stew : /obj/item/chems/glass/bowl/mapped/stew{@OLD} +/obj/item/food/hotchili : /obj/item/chems/glass/bowl/mapped/chili/hot{@OLD} +/obj/item/food/coldchili : /obj/item/chems/glass/bowl/mapped/chili/cold{@OLD} +/obj/item/food/katsucurry : /obj/item/chems/glass/bowl/mapped/curry/katsu{@OLD} + +/obj/item/food/mysterysoup : /obj/item/chems/glass/bowl/mystery{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4396_scrolls.txt b/tools/map_migrations/4396_scrolls.txt new file mode 100644 index 000000000000..5ea6bfd961bb --- /dev/null +++ b/tools/map_migrations/4396_scrolls.txt @@ -0,0 +1,3 @@ +/obj/item/teleportation_scroll/@SUBTYPES : /obj/item/paper/scroll/teleportation/@SUBTYPES{@OLD} +/obj/item/paper/crumpled/bloody/@SUBTYPES : /obj/item/paper/crumpled/@SUBTYPES{@OLD} +/obj/item/paper/cig/filter/@SUBTYPES : /obj/item/cigarette_filter/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4398_staves.txt b/tools/map_migrations/4398_staves.txt new file mode 100644 index 000000000000..b6e61028e592 --- /dev/null +++ b/tools/map_migrations/4398_staves.txt @@ -0,0 +1,5 @@ +/obj/item/cane/concealed/@SUBTYPES : /obj/item/cane/fancy/sword/@SUBTYPES{@OLD} +/obj/item/staff/gentcane/@SUBTYPES : /obj/item/cane/fancy/@SUBTYPES{@OLD} +/obj/item/cane : /obj/item/cane/aluminium +/obj/item/staff/fireball/@SUBTYPES : /obj/item/staff/crystal/beacon/fireball/@SUBTYPES{@OLD} +/obj/item/staff/@SUBTYPES : /obj/item/staff/crystal/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4420_condiments.txt b/tools/map_migrations/4420_condiments.txt new file mode 100644 index 000000000000..22425a4113e2 --- /dev/null +++ b/tools/map_migrations/4420_condiments.txt @@ -0,0 +1 @@ +/obj/item/chems/condiment/small/packet/@SUBTYPES : /obj/item/chems/packet/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4525_food_breakup.txt b/tools/map_migrations/4525_food_breakup.txt new file mode 100644 index 000000000000..513b12b39f5f --- /dev/null +++ b/tools/map_migrations/4525_food_breakup.txt @@ -0,0 +1,37 @@ +/obj/item/food/sosjerky/@SUBTYPES : /obj/item/food/junk/sosjerky/@SUBTYPES{@OLD} +/obj/item/food/no_raisin/@SUBTYPES : /obj/item/food/junk/no_raisin/@SUBTYPES{@OLD} +/obj/item/food/spacetwinkie/@SUBTYPES : /obj/item/food/junk/spacetwinkie/@SUBTYPES{@OLD} +/obj/item/food/cheesiehonkers/@SUBTYPES : /obj/item/food/junk/cheesiehonkers/@SUBTYPES{@OLD} +/obj/item/food/syndicake/@SUBTYPES : /obj/item/food/junk/syndicake/@SUBTYPES{@OLD} +/obj/item/food/pistachios/@SUBTYPES : /obj/item/food/junk/pistachios/@SUBTYPES{@OLD} +/obj/item/food/semki/@SUBTYPES : /obj/item/food/junk/semki/@SUBTYPES{@OLD} +/obj/item/food/squid/@SUBTYPES : /obj/item/food/junk/squid/@SUBTYPES{@OLD} +/obj/item/food/croutons/@SUBTYPES : /obj/item/food/junk/croutons/@SUBTYPES{@OLD} +/obj/item/food/salo/@SUBTYPES : /obj/item/food/junk/salo/@SUBTYPES{@OLD} +/obj/item/food/driedfish/@SUBTYPES : /obj/item/food/junk/driedfish/@SUBTYPES{@OLD} +/obj/item/food/liquidfood/@SUBTYPES : /obj/item/food/junk/liquidfood/@SUBTYPES{@OLD} +/obj/item/food/meatcube/@SUBTYPES : /obj/item/food/junk/meatcube/@SUBTYPES{@OLD} +/obj/item/food/tastybread/@SUBTYPES : /obj/item/food/junk/tastybread/@SUBTYPES{@OLD} +/obj/item/food/candy/@SUBTYPES : /obj/item/food/junk/candy/@SUBTYPES{@OLD} +/obj/item/food/candy_corn/@SUBTYPES : /obj/item/food/junk/candy_corn/@SUBTYPES{@OLD} +/obj/item/food/chips/@SUBTYPES : /obj/item/food/junk/chips/@SUBTYPES{@OLD} +/obj/item/food/lunacake/@SUBTYPES : /obj/item/food/junk/lunacake/@SUBTYPES{@OLD} +/obj/item/food/triton/@SUBTYPES : /obj/item/food/junk/triton/@SUBTYPES{@OLD} +/obj/item/food/saturn/@SUBTYPES : /obj/item/food/junk/saturn/@SUBTYPES{@OLD} +/obj/item/food/jupiter/@SUBTYPES : /obj/item/food/junk/jupiter/@SUBTYPES{@OLD} +/obj/item/food/pluto/@SUBTYPES : /obj/item/food/junk/pluto/@SUBTYPES{@OLD} +/obj/item/food/mars/@SUBTYPES : /obj/item/food/junk/mars/@SUBTYPES{@OLD} +/obj/item/food/venus/@SUBTYPES : /obj/item/food/junk/venus/@SUBTYPES{@OLD} +/obj/item/food/oort/@SUBTYPES : /obj/item/food/junk/oort/@SUBTYPES{@OLD} +/obj/item/food/ricecake/@SUBTYPES : /obj/item/food/junk/ricecake/@SUBTYPES{@OLD} +/obj/item/food/pokey/@SUBTYPES : /obj/item/food/junk/pokey/@SUBTYPES{@OLD} +/obj/item/food/weebonuts/@SUBTYPES : /obj/item/food/junk/weebonuts/@SUBTYPES{@OLD} +/obj/item/food/chocobanana/@SUBTYPES : /obj/item/food/junk/chocobanana/@SUBTYPES{@OLD} +/obj/item/food/dango/@SUBTYPES : /obj/item/food/junk/dango/@SUBTYPES{@OLD} + +/obj/item/food/xenomeat/@SUBTYPES : /obj/item/food/butchery/meat/xeno/@SUBTYPES{@OLD} +/obj/item/food/cosmoshark/@SUBTYPES : /obj/item/food/butchery/meat/fish/shark/@SUBTYPES{@OLD} +/obj/item/food/bearmeat/@SUBTYPES : /obj/item/food/butchery/meat/bear/@SUBTYPES{@OLD} + +/obj/item/food/meatkabob/@SUBTYPES : /obj/item/food/skewer/meat/@SUBTYPES{@OLD} +/obj/item/food/tofukabob/@SUBTYPES : /obj/item/food/skewer/tofu/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4533_animal_cubes.txt b/tools/map_migrations/4533_animal_cubes.txt new file mode 100644 index 000000000000..1a3a15a3b76f --- /dev/null +++ b/tools/map_migrations/4533_animal_cubes.txt @@ -0,0 +1,6 @@ +/obj/item/box/monkeycubes/spidercubes/@SUBTYPES : /obj/item/box/animal_cubes/spiders/@SUBTYPES{@OLD} +/obj/item/box/monkeycubes/@SUBTYPES : /obj/item/box/animal_cubes/monkeys/@SUBTYPES{@OLD} +/obj/item/food/monkeycube/wrapped/spidercube/@SUBTYPES : /obj/item/food/animal_cube/wrapped/spider/@SUBTYPES{@OLD} +/obj/item/food/monkeycube/spidercube/@SUBTYPES : /obj/item/food/animal_cube/spider/@SUBTYPES{@OLD} +/obj/item/food/monkeycube/wrapped/@SUBTYPES : /obj/item/food/animal_cube/wrapped/monkey/@SUBTYPES{@OLD} +/obj/item/food/monkeycube/@SUBTYPES : /obj/item/food/animal_cube/monkey/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4535_rations_crate.txt b/tools/map_migrations/4535_rations_crate.txt new file mode 100644 index 000000000000..addcc538ebd7 --- /dev/null +++ b/tools/map_migrations/4535_rations_crate.txt @@ -0,0 +1 @@ +/obj/structure/closet/crate/freezer/rations : /obj/structure/closet/crate/plastic/rations{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4545_mining_drills.txt b/tools/map_migrations/4545_mining_drills.txt new file mode 100644 index 000000000000..3f8e0cdc4e37 --- /dev/null +++ b/tools/map_migrations/4545_mining_drills.txt @@ -0,0 +1,2 @@ +/obj/machinery/mining/drill/@SUBTYPES : /obj/machinery/mining_drill/@SUBTYPES{@OLD} +/obj/machinery/mining/brace/@SUBTYPES : /obj/structure/drill_brace/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4555_airless_plating.txt b/tools/map_migrations/4555_airless_plating.txt new file mode 100644 index 000000000000..e51638933a62 --- /dev/null +++ b/tools/map_migrations/4555_airless_plating.txt @@ -0,0 +1,2 @@ +/turf/floor/airless/@SUBTYPES : /turf/floor/plating/airless/@SUBTYPES{@OLD} + diff --git a/tools/map_migrations/4583_tables.txt b/tools/map_migrations/4583_tables.txt new file mode 100644 index 000000000000..72bbd06136d5 --- /dev/null +++ b/tools/map_migrations/4583_tables.txt @@ -0,0 +1,11 @@ +/obj/structure/table/woodentable/@SUBTYPES : /obj/structure/table/wood/@SUBTYPES{@OLD} +/obj/structure/table/woodentable_reinforced/@SUBTYPES : /obj/structure/table/wood/reinforced/@SUBTYPES{@OLD} +/obj/item/stack/tile/wood/@SUBTYPES : /obj/item/stack/tile/wood/oak/@SUBTYPES{@OLD} +/obj/item/stack/tile/mahogany/@SUBTYPES : /obj/item/stack/tile/wood/mahogany/@SUBTYPES{@OLD} +/obj/item/stack/tile/maple/@SUBTYPES : /obj/item/stack/tile/wood/maple/@SUBTYPES{@OLD} +/obj/item/stack/tile/ebony/@SUBTYPES : /obj/item/stack/tile/wood/ebony/@SUBTYPES{@OLD} +/obj/item/stack/tile/walnut/@SUBTYPES : /obj/item/stack/tile/wood/walnut/@SUBTYPES{@OLD} +/obj/item/stack/tile/bamboo/@SUBTYPES : /obj/item/stack/tile/wood/bamboo/@SUBTYPES{@OLD} +/obj/item/stack/tile/yew/@SUBTYPES : /obj/item/stack/tile/wood/yew/@SUBTYPES{@OLD} + + diff --git a/tools/map_migrations/4615_target_stakes.txt b/tools/map_migrations/4615_target_stakes.txt new file mode 100644 index 000000000000..8e4677a219f1 --- /dev/null +++ b/tools/map_migrations/4615_target_stakes.txt @@ -0,0 +1,2 @@ +/obj/item/target/@SUBTYPES : /obj/item/target_dummy/@SUBTYPES{@OLD} +/obj/structure/target_stake/@SUBTYPES : /obj/structure/target_stake/steel/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4647_dirt.txt b/tools/map_migrations/4647_dirt.txt new file mode 100644 index 000000000000..fde23f21533c --- /dev/null +++ b/tools/map_migrations/4647_dirt.txt @@ -0,0 +1,2 @@ +/obj/effect/decal/cleanable/dirt : /obj/effect/decal/cleanable/dirt/visible{@OLD} + diff --git a/tools/map_migrations/4651_rods.txt b/tools/map_migrations/4651_rods.txt new file mode 100644 index 000000000000..e7d5bffba5e9 --- /dev/null +++ b/tools/map_migrations/4651_rods.txt @@ -0,0 +1,2 @@ +/obj/item/stack/material/rods/@SUBTYPES : /obj/item/stack/material/rods/mapped/steel/@SUBTYPES{@OLD} + diff --git a/tools/map_migrations/4662_waterskin.txt b/tools/map_migrations/4662_waterskin.txt new file mode 100644 index 000000000000..8fa91607ee8f --- /dev/null +++ b/tools/map_migrations/4662_waterskin.txt @@ -0,0 +1,2 @@ +/obj/item/chems/waterskin/@SUBTYPES : /obj/item/chems/glass/waterskin/@SUBTYPES{@OLD} + diff --git a/tools/map_migrations/4740_sulphur_sulfur.txt b/tools/map_migrations/4740_sulphur_sulfur.txt new file mode 100644 index 000000000000..20cc37ab7457 --- /dev/null +++ b/tools/map_migrations/4740_sulphur_sulfur.txt @@ -0,0 +1 @@ +/obj/item/chems/glass/beaker/sulphuric/@SUBTYPES : /obj/item/chems/glass/beaker/sulfuric/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4790_shuttle_ceilings.txt b/tools/map_migrations/4790_shuttle_ceilings.txt new file mode 100644 index 000000000000..083b1b9f32d6 --- /dev/null +++ b/tools/map_migrations/4790_shuttle_ceilings.txt @@ -0,0 +1 @@ +/turf/unsimulated/floor/shuttle_ceiling : /turf/floor/shuttle_ceiling{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4829_rags.txt b/tools/map_migrations/4829_rags.txt new file mode 100644 index 000000000000..8009144e5852 --- /dev/null +++ b/tools/map_migrations/4829_rags.txt @@ -0,0 +1 @@ +/obj/item/chems/glass/rag/@SUBTYPES : /obj/item/chems/rag/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4838_chairs.txt b/tools/map_migrations/4838_chairs.txt new file mode 100644 index 000000000000..a49c4df623eb --- /dev/null +++ b/tools/map_migrations/4838_chairs.txt @@ -0,0 +1,2 @@ +/obj/structure/bed/chair/janicart/@SUBTYPES : /obj/structure/janicart/@SUBTYPES{@OLD} +/obj/structure/bed/chair/@SUBTYPES : /obj/structure/chair/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4854_buckets.txt b/tools/map_migrations/4854_buckets.txt new file mode 100644 index 000000000000..e5a8e74319e4 --- /dev/null +++ b/tools/map_migrations/4854_buckets.txt @@ -0,0 +1 @@ +/obj/item/chems/glass/paint/@SUBTYPES : /obj/item/chems/glass/bucket/paint/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/4898_color_bowtie.txt b/tools/map_migrations/4898_color_bowtie.txt new file mode 100644 index 000000000000..50099e74e447 --- /dev/null +++ b/tools/map_migrations/4898_color_bowtie.txt @@ -0,0 +1 @@ +/obj/item/clothing/neck/tie/bow/color/@SUBTYPES : /obj/item/clothing/neck/tie/bow/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4898_jumpsuits_costumes.txt b/tools/map_migrations/4898_jumpsuits_costumes.txt new file mode 100644 index 000000000000..4a7af78fa802 --- /dev/null +++ b/tools/map_migrations/4898_jumpsuits_costumes.txt @@ -0,0 +1,11 @@ +# Converts a number of jumpsuits to costumes +# because they shouldn't have the full suite of jumpsuit modifiers +# (e.g. can't be rolled down, no sleeves to roll up, etc) +/obj/item/clothing/jumpsuit/research_director/rdalt : /obj/item/clothing/costume/research_director_suit{@OLD} +/obj/item/clothing/jumpsuit/captainformal/@SUBTYPES : /obj/item/clothing/costume/captainformal/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/mailman/@SUBTYPES : /obj/item/clothing/costume/mailman/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/vice/@SUBTYPES : /obj/item/clothing/costume/vice/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/johnny/@SUBTYPES : /obj/item/clothing/costume/johnny/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/psyche/@SUBTYPES : /obj/item/clothing/costume/psyche/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/wetsuit/@SUBTYPES : /obj/item/clothing/costume/wetsuit/@SUBTYPES{@OLD} +/obj/item/clothing/jumpsuit/caretaker/@SUBTYPES : /obj/item/clothing/costume/caretaker/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/4912_unused_clothes_removal.txt b/tools/map_migrations/4912_unused_clothes_removal.txt new file mode 100644 index 000000000000..553a95bd086a --- /dev/null +++ b/tools/map_migrations/4912_unused_clothes_removal.txt @@ -0,0 +1,3 @@ +/obj/item/clothing/jumpsuit/vice/@SUBTYPES : @DELETE +/obj/item/clothing/jumpsuit/johnny/@SUBTYPES : @DELETE +/obj/item/clothing/jumpsuit/caretaker/@SUBTYPES : @DELETE \ No newline at end of file diff --git a/tools/map_migrations/4975_kitchen.txt b/tools/map_migrations/4975_kitchen.txt new file mode 100644 index 000000000000..a796c54eb3ae --- /dev/null +++ b/tools/map_migrations/4975_kitchen.txt @@ -0,0 +1 @@ +/obj/item/kitchen/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/5056_circuit_repaths.txt b/tools/map_migrations/5056_circuit_repaths.txt new file mode 100644 index 000000000000..08bf6ca0318b --- /dev/null +++ b/tools/map_migrations/5056_circuit_repaths.txt @@ -0,0 +1,4 @@ +# PR #5056 removed `/obj/item/integrated_electronics` type +/obj/item/integrated_electronics/@SUBTYPES : /obj/item/@SUBTYPES{@OLD} +# PR #5056 repathed `/obj/prefab` to `/obj/abstract/prefab` +/obj/prefab/@SUBTYPES : /obj/abstract/prefab/@SUBTYPES{@OLD} diff --git a/tools/map_migrations/5120_powersensor.txt b/tools/map_migrations/5120_powersensor.txt new file mode 100644 index 000000000000..076dbeb33356 --- /dev/null +++ b/tools/map_migrations/5120_powersensor.txt @@ -0,0 +1,2 @@ +# Powernet sensors are no longer a subtype of /obj/machinery/power +/obj/machinery/power/sensor/@SUBTYPES : /obj/machinery/power_sensor/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/5151_power_apc.txt b/tools/map_migrations/5151_power_apc.txt new file mode 100644 index 000000000000..3725ae8b5d13 --- /dev/null +++ b/tools/map_migrations/5151_power_apc.txt @@ -0,0 +1,2 @@ +# APCs are no longer a subtype of /obj/machinery/power +/obj/machinery/power/apc/@SUBTYPES : /obj/machinery/apc/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/5281_freezer_heater.txt b/tools/map_migrations/5281_freezer_heater.txt new file mode 100644 index 000000000000..ea420f32ec3b --- /dev/null +++ b/tools/map_migrations/5281_freezer_heater.txt @@ -0,0 +1,2 @@ +/obj/machinery/atmospherics/unary/heater/@SUBTYPES : /obj/machinery/atmospherics/unary/temperature/heater{@OLD} +/obj/machinery/atmospherics/unary/freezer/@SUBTYPES : /obj/machinery/atmospherics/unary/temperature/freezer{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/5320_power_debug.txt b/tools/map_migrations/5320_power_debug.txt new file mode 100644 index 000000000000..b5a1d738e495 --- /dev/null +++ b/tools/map_migrations/5320_power_debug.txt @@ -0,0 +1,2 @@ +/obj/machinery/power/debug_items/@SUBTYPES : /obj/machinery/debug_items/@SUBTYPES{@OLD} +/obj/machinery/power/ascent_reactor/@SUBTYPES : /obj/machinery/ascent_reactor/@SUBTYPES{@OLD} \ No newline at end of file diff --git a/tools/map_migrations/9999_cigarettes.txt b/tools/map_migrations/9999_cigarettes.txt new file mode 100644 index 000000000000..875e6404ad48 --- /dev/null +++ b/tools/map_migrations/9999_cigarettes.txt @@ -0,0 +1,4 @@ +/obj/item/box/fancy/cigarettes/flash_powder : /obj/item/box/fancy/cigarettes/covert/flash_powder{@OLD} +/obj/item/box/fancy/cigarettes/chemsmoke : /obj/item/box/fancy/cigarettes/covert/flash_powder{@OLD} +/obj/item/box/fancy/cigarettes/mindbreak : /obj/item/box/fancy/cigarettes/covert/flash_powder{@OLD} +/obj/item/box/fancy/cigarettes/tricord : /obj/item/box/fancy/cigarettes/covert/flash_powder{@OLD} \ No newline at end of file diff --git a/tools/mapcapturemerge/.gitignore b/tools/mapcapturemerge/.gitignore index 20379651e836..508577d9cb19 100644 --- a/tools/mapcapturemerge/.gitignore +++ b/tools/mapcapturemerge/.gitignore @@ -1,3 +1,3 @@ -*.png -*.pyc -captures/*.png +*.png +*.pyc +captures/*.png diff --git a/tools/mapcapturemerge/README.md b/tools/mapcapturemerge/README.md index 5606211b2e65..15f398267edf 100644 --- a/tools/mapcapturemerge/README.md +++ b/tools/mapcapturemerge/README.md @@ -1,11 +1,11 @@ -Map capture merge tool manual -====== - -1. Capture desired Z levels using in game verb `Capture-map` -2. Before closing game window, go to cache folder usually located under Documents/BYOND and copy all map capture files named like `map_capture_x1_y33_z1_r32.png` to folder under this tool called `captures`. -3. Install *Python* and *Pillow* library (If you don't have them already). -4. Run `python merge.py` and wait for captures to be merged. -5. After execution you will find all z-level merged maps in the mapcapturemerge tool folder. - -Notes: +Map capture merge tool manual +====== + +1. Capture desired Z levels using in game verb `Capture-map` +2. Before closing game window, go to cache folder usually located under Documents/BYOND and copy all map capture files named like `map_capture_x1_y33_z1_r32.png` to folder under this tool called `captures`. +3. Install *Python* and *Pillow* library (If you don't have them already). +4. Run `python merge.py` and wait for captures to be merged. +5. After execution you will find all z-level merged maps in the mapcapturemerge tool folder. + +Notes: * This tool been tested with Python 2.7.6 under Windows 10 Bash. \ No newline at end of file diff --git a/tools/mapcapturemerge/imageHelpers.py b/tools/mapcapturemerge/imageHelpers.py index b7cdb309552b..90c501021eee 100644 --- a/tools/mapcapturemerge/imageHelpers.py +++ b/tools/mapcapturemerge/imageHelpers.py @@ -1,15 +1,15 @@ -from PIL import Image -import re -reg_findnums = re.compile("[0-9]+") - -class ImageFile: - def __init__(self, filename, path): - self.filename = path - nums = reg_findnums.findall(filename) - self.cords = (int(nums[0]), int(nums[1]), int(nums[2])) - self.range = int(nums[3]) - - def getImage(self): - im = Image.open(self.filename) - im.load() - return im +from PIL import Image +import re +reg_findnums = re.compile("[0-9]+") + +class ImageFile: + def __init__(self, filename, path): + self.filename = path + nums = reg_findnums.findall(filename) + self.cords = (int(nums[0]), int(nums[1]), int(nums[2])) + self.range = int(nums[3]) + + def getImage(self): + im = Image.open(self.filename) + im.load() + return im diff --git a/tools/mapcapturemerge/merge.py b/tools/mapcapturemerge/merge.py index 66fcae967bef..02966a937162 100644 --- a/tools/mapcapturemerge/merge.py +++ b/tools/mapcapturemerge/merge.py @@ -1,41 +1,41 @@ -from PIL import Image -import os, re, imageHelpers - -def BYONDCordsToPixelCords(B, BMax): - y = (BMax[1] - B[1]) - 31 - return (B[0] * 32 - 32, y * 32 - 32) - -image_location = os.path.join(os.getcwd(), 'captures') - -print("Map capture merger by Karolis") - -capture_images = [] -capture_re = re.compile("map_capture_x[0-9]+_y[0-9]+_z[0-9]+_r32\.png") -for image_file in os.listdir(image_location): - if os.path.isfile(os.path.join(image_location, image_file)) and capture_re.match(image_file): - #print(image_file) - capture_images.append(imageHelpers.ImageFile(image_file, os.path.join(image_location, image_file))) - -max_x = 0 -max_y = 0 -z_levels = [] -captures = {} -for capture in capture_images: - max_x = max(max_x, capture.cords[0] + capture.range) - max_y = max(max_y, capture.cords[1] + capture.range) - if not capture.cords[2] in z_levels: - z_levels.append(capture.cords[2]) - captures[capture.cords[2]] = [] - captures[capture.cords[2]].append(capture) - -maxCords = (max_x, max_y) - -for z in z_levels: - print("Merging map from " + str(z) + " z level.") - map = Image.new("RGBA", ((max_x - 1) * 32, (max_y - 1) * 32)) - for capture in captures[z]: - part = capture.getImage() - map.paste(part, BYONDCordsToPixelCords(capture.cords, maxCords)) - filename = "map_z" + str(z) + ".png" - print("Saving map as: " + filename) - map.save(filename) +from PIL import Image +import os, re, imageHelpers + +def BYONDCordsToPixelCords(B, BMax): + y = (BMax[1] - B[1]) - 31 + return (B[0] * 32 - 32, y * 32 - 32) + +image_location = os.path.join(os.getcwd(), 'captures') + +print("Map capture merger by Karolis") + +capture_images = [] +capture_re = re.compile("map_capture_x[0-9]+_y[0-9]+_z[0-9]+_r32\.png") +for image_file in os.listdir(image_location): + if os.path.isfile(os.path.join(image_location, image_file)) and capture_re.match(image_file): + #print(image_file) + capture_images.append(imageHelpers.ImageFile(image_file, os.path.join(image_location, image_file))) + +max_x = 0 +max_y = 0 +z_levels = [] +captures = {} +for capture in capture_images: + max_x = max(max_x, capture.cords[0] + capture.range) + max_y = max(max_y, capture.cords[1] + capture.range) + if not capture.cords[2] in z_levels: + z_levels.append(capture.cords[2]) + captures[capture.cords[2]] = [] + captures[capture.cords[2]].append(capture) + +maxCords = (max_x, max_y) + +for z in z_levels: + print("Merging map from " + str(z) + " z level.") + map = Image.new("RGBA", ((max_x - 1) * 32, (max_y - 1) * 32)) + for capture in captures[z]: + part = capture.getImage() + map.paste(part, BYONDCordsToPixelCords(capture.cords, maxCords)) + filename = "map_z" + str(z) + ".png" + print("Saving map as: " + filename) + map.save(filename) diff --git a/tools/mapmerge2/dmm.py b/tools/mapmerge2/dmm.py index f66f2b8edf13..b9068955bede 100644 --- a/tools/mapmerge2/dmm.py +++ b/tools/mapmerge2/dmm.py @@ -44,19 +44,13 @@ def to_bytes(self, tgm = True): return bio.getvalue() def generate_new_key(self): - free_keys = self._ensure_free_keys(1) + self._ensure_free_keys(1) + max_key = max_key_for(self.key_length) # choose one of the free keys at random - key = 0 - while free_keys: - if key not in self.dictionary: - # this construction is used to avoid needing to construct the - # full set in order to random.choice() from it - if random.random() < 1 / free_keys: - return key - free_keys -= 1 - key += 1 - - raise RuntimeError("ran out of keys, this shouldn't happen") + key = random.randint(0, max_key - 1) + while key in self.dictionary: + key = random.randint(0, max_key - 1) + return key def overwrite_key(self, key, fixed, bad_keys): try: @@ -75,6 +69,14 @@ def reassign_bad_keys(self, bad_keys): # reassign the grid entries which used the old key self.grid[k] = bad_keys.get(v, v) + def remove_unused_keys(self, modified_keys = None): + unused_keys = list(set(modified_keys)) if modified_keys is not None else self.dictionary.keys() + for key in self.grid.values(): + if key in unused_keys: + unused_keys.remove(key) + for key in unused_keys: + del self.dictionary[key] + def _presave_checks(self): # last-second handling of bogus keys to help prevent and fix broken maps self._ensure_free_keys(0) diff --git a/tools/mapmerge2/requirements-install.bat b/tools/mapmerge2/requirements-install.bat index 71341af87928..b47bbb6a57b9 100644 --- a/tools/mapmerge2/requirements-install.bat +++ b/tools/mapmerge2/requirements-install.bat @@ -1,3 +1,3 @@ @echo off -python -m pip install -r requirements.txt +python -m pip install -r requirements.txt --user pause diff --git a/tools/mapmerge2/requirements.txt b/tools/mapmerge2/requirements.txt index 41ddc96c1742..d0d9835bfc8a 100644 --- a/tools/mapmerge2/requirements.txt +++ b/tools/mapmerge2/requirements.txt @@ -1,3 +1,2 @@ -pygit2==1.0.1 -bidict==0.13.1 -Pillow==7.0.0 +pygit2 ~= 1.2 +bidict ~= 0.20.0 diff --git a/tools/mapmerge2/update_paths.py b/tools/mapmerge2/update_paths.py index 2c316e941dee..f0b6af46072b 100644 --- a/tools/mapmerge2/update_paths.py +++ b/tools/mapmerge2/update_paths.py @@ -9,8 +9,12 @@ Update dmm files given update file/string. Replacement syntax example: /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP} - /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"} + /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal{@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"} /turf/open/floor/plasteel/warningline{dir=2} : /obj/thing +Syntax for subtypes also exist, to update a path's type but maintain subtypes: + /obj/structure/closet/crate/@SUBTYPES : /obj/structure/new_box/@SUBTYPES {@OLD} +To delete a type, replace it with @DELETE: + /turf/open/floor/plasteel/warningline{dir=2} : @DELETE New paths properties: @OLD - if used as property name copies all modified properties from original path to this one property = @SKIP - will not copy this property through when global @OLD is used. @@ -20,13 +24,14 @@ Old paths properties: Will be used as a filter. property = @UNSET - will apply the rule only if the property is not mapedited + property = @SET - will apply the rule only if the property is mapedited """ default_map_directory = "../../_maps" replacement_re = re.compile(r'\s*(?P[^{]*)\s*(\{(?P.*)\})?') #urgent todo: replace with actual parser, this is slow as janitor in crit -split_re = re.compile(r'((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";]*)|@OLD)') +split_re = re.compile(r'((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|list\([^;]*\)|[^";]*)|@OLD)') def props_to_string(props): @@ -70,7 +75,7 @@ def update_path(dmm_data, replacement_string, verbose=False): old_path = old_path[:-len("/@SUBTYPES")] if verbose: print("Looking for subtypes of", old_path) - subtypes = r"(?:/\w+)*" + subtypes = r"(?P(?:/\w+)*)" replacement_pattern = re.compile(rf"(?P{re.escape(old_path)}{subtypes})\s*(:?{{(?P.*)}})?$") @@ -86,6 +91,22 @@ def replace_def(match): else: return [match.group(0)] else: + if old_path_props[filter_prop] == "@SET": + continue + if old_path_props[filter_prop] == "@NEGATIVE": + try: + if float(old_props[filter_prop]) < 0: + continue + return [match.group(0)] + except ValueError: + return [match.group(0)] + if old_path_props[filter_prop] == "@POSITIVE": + try: + if float(old_props[filter_prop]) > 0: + continue + return [match.group(0)] + except ValueError: + return [match.group(0)] if old_props[filter_prop] != old_path_props[filter_prop] or old_path_props[filter_prop] == "@UNSET": return [match.group(0)] #does not match current filter, skip the change. if verbose: @@ -94,6 +115,15 @@ def replace_def(match): for new_path, new_props in new_paths: if new_path == "@OLD": out = match.group('path') + elif new_path == "@DELETE": + if verbose: + print("Deleting match : {0}".format(match.group(0))) + return [None] + elif new_path.endswith("/@SUBTYPES"): + out = new_path[:-len("/@SUBTYPES")] + str(match.group('subpath') or '') + elif "/@SUBTYPES/" in new_path: + split_idx = new_path.index("/@SUBTYPES/") + out = new_path[:split_idx] + str(match.group('subpath') or '') + new_path[split_idx + len("/@SUBTYPES"):] else: out = new_path out_props = dict() @@ -125,21 +155,26 @@ def get_result(element): return [element] bad_keys = {} + modified_keys = [] keys = list(dmm_data.dictionary.keys()) for definition_key in keys: def_value = dmm_data.dictionary[definition_key] - new_value = tuple(y for x in def_value for y in get_result(x)) + new_value = tuple(y for x in def_value for y in get_result(x) if y != None) if new_value != def_value: dmm_data.overwrite_key(definition_key, new_value, bad_keys) + modified_keys.append(definition_key) dmm_data.reassign_bad_keys(bad_keys) + return modified_keys def update_map(map_filepath, updates, verbose=False): print("Updating: {0}".format(map_filepath)) dmm_data = DMM.from_file(map_filepath) + modified_keys = [] for update_string in updates: - update_path(dmm_data, update_string, verbose) - dmm_data.to_file(map_filepath, True) + modified_keys.extend(update_path(dmm_data, update_string, verbose)) + dmm_data.remove_unused_keys(modified_keys) + dmm_data.to_file(map_filepath) def update_all_maps(map_directory, updates, verbose=False): @@ -155,9 +190,20 @@ def main(args): print("Using replacement:", args.update_source) updates = [args.update_source] else: - with open(args.update_source) as f: - updates = [line for line in f if line and not line.startswith("#") and not line.isspace()] - print(f"Using {len(updates)} replacements from file:", args.update_source) + # optional support for passing a directory + if os.path.isdir(args.update_source): + updates = [] + for root, _, files in os.walk(args.update_source): + for filepath in files: + if filepath.endswith(".txt"): + path = os.path.join(root, filepath) + with open(path) as f: + updates.extend(line for line in f if line and not line.startswith("#") and not line.isspace()) + print(f"Using {len(updates)} replacements from directory:", args.update_source) + else: + with open(args.update_source) as f: + updates = [line for line in f if line and not line.startswith("#") and not line.isspace()] + print(f"Using {len(updates)} replacements from file:", args.update_source) if args.map: update_map(args.map, updates, verbose=args.verbose) diff --git a/tools/od_annotator/__main__.py b/tools/od_annotator/__main__.py new file mode 100644 index 000000000000..ca2dcf018c28 --- /dev/null +++ b/tools/od_annotator/__main__.py @@ -0,0 +1,43 @@ +import sys +import re + +def green(text): + return "\033[32m" + str(text) + "\033[0m" + +def red(text): + return "\033[31m" + str(text) + "\033[0m" + +def annotate(raw_output): + # Remove ANSI escape codes + raw_output = re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]', '', raw_output) + + print("::group::OpenDream Output") + print(raw_output) + print("::endgroup::") + + annotation_regex = r'((?PError|Warning) (?POD(?P\d{4})) at (?P(?P.+):(?P\d+):(?P\d+)|): (?P.+))' + failures_detected = False + + print("OpenDream Code Annotations:") + for annotation in re.finditer(annotation_regex, raw_output): + message = annotation['message'] + if message == "Unimplemented proc & var warnings are currently suppressed": # this happens every single run, it's important to know about it but we don't need to throw an error + message += " (This is expected and can be ignored)" # also there's no location for it to annotate to since it's an failure. + + if annotation['type'] == "Error": + failures_detected = True + + error_string = f"{annotation['errorcode']}: {message}" + + if annotation['location'] == "": + print(f"::{annotation['type']} file=,line=,col=::{error_string}") + else: + print(f"::{annotation['type']} file={annotation['filename']},line={annotation['line']},col={annotation['column']}::{error_string}") + + if failures_detected: + sys.exit(1) + return + + print(green("No OpenDream issues found!")) + +annotate(sys.stdin.read()) diff --git a/tools/validate_dme.py b/tools/validate_dme.py new file mode 100644 index 000000000000..cca8764cec9c --- /dev/null +++ b/tools/validate_dme.py @@ -0,0 +1,114 @@ +import fnmatch +import functools +import glob +import sys +from os.path import normpath + +reading = False + +FORBID_INCLUDE = [ + r'code/**/*_docs.dm', + r'code/**/*readme.dm', + r'code/**/*README.dm', +] + +IGNORE_INCLUDE = [ + # Some of these are included, some aren't. + r'code/unit_tests/*.dm', + # Ditto, todo: modularise or remove + r'code/datums/music_tracks/*.dm', +] + +lines = [] +total = 0 +for line in sys.stdin: + total+=1 + line = line.strip() + + if line == "// BEGIN_INCLUDE": + reading = True + continue + elif line == "// END_INCLUDE": + break + elif not reading: + continue + + lines.append(line) + +offset = total - len(lines) +print(f"{offset} lines were ignored in output") +fail_no_include = False + +for code_file in glob.glob("code/**/*.dm", recursive=True): + dm_path = code_file.replace('/', '\\') + + included = f"#include \"{dm_path}\"" in lines + forbid_include = False + + ignored = False + for ignore in IGNORE_INCLUDE: + if not fnmatch.fnmatchcase(code_file, normpath(ignore)): + continue + + ignored = True + break + + if ignored: + continue + + for forbid in FORBID_INCLUDE: + if not fnmatch.fnmatchcase(code_file, normpath(forbid)): + continue + + forbid_include = True + + if included: + print(f"{dm_path} should not be included") + print(f"::error file={code_file},line=1,title=DME Validator::File should not be included") + fail_no_include = True + + if forbid_include: + continue + + if not included: + print(f"{dm_path} is not included") + print(f"::error file={code_file},line=1,title=DME Validator::File is not included") + fail_no_include = True + +if fail_no_include: + sys.exit(1) + +def compare_lines(a, b): + # Remove initial include as well as the final quotation mark + a = a[len("#include \""):-1].lower() + b = b[len("#include \""):-1].lower() + + a_segments = a.split('\\') + b_segments = b.split('\\') + + for (a_segment, b_segment) in zip(a_segments, b_segments): + a_is_file = a_segment.endswith(".dm") + b_is_file = b_segment.endswith(".dm") + + # code\something.dm will ALWAYS come before code\directory\something.dm + if a_is_file and not b_is_file: + return -1 + + if b_is_file and not a_is_file: + return 1 + + # interface\something.dm will ALWAYS come after code\something.dm + if a_segment != b_segment: + return (a_segment > b_segment) - (a_segment < b_segment) + + raise f"Two lines were exactly the same ({a} vs. {b})" + +failed = False +sorted_lines = sorted(lines, key = functools.cmp_to_key(compare_lines)) +for (index, line) in enumerate(lines): + if sorted_lines[index] != line: + print(f"The include at line {index + offset} is out of order ({line}, expected {sorted_lines[index]})") + print(f"::error file=nebula.dme,line={index+offset},title=DME Validator::The include at line {index + offset} is out of order ({line}, expected {sorted_lines[index]})") + failed = True +if failed: + sys.exit(1) diff --git a/tools/validate_modpacks.py b/tools/validate_modpacks.py new file mode 100644 index 000000000000..aa192d073c83 --- /dev/null +++ b/tools/validate_modpacks.py @@ -0,0 +1,169 @@ +import fnmatch +import functools +import glob +import sys +import os + +""" +Paths to search for modpacks in. +Works best if search paths are only one-deep, so that nested modpacks can be added separately. +""" +MODPACK_ROOTS = [ + r'mods/content/*/*.dme', + r'mods/gamemodes/*/*.dme', + r'mods/mobs/*/*.dme', + r'mods/species/*/*.dme' + # Example nested modpack configuration: + # r'mods/some_downstream/*/*.dme' +] + +""" +A list of DME paths to not run validation on. +Useful for excluding the outermost DME in a nested-modpack situation. +""" +IGNORE_MODPACKS = [ + # Example: + # r'mods/some_downstream/some_downstream.dme/*.dme' +] + +""" +A dictionary mapping of modpack roots ('mods/content/corporate') +to a list of globs matching files to forbid inclusion of. +If a file matches any of the globs, validation fails. +""" +FORBID_INCLUDE = { + # Example: + # r'mods/content/whatever/_whatever.dme' : [r'mods/content/whatever/README.md', r'mods/content/whatever/something/something_docs.md'] +} + +""" +A dictionary mapping of modpack roots ('mods/content/corporate') +to a list of globs matching files ('mods/content/corporate/away_sites/**/*.dm) to ignore when checking for inclusion. +If a file matching any of the globs is not included, validation will NOT fail. +""" +IGNORE_INCLUDE = { + # The validator can't detect the weird way these are loaded. + r'mods/content/corporate': [ + r'mods/content/corporate/away_sites/**/*.dm', + ], + r'mods/content/government': [ + r'mods/content/government/away_sites/**/*.dm' + ] +} + +def validate_modpack(dme_path): + (modpack_path, dme_name) = os.path.split(dme_path) + reading = False + lines = [] + total = 0 + with open(dme_path, 'r') as dme_file: + for line in dme_file.readlines(): + total+=1 + line = line.strip() + + if line == "// BEGIN_INCLUDE": + reading = True + continue + elif line == "// END_INCLUDE": + break + elif not reading: + continue + elif not line.startswith("#include"): + continue + + lines.append(line) + + offset = total - len(lines) + print(f"{offset} lines were ignored in {dme_name}") + modpack_failed = False + + for code_file in glob.glob("**/*.dm", root_dir=modpack_path, recursive=True): + full_file = os.path.join(modpack_path, code_file) + dm_path = code_file.replace('/', '\\') + + included = f"#include \"{dm_path}\"" in lines + forbid_include = False + + ignored = False + + modpack_ignores = [] + if modpack_path in IGNORE_INCLUDE: + modpack_ignores = IGNORE_INCLUDE[modpack_path] + + for ignore in modpack_ignores: + if not fnmatch.fnmatch(full_file, ignore): + continue + + ignored = True + break + + if ignored: + continue + + modpack_forbids = [] + if modpack_path in FORBID_INCLUDE: + modpack_forbids = FORBID_INCLUDE[modpack_path] + + for forbid in modpack_forbids: + if not fnmatch.fnmatch(full_file, forbid): + continue + + forbid_include = True + + if included: + print(f"{os.path.join(modpack_path,dm_path)} should not be included") + print(f"::error file={full_file},line=1,title=DME Validator::File should not be included") + modpack_failed = True + + if forbid_include: + continue + + if not included: + print(f"{os.path.join(modpack_path,dm_path)} is not included") + print(f"::error file={full_file},line=1,title=DME Validator::File is not included") + modpack_failed = True + + def compare_lines(a, b): + # Remove initial include as well as the final quotation mark + a = a[len("#include \""):-1].lower() + b = b[len("#include \""):-1].lower() + + a_segments = a.split('\\') + b_segments = b.split('\\') + + for (a_segment, b_segment) in zip(a_segments, b_segments): + a_is_file = a_segment.endswith(".dm") + b_is_file = b_segment.endswith(".dm") + + # code\something.dm will ALWAYS come before code\directory\something.dm + if a_is_file and not b_is_file: + return -1 + + if b_is_file and not a_is_file: + return 1 + + # interface\something.dm will ALWAYS come after code\something.dm + if a_segment != b_segment: + return (a_segment > b_segment) - (a_segment < b_segment) + + raise ValueError(f"Two lines were exactly the same ({a} vs. {b})") + + sorted_lines = sorted(lines, key = functools.cmp_to_key(compare_lines)) + for (index, line) in enumerate(lines): + if sorted_lines[index] != line: + print(f"The include at line {index + offset} is out of order ({line}, expected {sorted_lines[index]})") + print(f"::error file={dme_path},line={index+offset},title=DME Validator::The include at line {index + offset} is out of order ({line}, expected {sorted_lines[index]})") + modpack_failed = True + return modpack_failed + +failed = False +for modpack_root in MODPACK_ROOTS: + for modpack_dme in glob.glob(modpack_root, recursive=True): + modpack_dme = modpack_dme.replace('\\', '/') + if modpack_dme in IGNORE_MODPACKS: + continue + failed = validate_modpack(modpack_dme) or failed + +if failed: + sys.exit(1) + diff --git a/~code/global_init.dm b/~code/global_init.dm index 39cdaba38673..c483e8f9e8b6 100644 --- a/~code/global_init.dm +++ b/~code/global_init.dm @@ -7,16 +7,18 @@ 5. The gameticker is created. */ -var/global/datum/global_init/init = new () - /* Pre-map initialization stuff should go here. */ + +var/global/global_init = new /datum/global_init() + /datum/global_init/New() - load_configuration() - callHook("global_init") - qdel(src) //we're done + SSconfiguration.load_all_configuration() + generate_game_id() + makeDatumRefLists() + QDEL_IN(src, 0) //we're done. give it some time to finish setting up though /datum/global_init/Destroy() - init = null + global.global_init = null return ..()